2023-01-03 17:20:51

by Yann Sionneau

[permalink] [raw]
Subject: [RFC PATCH 00/25] Upstream kvx Linux port

This patch series adds support for the kv3-1 CPU architecture of the kvx family
found in the Coolidge (aka MPPA3-80) SoC of Kalray.

This is an RFC, since kvx support is not yet upstreamed into gcc/binutils,
therefore this patch series cannot be merged into Linux for now.

The goal is to have preliminary reviews and to fix problems early.

The Kalray VLIW processor family (kvx) has the following features:
* 32/64 bits execution mode
* 6-issue VLIW architecture
* 64 x 64bits general purpose registers
* SIMD instructions
* little-endian
* deep learning co-processor

Kalray kv3-1 core which is the third of the kvx family is embedded in Kalray
Coolidge SoC currently used on K200 and K200-LP boards.

The Coolidge SoC contains 5 clusters each of which is made of:
* 4MiB of on-chip memory (SMEM)
* 1 dedicated safety/security core (kv3-1 core).
* 16 PEs (Processing Elements) (kv3-1 cores).
* 16 Co-processors (one per PE)
* 2 Crypto accelerators

The Coolidge SoC contains the following features:
* 5 Clusters
* 2 100G Ethernet controllers
* 8 PCIe GEN4 controllers (Root Complex and Endpoint capable)
* 2 USB 2.0 controllers
* 1 Octal SPI-NOR flash controller
* 1 eMMC controller
* 3 Quad SPI controllers
* 6 UART
* 5 I2C controllers (3 of which are SMBus capable)
* 4 CAN controllers
* 1 OTP memory

A kvx toolchain can be built using:
# install dependencies: texinfo bison flex libgmp-dev libmpc-dev libmpfr-dev
$ git clone https://github.com/kalray/build-scripts
$ cd build-scripts
$ source last.refs
$ ./build-kvx-xgcc.sh output

The kvx toolchain will be installed in the "output" directory.

A buildroot image (kernel+rootfs) and toolchain can be built using:
$ git clone -b coolidge-for-upstream https://github.com/kalray/buildroot
$ cd buildroot
$ make O=build_kvx kvx_defconfig
$ make O=build_kvx

The vmlinux image can be found in buildroot/build_kvx/images/vmlinux.

If you are just interested in building the Linux kernel with no rootfs you can
just do this with the kvx-elf- toolchain:
$ make ARCH=kvx O=build_kvx CROSS_COMPILE=kvx-elf- default_defconfig
$ make ARCH=kvx O=build_kvx CROSS_COMPILE=kvx-elf- -j$(($(nproc) + 1))

The vmlinux ELF can be run with qemu by doing:
# install dependencies: ninja pkg-config libglib-2.0-dev cmake libfdt-dev libpixman-1-dev zlib1g-dev
$ git clone https://github.com/kalray/qemu-builder
$ cd qemu-builder
$ git submodule update --init
$ make -j$(($(nproc) + 1))
$ ./qemu-system-kvx -m 1024 -nographic -kernel <path/to/vmlinux>

Yann Sionneau (25):
Documentation: kvx: Add basic documentation
kvx: Add ELF-related definitions
kvx: Add build infrastructure
kvx: Add CPU definition headers
kvx: Add atomic/locking headers
kvx: Add other common headers
kvx: Add boot and setup routines
kvx: Add exception/interrupt handling
kvx: irqchip: Add support for irq controllers
kvx: Add process management
kvx: Add memory management
kvx: Add system call support
kvx: Add signal handling support
kvx: Add ELF relocations and module support
kvx: Add misc common routines
kvx: Add some library functions
kvx: Add multi-processor (SMP) support
kvx: Add kvx default config file
kvx: power: scall poweroff driver
kvx: gdb: add kvx related gdb helpers
kvx: Add support for ftrace
kvx: Add support for jump labels
kvx: Add debugging related support
kvx: Add support for CPU Perf Monitors
kvx: Add support for cpuinfo

.../kalray,kvx-core-intc.txt | 22 +
.../devicetree/bindings/perf/kalray-pm.txt | 21 +
Documentation/kvx/kvx-exceptions.txt | 246 +
Documentation/kvx/kvx-iommu.txt | 183 +
Documentation/kvx/kvx-mmu.txt | 272 +
Documentation/kvx/kvx-smp.txt | 36 +
Documentation/kvx/kvx.txt | 268 +
arch/kvx/Kconfig | 249 +
arch/kvx/Kconfig.debug | 70 +
arch/kvx/Makefile | 52 +
arch/kvx/configs/default_defconfig | 130 +
arch/kvx/include/asm/Kbuild | 20 +
arch/kvx/include/asm/asm-prototypes.h | 14 +
arch/kvx/include/asm/atomic.h | 104 +
arch/kvx/include/asm/barrier.h | 15 +
arch/kvx/include/asm/bitops.h | 207 +
arch/kvx/include/asm/bitrev.h | 32 +
arch/kvx/include/asm/break_hook.h | 69 +
arch/kvx/include/asm/bug.h | 67 +
arch/kvx/include/asm/cache.h | 46 +
arch/kvx/include/asm/cacheflush.h | 181 +
arch/kvx/include/asm/clocksource.h | 17 +
arch/kvx/include/asm/cmpxchg.h | 185 +
arch/kvx/include/asm/current.h | 22 +
arch/kvx/include/asm/dame.h | 31 +
arch/kvx/include/asm/debug.h | 35 +
arch/kvx/include/asm/elf.h | 155 +
arch/kvx/include/asm/fixmap.h | 47 +
arch/kvx/include/asm/ftrace.h | 41 +
arch/kvx/include/asm/futex.h | 141 +
arch/kvx/include/asm/hardirq.h | 14 +
arch/kvx/include/asm/hugetlb.h | 36 +
arch/kvx/include/asm/hw_breakpoint.h | 72 +
arch/kvx/include/asm/hw_irq.h | 14 +
arch/kvx/include/asm/insns.h | 16 +
arch/kvx/include/asm/insns_defs.h | 197 +
arch/kvx/include/asm/io.h | 34 +
arch/kvx/include/asm/ipi.h | 16 +
arch/kvx/include/asm/irqflags.h | 58 +
arch/kvx/include/asm/jump_label.h | 59 +
arch/kvx/include/asm/l2_cache.h | 75 +
arch/kvx/include/asm/l2_cache_defs.h | 64 +
arch/kvx/include/asm/linkage.h | 13 +
arch/kvx/include/asm/mem_map.h | 44 +
arch/kvx/include/asm/mmu.h | 296 +
arch/kvx/include/asm/mmu_context.h | 156 +
arch/kvx/include/asm/mmu_stats.h | 38 +
arch/kvx/include/asm/page.h | 187 +
arch/kvx/include/asm/page_size.h | 29 +
arch/kvx/include/asm/pci.h | 36 +
arch/kvx/include/asm/perf_event.h | 90 +
arch/kvx/include/asm/pgalloc.h | 101 +
arch/kvx/include/asm/pgtable-bits.h | 102 +
arch/kvx/include/asm/pgtable.h | 451 ++
arch/kvx/include/asm/privilege.h | 211 +
arch/kvx/include/asm/processor.h | 176 +
arch/kvx/include/asm/ptrace.h | 217 +
arch/kvx/include/asm/pwr_ctrl.h | 45 +
arch/kvx/include/asm/rm_fw.h | 16 +
arch/kvx/include/asm/sections.h | 18 +
arch/kvx/include/asm/setup.h | 29 +
arch/kvx/include/asm/sfr.h | 107 +
arch/kvx/include/asm/sfr_defs.h | 5028 +++++++++++++++++
arch/kvx/include/asm/smp.h | 42 +
arch/kvx/include/asm/sparsemem.h | 15 +
arch/kvx/include/asm/spinlock.h | 16 +
arch/kvx/include/asm/spinlock_types.h | 17 +
arch/kvx/include/asm/stackprotector.h | 47 +
arch/kvx/include/asm/stacktrace.h | 44 +
arch/kvx/include/asm/string.h | 20 +
arch/kvx/include/asm/swab.h | 48 +
arch/kvx/include/asm/switch_to.h | 21 +
arch/kvx/include/asm/symbols.h | 16 +
arch/kvx/include/asm/sys_arch.h | 51 +
arch/kvx/include/asm/syscall.h | 73 +
arch/kvx/include/asm/syscalls.h | 21 +
arch/kvx/include/asm/thread_info.h | 78 +
arch/kvx/include/asm/timex.h | 20 +
arch/kvx/include/asm/tlb.h | 24 +
arch/kvx/include/asm/tlb_defs.h | 131 +
arch/kvx/include/asm/tlbflush.h | 58 +
arch/kvx/include/asm/traps.h | 76 +
arch/kvx/include/asm/types.h | 12 +
arch/kvx/include/asm/uaccess.h | 324 ++
arch/kvx/include/asm/unistd.h | 11 +
arch/kvx/include/asm/vermagic.h | 12 +
arch/kvx/include/asm/vmalloc.h | 10 +
arch/kvx/include/uapi/asm/Kbuild | 1 +
arch/kvx/include/uapi/asm/bitsperlong.h | 14 +
arch/kvx/include/uapi/asm/byteorder.h | 12 +
arch/kvx/include/uapi/asm/cachectl.h | 25 +
arch/kvx/include/uapi/asm/ptrace.h | 114 +
arch/kvx/include/uapi/asm/sigcontext.h | 16 +
arch/kvx/include/uapi/asm/unistd.h | 16 +
arch/kvx/kernel/Makefile | 27 +
arch/kvx/kernel/asm-offsets.c | 157 +
arch/kvx/kernel/break_hook.c | 77 +
arch/kvx/kernel/common.c | 11 +
arch/kvx/kernel/cpuinfo.c | 96 +
arch/kvx/kernel/dame_handler.c | 113 +
arch/kvx/kernel/debug.c | 64 +
arch/kvx/kernel/entry.S | 1759 ++++++
arch/kvx/kernel/ftrace.c | 339 ++
arch/kvx/kernel/head.S | 612 ++
arch/kvx/kernel/hw_breakpoint.c | 556 ++
arch/kvx/kernel/insns.c | 146 +
arch/kvx/kernel/io.c | 96 +
arch/kvx/kernel/irq.c | 78 +
arch/kvx/kernel/jump_label.c | 34 +
arch/kvx/kernel/kvx_ksyms.c | 29 +
arch/kvx/kernel/l2_cache.c | 448 ++
arch/kvx/kernel/mcount.S | 340 ++
arch/kvx/kernel/module.c | 148 +
arch/kvx/kernel/perf_event.c | 609 ++
arch/kvx/kernel/process.c | 212 +
arch/kvx/kernel/prom.c | 24 +
arch/kvx/kernel/ptrace.c | 461 ++
arch/kvx/kernel/reset.c | 37 +
arch/kvx/kernel/return_address.c | 55 +
arch/kvx/kernel/setup.c | 178 +
arch/kvx/kernel/signal.c | 266 +
arch/kvx/kernel/smp.c | 110 +
arch/kvx/kernel/smpboot.c | 127 +
arch/kvx/kernel/stacktrace.c | 173 +
arch/kvx/kernel/sys_kvx.c | 58 +
arch/kvx/kernel/syscall_table.c | 19 +
arch/kvx/kernel/time.c | 242 +
arch/kvx/kernel/traps.c | 243 +
arch/kvx/kernel/vdso.c | 87 +
arch/kvx/kernel/vmlinux.lds.S | 173 +
arch/kvx/lib/Makefile | 6 +
arch/kvx/lib/clear_page.S | 40 +
arch/kvx/lib/copy_page.S | 90 +
arch/kvx/lib/delay.c | 39 +
arch/kvx/lib/memcpy.c | 70 +
arch/kvx/lib/memset.S | 351 ++
arch/kvx/lib/strlen.S | 122 +
arch/kvx/lib/usercopy.S | 90 +
arch/kvx/mm/Makefile | 10 +
arch/kvx/mm/cacheflush.c | 154 +
arch/kvx/mm/dma-mapping.c | 95 +
arch/kvx/mm/extable.c | 24 +
arch/kvx/mm/fault.c | 264 +
arch/kvx/mm/hugetlbpage.c | 317 ++
arch/kvx/mm/init.c | 527 ++
arch/kvx/mm/kernel_rwx.c | 228 +
arch/kvx/mm/mmap.c | 31 +
arch/kvx/mm/mmu.c | 204 +
arch/kvx/mm/mmu_stats.c | 94 +
arch/kvx/mm/tlb.c | 433 ++
arch/kvx/platform/Makefile | 7 +
arch/kvx/platform/ipi.c | 110 +
arch/kvx/platform/pwr_ctrl.c | 93 +
drivers/irqchip/Kconfig | 27 +
drivers/irqchip/Makefile | 4 +
drivers/irqchip/irq-kvx-apic-gic.c | 349 ++
drivers/irqchip/irq-kvx-apic-mailbox.c | 465 ++
drivers/irqchip/irq-kvx-core-intc.c | 82 +
drivers/irqchip/irq-kvx-itgen.c | 224 +
drivers/power/reset/kvx-scall-poweroff.c | 53 +
include/linux/cpuhotplug.h | 2 +
include/linux/irqchip/irq-kvx-apic-gic.h | 21 +
include/linux/irqchip/irq-kvx-apic-mailbox.h | 29 +
include/linux/irqchip/irq-kvx-itgen.h | 24 +
include/uapi/linux/audit.h | 1 +
include/uapi/linux/elf-em.h | 1 +
include/uapi/linux/elf.h | 1 +
scripts/gdb/arch/Makefile | 11 +
scripts/gdb/arch/__init__.py | 1 +
scripts/gdb/arch/kvx/Makefile | 25 +
scripts/gdb/arch/kvx/__init__.py | 1 +
scripts/gdb/arch/kvx/constants.py.in | 74 +
scripts/gdb/arch/kvx/mmu.py | 199 +
scripts/gdb/arch/kvx/page_table_walk.py | 207 +
tools/include/uapi/asm/bitsperlong.h | 2 +
175 files changed, 25814 insertions(+)
create mode 100644 Documentation/devicetree/bindings/interrupt-controller/kalray,kvx-core-intc.txt
create mode 100644 Documentation/devicetree/bindings/perf/kalray-pm.txt
create mode 100644 Documentation/kvx/kvx-exceptions.txt
create mode 100644 Documentation/kvx/kvx-iommu.txt
create mode 100644 Documentation/kvx/kvx-mmu.txt
create mode 100644 Documentation/kvx/kvx-smp.txt
create mode 100644 Documentation/kvx/kvx.txt
create mode 100644 arch/kvx/Kconfig
create mode 100644 arch/kvx/Kconfig.debug
create mode 100644 arch/kvx/Makefile
create mode 100644 arch/kvx/configs/default_defconfig
create mode 100644 arch/kvx/include/asm/Kbuild
create mode 100644 arch/kvx/include/asm/asm-prototypes.h
create mode 100644 arch/kvx/include/asm/atomic.h
create mode 100644 arch/kvx/include/asm/barrier.h
create mode 100644 arch/kvx/include/asm/bitops.h
create mode 100644 arch/kvx/include/asm/bitrev.h
create mode 100644 arch/kvx/include/asm/break_hook.h
create mode 100644 arch/kvx/include/asm/bug.h
create mode 100644 arch/kvx/include/asm/cache.h
create mode 100644 arch/kvx/include/asm/cacheflush.h
create mode 100644 arch/kvx/include/asm/clocksource.h
create mode 100644 arch/kvx/include/asm/cmpxchg.h
create mode 100644 arch/kvx/include/asm/current.h
create mode 100644 arch/kvx/include/asm/dame.h
create mode 100644 arch/kvx/include/asm/debug.h
create mode 100644 arch/kvx/include/asm/elf.h
create mode 100644 arch/kvx/include/asm/fixmap.h
create mode 100644 arch/kvx/include/asm/ftrace.h
create mode 100644 arch/kvx/include/asm/futex.h
create mode 100644 arch/kvx/include/asm/hardirq.h
create mode 100644 arch/kvx/include/asm/hugetlb.h
create mode 100644 arch/kvx/include/asm/hw_breakpoint.h
create mode 100644 arch/kvx/include/asm/hw_irq.h
create mode 100644 arch/kvx/include/asm/insns.h
create mode 100644 arch/kvx/include/asm/insns_defs.h
create mode 100644 arch/kvx/include/asm/io.h
create mode 100644 arch/kvx/include/asm/ipi.h
create mode 100644 arch/kvx/include/asm/irqflags.h
create mode 100644 arch/kvx/include/asm/jump_label.h
create mode 100644 arch/kvx/include/asm/l2_cache.h
create mode 100644 arch/kvx/include/asm/l2_cache_defs.h
create mode 100644 arch/kvx/include/asm/linkage.h
create mode 100644 arch/kvx/include/asm/mem_map.h
create mode 100644 arch/kvx/include/asm/mmu.h
create mode 100644 arch/kvx/include/asm/mmu_context.h
create mode 100644 arch/kvx/include/asm/mmu_stats.h
create mode 100644 arch/kvx/include/asm/page.h
create mode 100644 arch/kvx/include/asm/page_size.h
create mode 100644 arch/kvx/include/asm/pci.h
create mode 100644 arch/kvx/include/asm/perf_event.h
create mode 100644 arch/kvx/include/asm/pgalloc.h
create mode 100644 arch/kvx/include/asm/pgtable-bits.h
create mode 100644 arch/kvx/include/asm/pgtable.h
create mode 100644 arch/kvx/include/asm/privilege.h
create mode 100644 arch/kvx/include/asm/processor.h
create mode 100644 arch/kvx/include/asm/ptrace.h
create mode 100644 arch/kvx/include/asm/pwr_ctrl.h
create mode 100644 arch/kvx/include/asm/rm_fw.h
create mode 100644 arch/kvx/include/asm/sections.h
create mode 100644 arch/kvx/include/asm/setup.h
create mode 100644 arch/kvx/include/asm/sfr.h
create mode 100644 arch/kvx/include/asm/sfr_defs.h
create mode 100644 arch/kvx/include/asm/smp.h
create mode 100644 arch/kvx/include/asm/sparsemem.h
create mode 100644 arch/kvx/include/asm/spinlock.h
create mode 100644 arch/kvx/include/asm/spinlock_types.h
create mode 100644 arch/kvx/include/asm/stackprotector.h
create mode 100644 arch/kvx/include/asm/stacktrace.h
create mode 100644 arch/kvx/include/asm/string.h
create mode 100644 arch/kvx/include/asm/swab.h
create mode 100644 arch/kvx/include/asm/switch_to.h
create mode 100644 arch/kvx/include/asm/symbols.h
create mode 100644 arch/kvx/include/asm/sys_arch.h
create mode 100644 arch/kvx/include/asm/syscall.h
create mode 100644 arch/kvx/include/asm/syscalls.h
create mode 100644 arch/kvx/include/asm/thread_info.h
create mode 100644 arch/kvx/include/asm/timex.h
create mode 100644 arch/kvx/include/asm/tlb.h
create mode 100644 arch/kvx/include/asm/tlb_defs.h
create mode 100644 arch/kvx/include/asm/tlbflush.h
create mode 100644 arch/kvx/include/asm/traps.h
create mode 100644 arch/kvx/include/asm/types.h
create mode 100644 arch/kvx/include/asm/uaccess.h
create mode 100644 arch/kvx/include/asm/unistd.h
create mode 100644 arch/kvx/include/asm/vermagic.h
create mode 100644 arch/kvx/include/asm/vmalloc.h
create mode 100644 arch/kvx/include/uapi/asm/Kbuild
create mode 100644 arch/kvx/include/uapi/asm/bitsperlong.h
create mode 100644 arch/kvx/include/uapi/asm/byteorder.h
create mode 100644 arch/kvx/include/uapi/asm/cachectl.h
create mode 100644 arch/kvx/include/uapi/asm/ptrace.h
create mode 100644 arch/kvx/include/uapi/asm/sigcontext.h
create mode 100644 arch/kvx/include/uapi/asm/unistd.h
create mode 100644 arch/kvx/kernel/Makefile
create mode 100644 arch/kvx/kernel/asm-offsets.c
create mode 100644 arch/kvx/kernel/break_hook.c
create mode 100644 arch/kvx/kernel/common.c
create mode 100644 arch/kvx/kernel/cpuinfo.c
create mode 100644 arch/kvx/kernel/dame_handler.c
create mode 100644 arch/kvx/kernel/debug.c
create mode 100644 arch/kvx/kernel/entry.S
create mode 100644 arch/kvx/kernel/ftrace.c
create mode 100644 arch/kvx/kernel/head.S
create mode 100644 arch/kvx/kernel/hw_breakpoint.c
create mode 100644 arch/kvx/kernel/insns.c
create mode 100644 arch/kvx/kernel/io.c
create mode 100644 arch/kvx/kernel/irq.c
create mode 100644 arch/kvx/kernel/jump_label.c
create mode 100644 arch/kvx/kernel/kvx_ksyms.c
create mode 100644 arch/kvx/kernel/l2_cache.c
create mode 100644 arch/kvx/kernel/mcount.S
create mode 100644 arch/kvx/kernel/module.c
create mode 100644 arch/kvx/kernel/perf_event.c
create mode 100644 arch/kvx/kernel/process.c
create mode 100644 arch/kvx/kernel/prom.c
create mode 100644 arch/kvx/kernel/ptrace.c
create mode 100644 arch/kvx/kernel/reset.c
create mode 100644 arch/kvx/kernel/return_address.c
create mode 100644 arch/kvx/kernel/setup.c
create mode 100644 arch/kvx/kernel/signal.c
create mode 100644 arch/kvx/kernel/smp.c
create mode 100644 arch/kvx/kernel/smpboot.c
create mode 100644 arch/kvx/kernel/stacktrace.c
create mode 100644 arch/kvx/kernel/sys_kvx.c
create mode 100644 arch/kvx/kernel/syscall_table.c
create mode 100644 arch/kvx/kernel/time.c
create mode 100644 arch/kvx/kernel/traps.c
create mode 100644 arch/kvx/kernel/vdso.c
create mode 100644 arch/kvx/kernel/vmlinux.lds.S
create mode 100644 arch/kvx/lib/Makefile
create mode 100644 arch/kvx/lib/clear_page.S
create mode 100644 arch/kvx/lib/copy_page.S
create mode 100644 arch/kvx/lib/delay.c
create mode 100644 arch/kvx/lib/memcpy.c
create mode 100644 arch/kvx/lib/memset.S
create mode 100644 arch/kvx/lib/strlen.S
create mode 100644 arch/kvx/lib/usercopy.S
create mode 100644 arch/kvx/mm/Makefile
create mode 100644 arch/kvx/mm/cacheflush.c
create mode 100644 arch/kvx/mm/dma-mapping.c
create mode 100644 arch/kvx/mm/extable.c
create mode 100644 arch/kvx/mm/fault.c
create mode 100644 arch/kvx/mm/hugetlbpage.c
create mode 100644 arch/kvx/mm/init.c
create mode 100644 arch/kvx/mm/kernel_rwx.c
create mode 100644 arch/kvx/mm/mmap.c
create mode 100644 arch/kvx/mm/mmu.c
create mode 100644 arch/kvx/mm/mmu_stats.c
create mode 100644 arch/kvx/mm/tlb.c
create mode 100644 arch/kvx/platform/Makefile
create mode 100644 arch/kvx/platform/ipi.c
create mode 100644 arch/kvx/platform/pwr_ctrl.c
create mode 100644 drivers/irqchip/irq-kvx-apic-gic.c
create mode 100644 drivers/irqchip/irq-kvx-apic-mailbox.c
create mode 100644 drivers/irqchip/irq-kvx-core-intc.c
create mode 100644 drivers/irqchip/irq-kvx-itgen.c
create mode 100644 drivers/power/reset/kvx-scall-poweroff.c
create mode 100644 include/linux/irqchip/irq-kvx-apic-gic.h
create mode 100644 include/linux/irqchip/irq-kvx-apic-mailbox.h
create mode 100644 include/linux/irqchip/irq-kvx-itgen.h
create mode 100644 scripts/gdb/arch/Makefile
create mode 100644 scripts/gdb/arch/__init__.py
create mode 100644 scripts/gdb/arch/kvx/Makefile
create mode 100644 scripts/gdb/arch/kvx/__init__.py
create mode 100644 scripts/gdb/arch/kvx/constants.py.in
create mode 100644 scripts/gdb/arch/kvx/mmu.py
create mode 100644 scripts/gdb/arch/kvx/page_table_walk.py

--
2.37.2






2023-01-03 17:20:57

by Yann Sionneau

[permalink] [raw]
Subject: [RFC PATCH 08/25] kvx: Add exception/interrupt handling

Add the exception and interrupt handling machanism for basic kvx
support.

CC: [email protected]
Co-developed-by: Clement Leger <[email protected]>
Signed-off-by: Clement Leger <[email protected]>
Co-developed-by: Guillaume Thouvenin <[email protected]>
Signed-off-by: Guillaume Thouvenin <[email protected]>
Co-developed-by: Julian Vetter <[email protected]>
Signed-off-by: Julian Vetter <[email protected]>
Co-developed-by: Luc Michel <[email protected]>
Signed-off-by: Luc Michel <[email protected]>
Co-developed-by: Marius Gligor <[email protected]>
Signed-off-by: Marius Gligor <[email protected]>
Co-developed-by: Yann Sionneau <[email protected]>
Signed-off-by: Yann Sionneau <[email protected]>
---
arch/kvx/include/asm/break_hook.h | 69 +++++++++
arch/kvx/include/asm/bug.h | 67 ++++++++
arch/kvx/include/asm/dame.h | 31 ++++
arch/kvx/include/asm/hardirq.h | 14 ++
arch/kvx/include/asm/hw_irq.h | 14 ++
arch/kvx/include/asm/ipi.h | 16 ++
arch/kvx/include/asm/irqflags.h | 58 +++++++
arch/kvx/include/asm/stacktrace.h | 44 ++++++
arch/kvx/include/asm/traps.h | 76 ++++++++++
arch/kvx/kernel/dame_handler.c | 113 ++++++++++++++
arch/kvx/kernel/irq.c | 78 ++++++++++
arch/kvx/kernel/traps.c | 243 ++++++++++++++++++++++++++++++
arch/kvx/platform/ipi.c | 110 ++++++++++++++
13 files changed, 933 insertions(+)
create mode 100644 arch/kvx/include/asm/break_hook.h
create mode 100644 arch/kvx/include/asm/bug.h
create mode 100644 arch/kvx/include/asm/dame.h
create mode 100644 arch/kvx/include/asm/hardirq.h
create mode 100644 arch/kvx/include/asm/hw_irq.h
create mode 100644 arch/kvx/include/asm/ipi.h
create mode 100644 arch/kvx/include/asm/irqflags.h
create mode 100644 arch/kvx/include/asm/stacktrace.h
create mode 100644 arch/kvx/include/asm/traps.h
create mode 100644 arch/kvx/kernel/dame_handler.c
create mode 100644 arch/kvx/kernel/irq.c
create mode 100644 arch/kvx/kernel/traps.c
create mode 100644 arch/kvx/platform/ipi.c

diff --git a/arch/kvx/include/asm/break_hook.h b/arch/kvx/include/asm/break_hook.h
new file mode 100644
index 000000000000..333b2c440c81
--- /dev/null
+++ b/arch/kvx/include/asm/break_hook.h
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Clement Leger
+ */
+
+#ifndef __ASM_KVX_BREAK_HOOK_H_
+#define __ASM_KVX_BREAK_HOOK_H_
+
+#include <linux/types.h>
+
+#include <asm/sfr_defs.h>
+#include <asm/insns_defs.h>
+
+/*
+ * The following macros define the different causes of break:
+ * We use the `set $vsfr0 = $rXX` instruction which will raise a trap into the
+ * debugger. The trapping instruction is read and decoded to extract the source
+ * register number. The source register number is used to differentiate the
+ * trap cause.
+ */
+#define BREAK_CAUSE_BUG KVX_REG_R1
+#define BREAK_CAUSE_KGDB_DYN KVX_REG_R2
+#define BREAK_CAUSE_KGDB_COMP KVX_REG_R3
+#define BREAK_CAUSE_BKPT KVX_REG_R63
+
+/**
+ * enum break_ret - Break return value
+ * @BREAK_HOOK_HANDLED: Hook handled successfully
+ * @BREAK_HOOK_ERROR: Hook was not handled
+ */
+enum break_ret {
+ BREAK_HOOK_HANDLED = 0,
+ BREAK_HOOK_ERROR = 1,
+};
+
+/*
+ * The following macro assembles a `set` instruction targeting $vsfr0
+ * using the source register whose number is __id.
+ */
+#define KVX_BREAK_INSN(__id) \
+ KVX_INSN_SET_SYLLABLE_0(KVX_INSN_PARALLEL_EOB, KVX_SFR_VSFR0, __id)
+
+#define KVX_BREAK_INSN_SIZE (KVX_INSN_SET_SIZE * KVX_INSN_SYLLABLE_WIDTH)
+
+struct pt_regs;
+
+/**
+ * struct break_hook - Break hook description
+ * @node: List node
+ * @handler: handler called when break matches this hook
+ * @imm: Immediate value expected for break insn
+ * @mode: Hook mode (user/kernel)
+ */
+struct break_hook {
+ struct list_head node;
+ int (*handler)(struct break_hook *brk_hook, struct pt_regs *regs);
+ u8 id;
+ u8 mode;
+};
+
+void kvx_skip_break_insn(struct pt_regs *regs);
+
+void break_hook_register(struct break_hook *brk_hook);
+void break_hook_unregister(struct break_hook *brk_hook);
+
+int break_hook_handler(u64 es, struct pt_regs *regs);
+
+#endif /* __ASM_KVX_BREAK_HOOK_H_ */
diff --git a/arch/kvx/include/asm/bug.h b/arch/kvx/include/asm/bug.h
new file mode 100644
index 000000000000..62f556b00d5a
--- /dev/null
+++ b/arch/kvx/include/asm/bug.h
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Clement Leger
+ */
+
+#ifndef _ASM_KVX_BUG_H
+#define _ASM_KVX_BUG_H
+
+#include <linux/compiler.h>
+#include <linux/const.h>
+#include <linux/types.h>
+
+#include <asm/break_hook.h>
+
+#ifdef CONFIG_GENERIC_BUG
+
+#define BUG_INSN KVX_BREAK_INSN(BREAK_CAUSE_BUG)
+
+#define __BUG_ENTRY_ADDR ".dword 1b"
+
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+#define __BUG_ENTRY_LAST_MEMBER flags
+#define __BUG_ENTRY \
+ __BUG_ENTRY_ADDR "\n\t" \
+ ".dword %0\n\t" \
+ ".short %1\n\t"
+#else
+#define __BUG_ENTRY_LAST_MEMBER file
+#define __BUG_ENTRY \
+ __BUG_ENTRY_ADDR "\n\t"
+#endif
+
+#define BUG() \
+do { \
+ __asm__ __volatile__ ( \
+ "1:\n\t" \
+ ".word " __stringify(BUG_INSN) "\n" \
+ ".pushsection __bug_table,\"a\"\n\t" \
+ "2:\n\t" \
+ __BUG_ENTRY \
+ ".fill 1, %2, 0\n\t" \
+ ".popsection" \
+ : \
+ : "i" (__FILE__), "i" (__LINE__), \
+ "i" (sizeof(struct bug_entry) - \
+ offsetof(struct bug_entry, __BUG_ENTRY_LAST_MEMBER))); \
+ unreachable(); \
+} while (0)
+
+#else /* CONFIG_GENERIC_BUG */
+#define BUG() \
+do { \
+ __asm__ __volatile__ (".word " __stringify(BUG_INSN) "\n"); \
+ unreachable(); \
+} while (0)
+#endif /* CONFIG_GENERIC_BUG */
+
+#define HAVE_ARCH_BUG
+
+struct pt_regs;
+
+void die(struct pt_regs *regs, unsigned long ea, const char *str);
+
+#include <asm-generic/bug.h>
+
+#endif /* _ASM_KVX_BUG_H */
diff --git a/arch/kvx/include/asm/dame.h b/arch/kvx/include/asm/dame.h
new file mode 100644
index 000000000000..8befd767bbee
--- /dev/null
+++ b/arch/kvx/include/asm/dame.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Clement Leger
+ */
+
+#ifndef _ASM_KVX_DAME_H
+#define _ASM_KVX_DAME_H
+
+#include <asm/sfr.h>
+#include <asm/ptrace.h>
+
+static inline void dame_irq_check(struct pt_regs *regs)
+{
+#ifdef CONFIG_SECURE_DAME_HANDLING
+ unsigned long ilr;
+ /* If we are returning to the kernel, no need to check for DAME */
+ if (!user_mode(regs))
+ return;
+
+ /* Else, make sure we do a barrier to trig any pending DAME IRQ */
+ __builtin_kvx_barrier();
+
+ /* Check if we triggered a DAME */
+ ilr = kvx_sfr_get(ILR);
+ if (ilr & KVX_SFR_ILR_IT16_MASK)
+ panic("DAME error encountered while in kernel !!!!\n");
+#endif
+}
+
+#endif /* _ASM_KVX_DAME_H */
diff --git a/arch/kvx/include/asm/hardirq.h b/arch/kvx/include/asm/hardirq.h
new file mode 100644
index 000000000000..f82630f7e4e2
--- /dev/null
+++ b/arch/kvx/include/asm/hardirq.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Clement Leger
+ */
+
+#ifndef _ASM_KVX_HARDIRQ_H
+#define _ASM_KVX_HARDIRQ_H
+
+#define __ARCH_IRQ_EXIT_IRQS_DISABLED 1
+
+#include <asm-generic/hardirq.h>
+
+#endif /* _ASM_KVX_HARDIRQ_H */
diff --git a/arch/kvx/include/asm/hw_irq.h b/arch/kvx/include/asm/hw_irq.h
new file mode 100644
index 000000000000..f073dba3b1c5
--- /dev/null
+++ b/arch/kvx/include/asm/hw_irq.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * derived from arch/mips/include/asm/ide.h
+ *
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Clement Leger
+ */
+
+#ifndef _ASM_KVX_HW_IRQ_H
+#define _ASM_KVX_HW_IRQ_H
+
+void kvx_init_core_irq(void);
+
+#endif /* _ASM_KVX_HW_IRQ_H */
diff --git a/arch/kvx/include/asm/ipi.h b/arch/kvx/include/asm/ipi.h
new file mode 100644
index 000000000000..137407a075e6
--- /dev/null
+++ b/arch/kvx/include/asm/ipi.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Clement Leger
+ */
+
+#ifndef _ASM_KVX_IPI_H
+#define _ASM_KVX_IPI_H
+
+#include <linux/irqreturn.h>
+
+int kvx_ipi_ctrl_probe(irqreturn_t (*ipi_irq_handler)(int, void *));
+
+void kvx_ipi_send(const struct cpumask *mask);
+
+#endif /* _ASM_KVX_IPI_H */
diff --git a/arch/kvx/include/asm/irqflags.h b/arch/kvx/include/asm/irqflags.h
new file mode 100644
index 000000000000..681c890b3fcd
--- /dev/null
+++ b/arch/kvx/include/asm/irqflags.h
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Clement Leger
+ */
+
+#ifndef _ASM_KVX_IRQFLAGS_H
+#define _ASM_KVX_IRQFLAGS_H
+
+#include <linux/types.h>
+
+#include <asm/sfr.h>
+
+static inline notrace unsigned long arch_local_save_flags(void)
+{
+ return kvx_sfr_get(PS) & (1 << KVX_SFR_PS_IE_SHIFT);
+}
+
+static inline notrace unsigned long arch_local_irq_save(void)
+{
+ unsigned long flags = arch_local_save_flags();
+
+ kvx_sfr_set_field(PS, IE, 0);
+
+ return flags;
+}
+
+static inline notrace void arch_local_irq_restore(unsigned long flags)
+{
+ /* If flags are set, interrupt are enabled), set the IE bit */
+ if (flags)
+ kvx_sfr_set_field(PS, IE, 1);
+ else
+ kvx_sfr_set_field(PS, IE, 0);
+}
+
+static inline notrace void arch_local_irq_enable(void)
+{
+ kvx_sfr_set_field(PS, IE, 1);
+}
+
+static inline notrace void arch_local_irq_disable(void)
+{
+ kvx_sfr_set_field(PS, IE, 0);
+}
+
+static inline notrace bool arch_irqs_disabled_flags(unsigned long flags)
+{
+ return (flags & (1 << KVX_SFR_PS_IE_SHIFT)) == 0;
+}
+
+static inline notrace bool arch_irqs_disabled(void)
+{
+ return arch_irqs_disabled_flags(kvx_sfr_get(PS));
+}
+
+
+#endif /* _ASM_KVX_IRQFLAGS_H */
diff --git a/arch/kvx/include/asm/stacktrace.h b/arch/kvx/include/asm/stacktrace.h
new file mode 100644
index 000000000000..0feed6bd4424
--- /dev/null
+++ b/arch/kvx/include/asm/stacktrace.h
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Clement Leger
+ */
+
+#ifndef _ASM_KVX_STACKTRACE_H
+#define _ASM_KVX_STACKTRACE_H
+
+#include <linux/sched/task_stack.h>
+
+/**
+ * Structure of a frame on the stack
+ */
+struct stackframe {
+ unsigned long fp; /* Next frame pointer */
+ unsigned long ra; /* Return address */
+};
+
+static inline bool on_task_stack(struct task_struct *tsk, unsigned long sp)
+{
+ unsigned long low = (unsigned long) task_stack_page(tsk);
+ unsigned long high = low + THREAD_SIZE;
+
+ if (sp < low || sp >= high)
+ return false;
+
+ return true;
+}
+
+void show_stacktrace(struct task_struct *task, struct pt_regs *regs);
+
+
+void walk_stackframe(struct task_struct *task, struct stackframe *frame,
+ bool (*fn)(unsigned long, void *), void *arg);
+
+static inline void start_stackframe(struct stackframe *frame,
+ unsigned long fp,
+ unsigned long pc)
+{
+ frame->fp = fp;
+ frame->ra = pc;
+}
+#endif /* _ASM_KVX_STACKTRACE_H */
diff --git a/arch/kvx/include/asm/traps.h b/arch/kvx/include/asm/traps.h
new file mode 100644
index 000000000000..77a663968135
--- /dev/null
+++ b/arch/kvx/include/asm/traps.h
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Clement Leger
+ * Guillaume Thouvenin
+ * Marius Gligor
+ */
+
+#ifndef _ASM_KVX_TRAPS_H
+#define _ASM_KVX_TRAPS_H
+
+#include <asm/sfr.h>
+
+#define KVX_TRAP_RESET 0x0
+#define KVX_TRAP_OPCODE 0x1
+#define KVX_TRAP_PRIVILEGE 0x2
+#define KVX_TRAP_DMISALIGN 0x3
+#define KVX_TRAP_PSYSERROR 0x4
+#define KVX_TRAP_DSYSERROR 0x5
+#define KVX_TRAP_PDECCERROR 0x6
+#define KVX_TRAP_DDECCERROR 0x7
+#define KVX_TRAP_PPARERROR 0x8
+#define KVX_TRAP_DPARERROR 0x9
+#define KVX_TRAP_PSECERROR 0xA
+#define KVX_TRAP_DSECERROR 0xB
+#define KVX_TRAP_NOMAPPING 0xC
+#define KVX_TRAP_PROTECTION 0xD
+#define KVX_TRAP_WRITETOCLEAN 0xE
+#define KVX_TRAP_ATOMICTOCLEAN 0xF
+#define KVX_TRAP_TPAR 0x10
+#define KVX_TRAP_DOUBLE_ECC 0x11
+#define KVX_TRAP_VSFR 0x12
+#define KVX_TRAP_PL_OVERFLOW 0x13
+
+#define KVX_TRAP_COUNT 0x14
+
+#define KVX_TRAP_SFRI_NOT_BCU 0
+#define KVX_TRAP_SFRI_GET 1
+#define KVX_TRAP_SFRI_IGET 2
+#define KVX_TRAP_SFRI_SET 4
+#define KVX_TRAP_SFRI_WFXL 5
+#define KVX_TRAP_SFRI_WFXM 6
+#define KVX_TRAP_SFRI_RSWAP 7
+
+/* Access type on memory trap */
+#define KVX_TRAP_RWX_FETCH 1
+#define KVX_TRAP_RWX_WRITE 2
+#define KVX_TRAP_RWX_READ 4
+#define KVX_TRAP_RWX_ATOMIC 6
+
+#ifndef __ASSEMBLY__
+
+typedef void (*trap_handler_func) (uint64_t es, uint64_t ea,
+ struct pt_regs *regs);
+
+#define trap_cause(__es) kvx_sfr_field_val(__es, ES, HTC)
+
+#define trap_sfri(__es) \
+ kvx_sfr_field_val((__es), ES, SFRI)
+
+#define trap_gprp(__es) \
+ kvx_sfr_field_val((__es), ES, GPRP)
+
+#define trap_sfrp(__es) \
+ kvx_sfr_field_val((__es), ES, SFRP)
+
+#ifdef CONFIG_MMU
+extern void do_page_fault(uint64_t es, uint64_t ea, struct pt_regs *regs);
+extern void do_writetoclean(uint64_t es, uint64_t ea, struct pt_regs *regs);
+#endif
+
+void user_do_sig(struct pt_regs *regs, int signo, int code, unsigned long addr);
+
+#endif /* __ASSEMBLY__ */
+
+#endif
diff --git a/arch/kvx/kernel/dame_handler.c b/arch/kvx/kernel/dame_handler.c
new file mode 100644
index 000000000000..ce190bee8211
--- /dev/null
+++ b/arch/kvx/kernel/dame_handler.c
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Clement Leger
+ */
+
+#include <linux/of.h>
+#include <linux/bug.h>
+#include <linux/init.h>
+#include <linux/of_irq.h>
+#include <linux/hardirq.h>
+#include <linux/irqchip.h>
+#include <linux/irqdomain.h>
+#include <linux/interrupt.h>
+#include <linux/cpuhotplug.h>
+#include <linux/sched/signal.h>
+
+static unsigned int kvx_dame_irq;
+
+static const char *error_str[KVX_SFR_ES_ITI_WIDTH] = {
+ "PSE",
+ "PILSY",
+ "PILDE",
+ "PILPA",
+ "DSE",
+ "DILSY",
+ "DILDE",
+ "DILPA",
+ "DDEE",
+ "DSYE"
+};
+
+static irqreturn_t dame_irq_handler(int irq, void *dev_id)
+{
+ int bit;
+ struct pt_regs *regs = get_irq_regs();
+ unsigned long error_status = kvx_sfr_field_val(regs->es, ES, ITI);
+
+ if (error_status) {
+ pr_err("Memory Error:\n");
+ for_each_set_bit(bit, &error_status, KVX_SFR_ES_ITI_WIDTH)
+ pr_err("- %s\n", error_str[bit]);
+ }
+
+ /*
+ * If the DAME happened in user mode, we can handle it properly
+ * by killing the user process.
+ * Otherwise, if we are in kernel, we are fried...
+ */
+ if (user_mode(regs))
+ force_sig_fault(SIGBUS, BUS_ADRERR, (void __user *) NULL);
+ else
+ die(regs, 0, "DAME error encountered while in kernel !!!!\n");
+
+ return IRQ_HANDLED;
+}
+
+static int kvx_dame_starting_cpu(unsigned int cpu)
+{
+ enable_percpu_irq(kvx_dame_irq, IRQ_TYPE_NONE);
+
+ return 0;
+}
+
+static int kvx_dame_dying_cpu(unsigned int cpu)
+{
+ disable_percpu_irq(kvx_dame_irq);
+
+ return 0;
+}
+
+static int __init dame_handler_init(void)
+{
+ struct device_node *dame_node;
+ int ret;
+
+ dame_node = of_find_compatible_node(NULL, NULL,
+ "kalray,kvx-dame-handler");
+ if (!dame_node) {
+ pr_err("Failed to find dame handler device tree node\n");
+ return -ENODEV;
+ }
+
+ kvx_dame_irq = irq_of_parse_and_map(dame_node, 0);
+ of_node_put(dame_node);
+
+ if (!kvx_dame_irq) {
+ pr_err("Failed to parse dame irq\n");
+ return -ENODEV;
+ }
+
+ ret = request_percpu_irq(kvx_dame_irq, dame_irq_handler, "dame",
+ &kvx_dame_irq);
+ if (ret) {
+ pr_err("Failed to request dame irq\n");
+ return -ENODEV;
+ }
+
+ ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
+ "kvx/dame_handler:online",
+ kvx_dame_starting_cpu,
+ kvx_dame_dying_cpu);
+ if (ret <= 0) {
+ pr_err("Failed to setup cpuhp\n");
+ return ret;
+ }
+
+ pr_info("DAME handler registered\n");
+
+ return 0;
+}
+
+core_initcall(dame_handler_init);
diff --git a/arch/kvx/kernel/irq.c b/arch/kvx/kernel/irq.c
new file mode 100644
index 000000000000..5d7c8cfba1dd
--- /dev/null
+++ b/arch/kvx/kernel/irq.c
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Clement Leger
+ */
+
+#include <linux/irqdomain.h>
+#include <linux/irqflags.h>
+#include <linux/hardirq.h>
+#include <linux/irqchip.h>
+#include <linux/bitops.h>
+#include <linux/init.h>
+
+#include <asm/dame.h>
+
+#define IT_MASK(__it) (KVX_SFR_ILL_ ## __it ## _MASK)
+#define IT_LEVEL(__it, __level) \
+ (__level##ULL << KVX_SFR_ILL_ ## __it ## _SHIFT)
+
+void do_IRQ(unsigned long hwirq_mask, struct pt_regs *regs)
+{
+ struct pt_regs *old_regs = set_irq_regs(regs);
+ int irq;
+ unsigned int hwirq;
+
+ trace_hardirqs_off();
+
+ irq_enter();
+
+ while (hwirq_mask) {
+ hwirq = __ffs(hwirq_mask);
+ irq = irq_find_mapping(NULL, hwirq);
+ generic_handle_irq(irq);
+ hwirq_mask &= ~BIT_ULL(hwirq);
+ }
+
+ irq_exit();
+ set_irq_regs(old_regs);
+
+ dame_irq_check(regs);
+}
+
+/*
+ * Early Hardware specific Interrupt setup
+ * -Called very early (start_kernel -> setup_arch -> setup_processor)
+ * -Needed for each CPU
+ */
+void kvx_init_core_irq(void)
+{
+ /*
+ * On KVX, Kernel only care about the following IT:
+ * - IT0: Timer 0
+ * - IT2: Watchdog
+ * - IT4: APIC IT 1
+ * - IT24: IPI
+ */
+ uint64_t mask = IT_MASK(IT0) | IT_MASK(IT2) | IT_MASK(IT4) |
+ IT_MASK(IT24);
+
+ /*
+ * Specific priorities for ITs:
+ * - Watchdog has the highest priority: 3
+ * - Timer has priority 2
+ * - APIC entries have lowest priority: 1
+ */
+ uint64_t value = IT_LEVEL(IT0, 0x2) | IT_LEVEL(IT2, 0x3) |
+ IT_LEVEL(IT4, 0x1) | IT_LEVEL(IT24, 0x1);
+
+ kvx_sfr_set_mask(ILL, mask, value);
+
+ /* Set core level to 0 */
+ kvx_sfr_set_field(PS, IL, 0);
+}
+
+void __init init_IRQ(void)
+{
+ irqchip_init();
+}
diff --git a/arch/kvx/kernel/traps.c b/arch/kvx/kernel/traps.c
new file mode 100644
index 000000000000..3a1706b666c2
--- /dev/null
+++ b/arch/kvx/kernel/traps.c
@@ -0,0 +1,243 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Clement Leger
+ * Guillaume Thouvenin
+ * Marius Gligor
+ */
+
+#include <linux/context_tracking.h>
+#include <linux/sched/task_stack.h>
+#include <linux/sched/debug.h>
+#include <linux/irqflags.h>
+#include <linux/uaccess.h>
+#include <linux/kdebug.h>
+#include <linux/module.h>
+#include <linux/printk.h>
+#include <linux/init.h>
+#include <linux/ptrace.h>
+
+#include <asm/dame.h>
+#include <asm/traps.h>
+#include <asm/ptrace.h>
+#include <asm/break_hook.h>
+#include <asm/stacktrace.h>
+
+int show_unhandled_signals = 1;
+
+static DEFINE_SPINLOCK(die_lock);
+
+static trap_handler_func trap_handler_table[KVX_TRAP_COUNT] = { NULL };
+
+/* Trap names associated to the trap numbers */
+static const char * const trap_name[] = {
+ "RESET",
+ "OPCODE",
+ "PRIVILEGE",
+ "DMISALIGN",
+ "PSYSERROR",
+ "DSYSERROR",
+ "PDECCERROR",
+ "DDECCERROR",
+ "PPARERROR",
+ "DPARERROR",
+ "PSECERROR",
+ "DSECERROR",
+ /* MMU related traps */
+ "NOMAPPING",
+ "PROTECTION",
+ "WRITETOCLEAN",
+ "ATOMICTOCLEAN",
+ "TPAR",
+ "DOUBLE_ECC",
+ "VSFR",
+ "PL_OVERFLOW"
+};
+
+void die(struct pt_regs *regs, unsigned long ea, const char *str)
+{
+ static int die_counter;
+ int ret;
+
+ oops_enter();
+
+ spin_lock_irq(&die_lock);
+ console_verbose();
+ bust_spinlocks(1);
+
+ pr_emerg("%s [#%d]\n", str, ++die_counter);
+ print_modules();
+ show_regs(regs);
+
+ if (!user_mode(regs))
+ show_stacktrace(NULL, regs);
+
+ ret = notify_die(DIE_OOPS, str, regs, ea, 0, SIGSEGV);
+
+ bust_spinlocks(0);
+ add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
+ spin_unlock_irq(&die_lock);
+ oops_exit();
+
+ if (in_interrupt())
+ panic("Fatal exception in interrupt");
+ if (panic_on_oops)
+ panic("Fatal exception");
+ if (ret != NOTIFY_STOP)
+ make_task_dead(SIGSEGV);
+}
+
+void user_do_sig(struct pt_regs *regs, int signo, int code, unsigned long addr)
+{
+ struct task_struct *tsk = current;
+
+ if (show_unhandled_signals && unhandled_signal(tsk, signo)
+ && printk_ratelimit()) {
+ pr_info("%s[%d]: unhandled signal %d code 0x%x at 0x%lx",
+ tsk->comm, task_pid_nr(tsk), signo, code, addr);
+ print_vma_addr(KERN_CONT " in ", instruction_pointer(regs));
+ pr_cont("\n");
+ show_regs(regs);
+ }
+ if (signo == SIGKILL) {
+ force_sig(signo);
+ return;
+ }
+ force_sig_fault(signo, code, (void __user *) addr);
+}
+
+static void panic_or_kill(uint64_t es, uint64_t ea, struct pt_regs *regs,
+ int signo, int sigcode)
+{
+ if (user_mode(regs)) {
+ user_do_sig(regs, signo, sigcode, ea);
+ return;
+ }
+
+ pr_alert(CUT_HERE "ERROR: TRAP %s received at 0x%.16llx\n",
+ trap_name[trap_cause(es)], regs->spc);
+ die(regs, ea, "Oops");
+ make_task_dead(SIGKILL);
+}
+
+int is_valid_bugaddr(unsigned long pc)
+{
+ /*
+ * Since the bug was reported, this means that the break hook handling
+ * already check the faulting instruction so there is no need for
+ * additionnal check here. This is a BUG for sure.
+ */
+ return 1;
+}
+
+static int bug_break_handler(struct break_hook *brk_hook, struct pt_regs *regs)
+{
+ enum bug_trap_type type;
+
+ type = report_bug(regs->spc, regs);
+ switch (type) {
+ case BUG_TRAP_TYPE_NONE:
+ return BREAK_HOOK_ERROR;
+ case BUG_TRAP_TYPE_WARN:
+ break;
+ case BUG_TRAP_TYPE_BUG:
+ die(regs, regs->spc, "Kernel BUG");
+ break;
+ }
+
+ /* Skip over break insn if we survived ! */
+ kvx_skip_break_insn(regs);
+
+ return BREAK_HOOK_HANDLED;
+}
+
+static struct break_hook bug_break_hook = {
+ .handler = bug_break_handler,
+ .id = BREAK_CAUSE_BUG,
+ .mode = MODE_KERNEL,
+};
+
+#define GEN_TRAP_HANDLER(__name, __sig, __code) \
+static void __name ## _trap_handler(uint64_t es, uint64_t ea, \
+ struct pt_regs *regs) \
+{ \
+ panic_or_kill(es, ea, regs, __sig, __code); \
+}
+
+GEN_TRAP_HANDLER(default, SIGKILL, SI_KERNEL);
+GEN_TRAP_HANDLER(privilege, SIGILL, ILL_PRVREG);
+GEN_TRAP_HANDLER(dmisalign, SIGBUS, BUS_ADRALN);
+GEN_TRAP_HANDLER(syserror, SIGBUS, BUS_ADRERR);
+GEN_TRAP_HANDLER(opcode, SIGILL, ILL_ILLOPC);
+
+static void register_trap_handler(unsigned int trap_nb, trap_handler_func fn)
+{
+
+ if (trap_nb >= KVX_TRAP_COUNT || fn == NULL)
+ panic("Failed to register handler #%d\n", trap_nb);
+
+ trap_handler_table[trap_nb] = fn;
+}
+
+static void do_vsfr_fault(uint64_t es, uint64_t ea, struct pt_regs *regs)
+{
+ if (break_hook_handler(es, regs) == BREAK_HOOK_HANDLED)
+ return;
+
+ panic_or_kill(es, ea, regs, SIGILL, ILL_PRVREG);
+}
+
+void __init trap_init(void)
+{
+ int i;
+
+ break_hook_register(&bug_break_hook);
+
+ for (i = 0; i < KVX_TRAP_COUNT; i++)
+ register_trap_handler(i, default_trap_handler);
+#ifdef CONFIG_MMU
+ register_trap_handler(KVX_TRAP_NOMAPPING, do_page_fault);
+ register_trap_handler(KVX_TRAP_PROTECTION, do_page_fault);
+ register_trap_handler(KVX_TRAP_WRITETOCLEAN, do_writetoclean);
+#endif
+
+ register_trap_handler(KVX_TRAP_PSYSERROR, syserror_trap_handler);
+ register_trap_handler(KVX_TRAP_DSYSERROR, syserror_trap_handler);
+ register_trap_handler(KVX_TRAP_PRIVILEGE, privilege_trap_handler);
+ register_trap_handler(KVX_TRAP_OPCODE, opcode_trap_handler);
+ register_trap_handler(KVX_TRAP_DMISALIGN, dmisalign_trap_handler);
+ register_trap_handler(KVX_TRAP_VSFR, do_vsfr_fault);
+}
+
+/**
+ * trap_handler - trap handler called by _trap_handler routine in trap_handler.S
+ * This handler will redirect to other trap handlers if present
+ * If not then it will do a generic action
+ * @es: Exception Syndrome register value
+ * @ea: Exception Address register
+ * @regs: pointer to registers saved when trapping
+ */
+void trap_handler(uint64_t es, uint64_t ea, struct pt_regs *regs)
+{
+ enum ctx_state prev_state = exception_enter();
+ int htc = trap_cause(es);
+ trap_handler_func trap_func = trap_handler_table[htc];
+
+ trace_hardirqs_off();
+
+ /* Normal traps number should and must be between 0 and 15 included */
+ if (unlikely(htc >= KVX_TRAP_COUNT)) {
+ pr_err("Invalid trap %d !\n", htc);
+ goto done;
+ }
+
+ /* If irqs were enabled in the preempted context, reenable them */
+ if (regs->sps & KVX_SFR_PS_IE_MASK)
+ local_irq_enable();
+
+ trap_func(es, ea, regs);
+
+done:
+ dame_irq_check(regs);
+ exception_exit(prev_state);
+}
diff --git a/arch/kvx/platform/ipi.c b/arch/kvx/platform/ipi.c
new file mode 100644
index 000000000000..73d1de27a628
--- /dev/null
+++ b/arch/kvx/platform/ipi.c
@@ -0,0 +1,110 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Clement Leger
+ * Luc Michel
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/cpumask.h>
+#include <linux/interrupt.h>
+#include <linux/cpuhotplug.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+
+#define IPI_INTERRUPT_OFFSET 0x0
+#define IPI_MASK_OFFSET 0x20
+
+/*
+ * IPI controller can signal RM and PE0 -> 15
+ * In order to restrict that to the PE, write the corresponding mask
+ */
+#define KVX_IPI_CPU_MASK (~0xFFFF)
+
+struct kvx_ipi_ctrl {
+ void __iomem *regs;
+ unsigned int ipi_irq;
+};
+
+static struct kvx_ipi_ctrl kvx_ipi_controller;
+
+/**
+ * @kvx_pwr_ctrl_cpu_poweron Wakeup a cpu
+ *
+ * cpu: cpu to wakeup
+ */
+void kvx_ipi_send(const struct cpumask *mask)
+{
+ const unsigned long *maskb = cpumask_bits(mask);
+
+ WARN_ON(*maskb & KVX_IPI_CPU_MASK);
+ writel(*maskb, kvx_ipi_controller.regs + IPI_INTERRUPT_OFFSET);
+}
+
+static int kvx_ipi_starting_cpu(unsigned int cpu)
+{
+ enable_percpu_irq(kvx_ipi_controller.ipi_irq, IRQ_TYPE_NONE);
+
+ return 0;
+}
+
+static int kvx_ipi_dying_cpu(unsigned int cpu)
+{
+ disable_percpu_irq(kvx_ipi_controller.ipi_irq);
+
+ return 0;
+}
+
+int __init kvx_ipi_ctrl_probe(irqreturn_t (*ipi_irq_handler)(int, void *))
+{
+ struct device_node *np;
+ int ret;
+ unsigned int ipi_irq;
+ void __iomem *ipi_base;
+
+ np = of_find_compatible_node(NULL, NULL, "kalray,kvx-ipi-ctrl");
+ BUG_ON(!np);
+
+ ipi_base = of_iomap(np, 0);
+ BUG_ON(!ipi_base);
+
+ kvx_ipi_controller.regs = ipi_base;
+
+ /* Init mask for interrupts to PE0 -> PE15 */
+ writel(KVX_IPI_CPU_MASK, kvx_ipi_controller.regs + IPI_MASK_OFFSET);
+
+ ipi_irq = irq_of_parse_and_map(np, 0);
+ of_node_put(np);
+ if (!ipi_irq) {
+ pr_err("Failed to parse irq: %d\n", ipi_irq);
+ return -EINVAL;
+ }
+
+ ret = request_percpu_irq(ipi_irq, ipi_irq_handler,
+ "kvx_ipi", &kvx_ipi_controller);
+ if (ret) {
+ pr_err("can't register interrupt %d (%d)\n",
+ ipi_irq, ret);
+ return ret;
+ }
+ kvx_ipi_controller.ipi_irq = ipi_irq;
+
+ ret = cpuhp_setup_state(CPUHP_AP_IRQ_KVX_STARTING,
+ "kvx/ipi:online",
+ kvx_ipi_starting_cpu,
+ kvx_ipi_dying_cpu);
+ if (ret < 0) {
+ pr_err("Failed to setup hotplug state");
+ return ret;
+ }
+
+ pr_info("controller probed\n");
+
+ return 0;
+}
--
2.37.2





2023-01-03 17:21:21

by Yann Sionneau

[permalink] [raw]
Subject: [RFC PATCH 21/25] kvx: Add support for ftrace

Add support for ftrace to kvx arch.

CC: Steven Rostedt <[email protected]>
CC: Masami Hiramatsu <[email protected]>
CC: Mark Rutland <[email protected]>
CC: [email protected]
Co-developed-by: Clement Leger <[email protected]>
Signed-off-by: Clement Leger <[email protected]>
Co-developed-by: Guillaume Thouvenin <[email protected]>
Signed-off-by: Guillaume Thouvenin <[email protected]>
Co-developed-by: Julian Vetter <[email protected]>
Signed-off-by: Julian Vetter <[email protected]>
Co-developed-by: Marius Gligor <[email protected]>
Signed-off-by: Marius Gligor <[email protected]>
Co-developed-by: Yann Sionneau <[email protected]>
Signed-off-by: Yann Sionneau <[email protected]>
---
arch/kvx/include/asm/ftrace.h | 41 ++++
arch/kvx/kernel/ftrace.c | 339 ++++++++++++++++++++++++++++++
arch/kvx/kernel/mcount.S | 340 +++++++++++++++++++++++++++++++
arch/kvx/kernel/return_address.c | 55 +++++
4 files changed, 775 insertions(+)
create mode 100644 arch/kvx/include/asm/ftrace.h
create mode 100644 arch/kvx/kernel/ftrace.c
create mode 100644 arch/kvx/kernel/mcount.S
create mode 100644 arch/kvx/kernel/return_address.c

diff --git a/arch/kvx/include/asm/ftrace.h b/arch/kvx/include/asm/ftrace.h
new file mode 100644
index 000000000000..f7bcb325d255
--- /dev/null
+++ b/arch/kvx/include/asm/ftrace.h
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Guillaume Thouvenin
+ * Clement Leger
+ */
+
+#ifndef _ASM_KVX_FTRACE_H
+#define _ASM_KVX_FTRACE_H
+
+#include <asm/insns_defs.h>
+
+#define INSN_MAKE_IMM64_SYLLABLE_SIZE INSN_SIZE(MAKE_IMM64)
+#define INSN_ICALL_SYLLABLE_SIZE INSN_SIZE(ICALL)
+#define INSN_IGOTO_SYLLABLE_SIZE INSN_SIZE(IGOTO)
+#define INSN_CALL_SYLLABLE_SIZE INSN_SIZE(CALL)
+#define INSN_NOP_SYLLABLE_SIZE INSN_SIZE(NOP)
+
+#define INSN_ICALL_REG_MASK 0x3f
+
+#define MCOUNT_ADDR ((unsigned long)(__mcount))
+#define MCOUNT_INSN_SIZE INSN_CALL_SYLLABLE_SIZE /* sizeof mcount call */
+
+extern void ftrace_graph_call(void);
+
+#ifdef CONFIG_DYNAMIC_FTRACE
+extern unsigned long ftrace_call_adjust(unsigned long addr);
+struct dyn_arch_ftrace {
+ unsigned int insn;
+};
+#endif
+
+extern void *return_address(unsigned int level);
+#define ftrace_return_address(n) return_address(n)
+
+#ifdef CONFIG_FUNCTION_TRACER
+extern void __mcount(void);
+#define mcount __mcount
+#endif /* CONFIG_FUNCTION_TRACER */
+
+#endif /* _ASM_KVX_FTRACE_H */
diff --git a/arch/kvx/kernel/ftrace.c b/arch/kvx/kernel/ftrace.c
new file mode 100644
index 000000000000..4c9e3ef62714
--- /dev/null
+++ b/arch/kvx/kernel/ftrace.c
@@ -0,0 +1,339 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Guillaume Thouvenin
+ * Marius Gligor
+ * Clement Leger
+ */
+
+#include <linux/ftrace.h>
+#include <linux/atomic.h>
+#include <linux/stop_machine.h>
+#include <asm/insns.h>
+#include <asm/insns_defs.h>
+#include <asm/cacheflush.h>
+
+/* The longest insns we check are for the far call: make + icall */
+#define MAX_SYLLABLES_TO_CHECK (KVX_INSN_MAKE_IMM64_SIZE + INSN_ICALL_SYLLABLE_SIZE)
+
+static int read_insns_and_check(u32 *insns, u8 insns_len, u32 *addr)
+{
+ u32 insns_read[MAX_SYLLABLES_TO_CHECK];
+ int syllables = insns_len / KVX_INSN_SYLLABLE_WIDTH;
+ int i;
+
+ if (syllables > MAX_SYLLABLES_TO_CHECK) {
+ pr_err("%s: shouldn't have more than %d syllables to check\n",
+ __func__, MAX_SYLLABLES_TO_CHECK);
+ return -EINVAL;
+ }
+
+ if (kvx_insns_read(insns_read, insns_len, addr)) {
+ pr_err("%s: error when trying to read syllable\n", __func__);
+ return -EFAULT;
+ }
+
+ for (i = 0; i < syllables; i++) {
+ if (insns[i] != insns_read[i]) {
+ pr_err("%s: Instruction verification failed at PC 0x%lx\n",
+ __func__,
+ (unsigned long)addr + i * KVX_INSN_SYLLABLE_WIDTH);
+ pr_err("%s: \tExpect 0x%x\n", __func__, insns[i]);
+ pr_err("%s: \tRead 0x%x\n", __func__, insns_read[i]);
+ return -EFAULT;
+ }
+ }
+
+ return 0;
+}
+
+static int write_insns_and_check(u32 *insns, u8 insns_len, u32 *insn_addr)
+{
+ int ret;
+
+ ret = kvx_insns_write_nostop(insns, insns_len, insn_addr);
+ if (ret)
+ return ret;
+
+ /* Check that what have been written is correct. */
+ return read_insns_and_check(insns, insns_len, insn_addr);
+}
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
+ unsigned long frame_pointer)
+{
+ unsigned long return_hooker = (unsigned long)&return_to_handler;
+ unsigned long old;
+
+ if (unlikely(atomic_read(&current->tracing_graph_pause)))
+ return;
+
+ old = *parent;
+ *parent = return_hooker;
+
+ if (function_graph_enter(old, self_addr, frame_pointer, NULL))
+ *parent = old;
+}
+
+#ifdef CONFIG_DYNAMIC_FTRACE
+int ftrace_enable_ftrace_graph_caller(void)
+{
+ unsigned int insn[KVX_INSN_MAKE_IMM64_SIZE + KVX_INSN_IGOTO_SIZE];
+ void *ip = (void *)ftrace_call;
+
+ KVX_INSN_MAKE_IMM64(insn, KVX_INSN_PARALLEL_EOB, KVX_REG_R32,
+ (unsigned long)&ftrace_graph_call);
+ KVX_INSN_IGOTO(&insn[KVX_INSN_MAKE_IMM64_SIZE],
+ KVX_INSN_PARALLEL_EOB,
+ KVX_REG_R32);
+
+ return write_insns_and_check(insn,
+ INSN_MAKE_IMM64_SYLLABLE_SIZE
+ + INSN_IGOTO_SYLLABLE_SIZE,
+ ip);
+}
+
+int ftrace_disable_ftrace_graph_caller(void)
+{
+ unsigned int nop;
+ void *ip = (void *)ftrace_call;
+
+ KVX_INSN_NOP(&nop, KVX_INSN_PARALLEL_EOB);
+ return write_insns_and_check(&nop,
+ INSN_NOP_SYLLABLE_SIZE,
+ ip + INSN_MAKE_IMM64_SYLLABLE_SIZE);
+}
+#endif /* CONFIG_DYNAMIC_FTRACE */
+
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+
+#ifdef CONFIG_DYNAMIC_FTRACE
+struct kvx_ftrace_modify_param {
+ atomic_t cpu_ack;
+ int cpu_master;
+ int cmd;
+};
+
+static int __ftrace_modify_code_kvx(void *data)
+{
+ struct kvx_ftrace_modify_param *mp = data;
+ int no_cpus = num_online_cpus();
+ int cpu = smp_processor_id();
+
+ if (cpu == mp->cpu_master) {
+ ftrace_modify_all_code(mp->cmd);
+
+ /* Inform the other cpus that they can invalidate I-cache */
+ atomic_inc(&mp->cpu_ack);
+
+ /* param (which contains the cpu_ack counter) is allocated on the
+ * master stack: the master must wait for all other CPUs to leave
+ * this function before returning and releasing the stack
+ * allocation.
+ */
+ while (atomic_read(&mp->cpu_ack) < no_cpus)
+ cpu_relax();
+ } else {
+ /* Wait for the master cpu to finish the code modification */
+ while (atomic_read(&mp->cpu_ack) == 0)
+ cpu_relax();
+ atomic_inc(&mp->cpu_ack);
+
+ l1_inval_icache_all();
+ }
+
+ return 0;
+}
+
+void arch_ftrace_update_code(int command)
+{
+ const struct cpumask *cpumask = cpu_online_mask;
+ struct kvx_ftrace_modify_param mp = {
+ .cpu_ack = ATOMIC_INIT(0),
+ .cpu_master = smp_processor_id(),
+ .cmd = command,
+ };
+
+ stop_machine(__ftrace_modify_code_kvx, &mp, cpu_online_mask);
+}
+
+unsigned long ftrace_call_adjust(unsigned long addr)
+{
+ /*
+ * Module are using far call and kernel functions are using
+ * pcrel. If it is a call we don't need to adjust the address but
+ * if it is an icall the address is on the make. The generated code
+ * looks like:
+ *
+ * 1c: e0 00 c4 8f get $r32 = $ra
+ * 20: 00 00 84 e0 00 00 00 80 00 00 00 00 make $r33 = 0 (0x0);;
+ *
+ * 20: R_KVX_S64_LO10 __mcount
+ * 24: R_KVX_S64_UP27 __mcount
+ * 28: R_KVX_S64_EX27 __mcount
+ * 2c: 21 00 dc 0f icall $r33;;
+ *
+ * So we just need to add INSN_MAKE_IMM64_SYLLABLE_SIZE (0xc) to the
+ * address.
+ */
+ unsigned int insn;
+
+ /*
+ * The CALL is 1 syllable while the MAKE IMM64 is 3. But we just
+ * need to check that the first syllable of the MAKE IMM64 is the
+ * LO10. So finally we just need to read one syllable to adjust the
+ * call.
+ */
+ if (kvx_insns_read(&insn, KVX_INSN_SYLLABLE_WIDTH, (void *)addr)) {
+ pr_err("%s: error when trying to read syllable\n", __func__);
+ return 0;
+ }
+
+ if (IS_INSN(insn, CALL))
+ return addr;
+
+ if (IS_INSN(insn, MAKE_IMM64))
+ return addr + INSN_MAKE_IMM64_SYLLABLE_SIZE;
+
+ pr_err("%s: syllable is neither a CALL nor a MAKE\n", __func__);
+ return 0;
+}
+
+/*
+ * Do runtime patching of the active tracer.
+ * This will be modifying the assembly code at the location of the
+ * ftrace_call symbol inside of the ftrace_caller() function.
+ */
+int ftrace_update_ftrace_func(ftrace_func_t func)
+{
+ void *ip;
+ unsigned int insn[KVX_INSN_MAKE_IMM64_SIZE + KVX_INSN_ICALL_SIZE];
+
+ ip = (void *)ftrace_call;
+ KVX_INSN_MAKE_IMM64(insn, KVX_INSN_PARALLEL_EOB, KVX_REG_R32,
+ (unsigned long)func);
+ KVX_INSN_ICALL(&insn[KVX_INSN_MAKE_IMM64_SIZE],
+ KVX_INSN_PARALLEL_EOB,
+ KVX_REG_R32);
+ return write_insns_and_check(insn,
+ INSN_MAKE_IMM64_SYLLABLE_SIZE
+ + INSN_ICALL_SYLLABLE_SIZE,
+ ip);
+}
+
+/*
+ * Turn the mcount call site into a call to an arbitrary location (but
+ * typically that is ftrace_caller()) at runtime.
+ */
+int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+{
+ void *ip = (void *)rec->ip;
+ unsigned int insn;
+ int ret;
+
+ /* Ensure that a NOP will be replaced */
+ if (kvx_insns_read(&insn, KVX_INSN_SYLLABLE_WIDTH, ip)) {
+ pr_err("%s: failed to read insn\n", __func__);
+ return -EFAULT;
+ }
+
+ if (!IS_INSN(insn, NOP)) {
+ pr_err("%s: insn 0x%x is not a NOP\n", __func__, insn);
+ return -EINVAL;
+ }
+
+ /*
+ * Now we can replace the instruction depending of what has been
+ * nopified (call or icall)
+ */
+ insn = rec->arch.insn;
+
+ if (IS_INSN(insn, CALL)) {
+ s32 pcrel = addr - (unsigned long) ip;
+ u32 insn_call;
+
+ BUG_ON(KVX_INSN_GOTO_PCREL27_CHECK(pcrel));
+ KVX_INSN_CALL(&insn_call, KVX_INSN_PARALLEL_EOB, pcrel);
+
+ return write_insns_and_check(&insn_call,
+ INSN_CALL_SYLLABLE_SIZE, ip);
+ }
+
+ if (IS_INSN(insn, ICALL)) {
+ u32 insn_make[KVX_INSN_MAKE_IMM64_SIZE];
+ u32 r = insn & INSN_ICALL_REG_MASK;
+
+ KVX_INSN_MAKE_IMM64(insn_make, KVX_INSN_PARALLEL_EOB, r, addr);
+ ret = write_insns_and_check(insn_make,
+ INSN_MAKE_IMM64_SYLLABLE_SIZE,
+ ip - INSN_MAKE_IMM64_SYLLABLE_SIZE);
+ if (ret)
+ return ret;
+
+ return write_insns_and_check(&insn,
+ INSN_ICALL_SYLLABLE_SIZE, ip);
+ }
+
+ /* It is neither a call nor an icall */
+ pr_err("%s: insn 0x%x is neither a CALL nor ICALL\n", __func__, insn);
+ return -EINVAL;
+}
+
+/*
+ * Turn the mcount call site into a nop at runtime
+ */
+int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
+ unsigned long addr)
+{
+ unsigned long ip = rec->ip;
+ unsigned int insn;
+ unsigned int nop;
+
+ /*
+ * Ensure that the instruction that will be replaced is a call or an
+ * icall to addr.
+ */
+ if (kvx_insns_read(&insn, KVX_INSN_SYLLABLE_WIDTH, (void *)ip)) {
+ pr_err("%s: error when trying to read syllable\n", __func__);
+ return -EFAULT;
+ }
+
+ if (IS_INSN(insn, CALL)) {
+ int pcrel = ((int)(insn & 0x7ffffff) << 5) >> 3;
+
+ if ((ip + pcrel != addr)) {
+ pr_err("%s: failed to check call addr 0x%lx != 0x%lx\n",
+ __func__, ip + pcrel, addr);
+ return -EINVAL;
+ }
+ } else if (IS_INSN(insn, ICALL)) {
+ unsigned int insn_make[KVX_INSN_MAKE_IMM64_SIZE];
+ unsigned int reg = insn & INSN_ICALL_REG_MASK;
+ int ret;
+
+ KVX_INSN_MAKE_IMM64(insn_make,
+ KVX_INSN_PARALLEL_EOB, reg,
+ addr);
+
+ ret = read_insns_and_check(insn_make,
+ INSN_MAKE_IMM64_SYLLABLE_SIZE,
+ (void *)ip -
+ INSN_MAKE_IMM64_SYLLABLE_SIZE);
+ if (ret)
+ return ret;
+ } else {
+ pr_err("%s: insn 0x%x is neither a CALL nor an ICALL\n",
+ __func__, insn);
+ return -EINVAL;
+ }
+
+ rec->arch.insn = insn;
+ KVX_INSN_NOP(&nop, KVX_INSN_PARALLEL_EOB);
+ return write_insns_and_check(&nop, INSN_NOP_SYLLABLE_SIZE, (void *)ip);
+}
+
+#endif /* CONFIG_DYNAMIC_FTRACE */
+
+/* __mcount is defined in mcount.S */
+EXPORT_SYMBOL(__mcount);
diff --git a/arch/kvx/kernel/mcount.S b/arch/kvx/kernel/mcount.S
new file mode 100644
index 000000000000..317797aeed42
--- /dev/null
+++ b/arch/kvx/kernel/mcount.S
@@ -0,0 +1,340 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Guillaume Thouvenin
+ * Marius Gligor
+ * Clement Leger
+ */
+
+#include <linux/linkage.h>
+#include <asm/insns_defs.h>
+#include <asm/sfr_defs.h>
+
+.altmacro
+
+/*
+ * !!! The call to __mcount is special and breaks the ABI !!!
+ * It is because with dynamic ftrace the call can be replaced by any
+ * tracer and GCC cannot assume which caller registers must be saved.
+ * It's because the call is being inserted in the prologue of functions
+ * that is out of GCC knowledge.
+ * We could make this known to GCC, but then we would hit the problem of not
+ * being able to easily decide which insns are emitted and how they are
+ * bundled. So we choose to save nothing when calling __mcount and we will
+ * save all caller registers once __mcount called.
+ *
+ * Another specificity is that parameter is passed in $r32 instead of $r0.
+ *
+ * Our stack will be:
+ * 0 | $FP $RA $r15 -
+ * 32 | $r0 $r1 $r2 $r3
+ * 64 | $r4 $r5 $r6 $r7
+ * 96 | $r8 $r9 $r10 $r11
+ * 128| $r32 $r33 $r34 $r35
+ * 160| $r36 $r37 $r38 $r39
+ * 192| $r40 $r41 $r42 $r43
+ * 224| $r44 $r45 $r46 $r47
+ * 256| $r48 $r49 $r50 $r51
+ * 288| $r52 $r53 $r54 $r55
+ * 320| $r56 $r57 $r58 $r59
+ * 352| $r60 $r61 $r62 $r63
+ * 384| $r16 $r17
+ */
+
+#define STACK_OFFSET_FP 0
+#define STACK_OFFSET_RA (STACK_OFFSET_FP + 8)
+#define STACK_OFFSET_R15 (STACK_OFFSET_RA + 8)
+#define STACK_OFFSET_Q0 (STACK_OFFSET_FP + 32)
+#define STACK_OFFSET_Q4 (STACK_OFFSET_Q0 + 32)
+#define STACK_OFFSET_Q8 (STACK_OFFSET_Q4 + 32)
+#define STACK_OFFSET_Q32 (STACK_OFFSET_Q8 + 32)
+#define STACK_OFFSET_Q36 (STACK_OFFSET_Q32 + 32)
+#define STACK_OFFSET_Q40 (STACK_OFFSET_Q36 + 32)
+#define STACK_OFFSET_Q44 (STACK_OFFSET_Q40 + 32)
+#define STACK_OFFSET_Q48 (STACK_OFFSET_Q44 + 32)
+#define STACK_OFFSET_Q52 (STACK_OFFSET_Q48 + 32)
+#define STACK_OFFSET_Q56 (STACK_OFFSET_Q52 + 32)
+#define STACK_OFFSET_Q60 (STACK_OFFSET_Q56 + 32)
+#define STACK_OFFSET_P16 (STACK_OFFSET_Q60 + 32)
+#define STACK_SIZE (STACK_OFFSET_P16 + 16)
+
+#define RA_DWARF_REGNO (64 + KVX_SFR_RA)
+#define R14_DWARF_REGNO 14
+
+.macro save_all_context_but_P16
+ /*
+ * r16 and r17 are already saved. r16 is already used to store the
+ * address of the function tracer if any.
+ * so !!! USE r17 as scratch register !!!
+ */
+ get $r17 = $ra
+ sd STACK_OFFSET_FP[$r12] = $r14
+ ;;
+ .cfi_offset R14_DWARF_REGNO, -STACK_SIZE + STACK_OFFSET_FP
+ sd STACK_OFFSET_RA[$r12] = $r17
+ ;;
+ .cfi_offset RA_DWARF_REGNO, -STACK_SIZE + STACK_OFFSET_RA
+ sd STACK_OFFSET_R15[$r12] = $r15
+ ;;
+ so STACK_OFFSET_Q0[$r12] = $r0r1r2r3
+ ;;
+ so STACK_OFFSET_Q4[$r12] = $r4r5r6r7
+ ;;
+ so STACK_OFFSET_Q8[$r12] = $r8r9r10r11
+ ;;
+ so STACK_OFFSET_Q32[$r12] = $r32r33r34r35
+ ;;
+ so STACK_OFFSET_Q36[$r12] = $r36r37r38r39
+ ;;
+ so STACK_OFFSET_Q40[$r12] = $r40r41r42r43
+ ;;
+ so STACK_OFFSET_Q44[$r12] = $r44r45r46r47
+ ;;
+ so STACK_OFFSET_Q48[$r12] = $r48r49r50r51
+ ;;
+ so STACK_OFFSET_Q52[$r12] = $r52r53r54r55
+ ;;
+ so STACK_OFFSET_Q56[$r12] = $r56r57r58r59
+ ;;
+ so STACK_OFFSET_Q60[$r12] = $r60r61r62r63
+ ;;
+.endm
+
+.macro restore_all_context
+ ld $r15 = STACK_OFFSET_RA[$r12]
+ ;;
+ ld $r14 = STACK_OFFSET_FP[$r12]
+ set $ra = $r15
+ ;;
+ .cfi_restore RA_DWARF_REGNO
+ .cfi_restore R14_DWARF_REGNO
+ ld $r15 = STACK_OFFSET_R15[$r12]
+ ;;
+ lq $r16r17 = STACK_OFFSET_P16[$r12]
+ ;;
+ lo $r0r1r2r3 = STACK_OFFSET_Q0[$r12]
+ ;;
+ lo $r4r5r6r7 = STACK_OFFSET_Q4[$r12]
+ ;;
+ lo $r8r9r10r11 = STACK_OFFSET_Q8[$r12]
+ ;;
+ lo $r32r33r34r35 = STACK_OFFSET_Q32[$r12]
+ ;;
+ lo $r36r37r38r39 = STACK_OFFSET_Q36[$r12]
+ ;;
+ lo $r40r41r42r43 = STACK_OFFSET_Q40[$r12]
+ ;;
+ lo $r44r45r46r47 = STACK_OFFSET_Q44[$r12]
+ ;;
+ lo $r48r49r50r51 = STACK_OFFSET_Q48[$r12]
+ ;;
+ lo $r52r53r54r55 = STACK_OFFSET_Q52[$r12]
+ ;;
+ lo $r56r57r58r59 = STACK_OFFSET_Q56[$r12]
+ ;;
+ lo $r60r61r62r63 = STACK_OFFSET_Q60[$r12]
+ ;;
+ addd $r12 = $r12, STACK_SIZE
+ ;;
+ .cfi_def_cfa_offset 0
+.endm
+
+ENTRY(__mcount)
+.cfi_startproc
+#ifdef CONFIG_DYNAMIC_FTRACE
+ /*
+ * With dynamic ftrace mcount() is only used during boot and then all
+ * references to it will be patched out never to return. ftrace_caller
+ * is used.
+ */
+ ret
+ ;;
+#endif
+ addd $r12 = $r12, -STACK_SIZE
+ ;;
+ .cfi_def_cfa_offset STACK_SIZE
+ sq STACK_OFFSET_P16[$r12] = $r16r17
+ ;;
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ /*
+ * Check the function pointers ftrace_graph_return
+ * (compare to ftrace_stub) and ftrace_graph_entry (compare to
+ * ftrace_graph_entry_stub). If either of those is not set to the
+ * relevant stub function, call the arch-specific function
+ * ftrace_graph_caller.
+ */
+ make $r16 = ftrace_graph_return
+ make $r17 = ftrace_graph_entry
+ ;;
+ ld $r16 = 0[$r16]
+ ;;
+ compd.eq $r16 = $r16, ftrace_stub
+ ld $r17 = 0[$r17]
+ ;;
+ /*
+ * If ftrace_graph_return is not equal to ftrace_stub ($r16 == 0) then
+ * jump to ftrace_graph_caller. Otherwise compare ftrace_graph_entry.
+ */
+ cb.deqz $r16? ftrace_graph_caller
+ compd.eq $r17 = $r17, ftrace_graph_entry_stub
+ ;;
+ /*
+ * If ftrace_graph_entry is equal to ftrace_graph_entry_stub ($r17 == 1)
+ * then jump to ftrace_graph_end. If not we continue.
+ */
+ cb.dnez $r17? ftrace_graph_end
+ ;;
+ftrace_graph_caller:
+ save_all_context_but_P16
+ ;;
+GLOBAL(ftrace_graph_call)
+ ld $r16 = 0[$r12]
+ ;;
+ addd $r0 = $r16, 0x8 /* a pointer to the frompc */
+ get $r1 = $ra /* selfpc */
+ copyd $r2 = $r16 /* FP of the function that called __mcount */
+ ;;
+ /* get the address of the bundle */
+ addd $r1 = $r1, -KVX_INSN_SYLLABLE_WIDTH
+ ;;
+ call prepare_ftrace_return
+ ;;
+ restore_all_context
+ ;;
+ ret
+ ;;
+ftrace_graph_end:
+ .cfi_def_cfa_offset STACK_SIZE
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+ /*
+ * Check if function pointer ftrace_trace_function is set to
+ * ftrace_stub.
+ * If it isn't, then call that function in the same way the mcount
+ * function normally calls __mcount_internal
+ * - the first argument is the "frompc" ($r0)
+ * - the second argument is the "selfpc" ($ra - mcount size adjustement)
+ * As we don't use any callee saved registers we don't need to save
+ * them.
+ */
+ make $r16 = ftrace_trace_function
+ ;;
+ ld $r16 = 0[$r16]
+ ;;
+ /*
+ * NOTE: keep value in $r16 (the function we may call if set). See
+ * comment in save_all_context_but_P16.
+ */
+ compd.eq $r17 = $r16, ftrace_stub
+ ;;
+ /*
+ * If ftrace_trace_function is equal to ftrace_stub ($r17 == 1), there
+ * is nothing to do, so return immediately otherwise call the function
+ * in $r16 with correct parameters.
+ */
+ cb.deqz $r17? 1f
+ ;;
+ /* Only need to restore P16 */
+ lq $r16r17 = STACK_OFFSET_P16[$r12]
+ ;;
+ addd $r12 = $r12, STACK_SIZE
+ ;;
+ .cfi_def_cfa_offset 0
+ ret
+ ;;
+
+1:
+ save_all_context_but_P16
+ ;;
+ copyd $r0 = $r32
+ get $r1 = $ra
+ ;;
+ addd $r1 = $r1, -KVX_INSN_SYLLABLE_WIDTH
+ ;;
+ icall $r16
+ ;;
+ restore_all_context
+ ;;
+ ret
+ ;;
+.cfi_endproc
+ENDPROC(__mcount)
+
+/* Required by ftrace_graph_ret_addr */
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ENTRY(return_to_handler)
+ addd $r12 = $r12, -128
+ ;;
+ so 0[$r12] = $r0r1r2r3
+ ;;
+ so 32[$r12] = $r4r5r6r7
+ ;;
+ so 64[$r12] = $r8r9r10r11
+ ;;
+ call ftrace_return_to_handler
+ ;;
+ set $ra = $r0
+ lo $r0r1r2r3 = 0[$r12]
+ ;;
+ lo $r4r5r6r7 = 32[$r12]
+ ;;
+ lo $r8r9r10r11 = 64[$r12]
+ addd $r12 = $r12, 128
+ ;;
+ ret
+ ;;
+ENDPROC(return_to_handler)
+#endif
+
+#ifdef CONFIG_DYNAMIC_FTRACE
+ENTRY(ftrace_caller)
+.cfi_startproc
+
+ addd $r12 = $r12, -STACK_SIZE
+ ;;
+ .cfi_def_cfa_offset STACK_SIZE
+ sq STACK_OFFSET_P16[$r12] = $r16r17
+ ;;
+ save_all_context_but_P16
+ ;;
+ copyd $r0 = $r32
+ get $r1 = $ra
+ ;;
+ addd $r1 = $r1, -KVX_INSN_SYLLABLE_WIDTH
+ ;;
+ goto ftrace_call
+ ;;
+.align 64
+GLOBAL(ftrace_call)
+ /*
+ * To work with module we need to use far call. So prepare the
+ * space for them:
+ * - make: 3 syllables
+ * - icall/igoto: 1 syllable
+ *
+ * We are using igoto in ftrace_enable_ftrace_graph_caller(). This is
+ * because this path is a tweak to enable function graph tracer with
+ * dynamic ftrace. We need to jump to ftrace_graph_call without updating
+ * RA and FP. Once in ftrace_graph_call we will return to the correct
+ * address from the classical path of the function graph tracer.
+ */
+ nop
+ ;;
+ nop
+ ;;
+ nop
+ ;;
+ nop
+ ;;
+ restore_all_context
+ ;;
+ ret
+ ;;
+.cfi_endproc
+ENDPROC(ftrace_caller)
+#endif // CONFIG_DYNAMIC_FTRACE
+
+ENTRY(ftrace_stub)
+ ret
+ ;;
+ENDPROC(ftrace_stub)
+
diff --git a/arch/kvx/kernel/return_address.c b/arch/kvx/kernel/return_address.c
new file mode 100644
index 000000000000..3ddf7b79662c
--- /dev/null
+++ b/arch/kvx/kernel/return_address.c
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * derived from arch/arm64/kernel/return_address.c
+ *
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Clement Leger
+ */
+
+#include <linux/export.h>
+#include <linux/ftrace.h>
+#include <linux/kprobes.h>
+
+#include <asm/stacktrace.h>
+
+struct return_address_data {
+ unsigned int level;
+ void *addr;
+};
+
+static bool save_return_addr(unsigned long pc, void *d)
+{
+ struct return_address_data *data = d;
+
+ /* We hit the desired level, return the address */
+ if (data->level == 0) {
+ data->addr = (void *) pc;
+ return true;
+ }
+
+ data->level--;
+ return false;
+}
+NOKPROBE_SYMBOL(save_return_addr);
+
+void *return_address(unsigned int level)
+{
+ struct return_address_data data;
+ struct stackframe frame;
+
+ /* Skip this function + caller */
+ data.level = level + 2;
+ data.addr = NULL;
+
+ start_stackframe(&frame,
+ (unsigned long) __builtin_frame_address(0),
+ (unsigned long) return_address);
+ walk_stackframe(current, &frame, save_return_addr, &data);
+
+ if (!data.level)
+ return data.addr;
+ else
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(return_address);
+NOKPROBE_SYMBOL(return_address);
--
2.37.2





2023-01-03 17:21:20

by Yann Sionneau

[permalink] [raw]
Subject: [RFC PATCH 09/25] kvx: irqchip: Add support for irq controllers

Add support for kvx irq controllers found in Coolidge MPPA SoC

The core-intc:

Each kvx core includes a hardware interrupt controller (core ITC)
with the following features:
* 32 independent interrupt sources
* 4-bit priotity level
* Individual interrupt enable bit
* Interrupt status bit displaying the pending interrupts
* Priority management between the 32 interrupts

Among those 32 interrupt sources, the first are hard-wired to hardware
sources. The remaining interrupt sources can be triggered via software
by directly writing to the ILR SFR.

The hard-wired interrupt sources are the following:
0: Timer 0
1: Timer 1
2: Watchdog
3: Performance Monitors
4: APIC GIC line 0
5: APIC GIC line 1
6: APIC GIC line 2
7: APIC GIC line 3
12: SECC error from memory system
13: Arithmetic exception (carry and IEEE 754 flags)
16: Data Asynchronous Memory Error (DAME), raised for DECC/DSYS errors
17: CLI (Cache Line Invalidation) for L1D or L1I following DECC/DSYS/Parity
errors

The APIC GIC lines will be used to route interrupts coming from SoC peripherals
from outside the Cluster to the kvx core. Those peripherals include USB host
controller, eMMC/SD host controller, i2c, spi, PCIe, IOMMUs etc...

The APIC GIC:

Each Cluster of the Coolidge SoC includes an APIC
(Advanced Programmable Interrupt Controller) GIC (Generic Interrupt Controller).
The APIC GIC acts as an intermediary interrupt controller, muxing/routing
incoming interrupts to output interrupts connected to the kvx core ITC lines.
The first 128 incoming interrupt lines come from the mailbox controller (itself
containing 128 mailboxes).
The remaining 11 interrupt lines come from external interrupt sources (NoC
router, the 5 IOMMUs, L2$ DMA job fifo, watchdog, SECC, DECC, D NoC).
The APIC GIC has 72 output interrupts: 4 per kvx cores in the cluster
(1 RM and 16 PE) connected to the "APIC GIC lines" described above and 1 for the
L2$ controller which makes 69 interrupts lines (rounded up to 72).

The APIC Mailbox:

The APIC includes a mailbox controller, containing 128 mailboxes.
This hardware block is basically a 1 Kb of smart memory space.
Each mailbox is an 8 bytes word memory location which can generate and
interrupt.
Each mailbox has a trigger function and an input function.
When a mailbox is written to, if the condition described by the
trigger function is satisfied, the corresponding interrupt
will fire.
Since this hardware block generates IRQs based on writes
at some memory locations, it is both an interrupt controller
and an MSI controller.

The ITGEN:

The ITGEN (InTerrupt GENerator) is an interrupt controller block.
It's purpose is to convert IRQ lines coming from SoC peripherals
(USB host controller for instance) into writes on the AXI bus.
Those writes are targeting the APIC Mailboxes.

CC: Thomas Gleixner <[email protected]>
CC: Marc Zyngier <[email protected]>
CC: Rob Herring <[email protected]>
CC: Krzysztof Kozlowski <[email protected]>
CC: [email protected]
CC: [email protected]
Co-developed-by: Clement Leger <[email protected]>
Signed-off-by: Clement Leger <[email protected]>
Co-developed-by: Jules Maselbas <[email protected]>
Signed-off-by: Jules Maselbas <[email protected]>
Co-developed-by: Julian Vetter <[email protected]>
Signed-off-by: Julian Vetter <[email protected]>
Co-developed-by: Luc Michel <[email protected]>
Signed-off-by: Luc Michel <[email protected]>
Co-developed-by: Vincent Chardon <[email protected]>
Signed-off-by: Vincent Chardon <[email protected]>
Co-developed-by: Yann Sionneau <[email protected]>
Signed-off-by: Yann Sionneau <[email protected]>
---
.../kalray,kvx-core-intc.txt | 22 +
drivers/irqchip/Kconfig | 27 +
drivers/irqchip/Makefile | 4 +
drivers/irqchip/irq-kvx-apic-gic.c | 349 +++++++++++++
drivers/irqchip/irq-kvx-apic-mailbox.c | 465 ++++++++++++++++++
drivers/irqchip/irq-kvx-core-intc.c | 82 +++
drivers/irqchip/irq-kvx-itgen.c | 224 +++++++++
include/linux/irqchip/irq-kvx-apic-gic.h | 21 +
include/linux/irqchip/irq-kvx-apic-mailbox.h | 29 ++
include/linux/irqchip/irq-kvx-itgen.h | 24 +
10 files changed, 1247 insertions(+)
create mode 100644 Documentation/devicetree/bindings/interrupt-controller/kalray,kvx-core-intc.txt
create mode 100644 drivers/irqchip/irq-kvx-apic-gic.c
create mode 100644 drivers/irqchip/irq-kvx-apic-mailbox.c
create mode 100644 drivers/irqchip/irq-kvx-core-intc.c
create mode 100644 drivers/irqchip/irq-kvx-itgen.c
create mode 100644 include/linux/irqchip/irq-kvx-apic-gic.h
create mode 100644 include/linux/irqchip/irq-kvx-apic-mailbox.h
create mode 100644 include/linux/irqchip/irq-kvx-itgen.h

diff --git a/Documentation/devicetree/bindings/interrupt-controller/kalray,kvx-core-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/kalray,kvx-core-intc.txt
new file mode 100644
index 000000000000..503a661e1e84
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/kalray,kvx-core-intc.txt
@@ -0,0 +1,22 @@
+* KVX Core Interrupt controller
+
+Required properties:
+
+- compatible: must to be "kalray,kvx-core-intc".
+- interrupt-controller
+- #interrupt-cells: has to be <1>: an interrupt index
+- regs: Base address of interrupt controller registers.
+
+Optional properties:
+
+- kalray,intc-nr-irqs: Number of irqs handled by the controller.
+ if not given, will default to 32.
+
+Example:
+
+ core_intc: core_intc@0 {
+ compatible = "kalray,kvx-core-intc";
+ #interrupt-cells = <1>;
+ interrupt-controller;
+ interrupt-parent = <&core_intc>;
+ };
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 7ef9f5e696d3..7c7753b33d4e 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -334,6 +334,33 @@ config MIPS_GIC
select IRQ_DOMAIN_HIERARCHY
select MIPS_CM

+config KVX_CORE_INTC
+ bool
+ depends on KVX
+ select IRQ_DOMAIN
+
+config KVX_APIC_GIC
+ bool
+ depends on KVX
+ select IRQ_DOMAIN
+ select IRQ_DOMAIN_HIERARCHY
+
+config KVX_APIC_MAILBOX
+ bool
+ depends on KVX
+ select GENERIC_IRQ_IPI if SMP
+ select GENERIC_MSI_IRQ_DOMAIN
+ select IRQ_DOMAIN
+ select IRQ_DOMAIN_HIERARCHY
+
+config KVX_ITGEN
+ bool
+ depends on KVX
+ select GENERIC_IRQ_IPI if SMP
+ select GENERIC_MSI_IRQ_DOMAIN
+ select IRQ_DOMAIN
+ select IRQ_DOMAIN_HIERARCHY
+
config INGENIC_IRQ
bool
depends on MACH_INGENIC
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 87b49a10962c..4e7e374314c3 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -69,6 +69,10 @@ obj-$(CONFIG_BCM7120_L2_IRQ) += irq-bcm7120-l2.o
obj-$(CONFIG_BRCMSTB_L2_IRQ) += irq-brcmstb-l2.o
obj-$(CONFIG_KEYSTONE_IRQ) += irq-keystone.o
obj-$(CONFIG_MIPS_GIC) += irq-mips-gic.o
+obj-$(CONFIG_KVX_CORE_INTC) += irq-kvx-core-intc.o
+obj-$(CONFIG_KVX_APIC_GIC) += irq-kvx-apic-gic.o
+obj-$(CONFIG_KVX_APIC_MAILBOX) += irq-kvx-apic-mailbox.o
+obj-$(CONFIG_KVX_ITGEN) += irq-kvx-itgen.o
obj-$(CONFIG_ARCH_MEDIATEK) += irq-mtk-sysirq.o irq-mtk-cirq.o
obj-$(CONFIG_ARCH_DIGICOLOR) += irq-digicolor.o
obj-$(CONFIG_ARCH_SA1100) += irq-sa11x0.o
diff --git a/drivers/irqchip/irq-kvx-apic-gic.c b/drivers/irqchip/irq-kvx-apic-gic.c
new file mode 100644
index 000000000000..42d28c8b3322
--- /dev/null
+++ b/drivers/irqchip/irq-kvx-apic-gic.c
@@ -0,0 +1,349 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2017 - 2022 Kalray Inc.
+ * Author(s): Clement Leger
+ * Julian Vetter
+ */
+
+#define pr_fmt(fmt) "kvx_apic_gic: " fmt
+
+#include <linux/irqchip/irq-kvx-apic-gic.h>
+#include <linux/of_address.h>
+#include <linux/cpuhotplug.h>
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/spinlock.h>
+#include <linux/irqchip.h>
+#include <linux/of_irq.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/of.h>
+
+/* APIC is organized in 18 groups of 4 output lines
+ * However, the two upper lines are for Secure RM and DMA engine
+ * Thus, we do not have to use them
+ */
+#define GIC_CPU_OUT_COUNT 16
+#define GIC_PER_CPU_IT_COUNT 4
+
+/**
+ * For each CPU, there is 4 output lines coming from the apic GIC.
+ * We only use 1 line and this structure represent this line.
+ * @base Output line base address
+ * @cpu CPU associated to this line
+ */
+struct gic_out_irq_line {
+ void __iomem *base;
+ unsigned int cpu;
+};
+
+/**
+ * Input irq line.
+ * This structure is used to store the status of the input line and the
+ * associated output line.
+ * @enabled Boolean for line status
+ * @cpu CPU currently receiving this interrupt
+ * @it_num Interrupt number
+ */
+struct gic_in_irq_line {
+ bool enabled;
+ struct gic_out_irq_line *out_line;
+ unsigned int it_num;
+};
+
+/**
+ * struct kvx_apic_gic - kvx apic gic
+ * @base: Base address of the controller
+ * @domain Domain for this controller
+ * @input_nr_irqs: maximum number of supported input interrupts
+ * @cpus: Per cpu interrupt configuration
+ * @output_irq: Array of output irq lines
+ * @input_irq: Array of input irq lines
+ */
+struct kvx_apic_gic {
+ raw_spinlock_t lock;
+ void __iomem *base;
+ struct irq_domain *domain;
+ uint32_t input_nr_irqs;
+ /* For each cpu, there is a output IT line */
+ struct gic_out_irq_line output_irq[GIC_CPU_OUT_COUNT];
+
+ /* Input interrupt status */
+ struct gic_in_irq_line input_irq[KVX_GIC_INPUT_IT_COUNT];
+};
+
+static int gic_parent_irq;
+
+/**
+ * Enable/Disable an output irq line
+ * This function is used by both mask/unmask to disable/enable the line.
+ */
+static void irq_line_set_enable(struct gic_out_irq_line *irq_line,
+ struct gic_in_irq_line *in_irq_line,
+ int enable)
+{
+ void __iomem *enable_line_addr = irq_line->base +
+ KVX_GIC_ENABLE_OFFSET +
+ in_irq_line->it_num * KVX_GIC_ENABLE_ELEM_SIZE;
+
+ writeb((uint8_t) enable ? 1 : 0, enable_line_addr);
+ in_irq_line->enabled = enable;
+}
+
+static void kvx_apic_gic_set_line(struct irq_data *data, int enable)
+{
+ struct kvx_apic_gic *gic = irq_data_get_irq_chip_data(data);
+ unsigned int in_irq = irqd_to_hwirq(data);
+ struct gic_in_irq_line *in_line = &gic->input_irq[in_irq];
+ struct gic_out_irq_line *out_line = in_line->out_line;
+
+ raw_spin_lock(&gic->lock);
+ /* Set line enable on currently assigned cpu */
+ irq_line_set_enable(out_line, in_line, enable);
+ raw_spin_unlock(&gic->lock);
+}
+
+static void kvx_apic_gic_mask(struct irq_data *data)
+{
+ kvx_apic_gic_set_line(data, 0);
+}
+
+static void kvx_apic_gic_unmask(struct irq_data *data)
+{
+ kvx_apic_gic_set_line(data, 1);
+}
+
+#ifdef CONFIG_SMP
+
+static int kvx_apic_gic_set_affinity(struct irq_data *d,
+ const struct cpumask *cpumask,
+ bool force)
+{
+ struct kvx_apic_gic *gic = irq_data_get_irq_chip_data(d);
+ unsigned int new_cpu;
+ unsigned int hw_irq = irqd_to_hwirq(d);
+ struct gic_in_irq_line *input_line = &gic->input_irq[hw_irq];
+ struct gic_out_irq_line *new_out_line;
+
+ /* We assume there is only one cpu in the mask */
+ new_cpu = cpumask_first(cpumask);
+ new_out_line = &gic->output_irq[new_cpu];
+
+ raw_spin_lock(&gic->lock);
+
+ /* Nothing to do, line is the same */
+ if (new_out_line == input_line->out_line)
+ goto out;
+
+ /* If old line was enabled, enable the new one before disabling
+ * the old one
+ */
+ if (input_line->enabled)
+ irq_line_set_enable(new_out_line, input_line, 1);
+
+ /* Disable it on old line */
+ irq_line_set_enable(input_line->out_line, input_line, 0);
+
+ /* Assign new output line to input IRQ */
+ input_line->out_line = new_out_line;
+
+out:
+ raw_spin_unlock(&gic->lock);
+
+ irq_data_update_effective_affinity(d, cpumask_of(new_cpu));
+
+ return IRQ_SET_MASK_OK;
+}
+#endif
+
+static struct irq_chip kvx_apic_gic_chip = {
+ .name = "kvx apic gic",
+ .irq_mask = kvx_apic_gic_mask,
+ .irq_unmask = kvx_apic_gic_unmask,
+#ifdef CONFIG_SMP
+ .irq_set_affinity = kvx_apic_gic_set_affinity,
+#endif
+};
+
+static int kvx_apic_gic_alloc(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs, void *args)
+{
+ int i;
+ struct irq_fwspec *fwspec = args;
+ int hwirq = fwspec->param[0];
+
+ for (i = 0; i < nr_irqs; i++) {
+ irq_domain_set_info(domain, virq + i, hwirq + i,
+ &kvx_apic_gic_chip,
+ domain->host_data, handle_simple_irq,
+ NULL, NULL);
+ }
+
+ return 0;
+}
+
+static const struct irq_domain_ops kvx_apic_gic_domain_ops = {
+ .alloc = kvx_apic_gic_alloc,
+ .free = irq_domain_free_irqs_common,
+};
+
+static void irq_line_get_status_lac(struct gic_out_irq_line *out_irq_line,
+ uint64_t status[KVX_GIC_STATUS_LAC_ARRAY_SIZE])
+{
+ int i;
+
+ for (i = 0; i < KVX_GIC_STATUS_LAC_ARRAY_SIZE; i++) {
+ status[i] = readq(out_irq_line->base +
+ KVX_GIC_STATUS_LAC_OFFSET +
+ i * KVX_GIC_STATUS_LAC_ELEM_SIZE);
+ }
+}
+
+static void kvx_apic_gic_handle_irq(struct irq_desc *desc)
+{
+ struct kvx_apic_gic *gic_data = irq_desc_get_handler_data(desc);
+ struct gic_out_irq_line *out_line;
+ uint64_t status[KVX_GIC_STATUS_LAC_ARRAY_SIZE];
+ unsigned long irqn, cascade_irq;
+ unsigned long cpu = smp_processor_id();
+
+ out_line = &gic_data->output_irq[cpu];
+
+ irq_line_get_status_lac(out_line, status);
+
+ for_each_set_bit(irqn, (unsigned long *) status,
+ KVX_GIC_STATUS_LAC_ARRAY_SIZE * BITS_PER_LONG) {
+
+ cascade_irq = irq_find_mapping(gic_data->domain, irqn);
+
+ generic_handle_irq(cascade_irq);
+ }
+}
+
+static void __init apic_gic_init(struct kvx_apic_gic *gic)
+{
+ unsigned int cpu, line;
+ struct gic_in_irq_line *input_irq_line;
+ struct gic_out_irq_line *output_irq_line;
+ uint64_t status[KVX_GIC_STATUS_LAC_ARRAY_SIZE];
+
+ /* Initialize all input lines (device -> )*/
+ for (line = 0; line < KVX_GIC_INPUT_IT_COUNT; line++) {
+ input_irq_line = &gic->input_irq[line];
+ input_irq_line->enabled = false;
+ /* All input lines map on output 0 */
+ input_irq_line->out_line = &gic->output_irq[0];
+ input_irq_line->it_num = line;
+ }
+
+ /* Clear all output lines (-> cpus) */
+ for (cpu = 0; cpu < GIC_CPU_OUT_COUNT; cpu++) {
+ output_irq_line = &gic->output_irq[cpu];
+ output_irq_line->cpu = cpu;
+ output_irq_line->base = gic->base +
+ cpu * (KVX_GIC_ELEM_SIZE * GIC_PER_CPU_IT_COUNT);
+
+ /* Disable all external lines on this core */
+ for (line = 0; line < KVX_GIC_INPUT_IT_COUNT; line++)
+ irq_line_set_enable(output_irq_line,
+ &gic->input_irq[line], 0x0);
+
+ irq_line_get_status_lac(output_irq_line, status);
+ }
+}
+
+static int kvx_gic_starting_cpu(unsigned int cpu)
+{
+ enable_percpu_irq(gic_parent_irq, IRQ_TYPE_NONE);
+
+ return 0;
+}
+
+static int kvx_gic_dying_cpu(unsigned int cpu)
+{
+ disable_percpu_irq(gic_parent_irq);
+
+ return 0;
+}
+
+static int __init kvx_init_apic_gic(struct device_node *node,
+ struct device_node *parent)
+{
+ struct kvx_apic_gic *gic;
+ int ret;
+ unsigned int irq;
+
+ if (!parent) {
+ pr_err("kvx apic gic does not have parent\n");
+ return -EINVAL;
+ }
+
+ gic = kzalloc(sizeof(*gic), GFP_KERNEL);
+ if (!gic)
+ return -ENOMEM;
+
+ if (of_property_read_u32(node, "kalray,intc-nr-irqs",
+ &gic->input_nr_irqs))
+ gic->input_nr_irqs = KVX_GIC_INPUT_IT_COUNT;
+
+ if (WARN_ON(gic->input_nr_irqs > KVX_GIC_INPUT_IT_COUNT)) {
+ ret = -EINVAL;
+ goto err_kfree;
+ }
+
+ gic->base = of_io_request_and_map(node, 0, node->name);
+ if (!gic->base) {
+ ret = -EINVAL;
+ goto err_kfree;
+ }
+
+ raw_spin_lock_init(&gic->lock);
+ apic_gic_init(gic);
+
+ gic->domain = irq_domain_add_linear(node,
+ gic->input_nr_irqs,
+ &kvx_apic_gic_domain_ops,
+ gic);
+ if (!gic->domain) {
+ pr_err("Failed to add IRQ domain\n");
+ ret = -EINVAL;
+ goto err_iounmap;
+ }
+
+ irq = irq_of_parse_and_map(node, 0);
+ if (irq <= 0) {
+ pr_err("unable to parse irq\n");
+ ret = -EINVAL;
+ goto err_irq_domain_remove;
+ }
+
+ irq_set_chained_handler_and_data(irq, kvx_apic_gic_handle_irq,
+ gic);
+
+ gic_parent_irq = irq;
+ ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
+ "kvx/gic:online",
+ kvx_gic_starting_cpu,
+ kvx_gic_dying_cpu);
+ if (ret < 0) {
+ pr_err("Failed to setup hotplug state");
+ goto err_irq_unmap;
+ }
+
+ pr_info("Initialized interrupt controller with %d interrupts\n",
+ gic->input_nr_irqs);
+ return 0;
+
+err_irq_unmap:
+ irq_dispose_mapping(irq);
+err_irq_domain_remove:
+ irq_domain_remove(gic->domain);
+err_iounmap:
+ iounmap(gic->base);
+err_kfree:
+ kfree(gic);
+
+ return ret;
+}
+
+IRQCHIP_DECLARE(kvx_apic_gic, "kalray,kvx-apic-gic", kvx_init_apic_gic);
diff --git a/drivers/irqchip/irq-kvx-apic-mailbox.c b/drivers/irqchip/irq-kvx-apic-mailbox.c
new file mode 100644
index 000000000000..c279a29ee7d0
--- /dev/null
+++ b/drivers/irqchip/irq-kvx-apic-mailbox.c
@@ -0,0 +1,465 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2017 - 2022 Kalray Inc.
+ * Author(s): Clement Leger
+ * Jules Maselbas
+ */
+
+#define pr_fmt(fmt) "kvx_apic_mailbox: " fmt
+
+#include <linux/irqchip/irq-kvx-apic-mailbox.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/of_address.h>
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/iommu.h>
+#include <linux/irqchip.h>
+#include <linux/module.h>
+#include <linux/of_irq.h>
+#include <linux/init.h>
+#include <linux/msi.h>
+#include <linux/of.h>
+
+#define MAILBOXES_MAX_COUNT 128
+
+/* Mailboxes are 64 bits wide */
+#define MAILBOXES_BIT_SIZE 64
+
+/* Maximum number of mailboxes available */
+#define MAILBOXES_MAX_BIT_COUNT (MAILBOXES_MAX_COUNT * MAILBOXES_BIT_SIZE)
+
+/* Mailboxes are grouped by 8 in a single page */
+#define MAILBOXES_BITS_PER_PAGE (8 * MAILBOXES_BIT_SIZE)
+
+/**
+ * struct mb_data - per mailbox data
+ * @cpu: CPU on which the mailbox is routed
+ * @parent_irq: Parent IRQ on the GIC
+ */
+struct mb_data {
+ unsigned int cpu;
+ unsigned int parent_irq;
+};
+
+/**
+ * struct kvx_apic_mailbox - kvx apic mailbox
+ * @base: base address of the controller
+ * @device_domain: IRQ device domain for mailboxes
+ * @msi_domain: platform MSI domain for MSI interface
+ * @domain_info: Domain information needed for the MSI domain
+ * @mb_count: Count of mailboxes we are handling
+ * @available: bitmap of availables bits in mailboxes
+ * @mailboxes_lock: lock for irq migration
+ * @mask_lock: lock for irq masking
+ * @mb_data: data associated to each mailbox
+ */
+struct kvx_apic_mailbox {
+ void __iomem *base;
+ phys_addr_t phys_base;
+ struct irq_domain *device_domain;
+ struct irq_domain *msi_domain;
+ struct msi_domain_info domain_info;
+ /* Start and count of device mailboxes */
+ unsigned int mb_count;
+ /* Bitmap of allocated bits in mailboxes */
+ DECLARE_BITMAP(available, MAILBOXES_MAX_BIT_COUNT);
+ spinlock_t mailboxes_lock;
+ raw_spinlock_t mask_lock;
+ struct mb_data mb_data[MAILBOXES_MAX_COUNT];
+};
+
+/**
+ * struct kvx_irq_data - per irq data
+ * @mb: Mailbox structure
+ */
+struct kvx_irq_data {
+ struct kvx_apic_mailbox *mb;
+};
+
+static void kvx_mailbox_get_from_hwirq(unsigned int hw_irq,
+ unsigned int *mailbox_num,
+ unsigned int *mailbox_bit)
+{
+ *mailbox_num = hw_irq / MAILBOXES_BIT_SIZE;
+ *mailbox_bit = hw_irq % MAILBOXES_BIT_SIZE;
+}
+
+static void __iomem *kvx_mailbox_get_addr(struct kvx_apic_mailbox *mb,
+ unsigned int num)
+{
+ return mb->base + (num * KVX_MAILBOX_ELEM_SIZE);
+}
+
+static phys_addr_t kvx_mailbox_get_phys_addr(struct kvx_apic_mailbox *mb,
+ unsigned int num)
+{
+ return mb->phys_base + (num * KVX_MAILBOX_ELEM_SIZE);
+}
+
+static void kvx_mailbox_msi_compose_msg(struct irq_data *data,
+ struct msi_msg *msg)
+{
+ struct kvx_irq_data *kd = irq_data_get_irq_chip_data(data);
+ struct kvx_apic_mailbox *mb = kd->mb;
+ unsigned int mb_num, mb_bit;
+ phys_addr_t mb_addr;
+
+ kvx_mailbox_get_from_hwirq(irqd_to_hwirq(data), &mb_num, &mb_bit);
+ mb_addr = kvx_mailbox_get_phys_addr(mb, mb_num);
+
+ msg->address_hi = upper_32_bits(mb_addr);
+ msg->address_lo = lower_32_bits(mb_addr);
+ msg->data = mb_bit;
+
+ iommu_dma_compose_msi_msg(irq_data_get_msi_desc(data), msg);
+}
+
+static void kvx_mailbox_set_irq_enable(struct irq_data *data,
+ bool enabled)
+{
+ struct kvx_irq_data *kd = irq_data_get_irq_chip_data(data);
+ struct kvx_apic_mailbox *mb = kd->mb;
+ unsigned int mb_num, mb_bit;
+ void __iomem *mb_addr;
+ u64 mask_value, mb_value;
+
+ kvx_mailbox_get_from_hwirq(irqd_to_hwirq(data), &mb_num, &mb_bit);
+ mb_addr = kvx_mailbox_get_addr(mb, mb_num);
+
+ raw_spin_lock(&mb->mask_lock);
+ mask_value = readq(mb_addr + KVX_MAILBOX_MASK_OFFSET);
+ if (enabled)
+ mask_value |= BIT_ULL(mb_bit);
+ else
+ mask_value &= ~BIT_ULL(mb_bit);
+
+ writeq(mask_value, mb_addr + KVX_MAILBOX_MASK_OFFSET);
+
+ raw_spin_unlock(&mb->mask_lock);
+
+ /**
+ * Since interrupts on mailboxes are edge triggered and are only
+ * triggered when writing the value, we need to trigger it manually
+ * after updating the mask if enabled. If the interrupt was triggered by
+ * the device just after the mask write, we can trigger a spurious
+ * interrupt but that is still better than missing one...
+ * Moreover, the mailbox is configured in OR mode which means that even
+ * if we write a single bit, all other bits will be kept intact.
+ */
+ if (enabled) {
+ mb_value = readq(mb_addr + KVX_MAILBOX_VALUE_OFFSET);
+ if (mb_value & BIT_ULL(mb_bit))
+ writeq(BIT_ULL(mb_bit),
+ mb_addr + KVX_MAILBOX_VALUE_OFFSET);
+ }
+}
+
+static void kvx_mailbox_mask(struct irq_data *data)
+{
+ kvx_mailbox_set_irq_enable(data, false);
+}
+
+static void kvx_mailbox_unmask(struct irq_data *data)
+{
+ kvx_mailbox_set_irq_enable(data, true);
+}
+
+static void kvx_mailbox_set_cpu(struct kvx_apic_mailbox *mb, int mb_id,
+ int new_cpu)
+{
+ irq_set_affinity(mb->mb_data[mb_id].parent_irq, cpumask_of(new_cpu));
+ mb->mb_data[mb_id].cpu = new_cpu;
+}
+
+static void kvx_mailbox_free_bit(struct kvx_apic_mailbox *mb, int hw_irq)
+{
+ unsigned int mb_num, mb_bit;
+
+ kvx_mailbox_get_from_hwirq(hw_irq, &mb_num, &mb_bit);
+ bitmap_clear(mb->available, hw_irq, 1);
+
+ /* If there is no more IRQ on this mailbox, reset it to CPU 0 */
+ if (mb->available[mb_num] == 0)
+ kvx_mailbox_set_cpu(mb, mb_num, 0);
+}
+
+struct irq_chip kvx_apic_mailbox_irq_chip = {
+ .name = "kvx apic mailbox",
+ .irq_compose_msi_msg = kvx_mailbox_msi_compose_msg,
+ .irq_mask = kvx_mailbox_mask,
+ .irq_unmask = kvx_mailbox_unmask,
+};
+
+static int kvx_mailbox_allocate_bits(struct kvx_apic_mailbox *mb, int num_req)
+{
+ int first, align_mask = 0;
+
+ /* This must be a power of 2 for bitmap_find_next_zero_area to work */
+ BUILD_BUG_ON((MAILBOXES_BITS_PER_PAGE & (MAILBOXES_BITS_PER_PAGE - 1)));
+
+ /*
+ * If user requested more than 1 mailbox, we must make sure it will be
+ * aligned on a page size for iommu_dma_prepare_msi to be correctly
+ * mapped in a single page.
+ */
+ if (num_req > 1)
+ align_mask = (MAILBOXES_BITS_PER_PAGE - 1);
+
+ spin_lock(&mb->mailboxes_lock);
+
+ first = bitmap_find_next_zero_area(mb->available,
+ mb->mb_count * MAILBOXES_BIT_SIZE, 0,
+ num_req, align_mask);
+ if (first >= MAILBOXES_MAX_BIT_COUNT) {
+ spin_unlock(&mb->mailboxes_lock);
+ return -ENOSPC;
+ }
+
+ bitmap_set(mb->available, first, num_req);
+
+ spin_unlock(&mb->mailboxes_lock);
+
+ return first;
+}
+
+static int kvx_apic_mailbox_msi_alloc(struct irq_domain *domain,
+ unsigned int virq,
+ unsigned int nr_irqs, void *args)
+{
+ int i, err;
+ int hwirq = 0;
+ u64 mb_addr;
+ struct irq_data *d;
+ struct kvx_irq_data *kd;
+ struct kvx_apic_mailbox *mb = domain->host_data;
+ struct msi_alloc_info *msi_info = (struct msi_alloc_info *)args;
+ struct msi_desc *desc = msi_info->desc;
+ unsigned int mb_num, mb_bit;
+
+ /* We will not be able to guarantee page alignment ! */
+ if (nr_irqs > MAILBOXES_BITS_PER_PAGE)
+ return -EINVAL;
+
+ hwirq = kvx_mailbox_allocate_bits(mb, nr_irqs);
+ if (hwirq < 0)
+ return hwirq;
+
+ kvx_mailbox_get_from_hwirq(hwirq, &mb_num, &mb_bit);
+ mb_addr = (u64) kvx_mailbox_get_phys_addr(mb, mb_num);
+ err = iommu_dma_prepare_msi(desc, mb_addr);
+ if (err)
+ goto free_mb_bits;
+
+ for (i = 0; i < nr_irqs; i++) {
+ kd = kmalloc(sizeof(*kd), GFP_KERNEL);
+ if (!kd) {
+ err = -ENOMEM;
+ goto free_irq_data;
+ }
+
+ kd->mb = mb;
+ irq_domain_set_info(domain, virq + i, hwirq + i,
+ &kvx_apic_mailbox_irq_chip,
+ kd, handle_simple_irq,
+ NULL, NULL);
+ }
+
+ return 0;
+
+free_irq_data:
+ for (i--; i >= 0; i--) {
+ d = irq_domain_get_irq_data(domain, virq + i);
+ kd = irq_data_get_irq_chip_data(d);
+ kfree(kd);
+ }
+
+free_mb_bits:
+ spin_lock(&mb->mailboxes_lock);
+ bitmap_clear(mb->available, hwirq, nr_irqs);
+ spin_unlock(&mb->mailboxes_lock);
+
+ return err;
+}
+
+static void kvx_apic_mailbox_msi_free(struct irq_domain *domain,
+ unsigned int virq,
+ unsigned int nr_irqs)
+{
+ int i;
+ struct irq_data *d;
+ struct kvx_irq_data *kd;
+ struct kvx_apic_mailbox *mb = domain->host_data;
+
+ spin_lock(&mb->mailboxes_lock);
+
+ for (i = 0; i < nr_irqs; i++) {
+ d = irq_domain_get_irq_data(domain, virq + i);
+ kd = irq_data_get_irq_chip_data(d);
+ kfree(kd);
+ kvx_mailbox_free_bit(mb, d->hwirq);
+ }
+
+ spin_unlock(&mb->mailboxes_lock);
+}
+
+static const struct irq_domain_ops kvx_apic_mailbox_domain_ops = {
+ .alloc = kvx_apic_mailbox_msi_alloc,
+ .free = kvx_apic_mailbox_msi_free
+};
+
+static struct irq_chip kvx_msi_irq_chip = {
+ .name = "KVX MSI",
+};
+
+static void kvx_apic_mailbox_handle_irq(struct irq_desc *desc)
+{
+ struct irq_data *data = irq_desc_get_irq_data(desc);
+ struct kvx_apic_mailbox *mb = irq_desc_get_handler_data(desc);
+ void __iomem *mb_addr = kvx_mailbox_get_addr(mb, irqd_to_hwirq(data));
+ unsigned int irqn, cascade_irq, bit;
+ u64 mask_value, masked_its;
+ u64 mb_value;
+ /* Since we allocate 64 interrupts for each mailbox, the scheme
+ * to find the hwirq associated to a mailbox irq is the
+ * following:
+ * hw_irq = mb_num * MAILBOXES_BIT_SIZE + bit
+ */
+ unsigned int mb_hwirq = irqd_to_hwirq(data) * MAILBOXES_BIT_SIZE;
+
+ mb_value = readq(mb_addr + KVX_MAILBOX_LAC_OFFSET);
+ mask_value = readq(mb_addr + KVX_MAILBOX_MASK_OFFSET);
+ /* Mask any disabled interrupts */
+ mb_value &= mask_value;
+
+ /**
+ * Write all pending ITs that are masked to process them later
+ * Since the mailbox is in OR mode, these bits will be merged with any
+ * already set bits and thus avoid losing any interrupts.
+ */
+ masked_its = (~mask_value) & mb_value;
+ if (masked_its)
+ writeq(masked_its, mb_addr + KVX_MAILBOX_LAC_OFFSET);
+
+ for_each_set_bit(bit, (unsigned long *) &mb_value, BITS_PER_LONG) {
+ irqn = bit + mb_hwirq;
+ cascade_irq = irq_find_mapping(mb->device_domain, irqn);
+ generic_handle_irq(cascade_irq);
+ }
+}
+
+static void __init
+apic_mailbox_reset(struct kvx_apic_mailbox *mb)
+{
+ unsigned int i;
+ unsigned int mb_end = mb->mb_count;
+ void __iomem *mb_addr;
+ u64 funct_val = (KVX_MAILBOX_MODE_OR << KVX_MAILBOX_FUNCT_MODE_SHIFT) |
+ (KVX_MAILBOX_TRIG_DOORBELL << KVX_MAILBOX_FUNCT_TRIG_SHIFT);
+
+ for (i = 0; i < mb_end; i++) {
+ mb_addr = kvx_mailbox_get_addr(mb, i);
+ /* Disable all interrupts */
+ writeq(0ULL, mb_addr + KVX_MAILBOX_MASK_OFFSET);
+ /* Set mailbox to OR mode + trigger */
+ writeq(funct_val, mb_addr + KVX_MAILBOX_FUNCT_OFFSET);
+ /* Load & Clear mailbox value */
+ readq(mb_addr + KVX_MAILBOX_LAC_OFFSET);
+ }
+}
+
+static struct msi_domain_ops kvx_msi_domain_ops = {
+};
+
+static struct msi_domain_info kvx_msi_domain_info = {
+ .flags = (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS),
+ .ops = &kvx_msi_domain_ops,
+ .chip = &kvx_msi_irq_chip,
+};
+
+static int __init
+kvx_init_apic_mailbox(struct device_node *node,
+ struct device_node *parent)
+{
+ struct kvx_apic_mailbox *mb;
+ unsigned int parent_irq, irq_count;
+ struct resource res;
+ int ret, i;
+
+ mb = kzalloc(sizeof(*mb), GFP_KERNEL);
+ if (!mb)
+ return -ENOMEM;
+
+ ret = of_address_to_resource(node, 0, &res);
+ if (ret)
+ return -EINVAL;
+
+ mb->phys_base = res.start;
+ mb->base = of_io_request_and_map(node, 0, node->name);
+ if (!mb->base) {
+ ret = -EINVAL;
+ goto err_kfree;
+ }
+
+ spin_lock_init(&mb->mailboxes_lock);
+ raw_spin_lock_init(&mb->mask_lock);
+
+ irq_count = of_irq_count(node);
+ if (irq_count == 0 || irq_count > MAILBOXES_MAX_COUNT) {
+ ret = -EINVAL;
+ goto err_kfree;
+ }
+ mb->mb_count = irq_count;
+
+ apic_mailbox_reset(mb);
+
+ mb->device_domain = irq_domain_add_tree(node,
+ &kvx_apic_mailbox_domain_ops,
+ mb);
+ if (!mb->device_domain) {
+ pr_err("Failed to setup device domain\n");
+ ret = -EINVAL;
+ goto err_iounmap;
+ }
+
+ mb->msi_domain = platform_msi_create_irq_domain(of_node_to_fwnode(node),
+ &kvx_msi_domain_info,
+ mb->device_domain);
+ if (!mb->msi_domain) {
+ ret = -EINVAL;
+ goto err_irq_domain_add_tree;
+ }
+
+ /* Chain all interrupts from gic to mailbox */
+ for (i = 0; i < irq_count; i++) {
+ parent_irq = irq_of_parse_and_map(node, i);
+ if (parent_irq == 0) {
+ pr_err("unable to parse irq\n");
+ ret = -EINVAL;
+ goto err_irq_domain_msi_create;
+ }
+ mb->mb_data[i].parent_irq = parent_irq;
+
+ irq_set_chained_handler_and_data(parent_irq,
+ kvx_apic_mailbox_handle_irq,
+ mb);
+ }
+
+ pr_info("Init with %d device interrupt\n",
+ mb->mb_count * MAILBOXES_BIT_SIZE);
+
+ return 0;
+
+err_irq_domain_msi_create:
+ irq_domain_remove(mb->msi_domain);
+err_irq_domain_add_tree:
+ irq_domain_remove(mb->device_domain);
+err_iounmap:
+ iounmap(mb->base);
+err_kfree:
+ kfree(mb);
+
+ return ret;
+}
+
+IRQCHIP_DECLARE(kvx_apic_mailbox, "kalray,kvx-apic-mailbox",
+ kvx_init_apic_mailbox);
diff --git a/drivers/irqchip/irq-kvx-core-intc.c b/drivers/irqchip/irq-kvx-core-intc.c
new file mode 100644
index 000000000000..4315108d563c
--- /dev/null
+++ b/drivers/irqchip/irq-kvx-core-intc.c
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2017 - 2022 Kalray Inc.
+ * Author(s): Clement Leger
+ */
+
+#define pr_fmt(fmt) "kvx_core_intc: " fmt
+
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/irqchip.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/of.h>
+#include <asm/irq.h>
+
+#define KVX_CORE_INTC_IRQ 32
+
+
+static void kvx_irq_mask(struct irq_data *data)
+{
+ kvx_sfr_clear_bit(ILE, data->hwirq);
+}
+
+static void kvx_irq_unmask(struct irq_data *data)
+{
+ kvx_sfr_set_bit(ILE, data->hwirq);
+}
+
+static struct irq_chip kvx_irq_chip = {
+ .name = "kvx core Intc",
+ .irq_mask = kvx_irq_mask,
+ .irq_unmask = kvx_irq_unmask,
+};
+
+static int kvx_irq_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hw)
+{
+ /* All interrupts for core are per cpu */
+ irq_set_percpu_devid(irq);
+ irq_set_chip_and_handler(irq, &kvx_irq_chip, handle_percpu_irq);
+
+ return 0;
+}
+
+static const struct irq_domain_ops kvx_irq_ops = {
+ .xlate = irq_domain_xlate_onecell,
+ .map = kvx_irq_map,
+};
+
+static int __init
+kvx_init_core_intc(struct device_node *intc, struct device_node *parent)
+{
+ struct irq_domain *root_domain;
+ uint32_t core_nr_irqs;
+
+ if (parent)
+ panic("DeviceTree core intc not a root irq controller\n");
+
+ if (of_property_read_u32(intc, "kalray,intc-nr-irqs", &core_nr_irqs))
+ core_nr_irqs = KVX_CORE_INTC_IRQ;
+
+ /* We only have up to 32 interrupts, according to IRQ-domain.txt,
+ * linear is likely to be the best choice
+ */
+ root_domain = irq_domain_add_linear(intc, core_nr_irqs,
+ &kvx_irq_ops, NULL);
+ if (!root_domain)
+ panic("root irq domain not avail\n");
+
+ /*
+ * Needed for primary domain lookup to succeed
+ * This is a primary irqchip, and can never have a parent
+ */
+ irq_set_default_host(root_domain);
+
+ pr_info("Initialized with %d interrupts\n", core_nr_irqs);
+
+ return 0;
+}
+
+IRQCHIP_DECLARE(kvx_core_intc, "kalray,kvx-core-intc", kvx_init_core_intc);
diff --git a/drivers/irqchip/irq-kvx-itgen.c b/drivers/irqchip/irq-kvx-itgen.c
new file mode 100644
index 000000000000..1d35c2c772a0
--- /dev/null
+++ b/drivers/irqchip/irq-kvx-itgen.c
@@ -0,0 +1,224 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2017 - 2022 Kalray Inc.
+ * Author(s): Clement Leger
+ * Julian Vetter
+ * Vincent Chardon
+ */
+
+#include <linux/irqchip/irq-kvx-itgen.h>
+#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
+#include <linux/irqchip.h>
+#include <linux/module.h>
+#include <linux/msi.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+
+#define MB_ADDR_CLUSTER_SHIFT 24
+#define MB_ADDR_MAILBOX_SHIFT 9
+
+/**
+ * struct kvx_itgen - kvx interrupt generator (MSI client)
+ * @base: base address of the itgen controller
+ * @domain: IRQ domain of the controller
+ * @pdev: Platform device associated to the controller
+ */
+struct kvx_itgen {
+ void __iomem *base;
+ struct irq_domain *domain;
+ struct platform_device *pdev;
+};
+
+static void __iomem *get_itgen_cfg_offset(struct kvx_itgen *itgen,
+ irq_hw_number_t hwirq)
+{
+ return itgen->base + KVX_ITGEN_CFG_TARGET_OFFSET +
+ hwirq * KVX_ITGEN_CFG_ELEM_SIZE;
+}
+
+void __iomem *get_itgen_param_offset(struct kvx_itgen *itgen)
+{
+ return itgen->base + KVX_ITGEN_PARAM_OFFSET;
+}
+
+static void kvx_itgen_enable(struct irq_data *data, u32 value)
+{
+ struct kvx_itgen *itgen = irq_data_get_irq_chip_data(data);
+ void __iomem *enable_reg =
+ get_itgen_cfg_offset(itgen, irqd_to_hwirq(data)) +
+ KVX_ITGEN_CFG_ENABLE_OFFSET;
+
+ dev_dbg(&itgen->pdev->dev, "%sabling hwirq %d, addr %p\n",
+ value ? "En" : "Dis",
+ (int) irqd_to_hwirq(data),
+ enable_reg);
+ writel(value, enable_reg);
+}
+
+static void kvx_itgen_mask(struct irq_data *data)
+{
+ kvx_itgen_enable(data, 0x0);
+ irq_chip_mask_parent(data);
+}
+
+static void kvx_itgen_unmask(struct irq_data *data)
+{
+ kvx_itgen_enable(data, 0x1);
+ irq_chip_unmask_parent(data);
+}
+
+#ifdef CONFIG_SMP
+static int kvx_itgen_irq_set_affinity(struct irq_data *data,
+ const struct cpumask *dest, bool force)
+{
+ return -ENOSYS;
+}
+#endif
+
+static struct irq_chip itgen_irq_chip = {
+ .name = "kvx-itgen",
+ .irq_mask = kvx_itgen_mask,
+ .irq_unmask = kvx_itgen_unmask,
+#ifdef CONFIG_SMP
+ .irq_set_affinity = kvx_itgen_irq_set_affinity,
+#endif
+};
+
+#define ITGEN_UNSUPPORTED_TYPES (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_EDGE_FALLING)
+
+static int kvx_itgen_domain_alloc(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs, void *args)
+{
+ int i, err;
+ struct irq_fwspec *fwspec = args;
+ int hwirq = fwspec->param[0];
+ int type = IRQ_TYPE_NONE;
+ struct kvx_itgen *itgen;
+
+ if (fwspec->param_count >= 2)
+ type = fwspec->param[1];
+
+ WARN_ON(type & ITGEN_UNSUPPORTED_TYPES);
+
+ err = platform_msi_device_domain_alloc(domain, virq, nr_irqs);
+ if (err)
+ return err;
+
+ itgen = platform_msi_get_host_data(domain);
+
+ for (i = 0; i < nr_irqs; i++) {
+ irq_domain_set_hwirq_and_chip(domain, virq + i, hwirq + i,
+ &itgen_irq_chip, itgen);
+ if (type == IRQ_TYPE_LEVEL_HIGH)
+ irq_set_handler(virq + i, handle_level_irq);
+ }
+
+ return 0;
+}
+
+static const struct irq_domain_ops itgen_domain_ops = {
+ .alloc = kvx_itgen_domain_alloc,
+ .free = irq_domain_free_irqs_common,
+};
+
+static void kvx_itgen_write_msg(struct msi_desc *desc, struct msi_msg *msg)
+{
+ struct irq_data *d = irq_get_irq_data(desc->irq);
+ struct kvx_itgen *itgen = irq_data_get_irq_chip_data(d);
+ uint32_t cfg_val = 0;
+ uintptr_t dest_addr = ((uint64_t) msg->address_hi << 32) |
+ msg->address_lo;
+ void __iomem *cfg = get_itgen_cfg_offset(itgen, irqd_to_hwirq(d));
+
+ /**
+ * Address in the msi data is the address of the targeted mailbox.
+ * To save a few cells of hw, itgen configuration expects the
+ * target of the write using mppa id, cluster id and mailbox id instead
+ * of address.
+ * We extract these information from mailbox address.
+ */
+
+ cfg_val |= (((kvx_sfr_get(PCR) & KVX_SFR_PCR_CID_MASK) >>
+ KVX_SFR_PCR_CID_SHIFT)
+ << KVX_ITGEN_CFG_TARGET_CLUSTER_SHIFT);
+ cfg_val |= ((dest_addr >> MB_ADDR_MAILBOX_SHIFT) &
+ KVX_ITGEN_CFG_TARGET_MAILBOX_MASK)
+ << KVX_ITGEN_CFG_TARGET_MAILBOX_SHIFT;
+
+ /**
+ * msg->data contains the bit number to be written and is included in
+ * the itgen config
+ */
+ cfg_val |= ((msg->data << KVX_ITGEN_CFG_TARGET_SELECT_BIT_SHIFT)
+ & KVX_ITGEN_CFG_TARGET_SELECT_BIT_MASK);
+
+ dev_dbg(&itgen->pdev->dev,
+ "Writing dest_addr %lx, value %x to cfg %p\n",
+ dest_addr, cfg_val, cfg);
+
+ writel(cfg_val, cfg);
+}
+
+static int
+kvx_itgen_device_probe(struct platform_device *pdev)
+{
+ struct kvx_itgen *itgen;
+ u32 it_count;
+ struct resource *mem;
+
+ itgen = devm_kzalloc(&pdev->dev, sizeof(*itgen), GFP_KERNEL);
+ if (!itgen)
+ return -ENOMEM;
+
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ itgen->base = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(itgen->base)) {
+ dev_err(&pdev->dev, "Failed to ioremap itgen\n");
+ return PTR_ERR(itgen->base);
+ }
+
+ itgen->pdev = pdev;
+ it_count = readl(get_itgen_param_offset(itgen) +
+ KVX_ITGEN_PARAM_IT_NUM_OFFSET);
+
+ itgen->domain = platform_msi_create_device_domain(&pdev->dev,
+ it_count,
+ kvx_itgen_write_msg,
+ &itgen_domain_ops,
+ itgen);
+ if (!itgen->domain) {
+ dev_err(&pdev->dev, "Failed to create device domain\n");
+ return -ENOMEM;
+ }
+
+ dev_info(&pdev->dev, "Probed with %d interrupts\n", it_count);
+
+ platform_set_drvdata(pdev, itgen);
+
+ return 0;
+}
+
+static const struct of_device_id itgen_of_match[] = {
+ { .compatible = "kalray,kvx-itgen" },
+ { /* END */ }
+};
+MODULE_DEVICE_TABLE(of, itgen_of_match);
+
+static struct platform_driver itgen_platform_driver = {
+ .driver = {
+ .name = "kvx-itgen",
+ .of_match_table = itgen_of_match,
+ },
+ .probe = kvx_itgen_device_probe,
+};
+
+static int __init kvx_itgen_init(void)
+{
+ return platform_driver_register(&itgen_platform_driver);
+}
+
+arch_initcall(kvx_itgen_init);
diff --git a/include/linux/irqchip/irq-kvx-apic-gic.h b/include/linux/irqchip/irq-kvx-apic-gic.h
new file mode 100644
index 000000000000..8efbcd05f3ea
--- /dev/null
+++ b/include/linux/irqchip/irq-kvx-apic-gic.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018-2023 Kalray Inc.
+ * Author: Clement Leger
+ */
+
+#ifndef KVX_APIC_GIC_H
+#define KVX_APIC_GIC_H
+
+/* GIC enable register definitions */
+#define KVX_GIC_ENABLE_OFFSET 0x0
+#define KVX_GIC_ENABLE_ELEM_SIZE 0x1
+#define KVX_GIC_INPUT_IT_COUNT 0x9D
+#define KVX_GIC_ELEM_SIZE 0x400
+
+/* GIC status lac register definitions */
+#define KVX_GIC_STATUS_LAC_OFFSET 0x120
+#define KVX_GIC_STATUS_LAC_ELEM_SIZE 0x8
+#define KVX_GIC_STATUS_LAC_ARRAY_SIZE 0x3
+
+#endif /* KVX_APIC_GIC_H */
diff --git a/include/linux/irqchip/irq-kvx-apic-mailbox.h b/include/linux/irqchip/irq-kvx-apic-mailbox.h
new file mode 100644
index 000000000000..40ec60de155c
--- /dev/null
+++ b/include/linux/irqchip/irq-kvx-apic-mailbox.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018-2023 Kalray Inc.
+ */
+
+#ifndef IRQ_KVX_APIC_MAILBOX_H
+#define IRQ_KVX_APIC_MAILBOX_H
+
+#define KVX_MAILBOX_MODE_WRITE 0x0
+#define KVX_MAILBOX_MODE_OR 0x1
+#define KVX_MAILBOX_MODE_ADD 0x2
+
+#define KVX_MAILBOX_TRIG_NO_TRIG 0x0
+#define KVX_MAILBOX_TRIG_DOORBELL 0x1
+#define KVX_MAILBOX_TRIG_MATCH 0x2
+#define KVX_MAILBOX_TRIG_BARRIER 0x3
+#define KVX_MAILBOX_TRIG_THRESHOLD 0x4
+
+/* Mailbox defines */
+#define KVX_MAILBOX_OFFSET 0x0
+#define KVX_MAILBOX_ELEM_SIZE 0x200
+#define KVX_MAILBOX_MASK_OFFSET 0x10
+#define KVX_MAILBOX_FUNCT_OFFSET 0x18
+#define KVX_MAILBOX_LAC_OFFSET 0x8
+#define KVX_MAILBOX_VALUE_OFFSET 0x0
+#define KVX_MAILBOX_FUNCT_MODE_SHIFT 0x0
+#define KVX_MAILBOX_FUNCT_TRIG_SHIFT 0x8
+
+#endif /* IRQ_KVX_APIC_MAILBOX_H */
diff --git a/include/linux/irqchip/irq-kvx-itgen.h b/include/linux/irqchip/irq-kvx-itgen.h
new file mode 100644
index 000000000000..6845a2509b14
--- /dev/null
+++ b/include/linux/irqchip/irq-kvx-itgen.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2018-2023 Kalray Inc.
+ */
+
+#ifndef IRQ_KVX_ITGEN_H
+#define IRQ_KVX_ITGEN_H
+
+/* Parameters */
+#define KVX_ITGEN_PARAM_OFFSET 0x1100
+#define KVX_ITGEN_PARAM_IT_NUM_OFFSET 0x0
+
+/* Target configuration */
+#define KVX_ITGEN_CFG_ENABLE_OFFSET 0x8
+#define KVX_ITGEN_CFG_ELEM_SIZE 0x10
+#define KVX_ITGEN_CFG_TARGET_OFFSET 0x0
+#define KVX_ITGEN_CFG_TARGET_MAILBOX_SHIFT 0x0
+#define KVX_ITGEN_CFG_TARGET_MAILBOX_MASK 0x7FUL
+#define KVX_ITGEN_CFG_TARGET_CLUSTER_SHIFT 0x8
+#define KVX_ITGEN_CFG_TARGET_CLUSTER_MASK 0x700UL
+#define KVX_ITGEN_CFG_TARGET_SELECT_BIT_SHIFT 0x18
+#define KVX_ITGEN_CFG_TARGET_SELECT_BIT_MASK 0x3F000000UL
+
+#endif /* IRQ_KVX_ITGEN_H */
--
2.37.2







2023-01-03 17:21:45

by Yann Sionneau

[permalink] [raw]
Subject: [RFC PATCH 24/25] kvx: Add support for CPU Perf Monitors

Each kvx core includes several Perf Monitors.
This commit adds the driver that handles those core PM.

CC: Will Deacon <[email protected]>
CC: Mark Rutland <[email protected]>
CC: Rob Herring <[email protected]>
CC: Krzysztof Kozlowski <[email protected]>
CC: Peter Zijlstra <[email protected]>
CC: Ingo Molnar <[email protected]>
CC: Arnaldo Carvalho de Melo <[email protected]>
CC: Alexander Shishkin <[email protected]>
CC: Jiri Olsa <[email protected]>
CC: Namhyung Kim <[email protected]>
CC: [email protected]
CC: [email protected]
CC: [email protected]
CC: [email protected]
Co-developed-by: Clement Leger <[email protected]>
Signed-off-by: Clement Leger <[email protected]>
Co-developed-by: Jules Maselbas <[email protected]>
Signed-off-by: Jules Maselbas <[email protected]>
Co-developed-by: Julian Vetter <[email protected]>
Signed-off-by: Julian Vetter <[email protected]>
Co-developed-by: Yann Sionneau <[email protected]>
Signed-off-by: Yann Sionneau <[email protected]>
---
.../devicetree/bindings/perf/kalray-pm.txt | 21 +
arch/kvx/include/asm/perf_event.h | 90 +++
arch/kvx/kernel/perf_event.c | 609 ++++++++++++++++++
3 files changed, 720 insertions(+)
create mode 100644 Documentation/devicetree/bindings/perf/kalray-pm.txt
create mode 100644 arch/kvx/include/asm/perf_event.h
create mode 100644 arch/kvx/kernel/perf_event.c

diff --git a/Documentation/devicetree/bindings/perf/kalray-pm.txt b/Documentation/devicetree/bindings/perf/kalray-pm.txt
new file mode 100644
index 000000000000..9ce00d703941
--- /dev/null
+++ b/Documentation/devicetree/bindings/perf/kalray-pm.txt
@@ -0,0 +1,21 @@
+* Kalray kvx Performance Monitors
+
+KVX core has several Performance Monitors for counting cpu and cache events.
+The KVX PM representation in the device tree should be done as under:
+
+Required properties:
+
+- compatible :
+ "kalray,kvx-core-pm"
+
+- interrupts : The interrupt number for kvx PM is 3.
+- interrupt-parent : The kvx core interrupt controller.
+- kalray,pm-num : Number of Performance Monitors the kvx core has.
+
+Example:
+core_pm {
+ compatible = "kalray,kvx-core-pm";
+ interrupts = <3>;
+ interrupt-parent = <&core_intc>;
+ kalray,pm-num = <4>;
+}
diff --git a/arch/kvx/include/asm/perf_event.h b/arch/kvx/include/asm/perf_event.h
new file mode 100644
index 000000000000..bb0147dfdf47
--- /dev/null
+++ b/arch/kvx/include/asm/perf_event.h
@@ -0,0 +1,90 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Yann Sionneau
+ * Clement Leger
+ */
+
+#ifndef _ASM_KVX_PERF_EVENT_H
+#define _ASM_KVX_PERF_EVENT_H
+
+#include <linux/perf_event.h>
+
+/**
+ * struct cpu_hw_events - per-cpu structure to describe PM resource usage
+ * @n_events: number of events currently existing
+ * @events: events[i] is the event using PMi. NULL if PMi is not used.
+ */
+struct cpu_hw_events {
+ unsigned int n_events;
+ struct perf_event **events;
+};
+
+enum kvx_pmc_ie {
+ PMC_IE_DISABLED,
+ PMC_IE_ENABLED
+};
+
+enum kvx_pm_idx {
+ KVX_PM_1,
+ KVX_PM_2,
+ KVX_PM_3
+};
+
+enum kvx_pm_event_code {
+ KVX_PM_PCC,
+ KVX_PM_ICC,
+ KVX_PM_EBE,
+ KVX_PM_ENIE,
+ KVX_PM_ENSE,
+ KVX_PM_ICHE,
+ KVX_PM_ICME,
+ KVX_PM_ICMABE,
+ KVX_PM_MNGIC,
+ KVX_PM_MIMHE,
+ KVX_PM_MIMME,
+ KVX_PM_IATSC,
+ KVX_PM_FE,
+ KVX_PM_PBSC,
+ KVX_PM_PNVC,
+ KVX_PM_PSC,
+ KVX_PM_TADBE,
+ KVX_PM_TABE,
+ KVX_PM_TBE,
+ KVX_PM_MDMHE,
+ KVX_PM_MDMME,
+ KVX_PM_DATSC,
+ KVX_PM_DCLHE,
+ KVX_PM_DCHE,
+ KVX_PM_DCLME,
+ KVX_PM_DCME,
+ KVX_PM_DARSC,
+ KVX_PM_LDSC,
+ KVX_PM_DCNGC,
+ KVX_PM_DMAE,
+ KVX_PM_LCFSC,
+ KVX_PM_MNGDC,
+ KVX_PM_MACC,
+ KVX_PM_TACC,
+ KVX_PM_IWC,
+ KVX_PM_WISC,
+ KVX_PM_SISC,
+ KVX_PM_DDSC,
+ KVX_PM_SC,
+ KVX_PM_ELE,
+ KVX_PM_ELNBE,
+ KVX_PM_ELUE,
+ KVX_PM_ELUNBE,
+ KVX_PM_ESE,
+ KVX_PM_ESNBE,
+ KVX_PM_EAE,
+ KVX_PM_CIRE,
+ KVX_PM_CIE,
+ KVX_PM_SE,
+ KVX_PM_RE,
+ KVX_PM_FSC,
+ KVX_PM_MAX,
+ KVX_PM_UNSUPPORTED = KVX_PM_MAX,
+};
+
+#endif /* _ASM_KVX_PERF_EVENT_H */
diff --git a/arch/kvx/kernel/perf_event.c b/arch/kvx/kernel/perf_event.c
new file mode 100644
index 000000000000..bfc547e78aba
--- /dev/null
+++ b/arch/kvx/kernel/perf_event.c
@@ -0,0 +1,609 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Yann Sionneau
+ * Clement Leger
+ */
+
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/kernel.h>
+#include <linux/perf_event.h>
+#include <linux/errno.h>
+#include <linux/platform_device.h>
+#include <asm/perf_event.h>
+
+static unsigned int pm_num;
+static unsigned int kvx_pm_irq;
+static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events);
+
+static const enum kvx_pm_event_code kvx_hw_event_map[] = {
+ [PERF_COUNT_HW_CPU_CYCLES] = KVX_PM_PCC,
+ [PERF_COUNT_HW_INSTRUCTIONS] = KVX_PM_ENIE,
+ [PERF_COUNT_HW_CACHE_REFERENCES] = KVX_PM_UNSUPPORTED,
+ [PERF_COUNT_HW_CACHE_MISSES] = KVX_PM_UNSUPPORTED,
+ [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = KVX_PM_TABE,
+ [PERF_COUNT_HW_BRANCH_MISSES] = KVX_PM_UNSUPPORTED,
+ [PERF_COUNT_HW_BUS_CYCLES] = KVX_PM_PCC,
+ [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = KVX_PM_PSC,
+ [PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = KVX_PM_UNSUPPORTED,
+ [PERF_COUNT_HW_REF_CPU_CYCLES] = KVX_PM_UNSUPPORTED,
+};
+
+#define C(_x) PERF_COUNT_HW_CACHE_##_x
+
+static const enum kvx_pm_event_code
+ kvx_cache_map[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
+[C(L1D)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = KVX_PM_UNSUPPORTED,
+ [C(RESULT_MISS)] = KVX_PM_DCLME,
+ },
+ [C(OP_WRITE)] = {
+ [C(RESULT_ACCESS)] = KVX_PM_UNSUPPORTED,
+ [C(RESULT_MISS)] = KVX_PM_UNSUPPORTED,
+ },
+ [C(OP_PREFETCH)] = {
+ [C(RESULT_ACCESS)] = KVX_PM_UNSUPPORTED,
+ [C(RESULT_MISS)] = KVX_PM_UNSUPPORTED,
+ },
+},
+[C(L1I)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = KVX_PM_UNSUPPORTED,
+ [C(RESULT_MISS)] = KVX_PM_ICME,
+ },
+ [C(OP_WRITE)] = {
+ [C(RESULT_ACCESS)] = KVX_PM_UNSUPPORTED,
+ [C(RESULT_MISS)] = KVX_PM_UNSUPPORTED,
+ },
+ [C(OP_PREFETCH)] = {
+ [C(RESULT_ACCESS)] = KVX_PM_UNSUPPORTED,
+ [C(RESULT_MISS)] = KVX_PM_UNSUPPORTED,
+ },
+},
+[C(LL)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = KVX_PM_UNSUPPORTED,
+ [C(RESULT_MISS)] = KVX_PM_UNSUPPORTED,
+ },
+ [C(OP_WRITE)] = {
+ [C(RESULT_ACCESS)] = KVX_PM_UNSUPPORTED,
+ [C(RESULT_MISS)] = KVX_PM_UNSUPPORTED,
+ },
+ [C(OP_PREFETCH)] = {
+ [C(RESULT_ACCESS)] = KVX_PM_UNSUPPORTED,
+ [C(RESULT_MISS)] = KVX_PM_UNSUPPORTED,
+ },
+},
+[C(DTLB)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = KVX_PM_UNSUPPORTED,
+ [C(RESULT_MISS)] = KVX_PM_UNSUPPORTED,
+ },
+ [C(OP_WRITE)] = {
+ [C(RESULT_ACCESS)] = KVX_PM_UNSUPPORTED,
+ [C(RESULT_MISS)] = KVX_PM_UNSUPPORTED,
+ },
+ [C(OP_PREFETCH)] = {
+ [C(RESULT_ACCESS)] = KVX_PM_UNSUPPORTED,
+ [C(RESULT_MISS)] = KVX_PM_UNSUPPORTED,
+ },
+},
+[C(ITLB)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = KVX_PM_UNSUPPORTED,
+ [C(RESULT_MISS)] = KVX_PM_MIMME,
+ },
+ [C(OP_WRITE)] = {
+ [C(RESULT_ACCESS)] = KVX_PM_UNSUPPORTED,
+ [C(RESULT_MISS)] = KVX_PM_UNSUPPORTED,
+ },
+ [C(OP_PREFETCH)] = {
+ [C(RESULT_ACCESS)] = KVX_PM_UNSUPPORTED,
+ [C(RESULT_MISS)] = KVX_PM_UNSUPPORTED,
+ },
+},
+[C(BPU)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = KVX_PM_UNSUPPORTED,
+ [C(RESULT_MISS)] = KVX_PM_UNSUPPORTED,
+ },
+ [C(OP_WRITE)] = {
+ [C(RESULT_ACCESS)] = KVX_PM_UNSUPPORTED,
+ [C(RESULT_MISS)] = KVX_PM_UNSUPPORTED,
+ },
+ [C(OP_PREFETCH)] = {
+ [C(RESULT_ACCESS)] = KVX_PM_UNSUPPORTED,
+ [C(RESULT_MISS)] = KVX_PM_UNSUPPORTED,
+ },
+},
+[C(NODE)] = {
+ [C(OP_READ)] = {
+ [C(RESULT_ACCESS)] = KVX_PM_UNSUPPORTED,
+ [C(RESULT_MISS)] = KVX_PM_UNSUPPORTED,
+ },
+ [C(OP_WRITE)] = {
+ [C(RESULT_ACCESS)] = KVX_PM_UNSUPPORTED,
+ [C(RESULT_MISS)] = KVX_PM_UNSUPPORTED,
+ },
+ [C(OP_PREFETCH)] = {
+ [C(RESULT_ACCESS)] = KVX_PM_UNSUPPORTED,
+ [C(RESULT_MISS)] = KVX_PM_UNSUPPORTED,
+ },
+},
+};
+
+static u64 read_counter(struct perf_event *event)
+{
+ struct hw_perf_event *hwc = &event->hw;
+ unsigned int pm = hwc->idx;
+
+ if (pm > pm_num) {
+ WARN_ONCE(1, "This PM (%u) does not exist!\n", pm);
+ return 0;
+ }
+ return kvx_sfr_iget(KVX_SFR_PM1 + pm);
+}
+
+static void kvx_pmu_read(struct perf_event *event)
+{
+ struct hw_perf_event *hwc = &event->hw;
+ u64 delta, prev_raw_count, new_raw_count;
+
+ do {
+ prev_raw_count = local64_read(&hwc->prev_count);
+ new_raw_count = read_counter(event);
+ } while (local64_cmpxchg(&hwc->prev_count, prev_raw_count,
+ new_raw_count) != prev_raw_count);
+ /*
+ * delta is the value to update the counter we maintain in the kernel.
+ */
+ delta = (new_raw_count - prev_raw_count);
+ local64_add(delta, &event->count);
+}
+
+static void kvx_set_pmc_ie(unsigned int pm_num, enum kvx_pmc_ie ievalue)
+{
+ u64 shifted_value = ((u64)ievalue << KVX_SFR_PMC_PM1IE_SHIFT)
+ & KVX_SFR_PMC_PM1IE_MASK;
+ u64 clr_mask = KVX_SFR_PMC_PM1IE_MASK << pm_num;
+ u64 set_mask = shifted_value << pm_num;
+
+ kvx_sfr_set_mask(PMC, clr_mask, set_mask);
+}
+
+static void kvx_set_pmc(unsigned int pm_num, enum kvx_pm_event_code pmc_value)
+{
+ u64 pm_shift = (pm_num + 1) * KVX_SFR_PMC_PM1C_SHIFT;
+ u64 clr_mask = KVX_SFR_PMC_PM0C_MASK << pm_shift;
+ u64 set_mask = pmc_value << pm_shift;
+
+ kvx_sfr_set_mask(PMC, clr_mask, set_mask);
+}
+
+static void give_pm_to_user(unsigned int pm)
+{
+ int pl_value = 1 << (KVX_SFR_MOW_PM0_SHIFT
+ + KVX_SFR_MOW_PM0_WIDTH * (pm + 1));
+ int pl_clr_mask = 3 << (KVX_SFR_MOW_PM0_SHIFT
+ + KVX_SFR_MOW_PM0_WIDTH * (pm + 1));
+ kvx_sfr_set_mask(MOW, pl_clr_mask, pl_value);
+}
+
+static void get_pm_back_to_kernel(unsigned int pm)
+{
+ int pl_value = 0;
+ int pl_clr_mask = 3 << (KVX_SFR_MOW_PM0_SHIFT
+ + KVX_SFR_MOW_PM0_WIDTH * (pm + 1));
+ kvx_sfr_set_mask(MOW, pl_clr_mask, pl_value);
+}
+
+static void kvx_set_pm(enum kvx_pm_idx pm, u64 value)
+{
+ switch (pm) {
+ case KVX_PM_1:
+ kvx_sfr_set(PM1, value);
+ break;
+ case KVX_PM_2:
+ kvx_sfr_set(PM2, value);
+ break;
+ case KVX_PM_3:
+ kvx_sfr_set(PM3, value);
+ break;
+ default:
+ WARN_ONCE(1, "This PM (%u) does not exist!\n", pm);
+ }
+}
+
+static void kvx_stop_sampling_event(unsigned int pm)
+{
+ kvx_set_pmc_ie(pm, PMC_IE_DISABLED);
+}
+
+static u64 kvx_start_sampling_event(struct perf_event *event, unsigned int pm)
+{
+ u64 start_value;
+
+ if (event->attr.freq) {
+ pr_err_once("kvx_pm: Frequency sampling is not supported\n");
+ return 0;
+ }
+
+ /* PM counter will overflow after "sample_period" ticks */
+ start_value = (u64)(-event->attr.sample_period);
+
+ kvx_set_pmc(pm, KVX_PM_SE);
+ kvx_set_pm(pm, start_value);
+ kvx_set_pmc_ie(pm, PMC_IE_ENABLED);
+ return start_value;
+}
+
+static void kvx_pmu_start(struct perf_event *event, int flags)
+{
+ struct hw_perf_event *hwc = &event->hw;
+ struct perf_event_attr *attr = &event->attr;
+ u64 pm_config = hwc->config;
+ unsigned int pm = hwc->idx;
+ u64 start_value = 0;
+
+ if (WARN_ON_ONCE(!(event->hw.state & PERF_HES_STOPPED)))
+ return;
+
+ if (flags & PERF_EF_RELOAD)
+ WARN_ON_ONCE(!(event->hw.state & PERF_HES_UPTODATE));
+
+ hwc->state = 0;
+ perf_event_update_userpage(event);
+
+ if (is_sampling_event(event))
+ start_value = kvx_start_sampling_event(event, pm);
+
+ local64_set(&hwc->prev_count, start_value);
+ if (attr->exclude_kernel)
+ give_pm_to_user(pm);
+ if (!is_sampling_event(event))
+ kvx_set_pmc(pm, KVX_PM_RE);
+ kvx_set_pmc(pm, pm_config);
+}
+
+static void kvx_pmu_stop(struct perf_event *event, int flags)
+{
+ struct hw_perf_event *hwc = &event->hw;
+ struct perf_event_attr *attr = &event->attr;
+ unsigned int pm = hwc->idx;
+
+ if (is_sampling_event(event))
+ kvx_stop_sampling_event(pm);
+
+ kvx_set_pmc(pm, KVX_PM_SE);
+ if (attr->exclude_kernel)
+ get_pm_back_to_kernel(pm);
+
+ WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED);
+ hwc->state |= PERF_HES_STOPPED;
+
+ if ((flags & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) {
+ kvx_pmu_read(event);
+ hwc->state |= PERF_HES_UPTODATE;
+ }
+}
+
+static void kvx_pmu_del(struct perf_event *event, int flags)
+{
+ struct hw_perf_event *hwc = &event->hw;
+ struct cpu_hw_events *cpuc = &get_cpu_var(cpu_hw_events);
+
+ cpuc->events[hwc->idx] = NULL;
+ cpuc->n_events--;
+ put_cpu_var(cpu_hw_events);
+ kvx_pmu_stop(event, PERF_EF_UPDATE);
+ perf_event_update_userpage(event);
+}
+
+static int kvx_pmu_add(struct perf_event *event, int flags)
+{
+ struct hw_perf_event *hwc = &event->hw;
+ struct cpu_hw_events *cpuc = &get_cpu_var(cpu_hw_events);
+ unsigned int i, idx = -1;
+
+ if (cpuc->n_events >= pm_num) {
+ put_cpu_var(cpu_hw_events);
+ return -ENOSPC;
+ }
+
+ for (i = 0; i < pm_num; i++)
+ if (cpuc->events[i] == NULL)
+ idx = i;
+
+ BUG_ON(idx == -1);
+
+ hwc->idx = idx;
+ cpuc->events[idx] = event;
+ cpuc->n_events++;
+ put_cpu_var(cpu_hw_events);
+ hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
+
+ if (flags & PERF_EF_START)
+ kvx_pmu_start(event, PERF_EF_RELOAD);
+
+ return 0;
+}
+
+static enum kvx_pm_event_code kvx_pmu_cache_event(u64 config)
+{
+ unsigned int type, op, result;
+ enum kvx_pm_event_code code;
+
+ type = (config >> 0) & 0xff;
+ op = (config >> 8) & 0xff;
+ result = (config >> 16) & 0xff;
+ if (type >= PERF_COUNT_HW_CACHE_MAX ||
+ op >= PERF_COUNT_HW_CACHE_OP_MAX ||
+ result >= PERF_COUNT_HW_CACHE_RESULT_MAX)
+ return KVX_PM_UNSUPPORTED;
+
+ code = kvx_cache_map[type][op][result];
+
+ return code;
+}
+
+static int kvx_pm_starting_cpu(unsigned int cpu)
+{
+ struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu);
+
+ cpuc->events = kmalloc_array(pm_num, sizeof(struct perf_event *),
+ GFP_ATOMIC);
+ if (!cpuc->events)
+ return -ENOMEM;
+
+ memset(cpuc->events, 0, pm_num * sizeof(struct perf_event *));
+
+ enable_percpu_irq(kvx_pm_irq, IRQ_TYPE_NONE);
+ return 0;
+}
+
+static int kvx_pm_dying_cpu(unsigned int cpu)
+{
+ struct cpu_hw_events *cpuc = &get_cpu_var(cpu_hw_events);
+
+ disable_percpu_irq(kvx_pm_irq);
+ kfree(cpuc->events);
+ put_cpu_var(cpu_hw_events);
+ return 0;
+}
+
+static enum kvx_pm_event_code kvx_pmu_raw_events(u64 config)
+{
+ if (config >= KVX_PM_MAX)
+ return KVX_PM_UNSUPPORTED;
+
+ if (config == KVX_PM_SE || config == KVX_PM_RE)
+ return KVX_PM_UNSUPPORTED;
+
+ return config;
+}
+
+static int kvx_pmu_event_init(struct perf_event *event)
+{
+ struct perf_event_attr *attr = &event->attr;
+ struct hw_perf_event *hwc = &event->hw;
+ enum kvx_pm_event_code code;
+
+ if (attr->exclude_user && !attr->exclude_kernel) {
+ attr->exclude_user = 0;
+ pr_err_once("kvx_pm: Cannot exclude userspace from perf events and not kernelspace\n");
+ }
+
+ switch (attr->type) {
+ case PERF_TYPE_HARDWARE:
+ code = kvx_hw_event_map[attr->config];
+ break;
+ case PERF_TYPE_HW_CACHE:
+ code = kvx_pmu_cache_event(attr->config);
+ break;
+ case PERF_TYPE_RAW:
+ code = kvx_pmu_raw_events(attr->config);
+ break;
+ default:
+ return -ENOENT;
+ }
+
+ if (code == KVX_PM_UNSUPPORTED)
+ return -EOPNOTSUPP;
+
+ hwc->config = code;
+ hwc->idx = -1;
+
+ if (event->cpu >= 0 && !cpu_online(event->cpu))
+ return -ENODEV;
+
+ return 0;
+}
+
+static struct pmu pmu = {
+ .event_init = kvx_pmu_event_init,
+ .add = kvx_pmu_add,
+ .del = kvx_pmu_del,
+ .start = kvx_pmu_start,
+ .stop = kvx_pmu_stop,
+ .read = kvx_pmu_read,
+};
+
+static void kvx_pm_clear_sav(void)
+{
+ u64 clr_mask = KVX_SFR_PMC_SAV_MASK;
+ u64 set_mask = 0;
+
+ kvx_sfr_set_mask(PMC, clr_mask, set_mask);
+}
+
+static void kvx_pm_reload(struct perf_event *event)
+{
+ struct hw_perf_event *hwc = &event->hw;
+ u64 pm = hwc->idx;
+ u64 start_value = (u64)(-event->attr.sample_period);
+
+ kvx_set_pmc(pm, KVX_PM_SE);
+ kvx_set_pm(pm, start_value);
+}
+
+static bool kvx_pm_is_sav_set(void)
+{
+ return kvx_sfr_get(PMC) & KVX_SFR_PMC_SAV_MASK;
+}
+
+static int handle_pm_overflow(u8 pm_id, struct perf_event *event, u64 pmc,
+ struct pt_regs *regs)
+{
+ u64 pm_ie_mask = KVX_SFR_PMC_PM0IE_MASK << (pm_id + 1);
+ u64 pmc_event_code_mask = KVX_SFR_PMC_PM0C_MASK <<
+ ((pm_id + 1)
+ * KVX_SFR_PMC_PM1C_SHIFT);
+ struct hw_perf_event *hwc = &event->hw;
+ struct perf_sample_data data;
+ u64 sample_period;
+ u64 pm;
+
+ sample_period = event->attr.sample_period;
+ pm = kvx_sfr_iget(pm_id + KVX_SFR_PM1);
+
+ /*
+ * check if this pm has just overflowed
+ * ie: pm value is 0, pm interrupt is enabled
+ * and pm is not stopped.
+ */
+ if ((pm < local64_read(&hwc->prev_count)) && (pmc & pm_ie_mask)
+ && ((pmc & pmc_event_code_mask) != KVX_PM_SE)) {
+ perf_sample_data_init(&data, 0, sample_period);
+ if (perf_event_overflow(event, &data, regs))
+ pmu.stop(event, 0);
+ else {
+ kvx_pmu_read(event);
+ if (is_sampling_event(event))
+ kvx_pm_reload(event);
+ }
+ return 1;
+ }
+
+ return 0;
+}
+
+irqreturn_t pm_irq_handler(int irq, void *dev_id)
+{
+ struct cpu_hw_events *cpuc = &get_cpu_var(cpu_hw_events);
+ struct pt_regs *regs;
+ enum kvx_pm_idx pm_id;
+ u64 pmc;
+ bool a_pm_overflowed = false;
+ irqreturn_t ret = IRQ_NONE;
+
+ regs = get_irq_regs();
+ pmc = kvx_sfr_get(PMC);
+
+ for (pm_id = KVX_PM_1; pm_id <= KVX_PM_3; pm_id++) {
+ struct perf_event *event = cpuc->events[pm_id];
+
+ if (!event)
+ continue;
+
+ if (handle_pm_overflow(pm_id, event, pmc, regs)) {
+ ret = IRQ_HANDLED;
+ a_pm_overflowed = true;
+ }
+ }
+
+ put_cpu_var(cpu_hw_events);
+
+ if (likely(kvx_pm_is_sav_set()))
+ kvx_pm_clear_sav();
+ else
+ pr_err_once("kvx_pm: PM triggered an IRQ but did not set pmc.sav\n");
+
+ if (unlikely(!a_pm_overflowed))
+ pr_err_once("kvx_pm: PM triggered an IRQ but no PM seemed to have overflowed\n");
+
+ if (ret == IRQ_HANDLED)
+ irq_work_run();
+ return ret;
+}
+
+static int kvx_pmu_device_probe(struct platform_device *pdev)
+{
+ int ret;
+ int statenum;
+ struct device *dev = &pdev->dev;
+
+ ret = of_property_read_u32(dev->of_node, "kalray,pm-num", &pm_num);
+ if (ret < 0) {
+ dev_err(dev, "Cannot read kalray,pm-num from device tree\n");
+ return -ENODEV;
+ }
+
+ /*
+ * PM0 is reserved for cycle counting, that's why pm_num is
+ * decremented.
+ */
+ if (pm_num-- < 2) {
+ dev_err(dev, "Not enough PM to handle perf events, at least 2 are needed\n");
+ return -ENODEV;
+ }
+
+ kvx_pm_irq = platform_get_irq(pdev, 0);
+ if (!kvx_pm_irq) {
+ dev_err(dev, "Failed to parse pm irq\n");
+ return -ENODEV;
+ }
+
+ ret = request_percpu_irq(kvx_pm_irq, pm_irq_handler, "pm",
+ this_cpu_ptr(&cpu_hw_events));
+ if (ret) {
+ dev_err(dev, "Failed to request pm irq\n");
+ return -ENODEV;
+ }
+
+ ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
+ "kvx/pm_handler:online",
+ kvx_pm_starting_cpu,
+ kvx_pm_dying_cpu);
+
+ if (ret <= 0) {
+ dev_err(dev, "Failed to setup cpuhp\n");
+ goto free_irq;
+ }
+ statenum = ret;
+
+ ret = perf_pmu_register(&pmu, "cpu", PERF_TYPE_RAW);
+ if (ret) {
+ dev_err(dev, "Failed to register CPU PM as PMU\n");
+ goto free_cpuhp_state;
+ }
+
+ return ret;
+
+free_cpuhp_state:
+ cpuhp_remove_state(statenum);
+free_irq:
+ free_percpu_irq(kvx_pm_irq, this_cpu_ptr(&cpu_hw_events));
+ return ret;
+}
+
+static const struct of_device_id kvx_pmu_of_device_ids[] = {
+ {.compatible = "kalray,kvx-core-pm"},
+ {},
+};
+
+static struct platform_driver kvx_pmu_driver = {
+ .driver = {
+ .name = "pmu",
+ .of_match_table = kvx_pmu_of_device_ids,
+ },
+ .probe = kvx_pmu_device_probe,
+};
+
+static int __init kvx_pmu_driver_init(void)
+{
+ return platform_driver_register(&kvx_pmu_driver);
+}
+
+device_initcall(kvx_pmu_driver_init);
--
2.37.2





2023-01-03 17:23:57

by Yann Sionneau

[permalink] [raw]
Subject: [RFC PATCH 17/25] kvx: Add multi-processor (SMP) support

Coolidge v1 SoC has 5 clusters of 16 kvx cores
(+1 special Resource Manager (RM) core).

Linux can run in SMP config on the 16 cores of
a Cluster.

Cache coherency is done by the L2 cache.

CC: [email protected]
Co-developed-by: Clement Leger <[email protected]>
Signed-off-by: Clement Leger <[email protected]>
Co-developed-by: Julian Vetter <[email protected]>
Signed-off-by: Julian Vetter <[email protected]>
Co-developed-by: Julien Hascoet <[email protected]>
Signed-off-by: Julien Hascoet <[email protected]>
Co-developed-by: Louis Morhet <[email protected]>
Signed-off-by: Louis Morhet <[email protected]>
Co-developed-by: Luc Michel <[email protected]>
Signed-off-by: Luc Michel <[email protected]>
Co-developed-by: Marius Gligor <[email protected]>
Signed-off-by: Marius Gligor <[email protected]>
Co-developed-by: Yann Sionneau <[email protected]>
Signed-off-by: Yann Sionneau <[email protected]>
---
arch/kvx/include/asm/pwr_ctrl.h | 45 ++++
arch/kvx/include/asm/smp.h | 42 +++
arch/kvx/kernel/l2_cache.c | 448 ++++++++++++++++++++++++++++++++
arch/kvx/kernel/smp.c | 110 ++++++++
arch/kvx/kernel/smpboot.c | 127 +++++++++
arch/kvx/platform/pwr_ctrl.c | 93 +++++++
include/linux/cpuhotplug.h | 2 +
7 files changed, 867 insertions(+)
create mode 100644 arch/kvx/include/asm/pwr_ctrl.h
create mode 100644 arch/kvx/include/asm/smp.h
create mode 100644 arch/kvx/kernel/l2_cache.c
create mode 100644 arch/kvx/kernel/smp.c
create mode 100644 arch/kvx/kernel/smpboot.c
create mode 100644 arch/kvx/platform/pwr_ctrl.c

diff --git a/arch/kvx/include/asm/pwr_ctrl.h b/arch/kvx/include/asm/pwr_ctrl.h
new file mode 100644
index 000000000000..25f403ba935a
--- /dev/null
+++ b/arch/kvx/include/asm/pwr_ctrl.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Clement Leger
+ * Marius Gligor
+ */
+
+#ifndef _ASM_KVX_PWR_CTRL_H
+#define _ASM_KVX_PWR_CTRL_H
+
+#ifndef __ASSEMBLY__
+
+int kvx_pwr_ctrl_probe(void);
+
+void kvx_pwr_ctrl_cpu_poweron(unsigned int cpu);
+
+#endif
+
+/* Power controller vector register definitions */
+#define KVX_PWR_CTRL_VEC_OFFSET 0x1000
+#define KVX_PWR_CTRL_VEC_WUP_SET_OFFSET 0x10
+#define KVX_PWR_CTRL_VEC_WUP_CLEAR_OFFSET 0x20
+
+/* Power controller PE reset PC register definitions */
+#define KVX_PWR_CTRL_RESET_PC_OFFSET 0x2000
+
+/* Power controller global register definitions */
+#define KVX_PWR_CTRL_GLOBAL_OFFSET 0x4040
+
+#define KVX_PWR_CTRL_GLOBAL_SET_OFFSET 0x10
+#define KVX_PWR_CTRL_GLOBAL_SET_PE_EN_SHIFT 0x1
+
+#define PWR_CTRL_WUP_SET_OFFSET \
+ (KVX_PWR_CTRL_VEC_OFFSET + \
+ KVX_PWR_CTRL_VEC_WUP_SET_OFFSET)
+
+#define PWR_CTRL_WUP_CLEAR_OFFSET \
+ (KVX_PWR_CTRL_VEC_OFFSET + \
+ KVX_PWR_CTRL_VEC_WUP_CLEAR_OFFSET)
+
+#define PWR_CTRL_GLOBAL_CONFIG_OFFSET \
+ (KVX_PWR_CTRL_GLOBAL_OFFSET + \
+ KVX_PWR_CTRL_GLOBAL_SET_OFFSET)
+
+#endif /* _ASM_KVX_PWR_CTRL_H */
diff --git a/arch/kvx/include/asm/smp.h b/arch/kvx/include/asm/smp.h
new file mode 100644
index 000000000000..e4fd4d001b2c
--- /dev/null
+++ b/arch/kvx/include/asm/smp.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Clement Leger
+ */
+
+#ifndef _ASM_KVX_SMP_H
+#define _ASM_KVX_SMP_H
+
+#include <linux/cpumask.h>
+#include <linux/irqreturn.h>
+
+#include <asm/sfr.h>
+
+#ifdef CONFIG_SMP
+
+/* Hook for the generic smp_call_function_many() routine. */
+void arch_send_call_function_ipi_mask(struct cpumask *mask);
+
+/* Hook for the generic smp_call_function_single() routine. */
+void arch_send_call_function_single_ipi(int cpu);
+
+void __init setup_processor(void);
+
+void smp_init_cpus(void);
+
+irqreturn_t ipi_call_interrupt(int irq, void *dev_id);
+
+#define raw_smp_processor_id() ((int) \
+ ((kvx_sfr_get(PCR) & KVX_SFR_PCR_PID_MASK) \
+ >> KVX_SFR_PCR_PID_SHIFT))
+
+#define flush_cache_vmap(start, end) do { } while (0)
+#define flush_cache_vunmap(start, end) do { } while (0)
+
+#else
+
+void smp_init_cpus(void) {}
+
+#endif /* CONFIG_SMP */
+
+#endif
diff --git a/arch/kvx/kernel/l2_cache.c b/arch/kvx/kernel/l2_cache.c
new file mode 100644
index 000000000000..94a4d9159471
--- /dev/null
+++ b/arch/kvx/kernel/l2_cache.c
@@ -0,0 +1,448 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Clement Leger
+ * Luc Michel
+ * Julien Hascoet
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/jiffies.h>
+#include <linux/of_address.h>
+#include <linux/irqchip/irq-kvx-apic-mailbox.h>
+
+#include <asm/rm_fw.h>
+#include <asm/l2_cache.h>
+#include <asm/sections.h>
+#include <asm/cacheflush.h>
+
+#define L2_START_TIMEOUT_MS 10
+#define L2_CMD_TIMEOUT_MS 200
+
+#define L2_MK_OP(__cmd, __sync) (BIT(L2_CMD_OP_VALID_SHIFT) | \
+ ((u64) __sync << L2_CMD_OP_SYNC_SHIFT) | \
+ ((u64) __cmd << L2_CMD_OP_CMD_SHIFT))
+
+#define L2_ERROR(_err) \
+ ((error & L2_ERROR_ERROR_CODE_MASK) >> L2_ERROR_ERROR_CODE_SHIFT)
+
+struct l2_cache_hw_cmd {
+ u64 op;
+ u64 args[L2_CMD_OP_ARG_COUNT];
+} __packed;
+
+struct l2_cache_cmd {
+ int sync;
+ int cmd_type;
+ unsigned int arg_count;
+ u64 args[L2_CMD_OP_ARG_COUNT];
+};
+
+/**
+ * struct l2_cached_data - Data associated to the l2-cache
+ * @regs: base of L2 registers
+ * @mbox_regs: Mailbox registers for L2 signaling
+ */
+struct l2_cache_data {
+ void __iomem *regs;
+ void __iomem *mbox_regs;
+ u64 fifo_cmd_count;
+};
+
+DEFINE_STATIC_KEY_FALSE(l2_enabled);
+static struct l2_cache_data l2c_ctrl;
+
+static void *l2_cmd_regs_addr(void)
+{
+ return l2c_ctrl.regs + L2_CMD_OFFSET;
+}
+
+static struct l2_cache_hw_cmd *l2_cache_hw_cmd_addr(u64 idx)
+{
+ void *cmd_regs = l2_cmd_regs_addr();
+
+ /* Wrap index */
+ idx &= (l2c_ctrl.fifo_cmd_count - 1);
+ return cmd_regs + L2_CMD_FIFO_OFFSET + idx * L2_CMD_FIFO_ELEM_SIZE;
+}
+
+static u64 l2_cache_get_cmd_idx(unsigned int cmd_count)
+{
+ u64 cmd_idx;
+ void *cmd_regs = l2_cmd_regs_addr();
+ u64 *write_idx_ptr = cmd_regs + L2_CMD_WRITE_IDX_OFFSET;
+ u64 *read_idx_ptr = cmd_regs + L2_CMD_READ_IDX_OFFSET;
+
+ /* Grab a commands tickets */
+ cmd_idx = __builtin_kvx_aladdd(write_idx_ptr, cmd_count);
+
+ /* Wait until there is room in command fifo to enqueue commands */
+ while ((cmd_idx + cmd_count) >=
+ (readq(read_idx_ptr) + l2c_ctrl.fifo_cmd_count))
+ cpu_relax();
+
+ return cmd_idx;
+}
+
+static void l2_wait_completion(u64 cmd_idx)
+{
+ u64 *read_idx_ptr = l2_cmd_regs_addr() + L2_CMD_READ_IDX_OFFSET;
+ unsigned long timeout = jiffies + msecs_to_jiffies(L2_CMD_TIMEOUT_MS);
+
+ /* Wait for completion */
+ while (cmd_idx >= readq(read_idx_ptr)) {
+ cpu_relax();
+ if (time_after(jiffies, timeout))
+ panic("L2 cache completion timeout\n");
+ }
+}
+
+static u64 l2_cache_push_cmds(struct l2_cache_cmd *cmds, int cmd_count)
+{
+ int i, arg;
+ u64 cmd_op;
+ struct l2_cache_hw_cmd *cmd;
+ struct l2_cache_cmd *soft_cmd;
+ u64 cmd_idx = l2_cache_get_cmd_idx(cmd_count);
+
+ for (i = 0; i < cmd_count; i++) {
+ soft_cmd = &cmds[i];
+ cmd = l2_cache_hw_cmd_addr(cmd_idx);
+ cmd_idx++;
+
+ for (arg = 0; arg < soft_cmd->arg_count; arg++)
+ writeq_relaxed(soft_cmd->args[arg], &cmd->args[arg]);
+
+ cmd_op = L2_MK_OP(soft_cmd->cmd_type, soft_cmd->sync);
+ writeq(cmd_op, &cmd->op);
+ }
+
+ return cmd_idx - 1;
+}
+
+static void l2_cache_create_line_cmd(struct l2_cache_cmd *cmd, int cmd_type,
+ int sync, u64 addr)
+{
+ cmd->cmd_type = cmd_type;
+ cmd->sync = sync;
+ cmd->arg_count = 1;
+ cmd->args[0] = addr;
+}
+
+static void l2_cache_create_area_cmd(struct l2_cache_cmd *cmd, int cmd_type,
+ int sync, u64 addr, u64 size)
+{
+ l2_cache_create_line_cmd(cmd, cmd_type, sync, addr);
+ cmd->arg_count = 2;
+ cmd->args[1] = size;
+}
+
+static void l2_cache_push_inval_cmd(phys_addr_t start,
+ unsigned long size)
+{
+ phys_addr_t end = start + size;
+ struct l2_cache_cmd cmds[3];
+ unsigned long irq_flags;
+ int cmd_count = 0;
+ u64 cmd_idx;
+
+ /*
+ * In case of invalidation, we must make sure we do not invalidate
+ * unwanted area and thus discard legit data. In case we are not aligned
+ * send a purge line command (writeback + inval) to unaligned lines
+ * (which can be the end line or the start line)
+ */
+ if (!IS_ALIGNED(end, L2_CACHE_LINE_SIZE)) {
+ end &= ~L2_CACHE_LINE_MASK;
+ l2_cache_create_line_cmd(&cmds[cmd_count],
+ L2_CMD_OP_CMD_PURGE_LINE, 1, end);
+ cmd_count++;
+ }
+
+ if (!IS_ALIGNED(start, L2_CACHE_LINE_SIZE)) {
+ start &= ~L2_CACHE_LINE_MASK;
+ /* If there is at least another line to clear */
+ if (end != start) {
+ l2_cache_create_line_cmd(&cmds[cmd_count],
+ L2_CMD_OP_CMD_PURGE_LINE, 1,
+ start);
+ cmd_count++;
+ start += L2_CACHE_LINE_SIZE;
+ }
+ }
+
+ BUG_ON(end < start);
+
+ size = (end - start);
+ if (size > 0) {
+ l2_cache_create_area_cmd(&cmds[cmd_count],
+ L2_CMD_OP_CMD_INVAL_AREA, 1, start,
+ size);
+ cmd_count++;
+ }
+
+ BUG_ON(cmd_count == 0);
+
+ local_irq_save(irq_flags);
+
+ cmd_idx = l2_cache_push_cmds(cmds, cmd_count);
+
+ /* Finally, ping the L2 cache controller */
+ writeq(1, l2c_ctrl.mbox_regs);
+
+ local_irq_restore(irq_flags);
+
+ l2_wait_completion(cmd_idx);
+}
+
+static void l2_cache_push_generic_cmd(u64 cmd_type, phys_addr_t start,
+ unsigned long size)
+{
+ unsigned long irq_flags;
+ struct l2_cache_cmd cmd;
+ u64 cmd_idx;
+
+ /* Align the start address and size on cache line */
+ size += start & (L2_CACHE_LINE_SIZE - 1);
+ size = ALIGN(size, L2_CACHE_LINE_SIZE);
+ start = ALIGN_DOWN(start, L2_CACHE_LINE_SIZE);
+
+ local_irq_save(irq_flags);
+
+ l2_cache_create_area_cmd(&cmd, cmd_type, 1, start, size);
+ cmd_idx = l2_cache_push_cmds(&cmd, 1);
+
+ /* Finally, ping the L2 cache controller */
+ writeq(1, l2c_ctrl.mbox_regs);
+
+ local_irq_restore(irq_flags);
+
+ l2_wait_completion(cmd_idx);
+}
+
+void l2_cache_push_area_cmd(u64 cmd_type, phys_addr_t start,
+ unsigned long size)
+{
+ if (WARN_ON(size == 0))
+ return;
+
+ if (cmd_type == L2_CMD_OP_CMD_INVAL_AREA)
+ l2_cache_push_inval_cmd(start, size);
+ else
+ l2_cache_push_generic_cmd(cmd_type, start, size);
+}
+
+static void __init l2_disp_error(u64 error)
+{
+ const char *err_type;
+
+ if (error & L2_ERROR_API_ERR_MASK)
+ err_type = "API";
+ else if (error & L2_ERROR_SETUP_ERR_MASK)
+ err_type = "SETUP";
+ else
+ err_type = "UNKNOWN";
+
+ pr_err("%s error: 0x%llx\n", err_type, L2_ERROR(error));
+}
+
+static int __init l2_cache_configure_mailboxes(void)
+{
+ phys_addr_t l2_mbox_addr = 0;
+ void *cmd_regs = l2_cmd_regs_addr();
+
+ /* We do not use mailbox to wait for completion, set it to 0 */
+ writeq(0, cmd_regs + L2_CMD_DOORBELL_READ_ADDR_OFFSET);
+
+ /* Read mailbox address from L2 registers */
+ l2_mbox_addr = readq(cmd_regs + L2_CMD_DOORBELL_WRITE_ADDR_OFFSET);
+
+ /* Then map the mailbox */
+ l2c_ctrl.mbox_regs = ioremap(l2_mbox_addr, PAGE_SIZE);
+ if (!l2c_ctrl.mbox_regs) {
+ pr_err("Failed to map mailbox\n");
+ return 1;
+ }
+
+ /* Lock this entry into the LTLB */
+ kvx_mmu_ltlb_add_entry((unsigned long) l2c_ctrl.mbox_regs & PAGE_MASK,
+ l2_mbox_addr & PAGE_MASK,
+ PAGE_KERNEL_DEVICE, TLB_PS_4K);
+
+ return 0;
+}
+
+static int __init l2_cache_read_queue_size(void)
+{
+ u64 inst;
+
+ /* Read command queue size */
+ inst = readq(l2c_ctrl.regs + L2_INSTANCE_OFFSET);
+ l2c_ctrl.fifo_cmd_count = (inst & L2_INSTANCE_CMD_QUEUE_SIZE_MASK)
+ >> L2_INSTANCE_CMD_QUEUE_SIZE_SHIFT;
+
+ /* Check if value is a power of two */
+ if (hweight64(l2c_ctrl.fifo_cmd_count) != 1) {
+ pr_err("Command queue size is not a power of two\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+static int __init l2_cache_init_hw(void)
+{
+ unsigned long timeout = jiffies + msecs_to_jiffies(L2_START_TIMEOUT_MS);
+ unsigned long flags;
+ u64 status, error;
+ int ret;
+
+ /* Wait for L2 to be up */
+ do {
+ status = readq(l2c_ctrl.regs + L2_STATUS_OFFSET);
+ if (status & (L2_STATUS_READY_MASK | L2_STATUS_ERROR_MASK))
+ break;
+ } while (time_before(jiffies, timeout));
+
+ if (!status) {
+ pr_err("Timeout while waiting for firmware status\n");
+ return -ENODEV;
+ }
+
+ if (status & L2_STATUS_ERROR_MASK) {
+ error = readq(l2c_ctrl.regs + L2_ERROR_OFFSET);
+ l2_disp_error(error);
+ return -EINVAL;
+ }
+
+ /* Now write ack to L2 firmware */
+ writeq(status | L2_STATUS_ACK_MASK, l2c_ctrl.regs + L2_STATUS_OFFSET);
+
+ ret = l2_cache_read_queue_size();
+ if (ret)
+ return ret;
+
+ ret = l2_cache_configure_mailboxes();
+ if (ret)
+ return ret;
+
+ /* Enable the L2 atomically */
+ local_irq_save(flags);
+
+ /* Fence data accesses */
+ kvx_fence();
+ /* Purge L1 */
+ l1_inval_dcache_all();
+ l1_inval_icache_all();
+ __builtin_kvx_barrier();
+
+ local_irq_restore(flags);
+
+ /* Enable L2$ */
+ kvx_sfr_set_field(PS, L2E, 1);
+
+ return 0;
+}
+
+static phys_addr_t __init l2_get_regs_addr(struct device_node *np)
+{
+ const void *reg;
+ struct resource res;
+ phys_addr_t l2_regs_addr;
+ int ret;
+
+ /*
+ * If regs is specified in device tree, then the L2$ has been loaded by
+ * someone else and not by ourself.
+ */
+ reg = of_get_property(np, "reg", NULL);
+ if (reg) {
+ ret = of_address_to_resource(np, 0, &res);
+ if (ret) {
+ pr_err("Address translation error\n");
+ return 0;
+ }
+ if ((res.end - res.start) > PAGE_SIZE) {
+ pr_err("L2 reg size > PAGE_SIZE\n");
+ return 0;
+ }
+
+ l2_regs_addr = res.start;
+ } else {
+ l2_regs_addr = (phys_addr_t) __rm_firmware_regs_start;
+ }
+
+ if (!IS_ALIGNED(l2_regs_addr, PAGE_SIZE)) {
+ pr_err("Registers not aligned on PAGE_SIZE\n");
+ return 0;
+ }
+
+ return l2_regs_addr;
+}
+
+static int __init l2_cache_init(void)
+{
+ int ret = -ENODEV;
+ struct device_node *np;
+ phys_addr_t l2_regs_addr;
+
+ np = of_find_compatible_node(NULL, NULL, "kalray,kvx-l2-cache");
+ if (!np || !of_device_is_available(np)) {
+ if (!IS_ENABLED(CONFIG_SMP)) {
+ pr_info("controller disabled\n");
+ return 0;
+ }
+
+ if (np && of_get_property(np, "kalray,is-qemu", NULL)) {
+ /*
+ * QEMU is always full cache coherent. The L2 cache controller is
+ * not strictly necessary to ensure coherency in SMP.
+ */
+ pr_info("controller disabled (QEMU detected)\n");
+ return 0;
+ }
+
+ /* Else, SMP is enabled and L2 is mandatory for it */
+ goto err;
+ }
+
+ l2_regs_addr = l2_get_regs_addr(np);
+ if (!l2_regs_addr)
+ goto err;
+
+ /* Map the L2 registers */
+ l2c_ctrl.regs = ioremap(l2_regs_addr, PAGE_SIZE);
+ if (!l2c_ctrl.regs)
+ goto err;
+
+ /* Lock this entry into the LTLB */
+ kvx_mmu_ltlb_add_entry((unsigned long) l2c_ctrl.regs, l2_regs_addr,
+ PAGE_KERNEL_NOCACHE, TLB_PS_4K);
+
+ ret = l2_cache_init_hw();
+ if (ret) {
+ pr_err("Failed to init L2 cache controller");
+ goto err_unmap_l2;
+ }
+
+ static_branch_enable(&l2_enabled);
+
+ pr_info("controller enabled\n");
+
+ return 0;
+
+err_unmap_l2:
+ kvx_mmu_ltlb_remove_entry((unsigned long) l2c_ctrl.regs);
+ iounmap(l2c_ctrl.regs);
+err:
+ if (IS_ENABLED(CONFIG_SMP))
+ panic("L2$ controller is mandatory for SMP");
+
+ return ret;
+}
+
+
+early_initcall(l2_cache_init);
diff --git a/arch/kvx/kernel/smp.c b/arch/kvx/kernel/smp.c
new file mode 100644
index 000000000000..ed4c35a8c4bc
--- /dev/null
+++ b/arch/kvx/kernel/smp.c
@@ -0,0 +1,110 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Clement Leger
+ */
+
+#include <linux/smp.h>
+#include <linux/cpu.h>
+#include <linux/of_irq.h>
+#include <linux/cpumask.h>
+#include <linux/irq_work.h>
+#include <linux/mm_types.h>
+#include <linux/interrupt.h>
+
+#include <asm/ipi.h>
+#include <asm/tlbflush.h>
+
+enum ipi_message_type {
+ IPI_RESCHEDULE,
+ IPI_CALL_FUNC,
+ IPI_IRQ_WORK,
+ IPI_MAX
+};
+
+/* A collection of single bit ipi messages. */
+static struct {
+ unsigned long bits ____cacheline_aligned;
+} ipi_data[NR_CPUS] __cacheline_aligned;
+
+static void send_ipi_message(const struct cpumask *mask,
+ enum ipi_message_type operation)
+{
+ unsigned long flags;
+ int cpu;
+
+ /* Set operation that must be done by receiver */
+ for_each_cpu(cpu, mask)
+ set_bit(operation, &ipi_data[cpu].bits);
+
+ /* Commit the write before sending IPI */
+ smp_wmb();
+
+ local_irq_save(flags);
+
+ kvx_ipi_send(mask);
+
+ local_irq_restore(flags);
+}
+
+void arch_send_call_function_ipi_mask(struct cpumask *mask)
+{
+ send_ipi_message(mask, IPI_CALL_FUNC);
+}
+
+void arch_send_call_function_single_ipi(int cpu)
+{
+ send_ipi_message(cpumask_of(cpu), IPI_CALL_FUNC);
+}
+
+#ifdef CONFIG_IRQ_WORK
+void arch_irq_work_raise(void)
+{
+ send_ipi_message(cpumask_of(smp_processor_id()), IPI_IRQ_WORK);
+}
+#endif
+
+static void ipi_stop(void *unused)
+{
+ local_cpu_stop();
+}
+
+void smp_send_stop(void)
+{
+ struct cpumask targets;
+
+ cpumask_copy(&targets, cpu_online_mask);
+ cpumask_clear_cpu(smp_processor_id(), &targets);
+
+ smp_call_function_many(&targets, ipi_stop, NULL, 0);
+}
+
+void smp_send_reschedule(int cpu)
+{
+ send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE);
+}
+
+irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
+{
+ unsigned long *pending_ipis = &ipi_data[smp_processor_id()].bits;
+
+ while (true) {
+ unsigned long ops = xchg(pending_ipis, 0);
+
+ if (ops == 0)
+ return IRQ_HANDLED;
+
+ if (ops & (1 << IPI_RESCHEDULE))
+ scheduler_ipi();
+
+ if (ops & (1 << IPI_CALL_FUNC))
+ generic_smp_call_function_interrupt();
+
+ if (ops & (1 << IPI_IRQ_WORK))
+ irq_work_run();
+
+ BUG_ON((ops >> IPI_MAX) != 0);
+ }
+
+ return IRQ_HANDLED;
+}
diff --git a/arch/kvx/kernel/smpboot.c b/arch/kvx/kernel/smpboot.c
new file mode 100644
index 000000000000..987a6f014163
--- /dev/null
+++ b/arch/kvx/kernel/smpboot.c
@@ -0,0 +1,127 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Clement Leger
+ * Julian Vetter
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/smp.h>
+#include <linux/cpu.h>
+#include <linux/sched.h>
+#include <linux/cpumask.h>
+#include <linux/sched/mm.h>
+#include <linux/mm_types.h>
+#include <linux/of_platform.h>
+#include <linux/sched/task_stack.h>
+
+#include <asm/pwr_ctrl.h>
+#include <asm/tlbflush.h>
+#include <asm/ipi.h>
+
+void *__cpu_up_stack_pointer[NR_CPUS];
+void *__cpu_up_task_pointer[NR_CPUS];
+
+void __init smp_prepare_boot_cpu(void)
+{
+}
+
+int __cpu_up(unsigned int cpu, struct task_struct *tidle)
+{
+ __cpu_up_stack_pointer[cpu] = task_stack_page(tidle) + THREAD_SIZE;
+ __cpu_up_task_pointer[cpu] = tidle;
+ /* We need to be sure writes are committed */
+ smp_mb();
+
+ kvx_pwr_ctrl_cpu_poweron(cpu);
+ while (!cpu_online(cpu))
+ cpu_relax();
+
+ return 0;
+}
+
+void __init smp_cpus_done(unsigned int max_cpus)
+{
+}
+
+void __init smp_init_cpus(void)
+{
+ struct cpumask cpumask;
+ struct device_node *cpu;
+ const __be32 *reg;
+ u32 cpu_num;
+ unsigned int nr_cpus = 0;
+
+ cpumask_clear(&cpumask);
+
+ for_each_of_cpu_node(cpu) {
+ if (!of_device_is_available(cpu))
+ continue;
+
+ reg = of_get_property(cpu, "reg", NULL);
+ if (!reg)
+ continue;
+
+ cpu_num = be32_to_cpup(reg);
+ if (cpu_num >= nr_cpu_ids)
+ continue;
+
+ nr_cpus++;
+ cpumask_set_cpu(cpu_num, &cpumask);
+ }
+
+ pr_info("%d possible cpus\n", nr_cpus);
+ init_cpu_possible(&cpumask);
+}
+
+void __init smp_prepare_cpus(unsigned int max_cpus)
+{
+ if (num_present_cpus() <= 1)
+ init_cpu_present(cpu_possible_mask);
+}
+
+int __init setup_smp(void)
+{
+ int ret;
+
+ ret = kvx_pwr_ctrl_probe();
+ if (ret)
+ panic("Failed to probe power controller !");
+
+ ret = kvx_ipi_ctrl_probe(ipi_call_interrupt);
+ if (ret)
+ panic("Failed to probe IPI controller !");
+
+ return 0;
+}
+
+early_initcall(setup_smp);
+
+/*
+ * C entry point for a secondary processor.
+ */
+void __init start_kernel_secondary(void)
+{
+ struct mm_struct *mm = &init_mm;
+ unsigned int cpu = smp_processor_id();
+
+ setup_processor();
+ kvx_mmu_early_setup();
+
+ /* All kernel threads share the same mm context. */
+ mmgrab(mm);
+ current->active_mm = mm;
+ cpumask_set_cpu(cpu, mm_cpumask(mm));
+
+ notify_cpu_starting(cpu);
+ set_cpu_online(cpu, true);
+ trace_hardirqs_off();
+
+ local_flush_tlb_all();
+
+ local_irq_enable();
+ cpu_startup_entry(CPUHP_AP_ONLINE_IDLE);
+}
diff --git a/arch/kvx/platform/pwr_ctrl.c b/arch/kvx/platform/pwr_ctrl.c
new file mode 100644
index 000000000000..64c86cd18695
--- /dev/null
+++ b/arch/kvx/platform/pwr_ctrl.c
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Clement Leger
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+
+#include <asm/pwr_ctrl.h>
+#include <asm/symbols.h>
+
+struct kvx_pwr_ctrl {
+ void __iomem *regs;
+};
+
+static struct kvx_pwr_ctrl kvx_pwr_controller;
+
+/**
+ * kvx_pwr_ctrl_cpu_poweron() - Wakeup a cpu
+ * @cpu: cpu to wakeup
+ */
+void kvx_pwr_ctrl_cpu_poweron(unsigned int cpu)
+{
+ /* Set PE boot address */
+ writeq((unsigned long long)kvx_start,
+ kvx_pwr_controller.regs + KVX_PWR_CTRL_RESET_PC_OFFSET);
+ /* Wake up processor ! */
+ writeq(1ULL << cpu,
+ kvx_pwr_controller.regs + PWR_CTRL_WUP_SET_OFFSET);
+ /* Then clear wakeup to allow processor to sleep */
+ writeq(1ULL << cpu,
+ kvx_pwr_controller.regs + PWR_CTRL_WUP_CLEAR_OFFSET);
+}
+
+static struct device_node * __init get_pwr_ctrl_node(void)
+{
+ const phandle *ph;
+ struct device_node *cpu;
+ struct device_node *node;
+
+ cpu = of_get_cpu_node(raw_smp_processor_id(), NULL);
+ if (!cpu) {
+ pr_err("Failed to get CPU node\n");
+ return NULL;
+ }
+
+ ph = of_get_property(cpu, "power-controller", NULL);
+ if (!ph) {
+ pr_err("Failed to get power-controller phandle\n");
+ return NULL;
+ }
+
+ node = of_find_node_by_phandle(be32_to_cpup(ph));
+ if (!node) {
+ pr_err("Failed to get power-controller node\n");
+ return NULL;
+ }
+
+ return node;
+}
+
+int __init kvx_pwr_ctrl_probe(void)
+{
+ struct device_node *ctrl;
+
+ ctrl = get_pwr_ctrl_node();
+ if (!ctrl) {
+ pr_err("Failed to get power controller node\n");
+ return -EINVAL;
+ }
+
+ if (!of_device_is_compatible(ctrl, "kalray,kvx-pwr-ctrl")) {
+ pr_err("Failed to get power controller node\n");
+ return -EINVAL;
+ }
+
+ kvx_pwr_controller.regs = of_iomap(ctrl, 0);
+ if (!kvx_pwr_controller.regs) {
+ pr_err("Failed ioremap\n");
+ return -EINVAL;
+ }
+
+ pr_info("kvx power controller probed\n");
+
+ return 0;
+}
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
index f61447913db9..f5a484547b15 100644
--- a/include/linux/cpuhotplug.h
+++ b/include/linux/cpuhotplug.h
@@ -152,6 +152,7 @@ enum cpuhp_state {
CPUHP_AP_IRQ_RISCV_STARTING,
CPUHP_AP_IRQ_LOONGARCH_STARTING,
CPUHP_AP_IRQ_SIFIVE_PLIC_STARTING,
+ CPUHP_AP_IRQ_KVX_STARTING,
CPUHP_AP_ARM_MVEBU_COHERENCY,
CPUHP_AP_MICROCODE_LOADER,
CPUHP_AP_PERF_X86_AMD_UNCORE_STARTING,
@@ -189,6 +190,7 @@ enum cpuhp_state {
CPUHP_AP_KVM_ARM_VGIC_INIT_STARTING,
CPUHP_AP_KVM_ARM_VGIC_STARTING,
CPUHP_AP_KVM_ARM_TIMER_STARTING,
+ CPUHP_AP_KVX_TIMER_STARTING,
/* Must be the last timer callback */
CPUHP_AP_DUMMY_TIMER_STARTING,
CPUHP_AP_ARM_XEN_STARTING,
--
2.37.2





2023-01-03 17:24:41

by Yann Sionneau

[permalink] [raw]
Subject: [RFC PATCH 19/25] kvx: power: scall poweroff driver

Add a driver to poweroff the Coolidge SoC
when running under Qemu, ISS or when
the debugger (jtag-runner) runs on PL0
to catch the scall.

CC: Sebastian Reichel <[email protected]>
CC: [email protected]
CC: [email protected]
Co-developed-by: Clement Leger <[email protected]>
Signed-off-by: Clement Leger <[email protected]>
Co-developed-by: Julian Vetter <[email protected]>
Signed-off-by: Julian Vetter <[email protected]>
Signed-off-by: Yann Sionneau <[email protected]>
---
drivers/power/reset/kvx-scall-poweroff.c | 53 ++++++++++++++++++++++++
1 file changed, 53 insertions(+)
create mode 100644 drivers/power/reset/kvx-scall-poweroff.c

diff --git a/drivers/power/reset/kvx-scall-poweroff.c b/drivers/power/reset/kvx-scall-poweroff.c
new file mode 100644
index 000000000000..586d93fbcaed
--- /dev/null
+++ b/drivers/power/reset/kvx-scall-poweroff.c
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2017 - 2022 Kalray Inc.
+ * Author(s): Clement Leger
+ */
+
+#include <linux/pm.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+#define SCALL_NUM_EXIT "0xfff"
+
+static void kvx_scall_poweroff(void)
+{
+ register int status asm("r0") = 0;
+
+ asm volatile ("scall " SCALL_NUM_EXIT "\n\t;;"
+ : /* out */
+ : "r"(status));
+
+ unreachable();
+}
+
+static int kvx_scall_poweroff_probe(struct platform_device *pdev)
+{
+ pm_power_off = kvx_scall_poweroff;
+
+ return 0;
+}
+
+static int kvx_scall_poweroff_remove(struct platform_device *pdev)
+{
+ if (pm_power_off == kvx_scall_poweroff)
+ pm_power_off = NULL;
+
+ return 0;
+}
+
+static const struct of_device_id kvx_scall_poweroff_of_match[] = {
+ { .compatible = "kalray,kvx-scall-poweroff" },
+ {}
+};
+
+static struct platform_driver kvx_scall_poweroff_driver = {
+ .probe = kvx_scall_poweroff_probe,
+ .remove = kvx_scall_poweroff_remove,
+ .driver = {
+ .name = "kvx-scall-poweroff",
+ .of_match_table = kvx_scall_poweroff_of_match,
+ },
+};
+module_platform_driver(kvx_scall_poweroff_driver);
--
2.37.2





2023-01-03 17:44:47

by Yann Sionneau

[permalink] [raw]
Subject: [RFC PATCH 12/25] kvx: Add system call support

Add system call support and related uaccess.h for kvx.

CC: Christian Brauner <[email protected]>
CC: Paul Walmsley <[email protected]>
CC: Palmer Dabbelt <[email protected]>
CC: Albert Ou <[email protected]>
CC: [email protected]
CC: [email protected]
Co-developed-by: Clement Leger <[email protected]>
Signed-off-by: Clement Leger <[email protected]>
Co-developed-by: Guillaume Thouvenin <[email protected]>
Signed-off-by: Guillaume Thouvenin <[email protected]>
Co-developed-by: Julian Vetter <[email protected]>
Signed-off-by: Julian Vetter <[email protected]>
Co-developed-by: Julien Villette <[email protected]>
Signed-off-by: Julien Villette <[email protected]>
Co-developed-by: Marius Gligor <[email protected]>
Signed-off-by: Marius Gligor <[email protected]>
Co-developed-by: Yann Sionneau <[email protected]>
Signed-off-by: Yann Sionneau <[email protected]>
---
arch/kvx/include/asm/syscall.h | 73 ++
arch/kvx/include/asm/syscalls.h | 21 +
arch/kvx/include/asm/uaccess.h | 324 +++++
arch/kvx/include/asm/unistd.h | 11 +
arch/kvx/include/uapi/asm/cachectl.h | 25 +
arch/kvx/include/uapi/asm/unistd.h | 16 +
arch/kvx/kernel/entry.S | 1759 ++++++++++++++++++++++++++
arch/kvx/kernel/sys_kvx.c | 58 +
arch/kvx/kernel/syscall_table.c | 19 +
9 files changed, 2306 insertions(+)
create mode 100644 arch/kvx/include/asm/syscall.h
create mode 100644 arch/kvx/include/asm/syscalls.h
create mode 100644 arch/kvx/include/asm/uaccess.h
create mode 100644 arch/kvx/include/asm/unistd.h
create mode 100644 arch/kvx/include/uapi/asm/cachectl.h
create mode 100644 arch/kvx/include/uapi/asm/unistd.h
create mode 100644 arch/kvx/kernel/entry.S
create mode 100644 arch/kvx/kernel/sys_kvx.c
create mode 100644 arch/kvx/kernel/syscall_table.c

diff --git a/arch/kvx/include/asm/syscall.h b/arch/kvx/include/asm/syscall.h
new file mode 100644
index 000000000000..a3f6cef73e4a
--- /dev/null
+++ b/arch/kvx/include/asm/syscall.h
@@ -0,0 +1,73 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Clement Leger
+ */
+
+#ifndef _ASM_KVX_SYSCALL_H
+#define _ASM_KVX_SYSCALL_H
+
+#include <linux/err.h>
+#include <linux/audit.h>
+
+#include <asm/ptrace.h>
+
+/* The array of function pointers for syscalls. */
+extern void *sys_call_table[];
+
+void scall_machine_exit(unsigned char value);
+
+/**
+ * syscall_get_nr - find which system call a task is executing
+ * @task: task of interest, must be blocked
+ * @regs: task_pt_regs() of @task
+ *
+ * If @task is executing a system call or is at system call
+ * tracing about to attempt one, returns the system call number.
+ * If @task is not executing a system call, i.e. it's blocked
+ * inside the kernel for a fault or signal, returns -1.
+ *
+ * Note this returns int even on 64-bit machines. Only 32 bits of
+ * system call number can be meaningful. If the actual arch value
+ * is 64 bits, this truncates to 32 bits so 0xffffffff means -1.
+ *
+ * It's only valid to call this when @task is known to be blocked.
+ */
+static inline int syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
+{
+ if (!in_syscall(regs))
+ return -1;
+
+ return es_sysno(regs);
+}
+
+static inline long syscall_get_error(struct task_struct *task,
+ struct pt_regs *regs)
+{
+ /* 0 if syscall succeeded, otherwise -Errorcode */
+ return IS_ERR_VALUE(regs->r0) ? regs->r0 : 0;
+}
+
+static inline long syscall_get_return_value(struct task_struct *task,
+ struct pt_regs *regs)
+{
+ return regs->r0;
+}
+
+static inline int syscall_get_arch(struct task_struct *task)
+{
+ return AUDIT_ARCH_KVX;
+}
+
+static inline void syscall_get_arguments(struct task_struct *task,
+ struct pt_regs *regs,
+ unsigned long *args)
+{
+ args[0] = regs->orig_r0;
+ args++;
+ memcpy(args, &regs->r1, 5 * sizeof(args[0]));
+}
+
+int __init setup_syscall_sigreturn_page(void *sigpage_addr);
+
+#endif
diff --git a/arch/kvx/include/asm/syscalls.h b/arch/kvx/include/asm/syscalls.h
new file mode 100644
index 000000000000..beec95ebb97a
--- /dev/null
+++ b/arch/kvx/include/asm/syscalls.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Clement Leger
+ */
+
+#ifndef _ASM_KVX_SYSCALLS_H
+#define _ASM_KVX_SYSCALLS_H
+
+#include <asm-generic/syscalls.h>
+
+/* We redefine clone in assembly for special slowpath */
+asmlinkage long __sys_clone(unsigned long clone_flags, unsigned long newsp,
+ int __user *parent_tid, int __user *child_tid, int tls);
+
+#define sys_clone __sys_clone
+
+long sys_cachectl(unsigned long addr, unsigned long len, unsigned long cache,
+ unsigned long flags);
+
+#endif
diff --git a/arch/kvx/include/asm/uaccess.h b/arch/kvx/include/asm/uaccess.h
new file mode 100644
index 000000000000..c72677800763
--- /dev/null
+++ b/arch/kvx/include/asm/uaccess.h
@@ -0,0 +1,324 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * derived from arch/riscv/include/asm/uaccess.h
+ *
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Clement Leger
+ * Guillaume Thouvenin
+ */
+
+#ifndef _ASM_KVX_UACCESS_H
+#define _ASM_KVX_UACCESS_H
+
+#include <linux/sched.h>
+#include <linux/types.h>
+
+/**
+ * access_ok: - Checks if a user space pointer is valid
+ * @addr: User space pointer to start of block to check
+ * @size: Size of block to check
+ *
+ * Context: User context only. This function may sleep.
+ *
+ * Checks if a pointer to a block of memory in user space is valid.
+ *
+ * Returns true (nonzero) if the memory block may be valid, false (zero)
+ * if it is definitely invalid.
+ *
+ * Note that, depending on architecture, this function probably just
+ * checks that the pointer is in the user space range - after calling
+ * this function, memory access functions may still return -EFAULT.
+ */
+#define access_ok(addr, size) ({ \
+ __chk_user_ptr(addr); \
+ likely(__access_ok((unsigned long __force)(addr), (size))); \
+})
+
+/*
+ * Ensure that the range [addr, addr+size) is within the process's
+ * address space
+ */
+static inline int __access_ok(unsigned long addr, unsigned long size)
+{
+ return size <= TASK_SIZE && addr <= TASK_SIZE - size;
+}
+
+/*
+ * The exception table consists of pairs of addresses: the first is the
+ * address of an instruction that is allowed to fault, and the second is
+ * the address at which the program should continue. No registers are
+ * modified, so it is entirely up to the continuation code to figure out
+ * what to do.
+ *
+ * All the routines below use bits of fixup code that are out of line
+ * with the main instruction path. This means when everything is well,
+ * we don't even have to jump over them. Further, they do not intrude
+ * on our cache or TLB entries.
+ */
+
+struct exception_table_entry {
+ unsigned long insn, fixup;
+};
+
+extern int fixup_exception(struct pt_regs *regs);
+
+/**
+ * Assembly defined function (usercopy.S)
+ */
+extern unsigned long
+raw_copy_from_user(void *to, const void __user *from, unsigned long n);
+
+extern unsigned long
+raw_copy_to_user(void __user *to, const void *from, unsigned long n);
+
+extern unsigned long
+asm_clear_user(void __user *to, unsigned long n);
+
+#define __clear_user asm_clear_user
+
+static inline __must_check unsigned long
+clear_user(void __user *to, unsigned long n)
+{
+ might_fault();
+ if (!access_ok(to, n))
+ return n;
+
+ return asm_clear_user(to, n);
+}
+
+extern __must_check long strnlen_user(const char __user *str, long n);
+extern long strncpy_from_user(char *dest, const char __user *src, long count);
+
+#define __enable_user_access()
+#define __disable_user_access()
+
+/**
+ * get_user: - Get a simple variable from user space.
+ * @x: Variable to store result.
+ * @ptr: Source address, in user space.
+ *
+ * Context: User context only. This function may sleep.
+ *
+ * This macro copies a single simple variable from user space to kernel
+ * space. It supports simple types like char and int, but not larger
+ * data types like structures or arrays.
+ *
+ * @ptr must have pointer-to-simple-variable type, and the result of
+ * dereferencing @ptr must be assignable to @x without a cast.
+ *
+ * Returns zero on success, or -EFAULT on error.
+ * On error, the variable @x is set to zero.
+ */
+#define get_user(x, ptr) \
+({ \
+ long __e = -EFAULT; \
+ const __typeof__(*(ptr)) __user *__p = (ptr); \
+ might_fault(); \
+ if (likely(access_ok(__p, sizeof(*__p)))) { \
+ __e = __get_user(x, __p); \
+ } else { \
+ x = 0; \
+ } \
+ __e; \
+})
+
+/**
+ * __get_user: - Get a simple variable from user space, with less checking.
+ * @x: Variable to store result.
+ * @ptr: Source address, in user space.
+ *
+ * Context: User context only. This function may sleep.
+ *
+ * This macro copies a single simple variable from user space to kernel
+ * space. It supports simple types like char and int, but not larger
+ * data types like structures or arrays.
+ *
+ * @ptr must have pointer-to-simple-variable type, and the result of
+ * dereferencing @ptr must be assignable to @x without a cast.
+ *
+ * Caller must check the pointer with access_ok() before calling this
+ * function.
+ *
+ * Returns zero on success, or -EFAULT on error.
+ * On error, the variable @x is set to zero.
+ */
+#define __get_user(x, ptr) \
+({ \
+ unsigned long __err = 0; \
+ __chk_user_ptr(ptr); \
+ \
+ __enable_user_access(); \
+ __get_user_nocheck(x, ptr, __err); \
+ __disable_user_access(); \
+ \
+ __err; \
+})
+
+#define __get_user_nocheck(x, ptr, err) \
+do { \
+ unsigned long __gu_addr = (unsigned long)(ptr); \
+ unsigned long __gu_val; \
+ switch (sizeof(*(ptr))) { \
+ case 1: \
+ __get_user_asm("lbz", __gu_val, __gu_addr, err); \
+ break; \
+ case 2: \
+ __get_user_asm("lhz", __gu_val, __gu_addr, err); \
+ break; \
+ case 4: \
+ __get_user_asm("lwz", __gu_val, __gu_addr, err); \
+ break; \
+ case 8: \
+ __get_user_asm("ld", __gu_val, __gu_addr, err); \
+ break; \
+ default: \
+ BUILD_BUG(); \
+ } \
+ (x) = (__typeof__(*(ptr)))__gu_val; \
+} while (0)
+
+#define __get_user_asm(op, x, addr, err) \
+({ \
+ __asm__ __volatile__( \
+ "1: "op" %1 = 0[%2]\n" \
+ " ;;\n" \
+ "2:\n" \
+ ".section .fixup,\"ax\"\n" \
+ "3: make %0 = 2b\n" \
+ " make %1 = 0\n" \
+ " ;;\n" \
+ " make %0 = %3\n" \
+ " igoto %0\n" \
+ " ;;\n" \
+ ".previous\n" \
+ ".section __ex_table,\"a\"\n" \
+ " .align 8\n" \
+ " .dword 1b,3b\n" \
+ ".previous" \
+ : "=r"(err), "=r"(x) \
+ : "r"(addr), "i"(-EFAULT), "0"(err)); \
+})
+
+/**
+ * put_user: - Write a simple value into user space.
+ * @x: Value to copy to user space.
+ * @ptr: Destination address, in user space.
+ *
+ * Context: User context only. This function may sleep.
+ *
+ * This macro copies a single simple value from kernel space to user
+ * space. It supports simple types like char and int, but not larger
+ * data types like structures or arrays.
+ *
+ * @ptr must have pointer-to-simple-variable type, and @x must be assignable
+ * to the result of dereferencing @ptr.
+ *
+ * Returns zero on success, or -EFAULT on error.
+ */
+#define put_user(x, ptr) \
+({ \
+ long __e = -EFAULT; \
+ __typeof__(*(ptr)) __user *__p = (ptr); \
+ might_fault(); \
+ if (likely(access_ok(__p, sizeof(*__p)))) { \
+ __e = __put_user(x, __p); \
+ } \
+ __e; \
+})
+
+/**
+ * __put_user: - Write a simple value into user space, with less checking.
+ * @x: Value to copy to user space.
+ * @ptr: Destination address, in user space.
+ *
+ * Context: User context only. This function may sleep.
+ *
+ * This macro copies a single simple value from kernel space to user
+ * space. It supports simple types like char and int, but not larger
+ * data types like structures or arrays.
+ *
+ * @ptr must have pointer-to-simple-variable type, and @x must be assignable
+ * to the result of dereferencing @ptr.
+ *
+ * Caller must check the pointer with access_ok() before calling this
+ * function.
+ *
+ * Returns zero on success, or -EFAULT on error.
+ */
+#define __put_user(x, ptr) \
+({ \
+ unsigned long __err = 0; \
+ __chk_user_ptr(ptr); \
+ \
+ __enable_user_access(); \
+ __put_user_nocheck(x, ptr, __err); \
+ __disable_user_access(); \
+ \
+ __err; \
+})
+
+#define __put_user_nocheck(x, ptr, err) \
+do { \
+ unsigned long __pu_addr = (unsigned long)(ptr); \
+ __typeof__(*(ptr)) __pu_val = (x); \
+ switch (sizeof(*(ptr))) { \
+ case 1: \
+ __put_user_asm("sb", __pu_val, __pu_addr, err); \
+ break; \
+ case 2: \
+ __put_user_asm("sh", __pu_val, __pu_addr, err); \
+ break; \
+ case 4: \
+ __put_user_asm("sw", __pu_val, __pu_addr, err); \
+ break; \
+ case 8: \
+ __put_user_asm("sd", __pu_val, __pu_addr, err); \
+ break; \
+ default: \
+ BUILD_BUG(); \
+ } \
+} while (0)
+
+#define __put_user_asm(op, x, addr, err) \
+({ \
+ __asm__ __volatile__( \
+ "1: "op" 0[%2], %1\n" \
+ " ;;\n" \
+ "2:\n" \
+ ".section .fixup,\"ax\"\n" \
+ "3: make %0 = 2b\n" \
+ " ;;\n" \
+ " make %0 = %3\n" \
+ " igoto %0\n" \
+ " ;;\n" \
+ ".previous\n" \
+ ".section __ex_table,\"a\"\n" \
+ " .align 8\n" \
+ " .dword 1b,3b\n" \
+ ".previous" \
+ : "=r"(err) \
+ : "r"(x), "r"(addr), "i"(-EFAULT), "0"(err)); \
+})
+
+#define HAVE_GET_KERNEL_NOFAULT
+
+#define __get_kernel_nofault(dst, src, type, err_label) \
+do { \
+ long __kr_err; \
+ \
+ __get_user_nocheck(*((type *)(dst)), (type *)(src), __kr_err); \
+ if (unlikely(__kr_err)) \
+ goto err_label; \
+} while (0)
+
+#define __put_kernel_nofault(dst, src, type, err_label) \
+do { \
+ long __kr_err; \
+ \
+ __put_user_nocheck(*((type *)(src)), (type *)(dst), __kr_err); \
+ if (unlikely(__kr_err)) \
+ goto err_label; \
+} while (0)
+
+
+#endif /* _ASM_KVX_UACCESS_H */
diff --git a/arch/kvx/include/asm/unistd.h b/arch/kvx/include/asm/unistd.h
new file mode 100644
index 000000000000..6cd093dbf2d8
--- /dev/null
+++ b/arch/kvx/include/asm/unistd.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Clement Leger
+ */
+
+#define __ARCH_WANT_SYS_CLONE
+
+#include <uapi/asm/unistd.h>
+
+#define NR_syscalls (__NR_syscalls)
diff --git a/arch/kvx/include/uapi/asm/cachectl.h b/arch/kvx/include/uapi/asm/cachectl.h
new file mode 100644
index 000000000000..be0a1aa23cf6
--- /dev/null
+++ b/arch/kvx/include/uapi/asm/cachectl.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
+/*
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Clement Leger
+ */
+
+#ifndef _UAPI_ASM_KVX_CACHECTL_H
+#define _UAPI_ASM_KVX_CACHECTL_H
+
+/*
+ * Cache type for cachectl system call
+ */
+#define CACHECTL_CACHE_DCACHE (1 << 0)
+
+/*
+ * Flags for cachectl system call
+ */
+#define CACHECTL_FLAG_OP_INVAL (1 << 0)
+#define CACHECTL_FLAG_OP_WB (1 << 1)
+#define CACHECTL_FLAG_OP_MASK (CACHECTL_FLAG_OP_INVAL | \
+ CACHECTL_FLAG_OP_WB)
+
+#define CACHECTL_FLAG_ADDR_PHYS (1 << 2)
+
+#endif /* _UAPI_ASM_KVX_CACHECTL_H */
diff --git a/arch/kvx/include/uapi/asm/unistd.h b/arch/kvx/include/uapi/asm/unistd.h
new file mode 100644
index 000000000000..5f86d81dbb76
--- /dev/null
+++ b/arch/kvx/include/uapi/asm/unistd.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
+/*
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Clement Leger
+ */
+
+#define __ARCH_WANT_RENAMEAT
+#define __ARCH_WANT_NEW_STAT
+#define __ARCH_WANT_SET_GET_RLIMIT
+#define __ARCH_WANT_SYS_CLONE3
+
+#include <asm-generic/unistd.h>
+
+/* Additional KVX specific syscalls */
+#define __NR_cachectl (__NR_arch_specific_syscall)
+__SYSCALL(__NR_cachectl, sys_cachectl)
diff --git a/arch/kvx/kernel/entry.S b/arch/kvx/kernel/entry.S
new file mode 100644
index 000000000000..2d16086d29dc
--- /dev/null
+++ b/arch/kvx/kernel/entry.S
@@ -0,0 +1,1759 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Clement Leger
+ * Guillaume Thouvenin
+ * Marius Gligor
+ * Yann Sionneau
+ * Julien Villette
+ */
+
+#include <linux/linkage.h>
+
+#include <asm/thread_info.h>
+#include <asm/asm-offsets.h>
+#include <asm/cache.h>
+#include <asm/page.h>
+#include <asm/pgtable-bits.h>
+#include <asm/sys_arch.h>
+#include <asm/sfr_defs.h>
+#include <asm/tlb_defs.h>
+#include <asm/mem_map.h>
+#include <asm/traps.h>
+#include <asm/unistd.h>
+
+#define MMU_SET_MASK ((1 << KVX_SFR_MMC_SS_WIDTH) - 1)
+
+/* Mask to replicate data from 32bits LSB to MSBs */
+#define REPLICATE_32_MASK 0x0804020108040201
+
+#define PS_HWLOOP_ENABLE (KVX_SFR_PS_HLE_MASK << 32)
+#define PS_HWLOOP_DISABLE (KVX_SFR_PS_HLE_MASK)
+#define PS_HWLOOP_EN_ET_CLEAR_DAUS_DIS \
+ (PS_HWLOOP_ENABLE | KVX_SFR_PS_ET_MASK | SFR_SET_VAL_WFXL(PS, DAUS, 0))
+#define PS_ET_CLEAR KVX_SFR_PS_ET_MASK
+#define PS_HLE_EN_IT_EN_ET_CLEAR_DAUS_DIS \
+ (SFR_SET_VAL_WFXL(PS, HLE, 1) | \
+ SFR_SET_VAL_WFXL(PS, IE, 1) | \
+ SFR_SET_VAL_WFXL(PS, ET, 0) | \
+ SFR_SET_VAL_WFXL(PS, DAUS, 0))
+
+#define PS_IT_DIS KVX_SFR_PS_IE_MASK
+#define PS_IL_CLEAR KVX_SFR_PS_IL_WFXL_CLEAR
+
+#define MMC_CLEAR_TLB_CLEAR_WAY \
+ (SFR_CLEAR_WFXL(MMC, SB) | SFR_CLEAR_WFXL(MMC, SW))
+
+#define MMC_SEL_TLB_CLEAR_WAY(__tlb) \
+ (SFR_SET_WFXL(MMC, SB, __tlb) | MMC_CLEAR_TLB_CLEAR_WAY)
+#define MMC_SEL_JTLB_CLEAR_WAY MMC_SEL_TLB_CLEAR_WAY(MMC_SB_JTLB)
+#define MMC_SEL_LTLB_CLEAR_WAY MMC_SEL_TLB_CLEAR_WAY(MMC_SB_LTLB)
+
+#define MME_WFXL(_enable) SFR_SET_VAL_WFXL(PS, MME, _enable)
+
+/* Temporary scract system register for trap handling */
+#define TMP_SCRATCH_SR $sr_pl3
+
+.altmacro
+
+#define TEL_DEFAULT_VALUE (TLB_ES_A_MODIFIED << KVX_SFR_TEL_ES_SHIFT)
+
+#define TASK_THREAD_SAVE_AREA_QUAD(__q) \
+ (TASK_THREAD_SAVE_AREA + (__q) * QUAD_REG_SIZE)
+
+#ifdef CONFIG_DEBUG_EXCEPTION_STACK
+.section .rodata
+stack_error_panic_str_label:
+ .string "Stack has been messed up !"
+#endif
+
+#ifdef CONFIG_KVX_DEBUG_TLB_WRITE
+.section .rodata
+mmc_error_panic_str_label:
+ .string "Failed to write entry to the JTLB (in assembly refill)"
+#endif
+
+#ifdef CONFIG_KVX_DEBUG_ASN
+.section .rodata
+asn_error_panic_str_label:
+ .string "ASN mismatch !"
+#endif
+
+/**
+ * call_trace_hardirqs: hardirqs tracing call
+ * state: State of hardirqs to be reported (on/off)
+ */
+.macro call_trace_hardirqs state
+#ifdef CONFIG_TRACE_IRQFLAGS
+ call trace_hardirqs_\state
+ ;;
+#endif
+.endm
+
+/**
+ * disable_interrupts: Disable interrupts
+ * tmp_reg: Temporary register to use for interrupt disabling
+ */
+.macro disable_interrupt tmp_reg
+ make \tmp_reg = KVX_SFR_PS_IE_MASK
+ ;;
+ wfxl $ps, \tmp_reg
+ ;;
+.endm
+
+/**
+ * call_do_work_pending: Call do_work_pending and set stack argument ($r0)
+ * NOTE: Since do_work_pending requires thread_flags in $r1, they must
+ * be provided in $r1 before calling this macro.
+ * Moreover, do_work_pending expects interrupts to be disabled.
+ */
+.macro call_do_work_pending
+ copyd $r0 = $sp
+ call do_work_pending
+ ;;
+.endm
+
+/**
+ * save_quad_regs: Save quad registers in temporary thread area
+ * After call, the quad is saved in task_struct.thread.save_area.
+ * sr_swap_reg is only used as a temporary value and will be
+ * restored after returning from this macro
+ *
+ * quad: Quad to saved
+ * sr_swap_reg: Register used for sr swap and quad saving.
+ */
+.macro save_quad_regs quad sr_swap_reg
+ rswap \sr_swap_reg = $sr
+ ;;
+ /* Save registers in save_area */
+ so __PA(TASK_THREAD_SAVE_AREA_QUAD(0))[\sr_swap_reg] = \quad
+ /* Restore register */
+ rswap \sr_swap_reg = $sr
+ ;;
+.endm
+
+/**
+ * Switch task when entering kernel if needed.
+ * sp_reg: register which will be used to store original stack pointer when
+ * entering the kernel
+ * task_reg: is a register containing the current task pointer
+ * save_regs_label: label to jump to save register immediately. This label is
+ * used when we are already in kernel execution context.
+ * NOTE: when returning from this macro, we consider that the assembly following
+ * it will be executed only when coming from user space
+ */
+.macro switch_stack sp_reg task_reg save_regs_label
+ get \sp_reg = $sps
+ ;;
+ /* Check if $sps.pl bit is 0 (ie in kernel mode)
+ * if so, then we dont have to switch stack */
+ cb.even \sp_reg? \save_regs_label
+ /* Copy original $sp in a scratch reg */
+ copyd \sp_reg = $sp
+ ;;
+ /* restore sp from kernel stack pointer */
+ ld $sp = __PA(TASK_THREAD_KERNEL_SP)[\task_reg]
+ ;;
+.endm
+
+/**
+ * Disable MMU using a specified register
+ * scratch_reg: Scratch register to be used for $ps modification (clobbered)
+ * ps_val: Additionnal $ps modifications after returning disabling MMU
+ */
+.macro disable_mmu scratch_reg ps_val=0
+ /* Disable MME in $sps */
+ make \scratch_reg = MME_WFXL(0)
+ ;;
+ wfxl $sps = \scratch_reg
+ ;;
+ /* Enable DAUS in $ps */
+ make \scratch_reg = SFR_SET_VAL_WFXL(PS, DAUS, 1) | \ps_val
+ ;;
+ wfxl $ps = \scratch_reg
+ /* We are now accessing data with MMU disabled */
+ ;;
+.endm
+
+/**
+ * Disable MMU when entering exception path
+ * This macro does not require any register since used register will be
+ * restored after use. This can safely be used directly after entering
+ * exceptions.
+ */
+.macro exception_entry_disable_mmu
+ set TMP_SCRATCH_SR = $r0
+ disable_mmu $r0
+ ;;
+ get $r0 = TMP_SCRATCH_SR
+ ;;
+.endm
+
+/* Save callee registers on stack */
+.macro save_callee
+ sq PT_R18R19[$sp] = $r18r19
+ ;;
+ so PT_Q20[$sp] = $r20r21r22r23
+ ;;
+ so PT_Q24[$sp] = $r24r25r26r27
+ ;;
+ so PT_Q28[$sp] = $r28r29r30r31
+ ;;
+.endm
+
+/**
+ * Save registers for entry in kernel space.
+ * sp_reg should point to the original stack pointer when entering kernel space
+ * task_reg is a register containing the current task pointer
+ * both task_reg and sp_reg must be in saved_quad since they have been cloberred
+ * and will be restored when restoring saved_quad.
+ * pt_regs_sp is a single register which will be filled by pt_regs addr.
+ * When "returning" from this macro, hardware loop are enabled and exception
+ * is cleared, allowing to call kernel function without any risk.
+ */
+.macro save_regs_for_exception sp_reg task_reg saved_quad pt_regs_sp
+.if (\saved_quad==$r4r5r6r7 || \saved_quad==$r60r61r62r63)
+.error "saved_quad must not be $r4r5r6r7 or $r60r61r62r63 !"
+.endif
+ /* make some room on stack to save registers */
+ addd $sp = $sp, -(PT_SIZE_ON_STACK)
+ so __PA(PT_Q4-PT_SIZE_ON_STACK)[$sp] = $r4r5r6r7
+ /* Compute physical address of stack to avoid using 64bits immediate */
+ addd $r6 = $sp, VA_TO_PA_OFFSET - (PT_SIZE_ON_STACK)
+ ;;
+ so PT_Q60[$r6] = $r60r61r62r63
+ /* Now that $r60r61r62r63 is saved, we can use it for saving
+ * original stack stored in scratch_reg. Note that we can not
+ * use the r12r13r14r15 quad to do that because it would
+ * modify the current $r12/sp ! This is if course not what we
+ * want and hence we use the freshly saved quad $r60r61r62r63.
+ *
+ * Note that we must use scratch_reg before reloading the saved
+ * quad since the scratch reg is contained in it, so reloading
+ * it before copying it would overwrite it.
+ */
+ copyd $r60 = \sp_reg
+ ;;
+ /* Reload the saved quad registers to save correct values
+ * Since we use the scratch reg before that */
+ lo \saved_quad = __PA(TASK_THREAD_SAVE_AREA_QUAD(0))[\task_reg]
+ ;;
+ so PT_Q8[$r6] = $r8r9r10r11
+ ;;
+ so PT_Q0[$r6] = $r0r1r2r3
+ copyd $r61 = $r13
+ get $r5 = $le
+ ;;
+ sq PT_R16R17[$r6] = $r16r17
+ make $r10 = 0x0
+ copyd $r62 = $r14
+ ;;
+ so PT_Q32[$r6] = $r32r33r34r35
+ /* Since we are going to enable hardware loop, we must be careful
+ * and reset le (loop exit) to avoid any exploit and return to
+ * user with kernel mode */
+ set $le = $r10
+ copyd $r63 = $r15
+ ;;
+ so PT_Q36[$r6] = $r36r37r38r39
+ get $r0 = $cs
+ ;;
+ so PT_Q40[$r6] = $r40r41r42r43
+ get $r1 = $spc
+ ;;
+ so PT_Q44[$r6] = $r44r45r46r47
+ get $r2 = $sps
+ ;;
+ so PT_Q48[$r6] = $r48r49r50r51
+ get $r3 = $es
+ ;;
+ so PT_Q52[$r6] = $r52r53r54r55
+ get $r7 = $ra
+ ;;
+ so PT_Q56[$r6] = $r56r57r58r59
+ get $r4 = $lc
+ ;;
+ so PT_Q12[$r6] = $r60r61r62r63
+ copyd $r63 = $r6
+ get $r6 = $ls
+ ;;
+ so PT_CS_SPC_SPS_ES[$r63] = $r0r1r2r3
+ ;;
+ so PT_LC_LE_LS_RA[$r63] = $r4r5r6r7
+ /* Clear frame pointer */
+ make $fp = 0
+ ;;
+ /* Copy regs stack pointer for macro caller */
+ copyd \pt_regs_sp = $sp
+#ifdef CONFIG_DEBUG_EXCEPTION_STACK
+ addd $sp = $sp, -STACK_REG_SIZE
+ ;;
+ sd VA_TO_PA_OFFSET[$sp] = $sp
+ ;;
+#endif
+ /* Reenable hwloop, MMU and clear exception taken */
+ make $r8 = PS_HWLOOP_EN_ET_CLEAR_DAUS_DIS
+ ;;
+ wfxl $ps, $r8
+ ;;
+.endm
+
+/***********************************************************************
+* Exception vectors trampolines
+***********************************************************************/
+#define exception_trampoline(__type) \
+.section .exception.## __type, "ax", @progbits ;\
+ENTRY(kvx_##__type ##_handler_trampoline): ;\
+ goto kvx_## __type ##_handler ;\
+ ;; ;\
+ENDPROC(kvx_ ## __type ## _handler_trampoline) ;\
+.section .early_exception.## __type, "ax", @progbits ;\
+ENTRY(kvx_## __type ##_early_handler): ;\
+1: nop ;\
+ ;; ;\
+ goto 1b ;\
+ ;; ;\
+ENDPROC(kvx_ ## __type ## _early_handler)
+
+exception_trampoline(debug)
+exception_trampoline(trap)
+exception_trampoline(interrupt)
+exception_trampoline(syscall)
+
+#define EXCEPTION_ENTRY(__name) \
+.section .exception.text, "ax", @progbits ;\
+ENTRY(__name)
+
+
+/***********************************************************************
+* Common exception return path
+***********************************************************************/
+/**
+ * Restore registers after exception
+ * When entering this macro, $sp must be located right before regs
+ * storage.
+ */
+EXCEPTION_ENTRY(return_from_exception)
+#ifdef CONFIG_DEBUG_EXCEPTION_STACK
+ ld $r1 = 0[$sp]
+ ;;
+ sbfd $r1 = $r1, $sp
+ ;;
+ cb.deqz $r1, _check_ok
+ ;;
+ make $r2 = panic
+ make $r0 = stack_error_panic_str_label
+ ;;
+ icall $r2
+ ;;
+_check_ok:
+ addd $sp = $sp, STACK_REG_SIZE
+ ;;
+#endif
+ get $r11 = $sr
+ /* Load sps value from saved registers */
+ ld $r6 = PT_SPS[$sp]
+ ;;
+ /* Disable interrupt to check task flags atomically */
+ disable_interrupt $r60
+ ;;
+ /* Check PL bit of sps, if set, then it means we are returning
+ * to a lower privilege level (ie to user), if so, we need to
+ * check work pending. If coming from kernel, directly go to
+ * register restoration */
+ cb.even $r6? _restore_regs
+ ld $r1 = TASK_TI_FLAGS[$r11]
+ ;;
+ /* Do we have work pending ? */
+ andd $r5 = $r1, _TIF_WORK_MASK
+ ;;
+ /**
+ * If we do not have work pending (ie $r5 == 0) then we can
+ * directly jump to _restore_regs without calling do_work_pending
+ */
+ cb.deqz $r5? _restore_regs
+ ;;
+ /*
+ * Work pending can potentially call a signal handler and then return
+ * via rt_sigreturn. Return path will be different (restore all regs)
+ * and hence all registers are needed to be saved.
+ */
+ save_callee
+ ;;
+ call_do_work_pending
+ ;;
+#ifdef CONFIG_TRACE_IRQFLAGS
+ /* reload sps value from saved registers */
+ ld $r6 = PT_SPS[$sp]
+ ;;
+#endif
+_restore_regs:
+#ifdef CONFIG_TRACE_IRQFLAGS
+ /* Check if IRQs are going to be reenable in next context */
+ andd $r6 = $r6, KVX_SFR_SPS_IE_MASK
+ ;;
+ cb.deqz $r6? 1f
+ ;;
+ call trace_hardirqs_on
+ ;;
+1:
+#endif
+ disable_mmu $r0, PS_HWLOOP_DISABLE
+ ;;
+ lo $r0r1r2r3 = __PA(PT_CS_SPC_SPS_ES)[$sp]
+ /* Compute physical address of stack to avoid using 64bits immediate */
+ addd $r11 = $sp, VA_TO_PA_OFFSET
+ ;;
+ lo $r4r5r6r7 = PT_LC_LE_LS_RA[$r11]
+ ;;
+ lo $r60r61r62r63 = PT_Q60[$r11]
+ ;;
+ lo $r56r57r58r59 = PT_Q56[$r11]
+ ;;
+ lo $r52r53r54r55 = PT_Q52[$r11]
+ get $r14 = $sps
+ ;;
+ lo $r48r49r50r51 = PT_Q48[$r11]
+ /* Generate a mask of ones at each bit where the current $sps
+ * differs from the $sps to be restored
+ */
+ xord $r14 = $r2, $r14
+ /* prepare wfxl clear mask on LSBs */
+ notd $r15 = $r2
+ /* prepare wfxl set mask on MSBs */
+ slld $r13 = $r2, 32
+ ;;
+ lo $r44r45r46r47 = PT_Q44[$r11]
+ /* Replicate mask of ones on the 32 MSBs */
+ sbmm8 $r14 = $r14, REPLICATE_32_MASK
+ /* Combine the set and clear mask for wfxl */
+ insf $r13 = $r15, 31, 0
+ ;;
+ lo $r40r41r42r43 = PT_Q40[$r11]
+ set $lc = $r4
+ /* Mask to drop identical bits in order to avoid useless
+ * privilege traps
+ */
+ andd $r13 = $r13, $r14
+ ;;
+ lq $r16r17 = PT_R16R17[$r11]
+ set $le = $r5
+ ;;
+ lo $r32r33r34r35 = PT_Q32[$r11]
+ set $ls = $r6
+ ;;
+ lo $r36r37r38r39 = PT_Q36[$r11]
+ copyd $r14 = $r11
+ set $ra = $r7
+ ;;
+ lo $r8r9r10r11 = PT_Q8[$r14]
+ set $cs = $r0
+ /* MME was disabled by disable_mmu, reenable it before leaving */
+ ord $r13 = $r13, SFR_SET_VAL_WFXL(SPS, MME, 1)
+ ;;
+ lo $r4r5r6r7 = PT_Q4[$r14]
+ set $spc = $r1
+ ;;
+ lo $r0r1r2r3 = PT_Q0[$r14]
+ /* Store $sps wfxl value in scratch system register */
+ set TMP_SCRATCH_SR = $r13
+ ;;
+ lo $r12r13r14r15 = PT_Q12[$r14]
+ rswap $r0 = TMP_SCRATCH_SR
+ ;;
+ wfxl $sps = $r0
+ ;;
+ /* Finally, restore $r0 value */
+ rswap $r0 = TMP_SCRATCH_SR
+ ;;
+ rfe
+ ;;
+ENDPROC(return_from_exception)
+
+/***********************************************************************
+* Debug handling
+***********************************************************************/
+EXCEPTION_ENTRY(kvx_debug_handler):
+ exception_entry_disable_mmu
+ ;;
+ save_quad_regs $r0r1r2r3 $r4
+ ;;
+ get $r2 = $sr
+ ;;
+ switch_stack $r1 $r2 debug_save_regs
+ ;;
+debug_save_regs:
+ save_regs_for_exception $r1 $r2 $r0r1r2r3 $r1
+ ;;
+ get $r0 = $ea
+ /* tail-call for return_from_exception */
+ make $r3 = return_from_exception
+ ;;
+ set $ra = $r3
+ ;;
+ goto debug_handler
+ ;;
+ENDPROC(kvx_debug_handler)
+
+/***********************************************************************
+* Traps handling
+***********************************************************************/
+/* These labels will be used for instruction patching */
+.global kvx_perf_tlb_refill, kvx_std_tlb_refill
+EXCEPTION_ENTRY(kvx_trap_handler):
+ /* Enable DAUS for physical data access */
+ exception_entry_disable_mmu
+ ;;
+ /* Save r3 in a temporary system register to check if the trap is a
+ * nomapping or not */
+ set TMP_SCRATCH_SR = $r3
+ ;;
+ get $r3 = $es
+ ;;
+ /* Hardware trap cause */
+ extfz $r3 = $r3, KVX_SFR_END(ES_HTC), KVX_SFR_START(ES_HTC)
+ ;;
+ /* Is this a nomapping trap ? */
+ compd.eq $r3 = $r3, KVX_TRAP_NOMAPPING
+ ;;
+ /* if nomapping trap, try fast_refill */
+ cb.even $r3? trap_slow_path
+ ;;
+ /*
+ * Fast TLB refill routine
+ *
+ * On kvx, we do not have hardware page walking, hence, TLB refill is
+ * done using the core on no-mapping traps.
+ * This routine must be as fast as possible to avoid wasting CPU time.
+ * For that purpose, it is called directly from trap_handle after saving
+ * only 8 registers ($r0 -> $r7) in a dedicated buffer.
+ * To avoid taking nomapping while accessing page tables inside this
+ * refill handler we switch to physical accesses using DAUS.
+ * Once the switch is done, we save up to 8 registers to compute
+ * the refill data.
+ * This allows to avoid computing a complete task switching in order
+ * to greatly reduce the refill time.
+ *
+ * We refill the JTLB which contains 128 sets with 4 way each.
+ * Currently, the way selection is done using a round robin algorithm.
+ *
+ * The refill is using the basic flow:
+ * 1 - Enable physical access using DAUS.
+ * 2 - Save necessary registers
+ * 3 - Walk the page table to find the TLB entry to add (virtual to
+ * physical)
+ * 4 - Compute the TLB entry to be written (convert PTE to TLB entry)
+ * 5 - Compute the target set (0 -> 127) for the new TLB entry
+ * This is done by extracting the 6 lsb of page number
+ * 6 - Get the current way to be used which is selected using a
+ simple round robin
+ * 7 - Mark PTE entry as _PAGE_ACCESSED (and optionally PAGE_DIRTY)
+ * 8 - Commit the new tlb entry
+ * 9 - Restore the virtual memory by disabling DAUS.
+ *
+ */
+ /* Get current task */
+ rswap $r63 = $sr
+ ;;
+#ifdef CONFIG_KVX_MMU_STATS
+ get $r3 = $pm0
+ ;;
+ sd __PA(TASK_THREAD_ENTRY_TS)[$r63] = $r3
+ ;;
+#endif
+ /* Restore $r3 from temporary system scratch register */
+ get $r3 = TMP_SCRATCH_SR
+ /* Save registers to save $tel, $teh and $mmc */
+ so __PA(TASK_THREAD_SAVE_AREA_QUAD(2))[$r63] = $r8r9r10r11
+ ;;
+ get $r8 = $tel
+ /* Save register for refill handler */
+ so __PA(TASK_THREAD_SAVE_AREA_QUAD(1))[$r63] = $r4r5r6r7
+ ;;
+ /* Get exception address */
+ get $r0 = $ea
+ /* Save more registers to be comfy */
+ so __PA(TASK_THREAD_SAVE_AREA_QUAD(0))[$r63] = $r0r1r2r3
+ ;;
+ get $r9 = $teh
+ ;;
+ get $r10 = $mmc
+ ;;
+ /* Restore $r63 value */
+ rswap $r63 = $sr
+ /* Check kernel address range */
+ addd $r4 = $r0, -KERNEL_DIRECT_MEMORY_MAP_BASE
+ /* Load task active mm for pgd loading in macro_tlb_refill */
+ ld $r1 = __PA(TASK_ACTIVE_MM)[$r63]
+ ;;
+kvx_perf_tlb_refill:
+ /* Check if the address is in the kernel direct memory mapping */
+ compd.ltu $r3 = $r4, KERNEL_DIRECT_MEMORY_MAP_SIZE
+ /* Clear low bits of virtual address to align on page size */
+ andd $r5 = $r0, ~(REFILL_PERF_PAGE_SIZE - 1)
+ /* Create corresponding physical address */
+ addd $r2 = $r4, PHYS_OFFSET
+ ;;
+ /* If address is not a kernel one, take the standard path */
+ cb.deqz $r3? kvx_std_tlb_refill
+ /* Prepare $teh value with virtual address and kernel value */
+ ord $r7 = $r5, REFILL_PERF_TEH_VAL
+ ;;
+ /* Get $pm0 value as a pseudo random value for LTLB way to use */
+ get $r4 = $pm0
+ /* Clear low bits of physical address to align on page size */
+ andd $r2 = $r2, ~(REFILL_PERF_PAGE_SIZE - 1)
+ /* Prepare value for $mmc wfxl to select LTLB and correct way */
+ make $r5 = MMC_SEL_LTLB_CLEAR_WAY
+ ;;
+ /* Keep low bits of timer value */
+ andw $r4 = $r4, (REFILL_PERF_ENTRIES - 1)
+ /* Get current task pointer for register restoration */
+ get $r11 = $sr
+ ;;
+ /* Add LTLB base way number for kernel refill way */
+ addw $r4 = $r4, LTLB_KERNEL_RESERVED
+ /* Prepare $tel value with physical address and kernel value */
+ ord $r6 = $r2, REFILL_PERF_TEL_VAL
+ set $teh = $r7
+ ;;
+ /* insert way in $mmc wfxl value */
+ insf $r5 = $r4, KVX_SFR_END(MMC_SW) + 32, KVX_SFR_START(MMC_SW) + 32
+ set $tel = $r6
+ ;;
+ wfxl $mmc = $r5
+ ;;
+ goto do_tlb_write
+ ;;
+kvx_std_tlb_refill:
+ /* extract PGD offset */
+ extfz $r3 = $r0, (ASM_PGDIR_SHIFT + ASM_PGDIR_BITS - 1), ASM_PGDIR_SHIFT
+ /* is mm NULL ? if so, use init_mm */
+ cmoved.deqz $r1? $r1 = init_mm
+ ;;
+ get $r7 = $pcr
+ /* Load pgd base address into $r1 */
+ ld $r1 = __PA(MM_PGD)[$r1]
+ ;;
+ /* Add offset for physical address */
+ addd $r1 = $r1, VA_TO_PA_OFFSET
+ /* Extract processor ID to compute cpu_offset*/
+ extfz $r7 = $r7, KVX_SFR_END(PCR_PID), KVX_SFR_START(PCR_PID)
+ ;;
+ /* Load PGD entry offset */
+ ld.xs $r1 = $r3[$r1]
+ /* Load per_cpu_offset */
+#if defined(CONFIG_SMP)
+ make $r5 = __PA(__per_cpu_offset)
+#endif
+ ;;
+ /* extract PMD offset*/
+ extfz $r3 = $r0, (ASM_PMD_SHIFT + ASM_PMD_BITS - 1), ASM_PMD_SHIFT
+ /* If pgd entry is null -> out */
+ cb.deqz $r1? refill_err_out
+#if defined(CONFIG_SMP)
+ /* Load cpu offset */
+ ld.xs $r7 = $r7[$r5]
+#else
+ /* Force cpu offset to 0 */
+ make $r7 = 0
+#endif
+ ;;
+ /* Load PMD entry offset and keep pointer to the entry for huge page */
+ addx8d $r2 = $r3, $r1
+ ld.xs $r1 = $r3[$r1]
+ ;;
+ /* Check if it is a huge page (2Mb or 512Mb in PMD table)*/
+ andd $r6 = $r1, _PAGE_HUGE
+ /* If pmd entry is null -> out */
+ cb.deqz $r1? refill_err_out
+ /* extract PTE offset */
+ extfz $r3 = $r0, (PAGE_SHIFT + 8), PAGE_SHIFT
+ ;;
+ /*
+ * If the page is a huge one we already have set the PTE and the
+ * pointer to the PTE.
+ */
+ cb.dnez $r6? is_huge_page
+ ;;
+ /* Load PTE entry */
+ ld.xs $r1 = $r3[$r1]
+ addx8d $r2 = $r3, $r1
+ ;;
+ /* Check if it is a huge page (64Kb in PTE table) */
+ andd $r6 = $r1, _PAGE_HUGE
+ ;;
+ /* Check if PTE entry is for a huge page */
+ cb.dnez $r6? is_huge_page
+ ;;
+ /* 4K: Extract set value */
+ extfz $r0 = $r1, (PAGE_SHIFT + KVX_SFR_MMC_SS_WIDTH - 1), PAGE_SHIFT
+ /* 4K: Extract virt page from ea */
+ andd $r4 = $r0, PAGE_MASK
+ ;;
+/*
+ * This path expects the following:
+ * - $r0 = set index
+ * - $r1 = pte entry
+ * - $r2 = pte entry address
+ * - $r4 = virtual page address
+ */
+pte_prepared:
+ /* Compute per_cpu_offset + current way of set address */
+ addd $r5 = $r0, $r7
+ /* Get exception cause for access type handling (page dirtying) */
+ get $r7 = $es
+ /* Clear way and select JTLB */
+ make $r6 = MMC_SEL_JTLB_CLEAR_WAY
+ ;;
+ /* Load current way to use for current set */
+ lbz $r0 = __PA(jtlb_current_set_way)[$r5]
+ /* Check if the access was a "write" access */
+ andd $r7 = $r7, (KVX_TRAP_RWX_WRITE << KVX_SFR_ES_RWX_SHIFT)
+ ;;
+ /* If bit PRESENT of pte entry is 0, then entry is not present */
+ cb.even $r1? refill_err_out
+ /*
+ * Set the JTLB way in $mmc value, add 32 bits to be in the set part.
+ * Since we are refilling JTLB, we must make sure we insert only
+ * relevant bits (ie 2 bits for ways) to avoid using nonexistent ways.
+ */
+ insf $r6 = $r0, KVX_SFR_START(MMC_SW) + 32 + (MMU_JTLB_WAYS_SHIFT - 1),\
+ KVX_SFR_START(MMC_SW) + 32
+ /* Extract page global bit */
+ extfz $r3 = $r1, _PAGE_GLOBAL_SHIFT, _PAGE_GLOBAL_SHIFT
+ /* Increment way value, note that we do not care about overflow since
+ * we only use the two lower byte */
+ addd $r0 = $r0, 1
+ ;;
+ /* Prepare MMC */
+ wfxl $mmc, $r6
+ ;;
+ /* Insert global bit (if any) to its position into $teh value */
+ insf $r4 = $r3, KVX_SFR_TEH_G_SHIFT, KVX_SFR_TEH_G_SHIFT
+ /* If "write" access ($r7 != 0), then set it as dirty */
+ cmoved.dnez $r7? $r7 = _PAGE_DIRTY
+ /* Clear bits not related to FN in the pte entry for TEL writing */
+ andd $r6 = $r1, KVX_PFN_MASK
+ /* Store new way */
+ sb __PA(jtlb_current_set_way)[$r5] = $r0
+ ;;
+ /* Extract access perms from pte entry (discard PAGE_READ bit +1) */
+ extfz $r3 = $r1, KVX_ACCESS_PERM_STOP_BIT, KVX_ACCESS_PERM_START_BIT + 1
+ /* Move FN bits to their place */
+ srld $r6 = $r6, KVX_PFN_SHIFT - PAGE_SHIFT
+ /* Extract the page size + cache policy */
+ andd $r0 = $r1, (KVX_PAGE_SZ_MASK | KVX_PAGE_CP_MASK)
+ /* Prepare SBMM value */
+ make $r5 = KVX_SBMM_BYTE_SEL
+ ;;
+ /* Add page size + cache policy to $tel value */
+ ord $r6 = $r6, $r0
+ /* Get $mmc to get current ASN */
+ get $r0 = $mmc
+ /* Add _PAGE_ACCESSED bit to PTE entry for writeback */
+ ord $r7 = $r7, _PAGE_ACCESSED
+ ;;
+ /* OR PTE value with accessed/dirty flags */
+ ord $r1 = $r1, $r7
+ /* Generate the byte selection for sbmm */
+ slld $r5 = $r5, $r3
+ /* Compute the mask to extract set and mask exception address */
+ make $r7 = KVX_PAGE_PA_MATRIX
+ ;;
+ ord $r0 = $r6, TEL_DEFAULT_VALUE
+ /* Add ASN from mmc into future $teh value */
+ insf $r4 = $r0, KVX_SFR_END(MMC_ASN), KVX_SFR_START(MMC_ASN)
+ /* Get the page permission value */
+ sbmm8 $r6 = $r7, $r5
+ /* Check PAGE_READ bit in PTE entry */
+ andd $r3 = $r1, _PAGE_READ
+ ;;
+ /* If PAGE_READ bit is not set, set policy as NA_NA */
+ cmoved.deqz $r3? $r6 = TLB_PA_NA_NA
+ ;;
+ /* Shift PA to correct position */
+ slld $r6 = $r6, KVX_SFR_TEL_PA_SHIFT
+ set $teh = $r4
+ ;;
+ /* Store updated pte entry */
+ sd 0[$r2] = $r1
+ /* Prepare tel */
+ ord $r6 = $r0, $r6
+ /* Get current task pointer for register restoration */
+ get $r11 = $sr
+ ;;
+ set $tel = $r6
+ ;;
+do_tlb_write:
+ tlbwrite
+ ;;
+#ifdef CONFIG_KVX_DEBUG_TLB_WRITE
+ goto mmc_error_check
+ ;;
+mmc_error_check_ok:
+#endif
+#ifdef CONFIG_KVX_DEBUG_ASN
+ goto asn_check
+ ;;
+asn_check_ok:
+#endif
+ set $tel = $r8
+ /* Restore registers */
+ lo $r4r5r6r7 = __PA(TASK_THREAD_SAVE_AREA_QUAD(1))[$r11]
+ ;;
+ set $teh = $r9
+ lo $r0r1r2r3 = __PA(TASK_THREAD_SAVE_AREA_QUAD(0))[$r11]
+ ;;
+ set $mmc = $r10
+ ;;
+ lo $r8r9r10r11 = __PA(TASK_THREAD_SAVE_AREA_QUAD(2))[$r11]
+ ;;
+#ifdef CONFIG_KVX_MMU_STATS
+ /*
+ * Fence to simulate a direct data dependency after returning from trap
+ * nomapping handling. This is the worst case that can happen and the
+ * processor will be stalled waiting for previous loads to complete.
+ */
+ fence
+ ;;
+ get $r4 = $pm0
+ ;;
+ get $r0 = $sr
+ ;;
+ /* Get cycles measured on trap entry */
+ ld $r1 = __PA(TASK_THREAD_ENTRY_TS)[$r0]
+ ;;
+ /* Compute refill time */
+ sbfd $r0 = $r1, $r4
+ ;;
+#ifdef CONFIG_SMP
+ get $r1 = $pcr
+ ;;
+ /* Extract processor ID to compute cpu_offset */
+ extfz $r1 = $r1, KVX_SFR_END(PCR_PID), KVX_SFR_START(PCR_PID)
+ make $r2 = __PA(__per_cpu_offset)
+ ;;
+ /* Load cpu offset */
+ ld.xs $r1 = $r1[$r2]
+ ;;
+ addd $r1 = $r1, __PA(mmu_stats)
+ ;;
+#else
+ make $r1 = __PA(mmu_stats)
+ ;;
+#endif
+ /* Load time between refill + last refill cycle */
+ lq $r2r3 = MMU_STATS_CYCLES_BETWEEN_REFILL_OFF[$r1]
+ ;;
+ /* Set last update time to current if 0 */
+ cmoved.deqz $r3? $r3 = $r4
+ /* remove current refill time to current cycle */
+ sbfd $r4 = $r0, $r4
+ ;;
+ /* Compute time between last refill and current refill */
+ sbfd $r5 = $r3, $r4
+ /* Update last cycle time */
+ copyd $r3 = $r4
+ ;;
+ /* Increment total time between refill */
+ addd $r2 = $r2, $r5
+ ;;
+ sq MMU_STATS_CYCLES_BETWEEN_REFILL_OFF[$r1] = $r2r3
+ /* Get exception address */
+ get $r4 = $ea
+ ;;
+ /* $r2 holds refill type (user/kernel/kernel_direct) */
+ make $r2 = MMU_STATS_REFILL_KERNEL_OFF
+ /* Check if address is a kernel direct mapping one */
+ compd.ltu $r3 = $r4, (KERNEL_DIRECT_MEMORY_MAP_BASE + \
+ KERNEL_DIRECT_MEMORY_MAP_SIZE)
+ ;;
+ cmoved.dnez $r3? $r2 = MMU_STATS_REFILL_KERNEL_DIRECT_OFF
+ /* Check if address is a user (ie below kernel) */
+ compd.ltu $r3 = $r4, KERNEL_DIRECT_MEMORY_MAP_BASE
+ ;;
+ cmoved.dnez $r3? $r2 = MMU_STATS_REFILL_USER_OFF
+ ;;
+ /* Compute refill struct addr into one reg */
+ addd $r1 = $r2, $r1
+ /* Load refill_struct values */
+ lo $r4r5r6r7 = $r2[$r1]
+ ;;
+ /* Increment count */
+ addd $r4 = $r4, 1
+ /* Increment total cycles count */
+ addd $r5 = $r5, $r0
+ ;;
+ /* Set min to ~0 if 0 */
+ cmoved.deqz $r6? $r6 = ~0
+ ;;
+ /* Compare min and max */
+ compd.ltu $r2 = $r0, $r6
+ compd.gtu $r3 = $r0, $r7
+ ;;
+ /* Update min and max*/
+ cmoved.dnez $r2? $r6 = $r0
+ cmoved.dnez $r3? $r7 = $r0
+ ;;
+ /* store back all values */
+ so 0[$r1] = $r4r5r6r7
+ ;;
+ get $r0 = $sr
+ ;;
+ /* Restore cloberred registers */
+ lo $r4r5r6r7 = __PA(TASK_THREAD_SAVE_AREA_QUAD(1))[$r0]
+ ;;
+ lo $r0r1r2r3 = __PA(TASK_THREAD_SAVE_AREA_QUAD(0))[$r0]
+ ;;
+#endif
+ /* Save $r4 for reenabling mmu and data cache in sps */
+ set TMP_SCRATCH_SR = $r4
+ /* Enable MME in $sps */
+ make $r4 = MME_WFXL(1)
+ ;;
+ /* Reenable $mme in $sps */
+ wfxl $sps = $r4
+ ;;
+ get $r4 = TMP_SCRATCH_SR
+ ;;
+ rfe
+ ;;
+
+is_huge_page:
+ /*
+ * When entering this path:
+ * - $r0 = $ea
+ * - $r1 = pte entry
+ * - $r7 = cpu offset for tlb_current_set_way
+ *
+ * From now on, we have the pte value in $r1 so we can extract the page
+ * size. This value is stored as it is expected by the MMU (ie between
+ * 0 and 3).
+ * Note that page size value is located at the same place as in $tel
+ * and this is checked at build time so we can use TEL_PS defines.
+ * In this codepath, we will extract the set and mask exception address
+ * and align virt and phys address with what the hardware expect.
+ * Indeed, MMU expect lsb of the virtual and physycal address to be 0
+ * according to page size.
+ * This means that for 4K pages, the 12 lsb must be 0, for 64K
+ * pages, the 16 lsb must be 0 and so on.
+ */
+ extfz $r5 = $r1, KVX_SFR_END(TEL_PS), KVX_SFR_START(TEL_PS)
+ /* Compute the mask to extract set and mask exception address */
+ make $r4 = KVX_PS_SHIFT_MATRIX
+ make $r6 = KVX_SBMM_BYTE_SEL
+ ;;
+ /* Generate the byte selection for sbmm */
+ slld $r6 = $r6, $r5
+ ;;
+ /* Get the shift value */
+ sbmm8 $r5 = $r4, $r6
+ make $r4 = 0xFFFFFFFFFFFFFFFF
+ ;;
+ /* extract TLB set from ea (6 lsb of virtual page) */
+ srld $r5 = $r0, $r5
+ /* Generate ea masking according to page shift */
+ slld $r4 = $r4, $r5
+ ;;
+ /* Mask to get the set value */
+ andd $r0 = $r5, MMU_SET_MASK
+ /* Extract virt page from ea */
+ andd $r4 = $r0, $r4
+ ;;
+ /* Returned to fast path */
+ goto pte_prepared
+ ;;
+
+#ifdef CONFIG_KVX_DEBUG_TLB_WRITE
+mmc_error_check:
+ get $r1 = $mmc
+ ;;
+ andd $r1 = $r1, KVX_SFR_MMC_E_MASK
+ ;;
+ cb.deqz $r1? mmc_error_check_ok
+ ;;
+ make $r0 = mmc_error_panic_str_label
+ goto asm_panic
+ ;;
+#endif
+#ifdef CONFIG_KVX_DEBUG_ASN
+/*
+ * When entering this path $r11 = $sr.
+ * WARNING: Do not clobber it here if you don't want to mess up with registers
+ * restoration above.
+ */
+asn_check:
+ get $r1 = $ea
+ ;;
+ /* Check if kernel address, if so, there is no ASN */
+ compd.geu $r2 = $r1, PAGE_OFFSET
+ ;;
+ cb.dnez $r2? asn_check_ok
+ ;;
+ get $r2 = $pcr
+ /* Load active mm addr */
+ ld $r3 = __PA(TASK_ACTIVE_MM)[$r11]
+ ;;
+ get $r5 = $mmc
+ /* Extract processor ID to compute cpu_offset*/
+ extfz $r2 = $r2, KVX_SFR_END(PCR_PID), KVX_SFR_START(PCR_PID)
+ addd $r3 = $r3, MM_CTXT_ASN
+ ;;
+ extfz $r4 = $r5, KVX_SFR_END(MMC_ASN), KVX_SFR_START(MMC_ASN)
+ addd $r3 = $r3, VA_TO_PA_OFFSET
+ ;;
+ /* Load current asn from active_mm */
+ ld.xs $r3 = $r2[$r3]
+ ;;
+ /* Error if ASN is not set */
+ cb.deqz $r3? asn_check_err
+ /* Mask $r3 asn cycle part */
+ andd $r5 = $r3, ((1 << KVX_SFR_MMC_ASN_WIDTH) - 1)
+ ;;
+ /* Compare asn in $mmc and asn in current task mm */
+ compd.eq $r3 = $r5, $r4
+ ;;
+ cb.dnez $r3? asn_check_ok
+ ;;
+asn_check_err:
+ /* We are fried, die peacefully */
+ make $r0 = asn_error_panic_str_label
+ goto asm_panic
+ ;;
+#endif
+
+#if defined(CONFIG_KVX_DEBUG_ASN) || defined(CONFIG_KVX_DEBUG_TLB_WRITE)
+
+/**
+ * This routine calls panic from assembly after setting appropriate things
+ * $r0 = panic string
+ */
+asm_panic:
+ /*
+ * Reenable hardware loop and traps (for nomapping) since some functions
+ * might need it. Moreover, disable DAUS to reenable MMU accesses.
+ */
+ make $r32 = PS_HWLOOP_EN_ET_CLEAR_DAUS_DIS
+ make $r33 = 0
+ get $r34 = $sr
+ ;;
+ /* Clear hw loop exit to disable current loop */
+ set $le = $r33
+ ;;
+ wfxl $ps = $r32
+ ;;
+ /* Restore kernel stack */
+ ld $r12 = TASK_THREAD_KERNEL_SP[$r34]
+ ;;
+ call panic
+ ;;
+#endif
+
+/* Error path for TLB refill */
+refill_err_out:
+ get $r2 = $sr
+ ;;
+ /* Restore clobbered registers */
+ lo $r8r9r10r11 = __PA(TASK_THREAD_SAVE_AREA_QUAD(2))[$r2]
+ ;;
+ lo $r4r5r6r7 = __PA(TASK_THREAD_SAVE_AREA_QUAD(1))[$r2]
+ goto trap_switch_stack
+ ;;
+
+/* This path is entered only when the trap is NOT a NOMAPPING */
+trap_slow_path:
+ /* Restore $r3 from temporary scratch system register */
+ get $r3 = TMP_SCRATCH_SR
+ ;;
+ save_quad_regs $r0r1r2r3 $r4
+ ;;
+ get $r2 = $sr
+ ;;
+trap_switch_stack:
+ switch_stack $r1 $r2 trap_save_regs
+ ;;
+trap_save_regs:
+ save_regs_for_exception $r1 $r2 $r0r1r2r3 $r2
+ ;;
+ get $r1 = $ea
+ /* tail-call for return_from_exception */
+ make $r3 = return_from_exception
+ ;;
+ set $ra = $r3
+ ;;
+ /* Handler call */
+ get $r0 = $es
+ ;;
+ goto trap_handler
+ ;;
+ENDPROC(kvx_trap_handler)
+
+/***********************************************************************
+* Interrupts handling
+***********************************************************************/
+EXCEPTION_ENTRY(kvx_interrupt_handler):
+ exception_entry_disable_mmu
+ ;;
+ save_quad_regs $r0r1r2r3 $r4
+ ;;
+ get $r0 = $sr
+ ;;
+ switch_stack $r1 $r0 it_save_regs
+ ;;
+#ifdef CONFIG_SECURE_DAME_HANDLING
+ /**
+ * In order to securely Handle Data Asynchronous Memory Error,
+ * we need to have a correct entry point. This means we do not
+ * want to handle a user induced DAME interrupt when entering
+ * kernel.
+ * In order to do that, we need to do a barrier, which will
+ * reflect the DAME status in $ilr (if any).
+ */
+ barrier
+ ;;
+#endif
+it_save_regs:
+ save_regs_for_exception $r1 $r0 $r0r1r2r3 $r1
+ ;;
+ get $r0 = $ilr
+ ;;
+ get $r2 = $ile
+ ;;
+ /**
+ * When an interrupt happens, the processor automatically clears the
+ * corresponding bit in $ilr. However, as we are using $ilr to get the
+ * list of irqs we want to handle, we need to add the automatically
+ * cleared interrupt bit. This is done by getting the interrupt number
+ * from $es.
+ */
+ get $r3 = $es
+ make $r4 = 1
+ ;;
+ /* Extract interrupt number from $es */
+ extfz $r3 = $r3, KVX_SFR_END(ES_ITN), KVX_SFR_START(ES_ITN)
+ /**
+ * Mask requests with enabled line since ILR will also contain disabled
+ * interrupt lines (ie not enabled in $ile) and we want to respect the
+ * current state of interrupt lines.
+ */
+ andd $r0 = $r0, $r2
+ ;;
+ /* Clear $ilr with bits we are going to handle */
+ wfxl $ilr = $r0
+ slld $r4 = $r4, $r3
+ ;;
+ /* OR the irq mask with the current pending irq */
+ ord $r0 = $r0, $r4
+ call do_IRQ
+ ;;
+ /* From now on, lower the interrupt level (IL) to allow IT nesting.
+ * If returning to user, we will call schedule which will reenable
+ * interrupts by itself when ready.
+ * If returning to kernel and with CONFIG_PREEMPT, we will call
+ * preempt_schedule_irq which will do the same.
+ */
+ make $r0 = PS_IL_CLEAR
+ ;;
+ wfxl $ps = $r0
+ ;;
+ goto return_from_exception
+ ;;
+ENDPROC(kvx_interrupt_handler)
+
+/***********************************************************************
+* Syscall handling
+***********************************************************************/
+EXCEPTION_ENTRY(kvx_syscall_handler):
+ /**
+ * Syscalls are seen as standard func call from ABI POV
+ * We may use all caller saved register whithout causing havoc
+ * in the userspace. We need to save callee registers because they
+ * will be restored when returning from fork.
+ * Note that r0 -> r11 MUST not be used since they are
+ * containing syscall parameters !
+ * During this function, $r38 is the syscall handler address. Hence,
+ * this register must not be cloberred during function calls (tracing
+ * for instance.
+ */
+ disable_mmu $r43
+ ;;
+ get $r43 = $es
+ copyd $r52 = $sp
+ copyd $r53 = $tp
+ ;;
+ get $r36 = $sr
+ copyd $r54 = $fp
+ copyd $r55 = $r15
+ ;;
+ /* Extract syscall number */
+ extfz $r32 = $r43, KVX_SFR_END(ES_SN), KVX_SFR_START(ES_SN)
+ /* Get regs to save on stack */
+ get $r63 = $ra
+ addd $r36 = $r36, VA_TO_PA_OFFSET
+ ;;
+ ld $r39 = TASK_TI_FLAGS[$r36]
+ get $r41 = $spc
+ make $r42 = __PA(sys_call_table)
+ ;;
+ /* Check for out-of-bound syscall number */
+ sbfd $r50 = $r32, __NR_syscalls
+ /* Compute syscall func addr (ie sys_call_table[$r32])*/
+ ld.xs $r38 = $r32[$r42]
+ get $r42 = $sps
+ ;;
+ /* True if trace syscall enable */
+ andd $r37 = $r39, _TIF_SYSCALL_WORK
+ /* Restore kernel stack pointer */
+ ld $sp = TASK_THREAD_KERNEL_SP[$r36]
+ /* If the syscall number is invalid, set invalid handler */
+ cmoved.dlez $r50? $r38 = sys_ni_syscall
+ ;;
+ /* Prepare space on stack */
+ addd $sp = $sp, -PT_SIZE_ON_STACK
+ get $r40 = $cs
+ /* Save regs r0 -> r3 in pt_regs for restart & trace if needed */
+ so __PA(PT_Q0 - PT_SIZE_ON_STACK)[$sp] = $r0r1r2r3
+ ;;
+ /* Store user stack pointer, frame pointer, thread pointer and r15 */
+ so __PA(PT_Q12)[$sp] = $r52r53r54r55
+ addd $r36 = $sp, VA_TO_PA_OFFSET
+ get $r60 = $lc
+ ;;
+#ifdef CONFIG_SECURE_DAME_HANDLING
+ get $r44 = $ilr
+ make $r45 = SFR_CLEAR_WFXL(ILR, IT16);
+ ;;
+ /* Extract $ilr.dame bit */
+ extfz $r44 = $r44, KVX_SFR_END(ILR_IT16), KVX_SFR_START(ILR_IT16)
+ /* Save $ilr value */
+ sd PT_ILR[$r36] = $r44
+ /* Clear $ilr.dame */
+ wfxl $ilr = $r45
+ ;;
+#endif
+ so PT_CS_SPC_SPS_ES[$r36] = $r40r41r42r43
+ get $r61 = $le
+ make $r43 = 0x0
+ ;;
+ /* Reenable hardware loops, IT, exceptions and disable DAUS */
+ make $r44 = PS_HLE_EN_IT_EN_ET_CLEAR_DAUS_DIS
+ get $r62 = $ls
+ /* Save regs r4 -> r7 in pt_regs for restart & trace if needed */
+ so PT_Q4[$r36] = $r4r5r6r7
+ ;;
+ /* Clear $le on entry */
+ set $le = $r43
+ /* Save hw loop stuff */
+ so PT_LC_LE_LS_RA[$r36] = $r60r61r62r63
+ /* Clear frame pointer for kernel */
+ make $fp = 0
+ ;;
+ /* Enable hwloop and interrupts and MMU
+ * Note that we have to reenable interrupts after saving context
+ * to avoid losing registers content */
+ wfxl $ps, $r44
+ ;;
+ /* Do we have to trace the syscall ? */
+ cb.dnez $r37? trace_syscall_enter
+ /* Stroe original r0 value */
+ sd PT_ORIG_R0[$sp] = $r0
+ ;;
+do_syscall:
+ /* Call the syscall handler */
+ icall $r38
+ ;;
+ /*
+ * rt_sigreturn syscall will not take this exit path (see
+ * sys_rt_sigreturn for more information).
+ */
+ /* Reload task flags since the syscall might have generated a signal*/
+ get $r36 = $sr
+ ;;
+#ifdef CONFIG_SECURE_DAME_HANDLING
+ /* Barrier to force DAME interrupt to be generated if any pending */
+ barrier
+ ;;
+#endif
+ /* Disable interrupt to check task flags atomically */
+ disable_interrupt $r60
+ ;;
+ ld $r38 = TASK_TI_FLAGS[$r36]
+ ;;
+ andd $r37 = $r38, _TIF_SYSCALL_WORK
+ ;;
+ /* Save r0 which was returned from do_scall previously and
+ * will be cloberred by do_work_pending(and potentially
+ * do_syscall_trace_exit if tracing is enabled)
+ * If do_signal is called and that syscall is restarted,
+ * it will be modified by handle_restart to restore original
+ * r0 value
+ */
+ sd PT_Q0[$sp] = $r0
+ /* used to store if trace system */
+ cb.dnez $r37? trace_syscall_exit
+ ;;
+check_work_pending:
+ /* Do we have work pending ? */
+ andd $r1 = $r38, _TIF_WORK_MASK
+ ;;
+ /* If no work pending, directly continue to ret_to_user */
+ cb.dnez $r1? call_work_pending
+ ;;
+ret_to_user:
+ disable_mmu $r60, PS_HWLOOP_DISABLE
+ ;;
+ /* Compute $sp virtual address to avoid using 64 bits offset */
+ addd $r15 = $sp, VA_TO_PA_OFFSET
+ ;;
+ /* Restore registers */
+ lo $r60r61r62r63 = PT_LC_LE_LS_RA[$r15]
+ get $r33 = $sps
+ ;;
+ lo $r40r41r42r43 = PT_CS_SPC_SPS_ES[$r15];
+ set $ra = $r63
+ ;;
+ /* Restore syscall arguments since they might be needed for
+ * syscall restart
+ */
+ lo $r0r1r2r3 = PT_Q0[$r15]
+ set $cs = $r40
+ /* Generate a mask of ones at each bit where the current $sps
+ * differs from the $sps to be restored
+ */
+ xord $r33 = $r42, $r33
+ /* prepare wfxl clear mask on LSBs */
+ notd $r34 = $r42
+ /* prepare wfxl set mask on MSBs */
+ slld $r35 = $r42, 32
+ ;;
+ set $lc = $r60
+ /* Replicate mask of ones on the 32 MSBs */
+ sbmm8 $r33 = $r33, REPLICATE_32_MASK
+ /* Combine the set and clear mask for wfxl */
+ insf $r35 = $r34, 31, 0
+ ;;
+ lo $r4r5r6r7 = PT_Q4[$r15]
+ set $le = $r61
+ /* Mask to drop identical bits in order to avoid useless
+ * privilege traps
+ */
+ andd $r35 = $r35, $r33
+ ;;
+ /* Restore $ilr */
+ ld $r44 = PT_ILR[$r15]
+ set $ls = $r62
+ /* Reenable MMU in $sps */
+ ord $r35 = $r35, SFR_SET_VAL_WFXL(SPS, MME, 1)
+ ;;
+ /* Restore user pointer */
+ lo $r12r13r14r15 = PT_Q12[$r15]
+ /* Prepare $r44 as a set mask for $ilr wfxl */
+ slld $r44 = $r44, 32
+ ;;
+ /**
+ * wfxl on $ilr to avoid privilege traps when restoring with set
+ * Note that we do that after disabling interrupt since we explicitly
+ * want to serve DAME itnerrupt to the user (ie not in kernel mode).
+ */
+ wfxl $ilr = $r44
+ ;;
+ wfxl $sps = $r35
+ ;;
+ set $spc = $r41
+ ;;
+ /* TODO: we might have to clear some registers to avoid leaking
+ * information to user space ! callee saved regs have been
+ * restored by called function but caller saved regs might
+ * have been used without being cleared */
+ rfe
+ ;;
+
+/* Slow paths handling */
+call_work_pending:
+ /*
+ * Work pending can potentially call a signal handler and then return
+ * via rt_sigreturn. Return path will be different (restore all regs)
+ * and hence all registers are needed to be saved.
+ */
+ save_callee
+ ;;
+ call_do_work_pending
+ ;;
+ /* Since we are returning to user, interrupts will be reenabled */
+ call_trace_hardirqs on
+ ;;
+ goto ret_to_user
+ ;;
+
+trace_syscall_enter:
+ /* Save $r38 (syscall handler) which was computed above */
+ sd PT_R38[$sp] = $r38
+ ;;
+ /* do_syscall_trace_enter expect pt_regs and syscall number
+ * as argument */
+ copyd $r0 = $sp
+ copyd $r1 = $r32
+ ;;
+ call do_syscall_trace_enter
+ ;;
+ /* Restore r38 (syscall handler) which might has been clobbered by
+ * do_syscall_trace_enter */
+ ld $r38 = PT_R38[$sp]
+ ;;
+ /* if the trace system requested to abort syscall, set $r38 to
+ * non implemented syscall */
+ cmoved.dnez $r0? $r38 = sys_ni_syscall
+ ;;
+ /* Restore registers since the do_syscall_trace_enter call might
+ * have clobbered them and we need them for the actual syscall
+ * call */
+ lo $r0r1r2r3 = PT_Q0[$sp]
+ ;;
+ lo $r4r5r6r7 = PT_Q4[$sp]
+ ;;
+ goto do_syscall
+ ;;
+trace_syscall_exit:
+ copyd $r0 = $sp
+ call do_syscall_trace_exit
+ ;;
+ /* ptrace_notify might re-enable interrupts, disable them to be sure
+ * it will not mess up context restoration path */
+ disable_interrupt $r36
+ ;;
+ get $r36 = $sr
+ ;;
+ ld $r38 = TASK_TI_FLAGS[$r36]
+ goto check_work_pending
+ ;;
+ENDPROC(kvx_syscall_handler)
+
+.text
+/**
+ * sys_rt_sigreturn: Special handler for sigreturn
+ * rt_sigreturn is called after invoking a user signal handler (see
+ * user_scall_rt_sigreturn). Since this signal handler can be invoked after
+ * interrupts have been handled, this means we must restore absolutely all user
+ * registers. Normally, this has been done by setup_sigcontext which saved all
+ * user registers on the user stack.
+ * In restore sigcontext, they have been restored onto entry stack (stack to be
+ * restored). However, the standard syscall path do not restore it completely
+ * since only callee-saved registers are restored for fork and al.
+ * Here, we will restore all registers which might have been cloberred.
+ */
+ENTRY(sys_rt_sigreturn)
+ /*
+ * If syscall tracing is enable (stored in $r37 during syscall
+ * fastpath), tail-call to trace_exit. If not, tail-call to
+ * ret_from_kernel.
+ */
+ cmoved.dnez $r37? $r38 = scall_trace_exit
+ cmoved.deqz $r37? $r38 = ret_from_kernel
+ ;;
+ set $ra = $r38
+ ;;
+ goto _sys_rt_sigreturn
+ ;;
+scall_trace_exit:
+ copyd $r0 = $sp
+ call do_syscall_trace_exit
+ ;;
+ goto ret_from_kernel
+ ;;
+ENDPROC(sys_rt_sigreturn)
+
+/**
+ * __sys_clone: slow path handler for clone
+ *
+ * Save callee registers (from $r18 to $31) since they are needed for
+ * child process when restoring it.
+ * Indeed, when forking we want it to have the same registers contents
+ * as its parent. These registers will then be restored in
+ * ret_from_fork.
+ * This slow path saves them out of the fast path to avoid bloating all syscall
+ * just for one special case.
+ */
+ENTRY(__sys_clone)
+ save_callee
+ ;;
+ /*
+ * Use goto since we want sys_clone to "ret" to the previous caller.
+ * This allows to simply go back in the normal syscall fastpath
+ */
+ goto sys_clone
+ ;;
+ENDPROC(__sys_clone)
+/***********************************************************************
+* Context switch
+***********************************************************************/
+
+#define SAVE_TCA_REG(__reg_num, __task_reg, __zero_reg1, __zero_reg2) \
+ xso (CTX_SWITCH_TCA_REGS + (__reg_num * TCA_REG_SIZE))[__task_reg] = \
+ $a##__reg_num ;\
+ movetq $a##__reg_num##.lo = __zero_reg1, __zero_reg2 ;\
+ movetq $a##__reg_num##.hi = __zero_reg1, __zero_reg2 ;\
+ ;;
+
+.macro save_tca_regs task_reg zero_reg1 zero_reg2
+ SAVE_TCA_REG(0, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(1, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(2, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(3, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(4, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(5, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(6, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(7, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(8, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(9, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(10, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(11, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(12, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(13, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(14, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(15, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(16, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(17, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(18, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(19, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(20, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(21, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(22, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(23, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(24, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(25, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(26, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(27, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(28, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(29, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(30, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(31, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(32, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(33, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(34, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(35, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(36, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(37, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(38, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(39, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(40, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(41, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(42, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(43, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(44, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(45, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(46, \task_reg, \zero_reg1, \zero_reg2)
+ SAVE_TCA_REG(47, \task_reg, \zero_reg1, \zero_reg2)
+.endm
+
+#define RESTORE_TCA_REG(__reg_num, __task_reg) \
+ xlo.u $a##__reg_num = (CTX_SWITCH_TCA_REGS + (__reg_num * TCA_REG_SIZE)) \
+ [__task_reg] ;\
+ ;;
+
+.macro restore_tca_regs task_reg
+ RESTORE_TCA_REG(0, \task_reg)
+ RESTORE_TCA_REG(1, \task_reg)
+ RESTORE_TCA_REG(2, \task_reg)
+ RESTORE_TCA_REG(3, \task_reg)
+ RESTORE_TCA_REG(4, \task_reg)
+ RESTORE_TCA_REG(5, \task_reg)
+ RESTORE_TCA_REG(6, \task_reg)
+ RESTORE_TCA_REG(7, \task_reg)
+ RESTORE_TCA_REG(8, \task_reg)
+ RESTORE_TCA_REG(9, \task_reg)
+ RESTORE_TCA_REG(10, \task_reg)
+ RESTORE_TCA_REG(11, \task_reg)
+ RESTORE_TCA_REG(12, \task_reg)
+ RESTORE_TCA_REG(13, \task_reg)
+ RESTORE_TCA_REG(14, \task_reg)
+ RESTORE_TCA_REG(15, \task_reg)
+ RESTORE_TCA_REG(16, \task_reg)
+ RESTORE_TCA_REG(17, \task_reg)
+ RESTORE_TCA_REG(18, \task_reg)
+ RESTORE_TCA_REG(19, \task_reg)
+ RESTORE_TCA_REG(20, \task_reg)
+ RESTORE_TCA_REG(21, \task_reg)
+ RESTORE_TCA_REG(22, \task_reg)
+ RESTORE_TCA_REG(23, \task_reg)
+ RESTORE_TCA_REG(24, \task_reg)
+ RESTORE_TCA_REG(25, \task_reg)
+ RESTORE_TCA_REG(26, \task_reg)
+ RESTORE_TCA_REG(27, \task_reg)
+ RESTORE_TCA_REG(28, \task_reg)
+ RESTORE_TCA_REG(29, \task_reg)
+ RESTORE_TCA_REG(30, \task_reg)
+ RESTORE_TCA_REG(31, \task_reg)
+ RESTORE_TCA_REG(32, \task_reg)
+ RESTORE_TCA_REG(33, \task_reg)
+ RESTORE_TCA_REG(34, \task_reg)
+ RESTORE_TCA_REG(35, \task_reg)
+ RESTORE_TCA_REG(36, \task_reg)
+ RESTORE_TCA_REG(37, \task_reg)
+ RESTORE_TCA_REG(38, \task_reg)
+ RESTORE_TCA_REG(39, \task_reg)
+ RESTORE_TCA_REG(40, \task_reg)
+ RESTORE_TCA_REG(41, \task_reg)
+ RESTORE_TCA_REG(42, \task_reg)
+ RESTORE_TCA_REG(43, \task_reg)
+ RESTORE_TCA_REG(44, \task_reg)
+ RESTORE_TCA_REG(45, \task_reg)
+ RESTORE_TCA_REG(46, \task_reg)
+ RESTORE_TCA_REG(47, \task_reg)
+.endm
+
+.text
+/*
+ * When entering in ret_from_kernel_thread, r20 and r21 where set by
+ * copy_thread and have been restored in switch_to.
+ * These registers contains the values needed to call a function
+ * specified by the switch_to caller (or where set by copy_thread).
+ */
+ENTRY(ret_from_kernel_thread)
+ call schedule_tail
+ ;;
+ /* Call fn(arg) */
+ copyd $r0 = $r21
+ ;;
+ icall $r20
+ ;;
+ goto ret_from_kernel
+ ;;
+ENDPROC(ret_from_kernel_thread)
+
+/**
+ * Return from fork.
+ * start_thread will set return stack and pc. Then copy_thread will
+ * take care of the copying logic.
+ * $r20 will then contains 0 if tracing disabled (set by copy_thread)
+ * The mechanism is almost the same as for ret_from_kernel_thread.
+ */
+ENTRY(ret_from_fork)
+ call schedule_tail
+ ;;
+ /* $r20 contains 0 if tracing disable */
+ cb.deqz $r20? ret_from_kernel
+ ;;
+ copyd $r0 = $sp
+ call do_syscall_trace_exit
+ ;;
+ret_from_kernel:
+ /*
+ * When returning from a fork, the child will take this path.
+ * Since we did not restore callee in return_from_exception, we
+ * must do it before.
+ */
+ lo $r28r29r30r31 = PT_Q28[$sp]
+ ;;
+ lo $r24r25r26r27 = PT_Q24[$sp]
+ ;;
+ lo $r20r21r22r23 = PT_Q20[$sp]
+ ;;
+ lq $r18r19 = PT_R18R19[$sp]
+ ;;
+#ifdef CONFIG_DEBUG_EXCEPTION_STACK
+ /**
+ * Debug code expect entry stack to be stored at current $sp.
+ * Make some room and store current $sp to avoid triggering false alarm.
+ */
+ addd $sp = $sp, -STACK_REG_SIZE
+ ;;
+ sd 0[$sp] = $sp
+#endif
+ ;;
+ goto return_from_exception
+ ;;
+ENDPROC(ret_from_fork)
+
+/*
+ * The callee-saved registers must be saved and restored.
+ * When entering:
+ * - r0 = previous task struct
+ * - r1 = next task struct
+ * Moreover, the parameters for function call (given by copy_thread)
+ * are stored in:
+ * - r20 = Func to call
+ * - r21 = Argument for function
+ */
+ENTRY(__switch_to)
+ sd CTX_SWITCH_FP[$r0] = $fp
+ ;;
+ /* Save previous task context */
+ so CTX_SWITCH_Q20[$r0] = $r20r21r22r23
+ ;;
+ so CTX_SWITCH_Q24[$r0] = $r24r25r26r27
+ get $r16 = $ra
+ ;;
+ so CTX_SWITCH_Q28[$r0] = $r28r29r30r31
+ copyd $r17 = $sp
+ get $r2 = $cs
+ ;;
+ so CTX_SWITCH_RA_SP_R18_R19[$r0] = $r16r17r18r19
+ /* Extract XMF bit which means coprocessor was used by user */
+ andd $r3 = $r2, KVX_SFR_CS_XMF_MASK
+ ;;
+#ifdef CONFIG_ENABLE_TCA
+ make $r4 = 0
+ make $r5 = 0
+ make $r6 = 1
+ cb.dnez $r3? save_tca_registers
+ /* Check if next task needs TCA registers to be restored */
+ ld $r7 = CTX_SWITCH_TCA_REGS_SAVED[$r1]
+ ;;
+check_restore_tca:
+ cb.dnez $r7? restore_tca_registers
+ ;;
+restore_fast_path:
+#endif
+ /* Restore next task context */
+ lo $r16r17r18r19 = CTX_SWITCH_RA_SP_R18_R19[$r1]
+ ;;
+ lo $r20r21r22r23 = CTX_SWITCH_Q20[$r1]
+ ;;
+ lo $r24r25r26r27 = CTX_SWITCH_Q24[$r1]
+ copyd $sp = $r17
+ set $ra = $r16
+ ;;
+ lo $r28r29r30r31 = CTX_SWITCH_Q28[$r1]
+ set $sr = $r1
+ ;;
+ ld $fp = CTX_SWITCH_FP[$r1]
+ ;;
+ ret
+ ;;
+#ifdef CONFIG_ENABLE_TCA
+save_tca_registers:
+ save_tca_regs $r0 $r4 $r5
+ ;;
+ /* Indicates that we saved the TCA context */
+ sb CTX_SWITCH_TCA_REGS_SAVED[$r0] = $r6
+ goto check_restore_tca
+ ;;
+restore_tca_registers:
+ restore_tca_regs $r1
+ ;;
+ /* Clear TCA registers saved hint */
+ sb CTX_SWITCH_TCA_REGS_SAVED[$r1] = $r5
+ goto restore_fast_path
+ ;;
+#endif
+ENDPROC(__switch_to)
+
+/***********************************************************************
+* Misc functions
+***********************************************************************/
+
+/**
+ * Avoid hardcoding trampoline for rt_sigreturn by using this code and
+ * copying it on user trampoline
+ */
+.pushsection .text
+.global user_scall_rt_sigreturn_end
+ENTRY(user_scall_rt_sigreturn)
+ make $r6 = __NR_rt_sigreturn
+ ;;
+ scall $r6
+ ;;
+user_scall_rt_sigreturn_end:
+ENDPROC(user_scall_rt_sigreturn)
+.popsection
diff --git a/arch/kvx/kernel/sys_kvx.c b/arch/kvx/kernel/sys_kvx.c
new file mode 100644
index 000000000000..b32a821d76c9
--- /dev/null
+++ b/arch/kvx/kernel/sys_kvx.c
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Clement Leger
+ * Guillaume Thouvenin
+ */
+
+#include <linux/syscalls.h>
+
+#include <asm/cacheflush.h>
+#include <asm/cachectl.h>
+
+SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len,
+ unsigned long, prot, unsigned long, flags,
+ unsigned long, fd, off_t, off)
+{
+ /* offset must be a multiple of the page size */
+ if (unlikely(offset_in_page(off) != 0))
+ return -EINVAL;
+
+ /* Unlike mmap2 where the offset is in PAGE_SIZE-byte units, here it
+ * is in bytes. So we need to use PAGE_SHIFT.
+ */
+ return ksys_mmap_pgoff(addr, len, prot, flags, fd, off >> PAGE_SHIFT);
+}
+
+SYSCALL_DEFINE4(cachectl, unsigned long, addr, unsigned long, len,
+ unsigned long, cache, unsigned long, flags)
+{
+ bool wb = !!(flags & CACHECTL_FLAG_OP_WB);
+ bool inval = !!(flags & CACHECTL_FLAG_OP_INVAL);
+
+ if (len == 0)
+ return 0;
+
+ /* Check for overflow */
+ if (addr + len < addr)
+ return -EFAULT;
+
+ if (cache != CACHECTL_CACHE_DCACHE)
+ return -EINVAL;
+
+ if ((flags & CACHECTL_FLAG_OP_MASK) == 0)
+ return -EINVAL;
+
+ if (flags & CACHECTL_FLAG_ADDR_PHYS) {
+ if (!IS_ENABLED(CONFIG_CACHECTL_UNSAFE_PHYS_OPERATIONS))
+ return -EINVAL;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ dcache_wb_inval_phys_range(addr, len, wb, inval);
+ return 0;
+ }
+
+ return dcache_wb_inval_virt_range(addr, len, wb, inval);
+}
diff --git a/arch/kvx/kernel/syscall_table.c b/arch/kvx/kernel/syscall_table.c
new file mode 100644
index 000000000000..7859d25e728d
--- /dev/null
+++ b/arch/kvx/kernel/syscall_table.c
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * derived from arch/riscv/kernel/syscall_table.c
+ *
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Clement Leger
+ */
+
+#include <linux/syscalls.h>
+
+#include <asm/syscalls.h>
+
+#undef __SYSCALL
+#define __SYSCALL(nr, call) [nr] = (call),
+
+void *sys_call_table[__NR_syscalls] = {
+ [0 ... __NR_syscalls - 1] = sys_ni_syscall,
+#include <asm/unistd.h>
+};
--
2.37.2





2023-01-03 17:48:06

by Yann Sionneau

[permalink] [raw]
Subject: [RFC PATCH 07/25] kvx: Add boot and setup routines

Add basic boot, setup and reset routines for kvx.

CC: [email protected]
Co-developed-by: Alex Michon <[email protected]>
Signed-off-by: Alex Michon <[email protected]>
Co-developed-by: Clement Leger <[email protected]>
Signed-off-by: Clement Leger <[email protected]>
Co-developed-by: Guillaume Missonnier <[email protected]>
Signed-off-by: Guillaume Missonnier <[email protected]>
Co-developed-by: Guillaume Thouvenin <[email protected]>
Signed-off-by: Guillaume Thouvenin <[email protected]>
Co-developed-by: Jules Maselbas <[email protected]>
Signed-off-by: Jules Maselbas <[email protected]>
Co-developed-by: Julian Vetter <[email protected]>
Signed-off-by: Julian Vetter <[email protected]>
Co-developed-by: Julien Hascoet <[email protected]>
Signed-off-by: Julien Hascoet <[email protected]>
Co-developed-by: Julien Villette <[email protected]>
Signed-off-by: Julien Villette <[email protected]>
Co-developed-by: Marc Poulhiès <[email protected]>
Signed-off-by: Marc Poulhiès <[email protected]>
Co-developed-by: Luc Michel <[email protected]>
Signed-off-by: Luc Michel <[email protected]>
Co-developed-by: Marius Gligor <[email protected]>
Signed-off-by: Marius Gligor <[email protected]>
Co-developed-by: Yann Sionneau <[email protected]>
Signed-off-by: Yann Sionneau <[email protected]>
---
arch/kvx/include/asm/setup.h | 29 ++
arch/kvx/kernel/common.c | 11 +
arch/kvx/kernel/head.S | 612 +++++++++++++++++++++++++++++++++++
arch/kvx/kernel/prom.c | 24 ++
arch/kvx/kernel/reset.c | 37 +++
arch/kvx/kernel/setup.c | 178 ++++++++++
arch/kvx/kernel/time.c | 242 ++++++++++++++
7 files changed, 1133 insertions(+)
create mode 100644 arch/kvx/include/asm/setup.h
create mode 100644 arch/kvx/kernel/common.c
create mode 100644 arch/kvx/kernel/head.S
create mode 100644 arch/kvx/kernel/prom.c
create mode 100644 arch/kvx/kernel/reset.c
create mode 100644 arch/kvx/kernel/setup.c
create mode 100644 arch/kvx/kernel/time.c

diff --git a/arch/kvx/include/asm/setup.h b/arch/kvx/include/asm/setup.h
new file mode 100644
index 000000000000..9c27d5981442
--- /dev/null
+++ b/arch/kvx/include/asm/setup.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Clement Leger
+ */
+
+#ifndef _ASM_KVX_SETUP_H
+#define _ASM_KVX_SETUP_H
+
+#include <linux/const.h>
+
+#include <asm-generic/setup.h>
+
+/* Magic is found in r0 when some parameters are given to kernel */
+#define LINUX_BOOT_PARAM_MAGIC ULL(0x31564752414E494C)
+
+#ifndef __ASSEMBLY__
+
+void early_fixmap_init(void);
+
+void setup_device_tree(void);
+
+void setup_arch_memory(void);
+
+void kvx_init_mmu(void);
+
+#endif
+
+#endif /* _ASM_KVX_SETUP_H */
diff --git a/arch/kvx/kernel/common.c b/arch/kvx/kernel/common.c
new file mode 100644
index 000000000000..322498f034fd
--- /dev/null
+++ b/arch/kvx/kernel/common.c
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Clement Leger
+ */
+
+#include <linux/percpu-defs.h>
+#include <linux/sched/task.h>
+
+DEFINE_PER_CPU(int, __preempt_count) = INIT_PREEMPT_COUNT;
+EXPORT_PER_CPU_SYMBOL(__preempt_count);
diff --git a/arch/kvx/kernel/head.S b/arch/kvx/kernel/head.S
new file mode 100644
index 000000000000..ab9848500f39
--- /dev/null
+++ b/arch/kvx/kernel/head.S
@@ -0,0 +1,612 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Clement Leger
+ * Guillaume Thouvenin
+ * Marius Gligor
+ * Julian Vetter
+ * Julien Hascoet
+ * Yann Sionneau
+ * Marc Poulhiès
+ */
+#include <asm/thread_info.h>
+#include <asm/page_size.h>
+#include <asm/pwr_ctrl.h>
+#include <asm/sfr_defs.h>
+#include <asm/sys_arch.h>
+#include <asm/privilege.h>
+#include <asm/tlb_defs.h>
+#include <asm/mem_map.h>
+#include <asm/rm_fw.h>
+#include <asm/setup.h>
+#include <asm/page.h>
+
+#include <linux/linkage.h>
+#include <linux/init.h>
+
+#ifdef CONFIG_SMP
+#define SECONDARY_START_ADDR smp_secondary_start
+#else
+#define SECONDARY_START_ADDR proc_power_off
+#endif
+
+#define PS_VAL_WFXL(__field, __val) \
+ SFR_SET_VAL_WFXL(PS, __field, __val)
+
+#define PS_WFXL_VALUE PS_VAL_WFXL(HLE, 1) | \
+ PS_VAL_WFXL(USE, 1) | \
+ PS_VAL_WFXL(DCE, 1) | \
+ PS_VAL_WFXL(ICE, 1) | \
+ PS_VAL_WFXL(MME, 1) | \
+ PS_VAL_WFXL(MMUP, 1) | \
+ PS_VAL_WFXL(ET, 0) | \
+ PS_VAL_WFXL(HTD, 0) | \
+ PS_VAL_WFXL(PMJ, KVX_SUPPORTED_PSIZE)
+
+#define PCR_VAL_WFXM(__field, __val) \
+ SFR_SET_VAL_WFXM(PCR, __field, __val)
+
+#define PCR_WFXM_VALUE PCR_VAL_WFXM(L1CE, 1)
+
+/* 30 sec for primary watchdog timeout */
+#define PRIMARY_WATCHDOG_VALUE (30000000000UL)
+
+#define TCR_WFXL_VALUE SFR_SET_VAL_WFXL(TCR, WUI, 1) | \
+ SFR_SET_VAL_WFXL(TCR, WCE, 1)
+
+/* Enable STOP in WS */
+#define WS_ENABLE_WU2 (KVX_SFR_WS_WU2_MASK)
+/* We only want to clear bits in ws */
+#define WS_WFXL_VALUE (WS_ENABLE_WU2)
+
+/* SMP stuff */
+#define RM_PID_MASK ((KVX_RM_ID) << KVX_SFR_PCR_PID_SHIFT)
+
+#define PWR_CTRL_ADDR 0xA40000
+
+#define PWR_CTRL_GLOBAL_CONFIG_VALUE \
+ (1 << KVX_PWR_CTRL_GLOBAL_SET_PE_EN_SHIFT)
+
+/* Clean error and selected buffer */
+#define MMC_CLEAR_ERROR (KVX_SFR_MMC_E_MASK)
+
+#define TEH_VIRTUAL_MEMORY \
+ TLB_MK_TEH_ENTRY(PAGE_OFFSET, 0, TLB_G_GLOBAL, 0)
+
+#define TEL_VIRTUAL_MEMORY \
+ TLB_MK_TEL_ENTRY(PHYS_OFFSET, TLB_PS_512M, TLB_ES_A_MODIFIED,\
+ TLB_CP_W_C, TLB_PA_NA_RWX)
+
+/* (TEH|TEL)_SHARED_MEMORY are mapping 0x0 to 0x0 */
+#define TEH_SHARED_MEMORY \
+ TLB_MK_TEH_ENTRY(0, 0, TLB_G_GLOBAL, 0)
+
+#define TEL_SHARED_MEMORY \
+ TLB_MK_TEL_ENTRY(0, TLB_PS_2M, TLB_ES_A_MODIFIED,\
+ TLB_CP_W_C, TLB_PA_NA_RWX)
+
+#define TEH_GDB_PAGE_MEMORY \
+ TLB_MK_TEH_ENTRY(0, 0, TLB_G_GLOBAL, 0)
+
+#define TEL_GDB_PAGE_MEMORY \
+ TLB_MK_TEL_ENTRY(0, TLB_PS_4K, TLB_ES_A_MODIFIED,\
+ TLB_CP_U_U, TLB_PA_RWX_RWX)
+
+/**
+ * Macros
+ */
+.altmacro
+
+/* To select the JTLB we clear SB from MMC */
+.macro select_jtlb scratch_reg
+ make \scratch_reg, KVX_SFR_MMC_SB_MASK
+ ;;
+ wfxl $mmc, \scratch_reg
+.endm
+
+/* To select the LTLB we set SB from MMC */
+.macro select_ltlb scratch_reg
+ make \scratch_reg, KVX_SFR_MMC_SB_MASK << 32
+ ;;
+ wfxl $mmc, \scratch_reg
+.endm
+
+/* Set SW of the MMC with number found in the reg register */
+.macro select_way_from_register reg scratch1 scratch2
+ slld \scratch1 = \reg, KVX_SFR_MMC_SW_SHIFT
+ make \scratch2 = KVX_SFR_MMC_SW_MASK
+ ;;
+ slld \scratch1 = \scratch1, 32
+ ;;
+ ord \scratch1 = \scratch1, \scratch2
+ ;;
+ wfxl $mmc = \scratch1
+.endm
+
+/* Set SW of the MMC with the immediate */
+.macro select_way_from_immediate imm scratch1 scratch2
+ make \scratch1 = (\imm << KVX_SFR_MMC_SW_SHIFT) << 32
+ make \scratch2 = KVX_SFR_MMC_SW_MASK
+ ;;
+ ord \scratch1 = \scratch1, \scratch2
+ ;;
+ wfxl $mmc = \scratch1
+.endm
+
+/* write tlb after setting teh and tel registers */
+.macro write_tlb_entry teh tel
+ set $teh = \teh
+ ;;
+ set $tel = \tel
+ ;;
+ tlbwrite
+.endm
+
+/* Boot args */
+#define BOOT_ARGS_COUNT 2
+.align 16
+.section .boot.data, "aw", @progbits
+rm_boot_args:
+.skip BOOT_ARGS_COUNT * 8
+
+/*
+ * This is our entry point. When entering from bootloader,
+ * the following registers are set:
+ * $r0 is a magic (LINUX_BOOT_PARAM_MAGIC)
+ * $r1 device tree pointer
+ *
+ * WARNING WARNING WARNING
+ * ! DO NOT CLOBBER THEM !
+ * WARNING WARNING WARNING
+ *
+ * Try to use register above $r20 to ease parameter adding in future
+ */
+
+__HEAD
+
+.align 8
+.section .boot.startup, "ax", @progbits
+
+ENTRY(kvx_start)
+ /* Setup 64 bit really early to avoid bugs */
+ make $r21 = PS_VAL_WFXL(V64, 1)
+ ;;
+ wfxl $ps = $r21
+ ;;
+ call asm_init_pl
+ ;;
+ get $r20 = $pcr
+ ;;
+ andd $r21 = $r20, RM_PID_MASK
+ ;;
+ cb.dnez $r21 ? asm_rm_cfg_pwr_ctrl
+ ;;
+init_core:
+ /**
+ * Setup watchdog early to catch potential
+ * crash before watchdog driver probe
+ */
+ make $r25 = PRIMARY_WATCHDOG_VALUE
+ make $r26 = TCR_WFXL_VALUE
+ ;;
+ set $wdv = $r25
+ ;;
+ wfxl $tcr, $r26
+ ;;
+ call asm_init_mmu
+ ;;
+ /* Setup default processor status */
+ make $r25 = PS_WFXL_VALUE
+ make $r26 = PCR_WFXM_VALUE
+ ;;
+ /**
+ * There is nothing much we can do if we take a early trap since the
+ * kernel is not yet ready to handle them.
+ * Register this as the early exception handler to at least avoid
+ * going in a black hole.
+ */
+ make $r27 = __early_exception_start
+ ;;
+ set $ev = $r27
+ ;;
+ wfxm $pcr = $r26
+ ;;
+ wfxl $ps = $r25
+ ;;
+ /* Use as break point for debugging purpose.
+ See Documentation/kvx/kvx.txt for more details. */
+gdb_mmu_enabled:
+ /* Extract processor identifier */
+ get $r24 = $pcr
+ ;;
+ extfz $r24 = $r24, KVX_SFR_END(PCR_PID), KVX_SFR_START(PCR_PID)
+ ;;
+ /* If proc 0, then go to clear bss and do normal boot */
+ cb.deqz $r24? clear_bss
+ make $r25 = SECONDARY_START_ADDR
+ ;;
+ icall $r25
+ ;;
+clear_bss:
+ /* Copy bootloader arguments before cloberring them */
+ copyd $r20 = $r0
+ copyd $r21 = $r1
+ ;;
+ /* Clear BSS */
+ make $r0 = __bss_start
+ make $r1 = __bss_stop
+ call asm_memzero
+ ;;
+ /* Setup stack */
+ make $r40 = init_thread_union
+ make $r41 = init_task
+ ;;
+ set $sr = $r41
+ copyd $r0 = $r20
+ copyd $r1 = $r21
+ ;;
+ addd $sp = $r40, THREAD_SIZE
+ /* Clear frame pointer */
+ make $fp = 0x0
+ /* Setup the exception handler */
+ make $r27 = __exception_start
+ ;;
+ set $ev = $r27
+ /* Here we go ! start the C stuff */
+ make $r20 = arch_low_level_start
+ ;;
+ icall $r20
+ ;;
+ make $r20 = proc_power_off
+ ;;
+ igoto $r20
+ ;;
+ENDPROC(kvx_start)
+
+/**
+ * When PE 0 is started from the RM, arguments from the bootloaders are copied
+ * into rm_boot_args. It allows to give parameters from RM to PE.
+ * Note that the 4K alignment is required by the reset pc register...
+ */
+.align (4 * 1024)
+ENTRY(pe_start_wrapper)
+ make $r0 = rm_boot_args
+ make $r27 = PWR_CTRL_ADDR
+ make $r28 = kvx_start
+ ;;
+ lq $r0r1 = 0[$r0]
+ ;;
+ /* Set reset PC back to original value for SMP start */
+ sd KVX_PWR_CTRL_RESET_PC_OFFSET[$r27] = $r28
+ ;;
+ fence
+ goto kvx_start
+ ;;
+ENDPROC(pe_start_wrapper)
+
+/**
+ * asm_memzero - Clear a memory zone with zeroes
+ * $r0 is the start of memory zone (must be align on 32 bytes boundary)
+ * $r1 is the end of memory zone (must be align on 32 bytes boundary)
+ */
+ENTRY(asm_memzero)
+ sbfd $r32 = $r0, $r1
+ make $r36 = 0
+ make $r37 = 0
+ ;;
+ make $r38 = 0
+ make $r39 = 0
+ /* Divide by 32 for hardware loop */
+ srld $r32, $r32, 5
+ ;;
+ /* Clear memory with hardware loop */
+ loopdo $r32, clear_mem_done
+ ;;
+ so 0[$r0] = $r36r37r38r39
+ addd $r0 = $r0, 32
+ ;;
+ clear_mem_done:
+ ret
+ ;;
+ENDPROC(asm_memzero)
+
+/**
+ * Configure the power controller to be accessible by PEs and start the
+ * rm firmware
+ */
+ENTRY(asm_rm_cfg_pwr_ctrl)
+ /* Enable hwloop for memzero */
+ make $r32 = PS_VAL_WFXL(HLE, 1)
+ ;;
+ wfxl $ps = $r32
+ ;;
+ make $r26 = PWR_CTRL_ADDR
+ make $r27 = PWR_CTRL_GLOBAL_CONFIG_VALUE
+ ;;
+ /* Set PE enable in power controller */
+ sd PWR_CTRL_GLOBAL_CONFIG_OFFSET[$r26] = $r27
+ make $r28 = rm_boot_args
+ ;;
+ /* Store parameters for PE0 */
+ sq 0[$r28] = $r0r1
+ /* Copy parameters before calling asm_memzero */
+ copyd $r20 = $r0
+ copyd $r21 = $r1
+ make $r29 = pe_start_wrapper
+ ;;
+ /* Set PE reset PC to arguments wrapper */
+ sd KVX_PWR_CTRL_RESET_PC_OFFSET[$r26] = $r29
+ ;;
+ /* Fence to make sure parameters will be visible by PE 0 */
+ fence
+ ;;
+ /* Clear L2 registers */
+ make $r0 = __rm_firmware_regs_start
+ make $r1 = __rm_firmware_regs_end
+ call asm_memzero
+ ;;
+ /* Start PE 0 (1 << cpu) */
+ make $r27 = 1
+ make $r26 = PWR_CTRL_ADDR
+ ;;
+ /* Wake up PE0 */
+ sd PWR_CTRL_WUP_SET_OFFSET[$r26] = $r27
+ ;;
+ /* And clear wakeup to allow PE0 to sleep */
+ sd PWR_CTRL_WUP_CLEAR_OFFSET[$r26] = $r27
+ ;;
+ /* Restore parameters */
+ copyd $r0 = $r20
+ copyd $r1 = $r21
+ ;;
+ /* Load device tree for RM firmware */
+ make $r21 = __PA(__dtb_start)
+ /* Check if magic is in $r0, if so, device tree to use is in $r1 */
+ compd.eq $r20 = $r0, LINUX_BOOT_PARAM_MAGIC
+ ;;
+ cmoved.dnez $r20? $r21 = $r1
+ ;;
+ /* Second argument is regs size */
+ make $r1 = __rm_firmware_regs_end
+ /* First argument is regs address */
+ make $r0 = __rm_firmware_regs_start
+ ;;
+ make $r20 = __rm_firmware_start
+ /* Third argument is dtb address */
+ copyd $r2 = $r21
+ ;;
+ /* Go to firmware */
+ igoto $r20
+ ;;
+ENDPROC(asm_rm_cfg_pwr_ctrl)
+
+#define request_ownership(__pl) ;\
+ make $r21 = SYO_WFXL_VALUE_##__pl ;\
+ ;; ;\
+ wfxl $syow = $r21 ;\
+ ;; ;\
+ make $r21 = HTO_WFXL_VALUE_##__pl ;\
+ ;; ;\
+ wfxl $htow = $r21 ;\
+ ;; ;\
+ make $r21 = MO_WFXL_VALUE_##__pl ;\
+ make $r22 = MO_WFXM_VALUE_##__pl ;\
+ ;; ;\
+ wfxl $mow = $r21 ;\
+ ;; ;\
+ wfxm $mow = $r22 ;\
+ ;; ;\
+ make $r21 = ITO_WFXL_VALUE_##__pl ;\
+ make $r22 = ITO_WFXM_VALUE_##__pl ;\
+ ;; ;\
+ wfxl $itow = $r21 ;\
+ ;; ;\
+ wfxm $itow = $r22 ;\
+ ;; ;\
+ make $r21 = PSO_WFXL_VALUE_##__pl ;\
+ make $r22 = PSO_WFXM_VALUE_##__pl ;\
+ ;; ;\
+ wfxl $psow = $r21 ;\
+ ;; ;\
+ wfxm $psow = $r22 ;\
+ ;; ;\
+ make $r21 = DO_WFXL_VALUE_##__pl ;\
+ ;; ;\
+ wfxl $dow = $r21 ;\
+ ;;
+
+/**
+ * Initialize privilege level for Kernel
+ */
+ENTRY(asm_init_pl)
+ get $r21 = $ps
+ ;;
+ /* Extract privilege level from $ps to check if we need to
+ * lower our privilege level
+ */
+ extfz $r20 = $r21, KVX_SFR_END(PS_PL), KVX_SFR_START(PS_PL)
+ ;;
+ /* If our privilege level is 0, then we need to lower in execution level
+ * to ring 1 in order to let the debug routines be inserted at runtime
+ * by the JTAG. In both case, we will request the resources we need for
+ * linux to run.
+ */
+ cb.deqz $r20? delegate_pl
+ ;;
+ /*
+ * When someone is already above us, request the resources we need to
+ * run the kernel. No need to request double exception or ECC traps for
+ * instance. When doing so, the more privileged level will trap for
+ * permission and delegate us the required resources.
+ */
+ request_ownership(PL_CUR)
+ ;;
+ ret
+ ;;
+delegate_pl:
+ request_ownership(PL_CUR_PLUS_1)
+ ;;
+ /* Copy our $ps into $sps for 1:1 restoration */
+ get $r22 = $ps
+ ;;
+ /* We will return to $ra after rfe */
+ get $r21 = $ra
+ /* Set privilege level to +1 is $sps */
+ addd $r22 = $r22, PL_CUR_PLUS_1
+ ;;
+ set $spc = $r21
+ ;;
+ set $sps = $r22
+ ;;
+ rfe
+ ;;
+ENDPROC(asm_init_pl)
+
+/**
+ * Reset and initialize minimal tlb entries
+ */
+ENTRY(asm_init_mmu)
+ make $r20 = MMC_CLEAR_ERROR
+ ;;
+ wfxl $mmc = $r20
+ ;;
+ /* Reset the JTLB */
+ select_jtlb $r20
+ ;;
+ make $r20 = (MMU_JTLB_SETS - 1) /* Used to select the set */
+ make $r21 = 0 /* Used for shifting and as scratch register */
+ ;;
+ set $tel = $r21 /* tel is always equal to 0 */
+ ;;
+ clear_jtlb:
+ slld $r21 = $r20, KVX_SFR_TEH_PN_SHIFT
+ addd $r20 = $r20, -1
+ ;;
+ set $teh = $r21
+ ;;
+ make $r22 = (MMU_JTLB_WAYS - 1) /* Used to select the way */
+ ;;
+ loop_jtlb_way:
+ select_way_from_register $r22 $r23 $r24
+ ;;
+ tlbwrite
+ ;;
+ addd $r22 = $r22, -1
+ ;;
+ cb.dgez $r22? loop_jtlb_way
+ ;;
+ /* loop_jtlb_way done */
+ cb.dgez $r20? clear_jtlb
+ ;;
+ clear_jtlb_done:
+ /* Reset the LTLB */
+ select_ltlb $r20
+ ;;
+ clear_ltlb:
+ /* There is only one set that is 0 so we can reuse the same
+ values for TEH and TEL. */
+ make $r20 = (MMU_LTLB_WAYS - 1)
+ ;;
+ loop_ltlb_way:
+ select_way_from_register $r20, $r21, $r22
+ ;;
+ tlbwrite
+ ;;
+ addd $r20 = $r20, -1
+ ;;
+ cb.dgez $r20? loop_ltlb_way
+ ;;
+ clear_ltlb_done:
+
+ /* See Documentation/kvx/kvx.txt for details about the settings of
+ the LTLB */
+ select_way_from_immediate LTLB_ENTRY_KERNEL_TEXT, $r20, $r21
+ ;;
+ make $r20 = TEH_VIRTUAL_MEMORY
+ make $r21 = TEL_VIRTUAL_MEMORY
+ ;;
+ write_tlb_entry $r20, $r21
+ ;;
+ select_way_from_immediate LTLB_ENTRY_EARLY_SMEM, $r20, $r21
+ ;;
+ make $r20 = TEH_SHARED_MEMORY
+ make $r21 = TEL_SHARED_MEMORY
+ ;;
+ write_tlb_entry $r20, $r21
+ ;;
+ select_way_from_immediate LTLB_ENTRY_GDB_PAGE, $r20, $r21
+ ;;
+ make $r20 = _debug_start_lma
+ make $r21 = _debug_start
+ ;;
+ andd $r20 = $r20, KVX_SFR_TEH_PN_MASK
+ andd $r21 = $r21, KVX_SFR_TEL_FN_MASK
+ ;;
+ addd $r20 = $r20, TEH_GDB_PAGE_MEMORY
+ addd $r21 = $r21, TEL_GDB_PAGE_MEMORY
+ ;;
+ write_tlb_entry $r20, $r21
+ ;;
+ ret
+ ;;
+ENDPROC(asm_init_mmu)
+
+/**
+ * Entry point for secondary processors
+ * $r24 has been set in caller and is the proc id
+ */
+ENTRY(smp_secondary_start)
+#ifdef CONFIG_SMP
+ dinval
+ ;;
+ iinval
+ ;;
+ barrier
+ ;;
+ /* Enable L2$ in $ps since it is mandatory for SMP */
+ make $r25 = PS_VAL_WFXL(L2E, 1)
+ ;;
+ wfxl $ps = $r25
+ ;;
+ make $r25 = __cpu_up_task_pointer
+ make $r26 = __cpu_up_stack_pointer
+ ;;
+ ld.xs $sp = $r24[$r26]
+ /* Clear frame pointer */
+ make $fp = 0x0
+ ;;
+ ld.xs $r25 = $r24[$r25]
+ ;;
+ set $sr = $r25
+ make $r27 = __exception_start
+ ;;
+ set $ev = $r27
+ make $r26 = start_kernel_secondary
+ ;;
+ icall $r26
+ ;;
+#endif
+ENDPROC(smp_secondary_start)
+
+ENTRY(proc_power_off)
+ make $r1 = WS_WFXL_VALUE
+ ;;
+ /* Enable STOP */
+ wfxl $ws, $r1
+ ;;
+1: stop
+ ;;
+ goto 1b
+ ;;
+ENDPROC(proc_power_off)
+
+/**
+ * This code will be put in rm_firmware section by default.
+ * If the rm_firmware section is overridden using another firmware,
+ * this default code will be overridden.
+ */
+.section .rm_firmware.default, "ax", @progbits
+ENTRY(rm_firmware)
+ goto proc_power_off
+ ;;
+ENDPROC(rm_firmware)
diff --git a/arch/kvx/kernel/prom.c b/arch/kvx/kernel/prom.c
new file mode 100644
index 000000000000..a5241aa66903
--- /dev/null
+++ b/arch/kvx/kernel/prom.c
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Clement Leger
+ */
+
+#include <linux/of_platform.h>
+#include <linux/of_fdt.h>
+#include <linux/printk.h>
+#include <linux/init.h>
+
+void __init setup_device_tree(void)
+{
+ const char *name;
+
+ name = of_flat_dt_get_machine_name();
+ if (!name)
+ return;
+
+ pr_info("Machine model: %s\n", name);
+ dump_stack_set_arch_desc("%s (DT)", name);
+
+ unflatten_device_tree();
+}
diff --git a/arch/kvx/kernel/reset.c b/arch/kvx/kernel/reset.c
new file mode 100644
index 000000000000..afa0ceb9d7e9
--- /dev/null
+++ b/arch/kvx/kernel/reset.c
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Clement Leger
+ */
+
+#include <linux/pm.h>
+#include <linux/reboot.h>
+
+#include <asm/processor.h>
+
+static void kvx_default_power_off(void)
+{
+ smp_send_stop();
+ local_cpu_stop();
+}
+
+void (*pm_power_off)(void) = kvx_default_power_off;
+EXPORT_SYMBOL(pm_power_off);
+
+void machine_restart(char *cmd)
+{
+ smp_send_stop();
+ do_kernel_restart(cmd);
+ pr_err("Reboot failed -- System halted\n");
+ local_cpu_stop();
+}
+
+void machine_halt(void)
+{
+ pm_power_off();
+}
+
+void machine_power_off(void)
+{
+ pm_power_off();
+}
diff --git a/arch/kvx/kernel/setup.c b/arch/kvx/kernel/setup.c
new file mode 100644
index 000000000000..6be74e587dca
--- /dev/null
+++ b/arch/kvx/kernel/setup.c
@@ -0,0 +1,178 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Clement Leger
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/start_kernel.h>
+#include <linux/screen_info.h>
+#include <linux/console.h>
+#include <linux/linkage.h>
+#include <linux/export.h>
+#include <linux/of_fdt.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+
+#include <asm/processor.h>
+#include <asm/l2_cache.h>
+#include <asm/sections.h>
+#include <asm/hw_irq.h>
+#include <asm/setup.h>
+#include <asm/rm_fw.h>
+#include <asm/page.h>
+#include <asm/sfr.h>
+#include <asm/mmu.h>
+#include <asm/smp.h>
+
+struct screen_info screen_info;
+
+unsigned long memory_start;
+EXPORT_SYMBOL(memory_start);
+unsigned long memory_end;
+EXPORT_SYMBOL(memory_end);
+
+DEFINE_PER_CPU_READ_MOSTLY(struct cpuinfo_kvx, cpu_info);
+EXPORT_PER_CPU_SYMBOL(cpu_info);
+
+static bool use_streaming = true;
+static int __init parse_kvx_streaming(char *arg)
+{
+ strtobool(arg, &use_streaming);
+
+ if (!use_streaming) {
+ pr_info("disabling streaming\n");
+ kvx_sfr_set_field(PS, USE, 0);
+ }
+
+ return 0;
+}
+early_param("kvx.streaming", parse_kvx_streaming);
+
+static void __init setup_user_privilege(void)
+{
+ /*
+ * We want to let the user control various fields of ps:
+ * - hardware loop
+ * - instruction cache enable
+ * - streaming enable
+ */
+ uint64_t mask = KVX_SFR_PSOW_HLE_MASK |
+ KVX_SFR_PSOW_ICE_MASK |
+ KVX_SFR_PSOW_USE_MASK;
+
+ uint64_t value = (1 << KVX_SFR_PSOW_HLE_SHIFT) |
+ (1 << KVX_SFR_PSOW_ICE_SHIFT) |
+ (1 << KVX_SFR_PSOW_USE_SHIFT);
+
+ kvx_sfr_set_mask(PSOW, mask, value);
+}
+
+void __init setup_cpuinfo(void)
+{
+ struct cpuinfo_kvx *n = this_cpu_ptr(&cpu_info);
+ u64 pcr = kvx_sfr_get(PCR);
+
+ n->copro_enable = kvx_sfr_field_val(pcr, PCR, COE);
+ n->arch_rev = kvx_sfr_field_val(pcr, PCR, CAR);
+ n->uarch_rev = kvx_sfr_field_val(pcr, PCR, CMA);
+}
+
+/*
+ * Everything that needs to be setup PER cpu should be put here.
+ * This function will be called by per-cpu setup routine.
+ */
+void __init setup_processor(void)
+{
+ /* Clear performance monitor 0 */
+ kvx_sfr_set_field(PMC, PM0C, 0);
+
+#ifdef CONFIG_ENABLE_TCA
+ /* Enable TCA (COE = Coprocessor Enable) */
+ kvx_sfr_set_field(PCR, COE, 1);
+#else
+ kvx_sfr_set_field(PCR, COE, 0);
+#endif
+
+ /*
+ * On kvx, we have speculative accesses which differ from normal
+ * accesses by the fact their trapping policy is directed by mmc.sne
+ * (speculative no-mapping enable) and mmc.spe (speculative protection
+ * enabled).
+ * To handle these accesses properly, we disable all traps on
+ * speculative accesses while in kernel and user (sne & spe)
+ * in order to silently discard data if fetched.
+ * This allows to do an effective prefetch.
+ */
+ kvx_sfr_set_field(MMC, SNE, 0);
+ kvx_sfr_set_field(MMC, SPE, 0);
+
+ if (!use_streaming)
+ kvx_sfr_set_field(PS, USE, 0);
+
+ kvx_init_core_irq();
+
+ setup_user_privilege();
+
+ setup_cpuinfo();
+}
+
+static char builtin_cmdline[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
+
+void __init setup_arch(char **cmdline_p)
+{
+ if (builtin_cmdline[0]) {
+ /* append boot loader cmdline to builtin */
+ strlcat(builtin_cmdline, " ", COMMAND_LINE_SIZE);
+ strlcat(builtin_cmdline, boot_command_line, COMMAND_LINE_SIZE);
+ strscpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
+ }
+
+ *cmdline_p = boot_command_line;
+
+ setup_processor();
+
+ /* Jump labels needs fixmap to be setup for text modifications */
+ early_fixmap_init();
+
+ /* Parameters might set static keys */
+ jump_label_init();
+ /*
+ * Parse early param after setting up arch memory since
+ * we need fixmap for earlycon and fixedmap need to do
+ * memory allocation (fixed_range_init).
+ */
+ parse_early_param();
+
+ setup_arch_memory();
+
+ paging_init();
+
+ setup_device_tree();
+
+ smp_init_cpus();
+
+#ifdef CONFIG_VT
+ conswitchp = &dummy_con;
+#endif
+}
+
+asmlinkage __visible void __init arch_low_level_start(unsigned long r0,
+ void *dtb_ptr)
+{
+ void *dt = __dtb_start;
+
+ kvx_mmu_early_setup();
+
+ if (r0 == LINUX_BOOT_PARAM_MAGIC)
+ dt = __va(dtb_ptr);
+
+ if (!early_init_dt_scan(dt))
+ panic("Missing device tree\n");
+
+ start_kernel();
+}
diff --git a/arch/kvx/kernel/time.c b/arch/kvx/kernel/time.c
new file mode 100644
index 000000000000..f27103a1a6f4
--- /dev/null
+++ b/arch/kvx/kernel/time.c
@@ -0,0 +1,242 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Clement Leger
+ * Yann Sionneau
+ * Guillaume Thouvenin
+ * Luc Michel
+ * Julian Vetter
+ */
+
+#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/init.h>
+#include <linux/of_irq.h>
+#include <linux/interrupt.h>
+#include <linux/cpuhotplug.h>
+#include <linux/clockchips.h>
+#include <linux/clocksource.h>
+#include <linux/clk-provider.h>
+#include <linux/of_address.h>
+#include <linux/sched_clock.h>
+
+#include <asm/sfr_defs.h>
+
+#define KVX_TIMER_MIN_DELTA 1
+#define KVX_TIMER_MAX_DELTA 0xFFFFFFFFFFFFFFFFULL
+#define KVX_TIMER_MAX_VALUE 0xFFFFFFFFFFFFFFFFULL
+
+/*
+ * Clockevent
+ */
+static unsigned int kvx_timer_frequency;
+static unsigned int kvx_periodic_timer_value;
+static unsigned int kvx_timer_irq;
+
+static void kvx_timer_set_value(unsigned long value, unsigned long reload_value)
+{
+ kvx_sfr_set(T0R, reload_value);
+ kvx_sfr_set(T0V, value);
+ /* Enable timer */
+ kvx_sfr_set_field(TCR, T0CE, 1);
+}
+
+static int kvx_clkevent_set_next_event(unsigned long cycles,
+ struct clock_event_device *dev)
+{
+ /*
+ * Hardware does not support oneshot mode.
+ * In order to support it, set a really high reload value.
+ * Then, during the interrupt handler, disable the timer if
+ * in oneshot mode
+ */
+ kvx_timer_set_value(cycles - 1, KVX_TIMER_MAX_VALUE);
+
+ return 0;
+}
+
+/*
+ * Configure the rtc to periodically tick HZ times per second
+ */
+static int kvx_clkevent_set_state_periodic(struct clock_event_device *dev)
+{
+ kvx_timer_set_value(kvx_periodic_timer_value,
+ kvx_periodic_timer_value);
+
+ return 0;
+}
+
+static int kvx_clkevent_set_state_oneshot(struct clock_event_device *dev)
+{
+ /* Same as for kvx_clkevent_set_next_event */
+ kvx_clkevent_set_next_event(kvx_periodic_timer_value, dev);
+
+ return 0;
+}
+
+static int kvx_clkevent_set_state_shutdown(struct clock_event_device *dev)
+{
+ kvx_sfr_set_field(TCR, T0CE, 0);
+
+ return 0;
+}
+
+static DEFINE_PER_CPU(struct clock_event_device, kvx_clockevent_device) = {
+ .name = "kvx-timer-0",
+ .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC,
+ /* arbitrary rating for this clockevent */
+ .rating = 300,
+ .set_next_event = kvx_clkevent_set_next_event,
+ .set_state_periodic = kvx_clkevent_set_state_periodic,
+ .set_state_oneshot = kvx_clkevent_set_state_oneshot,
+ .set_state_shutdown = kvx_clkevent_set_state_shutdown,
+};
+
+irqreturn_t kvx_timer_irq_handler(int irq, void *dev_id)
+{
+ struct clock_event_device *evt = this_cpu_ptr(&kvx_clockevent_device);
+
+ /* Disable timer if in oneshot mode before reloading */
+ if (likely(clockevent_state_oneshot(evt)))
+ kvx_sfr_set_field(TCR, T0CE, 0);
+
+ evt->event_handler(evt);
+
+ return IRQ_HANDLED;
+}
+
+static int kvx_timer_starting_cpu(unsigned int cpu)
+{
+ struct clock_event_device *evt = this_cpu_ptr(&kvx_clockevent_device);
+
+ evt->cpumask = cpumask_of(cpu);
+ evt->irq = kvx_timer_irq;
+
+ clockevents_config_and_register(evt, kvx_timer_frequency,
+ KVX_TIMER_MIN_DELTA,
+ KVX_TIMER_MAX_DELTA);
+
+ /* Enable timer interrupt */
+ kvx_sfr_set_field(TCR, T0IE, 1);
+
+ enable_percpu_irq(kvx_timer_irq, IRQ_TYPE_NONE);
+
+ return 0;
+}
+
+static int kvx_timer_dying_cpu(unsigned int cpu)
+{
+ disable_percpu_irq(kvx_timer_irq);
+
+ return 0;
+}
+
+static int __init kvx_setup_core_timer(struct device_node *np)
+{
+ struct clock_event_device *evt = this_cpu_ptr(&kvx_clockevent_device);
+ struct clk *clk;
+ int err;
+
+ clk = of_clk_get(np, 0);
+ if (IS_ERR(clk)) {
+ pr_err("kvx_core_timer: Failed to get CPU clock: %ld\n",
+ PTR_ERR(clk));
+ return 1;
+ }
+
+ kvx_timer_frequency = clk_get_rate(clk);
+ clk_put(clk);
+ kvx_periodic_timer_value = kvx_timer_frequency / HZ;
+
+ kvx_timer_irq = irq_of_parse_and_map(np, 0);
+ if (!kvx_timer_irq) {
+ pr_err("kvx_core_timer: Failed to parse irq: %d\n",
+ kvx_timer_irq);
+ return -EINVAL;
+ }
+
+ err = request_percpu_irq(kvx_timer_irq, kvx_timer_irq_handler,
+ "kvx_core_timer", evt);
+ if (err) {
+ pr_err("kvx_core_timer: can't register interrupt %d (%d)\n",
+ kvx_timer_irq, err);
+ return err;
+ }
+
+ err = cpuhp_setup_state(CPUHP_AP_KVX_TIMER_STARTING,
+ "kvx/time:online",
+ kvx_timer_starting_cpu,
+ kvx_timer_dying_cpu);
+ if (err < 0) {
+ pr_err("kvx_core_timer: Failed to setup hotplug state");
+ return err;
+ }
+
+ return 0;
+}
+
+TIMER_OF_DECLARE(kvx_core_timer, "kalray,kvx-core-timer",
+ kvx_setup_core_timer);
+
+/*
+ * Clocksource
+ */
+static u64 kvx_dsu_clocksource_read(struct clocksource *cs)
+{
+ return readq(cs->archdata.regs);
+}
+
+static struct clocksource kvx_dsu_clocksource = {
+ .name = "kvx-dsu-clock",
+ .rating = 400,
+ .read = kvx_dsu_clocksource_read,
+ .mask = CLOCKSOURCE_MASK(64),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static u64 notrace kvx_dsu_sched_read(void)
+{
+ return readq_relaxed(kvx_dsu_clocksource.archdata.regs);
+}
+
+static int __init kvx_setup_dsu_clock(struct device_node *np)
+{
+ int ret;
+ struct clk *clk;
+ unsigned long kvx_dsu_frequency;
+
+ kvx_dsu_clocksource.archdata.regs = of_iomap(np, 0);
+
+ WARN_ON(!kvx_dsu_clocksource.archdata.regs);
+ if (!kvx_dsu_clocksource.archdata.regs)
+ return -ENXIO;
+
+ clk = of_clk_get(np, 0);
+ if (IS_ERR(clk)) {
+ pr_err("Failed to get CPU clock: %ld\n", PTR_ERR(clk));
+ return PTR_ERR(clk);
+ }
+
+ kvx_dsu_frequency = clk_get_rate(clk);
+ clk_put(clk);
+
+ ret = clocksource_register_hz(&kvx_dsu_clocksource,
+ kvx_dsu_frequency);
+ if (ret) {
+ pr_err("failed to register dsu clocksource");
+ return ret;
+ }
+
+ sched_clock_register(kvx_dsu_sched_read, 64, kvx_dsu_frequency);
+ return 0;
+}
+
+TIMER_OF_DECLARE(kvx_dsu_clock, "kalray,kvx-dsu-clock",
+ kvx_setup_dsu_clock);
+
+void __init time_init(void)
+{
+ of_clk_init(NULL);
+
+ timer_probe();
+}
--
2.37.2





2023-01-03 18:28:11

by Yann Sionneau

[permalink] [raw]
Subject: [RFC PATCH 01/25] Documentation: kvx: Add basic documentation

Add some documentation for kvx arch and its Linux port.

CC: Jonathan Corbet <[email protected]>
CC: [email protected]
CC: [email protected]
Co-developed-by: Clement Leger <[email protected]>
Signed-off-by: Clement Leger <[email protected]>
Co-developed-by: Guillaume Thouvenin <[email protected]>
Signed-off-by: Guillaume Thouvenin <[email protected]>
Signed-off-by: Yann Sionneau <[email protected]>
---
Documentation/kvx/kvx-exceptions.txt | 246 ++++++++++++++++++++++++
Documentation/kvx/kvx-iommu.txt | 183 ++++++++++++++++++
Documentation/kvx/kvx-mmu.txt | 272 +++++++++++++++++++++++++++
Documentation/kvx/kvx-smp.txt | 36 ++++
Documentation/kvx/kvx.txt | 268 ++++++++++++++++++++++++++
5 files changed, 1005 insertions(+)
create mode 100644 Documentation/kvx/kvx-exceptions.txt
create mode 100644 Documentation/kvx/kvx-iommu.txt
create mode 100644 Documentation/kvx/kvx-mmu.txt
create mode 100644 Documentation/kvx/kvx-smp.txt
create mode 100644 Documentation/kvx/kvx.txt

diff --git a/Documentation/kvx/kvx-exceptions.txt b/Documentation/kvx/kvx-exceptions.txt
new file mode 100644
index 000000000000..11368287bd48
--- /dev/null
+++ b/Documentation/kvx/kvx-exceptions.txt
@@ -0,0 +1,246 @@
+Exceptions
+==========
+On kvx, handlers are set using $ev (exception vector) register which
+specifies a base address.
+An offset is added to $ev upon exception and the result is used as
+"Next $pc".
+The offset depends on which exception vector the cpu wants to jump to:
+* $ev + 0x00 for debug
+* $ev + 0x40 for trap
+* $ev + 0x80 for interrupt
+* $ev + 0xc0 for syscall
+
+Then, handlers are laid in the following order:
+
+ _____________
+ | |
+ | Syscall |
+ |_____________|
+ | |
+ | Interrupts |
+ |_____________|
+ | |
+ | Traps |
+ |_____________|
+ | | ^
+ | Debug | | Stride
+BASE -> |_____________| v
+
+
+Interrupts, and traps are serviced similarly, ie:
+- Jump to handler
+- Save all registers
+- Prepare the call (do_IRQ or trap_handler)
+- restore all registers
+- return from exception
+
+entry.S file is (as for other architectures) the entry point into the kernel.
+It contains all assembly routines related to interrupts/traps/syscall.
+
+Syscall handling
+================
+
+When executing a syscall, it must be done using "scall $r6"
+where $r6 contains the syscall number. Using this convention allow to
+modify and restart a syscall from the kernel.
+
+Syscalls are handled differently than interrupts/exceptions. From an ABI
+point of view, scalls are like function calls: any caller saved register
+can be clobbered by the syscall. However, syscall parameters are passed
+using registers r0 through r7. These registers must be preserved to avoid
+cloberring them before the actual syscall function.
+
+On syscall from userspace (scall instruction), the processor will put
+the syscall number in $es.sn and switch from user to kernel privilege
+mode. kvx_syscall_handler will be called in kernel mode.
+
+The following steps are then taken:
+
+- Switch to kernel stack
+- Extract syscall number
+- Check that the syscall number is not bogus
+ - If so, set syscall func to a not implemented one
+- Check if tracing is enabled
+ - If so, jump to trace_syscall_enter
+ - Save syscall arguments (r0 -> r7) on stack in pt_regs
+ - Call do_trace_syscall_enter function
+- Restore syscall arguments since they have been modified by C call
+- Call the syscall function
+- Save $r0 in pt_regs since it can be cloberred afterward
+- If tracing was enabled, call trace_syscall_exit
+- Call work_pending
+- Return to user !
+
+The trace call is handled out of the fast path. All slow path handling
+is done in another part of code to avoid messing with the cache.
+
+Signals
+=======
+
+Signals are handled when exiting kernel before returning to user.
+When handling a signal, the path is the following:
+
+1 - User application is executing normally
+ Then any exception happens (syscall, interrupt, trap)
+2 - The exception handling path is taken
+ and before returning to user, pending signals are checked
+3 - Signal are handled by do_signal
+ Registers are saved and a special part of the stack is modified
+ to create a trampoline to call rt_sigreturn
+ $spc is modified to jump to user signal handler
+ $ra is modified to jump to sigreturn trampoline directly after
+ returning from user signal handler.
+4 - User signal handler is called after rfe from exception
+ when returning, $ra is retored to $pc, resulting in a call
+ to the syscall trampoline.
+5 - syscall trampoline is executed, leading to rt_sigreturn syscall
+6 - rt_sigreturn syscall is executed
+ Previous registers are restored to allow returning to user correctly
+7 - User application is restored at the exact point it was interrupted
+ before.
+
+
+ +----------+
+ | 1 |
+ | User app | @func
+ | (user) |
+ +---+------+
+ |
+ | it/trap/scall
+ |
+ +---v-------+
+ | 2 |
+ | exception |
+ | handling |
+ | (kernel) |
+ +---+-------+
+ |
+ | Check if signal are pending, if so, handle signals
+ |
+ +---v--------+
+ | 3 |
+ | do_signal |
+ | handling |
+ | (kernel) |
+ +----+-------+
+ |
+ | Return to user signal handler
+ |
+ +----v------+
+ | 4 |
+ | signal |
+ | handler |
+ | (user) |
+ +----+------+
+ |
+ | Return to sigreturn trampoline
+ |
+ +----v-------+
+ | 5 |
+ | syscall |
+ |rt_sigreturn|
+ | (user) |
+ +----+-------+
+ |
+ | Syscall to rt_sigreturn
+ |
+ +----v-------+
+ | 6 |
+ | sigreturn |
+ | handler |
+ | (kernel) |
+ +----+-------+
+ |
+ | Modify context to return to original func
+ |
+ +----v-----+
+ | 7 |
+ | User app | @func
+ | (user) |
+ +----------+
+
+Registers handling
+==================
+
+MMU is disabled in all exceptions paths, during register save and restoration.
+This will prevent from triggering MMU fault (such as TLB miss) which could
+clobber the current register state. Such event can occurs when RWX mode is
+enabled and the memory accessed to save register can trigger a TLB miss.
+Aside from that which is common for all exceptions path, registers are saved
+differently regarding the type of exception.
+
+Interrupts and traps
+--------------------
+
+When interrupt and traps are triggered, we only save the caller-saved registers.
+Indeed, we rely on the fact that C code will save and restore callee-saved and
+hence, there is no need to save them. This path is the following:
+
+ +------------+ +-----------+ +---------------+
+IT | Save caller| C Call | Execute C | Ret | Restore caller| Ret from IT
++--->+ saved +--------->+ handler +------->+ saved +----->
+ | registers | +-----------+ | registers |
+ +------------+ +---------------+
+
+However, when returning to user, we check if there is work_pending. If a signal
+is pending and there is a signal handler to be called, then we need all
+registers to be saved on the stack in the pt_regs before executing the signal
+handler and restored after that. Since we only saved caller-saved registers, we
+need to also save callee-saved registers to restore them correctly when
+returning to user. This path is the following (a bit more complicated !):
+
+ +------------+
+ | Save caller| +-----------+ Ret +------------+
+ IT | saved | C Call | Execute C | to asm | Check work |
+ +--->+ registers +--------->+ handler +------->+ pending |
+ | to pt_regs | +-----------+ +--+---+-----+
+ +------------+ | |
+ Work pending | | No work pending
+ +--------------------------------------------+ |
+ | |
+ | +------------+
+ v |
+ +------+------+ v
+ | Save callee | +-------+-------+
+ | saved | | Restore caller| RFE from IT
+ | registers | | saved +------->
+ | to pt_regs | | registers |
+ +--+-------+--+ | from pt_regs |
+ | | +-------+-------+
+ | | +---------+ ^
+ | | | Execute | |
+ | +-------->+ needed +-----------+
+ | | work |
+ | +---------+
+ |Signal handler ?
+ v
++----+----------+ RFE to user +-------------+ +--------------+
+| Copy all | handler | Execute | ret | rt_sigreturn |
+| registers +------------>+ user signal +------>+ trampoline |
+| from pt_regs | | handler | | to kernel |
+| to user stack | +-------------+ +------+-------+
++---------------+ |
+ syscall rt_sigreturn |
+ +-------------------------------------------------+
+ |
+ v
++--------+-------+ +-------------+
+| Recopy all | | Restore all | RFE
+| registers from +--------------------->+ saved +------->
+| user stack | Return | registers |
+| to pt_regs | from sigreturn |from pt_regs |
++----------------+ (via ret_from_fork) +-------------+
+
+
+Syscalls
+--------
+As explained before, for syscalls, we can use whatever callee-saved registers
+we want since syscall are seen as a "classic" call from ABI pov.
+Only different path is the one for clone. For this path, since the child expects
+to find same callee-registers content than his parent, we must save them before
+executing the clone syscall and restore them after that for the child. This is
+done via a redefinition of __sys_clone in assembly which will be called in place
+of the standard sys_clone. This new call will save callee saved registers
+in pt_regs. Parent will return using the syscall standard path. Freshly spawned
+child however will be woken up via ret_from_fork which will restore all
+registers (even if caller saved are not needed).
diff --git a/Documentation/kvx/kvx-iommu.txt b/Documentation/kvx/kvx-iommu.txt
new file mode 100644
index 000000000000..96b74ce71acb
--- /dev/null
+++ b/Documentation/kvx/kvx-iommu.txt
@@ -0,0 +1,183 @@
+IOMMU
+=====
+
+General Overview
+----------------
+
+To exchange data between device and users through memory, the driver has to
+set up a buffer by doing some kernel allocation. The address of the buffer is
+virtual and the physical one is obtained through the MMU. When the device wants
+to access the same physical memory space it uses a bus address. This address is
+obtained by using the DMA mapping API. The Coolidge SoC includes several IOMMUs for clusters,
+PCIe peripherals, SoC peripherals, and more; that will translate this "bus address"
+into a physical one during DMA operations.
+
+The bus addresses are IOVA (I/O Virtual Address) or DMA addresses. This
+addresses can be obtained by calling the allocation functions of the DMA APIs.
+It can also be obtained through classical kernel allocation of physical
+contiguous memory and then calling mapping functions of the DMA API.
+
+In order to be able to use the kvx IOMMU we have implemented the IOMMU DMA
+interface in arch/kvx/mm/dma-mapping.c. DMA functions are registered by
+implementing arch_setup_dma_ops() and generic IOMMU functions. Generic IOMMU
+are calling our specific IOMMU functions that adding or removing mappings
+between DMA addresses and physical addresses in the IOMMU TLB.
+
+Specifics IOMMU functions are defined in the kvx IOMMU driver. A kvx IOMMU
+driver is managing two physical hardware IOMMU used for TX and RX. In the next
+section we described the HW IOMMUs.
+
+
+Cluster IOMMUs
+--------------
+
+IOMMUs on cluster are used for DMA and cryptographic accelerators.
+There are six IOMMUs connected to the:
+ - cluster DMA tx
+ - cluster DMA rx
+ - first non secure cryptographic accelerator
+ - second non secure cryptographic accelerator
+ - first secure cryptographic accelerator
+ - second secure cryptographic accelerator
+
+SoC peripherals IOMMUs
+----------------------
+
+Since SoC peripherals are connected to an AXI bus, two IOMMUs are used: one for
+each AXI channel (read and write). These two IOMMUs are shared between all master
+devices and DMA. These two IOMMUs will have the same entries but need to be configured
+independently.
+
+PCIe IOMMUs
+-----------
+
+There is a slave IOMMU (read and write from the MPPA to the PCIe endpoint)
+and a master IOMMU (read and write from a PCIe endpoint to system DDR).
+The PCIe root complex and the MSI/MSI-X controller have been designed to use
+the IOMMU feature when enabled. (For example for supporting endpoint that
+support only 32 bits addresses and allow them to access any memory in a
+64 bits address space). For security reason it is highly recommended to
+activate the IOMMU for PCIe.
+
+IOMMU implementation
+--------------------
+
+The kvx is providing several IOMMUs. Here is a simplified view of all IOMMUs
+and translations that occurs between memory and devices:
+
+ +---------------------------------------------------------------------+
+ | +------------+ +---------+ | CLUSTER X |
+ | | Cores 0-15 +---->+ Crypto | +-----------|
+ | +-----+------+ +----+----+ |
+ | | | |
+ | v v |
+ | +-------+ +------------------------------+ |
+ | | MMU | +----+ IOMMU x4 (secure + insecure) | |
+ | +---+---+ | +------------------------------+ |
+ | | | |
+ +--------------------+ |
+ | | | |
+ v v | |
+ +---+--------+-+ | |
+ | MEMORY | | +----------+ +--------+ +-------+ |
+ | +<-|-----+ IOMMU Rx |<----+ DMA Rx |<----+ | |
+ | | | +----------+ +--------+ | | |
+ | | | | NoC | |
+ | | | +----------+ +--------+ | | |
+ | +--|---->| IOMMU Tx +---->| DMA Tx +---->+ | |
+ | | | +----------+ +--------+ +-------+ |
+ | | +------------------------------------------------+
+ | |
+ | | +--------------+ +------+
+ | |<--->+ IOMMU Rx/Tx +<--->+ PCIe +
+ | | +--------------+ +------+
+ | |
+ | | +--------------+ +------------------------+
+ | |<--->+ IOMMU Rx/Tx +<--->+ master Soc Peripherals |
+ | | +--------------+ +------------------------+
+ +--------------+
+
+
+There is also an IOMMU dedicated to the crypto module but this module will not
+be accessed by the operating system.
+
+We will provide one driver to manage IOMMUs RX/TX. All of them will be
+described in the device tree to be able to get their particularities. See
+the example below that describes the relation between IOMMU, DMA and NoC in
+the cluster.
+
+IOMMU is related to a specific bus like PCIe we will be able to specify that
+all peripherals will go through this IOMMU.
+
+### IOMMU Page table
+
+We need to be able to know which IO virtual addresses (IOVA) are mapped in the
+TLB in order to be able to remove entries when a device finishes a transfer and
+release memory. This information could be extracted when needed by computing all
+sets used by the memory and then reads all sixteen ways and compare them to the
+IOVA but it won't be efficient. We also need to be able to translate an IOVA
+to a physical address as required by the iova_to_phys IOMMU ops that is used
+by DMA. Like previously it can be done by extracting the set from the address
+and comparing the IOVA to each sixteen entries of the given set.
+
+A solution is to keep a page table for the IOMMU. But this method is not
+efficient for reloading an entry of the TLB without the help of an hardware
+page table. So to prevent the need of a refill we will update the TLB when a
+device request access to memory and if there is no more slot available in the
+TLB we will just fail and the device will have to try again later. It is not
+efficient but at least we won't need to manage the refill of the TLB.
+
+This leads to an issue with the memory that can be used for transfer between
+device and memory (see Limitations below). As we only support 4Ko page size we
+can only map 8Mo. To be able to manage bigger transfer we can implement the
+huge page table in the Linux kernel and use a page table that match the size of
+huge page table for a given IOMMU (typically the PCIe IOMMU).
+
+As we won't refill the TLB we know that we won't have more than 128*16 entries.
+In this case we can simply keep a table with all possible entries.
+
+### Maintenance interface
+
+It is possible to have several "maintainers" for the same IOMMU. The driver is
+using two of them. One that writes the TLB and another interface reads TLB. For
+debug purpose it is possible to display the content of the tlb by using the
+following command in gdb:
+
+ gdb> p kvx_iommu_dump_tlb( <iommu addr>, 0)
+
+Since different management interface are used for read and write it is safe to
+execute the above command at any moment.
+
+### Interrupts
+
+IOMMU can have 3 kind of interrupts that corresponds to 3 different types of
+errors (no mapping. protection, parity). When the IOMMU is shared between
+clusters (SoC periph and PCIe) then fifteen IRQs are generated according to the
+configuration of an association table. The association table is indexed by the
+ASN number (9 bits) and the entry of the table is a subscription mask with one
+bit per destination. Currently this is not managed by the driver.
+
+The driver is only managing interrupts for the cluster. The mode used is the
+stall one. So when an interrupt occurs it is managed by the driver. All others
+interrupts that occurs are stored and the IOMMU is stalled. When driver cleans
+the first interrupt others will be managed one by one.
+
+### ASN (Address Space Number)
+
+This is also know as ASID in some other architecture. Each device will have a
+given ASN that will be given through the device tree. As address space is
+managed at the IOMMU domain level we will use one group and one domain per ID.
+ASN are coded on 9 bits.
+
+Device tree
+-----------
+
+Relationships between devices, DMAs and IOMMUs are described in the
+device tree (see Documentation/devicetree/bindings/iommu/kalray,kvx-iommu.txt
+for more details).
+
+Limitations
+-----------
+
+Only supporting 4 KB page size will limit the size of mapped memory to 8 MB
+because the IOMMU TLB can have at most 128*16 entries.
diff --git a/Documentation/kvx/kvx-mmu.txt b/Documentation/kvx/kvx-mmu.txt
new file mode 100644
index 000000000000..a3ebbef36981
--- /dev/null
+++ b/Documentation/kvx/kvx-mmu.txt
@@ -0,0 +1,272 @@
+MMU
+===
+
+Virtual addresses are on 41 bits for kvx when using 64-bit mode.
+To differentiate kernel from user space, we use the high order bit
+(bit 40). When bit 40 is set, then the higher remaining bits must also be set to
+1. The virtual address must be extended with 1 when the bit 40 is set,
+if not the address must be zero extended. Bit 40 is set for kernel space
+mappings and not set for user space mappings.
+
+Memory Map
+==========
+
+In Linux physical memories are arranged into banks according to the cost of an
+access in term of distance to a memory. As we are UMA architecture we only have
+one bank and thus one node.
+
+A node is divided into several kind of zone. For example if DMA can only access
+a specific area in the physical memory we will define a ZONE_DMA for this purpose.
+In our case we are considering that DMA can access all DDR so we don't have a specific
+zone for this. On 64 bit architecture all DDR can be mapped in virtual kernel space
+so there is no need for a ZONE_HIGHMEM. That means that in our case there is
+only one ZONE_NORMAL. This will be updated if DMA cannot access all memory.
+
+Currently, the memory mapping is the following for 4KB page:
+
++-----------------------+-----------------------+------+-------+--------------+
+| Start | End | Attr | Size | Name |
++-----------------------+-----------------------+------+-------+--------------+
+| 0000 0000 0000 0000 | 0000 003F FFFF FFFF | --- | 256GB | User |
+| 0000 0040 0000 0000 | 0000 007F FFFF FFFF | --- | 256GB | MMAP |
+| 0000 0080 0000 0000 | FFFF FF7F FFFF FFFF | --- | --- | Gap |
+| FFFF FF80 0000 0000 | FFFF FFFF FFFF FFFF | --- | 512GB | Kernel |
+| FFFF FF80 0000 0000 | FFFF FF8F FFFF FFFF | RWX | 64GB | Direct Map |
+| FFFF FF90 0000 0000 | FFFF FF90 3FFF FFFF | RWX | 1GB | Vmalloc |
+| FFFF FF90 4000 0000 | FFFF FFFF FFFF FFFF | RW | 447GB | Free area |
++-----------------------+-----------------------+------+-------+--------------+
+
+Enable the MMU
+==============
+
+All kernel functions and symbols are in virtual memory except for kvx_start()
+function which is loaded at 0x0 in physical memory.
+To be able to switch from physical addresses to virtual addresses we choose to
+setup the TLB at the very beginning of the boot process to be able to map both
+pieces of code. For this we added two entries in the LTLB. The first one,
+LTLB[0], contains the mapping between virtual memory and DDR. Its size is 512MB.
+The second entry, LTLB[1], contains a flat mapping of the first 2MB of the SMEM.
+Once those two entries are present we can enable the MMU. LTLB[1] will be
+removed during paging_init() because once we are really running in virtual space
+it will not be used anymore.
+In order to access more than 512MB DDR memory, the remaining memory (> 512MB) is
+refill using a comparison in kernel_perf_refill that does not walk the kernel
+page table, thus having a faster refill time for kernel. These entries are
+inserted into the LTLB for easier computation (4 LTLB entries). The drawback of
+this approach is that mapped entries are using RWX protection attributes,
+leading to no protection at all.
+
+Kernel strict RWX
+=================
+
+CONFIG_STRICT_KERNEL_RWX is enabled by default in default_defconfig.
+Once booted, if CONFIG_STRICT_KERNEL_RWX is enable, the kernel text and memory
+will be mapped in the init_mm page table. Once mapped, the refill routine for
+the kernel is patched to always do a page table walk, bypassing the faster
+comparison but enforcing page protection attributes when refilling.
+Finally, the LTLB[0] entry is replaced by a 4K one, mapping only exceptions with
+RX protection. It allows us to never trigger nomapping on nomapping refill
+routine which would (obviously) not work... Once this is done, we can flush the
+4 LTLB entries for kernel refill in order to be sure there is no stalled
+entries and that new entries inserted in JTLB will apply.
+
+By default, the following policy is applied on vmlinux sections:
+- init_data: RW
+- init_text: RX (or RWX if parameter rodata=off)
+- text: RX (or RWX if parameter rodata=off)
+- rodata: RW before init, RO after init
+- sdata: RW
+
+Kernel RWX mode can then be switched on/off using /sys/kvx/kernel_rwx file.
+
+Privilege Level
+================
+Since we are using privilege levels on kvx, we make use of the virtual
+spaces to be in the same space as the user. The kernel will have the
+$ps.mmup set in kernel (PL1) and unset for user (PL2).
+As said in kvx documentation, we have two cases when the kernel is
+booted:
+- Either we have been booted by someone (bootloader, hypervisor, etc)
+- Or we are alone (boot from flash)
+
+In both cases, we will use the virtual space 0. Indeed, if we are alone
+on the core, then it means nobody is using the MMU and we can take the
+first virtual space. If not alone, then when writing an entry to the tlb
+using writetlb instruction, the hypervisor will catch it and change the
+virtual space accordingly.
+
+Memblock
+========
+
+When the kernel starts there is no memory allocator available. One of the first
+step in the kernel is to detect the amount of DDR available by getting this
+information in the device tree and initialize the low-level "memblock" allocator.
+
+We start by reserving memory for the whole kernel. For instance with a device
+tree containing 512Mo of DDR you could see the following boot messages:
+
+setup_bootmem: Memory : 0x100000000 - 0x120000000
+setup_bootmem: Reserved: 0x10001f000 - 0x1002d1bc0
+
+During the paging init we need to set:
+ - min_low_pfn that is the lowest PFN available in the system
+ - max_low_pfn that indicates the end if NORMAL zone
+ - max_pfn that is the number of pages in the system
+
+This setting is used for dividing memory into pages and for configuring the
+zone. See the memory map section for more information about ZONE.
+
+Zones are configured in free_area_init_core(). During start_kernel() other
+allocations are done for command line, cpu areas, PID hash table, different
+caches for VFS. This allocator is used until mem_init() is called.
+
+mem_init() is provided by the architecture. For MPPA we just call
+free_all_bootmem() that will go through all pages that are not used by the
+low level allocator and mark them as not used. So physical pages that are
+reserved for the kernel are still used and remain in physical memory. All pages
+released will now be used by the buddy allocator.
+
+Peripherals
+===========
+
+Peripherals are mapped using standard ioremap infrastructure, therefore
+mapped addresses are located in the vmalloc space.
+
+LTLB Usage
+==========
+
+LTLB is used to add resident mapping which allows for faster MMU lookup.
+Currently, the LTLB is used to map some mandatory kernel pages and to allow fast
+accesses to l2 cache (mailbox and registers).
+When CONFIG_STRICT_KERNEL_RWX is disabled, 4 entries are reserved for kernel
+TLB refill using 512MB pages. When CONFIG_STRICT_KERNEL_RWX is enabled, these
+entries are unused since kernel is paginated using the same mecanism than for
+user (page walking and entries in JTLB)
+
+Page Table
+==========
+
+We only support three levels for the page table and 4KB for page size.
+
+3 levels page table
+-------------------
+
+...-----+--------+--------+--------+--------+--------+
+ 40|39 32|31 24|23 16|15 8|7 0|
+...-----++-------+--+-----+---+----+----+---+--------+
+ | | | |
+ | | | +---> [11:0] Offset (12 bits)
+ | | +-------------> [20:12] PTE offset (9 bits)
+ | +-----------------------> [29:21] PMD offset (9 bits)
+ +----------------------------------> [39:30] PGD offset (10 bits)
+Bits 40 to 64 are signed extended according to bit 39. If bit 39 is equal to 1
+we are in kernel space.
+
+As 10 bits are used for PGD we need to allocate 2 pages.
+
+PTE format
+==========
+
+About the format of the PTE entry, as we are not forced by hardware for choices,
+we choose to follow the format described in the RiscV implementation as a
+starting point.
+
+ +---------+--------+----+--------+---+---+---+---+---+---+------+---+---+
+ | 63..23 | 22..13 | 12 | 11..10 | 9 | 8 | 7 | 6 | 5 | 4 | 3..2 | 1 | 0 |
+ +---------+--------+----+--------+---+---+---+---+---+---+------+---+---+
+ PFN Unused S PageSZ H G X W R D CP A P
+ where:
+ P: Present
+ A: Accessed
+ CP: Cache policy
+ D: Dirty
+ R: Read
+ W: Write
+ X: Executable
+ G: Global
+ H: Huge page
+ PageSZ: Page size as set in TLB format (0:4Ko, 1:64Ko, 2:2Mo, 3:512Mo)
+ S: Soft/Special
+ PFN: Page frame number (depends on page size)
+
+Huge bit must be somewhere in the first 12 bits to be able to detect it
+when reading the PMD entry.
+
+PageSZ must be on bit 10 and 11 because it matches the TEL.PS bits. And
+by doing that it is easier in assembly to set the TEL.PS to PageSZ.
+
+Fast TLB refill
+===============
+
+kvx core does not feature a hardware page walker. This work must be done
+by the core in software. In order to optimize TLB refill, a special fast
+path is taken when entering in kernel space.
+In order to speed up the process, the following actions are taken:
+# Save some registers in a per process scratchpad
+# If the trap is a nomapping then try the fastpath
+# Save some more registers for this fastpath
+# Check if faulting address is a memory direct mapping one.
+ # If entry is a direct mapping one and RWX is not enabled, add an entry into LTLB
+ # If not, continue
+# Try to walk the page table
+ # If entry is not present, take the slowpath (do_page_fault)
+# Refill the tlb properly
+# Exit by restoring only a few registers
+
+ASN Handling
+============
+
+Disclaimer: Some part of this are taken from ARC architecture.
+
+kvx MMU provides 9-bit ASN (Address Space Number) in order to tag TLB entries.
+It allows for multiple process with the same virtual space to cohabit without
+the need to flush TLB everytime we context switch.
+kvx implementation to use them is based on other architectures (such as arc
+or xtensa) and uses a wrapping ASN counter containing both cycle/generation and
+asn.
+
++---------+--------+
+|63 10|9 0|
++---------+--------+
+ Cycle ASN
+
+This ASN counter is incremented monotonously to allocate new ASNs. When the
+counter reaches 511 (9 bit), TLB is completely flushed and a new cycle is
+started. A new allocation cycle, post rollover, could potentially reassign an
+ASN to a different task. Thus the rule is to reassign an ASN when the current
+context cycles does not match the allocation cycle.
+The 64 bit @cpu_asn_cache (and mm->asn) have 9 bits MMU ASN and rest 55 bits
+serve as cycle/generation indicator and natural 64 bit unsigned math
+automagically increments the generation when lower 9 bits rollover.
+When the counter completely wraps, we reset the counter to first cycle value
+(ie cycle = 1). This allows to distinguish context without any ASN and old cycle
+generated value with the same operation (XOR on cycle).
+
+Huge page
+=========
+
+Currently only 3 level page table has been implemented for 4Ko base page size.
+So the page shift is 12 bits, the pmd shift is 21 and the pgdir shift is 30
+bits. This choice implies that for 4Ko base page size if we use a PMD as a huge
+page the size will be 2Mo and if we use a PUD as a huge page it will be 1Go.
+
+To support other huge page sizes (64Ko and 512Mo) we need to use several
+contiguous entries in the page table. For huge page of 64Ko we will need to
+use 16 entries in the PTE and for a huge page of 512Mo it means that 256
+entries in PMD will be used.
+
+Debug
+=====
+
+In order to debug the page table and tlb entries, gdb scripts contains commands
+which allows to dump the page table:
+- lx-kvx-page-table-walk
+ - Display the current process page table by default
+- lx-kvx-tlb-decode
+ - Display the content of $tel and $teh into something readable
+
+Other commands available in kvx-gdb are the following:
+- mppa-dump-tlb
+ - Display the content of TLBs (JTLB and LTLB)
+- mppa-lookup-addr
+ - Find physical address matching a virtual one
diff --git a/Documentation/kvx/kvx-smp.txt b/Documentation/kvx/kvx-smp.txt
new file mode 100644
index 000000000000..1b69d77db8cd
--- /dev/null
+++ b/Documentation/kvx/kvx-smp.txt
@@ -0,0 +1,36 @@
+SMP
+===
+
+On kvx, 5 clusters are organized as groups of 16 processors + 1
+secure core (RM) for each cluster. These 17 processors are L1$ coherent
+for TCM (tightly Coupled Memory). A mixed hw/sw L2$ is present to have
+cache coherency on DDR as well as TCM.
+The RM manager is not meant to run Linux so, 16 processors are available
+for SMP.
+
+Booting
+=======
+
+When booting the kvx processor, only the RM is woken up. This RM will
+execute a portion of code located in a section named .rm_firmware.
+By default, a simple power off code is embedded in this section.
+To avoid embedding the firmware in kernel sources, the section is patched
+using external tools to add the L2$ firmware (and replace the default firmware).
+Before executing this firmware, the RM boots the PE0. PE0 will then enable L2
+coherency and request will be stalled until RM boots the L2$ firmware.
+
+Locking primitives
+==================
+
+spinlock/rwlock are using the kernel standard queued spinlock/rwlocks.
+These primitives are based on cmpxch and xchg. More particularly, it uses xchg16
+which is implemented as a read modify write with acswap on 32 bit word since
+kvx does not have cmpxchg for size < 32bits.
+
+IPI
+===
+
+An IPI controller allows to communicate between CPUs using a simple
+memory mapped register. This register can simply be written using a mask to
+trigger interrupts directly to the cores matching the mask.
+
diff --git a/Documentation/kvx/kvx.txt b/Documentation/kvx/kvx.txt
new file mode 100644
index 000000000000..8ce0703de681
--- /dev/null
+++ b/Documentation/kvx/kvx.txt
@@ -0,0 +1,268 @@
+kvx Core Implementation
+=======================
+
+This documents will try to explain any architecture choice for the kvx
+linux port.
+
+Regarding the peripheral, we MUST use device tree to describe ALL
+peripherals. The bindings should always start with "kalray,kvx" for all
+core related peripherals (watchdog, timer, etc)
+
+System Architecture
+===================
+
+On kvx, we have 4 levels of privilege level starting from 0 (most
+privileged one) to 3 (less privilege one). A system of owners allows
+to delegate ownership of resources by using specials system registers.
+
+The 2 main software stacks for Linux Kernel are the following:
+
++-------------+ +-------------+
+| PL0: Debug | | PL0: Debug |
++-------------+ +-------------+
+| PL1: Linux | | PL1: HyperV |
++-------------+ +-------------+
+| PL2: User | | PL2: Linux |
++-------------+ +-------------+
+| | | PL3: User |
++-------------+ +-------------+
+
+In both cases, the kvx support for privileges has been designed using
+only relative PL and thus should work on both configurations without
+any modifications.
+
+When booting, the CPU is executing in PL0 and owns all the privileges.
+This level is almost dedicated to the debug routines for the debugguer.
+It only needs to own few privileges (breakpoint 0 and watchpoint 0) to
+be able to debug a system executing in PL1 to PL3.
+Debug routines are not always there for instance when the kernel is
+executing alone (booted from flash).
+In order to ease the load of debug routines, software convention is to
+jump directly to PL1 and let PL0 for the debug.
+When the kernel boots, it checks if the current privilege level is 0
+($ps.pl is the only absolute value). If so, then it will delegate
+almost all resources to PL1 and use a RFE to lower its execution
+privilege level (see asm_delegate_pl in head.S).
+If the current PL is already different from 0, then it means somebody
+is above us and we need to request resource to inform it we need them. It will
+then either delegate them to us directly or virtualize the delegation.
+All privileges levels have their set of banked registers (ps, ea, sps,
+sr, etc) which contain privilege level specific values.
+$sr (system reserved) is banked and will hold the current task_struct.
+This register is reserved and should not be touched by any other code.
+For more information, refer to the kvx system level architecture manual.
+
+Boot
+====
+
+On kvx, the RM (Secure Core) of Cluster 0 will boot first. It will then be able
+to boot a firmware. This firmware is stored in the rm_firmware section.
+The first argument ($r0) of this firmware will be a pointer to a function with
+the following prototype: void firmware_init_done(uint64_t features). This
+function is responsible of describing the features supported by the firmware and
+will start the first PE after that.
+By default, the rm_firmware function act as the "default" firmware. This
+function does nothing except calling firmware_init_done and then goes to sleep.
+In order to add another firmware, the rm_firmware section is patched using
+objcopy. The content of this section is then replaced by the provided firmware.
+This firmware will do an init and then call firmware_init_done before running
+the main loop.
+When the PE boots, it will check for the firmware features to enable or disable
+specific core features (L2$ for instance).
+
+When entering the C (kvx_lowlevel_start) the kernel will look for a special
+magic in $r0 (0x494C314B). This magic tells the kernel if there is arguments
+passed by a bootloader.
+Currently, the following values are passed through registers:
+ - r1: pointer to command line setup by bootloader
+ - r2: device tree
+
+If this magic is not set, then, the command line will be the one
+provided in the device tree (see bootargs). The default device tree is
+not builtin but will be patched by the runner used (simulator or jtag) in the
+dtb section.
+
+A default stdout-path is desirable to allow early printk.
+
+Boot Memory Allocator
+=====================
+
+The boot memory allocator is used to allocate memory before paging is enabled.
+It is initialized with DDR and also with the shared memory. This first one is
+initialized during the setup_bootmem() and the second one when calling
+early_init_fdt_scan_reserved_mem().
+
+
+Virtual and physical memory
+===========================
+
+The mapping used and the memory management is described in
+Documentation/kvx/kvx-mmu.txt.
+Our Kernel is compiled using virtual addresses that starts at
+0xffffff0000000000. But when it is started the kernel uses physical addresses.
+Before calling the first function arch_low_level_start() we configure 2 entries
+of the LTLB.
+
+The first entry will map the first 1G of virtual address space to the first
+1G of DDR:
+ - TLB[0]: 0xffffff0000000000 -> 0x100000000 (size 512Mo)
+
+The second entry will be a flat mapping of the first 512 Ko of the SMEM. It
+is required to have this flat mapping because there is still code located at
+this address that needs to be executed:
+ - TLB[1]: 0x0 -> 0x0 (size 512Ko)
+
+Once virtual space reached the second entry is removed.
+
+To be able to set breakpoints when MMU is enabled we added a label called
+gdb_mmu_enabled. If you try to set a breakpoint on a function that is in
+virtual memory before the activation of the MMU this address as no signification
+for GDB. So, for example, if you want to break on the function start_kernel()
+you will need to run:
+
+ kvx-gdb -silent path_to/vmlinux \
+ -ex 'tbreak gdb_mmu_enabled' -ex 'run' \
+ -ex 'break start_kernel' \
+ -ex 'continue'
+
+We will also add an option to kvx-gdb to simplify this step.
+
+Timers
+======
+
+The free-runinng clock (clocksource) is based on the DSU. This clock is
+not interruptible and never stops even if core go into idle.
+
+Regarding the tick (clockevent), we use the timer 0 available on the core.
+This timer allows to set a periodic tick which will be used as the main
+tick for each core. Note that this clock is percpu.
+
+get_cycles implementation is based on performance counter. One of them
+is used to count cycles. Note that since this is used only when the core
+is running, there is no need to worry about core sleeping (which will
+stop the cycle counter)
+
+Context switching
+=================
+
+context switching is done in entry.S. When spawning a fresh thread,
+copy_thread is called. During this call, we setup callee saved register
+r20 and r21 to special values containing the function to call.
+
+The normal path for a kernel thread will be the following:
+
+ 1 - Enter copy_thread_tls and setup callee saved registers which will
+ be restored in __switch_to.
+ 2 - set r20 and r21 (in thread_struct) to function and argument and
+ ra to ret_from_kernel_thread.
+ These callee saved will be restored in switch_to.
+ 3 - Call _switch_to at some point.
+ 4 - Save all callee saved register since switch_to is seen as a
+ standard function call by the caller.
+ 5 - Change stack pointer to the new stack
+ 6 - At the end of switch to, set sr0 to the new task and use ret to
+ jump to ret_from_kernel_thread (address restored from ra).
+ 7 - In ret_from_kernel_thread, execute the function with arguments by
+ using r20, r21 and we are done
+
+For more explanation, you can refer to https://lwn.net/Articles/520227/
+
+User thread creation
+====================
+
+We are using almost the same path as copy_thread to create it.
+The detailed path is the following:
+
+ 1 - Call start_thread which will setup user pc and stack pointer in
+ task regs. We also set sps and clear privilege mode bit.
+ When returning from exception, it will "flip" to user mode.
+ 2 - Enter copy_thread_tls and setup callee saved registers which will
+ be restored in __switch_to. Also, set the "return" function to be
+ ret_from_fork which will be called at end of switch_to
+ 3 - set r20 (in thread_struct) with tracing information.
+ (simply by lazyness to avoid computing it in assembly...)
+ 4 - Call _switch_to at some point.
+ 5 - The current pc will then be restored to be ret_from fork.
+ 6 - Ret from fork calls schedule_tail and then check if tracing is
+ enabled. If so call syscall_trace_exit
+ 7 - finally, instead of returning to kernel, we restore all registers
+ that have been setup by start_thread by restoring regs stored on
+ stack
+
+L2$ handling
+============
+
+On kvx, the L2$ is handled by a firmware running on the RM. This firmware needs
+various information to be aware of its configuration and communicate with the
+kernel. In order to do that, when firmware is starting, the device tree is given
+as parameter along with the "registers" zone. This zone is simply a memory area
+where data are exchanged between kernel <-> L2$. When some commands are written
+to it, the kernel sends an interrupt using a mailbox.
+If the L2$ node is not present in the device tree, then, the RM will directly go
+into sleeping.
+
+Boot diagram:
+
+ RM PE 0
+ +
+ +---------+ |
+ | Boot | |
+ +----+----+ |
+ | |
+ v |
+ +-----+-----+ |
+ | Prepare | |
+ | L2 shared | |
+ | memory | |
+ |(registers)| |
+ +-----+-----+ |
+ | | +-----------+
+ +------------------->+ Boot |
+ | | +-----+-----+
+ v | |
+ +--------+---------+ | |
+ | L2 firmware | | |
+ | parameters: | | |
+ | r0 = registers | | |
+ | r1 = DTB | | |
+ +--------+---------+ | |
+ | | |
+ v | |
+ +-------+--------+ | +------+------+
+ | L2 firmware | | | Wait for L2 |
+ | execution | | | to be ready |
+ +-------+--------+ | +------+------+
+ | | |
+ +------v-------+ | v
+ | L2 requests | | +------+------+
++--->+ handling | | | Enable |
+| +-------+------+ | | L2 caching |
+| | | +------+------+
+| | | |
++------------+ + v
+
+
+Since this driver is started early (before SMP boot), A lot of drivers are not
+yet probed (mailboxes, iommu, etc) and thus can not be used.
+
+Building
+========
+
+In order to build the kernel, you will need a complete kvx toolchain.
+First, setup the config using the following command line
+
+$ make ARCH=kvx O=your_directory default_defconfig
+
+Adjust any configuration option you may need and then, build the kernel:
+
+$ make ARCH=kvx O=your_directory -j12
+
+You will finally have a vmlinux image ready to be run.
+
+$ kvx-mppa -- vmlinux
+
+Additionally, you may want to debug it. To do so, use kvx-gdb:
+
+$ kvx-gdb vmlinux
+
+
--
2.37.2







2023-01-03 18:28:33

by Yann Sionneau

[permalink] [raw]
Subject: [RFC PATCH 04/25] kvx: Add CPU definition headers

Add common headers for basic kvx support:
- CPU definition
- SFR (System Function Registers)
- Privilege levels owners
- Hw breakpoints

CC: [email protected]
Co-developed-by: Clement Leger <[email protected]>
Signed-off-by: Clement Leger <[email protected]>
Co-developed-by: Guillaume Thouvenin <[email protected]>
Signed-off-by: Guillaume Thouvenin <[email protected]>
Co-developed-by: Julian Vetter <[email protected]>
Signed-off-by: Julian Vetter <[email protected]>
Co-developed-by: Marius Gligor <[email protected]>
Signed-off-by: Marius Gligor <[email protected]>
Co-developed-by: Yann Sionneau <[email protected]>
Signed-off-by: Yann Sionneau <[email protected]>
---
arch/kvx/include/asm/hw_breakpoint.h | 72 +
arch/kvx/include/asm/privilege.h | 211 ++
arch/kvx/include/asm/processor.h | 176 +
arch/kvx/include/asm/sfr.h | 107 +
arch/kvx/include/asm/sfr_defs.h | 5028 ++++++++++++++++++++++++++
arch/kvx/include/asm/swab.h | 48 +
arch/kvx/include/asm/sys_arch.h | 51 +
7 files changed, 5693 insertions(+)
create mode 100644 arch/kvx/include/asm/hw_breakpoint.h
create mode 100644 arch/kvx/include/asm/privilege.h
create mode 100644 arch/kvx/include/asm/processor.h
create mode 100644 arch/kvx/include/asm/sfr.h
create mode 100644 arch/kvx/include/asm/sfr_defs.h
create mode 100644 arch/kvx/include/asm/swab.h
create mode 100644 arch/kvx/include/asm/sys_arch.h

diff --git a/arch/kvx/include/asm/hw_breakpoint.h b/arch/kvx/include/asm/hw_breakpoint.h
new file mode 100644
index 000000000000..4d8380c6a905
--- /dev/null
+++ b/arch/kvx/include/asm/hw_breakpoint.h
@@ -0,0 +1,72 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Marius Gligor
+ * Clement Leger
+ */
+
+#ifndef _ASM_KVX_HW_BREAKPOINT_H
+#define _ASM_KVX_HW_BREAKPOINT_H
+
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+
+#include <linux/types.h>
+
+#define KVX_HW_BREAKPOINT_TYPE 0
+#define KVX_HW_WATCHPOINT_TYPE 1
+
+#define KVX_HW_WP_PER_WP 2
+
+struct arch_hw_breakpoint {
+ u64 addr;
+ u32 len;
+ u32 type;
+ union {
+ struct {
+ u64 hw_addr;
+ u32 hw_range;
+ } bp;
+ struct {
+ u64 hw_addr[KVX_HW_WP_PER_WP];
+ u32 hw_range[KVX_HW_WP_PER_WP];
+ u32 use_wp1;
+ u32 hit_info;
+ } wp;
+ };
+};
+
+struct perf_event_attr;
+struct perf_event;
+struct pt_regs;
+struct task_struct;
+
+int hw_breakpoint_slots(int type);
+int arch_check_bp_in_kernelspace(struct arch_hw_breakpoint *hw);
+int hw_breakpoint_arch_parse(struct perf_event *bp,
+ const struct perf_event_attr *attr,
+ struct arch_hw_breakpoint *hw);
+int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
+ unsigned long val, void *data);
+
+int arch_install_hw_breakpoint(struct perf_event *bp);
+void arch_uninstall_hw_breakpoint(struct perf_event *bp);
+void hw_breakpoint_pmu_read(struct perf_event *bp);
+void check_hw_breakpoint(struct pt_regs *regs);
+int check_hw_watchpoint(struct pt_regs *regs, u64 ea);
+int check_hw_watchpoint_stepped(struct pt_regs *regs);
+void clear_ptrace_hw_breakpoint(struct task_struct *tsk);
+int ptrace_request_hw_breakpoint(int idx);
+int ptrace_request_hw_watchpoint(int idx);
+
+#else
+
+struct task_struct;
+
+static inline void clear_ptrace_hw_breakpoint(struct task_struct *tsk)
+{
+}
+
+#endif /* CONFIG_HAVE_HW_BREAKPOINT */
+
+#endif /* _ASM_KVX_HW_BREAKPOINT_H */
+
diff --git a/arch/kvx/include/asm/privilege.h b/arch/kvx/include/asm/privilege.h
new file mode 100644
index 000000000000..e639c4a541c6
--- /dev/null
+++ b/arch/kvx/include/asm/privilege.h
@@ -0,0 +1,211 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Clement Leger
+ * Yann Sionneau
+ * Marius Gligor
+ */
+
+#ifndef _ASM_KVX_PRIVILEGE_H
+#define _ASM_KVX_PRIVILEGE_H
+
+#include <asm/sys_arch.h>
+
+/**
+ * Privilege level stuff
+ */
+
+/*
+ * When manipulating ring levels, we always use relative values. This means that
+ * settings a resource owner to value 1 means "Current privilege level + 1.
+ * Setting it to 0 means "Current privilege level"
+ */
+#define PL_CUR_PLUS_1 1
+#define PL_CUR 0
+
+/**
+ * Syscall owner configuration
+ */
+#define SYO_WFXL_OWN(__field, __pl) \
+ SFR_SET_VAL_WFXL(SYO, __field, __pl)
+
+#define SYO_WFXL_VALUE(__pl) (SYO_WFXL_OWN(Q0, __pl) | \
+ SYO_WFXL_OWN(Q1, __pl) | \
+ SYO_WFXL_OWN(Q2, __pl) | \
+ SYO_WFXL_OWN(Q3, __pl))
+
+#define SYO_WFXL_VALUE_PL_CUR_PLUS_1 SYO_WFXL_VALUE(PL_CUR_PLUS_1)
+#define SYO_WFXL_VALUE_PL_CUR SYO_WFXL_VALUE(PL_CUR)
+
+/**
+ * hardware trap owner configuration
+ */
+#define HTO_WFXL_OWN(__field, __pl) \
+ SFR_SET_VAL_WFXL(HTO, __field, __pl)
+
+
+#define HTO_WFXL_VALUE_BASE(__pl) (HTO_WFXL_OWN(OPC, __pl) | \
+ HTO_WFXL_OWN(DMIS, __pl) | \
+ HTO_WFXL_OWN(PSYS, __pl) | \
+ HTO_WFXL_OWN(DSYS, __pl) | \
+ HTO_WFXL_OWN(NOMAP, __pl) | \
+ HTO_WFXL_OWN(PROT, __pl) | \
+ HTO_WFXL_OWN(W2CL, __pl) | \
+ HTO_WFXL_OWN(A2CL, __pl) | \
+ HTO_WFXL_OWN(VSFR, __pl) | \
+ HTO_WFXL_OWN(PLO, __pl))
+
+/*
+ * When alone on the processor, we need to request all traps or the processor
+ * will die badly without any information at all by jumping to the more
+ * privilege level even if nobody is there.
+ */
+#define HTO_WFXL_VALUE_PL_CUR_PLUS_1 (HTO_WFXL_VALUE_BASE(PL_CUR_PLUS_1) | \
+ HTO_WFXL_OWN(DECCG, PL_CUR_PLUS_1) | \
+ HTO_WFXL_OWN(SECCG, PL_CUR_PLUS_1) | \
+ HTO_WFXL_OWN(DE, PL_CUR_PLUS_1))
+
+#define HTO_WFXL_VALUE_PL_CUR HTO_WFXL_VALUE_BASE(PL_CUR)
+
+/**
+ * Interrupt owner configuration
+ */
+#define ITO_WFXL_OWN(__field, __pl) \
+ SFR_SET_VAL_WFXL(ITO, __field, __pl)
+
+#define ITO_WFXL_VALUE(__pl) (ITO_WFXL_OWN(IT0, __pl) | \
+ ITO_WFXL_OWN(IT1, __pl) | \
+ ITO_WFXL_OWN(IT2, __pl) | \
+ ITO_WFXL_OWN(IT3, __pl) | \
+ ITO_WFXL_OWN(IT4, __pl) | \
+ ITO_WFXL_OWN(IT5, __pl) | \
+ ITO_WFXL_OWN(IT6, __pl) | \
+ ITO_WFXL_OWN(IT7, __pl) | \
+ ITO_WFXL_OWN(IT8, __pl) | \
+ ITO_WFXL_OWN(IT9, __pl) | \
+ ITO_WFXL_OWN(IT10, __pl) | \
+ ITO_WFXL_OWN(IT11, __pl) | \
+ ITO_WFXL_OWN(IT12, __pl) | \
+ ITO_WFXL_OWN(IT13, __pl) | \
+ ITO_WFXL_OWN(IT14, __pl) | \
+ ITO_WFXL_OWN(IT15, __pl))
+
+#define ITO_WFXL_VALUE_PL_CUR_PLUS_1 ITO_WFXL_VALUE(PL_CUR_PLUS_1)
+#define ITO_WFXL_VALUE_PL_CUR ITO_WFXL_VALUE(PL_CUR)
+
+#define ITO_WFXM_OWN(__field, __pl) \
+ SFR_SET_VAL_WFXM(ITO, __field, __pl)
+
+#define ITO_WFXM_VALUE(__pl) (ITO_WFXM_OWN(IT16, __pl) | \
+ ITO_WFXM_OWN(IT17, __pl) | \
+ ITO_WFXM_OWN(IT18, __pl) | \
+ ITO_WFXM_OWN(IT19, __pl) | \
+ ITO_WFXM_OWN(IT20, __pl) | \
+ ITO_WFXM_OWN(IT21, __pl) | \
+ ITO_WFXM_OWN(IT22, __pl) | \
+ ITO_WFXM_OWN(IT23, __pl) | \
+ ITO_WFXM_OWN(IT24, __pl) | \
+ ITO_WFXM_OWN(IT25, __pl) | \
+ ITO_WFXM_OWN(IT26, __pl) | \
+ ITO_WFXM_OWN(IT27, __pl) | \
+ ITO_WFXM_OWN(IT28, __pl) | \
+ ITO_WFXM_OWN(IT29, __pl) | \
+ ITO_WFXM_OWN(IT30, __pl) | \
+ ITO_WFXM_OWN(IT31, __pl))
+
+#define ITO_WFXM_VALUE_PL_CUR_PLUS_1 ITO_WFXM_VALUE(PL_CUR_PLUS_1)
+#define ITO_WFXM_VALUE_PL_CUR ITO_WFXM_VALUE(PL_CUR)
+
+/**
+ * Debug Owner configuration
+ */
+
+#define DO_WFXL_OWN(__field, __pl) \
+ SFR_SET_VAL_WFXL(DO, __field, __pl)
+
+#define DO_WFXL_VALUE(__pl) (DO_WFXL_OWN(B0, __pl) | \
+ DO_WFXL_OWN(B1, __pl) | \
+ DO_WFXL_OWN(W0, __pl) | \
+ DO_WFXL_OWN(W1, __pl))
+
+#define DO_WFXL_VALUE_PL_CUR_PLUS_1 DO_WFXL_VALUE(PL_CUR_PLUS_1)
+#define DO_WFXL_VALUE_PL_CUR DO_WFXL_VALUE(PL_CUR)
+
+/**
+ * Misc owner configuration
+ */
+#define MO_WFXL_OWN(__field, __pl) \
+ SFR_SET_VAL_WFXL(MO, __field, __pl)
+
+#define MO_WFXL_VALUE(__pl) (MO_WFXL_OWN(MMI, __pl) | \
+ MO_WFXL_OWN(RFE, __pl) | \
+ MO_WFXL_OWN(STOP, __pl) | \
+ MO_WFXL_OWN(SYNC, __pl) | \
+ MO_WFXL_OWN(PCR, __pl) | \
+ MO_WFXL_OWN(MSG, __pl) | \
+ MO_WFXL_OWN(MEN, __pl) | \
+ MO_WFXL_OWN(MES, __pl) | \
+ MO_WFXL_OWN(CSIT, __pl) | \
+ MO_WFXL_OWN(T0, __pl) | \
+ MO_WFXL_OWN(T1, __pl) | \
+ MO_WFXL_OWN(WD, __pl) | \
+ MO_WFXL_OWN(PM0, __pl) | \
+ MO_WFXL_OWN(PM1, __pl) | \
+ MO_WFXL_OWN(PM2, __pl) | \
+ MO_WFXL_OWN(PM3, __pl))
+
+#define MO_WFXL_VALUE_PL_CUR_PLUS_1 MO_WFXL_VALUE(PL_CUR_PLUS_1)
+#define MO_WFXL_VALUE_PL_CUR MO_WFXL_VALUE(PL_CUR)
+
+#define MO_WFXM_OWN(__field, __pl) \
+ SFR_SET_VAL_WFXM(MO, __field, __pl)
+
+#define MO_WFXM_VALUE(__pl) (MO_WFXM_OWN(PMIT, __pl))
+
+#define MO_WFXM_VALUE_PL_CUR_PLUS_1 MO_WFXM_VALUE(PL_CUR_PLUS_1)
+#define MO_WFXM_VALUE_PL_CUR MO_WFXM_VALUE(PL_CUR)
+
+/**
+ * $ps owner configuration
+ */
+#define PSO_WFXL_OWN(__field, __pl) \
+ SFR_SET_VAL_WFXL(PSO, __field, __pl)
+
+#define PSO_WFXL_BASE_VALUE(__pl) (PSO_WFXL_OWN(PL0, __pl) | \
+ PSO_WFXL_OWN(PL1, __pl) | \
+ PSO_WFXL_OWN(ET, __pl) | \
+ PSO_WFXL_OWN(HTD, __pl) | \
+ PSO_WFXL_OWN(IE, __pl) | \
+ PSO_WFXL_OWN(HLE, __pl) | \
+ PSO_WFXL_OWN(SRE, __pl) | \
+ PSO_WFXL_OWN(DAUS, __pl) | \
+ PSO_WFXL_OWN(ICE, __pl) | \
+ PSO_WFXL_OWN(USE, __pl) | \
+ PSO_WFXL_OWN(DCE, __pl) | \
+ PSO_WFXL_OWN(MME, __pl) | \
+ PSO_WFXL_OWN(IL0, __pl) | \
+ PSO_WFXL_OWN(IL1, __pl) | \
+ PSO_WFXL_OWN(VS0, __pl))
+/* Request additionnal VS1 when alone */
+#define PSO_WFXL_VALUE_PL_CUR_PLUS_1 (PSO_WFXL_BASE_VALUE(PL_CUR_PLUS_1) | \
+ PSO_WFXL_OWN(VS1, PL_CUR_PLUS_1))
+#define PSO_WFXL_VALUE_PL_CUR PSO_WFXL_BASE_VALUE(PL_CUR)
+
+#define PSO_WFXM_OWN(__field, __pl) \
+ SFR_SET_VAL_WFXM(PSO, __field, __pl)
+
+#define PSO_WFXM_VALUE(__pl) (PSO_WFXM_OWN(V64, __pl) | \
+ PSO_WFXM_OWN(L2E, __pl) | \
+ PSO_WFXM_OWN(SME, __pl) | \
+ PSO_WFXM_OWN(SMR, __pl) | \
+ PSO_WFXM_OWN(PMJ0, __pl) | \
+ PSO_WFXM_OWN(PMJ1, __pl) | \
+ PSO_WFXM_OWN(PMJ2, __pl) | \
+ PSO_WFXM_OWN(PMJ3, __pl) | \
+ PSO_WFXM_OWN(MMUP, __pl))
+
+/* Request additionnal VS1 */
+#define PSO_WFXM_VALUE_PL_CUR_PLUS_1 PSO_WFXM_VALUE(PL_CUR_PLUS_1)
+#define PSO_WFXM_VALUE_PL_CUR PSO_WFXM_VALUE(PL_CUR)
+
+#endif /* _ASM_KVX_PRIVILEGE_H */
diff --git a/arch/kvx/include/asm/processor.h b/arch/kvx/include/asm/processor.h
new file mode 100644
index 000000000000..e69011c1a913
--- /dev/null
+++ b/arch/kvx/include/asm/processor.h
@@ -0,0 +1,176 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Clement Leger
+ * Guillaume Thouvenin
+ * Marius Gligor
+ */
+
+#ifndef _ASM_KVX_PROCESSOR_H
+#define _ASM_KVX_PROCESSOR_H
+
+#include <asm/mmu.h>
+#include <asm/types.h>
+#include <asm/ptrace.h>
+#include <asm/sfr_defs.h>
+
+#define ARCH_HAS_PREFETCH
+#define ARCH_HAS_PREFETCHW
+
+static inline void prefetch(const void *x)
+{
+ __builtin_prefetch(x);
+}
+
+static inline void prefetchw(const void *x)
+{
+ __builtin_prefetch(x, 1);
+}
+
+#define TASK_SIZE _BITULL(MMU_USR_ADDR_BITS)
+#define TASK_SIZE_MAX TASK_SIZE
+
+/*
+ * This decides where the kernel will search for a free chunk of vm
+ * space during mmap's.
+ */
+#define TASK_UNMAPPED_BASE PAGE_ALIGN(TASK_SIZE >> 1)
+
+#define STACK_TOP TASK_SIZE
+#define STACK_TOP_MAX STACK_TOP
+
+/* Stack alignment constant */
+#define STACK_ALIGNMENT 32
+#define STACK_ALIGN_MASK (STACK_ALIGNMENT - 1)
+
+#define cpu_relax() barrier()
+
+/* Size for register saving area for refill handler (enough for 3 quad regs) */
+#define SAVE_AREA_SIZE 12
+
+#define TCA_REG_COUNT 48
+
+/* TCA registers are 256 bits wide */
+struct tca_reg {
+ uint64_t x;
+ uint64_t y;
+ uint64_t z;
+ uint64_t t;
+};
+
+/**
+ * According to kvx ABI, the following registers are callee-saved:
+ * fp (r14) r18 r19 r20 r21 r22 r23 r24 r25 r26 r27 r28 r29 r30 r31.
+ * In order to switch from a task to another, we only need to save these
+ * registers + sp (r12) and ra
+ *
+ * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
+ *
+ * Do not reorder the following fields !
+ * They are used in asm-offset for store octuples so they must be
+ * all right behind each other
+ */
+struct ctx_switch_regs {
+
+ uint64_t fp;
+
+ uint64_t ra; /* Return address */
+ uint64_t sp;
+ uint64_t r18;
+ uint64_t r19;
+
+ uint64_t r20;
+ uint64_t r21;
+ uint64_t r22;
+ uint64_t r23;
+
+ uint64_t r24;
+ uint64_t r25;
+ uint64_t r26;
+ uint64_t r27;
+
+ uint64_t r28;
+ uint64_t r29;
+ uint64_t r30;
+ uint64_t r31;
+
+#ifdef CONFIG_ENABLE_TCA
+ struct tca_reg tca_regs[TCA_REG_COUNT];
+ uint8_t tca_regs_saved;
+#endif
+};
+
+struct debug_info {
+#ifdef CONFIG_HAVE_HW_BREAKPOINT
+ struct perf_event *ptrace_hbp[KVX_HW_BREAKPOINT_COUNT];
+ struct perf_event *ptrace_hwp[KVX_HW_WATCHPOINT_COUNT];
+#endif
+};
+
+struct thread_struct {
+ uint64_t kernel_sp;
+ uint64_t save_area[SAVE_AREA_SIZE]; /* regs save area */
+
+#ifdef CONFIG_KVX_MMU_STATS
+ uint64_t trap_entry_ts;
+#endif
+ /* Context switch related registers */
+ struct ctx_switch_regs ctx_switch;
+
+ /* debugging */
+ struct debug_info debug;
+} __packed;
+
+#define INIT_THREAD { \
+ .ctx_switch.sp = \
+ sizeof(init_stack) + (unsigned long) &init_stack, \
+}
+
+#define KSTK_ESP(tsk) (task_pt_regs(tsk)->sp)
+#define KSTK_EIP(tsk) (task_pt_regs(tsk)->spc)
+
+#define task_pt_regs(p) \
+ ((struct pt_regs *)(task_stack_page(p) + THREAD_SIZE) - 1)
+
+#define thread_saved_reg(__tsk, __reg) \
+ ((unsigned long) ((__tsk)->thread.ctx_switch.__reg))
+
+void release_thread(struct task_struct *t);
+
+void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp);
+
+unsigned long __get_wchan(struct task_struct *p);
+
+extern void ret_from_kernel_thread(void);
+
+/* User return function */
+extern void ret_from_fork(void);
+
+static inline void wait_for_interrupt(void)
+{
+ __builtin_kvx_await();
+ kvx_sfr_set_field(WS, WU0, 0);
+}
+
+static inline void local_cpu_stop(void)
+{
+ /* Clear Wake-Up 2 to allow stop instruction to work */
+ kvx_sfr_set_field(WS, WU2, 0);
+ __asm__ __volatile__ (
+ "1: stop\n"
+ ";;\n"
+ "goto 1b\n"
+ ";;\n"
+ );
+}
+
+struct cpuinfo_kvx {
+ u64 freq;
+ u8 arch_rev;
+ u8 uarch_rev;
+ u8 copro_enable;
+};
+
+DECLARE_PER_CPU_READ_MOSTLY(struct cpuinfo_kvx, cpu_info);
+
+#endif /* _ASM_KVX_PROCESSOR_H */
diff --git a/arch/kvx/include/asm/sfr.h b/arch/kvx/include/asm/sfr.h
new file mode 100644
index 000000000000..d91aaa335bb9
--- /dev/null
+++ b/arch/kvx/include/asm/sfr.h
@@ -0,0 +1,107 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Clement Leger
+ * Yann Sionneau
+ * Guillaume Thouvenin
+ */
+
+#ifndef _ASM_KVX_SFR_H
+#define _ASM_KVX_SFR_H
+
+#ifndef __ASSEMBLY__
+
+#include <linux/types.h>
+
+#include <asm/sfr_defs.h>
+
+#define wfxl(_sfr, _val) __builtin_kvx_wfxl(_sfr, _val)
+
+#define wfxm(_sfr, _val) __builtin_kvx_wfxm(_sfr, _val)
+
+static inline void
+__kvx_sfr_set_bit(unsigned char sfr, unsigned char bit)
+{
+ if (bit < 32)
+ wfxl(sfr, (uint64_t) (1 << bit) << 32);
+ else
+ wfxm(sfr, (uint64_t) 1 << bit);
+}
+
+#define kvx_sfr_set_bit(__sfr, __bit) \
+ __kvx_sfr_set_bit(KVX_SFR_ ## __sfr, __bit)
+
+static inline uint64_t make_sfr_val(uint64_t mask, uint64_t value)
+{
+ return ((value & 0xFFFFFFFF) << 32) | (mask & 0xFFFFFFFF);
+}
+
+static inline void
+__kvx_sfr_set_mask(unsigned char sfr, uint64_t mask, uint64_t value)
+{
+ uint64_t wf_val;
+
+ /* Least significant bits */
+ if (mask & 0xFFFFFFFF) {
+ wf_val = make_sfr_val(mask, value);
+ wfxl(sfr, wf_val);
+ }
+
+ /* Most significant bits */
+ if (mask & (0xFFFFFFFFULL << 32)) {
+ value >>= 32;
+ mask >>= 32;
+ wf_val = make_sfr_val(mask, value);
+ wfxm(sfr, wf_val);
+ }
+}
+
+static inline u64 kvx_sfr_iget(unsigned char sfr)
+{
+ u64 res = sfr;
+
+ asm volatile ("iget %0" : "+r"(res) :: );
+ return res;
+}
+
+#ifdef CONFIG_DEBUG_SFR_SET_MASK
+# define kvx_sfr_set_mask(__sfr, __mask, __value) \
+ do { \
+ BUG_ON(((__value) & (__mask)) != (__value)); \
+ __kvx_sfr_set_mask(KVX_SFR_ ## __sfr, __mask, __value); \
+ } while (0)
+
+#else
+# define kvx_sfr_set_mask(__sfr, __mask, __value) \
+ __kvx_sfr_set_mask(KVX_SFR_ ## __sfr, __mask, __value)
+#endif
+
+#define kvx_sfr_set_field(sfr, field, value) \
+ kvx_sfr_set_mask(sfr, KVX_SFR_ ## sfr ## _ ## field ## _MASK, \
+ ((uint64_t) (value) << KVX_SFR_ ## sfr ## _ ## field ## _SHIFT))
+
+static inline void
+__kvx_sfr_clear_bit(unsigned char sfr, unsigned char bit)
+{
+ if (bit < 32)
+ wfxl(sfr, (uint64_t) 1 << bit);
+ else
+ wfxm(sfr, (uint64_t) 1 << (bit - 32));
+}
+
+#define kvx_sfr_clear_bit(__sfr, __bit) \
+ __kvx_sfr_clear_bit(KVX_SFR_ ## __sfr, __bit)
+
+#define kvx_sfr_set(_sfr, _val) __builtin_kvx_set(KVX_SFR_ ## _sfr, _val)
+#define kvx_sfr_get(_sfr) __builtin_kvx_get(KVX_SFR_ ## _sfr)
+
+#define kvx_sfr_field_val(_val, _sfr, _field) \
+ (((_val) & KVX_SFR_ ## _sfr ## _ ## _field ## _MASK) \
+ >> KVX_SFR_ ## _sfr ## _ ## _field ## _SHIFT)
+
+#define kvx_sfr_bit(_sfr, _field) \
+ BIT_ULL(KVX_SFR_ ## _sfr ## _ ## _field ## _SHIFT)
+
+#endif
+
+#endif /* _ASM_KVX_SFR_DEFS_H */
diff --git a/arch/kvx/include/asm/sfr_defs.h b/arch/kvx/include/asm/sfr_defs.h
new file mode 100644
index 000000000000..7e6318348b83
--- /dev/null
+++ b/arch/kvx/include/asm/sfr_defs.h
@@ -0,0 +1,5028 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Clement Leger
+ */
+
+#ifndef _ASM_KVX_SFR_DEFS_H
+#define _ASM_KVX_SFR_DEFS_H
+
+#include <linux/const.h>
+
+/* Register file indices */
+#define KVX_SFR_PC 0 /* Program Counter $pc $s0 */
+#define KVX_SFR_PS 1 /* Processor State $ps $s1 */
+#define KVX_SFR_PCR 2 /* Processing Identification $pcr $s2 */
+#define KVX_SFR_RA 3 /* Return Address $ra $s3 */
+#define KVX_SFR_CS 4 /* Compute Status $cs $s4 */
+#define KVX_SFR_CSIT 5 /* Compute Status arithmetic interrupt $csit $s5 */
+#define KVX_SFR_AESPC 6 /* Arithmetic Exception Saved PC $aespc $s6 */
+#define KVX_SFR_LS 7 /* Loop Start Address $ls $s7 */
+#define KVX_SFR_LE 8 /* Loop Exit Address $le $s8 */
+#define KVX_SFR_LC 9 /* Loop Counter $lc $s9 */
+#define KVX_SFR_IPE 10 /* Inter Processor Event $ipe $s10 */
+#define KVX_SFR_MEN 11 /* Misc External Notifications $men $s11 */
+#define KVX_SFR_PMC 12 /* Performance Monitor Control $pmc $s12 */
+#define KVX_SFR_PM0 13 /* Performance Monitor 0 $pm0 $s13 */
+#define KVX_SFR_PM1 14 /* Performance Monitor 1 $pm1 $s14 */
+#define KVX_SFR_PM2 15 /* Performance Monitor 2 $pm2 $s15 */
+#define KVX_SFR_PM3 16 /* Performance Monitor 3 $pm3 $s16 */
+#define KVX_SFR_PMSA 17 /* Performance Monitor Saved Address $pmsa $s17 */
+#define KVX_SFR_TCR 18 /* Timer Control $tcr $s18 */
+#define KVX_SFR_T0V 19 /* Timer 0 value $t0v $s19 */
+#define KVX_SFR_T1V 20 /* Timer 1 value $t1v $s20 */
+#define KVX_SFR_T0R 21 /* Timer 0 reload value $t0r $s21 */
+#define KVX_SFR_T1R 22 /* Timer 1 reload value $t1r $s22 */
+#define KVX_SFR_WDV 23 /* Watchdog Value $wdv $s23 */
+#define KVX_SFR_WDR 24 /* Watchdog Reload $wdr $s24 */
+#define KVX_SFR_ILE 25 /* Interrupt Line Enable $ile $s25 */
+#define KVX_SFR_ILL 26 /* Interrupt Line Level $ill $s26 */
+#define KVX_SFR_ILR 27 /* Interrupt Line Request $ilr $s27 */
+#define KVX_SFR_MMC 28 /* Memory Management Control $mmc $s28 */
+#define KVX_SFR_TEL 29 /* TLB Entry Low $tel $s29 */
+#define KVX_SFR_TEH 30 /* TLB Entry High $teh $s30 */
+#define KVX_SFR_SYO 32 /* Syscall Owners $syo $s32 */
+#define KVX_SFR_HTO 33 /* Hardware Trap Owners $hto $s33 */
+#define KVX_SFR_ITO 34 /* Interrupt Owners $ito $s34 */
+#define KVX_SFR_DO 35 /* Debug Owners $do $s35 */
+#define KVX_SFR_MO 36 /* Miscellaneous Owners $mo $s36 */
+#define KVX_SFR_PSO 37 /* PS register fields Owners $pso $s37 */
+#define KVX_SFR_DC 40 /* OCE (Debug) Control $dc $s40 */
+#define KVX_SFR_DBA0 41 /* Breakpoint Address 0 $dba0 $s41 */
+#define KVX_SFR_DBA1 42 /* Breakpoint Address 1 $dba1 $s42 */
+#define KVX_SFR_DWA0 43 /* Watchpoint Address 0 $dwa0 $s43 */
+#define KVX_SFR_DWA1 44 /* Watchpoint Address 1 $dwa1 $s44 */
+#define KVX_SFR_MES 45 /* Memory Error Status $mes $s45 */
+#define KVX_SFR_WS 46 /* Wake-Up Status $ws $s46 */
+#define KVX_SFR_SPC_PL0 64 /* Shadow PC PL 0 $spc_pl0 $s64 */
+#define KVX_SFR_SPC_PL1 65 /* Shadow PC PL 1 $spc_pl1 $s65 */
+#define KVX_SFR_SPC_PL2 66 /* Shadow PC PL 2 $spc_pl2 $s66 */
+#define KVX_SFR_SPC_PL3 67 /* Shadow PC PL 3 $spc_pl3 $s67 */
+#define KVX_SFR_SPS_PL0 68 /* Shadow PS PL 0 $sps_pl0 $s68 */
+#define KVX_SFR_SPS_PL1 69 /* Shadow PS PL 1 $sps_pl1 $s69 */
+#define KVX_SFR_SPS_PL2 70 /* Shadow PS PL 2 $sps_pl2 $s70 */
+#define KVX_SFR_SPS_PL3 71 /* Shadow PS PL 3 $sps_pl3 $s71 */
+#define KVX_SFR_EA_PL0 72 /* Effective Address PL0 $ea_pl0 $s72 */
+#define KVX_SFR_EA_PL1 73 /* Effective Address PL1 $ea_pl1 $s73 */
+#define KVX_SFR_EA_PL2 74 /* Effective Address PL2 $ea_pl2 $s74 */
+#define KVX_SFR_EA_PL3 75 /* Effective Address PL3 $ea_pl3 $s75 */
+#define KVX_SFR_EV_PL0 76 /* Exception Vector PL 0 $ev_pl0 $s76 */
+#define KVX_SFR_EV_PL1 77 /* Exception Vector PL 1 $ev_pl1 $s77 */
+#define KVX_SFR_EV_PL2 78 /* Exception Vector PL 2 $ev_pl2 $s78 */
+#define KVX_SFR_EV_PL3 79 /* Exception Vector PL 3 $ev_pl3 $s79 */
+#define KVX_SFR_SR_PL0 80 /* System Register PL 0 $sr_pl0 $s80 */
+#define KVX_SFR_SR_PL1 81 /* System Register PL 1 $sr_pl1 $s81 */
+#define KVX_SFR_SR_PL2 82 /* System Register PL 2 $sr_pl2 $s82 */
+#define KVX_SFR_SR_PL3 83 /* System Register PL 3 $sr_pl3 $s83 */
+#define KVX_SFR_ES_PL0 84 /* Exception Syndrome PL 0 $es_pl0 $s84 */
+#define KVX_SFR_ES_PL1 85 /* Exception Syndrome PL 1 $es_pl1 $s85 */
+#define KVX_SFR_ES_PL2 86 /* Exception Syndrome PL 2 $es_pl2 $s86 */
+#define KVX_SFR_ES_PL3 87 /* Exception Syndrome PL 3 $es_pl3 $s87 */
+#define KVX_SFR_SYOW 96 /* Alias to SYO register $syow $s96 */
+#define KVX_SFR_HTOW 97 /* Alias to HTO register $htow $s97 */
+#define KVX_SFR_ITOW 98 /* Alias to ITO register $itow $s98 */
+#define KVX_SFR_DOW 99 /* Alias to DO register $dow $s99 */
+#define KVX_SFR_MOW 100 /* Alias to MO register $mow $s100 */
+#define KVX_SFR_PSOW 101 /* Alias to PSO register $psow $s101 */
+#define KVX_SFR_SPC 128 /* Shadow PC alias on SPC_PL<i> $spc $s128 */
+#define KVX_SFR_SPS 132 /* Shadow PS alias on PS_PL<i> $sps $s132 */
+#define KVX_SFR_EA 136 /* Effective Address alias on EA_PL<i> $ea $s136 */
+#define KVX_SFR_EV 140 /* Exception Vector alias on EV_PL<i> $ev $s140 */
+#define KVX_SFR_SR 144 /* System Register alias on SR_PL<i> $sr $s144 */
+#define KVX_SFR_ES 148 /* Exception Syndrome alias on ES_PL<i> $es $s148 */
+#define KVX_SFR_VSFR0 256 /* Virtual SFR 0 $vsfr0 $s256 */
+#define KVX_SFR_VSFR1 257 /* Virtual SFR 1 $vsfr1 $s257 */
+#define KVX_SFR_VSFR2 258 /* Virtual SFR 2 $vsfr2 $s258 */
+#define KVX_SFR_VSFR3 259 /* Virtual SFR 3 $vsfr3 $s259 */
+#define KVX_SFR_VSFR4 260 /* Virtual SFR 4 $vsfr4 $s260 */
+#define KVX_SFR_VSFR5 261 /* Virtual SFR 5 $vsfr5 $s261 */
+#define KVX_SFR_VSFR6 262 /* Virtual SFR 6 $vsfr6 $s262 */
+#define KVX_SFR_VSFR7 263 /* Virtual SFR 7 $vsfr7 $s263 */
+#define KVX_SFR_VSFR8 264 /* Virtual SFR 8 $vsfr8 $s264 */
+#define KVX_SFR_VSFR9 265 /* Virtual SFR 9 $vsfr9 $s265 */
+#define KVX_SFR_VSFR10 266 /* Virtual SFR 10 $vsfr10 $s266 */
+#define KVX_SFR_VSFR11 267 /* Virtual SFR 11 $vsfr11 $s267 */
+#define KVX_SFR_VSFR12 268 /* Virtual SFR 12 $vsfr12 $s268 */
+#define KVX_SFR_VSFR13 269 /* Virtual SFR 13 $vsfr13 $s269 */
+#define KVX_SFR_VSFR14 270 /* Virtual SFR 14 $vsfr14 $s270 */
+#define KVX_SFR_VSFR15 271 /* Virtual SFR 15 $vsfr15 $s271 */
+#define KVX_SFR_VSFR16 272 /* Virtual SFR 16 $vsfr16 $s272 */
+#define KVX_SFR_VSFR17 273 /* Virtual SFR 17 $vsfr17 $s273 */
+#define KVX_SFR_VSFR18 274 /* Virtual SFR 18 $vsfr18 $s274 */
+#define KVX_SFR_VSFR19 275 /* Virtual SFR 19 $vsfr19 $s275 */
+#define KVX_SFR_VSFR20 276 /* Virtual SFR 20 $vsfr20 $s276 */
+#define KVX_SFR_VSFR21 277 /* Virtual SFR 21 $vsfr21 $s277 */
+#define KVX_SFR_VSFR22 278 /* Virtual SFR 22 $vsfr22 $s278 */
+#define KVX_SFR_VSFR23 279 /* Virtual SFR 23 $vsfr23 $s279 */
+#define KVX_SFR_VSFR24 280 /* Virtual SFR 24 $vsfr24 $s280 */
+#define KVX_SFR_VSFR25 281 /* Virtual SFR 25 $vsfr25 $s281 */
+#define KVX_SFR_VSFR26 282 /* Virtual SFR 26 $vsfr26 $s282 */
+#define KVX_SFR_VSFR27 283 /* Virtual SFR 27 $vsfr27 $s283 */
+#define KVX_SFR_VSFR28 284 /* Virtual SFR 28 $vsfr28 $s284 */
+#define KVX_SFR_VSFR29 285 /* Virtual SFR 29 $vsfr29 $s285 */
+#define KVX_SFR_VSFR30 286 /* Virtual SFR 30 $vsfr30 $s286 */
+#define KVX_SFR_VSFR31 287 /* Virtual SFR 31 $vsfr31 $s287 */
+#define KVX_SFR_VSFR32 288 /* Virtual SFR 32 $vsfr32 $s288 */
+#define KVX_SFR_VSFR33 289 /* Virtual SFR 33 $vsfr33 $s289 */
+#define KVX_SFR_VSFR34 290 /* Virtual SFR 34 $vsfr34 $s290 */
+#define KVX_SFR_VSFR35 291 /* Virtual SFR 35 $vsfr35 $s291 */
+#define KVX_SFR_VSFR36 292 /* Virtual SFR 36 $vsfr36 $s292 */
+#define KVX_SFR_VSFR37 293 /* Virtual SFR 37 $vsfr37 $s293 */
+#define KVX_SFR_VSFR38 294 /* Virtual SFR 38 $vsfr38 $s294 */
+#define KVX_SFR_VSFR39 295 /* Virtual SFR 39 $vsfr39 $s295 */
+#define KVX_SFR_VSFR40 296 /* Virtual SFR 40 $vsfr40 $s296 */
+#define KVX_SFR_VSFR41 297 /* Virtual SFR 41 $vsfr41 $s297 */
+#define KVX_SFR_VSFR42 298 /* Virtual SFR 42 $vsfr42 $s298 */
+#define KVX_SFR_VSFR43 299 /* Virtual SFR 43 $vsfr43 $s299 */
+#define KVX_SFR_VSFR44 300 /* Virtual SFR 44 $vsfr44 $s300 */
+#define KVX_SFR_VSFR45 301 /* Virtual SFR 45 $vsfr45 $s301 */
+#define KVX_SFR_VSFR46 302 /* Virtual SFR 46 $vsfr46 $s302 */
+#define KVX_SFR_VSFR47 303 /* Virtual SFR 47 $vsfr47 $s303 */
+#define KVX_SFR_VSFR48 304 /* Virtual SFR 48 $vsfr48 $s304 */
+#define KVX_SFR_VSFR49 305 /* Virtual SFR 49 $vsfr49 $s305 */
+#define KVX_SFR_VSFR50 306 /* Virtual SFR 50 $vsfr50 $s306 */
+#define KVX_SFR_VSFR51 307 /* Virtual SFR 51 $vsfr51 $s307 */
+#define KVX_SFR_VSFR52 308 /* Virtual SFR 52 $vsfr52 $s308 */
+#define KVX_SFR_VSFR53 309 /* Virtual SFR 53 $vsfr53 $s309 */
+#define KVX_SFR_VSFR54 310 /* Virtual SFR 54 $vsfr54 $s310 */
+#define KVX_SFR_VSFR55 311 /* Virtual SFR 55 $vsfr55 $s311 */
+#define KVX_SFR_VSFR56 312 /* Virtual SFR 56 $vsfr56 $s312 */
+#define KVX_SFR_VSFR57 313 /* Virtual SFR 57 $vsfr57 $s313 */
+#define KVX_SFR_VSFR58 314 /* Virtual SFR 58 $vsfr58 $s314 */
+#define KVX_SFR_VSFR59 315 /* Virtual SFR 59 $vsfr59 $s315 */
+#define KVX_SFR_VSFR60 316 /* Virtual SFR 60 $vsfr60 $s316 */
+#define KVX_SFR_VSFR61 317 /* Virtual SFR 61 $vsfr61 $s317 */
+#define KVX_SFR_VSFR62 318 /* Virtual SFR 62 $vsfr62 $s318 */
+#define KVX_SFR_VSFR63 319 /* Virtual SFR 63 $vsfr63 $s319 */
+#define KVX_SFR_VSFR64 320 /* Virtual SFR 64 $vsfr64 $s320 */
+#define KVX_SFR_VSFR65 321 /* Virtual SFR 65 $vsfr65 $s321 */
+#define KVX_SFR_VSFR66 322 /* Virtual SFR 66 $vsfr66 $s322 */
+#define KVX_SFR_VSFR67 323 /* Virtual SFR 67 $vsfr67 $s323 */
+#define KVX_SFR_VSFR68 324 /* Virtual SFR 68 $vsfr68 $s324 */
+#define KVX_SFR_VSFR69 325 /* Virtual SFR 69 $vsfr69 $s325 */
+#define KVX_SFR_VSFR70 326 /* Virtual SFR 70 $vsfr70 $s326 */
+#define KVX_SFR_VSFR71 327 /* Virtual SFR 71 $vsfr71 $s327 */
+#define KVX_SFR_VSFR72 328 /* Virtual SFR 72 $vsfr72 $s328 */
+#define KVX_SFR_VSFR73 329 /* Virtual SFR 73 $vsfr73 $s329 */
+#define KVX_SFR_VSFR74 330 /* Virtual SFR 74 $vsfr74 $s330 */
+#define KVX_SFR_VSFR75 331 /* Virtual SFR 75 $vsfr75 $s331 */
+#define KVX_SFR_VSFR76 332 /* Virtual SFR 76 $vsfr76 $s332 */
+#define KVX_SFR_VSFR77 333 /* Virtual SFR 77 $vsfr77 $s333 */
+#define KVX_SFR_VSFR78 334 /* Virtual SFR 78 $vsfr78 $s334 */
+#define KVX_SFR_VSFR79 335 /* Virtual SFR 79 $vsfr79 $s335 */
+#define KVX_SFR_VSFR80 336 /* Virtual SFR 80 $vsfr80 $s336 */
+#define KVX_SFR_VSFR81 337 /* Virtual SFR 81 $vsfr81 $s337 */
+#define KVX_SFR_VSFR82 338 /* Virtual SFR 82 $vsfr82 $s338 */
+#define KVX_SFR_VSFR83 339 /* Virtual SFR 83 $vsfr83 $s339 */
+#define KVX_SFR_VSFR84 340 /* Virtual SFR 84 $vsfr84 $s340 */
+#define KVX_SFR_VSFR85 341 /* Virtual SFR 85 $vsfr85 $s341 */
+#define KVX_SFR_VSFR86 342 /* Virtual SFR 86 $vsfr86 $s342 */
+#define KVX_SFR_VSFR87 343 /* Virtual SFR 87 $vsfr87 $s343 */
+#define KVX_SFR_VSFR88 344 /* Virtual SFR 88 $vsfr88 $s344 */
+#define KVX_SFR_VSFR89 345 /* Virtual SFR 89 $vsfr89 $s345 */
+#define KVX_SFR_VSFR90 346 /* Virtual SFR 90 $vsfr90 $s346 */
+#define KVX_SFR_VSFR91 347 /* Virtual SFR 91 $vsfr91 $s347 */
+#define KVX_SFR_VSFR92 348 /* Virtual SFR 92 $vsfr92 $s348 */
+#define KVX_SFR_VSFR93 349 /* Virtual SFR 93 $vsfr93 $s349 */
+#define KVX_SFR_VSFR94 350 /* Virtual SFR 94 $vsfr94 $s350 */
+#define KVX_SFR_VSFR95 351 /* Virtual SFR 95 $vsfr95 $s351 */
+#define KVX_SFR_VSFR96 352 /* Virtual SFR 96 $vsfr96 $s352 */
+#define KVX_SFR_VSFR97 353 /* Virtual SFR 97 $vsfr97 $s353 */
+#define KVX_SFR_VSFR98 354 /* Virtual SFR 98 $vsfr98 $s354 */
+#define KVX_SFR_VSFR99 355 /* Virtual SFR 99 $vsfr99 $s355 */
+#define KVX_SFR_VSFR100 356 /* Virtual SFR 100 $vsfr100 $s356 */
+#define KVX_SFR_VSFR101 357 /* Virtual SFR 101 $vsfr101 $s357 */
+#define KVX_SFR_VSFR102 358 /* Virtual SFR 102 $vsfr102 $s358 */
+#define KVX_SFR_VSFR103 359 /* Virtual SFR 103 $vsfr103 $s359 */
+#define KVX_SFR_VSFR104 360 /* Virtual SFR 104 $vsfr104 $s360 */
+#define KVX_SFR_VSFR105 361 /* Virtual SFR 105 $vsfr105 $s361 */
+#define KVX_SFR_VSFR106 362 /* Virtual SFR 106 $vsfr106 $s362 */
+#define KVX_SFR_VSFR107 363 /* Virtual SFR 107 $vsfr107 $s363 */
+#define KVX_SFR_VSFR108 364 /* Virtual SFR 108 $vsfr108 $s364 */
+#define KVX_SFR_VSFR109 365 /* Virtual SFR 109 $vsfr109 $s365 */
+#define KVX_SFR_VSFR110 366 /* Virtual SFR 110 $vsfr110 $s366 */
+#define KVX_SFR_VSFR111 367 /* Virtual SFR 111 $vsfr111 $s367 */
+#define KVX_SFR_VSFR112 368 /* Virtual SFR 112 $vsfr112 $s368 */
+#define KVX_SFR_VSFR113 369 /* Virtual SFR 113 $vsfr113 $s369 */
+#define KVX_SFR_VSFR114 370 /* Virtual SFR 114 $vsfr114 $s370 */
+#define KVX_SFR_VSFR115 371 /* Virtual SFR 115 $vsfr115 $s371 */
+#define KVX_SFR_VSFR116 372 /* Virtual SFR 116 $vsfr116 $s372 */
+#define KVX_SFR_VSFR117 373 /* Virtual SFR 117 $vsfr117 $s373 */
+#define KVX_SFR_VSFR118 374 /* Virtual SFR 118 $vsfr118 $s374 */
+#define KVX_SFR_VSFR119 375 /* Virtual SFR 119 $vsfr119 $s375 */
+#define KVX_SFR_VSFR120 376 /* Virtual SFR 120 $vsfr120 $s376 */
+#define KVX_SFR_VSFR121 377 /* Virtual SFR 121 $vsfr121 $s377 */
+#define KVX_SFR_VSFR122 378 /* Virtual SFR 122 $vsfr122 $s378 */
+#define KVX_SFR_VSFR123 379 /* Virtual SFR 123 $vsfr123 $s379 */
+#define KVX_SFR_VSFR124 380 /* Virtual SFR 124 $vsfr124 $s380 */
+#define KVX_SFR_VSFR125 381 /* Virtual SFR 125 $vsfr125 $s381 */
+#define KVX_SFR_VSFR126 382 /* Virtual SFR 126 $vsfr126 $s382 */
+#define KVX_SFR_VSFR127 383 /* Virtual SFR 127 $vsfr127 $s383 */
+#define KVX_SFR_VSFR128 384 /* Virtual SFR 128 $vsfr128 $s384 */
+#define KVX_SFR_VSFR129 385 /* Virtual SFR 129 $vsfr129 $s385 */
+#define KVX_SFR_VSFR130 386 /* Virtual SFR 130 $vsfr130 $s386 */
+#define KVX_SFR_VSFR131 387 /* Virtual SFR 131 $vsfr131 $s387 */
+#define KVX_SFR_VSFR132 388 /* Virtual SFR 132 $vsfr132 $s388 */
+#define KVX_SFR_VSFR133 389 /* Virtual SFR 133 $vsfr133 $s389 */
+#define KVX_SFR_VSFR134 390 /* Virtual SFR 134 $vsfr134 $s390 */
+#define KVX_SFR_VSFR135 391 /* Virtual SFR 135 $vsfr135 $s391 */
+#define KVX_SFR_VSFR136 392 /* Virtual SFR 136 $vsfr136 $s392 */
+#define KVX_SFR_VSFR137 393 /* Virtual SFR 137 $vsfr137 $s393 */
+#define KVX_SFR_VSFR138 394 /* Virtual SFR 138 $vsfr138 $s394 */
+#define KVX_SFR_VSFR139 395 /* Virtual SFR 139 $vsfr139 $s395 */
+#define KVX_SFR_VSFR140 396 /* Virtual SFR 140 $vsfr140 $s396 */
+#define KVX_SFR_VSFR141 397 /* Virtual SFR 141 $vsfr141 $s397 */
+#define KVX_SFR_VSFR142 398 /* Virtual SFR 142 $vsfr142 $s398 */
+#define KVX_SFR_VSFR143 399 /* Virtual SFR 143 $vsfr143 $s399 */
+#define KVX_SFR_VSFR144 400 /* Virtual SFR 144 $vsfr144 $s400 */
+#define KVX_SFR_VSFR145 401 /* Virtual SFR 145 $vsfr145 $s401 */
+#define KVX_SFR_VSFR146 402 /* Virtual SFR 146 $vsfr146 $s402 */
+#define KVX_SFR_VSFR147 403 /* Virtual SFR 147 $vsfr147 $s403 */
+#define KVX_SFR_VSFR148 404 /* Virtual SFR 148 $vsfr148 $s404 */
+#define KVX_SFR_VSFR149 405 /* Virtual SFR 149 $vsfr149 $s405 */
+#define KVX_SFR_VSFR150 406 /* Virtual SFR 150 $vsfr150 $s406 */
+#define KVX_SFR_VSFR151 407 /* Virtual SFR 151 $vsfr151 $s407 */
+#define KVX_SFR_VSFR152 408 /* Virtual SFR 152 $vsfr152 $s408 */
+#define KVX_SFR_VSFR153 409 /* Virtual SFR 153 $vsfr153 $s409 */
+#define KVX_SFR_VSFR154 410 /* Virtual SFR 154 $vsfr154 $s410 */
+#define KVX_SFR_VSFR155 411 /* Virtual SFR 155 $vsfr155 $s411 */
+#define KVX_SFR_VSFR156 412 /* Virtual SFR 156 $vsfr156 $s412 */
+#define KVX_SFR_VSFR157 413 /* Virtual SFR 157 $vsfr157 $s413 */
+#define KVX_SFR_VSFR158 414 /* Virtual SFR 158 $vsfr158 $s414 */
+#define KVX_SFR_VSFR159 415 /* Virtual SFR 159 $vsfr159 $s415 */
+#define KVX_SFR_VSFR160 416 /* Virtual SFR 160 $vsfr160 $s416 */
+#define KVX_SFR_VSFR161 417 /* Virtual SFR 161 $vsfr161 $s417 */
+#define KVX_SFR_VSFR162 418 /* Virtual SFR 162 $vsfr162 $s418 */
+#define KVX_SFR_VSFR163 419 /* Virtual SFR 163 $vsfr163 $s419 */
+#define KVX_SFR_VSFR164 420 /* Virtual SFR 164 $vsfr164 $s420 */
+#define KVX_SFR_VSFR165 421 /* Virtual SFR 165 $vsfr165 $s421 */
+#define KVX_SFR_VSFR166 422 /* Virtual SFR 166 $vsfr166 $s422 */
+#define KVX_SFR_VSFR167 423 /* Virtual SFR 167 $vsfr167 $s423 */
+#define KVX_SFR_VSFR168 424 /* Virtual SFR 168 $vsfr168 $s424 */
+#define KVX_SFR_VSFR169 425 /* Virtual SFR 169 $vsfr169 $s425 */
+#define KVX_SFR_VSFR170 426 /* Virtual SFR 170 $vsfr170 $s426 */
+#define KVX_SFR_VSFR171 427 /* Virtual SFR 171 $vsfr171 $s427 */
+#define KVX_SFR_VSFR172 428 /* Virtual SFR 172 $vsfr172 $s428 */
+#define KVX_SFR_VSFR173 429 /* Virtual SFR 173 $vsfr173 $s429 */
+#define KVX_SFR_VSFR174 430 /* Virtual SFR 174 $vsfr174 $s430 */
+#define KVX_SFR_VSFR175 431 /* Virtual SFR 175 $vsfr175 $s431 */
+#define KVX_SFR_VSFR176 432 /* Virtual SFR 176 $vsfr176 $s432 */
+#define KVX_SFR_VSFR177 433 /* Virtual SFR 177 $vsfr177 $s433 */
+#define KVX_SFR_VSFR178 434 /* Virtual SFR 178 $vsfr178 $s434 */
+#define KVX_SFR_VSFR179 435 /* Virtual SFR 179 $vsfr179 $s435 */
+#define KVX_SFR_VSFR180 436 /* Virtual SFR 180 $vsfr180 $s436 */
+#define KVX_SFR_VSFR181 437 /* Virtual SFR 181 $vsfr181 $s437 */
+#define KVX_SFR_VSFR182 438 /* Virtual SFR 182 $vsfr182 $s438 */
+#define KVX_SFR_VSFR183 439 /* Virtual SFR 183 $vsfr183 $s439 */
+#define KVX_SFR_VSFR184 440 /* Virtual SFR 184 $vsfr184 $s440 */
+#define KVX_SFR_VSFR185 441 /* Virtual SFR 185 $vsfr185 $s441 */
+#define KVX_SFR_VSFR186 442 /* Virtual SFR 186 $vsfr186 $s442 */
+#define KVX_SFR_VSFR187 443 /* Virtual SFR 187 $vsfr187 $s443 */
+#define KVX_SFR_VSFR188 444 /* Virtual SFR 188 $vsfr188 $s444 */
+#define KVX_SFR_VSFR189 445 /* Virtual SFR 189 $vsfr189 $s445 */
+#define KVX_SFR_VSFR190 446 /* Virtual SFR 190 $vsfr190 $s446 */
+#define KVX_SFR_VSFR191 447 /* Virtual SFR 191 $vsfr191 $s447 */
+#define KVX_SFR_VSFR192 448 /* Virtual SFR 192 $vsfr192 $s448 */
+#define KVX_SFR_VSFR193 449 /* Virtual SFR 193 $vsfr193 $s449 */
+#define KVX_SFR_VSFR194 450 /* Virtual SFR 194 $vsfr194 $s450 */
+#define KVX_SFR_VSFR195 451 /* Virtual SFR 195 $vsfr195 $s451 */
+#define KVX_SFR_VSFR196 452 /* Virtual SFR 196 $vsfr196 $s452 */
+#define KVX_SFR_VSFR197 453 /* Virtual SFR 197 $vsfr197 $s453 */
+#define KVX_SFR_VSFR198 454 /* Virtual SFR 198 $vsfr198 $s454 */
+#define KVX_SFR_VSFR199 455 /* Virtual SFR 199 $vsfr199 $s455 */
+#define KVX_SFR_VSFR200 456 /* Virtual SFR 200 $vsfr200 $s456 */
+#define KVX_SFR_VSFR201 457 /* Virtual SFR 201 $vsfr201 $s457 */
+#define KVX_SFR_VSFR202 458 /* Virtual SFR 202 $vsfr202 $s458 */
+#define KVX_SFR_VSFR203 459 /* Virtual SFR 203 $vsfr203 $s459 */
+#define KVX_SFR_VSFR204 460 /* Virtual SFR 204 $vsfr204 $s460 */
+#define KVX_SFR_VSFR205 461 /* Virtual SFR 205 $vsfr205 $s461 */
+#define KVX_SFR_VSFR206 462 /* Virtual SFR 206 $vsfr206 $s462 */
+#define KVX_SFR_VSFR207 463 /* Virtual SFR 207 $vsfr207 $s463 */
+#define KVX_SFR_VSFR208 464 /* Virtual SFR 208 $vsfr208 $s464 */
+#define KVX_SFR_VSFR209 465 /* Virtual SFR 209 $vsfr209 $s465 */
+#define KVX_SFR_VSFR210 466 /* Virtual SFR 210 $vsfr210 $s466 */
+#define KVX_SFR_VSFR211 467 /* Virtual SFR 211 $vsfr211 $s467 */
+#define KVX_SFR_VSFR212 468 /* Virtual SFR 212 $vsfr212 $s468 */
+#define KVX_SFR_VSFR213 469 /* Virtual SFR 213 $vsfr213 $s469 */
+#define KVX_SFR_VSFR214 470 /* Virtual SFR 214 $vsfr214 $s470 */
+#define KVX_SFR_VSFR215 471 /* Virtual SFR 215 $vsfr215 $s471 */
+#define KVX_SFR_VSFR216 472 /* Virtual SFR 216 $vsfr216 $s472 */
+#define KVX_SFR_VSFR217 473 /* Virtual SFR 217 $vsfr217 $s473 */
+#define KVX_SFR_VSFR218 474 /* Virtual SFR 218 $vsfr218 $s474 */
+#define KVX_SFR_VSFR219 475 /* Virtual SFR 219 $vsfr219 $s475 */
+#define KVX_SFR_VSFR220 476 /* Virtual SFR 220 $vsfr220 $s476 */
+#define KVX_SFR_VSFR221 477 /* Virtual SFR 221 $vsfr221 $s477 */
+#define KVX_SFR_VSFR222 478 /* Virtual SFR 222 $vsfr222 $s478 */
+#define KVX_SFR_VSFR223 479 /* Virtual SFR 223 $vsfr223 $s479 */
+#define KVX_SFR_VSFR224 480 /* Virtual SFR 224 $vsfr224 $s480 */
+#define KVX_SFR_VSFR225 481 /* Virtual SFR 225 $vsfr225 $s481 */
+#define KVX_SFR_VSFR226 482 /* Virtual SFR 226 $vsfr226 $s482 */
+#define KVX_SFR_VSFR227 483 /* Virtual SFR 227 $vsfr227 $s483 */
+#define KVX_SFR_VSFR228 484 /* Virtual SFR 228 $vsfr228 $s484 */
+#define KVX_SFR_VSFR229 485 /* Virtual SFR 229 $vsfr229 $s485 */
+#define KVX_SFR_VSFR230 486 /* Virtual SFR 230 $vsfr230 $s486 */
+#define KVX_SFR_VSFR231 487 /* Virtual SFR 231 $vsfr231 $s487 */
+#define KVX_SFR_VSFR232 488 /* Virtual SFR 232 $vsfr232 $s488 */
+#define KVX_SFR_VSFR233 489 /* Virtual SFR 233 $vsfr233 $s489 */
+#define KVX_SFR_VSFR234 490 /* Virtual SFR 234 $vsfr234 $s490 */
+#define KVX_SFR_VSFR235 491 /* Virtual SFR 235 $vsfr235 $s491 */
+#define KVX_SFR_VSFR236 492 /* Virtual SFR 236 $vsfr236 $s492 */
+#define KVX_SFR_VSFR237 493 /* Virtual SFR 237 $vsfr237 $s493 */
+#define KVX_SFR_VSFR238 494 /* Virtual SFR 238 $vsfr238 $s494 */
+#define KVX_SFR_VSFR239 495 /* Virtual SFR 239 $vsfr239 $s495 */
+#define KVX_SFR_VSFR240 496 /* Virtual SFR 240 $vsfr240 $s496 */
+#define KVX_SFR_VSFR241 497 /* Virtual SFR 241 $vsfr241 $s497 */
+#define KVX_SFR_VSFR242 498 /* Virtual SFR 242 $vsfr242 $s498 */
+#define KVX_SFR_VSFR243 499 /* Virtual SFR 243 $vsfr243 $s499 */
+#define KVX_SFR_VSFR244 500 /* Virtual SFR 244 $vsfr244 $s500 */
+#define KVX_SFR_VSFR245 501 /* Virtual SFR 245 $vsfr245 $s501 */
+#define KVX_SFR_VSFR246 502 /* Virtual SFR 246 $vsfr246 $s502 */
+#define KVX_SFR_VSFR247 503 /* Virtual SFR 247 $vsfr247 $s503 */
+#define KVX_SFR_VSFR248 504 /* Virtual SFR 248 $vsfr248 $s504 */
+#define KVX_SFR_VSFR249 505 /* Virtual SFR 249 $vsfr249 $s505 */
+#define KVX_SFR_VSFR250 506 /* Virtual SFR 250 $vsfr250 $s506 */
+#define KVX_SFR_VSFR251 507 /* Virtual SFR 251 $vsfr251 $s507 */
+#define KVX_SFR_VSFR252 508 /* Virtual SFR 252 $vsfr252 $s508 */
+#define KVX_SFR_VSFR253 509 /* Virtual SFR 253 $vsfr253 $s509 */
+#define KVX_SFR_VSFR254 510 /* Virtual SFR 254 $vsfr254 $s510 */
+#define KVX_SFR_VSFR255 511 /* Virtual SFR 255 $vsfr255 $s511 */
+
+/* Register field masks */
+
+#define KVX_SFR_MEN_MEN_MASK _ULL(0xffff) /* Miscellaneous External Notifications */
+#define KVX_SFR_MEN_MEN_SHIFT 0
+#define KVX_SFR_MEN_MEN_WIDTH 16
+#define KVX_SFR_MEN_MEN_WFXL_MASK _ULL(0xffff)
+#define KVX_SFR_MEN_MEN_WFXL_CLEAR _ULL(0xffff)
+#define KVX_SFR_MEN_MEN_WFXL_SET _ULL(0xffff00000000)
+
+#define KVX_SFR_SYO_Q0_MASK _ULL(0x3) /* Quarter 0 syscalls 0 to 1023 owner */
+#define KVX_SFR_SYO_Q0_SHIFT 0
+#define KVX_SFR_SYO_Q0_WIDTH 2
+#define KVX_SFR_SYO_Q0_WFXL_MASK _ULL(0x3)
+#define KVX_SFR_SYO_Q0_WFXL_CLEAR _ULL(0x3)
+#define KVX_SFR_SYO_Q0_WFXL_SET _ULL(0x300000000)
+
+#define KVX_SFR_SYO_Q1_MASK _ULL(0xc) /* Quarter 1 syscalls 1024 to 2047 owner */
+#define KVX_SFR_SYO_Q1_SHIFT 2
+#define KVX_SFR_SYO_Q1_WIDTH 2
+#define KVX_SFR_SYO_Q1_WFXL_MASK _ULL(0xc)
+#define KVX_SFR_SYO_Q1_WFXL_CLEAR _ULL(0xc)
+#define KVX_SFR_SYO_Q1_WFXL_SET _ULL(0xc00000000)
+
+#define KVX_SFR_SYO_Q2_MASK _ULL(0x30) /* Quarter 2 syscalls 2048 to 3071 owner */
+#define KVX_SFR_SYO_Q2_SHIFT 4
+#define KVX_SFR_SYO_Q2_WIDTH 2
+#define KVX_SFR_SYO_Q2_WFXL_MASK _ULL(0x30)
+#define KVX_SFR_SYO_Q2_WFXL_CLEAR _ULL(0x30)
+#define KVX_SFR_SYO_Q2_WFXL_SET _ULL(0x3000000000)
+
+#define KVX_SFR_SYO_Q3_MASK _ULL(0xc0) /* Quarter 3 syscalls 3072 to 4095 owner */
+#define KVX_SFR_SYO_Q3_SHIFT 6
+#define KVX_SFR_SYO_Q3_WIDTH 2
+#define KVX_SFR_SYO_Q3_WFXL_MASK _ULL(0xc0)
+#define KVX_SFR_SYO_Q3_WFXL_CLEAR _ULL(0xc0)
+#define KVX_SFR_SYO_Q3_WFXL_SET _ULL(0xc000000000)
+
+#define KVX_SFR_SYOW_Q0_MASK _ULL(0x3) /* Quarter 0 syscalls 0 to 1023 owner */
+#define KVX_SFR_SYOW_Q0_SHIFT 0
+#define KVX_SFR_SYOW_Q0_WIDTH 2
+#define KVX_SFR_SYOW_Q0_WFXL_MASK _ULL(0x3)
+#define KVX_SFR_SYOW_Q0_WFXL_CLEAR _ULL(0x3)
+#define KVX_SFR_SYOW_Q0_WFXL_SET _ULL(0x300000000)
+
+#define KVX_SFR_SYOW_Q1_MASK _ULL(0xc) /* Quarter 1 syscalls 1024 to 2047 owner */
+#define KVX_SFR_SYOW_Q1_SHIFT 2
+#define KVX_SFR_SYOW_Q1_WIDTH 2
+#define KVX_SFR_SYOW_Q1_WFXL_MASK _ULL(0xc)
+#define KVX_SFR_SYOW_Q1_WFXL_CLEAR _ULL(0xc)
+#define KVX_SFR_SYOW_Q1_WFXL_SET _ULL(0xc00000000)
+
+#define KVX_SFR_SYOW_Q2_MASK _ULL(0x30) /* Quarter 2 syscalls 2048 to 3071 owner */
+#define KVX_SFR_SYOW_Q2_SHIFT 4
+#define KVX_SFR_SYOW_Q2_WIDTH 2
+#define KVX_SFR_SYOW_Q2_WFXL_MASK _ULL(0x30)
+#define KVX_SFR_SYOW_Q2_WFXL_CLEAR _ULL(0x30)
+#define KVX_SFR_SYOW_Q2_WFXL_SET _ULL(0x3000000000)
+
+#define KVX_SFR_SYOW_Q3_MASK _ULL(0xc0) /* Quarter 3 syscalls 3072 to 4095 owner */
+#define KVX_SFR_SYOW_Q3_SHIFT 6
+#define KVX_SFR_SYOW_Q3_WIDTH 2
+#define KVX_SFR_SYOW_Q3_WFXL_MASK _ULL(0xc0)
+#define KVX_SFR_SYOW_Q3_WFXL_CLEAR _ULL(0xc0)
+#define KVX_SFR_SYOW_Q3_WFXL_SET _ULL(0xc000000000)
+
+#define KVX_SFR_HTO_OPC_MASK _ULL(0x3) /* OPCode trap owner */
+#define KVX_SFR_HTO_OPC_SHIFT 0
+#define KVX_SFR_HTO_OPC_WIDTH 2
+#define KVX_SFR_HTO_OPC_WFXL_MASK _ULL(0x3)
+#define KVX_SFR_HTO_OPC_WFXL_CLEAR _ULL(0x3)
+#define KVX_SFR_HTO_OPC_WFXL_SET _ULL(0x300000000)
+
+#define KVX_SFR_HTO_DMIS_MASK _ULL(0xc) /* Data MISalign access trap owner */
+#define KVX_SFR_HTO_DMIS_SHIFT 2
+#define KVX_SFR_HTO_DMIS_WIDTH 2
+#define KVX_SFR_HTO_DMIS_WFXL_MASK _ULL(0xc)
+#define KVX_SFR_HTO_DMIS_WFXL_CLEAR _ULL(0xc)
+#define KVX_SFR_HTO_DMIS_WFXL_SET _ULL(0xc00000000)
+
+#define KVX_SFR_HTO_PSYS_MASK _ULL(0x30) /* Program System Error trap owner */
+#define KVX_SFR_HTO_PSYS_SHIFT 4
+#define KVX_SFR_HTO_PSYS_WIDTH 2
+#define KVX_SFR_HTO_PSYS_WFXL_MASK _ULL(0x30)
+#define KVX_SFR_HTO_PSYS_WFXL_CLEAR _ULL(0x30)
+#define KVX_SFR_HTO_PSYS_WFXL_SET _ULL(0x3000000000)
+
+#define KVX_SFR_HTO_DSYS_MASK _ULL(0xc0) /* Data System Error trap owner */
+#define KVX_SFR_HTO_DSYS_SHIFT 6
+#define KVX_SFR_HTO_DSYS_WIDTH 2
+#define KVX_SFR_HTO_DSYS_WFXL_MASK _ULL(0xc0)
+#define KVX_SFR_HTO_DSYS_WFXL_CLEAR _ULL(0xc0)
+#define KVX_SFR_HTO_DSYS_WFXL_SET _ULL(0xc000000000)
+
+#define KVX_SFR_HTO_DECCG_MASK _ULL(0x300) /* Double ECC traps group owner */
+#define KVX_SFR_HTO_DECCG_SHIFT 8
+#define KVX_SFR_HTO_DECCG_WIDTH 2
+#define KVX_SFR_HTO_DECCG_WFXL_MASK _ULL(0x300)
+#define KVX_SFR_HTO_DECCG_WFXL_CLEAR _ULL(0x300)
+#define KVX_SFR_HTO_DECCG_WFXL_SET _ULL(0x30000000000)
+
+#define KVX_SFR_HTO_SECCG_MASK _ULL(0xc00) /* Single ECC traps group owner */
+#define KVX_SFR_HTO_SECCG_SHIFT 10
+#define KVX_SFR_HTO_SECCG_WIDTH 2
+#define KVX_SFR_HTO_SECCG_WFXL_MASK _ULL(0xc00)
+#define KVX_SFR_HTO_SECCG_WFXL_CLEAR _ULL(0xc00)
+#define KVX_SFR_HTO_SECCG_WFXL_SET _ULL(0xc0000000000)
+
+#define KVX_SFR_HTO_NOMAP_MASK _ULL(0x3000) /* No mapping trap owner */
+#define KVX_SFR_HTO_NOMAP_SHIFT 12
+#define KVX_SFR_HTO_NOMAP_WIDTH 2
+#define KVX_SFR_HTO_NOMAP_WFXL_MASK _ULL(0x3000)
+#define KVX_SFR_HTO_NOMAP_WFXL_CLEAR _ULL(0x3000)
+#define KVX_SFR_HTO_NOMAP_WFXL_SET _ULL(0x300000000000)
+
+#define KVX_SFR_HTO_PROT_MASK _ULL(0xc000) /* PROTection trap owner */
+#define KVX_SFR_HTO_PROT_SHIFT 14
+#define KVX_SFR_HTO_PROT_WIDTH 2
+#define KVX_SFR_HTO_PROT_WFXL_MASK _ULL(0xc000)
+#define KVX_SFR_HTO_PROT_WFXL_CLEAR _ULL(0xc000)
+#define KVX_SFR_HTO_PROT_WFXL_SET _ULL(0xc00000000000)
+
+#define KVX_SFR_HTO_W2CL_MASK _ULL(0x30000) /* Write to clean trap owner */
+#define KVX_SFR_HTO_W2CL_SHIFT 16
+#define KVX_SFR_HTO_W2CL_WIDTH 2
+#define KVX_SFR_HTO_W2CL_WFXL_MASK _ULL(0x30000)
+#define KVX_SFR_HTO_W2CL_WFXL_CLEAR _ULL(0x30000)
+#define KVX_SFR_HTO_W2CL_WFXL_SET _ULL(0x3000000000000)
+
+#define KVX_SFR_HTO_A2CL_MASK _ULL(0xc0000) /* Atomic to clean trap owner */
+#define KVX_SFR_HTO_A2CL_SHIFT 18
+#define KVX_SFR_HTO_A2CL_WIDTH 2
+#define KVX_SFR_HTO_A2CL_WFXL_MASK _ULL(0xc0000)
+#define KVX_SFR_HTO_A2CL_WFXL_CLEAR _ULL(0xc0000)
+#define KVX_SFR_HTO_A2CL_WFXL_SET _ULL(0xc000000000000)
+
+#define KVX_SFR_HTO_DE_MASK _ULL(0x300000) /* Double Exception trap owner */
+#define KVX_SFR_HTO_DE_SHIFT 20
+#define KVX_SFR_HTO_DE_WIDTH 2
+#define KVX_SFR_HTO_DE_WFXL_MASK _ULL(0x300000)
+#define KVX_SFR_HTO_DE_WFXL_CLEAR _ULL(0x300000)
+#define KVX_SFR_HTO_DE_WFXL_SET _ULL(0x30000000000000)
+
+#define KVX_SFR_HTO_VSFR_MASK _ULL(0xc00000) /* Virtual SFR trap owner */
+#define KVX_SFR_HTO_VSFR_SHIFT 22
+#define KVX_SFR_HTO_VSFR_WIDTH 2
+#define KVX_SFR_HTO_VSFR_WFXL_MASK _ULL(0xc00000)
+#define KVX_SFR_HTO_VSFR_WFXL_CLEAR _ULL(0xc00000)
+#define KVX_SFR_HTO_VSFR_WFXL_SET _ULL(0xc0000000000000)
+
+#define KVX_SFR_HTO_PLO_MASK _ULL(0x3000000) /* Privilege Level Overflow trap owner */
+#define KVX_SFR_HTO_PLO_SHIFT 24
+#define KVX_SFR_HTO_PLO_WIDTH 2
+#define KVX_SFR_HTO_PLO_WFXL_MASK _ULL(0x3000000)
+#define KVX_SFR_HTO_PLO_WFXL_CLEAR _ULL(0x3000000)
+#define KVX_SFR_HTO_PLO_WFXL_SET _ULL(0x300000000000000)
+
+#define KVX_SFR_HTOW_OPC_MASK _ULL(0x3) /* OPCode trap owner */
+#define KVX_SFR_HTOW_OPC_SHIFT 0
+#define KVX_SFR_HTOW_OPC_WIDTH 2
+#define KVX_SFR_HTOW_OPC_WFXL_MASK _ULL(0x3)
+#define KVX_SFR_HTOW_OPC_WFXL_CLEAR _ULL(0x3)
+#define KVX_SFR_HTOW_OPC_WFXL_SET _ULL(0x300000000)
+
+#define KVX_SFR_HTOW_DMIS_MASK _ULL(0xc) /* Data MISalign access trap owner */
+#define KVX_SFR_HTOW_DMIS_SHIFT 2
+#define KVX_SFR_HTOW_DMIS_WIDTH 2
+#define KVX_SFR_HTOW_DMIS_WFXL_MASK _ULL(0xc)
+#define KVX_SFR_HTOW_DMIS_WFXL_CLEAR _ULL(0xc)
+#define KVX_SFR_HTOW_DMIS_WFXL_SET _ULL(0xc00000000)
+
+#define KVX_SFR_HTOW_PSYS_MASK _ULL(0x30) /* Program System Error trap owner */
+#define KVX_SFR_HTOW_PSYS_SHIFT 4
+#define KVX_SFR_HTOW_PSYS_WIDTH 2
+#define KVX_SFR_HTOW_PSYS_WFXL_MASK _ULL(0x30)
+#define KVX_SFR_HTOW_PSYS_WFXL_CLEAR _ULL(0x30)
+#define KVX_SFR_HTOW_PSYS_WFXL_SET _ULL(0x3000000000)
+
+#define KVX_SFR_HTOW_DSYS_MASK _ULL(0xc0) /* Data System Error trap owner */
+#define KVX_SFR_HTOW_DSYS_SHIFT 6
+#define KVX_SFR_HTOW_DSYS_WIDTH 2
+#define KVX_SFR_HTOW_DSYS_WFXL_MASK _ULL(0xc0)
+#define KVX_SFR_HTOW_DSYS_WFXL_CLEAR _ULL(0xc0)
+#define KVX_SFR_HTOW_DSYS_WFXL_SET _ULL(0xc000000000)
+
+#define KVX_SFR_HTOW_DECCG_MASK _ULL(0x300) /* Double ECC traps group owner */
+#define KVX_SFR_HTOW_DECCG_SHIFT 8
+#define KVX_SFR_HTOW_DECCG_WIDTH 2
+#define KVX_SFR_HTOW_DECCG_WFXL_MASK _ULL(0x300)
+#define KVX_SFR_HTOW_DECCG_WFXL_CLEAR _ULL(0x300)
+#define KVX_SFR_HTOW_DECCG_WFXL_SET _ULL(0x30000000000)
+
+#define KVX_SFR_HTOW_SECCG_MASK _ULL(0xc00) /* Single ECC traps group owner */
+#define KVX_SFR_HTOW_SECCG_SHIFT 10
+#define KVX_SFR_HTOW_SECCG_WIDTH 2
+#define KVX_SFR_HTOW_SECCG_WFXL_MASK _ULL(0xc00)
+#define KVX_SFR_HTOW_SECCG_WFXL_CLEAR _ULL(0xc00)
+#define KVX_SFR_HTOW_SECCG_WFXL_SET _ULL(0xc0000000000)
+
+#define KVX_SFR_HTOW_NOMAP_MASK _ULL(0x3000) /* No mapping trap owner */
+#define KVX_SFR_HTOW_NOMAP_SHIFT 12
+#define KVX_SFR_HTOW_NOMAP_WIDTH 2
+#define KVX_SFR_HTOW_NOMAP_WFXL_MASK _ULL(0x3000)
+#define KVX_SFR_HTOW_NOMAP_WFXL_CLEAR _ULL(0x3000)
+#define KVX_SFR_HTOW_NOMAP_WFXL_SET _ULL(0x300000000000)
+
+#define KVX_SFR_HTOW_PROT_MASK _ULL(0xc000) /* PROTection trap owner */
+#define KVX_SFR_HTOW_PROT_SHIFT 14
+#define KVX_SFR_HTOW_PROT_WIDTH 2
+#define KVX_SFR_HTOW_PROT_WFXL_MASK _ULL(0xc000)
+#define KVX_SFR_HTOW_PROT_WFXL_CLEAR _ULL(0xc000)
+#define KVX_SFR_HTOW_PROT_WFXL_SET _ULL(0xc00000000000)
+
+#define KVX_SFR_HTOW_W2CL_MASK _ULL(0x30000) /* Write to clean trap owner */
+#define KVX_SFR_HTOW_W2CL_SHIFT 16
+#define KVX_SFR_HTOW_W2CL_WIDTH 2
+#define KVX_SFR_HTOW_W2CL_WFXL_MASK _ULL(0x30000)
+#define KVX_SFR_HTOW_W2CL_WFXL_CLEAR _ULL(0x30000)
+#define KVX_SFR_HTOW_W2CL_WFXL_SET _ULL(0x3000000000000)
+
+#define KVX_SFR_HTOW_A2CL_MASK _ULL(0xc0000) /* Atomic to clean trap owner */
+#define KVX_SFR_HTOW_A2CL_SHIFT 18
+#define KVX_SFR_HTOW_A2CL_WIDTH 2
+#define KVX_SFR_HTOW_A2CL_WFXL_MASK _ULL(0xc0000)
+#define KVX_SFR_HTOW_A2CL_WFXL_CLEAR _ULL(0xc0000)
+#define KVX_SFR_HTOW_A2CL_WFXL_SET _ULL(0xc000000000000)
+
+#define KVX_SFR_HTOW_DE_MASK _ULL(0x300000) /* Double Exception trap owner */
+#define KVX_SFR_HTOW_DE_SHIFT 20
+#define KVX_SFR_HTOW_DE_WIDTH 2
+#define KVX_SFR_HTOW_DE_WFXL_MASK _ULL(0x300000)
+#define KVX_SFR_HTOW_DE_WFXL_CLEAR _ULL(0x300000)
+#define KVX_SFR_HTOW_DE_WFXL_SET _ULL(0x30000000000000)
+
+#define KVX_SFR_HTOW_VSFR_MASK _ULL(0xc00000) /* Virtual SFR trap owner */
+#define KVX_SFR_HTOW_VSFR_SHIFT 22
+#define KVX_SFR_HTOW_VSFR_WIDTH 2
+#define KVX_SFR_HTOW_VSFR_WFXL_MASK _ULL(0xc00000)
+#define KVX_SFR_HTOW_VSFR_WFXL_CLEAR _ULL(0xc00000)
+#define KVX_SFR_HTOW_VSFR_WFXL_SET _ULL(0xc0000000000000)
+
+#define KVX_SFR_HTOW_PLO_MASK _ULL(0x3000000) /* Privilege Level Overflow trap owner */
+#define KVX_SFR_HTOW_PLO_SHIFT 24
+#define KVX_SFR_HTOW_PLO_WIDTH 2
+#define KVX_SFR_HTOW_PLO_WFXL_MASK _ULL(0x3000000)
+#define KVX_SFR_HTOW_PLO_WFXL_CLEAR _ULL(0x3000000)
+#define KVX_SFR_HTOW_PLO_WFXL_SET _ULL(0x300000000000000)
+
+#define KVX_SFR_ITO_IT0_MASK _ULL(0x3) /* Interrupt 0 owner */
+#define KVX_SFR_ITO_IT0_SHIFT 0
+#define KVX_SFR_ITO_IT0_WIDTH 2
+#define KVX_SFR_ITO_IT0_WFXL_MASK _ULL(0x3)
+#define KVX_SFR_ITO_IT0_WFXL_CLEAR _ULL(0x3)
+#define KVX_SFR_ITO_IT0_WFXL_SET _ULL(0x300000000)
+
+#define KVX_SFR_ITO_IT1_MASK _ULL(0xc) /* Interrupt 1 owner */
+#define KVX_SFR_ITO_IT1_SHIFT 2
+#define KVX_SFR_ITO_IT1_WIDTH 2
+#define KVX_SFR_ITO_IT1_WFXL_MASK _ULL(0xc)
+#define KVX_SFR_ITO_IT1_WFXL_CLEAR _ULL(0xc)
+#define KVX_SFR_ITO_IT1_WFXL_SET _ULL(0xc00000000)
+
+#define KVX_SFR_ITO_IT2_MASK _ULL(0x30) /* Interrupt 2 owner */
+#define KVX_SFR_ITO_IT2_SHIFT 4
+#define KVX_SFR_ITO_IT2_WIDTH 2
+#define KVX_SFR_ITO_IT2_WFXL_MASK _ULL(0x30)
+#define KVX_SFR_ITO_IT2_WFXL_CLEAR _ULL(0x30)
+#define KVX_SFR_ITO_IT2_WFXL_SET _ULL(0x3000000000)
+
+#define KVX_SFR_ITO_IT3_MASK _ULL(0xc0) /* Interrupt 3 owner */
+#define KVX_SFR_ITO_IT3_SHIFT 6
+#define KVX_SFR_ITO_IT3_WIDTH 2
+#define KVX_SFR_ITO_IT3_WFXL_MASK _ULL(0xc0)
+#define KVX_SFR_ITO_IT3_WFXL_CLEAR _ULL(0xc0)
+#define KVX_SFR_ITO_IT3_WFXL_SET _ULL(0xc000000000)
+
+#define KVX_SFR_ITO_IT4_MASK _ULL(0x300) /* Interrupt 4 owner */
+#define KVX_SFR_ITO_IT4_SHIFT 8
+#define KVX_SFR_ITO_IT4_WIDTH 2
+#define KVX_SFR_ITO_IT4_WFXL_MASK _ULL(0x300)
+#define KVX_SFR_ITO_IT4_WFXL_CLEAR _ULL(0x300)
+#define KVX_SFR_ITO_IT4_WFXL_SET _ULL(0x30000000000)
+
+#define KVX_SFR_ITO_IT5_MASK _ULL(0xc00) /* Interrupt 5 owner */
+#define KVX_SFR_ITO_IT5_SHIFT 10
+#define KVX_SFR_ITO_IT5_WIDTH 2
+#define KVX_SFR_ITO_IT5_WFXL_MASK _ULL(0xc00)
+#define KVX_SFR_ITO_IT5_WFXL_CLEAR _ULL(0xc00)
+#define KVX_SFR_ITO_IT5_WFXL_SET _ULL(0xc0000000000)
+
+#define KVX_SFR_ITO_IT6_MASK _ULL(0x3000) /* Interrupt 6 owner */
+#define KVX_SFR_ITO_IT6_SHIFT 12
+#define KVX_SFR_ITO_IT6_WIDTH 2
+#define KVX_SFR_ITO_IT6_WFXL_MASK _ULL(0x3000)
+#define KVX_SFR_ITO_IT6_WFXL_CLEAR _ULL(0x3000)
+#define KVX_SFR_ITO_IT6_WFXL_SET _ULL(0x300000000000)
+
+#define KVX_SFR_ITO_IT7_MASK _ULL(0xc000) /* Interrupt 7 owner */
+#define KVX_SFR_ITO_IT7_SHIFT 14
+#define KVX_SFR_ITO_IT7_WIDTH 2
+#define KVX_SFR_ITO_IT7_WFXL_MASK _ULL(0xc000)
+#define KVX_SFR_ITO_IT7_WFXL_CLEAR _ULL(0xc000)
+#define KVX_SFR_ITO_IT7_WFXL_SET _ULL(0xc00000000000)
+
+#define KVX_SFR_ITO_IT8_MASK _ULL(0x30000) /* Interrupt 8 owner */
+#define KVX_SFR_ITO_IT8_SHIFT 16
+#define KVX_SFR_ITO_IT8_WIDTH 2
+#define KVX_SFR_ITO_IT8_WFXL_MASK _ULL(0x30000)
+#define KVX_SFR_ITO_IT8_WFXL_CLEAR _ULL(0x30000)
+#define KVX_SFR_ITO_IT8_WFXL_SET _ULL(0x3000000000000)
+
+#define KVX_SFR_ITO_IT9_MASK _ULL(0xc0000) /* Interrupt 9 owner */
+#define KVX_SFR_ITO_IT9_SHIFT 18
+#define KVX_SFR_ITO_IT9_WIDTH 2
+#define KVX_SFR_ITO_IT9_WFXL_MASK _ULL(0xc0000)
+#define KVX_SFR_ITO_IT9_WFXL_CLEAR _ULL(0xc0000)
+#define KVX_SFR_ITO_IT9_WFXL_SET _ULL(0xc000000000000)
+
+#define KVX_SFR_ITO_IT10_MASK _ULL(0x300000) /* Interrupt 10 owner */
+#define KVX_SFR_ITO_IT10_SHIFT 20
+#define KVX_SFR_ITO_IT10_WIDTH 2
+#define KVX_SFR_ITO_IT10_WFXL_MASK _ULL(0x300000)
+#define KVX_SFR_ITO_IT10_WFXL_CLEAR _ULL(0x300000)
+#define KVX_SFR_ITO_IT10_WFXL_SET _ULL(0x30000000000000)
+
+#define KVX_SFR_ITO_IT11_MASK _ULL(0xc00000) /* Interrupt 11 owner */
+#define KVX_SFR_ITO_IT11_SHIFT 22
+#define KVX_SFR_ITO_IT11_WIDTH 2
+#define KVX_SFR_ITO_IT11_WFXL_MASK _ULL(0xc00000)
+#define KVX_SFR_ITO_IT11_WFXL_CLEAR _ULL(0xc00000)
+#define KVX_SFR_ITO_IT11_WFXL_SET _ULL(0xc0000000000000)
+
+#define KVX_SFR_ITO_IT12_MASK _ULL(0x3000000) /* Interrupt 12 owner */
+#define KVX_SFR_ITO_IT12_SHIFT 24
+#define KVX_SFR_ITO_IT12_WIDTH 2
+#define KVX_SFR_ITO_IT12_WFXL_MASK _ULL(0x3000000)
+#define KVX_SFR_ITO_IT12_WFXL_CLEAR _ULL(0x3000000)
+#define KVX_SFR_ITO_IT12_WFXL_SET _ULL(0x300000000000000)
+
+#define KVX_SFR_ITO_IT13_MASK _ULL(0xc000000) /* Interrupt 13 owner */
+#define KVX_SFR_ITO_IT13_SHIFT 26
+#define KVX_SFR_ITO_IT13_WIDTH 2
+#define KVX_SFR_ITO_IT13_WFXL_MASK _ULL(0xc000000)
+#define KVX_SFR_ITO_IT13_WFXL_CLEAR _ULL(0xc000000)
+#define KVX_SFR_ITO_IT13_WFXL_SET _ULL(0xc00000000000000)
+
+#define KVX_SFR_ITO_IT14_MASK _ULL(0x30000000) /* Interrupt 14 owner */
+#define KVX_SFR_ITO_IT14_SHIFT 28
+#define KVX_SFR_ITO_IT14_WIDTH 2
+#define KVX_SFR_ITO_IT14_WFXL_MASK _ULL(0x30000000)
+#define KVX_SFR_ITO_IT14_WFXL_CLEAR _ULL(0x30000000)
+#define KVX_SFR_ITO_IT14_WFXL_SET _ULL(0x3000000000000000)
+
+#define KVX_SFR_ITO_IT15_MASK _ULL(0xc0000000) /* Interrupt 15 owner */
+#define KVX_SFR_ITO_IT15_SHIFT 30
+#define KVX_SFR_ITO_IT15_WIDTH 2
+#define KVX_SFR_ITO_IT15_WFXL_MASK _ULL(0xc0000000)
+#define KVX_SFR_ITO_IT15_WFXL_CLEAR _ULL(0xc0000000)
+#define KVX_SFR_ITO_IT15_WFXL_SET _ULL(0xc000000000000000)
+
+#define KVX_SFR_ITO_IT16_MASK _ULL(0x300000000) /* Interrupt 16 owner */
+#define KVX_SFR_ITO_IT16_SHIFT 32
+#define KVX_SFR_ITO_IT16_WIDTH 2
+#define KVX_SFR_ITO_IT16_WFXM_MASK _ULL(0x300000000)
+#define KVX_SFR_ITO_IT16_WFXM_CLEAR _ULL(0x3)
+#define KVX_SFR_ITO_IT16_WFXM_SET _ULL(0x300000000)
+
+#define KVX_SFR_ITO_IT17_MASK _ULL(0xc00000000) /* Interrupt 17 owner */
+#define KVX_SFR_ITO_IT17_SHIFT 34
+#define KVX_SFR_ITO_IT17_WIDTH 2
+#define KVX_SFR_ITO_IT17_WFXM_MASK _ULL(0xc00000000)
+#define KVX_SFR_ITO_IT17_WFXM_CLEAR _ULL(0xc)
+#define KVX_SFR_ITO_IT17_WFXM_SET _ULL(0xc00000000)
+
+#define KVX_SFR_ITO_IT18_MASK _ULL(0x3000000000) /* Interrupt 18 owner */
+#define KVX_SFR_ITO_IT18_SHIFT 36
+#define KVX_SFR_ITO_IT18_WIDTH 2
+#define KVX_SFR_ITO_IT18_WFXM_MASK _ULL(0x3000000000)
+#define KVX_SFR_ITO_IT18_WFXM_CLEAR _ULL(0x30)
+#define KVX_SFR_ITO_IT18_WFXM_SET _ULL(0x3000000000)
+
+#define KVX_SFR_ITO_IT19_MASK _ULL(0xc000000000) /* Interrupt 19 owner */
+#define KVX_SFR_ITO_IT19_SHIFT 38
+#define KVX_SFR_ITO_IT19_WIDTH 2
+#define KVX_SFR_ITO_IT19_WFXM_MASK _ULL(0xc000000000)
+#define KVX_SFR_ITO_IT19_WFXM_CLEAR _ULL(0xc0)
+#define KVX_SFR_ITO_IT19_WFXM_SET _ULL(0xc000000000)
+
+#define KVX_SFR_ITO_IT20_MASK _ULL(0x30000000000) /* Interrupt 20 owner */
+#define KVX_SFR_ITO_IT20_SHIFT 40
+#define KVX_SFR_ITO_IT20_WIDTH 2
+#define KVX_SFR_ITO_IT20_WFXM_MASK _ULL(0x30000000000)
+#define KVX_SFR_ITO_IT20_WFXM_CLEAR _ULL(0x300)
+#define KVX_SFR_ITO_IT20_WFXM_SET _ULL(0x30000000000)
+
+#define KVX_SFR_ITO_IT21_MASK _ULL(0xc0000000000) /* Interrupt 21 owner */
+#define KVX_SFR_ITO_IT21_SHIFT 42
+#define KVX_SFR_ITO_IT21_WIDTH 2
+#define KVX_SFR_ITO_IT21_WFXM_MASK _ULL(0xc0000000000)
+#define KVX_SFR_ITO_IT21_WFXM_CLEAR _ULL(0xc00)
+#define KVX_SFR_ITO_IT21_WFXM_SET _ULL(0xc0000000000)
+
+#define KVX_SFR_ITO_IT22_MASK _ULL(0x300000000000) /* Interrupt 22 owner */
+#define KVX_SFR_ITO_IT22_SHIFT 44
+#define KVX_SFR_ITO_IT22_WIDTH 2
+#define KVX_SFR_ITO_IT22_WFXM_MASK _ULL(0x300000000000)
+#define KVX_SFR_ITO_IT22_WFXM_CLEAR _ULL(0x3000)
+#define KVX_SFR_ITO_IT22_WFXM_SET _ULL(0x300000000000)
+
+#define KVX_SFR_ITO_IT23_MASK _ULL(0xc00000000000) /* Interrupt 23 owner */
+#define KVX_SFR_ITO_IT23_SHIFT 46
+#define KVX_SFR_ITO_IT23_WIDTH 2
+#define KVX_SFR_ITO_IT23_WFXM_MASK _ULL(0xc00000000000)
+#define KVX_SFR_ITO_IT23_WFXM_CLEAR _ULL(0xc000)
+#define KVX_SFR_ITO_IT23_WFXM_SET _ULL(0xc00000000000)
+
+#define KVX_SFR_ITO_IT24_MASK _ULL(0x3000000000000) /* Interrupt 24 owner */
+#define KVX_SFR_ITO_IT24_SHIFT 48
+#define KVX_SFR_ITO_IT24_WIDTH 2
+#define KVX_SFR_ITO_IT24_WFXM_MASK _ULL(0x3000000000000)
+#define KVX_SFR_ITO_IT24_WFXM_CLEAR _ULL(0x30000)
+#define KVX_SFR_ITO_IT24_WFXM_SET _ULL(0x3000000000000)
+
+#define KVX_SFR_ITO_IT25_MASK _ULL(0xc000000000000) /* Interrupt 25 owner */
+#define KVX_SFR_ITO_IT25_SHIFT 50
+#define KVX_SFR_ITO_IT25_WIDTH 2
+#define KVX_SFR_ITO_IT25_WFXM_MASK _ULL(0xc000000000000)
+#define KVX_SFR_ITO_IT25_WFXM_CLEAR _ULL(0xc0000)
+#define KVX_SFR_ITO_IT25_WFXM_SET _ULL(0xc000000000000)
+
+#define KVX_SFR_ITO_IT26_MASK _ULL(0x30000000000000) /* Interrupt 26 owner */
+#define KVX_SFR_ITO_IT26_SHIFT 52
+#define KVX_SFR_ITO_IT26_WIDTH 2
+#define KVX_SFR_ITO_IT26_WFXM_MASK _ULL(0x30000000000000)
+#define KVX_SFR_ITO_IT26_WFXM_CLEAR _ULL(0x300000)
+#define KVX_SFR_ITO_IT26_WFXM_SET _ULL(0x30000000000000)
+
+#define KVX_SFR_ITO_IT27_MASK _ULL(0xc0000000000000) /* Interrupt 27 owner */
+#define KVX_SFR_ITO_IT27_SHIFT 54
+#define KVX_SFR_ITO_IT27_WIDTH 2
+#define KVX_SFR_ITO_IT27_WFXM_MASK _ULL(0xc0000000000000)
+#define KVX_SFR_ITO_IT27_WFXM_CLEAR _ULL(0xc00000)
+#define KVX_SFR_ITO_IT27_WFXM_SET _ULL(0xc0000000000000)
+
+#define KVX_SFR_ITO_IT28_MASK _ULL(0x300000000000000) /* Interrupt 28 owner */
+#define KVX_SFR_ITO_IT28_SHIFT 56
+#define KVX_SFR_ITO_IT28_WIDTH 2
+#define KVX_SFR_ITO_IT28_WFXM_MASK _ULL(0x300000000000000)
+#define KVX_SFR_ITO_IT28_WFXM_CLEAR _ULL(0x3000000)
+#define KVX_SFR_ITO_IT28_WFXM_SET _ULL(0x300000000000000)
+
+#define KVX_SFR_ITO_IT29_MASK _ULL(0xc00000000000000) /* Interrupt 29 owner */
+#define KVX_SFR_ITO_IT29_SHIFT 58
+#define KVX_SFR_ITO_IT29_WIDTH 2
+#define KVX_SFR_ITO_IT29_WFXM_MASK _ULL(0xc00000000000000)
+#define KVX_SFR_ITO_IT29_WFXM_CLEAR _ULL(0xc000000)
+#define KVX_SFR_ITO_IT29_WFXM_SET _ULL(0xc00000000000000)
+
+#define KVX_SFR_ITO_IT30_MASK _ULL(0x3000000000000000) /* Interrupt 30 owner */
+#define KVX_SFR_ITO_IT30_SHIFT 60
+#define KVX_SFR_ITO_IT30_WIDTH 2
+#define KVX_SFR_ITO_IT30_WFXM_MASK _ULL(0x3000000000000000)
+#define KVX_SFR_ITO_IT30_WFXM_CLEAR _ULL(0x30000000)
+#define KVX_SFR_ITO_IT30_WFXM_SET _ULL(0x3000000000000000)
+
+#define KVX_SFR_ITO_IT31_MASK _ULL(0xc000000000000000) /* Interrupt 31 owner */
+#define KVX_SFR_ITO_IT31_SHIFT 62
+#define KVX_SFR_ITO_IT31_WIDTH 2
+#define KVX_SFR_ITO_IT31_WFXM_MASK _ULL(0xc000000000000000)
+#define KVX_SFR_ITO_IT31_WFXM_CLEAR _ULL(0xc0000000)
+#define KVX_SFR_ITO_IT31_WFXM_SET _ULL(0xc000000000000000)
+
+#define KVX_SFR_ILE_IT0_MASK _ULL(0x1) /* Interrupt 0 owner */
+#define KVX_SFR_ILE_IT0_SHIFT 0
+#define KVX_SFR_ILE_IT0_WIDTH 1
+#define KVX_SFR_ILE_IT0_WFXL_MASK _ULL(0x1)
+#define KVX_SFR_ILE_IT0_WFXL_CLEAR _ULL(0x1)
+#define KVX_SFR_ILE_IT0_WFXL_SET _ULL(0x100000000)
+
+#define KVX_SFR_ILE_IT1_MASK _ULL(0x2) /* Interrupt 1 owner */
+#define KVX_SFR_ILE_IT1_SHIFT 1
+#define KVX_SFR_ILE_IT1_WIDTH 1
+#define KVX_SFR_ILE_IT1_WFXL_MASK _ULL(0x2)
+#define KVX_SFR_ILE_IT1_WFXL_CLEAR _ULL(0x2)
+#define KVX_SFR_ILE_IT1_WFXL_SET _ULL(0x200000000)
+
+#define KVX_SFR_ILE_IT2_MASK _ULL(0x4) /* Interrupt 2 owner */
+#define KVX_SFR_ILE_IT2_SHIFT 2
+#define KVX_SFR_ILE_IT2_WIDTH 1
+#define KVX_SFR_ILE_IT2_WFXL_MASK _ULL(0x4)
+#define KVX_SFR_ILE_IT2_WFXL_CLEAR _ULL(0x4)
+#define KVX_SFR_ILE_IT2_WFXL_SET _ULL(0x400000000)
+
+#define KVX_SFR_ILE_IT3_MASK _ULL(0x8) /* Interrupt 3 owner */
+#define KVX_SFR_ILE_IT3_SHIFT 3
+#define KVX_SFR_ILE_IT3_WIDTH 1
+#define KVX_SFR_ILE_IT3_WFXL_MASK _ULL(0x8)
+#define KVX_SFR_ILE_IT3_WFXL_CLEAR _ULL(0x8)
+#define KVX_SFR_ILE_IT3_WFXL_SET _ULL(0x800000000)
+
+#define KVX_SFR_ILE_IT4_MASK _ULL(0x10) /* Interrupt 4 owner */
+#define KVX_SFR_ILE_IT4_SHIFT 4
+#define KVX_SFR_ILE_IT4_WIDTH 1
+#define KVX_SFR_ILE_IT4_WFXL_MASK _ULL(0x10)
+#define KVX_SFR_ILE_IT4_WFXL_CLEAR _ULL(0x10)
+#define KVX_SFR_ILE_IT4_WFXL_SET _ULL(0x1000000000)
+
+#define KVX_SFR_ILE_IT5_MASK _ULL(0x20) /* Interrupt 5 owner */
+#define KVX_SFR_ILE_IT5_SHIFT 5
+#define KVX_SFR_ILE_IT5_WIDTH 1
+#define KVX_SFR_ILE_IT5_WFXL_MASK _ULL(0x20)
+#define KVX_SFR_ILE_IT5_WFXL_CLEAR _ULL(0x20)
+#define KVX_SFR_ILE_IT5_WFXL_SET _ULL(0x2000000000)
+
+#define KVX_SFR_ILE_IT6_MASK _ULL(0x40) /* Interrupt 6 owner */
+#define KVX_SFR_ILE_IT6_SHIFT 6
+#define KVX_SFR_ILE_IT6_WIDTH 1
+#define KVX_SFR_ILE_IT6_WFXL_MASK _ULL(0x40)
+#define KVX_SFR_ILE_IT6_WFXL_CLEAR _ULL(0x40)
+#define KVX_SFR_ILE_IT6_WFXL_SET _ULL(0x4000000000)
+
+#define KVX_SFR_ILE_IT7_MASK _ULL(0x80) /* Interrupt 7 owner */
+#define KVX_SFR_ILE_IT7_SHIFT 7
+#define KVX_SFR_ILE_IT7_WIDTH 1
+#define KVX_SFR_ILE_IT7_WFXL_MASK _ULL(0x80)
+#define KVX_SFR_ILE_IT7_WFXL_CLEAR _ULL(0x80)
+#define KVX_SFR_ILE_IT7_WFXL_SET _ULL(0x8000000000)
+
+#define KVX_SFR_ILE_IT8_MASK _ULL(0x100) /* Interrupt 8 owner */
+#define KVX_SFR_ILE_IT8_SHIFT 8
+#define KVX_SFR_ILE_IT8_WIDTH 1
+#define KVX_SFR_ILE_IT8_WFXL_MASK _ULL(0x100)
+#define KVX_SFR_ILE_IT8_WFXL_CLEAR _ULL(0x100)
+#define KVX_SFR_ILE_IT8_WFXL_SET _ULL(0x10000000000)
+
+#define KVX_SFR_ILE_IT9_MASK _ULL(0x200) /* Interrupt 9 owner */
+#define KVX_SFR_ILE_IT9_SHIFT 9
+#define KVX_SFR_ILE_IT9_WIDTH 1
+#define KVX_SFR_ILE_IT9_WFXL_MASK _ULL(0x200)
+#define KVX_SFR_ILE_IT9_WFXL_CLEAR _ULL(0x200)
+#define KVX_SFR_ILE_IT9_WFXL_SET _ULL(0x20000000000)
+
+#define KVX_SFR_ILE_IT10_MASK _ULL(0x400) /* Interrupt 10 owner */
+#define KVX_SFR_ILE_IT10_SHIFT 10
+#define KVX_SFR_ILE_IT10_WIDTH 1
+#define KVX_SFR_ILE_IT10_WFXL_MASK _ULL(0x400)
+#define KVX_SFR_ILE_IT10_WFXL_CLEAR _ULL(0x400)
+#define KVX_SFR_ILE_IT10_WFXL_SET _ULL(0x40000000000)
+
+#define KVX_SFR_ILE_IT11_MASK _ULL(0x800) /* Interrupt 11 owner */
+#define KVX_SFR_ILE_IT11_SHIFT 11
+#define KVX_SFR_ILE_IT11_WIDTH 1
+#define KVX_SFR_ILE_IT11_WFXL_MASK _ULL(0x800)
+#define KVX_SFR_ILE_IT11_WFXL_CLEAR _ULL(0x800)
+#define KVX_SFR_ILE_IT11_WFXL_SET _ULL(0x80000000000)
+
+#define KVX_SFR_ILE_IT12_MASK _ULL(0x1000) /* Interrupt 12 owner */
+#define KVX_SFR_ILE_IT12_SHIFT 12
+#define KVX_SFR_ILE_IT12_WIDTH 1
+#define KVX_SFR_ILE_IT12_WFXL_MASK _ULL(0x1000)
+#define KVX_SFR_ILE_IT12_WFXL_CLEAR _ULL(0x1000)
+#define KVX_SFR_ILE_IT12_WFXL_SET _ULL(0x100000000000)
+
+#define KVX_SFR_ILE_IT13_MASK _ULL(0x2000) /* Interrupt 13 owner */
+#define KVX_SFR_ILE_IT13_SHIFT 13
+#define KVX_SFR_ILE_IT13_WIDTH 1
+#define KVX_SFR_ILE_IT13_WFXL_MASK _ULL(0x2000)
+#define KVX_SFR_ILE_IT13_WFXL_CLEAR _ULL(0x2000)
+#define KVX_SFR_ILE_IT13_WFXL_SET _ULL(0x200000000000)
+
+#define KVX_SFR_ILE_IT14_MASK _ULL(0x4000) /* Interrupt 14 owner */
+#define KVX_SFR_ILE_IT14_SHIFT 14
+#define KVX_SFR_ILE_IT14_WIDTH 1
+#define KVX_SFR_ILE_IT14_WFXL_MASK _ULL(0x4000)
+#define KVX_SFR_ILE_IT14_WFXL_CLEAR _ULL(0x4000)
+#define KVX_SFR_ILE_IT14_WFXL_SET _ULL(0x400000000000)
+
+#define KVX_SFR_ILE_IT15_MASK _ULL(0x8000) /* Interrupt 15 owner */
+#define KVX_SFR_ILE_IT15_SHIFT 15
+#define KVX_SFR_ILE_IT15_WIDTH 1
+#define KVX_SFR_ILE_IT15_WFXL_MASK _ULL(0x8000)
+#define KVX_SFR_ILE_IT15_WFXL_CLEAR _ULL(0x8000)
+#define KVX_SFR_ILE_IT15_WFXL_SET _ULL(0x800000000000)
+
+#define KVX_SFR_ILE_IT16_MASK _ULL(0x10000) /* Interrupt 16 owner */
+#define KVX_SFR_ILE_IT16_SHIFT 16
+#define KVX_SFR_ILE_IT16_WIDTH 1
+#define KVX_SFR_ILE_IT16_WFXL_MASK _ULL(0x10000)
+#define KVX_SFR_ILE_IT16_WFXL_CLEAR _ULL(0x10000)
+#define KVX_SFR_ILE_IT16_WFXL_SET _ULL(0x1000000000000)
+
+#define KVX_SFR_ILE_IT17_MASK _ULL(0x20000) /* Interrupt 17 owner */
+#define KVX_SFR_ILE_IT17_SHIFT 17
+#define KVX_SFR_ILE_IT17_WIDTH 1
+#define KVX_SFR_ILE_IT17_WFXL_MASK _ULL(0x20000)
+#define KVX_SFR_ILE_IT17_WFXL_CLEAR _ULL(0x20000)
+#define KVX_SFR_ILE_IT17_WFXL_SET _ULL(0x2000000000000)
+
+#define KVX_SFR_ILE_IT18_MASK _ULL(0x40000) /* Interrupt 18 owner */
+#define KVX_SFR_ILE_IT18_SHIFT 18
+#define KVX_SFR_ILE_IT18_WIDTH 1
+#define KVX_SFR_ILE_IT18_WFXL_MASK _ULL(0x40000)
+#define KVX_SFR_ILE_IT18_WFXL_CLEAR _ULL(0x40000)
+#define KVX_SFR_ILE_IT18_WFXL_SET _ULL(0x4000000000000)
+
+#define KVX_SFR_ILE_IT19_MASK _ULL(0x80000) /* Interrupt 19 owner */
+#define KVX_SFR_ILE_IT19_SHIFT 19
+#define KVX_SFR_ILE_IT19_WIDTH 1
+#define KVX_SFR_ILE_IT19_WFXL_MASK _ULL(0x80000)
+#define KVX_SFR_ILE_IT19_WFXL_CLEAR _ULL(0x80000)
+#define KVX_SFR_ILE_IT19_WFXL_SET _ULL(0x8000000000000)
+
+#define KVX_SFR_ILE_IT20_MASK _ULL(0x100000) /* Interrupt 20 owner */
+#define KVX_SFR_ILE_IT20_SHIFT 20
+#define KVX_SFR_ILE_IT20_WIDTH 1
+#define KVX_SFR_ILE_IT20_WFXL_MASK _ULL(0x100000)
+#define KVX_SFR_ILE_IT20_WFXL_CLEAR _ULL(0x100000)
+#define KVX_SFR_ILE_IT20_WFXL_SET _ULL(0x10000000000000)
+
+#define KVX_SFR_ILE_IT21_MASK _ULL(0x200000) /* Interrupt 21 owner */
+#define KVX_SFR_ILE_IT21_SHIFT 21
+#define KVX_SFR_ILE_IT21_WIDTH 1
+#define KVX_SFR_ILE_IT21_WFXL_MASK _ULL(0x200000)
+#define KVX_SFR_ILE_IT21_WFXL_CLEAR _ULL(0x200000)
+#define KVX_SFR_ILE_IT21_WFXL_SET _ULL(0x20000000000000)
+
+#define KVX_SFR_ILE_IT22_MASK _ULL(0x400000) /* Interrupt 22 owner */
+#define KVX_SFR_ILE_IT22_SHIFT 22
+#define KVX_SFR_ILE_IT22_WIDTH 1
+#define KVX_SFR_ILE_IT22_WFXL_MASK _ULL(0x400000)
+#define KVX_SFR_ILE_IT22_WFXL_CLEAR _ULL(0x400000)
+#define KVX_SFR_ILE_IT22_WFXL_SET _ULL(0x40000000000000)
+
+#define KVX_SFR_ILE_IT23_MASK _ULL(0x800000) /* Interrupt 23 owner */
+#define KVX_SFR_ILE_IT23_SHIFT 23
+#define KVX_SFR_ILE_IT23_WIDTH 1
+#define KVX_SFR_ILE_IT23_WFXL_MASK _ULL(0x800000)
+#define KVX_SFR_ILE_IT23_WFXL_CLEAR _ULL(0x800000)
+#define KVX_SFR_ILE_IT23_WFXL_SET _ULL(0x80000000000000)
+
+#define KVX_SFR_ILE_IT24_MASK _ULL(0x1000000) /* Interrupt 24 owner */
+#define KVX_SFR_ILE_IT24_SHIFT 24
+#define KVX_SFR_ILE_IT24_WIDTH 1
+#define KVX_SFR_ILE_IT24_WFXL_MASK _ULL(0x1000000)
+#define KVX_SFR_ILE_IT24_WFXL_CLEAR _ULL(0x1000000)
+#define KVX_SFR_ILE_IT24_WFXL_SET _ULL(0x100000000000000)
+
+#define KVX_SFR_ILE_IT25_MASK _ULL(0x2000000) /* Interrupt 25 owner */
+#define KVX_SFR_ILE_IT25_SHIFT 25
+#define KVX_SFR_ILE_IT25_WIDTH 1
+#define KVX_SFR_ILE_IT25_WFXL_MASK _ULL(0x2000000)
+#define KVX_SFR_ILE_IT25_WFXL_CLEAR _ULL(0x2000000)
+#define KVX_SFR_ILE_IT25_WFXL_SET _ULL(0x200000000000000)
+
+#define KVX_SFR_ILE_IT26_MASK _ULL(0x4000000) /* Interrupt 26 owner */
+#define KVX_SFR_ILE_IT26_SHIFT 26
+#define KVX_SFR_ILE_IT26_WIDTH 1
+#define KVX_SFR_ILE_IT26_WFXL_MASK _ULL(0x4000000)
+#define KVX_SFR_ILE_IT26_WFXL_CLEAR _ULL(0x4000000)
+#define KVX_SFR_ILE_IT26_WFXL_SET _ULL(0x400000000000000)
+
+#define KVX_SFR_ILE_IT27_MASK _ULL(0x8000000) /* Interrupt 27 owner */
+#define KVX_SFR_ILE_IT27_SHIFT 27
+#define KVX_SFR_ILE_IT27_WIDTH 1
+#define KVX_SFR_ILE_IT27_WFXL_MASK _ULL(0x8000000)
+#define KVX_SFR_ILE_IT27_WFXL_CLEAR _ULL(0x8000000)
+#define KVX_SFR_ILE_IT27_WFXL_SET _ULL(0x800000000000000)
+
+#define KVX_SFR_ILE_IT28_MASK _ULL(0x10000000) /* Interrupt 28 owner */
+#define KVX_SFR_ILE_IT28_SHIFT 28
+#define KVX_SFR_ILE_IT28_WIDTH 1
+#define KVX_SFR_ILE_IT28_WFXL_MASK _ULL(0x10000000)
+#define KVX_SFR_ILE_IT28_WFXL_CLEAR _ULL(0x10000000)
+#define KVX_SFR_ILE_IT28_WFXL_SET _ULL(0x1000000000000000)
+
+#define KVX_SFR_ILE_IT29_MASK _ULL(0x20000000) /* Interrupt 29 owner */
+#define KVX_SFR_ILE_IT29_SHIFT 29
+#define KVX_SFR_ILE_IT29_WIDTH 1
+#define KVX_SFR_ILE_IT29_WFXL_MASK _ULL(0x20000000)
+#define KVX_SFR_ILE_IT29_WFXL_CLEAR _ULL(0x20000000)
+#define KVX_SFR_ILE_IT29_WFXL_SET _ULL(0x2000000000000000)
+
+#define KVX_SFR_ILE_IT30_MASK _ULL(0x40000000) /* Interrupt 30 owner */
+#define KVX_SFR_ILE_IT30_SHIFT 30
+#define KVX_SFR_ILE_IT30_WIDTH 1
+#define KVX_SFR_ILE_IT30_WFXL_MASK _ULL(0x40000000)
+#define KVX_SFR_ILE_IT30_WFXL_CLEAR _ULL(0x40000000)
+#define KVX_SFR_ILE_IT30_WFXL_SET _ULL(0x4000000000000000)
+
+#define KVX_SFR_ILE_IT31_MASK _ULL(0x80000000) /* Interrupt 31 owner */
+#define KVX_SFR_ILE_IT31_SHIFT 31
+#define KVX_SFR_ILE_IT31_WIDTH 1
+#define KVX_SFR_ILE_IT31_WFXL_MASK _ULL(0x80000000)
+#define KVX_SFR_ILE_IT31_WFXL_CLEAR _ULL(0x80000000)
+#define KVX_SFR_ILE_IT31_WFXL_SET _ULL(0x8000000000000000)
+
+#define KVX_SFR_ILL_IT0_MASK _ULL(0x3) /* Interrupt 0 owner */
+#define KVX_SFR_ILL_IT0_SHIFT 0
+#define KVX_SFR_ILL_IT0_WIDTH 2
+#define KVX_SFR_ILL_IT0_WFXL_MASK _ULL(0x3)
+#define KVX_SFR_ILL_IT0_WFXL_CLEAR _ULL(0x3)
+#define KVX_SFR_ILL_IT0_WFXL_SET _ULL(0x300000000)
+
+#define KVX_SFR_ILL_IT1_MASK _ULL(0xc) /* Interrupt 1 owner */
+#define KVX_SFR_ILL_IT1_SHIFT 2
+#define KVX_SFR_ILL_IT1_WIDTH 2
+#define KVX_SFR_ILL_IT1_WFXL_MASK _ULL(0xc)
+#define KVX_SFR_ILL_IT1_WFXL_CLEAR _ULL(0xc)
+#define KVX_SFR_ILL_IT1_WFXL_SET _ULL(0xc00000000)
+
+#define KVX_SFR_ILL_IT2_MASK _ULL(0x30) /* Interrupt 2 owner */
+#define KVX_SFR_ILL_IT2_SHIFT 4
+#define KVX_SFR_ILL_IT2_WIDTH 2
+#define KVX_SFR_ILL_IT2_WFXL_MASK _ULL(0x30)
+#define KVX_SFR_ILL_IT2_WFXL_CLEAR _ULL(0x30)
+#define KVX_SFR_ILL_IT2_WFXL_SET _ULL(0x3000000000)
+
+#define KVX_SFR_ILL_IT3_MASK _ULL(0xc0) /* Interrupt 3 owner */
+#define KVX_SFR_ILL_IT3_SHIFT 6
+#define KVX_SFR_ILL_IT3_WIDTH 2
+#define KVX_SFR_ILL_IT3_WFXL_MASK _ULL(0xc0)
+#define KVX_SFR_ILL_IT3_WFXL_CLEAR _ULL(0xc0)
+#define KVX_SFR_ILL_IT3_WFXL_SET _ULL(0xc000000000)
+
+#define KVX_SFR_ILL_IT4_MASK _ULL(0x300) /* Interrupt 4 owner */
+#define KVX_SFR_ILL_IT4_SHIFT 8
+#define KVX_SFR_ILL_IT4_WIDTH 2
+#define KVX_SFR_ILL_IT4_WFXL_MASK _ULL(0x300)
+#define KVX_SFR_ILL_IT4_WFXL_CLEAR _ULL(0x300)
+#define KVX_SFR_ILL_IT4_WFXL_SET _ULL(0x30000000000)
+
+#define KVX_SFR_ILL_IT5_MASK _ULL(0xc00) /* Interrupt 5 owner */
+#define KVX_SFR_ILL_IT5_SHIFT 10
+#define KVX_SFR_ILL_IT5_WIDTH 2
+#define KVX_SFR_ILL_IT5_WFXL_MASK _ULL(0xc00)
+#define KVX_SFR_ILL_IT5_WFXL_CLEAR _ULL(0xc00)
+#define KVX_SFR_ILL_IT5_WFXL_SET _ULL(0xc0000000000)
+
+#define KVX_SFR_ILL_IT6_MASK _ULL(0x3000) /* Interrupt 6 owner */
+#define KVX_SFR_ILL_IT6_SHIFT 12
+#define KVX_SFR_ILL_IT6_WIDTH 2
+#define KVX_SFR_ILL_IT6_WFXL_MASK _ULL(0x3000)
+#define KVX_SFR_ILL_IT6_WFXL_CLEAR _ULL(0x3000)
+#define KVX_SFR_ILL_IT6_WFXL_SET _ULL(0x300000000000)
+
+#define KVX_SFR_ILL_IT7_MASK _ULL(0xc000) /* Interrupt 7 owner */
+#define KVX_SFR_ILL_IT7_SHIFT 14
+#define KVX_SFR_ILL_IT7_WIDTH 2
+#define KVX_SFR_ILL_IT7_WFXL_MASK _ULL(0xc000)
+#define KVX_SFR_ILL_IT7_WFXL_CLEAR _ULL(0xc000)
+#define KVX_SFR_ILL_IT7_WFXL_SET _ULL(0xc00000000000)
+
+#define KVX_SFR_ILL_IT8_MASK _ULL(0x30000) /* Interrupt 8 owner */
+#define KVX_SFR_ILL_IT8_SHIFT 16
+#define KVX_SFR_ILL_IT8_WIDTH 2
+#define KVX_SFR_ILL_IT8_WFXL_MASK _ULL(0x30000)
+#define KVX_SFR_ILL_IT8_WFXL_CLEAR _ULL(0x30000)
+#define KVX_SFR_ILL_IT8_WFXL_SET _ULL(0x3000000000000)
+
+#define KVX_SFR_ILL_IT9_MASK _ULL(0xc0000) /* Interrupt 9 owner */
+#define KVX_SFR_ILL_IT9_SHIFT 18
+#define KVX_SFR_ILL_IT9_WIDTH 2
+#define KVX_SFR_ILL_IT9_WFXL_MASK _ULL(0xc0000)
+#define KVX_SFR_ILL_IT9_WFXL_CLEAR _ULL(0xc0000)
+#define KVX_SFR_ILL_IT9_WFXL_SET _ULL(0xc000000000000)
+
+#define KVX_SFR_ILL_IT10_MASK _ULL(0x300000) /* Interrupt 10 owner */
+#define KVX_SFR_ILL_IT10_SHIFT 20
+#define KVX_SFR_ILL_IT10_WIDTH 2
+#define KVX_SFR_ILL_IT10_WFXL_MASK _ULL(0x300000)
+#define KVX_SFR_ILL_IT10_WFXL_CLEAR _ULL(0x300000)
+#define KVX_SFR_ILL_IT10_WFXL_SET _ULL(0x30000000000000)
+
+#define KVX_SFR_ILL_IT11_MASK _ULL(0xc00000) /* Interrupt 11 owner */
+#define KVX_SFR_ILL_IT11_SHIFT 22
+#define KVX_SFR_ILL_IT11_WIDTH 2
+#define KVX_SFR_ILL_IT11_WFXL_MASK _ULL(0xc00000)
+#define KVX_SFR_ILL_IT11_WFXL_CLEAR _ULL(0xc00000)
+#define KVX_SFR_ILL_IT11_WFXL_SET _ULL(0xc0000000000000)
+
+#define KVX_SFR_ILL_IT12_MASK _ULL(0x3000000) /* Interrupt 12 owner */
+#define KVX_SFR_ILL_IT12_SHIFT 24
+#define KVX_SFR_ILL_IT12_WIDTH 2
+#define KVX_SFR_ILL_IT12_WFXL_MASK _ULL(0x3000000)
+#define KVX_SFR_ILL_IT12_WFXL_CLEAR _ULL(0x3000000)
+#define KVX_SFR_ILL_IT12_WFXL_SET _ULL(0x300000000000000)
+
+#define KVX_SFR_ILL_IT13_MASK _ULL(0xc000000) /* Interrupt 13 owner */
+#define KVX_SFR_ILL_IT13_SHIFT 26
+#define KVX_SFR_ILL_IT13_WIDTH 2
+#define KVX_SFR_ILL_IT13_WFXL_MASK _ULL(0xc000000)
+#define KVX_SFR_ILL_IT13_WFXL_CLEAR _ULL(0xc000000)
+#define KVX_SFR_ILL_IT13_WFXL_SET _ULL(0xc00000000000000)
+
+#define KVX_SFR_ILL_IT14_MASK _ULL(0x30000000) /* Interrupt 14 owner */
+#define KVX_SFR_ILL_IT14_SHIFT 28
+#define KVX_SFR_ILL_IT14_WIDTH 2
+#define KVX_SFR_ILL_IT14_WFXL_MASK _ULL(0x30000000)
+#define KVX_SFR_ILL_IT14_WFXL_CLEAR _ULL(0x30000000)
+#define KVX_SFR_ILL_IT14_WFXL_SET _ULL(0x3000000000000000)
+
+#define KVX_SFR_ILL_IT15_MASK _ULL(0xc0000000) /* Interrupt 15 owner */
+#define KVX_SFR_ILL_IT15_SHIFT 30
+#define KVX_SFR_ILL_IT15_WIDTH 2
+#define KVX_SFR_ILL_IT15_WFXL_MASK _ULL(0xc0000000)
+#define KVX_SFR_ILL_IT15_WFXL_CLEAR _ULL(0xc0000000)
+#define KVX_SFR_ILL_IT15_WFXL_SET _ULL(0xc000000000000000)
+
+#define KVX_SFR_ILL_IT16_MASK _ULL(0x300000000) /* Interrupt 16 owner */
+#define KVX_SFR_ILL_IT16_SHIFT 32
+#define KVX_SFR_ILL_IT16_WIDTH 2
+#define KVX_SFR_ILL_IT16_WFXM_MASK _ULL(0x300000000)
+#define KVX_SFR_ILL_IT16_WFXM_CLEAR _ULL(0x3)
+#define KVX_SFR_ILL_IT16_WFXM_SET _ULL(0x300000000)
+
+#define KVX_SFR_ILL_IT17_MASK _ULL(0xc00000000) /* Interrupt 17 owner */
+#define KVX_SFR_ILL_IT17_SHIFT 34
+#define KVX_SFR_ILL_IT17_WIDTH 2
+#define KVX_SFR_ILL_IT17_WFXM_MASK _ULL(0xc00000000)
+#define KVX_SFR_ILL_IT17_WFXM_CLEAR _ULL(0xc)
+#define KVX_SFR_ILL_IT17_WFXM_SET _ULL(0xc00000000)
+
+#define KVX_SFR_ILL_IT18_MASK _ULL(0x3000000000) /* Interrupt 18 owner */
+#define KVX_SFR_ILL_IT18_SHIFT 36
+#define KVX_SFR_ILL_IT18_WIDTH 2
+#define KVX_SFR_ILL_IT18_WFXM_MASK _ULL(0x3000000000)
+#define KVX_SFR_ILL_IT18_WFXM_CLEAR _ULL(0x30)
+#define KVX_SFR_ILL_IT18_WFXM_SET _ULL(0x3000000000)
+
+#define KVX_SFR_ILL_IT19_MASK _ULL(0xc000000000) /* Interrupt 19 owner */
+#define KVX_SFR_ILL_IT19_SHIFT 38
+#define KVX_SFR_ILL_IT19_WIDTH 2
+#define KVX_SFR_ILL_IT19_WFXM_MASK _ULL(0xc000000000)
+#define KVX_SFR_ILL_IT19_WFXM_CLEAR _ULL(0xc0)
+#define KVX_SFR_ILL_IT19_WFXM_SET _ULL(0xc000000000)
+
+#define KVX_SFR_ILL_IT20_MASK _ULL(0x30000000000) /* Interrupt 20 owner */
+#define KVX_SFR_ILL_IT20_SHIFT 40
+#define KVX_SFR_ILL_IT20_WIDTH 2
+#define KVX_SFR_ILL_IT20_WFXM_MASK _ULL(0x30000000000)
+#define KVX_SFR_ILL_IT20_WFXM_CLEAR _ULL(0x300)
+#define KVX_SFR_ILL_IT20_WFXM_SET _ULL(0x30000000000)
+
+#define KVX_SFR_ILL_IT21_MASK _ULL(0xc0000000000) /* Interrupt 21 owner */
+#define KVX_SFR_ILL_IT21_SHIFT 42
+#define KVX_SFR_ILL_IT21_WIDTH 2
+#define KVX_SFR_ILL_IT21_WFXM_MASK _ULL(0xc0000000000)
+#define KVX_SFR_ILL_IT21_WFXM_CLEAR _ULL(0xc00)
+#define KVX_SFR_ILL_IT21_WFXM_SET _ULL(0xc0000000000)
+
+#define KVX_SFR_ILL_IT22_MASK _ULL(0x300000000000) /* Interrupt 22 owner */
+#define KVX_SFR_ILL_IT22_SHIFT 44
+#define KVX_SFR_ILL_IT22_WIDTH 2
+#define KVX_SFR_ILL_IT22_WFXM_MASK _ULL(0x300000000000)
+#define KVX_SFR_ILL_IT22_WFXM_CLEAR _ULL(0x3000)
+#define KVX_SFR_ILL_IT22_WFXM_SET _ULL(0x300000000000)
+
+#define KVX_SFR_ILL_IT23_MASK _ULL(0xc00000000000) /* Interrupt 23 owner */
+#define KVX_SFR_ILL_IT23_SHIFT 46
+#define KVX_SFR_ILL_IT23_WIDTH 2
+#define KVX_SFR_ILL_IT23_WFXM_MASK _ULL(0xc00000000000)
+#define KVX_SFR_ILL_IT23_WFXM_CLEAR _ULL(0xc000)
+#define KVX_SFR_ILL_IT23_WFXM_SET _ULL(0xc00000000000)
+
+#define KVX_SFR_ILL_IT24_MASK _ULL(0x3000000000000) /* Interrupt 24 owner */
+#define KVX_SFR_ILL_IT24_SHIFT 48
+#define KVX_SFR_ILL_IT24_WIDTH 2
+#define KVX_SFR_ILL_IT24_WFXM_MASK _ULL(0x3000000000000)
+#define KVX_SFR_ILL_IT24_WFXM_CLEAR _ULL(0x30000)
+#define KVX_SFR_ILL_IT24_WFXM_SET _ULL(0x3000000000000)
+
+#define KVX_SFR_ILL_IT25_MASK _ULL(0xc000000000000) /* Interrupt 25 owner */
+#define KVX_SFR_ILL_IT25_SHIFT 50
+#define KVX_SFR_ILL_IT25_WIDTH 2
+#define KVX_SFR_ILL_IT25_WFXM_MASK _ULL(0xc000000000000)
+#define KVX_SFR_ILL_IT25_WFXM_CLEAR _ULL(0xc0000)
+#define KVX_SFR_ILL_IT25_WFXM_SET _ULL(0xc000000000000)
+
+#define KVX_SFR_ILL_IT26_MASK _ULL(0x30000000000000) /* Interrupt 26 owner */
+#define KVX_SFR_ILL_IT26_SHIFT 52
+#define KVX_SFR_ILL_IT26_WIDTH 2
+#define KVX_SFR_ILL_IT26_WFXM_MASK _ULL(0x30000000000000)
+#define KVX_SFR_ILL_IT26_WFXM_CLEAR _ULL(0x300000)
+#define KVX_SFR_ILL_IT26_WFXM_SET _ULL(0x30000000000000)
+
+#define KVX_SFR_ILL_IT27_MASK _ULL(0xc0000000000000) /* Interrupt 27 owner */
+#define KVX_SFR_ILL_IT27_SHIFT 54
+#define KVX_SFR_ILL_IT27_WIDTH 2
+#define KVX_SFR_ILL_IT27_WFXM_MASK _ULL(0xc0000000000000)
+#define KVX_SFR_ILL_IT27_WFXM_CLEAR _ULL(0xc00000)
+#define KVX_SFR_ILL_IT27_WFXM_SET _ULL(0xc0000000000000)
+
+#define KVX_SFR_ILL_IT28_MASK _ULL(0x300000000000000) /* Interrupt 28 owner */
+#define KVX_SFR_ILL_IT28_SHIFT 56
+#define KVX_SFR_ILL_IT28_WIDTH 2
+#define KVX_SFR_ILL_IT28_WFXM_MASK _ULL(0x300000000000000)
+#define KVX_SFR_ILL_IT28_WFXM_CLEAR _ULL(0x3000000)
+#define KVX_SFR_ILL_IT28_WFXM_SET _ULL(0x300000000000000)
+
+#define KVX_SFR_ILL_IT29_MASK _ULL(0xc00000000000000) /* Interrupt 29 owner */
+#define KVX_SFR_ILL_IT29_SHIFT 58
+#define KVX_SFR_ILL_IT29_WIDTH 2
+#define KVX_SFR_ILL_IT29_WFXM_MASK _ULL(0xc00000000000000)
+#define KVX_SFR_ILL_IT29_WFXM_CLEAR _ULL(0xc000000)
+#define KVX_SFR_ILL_IT29_WFXM_SET _ULL(0xc00000000000000)
+
+#define KVX_SFR_ILL_IT30_MASK _ULL(0x3000000000000000) /* Interrupt 30 owner */
+#define KVX_SFR_ILL_IT30_SHIFT 60
+#define KVX_SFR_ILL_IT30_WIDTH 2
+#define KVX_SFR_ILL_IT30_WFXM_MASK _ULL(0x3000000000000000)
+#define KVX_SFR_ILL_IT30_WFXM_CLEAR _ULL(0x30000000)
+#define KVX_SFR_ILL_IT30_WFXM_SET _ULL(0x3000000000000000)
+
+#define KVX_SFR_ILL_IT31_MASK _ULL(0xc000000000000000) /* Interrupt 31 owner */
+#define KVX_SFR_ILL_IT31_SHIFT 62
+#define KVX_SFR_ILL_IT31_WIDTH 2
+#define KVX_SFR_ILL_IT31_WFXM_MASK _ULL(0xc000000000000000)
+#define KVX_SFR_ILL_IT31_WFXM_CLEAR _ULL(0xc0000000)
+#define KVX_SFR_ILL_IT31_WFXM_SET _ULL(0xc000000000000000)
+
+#define KVX_SFR_ILR_IT0_MASK _ULL(0x1) /* Interrupt 0 owner */
+#define KVX_SFR_ILR_IT0_SHIFT 0
+#define KVX_SFR_ILR_IT0_WIDTH 1
+#define KVX_SFR_ILR_IT0_WFXL_MASK _ULL(0x1)
+#define KVX_SFR_ILR_IT0_WFXL_CLEAR _ULL(0x1)
+#define KVX_SFR_ILR_IT0_WFXL_SET _ULL(0x100000000)
+
+#define KVX_SFR_ILR_IT1_MASK _ULL(0x2) /* Interrupt 1 owner */
+#define KVX_SFR_ILR_IT1_SHIFT 1
+#define KVX_SFR_ILR_IT1_WIDTH 1
+#define KVX_SFR_ILR_IT1_WFXL_MASK _ULL(0x2)
+#define KVX_SFR_ILR_IT1_WFXL_CLEAR _ULL(0x2)
+#define KVX_SFR_ILR_IT1_WFXL_SET _ULL(0x200000000)
+
+#define KVX_SFR_ILR_IT2_MASK _ULL(0x4) /* Interrupt 2 owner */
+#define KVX_SFR_ILR_IT2_SHIFT 2
+#define KVX_SFR_ILR_IT2_WIDTH 1
+#define KVX_SFR_ILR_IT2_WFXL_MASK _ULL(0x4)
+#define KVX_SFR_ILR_IT2_WFXL_CLEAR _ULL(0x4)
+#define KVX_SFR_ILR_IT2_WFXL_SET _ULL(0x400000000)
+
+#define KVX_SFR_ILR_IT3_MASK _ULL(0x8) /* Interrupt 3 owner */
+#define KVX_SFR_ILR_IT3_SHIFT 3
+#define KVX_SFR_ILR_IT3_WIDTH 1
+#define KVX_SFR_ILR_IT3_WFXL_MASK _ULL(0x8)
+#define KVX_SFR_ILR_IT3_WFXL_CLEAR _ULL(0x8)
+#define KVX_SFR_ILR_IT3_WFXL_SET _ULL(0x800000000)
+
+#define KVX_SFR_ILR_IT4_MASK _ULL(0x10) /* Interrupt 4 owner */
+#define KVX_SFR_ILR_IT4_SHIFT 4
+#define KVX_SFR_ILR_IT4_WIDTH 1
+#define KVX_SFR_ILR_IT4_WFXL_MASK _ULL(0x10)
+#define KVX_SFR_ILR_IT4_WFXL_CLEAR _ULL(0x10)
+#define KVX_SFR_ILR_IT4_WFXL_SET _ULL(0x1000000000)
+
+#define KVX_SFR_ILR_IT5_MASK _ULL(0x20) /* Interrupt 5 owner */
+#define KVX_SFR_ILR_IT5_SHIFT 5
+#define KVX_SFR_ILR_IT5_WIDTH 1
+#define KVX_SFR_ILR_IT5_WFXL_MASK _ULL(0x20)
+#define KVX_SFR_ILR_IT5_WFXL_CLEAR _ULL(0x20)
+#define KVX_SFR_ILR_IT5_WFXL_SET _ULL(0x2000000000)
+
+#define KVX_SFR_ILR_IT6_MASK _ULL(0x40) /* Interrupt 6 owner */
+#define KVX_SFR_ILR_IT6_SHIFT 6
+#define KVX_SFR_ILR_IT6_WIDTH 1
+#define KVX_SFR_ILR_IT6_WFXL_MASK _ULL(0x40)
+#define KVX_SFR_ILR_IT6_WFXL_CLEAR _ULL(0x40)
+#define KVX_SFR_ILR_IT6_WFXL_SET _ULL(0x4000000000)
+
+#define KVX_SFR_ILR_IT7_MASK _ULL(0x80) /* Interrupt 7 owner */
+#define KVX_SFR_ILR_IT7_SHIFT 7
+#define KVX_SFR_ILR_IT7_WIDTH 1
+#define KVX_SFR_ILR_IT7_WFXL_MASK _ULL(0x80)
+#define KVX_SFR_ILR_IT7_WFXL_CLEAR _ULL(0x80)
+#define KVX_SFR_ILR_IT7_WFXL_SET _ULL(0x8000000000)
+
+#define KVX_SFR_ILR_IT8_MASK _ULL(0x100) /* Interrupt 8 owner */
+#define KVX_SFR_ILR_IT8_SHIFT 8
+#define KVX_SFR_ILR_IT8_WIDTH 1
+#define KVX_SFR_ILR_IT8_WFXL_MASK _ULL(0x100)
+#define KVX_SFR_ILR_IT8_WFXL_CLEAR _ULL(0x100)
+#define KVX_SFR_ILR_IT8_WFXL_SET _ULL(0x10000000000)
+
+#define KVX_SFR_ILR_IT9_MASK _ULL(0x200) /* Interrupt 9 owner */
+#define KVX_SFR_ILR_IT9_SHIFT 9
+#define KVX_SFR_ILR_IT9_WIDTH 1
+#define KVX_SFR_ILR_IT9_WFXL_MASK _ULL(0x200)
+#define KVX_SFR_ILR_IT9_WFXL_CLEAR _ULL(0x200)
+#define KVX_SFR_ILR_IT9_WFXL_SET _ULL(0x20000000000)
+
+#define KVX_SFR_ILR_IT10_MASK _ULL(0x400) /* Interrupt 10 owner */
+#define KVX_SFR_ILR_IT10_SHIFT 10
+#define KVX_SFR_ILR_IT10_WIDTH 1
+#define KVX_SFR_ILR_IT10_WFXL_MASK _ULL(0x400)
+#define KVX_SFR_ILR_IT10_WFXL_CLEAR _ULL(0x400)
+#define KVX_SFR_ILR_IT10_WFXL_SET _ULL(0x40000000000)
+
+#define KVX_SFR_ILR_IT11_MASK _ULL(0x800) /* Interrupt 11 owner */
+#define KVX_SFR_ILR_IT11_SHIFT 11
+#define KVX_SFR_ILR_IT11_WIDTH 1
+#define KVX_SFR_ILR_IT11_WFXL_MASK _ULL(0x800)
+#define KVX_SFR_ILR_IT11_WFXL_CLEAR _ULL(0x800)
+#define KVX_SFR_ILR_IT11_WFXL_SET _ULL(0x80000000000)
+
+#define KVX_SFR_ILR_IT12_MASK _ULL(0x1000) /* Interrupt 12 owner */
+#define KVX_SFR_ILR_IT12_SHIFT 12
+#define KVX_SFR_ILR_IT12_WIDTH 1
+#define KVX_SFR_ILR_IT12_WFXL_MASK _ULL(0x1000)
+#define KVX_SFR_ILR_IT12_WFXL_CLEAR _ULL(0x1000)
+#define KVX_SFR_ILR_IT12_WFXL_SET _ULL(0x100000000000)
+
+#define KVX_SFR_ILR_IT13_MASK _ULL(0x2000) /* Interrupt 13 owner */
+#define KVX_SFR_ILR_IT13_SHIFT 13
+#define KVX_SFR_ILR_IT13_WIDTH 1
+#define KVX_SFR_ILR_IT13_WFXL_MASK _ULL(0x2000)
+#define KVX_SFR_ILR_IT13_WFXL_CLEAR _ULL(0x2000)
+#define KVX_SFR_ILR_IT13_WFXL_SET _ULL(0x200000000000)
+
+#define KVX_SFR_ILR_IT14_MASK _ULL(0x4000) /* Interrupt 14 owner */
+#define KVX_SFR_ILR_IT14_SHIFT 14
+#define KVX_SFR_ILR_IT14_WIDTH 1
+#define KVX_SFR_ILR_IT14_WFXL_MASK _ULL(0x4000)
+#define KVX_SFR_ILR_IT14_WFXL_CLEAR _ULL(0x4000)
+#define KVX_SFR_ILR_IT14_WFXL_SET _ULL(0x400000000000)
+
+#define KVX_SFR_ILR_IT15_MASK _ULL(0x8000) /* Interrupt 15 owner */
+#define KVX_SFR_ILR_IT15_SHIFT 15
+#define KVX_SFR_ILR_IT15_WIDTH 1
+#define KVX_SFR_ILR_IT15_WFXL_MASK _ULL(0x8000)
+#define KVX_SFR_ILR_IT15_WFXL_CLEAR _ULL(0x8000)
+#define KVX_SFR_ILR_IT15_WFXL_SET _ULL(0x800000000000)
+
+#define KVX_SFR_ILR_IT16_MASK _ULL(0x10000) /* Interrupt 16 owner */
+#define KVX_SFR_ILR_IT16_SHIFT 16
+#define KVX_SFR_ILR_IT16_WIDTH 1
+#define KVX_SFR_ILR_IT16_WFXL_MASK _ULL(0x10000)
+#define KVX_SFR_ILR_IT16_WFXL_CLEAR _ULL(0x10000)
+#define KVX_SFR_ILR_IT16_WFXL_SET _ULL(0x1000000000000)
+
+#define KVX_SFR_ILR_IT17_MASK _ULL(0x20000) /* Interrupt 17 owner */
+#define KVX_SFR_ILR_IT17_SHIFT 17
+#define KVX_SFR_ILR_IT17_WIDTH 1
+#define KVX_SFR_ILR_IT17_WFXL_MASK _ULL(0x20000)
+#define KVX_SFR_ILR_IT17_WFXL_CLEAR _ULL(0x20000)
+#define KVX_SFR_ILR_IT17_WFXL_SET _ULL(0x2000000000000)
+
+#define KVX_SFR_ILR_IT18_MASK _ULL(0x40000) /* Interrupt 18 owner */
+#define KVX_SFR_ILR_IT18_SHIFT 18
+#define KVX_SFR_ILR_IT18_WIDTH 1
+#define KVX_SFR_ILR_IT18_WFXL_MASK _ULL(0x40000)
+#define KVX_SFR_ILR_IT18_WFXL_CLEAR _ULL(0x40000)
+#define KVX_SFR_ILR_IT18_WFXL_SET _ULL(0x4000000000000)
+
+#define KVX_SFR_ILR_IT19_MASK _ULL(0x80000) /* Interrupt 19 owner */
+#define KVX_SFR_ILR_IT19_SHIFT 19
+#define KVX_SFR_ILR_IT19_WIDTH 1
+#define KVX_SFR_ILR_IT19_WFXL_MASK _ULL(0x80000)
+#define KVX_SFR_ILR_IT19_WFXL_CLEAR _ULL(0x80000)
+#define KVX_SFR_ILR_IT19_WFXL_SET _ULL(0x8000000000000)
+
+#define KVX_SFR_ILR_IT20_MASK _ULL(0x100000) /* Interrupt 20 owner */
+#define KVX_SFR_ILR_IT20_SHIFT 20
+#define KVX_SFR_ILR_IT20_WIDTH 1
+#define KVX_SFR_ILR_IT20_WFXL_MASK _ULL(0x100000)
+#define KVX_SFR_ILR_IT20_WFXL_CLEAR _ULL(0x100000)
+#define KVX_SFR_ILR_IT20_WFXL_SET _ULL(0x10000000000000)
+
+#define KVX_SFR_ILR_IT21_MASK _ULL(0x200000) /* Interrupt 21 owner */
+#define KVX_SFR_ILR_IT21_SHIFT 21
+#define KVX_SFR_ILR_IT21_WIDTH 1
+#define KVX_SFR_ILR_IT21_WFXL_MASK _ULL(0x200000)
+#define KVX_SFR_ILR_IT21_WFXL_CLEAR _ULL(0x200000)
+#define KVX_SFR_ILR_IT21_WFXL_SET _ULL(0x20000000000000)
+
+#define KVX_SFR_ILR_IT22_MASK _ULL(0x400000) /* Interrupt 22 owner */
+#define KVX_SFR_ILR_IT22_SHIFT 22
+#define KVX_SFR_ILR_IT22_WIDTH 1
+#define KVX_SFR_ILR_IT22_WFXL_MASK _ULL(0x400000)
+#define KVX_SFR_ILR_IT22_WFXL_CLEAR _ULL(0x400000)
+#define KVX_SFR_ILR_IT22_WFXL_SET _ULL(0x40000000000000)
+
+#define KVX_SFR_ILR_IT23_MASK _ULL(0x800000) /* Interrupt 23 owner */
+#define KVX_SFR_ILR_IT23_SHIFT 23
+#define KVX_SFR_ILR_IT23_WIDTH 1
+#define KVX_SFR_ILR_IT23_WFXL_MASK _ULL(0x800000)
+#define KVX_SFR_ILR_IT23_WFXL_CLEAR _ULL(0x800000)
+#define KVX_SFR_ILR_IT23_WFXL_SET _ULL(0x80000000000000)
+
+#define KVX_SFR_ILR_IT24_MASK _ULL(0x1000000) /* Interrupt 24 owner */
+#define KVX_SFR_ILR_IT24_SHIFT 24
+#define KVX_SFR_ILR_IT24_WIDTH 1
+#define KVX_SFR_ILR_IT24_WFXL_MASK _ULL(0x1000000)
+#define KVX_SFR_ILR_IT24_WFXL_CLEAR _ULL(0x1000000)
+#define KVX_SFR_ILR_IT24_WFXL_SET _ULL(0x100000000000000)
+
+#define KVX_SFR_ILR_IT25_MASK _ULL(0x2000000) /* Interrupt 25 owner */
+#define KVX_SFR_ILR_IT25_SHIFT 25
+#define KVX_SFR_ILR_IT25_WIDTH 1
+#define KVX_SFR_ILR_IT25_WFXL_MASK _ULL(0x2000000)
+#define KVX_SFR_ILR_IT25_WFXL_CLEAR _ULL(0x2000000)
+#define KVX_SFR_ILR_IT25_WFXL_SET _ULL(0x200000000000000)
+
+#define KVX_SFR_ILR_IT26_MASK _ULL(0x4000000) /* Interrupt 26 owner */
+#define KVX_SFR_ILR_IT26_SHIFT 26
+#define KVX_SFR_ILR_IT26_WIDTH 1
+#define KVX_SFR_ILR_IT26_WFXL_MASK _ULL(0x4000000)
+#define KVX_SFR_ILR_IT26_WFXL_CLEAR _ULL(0x4000000)
+#define KVX_SFR_ILR_IT26_WFXL_SET _ULL(0x400000000000000)
+
+#define KVX_SFR_ILR_IT27_MASK _ULL(0x8000000) /* Interrupt 27 owner */
+#define KVX_SFR_ILR_IT27_SHIFT 27
+#define KVX_SFR_ILR_IT27_WIDTH 1
+#define KVX_SFR_ILR_IT27_WFXL_MASK _ULL(0x8000000)
+#define KVX_SFR_ILR_IT27_WFXL_CLEAR _ULL(0x8000000)
+#define KVX_SFR_ILR_IT27_WFXL_SET _ULL(0x800000000000000)
+
+#define KVX_SFR_ILR_IT28_MASK _ULL(0x10000000) /* Interrupt 28 owner */
+#define KVX_SFR_ILR_IT28_SHIFT 28
+#define KVX_SFR_ILR_IT28_WIDTH 1
+#define KVX_SFR_ILR_IT28_WFXL_MASK _ULL(0x10000000)
+#define KVX_SFR_ILR_IT28_WFXL_CLEAR _ULL(0x10000000)
+#define KVX_SFR_ILR_IT28_WFXL_SET _ULL(0x1000000000000000)
+
+#define KVX_SFR_ILR_IT29_MASK _ULL(0x20000000) /* Interrupt 29 owner */
+#define KVX_SFR_ILR_IT29_SHIFT 29
+#define KVX_SFR_ILR_IT29_WIDTH 1
+#define KVX_SFR_ILR_IT29_WFXL_MASK _ULL(0x20000000)
+#define KVX_SFR_ILR_IT29_WFXL_CLEAR _ULL(0x20000000)
+#define KVX_SFR_ILR_IT29_WFXL_SET _ULL(0x2000000000000000)
+
+#define KVX_SFR_ILR_IT30_MASK _ULL(0x40000000) /* Interrupt 30 owner */
+#define KVX_SFR_ILR_IT30_SHIFT 30
+#define KVX_SFR_ILR_IT30_WIDTH 1
+#define KVX_SFR_ILR_IT30_WFXL_MASK _ULL(0x40000000)
+#define KVX_SFR_ILR_IT30_WFXL_CLEAR _ULL(0x40000000)
+#define KVX_SFR_ILR_IT30_WFXL_SET _ULL(0x4000000000000000)
+
+#define KVX_SFR_ILR_IT31_MASK _ULL(0x80000000) /* Interrupt 31 owner */
+#define KVX_SFR_ILR_IT31_SHIFT 31
+#define KVX_SFR_ILR_IT31_WIDTH 1
+#define KVX_SFR_ILR_IT31_WFXL_MASK _ULL(0x80000000)
+#define KVX_SFR_ILR_IT31_WFXL_CLEAR _ULL(0x80000000)
+#define KVX_SFR_ILR_IT31_WFXL_SET _ULL(0x8000000000000000)
+
+#define KVX_SFR_ITOW_IT0_MASK _ULL(0x3) /* Interrupt 0 owner */
+#define KVX_SFR_ITOW_IT0_SHIFT 0
+#define KVX_SFR_ITOW_IT0_WIDTH 2
+#define KVX_SFR_ITOW_IT0_WFXL_MASK _ULL(0x3)
+#define KVX_SFR_ITOW_IT0_WFXL_CLEAR _ULL(0x3)
+#define KVX_SFR_ITOW_IT0_WFXL_SET _ULL(0x300000000)
+
+#define KVX_SFR_ITOW_IT1_MASK _ULL(0xc) /* Interrupt 1 owner */
+#define KVX_SFR_ITOW_IT1_SHIFT 2
+#define KVX_SFR_ITOW_IT1_WIDTH 2
+#define KVX_SFR_ITOW_IT1_WFXL_MASK _ULL(0xc)
+#define KVX_SFR_ITOW_IT1_WFXL_CLEAR _ULL(0xc)
+#define KVX_SFR_ITOW_IT1_WFXL_SET _ULL(0xc00000000)
+
+#define KVX_SFR_ITOW_IT2_MASK _ULL(0x30) /* Interrupt 2 owner */
+#define KVX_SFR_ITOW_IT2_SHIFT 4
+#define KVX_SFR_ITOW_IT2_WIDTH 2
+#define KVX_SFR_ITOW_IT2_WFXL_MASK _ULL(0x30)
+#define KVX_SFR_ITOW_IT2_WFXL_CLEAR _ULL(0x30)
+#define KVX_SFR_ITOW_IT2_WFXL_SET _ULL(0x3000000000)
+
+#define KVX_SFR_ITOW_IT3_MASK _ULL(0xc0) /* Interrupt 3 owner */
+#define KVX_SFR_ITOW_IT3_SHIFT 6
+#define KVX_SFR_ITOW_IT3_WIDTH 2
+#define KVX_SFR_ITOW_IT3_WFXL_MASK _ULL(0xc0)
+#define KVX_SFR_ITOW_IT3_WFXL_CLEAR _ULL(0xc0)
+#define KVX_SFR_ITOW_IT3_WFXL_SET _ULL(0xc000000000)
+
+#define KVX_SFR_ITOW_IT4_MASK _ULL(0x300) /* Interrupt 4 owner */
+#define KVX_SFR_ITOW_IT4_SHIFT 8
+#define KVX_SFR_ITOW_IT4_WIDTH 2
+#define KVX_SFR_ITOW_IT4_WFXL_MASK _ULL(0x300)
+#define KVX_SFR_ITOW_IT4_WFXL_CLEAR _ULL(0x300)
+#define KVX_SFR_ITOW_IT4_WFXL_SET _ULL(0x30000000000)
+
+#define KVX_SFR_ITOW_IT5_MASK _ULL(0xc00) /* Interrupt 5 owner */
+#define KVX_SFR_ITOW_IT5_SHIFT 10
+#define KVX_SFR_ITOW_IT5_WIDTH 2
+#define KVX_SFR_ITOW_IT5_WFXL_MASK _ULL(0xc00)
+#define KVX_SFR_ITOW_IT5_WFXL_CLEAR _ULL(0xc00)
+#define KVX_SFR_ITOW_IT5_WFXL_SET _ULL(0xc0000000000)
+
+#define KVX_SFR_ITOW_IT6_MASK _ULL(0x3000) /* Interrupt 6 owner */
+#define KVX_SFR_ITOW_IT6_SHIFT 12
+#define KVX_SFR_ITOW_IT6_WIDTH 2
+#define KVX_SFR_ITOW_IT6_WFXL_MASK _ULL(0x3000)
+#define KVX_SFR_ITOW_IT6_WFXL_CLEAR _ULL(0x3000)
+#define KVX_SFR_ITOW_IT6_WFXL_SET _ULL(0x300000000000)
+
+#define KVX_SFR_ITOW_IT7_MASK _ULL(0xc000) /* Interrupt 7 owner */
+#define KVX_SFR_ITOW_IT7_SHIFT 14
+#define KVX_SFR_ITOW_IT7_WIDTH 2
+#define KVX_SFR_ITOW_IT7_WFXL_MASK _ULL(0xc000)
+#define KVX_SFR_ITOW_IT7_WFXL_CLEAR _ULL(0xc000)
+#define KVX_SFR_ITOW_IT7_WFXL_SET _ULL(0xc00000000000)
+
+#define KVX_SFR_ITOW_IT8_MASK _ULL(0x30000) /* Interrupt 8 owner */
+#define KVX_SFR_ITOW_IT8_SHIFT 16
+#define KVX_SFR_ITOW_IT8_WIDTH 2
+#define KVX_SFR_ITOW_IT8_WFXL_MASK _ULL(0x30000)
+#define KVX_SFR_ITOW_IT8_WFXL_CLEAR _ULL(0x30000)
+#define KVX_SFR_ITOW_IT8_WFXL_SET _ULL(0x3000000000000)
+
+#define KVX_SFR_ITOW_IT9_MASK _ULL(0xc0000) /* Interrupt 9 owner */
+#define KVX_SFR_ITOW_IT9_SHIFT 18
+#define KVX_SFR_ITOW_IT9_WIDTH 2
+#define KVX_SFR_ITOW_IT9_WFXL_MASK _ULL(0xc0000)
+#define KVX_SFR_ITOW_IT9_WFXL_CLEAR _ULL(0xc0000)
+#define KVX_SFR_ITOW_IT9_WFXL_SET _ULL(0xc000000000000)
+
+#define KVX_SFR_ITOW_IT10_MASK _ULL(0x300000) /* Interrupt 10 owner */
+#define KVX_SFR_ITOW_IT10_SHIFT 20
+#define KVX_SFR_ITOW_IT10_WIDTH 2
+#define KVX_SFR_ITOW_IT10_WFXL_MASK _ULL(0x300000)
+#define KVX_SFR_ITOW_IT10_WFXL_CLEAR _ULL(0x300000)
+#define KVX_SFR_ITOW_IT10_WFXL_SET _ULL(0x30000000000000)
+
+#define KVX_SFR_ITOW_IT11_MASK _ULL(0xc00000) /* Interrupt 11 owner */
+#define KVX_SFR_ITOW_IT11_SHIFT 22
+#define KVX_SFR_ITOW_IT11_WIDTH 2
+#define KVX_SFR_ITOW_IT11_WFXL_MASK _ULL(0xc00000)
+#define KVX_SFR_ITOW_IT11_WFXL_CLEAR _ULL(0xc00000)
+#define KVX_SFR_ITOW_IT11_WFXL_SET _ULL(0xc0000000000000)
+
+#define KVX_SFR_ITOW_IT12_MASK _ULL(0x3000000) /* Interrupt 12 owner */
+#define KVX_SFR_ITOW_IT12_SHIFT 24
+#define KVX_SFR_ITOW_IT12_WIDTH 2
+#define KVX_SFR_ITOW_IT12_WFXL_MASK _ULL(0x3000000)
+#define KVX_SFR_ITOW_IT12_WFXL_CLEAR _ULL(0x3000000)
+#define KVX_SFR_ITOW_IT12_WFXL_SET _ULL(0x300000000000000)
+
+#define KVX_SFR_ITOW_IT13_MASK _ULL(0xc000000) /* Interrupt 13 owner */
+#define KVX_SFR_ITOW_IT13_SHIFT 26
+#define KVX_SFR_ITOW_IT13_WIDTH 2
+#define KVX_SFR_ITOW_IT13_WFXL_MASK _ULL(0xc000000)
+#define KVX_SFR_ITOW_IT13_WFXL_CLEAR _ULL(0xc000000)
+#define KVX_SFR_ITOW_IT13_WFXL_SET _ULL(0xc00000000000000)
+
+#define KVX_SFR_ITOW_IT14_MASK _ULL(0x30000000) /* Interrupt 14 owner */
+#define KVX_SFR_ITOW_IT14_SHIFT 28
+#define KVX_SFR_ITOW_IT14_WIDTH 2
+#define KVX_SFR_ITOW_IT14_WFXL_MASK _ULL(0x30000000)
+#define KVX_SFR_ITOW_IT14_WFXL_CLEAR _ULL(0x30000000)
+#define KVX_SFR_ITOW_IT14_WFXL_SET _ULL(0x3000000000000000)
+
+#define KVX_SFR_ITOW_IT15_MASK _ULL(0xc0000000) /* Interrupt 15 owner */
+#define KVX_SFR_ITOW_IT15_SHIFT 30
+#define KVX_SFR_ITOW_IT15_WIDTH 2
+#define KVX_SFR_ITOW_IT15_WFXL_MASK _ULL(0xc0000000)
+#define KVX_SFR_ITOW_IT15_WFXL_CLEAR _ULL(0xc0000000)
+#define KVX_SFR_ITOW_IT15_WFXL_SET _ULL(0xc000000000000000)
+
+#define KVX_SFR_ITOW_IT16_MASK _ULL(0x300000000) /* Interrupt 16 owner */
+#define KVX_SFR_ITOW_IT16_SHIFT 32
+#define KVX_SFR_ITOW_IT16_WIDTH 2
+#define KVX_SFR_ITOW_IT16_WFXM_MASK _ULL(0x300000000)
+#define KVX_SFR_ITOW_IT16_WFXM_CLEAR _ULL(0x3)
+#define KVX_SFR_ITOW_IT16_WFXM_SET _ULL(0x300000000)
+
+#define KVX_SFR_ITOW_IT17_MASK _ULL(0xc00000000) /* Interrupt 17 owner */
+#define KVX_SFR_ITOW_IT17_SHIFT 34
+#define KVX_SFR_ITOW_IT17_WIDTH 2
+#define KVX_SFR_ITOW_IT17_WFXM_MASK _ULL(0xc00000000)
+#define KVX_SFR_ITOW_IT17_WFXM_CLEAR _ULL(0xc)
+#define KVX_SFR_ITOW_IT17_WFXM_SET _ULL(0xc00000000)
+
+#define KVX_SFR_ITOW_IT18_MASK _ULL(0x3000000000) /* Interrupt 18 owner */
+#define KVX_SFR_ITOW_IT18_SHIFT 36
+#define KVX_SFR_ITOW_IT18_WIDTH 2
+#define KVX_SFR_ITOW_IT18_WFXM_MASK _ULL(0x3000000000)
+#define KVX_SFR_ITOW_IT18_WFXM_CLEAR _ULL(0x30)
+#define KVX_SFR_ITOW_IT18_WFXM_SET _ULL(0x3000000000)
+
+#define KVX_SFR_ITOW_IT19_MASK _ULL(0xc000000000) /* Interrupt 19 owner */
+#define KVX_SFR_ITOW_IT19_SHIFT 38
+#define KVX_SFR_ITOW_IT19_WIDTH 2
+#define KVX_SFR_ITOW_IT19_WFXM_MASK _ULL(0xc000000000)
+#define KVX_SFR_ITOW_IT19_WFXM_CLEAR _ULL(0xc0)
+#define KVX_SFR_ITOW_IT19_WFXM_SET _ULL(0xc000000000)
+
+#define KVX_SFR_ITOW_IT20_MASK _ULL(0x30000000000) /* Interrupt 20 owner */
+#define KVX_SFR_ITOW_IT20_SHIFT 40
+#define KVX_SFR_ITOW_IT20_WIDTH 2
+#define KVX_SFR_ITOW_IT20_WFXM_MASK _ULL(0x30000000000)
+#define KVX_SFR_ITOW_IT20_WFXM_CLEAR _ULL(0x300)
+#define KVX_SFR_ITOW_IT20_WFXM_SET _ULL(0x30000000000)
+
+#define KVX_SFR_ITOW_IT21_MASK _ULL(0xc0000000000) /* Interrupt 21 owner */
+#define KVX_SFR_ITOW_IT21_SHIFT 42
+#define KVX_SFR_ITOW_IT21_WIDTH 2
+#define KVX_SFR_ITOW_IT21_WFXM_MASK _ULL(0xc0000000000)
+#define KVX_SFR_ITOW_IT21_WFXM_CLEAR _ULL(0xc00)
+#define KVX_SFR_ITOW_IT21_WFXM_SET _ULL(0xc0000000000)
+
+#define KVX_SFR_ITOW_IT22_MASK _ULL(0x300000000000) /* Interrupt 22 owner */
+#define KVX_SFR_ITOW_IT22_SHIFT 44
+#define KVX_SFR_ITOW_IT22_WIDTH 2
+#define KVX_SFR_ITOW_IT22_WFXM_MASK _ULL(0x300000000000)
+#define KVX_SFR_ITOW_IT22_WFXM_CLEAR _ULL(0x3000)
+#define KVX_SFR_ITOW_IT22_WFXM_SET _ULL(0x300000000000)
+
+#define KVX_SFR_ITOW_IT23_MASK _ULL(0xc00000000000) /* Interrupt 23 owner */
+#define KVX_SFR_ITOW_IT23_SHIFT 46
+#define KVX_SFR_ITOW_IT23_WIDTH 2
+#define KVX_SFR_ITOW_IT23_WFXM_MASK _ULL(0xc00000000000)
+#define KVX_SFR_ITOW_IT23_WFXM_CLEAR _ULL(0xc000)
+#define KVX_SFR_ITOW_IT23_WFXM_SET _ULL(0xc00000000000)
+
+#define KVX_SFR_ITOW_IT24_MASK _ULL(0x3000000000000) /* Interrupt 24 owner */
+#define KVX_SFR_ITOW_IT24_SHIFT 48
+#define KVX_SFR_ITOW_IT24_WIDTH 2
+#define KVX_SFR_ITOW_IT24_WFXM_MASK _ULL(0x3000000000000)
+#define KVX_SFR_ITOW_IT24_WFXM_CLEAR _ULL(0x30000)
+#define KVX_SFR_ITOW_IT24_WFXM_SET _ULL(0x3000000000000)
+
+#define KVX_SFR_ITOW_IT25_MASK _ULL(0xc000000000000) /* Interrupt 25 owner */
+#define KVX_SFR_ITOW_IT25_SHIFT 50
+#define KVX_SFR_ITOW_IT25_WIDTH 2
+#define KVX_SFR_ITOW_IT25_WFXM_MASK _ULL(0xc000000000000)
+#define KVX_SFR_ITOW_IT25_WFXM_CLEAR _ULL(0xc0000)
+#define KVX_SFR_ITOW_IT25_WFXM_SET _ULL(0xc000000000000)
+
+#define KVX_SFR_ITOW_IT26_MASK _ULL(0x30000000000000) /* Interrupt 26 owner */
+#define KVX_SFR_ITOW_IT26_SHIFT 52
+#define KVX_SFR_ITOW_IT26_WIDTH 2
+#define KVX_SFR_ITOW_IT26_WFXM_MASK _ULL(0x30000000000000)
+#define KVX_SFR_ITOW_IT26_WFXM_CLEAR _ULL(0x300000)
+#define KVX_SFR_ITOW_IT26_WFXM_SET _ULL(0x30000000000000)
+
+#define KVX_SFR_ITOW_IT27_MASK _ULL(0xc0000000000000) /* Interrupt 27 owner */
+#define KVX_SFR_ITOW_IT27_SHIFT 54
+#define KVX_SFR_ITOW_IT27_WIDTH 2
+#define KVX_SFR_ITOW_IT27_WFXM_MASK _ULL(0xc0000000000000)
+#define KVX_SFR_ITOW_IT27_WFXM_CLEAR _ULL(0xc00000)
+#define KVX_SFR_ITOW_IT27_WFXM_SET _ULL(0xc0000000000000)
+
+#define KVX_SFR_ITOW_IT28_MASK _ULL(0x300000000000000) /* Interrupt 28 owner */
+#define KVX_SFR_ITOW_IT28_SHIFT 56
+#define KVX_SFR_ITOW_IT28_WIDTH 2
+#define KVX_SFR_ITOW_IT28_WFXM_MASK _ULL(0x300000000000000)
+#define KVX_SFR_ITOW_IT28_WFXM_CLEAR _ULL(0x3000000)
+#define KVX_SFR_ITOW_IT28_WFXM_SET _ULL(0x300000000000000)
+
+#define KVX_SFR_ITOW_IT29_MASK _ULL(0xc00000000000000) /* Interrupt 29 owner */
+#define KVX_SFR_ITOW_IT29_SHIFT 58
+#define KVX_SFR_ITOW_IT29_WIDTH 2
+#define KVX_SFR_ITOW_IT29_WFXM_MASK _ULL(0xc00000000000000)
+#define KVX_SFR_ITOW_IT29_WFXM_CLEAR _ULL(0xc000000)
+#define KVX_SFR_ITOW_IT29_WFXM_SET _ULL(0xc00000000000000)
+
+#define KVX_SFR_ITOW_IT30_MASK _ULL(0x3000000000000000) /* Interrupt 30 owner */
+#define KVX_SFR_ITOW_IT30_SHIFT 60
+#define KVX_SFR_ITOW_IT30_WIDTH 2
+#define KVX_SFR_ITOW_IT30_WFXM_MASK _ULL(0x3000000000000000)
+#define KVX_SFR_ITOW_IT30_WFXM_CLEAR _ULL(0x30000000)
+#define KVX_SFR_ITOW_IT30_WFXM_SET _ULL(0x3000000000000000)
+
+#define KVX_SFR_ITOW_IT31_MASK _ULL(0xc000000000000000) /* Interrupt 31 owner */
+#define KVX_SFR_ITOW_IT31_SHIFT 62
+#define KVX_SFR_ITOW_IT31_WIDTH 2
+#define KVX_SFR_ITOW_IT31_WFXM_MASK _ULL(0xc000000000000000)
+#define KVX_SFR_ITOW_IT31_WFXM_CLEAR _ULL(0xc0000000)
+#define KVX_SFR_ITOW_IT31_WFXM_SET _ULL(0xc000000000000000)
+
+#define KVX_SFR_DO_B0_MASK _ULL(0x3) /* Breakpoint 0 owner. */
+#define KVX_SFR_DO_B0_SHIFT 0
+#define KVX_SFR_DO_B0_WIDTH 2
+#define KVX_SFR_DO_B0_WFXL_MASK _ULL(0x3)
+#define KVX_SFR_DO_B0_WFXL_CLEAR _ULL(0x3)
+#define KVX_SFR_DO_B0_WFXL_SET _ULL(0x300000000)
+
+#define KVX_SFR_DO_B1_MASK _ULL(0xc) /* Breakpoint 1 owner. */
+#define KVX_SFR_DO_B1_SHIFT 2
+#define KVX_SFR_DO_B1_WIDTH 2
+#define KVX_SFR_DO_B1_WFXL_MASK _ULL(0xc)
+#define KVX_SFR_DO_B1_WFXL_CLEAR _ULL(0xc)
+#define KVX_SFR_DO_B1_WFXL_SET _ULL(0xc00000000)
+
+#define KVX_SFR_DO_W0_MASK _ULL(0x30) /* Watchpoint 0 owner. */
+#define KVX_SFR_DO_W0_SHIFT 4
+#define KVX_SFR_DO_W0_WIDTH 2
+#define KVX_SFR_DO_W0_WFXL_MASK _ULL(0x30)
+#define KVX_SFR_DO_W0_WFXL_CLEAR _ULL(0x30)
+#define KVX_SFR_DO_W0_WFXL_SET _ULL(0x3000000000)
+
+#define KVX_SFR_DO_W1_MASK _ULL(0xc0) /* Watchpoint 1 owner. */
+#define KVX_SFR_DO_W1_SHIFT 6
+#define KVX_SFR_DO_W1_WIDTH 2
+#define KVX_SFR_DO_W1_WFXL_MASK _ULL(0xc0)
+#define KVX_SFR_DO_W1_WFXL_CLEAR _ULL(0xc0)
+#define KVX_SFR_DO_W1_WFXL_SET _ULL(0xc000000000)
+
+#define KVX_SFR_DBA0_DBA0_MASK _ULL(0xffffffffffffffff) /* Debug Breakpoint Address 0 */
+#define KVX_SFR_DBA0_DBA0_SHIFT 0
+#define KVX_SFR_DBA0_DBA0_WIDTH 64
+#define KVX_SFR_DBA0_DBA0_WFXL_MASK _ULL(0xffffffff)
+#define KVX_SFR_DBA0_DBA0_WFXL_CLEAR _ULL(0xffffffff)
+#define KVX_SFR_DBA0_DBA0_WFXL_SET _ULL(0xffffffff00000000)
+#define KVX_SFR_DBA0_DBA0_WFXM_MASK _ULL(0xffffffff00000000)
+#define KVX_SFR_DBA0_DBA0_WFXM_CLEAR _ULL(0xffffffff)
+#define KVX_SFR_DBA0_DBA0_WFXM_SET _ULL(0xffffffff00000000)
+
+#define KVX_SFR_DBA1_DBA1_MASK _ULL(0xffffffffffffffff) /* Debug Breakpoint Address 1 */
+#define KVX_SFR_DBA1_DBA1_SHIFT 0
+#define KVX_SFR_DBA1_DBA1_WIDTH 64
+#define KVX_SFR_DBA1_DBA1_WFXL_MASK _ULL(0xffffffff)
+#define KVX_SFR_DBA1_DBA1_WFXL_CLEAR _ULL(0xffffffff)
+#define KVX_SFR_DBA1_DBA1_WFXL_SET _ULL(0xffffffff00000000)
+#define KVX_SFR_DBA1_DBA1_WFXM_MASK _ULL(0xffffffff00000000)
+#define KVX_SFR_DBA1_DBA1_WFXM_CLEAR _ULL(0xffffffff)
+#define KVX_SFR_DBA1_DBA1_WFXM_SET _ULL(0xffffffff00000000)
+
+#define KVX_SFR_DWA0_DWA0_MASK _ULL(0xffffffffffffffff) /* Debug Breakpoint Address 0 */
+#define KVX_SFR_DWA0_DWA0_SHIFT 0
+#define KVX_SFR_DWA0_DWA0_WIDTH 64
+#define KVX_SFR_DWA0_DWA0_WFXL_MASK _ULL(0xffffffff)
+#define KVX_SFR_DWA0_DWA0_WFXL_CLEAR _ULL(0xffffffff)
+#define KVX_SFR_DWA0_DWA0_WFXL_SET _ULL(0xffffffff00000000)
+#define KVX_SFR_DWA0_DWA0_WFXM_MASK _ULL(0xffffffff00000000)
+#define KVX_SFR_DWA0_DWA0_WFXM_CLEAR _ULL(0xffffffff)
+#define KVX_SFR_DWA0_DWA0_WFXM_SET _ULL(0xffffffff00000000)
+
+#define KVX_SFR_DWA1_DWA1_MASK _ULL(0xffffffffffffffff) /* Debug Breakpoint Address 1 */
+#define KVX_SFR_DWA1_DWA1_SHIFT 0
+#define KVX_SFR_DWA1_DWA1_WIDTH 64
+#define KVX_SFR_DWA1_DWA1_WFXL_MASK _ULL(0xffffffff)
+#define KVX_SFR_DWA1_DWA1_WFXL_CLEAR _ULL(0xffffffff)
+#define KVX_SFR_DWA1_DWA1_WFXL_SET _ULL(0xffffffff00000000)
+#define KVX_SFR_DWA1_DWA1_WFXM_MASK _ULL(0xffffffff00000000)
+#define KVX_SFR_DWA1_DWA1_WFXM_CLEAR _ULL(0xffffffff)
+#define KVX_SFR_DWA1_DWA1_WFXM_SET _ULL(0xffffffff00000000)
+
+#define KVX_SFR_DOW_B0_MASK _ULL(0x3) /* Breakpoint 0 owner. */
+#define KVX_SFR_DOW_B0_SHIFT 0
+#define KVX_SFR_DOW_B0_WIDTH 2
+#define KVX_SFR_DOW_B0_WFXL_MASK _ULL(0x3)
+#define KVX_SFR_DOW_B0_WFXL_CLEAR _ULL(0x3)
+#define KVX_SFR_DOW_B0_WFXL_SET _ULL(0x300000000)
+
+#define KVX_SFR_DOW_B1_MASK _ULL(0xc) /* Breakpoint 1 owner. */
+#define KVX_SFR_DOW_B1_SHIFT 2
+#define KVX_SFR_DOW_B1_WIDTH 2
+#define KVX_SFR_DOW_B1_WFXL_MASK _ULL(0xc)
+#define KVX_SFR_DOW_B1_WFXL_CLEAR _ULL(0xc)
+#define KVX_SFR_DOW_B1_WFXL_SET _ULL(0xc00000000)
+
+#define KVX_SFR_DOW_W0_MASK _ULL(0x30) /* Watchpoint 0 owner. */
+#define KVX_SFR_DOW_W0_SHIFT 4
+#define KVX_SFR_DOW_W0_WIDTH 2
+#define KVX_SFR_DOW_W0_WFXL_MASK _ULL(0x30)
+#define KVX_SFR_DOW_W0_WFXL_CLEAR _ULL(0x30)
+#define KVX_SFR_DOW_W0_WFXL_SET _ULL(0x3000000000)
+
+#define KVX_SFR_DOW_W1_MASK _ULL(0xc0) /* Watchpoint 1 owner. */
+#define KVX_SFR_DOW_W1_SHIFT 6
+#define KVX_SFR_DOW_W1_WIDTH 2
+#define KVX_SFR_DOW_W1_WFXL_MASK _ULL(0xc0)
+#define KVX_SFR_DOW_W1_WFXL_CLEAR _ULL(0xc0)
+#define KVX_SFR_DOW_W1_WFXL_SET _ULL(0xc000000000)
+
+#define KVX_SFR_MO_MMI_MASK _ULL(0x3) /* Memory Management Instructions owner. */
+#define KVX_SFR_MO_MMI_SHIFT 0
+#define KVX_SFR_MO_MMI_WIDTH 2
+#define KVX_SFR_MO_MMI_WFXL_MASK _ULL(0x3)
+#define KVX_SFR_MO_MMI_WFXL_CLEAR _ULL(0x3)
+#define KVX_SFR_MO_MMI_WFXL_SET _ULL(0x300000000)
+
+#define KVX_SFR_MO_RFE_MASK _ULL(0xc) /* RFE instruction owner. */
+#define KVX_SFR_MO_RFE_SHIFT 2
+#define KVX_SFR_MO_RFE_WIDTH 2
+#define KVX_SFR_MO_RFE_WFXL_MASK _ULL(0xc)
+#define KVX_SFR_MO_RFE_WFXL_CLEAR _ULL(0xc)
+#define KVX_SFR_MO_RFE_WFXL_SET _ULL(0xc00000000)
+
+#define KVX_SFR_MO_STOP_MASK _ULL(0x30) /* STOP instruction owner. */
+#define KVX_SFR_MO_STOP_SHIFT 4
+#define KVX_SFR_MO_STOP_WIDTH 2
+#define KVX_SFR_MO_STOP_WFXL_MASK _ULL(0x30)
+#define KVX_SFR_MO_STOP_WFXL_CLEAR _ULL(0x30)
+#define KVX_SFR_MO_STOP_WFXL_SET _ULL(0x3000000000)
+
+#define KVX_SFR_MO_SYNC_MASK _ULL(0xc0) /* SYNCGROUP instruction owner. */
+#define KVX_SFR_MO_SYNC_SHIFT 6
+#define KVX_SFR_MO_SYNC_WIDTH 2
+#define KVX_SFR_MO_SYNC_WFXL_MASK _ULL(0xc0)
+#define KVX_SFR_MO_SYNC_WFXL_CLEAR _ULL(0xc0)
+#define KVX_SFR_MO_SYNC_WFXL_SET _ULL(0xc000000000)
+
+#define KVX_SFR_MO_PCR_MASK _ULL(0x300) /* PCR register owner. */
+#define KVX_SFR_MO_PCR_SHIFT 8
+#define KVX_SFR_MO_PCR_WIDTH 2
+#define KVX_SFR_MO_PCR_WFXL_MASK _ULL(0x300)
+#define KVX_SFR_MO_PCR_WFXL_CLEAR _ULL(0x300)
+#define KVX_SFR_MO_PCR_WFXL_SET _ULL(0x30000000000)
+
+#define KVX_SFR_MO_MSG_MASK _ULL(0xc00) /* MMU SFR GROUP registers owner. */
+#define KVX_SFR_MO_MSG_SHIFT 10
+#define KVX_SFR_MO_MSG_WIDTH 2
+#define KVX_SFR_MO_MSG_WFXL_MASK _ULL(0xc00)
+#define KVX_SFR_MO_MSG_WFXL_CLEAR _ULL(0xc00)
+#define KVX_SFR_MO_MSG_WFXL_SET _ULL(0xc0000000000)
+
+#define KVX_SFR_MO_MEN_MASK _ULL(0x3000) /* Miscellaneous External Notifications register owner. */
+#define KVX_SFR_MO_MEN_SHIFT 12
+#define KVX_SFR_MO_MEN_WIDTH 2
+#define KVX_SFR_MO_MEN_WFXL_MASK _ULL(0x3000)
+#define KVX_SFR_MO_MEN_WFXL_CLEAR _ULL(0x3000)
+#define KVX_SFR_MO_MEN_WFXL_SET _ULL(0x300000000000)
+
+#define KVX_SFR_MO_MES_MASK _ULL(0xc000) /* Memory Error Status register owner. */
+#define KVX_SFR_MO_MES_SHIFT 14
+#define KVX_SFR_MO_MES_WIDTH 2
+#define KVX_SFR_MO_MES_WFXL_MASK _ULL(0xc000)
+#define KVX_SFR_MO_MES_WFXL_CLEAR _ULL(0xc000)
+#define KVX_SFR_MO_MES_WFXL_SET _ULL(0xc00000000000)
+
+#define KVX_SFR_MO_CSIT_MASK _ULL(0x30000) /* Compute Status Artithmetic Interrupt register owner. */
+#define KVX_SFR_MO_CSIT_SHIFT 16
+#define KVX_SFR_MO_CSIT_WIDTH 2
+#define KVX_SFR_MO_CSIT_WFXL_MASK _ULL(0x30000)
+#define KVX_SFR_MO_CSIT_WFXL_CLEAR _ULL(0x30000)
+#define KVX_SFR_MO_CSIT_WFXL_SET _ULL(0x3000000000000)
+
+#define KVX_SFR_MO_T0_MASK _ULL(0xc0000) /* Timer 0 register group owner */
+#define KVX_SFR_MO_T0_SHIFT 18
+#define KVX_SFR_MO_T0_WIDTH 2
+#define KVX_SFR_MO_T0_WFXL_MASK _ULL(0xc0000)
+#define KVX_SFR_MO_T0_WFXL_CLEAR _ULL(0xc0000)
+#define KVX_SFR_MO_T0_WFXL_SET _ULL(0xc000000000000)
+
+#define KVX_SFR_MO_T1_MASK _ULL(0x300000) /* Timer 1 register group owner */
+#define KVX_SFR_MO_T1_SHIFT 20
+#define KVX_SFR_MO_T1_WIDTH 2
+#define KVX_SFR_MO_T1_WFXL_MASK _ULL(0x300000)
+#define KVX_SFR_MO_T1_WFXL_CLEAR _ULL(0x300000)
+#define KVX_SFR_MO_T1_WFXL_SET _ULL(0x30000000000000)
+
+#define KVX_SFR_MO_WD_MASK _ULL(0xc00000) /* Watch Dog register group owner. */
+#define KVX_SFR_MO_WD_SHIFT 22
+#define KVX_SFR_MO_WD_WIDTH 2
+#define KVX_SFR_MO_WD_WFXL_MASK _ULL(0xc00000)
+#define KVX_SFR_MO_WD_WFXL_CLEAR _ULL(0xc00000)
+#define KVX_SFR_MO_WD_WFXL_SET _ULL(0xc0000000000000)
+
+#define KVX_SFR_MO_PM0_MASK _ULL(0x3000000) /* Performance Monitor 0 register owner. */
+#define KVX_SFR_MO_PM0_SHIFT 24
+#define KVX_SFR_MO_PM0_WIDTH 2
+#define KVX_SFR_MO_PM0_WFXL_MASK _ULL(0x3000000)
+#define KVX_SFR_MO_PM0_WFXL_CLEAR _ULL(0x3000000)
+#define KVX_SFR_MO_PM0_WFXL_SET _ULL(0x300000000000000)
+
+#define KVX_SFR_MO_PM1_MASK _ULL(0xc000000) /* Performance Monitor 1 register owner. */
+#define KVX_SFR_MO_PM1_SHIFT 26
+#define KVX_SFR_MO_PM1_WIDTH 2
+#define KVX_SFR_MO_PM1_WFXL_MASK _ULL(0xc000000)
+#define KVX_SFR_MO_PM1_WFXL_CLEAR _ULL(0xc000000)
+#define KVX_SFR_MO_PM1_WFXL_SET _ULL(0xc00000000000000)
+
+#define KVX_SFR_MO_PM2_MASK _ULL(0x30000000) /* Performance Monitor 2 register owner. */
+#define KVX_SFR_MO_PM2_SHIFT 28
+#define KVX_SFR_MO_PM2_WIDTH 2
+#define KVX_SFR_MO_PM2_WFXL_MASK _ULL(0x30000000)
+#define KVX_SFR_MO_PM2_WFXL_CLEAR _ULL(0x30000000)
+#define KVX_SFR_MO_PM2_WFXL_SET _ULL(0x3000000000000000)
+
+#define KVX_SFR_MO_PM3_MASK _ULL(0xc0000000) /* Performance Monitor 3 register owner. */
+#define KVX_SFR_MO_PM3_SHIFT 30
+#define KVX_SFR_MO_PM3_WIDTH 2
+#define KVX_SFR_MO_PM3_WFXL_MASK _ULL(0xc0000000)
+#define KVX_SFR_MO_PM3_WFXL_CLEAR _ULL(0xc0000000)
+#define KVX_SFR_MO_PM3_WFXL_SET _ULL(0xc000000000000000)
+
+#define KVX_SFR_MO_PMIT_MASK _ULL(0x300000000) /* Performance Monitor Interrupt register group owner. */
+#define KVX_SFR_MO_PMIT_SHIFT 32
+#define KVX_SFR_MO_PMIT_WIDTH 2
+#define KVX_SFR_MO_PMIT_WFXM_MASK _ULL(0x300000000)
+#define KVX_SFR_MO_PMIT_WFXM_CLEAR _ULL(0x3)
+#define KVX_SFR_MO_PMIT_WFXM_SET _ULL(0x300000000)
+
+#define KVX_SFR_MOW_MMI_MASK _ULL(0x3) /* Memory Management Instructions owner. */
+#define KVX_SFR_MOW_MMI_SHIFT 0
+#define KVX_SFR_MOW_MMI_WIDTH 2
+#define KVX_SFR_MOW_MMI_WFXL_MASK _ULL(0x3)
+#define KVX_SFR_MOW_MMI_WFXL_CLEAR _ULL(0x3)
+#define KVX_SFR_MOW_MMI_WFXL_SET _ULL(0x300000000)
+
+#define KVX_SFR_MOW_RFE_MASK _ULL(0xc) /* RFE instruction owner. */
+#define KVX_SFR_MOW_RFE_SHIFT 2
+#define KVX_SFR_MOW_RFE_WIDTH 2
+#define KVX_SFR_MOW_RFE_WFXL_MASK _ULL(0xc)
+#define KVX_SFR_MOW_RFE_WFXL_CLEAR _ULL(0xc)
+#define KVX_SFR_MOW_RFE_WFXL_SET _ULL(0xc00000000)
+
+#define KVX_SFR_MOW_STOP_MASK _ULL(0x30) /* STOP instruction owner. */
+#define KVX_SFR_MOW_STOP_SHIFT 4
+#define KVX_SFR_MOW_STOP_WIDTH 2
+#define KVX_SFR_MOW_STOP_WFXL_MASK _ULL(0x30)
+#define KVX_SFR_MOW_STOP_WFXL_CLEAR _ULL(0x30)
+#define KVX_SFR_MOW_STOP_WFXL_SET _ULL(0x3000000000)
+
+#define KVX_SFR_MOW_SYNC_MASK _ULL(0xc0) /* SYNCGROUP instruction owner. */
+#define KVX_SFR_MOW_SYNC_SHIFT 6
+#define KVX_SFR_MOW_SYNC_WIDTH 2
+#define KVX_SFR_MOW_SYNC_WFXL_MASK _ULL(0xc0)
+#define KVX_SFR_MOW_SYNC_WFXL_CLEAR _ULL(0xc0)
+#define KVX_SFR_MOW_SYNC_WFXL_SET _ULL(0xc000000000)
+
+#define KVX_SFR_MOW_PCR_MASK _ULL(0x300) /* PCR register owner. */
+#define KVX_SFR_MOW_PCR_SHIFT 8
+#define KVX_SFR_MOW_PCR_WIDTH 2
+#define KVX_SFR_MOW_PCR_WFXL_MASK _ULL(0x300)
+#define KVX_SFR_MOW_PCR_WFXL_CLEAR _ULL(0x300)
+#define KVX_SFR_MOW_PCR_WFXL_SET _ULL(0x30000000000)
+
+#define KVX_SFR_MOW_MSG_MASK _ULL(0xc00) /* MMU SFR GROUP registers owner. */
+#define KVX_SFR_MOW_MSG_SHIFT 10
+#define KVX_SFR_MOW_MSG_WIDTH 2
+#define KVX_SFR_MOW_MSG_WFXL_MASK _ULL(0xc00)
+#define KVX_SFR_MOW_MSG_WFXL_CLEAR _ULL(0xc00)
+#define KVX_SFR_MOW_MSG_WFXL_SET _ULL(0xc0000000000)
+
+#define KVX_SFR_MOW_MEN_MASK _ULL(0x3000) /* Miscellaneous External Notifications register owner. */
+#define KVX_SFR_MOW_MEN_SHIFT 12
+#define KVX_SFR_MOW_MEN_WIDTH 2
+#define KVX_SFR_MOW_MEN_WFXL_MASK _ULL(0x3000)
+#define KVX_SFR_MOW_MEN_WFXL_CLEAR _ULL(0x3000)
+#define KVX_SFR_MOW_MEN_WFXL_SET _ULL(0x300000000000)
+
+#define KVX_SFR_MOW_MES_MASK _ULL(0xc000) /* Memory Error Status register owner. */
+#define KVX_SFR_MOW_MES_SHIFT 14
+#define KVX_SFR_MOW_MES_WIDTH 2
+#define KVX_SFR_MOW_MES_WFXL_MASK _ULL(0xc000)
+#define KVX_SFR_MOW_MES_WFXL_CLEAR _ULL(0xc000)
+#define KVX_SFR_MOW_MES_WFXL_SET _ULL(0xc00000000000)
+
+#define KVX_SFR_MOW_CSIT_MASK _ULL(0x30000) /* Compute Status Artithmetic Interrupt register owner. */
+#define KVX_SFR_MOW_CSIT_SHIFT 16
+#define KVX_SFR_MOW_CSIT_WIDTH 2
+#define KVX_SFR_MOW_CSIT_WFXL_MASK _ULL(0x30000)
+#define KVX_SFR_MOW_CSIT_WFXL_CLEAR _ULL(0x30000)
+#define KVX_SFR_MOW_CSIT_WFXL_SET _ULL(0x3000000000000)
+
+#define KVX_SFR_MOW_T0_MASK _ULL(0xc0000) /* Timer 0 register group owner */
+#define KVX_SFR_MOW_T0_SHIFT 18
+#define KVX_SFR_MOW_T0_WIDTH 2
+#define KVX_SFR_MOW_T0_WFXL_MASK _ULL(0xc0000)
+#define KVX_SFR_MOW_T0_WFXL_CLEAR _ULL(0xc0000)
+#define KVX_SFR_MOW_T0_WFXL_SET _ULL(0xc000000000000)
+
+#define KVX_SFR_MOW_T1_MASK _ULL(0x300000) /* Timer 1 register group owner */
+#define KVX_SFR_MOW_T1_SHIFT 20
+#define KVX_SFR_MOW_T1_WIDTH 2
+#define KVX_SFR_MOW_T1_WFXL_MASK _ULL(0x300000)
+#define KVX_SFR_MOW_T1_WFXL_CLEAR _ULL(0x300000)
+#define KVX_SFR_MOW_T1_WFXL_SET _ULL(0x30000000000000)
+
+#define KVX_SFR_MOW_WD_MASK _ULL(0xc00000) /* Watch Dog register group owner. */
+#define KVX_SFR_MOW_WD_SHIFT 22
+#define KVX_SFR_MOW_WD_WIDTH 2
+#define KVX_SFR_MOW_WD_WFXL_MASK _ULL(0xc00000)
+#define KVX_SFR_MOW_WD_WFXL_CLEAR _ULL(0xc00000)
+#define KVX_SFR_MOW_WD_WFXL_SET _ULL(0xc0000000000000)
+
+#define KVX_SFR_MOW_PM0_MASK _ULL(0x3000000) /* Performance Monitor 0 register owner. */
+#define KVX_SFR_MOW_PM0_SHIFT 24
+#define KVX_SFR_MOW_PM0_WIDTH 2
+#define KVX_SFR_MOW_PM0_WFXL_MASK _ULL(0x3000000)
+#define KVX_SFR_MOW_PM0_WFXL_CLEAR _ULL(0x3000000)
+#define KVX_SFR_MOW_PM0_WFXL_SET _ULL(0x300000000000000)
+
+#define KVX_SFR_MOW_PM1_MASK _ULL(0xc000000) /* Performance Monitor 1 register owner. */
+#define KVX_SFR_MOW_PM1_SHIFT 26
+#define KVX_SFR_MOW_PM1_WIDTH 2
+#define KVX_SFR_MOW_PM1_WFXL_MASK _ULL(0xc000000)
+#define KVX_SFR_MOW_PM1_WFXL_CLEAR _ULL(0xc000000)
+#define KVX_SFR_MOW_PM1_WFXL_SET _ULL(0xc00000000000000)
+
+#define KVX_SFR_MOW_PM2_MASK _ULL(0x30000000) /* Performance Monitor 2 register owner. */
+#define KVX_SFR_MOW_PM2_SHIFT 28
+#define KVX_SFR_MOW_PM2_WIDTH 2
+#define KVX_SFR_MOW_PM2_WFXL_MASK _ULL(0x30000000)
+#define KVX_SFR_MOW_PM2_WFXL_CLEAR _ULL(0x30000000)
+#define KVX_SFR_MOW_PM2_WFXL_SET _ULL(0x3000000000000000)
+
+#define KVX_SFR_MOW_PM3_MASK _ULL(0xc0000000) /* Performance Monitor 3 register owner. */
+#define KVX_SFR_MOW_PM3_SHIFT 30
+#define KVX_SFR_MOW_PM3_WIDTH 2
+#define KVX_SFR_MOW_PM3_WFXL_MASK _ULL(0xc0000000)
+#define KVX_SFR_MOW_PM3_WFXL_CLEAR _ULL(0xc0000000)
+#define KVX_SFR_MOW_PM3_WFXL_SET _ULL(0xc000000000000000)
+
+#define KVX_SFR_MOW_PMIT_MASK _ULL(0x300000000) /* Performance Monitor Interrupt register group owner. */
+#define KVX_SFR_MOW_PMIT_SHIFT 32
+#define KVX_SFR_MOW_PMIT_WIDTH 2
+#define KVX_SFR_MOW_PMIT_WFXM_MASK _ULL(0x300000000)
+#define KVX_SFR_MOW_PMIT_WFXM_CLEAR _ULL(0x3)
+#define KVX_SFR_MOW_PMIT_WFXM_SET _ULL(0x300000000)
+
+#define KVX_SFR_PS_PL_MASK _ULL(0x3) /* Current Privilege Level */
+#define KVX_SFR_PS_PL_SHIFT 0
+#define KVX_SFR_PS_PL_WIDTH 2
+#define KVX_SFR_PS_PL_WFXL_MASK _ULL(0x3)
+#define KVX_SFR_PS_PL_WFXL_CLEAR _ULL(0x3)
+#define KVX_SFR_PS_PL_WFXL_SET _ULL(0x300000000)
+
+#define KVX_SFR_PS_ET_MASK _ULL(0x4) /* Exception Taken */
+#define KVX_SFR_PS_ET_SHIFT 2
+#define KVX_SFR_PS_ET_WIDTH 1
+#define KVX_SFR_PS_ET_WFXL_MASK _ULL(0x4)
+#define KVX_SFR_PS_ET_WFXL_CLEAR _ULL(0x4)
+#define KVX_SFR_PS_ET_WFXL_SET _ULL(0x400000000)
+
+#define KVX_SFR_PS_HTD_MASK _ULL(0x8) /* Hardware Trap Disable */
+#define KVX_SFR_PS_HTD_SHIFT 3
+#define KVX_SFR_PS_HTD_WIDTH 1
+#define KVX_SFR_PS_HTD_WFXL_MASK _ULL(0x8)
+#define KVX_SFR_PS_HTD_WFXL_CLEAR _ULL(0x8)
+#define KVX_SFR_PS_HTD_WFXL_SET _ULL(0x800000000)
+
+#define KVX_SFR_PS_IE_MASK _ULL(0x10) /* Interrupt Enable */
+#define KVX_SFR_PS_IE_SHIFT 4
+#define KVX_SFR_PS_IE_WIDTH 1
+#define KVX_SFR_PS_IE_WFXL_MASK _ULL(0x10)
+#define KVX_SFR_PS_IE_WFXL_CLEAR _ULL(0x10)
+#define KVX_SFR_PS_IE_WFXL_SET _ULL(0x1000000000)
+
+#define KVX_SFR_PS_HLE_MASK _ULL(0x20) /* Hardware Loop Enable */
+#define KVX_SFR_PS_HLE_SHIFT 5
+#define KVX_SFR_PS_HLE_WIDTH 1
+#define KVX_SFR_PS_HLE_WFXL_MASK _ULL(0x20)
+#define KVX_SFR_PS_HLE_WFXL_CLEAR _ULL(0x20)
+#define KVX_SFR_PS_HLE_WFXL_SET _ULL(0x2000000000)
+
+#define KVX_SFR_PS_SRE_MASK _ULL(0x40) /* Software REserved */
+#define KVX_SFR_PS_SRE_SHIFT 6
+#define KVX_SFR_PS_SRE_WIDTH 1
+#define KVX_SFR_PS_SRE_WFXL_MASK _ULL(0x40)
+#define KVX_SFR_PS_SRE_WFXL_CLEAR _ULL(0x40)
+#define KVX_SFR_PS_SRE_WFXL_SET _ULL(0x4000000000)
+
+#define KVX_SFR_PS_DAUS_MASK _ULL(0x80) /* Data Accesses Use SPS settings */
+#define KVX_SFR_PS_DAUS_SHIFT 7
+#define KVX_SFR_PS_DAUS_WIDTH 1
+#define KVX_SFR_PS_DAUS_WFXL_MASK _ULL(0x80)
+#define KVX_SFR_PS_DAUS_WFXL_CLEAR _ULL(0x80)
+#define KVX_SFR_PS_DAUS_WFXL_SET _ULL(0x8000000000)
+
+#define KVX_SFR_PS_ICE_MASK _ULL(0x100) /* Instruction Cache Enable */
+#define KVX_SFR_PS_ICE_SHIFT 8
+#define KVX_SFR_PS_ICE_WIDTH 1
+#define KVX_SFR_PS_ICE_WFXL_MASK _ULL(0x100)
+#define KVX_SFR_PS_ICE_WFXL_CLEAR _ULL(0x100)
+#define KVX_SFR_PS_ICE_WFXL_SET _ULL(0x10000000000)
+
+#define KVX_SFR_PS_USE_MASK _ULL(0x200) /* Uncached Streaming Enable */
+#define KVX_SFR_PS_USE_SHIFT 9
+#define KVX_SFR_PS_USE_WIDTH 1
+#define KVX_SFR_PS_USE_WFXL_MASK _ULL(0x200)
+#define KVX_SFR_PS_USE_WFXL_CLEAR _ULL(0x200)
+#define KVX_SFR_PS_USE_WFXL_SET _ULL(0x20000000000)
+
+#define KVX_SFR_PS_DCE_MASK _ULL(0x400) /* Data Cache Enable */
+#define KVX_SFR_PS_DCE_SHIFT 10
+#define KVX_SFR_PS_DCE_WIDTH 1
+#define KVX_SFR_PS_DCE_WFXL_MASK _ULL(0x400)
+#define KVX_SFR_PS_DCE_WFXL_CLEAR _ULL(0x400)
+#define KVX_SFR_PS_DCE_WFXL_SET _ULL(0x40000000000)
+
+#define KVX_SFR_PS_MME_MASK _ULL(0x800) /* Memory Management Enable */
+#define KVX_SFR_PS_MME_SHIFT 11
+#define KVX_SFR_PS_MME_WIDTH 1
+#define KVX_SFR_PS_MME_WFXL_MASK _ULL(0x800)
+#define KVX_SFR_PS_MME_WFXL_CLEAR _ULL(0x800)
+#define KVX_SFR_PS_MME_WFXL_SET _ULL(0x80000000000)
+
+#define KVX_SFR_PS_IL_MASK _ULL(0x3000) /* Interrupt Level */
+#define KVX_SFR_PS_IL_SHIFT 12
+#define KVX_SFR_PS_IL_WIDTH 2
+#define KVX_SFR_PS_IL_WFXL_MASK _ULL(0x3000)
+#define KVX_SFR_PS_IL_WFXL_CLEAR _ULL(0x3000)
+#define KVX_SFR_PS_IL_WFXL_SET _ULL(0x300000000000)
+
+#define KVX_SFR_PS_VS_MASK _ULL(0xc000) /* Virtual Space */
+#define KVX_SFR_PS_VS_SHIFT 14
+#define KVX_SFR_PS_VS_WIDTH 2
+#define KVX_SFR_PS_VS_WFXL_MASK _ULL(0xc000)
+#define KVX_SFR_PS_VS_WFXL_CLEAR _ULL(0xc000)
+#define KVX_SFR_PS_VS_WFXL_SET _ULL(0xc00000000000)
+
+#define KVX_SFR_PS_V64_MASK _ULL(0x10000) /* Virtual 64 bits mode. */
+#define KVX_SFR_PS_V64_SHIFT 16
+#define KVX_SFR_PS_V64_WIDTH 1
+#define KVX_SFR_PS_V64_WFXL_MASK _ULL(0x10000)
+#define KVX_SFR_PS_V64_WFXL_CLEAR _ULL(0x10000)
+#define KVX_SFR_PS_V64_WFXL_SET _ULL(0x1000000000000)
+
+#define KVX_SFR_PS_L2E_MASK _ULL(0x20000) /* L2 cache Enable. */
+#define KVX_SFR_PS_L2E_SHIFT 17
+#define KVX_SFR_PS_L2E_WIDTH 1
+#define KVX_SFR_PS_L2E_WFXL_MASK _ULL(0x20000)
+#define KVX_SFR_PS_L2E_WFXL_CLEAR _ULL(0x20000)
+#define KVX_SFR_PS_L2E_WFXL_SET _ULL(0x2000000000000)
+
+#define KVX_SFR_PS_SME_MASK _ULL(0x40000) /* Step Mode Enabled */
+#define KVX_SFR_PS_SME_SHIFT 18
+#define KVX_SFR_PS_SME_WIDTH 1
+#define KVX_SFR_PS_SME_WFXL_MASK _ULL(0x40000)
+#define KVX_SFR_PS_SME_WFXL_CLEAR _ULL(0x40000)
+#define KVX_SFR_PS_SME_WFXL_SET _ULL(0x4000000000000)
+
+#define KVX_SFR_PS_SMR_MASK _ULL(0x80000) /* Step Mode Ready */
+#define KVX_SFR_PS_SMR_SHIFT 19
+#define KVX_SFR_PS_SMR_WIDTH 1
+#define KVX_SFR_PS_SMR_WFXL_MASK _ULL(0x80000)
+#define KVX_SFR_PS_SMR_WFXL_CLEAR _ULL(0x80000)
+#define KVX_SFR_PS_SMR_WFXL_SET _ULL(0x8000000000000)
+
+#define KVX_SFR_PS_PMJ_MASK _ULL(0xf00000) /* Page Mask in JTLB. */
+#define KVX_SFR_PS_PMJ_SHIFT 20
+#define KVX_SFR_PS_PMJ_WIDTH 4
+#define KVX_SFR_PS_PMJ_WFXL_MASK _ULL(0xf00000)
+#define KVX_SFR_PS_PMJ_WFXL_CLEAR _ULL(0xf00000)
+#define KVX_SFR_PS_PMJ_WFXL_SET _ULL(0xf0000000000000)
+
+#define KVX_SFR_PS_MMUP_MASK _ULL(0x1000000) /* Privileged on MMU. */
+#define KVX_SFR_PS_MMUP_SHIFT 24
+#define KVX_SFR_PS_MMUP_WIDTH 1
+#define KVX_SFR_PS_MMUP_WFXL_MASK _ULL(0x1000000)
+#define KVX_SFR_PS_MMUP_WFXL_CLEAR _ULL(0x1000000)
+#define KVX_SFR_PS_MMUP_WFXL_SET _ULL(0x100000000000000)
+
+#define KVX_SFR_SPS_PL_MASK _ULL(0x3) /* Current Privilege Level */
+#define KVX_SFR_SPS_PL_SHIFT 0
+#define KVX_SFR_SPS_PL_WIDTH 2
+#define KVX_SFR_SPS_PL_WFXL_MASK _ULL(0x3)
+#define KVX_SFR_SPS_PL_WFXL_CLEAR _ULL(0x3)
+#define KVX_SFR_SPS_PL_WFXL_SET _ULL(0x300000000)
+
+#define KVX_SFR_SPS_ET_MASK _ULL(0x4) /* Exception Taken */
+#define KVX_SFR_SPS_ET_SHIFT 2
+#define KVX_SFR_SPS_ET_WIDTH 1
+#define KVX_SFR_SPS_ET_WFXL_MASK _ULL(0x4)
+#define KVX_SFR_SPS_ET_WFXL_CLEAR _ULL(0x4)
+#define KVX_SFR_SPS_ET_WFXL_SET _ULL(0x400000000)
+
+#define KVX_SFR_SPS_HTD_MASK _ULL(0x8) /* Hardware Trap Disable */
+#define KVX_SFR_SPS_HTD_SHIFT 3
+#define KVX_SFR_SPS_HTD_WIDTH 1
+#define KVX_SFR_SPS_HTD_WFXL_MASK _ULL(0x8)
+#define KVX_SFR_SPS_HTD_WFXL_CLEAR _ULL(0x8)
+#define KVX_SFR_SPS_HTD_WFXL_SET _ULL(0x800000000)
+
+#define KVX_SFR_SPS_IE_MASK _ULL(0x10) /* Interrupt Enable */
+#define KVX_SFR_SPS_IE_SHIFT 4
+#define KVX_SFR_SPS_IE_WIDTH 1
+#define KVX_SFR_SPS_IE_WFXL_MASK _ULL(0x10)
+#define KVX_SFR_SPS_IE_WFXL_CLEAR _ULL(0x10)
+#define KVX_SFR_SPS_IE_WFXL_SET _ULL(0x1000000000)
+
+#define KVX_SFR_SPS_HLE_MASK _ULL(0x20) /* Hardware Loop Enable */
+#define KVX_SFR_SPS_HLE_SHIFT 5
+#define KVX_SFR_SPS_HLE_WIDTH 1
+#define KVX_SFR_SPS_HLE_WFXL_MASK _ULL(0x20)
+#define KVX_SFR_SPS_HLE_WFXL_CLEAR _ULL(0x20)
+#define KVX_SFR_SPS_HLE_WFXL_SET _ULL(0x2000000000)
+
+#define KVX_SFR_SPS_SRE_MASK _ULL(0x40) /* Software REserved */
+#define KVX_SFR_SPS_SRE_SHIFT 6
+#define KVX_SFR_SPS_SRE_WIDTH 1
+#define KVX_SFR_SPS_SRE_WFXL_MASK _ULL(0x40)
+#define KVX_SFR_SPS_SRE_WFXL_CLEAR _ULL(0x40)
+#define KVX_SFR_SPS_SRE_WFXL_SET _ULL(0x4000000000)
+
+#define KVX_SFR_SPS_DAUS_MASK _ULL(0x80) /* Data Accesses Use SPS settings */
+#define KVX_SFR_SPS_DAUS_SHIFT 7
+#define KVX_SFR_SPS_DAUS_WIDTH 1
+#define KVX_SFR_SPS_DAUS_WFXL_MASK _ULL(0x80)
+#define KVX_SFR_SPS_DAUS_WFXL_CLEAR _ULL(0x80)
+#define KVX_SFR_SPS_DAUS_WFXL_SET _ULL(0x8000000000)
+
+#define KVX_SFR_SPS_ICE_MASK _ULL(0x100) /* Instruction Cache Enable */
+#define KVX_SFR_SPS_ICE_SHIFT 8
+#define KVX_SFR_SPS_ICE_WIDTH 1
+#define KVX_SFR_SPS_ICE_WFXL_MASK _ULL(0x100)
+#define KVX_SFR_SPS_ICE_WFXL_CLEAR _ULL(0x100)
+#define KVX_SFR_SPS_ICE_WFXL_SET _ULL(0x10000000000)
+
+#define KVX_SFR_SPS_USE_MASK _ULL(0x200) /* Uncached Streaming Enable */
+#define KVX_SFR_SPS_USE_SHIFT 9
+#define KVX_SFR_SPS_USE_WIDTH 1
+#define KVX_SFR_SPS_USE_WFXL_MASK _ULL(0x200)
+#define KVX_SFR_SPS_USE_WFXL_CLEAR _ULL(0x200)
+#define KVX_SFR_SPS_USE_WFXL_SET _ULL(0x20000000000)
+
+#define KVX_SFR_SPS_DCE_MASK _ULL(0x400) /* Data Cache Enable */
+#define KVX_SFR_SPS_DCE_SHIFT 10
+#define KVX_SFR_SPS_DCE_WIDTH 1
+#define KVX_SFR_SPS_DCE_WFXL_MASK _ULL(0x400)
+#define KVX_SFR_SPS_DCE_WFXL_CLEAR _ULL(0x400)
+#define KVX_SFR_SPS_DCE_WFXL_SET _ULL(0x40000000000)
+
+#define KVX_SFR_SPS_MME_MASK _ULL(0x800) /* Memory Management Enable */
+#define KVX_SFR_SPS_MME_SHIFT 11
+#define KVX_SFR_SPS_MME_WIDTH 1
+#define KVX_SFR_SPS_MME_WFXL_MASK _ULL(0x800)
+#define KVX_SFR_SPS_MME_WFXL_CLEAR _ULL(0x800)
+#define KVX_SFR_SPS_MME_WFXL_SET _ULL(0x80000000000)
+
+#define KVX_SFR_SPS_IL_MASK _ULL(0x3000) /* Interrupt Level */
+#define KVX_SFR_SPS_IL_SHIFT 12
+#define KVX_SFR_SPS_IL_WIDTH 2
+#define KVX_SFR_SPS_IL_WFXL_MASK _ULL(0x3000)
+#define KVX_SFR_SPS_IL_WFXL_CLEAR _ULL(0x3000)
+#define KVX_SFR_SPS_IL_WFXL_SET _ULL(0x300000000000)
+
+#define KVX_SFR_SPS_VS_MASK _ULL(0xc000) /* Virtual Space */
+#define KVX_SFR_SPS_VS_SHIFT 14
+#define KVX_SFR_SPS_VS_WIDTH 2
+#define KVX_SFR_SPS_VS_WFXL_MASK _ULL(0xc000)
+#define KVX_SFR_SPS_VS_WFXL_CLEAR _ULL(0xc000)
+#define KVX_SFR_SPS_VS_WFXL_SET _ULL(0xc00000000000)
+
+#define KVX_SFR_SPS_V64_MASK _ULL(0x10000) /* Virtual 64 bits mode. */
+#define KVX_SFR_SPS_V64_SHIFT 16
+#define KVX_SFR_SPS_V64_WIDTH 1
+#define KVX_SFR_SPS_V64_WFXL_MASK _ULL(0x10000)
+#define KVX_SFR_SPS_V64_WFXL_CLEAR _ULL(0x10000)
+#define KVX_SFR_SPS_V64_WFXL_SET _ULL(0x1000000000000)
+
+#define KVX_SFR_SPS_L2E_MASK _ULL(0x20000) /* L2 cache Enable. */
+#define KVX_SFR_SPS_L2E_SHIFT 17
+#define KVX_SFR_SPS_L2E_WIDTH 1
+#define KVX_SFR_SPS_L2E_WFXL_MASK _ULL(0x20000)
+#define KVX_SFR_SPS_L2E_WFXL_CLEAR _ULL(0x20000)
+#define KVX_SFR_SPS_L2E_WFXL_SET _ULL(0x2000000000000)
+
+#define KVX_SFR_SPS_SME_MASK _ULL(0x40000) /* Step Mode Enabled */
+#define KVX_SFR_SPS_SME_SHIFT 18
+#define KVX_SFR_SPS_SME_WIDTH 1
+#define KVX_SFR_SPS_SME_WFXL_MASK _ULL(0x40000)
+#define KVX_SFR_SPS_SME_WFXL_CLEAR _ULL(0x40000)
+#define KVX_SFR_SPS_SME_WFXL_SET _ULL(0x4000000000000)
+
+#define KVX_SFR_SPS_SMR_MASK _ULL(0x80000) /* Step Mode Ready */
+#define KVX_SFR_SPS_SMR_SHIFT 19
+#define KVX_SFR_SPS_SMR_WIDTH 1
+#define KVX_SFR_SPS_SMR_WFXL_MASK _ULL(0x80000)
+#define KVX_SFR_SPS_SMR_WFXL_CLEAR _ULL(0x80000)
+#define KVX_SFR_SPS_SMR_WFXL_SET _ULL(0x8000000000000)
+
+#define KVX_SFR_SPS_PMJ_MASK _ULL(0xf00000) /* Page Mask in JTLB. */
+#define KVX_SFR_SPS_PMJ_SHIFT 20
+#define KVX_SFR_SPS_PMJ_WIDTH 4
+#define KVX_SFR_SPS_PMJ_WFXL_MASK _ULL(0xf00000)
+#define KVX_SFR_SPS_PMJ_WFXL_CLEAR _ULL(0xf00000)
+#define KVX_SFR_SPS_PMJ_WFXL_SET _ULL(0xf0000000000000)
+
+#define KVX_SFR_SPS_MMUP_MASK _ULL(0x1000000) /* Privileged on MMU. */
+#define KVX_SFR_SPS_MMUP_SHIFT 24
+#define KVX_SFR_SPS_MMUP_WIDTH 1
+#define KVX_SFR_SPS_MMUP_WFXL_MASK _ULL(0x1000000)
+#define KVX_SFR_SPS_MMUP_WFXL_CLEAR _ULL(0x1000000)
+#define KVX_SFR_SPS_MMUP_WFXL_SET _ULL(0x100000000000000)
+
+#define KVX_SFR_SPS_PL0_PL_MASK _ULL(0x3) /* Current Privilege Level */
+#define KVX_SFR_SPS_PL0_PL_SHIFT 0
+#define KVX_SFR_SPS_PL0_PL_WIDTH 2
+#define KVX_SFR_SPS_PL0_PL_WFXL_MASK _ULL(0x3)
+#define KVX_SFR_SPS_PL0_PL_WFXL_CLEAR _ULL(0x3)
+#define KVX_SFR_SPS_PL0_PL_WFXL_SET _ULL(0x300000000)
+
+#define KVX_SFR_SPS_PL0_ET_MASK _ULL(0x4) /* Exception Taken */
+#define KVX_SFR_SPS_PL0_ET_SHIFT 2
+#define KVX_SFR_SPS_PL0_ET_WIDTH 1
+#define KVX_SFR_SPS_PL0_ET_WFXL_MASK _ULL(0x4)
+#define KVX_SFR_SPS_PL0_ET_WFXL_CLEAR _ULL(0x4)
+#define KVX_SFR_SPS_PL0_ET_WFXL_SET _ULL(0x400000000)
+
+#define KVX_SFR_SPS_PL0_HTD_MASK _ULL(0x8) /* Hardware Trap Disable */
+#define KVX_SFR_SPS_PL0_HTD_SHIFT 3
+#define KVX_SFR_SPS_PL0_HTD_WIDTH 1
+#define KVX_SFR_SPS_PL0_HTD_WFXL_MASK _ULL(0x8)
+#define KVX_SFR_SPS_PL0_HTD_WFXL_CLEAR _ULL(0x8)
+#define KVX_SFR_SPS_PL0_HTD_WFXL_SET _ULL(0x800000000)
+
+#define KVX_SFR_SPS_PL0_IE_MASK _ULL(0x10) /* Interrupt Enable */
+#define KVX_SFR_SPS_PL0_IE_SHIFT 4
+#define KVX_SFR_SPS_PL0_IE_WIDTH 1
+#define KVX_SFR_SPS_PL0_IE_WFXL_MASK _ULL(0x10)
+#define KVX_SFR_SPS_PL0_IE_WFXL_CLEAR _ULL(0x10)
+#define KVX_SFR_SPS_PL0_IE_WFXL_SET _ULL(0x1000000000)
+
+#define KVX_SFR_SPS_PL0_HLE_MASK _ULL(0x20) /* Hardware Loop Enable */
+#define KVX_SFR_SPS_PL0_HLE_SHIFT 5
+#define KVX_SFR_SPS_PL0_HLE_WIDTH 1
+#define KVX_SFR_SPS_PL0_HLE_WFXL_MASK _ULL(0x20)
+#define KVX_SFR_SPS_PL0_HLE_WFXL_CLEAR _ULL(0x20)
+#define KVX_SFR_SPS_PL0_HLE_WFXL_SET _ULL(0x2000000000)
+
+#define KVX_SFR_SPS_PL0_SRE_MASK _ULL(0x40) /* Software REserved */
+#define KVX_SFR_SPS_PL0_SRE_SHIFT 6
+#define KVX_SFR_SPS_PL0_SRE_WIDTH 1
+#define KVX_SFR_SPS_PL0_SRE_WFXL_MASK _ULL(0x40)
+#define KVX_SFR_SPS_PL0_SRE_WFXL_CLEAR _ULL(0x40)
+#define KVX_SFR_SPS_PL0_SRE_WFXL_SET _ULL(0x4000000000)
+
+#define KVX_SFR_SPS_PL0_DAUS_MASK _ULL(0x80) /* Data Accesses Use SPS settings */
+#define KVX_SFR_SPS_PL0_DAUS_SHIFT 7
+#define KVX_SFR_SPS_PL0_DAUS_WIDTH 1
+#define KVX_SFR_SPS_PL0_DAUS_WFXL_MASK _ULL(0x80)
+#define KVX_SFR_SPS_PL0_DAUS_WFXL_CLEAR _ULL(0x80)
+#define KVX_SFR_SPS_PL0_DAUS_WFXL_SET _ULL(0x8000000000)
+
+#define KVX_SFR_SPS_PL0_ICE_MASK _ULL(0x100) /* Instruction Cache Enable */
+#define KVX_SFR_SPS_PL0_ICE_SHIFT 8
+#define KVX_SFR_SPS_PL0_ICE_WIDTH 1
+#define KVX_SFR_SPS_PL0_ICE_WFXL_MASK _ULL(0x100)
+#define KVX_SFR_SPS_PL0_ICE_WFXL_CLEAR _ULL(0x100)
+#define KVX_SFR_SPS_PL0_ICE_WFXL_SET _ULL(0x10000000000)
+
+#define KVX_SFR_SPS_PL0_USE_MASK _ULL(0x200) /* Uncached Streaming Enable */
+#define KVX_SFR_SPS_PL0_USE_SHIFT 9
+#define KVX_SFR_SPS_PL0_USE_WIDTH 1
+#define KVX_SFR_SPS_PL0_USE_WFXL_MASK _ULL(0x200)
+#define KVX_SFR_SPS_PL0_USE_WFXL_CLEAR _ULL(0x200)
+#define KVX_SFR_SPS_PL0_USE_WFXL_SET _ULL(0x20000000000)
+
+#define KVX_SFR_SPS_PL0_DCE_MASK _ULL(0x400) /* Data Cache Enable */
+#define KVX_SFR_SPS_PL0_DCE_SHIFT 10
+#define KVX_SFR_SPS_PL0_DCE_WIDTH 1
+#define KVX_SFR_SPS_PL0_DCE_WFXL_MASK _ULL(0x400)
+#define KVX_SFR_SPS_PL0_DCE_WFXL_CLEAR _ULL(0x400)
+#define KVX_SFR_SPS_PL0_DCE_WFXL_SET _ULL(0x40000000000)
+
+#define KVX_SFR_SPS_PL0_MME_MASK _ULL(0x800) /* Memory Management Enable */
+#define KVX_SFR_SPS_PL0_MME_SHIFT 11
+#define KVX_SFR_SPS_PL0_MME_WIDTH 1
+#define KVX_SFR_SPS_PL0_MME_WFXL_MASK _ULL(0x800)
+#define KVX_SFR_SPS_PL0_MME_WFXL_CLEAR _ULL(0x800)
+#define KVX_SFR_SPS_PL0_MME_WFXL_SET _ULL(0x80000000000)
+
+#define KVX_SFR_SPS_PL0_IL_MASK _ULL(0x3000) /* Interrupt Level */
+#define KVX_SFR_SPS_PL0_IL_SHIFT 12
+#define KVX_SFR_SPS_PL0_IL_WIDTH 2
+#define KVX_SFR_SPS_PL0_IL_WFXL_MASK _ULL(0x3000)
+#define KVX_SFR_SPS_PL0_IL_WFXL_CLEAR _ULL(0x3000)
+#define KVX_SFR_SPS_PL0_IL_WFXL_SET _ULL(0x300000000000)
+
+#define KVX_SFR_SPS_PL0_VS_MASK _ULL(0xc000) /* Virtual Space */
+#define KVX_SFR_SPS_PL0_VS_SHIFT 14
+#define KVX_SFR_SPS_PL0_VS_WIDTH 2
+#define KVX_SFR_SPS_PL0_VS_WFXL_MASK _ULL(0xc000)
+#define KVX_SFR_SPS_PL0_VS_WFXL_CLEAR _ULL(0xc000)
+#define KVX_SFR_SPS_PL0_VS_WFXL_SET _ULL(0xc00000000000)
+
+#define KVX_SFR_SPS_PL0_V64_MASK _ULL(0x10000) /* Virtual 64 bits mode. */
+#define KVX_SFR_SPS_PL0_V64_SHIFT 16
+#define KVX_SFR_SPS_PL0_V64_WIDTH 1
+#define KVX_SFR_SPS_PL0_V64_WFXL_MASK _ULL(0x10000)
+#define KVX_SFR_SPS_PL0_V64_WFXL_CLEAR _ULL(0x10000)
+#define KVX_SFR_SPS_PL0_V64_WFXL_SET _ULL(0x1000000000000)
+
+#define KVX_SFR_SPS_PL0_L2E_MASK _ULL(0x20000) /* L2 cache Enable. */
+#define KVX_SFR_SPS_PL0_L2E_SHIFT 17
+#define KVX_SFR_SPS_PL0_L2E_WIDTH 1
+#define KVX_SFR_SPS_PL0_L2E_WFXL_MASK _ULL(0x20000)
+#define KVX_SFR_SPS_PL0_L2E_WFXL_CLEAR _ULL(0x20000)
+#define KVX_SFR_SPS_PL0_L2E_WFXL_SET _ULL(0x2000000000000)
+
+#define KVX_SFR_SPS_PL0_SME_MASK _ULL(0x40000) /* Step Mode Enabled */
+#define KVX_SFR_SPS_PL0_SME_SHIFT 18
+#define KVX_SFR_SPS_PL0_SME_WIDTH 1
+#define KVX_SFR_SPS_PL0_SME_WFXL_MASK _ULL(0x40000)
+#define KVX_SFR_SPS_PL0_SME_WFXL_CLEAR _ULL(0x40000)
+#define KVX_SFR_SPS_PL0_SME_WFXL_SET _ULL(0x4000000000000)
+
+#define KVX_SFR_SPS_PL0_SMR_MASK _ULL(0x80000) /* Step Mode Ready */
+#define KVX_SFR_SPS_PL0_SMR_SHIFT 19
+#define KVX_SFR_SPS_PL0_SMR_WIDTH 1
+#define KVX_SFR_SPS_PL0_SMR_WFXL_MASK _ULL(0x80000)
+#define KVX_SFR_SPS_PL0_SMR_WFXL_CLEAR _ULL(0x80000)
+#define KVX_SFR_SPS_PL0_SMR_WFXL_SET _ULL(0x8000000000000)
+
+#define KVX_SFR_SPS_PL0_PMJ_MASK _ULL(0xf00000) /* Page Mask in JTLB. */
+#define KVX_SFR_SPS_PL0_PMJ_SHIFT 20
+#define KVX_SFR_SPS_PL0_PMJ_WIDTH 4
+#define KVX_SFR_SPS_PL0_PMJ_WFXL_MASK _ULL(0xf00000)
+#define KVX_SFR_SPS_PL0_PMJ_WFXL_CLEAR _ULL(0xf00000)
+#define KVX_SFR_SPS_PL0_PMJ_WFXL_SET _ULL(0xf0000000000000)
+
+#define KVX_SFR_SPS_PL0_MMUP_MASK _ULL(0x1000000) /* Privileged on MMU. */
+#define KVX_SFR_SPS_PL0_MMUP_SHIFT 24
+#define KVX_SFR_SPS_PL0_MMUP_WIDTH 1
+#define KVX_SFR_SPS_PL0_MMUP_WFXL_MASK _ULL(0x1000000)
+#define KVX_SFR_SPS_PL0_MMUP_WFXL_CLEAR _ULL(0x1000000)
+#define KVX_SFR_SPS_PL0_MMUP_WFXL_SET _ULL(0x100000000000000)
+
+#define KVX_SFR_SPS_PL1_PL_MASK _ULL(0x3) /* Current Privilege Level */
+#define KVX_SFR_SPS_PL1_PL_SHIFT 0
+#define KVX_SFR_SPS_PL1_PL_WIDTH 2
+#define KVX_SFR_SPS_PL1_PL_WFXL_MASK _ULL(0x3)
+#define KVX_SFR_SPS_PL1_PL_WFXL_CLEAR _ULL(0x3)
+#define KVX_SFR_SPS_PL1_PL_WFXL_SET _ULL(0x300000000)
+
+#define KVX_SFR_SPS_PL1_ET_MASK _ULL(0x4) /* Exception Taken */
+#define KVX_SFR_SPS_PL1_ET_SHIFT 2
+#define KVX_SFR_SPS_PL1_ET_WIDTH 1
+#define KVX_SFR_SPS_PL1_ET_WFXL_MASK _ULL(0x4)
+#define KVX_SFR_SPS_PL1_ET_WFXL_CLEAR _ULL(0x4)
+#define KVX_SFR_SPS_PL1_ET_WFXL_SET _ULL(0x400000000)
+
+#define KVX_SFR_SPS_PL1_HTD_MASK _ULL(0x8) /* Hardware Trap Disable */
+#define KVX_SFR_SPS_PL1_HTD_SHIFT 3
+#define KVX_SFR_SPS_PL1_HTD_WIDTH 1
+#define KVX_SFR_SPS_PL1_HTD_WFXL_MASK _ULL(0x8)
+#define KVX_SFR_SPS_PL1_HTD_WFXL_CLEAR _ULL(0x8)
+#define KVX_SFR_SPS_PL1_HTD_WFXL_SET _ULL(0x800000000)
+
+#define KVX_SFR_SPS_PL1_IE_MASK _ULL(0x10) /* Interrupt Enable */
+#define KVX_SFR_SPS_PL1_IE_SHIFT 4
+#define KVX_SFR_SPS_PL1_IE_WIDTH 1
+#define KVX_SFR_SPS_PL1_IE_WFXL_MASK _ULL(0x10)
+#define KVX_SFR_SPS_PL1_IE_WFXL_CLEAR _ULL(0x10)
+#define KVX_SFR_SPS_PL1_IE_WFXL_SET _ULL(0x1000000000)
+
+#define KVX_SFR_SPS_PL1_HLE_MASK _ULL(0x20) /* Hardware Loop Enable */
+#define KVX_SFR_SPS_PL1_HLE_SHIFT 5
+#define KVX_SFR_SPS_PL1_HLE_WIDTH 1
+#define KVX_SFR_SPS_PL1_HLE_WFXL_MASK _ULL(0x20)
+#define KVX_SFR_SPS_PL1_HLE_WFXL_CLEAR _ULL(0x20)
+#define KVX_SFR_SPS_PL1_HLE_WFXL_SET _ULL(0x2000000000)
+
+#define KVX_SFR_SPS_PL1_SRE_MASK _ULL(0x40) /* Software REserved */
+#define KVX_SFR_SPS_PL1_SRE_SHIFT 6
+#define KVX_SFR_SPS_PL1_SRE_WIDTH 1
+#define KVX_SFR_SPS_PL1_SRE_WFXL_MASK _ULL(0x40)
+#define KVX_SFR_SPS_PL1_SRE_WFXL_CLEAR _ULL(0x40)
+#define KVX_SFR_SPS_PL1_SRE_WFXL_SET _ULL(0x4000000000)
+
+#define KVX_SFR_SPS_PL1_DAUS_MASK _ULL(0x80) /* Data Accesses Use SPS settings */
+#define KVX_SFR_SPS_PL1_DAUS_SHIFT 7
+#define KVX_SFR_SPS_PL1_DAUS_WIDTH 1
+#define KVX_SFR_SPS_PL1_DAUS_WFXL_MASK _ULL(0x80)
+#define KVX_SFR_SPS_PL1_DAUS_WFXL_CLEAR _ULL(0x80)
+#define KVX_SFR_SPS_PL1_DAUS_WFXL_SET _ULL(0x8000000000)
+
+#define KVX_SFR_SPS_PL1_ICE_MASK _ULL(0x100) /* Instruction Cache Enable */
+#define KVX_SFR_SPS_PL1_ICE_SHIFT 8
+#define KVX_SFR_SPS_PL1_ICE_WIDTH 1
+#define KVX_SFR_SPS_PL1_ICE_WFXL_MASK _ULL(0x100)
+#define KVX_SFR_SPS_PL1_ICE_WFXL_CLEAR _ULL(0x100)
+#define KVX_SFR_SPS_PL1_ICE_WFXL_SET _ULL(0x10000000000)
+
+#define KVX_SFR_SPS_PL1_USE_MASK _ULL(0x200) /* Uncached Streaming Enable */
+#define KVX_SFR_SPS_PL1_USE_SHIFT 9
+#define KVX_SFR_SPS_PL1_USE_WIDTH 1
+#define KVX_SFR_SPS_PL1_USE_WFXL_MASK _ULL(0x200)
+#define KVX_SFR_SPS_PL1_USE_WFXL_CLEAR _ULL(0x200)
+#define KVX_SFR_SPS_PL1_USE_WFXL_SET _ULL(0x20000000000)
+
+#define KVX_SFR_SPS_PL1_DCE_MASK _ULL(0x400) /* Data Cache Enable */
+#define KVX_SFR_SPS_PL1_DCE_SHIFT 10
+#define KVX_SFR_SPS_PL1_DCE_WIDTH 1
+#define KVX_SFR_SPS_PL1_DCE_WFXL_MASK _ULL(0x400)
+#define KVX_SFR_SPS_PL1_DCE_WFXL_CLEAR _ULL(0x400)
+#define KVX_SFR_SPS_PL1_DCE_WFXL_SET _ULL(0x40000000000)
+
+#define KVX_SFR_SPS_PL1_MME_MASK _ULL(0x800) /* Memory Management Enable */
+#define KVX_SFR_SPS_PL1_MME_SHIFT 11
+#define KVX_SFR_SPS_PL1_MME_WIDTH 1
+#define KVX_SFR_SPS_PL1_MME_WFXL_MASK _ULL(0x800)
+#define KVX_SFR_SPS_PL1_MME_WFXL_CLEAR _ULL(0x800)
+#define KVX_SFR_SPS_PL1_MME_WFXL_SET _ULL(0x80000000000)
+
+#define KVX_SFR_SPS_PL1_IL_MASK _ULL(0x3000) /* Interrupt Level */
+#define KVX_SFR_SPS_PL1_IL_SHIFT 12
+#define KVX_SFR_SPS_PL1_IL_WIDTH 2
+#define KVX_SFR_SPS_PL1_IL_WFXL_MASK _ULL(0x3000)
+#define KVX_SFR_SPS_PL1_IL_WFXL_CLEAR _ULL(0x3000)
+#define KVX_SFR_SPS_PL1_IL_WFXL_SET _ULL(0x300000000000)
+
+#define KVX_SFR_SPS_PL1_VS_MASK _ULL(0xc000) /* Virtual Space */
+#define KVX_SFR_SPS_PL1_VS_SHIFT 14
+#define KVX_SFR_SPS_PL1_VS_WIDTH 2
+#define KVX_SFR_SPS_PL1_VS_WFXL_MASK _ULL(0xc000)
+#define KVX_SFR_SPS_PL1_VS_WFXL_CLEAR _ULL(0xc000)
+#define KVX_SFR_SPS_PL1_VS_WFXL_SET _ULL(0xc00000000000)
+
+#define KVX_SFR_SPS_PL1_V64_MASK _ULL(0x10000) /* Virtual 64 bits mode. */
+#define KVX_SFR_SPS_PL1_V64_SHIFT 16
+#define KVX_SFR_SPS_PL1_V64_WIDTH 1
+#define KVX_SFR_SPS_PL1_V64_WFXL_MASK _ULL(0x10000)
+#define KVX_SFR_SPS_PL1_V64_WFXL_CLEAR _ULL(0x10000)
+#define KVX_SFR_SPS_PL1_V64_WFXL_SET _ULL(0x1000000000000)
+
+#define KVX_SFR_SPS_PL1_L2E_MASK _ULL(0x20000) /* L2 cache Enable. */
+#define KVX_SFR_SPS_PL1_L2E_SHIFT 17
+#define KVX_SFR_SPS_PL1_L2E_WIDTH 1
+#define KVX_SFR_SPS_PL1_L2E_WFXL_MASK _ULL(0x20000)
+#define KVX_SFR_SPS_PL1_L2E_WFXL_CLEAR _ULL(0x20000)
+#define KVX_SFR_SPS_PL1_L2E_WFXL_SET _ULL(0x2000000000000)
+
+#define KVX_SFR_SPS_PL1_SME_MASK _ULL(0x40000) /* Step Mode Enabled */
+#define KVX_SFR_SPS_PL1_SME_SHIFT 18
+#define KVX_SFR_SPS_PL1_SME_WIDTH 1
+#define KVX_SFR_SPS_PL1_SME_WFXL_MASK _ULL(0x40000)
+#define KVX_SFR_SPS_PL1_SME_WFXL_CLEAR _ULL(0x40000)
+#define KVX_SFR_SPS_PL1_SME_WFXL_SET _ULL(0x4000000000000)
+
+#define KVX_SFR_SPS_PL1_SMR_MASK _ULL(0x80000) /* Step Mode Ready */
+#define KVX_SFR_SPS_PL1_SMR_SHIFT 19
+#define KVX_SFR_SPS_PL1_SMR_WIDTH 1
+#define KVX_SFR_SPS_PL1_SMR_WFXL_MASK _ULL(0x80000)
+#define KVX_SFR_SPS_PL1_SMR_WFXL_CLEAR _ULL(0x80000)
+#define KVX_SFR_SPS_PL1_SMR_WFXL_SET _ULL(0x8000000000000)
+
+#define KVX_SFR_SPS_PL1_PMJ_MASK _ULL(0xf00000) /* Page Mask in JTLB. */
+#define KVX_SFR_SPS_PL1_PMJ_SHIFT 20
+#define KVX_SFR_SPS_PL1_PMJ_WIDTH 4
+#define KVX_SFR_SPS_PL1_PMJ_WFXL_MASK _ULL(0xf00000)
+#define KVX_SFR_SPS_PL1_PMJ_WFXL_CLEAR _ULL(0xf00000)
+#define KVX_SFR_SPS_PL1_PMJ_WFXL_SET _ULL(0xf0000000000000)
+
+#define KVX_SFR_SPS_PL1_MMUP_MASK _ULL(0x1000000) /* Privileged on MMU. */
+#define KVX_SFR_SPS_PL1_MMUP_SHIFT 24
+#define KVX_SFR_SPS_PL1_MMUP_WIDTH 1
+#define KVX_SFR_SPS_PL1_MMUP_WFXL_MASK _ULL(0x1000000)
+#define KVX_SFR_SPS_PL1_MMUP_WFXL_CLEAR _ULL(0x1000000)
+#define KVX_SFR_SPS_PL1_MMUP_WFXL_SET _ULL(0x100000000000000)
+
+#define KVX_SFR_SPS_PL2_PL_MASK _ULL(0x3) /* Current Privilege Level */
+#define KVX_SFR_SPS_PL2_PL_SHIFT 0
+#define KVX_SFR_SPS_PL2_PL_WIDTH 2
+#define KVX_SFR_SPS_PL2_PL_WFXL_MASK _ULL(0x3)
+#define KVX_SFR_SPS_PL2_PL_WFXL_CLEAR _ULL(0x3)
+#define KVX_SFR_SPS_PL2_PL_WFXL_SET _ULL(0x300000000)
+
+#define KVX_SFR_SPS_PL2_ET_MASK _ULL(0x4) /* Exception Taken */
+#define KVX_SFR_SPS_PL2_ET_SHIFT 2
+#define KVX_SFR_SPS_PL2_ET_WIDTH 1
+#define KVX_SFR_SPS_PL2_ET_WFXL_MASK _ULL(0x4)
+#define KVX_SFR_SPS_PL2_ET_WFXL_CLEAR _ULL(0x4)
+#define KVX_SFR_SPS_PL2_ET_WFXL_SET _ULL(0x400000000)
+
+#define KVX_SFR_SPS_PL2_HTD_MASK _ULL(0x8) /* Hardware Trap Disable */
+#define KVX_SFR_SPS_PL2_HTD_SHIFT 3
+#define KVX_SFR_SPS_PL2_HTD_WIDTH 1
+#define KVX_SFR_SPS_PL2_HTD_WFXL_MASK _ULL(0x8)
+#define KVX_SFR_SPS_PL2_HTD_WFXL_CLEAR _ULL(0x8)
+#define KVX_SFR_SPS_PL2_HTD_WFXL_SET _ULL(0x800000000)
+
+#define KVX_SFR_SPS_PL2_IE_MASK _ULL(0x10) /* Interrupt Enable */
+#define KVX_SFR_SPS_PL2_IE_SHIFT 4
+#define KVX_SFR_SPS_PL2_IE_WIDTH 1
+#define KVX_SFR_SPS_PL2_IE_WFXL_MASK _ULL(0x10)
+#define KVX_SFR_SPS_PL2_IE_WFXL_CLEAR _ULL(0x10)
+#define KVX_SFR_SPS_PL2_IE_WFXL_SET _ULL(0x1000000000)
+
+#define KVX_SFR_SPS_PL2_HLE_MASK _ULL(0x20) /* Hardware Loop Enable */
+#define KVX_SFR_SPS_PL2_HLE_SHIFT 5
+#define KVX_SFR_SPS_PL2_HLE_WIDTH 1
+#define KVX_SFR_SPS_PL2_HLE_WFXL_MASK _ULL(0x20)
+#define KVX_SFR_SPS_PL2_HLE_WFXL_CLEAR _ULL(0x20)
+#define KVX_SFR_SPS_PL2_HLE_WFXL_SET _ULL(0x2000000000)
+
+#define KVX_SFR_SPS_PL2_SRE_MASK _ULL(0x40) /* Software REserved */
+#define KVX_SFR_SPS_PL2_SRE_SHIFT 6
+#define KVX_SFR_SPS_PL2_SRE_WIDTH 1
+#define KVX_SFR_SPS_PL2_SRE_WFXL_MASK _ULL(0x40)
+#define KVX_SFR_SPS_PL2_SRE_WFXL_CLEAR _ULL(0x40)
+#define KVX_SFR_SPS_PL2_SRE_WFXL_SET _ULL(0x4000000000)
+
+#define KVX_SFR_SPS_PL2_DAUS_MASK _ULL(0x80) /* Data Accesses Use SPS settings */
+#define KVX_SFR_SPS_PL2_DAUS_SHIFT 7
+#define KVX_SFR_SPS_PL2_DAUS_WIDTH 1
+#define KVX_SFR_SPS_PL2_DAUS_WFXL_MASK _ULL(0x80)
+#define KVX_SFR_SPS_PL2_DAUS_WFXL_CLEAR _ULL(0x80)
+#define KVX_SFR_SPS_PL2_DAUS_WFXL_SET _ULL(0x8000000000)
+
+#define KVX_SFR_SPS_PL2_ICE_MASK _ULL(0x100) /* Instruction Cache Enable */
+#define KVX_SFR_SPS_PL2_ICE_SHIFT 8
+#define KVX_SFR_SPS_PL2_ICE_WIDTH 1
+#define KVX_SFR_SPS_PL2_ICE_WFXL_MASK _ULL(0x100)
+#define KVX_SFR_SPS_PL2_ICE_WFXL_CLEAR _ULL(0x100)
+#define KVX_SFR_SPS_PL2_ICE_WFXL_SET _ULL(0x10000000000)
+
+#define KVX_SFR_SPS_PL2_USE_MASK _ULL(0x200) /* Uncached Streaming Enable */
+#define KVX_SFR_SPS_PL2_USE_SHIFT 9
+#define KVX_SFR_SPS_PL2_USE_WIDTH 1
+#define KVX_SFR_SPS_PL2_USE_WFXL_MASK _ULL(0x200)
+#define KVX_SFR_SPS_PL2_USE_WFXL_CLEAR _ULL(0x200)
+#define KVX_SFR_SPS_PL2_USE_WFXL_SET _ULL(0x20000000000)
+
+#define KVX_SFR_SPS_PL2_DCE_MASK _ULL(0x400) /* Data Cache Enable */
+#define KVX_SFR_SPS_PL2_DCE_SHIFT 10
+#define KVX_SFR_SPS_PL2_DCE_WIDTH 1
+#define KVX_SFR_SPS_PL2_DCE_WFXL_MASK _ULL(0x400)
+#define KVX_SFR_SPS_PL2_DCE_WFXL_CLEAR _ULL(0x400)
+#define KVX_SFR_SPS_PL2_DCE_WFXL_SET _ULL(0x40000000000)
+
+#define KVX_SFR_SPS_PL2_MME_MASK _ULL(0x800) /* Memory Management Enable */
+#define KVX_SFR_SPS_PL2_MME_SHIFT 11
+#define KVX_SFR_SPS_PL2_MME_WIDTH 1
+#define KVX_SFR_SPS_PL2_MME_WFXL_MASK _ULL(0x800)
+#define KVX_SFR_SPS_PL2_MME_WFXL_CLEAR _ULL(0x800)
+#define KVX_SFR_SPS_PL2_MME_WFXL_SET _ULL(0x80000000000)
+
+#define KVX_SFR_SPS_PL2_IL_MASK _ULL(0x3000) /* Interrupt Level */
+#define KVX_SFR_SPS_PL2_IL_SHIFT 12
+#define KVX_SFR_SPS_PL2_IL_WIDTH 2
+#define KVX_SFR_SPS_PL2_IL_WFXL_MASK _ULL(0x3000)
+#define KVX_SFR_SPS_PL2_IL_WFXL_CLEAR _ULL(0x3000)
+#define KVX_SFR_SPS_PL2_IL_WFXL_SET _ULL(0x300000000000)
+
+#define KVX_SFR_SPS_PL2_VS_MASK _ULL(0xc000) /* Virtual Space */
+#define KVX_SFR_SPS_PL2_VS_SHIFT 14
+#define KVX_SFR_SPS_PL2_VS_WIDTH 2
+#define KVX_SFR_SPS_PL2_VS_WFXL_MASK _ULL(0xc000)
+#define KVX_SFR_SPS_PL2_VS_WFXL_CLEAR _ULL(0xc000)
+#define KVX_SFR_SPS_PL2_VS_WFXL_SET _ULL(0xc00000000000)
+
+#define KVX_SFR_SPS_PL2_V64_MASK _ULL(0x10000) /* Virtual 64 bits mode. */
+#define KVX_SFR_SPS_PL2_V64_SHIFT 16
+#define KVX_SFR_SPS_PL2_V64_WIDTH 1
+#define KVX_SFR_SPS_PL2_V64_WFXL_MASK _ULL(0x10000)
+#define KVX_SFR_SPS_PL2_V64_WFXL_CLEAR _ULL(0x10000)
+#define KVX_SFR_SPS_PL2_V64_WFXL_SET _ULL(0x1000000000000)
+
+#define KVX_SFR_SPS_PL2_L2E_MASK _ULL(0x20000) /* L2 cache Enable. */
+#define KVX_SFR_SPS_PL2_L2E_SHIFT 17
+#define KVX_SFR_SPS_PL2_L2E_WIDTH 1
+#define KVX_SFR_SPS_PL2_L2E_WFXL_MASK _ULL(0x20000)
+#define KVX_SFR_SPS_PL2_L2E_WFXL_CLEAR _ULL(0x20000)
+#define KVX_SFR_SPS_PL2_L2E_WFXL_SET _ULL(0x2000000000000)
+
+#define KVX_SFR_SPS_PL2_SME_MASK _ULL(0x40000) /* Step Mode Enabled */
+#define KVX_SFR_SPS_PL2_SME_SHIFT 18
+#define KVX_SFR_SPS_PL2_SME_WIDTH 1
+#define KVX_SFR_SPS_PL2_SME_WFXL_MASK _ULL(0x40000)
+#define KVX_SFR_SPS_PL2_SME_WFXL_CLEAR _ULL(0x40000)
+#define KVX_SFR_SPS_PL2_SME_WFXL_SET _ULL(0x4000000000000)
+
+#define KVX_SFR_SPS_PL2_SMR_MASK _ULL(0x80000) /* Step Mode Ready */
+#define KVX_SFR_SPS_PL2_SMR_SHIFT 19
+#define KVX_SFR_SPS_PL2_SMR_WIDTH 1
+#define KVX_SFR_SPS_PL2_SMR_WFXL_MASK _ULL(0x80000)
+#define KVX_SFR_SPS_PL2_SMR_WFXL_CLEAR _ULL(0x80000)
+#define KVX_SFR_SPS_PL2_SMR_WFXL_SET _ULL(0x8000000000000)
+
+#define KVX_SFR_SPS_PL2_PMJ_MASK _ULL(0xf00000) /* Page Mask in JTLB. */
+#define KVX_SFR_SPS_PL2_PMJ_SHIFT 20
+#define KVX_SFR_SPS_PL2_PMJ_WIDTH 4
+#define KVX_SFR_SPS_PL2_PMJ_WFXL_MASK _ULL(0xf00000)
+#define KVX_SFR_SPS_PL2_PMJ_WFXL_CLEAR _ULL(0xf00000)
+#define KVX_SFR_SPS_PL2_PMJ_WFXL_SET _ULL(0xf0000000000000)
+
+#define KVX_SFR_SPS_PL2_MMUP_MASK _ULL(0x1000000) /* Privileged on MMU. */
+#define KVX_SFR_SPS_PL2_MMUP_SHIFT 24
+#define KVX_SFR_SPS_PL2_MMUP_WIDTH 1
+#define KVX_SFR_SPS_PL2_MMUP_WFXL_MASK _ULL(0x1000000)
+#define KVX_SFR_SPS_PL2_MMUP_WFXL_CLEAR _ULL(0x1000000)
+#define KVX_SFR_SPS_PL2_MMUP_WFXL_SET _ULL(0x100000000000000)
+
+#define KVX_SFR_SPS_PL3_PL_MASK _ULL(0x3) /* Current Privilege Level */
+#define KVX_SFR_SPS_PL3_PL_SHIFT 0
+#define KVX_SFR_SPS_PL3_PL_WIDTH 2
+#define KVX_SFR_SPS_PL3_PL_WFXL_MASK _ULL(0x3)
+#define KVX_SFR_SPS_PL3_PL_WFXL_CLEAR _ULL(0x3)
+#define KVX_SFR_SPS_PL3_PL_WFXL_SET _ULL(0x300000000)
+
+#define KVX_SFR_SPS_PL3_ET_MASK _ULL(0x4) /* Exception Taken */
+#define KVX_SFR_SPS_PL3_ET_SHIFT 2
+#define KVX_SFR_SPS_PL3_ET_WIDTH 1
+#define KVX_SFR_SPS_PL3_ET_WFXL_MASK _ULL(0x4)
+#define KVX_SFR_SPS_PL3_ET_WFXL_CLEAR _ULL(0x4)
+#define KVX_SFR_SPS_PL3_ET_WFXL_SET _ULL(0x400000000)
+
+#define KVX_SFR_SPS_PL3_HTD_MASK _ULL(0x8) /* Hardware Trap Disable */
+#define KVX_SFR_SPS_PL3_HTD_SHIFT 3
+#define KVX_SFR_SPS_PL3_HTD_WIDTH 1
+#define KVX_SFR_SPS_PL3_HTD_WFXL_MASK _ULL(0x8)
+#define KVX_SFR_SPS_PL3_HTD_WFXL_CLEAR _ULL(0x8)
+#define KVX_SFR_SPS_PL3_HTD_WFXL_SET _ULL(0x800000000)
+
+#define KVX_SFR_SPS_PL3_IE_MASK _ULL(0x10) /* Interrupt Enable */
+#define KVX_SFR_SPS_PL3_IE_SHIFT 4
+#define KVX_SFR_SPS_PL3_IE_WIDTH 1
+#define KVX_SFR_SPS_PL3_IE_WFXL_MASK _ULL(0x10)
+#define KVX_SFR_SPS_PL3_IE_WFXL_CLEAR _ULL(0x10)
+#define KVX_SFR_SPS_PL3_IE_WFXL_SET _ULL(0x1000000000)
+
+#define KVX_SFR_SPS_PL3_HLE_MASK _ULL(0x20) /* Hardware Loop Enable */
+#define KVX_SFR_SPS_PL3_HLE_SHIFT 5
+#define KVX_SFR_SPS_PL3_HLE_WIDTH 1
+#define KVX_SFR_SPS_PL3_HLE_WFXL_MASK _ULL(0x20)
+#define KVX_SFR_SPS_PL3_HLE_WFXL_CLEAR _ULL(0x20)
+#define KVX_SFR_SPS_PL3_HLE_WFXL_SET _ULL(0x2000000000)
+
+#define KVX_SFR_SPS_PL3_SRE_MASK _ULL(0x40) /* Software REserved */
+#define KVX_SFR_SPS_PL3_SRE_SHIFT 6
+#define KVX_SFR_SPS_PL3_SRE_WIDTH 1
+#define KVX_SFR_SPS_PL3_SRE_WFXL_MASK _ULL(0x40)
+#define KVX_SFR_SPS_PL3_SRE_WFXL_CLEAR _ULL(0x40)
+#define KVX_SFR_SPS_PL3_SRE_WFXL_SET _ULL(0x4000000000)
+
+#define KVX_SFR_SPS_PL3_DAUS_MASK _ULL(0x80) /* Data Accesses Use SPS settings */
+#define KVX_SFR_SPS_PL3_DAUS_SHIFT 7
+#define KVX_SFR_SPS_PL3_DAUS_WIDTH 1
+#define KVX_SFR_SPS_PL3_DAUS_WFXL_MASK _ULL(0x80)
+#define KVX_SFR_SPS_PL3_DAUS_WFXL_CLEAR _ULL(0x80)
+#define KVX_SFR_SPS_PL3_DAUS_WFXL_SET _ULL(0x8000000000)
+
+#define KVX_SFR_SPS_PL3_ICE_MASK _ULL(0x100) /* Instruction Cache Enable */
+#define KVX_SFR_SPS_PL3_ICE_SHIFT 8
+#define KVX_SFR_SPS_PL3_ICE_WIDTH 1
+#define KVX_SFR_SPS_PL3_ICE_WFXL_MASK _ULL(0x100)
+#define KVX_SFR_SPS_PL3_ICE_WFXL_CLEAR _ULL(0x100)
+#define KVX_SFR_SPS_PL3_ICE_WFXL_SET _ULL(0x10000000000)
+
+#define KVX_SFR_SPS_PL3_USE_MASK _ULL(0x200) /* Uncached Streaming Enable */
+#define KVX_SFR_SPS_PL3_USE_SHIFT 9
+#define KVX_SFR_SPS_PL3_USE_WIDTH 1
+#define KVX_SFR_SPS_PL3_USE_WFXL_MASK _ULL(0x200)
+#define KVX_SFR_SPS_PL3_USE_WFXL_CLEAR _ULL(0x200)
+#define KVX_SFR_SPS_PL3_USE_WFXL_SET _ULL(0x20000000000)
+
+#define KVX_SFR_SPS_PL3_DCE_MASK _ULL(0x400) /* Data Cache Enable */
+#define KVX_SFR_SPS_PL3_DCE_SHIFT 10
+#define KVX_SFR_SPS_PL3_DCE_WIDTH 1
+#define KVX_SFR_SPS_PL3_DCE_WFXL_MASK _ULL(0x400)
+#define KVX_SFR_SPS_PL3_DCE_WFXL_CLEAR _ULL(0x400)
+#define KVX_SFR_SPS_PL3_DCE_WFXL_SET _ULL(0x40000000000)
+
+#define KVX_SFR_SPS_PL3_MME_MASK _ULL(0x800) /* Memory Management Enable */
+#define KVX_SFR_SPS_PL3_MME_SHIFT 11
+#define KVX_SFR_SPS_PL3_MME_WIDTH 1
+#define KVX_SFR_SPS_PL3_MME_WFXL_MASK _ULL(0x800)
+#define KVX_SFR_SPS_PL3_MME_WFXL_CLEAR _ULL(0x800)
+#define KVX_SFR_SPS_PL3_MME_WFXL_SET _ULL(0x80000000000)
+
+#define KVX_SFR_SPS_PL3_IL_MASK _ULL(0x3000) /* Interrupt Level */
+#define KVX_SFR_SPS_PL3_IL_SHIFT 12
+#define KVX_SFR_SPS_PL3_IL_WIDTH 2
+#define KVX_SFR_SPS_PL3_IL_WFXL_MASK _ULL(0x3000)
+#define KVX_SFR_SPS_PL3_IL_WFXL_CLEAR _ULL(0x3000)
+#define KVX_SFR_SPS_PL3_IL_WFXL_SET _ULL(0x300000000000)
+
+#define KVX_SFR_SPS_PL3_VS_MASK _ULL(0xc000) /* Virtual Space */
+#define KVX_SFR_SPS_PL3_VS_SHIFT 14
+#define KVX_SFR_SPS_PL3_VS_WIDTH 2
+#define KVX_SFR_SPS_PL3_VS_WFXL_MASK _ULL(0xc000)
+#define KVX_SFR_SPS_PL3_VS_WFXL_CLEAR _ULL(0xc000)
+#define KVX_SFR_SPS_PL3_VS_WFXL_SET _ULL(0xc00000000000)
+
+#define KVX_SFR_SPS_PL3_V64_MASK _ULL(0x10000) /* Virtual 64 bits mode. */
+#define KVX_SFR_SPS_PL3_V64_SHIFT 16
+#define KVX_SFR_SPS_PL3_V64_WIDTH 1
+#define KVX_SFR_SPS_PL3_V64_WFXL_MASK _ULL(0x10000)
+#define KVX_SFR_SPS_PL3_V64_WFXL_CLEAR _ULL(0x10000)
+#define KVX_SFR_SPS_PL3_V64_WFXL_SET _ULL(0x1000000000000)
+
+#define KVX_SFR_SPS_PL3_L2E_MASK _ULL(0x20000) /* L2 cache Enable. */
+#define KVX_SFR_SPS_PL3_L2E_SHIFT 17
+#define KVX_SFR_SPS_PL3_L2E_WIDTH 1
+#define KVX_SFR_SPS_PL3_L2E_WFXL_MASK _ULL(0x20000)
+#define KVX_SFR_SPS_PL3_L2E_WFXL_CLEAR _ULL(0x20000)
+#define KVX_SFR_SPS_PL3_L2E_WFXL_SET _ULL(0x2000000000000)
+
+#define KVX_SFR_SPS_PL3_SME_MASK _ULL(0x40000) /* Step Mode Enabled */
+#define KVX_SFR_SPS_PL3_SME_SHIFT 18
+#define KVX_SFR_SPS_PL3_SME_WIDTH 1
+#define KVX_SFR_SPS_PL3_SME_WFXL_MASK _ULL(0x40000)
+#define KVX_SFR_SPS_PL3_SME_WFXL_CLEAR _ULL(0x40000)
+#define KVX_SFR_SPS_PL3_SME_WFXL_SET _ULL(0x4000000000000)
+
+#define KVX_SFR_SPS_PL3_SMR_MASK _ULL(0x80000) /* Step Mode Ready */
+#define KVX_SFR_SPS_PL3_SMR_SHIFT 19
+#define KVX_SFR_SPS_PL3_SMR_WIDTH 1
+#define KVX_SFR_SPS_PL3_SMR_WFXL_MASK _ULL(0x80000)
+#define KVX_SFR_SPS_PL3_SMR_WFXL_CLEAR _ULL(0x80000)
+#define KVX_SFR_SPS_PL3_SMR_WFXL_SET _ULL(0x8000000000000)
+
+#define KVX_SFR_SPS_PL3_PMJ_MASK _ULL(0xf00000) /* Page Mask in JTLB. */
+#define KVX_SFR_SPS_PL3_PMJ_SHIFT 20
+#define KVX_SFR_SPS_PL3_PMJ_WIDTH 4
+#define KVX_SFR_SPS_PL3_PMJ_WFXL_MASK _ULL(0xf00000)
+#define KVX_SFR_SPS_PL3_PMJ_WFXL_CLEAR _ULL(0xf00000)
+#define KVX_SFR_SPS_PL3_PMJ_WFXL_SET _ULL(0xf0000000000000)
+
+#define KVX_SFR_SPS_PL3_MMUP_MASK _ULL(0x1000000) /* Privileged on MMU. */
+#define KVX_SFR_SPS_PL3_MMUP_SHIFT 24
+#define KVX_SFR_SPS_PL3_MMUP_WIDTH 1
+#define KVX_SFR_SPS_PL3_MMUP_WFXL_MASK _ULL(0x1000000)
+#define KVX_SFR_SPS_PL3_MMUP_WFXL_CLEAR _ULL(0x1000000)
+#define KVX_SFR_SPS_PL3_MMUP_WFXL_SET _ULL(0x100000000000000)
+
+#define KVX_SFR_PSO_PL0_MASK _ULL(0x3) /* Current Privilege Level bit 0 owner */
+#define KVX_SFR_PSO_PL0_SHIFT 0
+#define KVX_SFR_PSO_PL0_WIDTH 2
+#define KVX_SFR_PSO_PL0_WFXL_MASK _ULL(0x3)
+#define KVX_SFR_PSO_PL0_WFXL_CLEAR _ULL(0x3)
+#define KVX_SFR_PSO_PL0_WFXL_SET _ULL(0x300000000)
+
+#define KVX_SFR_PSO_PL1_MASK _ULL(0xc) /* Current Privilege Level bit 1 owner */
+#define KVX_SFR_PSO_PL1_SHIFT 2
+#define KVX_SFR_PSO_PL1_WIDTH 2
+#define KVX_SFR_PSO_PL1_WFXL_MASK _ULL(0xc)
+#define KVX_SFR_PSO_PL1_WFXL_CLEAR _ULL(0xc)
+#define KVX_SFR_PSO_PL1_WFXL_SET _ULL(0xc00000000)
+
+#define KVX_SFR_PSO_ET_MASK _ULL(0x30) /* Exception Taken owner */
+#define KVX_SFR_PSO_ET_SHIFT 4
+#define KVX_SFR_PSO_ET_WIDTH 2
+#define KVX_SFR_PSO_ET_WFXL_MASK _ULL(0x30)
+#define KVX_SFR_PSO_ET_WFXL_CLEAR _ULL(0x30)
+#define KVX_SFR_PSO_ET_WFXL_SET _ULL(0x3000000000)
+
+#define KVX_SFR_PSO_HTD_MASK _ULL(0xc0) /* Hardware Trap Disable owner */
+#define KVX_SFR_PSO_HTD_SHIFT 6
+#define KVX_SFR_PSO_HTD_WIDTH 2
+#define KVX_SFR_PSO_HTD_WFXL_MASK _ULL(0xc0)
+#define KVX_SFR_PSO_HTD_WFXL_CLEAR _ULL(0xc0)
+#define KVX_SFR_PSO_HTD_WFXL_SET _ULL(0xc000000000)
+
+#define KVX_SFR_PSO_IE_MASK _ULL(0x300) /* Interrupt Enable owner */
+#define KVX_SFR_PSO_IE_SHIFT 8
+#define KVX_SFR_PSO_IE_WIDTH 2
+#define KVX_SFR_PSO_IE_WFXL_MASK _ULL(0x300)
+#define KVX_SFR_PSO_IE_WFXL_CLEAR _ULL(0x300)
+#define KVX_SFR_PSO_IE_WFXL_SET _ULL(0x30000000000)
+
+#define KVX_SFR_PSO_HLE_MASK _ULL(0xc00) /* Hardware Loop Enable owner */
+#define KVX_SFR_PSO_HLE_SHIFT 10
+#define KVX_SFR_PSO_HLE_WIDTH 2
+#define KVX_SFR_PSO_HLE_WFXL_MASK _ULL(0xc00)
+#define KVX_SFR_PSO_HLE_WFXL_CLEAR _ULL(0xc00)
+#define KVX_SFR_PSO_HLE_WFXL_SET _ULL(0xc0000000000)
+
+#define KVX_SFR_PSO_SRE_MASK _ULL(0x3000) /* Software REserved owner */
+#define KVX_SFR_PSO_SRE_SHIFT 12
+#define KVX_SFR_PSO_SRE_WIDTH 2
+#define KVX_SFR_PSO_SRE_WFXL_MASK _ULL(0x3000)
+#define KVX_SFR_PSO_SRE_WFXL_CLEAR _ULL(0x3000)
+#define KVX_SFR_PSO_SRE_WFXL_SET _ULL(0x300000000000)
+
+#define KVX_SFR_PSO_DAUS_MASK _ULL(0xc000) /* Data Accesses Use SPS settings owner */
+#define KVX_SFR_PSO_DAUS_SHIFT 14
+#define KVX_SFR_PSO_DAUS_WIDTH 2
+#define KVX_SFR_PSO_DAUS_WFXL_MASK _ULL(0xc000)
+#define KVX_SFR_PSO_DAUS_WFXL_CLEAR _ULL(0xc000)
+#define KVX_SFR_PSO_DAUS_WFXL_SET _ULL(0xc00000000000)
+
+#define KVX_SFR_PSO_ICE_MASK _ULL(0x30000) /* Instruction Cache Enable owner */
+#define KVX_SFR_PSO_ICE_SHIFT 16
+#define KVX_SFR_PSO_ICE_WIDTH 2
+#define KVX_SFR_PSO_ICE_WFXL_MASK _ULL(0x30000)
+#define KVX_SFR_PSO_ICE_WFXL_CLEAR _ULL(0x30000)
+#define KVX_SFR_PSO_ICE_WFXL_SET _ULL(0x3000000000000)
+
+#define KVX_SFR_PSO_USE_MASK _ULL(0xc0000) /* Uncached Streaming Enable owner */
+#define KVX_SFR_PSO_USE_SHIFT 18
+#define KVX_SFR_PSO_USE_WIDTH 2
+#define KVX_SFR_PSO_USE_WFXL_MASK _ULL(0xc0000)
+#define KVX_SFR_PSO_USE_WFXL_CLEAR _ULL(0xc0000)
+#define KVX_SFR_PSO_USE_WFXL_SET _ULL(0xc000000000000)
+
+#define KVX_SFR_PSO_DCE_MASK _ULL(0x300000) /* Data Cache Enable owner */
+#define KVX_SFR_PSO_DCE_SHIFT 20
+#define KVX_SFR_PSO_DCE_WIDTH 2
+#define KVX_SFR_PSO_DCE_WFXL_MASK _ULL(0x300000)
+#define KVX_SFR_PSO_DCE_WFXL_CLEAR _ULL(0x300000)
+#define KVX_SFR_PSO_DCE_WFXL_SET _ULL(0x30000000000000)
+
+#define KVX_SFR_PSO_MME_MASK _ULL(0xc00000) /* Memory Management Enable owner */
+#define KVX_SFR_PSO_MME_SHIFT 22
+#define KVX_SFR_PSO_MME_WIDTH 2
+#define KVX_SFR_PSO_MME_WFXL_MASK _ULL(0xc00000)
+#define KVX_SFR_PSO_MME_WFXL_CLEAR _ULL(0xc00000)
+#define KVX_SFR_PSO_MME_WFXL_SET _ULL(0xc0000000000000)
+
+#define KVX_SFR_PSO_IL0_MASK _ULL(0x3000000) /* Interrupt Level bit 0 owner */
+#define KVX_SFR_PSO_IL0_SHIFT 24
+#define KVX_SFR_PSO_IL0_WIDTH 2
+#define KVX_SFR_PSO_IL0_WFXL_MASK _ULL(0x3000000)
+#define KVX_SFR_PSO_IL0_WFXL_CLEAR _ULL(0x3000000)
+#define KVX_SFR_PSO_IL0_WFXL_SET _ULL(0x300000000000000)
+
+#define KVX_SFR_PSO_IL1_MASK _ULL(0xc000000) /* Interrupt Level bit 1 owner */
+#define KVX_SFR_PSO_IL1_SHIFT 26
+#define KVX_SFR_PSO_IL1_WIDTH 2
+#define KVX_SFR_PSO_IL1_WFXL_MASK _ULL(0xc000000)
+#define KVX_SFR_PSO_IL1_WFXL_CLEAR _ULL(0xc000000)
+#define KVX_SFR_PSO_IL1_WFXL_SET _ULL(0xc00000000000000)
+
+#define KVX_SFR_PSO_VS0_MASK _ULL(0x30000000) /* Virtual Space bit 0 owner */
+#define KVX_SFR_PSO_VS0_SHIFT 28
+#define KVX_SFR_PSO_VS0_WIDTH 2
+#define KVX_SFR_PSO_VS0_WFXL_MASK _ULL(0x30000000)
+#define KVX_SFR_PSO_VS0_WFXL_CLEAR _ULL(0x30000000)
+#define KVX_SFR_PSO_VS0_WFXL_SET _ULL(0x3000000000000000)
+
+#define KVX_SFR_PSO_VS1_MASK _ULL(0xc0000000) /* Virtual Space bit 1 owner */
+#define KVX_SFR_PSO_VS1_SHIFT 30
+#define KVX_SFR_PSO_VS1_WIDTH 2
+#define KVX_SFR_PSO_VS1_WFXL_MASK _ULL(0xc0000000)
+#define KVX_SFR_PSO_VS1_WFXL_CLEAR _ULL(0xc0000000)
+#define KVX_SFR_PSO_VS1_WFXL_SET _ULL(0xc000000000000000)
+
+#define KVX_SFR_PSO_V64_MASK _ULL(0x300000000) /* Virtual 64 bits mode owner */
+#define KVX_SFR_PSO_V64_SHIFT 32
+#define KVX_SFR_PSO_V64_WIDTH 2
+#define KVX_SFR_PSO_V64_WFXM_MASK _ULL(0x300000000)
+#define KVX_SFR_PSO_V64_WFXM_CLEAR _ULL(0x3)
+#define KVX_SFR_PSO_V64_WFXM_SET _ULL(0x300000000)
+
+#define KVX_SFR_PSO_L2E_MASK _ULL(0xc00000000) /* L2 cache Enable owner */
+#define KVX_SFR_PSO_L2E_SHIFT 34
+#define KVX_SFR_PSO_L2E_WIDTH 2
+#define KVX_SFR_PSO_L2E_WFXM_MASK _ULL(0xc00000000)
+#define KVX_SFR_PSO_L2E_WFXM_CLEAR _ULL(0xc)
+#define KVX_SFR_PSO_L2E_WFXM_SET _ULL(0xc00000000)
+
+#define KVX_SFR_PSO_SME_MASK _ULL(0x3000000000) /* Step Mode Enabled owner */
+#define KVX_SFR_PSO_SME_SHIFT 36
+#define KVX_SFR_PSO_SME_WIDTH 2
+#define KVX_SFR_PSO_SME_WFXM_MASK _ULL(0x3000000000)
+#define KVX_SFR_PSO_SME_WFXM_CLEAR _ULL(0x30)
+#define KVX_SFR_PSO_SME_WFXM_SET _ULL(0x3000000000)
+
+#define KVX_SFR_PSO_SMR_MASK _ULL(0xc000000000) /* Step Mode Ready owner */
+#define KVX_SFR_PSO_SMR_SHIFT 38
+#define KVX_SFR_PSO_SMR_WIDTH 2
+#define KVX_SFR_PSO_SMR_WFXM_MASK _ULL(0xc000000000)
+#define KVX_SFR_PSO_SMR_WFXM_CLEAR _ULL(0xc0)
+#define KVX_SFR_PSO_SMR_WFXM_SET _ULL(0xc000000000)
+
+#define KVX_SFR_PSO_PMJ0_MASK _ULL(0x30000000000) /* Page Mask in JTLB bit 0 owner */
+#define KVX_SFR_PSO_PMJ0_SHIFT 40
+#define KVX_SFR_PSO_PMJ0_WIDTH 2
+#define KVX_SFR_PSO_PMJ0_WFXM_MASK _ULL(0x30000000000)
+#define KVX_SFR_PSO_PMJ0_WFXM_CLEAR _ULL(0x300)
+#define KVX_SFR_PSO_PMJ0_WFXM_SET _ULL(0x30000000000)
+
+#define KVX_SFR_PSO_PMJ1_MASK _ULL(0xc0000000000) /* Page Mask in JTLB bit 1 owner */
+#define KVX_SFR_PSO_PMJ1_SHIFT 42
+#define KVX_SFR_PSO_PMJ1_WIDTH 2
+#define KVX_SFR_PSO_PMJ1_WFXM_MASK _ULL(0xc0000000000)
+#define KVX_SFR_PSO_PMJ1_WFXM_CLEAR _ULL(0xc00)
+#define KVX_SFR_PSO_PMJ1_WFXM_SET _ULL(0xc0000000000)
+
+#define KVX_SFR_PSO_PMJ2_MASK _ULL(0x300000000000) /* Page Mask in JTLB bit 2 owner */
+#define KVX_SFR_PSO_PMJ2_SHIFT 44
+#define KVX_SFR_PSO_PMJ2_WIDTH 2
+#define KVX_SFR_PSO_PMJ2_WFXM_MASK _ULL(0x300000000000)
+#define KVX_SFR_PSO_PMJ2_WFXM_CLEAR _ULL(0x3000)
+#define KVX_SFR_PSO_PMJ2_WFXM_SET _ULL(0x300000000000)
+
+#define KVX_SFR_PSO_PMJ3_MASK _ULL(0xc00000000000) /* Page Mask in JTLB bit 3 owner */
+#define KVX_SFR_PSO_PMJ3_SHIFT 46
+#define KVX_SFR_PSO_PMJ3_WIDTH 2
+#define KVX_SFR_PSO_PMJ3_WFXM_MASK _ULL(0xc00000000000)
+#define KVX_SFR_PSO_PMJ3_WFXM_CLEAR _ULL(0xc000)
+#define KVX_SFR_PSO_PMJ3_WFXM_SET _ULL(0xc00000000000)
+
+#define KVX_SFR_PSO_MMUP_MASK _ULL(0x3000000000000) /* Privileged on MMU owner. */
+#define KVX_SFR_PSO_MMUP_SHIFT 48
+#define KVX_SFR_PSO_MMUP_WIDTH 2
+#define KVX_SFR_PSO_MMUP_WFXM_MASK _ULL(0x3000000000000)
+#define KVX_SFR_PSO_MMUP_WFXM_CLEAR _ULL(0x30000)
+#define KVX_SFR_PSO_MMUP_WFXM_SET _ULL(0x3000000000000)
+
+#define KVX_SFR_PSOW_PL0_MASK _ULL(0x3) /* Current Privilege Level bit 0 owner */
+#define KVX_SFR_PSOW_PL0_SHIFT 0
+#define KVX_SFR_PSOW_PL0_WIDTH 2
+#define KVX_SFR_PSOW_PL0_WFXL_MASK _ULL(0x3)
+#define KVX_SFR_PSOW_PL0_WFXL_CLEAR _ULL(0x3)
+#define KVX_SFR_PSOW_PL0_WFXL_SET _ULL(0x300000000)
+
+#define KVX_SFR_PSOW_PL1_MASK _ULL(0xc) /* Current Privilege Level bit 1 owner */
+#define KVX_SFR_PSOW_PL1_SHIFT 2
+#define KVX_SFR_PSOW_PL1_WIDTH 2
+#define KVX_SFR_PSOW_PL1_WFXL_MASK _ULL(0xc)
+#define KVX_SFR_PSOW_PL1_WFXL_CLEAR _ULL(0xc)
+#define KVX_SFR_PSOW_PL1_WFXL_SET _ULL(0xc00000000)
+
+#define KVX_SFR_PSOW_ET_MASK _ULL(0x30) /* Exception Taken owner */
+#define KVX_SFR_PSOW_ET_SHIFT 4
+#define KVX_SFR_PSOW_ET_WIDTH 2
+#define KVX_SFR_PSOW_ET_WFXL_MASK _ULL(0x30)
+#define KVX_SFR_PSOW_ET_WFXL_CLEAR _ULL(0x30)
+#define KVX_SFR_PSOW_ET_WFXL_SET _ULL(0x3000000000)
+
+#define KVX_SFR_PSOW_HTD_MASK _ULL(0xc0) /* Hardware Trap Disable owner */
+#define KVX_SFR_PSOW_HTD_SHIFT 6
+#define KVX_SFR_PSOW_HTD_WIDTH 2
+#define KVX_SFR_PSOW_HTD_WFXL_MASK _ULL(0xc0)
+#define KVX_SFR_PSOW_HTD_WFXL_CLEAR _ULL(0xc0)
+#define KVX_SFR_PSOW_HTD_WFXL_SET _ULL(0xc000000000)
+
+#define KVX_SFR_PSOW_IE_MASK _ULL(0x300) /* Interrupt Enable owner */
+#define KVX_SFR_PSOW_IE_SHIFT 8
+#define KVX_SFR_PSOW_IE_WIDTH 2
+#define KVX_SFR_PSOW_IE_WFXL_MASK _ULL(0x300)
+#define KVX_SFR_PSOW_IE_WFXL_CLEAR _ULL(0x300)
+#define KVX_SFR_PSOW_IE_WFXL_SET _ULL(0x30000000000)
+
+#define KVX_SFR_PSOW_HLE_MASK _ULL(0xc00) /* Hardware Loop Enable owner */
+#define KVX_SFR_PSOW_HLE_SHIFT 10
+#define KVX_SFR_PSOW_HLE_WIDTH 2
+#define KVX_SFR_PSOW_HLE_WFXL_MASK _ULL(0xc00)
+#define KVX_SFR_PSOW_HLE_WFXL_CLEAR _ULL(0xc00)
+#define KVX_SFR_PSOW_HLE_WFXL_SET _ULL(0xc0000000000)
+
+#define KVX_SFR_PSOW_SRE_MASK _ULL(0x3000) /* Software REserved owner */
+#define KVX_SFR_PSOW_SRE_SHIFT 12
+#define KVX_SFR_PSOW_SRE_WIDTH 2
+#define KVX_SFR_PSOW_SRE_WFXL_MASK _ULL(0x3000)
+#define KVX_SFR_PSOW_SRE_WFXL_CLEAR _ULL(0x3000)
+#define KVX_SFR_PSOW_SRE_WFXL_SET _ULL(0x300000000000)
+
+#define KVX_SFR_PSOW_DAUS_MASK _ULL(0xc000) /* Data Accesses Use SPS settings owner */
+#define KVX_SFR_PSOW_DAUS_SHIFT 14
+#define KVX_SFR_PSOW_DAUS_WIDTH 2
+#define KVX_SFR_PSOW_DAUS_WFXL_MASK _ULL(0xc000)
+#define KVX_SFR_PSOW_DAUS_WFXL_CLEAR _ULL(0xc000)
+#define KVX_SFR_PSOW_DAUS_WFXL_SET _ULL(0xc00000000000)
+
+#define KVX_SFR_PSOW_ICE_MASK _ULL(0x30000) /* Instruction Cache Enable owner */
+#define KVX_SFR_PSOW_ICE_SHIFT 16
+#define KVX_SFR_PSOW_ICE_WIDTH 2
+#define KVX_SFR_PSOW_ICE_WFXL_MASK _ULL(0x30000)
+#define KVX_SFR_PSOW_ICE_WFXL_CLEAR _ULL(0x30000)
+#define KVX_SFR_PSOW_ICE_WFXL_SET _ULL(0x3000000000000)
+
+#define KVX_SFR_PSOW_USE_MASK _ULL(0xc0000) /* Uncached Streaming Enable owner */
+#define KVX_SFR_PSOW_USE_SHIFT 18
+#define KVX_SFR_PSOW_USE_WIDTH 2
+#define KVX_SFR_PSOW_USE_WFXL_MASK _ULL(0xc0000)
+#define KVX_SFR_PSOW_USE_WFXL_CLEAR _ULL(0xc0000)
+#define KVX_SFR_PSOW_USE_WFXL_SET _ULL(0xc000000000000)
+
+#define KVX_SFR_PSOW_DCE_MASK _ULL(0x300000) /* Data Cache Enable owner */
+#define KVX_SFR_PSOW_DCE_SHIFT 20
+#define KVX_SFR_PSOW_DCE_WIDTH 2
+#define KVX_SFR_PSOW_DCE_WFXL_MASK _ULL(0x300000)
+#define KVX_SFR_PSOW_DCE_WFXL_CLEAR _ULL(0x300000)
+#define KVX_SFR_PSOW_DCE_WFXL_SET _ULL(0x30000000000000)
+
+#define KVX_SFR_PSOW_MME_MASK _ULL(0xc00000) /* Memory Management Enable owner */
+#define KVX_SFR_PSOW_MME_SHIFT 22
+#define KVX_SFR_PSOW_MME_WIDTH 2
+#define KVX_SFR_PSOW_MME_WFXL_MASK _ULL(0xc00000)
+#define KVX_SFR_PSOW_MME_WFXL_CLEAR _ULL(0xc00000)
+#define KVX_SFR_PSOW_MME_WFXL_SET _ULL(0xc0000000000000)
+
+#define KVX_SFR_PSOW_IL0_MASK _ULL(0x3000000) /* Interrupt Level bit 0 owner */
+#define KVX_SFR_PSOW_IL0_SHIFT 24
+#define KVX_SFR_PSOW_IL0_WIDTH 2
+#define KVX_SFR_PSOW_IL0_WFXL_MASK _ULL(0x3000000)
+#define KVX_SFR_PSOW_IL0_WFXL_CLEAR _ULL(0x3000000)
+#define KVX_SFR_PSOW_IL0_WFXL_SET _ULL(0x300000000000000)
+
+#define KVX_SFR_PSOW_IL1_MASK _ULL(0xc000000) /* Interrupt Level bit 1 owner */
+#define KVX_SFR_PSOW_IL1_SHIFT 26
+#define KVX_SFR_PSOW_IL1_WIDTH 2
+#define KVX_SFR_PSOW_IL1_WFXL_MASK _ULL(0xc000000)
+#define KVX_SFR_PSOW_IL1_WFXL_CLEAR _ULL(0xc000000)
+#define KVX_SFR_PSOW_IL1_WFXL_SET _ULL(0xc00000000000000)
+
+#define KVX_SFR_PSOW_VS0_MASK _ULL(0x30000000) /* Virtual Space bit 0 owner */
+#define KVX_SFR_PSOW_VS0_SHIFT 28
+#define KVX_SFR_PSOW_VS0_WIDTH 2
+#define KVX_SFR_PSOW_VS0_WFXL_MASK _ULL(0x30000000)
+#define KVX_SFR_PSOW_VS0_WFXL_CLEAR _ULL(0x30000000)
+#define KVX_SFR_PSOW_VS0_WFXL_SET _ULL(0x3000000000000000)
+
+#define KVX_SFR_PSOW_VS1_MASK _ULL(0xc0000000) /* Virtual Space bit 1 owner */
+#define KVX_SFR_PSOW_VS1_SHIFT 30
+#define KVX_SFR_PSOW_VS1_WIDTH 2
+#define KVX_SFR_PSOW_VS1_WFXL_MASK _ULL(0xc0000000)
+#define KVX_SFR_PSOW_VS1_WFXL_CLEAR _ULL(0xc0000000)
+#define KVX_SFR_PSOW_VS1_WFXL_SET _ULL(0xc000000000000000)
+
+#define KVX_SFR_PSOW_V64_MASK _ULL(0x300000000) /* Virtual 64 bits mode owner */
+#define KVX_SFR_PSOW_V64_SHIFT 32
+#define KVX_SFR_PSOW_V64_WIDTH 2
+#define KVX_SFR_PSOW_V64_WFXM_MASK _ULL(0x300000000)
+#define KVX_SFR_PSOW_V64_WFXM_CLEAR _ULL(0x3)
+#define KVX_SFR_PSOW_V64_WFXM_SET _ULL(0x300000000)
+
+#define KVX_SFR_PSOW_L2E_MASK _ULL(0xc00000000) /* L2 cache Enable owner */
+#define KVX_SFR_PSOW_L2E_SHIFT 34
+#define KVX_SFR_PSOW_L2E_WIDTH 2
+#define KVX_SFR_PSOW_L2E_WFXM_MASK _ULL(0xc00000000)
+#define KVX_SFR_PSOW_L2E_WFXM_CLEAR _ULL(0xc)
+#define KVX_SFR_PSOW_L2E_WFXM_SET _ULL(0xc00000000)
+
+#define KVX_SFR_PSOW_SME_MASK _ULL(0x3000000000) /* Step Mode Enabled owner */
+#define KVX_SFR_PSOW_SME_SHIFT 36
+#define KVX_SFR_PSOW_SME_WIDTH 2
+#define KVX_SFR_PSOW_SME_WFXM_MASK _ULL(0x3000000000)
+#define KVX_SFR_PSOW_SME_WFXM_CLEAR _ULL(0x30)
+#define KVX_SFR_PSOW_SME_WFXM_SET _ULL(0x3000000000)
+
+#define KVX_SFR_PSOW_SMR_MASK _ULL(0xc000000000) /* Step Mode Ready owner */
+#define KVX_SFR_PSOW_SMR_SHIFT 38
+#define KVX_SFR_PSOW_SMR_WIDTH 2
+#define KVX_SFR_PSOW_SMR_WFXM_MASK _ULL(0xc000000000)
+#define KVX_SFR_PSOW_SMR_WFXM_CLEAR _ULL(0xc0)
+#define KVX_SFR_PSOW_SMR_WFXM_SET _ULL(0xc000000000)
+
+#define KVX_SFR_PSOW_PMJ0_MASK _ULL(0x30000000000) /* Page Mask in JTLB bit 0 owner */
+#define KVX_SFR_PSOW_PMJ0_SHIFT 40
+#define KVX_SFR_PSOW_PMJ0_WIDTH 2
+#define KVX_SFR_PSOW_PMJ0_WFXM_MASK _ULL(0x30000000000)
+#define KVX_SFR_PSOW_PMJ0_WFXM_CLEAR _ULL(0x300)
+#define KVX_SFR_PSOW_PMJ0_WFXM_SET _ULL(0x30000000000)
+
+#define KVX_SFR_PSOW_PMJ1_MASK _ULL(0xc0000000000) /* Page Mask in JTLB bit 1 owner */
+#define KVX_SFR_PSOW_PMJ1_SHIFT 42
+#define KVX_SFR_PSOW_PMJ1_WIDTH 2
+#define KVX_SFR_PSOW_PMJ1_WFXM_MASK _ULL(0xc0000000000)
+#define KVX_SFR_PSOW_PMJ1_WFXM_CLEAR _ULL(0xc00)
+#define KVX_SFR_PSOW_PMJ1_WFXM_SET _ULL(0xc0000000000)
+
+#define KVX_SFR_PSOW_PMJ2_MASK _ULL(0x300000000000) /* Page Mask in JTLB bit 2 owner */
+#define KVX_SFR_PSOW_PMJ2_SHIFT 44
+#define KVX_SFR_PSOW_PMJ2_WIDTH 2
+#define KVX_SFR_PSOW_PMJ2_WFXM_MASK _ULL(0x300000000000)
+#define KVX_SFR_PSOW_PMJ2_WFXM_CLEAR _ULL(0x3000)
+#define KVX_SFR_PSOW_PMJ2_WFXM_SET _ULL(0x300000000000)
+
+#define KVX_SFR_PSOW_PMJ3_MASK _ULL(0xc00000000000) /* Page Mask in JTLB bit 3 owner */
+#define KVX_SFR_PSOW_PMJ3_SHIFT 46
+#define KVX_SFR_PSOW_PMJ3_WIDTH 2
+#define KVX_SFR_PSOW_PMJ3_WFXM_MASK _ULL(0xc00000000000)
+#define KVX_SFR_PSOW_PMJ3_WFXM_CLEAR _ULL(0xc000)
+#define KVX_SFR_PSOW_PMJ3_WFXM_SET _ULL(0xc00000000000)
+
+#define KVX_SFR_PSOW_MMUP_MASK _ULL(0x3000000000000) /* Privileged on MMU owner. */
+#define KVX_SFR_PSOW_MMUP_SHIFT 48
+#define KVX_SFR_PSOW_MMUP_WIDTH 2
+#define KVX_SFR_PSOW_MMUP_WFXM_MASK _ULL(0x3000000000000)
+#define KVX_SFR_PSOW_MMUP_WFXM_CLEAR _ULL(0x30000)
+#define KVX_SFR_PSOW_MMUP_WFXM_SET _ULL(0x3000000000000)
+
+#define KVX_SFR_CS_IC_MASK _ULL(0x1) /* Integer Carry */
+#define KVX_SFR_CS_IC_SHIFT 0
+#define KVX_SFR_CS_IC_WIDTH 1
+#define KVX_SFR_CS_IC_WFXL_MASK _ULL(0x1)
+#define KVX_SFR_CS_IC_WFXL_CLEAR _ULL(0x1)
+#define KVX_SFR_CS_IC_WFXL_SET _ULL(0x100000000)
+
+#define KVX_SFR_CS_IO_MASK _ULL(0x2) /* IEEE 754 Invalid Operation */
+#define KVX_SFR_CS_IO_SHIFT 1
+#define KVX_SFR_CS_IO_WIDTH 1
+#define KVX_SFR_CS_IO_WFXL_MASK _ULL(0x2)
+#define KVX_SFR_CS_IO_WFXL_CLEAR _ULL(0x2)
+#define KVX_SFR_CS_IO_WFXL_SET _ULL(0x200000000)
+
+#define KVX_SFR_CS_DZ_MASK _ULL(0x4) /* IEEE 754 Divide by Zero */
+#define KVX_SFR_CS_DZ_SHIFT 2
+#define KVX_SFR_CS_DZ_WIDTH 1
+#define KVX_SFR_CS_DZ_WFXL_MASK _ULL(0x4)
+#define KVX_SFR_CS_DZ_WFXL_CLEAR _ULL(0x4)
+#define KVX_SFR_CS_DZ_WFXL_SET _ULL(0x400000000)
+
+#define KVX_SFR_CS_OV_MASK _ULL(0x8) /* IEEE 754 Overflow */
+#define KVX_SFR_CS_OV_SHIFT 3
+#define KVX_SFR_CS_OV_WIDTH 1
+#define KVX_SFR_CS_OV_WFXL_MASK _ULL(0x8)
+#define KVX_SFR_CS_OV_WFXL_CLEAR _ULL(0x8)
+#define KVX_SFR_CS_OV_WFXL_SET _ULL(0x800000000)
+
+#define KVX_SFR_CS_UN_MASK _ULL(0x10) /* IEEE 754 Underflow */
+#define KVX_SFR_CS_UN_SHIFT 4
+#define KVX_SFR_CS_UN_WIDTH 1
+#define KVX_SFR_CS_UN_WFXL_MASK _ULL(0x10)
+#define KVX_SFR_CS_UN_WFXL_CLEAR _ULL(0x10)
+#define KVX_SFR_CS_UN_WFXL_SET _ULL(0x1000000000)
+
+#define KVX_SFR_CS_IN_MASK _ULL(0x20) /* IEEE 754 Inexact */
+#define KVX_SFR_CS_IN_SHIFT 5
+#define KVX_SFR_CS_IN_WIDTH 1
+#define KVX_SFR_CS_IN_WFXL_MASK _ULL(0x20)
+#define KVX_SFR_CS_IN_WFXL_CLEAR _ULL(0x20)
+#define KVX_SFR_CS_IN_WFXL_SET _ULL(0x2000000000)
+
+#define KVX_SFR_CS_XIO_MASK _ULL(0x200) /* Extension IEEE 754 Invalid Operation */
+#define KVX_SFR_CS_XIO_SHIFT 9
+#define KVX_SFR_CS_XIO_WIDTH 1
+#define KVX_SFR_CS_XIO_WFXL_MASK _ULL(0x200)
+#define KVX_SFR_CS_XIO_WFXL_CLEAR _ULL(0x200)
+#define KVX_SFR_CS_XIO_WFXL_SET _ULL(0x20000000000)
+
+#define KVX_SFR_CS_XDZ_MASK _ULL(0x400) /* Extension IEEE 754 Divide by Zero */
+#define KVX_SFR_CS_XDZ_SHIFT 10
+#define KVX_SFR_CS_XDZ_WIDTH 1
+#define KVX_SFR_CS_XDZ_WFXL_MASK _ULL(0x400)
+#define KVX_SFR_CS_XDZ_WFXL_CLEAR _ULL(0x400)
+#define KVX_SFR_CS_XDZ_WFXL_SET _ULL(0x40000000000)
+
+#define KVX_SFR_CS_XOV_MASK _ULL(0x800) /* Extension IEEE 754 Overflow */
+#define KVX_SFR_CS_XOV_SHIFT 11
+#define KVX_SFR_CS_XOV_WIDTH 1
+#define KVX_SFR_CS_XOV_WFXL_MASK _ULL(0x800)
+#define KVX_SFR_CS_XOV_WFXL_CLEAR _ULL(0x800)
+#define KVX_SFR_CS_XOV_WFXL_SET _ULL(0x80000000000)
+
+#define KVX_SFR_CS_XUN_MASK _ULL(0x1000) /* Extension IEEE 754 Underflow */
+#define KVX_SFR_CS_XUN_SHIFT 12
+#define KVX_SFR_CS_XUN_WIDTH 1
+#define KVX_SFR_CS_XUN_WFXL_MASK _ULL(0x1000)
+#define KVX_SFR_CS_XUN_WFXL_CLEAR _ULL(0x1000)
+#define KVX_SFR_CS_XUN_WFXL_SET _ULL(0x100000000000)
+
+#define KVX_SFR_CS_XIN_MASK _ULL(0x2000) /* Extension IEEE 754 Inexact */
+#define KVX_SFR_CS_XIN_SHIFT 13
+#define KVX_SFR_CS_XIN_WIDTH 1
+#define KVX_SFR_CS_XIN_WFXL_MASK _ULL(0x2000)
+#define KVX_SFR_CS_XIN_WFXL_CLEAR _ULL(0x2000)
+#define KVX_SFR_CS_XIN_WFXL_SET _ULL(0x200000000000)
+
+#define KVX_SFR_CS_RM_MASK _ULL(0x30000) /* IEEE 754 Rounding Mode */
+#define KVX_SFR_CS_RM_SHIFT 16
+#define KVX_SFR_CS_RM_WIDTH 2
+#define KVX_SFR_CS_RM_WFXL_MASK _ULL(0x30000)
+#define KVX_SFR_CS_RM_WFXL_CLEAR _ULL(0x30000)
+#define KVX_SFR_CS_RM_WFXL_SET _ULL(0x3000000000000)
+
+#define KVX_SFR_CS_XRM_MASK _ULL(0x300000) /* Extension IEEE 754 Rounding Mode */
+#define KVX_SFR_CS_XRM_SHIFT 20
+#define KVX_SFR_CS_XRM_WIDTH 2
+#define KVX_SFR_CS_XRM_WFXL_MASK _ULL(0x300000)
+#define KVX_SFR_CS_XRM_WFXL_CLEAR _ULL(0x300000)
+#define KVX_SFR_CS_XRM_WFXL_SET _ULL(0x30000000000000)
+
+#define KVX_SFR_CS_XMF_MASK _ULL(0x1000000) /* eXtension ModiFied */
+#define KVX_SFR_CS_XMF_SHIFT 24
+#define KVX_SFR_CS_XMF_WIDTH 1
+#define KVX_SFR_CS_XMF_WFXL_MASK _ULL(0x1000000)
+#define KVX_SFR_CS_XMF_WFXL_CLEAR _ULL(0x1000000)
+#define KVX_SFR_CS_XMF_WFXL_SET _ULL(0x100000000000000)
+
+#define KVX_SFR_CS_CC_MASK _ULL(0xffff00000000) /* Carry Counter */
+#define KVX_SFR_CS_CC_SHIFT 32
+#define KVX_SFR_CS_CC_WIDTH 16
+#define KVX_SFR_CS_CC_WFXM_MASK _ULL(0xffff00000000)
+#define KVX_SFR_CS_CC_WFXM_CLEAR _ULL(0xffff)
+#define KVX_SFR_CS_CC_WFXM_SET _ULL(0xffff00000000)
+
+#define KVX_SFR_CS_XDROP_MASK _ULL(0x3f000000000000) /* Extension Conversion Drop Bits */
+#define KVX_SFR_CS_XDROP_SHIFT 48
+#define KVX_SFR_CS_XDROP_WIDTH 6
+#define KVX_SFR_CS_XDROP_WFXM_MASK _ULL(0x3f000000000000)
+#define KVX_SFR_CS_XDROP_WFXM_CLEAR _ULL(0x3f0000)
+#define KVX_SFR_CS_XDROP_WFXM_SET _ULL(0x3f000000000000)
+
+#define KVX_SFR_CS_XPOW2_MASK _ULL(0xfc0000000000000) /* Extension FScale Power of Two */
+#define KVX_SFR_CS_XPOW2_SHIFT 54
+#define KVX_SFR_CS_XPOW2_WIDTH 6
+#define KVX_SFR_CS_XPOW2_WFXM_MASK _ULL(0xfc0000000000000)
+#define KVX_SFR_CS_XPOW2_WFXM_CLEAR _ULL(0xfc00000)
+#define KVX_SFR_CS_XPOW2_WFXM_SET _ULL(0xfc0000000000000)
+
+#define KVX_SFR_AESPC_AESPC_MASK _ULL(0xffffffffffffffff) /* Arithmetic Exception Saved PC */
+#define KVX_SFR_AESPC_AESPC_SHIFT 0
+#define KVX_SFR_AESPC_AESPC_WIDTH 64
+#define KVX_SFR_AESPC_AESPC_WFXL_MASK _ULL(0xffffffff)
+#define KVX_SFR_AESPC_AESPC_WFXL_CLEAR _ULL(0xffffffff)
+#define KVX_SFR_AESPC_AESPC_WFXL_SET _ULL(0xffffffff00000000)
+#define KVX_SFR_AESPC_AESPC_WFXM_MASK _ULL(0xffffffff00000000)
+#define KVX_SFR_AESPC_AESPC_WFXM_CLEAR _ULL(0xffffffff)
+#define KVX_SFR_AESPC_AESPC_WFXM_SET _ULL(0xffffffff00000000)
+
+#define KVX_SFR_CSIT_ICIE_MASK _ULL(0x1) /* Integer Carry Interrupt Enable */
+#define KVX_SFR_CSIT_ICIE_SHIFT 0
+#define KVX_SFR_CSIT_ICIE_WIDTH 1
+#define KVX_SFR_CSIT_ICIE_WFXL_MASK _ULL(0x1)
+#define KVX_SFR_CSIT_ICIE_WFXL_CLEAR _ULL(0x1)
+#define KVX_SFR_CSIT_ICIE_WFXL_SET _ULL(0x100000000)
+
+#define KVX_SFR_CSIT_IOIE_MASK _ULL(0x2) /* IEEE 754 Invalid Operation Interrupt Enable */
+#define KVX_SFR_CSIT_IOIE_SHIFT 1
+#define KVX_SFR_CSIT_IOIE_WIDTH 1
+#define KVX_SFR_CSIT_IOIE_WFXL_MASK _ULL(0x2)
+#define KVX_SFR_CSIT_IOIE_WFXL_CLEAR _ULL(0x2)
+#define KVX_SFR_CSIT_IOIE_WFXL_SET _ULL(0x200000000)
+
+#define KVX_SFR_CSIT_DZIE_MASK _ULL(0x4) /* IEEE 754 Divide by Zero Interrupt Enable */
+#define KVX_SFR_CSIT_DZIE_SHIFT 2
+#define KVX_SFR_CSIT_DZIE_WIDTH 1
+#define KVX_SFR_CSIT_DZIE_WFXL_MASK _ULL(0x4)
+#define KVX_SFR_CSIT_DZIE_WFXL_CLEAR _ULL(0x4)
+#define KVX_SFR_CSIT_DZIE_WFXL_SET _ULL(0x400000000)
+
+#define KVX_SFR_CSIT_OVIE_MASK _ULL(0x8) /* IEEE 754 Overflow Interrupt Enable */
+#define KVX_SFR_CSIT_OVIE_SHIFT 3
+#define KVX_SFR_CSIT_OVIE_WIDTH 1
+#define KVX_SFR_CSIT_OVIE_WFXL_MASK _ULL(0x8)
+#define KVX_SFR_CSIT_OVIE_WFXL_CLEAR _ULL(0x8)
+#define KVX_SFR_CSIT_OVIE_WFXL_SET _ULL(0x800000000)
+
+#define KVX_SFR_CSIT_UNIE_MASK _ULL(0x10) /* IEEE 754 Underflow Interrupt Enable */
+#define KVX_SFR_CSIT_UNIE_SHIFT 4
+#define KVX_SFR_CSIT_UNIE_WIDTH 1
+#define KVX_SFR_CSIT_UNIE_WFXL_MASK _ULL(0x10)
+#define KVX_SFR_CSIT_UNIE_WFXL_CLEAR _ULL(0x10)
+#define KVX_SFR_CSIT_UNIE_WFXL_SET _ULL(0x1000000000)
+
+#define KVX_SFR_CSIT_INIE_MASK _ULL(0x20) /* IEEE 754 Inexact Interrupt Enable */
+#define KVX_SFR_CSIT_INIE_SHIFT 5
+#define KVX_SFR_CSIT_INIE_WIDTH 1
+#define KVX_SFR_CSIT_INIE_WFXL_MASK _ULL(0x20)
+#define KVX_SFR_CSIT_INIE_WFXL_CLEAR _ULL(0x20)
+#define KVX_SFR_CSIT_INIE_WFXL_SET _ULL(0x2000000000)
+
+#define KVX_SFR_CSIT_XIOIE_MASK _ULL(0x200) /* Extension IEEE 754 Invalid Operation Interrupt Enable */
+#define KVX_SFR_CSIT_XIOIE_SHIFT 9
+#define KVX_SFR_CSIT_XIOIE_WIDTH 1
+#define KVX_SFR_CSIT_XIOIE_WFXL_MASK _ULL(0x200)
+#define KVX_SFR_CSIT_XIOIE_WFXL_CLEAR _ULL(0x200)
+#define KVX_SFR_CSIT_XIOIE_WFXL_SET _ULL(0x20000000000)
+
+#define KVX_SFR_CSIT_XDZIE_MASK _ULL(0x400) /* Extension IEEE 754 Divide by Zero Interrupt Enable */
+#define KVX_SFR_CSIT_XDZIE_SHIFT 10
+#define KVX_SFR_CSIT_XDZIE_WIDTH 1
+#define KVX_SFR_CSIT_XDZIE_WFXL_MASK _ULL(0x400)
+#define KVX_SFR_CSIT_XDZIE_WFXL_CLEAR _ULL(0x400)
+#define KVX_SFR_CSIT_XDZIE_WFXL_SET _ULL(0x40000000000)
+
+#define KVX_SFR_CSIT_XOVIE_MASK _ULL(0x800) /* Extension IEEE 754 Overflow Interrupt Enable */
+#define KVX_SFR_CSIT_XOVIE_SHIFT 11
+#define KVX_SFR_CSIT_XOVIE_WIDTH 1
+#define KVX_SFR_CSIT_XOVIE_WFXL_MASK _ULL(0x800)
+#define KVX_SFR_CSIT_XOVIE_WFXL_CLEAR _ULL(0x800)
+#define KVX_SFR_CSIT_XOVIE_WFXL_SET _ULL(0x80000000000)
+
+#define KVX_SFR_CSIT_XUNIE_MASK _ULL(0x1000) /* Extension IEEE 754 Underflow Interrupt Enable */
+#define KVX_SFR_CSIT_XUNIE_SHIFT 12
+#define KVX_SFR_CSIT_XUNIE_WIDTH 1
+#define KVX_SFR_CSIT_XUNIE_WFXL_MASK _ULL(0x1000)
+#define KVX_SFR_CSIT_XUNIE_WFXL_CLEAR _ULL(0x1000)
+#define KVX_SFR_CSIT_XUNIE_WFXL_SET _ULL(0x100000000000)
+
+#define KVX_SFR_CSIT_XINIE_MASK _ULL(0x2000) /* Extension IEEE 754 Inexact Interrupt Enable */
+#define KVX_SFR_CSIT_XINIE_SHIFT 13
+#define KVX_SFR_CSIT_XINIE_WIDTH 1
+#define KVX_SFR_CSIT_XINIE_WFXL_MASK _ULL(0x2000)
+#define KVX_SFR_CSIT_XINIE_WFXL_CLEAR _ULL(0x2000)
+#define KVX_SFR_CSIT_XINIE_WFXL_SET _ULL(0x200000000000)
+
+#define KVX_SFR_CSIT_AEIR_MASK _ULL(0x10000) /* Arithmetic Exception Interrupt Raised */
+#define KVX_SFR_CSIT_AEIR_SHIFT 16
+#define KVX_SFR_CSIT_AEIR_WIDTH 1
+#define KVX_SFR_CSIT_AEIR_WFXL_MASK _ULL(0x10000)
+#define KVX_SFR_CSIT_AEIR_WFXL_CLEAR _ULL(0x10000)
+#define KVX_SFR_CSIT_AEIR_WFXL_SET _ULL(0x1000000000000)
+
+#define KVX_SFR_CSIT_AEC_MASK _ULL(0xe0000) /* Arithmetic Exception Code */
+#define KVX_SFR_CSIT_AEC_SHIFT 17
+#define KVX_SFR_CSIT_AEC_WIDTH 3
+#define KVX_SFR_CSIT_AEC_WFXL_MASK _ULL(0xe0000)
+#define KVX_SFR_CSIT_AEC_WFXL_CLEAR _ULL(0xe0000)
+#define KVX_SFR_CSIT_AEC_WFXL_SET _ULL(0xe000000000000)
+
+#define KVX_SFR_CSIT_SPCV_MASK _ULL(0x100000) /* SPC Valid */
+#define KVX_SFR_CSIT_SPCV_SHIFT 20
+#define KVX_SFR_CSIT_SPCV_WIDTH 1
+#define KVX_SFR_CSIT_SPCV_WFXL_MASK _ULL(0x100000)
+#define KVX_SFR_CSIT_SPCV_WFXL_CLEAR _ULL(0x100000)
+#define KVX_SFR_CSIT_SPCV_WFXL_SET _ULL(0x10000000000000)
+
+#define KVX_SFR_ES_EC_MASK _ULL(0xf) /* Exception Class */
+#define KVX_SFR_ES_EC_SHIFT 0
+#define KVX_SFR_ES_EC_WIDTH 4
+#define KVX_SFR_ES_EC_WFXL_MASK _ULL(0xf)
+#define KVX_SFR_ES_EC_WFXL_CLEAR _ULL(0xf)
+#define KVX_SFR_ES_EC_WFXL_SET _ULL(0xf00000000)
+
+#define KVX_SFR_ES_ED_MASK _ULL(0xfffffffffffffff0) /* Exception Details */
+#define KVX_SFR_ES_ED_SHIFT 4
+#define KVX_SFR_ES_ED_WIDTH 60
+#define KVX_SFR_ES_ED_WFXL_MASK _ULL(0xfffffff0)
+#define KVX_SFR_ES_ED_WFXL_CLEAR _ULL(0xfffffff0)
+#define KVX_SFR_ES_ED_WFXL_SET _ULL(0xfffffff000000000)
+#define KVX_SFR_ES_ED_WFXM_MASK _ULL(0xffffffff00000000)
+#define KVX_SFR_ES_ED_WFXM_CLEAR _ULL(0xffffffff)
+#define KVX_SFR_ES_ED_WFXM_SET _ULL(0xffffffff00000000)
+
+#define KVX_SFR_ES_OAPL_MASK _ULL(0x30) /* Origin Absolute PL */
+#define KVX_SFR_ES_OAPL_SHIFT 4
+#define KVX_SFR_ES_OAPL_WIDTH 2
+#define KVX_SFR_ES_OAPL_WFXL_MASK _ULL(0x30)
+#define KVX_SFR_ES_OAPL_WFXL_CLEAR _ULL(0x30)
+#define KVX_SFR_ES_OAPL_WFXL_SET _ULL(0x3000000000)
+
+#define KVX_SFR_ES_ORPL_MASK _ULL(0xc0) /* Origin Relative PL */
+#define KVX_SFR_ES_ORPL_SHIFT 6
+#define KVX_SFR_ES_ORPL_WIDTH 2
+#define KVX_SFR_ES_ORPL_WFXL_MASK _ULL(0xc0)
+#define KVX_SFR_ES_ORPL_WFXL_CLEAR _ULL(0xc0)
+#define KVX_SFR_ES_ORPL_WFXL_SET _ULL(0xc000000000)
+
+#define KVX_SFR_ES_PTAPL_MASK _ULL(0x300) /* Primary Target Absolute PL */
+#define KVX_SFR_ES_PTAPL_SHIFT 8
+#define KVX_SFR_ES_PTAPL_WIDTH 2
+#define KVX_SFR_ES_PTAPL_WFXL_MASK _ULL(0x300)
+#define KVX_SFR_ES_PTAPL_WFXL_CLEAR _ULL(0x300)
+#define KVX_SFR_ES_PTAPL_WFXL_SET _ULL(0x30000000000)
+
+#define KVX_SFR_ES_PTRPL_MASK _ULL(0xc00) /* Primary Target Relative PL */
+#define KVX_SFR_ES_PTRPL_SHIFT 10
+#define KVX_SFR_ES_PTRPL_WIDTH 2
+#define KVX_SFR_ES_PTRPL_WFXL_MASK _ULL(0xc00)
+#define KVX_SFR_ES_PTRPL_WFXL_CLEAR _ULL(0xc00)
+#define KVX_SFR_ES_PTRPL_WFXL_SET _ULL(0xc0000000000)
+
+#define KVX_SFR_ES_ITN_MASK _ULL(0x1f000) /* InTerrupt Number */
+#define KVX_SFR_ES_ITN_SHIFT 12
+#define KVX_SFR_ES_ITN_WIDTH 5
+#define KVX_SFR_ES_ITN_WFXL_MASK _ULL(0x1f000)
+#define KVX_SFR_ES_ITN_WFXL_CLEAR _ULL(0x1f000)
+#define KVX_SFR_ES_ITN_WFXL_SET _ULL(0x1f00000000000)
+
+#define KVX_SFR_ES_ITL_MASK _ULL(0x60000) /* InTerrupt Level */
+#define KVX_SFR_ES_ITL_SHIFT 17
+#define KVX_SFR_ES_ITL_WIDTH 2
+#define KVX_SFR_ES_ITL_WFXL_MASK _ULL(0x60000)
+#define KVX_SFR_ES_ITL_WFXL_CLEAR _ULL(0x60000)
+#define KVX_SFR_ES_ITL_WFXL_SET _ULL(0x6000000000000)
+
+#define KVX_SFR_ES_ITI_MASK _ULL(0x1ff80000) /* InTerrupt Info */
+#define KVX_SFR_ES_ITI_SHIFT 19
+#define KVX_SFR_ES_ITI_WIDTH 10
+#define KVX_SFR_ES_ITI_WFXL_MASK _ULL(0x1ff80000)
+#define KVX_SFR_ES_ITI_WFXL_CLEAR _ULL(0x1ff80000)
+#define KVX_SFR_ES_ITI_WFXL_SET _ULL(0x1ff8000000000000)
+
+#define KVX_SFR_ES_SN_MASK _ULL(0xfff000) /* Syscall Number */
+#define KVX_SFR_ES_SN_SHIFT 12
+#define KVX_SFR_ES_SN_WIDTH 12
+#define KVX_SFR_ES_SN_WFXL_MASK _ULL(0xfff000)
+#define KVX_SFR_ES_SN_WFXL_CLEAR _ULL(0xfff000)
+#define KVX_SFR_ES_SN_WFXL_SET _ULL(0xfff00000000000)
+
+#define KVX_SFR_ES_HTC_MASK _ULL(0x1f000) /* Hardware Trap Cause */
+#define KVX_SFR_ES_HTC_SHIFT 12
+#define KVX_SFR_ES_HTC_WIDTH 5
+#define KVX_SFR_ES_HTC_WFXL_MASK _ULL(0x1f000)
+#define KVX_SFR_ES_HTC_WFXL_CLEAR _ULL(0x1f000)
+#define KVX_SFR_ES_HTC_WFXL_SET _ULL(0x1f00000000000)
+
+#define KVX_SFR_ES_SFRT_MASK _ULL(0x20000) /* SFR Trap */
+#define KVX_SFR_ES_SFRT_SHIFT 17
+#define KVX_SFR_ES_SFRT_WIDTH 1
+#define KVX_SFR_ES_SFRT_WFXL_MASK _ULL(0x20000)
+#define KVX_SFR_ES_SFRT_WFXL_CLEAR _ULL(0x20000)
+#define KVX_SFR_ES_SFRT_WFXL_SET _ULL(0x2000000000000)
+
+#define KVX_SFR_ES_SFRI_MASK _ULL(0x1c0000) /* SFR Instruction */
+#define KVX_SFR_ES_SFRI_SHIFT 18
+#define KVX_SFR_ES_SFRI_WIDTH 3
+#define KVX_SFR_ES_SFRI_WFXL_MASK _ULL(0x1c0000)
+#define KVX_SFR_ES_SFRI_WFXL_CLEAR _ULL(0x1c0000)
+#define KVX_SFR_ES_SFRI_WFXL_SET _ULL(0x1c000000000000)
+
+#define KVX_SFR_ES_GPRP_MASK _ULL(0x7e00000) /* GPR Pointer */
+#define KVX_SFR_ES_GPRP_SHIFT 21
+#define KVX_SFR_ES_GPRP_WIDTH 6
+#define KVX_SFR_ES_GPRP_WFXL_MASK _ULL(0x7e00000)
+#define KVX_SFR_ES_GPRP_WFXL_CLEAR _ULL(0x7e00000)
+#define KVX_SFR_ES_GPRP_WFXL_SET _ULL(0x7e0000000000000)
+
+#define KVX_SFR_ES_SFRP_MASK _ULL(0xff8000000) /* SFR Pointer */
+#define KVX_SFR_ES_SFRP_SHIFT 27
+#define KVX_SFR_ES_SFRP_WIDTH 9
+#define KVX_SFR_ES_SFRP_WFXL_MASK _ULL(0xf8000000)
+#define KVX_SFR_ES_SFRP_WFXL_CLEAR _ULL(0xf8000000)
+#define KVX_SFR_ES_SFRP_WFXL_SET _ULL(0xf800000000000000)
+#define KVX_SFR_ES_SFRP_WFXM_MASK _ULL(0xf00000000)
+#define KVX_SFR_ES_SFRP_WFXM_CLEAR _ULL(0xf)
+#define KVX_SFR_ES_SFRP_WFXM_SET _ULL(0xf00000000)
+
+#define KVX_SFR_ES_DHT_MASK _ULL(0x1000000000) /* Disabled Hardware Trap */
+#define KVX_SFR_ES_DHT_SHIFT 36
+#define KVX_SFR_ES_DHT_WIDTH 1
+#define KVX_SFR_ES_DHT_WFXM_MASK _ULL(0x1000000000)
+#define KVX_SFR_ES_DHT_WFXM_CLEAR _ULL(0x10)
+#define KVX_SFR_ES_DHT_WFXM_SET _ULL(0x1000000000)
+
+#define KVX_SFR_ES_RWX_MASK _ULL(0x38000000000) /* Read Write Execute */
+#define KVX_SFR_ES_RWX_SHIFT 39
+#define KVX_SFR_ES_RWX_WIDTH 3
+#define KVX_SFR_ES_RWX_WFXM_MASK _ULL(0x38000000000)
+#define KVX_SFR_ES_RWX_WFXM_CLEAR _ULL(0x380)
+#define KVX_SFR_ES_RWX_WFXM_SET _ULL(0x38000000000)
+
+#define KVX_SFR_ES_NTA_MASK _ULL(0x40000000000) /* Non-Trapping Access */
+#define KVX_SFR_ES_NTA_SHIFT 42
+#define KVX_SFR_ES_NTA_WIDTH 1
+#define KVX_SFR_ES_NTA_WFXM_MASK _ULL(0x40000000000)
+#define KVX_SFR_ES_NTA_WFXM_CLEAR _ULL(0x400)
+#define KVX_SFR_ES_NTA_WFXM_SET _ULL(0x40000000000)
+
+#define KVX_SFR_ES_UCA_MASK _ULL(0x80000000000) /* Un-Cached Access */
+#define KVX_SFR_ES_UCA_SHIFT 43
+#define KVX_SFR_ES_UCA_WIDTH 1
+#define KVX_SFR_ES_UCA_WFXM_MASK _ULL(0x80000000000)
+#define KVX_SFR_ES_UCA_WFXM_CLEAR _ULL(0x800)
+#define KVX_SFR_ES_UCA_WFXM_SET _ULL(0x80000000000)
+
+#define KVX_SFR_ES_AS_MASK _ULL(0x3f00000000000) /* Access Size */
+#define KVX_SFR_ES_AS_SHIFT 44
+#define KVX_SFR_ES_AS_WIDTH 6
+#define KVX_SFR_ES_AS_WFXM_MASK _ULL(0x3f00000000000)
+#define KVX_SFR_ES_AS_WFXM_CLEAR _ULL(0x3f000)
+#define KVX_SFR_ES_AS_WFXM_SET _ULL(0x3f00000000000)
+
+#define KVX_SFR_ES_BS_MASK _ULL(0x3c000000000000) /* Bundle Size */
+#define KVX_SFR_ES_BS_SHIFT 50
+#define KVX_SFR_ES_BS_WIDTH 4
+#define KVX_SFR_ES_BS_WFXM_MASK _ULL(0x3c000000000000)
+#define KVX_SFR_ES_BS_WFXM_CLEAR _ULL(0x3c0000)
+#define KVX_SFR_ES_BS_WFXM_SET _ULL(0x3c000000000000)
+
+#define KVX_SFR_ES_DRI_MASK _ULL(0xfc0000000000000) /* Data Register Index */
+#define KVX_SFR_ES_DRI_SHIFT 54
+#define KVX_SFR_ES_DRI_WIDTH 6
+#define KVX_SFR_ES_DRI_WFXM_MASK _ULL(0xfc0000000000000)
+#define KVX_SFR_ES_DRI_WFXM_CLEAR _ULL(0xfc00000)
+#define KVX_SFR_ES_DRI_WFXM_SET _ULL(0xfc0000000000000)
+
+#define KVX_SFR_ES_PIC_MASK _ULL(0xf000000000000000) /* Privileged Instruction Code */
+#define KVX_SFR_ES_PIC_SHIFT 60
+#define KVX_SFR_ES_PIC_WIDTH 4
+#define KVX_SFR_ES_PIC_WFXM_MASK _ULL(0xf000000000000000)
+#define KVX_SFR_ES_PIC_WFXM_CLEAR _ULL(0xf0000000)
+#define KVX_SFR_ES_PIC_WFXM_SET _ULL(0xf000000000000000)
+
+#define KVX_SFR_ES_DC_MASK _ULL(0x3000) /* Debug Cause */
+#define KVX_SFR_ES_DC_SHIFT 12
+#define KVX_SFR_ES_DC_WIDTH 2
+#define KVX_SFR_ES_DC_WFXL_MASK _ULL(0x3000)
+#define KVX_SFR_ES_DC_WFXL_CLEAR _ULL(0x3000)
+#define KVX_SFR_ES_DC_WFXL_SET _ULL(0x300000000000)
+
+#define KVX_SFR_ES_BN_MASK _ULL(0x4000) /* Breakpoint Number */
+#define KVX_SFR_ES_BN_SHIFT 14
+#define KVX_SFR_ES_BN_WIDTH 1
+#define KVX_SFR_ES_BN_WFXL_MASK _ULL(0x4000)
+#define KVX_SFR_ES_BN_WFXL_CLEAR _ULL(0x4000)
+#define KVX_SFR_ES_BN_WFXL_SET _ULL(0x400000000000)
+
+#define KVX_SFR_ES_WN_MASK _ULL(0x8000) /* Watchpoint Number */
+#define KVX_SFR_ES_WN_SHIFT 15
+#define KVX_SFR_ES_WN_WIDTH 1
+#define KVX_SFR_ES_WN_WFXL_MASK _ULL(0x8000)
+#define KVX_SFR_ES_WN_WFXL_CLEAR _ULL(0x8000)
+#define KVX_SFR_ES_WN_WFXL_SET _ULL(0x800000000000)
+
+#define KVX_SFR_ES_PL0_EC_MASK _ULL(0xf) /* Exception Class */
+#define KVX_SFR_ES_PL0_EC_SHIFT 0
+#define KVX_SFR_ES_PL0_EC_WIDTH 4
+#define KVX_SFR_ES_PL0_EC_WFXL_MASK _ULL(0xf)
+#define KVX_SFR_ES_PL0_EC_WFXL_CLEAR _ULL(0xf)
+#define KVX_SFR_ES_PL0_EC_WFXL_SET _ULL(0xf00000000)
+
+#define KVX_SFR_ES_PL0_ED_MASK _ULL(0xfffffffffffffff0) /* Exception Details */
+#define KVX_SFR_ES_PL0_ED_SHIFT 4
+#define KVX_SFR_ES_PL0_ED_WIDTH 60
+#define KVX_SFR_ES_PL0_ED_WFXL_MASK _ULL(0xfffffff0)
+#define KVX_SFR_ES_PL0_ED_WFXL_CLEAR _ULL(0xfffffff0)
+#define KVX_SFR_ES_PL0_ED_WFXL_SET _ULL(0xfffffff000000000)
+#define KVX_SFR_ES_PL0_ED_WFXM_MASK _ULL(0xffffffff00000000)
+#define KVX_SFR_ES_PL0_ED_WFXM_CLEAR _ULL(0xffffffff)
+#define KVX_SFR_ES_PL0_ED_WFXM_SET _ULL(0xffffffff00000000)
+
+#define KVX_SFR_ES_PL0_OAPL_MASK _ULL(0x30) /* Origin Absolute PL */
+#define KVX_SFR_ES_PL0_OAPL_SHIFT 4
+#define KVX_SFR_ES_PL0_OAPL_WIDTH 2
+#define KVX_SFR_ES_PL0_OAPL_WFXL_MASK _ULL(0x30)
+#define KVX_SFR_ES_PL0_OAPL_WFXL_CLEAR _ULL(0x30)
+#define KVX_SFR_ES_PL0_OAPL_WFXL_SET _ULL(0x3000000000)
+
+#define KVX_SFR_ES_PL0_ORPL_MASK _ULL(0xc0) /* Origin Relative PL */
+#define KVX_SFR_ES_PL0_ORPL_SHIFT 6
+#define KVX_SFR_ES_PL0_ORPL_WIDTH 2
+#define KVX_SFR_ES_PL0_ORPL_WFXL_MASK _ULL(0xc0)
+#define KVX_SFR_ES_PL0_ORPL_WFXL_CLEAR _ULL(0xc0)
+#define KVX_SFR_ES_PL0_ORPL_WFXL_SET _ULL(0xc000000000)
+
+#define KVX_SFR_ES_PL0_PTAPL_MASK _ULL(0x300) /* Target Absolute PL */
+#define KVX_SFR_ES_PL0_PTAPL_SHIFT 8
+#define KVX_SFR_ES_PL0_PTAPL_WIDTH 2
+#define KVX_SFR_ES_PL0_PTAPL_WFXL_MASK _ULL(0x300)
+#define KVX_SFR_ES_PL0_PTAPL_WFXL_CLEAR _ULL(0x300)
+#define KVX_SFR_ES_PL0_PTAPL_WFXL_SET _ULL(0x30000000000)
+
+#define KVX_SFR_ES_PL0_PTRPL_MASK _ULL(0xc00) /* Target Relative PL */
+#define KVX_SFR_ES_PL0_PTRPL_SHIFT 10
+#define KVX_SFR_ES_PL0_PTRPL_WIDTH 2
+#define KVX_SFR_ES_PL0_PTRPL_WFXL_MASK _ULL(0xc00)
+#define KVX_SFR_ES_PL0_PTRPL_WFXL_CLEAR _ULL(0xc00)
+#define KVX_SFR_ES_PL0_PTRPL_WFXL_SET _ULL(0xc0000000000)
+
+#define KVX_SFR_ES_PL0_ITN_MASK _ULL(0x1f000) /* InTerrupt Number */
+#define KVX_SFR_ES_PL0_ITN_SHIFT 12
+#define KVX_SFR_ES_PL0_ITN_WIDTH 5
+#define KVX_SFR_ES_PL0_ITN_WFXL_MASK _ULL(0x1f000)
+#define KVX_SFR_ES_PL0_ITN_WFXL_CLEAR _ULL(0x1f000)
+#define KVX_SFR_ES_PL0_ITN_WFXL_SET _ULL(0x1f00000000000)
+
+#define KVX_SFR_ES_PL0_ITL_MASK _ULL(0x60000) /* InTerrupt Level */
+#define KVX_SFR_ES_PL0_ITL_SHIFT 17
+#define KVX_SFR_ES_PL0_ITL_WIDTH 2
+#define KVX_SFR_ES_PL0_ITL_WFXL_MASK _ULL(0x60000)
+#define KVX_SFR_ES_PL0_ITL_WFXL_CLEAR _ULL(0x60000)
+#define KVX_SFR_ES_PL0_ITL_WFXL_SET _ULL(0x6000000000000)
+
+#define KVX_SFR_ES_PL0_ITI_MASK _ULL(0x1ff80000) /* InTerrupt Info */
+#define KVX_SFR_ES_PL0_ITI_SHIFT 19
+#define KVX_SFR_ES_PL0_ITI_WIDTH 10
+#define KVX_SFR_ES_PL0_ITI_WFXL_MASK _ULL(0x1ff80000)
+#define KVX_SFR_ES_PL0_ITI_WFXL_CLEAR _ULL(0x1ff80000)
+#define KVX_SFR_ES_PL0_ITI_WFXL_SET _ULL(0x1ff8000000000000)
+
+#define KVX_SFR_ES_PL0_SN_MASK _ULL(0xfff000) /* Syscall Number */
+#define KVX_SFR_ES_PL0_SN_SHIFT 12
+#define KVX_SFR_ES_PL0_SN_WIDTH 12
+#define KVX_SFR_ES_PL0_SN_WFXL_MASK _ULL(0xfff000)
+#define KVX_SFR_ES_PL0_SN_WFXL_CLEAR _ULL(0xfff000)
+#define KVX_SFR_ES_PL0_SN_WFXL_SET _ULL(0xfff00000000000)
+
+#define KVX_SFR_ES_PL0_HTC_MASK _ULL(0x1f000) /* Hardware Trap Cause */
+#define KVX_SFR_ES_PL0_HTC_SHIFT 12
+#define KVX_SFR_ES_PL0_HTC_WIDTH 5
+#define KVX_SFR_ES_PL0_HTC_WFXL_MASK _ULL(0x1f000)
+#define KVX_SFR_ES_PL0_HTC_WFXL_CLEAR _ULL(0x1f000)
+#define KVX_SFR_ES_PL0_HTC_WFXL_SET _ULL(0x1f00000000000)
+
+#define KVX_SFR_ES_PL0_SFRT_MASK _ULL(0x20000) /* SFR Trap */
+#define KVX_SFR_ES_PL0_SFRT_SHIFT 17
+#define KVX_SFR_ES_PL0_SFRT_WIDTH 1
+#define KVX_SFR_ES_PL0_SFRT_WFXL_MASK _ULL(0x20000)
+#define KVX_SFR_ES_PL0_SFRT_WFXL_CLEAR _ULL(0x20000)
+#define KVX_SFR_ES_PL0_SFRT_WFXL_SET _ULL(0x2000000000000)
+
+#define KVX_SFR_ES_PL0_SFRI_MASK _ULL(0x1c0000) /* SFR Instruction */
+#define KVX_SFR_ES_PL0_SFRI_SHIFT 18
+#define KVX_SFR_ES_PL0_SFRI_WIDTH 3
+#define KVX_SFR_ES_PL0_SFRI_WFXL_MASK _ULL(0x1c0000)
+#define KVX_SFR_ES_PL0_SFRI_WFXL_CLEAR _ULL(0x1c0000)
+#define KVX_SFR_ES_PL0_SFRI_WFXL_SET _ULL(0x1c000000000000)
+
+#define KVX_SFR_ES_PL0_GPRP_MASK _ULL(0x7e00000) /* GPR Pointer */
+#define KVX_SFR_ES_PL0_GPRP_SHIFT 21
+#define KVX_SFR_ES_PL0_GPRP_WIDTH 6
+#define KVX_SFR_ES_PL0_GPRP_WFXL_MASK _ULL(0x7e00000)
+#define KVX_SFR_ES_PL0_GPRP_WFXL_CLEAR _ULL(0x7e00000)
+#define KVX_SFR_ES_PL0_GPRP_WFXL_SET _ULL(0x7e0000000000000)
+
+#define KVX_SFR_ES_PL0_SFRP_MASK _ULL(0xff8000000) /* SFR Pointer */
+#define KVX_SFR_ES_PL0_SFRP_SHIFT 27
+#define KVX_SFR_ES_PL0_SFRP_WIDTH 9
+#define KVX_SFR_ES_PL0_SFRP_WFXL_MASK _ULL(0xf8000000)
+#define KVX_SFR_ES_PL0_SFRP_WFXL_CLEAR _ULL(0xf8000000)
+#define KVX_SFR_ES_PL0_SFRP_WFXL_SET _ULL(0xf800000000000000)
+#define KVX_SFR_ES_PL0_SFRP_WFXM_MASK _ULL(0xf00000000)
+#define KVX_SFR_ES_PL0_SFRP_WFXM_CLEAR _ULL(0xf)
+#define KVX_SFR_ES_PL0_SFRP_WFXM_SET _ULL(0xf00000000)
+
+#define KVX_SFR_ES_PL0_DHT_MASK _ULL(0x1000000000) /* Disabled Hardware Trap */
+#define KVX_SFR_ES_PL0_DHT_SHIFT 36
+#define KVX_SFR_ES_PL0_DHT_WIDTH 1
+#define KVX_SFR_ES_PL0_DHT_WFXM_MASK _ULL(0x1000000000)
+#define KVX_SFR_ES_PL0_DHT_WFXM_CLEAR _ULL(0x10)
+#define KVX_SFR_ES_PL0_DHT_WFXM_SET _ULL(0x1000000000)
+
+#define KVX_SFR_ES_PL0_RWX_MASK _ULL(0x38000000000) /* Read Write Execute */
+#define KVX_SFR_ES_PL0_RWX_SHIFT 39
+#define KVX_SFR_ES_PL0_RWX_WIDTH 3
+#define KVX_SFR_ES_PL0_RWX_WFXM_MASK _ULL(0x38000000000)
+#define KVX_SFR_ES_PL0_RWX_WFXM_CLEAR _ULL(0x380)
+#define KVX_SFR_ES_PL0_RWX_WFXM_SET _ULL(0x38000000000)
+
+#define KVX_SFR_ES_PL0_NTA_MASK _ULL(0x40000000000) /* Non-Trapping Access */
+#define KVX_SFR_ES_PL0_NTA_SHIFT 42
+#define KVX_SFR_ES_PL0_NTA_WIDTH 1
+#define KVX_SFR_ES_PL0_NTA_WFXM_MASK _ULL(0x40000000000)
+#define KVX_SFR_ES_PL0_NTA_WFXM_CLEAR _ULL(0x400)
+#define KVX_SFR_ES_PL0_NTA_WFXM_SET _ULL(0x40000000000)
+
+#define KVX_SFR_ES_PL0_UCA_MASK _ULL(0x80000000000) /* Un-Cached Access */
+#define KVX_SFR_ES_PL0_UCA_SHIFT 43
+#define KVX_SFR_ES_PL0_UCA_WIDTH 1
+#define KVX_SFR_ES_PL0_UCA_WFXM_MASK _ULL(0x80000000000)
+#define KVX_SFR_ES_PL0_UCA_WFXM_CLEAR _ULL(0x800)
+#define KVX_SFR_ES_PL0_UCA_WFXM_SET _ULL(0x80000000000)
+
+#define KVX_SFR_ES_PL0_AS_MASK _ULL(0x3f00000000000) /* Access Size */
+#define KVX_SFR_ES_PL0_AS_SHIFT 44
+#define KVX_SFR_ES_PL0_AS_WIDTH 6
+#define KVX_SFR_ES_PL0_AS_WFXM_MASK _ULL(0x3f00000000000)
+#define KVX_SFR_ES_PL0_AS_WFXM_CLEAR _ULL(0x3f000)
+#define KVX_SFR_ES_PL0_AS_WFXM_SET _ULL(0x3f00000000000)
+
+#define KVX_SFR_ES_PL0_BS_MASK _ULL(0x3c000000000000) /* Bundle Size */
+#define KVX_SFR_ES_PL0_BS_SHIFT 50
+#define KVX_SFR_ES_PL0_BS_WIDTH 4
+#define KVX_SFR_ES_PL0_BS_WFXM_MASK _ULL(0x3c000000000000)
+#define KVX_SFR_ES_PL0_BS_WFXM_CLEAR _ULL(0x3c0000)
+#define KVX_SFR_ES_PL0_BS_WFXM_SET _ULL(0x3c000000000000)
+
+#define KVX_SFR_ES_PL0_DRI_MASK _ULL(0xfc0000000000000) /* Data Register Index */
+#define KVX_SFR_ES_PL0_DRI_SHIFT 54
+#define KVX_SFR_ES_PL0_DRI_WIDTH 6
+#define KVX_SFR_ES_PL0_DRI_WFXM_MASK _ULL(0xfc0000000000000)
+#define KVX_SFR_ES_PL0_DRI_WFXM_CLEAR _ULL(0xfc00000)
+#define KVX_SFR_ES_PL0_DRI_WFXM_SET _ULL(0xfc0000000000000)
+
+#define KVX_SFR_ES_PL0_PIC_MASK _ULL(0xf000000000000000) /* Privileged Instruction Code */
+#define KVX_SFR_ES_PL0_PIC_SHIFT 60
+#define KVX_SFR_ES_PL0_PIC_WIDTH 4
+#define KVX_SFR_ES_PL0_PIC_WFXM_MASK _ULL(0xf000000000000000)
+#define KVX_SFR_ES_PL0_PIC_WFXM_CLEAR _ULL(0xf0000000)
+#define KVX_SFR_ES_PL0_PIC_WFXM_SET _ULL(0xf000000000000000)
+
+#define KVX_SFR_ES_PL0_DC_MASK _ULL(0x3000) /* Debug Cause */
+#define KVX_SFR_ES_PL0_DC_SHIFT 12
+#define KVX_SFR_ES_PL0_DC_WIDTH 2
+#define KVX_SFR_ES_PL0_DC_WFXL_MASK _ULL(0x3000)
+#define KVX_SFR_ES_PL0_DC_WFXL_CLEAR _ULL(0x3000)
+#define KVX_SFR_ES_PL0_DC_WFXL_SET _ULL(0x300000000000)
+
+#define KVX_SFR_ES_PL0_BN_MASK _ULL(0x4000) /* Breakpoint Number */
+#define KVX_SFR_ES_PL0_BN_SHIFT 14
+#define KVX_SFR_ES_PL0_BN_WIDTH 1
+#define KVX_SFR_ES_PL0_BN_WFXL_MASK _ULL(0x4000)
+#define KVX_SFR_ES_PL0_BN_WFXL_CLEAR _ULL(0x4000)
+#define KVX_SFR_ES_PL0_BN_WFXL_SET _ULL(0x400000000000)
+
+#define KVX_SFR_ES_PL0_WN_MASK _ULL(0x8000) /* Watchpoint Number */
+#define KVX_SFR_ES_PL0_WN_SHIFT 15
+#define KVX_SFR_ES_PL0_WN_WIDTH 1
+#define KVX_SFR_ES_PL0_WN_WFXL_MASK _ULL(0x8000)
+#define KVX_SFR_ES_PL0_WN_WFXL_CLEAR _ULL(0x8000)
+#define KVX_SFR_ES_PL0_WN_WFXL_SET _ULL(0x800000000000)
+
+#define KVX_SFR_ES_PL1_EC_MASK _ULL(0xf) /* Exception Class */
+#define KVX_SFR_ES_PL1_EC_SHIFT 0
+#define KVX_SFR_ES_PL1_EC_WIDTH 4
+#define KVX_SFR_ES_PL1_EC_WFXL_MASK _ULL(0xf)
+#define KVX_SFR_ES_PL1_EC_WFXL_CLEAR _ULL(0xf)
+#define KVX_SFR_ES_PL1_EC_WFXL_SET _ULL(0xf00000000)
+
+#define KVX_SFR_ES_PL1_ED_MASK _ULL(0xfffffffffffffff0) /* Exception Details */
+#define KVX_SFR_ES_PL1_ED_SHIFT 4
+#define KVX_SFR_ES_PL1_ED_WIDTH 60
+#define KVX_SFR_ES_PL1_ED_WFXL_MASK _ULL(0xfffffff0)
+#define KVX_SFR_ES_PL1_ED_WFXL_CLEAR _ULL(0xfffffff0)
+#define KVX_SFR_ES_PL1_ED_WFXL_SET _ULL(0xfffffff000000000)
+#define KVX_SFR_ES_PL1_ED_WFXM_MASK _ULL(0xffffffff00000000)
+#define KVX_SFR_ES_PL1_ED_WFXM_CLEAR _ULL(0xffffffff)
+#define KVX_SFR_ES_PL1_ED_WFXM_SET _ULL(0xffffffff00000000)
+
+#define KVX_SFR_ES_PL1_OAPL_MASK _ULL(0x30) /* Origin Absolute PL */
+#define KVX_SFR_ES_PL1_OAPL_SHIFT 4
+#define KVX_SFR_ES_PL1_OAPL_WIDTH 2
+#define KVX_SFR_ES_PL1_OAPL_WFXL_MASK _ULL(0x30)
+#define KVX_SFR_ES_PL1_OAPL_WFXL_CLEAR _ULL(0x30)
+#define KVX_SFR_ES_PL1_OAPL_WFXL_SET _ULL(0x3000000000)
+
+#define KVX_SFR_ES_PL1_ORPL_MASK _ULL(0xc0) /* Origin Relative PL */
+#define KVX_SFR_ES_PL1_ORPL_SHIFT 6
+#define KVX_SFR_ES_PL1_ORPL_WIDTH 2
+#define KVX_SFR_ES_PL1_ORPL_WFXL_MASK _ULL(0xc0)
+#define KVX_SFR_ES_PL1_ORPL_WFXL_CLEAR _ULL(0xc0)
+#define KVX_SFR_ES_PL1_ORPL_WFXL_SET _ULL(0xc000000000)
+
+#define KVX_SFR_ES_PL1_PTAPL_MASK _ULL(0x300) /* Target Absolute PL */
+#define KVX_SFR_ES_PL1_PTAPL_SHIFT 8
+#define KVX_SFR_ES_PL1_PTAPL_WIDTH 2
+#define KVX_SFR_ES_PL1_PTAPL_WFXL_MASK _ULL(0x300)
+#define KVX_SFR_ES_PL1_PTAPL_WFXL_CLEAR _ULL(0x300)
+#define KVX_SFR_ES_PL1_PTAPL_WFXL_SET _ULL(0x30000000000)
+
+#define KVX_SFR_ES_PL1_PTRPL_MASK _ULL(0xc00) /* Target Relative PL */
+#define KVX_SFR_ES_PL1_PTRPL_SHIFT 10
+#define KVX_SFR_ES_PL1_PTRPL_WIDTH 2
+#define KVX_SFR_ES_PL1_PTRPL_WFXL_MASK _ULL(0xc00)
+#define KVX_SFR_ES_PL1_PTRPL_WFXL_CLEAR _ULL(0xc00)
+#define KVX_SFR_ES_PL1_PTRPL_WFXL_SET _ULL(0xc0000000000)
+
+#define KVX_SFR_ES_PL1_ITN_MASK _ULL(0x1f000) /* InTerrupt Number */
+#define KVX_SFR_ES_PL1_ITN_SHIFT 12
+#define KVX_SFR_ES_PL1_ITN_WIDTH 5
+#define KVX_SFR_ES_PL1_ITN_WFXL_MASK _ULL(0x1f000)
+#define KVX_SFR_ES_PL1_ITN_WFXL_CLEAR _ULL(0x1f000)
+#define KVX_SFR_ES_PL1_ITN_WFXL_SET _ULL(0x1f00000000000)
+
+#define KVX_SFR_ES_PL1_ITL_MASK _ULL(0x60000) /* InTerrupt Level */
+#define KVX_SFR_ES_PL1_ITL_SHIFT 17
+#define KVX_SFR_ES_PL1_ITL_WIDTH 2
+#define KVX_SFR_ES_PL1_ITL_WFXL_MASK _ULL(0x60000)
+#define KVX_SFR_ES_PL1_ITL_WFXL_CLEAR _ULL(0x60000)
+#define KVX_SFR_ES_PL1_ITL_WFXL_SET _ULL(0x6000000000000)
+
+#define KVX_SFR_ES_PL1_ITI_MASK _ULL(0x1ff80000) /* InTerrupt Info */
+#define KVX_SFR_ES_PL1_ITI_SHIFT 19
+#define KVX_SFR_ES_PL1_ITI_WIDTH 10
+#define KVX_SFR_ES_PL1_ITI_WFXL_MASK _ULL(0x1ff80000)
+#define KVX_SFR_ES_PL1_ITI_WFXL_CLEAR _ULL(0x1ff80000)
+#define KVX_SFR_ES_PL1_ITI_WFXL_SET _ULL(0x1ff8000000000000)
+
+#define KVX_SFR_ES_PL1_SN_MASK _ULL(0xfff000) /* Syscall Number */
+#define KVX_SFR_ES_PL1_SN_SHIFT 12
+#define KVX_SFR_ES_PL1_SN_WIDTH 12
+#define KVX_SFR_ES_PL1_SN_WFXL_MASK _ULL(0xfff000)
+#define KVX_SFR_ES_PL1_SN_WFXL_CLEAR _ULL(0xfff000)
+#define KVX_SFR_ES_PL1_SN_WFXL_SET _ULL(0xfff00000000000)
+
+#define KVX_SFR_ES_PL1_HTC_MASK _ULL(0x1f000) /* Hardware Trap Cause */
+#define KVX_SFR_ES_PL1_HTC_SHIFT 12
+#define KVX_SFR_ES_PL1_HTC_WIDTH 5
+#define KVX_SFR_ES_PL1_HTC_WFXL_MASK _ULL(0x1f000)
+#define KVX_SFR_ES_PL1_HTC_WFXL_CLEAR _ULL(0x1f000)
+#define KVX_SFR_ES_PL1_HTC_WFXL_SET _ULL(0x1f00000000000)
+
+#define KVX_SFR_ES_PL1_SFRT_MASK _ULL(0x20000) /* SFR Trap */
+#define KVX_SFR_ES_PL1_SFRT_SHIFT 17
+#define KVX_SFR_ES_PL1_SFRT_WIDTH 1
+#define KVX_SFR_ES_PL1_SFRT_WFXL_MASK _ULL(0x20000)
+#define KVX_SFR_ES_PL1_SFRT_WFXL_CLEAR _ULL(0x20000)
+#define KVX_SFR_ES_PL1_SFRT_WFXL_SET _ULL(0x2000000000000)
+
+#define KVX_SFR_ES_PL1_SFRI_MASK _ULL(0x1c0000) /* SFR Instruction */
+#define KVX_SFR_ES_PL1_SFRI_SHIFT 18
+#define KVX_SFR_ES_PL1_SFRI_WIDTH 3
+#define KVX_SFR_ES_PL1_SFRI_WFXL_MASK _ULL(0x1c0000)
+#define KVX_SFR_ES_PL1_SFRI_WFXL_CLEAR _ULL(0x1c0000)
+#define KVX_SFR_ES_PL1_SFRI_WFXL_SET _ULL(0x1c000000000000)
+
+#define KVX_SFR_ES_PL1_GPRP_MASK _ULL(0x7e00000) /* GPR Pointer */
+#define KVX_SFR_ES_PL1_GPRP_SHIFT 21
+#define KVX_SFR_ES_PL1_GPRP_WIDTH 6
+#define KVX_SFR_ES_PL1_GPRP_WFXL_MASK _ULL(0x7e00000)
+#define KVX_SFR_ES_PL1_GPRP_WFXL_CLEAR _ULL(0x7e00000)
+#define KVX_SFR_ES_PL1_GPRP_WFXL_SET _ULL(0x7e0000000000000)
+
+#define KVX_SFR_ES_PL1_SFRP_MASK _ULL(0xff8000000) /* SFR Pointer */
+#define KVX_SFR_ES_PL1_SFRP_SHIFT 27
+#define KVX_SFR_ES_PL1_SFRP_WIDTH 9
+#define KVX_SFR_ES_PL1_SFRP_WFXL_MASK _ULL(0xf8000000)
+#define KVX_SFR_ES_PL1_SFRP_WFXL_CLEAR _ULL(0xf8000000)
+#define KVX_SFR_ES_PL1_SFRP_WFXL_SET _ULL(0xf800000000000000)
+#define KVX_SFR_ES_PL1_SFRP_WFXM_MASK _ULL(0xf00000000)
+#define KVX_SFR_ES_PL1_SFRP_WFXM_CLEAR _ULL(0xf)
+#define KVX_SFR_ES_PL1_SFRP_WFXM_SET _ULL(0xf00000000)
+
+#define KVX_SFR_ES_PL1_DHT_MASK _ULL(0x1000000000) /* Disabled Hardware Trap */
+#define KVX_SFR_ES_PL1_DHT_SHIFT 36
+#define KVX_SFR_ES_PL1_DHT_WIDTH 1
+#define KVX_SFR_ES_PL1_DHT_WFXM_MASK _ULL(0x1000000000)
+#define KVX_SFR_ES_PL1_DHT_WFXM_CLEAR _ULL(0x10)
+#define KVX_SFR_ES_PL1_DHT_WFXM_SET _ULL(0x1000000000)
+
+#define KVX_SFR_ES_PL1_RWX_MASK _ULL(0x38000000000) /* Read Write Execute */
+#define KVX_SFR_ES_PL1_RWX_SHIFT 39
+#define KVX_SFR_ES_PL1_RWX_WIDTH 3
+#define KVX_SFR_ES_PL1_RWX_WFXM_MASK _ULL(0x38000000000)
+#define KVX_SFR_ES_PL1_RWX_WFXM_CLEAR _ULL(0x380)
+#define KVX_SFR_ES_PL1_RWX_WFXM_SET _ULL(0x38000000000)
+
+#define KVX_SFR_ES_PL1_NTA_MASK _ULL(0x40000000000) /* Non-Trapping Access */
+#define KVX_SFR_ES_PL1_NTA_SHIFT 42
+#define KVX_SFR_ES_PL1_NTA_WIDTH 1
+#define KVX_SFR_ES_PL1_NTA_WFXM_MASK _ULL(0x40000000000)
+#define KVX_SFR_ES_PL1_NTA_WFXM_CLEAR _ULL(0x400)
+#define KVX_SFR_ES_PL1_NTA_WFXM_SET _ULL(0x40000000000)
+
+#define KVX_SFR_ES_PL1_UCA_MASK _ULL(0x80000000000) /* Un-Cached Access */
+#define KVX_SFR_ES_PL1_UCA_SHIFT 43
+#define KVX_SFR_ES_PL1_UCA_WIDTH 1
+#define KVX_SFR_ES_PL1_UCA_WFXM_MASK _ULL(0x80000000000)
+#define KVX_SFR_ES_PL1_UCA_WFXM_CLEAR _ULL(0x800)
+#define KVX_SFR_ES_PL1_UCA_WFXM_SET _ULL(0x80000000000)
+
+#define KVX_SFR_ES_PL1_AS_MASK _ULL(0x3f00000000000) /* Access Size */
+#define KVX_SFR_ES_PL1_AS_SHIFT 44
+#define KVX_SFR_ES_PL1_AS_WIDTH 6
+#define KVX_SFR_ES_PL1_AS_WFXM_MASK _ULL(0x3f00000000000)
+#define KVX_SFR_ES_PL1_AS_WFXM_CLEAR _ULL(0x3f000)
+#define KVX_SFR_ES_PL1_AS_WFXM_SET _ULL(0x3f00000000000)
+
+#define KVX_SFR_ES_PL1_BS_MASK _ULL(0x3c000000000000) /* Bundle Size */
+#define KVX_SFR_ES_PL1_BS_SHIFT 50
+#define KVX_SFR_ES_PL1_BS_WIDTH 4
+#define KVX_SFR_ES_PL1_BS_WFXM_MASK _ULL(0x3c000000000000)
+#define KVX_SFR_ES_PL1_BS_WFXM_CLEAR _ULL(0x3c0000)
+#define KVX_SFR_ES_PL1_BS_WFXM_SET _ULL(0x3c000000000000)
+
+#define KVX_SFR_ES_PL1_DRI_MASK _ULL(0xfc0000000000000) /* Data Register Index */
+#define KVX_SFR_ES_PL1_DRI_SHIFT 54
+#define KVX_SFR_ES_PL1_DRI_WIDTH 6
+#define KVX_SFR_ES_PL1_DRI_WFXM_MASK _ULL(0xfc0000000000000)
+#define KVX_SFR_ES_PL1_DRI_WFXM_CLEAR _ULL(0xfc00000)
+#define KVX_SFR_ES_PL1_DRI_WFXM_SET _ULL(0xfc0000000000000)
+
+#define KVX_SFR_ES_PL1_PIC_MASK _ULL(0xf000000000000000) /* Privileged Instruction Code */
+#define KVX_SFR_ES_PL1_PIC_SHIFT 60
+#define KVX_SFR_ES_PL1_PIC_WIDTH 4
+#define KVX_SFR_ES_PL1_PIC_WFXM_MASK _ULL(0xf000000000000000)
+#define KVX_SFR_ES_PL1_PIC_WFXM_CLEAR _ULL(0xf0000000)
+#define KVX_SFR_ES_PL1_PIC_WFXM_SET _ULL(0xf000000000000000)
+
+#define KVX_SFR_ES_PL1_DC_MASK _ULL(0x3000) /* Debug Cause */
+#define KVX_SFR_ES_PL1_DC_SHIFT 12
+#define KVX_SFR_ES_PL1_DC_WIDTH 2
+#define KVX_SFR_ES_PL1_DC_WFXL_MASK _ULL(0x3000)
+#define KVX_SFR_ES_PL1_DC_WFXL_CLEAR _ULL(0x3000)
+#define KVX_SFR_ES_PL1_DC_WFXL_SET _ULL(0x300000000000)
+
+#define KVX_SFR_ES_PL1_BN_MASK _ULL(0x4000) /* Breakpoint Number */
+#define KVX_SFR_ES_PL1_BN_SHIFT 14
+#define KVX_SFR_ES_PL1_BN_WIDTH 1
+#define KVX_SFR_ES_PL1_BN_WFXL_MASK _ULL(0x4000)
+#define KVX_SFR_ES_PL1_BN_WFXL_CLEAR _ULL(0x4000)
+#define KVX_SFR_ES_PL1_BN_WFXL_SET _ULL(0x400000000000)
+
+#define KVX_SFR_ES_PL1_WN_MASK _ULL(0x8000) /* Watchpoint Number */
+#define KVX_SFR_ES_PL1_WN_SHIFT 15
+#define KVX_SFR_ES_PL1_WN_WIDTH 1
+#define KVX_SFR_ES_PL1_WN_WFXL_MASK _ULL(0x8000)
+#define KVX_SFR_ES_PL1_WN_WFXL_CLEAR _ULL(0x8000)
+#define KVX_SFR_ES_PL1_WN_WFXL_SET _ULL(0x800000000000)
+
+#define KVX_SFR_ES_PL2_EC_MASK _ULL(0xf) /* Exception Class */
+#define KVX_SFR_ES_PL2_EC_SHIFT 0
+#define KVX_SFR_ES_PL2_EC_WIDTH 4
+#define KVX_SFR_ES_PL2_EC_WFXL_MASK _ULL(0xf)
+#define KVX_SFR_ES_PL2_EC_WFXL_CLEAR _ULL(0xf)
+#define KVX_SFR_ES_PL2_EC_WFXL_SET _ULL(0xf00000000)
+
+#define KVX_SFR_ES_PL2_ED_MASK _ULL(0xfffffffffffffff0) /* Exception Details */
+#define KVX_SFR_ES_PL2_ED_SHIFT 4
+#define KVX_SFR_ES_PL2_ED_WIDTH 60
+#define KVX_SFR_ES_PL2_ED_WFXL_MASK _ULL(0xfffffff0)
+#define KVX_SFR_ES_PL2_ED_WFXL_CLEAR _ULL(0xfffffff0)
+#define KVX_SFR_ES_PL2_ED_WFXL_SET _ULL(0xfffffff000000000)
+#define KVX_SFR_ES_PL2_ED_WFXM_MASK _ULL(0xffffffff00000000)
+#define KVX_SFR_ES_PL2_ED_WFXM_CLEAR _ULL(0xffffffff)
+#define KVX_SFR_ES_PL2_ED_WFXM_SET _ULL(0xffffffff00000000)
+
+#define KVX_SFR_ES_PL2_OAPL_MASK _ULL(0x30) /* Origin Absolute PL */
+#define KVX_SFR_ES_PL2_OAPL_SHIFT 4
+#define KVX_SFR_ES_PL2_OAPL_WIDTH 2
+#define KVX_SFR_ES_PL2_OAPL_WFXL_MASK _ULL(0x30)
+#define KVX_SFR_ES_PL2_OAPL_WFXL_CLEAR _ULL(0x30)
+#define KVX_SFR_ES_PL2_OAPL_WFXL_SET _ULL(0x3000000000)
+
+#define KVX_SFR_ES_PL2_ORPL_MASK _ULL(0xc0) /* Origin Relative PL */
+#define KVX_SFR_ES_PL2_ORPL_SHIFT 6
+#define KVX_SFR_ES_PL2_ORPL_WIDTH 2
+#define KVX_SFR_ES_PL2_ORPL_WFXL_MASK _ULL(0xc0)
+#define KVX_SFR_ES_PL2_ORPL_WFXL_CLEAR _ULL(0xc0)
+#define KVX_SFR_ES_PL2_ORPL_WFXL_SET _ULL(0xc000000000)
+
+#define KVX_SFR_ES_PL2_PTAPL_MASK _ULL(0x300) /* Target Absolute PL */
+#define KVX_SFR_ES_PL2_PTAPL_SHIFT 8
+#define KVX_SFR_ES_PL2_PTAPL_WIDTH 2
+#define KVX_SFR_ES_PL2_PTAPL_WFXL_MASK _ULL(0x300)
+#define KVX_SFR_ES_PL2_PTAPL_WFXL_CLEAR _ULL(0x300)
+#define KVX_SFR_ES_PL2_PTAPL_WFXL_SET _ULL(0x30000000000)
+
+#define KVX_SFR_ES_PL2_PTRPL_MASK _ULL(0xc00) /* Target Relative PL */
+#define KVX_SFR_ES_PL2_PTRPL_SHIFT 10
+#define KVX_SFR_ES_PL2_PTRPL_WIDTH 2
+#define KVX_SFR_ES_PL2_PTRPL_WFXL_MASK _ULL(0xc00)
+#define KVX_SFR_ES_PL2_PTRPL_WFXL_CLEAR _ULL(0xc00)
+#define KVX_SFR_ES_PL2_PTRPL_WFXL_SET _ULL(0xc0000000000)
+
+#define KVX_SFR_ES_PL2_ITN_MASK _ULL(0x1f000) /* InTerrupt Number */
+#define KVX_SFR_ES_PL2_ITN_SHIFT 12
+#define KVX_SFR_ES_PL2_ITN_WIDTH 5
+#define KVX_SFR_ES_PL2_ITN_WFXL_MASK _ULL(0x1f000)
+#define KVX_SFR_ES_PL2_ITN_WFXL_CLEAR _ULL(0x1f000)
+#define KVX_SFR_ES_PL2_ITN_WFXL_SET _ULL(0x1f00000000000)
+
+#define KVX_SFR_ES_PL2_ITL_MASK _ULL(0x60000) /* InTerrupt Level */
+#define KVX_SFR_ES_PL2_ITL_SHIFT 17
+#define KVX_SFR_ES_PL2_ITL_WIDTH 2
+#define KVX_SFR_ES_PL2_ITL_WFXL_MASK _ULL(0x60000)
+#define KVX_SFR_ES_PL2_ITL_WFXL_CLEAR _ULL(0x60000)
+#define KVX_SFR_ES_PL2_ITL_WFXL_SET _ULL(0x6000000000000)
+
+#define KVX_SFR_ES_PL2_ITI_MASK _ULL(0x1ff80000) /* InTerrupt Info */
+#define KVX_SFR_ES_PL2_ITI_SHIFT 19
+#define KVX_SFR_ES_PL2_ITI_WIDTH 10
+#define KVX_SFR_ES_PL2_ITI_WFXL_MASK _ULL(0x1ff80000)
+#define KVX_SFR_ES_PL2_ITI_WFXL_CLEAR _ULL(0x1ff80000)
+#define KVX_SFR_ES_PL2_ITI_WFXL_SET _ULL(0x1ff8000000000000)
+
+#define KVX_SFR_ES_PL2_SN_MASK _ULL(0xfff000) /* Syscall Number */
+#define KVX_SFR_ES_PL2_SN_SHIFT 12
+#define KVX_SFR_ES_PL2_SN_WIDTH 12
+#define KVX_SFR_ES_PL2_SN_WFXL_MASK _ULL(0xfff000)
+#define KVX_SFR_ES_PL2_SN_WFXL_CLEAR _ULL(0xfff000)
+#define KVX_SFR_ES_PL2_SN_WFXL_SET _ULL(0xfff00000000000)
+
+#define KVX_SFR_ES_PL2_HTC_MASK _ULL(0x1f000) /* Hardware Trap Cause */
+#define KVX_SFR_ES_PL2_HTC_SHIFT 12
+#define KVX_SFR_ES_PL2_HTC_WIDTH 5
+#define KVX_SFR_ES_PL2_HTC_WFXL_MASK _ULL(0x1f000)
+#define KVX_SFR_ES_PL2_HTC_WFXL_CLEAR _ULL(0x1f000)
+#define KVX_SFR_ES_PL2_HTC_WFXL_SET _ULL(0x1f00000000000)
+
+#define KVX_SFR_ES_PL2_SFRT_MASK _ULL(0x20000) /* SFR Trap */
+#define KVX_SFR_ES_PL2_SFRT_SHIFT 17
+#define KVX_SFR_ES_PL2_SFRT_WIDTH 1
+#define KVX_SFR_ES_PL2_SFRT_WFXL_MASK _ULL(0x20000)
+#define KVX_SFR_ES_PL2_SFRT_WFXL_CLEAR _ULL(0x20000)
+#define KVX_SFR_ES_PL2_SFRT_WFXL_SET _ULL(0x2000000000000)
+
+#define KVX_SFR_ES_PL2_SFRI_MASK _ULL(0x1c0000) /* SFR Instruction */
+#define KVX_SFR_ES_PL2_SFRI_SHIFT 18
+#define KVX_SFR_ES_PL2_SFRI_WIDTH 3
+#define KVX_SFR_ES_PL2_SFRI_WFXL_MASK _ULL(0x1c0000)
+#define KVX_SFR_ES_PL2_SFRI_WFXL_CLEAR _ULL(0x1c0000)
+#define KVX_SFR_ES_PL2_SFRI_WFXL_SET _ULL(0x1c000000000000)
+
+#define KVX_SFR_ES_PL2_GPRP_MASK _ULL(0x7e00000) /* GPR Pointer */
+#define KVX_SFR_ES_PL2_GPRP_SHIFT 21
+#define KVX_SFR_ES_PL2_GPRP_WIDTH 6
+#define KVX_SFR_ES_PL2_GPRP_WFXL_MASK _ULL(0x7e00000)
+#define KVX_SFR_ES_PL2_GPRP_WFXL_CLEAR _ULL(0x7e00000)
+#define KVX_SFR_ES_PL2_GPRP_WFXL_SET _ULL(0x7e0000000000000)
+
+#define KVX_SFR_ES_PL2_SFRP_MASK _ULL(0xff8000000) /* SFR Pointer */
+#define KVX_SFR_ES_PL2_SFRP_SHIFT 27
+#define KVX_SFR_ES_PL2_SFRP_WIDTH 9
+#define KVX_SFR_ES_PL2_SFRP_WFXL_MASK _ULL(0xf8000000)
+#define KVX_SFR_ES_PL2_SFRP_WFXL_CLEAR _ULL(0xf8000000)
+#define KVX_SFR_ES_PL2_SFRP_WFXL_SET _ULL(0xf800000000000000)
+#define KVX_SFR_ES_PL2_SFRP_WFXM_MASK _ULL(0xf00000000)
+#define KVX_SFR_ES_PL2_SFRP_WFXM_CLEAR _ULL(0xf)
+#define KVX_SFR_ES_PL2_SFRP_WFXM_SET _ULL(0xf00000000)
+
+#define KVX_SFR_ES_PL2_DHT_MASK _ULL(0x1000000000) /* Disabled Hardware Trap */
+#define KVX_SFR_ES_PL2_DHT_SHIFT 36
+#define KVX_SFR_ES_PL2_DHT_WIDTH 1
+#define KVX_SFR_ES_PL2_DHT_WFXM_MASK _ULL(0x1000000000)
+#define KVX_SFR_ES_PL2_DHT_WFXM_CLEAR _ULL(0x10)
+#define KVX_SFR_ES_PL2_DHT_WFXM_SET _ULL(0x1000000000)
+
+#define KVX_SFR_ES_PL2_RWX_MASK _ULL(0x38000000000) /* Read Write Execute */
+#define KVX_SFR_ES_PL2_RWX_SHIFT 39
+#define KVX_SFR_ES_PL2_RWX_WIDTH 3
+#define KVX_SFR_ES_PL2_RWX_WFXM_MASK _ULL(0x38000000000)
+#define KVX_SFR_ES_PL2_RWX_WFXM_CLEAR _ULL(0x380)
+#define KVX_SFR_ES_PL2_RWX_WFXM_SET _ULL(0x38000000000)
+
+#define KVX_SFR_ES_PL2_NTA_MASK _ULL(0x40000000000) /* Non-Trapping Access */
+#define KVX_SFR_ES_PL2_NTA_SHIFT 42
+#define KVX_SFR_ES_PL2_NTA_WIDTH 1
+#define KVX_SFR_ES_PL2_NTA_WFXM_MASK _ULL(0x40000000000)
+#define KVX_SFR_ES_PL2_NTA_WFXM_CLEAR _ULL(0x400)
+#define KVX_SFR_ES_PL2_NTA_WFXM_SET _ULL(0x40000000000)
+
+#define KVX_SFR_ES_PL2_UCA_MASK _ULL(0x80000000000) /* Un-Cached Access */
+#define KVX_SFR_ES_PL2_UCA_SHIFT 43
+#define KVX_SFR_ES_PL2_UCA_WIDTH 1
+#define KVX_SFR_ES_PL2_UCA_WFXM_MASK _ULL(0x80000000000)
+#define KVX_SFR_ES_PL2_UCA_WFXM_CLEAR _ULL(0x800)
+#define KVX_SFR_ES_PL2_UCA_WFXM_SET _ULL(0x80000000000)
+
+#define KVX_SFR_ES_PL2_AS_MASK _ULL(0x3f00000000000) /* Access Size */
+#define KVX_SFR_ES_PL2_AS_SHIFT 44
+#define KVX_SFR_ES_PL2_AS_WIDTH 6
+#define KVX_SFR_ES_PL2_AS_WFXM_MASK _ULL(0x3f00000000000)
+#define KVX_SFR_ES_PL2_AS_WFXM_CLEAR _ULL(0x3f000)
+#define KVX_SFR_ES_PL2_AS_WFXM_SET _ULL(0x3f00000000000)
+
+#define KVX_SFR_ES_PL2_BS_MASK _ULL(0x3c000000000000) /* Bundle Size */
+#define KVX_SFR_ES_PL2_BS_SHIFT 50
+#define KVX_SFR_ES_PL2_BS_WIDTH 4
+#define KVX_SFR_ES_PL2_BS_WFXM_MASK _ULL(0x3c000000000000)
+#define KVX_SFR_ES_PL2_BS_WFXM_CLEAR _ULL(0x3c0000)
+#define KVX_SFR_ES_PL2_BS_WFXM_SET _ULL(0x3c000000000000)
+
+#define KVX_SFR_ES_PL2_DRI_MASK _ULL(0xfc0000000000000) /* Data Register Index */
+#define KVX_SFR_ES_PL2_DRI_SHIFT 54
+#define KVX_SFR_ES_PL2_DRI_WIDTH 6
+#define KVX_SFR_ES_PL2_DRI_WFXM_MASK _ULL(0xfc0000000000000)
+#define KVX_SFR_ES_PL2_DRI_WFXM_CLEAR _ULL(0xfc00000)
+#define KVX_SFR_ES_PL2_DRI_WFXM_SET _ULL(0xfc0000000000000)
+
+#define KVX_SFR_ES_PL2_PIC_MASK _ULL(0xf000000000000000) /* Privileged Instruction Code */
+#define KVX_SFR_ES_PL2_PIC_SHIFT 60
+#define KVX_SFR_ES_PL2_PIC_WIDTH 4
+#define KVX_SFR_ES_PL2_PIC_WFXM_MASK _ULL(0xf000000000000000)
+#define KVX_SFR_ES_PL2_PIC_WFXM_CLEAR _ULL(0xf0000000)
+#define KVX_SFR_ES_PL2_PIC_WFXM_SET _ULL(0xf000000000000000)
+
+#define KVX_SFR_ES_PL2_DC_MASK _ULL(0x3000) /* Debug Cause */
+#define KVX_SFR_ES_PL2_DC_SHIFT 12
+#define KVX_SFR_ES_PL2_DC_WIDTH 2
+#define KVX_SFR_ES_PL2_DC_WFXL_MASK _ULL(0x3000)
+#define KVX_SFR_ES_PL2_DC_WFXL_CLEAR _ULL(0x3000)
+#define KVX_SFR_ES_PL2_DC_WFXL_SET _ULL(0x300000000000)
+
+#define KVX_SFR_ES_PL2_BN_MASK _ULL(0x4000) /* Breakpoint Number */
+#define KVX_SFR_ES_PL2_BN_SHIFT 14
+#define KVX_SFR_ES_PL2_BN_WIDTH 1
+#define KVX_SFR_ES_PL2_BN_WFXL_MASK _ULL(0x4000)
+#define KVX_SFR_ES_PL2_BN_WFXL_CLEAR _ULL(0x4000)
+#define KVX_SFR_ES_PL2_BN_WFXL_SET _ULL(0x400000000000)
+
+#define KVX_SFR_ES_PL2_WN_MASK _ULL(0x8000) /* Watchpoint Number */
+#define KVX_SFR_ES_PL2_WN_SHIFT 15
+#define KVX_SFR_ES_PL2_WN_WIDTH 1
+#define KVX_SFR_ES_PL2_WN_WFXL_MASK _ULL(0x8000)
+#define KVX_SFR_ES_PL2_WN_WFXL_CLEAR _ULL(0x8000)
+#define KVX_SFR_ES_PL2_WN_WFXL_SET _ULL(0x800000000000)
+
+#define KVX_SFR_ES_PL3_EC_MASK _ULL(0xf) /* Exception Class */
+#define KVX_SFR_ES_PL3_EC_SHIFT 0
+#define KVX_SFR_ES_PL3_EC_WIDTH 4
+#define KVX_SFR_ES_PL3_EC_WFXL_MASK _ULL(0xf)
+#define KVX_SFR_ES_PL3_EC_WFXL_CLEAR _ULL(0xf)
+#define KVX_SFR_ES_PL3_EC_WFXL_SET _ULL(0xf00000000)
+
+#define KVX_SFR_ES_PL3_ED_MASK _ULL(0xfffffffffffffff0) /* Exception Details */
+#define KVX_SFR_ES_PL3_ED_SHIFT 4
+#define KVX_SFR_ES_PL3_ED_WIDTH 60
+#define KVX_SFR_ES_PL3_ED_WFXL_MASK _ULL(0xfffffff0)
+#define KVX_SFR_ES_PL3_ED_WFXL_CLEAR _ULL(0xfffffff0)
+#define KVX_SFR_ES_PL3_ED_WFXL_SET _ULL(0xfffffff000000000)
+#define KVX_SFR_ES_PL3_ED_WFXM_MASK _ULL(0xffffffff00000000)
+#define KVX_SFR_ES_PL3_ED_WFXM_CLEAR _ULL(0xffffffff)
+#define KVX_SFR_ES_PL3_ED_WFXM_SET _ULL(0xffffffff00000000)
+
+#define KVX_SFR_ES_PL3_OAPL_MASK _ULL(0x30) /* Origin Absolute PL */
+#define KVX_SFR_ES_PL3_OAPL_SHIFT 4
+#define KVX_SFR_ES_PL3_OAPL_WIDTH 2
+#define KVX_SFR_ES_PL3_OAPL_WFXL_MASK _ULL(0x30)
+#define KVX_SFR_ES_PL3_OAPL_WFXL_CLEAR _ULL(0x30)
+#define KVX_SFR_ES_PL3_OAPL_WFXL_SET _ULL(0x3000000000)
+
+#define KVX_SFR_ES_PL3_ORPL_MASK _ULL(0xc0) /* Origin Relative PL */
+#define KVX_SFR_ES_PL3_ORPL_SHIFT 6
+#define KVX_SFR_ES_PL3_ORPL_WIDTH 2
+#define KVX_SFR_ES_PL3_ORPL_WFXL_MASK _ULL(0xc0)
+#define KVX_SFR_ES_PL3_ORPL_WFXL_CLEAR _ULL(0xc0)
+#define KVX_SFR_ES_PL3_ORPL_WFXL_SET _ULL(0xc000000000)
+
+#define KVX_SFR_ES_PL3_PTAPL_MASK _ULL(0x300) /* Target Absolute PL */
+#define KVX_SFR_ES_PL3_PTAPL_SHIFT 8
+#define KVX_SFR_ES_PL3_PTAPL_WIDTH 2
+#define KVX_SFR_ES_PL3_PTAPL_WFXL_MASK _ULL(0x300)
+#define KVX_SFR_ES_PL3_PTAPL_WFXL_CLEAR _ULL(0x300)
+#define KVX_SFR_ES_PL3_PTAPL_WFXL_SET _ULL(0x30000000000)
+
+#define KVX_SFR_ES_PL3_PTRPL_MASK _ULL(0xc00) /* Target Relative PL */
+#define KVX_SFR_ES_PL3_PTRPL_SHIFT 10
+#define KVX_SFR_ES_PL3_PTRPL_WIDTH 2
+#define KVX_SFR_ES_PL3_PTRPL_WFXL_MASK _ULL(0xc00)
+#define KVX_SFR_ES_PL3_PTRPL_WFXL_CLEAR _ULL(0xc00)
+#define KVX_SFR_ES_PL3_PTRPL_WFXL_SET _ULL(0xc0000000000)
+
+#define KVX_SFR_ES_PL3_ITN_MASK _ULL(0x1f000) /* InTerrupt Number */
+#define KVX_SFR_ES_PL3_ITN_SHIFT 12
+#define KVX_SFR_ES_PL3_ITN_WIDTH 5
+#define KVX_SFR_ES_PL3_ITN_WFXL_MASK _ULL(0x1f000)
+#define KVX_SFR_ES_PL3_ITN_WFXL_CLEAR _ULL(0x1f000)
+#define KVX_SFR_ES_PL3_ITN_WFXL_SET _ULL(0x1f00000000000)
+
+#define KVX_SFR_ES_PL3_ITL_MASK _ULL(0x60000) /* InTerrupt Level */
+#define KVX_SFR_ES_PL3_ITL_SHIFT 17
+#define KVX_SFR_ES_PL3_ITL_WIDTH 2
+#define KVX_SFR_ES_PL3_ITL_WFXL_MASK _ULL(0x60000)
+#define KVX_SFR_ES_PL3_ITL_WFXL_CLEAR _ULL(0x60000)
+#define KVX_SFR_ES_PL3_ITL_WFXL_SET _ULL(0x6000000000000)
+
+#define KVX_SFR_ES_PL3_ITI_MASK _ULL(0x1ff80000) /* InTerrupt Info */
+#define KVX_SFR_ES_PL3_ITI_SHIFT 19
+#define KVX_SFR_ES_PL3_ITI_WIDTH 10
+#define KVX_SFR_ES_PL3_ITI_WFXL_MASK _ULL(0x1ff80000)
+#define KVX_SFR_ES_PL3_ITI_WFXL_CLEAR _ULL(0x1ff80000)
+#define KVX_SFR_ES_PL3_ITI_WFXL_SET _ULL(0x1ff8000000000000)
+
+#define KVX_SFR_ES_PL3_SN_MASK _ULL(0xfff000) /* Syscall Number */
+#define KVX_SFR_ES_PL3_SN_SHIFT 12
+#define KVX_SFR_ES_PL3_SN_WIDTH 12
+#define KVX_SFR_ES_PL3_SN_WFXL_MASK _ULL(0xfff000)
+#define KVX_SFR_ES_PL3_SN_WFXL_CLEAR _ULL(0xfff000)
+#define KVX_SFR_ES_PL3_SN_WFXL_SET _ULL(0xfff00000000000)
+
+#define KVX_SFR_ES_PL3_HTC_MASK _ULL(0x1f000) /* Hardware Trap Cause */
+#define KVX_SFR_ES_PL3_HTC_SHIFT 12
+#define KVX_SFR_ES_PL3_HTC_WIDTH 5
+#define KVX_SFR_ES_PL3_HTC_WFXL_MASK _ULL(0x1f000)
+#define KVX_SFR_ES_PL3_HTC_WFXL_CLEAR _ULL(0x1f000)
+#define KVX_SFR_ES_PL3_HTC_WFXL_SET _ULL(0x1f00000000000)
+
+#define KVX_SFR_ES_PL3_SFRT_MASK _ULL(0x20000) /* SFR Trap */
+#define KVX_SFR_ES_PL3_SFRT_SHIFT 17
+#define KVX_SFR_ES_PL3_SFRT_WIDTH 1
+#define KVX_SFR_ES_PL3_SFRT_WFXL_MASK _ULL(0x20000)
+#define KVX_SFR_ES_PL3_SFRT_WFXL_CLEAR _ULL(0x20000)
+#define KVX_SFR_ES_PL3_SFRT_WFXL_SET _ULL(0x2000000000000)
+
+#define KVX_SFR_ES_PL3_SFRI_MASK _ULL(0x1c0000) /* SFR Instruction */
+#define KVX_SFR_ES_PL3_SFRI_SHIFT 18
+#define KVX_SFR_ES_PL3_SFRI_WIDTH 3
+#define KVX_SFR_ES_PL3_SFRI_WFXL_MASK _ULL(0x1c0000)
+#define KVX_SFR_ES_PL3_SFRI_WFXL_CLEAR _ULL(0x1c0000)
+#define KVX_SFR_ES_PL3_SFRI_WFXL_SET _ULL(0x1c000000000000)
+
+#define KVX_SFR_ES_PL3_GPRP_MASK _ULL(0x7e00000) /* GPR Pointer */
+#define KVX_SFR_ES_PL3_GPRP_SHIFT 21
+#define KVX_SFR_ES_PL3_GPRP_WIDTH 6
+#define KVX_SFR_ES_PL3_GPRP_WFXL_MASK _ULL(0x7e00000)
+#define KVX_SFR_ES_PL3_GPRP_WFXL_CLEAR _ULL(0x7e00000)
+#define KVX_SFR_ES_PL3_GPRP_WFXL_SET _ULL(0x7e0000000000000)
+
+#define KVX_SFR_ES_PL3_SFRP_MASK _ULL(0xff8000000) /* SFR Pointer */
+#define KVX_SFR_ES_PL3_SFRP_SHIFT 27
+#define KVX_SFR_ES_PL3_SFRP_WIDTH 9
+#define KVX_SFR_ES_PL3_SFRP_WFXL_MASK _ULL(0xf8000000)
+#define KVX_SFR_ES_PL3_SFRP_WFXL_CLEAR _ULL(0xf8000000)
+#define KVX_SFR_ES_PL3_SFRP_WFXL_SET _ULL(0xf800000000000000)
+#define KVX_SFR_ES_PL3_SFRP_WFXM_MASK _ULL(0xf00000000)
+#define KVX_SFR_ES_PL3_SFRP_WFXM_CLEAR _ULL(0xf)
+#define KVX_SFR_ES_PL3_SFRP_WFXM_SET _ULL(0xf00000000)
+
+#define KVX_SFR_ES_PL3_DHT_MASK _ULL(0x1000000000) /* Disabled Hardware Trap */
+#define KVX_SFR_ES_PL3_DHT_SHIFT 36
+#define KVX_SFR_ES_PL3_DHT_WIDTH 1
+#define KVX_SFR_ES_PL3_DHT_WFXM_MASK _ULL(0x1000000000)
+#define KVX_SFR_ES_PL3_DHT_WFXM_CLEAR _ULL(0x10)
+#define KVX_SFR_ES_PL3_DHT_WFXM_SET _ULL(0x1000000000)
+
+#define KVX_SFR_ES_PL3_RWX_MASK _ULL(0x38000000000) /* Read Write Execute */
+#define KVX_SFR_ES_PL3_RWX_SHIFT 39
+#define KVX_SFR_ES_PL3_RWX_WIDTH 3
+#define KVX_SFR_ES_PL3_RWX_WFXM_MASK _ULL(0x38000000000)
+#define KVX_SFR_ES_PL3_RWX_WFXM_CLEAR _ULL(0x380)
+#define KVX_SFR_ES_PL3_RWX_WFXM_SET _ULL(0x38000000000)
+
+#define KVX_SFR_ES_PL3_NTA_MASK _ULL(0x40000000000) /* Non-Trapping Access */
+#define KVX_SFR_ES_PL3_NTA_SHIFT 42
+#define KVX_SFR_ES_PL3_NTA_WIDTH 1
+#define KVX_SFR_ES_PL3_NTA_WFXM_MASK _ULL(0x40000000000)
+#define KVX_SFR_ES_PL3_NTA_WFXM_CLEAR _ULL(0x400)
+#define KVX_SFR_ES_PL3_NTA_WFXM_SET _ULL(0x40000000000)
+
+#define KVX_SFR_ES_PL3_UCA_MASK _ULL(0x80000000000) /* Un-Cached Access */
+#define KVX_SFR_ES_PL3_UCA_SHIFT 43
+#define KVX_SFR_ES_PL3_UCA_WIDTH 1
+#define KVX_SFR_ES_PL3_UCA_WFXM_MASK _ULL(0x80000000000)
+#define KVX_SFR_ES_PL3_UCA_WFXM_CLEAR _ULL(0x800)
+#define KVX_SFR_ES_PL3_UCA_WFXM_SET _ULL(0x80000000000)
+
+#define KVX_SFR_ES_PL3_AS_MASK _ULL(0x3f00000000000) /* Access Size */
+#define KVX_SFR_ES_PL3_AS_SHIFT 44
+#define KVX_SFR_ES_PL3_AS_WIDTH 6
+#define KVX_SFR_ES_PL3_AS_WFXM_MASK _ULL(0x3f00000000000)
+#define KVX_SFR_ES_PL3_AS_WFXM_CLEAR _ULL(0x3f000)
+#define KVX_SFR_ES_PL3_AS_WFXM_SET _ULL(0x3f00000000000)
+
+#define KVX_SFR_ES_PL3_BS_MASK _ULL(0x3c000000000000) /* Bundle Size */
+#define KVX_SFR_ES_PL3_BS_SHIFT 50
+#define KVX_SFR_ES_PL3_BS_WIDTH 4
+#define KVX_SFR_ES_PL3_BS_WFXM_MASK _ULL(0x3c000000000000)
+#define KVX_SFR_ES_PL3_BS_WFXM_CLEAR _ULL(0x3c0000)
+#define KVX_SFR_ES_PL3_BS_WFXM_SET _ULL(0x3c000000000000)
+
+#define KVX_SFR_ES_PL3_DRI_MASK _ULL(0xfc0000000000000) /* Data Register Index */
+#define KVX_SFR_ES_PL3_DRI_SHIFT 54
+#define KVX_SFR_ES_PL3_DRI_WIDTH 6
+#define KVX_SFR_ES_PL3_DRI_WFXM_MASK _ULL(0xfc0000000000000)
+#define KVX_SFR_ES_PL3_DRI_WFXM_CLEAR _ULL(0xfc00000)
+#define KVX_SFR_ES_PL3_DRI_WFXM_SET _ULL(0xfc0000000000000)
+
+#define KVX_SFR_ES_PL3_PIC_MASK _ULL(0xf000000000000000) /* Privileged Instruction Code */
+#define KVX_SFR_ES_PL3_PIC_SHIFT 60
+#define KVX_SFR_ES_PL3_PIC_WIDTH 4
+#define KVX_SFR_ES_PL3_PIC_WFXM_MASK _ULL(0xf000000000000000)
+#define KVX_SFR_ES_PL3_PIC_WFXM_CLEAR _ULL(0xf0000000)
+#define KVX_SFR_ES_PL3_PIC_WFXM_SET _ULL(0xf000000000000000)
+
+#define KVX_SFR_ES_PL3_DC_MASK _ULL(0x3000) /* Debug Cause */
+#define KVX_SFR_ES_PL3_DC_SHIFT 12
+#define KVX_SFR_ES_PL3_DC_WIDTH 2
+#define KVX_SFR_ES_PL3_DC_WFXL_MASK _ULL(0x3000)
+#define KVX_SFR_ES_PL3_DC_WFXL_CLEAR _ULL(0x3000)
+#define KVX_SFR_ES_PL3_DC_WFXL_SET _ULL(0x300000000000)
+
+#define KVX_SFR_ES_PL3_BN_MASK _ULL(0x4000) /* Breakpoint Number */
+#define KVX_SFR_ES_PL3_BN_SHIFT 14
+#define KVX_SFR_ES_PL3_BN_WIDTH 1
+#define KVX_SFR_ES_PL3_BN_WFXL_MASK _ULL(0x4000)
+#define KVX_SFR_ES_PL3_BN_WFXL_CLEAR _ULL(0x4000)
+#define KVX_SFR_ES_PL3_BN_WFXL_SET _ULL(0x400000000000)
+
+#define KVX_SFR_ES_PL3_WN_MASK _ULL(0x8000) /* Watchpoint Number */
+#define KVX_SFR_ES_PL3_WN_SHIFT 15
+#define KVX_SFR_ES_PL3_WN_WIDTH 1
+#define KVX_SFR_ES_PL3_WN_WFXL_MASK _ULL(0x8000)
+#define KVX_SFR_ES_PL3_WN_WFXL_CLEAR _ULL(0x8000)
+#define KVX_SFR_ES_PL3_WN_WFXL_SET _ULL(0x800000000000)
+
+#define KVX_SFR_TCR_T0CE_MASK _ULL(0x10000) /* Timer 0 Count Enable */
+#define KVX_SFR_TCR_T0CE_SHIFT 16
+#define KVX_SFR_TCR_T0CE_WIDTH 1
+#define KVX_SFR_TCR_T0CE_WFXL_MASK _ULL(0x10000)
+#define KVX_SFR_TCR_T0CE_WFXL_CLEAR _ULL(0x10000)
+#define KVX_SFR_TCR_T0CE_WFXL_SET _ULL(0x1000000000000)
+
+#define KVX_SFR_TCR_T1CE_MASK _ULL(0x20000) /* Timer 1 Count Enable */
+#define KVX_SFR_TCR_T1CE_SHIFT 17
+#define KVX_SFR_TCR_T1CE_WIDTH 1
+#define KVX_SFR_TCR_T1CE_WFXL_MASK _ULL(0x20000)
+#define KVX_SFR_TCR_T1CE_WFXL_CLEAR _ULL(0x20000)
+#define KVX_SFR_TCR_T1CE_WFXL_SET _ULL(0x2000000000000)
+
+#define KVX_SFR_TCR_T0IE_MASK _ULL(0x40000) /* Timer 0 Interrupt Enable */
+#define KVX_SFR_TCR_T0IE_SHIFT 18
+#define KVX_SFR_TCR_T0IE_WIDTH 1
+#define KVX_SFR_TCR_T0IE_WFXL_MASK _ULL(0x40000)
+#define KVX_SFR_TCR_T0IE_WFXL_CLEAR _ULL(0x40000)
+#define KVX_SFR_TCR_T0IE_WFXL_SET _ULL(0x4000000000000)
+
+#define KVX_SFR_TCR_T1IE_MASK _ULL(0x80000) /* Timer 1 Interrupt Enable */
+#define KVX_SFR_TCR_T1IE_SHIFT 19
+#define KVX_SFR_TCR_T1IE_WIDTH 1
+#define KVX_SFR_TCR_T1IE_WFXL_MASK _ULL(0x80000)
+#define KVX_SFR_TCR_T1IE_WFXL_CLEAR _ULL(0x80000)
+#define KVX_SFR_TCR_T1IE_WFXL_SET _ULL(0x8000000000000)
+
+#define KVX_SFR_TCR_T0ST_MASK _ULL(0x100000) /* Timer 0 Status */
+#define KVX_SFR_TCR_T0ST_SHIFT 20
+#define KVX_SFR_TCR_T0ST_WIDTH 1
+#define KVX_SFR_TCR_T0ST_WFXL_MASK _ULL(0x100000)
+#define KVX_SFR_TCR_T0ST_WFXL_CLEAR _ULL(0x100000)
+#define KVX_SFR_TCR_T0ST_WFXL_SET _ULL(0x10000000000000)
+
+#define KVX_SFR_TCR_T1ST_MASK _ULL(0x200000) /* Timer 1 Status */
+#define KVX_SFR_TCR_T1ST_SHIFT 21
+#define KVX_SFR_TCR_T1ST_WIDTH 1
+#define KVX_SFR_TCR_T1ST_WFXL_MASK _ULL(0x200000)
+#define KVX_SFR_TCR_T1ST_WFXL_CLEAR _ULL(0x200000)
+#define KVX_SFR_TCR_T1ST_WFXL_SET _ULL(0x20000000000000)
+
+#define KVX_SFR_TCR_T0SI_MASK _ULL(0x400000) /* Stop Timer 0 in Idle */
+#define KVX_SFR_TCR_T0SI_SHIFT 22
+#define KVX_SFR_TCR_T0SI_WIDTH 1
+#define KVX_SFR_TCR_T0SI_WFXL_MASK _ULL(0x400000)
+#define KVX_SFR_TCR_T0SI_WFXL_CLEAR _ULL(0x400000)
+#define KVX_SFR_TCR_T0SI_WFXL_SET _ULL(0x40000000000000)
+
+#define KVX_SFR_TCR_T1SI_MASK _ULL(0x800000) /* Stop Timer 1 in Idle */
+#define KVX_SFR_TCR_T1SI_SHIFT 23
+#define KVX_SFR_TCR_T1SI_WIDTH 1
+#define KVX_SFR_TCR_T1SI_WFXL_MASK _ULL(0x800000)
+#define KVX_SFR_TCR_T1SI_WFXL_CLEAR _ULL(0x800000)
+#define KVX_SFR_TCR_T1SI_WFXL_SET _ULL(0x80000000000000)
+
+#define KVX_SFR_TCR_WCE_MASK _ULL(0x1000000) /* Watchdog Counting Enable */
+#define KVX_SFR_TCR_WCE_SHIFT 24
+#define KVX_SFR_TCR_WCE_WIDTH 1
+#define KVX_SFR_TCR_WCE_WFXL_MASK _ULL(0x1000000)
+#define KVX_SFR_TCR_WCE_WFXL_CLEAR _ULL(0x1000000)
+#define KVX_SFR_TCR_WCE_WFXL_SET _ULL(0x100000000000000)
+
+#define KVX_SFR_TCR_WIE_MASK _ULL(0x2000000) /* Watchdog Interrupt Enable */
+#define KVX_SFR_TCR_WIE_SHIFT 25
+#define KVX_SFR_TCR_WIE_WIDTH 1
+#define KVX_SFR_TCR_WIE_WFXL_MASK _ULL(0x2000000)
+#define KVX_SFR_TCR_WIE_WFXL_CLEAR _ULL(0x2000000)
+#define KVX_SFR_TCR_WIE_WFXL_SET _ULL(0x200000000000000)
+
+#define KVX_SFR_TCR_WUI_MASK _ULL(0x4000000) /* Watchdog Underflow Inform */
+#define KVX_SFR_TCR_WUI_SHIFT 26
+#define KVX_SFR_TCR_WUI_WIDTH 1
+#define KVX_SFR_TCR_WUI_WFXL_MASK _ULL(0x4000000)
+#define KVX_SFR_TCR_WUI_WFXL_CLEAR _ULL(0x4000000)
+#define KVX_SFR_TCR_WUI_WFXL_SET _ULL(0x400000000000000)
+
+#define KVX_SFR_TCR_WUS_MASK _ULL(0x8000000) /* Watchdog Underflow Status */
+#define KVX_SFR_TCR_WUS_SHIFT 27
+#define KVX_SFR_TCR_WUS_WIDTH 1
+#define KVX_SFR_TCR_WUS_WFXL_MASK _ULL(0x8000000)
+#define KVX_SFR_TCR_WUS_WFXL_CLEAR _ULL(0x8000000)
+#define KVX_SFR_TCR_WUS_WFXL_SET _ULL(0x800000000000000)
+
+#define KVX_SFR_TCR_WSI_MASK _ULL(0x10000000) /* Watchdog Stop in Idle */
+#define KVX_SFR_TCR_WSI_SHIFT 28
+#define KVX_SFR_TCR_WSI_WIDTH 1
+#define KVX_SFR_TCR_WSI_WFXL_MASK _ULL(0x10000000)
+#define KVX_SFR_TCR_WSI_WFXL_CLEAR _ULL(0x10000000)
+#define KVX_SFR_TCR_WSI_WFXL_SET _ULL(0x1000000000000000)
+
+#define KVX_SFR_PM0_PM0_MASK _ULL(0xffffffffffffffff) /* Performance Monitor 0 */
+#define KVX_SFR_PM0_PM0_SHIFT 0
+#define KVX_SFR_PM0_PM0_WIDTH 64
+#define KVX_SFR_PM0_PM0_WFXL_MASK _ULL(0xffffffff)
+#define KVX_SFR_PM0_PM0_WFXL_CLEAR _ULL(0xffffffff)
+#define KVX_SFR_PM0_PM0_WFXL_SET _ULL(0xffffffff00000000)
+#define KVX_SFR_PM0_PM0_WFXM_MASK _ULL(0xffffffff00000000)
+#define KVX_SFR_PM0_PM0_WFXM_CLEAR _ULL(0xffffffff)
+#define KVX_SFR_PM0_PM0_WFXM_SET _ULL(0xffffffff00000000)
+
+#define KVX_SFR_PM1_PM1_MASK _ULL(0xffffffffffffffff) /* Performance Monitor 1 */
+#define KVX_SFR_PM1_PM1_SHIFT 0
+#define KVX_SFR_PM1_PM1_WIDTH 64
+#define KVX_SFR_PM1_PM1_WFXL_MASK _ULL(0xffffffff)
+#define KVX_SFR_PM1_PM1_WFXL_CLEAR _ULL(0xffffffff)
+#define KVX_SFR_PM1_PM1_WFXL_SET _ULL(0xffffffff00000000)
+#define KVX_SFR_PM1_PM1_WFXM_MASK _ULL(0xffffffff00000000)
+#define KVX_SFR_PM1_PM1_WFXM_CLEAR _ULL(0xffffffff)
+#define KVX_SFR_PM1_PM1_WFXM_SET _ULL(0xffffffff00000000)
+
+#define KVX_SFR_PM2_PM2_MASK _ULL(0xffffffffffffffff) /* Performance Monitor 2 */
+#define KVX_SFR_PM2_PM2_SHIFT 0
+#define KVX_SFR_PM2_PM2_WIDTH 64
+#define KVX_SFR_PM2_PM2_WFXL_MASK _ULL(0xffffffff)
+#define KVX_SFR_PM2_PM2_WFXL_CLEAR _ULL(0xffffffff)
+#define KVX_SFR_PM2_PM2_WFXL_SET _ULL(0xffffffff00000000)
+#define KVX_SFR_PM2_PM2_WFXM_MASK _ULL(0xffffffff00000000)
+#define KVX_SFR_PM2_PM2_WFXM_CLEAR _ULL(0xffffffff)
+#define KVX_SFR_PM2_PM2_WFXM_SET _ULL(0xffffffff00000000)
+
+#define KVX_SFR_PM3_PM3_MASK _ULL(0xffffffffffffffff) /* Performance Monitor 3 */
+#define KVX_SFR_PM3_PM3_SHIFT 0
+#define KVX_SFR_PM3_PM3_WIDTH 64
+#define KVX_SFR_PM3_PM3_WFXL_MASK _ULL(0xffffffff)
+#define KVX_SFR_PM3_PM3_WFXL_CLEAR _ULL(0xffffffff)
+#define KVX_SFR_PM3_PM3_WFXL_SET _ULL(0xffffffff00000000)
+#define KVX_SFR_PM3_PM3_WFXM_MASK _ULL(0xffffffff00000000)
+#define KVX_SFR_PM3_PM3_WFXM_CLEAR _ULL(0xffffffff)
+#define KVX_SFR_PM3_PM3_WFXM_SET _ULL(0xffffffff00000000)
+
+#define KVX_SFR_PMSA_PMSA_MASK _ULL(0xffffffffffffffff) /* Performance Monitor Saved Address */
+#define KVX_SFR_PMSA_PMSA_SHIFT 0
+#define KVX_SFR_PMSA_PMSA_WIDTH 64
+#define KVX_SFR_PMSA_PMSA_WFXL_MASK _ULL(0xffffffff)
+#define KVX_SFR_PMSA_PMSA_WFXL_CLEAR _ULL(0xffffffff)
+#define KVX_SFR_PMSA_PMSA_WFXL_SET _ULL(0xffffffff00000000)
+#define KVX_SFR_PMSA_PMSA_WFXM_MASK _ULL(0xffffffff00000000)
+#define KVX_SFR_PMSA_PMSA_WFXM_CLEAR _ULL(0xffffffff)
+#define KVX_SFR_PMSA_PMSA_WFXM_SET _ULL(0xffffffff00000000)
+
+#define KVX_SFR_T0V_T0V_MASK _ULL(0xffffffffffffffff) /* Timer 0 value */
+#define KVX_SFR_T0V_T0V_SHIFT 0
+#define KVX_SFR_T0V_T0V_WIDTH 64
+#define KVX_SFR_T0V_T0V_WFXL_MASK _ULL(0xffffffff)
+#define KVX_SFR_T0V_T0V_WFXL_CLEAR _ULL(0xffffffff)
+#define KVX_SFR_T0V_T0V_WFXL_SET _ULL(0xffffffff00000000)
+#define KVX_SFR_T0V_T0V_WFXM_MASK _ULL(0xffffffff00000000)
+#define KVX_SFR_T0V_T0V_WFXM_CLEAR _ULL(0xffffffff)
+#define KVX_SFR_T0V_T0V_WFXM_SET _ULL(0xffffffff00000000)
+
+#define KVX_SFR_T1V_T1V_MASK _ULL(0xffffffffffffffff) /* Timer 1 value */
+#define KVX_SFR_T1V_T1V_SHIFT 0
+#define KVX_SFR_T1V_T1V_WIDTH 64
+#define KVX_SFR_T1V_T1V_WFXL_MASK _ULL(0xffffffff)
+#define KVX_SFR_T1V_T1V_WFXL_CLEAR _ULL(0xffffffff)
+#define KVX_SFR_T1V_T1V_WFXL_SET _ULL(0xffffffff00000000)
+#define KVX_SFR_T1V_T1V_WFXM_MASK _ULL(0xffffffff00000000)
+#define KVX_SFR_T1V_T1V_WFXM_CLEAR _ULL(0xffffffff)
+#define KVX_SFR_T1V_T1V_WFXM_SET _ULL(0xffffffff00000000)
+
+#define KVX_SFR_T0R_T0R_MASK _ULL(0xffffffffffffffff) /* Timer 0 reload value */
+#define KVX_SFR_T0R_T0R_SHIFT 0
+#define KVX_SFR_T0R_T0R_WIDTH 64
+#define KVX_SFR_T0R_T0R_WFXL_MASK _ULL(0xffffffff)
+#define KVX_SFR_T0R_T0R_WFXL_CLEAR _ULL(0xffffffff)
+#define KVX_SFR_T0R_T0R_WFXL_SET _ULL(0xffffffff00000000)
+#define KVX_SFR_T0R_T0R_WFXM_MASK _ULL(0xffffffff00000000)
+#define KVX_SFR_T0R_T0R_WFXM_CLEAR _ULL(0xffffffff)
+#define KVX_SFR_T0R_T0R_WFXM_SET _ULL(0xffffffff00000000)
+
+#define KVX_SFR_T1R_T1R_MASK _ULL(0xffffffffffffffff) /* Timer 1 reload value */
+#define KVX_SFR_T1R_T1R_SHIFT 0
+#define KVX_SFR_T1R_T1R_WIDTH 64
+#define KVX_SFR_T1R_T1R_WFXL_MASK _ULL(0xffffffff)
+#define KVX_SFR_T1R_T1R_WFXL_CLEAR _ULL(0xffffffff)
+#define KVX_SFR_T1R_T1R_WFXL_SET _ULL(0xffffffff00000000)
+#define KVX_SFR_T1R_T1R_WFXM_MASK _ULL(0xffffffff00000000)
+#define KVX_SFR_T1R_T1R_WFXM_CLEAR _ULL(0xffffffff)
+#define KVX_SFR_T1R_T1R_WFXM_SET _ULL(0xffffffff00000000)
+
+#define KVX_SFR_WDV_WDV_MASK _ULL(0xffffffffffffffff) /* Watchdog Value */
+#define KVX_SFR_WDV_WDV_SHIFT 0
+#define KVX_SFR_WDV_WDV_WIDTH 64
+#define KVX_SFR_WDV_WDV_WFXL_MASK _ULL(0xffffffff)
+#define KVX_SFR_WDV_WDV_WFXL_CLEAR _ULL(0xffffffff)
+#define KVX_SFR_WDV_WDV_WFXL_SET _ULL(0xffffffff00000000)
+#define KVX_SFR_WDV_WDV_WFXM_MASK _ULL(0xffffffff00000000)
+#define KVX_SFR_WDV_WDV_WFXM_CLEAR _ULL(0xffffffff)
+#define KVX_SFR_WDV_WDV_WFXM_SET _ULL(0xffffffff00000000)
+
+#define KVX_SFR_WDR_WDR_MASK _ULL(0xffffffffffffffff) /* Watchdog Reload Value */
+#define KVX_SFR_WDR_WDR_SHIFT 0
+#define KVX_SFR_WDR_WDR_WIDTH 64
+#define KVX_SFR_WDR_WDR_WFXL_MASK _ULL(0xffffffff)
+#define KVX_SFR_WDR_WDR_WFXL_CLEAR _ULL(0xffffffff)
+#define KVX_SFR_WDR_WDR_WFXL_SET _ULL(0xffffffff00000000)
+#define KVX_SFR_WDR_WDR_WFXM_MASK _ULL(0xffffffff00000000)
+#define KVX_SFR_WDR_WDR_WFXM_CLEAR _ULL(0xffffffff)
+#define KVX_SFR_WDR_WDR_WFXM_SET _ULL(0xffffffff00000000)
+
+#define KVX_SFR_PMC_PM0C_MASK _ULL(0x3f) /* PM0 Configuration */
+#define KVX_SFR_PMC_PM0C_SHIFT 0
+#define KVX_SFR_PMC_PM0C_WIDTH 6
+#define KVX_SFR_PMC_PM0C_WFXL_MASK _ULL(0x3f)
+#define KVX_SFR_PMC_PM0C_WFXL_CLEAR _ULL(0x3f)
+#define KVX_SFR_PMC_PM0C_WFXL_SET _ULL(0x3f00000000)
+
+#define KVX_SFR_PMC_PM1C_MASK _ULL(0x1f80) /* PM1 Configuration */
+#define KVX_SFR_PMC_PM1C_SHIFT 7
+#define KVX_SFR_PMC_PM1C_WIDTH 6
+#define KVX_SFR_PMC_PM1C_WFXL_MASK _ULL(0x1f80)
+#define KVX_SFR_PMC_PM1C_WFXL_CLEAR _ULL(0x1f80)
+#define KVX_SFR_PMC_PM1C_WFXL_SET _ULL(0x1f8000000000)
+
+#define KVX_SFR_PMC_PM2C_MASK _ULL(0xfc000) /* PM2 Configuration */
+#define KVX_SFR_PMC_PM2C_SHIFT 14
+#define KVX_SFR_PMC_PM2C_WIDTH 6
+#define KVX_SFR_PMC_PM2C_WFXL_MASK _ULL(0xfc000)
+#define KVX_SFR_PMC_PM2C_WFXL_CLEAR _ULL(0xfc000)
+#define KVX_SFR_PMC_PM2C_WFXL_SET _ULL(0xfc00000000000)
+
+#define KVX_SFR_PMC_PM3C_MASK _ULL(0x7e00000) /* PM3 Configuration */
+#define KVX_SFR_PMC_PM3C_SHIFT 21
+#define KVX_SFR_PMC_PM3C_WIDTH 6
+#define KVX_SFR_PMC_PM3C_WFXL_MASK _ULL(0x7e00000)
+#define KVX_SFR_PMC_PM3C_WFXL_CLEAR _ULL(0x7e00000)
+#define KVX_SFR_PMC_PM3C_WFXL_SET _ULL(0x7e0000000000000)
+
+#define KVX_SFR_PMC_SAV_MASK _ULL(0x40000000) /* Saved Address Valid */
+#define KVX_SFR_PMC_SAV_SHIFT 30
+#define KVX_SFR_PMC_SAV_WIDTH 1
+#define KVX_SFR_PMC_SAV_WFXL_MASK _ULL(0x40000000)
+#define KVX_SFR_PMC_SAV_WFXL_CLEAR _ULL(0x40000000)
+#define KVX_SFR_PMC_SAV_WFXL_SET _ULL(0x4000000000000000)
+
+#define KVX_SFR_PMC_PM0IE_MASK _ULL(0x100000000) /* PM0 Interrupt Enable */
+#define KVX_SFR_PMC_PM0IE_SHIFT 32
+#define KVX_SFR_PMC_PM0IE_WIDTH 1
+#define KVX_SFR_PMC_PM0IE_WFXM_MASK _ULL(0x100000000)
+#define KVX_SFR_PMC_PM0IE_WFXM_CLEAR _ULL(0x1)
+#define KVX_SFR_PMC_PM0IE_WFXM_SET _ULL(0x100000000)
+
+#define KVX_SFR_PMC_PM1IE_MASK _ULL(0x200000000) /* PM1 Interrupt Enable */
+#define KVX_SFR_PMC_PM1IE_SHIFT 33
+#define KVX_SFR_PMC_PM1IE_WIDTH 1
+#define KVX_SFR_PMC_PM1IE_WFXM_MASK _ULL(0x200000000)
+#define KVX_SFR_PMC_PM1IE_WFXM_CLEAR _ULL(0x2)
+#define KVX_SFR_PMC_PM1IE_WFXM_SET _ULL(0x200000000)
+
+#define KVX_SFR_PMC_PM2IE_MASK _ULL(0x400000000) /* PM2 Interrupt Enable */
+#define KVX_SFR_PMC_PM2IE_SHIFT 34
+#define KVX_SFR_PMC_PM2IE_WIDTH 1
+#define KVX_SFR_PMC_PM2IE_WFXM_MASK _ULL(0x400000000)
+#define KVX_SFR_PMC_PM2IE_WFXM_CLEAR _ULL(0x4)
+#define KVX_SFR_PMC_PM2IE_WFXM_SET _ULL(0x400000000)
+
+#define KVX_SFR_PMC_PM3IE_MASK _ULL(0x800000000) /* PM3 Interrupt Enable */
+#define KVX_SFR_PMC_PM3IE_SHIFT 35
+#define KVX_SFR_PMC_PM3IE_WIDTH 1
+#define KVX_SFR_PMC_PM3IE_WFXM_MASK _ULL(0x800000000)
+#define KVX_SFR_PMC_PM3IE_WFXM_CLEAR _ULL(0x8)
+#define KVX_SFR_PMC_PM3IE_WFXM_SET _ULL(0x800000000)
+
+#define KVX_SFR_PMC_SAT_MASK _ULL(0x3000000000) /* Saved Address Type */
+#define KVX_SFR_PMC_SAT_SHIFT 36
+#define KVX_SFR_PMC_SAT_WIDTH 2
+#define KVX_SFR_PMC_SAT_WFXM_MASK _ULL(0x3000000000)
+#define KVX_SFR_PMC_SAT_WFXM_CLEAR _ULL(0x30)
+#define KVX_SFR_PMC_SAT_WFXM_SET _ULL(0x3000000000)
+
+#define KVX_SFR_PCR_PID_MASK _ULL(0xff) /* Processing Identifier in cluster */
+#define KVX_SFR_PCR_PID_SHIFT 0
+#define KVX_SFR_PCR_PID_WIDTH 8
+#define KVX_SFR_PCR_PID_WFXL_MASK _ULL(0xff)
+#define KVX_SFR_PCR_PID_WFXL_CLEAR _ULL(0xff)
+#define KVX_SFR_PCR_PID_WFXL_SET _ULL(0xff00000000)
+
+#define KVX_SFR_PCR_CID_MASK _ULL(0xff00) /* Cluster Identifier in system */
+#define KVX_SFR_PCR_CID_SHIFT 8
+#define KVX_SFR_PCR_CID_WIDTH 8
+#define KVX_SFR_PCR_CID_WFXL_MASK _ULL(0xff00)
+#define KVX_SFR_PCR_CID_WFXL_CLEAR _ULL(0xff00)
+#define KVX_SFR_PCR_CID_WFXL_SET _ULL(0xff0000000000)
+
+#define KVX_SFR_PCR_MID_MASK _ULL(0xff0000) /* MPPA Identifier */
+#define KVX_SFR_PCR_MID_SHIFT 16
+#define KVX_SFR_PCR_MID_WIDTH 8
+#define KVX_SFR_PCR_MID_WFXL_MASK _ULL(0xff0000)
+#define KVX_SFR_PCR_MID_WFXL_CLEAR _ULL(0xff0000)
+#define KVX_SFR_PCR_MID_WFXL_SET _ULL(0xff000000000000)
+
+#define KVX_SFR_PCR_CAR_MASK _ULL(0xf000000) /* Core Architecture Revision ID */
+#define KVX_SFR_PCR_CAR_SHIFT 24
+#define KVX_SFR_PCR_CAR_WIDTH 4
+#define KVX_SFR_PCR_CAR_WFXL_MASK _ULL(0xf000000)
+#define KVX_SFR_PCR_CAR_WFXL_CLEAR _ULL(0xf000000)
+#define KVX_SFR_PCR_CAR_WFXL_SET _ULL(0xf00000000000000)
+
+#define KVX_SFR_PCR_CMA_MASK _ULL(0xf0000000) /* Core Micro-Architecture Revision ID */
+#define KVX_SFR_PCR_CMA_SHIFT 28
+#define KVX_SFR_PCR_CMA_WIDTH 4
+#define KVX_SFR_PCR_CMA_WFXL_MASK _ULL(0xf0000000)
+#define KVX_SFR_PCR_CMA_WFXL_CLEAR _ULL(0xf0000000)
+#define KVX_SFR_PCR_CMA_WFXL_SET _ULL(0xf000000000000000)
+
+#define KVX_SFR_PCR_SV_MASK _ULL(0xff00000000) /* System-On-Chip Version */
+#define KVX_SFR_PCR_SV_SHIFT 32
+#define KVX_SFR_PCR_SV_WIDTH 8
+#define KVX_SFR_PCR_SV_WFXM_MASK _ULL(0xff00000000)
+#define KVX_SFR_PCR_SV_WFXM_CLEAR _ULL(0xff)
+#define KVX_SFR_PCR_SV_WFXM_SET _ULL(0xff00000000)
+
+#define KVX_SFR_PCR_ST_MASK _ULL(0xf0000000000) /* System-On-Chip Type */
+#define KVX_SFR_PCR_ST_SHIFT 40
+#define KVX_SFR_PCR_ST_WIDTH 4
+#define KVX_SFR_PCR_ST_WFXM_MASK _ULL(0xf0000000000)
+#define KVX_SFR_PCR_ST_WFXM_CLEAR _ULL(0xf00)
+#define KVX_SFR_PCR_ST_WFXM_SET _ULL(0xf0000000000)
+
+#define KVX_SFR_PCR_BM_MASK _ULL(0xff00000000000) /* Boot Mode */
+#define KVX_SFR_PCR_BM_SHIFT 44
+#define KVX_SFR_PCR_BM_WIDTH 8
+#define KVX_SFR_PCR_BM_WFXM_MASK _ULL(0xff00000000000)
+#define KVX_SFR_PCR_BM_WFXM_CLEAR _ULL(0xff000)
+#define KVX_SFR_PCR_BM_WFXM_SET _ULL(0xff00000000000)
+
+#define KVX_SFR_PCR_COE_MASK _ULL(0x10000000000000) /* COprocessor Enable */
+#define KVX_SFR_PCR_COE_SHIFT 52
+#define KVX_SFR_PCR_COE_WIDTH 1
+#define KVX_SFR_PCR_COE_WFXM_MASK _ULL(0x10000000000000)
+#define KVX_SFR_PCR_COE_WFXM_CLEAR _ULL(0x100000)
+#define KVX_SFR_PCR_COE_WFXM_SET _ULL(0x10000000000000)
+
+#define KVX_SFR_PCR_L1CE_MASK _ULL(0x20000000000000) /* L1 cache Coherency Enable */
+#define KVX_SFR_PCR_L1CE_SHIFT 53
+#define KVX_SFR_PCR_L1CE_WIDTH 1
+#define KVX_SFR_PCR_L1CE_WFXM_MASK _ULL(0x20000000000000)
+#define KVX_SFR_PCR_L1CE_WFXM_CLEAR _ULL(0x200000)
+#define KVX_SFR_PCR_L1CE_WFXM_SET _ULL(0x20000000000000)
+
+#define KVX_SFR_PCR_DSEM_MASK _ULL(0x40000000000000) /* Data Simple Ecc exception Mode */
+#define KVX_SFR_PCR_DSEM_SHIFT 54
+#define KVX_SFR_PCR_DSEM_WIDTH 1
+#define KVX_SFR_PCR_DSEM_WFXM_MASK _ULL(0x40000000000000)
+#define KVX_SFR_PCR_DSEM_WFXM_CLEAR _ULL(0x400000)
+#define KVX_SFR_PCR_DSEM_WFXM_SET _ULL(0x40000000000000)
+
+#define KVX_SFR_MMC_ASN_MASK _ULL(0x1ff) /* Address Space Number */
+#define KVX_SFR_MMC_ASN_SHIFT 0
+#define KVX_SFR_MMC_ASN_WIDTH 9
+#define KVX_SFR_MMC_ASN_WFXL_MASK _ULL(0x1ff)
+#define KVX_SFR_MMC_ASN_WFXL_CLEAR _ULL(0x1ff)
+#define KVX_SFR_MMC_ASN_WFXL_SET _ULL(0x1ff00000000)
+
+#define KVX_SFR_MMC_S_MASK _ULL(0x200) /* Speculative */
+#define KVX_SFR_MMC_S_SHIFT 9
+#define KVX_SFR_MMC_S_WIDTH 1
+#define KVX_SFR_MMC_S_WFXL_MASK _ULL(0x200)
+#define KVX_SFR_MMC_S_WFXL_CLEAR _ULL(0x200)
+#define KVX_SFR_MMC_S_WFXL_SET _ULL(0x20000000000)
+
+#define KVX_SFR_MMC_SNE_MASK _ULL(0x4000) /* Speculative NOMAPPING Enable */
+#define KVX_SFR_MMC_SNE_SHIFT 14
+#define KVX_SFR_MMC_SNE_WIDTH 1
+#define KVX_SFR_MMC_SNE_WFXL_MASK _ULL(0x4000)
+#define KVX_SFR_MMC_SNE_WFXL_CLEAR _ULL(0x4000)
+#define KVX_SFR_MMC_SNE_WFXL_SET _ULL(0x400000000000)
+
+#define KVX_SFR_MMC_SPE_MASK _ULL(0x8000) /* Speculative PROTECTION Enable */
+#define KVX_SFR_MMC_SPE_SHIFT 15
+#define KVX_SFR_MMC_SPE_WIDTH 1
+#define KVX_SFR_MMC_SPE_WFXL_MASK _ULL(0x8000)
+#define KVX_SFR_MMC_SPE_WFXL_CLEAR _ULL(0x8000)
+#define KVX_SFR_MMC_SPE_WFXL_SET _ULL(0x800000000000)
+
+#define KVX_SFR_MMC_PTC_MASK _ULL(0x30000) /* Protection Trap Cause */
+#define KVX_SFR_MMC_PTC_SHIFT 16
+#define KVX_SFR_MMC_PTC_WIDTH 2
+#define KVX_SFR_MMC_PTC_WFXL_MASK _ULL(0x30000)
+#define KVX_SFR_MMC_PTC_WFXL_CLEAR _ULL(0x30000)
+#define KVX_SFR_MMC_PTC_WFXL_SET _ULL(0x3000000000000)
+
+#define KVX_SFR_MMC_SW_MASK _ULL(0x3c0000) /* Select Way */
+#define KVX_SFR_MMC_SW_SHIFT 18
+#define KVX_SFR_MMC_SW_WIDTH 4
+#define KVX_SFR_MMC_SW_WFXL_MASK _ULL(0x3c0000)
+#define KVX_SFR_MMC_SW_WFXL_CLEAR _ULL(0x3c0000)
+#define KVX_SFR_MMC_SW_WFXL_SET _ULL(0x3c000000000000)
+
+#define KVX_SFR_MMC_SS_MASK _ULL(0xfc00000) /* Select Set */
+#define KVX_SFR_MMC_SS_SHIFT 22
+#define KVX_SFR_MMC_SS_WIDTH 6
+#define KVX_SFR_MMC_SS_WFXL_MASK _ULL(0xfc00000)
+#define KVX_SFR_MMC_SS_WFXL_CLEAR _ULL(0xfc00000)
+#define KVX_SFR_MMC_SS_WFXL_SET _ULL(0xfc0000000000000)
+
+#define KVX_SFR_MMC_SB_MASK _ULL(0x10000000) /* Select Buffer */
+#define KVX_SFR_MMC_SB_SHIFT 28
+#define KVX_SFR_MMC_SB_WIDTH 1
+#define KVX_SFR_MMC_SB_WFXL_MASK _ULL(0x10000000)
+#define KVX_SFR_MMC_SB_WFXL_CLEAR _ULL(0x10000000)
+#define KVX_SFR_MMC_SB_WFXL_SET _ULL(0x1000000000000000)
+
+#define KVX_SFR_MMC_PAR_MASK _ULL(0x40000000) /* PARity error flag */
+#define KVX_SFR_MMC_PAR_SHIFT 30
+#define KVX_SFR_MMC_PAR_WIDTH 1
+#define KVX_SFR_MMC_PAR_WFXL_MASK _ULL(0x40000000)
+#define KVX_SFR_MMC_PAR_WFXL_CLEAR _ULL(0x40000000)
+#define KVX_SFR_MMC_PAR_WFXL_SET _ULL(0x4000000000000000)
+
+#define KVX_SFR_MMC_E_MASK _ULL(0x80000000) /* Error Flag */
+#define KVX_SFR_MMC_E_SHIFT 31
+#define KVX_SFR_MMC_E_WIDTH 1
+#define KVX_SFR_MMC_E_WFXL_MASK _ULL(0x80000000)
+#define KVX_SFR_MMC_E_WFXL_CLEAR _ULL(0x80000000)
+#define KVX_SFR_MMC_E_WFXL_SET _ULL(0x8000000000000000)
+
+#define KVX_SFR_TEL_ES_MASK _ULL(0x3) /* Entry Status */
+#define KVX_SFR_TEL_ES_SHIFT 0
+#define KVX_SFR_TEL_ES_WIDTH 2
+#define KVX_SFR_TEL_ES_WFXL_MASK _ULL(0x3)
+#define KVX_SFR_TEL_ES_WFXL_CLEAR _ULL(0x3)
+#define KVX_SFR_TEL_ES_WFXL_SET _ULL(0x300000000)
+
+#define KVX_SFR_TEL_CP_MASK _ULL(0xc) /* Cache Policy */
+#define KVX_SFR_TEL_CP_SHIFT 2
+#define KVX_SFR_TEL_CP_WIDTH 2
+#define KVX_SFR_TEL_CP_WFXL_MASK _ULL(0xc)
+#define KVX_SFR_TEL_CP_WFXL_CLEAR _ULL(0xc)
+#define KVX_SFR_TEL_CP_WFXL_SET _ULL(0xc00000000)
+
+#define KVX_SFR_TEL_PA_MASK _ULL(0xf0) /* Protection Attributes */
+#define KVX_SFR_TEL_PA_SHIFT 4
+#define KVX_SFR_TEL_PA_WIDTH 4
+#define KVX_SFR_TEL_PA_WFXL_MASK _ULL(0xf0)
+#define KVX_SFR_TEL_PA_WFXL_CLEAR _ULL(0xf0)
+#define KVX_SFR_TEL_PA_WFXL_SET _ULL(0xf000000000)
+
+#define KVX_SFR_TEL_PS_MASK _ULL(0xc00) /* Page Size */
+#define KVX_SFR_TEL_PS_SHIFT 10
+#define KVX_SFR_TEL_PS_WIDTH 2
+#define KVX_SFR_TEL_PS_WFXL_MASK _ULL(0xc00)
+#define KVX_SFR_TEL_PS_WFXL_CLEAR _ULL(0xc00)
+#define KVX_SFR_TEL_PS_WFXL_SET _ULL(0xc0000000000)
+
+#define KVX_SFR_TEL_FN_MASK _ULL(0xfffffff000) /* Frame Number */
+#define KVX_SFR_TEL_FN_SHIFT 12
+#define KVX_SFR_TEL_FN_WIDTH 28
+#define KVX_SFR_TEL_FN_WFXL_MASK _ULL(0xfffff000)
+#define KVX_SFR_TEL_FN_WFXL_CLEAR _ULL(0xfffff000)
+#define KVX_SFR_TEL_FN_WFXL_SET _ULL(0xfffff00000000000)
+#define KVX_SFR_TEL_FN_WFXM_MASK _ULL(0xff00000000)
+#define KVX_SFR_TEL_FN_WFXM_CLEAR _ULL(0xff)
+#define KVX_SFR_TEL_FN_WFXM_SET _ULL(0xff00000000)
+
+#define KVX_SFR_TEH_ASN_MASK _ULL(0x1ff) /* Address Space Number */
+#define KVX_SFR_TEH_ASN_SHIFT 0
+#define KVX_SFR_TEH_ASN_WIDTH 9
+#define KVX_SFR_TEH_ASN_WFXL_MASK _ULL(0x1ff)
+#define KVX_SFR_TEH_ASN_WFXL_CLEAR _ULL(0x1ff)
+#define KVX_SFR_TEH_ASN_WFXL_SET _ULL(0x1ff00000000)
+
+#define KVX_SFR_TEH_G_MASK _ULL(0x200) /* Global page indicator */
+#define KVX_SFR_TEH_G_SHIFT 9
+#define KVX_SFR_TEH_G_WIDTH 1
+#define KVX_SFR_TEH_G_WFXL_MASK _ULL(0x200)
+#define KVX_SFR_TEH_G_WFXL_CLEAR _ULL(0x200)
+#define KVX_SFR_TEH_G_WFXL_SET _ULL(0x20000000000)
+
+#define KVX_SFR_TEH_VS_MASK _ULL(0xc00) /* Virtual Space */
+#define KVX_SFR_TEH_VS_SHIFT 10
+#define KVX_SFR_TEH_VS_WIDTH 2
+#define KVX_SFR_TEH_VS_WFXL_MASK _ULL(0xc00)
+#define KVX_SFR_TEH_VS_WFXL_CLEAR _ULL(0xc00)
+#define KVX_SFR_TEH_VS_WFXL_SET _ULL(0xc0000000000)
+
+#define KVX_SFR_TEH_PN_MASK _ULL(0x1fffffff000) /* Page Number */
+#define KVX_SFR_TEH_PN_SHIFT 12
+#define KVX_SFR_TEH_PN_WIDTH 29
+#define KVX_SFR_TEH_PN_WFXL_MASK _ULL(0xfffff000)
+#define KVX_SFR_TEH_PN_WFXL_CLEAR _ULL(0xfffff000)
+#define KVX_SFR_TEH_PN_WFXL_SET _ULL(0xfffff00000000000)
+#define KVX_SFR_TEH_PN_WFXM_MASK _ULL(0x1ff00000000)
+#define KVX_SFR_TEH_PN_WFXM_CLEAR _ULL(0x1ff)
+#define KVX_SFR_TEH_PN_WFXM_SET _ULL(0x1ff00000000)
+
+#define KVX_SFR_DC_BE0_MASK _ULL(0x1) /* Breakpoint 0 Enable */
+#define KVX_SFR_DC_BE0_SHIFT 0
+#define KVX_SFR_DC_BE0_WIDTH 1
+#define KVX_SFR_DC_BE0_WFXL_MASK _ULL(0x1)
+#define KVX_SFR_DC_BE0_WFXL_CLEAR _ULL(0x1)
+#define KVX_SFR_DC_BE0_WFXL_SET _ULL(0x100000000)
+
+#define KVX_SFR_DC_BR0_MASK _ULL(0x7e) /* Breakpoint 0 Range */
+#define KVX_SFR_DC_BR0_SHIFT 1
+#define KVX_SFR_DC_BR0_WIDTH 6
+#define KVX_SFR_DC_BR0_WFXL_MASK _ULL(0x7e)
+#define KVX_SFR_DC_BR0_WFXL_CLEAR _ULL(0x7e)
+#define KVX_SFR_DC_BR0_WFXL_SET _ULL(0x7e00000000)
+
+#define KVX_SFR_DC_BE1_MASK _ULL(0x80) /* Breakpoint 1 Enable */
+#define KVX_SFR_DC_BE1_SHIFT 7
+#define KVX_SFR_DC_BE1_WIDTH 1
+#define KVX_SFR_DC_BE1_WFXL_MASK _ULL(0x80)
+#define KVX_SFR_DC_BE1_WFXL_CLEAR _ULL(0x80)
+#define KVX_SFR_DC_BE1_WFXL_SET _ULL(0x8000000000)
+
+#define KVX_SFR_DC_BR1_MASK _ULL(0x3f00) /* Breakpoint 1 Range */
+#define KVX_SFR_DC_BR1_SHIFT 8
+#define KVX_SFR_DC_BR1_WIDTH 6
+#define KVX_SFR_DC_BR1_WFXL_MASK _ULL(0x3f00)
+#define KVX_SFR_DC_BR1_WFXL_CLEAR _ULL(0x3f00)
+#define KVX_SFR_DC_BR1_WFXL_SET _ULL(0x3f0000000000)
+
+#define KVX_SFR_DC_WE0_MASK _ULL(0x4000) /* Watchpoint 0 Enable */
+#define KVX_SFR_DC_WE0_SHIFT 14
+#define KVX_SFR_DC_WE0_WIDTH 1
+#define KVX_SFR_DC_WE0_WFXL_MASK _ULL(0x4000)
+#define KVX_SFR_DC_WE0_WFXL_CLEAR _ULL(0x4000)
+#define KVX_SFR_DC_WE0_WFXL_SET _ULL(0x400000000000)
+
+#define KVX_SFR_DC_WR0_MASK _ULL(0x1f8000) /* Watchpoint 0 Range */
+#define KVX_SFR_DC_WR0_SHIFT 15
+#define KVX_SFR_DC_WR0_WIDTH 6
+#define KVX_SFR_DC_WR0_WFXL_MASK _ULL(0x1f8000)
+#define KVX_SFR_DC_WR0_WFXL_CLEAR _ULL(0x1f8000)
+#define KVX_SFR_DC_WR0_WFXL_SET _ULL(0x1f800000000000)
+
+#define KVX_SFR_DC_WE1_MASK _ULL(0x200000) /* Watchpoint 1 Enable */
+#define KVX_SFR_DC_WE1_SHIFT 21
+#define KVX_SFR_DC_WE1_WIDTH 1
+#define KVX_SFR_DC_WE1_WFXL_MASK _ULL(0x200000)
+#define KVX_SFR_DC_WE1_WFXL_CLEAR _ULL(0x200000)
+#define KVX_SFR_DC_WE1_WFXL_SET _ULL(0x20000000000000)
+
+#define KVX_SFR_DC_WR1_MASK _ULL(0xfc00000) /* Watchpoint 1 Range */
+#define KVX_SFR_DC_WR1_SHIFT 22
+#define KVX_SFR_DC_WR1_WIDTH 6
+#define KVX_SFR_DC_WR1_WFXL_MASK _ULL(0xfc00000)
+#define KVX_SFR_DC_WR1_WFXL_CLEAR _ULL(0xfc00000)
+#define KVX_SFR_DC_WR1_WFXL_SET _ULL(0xfc0000000000000)
+
+#define KVX_SFR_MES_PSE_MASK _ULL(0x1) /* Program Simple Ecc */
+#define KVX_SFR_MES_PSE_SHIFT 0
+#define KVX_SFR_MES_PSE_WIDTH 1
+#define KVX_SFR_MES_PSE_WFXL_MASK _ULL(0x1)
+#define KVX_SFR_MES_PSE_WFXL_CLEAR _ULL(0x1)
+#define KVX_SFR_MES_PSE_WFXL_SET _ULL(0x100000000)
+
+#define KVX_SFR_MES_PILSY_MASK _ULL(0x2) /* Program cache Invalidated Line following pSYs error. */
+#define KVX_SFR_MES_PILSY_SHIFT 1
+#define KVX_SFR_MES_PILSY_WIDTH 1
+#define KVX_SFR_MES_PILSY_WFXL_MASK _ULL(0x2)
+#define KVX_SFR_MES_PILSY_WFXL_CLEAR _ULL(0x2)
+#define KVX_SFR_MES_PILSY_WFXL_SET _ULL(0x200000000)
+
+#define KVX_SFR_MES_PILDE_MASK _ULL(0x4) /* Program cache Invalidated Line following pDEcc error. */
+#define KVX_SFR_MES_PILDE_SHIFT 2
+#define KVX_SFR_MES_PILDE_WIDTH 1
+#define KVX_SFR_MES_PILDE_WFXL_MASK _ULL(0x4)
+#define KVX_SFR_MES_PILDE_WFXL_CLEAR _ULL(0x4)
+#define KVX_SFR_MES_PILDE_WFXL_SET _ULL(0x400000000)
+
+#define KVX_SFR_MES_PILPA_MASK _ULL(0x8) /* Program cache Invalidated Line following pPArity error. */
+#define KVX_SFR_MES_PILPA_SHIFT 3
+#define KVX_SFR_MES_PILPA_WIDTH 1
+#define KVX_SFR_MES_PILPA_WFXL_MASK _ULL(0x8)
+#define KVX_SFR_MES_PILPA_WFXL_CLEAR _ULL(0x8)
+#define KVX_SFR_MES_PILPA_WFXL_SET _ULL(0x800000000)
+
+#define KVX_SFR_MES_DSE_MASK _ULL(0x10) /* Data Simple Ecc */
+#define KVX_SFR_MES_DSE_SHIFT 4
+#define KVX_SFR_MES_DSE_WIDTH 1
+#define KVX_SFR_MES_DSE_WFXL_MASK _ULL(0x10)
+#define KVX_SFR_MES_DSE_WFXL_CLEAR _ULL(0x10)
+#define KVX_SFR_MES_DSE_WFXL_SET _ULL(0x1000000000)
+
+#define KVX_SFR_MES_DILSY_MASK _ULL(0x20) /* Data cache Invalidated Line following dSYs error. */
+#define KVX_SFR_MES_DILSY_SHIFT 5
+#define KVX_SFR_MES_DILSY_WIDTH 1
+#define KVX_SFR_MES_DILSY_WFXL_MASK _ULL(0x20)
+#define KVX_SFR_MES_DILSY_WFXL_CLEAR _ULL(0x20)
+#define KVX_SFR_MES_DILSY_WFXL_SET _ULL(0x2000000000)
+
+#define KVX_SFR_MES_DILDE_MASK _ULL(0x40) /* Data cache Invalidated Line following dDEcc error. */
+#define KVX_SFR_MES_DILDE_SHIFT 6
+#define KVX_SFR_MES_DILDE_WIDTH 1
+#define KVX_SFR_MES_DILDE_WFXL_MASK _ULL(0x40)
+#define KVX_SFR_MES_DILDE_WFXL_CLEAR _ULL(0x40)
+#define KVX_SFR_MES_DILDE_WFXL_SET _ULL(0x4000000000)
+
+#define KVX_SFR_MES_DILPA_MASK _ULL(0x80) /* Data cache Invalidated Line following dPArity error. */
+#define KVX_SFR_MES_DILPA_SHIFT 7
+#define KVX_SFR_MES_DILPA_WIDTH 1
+#define KVX_SFR_MES_DILPA_WFXL_MASK _ULL(0x80)
+#define KVX_SFR_MES_DILPA_WFXL_CLEAR _ULL(0x80)
+#define KVX_SFR_MES_DILPA_WFXL_SET _ULL(0x8000000000)
+
+#define KVX_SFR_MES_DDEE_MASK _ULL(0x100) /* Data DEcc Error. */
+#define KVX_SFR_MES_DDEE_SHIFT 8
+#define KVX_SFR_MES_DDEE_WIDTH 1
+#define KVX_SFR_MES_DDEE_WFXL_MASK _ULL(0x100)
+#define KVX_SFR_MES_DDEE_WFXL_CLEAR _ULL(0x100)
+#define KVX_SFR_MES_DDEE_WFXL_SET _ULL(0x10000000000)
+
+#define KVX_SFR_MES_DSYE_MASK _ULL(0x200) /* Data dSYs Error. */
+#define KVX_SFR_MES_DSYE_SHIFT 9
+#define KVX_SFR_MES_DSYE_WIDTH 1
+#define KVX_SFR_MES_DSYE_WFXL_MASK _ULL(0x200)
+#define KVX_SFR_MES_DSYE_WFXL_CLEAR _ULL(0x200)
+#define KVX_SFR_MES_DSYE_WFXL_SET _ULL(0x20000000000)
+
+#define KVX_SFR_WS_WU0_MASK _ULL(0x1) /* Wake-Up 0 */
+#define KVX_SFR_WS_WU0_SHIFT 0
+#define KVX_SFR_WS_WU0_WIDTH 1
+#define KVX_SFR_WS_WU0_WFXL_MASK _ULL(0x1)
+#define KVX_SFR_WS_WU0_WFXL_CLEAR _ULL(0x1)
+#define KVX_SFR_WS_WU0_WFXL_SET _ULL(0x100000000)
+
+#define KVX_SFR_WS_WU1_MASK _ULL(0x2) /* Wake-Up 1 */
+#define KVX_SFR_WS_WU1_SHIFT 1
+#define KVX_SFR_WS_WU1_WIDTH 1
+#define KVX_SFR_WS_WU1_WFXL_MASK _ULL(0x2)
+#define KVX_SFR_WS_WU1_WFXL_CLEAR _ULL(0x2)
+#define KVX_SFR_WS_WU1_WFXL_SET _ULL(0x200000000)
+
+#define KVX_SFR_WS_WU2_MASK _ULL(0x4) /* Wake-Up 2 */
+#define KVX_SFR_WS_WU2_SHIFT 2
+#define KVX_SFR_WS_WU2_WIDTH 1
+#define KVX_SFR_WS_WU2_WFXL_MASK _ULL(0x4)
+#define KVX_SFR_WS_WU2_WFXL_CLEAR _ULL(0x4)
+#define KVX_SFR_WS_WU2_WFXL_SET _ULL(0x400000000)
+
+#define KVX_SFR_IPE_FE_MASK _ULL(0xffff) /* Forward Events */
+#define KVX_SFR_IPE_FE_SHIFT 0
+#define KVX_SFR_IPE_FE_WIDTH 16
+#define KVX_SFR_IPE_FE_WFXL_MASK _ULL(0xffff)
+#define KVX_SFR_IPE_FE_WFXL_CLEAR _ULL(0xffff)
+#define KVX_SFR_IPE_FE_WFXL_SET _ULL(0xffff00000000)
+
+#define KVX_SFR_IPE_BE_MASK _ULL(0xffff0000) /* Backward Events */
+#define KVX_SFR_IPE_BE_SHIFT 16
+#define KVX_SFR_IPE_BE_WIDTH 16
+#define KVX_SFR_IPE_BE_WFXL_MASK _ULL(0xffff0000)
+#define KVX_SFR_IPE_BE_WFXL_CLEAR _ULL(0xffff0000)
+#define KVX_SFR_IPE_BE_WFXL_SET _ULL(0xffff000000000000)
+
+#define KVX_SFR_IPE_FM_MASK _ULL(0xffff00000000) /* Forward Mode */
+#define KVX_SFR_IPE_FM_SHIFT 32
+#define KVX_SFR_IPE_FM_WIDTH 16
+#define KVX_SFR_IPE_FM_WFXM_MASK _ULL(0xffff00000000)
+#define KVX_SFR_IPE_FM_WFXM_CLEAR _ULL(0xffff)
+#define KVX_SFR_IPE_FM_WFXM_SET _ULL(0xffff00000000)
+
+#define KVX_SFR_IPE_BM_MASK _ULL(0xffff000000000000) /* Backward Modes */
+#define KVX_SFR_IPE_BM_SHIFT 48
+#define KVX_SFR_IPE_BM_WIDTH 16
+#define KVX_SFR_IPE_BM_WFXM_MASK _ULL(0xffff000000000000)
+#define KVX_SFR_IPE_BM_WFXM_CLEAR _ULL(0xffff0000)
+#define KVX_SFR_IPE_BM_WFXM_SET _ULL(0xffff000000000000)
+
+#endif /*_ASM_KVX_SFR_DEFS_H */
diff --git a/arch/kvx/include/asm/swab.h b/arch/kvx/include/asm/swab.h
new file mode 100644
index 000000000000..83a48871c8fb
--- /dev/null
+++ b/arch/kvx/include/asm/swab.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Clement Leger
+ */
+
+#ifndef _ASM_KVX_SWAB_H
+#define _ASM_KVX_SWAB_H
+
+#include <linux/types.h>
+
+#define U64_BYTE_SWAP_MATRIX 0x0102040810204080ULL
+#define U32_BYTE_SWAP_MATRIX 0x0000000001020408ULL
+#define U16_BYTE_SWAP_MATRIX 0x0000000000000102ULL
+#define U32_WORD_SWAP_MATRIX 0x0000000002010804ULL
+#define U32_HL_BYTE_SWAP_MATRIX 0x0000000004080102ULL
+
+static inline __attribute_const__ __u64 __arch_swab64(__u64 val)
+{
+ return __builtin_kvx_sbmm8(val, U64_BYTE_SWAP_MATRIX);
+}
+
+static inline __attribute_const__ __u32 __arch_swab32(__u32 val)
+{
+ return __builtin_kvx_sbmm8(val, U32_BYTE_SWAP_MATRIX);
+}
+
+static inline __attribute_const__ __u16 __arch_swab16(__u16 val)
+{
+ return __builtin_kvx_sbmm8(val, U16_BYTE_SWAP_MATRIX);
+}
+
+static inline __attribute_const__ __u32 __arch_swahw32(__u32 val)
+{
+ return __builtin_kvx_sbmm8(val, U32_WORD_SWAP_MATRIX);
+}
+
+static inline __attribute_const__ __u32 __arch_swahb32(__u32 val)
+{
+ return __builtin_kvx_sbmm8(val, U32_HL_BYTE_SWAP_MATRIX);
+}
+
+#define __arch_swab64 __arch_swab64
+#define __arch_swab32 __arch_swab32
+#define __arch_swab16 __arch_swab16
+#define __arch_swahw32 __arch_swahw32
+#define __arch_swahb32 __arch_swahb32
+#endif
diff --git a/arch/kvx/include/asm/sys_arch.h b/arch/kvx/include/asm/sys_arch.h
new file mode 100644
index 000000000000..ae518106a0a8
--- /dev/null
+++ b/arch/kvx/include/asm/sys_arch.h
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2017-2023 Kalray Inc.
+ * Author(s): Clement Leger
+ */
+
+#ifndef _ASM_KVX_SYS_ARCH_H
+#define _ASM_KVX_SYS_ARCH_H
+
+#include <asm/sfr_defs.h>
+
+#define EXCEPTION_STRIDE 0x40
+#define EXCEPTION_ALIGNMENT 0x100
+
+#define kvx_cluster_id() ((int) \
+ ((kvx_sfr_get(PCR) & KVX_SFR_PCR_CID_MASK) \
+ >> KVX_SFR_PCR_CID_SHIFT))
+
+#define KVX_SFR_START(__sfr_reg) \
+ (KVX_SFR_## __sfr_reg ## _SHIFT)
+
+#define KVX_SFR_END(__sfr_reg) \
+ (KVX_SFR_## __sfr_reg ## _SHIFT + KVX_SFR_## __sfr_reg ## _WIDTH - 1)
+
+/**
+ * Get the value to clear a sfr
+ */
+#define SFR_CLEAR(__sfr, __field, __lm) \
+ KVX_SFR_## __sfr ## _ ## __field ## _ ## __lm ## _CLEAR
+
+#define SFR_CLEAR_WFXL(__sfr, __field) SFR_CLEAR(__sfr, __field, WFXL)
+#define SFR_CLEAR_WFXM(__sfr, __field) SFR_CLEAR(__sfr, __field, WFXM)
+
+/**
+ * Get the value to set a sfr.
+ */
+#define SFR_SET_WFXL(__sfr, __field, __val) \
+ (__val << (KVX_SFR_ ## __sfr ## _ ## __field ## _SHIFT + 32))
+
+#define SFR_SET_WFXM(__sfr, __field, __val) \
+ (__val << (KVX_SFR_ ## __sfr ## _ ## __field ## _SHIFT))
+
+/**
+ * Generate the mask to clear and set a value using wfx{m|l}.
+ */
+#define SFR_SET_VAL_WFXL(__sfr, __field, __val) \
+ (SFR_SET_WFXL(__sfr, __field, __val) | SFR_CLEAR_WFXL(__sfr, __field))
+#define SFR_SET_VAL_WFXM(__sfr, __field, __val) \
+ (SFR_SET_WFXM(__sfr, __field, __val) | SFR_CLEAR_WFXM(__sfr, __field))
+
+#endif /* _ASM_KVX_SYS_ARCH_H */
--
2.37.2





2023-01-03 21:04:05

by Rob Herring

[permalink] [raw]
Subject: Re: [RFC PATCH 00/25] Upstream kvx Linux port

On Tue, Jan 03, 2023 at 05:43:34PM +0100, Yann Sionneau wrote:
> This patch series adds support for the kv3-1 CPU architecture of the kvx family
> found in the Coolidge (aka MPPA3-80) SoC of Kalray.
>
> This is an RFC, since kvx support is not yet upstreamed into gcc/binutils,
> therefore this patch series cannot be merged into Linux for now.
>
> The goal is to have preliminary reviews and to fix problems early.
>
> The Kalray VLIW processor family (kvx) has the following features:
> * 32/64 bits execution mode
> * 6-issue VLIW architecture
> * 64 x 64bits general purpose registers
> * SIMD instructions
> * little-endian
> * deep learning co-processor
>
> Kalray kv3-1 core which is the third of the kvx family is embedded in Kalray
> Coolidge SoC currently used on K200 and K200-LP boards.
>
> The Coolidge SoC contains 5 clusters each of which is made of:
> * 4MiB of on-chip memory (SMEM)
> * 1 dedicated safety/security core (kv3-1 core).
> * 16 PEs (Processing Elements) (kv3-1 cores).
> * 16 Co-processors (one per PE)
> * 2 Crypto accelerators
>
> The Coolidge SoC contains the following features:
> * 5 Clusters
> * 2 100G Ethernet controllers
> * 8 PCIe GEN4 controllers (Root Complex and Endpoint capable)
> * 2 USB 2.0 controllers
> * 1 Octal SPI-NOR flash controller
> * 1 eMMC controller
> * 3 Quad SPI controllers
> * 6 UART
> * 5 I2C controllers (3 of which are SMBus capable)
> * 4 CAN controllers
> * 1 OTP memory
>
> A kvx toolchain can be built using:
> # install dependencies: texinfo bison flex libgmp-dev libmpc-dev libmpfr-dev
> $ git clone https://github.com/kalray/build-scripts
> $ cd build-scripts
> $ source last.refs
> $ ./build-kvx-xgcc.sh output
>
> The kvx toolchain will be installed in the "output" directory.
>
> A buildroot image (kernel+rootfs) and toolchain can be built using:
> $ git clone -b coolidge-for-upstream https://github.com/kalray/buildroot
> $ cd buildroot
> $ make O=build_kvx kvx_defconfig
> $ make O=build_kvx
>
> The vmlinux image can be found in buildroot/build_kvx/images/vmlinux.
>
> If you are just interested in building the Linux kernel with no rootfs you can
> just do this with the kvx-elf- toolchain:
> $ make ARCH=kvx O=build_kvx CROSS_COMPILE=kvx-elf- default_defconfig
> $ make ARCH=kvx O=build_kvx CROSS_COMPILE=kvx-elf- -j$(($(nproc) + 1))
>
> The vmlinux ELF can be run with qemu by doing:
> # install dependencies: ninja pkg-config libglib-2.0-dev cmake libfdt-dev libpixman-1-dev zlib1g-dev
> $ git clone https://github.com/kalray/qemu-builder
> $ cd qemu-builder
> $ git submodule update --init
> $ make -j$(($(nproc) + 1))
> $ ./qemu-system-kvx -m 1024 -nographic -kernel <path/to/vmlinux>
>
> Yann Sionneau (25):
> Documentation: kvx: Add basic documentation
> kvx: Add ELF-related definitions
> kvx: Add build infrastructure
> kvx: Add CPU definition headers
> kvx: Add atomic/locking headers
> kvx: Add other common headers
> kvx: Add boot and setup routines
> kvx: Add exception/interrupt handling
> kvx: irqchip: Add support for irq controllers
> kvx: Add process management
> kvx: Add memory management
> kvx: Add system call support
> kvx: Add signal handling support
> kvx: Add ELF relocations and module support
> kvx: Add misc common routines
> kvx: Add some library functions
> kvx: Add multi-processor (SMP) support
> kvx: Add kvx default config file
> kvx: power: scall poweroff driver
> kvx: gdb: add kvx related gdb helpers
> kvx: Add support for ftrace
> kvx: Add support for jump labels
> kvx: Add debugging related support
> kvx: Add support for CPU Perf Monitors
> kvx: Add support for cpuinfo

You should strip this series down to just what's needed to boot. You
don't need the last 7 patches at least.

Rob

2023-01-03 21:35:18

by Rob Herring

[permalink] [raw]
Subject: Re: [RFC PATCH 09/25] kvx: irqchip: Add support for irq controllers

On Tue, Jan 03, 2023 at 05:43:43PM +0100, Yann Sionneau wrote:
> Add support for kvx irq controllers found in Coolidge MPPA SoC
>
> The core-intc:
>
> Each kvx core includes a hardware interrupt controller (core ITC)
> with the following features:
> * 32 independent interrupt sources
> * 4-bit priotity level
> * Individual interrupt enable bit
> * Interrupt status bit displaying the pending interrupts
> * Priority management between the 32 interrupts
>
> Among those 32 interrupt sources, the first are hard-wired to hardware
> sources. The remaining interrupt sources can be triggered via software
> by directly writing to the ILR SFR.
>
> The hard-wired interrupt sources are the following:
> 0: Timer 0
> 1: Timer 1
> 2: Watchdog
> 3: Performance Monitors
> 4: APIC GIC line 0
> 5: APIC GIC line 1
> 6: APIC GIC line 2
> 7: APIC GIC line 3
> 12: SECC error from memory system
> 13: Arithmetic exception (carry and IEEE 754 flags)
> 16: Data Asynchronous Memory Error (DAME), raised for DECC/DSYS errors
> 17: CLI (Cache Line Invalidation) for L1D or L1I following DECC/DSYS/Parity
> errors
>
> The APIC GIC lines will be used to route interrupts coming from SoC peripherals
> from outside the Cluster to the kvx core. Those peripherals include USB host
> controller, eMMC/SD host controller, i2c, spi, PCIe, IOMMUs etc...
>
> The APIC GIC:
>
> Each Cluster of the Coolidge SoC includes an APIC
> (Advanced Programmable Interrupt Controller) GIC (Generic Interrupt Controller).
> The APIC GIC acts as an intermediary interrupt controller, muxing/routing
> incoming interrupts to output interrupts connected to the kvx core ITC lines.
> The first 128 incoming interrupt lines come from the mailbox controller (itself
> containing 128 mailboxes).
> The remaining 11 interrupt lines come from external interrupt sources (NoC
> router, the 5 IOMMUs, L2$ DMA job fifo, watchdog, SECC, DECC, D NoC).
> The APIC GIC has 72 output interrupts: 4 per kvx cores in the cluster
> (1 RM and 16 PE) connected to the "APIC GIC lines" described above and 1 for the
> L2$ controller which makes 69 interrupts lines (rounded up to 72).
>
> The APIC Mailbox:
>
> The APIC includes a mailbox controller, containing 128 mailboxes.
> This hardware block is basically a 1 Kb of smart memory space.
> Each mailbox is an 8 bytes word memory location which can generate and
> interrupt.
> Each mailbox has a trigger function and an input function.
> When a mailbox is written to, if the condition described by the
> trigger function is satisfied, the corresponding interrupt
> will fire.
> Since this hardware block generates IRQs based on writes
> at some memory locations, it is both an interrupt controller
> and an MSI controller.
>
> The ITGEN:
>
> The ITGEN (InTerrupt GENerator) is an interrupt controller block.
> It's purpose is to convert IRQ lines coming from SoC peripherals
> (USB host controller for instance) into writes on the AXI bus.
> Those writes are targeting the APIC Mailboxes.
>
> CC: Thomas Gleixner <[email protected]>
> CC: Marc Zyngier <[email protected]>
> CC: Rob Herring <[email protected]>
> CC: Krzysztof Kozlowski <[email protected]>
> CC: [email protected]
> CC: [email protected]
> Co-developed-by: Clement Leger <[email protected]>
> Signed-off-by: Clement Leger <[email protected]>
> Co-developed-by: Jules Maselbas <[email protected]>
> Signed-off-by: Jules Maselbas <[email protected]>
> Co-developed-by: Julian Vetter <[email protected]>
> Signed-off-by: Julian Vetter <[email protected]>
> Co-developed-by: Luc Michel <[email protected]>
> Signed-off-by: Luc Michel <[email protected]>
> Co-developed-by: Vincent Chardon <[email protected]>
> Signed-off-by: Vincent Chardon <[email protected]>
> Co-developed-by: Yann Sionneau <[email protected]>
> Signed-off-by: Yann Sionneau <[email protected]>
> ---
> .../kalray,kvx-core-intc.txt | 22 +

Bindings should be a separate patch and must be in schema format now.

You probably should do a patch per driver too.

> diff --git a/Documentation/devicetree/bindings/interrupt-controller/kalray,kvx-core-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/kalray,kvx-core-intc.txt
> new file mode 100644
> index 000000000000..503a661e1e84
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/interrupt-controller/kalray,kvx-core-intc.txt
> @@ -0,0 +1,22 @@
> +* KVX Core Interrupt controller
> +
> +Required properties:
> +
> +- compatible: must to be "kalray,kvx-core-intc".

compatible strings should be specific enough to identify bugs/features
of a specific implementation unless there's another way to do that (e.g.
version registers).

> +- interrupt-controller
> +- #interrupt-cells: has to be <1>: an interrupt index
> +- regs: Base address of interrupt controller registers.
> +
> +Optional properties:
> +
> +- kalray,intc-nr-irqs: Number of irqs handled by the controller.
> + if not given, will default to 32.

What's the range?

> +
> +Example:
> +
> + core_intc: core_intc@0 {

interrupt-controller {

> + compatible = "kalray,kvx-core-intc";
> + #interrupt-cells = <1>;
> + interrupt-controller;
> + interrupt-parent = <&core_intc>;
> + };

[...]

> +IRQCHIP_DECLARE(kvx_apic_gic, "kalray,kvx-apic-gic", kvx_init_apic_gic);

> +IRQCHIP_DECLARE(kvx_apic_mailbox, "kalray,kvx-apic-mailbox",
> + kvx_init_apic_mailbox);

> +static const struct of_device_id itgen_of_match[] = {
> + { .compatible = "kalray,kvx-itgen" },
> + { /* END */ }
> +};

All these compatible strings need binding schemas, too.


> diff --git a/include/linux/irqchip/irq-kvx-apic-gic.h b/include/linux/irqchip/irq-kvx-apic-gic.h
> new file mode 100644
> index 000000000000..8efbcd05f3ea
> --- /dev/null
> +++ b/include/linux/irqchip/irq-kvx-apic-gic.h
> @@ -0,0 +1,21 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2018-2023 Kalray Inc.
> + * Author: Clement Leger
> + */
> +
> +#ifndef KVX_APIC_GIC_H
> +#define KVX_APIC_GIC_H
> +
> +/* GIC enable register definitions */
> +#define KVX_GIC_ENABLE_OFFSET 0x0
> +#define KVX_GIC_ENABLE_ELEM_SIZE 0x1
> +#define KVX_GIC_INPUT_IT_COUNT 0x9D
> +#define KVX_GIC_ELEM_SIZE 0x400
> +
> +/* GIC status lac register definitions */
> +#define KVX_GIC_STATUS_LAC_OFFSET 0x120
> +#define KVX_GIC_STATUS_LAC_ELEM_SIZE 0x8
> +#define KVX_GIC_STATUS_LAC_ARRAY_SIZE 0x3

Do these defines need to be public to *all* the kernel? Doesn't look
like it.

Same question on the other headers.

Rob

2023-01-03 22:06:29

by Rob Herring

[permalink] [raw]
Subject: Re: [RFC PATCH 17/25] kvx: Add multi-processor (SMP) support

On Tue, Jan 03, 2023 at 05:43:51PM +0100, Yann Sionneau wrote:
> Coolidge v1 SoC has 5 clusters of 16 kvx cores
> (+1 special Resource Manager (RM) core).
>
> Linux can run in SMP config on the 16 cores of
> a Cluster.
>
> Cache coherency is done by the L2 cache.
>
> CC: [email protected]
> Co-developed-by: Clement Leger <[email protected]>
> Signed-off-by: Clement Leger <[email protected]>
> Co-developed-by: Julian Vetter <[email protected]>
> Signed-off-by: Julian Vetter <[email protected]>
> Co-developed-by: Julien Hascoet <[email protected]>
> Signed-off-by: Julien Hascoet <[email protected]>
> Co-developed-by: Louis Morhet <[email protected]>
> Signed-off-by: Louis Morhet <[email protected]>
> Co-developed-by: Luc Michel <[email protected]>
> Signed-off-by: Luc Michel <[email protected]>
> Co-developed-by: Marius Gligor <[email protected]>
> Signed-off-by: Marius Gligor <[email protected]>
> Co-developed-by: Yann Sionneau <[email protected]>
> Signed-off-by: Yann Sionneau <[email protected]>
> ---
> arch/kvx/include/asm/pwr_ctrl.h | 45 ++++
> arch/kvx/include/asm/smp.h | 42 +++
> arch/kvx/kernel/l2_cache.c | 448 ++++++++++++++++++++++++++++++++
> arch/kvx/kernel/smp.c | 110 ++++++++
> arch/kvx/kernel/smpboot.c | 127 +++++++++
> arch/kvx/platform/pwr_ctrl.c | 93 +++++++
> include/linux/cpuhotplug.h | 2 +
> 7 files changed, 867 insertions(+)
> create mode 100644 arch/kvx/include/asm/pwr_ctrl.h
> create mode 100644 arch/kvx/include/asm/smp.h
> create mode 100644 arch/kvx/kernel/l2_cache.c
> create mode 100644 arch/kvx/kernel/smp.c
> create mode 100644 arch/kvx/kernel/smpboot.c
> create mode 100644 arch/kvx/platform/pwr_ctrl.c
>
> diff --git a/arch/kvx/include/asm/pwr_ctrl.h b/arch/kvx/include/asm/pwr_ctrl.h
> new file mode 100644
> index 000000000000..25f403ba935a
> --- /dev/null
> +++ b/arch/kvx/include/asm/pwr_ctrl.h
> @@ -0,0 +1,45 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (C) 2017-2023 Kalray Inc.
> + * Author(s): Clement Leger
> + * Marius Gligor
> + */
> +
> +#ifndef _ASM_KVX_PWR_CTRL_H
> +#define _ASM_KVX_PWR_CTRL_H
> +
> +#ifndef __ASSEMBLY__
> +
> +int kvx_pwr_ctrl_probe(void);
> +
> +void kvx_pwr_ctrl_cpu_poweron(unsigned int cpu);
> +
> +#endif
> +
> +/* Power controller vector register definitions */
> +#define KVX_PWR_CTRL_VEC_OFFSET 0x1000
> +#define KVX_PWR_CTRL_VEC_WUP_SET_OFFSET 0x10
> +#define KVX_PWR_CTRL_VEC_WUP_CLEAR_OFFSET 0x20
> +
> +/* Power controller PE reset PC register definitions */
> +#define KVX_PWR_CTRL_RESET_PC_OFFSET 0x2000
> +
> +/* Power controller global register definitions */
> +#define KVX_PWR_CTRL_GLOBAL_OFFSET 0x4040
> +
> +#define KVX_PWR_CTRL_GLOBAL_SET_OFFSET 0x10
> +#define KVX_PWR_CTRL_GLOBAL_SET_PE_EN_SHIFT 0x1
> +
> +#define PWR_CTRL_WUP_SET_OFFSET \
> + (KVX_PWR_CTRL_VEC_OFFSET + \
> + KVX_PWR_CTRL_VEC_WUP_SET_OFFSET)
> +
> +#define PWR_CTRL_WUP_CLEAR_OFFSET \
> + (KVX_PWR_CTRL_VEC_OFFSET + \
> + KVX_PWR_CTRL_VEC_WUP_CLEAR_OFFSET)
> +
> +#define PWR_CTRL_GLOBAL_CONFIG_OFFSET \
> + (KVX_PWR_CTRL_GLOBAL_OFFSET + \
> + KVX_PWR_CTRL_GLOBAL_SET_OFFSET)
> +
> +#endif /* _ASM_KVX_PWR_CTRL_H */
> diff --git a/arch/kvx/include/asm/smp.h b/arch/kvx/include/asm/smp.h
> new file mode 100644
> index 000000000000..e4fd4d001b2c
> --- /dev/null
> +++ b/arch/kvx/include/asm/smp.h
> @@ -0,0 +1,42 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (C) 2017-2023 Kalray Inc.
> + * Author(s): Clement Leger
> + */
> +
> +#ifndef _ASM_KVX_SMP_H
> +#define _ASM_KVX_SMP_H
> +
> +#include <linux/cpumask.h>
> +#include <linux/irqreturn.h>
> +
> +#include <asm/sfr.h>
> +
> +#ifdef CONFIG_SMP
> +
> +/* Hook for the generic smp_call_function_many() routine. */
> +void arch_send_call_function_ipi_mask(struct cpumask *mask);
> +
> +/* Hook for the generic smp_call_function_single() routine. */
> +void arch_send_call_function_single_ipi(int cpu);
> +
> +void __init setup_processor(void);
> +
> +void smp_init_cpus(void);
> +
> +irqreturn_t ipi_call_interrupt(int irq, void *dev_id);
> +
> +#define raw_smp_processor_id() ((int) \
> + ((kvx_sfr_get(PCR) & KVX_SFR_PCR_PID_MASK) \
> + >> KVX_SFR_PCR_PID_SHIFT))
> +
> +#define flush_cache_vmap(start, end) do { } while (0)
> +#define flush_cache_vunmap(start, end) do { } while (0)
> +
> +#else
> +
> +void smp_init_cpus(void) {}
> +
> +#endif /* CONFIG_SMP */
> +
> +#endif
> diff --git a/arch/kvx/kernel/l2_cache.c b/arch/kvx/kernel/l2_cache.c
> new file mode 100644
> index 000000000000..94a4d9159471
> --- /dev/null
> +++ b/arch/kvx/kernel/l2_cache.c
> @@ -0,0 +1,448 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2017-2023 Kalray Inc.
> + * Author(s): Clement Leger
> + * Luc Michel
> + * Julien Hascoet
> + */
> +
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +
> +#include <linux/io.h>
> +#include <linux/of.h>
> +#include <linux/jiffies.h>
> +#include <linux/of_address.h>
> +#include <linux/irqchip/irq-kvx-apic-mailbox.h>
> +
> +#include <asm/rm_fw.h>
> +#include <asm/l2_cache.h>
> +#include <asm/sections.h>
> +#include <asm/cacheflush.h>
> +
> +#define L2_START_TIMEOUT_MS 10
> +#define L2_CMD_TIMEOUT_MS 200
> +
> +#define L2_MK_OP(__cmd, __sync) (BIT(L2_CMD_OP_VALID_SHIFT) | \
> + ((u64) __sync << L2_CMD_OP_SYNC_SHIFT) | \
> + ((u64) __cmd << L2_CMD_OP_CMD_SHIFT))
> +
> +#define L2_ERROR(_err) \
> + ((error & L2_ERROR_ERROR_CODE_MASK) >> L2_ERROR_ERROR_CODE_SHIFT)
> +
> +struct l2_cache_hw_cmd {
> + u64 op;
> + u64 args[L2_CMD_OP_ARG_COUNT];
> +} __packed;
> +
> +struct l2_cache_cmd {
> + int sync;
> + int cmd_type;
> + unsigned int arg_count;
> + u64 args[L2_CMD_OP_ARG_COUNT];
> +};
> +
> +/**
> + * struct l2_cached_data - Data associated to the l2-cache
> + * @regs: base of L2 registers
> + * @mbox_regs: Mailbox registers for L2 signaling
> + */
> +struct l2_cache_data {
> + void __iomem *regs;
> + void __iomem *mbox_regs;
> + u64 fifo_cmd_count;
> +};
> +
> +DEFINE_STATIC_KEY_FALSE(l2_enabled);
> +static struct l2_cache_data l2c_ctrl;
> +
> +static void *l2_cmd_regs_addr(void)
> +{
> + return l2c_ctrl.regs + L2_CMD_OFFSET;
> +}
> +
> +static struct l2_cache_hw_cmd *l2_cache_hw_cmd_addr(u64 idx)
> +{
> + void *cmd_regs = l2_cmd_regs_addr();
> +
> + /* Wrap index */
> + idx &= (l2c_ctrl.fifo_cmd_count - 1);
> + return cmd_regs + L2_CMD_FIFO_OFFSET + idx * L2_CMD_FIFO_ELEM_SIZE;
> +}
> +
> +static u64 l2_cache_get_cmd_idx(unsigned int cmd_count)
> +{
> + u64 cmd_idx;
> + void *cmd_regs = l2_cmd_regs_addr();
> + u64 *write_idx_ptr = cmd_regs + L2_CMD_WRITE_IDX_OFFSET;
> + u64 *read_idx_ptr = cmd_regs + L2_CMD_READ_IDX_OFFSET;
> +
> + /* Grab a commands tickets */
> + cmd_idx = __builtin_kvx_aladdd(write_idx_ptr, cmd_count);
> +
> + /* Wait until there is room in command fifo to enqueue commands */
> + while ((cmd_idx + cmd_count) >=
> + (readq(read_idx_ptr) + l2c_ctrl.fifo_cmd_count))
> + cpu_relax();
> +
> + return cmd_idx;
> +}
> +
> +static void l2_wait_completion(u64 cmd_idx)
> +{
> + u64 *read_idx_ptr = l2_cmd_regs_addr() + L2_CMD_READ_IDX_OFFSET;
> + unsigned long timeout = jiffies + msecs_to_jiffies(L2_CMD_TIMEOUT_MS);
> +
> + /* Wait for completion */
> + while (cmd_idx >= readq(read_idx_ptr)) {
> + cpu_relax();
> + if (time_after(jiffies, timeout))
> + panic("L2 cache completion timeout\n");
> + }
> +}
> +
> +static u64 l2_cache_push_cmds(struct l2_cache_cmd *cmds, int cmd_count)
> +{
> + int i, arg;
> + u64 cmd_op;
> + struct l2_cache_hw_cmd *cmd;
> + struct l2_cache_cmd *soft_cmd;
> + u64 cmd_idx = l2_cache_get_cmd_idx(cmd_count);
> +
> + for (i = 0; i < cmd_count; i++) {
> + soft_cmd = &cmds[i];
> + cmd = l2_cache_hw_cmd_addr(cmd_idx);
> + cmd_idx++;
> +
> + for (arg = 0; arg < soft_cmd->arg_count; arg++)
> + writeq_relaxed(soft_cmd->args[arg], &cmd->args[arg]);
> +
> + cmd_op = L2_MK_OP(soft_cmd->cmd_type, soft_cmd->sync);
> + writeq(cmd_op, &cmd->op);
> + }
> +
> + return cmd_idx - 1;
> +}
> +
> +static void l2_cache_create_line_cmd(struct l2_cache_cmd *cmd, int cmd_type,
> + int sync, u64 addr)
> +{
> + cmd->cmd_type = cmd_type;
> + cmd->sync = sync;
> + cmd->arg_count = 1;
> + cmd->args[0] = addr;
> +}
> +
> +static void l2_cache_create_area_cmd(struct l2_cache_cmd *cmd, int cmd_type,
> + int sync, u64 addr, u64 size)
> +{
> + l2_cache_create_line_cmd(cmd, cmd_type, sync, addr);
> + cmd->arg_count = 2;
> + cmd->args[1] = size;
> +}
> +
> +static void l2_cache_push_inval_cmd(phys_addr_t start,
> + unsigned long size)
> +{
> + phys_addr_t end = start + size;
> + struct l2_cache_cmd cmds[3];
> + unsigned long irq_flags;
> + int cmd_count = 0;
> + u64 cmd_idx;
> +
> + /*
> + * In case of invalidation, we must make sure we do not invalidate
> + * unwanted area and thus discard legit data. In case we are not aligned
> + * send a purge line command (writeback + inval) to unaligned lines
> + * (which can be the end line or the start line)
> + */
> + if (!IS_ALIGNED(end, L2_CACHE_LINE_SIZE)) {
> + end &= ~L2_CACHE_LINE_MASK;
> + l2_cache_create_line_cmd(&cmds[cmd_count],
> + L2_CMD_OP_CMD_PURGE_LINE, 1, end);
> + cmd_count++;
> + }
> +
> + if (!IS_ALIGNED(start, L2_CACHE_LINE_SIZE)) {
> + start &= ~L2_CACHE_LINE_MASK;
> + /* If there is at least another line to clear */
> + if (end != start) {
> + l2_cache_create_line_cmd(&cmds[cmd_count],
> + L2_CMD_OP_CMD_PURGE_LINE, 1,
> + start);
> + cmd_count++;
> + start += L2_CACHE_LINE_SIZE;
> + }
> + }
> +
> + BUG_ON(end < start);
> +
> + size = (end - start);
> + if (size > 0) {
> + l2_cache_create_area_cmd(&cmds[cmd_count],
> + L2_CMD_OP_CMD_INVAL_AREA, 1, start,
> + size);
> + cmd_count++;
> + }
> +
> + BUG_ON(cmd_count == 0);
> +
> + local_irq_save(irq_flags);
> +
> + cmd_idx = l2_cache_push_cmds(cmds, cmd_count);
> +
> + /* Finally, ping the L2 cache controller */
> + writeq(1, l2c_ctrl.mbox_regs);
> +
> + local_irq_restore(irq_flags);
> +
> + l2_wait_completion(cmd_idx);
> +}
> +
> +static void l2_cache_push_generic_cmd(u64 cmd_type, phys_addr_t start,
> + unsigned long size)
> +{
> + unsigned long irq_flags;
> + struct l2_cache_cmd cmd;
> + u64 cmd_idx;
> +
> + /* Align the start address and size on cache line */
> + size += start & (L2_CACHE_LINE_SIZE - 1);
> + size = ALIGN(size, L2_CACHE_LINE_SIZE);
> + start = ALIGN_DOWN(start, L2_CACHE_LINE_SIZE);
> +
> + local_irq_save(irq_flags);
> +
> + l2_cache_create_area_cmd(&cmd, cmd_type, 1, start, size);
> + cmd_idx = l2_cache_push_cmds(&cmd, 1);
> +
> + /* Finally, ping the L2 cache controller */
> + writeq(1, l2c_ctrl.mbox_regs);
> +
> + local_irq_restore(irq_flags);
> +
> + l2_wait_completion(cmd_idx);
> +}
> +
> +void l2_cache_push_area_cmd(u64 cmd_type, phys_addr_t start,
> + unsigned long size)
> +{
> + if (WARN_ON(size == 0))
> + return;
> +
> + if (cmd_type == L2_CMD_OP_CMD_INVAL_AREA)
> + l2_cache_push_inval_cmd(start, size);
> + else
> + l2_cache_push_generic_cmd(cmd_type, start, size);
> +}
> +
> +static void __init l2_disp_error(u64 error)
> +{
> + const char *err_type;
> +
> + if (error & L2_ERROR_API_ERR_MASK)
> + err_type = "API";
> + else if (error & L2_ERROR_SETUP_ERR_MASK)
> + err_type = "SETUP";
> + else
> + err_type = "UNKNOWN";
> +
> + pr_err("%s error: 0x%llx\n", err_type, L2_ERROR(error));
> +}
> +
> +static int __init l2_cache_configure_mailboxes(void)
> +{
> + phys_addr_t l2_mbox_addr = 0;
> + void *cmd_regs = l2_cmd_regs_addr();
> +
> + /* We do not use mailbox to wait for completion, set it to 0 */
> + writeq(0, cmd_regs + L2_CMD_DOORBELL_READ_ADDR_OFFSET);
> +
> + /* Read mailbox address from L2 registers */
> + l2_mbox_addr = readq(cmd_regs + L2_CMD_DOORBELL_WRITE_ADDR_OFFSET);
> +
> + /* Then map the mailbox */
> + l2c_ctrl.mbox_regs = ioremap(l2_mbox_addr, PAGE_SIZE);
> + if (!l2c_ctrl.mbox_regs) {
> + pr_err("Failed to map mailbox\n");
> + return 1;
> + }
> +
> + /* Lock this entry into the LTLB */
> + kvx_mmu_ltlb_add_entry((unsigned long) l2c_ctrl.mbox_regs & PAGE_MASK,
> + l2_mbox_addr & PAGE_MASK,
> + PAGE_KERNEL_DEVICE, TLB_PS_4K);
> +
> + return 0;
> +}
> +
> +static int __init l2_cache_read_queue_size(void)
> +{
> + u64 inst;
> +
> + /* Read command queue size */
> + inst = readq(l2c_ctrl.regs + L2_INSTANCE_OFFSET);
> + l2c_ctrl.fifo_cmd_count = (inst & L2_INSTANCE_CMD_QUEUE_SIZE_MASK)
> + >> L2_INSTANCE_CMD_QUEUE_SIZE_SHIFT;
> +
> + /* Check if value is a power of two */
> + if (hweight64(l2c_ctrl.fifo_cmd_count) != 1) {
> + pr_err("Command queue size is not a power of two\n");
> + return 1;
> + }
> +
> + return 0;
> +}
> +
> +static int __init l2_cache_init_hw(void)
> +{
> + unsigned long timeout = jiffies + msecs_to_jiffies(L2_START_TIMEOUT_MS);
> + unsigned long flags;
> + u64 status, error;
> + int ret;
> +
> + /* Wait for L2 to be up */
> + do {
> + status = readq(l2c_ctrl.regs + L2_STATUS_OFFSET);
> + if (status & (L2_STATUS_READY_MASK | L2_STATUS_ERROR_MASK))
> + break;
> + } while (time_before(jiffies, timeout));
> +
> + if (!status) {
> + pr_err("Timeout while waiting for firmware status\n");
> + return -ENODEV;
> + }
> +
> + if (status & L2_STATUS_ERROR_MASK) {
> + error = readq(l2c_ctrl.regs + L2_ERROR_OFFSET);
> + l2_disp_error(error);
> + return -EINVAL;
> + }
> +
> + /* Now write ack to L2 firmware */
> + writeq(status | L2_STATUS_ACK_MASK, l2c_ctrl.regs + L2_STATUS_OFFSET);
> +
> + ret = l2_cache_read_queue_size();
> + if (ret)
> + return ret;
> +
> + ret = l2_cache_configure_mailboxes();
> + if (ret)
> + return ret;
> +
> + /* Enable the L2 atomically */
> + local_irq_save(flags);
> +
> + /* Fence data accesses */
> + kvx_fence();
> + /* Purge L1 */
> + l1_inval_dcache_all();
> + l1_inval_icache_all();
> + __builtin_kvx_barrier();
> +
> + local_irq_restore(flags);
> +
> + /* Enable L2$ */
> + kvx_sfr_set_field(PS, L2E, 1);
> +
> + return 0;
> +}
> +
> +static phys_addr_t __init l2_get_regs_addr(struct device_node *np)
> +{
> + const void *reg;
> + struct resource res;
> + phys_addr_t l2_regs_addr;
> + int ret;
> +
> + /*
> + * If regs is specified in device tree, then the L2$ has been loaded by
> + * someone else and not by ourself.
> + */
> + reg = of_get_property(np, "reg", NULL);

Why do you read 'reg' and then...

> + if (reg) {
> + ret = of_address_to_resource(np, 0, &res);

...read it again?

> + if (ret) {
> + pr_err("Address translation error\n");
> + return 0;
> + }
> + if ((res.end - res.start) > PAGE_SIZE) {
> + pr_err("L2 reg size > PAGE_SIZE\n");

Why do you care?

> + return 0;
> + }
> +
> + l2_regs_addr = res.start;
> + } else {
> + l2_regs_addr = (phys_addr_t) __rm_firmware_regs_start;
> + }
> +
> + if (!IS_ALIGNED(l2_regs_addr, PAGE_SIZE)) {
> + pr_err("Registers not aligned on PAGE_SIZE\n");

So?

If you have constraints, put those in the DT schema for this device and
validate your DT. The kernel doesn't need to validate the DT.

> + return 0;
> + }
> +
> + return l2_regs_addr;
> +}
> +
> +static int __init l2_cache_init(void)
> +{
> + int ret = -ENODEV;
> + struct device_node *np;
> + phys_addr_t l2_regs_addr;
> +
> + np = of_find_compatible_node(NULL, NULL, "kalray,kvx-l2-cache");

Needs to be documented.

> + if (!np || !of_device_is_available(np)) {
> + if (!IS_ENABLED(CONFIG_SMP)) {
> + pr_info("controller disabled\n");
> + return 0;
> + }
> +
> + if (np && of_get_property(np, "kalray,is-qemu", NULL)) {

Make your compatible strings specific enough to detect this rather than
a flag.

> + /*
> + * QEMU is always full cache coherent. The L2 cache controller is
> + * not strictly necessary to ensure coherency in SMP.
> + */
> + pr_info("controller disabled (QEMU detected)\n");
> + return 0;
> + }
> +
> + /* Else, SMP is enabled and L2 is mandatory for it */
> + goto err;
> + }
> +
> + l2_regs_addr = l2_get_regs_addr(np);
> + if (!l2_regs_addr)
> + goto err;
> +
> + /* Map the L2 registers */
> + l2c_ctrl.regs = ioremap(l2_regs_addr, PAGE_SIZE);
> + if (!l2c_ctrl.regs)
> + goto err;
> +
> + /* Lock this entry into the LTLB */
> + kvx_mmu_ltlb_add_entry((unsigned long) l2c_ctrl.regs, l2_regs_addr,
> + PAGE_KERNEL_NOCACHE, TLB_PS_4K);
> +
> + ret = l2_cache_init_hw();
> + if (ret) {
> + pr_err("Failed to init L2 cache controller");
> + goto err_unmap_l2;
> + }
> +
> + static_branch_enable(&l2_enabled);
> +
> + pr_info("controller enabled\n");
> +
> + return 0;
> +
> +err_unmap_l2:
> + kvx_mmu_ltlb_remove_entry((unsigned long) l2c_ctrl.regs);
> + iounmap(l2c_ctrl.regs);
> +err:
> + if (IS_ENABLED(CONFIG_SMP))
> + panic("L2$ controller is mandatory for SMP");
> +
> + return ret;
> +}
> +
> +
> +early_initcall(l2_cache_init);
> diff --git a/arch/kvx/kernel/smp.c b/arch/kvx/kernel/smp.c
> new file mode 100644
> index 000000000000..ed4c35a8c4bc
> --- /dev/null
> +++ b/arch/kvx/kernel/smp.c
> @@ -0,0 +1,110 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2017-2023 Kalray Inc.
> + * Author(s): Clement Leger
> + */
> +
> +#include <linux/smp.h>
> +#include <linux/cpu.h>
> +#include <linux/of_irq.h>
> +#include <linux/cpumask.h>
> +#include <linux/irq_work.h>
> +#include <linux/mm_types.h>
> +#include <linux/interrupt.h>
> +
> +#include <asm/ipi.h>
> +#include <asm/tlbflush.h>
> +
> +enum ipi_message_type {
> + IPI_RESCHEDULE,
> + IPI_CALL_FUNC,
> + IPI_IRQ_WORK,
> + IPI_MAX
> +};
> +
> +/* A collection of single bit ipi messages. */
> +static struct {
> + unsigned long bits ____cacheline_aligned;
> +} ipi_data[NR_CPUS] __cacheline_aligned;
> +
> +static void send_ipi_message(const struct cpumask *mask,
> + enum ipi_message_type operation)
> +{
> + unsigned long flags;
> + int cpu;
> +
> + /* Set operation that must be done by receiver */
> + for_each_cpu(cpu, mask)
> + set_bit(operation, &ipi_data[cpu].bits);
> +
> + /* Commit the write before sending IPI */
> + smp_wmb();
> +
> + local_irq_save(flags);
> +
> + kvx_ipi_send(mask);
> +
> + local_irq_restore(flags);
> +}
> +
> +void arch_send_call_function_ipi_mask(struct cpumask *mask)
> +{
> + send_ipi_message(mask, IPI_CALL_FUNC);
> +}
> +
> +void arch_send_call_function_single_ipi(int cpu)
> +{
> + send_ipi_message(cpumask_of(cpu), IPI_CALL_FUNC);
> +}
> +
> +#ifdef CONFIG_IRQ_WORK
> +void arch_irq_work_raise(void)
> +{
> + send_ipi_message(cpumask_of(smp_processor_id()), IPI_IRQ_WORK);
> +}
> +#endif
> +
> +static void ipi_stop(void *unused)
> +{
> + local_cpu_stop();
> +}
> +
> +void smp_send_stop(void)
> +{
> + struct cpumask targets;
> +
> + cpumask_copy(&targets, cpu_online_mask);
> + cpumask_clear_cpu(smp_processor_id(), &targets);
> +
> + smp_call_function_many(&targets, ipi_stop, NULL, 0);
> +}
> +
> +void smp_send_reschedule(int cpu)
> +{
> + send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE);
> +}
> +
> +irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
> +{
> + unsigned long *pending_ipis = &ipi_data[smp_processor_id()].bits;
> +
> + while (true) {
> + unsigned long ops = xchg(pending_ipis, 0);
> +
> + if (ops == 0)
> + return IRQ_HANDLED;
> +
> + if (ops & (1 << IPI_RESCHEDULE))
> + scheduler_ipi();
> +
> + if (ops & (1 << IPI_CALL_FUNC))
> + generic_smp_call_function_interrupt();
> +
> + if (ops & (1 << IPI_IRQ_WORK))
> + irq_work_run();
> +
> + BUG_ON((ops >> IPI_MAX) != 0);
> + }
> +
> + return IRQ_HANDLED;
> +}
> diff --git a/arch/kvx/kernel/smpboot.c b/arch/kvx/kernel/smpboot.c
> new file mode 100644
> index 000000000000..987a6f014163
> --- /dev/null
> +++ b/arch/kvx/kernel/smpboot.c
> @@ -0,0 +1,127 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2017-2023 Kalray Inc.
> + * Author(s): Clement Leger
> + * Julian Vetter
> + */
> +
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +
> +#include <linux/io.h>
> +#include <linux/of.h>
> +#include <linux/smp.h>
> +#include <linux/cpu.h>
> +#include <linux/sched.h>
> +#include <linux/cpumask.h>
> +#include <linux/sched/mm.h>
> +#include <linux/mm_types.h>
> +#include <linux/of_platform.h>

Don't think this is needed.

> +#include <linux/sched/task_stack.h>
> +
> +#include <asm/pwr_ctrl.h>
> +#include <asm/tlbflush.h>
> +#include <asm/ipi.h>
> +
> +void *__cpu_up_stack_pointer[NR_CPUS];
> +void *__cpu_up_task_pointer[NR_CPUS];
> +
> +void __init smp_prepare_boot_cpu(void)
> +{
> +}
> +
> +int __cpu_up(unsigned int cpu, struct task_struct *tidle)
> +{
> + __cpu_up_stack_pointer[cpu] = task_stack_page(tidle) + THREAD_SIZE;
> + __cpu_up_task_pointer[cpu] = tidle;
> + /* We need to be sure writes are committed */
> + smp_mb();
> +
> + kvx_pwr_ctrl_cpu_poweron(cpu);
> + while (!cpu_online(cpu))
> + cpu_relax();
> +
> + return 0;
> +}
> +
> +void __init smp_cpus_done(unsigned int max_cpus)
> +{
> +}
> +
> +void __init smp_init_cpus(void)
> +{
> + struct cpumask cpumask;
> + struct device_node *cpu;
> + const __be32 *reg;
> + u32 cpu_num;
> + unsigned int nr_cpus = 0;
> +
> + cpumask_clear(&cpumask);
> +
> + for_each_of_cpu_node(cpu) {
> + if (!of_device_is_available(cpu))
> + continue;
> +
> + reg = of_get_property(cpu, "reg", NULL);

Use of_get_cpu_hwid()

> + if (!reg)
> + continue;
> +
> + cpu_num = be32_to_cpup(reg);
> + if (cpu_num >= nr_cpu_ids)
> + continue;
> +
> + nr_cpus++;
> + cpumask_set_cpu(cpu_num, &cpumask);

Why not just do set_cpu_possible() directly instead of the temp cpumask.

> + }
> +
> + pr_info("%d possible cpus\n", nr_cpus);
> + init_cpu_possible(&cpumask);
> +}
> +
> +void __init smp_prepare_cpus(unsigned int max_cpus)
> +{
> + if (num_present_cpus() <= 1)
> + init_cpu_present(cpu_possible_mask);
> +}
> +
> +int __init setup_smp(void)
> +{
> + int ret;
> +
> + ret = kvx_pwr_ctrl_probe();
> + if (ret)
> + panic("Failed to probe power controller !");
> +
> + ret = kvx_ipi_ctrl_probe(ipi_call_interrupt);
> + if (ret)
> + panic("Failed to probe IPI controller !");
> +
> + return 0;
> +}
> +
> +early_initcall(setup_smp);
> +
> +/*
> + * C entry point for a secondary processor.
> + */
> +void __init start_kernel_secondary(void)
> +{
> + struct mm_struct *mm = &init_mm;
> + unsigned int cpu = smp_processor_id();
> +
> + setup_processor();
> + kvx_mmu_early_setup();
> +
> + /* All kernel threads share the same mm context. */
> + mmgrab(mm);
> + current->active_mm = mm;
> + cpumask_set_cpu(cpu, mm_cpumask(mm));
> +
> + notify_cpu_starting(cpu);
> + set_cpu_online(cpu, true);
> + trace_hardirqs_off();
> +
> + local_flush_tlb_all();
> +
> + local_irq_enable();
> + cpu_startup_entry(CPUHP_AP_ONLINE_IDLE);
> +}
> diff --git a/arch/kvx/platform/pwr_ctrl.c b/arch/kvx/platform/pwr_ctrl.c
> new file mode 100644
> index 000000000000..64c86cd18695
> --- /dev/null
> +++ b/arch/kvx/platform/pwr_ctrl.c
> @@ -0,0 +1,93 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2017-2023 Kalray Inc.
> + * Author(s): Clement Leger
> + */
> +
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +
> +#include <linux/io.h>
> +#include <linux/slab.h>
> +#include <linux/types.h>
> +#include <linux/module.h>
> +#include <linux/of_address.h>
> +#include <linux/of_platform.h>
> +
> +#include <asm/pwr_ctrl.h>
> +#include <asm/symbols.h>
> +
> +struct kvx_pwr_ctrl {
> + void __iomem *regs;
> +};
> +
> +static struct kvx_pwr_ctrl kvx_pwr_controller;
> +
> +/**
> + * kvx_pwr_ctrl_cpu_poweron() - Wakeup a cpu
> + * @cpu: cpu to wakeup
> + */
> +void kvx_pwr_ctrl_cpu_poweron(unsigned int cpu)
> +{
> + /* Set PE boot address */
> + writeq((unsigned long long)kvx_start,
> + kvx_pwr_controller.regs + KVX_PWR_CTRL_RESET_PC_OFFSET);
> + /* Wake up processor ! */
> + writeq(1ULL << cpu,
> + kvx_pwr_controller.regs + PWR_CTRL_WUP_SET_OFFSET);
> + /* Then clear wakeup to allow processor to sleep */
> + writeq(1ULL << cpu,
> + kvx_pwr_controller.regs + PWR_CTRL_WUP_CLEAR_OFFSET);
> +}
> +
> +static struct device_node * __init get_pwr_ctrl_node(void)
> +{
> + const phandle *ph;
> + struct device_node *cpu;
> + struct device_node *node;
> +
> + cpu = of_get_cpu_node(raw_smp_processor_id(), NULL);
> + if (!cpu) {
> + pr_err("Failed to get CPU node\n");
> + return NULL;
> + }
> +
> + ph = of_get_property(cpu, "power-controller", NULL);

Not a standard property.

> + if (!ph) {
> + pr_err("Failed to get power-controller phandle\n");
> + return NULL;
> + }
> +
> + node = of_find_node_by_phandle(be32_to_cpup(ph));
> + if (!node) {
> + pr_err("Failed to get power-controller node\n");
> + return NULL;
> + }
> +
> + return node;
> +}
> +
> +int __init kvx_pwr_ctrl_probe(void)
> +{
> + struct device_node *ctrl;
> +
> + ctrl = get_pwr_ctrl_node();
> + if (!ctrl) {
> + pr_err("Failed to get power controller node\n");
> + return -EINVAL;
> + }
> +
> + if (!of_device_is_compatible(ctrl, "kalray,kvx-pwr-ctrl")) {

Needs to be documented...

> + pr_err("Failed to get power controller node\n");
> + return -EINVAL;
> + }
> +
> + kvx_pwr_controller.regs = of_iomap(ctrl, 0);
> + if (!kvx_pwr_controller.regs) {
> + pr_err("Failed ioremap\n");
> + return -EINVAL;
> + }
> +
> + pr_info("kvx power controller probed\n");

Drop success messages.

> +
> + return 0;
> +}
> diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
> index f61447913db9..f5a484547b15 100644
> --- a/include/linux/cpuhotplug.h
> +++ b/include/linux/cpuhotplug.h
> @@ -152,6 +152,7 @@ enum cpuhp_state {
> CPUHP_AP_IRQ_RISCV_STARTING,
> CPUHP_AP_IRQ_LOONGARCH_STARTING,
> CPUHP_AP_IRQ_SIFIVE_PLIC_STARTING,
> + CPUHP_AP_IRQ_KVX_STARTING,
> CPUHP_AP_ARM_MVEBU_COHERENCY,
> CPUHP_AP_MICROCODE_LOADER,
> CPUHP_AP_PERF_X86_AMD_UNCORE_STARTING,
> @@ -189,6 +190,7 @@ enum cpuhp_state {
> CPUHP_AP_KVM_ARM_VGIC_INIT_STARTING,
> CPUHP_AP_KVM_ARM_VGIC_STARTING,
> CPUHP_AP_KVM_ARM_TIMER_STARTING,
> + CPUHP_AP_KVX_TIMER_STARTING,
> /* Must be the last timer callback */
> CPUHP_AP_DUMMY_TIMER_STARTING,
> CPUHP_AP_ARM_XEN_STARTING,
> --
> 2.37.2
>
>
>
>
>
>

2023-01-04 15:33:03

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [RFC PATCH 12/25] kvx: Add system call support

On Tue, Jan 3, 2023, at 17:43, Yann Sionneau wrote:

> +
> +/*
> + * Ensure that the range [addr, addr+size) is within the process's
> + * address space
> + */
> +static inline int __access_ok(unsigned long addr, unsigned long size)
> +{
> + return size <= TASK_SIZE && addr <= TASK_SIZE - size;
> +}

This is the same as the generic version, so just use that instead.

> +#define HAVE_GET_KERNEL_NOFAULT
> +
> +#define __get_kernel_nofault(dst, src, type, err_label) \
> +do { \
> + long __kr_err; \
> + \
> + __get_user_nocheck(*((type *)(dst)), (type *)(src), __kr_err); \
> + if (unlikely(__kr_err)) \
> + goto err_label; \
> +} while (0)
> +
> +#define __put_kernel_nofault(dst, src, type, err_label) \
> +do { \
> + long __kr_err; \
> + \
> + __put_user_nocheck(*((type *)(src)), (type *)(dst), __kr_err); \
> + if (unlikely(__kr_err)) \
> + goto err_label; \
> +} while (0)

The wrapper around __get_user_nocheck/__put_user_nocheck
is not ideal here. Since I think you only support new
compilers anyway, you can use the asm-goto-with-output feature
to define the asm to branch to the label directly, and use
the same thing to build __get_user()/__put_user().

> +++ b/arch/kvx/include/uapi/asm/unistd.h
> @@ -0,0 +1,16 @@

> +
> +#define __ARCH_WANT_RENAMEAT
> +#define __ARCH_WANT_NEW_STAT
> +#define __ARCH_WANT_SET_GET_RLIMIT
> +#define __ARCH_WANT_SYS_CLONE3

It's good to have clone3() but the other three sets
of syscalls should no longer be defined for new architectures,
so please remove those.

Arnd

2023-01-04 16:12:28

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [RFC PATCH 00/25] Upstream kvx Linux port

On Tue, Jan 3, 2023, at 17:43, Yann Sionneau wrote:
> This patch series adds support for the kv3-1 CPU architecture of the kvx family
> found in the Coolidge (aka MPPA3-80) SoC of Kalray.
>
> This is an RFC, since kvx support is not yet upstreamed into gcc/binutils,
> therefore this patch series cannot be merged into Linux for now.
>
> The goal is to have preliminary reviews and to fix problems early.
>
> The Kalray VLIW processor family (kvx) has the following features:
> * 32/64 bits execution mode
> * 6-issue VLIW architecture
> * 64 x 64bits general purpose registers
> * SIMD instructions
> * little-endian
> * deep learning co-processor

Thanks for posting these, I had been wondering about the
state of the port. Overall this looks really nice, I can
see that you and the team have looked at other ports
and generally made the right decisions.

I commented on the syscall patch directly, I think it's
important to stop using the deprecated syscalls as soon
as possible to avoid having dependencies in too many
libc binaries. Almost everything else can be changed
easily as you get closer to upstream inclusion.

I did not receive most of the other patches as I'm
not subscribed to all the mainline lists. For future
submissions, can you add the linux-arch list to Cc for
all patches?

Reading the rest of the series through lore.kernel.org,
most of the comments I have are for improvements that
you may find valuable rather than serious mistakes:

- the {copy_to,copy_from,clear}_user functions are
well worth optimizing better than the byte-at-a-time
version you have, even just a C version built around
your __get_user/__put_user inline asm should help, and
could be added to lib/usercopy.c.

- The __raw_{read,write}{b,w,l,q} helpers should
normally be defined as inline asm instead of
volatile pointer dereferences, I've seen cases where
the compiler ends up splitting the access or does
other things you may not want on MMIO areas.

- I would recomment implementing HAVE_ARCH_VMAP_STACK
as well as IRQ stacks, both of these help to
avoid data corruption from stack overflow that you
will eventually run into.

- You use qspinlock as the only available spinlock
implementation, but only support running on a
single cluster of 16 cores. It may help to use
the generic ticket spinlock instead, or leave it
as a Kconfig option, in particular since you only
have the emulated xchg16() atomic for qspinlock.

- Your defconfig file enables CONFIG_EMBEDDED, which
in turn enables CONFIG_EXPERT. This is probably
not what you want, so better turn off both of these.

- The GENERIC_CALIBRATE_DELAY should not be necessary
since you have a get_cycles() based delay loop.
Just set loops_per_jiffy to the correct value based
on the frequency of the cycle counter, to save
a little time during boot and get a more accurate
delay loop.

Arnd

2023-01-04 18:15:22

by Sebastian Reichel

[permalink] [raw]
Subject: Re: [RFC PATCH 19/25] kvx: power: scall poweroff driver

Hi,

On Tue, Jan 03, 2023 at 05:43:53PM +0100, Yann Sionneau wrote:
> Add a driver to poweroff the Coolidge SoC
> when running under Qemu, ISS or when
> the debugger (jtag-runner) runs on PL0
> to catch the scall.

line length of 41 characters is quite short.

> CC: Sebastian Reichel <[email protected]>
> CC: [email protected]
> CC: [email protected]
> Co-developed-by: Clement Leger <[email protected]>
> Signed-off-by: Clement Leger <[email protected]>
> Co-developed-by: Julian Vetter <[email protected]>
> Signed-off-by: Julian Vetter <[email protected]>
> Signed-off-by: Yann Sionneau <[email protected]>
> ---
> drivers/power/reset/kvx-scall-poweroff.c | 53 ++++++++++++++++++++++++
> 1 file changed, 53 insertions(+)
> create mode 100644 drivers/power/reset/kvx-scall-poweroff.c
>
> diff --git a/drivers/power/reset/kvx-scall-poweroff.c b/drivers/power/reset/kvx-scall-poweroff.c
> new file mode 100644
> index 000000000000..586d93fbcaed
> --- /dev/null
> +++ b/drivers/power/reset/kvx-scall-poweroff.c
> @@ -0,0 +1,53 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (c) 2017 - 2022 Kalray Inc.
> + * Author(s): Clement Leger
> + */
> +
> +#include <linux/pm.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +
> +#define SCALL_NUM_EXIT "0xfff"
> +
> +static void kvx_scall_poweroff(void)
> +{
> + register int status asm("r0") = 0;
> +
> + asm volatile ("scall " SCALL_NUM_EXIT "\n\t;;"
> + : /* out */
> + : "r"(status));
> +
> + unreachable();
> +}
> +
> +static int kvx_scall_poweroff_probe(struct platform_device *pdev)
> +{
> + pm_power_off = kvx_scall_poweroff;
> +
> + return 0;
> +}

Please use devm_register_power_off_handler().

-- Sebastian

> +static int kvx_scall_poweroff_remove(struct platform_device *pdev)
> +{
> + if (pm_power_off == kvx_scall_poweroff)
> + pm_power_off = NULL;
> +
> + return 0;
> +}
> +
> +static const struct of_device_id kvx_scall_poweroff_of_match[] = {
> + { .compatible = "kalray,kvx-scall-poweroff" },
> + {}
> +};
> +
> +static struct platform_driver kvx_scall_poweroff_driver = {
> + .probe = kvx_scall_poweroff_probe,
> + .remove = kvx_scall_poweroff_remove,
> + .driver = {
> + .name = "kvx-scall-poweroff",
> + .of_match_table = kvx_scall_poweroff_of_match,
> + },
> +};
> +module_platform_driver(kvx_scall_poweroff_driver);
> --
> 2.37.2
>
>
>
>
>


Attachments:
(No filename) (2.48 kB)
signature.asc (849.00 B)
Download all attachments

2023-01-05 08:16:05

by Clément Léger

[permalink] [raw]
Subject: Re: [RFC PATCH 17/25] kvx: Add multi-processor (SMP) support

Le Tue, 3 Jan 2023 17:43:51 +0100,
Yann Sionneau <[email protected]> a écrit :

> Coolidge v1 SoC has 5 clusters of 16 kvx cores
> (+1 special Resource Manager (RM) core).
>
> Linux can run in SMP config on the 16 cores of
> a Cluster.
>
> Cache coherency is done by the L2 cache.
>
> CC: [email protected]
> Co-developed-by: Clement Leger <[email protected]>
> Signed-off-by: Clement Leger <[email protected]>
> Co-developed-by: Julian Vetter <[email protected]>
> Signed-off-by: Julian Vetter <[email protected]>
> Co-developed-by: Julien Hascoet <[email protected]>
> Signed-off-by: Julien Hascoet <[email protected]>
> Co-developed-by: Louis Morhet <[email protected]>
> Signed-off-by: Louis Morhet <[email protected]>
> Co-developed-by: Luc Michel <[email protected]>
> Signed-off-by: Luc Michel <[email protected]>
> Co-developed-by: Marius Gligor <[email protected]>
> Signed-off-by: Marius Gligor <[email protected]>
> Co-developed-by: Yann Sionneau <[email protected]>
> Signed-off-by: Yann Sionneau <[email protected]>
> ---
> arch/kvx/include/asm/pwr_ctrl.h | 45 ++++
> arch/kvx/include/asm/smp.h | 42 +++
> arch/kvx/kernel/l2_cache.c | 448 ++++++++++++++++++++++++++++++++
> arch/kvx/kernel/smp.c | 110 ++++++++
> arch/kvx/kernel/smpboot.c | 127 +++++++++
> arch/kvx/platform/pwr_ctrl.c | 93 +++++++
> include/linux/cpuhotplug.h | 2 +
> 7 files changed, 867 insertions(+)
> create mode 100644 arch/kvx/include/asm/pwr_ctrl.h
> create mode 100644 arch/kvx/include/asm/smp.h
> create mode 100644 arch/kvx/kernel/l2_cache.c
> create mode 100644 arch/kvx/kernel/smp.c
> create mode 100644 arch/kvx/kernel/smpboot.c
> create mode 100644 arch/kvx/platform/pwr_ctrl.c
>
> diff --git a/arch/kvx/include/asm/pwr_ctrl.h b/arch/kvx/include/asm/pwr_ctrl.h
> new file mode 100644
> index 000000000000..25f403ba935a
> --- /dev/null
> +++ b/arch/kvx/include/asm/pwr_ctrl.h
> @@ -0,0 +1,45 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (C) 2017-2023 Kalray Inc.
> + * Author(s): Clement Leger
> + * Marius Gligor
> + */
> +
> +#ifndef _ASM_KVX_PWR_CTRL_H
> +#define _ASM_KVX_PWR_CTRL_H
> +
> +#ifndef __ASSEMBLY__
> +
> +int kvx_pwr_ctrl_probe(void);
> +
> +void kvx_pwr_ctrl_cpu_poweron(unsigned int cpu);
> +
> +#endif
> +
> +/* Power controller vector register definitions */
> +#define KVX_PWR_CTRL_VEC_OFFSET 0x1000
> +#define KVX_PWR_CTRL_VEC_WUP_SET_OFFSET 0x10
> +#define KVX_PWR_CTRL_VEC_WUP_CLEAR_OFFSET 0x20
> +
> +/* Power controller PE reset PC register definitions */
> +#define KVX_PWR_CTRL_RESET_PC_OFFSET 0x2000
> +
> +/* Power controller global register definitions */
> +#define KVX_PWR_CTRL_GLOBAL_OFFSET 0x4040
> +
> +#define KVX_PWR_CTRL_GLOBAL_SET_OFFSET 0x10
> +#define KVX_PWR_CTRL_GLOBAL_SET_PE_EN_SHIFT 0x1
> +
> +#define PWR_CTRL_WUP_SET_OFFSET \
> + (KVX_PWR_CTRL_VEC_OFFSET + \
> + KVX_PWR_CTRL_VEC_WUP_SET_OFFSET)
> +
> +#define PWR_CTRL_WUP_CLEAR_OFFSET \
> + (KVX_PWR_CTRL_VEC_OFFSET + \
> + KVX_PWR_CTRL_VEC_WUP_CLEAR_OFFSET)
> +
> +#define PWR_CTRL_GLOBAL_CONFIG_OFFSET \
> + (KVX_PWR_CTRL_GLOBAL_OFFSET + \
> + KVX_PWR_CTRL_GLOBAL_SET_OFFSET)
> +
> +#endif /* _ASM_KVX_PWR_CTRL_H */
> diff --git a/arch/kvx/include/asm/smp.h b/arch/kvx/include/asm/smp.h
> new file mode 100644
> index 000000000000..e4fd4d001b2c
> --- /dev/null
> +++ b/arch/kvx/include/asm/smp.h
> @@ -0,0 +1,42 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (C) 2017-2023 Kalray Inc.
> + * Author(s): Clement Leger
> + */
> +
> +#ifndef _ASM_KVX_SMP_H
> +#define _ASM_KVX_SMP_H
> +
> +#include <linux/cpumask.h>
> +#include <linux/irqreturn.h>
> +
> +#include <asm/sfr.h>
> +
> +#ifdef CONFIG_SMP
> +
> +/* Hook for the generic smp_call_function_many() routine. */
> +void arch_send_call_function_ipi_mask(struct cpumask *mask);
> +
> +/* Hook for the generic smp_call_function_single() routine. */
> +void arch_send_call_function_single_ipi(int cpu);
> +
> +void __init setup_processor(void);
> +
> +void smp_init_cpus(void);
> +
> +irqreturn_t ipi_call_interrupt(int irq, void *dev_id);
> +
> +#define raw_smp_processor_id() ((int) \
> + ((kvx_sfr_get(PCR) & KVX_SFR_PCR_PID_MASK) \
> + >> KVX_SFR_PCR_PID_SHIFT))
> +
> +#define flush_cache_vmap(start, end) do { } while (0)
> +#define flush_cache_vunmap(start, end) do { } while (0)
> +
> +#else
> +
> +void smp_init_cpus(void) {}
> +
> +#endif /* CONFIG_SMP */
> +
> +#endif
> diff --git a/arch/kvx/kernel/l2_cache.c b/arch/kvx/kernel/l2_cache.c
> new file mode 100644
> index 000000000000..94a4d9159471
> --- /dev/null
> +++ b/arch/kvx/kernel/l2_cache.c
> @@ -0,0 +1,448 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2017-2023 Kalray Inc.
> + * Author(s): Clement Leger
> + * Luc Michel
> + * Julien Hascoet
> + */
> +
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +
> +#include <linux/io.h>
> +#include <linux/of.h>
> +#include <linux/jiffies.h>
> +#include <linux/of_address.h>
> +#include <linux/irqchip/irq-kvx-apic-mailbox.h>
> +
> +#include <asm/rm_fw.h>
> +#include <asm/l2_cache.h>
> +#include <asm/sections.h>
> +#include <asm/cacheflush.h>
> +
> +#define L2_START_TIMEOUT_MS 10
> +#define L2_CMD_TIMEOUT_MS 200
> +
> +#define L2_MK_OP(__cmd, __sync) (BIT(L2_CMD_OP_VALID_SHIFT) | \
> + ((u64) __sync << L2_CMD_OP_SYNC_SHIFT) | \
> + ((u64) __cmd << L2_CMD_OP_CMD_SHIFT))
> +
> +#define L2_ERROR(_err) \
> + ((error & L2_ERROR_ERROR_CODE_MASK) >> L2_ERROR_ERROR_CODE_SHIFT)
> +
> +struct l2_cache_hw_cmd {
> + u64 op;
> + u64 args[L2_CMD_OP_ARG_COUNT];
> +} __packed;
> +
> +struct l2_cache_cmd {
> + int sync;
> + int cmd_type;
> + unsigned int arg_count;
> + u64 args[L2_CMD_OP_ARG_COUNT];
> +};
> +
> +/**
> + * struct l2_cached_data - Data associated to the l2-cache
> + * @regs: base of L2 registers
> + * @mbox_regs: Mailbox registers for L2 signaling
> + */
> +struct l2_cache_data {
> + void __iomem *regs;
> + void __iomem *mbox_regs;
> + u64 fifo_cmd_count;
> +};
> +
> +DEFINE_STATIC_KEY_FALSE(l2_enabled);
> +static struct l2_cache_data l2c_ctrl;
> +
> +static void *l2_cmd_regs_addr(void)
> +{
> + return l2c_ctrl.regs + L2_CMD_OFFSET;
> +}
> +
> +static struct l2_cache_hw_cmd *l2_cache_hw_cmd_addr(u64 idx)
> +{
> + void *cmd_regs = l2_cmd_regs_addr();
> +
> + /* Wrap index */
> + idx &= (l2c_ctrl.fifo_cmd_count - 1);
> + return cmd_regs + L2_CMD_FIFO_OFFSET + idx * L2_CMD_FIFO_ELEM_SIZE;
> +}
> +
> +static u64 l2_cache_get_cmd_idx(unsigned int cmd_count)
> +{
> + u64 cmd_idx;
> + void *cmd_regs = l2_cmd_regs_addr();
> + u64 *write_idx_ptr = cmd_regs + L2_CMD_WRITE_IDX_OFFSET;
> + u64 *read_idx_ptr = cmd_regs + L2_CMD_READ_IDX_OFFSET;
> +
> + /* Grab a commands tickets */
> + cmd_idx = __builtin_kvx_aladdd(write_idx_ptr, cmd_count);
> +
> + /* Wait until there is room in command fifo to enqueue commands */
> + while ((cmd_idx + cmd_count) >=
> + (readq(read_idx_ptr) + l2c_ctrl.fifo_cmd_count))
> + cpu_relax();
> +
> + return cmd_idx;
> +}
> +
> +static void l2_wait_completion(u64 cmd_idx)
> +{
> + u64 *read_idx_ptr = l2_cmd_regs_addr() + L2_CMD_READ_IDX_OFFSET;
> + unsigned long timeout = jiffies + msecs_to_jiffies(L2_CMD_TIMEOUT_MS);
> +
> + /* Wait for completion */
> + while (cmd_idx >= readq(read_idx_ptr)) {
> + cpu_relax();
> + if (time_after(jiffies, timeout))
> + panic("L2 cache completion timeout\n");
> + }
> +}
> +
> +static u64 l2_cache_push_cmds(struct l2_cache_cmd *cmds, int cmd_count)
> +{
> + int i, arg;
> + u64 cmd_op;
> + struct l2_cache_hw_cmd *cmd;
> + struct l2_cache_cmd *soft_cmd;
> + u64 cmd_idx = l2_cache_get_cmd_idx(cmd_count);
> +
> + for (i = 0; i < cmd_count; i++) {
> + soft_cmd = &cmds[i];
> + cmd = l2_cache_hw_cmd_addr(cmd_idx);
> + cmd_idx++;
> +
> + for (arg = 0; arg < soft_cmd->arg_count; arg++)
> + writeq_relaxed(soft_cmd->args[arg], &cmd->args[arg]);
> +
> + cmd_op = L2_MK_OP(soft_cmd->cmd_type, soft_cmd->sync);
> + writeq(cmd_op, &cmd->op);
> + }
> +
> + return cmd_idx - 1;
> +}
> +
> +static void l2_cache_create_line_cmd(struct l2_cache_cmd *cmd, int cmd_type,
> + int sync, u64 addr)
> +{
> + cmd->cmd_type = cmd_type;
> + cmd->sync = sync;
> + cmd->arg_count = 1;
> + cmd->args[0] = addr;
> +}
> +
> +static void l2_cache_create_area_cmd(struct l2_cache_cmd *cmd, int cmd_type,
> + int sync, u64 addr, u64 size)
> +{
> + l2_cache_create_line_cmd(cmd, cmd_type, sync, addr);
> + cmd->arg_count = 2;
> + cmd->args[1] = size;
> +}
> +
> +static void l2_cache_push_inval_cmd(phys_addr_t start,
> + unsigned long size)
> +{
> + phys_addr_t end = start + size;
> + struct l2_cache_cmd cmds[3];
> + unsigned long irq_flags;
> + int cmd_count = 0;
> + u64 cmd_idx;
> +
> + /*
> + * In case of invalidation, we must make sure we do not invalidate
> + * unwanted area and thus discard legit data. In case we are not aligned
> + * send a purge line command (writeback + inval) to unaligned lines
> + * (which can be the end line or the start line)
> + */
> + if (!IS_ALIGNED(end, L2_CACHE_LINE_SIZE)) {
> + end &= ~L2_CACHE_LINE_MASK;
> + l2_cache_create_line_cmd(&cmds[cmd_count],
> + L2_CMD_OP_CMD_PURGE_LINE, 1, end);
> + cmd_count++;
> + }
> +
> + if (!IS_ALIGNED(start, L2_CACHE_LINE_SIZE)) {
> + start &= ~L2_CACHE_LINE_MASK;
> + /* If there is at least another line to clear */
> + if (end != start) {
> + l2_cache_create_line_cmd(&cmds[cmd_count],
> + L2_CMD_OP_CMD_PURGE_LINE, 1,
> + start);
> + cmd_count++;
> + start += L2_CACHE_LINE_SIZE;
> + }
> + }
> +
> + BUG_ON(end < start);
> +
> + size = (end - start);
> + if (size > 0) {
> + l2_cache_create_area_cmd(&cmds[cmd_count],
> + L2_CMD_OP_CMD_INVAL_AREA, 1, start,
> + size);
> + cmd_count++;
> + }
> +
> + BUG_ON(cmd_count == 0);
> +
> + local_irq_save(irq_flags);
> +
> + cmd_idx = l2_cache_push_cmds(cmds, cmd_count);
> +
> + /* Finally, ping the L2 cache controller */
> + writeq(1, l2c_ctrl.mbox_regs);
> +
> + local_irq_restore(irq_flags);
> +
> + l2_wait_completion(cmd_idx);
> +}
> +
> +static void l2_cache_push_generic_cmd(u64 cmd_type, phys_addr_t start,
> + unsigned long size)
> +{
> + unsigned long irq_flags;
> + struct l2_cache_cmd cmd;
> + u64 cmd_idx;
> +
> + /* Align the start address and size on cache line */
> + size += start & (L2_CACHE_LINE_SIZE - 1);
> + size = ALIGN(size, L2_CACHE_LINE_SIZE);
> + start = ALIGN_DOWN(start, L2_CACHE_LINE_SIZE);
> +
> + local_irq_save(irq_flags);
> +
> + l2_cache_create_area_cmd(&cmd, cmd_type, 1, start, size);
> + cmd_idx = l2_cache_push_cmds(&cmd, 1);
> +
> + /* Finally, ping the L2 cache controller */
> + writeq(1, l2c_ctrl.mbox_regs);
> +
> + local_irq_restore(irq_flags);
> +
> + l2_wait_completion(cmd_idx);
> +}
> +
> +void l2_cache_push_area_cmd(u64 cmd_type, phys_addr_t start,
> + unsigned long size)
> +{
> + if (WARN_ON(size == 0))
> + return;
> +
> + if (cmd_type == L2_CMD_OP_CMD_INVAL_AREA)
> + l2_cache_push_inval_cmd(start, size);
> + else
> + l2_cache_push_generic_cmd(cmd_type, start, size);
> +}
> +
> +static void __init l2_disp_error(u64 error)
> +{
> + const char *err_type;
> +
> + if (error & L2_ERROR_API_ERR_MASK)
> + err_type = "API";
> + else if (error & L2_ERROR_SETUP_ERR_MASK)
> + err_type = "SETUP";
> + else
> + err_type = "UNKNOWN";
> +
> + pr_err("%s error: 0x%llx\n", err_type, L2_ERROR(error));
> +}
> +
> +static int __init l2_cache_configure_mailboxes(void)
> +{
> + phys_addr_t l2_mbox_addr = 0;
> + void *cmd_regs = l2_cmd_regs_addr();
> +
> + /* We do not use mailbox to wait for completion, set it to 0 */
> + writeq(0, cmd_regs + L2_CMD_DOORBELL_READ_ADDR_OFFSET);
> +
> + /* Read mailbox address from L2 registers */
> + l2_mbox_addr = readq(cmd_regs + L2_CMD_DOORBELL_WRITE_ADDR_OFFSET);
> +
> + /* Then map the mailbox */
> + l2c_ctrl.mbox_regs = ioremap(l2_mbox_addr, PAGE_SIZE);
> + if (!l2c_ctrl.mbox_regs) {
> + pr_err("Failed to map mailbox\n");
> + return 1;
> + }
> +
> + /* Lock this entry into the LTLB */
> + kvx_mmu_ltlb_add_entry((unsigned long) l2c_ctrl.mbox_regs & PAGE_MASK,
> + l2_mbox_addr & PAGE_MASK,
> + PAGE_KERNEL_DEVICE, TLB_PS_4K);
> +
> + return 0;
> +}
> +
> +static int __init l2_cache_read_queue_size(void)
> +{
> + u64 inst;
> +
> + /* Read command queue size */
> + inst = readq(l2c_ctrl.regs + L2_INSTANCE_OFFSET);
> + l2c_ctrl.fifo_cmd_count = (inst & L2_INSTANCE_CMD_QUEUE_SIZE_MASK)
> + >> L2_INSTANCE_CMD_QUEUE_SIZE_SHIFT;
> +
> + /* Check if value is a power of two */
> + if (hweight64(l2c_ctrl.fifo_cmd_count) != 1) {
> + pr_err("Command queue size is not a power of two\n");
> + return 1;
> + }
> +
> + return 0;
> +}
> +
> +static int __init l2_cache_init_hw(void)
> +{
> + unsigned long timeout = jiffies + msecs_to_jiffies(L2_START_TIMEOUT_MS);
> + unsigned long flags;
> + u64 status, error;
> + int ret;
> +
> + /* Wait for L2 to be up */
> + do {
> + status = readq(l2c_ctrl.regs + L2_STATUS_OFFSET);
> + if (status & (L2_STATUS_READY_MASK | L2_STATUS_ERROR_MASK))
> + break;
> + } while (time_before(jiffies, timeout));
> +
> + if (!status) {
> + pr_err("Timeout while waiting for firmware status\n");
> + return -ENODEV;
> + }
> +
> + if (status & L2_STATUS_ERROR_MASK) {
> + error = readq(l2c_ctrl.regs + L2_ERROR_OFFSET);
> + l2_disp_error(error);
> + return -EINVAL;
> + }
> +
> + /* Now write ack to L2 firmware */
> + writeq(status | L2_STATUS_ACK_MASK, l2c_ctrl.regs + L2_STATUS_OFFSET);
> +
> + ret = l2_cache_read_queue_size();
> + if (ret)
> + return ret;
> +
> + ret = l2_cache_configure_mailboxes();
> + if (ret)
> + return ret;
> +
> + /* Enable the L2 atomically */
> + local_irq_save(flags);
> +
> + /* Fence data accesses */
> + kvx_fence();
> + /* Purge L1 */
> + l1_inval_dcache_all();
> + l1_inval_icache_all();
> + __builtin_kvx_barrier();
> +
> + local_irq_restore(flags);
> +
> + /* Enable L2$ */
> + kvx_sfr_set_field(PS, L2E, 1);
> +
> + return 0;
> +}
> +
> +static phys_addr_t __init l2_get_regs_addr(struct device_node *np)
> +{
> + const void *reg;
> + struct resource res;
> + phys_addr_t l2_regs_addr;
> + int ret;
> +
> + /*
> + * If regs is specified in device tree, then the L2$ has been loaded by
> + * someone else and not by ourself.
> + */
> + reg = of_get_property(np, "reg", NULL);
> + if (reg) {
> + ret = of_address_to_resource(np, 0, &res);
> + if (ret) {
> + pr_err("Address translation error\n");
> + return 0;
> + }
> + if ((res.end - res.start) > PAGE_SIZE) {
> + pr_err("L2 reg size > PAGE_SIZE\n");
> + return 0;
> + }
> +
> + l2_regs_addr = res.start;
> + } else {
> + l2_regs_addr = (phys_addr_t)
> __rm_firmware_regs_start;

Hi Yann !

Regarding the L2 cache support, since for the moment, only the QEMU
support is available and that KVX QEMU emulates a coherent L2 cache, I
think it would be preferable to remove this L2 cache driver for
multiple reasons:

- The firmware is still proprietary-sourced (at least to my knowledge)
and can not be obtained easily.
- L2 cache firmware needs to be linked with the kernel at compile time
if not already loaded by the RM.

If the RM is now already loaded with the L2 cache firmware at linux boot
time, then maybe this support can be kept but the "rm_firmware_regs"
section support can then be removed.

Clément

> + }
> +
> + if (!IS_ALIGNED(l2_regs_addr, PAGE_SIZE)) {
> + pr_err("Registers not aligned on PAGE_SIZE\n");
> + return 0;
> + }
> +
> + return l2_regs_addr;
> +}
> +
> +static int __init l2_cache_init(void)
> +{
> + int ret = -ENODEV;
> + struct device_node *np;
> + phys_addr_t l2_regs_addr;
> +
> + np = of_find_compatible_node(NULL, NULL, "kalray,kvx-l2-cache");
> + if (!np || !of_device_is_available(np)) {
> + if (!IS_ENABLED(CONFIG_SMP)) {
> + pr_info("controller disabled\n");
> + return 0;
> + }
> +
> + if (np && of_get_property(np, "kalray,is-qemu", NULL)) {
> + /*
> + * QEMU is always full cache coherent. The L2 cache controller is
> + * not strictly necessary to ensure coherency in SMP.
> + */
> + pr_info("controller disabled (QEMU detected)\n");
> + return 0;
> + }
> +
> + /* Else, SMP is enabled and L2 is mandatory for it */
> + goto err;
> + }
> +
> + l2_regs_addr = l2_get_regs_addr(np);
> + if (!l2_regs_addr)
> + goto err;
> +
> + /* Map the L2 registers */
> + l2c_ctrl.regs = ioremap(l2_regs_addr, PAGE_SIZE);
> + if (!l2c_ctrl.regs)
> + goto err;
> +
> + /* Lock this entry into the LTLB */
> + kvx_mmu_ltlb_add_entry((unsigned long) l2c_ctrl.regs, l2_regs_addr,
> + PAGE_KERNEL_NOCACHE, TLB_PS_4K);
> +
> + ret = l2_cache_init_hw();
> + if (ret) {
> + pr_err("Failed to init L2 cache controller");
> + goto err_unmap_l2;
> + }
> +
> + static_branch_enable(&l2_enabled);
> +
> + pr_info("controller enabled\n");
> +
> + return 0;
> +
> +err_unmap_l2:
> + kvx_mmu_ltlb_remove_entry((unsigned long) l2c_ctrl.regs);
> + iounmap(l2c_ctrl.regs);
> +err:
> + if (IS_ENABLED(CONFIG_SMP))
> + panic("L2$ controller is mandatory for SMP");
> +
> + return ret;
> +}
> +
> +
> +early_initcall(l2_cache_init);
> diff --git a/arch/kvx/kernel/smp.c b/arch/kvx/kernel/smp.c
> new file mode 100644
> index 000000000000..ed4c35a8c4bc
> --- /dev/null
> +++ b/arch/kvx/kernel/smp.c
> @@ -0,0 +1,110 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2017-2023 Kalray Inc.
> + * Author(s): Clement Leger
> + */
> +
> +#include <linux/smp.h>
> +#include <linux/cpu.h>
> +#include <linux/of_irq.h>
> +#include <linux/cpumask.h>
> +#include <linux/irq_work.h>
> +#include <linux/mm_types.h>
> +#include <linux/interrupt.h>
> +
> +#include <asm/ipi.h>
> +#include <asm/tlbflush.h>
> +
> +enum ipi_message_type {
> + IPI_RESCHEDULE,
> + IPI_CALL_FUNC,
> + IPI_IRQ_WORK,
> + IPI_MAX
> +};
> +
> +/* A collection of single bit ipi messages. */
> +static struct {
> + unsigned long bits ____cacheline_aligned;
> +} ipi_data[NR_CPUS] __cacheline_aligned;
> +
> +static void send_ipi_message(const struct cpumask *mask,
> + enum ipi_message_type operation)
> +{
> + unsigned long flags;
> + int cpu;
> +
> + /* Set operation that must be done by receiver */
> + for_each_cpu(cpu, mask)
> + set_bit(operation, &ipi_data[cpu].bits);
> +
> + /* Commit the write before sending IPI */
> + smp_wmb();
> +
> + local_irq_save(flags);
> +
> + kvx_ipi_send(mask);
> +
> + local_irq_restore(flags);
> +}
> +
> +void arch_send_call_function_ipi_mask(struct cpumask *mask)
> +{
> + send_ipi_message(mask, IPI_CALL_FUNC);
> +}
> +
> +void arch_send_call_function_single_ipi(int cpu)
> +{
> + send_ipi_message(cpumask_of(cpu), IPI_CALL_FUNC);
> +}
> +
> +#ifdef CONFIG_IRQ_WORK
> +void arch_irq_work_raise(void)
> +{
> + send_ipi_message(cpumask_of(smp_processor_id()), IPI_IRQ_WORK);
> +}
> +#endif
> +
> +static void ipi_stop(void *unused)
> +{
> + local_cpu_stop();
> +}
> +
> +void smp_send_stop(void)
> +{
> + struct cpumask targets;
> +
> + cpumask_copy(&targets, cpu_online_mask);
> + cpumask_clear_cpu(smp_processor_id(), &targets);
> +
> + smp_call_function_many(&targets, ipi_stop, NULL, 0);
> +}
> +
> +void smp_send_reschedule(int cpu)
> +{
> + send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE);
> +}
> +
> +irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
> +{
> + unsigned long *pending_ipis = &ipi_data[smp_processor_id()].bits;
> +
> + while (true) {
> + unsigned long ops = xchg(pending_ipis, 0);
> +
> + if (ops == 0)
> + return IRQ_HANDLED;
> +
> + if (ops & (1 << IPI_RESCHEDULE))
> + scheduler_ipi();
> +
> + if (ops & (1 << IPI_CALL_FUNC))
> + generic_smp_call_function_interrupt();
> +
> + if (ops & (1 << IPI_IRQ_WORK))
> + irq_work_run();
> +
> + BUG_ON((ops >> IPI_MAX) != 0);
> + }
> +
> + return IRQ_HANDLED;
> +}
> diff --git a/arch/kvx/kernel/smpboot.c b/arch/kvx/kernel/smpboot.c
> new file mode 100644
> index 000000000000..987a6f014163
> --- /dev/null
> +++ b/arch/kvx/kernel/smpboot.c
> @@ -0,0 +1,127 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2017-2023 Kalray Inc.
> + * Author(s): Clement Leger
> + * Julian Vetter
> + */
> +
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +
> +#include <linux/io.h>
> +#include <linux/of.h>
> +#include <linux/smp.h>
> +#include <linux/cpu.h>
> +#include <linux/sched.h>
> +#include <linux/cpumask.h>
> +#include <linux/sched/mm.h>
> +#include <linux/mm_types.h>
> +#include <linux/of_platform.h>
> +#include <linux/sched/task_stack.h>
> +
> +#include <asm/pwr_ctrl.h>
> +#include <asm/tlbflush.h>
> +#include <asm/ipi.h>
> +
> +void *__cpu_up_stack_pointer[NR_CPUS];
> +void *__cpu_up_task_pointer[NR_CPUS];
> +
> +void __init smp_prepare_boot_cpu(void)
> +{
> +}
> +
> +int __cpu_up(unsigned int cpu, struct task_struct *tidle)
> +{
> + __cpu_up_stack_pointer[cpu] = task_stack_page(tidle) + THREAD_SIZE;
> + __cpu_up_task_pointer[cpu] = tidle;
> + /* We need to be sure writes are committed */
> + smp_mb();
> +
> + kvx_pwr_ctrl_cpu_poweron(cpu);
> + while (!cpu_online(cpu))
> + cpu_relax();
> +
> + return 0;
> +}
> +
> +void __init smp_cpus_done(unsigned int max_cpus)
> +{
> +}
> +
> +void __init smp_init_cpus(void)
> +{
> + struct cpumask cpumask;
> + struct device_node *cpu;
> + const __be32 *reg;
> + u32 cpu_num;
> + unsigned int nr_cpus = 0;
> +
> + cpumask_clear(&cpumask);
> +
> + for_each_of_cpu_node(cpu) {
> + if (!of_device_is_available(cpu))
> + continue;
> +
> + reg = of_get_property(cpu, "reg", NULL);
> + if (!reg)
> + continue;
> +
> + cpu_num = be32_to_cpup(reg);
> + if (cpu_num >= nr_cpu_ids)
> + continue;
> +
> + nr_cpus++;
> + cpumask_set_cpu(cpu_num, &cpumask);
> + }
> +
> + pr_info("%d possible cpus\n", nr_cpus);
> + init_cpu_possible(&cpumask);
> +}
> +
> +void __init smp_prepare_cpus(unsigned int max_cpus)
> +{
> + if (num_present_cpus() <= 1)
> + init_cpu_present(cpu_possible_mask);
> +}
> +
> +int __init setup_smp(void)
> +{
> + int ret;
> +
> + ret = kvx_pwr_ctrl_probe();
> + if (ret)
> + panic("Failed to probe power controller !");
> +
> + ret = kvx_ipi_ctrl_probe(ipi_call_interrupt);
> + if (ret)
> + panic("Failed to probe IPI controller !");
> +
> + return 0;
> +}
> +
> +early_initcall(setup_smp);
> +
> +/*
> + * C entry point for a secondary processor.
> + */
> +void __init start_kernel_secondary(void)
> +{
> + struct mm_struct *mm = &init_mm;
> + unsigned int cpu = smp_processor_id();
> +
> + setup_processor();
> + kvx_mmu_early_setup();
> +
> + /* All kernel threads share the same mm context. */
> + mmgrab(mm);
> + current->active_mm = mm;
> + cpumask_set_cpu(cpu, mm_cpumask(mm));
> +
> + notify_cpu_starting(cpu);
> + set_cpu_online(cpu, true);
> + trace_hardirqs_off();
> +
> + local_flush_tlb_all();
> +
> + local_irq_enable();
> + cpu_startup_entry(CPUHP_AP_ONLINE_IDLE);
> +}
> diff --git a/arch/kvx/platform/pwr_ctrl.c b/arch/kvx/platform/pwr_ctrl.c
> new file mode 100644
> index 000000000000..64c86cd18695
> --- /dev/null
> +++ b/arch/kvx/platform/pwr_ctrl.c
> @@ -0,0 +1,93 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2017-2023 Kalray Inc.
> + * Author(s): Clement Leger
> + */
> +
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +
> +#include <linux/io.h>
> +#include <linux/slab.h>
> +#include <linux/types.h>
> +#include <linux/module.h>
> +#include <linux/of_address.h>
> +#include <linux/of_platform.h>
> +
> +#include <asm/pwr_ctrl.h>
> +#include <asm/symbols.h>
> +
> +struct kvx_pwr_ctrl {
> + void __iomem *regs;
> +};
> +
> +static struct kvx_pwr_ctrl kvx_pwr_controller;
> +
> +/**
> + * kvx_pwr_ctrl_cpu_poweron() - Wakeup a cpu
> + * @cpu: cpu to wakeup
> + */
> +void kvx_pwr_ctrl_cpu_poweron(unsigned int cpu)
> +{
> + /* Set PE boot address */
> + writeq((unsigned long long)kvx_start,
> + kvx_pwr_controller.regs + KVX_PWR_CTRL_RESET_PC_OFFSET);
> + /* Wake up processor ! */
> + writeq(1ULL << cpu,
> + kvx_pwr_controller.regs + PWR_CTRL_WUP_SET_OFFSET);
> + /* Then clear wakeup to allow processor to sleep */
> + writeq(1ULL << cpu,
> + kvx_pwr_controller.regs + PWR_CTRL_WUP_CLEAR_OFFSET);
> +}
> +
> +static struct device_node * __init get_pwr_ctrl_node(void)
> +{
> + const phandle *ph;
> + struct device_node *cpu;
> + struct device_node *node;
> +
> + cpu = of_get_cpu_node(raw_smp_processor_id(), NULL);
> + if (!cpu) {
> + pr_err("Failed to get CPU node\n");
> + return NULL;
> + }
> +
> + ph = of_get_property(cpu, "power-controller", NULL);
> + if (!ph) {
> + pr_err("Failed to get power-controller phandle\n");
> + return NULL;
> + }
> +
> + node = of_find_node_by_phandle(be32_to_cpup(ph));
> + if (!node) {
> + pr_err("Failed to get power-controller node\n");
> + return NULL;
> + }
> +
> + return node;
> +}
> +
> +int __init kvx_pwr_ctrl_probe(void)
> +{
> + struct device_node *ctrl;
> +
> + ctrl = get_pwr_ctrl_node();
> + if (!ctrl) {
> + pr_err("Failed to get power controller node\n");
> + return -EINVAL;
> + }
> +
> + if (!of_device_is_compatible(ctrl, "kalray,kvx-pwr-ctrl")) {
> + pr_err("Failed to get power controller node\n");
> + return -EINVAL;
> + }
> +
> + kvx_pwr_controller.regs = of_iomap(ctrl, 0);
> + if (!kvx_pwr_controller.regs) {
> + pr_err("Failed ioremap\n");
> + return -EINVAL;
> + }
> +
> + pr_info("kvx power controller probed\n");
> +
> + return 0;
> +}
> diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
> index f61447913db9..f5a484547b15 100644
> --- a/include/linux/cpuhotplug.h
> +++ b/include/linux/cpuhotplug.h
> @@ -152,6 +152,7 @@ enum cpuhp_state {
> CPUHP_AP_IRQ_RISCV_STARTING,
> CPUHP_AP_IRQ_LOONGARCH_STARTING,
> CPUHP_AP_IRQ_SIFIVE_PLIC_STARTING,
> + CPUHP_AP_IRQ_KVX_STARTING,
> CPUHP_AP_ARM_MVEBU_COHERENCY,
> CPUHP_AP_MICROCODE_LOADER,
> CPUHP_AP_PERF_X86_AMD_UNCORE_STARTING,
> @@ -189,6 +190,7 @@ enum cpuhp_state {
> CPUHP_AP_KVM_ARM_VGIC_INIT_STARTING,
> CPUHP_AP_KVM_ARM_VGIC_STARTING,
> CPUHP_AP_KVM_ARM_TIMER_STARTING,
> + CPUHP_AP_KVX_TIMER_STARTING,
> /* Must be the last timer callback */
> CPUHP_AP_DUMMY_TIMER_STARTING,
> CPUHP_AP_ARM_XEN_STARTING,



--
Clément Léger,
Embedded Linux and Kernel engineer at Bootlin
https://bootlin.com

2023-01-05 11:44:57

by Jules Maselbas

[permalink] [raw]
Subject: Re: [RFC PATCH 00/25] Upstream kvx Linux port

Hi,

On Wed, Jan 04, 2023 at 04:58:25PM +0100, Arnd Bergmann wrote:
> On Tue, Jan 3, 2023, at 17:43, Yann Sionneau wrote:
> > This patch series adds support for the kv3-1 CPU architecture of the kvx family
> > found in the Coolidge (aka MPPA3-80) SoC of Kalray.
> >
> > This is an RFC, since kvx support is not yet upstreamed into gcc/binutils,
> > therefore this patch series cannot be merged into Linux for now.
> >
> > The goal is to have preliminary reviews and to fix problems early.
> >
> > The Kalray VLIW processor family (kvx) has the following features:
> > * 32/64 bits execution mode
> > * 6-issue VLIW architecture
> > * 64 x 64bits general purpose registers
> > * SIMD instructions
> > * little-endian
> > * deep learning co-processor
>
> Thanks for posting these, I had been wondering about the
> state of the port. Overall this looks really nice, I can
> see that you and the team have looked at other ports
> and generally made the right decisions.

Thank you and all for the reviews. We are currently going
through every remarks and we are trying to do our best to
send a new patch series with everything addressed.

> I commented on the syscall patch directly, I think it's
> important to stop using the deprecated syscalls as soon
> as possible to avoid having dependencies in too many
> libc binaries. Almost everything else can be changed
> easily as you get closer to upstream inclusion.
>
> I did not receive most of the other patches as I'm
> not subscribed to all the mainline lists. For future
> submissions, can you add the linux-arch list to Cc for
> all patches?

We misused get_maintainers.pl, running it on each patch instead
of using it on the whole series. next time every one will be in
copy of every patch in the series and including linux-arch.

> Reading the rest of the series through lore.kernel.org,
> most of the comments I have are for improvements that
> you may find valuable rather than serious mistakes:
>
> - the {copy_to,copy_from,clear}_user functions are
> well worth optimizing better than the byte-at-a-time
> version you have, even just a C version built around
> your __get_user/__put_user inline asm should help, and
> could be added to lib/usercopy.c.

right, we are using memcpy for {copy_to,copy_from}_user_page
which has a simple optimized version introduced in
(kvx: Add some library functions).
I wonder if it is possible to do the same for copy_*_user functions.

> - The __raw_{read,write}{b,w,l,q} helpers should
> normally be defined as inline asm instead of
> volatile pointer dereferences, I've seen cases where
> the compiler ends up splitting the access or does
> other things you may not want on MMIO areas.
>
> - I would recomment implementing HAVE_ARCH_VMAP_STACK
> as well as IRQ stacks, both of these help to
> avoid data corruption from stack overflow that you
> will eventually run into.
>
> - You use qspinlock as the only available spinlock
> implementation, but only support running on a
> single cluster of 16 cores. It may help to use
> the generic ticket spinlock instead, or leave it
> as a Kconfig option, in particular since you only
> have the emulated xchg16() atomic for qspinlock.
>
> - Your defconfig file enables CONFIG_EMBEDDED, which
> in turn enables CONFIG_EXPERT. This is probably
> not what you want, so better turn off both of these.
>
> - The GENERIC_CALIBRATE_DELAY should not be necessary
> since you have a get_cycles() based delay loop.
> Just set loops_per_jiffy to the correct value based
> on the frequency of the cycle counter, to save
> a little time during boot and get a more accurate
> delay loop.
>
Ack !

Jules




2023-01-05 12:33:48

by Arnd Bergmann

[permalink] [raw]
Subject: Re: [RFC PATCH 00/25] Upstream kvx Linux port

On Thu, Jan 5, 2023, at 11:40, Jules Maselbas wrote:
> On Wed, Jan 04, 2023 at 04:58:25PM +0100, Arnd Bergmann wrote:
>> On Tue, Jan 3, 2023, at 17:43, Yann Sionneau wrote:

>> I commented on the syscall patch directly, I think it's
>> important to stop using the deprecated syscalls as soon
>> as possible to avoid having dependencies in too many
>> libc binaries. Almost everything else can be changed
>> easily as you get closer to upstream inclusion.
>>
>> I did not receive most of the other patches as I'm
>> not subscribed to all the mainline lists. For future
>> submissions, can you add the linux-arch list to Cc for
>> all patches?
>
> We misused get_maintainers.pl, running it on each patch instead
> of using it on the whole series. next time every one will be in
> copy of every patch in the series and including linux-arch.

Be careful not to make the list too long though, there is
usually a limit of 1024 characters for the entire Cc list,
above this your mails may get dropped by the mailing lists.

>> Reading the rest of the series through lore.kernel.org,
>> most of the comments I have are for improvements that
>> you may find valuable rather than serious mistakes:
>>
>> - the {copy_to,copy_from,clear}_user functions are
>> well worth optimizing better than the byte-at-a-time
>> version you have, even just a C version built around
>> your __get_user/__put_user inline asm should help, and
>> could be added to lib/usercopy.c.
>
> right, we are using memcpy for {copy_to,copy_from}_user_page
> which has a simple optimized version introduced in
> (kvx: Add some library functions).
> I wonder if it is possible to do the same for copy_*_user functions.

copy_from_user_page() is only about managing cache aliases,
not user access, and it's not used anywhere in the fast
path, so it's a bit different.

arch/arm/lib/copy_template.S has an example for how
you can share the same assembler implementation between
memcpy() and copy_from_user(), but it's not very
intuitive.

The tricky bit with copy_from_user() is the partial copy
that relies on copying the exact amount of data that can
be accessed including the last byte before the end of
the mapping, and returning the correct count of non-copied
bytes.

If you want a C version, you can probably use the
copy_from_kernel_nofault implementation mm/maccess.c
as a template, but have to add code for the correct
return value.

Arnd

2023-01-05 13:19:25

by Clément Léger

[permalink] [raw]
Subject: Re: [RFC PATCH 21/25] kvx: Add support for ftrace

Le Tue, 3 Jan 2023 17:43:55 +0100,
Yann Sionneau <[email protected]> a écrit :

> Add support for ftrace to kvx arch.
>
> CC: Steven Rostedt <[email protected]>
> CC: Masami Hiramatsu <[email protected]>
> CC: Mark Rutland <[email protected]>
> CC: [email protected]
> Co-developed-by: Clement Leger <[email protected]>
> Signed-off-by: Clement Leger <[email protected]>
> Co-developed-by: Guillaume Thouvenin <[email protected]>
> Signed-off-by: Guillaume Thouvenin <[email protected]>
> Co-developed-by: Julian Vetter <[email protected]>
> Signed-off-by: Julian Vetter <[email protected]>
> Co-developed-by: Marius Gligor <[email protected]>
> Signed-off-by: Marius Gligor <[email protected]>
> Co-developed-by: Yann Sionneau <[email protected]>
> Signed-off-by: Yann Sionneau <[email protected]>
> ---
> arch/kvx/include/asm/ftrace.h | 41 ++++
> arch/kvx/kernel/ftrace.c | 339 ++++++++++++++++++++++++++++++
> arch/kvx/kernel/mcount.S | 340 +++++++++++++++++++++++++++++++
> arch/kvx/kernel/return_address.c | 55 +++++
> 4 files changed, 775 insertions(+)
> create mode 100644 arch/kvx/include/asm/ftrace.h
> create mode 100644 arch/kvx/kernel/ftrace.c
> create mode 100644 arch/kvx/kernel/mcount.S
> create mode 100644 arch/kvx/kernel/return_address.c
>
> diff --git a/arch/kvx/include/asm/ftrace.h b/arch/kvx/include/asm/ftrace.h
> new file mode 100644
> index 000000000000..f7bcb325d255
> --- /dev/null
> +++ b/arch/kvx/include/asm/ftrace.h
> @@ -0,0 +1,41 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (C) 2017-2023 Kalray Inc.
> + * Author(s): Guillaume Thouvenin
> + * Clement Leger
> + */
> +
> +#ifndef _ASM_KVX_FTRACE_H
> +#define _ASM_KVX_FTRACE_H
> +
> +#include <asm/insns_defs.h>
> +
> +#define INSN_MAKE_IMM64_SYLLABLE_SIZE INSN_SIZE(MAKE_IMM64)
> +#define INSN_ICALL_SYLLABLE_SIZE INSN_SIZE(ICALL)
> +#define INSN_IGOTO_SYLLABLE_SIZE INSN_SIZE(IGOTO)
> +#define INSN_CALL_SYLLABLE_SIZE INSN_SIZE(CALL)
> +#define INSN_NOP_SYLLABLE_SIZE INSN_SIZE(NOP)
> +
> +#define INSN_ICALL_REG_MASK 0x3f
> +
> +#define MCOUNT_ADDR ((unsigned long)(__mcount))
> +#define MCOUNT_INSN_SIZE INSN_CALL_SYLLABLE_SIZE /* sizeof mcount call */
> +
> +extern void ftrace_graph_call(void);
> +
> +#ifdef CONFIG_DYNAMIC_FTRACE
> +extern unsigned long ftrace_call_adjust(unsigned long addr);
> +struct dyn_arch_ftrace {
> + unsigned int insn;
> +};
> +#endif
> +
> +extern void *return_address(unsigned int level);
> +#define ftrace_return_address(n) return_address(n)
> +
> +#ifdef CONFIG_FUNCTION_TRACER
> +extern void __mcount(void);
> +#define mcount __mcount
> +#endif /* CONFIG_FUNCTION_TRACER */
> +
> +#endif /* _ASM_KVX_FTRACE_H */
> diff --git a/arch/kvx/kernel/ftrace.c b/arch/kvx/kernel/ftrace.c
> new file mode 100644
> index 000000000000..4c9e3ef62714
> --- /dev/null
> +++ b/arch/kvx/kernel/ftrace.c
> @@ -0,0 +1,339 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2017-2023 Kalray Inc.
> + * Author(s): Guillaume Thouvenin
> + * Marius Gligor
> + * Clement Leger
> + */
> +
> +#include <linux/ftrace.h>
> +#include <linux/atomic.h>
> +#include <linux/stop_machine.h>
> +#include <asm/insns.h>
> +#include <asm/insns_defs.h>
> +#include <asm/cacheflush.h>
> +
> +/* The longest insns we check are for the far call: make + icall */
> +#define MAX_SYLLABLES_TO_CHECK (KVX_INSN_MAKE_IMM64_SIZE + INSN_ICALL_SYLLABLE_SIZE)
> +
> +static int read_insns_and_check(u32 *insns, u8 insns_len, u32 *addr)
> +{
> + u32 insns_read[MAX_SYLLABLES_TO_CHECK];
> + int syllables = insns_len / KVX_INSN_SYLLABLE_WIDTH;
> + int i;
> +
> + if (syllables > MAX_SYLLABLES_TO_CHECK) {
> + pr_err("%s: shouldn't have more than %d syllables to check\n",
> + __func__, MAX_SYLLABLES_TO_CHECK);
> + return -EINVAL;
> + }
> +
> + if (kvx_insns_read(insns_read, insns_len, addr)) {
> + pr_err("%s: error when trying to read syllable\n", __func__);
> + return -EFAULT;
> + }
> +
> + for (i = 0; i < syllables; i++) {
> + if (insns[i] != insns_read[i]) {
> + pr_err("%s: Instruction verification failed at PC 0x%lx\n",
> + __func__,
> + (unsigned long)addr + i * KVX_INSN_SYLLABLE_WIDTH);
> + pr_err("%s: \tExpect 0x%x\n", __func__, insns[i]);
> + pr_err("%s: \tRead 0x%x\n", __func__, insns_read[i]);
> + return -EFAULT;
> + }
> + }
> +
> + return 0;
> +}

Hi Yann,

Is this still needed ? I'm guessing the instructions should always be
correctly written no ? If not, something probably went horribly wrong ;)

> +
> +static int write_insns_and_check(u32 *insns, u8 insns_len, u32 *insn_addr)
> +{
> + int ret;
> +
> + ret = kvx_insns_write_nostop(insns, insns_len, insn_addr);
> + if (ret)
> + return ret;
> +
> + /* Check that what have been written is correct. */
> + return read_insns_and_check(insns, insns_len, insn_addr);
> +}
> +
> +#ifdef CONFIG_FUNCTION_GRAPH_TRACER
> +void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
> + unsigned long frame_pointer)
> +{
> + unsigned long return_hooker = (unsigned long)&return_to_handler;
> + unsigned long old;
> +
> + if (unlikely(atomic_read(&current->tracing_graph_pause)))
> + return;
> +
> + old = *parent;
> + *parent = return_hooker;
> +
> + if (function_graph_enter(old, self_addr, frame_pointer, NULL))
> + *parent = old;
> +}
> +
> +#ifdef CONFIG_DYNAMIC_FTRACE
> +int ftrace_enable_ftrace_graph_caller(void)
> +{
> + unsigned int insn[KVX_INSN_MAKE_IMM64_SIZE + KVX_INSN_IGOTO_SIZE];
> + void *ip = (void *)ftrace_call;
> +
> + KVX_INSN_MAKE_IMM64(insn, KVX_INSN_PARALLEL_EOB, KVX_REG_R32,
> + (unsigned long)&ftrace_graph_call);
> + KVX_INSN_IGOTO(&insn[KVX_INSN_MAKE_IMM64_SIZE],
> + KVX_INSN_PARALLEL_EOB,
> + KVX_REG_R32);
> +
> + return write_insns_and_check(insn,
> + INSN_MAKE_IMM64_SYLLABLE_SIZE
> + + INSN_IGOTO_SYLLABLE_SIZE,
> + ip);
> +}
> +
> +int ftrace_disable_ftrace_graph_caller(void)
> +{
> + unsigned int nop;
> + void *ip = (void *)ftrace_call;
> +
> + KVX_INSN_NOP(&nop, KVX_INSN_PARALLEL_EOB);
> + return write_insns_and_check(&nop,
> + INSN_NOP_SYLLABLE_SIZE,
> + ip + INSN_MAKE_IMM64_SYLLABLE_SIZE);
> +}
> +#endif /* CONFIG_DYNAMIC_FTRACE */
> +
> +#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
> +
> +#ifdef CONFIG_DYNAMIC_FTRACE
> +struct kvx_ftrace_modify_param {
> + atomic_t cpu_ack;
> + int cpu_master;
> + int cmd;
> +};
> +
> +static int __ftrace_modify_code_kvx(void *data)
> +{
> + struct kvx_ftrace_modify_param *mp = data;
> + int no_cpus = num_online_cpus();
> + int cpu = smp_processor_id();
> +
> + if (cpu == mp->cpu_master) {
> + ftrace_modify_all_code(mp->cmd);
> +
> + /* Inform the other cpus that they can invalidate I-cache */
> + atomic_inc(&mp->cpu_ack);
> +
> + /* param (which contains the cpu_ack counter) is allocated on the
> + * master stack: the master must wait for all other CPUs to leave
> + * this function before returning and releasing the stack
> + * allocation.
> + */
> + while (atomic_read(&mp->cpu_ack) < no_cpus)
> + cpu_relax();
> + } else {
> + /* Wait for the master cpu to finish the code modification */
> + while (atomic_read(&mp->cpu_ack) == 0)
> + cpu_relax();
> + atomic_inc(&mp->cpu_ack);
> +
> + l1_inval_icache_all();
> + }
> +
> + return 0;
> +}
> +
> +void arch_ftrace_update_code(int command)
> +{
> + const struct cpumask *cpumask = cpu_online_mask;
> + struct kvx_ftrace_modify_param mp = {
> + .cpu_ack = ATOMIC_INIT(0),
> + .cpu_master = smp_processor_id(),
> + .cmd = command,
> + };
> +
> + stop_machine(__ftrace_modify_code_kvx, &mp, cpu_online_mask);
> +}
> +
> +unsigned long ftrace_call_adjust(unsigned long addr)
> +{
> + /*
> + * Module are using far call and kernel functions are using
> + * pcrel. If it is a call we don't need to adjust the address but
> + * if it is an icall the address is on the make. The generated code
> + * looks like:
> + *
> + * 1c: e0 00 c4 8f get $r32 = $ra
> + * 20: 00 00 84 e0 00 00 00 80 00 00 00 00 make $r33 = 0 (0x0);;
> + *
> + * 20: R_KVX_S64_LO10 __mcount
> + * 24: R_KVX_S64_UP27 __mcount
> + * 28: R_KVX_S64_EX27 __mcount
> + * 2c: 21 00 dc 0f icall $r33;;
> + *
> + * So we just need to add INSN_MAKE_IMM64_SYLLABLE_SIZE (0xc) to the
> + * address.
> + */
> + unsigned int insn;
> +
> + /*
> + * The CALL is 1 syllable while the MAKE IMM64 is 3. But we just
> + * need to check that the first syllable of the MAKE IMM64 is the
> + * LO10. So finally we just need to read one syllable to adjust the
> + * call.
> + */
> + if (kvx_insns_read(&insn, KVX_INSN_SYLLABLE_WIDTH, (void *)addr)) {
> + pr_err("%s: error when trying to read syllable\n", __func__);
> + return 0;
> + }
> +
> + if (IS_INSN(insn, CALL))
> + return addr;
> +
> + if (IS_INSN(insn, MAKE_IMM64))
> + return addr + INSN_MAKE_IMM64_SYLLABLE_SIZE;
> +
> + pr_err("%s: syllable is neither a CALL nor a MAKE\n", __func__);
> + return 0;
> +}
> +
> +/*
> + * Do runtime patching of the active tracer.
> + * This will be modifying the assembly code at the location of the
> + * ftrace_call symbol inside of the ftrace_caller() function.
> + */
> +int ftrace_update_ftrace_func(ftrace_func_t func)
> +{
> + void *ip;
> + unsigned int insn[KVX_INSN_MAKE_IMM64_SIZE + KVX_INSN_ICALL_SIZE];
> +
> + ip = (void *)ftrace_call;
> + KVX_INSN_MAKE_IMM64(insn, KVX_INSN_PARALLEL_EOB, KVX_REG_R32,
> + (unsigned long)func);
> + KVX_INSN_ICALL(&insn[KVX_INSN_MAKE_IMM64_SIZE],
> + KVX_INSN_PARALLEL_EOB,
> + KVX_REG_R32);
> + return write_insns_and_check(insn,
> + INSN_MAKE_IMM64_SYLLABLE_SIZE
> + + INSN_ICALL_SYLLABLE_SIZE,
> + ip);
> +}
> +
> +/*
> + * Turn the mcount call site into a call to an arbitrary location (but
> + * typically that is ftrace_caller()) at runtime.
> + */
> +int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
> +{
> + void *ip = (void *)rec->ip;
> + unsigned int insn;
> + int ret;
> +
> + /* Ensure that a NOP will be replaced */
> + if (kvx_insns_read(&insn, KVX_INSN_SYLLABLE_WIDTH, ip)) {
> + pr_err("%s: failed to read insn\n", __func__);
> + return -EFAULT;
> + }
> +
> + if (!IS_INSN(insn, NOP)) {
> + pr_err("%s: insn 0x%x is not a NOP\n", __func__, insn);
> + return -EINVAL;
> + }
> +
> + /*
> + * Now we can replace the instruction depending of what has been
> + * nopified (call or icall)
> + */
> + insn = rec->arch.insn;
> +
> + if (IS_INSN(insn, CALL)) {
> + s32 pcrel = addr - (unsigned long) ip;
> + u32 insn_call;
> +
> + BUG_ON(KVX_INSN_GOTO_PCREL27_CHECK(pcrel));
> + KVX_INSN_CALL(&insn_call, KVX_INSN_PARALLEL_EOB, pcrel);
> +
> + return write_insns_and_check(&insn_call,
> + INSN_CALL_SYLLABLE_SIZE, ip);
> + }
> +
> + if (IS_INSN(insn, ICALL)) {
> + u32 insn_make[KVX_INSN_MAKE_IMM64_SIZE];
> + u32 r = insn & INSN_ICALL_REG_MASK;
> +
> + KVX_INSN_MAKE_IMM64(insn_make, KVX_INSN_PARALLEL_EOB, r, addr);
> + ret = write_insns_and_check(insn_make,
> + INSN_MAKE_IMM64_SYLLABLE_SIZE,
> + ip - INSN_MAKE_IMM64_SYLLABLE_SIZE);
> + if (ret)
> + return ret;
> +
> + return write_insns_and_check(&insn,
> + INSN_ICALL_SYLLABLE_SIZE, ip);
> + }
> +
> + /* It is neither a call nor an icall */
> + pr_err("%s: insn 0x%x is neither a CALL nor ICALL\n", __func__, insn);
> + return -EINVAL;
> +}
> +
> +/*
> + * Turn the mcount call site into a nop at runtime
> + */
> +int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
> + unsigned long addr)
> +{
> + unsigned long ip = rec->ip;
> + unsigned int insn;
> + unsigned int nop;
> +
> + /*
> + * Ensure that the instruction that will be replaced is a call or an
> + * icall to addr.
> + */
> + if (kvx_insns_read(&insn, KVX_INSN_SYLLABLE_WIDTH, (void *)ip)) {
> + pr_err("%s: error when trying to read syllable\n", __func__);
> + return -EFAULT;
> + }
> +
> + if (IS_INSN(insn, CALL)) {
> + int pcrel = ((int)(insn & 0x7ffffff) << 5) >> 3;

Hardcoded values

> +
> + if ((ip + pcrel != addr)) {
> + pr_err("%s: failed to check call addr 0x%lx != 0x%lx\n",
> + __func__, ip + pcrel, addr);
> + return -EINVAL;
> + }
> + } else if (IS_INSN(insn, ICALL)) {
> + unsigned int insn_make[KVX_INSN_MAKE_IMM64_SIZE];
> + unsigned int reg = insn & INSN_ICALL_REG_MASK;
> + int ret;
> +
> + KVX_INSN_MAKE_IMM64(insn_make,
> + KVX_INSN_PARALLEL_EOB, reg,
> + addr);
> +
> + ret = read_insns_and_check(insn_make,
> + INSN_MAKE_IMM64_SYLLABLE_SIZE,
> + (void *)ip -
> + INSN_MAKE_IMM64_SYLLABLE_SIZE);
> + if (ret)
> + return ret;
> + } else {
> + pr_err("%s: insn 0x%x is neither a CALL nor an ICALL\n",
> + __func__, insn);
> + return -EINVAL;
> + }
> +
> + rec->arch.insn = insn;
> + KVX_INSN_NOP(&nop, KVX_INSN_PARALLEL_EOB);
> + return write_insns_and_check(&nop, INSN_NOP_SYLLABLE_SIZE, (void *)ip);
> +}
> +
> +#endif /* CONFIG_DYNAMIC_FTRACE */
> +
> +/* __mcount is defined in mcount.S */
> +EXPORT_SYMBOL(__mcount);
> diff --git a/arch/kvx/kernel/mcount.S b/arch/kvx/kernel/mcount.S
> new file mode 100644
> index 000000000000..317797aeed42
> --- /dev/null
> +++ b/arch/kvx/kernel/mcount.S
> @@ -0,0 +1,340 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (C) 2017-2023 Kalray Inc.
> + * Author(s): Guillaume Thouvenin
> + * Marius Gligor
> + * Clement Leger
> + */
> +
> +#include <linux/linkage.h>
> +#include <asm/insns_defs.h>
> +#include <asm/sfr_defs.h>
> +
> +.altmacro
> +
> +/*
> + * !!! The call to __mcount is special and breaks the ABI !!!
> + * It is because with dynamic ftrace the call can be replaced by any
> + * tracer and GCC cannot assume which caller registers must be saved.
> + * It's because the call is being inserted in the prologue of functions
> + * that is out of GCC knowledge.
> + * We could make this known to GCC, but then we would hit the problem of not
> + * being able to easily decide which insns are emitted and how they are
> + * bundled. So we choose to save nothing when calling __mcount and we will
> + * save all caller registers once __mcount called.
> + *
> + * Another specificity is that parameter is passed in $r32 instead of $r0.
> + *
> + * Our stack will be:
> + * 0 | $FP $RA $r15 -
> + * 32 | $r0 $r1 $r2 $r3
> + * 64 | $r4 $r5 $r6 $r7
> + * 96 | $r8 $r9 $r10 $r11
> + * 128| $r32 $r33 $r34 $r35
> + * 160| $r36 $r37 $r38 $r39
> + * 192| $r40 $r41 $r42 $r43
> + * 224| $r44 $r45 $r46 $r47
> + * 256| $r48 $r49 $r50 $r51
> + * 288| $r52 $r53 $r54 $r55
> + * 320| $r56 $r57 $r58 $r59
> + * 352| $r60 $r61 $r62 $r63
> + * 384| $r16 $r17
> + */
> +
> +#define STACK_OFFSET_FP 0
> +#define STACK_OFFSET_RA (STACK_OFFSET_FP + 8)
> +#define STACK_OFFSET_R15 (STACK_OFFSET_RA + 8)
> +#define STACK_OFFSET_Q0 (STACK_OFFSET_FP + 32)
> +#define STACK_OFFSET_Q4 (STACK_OFFSET_Q0 + 32)
> +#define STACK_OFFSET_Q8 (STACK_OFFSET_Q4 + 32)
> +#define STACK_OFFSET_Q32 (STACK_OFFSET_Q8 + 32)
> +#define STACK_OFFSET_Q36 (STACK_OFFSET_Q32 + 32)
> +#define STACK_OFFSET_Q40 (STACK_OFFSET_Q36 + 32)
> +#define STACK_OFFSET_Q44 (STACK_OFFSET_Q40 + 32)
> +#define STACK_OFFSET_Q48 (STACK_OFFSET_Q44 + 32)
> +#define STACK_OFFSET_Q52 (STACK_OFFSET_Q48 + 32)
> +#define STACK_OFFSET_Q56 (STACK_OFFSET_Q52 + 32)
> +#define STACK_OFFSET_Q60 (STACK_OFFSET_Q56 + 32)
> +#define STACK_OFFSET_P16 (STACK_OFFSET_Q60 + 32)
> +#define STACK_SIZE (STACK_OFFSET_P16 + 16)
> +
> +#define RA_DWARF_REGNO (64 + KVX_SFR_RA)
> +#define R14_DWARF_REGNO 14
> +
> +.macro save_all_context_but_P16
> + /*
> + * r16 and r17 are already saved. r16 is already used to store the
> + * address of the function tracer if any.
> + * so !!! USE r17 as scratch register !!!
> + */
> + get $r17 = $ra
> + sd STACK_OFFSET_FP[$r12] = $r14
> + ;;
> + .cfi_offset R14_DWARF_REGNO, -STACK_SIZE + STACK_OFFSET_FP
> + sd STACK_OFFSET_RA[$r12] = $r17
> + ;;
> + .cfi_offset RA_DWARF_REGNO, -STACK_SIZE + STACK_OFFSET_RA
> + sd STACK_OFFSET_R15[$r12] = $r15
> + ;;
> + so STACK_OFFSET_Q0[$r12] = $r0r1r2r3
> + ;;
> + so STACK_OFFSET_Q4[$r12] = $r4r5r6r7
> + ;;
> + so STACK_OFFSET_Q8[$r12] = $r8r9r10r11
> + ;;
> + so STACK_OFFSET_Q32[$r12] = $r32r33r34r35
> + ;;
> + so STACK_OFFSET_Q36[$r12] = $r36r37r38r39
> + ;;
> + so STACK_OFFSET_Q40[$r12] = $r40r41r42r43
> + ;;
> + so STACK_OFFSET_Q44[$r12] = $r44r45r46r47
> + ;;
> + so STACK_OFFSET_Q48[$r12] = $r48r49r50r51
> + ;;
> + so STACK_OFFSET_Q52[$r12] = $r52r53r54r55
> + ;;
> + so STACK_OFFSET_Q56[$r12] = $r56r57r58r59
> + ;;
> + so STACK_OFFSET_Q60[$r12] = $r60r61r62r63
> + ;;
> +.endm
> +
> +.macro restore_all_context
> + ld $r15 = STACK_OFFSET_RA[$r12]
> + ;;
> + ld $r14 = STACK_OFFSET_FP[$r12]
> + set $ra = $r15
> + ;;
> + .cfi_restore RA_DWARF_REGNO
> + .cfi_restore R14_DWARF_REGNO
> + ld $r15 = STACK_OFFSET_R15[$r12]
> + ;;
> + lq $r16r17 = STACK_OFFSET_P16[$r12]
> + ;;
> + lo $r0r1r2r3 = STACK_OFFSET_Q0[$r12]
> + ;;
> + lo $r4r5r6r7 = STACK_OFFSET_Q4[$r12]
> + ;;
> + lo $r8r9r10r11 = STACK_OFFSET_Q8[$r12]
> + ;;
> + lo $r32r33r34r35 = STACK_OFFSET_Q32[$r12]
> + ;;
> + lo $r36r37r38r39 = STACK_OFFSET_Q36[$r12]
> + ;;
> + lo $r40r41r42r43 = STACK_OFFSET_Q40[$r12]
> + ;;
> + lo $r44r45r46r47 = STACK_OFFSET_Q44[$r12]
> + ;;
> + lo $r48r49r50r51 = STACK_OFFSET_Q48[$r12]
> + ;;
> + lo $r52r53r54r55 = STACK_OFFSET_Q52[$r12]
> + ;;
> + lo $r56r57r58r59 = STACK_OFFSET_Q56[$r12]
> + ;;
> + lo $r60r61r62r63 = STACK_OFFSET_Q60[$r12]
> + ;;
> + addd $r12 = $r12, STACK_SIZE
> + ;;
> + .cfi_def_cfa_offset 0
> +.endm
> +
> +ENTRY(__mcount)
> +.cfi_startproc
> +#ifdef CONFIG_DYNAMIC_FTRACE
> + /*
> + * With dynamic ftrace mcount() is only used during boot and then all
> + * references to it will be patched out never to return. ftrace_caller
> + * is used.
> + */
> + ret
> + ;;
> +#endif
> + addd $r12 = $r12, -STACK_SIZE
> + ;;
> + .cfi_def_cfa_offset STACK_SIZE
> + sq STACK_OFFSET_P16[$r12] = $r16r17
> + ;;
> +#ifdef CONFIG_FUNCTION_GRAPH_TRACER
> + /*
> + * Check the function pointers ftrace_graph_return
> + * (compare to ftrace_stub) and ftrace_graph_entry (compare to
> + * ftrace_graph_entry_stub). If either of those is not set to the
> + * relevant stub function, call the arch-specific function
> + * ftrace_graph_caller.
> + */
> + make $r16 = ftrace_graph_return
> + make $r17 = ftrace_graph_entry
> + ;;
> + ld $r16 = 0[$r16]
> + ;;
> + compd.eq $r16 = $r16, ftrace_stub
> + ld $r17 = 0[$r17]
> + ;;
> + /*
> + * If ftrace_graph_return is not equal to ftrace_stub ($r16 == 0) then
> + * jump to ftrace_graph_caller. Otherwise compare ftrace_graph_entry.
> + */
> + cb.deqz $r16? ftrace_graph_caller
> + compd.eq $r17 = $r17, ftrace_graph_entry_stub
> + ;;
> + /*
> + * If ftrace_graph_entry is equal to ftrace_graph_entry_stub ($r17 == 1)
> + * then jump to ftrace_graph_end. If not we continue.
> + */
> + cb.dnez $r17? ftrace_graph_end
> + ;;
> +ftrace_graph_caller:
> + save_all_context_but_P16
> + ;;
> +GLOBAL(ftrace_graph_call)
> + ld $r16 = 0[$r12]
> + ;;
> + addd $r0 = $r16, 0x8 /* a pointer to the frompc */
> + get $r1 = $ra /* selfpc */
> + copyd $r2 = $r16 /* FP of the function that called __mcount */
> + ;;
> + /* get the address of the bundle */
> + addd $r1 = $r1, -KVX_INSN_SYLLABLE_WIDTH
> + ;;
> + call prepare_ftrace_return
> + ;;
> + restore_all_context
> + ;;
> + ret
> + ;;
> +ftrace_graph_end:
> + .cfi_def_cfa_offset STACK_SIZE
> +#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
> + /*
> + * Check if function pointer ftrace_trace_function is set to
> + * ftrace_stub.
> + * If it isn't, then call that function in the same way the mcount
> + * function normally calls __mcount_internal
> + * - the first argument is the "frompc" ($r0)
> + * - the second argument is the "selfpc" ($ra - mcount size adjustement)
> + * As we don't use any callee saved registers we don't need to save
> + * them.
> + */
> + make $r16 = ftrace_trace_function
> + ;;
> + ld $r16 = 0[$r16]
> + ;;
> + /*
> + * NOTE: keep value in $r16 (the function we may call if set). See
> + * comment in save_all_context_but_P16.
> + */
> + compd.eq $r17 = $r16, ftrace_stub
> + ;;
> + /*
> + * If ftrace_trace_function is equal to ftrace_stub ($r17 == 1), there
> + * is nothing to do, so return immediately otherwise call the function
> + * in $r16 with correct parameters.
> + */
> + cb.deqz $r17? 1f
> + ;;
> + /* Only need to restore P16 */
> + lq $r16r17 = STACK_OFFSET_P16[$r12]
> + ;;
> + addd $r12 = $r12, STACK_SIZE
> + ;;
> + .cfi_def_cfa_offset 0
> + ret
> + ;;
> +
> +1:
> + save_all_context_but_P16
> + ;;
> + copyd $r0 = $r32
> + get $r1 = $ra
> + ;;
> + addd $r1 = $r1, -KVX_INSN_SYLLABLE_WIDTH
> + ;;
> + icall $r16
> + ;;
> + restore_all_context
> + ;;
> + ret
> + ;;
> +.cfi_endproc
> +ENDPROC(__mcount)
> +
> +/* Required by ftrace_graph_ret_addr */
> +#ifdef CONFIG_FUNCTION_GRAPH_TRACER
> +ENTRY(return_to_handler)
> + addd $r12 = $r12, -128
> + ;;
> + so 0[$r12] = $r0r1r2r3
> + ;;
> + so 32[$r12] = $r4r5r6r7
> + ;;
> + so 64[$r12] = $r8r9r10r11
> + ;;
> + call ftrace_return_to_handler
> + ;;
> + set $ra = $r0
> + lo $r0r1r2r3 = 0[$r12]
> + ;;
> + lo $r4r5r6r7 = 32[$r12]
> + ;;
> + lo $r8r9r10r11 = 64[$r12]
> + addd $r12 = $r12, 128
> + ;;
> + ret
> + ;;
> +ENDPROC(return_to_handler)
> +#endif
> +
> +#ifdef CONFIG_DYNAMIC_FTRACE
> +ENTRY(ftrace_caller)
> +.cfi_startproc
> +
> + addd $r12 = $r12, -STACK_SIZE
> + ;;
> + .cfi_def_cfa_offset STACK_SIZE
> + sq STACK_OFFSET_P16[$r12] = $r16r17
> + ;;
> + save_all_context_but_P16
> + ;;
> + copyd $r0 = $r32
> + get $r1 = $ra
> + ;;
> + addd $r1 = $r1, -KVX_INSN_SYLLABLE_WIDTH
> + ;;
> + goto ftrace_call
> + ;;
> +.align 64
> +GLOBAL(ftrace_call)
> + /*
> + * To work with module we need to use far call. So prepare the
> + * space for them:
> + * - make: 3 syllables
> + * - icall/igoto: 1 syllable
> + *
> + * We are using igoto in ftrace_enable_ftrace_graph_caller(). This is
> + * because this path is a tweak to enable function graph tracer with
> + * dynamic ftrace. We need to jump to ftrace_graph_call without updating
> + * RA and FP. Once in ftrace_graph_call we will return to the correct
> + * address from the classical path of the function graph tracer.
> + */
> + nop
> + ;;
> + nop
> + ;;
> + nop
> + ;;
> + nop
> + ;;
> + restore_all_context
> + ;;
> + ret
> + ;;
> +.cfi_endproc
> +ENDPROC(ftrace_caller)
> +#endif // CONFIG_DYNAMIC_FTRACE
> +
> +ENTRY(ftrace_stub)
> + ret
> + ;;
> +ENDPROC(ftrace_stub)
> +
> diff --git a/arch/kvx/kernel/return_address.c b/arch/kvx/kernel/return_address.c
> new file mode 100644
> index 000000000000..3ddf7b79662c
> --- /dev/null
> +++ b/arch/kvx/kernel/return_address.c
> @@ -0,0 +1,55 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * derived from arch/arm64/kernel/return_address.c
> + *
> + * Copyright (C) 2017-2023 Kalray Inc.
> + * Author(s): Clement Leger
> + */
> +
> +#include <linux/export.h>
> +#include <linux/ftrace.h>
> +#include <linux/kprobes.h>
> +
> +#include <asm/stacktrace.h>
> +
> +struct return_address_data {
> + unsigned int level;
> + void *addr;
> +};
> +
> +static bool save_return_addr(unsigned long pc, void *d)
> +{
> + struct return_address_data *data = d;
> +
> + /* We hit the desired level, return the address */
> + if (data->level == 0) {
> + data->addr = (void *) pc;
> + return true;
> + }
> +
> + data->level--;
> + return false;
> +}
> +NOKPROBE_SYMBOL(save_return_addr);
> +
> +void *return_address(unsigned int level)
> +{
> + struct return_address_data data;
> + struct stackframe frame;
> +
> + /* Skip this function + caller */
> + data.level = level + 2;
> + data.addr = NULL;
> +
> + start_stackframe(&frame,
> + (unsigned long) __builtin_frame_address(0),
> + (unsigned long) return_address);
> + walk_stackframe(current, &frame, save_return_addr, &data);
> +
> + if (!data.level)
> + return data.addr;
> + else
> + return NULL;
> +}
> +EXPORT_SYMBOL_GPL(return_address);
> +NOKPROBE_SYMBOL(return_address);



--
Clément Léger,
Embedded Linux and Kernel engineer at Bootlin
https://bootlin.com

2023-01-05 14:51:12

by Steven Rostedt

[permalink] [raw]
Subject: Re: [RFC PATCH 21/25] kvx: Add support for ftrace

On Thu, 5 Jan 2023 13:55:26 +0100
Clément Léger <[email protected]> wrote:

> > +/* The longest insns we check are for the far call: make + icall */
> > +#define MAX_SYLLABLES_TO_CHECK (KVX_INSN_MAKE_IMM64_SIZE + INSN_ICALL_SYLLABLE_SIZE)
> > +
> > +static int read_insns_and_check(u32 *insns, u8 insns_len, u32 *addr)
> > +{
> > + u32 insns_read[MAX_SYLLABLES_TO_CHECK];
> > + int syllables = insns_len / KVX_INSN_SYLLABLE_WIDTH;
> > + int i;
> > +
> > + if (syllables > MAX_SYLLABLES_TO_CHECK) {
> > + pr_err("%s: shouldn't have more than %d syllables to check\n",
> > + __func__, MAX_SYLLABLES_TO_CHECK);
> > + return -EINVAL;
> > + }
> > +
> > + if (kvx_insns_read(insns_read, insns_len, addr)) {
> > + pr_err("%s: error when trying to read syllable\n", __func__);
> > + return -EFAULT;
> > + }
> > +
> > + for (i = 0; i < syllables; i++) {
> > + if (insns[i] != insns_read[i]) {
> > + pr_err("%s: Instruction verification failed at PC 0x%lx\n",
> > + __func__,
> > + (unsigned long)addr + i * KVX_INSN_SYLLABLE_WIDTH);
> > + pr_err("%s: \tExpect 0x%x\n", __func__, insns[i]);
> > + pr_err("%s: \tRead 0x%x\n", __func__, insns_read[i]);
> > + return -EFAULT;
> > + }
> > + }
> > +
> > + return 0;
> > +}
>
> Hi Yann,
>
> Is this still needed ? I'm guessing the instructions should always be
> correctly written no ? If not, something probably went horribly wrong ;)

I would definitely keep it. Code modifications can be quite fragile. Most
of the time things don't go wrong, but when they do, having these checks
makes it obvious to where the problem happened. Problems here is usually
some code mapping that got incorrectly flagged to be traced, when it
shouldn't be. Reporting these errors helps find what that was.

-- Steve


>
> > +
> > +static int write_insns_and_check(u32 *insns, u8 insns_len, u32 *insn_addr)
> > +{
> > + int ret;
> > +
> > + ret = kvx_insns_write_nostop(insns, insns_len, insn_addr);
> > + if (ret)
> > + return ret;
> > +
> > + /* Check that what have been written is correct. */
> > + return read_insns_and_check(insns, insns_len, insn_addr);
> > +}
> > +

2023-01-05 15:07:20

by Steven Rostedt

[permalink] [raw]
Subject: Re: [RFC PATCH 00/25] Upstream kvx Linux port

On Thu, 05 Jan 2023 13:05:32 +0100
"Arnd Bergmann" <[email protected]> wrote:

> >> I did not receive most of the other patches as I'm
> >> not subscribed to all the mainline lists. For future
> >> submissions, can you add the linux-arch list to Cc for
> >> all patches?
> >
> > We misused get_maintainers.pl, running it on each patch instead
> > of using it on the whole series. next time every one will be in
> > copy of every patch in the series and including linux-arch.
>
> Be careful not to make the list too long though, there is
> usually a limit of 1024 characters for the entire Cc list,
> above this your mails may get dropped by the mailing lists.

It's best to include mailing lists for the entire series, and perhaps
individuals for each patch. As I don't want the entire series just to see
the tracing portion.

-- Steve

2023-01-05 15:35:46

by Mark Rutland

[permalink] [raw]
Subject: Re: [RFC PATCH 21/25] kvx: Add support for ftrace

Hi,

As others have said, I think it'd be worth splitting this series up, with this
being part of a follow-up, since it's not vital to boot and use the kernel.
That'll aid review of the smaller initial series, and later we can focus on the
bits and pieces here.

That said, I have a few comments below.

On Tue, Jan 03, 2023 at 05:43:55PM +0100, Yann Sionneau wrote:
> Add support for ftrace to kvx arch.
>
> CC: Steven Rostedt <[email protected]>
> CC: Masami Hiramatsu <[email protected]>
> CC: Mark Rutland <[email protected]>
> CC: [email protected]
> Co-developed-by: Clement Leger <[email protected]>
> Signed-off-by: Clement Leger <[email protected]>
> Co-developed-by: Guillaume Thouvenin <[email protected]>
> Signed-off-by: Guillaume Thouvenin <[email protected]>
> Co-developed-by: Julian Vetter <[email protected]>
> Signed-off-by: Julian Vetter <[email protected]>
> Co-developed-by: Marius Gligor <[email protected]>
> Signed-off-by: Marius Gligor <[email protected]>
> Co-developed-by: Yann Sionneau <[email protected]>
> Signed-off-by: Yann Sionneau <[email protected]>
> ---
> arch/kvx/include/asm/ftrace.h | 41 ++++
> arch/kvx/kernel/ftrace.c | 339 ++++++++++++++++++++++++++++++
> arch/kvx/kernel/mcount.S | 340 +++++++++++++++++++++++++++++++
> arch/kvx/kernel/return_address.c | 55 +++++
> 4 files changed, 775 insertions(+)
> create mode 100644 arch/kvx/include/asm/ftrace.h
> create mode 100644 arch/kvx/kernel/ftrace.c
> create mode 100644 arch/kvx/kernel/mcount.S
> create mode 100644 arch/kvx/kernel/return_address.c
>
> diff --git a/arch/kvx/include/asm/ftrace.h b/arch/kvx/include/asm/ftrace.h
> new file mode 100644
> index 000000000000..f7bcb325d255
> --- /dev/null
> +++ b/arch/kvx/include/asm/ftrace.h
> @@ -0,0 +1,41 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (C) 2017-2023 Kalray Inc.
> + * Author(s): Guillaume Thouvenin
> + * Clement Leger
> + */
> +
> +#ifndef _ASM_KVX_FTRACE_H
> +#define _ASM_KVX_FTRACE_H
> +
> +#include <asm/insns_defs.h>

The <asm/insns_defs.h> header file gets added by a subsequent patch, in:

"[RFC PATCH 23/25] kvx: Add debugging related support"

Obviously that means it won't build as-is, but it's also confusing for
reviewers.

> +
> +#define INSN_MAKE_IMM64_SYLLABLE_SIZE INSN_SIZE(MAKE_IMM64)

IIUC this is 12 bytes.

> +#define INSN_ICALL_SYLLABLE_SIZE INSN_SIZE(ICALL)
> +#define INSN_IGOTO_SYLLABLE_SIZE INSN_SIZE(IGOTO)
> +#define INSN_CALL_SYLLABLE_SIZE INSN_SIZE(CALL)
> +#define INSN_NOP_SYLLABLE_SIZE INSN_SIZE(NOP)

IIUC all these are all 4 bytes.

> +
> +#define INSN_ICALL_REG_MASK 0x3f
> +
> +#define MCOUNT_ADDR ((unsigned long)(__mcount))
> +#define MCOUNT_INSN_SIZE INSN_CALL_SYLLABLE_SIZE /* sizeof mcount call */

Does your GCC port support -fpatchable-function-entry?

If it does, I would strongly recommend moving over to using that, as it'll
allow you to implement FTRACE_WITH_ARGS and all the fancy features dependent
upon that.

If it doesn't, I'd strongly recommend implementing that on the GCC side now so
that you can make use of it in future without having to retain support for an
mcount based ftrace. That'll make things easier to maintain going forwards, and
it'll give you a lot of flexibility w.r.t. your ftrace implementation.

> +extern void ftrace_graph_call(void);
> +
> +#ifdef CONFIG_DYNAMIC_FTRACE
> +extern unsigned long ftrace_call_adjust(unsigned long addr);
> +struct dyn_arch_ftrace {
> + unsigned int insn;
> +};
> +#endif
> +
> +extern void *return_address(unsigned int level);
> +#define ftrace_return_address(n) return_address(n)
> +
> +#ifdef CONFIG_FUNCTION_TRACER
> +extern void __mcount(void);
> +#define mcount __mcount
> +#endif /* CONFIG_FUNCTION_TRACER */
> +
> +#endif /* _ASM_KVX_FTRACE_H */
> diff --git a/arch/kvx/kernel/ftrace.c b/arch/kvx/kernel/ftrace.c
> new file mode 100644
> index 000000000000..4c9e3ef62714
> --- /dev/null
> +++ b/arch/kvx/kernel/ftrace.c
> @@ -0,0 +1,339 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2017-2023 Kalray Inc.
> + * Author(s): Guillaume Thouvenin
> + * Marius Gligor
> + * Clement Leger
> + */
> +
> +#include <linux/ftrace.h>
> +#include <linux/atomic.h>
> +#include <linux/stop_machine.h>
> +#include <asm/insns.h>
> +#include <asm/insns_defs.h>
> +#include <asm/cacheflush.h>
> +
> +/* The longest insns we check are for the far call: make + icall */
> +#define MAX_SYLLABLES_TO_CHECK (KVX_INSN_MAKE_IMM64_SIZE + INSN_ICALL_SYLLABLE_SIZE)

What's the range on your CALL instruction? Is that smaller than your kernel
image size, or is this just for modules?

> +
> +static int read_insns_and_check(u32 *insns, u8 insns_len, u32 *addr)
> +{
> + u32 insns_read[MAX_SYLLABLES_TO_CHECK];
> + int syllables = insns_len / KVX_INSN_SYLLABLE_WIDTH;
> + int i;
> +
> + if (syllables > MAX_SYLLABLES_TO_CHECK) {
> + pr_err("%s: shouldn't have more than %d syllables to check\n",
> + __func__, MAX_SYLLABLES_TO_CHECK);
> + return -EINVAL;
> + }
> +
> + if (kvx_insns_read(insns_read, insns_len, addr)) {
> + pr_err("%s: error when trying to read syllable\n", __func__);
> + return -EFAULT;
> + }
> +
> + for (i = 0; i < syllables; i++) {
> + if (insns[i] != insns_read[i]) {
> + pr_err("%s: Instruction verification failed at PC 0x%lx\n",
> + __func__,
> + (unsigned long)addr + i * KVX_INSN_SYLLABLE_WIDTH);
> + pr_err("%s: \tExpect 0x%x\n", __func__, insns[i]);
> + pr_err("%s: \tRead 0x%x\n", __func__, insns_read[i]);
> + return -EFAULT;
> + }
> + }
> +
> + return 0;
> +}
> +
> +static int write_insns_and_check(u32 *insns, u8 insns_len, u32 *insn_addr)
> +{
> + int ret;
> +
> + ret = kvx_insns_write_nostop(insns, insns_len, insn_addr);
> + if (ret)
> + return ret;

Again, kvx_insns_write_nostop() is added by a subsequenbt patch, which makes
this painful to review.

AFAICT this assumees that you can concurrently modify instructions while those
are being executed. Does your architecture provide a strong guanratee there?
For example, on arm64 we can only do this safely for a defined small set of
instructions (including B/BL/BLR/NOP), and even then it doesn't gurantee that
updates to multiple instructions will be seen in order.

I see that ftrace_enable_ftrace_graph_caller() writes multiple instructions,
which strikes me as likely to be unsafe depending on the ordering and atomicity
of both those writes and the instruction fetches which will consume them.

I see that for arch_ftrace_update_code() you use stop_machine(), and I'd expect
similar here, but maybe I've missed something that inhibits concurrent
exxecution?

> +
> + /* Check that what have been written is correct. */
> + return read_insns_and_check(insns, insns_len, insn_addr);
> +}
> +
> +#ifdef CONFIG_FUNCTION_GRAPH_TRACER
> +void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
> + unsigned long frame_pointer)
> +{
> + unsigned long return_hooker = (unsigned long)&return_to_handler;
> + unsigned long old;
> +
> + if (unlikely(atomic_read(&current->tracing_graph_pause)))
> + return;
> +
> + old = *parent;
> + *parent = return_hooker;
> +
> + if (function_graph_enter(old, self_addr, frame_pointer, NULL))
> + *parent = old;
> +}
> +
> +#ifdef CONFIG_DYNAMIC_FTRACE
> +int ftrace_enable_ftrace_graph_caller(void)
> +{
> + unsigned int insn[KVX_INSN_MAKE_IMM64_SIZE + KVX_INSN_IGOTO_SIZE];
> + void *ip = (void *)ftrace_call;
> +
> + KVX_INSN_MAKE_IMM64(insn, KVX_INSN_PARALLEL_EOB, KVX_REG_R32,
> + (unsigned long)&ftrace_graph_call);
> + KVX_INSN_IGOTO(&insn[KVX_INSN_MAKE_IMM64_SIZE],
> + KVX_INSN_PARALLEL_EOB,
> + KVX_REG_R32);
> +
> + return write_insns_and_check(insn,
> + INSN_MAKE_IMM64_SYLLABLE_SIZE
> + + INSN_IGOTO_SYLLABLE_SIZE,
> + ip);
> +}
> +
> +int ftrace_disable_ftrace_graph_caller(void)
> +{
> + unsigned int nop;
> + void *ip = (void *)ftrace_call;
> +
> + KVX_INSN_NOP(&nop, KVX_INSN_PARALLEL_EOB);
> + return write_insns_and_check(&nop,
> + INSN_NOP_SYLLABLE_SIZE,
> + ip + INSN_MAKE_IMM64_SYLLABLE_SIZE);
> +}
> +#endif /* CONFIG_DYNAMIC_FTRACE */
> +
> +#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
> +
> +#ifdef CONFIG_DYNAMIC_FTRACE
> +struct kvx_ftrace_modify_param {
> + atomic_t cpu_ack;
> + int cpu_master;
> + int cmd;
> +};
> +
> +static int __ftrace_modify_code_kvx(void *data)
> +{
> + struct kvx_ftrace_modify_param *mp = data;
> + int no_cpus = num_online_cpus();
> + int cpu = smp_processor_id();
> +
> + if (cpu == mp->cpu_master) {
> + ftrace_modify_all_code(mp->cmd);
> +
> + /* Inform the other cpus that they can invalidate I-cache */
> + atomic_inc(&mp->cpu_ack);
> +
> + /* param (which contains the cpu_ack counter) is allocated on the
> + * master stack: the master must wait for all other CPUs to leave
> + * this function before returning and releasing the stack
> + * allocation.
> + */
> + while (atomic_read(&mp->cpu_ack) < no_cpus)
> + cpu_relax();
> + } else {
> + /* Wait for the master cpu to finish the code modification */
> + while (atomic_read(&mp->cpu_ack) == 0)
> + cpu_relax();
> + atomic_inc(&mp->cpu_ack);
> +
> + l1_inval_icache_all();

Wouldn't it make more sense to do the icache invalidate *before* signalling the
master?

This function (and its callees) will need to be noinstr to be safe. There's
some latent issues there on arm64 which I'm slowly working through at the
moment, but there's no need for you to start with the same problems.

> + }
> +
> + return 0;
> +}
> +
> +void arch_ftrace_update_code(int command)
> +{
> + const struct cpumask *cpumask = cpu_online_mask;

Below you use cpu_online_mask directly, so this isn't necessary.

> + struct kvx_ftrace_modify_param mp = {
> + .cpu_ack = ATOMIC_INIT(0),
> + .cpu_master = smp_processor_id(),
> + .cmd = command,
> + };
> +
> + stop_machine(__ftrace_modify_code_kvx, &mp, cpu_online_mask);
> +}
> +
> +unsigned long ftrace_call_adjust(unsigned long addr)
> +{
> + /*
> + * Module are using far call and kernel functions are using
> + * pcrel. If it is a call we don't need to adjust the address but
> + * if it is an icall the address is on the make. The generated code
> + * looks like:
> + *
> + * 1c: e0 00 c4 8f get $r32 = $ra
> + * 20: 00 00 84 e0 00 00 00 80 00 00 00 00 make $r33 = 0 (0x0);;
> + *
> + * 20: R_KVX_S64_LO10 __mcount
> + * 24: R_KVX_S64_UP27 __mcount
> + * 28: R_KVX_S64_EX27 __mcount
> + * 2c: 21 00 dc 0f icall $r33;;
> + *
> + * So we just need to add INSN_MAKE_IMM64_SYLLABLE_SIZE (0xc) to the
> + * address.
> + */

You could cheat here, and place a small veneer/PLT next to each module to do
the indirect branch to ftrace. That way, each call site would only need a pcrel
rather than a far call, which might simplfiy your runtime patching logic.

On arm64 we a special ftrace PLT for this.

> + unsigned int insn;
> +
> + /*
> + * The CALL is 1 syllable while the MAKE IMM64 is 3. But we just
> + * need to check that the first syllable of the MAKE IMM64 is the
> + * LO10. So finally we just need to read one syllable to adjust the
> + * call.
> + */
> + if (kvx_insns_read(&insn, KVX_INSN_SYLLABLE_WIDTH, (void *)addr)) {
> + pr_err("%s: error when trying to read syllable\n", __func__);
> + return 0;
> + }
> +
> + if (IS_INSN(insn, CALL))
> + return addr;
> +
> + if (IS_INSN(insn, MAKE_IMM64))
> + return addr + INSN_MAKE_IMM64_SYLLABLE_SIZE;
> +
> + pr_err("%s: syllable is neither a CALL nor a MAKE\n", __func__);
> + return 0;
> +}
> +
> +/*
> + * Do runtime patching of the active tracer.
> + * This will be modifying the assembly code at the location of the
> + * ftrace_call symbol inside of the ftrace_caller() function.
> + */
> +int ftrace_update_ftrace_func(ftrace_func_t func)
> +{
> + void *ip;
> + unsigned int insn[KVX_INSN_MAKE_IMM64_SIZE + KVX_INSN_ICALL_SIZE];
> +
> + ip = (void *)ftrace_call;
> + KVX_INSN_MAKE_IMM64(insn, KVX_INSN_PARALLEL_EOB, KVX_REG_R32,
> + (unsigned long)func);
> + KVX_INSN_ICALL(&insn[KVX_INSN_MAKE_IMM64_SIZE],
> + KVX_INSN_PARALLEL_EOB,
> + KVX_REG_R32);
> + return write_insns_and_check(insn,
> + INSN_MAKE_IMM64_SYLLABLE_SIZE
> + + INSN_ICALL_SYLLABLE_SIZE,
> + ip);
> +}
> +
> +/*
> + * Turn the mcount call site into a call to an arbitrary location (but
> + * typically that is ftrace_caller()) at runtime.
> + */
> +int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
> +{
> + void *ip = (void *)rec->ip;
> + unsigned int insn;
> + int ret;
> +
> + /* Ensure that a NOP will be replaced */
> + if (kvx_insns_read(&insn, KVX_INSN_SYLLABLE_WIDTH, ip)) {
> + pr_err("%s: failed to read insn\n", __func__);
> + return -EFAULT;
> + }
> +
> + if (!IS_INSN(insn, NOP)) {
> + pr_err("%s: insn 0x%x is not a NOP\n", __func__, insn);
> + return -EINVAL;
> + }
> +
> + /*
> + * Now we can replace the instruction depending of what has been
> + * nopified (call or icall)
> + */
> + insn = rec->arch.insn;
> +
> + if (IS_INSN(insn, CALL)) {
> + s32 pcrel = addr - (unsigned long) ip;
> + u32 insn_call;
> +
> + BUG_ON(KVX_INSN_GOTO_PCREL27_CHECK(pcrel));
> + KVX_INSN_CALL(&insn_call, KVX_INSN_PARALLEL_EOB, pcrel);
> +
> + return write_insns_and_check(&insn_call,
> + INSN_CALL_SYLLABLE_SIZE, ip);
> + }
> +
> + if (IS_INSN(insn, ICALL)) {
> + u32 insn_make[KVX_INSN_MAKE_IMM64_SIZE];
> + u32 r = insn & INSN_ICALL_REG_MASK;
> +
> + KVX_INSN_MAKE_IMM64(insn_make, KVX_INSN_PARALLEL_EOB, r, addr);
> + ret = write_insns_and_check(insn_make,
> + INSN_MAKE_IMM64_SYLLABLE_SIZE,
> + ip - INSN_MAKE_IMM64_SYLLABLE_SIZE);
> + if (ret)
> + return ret;
> +
> + return write_insns_and_check(&insn,
> + INSN_ICALL_SYLLABLE_SIZE, ip);
> + }
> +
> + /* It is neither a call nor an icall */
> + pr_err("%s: insn 0x%x is neither a CALL nor ICALL\n", __func__, insn);
> + return -EINVAL;
> +}
> +
> +/*
> + * Turn the mcount call site into a nop at runtime
> + */
> +int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
> + unsigned long addr)
> +{
> + unsigned long ip = rec->ip;
> + unsigned int insn;
> + unsigned int nop;
> +
> + /*
> + * Ensure that the instruction that will be replaced is a call or an
> + * icall to addr.
> + */
> + if (kvx_insns_read(&insn, KVX_INSN_SYLLABLE_WIDTH, (void *)ip)) {
> + pr_err("%s: error when trying to read syllable\n", __func__);
> + return -EFAULT;
> + }
> +
> + if (IS_INSN(insn, CALL)) {
> + int pcrel = ((int)(insn & 0x7ffffff) << 5) >> 3;
> +
> + if ((ip + pcrel != addr)) {
> + pr_err("%s: failed to check call addr 0x%lx != 0x%lx\n",
> + __func__, ip + pcrel, addr);
> + return -EINVAL;
> + }
> + } else if (IS_INSN(insn, ICALL)) {
> + unsigned int insn_make[KVX_INSN_MAKE_IMM64_SIZE];
> + unsigned int reg = insn & INSN_ICALL_REG_MASK;
> + int ret;
> +
> + KVX_INSN_MAKE_IMM64(insn_make,
> + KVX_INSN_PARALLEL_EOB, reg,
> + addr);
> +
> + ret = read_insns_and_check(insn_make,
> + INSN_MAKE_IMM64_SYLLABLE_SIZE,
> + (void *)ip -
> + INSN_MAKE_IMM64_SYLLABLE_SIZE);
> + if (ret)
> + return ret;
> + } else {
> + pr_err("%s: insn 0x%x is neither a CALL nor an ICALL\n",
> + __func__, insn);
> + return -EINVAL;
> + }
> +
> + rec->arch.insn = insn;
> + KVX_INSN_NOP(&nop, KVX_INSN_PARALLEL_EOB);
> + return write_insns_and_check(&nop, INSN_NOP_SYLLABLE_SIZE, (void *)ip);
> +}
> +
> +#endif /* CONFIG_DYNAMIC_FTRACE */
> +
> +/* __mcount is defined in mcount.S */
> +EXPORT_SYMBOL(__mcount);
> diff --git a/arch/kvx/kernel/mcount.S b/arch/kvx/kernel/mcount.S
> new file mode 100644
> index 000000000000..317797aeed42
> --- /dev/null
> +++ b/arch/kvx/kernel/mcount.S
> @@ -0,0 +1,340 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (C) 2017-2023 Kalray Inc.
> + * Author(s): Guillaume Thouvenin
> + * Marius Gligor
> + * Clement Leger
> + */
> +
> +#include <linux/linkage.h>
> +#include <asm/insns_defs.h>
> +#include <asm/sfr_defs.h>
> +
> +.altmacro
> +
> +/*
> + * !!! The call to __mcount is special and breaks the ABI !!!
> + * It is because with dynamic ftrace the call can be replaced by any
> + * tracer and GCC cannot assume which caller registers must be saved.
> + * It's because the call is being inserted in the prologue of functions
> + * that is out of GCC knowledge.
> + * We could make this known to GCC, but then we would hit the problem of not
> + * being able to easily decide which insns are emitted and how they are
> + * bundled. So we choose to save nothing when calling __mcount and we will
> + * save all caller registers once __mcount called.

What about the return address? I assume that this is a branch-and-link
architecture, and CALL/ICALL clobber that?

Thanks,
Mark.

> + *
> + * Another specificity is that parameter is passed in $r32 instead of $r0.
> + *
> + * Our stack will be:
> + * 0 | $FP $RA $r15 -
> + * 32 | $r0 $r1 $r2 $r3
> + * 64 | $r4 $r5 $r6 $r7
> + * 96 | $r8 $r9 $r10 $r11
> + * 128| $r32 $r33 $r34 $r35
> + * 160| $r36 $r37 $r38 $r39
> + * 192| $r40 $r41 $r42 $r43
> + * 224| $r44 $r45 $r46 $r47
> + * 256| $r48 $r49 $r50 $r51
> + * 288| $r52 $r53 $r54 $r55
> + * 320| $r56 $r57 $r58 $r59
> + * 352| $r60 $r61 $r62 $r63
> + * 384| $r16 $r17
> + */
> +
> +#define STACK_OFFSET_FP 0
> +#define STACK_OFFSET_RA (STACK_OFFSET_FP + 8)
> +#define STACK_OFFSET_R15 (STACK_OFFSET_RA + 8)
> +#define STACK_OFFSET_Q0 (STACK_OFFSET_FP + 32)
> +#define STACK_OFFSET_Q4 (STACK_OFFSET_Q0 + 32)
> +#define STACK_OFFSET_Q8 (STACK_OFFSET_Q4 + 32)
> +#define STACK_OFFSET_Q32 (STACK_OFFSET_Q8 + 32)
> +#define STACK_OFFSET_Q36 (STACK_OFFSET_Q32 + 32)
> +#define STACK_OFFSET_Q40 (STACK_OFFSET_Q36 + 32)
> +#define STACK_OFFSET_Q44 (STACK_OFFSET_Q40 + 32)
> +#define STACK_OFFSET_Q48 (STACK_OFFSET_Q44 + 32)
> +#define STACK_OFFSET_Q52 (STACK_OFFSET_Q48 + 32)
> +#define STACK_OFFSET_Q56 (STACK_OFFSET_Q52 + 32)
> +#define STACK_OFFSET_Q60 (STACK_OFFSET_Q56 + 32)
> +#define STACK_OFFSET_P16 (STACK_OFFSET_Q60 + 32)
> +#define STACK_SIZE (STACK_OFFSET_P16 + 16)
> +
> +#define RA_DWARF_REGNO (64 + KVX_SFR_RA)
> +#define R14_DWARF_REGNO 14
> +
> +.macro save_all_context_but_P16
> + /*
> + * r16 and r17 are already saved. r16 is already used to store the
> + * address of the function tracer if any.
> + * so !!! USE r17 as scratch register !!!
> + */
> + get $r17 = $ra
> + sd STACK_OFFSET_FP[$r12] = $r14
> + ;;
> + .cfi_offset R14_DWARF_REGNO, -STACK_SIZE + STACK_OFFSET_FP
> + sd STACK_OFFSET_RA[$r12] = $r17
> + ;;
> + .cfi_offset RA_DWARF_REGNO, -STACK_SIZE + STACK_OFFSET_RA
> + sd STACK_OFFSET_R15[$r12] = $r15
> + ;;
> + so STACK_OFFSET_Q0[$r12] = $r0r1r2r3
> + ;;
> + so STACK_OFFSET_Q4[$r12] = $r4r5r6r7
> + ;;
> + so STACK_OFFSET_Q8[$r12] = $r8r9r10r11
> + ;;
> + so STACK_OFFSET_Q32[$r12] = $r32r33r34r35
> + ;;
> + so STACK_OFFSET_Q36[$r12] = $r36r37r38r39
> + ;;
> + so STACK_OFFSET_Q40[$r12] = $r40r41r42r43
> + ;;
> + so STACK_OFFSET_Q44[$r12] = $r44r45r46r47
> + ;;
> + so STACK_OFFSET_Q48[$r12] = $r48r49r50r51
> + ;;
> + so STACK_OFFSET_Q52[$r12] = $r52r53r54r55
> + ;;
> + so STACK_OFFSET_Q56[$r12] = $r56r57r58r59
> + ;;
> + so STACK_OFFSET_Q60[$r12] = $r60r61r62r63
> + ;;
> +.endm
> +
> +.macro restore_all_context
> + ld $r15 = STACK_OFFSET_RA[$r12]
> + ;;
> + ld $r14 = STACK_OFFSET_FP[$r12]
> + set $ra = $r15
> + ;;
> + .cfi_restore RA_DWARF_REGNO
> + .cfi_restore R14_DWARF_REGNO
> + ld $r15 = STACK_OFFSET_R15[$r12]
> + ;;
> + lq $r16r17 = STACK_OFFSET_P16[$r12]
> + ;;
> + lo $r0r1r2r3 = STACK_OFFSET_Q0[$r12]
> + ;;
> + lo $r4r5r6r7 = STACK_OFFSET_Q4[$r12]
> + ;;
> + lo $r8r9r10r11 = STACK_OFFSET_Q8[$r12]
> + ;;
> + lo $r32r33r34r35 = STACK_OFFSET_Q32[$r12]
> + ;;
> + lo $r36r37r38r39 = STACK_OFFSET_Q36[$r12]
> + ;;
> + lo $r40r41r42r43 = STACK_OFFSET_Q40[$r12]
> + ;;
> + lo $r44r45r46r47 = STACK_OFFSET_Q44[$r12]
> + ;;
> + lo $r48r49r50r51 = STACK_OFFSET_Q48[$r12]
> + ;;
> + lo $r52r53r54r55 = STACK_OFFSET_Q52[$r12]
> + ;;
> + lo $r56r57r58r59 = STACK_OFFSET_Q56[$r12]
> + ;;
> + lo $r60r61r62r63 = STACK_OFFSET_Q60[$r12]
> + ;;
> + addd $r12 = $r12, STACK_SIZE
> + ;;
> + .cfi_def_cfa_offset 0
> +.endm
> +
> +ENTRY(__mcount)
> +.cfi_startproc
> +#ifdef CONFIG_DYNAMIC_FTRACE
> + /*
> + * With dynamic ftrace mcount() is only used during boot and then all
> + * references to it will be patched out never to return. ftrace_caller
> + * is used.
> + */
> + ret
> + ;;
> +#endif
> + addd $r12 = $r12, -STACK_SIZE
> + ;;
> + .cfi_def_cfa_offset STACK_SIZE
> + sq STACK_OFFSET_P16[$r12] = $r16r17
> + ;;
> +#ifdef CONFIG_FUNCTION_GRAPH_TRACER
> + /*
> + * Check the function pointers ftrace_graph_return
> + * (compare to ftrace_stub) and ftrace_graph_entry (compare to
> + * ftrace_graph_entry_stub). If either of those is not set to the
> + * relevant stub function, call the arch-specific function
> + * ftrace_graph_caller.
> + */
> + make $r16 = ftrace_graph_return
> + make $r17 = ftrace_graph_entry
> + ;;
> + ld $r16 = 0[$r16]
> + ;;
> + compd.eq $r16 = $r16, ftrace_stub
> + ld $r17 = 0[$r17]
> + ;;
> + /*
> + * If ftrace_graph_return is not equal to ftrace_stub ($r16 == 0) then
> + * jump to ftrace_graph_caller. Otherwise compare ftrace_graph_entry.
> + */
> + cb.deqz $r16? ftrace_graph_caller
> + compd.eq $r17 = $r17, ftrace_graph_entry_stub
> + ;;
> + /*
> + * If ftrace_graph_entry is equal to ftrace_graph_entry_stub ($r17 == 1)
> + * then jump to ftrace_graph_end. If not we continue.
> + */
> + cb.dnez $r17? ftrace_graph_end
> + ;;
> +ftrace_graph_caller:
> + save_all_context_but_P16
> + ;;
> +GLOBAL(ftrace_graph_call)
> + ld $r16 = 0[$r12]
> + ;;
> + addd $r0 = $r16, 0x8 /* a pointer to the frompc */
> + get $r1 = $ra /* selfpc */
> + copyd $r2 = $r16 /* FP of the function that called __mcount */
> + ;;
> + /* get the address of the bundle */
> + addd $r1 = $r1, -KVX_INSN_SYLLABLE_WIDTH
> + ;;
> + call prepare_ftrace_return
> + ;;
> + restore_all_context
> + ;;
> + ret
> + ;;
> +ftrace_graph_end:
> + .cfi_def_cfa_offset STACK_SIZE
> +#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
> + /*
> + * Check if function pointer ftrace_trace_function is set to
> + * ftrace_stub.
> + * If it isn't, then call that function in the same way the mcount
> + * function normally calls __mcount_internal
> + * - the first argument is the "frompc" ($r0)
> + * - the second argument is the "selfpc" ($ra - mcount size adjustement)
> + * As we don't use any callee saved registers we don't need to save
> + * them.
> + */
> + make $r16 = ftrace_trace_function
> + ;;
> + ld $r16 = 0[$r16]
> + ;;
> + /*
> + * NOTE: keep value in $r16 (the function we may call if set). See
> + * comment in save_all_context_but_P16.
> + */
> + compd.eq $r17 = $r16, ftrace_stub
> + ;;
> + /*
> + * If ftrace_trace_function is equal to ftrace_stub ($r17 == 1), there
> + * is nothing to do, so return immediately otherwise call the function
> + * in $r16 with correct parameters.
> + */
> + cb.deqz $r17? 1f
> + ;;
> + /* Only need to restore P16 */
> + lq $r16r17 = STACK_OFFSET_P16[$r12]
> + ;;
> + addd $r12 = $r12, STACK_SIZE
> + ;;
> + .cfi_def_cfa_offset 0
> + ret
> + ;;
> +
> +1:
> + save_all_context_but_P16
> + ;;
> + copyd $r0 = $r32
> + get $r1 = $ra
> + ;;
> + addd $r1 = $r1, -KVX_INSN_SYLLABLE_WIDTH
> + ;;
> + icall $r16
> + ;;
> + restore_all_context
> + ;;
> + ret
> + ;;
> +.cfi_endproc
> +ENDPROC(__mcount)
> +
> +/* Required by ftrace_graph_ret_addr */
> +#ifdef CONFIG_FUNCTION_GRAPH_TRACER
> +ENTRY(return_to_handler)
> + addd $r12 = $r12, -128
> + ;;
> + so 0[$r12] = $r0r1r2r3
> + ;;
> + so 32[$r12] = $r4r5r6r7
> + ;;
> + so 64[$r12] = $r8r9r10r11
> + ;;
> + call ftrace_return_to_handler
> + ;;
> + set $ra = $r0
> + lo $r0r1r2r3 = 0[$r12]
> + ;;
> + lo $r4r5r6r7 = 32[$r12]
> + ;;
> + lo $r8r9r10r11 = 64[$r12]
> + addd $r12 = $r12, 128
> + ;;
> + ret
> + ;;
> +ENDPROC(return_to_handler)
> +#endif
> +
> +#ifdef CONFIG_DYNAMIC_FTRACE
> +ENTRY(ftrace_caller)
> +.cfi_startproc
> +
> + addd $r12 = $r12, -STACK_SIZE
> + ;;
> + .cfi_def_cfa_offset STACK_SIZE
> + sq STACK_OFFSET_P16[$r12] = $r16r17
> + ;;
> + save_all_context_but_P16
> + ;;
> + copyd $r0 = $r32
> + get $r1 = $ra
> + ;;
> + addd $r1 = $r1, -KVX_INSN_SYLLABLE_WIDTH
> + ;;
> + goto ftrace_call
> + ;;
> +.align 64
> +GLOBAL(ftrace_call)
> + /*
> + * To work with module we need to use far call. So prepare the
> + * space for them:
> + * - make: 3 syllables
> + * - icall/igoto: 1 syllable
> + *
> + * We are using igoto in ftrace_enable_ftrace_graph_caller(). This is
> + * because this path is a tweak to enable function graph tracer with
> + * dynamic ftrace. We need to jump to ftrace_graph_call without updating
> + * RA and FP. Once in ftrace_graph_call we will return to the correct
> + * address from the classical path of the function graph tracer.
> + */
> + nop
> + ;;
> + nop
> + ;;
> + nop
> + ;;
> + nop
> + ;;
> + restore_all_context
> + ;;
> + ret
> + ;;
> +.cfi_endproc
> +ENDPROC(ftrace_caller)
> +#endif // CONFIG_DYNAMIC_FTRACE
> +
> +ENTRY(ftrace_stub)
> + ret
> + ;;
> +ENDPROC(ftrace_stub)
> +

2023-01-07 06:46:11

by Jeff Xie

[permalink] [raw]
Subject: Re: [RFC PATCH 00/25] Upstream kvx Linux port

Hi,

On Wed, Jan 4, 2023 at 1:01 AM Yann Sionneau <[email protected]> wrote:
>
> This patch series adds support for the kv3-1 CPU architecture of the kvx family
> found in the Coolidge (aka MPPA3-80) SoC of Kalray.
>
> This is an RFC, since kvx support is not yet upstreamed into gcc/binutils,
> therefore this patch series cannot be merged into Linux for now.
>
> The goal is to have preliminary reviews and to fix problems early.
>
> The Kalray VLIW processor family (kvx) has the following features:
> * 32/64 bits execution mode
> * 6-issue VLIW architecture
> * 64 x 64bits general purpose registers
> * SIMD instructions
> * little-endian
> * deep learning co-processor
>
> Kalray kv3-1 core which is the third of the kvx family is embedded in Kalray
> Coolidge SoC currently used on K200 and K200-LP boards.
>
> The Coolidge SoC contains 5 clusters each of which is made of:
> * 4MiB of on-chip memory (SMEM)
> * 1 dedicated safety/security core (kv3-1 core).
> * 16 PEs (Processing Elements) (kv3-1 cores).
> * 16 Co-processors (one per PE)
> * 2 Crypto accelerators
>
> The Coolidge SoC contains the following features:
> * 5 Clusters
> * 2 100G Ethernet controllers
> * 8 PCIe GEN4 controllers (Root Complex and Endpoint capable)
> * 2 USB 2.0 controllers
> * 1 Octal SPI-NOR flash controller
> * 1 eMMC controller
> * 3 Quad SPI controllers
> * 6 UART
> * 5 I2C controllers (3 of which are SMBus capable)
> * 4 CAN controllers
> * 1 OTP memory
>
> A kvx toolchain can be built using:
> # install dependencies: texinfo bison flex libgmp-dev libmpc-dev libmpfr-dev
> $ git clone https://github.com/kalray/build-scripts
> $ cd build-scripts
> $ source last.refs
> $ ./build-kvx-xgcc.sh output

I would like to build the kvx-xgcc to compile and test the linux
kernel, but it reported a compile error.
I wonder what version of gcc you are using.

My build environment:
VERSION="20.04.2 LTS (Focal Fossa)"
gcc version 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04)


Compile error:
$ ./build-kvx-xgcc.sh output

../../binutils/libiberty/fibheap.c: In function ‘fibheap_replace_key_data’:
../../binutils/libiberty/fibheap.c:38:24: error: ‘LONG_MIN’ undeclared
(first use in this function)
38 | #define FIBHEAPKEY_MIN LONG_MIN
| ^~~~~~~~
../../binutils/libiberty/fibheap.c:220:30: note: in expansion of macro
‘FIBHEAPKEY_MIN’
220 | if (okey == key && okey != FIBHEAPKEY_MIN)
| ^~~~~~~~~~~~~~
../../binutils/libiberty/fibheap.c:36:1: note: ‘LONG_MIN’ is defined
in header ‘<limits.h>’; did you forget to ‘#include <limits.h>’?
35 | #include "fibheap.h"
+++ |+#include <limits.h>
36 |
../../binutils/libiberty/fibheap.c:38:24: note: each undeclared
identifier is reported only once for each function it appears in
38 | #define FIBHEAPKEY_MIN LONG_MIN
| ^~~~~~~~
../../binutils/libiberty/fibheap.c:220:30: note: in expansion of macro
‘FIBHEAPKEY_MIN’
220 | if (okey == key && okey != FIBHEAPKEY_MIN)
| ^~~~~~~~~~~~~~
../../binutils/libiberty/fibheap.c: In function ‘fibheap_delete_node’:
../../binutils/libiberty/fibheap.c:38:24: error: ‘LONG_MIN’ undeclared
(first use in this function)
38 | #define FIBHEAPKEY_MIN LONG_MIN
| ^~~~~~~~
../../binutils/libiberty/fibheap.c:261:36: note: in expansion of macro
‘FIBHEAPKEY_MIN’
261 | fibheap_replace_key (heap, node, FIBHEAPKEY_MIN);
| ^~~~~~~~~~~~~~
../../binutils/libiberty/fibheap.c:38:24: note: ‘LONG_MIN’ is defined
in header ‘<limits.h>’; did you forget to ‘#include <limits.h>’?
38 | #define FIBHEAPKEY_MIN LONG_MIN
| ^~~~~~~~
../../binutils/libiberty/fibheap.c:261:36: note: in expansion of macro
‘FIBHEAPKEY_MIN’
261 | fibheap_replace_key (heap, node, FIBHEAPKEY_MIN);
| ^~~~~~~~~~~~~~


> The kvx toolchain will be installed in the "output" directory.
>
> A buildroot image (kernel+rootfs) and toolchain can be built using:
> $ git clone -b coolidge-for-upstream https://github.com/kalray/buildroot
> $ cd buildroot
> $ make O=build_kvx kvx_defconfig
> $ make O=build_kvx
>
> The vmlinux image can be found in buildroot/build_kvx/images/vmlinux.
>
> If you are just interested in building the Linux kernel with no rootfs you can
> just do this with the kvx-elf- toolchain:
> $ make ARCH=kvx O=build_kvx CROSS_COMPILE=kvx-elf- default_defconfig
> $ make ARCH=kvx O=build_kvx CROSS_COMPILE=kvx-elf- -j$(($(nproc) + 1))
>
> The vmlinux ELF can be run with qemu by doing:
> # install dependencies: ninja pkg-config libglib-2.0-dev cmake libfdt-dev libpixman-1-dev zlib1g-dev
> $ git clone https://github.com/kalray/qemu-builder
> $ cd qemu-builder
> $ git submodule update --init
> $ make -j$(($(nproc) + 1))
> $ ./qemu-system-kvx -m 1024 -nographic -kernel <path/to/vmlinux>
>
> Yann Sionneau (25):
> Documentation: kvx: Add basic documentation
> kvx: Add ELF-related definitions
> kvx: Add build infrastructure
> kvx: Add CPU definition headers
> kvx: Add atomic/locking headers
> kvx: Add other common headers
> kvx: Add boot and setup routines
> kvx: Add exception/interrupt handling
> kvx: irqchip: Add support for irq controllers
> kvx: Add process management
> kvx: Add memory management
> kvx: Add system call support
> kvx: Add signal handling support
> kvx: Add ELF relocations and module support
> kvx: Add misc common routines
> kvx: Add some library functions
> kvx: Add multi-processor (SMP) support
> kvx: Add kvx default config file
> kvx: power: scall poweroff driver
> kvx: gdb: add kvx related gdb helpers
> kvx: Add support for ftrace
> kvx: Add support for jump labels
> kvx: Add debugging related support
> kvx: Add support for CPU Perf Monitors
> kvx: Add support for cpuinfo
>
> .../kalray,kvx-core-intc.txt | 22 +
> .../devicetree/bindings/perf/kalray-pm.txt | 21 +
> Documentation/kvx/kvx-exceptions.txt | 246 +
> Documentation/kvx/kvx-iommu.txt | 183 +
> Documentation/kvx/kvx-mmu.txt | 272 +
> Documentation/kvx/kvx-smp.txt | 36 +
> Documentation/kvx/kvx.txt | 268 +
> arch/kvx/Kconfig | 249 +
> arch/kvx/Kconfig.debug | 70 +
> arch/kvx/Makefile | 52 +
> arch/kvx/configs/default_defconfig | 130 +
> arch/kvx/include/asm/Kbuild | 20 +
> arch/kvx/include/asm/asm-prototypes.h | 14 +
> arch/kvx/include/asm/atomic.h | 104 +
> arch/kvx/include/asm/barrier.h | 15 +
> arch/kvx/include/asm/bitops.h | 207 +
> arch/kvx/include/asm/bitrev.h | 32 +
> arch/kvx/include/asm/break_hook.h | 69 +
> arch/kvx/include/asm/bug.h | 67 +
> arch/kvx/include/asm/cache.h | 46 +
> arch/kvx/include/asm/cacheflush.h | 181 +
> arch/kvx/include/asm/clocksource.h | 17 +
> arch/kvx/include/asm/cmpxchg.h | 185 +
> arch/kvx/include/asm/current.h | 22 +
> arch/kvx/include/asm/dame.h | 31 +
> arch/kvx/include/asm/debug.h | 35 +
> arch/kvx/include/asm/elf.h | 155 +
> arch/kvx/include/asm/fixmap.h | 47 +
> arch/kvx/include/asm/ftrace.h | 41 +
> arch/kvx/include/asm/futex.h | 141 +
> arch/kvx/include/asm/hardirq.h | 14 +
> arch/kvx/include/asm/hugetlb.h | 36 +
> arch/kvx/include/asm/hw_breakpoint.h | 72 +
> arch/kvx/include/asm/hw_irq.h | 14 +
> arch/kvx/include/asm/insns.h | 16 +
> arch/kvx/include/asm/insns_defs.h | 197 +
> arch/kvx/include/asm/io.h | 34 +
> arch/kvx/include/asm/ipi.h | 16 +
> arch/kvx/include/asm/irqflags.h | 58 +
> arch/kvx/include/asm/jump_label.h | 59 +
> arch/kvx/include/asm/l2_cache.h | 75 +
> arch/kvx/include/asm/l2_cache_defs.h | 64 +
> arch/kvx/include/asm/linkage.h | 13 +
> arch/kvx/include/asm/mem_map.h | 44 +
> arch/kvx/include/asm/mmu.h | 296 +
> arch/kvx/include/asm/mmu_context.h | 156 +
> arch/kvx/include/asm/mmu_stats.h | 38 +
> arch/kvx/include/asm/page.h | 187 +
> arch/kvx/include/asm/page_size.h | 29 +
> arch/kvx/include/asm/pci.h | 36 +
> arch/kvx/include/asm/perf_event.h | 90 +
> arch/kvx/include/asm/pgalloc.h | 101 +
> arch/kvx/include/asm/pgtable-bits.h | 102 +
> arch/kvx/include/asm/pgtable.h | 451 ++
> arch/kvx/include/asm/privilege.h | 211 +
> arch/kvx/include/asm/processor.h | 176 +
> arch/kvx/include/asm/ptrace.h | 217 +
> arch/kvx/include/asm/pwr_ctrl.h | 45 +
> arch/kvx/include/asm/rm_fw.h | 16 +
> arch/kvx/include/asm/sections.h | 18 +
> arch/kvx/include/asm/setup.h | 29 +
> arch/kvx/include/asm/sfr.h | 107 +
> arch/kvx/include/asm/sfr_defs.h | 5028 +++++++++++++++++
> arch/kvx/include/asm/smp.h | 42 +
> arch/kvx/include/asm/sparsemem.h | 15 +
> arch/kvx/include/asm/spinlock.h | 16 +
> arch/kvx/include/asm/spinlock_types.h | 17 +
> arch/kvx/include/asm/stackprotector.h | 47 +
> arch/kvx/include/asm/stacktrace.h | 44 +
> arch/kvx/include/asm/string.h | 20 +
> arch/kvx/include/asm/swab.h | 48 +
> arch/kvx/include/asm/switch_to.h | 21 +
> arch/kvx/include/asm/symbols.h | 16 +
> arch/kvx/include/asm/sys_arch.h | 51 +
> arch/kvx/include/asm/syscall.h | 73 +
> arch/kvx/include/asm/syscalls.h | 21 +
> arch/kvx/include/asm/thread_info.h | 78 +
> arch/kvx/include/asm/timex.h | 20 +
> arch/kvx/include/asm/tlb.h | 24 +
> arch/kvx/include/asm/tlb_defs.h | 131 +
> arch/kvx/include/asm/tlbflush.h | 58 +
> arch/kvx/include/asm/traps.h | 76 +
> arch/kvx/include/asm/types.h | 12 +
> arch/kvx/include/asm/uaccess.h | 324 ++
> arch/kvx/include/asm/unistd.h | 11 +
> arch/kvx/include/asm/vermagic.h | 12 +
> arch/kvx/include/asm/vmalloc.h | 10 +
> arch/kvx/include/uapi/asm/Kbuild | 1 +
> arch/kvx/include/uapi/asm/bitsperlong.h | 14 +
> arch/kvx/include/uapi/asm/byteorder.h | 12 +
> arch/kvx/include/uapi/asm/cachectl.h | 25 +
> arch/kvx/include/uapi/asm/ptrace.h | 114 +
> arch/kvx/include/uapi/asm/sigcontext.h | 16 +
> arch/kvx/include/uapi/asm/unistd.h | 16 +
> arch/kvx/kernel/Makefile | 27 +
> arch/kvx/kernel/asm-offsets.c | 157 +
> arch/kvx/kernel/break_hook.c | 77 +
> arch/kvx/kernel/common.c | 11 +
> arch/kvx/kernel/cpuinfo.c | 96 +
> arch/kvx/kernel/dame_handler.c | 113 +
> arch/kvx/kernel/debug.c | 64 +
> arch/kvx/kernel/entry.S | 1759 ++++++
> arch/kvx/kernel/ftrace.c | 339 ++
> arch/kvx/kernel/head.S | 612 ++
> arch/kvx/kernel/hw_breakpoint.c | 556 ++
> arch/kvx/kernel/insns.c | 146 +
> arch/kvx/kernel/io.c | 96 +
> arch/kvx/kernel/irq.c | 78 +
> arch/kvx/kernel/jump_label.c | 34 +
> arch/kvx/kernel/kvx_ksyms.c | 29 +
> arch/kvx/kernel/l2_cache.c | 448 ++
> arch/kvx/kernel/mcount.S | 340 ++
> arch/kvx/kernel/module.c | 148 +
> arch/kvx/kernel/perf_event.c | 609 ++
> arch/kvx/kernel/process.c | 212 +
> arch/kvx/kernel/prom.c | 24 +
> arch/kvx/kernel/ptrace.c | 461 ++
> arch/kvx/kernel/reset.c | 37 +
> arch/kvx/kernel/return_address.c | 55 +
> arch/kvx/kernel/setup.c | 178 +
> arch/kvx/kernel/signal.c | 266 +
> arch/kvx/kernel/smp.c | 110 +
> arch/kvx/kernel/smpboot.c | 127 +
> arch/kvx/kernel/stacktrace.c | 173 +
> arch/kvx/kernel/sys_kvx.c | 58 +
> arch/kvx/kernel/syscall_table.c | 19 +
> arch/kvx/kernel/time.c | 242 +
> arch/kvx/kernel/traps.c | 243 +
> arch/kvx/kernel/vdso.c | 87 +
> arch/kvx/kernel/vmlinux.lds.S | 173 +
> arch/kvx/lib/Makefile | 6 +
> arch/kvx/lib/clear_page.S | 40 +
> arch/kvx/lib/copy_page.S | 90 +
> arch/kvx/lib/delay.c | 39 +
> arch/kvx/lib/memcpy.c | 70 +
> arch/kvx/lib/memset.S | 351 ++
> arch/kvx/lib/strlen.S | 122 +
> arch/kvx/lib/usercopy.S | 90 +
> arch/kvx/mm/Makefile | 10 +
> arch/kvx/mm/cacheflush.c | 154 +
> arch/kvx/mm/dma-mapping.c | 95 +
> arch/kvx/mm/extable.c | 24 +
> arch/kvx/mm/fault.c | 264 +
> arch/kvx/mm/hugetlbpage.c | 317 ++
> arch/kvx/mm/init.c | 527 ++
> arch/kvx/mm/kernel_rwx.c | 228 +
> arch/kvx/mm/mmap.c | 31 +
> arch/kvx/mm/mmu.c | 204 +
> arch/kvx/mm/mmu_stats.c | 94 +
> arch/kvx/mm/tlb.c | 433 ++
> arch/kvx/platform/Makefile | 7 +
> arch/kvx/platform/ipi.c | 110 +
> arch/kvx/platform/pwr_ctrl.c | 93 +
> drivers/irqchip/Kconfig | 27 +
> drivers/irqchip/Makefile | 4 +
> drivers/irqchip/irq-kvx-apic-gic.c | 349 ++
> drivers/irqchip/irq-kvx-apic-mailbox.c | 465 ++
> drivers/irqchip/irq-kvx-core-intc.c | 82 +
> drivers/irqchip/irq-kvx-itgen.c | 224 +
> drivers/power/reset/kvx-scall-poweroff.c | 53 +
> include/linux/cpuhotplug.h | 2 +
> include/linux/irqchip/irq-kvx-apic-gic.h | 21 +
> include/linux/irqchip/irq-kvx-apic-mailbox.h | 29 +
> include/linux/irqchip/irq-kvx-itgen.h | 24 +
> include/uapi/linux/audit.h | 1 +
> include/uapi/linux/elf-em.h | 1 +
> include/uapi/linux/elf.h | 1 +
> scripts/gdb/arch/Makefile | 11 +
> scripts/gdb/arch/__init__.py | 1 +
> scripts/gdb/arch/kvx/Makefile | 25 +
> scripts/gdb/arch/kvx/__init__.py | 1 +
> scripts/gdb/arch/kvx/constants.py.in | 74 +
> scripts/gdb/arch/kvx/mmu.py | 199 +
> scripts/gdb/arch/kvx/page_table_walk.py | 207 +
> tools/include/uapi/asm/bitsperlong.h | 2 +
> 175 files changed, 25814 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/interrupt-controller/kalray,kvx-core-intc.txt
> create mode 100644 Documentation/devicetree/bindings/perf/kalray-pm.txt
> create mode 100644 Documentation/kvx/kvx-exceptions.txt
> create mode 100644 Documentation/kvx/kvx-iommu.txt
> create mode 100644 Documentation/kvx/kvx-mmu.txt
> create mode 100644 Documentation/kvx/kvx-smp.txt
> create mode 100644 Documentation/kvx/kvx.txt
> create mode 100644 arch/kvx/Kconfig
> create mode 100644 arch/kvx/Kconfig.debug
> create mode 100644 arch/kvx/Makefile
> create mode 100644 arch/kvx/configs/default_defconfig
> create mode 100644 arch/kvx/include/asm/Kbuild
> create mode 100644 arch/kvx/include/asm/asm-prototypes.h
> create mode 100644 arch/kvx/include/asm/atomic.h
> create mode 100644 arch/kvx/include/asm/barrier.h
> create mode 100644 arch/kvx/include/asm/bitops.h
> create mode 100644 arch/kvx/include/asm/bitrev.h
> create mode 100644 arch/kvx/include/asm/break_hook.h
> create mode 100644 arch/kvx/include/asm/bug.h
> create mode 100644 arch/kvx/include/asm/cache.h
> create mode 100644 arch/kvx/include/asm/cacheflush.h
> create mode 100644 arch/kvx/include/asm/clocksource.h
> create mode 100644 arch/kvx/include/asm/cmpxchg.h
> create mode 100644 arch/kvx/include/asm/current.h
> create mode 100644 arch/kvx/include/asm/dame.h
> create mode 100644 arch/kvx/include/asm/debug.h
> create mode 100644 arch/kvx/include/asm/elf.h
> create mode 100644 arch/kvx/include/asm/fixmap.h
> create mode 100644 arch/kvx/include/asm/ftrace.h
> create mode 100644 arch/kvx/include/asm/futex.h
> create mode 100644 arch/kvx/include/asm/hardirq.h
> create mode 100644 arch/kvx/include/asm/hugetlb.h
> create mode 100644 arch/kvx/include/asm/hw_breakpoint.h
> create mode 100644 arch/kvx/include/asm/hw_irq.h
> create mode 100644 arch/kvx/include/asm/insns.h
> create mode 100644 arch/kvx/include/asm/insns_defs.h
> create mode 100644 arch/kvx/include/asm/io.h
> create mode 100644 arch/kvx/include/asm/ipi.h
> create mode 100644 arch/kvx/include/asm/irqflags.h
> create mode 100644 arch/kvx/include/asm/jump_label.h
> create mode 100644 arch/kvx/include/asm/l2_cache.h
> create mode 100644 arch/kvx/include/asm/l2_cache_defs.h
> create mode 100644 arch/kvx/include/asm/linkage.h
> create mode 100644 arch/kvx/include/asm/mem_map.h
> create mode 100644 arch/kvx/include/asm/mmu.h
> create mode 100644 arch/kvx/include/asm/mmu_context.h
> create mode 100644 arch/kvx/include/asm/mmu_stats.h
> create mode 100644 arch/kvx/include/asm/page.h
> create mode 100644 arch/kvx/include/asm/page_size.h
> create mode 100644 arch/kvx/include/asm/pci.h
> create mode 100644 arch/kvx/include/asm/perf_event.h
> create mode 100644 arch/kvx/include/asm/pgalloc.h
> create mode 100644 arch/kvx/include/asm/pgtable-bits.h
> create mode 100644 arch/kvx/include/asm/pgtable.h
> create mode 100644 arch/kvx/include/asm/privilege.h
> create mode 100644 arch/kvx/include/asm/processor.h
> create mode 100644 arch/kvx/include/asm/ptrace.h
> create mode 100644 arch/kvx/include/asm/pwr_ctrl.h
> create mode 100644 arch/kvx/include/asm/rm_fw.h
> create mode 100644 arch/kvx/include/asm/sections.h
> create mode 100644 arch/kvx/include/asm/setup.h
> create mode 100644 arch/kvx/include/asm/sfr.h
> create mode 100644 arch/kvx/include/asm/sfr_defs.h
> create mode 100644 arch/kvx/include/asm/smp.h
> create mode 100644 arch/kvx/include/asm/sparsemem.h
> create mode 100644 arch/kvx/include/asm/spinlock.h
> create mode 100644 arch/kvx/include/asm/spinlock_types.h
> create mode 100644 arch/kvx/include/asm/stackprotector.h
> create mode 100644 arch/kvx/include/asm/stacktrace.h
> create mode 100644 arch/kvx/include/asm/string.h
> create mode 100644 arch/kvx/include/asm/swab.h
> create mode 100644 arch/kvx/include/asm/switch_to.h
> create mode 100644 arch/kvx/include/asm/symbols.h
> create mode 100644 arch/kvx/include/asm/sys_arch.h
> create mode 100644 arch/kvx/include/asm/syscall.h
> create mode 100644 arch/kvx/include/asm/syscalls.h
> create mode 100644 arch/kvx/include/asm/thread_info.h
> create mode 100644 arch/kvx/include/asm/timex.h
> create mode 100644 arch/kvx/include/asm/tlb.h
> create mode 100644 arch/kvx/include/asm/tlb_defs.h
> create mode 100644 arch/kvx/include/asm/tlbflush.h
> create mode 100644 arch/kvx/include/asm/traps.h
> create mode 100644 arch/kvx/include/asm/types.h
> create mode 100644 arch/kvx/include/asm/uaccess.h
> create mode 100644 arch/kvx/include/asm/unistd.h
> create mode 100644 arch/kvx/include/asm/vermagic.h
> create mode 100644 arch/kvx/include/asm/vmalloc.h
> create mode 100644 arch/kvx/include/uapi/asm/Kbuild
> create mode 100644 arch/kvx/include/uapi/asm/bitsperlong.h
> create mode 100644 arch/kvx/include/uapi/asm/byteorder.h
> create mode 100644 arch/kvx/include/uapi/asm/cachectl.h
> create mode 100644 arch/kvx/include/uapi/asm/ptrace.h
> create mode 100644 arch/kvx/include/uapi/asm/sigcontext.h
> create mode 100644 arch/kvx/include/uapi/asm/unistd.h
> create mode 100644 arch/kvx/kernel/Makefile
> create mode 100644 arch/kvx/kernel/asm-offsets.c
> create mode 100644 arch/kvx/kernel/break_hook.c
> create mode 100644 arch/kvx/kernel/common.c
> create mode 100644 arch/kvx/kernel/cpuinfo.c
> create mode 100644 arch/kvx/kernel/dame_handler.c
> create mode 100644 arch/kvx/kernel/debug.c
> create mode 100644 arch/kvx/kernel/entry.S
> create mode 100644 arch/kvx/kernel/ftrace.c
> create mode 100644 arch/kvx/kernel/head.S
> create mode 100644 arch/kvx/kernel/hw_breakpoint.c
> create mode 100644 arch/kvx/kernel/insns.c
> create mode 100644 arch/kvx/kernel/io.c
> create mode 100644 arch/kvx/kernel/irq.c
> create mode 100644 arch/kvx/kernel/jump_label.c
> create mode 100644 arch/kvx/kernel/kvx_ksyms.c
> create mode 100644 arch/kvx/kernel/l2_cache.c
> create mode 100644 arch/kvx/kernel/mcount.S
> create mode 100644 arch/kvx/kernel/module.c
> create mode 100644 arch/kvx/kernel/perf_event.c
> create mode 100644 arch/kvx/kernel/process.c
> create mode 100644 arch/kvx/kernel/prom.c
> create mode 100644 arch/kvx/kernel/ptrace.c
> create mode 100644 arch/kvx/kernel/reset.c
> create mode 100644 arch/kvx/kernel/return_address.c
> create mode 100644 arch/kvx/kernel/setup.c
> create mode 100644 arch/kvx/kernel/signal.c
> create mode 100644 arch/kvx/kernel/smp.c
> create mode 100644 arch/kvx/kernel/smpboot.c
> create mode 100644 arch/kvx/kernel/stacktrace.c
> create mode 100644 arch/kvx/kernel/sys_kvx.c
> create mode 100644 arch/kvx/kernel/syscall_table.c
> create mode 100644 arch/kvx/kernel/time.c
> create mode 100644 arch/kvx/kernel/traps.c
> create mode 100644 arch/kvx/kernel/vdso.c
> create mode 100644 arch/kvx/kernel/vmlinux.lds.S
> create mode 100644 arch/kvx/lib/Makefile
> create mode 100644 arch/kvx/lib/clear_page.S
> create mode 100644 arch/kvx/lib/copy_page.S
> create mode 100644 arch/kvx/lib/delay.c
> create mode 100644 arch/kvx/lib/memcpy.c
> create mode 100644 arch/kvx/lib/memset.S
> create mode 100644 arch/kvx/lib/strlen.S
> create mode 100644 arch/kvx/lib/usercopy.S
> create mode 100644 arch/kvx/mm/Makefile
> create mode 100644 arch/kvx/mm/cacheflush.c
> create mode 100644 arch/kvx/mm/dma-mapping.c
> create mode 100644 arch/kvx/mm/extable.c
> create mode 100644 arch/kvx/mm/fault.c
> create mode 100644 arch/kvx/mm/hugetlbpage.c
> create mode 100644 arch/kvx/mm/init.c
> create mode 100644 arch/kvx/mm/kernel_rwx.c
> create mode 100644 arch/kvx/mm/mmap.c
> create mode 100644 arch/kvx/mm/mmu.c
> create mode 100644 arch/kvx/mm/mmu_stats.c
> create mode 100644 arch/kvx/mm/tlb.c
> create mode 100644 arch/kvx/platform/Makefile
> create mode 100644 arch/kvx/platform/ipi.c
> create mode 100644 arch/kvx/platform/pwr_ctrl.c
> create mode 100644 drivers/irqchip/irq-kvx-apic-gic.c
> create mode 100644 drivers/irqchip/irq-kvx-apic-mailbox.c
> create mode 100644 drivers/irqchip/irq-kvx-core-intc.c
> create mode 100644 drivers/irqchip/irq-kvx-itgen.c
> create mode 100644 drivers/power/reset/kvx-scall-poweroff.c
> create mode 100644 include/linux/irqchip/irq-kvx-apic-gic.h
> create mode 100644 include/linux/irqchip/irq-kvx-apic-mailbox.h
> create mode 100644 include/linux/irqchip/irq-kvx-itgen.h
> create mode 100644 scripts/gdb/arch/Makefile
> create mode 100644 scripts/gdb/arch/__init__.py
> create mode 100644 scripts/gdb/arch/kvx/Makefile
> create mode 100644 scripts/gdb/arch/kvx/__init__.py
> create mode 100644 scripts/gdb/arch/kvx/constants.py.in
> create mode 100644 scripts/gdb/arch/kvx/mmu.py
> create mode 100644 scripts/gdb/arch/kvx/page_table_walk.py
>
> --
> 2.37.2
>
>
>
>
>


--
Thanks,
JeffXie

2023-01-09 14:16:28

by Yann Sionneau

[permalink] [raw]
Subject: Re: [RFC PATCH 00/25] Upstream kvx Linux port

Hi Jeff,

On 1/7/23 07:25, Jeff Xie wrote:
> Hi,
>
> On Wed, Jan 4, 2023 at 1:01 AM Yann Sionneau <[email protected]> wrote:
>> [snip]
>>
>> A kvx toolchain can be built using:
>> # install dependencies: texinfo bison flex libgmp-dev libmpc-dev libmpfr-dev
>> $ git clone https://github.com/kalray/build-scripts
>> $ cd build-scripts
>> $ source last.refs
>> $ ./build-kvx-xgcc.sh output
> I would like to build the kvx-xgcc to compile and test the linux
> kernel, but it reported a compile error.
> I wonder what version of gcc you are using.
>
> My build environment:
> VERSION="20.04.2 LTS (Focal Fossa)"
> gcc version 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04)
>
>
> Compile error:
> $ ./build-kvx-xgcc.sh output
>
> ../../binutils/libiberty/fibheap.c: In function ‘fibheap_replace_key_data’:
> ../../binutils/libiberty/fibheap.c:38:24: error: ‘LONG_MIN’ undeclared
> (first use in this function)
> 38 | #define FIBHEAPKEY_MIN LONG_MIN
> | ^~~~~~~~
> [snip]

What SHA1 of https://github.com/kalray/build-scripts are you using?

We are building our toolchain on Ubuntu 18.04 / 20.04 and 22.04 without
issues, I don't understand why it does not work for you, although indeed
the error log you are having pops out on my search engine and seems to
be some well known issue.

If the build-script does not work for you, you can still use the
pre-built toolchains generated by the GitHub automated actions:
https://github.com/kalray/build-scripts/releases/tag/v4.11.1 ("latest"
means 22.04)

I hope it will work for you.

Regards,

--

Yann





2023-01-09 15:42:12

by Jeff Xie

[permalink] [raw]
Subject: Re: [RFC PATCH 00/25] Upstream kvx Linux port

On Mon, Jan 9, 2023 at 9:21 PM Yann Sionneau <[email protected]> wrote:
>
> Hi Jeff,
>
> On 1/7/23 07:25, Jeff Xie wrote:
> > Hi,
> >
> > On Wed, Jan 4, 2023 at 1:01 AM Yann Sionneau <[email protected]> wrote:
> >> [snip]
> >>
> >> A kvx toolchain can be built using:
> >> # install dependencies: texinfo bison flex libgmp-dev libmpc-dev libmpfr-dev
> >> $ git clone https://github.com/kalray/build-scripts
> >> $ cd build-scripts
> >> $ source last.refs
> >> $ ./build-kvx-xgcc.sh output
> > I would like to build the kvx-xgcc to compile and test the linux
> > kernel, but it reported a compile error.
> > I wonder what version of gcc you are using.
> >
> > My build environment:
> > VERSION="20.04.2 LTS (Focal Fossa)"
> > gcc version 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04)
> >
> >
> > Compile error:
> > $ ./build-kvx-xgcc.sh output
> >
> > ../../binutils/libiberty/fibheap.c: In function ‘fibheap_replace_key_data’:
> > ../../binutils/libiberty/fibheap.c:38:24: error: ‘LONG_MIN’ undeclared
> > (first use in this function)
> > 38 | #define FIBHEAPKEY_MIN LONG_MIN
> > | ^~~~~~~~
> > [snip]
>
> What SHA1 of https://github.com/kalray/build-scripts are you using?

I have executed the "source last.refs"

> We are building our toolchain on Ubuntu 18.04 / 20.04 and 22.04 without
> issues, I don't understand why it does not work for you, although indeed
> the error log you are having pops out on my search engine and seems to
> be some well known issue.

Yes, there are many answers on the web, but none of them solve this problem.

> If the build-script does not work for you, you can still use the
> pre-built toolchains generated by the GitHub automated actions:
> https://github.com/kalray/build-scripts/releases/tag/v4.11.1 ("latest"
> means 22.04)

Thanks, this is the final solution ;-)

>
> I hope it will work for you.
>
> Regards,
>
> --
>
> Yann
>
>
>
>
>


--
Thanks,
JeffXie

2023-01-09 15:48:26

by Yann Sionneau

[permalink] [raw]
Subject: Re: [RFC PATCH 00/25] Upstream kvx Linux port

Hi Jeff,

On 1/9/23 16:11, Jeff Xie wrote:
> On Mon, Jan 9, 2023 at 9:21 PM Yann Sionneau <[email protected]> wrote:
>> Hi Jeff,
>>
>> On 1/7/23 07:25, Jeff Xie wrote:
>>> Hi,
>>>
>>> On Wed, Jan 4, 2023 at 1:01 AM Yann Sionneau <[email protected]> wrote:
>>>> [snip]
>>>>
>>>> A kvx toolchain can be built using:
>>>> # install dependencies: texinfo bison flex libgmp-dev libmpc-dev libmpfr-dev
>>>> $ git clone https://github.com/kalray/build-scripts
>>>> $ cd build-scripts
>>>> $ source last.refs
>>>> $ ./build-kvx-xgcc.sh output
>>> I would like to build the kvx-xgcc to compile and test the linux
>>> kernel, but it reported a compile error.
>>> I wonder what version of gcc you are using.
>>>
>>> My build environment:
>>> VERSION="20.04.2 LTS (Focal Fossa)"
>>> gcc version 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04)
>>>
>>>
>>> Compile error:
>>> $ ./build-kvx-xgcc.sh output
>>>
>>> ../../binutils/libiberty/fibheap.c: In function ‘fibheap_replace_key_data’:
>>> ../../binutils/libiberty/fibheap.c:38:24: error: ‘LONG_MIN’ undeclared
>>> (first use in this function)
>>> 38 | #define FIBHEAPKEY_MIN LONG_MIN
>>> | ^~~~~~~~
>>> [snip]
>> What SHA1 of https://github.com/kalray/build-scripts are you using?
> I have executed the "source last.refs"

I was referring to the SHA1 of the repo itself (build-scripts).

`last.refs` is a symbolic link which can point to several releases,
depending on "when" you did the clone.

I am asking this because we recently published new toolchains.

I want to make sure which one you are trying to build.

>> We are building our toolchain on Ubuntu 18.04 / 20.04 and 22.04 without
>> issues, I don't understand why it does not work for you, although indeed
>> the error log you are having pops out on my search engine and seems to
>> be some well known issue.
> Yes, there are many answers on the web, but none of them solve this problem.
>
>> If the build-script does not work for you, you can still use the
>> pre-built toolchains generated by the GitHub automated actions:
>> https://github.com/kalray/build-scripts/releases/tag/v4.11.1 ("latest"
>> means 22.04)
> Thanks, this is the final solution ;-)
Good to see it helped :)

Regards,

--

Yann





2023-01-09 16:11:37

by Jeff Xie

[permalink] [raw]
Subject: Re: [RFC PATCH 00/25] Upstream kvx Linux port

On Mon, Jan 9, 2023 at 11:30 PM Yann Sionneau <[email protected]> wrote:
>
> Hi Jeff,
>
> On 1/9/23 16:11, Jeff Xie wrote:
> > On Mon, Jan 9, 2023 at 9:21 PM Yann Sionneau <[email protected]> wrote:
> >> Hi Jeff,
> >>
> >> On 1/7/23 07:25, Jeff Xie wrote:
> >>> Hi,
> >>>
> >>> On Wed, Jan 4, 2023 at 1:01 AM Yann Sionneau <[email protected]> wrote:
> >>>> [snip]
> >>>>
> >>>> A kvx toolchain can be built using:
> >>>> # install dependencies: texinfo bison flex libgmp-dev libmpc-dev libmpfr-dev
> >>>> $ git clone https://github.com/kalray/build-scripts
> >>>> $ cd build-scripts
> >>>> $ source last.refs
> >>>> $ ./build-kvx-xgcc.sh output
> >>> I would like to build the kvx-xgcc to compile and test the linux
> >>> kernel, but it reported a compile error.
> >>> I wonder what version of gcc you are using.
> >>>
> >>> My build environment:
> >>> VERSION="20.04.2 LTS (Focal Fossa)"
> >>> gcc version 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04)
> >>>
> >>>
> >>> Compile error:
> >>> $ ./build-kvx-xgcc.sh output
> >>>
> >>> ../../binutils/libiberty/fibheap.c: In function ‘fibheap_replace_key_data’:
> >>> ../../binutils/libiberty/fibheap.c:38:24: error: ‘LONG_MIN’ undeclared
> >>> (first use in this function)
> >>> 38 | #define FIBHEAPKEY_MIN LONG_MIN
> >>> | ^~~~~~~~
> >>> [snip]
> >> What SHA1 of https://github.com/kalray/build-scripts are you using?
> > I have executed the "source last.refs"
>
> I was referring to the SHA1 of the repo itself (build-scripts).
>
> `last.refs` is a symbolic link which can point to several releases,
> depending on "when" you did the clone.
>
> I am asking this because we recently published new toolchains.
>
> I want to make sure which one you are trying to build.

Unfortunately I deleted this repo a few minutes before you asked me ;-(
But I remember that I cloned this repo two days ago.
it should be: last.refs -> refs/4.11.0.refs


> >> We are building our toolchain on Ubuntu 18.04 / 20.04 and 22.04 without
> >> issues, I don't understand why it does not work for you, although indeed
> >> the error log you are having pops out on my search engine and seems to
> >> be some well known issue.
> > Yes, there are many answers on the web, but none of them solve this problem.
> >
> >> If the build-script does not work for you, you can still use the
> >> pre-built toolchains generated by the GitHub automated actions:
> >> https://github.com/kalray/build-scripts/releases/tag/v4.11.1 ("latest"
> >> means 22.04)
> > Thanks, this is the final solution ;-)
> Good to see it helped :)
>
> Regards,
>
> --
>
> Yann
>
>
>
>
>


--
Thanks,
JeffXie

2023-01-09 21:12:56

by Thomas Gleixner

[permalink] [raw]
Subject: Re: [RFC PATCH 12/25] kvx: Add system call support

On Tue, Jan 03 2023 at 17:43, Yann Sionneau wrote:
> +/***********************************************************************
> +* Common exception return path
> +***********************************************************************/
> +/**
> + * Restore registers after exception
> + * When entering this macro, $sp must be located right before regs
> + * storage.
> + */
> +EXCEPTION_ENTRY(return_from_exception)
> +#ifdef CONFIG_DEBUG_EXCEPTION_STACK
> + ld $r1 = 0[$sp]
> + ;;
> + sbfd $r1 = $r1, $sp
> + ;;
> + cb.deqz $r1, _check_ok
> + ;;
> + make $r2 = panic
> + make $r0 = stack_error_panic_str_label
> + ;;
> + icall $r2
> + ;;
> +_check_ok:
> + addd $sp = $sp, STACK_REG_SIZE
> + ;;
> +#endif
> + get $r11 = $sr
> + /* Load sps value from saved registers */
> + ld $r6 = PT_SPS[$sp]
> + ;;
> + /* Disable interrupt to check task flags atomically */
> + disable_interrupt $r60
> + ;;
> + /* Check PL bit of sps, if set, then it means we are returning
> + * to a lower privilege level (ie to user), if so, we need to
> + * check work pending. If coming from kernel, directly go to
> + * register restoration */
> + cb.even $r6? _restore_regs
> + ld $r1 = TASK_TI_FLAGS[$r11]
> + ;;
> + /* Do we have work pending ? */
> + andd $r5 = $r1, _TIF_WORK_MASK

Please use the generic entry code to handle pending work, tracing etc.

All over the place....

Thanks,

tglx

2023-01-09 21:32:44

by Thomas Gleixner

[permalink] [raw]
Subject: Re: [RFC PATCH 08/25] kvx: Add exception/interrupt handling

On Tue, Jan 03 2023 at 17:43, Yann Sionneau wrote:
> --- /dev/null
> +++ b/arch/kvx/kernel/irq.c
> @@ -0,0 +1,78 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2017-2023 Kalray Inc.
> + * Author(s): Clement Leger
> + */
> +
> +#include <linux/irqdomain.h>
> +#include <linux/irqflags.h>
> +#include <linux/hardirq.h>
> +#include <linux/irqchip.h>
> +#include <linux/bitops.h>
> +#include <linux/init.h>
> +
> +#include <asm/dame.h>
> +
> +#define IT_MASK(__it) (KVX_SFR_ILL_ ## __it ## _MASK)
> +#define IT_LEVEL(__it, __level) \
> + (__level##ULL << KVX_SFR_ILL_ ## __it ## _SHIFT)
> +
> +void do_IRQ(unsigned long hwirq_mask, struct pt_regs *regs)
> +{
> + struct pt_regs *old_regs = set_irq_regs(regs);
> + int irq;
> + unsigned int hwirq;
> +
> + trace_hardirqs_off();
> +
> + irq_enter();

Please use the generic entry code for interrupts to handle tracing,
irq_enter() etc. correctly.

> +/**
> + * trap_handler - trap handler called by _trap_handler routine in trap_handler.S
> + * This handler will redirect to other trap handlers if present
> + * If not then it will do a generic action
> + * @es: Exception Syndrome register value
> + * @ea: Exception Address register
> + * @regs: pointer to registers saved when trapping
> + */
> +void trap_handler(uint64_t es, uint64_t ea, struct pt_regs *regs)
> +{
> + enum ctx_state prev_state = exception_enter();

Please do not implement exception_enter/exit(). Use the generic entry
handling code so your code is correct and extensible.

Thanks,

tglx

2023-01-16 07:40:28

by Jeff Xie

[permalink] [raw]
Subject: Re: [RFC PATCH 00/25] Upstream kvx Linux port

On Mon, Jan 9, 2023 at 11:53 PM Jeff Xie <[email protected]> wrote:
>
> On Mon, Jan 9, 2023 at 11:30 PM Yann Sionneau <[email protected]> wrote:
> >
> > Hi Jeff,
> >
> > On 1/9/23 16:11, Jeff Xie wrote:
> > > On Mon, Jan 9, 2023 at 9:21 PM Yann Sionneau <[email protected]> wrote:
> > >> Hi Jeff,
> > >>
> > >> On 1/7/23 07:25, Jeff Xie wrote:
> > >>> Hi,
> > >>>
> > >>> On Wed, Jan 4, 2023 at 1:01 AM Yann Sionneau <[email protected]> wrote:
> > >>>> [snip]
> > >>>>
> > >>>> A kvx toolchain can be built using:
> > >>>> # install dependencies: texinfo bison flex libgmp-dev libmpc-dev libmpfr-dev
> > >>>> $ git clone https://github.com/kalray/build-scripts
> > >>>> $ cd build-scripts
> > >>>> $ source last.refs
> > >>>> $ ./build-kvx-xgcc.sh output
> > >>> I would like to build the kvx-xgcc to compile and test the linux
> > >>> kernel, but it reported a compile error.
> > >>> I wonder what version of gcc you are using.
> > >>>
> > >>> My build environment:
> > >>> VERSION="20.04.2 LTS (Focal Fossa)"
> > >>> gcc version 9.3.0 (Ubuntu 9.3.0-17ubuntu1~20.04)
> > >>>
> > >>>
> > >>> Compile error:
> > >>> $ ./build-kvx-xgcc.sh output
> > >>>
> > >>> ../../binutils/libiberty/fibheap.c: In function ‘fibheap_replace_key_data’:
> > >>> ../../binutils/libiberty/fibheap.c:38:24: error: ‘LONG_MIN’ undeclared
> > >>> (first use in this function)
> > >>> 38 | #define FIBHEAPKEY_MIN LONG_MIN
> > >>> | ^~~~~~~~
> > >>> [snip]
> > >> What SHA1 of https://github.com/kalray/build-scripts are you using?
> > > I have executed the "source last.refs"
> >
> > I was referring to the SHA1 of the repo itself (build-scripts).
> >
> > `last.refs` is a symbolic link which can point to several releases,
> > depending on "when" you did the clone.
> >
> > I am asking this because we recently published new toolchains.
> >
> > I want to make sure which one you are trying to build.
>
> Unfortunately I deleted this repo a few minutes before you asked me ;-(
> But I remember that I cloned this repo two days ago.
> it should be: last.refs -> refs/4.11.0.refs

It should be my own environmental problem.
I reinstalled the system once and it has been able to compile normally ;-)

In the past few days, I have reviewed almost all the codes,
which is very meaningful for me to learn, thank you team.


>
> > >> We are building our toolchain on Ubuntu 18.04 / 20.04 and 22.04 without
> > >> issues, I don't understand why it does not work for you, although indeed
> > >> the error log you are having pops out on my search engine and seems to
> > >> be some well known issue.
> > > Yes, there are many answers on the web, but none of them solve this problem.
> > >
> > >> If the build-script does not work for you, you can still use the
> > >> pre-built toolchains generated by the GitHub automated actions:
> > >> https://github.com/kalray/build-scripts/releases/tag/v4.11.1 ("latest"
> > >> means 22.04)
> > > Thanks, this is the final solution ;-)
> > Good to see it helped :)
> >
> > Regards,
> >
> > --
> >
> > Yann
> >
> >
> >
> >
> >
>
>
> --
> Thanks,
> JeffXie



--
Thanks,
JeffXie

2023-01-18 15:25:32

by Jeff Xie

[permalink] [raw]
Subject: Re: [RFC PATCH 01/25] Documentation: kvx: Add basic documentation

On Wed, Jan 4, 2023 at 1:04 AM Yann Sionneau <[email protected]> wrote:
>
> Add some documentation for kvx arch and its Linux port.
>
> CC: Jonathan Corbet <[email protected]>
> CC: [email protected]
> CC: [email protected]
> Co-developed-by: Clement Leger <[email protected]>
> Signed-off-by: Clement Leger <[email protected]>
> Co-developed-by: Guillaume Thouvenin <[email protected]>
> Signed-off-by: Guillaume Thouvenin <[email protected]>
> Signed-off-by: Yann Sionneau <[email protected]>
> ---
> Documentation/kvx/kvx-exceptions.txt | 246 ++++++++++++++++++++++++
> Documentation/kvx/kvx-iommu.txt | 183 ++++++++++++++++++
> Documentation/kvx/kvx-mmu.txt | 272 +++++++++++++++++++++++++++
> Documentation/kvx/kvx-smp.txt | 36 ++++
> Documentation/kvx/kvx.txt | 268 ++++++++++++++++++++++++++
> 5 files changed, 1005 insertions(+)
> create mode 100644 Documentation/kvx/kvx-exceptions.txt
> create mode 100644 Documentation/kvx/kvx-iommu.txt
> create mode 100644 Documentation/kvx/kvx-mmu.txt
> create mode 100644 Documentation/kvx/kvx-smp.txt
> create mode 100644 Documentation/kvx/kvx.txt

[...]

> +Virtual and physical memory
> +===========================
> +
> +The mapping used and the memory management is described in
> +Documentation/kvx/kvx-mmu.txt.
> +Our Kernel is compiled using virtual addresses that starts at
> +0xffffff0000000000. But when it is started the kernel uses physical addresses.
> +Before calling the first function arch_low_level_start() we configure 2 entries
> +of the LTLB.
> +
> +The first entry will map the first 1G of virtual address space to the first
> +1G of DDR:
> + - TLB[0]: 0xffffff0000000000 -> 0x100000000 (size 512Mo)

Maybe should change it to:
- TLB[0]: 0xffffff8000000000 -> 0x100000000 (size 512Mo)

As the PAGE_OFFSET = 0xffffff8000000000

[...]



--
Thanks,
JeffXie