summaryrefslogtreecommitdiffstats
path: root/arch/parisc
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-11 08:27:49 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-11 08:27:49 +0000
commitace9429bb58fd418f0c81d4c2835699bddf6bde6 (patch)
treeb2d64bc10158fdd5497876388cd68142ca374ed3 /arch/parisc
parentInitial commit. (diff)
downloadlinux-ace9429bb58fd418f0c81d4c2835699bddf6bde6.tar.xz
linux-ace9429bb58fd418f0c81d4c2835699bddf6bde6.zip
Adding upstream version 6.6.15.upstream/6.6.15
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'arch/parisc')
-rw-r--r--arch/parisc/Kbuild5
-rw-r--r--arch/parisc/Kconfig378
-rw-r--r--arch/parisc/Kconfig.debug23
-rw-r--r--arch/parisc/Makefile207
-rw-r--r--arch/parisc/boot/.gitignore3
-rw-r--r--arch/parisc/boot/Makefile17
-rw-r--r--arch/parisc/boot/compressed/.gitignore4
-rw-r--r--arch/parisc/boot/compressed/Makefile75
-rw-r--r--arch/parisc/boot/compressed/firmware.c2
-rw-r--r--arch/parisc/boot/compressed/head.S85
-rw-r--r--arch/parisc/boot/compressed/misc.c370
-rw-r--r--arch/parisc/boot/compressed/real2.S2
-rw-r--r--arch/parisc/boot/compressed/vmlinux.lds.S106
-rw-r--r--arch/parisc/boot/compressed/vmlinux.scr10
-rw-r--r--arch/parisc/configs/generic-32bit_defconfig281
-rw-r--r--arch/parisc/configs/generic-64bit_defconfig305
-rw-r--r--arch/parisc/defpalo.conf21
-rw-r--r--arch/parisc/include/asm/Kbuild7
-rw-r--r--arch/parisc/include/asm/alternative.h66
-rw-r--r--arch/parisc/include/asm/asm-offsets.h1
-rw-r--r--arch/parisc/include/asm/asmregs.h170
-rw-r--r--arch/parisc/include/asm/assembly.h583
-rw-r--r--arch/parisc/include/asm/atomic.h238
-rw-r--r--arch/parisc/include/asm/barrier.h97
-rw-r--r--arch/parisc/include/asm/bitops.h209
-rw-r--r--arch/parisc/include/asm/bug.h101
-rw-r--r--arch/parisc/include/asm/cache.h68
-rw-r--r--arch/parisc/include/asm/cacheflush.h92
-rw-r--r--arch/parisc/include/asm/checksum.h177
-rw-r--r--arch/parisc/include/asm/cmpxchg.h124
-rw-r--r--arch/parisc/include/asm/compat.h141
-rw-r--r--arch/parisc/include/asm/compat_ucontext.h18
-rw-r--r--arch/parisc/include/asm/current.h21
-rw-r--r--arch/parisc/include/asm/delay.h23
-rw-r--r--arch/parisc/include/asm/dma-mapping.h29
-rw-r--r--arch/parisc/include/asm/dma.h181
-rw-r--r--arch/parisc/include/asm/dwarf.h20
-rw-r--r--arch/parisc/include/asm/eisa_bus.h18
-rw-r--r--arch/parisc/include/asm/eisa_eeprom.h148
-rw-r--r--arch/parisc/include/asm/elf.h368
-rw-r--r--arch/parisc/include/asm/fb.h14
-rw-r--r--arch/parisc/include/asm/fixmap.h64
-rw-r--r--arch/parisc/include/asm/floppy.h259
-rw-r--r--arch/parisc/include/asm/ftrace.h34
-rw-r--r--arch/parisc/include/asm/futex.h127
-rw-r--r--arch/parisc/include/asm/grfioctl.h62
-rw-r--r--arch/parisc/include/asm/hardirq.h35
-rw-r--r--arch/parisc/include/asm/hardware.h129
-rw-r--r--arch/parisc/include/asm/hash.h147
-rw-r--r--arch/parisc/include/asm/hugetlb.h48
-rw-r--r--arch/parisc/include/asm/io.h280
-rw-r--r--arch/parisc/include/asm/irq.h50
-rw-r--r--arch/parisc/include/asm/irqflags.h52
-rw-r--r--arch/parisc/include/asm/jump_label.h48
-rw-r--r--arch/parisc/include/asm/kbdleds.h20
-rw-r--r--arch/parisc/include/asm/kexec.h33
-rw-r--r--arch/parisc/include/asm/kfence.h44
-rw-r--r--arch/parisc/include/asm/kgdb.h70
-rw-r--r--arch/parisc/include/asm/kprobes.h60
-rw-r--r--arch/parisc/include/asm/ldcw.h61
-rw-r--r--arch/parisc/include/asm/led.h37
-rw-r--r--arch/parisc/include/asm/linkage.h40
-rw-r--r--arch/parisc/include/asm/mmu.h10
-rw-r--r--arch/parisc/include/asm/mmu_context.h100
-rw-r--r--arch/parisc/include/asm/mmzone.h7
-rw-r--r--arch/parisc/include/asm/module.h25
-rw-r--r--arch/parisc/include/asm/page.h190
-rw-r--r--arch/parisc/include/asm/parisc-device.h68
-rw-r--r--arch/parisc/include/asm/parport.h19
-rw-r--r--arch/parisc/include/asm/patch.h13
-rw-r--r--arch/parisc/include/asm/pci.h168
-rw-r--r--arch/parisc/include/asm/pdc.h113
-rw-r--r--arch/parisc/include/asm/pdc_chassis.h367
-rw-r--r--arch/parisc/include/asm/pdcpat.h394
-rw-r--r--arch/parisc/include/asm/perf.h75
-rw-r--r--arch/parisc/include/asm/perf_event.h6
-rw-r--r--arch/parisc/include/asm/pgalloc.h73
-rw-r--r--arch/parisc/include/asm/pgtable.h518
-rw-r--r--arch/parisc/include/asm/prefetch.h45
-rw-r--r--arch/parisc/include/asm/processor.h329
-rw-r--r--arch/parisc/include/asm/psw.h104
-rw-r--r--arch/parisc/include/asm/ptrace.h53
-rw-r--r--arch/parisc/include/asm/ropes.h326
-rw-r--r--arch/parisc/include/asm/rt_sigframe.h16
-rw-r--r--arch/parisc/include/asm/runway.h8
-rw-r--r--arch/parisc/include/asm/seccomp.h22
-rw-r--r--arch/parisc/include/asm/sections.h15
-rw-r--r--arch/parisc/include/asm/serial.h8
-rw-r--r--arch/parisc/include/asm/shmparam.h23
-rw-r--r--arch/parisc/include/asm/signal.h27
-rw-r--r--arch/parisc/include/asm/smp.h50
-rw-r--r--arch/parisc/include/asm/socket.h12
-rw-r--r--arch/parisc/include/asm/sparsemem.h14
-rw-r--r--arch/parisc/include/asm/special_insns.h71
-rw-r--r--arch/parisc/include/asm/spinlock.h161
-rw-r--r--arch/parisc/include/asm/spinlock_types.h35
-rw-r--r--arch/parisc/include/asm/string.h11
-rw-r--r--arch/parisc/include/asm/superio.h86
-rw-r--r--arch/parisc/include/asm/switch_to.h13
-rw-r--r--arch/parisc/include/asm/syscall.h67
-rw-r--r--arch/parisc/include/asm/thread_info.h85
-rw-r--r--arch/parisc/include/asm/timex.h22
-rw-r--r--arch/parisc/include/asm/tlb.h12
-rw-r--r--arch/parisc/include/asm/tlbflush.h69
-rw-r--r--arch/parisc/include/asm/topology.h19
-rw-r--r--arch/parisc/include/asm/traps.h24
-rw-r--r--arch/parisc/include/asm/uaccess.h222
-rw-r--r--arch/parisc/include/asm/ucontext.h13
-rw-r--r--arch/parisc/include/asm/unaligned.h11
-rw-r--r--arch/parisc/include/asm/unistd.h176
-rw-r--r--arch/parisc/include/asm/unwind.h85
-rw-r--r--arch/parisc/include/asm/vdso.h24
-rw-r--r--arch/parisc/include/asm/vmalloc.h4
-rw-r--r--arch/parisc/include/uapi/asm/Kbuild3
-rw-r--r--arch/parisc/include/uapi/asm/auxvec.h8
-rw-r--r--arch/parisc/include/uapi/asm/bitsperlong.h13
-rw-r--r--arch/parisc/include/uapi/asm/byteorder.h7
-rw-r--r--arch/parisc/include/uapi/asm/cachectl.h12
-rw-r--r--arch/parisc/include/uapi/asm/errno.h125
-rw-r--r--arch/parisc/include/uapi/asm/fcntl.h39
-rw-r--r--arch/parisc/include/uapi/asm/ioctl.h45
-rw-r--r--arch/parisc/include/uapi/asm/ioctls.h101
-rw-r--r--arch/parisc/include/uapi/asm/ipcbuf.h33
-rw-r--r--arch/parisc/include/uapi/asm/mman.h86
-rw-r--r--arch/parisc/include/uapi/asm/msgbuf.h40
-rw-r--r--arch/parisc/include/uapi/asm/pdc.h723
-rw-r--r--arch/parisc/include/uapi/asm/posix_types.h24
-rw-r--r--arch/parisc/include/uapi/asm/ptrace.h96
-rw-r--r--arch/parisc/include/uapi/asm/sembuf.h33
-rw-r--r--arch/parisc/include/uapi/asm/setup.h7
-rw-r--r--arch/parisc/include/uapi/asm/shmbuf.h53
-rw-r--r--arch/parisc/include/uapi/asm/sigcontext.h21
-rw-r--r--arch/parisc/include/uapi/asm/signal.h74
-rw-r--r--arch/parisc/include/uapi/asm/socket.h158
-rw-r--r--arch/parisc/include/uapi/asm/stat.h68
-rw-r--r--arch/parisc/include/uapi/asm/statfs.h8
-rw-r--r--arch/parisc/include/uapi/asm/termbits.h149
-rw-r--r--arch/parisc/include/uapi/asm/unistd.h13
-rwxr-xr-xarch/parisc/install.sh39
-rw-r--r--arch/parisc/kernel/.gitignore2
-rw-r--r--arch/parisc/kernel/Makefile49
-rw-r--r--arch/parisc/kernel/alternative.c122
-rw-r--r--arch/parisc/kernel/asm-offsets.c287
-rw-r--r--arch/parisc/kernel/audit.c83
-rw-r--r--arch/parisc/kernel/cache.c874
-rw-r--r--arch/parisc/kernel/compat_audit.c28
-rw-r--r--arch/parisc/kernel/drivers.c1102
-rw-r--r--arch/parisc/kernel/entry.S2341
-rw-r--r--arch/parisc/kernel/firmware.c1931
-rw-r--r--arch/parisc/kernel/ftrace.c251
-rw-r--r--arch/parisc/kernel/hardware.c1374
-rw-r--r--arch/parisc/kernel/head.S443
-rw-r--r--arch/parisc/kernel/hpmc.S289
-rw-r--r--arch/parisc/kernel/inventory.c674
-rw-r--r--arch/parisc/kernel/irq.c579
-rw-r--r--arch/parisc/kernel/jump_label.c44
-rw-r--r--arch/parisc/kernel/kexec.c114
-rw-r--r--arch/parisc/kernel/kexec_file.c86
-rw-r--r--arch/parisc/kernel/kgdb.c210
-rw-r--r--arch/parisc/kernel/kprobes.c228
-rw-r--r--arch/parisc/kernel/module.c973
-rw-r--r--arch/parisc/kernel/pacache.S1295
-rw-r--r--arch/parisc/kernel/parisc_ksyms.c129
-rw-r--r--arch/parisc/kernel/patch.c130
-rw-r--r--arch/parisc/kernel/pci-dma.c464
-rw-r--r--arch/parisc/kernel/pci.c268
-rw-r--r--arch/parisc/kernel/pdc_chassis.c290
-rw-r--r--arch/parisc/kernel/pdc_cons.c65
-rw-r--r--arch/parisc/kernel/pdt.c361
-rw-r--r--arch/parisc/kernel/perf.c838
-rw-r--r--arch/parisc/kernel/perf_asm.S1679
-rw-r--r--arch/parisc/kernel/perf_images.h3125
-rw-r--r--arch/parisc/kernel/process.c280
-rw-r--r--arch/parisc/kernel/processor.c486
-rw-r--r--arch/parisc/kernel/ptrace.c793
-rw-r--r--arch/parisc/kernel/real2.S292
-rw-r--r--arch/parisc/kernel/relocate_kernel.S149
-rw-r--r--arch/parisc/kernel/setup.c310
-rw-r--r--arch/parisc/kernel/signal.c589
-rw-r--r--arch/parisc/kernel/signal32.c248
-rw-r--r--arch/parisc/kernel/signal32.h64
-rw-r--r--arch/parisc/kernel/smp.c513
-rw-r--r--arch/parisc/kernel/stacktrace.c43
-rw-r--r--arch/parisc/kernel/sys_parisc.c404
-rw-r--r--arch/parisc/kernel/sys_parisc32.c34
-rw-r--r--arch/parisc/kernel/syscall.S1358
-rw-r--r--arch/parisc/kernel/syscalls/Makefile33
-rw-r--r--arch/parisc/kernel/syscalls/syscall.tbl453
-rw-r--r--arch/parisc/kernel/time.c269
-rw-r--r--arch/parisc/kernel/toc.c126
-rw-r--r--arch/parisc/kernel/toc_asm.S75
-rw-r--r--arch/parisc/kernel/topology.c87
-rw-r--r--arch/parisc/kernel/traps.c859
-rw-r--r--arch/parisc/kernel/unaligned.c674
-rw-r--r--arch/parisc/kernel/unwind.c491
-rw-r--r--arch/parisc/kernel/vdso.c122
-rw-r--r--arch/parisc/kernel/vdso32/Makefile53
-rwxr-xr-xarch/parisc/kernel/vdso32/gen_vdso_offsets.sh15
-rw-r--r--arch/parisc/kernel/vdso32/note.S26
-rw-r--r--arch/parisc/kernel/vdso32/restart_syscall.S32
-rw-r--r--arch/parisc/kernel/vdso32/sigtramp.S195
-rw-r--r--arch/parisc/kernel/vdso32/vdso32.lds.S111
-rw-r--r--arch/parisc/kernel/vdso32/vdso32_wrapper.S14
-rw-r--r--arch/parisc/kernel/vdso64/Makefile48
-rwxr-xr-xarch/parisc/kernel/vdso64/gen_vdso_offsets.sh15
-rw-r--r--arch/parisc/kernel/vdso64/note.S2
-rw-r--r--arch/parisc/kernel/vdso64/restart_syscall.S3
-rw-r--r--arch/parisc/kernel/vdso64/sigtramp.S166
-rw-r--r--arch/parisc/kernel/vdso64/vdso64.lds.S109
-rw-r--r--arch/parisc/kernel/vdso64/vdso64_wrapper.S14
-rw-r--r--arch/parisc/kernel/vmlinux.lds.S186
-rw-r--r--arch/parisc/lib/Makefile9
-rw-r--r--arch/parisc/lib/bitops.c93
-rw-r--r--arch/parisc/lib/checksum.c108
-rw-r--r--arch/parisc/lib/delay.c72
-rw-r--r--arch/parisc/lib/io.c489
-rw-r--r--arch/parisc/lib/iomap.c551
-rw-r--r--arch/parisc/lib/lusercopy.S362
-rw-r--r--arch/parisc/lib/memcpy.c57
-rw-r--r--arch/parisc/lib/memset.c72
-rw-r--r--arch/parisc/lib/ucmpdi2.c27
-rw-r--r--arch/parisc/math-emu/Makefile22
-rw-r--r--arch/parisc/math-emu/README11
-rw-r--r--arch/parisc/math-emu/cnv_float.h363
-rw-r--r--arch/parisc/math-emu/dbl_float.h834
-rw-r--r--arch/parisc/math-emu/decode_exc.c357
-rw-r--r--arch/parisc/math-emu/denormal.c122
-rw-r--r--arch/parisc/math-emu/dfadd.c511
-rw-r--r--arch/parisc/math-emu/dfcmp.c168
-rw-r--r--arch/parisc/math-emu/dfdiv.c387
-rw-r--r--arch/parisc/math-emu/dfmpy.c381
-rw-r--r--arch/parisc/math-emu/dfrem.c284
-rw-r--r--arch/parisc/math-emu/dfsqrt.c182
-rw-r--r--arch/parisc/math-emu/dfsub.c513
-rw-r--r--arch/parisc/math-emu/driver.c112
-rw-r--r--arch/parisc/math-emu/fcnvff.c296
-rw-r--r--arch/parisc/math-emu/fcnvfu.c523
-rw-r--r--arch/parisc/math-emu/fcnvfut.c319
-rw-r--r--arch/parisc/math-emu/fcnvfx.c488
-rw-r--r--arch/parisc/math-emu/fcnvfxt.c315
-rw-r--r--arch/parisc/math-emu/fcnvuf.c305
-rw-r--r--arch/parisc/math-emu/fcnvxf.c373
-rw-r--r--arch/parisc/math-emu/float.h568
-rw-r--r--arch/parisc/math-emu/fmpyfadd.c2642
-rw-r--r--arch/parisc/math-emu/fpbits.h52
-rw-r--r--arch/parisc/math-emu/fpu.h37
-rw-r--r--arch/parisc/math-emu/fpudispatch.c1480
-rw-r--r--arch/parisc/math-emu/frnd.c239
-rw-r--r--arch/parisc/math-emu/hppa.h29
-rw-r--r--arch/parisc/math-emu/math-emu.h14
-rw-r--r--arch/parisc/math-emu/sfadd.c505
-rw-r--r--arch/parisc/math-emu/sfcmp.c142
-rw-r--r--arch/parisc/math-emu/sfdiv.c379
-rw-r--r--arch/parisc/math-emu/sfmpy.c367
-rw-r--r--arch/parisc/math-emu/sfrem.c277
-rw-r--r--arch/parisc/math-emu/sfsqrt.c174
-rw-r--r--arch/parisc/math-emu/sfsub.c508
-rw-r--r--arch/parisc/math-emu/sgl_float.h473
-rw-r--r--arch/parisc/mm/Makefile7
-rw-r--r--arch/parisc/mm/fault.c526
-rw-r--r--arch/parisc/mm/fixmap.c38
-rw-r--r--arch/parisc/mm/hugetlbpage.c193
-rw-r--r--arch/parisc/mm/init.c993
-rw-r--r--arch/parisc/mm/ioremap.c46
-rw-r--r--arch/parisc/net/Makefile9
-rw-r--r--arch/parisc/net/bpf_jit.h479
-rw-r--r--arch/parisc/net/bpf_jit_comp32.c1615
-rw-r--r--arch/parisc/net/bpf_jit_comp64.c1209
-rw-r--r--arch/parisc/net/bpf_jit_core.c201
-rw-r--r--arch/parisc/video/Makefile3
-rw-r--r--arch/parisc/video/fbdev.c26
271 files changed, 65300 insertions, 0 deletions
diff --git a/arch/parisc/Kbuild b/arch/parisc/Kbuild
new file mode 100644
index 000000000..749b195f2
--- /dev/null
+++ b/arch/parisc/Kbuild
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-y += mm/ kernel/ math-emu/ net/
+
+# for cleaning
+subdir- += boot
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig
new file mode 100644
index 000000000..8c45b98df
--- /dev/null
+++ b/arch/parisc/Kconfig
@@ -0,0 +1,378 @@
+# SPDX-License-Identifier: GPL-2.0
+config PARISC
+ def_bool y
+ select ALTERNATE_USER_ADDRESS_SPACE
+ select ARCH_32BIT_OFF_T if !64BIT
+ select ARCH_MIGHT_HAVE_PC_PARPORT
+ select HAVE_FUNCTION_TRACER
+ select HAVE_FUNCTION_GRAPH_TRACER
+ select HAVE_SYSCALL_TRACEPOINTS
+ select ARCH_WANT_FRAME_POINTERS
+ select ARCH_HAS_ELF_RANDOMIZE
+ select ARCH_HAS_STRICT_KERNEL_RWX
+ select ARCH_HAS_STRICT_MODULE_RWX
+ select ARCH_HAS_UBSAN_SANITIZE_ALL
+ select ARCH_HAS_PTE_SPECIAL
+ select ARCH_NO_SG_CHAIN
+ select ARCH_SUPPORTS_HUGETLBFS if PA20
+ select ARCH_SUPPORTS_MEMORY_FAILURE
+ select ARCH_STACKWALK
+ select ARCH_HAS_DEBUG_VM_PGTABLE
+ select HAVE_RELIABLE_STACKTRACE
+ select DMA_OPS
+ select RTC_CLASS
+ select RTC_DRV_GENERIC
+ select INIT_ALL_POSSIBLE
+ select BUG
+ select BUILDTIME_TABLE_SORT
+ select HAVE_PCI
+ select HAVE_PERF_EVENTS
+ select HAVE_KERNEL_BZIP2
+ select HAVE_KERNEL_GZIP
+ select HAVE_KERNEL_LZ4
+ select HAVE_KERNEL_LZMA
+ select HAVE_KERNEL_LZO
+ select HAVE_KERNEL_XZ
+ select GENERIC_ATOMIC64 if !64BIT
+ select GENERIC_IRQ_PROBE
+ select GENERIC_PCI_IOMAP
+ select GENERIC_IOREMAP
+ select ARCH_HAVE_NMI_SAFE_CMPXCHG
+ select GENERIC_SMP_IDLE_THREAD
+ select GENERIC_ARCH_TOPOLOGY if SMP
+ select GENERIC_CPU_DEVICES if !SMP
+ select GENERIC_LIB_DEVMEM_IS_ALLOWED
+ select SYSCTL_ARCH_UNALIGN_ALLOW
+ select SYSCTL_EXCEPTION_TRACE
+ select HAVE_MOD_ARCH_SPECIFIC
+ select MODULES_USE_ELF_RELA
+ select CLONE_BACKWARDS
+ select TTY # Needed for pdc_cons.c
+ select HAS_IOPORT if PCI || EISA
+ select HAVE_DEBUG_STACKOVERFLOW
+ select ARCH_WANT_DEFAULT_TOPDOWN_MMAP_LAYOUT
+ select HAVE_ARCH_MMAP_RND_COMPAT_BITS if COMPAT
+ select HAVE_ARCH_MMAP_RND_BITS
+ select HAVE_ARCH_AUDITSYSCALL
+ select HAVE_ARCH_HASH
+ select HAVE_ARCH_JUMP_LABEL
+ select HAVE_ARCH_JUMP_LABEL_RELATIVE
+ select HAVE_ARCH_KFENCE
+ select HAVE_ARCH_SECCOMP_FILTER
+ select HAVE_ARCH_TRACEHOOK
+ select HAVE_EBPF_JIT
+ select ARCH_WANT_DEFAULT_BPF_JIT
+ select HAVE_REGS_AND_STACK_ACCESS_API
+ select HOTPLUG_CORE_SYNC_DEAD if HOTPLUG_CPU
+ select GENERIC_SCHED_CLOCK
+ select GENERIC_IRQ_MIGRATION if SMP
+ select HAVE_UNSTABLE_SCHED_CLOCK if SMP
+ select LEGACY_TIMER_TICK
+ select CPU_NO_EFFICIENT_FFS
+ select THREAD_INFO_IN_TASK
+ select NEED_DMA_MAP_STATE
+ select NEED_SG_DMA_LENGTH
+ select HAVE_ARCH_KGDB
+ select HAVE_KPROBES
+ select HAVE_KRETPROBES
+ select HAVE_DYNAMIC_FTRACE if $(cc-option,-fpatchable-function-entry=1,1)
+ select HAVE_FTRACE_MCOUNT_RECORD if HAVE_DYNAMIC_FTRACE
+ select FTRACE_MCOUNT_USE_PATCHABLE_FUNCTION_ENTRY if DYNAMIC_FTRACE
+ select HAVE_KPROBES_ON_FTRACE
+ select HAVE_DYNAMIC_FTRACE_WITH_REGS
+ select HAVE_SOFTIRQ_ON_OWN_STACK if IRQSTACKS
+ select TRACE_IRQFLAGS_SUPPORT
+ select HAVE_FUNCTION_DESCRIPTORS if 64BIT
+
+ help
+ The PA-RISC microprocessor is designed by Hewlett-Packard and used
+ in many of their workstations & servers (HP9000 700 and 800 series,
+ and later HP3000 series). The PA-RISC Linux project home page is
+ at <https://parisc.wiki.kernel.org>.
+
+config CPU_BIG_ENDIAN
+ def_bool y
+
+config MMU
+ def_bool y
+
+config STACK_GROWSUP
+ def_bool y
+
+config GENERIC_LOCKBREAK
+ bool
+ default y
+ depends on SMP && PREEMPTION
+
+config ARCH_HAS_ILOG2_U32
+ bool
+ default n
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
+config GENERIC_BUG
+ def_bool y
+ depends on BUG
+ select GENERIC_BUG_RELATIVE_POINTERS if 64BIT
+
+config GENERIC_BUG_RELATIVE_POINTERS
+ bool
+
+config GENERIC_HWEIGHT
+ bool
+ default y
+
+config GENERIC_CALIBRATE_DELAY
+ bool
+ default y
+
+config TIME_LOW_RES
+ bool
+ depends on SMP
+ default y
+
+config ARCH_MMAP_RND_BITS_MIN
+ default 18 if 64BIT
+ default 8
+
+config ARCH_MMAP_RND_COMPAT_BITS_MIN
+ default 8
+
+config ARCH_MMAP_RND_BITS_MAX
+ default 18 if 64BIT
+ default 13
+
+config ARCH_MMAP_RND_COMPAT_BITS_MAX
+ default 13
+
+# unless you want to implement ACPI on PA-RISC ... ;-)
+config PM
+ bool
+
+config STACKTRACE_SUPPORT
+ def_bool y
+
+config LOCKDEP_SUPPORT
+ bool
+ default y
+
+config ISA_DMA_API
+ bool
+
+config ARCH_MAY_HAVE_PC_FDC
+ bool
+ depends on BROKEN
+ default y
+
+config PGTABLE_LEVELS
+ int
+ default 3 if 64BIT && PARISC_PAGE_SIZE_4KB
+ default 2
+
+menu "Processor type and features"
+
+choice
+ prompt "Processor type"
+ default PA7000 if "$(ARCH)" = "parisc"
+
+config PA7000
+ bool "PA7000/PA7100" if "$(ARCH)" = "parisc"
+ help
+ This is the processor type of your CPU. This information is
+ used for optimizing purposes. In order to compile a kernel
+ that can run on all 32-bit PA CPUs (albeit not optimally fast),
+ you can specify "PA7000" here.
+
+ Specifying "PA8000" here will allow you to select a 64-bit kernel
+ which is required on some machines.
+
+config PA7100LC
+ bool "PA7100LC" if "$(ARCH)" = "parisc"
+ help
+ Select this option for the PCX-L processor, as used in the
+ 712, 715/64, 715/80, 715/100, 715/100XC, 725/100, 743, 748,
+ D200, D210, D300, D310 and E-class
+
+config PA7200
+ bool "PA7200" if "$(ARCH)" = "parisc"
+ help
+ Select this option for the PCX-T' processor, as used in the
+ C100, C110, J100, J110, J210XC, D250, D260, D350, D360,
+ K100, K200, K210, K220, K400, K410 and K420
+
+config PA7300LC
+ bool "PA7300LC" if "$(ARCH)" = "parisc"
+ help
+ Select this option for the PCX-L2 processor, as used in the
+ 744, A180, B132L, B160L, B180L, C132L, C160L, C180L,
+ D220, D230, D320 and D330.
+
+config PA8X00
+ bool "PA8000 and up"
+ help
+ Select this option for PCX-U to PCX-W2 processors.
+
+endchoice
+
+# Define implied options from the CPU selection here
+
+config PA20
+ def_bool y
+ depends on PA8X00
+
+config PA11
+ def_bool y
+ depends on PA7000 || PA7100LC || PA7200 || PA7300LC
+ select ARCH_HAS_SYNC_DMA_FOR_CPU
+ select ARCH_HAS_SYNC_DMA_FOR_DEVICE
+
+config PREFETCH
+ def_bool y
+ depends on PA8X00 || PA7200
+
+config PARISC_HUGE_KERNEL
+ def_bool y if !MODULES || UBSAN || FTRACE || COMPILE_TEST
+
+config MLONGCALLS
+ def_bool y if PARISC_HUGE_KERNEL
+ bool "Enable the -mlong-calls compiler option for big kernels" if !PARISC_HUGE_KERNEL
+ depends on PA8X00
+ help
+ If you configure the kernel to include many drivers built-in instead
+ as modules, the kernel executable may become too big, so that the
+ linker will not be able to resolve some long branches and fails to link
+ your vmlinux kernel. In that case enabling this option will help you
+ to overcome this limit by using the -mlong-calls compiler option.
+
+ Usually you want to say N here, unless you e.g. want to build
+ a kernel which includes all necessary drivers built-in and which can
+ be used for TFTP booting without the need to have an initrd ramdisk.
+
+ Enabling this option will probably slow down your kernel.
+
+config 64BIT
+ def_bool y if "$(ARCH)" = "parisc64"
+ bool "64-bit kernel" if "$(ARCH)" = "parisc"
+ depends on PA8X00
+ help
+ Enable this if you want to support 64bit kernel on PA-RISC platform.
+
+ At the moment, only people willing to use more than 2GB of RAM,
+ or having a 64bit-only capable PA-RISC machine should say Y here.
+
+ Since there is no 64bit userland on PA-RISC, there is no point to
+ enable this option otherwise. The 64bit kernel is significantly bigger
+ and slower than the 32bit one.
+
+choice
+ prompt "Kernel page size"
+ default PARISC_PAGE_SIZE_4KB
+
+config PARISC_PAGE_SIZE_4KB
+ bool "4KB"
+ help
+ This lets you select the page size of the kernel. For best
+ performance, a page size of 16KB is recommended. For best
+ compatibility with 32bit applications, a page size of 4KB should be
+ selected (the vast majority of 32bit binaries work perfectly fine
+ with a larger page size).
+
+ 4KB For best 32bit compatibility
+ 16KB For best performance
+ 64KB For best performance, might give more overhead.
+
+ If you don't know what to do, choose 4KB.
+
+config PARISC_PAGE_SIZE_16KB
+ bool "16KB"
+ depends on PA8X00 && BROKEN && !KFENCE
+
+config PARISC_PAGE_SIZE_64KB
+ bool "64KB"
+ depends on PA8X00 && BROKEN && !KFENCE
+
+endchoice
+
+config SMP
+ bool "Symmetric multi-processing support"
+ help
+ This enables support for systems with more than one CPU. If you have
+ a system with only one CPU, say N. If you have a system with more
+ than one CPU, say Y.
+
+ If you say N here, the kernel will run on uni- and multiprocessor
+ machines, but will use only one CPU of a multiprocessor machine.
+ On a uniprocessor machine, the kernel will run faster if you say N.
+
+ See also <file:Documentation/admin-guide/lockup-watchdogs.rst> and the SMP-HOWTO
+ available at <https://www.tldp.org/docs.html#howto>.
+
+ If you don't know what to do here, say N.
+
+config SCHED_MC
+ bool "Multi-core scheduler support"
+ depends on GENERIC_ARCH_TOPOLOGY && PA8X00
+ help
+ Multi-core scheduler support improves the CPU scheduler's decision
+ making when dealing with multi-core CPU chips at a cost of slightly
+ increased overhead in some places. If unsure say N here.
+
+config IRQSTACKS
+ bool "Use separate kernel stacks when processing interrupts"
+ default y
+ help
+ If you say Y here the kernel will use separate kernel stacks
+ for handling hard and soft interrupts. This can help avoid
+ overflowing the process kernel stacks.
+
+config HOTPLUG_CPU
+ bool
+ default y if SMP
+
+config ARCH_SELECT_MEMORY_MODEL
+ def_bool y
+ depends on 64BIT
+
+config ARCH_SPARSEMEM_ENABLE
+ def_bool y
+ depends on 64BIT
+
+config ARCH_FLATMEM_ENABLE
+ def_bool y
+
+config ARCH_SPARSEMEM_DEFAULT
+ def_bool y
+ depends on ARCH_SPARSEMEM_ENABLE
+
+source "kernel/Kconfig.hz"
+
+config COMPAT
+ def_bool y
+ depends on 64BIT
+
+config AUDIT_ARCH
+ def_bool y
+
+config NR_CPUS
+ int "Maximum number of CPUs (2-32)"
+ range 2 32
+ depends on SMP
+ default "8" if 64BIT
+ default "16"
+
+endmenu
+
+config ARCH_SUPPORTS_KEXEC
+ def_bool y
+
+config ARCH_SUPPORTS_KEXEC_FILE
+ def_bool y
+
+config ARCH_SELECTS_KEXEC_FILE
+ def_bool y
+ depends on KEXEC_FILE
+ select KEXEC_ELF
+
+source "drivers/parisc/Kconfig"
diff --git a/arch/parisc/Kconfig.debug b/arch/parisc/Kconfig.debug
new file mode 100644
index 000000000..f4f164eb1
--- /dev/null
+++ b/arch/parisc/Kconfig.debug
@@ -0,0 +1,23 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+config LIGHTWEIGHT_SPINLOCK_CHECK
+ bool "Enable lightweight spinlock checks"
+ depends on DEBUG_KERNEL && SMP && !DEBUG_SPINLOCK
+ default y
+ help
+ Add checks with low performance impact to the spinlock functions
+ to catch memory overwrites at runtime. For more advanced
+ spinlock debugging you should choose the DEBUG_SPINLOCK option
+ which will detect unitialized spinlocks too.
+ If unsure say Y here.
+
+config TLB_PTLOCK
+ bool "Use page table locks in TLB fault handler"
+ depends on DEBUG_KERNEL && SMP
+ default n
+ help
+ Select this option to enable page table locking in the TLB
+ fault handler. This ensures that page table entries are
+ updated consistently on SMP machines at the expense of some
+ loss in performance.
+
diff --git a/arch/parisc/Makefile b/arch/parisc/Makefile
new file mode 100644
index 000000000..968ebe174
--- /dev/null
+++ b/arch/parisc/Makefile
@@ -0,0 +1,207 @@
+#
+# parisc/Makefile
+#
+# This file is included by the global makefile so that you can add your own
+# architecture-specific flags and dependencies.
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License. See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+# Copyright (C) 1994 by Linus Torvalds
+# Portions Copyright (C) 1999 The Puffin Group
+#
+# Modified for PA-RISC Linux by Paul Lahaie, Alex deVries,
+# Mike Shaver, Helge Deller and Martin K. Petersen
+#
+
+boot := arch/parisc/boot
+KBUILD_IMAGE := $(boot)/bzImage
+
+CHECKFLAGS += -D__hppa__=1
+
+ifdef CONFIG_64BIT
+UTS_MACHINE := parisc64
+CHECKFLAGS += -D__LP64__=1
+LD_BFD := elf64-hppa-linux
+else # 32-bit
+LD_BFD := elf32-hppa-linux
+endif
+
+# select defconfig based on actual architecture
+ifeq ($(ARCH),parisc64)
+ KBUILD_DEFCONFIG := generic-64bit_defconfig
+ CC_ARCHES := hppa64
+else
+ KBUILD_DEFCONFIG := generic-32bit_defconfig
+ CC_ARCHES := hppa hppa2.0 hppa1.1
+endif
+
+export LD_BFD
+
+# Set default 32 bits cross compilers for vdso
+CC_ARCHES_32 = hppa hppa2.0 hppa1.1
+CC_SUFFIXES = linux linux-gnu unknown-linux-gnu suse-linux
+CROSS32_COMPILE := $(call cc-cross-prefix, \
+ $(foreach a,$(CC_ARCHES_32), \
+ $(foreach s,$(CC_SUFFIXES),$(a)-$(s)-)))
+CROSS32CC := $(CROSS32_COMPILE)gcc
+export CROSS32CC
+
+# Set default cross compiler for kernel build
+ifdef cross_compiling
+ ifeq ($(CROSS_COMPILE),)
+ CC_SUFFIXES = linux linux-gnu unknown-linux-gnu suse-linux
+ CROSS_COMPILE := $(call cc-cross-prefix, \
+ $(foreach a,$(CC_ARCHES), \
+ $(foreach s,$(CC_SUFFIXES),$(a)-$(s)-)))
+ endif
+endif
+
+ifdef CONFIG_DYNAMIC_FTRACE
+ifdef CONFIG_64BIT
+NOP_COUNT := 8
+else
+NOP_COUNT := 5
+endif
+
+export CC_USING_RECORD_MCOUNT:=1
+export CC_USING_PATCHABLE_FUNCTION_ENTRY:=1
+
+KBUILD_AFLAGS += -DCC_USING_PATCHABLE_FUNCTION_ENTRY=1
+KBUILD_CFLAGS += -DCC_USING_PATCHABLE_FUNCTION_ENTRY=1 \
+ -DFTRACE_PATCHABLE_FUNCTION_SIZE=$(NOP_COUNT)
+
+CC_FLAGS_FTRACE := -fpatchable-function-entry=$(NOP_COUNT),$(shell echo $$(($(NOP_COUNT)-1)))
+endif
+
+OBJCOPY_FLAGS =-O binary -R .note -R .comment -S
+
+cflags-y := -pipe
+
+# These flags should be implied by an hppa-linux configuration, but they
+# are not in gcc 3.2.
+cflags-y += -mno-space-regs
+
+# -mfast-indirect-calls is only relevant for 32-bit kernels.
+ifndef CONFIG_64BIT
+cflags-y += -mfast-indirect-calls
+endif
+
+# Currently we save and restore fpregs on all kernel entry/interruption paths.
+# If that gets optimized, we might need to disable the use of fpregs in the
+# kernel.
+cflags-y += -mdisable-fpregs
+
+# Use long jumps instead of long branches (needed if your linker fails to
+# link a too big vmlinux executable). Not enabled for building modules.
+ifdef CONFIG_MLONGCALLS
+KBUILD_CFLAGS_KERNEL += -mlong-calls
+endif
+
+# Without this, "ld -r" results in .text sections that are too big (> 0x40000)
+# for branches to reach stubs. And multiple .text sections trigger a warning
+# when creating the sysfs module information section.
+ifndef CONFIG_64BIT
+KBUILD_CFLAGS_MODULE += -ffunction-sections
+endif
+
+# select which processor to optimise for
+cflags-$(CONFIG_PA7000) += -march=1.1 -mschedule=7100
+cflags-$(CONFIG_PA7200) += -march=1.1 -mschedule=7200
+cflags-$(CONFIG_PA7100LC) += -march=1.1 -mschedule=7100LC
+cflags-$(CONFIG_PA7300LC) += -march=1.1 -mschedule=7300
+cflags-$(CONFIG_PA8X00) += -march=2.0 -mschedule=8000
+
+KBUILD_CFLAGS += $(cflags-y)
+LIBGCC := $(shell $(CC) -print-libgcc-file-name)
+export LIBGCC
+
+libs-y += arch/parisc/lib/ $(LIBGCC)
+
+drivers-y += arch/parisc/video/
+
+boot := arch/parisc/boot
+
+PALO := $(shell if (which palo 2>&1); then : ; \
+ elif [ -x /sbin/palo ]; then echo /sbin/palo; \
+ fi)
+
+PALOCONF := $(shell if [ -f $(srctree)/palo.conf ]; then echo $(srctree)/palo.conf; \
+ else echo $(objtree)/palo.conf; \
+ fi)
+
+palo lifimage: vmlinuz
+ @if test ! -x "$(PALO)"; then \
+ echo 'ERROR: Please install palo first (apt-get install palo)';\
+ echo 'or build it from source and install it somewhere in your $$PATH';\
+ false; \
+ fi
+ @if test ! -f "$(PALOCONF)"; then \
+ cp $(srctree)/arch/parisc/defpalo.conf $(objtree)/palo.conf; \
+ echo 'A generic palo config file ($(objree)/palo.conf) has been created for you.'; \
+ echo 'You should check it and re-run "make palo".'; \
+ echo 'WARNING: the "lifimage" file is now placed in this directory by default!'; \
+ false; \
+ fi
+ $(PALO) -f $(PALOCONF)
+
+BOOT_TARGETS = zImage Image palo lifimage
+INSTALL_TARGETS = zinstall install
+
+PHONY += bzImage $(BOOT_TARGETS) $(INSTALL_TARGETS)
+
+# Default kernel to build
+all: bzImage
+
+zImage: vmlinuz
+Image: vmlinux
+
+bzImage: vmlinux
+ $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
+
+vmlinuz: bzImage
+ $(OBJCOPY) $(boot)/bzImage $@
+
+ifeq ($(KBUILD_EXTMOD),)
+# We need to generate vdso-offsets.h before compiling certain files in kernel/.
+# In order to do that, we should use the archprepare target, but we can't since
+# asm-offsets.h is included in some files used to generate vdso-offsets.h, and
+# asm-offsets.h is built in prepare0, for which archprepare is a dependency.
+# Therefore we need to generate the header after prepare0 has been made, hence
+# this hack.
+prepare: vdso_prepare
+vdso_prepare: prepare0
+ $(if $(CONFIG_64BIT),$(Q)$(MAKE) \
+ $(build)=arch/parisc/kernel/vdso64 include/generated/vdso64-offsets.h)
+ $(Q)$(MAKE) $(build)=arch/parisc/kernel/vdso32 include/generated/vdso32-offsets.h
+endif
+
+PHONY += vdso_install
+
+vdso_install:
+ $(Q)$(MAKE) $(build)=arch/parisc/kernel/vdso $@
+ $(if $(CONFIG_COMPAT_VDSO), \
+ $(Q)$(MAKE) $(build)=arch/parisc/kernel/vdso32 $@)
+
+install: KBUILD_IMAGE := vmlinux
+zinstall: KBUILD_IMAGE := vmlinuz
+install zinstall:
+ $(call cmd,install)
+
+CLEAN_FILES += lifimage
+MRPROPER_FILES += palo.conf
+
+define archhelp
+ @echo '* vmlinux - Uncompressed kernel image (./vmlinux)'
+ @echo ' vmlinuz - Compressed kernel image (./vmlinuz)'
+ @echo ' palo - Bootable image (./lifimage)'
+ @echo ' install - Install uncompressed vmlinux kernel using'
+ @echo ' (your) ~/bin/$(INSTALLKERNEL) or'
+ @echo ' (distribution) /sbin/$(INSTALLKERNEL) or'
+ @echo ' copy to $$(INSTALL_PATH)'
+ @echo ' zinstall - Install compressed vmlinuz kernel'
+endef
+
+archheaders:
+ $(Q)$(MAKE) $(build)=arch/parisc/kernel/syscalls all
diff --git a/arch/parisc/boot/.gitignore b/arch/parisc/boot/.gitignore
new file mode 100644
index 000000000..adf2ae0e7
--- /dev/null
+++ b/arch/parisc/boot/.gitignore
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+image
+bzImage
diff --git a/arch/parisc/boot/Makefile b/arch/parisc/boot/Makefile
new file mode 100644
index 000000000..b873ee472
--- /dev/null
+++ b/arch/parisc/boot/Makefile
@@ -0,0 +1,17 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Makefile for the linux parisc-specific parts of the boot image creator.
+#
+
+targets := image
+targets += bzImage
+subdir- := compressed
+
+$(obj)/image: vmlinux FORCE
+ $(call if_changed,objcopy)
+
+$(obj)/bzImage: $(obj)/compressed/vmlinux FORCE
+ $(call if_changed,objcopy)
+
+$(obj)/compressed/vmlinux: FORCE
+ $(Q)$(MAKE) $(build)=$(obj)/compressed $@
diff --git a/arch/parisc/boot/compressed/.gitignore b/arch/parisc/boot/compressed/.gitignore
new file mode 100644
index 000000000..a5839aa16
--- /dev/null
+++ b/arch/parisc/boot/compressed/.gitignore
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
+sizes.h
+vmlinux
+vmlinux.lds
diff --git a/arch/parisc/boot/compressed/Makefile b/arch/parisc/boot/compressed/Makefile
new file mode 100644
index 000000000..a294a1b58
--- /dev/null
+++ b/arch/parisc/boot/compressed/Makefile
@@ -0,0 +1,75 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# linux/arch/parisc/boot/compressed/Makefile
+#
+# create a compressed self-extracting vmlinux image from the original vmlinux
+#
+
+KCOV_INSTRUMENT := n
+GCOV_PROFILE := n
+UBSAN_SANITIZE := n
+
+OBJECTS := head.o real2.o firmware.o misc.o piggy.o
+targets := vmlinux.lds vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2
+targets += vmlinux.bin.xz vmlinux.bin.lzma vmlinux.bin.lzo vmlinux.bin.lz4
+targets += $(OBJECTS) sizes.h
+
+KBUILD_CFLAGS := -D__KERNEL__ -O2 -DBOOTLOADER
+KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING
+KBUILD_CFLAGS += -fno-strict-aliasing
+KBUILD_CFLAGS += $(cflags-y) -fno-delete-null-pointer-checks -fno-builtin-printf
+KBUILD_CFLAGS += -fno-PIE -mno-space-regs -mdisable-fpregs -Os
+ifndef CONFIG_64BIT
+KBUILD_CFLAGS += -mfast-indirect-calls
+endif
+
+LDFLAGS_vmlinux := -X -e startup --as-needed -T
+$(obj)/vmlinux: $(obj)/vmlinux.lds $(addprefix $(obj)/, $(OBJECTS)) $(LIBGCC) FORCE
+ $(call if_changed,ld)
+
+sed-sizes := -e 's/^\([0-9a-fA-F]*\) . \(__bss_start\|_end\|parisc_kernel_start\)$$/\#define SZ\2 0x\1/p'
+
+quiet_cmd_sizes = GEN $@
+ cmd_sizes = $(NM) $< | sed -n $(sed-sizes) > $@
+
+$(obj)/sizes.h: vmlinux FORCE
+ $(call if_changed,sizes)
+
+AFLAGS_head.o += -I$(objtree)/$(obj) -DBOOTLOADER
+$(obj)/head.o: $(obj)/sizes.h
+
+CFLAGS_misc.o += -I$(objtree)/$(obj)
+$(obj)/misc.o: $(obj)/sizes.h
+
+AFLAGS_real2.o += -DBOOTLOADER
+
+CPPFLAGS_vmlinux.lds += -I$(objtree)/$(obj) -DBOOTLOADER
+$(obj)/vmlinux.lds: $(obj)/sizes.h
+
+OBJCOPYFLAGS_vmlinux.bin := -R .comment -R .note -S
+$(obj)/vmlinux.bin: vmlinux FORCE
+ $(call if_changed,objcopy)
+
+suffix-$(CONFIG_KERNEL_GZIP) := gz
+suffix-$(CONFIG_KERNEL_BZIP2) := bz2
+suffix-$(CONFIG_KERNEL_LZ4) := lz4
+suffix-$(CONFIG_KERNEL_LZMA) := lzma
+suffix-$(CONFIG_KERNEL_LZO) := lzo
+suffix-$(CONFIG_KERNEL_XZ) := xz
+
+$(obj)/vmlinux.bin.gz: $(obj)/vmlinux.bin FORCE
+ $(call if_changed,gzip)
+$(obj)/vmlinux.bin.bz2: $(obj)/vmlinux.bin FORCE
+ $(call if_changed,bzip2_with_size)
+$(obj)/vmlinux.bin.lz4: $(obj)/vmlinux.bin FORCE
+ $(call if_changed,lz4_with_size)
+$(obj)/vmlinux.bin.lzma: $(obj)/vmlinux.bin FORCE
+ $(call if_changed,lzma_with_size)
+$(obj)/vmlinux.bin.lzo: $(obj)/vmlinux.bin FORCE
+ $(call if_changed,lzo_with_size)
+$(obj)/vmlinux.bin.xz: $(obj)/vmlinux.bin FORCE
+ $(call if_changed,xzkern_with_size)
+
+LDFLAGS_piggy.o := -r --format binary --oformat $(LD_BFD) -T
+$(obj)/piggy.o: $(obj)/vmlinux.scr $(obj)/vmlinux.bin.$(suffix-y) FORCE
+ $(call if_changed,ld)
diff --git a/arch/parisc/boot/compressed/firmware.c b/arch/parisc/boot/compressed/firmware.c
new file mode 100644
index 000000000..16a07137f
--- /dev/null
+++ b/arch/parisc/boot/compressed/firmware.c
@@ -0,0 +1,2 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include "../../kernel/firmware.c"
diff --git a/arch/parisc/boot/compressed/head.S b/arch/parisc/boot/compressed/head.S
new file mode 100644
index 000000000..e8b798fd0
--- /dev/null
+++ b/arch/parisc/boot/compressed/head.S
@@ -0,0 +1,85 @@
+/*
+ * Startup glue code to uncompress the kernel
+ *
+ * (C) 2017 Helge Deller <deller@gmx.de>
+ */
+
+#include <linux/init.h>
+#include <linux/linkage.h>
+#include <asm/asm-offsets.h>
+#include <asm/page.h>
+#include <asm/psw.h>
+#include <asm/pdc.h>
+#include <asm/assembly.h>
+#include "sizes.h"
+
+#define BOOTADDR(x) (x)
+
+#ifndef CONFIG_64BIT
+ .import $global$ /* forward declaration */
+#endif /*!CONFIG_64BIT*/
+
+ __HEAD
+
+ENTRY(startup)
+ .level PA_ASM_LEVEL
+
+#define PSW_W_SM 0x200
+#define PSW_W_BIT 36
+
+ ;! nuke the W bit, saving original value
+ .level 2.0
+ rsm PSW_W_SM, %r1
+
+ .level 1.1
+ extrw,u %r1, PSW_W_BIT-32, 1, %r1
+ copy %r1, %arg0
+
+ /* Make sure sr4-sr7 are set to zero for the kernel address space */
+ mtsp %r0,%sr4
+ mtsp %r0,%sr5
+ mtsp %r0,%sr6
+ mtsp %r0,%sr7
+
+ /* Clear BSS */
+
+ .import _bss,data
+ .import _ebss,data
+
+ load32 BOOTADDR(_bss),%r3
+ load32 BOOTADDR(_ebss),%r4
+ ldo FRAME_SIZE(%r4),%sp /* stack at end of bss */
+$bss_loop:
+ cmpb,<<,n %r3,%r4,$bss_loop
+ stw,ma %r0,4(%r3)
+
+ /* Initialize the global data pointer */
+ loadgp
+
+ /* arg0..arg4 were set by palo. */
+ copy %arg1, %r6 /* command line */
+ copy %arg2, %r7 /* rd-start */
+ copy %arg3, %r8 /* rd-end */
+ load32 BOOTADDR(decompress_kernel),%r3
+
+#ifdef CONFIG_64BIT
+ .level PA_ASM_LEVEL
+ ssm PSW_W_SM, %r0 /* set W-bit */
+ depdi 0, 31, 32, %r3
+#endif
+ load32 BOOTADDR(startup_continue), %r2
+ bv,n 0(%r3)
+
+startup_continue:
+#ifdef CONFIG_64BIT
+ .level PA_ASM_LEVEL
+ rsm PSW_W_SM, %r0 /* clear W-bit */
+#endif
+
+ load32 KERNEL_BINARY_TEXT_START, %arg0 /* free mem */
+ copy %r6, %arg1 /* command line */
+ copy %r7, %arg2 /* rd-start */
+ copy %r8, %arg3 /* rd-end */
+
+ bv,n 0(%ret0)
+END(startup)
diff --git a/arch/parisc/boot/compressed/misc.c b/arch/parisc/boot/compressed/misc.c
new file mode 100644
index 000000000..d389359e2
--- /dev/null
+++ b/arch/parisc/boot/compressed/misc.c
@@ -0,0 +1,370 @@
+/*
+ * Definitions and wrapper functions for kernel decompressor
+ *
+ * (C) 2017 Helge Deller <deller@gmx.de>
+ */
+
+#include <linux/uaccess.h>
+#include <linux/elf.h>
+#include <asm/unaligned.h>
+#include <asm/page.h>
+#include "sizes.h"
+
+/*
+ * gzip declarations
+ */
+#define STATIC static
+
+#undef memmove
+#define memmove memmove
+#define memzero(s, n) memset((s), 0, (n))
+
+#define malloc malloc_gzip
+#define free free_gzip
+
+/* Symbols defined by linker scripts */
+extern char input_data[];
+extern int input_len;
+/* output_len is inserted by the linker possibly at an unaligned address */
+extern char output_len;
+extern char _text, _end;
+extern char _bss, _ebss;
+extern char _startcode_end;
+extern void startup_continue(void *entry, unsigned long cmdline,
+ unsigned long rd_start, unsigned long rd_end) __noreturn;
+
+void error(char *m) __noreturn;
+
+static unsigned long free_mem_ptr;
+static unsigned long free_mem_end_ptr;
+
+#ifdef CONFIG_KERNEL_GZIP
+#include "../../../../lib/decompress_inflate.c"
+#endif
+
+#ifdef CONFIG_KERNEL_BZIP2
+#include "../../../../lib/decompress_bunzip2.c"
+#endif
+
+#ifdef CONFIG_KERNEL_LZ4
+#include "../../../../lib/decompress_unlz4.c"
+#endif
+
+#ifdef CONFIG_KERNEL_LZMA
+#include "../../../../lib/decompress_unlzma.c"
+#endif
+
+#ifdef CONFIG_KERNEL_LZO
+#include "../../../../lib/decompress_unlzo.c"
+#endif
+
+#ifdef CONFIG_KERNEL_XZ
+#include "../../../../lib/decompress_unxz.c"
+#endif
+
+void *memmove(void *dest, const void *src, size_t n)
+{
+ const char *s = src;
+ char *d = dest;
+
+ if (d <= s) {
+ while (n--)
+ *d++ = *s++;
+ } else {
+ d += n;
+ s += n;
+ while (n--)
+ *--d = *--s;
+ }
+ return dest;
+}
+
+void *memset(void *s, int c, size_t count)
+{
+ char *xs = (char *)s;
+
+ while (count--)
+ *xs++ = c;
+ return s;
+}
+
+void *memcpy(void *d, const void *s, size_t len)
+{
+ char *dest = (char *)d;
+ const char *source = (const char *)s;
+
+ while (len--)
+ *dest++ = *source++;
+ return d;
+}
+
+size_t strlen(const char *s)
+{
+ const char *sc;
+
+ for (sc = s; *sc != '\0'; ++sc)
+ ;
+ return sc - s;
+}
+
+char *strchr(const char *s, int c)
+{
+ while (*s) {
+ if (*s == (char)c)
+ return (char *)s;
+ ++s;
+ }
+ return NULL;
+}
+
+static int puts(const char *s)
+{
+ const char *nuline = s;
+
+ while ((nuline = strchr(s, '\n')) != NULL) {
+ if (nuline != s)
+ pdc_iodc_print(s, nuline - s);
+ pdc_iodc_print("\r\n", 2);
+ s = nuline + 1;
+ }
+ if (*s != '\0')
+ pdc_iodc_print(s, strlen(s));
+
+ return 0;
+}
+
+static int putchar(int c)
+{
+ char buf[2];
+
+ buf[0] = c;
+ buf[1] = '\0';
+ puts(buf);
+ return c;
+}
+
+void __noreturn error(char *x)
+{
+ if (x) puts(x);
+ puts("\n -- System halted\n");
+ while (1) /* wait forever */
+ ;
+}
+
+static int print_num(unsigned long num, int base)
+{
+ const char hex[] = "0123456789abcdef";
+ char str[40];
+ int i = sizeof(str)-1;
+
+ str[i--] = '\0';
+ do {
+ str[i--] = hex[num % base];
+ num = num / base;
+ } while (num);
+
+ if (base == 16) {
+ str[i--] = 'x';
+ str[i] = '0';
+ } else i++;
+ puts(&str[i]);
+
+ return 0;
+}
+
+static int printf(const char *fmt, ...)
+{
+ va_list args;
+ int i = 0;
+
+ va_start(args, fmt);
+
+ while (fmt[i]) {
+ if (fmt[i] != '%') {
+put:
+ putchar(fmt[i++]);
+ continue;
+ }
+
+ if (fmt[++i] == '%')
+ goto put;
+ print_num(va_arg(args, unsigned long),
+ fmt[i] == 'x' ? 16:10);
+ ++i;
+ }
+
+ va_end(args);
+ return 0;
+}
+
+/* helper functions for libgcc */
+void abort(void)
+{
+ error("aborted.");
+}
+
+#undef malloc
+static void *malloc(size_t size)
+{
+ return malloc_gzip(size);
+}
+
+#undef free
+static void free(void *ptr)
+{
+ return free_gzip(ptr);
+}
+
+
+static void flush_data_cache(char *start, unsigned long length)
+{
+ char *end = start + length;
+
+ do {
+ asm volatile("fdc 0(%0)" : : "r" (start));
+ asm volatile("fic 0(%%sr0,%0)" : : "r" (start));
+ start += 16;
+ } while (start < end);
+ asm volatile("fdc 0(%0)" : : "r" (end));
+
+ asm ("sync");
+}
+
+static void parse_elf(void *output)
+{
+#ifdef CONFIG_64BIT
+ Elf64_Ehdr ehdr;
+ Elf64_Phdr *phdrs, *phdr;
+#else
+ Elf32_Ehdr ehdr;
+ Elf32_Phdr *phdrs, *phdr;
+#endif
+ void *dest;
+ int i;
+
+ memcpy(&ehdr, output, sizeof(ehdr));
+ if (ehdr.e_ident[EI_MAG0] != ELFMAG0 ||
+ ehdr.e_ident[EI_MAG1] != ELFMAG1 ||
+ ehdr.e_ident[EI_MAG2] != ELFMAG2 ||
+ ehdr.e_ident[EI_MAG3] != ELFMAG3) {
+ error("Kernel is not a valid ELF file");
+ return;
+ }
+
+#ifdef DEBUG
+ printf("Parsing ELF... ");
+#endif
+
+ phdrs = malloc(sizeof(*phdrs) * ehdr.e_phnum);
+ if (!phdrs)
+ error("Failed to allocate space for phdrs");
+
+ memcpy(phdrs, output + ehdr.e_phoff, sizeof(*phdrs) * ehdr.e_phnum);
+
+ for (i = 0; i < ehdr.e_phnum; i++) {
+ phdr = &phdrs[i];
+
+ switch (phdr->p_type) {
+ case PT_LOAD:
+ dest = (void *)((unsigned long) phdr->p_paddr &
+ (__PAGE_OFFSET_DEFAULT-1));
+ memmove(dest, output + phdr->p_offset, phdr->p_filesz);
+ break;
+ default:
+ break;
+ }
+ }
+
+ free(phdrs);
+}
+
+asmlinkage unsigned long __visible decompress_kernel(unsigned int started_wide,
+ unsigned int command_line,
+ const unsigned int rd_start,
+ const unsigned int rd_end)
+{
+ char *output;
+ unsigned long vmlinux_addr, vmlinux_len;
+ unsigned long kernel_addr, kernel_len;
+
+#ifdef CONFIG_64BIT
+ parisc_narrow_firmware = 0;
+#endif
+
+ set_firmware_width_unlocked();
+
+ putchar('D'); /* if you get this D and no more, string storage */
+ /* in $GLOBAL$ is wrong or %dp is wrong */
+ puts("ecompressing Linux... ");
+
+ /* where the final bits are stored */
+ kernel_addr = KERNEL_BINARY_TEXT_START;
+ kernel_len = __pa(SZ_end) - __pa(SZparisc_kernel_start);
+ if ((unsigned long) &_startcode_end > kernel_addr)
+ error("Bootcode overlaps kernel code");
+
+ /*
+ * Calculate addr to where the vmlinux ELF file shall be decompressed.
+ * Assembly code in head.S positioned the stack directly behind bss, so
+ * leave 2 MB for the stack.
+ */
+ vmlinux_addr = (unsigned long) &_ebss + 2*1024*1024;
+ vmlinux_len = get_unaligned_le32(&output_len);
+ output = (char *) vmlinux_addr;
+
+ /*
+ * Initialize free_mem_ptr and free_mem_end_ptr.
+ */
+ free_mem_ptr = vmlinux_addr + vmlinux_len;
+
+ /* Limit memory for bootoader to 1GB */
+ #define ARTIFICIAL_LIMIT (1*1024*1024*1024)
+ free_mem_end_ptr = PAGE0->imm_max_mem;
+ if (free_mem_end_ptr > ARTIFICIAL_LIMIT)
+ free_mem_end_ptr = ARTIFICIAL_LIMIT;
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ /* if we have ramdisk this is at end of memory */
+ if (rd_start && rd_start < free_mem_end_ptr)
+ free_mem_end_ptr = rd_start;
+#endif
+
+ if (free_mem_ptr >= free_mem_end_ptr) {
+ int free_ram;
+ free_ram = (free_mem_ptr >> 20) + 1;
+ if (free_ram < 32)
+ free_ram = 32;
+ printf("\nKernel requires at least %d MB RAM.\n",
+ free_ram);
+ error(NULL);
+ }
+
+#ifdef DEBUG
+ printf("\n");
+ printf("startcode_end = %x\n", &_startcode_end);
+ printf("commandline = %x\n", command_line);
+ printf("rd_start = %x\n", rd_start);
+ printf("rd_end = %x\n", rd_end);
+
+ printf("free_ptr = %x\n", free_mem_ptr);
+ printf("free_ptr_end = %x\n", free_mem_end_ptr);
+
+ printf("input_data = %x\n", input_data);
+ printf("input_len = %x\n", input_len);
+ printf("output = %x\n", output);
+ printf("output_len = %x\n", vmlinux_len);
+ printf("kernel_addr = %x\n", kernel_addr);
+ printf("kernel_len = %x\n", kernel_len);
+#endif
+
+ __decompress(input_data, input_len, NULL, NULL,
+ output, 0, NULL, error);
+ parse_elf(output);
+
+ output = (char *) kernel_addr;
+ flush_data_cache(output, kernel_len);
+
+ printf("done.\nBooting the kernel.\n");
+
+ return (unsigned long) output;
+}
diff --git a/arch/parisc/boot/compressed/real2.S b/arch/parisc/boot/compressed/real2.S
new file mode 100644
index 000000000..cdc6a4da3
--- /dev/null
+++ b/arch/parisc/boot/compressed/real2.S
@@ -0,0 +1,2 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#include "../../kernel/real2.S"
diff --git a/arch/parisc/boot/compressed/vmlinux.lds.S b/arch/parisc/boot/compressed/vmlinux.lds.S
new file mode 100644
index 000000000..ab7b43990
--- /dev/null
+++ b/arch/parisc/boot/compressed/vmlinux.lds.S
@@ -0,0 +1,106 @@
+#include <asm-generic/vmlinux.lds.h>
+#include <asm/page.h>
+#include "sizes.h"
+
+#ifndef CONFIG_64BIT
+OUTPUT_FORMAT("elf32-hppa-linux")
+OUTPUT_ARCH(hppa)
+#else
+OUTPUT_FORMAT("elf64-hppa-linux")
+OUTPUT_ARCH(hppa:hppa2.0w)
+#endif
+
+ENTRY(startup)
+
+SECTIONS
+{
+ /* palo loads at 0x60000 */
+ /* loaded kernel will move to 0x10000 */
+ . = 0xe0000; /* should not overwrite palo code */
+
+ .head.text : {
+ _head = . ;
+ HEAD_TEXT
+ _ehead = . ;
+ }
+
+ /* keep __gp below 0x1000000 */
+#ifdef CONFIG_64BIT
+ . = ALIGN(16);
+ /* Linkage tables */
+ .opd : {
+ __start_opd = .;
+ *(.opd)
+ __end_opd = .;
+ } PROVIDE (__gp = .);
+ .plt : {
+ *(.plt)
+ }
+ .dlt : {
+ *(.dlt)
+ }
+#endif
+ _startcode_end = .;
+
+ /* vmlinux.bin.gz is here */
+ . = ALIGN(8);
+ .rodata.compressed : {
+ *(.rodata.compressed)
+ }
+
+ /* bootloader code and data starts at least behind area of extracted kernel */
+ . = MAX(ABSOLUTE(.), (SZ_end - SZparisc_kernel_start + KERNEL_BINARY_TEXT_START));
+
+ /* align on next page boundary */
+ . = ALIGN(4096);
+ .text : {
+ _text = .; /* Text */
+ *(.text)
+ *(.text.*)
+ _etext = . ;
+ }
+ . = ALIGN(8);
+ .data : {
+ _data = . ;
+ *(.data)
+ *(.data.*)
+ _edata = . ;
+ }
+ . = ALIGN(8);
+ .rodata : {
+ _rodata = . ;
+ *(.rodata) /* read-only data */
+ *(.rodata.*)
+ _erodata = . ;
+ }
+ . = ALIGN(8);
+ .bss : {
+ _bss = . ;
+ *(.bss)
+ *(.bss.*)
+ *(COMMON)
+ . = ALIGN(4096);
+ _ebss = .;
+ }
+
+ STABS_DEBUG
+ ELF_DETAILS
+ .note 0 : { *(.note) }
+
+ /* Sections to be discarded */
+ DISCARDS
+ /DISCARD/ : {
+#ifdef CONFIG_64BIT
+ /* temporary hack until binutils is fixed to not emit these
+ * for static binaries
+ */
+ *(.PARISC.unwind) /* no unwind data */
+ *(.interp)
+ *(.dynsym)
+ *(.dynstr)
+ *(.dynamic)
+ *(.hash)
+ *(.gnu.hash)
+#endif
+ }
+}
diff --git a/arch/parisc/boot/compressed/vmlinux.scr b/arch/parisc/boot/compressed/vmlinux.scr
new file mode 100644
index 000000000..dac2d142b
--- /dev/null
+++ b/arch/parisc/boot/compressed/vmlinux.scr
@@ -0,0 +1,10 @@
+SECTIONS
+{
+ .rodata.compressed : {
+ input_len = .;
+ LONG(input_data_end - input_data) input_data = .;
+ *(.data)
+ output_len = . - 4; /* can be at unaligned address */
+ input_data_end = .;
+ }
+}
diff --git a/arch/parisc/configs/generic-32bit_defconfig b/arch/parisc/configs/generic-32bit_defconfig
new file mode 100644
index 000000000..ee4febb30
--- /dev/null
+++ b/arch/parisc/configs/generic-32bit_defconfig
@@ -0,0 +1,281 @@
+CONFIG_LOCALVERSION="-32bit"
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=16
+CONFIG_CGROUPS=y
+CONFIG_NAMESPACES=y
+CONFIG_USER_NS=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_EXPERT=y
+CONFIG_PERF_EVENTS=y
+CONFIG_PA7100LC=y
+CONFIG_SMP=y
+CONFIG_HZ_100=y
+CONFIG_IOMMU_CCIO=y
+CONFIG_GSC_LASI=y
+CONFIG_GSC_WAX=y
+CONFIG_GSC_DINO=y
+CONFIG_PCI_LBA=y
+# CONFIG_PDC_CHASSIS is not set
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_BINFMT_MISC=m
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=m
+CONFIG_NET_KEY=m
+CONFIG_INET=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_DIAG=m
+CONFIG_LLC2=m
+# CONFIG_WIRELESS is not set
+CONFIG_EISA=y
+CONFIG_PCI=y
+CONFIG_PCCARD=m
+CONFIG_YENTA=m
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+# CONFIG_STANDALONE is not set
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+CONFIG_PARPORT=y
+CONFIG_PARPORT_PC=m
+CONFIG_PARPORT_1284=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_SIZE=6144
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_CHR_DEV_SG=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_SCSI_LASI700=y
+CONFIG_SCSI_SYM53C8XX_2=y
+CONFIG_SCSI_ZALON=y
+CONFIG_SCSI_DH=y
+CONFIG_ATA=y
+CONFIG_PATA_NS87415=y
+CONFIG_ATA_GENERIC=y
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID10=m
+CONFIG_MD_RAID456=m
+CONFIG_BLK_DEV_DM=y
+CONFIG_DM_UEVENT=y
+CONFIG_NETDEVICES=y
+CONFIG_BONDING=m
+CONFIG_DUMMY=m
+CONFIG_TUN=m
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NET_VENDOR_ADAPTEC is not set
+# CONFIG_NET_VENDOR_ALTEON is not set
+# CONFIG_NET_VENDOR_AMD is not set
+# CONFIG_NET_VENDOR_ATHEROS is not set
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CHELSIO is not set
+# CONFIG_NET_VENDOR_CISCO is not set
+CONFIG_NET_TULIP=y
+CONFIG_TULIP=y
+# CONFIG_NET_VENDOR_DLINK is not set
+# CONFIG_NET_VENDOR_EMULEX is not set
+CONFIG_LASI_82596=y
+# CONFIG_NET_VENDOR_MELLANOX is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_MYRI is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_NVIDIA is not set
+# CONFIG_NET_VENDOR_OKI is not set
+# CONFIG_NET_VENDOR_QLOGIC is not set
+# CONFIG_NET_VENDOR_BROCADE is not set
+# CONFIG_NET_VENDOR_RDC is not set
+# CONFIG_NET_VENDOR_REALTEK is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SILAN is not set
+# CONFIG_NET_VENDOR_SIS is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_NET_VENDOR_SUN is not set
+# CONFIG_NET_VENDOR_TEHUTI is not set
+# CONFIG_NET_VENDOR_TI is not set
+# CONFIG_NET_VENDOR_VIA is not set
+CONFIG_PPP=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPPOE=m
+# CONFIG_WLAN is not set
+CONFIG_KEYBOARD_HIL_OLD=m
+CONFIG_KEYBOARD_HIL=m
+CONFIG_MOUSE_SERIAL=y
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=m
+CONFIG_LEGACY_PTY_COUNT=64
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=8
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_PRINTER=m
+CONFIG_PPDEV=m
+# CONFIG_HW_RANDOM is not set
+CONFIG_I2C=y
+CONFIG_HWMON=m
+CONFIG_DRM=m
+CONFIG_DRM_DP_CEC=y
+# CONFIG_DRM_I2C_CH7006 is not set
+# CONFIG_DRM_I2C_SIL164 is not set
+CONFIG_DRM_RADEON=m
+CONFIG_DRM_NOUVEAU=m
+# CONFIG_DRM_NOUVEAU_BACKLIGHT is not set
+CONFIG_DRM_VGEM=m
+CONFIG_DRM_UDL=m
+CONFIG_DRM_MGAG200=m
+CONFIG_FB=y
+CONFIG_FB_FOREIGN_ENDIAN=y
+CONFIG_FB_PM2=m
+CONFIG_FB_PM2_FIFO_DISCONNECT=y
+CONFIG_FB_NVIDIA=m
+CONFIG_FB_NVIDIA_I2C=y
+# CONFIG_FB_NVIDIA_BACKLIGHT is not set
+CONFIG_FB_RIVA=m
+CONFIG_FB_RIVA_I2C=y
+# CONFIG_FB_RIVA_BACKLIGHT is not set
+CONFIG_FB_MATROX=m
+CONFIG_FB_MATROX_MILLENIUM=y
+CONFIG_FB_MATROX_MYSTIQUE=y
+CONFIG_FB_MATROX_G=y
+CONFIG_FB_MATROX_I2C=m
+CONFIG_FB_MATROX_MAVEN=m
+CONFIG_FB_ATY128=m
+# CONFIG_FB_ATY128_BACKLIGHT is not set
+CONFIG_FB_ATY=m
+CONFIG_FB_ATY_CT=y
+CONFIG_FB_ATY_GX=y
+# CONFIG_FB_ATY_BACKLIGHT is not set
+CONFIG_FB_S3=m
+CONFIG_FB_SAVAGE=m
+CONFIG_FB_SAVAGE_I2C=y
+CONFIG_FB_SAVAGE_ACCEL=y
+CONFIG_FB_SIS=m
+CONFIG_FB_SIS_300=y
+CONFIG_FB_SIS_315=y
+CONFIG_FB_VOODOO1=m
+CONFIG_FB_TRIDENT=m
+CONFIG_FB_SMSCUFX=m
+CONFIG_FB_UDL=m
+CONFIG_DUMMY_CONSOLE_COLUMNS=128
+CONFIG_DUMMY_CONSOLE_ROWS=48
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+# CONFIG_LOGO_LINUX_CLUT224 is not set
+CONFIG_SOUND=m
+CONFIG_SND=m
+CONFIG_SND_DYNAMIC_MINORS=y
+CONFIG_SND_SEQUENCER=m
+CONFIG_SND_AD1889=m
+CONFIG_SND_HARMONY=m
+CONFIG_HIDRAW=y
+CONFIG_HID_A4TECH=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_BELKIN=y
+CONFIG_HID_CHERRY=y
+CONFIG_HID_CHICONY=y
+CONFIG_HID_CYPRESS=y
+CONFIG_HID_DRAGONRISE=y
+CONFIG_HID_EZKEY=y
+CONFIG_HID_KYE=y
+CONFIG_HID_GYRATION=y
+CONFIG_HID_TWINHAN=y
+CONFIG_HID_KENSINGTON=y
+CONFIG_HID_LOGITECH=y
+CONFIG_HID_LOGITECH_DJ=m
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MONTEREY=y
+CONFIG_HID_NTRIG=y
+CONFIG_HID_ORTEK=y
+CONFIG_HID_PANTHERLORD=y
+CONFIG_HID_PETALYNX=y
+CONFIG_HID_SAMSUNG=y
+CONFIG_HID_SONY=y
+CONFIG_HID_SUNPLUS=y
+CONFIG_HID_GREENASIA=y
+CONFIG_HID_SMARTJOYPLUS=y
+CONFIG_HID_TOPSEED=y
+CONFIG_HID_THRUSTMASTER=y
+CONFIG_HID_ZEROPLUS=y
+CONFIG_USB=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+CONFIG_USB_MON=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_UHCI_HCD=y
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=y
+CONFIG_LEDS_TRIGGER_DISK=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
+CONFIG_DMADEVICES=y
+CONFIG_AUXDISPLAY=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_QUOTA=y
+CONFIG_QUOTA_NETLINK_INTERFACE=y
+CONFIG_QFMT_V2=y
+CONFIG_AUTOFS_FS=y
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+CONFIG_VFAT_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_XATTR=y
+CONFIG_NFS_FS=m
+# CONFIG_NFS_V2 is not set
+CONFIG_NFSD=m
+CONFIG_CIFS=m
+CONFIG_CIFS_XATTR=y
+CONFIG_CIFS_POSIX=y
+# CONFIG_CIFS_DEBUG is not set
+CONFIG_CRYPTO_TEST=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_DEFLATE=y
+CONFIG_CRC_CCITT=m
+CONFIG_CRC_T10DIF=y
+CONFIG_FONTS=y
+CONFIG_PRINTK_TIME=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DEBUG_STACKOVERFLOW=y
+CONFIG_DEBUG_SHIRQ=y
+CONFIG_DETECT_HUNG_TASK=y
+CONFIG_DEBUG_RT_MUTEXES=y
+CONFIG_DEBUG_SPINLOCK=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_LATENCYTOP=y
+CONFIG_LKDTM=m
diff --git a/arch/parisc/configs/generic-64bit_defconfig b/arch/parisc/configs/generic-64bit_defconfig
new file mode 100644
index 000000000..f6ded7147
--- /dev/null
+++ b/arch/parisc/configs/generic-64bit_defconfig
@@ -0,0 +1,305 @@
+CONFIG_LOCALVERSION="-64bit"
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_KERNEL_LZ4=y
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_AUDIT=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+CONFIG_TASKSTATS=y
+CONFIG_TASK_DELAY_ACCT=y
+CONFIG_TASK_XACCT=y
+CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_CGROUPS=y
+CONFIG_MEMCG=y
+CONFIG_CGROUP_PIDS=y
+CONFIG_CPUSETS=y
+CONFIG_USER_NS=y
+CONFIG_RELAY=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SMP=y
+CONFIG_HPPB=y
+CONFIG_IOMMU_CCIO=y
+CONFIG_GSC_LASI=y
+CONFIG_GSC_WAX=y
+CONFIG_GSC_DINO=y
+CONFIG_PCI_LBA=y
+CONFIG_MODULES=y
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_BLK_DEV_INTEGRITY=y
+CONFIG_BINFMT_MISC=m
+# CONFIG_COMPAT_BRK is not set
+# CONFIG_COMPACTION is not set
+CONFIG_MEMORY_FAILURE=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_XFRM_USER=m
+CONFIG_XFRM_SUB_POLICY=y
+CONFIG_XFRM_MIGRATE=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_PNP=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_DIAG=m
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_ADVANCED is not set
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_DCB=y
+# CONFIG_WIRELESS is not set
+CONFIG_PCI=y
+CONFIG_PCI_STUB=m
+CONFIG_PCI_IOV=y
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_SCSI_PROC_FS is not set
+CONFIG_BLK_DEV_SD=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_SCSI_ISCSI_ATTRS=y
+CONFIG_SCSI_SRP_ATTRS=y
+CONFIG_ISCSI_BOOT_SYSFS=y
+CONFIG_SCSI_MPT2SAS=y
+CONFIG_SCSI_LASI700=y
+CONFIG_SCSI_SYM53C8XX_2=y
+CONFIG_SCSI_ZALON=y
+CONFIG_SCSI_QLA_ISCSI=m
+CONFIG_SCSI_DH=y
+CONFIG_ATA=y
+CONFIG_SATA_SIL=y
+CONFIG_SATA_SIS=y
+CONFIG_SATA_VIA=y
+CONFIG_PATA_NS87415=y
+CONFIG_PATA_SIL680=y
+CONFIG_ATA_GENERIC=y
+CONFIG_MD=y
+CONFIG_MD_LINEAR=m
+CONFIG_BLK_DEV_DM=m
+CONFIG_DM_RAID=m
+CONFIG_DM_UEVENT=y
+CONFIG_DM_AUDIT=y
+CONFIG_FUSION=y
+CONFIG_FUSION_SPI=y
+CONFIG_FUSION_SAS=y
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+CONFIG_MACVLAN=m
+CONFIG_MACVTAP=m
+CONFIG_NETCONSOLE=m
+CONFIG_NETCONSOLE_DYNAMIC=y
+CONFIG_TUN=y
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NET_VENDOR_ADAPTEC is not set
+# CONFIG_NET_VENDOR_ALTEON is not set
+# CONFIG_NET_VENDOR_AMD is not set
+# CONFIG_NET_VENDOR_ATHEROS is not set
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CHELSIO is not set
+# CONFIG_NET_VENDOR_CISCO is not set
+CONFIG_NET_TULIP=y
+CONFIG_TULIP=y
+# CONFIG_NET_VENDOR_DLINK is not set
+# CONFIG_NET_VENDOR_EMULEX is not set
+CONFIG_LASI_82596=y
+CONFIG_E1000=y
+# CONFIG_NET_VENDOR_MARVELL is not set
+# CONFIG_NET_VENDOR_MELLANOX is not set
+# CONFIG_NET_VENDOR_MICREL is not set
+# CONFIG_NET_VENDOR_MYRI is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_NVIDIA is not set
+# CONFIG_NET_VENDOR_OKI is not set
+CONFIG_QLA3XXX=m
+CONFIG_QLCNIC=m
+# CONFIG_NET_VENDOR_BROCADE is not set
+# CONFIG_NET_VENDOR_RDC is not set
+# CONFIG_NET_VENDOR_REALTEK is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
+# CONFIG_NET_VENDOR_SILAN is not set
+# CONFIG_NET_VENDOR_SIS is not set
+# CONFIG_NET_VENDOR_SMSC is not set
+# CONFIG_NET_VENDOR_STMICRO is not set
+# CONFIG_NET_VENDOR_SUN is not set
+# CONFIG_NET_VENDOR_TEHUTI is not set
+# CONFIG_NET_VENDOR_TI is not set
+# CONFIG_NET_VENDOR_VIA is not set
+# CONFIG_NET_VENDOR_WIZNET is not set
+CONFIG_PHYLIB=y
+CONFIG_BROADCOM_PHY=m
+CONFIG_CICADA_PHY=m
+CONFIG_DAVICOM_PHY=m
+CONFIG_ICPLUS_PHY=m
+CONFIG_LXT_PHY=m
+CONFIG_LSI_ET1011C_PHY=m
+CONFIG_MARVELL_PHY=m
+CONFIG_NATIONAL_PHY=m
+CONFIG_QSEMI_PHY=m
+CONFIG_REALTEK_PHY=m
+CONFIG_SMSC_PHY=m
+CONFIG_STE10XP=m
+CONFIG_VITESSE_PHY=m
+CONFIG_MDIO_BITBANG=m
+CONFIG_SLIP=m
+# CONFIG_WLAN is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_KEYBOARD_HIL_OLD is not set
+# CONFIG_KEYBOARD_HIL is not set
+# CONFIG_MOUSE_PS2 is not set
+CONFIG_INPUT_MISC=y
+CONFIG_SERIO_SERPORT=m
+# CONFIG_HP_SDC is not set
+CONFIG_SERIO_RAW=m
+# CONFIG_LEGACY_PTYS is not set
+CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=8
+CONFIG_SERIAL_8250_RUNTIME_UARTS=8
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_JSM=m
+CONFIG_NOZOMI=m
+CONFIG_IPMI_HANDLER=y
+CONFIG_IPMI_DEVICE_INTERFACE=y
+CONFIG_IPMI_SI=y
+# CONFIG_HW_RANDOM is not set
+CONFIG_TCG_TPM=m
+CONFIG_TCG_ATMEL=m
+CONFIG_PTP_1588_CLOCK=m
+CONFIG_SENSORS_I5K_AMB=m
+CONFIG_SENSORS_F71882FG=m
+CONFIG_SENSORS_PC87427=m
+CONFIG_SENSORS_VT1211=m
+CONFIG_SENSORS_VT8231=m
+CONFIG_SENSORS_W83627EHF=m
+CONFIG_WATCHDOG=y
+CONFIG_SOFT_WATCHDOG=m
+CONFIG_SSB=m
+CONFIG_SSB_DRIVER_PCICORE=y
+CONFIG_LPC_SCH=m
+CONFIG_MFD_SM501=m
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=m
+CONFIG_REGULATOR_USERSPACE_CONSUMER=m
+CONFIG_MEDIA_SUPPORT=m
+CONFIG_AGP=y
+CONFIG_AGP_PARISC=y
+CONFIG_DRM=y
+# CONFIG_DRM_I2C_CH7006 is not set
+# CONFIG_DRM_I2C_SIL164 is not set
+CONFIG_DRM_RADEON=y
+CONFIG_DRM_NOUVEAU=m
+# CONFIG_DRM_NOUVEAU_BACKLIGHT is not set
+CONFIG_DRM_MGAG200=m
+CONFIG_FB=y
+CONFIG_FB_PM2=m
+CONFIG_FB_PM2_FIFO_DISCONNECT=y
+CONFIG_FB_NVIDIA=m
+CONFIG_FB_NVIDIA_I2C=y
+# CONFIG_FB_NVIDIA_BACKLIGHT is not set
+CONFIG_FB_RIVA=m
+CONFIG_FB_RIVA_I2C=y
+# CONFIG_FB_RIVA_BACKLIGHT is not set
+CONFIG_FB_MATROX=m
+CONFIG_FB_MATROX_MILLENIUM=y
+CONFIG_FB_MATROX_MYSTIQUE=y
+CONFIG_FB_MATROX_G=y
+CONFIG_FB_MATROX_I2C=m
+CONFIG_FB_MATROX_MAVEN=m
+CONFIG_FB_RADEON=y
+# CONFIG_FB_RADEON_BACKLIGHT is not set
+CONFIG_FB_ATY128=m
+# CONFIG_FB_ATY128_BACKLIGHT is not set
+CONFIG_FB_ATY=m
+CONFIG_FB_ATY_CT=y
+CONFIG_FB_ATY_GX=y
+# CONFIG_FB_ATY_BACKLIGHT is not set
+CONFIG_FB_S3=m
+CONFIG_FB_SAVAGE=m
+CONFIG_FB_SAVAGE_I2C=y
+CONFIG_FB_SAVAGE_ACCEL=y
+CONFIG_FB_SIS=m
+CONFIG_FB_SIS_300=y
+CONFIG_FB_SIS_315=y
+CONFIG_FB_VOODOO1=m
+CONFIG_FB_TRIDENT=m
+CONFIG_FB_SMSCUFX=m
+CONFIG_FB_UDL=m
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_CLUT224 is not set
+CONFIG_HIDRAW=y
+CONFIG_HID_PID=y
+CONFIG_USB_HIDDEV=y
+CONFIG_USB=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PLATFORM=y
+CONFIG_UIO=y
+CONFIG_UIO_PDRV_GENIRQ=m
+CONFIG_UIO_AEC=m
+CONFIG_UIO_SERCOS3=m
+CONFIG_UIO_PCI_GENERIC=m
+CONFIG_STAGING=y
+CONFIG_QLGE=m
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_SECURITY=y
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_XFS_FS=m
+CONFIG_BTRFS_FS=m
+CONFIG_QUOTA=y
+CONFIG_QUOTA_NETLINK_INTERFACE=y
+CONFIG_QFMT_V2=y
+CONFIG_AUTOFS_FS=y
+CONFIG_FUSE_FS=y
+CONFIG_CUSE=y
+CONFIG_ISO9660_FS=y
+CONFIG_UDF_FS=y
+CONFIG_VFAT_FS=m
+CONFIG_PROC_KCORE=y
+CONFIG_TMPFS=y
+CONFIG_TMPFS_XATTR=y
+CONFIG_CONFIGFS_FS=y
+CONFIG_SYSV_FS=y
+CONFIG_NFS_FS=m
+CONFIG_NFS_V4=m
+CONFIG_NFS_V4_1=y
+CONFIG_NFSD=m
+CONFIG_NFSD_V4=y
+CONFIG_NLS_DEFAULT="utf8"
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_UTF8=m
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_FCRYPT=m
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_DEFLATE=m
+# CONFIG_CRYPTO_HW is not set
+CONFIG_CRC_CCITT=m
+CONFIG_LIBCRC32C=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_STRIP_ASM_SYMS=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_FS=y
+CONFIG_DEBUG_STACKOVERFLOW=y
+# CONFIG_SCHED_DEBUG is not set
diff --git a/arch/parisc/defpalo.conf b/arch/parisc/defpalo.conf
new file mode 100644
index 000000000..208ff3b41
--- /dev/null
+++ b/arch/parisc/defpalo.conf
@@ -0,0 +1,21 @@
+# This a generic Palo configuration file. For more information about how
+# it works try 'palo -?'.
+#
+# Most people using 'make palo' want a bootable file, usable for
+# network or tape booting for example.
+--init-tape=lifimage
+--recoverykernel=vmlinuz
+
+########## Pick your ROOT here! ##########
+# You need at least one 'root='!
+#
+# If you want a root ramdisk, use the next 2 lines
+# (Edit the ramdisk image name!!!!)
+--ramdisk=ram-disk-image-file
+--commandline=0/vmlinuz HOME=/ root=/dev/ram initrd=0/ramdisk panic_timeout=60 panic=-1
+
+# If you want NFS root, use the following command line (Edit the HOSTNAME!!!)
+#--commandline=0/vmlinuz HOME=/ root=/dev/nfs nfsroot=HOSTNAME ip=bootp
+
+# If you have root on a disk partition, use this (Edit the partition name!!!)
+#--commandline=0/vmlinuz HOME=/ root=/dev/sda1
diff --git a/arch/parisc/include/asm/Kbuild b/arch/parisc/include/asm/Kbuild
new file mode 100644
index 000000000..4fb596d94
--- /dev/null
+++ b/arch/parisc/include/asm/Kbuild
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+generated-y += syscall_table_32.h
+generated-y += syscall_table_64.h
+generic-y += agp.h
+generic-y += kvm_para.h
+generic-y += mcs_spinlock.h
+generic-y += user.h
diff --git a/arch/parisc/include/asm/alternative.h b/arch/parisc/include/asm/alternative.h
new file mode 100644
index 000000000..1eb488f25
--- /dev/null
+++ b/arch/parisc/include/asm/alternative.h
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_PARISC_ALTERNATIVE_H
+#define __ASM_PARISC_ALTERNATIVE_H
+
+#define ALT_COND_ALWAYS 0x80 /* always replace instruction */
+#define ALT_COND_NO_SMP 0x01 /* when running UP instead of SMP */
+#define ALT_COND_NO_DCACHE 0x02 /* if system has no d-cache */
+#define ALT_COND_NO_ICACHE 0x04 /* if system has no i-cache */
+#define ALT_COND_NO_SPLIT_TLB 0x08 /* if split_tlb == 0 */
+#define ALT_COND_NO_IOC_FDC 0x10 /* if I/O cache does not need flushes */
+#define ALT_COND_RUN_ON_QEMU 0x20 /* if running on QEMU */
+
+#define INSN_PxTLB 0x02 /* modify pdtlb, pitlb */
+#define INSN_NOP 0x08000240 /* nop */
+
+#ifndef __ASSEMBLY__
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/stddef.h>
+#include <linux/stringify.h>
+
+struct alt_instr {
+ s32 orig_offset; /* offset to original instructions */
+ s16 len; /* end of original instructions */
+ u16 cond; /* see ALT_COND_XXX */
+ u32 replacement; /* replacement instruction or code */
+} __packed;
+
+void set_kernel_text_rw(int enable_read_write);
+void apply_alternatives_all(void);
+void apply_alternatives(struct alt_instr *start, struct alt_instr *end,
+ const char *module_name);
+
+/* Alternative SMP implementation. */
+#define ALTERNATIVE(cond, replacement) "!0:" \
+ ".section .altinstructions, \"a\" !" \
+ ".align 4 !" \
+ ".word (0b-4-.) !" \
+ ".hword 1, " __stringify(cond) " !" \
+ ".word " __stringify(replacement) " !" \
+ ".previous"
+
+#else
+
+/* to replace one single instructions by a new instruction */
+#define ALTERNATIVE(from, to, cond, replacement)\
+ .section .altinstructions, "a" ! \
+ .align 4 ! \
+ .word (from - .) ! \
+ .hword (to - from)/4, cond ! \
+ .word replacement ! \
+ .previous
+
+/* to replace multiple instructions by new code */
+#define ALTERNATIVE_CODE(from, num_instructions, cond, new_instr_ptr)\
+ .section .altinstructions, "a" ! \
+ .align 4 ! \
+ .word (from - .) ! \
+ .hword -num_instructions, cond ! \
+ .word (new_instr_ptr - .) ! \
+ .previous
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __ASM_PARISC_ALTERNATIVE_H */
diff --git a/arch/parisc/include/asm/asm-offsets.h b/arch/parisc/include/asm/asm-offsets.h
new file mode 100644
index 000000000..d370ee36a
--- /dev/null
+++ b/arch/parisc/include/asm/asm-offsets.h
@@ -0,0 +1 @@
+#include <generated/asm-offsets.h>
diff --git a/arch/parisc/include/asm/asmregs.h b/arch/parisc/include/asm/asmregs.h
new file mode 100644
index 000000000..81d8029d8
--- /dev/null
+++ b/arch/parisc/include/asm/asmregs.h
@@ -0,0 +1,170 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 1999 Hewlett-Packard (Frank Rowand)
+ */
+
+#ifndef _PARISC_ASMREGS_H
+#define _PARISC_ASMREGS_H
+
+;! General Registers
+
+rp: .reg %r2
+arg3: .reg %r23
+arg2: .reg %r24
+arg1: .reg %r25
+arg0: .reg %r26
+dp: .reg %r27
+ret0: .reg %r28
+ret1: .reg %r29
+sl: .reg %r29
+sp: .reg %r30
+
+#if 0
+/* PA20_REVISIT */
+arg7: .reg r19
+arg6: .reg r20
+arg5: .reg r21
+arg4: .reg r22
+gp: .reg r27
+ap: .reg r29
+#endif
+
+
+r0: .reg %r0
+r1: .reg %r1
+r2: .reg %r2
+r3: .reg %r3
+r4: .reg %r4
+r5: .reg %r5
+r6: .reg %r6
+r7: .reg %r7
+r8: .reg %r8
+r9: .reg %r9
+r10: .reg %r10
+r11: .reg %r11
+r12: .reg %r12
+r13: .reg %r13
+r14: .reg %r14
+r15: .reg %r15
+r16: .reg %r16
+r17: .reg %r17
+r18: .reg %r18
+r19: .reg %r19
+r20: .reg %r20
+r21: .reg %r21
+r22: .reg %r22
+r23: .reg %r23
+r24: .reg %r24
+r25: .reg %r25
+r26: .reg %r26
+r27: .reg %r27
+r28: .reg %r28
+r29: .reg %r29
+r30: .reg %r30
+r31: .reg %r31
+
+
+;! Space Registers
+
+sr0: .reg %sr0
+sr1: .reg %sr1
+sr2: .reg %sr2
+sr3: .reg %sr3
+sr4: .reg %sr4
+sr5: .reg %sr5
+sr6: .reg %sr6
+sr7: .reg %sr7
+
+
+;! Floating Point Registers
+
+fr0: .reg %fr0
+fr1: .reg %fr1
+fr2: .reg %fr2
+fr3: .reg %fr3
+fr4: .reg %fr4
+fr5: .reg %fr5
+fr6: .reg %fr6
+fr7: .reg %fr7
+fr8: .reg %fr8
+fr9: .reg %fr9
+fr10: .reg %fr10
+fr11: .reg %fr11
+fr12: .reg %fr12
+fr13: .reg %fr13
+fr14: .reg %fr14
+fr15: .reg %fr15
+fr16: .reg %fr16
+fr17: .reg %fr17
+fr18: .reg %fr18
+fr19: .reg %fr19
+fr20: .reg %fr20
+fr21: .reg %fr21
+fr22: .reg %fr22
+fr23: .reg %fr23
+fr24: .reg %fr24
+fr25: .reg %fr25
+fr26: .reg %fr26
+fr27: .reg %fr27
+fr28: .reg %fr28
+fr29: .reg %fr29
+fr30: .reg %fr30
+fr31: .reg %fr31
+
+
+;! Control Registers
+
+rctr: .reg %cr0
+pidr1: .reg %cr8
+pidr2: .reg %cr9
+ccr: .reg %cr10
+sar: .reg %cr11
+pidr3: .reg %cr12
+pidr4: .reg %cr13
+iva: .reg %cr14
+eiem: .reg %cr15
+itmr: .reg %cr16
+pcsq: .reg %cr17
+pcoq: .reg %cr18
+iir: .reg %cr19
+isr: .reg %cr20
+ior: .reg %cr21
+ipsw: .reg %cr22
+eirr: .reg %cr23
+tr0: .reg %cr24
+tr1: .reg %cr25
+tr2: .reg %cr26
+tr3: .reg %cr27
+tr4: .reg %cr28
+tr5: .reg %cr29
+tr6: .reg %cr30
+tr7: .reg %cr31
+
+
+cr0: .reg %cr0
+cr8: .reg %cr8
+cr9: .reg %cr9
+cr10: .reg %cr10
+cr11: .reg %cr11
+cr12: .reg %cr12
+cr13: .reg %cr13
+cr14: .reg %cr14
+cr15: .reg %cr15
+cr16: .reg %cr16
+cr17: .reg %cr17
+cr18: .reg %cr18
+cr19: .reg %cr19
+cr20: .reg %cr20
+cr21: .reg %cr21
+cr22: .reg %cr22
+cr23: .reg %cr23
+cr24: .reg %cr24
+cr25: .reg %cr25
+cr26: .reg %cr26
+cr27: .reg %cr27
+cr28: .reg %cr28
+cr29: .reg %cr29
+cr30: .reg %cr30
+cr31: .reg %cr31
+
+#endif
diff --git a/arch/parisc/include/asm/assembly.h b/arch/parisc/include/asm/assembly.h
new file mode 100644
index 000000000..74d17d7e7
--- /dev/null
+++ b/arch/parisc/include/asm/assembly.h
@@ -0,0 +1,583 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 1999 Hewlett-Packard (Frank Rowand)
+ * Copyright (C) 1999 Philipp Rumpf <prumpf@tux.org>
+ * Copyright (C) 1999 SuSE GmbH
+ * Copyright (C) 2021 Helge Deller <deller@gmx.de>
+ */
+
+#ifndef _PARISC_ASSEMBLY_H
+#define _PARISC_ASSEMBLY_H
+
+#ifdef CONFIG_64BIT
+#define RP_OFFSET 16
+#define FRAME_SIZE 128
+#define CALLEE_REG_FRAME_SIZE 144
+#define REG_SZ 8
+#define ASM_ULONG_INSN .dword
+#else /* CONFIG_64BIT */
+#define RP_OFFSET 20
+#define FRAME_SIZE 64
+#define CALLEE_REG_FRAME_SIZE 128
+#define REG_SZ 4
+#define ASM_ULONG_INSN .word
+#endif
+
+/* Frame alignment for 32- and 64-bit */
+#define FRAME_ALIGN 64
+
+#define CALLEE_FLOAT_FRAME_SIZE 80
+#define CALLEE_SAVE_FRAME_SIZE (CALLEE_REG_FRAME_SIZE + CALLEE_FLOAT_FRAME_SIZE)
+
+#ifdef CONFIG_PA20
+#define LDCW ldcw,co
+#define BL b,l
+# ifdef CONFIG_64BIT
+# define PA_ASM_LEVEL 2.0w
+# else
+# define PA_ASM_LEVEL 2.0
+# endif
+#else
+#define LDCW ldcw
+#define BL bl
+#define PA_ASM_LEVEL 1.1
+#endif
+
+/* Privilege level field in the rightmost two bits of the IA queues */
+#define PRIV_USER 3
+#define PRIV_KERNEL 0
+
+/* Space register used inside kernel */
+#define SR_KERNEL 0
+#define SR_TEMP1 1
+#define SR_TEMP2 2
+#define SR_USER 3
+
+#ifdef __ASSEMBLY__
+
+#ifdef CONFIG_64BIT
+#define LDREG ldd
+#define STREG std
+#define LDREGX ldd,s
+#define LDREGM ldd,mb
+#define STREGM std,ma
+#define SHRREG shrd
+#define SHLREG shld
+#define ANDCM andcm,*
+#define COND(x) * ## x
+#else /* CONFIG_64BIT */
+#define LDREG ldw
+#define STREG stw
+#define LDREGX ldwx,s
+#define LDREGM ldwm
+#define STREGM stwm
+#define SHRREG shr
+#define SHLREG shlw
+#define ANDCM andcm
+#define COND(x) x
+#endif
+
+#ifdef CONFIG_64BIT
+/* the 64-bit pa gnu assembler unfortunately defaults to .level 1.1 or 2.0 so
+ * work around that for now... */
+ .level 2.0w
+#endif
+
+#include <asm/asm-offsets.h>
+#include <asm/page.h>
+#include <asm/types.h>
+
+#include <asm/asmregs.h>
+#include <asm/psw.h>
+
+ /*
+ * We provide two versions of each macro to convert from physical
+ * to virtual and vice versa. The "_r1" versions take one argument
+ * register, but trashes r1 to do the conversion. The other
+ * version takes two arguments: a src and destination register.
+ * However, the source and destination registers can not be
+ * the same register.
+ */
+
+ .macro tophys grvirt, grphys
+ ldil L%(__PAGE_OFFSET), \grphys
+ sub \grvirt, \grphys, \grphys
+ .endm
+
+ .macro tovirt grphys, grvirt
+ ldil L%(__PAGE_OFFSET), \grvirt
+ add \grphys, \grvirt, \grvirt
+ .endm
+
+ .macro tophys_r1 gr
+ ldil L%(__PAGE_OFFSET), %r1
+ sub \gr, %r1, \gr
+ .endm
+
+ .macro tovirt_r1 gr
+ ldil L%(__PAGE_OFFSET), %r1
+ add \gr, %r1, \gr
+ .endm
+
+ .macro delay value
+ ldil L%\value, 1
+ ldo R%\value(1), 1
+ addib,UV,n -1,1,.
+ addib,NUV,n -1,1,.+8
+ nop
+ .endm
+
+ .macro debug value
+ .endm
+
+ .macro shlw r, sa, t
+ zdep \r, 31-(\sa), 32-(\sa), \t
+ .endm
+
+ /* And the PA 2.0W shift left */
+ .macro shld r, sa, t
+ depd,z \r, 63-(\sa), 64-(\sa), \t
+ .endm
+
+ /* Shift Right for 32-bit. Clobbers upper 32-bit on PA2.0. */
+ .macro shr r, sa, t
+ extru \r, 31-(\sa), 32-(\sa), \t
+ .endm
+
+ /* pa20w version of shift right */
+ .macro shrd r, sa, t
+ extrd,u \r, 63-(\sa), 64-(\sa), \t
+ .endm
+
+ /* Extract unsigned for 32- and 64-bit
+ * The extru instruction leaves the most significant 32 bits of the
+ * target register in an undefined state on PA 2.0 systems. */
+ .macro extru_safe r, p, len, t
+#ifdef CONFIG_64BIT
+ extrd,u \r, 32+(\p), \len, \t
+#else
+ extru \r, \p, \len, \t
+#endif
+ .endm
+
+ /* The depi instruction leaves the most significant 32 bits of the
+ * target register in an undefined state on PA 2.0 systems. */
+ .macro depi_safe i, p, len, t
+#ifdef CONFIG_64BIT
+ depdi \i, 32+(\p), \len, \t
+#else
+ depi \i, \p, \len, \t
+#endif
+ .endm
+
+ /* The depw instruction leaves the most significant 32 bits of the
+ * target register in an undefined state on PA 2.0 systems. */
+ .macro dep_safe i, p, len, t
+#ifdef CONFIG_64BIT
+ depd \i, 32+(\p), \len, \t
+#else
+ depw \i, \p, \len, \t
+#endif
+ .endm
+
+ /* load 32-bit 'value' into 'reg' compensating for the ldil
+ * sign-extension when running in wide mode.
+ * WARNING!! neither 'value' nor 'reg' can be expressions
+ * containing '.'!!!! */
+ .macro load32 value, reg
+ ldil L%\value, \reg
+ ldo R%\value(\reg), \reg
+ .endm
+
+ .macro loadgp
+#ifdef CONFIG_64BIT
+ ldil L%__gp, %r27
+ ldo R%__gp(%r27), %r27
+#else
+ ldil L%$global$, %r27
+ ldo R%$global$(%r27), %r27
+#endif
+ .endm
+
+#define SAVE_SP(r, where) mfsp r, %r1 ! STREG %r1, where
+#define REST_SP(r, where) LDREG where, %r1 ! mtsp %r1, r
+#define SAVE_CR(r, where) mfctl r, %r1 ! STREG %r1, where
+#define REST_CR(r, where) LDREG where, %r1 ! mtctl %r1, r
+
+ .macro save_general regs
+ STREG %r1, PT_GR1 (\regs)
+ STREG %r2, PT_GR2 (\regs)
+ STREG %r3, PT_GR3 (\regs)
+ STREG %r4, PT_GR4 (\regs)
+ STREG %r5, PT_GR5 (\regs)
+ STREG %r6, PT_GR6 (\regs)
+ STREG %r7, PT_GR7 (\regs)
+ STREG %r8, PT_GR8 (\regs)
+ STREG %r9, PT_GR9 (\regs)
+ STREG %r10, PT_GR10(\regs)
+ STREG %r11, PT_GR11(\regs)
+ STREG %r12, PT_GR12(\regs)
+ STREG %r13, PT_GR13(\regs)
+ STREG %r14, PT_GR14(\regs)
+ STREG %r15, PT_GR15(\regs)
+ STREG %r16, PT_GR16(\regs)
+ STREG %r17, PT_GR17(\regs)
+ STREG %r18, PT_GR18(\regs)
+ STREG %r19, PT_GR19(\regs)
+ STREG %r20, PT_GR20(\regs)
+ STREG %r21, PT_GR21(\regs)
+ STREG %r22, PT_GR22(\regs)
+ STREG %r23, PT_GR23(\regs)
+ STREG %r24, PT_GR24(\regs)
+ STREG %r25, PT_GR25(\regs)
+ /* r26 is saved in get_stack and used to preserve a value across virt_map */
+ STREG %r27, PT_GR27(\regs)
+ STREG %r28, PT_GR28(\regs)
+ /* r29 is saved in get_stack and used to point to saved registers */
+ /* r30 stack pointer saved in get_stack */
+ STREG %r31, PT_GR31(\regs)
+ .endm
+
+ .macro rest_general regs
+ /* r1 used as a temp in rest_stack and is restored there */
+ LDREG PT_GR2 (\regs), %r2
+ LDREG PT_GR3 (\regs), %r3
+ LDREG PT_GR4 (\regs), %r4
+ LDREG PT_GR5 (\regs), %r5
+ LDREG PT_GR6 (\regs), %r6
+ LDREG PT_GR7 (\regs), %r7
+ LDREG PT_GR8 (\regs), %r8
+ LDREG PT_GR9 (\regs), %r9
+ LDREG PT_GR10(\regs), %r10
+ LDREG PT_GR11(\regs), %r11
+ LDREG PT_GR12(\regs), %r12
+ LDREG PT_GR13(\regs), %r13
+ LDREG PT_GR14(\regs), %r14
+ LDREG PT_GR15(\regs), %r15
+ LDREG PT_GR16(\regs), %r16
+ LDREG PT_GR17(\regs), %r17
+ LDREG PT_GR18(\regs), %r18
+ LDREG PT_GR19(\regs), %r19
+ LDREG PT_GR20(\regs), %r20
+ LDREG PT_GR21(\regs), %r21
+ LDREG PT_GR22(\regs), %r22
+ LDREG PT_GR23(\regs), %r23
+ LDREG PT_GR24(\regs), %r24
+ LDREG PT_GR25(\regs), %r25
+ LDREG PT_GR26(\regs), %r26
+ LDREG PT_GR27(\regs), %r27
+ LDREG PT_GR28(\regs), %r28
+ /* r29 points to register save area, and is restored in rest_stack */
+ /* r30 stack pointer restored in rest_stack */
+ LDREG PT_GR31(\regs), %r31
+ .endm
+
+ .macro save_fp regs
+ fstd,ma %fr0, 8(\regs)
+ fstd,ma %fr1, 8(\regs)
+ fstd,ma %fr2, 8(\regs)
+ fstd,ma %fr3, 8(\regs)
+ fstd,ma %fr4, 8(\regs)
+ fstd,ma %fr5, 8(\regs)
+ fstd,ma %fr6, 8(\regs)
+ fstd,ma %fr7, 8(\regs)
+ fstd,ma %fr8, 8(\regs)
+ fstd,ma %fr9, 8(\regs)
+ fstd,ma %fr10, 8(\regs)
+ fstd,ma %fr11, 8(\regs)
+ fstd,ma %fr12, 8(\regs)
+ fstd,ma %fr13, 8(\regs)
+ fstd,ma %fr14, 8(\regs)
+ fstd,ma %fr15, 8(\regs)
+ fstd,ma %fr16, 8(\regs)
+ fstd,ma %fr17, 8(\regs)
+ fstd,ma %fr18, 8(\regs)
+ fstd,ma %fr19, 8(\regs)
+ fstd,ma %fr20, 8(\regs)
+ fstd,ma %fr21, 8(\regs)
+ fstd,ma %fr22, 8(\regs)
+ fstd,ma %fr23, 8(\regs)
+ fstd,ma %fr24, 8(\regs)
+ fstd,ma %fr25, 8(\regs)
+ fstd,ma %fr26, 8(\regs)
+ fstd,ma %fr27, 8(\regs)
+ fstd,ma %fr28, 8(\regs)
+ fstd,ma %fr29, 8(\regs)
+ fstd,ma %fr30, 8(\regs)
+ fstd %fr31, 0(\regs)
+ .endm
+
+ .macro rest_fp regs
+ fldd 0(\regs), %fr31
+ fldd,mb -8(\regs), %fr30
+ fldd,mb -8(\regs), %fr29
+ fldd,mb -8(\regs), %fr28
+ fldd,mb -8(\regs), %fr27
+ fldd,mb -8(\regs), %fr26
+ fldd,mb -8(\regs), %fr25
+ fldd,mb -8(\regs), %fr24
+ fldd,mb -8(\regs), %fr23
+ fldd,mb -8(\regs), %fr22
+ fldd,mb -8(\regs), %fr21
+ fldd,mb -8(\regs), %fr20
+ fldd,mb -8(\regs), %fr19
+ fldd,mb -8(\regs), %fr18
+ fldd,mb -8(\regs), %fr17
+ fldd,mb -8(\regs), %fr16
+ fldd,mb -8(\regs), %fr15
+ fldd,mb -8(\regs), %fr14
+ fldd,mb -8(\regs), %fr13
+ fldd,mb -8(\regs), %fr12
+ fldd,mb -8(\regs), %fr11
+ fldd,mb -8(\regs), %fr10
+ fldd,mb -8(\regs), %fr9
+ fldd,mb -8(\regs), %fr8
+ fldd,mb -8(\regs), %fr7
+ fldd,mb -8(\regs), %fr6
+ fldd,mb -8(\regs), %fr5
+ fldd,mb -8(\regs), %fr4
+ fldd,mb -8(\regs), %fr3
+ fldd,mb -8(\regs), %fr2
+ fldd,mb -8(\regs), %fr1
+ fldd,mb -8(\regs), %fr0
+ .endm
+
+ .macro callee_save_float
+ fstd,ma %fr12, 8(%r30)
+ fstd,ma %fr13, 8(%r30)
+ fstd,ma %fr14, 8(%r30)
+ fstd,ma %fr15, 8(%r30)
+ fstd,ma %fr16, 8(%r30)
+ fstd,ma %fr17, 8(%r30)
+ fstd,ma %fr18, 8(%r30)
+ fstd,ma %fr19, 8(%r30)
+ fstd,ma %fr20, 8(%r30)
+ fstd,ma %fr21, 8(%r30)
+ .endm
+
+ .macro callee_rest_float
+ fldd,mb -8(%r30), %fr21
+ fldd,mb -8(%r30), %fr20
+ fldd,mb -8(%r30), %fr19
+ fldd,mb -8(%r30), %fr18
+ fldd,mb -8(%r30), %fr17
+ fldd,mb -8(%r30), %fr16
+ fldd,mb -8(%r30), %fr15
+ fldd,mb -8(%r30), %fr14
+ fldd,mb -8(%r30), %fr13
+ fldd,mb -8(%r30), %fr12
+ .endm
+
+#ifdef CONFIG_64BIT
+ .macro callee_save
+ std,ma %r3, CALLEE_REG_FRAME_SIZE(%r30)
+ mfctl %cr27, %r3
+ std %r4, -136(%r30)
+ std %r5, -128(%r30)
+ std %r6, -120(%r30)
+ std %r7, -112(%r30)
+ std %r8, -104(%r30)
+ std %r9, -96(%r30)
+ std %r10, -88(%r30)
+ std %r11, -80(%r30)
+ std %r12, -72(%r30)
+ std %r13, -64(%r30)
+ std %r14, -56(%r30)
+ std %r15, -48(%r30)
+ std %r16, -40(%r30)
+ std %r17, -32(%r30)
+ std %r18, -24(%r30)
+ std %r3, -16(%r30)
+ .endm
+
+ .macro callee_rest
+ ldd -16(%r30), %r3
+ ldd -24(%r30), %r18
+ ldd -32(%r30), %r17
+ ldd -40(%r30), %r16
+ ldd -48(%r30), %r15
+ ldd -56(%r30), %r14
+ ldd -64(%r30), %r13
+ ldd -72(%r30), %r12
+ ldd -80(%r30), %r11
+ ldd -88(%r30), %r10
+ ldd -96(%r30), %r9
+ ldd -104(%r30), %r8
+ ldd -112(%r30), %r7
+ ldd -120(%r30), %r6
+ ldd -128(%r30), %r5
+ ldd -136(%r30), %r4
+ mtctl %r3, %cr27
+ ldd,mb -CALLEE_REG_FRAME_SIZE(%r30), %r3
+ .endm
+
+#else /* ! CONFIG_64BIT */
+
+ .macro callee_save
+ stw,ma %r3, CALLEE_REG_FRAME_SIZE(%r30)
+ mfctl %cr27, %r3
+ stw %r4, -124(%r30)
+ stw %r5, -120(%r30)
+ stw %r6, -116(%r30)
+ stw %r7, -112(%r30)
+ stw %r8, -108(%r30)
+ stw %r9, -104(%r30)
+ stw %r10, -100(%r30)
+ stw %r11, -96(%r30)
+ stw %r12, -92(%r30)
+ stw %r13, -88(%r30)
+ stw %r14, -84(%r30)
+ stw %r15, -80(%r30)
+ stw %r16, -76(%r30)
+ stw %r17, -72(%r30)
+ stw %r18, -68(%r30)
+ stw %r3, -64(%r30)
+ .endm
+
+ .macro callee_rest
+ ldw -64(%r30), %r3
+ ldw -68(%r30), %r18
+ ldw -72(%r30), %r17
+ ldw -76(%r30), %r16
+ ldw -80(%r30), %r15
+ ldw -84(%r30), %r14
+ ldw -88(%r30), %r13
+ ldw -92(%r30), %r12
+ ldw -96(%r30), %r11
+ ldw -100(%r30), %r10
+ ldw -104(%r30), %r9
+ ldw -108(%r30), %r8
+ ldw -112(%r30), %r7
+ ldw -116(%r30), %r6
+ ldw -120(%r30), %r5
+ ldw -124(%r30), %r4
+ mtctl %r3, %cr27
+ ldw,mb -CALLEE_REG_FRAME_SIZE(%r30), %r3
+ .endm
+#endif /* ! CONFIG_64BIT */
+
+ .macro save_specials regs
+
+ SAVE_SP (%sr0, PT_SR0 (\regs))
+ SAVE_SP (%sr1, PT_SR1 (\regs))
+ SAVE_SP (%sr2, PT_SR2 (\regs))
+ SAVE_SP (%sr3, PT_SR3 (\regs))
+ SAVE_SP (%sr4, PT_SR4 (\regs))
+ SAVE_SP (%sr5, PT_SR5 (\regs))
+ SAVE_SP (%sr6, PT_SR6 (\regs))
+
+ SAVE_CR (%cr17, PT_IASQ0(\regs))
+ mtctl %r0, %cr17
+ SAVE_CR (%cr17, PT_IASQ1(\regs))
+
+ SAVE_CR (%cr18, PT_IAOQ0(\regs))
+ mtctl %r0, %cr18
+ SAVE_CR (%cr18, PT_IAOQ1(\regs))
+
+#ifdef CONFIG_64BIT
+ /* cr11 (sar) is a funny one. 5 bits on PA1.1 and 6 bit on PA2.0
+ * For PA2.0 mtsar or mtctl always write 6 bits, but mfctl only
+ * reads 5 bits. Use mfctl,w to read all six bits. Otherwise
+ * we lose the 6th bit on a save/restore over interrupt.
+ */
+ mfctl,w %cr11, %r1
+ STREG %r1, PT_SAR (\regs)
+#else
+ SAVE_CR (%cr11, PT_SAR (\regs))
+#endif
+ SAVE_CR (%cr19, PT_IIR (\regs))
+
+ /*
+ * Code immediately following this macro (in intr_save) relies
+ * on r8 containing ipsw.
+ */
+ mfctl %cr22, %r8
+ STREG %r8, PT_PSW(\regs)
+ .endm
+
+ .macro rest_specials regs
+
+ REST_SP (%sr0, PT_SR0 (\regs))
+ REST_SP (%sr1, PT_SR1 (\regs))
+ REST_SP (%sr2, PT_SR2 (\regs))
+ REST_SP (%sr3, PT_SR3 (\regs))
+ REST_SP (%sr4, PT_SR4 (\regs))
+ REST_SP (%sr5, PT_SR5 (\regs))
+ REST_SP (%sr6, PT_SR6 (\regs))
+ REST_SP (%sr7, PT_SR7 (\regs))
+
+ REST_CR (%cr17, PT_IASQ0(\regs))
+ REST_CR (%cr17, PT_IASQ1(\regs))
+
+ REST_CR (%cr18, PT_IAOQ0(\regs))
+ REST_CR (%cr18, PT_IAOQ1(\regs))
+
+ REST_CR (%cr11, PT_SAR (\regs))
+
+ REST_CR (%cr22, PT_PSW (\regs))
+ .endm
+
+
+ /* First step to create a "relied upon translation"
+ * See PA 2.0 Arch. page F-4 and F-5.
+ *
+ * The ssm was originally necessary due to a "PCxT bug".
+ * But someone decided it needed to be added to the architecture
+ * and this "feature" went into rev3 of PA-RISC 1.1 Arch Manual.
+ * It's been carried forward into PA 2.0 Arch as well. :^(
+ *
+ * "ssm 0,%r0" is a NOP with side effects (prefetch barrier).
+ * rsm/ssm prevents the ifetch unit from speculatively fetching
+ * instructions past this line in the code stream.
+ * PA 2.0 processor will single step all insn in the same QUAD (4 insn).
+ */
+ .macro pcxt_ssm_bug
+ rsm PSW_SM_I,%r0
+ nop /* 1 */
+ nop /* 2 */
+ nop /* 3 */
+ nop /* 4 */
+ nop /* 5 */
+ nop /* 6 */
+ nop /* 7 */
+ .endm
+
+ /* Switch to virtual mapping, trashing only %r1 */
+ .macro virt_map
+ /* pcxt_ssm_bug */
+ rsm PSW_SM_I, %r0 /* barrier for "Relied upon Translation */
+ mtsp %r0, %sr4
+ mtsp %r0, %sr5
+ mtsp %r0, %sr6
+ tovirt_r1 %r29
+ load32 KERNEL_PSW, %r1
+
+ rsm PSW_SM_QUIET,%r0 /* second "heavy weight" ctl op */
+ mtctl %r0, %cr17 /* Clear IIASQ tail */
+ mtctl %r0, %cr17 /* Clear IIASQ head */
+ mtctl %r1, %ipsw
+ load32 4f, %r1
+ mtctl %r1, %cr18 /* Set IIAOQ tail */
+ ldo 4(%r1), %r1
+ mtctl %r1, %cr18 /* Set IIAOQ head */
+ rfir
+ nop
+4:
+ .endm
+
+
+ /*
+ * ASM_EXCEPTIONTABLE_ENTRY
+ *
+ * Creates an exception table entry.
+ * Do not convert to a assembler macro. This won't work.
+ */
+#define ASM_EXCEPTIONTABLE_ENTRY(fault_addr, except_addr) \
+ .section __ex_table,"aw" ! \
+ .align 4 ! \
+ .word (fault_addr - .), (except_addr - .) ! \
+ .previous
+
+
+#endif /* __ASSEMBLY__ */
+#endif
diff --git a/arch/parisc/include/asm/atomic.h b/arch/parisc/include/asm/atomic.h
new file mode 100644
index 000000000..d4f023887
--- /dev/null
+++ b/arch/parisc/include/asm/atomic.h
@@ -0,0 +1,238 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
+ * Copyright (C) 2006 Kyle McMartin <kyle@parisc-linux.org>
+ */
+
+#ifndef _ASM_PARISC_ATOMIC_H_
+#define _ASM_PARISC_ATOMIC_H_
+
+#include <linux/types.h>
+#include <asm/cmpxchg.h>
+#include <asm/barrier.h>
+
+/*
+ * Atomic operations that C can't guarantee us. Useful for
+ * resource counting etc..
+ *
+ * And probably incredibly slow on parisc. OTOH, we don't
+ * have to write any serious assembly. prumpf
+ */
+
+#ifdef CONFIG_SMP
+#include <asm/spinlock.h>
+#include <asm/cache.h> /* we use L1_CACHE_BYTES */
+
+/* Use an array of spinlocks for our atomic_ts.
+ * Hash function to index into a different SPINLOCK.
+ * Since "a" is usually an address, use one spinlock per cacheline.
+ */
+# define ATOMIC_HASH_SIZE 4
+# define ATOMIC_HASH(a) (&(__atomic_hash[ (((unsigned long) (a))/L1_CACHE_BYTES) & (ATOMIC_HASH_SIZE-1) ]))
+
+extern arch_spinlock_t __atomic_hash[ATOMIC_HASH_SIZE] __lock_aligned;
+
+/* Can't use raw_spin_lock_irq because of #include problems, so
+ * this is the substitute */
+#define _atomic_spin_lock_irqsave(l,f) do { \
+ arch_spinlock_t *s = ATOMIC_HASH(l); \
+ local_irq_save(f); \
+ arch_spin_lock(s); \
+} while(0)
+
+#define _atomic_spin_unlock_irqrestore(l,f) do { \
+ arch_spinlock_t *s = ATOMIC_HASH(l); \
+ arch_spin_unlock(s); \
+ local_irq_restore(f); \
+} while(0)
+
+
+#else
+# define _atomic_spin_lock_irqsave(l,f) do { local_irq_save(f); } while (0)
+# define _atomic_spin_unlock_irqrestore(l,f) do { local_irq_restore(f); } while (0)
+#endif
+
+/*
+ * Note that we need not lock read accesses - aligned word writes/reads
+ * are atomic, so a reader never sees inconsistent values.
+ */
+
+static __inline__ void arch_atomic_set(atomic_t *v, int i)
+{
+ unsigned long flags;
+ _atomic_spin_lock_irqsave(v, flags);
+
+ v->counter = i;
+
+ _atomic_spin_unlock_irqrestore(v, flags);
+}
+
+#define arch_atomic_set_release(v, i) arch_atomic_set((v), (i))
+
+static __inline__ int arch_atomic_read(const atomic_t *v)
+{
+ return READ_ONCE((v)->counter);
+}
+
+#define ATOMIC_OP(op, c_op) \
+static __inline__ void arch_atomic_##op(int i, atomic_t *v) \
+{ \
+ unsigned long flags; \
+ \
+ _atomic_spin_lock_irqsave(v, flags); \
+ v->counter c_op i; \
+ _atomic_spin_unlock_irqrestore(v, flags); \
+}
+
+#define ATOMIC_OP_RETURN(op, c_op) \
+static __inline__ int arch_atomic_##op##_return(int i, atomic_t *v) \
+{ \
+ unsigned long flags; \
+ int ret; \
+ \
+ _atomic_spin_lock_irqsave(v, flags); \
+ ret = (v->counter c_op i); \
+ _atomic_spin_unlock_irqrestore(v, flags); \
+ \
+ return ret; \
+}
+
+#define ATOMIC_FETCH_OP(op, c_op) \
+static __inline__ int arch_atomic_fetch_##op(int i, atomic_t *v) \
+{ \
+ unsigned long flags; \
+ int ret; \
+ \
+ _atomic_spin_lock_irqsave(v, flags); \
+ ret = v->counter; \
+ v->counter c_op i; \
+ _atomic_spin_unlock_irqrestore(v, flags); \
+ \
+ return ret; \
+}
+
+#define ATOMIC_OPS(op, c_op) \
+ ATOMIC_OP(op, c_op) \
+ ATOMIC_OP_RETURN(op, c_op) \
+ ATOMIC_FETCH_OP(op, c_op)
+
+ATOMIC_OPS(add, +=)
+ATOMIC_OPS(sub, -=)
+
+#define arch_atomic_add_return arch_atomic_add_return
+#define arch_atomic_sub_return arch_atomic_sub_return
+#define arch_atomic_fetch_add arch_atomic_fetch_add
+#define arch_atomic_fetch_sub arch_atomic_fetch_sub
+
+#undef ATOMIC_OPS
+#define ATOMIC_OPS(op, c_op) \
+ ATOMIC_OP(op, c_op) \
+ ATOMIC_FETCH_OP(op, c_op)
+
+ATOMIC_OPS(and, &=)
+ATOMIC_OPS(or, |=)
+ATOMIC_OPS(xor, ^=)
+
+#define arch_atomic_fetch_and arch_atomic_fetch_and
+#define arch_atomic_fetch_or arch_atomic_fetch_or
+#define arch_atomic_fetch_xor arch_atomic_fetch_xor
+
+#undef ATOMIC_OPS
+#undef ATOMIC_FETCH_OP
+#undef ATOMIC_OP_RETURN
+#undef ATOMIC_OP
+
+#ifdef CONFIG_64BIT
+
+#define ATOMIC64_INIT(i) { (i) }
+
+#define ATOMIC64_OP(op, c_op) \
+static __inline__ void arch_atomic64_##op(s64 i, atomic64_t *v) \
+{ \
+ unsigned long flags; \
+ \
+ _atomic_spin_lock_irqsave(v, flags); \
+ v->counter c_op i; \
+ _atomic_spin_unlock_irqrestore(v, flags); \
+}
+
+#define ATOMIC64_OP_RETURN(op, c_op) \
+static __inline__ s64 arch_atomic64_##op##_return(s64 i, atomic64_t *v) \
+{ \
+ unsigned long flags; \
+ s64 ret; \
+ \
+ _atomic_spin_lock_irqsave(v, flags); \
+ ret = (v->counter c_op i); \
+ _atomic_spin_unlock_irqrestore(v, flags); \
+ \
+ return ret; \
+}
+
+#define ATOMIC64_FETCH_OP(op, c_op) \
+static __inline__ s64 arch_atomic64_fetch_##op(s64 i, atomic64_t *v) \
+{ \
+ unsigned long flags; \
+ s64 ret; \
+ \
+ _atomic_spin_lock_irqsave(v, flags); \
+ ret = v->counter; \
+ v->counter c_op i; \
+ _atomic_spin_unlock_irqrestore(v, flags); \
+ \
+ return ret; \
+}
+
+#define ATOMIC64_OPS(op, c_op) \
+ ATOMIC64_OP(op, c_op) \
+ ATOMIC64_OP_RETURN(op, c_op) \
+ ATOMIC64_FETCH_OP(op, c_op)
+
+ATOMIC64_OPS(add, +=)
+ATOMIC64_OPS(sub, -=)
+
+#define arch_atomic64_add_return arch_atomic64_add_return
+#define arch_atomic64_sub_return arch_atomic64_sub_return
+#define arch_atomic64_fetch_add arch_atomic64_fetch_add
+#define arch_atomic64_fetch_sub arch_atomic64_fetch_sub
+
+#undef ATOMIC64_OPS
+#define ATOMIC64_OPS(op, c_op) \
+ ATOMIC64_OP(op, c_op) \
+ ATOMIC64_FETCH_OP(op, c_op)
+
+ATOMIC64_OPS(and, &=)
+ATOMIC64_OPS(or, |=)
+ATOMIC64_OPS(xor, ^=)
+
+#define arch_atomic64_fetch_and arch_atomic64_fetch_and
+#define arch_atomic64_fetch_or arch_atomic64_fetch_or
+#define arch_atomic64_fetch_xor arch_atomic64_fetch_xor
+
+#undef ATOMIC64_OPS
+#undef ATOMIC64_FETCH_OP
+#undef ATOMIC64_OP_RETURN
+#undef ATOMIC64_OP
+
+static __inline__ void
+arch_atomic64_set(atomic64_t *v, s64 i)
+{
+ unsigned long flags;
+ _atomic_spin_lock_irqsave(v, flags);
+
+ v->counter = i;
+
+ _atomic_spin_unlock_irqrestore(v, flags);
+}
+
+#define arch_atomic64_set_release(v, i) arch_atomic64_set((v), (i))
+
+static __inline__ s64
+arch_atomic64_read(const atomic64_t *v)
+{
+ return READ_ONCE((v)->counter);
+}
+
+#endif /* !CONFIG_64BIT */
+
+
+#endif /* _ASM_PARISC_ATOMIC_H_ */
diff --git a/arch/parisc/include/asm/barrier.h b/arch/parisc/include/asm/barrier.h
new file mode 100644
index 000000000..c705decf2
--- /dev/null
+++ b/arch/parisc/include/asm/barrier.h
@@ -0,0 +1,97 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_BARRIER_H
+#define __ASM_BARRIER_H
+
+#include <asm/alternative.h>
+
+#ifndef __ASSEMBLY__
+
+/* The synchronize caches instruction executes as a nop on systems in
+ which all memory references are performed in order. */
+#define synchronize_caches() asm volatile("sync" \
+ ALTERNATIVE(ALT_COND_NO_SMP, INSN_NOP) \
+ : : : "memory")
+
+#if defined(CONFIG_SMP)
+#define mb() do { synchronize_caches(); } while (0)
+#define rmb() mb()
+#define wmb() mb()
+#define dma_rmb() mb()
+#define dma_wmb() mb()
+#else
+#define mb() barrier()
+#define rmb() barrier()
+#define wmb() barrier()
+#define dma_rmb() barrier()
+#define dma_wmb() barrier()
+#endif
+
+#define __smp_mb() mb()
+#define __smp_rmb() mb()
+#define __smp_wmb() mb()
+
+#define __smp_store_release(p, v) \
+do { \
+ typeof(p) __p = (p); \
+ union { typeof(*p) __val; char __c[1]; } __u = \
+ { .__val = (__force typeof(*p)) (v) }; \
+ compiletime_assert_atomic_type(*p); \
+ switch (sizeof(*p)) { \
+ case 1: \
+ asm volatile("stb,ma %0,0(%1)" \
+ : : "r"(*(__u8 *)__u.__c), "r"(__p) \
+ : "memory"); \
+ break; \
+ case 2: \
+ asm volatile("sth,ma %0,0(%1)" \
+ : : "r"(*(__u16 *)__u.__c), "r"(__p) \
+ : "memory"); \
+ break; \
+ case 4: \
+ asm volatile("stw,ma %0,0(%1)" \
+ : : "r"(*(__u32 *)__u.__c), "r"(__p) \
+ : "memory"); \
+ break; \
+ case 8: \
+ if (IS_ENABLED(CONFIG_64BIT)) \
+ asm volatile("std,ma %0,0(%1)" \
+ : : "r"(*(__u64 *)__u.__c), "r"(__p) \
+ : "memory"); \
+ break; \
+ } \
+} while (0)
+
+#define __smp_load_acquire(p) \
+({ \
+ union { typeof(*p) __val; char __c[1]; } __u; \
+ typeof(p) __p = (p); \
+ compiletime_assert_atomic_type(*p); \
+ switch (sizeof(*p)) { \
+ case 1: \
+ asm volatile("ldb,ma 0(%1),%0" \
+ : "=r"(*(__u8 *)__u.__c) : "r"(__p) \
+ : "memory"); \
+ break; \
+ case 2: \
+ asm volatile("ldh,ma 0(%1),%0" \
+ : "=r"(*(__u16 *)__u.__c) : "r"(__p) \
+ : "memory"); \
+ break; \
+ case 4: \
+ asm volatile("ldw,ma 0(%1),%0" \
+ : "=r"(*(__u32 *)__u.__c) : "r"(__p) \
+ : "memory"); \
+ break; \
+ case 8: \
+ if (IS_ENABLED(CONFIG_64BIT)) \
+ asm volatile("ldd,ma 0(%1),%0" \
+ : "=r"(*(__u64 *)__u.__c) : "r"(__p) \
+ : "memory"); \
+ break; \
+ } \
+ __u.__val; \
+})
+#include <asm-generic/barrier.h>
+
+#endif /* !__ASSEMBLY__ */
+#endif /* __ASM_BARRIER_H */
diff --git a/arch/parisc/include/asm/bitops.h b/arch/parisc/include/asm/bitops.h
new file mode 100644
index 000000000..0ec9cfc51
--- /dev/null
+++ b/arch/parisc/include/asm/bitops.h
@@ -0,0 +1,209 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _PARISC_BITOPS_H
+#define _PARISC_BITOPS_H
+
+#ifndef _LINUX_BITOPS_H
+#error only <linux/bitops.h> can be included directly
+#endif
+
+#include <linux/compiler.h>
+#include <asm/types.h>
+#include <asm/byteorder.h>
+#include <asm/barrier.h>
+#include <linux/atomic.h>
+
+/* See http://marc.theaimsgroup.com/?t=108826637900003 for discussion
+ * on use of volatile and __*_bit() (set/clear/change):
+ * *_bit() want use of volatile.
+ * __*_bit() are "relaxed" and don't use spinlock or volatile.
+ */
+
+static __inline__ void set_bit(int nr, volatile unsigned long * addr)
+{
+ unsigned long mask = BIT_MASK(nr);
+ unsigned long flags;
+
+ addr += BIT_WORD(nr);
+ _atomic_spin_lock_irqsave(addr, flags);
+ *addr |= mask;
+ _atomic_spin_unlock_irqrestore(addr, flags);
+}
+
+static __inline__ void clear_bit(int nr, volatile unsigned long * addr)
+{
+ unsigned long mask = BIT_MASK(nr);
+ unsigned long flags;
+
+ addr += BIT_WORD(nr);
+ _atomic_spin_lock_irqsave(addr, flags);
+ *addr &= ~mask;
+ _atomic_spin_unlock_irqrestore(addr, flags);
+}
+
+static __inline__ void change_bit(int nr, volatile unsigned long * addr)
+{
+ unsigned long mask = BIT_MASK(nr);
+ unsigned long flags;
+
+ addr += BIT_WORD(nr);
+ _atomic_spin_lock_irqsave(addr, flags);
+ *addr ^= mask;
+ _atomic_spin_unlock_irqrestore(addr, flags);
+}
+
+static __inline__ int test_and_set_bit(int nr, volatile unsigned long * addr)
+{
+ unsigned long mask = BIT_MASK(nr);
+ unsigned long old;
+ unsigned long flags;
+ int set;
+
+ addr += BIT_WORD(nr);
+ _atomic_spin_lock_irqsave(addr, flags);
+ old = *addr;
+ set = (old & mask) ? 1 : 0;
+ if (!set)
+ *addr = old | mask;
+ _atomic_spin_unlock_irqrestore(addr, flags);
+
+ return set;
+}
+
+static __inline__ int test_and_clear_bit(int nr, volatile unsigned long * addr)
+{
+ unsigned long mask = BIT_MASK(nr);
+ unsigned long old;
+ unsigned long flags;
+ int set;
+
+ addr += BIT_WORD(nr);
+ _atomic_spin_lock_irqsave(addr, flags);
+ old = *addr;
+ set = (old & mask) ? 1 : 0;
+ if (set)
+ *addr = old & ~mask;
+ _atomic_spin_unlock_irqrestore(addr, flags);
+
+ return set;
+}
+
+static __inline__ int test_and_change_bit(int nr, volatile unsigned long * addr)
+{
+ unsigned long mask = BIT_MASK(nr);
+ unsigned long oldbit;
+ unsigned long flags;
+
+ addr += BIT_WORD(nr);
+ _atomic_spin_lock_irqsave(addr, flags);
+ oldbit = *addr;
+ *addr = oldbit ^ mask;
+ _atomic_spin_unlock_irqrestore(addr, flags);
+
+ return (oldbit & mask) ? 1 : 0;
+}
+
+#include <asm-generic/bitops/non-atomic.h>
+
+/**
+ * __ffs - find first bit in word. returns 0 to "BITS_PER_LONG-1".
+ * @word: The word to search
+ *
+ * __ffs() return is undefined if no bit is set.
+ *
+ * 32-bit fast __ffs by LaMont Jones "lamont At hp com".
+ * 64-bit enhancement by Grant Grundler "grundler At parisc-linux org".
+ * (with help from willy/jejb to get the semantics right)
+ *
+ * This algorithm avoids branches by making use of nullification.
+ * One side effect of "extr" instructions is it sets PSW[N] bit.
+ * How PSW[N] (nullify next insn) gets set is determined by the
+ * "condition" field (eg "<>" or "TR" below) in the extr* insn.
+ * Only the 1st and one of either the 2cd or 3rd insn will get executed.
+ * Each set of 3 insn will get executed in 2 cycles on PA8x00 vs 16 or so
+ * cycles for each mispredicted branch.
+ */
+
+static __inline__ unsigned long __ffs(unsigned long x)
+{
+ unsigned long ret;
+
+ __asm__(
+#ifdef CONFIG_64BIT
+ " ldi 63,%1\n"
+ " extrd,u,*<> %0,63,32,%%r0\n"
+ " extrd,u,*TR %0,31,32,%0\n" /* move top 32-bits down */
+ " addi -32,%1,%1\n"
+#else
+ " ldi 31,%1\n"
+#endif
+ " extru,<> %0,31,16,%%r0\n"
+ " extru,TR %0,15,16,%0\n" /* xxxx0000 -> 0000xxxx */
+ " addi -16,%1,%1\n"
+ " extru,<> %0,31,8,%%r0\n"
+ " extru,TR %0,23,8,%0\n" /* 0000xx00 -> 000000xx */
+ " addi -8,%1,%1\n"
+ " extru,<> %0,31,4,%%r0\n"
+ " extru,TR %0,27,4,%0\n" /* 000000x0 -> 0000000x */
+ " addi -4,%1,%1\n"
+ " extru,<> %0,31,2,%%r0\n"
+ " extru,TR %0,29,2,%0\n" /* 0000000y, 1100b -> 0011b */
+ " addi -2,%1,%1\n"
+ " extru,= %0,31,1,%%r0\n" /* check last bit */
+ " addi -1,%1,%1\n"
+ : "+r" (x), "=r" (ret) );
+ return ret;
+}
+
+#include <asm-generic/bitops/ffz.h>
+
+/*
+ * ffs: find first bit set. returns 1 to BITS_PER_LONG or 0 (if none set)
+ * This is defined the same way as the libc and compiler builtin
+ * ffs routines, therefore differs in spirit from the above ffz (man ffs).
+ */
+static __inline__ int ffs(int x)
+{
+ return x ? (__ffs((unsigned long)x) + 1) : 0;
+}
+
+/*
+ * fls: find last (most significant) bit set.
+ * fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
+ */
+
+static __inline__ int fls(unsigned int x)
+{
+ int ret;
+ if (!x)
+ return 0;
+
+ __asm__(
+ " ldi 1,%1\n"
+ " extru,<> %0,15,16,%%r0\n"
+ " zdep,TR %0,15,16,%0\n" /* xxxx0000 */
+ " addi 16,%1,%1\n"
+ " extru,<> %0,7,8,%%r0\n"
+ " zdep,TR %0,23,24,%0\n" /* xx000000 */
+ " addi 8,%1,%1\n"
+ " extru,<> %0,3,4,%%r0\n"
+ " zdep,TR %0,27,28,%0\n" /* x0000000 */
+ " addi 4,%1,%1\n"
+ " extru,<> %0,1,2,%%r0\n"
+ " zdep,TR %0,29,30,%0\n" /* y0000000 (y&3 = 0) */
+ " addi 2,%1,%1\n"
+ " extru,= %0,0,1,%%r0\n"
+ " addi 1,%1,%1\n" /* if y & 8, add 1 */
+ : "+r" (x), "=r" (ret) );
+
+ return ret;
+}
+
+#include <asm-generic/bitops/__fls.h>
+#include <asm-generic/bitops/fls64.h>
+#include <asm-generic/bitops/hweight.h>
+#include <asm-generic/bitops/lock.h>
+#include <asm-generic/bitops/sched.h>
+#include <asm-generic/bitops/le.h>
+#include <asm-generic/bitops/ext2-atomic-setbit.h>
+
+#endif /* _PARISC_BITOPS_H */
diff --git a/arch/parisc/include/asm/bug.h b/arch/parisc/include/asm/bug.h
new file mode 100644
index 000000000..833555f74
--- /dev/null
+++ b/arch/parisc/include/asm/bug.h
@@ -0,0 +1,101 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _PARISC_BUG_H
+#define _PARISC_BUG_H
+
+#include <linux/kernel.h> /* for BUGFLAG_TAINT */
+
+/*
+ * Tell the user there is some problem.
+ * The offending file and line are encoded in the __bug_table section.
+ */
+
+#ifdef CONFIG_BUG
+#define HAVE_ARCH_BUG
+#define HAVE_ARCH_WARN_ON
+
+/* the break instruction is used as BUG() marker. */
+#define PARISC_BUG_BREAK_ASM "break 0x1f, 0x1fff"
+#define PARISC_BUG_BREAK_INSN 0x03ffe01f /* PARISC_BUG_BREAK_ASM */
+
+#ifdef CONFIG_GENERIC_BUG_RELATIVE_POINTERS
+# define __BUG_REL(val) ".word " __stringify(val) " - ."
+#else
+# define __BUG_REL(val) ".word " __stringify(val)
+#endif
+
+
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+#define BUG() \
+ do { \
+ asm volatile("\n" \
+ "1:\t" PARISC_BUG_BREAK_ASM "\n" \
+ "\t.pushsection __bug_table,\"a\"\n" \
+ "\t.align 4\n" \
+ "2:\t" __BUG_REL(1b) "\n" \
+ "\t" __BUG_REL(%c0) "\n" \
+ "\t.short %1, %2\n" \
+ "\t.blockz %3-2*4-2*2\n" \
+ "\t.popsection" \
+ : : "i" (__FILE__), "i" (__LINE__), \
+ "i" (0), "i" (sizeof(struct bug_entry)) ); \
+ unreachable(); \
+ } while(0)
+
+#else
+#define BUG() \
+ do { \
+ asm volatile(PARISC_BUG_BREAK_ASM : : ); \
+ unreachable(); \
+ } while(0)
+#endif
+
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+#define __WARN_FLAGS(flags) \
+ do { \
+ asm volatile("\n" \
+ "1:\t" PARISC_BUG_BREAK_ASM "\n" \
+ "\t.pushsection __bug_table,\"a\"\n" \
+ "\t.align 4\n" \
+ "2:\t" __BUG_REL(1b) "\n" \
+ "\t" __BUG_REL(%c0) "\n" \
+ "\t.short %1, %2\n" \
+ "\t.blockz %3-2*4-2*2\n" \
+ "\t.popsection" \
+ : : "i" (__FILE__), "i" (__LINE__), \
+ "i" (BUGFLAG_WARNING|(flags)), \
+ "i" (sizeof(struct bug_entry)) ); \
+ } while(0)
+#else
+#define __WARN_FLAGS(flags) \
+ do { \
+ asm volatile("\n" \
+ "1:\t" PARISC_BUG_BREAK_ASM "\n" \
+ "\t.pushsection __bug_table,\"a\"\n" \
+ "\t.align 4\n" \
+ "2:\t" __BUG_REL(1b) "\n" \
+ "\t.short %0\n" \
+ "\t.blockz %1-4-2\n" \
+ "\t.popsection" \
+ : : "i" (BUGFLAG_WARNING|(flags)), \
+ "i" (sizeof(struct bug_entry)) ); \
+ } while(0)
+#endif
+
+
+#define WARN_ON(x) ({ \
+ int __ret_warn_on = !!(x); \
+ if (__builtin_constant_p(__ret_warn_on)) { \
+ if (__ret_warn_on) \
+ __WARN(); \
+ } else { \
+ if (unlikely(__ret_warn_on)) \
+ __WARN(); \
+ } \
+ unlikely(__ret_warn_on); \
+})
+
+#endif
+
+#include <asm-generic/bug.h>
+#endif
+
diff --git a/arch/parisc/include/asm/cache.h b/arch/parisc/include/asm/cache.h
new file mode 100644
index 000000000..2a60d7a72
--- /dev/null
+++ b/arch/parisc/include/asm/cache.h
@@ -0,0 +1,68 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * include/asm-parisc/cache.h
+ */
+
+#ifndef __ARCH_PARISC_CACHE_H
+#define __ARCH_PARISC_CACHE_H
+
+#include <asm/alternative.h>
+
+/*
+ * PA 2.0 processors have 64 and 128-byte L2 cachelines; PA 1.1 processors
+ * have 32-byte cachelines. The L1 length appears to be 16 bytes but this
+ * is not clearly documented.
+ */
+#define L1_CACHE_BYTES 16
+#define L1_CACHE_SHIFT 4
+
+#ifndef __ASSEMBLY__
+
+#define SMP_CACHE_BYTES L1_CACHE_BYTES
+
+#define ARCH_DMA_MINALIGN L1_CACHE_BYTES
+
+#define __read_mostly __section(".data..read_mostly")
+
+void parisc_cache_init(void); /* initializes cache-flushing */
+void disable_sr_hashing_asm(int); /* low level support for above */
+void disable_sr_hashing(void); /* turns off space register hashing */
+void free_sid(unsigned long);
+unsigned long alloc_sid(void);
+
+struct seq_file;
+extern void show_cache_info(struct seq_file *m);
+
+extern int split_tlb;
+extern int dcache_stride;
+extern int icache_stride;
+extern struct pdc_cache_info cache_info;
+extern struct pdc_btlb_info btlb_info;
+void parisc_setup_cache_timing(void);
+
+#define pdtlb(sr, addr) asm volatile("pdtlb 0(%%sr%0,%1)" \
+ ALTERNATIVE(ALT_COND_NO_SMP, INSN_PxTLB) \
+ : : "i"(sr), "r" (addr) : "memory")
+#define pitlb(sr, addr) asm volatile("pitlb 0(%%sr%0,%1)" \
+ ALTERNATIVE(ALT_COND_NO_SMP, INSN_PxTLB) \
+ ALTERNATIVE(ALT_COND_NO_SPLIT_TLB, INSN_NOP) \
+ : : "i"(sr), "r" (addr) : "memory")
+
+#define asm_io_fdc(addr) asm volatile("fdc %%r0(%0)" \
+ ALTERNATIVE(ALT_COND_NO_DCACHE, INSN_NOP) \
+ ALTERNATIVE(ALT_COND_NO_IOC_FDC, INSN_NOP) \
+ : : "r" (addr) : "memory")
+#define asm_io_sync() asm volatile("sync" \
+ ALTERNATIVE(ALT_COND_NO_DCACHE, INSN_NOP) \
+ ALTERNATIVE(ALT_COND_NO_IOC_FDC, INSN_NOP) :::"memory")
+#define asm_syncdma() asm volatile("syncdma" :::"memory")
+
+#endif /* ! __ASSEMBLY__ */
+
+/* Classes of processor wrt: disabling space register hashing */
+
+#define SRHASH_PCXST 0 /* pcxs, pcxt, pcxt_ */
+#define SRHASH_PCXL 1 /* pcxl */
+#define SRHASH_PA20 2 /* pcxu, pcxu_, pcxw, pcxw_ */
+
+#endif
diff --git a/arch/parisc/include/asm/cacheflush.h b/arch/parisc/include/asm/cacheflush.h
new file mode 100644
index 000000000..b4006f2a9
--- /dev/null
+++ b/arch/parisc/include/asm/cacheflush.h
@@ -0,0 +1,92 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _PARISC_CACHEFLUSH_H
+#define _PARISC_CACHEFLUSH_H
+
+#include <linux/mm.h>
+#include <linux/uaccess.h>
+#include <asm/tlbflush.h>
+
+/* The usual comment is "Caches aren't brain-dead on the <architecture>".
+ * Unfortunately, that doesn't apply to PA-RISC. */
+
+#include <linux/jump_label.h>
+
+DECLARE_STATIC_KEY_TRUE(parisc_has_cache);
+DECLARE_STATIC_KEY_TRUE(parisc_has_dcache);
+DECLARE_STATIC_KEY_TRUE(parisc_has_icache);
+
+#define flush_cache_dup_mm(mm) flush_cache_mm(mm)
+
+void flush_user_icache_range_asm(unsigned long, unsigned long);
+void flush_kernel_icache_range_asm(unsigned long, unsigned long);
+void flush_user_dcache_range_asm(unsigned long, unsigned long);
+void flush_kernel_dcache_range_asm(unsigned long, unsigned long);
+void purge_kernel_dcache_range_asm(unsigned long, unsigned long);
+void flush_kernel_dcache_page_asm(const void *addr);
+void flush_kernel_icache_page(void *);
+
+/* Cache flush operations */
+
+void flush_cache_all_local(void);
+void flush_cache_all(void);
+void flush_cache_mm(struct mm_struct *mm);
+
+void flush_kernel_dcache_page_addr(const void *addr);
+
+#define flush_kernel_dcache_range(start,size) \
+ flush_kernel_dcache_range_asm((start), (start)+(size));
+
+#define ARCH_IMPLEMENTS_FLUSH_KERNEL_VMAP_RANGE 1
+void flush_kernel_vmap_range(void *vaddr, int size);
+void invalidate_kernel_vmap_range(void *vaddr, int size);
+
+#define flush_cache_vmap(start, end) flush_cache_all()
+#define flush_cache_vunmap(start, end) flush_cache_all()
+
+void flush_dcache_folio(struct folio *folio);
+#define flush_dcache_folio flush_dcache_folio
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
+static inline void flush_dcache_page(struct page *page)
+{
+ flush_dcache_folio(page_folio(page));
+}
+
+#define flush_dcache_mmap_lock(mapping) xa_lock_irq(&mapping->i_pages)
+#define flush_dcache_mmap_unlock(mapping) xa_unlock_irq(&mapping->i_pages)
+#define flush_dcache_mmap_lock_irqsave(mapping, flags) \
+ xa_lock_irqsave(&mapping->i_pages, flags)
+#define flush_dcache_mmap_unlock_irqrestore(mapping, flags) \
+ xa_unlock_irqrestore(&mapping->i_pages, flags)
+
+void flush_icache_pages(struct vm_area_struct *vma, struct page *page,
+ unsigned int nr);
+#define flush_icache_pages flush_icache_pages
+
+#define flush_icache_range(s,e) do { \
+ flush_kernel_dcache_range_asm(s,e); \
+ flush_kernel_icache_range_asm(s,e); \
+} while (0)
+
+void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
+ unsigned long user_vaddr, void *dst, void *src, int len);
+void copy_from_user_page(struct vm_area_struct *vma, struct page *page,
+ unsigned long user_vaddr, void *dst, void *src, int len);
+void flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr,
+ unsigned long pfn);
+void flush_cache_range(struct vm_area_struct *vma,
+ unsigned long start, unsigned long end);
+
+/* defined in pacache.S exported in cache.c used by flush_anon_page */
+void flush_dcache_page_asm(unsigned long phys_addr, unsigned long vaddr);
+
+#define ARCH_HAS_FLUSH_ANON_PAGE
+void flush_anon_page(struct vm_area_struct *vma, struct page *page, unsigned long vmaddr);
+
+#define ARCH_HAS_FLUSH_ON_KUNMAP
+static inline void kunmap_flush_on_unmap(const void *addr)
+{
+ flush_kernel_dcache_page_addr(addr);
+}
+
+#endif /* _PARISC_CACHEFLUSH_H */
+
diff --git a/arch/parisc/include/asm/checksum.h b/arch/parisc/include/asm/checksum.h
new file mode 100644
index 000000000..3c43baca7
--- /dev/null
+++ b/arch/parisc/include/asm/checksum.h
@@ -0,0 +1,177 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _PARISC_CHECKSUM_H
+#define _PARISC_CHECKSUM_H
+
+#include <linux/in6.h>
+
+/*
+ * computes the checksum of a memory block at buff, length len,
+ * and adds in "sum" (32-bit)
+ *
+ * returns a 32-bit number suitable for feeding into itself
+ * or csum_tcpudp_magic
+ *
+ * this function must be called with even lengths, except
+ * for the last fragment, which may be odd
+ *
+ * it's best to have buff aligned on a 32-bit boundary
+ */
+extern __wsum csum_partial(const void *, int, __wsum);
+
+/*
+ * Optimized for IP headers, which always checksum on 4 octet boundaries.
+ *
+ * Written by Randolph Chung <tausq@debian.org>, and then mucked with by
+ * LaMont Jones <lamont@debian.org>
+ */
+static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
+{
+ unsigned int sum;
+ unsigned long t0, t1, t2;
+
+ __asm__ __volatile__ (
+" ldws,ma 4(%1), %0\n"
+" addib,<= -4, %2, 2f\n"
+"\n"
+" ldws 4(%1), %4\n"
+" ldws 8(%1), %5\n"
+" add %0, %4, %0\n"
+" ldws,ma 12(%1), %3\n"
+" addc %0, %5, %0\n"
+" addc %0, %3, %0\n"
+"1: ldws,ma 4(%1), %3\n"
+" addib,< 0, %2, 1b\n"
+" addc %0, %3, %0\n"
+"\n"
+" extru %0, 31, 16, %4\n"
+" extru %0, 15, 16, %5\n"
+" addc %4, %5, %0\n"
+" extru %0, 15, 16, %5\n"
+" add %0, %5, %0\n"
+" subi -1, %0, %0\n"
+"2:\n"
+ : "=r" (sum), "=r" (iph), "=r" (ihl), "=r" (t0), "=r" (t1), "=r" (t2)
+ : "1" (iph), "2" (ihl)
+ : "memory");
+
+ return (__force __sum16)sum;
+}
+
+/*
+ * Fold a partial checksum
+ */
+static inline __sum16 csum_fold(__wsum csum)
+{
+ u32 sum = (__force u32)csum;
+ /* add the swapped two 16-bit halves of sum,
+ a possible carry from adding the two 16-bit halves,
+ will carry from the lower half into the upper half,
+ giving us the correct sum in the upper half. */
+ sum += (sum << 16) + (sum >> 16);
+ return (__force __sum16)(~sum >> 16);
+}
+
+static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
+ __u32 len, __u8 proto,
+ __wsum sum)
+{
+ __asm__(
+ " add %1, %0, %0\n"
+ " addc %2, %0, %0\n"
+ " addc %3, %0, %0\n"
+ " addc %%r0, %0, %0\n"
+ : "=r" (sum)
+ : "r" (daddr), "r"(saddr), "r"(proto+len), "0"(sum));
+ return sum;
+}
+
+/*
+ * computes the checksum of the TCP/UDP pseudo-header
+ * returns a 16-bit checksum, already complemented
+ */
+static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
+ __u32 len, __u8 proto,
+ __wsum sum)
+{
+ return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
+}
+
+/*
+ * this routine is used for miscellaneous IP-like checksums, mainly
+ * in icmp.c
+ */
+static inline __sum16 ip_compute_csum(const void *buf, int len)
+{
+ return csum_fold (csum_partial(buf, len, 0));
+}
+
+
+#define _HAVE_ARCH_IPV6_CSUM
+static __inline__ __sum16 csum_ipv6_magic(const struct in6_addr *saddr,
+ const struct in6_addr *daddr,
+ __u32 len, __u8 proto,
+ __wsum sum)
+{
+ unsigned long t0, t1, t2, t3;
+
+ len += proto; /* add 16-bit proto + len */
+
+ __asm__ __volatile__ (
+
+#if BITS_PER_LONG > 32
+
+ /*
+ ** We can execute two loads and two adds per cycle on PA 8000.
+ ** But add insn's get serialized waiting for the carry bit.
+ ** Try to keep 4 registers with "live" values ahead of the ALU.
+ */
+
+" ldd,ma 8(%1), %4\n" /* get 1st saddr word */
+" ldd,ma 8(%2), %5\n" /* get 1st daddr word */
+" add %4, %0, %0\n"
+" ldd,ma 8(%1), %6\n" /* 2nd saddr */
+" ldd,ma 8(%2), %7\n" /* 2nd daddr */
+" add,dc %5, %0, %0\n"
+" add,dc %6, %0, %0\n"
+" add,dc %7, %0, %0\n"
+" add,dc %3, %0, %0\n" /* fold in proto+len | carry bit */
+" extrd,u %0, 31, 32, %4\n"/* copy upper half down */
+" depdi 0, 31, 32, %0\n"/* clear upper half */
+" add %4, %0, %0\n" /* fold into 32-bits */
+" addc 0, %0, %0\n" /* add carry */
+
+#else
+
+ /*
+ ** For PA 1.x, the insn order doesn't matter as much.
+ ** Insn stream is serialized on the carry bit here too.
+ ** result from the previous operation (eg r0 + x)
+ */
+" ldw,ma 4(%1), %4\n" /* get 1st saddr word */
+" ldw,ma 4(%2), %5\n" /* get 1st daddr word */
+" add %4, %0, %0\n"
+" ldw,ma 4(%1), %6\n" /* 2nd saddr */
+" addc %5, %0, %0\n"
+" ldw,ma 4(%2), %7\n" /* 2nd daddr */
+" addc %6, %0, %0\n"
+" ldw,ma 4(%1), %4\n" /* 3rd saddr */
+" addc %7, %0, %0\n"
+" ldw,ma 4(%2), %5\n" /* 3rd daddr */
+" addc %4, %0, %0\n"
+" ldw,ma 4(%1), %6\n" /* 4th saddr */
+" addc %5, %0, %0\n"
+" ldw,ma 4(%2), %7\n" /* 4th daddr */
+" addc %6, %0, %0\n"
+" addc %7, %0, %0\n"
+" addc %3, %0, %0\n" /* fold in proto+len, catch carry */
+
+#endif
+ : "=r" (sum), "=r" (saddr), "=r" (daddr), "=r" (len),
+ "=r" (t0), "=r" (t1), "=r" (t2), "=r" (t3)
+ : "0" (sum), "1" (saddr), "2" (daddr), "3" (len)
+ : "memory");
+ return csum_fold(sum);
+}
+
+#endif
+
diff --git a/arch/parisc/include/asm/cmpxchg.h b/arch/parisc/include/asm/cmpxchg.h
new file mode 100644
index 000000000..c1d776bb1
--- /dev/null
+++ b/arch/parisc/include/asm/cmpxchg.h
@@ -0,0 +1,124 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * forked from parisc asm/atomic.h which was:
+ * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
+ * Copyright (C) 2006 Kyle McMartin <kyle@parisc-linux.org>
+ */
+
+#ifndef _ASM_PARISC_CMPXCHG_H_
+#define _ASM_PARISC_CMPXCHG_H_
+
+/* This should get optimized out since it's never called.
+** Or get a link error if xchg is used "wrong".
+*/
+extern void __xchg_called_with_bad_pointer(void);
+
+/* __xchg32/64 defined in arch/parisc/lib/bitops.c */
+extern unsigned long __xchg8(char, volatile char *);
+extern unsigned long __xchg32(int, volatile int *);
+#ifdef CONFIG_64BIT
+extern unsigned long __xchg64(unsigned long, volatile unsigned long *);
+#endif
+
+/* optimizer better get rid of switch since size is a constant */
+static inline unsigned long
+__arch_xchg(unsigned long x, volatile void *ptr, int size)
+{
+ switch (size) {
+#ifdef CONFIG_64BIT
+ case 8: return __xchg64(x, (volatile unsigned long *) ptr);
+#endif
+ case 4: return __xchg32((int) x, (volatile int *) ptr);
+ case 1: return __xchg8((char) x, (volatile char *) ptr);
+ }
+ __xchg_called_with_bad_pointer();
+ return x;
+}
+
+/*
+** REVISIT - Abandoned use of LDCW in xchg() for now:
+** o need to test sizeof(*ptr) to avoid clearing adjacent bytes
+** o and while we are at it, could CONFIG_64BIT code use LDCD too?
+**
+** if (__builtin_constant_p(x) && (x == NULL))
+** if (((unsigned long)p & 0xf) == 0)
+** return __ldcw(p);
+*/
+#define arch_xchg(ptr, x) \
+({ \
+ __typeof__(*(ptr)) __ret; \
+ __typeof__(*(ptr)) _x_ = (x); \
+ __ret = (__typeof__(*(ptr))) \
+ __arch_xchg((unsigned long)_x_, (ptr), sizeof(*(ptr))); \
+ __ret; \
+})
+
+/* bug catcher for when unsupported size is used - won't link */
+extern void __cmpxchg_called_with_bad_pointer(void);
+
+/* __cmpxchg_u32/u64 defined in arch/parisc/lib/bitops.c */
+extern unsigned long __cmpxchg_u32(volatile unsigned int *m, unsigned int old,
+ unsigned int new_);
+extern u64 __cmpxchg_u64(volatile u64 *ptr, u64 old, u64 new_);
+extern u8 __cmpxchg_u8(volatile u8 *ptr, u8 old, u8 new_);
+
+/* don't worry...optimizer will get rid of most of this */
+static inline unsigned long
+__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new_, int size)
+{
+ switch (size) {
+#ifdef CONFIG_64BIT
+ case 8: return __cmpxchg_u64((u64 *)ptr, old, new_);
+#endif
+ case 4: return __cmpxchg_u32((unsigned int *)ptr,
+ (unsigned int)old, (unsigned int)new_);
+ case 1: return __cmpxchg_u8((u8 *)ptr, old & 0xff, new_ & 0xff);
+ }
+ __cmpxchg_called_with_bad_pointer();
+ return old;
+}
+
+#define arch_cmpxchg(ptr, o, n) \
+({ \
+ __typeof__(*(ptr)) _o_ = (o); \
+ __typeof__(*(ptr)) _n_ = (n); \
+ (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_, \
+ (unsigned long)_n_, sizeof(*(ptr))); \
+})
+
+#include <asm-generic/cmpxchg-local.h>
+
+static inline unsigned long __cmpxchg_local(volatile void *ptr,
+ unsigned long old,
+ unsigned long new_, int size)
+{
+ switch (size) {
+#ifdef CONFIG_64BIT
+ case 8: return __cmpxchg_u64((u64 *)ptr, old, new_);
+#endif
+ case 4: return __cmpxchg_u32(ptr, old, new_);
+ default:
+ return __generic_cmpxchg_local(ptr, old, new_, size);
+ }
+}
+
+/*
+ * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make
+ * them available.
+ */
+#define arch_cmpxchg_local(ptr, o, n) \
+ ((__typeof__(*(ptr)))__cmpxchg_local((ptr), (unsigned long)(o), \
+ (unsigned long)(n), sizeof(*(ptr))))
+#ifdef CONFIG_64BIT
+#define arch_cmpxchg64_local(ptr, o, n) \
+({ \
+ BUILD_BUG_ON(sizeof(*(ptr)) != 8); \
+ cmpxchg_local((ptr), (o), (n)); \
+})
+#else
+#define arch_cmpxchg64_local(ptr, o, n) __generic_cmpxchg64_local((ptr), (o), (n))
+#endif
+
+#define arch_cmpxchg64(ptr, o, n) __cmpxchg_u64(ptr, o, n)
+
+#endif /* _ASM_PARISC_CMPXCHG_H_ */
diff --git a/arch/parisc/include/asm/compat.h b/arch/parisc/include/asm/compat.h
new file mode 100644
index 000000000..339d1b833
--- /dev/null
+++ b/arch/parisc/include/asm/compat.h
@@ -0,0 +1,141 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_PARISC_COMPAT_H
+#define _ASM_PARISC_COMPAT_H
+/*
+ * Architecture specific compatibility types
+ */
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/thread_info.h>
+
+#define compat_mode_t compat_mode_t
+typedef u16 compat_mode_t;
+
+#define compat_ipc_pid_t compat_ipc_pid_t
+typedef u16 compat_ipc_pid_t;
+
+#define compat_ipc64_perm compat_ipc64_perm
+
+#include <asm-generic/compat.h>
+
+#define COMPAT_UTS_MACHINE "parisc\0\0"
+
+typedef u16 compat_nlink_t;
+
+struct compat_stat {
+ compat_dev_t st_dev; /* dev_t is 32 bits on parisc */
+ compat_ino_t st_ino; /* 32 bits */
+ compat_mode_t st_mode; /* 16 bits */
+ compat_nlink_t st_nlink; /* 16 bits */
+ u16 st_reserved1; /* old st_uid */
+ u16 st_reserved2; /* old st_gid */
+ compat_dev_t st_rdev;
+ compat_off_t st_size;
+ old_time32_t st_atime;
+ u32 st_atime_nsec;
+ old_time32_t st_mtime;
+ u32 st_mtime_nsec;
+ old_time32_t st_ctime;
+ u32 st_ctime_nsec;
+ s32 st_blksize;
+ s32 st_blocks;
+ u32 __unused1; /* ACL stuff */
+ compat_dev_t __unused2; /* network */
+ compat_ino_t __unused3; /* network */
+ u32 __unused4; /* cnodes */
+ u16 __unused5; /* netsite */
+ short st_fstype;
+ compat_dev_t st_realdev;
+ u16 st_basemode;
+ u16 st_spareshort;
+ __compat_uid32_t st_uid;
+ __compat_gid32_t st_gid;
+ u32 st_spare4[3];
+};
+
+struct compat_sigcontext {
+ compat_int_t sc_flags;
+ compat_int_t sc_gr[32]; /* PSW in sc_gr[0] */
+ u64 sc_fr[32];
+ compat_int_t sc_iasq[2];
+ compat_int_t sc_iaoq[2];
+ compat_int_t sc_sar; /* cr11 */
+};
+
+struct compat_ipc64_perm {
+ compat_key_t key;
+ __compat_uid_t uid;
+ __compat_gid_t gid;
+ __compat_uid_t cuid;
+ __compat_gid_t cgid;
+ unsigned short int __pad1;
+ compat_mode_t mode;
+ unsigned short int __pad2;
+ unsigned short int seq;
+ unsigned int __pad3;
+ unsigned long __unused1; /* yes they really are 64bit pads */
+ unsigned long __unused2;
+};
+
+struct compat_semid64_ds {
+ struct compat_ipc64_perm sem_perm;
+ unsigned int sem_otime_high;
+ unsigned int sem_otime;
+ unsigned int sem_ctime_high;
+ unsigned int sem_ctime;
+ compat_ulong_t sem_nsems;
+ compat_ulong_t __unused3;
+ compat_ulong_t __unused4;
+};
+
+struct compat_msqid64_ds {
+ struct compat_ipc64_perm msg_perm;
+ unsigned int msg_stime_high;
+ unsigned int msg_stime;
+ unsigned int msg_rtime_high;
+ unsigned int msg_rtime;
+ unsigned int msg_ctime_high;
+ unsigned int msg_ctime;
+ compat_ulong_t msg_cbytes;
+ compat_ulong_t msg_qnum;
+ compat_ulong_t msg_qbytes;
+ compat_pid_t msg_lspid;
+ compat_pid_t msg_lrpid;
+ compat_ulong_t __unused4;
+ compat_ulong_t __unused5;
+};
+
+struct compat_shmid64_ds {
+ struct compat_ipc64_perm shm_perm;
+ unsigned int shm_atime_high;
+ unsigned int shm_atime;
+ unsigned int shm_dtime_high;
+ unsigned int shm_dtime;
+ unsigned int shm_ctime_high;
+ unsigned int shm_ctime;
+ unsigned int __unused4;
+ compat_size_t shm_segsz;
+ compat_pid_t shm_cpid;
+ compat_pid_t shm_lpid;
+ compat_ulong_t shm_nattch;
+ compat_ulong_t __unused5;
+ compat_ulong_t __unused6;
+};
+
+/*
+ * The type of struct elf_prstatus.pr_reg in compatible core dumps.
+ */
+#define COMPAT_ELF_NGREG 80
+typedef compat_ulong_t compat_elf_gregset_t[COMPAT_ELF_NGREG];
+
+static inline int __is_compat_task(struct task_struct *t)
+{
+ return test_tsk_thread_flag(t, TIF_32BIT);
+}
+
+static inline int is_compat_task(void)
+{
+ return __is_compat_task(current);
+}
+
+#endif /* _ASM_PARISC_COMPAT_H */
diff --git a/arch/parisc/include/asm/compat_ucontext.h b/arch/parisc/include/asm/compat_ucontext.h
new file mode 100644
index 000000000..c606f1bc8
--- /dev/null
+++ b/arch/parisc/include/asm/compat_ucontext.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_PARISC_COMPAT_UCONTEXT_H
+#define _ASM_PARISC_COMPAT_UCONTEXT_H
+
+#include <linux/compat.h>
+
+/* 32-bit ucontext as seen from an 64-bit kernel */
+struct compat_ucontext {
+ compat_uint_t uc_flags;
+ compat_uptr_t uc_link;
+ compat_stack_t uc_stack; /* struct compat_sigaltstack (12 bytes)*/
+ /* FIXME: Pad out to get uc_mcontext to start at an 8-byte aligned boundary */
+ compat_uint_t pad[1];
+ struct compat_sigcontext uc_mcontext;
+ compat_sigset_t uc_sigmask; /* mask last for extensibility */
+};
+
+#endif /* !_ASM_PARISC_COMPAT_UCONTEXT_H */
diff --git a/arch/parisc/include/asm/current.h b/arch/parisc/include/asm/current.h
new file mode 100644
index 000000000..dc7aea07c
--- /dev/null
+++ b/arch/parisc/include/asm/current.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_PARISC_CURRENT_H
+#define _ASM_PARISC_CURRENT_H
+
+#ifndef __ASSEMBLY__
+struct task_struct;
+
+static __always_inline struct task_struct *get_current(void)
+{
+ struct task_struct *ts;
+
+ /* do not use mfctl() macro as it is marked volatile */
+ asm( "mfctl %%cr30,%0" : "=r" (ts) );
+ return ts;
+}
+
+#define current get_current()
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_PARISC_CURRENT_H */
diff --git a/arch/parisc/include/asm/delay.h b/arch/parisc/include/asm/delay.h
new file mode 100644
index 000000000..841b506b7
--- /dev/null
+++ b/arch/parisc/include/asm/delay.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_PARISC_DELAY_H
+#define _ASM_PARISC_DELAY_H
+
+static __inline__ void __delay(unsigned long loops) {
+ asm volatile(
+ " .balignl 64,0x34000034\n"
+ " addib,UV -1,%0,.\n"
+ " nop\n"
+ : "=r" (loops) : "0" (loops));
+}
+
+extern void __udelay(unsigned long usecs);
+extern void __udelay_bad(unsigned long usecs);
+
+static inline void udelay(unsigned long usecs)
+{
+ if (__builtin_constant_p(usecs) && (usecs) > 20000)
+ __udelay_bad(usecs);
+ __udelay(usecs);
+}
+
+#endif /* _ASM_PARISC_DELAY_H */
diff --git a/arch/parisc/include/asm/dma-mapping.h b/arch/parisc/include/asm/dma-mapping.h
new file mode 100644
index 000000000..635665004
--- /dev/null
+++ b/arch/parisc/include/asm/dma-mapping.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _PARISC_DMA_MAPPING_H
+#define _PARISC_DMA_MAPPING_H
+
+/*
+** We need to support 4 different coherent dma models with one binary:
+**
+** I/O MMU consistent method dma_sync behavior
+** ============= ====================== =======================
+** a) PA-7x00LC uncachable host memory flush/purge
+** b) U2/Uturn cachable host memory NOP
+** c) Ike/Astro cachable host memory NOP
+** d) EPIC/SAGA memory on EPIC/SAGA flush/reset DMA channel
+**
+** PA-7[13]00LC processors have a GSC bus interface and no I/O MMU.
+**
+** Systems (eg PCX-T workstations) that don't fall into the above
+** categories will need to modify the needed drivers to perform
+** flush/purge and allocate "regular" cacheable pages for everything.
+*/
+
+extern const struct dma_map_ops *hppa_dma_ops;
+
+static inline const struct dma_map_ops *get_arch_dma_ops(void)
+{
+ return hppa_dma_ops;
+}
+
+#endif
diff --git a/arch/parisc/include/asm/dma.h b/arch/parisc/include/asm/dma.h
new file mode 100644
index 000000000..582fb5d1a
--- /dev/null
+++ b/arch/parisc/include/asm/dma.h
@@ -0,0 +1,181 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* asm/dma.h: Defines for using and allocating dma channels.
+ * Written by Hennus Bergman, 1992.
+ * High DMA channel support & info by Hannu Savolainen
+ * and John Boyd, Nov. 1992.
+ * (c) Copyright 2000, Grant Grundler
+ */
+
+#ifndef _ASM_DMA_H
+#define _ASM_DMA_H
+
+#include <asm/io.h> /* need byte IO */
+
+#define dma_outb outb
+#define dma_inb inb
+
+extern unsigned long pcxl_dma_start;
+
+/*
+** DMA_CHUNK_SIZE is used by the SCSI mid-layer to break up
+** (or rather not merge) DMAs into manageable chunks.
+** On parisc, this is more of the software/tuning constraint
+** rather than the HW. I/O MMU allocation algorithms can be
+** faster with smaller sizes (to some degree).
+*/
+#define DMA_CHUNK_SIZE (BITS_PER_LONG*PAGE_SIZE)
+
+/* The maximum address that we can perform a DMA transfer to on this platform
+** New dynamic DMA interfaces should obsolete this....
+*/
+#define MAX_DMA_ADDRESS (~0UL)
+
+/*
+** We don't have DMA channels... well V-class does but the
+** Dynamic DMA Mapping interface will support them... right? :^)
+** Note: this is not relevant right now for PA-RISC, but we cannot
+** leave this as undefined because some things (e.g. sound)
+** won't compile :-(
+*/
+#define MAX_DMA_CHANNELS 8
+#define DMA_MODE_READ 0x44 /* I/O to memory, no autoinit, increment, single mode */
+#define DMA_MODE_WRITE 0x48 /* memory to I/O, no autoinit, increment, single mode */
+#define DMA_MODE_CASCADE 0xC0 /* pass thru DREQ->HRQ, DACK<-HLDA only */
+
+#define DMA_AUTOINIT 0x10
+
+/* 8237 DMA controllers */
+#define IO_DMA1_BASE 0x00 /* 8 bit slave DMA, channels 0..3 */
+#define IO_DMA2_BASE 0xC0 /* 16 bit master DMA, ch 4(=slave input)..7 */
+
+/* DMA controller registers */
+#define DMA1_CMD_REG 0x08 /* command register (w) */
+#define DMA1_STAT_REG 0x08 /* status register (r) */
+#define DMA1_REQ_REG 0x09 /* request register (w) */
+#define DMA1_MASK_REG 0x0A /* single-channel mask (w) */
+#define DMA1_MODE_REG 0x0B /* mode register (w) */
+#define DMA1_CLEAR_FF_REG 0x0C /* clear pointer flip-flop (w) */
+#define DMA1_TEMP_REG 0x0D /* Temporary Register (r) */
+#define DMA1_RESET_REG 0x0D /* Master Clear (w) */
+#define DMA1_CLR_MASK_REG 0x0E /* Clear Mask */
+#define DMA1_MASK_ALL_REG 0x0F /* all-channels mask (w) */
+#define DMA1_EXT_MODE_REG (0x400 | DMA1_MODE_REG)
+
+#define DMA2_CMD_REG 0xD0 /* command register (w) */
+#define DMA2_STAT_REG 0xD0 /* status register (r) */
+#define DMA2_REQ_REG 0xD2 /* request register (w) */
+#define DMA2_MASK_REG 0xD4 /* single-channel mask (w) */
+#define DMA2_MODE_REG 0xD6 /* mode register (w) */
+#define DMA2_CLEAR_FF_REG 0xD8 /* clear pointer flip-flop (w) */
+#define DMA2_TEMP_REG 0xDA /* Temporary Register (r) */
+#define DMA2_RESET_REG 0xDA /* Master Clear (w) */
+#define DMA2_CLR_MASK_REG 0xDC /* Clear Mask */
+#define DMA2_MASK_ALL_REG 0xDE /* all-channels mask (w) */
+#define DMA2_EXT_MODE_REG (0x400 | DMA2_MODE_REG)
+
+static __inline__ unsigned long claim_dma_lock(void)
+{
+ return 0;
+}
+
+static __inline__ void release_dma_lock(unsigned long flags)
+{
+}
+
+
+/* Get DMA residue count. After a DMA transfer, this
+ * should return zero. Reading this while a DMA transfer is
+ * still in progress will return unpredictable results.
+ * If called before the channel has been used, it may return 1.
+ * Otherwise, it returns the number of _bytes_ left to transfer.
+ *
+ * Assumes DMA flip-flop is clear.
+ */
+static __inline__ int get_dma_residue(unsigned int dmanr)
+{
+ unsigned int io_port = (dmanr<=3)? ((dmanr&3)<<1) + 1 + IO_DMA1_BASE
+ : ((dmanr&3)<<2) + 2 + IO_DMA2_BASE;
+
+ /* using short to get 16-bit wrap around */
+ unsigned short count;
+
+ count = 1 + dma_inb(io_port);
+ count += dma_inb(io_port) << 8;
+
+ return (dmanr<=3)? count : (count<<1);
+}
+
+/* enable/disable a specific DMA channel */
+static __inline__ void enable_dma(unsigned int dmanr)
+{
+#ifdef CONFIG_SUPERIO
+ if (dmanr<=3)
+ dma_outb(dmanr, DMA1_MASK_REG);
+ else
+ dma_outb(dmanr & 3, DMA2_MASK_REG);
+#endif
+}
+
+static __inline__ void disable_dma(unsigned int dmanr)
+{
+#ifdef CONFIG_SUPERIO
+ if (dmanr<=3)
+ dma_outb(dmanr | 4, DMA1_MASK_REG);
+ else
+ dma_outb((dmanr & 3) | 4, DMA2_MASK_REG);
+#endif
+}
+
+/* reserve a DMA channel */
+#define request_dma(dmanr, device_id) (0)
+
+/* Clear the 'DMA Pointer Flip Flop'.
+ * Write 0 for LSB/MSB, 1 for MSB/LSB access.
+ * Use this once to initialize the FF to a known state.
+ * After that, keep track of it. :-)
+ * --- In order to do that, the DMA routines below should ---
+ * --- only be used while holding the DMA lock ! ---
+ */
+static __inline__ void clear_dma_ff(unsigned int dmanr)
+{
+}
+
+/* set mode (above) for a specific DMA channel */
+static __inline__ void set_dma_mode(unsigned int dmanr, char mode)
+{
+}
+
+/* Set only the page register bits of the transfer address.
+ * This is used for successive transfers when we know the contents of
+ * the lower 16 bits of the DMA current address register, but a 64k boundary
+ * may have been crossed.
+ */
+static __inline__ void set_dma_page(unsigned int dmanr, char pagenr)
+{
+}
+
+
+/* Set transfer address & page bits for specific DMA channel.
+ * Assumes dma flipflop is clear.
+ */
+static __inline__ void set_dma_addr(unsigned int dmanr, unsigned int a)
+{
+}
+
+
+/* Set transfer size (max 64k for DMA1..3, 128k for DMA5..7) for
+ * a specific DMA channel.
+ * You must ensure the parameters are valid.
+ * NOTE: from a manual: "the number of transfers is one more
+ * than the initial word count"! This is taken into account.
+ * Assumes dma flip-flop is clear.
+ * NOTE 2: "count" represents _bytes_ and must be even for channels 5-7.
+ */
+static __inline__ void set_dma_count(unsigned int dmanr, unsigned int count)
+{
+}
+
+
+#define free_dma(dmanr)
+
+#endif /* _ASM_DMA_H */
diff --git a/arch/parisc/include/asm/dwarf.h b/arch/parisc/include/asm/dwarf.h
new file mode 100644
index 000000000..f4512db86
--- /dev/null
+++ b/arch/parisc/include/asm/dwarf.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2016 Helge Deller <deller@gmx.de>
+ */
+
+#ifndef _ASM_PARISC_DWARF_H
+#define _ASM_PARISC_DWARF_H
+
+#ifdef __ASSEMBLY__
+
+#define CFI_STARTPROC .cfi_startproc
+#define CFI_ENDPROC .cfi_endproc
+#define CFI_DEF_CFA .cfi_def_cfa
+#define CFI_REGISTER .cfi_register
+#define CFI_REL_OFFSET .cfi_rel_offset
+#define CFI_UNDEFINED .cfi_undefined
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_PARISC_DWARF_H */
diff --git a/arch/parisc/include/asm/eisa_bus.h b/arch/parisc/include/asm/eisa_bus.h
new file mode 100644
index 000000000..55dba9cd4
--- /dev/null
+++ b/arch/parisc/include/asm/eisa_bus.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * eisa_bus.h interface between the eisa BA driver and the bus enumerator
+ *
+ * Copyright (c) 2002 Daniel Engstrom <5116@telia.com>
+ */
+
+#ifndef ASM_EISA_H
+#define ASM_EISA_H
+
+extern void eisa_make_irq_level(int num);
+extern void eisa_make_irq_edge(int num);
+extern int eisa_enumerator(unsigned long eeprom_addr,
+ struct resource *io_parent,
+ struct resource *mem_parent);
+extern int eisa_eeprom_init(unsigned long addr);
+
+#endif
diff --git a/arch/parisc/include/asm/eisa_eeprom.h b/arch/parisc/include/asm/eisa_eeprom.h
new file mode 100644
index 000000000..fdac7fc94
--- /dev/null
+++ b/arch/parisc/include/asm/eisa_eeprom.h
@@ -0,0 +1,148 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * eisa_eeprom.h - provide support for EISA adapters in PA-RISC machines
+ *
+ * Copyright (c) 2001, 2002 Daniel Engstrom <5116@telia.com>
+ */
+
+#ifndef ASM_EISA_EEPROM_H
+#define ASM_EISA_EEPROM_H
+
+extern void __iomem *eisa_eeprom_addr;
+
+#define HPEE_MAX_LENGTH 0x2000 /* maximum eeprom length */
+
+#define HPEE_SLOT_INFO(slot) (20+(48*slot))
+
+struct eeprom_header
+{
+
+ u_int32_t num_writes; /* number of writes */
+ u_int8_t flags; /* flags, usage? */
+ u_int8_t ver_maj;
+ u_int8_t ver_min;
+ u_int8_t num_slots; /* number of EISA slots in system */
+ u_int16_t csum; /* checksum, I don't know how to calculate this */
+ u_int8_t pad[10];
+} __attribute__ ((packed));
+
+
+struct eeprom_eisa_slot_info
+{
+ u_int32_t eisa_slot_id;
+ u_int32_t config_data_offset;
+ u_int32_t num_writes;
+ u_int16_t csum;
+ u_int16_t num_functions;
+ u_int16_t config_data_length;
+
+ /* bits 0..3 are the duplicate slot id */
+#define HPEE_SLOT_INFO_EMBEDDED 0x10
+#define HPEE_SLOT_INFO_VIRTUAL 0x20
+#define HPEE_SLOT_INFO_NO_READID 0x40
+#define HPEE_SLOT_INFO_DUPLICATE 0x80
+ u_int8_t slot_info;
+
+#define HPEE_SLOT_FEATURES_ENABLE 0x01
+#define HPEE_SLOT_FEATURES_IOCHK 0x02
+#define HPEE_SLOT_FEATURES_CFG_INCOMPLETE 0x80
+ u_int8_t slot_features;
+
+ u_int8_t ver_min;
+ u_int8_t ver_maj;
+
+#define HPEE_FUNCTION_INFO_HAVE_TYPE 0x01
+#define HPEE_FUNCTION_INFO_HAVE_MEMORY 0x02
+#define HPEE_FUNCTION_INFO_HAVE_IRQ 0x04
+#define HPEE_FUNCTION_INFO_HAVE_DMA 0x08
+#define HPEE_FUNCTION_INFO_HAVE_PORT 0x10
+#define HPEE_FUNCTION_INFO_HAVE_PORT_INIT 0x20
+/* I think there are two slighty different
+ * versions of the function_info field
+ * one int the fixed header and one optional
+ * in the parsed slot data area */
+#define HPEE_FUNCTION_INFO_HAVE_FUNCTION 0x01
+#define HPEE_FUNCTION_INFO_F_DISABLED 0x80
+#define HPEE_FUNCTION_INFO_CFG_FREE_FORM 0x40
+ u_int8_t function_info;
+
+#define HPEE_FLAG_BOARD_IS_ISA 0x01 /* flag and minor version for isa board */
+ u_int8_t flags;
+ u_int8_t pad[24];
+} __attribute__ ((packed));
+
+
+#define HPEE_MEMORY_MAX_ENT 9
+/* memory descriptor: byte 0 */
+#define HPEE_MEMORY_WRITABLE 0x01
+#define HPEE_MEMORY_CACHABLE 0x02
+#define HPEE_MEMORY_TYPE_MASK 0x18
+#define HPEE_MEMORY_TYPE_SYS 0x00
+#define HPEE_MEMORY_TYPE_EXP 0x08
+#define HPEE_MEMORY_TYPE_VIR 0x10
+#define HPEE_MEMORY_TYPE_OTH 0x18
+#define HPEE_MEMORY_SHARED 0x20
+#define HPEE_MEMORY_MORE 0x80
+
+/* memory descriptor: byte 1 */
+#define HPEE_MEMORY_WIDTH_MASK 0x03
+#define HPEE_MEMORY_WIDTH_BYTE 0x00
+#define HPEE_MEMORY_WIDTH_WORD 0x01
+#define HPEE_MEMORY_WIDTH_DWORD 0x02
+#define HPEE_MEMORY_DECODE_MASK 0x0c
+#define HPEE_MEMORY_DECODE_20BITS 0x00
+#define HPEE_MEMORY_DECODE_24BITS 0x04
+#define HPEE_MEMORY_DECODE_32BITS 0x08
+/* byte 2 and 3 are a 16bit LE value
+ * containing the memory size in kilobytes */
+/* byte 4,5,6 are a 24bit LE value
+ * containing the memory base address */
+
+
+#define HPEE_IRQ_MAX_ENT 7
+/* Interrupt entry: byte 0 */
+#define HPEE_IRQ_CHANNEL_MASK 0xf
+#define HPEE_IRQ_TRIG_LEVEL 0x20
+#define HPEE_IRQ_MORE 0x80
+/* byte 1 seems to be unused */
+
+#define HPEE_DMA_MAX_ENT 4
+
+/* dma entry: byte 0 */
+#define HPEE_DMA_CHANNEL_MASK 7
+#define HPEE_DMA_SIZE_MASK 0xc
+#define HPEE_DMA_SIZE_BYTE 0x0
+#define HPEE_DMA_SIZE_WORD 0x4
+#define HPEE_DMA_SIZE_DWORD 0x8
+#define HPEE_DMA_SHARED 0x40
+#define HPEE_DMA_MORE 0x80
+
+/* dma entry: byte 1 */
+#define HPEE_DMA_TIMING_MASK 0x30
+#define HPEE_DMA_TIMING_ISA 0x0
+#define HPEE_DMA_TIMING_TYPEA 0x10
+#define HPEE_DMA_TIMING_TYPEB 0x20
+#define HPEE_DMA_TIMING_TYPEC 0x30
+
+#define HPEE_PORT_MAX_ENT 20
+/* port entry byte 0 */
+#define HPEE_PORT_SIZE_MASK 0x1f
+#define HPEE_PORT_SHARED 0x40
+#define HPEE_PORT_MORE 0x80
+/* byte 1 and 2 is a 16bit LE value
+ * containing the start port number */
+
+#define HPEE_PORT_INIT_MAX_LEN 60 /* in bytes here */
+/* port init entry byte 0 */
+#define HPEE_PORT_INIT_WIDTH_MASK 0x3
+#define HPEE_PORT_INIT_WIDTH_BYTE 0x0
+#define HPEE_PORT_INIT_WIDTH_WORD 0x1
+#define HPEE_PORT_INIT_WIDTH_DWORD 0x2
+#define HPEE_PORT_INIT_MASK 0x4
+#define HPEE_PORT_INIT_MORE 0x80
+
+#define HPEE_SELECTION_MAX_ENT 26
+
+#define HPEE_TYPE_MAX_LEN 80
+
+#endif
diff --git a/arch/parisc/include/asm/elf.h b/arch/parisc/include/asm/elf.h
new file mode 100644
index 000000000..2d73d3c3c
--- /dev/null
+++ b/arch/parisc/include/asm/elf.h
@@ -0,0 +1,368 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASMPARISC_ELF_H
+#define __ASMPARISC_ELF_H
+
+/*
+ * ELF register definitions..
+ */
+
+#include <linux/types.h>
+
+#define EM_PARISC 15
+
+/* HPPA specific definitions. */
+
+/* Legal values for e_flags field of Elf32_Ehdr. */
+
+#define EF_PARISC_TRAPNIL 0x00010000 /* Trap nil pointer dereference. */
+#define EF_PARISC_EXT 0x00020000 /* Program uses arch. extensions. */
+#define EF_PARISC_LSB 0x00040000 /* Program expects little endian. */
+#define EF_PARISC_WIDE 0x00080000 /* Program expects wide mode. */
+#define EF_PARISC_NO_KABP 0x00100000 /* No kernel assisted branch
+ prediction. */
+#define EF_PARISC_LAZYSWAP 0x00400000 /* Allow lazy swapping. */
+#define EF_PARISC_ARCH 0x0000ffff /* Architecture version. */
+
+/* Defined values for `e_flags & EF_PARISC_ARCH' are: */
+
+#define EFA_PARISC_1_0 0x020b /* PA-RISC 1.0 big-endian. */
+#define EFA_PARISC_1_1 0x0210 /* PA-RISC 1.1 big-endian. */
+#define EFA_PARISC_2_0 0x0214 /* PA-RISC 2.0 big-endian. */
+
+/* Additional section indices. */
+
+#define SHN_PARISC_ANSI_COMMON 0xff00 /* Section for tenatively declared
+ symbols in ANSI C. */
+#define SHN_PARISC_HUGE_COMMON 0xff01 /* Common blocks in huge model. */
+
+/* Legal values for sh_type field of Elf32_Shdr. */
+
+#define SHT_PARISC_EXT 0x70000000 /* Contains product specific ext. */
+#define SHT_PARISC_UNWIND 0x70000001 /* Unwind information. */
+#define SHT_PARISC_DOC 0x70000002 /* Debug info for optimized code. */
+
+/* Legal values for sh_flags field of Elf32_Shdr. */
+
+#define SHF_PARISC_SHORT 0x20000000 /* Section with short addressing. */
+#define SHF_PARISC_HUGE 0x40000000 /* Section far from gp. */
+#define SHF_PARISC_SBP 0x80000000 /* Static branch prediction code. */
+
+/* Legal values for ST_TYPE subfield of st_info (symbol type). */
+
+#define STT_PARISC_MILLICODE 13 /* Millicode function entry point. */
+
+#define STT_HP_OPAQUE (STT_LOOS + 0x1)
+#define STT_HP_STUB (STT_LOOS + 0x2)
+
+/* HPPA relocs. */
+
+#define R_PARISC_NONE 0 /* No reloc. */
+#define R_PARISC_DIR32 1 /* Direct 32-bit reference. */
+#define R_PARISC_DIR21L 2 /* Left 21 bits of eff. address. */
+#define R_PARISC_DIR17R 3 /* Right 17 bits of eff. address. */
+#define R_PARISC_DIR17F 4 /* 17 bits of eff. address. */
+#define R_PARISC_DIR14R 6 /* Right 14 bits of eff. address. */
+#define R_PARISC_PCREL32 9 /* 32-bit rel. address. */
+#define R_PARISC_PCREL21L 10 /* Left 21 bits of rel. address. */
+#define R_PARISC_PCREL17R 11 /* Right 17 bits of rel. address. */
+#define R_PARISC_PCREL17F 12 /* 17 bits of rel. address. */
+#define R_PARISC_PCREL14R 14 /* Right 14 bits of rel. address. */
+#define R_PARISC_DPREL21L 18 /* Left 21 bits of rel. address. */
+#define R_PARISC_DPREL14R 22 /* Right 14 bits of rel. address. */
+#define R_PARISC_GPREL21L 26 /* GP-relative, left 21 bits. */
+#define R_PARISC_GPREL14R 30 /* GP-relative, right 14 bits. */
+#define R_PARISC_LTOFF21L 34 /* LT-relative, left 21 bits. */
+#define R_PARISC_LTOFF14R 38 /* LT-relative, right 14 bits. */
+#define R_PARISC_SECREL32 41 /* 32 bits section rel. address. */
+#define R_PARISC_SEGBASE 48 /* No relocation, set segment base. */
+#define R_PARISC_SEGREL32 49 /* 32 bits segment rel. address. */
+#define R_PARISC_PLTOFF21L 50 /* PLT rel. address, left 21 bits. */
+#define R_PARISC_PLTOFF14R 54 /* PLT rel. address, right 14 bits. */
+#define R_PARISC_LTOFF_FPTR32 57 /* 32 bits LT-rel. function pointer. */
+#define R_PARISC_LTOFF_FPTR21L 58 /* LT-rel. fct ptr, left 21 bits. */
+#define R_PARISC_LTOFF_FPTR14R 62 /* LT-rel. fct ptr, right 14 bits. */
+#define R_PARISC_FPTR64 64 /* 64 bits function address. */
+#define R_PARISC_PLABEL32 65 /* 32 bits function address. */
+#define R_PARISC_PCREL64 72 /* 64 bits PC-rel. address. */
+#define R_PARISC_PCREL22F 74 /* 22 bits PC-rel. address. */
+#define R_PARISC_PCREL14WR 75 /* PC-rel. address, right 14 bits. */
+#define R_PARISC_PCREL14DR 76 /* PC rel. address, right 14 bits. */
+#define R_PARISC_PCREL16F 77 /* 16 bits PC-rel. address. */
+#define R_PARISC_PCREL16WF 78 /* 16 bits PC-rel. address. */
+#define R_PARISC_PCREL16DF 79 /* 16 bits PC-rel. address. */
+#define R_PARISC_DIR64 80 /* 64 bits of eff. address. */
+#define R_PARISC_DIR14WR 83 /* 14 bits of eff. address. */
+#define R_PARISC_DIR14DR 84 /* 14 bits of eff. address. */
+#define R_PARISC_DIR16F 85 /* 16 bits of eff. address. */
+#define R_PARISC_DIR16WF 86 /* 16 bits of eff. address. */
+#define R_PARISC_DIR16DF 87 /* 16 bits of eff. address. */
+#define R_PARISC_GPREL64 88 /* 64 bits of GP-rel. address. */
+#define R_PARISC_GPREL14WR 91 /* GP-rel. address, right 14 bits. */
+#define R_PARISC_GPREL14DR 92 /* GP-rel. address, right 14 bits. */
+#define R_PARISC_GPREL16F 93 /* 16 bits GP-rel. address. */
+#define R_PARISC_GPREL16WF 94 /* 16 bits GP-rel. address. */
+#define R_PARISC_GPREL16DF 95 /* 16 bits GP-rel. address. */
+#define R_PARISC_LTOFF64 96 /* 64 bits LT-rel. address. */
+#define R_PARISC_LTOFF14WR 99 /* LT-rel. address, right 14 bits. */
+#define R_PARISC_LTOFF14DR 100 /* LT-rel. address, right 14 bits. */
+#define R_PARISC_LTOFF16F 101 /* 16 bits LT-rel. address. */
+#define R_PARISC_LTOFF16WF 102 /* 16 bits LT-rel. address. */
+#define R_PARISC_LTOFF16DF 103 /* 16 bits LT-rel. address. */
+#define R_PARISC_SECREL64 104 /* 64 bits section rel. address. */
+#define R_PARISC_SEGREL64 112 /* 64 bits segment rel. address. */
+#define R_PARISC_PLTOFF14WR 115 /* PLT-rel. address, right 14 bits. */
+#define R_PARISC_PLTOFF14DR 116 /* PLT-rel. address, right 14 bits. */
+#define R_PARISC_PLTOFF16F 117 /* 16 bits LT-rel. address. */
+#define R_PARISC_PLTOFF16WF 118 /* 16 bits PLT-rel. address. */
+#define R_PARISC_PLTOFF16DF 119 /* 16 bits PLT-rel. address. */
+#define R_PARISC_LTOFF_FPTR64 120 /* 64 bits LT-rel. function ptr. */
+#define R_PARISC_LTOFF_FPTR14WR 123 /* LT-rel. fct. ptr., right 14 bits. */
+#define R_PARISC_LTOFF_FPTR14DR 124 /* LT-rel. fct. ptr., right 14 bits. */
+#define R_PARISC_LTOFF_FPTR16F 125 /* 16 bits LT-rel. function ptr. */
+#define R_PARISC_LTOFF_FPTR16WF 126 /* 16 bits LT-rel. function ptr. */
+#define R_PARISC_LTOFF_FPTR16DF 127 /* 16 bits LT-rel. function ptr. */
+#define R_PARISC_LORESERVE 128
+#define R_PARISC_COPY 128 /* Copy relocation. */
+#define R_PARISC_IPLT 129 /* Dynamic reloc, imported PLT */
+#define R_PARISC_EPLT 130 /* Dynamic reloc, exported PLT */
+#define R_PARISC_TPREL32 153 /* 32 bits TP-rel. address. */
+#define R_PARISC_TPREL21L 154 /* TP-rel. address, left 21 bits. */
+#define R_PARISC_TPREL14R 158 /* TP-rel. address, right 14 bits. */
+#define R_PARISC_LTOFF_TP21L 162 /* LT-TP-rel. address, left 21 bits. */
+#define R_PARISC_LTOFF_TP14R 166 /* LT-TP-rel. address, right 14 bits.*/
+#define R_PARISC_LTOFF_TP14F 167 /* 14 bits LT-TP-rel. address. */
+#define R_PARISC_TPREL64 216 /* 64 bits TP-rel. address. */
+#define R_PARISC_TPREL14WR 219 /* TP-rel. address, right 14 bits. */
+#define R_PARISC_TPREL14DR 220 /* TP-rel. address, right 14 bits. */
+#define R_PARISC_TPREL16F 221 /* 16 bits TP-rel. address. */
+#define R_PARISC_TPREL16WF 222 /* 16 bits TP-rel. address. */
+#define R_PARISC_TPREL16DF 223 /* 16 bits TP-rel. address. */
+#define R_PARISC_LTOFF_TP64 224 /* 64 bits LT-TP-rel. address. */
+#define R_PARISC_LTOFF_TP14WR 227 /* LT-TP-rel. address, right 14 bits.*/
+#define R_PARISC_LTOFF_TP14DR 228 /* LT-TP-rel. address, right 14 bits.*/
+#define R_PARISC_LTOFF_TP16F 229 /* 16 bits LT-TP-rel. address. */
+#define R_PARISC_LTOFF_TP16WF 230 /* 16 bits LT-TP-rel. address. */
+#define R_PARISC_LTOFF_TP16DF 231 /* 16 bits LT-TP-rel. address. */
+#define R_PARISC_HIRESERVE 255
+
+#define PA_PLABEL_FDESC 0x02 /* bit set if PLABEL points to
+ * a function descriptor, not
+ * an address */
+
+/* The following are PA function descriptors
+ *
+ * addr: the absolute address of the function
+ * gp: either the data pointer (r27) for non-PIC code or
+ * the PLT pointer (r19) for PIC code */
+
+/* Format for the Elf32 Function descriptor */
+typedef struct elf32_fdesc {
+ __u32 addr;
+ __u32 gp;
+} Elf32_Fdesc;
+
+/* Format for the Elf64 Function descriptor */
+typedef struct elf64_fdesc {
+ __u64 dummy[2]; /* used by 64-bit eBPF and tracing functions */
+ __u64 addr;
+ __u64 gp;
+} Elf64_Fdesc;
+
+#ifdef CONFIG_64BIT
+#define Elf_Fdesc Elf64_Fdesc
+#else
+#define Elf_Fdesc Elf32_Fdesc
+#endif /*CONFIG_64BIT*/
+
+/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr. */
+
+#define PT_HP_TLS (PT_LOOS + 0x0)
+#define PT_HP_CORE_NONE (PT_LOOS + 0x1)
+#define PT_HP_CORE_VERSION (PT_LOOS + 0x2)
+#define PT_HP_CORE_KERNEL (PT_LOOS + 0x3)
+#define PT_HP_CORE_COMM (PT_LOOS + 0x4)
+#define PT_HP_CORE_PROC (PT_LOOS + 0x5)
+#define PT_HP_CORE_LOADABLE (PT_LOOS + 0x6)
+#define PT_HP_CORE_STACK (PT_LOOS + 0x7)
+#define PT_HP_CORE_SHM (PT_LOOS + 0x8)
+#define PT_HP_CORE_MMF (PT_LOOS + 0x9)
+#define PT_HP_PARALLEL (PT_LOOS + 0x10)
+#define PT_HP_FASTBIND (PT_LOOS + 0x11)
+#define PT_HP_OPT_ANNOT (PT_LOOS + 0x12)
+#define PT_HP_HSL_ANNOT (PT_LOOS + 0x13)
+#define PT_HP_STACK (PT_LOOS + 0x14)
+
+#define PT_PARISC_ARCHEXT 0x70000000
+#define PT_PARISC_UNWIND 0x70000001
+
+/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr. */
+
+#define PF_PARISC_SBP 0x08000000
+
+#define PF_HP_PAGE_SIZE 0x00100000
+#define PF_HP_FAR_SHARED 0x00200000
+#define PF_HP_NEAR_SHARED 0x00400000
+#define PF_HP_CODE 0x01000000
+#define PF_HP_MODIFY 0x02000000
+#define PF_HP_LAZYSWAP 0x04000000
+#define PF_HP_SBP 0x08000000
+
+/*
+ * This yields a string that ld.so will use to load implementation
+ * specific libraries for optimization. This is more specific in
+ * intent than poking at uname or /proc/cpuinfo.
+ */
+
+#define ELF_PLATFORM ("PARISC")
+
+/*
+ * The following definitions are those for 32-bit ELF binaries on a 32-bit
+ * kernel and for 64-bit binaries on a 64-bit kernel. To run 32-bit binaries
+ * on a 64-bit kernel, fs/compat_binfmt_elf.c defines ELF_CLASS and then
+ * #includes binfmt_elf.c, which then includes this file.
+ */
+#ifndef ELF_CLASS
+
+#ifdef CONFIG_64BIT
+#define ELF_CLASS ELFCLASS64
+#else
+#define ELF_CLASS ELFCLASS32
+#endif
+
+typedef unsigned long elf_greg_t;
+
+#define SET_PERSONALITY(ex) \
+({ \
+ set_personality((current->personality & ~PER_MASK) | PER_LINUX); \
+ clear_thread_flag(TIF_32BIT); \
+ current->thread.map_base = DEFAULT_MAP_BASE; \
+ current->thread.task_size = DEFAULT_TASK_SIZE; \
+ })
+
+#endif /* ! ELF_CLASS */
+
+#define COMPAT_SET_PERSONALITY(ex) \
+({ \
+ if ((ex).e_ident[EI_CLASS] == ELFCLASS32) { \
+ set_thread_flag(TIF_32BIT); \
+ current->thread.map_base = DEFAULT_MAP_BASE32; \
+ current->thread.task_size = DEFAULT_TASK_SIZE32; \
+ } else clear_thread_flag(TIF_32BIT); \
+ })
+
+/*
+ * Fill in general registers in a core dump. This saves pretty
+ * much the same registers as hp-ux, although in a different order.
+ * Registers marked # below are not currently saved in pt_regs, so
+ * we use their current values here.
+ *
+ * gr0..gr31
+ * sr0..sr7
+ * iaoq0..iaoq1
+ * iasq0..iasq1
+ * cr11 (sar)
+ * cr19 (iir)
+ * cr20 (isr)
+ * cr21 (ior)
+ * # cr22 (ipsw)
+ * # cr0 (recovery counter)
+ * # cr24..cr31 (temporary registers)
+ * # cr8,9,12,13 (protection IDs)
+ * # cr10 (scr/ccr)
+ * # cr15 (ext int enable mask)
+ *
+ */
+
+#define ELF_CORE_COPY_REGS(dst, pt) \
+ memset(dst, 0, sizeof(dst)); /* don't leak any "random" bits */ \
+ { int i; \
+ for (i = 0; i < 32; i++) dst[i] = pt->gr[i]; \
+ for (i = 0; i < 8; i++) dst[32 + i] = pt->sr[i]; \
+ } \
+ dst[40] = pt->iaoq[0]; dst[41] = pt->iaoq[1]; \
+ dst[42] = pt->iasq[0]; dst[43] = pt->iasq[1]; \
+ dst[44] = pt->sar; dst[45] = pt->iir; \
+ dst[46] = pt->isr; dst[47] = pt->ior; \
+ dst[48] = mfctl(22); dst[49] = mfctl(0); \
+ dst[50] = mfctl(24); dst[51] = mfctl(25); \
+ dst[52] = mfctl(26); dst[53] = mfctl(27); \
+ dst[54] = mfctl(28); dst[55] = mfctl(29); \
+ dst[56] = mfctl(30); dst[57] = mfctl(31); \
+ dst[58] = mfctl( 8); dst[59] = mfctl( 9); \
+ dst[60] = mfctl(12); dst[61] = mfctl(13); \
+ dst[62] = mfctl(10); dst[63] = mfctl(15);
+
+#define CORE_DUMP_USE_REGSET
+
+#define ELF_NGREG 80 /* We only need 64 at present, but leave space
+ for expansion. */
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+
+#define ELF_NFPREG 32
+typedef double elf_fpreg_t;
+typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
+
+struct task_struct;
+
+struct pt_regs; /* forward declaration... */
+
+
+#define elf_check_arch(x) \
+ ((x)->e_machine == EM_PARISC && (x)->e_ident[EI_CLASS] == ELF_CLASS)
+#define compat_elf_check_arch(x) \
+ ((x)->e_machine == EM_PARISC && (x)->e_ident[EI_CLASS] == ELFCLASS32)
+
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_DATA ELFDATA2MSB
+#define ELF_ARCH EM_PARISC
+#define ELF_OSABI ELFOSABI_LINUX
+
+/* %r23 is set by ld.so to a pointer to a function which might be
+ registered using atexit. This provides a means for the dynamic
+ linker to call DT_FINI functions for shared libraries that have
+ been loaded before the code runs.
+
+ So that we can use the same startup file with static executables,
+ we start programs with a value of 0 to indicate that there is no
+ such function. */
+#define ELF_PLAT_INIT(_r, load_addr) _r->gr[23] = 0
+
+#define ELF_EXEC_PAGESIZE 4096
+
+/* This is the location that an ET_DYN program is loaded if exec'ed. Typical
+ use of this is to invoke "./ld.so someprog" to test out a new version of
+ the loader. We need to make sure that it is out of the way of the program
+ that it will "exec", and that there is sufficient room for the brk.
+
+ (2 * TASK_SIZE / 3) turns into something undefined when run through a
+ 32 bit preprocessor and in some cases results in the kernel trying to map
+ ld.so to the kernel virtual base. Use a sane value instead. /Jes
+ */
+
+#define ELF_ET_DYN_BASE (TASK_UNMAPPED_BASE + 0x01000000)
+
+/* This yields a mask that user programs can use to figure out what
+ instruction set this CPU supports. This could be done in user space,
+ but it's not easy, and we've already done it here. */
+
+#define ELF_HWCAP 0
+
+#define STACK_RND_MASK 0x7ff /* 8MB of VA */
+
+#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1
+struct linux_binprm;
+extern int arch_setup_additional_pages(struct linux_binprm *bprm,
+ int executable_stack);
+#define VDSO_AUX_ENT(a, b) NEW_AUX_ENT(a, b)
+#define VDSO_CURRENT_BASE current->mm->context.vdso_base
+
+#define ARCH_DLINFO \
+do { \
+ if (VDSO_CURRENT_BASE) { \
+ NEW_AUX_ENT(AT_SYSINFO_EHDR, VDSO_CURRENT_BASE);\
+ } \
+} while (0)
+
+#endif
diff --git a/arch/parisc/include/asm/fb.h b/arch/parisc/include/asm/fb.h
new file mode 100644
index 000000000..658a8a7dc
--- /dev/null
+++ b/arch/parisc/include/asm/fb.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_FB_H_
+#define _ASM_FB_H_
+
+struct fb_info;
+
+#if defined(CONFIG_STI_CORE)
+int fb_is_primary_device(struct fb_info *info);
+#define fb_is_primary_device fb_is_primary_device
+#endif
+
+#include <asm-generic/fb.h>
+
+#endif /* _ASM_FB_H_ */
diff --git a/arch/parisc/include/asm/fixmap.h b/arch/parisc/include/asm/fixmap.h
new file mode 100644
index 000000000..5cd80ce11
--- /dev/null
+++ b/arch/parisc/include/asm/fixmap.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_FIXMAP_H
+#define _ASM_FIXMAP_H
+
+/*
+ * This file defines the locations of the fixed mappings on parisc.
+ *
+ * All of the values in this file are machine virtual addresses.
+ *
+ * All of the values in this file must be <4GB (because of assembly
+ * loading restrictions). If you place this region anywhere above
+ * __PAGE_OFFSET, you must adjust the memory map accordingly
+ */
+
+/*
+ * The tmpalias region is used in kernel space to copy/clear/flush data
+ * from pages congruently mapped with user space. It is comprised of
+ * a pair regions. The size of these regions is determined by the largest
+ * cache aliasing boundary for machines that support equivalent aliasing.
+ *
+ * The c3750 with PA8700 processor returns an alias value of 11. This
+ * indicates that it has an alias boundary of 4 MB. It also supports
+ * non-equivalent aliasing without a performance penalty.
+ *
+ * Machines with PA8800/PA8900 processors return an alias value of 0.
+ * This indicates the alias boundary is unknown and may be larger than
+ * 16 MB. Non-equivalent aliasing is not supported.
+ *
+ * Here we assume the maximum alias boundary is 4 MB.
+ */
+#define TMPALIAS_SIZE_BITS 22 /* 4 MB */
+#define TMPALIAS_MAP_START ((__PAGE_OFFSET) - (2 << TMPALIAS_SIZE_BITS))
+
+#define FIXMAP_SIZE (FIX_BITMAP_COUNT << PAGE_SHIFT)
+#define FIXMAP_START (TMPALIAS_MAP_START - FIXMAP_SIZE)
+/* This is the kernel area for all maps (vmalloc, dma etc.) most
+ * usually, it extends up to TMPALIAS_MAP_START. Virtual addresses
+ * 0..GATEWAY_PAGE_SIZE are reserved for the gateway page */
+#define KERNEL_MAP_START (GATEWAY_PAGE_SIZE)
+#define KERNEL_MAP_END (FIXMAP_START)
+
+#ifndef __ASSEMBLY__
+
+
+enum fixed_addresses {
+ /* Support writing RO kernel text via kprobes, jump labels, etc. */
+ FIX_TEXT_POKE0,
+ FIX_TEXT_KEXEC,
+ FIX_BITMAP_COUNT
+};
+
+extern void *parisc_vmalloc_start;
+#define PCXL_DMA_MAP_SIZE (8*1024*1024)
+#define VMALLOC_START ((unsigned long)parisc_vmalloc_start)
+#define VMALLOC_END (KERNEL_MAP_END)
+
+#define __fix_to_virt(_x) (FIXMAP_START + ((_x) << PAGE_SHIFT))
+
+void set_fixmap(enum fixed_addresses idx, phys_addr_t phys);
+void clear_fixmap(enum fixed_addresses idx);
+
+#endif /*__ASSEMBLY__*/
+
+#endif /*_ASM_FIXMAP_H*/
diff --git a/arch/parisc/include/asm/floppy.h b/arch/parisc/include/asm/floppy.h
new file mode 100644
index 000000000..b318a7df5
--- /dev/null
+++ b/arch/parisc/include/asm/floppy.h
@@ -0,0 +1,259 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* Architecture specific parts of the Floppy driver
+ *
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ * Copyright (C) 2000 Matthew Wilcox (willy a debian . org)
+ * Copyright (C) 2000 Dave Kennedy
+ */
+#ifndef __ASM_PARISC_FLOPPY_H
+#define __ASM_PARISC_FLOPPY_H
+
+#include <linux/vmalloc.h>
+
+
+/*
+ * The DMA channel used by the floppy controller cannot access data at
+ * addresses >= 16MB
+ *
+ * Went back to the 1MB limit, as some people had problems with the floppy
+ * driver otherwise. It doesn't matter much for performance anyway, as most
+ * floppy accesses go through the track buffer.
+ */
+#define _CROSS_64KB(a,s,vdma) \
+(!(vdma) && ((unsigned long)(a)/K_64 != ((unsigned long)(a) + (s) - 1) / K_64))
+
+#define CROSS_64KB(a,s) _CROSS_64KB(a,s,use_virtual_dma & 1)
+
+
+#define SW fd_routine[use_virtual_dma&1]
+#define CSW fd_routine[can_use_virtual_dma & 1]
+
+
+#define fd_inb(base, reg) readb((base) + (reg))
+#define fd_outb(value, base, reg) writeb(value, (base) + (reg))
+
+#define fd_request_dma() CSW._request_dma(FLOPPY_DMA,"floppy")
+#define fd_free_dma() CSW._free_dma(FLOPPY_DMA)
+#define fd_enable_irq() enable_irq(FLOPPY_IRQ)
+#define fd_disable_irq() disable_irq(FLOPPY_IRQ)
+#define fd_free_irq() free_irq(FLOPPY_IRQ, NULL)
+#define fd_get_dma_residue() SW._get_dma_residue(FLOPPY_DMA)
+#define fd_dma_mem_alloc(size) SW._dma_mem_alloc(size)
+#define fd_dma_setup(addr, size, mode, io) SW._dma_setup(addr, size, mode, io)
+
+#define FLOPPY_CAN_FALLBACK_ON_NODMA
+
+static int virtual_dma_count=0;
+static int virtual_dma_residue=0;
+static char *virtual_dma_addr=0;
+static int virtual_dma_mode=0;
+static int doing_pdma=0;
+
+static void floppy_hardint(int irq, void *dev_id, struct pt_regs * regs)
+{
+ register unsigned char st;
+
+#undef TRACE_FLPY_INT
+
+#ifdef TRACE_FLPY_INT
+ static int calls=0;
+ static int bytes=0;
+ static int dma_wait=0;
+#endif
+ if (!doing_pdma) {
+ floppy_interrupt(irq, dev_id, regs);
+ return;
+ }
+
+#ifdef TRACE_FLPY_INT
+ if(!calls)
+ bytes = virtual_dma_count;
+#endif
+
+ {
+ register int lcount;
+ register char *lptr = virtual_dma_addr;
+
+ for (lcount = virtual_dma_count; lcount; lcount--) {
+ st = fd_inb(virtual_dma_port, FD_STATUS);
+ st &= STATUS_DMA | STATUS_READY;
+ if (st != (STATUS_DMA | STATUS_READY))
+ break;
+ if (virtual_dma_mode) {
+ fd_outb(*lptr, virtual_dma_port, FD_DATA);
+ } else {
+ *lptr = fd_inb(virtual_dma_port, FD_DATA);
+ }
+ lptr++;
+ }
+ virtual_dma_count = lcount;
+ virtual_dma_addr = lptr;
+ st = fd_inb(virtual_dma_port, FD_STATUS);
+ }
+
+#ifdef TRACE_FLPY_INT
+ calls++;
+#endif
+ if (st == STATUS_DMA)
+ return;
+ if (!(st & STATUS_DMA)) {
+ virtual_dma_residue += virtual_dma_count;
+ virtual_dma_count = 0;
+#ifdef TRACE_FLPY_INT
+ printk("count=%x, residue=%x calls=%d bytes=%d dma_wait=%d\n",
+ virtual_dma_count, virtual_dma_residue, calls, bytes,
+ dma_wait);
+ calls = 0;
+ dma_wait=0;
+#endif
+ doing_pdma = 0;
+ floppy_interrupt(irq, dev_id, regs);
+ return;
+ }
+#ifdef TRACE_FLPY_INT
+ if (!virtual_dma_count)
+ dma_wait++;
+#endif
+}
+
+static void fd_disable_dma(void)
+{
+ if(! (can_use_virtual_dma & 1))
+ disable_dma(FLOPPY_DMA);
+ doing_pdma = 0;
+ virtual_dma_residue += virtual_dma_count;
+ virtual_dma_count=0;
+}
+
+static int vdma_request_dma(unsigned int dmanr, const char * device_id)
+{
+ return 0;
+}
+
+static void vdma_nop(unsigned int dummy)
+{
+}
+
+
+static int vdma_get_dma_residue(unsigned int dummy)
+{
+ return virtual_dma_count + virtual_dma_residue;
+}
+
+
+static int fd_request_irq(void)
+{
+ if(can_use_virtual_dma)
+ return request_irq(FLOPPY_IRQ, floppy_hardint,
+ 0, "floppy", NULL);
+ else
+ return request_irq(FLOPPY_IRQ, floppy_interrupt,
+ 0, "floppy", NULL);
+}
+
+static unsigned long dma_mem_alloc(unsigned long size)
+{
+ return __get_dma_pages(GFP_KERNEL, get_order(size));
+}
+
+
+static unsigned long vdma_mem_alloc(unsigned long size)
+{
+ return (unsigned long) vmalloc(size);
+
+}
+
+#define nodma_mem_alloc(size) vdma_mem_alloc(size)
+
+static void _fd_dma_mem_free(unsigned long addr, unsigned long size)
+{
+ if((unsigned int) addr >= (unsigned int) high_memory)
+ return vfree((void *)addr);
+ else
+ free_pages(addr, get_order(size));
+}
+
+#define fd_dma_mem_free(addr, size) _fd_dma_mem_free(addr, size)
+
+static void _fd_chose_dma_mode(char *addr, unsigned long size)
+{
+ if(can_use_virtual_dma == 2) {
+ if((unsigned int) addr >= (unsigned int) high_memory ||
+ virt_to_phys(addr) >= 0x1000000 ||
+ _CROSS_64KB(addr, size, 0))
+ use_virtual_dma = 1;
+ else
+ use_virtual_dma = 0;
+ } else {
+ use_virtual_dma = can_use_virtual_dma & 1;
+ }
+}
+
+#define fd_chose_dma_mode(addr, size) _fd_chose_dma_mode(addr, size)
+
+
+static int vdma_dma_setup(char *addr, unsigned long size, int mode, int io)
+{
+ doing_pdma = 1;
+ virtual_dma_port = io;
+ virtual_dma_mode = (mode == DMA_MODE_WRITE);
+ virtual_dma_addr = addr;
+ virtual_dma_count = size;
+ virtual_dma_residue = 0;
+ return 0;
+}
+
+static int hard_dma_setup(char *addr, unsigned long size, int mode, int io)
+{
+#ifdef FLOPPY_SANITY_CHECK
+ if (CROSS_64KB(addr, size)) {
+ printk("DMA crossing 64-K boundary %p-%p\n", addr, addr+size);
+ return -1;
+ }
+#endif
+ /* actual, physical DMA */
+ doing_pdma = 0;
+ clear_dma_ff(FLOPPY_DMA);
+ set_dma_mode(FLOPPY_DMA,mode);
+ set_dma_addr(FLOPPY_DMA,virt_to_phys(addr));
+ set_dma_count(FLOPPY_DMA,size);
+ enable_dma(FLOPPY_DMA);
+ return 0;
+}
+
+static struct fd_routine_l {
+ int (*_request_dma)(unsigned int dmanr, const char * device_id);
+ void (*_free_dma)(unsigned int dmanr);
+ int (*_get_dma_residue)(unsigned int dummy);
+ unsigned long (*_dma_mem_alloc) (unsigned long size);
+ int (*_dma_setup)(char *addr, unsigned long size, int mode, int io);
+} fd_routine[] = {
+ {
+ request_dma,
+ free_dma,
+ get_dma_residue,
+ dma_mem_alloc,
+ hard_dma_setup
+ },
+ {
+ vdma_request_dma,
+ vdma_nop,
+ vdma_get_dma_residue,
+ vdma_mem_alloc,
+ vdma_dma_setup
+ }
+};
+
+
+static int FDC1 = 0x3f0; /* Lies. Floppy controller is memory mapped, not io mapped */
+static int FDC2 = -1;
+
+#define FLOPPY0_TYPE 0
+#define FLOPPY1_TYPE 0
+
+#define N_FDC 1
+#define N_DRIVE 8
+
+#define EXTRA_FLOPPY_PARAMS
+
+#endif /* __ASM_PARISC_FLOPPY_H */
diff --git a/arch/parisc/include/asm/ftrace.h b/arch/parisc/include/asm/ftrace.h
new file mode 100644
index 000000000..f1cc1ee3a
--- /dev/null
+++ b/arch/parisc/include/asm/ftrace.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_PARISC_FTRACE_H
+#define _ASM_PARISC_FTRACE_H
+
+#ifndef __ASSEMBLY__
+extern void mcount(void);
+
+#define MCOUNT_ADDR ((unsigned long)mcount)
+#define MCOUNT_INSN_SIZE 4
+#define CC_USING_NOP_MCOUNT
+#define ARCH_SUPPORTS_FTRACE_OPS 1
+extern unsigned long sys_call_table[];
+
+extern unsigned long return_address(unsigned int);
+struct ftrace_regs;
+extern void ftrace_function_trampoline(unsigned long parent,
+ unsigned long self_addr, unsigned long org_sp_gr3,
+ struct ftrace_regs *fregs);
+
+#ifdef CONFIG_DYNAMIC_FTRACE
+extern void ftrace_caller(void);
+
+struct dyn_arch_ftrace {
+};
+
+unsigned long ftrace_call_adjust(unsigned long addr);
+
+#endif
+
+#define ftrace_return_address(n) return_address(n)
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_PARISC_FTRACE_H */
diff --git a/arch/parisc/include/asm/futex.h b/arch/parisc/include/asm/futex.h
new file mode 100644
index 000000000..3222206cb
--- /dev/null
+++ b/arch/parisc/include/asm/futex.h
@@ -0,0 +1,127 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_PARISC_FUTEX_H
+#define _ASM_PARISC_FUTEX_H
+
+#include <linux/futex.h>
+#include <linux/uaccess.h>
+#include <asm/atomic.h>
+#include <asm/errno.h>
+
+/* The following has to match the LWS code in syscall.S. We have
+ * 256 four-word locks. We use bits 20-27 of the futex virtual
+ * address for the hash index.
+ */
+
+static inline unsigned long _futex_hash_index(unsigned long ua)
+{
+ return (ua >> 2) & 0x3fc;
+}
+
+static inline void
+_futex_spin_lock_irqsave(arch_spinlock_t *s, unsigned long *flags)
+{
+ local_irq_save(*flags);
+ arch_spin_lock(s);
+}
+
+static inline void
+_futex_spin_unlock_irqrestore(arch_spinlock_t *s, unsigned long *flags)
+{
+ arch_spin_unlock(s);
+ local_irq_restore(*flags);
+}
+
+static inline int
+arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
+{
+ extern u32 lws_lock_start[];
+ unsigned long ua = (unsigned long)uaddr;
+ arch_spinlock_t *s;
+ unsigned long flags;
+ int oldval, ret;
+ u32 tmp;
+
+ s = (arch_spinlock_t *)&lws_lock_start[_futex_hash_index(ua)];
+ _futex_spin_lock_irqsave(s, &flags);
+
+ /* Return -EFAULT if we encounter a page fault or COW break */
+ if (unlikely(get_user(oldval, uaddr) != 0)) {
+ ret = -EFAULT;
+ goto out_pagefault_enable;
+ }
+
+ ret = 0;
+ tmp = oldval;
+
+ switch (op) {
+ case FUTEX_OP_SET:
+ tmp = oparg;
+ break;
+ case FUTEX_OP_ADD:
+ tmp += oparg;
+ break;
+ case FUTEX_OP_OR:
+ tmp |= oparg;
+ break;
+ case FUTEX_OP_ANDN:
+ tmp &= ~oparg;
+ break;
+ case FUTEX_OP_XOR:
+ tmp ^= oparg;
+ break;
+ default:
+ ret = -ENOSYS;
+ goto out_pagefault_enable;
+ }
+
+ if (unlikely(put_user(tmp, uaddr) != 0))
+ ret = -EFAULT;
+
+out_pagefault_enable:
+ _futex_spin_unlock_irqrestore(s, &flags);
+
+ if (!ret)
+ *oval = oldval;
+
+ return ret;
+}
+
+static inline int
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
+{
+ extern u32 lws_lock_start[];
+ unsigned long ua = (unsigned long)uaddr;
+ arch_spinlock_t *s;
+ u32 val;
+ unsigned long flags;
+
+ if (!access_ok(uaddr, sizeof(u32)))
+ return -EFAULT;
+
+ /* HPPA has no cmpxchg in hardware and therefore the
+ * best we can do here is use an array of locks. The
+ * lock selected is based on a hash of the virtual
+ * address of the futex. This should scale to a couple
+ * of CPUs.
+ */
+
+ s = (arch_spinlock_t *)&lws_lock_start[_futex_hash_index(ua)];
+ _futex_spin_lock_irqsave(s, &flags);
+ if (unlikely(get_user(val, uaddr) != 0)) {
+ _futex_spin_unlock_irqrestore(s, &flags);
+ return -EFAULT;
+ }
+
+ if (val == oldval && unlikely(put_user(newval, uaddr) != 0)) {
+ _futex_spin_unlock_irqrestore(s, &flags);
+ return -EFAULT;
+ }
+
+ *uval = val;
+ _futex_spin_unlock_irqrestore(s, &flags);
+
+ return 0;
+}
+
+#endif /*_ASM_PARISC_FUTEX_H*/
diff --git a/arch/parisc/include/asm/grfioctl.h b/arch/parisc/include/asm/grfioctl.h
new file mode 100644
index 000000000..597201530
--- /dev/null
+++ b/arch/parisc/include/asm/grfioctl.h
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* Architecture specific parts of HP's STI (framebuffer) driver.
+ * Structures are HP-UX compatible for XFree86 usage.
+ *
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ * Copyright (C) 2001 Helge Deller (deller a parisc-linux org)
+ */
+
+#ifndef __ASM_PARISC_GRFIOCTL_H
+#define __ASM_PARISC_GRFIOCTL_H
+
+/* upper 32 bits of graphics id (HP/UX identifier) */
+
+#define GRFGATOR 8
+#define S9000_ID_S300 9
+#define GRFBOBCAT 9
+#define GRFCATSEYE 9
+#define S9000_ID_98720 10
+#define GRFRBOX 10
+#define S9000_ID_98550 11
+#define GRFFIREEYE 11
+#define S9000_ID_A1096A 12
+#define GRFHYPERION 12
+#define S9000_ID_FRI 13
+#define S9000_ID_98730 14
+#define GRFDAVINCI 14
+#define S9000_ID_98705 0x26C08070 /* Tigershark */
+#define S9000_ID_98736 0x26D148AB
+#define S9000_ID_A1659A 0x26D1482A /* CRX 8 plane color (=ELK) */
+#define S9000_ID_ELK S9000_ID_A1659A
+#define S9000_ID_A1439A 0x26D148EE /* CRX24 = CRX+ (24-plane color) */
+#define S9000_ID_A1924A 0x26D1488C /* GRX gray-scale */
+#define S9000_ID_ELM S9000_ID_A1924A
+#define S9000_ID_98765 0x27480DEF
+#define S9000_ID_ELK_768 0x27482101
+#define S9000_ID_STINGER 0x27A4A402
+#define S9000_ID_TIMBER 0x27F12392 /* Bushmaster (710) Graphics */
+#define S9000_ID_TOMCAT 0x27FCCB6D /* dual-headed ELK (Dual CRX) */
+#define S9000_ID_ARTIST 0x2B4DED6D /* Artist (Gecko/712 & 715) onboard Graphics */
+#define S9000_ID_HCRX 0x2BCB015A /* Hyperdrive/Hyperbowl (A4071A) Graphics */
+#define CRX24_OVERLAY_PLANES 0x920825AA /* Overlay planes on CRX24 */
+
+#define CRT_ID_ELK_1024 S9000_ID_ELK_768 /* Elk 1024x768 CRX */
+#define CRT_ID_ELK_1280 S9000_ID_A1659A /* Elk 1280x1024 CRX */
+#define CRT_ID_ELK_1024DB 0x27849CA5 /* Elk 1024x768 double buffer */
+#define CRT_ID_ELK_GS S9000_ID_A1924A /* Elk 1280x1024 GreyScale */
+#define CRT_ID_CRX24 S9000_ID_A1439A /* Piranha */
+#define CRT_ID_VISUALIZE_EG 0x2D08C0A7 /* Graffiti, A4450A (built-in B132+/B160L) */
+#define CRT_ID_THUNDER 0x2F23E5FC /* Thunder 1 VISUALIZE 48*/
+#define CRT_ID_THUNDER2 0x2F8D570E /* Thunder 2 VISUALIZE 48 XP*/
+#define CRT_ID_HCRX S9000_ID_HCRX /* Hyperdrive HCRX */
+#define CRT_ID_CRX48Z S9000_ID_STINGER /* Stinger */
+#define CRT_ID_DUAL_CRX S9000_ID_TOMCAT /* Tomcat */
+#define CRT_ID_PVRX S9000_ID_98705 /* Tigershark */
+#define CRT_ID_TIMBER S9000_ID_TIMBER /* Timber (710 builtin) */
+#define CRT_ID_TVRX S9000_ID_98765 /* TVRX (gto/falcon) */
+#define CRT_ID_ARTIST S9000_ID_ARTIST /* Artist */
+#define CRT_ID_SUMMIT 0x2FC1066B /* Summit FX2, FX4, FX6 ... */
+#define CRT_ID_LEGO 0x35ACDA30 /* Lego FX5, FX10 ... */
+#define CRT_ID_PINNACLE 0x35ACDA16 /* Pinnacle FXe */
+
+#endif /* __ASM_PARISC_GRFIOCTL_H */
diff --git a/arch/parisc/include/asm/hardirq.h b/arch/parisc/include/asm/hardirq.h
new file mode 100644
index 000000000..1e4fbd0fd
--- /dev/null
+++ b/arch/parisc/include/asm/hardirq.h
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* hardirq.h: PA-RISC hard IRQ support.
+ *
+ * Copyright (C) 2001 Matthew Wilcox <matthew@wil.cx>
+ * Copyright (C) 2013 Helge Deller <deller@gmx.de>
+ */
+
+#ifndef _PARISC_HARDIRQ_H
+#define _PARISC_HARDIRQ_H
+
+#include <linux/cache.h>
+#include <linux/threads.h>
+#include <linux/irq.h>
+
+typedef struct {
+ unsigned int __softirq_pending;
+ unsigned int kernel_stack_usage;
+ unsigned int irq_stack_usage;
+#ifdef CONFIG_SMP
+ unsigned int irq_resched_count;
+ unsigned int irq_call_count;
+#endif
+ unsigned int irq_unaligned_count;
+ unsigned int irq_fpassist_count;
+ unsigned int irq_tlb_count;
+} ____cacheline_aligned irq_cpustat_t;
+
+DECLARE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat);
+
+#define __ARCH_IRQ_STAT
+#define inc_irq_stat(member) this_cpu_inc(irq_stat.member)
+#define __inc_irq_stat(member) __this_cpu_inc(irq_stat.member)
+#define ack_bad_irq(irq) WARN(1, "unexpected IRQ trap at vector %02x\n", irq)
+
+#endif /* _PARISC_HARDIRQ_H */
diff --git a/arch/parisc/include/asm/hardware.h b/arch/parisc/include/asm/hardware.h
new file mode 100644
index 000000000..a005ebc54
--- /dev/null
+++ b/arch/parisc/include/asm/hardware.h
@@ -0,0 +1,129 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _PARISC_HARDWARE_H
+#define _PARISC_HARDWARE_H
+
+#include <linux/mod_devicetable.h>
+
+#define HWTYPE_ANY_ID PA_HWTYPE_ANY_ID
+#define HVERSION_ANY_ID PA_HVERSION_ANY_ID
+#define HVERSION_REV_ANY_ID PA_HVERSION_REV_ANY_ID
+#define SVERSION_ANY_ID PA_SVERSION_ANY_ID
+
+struct hp_hardware {
+ unsigned int hw_type:8; /* HPHW_xxx */
+ unsigned int hversion:12;
+ unsigned int sversion:12;
+ unsigned char opt;
+ unsigned char name[59]; /* The hardware description */
+} __packed;
+
+struct parisc_device;
+
+enum cpu_type {
+ pcx = 0, /* pa7000 pa 1.0 */
+ pcxs = 1, /* pa7000 pa 1.1a */
+ pcxt = 2, /* pa7100 pa 1.1b */
+ pcxt_ = 3, /* pa7200 (t') pa 1.1c */
+ pcxl = 4, /* pa7100lc pa 1.1d */
+ pcxl2 = 5, /* pa7300lc pa 1.1e */
+ pcxu = 6, /* pa8000 pa 2.0 */
+ pcxu_ = 7, /* pa8200 (u+) pa 2.0 */
+ pcxw = 8, /* pa8500 pa 2.0 */
+ pcxw_ = 9, /* pa8600 (w+) pa 2.0 */
+ pcxw2 = 10, /* pa8700 pa 2.0 */
+ mako = 11, /* pa8800 pa 2.0 */
+ mako2 = 12 /* pa8900 pa 2.0 */
+};
+
+extern const char * const cpu_name_version[][2]; /* mapping from enum cpu_type to strings */
+
+struct parisc_driver;
+
+struct io_module {
+ volatile uint32_t nothing; /* reg 0 */
+ volatile uint32_t io_eim;
+ volatile uint32_t io_dc_adata;
+ volatile uint32_t io_ii_cdata;
+ volatile uint32_t io_dma_link; /* reg 4 */
+ volatile uint32_t io_dma_command;
+ volatile uint32_t io_dma_address;
+ volatile uint32_t io_dma_count;
+ volatile uint32_t io_flex; /* reg 8 */
+ volatile uint32_t io_spa_address;
+ volatile uint32_t reserved1[2];
+ volatile uint32_t io_command; /* reg 12 */
+ volatile uint32_t io_status;
+ volatile uint32_t io_control;
+ volatile uint32_t io_data;
+ volatile uint32_t reserved2; /* reg 16 */
+ volatile uint32_t chain_addr;
+ volatile uint32_t sub_mask_clr;
+ volatile uint32_t reserved3[13];
+ volatile uint32_t undefined[480];
+ volatile uint32_t unpriv[512];
+};
+
+struct bc_module {
+ volatile uint32_t unused1[12];
+ volatile uint32_t io_command;
+ volatile uint32_t io_status;
+ volatile uint32_t io_control;
+ volatile uint32_t unused2[1];
+ volatile uint32_t io_err_resp;
+ volatile uint32_t io_err_info;
+ volatile uint32_t io_err_req;
+ volatile uint32_t unused3[11];
+ volatile uint32_t io_io_low;
+ volatile uint32_t io_io_high;
+};
+
+#define HPHW_NPROC 0
+#define HPHW_MEMORY 1
+#define HPHW_B_DMA 2
+#define HPHW_OBSOLETE 3
+#define HPHW_A_DMA 4
+#define HPHW_A_DIRECT 5
+#define HPHW_OTHER 6
+#define HPHW_BCPORT 7
+#define HPHW_CIO 8
+#define HPHW_CONSOLE 9
+#define HPHW_FIO 10
+#define HPHW_BA 11
+#define HPHW_IOA 12
+#define HPHW_BRIDGE 13
+#define HPHW_FABRIC 14
+#define HPHW_MC 15
+#define HPHW_FAULTY 31
+
+struct parisc_device_id;
+
+/* hardware.c: */
+extern const char *parisc_hardware_description(struct parisc_device_id *id);
+extern enum cpu_type parisc_get_cpu_type(unsigned long hversion);
+
+struct pci_dev;
+struct hardware_path;
+
+/* drivers.c: */
+extern struct parisc_device *alloc_pa_dev(unsigned long hpa,
+ struct hardware_path *path);
+extern int register_parisc_device(struct parisc_device *dev);
+extern int register_parisc_driver(struct parisc_driver *driver);
+extern int count_parisc_driver(struct parisc_driver *driver);
+extern int unregister_parisc_driver(struct parisc_driver *driver);
+extern void walk_central_bus(void);
+extern const struct parisc_device *find_pa_parent_type(const struct parisc_device *, int);
+extern void print_parisc_devices(void);
+extern char *print_pa_hwpath(struct parisc_device *dev, char *path);
+extern char *print_pci_hwpath(struct pci_dev *dev, char *path);
+extern void get_pci_node_path(struct pci_dev *dev, struct hardware_path *path);
+extern void init_parisc_bus(void);
+extern struct device *hwpath_to_device(struct hardware_path *modpath);
+extern void device_to_hwpath(struct device *dev, struct hardware_path *path);
+extern int machine_has_merced_bus(void);
+
+/* inventory.c: */
+extern void do_memory_inventory(void);
+extern void do_device_inventory(void);
+
+#endif /* _PARISC_HARDWARE_H */
diff --git a/arch/parisc/include/asm/hash.h b/arch/parisc/include/asm/hash.h
new file mode 100644
index 000000000..525950ed8
--- /dev/null
+++ b/arch/parisc/include/asm/hash.h
@@ -0,0 +1,147 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_HASH_H
+#define _ASM_HASH_H
+
+/*
+ * HP-PA only implements integer multiply in the FPU. However, for
+ * integer multiplies by constant, it has a number of shift-and-add
+ * (but no shift-and-subtract, sigh!) instructions that a compiler
+ * can synthesize a code sequence with.
+ *
+ * Unfortunately, GCC isn't very efficient at using them. For example
+ * it uses three instructions for "x *= 21" when only two are needed.
+ * But we can find a sequence manually.
+ */
+
+#define HAVE_ARCH__HASH_32 1
+
+/*
+ * This is a multiply by GOLDEN_RATIO_32 = 0x61C88647 optimized for the
+ * PA7100 pairing rules. This is an in-order 2-way superscalar processor.
+ * Only one instruction in a pair may be a shift (by more than 3 bits),
+ * but other than that, simple ALU ops (including shift-and-add by up
+ * to 3 bits) may be paired arbitrarily.
+ *
+ * PA8xxx processors also dual-issue ALU instructions, although with
+ * fewer constraints, so this schedule is good for them, too.
+ *
+ * This 6-step sequence was found by Yevgen Voronenko's implementation
+ * of the Hcub algorithm at http://spiral.ece.cmu.edu/mcm/gen.html.
+ */
+static inline u32 __attribute_const__ __hash_32(u32 x)
+{
+ u32 a, b, c;
+
+ /*
+ * Phase 1: Compute a = (x << 19) + x,
+ * b = (x << 9) + a, c = (x << 23) + b.
+ */
+ a = x << 19; /* Two shifts can't be paired */
+ b = x << 9; a += x;
+ c = x << 23; b += a;
+ c += b;
+ /* Phase 2: Return (b<<11) + (c<<6) + (a<<3) - c */
+ b <<= 11;
+ a += c << 3; b -= c;
+ return (a << 3) + b;
+}
+
+#if BITS_PER_LONG == 64
+
+#define HAVE_ARCH_HASH_64 1
+
+/*
+ * Finding a good shift-and-add chain for GOLDEN_RATIO_64 is tricky,
+ * because available software for the purpose chokes on constants this
+ * large. (It's mostly designed for compiling FIR filter coefficients
+ * into FPGAs.)
+ *
+ * However, Jason Thong pointed out a work-around. The Hcub software
+ * (http://spiral.ece.cmu.edu/mcm/gen.html) is designed for *multiple*
+ * constant multiplication, and is good at finding shift-and-add chains
+ * which share common terms.
+ *
+ * Looking at 0x0x61C8864680B583EB in binary:
+ * 0110000111001000100001100100011010000000101101011000001111101011
+ * \______________/ \__________/ \_______/ \________/
+ * \____________________________/ \____________________/
+ * you can see the non-zero bits are divided into several well-separated
+ * blocks. Hcub can find algorithms for those terms separately, which
+ * can then be shifted and added together.
+ *
+ * Dividing the input into 2, 3 or 4 blocks, Hcub can find solutions
+ * with 10, 9 or 8 adds, respectively, making a total of 11 for the
+ * whole number.
+ *
+ * Using just two large blocks, 0xC3910C8D << 31 in the high bits,
+ * and 0xB583EB in the low bits, produces as good an algorithm as any,
+ * and with one more small shift than alternatives.
+ *
+ * The high bits are a larger number and more work to compute, as well
+ * as needing one extra cycle to shift left 31 bits before the final
+ * addition, so they are the critical path for scheduling. The low bits
+ * can fit into the scheduling slots left over.
+ */
+
+
+/*
+ * This _ASSIGN(dst, src) macro performs "dst = src", but prevents GCC
+ * from inferring anything about the value assigned to "dest".
+ *
+ * This prevents it from mis-optimizing certain sequences.
+ * In particular, gcc is annoyingly eager to combine consecutive shifts.
+ * Given "x <<= 19; y += x; z += x << 1;", GCC will turn this into
+ * "y += x << 19; z += x << 20;" even though the latter sequence needs
+ * an additional instruction and temporary register.
+ *
+ * Because no actual assembly code is generated, this construct is
+ * usefully portable across all GCC platforms, and so can be test-compiled
+ * on non-PA systems.
+ *
+ * In two places, additional unused input dependencies are added. This
+ * forces GCC's scheduling so it does not rearrange instructions too much.
+ * Because the PA-8xxx is out of order, I'm not sure how much this matters,
+ * but why make it more difficult for the processor than necessary?
+ */
+#define _ASSIGN(dst, src, ...) asm("" : "=r" (dst) : "0" (src), ##__VA_ARGS__)
+
+/*
+ * Multiply by GOLDEN_RATIO_64 = 0x0x61C8864680B583EB using a heavily
+ * optimized shift-and-add sequence.
+ *
+ * Without the final shift, the multiply proper is 19 instructions,
+ * 10 cycles and uses only 4 temporaries. Whew!
+ *
+ * You are not expected to understand this.
+ */
+static __always_inline u32 __attribute_const__
+hash_64(u64 a, unsigned int bits)
+{
+ u64 b, c, d;
+
+ /*
+ * Encourage GCC to move a dynamic shift to %sar early,
+ * thereby freeing up an additional temporary register.
+ */
+ if (!__builtin_constant_p(bits))
+ asm("" : "=q" (bits) : "0" (64 - bits));
+ else
+ bits = 64 - bits;
+
+ _ASSIGN(b, a*5); c = a << 13;
+ b = (b << 2) + a; _ASSIGN(d, a << 17);
+ a = b + (a << 1); c += d;
+ d = a << 10; _ASSIGN(a, a << 19);
+ d = a - d; _ASSIGN(a, a << 4, "X" (d));
+ c += b; a += b;
+ d -= c; c += a << 1;
+ a += c << 3; _ASSIGN(b, b << (7+31), "X" (c), "X" (d));
+ a <<= 31; b += d;
+ a += b;
+ return a >> bits;
+}
+#undef _ASSIGN /* We're a widely-used header file, so don't litter! */
+
+#endif /* BITS_PER_LONG == 64 */
+
+#endif /* _ASM_HASH_H */
diff --git a/arch/parisc/include/asm/hugetlb.h b/arch/parisc/include/asm/hugetlb.h
new file mode 100644
index 000000000..72daacc47
--- /dev/null
+++ b/arch/parisc/include/asm/hugetlb.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_PARISC64_HUGETLB_H
+#define _ASM_PARISC64_HUGETLB_H
+
+#include <asm/page.h>
+
+#define __HAVE_ARCH_HUGE_SET_HUGE_PTE_AT
+void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t pte, unsigned long sz);
+
+#define __HAVE_ARCH_HUGE_PTEP_GET_AND_CLEAR
+pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep);
+
+/*
+ * If the arch doesn't supply something else, assume that hugepage
+ * size aligned regions are ok without further preparation.
+ */
+#define __HAVE_ARCH_PREPARE_HUGEPAGE_RANGE
+static inline int prepare_hugepage_range(struct file *file,
+ unsigned long addr, unsigned long len)
+{
+ if (len & ~HPAGE_MASK)
+ return -EINVAL;
+ if (addr & ~HPAGE_MASK)
+ return -EINVAL;
+ return 0;
+}
+
+#define __HAVE_ARCH_HUGE_PTEP_CLEAR_FLUSH
+static inline pte_t huge_ptep_clear_flush(struct vm_area_struct *vma,
+ unsigned long addr, pte_t *ptep)
+{
+ return *ptep;
+}
+
+#define __HAVE_ARCH_HUGE_PTEP_SET_WRPROTECT
+void huge_ptep_set_wrprotect(struct mm_struct *mm,
+ unsigned long addr, pte_t *ptep);
+
+#define __HAVE_ARCH_HUGE_PTEP_SET_ACCESS_FLAGS
+int huge_ptep_set_access_flags(struct vm_area_struct *vma,
+ unsigned long addr, pte_t *ptep,
+ pte_t pte, int dirty);
+
+#include <asm-generic/hugetlb.h>
+
+#endif /* _ASM_PARISC64_HUGETLB_H */
diff --git a/arch/parisc/include/asm/io.h b/arch/parisc/include/asm/io.h
new file mode 100644
index 000000000..366537042
--- /dev/null
+++ b/arch/parisc/include/asm/io.h
@@ -0,0 +1,280 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_IO_H
+#define _ASM_IO_H
+
+#include <linux/types.h>
+#include <linux/pgtable.h>
+
+#define virt_to_phys(a) ((unsigned long)__pa(a))
+#define phys_to_virt(a) __va(a)
+
+static inline unsigned long isa_bus_to_virt(unsigned long addr) {
+ BUG();
+ return 0;
+}
+
+static inline unsigned long isa_virt_to_bus(void *addr) {
+ BUG();
+ return 0;
+}
+
+/*
+ * Memory mapped I/O
+ *
+ * readX()/writeX() do byteswapping and take an ioremapped address
+ * __raw_readX()/__raw_writeX() don't byteswap and take an ioremapped address.
+ * gsc_*() don't byteswap and operate on physical addresses;
+ * eg dev->hpa or 0xfee00000.
+ */
+
+static inline unsigned char gsc_readb(unsigned long addr)
+{
+ long flags;
+ unsigned char ret;
+
+ __asm__ __volatile__(
+ " rsm %3,%0\n"
+ " ldbx 0(%2),%1\n"
+ " mtsm %0\n"
+ : "=&r" (flags), "=r" (ret) : "r" (addr), "i" (PSW_SM_D) );
+
+ return ret;
+}
+
+static inline unsigned short gsc_readw(unsigned long addr)
+{
+ long flags;
+ unsigned short ret;
+
+ __asm__ __volatile__(
+ " rsm %3,%0\n"
+ " ldhx 0(%2),%1\n"
+ " mtsm %0\n"
+ : "=&r" (flags), "=r" (ret) : "r" (addr), "i" (PSW_SM_D) );
+
+ return ret;
+}
+
+static inline unsigned int gsc_readl(unsigned long addr)
+{
+ u32 ret;
+
+ __asm__ __volatile__(
+ " ldwax 0(%1),%0\n"
+ : "=r" (ret) : "r" (addr) );
+
+ return ret;
+}
+
+static inline unsigned long long gsc_readq(unsigned long addr)
+{
+ unsigned long long ret;
+
+#ifdef CONFIG_64BIT
+ __asm__ __volatile__(
+ " ldda 0(%1),%0\n"
+ : "=r" (ret) : "r" (addr) );
+#else
+ /* two reads may have side effects.. */
+ ret = ((u64) gsc_readl(addr)) << 32;
+ ret |= gsc_readl(addr+4);
+#endif
+ return ret;
+}
+
+static inline void gsc_writeb(unsigned char val, unsigned long addr)
+{
+ long flags;
+ __asm__ __volatile__(
+ " rsm %3,%0\n"
+ " stbs %1,0(%2)\n"
+ " mtsm %0\n"
+ : "=&r" (flags) : "r" (val), "r" (addr), "i" (PSW_SM_D) );
+}
+
+static inline void gsc_writew(unsigned short val, unsigned long addr)
+{
+ long flags;
+ __asm__ __volatile__(
+ " rsm %3,%0\n"
+ " sths %1,0(%2)\n"
+ " mtsm %0\n"
+ : "=&r" (flags) : "r" (val), "r" (addr), "i" (PSW_SM_D) );
+}
+
+static inline void gsc_writel(unsigned int val, unsigned long addr)
+{
+ __asm__ __volatile__(
+ " stwas %0,0(%1)\n"
+ : : "r" (val), "r" (addr) );
+}
+
+static inline void gsc_writeq(unsigned long long val, unsigned long addr)
+{
+#ifdef CONFIG_64BIT
+ __asm__ __volatile__(
+ " stda %0,0(%1)\n"
+ : : "r" (val), "r" (addr) );
+#else
+ /* two writes may have side effects.. */
+ gsc_writel(val >> 32, addr);
+ gsc_writel(val, addr+4);
+#endif
+}
+
+/*
+ * The standard PCI ioremap interfaces
+ */
+#define ioremap_prot ioremap_prot
+
+#define _PAGE_IOREMAP (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | \
+ _PAGE_ACCESSED | _PAGE_NO_CACHE)
+
+#define ioremap_wc(addr, size) \
+ ioremap_prot((addr), (size), _PAGE_IOREMAP)
+#define ioremap_uc(addr, size) \
+ ioremap_prot((addr), (size), _PAGE_IOREMAP)
+
+#define pci_iounmap pci_iounmap
+
+void memset_io(volatile void __iomem *addr, unsigned char val, int count);
+void memcpy_fromio(void *dst, const volatile void __iomem *src, int count);
+void memcpy_toio(volatile void __iomem *dst, const void *src, int count);
+#define memset_io memset_io
+#define memcpy_fromio memcpy_fromio
+#define memcpy_toio memcpy_toio
+
+/* Port-space IO */
+
+#define inb_p inb
+#define inw_p inw
+#define inl_p inl
+#define outb_p outb
+#define outw_p outw
+#define outl_p outl
+
+extern unsigned char eisa_in8(unsigned short port);
+extern unsigned short eisa_in16(unsigned short port);
+extern unsigned int eisa_in32(unsigned short port);
+extern void eisa_out8(unsigned char data, unsigned short port);
+extern void eisa_out16(unsigned short data, unsigned short port);
+extern void eisa_out32(unsigned int data, unsigned short port);
+
+#if defined(CONFIG_PCI)
+extern unsigned char inb(int addr);
+extern unsigned short inw(int addr);
+extern unsigned int inl(int addr);
+extern void outb(unsigned char b, int addr);
+extern void outw(unsigned short b, int addr);
+extern void outl(unsigned int b, int addr);
+#define inb inb
+#define inw inw
+#define inl inl
+#define outb outb
+#define outw outw
+#define outl outl
+#elif defined(CONFIG_EISA)
+#define inb eisa_in8
+#define inw eisa_in16
+#define inl eisa_in32
+#define outb eisa_out8
+#define outw eisa_out16
+#define outl eisa_out32
+#else
+static inline char inb(unsigned long addr)
+{
+ BUG();
+ return -1;
+}
+
+static inline short inw(unsigned long addr)
+{
+ BUG();
+ return -1;
+}
+
+static inline int inl(unsigned long addr)
+{
+ BUG();
+ return -1;
+}
+#define inb inb
+#define inw inw
+#define inl inl
+#define outb(x, y) ({(void)(x); (void)(y); BUG(); 0;})
+#define outw(x, y) ({(void)(x); (void)(y); BUG(); 0;})
+#define outl(x, y) ({(void)(x); (void)(y); BUG(); 0;})
+#endif
+
+/*
+ * String versions of in/out ops:
+ */
+extern void insb (unsigned long port, void *dst, unsigned long count);
+extern void insw (unsigned long port, void *dst, unsigned long count);
+extern void insl (unsigned long port, void *dst, unsigned long count);
+extern void outsb (unsigned long port, const void *src, unsigned long count);
+extern void outsw (unsigned long port, const void *src, unsigned long count);
+extern void outsl (unsigned long port, const void *src, unsigned long count);
+#define insb insb
+#define insw insw
+#define insl insl
+#define outsb outsb
+#define outsw outsw
+#define outsl outsl
+
+/* IO Port space is : BBiiii where BB is HBA number. */
+#define IO_SPACE_LIMIT 0x00ffffff
+
+/* PA machines have an MM I/O space from 0xf0000000-0xffffffff in 32
+ * bit mode and from 0xfffffffff0000000-0xfffffffffffffff in 64 bit
+ * mode (essentially just sign extending. This macro takes in a 32
+ * bit I/O address (still with the leading f) and outputs the correct
+ * value for either 32 or 64 bit mode */
+#define F_EXTEND(x) ((unsigned long)((x) | (0xffffffff00000000ULL)))
+
+#ifdef CONFIG_64BIT
+#define ioread64 ioread64
+#define ioread64be ioread64be
+#define iowrite64 iowrite64
+#define iowrite64be iowrite64be
+extern u64 ioread64(const void __iomem *addr);
+extern u64 ioread64be(const void __iomem *addr);
+extern void iowrite64(u64 val, void __iomem *addr);
+extern void iowrite64be(u64 val, void __iomem *addr);
+#endif
+
+#include <asm-generic/iomap.h>
+/*
+ * These get provided from <asm-generic/iomap.h> since parisc does not
+ * select GENERIC_IOMAP.
+ */
+#define ioport_map ioport_map
+#define ioport_unmap ioport_unmap
+#define ioread8 ioread8
+#define ioread16 ioread16
+#define ioread32 ioread32
+#define ioread16be ioread16be
+#define ioread32be ioread32be
+#define iowrite8 iowrite8
+#define iowrite16 iowrite16
+#define iowrite32 iowrite32
+#define iowrite16be iowrite16be
+#define iowrite32be iowrite32be
+#define ioread8_rep ioread8_rep
+#define ioread16_rep ioread16_rep
+#define ioread32_rep ioread32_rep
+#define iowrite8_rep iowrite8_rep
+#define iowrite16_rep iowrite16_rep
+#define iowrite32_rep iowrite32_rep
+
+/*
+ * Convert a physical pointer to a virtual kernel pointer for /dev/mem
+ * access
+ */
+#define xlate_dev_mem_ptr(p) __va(p)
+
+extern int devmem_is_allowed(unsigned long pfn);
+
+#include <asm-generic/io.h>
+
+#endif
diff --git a/arch/parisc/include/asm/irq.h b/arch/parisc/include/asm/irq.h
new file mode 100644
index 000000000..378f63c40
--- /dev/null
+++ b/arch/parisc/include/asm/irq.h
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * include/asm-parisc/irq.h
+ *
+ * Copyright 2005 Matthew Wilcox <matthew@wil.cx>
+ */
+
+#ifndef _ASM_PARISC_IRQ_H
+#define _ASM_PARISC_IRQ_H
+
+#include <linux/cpumask.h>
+#include <asm/types.h>
+
+#define NO_IRQ (-1)
+
+#ifdef CONFIG_GSC
+#define GSC_IRQ_BASE 16
+#define GSC_IRQ_MAX 63
+#define CPU_IRQ_BASE 64
+#else
+#define CPU_IRQ_BASE 16
+#endif
+
+#define TIMER_IRQ (CPU_IRQ_BASE + 0)
+#define IPI_IRQ (CPU_IRQ_BASE + 1)
+#define CPU_IRQ_MAX (CPU_IRQ_BASE + (BITS_PER_LONG - 1))
+
+#define NR_IRQS (CPU_IRQ_MAX + 1)
+
+static __inline__ int irq_canonicalize(int irq)
+{
+ return (irq == 2) ? 9 : irq;
+}
+
+struct irq_chip;
+struct irq_data;
+
+void cpu_ack_irq(struct irq_data *d);
+void cpu_eoi_irq(struct irq_data *d);
+
+extern int txn_alloc_irq(unsigned int nbits);
+extern int txn_claim_irq(int);
+extern unsigned int txn_alloc_data(unsigned int);
+extern unsigned long txn_alloc_addr(unsigned int);
+extern unsigned long txn_affinity_addr(unsigned int irq, int cpu);
+
+extern int cpu_claim_irq(unsigned int irq, struct irq_chip *, void *);
+extern int cpu_check_affinity(struct irq_data *d, const struct cpumask *dest);
+
+#endif /* _ASM_PARISC_IRQ_H */
diff --git a/arch/parisc/include/asm/irqflags.h b/arch/parisc/include/asm/irqflags.h
new file mode 100644
index 000000000..00fd87724
--- /dev/null
+++ b/arch/parisc/include/asm/irqflags.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __PARISC_IRQFLAGS_H
+#define __PARISC_IRQFLAGS_H
+
+#include <linux/types.h>
+#include <asm/psw.h>
+
+static inline unsigned long arch_local_save_flags(void)
+{
+ unsigned long flags;
+ asm volatile("ssm 0, %0" : "=r" (flags) : : "memory");
+ return flags;
+}
+
+static inline void arch_local_irq_disable(void)
+{
+ asm volatile("rsm %0,%%r0\n" : : "i" (PSW_I) : "memory");
+}
+
+static inline void arch_local_irq_enable(void)
+{
+ asm volatile("ssm %0,%%r0\n" : : "i" (PSW_I) : "memory");
+}
+
+static inline unsigned long arch_local_irq_save(void)
+{
+ unsigned long flags;
+ asm volatile("rsm %1,%0" : "=r" (flags) : "i" (PSW_I) : "memory");
+ return flags;
+}
+
+static inline void arch_local_irq_restore(unsigned long flags)
+{
+ /* warn if IRQs are on although they should be off */
+ if (IS_ENABLED(CONFIG_LIGHTWEIGHT_SPINLOCK_CHECK))
+ if (arch_local_save_flags() & PSW_I)
+ asm volatile("break 6,6\n"); /* SPINLOCK_BREAK_INSN */
+
+ asm volatile("mtsm %0" : : "r" (flags) : "memory");
+}
+
+static inline bool arch_irqs_disabled_flags(unsigned long flags)
+{
+ return (flags & PSW_I) == 0;
+}
+
+static inline bool arch_irqs_disabled(void)
+{
+ return arch_irqs_disabled_flags(arch_local_save_flags());
+}
+
+#endif /* __PARISC_IRQFLAGS_H */
diff --git a/arch/parisc/include/asm/jump_label.h b/arch/parisc/include/asm/jump_label.h
new file mode 100644
index 000000000..94428798b
--- /dev/null
+++ b/arch/parisc/include/asm/jump_label.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_PARISC_JUMP_LABEL_H
+#define _ASM_PARISC_JUMP_LABEL_H
+
+#ifndef __ASSEMBLY__
+
+#include <linux/types.h>
+#include <linux/stringify.h>
+#include <asm/assembly.h>
+
+#define JUMP_LABEL_NOP_SIZE 4
+
+static __always_inline bool arch_static_branch(struct static_key *key, bool branch)
+{
+ asm_volatile_goto("1:\n\t"
+ "nop\n\t"
+ ".pushsection __jump_table, \"aw\"\n\t"
+ ".align %1\n\t"
+ ".word 1b - ., %l[l_yes] - .\n\t"
+ __stringify(ASM_ULONG_INSN) " %c0 - .\n\t"
+ ".popsection\n\t"
+ : : "i" (&((char *)key)[branch]), "i" (sizeof(long))
+ : : l_yes);
+
+ return false;
+l_yes:
+ return true;
+}
+
+static __always_inline bool arch_static_branch_jump(struct static_key *key, bool branch)
+{
+ asm_volatile_goto("1:\n\t"
+ "b,n %l[l_yes]\n\t"
+ ".pushsection __jump_table, \"aw\"\n\t"
+ ".align %1\n\t"
+ ".word 1b - ., %l[l_yes] - .\n\t"
+ __stringify(ASM_ULONG_INSN) " %c0 - .\n\t"
+ ".popsection\n\t"
+ : : "i" (&((char *)key)[branch]), "i" (sizeof(long))
+ : : l_yes);
+
+ return false;
+l_yes:
+ return true;
+}
+
+#endif /* __ASSEMBLY__ */
+#endif
diff --git a/arch/parisc/include/asm/kbdleds.h b/arch/parisc/include/asm/kbdleds.h
new file mode 100644
index 000000000..50fcce810
--- /dev/null
+++ b/arch/parisc/include/asm/kbdleds.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_PARISC_KBDLEDS_H
+#define _ASM_PARISC_KBDLEDS_H
+
+/*
+ * On HIL keyboards of PARISC machines there is no NumLock key and
+ * everyone expects the keypad to be used for numbers. That's why
+ * we can safely turn on the NUMLOCK bit.
+ */
+
+static inline int kbd_defleds(void)
+{
+#if defined(CONFIG_KEYBOARD_HIL) || defined(CONFIG_KEYBOARD_HIL_OLD)
+ return 1 << VC_NUMLOCK;
+#else
+ return 0;
+#endif
+}
+
+#endif /* _ASM_PARISC_KBDLEDS_H */
diff --git a/arch/parisc/include/asm/kexec.h b/arch/parisc/include/asm/kexec.h
new file mode 100644
index 000000000..87e174006
--- /dev/null
+++ b/arch/parisc/include/asm/kexec.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_PARISC_KEXEC_H
+#define _ASM_PARISC_KEXEC_H
+
+/* Maximum physical address we can use pages from */
+#define KEXEC_SOURCE_MEMORY_LIMIT (-1UL)
+/* Maximum address we can reach in physical address mode */
+#define KEXEC_DESTINATION_MEMORY_LIMIT (-1UL)
+/* Maximum address we can use for the control code buffer */
+#define KEXEC_CONTROL_MEMORY_LIMIT (-1UL)
+
+#define KEXEC_CONTROL_PAGE_SIZE 4096
+
+#define KEXEC_ARCH KEXEC_ARCH_PARISC
+#define ARCH_HAS_KIMAGE_ARCH
+
+#ifndef __ASSEMBLY__
+
+struct kimage_arch {
+ unsigned long initrd_start;
+ unsigned long initrd_end;
+ unsigned long cmdline;
+};
+
+static inline void crash_setup_regs(struct pt_regs *newregs,
+ struct pt_regs *oldregs)
+{
+ /* Dummy implementation for now */
+}
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_PARISC_KEXEC_H */
diff --git a/arch/parisc/include/asm/kfence.h b/arch/parisc/include/asm/kfence.h
new file mode 100644
index 000000000..6259e5ac1
--- /dev/null
+++ b/arch/parisc/include/asm/kfence.h
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * PA-RISC KFENCE support.
+ *
+ * Copyright (C) 2021, Helge Deller <deller@gmx.de>
+ */
+
+#ifndef _ASM_PARISC_KFENCE_H
+#define _ASM_PARISC_KFENCE_H
+
+#include <linux/kfence.h>
+
+#include <asm/pgtable.h>
+#include <asm/tlbflush.h>
+
+static inline bool arch_kfence_init_pool(void)
+{
+ return true;
+}
+
+/* Protect the given page and flush TLB. */
+static inline bool kfence_protect_page(unsigned long addr, bool protect)
+{
+ pte_t *pte = virt_to_kpte(addr);
+
+ if (WARN_ON(!pte))
+ return false;
+
+ /*
+ * We need to avoid IPIs, as we may get KFENCE allocations or faults
+ * with interrupts disabled.
+ */
+
+ if (protect)
+ set_pte(pte, __pte(pte_val(*pte) & ~_PAGE_PRESENT));
+ else
+ set_pte(pte, __pte(pte_val(*pte) | _PAGE_PRESENT));
+
+ flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
+
+ return true;
+}
+
+#endif /* _ASM_PARISC_KFENCE_H */
diff --git a/arch/parisc/include/asm/kgdb.h b/arch/parisc/include/asm/kgdb.h
new file mode 100644
index 000000000..317cd434b
--- /dev/null
+++ b/arch/parisc/include/asm/kgdb.h
@@ -0,0 +1,70 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * PA-RISC KGDB support
+ *
+ * Copyright (c) 2019 Sven Schnelle <svens@stackframe.org>
+ *
+ */
+
+#ifndef __PARISC_KGDB_H__
+#define __PARISC_KGDB_H__
+
+#define BREAK_INSTR_SIZE 4
+#define PARISC_KGDB_COMPILED_BREAK_INSN 0x3ffc01f
+#define PARISC_KGDB_BREAK_INSN 0x3ffa01f
+
+
+#define NUMREGBYTES sizeof(struct parisc_gdb_regs)
+#define BUFMAX 4096
+
+#define KGDB_MAX_BREAKPOINTS 40
+
+#define CACHE_FLUSH_IS_SAFE 1
+
+#ifndef __ASSEMBLY__
+
+static inline void arch_kgdb_breakpoint(void)
+{
+ asm(".word %0" : : "i"(PARISC_KGDB_COMPILED_BREAK_INSN) : "memory");
+}
+
+struct parisc_gdb_regs {
+ unsigned long gpr[32];
+ unsigned long sar;
+ unsigned long iaoq_f;
+ unsigned long iasq_f;
+ unsigned long iaoq_b;
+ unsigned long iasq_b;
+ unsigned long eiem;
+ unsigned long iir;
+ unsigned long isr;
+ unsigned long ior;
+ unsigned long ipsw;
+ unsigned long __unused0;
+ unsigned long sr4;
+ unsigned long sr0;
+ unsigned long sr1;
+ unsigned long sr2;
+ unsigned long sr3;
+ unsigned long sr5;
+ unsigned long sr6;
+ unsigned long sr7;
+ unsigned long cr0;
+ unsigned long pid1;
+ unsigned long pid2;
+ unsigned long scrccr;
+ unsigned long pid3;
+ unsigned long pid4;
+ unsigned long cr24;
+ unsigned long cr25;
+ unsigned long cr26;
+ unsigned long cr27;
+ unsigned long cr28;
+ unsigned long cr29;
+ unsigned long cr30;
+
+ u64 fr[32];
+};
+
+#endif
+#endif
diff --git a/arch/parisc/include/asm/kprobes.h b/arch/parisc/include/asm/kprobes.h
new file mode 100644
index 000000000..0a175ac87
--- /dev/null
+++ b/arch/parisc/include/asm/kprobes.h
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * arch/parisc/include/asm/kprobes.h
+ *
+ * PA-RISC kprobes implementation
+ *
+ * Copyright (c) 2019 Sven Schnelle <svens@stackframe.org>
+ */
+
+#ifndef _PARISC_KPROBES_H
+#define _PARISC_KPROBES_H
+
+#ifdef CONFIG_KPROBES
+
+#include <asm-generic/kprobes.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/notifier.h>
+
+#define PARISC_KPROBES_BREAK_INSN 0x3ff801f
+#define PARISC_KPROBES_BREAK_INSN2 0x3ff801e
+#define __ARCH_WANT_KPROBES_INSN_SLOT
+#define MAX_INSN_SIZE 2
+
+typedef u32 kprobe_opcode_t;
+struct kprobe;
+
+void arch_remove_kprobe(struct kprobe *p);
+
+#define flush_insn_slot(p) \
+ flush_icache_range((unsigned long)&(p)->ainsn.insn[0], \
+ (unsigned long)&(p)->ainsn.insn[0] + \
+ MAX_INSN_SIZE*sizeof(kprobe_opcode_t))
+
+#define kretprobe_blacklist_size 0
+
+struct arch_specific_insn {
+ kprobe_opcode_t *insn;
+};
+
+struct prev_kprobe {
+ struct kprobe *kp;
+ unsigned long status;
+};
+
+struct kprobe_ctlblk {
+ unsigned int kprobe_status;
+ struct prev_kprobe prev_kprobe;
+ unsigned long iaoq[2];
+};
+
+int __kprobes parisc_kprobe_break_handler(struct pt_regs *regs);
+int __kprobes parisc_kprobe_ss_handler(struct pt_regs *regs);
+static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
+{
+ return 0;
+}
+
+#endif /* CONFIG_KPROBES */
+#endif /* _PARISC_KPROBES_H */
diff --git a/arch/parisc/include/asm/ldcw.h b/arch/parisc/include/asm/ldcw.h
new file mode 100644
index 000000000..47ebc4c91
--- /dev/null
+++ b/arch/parisc/include/asm/ldcw.h
@@ -0,0 +1,61 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __PARISC_LDCW_H
+#define __PARISC_LDCW_H
+
+/* Because kmalloc only guarantees 8-byte alignment for kmalloc'd data,
+ and GCC only guarantees 8-byte alignment for stack locals, we can't
+ be assured of 16-byte alignment for atomic lock data even if we
+ specify "__attribute ((aligned(16)))" in the type declaration. So,
+ we use a struct containing an array of four ints for the atomic lock
+ type and dynamically select the 16-byte aligned int from the array
+ for the semaphore. */
+
+/* From: "Jim Hull" <jim.hull of hp.com>
+ I've attached a summary of the change, but basically, for PA 2.0, as
+ long as the ",CO" (coherent operation) completer is implemented, then the
+ 16-byte alignment requirement for ldcw and ldcd is relaxed, and instead
+ they only require "natural" alignment (4-byte for ldcw, 8-byte for
+ ldcd).
+
+ Although the cache control hint is accepted by all PA 2.0 processors,
+ it is only implemented on PA8800/PA8900 CPUs. Prior PA8X00 CPUs still
+ require 16-byte alignment. If the address is unaligned, the operation
+ of the instruction is undefined. The ldcw instruction does not generate
+ unaligned data reference traps so misaligned accesses are not detected.
+ This hid the problem for years. So, restore the 16-byte alignment dropped
+ by Kyle McMartin in "Remove __ldcw_align for PA-RISC 2.0 processors". */
+
+#define __PA_LDCW_ALIGNMENT 16
+#define __ldcw_align(a) ({ \
+ unsigned long __ret = (unsigned long) &(a)->lock[0]; \
+ __ret = (__ret + __PA_LDCW_ALIGNMENT - 1) \
+ & ~(__PA_LDCW_ALIGNMENT - 1); \
+ (volatile unsigned int *) __ret; \
+})
+
+#ifdef CONFIG_PA20
+#define __LDCW "ldcw,co"
+#else
+#define __LDCW "ldcw"
+#endif
+
+/* LDCW, the only atomic read-write operation PA-RISC has. *sigh*.
+ We don't explicitly expose that "*a" may be written as reload
+ fails to find a register in class R1_REGS when "a" needs to be
+ reloaded when generating 64-bit PIC code. Instead, we clobber
+ memory to indicate to the compiler that the assembly code reads
+ or writes to items other than those listed in the input and output
+ operands. This may pessimize the code somewhat but __ldcw is
+ usually used within code blocks surrounded by memory barriers. */
+#define __ldcw(a) ({ \
+ unsigned __ret; \
+ __asm__ __volatile__(__LDCW " 0(%1),%0" \
+ : "=r" (__ret) : "r" (a) : "memory"); \
+ __ret; \
+})
+
+#ifdef CONFIG_SMP
+# define __lock_aligned __section(".data..lock_aligned") __aligned(16)
+#endif
+
+#endif /* __PARISC_LDCW_H */
diff --git a/arch/parisc/include/asm/led.h b/arch/parisc/include/asm/led.h
new file mode 100644
index 000000000..0aea47eff
--- /dev/null
+++ b/arch/parisc/include/asm/led.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef LED_H
+#define LED_H
+
+#define LED7 0x80 /* top (or furthest right) LED */
+#define LED6 0x40
+#define LED5 0x20
+#define LED4 0x10
+#define LED3 0x08
+#define LED2 0x04
+#define LED1 0x02
+#define LED0 0x01 /* bottom (or furthest left) LED */
+
+#define LED_LAN_RCV LED0 /* for LAN receive activity */
+#define LED_LAN_TX LED1 /* for LAN transmit activity */
+#define LED_DISK_IO LED2 /* for disk activity */
+#define LED_HEARTBEAT LED3 /* heartbeat */
+
+/* values for pdc_chassis_lcd_info_ret_block.model: */
+#define DISPLAY_MODEL_LCD 0 /* KittyHawk LED or LCD */
+#define DISPLAY_MODEL_NONE 1 /* no LED or LCD */
+#define DISPLAY_MODEL_LASI 2 /* LASI style 8 bit LED */
+#define DISPLAY_MODEL_OLD_ASP 0x7F /* faked: ASP style 8 x 1 bit LED (only very old ASP versions) */
+
+#define LED_CMD_REG_NONE 0 /* NULL == no addr for the cmd register */
+
+/* register_led_driver() */
+int register_led_driver(int model, unsigned long cmd_reg, unsigned long data_reg);
+
+#ifdef CONFIG_CHASSIS_LCD_LED
+/* writes a string to the LCD display (if possible on this h/w) */
+void lcd_print(const char *str);
+#else
+#define lcd_print(str) do { } while (0)
+#endif
+
+#endif /* LED_H */
diff --git a/arch/parisc/include/asm/linkage.h b/arch/parisc/include/asm/linkage.h
new file mode 100644
index 000000000..cd6fe4feb
--- /dev/null
+++ b/arch/parisc/include/asm/linkage.h
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_PARISC_LINKAGE_H
+#define __ASM_PARISC_LINKAGE_H
+
+#include <asm/dwarf.h>
+
+#ifndef __ALIGN
+#define __ALIGN .align 4
+#define __ALIGN_STR ".align 4"
+#endif
+
+/*
+ * In parisc assembly a semicolon marks a comment while a
+ * exclamation mark is used to separate independent lines.
+ */
+#define ASM_NL !
+
+#ifdef __ASSEMBLY__
+
+#define ENTRY(name) \
+ ALIGN !\
+name: ASM_NL\
+ .export name
+
+#define ENTRY_CFI(name, ...) \
+ ENTRY(name) ASM_NL\
+ .proc ASM_NL\
+ .callinfo __VA_ARGS__ ASM_NL\
+ .entry ASM_NL\
+ CFI_STARTPROC
+
+#define ENDPROC_CFI(name) \
+ CFI_ENDPROC ASM_NL\
+ .exit ASM_NL\
+ .procend ASM_NL\
+ ENDPROC(name)
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __ASM_PARISC_LINKAGE_H */
diff --git a/arch/parisc/include/asm/mmu.h b/arch/parisc/include/asm/mmu.h
new file mode 100644
index 000000000..44fd062b6
--- /dev/null
+++ b/arch/parisc/include/asm/mmu.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _PARISC_MMU_H_
+#define _PARISC_MMU_H_
+
+typedef struct {
+ unsigned long space_id;
+ unsigned long vdso_base;
+} mm_context_t;
+
+#endif /* _PARISC_MMU_H_ */
diff --git a/arch/parisc/include/asm/mmu_context.h b/arch/parisc/include/asm/mmu_context.h
new file mode 100644
index 000000000..c9187fe83
--- /dev/null
+++ b/arch/parisc/include/asm/mmu_context.h
@@ -0,0 +1,100 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __PARISC_MMU_CONTEXT_H
+#define __PARISC_MMU_CONTEXT_H
+
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/atomic.h>
+#include <linux/spinlock.h>
+#include <asm-generic/mm_hooks.h>
+
+/* on PA-RISC, we actually have enough contexts to justify an allocator
+ * for them. prumpf */
+
+extern unsigned long alloc_sid(void);
+extern void free_sid(unsigned long);
+
+#define init_new_context init_new_context
+static inline int
+init_new_context(struct task_struct *tsk, struct mm_struct *mm)
+{
+ BUG_ON(atomic_read(&mm->mm_users) != 1);
+
+ mm->context.space_id = alloc_sid();
+ return 0;
+}
+
+#define destroy_context destroy_context
+static inline void
+destroy_context(struct mm_struct *mm)
+{
+ free_sid(mm->context.space_id);
+ mm->context.space_id = 0;
+}
+
+static inline unsigned long __space_to_prot(mm_context_t context)
+{
+#if SPACEID_SHIFT == 0
+ return context.space_id << 1;
+#else
+ return context.space_id >> (SPACEID_SHIFT - 1);
+#endif
+}
+
+static inline void load_context(mm_context_t context)
+{
+ mtsp(context.space_id, SR_USER);
+ mtctl(__space_to_prot(context), 8);
+}
+
+static inline void switch_mm_irqs_off(struct mm_struct *prev,
+ struct mm_struct *next, struct task_struct *tsk)
+{
+ if (prev != next) {
+#ifdef CONFIG_TLB_PTLOCK
+ /* put physical address of page_table_lock in cr28 (tr4)
+ for TLB faults */
+ spinlock_t *pgd_lock = &next->page_table_lock;
+ mtctl(__pa(__ldcw_align(&pgd_lock->rlock.raw_lock)), 28);
+#endif
+ mtctl(__pa(next->pgd), 25);
+ load_context(next->context);
+ }
+}
+
+static inline void switch_mm(struct mm_struct *prev,
+ struct mm_struct *next, struct task_struct *tsk)
+{
+ unsigned long flags;
+
+ if (prev == next)
+ return;
+
+ local_irq_save(flags);
+ switch_mm_irqs_off(prev, next, tsk);
+ local_irq_restore(flags);
+}
+#define switch_mm_irqs_off switch_mm_irqs_off
+
+#define activate_mm activate_mm
+static inline void activate_mm(struct mm_struct *prev, struct mm_struct *next)
+{
+ /*
+ * Activate_mm is our one chance to allocate a space id
+ * for a new mm created in the exec path. There's also
+ * some lazy tlb stuff, which is currently dead code, but
+ * we only allocate a space id if one hasn't been allocated
+ * already, so we should be OK.
+ */
+
+ BUG_ON(next == &init_mm); /* Should never happen */
+
+ if (next->context.space_id == 0)
+ next->context.space_id = alloc_sid();
+
+ switch_mm(prev,next,current);
+}
+
+#include <asm-generic/mmu_context.h>
+
+#endif
diff --git a/arch/parisc/include/asm/mmzone.h b/arch/parisc/include/asm/mmzone.h
new file mode 100644
index 000000000..8d390406d
--- /dev/null
+++ b/arch/parisc/include/asm/mmzone.h
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _PARISC_MMZONE_H
+#define _PARISC_MMZONE_H
+
+#define MAX_PHYSMEM_RANGES 4 /* Fix the size for now (current known max is 3) */
+
+#endif /* _PARISC_MMZONE_H */
diff --git a/arch/parisc/include/asm/module.h b/arch/parisc/include/asm/module.h
new file mode 100644
index 000000000..c8c131a74
--- /dev/null
+++ b/arch/parisc/include/asm/module.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_PARISC_MODULE_H
+#define _ASM_PARISC_MODULE_H
+
+#include <asm-generic/module.h>
+
+/*
+ * This file contains the parisc architecture specific module code.
+ */
+
+struct unwind_table;
+
+struct mod_arch_specific
+{
+ unsigned long got_offset, got_count, got_max;
+ unsigned long fdesc_offset, fdesc_count, fdesc_max;
+ struct {
+ unsigned long stub_offset;
+ unsigned int stub_entries;
+ } *section;
+ int unwind_section;
+ struct unwind_table *unwind;
+};
+
+#endif /* _ASM_PARISC_MODULE_H */
diff --git a/arch/parisc/include/asm/page.h b/arch/parisc/include/asm/page.h
new file mode 100644
index 000000000..667e703c0
--- /dev/null
+++ b/arch/parisc/include/asm/page.h
@@ -0,0 +1,190 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _PARISC_PAGE_H
+#define _PARISC_PAGE_H
+
+#include <linux/const.h>
+
+#if defined(CONFIG_PARISC_PAGE_SIZE_4KB)
+# define PAGE_SHIFT 12
+#elif defined(CONFIG_PARISC_PAGE_SIZE_16KB)
+# define PAGE_SHIFT 14
+#elif defined(CONFIG_PARISC_PAGE_SIZE_64KB)
+# define PAGE_SHIFT 16
+#else
+# error "unknown default kernel page size"
+#endif
+#define PAGE_SIZE (_AC(1,UL) << PAGE_SHIFT)
+#define PAGE_MASK (~(PAGE_SIZE-1))
+
+
+#ifndef __ASSEMBLY__
+
+#include <asm/types.h>
+#include <asm/cache.h>
+
+#define clear_page(page) clear_page_asm((void *)(page))
+#define copy_page(to, from) copy_page_asm((void *)(to), (void *)(from))
+
+struct page;
+struct vm_area_struct;
+
+void clear_page_asm(void *page);
+void copy_page_asm(void *to, void *from);
+#define clear_user_page(vto, vaddr, page) clear_page_asm(vto)
+void copy_user_highpage(struct page *to, struct page *from, unsigned long vaddr,
+ struct vm_area_struct *vma);
+#define __HAVE_ARCH_COPY_USER_HIGHPAGE
+
+/*
+ * These are used to make use of C type-checking..
+ */
+#define STRICT_MM_TYPECHECKS
+#ifdef STRICT_MM_TYPECHECKS
+typedef struct { unsigned long pte; } pte_t; /* either 32 or 64bit */
+
+/* NOTE: even on 64 bits, these entries are __u32 because we allocate
+ * the pmd and pgd in ZONE_DMA (i.e. under 4GB) */
+typedef struct { __u32 pgd; } pgd_t;
+typedef struct { unsigned long pgprot; } pgprot_t;
+
+#if CONFIG_PGTABLE_LEVELS == 3
+typedef struct { __u32 pmd; } pmd_t;
+#define __pmd(x) ((pmd_t) { (x) } )
+/* pXd_val() do not work as lvalues, so make sure we don't use them as such. */
+#define pmd_val(x) ((x).pmd + 0)
+#endif
+
+#define pte_val(x) ((x).pte)
+#define pgd_val(x) ((x).pgd + 0)
+#define pgprot_val(x) ((x).pgprot)
+
+#define __pte(x) ((pte_t) { (x) } )
+#define __pgd(x) ((pgd_t) { (x) } )
+#define __pgprot(x) ((pgprot_t) { (x) } )
+
+#else
+/*
+ * .. while these make it easier on the compiler
+ */
+typedef unsigned long pte_t;
+
+#if CONFIG_PGTABLE_LEVELS == 3
+typedef __u32 pmd_t;
+#define pmd_val(x) (x)
+#define __pmd(x) (x)
+#endif
+
+typedef __u32 pgd_t;
+typedef unsigned long pgprot_t;
+
+#define pte_val(x) (x)
+#define pgd_val(x) (x)
+#define pgprot_val(x) (x)
+
+#define __pte(x) (x)
+#define __pgd(x) (x)
+#define __pgprot(x) (x)
+
+#endif /* STRICT_MM_TYPECHECKS */
+
+#define set_pmd(pmdptr, pmdval) (*(pmdptr) = (pmdval))
+#if CONFIG_PGTABLE_LEVELS == 3
+#define set_pud(pudptr, pudval) (*(pudptr) = (pudval))
+#endif
+
+typedef struct page *pgtable_t;
+
+typedef struct __physmem_range {
+ unsigned long start_pfn;
+ unsigned long pages; /* PAGE_SIZE pages */
+} physmem_range_t;
+
+extern physmem_range_t pmem_ranges[];
+extern int npmem_ranges;
+
+#endif /* !__ASSEMBLY__ */
+
+/* WARNING: The definitions below must match exactly to sizeof(pte_t)
+ * etc
+ */
+#ifdef CONFIG_64BIT
+#define BITS_PER_PTE_ENTRY 3
+#define BITS_PER_PMD_ENTRY 2
+#define BITS_PER_PGD_ENTRY 2
+#else
+#define BITS_PER_PTE_ENTRY 2
+#define BITS_PER_PMD_ENTRY 2
+#define BITS_PER_PGD_ENTRY 2
+#endif
+#define PGD_ENTRY_SIZE (1UL << BITS_PER_PGD_ENTRY)
+#define PMD_ENTRY_SIZE (1UL << BITS_PER_PMD_ENTRY)
+#define PTE_ENTRY_SIZE (1UL << BITS_PER_PTE_ENTRY)
+
+#define LINUX_GATEWAY_SPACE 0
+
+/* This governs the relationship between virtual and physical addresses.
+ * If you alter it, make sure to take care of our various fixed mapping
+ * segments in fixmap.h */
+#ifdef CONFIG_64BIT
+#define __PAGE_OFFSET_DEFAULT (0x40000000) /* 1GB */
+#else
+#define __PAGE_OFFSET_DEFAULT (0x10000000) /* 256MB */
+#endif
+
+#if defined(BOOTLOADER)
+#define __PAGE_OFFSET (0) /* bootloader uses physical addresses */
+#else
+#define __PAGE_OFFSET __PAGE_OFFSET_DEFAULT
+#endif /* BOOTLOADER */
+
+#define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET)
+
+/* The size of the gateway page (we leave lots of room for expansion) */
+#define GATEWAY_PAGE_SIZE 0x4000
+
+/* The start of the actual kernel binary---used in vmlinux.lds.S
+ * Leave some space after __PAGE_OFFSET for detecting kernel null
+ * ptr derefs */
+#define KERNEL_BINARY_TEXT_START (__PAGE_OFFSET + 0x100000)
+
+/* These macros don't work for 64-bit C code -- don't allow in C at all */
+#ifdef __ASSEMBLY__
+# define PA(x) ((x)-__PAGE_OFFSET)
+# define VA(x) ((x)+__PAGE_OFFSET)
+#endif
+#define __pa(x) ((unsigned long)(x)-PAGE_OFFSET)
+#define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET))
+
+#ifdef CONFIG_HUGETLB_PAGE
+#define HPAGE_SHIFT PMD_SHIFT /* fixed for transparent huge pages */
+#define HPAGE_SIZE ((1UL) << HPAGE_SHIFT)
+#define HPAGE_MASK (~(HPAGE_SIZE - 1))
+#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT)
+
+#if defined(CONFIG_64BIT) && defined(CONFIG_PARISC_PAGE_SIZE_4KB)
+# define REAL_HPAGE_SHIFT 20 /* 20 = 1MB */
+# define _HUGE_PAGE_SIZE_ENCODING_DEFAULT _PAGE_SIZE_ENCODING_1M
+#elif !defined(CONFIG_64BIT) && defined(CONFIG_PARISC_PAGE_SIZE_4KB)
+# define REAL_HPAGE_SHIFT 22 /* 22 = 4MB */
+# define _HUGE_PAGE_SIZE_ENCODING_DEFAULT _PAGE_SIZE_ENCODING_4M
+#else
+# define REAL_HPAGE_SHIFT 24 /* 24 = 16MB */
+# define _HUGE_PAGE_SIZE_ENCODING_DEFAULT _PAGE_SIZE_ENCODING_16M
+#endif
+#endif /* CONFIG_HUGETLB_PAGE */
+
+#define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
+
+#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT)
+#define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
+
+#include <asm-generic/memory_model.h>
+#include <asm-generic/getorder.h>
+#include <asm/pdc.h>
+
+#define PAGE0 ((struct zeropage *)absolute_pointer(__PAGE_OFFSET))
+
+/* DEFINITION OF THE ZERO-PAGE (PAG0) */
+/* based on work by Jason Eckhardt (jason@equator.com) */
+
+#endif /* _PARISC_PAGE_H */
diff --git a/arch/parisc/include/asm/parisc-device.h b/arch/parisc/include/asm/parisc-device.h
new file mode 100644
index 000000000..4de3b391d
--- /dev/null
+++ b/arch/parisc/include/asm/parisc-device.h
@@ -0,0 +1,68 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_PARISC_PARISC_DEVICE_H_
+#define _ASM_PARISC_PARISC_DEVICE_H_
+
+#include <linux/device.h>
+
+struct parisc_device {
+ struct resource hpa; /* Hard Physical Address */
+ struct parisc_device_id id;
+ struct parisc_driver *driver; /* Driver for this device */
+ char name[80]; /* The hardware description */
+ int irq;
+ int aux_irq; /* Some devices have a second IRQ */
+
+ char hw_path; /* The module number on this bus */
+ unsigned int num_addrs; /* some devices have additional address ranges. */
+ unsigned long *addr; /* which will be stored here */
+
+#ifdef CONFIG_64BIT
+ /* parms for pdc_pat_cell_module() call */
+ unsigned long pcell_loc; /* Physical Cell location */
+ unsigned long mod_index; /* PAT specific - Misc Module info */
+
+ /* generic info returned from pdc_pat_cell_module() */
+ unsigned long mod_info; /* PAT specific - Misc Module info */
+ unsigned long pmod_loc; /* physical Module location */
+ unsigned long mod0;
+#endif
+ u64 dma_mask; /* DMA mask for I/O */
+ struct device dev;
+};
+
+struct parisc_driver {
+ struct parisc_driver *next;
+ char *name;
+ const struct parisc_device_id *id_table;
+ int (*probe)(struct parisc_device *dev); /* New device discovered */
+ void (*remove)(struct parisc_device *dev);
+ struct device_driver drv;
+};
+
+
+#define to_parisc_device(d) container_of(d, struct parisc_device, dev)
+#define to_parisc_driver(d) container_of(d, struct parisc_driver, drv)
+#define parisc_parent(d) to_parisc_device(d->dev.parent)
+
+static inline const char *parisc_pathname(struct parisc_device *d)
+{
+ return dev_name(&d->dev);
+}
+
+static inline void
+parisc_set_drvdata(struct parisc_device *d, void *p)
+{
+ dev_set_drvdata(&d->dev, p);
+}
+
+static inline void *
+parisc_get_drvdata(struct parisc_device *d)
+{
+ return dev_get_drvdata(&d->dev);
+}
+
+extern struct bus_type parisc_bus_type;
+
+int iosapic_serial_irq(struct parisc_device *dev);
+
+#endif /*_ASM_PARISC_PARISC_DEVICE_H_*/
diff --git a/arch/parisc/include/asm/parport.h b/arch/parisc/include/asm/parport.h
new file mode 100644
index 000000000..2c8e2321c
--- /dev/null
+++ b/arch/parisc/include/asm/parport.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ *
+ * parport.h: ia32-compatible parport initialisation
+ *
+ * This file should only be included by drivers/parport/parport_pc.c.
+ */
+#ifndef _ASM_PARPORT_H
+#define _ASM_PARPORT_H 1
+
+
+static int parport_pc_find_nonpci_ports (int autoirq, int autodma)
+{
+ /* nothing ! */
+ return 0;
+}
+
+
+#endif /* !(_ASM_PARPORT_H) */
diff --git a/arch/parisc/include/asm/patch.h b/arch/parisc/include/asm/patch.h
new file mode 100644
index 000000000..400d84c6e
--- /dev/null
+++ b/arch/parisc/include/asm/patch.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _PARISC_KERNEL_PATCH_H
+#define _PARISC_KERNEL_PATCH_H
+
+/* stop machine and patch kernel text */
+void patch_text(void *addr, unsigned int insn);
+void patch_text_multiple(void *addr, u32 *insn, unsigned int len);
+
+/* patch kernel text with machine already stopped (e.g. in kgdb) */
+void __patch_text(void *addr, u32 insn);
+void __patch_text_multiple(void *addr, u32 *insn, unsigned int len);
+
+#endif
diff --git a/arch/parisc/include/asm/pci.h b/arch/parisc/include/asm/pci.h
new file mode 100644
index 000000000..127ed5021
--- /dev/null
+++ b/arch/parisc/include/asm/pci.h
@@ -0,0 +1,168 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_PARISC_PCI_H
+#define __ASM_PARISC_PCI_H
+
+#include <linux/scatterlist.h>
+
+
+
+/*
+** HP PCI platforms generally support multiple bus adapters.
+** (workstations 1-~4, servers 2-~32)
+**
+** Newer platforms number the busses across PCI bus adapters *sparsely*.
+** E.g. 0, 8, 16, ...
+**
+** Under a PCI bus, most HP platforms support PPBs up to two or three
+** levels deep. See "Bit3" product line.
+*/
+#define PCI_MAX_BUSSES 256
+
+
+/* To be used as: mdelay(pci_post_reset_delay);
+ *
+ * post_reset is the time the kernel should stall to prevent anyone from
+ * accessing the PCI bus once #RESET is de-asserted.
+ * PCI spec somewhere says 1 second but with multi-PCI bus systems,
+ * this makes the boot time much longer than necessary.
+ * 20ms seems to work for all the HP PCI implementations to date.
+ */
+#define pci_post_reset_delay 50
+
+
+/*
+** pci_hba_data (aka H2P_OBJECT in HP/UX)
+**
+** This is the "common" or "base" data structure which HBA drivers
+** (eg Dino or LBA) are required to place at the top of their own
+** platform_data structure. I've heard this called "C inheritance" too.
+**
+** Data needed by pcibios layer belongs here.
+*/
+struct pci_hba_data {
+ void __iomem *base_addr; /* aka Host Physical Address */
+ const struct parisc_device *dev; /* device from PA bus walk */
+ struct pci_bus *hba_bus; /* primary PCI bus below HBA */
+ int hba_num; /* I/O port space access "key" */
+ struct resource bus_num; /* PCI bus numbers */
+ struct resource io_space; /* PIOP */
+ struct resource lmmio_space; /* bus addresses < 4Gb */
+ struct resource elmmio_space; /* additional bus addresses < 4Gb */
+ struct resource gmmio_space; /* bus addresses > 4Gb */
+
+ /* NOTE: Dino code assumes it can use *all* of the lmmio_space,
+ * elmmio_space and gmmio_space as a contiguous array of
+ * resources. This #define represents the array size */
+ #define DINO_MAX_LMMIO_RESOURCES 3
+
+ unsigned long lmmio_space_offset; /* CPU view - PCI view */
+ struct ioc *iommu; /* IOMMU this device is under */
+ /* REVISIT - spinlock to protect resources? */
+
+ #define HBA_NAME_SIZE 16
+ char io_name[HBA_NAME_SIZE];
+ char lmmio_name[HBA_NAME_SIZE];
+ char elmmio_name[HBA_NAME_SIZE];
+ char gmmio_name[HBA_NAME_SIZE];
+};
+
+/*
+** We support 2^16 I/O ports per HBA. These are set up in the form
+** 0xbbxxxx, where bb is the bus number and xxxx is the I/O port
+** space address.
+*/
+#define HBA_PORT_SPACE_BITS 16
+
+#define HBA_PORT_BASE(h) ((h) << HBA_PORT_SPACE_BITS)
+#define HBA_PORT_SPACE_SIZE (1UL << HBA_PORT_SPACE_BITS)
+
+#define PCI_PORT_HBA(a) ((a) >> HBA_PORT_SPACE_BITS)
+#define PCI_PORT_ADDR(a) ((a) & (HBA_PORT_SPACE_SIZE - 1))
+
+#ifdef CONFIG_64BIT
+#define PCI_F_EXTEND 0xffffffff00000000UL
+#else /* !CONFIG_64BIT */
+#define PCI_F_EXTEND 0UL
+#endif /* !CONFIG_64BIT */
+
+/*
+** Most PCI devices (eg Tulip, NCR720) also export the same registers
+** to both MMIO and I/O port space. Due to poor performance of I/O Port
+** access under HP PCI bus adapters, strongly recommend the use of MMIO
+** address space.
+**
+** While I'm at it more PA programming notes:
+**
+** 1) MMIO stores (writes) are posted operations. This means the processor
+** gets an "ACK" before the write actually gets to the device. A read
+** to the same device (or typically the bus adapter above it) will
+** force in-flight write transaction(s) out to the targeted device
+** before the read can complete.
+**
+** 2) The Programmed I/O (PIO) data may not always be strongly ordered with
+** respect to DMA on all platforms. Ie PIO data can reach the processor
+** before in-flight DMA reaches memory. Since most SMP PA platforms
+** are I/O coherent, it generally doesn't matter...but sometimes
+** it does.
+**
+** I've helped device driver writers debug both types of problems.
+*/
+struct pci_port_ops {
+ u8 (*inb) (struct pci_hba_data *hba, u16 port);
+ u16 (*inw) (struct pci_hba_data *hba, u16 port);
+ u32 (*inl) (struct pci_hba_data *hba, u16 port);
+ void (*outb) (struct pci_hba_data *hba, u16 port, u8 data);
+ void (*outw) (struct pci_hba_data *hba, u16 port, u16 data);
+ void (*outl) (struct pci_hba_data *hba, u16 port, u32 data);
+};
+
+
+struct pci_bios_ops {
+ void (*init)(void);
+ void (*fixup_bus)(struct pci_bus *bus);
+};
+
+/*
+** Stuff declared in arch/parisc/kernel/pci.c
+*/
+extern struct pci_port_ops *pci_port;
+extern struct pci_bios_ops *pci_bios;
+
+#ifdef CONFIG_PCI
+extern void pcibios_register_hba(struct pci_hba_data *);
+#else
+static inline void pcibios_register_hba(struct pci_hba_data *x)
+{
+}
+#endif
+extern void pcibios_init_bridge(struct pci_dev *);
+
+/*
+ * pcibios_assign_all_busses() is used in drivers/pci/pci.c:pci_do_scan_bus()
+ * 0 == check if bridge is numbered before re-numbering.
+ * 1 == pci_do_scan_bus() should automatically number all PCI-PCI bridges.
+ *
+ * We *should* set this to zero for "legacy" platforms and one
+ * for PAT platforms.
+ *
+ * But legacy platforms also need to renumber the busses below a Host
+ * Bus controller. Adding a 4-port Tulip card on the first PCI root
+ * bus of a C200 resulted in the secondary bus being numbered as 1.
+ * The second PCI host bus controller's root bus had already been
+ * assigned bus number 1 by firmware and sysfs complained.
+ *
+ * Firmware isn't doing anything wrong here since each controller
+ * is its own PCI domain. It's simpler and easier for us to renumber
+ * the busses rather than treat each Dino as a separate PCI domain.
+ * Eventually, we may want to introduce PCI domains for Superdome or
+ * rp7420/8420 boxes and then revisit this issue.
+ */
+#define pcibios_assign_all_busses() (1)
+
+#define PCIBIOS_MIN_IO 0x10
+#define PCIBIOS_MIN_MEM 0x1000 /* NBPG - but pci/setup-res.c dies */
+
+#define HAVE_PCI_MMAP
+#define ARCH_GENERIC_PCI_MMAP_RESOURCE
+
+#endif /* __ASM_PARISC_PCI_H */
diff --git a/arch/parisc/include/asm/pdc.h b/arch/parisc/include/asm/pdc.h
new file mode 100644
index 000000000..5d2d9737e
--- /dev/null
+++ b/arch/parisc/include/asm/pdc.h
@@ -0,0 +1,113 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _PARISC_PDC_H
+#define _PARISC_PDC_H
+
+#include <uapi/asm/pdc.h>
+
+#if !defined(__ASSEMBLY__)
+
+extern int parisc_narrow_firmware;
+
+extern int pdc_type;
+extern unsigned long parisc_cell_num; /* cell number the CPU runs on (PAT) */
+extern unsigned long parisc_cell_loc; /* cell location of CPU (PAT) */
+extern unsigned long parisc_pat_pdc_cap; /* PDC capabilities (PAT) */
+
+/* Values for pdc_type */
+#define PDC_TYPE_ILLEGAL -1
+#define PDC_TYPE_PAT 0 /* 64-bit PAT-PDC */
+#define PDC_TYPE_SYSTEM_MAP 1 /* 32-bit, but supports PDC_SYSTEM_MAP */
+#define PDC_TYPE_SNAKE 2 /* Doesn't support SYSTEM_MAP */
+
+void setup_pdc(void); /* in inventory.c */
+
+/* wrapper-functions from pdc.c */
+
+int pdc_add_valid(unsigned long address);
+int pdc_instr(unsigned int *instr);
+int pdc_chassis_info(struct pdc_chassis_info *chassis_info, void *led_info, unsigned long len);
+int pdc_chassis_disp(unsigned long disp);
+int pdc_chassis_warn(unsigned long *warn);
+int pdc_coproc_cfg(struct pdc_coproc_cfg *pdc_coproc_info);
+int pdc_coproc_cfg_unlocked(struct pdc_coproc_cfg *pdc_coproc_info);
+int pdc_iodc_read(unsigned long *actcnt, unsigned long hpa, unsigned int index,
+ void *iodc_data, unsigned int iodc_data_size);
+int pdc_system_map_find_mods(struct pdc_system_map_mod_info *pdc_mod_info,
+ struct pdc_module_path *mod_path, long mod_index);
+int pdc_system_map_find_addrs(struct pdc_system_map_addr_info *pdc_addr_info,
+ long mod_index, long addr_index);
+int pdc_model_info(struct pdc_model *model);
+int pdc_model_sysmodel(unsigned int os_id, char *name);
+int pdc_model_cpuid(unsigned long *cpu_id);
+int pdc_model_versions(unsigned long *versions, int id);
+int pdc_model_capabilities(unsigned long *capabilities);
+int pdc_model_platform_info(char *orig_prod_num, char *current_prod_num, char *serial_no);
+int pdc_cache_info(struct pdc_cache_info *cache);
+int pdc_spaceid_bits(unsigned long *space_bits);
+int pdc_btlb_info(struct pdc_btlb_info *btlb);
+int pdc_btlb_insert(unsigned long long vpage, unsigned long physpage, unsigned long len,
+ unsigned long entry_info, unsigned long slot);
+int pdc_btlb_purge_all(void);
+int pdc_mem_map_hpa(struct pdc_memory_map *r_addr, struct pdc_module_path *mod_path);
+int pdc_pim_toc11(struct pdc_toc_pim_11 *ret);
+int pdc_pim_toc20(struct pdc_toc_pim_20 *ret);
+int pdc_lan_station_id(char *lan_addr, unsigned long net_hpa);
+
+int pdc_stable_read(unsigned long staddr, void *memaddr, unsigned long count);
+int pdc_stable_write(unsigned long staddr, void *memaddr, unsigned long count);
+int pdc_stable_get_size(unsigned long *size);
+int pdc_stable_verify_contents(void);
+int pdc_stable_initialize(void);
+
+int pdc_pci_irt_size(unsigned long *num_entries, unsigned long hpa);
+int pdc_pci_irt(unsigned long num_entries, unsigned long hpa, void *tbl);
+
+int pdc_get_initiator(struct hardware_path *, struct pdc_initiator *);
+int pdc_tod_read(struct pdc_tod *tod);
+int pdc_tod_set(unsigned long sec, unsigned long usec);
+
+void pdc_pdt_init(void); /* in pdt.c */
+int pdc_mem_pdt_info(struct pdc_mem_retinfo *rinfo);
+int pdc_mem_pdt_read_entries(struct pdc_mem_read_pdt *rpdt_read,
+ unsigned long *pdt_entries_ptr);
+#ifdef CONFIG_64BIT
+int pdc_mem_mem_table(struct pdc_memory_table_raddr *r_addr,
+ struct pdc_memory_table *tbl, unsigned long entries);
+#endif
+
+void set_firmware_width(void);
+void set_firmware_width_unlocked(void);
+int pdc_do_firm_test_reset(unsigned long ftc_bitmap);
+int pdc_do_reset(void);
+int pdc_soft_power_info(unsigned long *power_reg);
+int pdc_soft_power_button(int sw_control);
+int pdc_soft_power_button_panic(int sw_control);
+void pdc_io_reset(void);
+void pdc_io_reset_devices(void);
+int pdc_iodc_getc(void);
+int pdc_iodc_print(const unsigned char *str, unsigned count);
+
+void pdc_emergency_unlock(void);
+int pdc_sti_call(unsigned long func, unsigned long flags,
+ unsigned long inptr, unsigned long outputr,
+ unsigned long glob_cfg, int do_call64);
+
+int __pdc_cpu_rendezvous(void);
+void pdc_cpu_rendezvous_lock(void);
+void pdc_cpu_rendezvous_unlock(void);
+
+static inline char * os_id_to_string(u16 os_id) {
+ switch(os_id) {
+ case OS_ID_NONE: return "No OS";
+ case OS_ID_HPUX: return "HP-UX";
+ case OS_ID_MPEXL: return "MPE-iX";
+ case OS_ID_OSF: return "OSF";
+ case OS_ID_HPRT: return "HP-RT";
+ case OS_ID_NOVEL: return "Novell Netware";
+ case OS_ID_LINUX: return "Linux";
+ default: return "Unknown";
+ }
+}
+
+#endif /* !defined(__ASSEMBLY__) */
+#endif /* _PARISC_PDC_H */
diff --git a/arch/parisc/include/asm/pdc_chassis.h b/arch/parisc/include/asm/pdc_chassis.h
new file mode 100644
index 000000000..d6d82f53d
--- /dev/null
+++ b/arch/parisc/include/asm/pdc_chassis.h
@@ -0,0 +1,367 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * include/asm-parisc/pdc_chassis.h
+ *
+ * Copyright (C) 2002 Laurent Canet <canetl@esiee.fr>
+ * Copyright (C) 2002 Thibaut Varene <varenet@parisc-linux.org>
+ *
+ * TODO: - handle processor number on SMP systems (Reporting Entity ID)
+ * - handle message ID
+ * - handle timestamps
+ */
+
+
+#ifndef _PARISC_PDC_CHASSIS_H
+#define _PARISC_PDC_CHASSIS_H
+
+/*
+ * ----------
+ * Prototypes
+ * ----------
+ */
+
+int pdc_chassis_send_status(int message);
+void parisc_pdc_chassis_init(void);
+
+
+/*
+ * -----------------
+ * Direct call names
+ * -----------------
+ * They setup everything for you, the Log message and the corresponding LED state
+ */
+
+#define PDC_CHASSIS_DIRECT_BSTART 0
+#define PDC_CHASSIS_DIRECT_BCOMPLETE 1
+#define PDC_CHASSIS_DIRECT_SHUTDOWN 2
+#define PDC_CHASSIS_DIRECT_PANIC 3
+#define PDC_CHASSIS_DIRECT_HPMC 4
+#define PDC_CHASSIS_DIRECT_LPMC 5
+#define PDC_CHASSIS_DIRECT_DUMP 6 /* not yet implemented */
+#define PDC_CHASSIS_DIRECT_OOPS 7 /* not yet implemented */
+
+
+/*
+ * ------------
+ * LEDs control
+ * ------------
+ * Set the three LEDs -- Run, Attn, and Fault.
+ */
+
+/* Old PDC LED control */
+#define PDC_CHASSIS_DISP_DATA(v) ((unsigned long)(v) << 17)
+
+/*
+ * Available PDC PAT LED states
+ */
+
+#define PDC_CHASSIS_LED_RUN_OFF (0ULL << 4)
+#define PDC_CHASSIS_LED_RUN_FLASH (1ULL << 4)
+#define PDC_CHASSIS_LED_RUN_ON (2ULL << 4)
+#define PDC_CHASSIS_LED_RUN_NC (3ULL << 4)
+#define PDC_CHASSIS_LED_ATTN_OFF (0ULL << 6)
+#define PDC_CHASSIS_LED_ATTN_FLASH (1ULL << 6)
+#define PDC_CHASSIS_LED_ATTN_NC (3ULL << 6) /* ATTN ON is invalid */
+#define PDC_CHASSIS_LED_FAULT_OFF (0ULL << 8)
+#define PDC_CHASSIS_LED_FAULT_FLASH (1ULL << 8)
+#define PDC_CHASSIS_LED_FAULT_ON (2ULL << 8)
+#define PDC_CHASSIS_LED_FAULT_NC (3ULL << 8)
+#define PDC_CHASSIS_LED_VALID (1ULL << 10)
+
+/*
+ * Valid PDC PAT LED states combinations
+ */
+
+/* System running normally */
+#define PDC_CHASSIS_LSTATE_RUN_NORMAL (PDC_CHASSIS_LED_RUN_ON | \
+ PDC_CHASSIS_LED_ATTN_OFF | \
+ PDC_CHASSIS_LED_FAULT_OFF | \
+ PDC_CHASSIS_LED_VALID )
+/* System crashed and rebooted itself successfully */
+#define PDC_CHASSIS_LSTATE_RUN_CRASHREC (PDC_CHASSIS_LED_RUN_ON | \
+ PDC_CHASSIS_LED_ATTN_OFF | \
+ PDC_CHASSIS_LED_FAULT_FLASH | \
+ PDC_CHASSIS_LED_VALID )
+/* There was a system interruption that did not take the system down */
+#define PDC_CHASSIS_LSTATE_RUN_SYSINT (PDC_CHASSIS_LED_RUN_ON | \
+ PDC_CHASSIS_LED_ATTN_FLASH | \
+ PDC_CHASSIS_LED_FAULT_OFF | \
+ PDC_CHASSIS_LED_VALID )
+/* System running and unexpected reboot or non-critical error detected */
+#define PDC_CHASSIS_LSTATE_RUN_NCRIT (PDC_CHASSIS_LED_RUN_ON | \
+ PDC_CHASSIS_LED_ATTN_FLASH | \
+ PDC_CHASSIS_LED_FAULT_FLASH | \
+ PDC_CHASSIS_LED_VALID )
+/* Executing non-OS code */
+#define PDC_CHASSIS_LSTATE_NONOS (PDC_CHASSIS_LED_RUN_FLASH | \
+ PDC_CHASSIS_LED_ATTN_OFF | \
+ PDC_CHASSIS_LED_FAULT_OFF | \
+ PDC_CHASSIS_LED_VALID )
+/* Boot failed - Executing non-OS code */
+#define PDC_CHASSIS_LSTATE_NONOS_BFAIL (PDC_CHASSIS_LED_RUN_FLASH | \
+ PDC_CHASSIS_LED_ATTN_OFF | \
+ PDC_CHASSIS_LED_FAULT_ON | \
+ PDC_CHASSIS_LED_VALID )
+/* Unexpected reboot occurred - Executing non-OS code */
+#define PDC_CHASSIS_LSTATE_NONOS_UNEXP (PDC_CHASSIS_LED_RUN_FLASH | \
+ PDC_CHASSIS_LED_ATTN_OFF | \
+ PDC_CHASSIS_LED_FAULT_FLASH | \
+ PDC_CHASSIS_LED_VALID )
+/* Executing non-OS code - Non-critical error detected */
+#define PDC_CHASSIS_LSTATE_NONOS_NCRIT (PDC_CHASSIS_LED_RUN_FLASH | \
+ PDC_CHASSIS_LED_ATTN_FLASH | \
+ PDC_CHASSIS_LED_FAULT_OFF | \
+ PDC_CHASSIS_LED_VALID )
+/* Boot failed - Executing non-OS code - Non-critical error detected */
+#define PDC_CHASSIS_LSTATE_BFAIL_NCRIT (PDC_CHASSIS_LED_RUN_FLASH | \
+ PDC_CHASSIS_LED_ATTN_FLASH | \
+ PDC_CHASSIS_LED_FAULT_ON | \
+ PDC_CHASSIS_LED_VALID )
+/* Unexpected reboot/recovering - Executing non-OS code - Non-critical error detected */
+#define PDC_CHASSIS_LSTATE_UNEXP_NCRIT (PDC_CHASSIS_LED_RUN_FLASH | \
+ PDC_CHASSIS_LED_ATTN_FLASH | \
+ PDC_CHASSIS_LED_FAULT_FLASH | \
+ PDC_CHASSIS_LED_VALID )
+/* Cannot execute PDC */
+#define PDC_CHASSIS_LSTATE_CANNOT_PDC (PDC_CHASSIS_LED_RUN_OFF | \
+ PDC_CHASSIS_LED_ATTN_OFF | \
+ PDC_CHASSIS_LED_FAULT_OFF | \
+ PDC_CHASSIS_LED_VALID )
+/* Boot failed - OS not up - PDC has detected a failure that prevents boot */
+#define PDC_CHASSIS_LSTATE_FATAL_BFAIL (PDC_CHASSIS_LED_RUN_OFF | \
+ PDC_CHASSIS_LED_ATTN_OFF | \
+ PDC_CHASSIS_LED_FAULT_ON | \
+ PDC_CHASSIS_LED_VALID )
+/* No code running - Non-critical error detected (double fault situation) */
+#define PDC_CHASSIS_LSTATE_NOCODE_NCRIT (PDC_CHASSIS_LED_RUN_OFF | \
+ PDC_CHASSIS_LED_ATTN_FLASH | \
+ PDC_CHASSIS_LED_FAULT_OFF | \
+ PDC_CHASSIS_LED_VALID )
+/* Boot failed - OS not up - Fatal failure detected - Non-critical error detected */
+#define PDC_CHASSIS_LSTATE_FATAL_NCRIT (PDC_CHASSIS_LED_RUN_OFF | \
+ PDC_CHASSIS_LED_ATTN_FLASH | \
+ PDC_CHASSIS_LED_FAULT_ON | \
+ PDC_CHASSIS_LED_VALID )
+/* All other states are invalid */
+
+
+/*
+ * --------------
+ * PDC Log events
+ * --------------
+ * Here follows bits needed to fill up the log event sent to PDC_CHASSIS
+ * The log message contains: Alert level, Source, Source detail,
+ * Source ID, Problem detail, Caller activity, Activity status,
+ * Caller subactivity, Reporting entity type, Reporting entity ID,
+ * Data type, Unique message ID and EOM.
+ */
+
+/* Alert level */
+#define PDC_CHASSIS_ALERT_FORWARD (0ULL << 36) /* no failure detected */
+#define PDC_CHASSIS_ALERT_SERPROC (1ULL << 36) /* service proc - no failure */
+#define PDC_CHASSIS_ALERT_NURGENT (2ULL << 36) /* non-urgent operator attn */
+#define PDC_CHASSIS_ALERT_BLOCKED (3ULL << 36) /* system blocked */
+#define PDC_CHASSIS_ALERT_CONF_CHG (4ULL << 36) /* unexpected configuration change */
+#define PDC_CHASSIS_ALERT_ENV_PB (5ULL << 36) /* boot possible, environmental pb */
+#define PDC_CHASSIS_ALERT_PENDING (6ULL << 36) /* boot possible, pending failure */
+#define PDC_CHASSIS_ALERT_PERF_IMP (8ULL << 36) /* boot possible, performance impaired */
+#define PDC_CHASSIS_ALERT_FUNC_IMP (10ULL << 36) /* boot possible, functionality impaired */
+#define PDC_CHASSIS_ALERT_SOFT_FAIL (12ULL << 36) /* software failure */
+#define PDC_CHASSIS_ALERT_HANG (13ULL << 36) /* system hang */
+#define PDC_CHASSIS_ALERT_ENV_FATAL (14ULL << 36) /* fatal power or environmental pb */
+#define PDC_CHASSIS_ALERT_HW_FATAL (15ULL << 36) /* fatal hardware problem */
+
+/* Source */
+#define PDC_CHASSIS_SRC_NONE (0ULL << 28) /* unknown, no source stated */
+#define PDC_CHASSIS_SRC_PROC (1ULL << 28) /* processor */
+/* For later use ? */
+#define PDC_CHASSIS_SRC_PROC_CACHE (2ULL << 28) /* processor cache*/
+#define PDC_CHASSIS_SRC_PDH (3ULL << 28) /* processor dependent hardware */
+#define PDC_CHASSIS_SRC_PWR (4ULL << 28) /* power */
+#define PDC_CHASSIS_SRC_FAB (5ULL << 28) /* fabric connector */
+#define PDC_CHASSIS_SRC_PLATi (6ULL << 28) /* platform */
+#define PDC_CHASSIS_SRC_MEM (7ULL << 28) /* memory */
+#define PDC_CHASSIS_SRC_IO (8ULL << 28) /* I/O */
+#define PDC_CHASSIS_SRC_CELL (9ULL << 28) /* cell */
+#define PDC_CHASSIS_SRC_PD (10ULL << 28) /* protected domain */
+
+/* Source detail field */
+#define PDC_CHASSIS_SRC_D_PROC (1ULL << 24) /* processor general */
+
+/* Source ID - platform dependent */
+#define PDC_CHASSIS_SRC_ID_UNSPEC (0ULL << 16)
+
+/* Problem detail - problem source dependent */
+#define PDC_CHASSIS_PB_D_PROC_NONE (0ULL << 32) /* no problem detail */
+#define PDC_CHASSIS_PB_D_PROC_TIMEOUT (4ULL << 32) /* timeout */
+
+/* Caller activity */
+#define PDC_CHASSIS_CALL_ACT_HPUX_BL (7ULL << 12) /* Boot Loader */
+#define PDC_CHASSIS_CALL_ACT_HPUX_PD (8ULL << 12) /* SAL_PD activities */
+#define PDC_CHASSIS_CALL_ACT_HPUX_EVENT (9ULL << 12) /* SAL_EVENTS activities */
+#define PDC_CHASSIS_CALL_ACT_HPUX_IO (10ULL << 12) /* SAL_IO activities */
+#define PDC_CHASSIS_CALL_ACT_HPUX_PANIC (11ULL << 12) /* System panic */
+#define PDC_CHASSIS_CALL_ACT_HPUX_INIT (12ULL << 12) /* System initialization */
+#define PDC_CHASSIS_CALL_ACT_HPUX_SHUT (13ULL << 12) /* System shutdown */
+#define PDC_CHASSIS_CALL_ACT_HPUX_WARN (14ULL << 12) /* System warning */
+#define PDC_CHASSIS_CALL_ACT_HPUX_DU (15ULL << 12) /* Display_Activity() update */
+
+/* Activity status - implementation dependent */
+#define PDC_CHASSIS_ACT_STATUS_UNSPEC (0ULL << 0)
+
+/* Caller subactivity - implementation dependent */
+/* FIXME: other subactivities ? */
+#define PDC_CHASSIS_CALL_SACT_UNSPEC (0ULL << 4) /* implementation dependent */
+
+/* Reporting entity type */
+#define PDC_CHASSIS_RET_GENERICOS (12ULL << 52) /* generic OSes */
+#define PDC_CHASSIS_RET_IA64_NT (13ULL << 52) /* IA-64 NT */
+#define PDC_CHASSIS_RET_HPUX (14ULL << 52) /* HP-UX */
+#define PDC_CHASSIS_RET_DIAG (15ULL << 52) /* offline diagnostics & utilities */
+
+/* Reporting entity ID */
+#define PDC_CHASSIS_REID_UNSPEC (0ULL << 44)
+
+/* Data type */
+#define PDC_CHASSIS_DT_NONE (0ULL << 59) /* data field unused */
+/* For later use ? Do we need these ? */
+#define PDC_CHASSIS_DT_PHYS_ADDR (1ULL << 59) /* physical address */
+#define PDC_CHASSIS_DT_DATA_EXPECT (2ULL << 59) /* expected data */
+#define PDC_CHASSIS_DT_ACTUAL (3ULL << 59) /* actual data */
+#define PDC_CHASSIS_DT_PHYS_LOC (4ULL << 59) /* physical location */
+#define PDC_CHASSIS_DT_PHYS_LOC_EXT (5ULL << 59) /* physical location extension */
+#define PDC_CHASSIS_DT_TAG (6ULL << 59) /* tag */
+#define PDC_CHASSIS_DT_SYNDROME (7ULL << 59) /* syndrome */
+#define PDC_CHASSIS_DT_CODE_ADDR (8ULL << 59) /* code address */
+#define PDC_CHASSIS_DT_ASCII_MSG (9ULL << 59) /* ascii message */
+#define PDC_CHASSIS_DT_POST (10ULL << 59) /* POST code */
+#define PDC_CHASSIS_DT_TIMESTAMP (11ULL << 59) /* timestamp */
+#define PDC_CHASSIS_DT_DEV_STAT (12ULL << 59) /* device status */
+#define PDC_CHASSIS_DT_DEV_TYPE (13ULL << 59) /* device type */
+#define PDC_CHASSIS_DT_PB_DET (14ULL << 59) /* problem detail */
+#define PDC_CHASSIS_DT_ACT_LEV (15ULL << 59) /* activity level/timeout */
+#define PDC_CHASSIS_DT_SER_NUM (16ULL << 59) /* serial number */
+#define PDC_CHASSIS_DT_REV_NUM (17ULL << 59) /* revision number */
+#define PDC_CHASSIS_DT_INTERRUPT (18ULL << 59) /* interruption information */
+#define PDC_CHASSIS_DT_TEST_NUM (19ULL << 59) /* test number */
+#define PDC_CHASSIS_DT_STATE_CHG (20ULL << 59) /* major changes in system state */
+#define PDC_CHASSIS_DT_PROC_DEALLOC (21ULL << 59) /* processor deallocate */
+#define PDC_CHASSIS_DT_RESET (30ULL << 59) /* reset type and cause */
+#define PDC_CHASSIS_DT_PA_LEGACY (31ULL << 59) /* legacy PA hex chassis code */
+
+/* System states - part of major changes in system state data field */
+#define PDC_CHASSIS_SYSTATE_BSTART (0ULL << 0) /* boot start */
+#define PDC_CHASSIS_SYSTATE_BCOMP (1ULL << 0) /* boot complete */
+#define PDC_CHASSIS_SYSTATE_CHANGE (2ULL << 0) /* major change */
+#define PDC_CHASSIS_SYSTATE_LED (3ULL << 0) /* LED change */
+#define PDC_CHASSIS_SYSTATE_PANIC (9ULL << 0) /* OS Panic */
+#define PDC_CHASSIS_SYSTATE_DUMP (10ULL << 0) /* memory dump */
+#define PDC_CHASSIS_SYSTATE_HPMC (11ULL << 0) /* processing HPMC */
+#define PDC_CHASSIS_SYSTATE_HALT (15ULL << 0) /* system halted */
+
+/* Message ID */
+#define PDC_CHASSIS_MSG_ID (0ULL << 40) /* we do not handle msg IDs atm */
+
+/* EOM - separates log entries */
+#define PDC_CHASSIS_EOM_CLEAR (0ULL << 43)
+#define PDC_CHASSIS_EOM_SET (1ULL << 43)
+
+/*
+ * Preformated well known messages
+ */
+
+/* Boot started */
+#define PDC_CHASSIS_PMSG_BSTART (PDC_CHASSIS_ALERT_SERPROC | \
+ PDC_CHASSIS_SRC_PROC | \
+ PDC_CHASSIS_SRC_D_PROC | \
+ PDC_CHASSIS_SRC_ID_UNSPEC | \
+ PDC_CHASSIS_PB_D_PROC_NONE | \
+ PDC_CHASSIS_CALL_ACT_HPUX_INIT | \
+ PDC_CHASSIS_ACT_STATUS_UNSPEC | \
+ PDC_CHASSIS_CALL_SACT_UNSPEC | \
+ PDC_CHASSIS_RET_HPUX | \
+ PDC_CHASSIS_REID_UNSPEC | \
+ PDC_CHASSIS_DT_STATE_CHG | \
+ PDC_CHASSIS_SYSTATE_BSTART | \
+ PDC_CHASSIS_MSG_ID | \
+ PDC_CHASSIS_EOM_SET )
+
+/* Boot complete */
+#define PDC_CHASSIS_PMSG_BCOMPLETE (PDC_CHASSIS_ALERT_SERPROC | \
+ PDC_CHASSIS_SRC_PROC | \
+ PDC_CHASSIS_SRC_D_PROC | \
+ PDC_CHASSIS_SRC_ID_UNSPEC | \
+ PDC_CHASSIS_PB_D_PROC_NONE | \
+ PDC_CHASSIS_CALL_ACT_HPUX_INIT | \
+ PDC_CHASSIS_ACT_STATUS_UNSPEC | \
+ PDC_CHASSIS_CALL_SACT_UNSPEC | \
+ PDC_CHASSIS_RET_HPUX | \
+ PDC_CHASSIS_REID_UNSPEC | \
+ PDC_CHASSIS_DT_STATE_CHG | \
+ PDC_CHASSIS_SYSTATE_BCOMP | \
+ PDC_CHASSIS_MSG_ID | \
+ PDC_CHASSIS_EOM_SET )
+
+/* Shutdown */
+#define PDC_CHASSIS_PMSG_SHUTDOWN (PDC_CHASSIS_ALERT_SERPROC | \
+ PDC_CHASSIS_SRC_PROC | \
+ PDC_CHASSIS_SRC_D_PROC | \
+ PDC_CHASSIS_SRC_ID_UNSPEC | \
+ PDC_CHASSIS_PB_D_PROC_NONE | \
+ PDC_CHASSIS_CALL_ACT_HPUX_SHUT | \
+ PDC_CHASSIS_ACT_STATUS_UNSPEC | \
+ PDC_CHASSIS_CALL_SACT_UNSPEC | \
+ PDC_CHASSIS_RET_HPUX | \
+ PDC_CHASSIS_REID_UNSPEC | \
+ PDC_CHASSIS_DT_STATE_CHG | \
+ PDC_CHASSIS_SYSTATE_HALT | \
+ PDC_CHASSIS_MSG_ID | \
+ PDC_CHASSIS_EOM_SET )
+
+/* Panic */
+#define PDC_CHASSIS_PMSG_PANIC (PDC_CHASSIS_ALERT_SOFT_FAIL | \
+ PDC_CHASSIS_SRC_PROC | \
+ PDC_CHASSIS_SRC_D_PROC | \
+ PDC_CHASSIS_SRC_ID_UNSPEC | \
+ PDC_CHASSIS_PB_D_PROC_NONE | \
+ PDC_CHASSIS_CALL_ACT_HPUX_PANIC| \
+ PDC_CHASSIS_ACT_STATUS_UNSPEC | \
+ PDC_CHASSIS_CALL_SACT_UNSPEC | \
+ PDC_CHASSIS_RET_HPUX | \
+ PDC_CHASSIS_REID_UNSPEC | \
+ PDC_CHASSIS_DT_STATE_CHG | \
+ PDC_CHASSIS_SYSTATE_PANIC | \
+ PDC_CHASSIS_MSG_ID | \
+ PDC_CHASSIS_EOM_SET )
+
+// FIXME: extrapolated data
+/* HPMC */
+#define PDC_CHASSIS_PMSG_HPMC (PDC_CHASSIS_ALERT_CONF_CHG /*?*/ | \
+ PDC_CHASSIS_SRC_PROC | \
+ PDC_CHASSIS_SRC_D_PROC | \
+ PDC_CHASSIS_SRC_ID_UNSPEC | \
+ PDC_CHASSIS_PB_D_PROC_NONE | \
+ PDC_CHASSIS_CALL_ACT_HPUX_WARN | \
+ PDC_CHASSIS_RET_HPUX | \
+ PDC_CHASSIS_DT_STATE_CHG | \
+ PDC_CHASSIS_SYSTATE_HPMC | \
+ PDC_CHASSIS_MSG_ID | \
+ PDC_CHASSIS_EOM_SET )
+
+/* LPMC */
+#define PDC_CHASSIS_PMSG_LPMC (PDC_CHASSIS_ALERT_BLOCKED /*?*/| \
+ PDC_CHASSIS_SRC_PROC | \
+ PDC_CHASSIS_SRC_D_PROC | \
+ PDC_CHASSIS_SRC_ID_UNSPEC | \
+ PDC_CHASSIS_PB_D_PROC_NONE | \
+ PDC_CHASSIS_CALL_ACT_HPUX_WARN | \
+ PDC_CHASSIS_ACT_STATUS_UNSPEC | \
+ PDC_CHASSIS_CALL_SACT_UNSPEC | \
+ PDC_CHASSIS_RET_HPUX | \
+ PDC_CHASSIS_REID_UNSPEC | \
+ PDC_CHASSIS_DT_STATE_CHG | \
+ PDC_CHASSIS_SYSTATE_CHANGE | \
+ PDC_CHASSIS_MSG_ID | \
+ PDC_CHASSIS_EOM_SET )
+
+#endif /* _PARISC_PDC_CHASSIS_H */
diff --git a/arch/parisc/include/asm/pdcpat.h b/arch/parisc/include/asm/pdcpat.h
new file mode 100644
index 000000000..8f160375b
--- /dev/null
+++ b/arch/parisc/include/asm/pdcpat.h
@@ -0,0 +1,394 @@
+#ifndef __PARISC_PATPDC_H
+#define __PARISC_PATPDC_H
+
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright 2000 (c) Hewlett Packard (Paul Bame <bame()spam.parisc-linux.org>)
+ * Copyright 2000,2004 (c) Grant Grundler <grundler()nahspam.parisc-linux.org>
+ */
+
+
+#define PDC_PAT_CELL 64L /* Interface for gaining and
+ * manipulatin g cell state within PD */
+#define PDC_PAT_CELL_GET_NUMBER 0L /* Return Cell number */
+#define PDC_PAT_CELL_GET_INFO 1L /* Returns info about Cell */
+#define PDC_PAT_CELL_MODULE 2L /* Returns info about Module */
+#define PDC_PAT_CELL_SET_ATTENTION 9L /* Set Cell Attention indicator */
+#define PDC_PAT_CELL_NUMBER_TO_LOC 10L /* Cell Number -> Location */
+#define PDC_PAT_CELL_WALK_FABRIC 11L /* Walk the Fabric */
+#define PDC_PAT_CELL_GET_RDT_SIZE 12L /* Return Route Distance Table Sizes */
+#define PDC_PAT_CELL_GET_RDT 13L /* Return Route Distance Tables */
+#define PDC_PAT_CELL_GET_LOCAL_PDH_SZ 14L /* Read Local PDH Buffer Size */
+#define PDC_PAT_CELL_SET_LOCAL_PDH 15L /* Write Local PDH Buffer */
+#define PDC_PAT_CELL_GET_REMOTE_PDH_SZ 16L /* Return Remote PDH Buffer Size */
+#define PDC_PAT_CELL_GET_REMOTE_PDH 17L /* Read Remote PDH Buffer */
+#define PDC_PAT_CELL_GET_DBG_INFO 128L /* Return DBG Buffer Info */
+#define PDC_PAT_CELL_CHANGE_ALIAS 129L /* Change Non-Equivalent Alias Chacking */
+
+
+/*
+** Arg to PDC_PAT_CELL_MODULE memaddr[4]
+**
+** Addresses on the Merced Bus != all Runway Bus addresses.
+** This is intended for programming SBA/LBA chips range registers.
+*/
+#define IO_VIEW 0UL
+#define PA_VIEW 1UL
+
+/* PDC_PAT_CELL_MODULE entity type values */
+#define PAT_ENTITY_CA 0 /* central agent */
+#define PAT_ENTITY_PROC 1 /* processor */
+#define PAT_ENTITY_MEM 2 /* memory controller */
+#define PAT_ENTITY_SBA 3 /* system bus adapter */
+#define PAT_ENTITY_LBA 4 /* local bus adapter */
+#define PAT_ENTITY_PBC 5 /* processor bus converter */
+#define PAT_ENTITY_XBC 6 /* crossbar fabric connect */
+#define PAT_ENTITY_RC 7 /* fabric interconnect */
+
+/* PDC_PAT_CELL_MODULE address range type values */
+#define PAT_PBNUM 0 /* PCI Bus Number */
+#define PAT_LMMIO 1 /* < 4G MMIO Space */
+#define PAT_GMMIO 2 /* > 4G MMIO Space */
+#define PAT_NPIOP 3 /* Non Postable I/O Port Space */
+#define PAT_PIOP 4 /* Postable I/O Port Space */
+#define PAT_AHPA 5 /* Addional HPA Space */
+#define PAT_UFO 6 /* HPA Space (UFO for Mariposa) */
+#define PAT_GNIP 7 /* GNI Reserved Space */
+
+
+
+/* PDC PAT CHASSIS LOG -- Platform logging & forward progress functions */
+
+#define PDC_PAT_CHASSIS_LOG 65L
+#define PDC_PAT_CHASSIS_WRITE_LOG 0L /* Write Log Entry */
+#define PDC_PAT_CHASSIS_READ_LOG 1L /* Read Log Entry */
+
+
+/* PDC PAT COMPLEX */
+
+#define PDC_PAT_COMPLEX 66L
+
+/* PDC PAT CPU -- CPU configuration within the protection domain */
+
+#define PDC_PAT_CPU 67L
+#define PDC_PAT_CPU_INFO 0L /* Return CPU config info */
+#define PDC_PAT_CPU_DELETE 1L /* Delete CPU */
+#define PDC_PAT_CPU_ADD 2L /* Add CPU */
+#define PDC_PAT_CPU_GET_NUMBER 3L /* Return CPU Number */
+#define PDC_PAT_CPU_GET_HPA 4L /* Return CPU HPA */
+#define PDC_PAT_CPU_STOP 5L /* Stop CPU */
+#define PDC_PAT_CPU_RENDEZVOUS 6L /* Rendezvous CPU */
+#define PDC_PAT_CPU_GET_CLOCK_INFO 7L /* Return CPU Clock info */
+#define PDC_PAT_CPU_GET_RENDEZVOUS_STATE 8L /* Return Rendezvous State */
+#define PDC_PAT_CPU_GET_PDC_ENTRYPOINT 11L /* Return PDC Entry point */
+#define PDC_PAT_CPU_PLUNGE_FABRIC 128L /* Plunge Fabric */
+#define PDC_PAT_CPU_UPDATE_CACHE_CLEANSING 129L /* Manipulate Cache
+ * Cleansing Mode */
+/* PDC PAT EVENT -- Platform Events */
+
+#define PDC_PAT_EVENT 68L
+#define PDC_PAT_EVENT_GET_CAPS 0L /* Get Capabilities */
+#define PDC_PAT_EVENT_SET_MODE 1L /* Set Notification Mode */
+#define PDC_PAT_EVENT_SCAN 2L /* Scan Event */
+#define PDC_PAT_EVENT_HANDLE 3L /* Handle Event */
+#define PDC_PAT_EVENT_GET_NB_CALL 4L /* Get Non-Blocking call Args */
+
+/* PDC PAT HPMC -- Cause processor to go into spin loop, and wait
+ * for wake up from Monarch Processor.
+ */
+
+#define PDC_PAT_HPMC 70L
+#define PDC_PAT_HPMC_RENDEZ_CPU 0L /* go into spin loop */
+#define PDC_PAT_HPMC_SET_PARAMS 1L /* Allows OS to specify intr which PDC
+ * will use to interrupt OS during
+ * machine check rendezvous */
+
+/* parameters for PDC_PAT_HPMC_SET_PARAMS: */
+#define HPMC_SET_PARAMS_INTR 1L /* Rendezvous Interrupt */
+#define HPMC_SET_PARAMS_WAKE 2L /* Wake up processor */
+
+
+/* PDC PAT IO -- On-line services for I/O modules */
+
+#define PDC_PAT_IO 71L
+#define PDC_PAT_IO_GET_SLOT_STATUS 5L /* Get Slot Status Info*/
+#define PDC_PAT_IO_GET_LOC_FROM_HARDWARE 6L /* Get Physical Location from */
+ /* Hardware Path */
+#define PDC_PAT_IO_GET_HARDWARE_FROM_LOC 7L /* Get Hardware Path from
+ * Physical Location */
+#define PDC_PAT_IO_GET_PCI_CONFIG_FROM_HW 11L /* Get PCI Configuration
+ * Address from Hardware Path */
+#define PDC_PAT_IO_GET_HW_FROM_PCI_CONFIG 12L /* Get Hardware Path
+ * from PCI Configuration Address */
+#define PDC_PAT_IO_READ_HOST_BRIDGE_INFO 13L /* Read Host Bridge State Info */
+#define PDC_PAT_IO_CLEAR_HOST_BRIDGE_INFO 14L /* Clear Host Bridge State Info*/
+#define PDC_PAT_IO_GET_PCI_ROUTING_TABLE_SIZE 15L /* Get PCI INT Routing Table
+ * Size */
+#define PDC_PAT_IO_GET_PCI_ROUTING_TABLE 16L /* Get PCI INT Routing Table */
+#define PDC_PAT_IO_GET_HINT_TABLE_SIZE 17L /* Get Hint Table Size */
+#define PDC_PAT_IO_GET_HINT_TABLE 18L /* Get Hint Table */
+#define PDC_PAT_IO_PCI_CONFIG_READ 19L /* PCI Config Read */
+#define PDC_PAT_IO_PCI_CONFIG_WRITE 20L /* PCI Config Write */
+#define PDC_PAT_IO_GET_NUM_IO_SLOTS 21L /* Get Number of I/O Bay Slots in
+ * Cabinet */
+#define PDC_PAT_IO_GET_LOC_IO_SLOTS 22L /* Get Physical Location of I/O */
+ /* Bay Slots in Cabinet */
+#define PDC_PAT_IO_BAY_STATUS_INFO 28L /* Get I/O Bay Slot Status Info */
+#define PDC_PAT_IO_GET_PROC_VIEW 29L /* Get Processor view of IO address */
+#define PDC_PAT_IO_PROG_SBA_DIR_RANGE 30L /* Program directed range */
+
+
+/* PDC PAT MEM -- Manage memory page deallocation */
+
+#define PDC_PAT_MEM 72L
+#define PDC_PAT_MEM_PD_INFO 0L /* Return PDT info for PD */
+#define PDC_PAT_MEM_PD_CLEAR 1L /* Clear PDT for PD */
+#define PDC_PAT_MEM_PD_READ 2L /* Read PDT entries for PD */
+#define PDC_PAT_MEM_PD_RESET 3L /* Reset clear bit for PD */
+#define PDC_PAT_MEM_CELL_INFO 5L /* Return PDT info For Cell */
+#define PDC_PAT_MEM_CELL_CLEAR 6L /* Clear PDT For Cell */
+#define PDC_PAT_MEM_CELL_READ 7L /* Read PDT entries For Cell */
+#define PDC_PAT_MEM_CELL_RESET 8L /* Reset clear bit For Cell */
+#define PDC_PAT_MEM_SETGM 9L /* Set Good Memory value */
+#define PDC_PAT_MEM_ADD_PAGE 10L /* ADDs a page to the cell */
+#define PDC_PAT_MEM_ADDRESS 11L /* Get Physical Location From */
+ /* Memory Address */
+#define PDC_PAT_MEM_GET_TXT_SIZE 12L /* Get Formatted Text Size */
+#define PDC_PAT_MEM_GET_PD_TXT 13L /* Get PD Formatted Text */
+#define PDC_PAT_MEM_GET_CELL_TXT 14L /* Get Cell Formatted Text */
+#define PDC_PAT_MEM_RD_STATE_INFO 15L /* Read Mem Module State Info*/
+#define PDC_PAT_MEM_CLR_STATE_INFO 16L /*Clear Mem Module State Info*/
+#define PDC_PAT_MEM_CLEAN_RANGE 128L /*Clean Mem in specific range*/
+#define PDC_PAT_MEM_GET_TBL_SIZE 131L /* Get Memory Table Size */
+#define PDC_PAT_MEM_GET_TBL 132L /* Get Memory Table */
+
+
+/* PDC PAT NVOLATILE -- Access Non-Volatile Memory */
+
+#define PDC_PAT_NVOLATILE 73L
+#define PDC_PAT_NVOLATILE_READ 0L /* Read Non-Volatile Memory */
+#define PDC_PAT_NVOLATILE_WRITE 1L /* Write Non-Volatile Memory */
+#define PDC_PAT_NVOLATILE_GET_SIZE 2L /* Return size of NVM */
+#define PDC_PAT_NVOLATILE_VERIFY 3L /* Verify contents of NVM */
+#define PDC_PAT_NVOLATILE_INIT 4L /* Initialize NVM */
+
+/* PDC PAT PD */
+#define PDC_PAT_PD 74L /* Protection Domain Info */
+#define PDC_PAT_PD_GET_ADDR_MAP 0L /* Get Address Map */
+#define PDC_PAT_PD_GET_PDC_INTERF_REV 1L /* Get PDC Interface Revisions */
+
+#define PDC_PAT_CAPABILITY_BIT_PDC_SERIALIZE (1UL << 0)
+#define PDC_PAT_CAPABILITY_BIT_PDC_POLLING (1UL << 1)
+#define PDC_PAT_CAPABILITY_BIT_PDC_NBC (1UL << 2) /* non-blocking calls */
+#define PDC_PAT_CAPABILITY_BIT_PDC_UFO (1UL << 3)
+#define PDC_PAT_CAPABILITY_BIT_PDC_IODC_32 (1UL << 4)
+#define PDC_PAT_CAPABILITY_BIT_PDC_IODC_64 (1UL << 5)
+#define PDC_PAT_CAPABILITY_BIT_PDC_HPMC_RENDEZ (1UL << 6)
+#define PDC_PAT_CAPABILITY_BIT_SIMULTANEOUS_PTLB (1UL << 7)
+
+/* PDC_PAT_PD_GET_ADDR_MAP entry types */
+#define PAT_MEMORY_DESCRIPTOR 1
+
+/* PDC_PAT_PD_GET_ADDR_MAP memory types */
+#define PAT_MEMTYPE_MEMORY 0
+#define PAT_MEMTYPE_FIRMWARE 4
+
+/* PDC_PAT_PD_GET_ADDR_MAP memory usage */
+#define PAT_MEMUSE_GENERAL 0
+#define PAT_MEMUSE_GI 128
+#define PAT_MEMUSE_GNI 129
+
+/* PDC PAT REGISTER TOC */
+#define PDC_PAT_REGISTER_TOC 75L
+#define PDC_PAT_TOC_REGISTER_VECTOR 0L /* Register TOC Vector */
+#define PDC_PAT_TOC_READ_VECTOR 1L /* Read TOC Vector */
+
+/* PDC PAT SYSTEM_INFO */
+#define PDC_PAT_SYSTEM_INFO 76L
+/* PDC_PAT_SYSTEM_INFO uses the same options as PDC_SYSTEM_INFO function. */
+
+#ifndef __ASSEMBLY__
+#include <linux/types.h>
+
+#ifdef CONFIG_64BIT
+#define is_pdc_pat() (PDC_TYPE_PAT == pdc_type)
+extern int pdc_pat_get_irt_size(unsigned long *num_entries, unsigned long cell_num);
+extern int pdc_pat_get_irt(void *r_addr, unsigned long cell_num);
+#else /* ! CONFIG_64BIT */
+/* No PAT support for 32-bit kernels...sorry */
+#define is_pdc_pat() (0)
+#define pdc_pat_get_irt_size(num_entries, cell_numn) PDC_BAD_PROC
+#define pdc_pat_get_irt(r_addr, cell_num) PDC_BAD_PROC
+#endif /* ! CONFIG_64BIT */
+
+
+struct pdc_pat_cell_num {
+ unsigned long cell_num;
+ unsigned long cell_loc;
+};
+
+struct pdc_pat_cpu_num {
+ unsigned long cpu_num;
+ unsigned long cpu_loc;
+};
+
+struct pdc_pat_mem_retinfo { /* PDC_PAT_MEM/PDC_PAT_MEM_PD_INFO (return info) */
+ unsigned int ke; /* bit 0: memory inside good memory? */
+ unsigned int current_pdt_entries:16;
+ unsigned int max_pdt_entries:16;
+ unsigned long Cs_bitmap;
+ unsigned long Ic_bitmap;
+ unsigned long good_mem;
+ unsigned long first_dbe_loc; /* first location of double bit error */
+ unsigned long clear_time; /* last PDT clear time (since Jan 1970) */
+};
+
+struct pdc_pat_mem_cell_pdt_retinfo { /* PDC_PAT_MEM/PDC_PAT_MEM_CELL_INFO */
+ u64 reserved:32;
+ u64 cs:1; /* clear status: cleared since the last call? */
+ u64 current_pdt_entries:15;
+ u64 ic:1; /* interleaving had to be changed ? */
+ u64 max_pdt_entries:15;
+ unsigned long good_mem;
+ unsigned long first_dbe_loc; /* first location of double bit error */
+ unsigned long clear_time; /* last PDT clear time (since Jan 1970) */
+};
+
+
+struct pdc_pat_mem_read_pd_retinfo { /* PDC_PAT_MEM/PDC_PAT_MEM_PD_READ */
+ unsigned long actual_count_bytes;
+ unsigned long pdt_entries;
+};
+
+struct pdc_pat_mem_phys_mem_location { /* PDC_PAT_MEM/PDC_PAT_MEM_ADDRESS */
+ u64 cabinet:8;
+ u64 ign1:8;
+ u64 ign2:8;
+ u64 cell_slot:8;
+ u64 ign3:8;
+ u64 dimm_slot:8; /* DIMM slot, e.g. 0x1A, 0x2B, show user hex value! */
+ u64 ign4:8;
+ u64 source:4; /* for mem: always 0x07 */
+ u64 source_detail:4; /* for mem: always 0x04 (SIMM or DIMM) */
+};
+
+struct pdc_pat_pd_addr_map_entry {
+ unsigned char entry_type; /* 1 = Memory Descriptor Entry Type */
+ unsigned char reserve1[5];
+ unsigned char memory_type;
+ unsigned char memory_usage;
+ unsigned long paddr;
+ unsigned int pages; /* Length in 4K pages */
+ unsigned int reserve2;
+ unsigned long cell_map;
+};
+
+/********************************************************************
+* PDC_PAT_CELL[Return Cell Module] memaddr[0] conf_base_addr
+* ----------------------------------------------------------
+* Bit 0 to 51 - conf_base_addr
+* Bit 52 to 62 - reserved
+* Bit 63 - endianess bit
+********************************************************************/
+#define PAT_GET_CBA(value) ((value) & 0xfffffffffffff000UL)
+
+/********************************************************************
+* PDC_PAT_CELL[Return Cell Module] memaddr[1] mod_info
+* ----------------------------------------------------
+* Bit 0 to 7 - entity type
+* 0 = central agent, 1 = processor,
+* 2 = memory controller, 3 = system bus adapter,
+* 4 = local bus adapter, 5 = processor bus converter,
+* 6 = crossbar fabric connect, 7 = fabric interconnect,
+* 8 to 254 reserved, 255 = unknown.
+* Bit 8 to 15 - DVI
+* Bit 16 to 23 - IOC functions
+* Bit 24 to 39 - reserved
+* Bit 40 to 63 - mod_pages
+* number of 4K pages a module occupies starting at conf_base_addr
+********************************************************************/
+#define PAT_GET_ENTITY(value) (((value) >> 56) & 0xffUL)
+#define PAT_GET_DVI(value) (((value) >> 48) & 0xffUL)
+#define PAT_GET_IOC(value) (((value) >> 40) & 0xffUL)
+#define PAT_GET_MOD_PAGES(value) ((value) & 0xffffffUL)
+
+
+/*
+** PDC_PAT_CELL_GET_INFO return block
+*/
+typedef struct pdc_pat_cell_info_rtn_block {
+ unsigned long pdc_rev;
+ unsigned long capabilities; /* see PDC_PAT_CAPABILITY_BIT_* */
+ unsigned long reserved0[2];
+ unsigned long cell_info; /* 0x20 */
+ unsigned long cell_phys_location;
+ unsigned long cpu_info;
+ unsigned long cpu_speed;
+ unsigned long io_chassis_phys_location;
+ unsigned long cell_io_information;
+ unsigned long reserved1[2];
+ unsigned long io_slot_info_size; /* 0x60 */
+ struct {
+ unsigned long header, info0, info1;
+ unsigned long phys_loc, hw_path;
+ } io_slot[16];
+ unsigned long cell_mem_size; /* 0x2e8 */
+ unsigned long cell_dimm_info_size;
+ unsigned long dimm_info[16];
+ unsigned long fabric_info_size; /* 0x3f8 */
+ struct { /* 0x380 */
+ unsigned long fabric_info_xbc_port;
+ unsigned long rc_attached_to_xbc;
+ } xbc[8*4];
+} pdc_pat_cell_info_rtn_block_t;
+
+
+/* FIXME: mod[508] should really be a union of the various mod components */
+struct pdc_pat_cell_mod_maddr_block { /* PDC_PAT_CELL_MODULE */
+ unsigned long cba; /* func 0 cfg space address */
+ unsigned long mod_info; /* module information */
+ unsigned long mod_location; /* physical location of the module */
+ struct hardware_path mod_path; /* module path (device path - layers) */
+ unsigned long mod[508]; /* PAT cell module components */
+} __attribute__((aligned(8))) ;
+
+typedef struct pdc_pat_cell_mod_maddr_block pdc_pat_cell_mod_maddr_block_t;
+
+extern int pdc_pat_get_PDC_entrypoint(unsigned long *pdc_entry);
+extern int pdc_pat_chassis_send_log(unsigned long status, unsigned long data);
+extern int pdc_pat_cell_get_number(struct pdc_pat_cell_num *cell_info);
+extern int pdc_pat_cell_info(struct pdc_pat_cell_info_rtn_block *info,
+ unsigned long *actcnt, unsigned long offset,
+ unsigned long cell_number);
+extern int pdc_pat_cell_module(unsigned long *actcnt, unsigned long ploc,
+ unsigned long mod, unsigned long view_type, void *mem_addr);
+extern int pdc_pat_cell_num_to_loc(void *, unsigned long);
+
+extern int pdc_pat_cpu_get_number(struct pdc_pat_cpu_num *cpu_info, unsigned long hpa);
+
+extern int pdc_pat_pd_get_addr_map(unsigned long *actual_len, void *mem_addr,
+ unsigned long count, unsigned long offset);
+extern int pdc_pat_pd_get_pdc_revisions(unsigned long *legacy_rev,
+ unsigned long *pat_rev, unsigned long *pdc_cap);
+
+extern int pdc_pat_io_pci_cfg_read(unsigned long pci_addr, int pci_size, u32 *val);
+extern int pdc_pat_io_pci_cfg_write(unsigned long pci_addr, int pci_size, u32 val);
+
+extern int pdc_pat_mem_pdt_info(struct pdc_pat_mem_retinfo *rinfo);
+extern int pdc_pat_mem_pdt_cell_info(struct pdc_pat_mem_cell_pdt_retinfo *rinfo,
+ unsigned long cell);
+extern int pdc_pat_mem_read_cell_pdt(struct pdc_pat_mem_read_pd_retinfo *pret,
+ unsigned long *pdt_entries_ptr, unsigned long max_entries);
+extern int pdc_pat_mem_read_pd_pdt(struct pdc_pat_mem_read_pd_retinfo *pret,
+ unsigned long *pdt_entries_ptr, unsigned long count,
+ unsigned long offset);
+extern int pdc_pat_mem_get_dimm_phys_location(
+ struct pdc_pat_mem_phys_mem_location *pret,
+ unsigned long phys_addr);
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* ! __PARISC_PATPDC_H */
diff --git a/arch/parisc/include/asm/perf.h b/arch/parisc/include/asm/perf.h
new file mode 100644
index 000000000..2a5a60aff
--- /dev/null
+++ b/arch/parisc/include/asm/perf.h
@@ -0,0 +1,75 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_PERF_H_
+#define _ASM_PERF_H_
+
+/* ioctls */
+#define PA_PERF_ON _IO('p', 1)
+#define PA_PERF_OFF _IOR('p', 2, unsigned int)
+#define PA_PERF_VERSION _IOR('p', 3, int)
+
+#define PA_PERF_DEV "perf"
+#define PA_PERF_MINOR 146
+
+/* Interface types */
+#define UNKNOWN_INTF 255
+#define ONYX_INTF 0
+#define CUDA_INTF 1
+
+/* Common Onyx and Cuda images */
+#define CPI 0
+#define BUSUTIL 1
+#define TLBMISS 2
+#define TLBHANDMISS 3
+#define PTKN 4
+#define PNTKN 5
+#define IMISS 6
+#define DMISS 7
+#define DMISS_ACCESS 8
+#define BIG_CPI 9
+#define BIG_LS 10
+#define BR_ABORT 11
+#define ISNT 12
+#define QUADRANT 13
+#define RW_PDFET 14
+#define RW_WDFET 15
+#define SHLIB_CPI 16
+
+/* Cuda only Images */
+#define FLOPS 17
+#define CACHEMISS 18
+#define BRANCHES 19
+#define CRSTACK 20
+#define I_CACHE_SPEC 21
+#define MAX_CUDA_IMAGES 22
+
+/* Onyx only Images */
+#define ADDR_INV_ABORT_ALU 17
+#define BRAD_STALL 18
+#define CNTL_IN_PIPEL 19
+#define DSNT_XFH 20
+#define FET_SIG1 21
+#define FET_SIG2 22
+#define G7_1 23
+#define G7_2 24
+#define G7_3 25
+#define G7_4 26
+#define MPB_LABORT 27
+#define PANIC 28
+#define RARE_INST 29
+#define RW_DFET 30
+#define RW_IFET 31
+#define RW_SDFET 32
+#define SPEC_IFET 33
+#define ST_COND0 34
+#define ST_COND1 35
+#define ST_COND2 36
+#define ST_COND3 37
+#define ST_COND4 38
+#define ST_UNPRED0 39
+#define ST_UNPRED1 40
+#define UNPRED 41
+#define GO_STORE 42
+#define SHLIB_CALL 43
+#define MAX_ONYX_IMAGES 44
+
+#endif
diff --git a/arch/parisc/include/asm/perf_event.h b/arch/parisc/include/asm/perf_event.h
new file mode 100644
index 000000000..1e0fd8ba6
--- /dev/null
+++ b/arch/parisc/include/asm/perf_event.h
@@ -0,0 +1,6 @@
+#ifndef __ASM_PARISC_PERF_EVENT_H
+#define __ASM_PARISC_PERF_EVENT_H
+
+/* Empty, just to avoid compiling error */
+
+#endif /* __ASM_PARISC_PERF_EVENT_H */
diff --git a/arch/parisc/include/asm/pgalloc.h b/arch/parisc/include/asm/pgalloc.h
new file mode 100644
index 000000000..e3e142b1c
--- /dev/null
+++ b/arch/parisc/include/asm/pgalloc.h
@@ -0,0 +1,73 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_PGALLOC_H
+#define _ASM_PGALLOC_H
+
+#include <linux/gfp.h>
+#include <linux/mm.h>
+#include <linux/threads.h>
+#include <asm/processor.h>
+#include <asm/fixmap.h>
+
+#include <asm/cache.h>
+
+#define __HAVE_ARCH_PMD_ALLOC_ONE
+#define __HAVE_ARCH_PMD_FREE
+#define __HAVE_ARCH_PGD_FREE
+#include <asm-generic/pgalloc.h>
+
+/* Allocate the top level pgd (page directory) */
+static inline pgd_t *pgd_alloc(struct mm_struct *mm)
+{
+ pgd_t *pgd;
+
+ pgd = (pgd_t *) __get_free_pages(GFP_KERNEL, PGD_TABLE_ORDER);
+ if (unlikely(pgd == NULL))
+ return NULL;
+
+ memset(pgd, 0, PAGE_SIZE << PGD_TABLE_ORDER);
+
+ return pgd;
+}
+
+static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
+{
+ free_pages((unsigned long)pgd, PGD_TABLE_ORDER);
+}
+
+#if CONFIG_PGTABLE_LEVELS == 3
+
+/* Three Level Page Table Support for pmd's */
+
+static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
+{
+ set_pud(pud, __pud((PxD_FLAG_PRESENT | PxD_FLAG_VALID) +
+ (__u32)(__pa((unsigned long)pmd) >> PxD_VALUE_SHIFT)));
+}
+
+static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
+{
+ pmd_t *pmd;
+
+ pmd = (pmd_t *)__get_free_pages(GFP_PGTABLE_KERNEL, PMD_TABLE_ORDER);
+ if (likely(pmd))
+ memset ((void *)pmd, 0, PAGE_SIZE << PMD_TABLE_ORDER);
+ return pmd;
+}
+
+static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
+{
+ free_pages((unsigned long)pmd, PMD_TABLE_ORDER);
+}
+#endif
+
+static inline void
+pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, pte_t *pte)
+{
+ set_pmd(pmd, __pmd((PxD_FLAG_PRESENT | PxD_FLAG_VALID)
+ + (__u32)(__pa((unsigned long)pte) >> PxD_VALUE_SHIFT)));
+}
+
+#define pmd_populate(mm, pmd, pte_page) \
+ pmd_populate_kernel(mm, pmd, page_address(pte_page))
+
+#endif
diff --git a/arch/parisc/include/asm/pgtable.h b/arch/parisc/include/asm/pgtable.h
new file mode 100644
index 000000000..974accac0
--- /dev/null
+++ b/arch/parisc/include/asm/pgtable.h
@@ -0,0 +1,518 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _PARISC_PGTABLE_H
+#define _PARISC_PGTABLE_H
+
+#include <asm/page.h>
+
+#if CONFIG_PGTABLE_LEVELS == 3
+#include <asm-generic/pgtable-nopud.h>
+#elif CONFIG_PGTABLE_LEVELS == 2
+#include <asm-generic/pgtable-nopmd.h>
+#endif
+
+#include <asm/fixmap.h>
+
+#ifndef __ASSEMBLY__
+/*
+ * we simulate an x86-style page table for the linux mm code
+ */
+
+#include <linux/bitops.h>
+#include <linux/spinlock.h>
+#include <linux/mm_types.h>
+#include <asm/processor.h>
+#include <asm/cache.h>
+
+/* This is for the serialization of PxTLB broadcasts. At least on the N class
+ * systems, only one PxTLB inter processor broadcast can be active at any one
+ * time on the Merced bus. */
+extern spinlock_t pa_tlb_flush_lock;
+#if defined(CONFIG_64BIT) && defined(CONFIG_SMP)
+extern int pa_serialize_tlb_flushes;
+#else
+#define pa_serialize_tlb_flushes (0)
+#endif
+
+#define purge_tlb_start(flags) do { \
+ if (pa_serialize_tlb_flushes) \
+ spin_lock_irqsave(&pa_tlb_flush_lock, flags); \
+ else \
+ local_irq_save(flags); \
+ } while (0)
+#define purge_tlb_end(flags) do { \
+ if (pa_serialize_tlb_flushes) \
+ spin_unlock_irqrestore(&pa_tlb_flush_lock, flags); \
+ else \
+ local_irq_restore(flags); \
+ } while (0)
+
+/* Purge data and instruction TLB entries. The TLB purge instructions
+ * are slow on SMP machines since the purge must be broadcast to all CPUs.
+ */
+
+static inline void purge_tlb_entries(struct mm_struct *mm, unsigned long addr)
+{
+ unsigned long flags;
+
+ purge_tlb_start(flags);
+ mtsp(mm->context.space_id, SR_TEMP1);
+ pdtlb(SR_TEMP1, addr);
+ pitlb(SR_TEMP1, addr);
+ purge_tlb_end(flags);
+}
+
+extern void __update_cache(pte_t pte);
+
+/* Certain architectures need to do special things when PTEs
+ * within a page table are directly modified. Thus, the following
+ * hook is made available.
+ */
+#define set_pte(pteptr, pteval) \
+ do { \
+ *(pteptr) = (pteval); \
+ mb(); \
+ } while(0)
+
+#endif /* !__ASSEMBLY__ */
+
+#define pte_ERROR(e) \
+ printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
+#if CONFIG_PGTABLE_LEVELS == 3
+#define pmd_ERROR(e) \
+ printk("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, (unsigned long)pmd_val(e))
+#endif
+#define pgd_ERROR(e) \
+ printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, (unsigned long)pgd_val(e))
+
+/* This is the size of the initially mapped kernel memory */
+#if defined(CONFIG_64BIT)
+#define KERNEL_INITIAL_ORDER 26 /* 1<<26 = 64MB */
+#else
+#define KERNEL_INITIAL_ORDER 25 /* 1<<25 = 32MB */
+#endif
+#define KERNEL_INITIAL_SIZE (1 << KERNEL_INITIAL_ORDER)
+
+#if CONFIG_PGTABLE_LEVELS == 3
+#define PMD_TABLE_ORDER 1
+#define PGD_TABLE_ORDER 0
+#else
+#define PGD_TABLE_ORDER 1
+#endif
+
+/* Definitions for 3rd level (we use PLD here for Page Lower directory
+ * because PTE_SHIFT is used lower down to mean shift that has to be
+ * done to get usable bits out of the PTE) */
+#define PLD_SHIFT PAGE_SHIFT
+#define PLD_SIZE PAGE_SIZE
+#define BITS_PER_PTE (PAGE_SHIFT - BITS_PER_PTE_ENTRY)
+#define PTRS_PER_PTE (1UL << BITS_PER_PTE)
+
+/* Definitions for 2nd level */
+#if CONFIG_PGTABLE_LEVELS == 3
+#define PMD_SHIFT (PLD_SHIFT + BITS_PER_PTE)
+#define PMD_SIZE (1UL << PMD_SHIFT)
+#define PMD_MASK (~(PMD_SIZE-1))
+#define BITS_PER_PMD (PAGE_SHIFT + PMD_TABLE_ORDER - BITS_PER_PMD_ENTRY)
+#define PTRS_PER_PMD (1UL << BITS_PER_PMD)
+#else
+#define BITS_PER_PMD 0
+#endif
+
+/* Definitions for 1st level */
+#define PGDIR_SHIFT (PLD_SHIFT + BITS_PER_PTE + BITS_PER_PMD)
+#if (PGDIR_SHIFT + PAGE_SHIFT + PGD_TABLE_ORDER - BITS_PER_PGD_ENTRY) > BITS_PER_LONG
+#define BITS_PER_PGD (BITS_PER_LONG - PGDIR_SHIFT)
+#else
+#define BITS_PER_PGD (PAGE_SHIFT + PGD_TABLE_ORDER - BITS_PER_PGD_ENTRY)
+#endif
+#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
+#define PGDIR_MASK (~(PGDIR_SIZE-1))
+#define PTRS_PER_PGD (1UL << BITS_PER_PGD)
+#define USER_PTRS_PER_PGD PTRS_PER_PGD
+
+#ifdef CONFIG_64BIT
+#define MAX_ADDRBITS (PGDIR_SHIFT + BITS_PER_PGD)
+#define MAX_ADDRESS (1UL << MAX_ADDRBITS)
+#define SPACEID_SHIFT (MAX_ADDRBITS - 32)
+#else
+#define MAX_ADDRBITS (BITS_PER_LONG)
+#define MAX_ADDRESS (1ULL << MAX_ADDRBITS)
+#define SPACEID_SHIFT 0
+#endif
+
+/* This calculates the number of initial pages we need for the initial
+ * page tables */
+#if (KERNEL_INITIAL_ORDER) >= (PLD_SHIFT + BITS_PER_PTE)
+# define PT_INITIAL (1 << (KERNEL_INITIAL_ORDER - PLD_SHIFT - BITS_PER_PTE))
+#else
+# define PT_INITIAL (1) /* all initial PTEs fit into one page */
+#endif
+
+/*
+ * pgd entries used up by user/kernel:
+ */
+
+/* NB: The tlb miss handlers make certain assumptions about the order */
+/* of the following bits, so be careful (One example, bits 25-31 */
+/* are moved together in one instruction). */
+
+#define _PAGE_READ_BIT 31 /* (0x001) read access allowed */
+#define _PAGE_WRITE_BIT 30 /* (0x002) write access allowed */
+#define _PAGE_EXEC_BIT 29 /* (0x004) execute access allowed */
+#define _PAGE_GATEWAY_BIT 28 /* (0x008) privilege promotion allowed */
+#define _PAGE_DMB_BIT 27 /* (0x010) Data Memory Break enable (B bit) */
+#define _PAGE_DIRTY_BIT 26 /* (0x020) Page Dirty (D bit) */
+#define _PAGE_REFTRAP_BIT 25 /* (0x040) Page Ref. Trap enable (T bit) */
+#define _PAGE_NO_CACHE_BIT 24 /* (0x080) Uncached Page (U bit) */
+#define _PAGE_ACCESSED_BIT 23 /* (0x100) Software: Page Accessed */
+#define _PAGE_PRESENT_BIT 22 /* (0x200) Software: translation valid */
+#define _PAGE_HPAGE_BIT 21 /* (0x400) Software: Huge Page */
+#define _PAGE_USER_BIT 20 /* (0x800) Software: User accessible page */
+#ifdef CONFIG_HUGETLB_PAGE
+#define _PAGE_SPECIAL_BIT _PAGE_DMB_BIT /* DMB feature is currently unused */
+#else
+#define _PAGE_SPECIAL_BIT _PAGE_HPAGE_BIT /* use unused HUGE PAGE bit */
+#endif
+
+/* N.B. The bits are defined in terms of a 32 bit word above, so the */
+/* following macro is ok for both 32 and 64 bit. */
+
+#define xlate_pabit(x) (31 - x)
+
+/* this defines the shift to the usable bits in the PTE it is set so
+ * that the valid bits _PAGE_PRESENT_BIT and _PAGE_USER_BIT are set
+ * to zero */
+#define PTE_SHIFT xlate_pabit(_PAGE_USER_BIT)
+
+/* PFN_PTE_SHIFT defines the shift of a PTE value to access the PFN field */
+#define PFN_PTE_SHIFT 12
+
+#define _PAGE_READ (1 << xlate_pabit(_PAGE_READ_BIT))
+#define _PAGE_WRITE (1 << xlate_pabit(_PAGE_WRITE_BIT))
+#define _PAGE_RW (_PAGE_READ | _PAGE_WRITE)
+#define _PAGE_EXEC (1 << xlate_pabit(_PAGE_EXEC_BIT))
+#define _PAGE_GATEWAY (1 << xlate_pabit(_PAGE_GATEWAY_BIT))
+#define _PAGE_DMB (1 << xlate_pabit(_PAGE_DMB_BIT))
+#define _PAGE_DIRTY (1 << xlate_pabit(_PAGE_DIRTY_BIT))
+#define _PAGE_REFTRAP (1 << xlate_pabit(_PAGE_REFTRAP_BIT))
+#define _PAGE_NO_CACHE (1 << xlate_pabit(_PAGE_NO_CACHE_BIT))
+#define _PAGE_ACCESSED (1 << xlate_pabit(_PAGE_ACCESSED_BIT))
+#define _PAGE_PRESENT (1 << xlate_pabit(_PAGE_PRESENT_BIT))
+#define _PAGE_HUGE (1 << xlate_pabit(_PAGE_HPAGE_BIT))
+#define _PAGE_USER (1 << xlate_pabit(_PAGE_USER_BIT))
+#define _PAGE_SPECIAL (1 << xlate_pabit(_PAGE_SPECIAL_BIT))
+
+#define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_READ | _PAGE_WRITE | _PAGE_DIRTY | _PAGE_ACCESSED)
+#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_SPECIAL)
+#define _PAGE_KERNEL_RO (_PAGE_PRESENT | _PAGE_READ | _PAGE_DIRTY | _PAGE_ACCESSED)
+#define _PAGE_KERNEL_EXEC (_PAGE_KERNEL_RO | _PAGE_EXEC)
+#define _PAGE_KERNEL_RWX (_PAGE_KERNEL_EXEC | _PAGE_WRITE)
+#define _PAGE_KERNEL (_PAGE_KERNEL_RO | _PAGE_WRITE)
+
+/* We borrow bit 23 to store the exclusive marker in swap PTEs. */
+#define _PAGE_SWP_EXCLUSIVE _PAGE_ACCESSED
+
+/* The pgd/pmd contains a ptr (in phys addr space); since all pgds/pmds
+ * are page-aligned, we don't care about the PAGE_OFFSET bits, except
+ * for a few meta-information bits, so we shift the address to be
+ * able to effectively address 40/42/44-bits of physical address space
+ * depending on 4k/16k/64k PAGE_SIZE */
+#define _PxD_PRESENT_BIT 31
+#define _PxD_VALID_BIT 30
+
+#define PxD_FLAG_PRESENT (1 << xlate_pabit(_PxD_PRESENT_BIT))
+#define PxD_FLAG_VALID (1 << xlate_pabit(_PxD_VALID_BIT))
+#define PxD_FLAG_MASK (0xf)
+#define PxD_FLAG_SHIFT (4)
+#define PxD_VALUE_SHIFT (PFN_PTE_SHIFT-PxD_FLAG_SHIFT)
+
+#ifndef __ASSEMBLY__
+
+#define PAGE_NONE __pgprot(_PAGE_PRESENT | _PAGE_USER)
+#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_READ | _PAGE_WRITE)
+/* Others seem to make this executable, I don't know if that's correct
+ or not. The stack is mapped this way though so this is necessary
+ in the short term - dhd@linuxcare.com, 2000-08-08 */
+#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_READ)
+#define PAGE_WRITEONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_WRITE)
+#define PAGE_EXECREAD __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_READ | _PAGE_EXEC)
+#define PAGE_COPY PAGE_EXECREAD
+#define PAGE_RWX __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_READ | _PAGE_WRITE | _PAGE_EXEC)
+#define PAGE_KERNEL __pgprot(_PAGE_KERNEL)
+#define PAGE_KERNEL_EXEC __pgprot(_PAGE_KERNEL_EXEC)
+#define PAGE_KERNEL_RWX __pgprot(_PAGE_KERNEL_RWX)
+#define PAGE_KERNEL_RO __pgprot(_PAGE_KERNEL_RO)
+#define PAGE_KERNEL_UNC __pgprot(_PAGE_KERNEL | _PAGE_NO_CACHE)
+#define PAGE_GATEWAY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_GATEWAY| _PAGE_READ)
+
+
+/*
+ * We could have an execute only page using "gateway - promote to priv
+ * level 3", but that is kind of silly. So, the way things are defined
+ * now, we must always have read permission for pages with execute
+ * permission. For the fun of it we'll go ahead and support write only
+ * pages.
+ */
+
+ /*xwr*/
+
+extern pgd_t swapper_pg_dir[]; /* declared in init_task.c */
+
+/* initial page tables for 0-8MB for kernel */
+
+extern pte_t pg0[];
+
+/* zero page used for uninitialized stuff */
+
+extern unsigned long *empty_zero_page;
+
+/*
+ * ZERO_PAGE is a global shared page that is always zero: used
+ * for zero-mapped memory areas etc..
+ */
+
+#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
+
+#define pte_none(x) (pte_val(x) == 0)
+#define pte_present(x) (pte_val(x) & _PAGE_PRESENT)
+#define pte_user(x) (pte_val(x) & _PAGE_USER)
+#define pte_clear(mm, addr, xp) set_pte(xp, __pte(0))
+
+#define pmd_flag(x) (pmd_val(x) & PxD_FLAG_MASK)
+#define pmd_address(x) ((unsigned long)(pmd_val(x) &~ PxD_FLAG_MASK) << PxD_VALUE_SHIFT)
+#define pud_flag(x) (pud_val(x) & PxD_FLAG_MASK)
+#define pud_address(x) ((unsigned long)(pud_val(x) &~ PxD_FLAG_MASK) << PxD_VALUE_SHIFT)
+#define pgd_flag(x) (pgd_val(x) & PxD_FLAG_MASK)
+#define pgd_address(x) ((unsigned long)(pgd_val(x) &~ PxD_FLAG_MASK) << PxD_VALUE_SHIFT)
+
+#define pmd_none(x) (!pmd_val(x))
+#define pmd_bad(x) (!(pmd_flag(x) & PxD_FLAG_VALID))
+#define pmd_present(x) (pmd_flag(x) & PxD_FLAG_PRESENT)
+static inline void pmd_clear(pmd_t *pmd) {
+ set_pmd(pmd, __pmd(0));
+}
+
+
+
+#if CONFIG_PGTABLE_LEVELS == 3
+#define pud_pgtable(pud) ((pmd_t *) __va(pud_address(pud)))
+#define pud_page(pud) virt_to_page((void *)pud_pgtable(pud))
+
+/* For 64 bit we have three level tables */
+
+#define pud_none(x) (!pud_val(x))
+#define pud_bad(x) (!(pud_flag(x) & PxD_FLAG_VALID))
+#define pud_present(x) (pud_flag(x) & PxD_FLAG_PRESENT)
+static inline void pud_clear(pud_t *pud) {
+ set_pud(pud, __pud(0));
+}
+#endif
+
+/*
+ * The following only work if pte_present() is true.
+ * Undefined behaviour if not..
+ */
+static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; }
+static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; }
+static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_WRITE; }
+static inline int pte_special(pte_t pte) { return pte_val(pte) & _PAGE_SPECIAL; }
+
+static inline pte_t pte_mkclean(pte_t pte) { pte_val(pte) &= ~_PAGE_DIRTY; return pte; }
+static inline pte_t pte_mkold(pte_t pte) { pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
+static inline pte_t pte_wrprotect(pte_t pte) { pte_val(pte) &= ~_PAGE_WRITE; return pte; }
+static inline pte_t pte_mkdirty(pte_t pte) { pte_val(pte) |= _PAGE_DIRTY; return pte; }
+static inline pte_t pte_mkyoung(pte_t pte) { pte_val(pte) |= _PAGE_ACCESSED; return pte; }
+static inline pte_t pte_mkwrite_novma(pte_t pte) { pte_val(pte) |= _PAGE_WRITE; return pte; }
+static inline pte_t pte_mkspecial(pte_t pte) { pte_val(pte) |= _PAGE_SPECIAL; return pte; }
+
+/*
+ * Huge pte definitions.
+ */
+#ifdef CONFIG_HUGETLB_PAGE
+#define pte_huge(pte) (pte_val(pte) & _PAGE_HUGE)
+#define pte_mkhuge(pte) (__pte(pte_val(pte) | \
+ (parisc_requires_coherency() ? 0 : _PAGE_HUGE)))
+#else
+#define pte_huge(pte) (0)
+#define pte_mkhuge(pte) (pte)
+#endif
+
+
+/*
+ * Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ */
+#define __mk_pte(addr,pgprot) \
+({ \
+ pte_t __pte; \
+ \
+ pte_val(__pte) = ((((addr)>>PAGE_SHIFT)<<PFN_PTE_SHIFT) + pgprot_val(pgprot)); \
+ \
+ __pte; \
+})
+
+#define mk_pte(page, pgprot) pfn_pte(page_to_pfn(page), (pgprot))
+
+static inline pte_t pfn_pte(unsigned long pfn, pgprot_t pgprot)
+{
+ pte_t pte;
+ pte_val(pte) = (pfn << PFN_PTE_SHIFT) | pgprot_val(pgprot);
+ return pte;
+}
+
+static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+{ pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); return pte; }
+
+/* Permanent address of a page. On parisc we don't have highmem. */
+
+#define pte_pfn(x) (pte_val(x) >> PFN_PTE_SHIFT)
+
+#define pte_page(pte) (pfn_to_page(pte_pfn(pte)))
+
+static inline unsigned long pmd_page_vaddr(pmd_t pmd)
+{
+ return ((unsigned long) __va(pmd_address(pmd)));
+}
+
+#define pmd_pfn(pmd) (pmd_address(pmd) >> PAGE_SHIFT)
+#define __pmd_page(pmd) ((unsigned long) __va(pmd_address(pmd)))
+#define pmd_page(pmd) virt_to_page((void *)__pmd_page(pmd))
+
+/* Find an entry in the second-level page table.. */
+
+extern void paging_init (void);
+
+static inline void set_ptes(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t pte, unsigned int nr)
+{
+ if (pte_present(pte) && pte_user(pte))
+ __update_cache(pte);
+ for (;;) {
+ *ptep = pte;
+ purge_tlb_entries(mm, addr);
+ if (--nr == 0)
+ break;
+ ptep++;
+ pte_val(pte) += 1 << PFN_PTE_SHIFT;
+ addr += PAGE_SIZE;
+ }
+}
+#define set_ptes set_ptes
+
+/* Used for deferring calls to flush_dcache_page() */
+
+#define PG_dcache_dirty PG_arch_1
+
+#define update_mmu_cache_range(vmf, vma, addr, ptep, nr) __update_cache(*ptep)
+#define update_mmu_cache(vma, addr, ptep) __update_cache(*ptep)
+
+/*
+ * Encode/decode swap entries and swap PTEs. Swap PTEs are all PTEs that
+ * are !pte_none() && !pte_present().
+ *
+ * Format of swap PTEs (32bit):
+ *
+ * 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * <---------------- offset -----------------> P E <ofs> < type ->
+ *
+ * E is the exclusive marker that is not stored in swap entries.
+ * _PAGE_PRESENT (P) must be 0.
+ *
+ * For the 64bit version, the offset is extended by 32bit.
+ */
+#define __swp_type(x) ((x).val & 0x1f)
+#define __swp_offset(x) ( (((x).val >> 5) & 0x7) | \
+ (((x).val >> 10) << 3) )
+#define __swp_entry(type, offset) ((swp_entry_t) { \
+ ((type) & 0x1f) | \
+ ((offset & 0x7) << 5) | \
+ ((offset >> 3) << 10) })
+#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) })
+#define __swp_entry_to_pte(x) ((pte_t) { (x).val })
+
+static inline int pte_swp_exclusive(pte_t pte)
+{
+ return pte_val(pte) & _PAGE_SWP_EXCLUSIVE;
+}
+
+static inline pte_t pte_swp_mkexclusive(pte_t pte)
+{
+ pte_val(pte) |= _PAGE_SWP_EXCLUSIVE;
+ return pte;
+}
+
+static inline pte_t pte_swp_clear_exclusive(pte_t pte)
+{
+ pte_val(pte) &= ~_PAGE_SWP_EXCLUSIVE;
+ return pte;
+}
+
+static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
+{
+ pte_t pte;
+
+ if (!pte_young(*ptep))
+ return 0;
+
+ pte = *ptep;
+ if (!pte_young(pte)) {
+ return 0;
+ }
+ set_pte(ptep, pte_mkold(pte));
+ return 1;
+}
+
+struct mm_struct;
+static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
+{
+ pte_t old_pte;
+
+ old_pte = *ptep;
+ set_pte(ptep, __pte(0));
+
+ return old_pte;
+}
+
+static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
+{
+ set_pte(ptep, pte_wrprotect(*ptep));
+}
+
+#define pte_same(A,B) (pte_val(A) == pte_val(B))
+
+#endif /* !__ASSEMBLY__ */
+
+
+/* TLB page size encoding - see table 3-1 in parisc20.pdf */
+#define _PAGE_SIZE_ENCODING_4K 0
+#define _PAGE_SIZE_ENCODING_16K 1
+#define _PAGE_SIZE_ENCODING_64K 2
+#define _PAGE_SIZE_ENCODING_256K 3
+#define _PAGE_SIZE_ENCODING_1M 4
+#define _PAGE_SIZE_ENCODING_4M 5
+#define _PAGE_SIZE_ENCODING_16M 6
+#define _PAGE_SIZE_ENCODING_64M 7
+
+#if defined(CONFIG_PARISC_PAGE_SIZE_4KB)
+# define _PAGE_SIZE_ENCODING_DEFAULT _PAGE_SIZE_ENCODING_4K
+#elif defined(CONFIG_PARISC_PAGE_SIZE_16KB)
+# define _PAGE_SIZE_ENCODING_DEFAULT _PAGE_SIZE_ENCODING_16K
+#elif defined(CONFIG_PARISC_PAGE_SIZE_64KB)
+# define _PAGE_SIZE_ENCODING_DEFAULT _PAGE_SIZE_ENCODING_64K
+#endif
+
+
+#define pgprot_noncached(prot) __pgprot(pgprot_val(prot) | _PAGE_NO_CACHE)
+
+/* We provide our own get_unmapped_area to provide cache coherency */
+
+#define HAVE_ARCH_UNMAPPED_AREA
+#define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN
+
+#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
+#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
+#define __HAVE_ARCH_PTEP_SET_WRPROTECT
+#define __HAVE_ARCH_PTE_SAME
+
+#endif /* _PARISC_PGTABLE_H */
diff --git a/arch/parisc/include/asm/prefetch.h b/arch/parisc/include/asm/prefetch.h
new file mode 100644
index 000000000..6e63f7200
--- /dev/null
+++ b/arch/parisc/include/asm/prefetch.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * include/asm-parisc/prefetch.h
+ *
+ * PA 2.0 defines data prefetch instructions on page 6-11 of the Kane book.
+ * In addition, many implementations do hardware prefetching of both
+ * instructions and data.
+ *
+ * PA7300LC (page 14-4 of the ERS) also implements prefetching by a load
+ * to gr0 but not in a way that Linux can use. If the load would cause an
+ * interruption (eg due to prefetching 0), it is suppressed on PA2.0
+ * processors, but not on 7300LC.
+ *
+ */
+
+#ifndef __ASM_PARISC_PREFETCH_H
+#define __ASM_PARISC_PREFETCH_H
+
+#ifndef __ASSEMBLY__
+#ifdef CONFIG_PREFETCH
+
+#define ARCH_HAS_PREFETCH
+static inline void prefetch(const void *addr)
+{
+ __asm__(
+#ifndef CONFIG_PA20
+ /* Need to avoid prefetch of NULL on PA7300LC */
+ " extrw,u,= %0,31,32,%%r0\n"
+#endif
+ " ldw 0(%0), %%r0" : : "r" (addr));
+}
+
+/* LDD is a PA2.0 addition. */
+#ifdef CONFIG_PA20
+#define ARCH_HAS_PREFETCHW
+static inline void prefetchw(const void *addr)
+{
+ __asm__("ldd 0(%0), %%r0" : : "r" (addr));
+}
+#endif /* CONFIG_PA20 */
+
+#endif /* CONFIG_PREFETCH */
+#endif /* __ASSEMBLY__ */
+
+#endif /* __ASM_PARISC_PROCESSOR_H */
diff --git a/arch/parisc/include/asm/processor.h b/arch/parisc/include/asm/processor.h
new file mode 100644
index 000000000..ece4b3046
--- /dev/null
+++ b/arch/parisc/include/asm/processor.h
@@ -0,0 +1,329 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * include/asm-parisc/processor.h
+ *
+ * Copyright (C) 1994 Linus Torvalds
+ * Copyright (C) 2001 Grant Grundler
+ */
+
+#ifndef __ASM_PARISC_PROCESSOR_H
+#define __ASM_PARISC_PROCESSOR_H
+
+#ifndef __ASSEMBLY__
+#include <linux/threads.h>
+#include <linux/irqreturn.h>
+
+#include <asm/assembly.h>
+#include <asm/prefetch.h>
+#include <asm/hardware.h>
+#include <asm/pdc.h>
+#include <asm/ptrace.h>
+#include <asm/types.h>
+#include <asm/percpu.h>
+#endif /* __ASSEMBLY__ */
+
+#define HAVE_ARCH_PICK_MMAP_LAYOUT
+
+#define TASK_SIZE_OF(tsk) ((tsk)->thread.task_size)
+#define TASK_SIZE TASK_SIZE_OF(current)
+#define TASK_UNMAPPED_BASE (current->thread.map_base)
+
+#define DEFAULT_TASK_SIZE32 (0xFFF00000UL)
+#define DEFAULT_MAP_BASE32 (0x40000000UL)
+
+#ifdef CONFIG_64BIT
+#define DEFAULT_TASK_SIZE (MAX_ADDRESS-0xf000000)
+#define DEFAULT_MAP_BASE (0x200000000UL)
+#else
+#define DEFAULT_TASK_SIZE DEFAULT_TASK_SIZE32
+#define DEFAULT_MAP_BASE DEFAULT_MAP_BASE32
+#endif
+
+/* XXX: STACK_TOP actually should be STACK_BOTTOM for parisc.
+ * prumpf */
+
+#define STACK_TOP TASK_SIZE
+#define STACK_TOP_MAX DEFAULT_TASK_SIZE
+
+#ifndef __ASSEMBLY__
+
+struct rlimit;
+unsigned long mmap_upper_limit(struct rlimit *rlim_stack);
+unsigned long calc_max_stack_size(unsigned long stack_max);
+
+/*
+ * Data detected about CPUs at boot time which is the same for all CPU's.
+ * HP boxes are SMP - ie identical processors.
+ *
+ * FIXME: some CPU rev info may be processor specific...
+ */
+struct system_cpuinfo_parisc {
+ unsigned int cpu_count;
+ unsigned int cpu_hz;
+ unsigned int hversion;
+ unsigned int sversion;
+ enum cpu_type cpu_type;
+
+ struct {
+ struct pdc_model model;
+ unsigned long versions;
+ unsigned long cpuid;
+ unsigned long capabilities;
+ char sys_model_name[81]; /* PDC-ROM returnes this model name */
+ } pdc;
+
+ const char *cpu_name; /* e.g. "PA7300LC (PCX-L2)" */
+ const char *family_name; /* e.g. "1.1e" */
+};
+
+
+/* Per CPU data structure - ie varies per CPU. */
+struct cpuinfo_parisc {
+ unsigned long it_value; /* Interval Timer at last timer Intr */
+ unsigned long irq_count; /* number of IRQ's since boot */
+ unsigned long cpuid; /* aka slot_number or set to NO_PROC_ID */
+ unsigned long hpa; /* Host Physical address */
+ unsigned long txn_addr; /* MMIO addr of EIR or id_eid */
+#ifdef CONFIG_SMP
+ unsigned long pending_ipi; /* bitmap of type ipi_message_type */
+#endif
+ unsigned long bh_count; /* number of times bh was invoked */
+ unsigned long fp_rev;
+ unsigned long fp_model;
+ unsigned long cpu_num; /* CPU number from PAT firmware */
+ unsigned long cpu_loc; /* CPU location from PAT firmware */
+ unsigned int state;
+ struct parisc_device *dev;
+};
+
+extern struct system_cpuinfo_parisc boot_cpu_data;
+DECLARE_PER_CPU(struct cpuinfo_parisc, cpu_data);
+extern int time_keeper_id; /* CPU used for timekeeping */
+
+#define CPU_HVERSION ((boot_cpu_data.hversion >> 4) & 0x0FFF)
+
+struct thread_struct {
+ struct pt_regs regs;
+ unsigned long task_size;
+ unsigned long map_base;
+ unsigned long flags;
+};
+
+#define task_pt_regs(tsk) ((struct pt_regs *)&((tsk)->thread.regs))
+
+/* Thread struct flags. */
+#define PARISC_UAC_NOPRINT (1UL << 0) /* see prctl and unaligned.c */
+#define PARISC_UAC_SIGBUS (1UL << 1)
+#define PARISC_KERNEL_DEATH (1UL << 31) /* see die_if_kernel()... */
+
+#define PARISC_UAC_SHIFT 0
+#define PARISC_UAC_MASK (PARISC_UAC_NOPRINT|PARISC_UAC_SIGBUS)
+
+#define SET_UNALIGN_CTL(task,value) \
+ ({ \
+ (task)->thread.flags = (((task)->thread.flags & ~PARISC_UAC_MASK) \
+ | (((value) << PARISC_UAC_SHIFT) & \
+ PARISC_UAC_MASK)); \
+ 0; \
+ })
+
+#define GET_UNALIGN_CTL(task,addr) \
+ ({ \
+ put_user(((task)->thread.flags & PARISC_UAC_MASK) \
+ >> PARISC_UAC_SHIFT, (int __user *) (addr)); \
+ })
+
+#define INIT_THREAD { \
+ .regs = { .gr = { 0, }, \
+ .fr = { 0, }, \
+ .sr = { 0, }, \
+ .iasq = { 0, }, \
+ .iaoq = { 0, }, \
+ .cr27 = 0, \
+ }, \
+ .task_size = DEFAULT_TASK_SIZE, \
+ .map_base = DEFAULT_MAP_BASE, \
+ .flags = 0 \
+ }
+
+struct task_struct;
+void show_trace(struct task_struct *task, unsigned long *stack);
+
+/*
+ * Start user thread in another space.
+ *
+ * Note that we set both the iaoq and r31 to the new pc. When
+ * the kernel initially calls execve it will return through an
+ * rfi path that will use the values in the iaoq. The execve
+ * syscall path will return through the gateway page, and
+ * that uses r31 to branch to.
+ *
+ * For ELF we clear r23, because the dynamic linker uses it to pass
+ * the address of the finalizer function.
+ *
+ * We also initialize sr3 to an illegal value (illegal for our
+ * implementation, not for the architecture).
+ */
+typedef unsigned int elf_caddr_t;
+
+/* The ELF abi wants things done a "wee bit" differently than
+ * som does. Supporting this behavior here avoids
+ * having our own version of create_elf_tables.
+ *
+ * Oh, and yes, that is not a typo, we are really passing argc in r25
+ * and argv in r24 (rather than r26 and r25). This is because that's
+ * where __libc_start_main wants them.
+ *
+ * Duplicated from dl-machine.h for the benefit of readers:
+ *
+ * Our initial stack layout is rather different from everyone else's
+ * due to the unique PA-RISC ABI. As far as I know it looks like
+ * this:
+
+ ----------------------------------- (user startup code creates this frame)
+ | 32 bytes of magic |
+ |---------------------------------|
+ | 32 bytes argument/sp save area |
+ |---------------------------------| (bprm->p)
+ | ELF auxiliary info |
+ | (up to 28 words) |
+ |---------------------------------|
+ | NULL |
+ |---------------------------------|
+ | Environment pointers |
+ |---------------------------------|
+ | NULL |
+ |---------------------------------|
+ | Argument pointers |
+ |---------------------------------| <- argv
+ | argc (1 word) |
+ |---------------------------------| <- bprm->exec (HACK!)
+ | N bytes of slack |
+ |---------------------------------|
+ | filename passed to execve |
+ |---------------------------------| (mm->env_end)
+ | env strings |
+ |---------------------------------| (mm->env_start, mm->arg_end)
+ | arg strings |
+ |---------------------------------|
+ | additional faked arg strings if |
+ | we're invoked via binfmt_script |
+ |---------------------------------| (mm->arg_start)
+ stack base is at TASK_SIZE - rlim_max.
+
+on downward growing arches, it looks like this:
+ stack base at TASK_SIZE
+ | filename passed to execve
+ | env strings
+ | arg strings
+ | faked arg strings
+ | slack
+ | ELF
+ | envps
+ | argvs
+ | argc
+
+ * The pleasant part of this is that if we need to skip arguments we
+ * can just decrement argc and move argv, because the stack pointer
+ * is utterly unrelated to the location of the environment and
+ * argument vectors.
+ *
+ * Note that the S/390 people took the easy way out and hacked their
+ * GCC to make the stack grow downwards.
+ *
+ * Final Note: For entry from syscall, the W (wide) bit of the PSW
+ * is stuffed into the lowest bit of the user sp (%r30), so we fill
+ * it in here from the current->personality
+ */
+
+#define USER_WIDE_MODE (!is_32bit_task())
+
+#define start_thread(regs, new_pc, new_sp) do { \
+ elf_addr_t *sp = (elf_addr_t *)new_sp; \
+ __u32 spaceid = (__u32)current->mm->context.space_id; \
+ elf_addr_t pc = (elf_addr_t)new_pc | 3; \
+ elf_caddr_t *argv = (elf_caddr_t *)bprm->exec + 1; \
+ \
+ regs->iasq[0] = spaceid; \
+ regs->iasq[1] = spaceid; \
+ regs->iaoq[0] = pc; \
+ regs->iaoq[1] = pc + 4; \
+ regs->sr[2] = LINUX_GATEWAY_SPACE; \
+ regs->sr[3] = 0xffff; \
+ regs->sr[4] = spaceid; \
+ regs->sr[5] = spaceid; \
+ regs->sr[6] = spaceid; \
+ regs->sr[7] = spaceid; \
+ regs->gr[ 0] = USER_PSW | (USER_WIDE_MODE ? PSW_W : 0); \
+ regs->fr[ 0] = 0LL; \
+ regs->fr[ 1] = 0LL; \
+ regs->fr[ 2] = 0LL; \
+ regs->fr[ 3] = 0LL; \
+ regs->gr[30] = (((unsigned long)sp + 63) &~ 63) | (USER_WIDE_MODE ? 1 : 0); \
+ regs->gr[31] = pc; \
+ \
+ get_user(regs->gr[25], (argv - 1)); \
+ regs->gr[24] = (long) argv; \
+ regs->gr[23] = 0; \
+} while(0)
+
+struct mm_struct;
+
+extern unsigned long __get_wchan(struct task_struct *p);
+
+#define KSTK_EIP(tsk) ((tsk)->thread.regs.iaoq[0])
+#define KSTK_ESP(tsk) ((tsk)->thread.regs.gr[30])
+
+#define cpu_relax() barrier()
+
+/*
+ * parisc_requires_coherency() is used to identify the combined VIPT/PIPT
+ * cached CPUs which require a guarantee of coherency (no inequivalent aliases
+ * with different data, whether clean or not) to operate
+ */
+#ifdef CONFIG_PA8X00
+extern int _parisc_requires_coherency;
+#define parisc_requires_coherency() _parisc_requires_coherency
+#else
+#define parisc_requires_coherency() (0)
+#endif
+
+extern int running_on_qemu;
+
+extern void __noreturn toc_intr(struct pt_regs *regs);
+extern void toc_handler(void);
+extern unsigned int toc_handler_size;
+extern unsigned int toc_handler_csum;
+extern void do_cpu_irq_mask(struct pt_regs *);
+extern irqreturn_t timer_interrupt(int, void *);
+extern irqreturn_t ipi_interrupt(int, void *);
+extern void start_cpu_itimer(void);
+extern void handle_interruption(int, struct pt_regs *);
+
+/* called from assembly code: */
+extern void start_parisc(void);
+extern void smp_callin(unsigned long);
+extern void sys_rt_sigreturn(struct pt_regs *, int);
+extern void do_notify_resume(struct pt_regs *, long);
+extern long do_syscall_trace_enter(struct pt_regs *);
+extern void do_syscall_trace_exit(struct pt_regs *);
+
+/* CPU startup and info */
+struct seq_file;
+extern void early_trap_init(void);
+extern void collect_boot_cpu_data(void);
+extern void btlb_init_per_cpu(void);
+extern int show_cpuinfo (struct seq_file *m, void *v);
+
+/* driver code in driver/parisc */
+extern void processor_init(void);
+struct parisc_device;
+struct resource;
+extern void sba_distributed_lmmio(struct parisc_device *, struct resource *);
+extern void sba_directed_lmmio(struct parisc_device *, struct resource *);
+extern void lba_set_iregs(struct parisc_device *lba, u32 ibase, u32 imask);
+extern void ccio_cujo20_fixup(struct parisc_device *dev, u32 iovp);
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __ASM_PARISC_PROCESSOR_H */
diff --git a/arch/parisc/include/asm/psw.h b/arch/parisc/include/asm/psw.h
new file mode 100644
index 000000000..46921ffcc
--- /dev/null
+++ b/arch/parisc/include/asm/psw.h
@@ -0,0 +1,104 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _PARISC_PSW_H
+#define _PARISC_PSW_H
+
+#define PSW_I 0x00000001
+#define PSW_D 0x00000002
+#define PSW_P 0x00000004
+#define PSW_Q 0x00000008
+
+#define PSW_R 0x00000010
+#define PSW_F 0x00000020
+#define PSW_G 0x00000040 /* PA1.x only */
+#define PSW_O 0x00000080 /* PA2.0 only */
+
+/* ssm/rsm instructions number PSW_W and PSW_E differently */
+#define PSW_SM_I PSW_I /* Enable External Interrupts */
+#define PSW_SM_D PSW_D
+#define PSW_SM_P PSW_P
+#define PSW_SM_Q PSW_Q /* Enable Interrupt State Collection */
+#define PSW_SM_R PSW_R /* Enable Recover Counter Trap */
+#define PSW_SM_W 0x200 /* PA2.0 only : Enable Wide Mode */
+
+#define PSW_SM_QUIET PSW_SM_R+PSW_SM_Q+PSW_SM_P+PSW_SM_D+PSW_SM_I
+
+#define PSW_CB 0x0000ff00
+
+#define PSW_M 0x00010000
+#define PSW_V 0x00020000
+#define PSW_C 0x00040000
+#define PSW_B 0x00080000
+
+#define PSW_X 0x00100000
+#define PSW_N 0x00200000
+#define PSW_L 0x00400000
+#define PSW_H 0x00800000
+
+#define PSW_T 0x01000000
+#define PSW_S 0x02000000
+#define PSW_E 0x04000000
+#define PSW_W 0x08000000 /* PA2.0 only */
+#define PSW_W_BIT 36 /* PA2.0 only */
+
+#define PSW_Z 0x40000000 /* PA1.x only */
+#define PSW_Y 0x80000000 /* PA1.x only */
+
+#ifdef CONFIG_64BIT
+# define PSW_HI_CB 0x000000ff /* PA2.0 only */
+#endif
+
+#ifdef CONFIG_64BIT
+# define USER_PSW_HI_MASK PSW_HI_CB
+# define WIDE_PSW PSW_W
+#else
+# define WIDE_PSW 0
+#endif
+
+/* Used when setting up for rfi */
+#define KERNEL_PSW (WIDE_PSW | PSW_C | PSW_Q | PSW_P | PSW_D)
+#define REAL_MODE_PSW (WIDE_PSW | PSW_Q)
+#define USER_PSW_MASK (WIDE_PSW | PSW_T | PSW_N | PSW_X | PSW_B | PSW_V | PSW_CB)
+#define USER_PSW (PSW_C | PSW_Q | PSW_P | PSW_D | PSW_I)
+
+#ifndef __ASSEMBLY__
+
+/* The program status word as bitfields. */
+struct pa_psw {
+ unsigned int y:1;
+ unsigned int z:1;
+ unsigned int rv:2;
+ unsigned int w:1;
+ unsigned int e:1;
+ unsigned int s:1;
+ unsigned int t:1;
+
+ unsigned int h:1;
+ unsigned int l:1;
+ unsigned int n:1;
+ unsigned int x:1;
+ unsigned int b:1;
+ unsigned int c:1;
+ unsigned int v:1;
+ unsigned int m:1;
+
+ unsigned int cb:8;
+
+ unsigned int o:1;
+ unsigned int g:1;
+ unsigned int f:1;
+ unsigned int r:1;
+ unsigned int q:1;
+ unsigned int p:1;
+ unsigned int d:1;
+ unsigned int i:1;
+};
+
+#ifdef CONFIG_64BIT
+#define pa_psw(task) ((struct pa_psw *) ((char *) (task) + TASK_PT_PSW + 4))
+#else
+#define pa_psw(task) ((struct pa_psw *) ((char *) (task) + TASK_PT_PSW))
+#endif
+
+#endif /* !__ASSEMBLY__ */
+
+#endif
diff --git a/arch/parisc/include/asm/ptrace.h b/arch/parisc/include/asm/ptrace.h
new file mode 100644
index 000000000..eea3f3df0
--- /dev/null
+++ b/arch/parisc/include/asm/ptrace.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* written by Philipp Rumpf, Copyright (C) 1999 SuSE GmbH Nuernberg
+** Copyright (C) 2000 Grant Grundler, Hewlett-Packard
+*/
+#ifndef _PARISC_PTRACE_H
+#define _PARISC_PTRACE_H
+
+#include <asm/assembly.h>
+#include <uapi/asm/ptrace.h>
+
+#define task_regs(task) ((struct pt_regs *) ((char *)(task) + TASK_REGS))
+
+#define arch_has_single_step() 1
+#define arch_has_block_step() 1
+
+/* XXX should we use iaoq[1] or iaoq[0] ? */
+#define user_mode(regs) (((regs)->iaoq[0] & 3) != PRIV_KERNEL)
+#define user_space(regs) ((regs)->iasq[1] != PRIV_KERNEL)
+#define instruction_pointer(regs) ((regs)->iaoq[0] & ~3)
+#define user_stack_pointer(regs) ((regs)->gr[30])
+unsigned long profile_pc(struct pt_regs *);
+
+static inline unsigned long regs_return_value(struct pt_regs *regs)
+{
+ return regs->gr[28];
+}
+
+static inline void instruction_pointer_set(struct pt_regs *regs,
+ unsigned long val)
+{
+ regs->iaoq[0] = val;
+ regs->iaoq[1] = val + 4;
+}
+
+/* Query offset/name of register from its name/offset */
+extern int regs_query_register_offset(const char *name);
+extern const char *regs_query_register_name(unsigned int offset);
+#define MAX_REG_OFFSET (offsetof(struct pt_regs, ipsw))
+
+#define kernel_stack_pointer(regs) ((regs)->gr[30])
+
+static inline unsigned long regs_get_register(struct pt_regs *regs,
+ unsigned int offset)
+{
+ if (unlikely(offset > MAX_REG_OFFSET))
+ return 0;
+ return *(unsigned long *)((unsigned long)regs + offset);
+}
+
+unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n);
+int regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr);
+
+#endif
diff --git a/arch/parisc/include/asm/ropes.h b/arch/parisc/include/asm/ropes.h
new file mode 100644
index 000000000..e2d2d7e9b
--- /dev/null
+++ b/arch/parisc/include/asm/ropes.h
@@ -0,0 +1,326 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_PARISC_ROPES_H_
+#define _ASM_PARISC_ROPES_H_
+
+#include <asm/parisc-device.h>
+
+#ifdef CONFIG_64BIT
+/* "low end" PA8800 machines use ZX1 chipset: PAT PDC and only run 64-bit */
+#define ZX1_SUPPORT
+#endif
+
+#ifdef CONFIG_PROC_FS
+/* depends on proc fs support. But costs CPU performance */
+#undef SBA_COLLECT_STATS
+#endif
+
+/*
+** The number of pdir entries to "free" before issuing
+** a read to PCOM register to flush out PCOM writes.
+** Interacts with allocation granularity (ie 4 or 8 entries
+** allocated and free'd/purged at a time might make this
+** less interesting).
+*/
+#define DELAYED_RESOURCE_CNT 16
+
+#define MAX_IOC 2 /* per Ike. Pluto/Astro only have 1. */
+#define ROPES_PER_IOC 8 /* per Ike half or Pluto/Astro */
+
+struct ioc {
+ void __iomem *ioc_hpa; /* I/O MMU base address */
+ char *res_map; /* resource map, bit == pdir entry */
+ __le64 *pdir_base; /* physical base address */
+ unsigned long ibase; /* pdir IOV Space base - shared w/lba_pci */
+ unsigned long imask; /* pdir IOV Space mask - shared w/lba_pci */
+#ifdef ZX1_SUPPORT
+ unsigned long iovp_mask; /* help convert IOVA to IOVP */
+#endif
+ unsigned long *res_hint; /* next avail IOVP - circular search */
+ spinlock_t res_lock;
+ unsigned int res_bitshift; /* from the LEFT! */
+ unsigned int res_size; /* size of resource map in bytes */
+#ifdef SBA_HINT_SUPPORT
+/* FIXME : DMA HINTs not used */
+ unsigned long hint_mask_pdir; /* bits used for DMA hints */
+ unsigned int hint_shift_pdir;
+#endif
+#if DELAYED_RESOURCE_CNT > 0
+ int saved_cnt;
+ struct sba_dma_pair {
+ dma_addr_t iova;
+ size_t size;
+ } saved[DELAYED_RESOURCE_CNT];
+#endif
+
+#ifdef SBA_COLLECT_STATS
+#define SBA_SEARCH_SAMPLE 0x100
+ unsigned long avg_search[SBA_SEARCH_SAMPLE];
+ unsigned long avg_idx; /* current index into avg_search */
+ unsigned long used_pages;
+ unsigned long msingle_calls;
+ unsigned long msingle_pages;
+ unsigned long msg_calls;
+ unsigned long msg_pages;
+ unsigned long usingle_calls;
+ unsigned long usingle_pages;
+ unsigned long usg_calls;
+ unsigned long usg_pages;
+#endif
+ /* STUFF We don't need in performance path */
+ unsigned int pdir_size; /* in bytes, determined by IOV Space size */
+};
+
+struct sba_device {
+ struct sba_device *next; /* list of SBA's in system */
+ struct parisc_device *dev; /* dev found in bus walk */
+ const char *name;
+ void __iomem *sba_hpa; /* base address */
+ spinlock_t sba_lock;
+ unsigned int flags; /* state/functionality enabled */
+ unsigned int hw_rev; /* HW revision of chip */
+
+ struct resource chip_resv; /* MMIO reserved for chip */
+ struct resource iommu_resv; /* MMIO reserved for iommu */
+
+ unsigned int num_ioc; /* number of on-board IOC's */
+ struct ioc ioc[MAX_IOC];
+};
+
+/* list of SBA's in system, see drivers/parisc/sba_iommu.c */
+extern struct sba_device *sba_list;
+
+#define ASTRO_RUNWAY_PORT 0x582
+#define IKE_MERCED_PORT 0x803
+#define REO_MERCED_PORT 0x804
+#define REOG_MERCED_PORT 0x805
+#define PLUTO_MCKINLEY_PORT 0x880
+
+static inline int IS_ASTRO(struct parisc_device *d) {
+ return d->id.hversion == ASTRO_RUNWAY_PORT;
+}
+
+static inline int IS_IKE(struct parisc_device *d) {
+ return d->id.hversion == IKE_MERCED_PORT;
+}
+
+static inline int IS_PLUTO(struct parisc_device *d) {
+ return d->id.hversion == PLUTO_MCKINLEY_PORT;
+}
+
+#define PLUTO_IOVA_BASE (1UL*1024*1024*1024) /* 1GB */
+#define PLUTO_IOVA_SIZE (1UL*1024*1024*1024) /* 1GB */
+#define PLUTO_GART_SIZE (PLUTO_IOVA_SIZE / 2)
+
+#define SBA_PDIR_VALID_BIT 0x8000000000000000ULL
+
+#define SBA_AGPGART_COOKIE (__force __le64) 0x0000badbadc0ffeeULL
+
+#define SBA_FUNC_ID 0x0000 /* function id */
+#define SBA_FCLASS 0x0008 /* function class, bist, header, rev... */
+
+#define SBA_FUNC_SIZE 4096 /* SBA configuration function reg set */
+
+#define ASTRO_IOC_OFFSET (32 * SBA_FUNC_SIZE)
+#define PLUTO_IOC_OFFSET (1 * SBA_FUNC_SIZE)
+/* Ike's IOC's occupy functions 2 and 3 */
+#define IKE_IOC_OFFSET(p) ((p+2) * SBA_FUNC_SIZE)
+
+#define IOC_CTRL 0x8 /* IOC_CTRL offset */
+#define IOC_CTRL_TC (1 << 0) /* TOC Enable */
+#define IOC_CTRL_CE (1 << 1) /* Coalesce Enable */
+#define IOC_CTRL_DE (1 << 2) /* Dillon Enable */
+#define IOC_CTRL_RM (1 << 8) /* Real Mode */
+#define IOC_CTRL_NC (1 << 9) /* Non Coherent Mode */
+#define IOC_CTRL_D4 (1 << 11) /* Disable 4-byte coalescing */
+#define IOC_CTRL_DD (1 << 13) /* Disable distr. LMMIO range coalescing */
+
+/*
+** Offsets into MBIB (Function 0 on Ike and hopefully Astro)
+** Firmware programs this stuff. Don't touch it.
+*/
+#define LMMIO_DIRECT0_BASE 0x300
+#define LMMIO_DIRECT0_MASK 0x308
+#define LMMIO_DIRECT0_ROUTE 0x310
+
+#define LMMIO_DIST_BASE 0x360
+#define LMMIO_DIST_MASK 0x368
+#define LMMIO_DIST_ROUTE 0x370
+
+#define IOS_DIST_BASE 0x390
+#define IOS_DIST_MASK 0x398
+#define IOS_DIST_ROUTE 0x3A0
+
+#define IOS_DIRECT_BASE 0x3C0
+#define IOS_DIRECT_MASK 0x3C8
+#define IOS_DIRECT_ROUTE 0x3D0
+
+/*
+** Offsets into I/O TLB (Function 2 and 3 on Ike)
+*/
+#define ROPE0_CTL 0x200 /* "regbus pci0" */
+#define ROPE1_CTL 0x208
+#define ROPE2_CTL 0x210
+#define ROPE3_CTL 0x218
+#define ROPE4_CTL 0x220
+#define ROPE5_CTL 0x228
+#define ROPE6_CTL 0x230
+#define ROPE7_CTL 0x238
+
+#define IOC_ROPE0_CFG 0x500 /* pluto only */
+#define IOC_ROPE_AO 0x10 /* Allow "Relaxed Ordering" */
+
+#define HF_ENABLE 0x40
+
+#define IOC_IBASE 0x300 /* IO TLB */
+#define IOC_IMASK 0x308
+#define IOC_PCOM 0x310
+#define IOC_TCNFG 0x318
+#define IOC_PDIR_BASE 0x320
+
+/*
+** IOC supports 4/8/16/64KB page sizes (see TCNFG register)
+** It's safer (avoid memory corruption) to keep DMA page mappings
+** equivalently sized to VM PAGE_SIZE.
+**
+** We really can't avoid generating a new mapping for each
+** page since the Virtual Coherence Index has to be generated
+** and updated for each page.
+**
+** PAGE_SIZE could be greater than IOVP_SIZE. But not the inverse.
+*/
+#define IOVP_SIZE PAGE_SIZE
+#define IOVP_SHIFT PAGE_SHIFT
+#define IOVP_MASK PAGE_MASK
+
+#define SBA_PERF_CFG 0x708 /* Performance Counter stuff */
+#define SBA_PERF_MASK1 0x718
+#define SBA_PERF_MASK2 0x730
+
+/*
+** Offsets into PCI Performance Counters (functions 12 and 13)
+** Controlled by PERF registers in function 2 & 3 respectively.
+*/
+#define SBA_PERF_CNT1 0x200
+#define SBA_PERF_CNT2 0x208
+#define SBA_PERF_CNT3 0x210
+
+/*
+** lba_device: Per instance Elroy data structure
+*/
+struct lba_device {
+ struct pci_hba_data hba;
+
+ spinlock_t lba_lock;
+ void *iosapic_obj;
+
+#ifdef CONFIG_64BIT
+ void __iomem *iop_base; /* PA_VIEW - for IO port accessor funcs */
+#endif
+
+ int flags; /* state/functionality enabled */
+ int hw_rev; /* HW revision of chip */
+};
+
+#define ELROY_HVERS 0x782
+#define MERCURY_HVERS 0x783
+#define QUICKSILVER_HVERS 0x784
+
+static inline int IS_ELROY(struct parisc_device *d) {
+ return (d->id.hversion == ELROY_HVERS);
+}
+
+static inline int IS_MERCURY(struct parisc_device *d) {
+ return (d->id.hversion == MERCURY_HVERS);
+}
+
+static inline int IS_QUICKSILVER(struct parisc_device *d) {
+ return (d->id.hversion == QUICKSILVER_HVERS);
+}
+
+static inline int agp_mode_mercury(void __iomem *hpa) {
+ u64 bus_mode;
+
+ bus_mode = readl(hpa + 0x0620);
+ if (bus_mode & 1)
+ return 1;
+
+ return 0;
+}
+
+/*
+** I/O SAPIC init function
+** Caller knows where an I/O SAPIC is. LBA has an integrated I/O SAPIC.
+** Call setup as part of per instance initialization.
+** (ie *not* init_module() function unless only one is present.)
+** fixup_irq is to initialize PCI IRQ line support and
+** virtualize pcidev->irq value. To be called by pci_fixup_bus().
+*/
+extern void *iosapic_register(unsigned long hpa, void __iomem *vaddr);
+extern int iosapic_fixup_irq(void *obj, struct pci_dev *pcidev);
+
+#define LBA_FUNC_ID 0x0000 /* function id */
+#define LBA_FCLASS 0x0008 /* function class, bist, header, rev... */
+#define LBA_CAPABLE 0x0030 /* capabilities register */
+
+#define LBA_PCI_CFG_ADDR 0x0040 /* poke CFG address here */
+#define LBA_PCI_CFG_DATA 0x0048 /* read or write data here */
+
+#define LBA_PMC_MTLT 0x0050 /* Firmware sets this - read only. */
+#define LBA_FW_SCRATCH 0x0058 /* Firmware writes the PCI bus number here. */
+#define LBA_ERROR_ADDR 0x0070 /* On error, address gets logged here */
+
+#define LBA_ARB_MASK 0x0080 /* bit 0 enable arbitration. PAT/PDC enables */
+#define LBA_ARB_PRI 0x0088 /* firmware sets this. */
+#define LBA_ARB_MODE 0x0090 /* firmware sets this. */
+#define LBA_ARB_MTLT 0x0098 /* firmware sets this. */
+
+#define LBA_MOD_ID 0x0100 /* Module ID. PDC_PAT_CELL reports 4 */
+
+#define LBA_STAT_CTL 0x0108 /* Status & Control */
+#define LBA_BUS_RESET 0x01 /* Deassert PCI Bus Reset Signal */
+#define CLEAR_ERRLOG 0x10 /* "Clear Error Log" cmd */
+#define CLEAR_ERRLOG_ENABLE 0x20 /* "Clear Error Log" Enable */
+#define HF_ENABLE 0x40 /* enable HF mode (default is -1 mode) */
+
+#define LBA_LMMIO_BASE 0x0200 /* < 4GB I/O address range */
+#define LBA_LMMIO_MASK 0x0208
+
+#define LBA_GMMIO_BASE 0x0210 /* > 4GB I/O address range */
+#define LBA_GMMIO_MASK 0x0218
+
+#define LBA_WLMMIO_BASE 0x0220 /* All < 4GB ranges under the same *SBA* */
+#define LBA_WLMMIO_MASK 0x0228
+
+#define LBA_WGMMIO_BASE 0x0230 /* All > 4GB ranges under the same *SBA* */
+#define LBA_WGMMIO_MASK 0x0238
+
+#define LBA_IOS_BASE 0x0240 /* I/O port space for this LBA */
+#define LBA_IOS_MASK 0x0248
+
+#define LBA_ELMMIO_BASE 0x0250 /* Extra LMMIO range */
+#define LBA_ELMMIO_MASK 0x0258
+
+#define LBA_EIOS_BASE 0x0260 /* Extra I/O port space */
+#define LBA_EIOS_MASK 0x0268
+
+#define LBA_GLOBAL_MASK 0x0270 /* Mercury only: Global Address Mask */
+#define LBA_DMA_CTL 0x0278 /* firmware sets this */
+
+#define LBA_IBASE 0x0300 /* SBA DMA support */
+#define LBA_IMASK 0x0308
+
+/* FIXME: ignore DMA Hint stuff until we can measure performance */
+#define LBA_HINT_CFG 0x0310
+#define LBA_HINT_BASE 0x0380 /* 14 registers at every 8 bytes. */
+
+#define LBA_BUS_MODE 0x0620
+
+/* ERROR regs are needed for config cycle kluges */
+#define LBA_ERROR_CONFIG 0x0680
+#define LBA_SMART_MODE 0x20
+#define LBA_ERROR_STATUS 0x0688
+#define LBA_ROPE_CTL 0x06A0
+
+#define LBA_IOSAPIC_BASE 0x800 /* Offset of IRQ logic */
+
+#endif /*_ASM_PARISC_ROPES_H_*/
diff --git a/arch/parisc/include/asm/rt_sigframe.h b/arch/parisc/include/asm/rt_sigframe.h
new file mode 100644
index 000000000..bb7fb4153
--- /dev/null
+++ b/arch/parisc/include/asm/rt_sigframe.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_PARISC_RT_SIGFRAME_H
+#define _ASM_PARISC_RT_SIGFRAME_H
+
+struct rt_sigframe {
+ unsigned int tramp[2]; /* holds original return address */
+ struct siginfo info;
+ struct ucontext uc;
+};
+
+#define SIGFRAME 128
+#define FUNCTIONCALLFRAME 96
+#define PARISC_RT_SIGFRAME_SIZE \
+ (((sizeof(struct rt_sigframe) + FUNCTIONCALLFRAME) + SIGFRAME) & -SIGFRAME)
+
+#endif
diff --git a/arch/parisc/include/asm/runway.h b/arch/parisc/include/asm/runway.h
new file mode 100644
index 000000000..2837f0223
--- /dev/null
+++ b/arch/parisc/include/asm/runway.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef ASM_PARISC_RUNWAY_H
+#define ASM_PARISC_RUNWAY_H
+
+#define RUNWAY_STATUS 0x10
+#define RUNWAY_DEBUG 0x40
+
+#endif /* ASM_PARISC_RUNWAY_H */
diff --git a/arch/parisc/include/asm/seccomp.h b/arch/parisc/include/asm/seccomp.h
new file mode 100644
index 000000000..b058b2220
--- /dev/null
+++ b/arch/parisc/include/asm/seccomp.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _ASM_SECCOMP_H
+#define _ASM_SECCOMP_H
+
+#include <asm-generic/seccomp.h>
+
+#ifdef CONFIG_64BIT
+# define SECCOMP_ARCH_NATIVE AUDIT_ARCH_PARISC64
+# define SECCOMP_ARCH_NATIVE_NR NR_syscalls
+# define SECCOMP_ARCH_NATIVE_NAME "parisc64"
+# ifdef CONFIG_COMPAT
+# define SECCOMP_ARCH_COMPAT AUDIT_ARCH_PARISC
+# define SECCOMP_ARCH_COMPAT_NR NR_syscalls
+# define SECCOMP_ARCH_COMPAT_NAME "parisc"
+# endif
+#else /* !CONFIG_64BIT */
+# define SECCOMP_ARCH_NATIVE AUDIT_ARCH_PARISC
+# define SECCOMP_ARCH_NATIVE_NR NR_syscalls
+# define SECCOMP_ARCH_NATIVE_NAME "parisc"
+#endif
+
+#endif /* _ASM_SECCOMP_H */
diff --git a/arch/parisc/include/asm/sections.h b/arch/parisc/include/asm/sections.h
new file mode 100644
index 000000000..33df42b5c
--- /dev/null
+++ b/arch/parisc/include/asm/sections.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _PARISC_SECTIONS_H
+#define _PARISC_SECTIONS_H
+
+#ifdef CONFIG_HAVE_FUNCTION_DESCRIPTORS
+#include <asm/elf.h>
+typedef Elf64_Fdesc func_desc_t;
+#endif
+
+/* nothing to see, move along */
+#include <asm-generic/sections.h>
+
+extern char __alt_instructions[], __alt_instructions_end[];
+
+#endif
diff --git a/arch/parisc/include/asm/serial.h b/arch/parisc/include/asm/serial.h
new file mode 100644
index 000000000..77e9b67c8
--- /dev/null
+++ b/arch/parisc/include/asm/serial.h
@@ -0,0 +1,8 @@
+/*
+ * include/asm-parisc/serial.h
+ */
+
+/*
+ * This is used for 16550-compatible UARTs
+ */
+#define BASE_BAUD ( 1843200 / 16 )
diff --git a/arch/parisc/include/asm/shmparam.h b/arch/parisc/include/asm/shmparam.h
new file mode 100644
index 000000000..5a95b0f62
--- /dev/null
+++ b/arch/parisc/include/asm/shmparam.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASMPARISC_SHMPARAM_H
+#define _ASMPARISC_SHMPARAM_H
+
+/*
+ * PA-RISC uses virtually indexed & physically tagged (VIPT) caches
+ * which has strict requirements when two pages to the same physical
+ * address are accessed through different mappings. Read the section
+ * "Address Aliasing" in the arch docs for more detail:
+ * PA-RISC 1.1 (page 3-6):
+ * https://parisc.wiki.kernel.org/images-parisc/6/68/Pa11_acd.pdf
+ * PA-RISC 2.0 (page F-5):
+ * https://parisc.wiki.kernel.org/images-parisc/7/73/Parisc2.0.pdf
+ *
+ * For Linux we allow kernel and userspace to map pages on page size
+ * granularity (SHMLBA) but have to ensure that, if two pages are
+ * mapped to the same physical address, the virtual and physical
+ * addresses modulo SHM_COLOUR are identical.
+ */
+#define SHMLBA PAGE_SIZE /* attach addr a multiple of this */
+#define SHM_COLOUR 0x00400000 /* shared mappings colouring */
+
+#endif /* _ASMPARISC_SHMPARAM_H */
diff --git a/arch/parisc/include/asm/signal.h b/arch/parisc/include/asm/signal.h
new file mode 100644
index 000000000..715c96ba2
--- /dev/null
+++ b/arch/parisc/include/asm/signal.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_PARISC_SIGNAL_H
+#define _ASM_PARISC_SIGNAL_H
+
+#include <uapi/asm/signal.h>
+
+#define _NSIG 64
+/* bits-per-word, where word apparently means 'long' not 'int' */
+#define _NSIG_BPW BITS_PER_LONG
+#define _NSIG_WORDS (_NSIG / _NSIG_BPW)
+
+# ifndef __ASSEMBLY__
+
+/* Most things should be clean enough to redefine this at will, if care
+ is taken to make libc match. */
+
+typedef unsigned long old_sigset_t; /* at least 32 bits */
+
+typedef struct {
+ /* next_signal() assumes this is a long - no choice */
+ unsigned long sig[_NSIG_WORDS];
+} sigset_t;
+
+#include <asm/sigcontext.h>
+
+#endif /* !__ASSEMBLY */
+#endif /* _ASM_PARISC_SIGNAL_H */
diff --git a/arch/parisc/include/asm/smp.h b/arch/parisc/include/asm/smp.h
new file mode 100644
index 000000000..94d1f21ce
--- /dev/null
+++ b/arch/parisc/include/asm/smp.h
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_SMP_H
+#define __ASM_SMP_H
+
+extern int init_per_cpu(int cpuid);
+
+#if defined(CONFIG_SMP)
+
+/* Page Zero Location PDC will look for the address to branch to when we poke
+** slave CPUs still in "Icache loop".
+*/
+#define PDC_OS_BOOT_RENDEZVOUS 0x10
+#define PDC_OS_BOOT_RENDEZVOUS_HI 0x28
+
+#ifndef ASSEMBLY
+#include <linux/bitops.h>
+#include <linux/threads.h> /* for NR_CPUS */
+#include <linux/cpumask.h>
+typedef unsigned long address_t;
+
+
+/*
+ * Private routines/data
+ *
+ * physical and logical are equivalent until we support CPU hotplug.
+ */
+#define cpu_number_map(cpu) (cpu)
+#define cpu_logical_map(cpu) (cpu)
+
+extern void smp_send_all_nop(void);
+
+extern void arch_send_call_function_single_ipi(int cpu);
+extern void arch_send_call_function_ipi_mask(const struct cpumask *mask);
+
+#define raw_smp_processor_id() (current_thread_info()->cpu)
+
+#endif /* !ASSEMBLY */
+
+#else /* CONFIG_SMP */
+
+static inline void smp_send_all_nop(void) { return; }
+
+#endif
+
+#define NO_PROC_ID 0xFF /* No processor magic marker */
+#define ANY_PROC_ID 0xFF /* Any processor magic marker */
+int __cpu_disable(void);
+void __cpu_die(unsigned int cpu);
+
+#endif /* __ASM_SMP_H */
diff --git a/arch/parisc/include/asm/socket.h b/arch/parisc/include/asm/socket.h
new file mode 100644
index 000000000..33500c9f6
--- /dev/null
+++ b/arch/parisc/include/asm/socket.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_SOCKET_H
+#define _ASM_SOCKET_H
+
+#include <uapi/asm/socket.h>
+
+/* O_NONBLOCK clashed with the bits used for socket types. Therefore we
+ * had to define SOCK_NONBLOCK to a different value here.
+ */
+#define SOCK_NONBLOCK 0x40000000
+
+#endif /* _ASM_SOCKET_H */
diff --git a/arch/parisc/include/asm/sparsemem.h b/arch/parisc/include/asm/sparsemem.h
new file mode 100644
index 000000000..b5c3a7904
--- /dev/null
+++ b/arch/parisc/include/asm/sparsemem.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef ASM_PARISC_SPARSEMEM_H
+#define ASM_PARISC_SPARSEMEM_H
+
+/* We have these possible memory map layouts:
+ * Astro: 0-3.75, 67.75-68, 4-64
+ * zx1: 0-1, 257-260, 4-256
+ * Stretch (N-class): 0-2, 4-32, 34-xxx
+ */
+
+#define MAX_PHYSMEM_BITS 39 /* 512 GB */
+#define SECTION_SIZE_BITS 27 /* 128 MB */
+
+#endif
diff --git a/arch/parisc/include/asm/special_insns.h b/arch/parisc/include/asm/special_insns.h
new file mode 100644
index 000000000..c822bd0c0
--- /dev/null
+++ b/arch/parisc/include/asm/special_insns.h
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __PARISC_SPECIAL_INSNS_H
+#define __PARISC_SPECIAL_INSNS_H
+
+#define lpa(va) ({ \
+ unsigned long pa; \
+ __asm__ __volatile__( \
+ "copy %%r0,%0\n" \
+ "8:\tlpa %%r0(%1),%0\n" \
+ "9:\n" \
+ ASM_EXCEPTIONTABLE_ENTRY(8b, 9b) \
+ : "=&r" (pa) \
+ : "r" (va) \
+ : "memory" \
+ ); \
+ pa; \
+})
+
+#define lpa_user(va) ({ \
+ unsigned long pa; \
+ __asm__ __volatile__( \
+ "copy %%r0,%0\n" \
+ "8:\tlpa %%r0(%%sr3,%1),%0\n" \
+ "9:\n" \
+ ASM_EXCEPTIONTABLE_ENTRY(8b, 9b) \
+ : "=&r" (pa) \
+ : "r" (va) \
+ : "memory" \
+ ); \
+ pa; \
+})
+
+#define CR_EIEM 15 /* External Interrupt Enable Mask */
+#define CR_CR16 16 /* CR16 Interval Timer */
+#define CR_EIRR 23 /* External Interrupt Request Register */
+
+#define mfctl(reg) ({ \
+ unsigned long cr; \
+ __asm__ __volatile__( \
+ "mfctl %1,%0" : \
+ "=r" (cr) : "i" (reg) \
+ ); \
+ cr; \
+})
+
+#define mtctl(gr, cr) \
+ __asm__ __volatile__("mtctl %0,%1" \
+ : /* no outputs */ \
+ : "r" (gr), "i" (cr) : "memory")
+
+#define get_eiem() mfctl(CR_EIEM)
+#define set_eiem(val) mtctl(val, CR_EIEM)
+
+#define mfsp(reg) ({ \
+ unsigned long cr; \
+ __asm__ __volatile__( \
+ "mfsp %%sr%1,%0" \
+ : "=r" (cr) : "i"(reg) \
+ ); \
+ cr; \
+})
+
+#define mtsp(val, cr) \
+ { if (__builtin_constant_p(val) && ((val) == 0)) \
+ __asm__ __volatile__("mtsp %%r0,%0" : : "i" (cr) : "memory"); \
+ else \
+ __asm__ __volatile__("mtsp %0,%1" \
+ : /* no outputs */ \
+ : "r" (val), "i" (cr) : "memory"); }
+
+#endif /* __PARISC_SPECIAL_INSNS_H */
diff --git a/arch/parisc/include/asm/spinlock.h b/arch/parisc/include/asm/spinlock.h
new file mode 100644
index 000000000..0b326e522
--- /dev/null
+++ b/arch/parisc/include/asm/spinlock.h
@@ -0,0 +1,161 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_SPINLOCK_H
+#define __ASM_SPINLOCK_H
+
+#include <asm/barrier.h>
+#include <asm/ldcw.h>
+#include <asm/processor.h>
+#include <asm/spinlock_types.h>
+
+static inline void arch_spin_val_check(int lock_val)
+{
+ if (IS_ENABLED(CONFIG_LIGHTWEIGHT_SPINLOCK_CHECK))
+ asm volatile( "andcm,= %0,%1,%%r0\n"
+ ".word %2\n"
+ : : "r" (lock_val), "r" (__ARCH_SPIN_LOCK_UNLOCKED_VAL),
+ "i" (SPINLOCK_BREAK_INSN));
+}
+
+static inline int arch_spin_is_locked(arch_spinlock_t *x)
+{
+ volatile unsigned int *a;
+ int lock_val;
+
+ a = __ldcw_align(x);
+ lock_val = READ_ONCE(*a);
+ arch_spin_val_check(lock_val);
+ return (lock_val == 0);
+}
+
+static inline void arch_spin_lock(arch_spinlock_t *x)
+{
+ volatile unsigned int *a;
+
+ a = __ldcw_align(x);
+ do {
+ int lock_val_old;
+
+ lock_val_old = __ldcw(a);
+ arch_spin_val_check(lock_val_old);
+ if (lock_val_old)
+ return; /* got lock */
+
+ /* wait until we should try to get lock again */
+ while (*a == 0)
+ continue;
+ } while (1);
+}
+
+static inline void arch_spin_unlock(arch_spinlock_t *x)
+{
+ volatile unsigned int *a;
+
+ a = __ldcw_align(x);
+ /* Release with ordered store. */
+ __asm__ __volatile__("stw,ma %0,0(%1)"
+ : : "r"(__ARCH_SPIN_LOCK_UNLOCKED_VAL), "r"(a) : "memory");
+}
+
+static inline int arch_spin_trylock(arch_spinlock_t *x)
+{
+ volatile unsigned int *a;
+ int lock_val;
+
+ a = __ldcw_align(x);
+ lock_val = __ldcw(a);
+ arch_spin_val_check(lock_val);
+ return lock_val != 0;
+}
+
+/*
+ * Read-write spinlocks, allowing multiple readers but only one writer.
+ * Unfair locking as Writers could be starved indefinitely by Reader(s)
+ *
+ * The spinlock itself is contained in @counter and access to it is
+ * serialized with @lock_mutex.
+ */
+
+/* 1 - lock taken successfully */
+static inline int arch_read_trylock(arch_rwlock_t *rw)
+{
+ int ret = 0;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ arch_spin_lock(&(rw->lock_mutex));
+
+ /*
+ * zero means writer holds the lock exclusively, deny Reader.
+ * Otherwise grant lock to first/subseq reader
+ */
+ if (rw->counter > 0) {
+ rw->counter--;
+ ret = 1;
+ }
+
+ arch_spin_unlock(&(rw->lock_mutex));
+ local_irq_restore(flags);
+
+ return ret;
+}
+
+/* 1 - lock taken successfully */
+static inline int arch_write_trylock(arch_rwlock_t *rw)
+{
+ int ret = 0;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ arch_spin_lock(&(rw->lock_mutex));
+
+ /*
+ * If reader(s) hold lock (lock < __ARCH_RW_LOCK_UNLOCKED__),
+ * deny writer. Otherwise if unlocked grant to writer
+ * Hence the claim that Linux rwlocks are unfair to writers.
+ * (can be starved for an indefinite time by readers).
+ */
+ if (rw->counter == __ARCH_RW_LOCK_UNLOCKED__) {
+ rw->counter = 0;
+ ret = 1;
+ }
+ arch_spin_unlock(&(rw->lock_mutex));
+ local_irq_restore(flags);
+
+ return ret;
+}
+
+static inline void arch_read_lock(arch_rwlock_t *rw)
+{
+ while (!arch_read_trylock(rw))
+ cpu_relax();
+}
+
+static inline void arch_write_lock(arch_rwlock_t *rw)
+{
+ while (!arch_write_trylock(rw))
+ cpu_relax();
+}
+
+static inline void arch_read_unlock(arch_rwlock_t *rw)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ arch_spin_lock(&(rw->lock_mutex));
+ rw->counter++;
+ arch_spin_unlock(&(rw->lock_mutex));
+ local_irq_restore(flags);
+}
+
+static inline void arch_write_unlock(arch_rwlock_t *rw)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ arch_spin_lock(&(rw->lock_mutex));
+ rw->counter = __ARCH_RW_LOCK_UNLOCKED__;
+ arch_spin_unlock(&(rw->lock_mutex));
+ local_irq_restore(flags);
+}
+
+#endif /* __ASM_SPINLOCK_H */
diff --git a/arch/parisc/include/asm/spinlock_types.h b/arch/parisc/include/asm/spinlock_types.h
new file mode 100644
index 000000000..7b986b09d
--- /dev/null
+++ b/arch/parisc/include/asm/spinlock_types.h
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_SPINLOCK_TYPES_H
+#define __ASM_SPINLOCK_TYPES_H
+
+#define __ARCH_SPIN_LOCK_UNLOCKED_VAL 0x1a46
+
+#define SPINLOCK_BREAK_INSN 0x0000c006 /* break 6,6 */
+
+#ifndef __ASSEMBLY__
+
+typedef struct {
+ volatile unsigned int lock[4];
+# define __ARCH_SPIN_LOCK_UNLOCKED \
+ { { __ARCH_SPIN_LOCK_UNLOCKED_VAL, __ARCH_SPIN_LOCK_UNLOCKED_VAL, \
+ __ARCH_SPIN_LOCK_UNLOCKED_VAL, __ARCH_SPIN_LOCK_UNLOCKED_VAL } }
+} arch_spinlock_t;
+
+
+/* counter:
+ * Unlocked : 0x0100_0000
+ * Read lock(s) : 0x00FF_FFFF to 0x01 (Multiple Readers decrement it)
+ * Write lock : 0x0, but only if prior value is "unlocked" 0x0100_0000
+ */
+typedef struct {
+ arch_spinlock_t lock_mutex;
+ volatile unsigned int counter;
+} arch_rwlock_t;
+
+#endif /* __ASSEMBLY__ */
+
+#define __ARCH_RW_LOCK_UNLOCKED__ 0x01000000
+#define __ARCH_RW_LOCK_UNLOCKED { .lock_mutex = __ARCH_SPIN_LOCK_UNLOCKED, \
+ .counter = __ARCH_RW_LOCK_UNLOCKED__ }
+
+#endif
diff --git a/arch/parisc/include/asm/string.h b/arch/parisc/include/asm/string.h
new file mode 100644
index 000000000..f6e1132f4
--- /dev/null
+++ b/arch/parisc/include/asm/string.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _PA_STRING_H_
+#define _PA_STRING_H_
+
+#define __HAVE_ARCH_MEMSET
+extern void * memset(void *, int, size_t);
+
+#define __HAVE_ARCH_MEMCPY
+void * memcpy(void * dest,const void *src,size_t count);
+
+#endif
diff --git a/arch/parisc/include/asm/superio.h b/arch/parisc/include/asm/superio.h
new file mode 100644
index 000000000..5e11c11d4
--- /dev/null
+++ b/arch/parisc/include/asm/superio.h
@@ -0,0 +1,86 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _PARISC_SUPERIO_H
+#define _PARISC_SUPERIO_H
+
+#define IC_PIC1 0x20 /* PCI I/O address of master 8259 */
+#define IC_PIC2 0xA0 /* PCI I/O address of slave */
+
+/* Config Space Offsets to configuration and base address registers */
+#define SIO_CR 0x5A /* Configuration Register */
+#define SIO_ACPIBAR 0x88 /* ACPI BAR */
+#define SIO_FDCBAR 0x90 /* Floppy Disk Controller BAR */
+#define SIO_SP1BAR 0x94 /* Serial 1 BAR */
+#define SIO_SP2BAR 0x98 /* Serial 2 BAR */
+#define SIO_PPBAR 0x9C /* Parallel BAR */
+
+#define TRIGGER_1 0x67 /* Edge/level trigger register 1 */
+#define TRIGGER_2 0x68 /* Edge/level trigger register 2 */
+
+/* Interrupt Routing Control registers */
+#define CFG_IR_SER 0x69 /* Serial 1 [0:3] and Serial 2 [4:7] */
+#define CFG_IR_PFD 0x6a /* Parallel [0:3] and Floppy [4:7] */
+#define CFG_IR_IDE 0x6b /* IDE1 [0:3] and IDE2 [4:7] */
+#define CFG_IR_INTAB 0x6c /* PCI INTA [0:3] and INT B [4:7] */
+#define CFG_IR_INTCD 0x6d /* PCI INTC [0:3] and INT D [4:7] */
+#define CFG_IR_PS2 0x6e /* PS/2 KBINT [0:3] and Mouse [4:7] */
+#define CFG_IR_FXBUS 0x6f /* FXIRQ[0] [0:3] and FXIRQ[1] [4:7] */
+#define CFG_IR_USB 0x70 /* FXIRQ[2] [0:3] and USB [4:7] */
+#define CFG_IR_ACPI 0x71 /* ACPI SCI [0:3] and reserved [4:7] */
+
+#define CFG_IR_LOW CFG_IR_SER /* Lowest interrupt routing reg */
+#define CFG_IR_HIGH CFG_IR_ACPI /* Highest interrupt routing reg */
+
+/* 8259 operational control words */
+#define OCW2_EOI 0x20 /* Non-specific EOI */
+#define OCW2_SEOI 0x60 /* Specific EOI */
+#define OCW3_IIR 0x0A /* Read request register */
+#define OCW3_ISR 0x0B /* Read service register */
+#define OCW3_POLL 0x0C /* Poll the PIC for an interrupt vector */
+
+/* Interrupt lines. Only PIC1 is used */
+#define USB_IRQ 1 /* USB */
+#define SP1_IRQ 3 /* Serial port 1 */
+#define SP2_IRQ 4 /* Serial port 2 */
+#define PAR_IRQ 5 /* Parallel port */
+#define FDC_IRQ 6 /* Floppy controller */
+#define IDE_IRQ 7 /* IDE (pri+sec) */
+
+/* ACPI registers */
+#define USB_REG_CR 0x1f /* USB Regulator Control Register */
+
+#define SUPERIO_NIRQS 8
+
+struct superio_device {
+ u32 fdc_base;
+ u32 sp1_base;
+ u32 sp2_base;
+ u32 pp_base;
+ u32 acpi_base;
+ int suckyio_irq_enabled;
+ struct pci_dev *lio_pdev; /* pci device for legacy IO (fn 1) */
+ struct pci_dev *usb_pdev; /* pci device for USB (fn 2) */
+};
+
+/*
+ * Does NS make a 87415 based plug in PCI card? If so, because of this
+ * macro we currently don't support it being plugged into a machine
+ * that contains a SuperIO chip AND has CONFIG_SUPERIO enabled.
+ *
+ * This could be fixed by checking to see if function 1 exists, and
+ * if it is SuperIO Legacy IO; but really now, is this combination
+ * going to EVER happen?
+ */
+
+#define SUPERIO_IDE_FN 0 /* Function number of IDE controller */
+#define SUPERIO_LIO_FN 1 /* Function number of Legacy IO controller */
+#define SUPERIO_USB_FN 2 /* Function number of USB controller */
+
+#define is_superio_device(x) \
+ (((x)->vendor == PCI_VENDOR_ID_NS) && \
+ ( ((x)->device == PCI_DEVICE_ID_NS_87415) \
+ || ((x)->device == PCI_DEVICE_ID_NS_87560_LIO) \
+ || ((x)->device == PCI_DEVICE_ID_NS_87560_USB) ) )
+
+extern int superio_fixup_irq(struct pci_dev *pcidev); /* called by iosapic */
+
+#endif /* _PARISC_SUPERIO_H */
diff --git a/arch/parisc/include/asm/switch_to.h b/arch/parisc/include/asm/switch_to.h
new file mode 100644
index 000000000..f2ac9cc0d
--- /dev/null
+++ b/arch/parisc/include/asm/switch_to.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __PARISC_SWITCH_TO_H
+#define __PARISC_SWITCH_TO_H
+
+struct task_struct;
+
+extern struct task_struct *_switch_to(struct task_struct *, struct task_struct *);
+
+#define switch_to(prev, next, last) do { \
+ (last) = _switch_to(prev, next); \
+} while(0)
+
+#endif /* __PARISC_SWITCH_TO_H */
diff --git a/arch/parisc/include/asm/syscall.h b/arch/parisc/include/asm/syscall.h
new file mode 100644
index 000000000..00b127a5e
--- /dev/null
+++ b/arch/parisc/include/asm/syscall.h
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* syscall.h */
+
+#ifndef _ASM_PARISC_SYSCALL_H_
+#define _ASM_PARISC_SYSCALL_H_
+
+#include <uapi/linux/audit.h>
+#include <linux/compat.h>
+#include <linux/err.h>
+#include <asm/ptrace.h>
+
+#define NR_syscalls (__NR_Linux_syscalls)
+
+static inline long syscall_get_nr(struct task_struct *tsk,
+ struct pt_regs *regs)
+{
+ return regs->gr[20];
+}
+
+static inline void syscall_get_arguments(struct task_struct *tsk,
+ struct pt_regs *regs,
+ unsigned long *args)
+{
+ args[5] = regs->gr[21];
+ args[4] = regs->gr[22];
+ args[3] = regs->gr[23];
+ args[2] = regs->gr[24];
+ args[1] = regs->gr[25];
+ args[0] = regs->gr[26];
+}
+
+static inline long syscall_get_error(struct task_struct *task,
+ struct pt_regs *regs)
+{
+ unsigned long error = regs->gr[28];
+ return IS_ERR_VALUE(error) ? error : 0;
+}
+
+static inline long syscall_get_return_value(struct task_struct *task,
+ struct pt_regs *regs)
+{
+ return regs->gr[28];
+}
+
+static inline void syscall_set_return_value(struct task_struct *task,
+ struct pt_regs *regs,
+ int error, long val)
+{
+ regs->gr[28] = error ? error : val;
+}
+
+static inline void syscall_rollback(struct task_struct *task,
+ struct pt_regs *regs)
+{
+ /* do nothing */
+}
+
+static inline int syscall_get_arch(struct task_struct *task)
+{
+ int arch = AUDIT_ARCH_PARISC;
+#ifdef CONFIG_64BIT
+ if (!__is_compat_task(task))
+ arch = AUDIT_ARCH_PARISC64;
+#endif
+ return arch;
+}
+#endif /*_ASM_PARISC_SYSCALL_H_*/
diff --git a/arch/parisc/include/asm/thread_info.h b/arch/parisc/include/asm/thread_info.h
new file mode 100644
index 000000000..1a58795f7
--- /dev/null
+++ b/arch/parisc/include/asm/thread_info.h
@@ -0,0 +1,85 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_PARISC_THREAD_INFO_H
+#define _ASM_PARISC_THREAD_INFO_H
+
+#ifndef __ASSEMBLY__
+#include <asm/processor.h>
+#include <asm/special_insns.h>
+
+struct thread_info {
+ unsigned long flags; /* thread_info flags (see TIF_*) */
+ int preempt_count; /* 0=premptable, <0=BUG; will also serve as bh-counter */
+#ifdef CONFIG_SMP
+ unsigned int cpu;
+#endif
+};
+
+#define INIT_THREAD_INFO(tsk) \
+{ \
+ .flags = 0, \
+ .preempt_count = INIT_PREEMPT_COUNT, \
+}
+
+#endif /* !__ASSEMBLY */
+
+/* thread information allocation */
+
+#ifdef CONFIG_IRQSTACKS
+#define THREAD_SIZE_ORDER 2 /* PA-RISC requires at least 16k stack */
+#else
+#define THREAD_SIZE_ORDER 3 /* PA-RISC requires at least 32k stack */
+#endif
+
+/* Be sure to hunt all references to this down when you change the size of
+ * the kernel stack */
+#define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER)
+#define THREAD_SHIFT (PAGE_SHIFT + THREAD_SIZE_ORDER)
+
+/*
+ * thread information flags
+ */
+#define TIF_SYSCALL_TRACE 0 /* syscall trace active */
+#define TIF_SIGPENDING 1 /* signal pending */
+#define TIF_NEED_RESCHED 2 /* rescheduling necessary */
+#define TIF_POLLING_NRFLAG 3 /* true if poll_idle() is polling TIF_NEED_RESCHED */
+#define TIF_32BIT 4 /* 32 bit binary */
+#define TIF_MEMDIE 5 /* is terminating due to OOM killer */
+#define TIF_NOTIFY_SIGNAL 6 /* signal notifications exist */
+#define TIF_SYSCALL_AUDIT 7 /* syscall auditing active */
+#define TIF_NOTIFY_RESUME 8 /* callback before returning to user */
+#define TIF_SINGLESTEP 9 /* single stepping? */
+#define TIF_BLOCKSTEP 10 /* branch stepping? */
+#define TIF_SECCOMP 11 /* secure computing */
+#define TIF_SYSCALL_TRACEPOINT 12 /* syscall tracepoint instrumentation */
+#define TIF_NONBLOCK_WARNING 13 /* warned about wrong O_NONBLOCK usage */
+
+#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
+#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
+#define _TIF_NOTIFY_SIGNAL (1 << TIF_NOTIFY_SIGNAL)
+#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
+#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG)
+#define _TIF_32BIT (1 << TIF_32BIT)
+#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
+#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
+#define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP)
+#define _TIF_BLOCKSTEP (1 << TIF_BLOCKSTEP)
+#define _TIF_SECCOMP (1 << TIF_SECCOMP)
+#define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT)
+
+#define _TIF_USER_WORK_MASK (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | \
+ _TIF_NEED_RESCHED | _TIF_NOTIFY_SIGNAL)
+#define _TIF_SYSCALL_TRACE_MASK (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP | \
+ _TIF_BLOCKSTEP | _TIF_SYSCALL_AUDIT | \
+ _TIF_SECCOMP | _TIF_SYSCALL_TRACEPOINT)
+
+#ifdef CONFIG_64BIT
+# ifdef CONFIG_COMPAT
+# define is_32bit_task() (test_thread_flag(TIF_32BIT))
+# else
+# define is_32bit_task() (0)
+# endif
+#else
+# define is_32bit_task() (1)
+#endif
+
+#endif /* _ASM_PARISC_THREAD_INFO_H */
diff --git a/arch/parisc/include/asm/timex.h b/arch/parisc/include/asm/timex.h
new file mode 100644
index 000000000..b4622cb06
--- /dev/null
+++ b/arch/parisc/include/asm/timex.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * linux/include/asm-parisc/timex.h
+ *
+ * PARISC architecture timex specifications
+ */
+#ifndef _ASMPARISC_TIMEX_H
+#define _ASMPARISC_TIMEX_H
+
+#include <asm/special_insns.h>
+
+#define CLOCK_TICK_RATE 1193180 /* Underlying HZ */
+
+typedef unsigned long cycles_t;
+
+static inline cycles_t get_cycles(void)
+{
+ return mfctl(16);
+}
+#define get_cycles get_cycles
+
+#endif
diff --git a/arch/parisc/include/asm/tlb.h b/arch/parisc/include/asm/tlb.h
new file mode 100644
index 000000000..44235f367
--- /dev/null
+++ b/arch/parisc/include/asm/tlb.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _PARISC_TLB_H
+#define _PARISC_TLB_H
+
+#include <asm-generic/tlb.h>
+
+#if CONFIG_PGTABLE_LEVELS == 3
+#define __pmd_free_tlb(tlb, pmd, addr) pmd_free((tlb)->mm, pmd)
+#endif
+#define __pte_free_tlb(tlb, pte, addr) pte_free((tlb)->mm, pte)
+
+#endif
diff --git a/arch/parisc/include/asm/tlbflush.h b/arch/parisc/include/asm/tlbflush.h
new file mode 100644
index 000000000..5ffd7c17f
--- /dev/null
+++ b/arch/parisc/include/asm/tlbflush.h
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _PARISC_TLBFLUSH_H
+#define _PARISC_TLBFLUSH_H
+
+/* TLB flushing routines.... */
+
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <asm/mmu_context.h>
+
+extern void flush_tlb_all(void);
+extern void flush_tlb_all_local(void *);
+
+#define smp_flush_tlb_all() flush_tlb_all()
+
+int __flush_tlb_range(unsigned long sid,
+ unsigned long start, unsigned long end);
+
+#define flush_tlb_range(vma, start, end) \
+ __flush_tlb_range((vma)->vm_mm->context.space_id, start, end)
+
+#define flush_tlb_kernel_range(start, end) \
+ __flush_tlb_range(0, start, end)
+
+/*
+ * flush_tlb_mm()
+ *
+ * The code to switch to a new context is NOT valid for processes
+ * which play with the space id's. Thus, we have to preserve the
+ * space and just flush the entire tlb. However, the compilers,
+ * dynamic linker, etc, do not manipulate space id's, so there
+ * could be a significant performance benefit in switching contexts
+ * and not flushing the whole tlb.
+ */
+
+static inline void flush_tlb_mm(struct mm_struct *mm)
+{
+ BUG_ON(mm == &init_mm); /* Should never happen */
+
+#if 1 || defined(CONFIG_SMP)
+ /* Except for very small threads, flushing the whole TLB is
+ * faster than using __flush_tlb_range. The pdtlb and pitlb
+ * instructions are very slow because of the TLB broadcast.
+ * It might be faster to do local range flushes on all CPUs
+ * on PA 2.0 systems.
+ */
+ flush_tlb_all();
+#else
+ /* FIXME: currently broken, causing space id and protection ids
+ * to go out of sync, resulting in faults on userspace accesses.
+ * This approach needs further investigation since running many
+ * small applications (e.g., GCC testsuite) is faster on HP-UX.
+ */
+ if (mm) {
+ if (mm->context != 0)
+ free_sid(mm->context);
+ mm->context = alloc_sid();
+ if (mm == current->active_mm)
+ load_context(mm->context);
+ }
+#endif
+}
+
+static inline void flush_tlb_page(struct vm_area_struct *vma,
+ unsigned long addr)
+{
+ purge_tlb_entries(vma->vm_mm, addr);
+}
+#endif
diff --git a/arch/parisc/include/asm/topology.h b/arch/parisc/include/asm/topology.h
new file mode 100644
index 000000000..406afb356
--- /dev/null
+++ b/arch/parisc/include/asm/topology.h
@@ -0,0 +1,19 @@
+#ifndef _ASM_PARISC_TOPOLOGY_H
+#define _ASM_PARISC_TOPOLOGY_H
+
+#ifdef CONFIG_GENERIC_ARCH_TOPOLOGY
+
+#include <linux/cpumask.h>
+#include <linux/arch_topology.h>
+
+#else
+
+static inline void init_cpu_topology(void) { }
+static inline void store_cpu_topology(unsigned int cpuid) { }
+static inline void reset_cpu_topology(void) { }
+
+#endif
+
+#include <asm-generic/topology.h>
+
+#endif /* _ASM_ARM_TOPOLOGY_H */
diff --git a/arch/parisc/include/asm/traps.h b/arch/parisc/include/asm/traps.h
new file mode 100644
index 000000000..0ccdb738a
--- /dev/null
+++ b/arch/parisc/include/asm/traps.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __ASM_TRAPS_H
+#define __ASM_TRAPS_H
+
+#define PARISC_ITLB_TRAP 6 /* defined by architecture. Do not change. */
+
+#if !defined(__ASSEMBLY__)
+struct pt_regs;
+
+/* traps.c */
+void parisc_terminate(char *msg, struct pt_regs *regs,
+ int code, unsigned long offset) __noreturn __cold;
+
+void die_if_kernel(char *str, struct pt_regs *regs, long err);
+
+/* mm/fault.c */
+unsigned long parisc_acctyp(unsigned long code, unsigned int inst);
+const char *trap_name(unsigned long code);
+void do_page_fault(struct pt_regs *regs, unsigned long code,
+ unsigned long address);
+int handle_nadtlb_fault(struct pt_regs *regs);
+#endif
+
+#endif
diff --git a/arch/parisc/include/asm/uaccess.h b/arch/parisc/include/asm/uaccess.h
new file mode 100644
index 000000000..416507989
--- /dev/null
+++ b/arch/parisc/include/asm/uaccess.h
@@ -0,0 +1,222 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __PARISC_UACCESS_H
+#define __PARISC_UACCESS_H
+
+/*
+ * User space memory access functions
+ */
+#include <asm/page.h>
+#include <asm/cache.h>
+
+#include <linux/bug.h>
+#include <linux/string.h>
+
+#define TASK_SIZE_MAX DEFAULT_TASK_SIZE
+#include <asm/pgtable.h>
+#include <asm-generic/access_ok.h>
+
+#define put_user __put_user
+#define get_user __get_user
+
+#if !defined(CONFIG_64BIT)
+#define LDD_USER(sr, val, ptr) __get_user_asm64(sr, val, ptr)
+#define STD_USER(sr, x, ptr) __put_user_asm64(sr, x, ptr)
+#else
+#define LDD_USER(sr, val, ptr) __get_user_asm(sr, val, "ldd", ptr)
+#define STD_USER(sr, x, ptr) __put_user_asm(sr, "std", x, ptr)
+#endif
+
+/*
+ * The exception table contains two values: the first is the relative offset to
+ * the address of the instruction that is allowed to fault, and the second is
+ * the relative offset to the address of the fixup routine. Since relative
+ * addresses are used, 32bit values are sufficient even on 64bit kernel.
+ */
+
+#define ARCH_HAS_RELATIVE_EXTABLE
+struct exception_table_entry {
+ int insn; /* relative address of insn that is allowed to fault. */
+ int fixup; /* relative address of fixup routine */
+};
+
+#define ASM_EXCEPTIONTABLE_ENTRY( fault_addr, except_addr )\
+ ".section __ex_table,\"aw\"\n" \
+ ".align 4\n" \
+ ".word (" #fault_addr " - .), (" #except_addr " - .)\n\t" \
+ ".previous\n"
+
+/*
+ * ASM_EXCEPTIONTABLE_ENTRY_EFAULT() creates a special exception table entry
+ * (with lowest bit set) for which the fault handler in fixup_exception() will
+ * load -EFAULT into %r29 for a read or write fault, and zeroes the target
+ * register in case of a read fault in get_user().
+ */
+#define ASM_EXCEPTIONTABLE_REG 29
+#define ASM_EXCEPTIONTABLE_VAR(__variable) \
+ register long __variable __asm__ ("r29") = 0
+#define ASM_EXCEPTIONTABLE_ENTRY_EFAULT( fault_addr, except_addr )\
+ ASM_EXCEPTIONTABLE_ENTRY( fault_addr, except_addr + 1)
+
+#define __get_user_internal(sr, val, ptr) \
+({ \
+ ASM_EXCEPTIONTABLE_VAR(__gu_err); \
+ \
+ switch (sizeof(*(ptr))) { \
+ case 1: __get_user_asm(sr, val, "ldb", ptr); break; \
+ case 2: __get_user_asm(sr, val, "ldh", ptr); break; \
+ case 4: __get_user_asm(sr, val, "ldw", ptr); break; \
+ case 8: LDD_USER(sr, val, ptr); break; \
+ default: BUILD_BUG(); \
+ } \
+ \
+ __gu_err; \
+})
+
+#define __get_user(val, ptr) \
+({ \
+ __get_user_internal(SR_USER, val, ptr); \
+})
+
+#define __get_user_asm(sr, val, ldx, ptr) \
+{ \
+ register long __gu_val; \
+ \
+ __asm__("1: " ldx " 0(%%sr%2,%3),%0\n" \
+ "9:\n" \
+ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \
+ : "=r"(__gu_val), "+r"(__gu_err) \
+ : "i"(sr), "r"(ptr)); \
+ \
+ (val) = (__force __typeof__(*(ptr))) __gu_val; \
+}
+
+#define __get_kernel_nofault(dst, src, type, err_label) \
+{ \
+ type __z; \
+ long __err; \
+ __err = __get_user_internal(SR_KERNEL, __z, (type *)(src)); \
+ if (unlikely(__err)) \
+ goto err_label; \
+ else \
+ *(type *)(dst) = __z; \
+}
+
+
+#if !defined(CONFIG_64BIT)
+
+#define __get_user_asm64(sr, val, ptr) \
+{ \
+ union { \
+ unsigned long long l; \
+ __typeof__(*(ptr)) t; \
+ } __gu_tmp; \
+ \
+ __asm__(" copy %%r0,%R0\n" \
+ "1: ldw 0(%%sr%2,%3),%0\n" \
+ "2: ldw 4(%%sr%2,%3),%R0\n" \
+ "9:\n" \
+ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \
+ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 9b) \
+ : "=&r"(__gu_tmp.l), "+r"(__gu_err) \
+ : "i"(sr), "r"(ptr)); \
+ \
+ (val) = __gu_tmp.t; \
+}
+
+#endif /* !defined(CONFIG_64BIT) */
+
+
+#define __put_user_internal(sr, x, ptr) \
+({ \
+ ASM_EXCEPTIONTABLE_VAR(__pu_err); \
+ \
+ switch (sizeof(*(ptr))) { \
+ case 1: __put_user_asm(sr, "stb", x, ptr); break; \
+ case 2: __put_user_asm(sr, "sth", x, ptr); break; \
+ case 4: __put_user_asm(sr, "stw", x, ptr); break; \
+ case 8: STD_USER(sr, x, ptr); break; \
+ default: BUILD_BUG(); \
+ } \
+ \
+ __pu_err; \
+})
+
+#define __put_user(x, ptr) \
+({ \
+ __typeof__(&*(ptr)) __ptr = ptr; \
+ __typeof__(*(__ptr)) __x = (__typeof__(*(__ptr)))(x); \
+ __put_user_internal(SR_USER, __x, __ptr); \
+})
+
+#define __put_kernel_nofault(dst, src, type, err_label) \
+{ \
+ type __z = *(type *)(src); \
+ long __err; \
+ __err = __put_user_internal(SR_KERNEL, __z, (type *)(dst)); \
+ if (unlikely(__err)) \
+ goto err_label; \
+}
+
+
+
+
+/*
+ * The "__put_user/kernel_asm()" macros tell gcc they read from memory
+ * instead of writing. This is because they do not write to any memory
+ * gcc knows about, so there are no aliasing issues. These macros must
+ * also be aware that fixups are executed in the context of the fault,
+ * and any registers used there must be listed as clobbers.
+ * The register holding the possible EFAULT error (ASM_EXCEPTIONTABLE_REG)
+ * is already listed as input and output register.
+ */
+
+#define __put_user_asm(sr, stx, x, ptr) \
+ __asm__ __volatile__ ( \
+ "1: " stx " %1,0(%%sr%2,%3)\n" \
+ "9:\n" \
+ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \
+ : "+r"(__pu_err) \
+ : "r"(x), "i"(sr), "r"(ptr))
+
+
+#if !defined(CONFIG_64BIT)
+
+#define __put_user_asm64(sr, __val, ptr) do { \
+ __asm__ __volatile__ ( \
+ "1: stw %1,0(%%sr%2,%3)\n" \
+ "2: stw %R1,4(%%sr%2,%3)\n" \
+ "9:\n" \
+ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \
+ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 9b) \
+ : "+r"(__pu_err) \
+ : "r"(__val), "i"(sr), "r"(ptr)); \
+} while (0)
+
+#endif /* !defined(CONFIG_64BIT) */
+
+
+/*
+ * Complex access routines -- external declarations
+ */
+
+extern long strncpy_from_user(char *, const char __user *, long);
+extern __must_check unsigned lclear_user(void __user *, unsigned long);
+extern __must_check long strnlen_user(const char __user *src, long n);
+/*
+ * Complex access routines -- macros
+ */
+
+#define clear_user lclear_user
+#define __clear_user lclear_user
+
+unsigned long __must_check raw_copy_to_user(void __user *dst, const void *src,
+ unsigned long len);
+unsigned long __must_check raw_copy_from_user(void *dst, const void __user *src,
+ unsigned long len);
+#define INLINE_COPY_TO_USER
+#define INLINE_COPY_FROM_USER
+
+struct pt_regs;
+int fixup_exception(struct pt_regs *regs);
+
+#endif /* __PARISC_UACCESS_H */
diff --git a/arch/parisc/include/asm/ucontext.h b/arch/parisc/include/asm/ucontext.h
new file mode 100644
index 000000000..ac7f86386
--- /dev/null
+++ b/arch/parisc/include/asm/ucontext.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_PARISC_UCONTEXT_H
+#define _ASM_PARISC_UCONTEXT_H
+
+struct ucontext {
+ unsigned int uc_flags;
+ struct ucontext *uc_link;
+ stack_t uc_stack;
+ struct sigcontext uc_mcontext;
+ sigset_t uc_sigmask; /* mask last for extensibility */
+};
+
+#endif /* !_ASM_PARISC_UCONTEXT_H */
diff --git a/arch/parisc/include/asm/unaligned.h b/arch/parisc/include/asm/unaligned.h
new file mode 100644
index 000000000..c06212951
--- /dev/null
+++ b/arch/parisc/include/asm/unaligned.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_PARISC_UNALIGNED_H
+#define _ASM_PARISC_UNALIGNED_H
+
+#include <asm-generic/unaligned.h>
+
+struct pt_regs;
+void handle_unaligned(struct pt_regs *regs);
+int check_unaligned(struct pt_regs *regs);
+
+#endif /* _ASM_PARISC_UNALIGNED_H */
diff --git a/arch/parisc/include/asm/unistd.h b/arch/parisc/include/asm/unistd.h
new file mode 100644
index 000000000..e38f9a90a
--- /dev/null
+++ b/arch/parisc/include/asm/unistd.h
@@ -0,0 +1,176 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_PARISC_UNISTD_H_
+#define _ASM_PARISC_UNISTD_H_
+
+#include <uapi/asm/unistd.h>
+
+#define __NR_Linux_syscalls __NR_syscalls
+
+#ifndef __ASSEMBLY__
+
+#define SYS_ify(syscall_name) __NR_##syscall_name
+
+#define __IGNORE_fadvise64 /* fadvise64_64 */
+
+#ifndef ASM_LINE_SEP
+# define ASM_LINE_SEP ;
+#endif
+
+/* Definition taken from glibc 2.3.3
+ * sysdeps/unix/sysv/linux/hppa/sysdep.h
+ */
+
+#ifdef PIC
+/* WARNING: CANNOT BE USED IN A NOP! */
+# define K_STW_ASM_PIC " copy %%r19, %%r4\n"
+# define K_LDW_ASM_PIC " copy %%r4, %%r19\n"
+# define K_USING_GR4 "%r4",
+#else
+# define K_STW_ASM_PIC " \n"
+# define K_LDW_ASM_PIC " \n"
+# define K_USING_GR4
+#endif
+
+/* GCC has to be warned that a syscall may clobber all the ABI
+ registers listed as "caller-saves", see page 8, Table 2
+ in section 2.2.6 of the PA-RISC RUN-TIME architecture
+ document. However! r28 is the result and will conflict with
+ the clobber list so it is left out. Also the input arguments
+ registers r20 -> r26 will conflict with the list so they
+ are treated specially. Although r19 is clobbered by the syscall
+ we cannot say this because it would violate ABI, thus we say
+ r4 is clobbered and use that register to save/restore r19
+ across the syscall. */
+
+#define K_CALL_CLOB_REGS "%r1", "%r2", K_USING_GR4 \
+ "%r20", "%r29", "%r31"
+
+#undef K_INLINE_SYSCALL
+#define K_INLINE_SYSCALL(name, nr, args...) ({ \
+ long __sys_res; \
+ { \
+ register unsigned long __res __asm__("r28"); \
+ K_LOAD_ARGS_##nr(args) \
+ /* FIXME: HACK stw/ldw r19 around syscall */ \
+ __asm__ volatile( \
+ K_STW_ASM_PIC \
+ " ble 0x100(%%sr2, %%r0)\n" \
+ " ldi %1, %%r20\n" \
+ K_LDW_ASM_PIC \
+ : "=r" (__res) \
+ : "i" (SYS_ify(name)) K_ASM_ARGS_##nr \
+ : "memory", K_CALL_CLOB_REGS K_CLOB_ARGS_##nr \
+ ); \
+ __sys_res = (long)__res; \
+ } \
+ __sys_res; \
+})
+
+#define K_LOAD_ARGS_0()
+#define K_LOAD_ARGS_1(r26) \
+ register unsigned long __r26 __asm__("r26") = (unsigned long)(r26); \
+ K_LOAD_ARGS_0()
+#define K_LOAD_ARGS_2(r26,r25) \
+ register unsigned long __r25 __asm__("r25") = (unsigned long)(r25); \
+ K_LOAD_ARGS_1(r26)
+#define K_LOAD_ARGS_3(r26,r25,r24) \
+ register unsigned long __r24 __asm__("r24") = (unsigned long)(r24); \
+ K_LOAD_ARGS_2(r26,r25)
+#define K_LOAD_ARGS_4(r26,r25,r24,r23) \
+ register unsigned long __r23 __asm__("r23") = (unsigned long)(r23); \
+ K_LOAD_ARGS_3(r26,r25,r24)
+#define K_LOAD_ARGS_5(r26,r25,r24,r23,r22) \
+ register unsigned long __r22 __asm__("r22") = (unsigned long)(r22); \
+ K_LOAD_ARGS_4(r26,r25,r24,r23)
+#define K_LOAD_ARGS_6(r26,r25,r24,r23,r22,r21) \
+ register unsigned long __r21 __asm__("r21") = (unsigned long)(r21); \
+ K_LOAD_ARGS_5(r26,r25,r24,r23,r22)
+
+/* Even with zero args we use r20 for the syscall number */
+#define K_ASM_ARGS_0
+#define K_ASM_ARGS_1 K_ASM_ARGS_0, "r" (__r26)
+#define K_ASM_ARGS_2 K_ASM_ARGS_1, "r" (__r25)
+#define K_ASM_ARGS_3 K_ASM_ARGS_2, "r" (__r24)
+#define K_ASM_ARGS_4 K_ASM_ARGS_3, "r" (__r23)
+#define K_ASM_ARGS_5 K_ASM_ARGS_4, "r" (__r22)
+#define K_ASM_ARGS_6 K_ASM_ARGS_5, "r" (__r21)
+
+/* The registers not listed as inputs but clobbered */
+#define K_CLOB_ARGS_6
+#define K_CLOB_ARGS_5 K_CLOB_ARGS_6, "%r21"
+#define K_CLOB_ARGS_4 K_CLOB_ARGS_5, "%r22"
+#define K_CLOB_ARGS_3 K_CLOB_ARGS_4, "%r23"
+#define K_CLOB_ARGS_2 K_CLOB_ARGS_3, "%r24"
+#define K_CLOB_ARGS_1 K_CLOB_ARGS_2, "%r25"
+#define K_CLOB_ARGS_0 K_CLOB_ARGS_1, "%r26"
+
+#define _syscall0(type,name) \
+type name(void) \
+{ \
+ return K_INLINE_SYSCALL(name, 0); \
+}
+
+#define _syscall1(type,name,type1,arg1) \
+type name(type1 arg1) \
+{ \
+ return K_INLINE_SYSCALL(name, 1, arg1); \
+}
+
+#define _syscall2(type,name,type1,arg1,type2,arg2) \
+type name(type1 arg1, type2 arg2) \
+{ \
+ return K_INLINE_SYSCALL(name, 2, arg1, arg2); \
+}
+
+#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
+type name(type1 arg1, type2 arg2, type3 arg3) \
+{ \
+ return K_INLINE_SYSCALL(name, 3, arg1, arg2, arg3); \
+}
+
+#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
+type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
+{ \
+ return K_INLINE_SYSCALL(name, 4, arg1, arg2, arg3, arg4); \
+}
+
+/* select takes 5 arguments */
+#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5) \
+type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \
+{ \
+ return K_INLINE_SYSCALL(name, 5, arg1, arg2, arg3, arg4, arg5); \
+}
+
+#define __ARCH_WANT_NEW_STAT
+#define __ARCH_WANT_STAT64
+#define __ARCH_WANT_SYS_ALARM
+#define __ARCH_WANT_SYS_GETHOSTNAME
+#define __ARCH_WANT_SYS_PAUSE
+#define __ARCH_WANT_SYS_SIGNAL
+#define __ARCH_WANT_SYS_TIME32
+#define __ARCH_WANT_COMPAT_SYS_SCHED_RR_GET_INTERVAL
+#define __ARCH_WANT_SYS_UTIME32
+#define __ARCH_WANT_SYS_WAITPID
+#define __ARCH_WANT_SYS_SOCKETCALL
+#define __ARCH_WANT_SYS_FADVISE64
+#define __ARCH_WANT_SYS_GETPGRP
+#define __ARCH_WANT_SYS_NICE
+#define __ARCH_WANT_SYS_SIGPENDING
+#define __ARCH_WANT_SYS_SIGPROCMASK
+#define __ARCH_WANT_SYS_FORK
+#define __ARCH_WANT_SYS_VFORK
+#define __ARCH_WANT_SYS_CLONE
+#define __ARCH_WANT_SYS_CLONE3
+#define __ARCH_WANT_COMPAT_SYS_SENDFILE
+#define __ARCH_WANT_COMPAT_STAT
+
+#ifdef CONFIG_64BIT
+#define __ARCH_WANT_SYS_TIME
+#define __ARCH_WANT_SYS_UTIME
+#endif
+
+#endif /* __ASSEMBLY__ */
+
+#undef STR
+
+#endif /* _ASM_PARISC_UNISTD_H_ */
diff --git a/arch/parisc/include/asm/unwind.h b/arch/parisc/include/asm/unwind.h
new file mode 100644
index 000000000..9547e5261
--- /dev/null
+++ b/arch/parisc/include/asm/unwind.h
@@ -0,0 +1,85 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _UNWIND_H_
+#define _UNWIND_H_
+
+#include <linux/list.h>
+
+/* Max number of levels to backtrace */
+#define MAX_UNWIND_ENTRIES 30
+
+/* From ABI specifications */
+struct unwind_table_entry {
+ unsigned int region_start;
+ unsigned int region_end;
+ unsigned int Cannot_unwind:1; /* 0 */
+ unsigned int Millicode:1; /* 1 */
+ unsigned int Millicode_save_sr0:1; /* 2 */
+ unsigned int Region_description:2; /* 3..4 */
+ unsigned int reserved1:1; /* 5 */
+ unsigned int Entry_SR:1; /* 6 */
+ unsigned int Entry_FR:4; /* number saved *//* 7..10 */
+ unsigned int Entry_GR:5; /* number saved *//* 11..15 */
+ unsigned int Args_stored:1; /* 16 */
+ unsigned int Variable_Frame:1; /* 17 */
+ unsigned int Separate_Package_Body:1; /* 18 */
+ unsigned int Frame_Extension_Millicode:1; /* 19 */
+ unsigned int Stack_Overflow_Check:1; /* 20 */
+ unsigned int Two_Instruction_SP_Increment:1; /* 21 */
+ unsigned int Ada_Region:1; /* 22 */
+ unsigned int cxx_info:1; /* 23 */
+ unsigned int cxx_try_catch:1; /* 24 */
+ unsigned int sched_entry_seq:1; /* 25 */
+ unsigned int reserved2:1; /* 26 */
+ unsigned int Save_SP:1; /* 27 */
+ unsigned int Save_RP:1; /* 28 */
+ unsigned int Save_MRP_in_frame:1; /* 29 */
+ unsigned int extn_ptr_defined:1; /* 30 */
+ unsigned int Cleanup_defined:1; /* 31 */
+
+ unsigned int MPE_XL_interrupt_marker:1; /* 0 */
+ unsigned int HP_UX_interrupt_marker:1; /* 1 */
+ unsigned int Large_frame:1; /* 2 */
+ unsigned int Pseudo_SP_Set:1; /* 3 */
+ unsigned int reserved4:1; /* 4 */
+ unsigned int Total_frame_size:27; /* 5..31 */
+};
+
+struct unwind_table {
+ struct list_head list;
+ const char *name;
+ unsigned long gp;
+ unsigned long base_addr;
+ unsigned long start;
+ unsigned long end;
+ const struct unwind_table_entry *table;
+ unsigned long length;
+};
+
+struct unwind_frame_info {
+ struct task_struct *t;
+ /* Eventually we would like to be able to get at any of the registers
+ available; but for now we only try to get the sp and ip for each
+ frame */
+ /* struct pt_regs regs; */
+ unsigned long sp, ip, rp, r31;
+ unsigned long prev_sp, prev_ip;
+};
+
+struct unwind_table *
+unwind_table_add(const char *name, unsigned long base_addr,
+ unsigned long gp, void *start, void *end);
+void
+unwind_table_remove(struct unwind_table *table);
+
+void unwind_frame_init(struct unwind_frame_info *info, struct task_struct *t,
+ struct pt_regs *regs);
+void unwind_frame_init_from_blocked_task(struct unwind_frame_info *info,
+ struct task_struct *t);
+void unwind_frame_init_task(struct unwind_frame_info *info,
+ struct task_struct *task, struct pt_regs *regs);
+int unwind_once(struct unwind_frame_info *info);
+int unwind_to_user(struct unwind_frame_info *info);
+
+int unwind_init(void);
+
+#endif
diff --git a/arch/parisc/include/asm/vdso.h b/arch/parisc/include/asm/vdso.h
new file mode 100644
index 000000000..ef8206193
--- /dev/null
+++ b/arch/parisc/include/asm/vdso.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __PARISC_VDSO_H__
+#define __PARISC_VDSO_H__
+
+#ifndef __ASSEMBLY__
+
+#ifdef CONFIG_64BIT
+#include <generated/vdso64-offsets.h>
+#endif
+#include <generated/vdso32-offsets.h>
+
+#define VDSO64_SYMBOL(tsk, name) ((tsk)->mm->context.vdso_base + (vdso64_offset_##name))
+#define VDSO32_SYMBOL(tsk, name) ((tsk)->mm->context.vdso_base + (vdso32_offset_##name))
+
+extern struct vdso_data *vdso_data;
+
+#endif /* __ASSEMBLY __ */
+
+/* Default link addresses for the vDSOs */
+#define VDSO_LBASE 0
+
+#define VDSO_VERSION_STRING LINUX_5.18
+
+#endif /* __PARISC_VDSO_H__ */
diff --git a/arch/parisc/include/asm/vmalloc.h b/arch/parisc/include/asm/vmalloc.h
new file mode 100644
index 000000000..1088ae4e7
--- /dev/null
+++ b/arch/parisc/include/asm/vmalloc.h
@@ -0,0 +1,4 @@
+#ifndef _ASM_PARISC_VMALLOC_H
+#define _ASM_PARISC_VMALLOC_H
+
+#endif /* _ASM_PARISC_VMALLOC_H */
diff --git a/arch/parisc/include/uapi/asm/Kbuild b/arch/parisc/include/uapi/asm/Kbuild
new file mode 100644
index 000000000..353b70b19
--- /dev/null
+++ b/arch/parisc/include/uapi/asm/Kbuild
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+generated-y += unistd_32.h
+generated-y += unistd_64.h
diff --git a/arch/parisc/include/uapi/asm/auxvec.h b/arch/parisc/include/uapi/asm/auxvec.h
new file mode 100644
index 000000000..90d2aa699
--- /dev/null
+++ b/arch/parisc/include/uapi/asm/auxvec.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _UAPI_PARISC_AUXVEC_H
+#define _UAPI_PARISC_AUXVEC_H
+
+/* The vDSO location. */
+#define AT_SYSINFO_EHDR 33
+
+#endif /* _UAPI_PARISC_AUXVEC_H */
diff --git a/arch/parisc/include/uapi/asm/bitsperlong.h b/arch/parisc/include/uapi/asm/bitsperlong.h
new file mode 100644
index 000000000..307e2ef1c
--- /dev/null
+++ b/arch/parisc/include/uapi/asm/bitsperlong.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef __ASM_PARISC_BITSPERLONG_H
+#define __ASM_PARISC_BITSPERLONG_H
+
+#if defined(__LP64__)
+#define __BITS_PER_LONG 64
+#else
+#define __BITS_PER_LONG 32
+#endif
+
+#include <asm-generic/bitsperlong.h>
+
+#endif /* __ASM_PARISC_BITSPERLONG_H */
diff --git a/arch/parisc/include/uapi/asm/byteorder.h b/arch/parisc/include/uapi/asm/byteorder.h
new file mode 100644
index 000000000..a59d9b7e3
--- /dev/null
+++ b/arch/parisc/include/uapi/asm/byteorder.h
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _PARISC_BYTEORDER_H
+#define _PARISC_BYTEORDER_H
+
+#include <linux/byteorder/big_endian.h>
+
+#endif /* _PARISC_BYTEORDER_H */
diff --git a/arch/parisc/include/uapi/asm/cachectl.h b/arch/parisc/include/uapi/asm/cachectl.h
new file mode 100644
index 000000000..68d6b4554
--- /dev/null
+++ b/arch/parisc/include/uapi/asm/cachectl.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _ASM_CACHECTL
+#define _ASM_CACHECTL
+
+/*
+ * Options for cacheflush system call
+ */
+#define ICACHE (1<<0) /* flush instruction cache */
+#define DCACHE (1<<1) /* writeback and flush data cache */
+#define BCACHE (ICACHE|DCACHE) /* flush both caches */
+
+#endif /* _ASM_CACHECTL */
diff --git a/arch/parisc/include/uapi/asm/errno.h b/arch/parisc/include/uapi/asm/errno.h
new file mode 100644
index 000000000..8d94739d7
--- /dev/null
+++ b/arch/parisc/include/uapi/asm/errno.h
@@ -0,0 +1,125 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _PARISC_ERRNO_H
+#define _PARISC_ERRNO_H
+
+#include <asm-generic/errno-base.h>
+
+#define ENOMSG 35 /* No message of desired type */
+#define EIDRM 36 /* Identifier removed */
+#define ECHRNG 37 /* Channel number out of range */
+#define EL2NSYNC 38 /* Level 2 not synchronized */
+#define EL3HLT 39 /* Level 3 halted */
+#define EL3RST 40 /* Level 3 reset */
+#define ELNRNG 41 /* Link number out of range */
+#define EUNATCH 42 /* Protocol driver not attached */
+#define ENOCSI 43 /* No CSI structure available */
+#define EL2HLT 44 /* Level 2 halted */
+#define EDEADLK 45 /* Resource deadlock would occur */
+#define EDEADLOCK EDEADLK
+#define ENOLCK 46 /* No record locks available */
+#define EILSEQ 47 /* Illegal byte sequence */
+
+#define ENONET 50 /* Machine is not on the network */
+#define ENODATA 51 /* No data available */
+#define ETIME 52 /* Timer expired */
+#define ENOSR 53 /* Out of streams resources */
+#define ENOSTR 54 /* Device not a stream */
+#define ENOPKG 55 /* Package not installed */
+
+#define ENOLINK 57 /* Link has been severed */
+#define EADV 58 /* Advertise error */
+#define ESRMNT 59 /* Srmount error */
+#define ECOMM 60 /* Communication error on send */
+#define EPROTO 61 /* Protocol error */
+
+#define EMULTIHOP 64 /* Multihop attempted */
+
+#define EDOTDOT 66 /* RFS specific error */
+#define EBADMSG 67 /* Not a data message */
+#define EUSERS 68 /* Too many users */
+#define EDQUOT 69 /* Quota exceeded */
+#define ESTALE 70 /* Stale file handle */
+#define EREMOTE 71 /* Object is remote */
+#define EOVERFLOW 72 /* Value too large for defined data type */
+
+/* these errnos are defined by Linux but not HPUX. */
+
+#define EBADE 160 /* Invalid exchange */
+#define EBADR 161 /* Invalid request descriptor */
+#define EXFULL 162 /* Exchange full */
+#define ENOANO 163 /* No anode */
+#define EBADRQC 164 /* Invalid request code */
+#define EBADSLT 165 /* Invalid slot */
+#define EBFONT 166 /* Bad font file format */
+#define ENOTUNIQ 167 /* Name not unique on network */
+#define EBADFD 168 /* File descriptor in bad state */
+#define EREMCHG 169 /* Remote address changed */
+#define ELIBACC 170 /* Can not access a needed shared library */
+#define ELIBBAD 171 /* Accessing a corrupted shared library */
+#define ELIBSCN 172 /* .lib section in a.out corrupted */
+#define ELIBMAX 173 /* Attempting to link in too many shared libraries */
+#define ELIBEXEC 174 /* Cannot exec a shared library directly */
+#define ERESTART 175 /* Interrupted system call should be restarted */
+#define ESTRPIPE 176 /* Streams pipe error */
+#define EUCLEAN 177 /* Structure needs cleaning */
+#define ENOTNAM 178 /* Not a XENIX named type file */
+#define ENAVAIL 179 /* No XENIX semaphores available */
+#define EISNAM 180 /* Is a named type file */
+#define EREMOTEIO 181 /* Remote I/O error */
+#define ENOMEDIUM 182 /* No medium found */
+#define EMEDIUMTYPE 183 /* Wrong medium type */
+#define ENOKEY 184 /* Required key not available */
+#define EKEYEXPIRED 185 /* Key has expired */
+#define EKEYREVOKED 186 /* Key has been revoked */
+#define EKEYREJECTED 187 /* Key was rejected by service */
+
+/* We now return you to your regularly scheduled HPUX. */
+
+#define ENOTSOCK 216 /* Socket operation on non-socket */
+#define EDESTADDRREQ 217 /* Destination address required */
+#define EMSGSIZE 218 /* Message too long */
+#define EPROTOTYPE 219 /* Protocol wrong type for socket */
+#define ENOPROTOOPT 220 /* Protocol not available */
+#define EPROTONOSUPPORT 221 /* Protocol not supported */
+#define ESOCKTNOSUPPORT 222 /* Socket type not supported */
+#define EOPNOTSUPP 223 /* Operation not supported on transport endpoint */
+#define EPFNOSUPPORT 224 /* Protocol family not supported */
+#define EAFNOSUPPORT 225 /* Address family not supported by protocol */
+#define EADDRINUSE 226 /* Address already in use */
+#define EADDRNOTAVAIL 227 /* Cannot assign requested address */
+#define ENETDOWN 228 /* Network is down */
+#define ENETUNREACH 229 /* Network is unreachable */
+#define ENETRESET 230 /* Network dropped connection because of reset */
+#define ECONNABORTED 231 /* Software caused connection abort */
+#define ECONNRESET 232 /* Connection reset by peer */
+#define ENOBUFS 233 /* No buffer space available */
+#define EISCONN 234 /* Transport endpoint is already connected */
+#define ENOTCONN 235 /* Transport endpoint is not connected */
+#define ESHUTDOWN 236 /* Cannot send after transport endpoint shutdown */
+#define ETOOMANYREFS 237 /* Too many references: cannot splice */
+#define ETIMEDOUT 238 /* Connection timed out */
+#define ECONNREFUSED 239 /* Connection refused */
+#define EREFUSED ECONNREFUSED /* for HP's NFS apparently */
+#define EHOSTDOWN 241 /* Host is down */
+#define EHOSTUNREACH 242 /* No route to host */
+
+#define EALREADY 244 /* Operation already in progress */
+#define EINPROGRESS 245 /* Operation now in progress */
+#define EWOULDBLOCK EAGAIN /* Operation would block (Not HPUX compliant) */
+#define ENOTEMPTY 247 /* Directory not empty */
+#define ENAMETOOLONG 248 /* File name too long */
+#define ELOOP 249 /* Too many symbolic links encountered */
+#define ENOSYS 251 /* Function not implemented */
+
+#define ECANCELLED 253 /* aio request was canceled before complete (POSIX.4 / HPUX) */
+#define ECANCELED ECANCELLED /* SuSv3 and Solaris wants one 'L' */
+
+/* for robust mutexes */
+#define EOWNERDEAD 254 /* Owner died */
+#define ENOTRECOVERABLE 255 /* State not recoverable */
+
+#define ERFKILL 256 /* Operation not possible due to RF-kill */
+
+#define EHWPOISON 257 /* Memory page has hardware error */
+
+#endif
diff --git a/arch/parisc/include/uapi/asm/fcntl.h b/arch/parisc/include/uapi/asm/fcntl.h
new file mode 100644
index 000000000..03dee816c
--- /dev/null
+++ b/arch/parisc/include/uapi/asm/fcntl.h
@@ -0,0 +1,39 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _PARISC_FCNTL_H
+#define _PARISC_FCNTL_H
+
+#define O_APPEND 000000010
+#define O_CREAT 000000400 /* not fcntl */
+#define O_EXCL 000002000 /* not fcntl */
+#define O_LARGEFILE 000004000
+#define __O_SYNC 000100000
+#define O_SYNC (__O_SYNC|O_DSYNC)
+#define O_NONBLOCK 000200000
+#define O_NOCTTY 000400000 /* not fcntl */
+#define O_DSYNC 001000000
+#define O_NOATIME 004000000
+#define O_CLOEXEC 010000000 /* set close_on_exec */
+
+#define O_DIRECTORY 000010000 /* must be a directory */
+#define O_NOFOLLOW 000000200 /* don't follow links */
+
+#define O_PATH 020000000
+#define __O_TMPFILE 040000000
+
+#define F_GETLK64 8
+#define F_SETLK64 9
+#define F_SETLKW64 10
+
+#define F_GETOWN 11 /* for sockets. */
+#define F_SETOWN 12 /* for sockets. */
+#define F_SETSIG 13 /* for sockets. */
+#define F_GETSIG 14 /* for sockets. */
+
+/* for posix fcntl() and lockf() */
+#define F_RDLCK 01
+#define F_WRLCK 02
+#define F_UNLCK 03
+
+#include <asm-generic/fcntl.h>
+
+#endif
diff --git a/arch/parisc/include/uapi/asm/ioctl.h b/arch/parisc/include/uapi/asm/ioctl.h
new file mode 100644
index 000000000..b509bcc94
--- /dev/null
+++ b/arch/parisc/include/uapi/asm/ioctl.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ * Copyright (C) 1999,2003 Matthew Wilcox < willy at debian . org >
+ * portions from "linux/ioctl.h for Linux" by H.H. Bergman.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef _ASM_PARISC_IOCTL_H
+#define _ASM_PARISC_IOCTL_H
+
+/* ioctl command encoding: 32 bits total, command in lower 16 bits,
+ * size of the parameter structure in the lower 14 bits of the
+ * upper 16 bits.
+ * Encoding the size of the parameter structure in the ioctl request
+ * is useful for catching programs compiled with old versions
+ * and to avoid overwriting user space outside the user buffer area.
+ * The highest 2 bits are reserved for indicating the ``access mode''.
+ * NOTE: This limits the max parameter size to 16kB -1 !
+ */
+
+/*
+ * Direction bits.
+ */
+#define _IOC_NONE 0U
+#define _IOC_WRITE 2U
+#define _IOC_READ 1U
+
+#include <asm-generic/ioctl.h>
+
+#endif /* _ASM_PARISC_IOCTL_H */
diff --git a/arch/parisc/include/uapi/asm/ioctls.h b/arch/parisc/include/uapi/asm/ioctls.h
new file mode 100644
index 000000000..82d1148c6
--- /dev/null
+++ b/arch/parisc/include/uapi/asm/ioctls.h
@@ -0,0 +1,101 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef __ARCH_PARISC_IOCTLS_H__
+#define __ARCH_PARISC_IOCTLS_H__
+
+#include <asm/ioctl.h>
+
+/* 0x54 is just a magic number to make these relatively unique ('T') */
+
+#define TCGETS _IOR('T', 16, struct termios) /* TCGETATTR */
+#define TCSETS _IOW('T', 17, struct termios) /* TCSETATTR */
+#define TCSETSW _IOW('T', 18, struct termios) /* TCSETATTRD */
+#define TCSETSF _IOW('T', 19, struct termios) /* TCSETATTRF */
+#define TCGETA _IOR('T', 1, struct termio)
+#define TCSETA _IOW('T', 2, struct termio)
+#define TCSETAW _IOW('T', 3, struct termio)
+#define TCSETAF _IOW('T', 4, struct termio)
+#define TCSBRK _IO('T', 5)
+#define TCXONC _IO('T', 6)
+#define TCFLSH _IO('T', 7)
+#define TIOCEXCL 0x540C
+#define TIOCNXCL 0x540D
+#define TIOCSCTTY 0x540E
+#define TIOCGPGRP _IOR('T', 30, int)
+#define TIOCSPGRP _IOW('T', 29, int)
+#define TIOCOUTQ 0x5411
+#define TIOCSTI 0x5412
+#define TIOCGWINSZ 0x5413
+#define TIOCSWINSZ 0x5414
+#define TIOCMGET 0x5415
+#define TIOCMBIS 0x5416
+#define TIOCMBIC 0x5417
+#define TIOCMSET 0x5418
+#define TIOCGSOFTCAR 0x5419
+#define TIOCSSOFTCAR 0x541A
+#define FIONREAD 0x541B
+#define TIOCINQ FIONREAD
+#define TIOCLINUX 0x541C
+#define TIOCCONS 0x541D
+#define TIOCGSERIAL 0x541E
+#define TIOCSSERIAL 0x541F
+#define TIOCPKT 0x5420
+#define FIONBIO 0x5421
+#define TIOCNOTTY 0x5422
+#define TIOCSETD 0x5423
+#define TIOCGETD 0x5424
+#define TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */
+#define TIOCSBRK 0x5427 /* BSD compatibility */
+#define TIOCCBRK 0x5428 /* BSD compatibility */
+#define TIOCGSID _IOR('T', 20, int) /* Return the session ID of FD */
+#define TCGETS2 _IOR('T',0x2A, struct termios2)
+#define TCSETS2 _IOW('T',0x2B, struct termios2)
+#define TCSETSW2 _IOW('T',0x2C, struct termios2)
+#define TCSETSF2 _IOW('T',0x2D, struct termios2)
+#define TIOCGRS485 _IOR('T', 0x2E, struct serial_rs485)
+#define TIOCSRS485 _IOWR('T', 0x2F, struct serial_rs485)
+#define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
+#define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */
+#define TIOCGDEV _IOR('T',0x32, int) /* Get primary device node of /dev/console */
+#define TIOCSIG _IOW('T',0x36, int) /* Generate signal on Pty slave */
+#define TIOCVHANGUP 0x5437
+#define TIOCGPKT _IOR('T', 0x38, int) /* Get packet mode state */
+#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */
+#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */
+#define TIOCGPTPEER _IO('T', 0x41) /* Safely open the slave */
+#define TIOCGISO7816 _IOR('T', 0x42, struct serial_iso7816)
+#define TIOCSISO7816 _IOWR('T', 0x43, struct serial_iso7816)
+
+#define FIONCLEX 0x5450 /* these numbers need to be adjusted. */
+#define FIOCLEX 0x5451
+#define FIOASYNC 0x5452
+#define TIOCSERCONFIG 0x5453
+#define TIOCSERGWILD 0x5454
+#define TIOCSERSWILD 0x5455
+#define TIOCGLCKTRMIOS 0x5456
+#define TIOCSLCKTRMIOS 0x5457
+#define TIOCSERGSTRUCT 0x5458 /* For debugging only */
+#define TIOCSERGETLSR 0x5459 /* Get line status register */
+#define TIOCSERGETMULTI 0x545A /* Get multiport config */
+#define TIOCSERSETMULTI 0x545B /* Set multiport config */
+
+#define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */
+#define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */
+#define FIOQSIZE 0x5460 /* Get exact space used by quota */
+
+#define TIOCSTART 0x5461
+#define TIOCSTOP 0x5462
+#define TIOCSLTC 0x5462
+
+/* Used for packet mode */
+#define TIOCPKT_DATA 0
+#define TIOCPKT_FLUSHREAD 1
+#define TIOCPKT_FLUSHWRITE 2
+#define TIOCPKT_STOP 4
+#define TIOCPKT_START 8
+#define TIOCPKT_NOSTOP 16
+#define TIOCPKT_DOSTOP 32
+#define TIOCPKT_IOCTL 64
+
+#define TIOCSER_TEMT 0x01 /* Transmitter physically empty */
+
+#endif /* _ASM_PARISC_IOCTLS_H */
diff --git a/arch/parisc/include/uapi/asm/ipcbuf.h b/arch/parisc/include/uapi/asm/ipcbuf.h
new file mode 100644
index 000000000..edf266204
--- /dev/null
+++ b/arch/parisc/include/uapi/asm/ipcbuf.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef __PARISC_IPCBUF_H__
+#define __PARISC_IPCBUF_H__
+
+#include <asm/bitsperlong.h>
+#include <linux/posix_types.h>
+
+/*
+ * The ipc64_perm structure for PA-RISC is almost identical to
+ * kern_ipc_perm as we have always had 32-bit UIDs and GIDs in the kernel.
+ * 'seq' has been changed from long to int so that it's the same size
+ * on 64-bit kernels as on 32-bit ones.
+ */
+
+struct ipc64_perm
+{
+ __kernel_key_t key;
+ __kernel_uid_t uid;
+ __kernel_gid_t gid;
+ __kernel_uid_t cuid;
+ __kernel_gid_t cgid;
+#if __BITS_PER_LONG != 64
+ unsigned short int __pad1;
+#endif
+ __kernel_mode_t mode;
+ unsigned short int __pad2;
+ unsigned short int seq;
+ unsigned int __pad3;
+ unsigned long long int __unused1;
+ unsigned long long int __unused2;
+};
+
+#endif /* __PARISC_IPCBUF_H__ */
diff --git a/arch/parisc/include/uapi/asm/mman.h b/arch/parisc/include/uapi/asm/mman.h
new file mode 100644
index 000000000..68c44f99b
--- /dev/null
+++ b/arch/parisc/include/uapi/asm/mman.h
@@ -0,0 +1,86 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef __PARISC_MMAN_H__
+#define __PARISC_MMAN_H__
+
+#define PROT_READ 0x1 /* page can be read */
+#define PROT_WRITE 0x2 /* page can be written */
+#define PROT_EXEC 0x4 /* page can be executed */
+#define PROT_SEM 0x8 /* page may be used for atomic ops */
+#define PROT_NONE 0x0 /* page can not be accessed */
+#define PROT_GROWSDOWN 0x01000000 /* mprotect flag: extend change to start of growsdown vma */
+#define PROT_GROWSUP 0x02000000 /* mprotect flag: extend change to end of growsup vma */
+
+/* 0x01 - 0x03 are defined in linux/mman.h */
+#define MAP_TYPE 0x2b /* Mask for type of mapping, includes bits 0x08 and 0x20 */
+#define MAP_FIXED 0x04 /* Interpret addr exactly */
+#define MAP_ANONYMOUS 0x10 /* don't use a file */
+
+#define MAP_DENYWRITE 0x0800 /* ETXTBSY */
+#define MAP_EXECUTABLE 0x1000 /* mark it as an executable */
+#define MAP_LOCKED 0x2000 /* pages are locked */
+#define MAP_NORESERVE 0x4000 /* don't check for reservations */
+#define MAP_GROWSDOWN 0x8000 /* stack-like segment */
+#define MAP_POPULATE 0x10000 /* populate (prefault) pagetables */
+#define MAP_NONBLOCK 0x20000 /* do not block on IO */
+#define MAP_STACK 0x40000 /* give out an address that is best suited for process/thread stacks */
+#define MAP_HUGETLB 0x80000 /* create a huge page mapping */
+#define MAP_FIXED_NOREPLACE 0x100000 /* MAP_FIXED which doesn't unmap underlying mapping */
+#define MAP_UNINITIALIZED 0 /* uninitialized anonymous mmap */
+
+#define MS_SYNC 1 /* synchronous memory sync */
+#define MS_ASYNC 2 /* sync memory asynchronously */
+#define MS_INVALIDATE 4 /* invalidate the caches */
+
+#define MCL_CURRENT 1 /* lock all current mappings */
+#define MCL_FUTURE 2 /* lock all future mappings */
+#define MCL_ONFAULT 4 /* lock all pages that are faulted in */
+
+#define MLOCK_ONFAULT 0x01 /* Lock pages in range after they are faulted in, do not prefault */
+
+#define MADV_NORMAL 0 /* no further special treatment */
+#define MADV_RANDOM 1 /* expect random page references */
+#define MADV_SEQUENTIAL 2 /* expect sequential page references */
+#define MADV_WILLNEED 3 /* will need these pages */
+#define MADV_DONTNEED 4 /* don't need these pages */
+
+/* common/generic parameters */
+#define MADV_FREE 8 /* free pages only if memory pressure */
+#define MADV_REMOVE 9 /* remove these pages & resources */
+#define MADV_DONTFORK 10 /* don't inherit across fork */
+#define MADV_DOFORK 11 /* do inherit across fork */
+
+#define MADV_MERGEABLE 12 /* KSM may merge identical pages */
+#define MADV_UNMERGEABLE 13 /* KSM may not merge identical pages */
+
+#define MADV_HUGEPAGE 14 /* Worth backing with hugepages */
+#define MADV_NOHUGEPAGE 15 /* Not worth backing with hugepages */
+
+#define MADV_DONTDUMP 16 /* Explicity exclude from the core dump,
+ overrides the coredump filter bits */
+#define MADV_DODUMP 17 /* Clear the MADV_NODUMP flag */
+
+#define MADV_WIPEONFORK 18 /* Zero memory on fork, child only */
+#define MADV_KEEPONFORK 19 /* Undo MADV_WIPEONFORK */
+
+#define MADV_COLD 20 /* deactivate these pages */
+#define MADV_PAGEOUT 21 /* reclaim these pages */
+
+#define MADV_POPULATE_READ 22 /* populate (prefault) page tables readable */
+#define MADV_POPULATE_WRITE 23 /* populate (prefault) page tables writable */
+
+#define MADV_DONTNEED_LOCKED 24 /* like DONTNEED, but drop locked pages too */
+
+#define MADV_COLLAPSE 25 /* Synchronous hugepage collapse */
+
+#define MADV_HWPOISON 100 /* poison a page for testing */
+#define MADV_SOFT_OFFLINE 101 /* soft offline page for testing */
+
+/* compatibility flags */
+#define MAP_FILE 0
+
+#define PKEY_DISABLE_ACCESS 0x1
+#define PKEY_DISABLE_WRITE 0x2
+#define PKEY_ACCESS_MASK (PKEY_DISABLE_ACCESS |\
+ PKEY_DISABLE_WRITE)
+
+#endif /* __PARISC_MMAN_H__ */
diff --git a/arch/parisc/include/uapi/asm/msgbuf.h b/arch/parisc/include/uapi/asm/msgbuf.h
new file mode 100644
index 000000000..3b4de5b66
--- /dev/null
+++ b/arch/parisc/include/uapi/asm/msgbuf.h
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _PARISC_MSGBUF_H
+#define _PARISC_MSGBUF_H
+
+#include <asm/bitsperlong.h>
+#include <asm/ipcbuf.h>
+
+/*
+ * The msqid64_ds structure for parisc architecture, copied from sparc.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct msqid64_ds {
+ struct ipc64_perm msg_perm;
+#if __BITS_PER_LONG == 64
+ long msg_stime; /* last msgsnd time */
+ long msg_rtime; /* last msgrcv time */
+ long msg_ctime; /* last change time */
+#else
+ unsigned long msg_stime_high;
+ unsigned long msg_stime; /* last msgsnd time */
+ unsigned long msg_rtime_high;
+ unsigned long msg_rtime; /* last msgrcv time */
+ unsigned long msg_ctime_high;
+ unsigned long msg_ctime; /* last change time */
+#endif
+ unsigned long msg_cbytes; /* current number of bytes on queue */
+ unsigned long msg_qnum; /* number of messages in queue */
+ unsigned long msg_qbytes; /* max number of bytes on queue */
+ __kernel_pid_t msg_lspid; /* pid of last msgsnd */
+ __kernel_pid_t msg_lrpid; /* last receive pid */
+ unsigned long __unused1;
+ unsigned long __unused2;
+};
+
+#endif /* _PARISC_MSGBUF_H */
diff --git a/arch/parisc/include/uapi/asm/pdc.h b/arch/parisc/include/uapi/asm/pdc.h
new file mode 100644
index 000000000..8e38a8699
--- /dev/null
+++ b/arch/parisc/include/uapi/asm/pdc.h
@@ -0,0 +1,723 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _UAPI_PARISC_PDC_H
+#define _UAPI_PARISC_PDC_H
+
+/*
+ * PDC return values ...
+ * All PDC calls return a subset of these errors.
+ */
+
+#define PDC_WARN 3 /* Call completed with a warning */
+#define PDC_REQ_ERR_1 2 /* See above */
+#define PDC_REQ_ERR_0 1 /* Call would generate a requestor error */
+#define PDC_OK 0 /* Call completed successfully */
+#define PDC_BAD_PROC -1 /* Called non-existent procedure*/
+#define PDC_BAD_OPTION -2 /* Called with non-existent option */
+#define PDC_ERROR -3 /* Call could not complete without an error */
+#define PDC_NE_MOD -5 /* Module not found */
+#define PDC_NE_CELL_MOD -7 /* Cell module not found */
+#define PDC_NE_BOOTDEV -9 /* Cannot locate a console device or boot device */
+#define PDC_INVALID_ARG -10 /* Called with an invalid argument */
+#define PDC_BUS_POW_WARN -12 /* Call could not complete in allowed power budget */
+#define PDC_NOT_NARROW -17 /* Narrow mode not supported */
+
+/*
+ * PDC entry points...
+ */
+
+#define PDC_POW_FAIL 1 /* perform a power-fail */
+#define PDC_POW_FAIL_PREPARE 0 /* prepare for powerfail */
+
+#define PDC_CHASSIS 2 /* PDC-chassis functions */
+#define PDC_CHASSIS_DISP 0 /* update chassis display */
+#define PDC_CHASSIS_WARN 1 /* return chassis warnings */
+#define PDC_CHASSIS_DISPWARN 2 /* update&return chassis status */
+#define PDC_RETURN_CHASSIS_INFO 128 /* HVERSION dependent: return chassis LED/LCD info */
+
+#define PDC_PIM 3 /* Get PIM data */
+#define PDC_PIM_HPMC 0 /* Transfer HPMC data */
+#define PDC_PIM_RETURN_SIZE 1 /* Get Max buffer needed for PIM*/
+#define PDC_PIM_LPMC 2 /* Transfer HPMC data */
+#define PDC_PIM_SOFT_BOOT 3 /* Transfer Soft Boot data */
+#define PDC_PIM_TOC 4 /* Transfer TOC data */
+
+#define PDC_MODEL 4 /* PDC model information call */
+#define PDC_MODEL_INFO 0 /* returns information */
+#define PDC_MODEL_BOOTID 1 /* set the BOOT_ID */
+#define PDC_MODEL_VERSIONS 2 /* returns cpu-internal versions*/
+#define PDC_MODEL_SYSMODEL 3 /* return system model info */
+#define PDC_MODEL_ENSPEC 4 /* enable specific option */
+#define PDC_MODEL_DISPEC 5 /* disable specific option */
+#define PDC_MODEL_CPU_ID 6 /* returns cpu-id (only newer machines!) */
+#define PDC_MODEL_CAPABILITIES 7 /* returns OS32/OS64-flags */
+/* Values for PDC_MODEL_CAPABILITIES non-equivalent virtual aliasing support */
+#define PDC_MODEL_OS64 (1 << 0)
+#define PDC_MODEL_OS32 (1 << 1)
+#define PDC_MODEL_IOPDIR_FDC (1 << 2)
+#define PDC_MODEL_NVA_MASK (3 << 4)
+#define PDC_MODEL_NVA_SUPPORTED (0 << 4)
+#define PDC_MODEL_NVA_SLOW (1 << 4)
+#define PDC_MODEL_NVA_UNSUPPORTED (3 << 4)
+#define PDC_MODEL_GET_BOOT__OP 8 /* returns boot test options */
+#define PDC_MODEL_SET_BOOT__OP 9 /* set boot test options */
+#define PDC_MODEL_GET_PLATFORM_INFO 10 /* returns platform info */
+#define PDC_MODEL_GET_INSTALL_KERNEL 11 /* returns kernel for installation */
+
+#define PA89_INSTRUCTION_SET 0x4 /* capabilities returned */
+#define PA90_INSTRUCTION_SET 0x8
+
+#define PDC_CACHE 5 /* return/set cache (& TLB) info*/
+#define PDC_CACHE_INFO 0 /* returns information */
+#define PDC_CACHE_SET_COH 1 /* set coherence state */
+#define PDC_CACHE_RET_SPID 2 /* returns space-ID bits */
+
+#define PDC_HPA 6 /* return HPA of processor */
+#define PDC_HPA_PROCESSOR 0
+#define PDC_HPA_MODULES 1
+
+#define PDC_COPROC 7 /* Co-Processor (usually FP unit(s)) */
+#define PDC_COPROC_CFG 0 /* Co-Processor Cfg (FP unit(s) enabled?) */
+
+#define PDC_IODC 8 /* talk to IODC */
+#define PDC_IODC_READ 0 /* read IODC entry point */
+/* PDC_IODC_RI_ * INDEX parameter of PDC_IODC_READ */
+#define PDC_IODC_RI_DATA_BYTES 0 /* IODC Data Bytes */
+/* 1, 2 obsolete - HVERSION dependent*/
+#define PDC_IODC_RI_INIT 3 /* Initialize module */
+#define PDC_IODC_RI_IO 4 /* Module input/output */
+#define PDC_IODC_RI_SPA 5 /* Module input/output */
+#define PDC_IODC_RI_CONFIG 6 /* Module input/output */
+/* 7 obsolete - HVERSION dependent */
+#define PDC_IODC_RI_TEST 8 /* Module input/output */
+#define PDC_IODC_RI_TLB 9 /* Module input/output */
+#define PDC_IODC_NINIT 2 /* non-destructive init */
+#define PDC_IODC_DINIT 3 /* destructive init */
+#define PDC_IODC_MEMERR 4 /* check for memory errors */
+#define PDC_IODC_INDEX_DATA 0 /* get first 16 bytes from mod IODC */
+#define PDC_IODC_BUS_ERROR -4 /* bus error return value */
+#define PDC_IODC_INVALID_INDEX -5 /* invalid index return value */
+#define PDC_IODC_COUNT -6 /* count is too small */
+
+#define PDC_TOD 9 /* time-of-day clock (TOD) */
+#define PDC_TOD_READ 0 /* read TOD */
+#define PDC_TOD_WRITE 1 /* write TOD */
+#define PDC_TOD_CALIBRATE 2 /* calibrate timers */
+
+#define PDC_STABLE 10 /* stable storage (sprockets) */
+#define PDC_STABLE_READ 0
+#define PDC_STABLE_WRITE 1
+#define PDC_STABLE_RETURN_SIZE 2
+#define PDC_STABLE_VERIFY_CONTENTS 3
+#define PDC_STABLE_INITIALIZE 4
+
+#define PDC_NVOLATILE 11 /* often not implemented */
+#define PDC_NVOLATILE_READ 0
+#define PDC_NVOLATILE_WRITE 1
+#define PDC_NVOLATILE_RETURN_SIZE 2
+#define PDC_NVOLATILE_VERIFY_CONTENTS 3
+#define PDC_NVOLATILE_INITIALIZE 4
+
+#define PDC_ADD_VALID 12 /* Memory validation PDC call */
+#define PDC_ADD_VALID_VERIFY 0 /* Make PDC_ADD_VALID verify region */
+
+#define PDC_DEBUG 14 /* Obsolete */
+
+#define PDC_INSTR 15 /* get instr to invoke PDCE_CHECK() */
+
+#define PDC_PROC 16 /* (sprockets) */
+
+#define PDC_CONFIG 17 /* (sprockets) */
+#define PDC_CONFIG_DECONFIG 0
+#define PDC_CONFIG_DRECONFIG 1
+#define PDC_CONFIG_DRETURN_CONFIG 2
+
+#define PDC_BLOCK_TLB 18 /* manage hardware block-TLB */
+#define PDC_BTLB_INFO 0 /* returns parameter */
+#define PDC_BTLB_INSERT 1 /* insert BTLB entry */
+#define PDC_BTLB_PURGE 2 /* purge BTLB entries */
+#define PDC_BTLB_PURGE_ALL 3 /* purge all BTLB entries */
+
+#define PDC_TLB 19 /* manage hardware TLB miss handling */
+#define PDC_TLB_INFO 0 /* returns parameter */
+#define PDC_TLB_SETUP 1 /* set up miss handling */
+
+#define PDC_MEM 20 /* Manage memory */
+#define PDC_MEM_MEMINFO 0 /* Return PDT info */
+#define PDC_MEM_ADD_PAGE 1 /* Add page to PDT */
+#define PDC_MEM_CLEAR_PDT 2 /* Clear PDT */
+#define PDC_MEM_READ_PDT 3 /* Read PDT entry */
+#define PDC_MEM_RESET_CLEAR 4 /* Reset PDT clear flag */
+#define PDC_MEM_GOODMEM 5 /* Set good_mem value */
+#define PDC_MEM_TABLE 128 /* Non contig mem map (sprockets) */
+#define PDC_MEM_RETURN_ADDRESS_TABLE PDC_MEM_TABLE
+#define PDC_MEM_GET_MEMORY_SYSTEM_TABLES_SIZE 131
+#define PDC_MEM_GET_MEMORY_SYSTEM_TABLES 132
+#define PDC_MEM_GET_PHYSICAL_LOCATION_FROM_MEMORY_ADDRESS 133
+
+#define PDC_MEM_RET_SBE_REPLACED 5 /* PDC_MEM return values */
+#define PDC_MEM_RET_DUPLICATE_ENTRY 4
+#define PDC_MEM_RET_BUF_SIZE_SMALL 1
+#define PDC_MEM_RET_PDT_FULL -11
+#define PDC_MEM_RET_INVALID_PHYSICAL_LOCATION ~0ULL
+
+#define PDC_PSW 21 /* Get/Set default System Mask */
+#define PDC_PSW_MASK 0 /* Return mask */
+#define PDC_PSW_GET_DEFAULTS 1 /* Return defaults */
+#define PDC_PSW_SET_DEFAULTS 2 /* Set default */
+#define PDC_PSW_ENDIAN_BIT 1 /* set for big endian */
+#define PDC_PSW_WIDE_BIT 2 /* set for wide mode */
+
+#define PDC_SYSTEM_MAP 22 /* find system modules */
+#define PDC_FIND_MODULE 0
+#define PDC_FIND_ADDRESS 1
+#define PDC_TRANSLATE_PATH 2
+
+#define PDC_SOFT_POWER 23 /* soft power switch */
+#define PDC_SOFT_POWER_INFO 0 /* return info about the soft power switch */
+#define PDC_SOFT_POWER_ENABLE 1 /* enable/disable soft power switch */
+
+#define PDC_ALLOC 24 /* allocate static storage for PDC & IODC */
+
+#define PDC_CRASH_PREP 25 /* Prepare system for crash dump */
+#define PDC_CRASH_DUMP 0 /* Do platform specific preparations for dump */
+#define PDC_CRASH_LOG_CEC_ERROR 1 /* Dump hardware registers */
+
+#define PDC_SCSI_PARMS 26 /* Get and set SCSI parameters */
+#define PDC_SCSI_GET_PARMS 0 /* Get SCSI parameters for I/O device */
+#define PDC_SCSI_SET_PARMS 1 /* Set SCSI parameters for I/O device */
+
+/* HVERSION dependent */
+
+/* The PDC_MEM_MAP calls */
+#define PDC_MEM_MAP 128 /* on s700: return page info */
+#define PDC_MEM_MAP_HPA 0 /* returns hpa of a module */
+
+#define PDC_EEPROM 129 /* EEPROM access */
+#define PDC_EEPROM_READ_WORD 0
+#define PDC_EEPROM_WRITE_WORD 1
+#define PDC_EEPROM_READ_BYTE 2
+#define PDC_EEPROM_WRITE_BYTE 3
+#define PDC_EEPROM_EEPROM_PASSWORD -1000
+
+#define PDC_NVM 130 /* NVM (non-volatile memory) access */
+#define PDC_NVM_READ_WORD 0
+#define PDC_NVM_WRITE_WORD 1
+#define PDC_NVM_READ_BYTE 2
+#define PDC_NVM_WRITE_BYTE 3
+
+#define PDC_SEED_ERROR 132 /* (sprockets) */
+
+#define PDC_IO 135 /* log error info, reset IO system */
+#define PDC_IO_READ_AND_CLEAR_ERRORS 0
+#define PDC_IO_RESET 1
+#define PDC_IO_RESET_DEVICES 2
+/* sets bits 6&7 (little endian) of the HcControl Register */
+#define PDC_IO_USB_SUSPEND 0xC000000000000000
+#define PDC_IO_EEPROM_IO_ERR_TABLE_FULL -5 /* return value */
+#define PDC_IO_NO_SUSPEND -6 /* return value */
+
+#define PDC_BROADCAST_RESET 136 /* reset all processors */
+#define PDC_DO_RESET 0 /* option: perform a broadcast reset */
+#define PDC_DO_FIRM_TEST_RESET 1 /* Do broadcast reset with bitmap */
+#define PDC_BR_RECONFIGURATION 2 /* reset w/reconfiguration */
+#define PDC_FIRM_TEST_MAGIC 0xab9ec36fUL /* for this reboot only */
+
+#define PDC_LAN_STATION_ID 138 /* Hversion dependent mechanism for */
+#define PDC_LAN_STATION_ID_READ 0 /* getting the lan station address */
+
+#define PDC_LAN_STATION_ID_SIZE 6
+
+#define PDC_CHECK_RANGES 139 /* (sprockets) */
+
+#define PDC_NV_SECTIONS 141 /* (sprockets) */
+
+#define PDC_PERFORMANCE 142 /* performance monitoring */
+
+#define PDC_SYSTEM_INFO 143 /* system information */
+#define PDC_SYSINFO_RETURN_INFO_SIZE 0
+#define PDC_SYSINFO_RRETURN_SYS_INFO 1
+#define PDC_SYSINFO_RRETURN_ERRORS 2
+#define PDC_SYSINFO_RRETURN_WARNINGS 3
+#define PDC_SYSINFO_RETURN_REVISIONS 4
+#define PDC_SYSINFO_RRETURN_DIAGNOSE 5
+#define PDC_SYSINFO_RRETURN_HV_DIAGNOSE 1005
+
+#define PDC_RDR 144 /* (sprockets) */
+#define PDC_RDR_READ_BUFFER 0
+#define PDC_RDR_READ_SINGLE 1
+#define PDC_RDR_WRITE_SINGLE 2
+
+#define PDC_INTRIGUE 145 /* (sprockets) */
+#define PDC_INTRIGUE_WRITE_BUFFER 0
+#define PDC_INTRIGUE_GET_SCRATCH_BUFSIZE 1
+#define PDC_INTRIGUE_START_CPU_COUNTERS 2
+#define PDC_INTRIGUE_STOP_CPU_COUNTERS 3
+
+#define PDC_STI 146 /* STI access */
+/* same as PDC_PCI_XXX values (see below) */
+
+/* Legacy PDC definitions for same stuff */
+#define PDC_PCI_INDEX 147
+#define PDC_PCI_INTERFACE_INFO 0
+#define PDC_PCI_SLOT_INFO 1
+#define PDC_PCI_INFLIGHT_BYTES 2
+#define PDC_PCI_READ_CONFIG 3
+#define PDC_PCI_WRITE_CONFIG 4
+#define PDC_PCI_READ_PCI_IO 5
+#define PDC_PCI_WRITE_PCI_IO 6
+#define PDC_PCI_READ_CONFIG_DELAY 7
+#define PDC_PCI_UPDATE_CONFIG_DELAY 8
+#define PDC_PCI_PCI_PATH_TO_PCI_HPA 9
+#define PDC_PCI_PCI_HPA_TO_PCI_PATH 10
+#define PDC_PCI_PCI_PATH_TO_PCI_BUS 11
+#define PDC_PCI_PCI_RESERVED 12
+#define PDC_PCI_PCI_INT_ROUTE_SIZE 13
+#define PDC_PCI_GET_INT_TBL_SIZE PDC_PCI_PCI_INT_ROUTE_SIZE
+#define PDC_PCI_PCI_INT_ROUTE 14
+#define PDC_PCI_GET_INT_TBL PDC_PCI_PCI_INT_ROUTE
+#define PDC_PCI_READ_MON_TYPE 15
+#define PDC_PCI_WRITE_MON_TYPE 16
+
+#define PDC_RELOCATE 149 /* (sprockets) */
+#define PDC_RELOCATE_GET_RELOCINFO 0
+#define PDC_RELOCATE_CHECKSUM 1
+#define PDC_RELOCATE_RELOCATE 2
+
+/* Get SCSI Interface Card info: SDTR, SCSI ID, mode (SE vs LVD) */
+#define PDC_INITIATOR 163
+#define PDC_GET_INITIATOR 0
+#define PDC_SET_INITIATOR 1
+#define PDC_DELETE_INITIATOR 2
+#define PDC_RETURN_TABLE_SIZE 3
+#define PDC_RETURN_TABLE 4
+
+#define PDC_LINK 165 /* (sprockets) */
+#define PDC_LINK_PCI_ENTRY_POINTS 0 /* list (Arg1) = 0 */
+#define PDC_LINK_USB_ENTRY_POINTS 1 /* list (Arg1) = 1 */
+
+/* cl_class
+ * page 3-33 of IO-Firmware ARS
+ * IODC ENTRY_INIT(Search first) RET[1]
+ */
+#define CL_NULL 0 /* invalid */
+#define CL_RANDOM 1 /* random access (as disk) */
+#define CL_SEQU 2 /* sequential access (as tape) */
+#define CL_DUPLEX 7 /* full-duplex point-to-point (RS-232, Net) */
+#define CL_KEYBD 8 /* half-duplex console (HIL Keyboard) */
+#define CL_DISPL 9 /* half-duplex console (display) */
+#define CL_FC 10 /* FiberChannel access media */
+
+/* IODC ENTRY_INIT() */
+#define ENTRY_INIT_SRCH_FRST 2
+#define ENTRY_INIT_SRCH_NEXT 3
+#define ENTRY_INIT_MOD_DEV 4
+#define ENTRY_INIT_DEV 5
+#define ENTRY_INIT_MOD 6
+#define ENTRY_INIT_MSG 9
+
+/* IODC ENTRY_IO() */
+#define ENTRY_IO_BOOTIN 0
+#define ENTRY_IO_BOOTOUT 1
+#define ENTRY_IO_CIN 2
+#define ENTRY_IO_COUT 3
+#define ENTRY_IO_CLOSE 4
+#define ENTRY_IO_GETMSG 9
+#define ENTRY_IO_BBLOCK_IN 16
+#define ENTRY_IO_BBLOCK_OUT 17
+
+/* IODC ENTRY_SPA() */
+
+/* IODC ENTRY_CONFIG() */
+
+/* IODC ENTRY_TEST() */
+
+/* IODC ENTRY_TLB() */
+
+/* constants for OS (NVM...) */
+#define OS_ID_NONE 0 /* Undefined OS ID */
+#define OS_ID_HPUX 1 /* HP-UX OS */
+#define OS_ID_MPEXL 2 /* MPE XL OS */
+#define OS_ID_OSF 3 /* OSF OS */
+#define OS_ID_HPRT 4 /* HP-RT OS */
+#define OS_ID_NOVEL 5 /* NOVELL OS */
+#define OS_ID_LINUX 6 /* Linux */
+
+
+/* constants for PDC_CHASSIS */
+#define OSTAT_OFF 0
+#define OSTAT_FLT 1
+#define OSTAT_TEST 2
+#define OSTAT_INIT 3
+#define OSTAT_SHUT 4
+#define OSTAT_WARN 5
+#define OSTAT_RUN 6
+#define OSTAT_ON 7
+
+/* Page Zero constant offsets used by the HPMC handler */
+#define BOOT_CONSOLE_HPA_OFFSET 0x3c0
+#define BOOT_CONSOLE_SPA_OFFSET 0x3c4
+#define BOOT_CONSOLE_PATH_OFFSET 0x3a8
+
+/* size of the pdc_result buffer for firmware.c */
+#define NUM_PDC_RESULT 32
+
+#if !defined(__ASSEMBLY__)
+
+/* flags for hardware_path */
+#define PF_AUTOBOOT 0x80
+#define PF_AUTOSEARCH 0x40
+#define PF_TIMER 0x0F
+
+struct hardware_path {
+ unsigned char flags; /* see bit definitions below */
+ signed char bc[6]; /* Bus Converter routing info to a specific */
+ /* I/O adaptor (< 0 means none, > 63 resvd) */
+ signed char mod; /* fixed field of specified module */
+};
+
+struct pdc_module_path { /* page 1-69 */
+ struct hardware_path path;
+ unsigned int layers[6]; /* device-specific info (ctlr #, unit # ...) */
+} __attribute__((aligned(8)));
+
+struct pz_device {
+ struct pdc_module_path dp; /* see above */
+ /* struct iomod *hpa; */
+ unsigned int hpa; /* HPA base address */
+ /* char *spa; */
+ unsigned int spa; /* SPA base address */
+ /* int (*iodc_io)(struct iomod*, ...); */
+ unsigned int iodc_io; /* device entry point */
+ short pad; /* reserved */
+ unsigned short cl_class;/* see below */
+} __attribute__((aligned(8))) ;
+
+struct zeropage {
+ /* [0x000] initialize vectors (VEC) */
+ unsigned int vec_special; /* must be zero */
+ /* int (*vec_pow_fail)(void);*/
+ unsigned int vec_pow_fail; /* power failure handler */
+ /* int (*vec_toc)(void); */
+ unsigned int vec_toc;
+ unsigned int vec_toclen;
+ /* int (*vec_rendz)(void); */
+ unsigned int vec_rendz;
+ int vec_pow_fail_flen;
+ int vec_pad0[3];
+ unsigned int vec_toc_hi;
+ int vec_pad1[6];
+
+ /* [0x040] reserved processor dependent */
+ int pad0[112]; /* in QEMU pad0[0] holds "SeaBIOS\0" */
+
+ /* [0x200] reserved */
+ int pad1[84];
+
+ /* [0x350] memory configuration (MC) */
+ int memc_cont; /* contiguous mem size (bytes) */
+ int memc_phsize; /* physical memory size */
+ int memc_adsize; /* additional mem size, bytes of SPA space used by PDC */
+ unsigned int mem_pdc_hi; /* used for 64-bit */
+
+ /* [0x360] various parameters for the boot-CPU */
+ /* unsigned int *mem_booterr[8]; */
+ unsigned int mem_booterr[8]; /* ptr to boot errors */
+ unsigned int mem_free; /* first location, where OS can be loaded */
+ /* struct iomod *mem_hpa; */
+ unsigned int mem_hpa; /* HPA of the boot-CPU */
+ /* int (*mem_pdc)(int, ...); */
+ unsigned int mem_pdc; /* PDC entry point */
+ unsigned int mem_10msec; /* number of clock ticks in 10msec */
+
+ /* [0x390] initial memory module (IMM) */
+ /* struct iomod *imm_hpa; */
+ unsigned int imm_hpa; /* HPA of the IMM */
+ int imm_soft_boot; /* 0 = was hard boot, 1 = was soft boot */
+ unsigned int imm_spa_size; /* SPA size of the IMM in bytes */
+ unsigned int imm_max_mem; /* bytes of mem in IMM */
+
+ /* [0x3A0] boot console, display device and keyboard */
+ struct pz_device mem_cons; /* description of console device */
+ struct pz_device mem_boot; /* description of boot device */
+ struct pz_device mem_kbd; /* description of keyboard device */
+
+ /* [0x430] reserved */
+ int pad430[116];
+
+ /* [0x600] processor dependent */
+ unsigned int pad600[1];
+ unsigned int proc_sti; /* pointer to STI ROM */
+ unsigned int pad608[126];
+};
+
+struct pdc_chassis_info { /* for PDC_CHASSIS_INFO */
+ unsigned long actcnt; /* actual number of bytes returned */
+ unsigned long maxcnt; /* maximum number of bytes that could be returned */
+};
+
+struct pdc_coproc_cfg { /* for PDC_COPROC_CFG */
+ unsigned long ccr_functional;
+ unsigned long ccr_present;
+ unsigned long revision;
+ unsigned long model;
+};
+
+struct pdc_model { /* for PDC_MODEL */
+ unsigned long hversion;
+ unsigned long sversion;
+ unsigned long hw_id;
+ unsigned long boot_id;
+ unsigned long sw_id;
+ unsigned long sw_cap;
+ unsigned long arch_rev;
+ unsigned long pot_key;
+ unsigned long curr_key;
+ unsigned long width; /* default of PSW_W bit (1=enabled) */
+};
+
+struct pdc_cache_cf { /* for PDC_CACHE (I/D-caches) */
+ unsigned long
+#ifdef __LP64__
+ cc_padW:32,
+#endif
+ cc_alias: 4, /* alias boundaries for virtual addresses */
+ cc_block: 4, /* to determine most efficient stride */
+ cc_line : 3, /* maximum amount written back as a result of store (multiple of 16 bytes) */
+ cc_shift: 2, /* how much to shift cc_block left */
+ cc_wt : 1, /* 0 = WT-Dcache, 1 = WB-Dcache */
+ cc_sh : 2, /* 0 = separate I/D-cache, else shared I/D-cache */
+ cc_cst : 3, /* 0 = incoherent D-cache, 1=coherent D-cache */
+ cc_pad1 : 10, /* reserved */
+ cc_hv : 3; /* hversion dependent */
+};
+
+struct pdc_tlb_cf { /* for PDC_CACHE (I/D-TLB's) */
+ unsigned long tc_pad0:12, /* reserved */
+#ifdef __LP64__
+ tc_padW:32,
+#endif
+ tc_sh : 2, /* 0 = separate I/D-TLB, else shared I/D-TLB */
+ tc_hv : 1, /* HV */
+ tc_page : 1, /* 0 = 2K page-size-machine, 1 = 4k page size */
+ tc_cst : 3, /* 0 = incoherent operations, else coherent operations */
+ tc_aid : 5, /* ITLB: width of access ids of processor (encoded!) */
+ tc_sr : 8; /* ITLB: width of space-registers (encoded) */
+};
+
+struct pdc_cache_info { /* main-PDC_CACHE-structure (caches & TLB's) */
+ /* I-cache */
+ unsigned long ic_size; /* size in bytes */
+ struct pdc_cache_cf ic_conf; /* configuration */
+ unsigned long ic_base; /* base-addr */
+ unsigned long ic_stride;
+ unsigned long ic_count;
+ unsigned long ic_loop;
+ /* D-cache */
+ unsigned long dc_size; /* size in bytes */
+ struct pdc_cache_cf dc_conf; /* configuration */
+ unsigned long dc_base; /* base-addr */
+ unsigned long dc_stride;
+ unsigned long dc_count;
+ unsigned long dc_loop;
+ /* Instruction-TLB */
+ unsigned long it_size; /* number of entries in I-TLB */
+ struct pdc_tlb_cf it_conf; /* I-TLB-configuration */
+ unsigned long it_sp_base;
+ unsigned long it_sp_stride;
+ unsigned long it_sp_count;
+ unsigned long it_off_base;
+ unsigned long it_off_stride;
+ unsigned long it_off_count;
+ unsigned long it_loop;
+ /* data-TLB */
+ unsigned long dt_size; /* number of entries in D-TLB */
+ struct pdc_tlb_cf dt_conf; /* D-TLB-configuration */
+ unsigned long dt_sp_base;
+ unsigned long dt_sp_stride;
+ unsigned long dt_sp_count;
+ unsigned long dt_off_base;
+ unsigned long dt_off_stride;
+ unsigned long dt_off_count;
+ unsigned long dt_loop;
+};
+
+/* Might need adjustment to work with 64-bit firmware */
+struct pdc_iodc { /* PDC_IODC */
+ unsigned char hversion_model;
+ unsigned char hversion;
+ unsigned char spa;
+ unsigned char type;
+ unsigned int sversion_rev:4;
+ unsigned int sversion_model:19;
+ unsigned int sversion_opt:8;
+ unsigned char rev;
+ unsigned char dep;
+ unsigned char features;
+ unsigned char pad1;
+ unsigned int checksum:16;
+ unsigned int length:16;
+ unsigned int pad[15];
+} __attribute__((aligned(8))) ;
+
+/* no BLTBs in pa2.0 processors */
+struct pdc_btlb_info_range {
+ unsigned char res00;
+ unsigned char num_i;
+ unsigned char num_d;
+ unsigned char num_comb;
+};
+
+struct pdc_btlb_info { /* PDC_BLOCK_TLB, return of PDC_BTLB_INFO */
+ unsigned int min_size; /* minimum size of BTLB in pages */
+ unsigned int max_size; /* maximum size of BTLB in pages */
+ struct pdc_btlb_info_range fixed_range_info;
+ struct pdc_btlb_info_range variable_range_info;
+};
+
+struct pdc_mem_retinfo { /* PDC_MEM/PDC_MEM_MEMINFO (return info) */
+ unsigned long pdt_size;
+ unsigned long pdt_entries;
+ unsigned long pdt_status;
+ unsigned long first_dbe_loc;
+ unsigned long good_mem;
+};
+
+struct pdc_mem_read_pdt { /* PDC_MEM/PDC_MEM_READ_PDT (return info) */
+ unsigned long pdt_entries;
+};
+
+#ifdef __LP64__
+struct pdc_memory_table_raddr { /* PDC_MEM/PDC_MEM_TABLE (return info) */
+ unsigned long entries_returned;
+ unsigned long entries_total;
+};
+
+struct pdc_memory_table { /* PDC_MEM/PDC_MEM_TABLE (arguments) */
+ unsigned long paddr;
+ unsigned int pages;
+ unsigned int reserved;
+};
+#endif /* __LP64__ */
+
+struct pdc_system_map_mod_info { /* PDC_SYSTEM_MAP/FIND_MODULE */
+ unsigned long mod_addr;
+ unsigned long mod_pgs;
+ unsigned long add_addrs;
+};
+
+struct pdc_system_map_addr_info { /* PDC_SYSTEM_MAP/FIND_ADDRESS */
+ unsigned long mod_addr;
+ unsigned long mod_pgs;
+};
+
+struct pdc_initiator { /* PDC_INITIATOR */
+ int host_id;
+ int factor;
+ int width;
+ int mode;
+};
+
+/* Only used on some pre-PA2.0 boxes */
+struct pdc_memory_map { /* PDC_MEMORY_MAP */
+ unsigned long hpa; /* mod's register set address */
+ unsigned long more_pgs; /* number of additional I/O pgs */
+};
+
+struct pdc_tod {
+ unsigned long tod_sec;
+ unsigned long tod_usec;
+};
+
+/* architected results from PDC_PIM/transfer hpmc on a PA1.1 machine */
+
+struct pdc_hpmc_pim_11 { /* PDC_PIM */
+ unsigned int gr[32];
+ unsigned int cr[32];
+ unsigned int sr[8];
+ unsigned int iasq_back;
+ unsigned int iaoq_back;
+ unsigned int check_type;
+ unsigned int cpu_state;
+ unsigned int rsvd1;
+ unsigned int cache_check;
+ unsigned int tlb_check;
+ unsigned int bus_check;
+ unsigned int assists_check;
+ unsigned int rsvd2;
+ unsigned int assist_state;
+ unsigned int responder_addr;
+ unsigned int requestor_addr;
+ unsigned int path_info;
+ unsigned long long fr[32];
+};
+
+/*
+ * architected results from PDC_PIM/transfer hpmc on a PA2.0 machine
+ *
+ * Note that PDC_PIM doesn't care whether or not wide mode was enabled
+ * so the results are different on PA1.1 vs. PA2.0 when in narrow mode.
+ *
+ * Note also that there are unarchitected results available, which
+ * are hversion dependent. Do a "ser pim 0 hpmc" after rebooting, since
+ * the firmware is probably the best way of printing hversion dependent
+ * data.
+ */
+
+struct pdc_hpmc_pim_20 { /* PDC_PIM */
+ unsigned long long gr[32];
+ unsigned long long cr[32];
+ unsigned long long sr[8];
+ unsigned long long iasq_back;
+ unsigned long long iaoq_back;
+ unsigned int check_type;
+ unsigned int cpu_state;
+ unsigned int cache_check;
+ unsigned int tlb_check;
+ unsigned int bus_check;
+ unsigned int assists_check;
+ unsigned int assist_state;
+ unsigned int path_info;
+ unsigned long long responder_addr;
+ unsigned long long requestor_addr;
+ unsigned long long fr[32];
+};
+
+struct pim_cpu_state_cf {
+ union {
+ unsigned int
+ iqv : 1, /* IIA queue Valid */
+ iqf : 1, /* IIA queue Failure */
+ ipv : 1, /* IPRs Valid */
+ grv : 1, /* GRs Valid */
+ crv : 1, /* CRs Valid */
+ srv : 1, /* SRs Valid */
+ trv : 1, /* CR24 through CR31 valid */
+ pad : 24, /* reserved */
+ td : 1; /* TOC did not cause any damage to the system state */
+ unsigned int val;
+ };
+};
+
+struct pdc_toc_pim_11 {
+ unsigned int gr[32];
+ unsigned int cr[32];
+ unsigned int sr[8];
+ unsigned int iasq_back;
+ unsigned int iaoq_back;
+ unsigned int check_type;
+ struct pim_cpu_state_cf cpu_state;
+};
+
+struct pdc_toc_pim_20 {
+ unsigned long long gr[32];
+ unsigned long long cr[32];
+ unsigned long long sr[8];
+ unsigned long long iasq_back;
+ unsigned long long iaoq_back;
+ unsigned int check_type;
+ struct pim_cpu_state_cf cpu_state;
+};
+
+#endif /* !defined(__ASSEMBLY__) */
+
+#endif /* _UAPI_PARISC_PDC_H */
diff --git a/arch/parisc/include/uapi/asm/posix_types.h b/arch/parisc/include/uapi/asm/posix_types.h
new file mode 100644
index 000000000..8dce56f5d
--- /dev/null
+++ b/arch/parisc/include/uapi/asm/posix_types.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef __ARCH_PARISC_POSIX_TYPES_H
+#define __ARCH_PARISC_POSIX_TYPES_H
+
+/*
+ * This file is generally used by user-level software, so you need to
+ * be a little careful about namespace pollution etc. Also, we cannot
+ * assume GCC is being used.
+ */
+
+#ifndef __LP64__
+typedef unsigned short __kernel_mode_t;
+#define __kernel_mode_t __kernel_mode_t
+#endif
+
+typedef unsigned short __kernel_ipc_pid_t;
+#define __kernel_ipc_pid_t __kernel_ipc_pid_t
+
+typedef long long __kernel_off64_t;
+typedef unsigned long long __kernel_ino64_t;
+
+#include <asm-generic/posix_types.h>
+
+#endif
diff --git a/arch/parisc/include/uapi/asm/ptrace.h b/arch/parisc/include/uapi/asm/ptrace.h
new file mode 100644
index 000000000..e72e06247
--- /dev/null
+++ b/arch/parisc/include/uapi/asm/ptrace.h
@@ -0,0 +1,96 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/* written by Philipp Rumpf, Copyright (C) 1999 SuSE GmbH Nuernberg
+** Copyright (C) 2000 Grant Grundler, Hewlett-Packard
+*/
+#ifndef _UAPI_PARISC_PTRACE_H
+#define _UAPI_PARISC_PTRACE_H
+
+
+#include <linux/types.h>
+
+/* This struct defines the way the registers are stored on the
+ * stack during a system call.
+ *
+ * N.B. gdb/strace care about the size and offsets within this
+ * structure. If you change things, you may break object compatibility
+ * for those applications.
+ *
+ * Please do NOT use this structure for future programs, but use
+ * user_regs_struct (see below) instead.
+ *
+ * It can be accessed through PTRACE_PEEKUSR/PTRACE_POKEUSR only.
+ */
+
+struct pt_regs {
+ unsigned long gr[32]; /* PSW is in gr[0] */
+ __u64 fr[32];
+ unsigned long sr[ 8];
+ unsigned long iasq[2];
+ unsigned long iaoq[2];
+ unsigned long cr27;
+ unsigned long pad0; /* available for other uses */
+ unsigned long orig_r28;
+ unsigned long ksp;
+ unsigned long kpc;
+ unsigned long sar; /* CR11 */
+ unsigned long iir; /* CR19 */
+ unsigned long isr; /* CR20 */
+ unsigned long ior; /* CR21 */
+ unsigned long ipsw; /* CR22 */
+};
+
+/**
+ * struct user_regs_struct - User general purpose registers
+ *
+ * This is the user-visible general purpose register state structure
+ * which is used to define the elf_gregset_t.
+ *
+ * It can be accessed through PTRACE_GETREGSET with NT_PRSTATUS
+ * and through PTRACE_GETREGS.
+ */
+struct user_regs_struct {
+ unsigned long gr[32]; /* PSW is in gr[0] */
+ unsigned long sr[8];
+ unsigned long iaoq[2];
+ unsigned long iasq[2];
+ unsigned long sar; /* CR11 */
+ unsigned long iir; /* CR19 */
+ unsigned long isr; /* CR20 */
+ unsigned long ior; /* CR21 */
+ unsigned long ipsw; /* CR22 */
+ unsigned long cr0;
+ unsigned long cr24, cr25, cr26, cr27, cr28, cr29, cr30, cr31;
+ unsigned long cr8, cr9, cr12, cr13, cr10, cr15;
+ unsigned long _pad[80-64]; /* pad to ELF_NGREG (80) */
+};
+
+/**
+ * struct user_fp_struct - User floating point registers
+ *
+ * This is the user-visible floating point register state structure.
+ * It uses the same layout and size as elf_fpregset_t.
+ *
+ * It can be accessed through PTRACE_GETREGSET with NT_PRFPREG
+ * and through PTRACE_GETFPREGS.
+ */
+struct user_fp_struct {
+ __u64 fr[32];
+};
+
+
+/*
+ * The numbers chosen here are somewhat arbitrary but absolutely MUST
+ * not overlap with any of the number assigned in <linux/ptrace.h>.
+ *
+ * These ones are taken from IA-64 on the assumption that theirs are
+ * the most correct (and we also want to support PTRACE_SINGLEBLOCK
+ * since we have taken branch traps too)
+ */
+#define PTRACE_SINGLEBLOCK 12 /* resume execution until next branch */
+
+#define PTRACE_GETREGS 18
+#define PTRACE_SETREGS 19
+#define PTRACE_GETFPREGS 14
+#define PTRACE_SETFPREGS 15
+
+#endif /* _UAPI_PARISC_PTRACE_H */
diff --git a/arch/parisc/include/uapi/asm/sembuf.h b/arch/parisc/include/uapi/asm/sembuf.h
new file mode 100644
index 000000000..e2ca4301c
--- /dev/null
+++ b/arch/parisc/include/uapi/asm/sembuf.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _PARISC_SEMBUF_H
+#define _PARISC_SEMBUF_H
+
+#include <asm/bitsperlong.h>
+#include <asm/ipcbuf.h>
+
+/*
+ * The semid64_ds structure for parisc architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct semid64_ds {
+ struct ipc64_perm sem_perm; /* permissions .. see ipc.h */
+#if __BITS_PER_LONG == 64
+ long sem_otime; /* last semop time */
+ long sem_ctime; /* last change time */
+#else
+ unsigned long sem_otime_high;
+ unsigned long sem_otime; /* last semop time */
+ unsigned long sem_ctime_high;
+ unsigned long sem_ctime; /* last change time */
+#endif
+ unsigned long sem_nsems; /* no. of semaphores in array */
+ unsigned long __unused1;
+ unsigned long __unused2;
+};
+
+#endif /* _PARISC_SEMBUF_H */
diff --git a/arch/parisc/include/uapi/asm/setup.h b/arch/parisc/include/uapi/asm/setup.h
new file mode 100644
index 000000000..78b2f4ec7
--- /dev/null
+++ b/arch/parisc/include/uapi/asm/setup.h
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _PARISC_SETUP_H
+#define _PARISC_SETUP_H
+
+#define COMMAND_LINE_SIZE 1024
+
+#endif /* _PARISC_SETUP_H */
diff --git a/arch/parisc/include/uapi/asm/shmbuf.h b/arch/parisc/include/uapi/asm/shmbuf.h
new file mode 100644
index 000000000..532da742f
--- /dev/null
+++ b/arch/parisc/include/uapi/asm/shmbuf.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _PARISC_SHMBUF_H
+#define _PARISC_SHMBUF_H
+
+#include <asm/bitsperlong.h>
+#include <asm/ipcbuf.h>
+#include <asm/posix_types.h>
+
+/*
+ * The shmid64_ds structure for parisc architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 2 miscellaneous 32-bit values
+ */
+
+struct shmid64_ds {
+ struct ipc64_perm shm_perm; /* operation perms */
+#if __BITS_PER_LONG == 64
+ long shm_atime; /* last attach time */
+ long shm_dtime; /* last detach time */
+ long shm_ctime; /* last change time */
+#else
+ unsigned long shm_atime_high;
+ unsigned long shm_atime; /* last attach time */
+ unsigned long shm_dtime_high;
+ unsigned long shm_dtime; /* last detach time */
+ unsigned long shm_ctime_high;
+ unsigned long shm_ctime; /* last change time */
+ unsigned int __pad4;
+#endif
+ __kernel_size_t shm_segsz; /* size of segment (bytes) */
+ __kernel_pid_t shm_cpid; /* pid of creator */
+ __kernel_pid_t shm_lpid; /* pid of last operator */
+ unsigned long shm_nattch; /* no. of current attaches */
+ unsigned long __unused1;
+ unsigned long __unused2;
+};
+
+struct shminfo64 {
+ unsigned long shmmax;
+ unsigned long shmmin;
+ unsigned long shmmni;
+ unsigned long shmseg;
+ unsigned long shmall;
+ unsigned long __unused1;
+ unsigned long __unused2;
+ unsigned long __unused3;
+ unsigned long __unused4;
+};
+
+#endif /* _PARISC_SHMBUF_H */
diff --git a/arch/parisc/include/uapi/asm/sigcontext.h b/arch/parisc/include/uapi/asm/sigcontext.h
new file mode 100644
index 000000000..be404bb0f
--- /dev/null
+++ b/arch/parisc/include/uapi/asm/sigcontext.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _ASMPARISC_SIGCONTEXT_H
+#define _ASMPARISC_SIGCONTEXT_H
+
+#define PARISC_SC_FLAG_ONSTACK 1<<0
+#define PARISC_SC_FLAG_IN_SYSCALL 1<<1
+
+/* We will add more stuff here as it becomes necessary, until we know
+ it works. */
+struct sigcontext {
+ unsigned long sc_flags;
+
+ unsigned long sc_gr[32]; /* PSW in sc_gr[0] */
+ unsigned long long sc_fr[32]; /* FIXME, do we need other state info? */
+ unsigned long sc_iasq[2];
+ unsigned long sc_iaoq[2];
+ unsigned long sc_sar; /* cr11 */
+};
+
+
+#endif
diff --git a/arch/parisc/include/uapi/asm/signal.h b/arch/parisc/include/uapi/asm/signal.h
new file mode 100644
index 000000000..8e4895c5e
--- /dev/null
+++ b/arch/parisc/include/uapi/asm/signal.h
@@ -0,0 +1,74 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _UAPI_ASM_PARISC_SIGNAL_H
+#define _UAPI_ASM_PARISC_SIGNAL_H
+
+#define SIGHUP 1
+#define SIGINT 2
+#define SIGQUIT 3
+#define SIGILL 4
+#define SIGTRAP 5
+#define SIGABRT 6
+#define SIGIOT 6
+#define SIGSTKFLT 7
+#define SIGFPE 8
+#define SIGKILL 9
+#define SIGBUS 10
+#define SIGSEGV 11
+#define SIGXCPU 12
+#define SIGPIPE 13
+#define SIGALRM 14
+#define SIGTERM 15
+#define SIGUSR1 16
+#define SIGUSR2 17
+#define SIGCHLD 18
+#define SIGPWR 19
+#define SIGVTALRM 20
+#define SIGPROF 21
+#define SIGIO 22
+#define SIGPOLL SIGIO
+#define SIGWINCH 23
+#define SIGSTOP 24
+#define SIGTSTP 25
+#define SIGCONT 26
+#define SIGTTIN 27
+#define SIGTTOU 28
+#define SIGURG 29
+#define SIGXFSZ 30
+#define SIGUNUSED 31
+#define SIGSYS 31
+
+/* These should not be considered constants from userland. */
+#define SIGRTMIN 32
+#define SIGRTMAX _NSIG
+
+#define SA_ONSTACK 0x00000001
+#define SA_RESETHAND 0x00000004
+#define SA_NOCLDSTOP 0x00000008
+#define SA_SIGINFO 0x00000010
+#define SA_NODEFER 0x00000020
+#define SA_RESTART 0x00000040
+#define SA_NOCLDWAIT 0x00000080
+
+#define SA_NOMASK SA_NODEFER
+#define SA_ONESHOT SA_RESETHAND
+
+#define MINSIGSTKSZ 2048
+#define SIGSTKSZ 8192
+
+#include <asm-generic/signal-defs.h>
+
+# ifndef __ASSEMBLY__
+
+# include <linux/types.h>
+
+/* Avoid too many header ordering problems. */
+struct siginfo;
+
+typedef struct sigaltstack {
+ void __user *ss_sp;
+ int ss_flags;
+ __kernel_size_t ss_size;
+} stack_t;
+
+#endif /* !__ASSEMBLY */
+#endif /* _UAPI_ASM_PARISC_SIGNAL_H */
diff --git a/arch/parisc/include/uapi/asm/socket.h b/arch/parisc/include/uapi/asm/socket.h
new file mode 100644
index 000000000..be264c2b1
--- /dev/null
+++ b/arch/parisc/include/uapi/asm/socket.h
@@ -0,0 +1,158 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _UAPI_ASM_SOCKET_H
+#define _UAPI_ASM_SOCKET_H
+
+#include <linux/posix_types.h>
+#include <asm/sockios.h>
+
+/* For setsockopt(2) */
+#define SOL_SOCKET 0xffff
+
+#define SO_DEBUG 0x0001
+#define SO_REUSEADDR 0x0004
+#define SO_KEEPALIVE 0x0008
+#define SO_DONTROUTE 0x0010
+#define SO_BROADCAST 0x0020
+#define SO_LINGER 0x0080
+#define SO_OOBINLINE 0x0100
+#define SO_REUSEPORT 0x0200
+#define SO_SNDBUF 0x1001
+#define SO_RCVBUF 0x1002
+#define SO_SNDBUFFORCE 0x100a
+#define SO_RCVBUFFORCE 0x100b
+#define SO_SNDLOWAT 0x1003
+#define SO_RCVLOWAT 0x1004
+#define SO_SNDTIMEO_OLD 0x1005
+#define SO_RCVTIMEO_OLD 0x1006
+#define SO_ERROR 0x1007
+#define SO_TYPE 0x1008
+#define SO_PROTOCOL 0x1028
+#define SO_DOMAIN 0x1029
+#define SO_PEERNAME 0x2000
+
+#define SO_NO_CHECK 0x400b
+#define SO_PRIORITY 0x400c
+#define SO_BSDCOMPAT 0x400e
+#define SO_PASSCRED 0x4010
+#define SO_PEERCRED 0x4011
+
+/* Security levels - as per NRL IPv6 - don't actually do anything */
+#define SO_SECURITY_AUTHENTICATION 0x4016
+#define SO_SECURITY_ENCRYPTION_TRANSPORT 0x4017
+#define SO_SECURITY_ENCRYPTION_NETWORK 0x4018
+
+#define SO_BINDTODEVICE 0x4019
+
+/* Socket filtering */
+#define SO_ATTACH_FILTER 0x401a
+#define SO_DETACH_FILTER 0x401b
+#define SO_GET_FILTER SO_ATTACH_FILTER
+
+#define SO_ACCEPTCONN 0x401c
+
+#define SO_PEERSEC 0x401d
+#define SO_PASSSEC 0x401e
+
+#define SO_MARK 0x401f
+
+#define SO_RXQ_OVFL 0x4021
+
+#define SO_WIFI_STATUS 0x4022
+#define SCM_WIFI_STATUS SO_WIFI_STATUS
+#define SO_PEEK_OFF 0x4023
+
+/* Instruct lower device to use last 4-bytes of skb data as FCS */
+#define SO_NOFCS 0x4024
+
+#define SO_LOCK_FILTER 0x4025
+
+#define SO_SELECT_ERR_QUEUE 0x4026
+
+#define SO_BUSY_POLL 0x4027
+
+#define SO_MAX_PACING_RATE 0x4028
+
+#define SO_BPF_EXTENSIONS 0x4029
+
+#define SO_INCOMING_CPU 0x402A
+
+#define SO_ATTACH_BPF 0x402B
+#define SO_DETACH_BPF SO_DETACH_FILTER
+
+#define SO_ATTACH_REUSEPORT_CBPF 0x402C
+#define SO_ATTACH_REUSEPORT_EBPF 0x402D
+
+#define SO_CNX_ADVICE 0x402E
+
+#define SCM_TIMESTAMPING_OPT_STATS 0x402F
+
+#define SO_MEMINFO 0x4030
+
+#define SO_INCOMING_NAPI_ID 0x4031
+
+#define SO_COOKIE 0x4032
+
+#define SCM_TIMESTAMPING_PKTINFO 0x4033
+
+#define SO_PEERGROUPS 0x4034
+
+#define SO_ZEROCOPY 0x4035
+
+#define SO_TXTIME 0x4036
+#define SCM_TXTIME SO_TXTIME
+
+#define SO_BINDTOIFINDEX 0x4037
+
+#define SO_TIMESTAMP_OLD 0x4012
+#define SO_TIMESTAMPNS_OLD 0x4013
+#define SO_TIMESTAMPING_OLD 0x4020
+
+#define SO_TIMESTAMP_NEW 0x4038
+#define SO_TIMESTAMPNS_NEW 0x4039
+#define SO_TIMESTAMPING_NEW 0x403A
+
+#define SO_RCVTIMEO_NEW 0x4040
+#define SO_SNDTIMEO_NEW 0x4041
+
+#define SO_DETACH_REUSEPORT_BPF 0x4042
+
+#define SO_PREFER_BUSY_POLL 0x4043
+#define SO_BUSY_POLL_BUDGET 0x4044
+
+#define SO_NETNS_COOKIE 0x4045
+
+#define SO_BUF_LOCK 0x4046
+
+#define SO_RESERVE_MEM 0x4047
+
+#define SO_TXREHASH 0x4048
+
+#define SO_RCVMARK 0x4049
+
+#define SO_PASSPIDFD 0x404A
+#define SO_PEERPIDFD 0x404B
+
+#if !defined(__KERNEL__)
+
+#if __BITS_PER_LONG == 64
+#define SO_TIMESTAMP SO_TIMESTAMP_OLD
+#define SO_TIMESTAMPNS SO_TIMESTAMPNS_OLD
+#define SO_TIMESTAMPING SO_TIMESTAMPING_OLD
+#define SO_RCVTIMEO SO_RCVTIMEO_OLD
+#define SO_SNDTIMEO SO_SNDTIMEO_OLD
+#else
+#define SO_TIMESTAMP (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_TIMESTAMP_OLD : SO_TIMESTAMP_NEW)
+#define SO_TIMESTAMPNS (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_TIMESTAMPNS_OLD : SO_TIMESTAMPNS_NEW)
+#define SO_TIMESTAMPING (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_TIMESTAMPING_OLD : SO_TIMESTAMPING_NEW)
+
+#define SO_RCVTIMEO (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_RCVTIMEO_OLD : SO_RCVTIMEO_NEW)
+#define SO_SNDTIMEO (sizeof(time_t) == sizeof(__kernel_long_t) ? SO_SNDTIMEO_OLD : SO_SNDTIMEO_NEW)
+#endif
+
+#define SCM_TIMESTAMP SO_TIMESTAMP
+#define SCM_TIMESTAMPNS SO_TIMESTAMPNS
+#define SCM_TIMESTAMPING SO_TIMESTAMPING
+
+#endif
+
+#endif /* _UAPI_ASM_SOCKET_H */
diff --git a/arch/parisc/include/uapi/asm/stat.h b/arch/parisc/include/uapi/asm/stat.h
new file mode 100644
index 000000000..b5bbf6704
--- /dev/null
+++ b/arch/parisc/include/uapi/asm/stat.h
@@ -0,0 +1,68 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _PARISC_STAT_H
+#define _PARISC_STAT_H
+
+#include <linux/types.h>
+
+struct stat {
+ unsigned int st_dev; /* dev_t is 32 bits on parisc */
+ unsigned int st_ino; /* 32 bits */
+ unsigned short st_mode; /* 16 bits */
+ unsigned short st_nlink; /* 16 bits */
+ unsigned short st_reserved1; /* old st_uid */
+ unsigned short st_reserved2; /* old st_gid */
+ unsigned int st_rdev;
+ signed int st_size;
+ signed int st_atime;
+ unsigned int st_atime_nsec;
+ signed int st_mtime;
+ unsigned int st_mtime_nsec;
+ signed int st_ctime;
+ unsigned int st_ctime_nsec;
+ int st_blksize;
+ int st_blocks;
+ unsigned int __unused1; /* ACL stuff */
+ unsigned int __unused2; /* network */
+ unsigned int __unused3; /* network */
+ unsigned int __unused4; /* cnodes */
+ unsigned short __unused5; /* netsite */
+ short st_fstype;
+ unsigned int st_realdev;
+ unsigned short st_basemode;
+ unsigned short st_spareshort;
+ unsigned int st_uid;
+ unsigned int st_gid;
+ unsigned int st_spare4[3];
+};
+
+#define STAT_HAVE_NSEC
+
+/* This is the struct that 32-bit userspace applications are expecting.
+ * How 64-bit apps are going to be compiled, I have no idea. But at least
+ * this way, we don't have a wrapper in the kernel.
+ */
+struct stat64 {
+ unsigned long long st_dev;
+ unsigned int __pad1;
+
+ unsigned int __st_ino; /* Not actually filled in */
+ unsigned int st_mode;
+ unsigned int st_nlink;
+ unsigned int st_uid;
+ unsigned int st_gid;
+ unsigned long long st_rdev;
+ unsigned int __pad2;
+ signed long long st_size;
+ signed int st_blksize;
+
+ signed long long st_blocks;
+ signed int st_atime;
+ unsigned int st_atime_nsec;
+ signed int st_mtime;
+ unsigned int st_mtime_nsec;
+ signed int st_ctime;
+ unsigned int st_ctime_nsec;
+ unsigned long long st_ino;
+};
+
+#endif
diff --git a/arch/parisc/include/uapi/asm/statfs.h b/arch/parisc/include/uapi/asm/statfs.h
new file mode 100644
index 000000000..e5de020c2
--- /dev/null
+++ b/arch/parisc/include/uapi/asm/statfs.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _PARISC_STATFS_H
+#define _PARISC_STATFS_H
+
+#define __statfs_word long
+#include <asm-generic/statfs.h>
+
+#endif
diff --git a/arch/parisc/include/uapi/asm/termbits.h b/arch/parisc/include/uapi/asm/termbits.h
new file mode 100644
index 000000000..3a8938d26
--- /dev/null
+++ b/arch/parisc/include/uapi/asm/termbits.h
@@ -0,0 +1,149 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef __ARCH_PARISC_TERMBITS_H__
+#define __ARCH_PARISC_TERMBITS_H__
+
+#include <asm-generic/termbits-common.h>
+
+typedef unsigned int tcflag_t;
+
+#define NCCS 19
+struct termios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+};
+
+struct termios2 {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
+struct ktermios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
+/* c_cc characters */
+#define VINTR 0
+#define VQUIT 1
+#define VERASE 2
+#define VKILL 3
+#define VEOF 4
+#define VTIME 5
+#define VMIN 6
+#define VSWTC 7
+#define VSTART 8
+#define VSTOP 9
+#define VSUSP 10
+#define VEOL 11
+#define VREPRINT 12
+#define VDISCARD 13
+#define VWERASE 14
+#define VLNEXT 15
+#define VEOL2 16
+
+/* c_iflag bits */
+#define IUCLC 0x0200
+#define IXON 0x0400
+#define IXOFF 0x1000
+#define IMAXBEL 0x4000
+#define IUTF8 0x8000
+
+/* c_oflag bits */
+#define OLCUC 0x00002
+#define ONLCR 0x00004
+#define NLDLY 0x00100
+#define NL0 0x00000
+#define NL1 0x00100
+#define CRDLY 0x00600
+#define CR0 0x00000
+#define CR1 0x00200
+#define CR2 0x00400
+#define CR3 0x00600
+#define TABDLY 0x01800
+#define TAB0 0x00000
+#define TAB1 0x00800
+#define TAB2 0x01000
+#define TAB3 0x01800
+#define XTABS 0x01800
+#define BSDLY 0x02000
+#define BS0 0x00000
+#define BS1 0x02000
+#define VTDLY 0x04000
+#define VT0 0x00000
+#define VT1 0x04000
+#define FFDLY 0x08000
+#define FF0 0x00000
+#define FF1 0x08000
+
+/* c_cflag bit meaning */
+#define CBAUD 0x0000100f
+#define CSIZE 0x00000030
+#define CS5 0x00000000
+#define CS6 0x00000010
+#define CS7 0x00000020
+#define CS8 0x00000030
+#define CSTOPB 0x00000040
+#define CREAD 0x00000080
+#define PARENB 0x00000100
+#define PARODD 0x00000200
+#define HUPCL 0x00000400
+#define CLOCAL 0x00000800
+#define CBAUDEX 0x00001000
+#define BOTHER 0x00001000
+#define B57600 0x00001001
+#define B115200 0x00001002
+#define B230400 0x00001003
+#define B460800 0x00001004
+#define B500000 0x00001005
+#define B576000 0x00001006
+#define B921600 0x00001007
+#define B1000000 0x00001008
+#define B1152000 0x00001009
+#define B1500000 0x0000100a
+#define B2000000 0x0000100b
+#define B2500000 0x0000100c
+#define B3000000 0x0000100d
+#define B3500000 0x0000100e
+#define B4000000 0x0000100f
+#define CIBAUD 0x100f0000 /* input baud rate */
+
+/* c_lflag bits */
+#define ISIG 0x00001
+#define ICANON 0x00002
+#define XCASE 0x00004
+#define ECHO 0x00008
+#define ECHOE 0x00010
+#define ECHOK 0x00020
+#define ECHONL 0x00040
+#define NOFLSH 0x00080
+#define TOSTOP 0x00100
+#define ECHOCTL 0x00200
+#define ECHOPRT 0x00400
+#define ECHOKE 0x00800
+#define FLUSHO 0x01000
+#define PENDIN 0x04000
+#define IEXTEN 0x08000
+#define EXTPROC 0x10000
+
+/* tcsetattr uses these */
+#define TCSANOW 0
+#define TCSADRAIN 1
+#define TCSAFLUSH 2
+
+#endif
diff --git a/arch/parisc/include/uapi/asm/unistd.h b/arch/parisc/include/uapi/asm/unistd.h
new file mode 100644
index 000000000..98dc95365
--- /dev/null
+++ b/arch/parisc/include/uapi/asm/unistd.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _UAPI_ASM_PARISC_UNISTD_H_
+#define _UAPI_ASM_PARISC_UNISTD_H_
+
+#ifdef __LP64__
+#include <asm/unistd_64.h>
+#else
+#include <asm/unistd_32.h>
+#endif
+
+#define LINUX_GATEWAY_ADDR 0x100
+
+#endif /* _UAPI_ASM_PARISC_UNISTD_H_ */
diff --git a/arch/parisc/install.sh b/arch/parisc/install.sh
new file mode 100755
index 000000000..933d031c2
--- /dev/null
+++ b/arch/parisc/install.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License. See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+# Copyright (C) 1995 by Linus Torvalds
+#
+# Adapted from code in arch/i386/boot/Makefile by H. Peter Anvin
+#
+# "make install" script for i386 architecture
+#
+# Arguments:
+# $1 - kernel version
+# $2 - kernel image file
+# $3 - kernel map file
+# $4 - default install path (blank if root directory)
+
+if [ "$(basename $2)" = "vmlinuz" ]; then
+# Compressed install
+ echo "Installing compressed kernel"
+ base=vmlinuz
+else
+# Normal install
+ echo "Installing normal kernel"
+ base=vmlinux
+fi
+
+if [ -f $4/$base-$1 ]; then
+ mv $4/$base-$1 $4/$base-$1.old
+fi
+cat $2 > $4/$base-$1
+
+# Install system map file
+if [ -f $4/System.map-$1 ]; then
+ mv $4/System.map-$1 $4/System.map-$1.old
+fi
+cp $3 $4/System.map-$1
+
diff --git a/arch/parisc/kernel/.gitignore b/arch/parisc/kernel/.gitignore
new file mode 100644
index 000000000..bbb90f92d
--- /dev/null
+++ b/arch/parisc/kernel/.gitignore
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0-only
+vmlinux.lds
diff --git a/arch/parisc/kernel/Makefile b/arch/parisc/kernel/Makefile
new file mode 100644
index 000000000..5ab0467be
--- /dev/null
+++ b/arch/parisc/kernel/Makefile
@@ -0,0 +1,49 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for arch/parisc/kernel
+#
+
+extra-y := vmlinux.lds
+
+obj-y := head.o cache.o pacache.o setup.o pdt.o traps.o time.o irq.o \
+ syscall.o entry.o sys_parisc.o firmware.o \
+ ptrace.o hardware.o inventory.o drivers.o alternative.o \
+ signal.o hpmc.o real2.o parisc_ksyms.o unaligned.o \
+ process.o processor.o pdc_cons.o pdc_chassis.o unwind.o \
+ patch.o toc.o toc_asm.o
+
+ifdef CONFIG_FUNCTION_TRACER
+# Do not profile debug and lowlevel utilities
+CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE)
+CFLAGS_REMOVE_cache.o = $(CC_FLAGS_FTRACE)
+CFLAGS_REMOVE_perf.o = $(CC_FLAGS_FTRACE)
+CFLAGS_REMOVE_unwind.o = $(CC_FLAGS_FTRACE)
+CFLAGS_REMOVE_patch.o = $(CC_FLAGS_FTRACE)
+endif
+
+CFLAGS_REMOVE_sys_parisc.o = -Wmissing-prototypes -Wmissing-declarations
+CFLAGS_REMOVE_sys_parisc32.o = -Wmissing-prototypes -Wmissing-declarations
+
+obj-$(CONFIG_SMP) += smp.o
+obj-$(CONFIG_PA11) += pci-dma.o
+obj-$(CONFIG_PCI) += pci.o
+obj-$(CONFIG_MODULES) += module.o
+obj-$(CONFIG_64BIT) += sys_parisc32.o signal32.o
+obj-$(CONFIG_STACKTRACE)+= stacktrace.o
+obj-$(CONFIG_AUDIT) += audit.o
+obj64-$(CONFIG_AUDIT) += compat_audit.o
+# only supported for PCX-W/U in 64-bit mode at the moment
+obj-$(CONFIG_64BIT) += perf.o perf_asm.o $(obj64-y)
+obj-$(CONFIG_GENERIC_ARCH_TOPOLOGY) += topology.o
+obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o
+obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
+obj-$(CONFIG_JUMP_LABEL) += jump_label.o
+obj-$(CONFIG_KGDB) += kgdb.o
+obj-$(CONFIG_KPROBES) += kprobes.o
+obj-$(CONFIG_KEXEC_CORE) += kexec.o relocate_kernel.o
+obj-$(CONFIG_KEXEC_FILE) += kexec_file.o
+
+# vdso
+obj-y += vdso.o
+obj-$(CONFIG_64BIT) += vdso64/
+obj-y += vdso32/
diff --git a/arch/parisc/kernel/alternative.c b/arch/parisc/kernel/alternative.c
new file mode 100644
index 000000000..25c4d6c33
--- /dev/null
+++ b/arch/parisc/kernel/alternative.c
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Alternative live-patching for parisc.
+ * Copyright (C) 2018 Helge Deller <deller@gmx.de>
+ *
+ */
+
+#include <asm/processor.h>
+#include <asm/sections.h>
+#include <asm/alternative.h>
+#include <asm/cacheflush.h>
+
+#include <linux/module.h>
+
+static int no_alternatives;
+static int __init setup_no_alternatives(char *str)
+{
+ no_alternatives = 1;
+ return 1;
+}
+__setup("no-alternatives", setup_no_alternatives);
+
+void __init_or_module apply_alternatives(struct alt_instr *start,
+ struct alt_instr *end, const char *module_name)
+{
+ struct alt_instr *entry;
+ int index = 0, applied = 0;
+ int num_cpus = num_present_cpus();
+ u16 cond_check;
+
+ cond_check = ALT_COND_ALWAYS |
+ ((num_cpus == 1) ? ALT_COND_NO_SMP : 0) |
+ ((cache_info.dc_size == 0) ? ALT_COND_NO_DCACHE : 0) |
+ ((cache_info.ic_size == 0) ? ALT_COND_NO_ICACHE : 0) |
+ (running_on_qemu ? ALT_COND_RUN_ON_QEMU : 0) |
+ ((split_tlb == 0) ? ALT_COND_NO_SPLIT_TLB : 0) |
+ /*
+ * If the PDC_MODEL capabilities has Non-coherent IO-PDIR bit
+ * set (bit #61, big endian), we have to flush and sync every
+ * time IO-PDIR is changed in Ike/Astro.
+ */
+ (((boot_cpu_data.cpu_type > pcxw_) &&
+ ((boot_cpu_data.pdc.capabilities & PDC_MODEL_IOPDIR_FDC) == 0))
+ ? ALT_COND_NO_IOC_FDC : 0);
+
+ for (entry = start; entry < end; entry++, index++) {
+
+ u32 *from, replacement;
+ u16 cond;
+ s16 len;
+
+ from = (u32 *)((ulong)&entry->orig_offset + entry->orig_offset);
+ len = entry->len;
+ cond = entry->cond;
+ replacement = entry->replacement;
+
+ WARN_ON(!cond);
+
+ if ((cond & ALT_COND_ALWAYS) == 0 && no_alternatives)
+ continue;
+
+ pr_debug("Check %d: Cond 0x%x, Replace %02d instructions @ 0x%px with 0x%08x\n",
+ index, cond, len, from, replacement);
+
+ /* Bounce out if none of the conditions are true. */
+ if ((cond & cond_check) == 0)
+ continue;
+
+ /* Want to replace pdtlb by a pdtlb,l instruction? */
+ if (replacement == INSN_PxTLB) {
+ replacement = *from;
+ if (boot_cpu_data.cpu_type >= pcxu) /* >= pa2.0 ? */
+ replacement |= (1 << 10); /* set el bit */
+ }
+
+ /*
+ * Replace instruction with NOPs?
+ * For long distance insert a branch instruction instead.
+ */
+ if (replacement == INSN_NOP && len > 1)
+ replacement = 0xe8000002 + (len-2)*8; /* "b,n .+8" */
+
+ pr_debug("ALTERNATIVE %3d: Cond %2x, Replace %2d instructions to 0x%08x @ 0x%px (%pS)\n",
+ index, cond, len, replacement, from, from);
+
+ if (len < 0) {
+ /* Replace multiple instruction by new code */
+ u32 *source;
+ len = -len;
+ source = (u32 *)((ulong)&entry->replacement + entry->replacement);
+ memcpy(from, source, 4 * len);
+ } else {
+ /* Replace by one instruction */
+ *from = replacement;
+ }
+ applied++;
+ }
+
+ pr_info("%s%salternatives: applied %d out of %d patches\n",
+ module_name ? : "", module_name ? " " : "",
+ applied, index);
+}
+
+
+void __init apply_alternatives_all(void)
+{
+ set_kernel_text_rw(1);
+
+ apply_alternatives((struct alt_instr *) &__alt_instructions,
+ (struct alt_instr *) &__alt_instructions_end, NULL);
+
+ if (cache_info.dc_size == 0 && cache_info.ic_size == 0) {
+ pr_info("alternatives: optimizing cache-flushes.\n");
+ static_branch_disable(&parisc_has_cache);
+ }
+ if (cache_info.dc_size == 0)
+ static_branch_disable(&parisc_has_dcache);
+ if (cache_info.ic_size == 0)
+ static_branch_disable(&parisc_has_icache);
+
+ set_kernel_text_rw(0);
+}
diff --git a/arch/parisc/kernel/asm-offsets.c b/arch/parisc/kernel/asm-offsets.c
new file mode 100644
index 000000000..757816a7b
--- /dev/null
+++ b/arch/parisc/kernel/asm-offsets.c
@@ -0,0 +1,287 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Generate definitions needed by assembly language modules.
+ * This code generates raw asm output which is post-processed to extract
+ * and format the required data.
+ *
+ * Copyright (C) 2000-2001 John Marvin <jsm at parisc-linux.org>
+ * Copyright (C) 2000 David Huggins-Daines <dhd with pobox.org>
+ * Copyright (C) 2000 Sam Creasey <sammy@sammy.net>
+ * Copyright (C) 2000 Grant Grundler <grundler with parisc-linux.org>
+ * Copyright (C) 2001 Paul Bame <bame at parisc-linux.org>
+ * Copyright (C) 2001 Richard Hirst <rhirst at parisc-linux.org>
+ * Copyright (C) 2002 Randolph Chung <tausq with parisc-linux.org>
+ * Copyright (C) 2003 James Bottomley <jejb at parisc-linux.org>
+ */
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/thread_info.h>
+#include <linux/ptrace.h>
+#include <linux/hardirq.h>
+#include <linux/kbuild.h>
+#include <linux/pgtable.h>
+
+#include <asm/assembly.h>
+#include <asm/ptrace.h>
+#include <asm/processor.h>
+#include <asm/pdc.h>
+#include <uapi/asm/sigcontext.h>
+#include <asm/ucontext.h>
+#include <asm/rt_sigframe.h>
+#include <linux/uaccess.h>
+#include "signal32.h"
+
+/* Add FRAME_SIZE to the size x and align it to y. All definitions
+ * that use align_frame will include space for a frame.
+ */
+#define align_frame(x,y) (((x)+FRAME_SIZE+(y)-1) - (((x)+(y)-1)%(y)))
+
+int main(void)
+{
+ DEFINE(TASK_TI_FLAGS, offsetof(struct task_struct, thread_info.flags));
+#ifdef CONFIG_SMP
+ DEFINE(TASK_TI_CPU, offsetof(struct task_struct, thread_info.cpu));
+#endif
+ DEFINE(TASK_STACK, offsetof(struct task_struct, stack));
+ DEFINE(TASK_PAGEFAULT_DISABLED, offsetof(struct task_struct, pagefault_disabled));
+ BLANK();
+ DEFINE(TASK_REGS, offsetof(struct task_struct, thread.regs));
+ DEFINE(TASK_PT_PSW, offsetof(struct task_struct, thread.regs.gr[ 0]));
+ DEFINE(TASK_PT_GR1, offsetof(struct task_struct, thread.regs.gr[ 1]));
+ DEFINE(TASK_PT_GR2, offsetof(struct task_struct, thread.regs.gr[ 2]));
+ DEFINE(TASK_PT_GR3, offsetof(struct task_struct, thread.regs.gr[ 3]));
+ DEFINE(TASK_PT_GR4, offsetof(struct task_struct, thread.regs.gr[ 4]));
+ DEFINE(TASK_PT_GR5, offsetof(struct task_struct, thread.regs.gr[ 5]));
+ DEFINE(TASK_PT_GR6, offsetof(struct task_struct, thread.regs.gr[ 6]));
+ DEFINE(TASK_PT_GR7, offsetof(struct task_struct, thread.regs.gr[ 7]));
+ DEFINE(TASK_PT_GR8, offsetof(struct task_struct, thread.regs.gr[ 8]));
+ DEFINE(TASK_PT_GR9, offsetof(struct task_struct, thread.regs.gr[ 9]));
+ DEFINE(TASK_PT_GR10, offsetof(struct task_struct, thread.regs.gr[10]));
+ DEFINE(TASK_PT_GR11, offsetof(struct task_struct, thread.regs.gr[11]));
+ DEFINE(TASK_PT_GR12, offsetof(struct task_struct, thread.regs.gr[12]));
+ DEFINE(TASK_PT_GR13, offsetof(struct task_struct, thread.regs.gr[13]));
+ DEFINE(TASK_PT_GR14, offsetof(struct task_struct, thread.regs.gr[14]));
+ DEFINE(TASK_PT_GR15, offsetof(struct task_struct, thread.regs.gr[15]));
+ DEFINE(TASK_PT_GR16, offsetof(struct task_struct, thread.regs.gr[16]));
+ DEFINE(TASK_PT_GR17, offsetof(struct task_struct, thread.regs.gr[17]));
+ DEFINE(TASK_PT_GR18, offsetof(struct task_struct, thread.regs.gr[18]));
+ DEFINE(TASK_PT_GR19, offsetof(struct task_struct, thread.regs.gr[19]));
+ DEFINE(TASK_PT_GR20, offsetof(struct task_struct, thread.regs.gr[20]));
+ DEFINE(TASK_PT_GR21, offsetof(struct task_struct, thread.regs.gr[21]));
+ DEFINE(TASK_PT_GR22, offsetof(struct task_struct, thread.regs.gr[22]));
+ DEFINE(TASK_PT_GR23, offsetof(struct task_struct, thread.regs.gr[23]));
+ DEFINE(TASK_PT_GR24, offsetof(struct task_struct, thread.regs.gr[24]));
+ DEFINE(TASK_PT_GR25, offsetof(struct task_struct, thread.regs.gr[25]));
+ DEFINE(TASK_PT_GR26, offsetof(struct task_struct, thread.regs.gr[26]));
+ DEFINE(TASK_PT_GR27, offsetof(struct task_struct, thread.regs.gr[27]));
+ DEFINE(TASK_PT_GR28, offsetof(struct task_struct, thread.regs.gr[28]));
+ DEFINE(TASK_PT_GR29, offsetof(struct task_struct, thread.regs.gr[29]));
+ DEFINE(TASK_PT_GR30, offsetof(struct task_struct, thread.regs.gr[30]));
+ DEFINE(TASK_PT_GR31, offsetof(struct task_struct, thread.regs.gr[31]));
+ DEFINE(TASK_PT_FR0, offsetof(struct task_struct, thread.regs.fr[ 0]));
+ DEFINE(TASK_PT_FR1, offsetof(struct task_struct, thread.regs.fr[ 1]));
+ DEFINE(TASK_PT_FR2, offsetof(struct task_struct, thread.regs.fr[ 2]));
+ DEFINE(TASK_PT_FR3, offsetof(struct task_struct, thread.regs.fr[ 3]));
+ DEFINE(TASK_PT_FR4, offsetof(struct task_struct, thread.regs.fr[ 4]));
+ DEFINE(TASK_PT_FR5, offsetof(struct task_struct, thread.regs.fr[ 5]));
+ DEFINE(TASK_PT_FR6, offsetof(struct task_struct, thread.regs.fr[ 6]));
+ DEFINE(TASK_PT_FR7, offsetof(struct task_struct, thread.regs.fr[ 7]));
+ DEFINE(TASK_PT_FR8, offsetof(struct task_struct, thread.regs.fr[ 8]));
+ DEFINE(TASK_PT_FR9, offsetof(struct task_struct, thread.regs.fr[ 9]));
+ DEFINE(TASK_PT_FR10, offsetof(struct task_struct, thread.regs.fr[10]));
+ DEFINE(TASK_PT_FR11, offsetof(struct task_struct, thread.regs.fr[11]));
+ DEFINE(TASK_PT_FR12, offsetof(struct task_struct, thread.regs.fr[12]));
+ DEFINE(TASK_PT_FR13, offsetof(struct task_struct, thread.regs.fr[13]));
+ DEFINE(TASK_PT_FR14, offsetof(struct task_struct, thread.regs.fr[14]));
+ DEFINE(TASK_PT_FR15, offsetof(struct task_struct, thread.regs.fr[15]));
+ DEFINE(TASK_PT_FR16, offsetof(struct task_struct, thread.regs.fr[16]));
+ DEFINE(TASK_PT_FR17, offsetof(struct task_struct, thread.regs.fr[17]));
+ DEFINE(TASK_PT_FR18, offsetof(struct task_struct, thread.regs.fr[18]));
+ DEFINE(TASK_PT_FR19, offsetof(struct task_struct, thread.regs.fr[19]));
+ DEFINE(TASK_PT_FR20, offsetof(struct task_struct, thread.regs.fr[20]));
+ DEFINE(TASK_PT_FR21, offsetof(struct task_struct, thread.regs.fr[21]));
+ DEFINE(TASK_PT_FR22, offsetof(struct task_struct, thread.regs.fr[22]));
+ DEFINE(TASK_PT_FR23, offsetof(struct task_struct, thread.regs.fr[23]));
+ DEFINE(TASK_PT_FR24, offsetof(struct task_struct, thread.regs.fr[24]));
+ DEFINE(TASK_PT_FR25, offsetof(struct task_struct, thread.regs.fr[25]));
+ DEFINE(TASK_PT_FR26, offsetof(struct task_struct, thread.regs.fr[26]));
+ DEFINE(TASK_PT_FR27, offsetof(struct task_struct, thread.regs.fr[27]));
+ DEFINE(TASK_PT_FR28, offsetof(struct task_struct, thread.regs.fr[28]));
+ DEFINE(TASK_PT_FR29, offsetof(struct task_struct, thread.regs.fr[29]));
+ DEFINE(TASK_PT_FR30, offsetof(struct task_struct, thread.regs.fr[30]));
+ DEFINE(TASK_PT_FR31, offsetof(struct task_struct, thread.regs.fr[31]));
+ DEFINE(TASK_PT_SR0, offsetof(struct task_struct, thread.regs.sr[ 0]));
+ DEFINE(TASK_PT_SR1, offsetof(struct task_struct, thread.regs.sr[ 1]));
+ DEFINE(TASK_PT_SR2, offsetof(struct task_struct, thread.regs.sr[ 2]));
+ DEFINE(TASK_PT_SR3, offsetof(struct task_struct, thread.regs.sr[ 3]));
+ DEFINE(TASK_PT_SR4, offsetof(struct task_struct, thread.regs.sr[ 4]));
+ DEFINE(TASK_PT_SR5, offsetof(struct task_struct, thread.regs.sr[ 5]));
+ DEFINE(TASK_PT_SR6, offsetof(struct task_struct, thread.regs.sr[ 6]));
+ DEFINE(TASK_PT_SR7, offsetof(struct task_struct, thread.regs.sr[ 7]));
+ DEFINE(TASK_PT_IASQ0, offsetof(struct task_struct, thread.regs.iasq[0]));
+ DEFINE(TASK_PT_IASQ1, offsetof(struct task_struct, thread.regs.iasq[1]));
+ DEFINE(TASK_PT_IAOQ0, offsetof(struct task_struct, thread.regs.iaoq[0]));
+ DEFINE(TASK_PT_IAOQ1, offsetof(struct task_struct, thread.regs.iaoq[1]));
+ DEFINE(TASK_PT_CR27, offsetof(struct task_struct, thread.regs.cr27));
+ DEFINE(TASK_PT_ORIG_R28, offsetof(struct task_struct, thread.regs.orig_r28));
+ DEFINE(TASK_PT_KSP, offsetof(struct task_struct, thread.regs.ksp));
+ DEFINE(TASK_PT_KPC, offsetof(struct task_struct, thread.regs.kpc));
+ DEFINE(TASK_PT_SAR, offsetof(struct task_struct, thread.regs.sar));
+ DEFINE(TASK_PT_IIR, offsetof(struct task_struct, thread.regs.iir));
+ DEFINE(TASK_PT_ISR, offsetof(struct task_struct, thread.regs.isr));
+ DEFINE(TASK_PT_IOR, offsetof(struct task_struct, thread.regs.ior));
+ BLANK();
+ DEFINE(PT_PSW, offsetof(struct pt_regs, gr[ 0]));
+ DEFINE(PT_GR1, offsetof(struct pt_regs, gr[ 1]));
+ DEFINE(PT_GR2, offsetof(struct pt_regs, gr[ 2]));
+ DEFINE(PT_GR3, offsetof(struct pt_regs, gr[ 3]));
+ DEFINE(PT_GR4, offsetof(struct pt_regs, gr[ 4]));
+ DEFINE(PT_GR5, offsetof(struct pt_regs, gr[ 5]));
+ DEFINE(PT_GR6, offsetof(struct pt_regs, gr[ 6]));
+ DEFINE(PT_GR7, offsetof(struct pt_regs, gr[ 7]));
+ DEFINE(PT_GR8, offsetof(struct pt_regs, gr[ 8]));
+ DEFINE(PT_GR9, offsetof(struct pt_regs, gr[ 9]));
+ DEFINE(PT_GR10, offsetof(struct pt_regs, gr[10]));
+ DEFINE(PT_GR11, offsetof(struct pt_regs, gr[11]));
+ DEFINE(PT_GR12, offsetof(struct pt_regs, gr[12]));
+ DEFINE(PT_GR13, offsetof(struct pt_regs, gr[13]));
+ DEFINE(PT_GR14, offsetof(struct pt_regs, gr[14]));
+ DEFINE(PT_GR15, offsetof(struct pt_regs, gr[15]));
+ DEFINE(PT_GR16, offsetof(struct pt_regs, gr[16]));
+ DEFINE(PT_GR17, offsetof(struct pt_regs, gr[17]));
+ DEFINE(PT_GR18, offsetof(struct pt_regs, gr[18]));
+ DEFINE(PT_GR19, offsetof(struct pt_regs, gr[19]));
+ DEFINE(PT_GR20, offsetof(struct pt_regs, gr[20]));
+ DEFINE(PT_GR21, offsetof(struct pt_regs, gr[21]));
+ DEFINE(PT_GR22, offsetof(struct pt_regs, gr[22]));
+ DEFINE(PT_GR23, offsetof(struct pt_regs, gr[23]));
+ DEFINE(PT_GR24, offsetof(struct pt_regs, gr[24]));
+ DEFINE(PT_GR25, offsetof(struct pt_regs, gr[25]));
+ DEFINE(PT_GR26, offsetof(struct pt_regs, gr[26]));
+ DEFINE(PT_GR27, offsetof(struct pt_regs, gr[27]));
+ DEFINE(PT_GR28, offsetof(struct pt_regs, gr[28]));
+ DEFINE(PT_GR29, offsetof(struct pt_regs, gr[29]));
+ DEFINE(PT_GR30, offsetof(struct pt_regs, gr[30]));
+ DEFINE(PT_GR31, offsetof(struct pt_regs, gr[31]));
+ DEFINE(PT_FR0, offsetof(struct pt_regs, fr[ 0]));
+ DEFINE(PT_FR1, offsetof(struct pt_regs, fr[ 1]));
+ DEFINE(PT_FR2, offsetof(struct pt_regs, fr[ 2]));
+ DEFINE(PT_FR3, offsetof(struct pt_regs, fr[ 3]));
+ DEFINE(PT_FR4, offsetof(struct pt_regs, fr[ 4]));
+ DEFINE(PT_FR5, offsetof(struct pt_regs, fr[ 5]));
+ DEFINE(PT_FR6, offsetof(struct pt_regs, fr[ 6]));
+ DEFINE(PT_FR7, offsetof(struct pt_regs, fr[ 7]));
+ DEFINE(PT_FR8, offsetof(struct pt_regs, fr[ 8]));
+ DEFINE(PT_FR9, offsetof(struct pt_regs, fr[ 9]));
+ DEFINE(PT_FR10, offsetof(struct pt_regs, fr[10]));
+ DEFINE(PT_FR11, offsetof(struct pt_regs, fr[11]));
+ DEFINE(PT_FR12, offsetof(struct pt_regs, fr[12]));
+ DEFINE(PT_FR13, offsetof(struct pt_regs, fr[13]));
+ DEFINE(PT_FR14, offsetof(struct pt_regs, fr[14]));
+ DEFINE(PT_FR15, offsetof(struct pt_regs, fr[15]));
+ DEFINE(PT_FR16, offsetof(struct pt_regs, fr[16]));
+ DEFINE(PT_FR17, offsetof(struct pt_regs, fr[17]));
+ DEFINE(PT_FR18, offsetof(struct pt_regs, fr[18]));
+ DEFINE(PT_FR19, offsetof(struct pt_regs, fr[19]));
+ DEFINE(PT_FR20, offsetof(struct pt_regs, fr[20]));
+ DEFINE(PT_FR21, offsetof(struct pt_regs, fr[21]));
+ DEFINE(PT_FR22, offsetof(struct pt_regs, fr[22]));
+ DEFINE(PT_FR23, offsetof(struct pt_regs, fr[23]));
+ DEFINE(PT_FR24, offsetof(struct pt_regs, fr[24]));
+ DEFINE(PT_FR25, offsetof(struct pt_regs, fr[25]));
+ DEFINE(PT_FR26, offsetof(struct pt_regs, fr[26]));
+ DEFINE(PT_FR27, offsetof(struct pt_regs, fr[27]));
+ DEFINE(PT_FR28, offsetof(struct pt_regs, fr[28]));
+ DEFINE(PT_FR29, offsetof(struct pt_regs, fr[29]));
+ DEFINE(PT_FR30, offsetof(struct pt_regs, fr[30]));
+ DEFINE(PT_FR31, offsetof(struct pt_regs, fr[31]));
+ DEFINE(PT_SR0, offsetof(struct pt_regs, sr[ 0]));
+ DEFINE(PT_SR1, offsetof(struct pt_regs, sr[ 1]));
+ DEFINE(PT_SR2, offsetof(struct pt_regs, sr[ 2]));
+ DEFINE(PT_SR3, offsetof(struct pt_regs, sr[ 3]));
+ DEFINE(PT_SR4, offsetof(struct pt_regs, sr[ 4]));
+ DEFINE(PT_SR5, offsetof(struct pt_regs, sr[ 5]));
+ DEFINE(PT_SR6, offsetof(struct pt_regs, sr[ 6]));
+ DEFINE(PT_SR7, offsetof(struct pt_regs, sr[ 7]));
+ DEFINE(PT_IASQ0, offsetof(struct pt_regs, iasq[0]));
+ DEFINE(PT_IASQ1, offsetof(struct pt_regs, iasq[1]));
+ DEFINE(PT_IAOQ0, offsetof(struct pt_regs, iaoq[0]));
+ DEFINE(PT_IAOQ1, offsetof(struct pt_regs, iaoq[1]));
+ DEFINE(PT_CR27, offsetof(struct pt_regs, cr27));
+ DEFINE(PT_ORIG_R28, offsetof(struct pt_regs, orig_r28));
+ DEFINE(PT_KSP, offsetof(struct pt_regs, ksp));
+ DEFINE(PT_KPC, offsetof(struct pt_regs, kpc));
+ DEFINE(PT_SAR, offsetof(struct pt_regs, sar));
+ DEFINE(PT_IIR, offsetof(struct pt_regs, iir));
+ DEFINE(PT_ISR, offsetof(struct pt_regs, isr));
+ DEFINE(PT_IOR, offsetof(struct pt_regs, ior));
+ /* PT_SZ_ALGN includes space for a stack frame. */
+ DEFINE(PT_SZ_ALGN, align_frame(sizeof(struct pt_regs), FRAME_ALIGN));
+ BLANK();
+ DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
+ DEFINE(TI_PRE_COUNT, offsetof(struct task_struct, thread_info.preempt_count));
+ BLANK();
+ DEFINE(ASM_SIGFRAME_SIZE, PARISC_RT_SIGFRAME_SIZE);
+ DEFINE(SIGFRAME_CONTEXT_REGS, offsetof(struct rt_sigframe, uc.uc_mcontext) - PARISC_RT_SIGFRAME_SIZE);
+#ifdef CONFIG_64BIT
+ DEFINE(ASM_SIGFRAME_SIZE32, PARISC_RT_SIGFRAME_SIZE32);
+ DEFINE(SIGFRAME_CONTEXT_REGS32, offsetof(struct compat_rt_sigframe, uc.uc_mcontext) - PARISC_RT_SIGFRAME_SIZE32);
+#else
+ DEFINE(ASM_SIGFRAME_SIZE32, PARISC_RT_SIGFRAME_SIZE);
+ DEFINE(SIGFRAME_CONTEXT_REGS32, offsetof(struct rt_sigframe, uc.uc_mcontext) - PARISC_RT_SIGFRAME_SIZE);
+#endif
+ BLANK();
+ DEFINE(ICACHE_BASE, offsetof(struct pdc_cache_info, ic_base));
+ DEFINE(ICACHE_STRIDE, offsetof(struct pdc_cache_info, ic_stride));
+ DEFINE(ICACHE_COUNT, offsetof(struct pdc_cache_info, ic_count));
+ DEFINE(ICACHE_LOOP, offsetof(struct pdc_cache_info, ic_loop));
+ DEFINE(DCACHE_BASE, offsetof(struct pdc_cache_info, dc_base));
+ DEFINE(DCACHE_STRIDE, offsetof(struct pdc_cache_info, dc_stride));
+ DEFINE(DCACHE_COUNT, offsetof(struct pdc_cache_info, dc_count));
+ DEFINE(DCACHE_LOOP, offsetof(struct pdc_cache_info, dc_loop));
+ DEFINE(ITLB_SID_BASE, offsetof(struct pdc_cache_info, it_sp_base));
+ DEFINE(ITLB_SID_STRIDE, offsetof(struct pdc_cache_info, it_sp_stride));
+ DEFINE(ITLB_SID_COUNT, offsetof(struct pdc_cache_info, it_sp_count));
+ DEFINE(ITLB_OFF_BASE, offsetof(struct pdc_cache_info, it_off_base));
+ DEFINE(ITLB_OFF_STRIDE, offsetof(struct pdc_cache_info, it_off_stride));
+ DEFINE(ITLB_OFF_COUNT, offsetof(struct pdc_cache_info, it_off_count));
+ DEFINE(ITLB_LOOP, offsetof(struct pdc_cache_info, it_loop));
+ DEFINE(DTLB_SID_BASE, offsetof(struct pdc_cache_info, dt_sp_base));
+ DEFINE(DTLB_SID_STRIDE, offsetof(struct pdc_cache_info, dt_sp_stride));
+ DEFINE(DTLB_SID_COUNT, offsetof(struct pdc_cache_info, dt_sp_count));
+ DEFINE(DTLB_OFF_BASE, offsetof(struct pdc_cache_info, dt_off_base));
+ DEFINE(DTLB_OFF_STRIDE, offsetof(struct pdc_cache_info, dt_off_stride));
+ DEFINE(DTLB_OFF_COUNT, offsetof(struct pdc_cache_info, dt_off_count));
+ DEFINE(DTLB_LOOP, offsetof(struct pdc_cache_info, dt_loop));
+ BLANK();
+ DEFINE(TIF_BLOCKSTEP_PA_BIT, 31-TIF_BLOCKSTEP);
+ DEFINE(TIF_SINGLESTEP_PA_BIT, 31-TIF_SINGLESTEP);
+ BLANK();
+ DEFINE(ASM_PMD_SHIFT, PMD_SHIFT);
+ DEFINE(ASM_PGDIR_SHIFT, PGDIR_SHIFT);
+ DEFINE(ASM_BITS_PER_PGD, BITS_PER_PGD);
+ DEFINE(ASM_BITS_PER_PMD, BITS_PER_PMD);
+ DEFINE(ASM_BITS_PER_PTE, BITS_PER_PTE);
+ DEFINE(ASM_PMD_ENTRY, ((PAGE_OFFSET & PMD_MASK) >> PMD_SHIFT));
+ DEFINE(ASM_PGD_ENTRY, PAGE_OFFSET >> PGDIR_SHIFT);
+ DEFINE(ASM_PGD_ENTRY_SIZE, PGD_ENTRY_SIZE);
+ DEFINE(ASM_PMD_ENTRY_SIZE, PMD_ENTRY_SIZE);
+ DEFINE(ASM_PTE_ENTRY_SIZE, PTE_ENTRY_SIZE);
+ DEFINE(ASM_PFN_PTE_SHIFT, PFN_PTE_SHIFT);
+ DEFINE(ASM_PT_INITIAL, PT_INITIAL);
+ BLANK();
+ /* HUGEPAGE_SIZE is only used in vmlinux.lds.S to align kernel text
+ * and kernel data on physical huge pages */
+#ifdef CONFIG_HUGETLB_PAGE
+ DEFINE(HUGEPAGE_SIZE, 1UL << REAL_HPAGE_SHIFT);
+#elif !defined(CONFIG_64BIT)
+ DEFINE(HUGEPAGE_SIZE, 4*1024*1024);
+#else
+ DEFINE(HUGEPAGE_SIZE, PAGE_SIZE);
+#endif
+ BLANK();
+ DEFINE(ASM_PDC_RESULT_SIZE, NUM_PDC_RESULT * sizeof(unsigned long));
+ BLANK();
+ return 0;
+}
diff --git a/arch/parisc/kernel/audit.c b/arch/parisc/kernel/audit.c
new file mode 100644
index 000000000..375cd73b5
--- /dev/null
+++ b/arch/parisc/kernel/audit.c
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/audit.h>
+#include <asm/unistd.h>
+
+static unsigned dir_class[] = {
+#include <asm-generic/audit_dir_write.h>
+~0U
+};
+
+static unsigned read_class[] = {
+#include <asm-generic/audit_read.h>
+~0U
+};
+
+static unsigned write_class[] = {
+#include <asm-generic/audit_write.h>
+~0U
+};
+
+static unsigned chattr_class[] = {
+#include <asm-generic/audit_change_attr.h>
+~0U
+};
+
+static unsigned signal_class[] = {
+#include <asm-generic/audit_signal.h>
+~0U
+};
+
+int audit_classify_arch(int arch)
+{
+#ifdef CONFIG_COMPAT
+ if (arch == AUDIT_ARCH_PARISC)
+ return 1;
+#endif
+ return 0;
+}
+
+int audit_classify_syscall(int abi, unsigned syscall)
+{
+ switch (syscall) {
+ case __NR_open:
+ return AUDITSC_OPEN;
+ case __NR_openat:
+ return AUDITSC_OPENAT;
+ case __NR_execve:
+ return AUDITSC_EXECVE;
+ case __NR_openat2:
+ return AUDITSC_OPENAT2;
+ default:
+#ifdef CONFIG_COMPAT
+ if (abi == AUDIT_ARCH_PARISC)
+ return AUDITSC_COMPAT;
+#endif
+ return AUDITSC_NATIVE;
+ }
+}
+
+static int __init audit_classes_init(void)
+{
+#ifdef CONFIG_COMPAT
+ extern __u32 parisc32_dir_class[];
+ extern __u32 parisc32_write_class[];
+ extern __u32 parisc32_read_class[];
+ extern __u32 parisc32_chattr_class[];
+ extern __u32 parisc32_signal_class[];
+ audit_register_class(AUDIT_CLASS_WRITE_32, parisc32_write_class);
+ audit_register_class(AUDIT_CLASS_READ_32, parisc32_read_class);
+ audit_register_class(AUDIT_CLASS_DIR_WRITE_32, parisc32_dir_class);
+ audit_register_class(AUDIT_CLASS_CHATTR_32, parisc32_chattr_class);
+ audit_register_class(AUDIT_CLASS_SIGNAL_32, parisc32_signal_class);
+#endif
+ audit_register_class(AUDIT_CLASS_WRITE, write_class);
+ audit_register_class(AUDIT_CLASS_READ, read_class);
+ audit_register_class(AUDIT_CLASS_DIR_WRITE, dir_class);
+ audit_register_class(AUDIT_CLASS_CHATTR, chattr_class);
+ audit_register_class(AUDIT_CLASS_SIGNAL, signal_class);
+ return 0;
+}
+
+__initcall(audit_classes_init);
diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c
new file mode 100644
index 000000000..268d90a93
--- /dev/null
+++ b/arch/parisc/kernel/cache.c
@@ -0,0 +1,874 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1999-2006 Helge Deller <deller@gmx.de> (07-13-1999)
+ * Copyright (C) 1999 SuSE GmbH Nuernberg
+ * Copyright (C) 2000 Philipp Rumpf (prumpf@tux.org)
+ *
+ * Cache and TLB management
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include <linux/pagemap.h>
+#include <linux/sched.h>
+#include <linux/sched/mm.h>
+#include <linux/syscalls.h>
+#include <asm/pdc.h>
+#include <asm/cache.h>
+#include <asm/cacheflush.h>
+#include <asm/tlbflush.h>
+#include <asm/page.h>
+#include <asm/processor.h>
+#include <asm/sections.h>
+#include <asm/shmparam.h>
+#include <asm/mmu_context.h>
+#include <asm/cachectl.h>
+
+int split_tlb __ro_after_init;
+int dcache_stride __ro_after_init;
+int icache_stride __ro_after_init;
+EXPORT_SYMBOL(dcache_stride);
+
+void flush_dcache_page_asm(unsigned long phys_addr, unsigned long vaddr);
+EXPORT_SYMBOL(flush_dcache_page_asm);
+void purge_dcache_page_asm(unsigned long phys_addr, unsigned long vaddr);
+void flush_icache_page_asm(unsigned long phys_addr, unsigned long vaddr);
+
+/* Internal implementation in arch/parisc/kernel/pacache.S */
+void flush_data_cache_local(void *); /* flushes local data-cache only */
+void flush_instruction_cache_local(void); /* flushes local code-cache only */
+
+/* On some machines (i.e., ones with the Merced bus), there can be
+ * only a single PxTLB broadcast at a time; this must be guaranteed
+ * by software. We need a spinlock around all TLB flushes to ensure
+ * this.
+ */
+DEFINE_SPINLOCK(pa_tlb_flush_lock);
+
+#if defined(CONFIG_64BIT) && defined(CONFIG_SMP)
+int pa_serialize_tlb_flushes __ro_after_init;
+#endif
+
+struct pdc_cache_info cache_info __ro_after_init;
+#ifndef CONFIG_PA20
+struct pdc_btlb_info btlb_info __ro_after_init;
+#endif
+
+DEFINE_STATIC_KEY_TRUE(parisc_has_cache);
+DEFINE_STATIC_KEY_TRUE(parisc_has_dcache);
+DEFINE_STATIC_KEY_TRUE(parisc_has_icache);
+
+static void cache_flush_local_cpu(void *dummy)
+{
+ if (static_branch_likely(&parisc_has_icache))
+ flush_instruction_cache_local();
+ if (static_branch_likely(&parisc_has_dcache))
+ flush_data_cache_local(NULL);
+}
+
+void flush_cache_all_local(void)
+{
+ cache_flush_local_cpu(NULL);
+}
+
+void flush_cache_all(void)
+{
+ if (static_branch_likely(&parisc_has_cache))
+ on_each_cpu(cache_flush_local_cpu, NULL, 1);
+}
+
+static inline void flush_data_cache(void)
+{
+ if (static_branch_likely(&parisc_has_dcache))
+ on_each_cpu(flush_data_cache_local, NULL, 1);
+}
+
+
+/* Kernel virtual address of pfn. */
+#define pfn_va(pfn) __va(PFN_PHYS(pfn))
+
+void __update_cache(pte_t pte)
+{
+ unsigned long pfn = pte_pfn(pte);
+ struct folio *folio;
+ unsigned int nr;
+
+ /* We don't have pte special. As a result, we can be called with
+ an invalid pfn and we don't need to flush the kernel dcache page.
+ This occurs with FireGL card in C8000. */
+ if (!pfn_valid(pfn))
+ return;
+
+ folio = page_folio(pfn_to_page(pfn));
+ pfn = folio_pfn(folio);
+ nr = folio_nr_pages(folio);
+ if (folio_flush_mapping(folio) &&
+ test_bit(PG_dcache_dirty, &folio->flags)) {
+ while (nr--)
+ flush_kernel_dcache_page_addr(pfn_va(pfn + nr));
+ clear_bit(PG_dcache_dirty, &folio->flags);
+ } else if (parisc_requires_coherency())
+ while (nr--)
+ flush_kernel_dcache_page_addr(pfn_va(pfn + nr));
+}
+
+void
+show_cache_info(struct seq_file *m)
+{
+ char buf[32];
+
+ seq_printf(m, "I-cache\t\t: %ld KB\n",
+ cache_info.ic_size/1024 );
+ if (cache_info.dc_loop != 1)
+ snprintf(buf, 32, "%lu-way associative", cache_info.dc_loop);
+ seq_printf(m, "D-cache\t\t: %ld KB (%s%s, %s, alias=%d)\n",
+ cache_info.dc_size/1024,
+ (cache_info.dc_conf.cc_wt ? "WT":"WB"),
+ (cache_info.dc_conf.cc_sh ? ", shared I/D":""),
+ ((cache_info.dc_loop == 1) ? "direct mapped" : buf),
+ cache_info.dc_conf.cc_alias
+ );
+ seq_printf(m, "ITLB entries\t: %ld\n" "DTLB entries\t: %ld%s\n",
+ cache_info.it_size,
+ cache_info.dt_size,
+ cache_info.dt_conf.tc_sh ? " - shared with ITLB":""
+ );
+
+#ifndef CONFIG_PA20
+ /* BTLB - Block TLB */
+ if (btlb_info.max_size==0) {
+ seq_printf(m, "BTLB\t\t: not supported\n" );
+ } else {
+ seq_printf(m,
+ "BTLB fixed\t: max. %d pages, pagesize=%d (%dMB)\n"
+ "BTLB fix-entr.\t: %d instruction, %d data (%d combined)\n"
+ "BTLB var-entr.\t: %d instruction, %d data (%d combined)\n",
+ btlb_info.max_size, (int)4096,
+ btlb_info.max_size>>8,
+ btlb_info.fixed_range_info.num_i,
+ btlb_info.fixed_range_info.num_d,
+ btlb_info.fixed_range_info.num_comb,
+ btlb_info.variable_range_info.num_i,
+ btlb_info.variable_range_info.num_d,
+ btlb_info.variable_range_info.num_comb
+ );
+ }
+#endif
+}
+
+void __init
+parisc_cache_init(void)
+{
+ if (pdc_cache_info(&cache_info) < 0)
+ panic("parisc_cache_init: pdc_cache_info failed");
+
+#if 0
+ printk("ic_size %lx dc_size %lx it_size %lx\n",
+ cache_info.ic_size,
+ cache_info.dc_size,
+ cache_info.it_size);
+
+ printk("DC base 0x%lx stride 0x%lx count 0x%lx loop 0x%lx\n",
+ cache_info.dc_base,
+ cache_info.dc_stride,
+ cache_info.dc_count,
+ cache_info.dc_loop);
+
+ printk("dc_conf = 0x%lx alias %d blk %d line %d shift %d\n",
+ *(unsigned long *) (&cache_info.dc_conf),
+ cache_info.dc_conf.cc_alias,
+ cache_info.dc_conf.cc_block,
+ cache_info.dc_conf.cc_line,
+ cache_info.dc_conf.cc_shift);
+ printk(" wt %d sh %d cst %d hv %d\n",
+ cache_info.dc_conf.cc_wt,
+ cache_info.dc_conf.cc_sh,
+ cache_info.dc_conf.cc_cst,
+ cache_info.dc_conf.cc_hv);
+
+ printk("IC base 0x%lx stride 0x%lx count 0x%lx loop 0x%lx\n",
+ cache_info.ic_base,
+ cache_info.ic_stride,
+ cache_info.ic_count,
+ cache_info.ic_loop);
+
+ printk("IT base 0x%lx stride 0x%lx count 0x%lx loop 0x%lx off_base 0x%lx off_stride 0x%lx off_count 0x%lx\n",
+ cache_info.it_sp_base,
+ cache_info.it_sp_stride,
+ cache_info.it_sp_count,
+ cache_info.it_loop,
+ cache_info.it_off_base,
+ cache_info.it_off_stride,
+ cache_info.it_off_count);
+
+ printk("DT base 0x%lx stride 0x%lx count 0x%lx loop 0x%lx off_base 0x%lx off_stride 0x%lx off_count 0x%lx\n",
+ cache_info.dt_sp_base,
+ cache_info.dt_sp_stride,
+ cache_info.dt_sp_count,
+ cache_info.dt_loop,
+ cache_info.dt_off_base,
+ cache_info.dt_off_stride,
+ cache_info.dt_off_count);
+
+ printk("ic_conf = 0x%lx alias %d blk %d line %d shift %d\n",
+ *(unsigned long *) (&cache_info.ic_conf),
+ cache_info.ic_conf.cc_alias,
+ cache_info.ic_conf.cc_block,
+ cache_info.ic_conf.cc_line,
+ cache_info.ic_conf.cc_shift);
+ printk(" wt %d sh %d cst %d hv %d\n",
+ cache_info.ic_conf.cc_wt,
+ cache_info.ic_conf.cc_sh,
+ cache_info.ic_conf.cc_cst,
+ cache_info.ic_conf.cc_hv);
+
+ printk("D-TLB conf: sh %d page %d cst %d aid %d sr %d\n",
+ cache_info.dt_conf.tc_sh,
+ cache_info.dt_conf.tc_page,
+ cache_info.dt_conf.tc_cst,
+ cache_info.dt_conf.tc_aid,
+ cache_info.dt_conf.tc_sr);
+
+ printk("I-TLB conf: sh %d page %d cst %d aid %d sr %d\n",
+ cache_info.it_conf.tc_sh,
+ cache_info.it_conf.tc_page,
+ cache_info.it_conf.tc_cst,
+ cache_info.it_conf.tc_aid,
+ cache_info.it_conf.tc_sr);
+#endif
+
+ split_tlb = 0;
+ if (cache_info.dt_conf.tc_sh == 0 || cache_info.dt_conf.tc_sh == 2) {
+ if (cache_info.dt_conf.tc_sh == 2)
+ printk(KERN_WARNING "Unexpected TLB configuration. "
+ "Will flush I/D separately (could be optimized).\n");
+
+ split_tlb = 1;
+ }
+
+ /* "New and Improved" version from Jim Hull
+ * (1 << (cc_block-1)) * (cc_line << (4 + cnf.cc_shift))
+ * The following CAFL_STRIDE is an optimized version, see
+ * http://lists.parisc-linux.org/pipermail/parisc-linux/2004-June/023625.html
+ * http://lists.parisc-linux.org/pipermail/parisc-linux/2004-June/023671.html
+ */
+#define CAFL_STRIDE(cnf) (cnf.cc_line << (3 + cnf.cc_block + cnf.cc_shift))
+ dcache_stride = CAFL_STRIDE(cache_info.dc_conf);
+ icache_stride = CAFL_STRIDE(cache_info.ic_conf);
+#undef CAFL_STRIDE
+
+ if ((boot_cpu_data.pdc.capabilities & PDC_MODEL_NVA_MASK) ==
+ PDC_MODEL_NVA_UNSUPPORTED) {
+ printk(KERN_WARNING "parisc_cache_init: Only equivalent aliasing supported!\n");
+#if 0
+ panic("SMP kernel required to avoid non-equivalent aliasing");
+#endif
+ }
+}
+
+void disable_sr_hashing(void)
+{
+ int srhash_type, retval;
+ unsigned long space_bits;
+
+ switch (boot_cpu_data.cpu_type) {
+ case pcx: /* We shouldn't get this far. setup.c should prevent it. */
+ BUG();
+ return;
+
+ case pcxs:
+ case pcxt:
+ case pcxt_:
+ srhash_type = SRHASH_PCXST;
+ break;
+
+ case pcxl:
+ srhash_type = SRHASH_PCXL;
+ break;
+
+ case pcxl2: /* pcxl2 doesn't support space register hashing */
+ return;
+
+ default: /* Currently all PA2.0 machines use the same ins. sequence */
+ srhash_type = SRHASH_PA20;
+ break;
+ }
+
+ disable_sr_hashing_asm(srhash_type);
+
+ retval = pdc_spaceid_bits(&space_bits);
+ /* If this procedure isn't implemented, don't panic. */
+ if (retval < 0 && retval != PDC_BAD_OPTION)
+ panic("pdc_spaceid_bits call failed.\n");
+ if (space_bits != 0)
+ panic("SpaceID hashing is still on!\n");
+}
+
+static inline void
+__flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr,
+ unsigned long physaddr)
+{
+ if (!static_branch_likely(&parisc_has_cache))
+ return;
+ preempt_disable();
+ flush_dcache_page_asm(physaddr, vmaddr);
+ if (vma->vm_flags & VM_EXEC)
+ flush_icache_page_asm(physaddr, vmaddr);
+ preempt_enable();
+}
+
+static void flush_user_cache_page(struct vm_area_struct *vma, unsigned long vmaddr)
+{
+ unsigned long flags, space, pgd, prot;
+#ifdef CONFIG_TLB_PTLOCK
+ unsigned long pgd_lock;
+#endif
+
+ vmaddr &= PAGE_MASK;
+
+ preempt_disable();
+
+ /* Set context for flush */
+ local_irq_save(flags);
+ prot = mfctl(8);
+ space = mfsp(SR_USER);
+ pgd = mfctl(25);
+#ifdef CONFIG_TLB_PTLOCK
+ pgd_lock = mfctl(28);
+#endif
+ switch_mm_irqs_off(NULL, vma->vm_mm, NULL);
+ local_irq_restore(flags);
+
+ flush_user_dcache_range_asm(vmaddr, vmaddr + PAGE_SIZE);
+ if (vma->vm_flags & VM_EXEC)
+ flush_user_icache_range_asm(vmaddr, vmaddr + PAGE_SIZE);
+ flush_tlb_page(vma, vmaddr);
+
+ /* Restore previous context */
+ local_irq_save(flags);
+#ifdef CONFIG_TLB_PTLOCK
+ mtctl(pgd_lock, 28);
+#endif
+ mtctl(pgd, 25);
+ mtsp(space, SR_USER);
+ mtctl(prot, 8);
+ local_irq_restore(flags);
+
+ preempt_enable();
+}
+
+void flush_icache_pages(struct vm_area_struct *vma, struct page *page,
+ unsigned int nr)
+{
+ void *kaddr = page_address(page);
+
+ for (;;) {
+ flush_kernel_dcache_page_addr(kaddr);
+ flush_kernel_icache_page(kaddr);
+ if (--nr == 0)
+ break;
+ kaddr += PAGE_SIZE;
+ }
+}
+
+static inline pte_t *get_ptep(struct mm_struct *mm, unsigned long addr)
+{
+ pte_t *ptep = NULL;
+ pgd_t *pgd = mm->pgd;
+ p4d_t *p4d;
+ pud_t *pud;
+ pmd_t *pmd;
+
+ if (!pgd_none(*pgd)) {
+ p4d = p4d_offset(pgd, addr);
+ if (!p4d_none(*p4d)) {
+ pud = pud_offset(p4d, addr);
+ if (!pud_none(*pud)) {
+ pmd = pmd_offset(pud, addr);
+ if (!pmd_none(*pmd))
+ ptep = pte_offset_map(pmd, addr);
+ }
+ }
+ }
+ return ptep;
+}
+
+static inline bool pte_needs_flush(pte_t pte)
+{
+ return (pte_val(pte) & (_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_NO_CACHE))
+ == (_PAGE_PRESENT | _PAGE_ACCESSED);
+}
+
+void flush_dcache_folio(struct folio *folio)
+{
+ struct address_space *mapping = folio_flush_mapping(folio);
+ struct vm_area_struct *vma;
+ unsigned long addr, old_addr = 0;
+ void *kaddr;
+ unsigned long count = 0;
+ unsigned long i, nr, flags;
+ pgoff_t pgoff;
+
+ if (mapping && !mapping_mapped(mapping)) {
+ set_bit(PG_dcache_dirty, &folio->flags);
+ return;
+ }
+
+ nr = folio_nr_pages(folio);
+ kaddr = folio_address(folio);
+ for (i = 0; i < nr; i++)
+ flush_kernel_dcache_page_addr(kaddr + i * PAGE_SIZE);
+
+ if (!mapping)
+ return;
+
+ pgoff = folio->index;
+
+ /*
+ * We have carefully arranged in arch_get_unmapped_area() that
+ * *any* mappings of a file are always congruently mapped (whether
+ * declared as MAP_PRIVATE or MAP_SHARED), so we only need
+ * to flush one address here for them all to become coherent
+ * on machines that support equivalent aliasing
+ */
+ flush_dcache_mmap_lock_irqsave(mapping, flags);
+ vma_interval_tree_foreach(vma, &mapping->i_mmap, pgoff, pgoff + nr - 1) {
+ unsigned long offset = pgoff - vma->vm_pgoff;
+ unsigned long pfn = folio_pfn(folio);
+
+ addr = vma->vm_start;
+ nr = folio_nr_pages(folio);
+ if (offset > -nr) {
+ pfn -= offset;
+ nr += offset;
+ } else {
+ addr += offset * PAGE_SIZE;
+ }
+ if (addr + nr * PAGE_SIZE > vma->vm_end)
+ nr = (vma->vm_end - addr) / PAGE_SIZE;
+
+ if (parisc_requires_coherency()) {
+ for (i = 0; i < nr; i++) {
+ pte_t *ptep = get_ptep(vma->vm_mm,
+ addr + i * PAGE_SIZE);
+ if (!ptep)
+ continue;
+ if (pte_needs_flush(*ptep))
+ flush_user_cache_page(vma,
+ addr + i * PAGE_SIZE);
+ /* Optimise accesses to the same table? */
+ pte_unmap(ptep);
+ }
+ } else {
+ /*
+ * The TLB is the engine of coherence on parisc:
+ * The CPU is entitled to speculate any page
+ * with a TLB mapping, so here we kill the
+ * mapping then flush the page along a special
+ * flush only alias mapping. This guarantees that
+ * the page is no-longer in the cache for any
+ * process and nor may it be speculatively read
+ * in (until the user or kernel specifically
+ * accesses it, of course)
+ */
+ for (i = 0; i < nr; i++)
+ flush_tlb_page(vma, addr + i * PAGE_SIZE);
+ if (old_addr == 0 || (old_addr & (SHM_COLOUR - 1))
+ != (addr & (SHM_COLOUR - 1))) {
+ for (i = 0; i < nr; i++)
+ __flush_cache_page(vma,
+ addr + i * PAGE_SIZE,
+ (pfn + i) * PAGE_SIZE);
+ /*
+ * Software is allowed to have any number
+ * of private mappings to a page.
+ */
+ if (!(vma->vm_flags & VM_SHARED))
+ continue;
+ if (old_addr)
+ pr_err("INEQUIVALENT ALIASES 0x%lx and 0x%lx in file %pD\n",
+ old_addr, addr, vma->vm_file);
+ if (nr == folio_nr_pages(folio))
+ old_addr = addr;
+ }
+ }
+ WARN_ON(++count == 4096);
+ }
+ flush_dcache_mmap_unlock_irqrestore(mapping, flags);
+}
+EXPORT_SYMBOL(flush_dcache_folio);
+
+/* Defined in arch/parisc/kernel/pacache.S */
+EXPORT_SYMBOL(flush_kernel_dcache_range_asm);
+EXPORT_SYMBOL(flush_kernel_icache_range_asm);
+
+#define FLUSH_THRESHOLD 0x80000 /* 0.5MB */
+static unsigned long parisc_cache_flush_threshold __ro_after_init = FLUSH_THRESHOLD;
+
+#define FLUSH_TLB_THRESHOLD (16*1024) /* 16 KiB minimum TLB threshold */
+static unsigned long parisc_tlb_flush_threshold __ro_after_init = ~0UL;
+
+void __init parisc_setup_cache_timing(void)
+{
+ unsigned long rangetime, alltime;
+ unsigned long size;
+ unsigned long threshold, threshold2;
+
+ alltime = mfctl(16);
+ flush_data_cache();
+ alltime = mfctl(16) - alltime;
+
+ size = (unsigned long)(_end - _text);
+ rangetime = mfctl(16);
+ flush_kernel_dcache_range((unsigned long)_text, size);
+ rangetime = mfctl(16) - rangetime;
+
+ printk(KERN_DEBUG "Whole cache flush %lu cycles, flushing %lu bytes %lu cycles\n",
+ alltime, size, rangetime);
+
+ threshold = L1_CACHE_ALIGN((unsigned long)((uint64_t)size * alltime / rangetime));
+ pr_info("Calculated flush threshold is %lu KiB\n",
+ threshold/1024);
+
+ /*
+ * The threshold computed above isn't very reliable. The following
+ * heuristic works reasonably well on c8000/rp3440.
+ */
+ threshold2 = cache_info.dc_size * num_online_cpus();
+ parisc_cache_flush_threshold = threshold2;
+ printk(KERN_INFO "Cache flush threshold set to %lu KiB\n",
+ parisc_cache_flush_threshold/1024);
+
+ /* calculate TLB flush threshold */
+
+ /* On SMP machines, skip the TLB measure of kernel text which
+ * has been mapped as huge pages. */
+ if (num_online_cpus() > 1 && !parisc_requires_coherency()) {
+ threshold = max(cache_info.it_size, cache_info.dt_size);
+ threshold *= PAGE_SIZE;
+ threshold /= num_online_cpus();
+ goto set_tlb_threshold;
+ }
+
+ size = (unsigned long)_end - (unsigned long)_text;
+ rangetime = mfctl(16);
+ flush_tlb_kernel_range((unsigned long)_text, (unsigned long)_end);
+ rangetime = mfctl(16) - rangetime;
+
+ alltime = mfctl(16);
+ flush_tlb_all();
+ alltime = mfctl(16) - alltime;
+
+ printk(KERN_INFO "Whole TLB flush %lu cycles, Range flush %lu bytes %lu cycles\n",
+ alltime, size, rangetime);
+
+ threshold = PAGE_ALIGN((num_online_cpus() * size * alltime) / rangetime);
+ printk(KERN_INFO "Calculated TLB flush threshold %lu KiB\n",
+ threshold/1024);
+
+set_tlb_threshold:
+ if (threshold > FLUSH_TLB_THRESHOLD)
+ parisc_tlb_flush_threshold = threshold;
+ else
+ parisc_tlb_flush_threshold = FLUSH_TLB_THRESHOLD;
+
+ printk(KERN_INFO "TLB flush threshold set to %lu KiB\n",
+ parisc_tlb_flush_threshold/1024);
+}
+
+extern void purge_kernel_dcache_page_asm(unsigned long);
+extern void clear_user_page_asm(void *, unsigned long);
+extern void copy_user_page_asm(void *, void *, unsigned long);
+
+void flush_kernel_dcache_page_addr(const void *addr)
+{
+ unsigned long flags;
+
+ flush_kernel_dcache_page_asm(addr);
+ purge_tlb_start(flags);
+ pdtlb(SR_KERNEL, addr);
+ purge_tlb_end(flags);
+}
+EXPORT_SYMBOL(flush_kernel_dcache_page_addr);
+
+static void flush_cache_page_if_present(struct vm_area_struct *vma,
+ unsigned long vmaddr, unsigned long pfn)
+{
+ bool needs_flush = false;
+ pte_t *ptep;
+
+ /*
+ * The pte check is racy and sometimes the flush will trigger
+ * a non-access TLB miss. Hopefully, the page has already been
+ * flushed.
+ */
+ ptep = get_ptep(vma->vm_mm, vmaddr);
+ if (ptep) {
+ needs_flush = pte_needs_flush(*ptep);
+ pte_unmap(ptep);
+ }
+ if (needs_flush)
+ flush_cache_page(vma, vmaddr, pfn);
+}
+
+void copy_user_highpage(struct page *to, struct page *from,
+ unsigned long vaddr, struct vm_area_struct *vma)
+{
+ void *kto, *kfrom;
+
+ kfrom = kmap_local_page(from);
+ kto = kmap_local_page(to);
+ flush_cache_page_if_present(vma, vaddr, page_to_pfn(from));
+ copy_page_asm(kto, kfrom);
+ kunmap_local(kto);
+ kunmap_local(kfrom);
+}
+
+void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
+ unsigned long user_vaddr, void *dst, void *src, int len)
+{
+ flush_cache_page_if_present(vma, user_vaddr, page_to_pfn(page));
+ memcpy(dst, src, len);
+ flush_kernel_dcache_range_asm((unsigned long)dst, (unsigned long)dst + len);
+}
+
+void copy_from_user_page(struct vm_area_struct *vma, struct page *page,
+ unsigned long user_vaddr, void *dst, void *src, int len)
+{
+ flush_cache_page_if_present(vma, user_vaddr, page_to_pfn(page));
+ memcpy(dst, src, len);
+}
+
+/* __flush_tlb_range()
+ *
+ * returns 1 if all TLBs were flushed.
+ */
+int __flush_tlb_range(unsigned long sid, unsigned long start,
+ unsigned long end)
+{
+ unsigned long flags;
+
+ if ((!IS_ENABLED(CONFIG_SMP) || !arch_irqs_disabled()) &&
+ end - start >= parisc_tlb_flush_threshold) {
+ flush_tlb_all();
+ return 1;
+ }
+
+ /* Purge TLB entries for small ranges using the pdtlb and
+ pitlb instructions. These instructions execute locally
+ but cause a purge request to be broadcast to other TLBs. */
+ while (start < end) {
+ purge_tlb_start(flags);
+ mtsp(sid, SR_TEMP1);
+ pdtlb(SR_TEMP1, start);
+ pitlb(SR_TEMP1, start);
+ purge_tlb_end(flags);
+ start += PAGE_SIZE;
+ }
+ return 0;
+}
+
+static void flush_cache_pages(struct vm_area_struct *vma, unsigned long start, unsigned long end)
+{
+ unsigned long addr, pfn;
+ pte_t *ptep;
+
+ for (addr = start; addr < end; addr += PAGE_SIZE) {
+ bool needs_flush = false;
+ /*
+ * The vma can contain pages that aren't present. Although
+ * the pte search is expensive, we need the pte to find the
+ * page pfn and to check whether the page should be flushed.
+ */
+ ptep = get_ptep(vma->vm_mm, addr);
+ if (ptep) {
+ needs_flush = pte_needs_flush(*ptep);
+ pfn = pte_pfn(*ptep);
+ pte_unmap(ptep);
+ }
+ if (needs_flush) {
+ if (parisc_requires_coherency()) {
+ flush_user_cache_page(vma, addr);
+ } else {
+ if (WARN_ON(!pfn_valid(pfn)))
+ return;
+ __flush_cache_page(vma, addr, PFN_PHYS(pfn));
+ }
+ }
+ }
+}
+
+static inline unsigned long mm_total_size(struct mm_struct *mm)
+{
+ struct vm_area_struct *vma;
+ unsigned long usize = 0;
+ VMA_ITERATOR(vmi, mm, 0);
+
+ for_each_vma(vmi, vma) {
+ if (usize >= parisc_cache_flush_threshold)
+ break;
+ usize += vma->vm_end - vma->vm_start;
+ }
+ return usize;
+}
+
+void flush_cache_mm(struct mm_struct *mm)
+{
+ struct vm_area_struct *vma;
+ VMA_ITERATOR(vmi, mm, 0);
+
+ /*
+ * Flushing the whole cache on each cpu takes forever on
+ * rp3440, etc. So, avoid it if the mm isn't too big.
+ *
+ * Note that we must flush the entire cache on machines
+ * with aliasing caches to prevent random segmentation
+ * faults.
+ */
+ if (!parisc_requires_coherency()
+ || mm_total_size(mm) >= parisc_cache_flush_threshold) {
+ if (WARN_ON(IS_ENABLED(CONFIG_SMP) && arch_irqs_disabled()))
+ return;
+ flush_tlb_all();
+ flush_cache_all();
+ return;
+ }
+
+ /* Flush mm */
+ for_each_vma(vmi, vma)
+ flush_cache_pages(vma, vma->vm_start, vma->vm_end);
+}
+
+void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
+{
+ if (!parisc_requires_coherency()
+ || end - start >= parisc_cache_flush_threshold) {
+ if (WARN_ON(IS_ENABLED(CONFIG_SMP) && arch_irqs_disabled()))
+ return;
+ flush_tlb_range(vma, start, end);
+ flush_cache_all();
+ return;
+ }
+
+ flush_cache_pages(vma, start, end);
+}
+
+void flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long pfn)
+{
+ if (WARN_ON(!pfn_valid(pfn)))
+ return;
+ if (parisc_requires_coherency())
+ flush_user_cache_page(vma, vmaddr);
+ else
+ __flush_cache_page(vma, vmaddr, PFN_PHYS(pfn));
+}
+
+void flush_anon_page(struct vm_area_struct *vma, struct page *page, unsigned long vmaddr)
+{
+ if (!PageAnon(page))
+ return;
+
+ if (parisc_requires_coherency()) {
+ if (vma->vm_flags & VM_SHARED)
+ flush_data_cache();
+ else
+ flush_user_cache_page(vma, vmaddr);
+ return;
+ }
+
+ flush_tlb_page(vma, vmaddr);
+ preempt_disable();
+ flush_dcache_page_asm(page_to_phys(page), vmaddr);
+ preempt_enable();
+}
+
+void flush_kernel_vmap_range(void *vaddr, int size)
+{
+ unsigned long start = (unsigned long)vaddr;
+ unsigned long end = start + size;
+
+ if ((!IS_ENABLED(CONFIG_SMP) || !arch_irqs_disabled()) &&
+ (unsigned long)size >= parisc_cache_flush_threshold) {
+ flush_tlb_kernel_range(start, end);
+ flush_data_cache();
+ return;
+ }
+
+ flush_kernel_dcache_range_asm(start, end);
+ flush_tlb_kernel_range(start, end);
+}
+EXPORT_SYMBOL(flush_kernel_vmap_range);
+
+void invalidate_kernel_vmap_range(void *vaddr, int size)
+{
+ unsigned long start = (unsigned long)vaddr;
+ unsigned long end = start + size;
+
+ /* Ensure DMA is complete */
+ asm_syncdma();
+
+ if ((!IS_ENABLED(CONFIG_SMP) || !arch_irqs_disabled()) &&
+ (unsigned long)size >= parisc_cache_flush_threshold) {
+ flush_tlb_kernel_range(start, end);
+ flush_data_cache();
+ return;
+ }
+
+ purge_kernel_dcache_range_asm(start, end);
+ flush_tlb_kernel_range(start, end);
+}
+EXPORT_SYMBOL(invalidate_kernel_vmap_range);
+
+
+SYSCALL_DEFINE3(cacheflush, unsigned long, addr, unsigned long, bytes,
+ unsigned int, cache)
+{
+ unsigned long start, end;
+ ASM_EXCEPTIONTABLE_VAR(error);
+
+ if (bytes == 0)
+ return 0;
+ if (!access_ok((void __user *) addr, bytes))
+ return -EFAULT;
+
+ end = addr + bytes;
+
+ if (cache & DCACHE) {
+ start = addr;
+ __asm__ __volatile__ (
+#ifdef CONFIG_64BIT
+ "1: cmpb,*<<,n %0,%2,1b\n"
+#else
+ "1: cmpb,<<,n %0,%2,1b\n"
+#endif
+ " fic,m %3(%4,%0)\n"
+ "2: sync\n"
+ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 2b)
+ : "+r" (start), "+r" (error)
+ : "r" (end), "r" (dcache_stride), "i" (SR_USER));
+ }
+
+ if (cache & ICACHE && error == 0) {
+ start = addr;
+ __asm__ __volatile__ (
+#ifdef CONFIG_64BIT
+ "1: cmpb,*<<,n %0,%2,1b\n"
+#else
+ "1: cmpb,<<,n %0,%2,1b\n"
+#endif
+ " fdc,m %3(%4,%0)\n"
+ "2: sync\n"
+ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 2b)
+ : "+r" (start), "+r" (error)
+ : "r" (end), "r" (icache_stride), "i" (SR_USER));
+ }
+
+ return error;
+}
diff --git a/arch/parisc/kernel/compat_audit.c b/arch/parisc/kernel/compat_audit.c
new file mode 100644
index 000000000..3ac53f1ab
--- /dev/null
+++ b/arch/parisc/kernel/compat_audit.c
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/audit_arch.h>
+#include <asm/unistd.h>
+
+unsigned int parisc32_dir_class[] = {
+#include <asm-generic/audit_dir_write.h>
+~0U
+};
+
+unsigned int parisc32_chattr_class[] = {
+#include <asm-generic/audit_change_attr.h>
+~0U
+};
+
+unsigned int parisc32_write_class[] = {
+#include <asm-generic/audit_write.h>
+~0U
+};
+
+unsigned int parisc32_read_class[] = {
+#include <asm-generic/audit_read.h>
+~0U
+};
+
+unsigned int parisc32_signal_class[] = {
+#include <asm-generic/audit_signal.h>
+~0U
+};
diff --git a/arch/parisc/kernel/drivers.c b/arch/parisc/kernel/drivers.c
new file mode 100644
index 000000000..ed8b75948
--- /dev/null
+++ b/arch/parisc/kernel/drivers.c
@@ -0,0 +1,1102 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * drivers.c
+ *
+ * Copyright (c) 1999 The Puffin Group
+ * Copyright (c) 2001 Matthew Wilcox for Hewlett Packard
+ * Copyright (c) 2001-2023 Helge Deller <deller@gmx.de>
+ * Copyright (c) 2001,2002 Ryan Bradetich
+ * Copyright (c) 2004-2005 Thibaut VARENE <varenet@parisc-linux.org>
+ *
+ * The file handles registering devices and drivers, then matching them.
+ * It's the closest we get to a dating agency.
+ *
+ * If you're thinking about modifying this file, here are some gotchas to
+ * bear in mind:
+ * - 715/Mirage device paths have a dummy device between Lasi and its children
+ * - The EISA adapter may show up as a sibling or child of Wax
+ * - Dino has an optionally functional serial port. If firmware enables it,
+ * it shows up as a child of Dino. If firmware disables it, the buswalk
+ * finds it and it shows up as a child of Cujo
+ * - Dino has both parisc and pci devices as children
+ * - parisc devices are discovered in a random order, including children
+ * before parents in some cases.
+ */
+
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/export.h>
+#include <linux/dma-map-ops.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/pdc.h>
+#include <asm/parisc-device.h>
+#include <asm/ropes.h>
+
+/* See comments in include/asm-parisc/pci.h */
+const struct dma_map_ops *hppa_dma_ops __ro_after_init;
+EXPORT_SYMBOL(hppa_dma_ops);
+
+static struct device root = {
+ .init_name = "parisc",
+};
+
+static inline int check_dev(struct device *dev)
+{
+ if (dev->bus == &parisc_bus_type) {
+ struct parisc_device *pdev;
+ pdev = to_parisc_device(dev);
+ return pdev->id.hw_type != HPHW_FAULTY;
+ }
+ return 1;
+}
+
+static struct device *
+parse_tree_node(struct device *parent, int index, struct hardware_path *modpath);
+
+struct recurse_struct {
+ void * obj;
+ int (*fn)(struct device *, void *);
+};
+
+static int descend_children(struct device * dev, void * data)
+{
+ struct recurse_struct * recurse_data = (struct recurse_struct *)data;
+
+ if (recurse_data->fn(dev, recurse_data->obj))
+ return 1;
+ else
+ return device_for_each_child(dev, recurse_data, descend_children);
+}
+
+/**
+ * for_each_padev - Iterate over all devices in the tree
+ * @fn: Function to call for each device.
+ * @data: Data to pass to the called function.
+ *
+ * This performs a depth-first traversal of the tree, calling the
+ * function passed for each node. It calls the function for parents
+ * before children.
+ */
+
+static int for_each_padev(int (*fn)(struct device *, void *), void * data)
+{
+ struct recurse_struct recurse_data = {
+ .obj = data,
+ .fn = fn,
+ };
+ return device_for_each_child(&root, &recurse_data, descend_children);
+}
+
+/**
+ * match_device - Report whether this driver can handle this device
+ * @driver: the PA-RISC driver to try
+ * @dev: the PA-RISC device to try
+ */
+static int match_device(struct parisc_driver *driver, struct parisc_device *dev)
+{
+ const struct parisc_device_id *ids;
+
+ for (ids = driver->id_table; ids->sversion; ids++) {
+ if ((ids->sversion != SVERSION_ANY_ID) &&
+ (ids->sversion != dev->id.sversion))
+ continue;
+
+ if ((ids->hw_type != HWTYPE_ANY_ID) &&
+ (ids->hw_type != dev->id.hw_type))
+ continue;
+
+ if ((ids->hversion != HVERSION_ANY_ID) &&
+ (ids->hversion != dev->id.hversion))
+ continue;
+
+ return 1;
+ }
+ return 0;
+}
+
+static int parisc_driver_probe(struct device *dev)
+{
+ int rc;
+ struct parisc_device *pa_dev = to_parisc_device(dev);
+ struct parisc_driver *pa_drv = to_parisc_driver(dev->driver);
+
+ rc = pa_drv->probe(pa_dev);
+
+ if (!rc)
+ pa_dev->driver = pa_drv;
+
+ return rc;
+}
+
+static void __exit parisc_driver_remove(struct device *dev)
+{
+ struct parisc_device *pa_dev = to_parisc_device(dev);
+ struct parisc_driver *pa_drv = to_parisc_driver(dev->driver);
+
+ if (pa_drv->remove)
+ pa_drv->remove(pa_dev);
+}
+
+
+/**
+ * register_parisc_driver - Register this driver if it can handle a device
+ * @driver: the PA-RISC driver to try
+ */
+int register_parisc_driver(struct parisc_driver *driver)
+{
+ /* FIXME: we need this because apparently the sti
+ * driver can be registered twice */
+ if (driver->drv.name) {
+ pr_warn("BUG: skipping previously registered driver %s\n",
+ driver->name);
+ return 1;
+ }
+
+ if (!driver->probe) {
+ pr_warn("BUG: driver %s has no probe routine\n", driver->name);
+ return 1;
+ }
+
+ driver->drv.bus = &parisc_bus_type;
+
+ /* We install our own probe and remove routines */
+ WARN_ON(driver->drv.probe != NULL);
+ WARN_ON(driver->drv.remove != NULL);
+
+ driver->drv.name = driver->name;
+
+ return driver_register(&driver->drv);
+}
+EXPORT_SYMBOL(register_parisc_driver);
+
+
+struct match_count {
+ struct parisc_driver * driver;
+ int count;
+};
+
+static int match_and_count(struct device * dev, void * data)
+{
+ struct match_count * m = data;
+ struct parisc_device * pdev = to_parisc_device(dev);
+
+ if (check_dev(dev)) {
+ if (match_device(m->driver, pdev))
+ m->count++;
+ }
+ return 0;
+}
+
+/**
+ * count_parisc_driver - count # of devices this driver would match
+ * @driver: the PA-RISC driver to try
+ *
+ * Use by IOMMU support to "guess" the right size IOPdir.
+ * Formula is something like memsize/(num_iommu * entry_size).
+ */
+int __init count_parisc_driver(struct parisc_driver *driver)
+{
+ struct match_count m = {
+ .driver = driver,
+ .count = 0,
+ };
+
+ for_each_padev(match_and_count, &m);
+
+ return m.count;
+}
+
+
+
+/**
+ * unregister_parisc_driver - Unregister this driver from the list of drivers
+ * @driver: the PA-RISC driver to unregister
+ */
+int unregister_parisc_driver(struct parisc_driver *driver)
+{
+ driver_unregister(&driver->drv);
+ return 0;
+}
+EXPORT_SYMBOL(unregister_parisc_driver);
+
+struct find_data {
+ unsigned long hpa;
+ struct parisc_device * dev;
+};
+
+static int find_device(struct device * dev, void * data)
+{
+ struct parisc_device * pdev = to_parisc_device(dev);
+ struct find_data * d = (struct find_data*)data;
+
+ if (check_dev(dev)) {
+ if (pdev->hpa.start == d->hpa) {
+ d->dev = pdev;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static struct parisc_device *find_device_by_addr(unsigned long hpa)
+{
+ struct find_data d = {
+ .hpa = hpa,
+ };
+ int ret;
+
+ ret = for_each_padev(find_device, &d);
+ return ret ? d.dev : NULL;
+}
+
+static int __init is_IKE_device(struct device *dev, void *data)
+{
+ struct parisc_device *pdev = to_parisc_device(dev);
+
+ if (!check_dev(dev))
+ return 0;
+ if (pdev->id.hw_type != HPHW_BCPORT)
+ return 0;
+ if (IS_IKE(pdev) ||
+ (pdev->id.hversion == REO_MERCED_PORT) ||
+ (pdev->id.hversion == REOG_MERCED_PORT)) {
+ return 1;
+ }
+ return 0;
+}
+
+int __init machine_has_merced_bus(void)
+{
+ int ret;
+
+ ret = for_each_padev(is_IKE_device, NULL);
+ return ret ? 1 : 0;
+}
+
+/**
+ * find_pa_parent_type - Find a parent of a specific type
+ * @padev: The device to start searching from
+ * @type: The device type to search for.
+ *
+ * Walks up the device tree looking for a device of the specified type.
+ * If it finds it, it returns it. If not, it returns NULL.
+ */
+const struct parisc_device *
+find_pa_parent_type(const struct parisc_device *padev, int type)
+{
+ const struct device *dev = &padev->dev;
+ while (dev != &root) {
+ struct parisc_device *candidate = to_parisc_device(dev);
+ if (candidate->id.hw_type == type)
+ return candidate;
+ dev = dev->parent;
+ }
+
+ return NULL;
+}
+
+/*
+ * get_node_path fills in @path with the firmware path to the device.
+ * Note that if @node is a parisc device, we don't fill in the 'mod' field.
+ * This is because both callers pass the parent and fill in the mod
+ * themselves. If @node is a PCI device, we do fill it in, even though this
+ * is inconsistent.
+ */
+static void get_node_path(struct device *dev, struct hardware_path *path)
+{
+ int i = 5;
+ memset(&path->bc, -1, 6);
+
+ if (dev_is_pci(dev)) {
+ unsigned int devfn = to_pci_dev(dev)->devfn;
+ path->mod = PCI_FUNC(devfn);
+ path->bc[i--] = PCI_SLOT(devfn);
+ dev = dev->parent;
+ }
+
+ while (dev != &root) {
+ if (dev_is_pci(dev)) {
+ unsigned int devfn = to_pci_dev(dev)->devfn;
+ path->bc[i--] = PCI_SLOT(devfn) | (PCI_FUNC(devfn)<< 5);
+ } else if (dev->bus == &parisc_bus_type) {
+ path->bc[i--] = to_parisc_device(dev)->hw_path;
+ }
+ dev = dev->parent;
+ }
+}
+
+static char *print_hwpath(struct hardware_path *path, char *output)
+{
+ int i;
+ for (i = 0; i < 6; i++) {
+ if (path->bc[i] == -1)
+ continue;
+ output += sprintf(output, "%u/", (unsigned char) path->bc[i]);
+ }
+ output += sprintf(output, "%u", (unsigned char) path->mod);
+ return output;
+}
+
+/**
+ * print_pa_hwpath - Returns hardware path for PA devices
+ * @dev: The device to return the path for
+ * @output: Pointer to a previously-allocated array to place the path in.
+ *
+ * This function fills in the output array with a human-readable path
+ * to a PA device. This string is compatible with that used by PDC, and
+ * may be printed on the outside of the box.
+ */
+char *print_pa_hwpath(struct parisc_device *dev, char *output)
+{
+ struct hardware_path path;
+
+ get_node_path(dev->dev.parent, &path);
+ path.mod = dev->hw_path;
+ return print_hwpath(&path, output);
+}
+EXPORT_SYMBOL(print_pa_hwpath);
+
+#if defined(CONFIG_PCI) || defined(CONFIG_ISA)
+/**
+ * get_pci_node_path - Determines the hardware path for a PCI device
+ * @pdev: The device to return the path for
+ * @path: Pointer to a previously-allocated array to place the path in.
+ *
+ * This function fills in the hardware_path structure with the route to
+ * the specified PCI device. This structure is suitable for passing to
+ * PDC calls.
+ */
+void get_pci_node_path(struct pci_dev *pdev, struct hardware_path *path)
+{
+ get_node_path(&pdev->dev, path);
+}
+EXPORT_SYMBOL(get_pci_node_path);
+
+/**
+ * print_pci_hwpath - Returns hardware path for PCI devices
+ * @dev: The device to return the path for
+ * @output: Pointer to a previously-allocated array to place the path in.
+ *
+ * This function fills in the output array with a human-readable path
+ * to a PCI device. This string is compatible with that used by PDC, and
+ * may be printed on the outside of the box.
+ */
+char *print_pci_hwpath(struct pci_dev *dev, char *output)
+{
+ struct hardware_path path;
+
+ get_pci_node_path(dev, &path);
+ return print_hwpath(&path, output);
+}
+EXPORT_SYMBOL(print_pci_hwpath);
+
+#endif /* defined(CONFIG_PCI) || defined(CONFIG_ISA) */
+
+static void setup_bus_id(struct parisc_device *padev)
+{
+ struct hardware_path path;
+ char name[28];
+ char *output = name;
+ int i;
+
+ get_node_path(padev->dev.parent, &path);
+
+ for (i = 0; i < 6; i++) {
+ if (path.bc[i] == -1)
+ continue;
+ output += sprintf(output, "%u:", (unsigned char) path.bc[i]);
+ }
+ sprintf(output, "%u", (unsigned char) padev->hw_path);
+ dev_set_name(&padev->dev, name);
+}
+
+static struct parisc_device * __init create_tree_node(char id,
+ struct device *parent)
+{
+ struct parisc_device *dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return NULL;
+
+ dev->hw_path = id;
+ dev->id.hw_type = HPHW_FAULTY;
+
+ dev->dev.parent = parent;
+ setup_bus_id(dev);
+
+ dev->dev.bus = &parisc_bus_type;
+ dev->dma_mask = 0xffffffffUL; /* PARISC devices are 32-bit */
+
+ /* make the generic dma mask a pointer to the parisc one */
+ dev->dev.dma_mask = &dev->dma_mask;
+ dev->dev.coherent_dma_mask = dev->dma_mask;
+ if (device_register(&dev->dev)) {
+ kfree(dev);
+ return NULL;
+ }
+
+ return dev;
+}
+
+struct match_id_data {
+ char id;
+ struct parisc_device * dev;
+};
+
+static int match_by_id(struct device * dev, void * data)
+{
+ struct parisc_device * pdev = to_parisc_device(dev);
+ struct match_id_data * d = data;
+
+ if (pdev->hw_path == d->id) {
+ d->dev = pdev;
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * alloc_tree_node - returns a device entry in the iotree
+ * @parent: the parent node in the tree
+ * @id: the element of the module path for this entry
+ *
+ * Checks all the children of @parent for a matching @id. If none
+ * found, it allocates a new device and returns it.
+ */
+static struct parisc_device * __init alloc_tree_node(
+ struct device *parent, char id)
+{
+ struct match_id_data d = {
+ .id = id,
+ };
+ if (device_for_each_child(parent, &d, match_by_id))
+ return d.dev;
+ else
+ return create_tree_node(id, parent);
+}
+
+static struct parisc_device *create_parisc_device(struct hardware_path *modpath)
+{
+ int i;
+ struct device *parent = &root;
+ for (i = 0; i < 6; i++) {
+ if (modpath->bc[i] == -1)
+ continue;
+ parent = &alloc_tree_node(parent, modpath->bc[i])->dev;
+ }
+ return alloc_tree_node(parent, modpath->mod);
+}
+
+struct parisc_device * __init
+alloc_pa_dev(unsigned long hpa, struct hardware_path *mod_path)
+{
+ int status;
+ unsigned long bytecnt;
+ u8 iodc_data[32];
+ struct parisc_device *dev;
+ const char *name;
+
+ /* Check to make sure this device has not already been added - Ryan */
+ if (find_device_by_addr(hpa) != NULL)
+ return NULL;
+
+ status = pdc_iodc_read(&bytecnt, hpa, 0, &iodc_data, 32);
+ if (status != PDC_OK)
+ return NULL;
+
+ dev = create_parisc_device(mod_path);
+ if (dev->id.hw_type != HPHW_FAULTY) {
+ pr_err("Two devices have hardware path [%s]. IODC data for second device: %7phN\n"
+ "Rearranging GSC cards sometimes helps\n",
+ parisc_pathname(dev), iodc_data);
+ return NULL;
+ }
+
+ dev->id.hw_type = iodc_data[3] & 0x1f;
+ dev->id.hversion = (iodc_data[0] << 4) | ((iodc_data[1] & 0xf0) >> 4);
+ dev->id.hversion_rev = iodc_data[1] & 0x0f;
+ dev->id.sversion = ((iodc_data[4] & 0x0f) << 16) |
+ (iodc_data[5] << 8) | iodc_data[6];
+ dev->hpa.start = hpa;
+ /* This is awkward. The STI spec says that gfx devices may occupy
+ * 32MB or 64MB. Unfortunately, we don't know how to tell whether
+ * it's the former or the latter. Assumptions either way can hurt us.
+ */
+ if (hpa == 0xf4000000 || hpa == 0xf8000000) {
+ dev->hpa.end = hpa + 0x03ffffff;
+ } else if (hpa == 0xf6000000 || hpa == 0xfa000000) {
+ dev->hpa.end = hpa + 0x01ffffff;
+ } else {
+ dev->hpa.end = hpa + 0xfff;
+ }
+ dev->hpa.flags = IORESOURCE_MEM;
+ dev->hpa.name = dev->name;
+ name = parisc_hardware_description(&dev->id) ? : "unknown";
+ snprintf(dev->name, sizeof(dev->name), "%s [%s]",
+ name, parisc_pathname(dev));
+
+ /* Silently fail things like mouse ports which are subsumed within
+ * the keyboard controller
+ */
+ if ((hpa & 0xfff) == 0 && insert_resource(&iomem_resource, &dev->hpa))
+ pr_warn("Unable to claim HPA %lx for device %s\n", hpa, name);
+
+ return dev;
+}
+
+static int parisc_generic_match(struct device *dev, struct device_driver *drv)
+{
+ return match_device(to_parisc_driver(drv), to_parisc_device(dev));
+}
+
+static ssize_t make_modalias(const struct device *dev, char *buf)
+{
+ const struct parisc_device *padev = to_parisc_device(dev);
+ const struct parisc_device_id *id = &padev->id;
+
+ return sprintf(buf, "parisc:t%02Xhv%04Xrev%02Xsv%08X\n",
+ (u8)id->hw_type, (u16)id->hversion, (u8)id->hversion_rev,
+ (u32)id->sversion);
+}
+
+static int parisc_uevent(const struct device *dev, struct kobj_uevent_env *env)
+{
+ const struct parisc_device *padev;
+ char modalias[40];
+
+ if (!dev)
+ return -ENODEV;
+
+ padev = to_parisc_device(dev);
+ if (!padev)
+ return -ENODEV;
+
+ if (add_uevent_var(env, "PARISC_NAME=%s", padev->name))
+ return -ENOMEM;
+
+ make_modalias(dev, modalias);
+ if (add_uevent_var(env, "MODALIAS=%s", modalias))
+ return -ENOMEM;
+
+ return 0;
+}
+
+#define pa_dev_attr(name, field, format_string) \
+static ssize_t name##_show(struct device *dev, struct device_attribute *attr, char *buf) \
+{ \
+ struct parisc_device *padev = to_parisc_device(dev); \
+ return sprintf(buf, format_string, padev->field); \
+} \
+static DEVICE_ATTR_RO(name);
+
+#define pa_dev_attr_id(field, format) pa_dev_attr(field, id.field, format)
+
+pa_dev_attr(irq, irq, "%u\n");
+pa_dev_attr_id(hw_type, "0x%02x\n");
+pa_dev_attr(rev, id.hversion_rev, "0x%x\n");
+pa_dev_attr_id(hversion, "0x%03x\n");
+pa_dev_attr_id(sversion, "0x%05x\n");
+
+static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ return make_modalias(dev, buf);
+}
+static DEVICE_ATTR_RO(modalias);
+
+static struct attribute *parisc_device_attrs[] = {
+ &dev_attr_irq.attr,
+ &dev_attr_hw_type.attr,
+ &dev_attr_rev.attr,
+ &dev_attr_hversion.attr,
+ &dev_attr_sversion.attr,
+ &dev_attr_modalias.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(parisc_device);
+
+struct bus_type parisc_bus_type = {
+ .name = "parisc",
+ .match = parisc_generic_match,
+ .uevent = parisc_uevent,
+ .dev_groups = parisc_device_groups,
+ .probe = parisc_driver_probe,
+ .remove = __exit_p(parisc_driver_remove),
+};
+
+/**
+ * register_parisc_device - Locate a driver to manage this device.
+ * @dev: The parisc device.
+ *
+ * Search the driver list for a driver that is willing to manage
+ * this device.
+ */
+int __init register_parisc_device(struct parisc_device *dev)
+{
+ if (!dev)
+ return 0;
+
+ if (dev->driver)
+ return 1;
+
+ return 0;
+}
+
+/**
+ * match_pci_device - Matches a pci device against a given hardware path
+ * entry.
+ * @dev: the generic device (known to be contained by a pci_dev).
+ * @index: the current BC index
+ * @modpath: the hardware path.
+ * @return: true if the device matches the hardware path.
+ */
+static int match_pci_device(struct device *dev, int index,
+ struct hardware_path *modpath)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ int id;
+
+ if (index == 5) {
+ /* we are at the end of the path, and on the actual device */
+ unsigned int devfn = pdev->devfn;
+ return ((modpath->bc[5] == PCI_SLOT(devfn)) &&
+ (modpath->mod == PCI_FUNC(devfn)));
+ }
+
+ /* index might be out of bounds for bc[] */
+ if (index >= 6)
+ return 0;
+
+ id = PCI_SLOT(pdev->devfn) | (PCI_FUNC(pdev->devfn) << 5);
+ return (modpath->bc[index] == id);
+}
+
+/**
+ * match_parisc_device - Matches a parisc device against a given hardware
+ * path entry.
+ * @dev: the generic device (known to be contained by a parisc_device).
+ * @index: the current BC index
+ * @modpath: the hardware path.
+ * @return: true if the device matches the hardware path.
+ */
+static int match_parisc_device(struct device *dev, int index,
+ struct hardware_path *modpath)
+{
+ struct parisc_device *curr = to_parisc_device(dev);
+ char id = (index == 6) ? modpath->mod : modpath->bc[index];
+
+ return (curr->hw_path == id);
+}
+
+struct parse_tree_data {
+ int index;
+ struct hardware_path * modpath;
+ struct device * dev;
+};
+
+static int check_parent(struct device * dev, void * data)
+{
+ struct parse_tree_data * d = data;
+
+ if (check_dev(dev)) {
+ if (dev->bus == &parisc_bus_type) {
+ if (match_parisc_device(dev, d->index, d->modpath))
+ d->dev = dev;
+ } else if (dev_is_pci(dev)) {
+ if (match_pci_device(dev, d->index, d->modpath))
+ d->dev = dev;
+ } else if (dev->bus == NULL) {
+ /* we are on a bus bridge */
+ struct device *new = parse_tree_node(dev, d->index, d->modpath);
+ if (new)
+ d->dev = new;
+ }
+ }
+ return d->dev != NULL;
+}
+
+/**
+ * parse_tree_node - returns a device entry in the iotree
+ * @parent: the parent node in the tree
+ * @index: the current BC index
+ * @modpath: the hardware_path struct to match a device against
+ * @return: The corresponding device if found, NULL otherwise.
+ *
+ * Checks all the children of @parent for a matching @id. If none
+ * found, it returns NULL.
+ */
+static struct device *
+parse_tree_node(struct device *parent, int index, struct hardware_path *modpath)
+{
+ struct parse_tree_data d = {
+ .index = index,
+ .modpath = modpath,
+ };
+
+ struct recurse_struct recurse_data = {
+ .obj = &d,
+ .fn = check_parent,
+ };
+
+ if (device_for_each_child(parent, &recurse_data, descend_children))
+ { /* nothing */ };
+
+ return d.dev;
+}
+
+/**
+ * hwpath_to_device - Finds the generic device corresponding to a given hardware path.
+ * @modpath: the hardware path.
+ * @return: The target device, NULL if not found.
+ */
+struct device *hwpath_to_device(struct hardware_path *modpath)
+{
+ int i;
+ struct device *parent = &root;
+ for (i = 0; i < 6; i++) {
+ if (modpath->bc[i] == -1)
+ continue;
+ parent = parse_tree_node(parent, i, modpath);
+ if (!parent)
+ return NULL;
+ }
+ if (dev_is_pci(parent)) /* pci devices already parse MOD */
+ return parent;
+ else
+ return parse_tree_node(parent, 6, modpath);
+}
+EXPORT_SYMBOL(hwpath_to_device);
+
+/**
+ * device_to_hwpath - Populates the hwpath corresponding to the given device.
+ * @dev: the target device
+ * @path: pointer to a previously allocated hwpath struct to be filled in
+ */
+void device_to_hwpath(struct device *dev, struct hardware_path *path)
+{
+ struct parisc_device *padev;
+ if (dev->bus == &parisc_bus_type) {
+ padev = to_parisc_device(dev);
+ get_node_path(dev->parent, path);
+ path->mod = padev->hw_path;
+ } else if (dev_is_pci(dev)) {
+ get_node_path(dev, path);
+ }
+}
+EXPORT_SYMBOL(device_to_hwpath);
+
+#define BC_PORT_MASK 0x8
+#define BC_LOWER_PORT 0x8
+
+#define BUS_CONVERTER(dev) \
+ ((dev->id.hw_type == HPHW_IOA) || (dev->id.hw_type == HPHW_BCPORT))
+
+#define IS_LOWER_PORT(dev) \
+ ((gsc_readl(dev->hpa.start + offsetof(struct bc_module, io_status)) \
+ & BC_PORT_MASK) == BC_LOWER_PORT)
+
+#define MAX_NATIVE_DEVICES 64
+#define NATIVE_DEVICE_OFFSET 0x1000
+
+#define FLEX_MASK F_EXTEND(0xfffc0000)
+#define IO_IO_LOW offsetof(struct bc_module, io_io_low)
+#define IO_IO_HIGH offsetof(struct bc_module, io_io_high)
+#define READ_IO_IO_LOW(dev) (unsigned long)(signed int)gsc_readl(dev->hpa.start + IO_IO_LOW)
+#define READ_IO_IO_HIGH(dev) (unsigned long)(signed int)gsc_readl(dev->hpa.start + IO_IO_HIGH)
+
+static void walk_native_bus(unsigned long io_io_low, unsigned long io_io_high,
+ struct device *parent);
+
+static void __init walk_lower_bus(struct parisc_device *dev)
+{
+ unsigned long io_io_low, io_io_high;
+
+ if (!BUS_CONVERTER(dev) || IS_LOWER_PORT(dev))
+ return;
+
+ if (dev->id.hw_type == HPHW_IOA) {
+ io_io_low = (unsigned long)(signed int)(READ_IO_IO_LOW(dev) << 16);
+ io_io_high = io_io_low + MAX_NATIVE_DEVICES * NATIVE_DEVICE_OFFSET;
+ } else {
+ io_io_low = (READ_IO_IO_LOW(dev) + ~FLEX_MASK) & FLEX_MASK;
+ io_io_high = (READ_IO_IO_HIGH(dev)+ ~FLEX_MASK) & FLEX_MASK;
+ }
+
+ walk_native_bus(io_io_low, io_io_high, &dev->dev);
+}
+
+/**
+ * walk_native_bus -- Probe a bus for devices
+ * @io_io_low: Base address of this bus.
+ * @io_io_high: Last address of this bus.
+ * @parent: The parent bus device.
+ *
+ * A native bus (eg Runway or GSC) may have up to 64 devices on it,
+ * spaced at intervals of 0x1000 bytes. PDC may not inform us of these
+ * devices, so we have to probe for them. Unfortunately, we may find
+ * devices which are not physically connected (such as extra serial &
+ * keyboard ports). This problem is not yet solved.
+ */
+static void __init walk_native_bus(unsigned long io_io_low,
+ unsigned long io_io_high, struct device *parent)
+{
+ int i, devices_found = 0;
+ unsigned long hpa = io_io_low;
+ struct hardware_path path;
+
+ get_node_path(parent, &path);
+ do {
+ for(i = 0; i < MAX_NATIVE_DEVICES; i++, hpa += NATIVE_DEVICE_OFFSET) {
+ struct parisc_device *dev;
+
+ /* Was the device already added by Firmware? */
+ dev = find_device_by_addr(hpa);
+ if (!dev) {
+ path.mod = i;
+ dev = alloc_pa_dev(hpa, &path);
+ if (!dev)
+ continue;
+
+ register_parisc_device(dev);
+ devices_found++;
+ }
+ walk_lower_bus(dev);
+ }
+ } while(!devices_found && hpa < io_io_high);
+}
+
+#define CENTRAL_BUS_ADDR F_EXTEND(0xfff80000)
+
+/**
+ * walk_central_bus - Find devices attached to the central bus
+ *
+ * PDC doesn't tell us about all devices in the system. This routine
+ * finds devices connected to the central bus.
+ */
+void __init walk_central_bus(void)
+{
+ walk_native_bus(CENTRAL_BUS_ADDR,
+ CENTRAL_BUS_ADDR + (MAX_NATIVE_DEVICES * NATIVE_DEVICE_OFFSET),
+ &root);
+}
+
+static __init void print_parisc_device(struct parisc_device *dev)
+{
+ static int count __initdata;
+
+ pr_info("%d. %s at %pap { type:%d, hv:%#x, sv:%#x, rev:%#x }",
+ ++count, dev->name, &(dev->hpa.start), dev->id.hw_type,
+ dev->id.hversion, dev->id.sversion, dev->id.hversion_rev);
+
+ if (dev->num_addrs) {
+ int k;
+ pr_cont(", additional addresses: ");
+ for (k = 0; k < dev->num_addrs; k++)
+ pr_cont("0x%lx ", dev->addr[k]);
+ }
+ pr_cont("\n");
+}
+
+/**
+ * init_parisc_bus - Some preparation to be done before inventory
+ */
+void __init init_parisc_bus(void)
+{
+ if (bus_register(&parisc_bus_type))
+ panic("Could not register PA-RISC bus type\n");
+ if (device_register(&root))
+ panic("Could not register PA-RISC root device\n");
+ get_device(&root);
+}
+
+static __init void qemu_header(void)
+{
+ int num;
+ unsigned long *p;
+
+ pr_info("--- cut here ---\n");
+ pr_info("/* AUTO-GENERATED HEADER FILE FOR SEABIOS FIRMWARE */\n");
+ pr_cont("/* generated with Linux kernel */\n");
+ pr_cont("/* search for PARISC_QEMU_MACHINE_HEADER in Linux */\n\n");
+
+ pr_info("#define PARISC_MODEL \"%s\"\n\n",
+ boot_cpu_data.pdc.sys_model_name);
+
+ #define p ((unsigned long *)&boot_cpu_data.pdc.model)
+ pr_info("#define PARISC_PDC_MODEL 0x%lx, 0x%lx, 0x%lx, "
+ "0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx\n\n",
+ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8]);
+ #undef p
+
+ pr_info("#define PARISC_PDC_VERSION 0x%04lx\n\n",
+ boot_cpu_data.pdc.versions);
+
+ pr_info("#define PARISC_PDC_CPUID 0x%04lx\n\n",
+ boot_cpu_data.pdc.cpuid);
+
+ pr_info("#define PARISC_PDC_CAPABILITIES 0x%04lx\n\n",
+ boot_cpu_data.pdc.capabilities);
+
+ pr_info("#define PARISC_PDC_ENTRY_ORG 0x%04lx\n\n",
+#ifdef CONFIG_64BIT
+ (unsigned long)(PAGE0->mem_pdc_hi) << 32 |
+#endif
+ (unsigned long)PAGE0->mem_pdc);
+
+ pr_info("#define PARISC_PDC_CACHE_INFO");
+ p = (unsigned long *) &cache_info;
+ for (num = 0; num < sizeof(cache_info); num += sizeof(unsigned long)) {
+ if (((num % 5) == 0)) {
+ pr_cont(" \\\n");
+ pr_info("\t");
+ }
+ pr_cont("%s0x%04lx",
+ num?", ":"", *p++);
+ }
+ pr_cont("\n\n");
+}
+
+static __init int qemu_print_hpa(struct device *lin_dev, void *data)
+{
+ struct parisc_device *dev = to_parisc_device(lin_dev);
+ unsigned long hpa = dev->hpa.start;
+
+ pr_cont("\t{\t.hpa = 0x%08lx,\\\n", hpa);
+ pr_cont("\t\t.iodc = &iodc_data_hpa_%08lx,\\\n", hpa);
+ pr_cont("\t\t.mod_info = &mod_info_hpa_%08lx,\\\n", hpa);
+ pr_cont("\t\t.mod_path = &mod_path_hpa_%08lx,\\\n", hpa);
+ pr_cont("\t\t.num_addr = HPA_%08lx_num_addr,\\\n", hpa);
+ pr_cont("\t\t.add_addr = { HPA_%08lx_add_addr } },\\\n", hpa);
+ return 0;
+}
+
+
+static __init void qemu_footer(void)
+{
+ pr_info("\n\n#define PARISC_DEVICE_LIST \\\n");
+ for_each_padev(qemu_print_hpa, NULL);
+ pr_cont("\t{ 0, }\n");
+ pr_info("--- cut here ---\n");
+}
+
+/* print iodc data of the various hpa modules for qemu inclusion */
+static __init int qemu_print_iodc_data(struct device *lin_dev, void *data)
+{
+ struct parisc_device *dev = to_parisc_device(lin_dev);
+ unsigned long count;
+ unsigned long hpa = dev->hpa.start;
+ int status;
+ struct pdc_iodc iodc_data;
+
+ int mod_index;
+ struct pdc_system_map_mod_info pdc_mod_info;
+ struct pdc_module_path mod_path;
+
+ status = pdc_iodc_read(&count, hpa, 0,
+ &iodc_data, sizeof(iodc_data));
+ if (status != PDC_OK) {
+ pr_info("No IODC data for hpa 0x%08lx\n", hpa);
+ return 0;
+ }
+
+ pr_info("\n");
+
+ pr_info("#define HPA_%08lx_DESCRIPTION \"%s\"\n",
+ hpa, parisc_hardware_description(&dev->id));
+
+ mod_index = 0;
+ do {
+ status = pdc_system_map_find_mods(&pdc_mod_info,
+ &mod_path, mod_index++);
+ } while (status == PDC_OK && pdc_mod_info.mod_addr != hpa);
+
+ pr_info("static struct pdc_system_map_mod_info"
+ " mod_info_hpa_%08lx = {\n", hpa);
+ #define DO(member) \
+ pr_cont("\t." #member " = 0x%x,\n", \
+ (unsigned int)pdc_mod_info.member)
+ DO(mod_addr);
+ DO(mod_pgs);
+ DO(add_addrs);
+ pr_cont("};\n");
+ #undef DO
+ pr_info("static struct pdc_module_path "
+ "mod_path_hpa_%08lx = {\n", hpa);
+ pr_cont("\t.path = { ");
+ pr_cont(".flags = 0x%x, ", mod_path.path.flags);
+ pr_cont(".bc = { 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x }, ",
+ (unsigned char)mod_path.path.bc[0],
+ (unsigned char)mod_path.path.bc[1],
+ (unsigned char)mod_path.path.bc[2],
+ (unsigned char)mod_path.path.bc[3],
+ (unsigned char)mod_path.path.bc[4],
+ (unsigned char)mod_path.path.bc[5]);
+ pr_cont(".mod = 0x%x ", mod_path.path.mod);
+ pr_cont(" },\n");
+ pr_cont("\t.layers = { 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x }\n",
+ mod_path.layers[0], mod_path.layers[1], mod_path.layers[2],
+ mod_path.layers[3], mod_path.layers[4], mod_path.layers[5]);
+ pr_cont("};\n");
+
+ pr_info("static struct pdc_iodc iodc_data_hpa_%08lx = {\n", hpa);
+ #define DO(member) \
+ pr_cont("\t." #member " = 0x%04lx,\n", \
+ (unsigned long)iodc_data.member)
+ DO(hversion_model);
+ DO(hversion);
+ DO(spa);
+ DO(type);
+ DO(sversion_rev);
+ DO(sversion_model);
+ DO(sversion_opt);
+ DO(rev);
+ DO(dep);
+ DO(features);
+ DO(checksum);
+ DO(length);
+ #undef DO
+ pr_cont("\t/* pad: 0x%04x, 0x%04x */\n",
+ iodc_data.pad[0], iodc_data.pad[1]);
+ pr_cont("};\n");
+
+ pr_info("#define HPA_%08lx_num_addr %d\n", hpa, dev->num_addrs);
+ pr_info("#define HPA_%08lx_add_addr ", hpa);
+ count = 0;
+ if (dev->num_addrs == 0)
+ pr_cont("0");
+ while (count < dev->num_addrs) {
+ pr_cont("0x%08lx, ", dev->addr[count]);
+ count++;
+ }
+ pr_cont("\n\n");
+
+ return 0;
+}
+
+
+
+static __init int print_one_device(struct device * dev, void * data)
+{
+ struct parisc_device * pdev = to_parisc_device(dev);
+
+ if (check_dev(dev))
+ print_parisc_device(pdev);
+ return 0;
+}
+
+/**
+ * print_parisc_devices - Print out a list of devices found in this system
+ */
+void __init print_parisc_devices(void)
+{
+ for_each_padev(print_one_device, NULL);
+ #define PARISC_QEMU_MACHINE_HEADER 0
+ if (PARISC_QEMU_MACHINE_HEADER) {
+ qemu_header();
+ for_each_padev(qemu_print_iodc_data, NULL);
+ qemu_footer();
+ }
+}
diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S
new file mode 100644
index 000000000..ab23e61a6
--- /dev/null
+++ b/arch/parisc/kernel/entry.S
@@ -0,0 +1,2341 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * kernel entry points (interruptions, system call wrappers)
+ * Copyright (C) 1999,2000 Philipp Rumpf
+ * Copyright (C) 1999 SuSE GmbH Nuernberg
+ * Copyright (C) 2000 Hewlett-Packard (John Marvin)
+ * Copyright (C) 1999 Hewlett-Packard (Frank Rowand)
+ */
+
+#include <asm/asm-offsets.h>
+
+/* we have the following possibilities to act on an interruption:
+ * - handle in assembly and use shadowed registers only
+ * - save registers to kernel stack and handle in assembly or C */
+
+
+#include <asm/psw.h>
+#include <asm/cache.h> /* for L1_CACHE_SHIFT */
+#include <asm/assembly.h> /* for LDREG/STREG defines */
+#include <asm/signal.h>
+#include <asm/unistd.h>
+#include <asm/ldcw.h>
+#include <asm/traps.h>
+#include <asm/thread_info.h>
+#include <asm/alternative.h>
+#include <asm/spinlock_types.h>
+
+#include <linux/linkage.h>
+#include <linux/pgtable.h>
+
+#ifdef CONFIG_64BIT
+ .level 2.0w
+#else
+ .level 2.0
+#endif
+
+/*
+ * We need seven instructions after a TLB insert for it to take effect.
+ * The PA8800/PA8900 processors are an exception and need 12 instructions.
+ * The RFI changes both IAOQ_Back and IAOQ_Front, so it counts as one.
+ */
+#ifdef CONFIG_64BIT
+#define NUM_PIPELINE_INSNS 12
+#else
+#define NUM_PIPELINE_INSNS 7
+#endif
+
+ /* Insert num nops */
+ .macro insert_nops num
+ .rept \num
+ nop
+ .endr
+ .endm
+
+ /* Get aligned page_table_lock address for this mm from cr28/tr4 */
+ .macro get_ptl reg
+ mfctl %cr28,\reg
+ .endm
+
+ /* space_to_prot macro creates a prot id from a space id */
+
+#if (SPACEID_SHIFT) == 0
+ .macro space_to_prot spc prot
+ depd,z \spc,62,31,\prot
+ .endm
+#else
+ .macro space_to_prot spc prot
+ extrd,u \spc,(64 - (SPACEID_SHIFT)),32,\prot
+ .endm
+#endif
+ /*
+ * The "get_stack" macros are responsible for determining the
+ * kernel stack value.
+ *
+ * If sr7 == 0
+ * Already using a kernel stack, so call the
+ * get_stack_use_r30 macro to push a pt_regs structure
+ * on the stack, and store registers there.
+ * else
+ * Need to set up a kernel stack, so call the
+ * get_stack_use_cr30 macro to set up a pointer
+ * to the pt_regs structure contained within the
+ * task pointer pointed to by cr30. Load the stack
+ * pointer from the task structure.
+ *
+ * Note that we use shadowed registers for temps until
+ * we can save %r26 and %r29. %r26 is used to preserve
+ * %r8 (a shadowed register) which temporarily contained
+ * either the fault type ("code") or the eirr. We need
+ * to use a non-shadowed register to carry the value over
+ * the rfir in virt_map. We use %r26 since this value winds
+ * up being passed as the argument to either do_cpu_irq_mask
+ * or handle_interruption. %r29 is used to hold a pointer
+ * the register save area, and once again, it needs to
+ * be a non-shadowed register so that it survives the rfir.
+ */
+
+ .macro get_stack_use_cr30
+
+ /* we save the registers in the task struct */
+
+ copy %r30, %r17
+ mfctl %cr30, %r1
+ tophys %r1,%r9 /* task_struct */
+ LDREG TASK_STACK(%r9),%r30
+ ldo PT_SZ_ALGN(%r30),%r30
+ mtsp %r0,%sr7 /* clear sr7 after kernel stack was set! */
+ mtsp %r16,%sr3
+ ldo TASK_REGS(%r9),%r9
+ STREG %r17,PT_GR30(%r9)
+ STREG %r29,PT_GR29(%r9)
+ STREG %r26,PT_GR26(%r9)
+ STREG %r16,PT_SR7(%r9)
+ copy %r9,%r29
+ .endm
+
+ .macro get_stack_use_r30
+
+ /* we put a struct pt_regs on the stack and save the registers there */
+
+ tophys %r30,%r9
+ copy %r30,%r1
+ ldo PT_SZ_ALGN(%r30),%r30
+ STREG %r1,PT_GR30(%r9)
+ STREG %r29,PT_GR29(%r9)
+ STREG %r26,PT_GR26(%r9)
+ STREG %r16,PT_SR7(%r9)
+ copy %r9,%r29
+ .endm
+
+ .macro rest_stack
+ LDREG PT_GR1(%r29), %r1
+ LDREG PT_GR30(%r29),%r30
+ LDREG PT_GR29(%r29),%r29
+ .endm
+
+ /* default interruption handler
+ * (calls traps.c:handle_interruption) */
+ .macro def code
+ b intr_save
+ ldi \code, %r8
+ .align 32
+ .endm
+
+ /* Interrupt interruption handler
+ * (calls irq.c:do_cpu_irq_mask) */
+ .macro extint code
+ b intr_extint
+ mfsp %sr7,%r16
+ .align 32
+ .endm
+
+ .import os_hpmc, code
+
+ /* HPMC handler */
+ .macro hpmc code
+ nop /* must be a NOP, will be patched later */
+ load32 PA(os_hpmc), %r3
+ bv,n 0(%r3)
+ nop
+ .word 0 /* checksum (will be patched) */
+ .word 0 /* address of handler */
+ .word 0 /* length of handler */
+ .endm
+
+ /*
+ * Performance Note: Instructions will be moved up into
+ * this part of the code later on, once we are sure
+ * that the tlb miss handlers are close to final form.
+ */
+
+ /* Register definitions for tlb miss handler macros */
+
+ va = r8 /* virtual address for which the trap occurred */
+ spc = r24 /* space for which the trap occurred */
+
+#ifndef CONFIG_64BIT
+
+ /*
+ * itlb miss interruption handler (parisc 1.1 - 32 bit)
+ */
+
+ .macro itlb_11 code
+
+ mfctl %pcsq, spc
+ b itlb_miss_11
+ mfctl %pcoq, va
+
+ .align 32
+ .endm
+#endif
+
+ /*
+ * itlb miss interruption handler (parisc 2.0)
+ */
+
+ .macro itlb_20 code
+ mfctl %pcsq, spc
+#ifdef CONFIG_64BIT
+ b itlb_miss_20w
+#else
+ b itlb_miss_20
+#endif
+ mfctl %pcoq, va
+
+ .align 32
+ .endm
+
+#ifndef CONFIG_64BIT
+ /*
+ * naitlb miss interruption handler (parisc 1.1 - 32 bit)
+ */
+
+ .macro naitlb_11 code
+
+ mfctl %isr,spc
+ b naitlb_miss_11
+ mfctl %ior,va
+
+ .align 32
+ .endm
+#endif
+
+ /*
+ * naitlb miss interruption handler (parisc 2.0)
+ */
+
+ .macro naitlb_20 code
+
+ mfctl %isr,spc
+#ifdef CONFIG_64BIT
+ b naitlb_miss_20w
+#else
+ b naitlb_miss_20
+#endif
+ mfctl %ior,va
+
+ .align 32
+ .endm
+
+#ifndef CONFIG_64BIT
+ /*
+ * dtlb miss interruption handler (parisc 1.1 - 32 bit)
+ */
+
+ .macro dtlb_11 code
+
+ mfctl %isr, spc
+ b dtlb_miss_11
+ mfctl %ior, va
+
+ .align 32
+ .endm
+#endif
+
+ /*
+ * dtlb miss interruption handler (parisc 2.0)
+ */
+
+ .macro dtlb_20 code
+
+ mfctl %isr, spc
+#ifdef CONFIG_64BIT
+ b dtlb_miss_20w
+#else
+ b dtlb_miss_20
+#endif
+ mfctl %ior, va
+
+ .align 32
+ .endm
+
+#ifndef CONFIG_64BIT
+ /* nadtlb miss interruption handler (parisc 1.1 - 32 bit) */
+
+ .macro nadtlb_11 code
+
+ mfctl %isr,spc
+ b nadtlb_miss_11
+ mfctl %ior,va
+
+ .align 32
+ .endm
+#endif
+
+ /* nadtlb miss interruption handler (parisc 2.0) */
+
+ .macro nadtlb_20 code
+
+ mfctl %isr,spc
+#ifdef CONFIG_64BIT
+ b nadtlb_miss_20w
+#else
+ b nadtlb_miss_20
+#endif
+ mfctl %ior,va
+
+ .align 32
+ .endm
+
+#ifndef CONFIG_64BIT
+ /*
+ * dirty bit trap interruption handler (parisc 1.1 - 32 bit)
+ */
+
+ .macro dbit_11 code
+
+ mfctl %isr,spc
+ b dbit_trap_11
+ mfctl %ior,va
+
+ .align 32
+ .endm
+#endif
+
+ /*
+ * dirty bit trap interruption handler (parisc 2.0)
+ */
+
+ .macro dbit_20 code
+
+ mfctl %isr,spc
+#ifdef CONFIG_64BIT
+ b dbit_trap_20w
+#else
+ b dbit_trap_20
+#endif
+ mfctl %ior,va
+
+ .align 32
+ .endm
+
+ /* In LP64, the space contains part of the upper 32 bits of the
+ * fault. We have to extract this and place it in the va,
+ * zeroing the corresponding bits in the space register */
+ .macro space_adjust spc,va,tmp
+#ifdef CONFIG_64BIT
+ extrd,u \spc,63,SPACEID_SHIFT,\tmp
+ depd %r0,63,SPACEID_SHIFT,\spc
+ depd \tmp,31,SPACEID_SHIFT,\va
+#endif
+ .endm
+
+ .import swapper_pg_dir,code
+
+ /* Get the pgd. For faults on space zero (kernel space), this
+ * is simply swapper_pg_dir. For user space faults, the
+ * pgd is stored in %cr25 */
+ .macro get_pgd spc,reg
+ ldil L%PA(swapper_pg_dir),\reg
+ ldo R%PA(swapper_pg_dir)(\reg),\reg
+ or,COND(=) %r0,\spc,%r0
+ mfctl %cr25,\reg
+ .endm
+
+ /*
+ space_check(spc,tmp,fault)
+
+ spc - The space we saw the fault with.
+ tmp - The place to store the current space.
+ fault - Function to call on failure.
+
+ Only allow faults on different spaces from the
+ currently active one if we're the kernel
+
+ */
+ .macro space_check spc,tmp,fault
+ mfsp %sr7,\tmp
+ /* check against %r0 which is same value as LINUX_GATEWAY_SPACE */
+ or,COND(<>) %r0,\spc,%r0 /* user may execute gateway page
+ * as kernel, so defeat the space
+ * check if it is */
+ copy \spc,\tmp
+ or,COND(=) %r0,\tmp,%r0 /* nullify if executing as kernel */
+ cmpb,COND(<>),n \tmp,\spc,\fault
+ .endm
+
+ /* Look up a PTE in a 2-Level scheme (faulting at each
+ * level if the entry isn't present
+ *
+ * NOTE: we use ldw even for LP64, since the short pointers
+ * can address up to 1TB
+ */
+ .macro L2_ptep pmd,pte,index,va,fault
+#if CONFIG_PGTABLE_LEVELS == 3
+ extru_safe \va,31-ASM_PMD_SHIFT,ASM_BITS_PER_PMD,\index
+#else
+ extru_safe \va,31-ASM_PGDIR_SHIFT,ASM_BITS_PER_PGD,\index
+#endif
+ dep %r0,31,PAGE_SHIFT,\pmd /* clear offset */
+#if CONFIG_PGTABLE_LEVELS < 3
+ copy %r0,\pte
+#endif
+ ldw,s \index(\pmd),\pmd
+ bb,>=,n \pmd,_PxD_PRESENT_BIT,\fault
+ dep %r0,31,PxD_FLAG_SHIFT,\pmd /* clear flags */
+ SHLREG \pmd,PxD_VALUE_SHIFT,\pmd
+ extru_safe \va,31-PAGE_SHIFT,ASM_BITS_PER_PTE,\index
+ dep %r0,31,PAGE_SHIFT,\pmd /* clear offset */
+ shladd \index,BITS_PER_PTE_ENTRY,\pmd,\pmd /* pmd is now pte */
+ .endm
+
+ /* Look up PTE in a 3-Level scheme. */
+ .macro L3_ptep pgd,pte,index,va,fault
+#if CONFIG_PGTABLE_LEVELS == 3
+ copy %r0,\pte
+ extrd,u \va,63-ASM_PGDIR_SHIFT,ASM_BITS_PER_PGD,\index
+ ldw,s \index(\pgd),\pgd
+ bb,>=,n \pgd,_PxD_PRESENT_BIT,\fault
+ shld \pgd,PxD_VALUE_SHIFT,\pgd
+#endif
+ L2_ptep \pgd,\pte,\index,\va,\fault
+ .endm
+
+ /* Acquire page_table_lock and check page is present. */
+ .macro ptl_lock spc,ptp,pte,tmp,tmp1,fault
+#ifdef CONFIG_TLB_PTLOCK
+98: cmpib,COND(=),n 0,\spc,2f
+ get_ptl \tmp
+1: LDCW 0(\tmp),\tmp1
+ cmpib,COND(=) 0,\tmp1,1b
+ nop
+ LDREG 0(\ptp),\pte
+ bb,<,n \pte,_PAGE_PRESENT_BIT,3f
+ b \fault
+ stw \tmp1,0(\tmp)
+99: ALTERNATIVE(98b, 99b, ALT_COND_NO_SMP, INSN_NOP)
+#endif
+2: LDREG 0(\ptp),\pte
+ bb,>=,n \pte,_PAGE_PRESENT_BIT,\fault
+3:
+ .endm
+
+ /* Release page_table_lock if for user space. We use an ordered
+ store to ensure all prior accesses are performed prior to
+ releasing the lock. Note stw may not be executed, so we
+ provide one extra nop when CONFIG_TLB_PTLOCK is defined. */
+ .macro ptl_unlock spc,tmp,tmp2
+#ifdef CONFIG_TLB_PTLOCK
+98: get_ptl \tmp
+ ldi __ARCH_SPIN_LOCK_UNLOCKED_VAL, \tmp2
+ or,COND(=) %r0,\spc,%r0
+ stw,ma \tmp2,0(\tmp)
+99: ALTERNATIVE(98b, 99b, ALT_COND_NO_SMP, INSN_NOP)
+ insert_nops NUM_PIPELINE_INSNS - 4
+#else
+ insert_nops NUM_PIPELINE_INSNS - 1
+#endif
+ .endm
+
+ /* Set the _PAGE_ACCESSED bit of the PTE. Be clever and
+ * don't needlessly dirty the cache line if it was already set */
+ .macro update_accessed ptp,pte,tmp,tmp1
+ ldi _PAGE_ACCESSED,\tmp1
+ or \tmp1,\pte,\tmp
+ and,COND(<>) \tmp1,\pte,%r0
+ STREG \tmp,0(\ptp)
+ .endm
+
+ /* Set the dirty bit (and accessed bit). No need to be
+ * clever, this is only used from the dirty fault */
+ .macro update_dirty ptp,pte,tmp
+ ldi _PAGE_ACCESSED|_PAGE_DIRTY,\tmp
+ or \tmp,\pte,\pte
+ STREG \pte,0(\ptp)
+ .endm
+
+ /* We have (depending on the page size):
+ * - 38 to 52-bit Physical Page Number
+ * - 12 to 26-bit page offset
+ */
+ /* bitshift difference between a PFN (based on kernel's PAGE_SIZE)
+ * to a CPU TLB 4k PFN (4k => 12 bits to shift) */
+ #define PAGE_ADD_SHIFT (PAGE_SHIFT-12)
+ #define PAGE_ADD_HUGE_SHIFT (REAL_HPAGE_SHIFT-12)
+ #define PFN_START_BIT (63-ASM_PFN_PTE_SHIFT+(63-58)-PAGE_ADD_SHIFT)
+
+ /* Drop prot bits and convert to page addr for iitlbt and idtlbt */
+ .macro convert_for_tlb_insert20 pte,tmp
+#ifdef CONFIG_HUGETLB_PAGE
+ copy \pte,\tmp
+ extrd,u \tmp,PFN_START_BIT,PFN_START_BIT+1,\pte
+
+ depdi _PAGE_SIZE_ENCODING_DEFAULT,63,\
+ (63-58)+PAGE_ADD_SHIFT,\pte
+ extrd,u,*= \tmp,_PAGE_HPAGE_BIT+32,1,%r0
+ depdi _HUGE_PAGE_SIZE_ENCODING_DEFAULT,63,\
+ (63-58)+PAGE_ADD_HUGE_SHIFT,\pte
+#else /* Huge pages disabled */
+ extrd,u \pte,PFN_START_BIT,PFN_START_BIT+1,\pte
+ depdi _PAGE_SIZE_ENCODING_DEFAULT,63,\
+ (63-58)+PAGE_ADD_SHIFT,\pte
+#endif
+ .endm
+
+ /* Convert the pte and prot to tlb insertion values. How
+ * this happens is quite subtle, read below */
+ .macro make_insert_tlb spc,pte,prot,tmp
+ space_to_prot \spc \prot /* create prot id from space */
+ /* The following is the real subtlety. This is depositing
+ * T <-> _PAGE_REFTRAP
+ * D <-> _PAGE_DIRTY
+ * B <-> _PAGE_DMB (memory break)
+ *
+ * Then incredible subtlety: The access rights are
+ * _PAGE_GATEWAY, _PAGE_EXEC and _PAGE_WRITE
+ * See 3-14 of the parisc 2.0 manual
+ *
+ * Finally, _PAGE_READ goes in the top bit of PL1 (so we
+ * trigger an access rights trap in user space if the user
+ * tries to read an unreadable page */
+#if _PAGE_SPECIAL_BIT == _PAGE_DMB_BIT
+ /* need to drop DMB bit, as it's used as SPECIAL flag */
+ depi 0,_PAGE_SPECIAL_BIT,1,\pte
+#endif
+ depd \pte,8,7,\prot
+
+ /* PAGE_USER indicates the page can be read with user privileges,
+ * so deposit X1|11 to PL1|PL2 (remember the upper bit of PL1
+ * contains _PAGE_READ) */
+ extrd,u,*= \pte,_PAGE_USER_BIT+32,1,%r0
+ depdi 7,11,3,\prot
+ /* If we're a gateway page, drop PL2 back to zero for promotion
+ * to kernel privilege (so we can execute the page as kernel).
+ * Any privilege promotion page always denys read and write */
+ extrd,u,*= \pte,_PAGE_GATEWAY_BIT+32,1,%r0
+ depd %r0,11,2,\prot /* If Gateway, Set PL2 to 0 */
+
+ /* Enforce uncacheable pages.
+ * This should ONLY be use for MMIO on PA 2.0 machines.
+ * Memory/DMA is cache coherent on all PA2.0 machines we support
+ * (that means T-class is NOT supported) and the memory controllers
+ * on most of those machines only handles cache transactions.
+ */
+ extrd,u,*= \pte,_PAGE_NO_CACHE_BIT+32,1,%r0
+ depdi 1,12,1,\prot
+
+ /* Drop prot bits and convert to page addr for iitlbt and idtlbt */
+ convert_for_tlb_insert20 \pte \tmp
+ .endm
+
+ /* Identical macro to make_insert_tlb above, except it
+ * makes the tlb entry for the differently formatted pa11
+ * insertion instructions */
+ .macro make_insert_tlb_11 spc,pte,prot
+#if _PAGE_SPECIAL_BIT == _PAGE_DMB_BIT
+ /* need to drop DMB bit, as it's used as SPECIAL flag */
+ depi 0,_PAGE_SPECIAL_BIT,1,\pte
+#endif
+ zdep \spc,30,15,\prot
+ dep \pte,8,7,\prot
+ extru,= \pte,_PAGE_NO_CACHE_BIT,1,%r0
+ depi 1,12,1,\prot
+ extru,= \pte,_PAGE_USER_BIT,1,%r0
+ depi 7,11,3,\prot /* Set for user space (1 rsvd for read) */
+ extru,= \pte,_PAGE_GATEWAY_BIT,1,%r0
+ depi 0,11,2,\prot /* If Gateway, Set PL2 to 0 */
+
+ /* Get rid of prot bits and convert to page addr for iitlba */
+
+ depi 0,31,ASM_PFN_PTE_SHIFT,\pte
+ SHRREG \pte,(ASM_PFN_PTE_SHIFT-(31-26)),\pte
+ .endm
+
+ /* This is for ILP32 PA2.0 only. The TLB insertion needs
+ * to extend into I/O space if the address is 0xfXXXXXXX
+ * so we extend the f's into the top word of the pte in
+ * this case */
+ .macro f_extend pte,tmp
+ extrd,s \pte,42,4,\tmp
+ addi,<> 1,\tmp,%r0
+ extrd,s \pte,63,25,\pte
+ .endm
+
+ /* The alias region is comprised of a pair of 4 MB regions
+ * aligned to 8 MB. It is used to clear/copy/flush user pages
+ * using kernel virtual addresses congruent with the user
+ * virtual address.
+ *
+ * To use the alias page, you set %r26 up with the to TLB
+ * entry (identifying the physical page) and %r23 up with
+ * the from tlb entry (or nothing if only a to entry---for
+ * clear_user_page_asm) */
+ .macro do_alias spc,tmp,tmp1,va,pte,prot,fault,patype
+ cmpib,COND(<>),n 0,\spc,\fault
+ ldil L%(TMPALIAS_MAP_START),\tmp
+ copy \va,\tmp1
+ depi_safe 0,31,TMPALIAS_SIZE_BITS+1,\tmp1
+ cmpb,COND(<>),n \tmp,\tmp1,\fault
+ mfctl %cr19,\tmp /* iir */
+ /* get the opcode (first six bits) into \tmp */
+ extrw,u \tmp,5,6,\tmp
+ /*
+ * Only setting the T bit prevents data cache movein
+ * Setting access rights to zero prevents instruction cache movein
+ *
+ * Note subtlety here: _PAGE_GATEWAY, _PAGE_EXEC and _PAGE_WRITE go
+ * to type field and _PAGE_READ goes to top bit of PL1
+ */
+ ldi (_PAGE_REFTRAP|_PAGE_READ|_PAGE_WRITE),\prot
+ /*
+ * so if the opcode is one (i.e. this is a memory management
+ * instruction) nullify the next load so \prot is only T.
+ * Otherwise this is a normal data operation
+ */
+ cmpiclr,= 0x01,\tmp,%r0
+ ldi (_PAGE_DIRTY|_PAGE_READ|_PAGE_WRITE),\prot
+.ifc \patype,20
+ depd,z \prot,8,7,\prot
+.else
+.ifc \patype,11
+ depw,z \prot,8,7,\prot
+.else
+ .error "undefined PA type to do_alias"
+.endif
+.endif
+ /*
+ * OK, it is in the temp alias region, check whether "from" or "to".
+ * Check "subtle" note in pacache.S re: r23/r26.
+ */
+ extrw,u,= \va,31-TMPALIAS_SIZE_BITS,1,%r0
+ or,COND(tr) %r23,%r0,\pte
+ or %r26,%r0,\pte
+
+ /* convert phys addr in \pte (from r23 or r26) to tlb insert format */
+ SHRREG \pte,PAGE_SHIFT+PAGE_ADD_SHIFT-5, \pte
+ depi_safe _PAGE_SIZE_ENCODING_DEFAULT, 31,5, \pte
+ .endm
+
+
+ /*
+ * Fault_vectors are architecturally required to be aligned on a 2K
+ * boundary
+ */
+
+ .section .text.hot
+ .align 2048
+
+ENTRY(fault_vector_20)
+ /* First vector is invalid (0) */
+ .ascii "cows can fly"
+ .byte 0
+ .align 32
+
+ hpmc 1
+ def 2
+ def 3
+ extint 4
+ def 5
+ itlb_20 PARISC_ITLB_TRAP
+ def 7
+ def 8
+ def 9
+ def 10
+ def 11
+ def 12
+ def 13
+ def 14
+ dtlb_20 15
+ naitlb_20 16
+ nadtlb_20 17
+ def 18
+ def 19
+ dbit_20 20
+ def 21
+ def 22
+ def 23
+ def 24
+ def 25
+ def 26
+ def 27
+ def 28
+ def 29
+ def 30
+ def 31
+END(fault_vector_20)
+
+#ifndef CONFIG_64BIT
+
+ .align 2048
+
+ENTRY(fault_vector_11)
+ /* First vector is invalid (0) */
+ .ascii "cows can fly"
+ .byte 0
+ .align 32
+
+ hpmc 1
+ def 2
+ def 3
+ extint 4
+ def 5
+ itlb_11 PARISC_ITLB_TRAP
+ def 7
+ def 8
+ def 9
+ def 10
+ def 11
+ def 12
+ def 13
+ def 14
+ dtlb_11 15
+ naitlb_11 16
+ nadtlb_11 17
+ def 18
+ def 19
+ dbit_11 20
+ def 21
+ def 22
+ def 23
+ def 24
+ def 25
+ def 26
+ def 27
+ def 28
+ def 29
+ def 30
+ def 31
+END(fault_vector_11)
+
+#endif
+ /* Fault vector is separately protected and *must* be on its own page */
+ .align PAGE_SIZE
+
+ .import handle_interruption,code
+ .import do_cpu_irq_mask,code
+
+ /*
+ * Child Returns here
+ *
+ * copy_thread moved args into task save area.
+ */
+
+ENTRY(ret_from_kernel_thread)
+ /* Call schedule_tail first though */
+ BL schedule_tail, %r2
+ nop
+
+ mfctl %cr30,%r1 /* task_struct */
+ LDREG TASK_PT_GR25(%r1), %r26
+#ifdef CONFIG_64BIT
+ LDREG TASK_PT_GR27(%r1), %r27
+#endif
+ LDREG TASK_PT_GR26(%r1), %r1
+ ble 0(%sr7, %r1)
+ copy %r31, %r2
+ b finish_child_return
+ nop
+END(ret_from_kernel_thread)
+
+
+ /*
+ * struct task_struct *_switch_to(struct task_struct *prev,
+ * struct task_struct *next)
+ *
+ * switch kernel stacks and return prev */
+ENTRY_CFI(_switch_to)
+ STREG %r2, -RP_OFFSET(%r30)
+
+ callee_save_float
+ callee_save
+
+ load32 _switch_to_ret, %r2
+
+ STREG %r2, TASK_PT_KPC(%r26)
+ LDREG TASK_PT_KPC(%r25), %r2
+
+ STREG %r30, TASK_PT_KSP(%r26)
+ LDREG TASK_PT_KSP(%r25), %r30
+ bv %r0(%r2)
+ mtctl %r25,%cr30
+
+ENTRY(_switch_to_ret)
+ mtctl %r0, %cr0 /* Needed for single stepping */
+ callee_rest
+ callee_rest_float
+
+ LDREG -RP_OFFSET(%r30), %r2
+ bv %r0(%r2)
+ copy %r26, %r28
+ENDPROC_CFI(_switch_to)
+
+ /*
+ * Common rfi return path for interruptions, kernel execve, and
+ * sys_rt_sigreturn (sometimes). The sys_rt_sigreturn syscall will
+ * return via this path if the signal was received when the process
+ * was running; if the process was blocked on a syscall then the
+ * normal syscall_exit path is used. All syscalls for traced
+ * proceses exit via intr_restore.
+ *
+ * XXX If any syscalls that change a processes space id ever exit
+ * this way, then we will need to copy %sr3 in to PT_SR[3..7], and
+ * adjust IASQ[0..1].
+ *
+ */
+
+ .align PAGE_SIZE
+
+ENTRY_CFI(syscall_exit_rfi)
+ mfctl %cr30,%r16 /* task_struct */
+ ldo TASK_REGS(%r16),%r16
+ /* Force iaoq to userspace, as the user has had access to our current
+ * context via sigcontext. Also Filter the PSW for the same reason.
+ */
+ LDREG PT_IAOQ0(%r16),%r19
+ depi PRIV_USER,31,2,%r19
+ STREG %r19,PT_IAOQ0(%r16)
+ LDREG PT_IAOQ1(%r16),%r19
+ depi PRIV_USER,31,2,%r19
+ STREG %r19,PT_IAOQ1(%r16)
+ LDREG PT_PSW(%r16),%r19
+ load32 USER_PSW_MASK,%r1
+#ifdef CONFIG_64BIT
+ load32 USER_PSW_HI_MASK,%r20
+ depd %r20,31,32,%r1
+#endif
+ and %r19,%r1,%r19 /* Mask out bits that user shouldn't play with */
+ load32 USER_PSW,%r1
+ or %r19,%r1,%r19 /* Make sure default USER_PSW bits are set */
+ STREG %r19,PT_PSW(%r16)
+
+ /*
+ * If we aren't being traced, we never saved space registers
+ * (we don't store them in the sigcontext), so set them
+ * to "proper" values now (otherwise we'll wind up restoring
+ * whatever was last stored in the task structure, which might
+ * be inconsistent if an interrupt occurred while on the gateway
+ * page). Note that we may be "trashing" values the user put in
+ * them, but we don't support the user changing them.
+ */
+
+ STREG %r0,PT_SR2(%r16)
+ mfsp %sr3,%r19
+ STREG %r19,PT_SR0(%r16)
+ STREG %r19,PT_SR1(%r16)
+ STREG %r19,PT_SR3(%r16)
+ STREG %r19,PT_SR4(%r16)
+ STREG %r19,PT_SR5(%r16)
+ STREG %r19,PT_SR6(%r16)
+ STREG %r19,PT_SR7(%r16)
+
+ENTRY(intr_return)
+ /* check for reschedule */
+ mfctl %cr30,%r1
+ LDREG TASK_TI_FLAGS(%r1),%r19 /* sched.h: TIF_NEED_RESCHED */
+ bb,<,n %r19,31-TIF_NEED_RESCHED,intr_do_resched /* forward */
+
+ .import do_notify_resume,code
+intr_check_sig:
+ /* As above */
+ mfctl %cr30,%r1
+ LDREG TASK_TI_FLAGS(%r1),%r19
+ ldi (_TIF_USER_WORK_MASK & ~_TIF_NEED_RESCHED), %r20
+ and,COND(<>) %r19, %r20, %r0
+ b,n intr_restore /* skip past if we've nothing to do */
+
+ /* This check is critical to having LWS
+ * working. The IASQ is zero on the gateway
+ * page and we cannot deliver any signals until
+ * we get off the gateway page.
+ *
+ * Only do signals if we are returning to user space
+ */
+ LDREG PT_IASQ0(%r16), %r20
+ cmpib,COND(=),n LINUX_GATEWAY_SPACE, %r20, intr_restore /* forward */
+ LDREG PT_IASQ1(%r16), %r20
+ cmpib,COND(=),n LINUX_GATEWAY_SPACE, %r20, intr_restore /* forward */
+
+ copy %r0, %r25 /* long in_syscall = 0 */
+#ifdef CONFIG_64BIT
+ ldo -16(%r30),%r29 /* Reference param save area */
+#endif
+
+ /* NOTE: We need to enable interrupts if we have to deliver
+ * signals. We used to do this earlier but it caused kernel
+ * stack overflows. */
+ ssm PSW_SM_I, %r0
+
+ BL do_notify_resume,%r2
+ copy %r16, %r26 /* struct pt_regs *regs */
+
+ b,n intr_check_sig
+
+intr_restore:
+ copy %r16,%r29
+ ldo PT_FR31(%r29),%r1
+ rest_fp %r1
+ rest_general %r29
+
+ /* inverse of virt_map */
+ pcxt_ssm_bug
+ rsm PSW_SM_QUIET,%r0 /* prepare for rfi */
+ tophys_r1 %r29
+
+ /* Restore space id's and special cr's from PT_REGS
+ * structure pointed to by r29
+ */
+ rest_specials %r29
+
+ /* IMPORTANT: rest_stack restores r29 last (we are using it)!
+ * It also restores r1 and r30.
+ */
+ rest_stack
+
+ rfi
+ nop
+
+#ifndef CONFIG_PREEMPTION
+# define intr_do_preempt intr_restore
+#endif /* !CONFIG_PREEMPTION */
+
+ .import schedule,code
+intr_do_resched:
+ /* Only call schedule on return to userspace. If we're returning
+ * to kernel space, we may schedule if CONFIG_PREEMPTION, otherwise
+ * we jump back to intr_restore.
+ */
+ LDREG PT_IASQ0(%r16), %r20
+ cmpib,COND(=) 0, %r20, intr_do_preempt
+ nop
+ LDREG PT_IASQ1(%r16), %r20
+ cmpib,COND(=) 0, %r20, intr_do_preempt
+ nop
+
+ /* NOTE: We need to enable interrupts if we schedule. We used
+ * to do this earlier but it caused kernel stack overflows. */
+ ssm PSW_SM_I, %r0
+
+#ifdef CONFIG_64BIT
+ ldo -16(%r30),%r29 /* Reference param save area */
+#endif
+
+ ldil L%intr_check_sig, %r2
+#ifndef CONFIG_64BIT
+ b schedule
+#else
+ load32 schedule, %r20
+ bv %r0(%r20)
+#endif
+ ldo R%intr_check_sig(%r2), %r2
+
+ /* preempt the current task on returning to kernel
+ * mode from an interrupt, iff need_resched is set,
+ * and preempt_count is 0. otherwise, we continue on
+ * our merry way back to the current running task.
+ */
+#ifdef CONFIG_PREEMPTION
+ .import preempt_schedule_irq,code
+intr_do_preempt:
+ rsm PSW_SM_I, %r0 /* disable interrupts */
+
+ /* current_thread_info()->preempt_count */
+ mfctl %cr30, %r1
+ ldw TI_PRE_COUNT(%r1), %r19
+ cmpib,<> 0, %r19, intr_restore /* if preempt_count > 0 */
+ nop /* prev insn branched backwards */
+
+ /* check if we interrupted a critical path */
+ LDREG PT_PSW(%r16), %r20
+ bb,<,n %r20, 31 - PSW_SM_I, intr_restore
+ nop
+
+ /* ssm PSW_SM_I done later in intr_restore */
+#ifdef CONFIG_MLONGCALLS
+ ldil L%intr_restore, %r2
+ load32 preempt_schedule_irq, %r1
+ bv %r0(%r1)
+ ldo R%intr_restore(%r2), %r2
+#else
+ ldil L%intr_restore, %r1
+ BL preempt_schedule_irq, %r2
+ ldo R%intr_restore(%r1), %r2
+#endif
+#endif /* CONFIG_PREEMPTION */
+
+ /*
+ * External interrupts.
+ */
+
+intr_extint:
+ cmpib,COND(=),n 0,%r16,1f
+
+ get_stack_use_cr30
+ b,n 2f
+
+1:
+ get_stack_use_r30
+2:
+ save_specials %r29
+ virt_map
+ save_general %r29
+
+ ldo PT_FR0(%r29), %r24
+ save_fp %r24
+
+ loadgp
+
+ copy %r29, %r26 /* arg0 is pt_regs */
+ copy %r29, %r16 /* save pt_regs */
+
+ ldil L%intr_return, %r2
+
+#ifdef CONFIG_64BIT
+ ldo -16(%r30),%r29 /* Reference param save area */
+#endif
+
+ b do_cpu_irq_mask
+ ldo R%intr_return(%r2), %r2 /* return to intr_return, not here */
+ENDPROC_CFI(syscall_exit_rfi)
+
+
+ /* Generic interruptions (illegal insn, unaligned, page fault, etc) */
+
+ENTRY_CFI(intr_save) /* for os_hpmc */
+ mfsp %sr7,%r16
+ cmpib,COND(=),n 0,%r16,1f
+ get_stack_use_cr30
+ b 2f
+ copy %r8,%r26
+
+1:
+ get_stack_use_r30
+ copy %r8,%r26
+
+2:
+ save_specials %r29
+
+ /* If this trap is a itlb miss, skip saving/adjusting isr/ior */
+ cmpib,COND(=),n PARISC_ITLB_TRAP,%r26,skip_save_ior
+
+
+ mfctl %isr, %r16
+ nop /* serialize mfctl on PA 2.0 to avoid 4 cycle penalty */
+ mfctl %ior, %r17
+
+
+#ifdef CONFIG_64BIT
+ /*
+ * If the interrupted code was running with W bit off (32 bit),
+ * clear the b bits (bits 0 & 1) in the ior.
+ * save_specials left ipsw value in r8 for us to test.
+ */
+ extrd,u,*<> %r8,PSW_W_BIT,1,%r0
+ depdi 0,1,2,%r17
+
+ /* adjust isr/ior: get high bits from isr and deposit in ior */
+ space_adjust %r16,%r17,%r1
+#endif
+ STREG %r16, PT_ISR(%r29)
+ STREG %r17, PT_IOR(%r29)
+
+#if 0 && defined(CONFIG_64BIT)
+ /* Revisit when we have 64-bit code above 4Gb */
+ b,n intr_save2
+
+skip_save_ior:
+ /* We have a itlb miss, and when executing code above 4 Gb on ILP64, we
+ * need to adjust iasq/iaoq here in the same way we adjusted isr/ior
+ * above.
+ */
+ extrd,u,* %r8,PSW_W_BIT,1,%r1
+ cmpib,COND(=),n 1,%r1,intr_save2
+ LDREG PT_IASQ0(%r29), %r16
+ LDREG PT_IAOQ0(%r29), %r17
+ /* adjust iasq/iaoq */
+ space_adjust %r16,%r17,%r1
+ STREG %r16, PT_IASQ0(%r29)
+ STREG %r17, PT_IAOQ0(%r29)
+#else
+skip_save_ior:
+#endif
+
+intr_save2:
+ virt_map
+ save_general %r29
+
+ ldo PT_FR0(%r29), %r25
+ save_fp %r25
+
+ loadgp
+
+ copy %r29, %r25 /* arg1 is pt_regs */
+#ifdef CONFIG_64BIT
+ ldo -16(%r30),%r29 /* Reference param save area */
+#endif
+
+ ldil L%intr_check_sig, %r2
+ copy %r25, %r16 /* save pt_regs */
+
+ b handle_interruption
+ ldo R%intr_check_sig(%r2), %r2
+ENDPROC_CFI(intr_save)
+
+
+ /*
+ * Note for all tlb miss handlers:
+ *
+ * cr24 contains a pointer to the kernel address space
+ * page directory.
+ *
+ * cr25 contains a pointer to the current user address
+ * space page directory.
+ *
+ * sr3 will contain the space id of the user address space
+ * of the current running thread while that thread is
+ * running in the kernel.
+ */
+
+ /*
+ * register number allocations. Note that these are all
+ * in the shadowed registers
+ */
+
+ t0 = r1 /* temporary register 0 */
+ va = r8 /* virtual address for which the trap occurred */
+ t1 = r9 /* temporary register 1 */
+ pte = r16 /* pte/phys page # */
+ prot = r17 /* prot bits */
+ spc = r24 /* space for which the trap occurred */
+ ptp = r25 /* page directory/page table pointer */
+
+#ifdef CONFIG_64BIT
+
+dtlb_miss_20w:
+ space_adjust spc,va,t0
+ get_pgd spc,ptp
+ space_check spc,t0,dtlb_fault
+
+ L3_ptep ptp,pte,t0,va,dtlb_check_alias_20w
+
+ ptl_lock spc,ptp,pte,t0,t1,dtlb_check_alias_20w
+ update_accessed ptp,pte,t0,t1
+
+ make_insert_tlb spc,pte,prot,t1
+
+ idtlbt pte,prot
+
+ ptl_unlock spc,t0,t1
+ rfir
+ nop
+
+dtlb_check_alias_20w:
+ do_alias spc,t0,t1,va,pte,prot,dtlb_fault,20
+
+ idtlbt pte,prot
+
+ insert_nops NUM_PIPELINE_INSNS - 1
+ rfir
+ nop
+
+nadtlb_miss_20w:
+ space_adjust spc,va,t0
+ get_pgd spc,ptp
+ space_check spc,t0,nadtlb_fault
+
+ L3_ptep ptp,pte,t0,va,nadtlb_check_alias_20w
+
+ ptl_lock spc,ptp,pte,t0,t1,nadtlb_check_alias_20w
+ update_accessed ptp,pte,t0,t1
+
+ make_insert_tlb spc,pte,prot,t1
+
+ idtlbt pte,prot
+
+ ptl_unlock spc,t0,t1
+ rfir
+ nop
+
+nadtlb_check_alias_20w:
+ do_alias spc,t0,t1,va,pte,prot,nadtlb_emulate,20
+
+ idtlbt pte,prot
+
+ insert_nops NUM_PIPELINE_INSNS - 1
+ rfir
+ nop
+
+#else
+
+dtlb_miss_11:
+ get_pgd spc,ptp
+
+ space_check spc,t0,dtlb_fault
+
+ L2_ptep ptp,pte,t0,va,dtlb_check_alias_11
+
+ ptl_lock spc,ptp,pte,t0,t1,dtlb_check_alias_11
+ update_accessed ptp,pte,t0,t1
+
+ make_insert_tlb_11 spc,pte,prot
+
+ mfsp %sr1,t1 /* Save sr1 so we can use it in tlb inserts */
+ mtsp spc,%sr1
+
+ idtlba pte,(%sr1,va)
+ idtlbp prot,(%sr1,va)
+
+ mtsp t1, %sr1 /* Restore sr1 */
+
+ ptl_unlock spc,t0,t1
+ rfir
+ nop
+
+dtlb_check_alias_11:
+ do_alias spc,t0,t1,va,pte,prot,dtlb_fault,11
+
+ idtlba pte,(va)
+ idtlbp prot,(va)
+
+ insert_nops NUM_PIPELINE_INSNS - 1
+ rfir
+ nop
+
+nadtlb_miss_11:
+ get_pgd spc,ptp
+
+ space_check spc,t0,nadtlb_fault
+
+ L2_ptep ptp,pte,t0,va,nadtlb_check_alias_11
+
+ ptl_lock spc,ptp,pte,t0,t1,nadtlb_check_alias_11
+ update_accessed ptp,pte,t0,t1
+
+ make_insert_tlb_11 spc,pte,prot
+
+ mfsp %sr1,t1 /* Save sr1 so we can use it in tlb inserts */
+ mtsp spc,%sr1
+
+ idtlba pte,(%sr1,va)
+ idtlbp prot,(%sr1,va)
+
+ mtsp t1, %sr1 /* Restore sr1 */
+
+ ptl_unlock spc,t0,t1
+ rfir
+ nop
+
+nadtlb_check_alias_11:
+ do_alias spc,t0,t1,va,pte,prot,nadtlb_emulate,11
+
+ idtlba pte,(va)
+ idtlbp prot,(va)
+
+ insert_nops NUM_PIPELINE_INSNS - 1
+ rfir
+ nop
+
+dtlb_miss_20:
+ space_adjust spc,va,t0
+ get_pgd spc,ptp
+ space_check spc,t0,dtlb_fault
+
+ L2_ptep ptp,pte,t0,va,dtlb_check_alias_20
+
+ ptl_lock spc,ptp,pte,t0,t1,dtlb_check_alias_20
+ update_accessed ptp,pte,t0,t1
+
+ make_insert_tlb spc,pte,prot,t1
+
+ f_extend pte,t1
+
+ idtlbt pte,prot
+
+ ptl_unlock spc,t0,t1
+ rfir
+ nop
+
+dtlb_check_alias_20:
+ do_alias spc,t0,t1,va,pte,prot,dtlb_fault,20
+
+ idtlbt pte,prot
+
+ insert_nops NUM_PIPELINE_INSNS - 1
+ rfir
+ nop
+
+nadtlb_miss_20:
+ get_pgd spc,ptp
+
+ space_check spc,t0,nadtlb_fault
+
+ L2_ptep ptp,pte,t0,va,nadtlb_check_alias_20
+
+ ptl_lock spc,ptp,pte,t0,t1,nadtlb_check_alias_20
+ update_accessed ptp,pte,t0,t1
+
+ make_insert_tlb spc,pte,prot,t1
+
+ f_extend pte,t1
+
+ idtlbt pte,prot
+
+ ptl_unlock spc,t0,t1
+ rfir
+ nop
+
+nadtlb_check_alias_20:
+ do_alias spc,t0,t1,va,pte,prot,nadtlb_emulate,20
+
+ idtlbt pte,prot
+
+ insert_nops NUM_PIPELINE_INSNS - 1
+ rfir
+ nop
+
+#endif
+
+nadtlb_emulate:
+
+ /*
+ * Non-access misses can be caused by fdc,fic,pdc,lpa,probe and
+ * probei instructions. The kernel no longer faults doing flushes.
+ * Use of lpa and probe instructions is rare. Given the issue
+ * with shadow registers, we defer everything to the "slow" path.
+ */
+ b,n nadtlb_fault
+
+#ifdef CONFIG_64BIT
+itlb_miss_20w:
+
+ /*
+ * I miss is a little different, since we allow users to fault
+ * on the gateway page which is in the kernel address space.
+ */
+
+ space_adjust spc,va,t0
+ get_pgd spc,ptp
+ space_check spc,t0,itlb_fault
+
+ L3_ptep ptp,pte,t0,va,itlb_fault
+
+ ptl_lock spc,ptp,pte,t0,t1,itlb_fault
+ update_accessed ptp,pte,t0,t1
+
+ make_insert_tlb spc,pte,prot,t1
+
+ iitlbt pte,prot
+
+ ptl_unlock spc,t0,t1
+ rfir
+ nop
+
+naitlb_miss_20w:
+
+ /*
+ * I miss is a little different, since we allow users to fault
+ * on the gateway page which is in the kernel address space.
+ */
+
+ space_adjust spc,va,t0
+ get_pgd spc,ptp
+ space_check spc,t0,naitlb_fault
+
+ L3_ptep ptp,pte,t0,va,naitlb_check_alias_20w
+
+ ptl_lock spc,ptp,pte,t0,t1,naitlb_check_alias_20w
+ update_accessed ptp,pte,t0,t1
+
+ make_insert_tlb spc,pte,prot,t1
+
+ iitlbt pte,prot
+
+ ptl_unlock spc,t0,t1
+ rfir
+ nop
+
+naitlb_check_alias_20w:
+ do_alias spc,t0,t1,va,pte,prot,naitlb_fault,20
+
+ iitlbt pte,prot
+
+ insert_nops NUM_PIPELINE_INSNS - 1
+ rfir
+ nop
+
+#else
+
+itlb_miss_11:
+ get_pgd spc,ptp
+
+ space_check spc,t0,itlb_fault
+
+ L2_ptep ptp,pte,t0,va,itlb_fault
+
+ ptl_lock spc,ptp,pte,t0,t1,itlb_fault
+ update_accessed ptp,pte,t0,t1
+
+ make_insert_tlb_11 spc,pte,prot
+
+ mfsp %sr1,t1 /* Save sr1 so we can use it in tlb inserts */
+ mtsp spc,%sr1
+
+ iitlba pte,(%sr1,va)
+ iitlbp prot,(%sr1,va)
+
+ mtsp t1, %sr1 /* Restore sr1 */
+
+ ptl_unlock spc,t0,t1
+ rfir
+ nop
+
+naitlb_miss_11:
+ get_pgd spc,ptp
+
+ space_check spc,t0,naitlb_fault
+
+ L2_ptep ptp,pte,t0,va,naitlb_check_alias_11
+
+ ptl_lock spc,ptp,pte,t0,t1,naitlb_check_alias_11
+ update_accessed ptp,pte,t0,t1
+
+ make_insert_tlb_11 spc,pte,prot
+
+ mfsp %sr1,t1 /* Save sr1 so we can use it in tlb inserts */
+ mtsp spc,%sr1
+
+ iitlba pte,(%sr1,va)
+ iitlbp prot,(%sr1,va)
+
+ mtsp t1, %sr1 /* Restore sr1 */
+
+ ptl_unlock spc,t0,t1
+ rfir
+ nop
+
+naitlb_check_alias_11:
+ do_alias spc,t0,t1,va,pte,prot,itlb_fault,11
+
+ iitlba pte,(%sr0, va)
+ iitlbp prot,(%sr0, va)
+
+ insert_nops NUM_PIPELINE_INSNS - 1
+ rfir
+ nop
+
+
+itlb_miss_20:
+ get_pgd spc,ptp
+
+ space_check spc,t0,itlb_fault
+
+ L2_ptep ptp,pte,t0,va,itlb_fault
+
+ ptl_lock spc,ptp,pte,t0,t1,itlb_fault
+ update_accessed ptp,pte,t0,t1
+
+ make_insert_tlb spc,pte,prot,t1
+
+ f_extend pte,t1
+
+ iitlbt pte,prot
+
+ ptl_unlock spc,t0,t1
+ rfir
+ nop
+
+naitlb_miss_20:
+ get_pgd spc,ptp
+
+ space_check spc,t0,naitlb_fault
+
+ L2_ptep ptp,pte,t0,va,naitlb_check_alias_20
+
+ ptl_lock spc,ptp,pte,t0,t1,naitlb_check_alias_20
+ update_accessed ptp,pte,t0,t1
+
+ make_insert_tlb spc,pte,prot,t1
+
+ f_extend pte,t1
+
+ iitlbt pte,prot
+
+ ptl_unlock spc,t0,t1
+ rfir
+ nop
+
+naitlb_check_alias_20:
+ do_alias spc,t0,t1,va,pte,prot,naitlb_fault,20
+
+ iitlbt pte,prot
+
+ insert_nops NUM_PIPELINE_INSNS - 1
+ rfir
+ nop
+
+#endif
+
+#ifdef CONFIG_64BIT
+
+dbit_trap_20w:
+ space_adjust spc,va,t0
+ get_pgd spc,ptp
+ space_check spc,t0,dbit_fault
+
+ L3_ptep ptp,pte,t0,va,dbit_fault
+
+ ptl_lock spc,ptp,pte,t0,t1,dbit_fault
+ update_dirty ptp,pte,t1
+
+ make_insert_tlb spc,pte,prot,t1
+
+ idtlbt pte,prot
+
+ ptl_unlock spc,t0,t1
+ rfir
+ nop
+#else
+
+dbit_trap_11:
+
+ get_pgd spc,ptp
+
+ space_check spc,t0,dbit_fault
+
+ L2_ptep ptp,pte,t0,va,dbit_fault
+
+ ptl_lock spc,ptp,pte,t0,t1,dbit_fault
+ update_dirty ptp,pte,t1
+
+ make_insert_tlb_11 spc,pte,prot
+
+ mfsp %sr1,t1 /* Save sr1 so we can use it in tlb inserts */
+ mtsp spc,%sr1
+
+ idtlba pte,(%sr1,va)
+ idtlbp prot,(%sr1,va)
+
+ mtsp t1, %sr1 /* Restore sr1 */
+
+ ptl_unlock spc,t0,t1
+ rfir
+ nop
+
+dbit_trap_20:
+ get_pgd spc,ptp
+
+ space_check spc,t0,dbit_fault
+
+ L2_ptep ptp,pte,t0,va,dbit_fault
+
+ ptl_lock spc,ptp,pte,t0,t1,dbit_fault
+ update_dirty ptp,pte,t1
+
+ make_insert_tlb spc,pte,prot,t1
+
+ f_extend pte,t1
+
+ idtlbt pte,prot
+
+ ptl_unlock spc,t0,t1
+ rfir
+ nop
+#endif
+
+ .import handle_interruption,code
+
+kernel_bad_space:
+ b intr_save
+ ldi 31,%r8 /* Use an unused code */
+
+dbit_fault:
+ b intr_save
+ ldi 20,%r8
+
+itlb_fault:
+ b intr_save
+ ldi PARISC_ITLB_TRAP,%r8
+
+nadtlb_fault:
+ b intr_save
+ ldi 17,%r8
+
+naitlb_fault:
+ b intr_save
+ ldi 16,%r8
+
+dtlb_fault:
+ b intr_save
+ ldi 15,%r8
+
+ /* Register saving semantics for system calls:
+
+ %r1 clobbered by system call macro in userspace
+ %r2 saved in PT_REGS by gateway page
+ %r3 - %r18 preserved by C code (saved by signal code)
+ %r19 - %r20 saved in PT_REGS by gateway page
+ %r21 - %r22 non-standard syscall args
+ stored in kernel stack by gateway page
+ %r23 - %r26 arg3-arg0, saved in PT_REGS by gateway page
+ %r27 - %r30 saved in PT_REGS by gateway page
+ %r31 syscall return pointer
+ */
+
+ /* Floating point registers (FIXME: what do we do with these?)
+
+ %fr0 - %fr3 status/exception, not preserved
+ %fr4 - %fr7 arguments
+ %fr8 - %fr11 not preserved by C code
+ %fr12 - %fr21 preserved by C code
+ %fr22 - %fr31 not preserved by C code
+ */
+
+ .macro reg_save regs
+ STREG %r3, PT_GR3(\regs)
+ STREG %r4, PT_GR4(\regs)
+ STREG %r5, PT_GR5(\regs)
+ STREG %r6, PT_GR6(\regs)
+ STREG %r7, PT_GR7(\regs)
+ STREG %r8, PT_GR8(\regs)
+ STREG %r9, PT_GR9(\regs)
+ STREG %r10,PT_GR10(\regs)
+ STREG %r11,PT_GR11(\regs)
+ STREG %r12,PT_GR12(\regs)
+ STREG %r13,PT_GR13(\regs)
+ STREG %r14,PT_GR14(\regs)
+ STREG %r15,PT_GR15(\regs)
+ STREG %r16,PT_GR16(\regs)
+ STREG %r17,PT_GR17(\regs)
+ STREG %r18,PT_GR18(\regs)
+ .endm
+
+ .macro reg_restore regs
+ LDREG PT_GR3(\regs), %r3
+ LDREG PT_GR4(\regs), %r4
+ LDREG PT_GR5(\regs), %r5
+ LDREG PT_GR6(\regs), %r6
+ LDREG PT_GR7(\regs), %r7
+ LDREG PT_GR8(\regs), %r8
+ LDREG PT_GR9(\regs), %r9
+ LDREG PT_GR10(\regs),%r10
+ LDREG PT_GR11(\regs),%r11
+ LDREG PT_GR12(\regs),%r12
+ LDREG PT_GR13(\regs),%r13
+ LDREG PT_GR14(\regs),%r14
+ LDREG PT_GR15(\regs),%r15
+ LDREG PT_GR16(\regs),%r16
+ LDREG PT_GR17(\regs),%r17
+ LDREG PT_GR18(\regs),%r18
+ .endm
+
+ .macro fork_like name
+ENTRY_CFI(sys_\name\()_wrapper)
+ mfctl %cr30,%r1
+ ldo TASK_REGS(%r1),%r1
+ reg_save %r1
+ mfctl %cr27, %r28
+ ldil L%sys_\name, %r31
+ be R%sys_\name(%sr4,%r31)
+ STREG %r28, PT_CR27(%r1)
+ENDPROC_CFI(sys_\name\()_wrapper)
+ .endm
+
+fork_like clone
+fork_like clone3
+fork_like fork
+fork_like vfork
+
+ /* Set the return value for the child */
+ENTRY(child_return)
+ BL schedule_tail, %r2
+ nop
+finish_child_return:
+ mfctl %cr30,%r1
+ ldo TASK_REGS(%r1),%r1 /* get pt regs */
+
+ LDREG PT_CR27(%r1), %r3
+ mtctl %r3, %cr27
+ reg_restore %r1
+ b syscall_exit
+ copy %r0,%r28
+END(child_return)
+
+ENTRY_CFI(sys_rt_sigreturn_wrapper)
+ mfctl %cr30,%r26
+ ldo TASK_REGS(%r26),%r26 /* get pt regs */
+ /* Don't save regs, we are going to restore them from sigcontext. */
+ STREG %r2, -RP_OFFSET(%r30)
+#ifdef CONFIG_64BIT
+ ldo FRAME_SIZE(%r30), %r30
+ BL sys_rt_sigreturn,%r2
+ ldo -16(%r30),%r29 /* Reference param save area */
+#else
+ BL sys_rt_sigreturn,%r2
+ ldo FRAME_SIZE(%r30), %r30
+#endif
+
+ ldo -FRAME_SIZE(%r30), %r30
+ LDREG -RP_OFFSET(%r30), %r2
+
+ /* FIXME: I think we need to restore a few more things here. */
+ mfctl %cr30,%r1
+ ldo TASK_REGS(%r1),%r1 /* get pt regs */
+ reg_restore %r1
+
+ /* If the signal was received while the process was blocked on a
+ * syscall, then r2 will take us to syscall_exit; otherwise r2 will
+ * take us to syscall_exit_rfi and on to intr_return.
+ */
+ bv %r0(%r2)
+ LDREG PT_GR28(%r1),%r28 /* reload original r28 for syscall_exit */
+ENDPROC_CFI(sys_rt_sigreturn_wrapper)
+
+ENTRY(syscall_exit)
+ /* NOTE: Not all syscalls exit this way. rt_sigreturn will exit
+ * via syscall_exit_rfi if the signal was received while the process
+ * was running.
+ */
+
+ /* save return value now */
+ mfctl %cr30, %r1
+ STREG %r28,TASK_PT_GR28(%r1)
+
+ /* Seems to me that dp could be wrong here, if the syscall involved
+ * calling a module, and nothing got round to restoring dp on return.
+ */
+ loadgp
+
+syscall_check_resched:
+
+ /* check for reschedule */
+ mfctl %cr30,%r19
+ LDREG TASK_TI_FLAGS(%r19),%r19 /* long */
+ bb,<,n %r19, 31-TIF_NEED_RESCHED, syscall_do_resched /* forward */
+
+ .import do_signal,code
+syscall_check_sig:
+ mfctl %cr30,%r19
+ LDREG TASK_TI_FLAGS(%r19),%r19
+ ldi (_TIF_USER_WORK_MASK & ~_TIF_NEED_RESCHED), %r26
+ and,COND(<>) %r19, %r26, %r0
+ b,n syscall_restore /* skip past if we've nothing to do */
+
+syscall_do_signal:
+ /* Save callee-save registers (for sigcontext).
+ * FIXME: After this point the process structure should be
+ * consistent with all the relevant state of the process
+ * before the syscall. We need to verify this.
+ */
+ mfctl %cr30,%r1
+ ldo TASK_REGS(%r1), %r26 /* struct pt_regs *regs */
+ reg_save %r26
+
+#ifdef CONFIG_64BIT
+ ldo -16(%r30),%r29 /* Reference param save area */
+#endif
+
+ BL do_notify_resume,%r2
+ ldi 1, %r25 /* long in_syscall = 1 */
+
+ mfctl %cr30,%r1
+ ldo TASK_REGS(%r1), %r20 /* reload pt_regs */
+ reg_restore %r20
+
+ b,n syscall_check_sig
+
+syscall_restore:
+ mfctl %cr30,%r1
+
+ /* Are we being ptraced? */
+ LDREG TASK_TI_FLAGS(%r1),%r19
+ ldi _TIF_SINGLESTEP|_TIF_BLOCKSTEP,%r2
+ and,COND(=) %r19,%r2,%r0
+ b,n syscall_restore_rfi
+
+ ldo TASK_PT_FR31(%r1),%r19 /* reload fpregs */
+ rest_fp %r19
+
+ LDREG TASK_PT_SAR(%r1),%r19 /* restore SAR */
+ mtsar %r19
+
+ LDREG TASK_PT_GR2(%r1),%r2 /* restore user rp */
+ LDREG TASK_PT_GR19(%r1),%r19
+ LDREG TASK_PT_GR20(%r1),%r20
+ LDREG TASK_PT_GR21(%r1),%r21
+ LDREG TASK_PT_GR22(%r1),%r22
+ LDREG TASK_PT_GR23(%r1),%r23
+ LDREG TASK_PT_GR24(%r1),%r24
+ LDREG TASK_PT_GR25(%r1),%r25
+ LDREG TASK_PT_GR26(%r1),%r26
+ LDREG TASK_PT_GR27(%r1),%r27 /* restore user dp */
+ LDREG TASK_PT_GR28(%r1),%r28 /* syscall return value */
+ LDREG TASK_PT_GR29(%r1),%r29
+ LDREG TASK_PT_GR31(%r1),%r31 /* restore syscall rp */
+
+ /* NOTE: We use rsm/ssm pair to make this operation atomic */
+ LDREG TASK_PT_GR30(%r1),%r1 /* Get user sp */
+ rsm PSW_SM_I, %r0
+ copy %r1,%r30 /* Restore user sp */
+ mfsp %sr3,%r1 /* Get user space id */
+ mtsp %r1,%sr7 /* Restore sr7 */
+ ssm PSW_SM_I, %r0
+
+ /* Set sr2 to zero for userspace syscalls to work. */
+ mtsp %r0,%sr2
+ mtsp %r1,%sr4 /* Restore sr4 */
+ mtsp %r1,%sr5 /* Restore sr5 */
+ mtsp %r1,%sr6 /* Restore sr6 */
+
+ depi PRIV_USER,31,2,%r31 /* ensure return to user mode. */
+
+#ifdef CONFIG_64BIT
+ /* decide whether to reset the wide mode bit
+ *
+ * For a syscall, the W bit is stored in the lowest bit
+ * of sp. Extract it and reset W if it is zero */
+ extrd,u,*<> %r30,63,1,%r1
+ rsm PSW_SM_W, %r0
+ /* now reset the lowest bit of sp if it was set */
+ xor %r30,%r1,%r30
+#endif
+ be,n 0(%sr3,%r31) /* return to user space */
+
+ /* We have to return via an RFI, so that PSW T and R bits can be set
+ * appropriately.
+ * This sets up pt_regs so we can return via intr_restore, which is not
+ * the most efficient way of doing things, but it works.
+ */
+syscall_restore_rfi:
+ ldo -1(%r0),%r2 /* Set recovery cntr to -1 */
+ mtctl %r2,%cr0 /* for immediate trap */
+ LDREG TASK_PT_PSW(%r1),%r2 /* Get old PSW */
+ ldi 0x0b,%r20 /* Create new PSW */
+ depi -1,13,1,%r20 /* C, Q, D, and I bits */
+
+ /* The values of SINGLESTEP_BIT and BLOCKSTEP_BIT are
+ * set in thread_info.h and converted to PA bitmap
+ * numbers in asm-offsets.c */
+
+ /* if ((%r19.SINGLESTEP_BIT)) { %r20.27=1} */
+ extru,= %r19,TIF_SINGLESTEP_PA_BIT,1,%r0
+ depi -1,27,1,%r20 /* R bit */
+
+ /* if ((%r19.BLOCKSTEP_BIT)) { %r20.7=1} */
+ extru,= %r19,TIF_BLOCKSTEP_PA_BIT,1,%r0
+ depi -1,7,1,%r20 /* T bit */
+
+ STREG %r20,TASK_PT_PSW(%r1)
+
+ /* Always store space registers, since sr3 can be changed (e.g. fork) */
+
+ mfsp %sr3,%r25
+ STREG %r25,TASK_PT_SR3(%r1)
+ STREG %r25,TASK_PT_SR4(%r1)
+ STREG %r25,TASK_PT_SR5(%r1)
+ STREG %r25,TASK_PT_SR6(%r1)
+ STREG %r25,TASK_PT_SR7(%r1)
+ STREG %r25,TASK_PT_IASQ0(%r1)
+ STREG %r25,TASK_PT_IASQ1(%r1)
+
+ /* XXX W bit??? */
+ /* Now if old D bit is clear, it means we didn't save all registers
+ * on syscall entry, so do that now. This only happens on TRACEME
+ * calls, or if someone attached to us while we were on a syscall.
+ * We could make this more efficient by not saving r3-r18, but
+ * then we wouldn't be able to use the common intr_restore path.
+ * It is only for traced processes anyway, so performance is not
+ * an issue.
+ */
+ bb,< %r2,30,pt_regs_ok /* Branch if D set */
+ ldo TASK_REGS(%r1),%r25
+ reg_save %r25 /* Save r3 to r18 */
+
+ /* Save the current sr */
+ mfsp %sr0,%r2
+ STREG %r2,TASK_PT_SR0(%r1)
+
+ /* Save the scratch sr */
+ mfsp %sr1,%r2
+ STREG %r2,TASK_PT_SR1(%r1)
+
+ /* sr2 should be set to zero for userspace syscalls */
+ STREG %r0,TASK_PT_SR2(%r1)
+
+ LDREG TASK_PT_GR31(%r1),%r2
+ depi PRIV_USER,31,2,%r2 /* ensure return to user mode. */
+ STREG %r2,TASK_PT_IAOQ0(%r1)
+ ldo 4(%r2),%r2
+ STREG %r2,TASK_PT_IAOQ1(%r1)
+ b intr_restore
+ copy %r25,%r16
+
+pt_regs_ok:
+ LDREG TASK_PT_IAOQ0(%r1),%r2
+ depi PRIV_USER,31,2,%r2 /* ensure return to user mode. */
+ STREG %r2,TASK_PT_IAOQ0(%r1)
+ LDREG TASK_PT_IAOQ1(%r1),%r2
+ depi PRIV_USER,31,2,%r2
+ STREG %r2,TASK_PT_IAOQ1(%r1)
+ b intr_restore
+ copy %r25,%r16
+
+syscall_do_resched:
+ load32 syscall_check_resched,%r2 /* if resched, we start over again */
+ load32 schedule,%r19
+ bv %r0(%r19) /* jumps to schedule() */
+#ifdef CONFIG_64BIT
+ ldo -16(%r30),%r29 /* Reference param save area */
+#else
+ nop
+#endif
+END(syscall_exit)
+
+
+#ifdef CONFIG_FUNCTION_TRACER
+
+ .import ftrace_function_trampoline,code
+ .align L1_CACHE_BYTES
+ENTRY_CFI(mcount, caller)
+_mcount:
+ .export _mcount,data
+ /*
+ * The 64bit mcount() function pointer needs 4 dwords, of which the
+ * first two are free. We optimize it here and put 2 instructions for
+ * calling mcount(), and 2 instructions for ftrace_stub(). That way we
+ * have all on one L1 cacheline.
+ */
+ ldi 0, %arg3
+ b ftrace_function_trampoline
+ copy %r3, %arg2 /* caller original %sp */
+ftrace_stub:
+ .globl ftrace_stub
+ .type ftrace_stub, @function
+#ifdef CONFIG_64BIT
+ bve (%rp)
+#else
+ bv %r0(%rp)
+#endif
+ nop
+#ifdef CONFIG_64BIT
+ .dword mcount
+ .dword 0 /* code in head.S puts value of global gp here */
+#endif
+ENDPROC_CFI(mcount)
+
+#ifdef CONFIG_DYNAMIC_FTRACE
+
+#ifdef CONFIG_64BIT
+#define FTRACE_FRAME_SIZE (2*FRAME_SIZE)
+#else
+#define FTRACE_FRAME_SIZE FRAME_SIZE
+#endif
+ENTRY_CFI(ftrace_caller, caller,frame=FTRACE_FRAME_SIZE,CALLS,SAVE_RP,SAVE_SP)
+ftrace_caller:
+ .global ftrace_caller
+
+ STREG %r3, -FTRACE_FRAME_SIZE+1*REG_SZ(%sp)
+ ldo -FTRACE_FRAME_SIZE(%sp), %r3
+ STREG %rp, -RP_OFFSET(%r3)
+
+ /* Offset 0 is already allocated for %r1 */
+ STREG %r23, 2*REG_SZ(%r3)
+ STREG %r24, 3*REG_SZ(%r3)
+ STREG %r25, 4*REG_SZ(%r3)
+ STREG %r26, 5*REG_SZ(%r3)
+ STREG %r28, 6*REG_SZ(%r3)
+ STREG %r29, 7*REG_SZ(%r3)
+#ifdef CONFIG_64BIT
+ STREG %r19, 8*REG_SZ(%r3)
+ STREG %r20, 9*REG_SZ(%r3)
+ STREG %r21, 10*REG_SZ(%r3)
+ STREG %r22, 11*REG_SZ(%r3)
+ STREG %r27, 12*REG_SZ(%r3)
+ STREG %r31, 13*REG_SZ(%r3)
+ loadgp
+ ldo -16(%sp),%r29
+#endif
+ LDREG 0(%r3), %r25
+ copy %rp, %r26
+ ldo -8(%r25), %r25
+ ldi 0, %r23 /* no pt_regs */
+ b,l ftrace_function_trampoline, %rp
+ copy %r3, %r24
+
+ LDREG -RP_OFFSET(%r3), %rp
+ LDREG 2*REG_SZ(%r3), %r23
+ LDREG 3*REG_SZ(%r3), %r24
+ LDREG 4*REG_SZ(%r3), %r25
+ LDREG 5*REG_SZ(%r3), %r26
+ LDREG 6*REG_SZ(%r3), %r28
+ LDREG 7*REG_SZ(%r3), %r29
+#ifdef CONFIG_64BIT
+ LDREG 8*REG_SZ(%r3), %r19
+ LDREG 9*REG_SZ(%r3), %r20
+ LDREG 10*REG_SZ(%r3), %r21
+ LDREG 11*REG_SZ(%r3), %r22
+ LDREG 12*REG_SZ(%r3), %r27
+ LDREG 13*REG_SZ(%r3), %r31
+#endif
+ LDREG 1*REG_SZ(%r3), %r3
+
+ LDREGM -FTRACE_FRAME_SIZE(%sp), %r1
+ /* Adjust return point to jump back to beginning of traced function */
+ ldo -4(%r1), %r1
+ bv,n (%r1)
+
+ENDPROC_CFI(ftrace_caller)
+
+#ifdef CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS
+ENTRY_CFI(ftrace_regs_caller,caller,frame=FTRACE_FRAME_SIZE+PT_SZ_ALGN,
+ CALLS,SAVE_RP,SAVE_SP)
+ftrace_regs_caller:
+ .global ftrace_regs_caller
+
+ ldo -FTRACE_FRAME_SIZE(%sp), %r1
+ STREG %rp, -RP_OFFSET(%r1)
+
+ copy %sp, %r1
+ ldo PT_SZ_ALGN(%sp), %sp
+
+ STREG %rp, PT_GR2(%r1)
+ STREG %r3, PT_GR3(%r1)
+ STREG %r4, PT_GR4(%r1)
+ STREG %r5, PT_GR5(%r1)
+ STREG %r6, PT_GR6(%r1)
+ STREG %r7, PT_GR7(%r1)
+ STREG %r8, PT_GR8(%r1)
+ STREG %r9, PT_GR9(%r1)
+ STREG %r10, PT_GR10(%r1)
+ STREG %r11, PT_GR11(%r1)
+ STREG %r12, PT_GR12(%r1)
+ STREG %r13, PT_GR13(%r1)
+ STREG %r14, PT_GR14(%r1)
+ STREG %r15, PT_GR15(%r1)
+ STREG %r16, PT_GR16(%r1)
+ STREG %r17, PT_GR17(%r1)
+ STREG %r18, PT_GR18(%r1)
+ STREG %r19, PT_GR19(%r1)
+ STREG %r20, PT_GR20(%r1)
+ STREG %r21, PT_GR21(%r1)
+ STREG %r22, PT_GR22(%r1)
+ STREG %r23, PT_GR23(%r1)
+ STREG %r24, PT_GR24(%r1)
+ STREG %r25, PT_GR25(%r1)
+ STREG %r26, PT_GR26(%r1)
+ STREG %r27, PT_GR27(%r1)
+ STREG %r28, PT_GR28(%r1)
+ STREG %r29, PT_GR29(%r1)
+ STREG %r30, PT_GR30(%r1)
+ STREG %r31, PT_GR31(%r1)
+ mfctl %cr11, %r26
+ STREG %r26, PT_SAR(%r1)
+
+ copy %rp, %r26
+ LDREG -FTRACE_FRAME_SIZE-PT_SZ_ALGN(%sp), %r25
+ ldo -8(%r25), %r25
+ ldo -FTRACE_FRAME_SIZE(%r1), %arg2
+ b,l ftrace_function_trampoline, %rp
+ copy %r1, %arg3 /* struct pt_regs */
+
+ ldo -PT_SZ_ALGN(%sp), %r1
+
+ LDREG PT_SAR(%r1), %rp
+ mtctl %rp, %cr11
+
+ LDREG PT_GR2(%r1), %rp
+ LDREG PT_GR3(%r1), %r3
+ LDREG PT_GR4(%r1), %r4
+ LDREG PT_GR5(%r1), %r5
+ LDREG PT_GR6(%r1), %r6
+ LDREG PT_GR7(%r1), %r7
+ LDREG PT_GR8(%r1), %r8
+ LDREG PT_GR9(%r1), %r9
+ LDREG PT_GR10(%r1),%r10
+ LDREG PT_GR11(%r1),%r11
+ LDREG PT_GR12(%r1),%r12
+ LDREG PT_GR13(%r1),%r13
+ LDREG PT_GR14(%r1),%r14
+ LDREG PT_GR15(%r1),%r15
+ LDREG PT_GR16(%r1),%r16
+ LDREG PT_GR17(%r1),%r17
+ LDREG PT_GR18(%r1),%r18
+ LDREG PT_GR19(%r1),%r19
+ LDREG PT_GR20(%r1),%r20
+ LDREG PT_GR21(%r1),%r21
+ LDREG PT_GR22(%r1),%r22
+ LDREG PT_GR23(%r1),%r23
+ LDREG PT_GR24(%r1),%r24
+ LDREG PT_GR25(%r1),%r25
+ LDREG PT_GR26(%r1),%r26
+ LDREG PT_GR27(%r1),%r27
+ LDREG PT_GR28(%r1),%r28
+ LDREG PT_GR29(%r1),%r29
+ LDREG PT_GR30(%r1),%r30
+ LDREG PT_GR31(%r1),%r31
+
+ ldo -PT_SZ_ALGN(%sp), %sp
+ LDREGM -FTRACE_FRAME_SIZE(%sp), %r1
+ /* Adjust return point to jump back to beginning of traced function */
+ ldo -4(%r1), %r1
+ bv,n (%r1)
+
+ENDPROC_CFI(ftrace_regs_caller)
+
+#endif
+#endif
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ .align 8
+ENTRY_CFI(return_to_handler, caller,frame=FRAME_SIZE)
+ .export parisc_return_to_handler,data
+parisc_return_to_handler:
+ copy %r3,%r1
+ STREG %r0,-RP_OFFSET(%sp) /* store 0 as %rp */
+ copy %sp,%r3
+ STREGM %r1,FRAME_SIZE(%sp)
+ STREG %ret0,8(%r3)
+ STREG %ret1,16(%r3)
+
+#ifdef CONFIG_64BIT
+ loadgp
+#endif
+
+ /* call ftrace_return_to_handler(0) */
+ .import ftrace_return_to_handler,code
+ load32 ftrace_return_to_handler,%ret0
+ load32 .Lftrace_ret,%r2
+#ifdef CONFIG_64BIT
+ ldo -16(%sp),%ret1 /* Reference param save area */
+ bve (%ret0)
+#else
+ bv %r0(%ret0)
+#endif
+ ldi 0,%r26
+.Lftrace_ret:
+ copy %ret0,%rp
+
+ /* restore original return values */
+ LDREG 8(%r3),%ret0
+ LDREG 16(%r3),%ret1
+
+ /* return from function */
+#ifdef CONFIG_64BIT
+ bve (%rp)
+#else
+ bv %r0(%rp)
+#endif
+ LDREGM -FRAME_SIZE(%sp),%r3
+ENDPROC_CFI(return_to_handler)
+
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+
+#endif /* CONFIG_FUNCTION_TRACER */
+
+#ifdef CONFIG_IRQSTACKS
+/* void call_on_stack(unsigned long param1, void *func,
+ unsigned long new_stack) */
+ENTRY_CFI(call_on_stack, FRAME=2*FRAME_SIZE,CALLS,SAVE_RP,SAVE_SP)
+ENTRY(_call_on_stack)
+ copy %sp, %r1
+
+ /* Regarding the HPPA calling conventions for function pointers,
+ we assume the PIC register is not changed across call. For
+ CONFIG_64BIT, the argument pointer is left to point at the
+ argument region allocated for the call to call_on_stack. */
+
+ /* Switch to new stack. We allocate two frames. */
+ ldo 2*FRAME_SIZE(%arg2), %sp
+# ifdef CONFIG_64BIT
+ /* Save previous stack pointer and return pointer in frame marker */
+ STREG %rp, -FRAME_SIZE-RP_OFFSET(%sp)
+ /* Calls always use function descriptor */
+ LDREG 16(%arg1), %arg1
+ bve,l (%arg1), %rp
+ STREG %r1, -FRAME_SIZE-REG_SZ(%sp)
+ LDREG -FRAME_SIZE-RP_OFFSET(%sp), %rp
+ bve (%rp)
+ LDREG -FRAME_SIZE-REG_SZ(%sp), %sp
+# else
+ /* Save previous stack pointer and return pointer in frame marker */
+ STREG %r1, -FRAME_SIZE-REG_SZ(%sp)
+ STREG %rp, -FRAME_SIZE-RP_OFFSET(%sp)
+ /* Calls use function descriptor if PLABEL bit is set */
+ bb,>=,n %arg1, 30, 1f
+ depwi 0,31,2, %arg1
+ LDREG 0(%arg1), %arg1
+1:
+ be,l 0(%sr4,%arg1), %sr0, %r31
+ copy %r31, %rp
+ LDREG -FRAME_SIZE-RP_OFFSET(%sp), %rp
+ bv (%rp)
+ LDREG -FRAME_SIZE-REG_SZ(%sp), %sp
+# endif /* CONFIG_64BIT */
+ENDPROC_CFI(call_on_stack)
+#endif /* CONFIG_IRQSTACKS */
+
+ENTRY_CFI(get_register)
+ /*
+ * get_register is used by the non access tlb miss handlers to
+ * copy the value of the general register specified in r8 into
+ * r1. This routine can't be used for shadowed registers, since
+ * the rfir will restore the original value. So, for the shadowed
+ * registers we put a -1 into r1 to indicate that the register
+ * should not be used (the register being copied could also have
+ * a -1 in it, but that is OK, it just means that we will have
+ * to use the slow path instead).
+ */
+ blr %r8,%r0
+ nop
+ bv %r0(%r25) /* r0 */
+ copy %r0,%r1
+ bv %r0(%r25) /* r1 - shadowed */
+ ldi -1,%r1
+ bv %r0(%r25) /* r2 */
+ copy %r2,%r1
+ bv %r0(%r25) /* r3 */
+ copy %r3,%r1
+ bv %r0(%r25) /* r4 */
+ copy %r4,%r1
+ bv %r0(%r25) /* r5 */
+ copy %r5,%r1
+ bv %r0(%r25) /* r6 */
+ copy %r6,%r1
+ bv %r0(%r25) /* r7 */
+ copy %r7,%r1
+ bv %r0(%r25) /* r8 - shadowed */
+ ldi -1,%r1
+ bv %r0(%r25) /* r9 - shadowed */
+ ldi -1,%r1
+ bv %r0(%r25) /* r10 */
+ copy %r10,%r1
+ bv %r0(%r25) /* r11 */
+ copy %r11,%r1
+ bv %r0(%r25) /* r12 */
+ copy %r12,%r1
+ bv %r0(%r25) /* r13 */
+ copy %r13,%r1
+ bv %r0(%r25) /* r14 */
+ copy %r14,%r1
+ bv %r0(%r25) /* r15 */
+ copy %r15,%r1
+ bv %r0(%r25) /* r16 - shadowed */
+ ldi -1,%r1
+ bv %r0(%r25) /* r17 - shadowed */
+ ldi -1,%r1
+ bv %r0(%r25) /* r18 */
+ copy %r18,%r1
+ bv %r0(%r25) /* r19 */
+ copy %r19,%r1
+ bv %r0(%r25) /* r20 */
+ copy %r20,%r1
+ bv %r0(%r25) /* r21 */
+ copy %r21,%r1
+ bv %r0(%r25) /* r22 */
+ copy %r22,%r1
+ bv %r0(%r25) /* r23 */
+ copy %r23,%r1
+ bv %r0(%r25) /* r24 - shadowed */
+ ldi -1,%r1
+ bv %r0(%r25) /* r25 - shadowed */
+ ldi -1,%r1
+ bv %r0(%r25) /* r26 */
+ copy %r26,%r1
+ bv %r0(%r25) /* r27 */
+ copy %r27,%r1
+ bv %r0(%r25) /* r28 */
+ copy %r28,%r1
+ bv %r0(%r25) /* r29 */
+ copy %r29,%r1
+ bv %r0(%r25) /* r30 */
+ copy %r30,%r1
+ bv %r0(%r25) /* r31 */
+ copy %r31,%r1
+ENDPROC_CFI(get_register)
+
+
+ENTRY_CFI(set_register)
+ /*
+ * set_register is used by the non access tlb miss handlers to
+ * copy the value of r1 into the general register specified in
+ * r8.
+ */
+ blr %r8,%r0
+ nop
+ bv %r0(%r25) /* r0 (silly, but it is a place holder) */
+ copy %r1,%r0
+ bv %r0(%r25) /* r1 */
+ copy %r1,%r1
+ bv %r0(%r25) /* r2 */
+ copy %r1,%r2
+ bv %r0(%r25) /* r3 */
+ copy %r1,%r3
+ bv %r0(%r25) /* r4 */
+ copy %r1,%r4
+ bv %r0(%r25) /* r5 */
+ copy %r1,%r5
+ bv %r0(%r25) /* r6 */
+ copy %r1,%r6
+ bv %r0(%r25) /* r7 */
+ copy %r1,%r7
+ bv %r0(%r25) /* r8 */
+ copy %r1,%r8
+ bv %r0(%r25) /* r9 */
+ copy %r1,%r9
+ bv %r0(%r25) /* r10 */
+ copy %r1,%r10
+ bv %r0(%r25) /* r11 */
+ copy %r1,%r11
+ bv %r0(%r25) /* r12 */
+ copy %r1,%r12
+ bv %r0(%r25) /* r13 */
+ copy %r1,%r13
+ bv %r0(%r25) /* r14 */
+ copy %r1,%r14
+ bv %r0(%r25) /* r15 */
+ copy %r1,%r15
+ bv %r0(%r25) /* r16 */
+ copy %r1,%r16
+ bv %r0(%r25) /* r17 */
+ copy %r1,%r17
+ bv %r0(%r25) /* r18 */
+ copy %r1,%r18
+ bv %r0(%r25) /* r19 */
+ copy %r1,%r19
+ bv %r0(%r25) /* r20 */
+ copy %r1,%r20
+ bv %r0(%r25) /* r21 */
+ copy %r1,%r21
+ bv %r0(%r25) /* r22 */
+ copy %r1,%r22
+ bv %r0(%r25) /* r23 */
+ copy %r1,%r23
+ bv %r0(%r25) /* r24 */
+ copy %r1,%r24
+ bv %r0(%r25) /* r25 */
+ copy %r1,%r25
+ bv %r0(%r25) /* r26 */
+ copy %r1,%r26
+ bv %r0(%r25) /* r27 */
+ copy %r1,%r27
+ bv %r0(%r25) /* r28 */
+ copy %r1,%r28
+ bv %r0(%r25) /* r29 */
+ copy %r1,%r29
+ bv %r0(%r25) /* r30 */
+ copy %r1,%r30
+ bv %r0(%r25) /* r31 */
+ copy %r1,%r31
+ENDPROC_CFI(set_register)
+
diff --git a/arch/parisc/kernel/firmware.c b/arch/parisc/kernel/firmware.c
new file mode 100644
index 000000000..56e694f6a
--- /dev/null
+++ b/arch/parisc/kernel/firmware.c
@@ -0,0 +1,1931 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * arch/parisc/kernel/firmware.c - safe PDC access routines
+ *
+ * PDC == Processor Dependent Code
+ *
+ * See PDC documentation at
+ * https://parisc.wiki.kernel.org/index.php/Technical_Documentation
+ * for documentation describing the entry points and calling
+ * conventions defined below.
+ *
+ * Copyright 1999 SuSE GmbH Nuernberg (Philipp Rumpf, prumpf@tux.org)
+ * Copyright 1999 The Puffin Group, (Alex deVries, David Kennedy)
+ * Copyright 2003 Grant Grundler <grundler parisc-linux org>
+ * Copyright 2003,2004 Ryan Bradetich <rbrad@parisc-linux.org>
+ * Copyright 2004,2006 Thibaut VARENE <varenet@parisc-linux.org>
+ */
+
+/* I think it would be in everyone's best interest to follow this
+ * guidelines when writing PDC wrappers:
+ *
+ * - the name of the pdc wrapper should match one of the macros
+ * used for the first two arguments
+ * - don't use caps for random parts of the name
+ * - use the static PDC result buffers and "copyout" to structs
+ * supplied by the caller to encapsulate alignment restrictions
+ * - hold pdc_lock while in PDC or using static result buffers
+ * - use __pa() to convert virtual (kernel) pointers to physical
+ * ones.
+ * - the name of the struct used for pdc return values should equal
+ * one of the macros used for the first two arguments to the
+ * corresponding PDC call
+ * - keep the order of arguments
+ * - don't be smart (setting trailing NUL bytes for strings, return
+ * something useful even if the call failed) unless you are sure
+ * it's not going to affect functionality or performance
+ *
+ * Example:
+ * int pdc_cache_info(struct pdc_cache_info *cache_info )
+ * {
+ * int retval;
+ *
+ * spin_lock_irq(&pdc_lock);
+ * retval = mem_pdc_call(PDC_CACHE,PDC_CACHE_INFO,__pa(cache_info),0);
+ * convert_to_wide(pdc_result);
+ * memcpy(cache_info, pdc_result, sizeof(*cache_info));
+ * spin_unlock_irq(&pdc_lock);
+ *
+ * return retval;
+ * }
+ * prumpf 991016
+ */
+
+#include <linux/stdarg.h>
+
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/spinlock.h>
+
+#include <asm/page.h>
+#include <asm/pdc.h>
+#include <asm/pdcpat.h>
+#include <asm/processor.h> /* for boot_cpu_data */
+
+#if defined(BOOTLOADER)
+# undef spin_lock_irqsave
+# define spin_lock_irqsave(a, b) { b = 1; }
+# undef spin_unlock_irqrestore
+# define spin_unlock_irqrestore(a, b)
+#else
+static DEFINE_SPINLOCK(pdc_lock);
+#endif
+
+static unsigned long pdc_result[NUM_PDC_RESULT] __aligned(8);
+static unsigned long pdc_result2[NUM_PDC_RESULT] __aligned(8);
+
+#ifdef CONFIG_64BIT
+#define WIDE_FIRMWARE 0x1
+#define NARROW_FIRMWARE 0x2
+
+/* Firmware needs to be initially set to narrow to determine the
+ * actual firmware width. */
+int parisc_narrow_firmware __ro_after_init = 2;
+#endif
+
+/* On most currently-supported platforms, IODC I/O calls are 32-bit calls
+ * and MEM_PDC calls are always the same width as the OS.
+ * Some PAT boxes may have 64-bit IODC I/O.
+ *
+ * Ryan Bradetich added the now obsolete CONFIG_PDC_NARROW to allow
+ * 64-bit kernels to run on systems with 32-bit MEM_PDC calls.
+ * This allowed wide kernels to run on Cxxx boxes.
+ * We now detect 32-bit-only PDC and dynamically switch to 32-bit mode
+ * when running a 64-bit kernel on such boxes (e.g. C200 or C360).
+ */
+
+#ifdef CONFIG_64BIT
+long real64_call(unsigned long function, ...);
+#endif
+long real32_call(unsigned long function, ...);
+
+#ifdef CONFIG_64BIT
+# define MEM_PDC (unsigned long)(PAGE0->mem_pdc_hi) << 32 | PAGE0->mem_pdc
+# define mem_pdc_call(args...) unlikely(parisc_narrow_firmware) ? real32_call(MEM_PDC, args) : real64_call(MEM_PDC, args)
+#else
+# define MEM_PDC (unsigned long)PAGE0->mem_pdc
+# define mem_pdc_call(args...) real32_call(MEM_PDC, args)
+#endif
+
+
+/**
+ * f_extend - Convert PDC addresses to kernel addresses.
+ * @address: Address returned from PDC.
+ *
+ * This function is used to convert PDC addresses into kernel addresses
+ * when the PDC address size and kernel address size are different.
+ */
+static unsigned long f_extend(unsigned long address)
+{
+#ifdef CONFIG_64BIT
+ if(unlikely(parisc_narrow_firmware)) {
+ if((address & 0xff000000) == 0xf0000000)
+ return (0xfffffff0UL << 32) | (u32)address;
+
+ if((address & 0xf0000000) == 0xf0000000)
+ return (0xffffffffUL << 32) | (u32)address;
+ }
+#endif
+ return address;
+}
+
+/**
+ * convert_to_wide - Convert the return buffer addresses into kernel addresses.
+ * @addr: The return buffer from PDC.
+ *
+ * This function is used to convert the return buffer addresses retrieved from PDC
+ * into kernel addresses when the PDC address size and kernel address size are
+ * different.
+ */
+static void convert_to_wide(unsigned long *addr)
+{
+#ifdef CONFIG_64BIT
+ int i;
+ unsigned int *p = (unsigned int *)addr;
+
+ if (unlikely(parisc_narrow_firmware)) {
+ for (i = (NUM_PDC_RESULT-1); i >= 0; --i)
+ addr[i] = p[i];
+ }
+#endif
+}
+
+#ifdef CONFIG_64BIT
+void set_firmware_width_unlocked(void)
+{
+ int ret;
+
+ ret = mem_pdc_call(PDC_MODEL, PDC_MODEL_CAPABILITIES,
+ __pa(pdc_result), 0);
+ if (ret < 0)
+ return;
+ convert_to_wide(pdc_result);
+ if (pdc_result[0] != NARROW_FIRMWARE)
+ parisc_narrow_firmware = 0;
+}
+
+/**
+ * set_firmware_width - Determine if the firmware is wide or narrow.
+ *
+ * This function must be called before any pdc_* function that uses the
+ * convert_to_wide function.
+ */
+void set_firmware_width(void)
+{
+ unsigned long flags;
+
+ /* already initialized? */
+ if (parisc_narrow_firmware != 2)
+ return;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ set_firmware_width_unlocked();
+ spin_unlock_irqrestore(&pdc_lock, flags);
+}
+#else
+void set_firmware_width_unlocked(void)
+{
+ return;
+}
+
+void set_firmware_width(void)
+{
+ return;
+}
+#endif /*CONFIG_64BIT*/
+
+
+#if !defined(BOOTLOADER)
+/**
+ * pdc_emergency_unlock - Unlock the linux pdc lock
+ *
+ * This call unlocks the linux pdc lock in case we need some PDC functions
+ * (like pdc_add_valid) during kernel stack dump.
+ */
+void pdc_emergency_unlock(void)
+{
+ /* Spinlock DEBUG code freaks out if we unconditionally unlock */
+ if (spin_is_locked(&pdc_lock))
+ spin_unlock(&pdc_lock);
+}
+
+
+/**
+ * pdc_add_valid - Verify address can be accessed without causing a HPMC.
+ * @address: Address to be verified.
+ *
+ * This PDC call attempts to read from the specified address and verifies
+ * if the address is valid.
+ *
+ * The return value is PDC_OK (0) in case accessing this address is valid.
+ */
+int pdc_add_valid(unsigned long address)
+{
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_ADD_VALID, PDC_ADD_VALID_VERIFY, address);
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+EXPORT_SYMBOL(pdc_add_valid);
+
+/**
+ * pdc_instr - Get instruction that invokes PDCE_CHECK in HPMC handler.
+ * @instr: Pointer to variable which will get instruction opcode.
+ *
+ * The return value is PDC_OK (0) in case call succeeded.
+ */
+int __init pdc_instr(unsigned int *instr)
+{
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_INSTR, 0UL, __pa(pdc_result));
+ convert_to_wide(pdc_result);
+ *instr = pdc_result[0];
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+
+/**
+ * pdc_chassis_info - Return chassis information.
+ * @chassis_info: The memory buffer address.
+ * @led_info: The size of the memory buffer address.
+ * @len: The size of the memory buffer address.
+ *
+ * An HVERSION dependent call for returning the chassis information.
+ */
+int __init pdc_chassis_info(struct pdc_chassis_info *chassis_info, void *led_info, unsigned long len)
+{
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ memcpy(&pdc_result, chassis_info, sizeof(*chassis_info));
+ memcpy(&pdc_result2, led_info, len);
+ retval = mem_pdc_call(PDC_CHASSIS, PDC_RETURN_CHASSIS_INFO,
+ __pa(pdc_result), __pa(pdc_result2), len);
+ memcpy(chassis_info, pdc_result, sizeof(*chassis_info));
+ memcpy(led_info, pdc_result2, len);
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+
+/**
+ * pdc_pat_chassis_send_log - Sends a PDC PAT CHASSIS log message.
+ * @state: state of the machine
+ * @data: value for that state
+ *
+ * Must be correctly formatted or expect system crash
+ */
+#ifdef CONFIG_64BIT
+int pdc_pat_chassis_send_log(unsigned long state, unsigned long data)
+{
+ int retval = 0;
+ unsigned long flags;
+
+ if (!is_pdc_pat())
+ return -1;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_PAT_CHASSIS_LOG, PDC_PAT_CHASSIS_WRITE_LOG, __pa(&state), __pa(&data));
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+#endif
+
+/**
+ * pdc_chassis_disp - Updates chassis code
+ * @disp: value to show on display
+ */
+int pdc_chassis_disp(unsigned long disp)
+{
+ int retval = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_CHASSIS, PDC_CHASSIS_DISP, disp);
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+
+/**
+ * __pdc_cpu_rendezvous - Stop currently executing CPU and do not return.
+ */
+int __pdc_cpu_rendezvous(void)
+{
+ if (is_pdc_pat())
+ return mem_pdc_call(PDC_PAT_CPU, PDC_PAT_CPU_RENDEZVOUS);
+ else
+ return mem_pdc_call(PDC_PROC, 1, 0);
+}
+
+/**
+ * pdc_cpu_rendezvous_lock - Lock PDC while transitioning to rendezvous state
+ */
+void pdc_cpu_rendezvous_lock(void) __acquires(&pdc_lock)
+{
+ spin_lock(&pdc_lock);
+}
+
+/**
+ * pdc_cpu_rendezvous_unlock - Unlock PDC after reaching rendezvous state
+ */
+void pdc_cpu_rendezvous_unlock(void) __releases(&pdc_lock)
+{
+ spin_unlock(&pdc_lock);
+}
+
+/**
+ * pdc_pat_get_PDC_entrypoint - Get PDC entry point for current CPU
+ * @pdc_entry: pointer to where the PDC entry point should be stored
+ */
+int pdc_pat_get_PDC_entrypoint(unsigned long *pdc_entry)
+{
+ int retval = 0;
+ unsigned long flags;
+
+ if (!IS_ENABLED(CONFIG_SMP) || !is_pdc_pat()) {
+ *pdc_entry = MEM_PDC;
+ return 0;
+ }
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_PAT_CPU, PDC_PAT_CPU_GET_PDC_ENTRYPOINT,
+ __pa(pdc_result));
+ *pdc_entry = pdc_result[0];
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+/**
+ * pdc_chassis_warn - Fetches chassis warnings
+ * @warn: The warning value to be shown
+ */
+int pdc_chassis_warn(unsigned long *warn)
+{
+ int retval = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_CHASSIS, PDC_CHASSIS_WARN, __pa(pdc_result));
+ *warn = pdc_result[0];
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+
+int pdc_coproc_cfg_unlocked(struct pdc_coproc_cfg *pdc_coproc_info)
+{
+ int ret;
+
+ ret = mem_pdc_call(PDC_COPROC, PDC_COPROC_CFG, __pa(pdc_result));
+ convert_to_wide(pdc_result);
+ pdc_coproc_info->ccr_functional = pdc_result[0];
+ pdc_coproc_info->ccr_present = pdc_result[1];
+ pdc_coproc_info->revision = pdc_result[17];
+ pdc_coproc_info->model = pdc_result[18];
+
+ return ret;
+}
+
+/**
+ * pdc_coproc_cfg - To identify coprocessors attached to the processor.
+ * @pdc_coproc_info: Return buffer address.
+ *
+ * This PDC call returns the presence and status of all the coprocessors
+ * attached to the processor.
+ */
+int pdc_coproc_cfg(struct pdc_coproc_cfg *pdc_coproc_info)
+{
+ int ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ ret = pdc_coproc_cfg_unlocked(pdc_coproc_info);
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return ret;
+}
+
+/**
+ * pdc_iodc_read - Read data from the modules IODC.
+ * @actcnt: The actual number of bytes.
+ * @hpa: The HPA of the module for the iodc read.
+ * @index: The iodc entry point.
+ * @iodc_data: A buffer memory for the iodc options.
+ * @iodc_data_size: Size of the memory buffer.
+ *
+ * This PDC call reads from the IODC of the module specified by the hpa
+ * argument.
+ */
+int pdc_iodc_read(unsigned long *actcnt, unsigned long hpa, unsigned int index,
+ void *iodc_data, unsigned int iodc_data_size)
+{
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_IODC, PDC_IODC_READ, __pa(pdc_result), hpa,
+ index, __pa(pdc_result2), iodc_data_size);
+ convert_to_wide(pdc_result);
+ *actcnt = pdc_result[0];
+ memcpy(iodc_data, pdc_result2, iodc_data_size);
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+EXPORT_SYMBOL(pdc_iodc_read);
+
+/**
+ * pdc_system_map_find_mods - Locate unarchitected modules.
+ * @pdc_mod_info: Return buffer address.
+ * @mod_path: pointer to dev path structure.
+ * @mod_index: fixed address module index.
+ *
+ * To locate and identify modules which reside at fixed I/O addresses, which
+ * do not self-identify via architected bus walks.
+ */
+int pdc_system_map_find_mods(struct pdc_system_map_mod_info *pdc_mod_info,
+ struct pdc_module_path *mod_path, long mod_index)
+{
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_SYSTEM_MAP, PDC_FIND_MODULE, __pa(pdc_result),
+ __pa(pdc_result2), mod_index);
+ convert_to_wide(pdc_result);
+ memcpy(pdc_mod_info, pdc_result, sizeof(*pdc_mod_info));
+ memcpy(mod_path, pdc_result2, sizeof(*mod_path));
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ pdc_mod_info->mod_addr = f_extend(pdc_mod_info->mod_addr);
+ return retval;
+}
+
+/**
+ * pdc_system_map_find_addrs - Retrieve additional address ranges.
+ * @pdc_addr_info: Return buffer address.
+ * @mod_index: Fixed address module index.
+ * @addr_index: Address range index.
+ *
+ * Retrieve additional information about subsequent address ranges for modules
+ * with multiple address ranges.
+ */
+int pdc_system_map_find_addrs(struct pdc_system_map_addr_info *pdc_addr_info,
+ long mod_index, long addr_index)
+{
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_SYSTEM_MAP, PDC_FIND_ADDRESS, __pa(pdc_result),
+ mod_index, addr_index);
+ convert_to_wide(pdc_result);
+ memcpy(pdc_addr_info, pdc_result, sizeof(*pdc_addr_info));
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ pdc_addr_info->mod_addr = f_extend(pdc_addr_info->mod_addr);
+ return retval;
+}
+
+/**
+ * pdc_model_info - Return model information about the processor.
+ * @model: The return buffer.
+ *
+ * Returns the version numbers, identifiers, and capabilities from the processor module.
+ */
+int pdc_model_info(struct pdc_model *model)
+{
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_MODEL, PDC_MODEL_INFO, __pa(pdc_result), 0);
+ convert_to_wide(pdc_result);
+ memcpy(model, pdc_result, sizeof(*model));
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+
+/**
+ * pdc_model_sysmodel - Get the system model name.
+ * @os_id: The operating system ID asked for (an OS_ID_* value)
+ * @name: A char array of at least 81 characters.
+ *
+ * Get system model name from PDC ROM (e.g. 9000/715 or 9000/778/B160L).
+ * Using OS_ID_HPUX will return the equivalent of the 'modelname' command
+ * on HP/UX.
+ */
+int pdc_model_sysmodel(unsigned int os_id, char *name)
+{
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_MODEL, PDC_MODEL_SYSMODEL, __pa(pdc_result),
+ os_id, __pa(name));
+ convert_to_wide(pdc_result);
+
+ if (retval == PDC_OK) {
+ name[pdc_result[0]] = '\0'; /* add trailing '\0' */
+ } else {
+ name[0] = 0;
+ }
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+
+/**
+ * pdc_model_versions - Identify the version number of each processor.
+ * @versions: The return buffer.
+ * @id: The id of the processor to check.
+ *
+ * Returns the version number for each processor component.
+ *
+ * This comment was here before, but I do not know what it means :( -RB
+ * id: 0 = cpu revision, 1 = boot-rom-version
+ */
+int pdc_model_versions(unsigned long *versions, int id)
+{
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_MODEL, PDC_MODEL_VERSIONS, __pa(pdc_result), id);
+ convert_to_wide(pdc_result);
+ *versions = pdc_result[0];
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+
+/**
+ * pdc_model_cpuid - Returns the CPU_ID.
+ * @cpu_id: The return buffer.
+ *
+ * Returns the CPU_ID value which uniquely identifies the cpu portion of
+ * the processor module.
+ */
+int pdc_model_cpuid(unsigned long *cpu_id)
+{
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ pdc_result[0] = 0; /* preset zero (call may not be implemented!) */
+ retval = mem_pdc_call(PDC_MODEL, PDC_MODEL_CPU_ID, __pa(pdc_result), 0);
+ convert_to_wide(pdc_result);
+ *cpu_id = pdc_result[0];
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+
+/**
+ * pdc_model_capabilities - Returns the platform capabilities.
+ * @capabilities: The return buffer.
+ *
+ * Returns information about platform support for 32- and/or 64-bit
+ * OSes, IO-PDIR coherency, and virtual aliasing.
+ */
+int pdc_model_capabilities(unsigned long *capabilities)
+{
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ pdc_result[0] = 0; /* preset zero (call may not be implemented!) */
+ retval = mem_pdc_call(PDC_MODEL, PDC_MODEL_CAPABILITIES, __pa(pdc_result), 0);
+ convert_to_wide(pdc_result);
+ if (retval == PDC_OK) {
+ *capabilities = pdc_result[0];
+ } else {
+ *capabilities = PDC_MODEL_OS32;
+ }
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+
+/**
+ * pdc_model_platform_info - Returns machine product and serial number.
+ * @orig_prod_num: Return buffer for original product number.
+ * @current_prod_num: Return buffer for current product number.
+ * @serial_no: Return buffer for serial number.
+ *
+ * Returns strings containing the original and current product numbers and the
+ * serial number of the system.
+ */
+int pdc_model_platform_info(char *orig_prod_num, char *current_prod_num,
+ char *serial_no)
+{
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_MODEL, PDC_MODEL_GET_PLATFORM_INFO,
+ __pa(orig_prod_num), __pa(current_prod_num), __pa(serial_no));
+ convert_to_wide(pdc_result);
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+
+/**
+ * pdc_cache_info - Return cache and TLB information.
+ * @cache_info: The return buffer.
+ *
+ * Returns information about the processor's cache and TLB.
+ */
+int pdc_cache_info(struct pdc_cache_info *cache_info)
+{
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_CACHE, PDC_CACHE_INFO, __pa(pdc_result), 0);
+ convert_to_wide(pdc_result);
+ memcpy(cache_info, pdc_result, sizeof(*cache_info));
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+
+/**
+ * pdc_spaceid_bits - Return whether Space ID hashing is turned on.
+ * @space_bits: Should be 0, if not, bad mojo!
+ *
+ * Returns information about Space ID hashing.
+ */
+int pdc_spaceid_bits(unsigned long *space_bits)
+{
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ pdc_result[0] = 0;
+ retval = mem_pdc_call(PDC_CACHE, PDC_CACHE_RET_SPID, __pa(pdc_result), 0);
+ convert_to_wide(pdc_result);
+ *space_bits = pdc_result[0];
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+
+/**
+ * pdc_btlb_info - Return block TLB information.
+ * @btlb: The return buffer.
+ *
+ * Returns information about the hardware Block TLB.
+ */
+int pdc_btlb_info(struct pdc_btlb_info *btlb)
+{
+ int retval;
+ unsigned long flags;
+
+ if (IS_ENABLED(CONFIG_PA20))
+ return PDC_BAD_PROC;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_BLOCK_TLB, PDC_BTLB_INFO, __pa(pdc_result), 0);
+ memcpy(btlb, pdc_result, sizeof(*btlb));
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ if(retval < 0) {
+ btlb->max_size = 0;
+ }
+ return retval;
+}
+
+int pdc_btlb_insert(unsigned long long vpage, unsigned long physpage, unsigned long len,
+ unsigned long entry_info, unsigned long slot)
+{
+ int retval;
+ unsigned long flags;
+
+ if (IS_ENABLED(CONFIG_PA20))
+ return PDC_BAD_PROC;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_BLOCK_TLB, PDC_BTLB_INSERT, (unsigned long) (vpage >> 32),
+ (unsigned long) vpage, physpage, len, entry_info, slot);
+ spin_unlock_irqrestore(&pdc_lock, flags);
+ return retval;
+}
+
+int pdc_btlb_purge_all(void)
+{
+ int retval;
+ unsigned long flags;
+
+ if (IS_ENABLED(CONFIG_PA20))
+ return PDC_BAD_PROC;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_BLOCK_TLB, PDC_BTLB_PURGE_ALL);
+ spin_unlock_irqrestore(&pdc_lock, flags);
+ return retval;
+}
+
+/**
+ * pdc_mem_map_hpa - Find fixed module information.
+ * @address: The return buffer
+ * @mod_path: pointer to dev path structure.
+ *
+ * This call was developed for S700 workstations to allow the kernel to find
+ * the I/O devices (Core I/O). In the future (Kittyhawk and beyond) this
+ * call will be replaced (on workstations) by the architected PDC_SYSTEM_MAP
+ * call.
+ *
+ * This call is supported by all existing S700 workstations (up to Gecko).
+ */
+int pdc_mem_map_hpa(struct pdc_memory_map *address,
+ struct pdc_module_path *mod_path)
+{
+ int retval;
+ unsigned long flags;
+
+ if (IS_ENABLED(CONFIG_PA20))
+ return PDC_BAD_PROC;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ memcpy(pdc_result2, mod_path, sizeof(*mod_path));
+ retval = mem_pdc_call(PDC_MEM_MAP, PDC_MEM_MAP_HPA, __pa(pdc_result),
+ __pa(pdc_result2));
+ memcpy(address, pdc_result, sizeof(*address));
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+
+/**
+ * pdc_lan_station_id - Get the LAN address.
+ * @lan_addr: The return buffer.
+ * @hpa: The network device HPA.
+ *
+ * Get the LAN station address when it is not directly available from the LAN hardware.
+ */
+int pdc_lan_station_id(char *lan_addr, unsigned long hpa)
+{
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_LAN_STATION_ID, PDC_LAN_STATION_ID_READ,
+ __pa(pdc_result), hpa);
+ if (retval < 0) {
+ /* FIXME: else read MAC from NVRAM */
+ memset(lan_addr, 0, PDC_LAN_STATION_ID_SIZE);
+ } else {
+ memcpy(lan_addr, pdc_result, PDC_LAN_STATION_ID_SIZE);
+ }
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+EXPORT_SYMBOL(pdc_lan_station_id);
+
+/**
+ * pdc_stable_read - Read data from Stable Storage.
+ * @staddr: Stable Storage address to access.
+ * @memaddr: The memory address where Stable Storage data shall be copied.
+ * @count: number of bytes to transfer. count is multiple of 4.
+ *
+ * This PDC call reads from the Stable Storage address supplied in staddr
+ * and copies count bytes to the memory address memaddr.
+ * The call will fail if staddr+count > PDC_STABLE size.
+ */
+int pdc_stable_read(unsigned long staddr, void *memaddr, unsigned long count)
+{
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_STABLE, PDC_STABLE_READ, staddr,
+ __pa(pdc_result), count);
+ convert_to_wide(pdc_result);
+ memcpy(memaddr, pdc_result, count);
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+EXPORT_SYMBOL(pdc_stable_read);
+
+/**
+ * pdc_stable_write - Write data to Stable Storage.
+ * @staddr: Stable Storage address to access.
+ * @memaddr: The memory address where Stable Storage data shall be read from.
+ * @count: number of bytes to transfer. count is multiple of 4.
+ *
+ * This PDC call reads count bytes from the supplied memaddr address,
+ * and copies count bytes to the Stable Storage address staddr.
+ * The call will fail if staddr+count > PDC_STABLE size.
+ */
+int pdc_stable_write(unsigned long staddr, void *memaddr, unsigned long count)
+{
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ memcpy(pdc_result, memaddr, count);
+ convert_to_wide(pdc_result);
+ retval = mem_pdc_call(PDC_STABLE, PDC_STABLE_WRITE, staddr,
+ __pa(pdc_result), count);
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+EXPORT_SYMBOL(pdc_stable_write);
+
+/**
+ * pdc_stable_get_size - Get Stable Storage size in bytes.
+ * @size: pointer where the size will be stored.
+ *
+ * This PDC call returns the number of bytes in the processor's Stable
+ * Storage, which is the number of contiguous bytes implemented in Stable
+ * Storage starting from staddr=0. size in an unsigned 64-bit integer
+ * which is a multiple of four.
+ */
+int pdc_stable_get_size(unsigned long *size)
+{
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_STABLE, PDC_STABLE_RETURN_SIZE, __pa(pdc_result));
+ *size = pdc_result[0];
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+EXPORT_SYMBOL(pdc_stable_get_size);
+
+/**
+ * pdc_stable_verify_contents - Checks that Stable Storage contents are valid.
+ *
+ * This PDC call is meant to be used to check the integrity of the current
+ * contents of Stable Storage.
+ */
+int pdc_stable_verify_contents(void)
+{
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_STABLE, PDC_STABLE_VERIFY_CONTENTS);
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+EXPORT_SYMBOL(pdc_stable_verify_contents);
+
+/**
+ * pdc_stable_initialize - Sets Stable Storage contents to zero and initialize
+ * the validity indicator.
+ *
+ * This PDC call will erase all contents of Stable Storage. Use with care!
+ */
+int pdc_stable_initialize(void)
+{
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_STABLE, PDC_STABLE_INITIALIZE);
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+EXPORT_SYMBOL(pdc_stable_initialize);
+
+/**
+ * pdc_get_initiator - Get the SCSI Interface Card params (SCSI ID, SDTR, SE or LVD)
+ * @hwpath: fully bc.mod style path to the device.
+ * @initiator: the array to return the result into
+ *
+ * Get the SCSI operational parameters from PDC.
+ * Needed since HPUX never used BIOS or symbios card NVRAM.
+ * Most ncr/sym cards won't have an entry and just use whatever
+ * capabilities of the card are (eg Ultra, LVD). But there are
+ * several cases where it's useful:
+ * o set SCSI id for Multi-initiator clusters,
+ * o cable too long (ie SE scsi 10Mhz won't support 6m length),
+ * o bus width exported is less than what the interface chip supports.
+ */
+int pdc_get_initiator(struct hardware_path *hwpath, struct pdc_initiator *initiator)
+{
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+
+/* BCJ-XXXX series boxes. E.G. "9000/785/C3000" */
+#define IS_SPROCKETS() (strlen(boot_cpu_data.pdc.sys_model_name) == 14 && \
+ strncmp(boot_cpu_data.pdc.sys_model_name, "9000/785", 8) == 0)
+
+ retval = mem_pdc_call(PDC_INITIATOR, PDC_GET_INITIATOR,
+ __pa(pdc_result), __pa(hwpath));
+ if (retval < PDC_OK)
+ goto out;
+
+ if (pdc_result[0] < 16) {
+ initiator->host_id = pdc_result[0];
+ } else {
+ initiator->host_id = -1;
+ }
+
+ /*
+ * Sprockets and Piranha return 20 or 40 (MT/s). Prelude returns
+ * 1, 2, 5 or 10 for 5, 10, 20 or 40 MT/s, respectively
+ */
+ switch (pdc_result[1]) {
+ case 1: initiator->factor = 50; break;
+ case 2: initiator->factor = 25; break;
+ case 5: initiator->factor = 12; break;
+ case 25: initiator->factor = 10; break;
+ case 20: initiator->factor = 12; break;
+ case 40: initiator->factor = 10; break;
+ default: initiator->factor = -1; break;
+ }
+
+ if (IS_SPROCKETS()) {
+ initiator->width = pdc_result[4];
+ initiator->mode = pdc_result[5];
+ } else {
+ initiator->width = -1;
+ initiator->mode = -1;
+ }
+
+ out:
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return (retval >= PDC_OK);
+}
+EXPORT_SYMBOL(pdc_get_initiator);
+
+
+/**
+ * pdc_pci_irt_size - Get the number of entries in the interrupt routing table.
+ * @num_entries: The return value.
+ * @hpa: The HPA for the device.
+ *
+ * This PDC function returns the number of entries in the specified cell's
+ * interrupt table.
+ * Similar to PDC_PAT stuff - but added for Forte/Allegro boxes
+ */
+int pdc_pci_irt_size(unsigned long *num_entries, unsigned long hpa)
+{
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_PCI_INDEX, PDC_PCI_GET_INT_TBL_SIZE,
+ __pa(pdc_result), hpa);
+ convert_to_wide(pdc_result);
+ *num_entries = pdc_result[0];
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+
+/**
+ * pdc_pci_irt - Get the PCI interrupt routing table.
+ * @num_entries: The number of entries in the table.
+ * @hpa: The Hard Physical Address of the device.
+ * @tbl:
+ *
+ * Get the PCI interrupt routing table for the device at the given HPA.
+ * Similar to PDC_PAT stuff - but added for Forte/Allegro boxes
+ */
+int pdc_pci_irt(unsigned long num_entries, unsigned long hpa, void *tbl)
+{
+ int retval;
+ unsigned long flags;
+
+ BUG_ON((unsigned long)tbl & 0x7);
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ pdc_result[0] = num_entries;
+ retval = mem_pdc_call(PDC_PCI_INDEX, PDC_PCI_GET_INT_TBL,
+ __pa(pdc_result), hpa, __pa(tbl));
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+
+
+#if 0 /* UNTEST CODE - left here in case someone needs it */
+
+/**
+ * pdc_pci_config_read - read PCI config space.
+ * @hpa: Token from PDC to indicate which PCI device
+ * @cfg_addr: Configuration space address to read from
+ *
+ * Read PCI Configuration space *before* linux PCI subsystem is running.
+ */
+unsigned int pdc_pci_config_read(void *hpa, unsigned long cfg_addr)
+{
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ pdc_result[0] = 0;
+ pdc_result[1] = 0;
+ retval = mem_pdc_call(PDC_PCI_INDEX, PDC_PCI_READ_CONFIG,
+ __pa(pdc_result), hpa, cfg_addr&~3UL, 4UL);
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval ? ~0 : (unsigned int) pdc_result[0];
+}
+
+
+/**
+ * pdc_pci_config_write - read PCI config space.
+ * @hpa: Token from PDC to indicate which PCI device
+ * @cfg_addr: Configuration space address to write
+ * @val: Value we want in the 32-bit register
+ *
+ * Write PCI Configuration space *before* linux PCI subsystem is running.
+ */
+void pdc_pci_config_write(void *hpa, unsigned long cfg_addr, unsigned int val)
+{
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ pdc_result[0] = 0;
+ retval = mem_pdc_call(PDC_PCI_INDEX, PDC_PCI_WRITE_CONFIG,
+ __pa(pdc_result), hpa,
+ cfg_addr&~3UL, 4UL, (unsigned long) val);
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+#endif /* UNTESTED CODE */
+
+/**
+ * pdc_tod_read - Read the Time-Of-Day clock.
+ * @tod: The return buffer:
+ *
+ * Read the Time-Of-Day clock
+ */
+int pdc_tod_read(struct pdc_tod *tod)
+{
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_TOD, PDC_TOD_READ, __pa(pdc_result), 0);
+ convert_to_wide(pdc_result);
+ memcpy(tod, pdc_result, sizeof(*tod));
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+EXPORT_SYMBOL(pdc_tod_read);
+
+int pdc_mem_pdt_info(struct pdc_mem_retinfo *rinfo)
+{
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_MEM, PDC_MEM_MEMINFO, __pa(pdc_result), 0);
+ convert_to_wide(pdc_result);
+ memcpy(rinfo, pdc_result, sizeof(*rinfo));
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+
+int pdc_mem_pdt_read_entries(struct pdc_mem_read_pdt *pret,
+ unsigned long *pdt_entries_ptr)
+{
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_MEM, PDC_MEM_READ_PDT, __pa(pdc_result),
+ __pa(pdt_entries_ptr));
+ if (retval == PDC_OK) {
+ convert_to_wide(pdc_result);
+ memcpy(pret, pdc_result, sizeof(*pret));
+ }
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+#ifdef CONFIG_64BIT
+ /*
+ * 64-bit kernels should not call this PDT function in narrow mode.
+ * The pdt_entries_ptr array above will now contain 32-bit values
+ */
+ if (WARN_ON_ONCE((retval == PDC_OK) && parisc_narrow_firmware))
+ return PDC_ERROR;
+#endif
+
+ return retval;
+}
+
+/**
+ * pdc_pim_toc11 - Fetch TOC PIM 1.1 data from firmware.
+ * @ret: pointer to return buffer
+ */
+int pdc_pim_toc11(struct pdc_toc_pim_11 *ret)
+{
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_PIM, PDC_PIM_TOC, __pa(pdc_result),
+ __pa(ret), sizeof(*ret));
+ spin_unlock_irqrestore(&pdc_lock, flags);
+ return retval;
+}
+
+/**
+ * pdc_pim_toc20 - Fetch TOC PIM 2.0 data from firmware.
+ * @ret: pointer to return buffer
+ */
+int pdc_pim_toc20(struct pdc_toc_pim_20 *ret)
+{
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_PIM, PDC_PIM_TOC, __pa(pdc_result),
+ __pa(ret), sizeof(*ret));
+ spin_unlock_irqrestore(&pdc_lock, flags);
+ return retval;
+}
+
+/**
+ * pdc_tod_set - Set the Time-Of-Day clock.
+ * @sec: The number of seconds since epoch.
+ * @usec: The number of micro seconds.
+ *
+ * Set the Time-Of-Day clock.
+ */
+int pdc_tod_set(unsigned long sec, unsigned long usec)
+{
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_TOD, PDC_TOD_WRITE, sec, usec);
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+EXPORT_SYMBOL(pdc_tod_set);
+
+#ifdef CONFIG_64BIT
+int pdc_mem_mem_table(struct pdc_memory_table_raddr *r_addr,
+ struct pdc_memory_table *tbl, unsigned long entries)
+{
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_MEM, PDC_MEM_TABLE, __pa(pdc_result), __pa(pdc_result2), entries);
+ convert_to_wide(pdc_result);
+ memcpy(r_addr, pdc_result, sizeof(*r_addr));
+ memcpy(tbl, pdc_result2, entries * sizeof(*tbl));
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+#endif /* CONFIG_64BIT */
+
+/* FIXME: Is this pdc used? I could not find type reference to ftc_bitmap
+ * so I guessed at unsigned long. Someone who knows what this does, can fix
+ * it later. :)
+ */
+int pdc_do_firm_test_reset(unsigned long ftc_bitmap)
+{
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_BROADCAST_RESET, PDC_DO_FIRM_TEST_RESET,
+ PDC_FIRM_TEST_MAGIC, ftc_bitmap);
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+
+/*
+ * pdc_do_reset - Reset the system.
+ *
+ * Reset the system.
+ */
+int pdc_do_reset(void)
+{
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_BROADCAST_RESET, PDC_DO_RESET);
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+
+/*
+ * pdc_soft_power_info - Enable soft power switch.
+ * @power_reg: address of soft power register
+ *
+ * Return the absolute address of the soft power switch register
+ */
+int __init pdc_soft_power_info(unsigned long *power_reg)
+{
+ int retval;
+ unsigned long flags;
+
+ *power_reg = (unsigned long) (-1);
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_SOFT_POWER, PDC_SOFT_POWER_INFO, __pa(pdc_result), 0);
+ if (retval == PDC_OK) {
+ convert_to_wide(pdc_result);
+ *power_reg = f_extend(pdc_result[0]);
+ }
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+
+/*
+ * pdc_soft_power_button{_panic} - Control the soft power button behaviour
+ * @sw_control: 0 for hardware control, 1 for software control
+ *
+ *
+ * This PDC function places the soft power button under software or
+ * hardware control.
+ * Under software control the OS may control to when to allow to shut
+ * down the system. Under hardware control pressing the power button
+ * powers off the system immediately.
+ *
+ * The _panic version relies on spin_trylock to prevent deadlock
+ * on panic path.
+ */
+int pdc_soft_power_button(int sw_control)
+{
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_SOFT_POWER, PDC_SOFT_POWER_ENABLE, __pa(pdc_result), sw_control);
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+
+int pdc_soft_power_button_panic(int sw_control)
+{
+ int retval;
+ unsigned long flags;
+
+ if (!spin_trylock_irqsave(&pdc_lock, flags)) {
+ pr_emerg("Couldn't enable soft power button\n");
+ return -EBUSY; /* ignored by the panic notifier */
+ }
+
+ retval = mem_pdc_call(PDC_SOFT_POWER, PDC_SOFT_POWER_ENABLE, __pa(pdc_result), sw_control);
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+
+/*
+ * pdc_io_reset - Hack to avoid overlapping range registers of Bridges devices.
+ * Primarily a problem on T600 (which parisc-linux doesn't support) but
+ * who knows what other platform firmware might do with this OS "hook".
+ */
+void pdc_io_reset(void)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ mem_pdc_call(PDC_IO, PDC_IO_RESET, 0);
+ spin_unlock_irqrestore(&pdc_lock, flags);
+}
+
+/*
+ * pdc_io_reset_devices - Hack to Stop USB controller
+ *
+ * If PDC used the usb controller, the usb controller
+ * is still running and will crash the machines during iommu
+ * setup, because of still running DMA. This PDC call
+ * stops the USB controller.
+ * Normally called after calling pdc_io_reset().
+ */
+void pdc_io_reset_devices(void)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ mem_pdc_call(PDC_IO, PDC_IO_RESET_DEVICES, 0);
+ spin_unlock_irqrestore(&pdc_lock, flags);
+}
+
+#endif /* defined(BOOTLOADER) */
+
+/* locked by pdc_lock */
+static char iodc_dbuf[4096] __page_aligned_bss;
+
+/**
+ * pdc_iodc_print - Console print using IODC.
+ * @str: the string to output.
+ * @count: length of str
+ *
+ * Note that only these special chars are architected for console IODC io:
+ * BEL, BS, CR, and LF. Others are passed through.
+ * Since the HP console requires CR+LF to perform a 'newline', we translate
+ * "\n" to "\r\n".
+ */
+int pdc_iodc_print(const unsigned char *str, unsigned count)
+{
+ unsigned int i, found = 0;
+ unsigned long flags;
+
+ count = min_t(unsigned int, count, sizeof(iodc_dbuf));
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ for (i = 0; i < count;) {
+ switch(str[i]) {
+ case '\n':
+ iodc_dbuf[i+0] = '\r';
+ iodc_dbuf[i+1] = '\n';
+ i += 2;
+ found = 1;
+ goto print;
+ default:
+ iodc_dbuf[i] = str[i];
+ i++;
+ break;
+ }
+ }
+
+print:
+ real32_call(PAGE0->mem_cons.iodc_io,
+ (unsigned long)PAGE0->mem_cons.hpa, ENTRY_IO_COUT,
+ PAGE0->mem_cons.spa, __pa(PAGE0->mem_cons.dp.layers),
+ __pa(pdc_result), 0, __pa(iodc_dbuf), i, 0);
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return i - found;
+}
+
+#if !defined(BOOTLOADER)
+/**
+ * pdc_iodc_getc - Read a character (non-blocking) from the PDC console.
+ *
+ * Read a character (non-blocking) from the PDC console, returns -1 if
+ * key is not present.
+ */
+int pdc_iodc_getc(void)
+{
+ int ch;
+ int status;
+ unsigned long flags;
+
+ /* Bail if no console input device. */
+ if (!PAGE0->mem_kbd.iodc_io)
+ return 0;
+
+ /* wait for a keyboard (rs232)-input */
+ spin_lock_irqsave(&pdc_lock, flags);
+ real32_call(PAGE0->mem_kbd.iodc_io,
+ (unsigned long)PAGE0->mem_kbd.hpa, ENTRY_IO_CIN,
+ PAGE0->mem_kbd.spa, __pa(PAGE0->mem_kbd.dp.layers),
+ __pa(pdc_result), 0, __pa(iodc_dbuf), 1, 0);
+
+ ch = *iodc_dbuf;
+ /* like convert_to_wide() but for first return value only: */
+ status = *(int *)&pdc_result;
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ if (status == 0)
+ return -1;
+
+ return ch;
+}
+
+int pdc_sti_call(unsigned long func, unsigned long flags,
+ unsigned long inptr, unsigned long outputr,
+ unsigned long glob_cfg, int do_call64)
+{
+ int retval = 0;
+ unsigned long irqflags;
+
+ spin_lock_irqsave(&pdc_lock, irqflags);
+ if (IS_ENABLED(CONFIG_64BIT) && do_call64) {
+#ifdef CONFIG_64BIT
+ retval = real64_call(func, flags, inptr, outputr, glob_cfg);
+#else
+ WARN_ON(1);
+#endif
+ } else {
+ retval = real32_call(func, flags, inptr, outputr, glob_cfg);
+ }
+ spin_unlock_irqrestore(&pdc_lock, irqflags);
+
+ return retval;
+}
+EXPORT_SYMBOL(pdc_sti_call);
+
+#ifdef CONFIG_64BIT
+/**
+ * pdc_pat_cell_get_number - Returns the cell number.
+ * @cell_info: The return buffer.
+ *
+ * This PDC call returns the cell number of the cell from which the call
+ * is made.
+ */
+int pdc_pat_cell_get_number(struct pdc_pat_cell_num *cell_info)
+{
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_PAT_CELL, PDC_PAT_CELL_GET_NUMBER, __pa(pdc_result));
+ memcpy(cell_info, pdc_result, sizeof(*cell_info));
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+
+/**
+ * pdc_pat_cell_module - Retrieve the cell's module information.
+ * @actcnt: The number of bytes written to mem_addr.
+ * @ploc: The physical location.
+ * @mod: The module index.
+ * @view_type: The view of the address type.
+ * @mem_addr: The return buffer.
+ *
+ * This PDC call returns information about each module attached to the cell
+ * at the specified location.
+ */
+int pdc_pat_cell_module(unsigned long *actcnt, unsigned long ploc, unsigned long mod,
+ unsigned long view_type, void *mem_addr)
+{
+ int retval;
+ unsigned long flags;
+ static struct pdc_pat_cell_mod_maddr_block result __attribute__ ((aligned (8)));
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_PAT_CELL, PDC_PAT_CELL_MODULE, __pa(pdc_result),
+ ploc, mod, view_type, __pa(&result));
+ if(!retval) {
+ *actcnt = pdc_result[0];
+ memcpy(mem_addr, &result, *actcnt);
+ }
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+
+/**
+ * pdc_pat_cell_info - Retrieve the cell's information.
+ * @info: The pointer to a struct pdc_pat_cell_info_rtn_block.
+ * @actcnt: The number of bytes which should be written to info.
+ * @offset: offset of the structure.
+ * @cell_number: The cell number which should be asked, or -1 for current cell.
+ *
+ * This PDC call returns information about the given cell (or all cells).
+ */
+int pdc_pat_cell_info(struct pdc_pat_cell_info_rtn_block *info,
+ unsigned long *actcnt, unsigned long offset,
+ unsigned long cell_number)
+{
+ int retval;
+ unsigned long flags;
+ struct pdc_pat_cell_info_rtn_block result;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_PAT_CELL, PDC_PAT_CELL_GET_INFO,
+ __pa(pdc_result), __pa(&result), *actcnt,
+ offset, cell_number);
+ if (!retval) {
+ *actcnt = pdc_result[0];
+ memcpy(info, &result, *actcnt);
+ }
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+
+/**
+ * pdc_pat_cpu_get_number - Retrieve the cpu number.
+ * @cpu_info: The return buffer.
+ * @hpa: The Hard Physical Address of the CPU.
+ *
+ * Retrieve the cpu number for the cpu at the specified HPA.
+ */
+int pdc_pat_cpu_get_number(struct pdc_pat_cpu_num *cpu_info, unsigned long hpa)
+{
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_PAT_CPU, PDC_PAT_CPU_GET_NUMBER,
+ __pa(&pdc_result), hpa);
+ memcpy(cpu_info, pdc_result, sizeof(*cpu_info));
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+
+/**
+ * pdc_pat_get_irt_size - Retrieve the number of entries in the cell's interrupt table.
+ * @num_entries: The return value.
+ * @cell_num: The target cell.
+ *
+ * This PDC function returns the number of entries in the specified cell's
+ * interrupt table.
+ */
+int pdc_pat_get_irt_size(unsigned long *num_entries, unsigned long cell_num)
+{
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_PAT_IO, PDC_PAT_IO_GET_PCI_ROUTING_TABLE_SIZE,
+ __pa(pdc_result), cell_num);
+ *num_entries = pdc_result[0];
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+
+/**
+ * pdc_pat_get_irt - Retrieve the cell's interrupt table.
+ * @r_addr: The return buffer.
+ * @cell_num: The target cell.
+ *
+ * This PDC function returns the actual interrupt table for the specified cell.
+ */
+int pdc_pat_get_irt(void *r_addr, unsigned long cell_num)
+{
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_PAT_IO, PDC_PAT_IO_GET_PCI_ROUTING_TABLE,
+ __pa(r_addr), cell_num);
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+
+/**
+ * pdc_pat_pd_get_addr_map - Retrieve information about memory address ranges.
+ * @actual_len: The return buffer.
+ * @mem_addr: Pointer to the memory buffer.
+ * @count: The number of bytes to read from the buffer.
+ * @offset: The offset with respect to the beginning of the buffer.
+ *
+ */
+int pdc_pat_pd_get_addr_map(unsigned long *actual_len, void *mem_addr,
+ unsigned long count, unsigned long offset)
+{
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_PAT_PD, PDC_PAT_PD_GET_ADDR_MAP, __pa(pdc_result),
+ __pa(pdc_result2), count, offset);
+ *actual_len = pdc_result[0];
+ memcpy(mem_addr, pdc_result2, *actual_len);
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+
+/**
+ * pdc_pat_pd_get_pdc_revisions - Retrieve PDC interface revisions.
+ * @legacy_rev: The legacy revision.
+ * @pat_rev: The PAT revision.
+ * @pdc_cap: The PDC capabilities.
+ *
+ */
+int pdc_pat_pd_get_pdc_revisions(unsigned long *legacy_rev,
+ unsigned long *pat_rev, unsigned long *pdc_cap)
+{
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_PAT_PD, PDC_PAT_PD_GET_PDC_INTERF_REV,
+ __pa(pdc_result));
+ if (retval == PDC_OK) {
+ *legacy_rev = pdc_result[0];
+ *pat_rev = pdc_result[1];
+ *pdc_cap = pdc_result[2];
+ }
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+
+
+/**
+ * pdc_pat_io_pci_cfg_read - Read PCI configuration space.
+ * @pci_addr: PCI configuration space address for which the read request is being made.
+ * @pci_size: Size of read in bytes. Valid values are 1, 2, and 4.
+ * @mem_addr: Pointer to return memory buffer.
+ *
+ */
+int pdc_pat_io_pci_cfg_read(unsigned long pci_addr, int pci_size, u32 *mem_addr)
+{
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_PAT_IO, PDC_PAT_IO_PCI_CONFIG_READ,
+ __pa(pdc_result), pci_addr, pci_size);
+ switch(pci_size) {
+ case 1: *(u8 *) mem_addr = (u8) pdc_result[0]; break;
+ case 2: *(u16 *)mem_addr = (u16) pdc_result[0]; break;
+ case 4: *(u32 *)mem_addr = (u32) pdc_result[0]; break;
+ }
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+
+/**
+ * pdc_pat_io_pci_cfg_write - Retrieve information about memory address ranges.
+ * @pci_addr: PCI configuration space address for which the write request is being made.
+ * @pci_size: Size of write in bytes. Valid values are 1, 2, and 4.
+ * @val: Pointer to 1, 2, or 4 byte value in low order end of argument to be
+ * written to PCI Config space.
+ *
+ */
+int pdc_pat_io_pci_cfg_write(unsigned long pci_addr, int pci_size, u32 val)
+{
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_PAT_IO, PDC_PAT_IO_PCI_CONFIG_WRITE,
+ pci_addr, pci_size, val);
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+
+/**
+ * pdc_pat_mem_pdt_info - Retrieve information about page deallocation table
+ * @rinfo: memory pdt information
+ *
+ */
+int pdc_pat_mem_pdt_info(struct pdc_pat_mem_retinfo *rinfo)
+{
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_PAT_MEM, PDC_PAT_MEM_PD_INFO,
+ __pa(&pdc_result));
+ if (retval == PDC_OK)
+ memcpy(rinfo, &pdc_result, sizeof(*rinfo));
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+
+/**
+ * pdc_pat_mem_pdt_cell_info - Retrieve information about page deallocation
+ * table of a cell
+ * @rinfo: memory pdt information
+ * @cell: cell number
+ *
+ */
+int pdc_pat_mem_pdt_cell_info(struct pdc_pat_mem_cell_pdt_retinfo *rinfo,
+ unsigned long cell)
+{
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_PAT_MEM, PDC_PAT_MEM_CELL_INFO,
+ __pa(&pdc_result), cell);
+ if (retval == PDC_OK)
+ memcpy(rinfo, &pdc_result, sizeof(*rinfo));
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+
+/**
+ * pdc_pat_mem_read_cell_pdt - Read PDT entries from (old) PAT firmware
+ * @pret: array of PDT entries
+ * @pdt_entries_ptr: ptr to hold number of PDT entries
+ * @max_entries: maximum number of entries to be read
+ *
+ */
+int pdc_pat_mem_read_cell_pdt(struct pdc_pat_mem_read_pd_retinfo *pret,
+ unsigned long *pdt_entries_ptr, unsigned long max_entries)
+{
+ int retval;
+ unsigned long flags, entries;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ /* PDC_PAT_MEM_CELL_READ is available on early PAT machines only */
+ retval = mem_pdc_call(PDC_PAT_MEM, PDC_PAT_MEM_CELL_READ,
+ __pa(&pdc_result), parisc_cell_num,
+ __pa(pdt_entries_ptr));
+
+ if (retval == PDC_OK) {
+ /* build up return value as for PDC_PAT_MEM_PD_READ */
+ entries = min(pdc_result[0], max_entries);
+ pret->pdt_entries = entries;
+ pret->actual_count_bytes = entries * sizeof(unsigned long);
+ }
+
+ spin_unlock_irqrestore(&pdc_lock, flags);
+ WARN_ON(retval == PDC_OK && pdc_result[0] > max_entries);
+
+ return retval;
+}
+/**
+ * pdc_pat_mem_read_pd_pdt - Read PDT entries from (newer) PAT firmware
+ * @pret: array of PDT entries
+ * @pdt_entries_ptr: ptr to hold number of PDT entries
+ * @count: number of bytes to read
+ * @offset: offset to start (in bytes)
+ *
+ */
+int pdc_pat_mem_read_pd_pdt(struct pdc_pat_mem_read_pd_retinfo *pret,
+ unsigned long *pdt_entries_ptr, unsigned long count,
+ unsigned long offset)
+{
+ int retval;
+ unsigned long flags, entries;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_PAT_MEM, PDC_PAT_MEM_PD_READ,
+ __pa(&pdc_result), __pa(pdt_entries_ptr),
+ count, offset);
+
+ if (retval == PDC_OK) {
+ entries = min(pdc_result[0], count);
+ pret->actual_count_bytes = entries;
+ pret->pdt_entries = entries / sizeof(unsigned long);
+ }
+
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+
+/**
+ * pdc_pat_mem_get_dimm_phys_location - Get physical DIMM slot via PAT firmware
+ * @pret: ptr to hold returned information
+ * @phys_addr: physical address to examine
+ *
+ */
+int pdc_pat_mem_get_dimm_phys_location(
+ struct pdc_pat_mem_phys_mem_location *pret,
+ unsigned long phys_addr)
+{
+ int retval;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
+ retval = mem_pdc_call(PDC_PAT_MEM, PDC_PAT_MEM_ADDRESS,
+ __pa(&pdc_result), phys_addr);
+
+ if (retval == PDC_OK)
+ memcpy(pret, &pdc_result, sizeof(*pret));
+
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
+ return retval;
+}
+#endif /* CONFIG_64BIT */
+#endif /* defined(BOOTLOADER) */
+
+
+/***************** 32-bit real-mode calls ***********/
+/* The struct below is used
+ * to overlay real_stack (real2.S), preparing a 32-bit call frame.
+ * real32_call_asm() then uses this stack in narrow real mode
+ */
+
+struct narrow_stack {
+ /* use int, not long which is 64 bits */
+ unsigned int arg13;
+ unsigned int arg12;
+ unsigned int arg11;
+ unsigned int arg10;
+ unsigned int arg9;
+ unsigned int arg8;
+ unsigned int arg7;
+ unsigned int arg6;
+ unsigned int arg5;
+ unsigned int arg4;
+ unsigned int arg3;
+ unsigned int arg2;
+ unsigned int arg1;
+ unsigned int arg0;
+ unsigned int frame_marker[8];
+ unsigned int sp;
+ /* in reality, there's nearly 8k of stack after this */
+};
+
+long real32_call(unsigned long fn, ...)
+{
+ va_list args;
+ extern struct narrow_stack real_stack;
+ extern unsigned long real32_call_asm(unsigned int *,
+ unsigned int *,
+ unsigned int);
+
+ va_start(args, fn);
+ real_stack.arg0 = va_arg(args, unsigned int);
+ real_stack.arg1 = va_arg(args, unsigned int);
+ real_stack.arg2 = va_arg(args, unsigned int);
+ real_stack.arg3 = va_arg(args, unsigned int);
+ real_stack.arg4 = va_arg(args, unsigned int);
+ real_stack.arg5 = va_arg(args, unsigned int);
+ real_stack.arg6 = va_arg(args, unsigned int);
+ real_stack.arg7 = va_arg(args, unsigned int);
+ real_stack.arg8 = va_arg(args, unsigned int);
+ real_stack.arg9 = va_arg(args, unsigned int);
+ real_stack.arg10 = va_arg(args, unsigned int);
+ real_stack.arg11 = va_arg(args, unsigned int);
+ real_stack.arg12 = va_arg(args, unsigned int);
+ real_stack.arg13 = va_arg(args, unsigned int);
+ va_end(args);
+
+ return real32_call_asm(&real_stack.sp, &real_stack.arg0, fn);
+}
+
+#ifdef CONFIG_64BIT
+/***************** 64-bit real-mode calls ***********/
+
+struct wide_stack {
+ unsigned long arg0;
+ unsigned long arg1;
+ unsigned long arg2;
+ unsigned long arg3;
+ unsigned long arg4;
+ unsigned long arg5;
+ unsigned long arg6;
+ unsigned long arg7;
+ unsigned long arg8;
+ unsigned long arg9;
+ unsigned long arg10;
+ unsigned long arg11;
+ unsigned long arg12;
+ unsigned long arg13;
+ unsigned long frame_marker[2]; /* rp, previous sp */
+ unsigned long sp;
+ /* in reality, there's nearly 8k of stack after this */
+};
+
+long real64_call(unsigned long fn, ...)
+{
+ va_list args;
+ extern struct wide_stack real64_stack;
+ extern unsigned long real64_call_asm(unsigned long *,
+ unsigned long *,
+ unsigned long);
+
+ va_start(args, fn);
+ real64_stack.arg0 = va_arg(args, unsigned long);
+ real64_stack.arg1 = va_arg(args, unsigned long);
+ real64_stack.arg2 = va_arg(args, unsigned long);
+ real64_stack.arg3 = va_arg(args, unsigned long);
+ real64_stack.arg4 = va_arg(args, unsigned long);
+ real64_stack.arg5 = va_arg(args, unsigned long);
+ real64_stack.arg6 = va_arg(args, unsigned long);
+ real64_stack.arg7 = va_arg(args, unsigned long);
+ real64_stack.arg8 = va_arg(args, unsigned long);
+ real64_stack.arg9 = va_arg(args, unsigned long);
+ real64_stack.arg10 = va_arg(args, unsigned long);
+ real64_stack.arg11 = va_arg(args, unsigned long);
+ real64_stack.arg12 = va_arg(args, unsigned long);
+ real64_stack.arg13 = va_arg(args, unsigned long);
+ va_end(args);
+
+ return real64_call_asm(&real64_stack.sp, &real64_stack.arg0, fn);
+}
+
+#endif /* CONFIG_64BIT */
diff --git a/arch/parisc/kernel/ftrace.c b/arch/parisc/kernel/ftrace.c
new file mode 100644
index 000000000..d1defb9ed
--- /dev/null
+++ b/arch/parisc/kernel/ftrace.c
@@ -0,0 +1,251 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Code for tracing calls in Linux kernel.
+ * Copyright (C) 2009-2016 Helge Deller <deller@gmx.de>
+ *
+ * based on code for x86 which is:
+ * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com>
+ *
+ * future possible enhancements:
+ * - add CONFIG_STACK_TRACER
+ */
+
+#include <linux/init.h>
+#include <linux/ftrace.h>
+#include <linux/uaccess.h>
+#include <linux/kprobes.h>
+#include <linux/ptrace.h>
+#include <linux/jump_label.h>
+
+#include <asm/assembly.h>
+#include <asm/sections.h>
+#include <asm/ftrace.h>
+#include <asm/patch.h>
+
+#define __hot __section(".text.hot")
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+static DEFINE_STATIC_KEY_FALSE(ftrace_graph_enable);
+
+/*
+ * Hook the return address and push it in the stack of return addrs
+ * in current thread info.
+ */
+static void __hot prepare_ftrace_return(unsigned long *parent,
+ unsigned long self_addr)
+{
+ unsigned long old;
+ extern int parisc_return_to_handler;
+
+ if (unlikely(ftrace_graph_is_dead()))
+ return;
+
+ if (unlikely(atomic_read(&current->tracing_graph_pause)))
+ return;
+
+ old = *parent;
+
+ if (!function_graph_enter(old, self_addr, 0, NULL))
+ /* activate parisc_return_to_handler() as return point */
+ *parent = (unsigned long) &parisc_return_to_handler;
+}
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+
+static ftrace_func_t ftrace_func;
+
+asmlinkage void notrace __hot ftrace_function_trampoline(unsigned long parent,
+ unsigned long self_addr,
+ unsigned long org_sp_gr3,
+ struct ftrace_regs *fregs)
+{
+ extern struct ftrace_ops *function_trace_op;
+
+ ftrace_func(self_addr, parent, function_trace_op, fregs);
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ if (static_branch_unlikely(&ftrace_graph_enable)) {
+ unsigned long *parent_rp;
+
+ /* calculate pointer to %rp in stack */
+ parent_rp = (unsigned long *) (org_sp_gr3 - RP_OFFSET);
+ /* sanity check: parent_rp should hold parent */
+ if (*parent_rp != parent)
+ return;
+
+ prepare_ftrace_return(parent_rp, self_addr);
+ return;
+ }
+#endif
+}
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+int ftrace_enable_ftrace_graph_caller(void)
+{
+ static_key_enable(&ftrace_graph_enable.key);
+ return 0;
+}
+
+int ftrace_disable_ftrace_graph_caller(void)
+{
+ static_key_enable(&ftrace_graph_enable.key);
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_DYNAMIC_FTRACE
+int ftrace_update_ftrace_func(ftrace_func_t func)
+{
+ ftrace_func = func;
+ return 0;
+}
+
+int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
+ unsigned long addr)
+{
+ return 0;
+}
+
+unsigned long ftrace_call_adjust(unsigned long addr)
+{
+ return addr+(FTRACE_PATCHABLE_FUNCTION_SIZE-1)*4;
+}
+
+int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
+{
+ u32 insn[FTRACE_PATCHABLE_FUNCTION_SIZE];
+ u32 *tramp;
+ int size, ret, i;
+ void *ip;
+
+#ifdef CONFIG_64BIT
+ unsigned long addr2 =
+ (unsigned long)dereference_function_descriptor((void *)addr);
+
+ u32 ftrace_trampoline[] = {
+ 0x73c10208, /* std,ma r1,100(sp) */
+ 0x0c2110c1, /* ldd -10(r1),r1 */
+ 0xe820d002, /* bve,n (r1) */
+ addr2 >> 32,
+ addr2 & 0xffffffff,
+ 0xe83f1fd7, /* b,l,n .-14,r1 */
+ };
+
+ u32 ftrace_trampoline_unaligned[] = {
+ addr2 >> 32,
+ addr2 & 0xffffffff,
+ 0x37de0200, /* ldo 100(sp),sp */
+ 0x73c13e01, /* std r1,-100(sp) */
+ 0x34213ff9, /* ldo -4(r1),r1 */
+ 0x50213fc1, /* ldd -20(r1),r1 */
+ 0xe820d002, /* bve,n (r1) */
+ 0xe83f1fcf, /* b,l,n .-20,r1 */
+ };
+
+ BUILD_BUG_ON(ARRAY_SIZE(ftrace_trampoline_unaligned) >
+ FTRACE_PATCHABLE_FUNCTION_SIZE);
+#else
+ u32 ftrace_trampoline[] = {
+ (u32)addr,
+ 0x6fc10080, /* stw,ma r1,40(sp) */
+ 0x48213fd1, /* ldw -18(r1),r1 */
+ 0xe820c002, /* bv,n r0(r1) */
+ 0xe83f1fdf, /* b,l,n .-c,r1 */
+ };
+#endif
+
+ BUILD_BUG_ON(ARRAY_SIZE(ftrace_trampoline) >
+ FTRACE_PATCHABLE_FUNCTION_SIZE);
+
+ size = sizeof(ftrace_trampoline);
+ tramp = ftrace_trampoline;
+
+#ifdef CONFIG_64BIT
+ if (rec->ip & 0x4) {
+ size = sizeof(ftrace_trampoline_unaligned);
+ tramp = ftrace_trampoline_unaligned;
+ }
+#endif
+
+ ip = (void *)(rec->ip + 4 - size);
+
+ ret = copy_from_kernel_nofault(insn, ip, size);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < size / 4; i++) {
+ if (insn[i] != INSN_NOP)
+ return -EINVAL;
+ }
+
+ __patch_text_multiple(ip, tramp, size);
+ return 0;
+}
+
+int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
+ unsigned long addr)
+{
+ u32 insn[FTRACE_PATCHABLE_FUNCTION_SIZE];
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(insn); i++)
+ insn[i] = INSN_NOP;
+
+ __patch_text((void *)rec->ip, INSN_NOP);
+ __patch_text_multiple((void *)rec->ip + 4 - sizeof(insn),
+ insn, sizeof(insn)-4);
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_KPROBES_ON_FTRACE
+void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
+ struct ftrace_ops *ops, struct ftrace_regs *fregs)
+{
+ struct kprobe_ctlblk *kcb;
+ struct pt_regs *regs;
+ struct kprobe *p;
+ int bit;
+
+ bit = ftrace_test_recursion_trylock(ip, parent_ip);
+ if (bit < 0)
+ return;
+
+ regs = ftrace_get_regs(fregs);
+ p = get_kprobe((kprobe_opcode_t *)ip);
+ if (unlikely(!p) || kprobe_disabled(p))
+ goto out;
+
+ if (kprobe_running()) {
+ kprobes_inc_nmissed_count(p);
+ goto out;
+ }
+
+ __this_cpu_write(current_kprobe, p);
+
+ kcb = get_kprobe_ctlblk();
+ kcb->kprobe_status = KPROBE_HIT_ACTIVE;
+
+ regs->iaoq[0] = ip;
+ regs->iaoq[1] = ip + 4;
+
+ if (!p->pre_handler || !p->pre_handler(p, regs)) {
+ regs->iaoq[0] = ip + 4;
+ regs->iaoq[1] = ip + 8;
+
+ if (unlikely(p->post_handler)) {
+ kcb->kprobe_status = KPROBE_HIT_SSDONE;
+ p->post_handler(p, regs, 0);
+ }
+ }
+ __this_cpu_write(current_kprobe, NULL);
+out:
+ ftrace_test_recursion_unlock(bit);
+}
+NOKPROBE_SYMBOL(kprobe_ftrace_handler);
+
+int arch_prepare_kprobe_ftrace(struct kprobe *p)
+{
+ p->ainsn.insn = NULL;
+ return 0;
+}
+#endif
diff --git a/arch/parisc/kernel/hardware.c b/arch/parisc/kernel/hardware.c
new file mode 100644
index 000000000..357d9cdab
--- /dev/null
+++ b/arch/parisc/kernel/hardware.c
@@ -0,0 +1,1374 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Hardware descriptions for HP 9000 based hardware, including
+ * system types, SCSI controllers, DMA controllers, HPPB controllers
+ * and lots more.
+ *
+ * Based on the document "PA-RISC 1.1 I/O Firmware Architecture
+ * Reference Specification", March 7, 1999, version 0.96. This
+ * is available at
+ * https://parisc.wiki.kernel.org/index.php/Technical_Documentation
+ *
+ * Copyright 1999 by Alex deVries <alex@onefishtwo.ca>
+ * and copyright 1999 The Puffin Group Inc.
+ */
+
+
+#include <asm/hardware.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+/*
+ * HP PARISC Hardware Database
+ * Access to this database is only possible during bootup
+ * so don't reference this table after starting the init process
+ */
+
+static struct hp_hardware hp_hardware_list[] __initdata = {
+ {HPHW_NPROC,0x01,0x4,0x0,"Indigo (840, 930)"},
+ {HPHW_NPROC,0x8,0x4,0x01,"Firefox(825,925)"},
+ {HPHW_NPROC,0xA,0x4,0x01,"Top Gun (835,834,935,635)"},
+ {HPHW_NPROC,0xB,0x4,0x01,"Technical Shogun (845, 645)"},
+ {HPHW_NPROC,0xF,0x4,0x01,"Commercial Shogun (949)"},
+ {HPHW_NPROC,0xC,0x4,0x01,"Cheetah (850, 950)"},
+ {HPHW_NPROC,0x80,0x4,0x01,"Cheetah (950S)"},
+ {HPHW_NPROC,0x81,0x4,0x01,"Jaguar (855, 955)"},
+ {HPHW_NPROC,0x82,0x4,0x01,"Cougar (860, 960)"},
+ {HPHW_NPROC,0x83,0x4,0x13,"Panther (865, 870, 980)"},
+ {HPHW_NPROC,0x100,0x4,0x01,"Burgundy (810)"},
+ {HPHW_NPROC,0x101,0x4,0x01,"SilverFox Low (822, 922)"},
+ {HPHW_NPROC,0x102,0x4,0x01,"SilverFox High (832, 932)"},
+ {HPHW_NPROC,0x103,0x4,0x01,"Lego, SilverLite (815, 808, 920)"},
+ {HPHW_NPROC,0x104,0x4,0x03,"SilverBullet Low (842, 948)"},
+ {HPHW_NPROC,0x105,0x4,0x03,"SilverBullet High (852, 958)"},
+ {HPHW_NPROC,0x106,0x4,0x81,"Oboe"},
+ {HPHW_NPROC,0x180,0x4,0x12,"Dragon"},
+ {HPHW_NPROC,0x181,0x4,0x13,"Chimera (890, 990, 992)"},
+ {HPHW_NPROC,0x182,0x4,0x91,"TNT 100 (891,T500)"},
+ {HPHW_NPROC,0x183,0x4,0x91,"TNT 120 (892,T520)"},
+ {HPHW_NPROC,0x184,0x4,0x91,"Jade 180 U (893,T540)"},
+ {HPHW_NPROC,0x1FF,0x4,0x91,"Hitachi X Processor"},
+ {HPHW_NPROC,0x200,0x4,0x81,"Cobra (720)"},
+ {HPHW_NPROC,0x201,0x4,0x81,"Coral (750)"},
+ {HPHW_NPROC,0x202,0x4,0x81,"King Cobra (730)"},
+ {HPHW_NPROC,0x203,0x4,0x81,"Hardball (735/99)"},
+ {HPHW_NPROC,0x204,0x4,0x81,"Coral II (755/99)"},
+ {HPHW_NPROC,0x205,0x4,0x81,"Coral II (755/125)"},
+ {HPHW_NPROC,0x205,0x4,0x91,"Snake Eagle "},
+ {HPHW_NPROC,0x206,0x4,0x81,"Snake Cheetah (735/130)"},
+ {HPHW_NPROC,0x280,0x4,0x81,"Nova Low (817, 827, 957, 957LX)"},
+ {HPHW_NPROC,0x281,0x4,0x81,"Nova High (837, 847, 857, 967, 967LX)"},
+ {HPHW_NPROC,0x282,0x4,0x81,"Nova8 (807, 917, 917LX, 927,927LX, 937, 937LX, 947,947LX)"},
+ {HPHW_NPROC,0x283,0x4,0x81,"Nova64 (867, 877, 977)"},
+ {HPHW_NPROC,0x284,0x4,0x81,"TNova (887, 897, 987)"},
+ {HPHW_NPROC,0x285,0x4,0x81,"TNova64"},
+ {HPHW_NPROC,0x286,0x4,0x91,"Hydra64 (Nova)"},
+ {HPHW_NPROC,0x287,0x4,0x91,"Hydra96 (Nova)"},
+ {HPHW_NPROC,0x288,0x4,0x81,"TNova96"},
+ {HPHW_NPROC,0x300,0x4,0x81,"Bushmaster (710)"},
+ {HPHW_NPROC,0x302,0x4,0x81,"Flounder (705)"},
+ {HPHW_NPROC,0x310,0x4,0x81,"Scorpio (715/50)"},
+ {HPHW_NPROC,0x311,0x4,0x81,"Scorpio Jr.(715/33)"},
+ {HPHW_NPROC,0x312,0x4,0x81,"Strider-50 (715S/50)"},
+ {HPHW_NPROC,0x313,0x4,0x81,"Strider-33 (715S/33)"},
+ {HPHW_NPROC,0x314,0x4,0x81,"Trailways-50 (715T/50)"},
+ {HPHW_NPROC,0x315,0x4,0x81,"Trailways-33 (715T/33)"},
+ {HPHW_NPROC,0x316,0x4,0x81,"Scorpio Sr.(715/75)"},
+ {HPHW_NPROC,0x317,0x4,0x81,"Scorpio 100 (715/100)"},
+ {HPHW_NPROC,0x318,0x4,0x81,"Spectra (725/50)"},
+ {HPHW_NPROC,0x319,0x4,0x81,"Spectra (725/75)"},
+ {HPHW_NPROC,0x320,0x4,0x81,"Spectra (725/100)"},
+ {HPHW_NPROC,0x401,0x4,0x81,"Pace (745i, 747i)"},
+ {HPHW_NPROC,0x402,0x4,0x81,"Sidewinder (742i)"},
+ {HPHW_NPROC,0x403,0x4,0x81,"Fast Pace"},
+ {HPHW_NPROC,0x480,0x4,0x81,"Orville (E23)"},
+ {HPHW_NPROC,0x481,0x4,0x81,"Wilbur (E25)"},
+ {HPHW_NPROC,0x482,0x4,0x81,"WB-80 (E35)"},
+ {HPHW_NPROC,0x483,0x4,0x81,"WB-96 (E45)"},
+ {HPHW_NPROC,0x484,0x4,0x81,"UL Proc L-100 (811/D210,D310)"},
+ {HPHW_NPROC,0x485,0x4,0x81,"UL Proc L-75 (801/D200)"},
+ {HPHW_NPROC,0x501,0x4,0x81,"Merlin L2 132 (9000/778/B132L)"},
+ {HPHW_NPROC,0x502,0x4,0x81,"Merlin L2 160 (9000/778/B160L)"},
+ {HPHW_NPROC,0x503,0x4,0x81,"Merlin L2+ 132 (9000/778/B132L)"},
+ {HPHW_NPROC,0x504,0x4,0x81,"Merlin L2+ 180 (9000/778/B180L)"},
+ {HPHW_NPROC,0x505,0x4,0x81,"Raven L2 132 (9000/778/C132L)"},
+ {HPHW_NPROC,0x506,0x4,0x81,"Raven L2 160 (9000/779/C160L)"},
+ {HPHW_NPROC,0x507,0x4,0x81,"Raven L2 180 (9000/779/C180L)"},
+ {HPHW_NPROC,0x508,0x4,0x81,"Raven L2 160 (9000/779/C160L)"},
+ {HPHW_NPROC,0x509,0x4,0x81,"712/132 L2 Upgrade"},
+ {HPHW_NPROC,0x50A,0x4,0x81,"712/160 L2 Upgrade"},
+ {HPHW_NPROC,0x50B,0x4,0x81,"715/132 L2 Upgrade"},
+ {HPHW_NPROC,0x50C,0x4,0x81,"715/160 L2 Upgrade"},
+ {HPHW_NPROC,0x50D,0x4,0x81,"Rocky2 L2 120"},
+ {HPHW_NPROC,0x50E,0x4,0x81,"Rocky2 L2 150"},
+ {HPHW_NPROC,0x50F,0x4,0x81,"Anole L2 132 (744)"},
+ {HPHW_NPROC,0x510,0x4,0x81,"Anole L2 165 (744)"},
+ {HPHW_NPROC,0x511,0x4,0x81,"Kiji L2 132"},
+ {HPHW_NPROC,0x512,0x4,0x81,"UL L2 132 (803/D220,D320)"},
+ {HPHW_NPROC,0x513,0x4,0x81,"UL L2 160 (813/D220,D320)"},
+ {HPHW_NPROC,0x514,0x4,0x81,"Merlin Jr L2 132"},
+ {HPHW_NPROC,0x515,0x4,0x81,"Staccato L2 132"},
+ {HPHW_NPROC,0x516,0x4,0x81,"Staccato L2 180 (A Class 180)"},
+ {HPHW_NPROC,0x580,0x4,0x81,"KittyHawk DC2-100 (K100)"},
+ {HPHW_NPROC,0x581,0x4,0x91,"KittyHawk DC3-120 (K210)"},
+ {HPHW_NPROC,0x582,0x4,0x91,"KittyHawk DC3 100 (K400)"},
+ {HPHW_NPROC,0x583,0x4,0x91,"KittyHawk DC3 120 (K410)"},
+ {HPHW_NPROC,0x584,0x4,0x91,"LighteningHawk T120"},
+ {HPHW_NPROC,0x585,0x4,0x91,"SkyHawk 100"},
+ {HPHW_NPROC,0x586,0x4,0x91,"SkyHawk 120"},
+ {HPHW_NPROC,0x587,0x4,0x81,"UL Proc 1-way T'120"},
+ {HPHW_NPROC,0x588,0x4,0x91,"UL Proc 2-way T'120"},
+ {HPHW_NPROC,0x589,0x4,0x81,"UL Proc 1-way T'100 (821/D250,D350)"},
+ {HPHW_NPROC,0x58A,0x4,0x91,"UL Proc 2-way T'100 (831/D250,D350)"},
+ {HPHW_NPROC,0x58B,0x4,0x91,"KittyHawk DC2 100 (K200)"},
+ {HPHW_NPROC,0x58C,0x4,0x91,"ThunderHawk DC3- 120 1M (K220)"},
+ {HPHW_NPROC,0x58D,0x4,0x91,"ThunderHawk DC3 120 1M (K420)"},
+ {HPHW_NPROC,0x58E,0x4,0x81,"Raven 120 T'"},
+ {HPHW_NPROC,0x58F,0x4,0x91,"Mohawk 160 U 1M DC3 (K450)"},
+ {HPHW_NPROC,0x590,0x4,0x91,"Mohawk 180 U 1M DC3 (K460)"},
+ {HPHW_NPROC,0x591,0x4,0x91,"Mohawk 200 U 1M DC3"},
+ {HPHW_NPROC,0x592,0x4,0x81,"Raven 100 T'"},
+ {HPHW_NPROC,0x593,0x4,0x91,"FireHawk 160 U"},
+ {HPHW_NPROC,0x594,0x4,0x91,"FireHawk 180 U"},
+ {HPHW_NPROC,0x595,0x4,0x91,"FireHawk 220 U"},
+ {HPHW_NPROC,0x596,0x4,0x91,"FireHawk 240 U"},
+ {HPHW_NPROC,0x597,0x4,0x91,"SPP2000 processor"},
+ {HPHW_NPROC,0x598,0x4,0x81,"Raven U 230 (9000/780/C230)"},
+ {HPHW_NPROC,0x599,0x4,0x81,"Raven U 240 (9000/780/C240)"},
+ {HPHW_NPROC,0x59A,0x4,0x91,"Unlisted but reserved"},
+ {HPHW_NPROC,0x59A,0x4,0x81,"Unlisted but reserved"},
+ {HPHW_NPROC,0x59B,0x4,0x81,"Raven U 160 (9000/780/C160)"},
+ {HPHW_NPROC,0x59C,0x4,0x81,"Raven U 180 (9000/780/C180)"},
+ {HPHW_NPROC,0x59D,0x4,0x81,"Raven U 200 (9000/780/C200)"},
+ {HPHW_NPROC,0x59E,0x4,0x91,"ThunderHawk T' 120"},
+ {HPHW_NPROC,0x59F,0x4,0x91,"Raven U 180+ (9000/780)"},
+ {HPHW_NPROC,0x5A0,0x4,0x81,"UL 1w T120 1MB/1MB (841/D260,D360)"},
+ {HPHW_NPROC,0x5A1,0x4,0x91,"UL 2w T120 1MB/1MB (851/D260,D360)"},
+ {HPHW_NPROC,0x5A2,0x4,0x81,"UL 1w U160 512K/512K (861/D270,D370)"},
+ {HPHW_NPROC,0x5A3,0x4,0x91,"UL 2w U160 512K/512K (871/D270,D370)"},
+ {HPHW_NPROC,0x5A4,0x4,0x91,"Mohawk 160 U 1M DC3- (K250)"},
+ {HPHW_NPROC,0x5A5,0x4,0x91,"Mohawk 180 U 1M DC3- (K260)"},
+ {HPHW_NPROC,0x5A6,0x4,0x91,"Mohawk 200 U 1M DC3-"},
+ {HPHW_NPROC,0x5A7,0x4,0x81,"UL proc 1-way U160 1M/1M"},
+ {HPHW_NPROC,0x5A8,0x4,0x91,"UL proc 2-way U160 1M/1M"},
+ {HPHW_NPROC,0x5A9,0x4,0x81,"UL proc 1-way U180 1M/1M"},
+ {HPHW_NPROC,0x5AA,0x4,0x91,"UL proc 2-way U180 1M/1M"},
+ {HPHW_NPROC,0x5AB,0x4,0x91,"Obsolete"},
+ {HPHW_NPROC,0x5AB,0x4,0x81,"Obsolete"},
+ {HPHW_NPROC,0x5AC,0x4,0x91,"Obsolete"},
+ {HPHW_NPROC,0x5AC,0x4,0x81,"Obsolete"},
+ {HPHW_NPROC,0x5AD,0x4,0x91,"BraveHawk 180MHz DC3-"},
+ {HPHW_NPROC,0x5AE,0x4,0x91,"BraveHawk 200MHz DC3- (898/K370)"},
+ {HPHW_NPROC,0x5AF,0x4,0x91,"BraveHawk 220MHz DC3-"},
+ {HPHW_NPROC,0x5B0,0x4,0x91,"BraveHawk 180MHz DC3"},
+ {HPHW_NPROC,0x5B1,0x4,0x91,"BraveHawk 200MHz DC3 (899/K570)"},
+ {HPHW_NPROC,0x5B2,0x4,0x91,"BraveHawk 220MHz DC3"},
+ {HPHW_NPROC,0x5B3,0x4,0x91,"FireHawk 200"},
+ {HPHW_NPROC,0x5B4,0x4,0x91,"SPP2500"},
+ {HPHW_NPROC,0x5B5,0x4,0x91,"SummitHawk U+"},
+ {HPHW_NPROC,0x5B6,0x4,0x91,"DragonHawk U+ 240 DC3"},
+ {HPHW_NPROC,0x5B7,0x4,0x91,"DragonHawk U+ 240 DC3-"},
+ {HPHW_NPROC,0x5B8,0x4,0x91,"SPP2250 240 MHz"},
+ {HPHW_NPROC,0x5B9,0x4,0x81,"UL 1w U+/240 (350/550)"},
+ {HPHW_NPROC,0x5BA,0x4,0x91,"UL 2w U+/240 (350/550)"},
+ {HPHW_NPROC,0x5BB,0x4,0x81,"AllegroHigh W"},
+ {HPHW_NPROC,0x5BC,0x4,0x91,"AllegroLow W"},
+ {HPHW_NPROC,0x5BD,0x4,0x91,"Forte W 2-way"},
+ {HPHW_NPROC,0x5BE,0x4,0x91,"Prelude W"},
+ {HPHW_NPROC,0x5BF,0x4,0x91,"Forte W 4-way"},
+ {HPHW_NPROC,0x5C0,0x4,0x91,"M2250"},
+ {HPHW_NPROC,0x5C1,0x4,0x91,"M2500"},
+ {HPHW_NPROC,0x5C2,0x4,0x91,"Sonata 440"},
+ {HPHW_NPROC,0x5C3,0x4,0x91,"Sonata 360"},
+ {HPHW_NPROC,0x5C4,0x4,0x91,"Rhapsody 440"},
+ {HPHW_NPROC,0x5C5,0x4,0x91,"Rhapsody 360"},
+ {HPHW_NPROC,0x5C6,0x4,0x91,"Raven W 360 (9000/780)"},
+ {HPHW_NPROC,0x5C7,0x4,0x91,"Halfdome W 440"},
+ {HPHW_NPROC,0x5C8,0x4,0x81,"Lego 360 processor"},
+ {HPHW_NPROC,0x5C9,0x4,0x91,"Rhapsody DC- 440"},
+ {HPHW_NPROC,0x5CA,0x4,0x91,"Rhapsody DC- 360"},
+ {HPHW_NPROC,0x5CB,0x4,0x91,"Crescendo 440"},
+ {HPHW_NPROC,0x5CC,0x4,0x91,"Prelude W 440"},
+ {HPHW_NPROC,0x5CD,0x4,0x91,"SPP2600"},
+ {HPHW_NPROC,0x5CE,0x4,0x91,"M2600"},
+ {HPHW_NPROC,0x5CF,0x4,0x81,"Allegro W+"},
+ {HPHW_NPROC,0x5D0,0x4,0x81,"Kazoo W+"},
+ {HPHW_NPROC,0x5D1,0x4,0x91,"Forte W+ 2w"},
+ {HPHW_NPROC,0x5D2,0x4,0x91,"Forte W+ 4w"},
+ {HPHW_NPROC,0x5D3,0x4,0x91,"Prelude W+ 540"},
+ {HPHW_NPROC,0x5D4,0x4,0x91,"Duet W+"},
+ {HPHW_NPROC,0x5D5,0x4,0x91,"Crescendo 550"},
+ {HPHW_NPROC,0x5D6,0x4,0x81,"Crescendo DC- 440"},
+ {HPHW_NPROC,0x5D7,0x4,0x91,"Keystone W+"},
+ {HPHW_NPROC,0x5D8,0x4,0x91,"Rhapsody wave 2 W+ DC-"},
+ {HPHW_NPROC,0x5D9,0x4,0x91,"Rhapsody wave 2 W+"},
+ {HPHW_NPROC,0x5DA,0x4,0x91,"Marcato W+ DC-"},
+ {HPHW_NPROC,0x5DB,0x4,0x91,"Marcato W+"},
+ {HPHW_NPROC,0x5DC,0x4,0x91,"Allegro W2"},
+ {HPHW_NPROC,0x5DD,0x4,0x81,"Duet W2"},
+ {HPHW_NPROC,0x5DE,0x4,0x81,"Piccolo W+"},
+ {HPHW_NPROC,0x5DF,0x4,0x81,"Cantata W2"},
+ {HPHW_NPROC,0x5DF,0x0,0x00,"Marcato W+ (rp5470)"},
+ {HPHW_NPROC,0x5E0,0x4,0x91,"Cantata DC- W2"},
+ {HPHW_NPROC,0x5E1,0x4,0x91,"Crescendo DC- W2"},
+ {HPHW_NPROC,0x5E2,0x4,0x91,"Crescendo 650 W2"},
+ {HPHW_NPROC,0x5E3,0x4,0x91,"Crescendo 750 W2"},
+ {HPHW_NPROC,0x5E4,0x4,0x91,"Keystone/Matterhorn W2 750"},
+ {HPHW_NPROC,0x5E5,0x4,0x91,"PowerBar W+"},
+ {HPHW_NPROC,0x5E6,0x4,0x91,"Keystone/Matterhorn W2 650"},
+ {HPHW_NPROC,0x5E7,0x4,0x91,"Caribe W2 800"},
+ {HPHW_NPROC,0x5E8,0x4,0x91,"Pikes Peak W2"},
+ {HPHW_NPROC,0x5EB,0x4,0x91,"Perf/Leone 875 W2+"},
+ {HPHW_NPROC,0x5FF,0x4,0x91,"Hitachi W"},
+ {HPHW_NPROC,0x600,0x4,0x81,"Gecko (712/60)"},
+ {HPHW_NPROC,0x601,0x4,0x81,"Gecko 80 (712/80)"},
+ {HPHW_NPROC,0x602,0x4,0x81,"Gecko 100 (712/100)"},
+ {HPHW_NPROC,0x603,0x4,0x81,"Anole 64 (743/64)"},
+ {HPHW_NPROC,0x604,0x4,0x81,"Anole 100 (743/100)"},
+ {HPHW_NPROC,0x605,0x4,0x81,"Gecko 120 (712/120)"},
+ {HPHW_NPROC,0x606,0x4,0x81,"Gila 80"},
+ {HPHW_NPROC,0x607,0x4,0x81,"Gila 100"},
+ {HPHW_NPROC,0x608,0x4,0x81,"Gila 120"},
+ {HPHW_NPROC,0x609,0x4,0x81,"Scorpio-L 80"},
+ {HPHW_NPROC,0x60A,0x4,0x81,"Mirage Jr (715/64)"},
+ {HPHW_NPROC,0x60B,0x4,0x81,"Mirage 100"},
+ {HPHW_NPROC,0x60C,0x4,0x81,"Mirage 100+"},
+ {HPHW_NPROC,0x60D,0x4,0x81,"Electra 100"},
+ {HPHW_NPROC,0x60E,0x4,0x81,"Electra 120"},
+ {HPHW_NPROC,0x610,0x4,0x81,"Scorpio-L 100"},
+ {HPHW_NPROC,0x611,0x4,0x81,"Scorpio-L 120"},
+ {HPHW_NPROC,0x612,0x4,0x81,"Spectra-L 80"},
+ {HPHW_NPROC,0x613,0x4,0x81,"Spectra-L 100"},
+ {HPHW_NPROC,0x614,0x4,0x81,"Spectra-L 120"},
+ {HPHW_NPROC,0x615,0x4,0x81,"Piranha 100"},
+ {HPHW_NPROC,0x616,0x4,0x81,"Piranha 120"},
+ {HPHW_NPROC,0x617,0x4,0x81,"Jason 50"},
+ {HPHW_NPROC,0x618,0x4,0x81,"Jason 100"},
+ {HPHW_NPROC,0x619,0x4,0x81,"Mirage 80"},
+ {HPHW_NPROC,0x61A,0x4,0x81,"SAIC L-80"},
+ {HPHW_NPROC,0x61B,0x4,0x81,"Rocky1 L-60"},
+ {HPHW_NPROC,0x61C,0x4,0x81,"Anole T (743/T)"},
+ {HPHW_NPROC,0x67E,0x4,0x81,"Hitachi Tiny 80"},
+ {HPHW_NPROC,0x67F,0x4,0x81,"Hitachi Tiny 64"},
+ {HPHW_NPROC,0x700,0x4,0x91,"NEC Aska Processor"},
+ {HPHW_NPROC,0x880,0x4,0x91,"Orca Mako"},
+ {HPHW_NPROC,0x881,0x4,0x91,"Everest Mako"},
+ {HPHW_NPROC,0x882,0x4,0x91,"Rainier/Medel Mako Slow"},
+ {HPHW_NPROC,0x883,0x4,0x91,"Rainier/Medel Mako Fast"},
+ {HPHW_NPROC,0x884,0x4,0x91,"Mt. Hamilton"},
+ {HPHW_NPROC,0x885,0x4,0x91,"Mt. Hamilton DC-"},
+ {HPHW_NPROC,0x886,0x4,0x91,"Storm Peak Slow DC-"},
+ {HPHW_NPROC,0x887,0x4,0x91,"Storm Peak Slow"},
+ {HPHW_NPROC,0x888,0x4,0x91,"Storm Peak Fast DC-"},
+ {HPHW_NPROC,0x889,0x4,0x91,"Storm Peak Fast"},
+ {HPHW_NPROC,0x88A,0x4,0x91,"Crestone Peak Slow"},
+ {HPHW_NPROC,0x88B,0x4,0x91,"Crestone Peak Fast"},
+ {HPHW_NPROC,0x88C,0x4,0x91,"Orca Mako+"},
+ {HPHW_NPROC,0x88D,0x4,0x91,"Rainier/Medel Mako+ Slow"},
+ {HPHW_NPROC,0x88E,0x4,0x91,"Rainier/Medel Mako+ Fast"},
+ {HPHW_NPROC,0x892,0x4,0x91,"Mt. Hamilton Slow Mako+"},
+ {HPHW_NPROC,0x894,0x4,0x91,"Mt. Hamilton Fast Mako+"},
+ {HPHW_NPROC,0x895,0x4,0x91,"Storm Peak Slow Mako+"},
+ {HPHW_NPROC,0x896,0x4,0x91,"Storm Peak Fast Mako+"},
+ {HPHW_NPROC,0x897,0x4,0x91,"Storm Peak DC- Slow Mako+"},
+ {HPHW_NPROC,0x898,0x4,0x91,"Storm Peak DC- Fast Mako+"},
+ {HPHW_NPROC,0x899,0x4,0x91,"Mt. Hamilton Slow Mako+"},
+ {HPHW_NPROC,0x89B,0x4,0x91,"Crestone Peak Mako+ Slow"},
+ {HPHW_NPROC,0x89C,0x4,0x91,"Crestone Peak Mako+ Fast"},
+ {HPHW_A_DIRECT, 0x004, 0x0000D, 0x00, "Arrakis MUX"},
+ {HPHW_A_DIRECT, 0x005, 0x0000D, 0x00, "Dyun Kiuh MUX"},
+ {HPHW_A_DIRECT, 0x006, 0x0000D, 0x00, "Baat Kiuh AP/MUX (40299B)"},
+ {HPHW_A_DIRECT, 0x007, 0x0000D, 0x00, "Dino AP"},
+ {HPHW_A_DIRECT, 0x009, 0x0000D, 0x00, "Solaris Direct Connect MUX (J2092A)"},
+ {HPHW_A_DIRECT, 0x00A, 0x0000D, 0x00, "Solaris RS-422/423 MUX (J2093A)"},
+ {HPHW_A_DIRECT, 0x00B, 0x0000D, 0x00, "Solaris RS-422/423 Quadriloops MUX"},
+ {HPHW_A_DIRECT, 0x00C, 0x0000D, 0x00, "Solaris Modem MUX (J2094A)"},
+ {HPHW_A_DIRECT, 0x00D, 0x0000D, 0x00, "Twins Direct Connect MUX"},
+ {HPHW_A_DIRECT, 0x00E, 0x0000D, 0x00, "Twins Modem MUX"},
+ {HPHW_A_DIRECT, 0x00F, 0x0000D, 0x00, "Nautilus RS-485"},
+ {HPHW_A_DIRECT, 0x010, 0x0000D, 0x00, "UltraLight CAP/MUX"},
+ {HPHW_A_DIRECT, 0x015, 0x0000D, 0x00, "Eole CAP/MUX"},
+ {HPHW_A_DIRECT, 0x024, 0x0000D, 0x00, "Sahp Kiuh AP/MUX"},
+ {HPHW_A_DIRECT, 0x034, 0x0000D, 0x00, "Sahp Kiuh Low AP/MUX"},
+ {HPHW_A_DIRECT, 0x044, 0x0000D, 0x00, "Sahp Baat Kiuh AP/MUX"},
+ {HPHW_A_DIRECT, 0x004, 0x0000E, 0x80, "Burgundy RS-232"},
+ {HPHW_A_DIRECT, 0x005, 0x0000E, 0x80, "Silverfox RS-232"},
+ {HPHW_A_DIRECT, 0x006, 0x0000E, 0x80, "Lego RS-232"},
+ {HPHW_A_DIRECT, 0x004, 0x0000F, 0x00, "Peacock Graphics"},
+ {HPHW_A_DIRECT, 0x004, 0x00014, 0x80, "Burgundy HIL"},
+ {HPHW_A_DIRECT, 0x005, 0x00014, 0x80, "Peacock HIL"},
+ {HPHW_A_DIRECT, 0x004, 0x00015, 0x80, "Leonardo"},
+ {HPHW_A_DIRECT, 0x004, 0x00016, 0x80, "HP-PB HRM"},
+ {HPHW_A_DIRECT, 0x004, 0x00017, 0x80, "HP-PB HRC"},
+ {HPHW_A_DIRECT, 0x004, 0x0003A, 0x80, "Skunk Centronics (28655A)"},
+ {HPHW_A_DIRECT, 0x024, 0x0003A, 0x80, "Sahp Kiuh Centronics"},
+ {HPHW_A_DIRECT, 0x044, 0x0003A, 0x80, "Sahp Baat Kiuh Centronics"},
+ {HPHW_A_DIRECT, 0x004, 0x0004E, 0x80, "AT&T DataKit (AMSO)"},
+ {HPHW_A_DIRECT, 0x004, 0x0009B, 0x80, "Test&Meas GSC HPIB"},
+ {HPHW_A_DIRECT, 0x004, 0x000A8, 0x00, "Rocky2-120 Front Keyboard"},
+ {HPHW_A_DIRECT, 0x005, 0x000A8, 0x00, "Rocky2-150 Front Keyboard"},
+ {HPHW_A_DIRECT, 0x004, 0x00101, 0x80, "Hitachi Console Module"},
+ {HPHW_A_DIRECT, 0x004, 0x00102, 0x80, "Hitachi Boot Module"},
+ {HPHW_A_DIRECT, 0x004, 0x00203, 0x80, "MELCO HBMLA MLAIT"},
+ {HPHW_A_DIRECT, 0x004, 0x00208, 0x80, "MELCO HBDPC"},
+ {HPHW_A_DIRECT, 0x004, 0x00300, 0x00, "DCI TWINAX TERM IO MUX"},
+ {HPHW_A_DMA, 0x004, 0x00039, 0x80, "Skunk SCSI (28655A)"},
+ {HPHW_A_DMA, 0x005, 0x00039, 0x80, "KittyHawk CSY Core SCSI"},
+ {HPHW_A_DMA, 0x014, 0x00039, 0x80, "Diablo SCSI"},
+ {HPHW_A_DMA, 0x024, 0x00039, 0x80, "Sahp Kiuh SCSI"},
+ {HPHW_A_DMA, 0x034, 0x00039, 0x80, "Sahp Kiuh Low SCSI"},
+ {HPHW_A_DMA, 0x044, 0x00039, 0x80, "Sahp Baat Kiuh SCSI"},
+ {HPHW_A_DMA, 0x004, 0x0003B, 0x80, "Wizard SCSI"},
+ {HPHW_A_DMA, 0x005, 0x0003B, 0x80, "KittyHawk CSY Core FW-SCSI"},
+ {HPHW_A_DMA, 0x006, 0x0003B, 0x80, "Symbios EPIC FW-SCSI"},
+ {HPHW_A_DMA, 0x004, 0x00040, 0x80, "HP-PB Shazam HPIB (28650A)"},
+ {HPHW_A_DMA, 0x005, 0x00040, 0x80, "Burgundy HPIB"},
+ {HPHW_A_DMA, 0x004, 0x00041, 0x80, "HP-PB HP-FL"},
+ {HPHW_A_DMA, 0x004, 0x00042, 0x80, "HP-PB LoQuix HPIB (28650B)"},
+ {HPHW_A_DMA, 0x004, 0x00043, 0x80, "HP-PB Crypt LoQuix"},
+ {HPHW_A_DMA, 0x004, 0x00044, 0x80, "HP-PB Shazam GPIO (28651A)"},
+ {HPHW_A_DMA, 0x004, 0x00045, 0x80, "HP-PB LoQuix GPIO"},
+ {HPHW_A_DMA, 0x004, 0x00046, 0x80, "2-Port X.25 NIO_ACC (AMSO)"},
+ {HPHW_A_DMA, 0x004, 0x00047, 0x80, "4-Port X.25 NIO_ACC (AMSO)"},
+ {HPHW_A_DMA, 0x004, 0x0004B, 0x80, "LGB Control"},
+ {HPHW_A_DMA, 0x004, 0x0004C, 0x80, "Martian RTI (AMSO)"},
+ {HPHW_A_DMA, 0x004, 0x0004D, 0x80, "ACC Mux (AMSO)"},
+ {HPHW_A_DMA, 0x004, 0x00050, 0x80, "Lanbrusca 802.3 (36967A)"},
+ {HPHW_A_DMA, 0x004, 0x00056, 0x80, "HP-PB LoQuix FDDI"},
+ {HPHW_A_DMA, 0x004, 0x00057, 0x80, "HP-PB LoQuix FDDI (28670A)"},
+ {HPHW_A_DMA, 0x004, 0x0005E, 0x00, "Gecko Add-on Token Ring"},
+ {HPHW_A_DMA, 0x012, 0x00089, 0x80, "Barracuda Add-on FW-SCSI"},
+ {HPHW_A_DMA, 0x013, 0x00089, 0x80, "Bluefish Add-on FW-SCSI"},
+ {HPHW_A_DMA, 0x014, 0x00089, 0x80, "Shrike Add-on FW-SCSI"},
+ {HPHW_A_DMA, 0x015, 0x00089, 0x80, "KittyHawk GSY Core FW-SCSI"},
+ {HPHW_A_DMA, 0x017, 0x00089, 0x80, "Shrike Jade Add-on FW-SCSI (A3644A)"},
+ {HPHW_A_DMA, 0x01F, 0x00089, 0x80, "SkyHawk 100/120 FW-SCSI"},
+ {HPHW_A_DMA, 0x027, 0x00089, 0x80, "Piranha 100 FW-SCSI"},
+ {HPHW_A_DMA, 0x032, 0x00089, 0x80, "Raven T' Core FW-SCSI"},
+ {HPHW_A_DMA, 0x03B, 0x00089, 0x80, "Raven U/L2 Core FW-SCSI"},
+ {HPHW_A_DMA, 0x03C, 0x00089, 0x80, "Merlin 132 Core FW-SCSI"},
+ {HPHW_A_DMA, 0x03D, 0x00089, 0x80, "Merlin 160 Core FW-SCSI"},
+ {HPHW_A_DMA, 0x044, 0x00089, 0x80, "Mohawk Core FW-SCSI"},
+ {HPHW_A_DMA, 0x051, 0x00089, 0x80, "Firehawk FW-SCSI"},
+ {HPHW_A_DMA, 0x058, 0x00089, 0x80, "FireHawk 200 FW-SCSI"},
+ {HPHW_A_DMA, 0x05C, 0x00089, 0x80, "SummitHawk 230 Ultra-SCSI"},
+ {HPHW_A_DMA, 0x014, 0x00091, 0x80, "Baby Hugo Add-on Net FC (A3406A)"},
+ {HPHW_A_DMA, 0x020, 0x00091, 0x80, "Baby Jade Add-on Net FC (A3638A)"},
+ {HPHW_A_DMA, 0x004, 0x00092, 0x80, "GSC+ YLIASTER ATM"},
+ {HPHW_A_DMA, 0x004, 0x00095, 0x80, "Hamlyn GSC+ Network Card"},
+ {HPHW_A_DMA, 0x004, 0x00098, 0x80, "Lo-fat Emulator"},
+ {HPHW_A_DMA, 0x004, 0x0009A, 0x80, "GSC+ Venus ATM"},
+ {HPHW_A_DMA, 0x005, 0x0009A, 0x80, "GSC+ Samorobrive ATM"},
+ {HPHW_A_DMA, 0x004, 0x0009D, 0x80, "HP HSC-PCI Cards"},
+ {HPHW_A_DMA, 0x004, 0x0009E, 0x80, "Alaxis GSC+ 155Mb ATM"},
+ {HPHW_A_DMA, 0x005, 0x0009E, 0x80, "Alaxis GSC+ 622Mb ATM"},
+ {HPHW_A_DMA, 0x05C, 0x0009F, 0x80, "SummitHawk 230 USB"},
+ {HPHW_A_DMA, 0x05C, 0x000A0, 0x80, "SummitHawk 230 100BaseT"},
+ {HPHW_A_DMA, 0x015, 0x000A7, 0x80, "Baby Hugo Add-on mass FC (A3404A)"},
+ {HPHW_A_DMA, 0x018, 0x000A7, 0x80, "Mombasa GS Add-on mass FC (A3591)"},
+ {HPHW_A_DMA, 0x021, 0x000A7, 0x80, "Baby Jade Add-on mass FC (A3636A)"},
+ {HPHW_A_DMA, 0x004, 0x00201, 0x80, "MELCO HCMAP"},
+ {HPHW_A_DMA, 0x004, 0x00202, 0x80, "MELCO HBMLA MLAMA"},
+ {HPHW_A_DMA, 0x004, 0x00205, 0x80, "MELCO HBRFU"},
+ {HPHW_A_DMA, 0x004, 0x00380, 0x80, "Interphase NIO-FC"},
+ {HPHW_A_DMA, 0x004, 0x00381, 0x80, "Interphase NIO-ATM"},
+ {HPHW_A_DMA, 0x004, 0x00382, 0x80, "Interphase NIO-100BaseTX"},
+ {HPHW_BA, 0x004, 0x00070, 0x0, "Cobra Core BA"},
+ {HPHW_BA, 0x005, 0x00070, 0x0, "Coral Core BA"},
+ {HPHW_BA, 0x006, 0x00070, 0x0, "Bushmaster Core BA"},
+ {HPHW_BA, 0x007, 0x00070, 0x0, "Scorpio Core BA"},
+ {HPHW_BA, 0x008, 0x00070, 0x0, "Flounder Core BA"},
+ {HPHW_BA, 0x009, 0x00070, 0x0, "Outfield Core BA"},
+ {HPHW_BA, 0x00A, 0x00070, 0x0, "CoralII Core BA"},
+ {HPHW_BA, 0x00B, 0x00070, 0x0, "Scorpio Jr. Core BA"},
+ {HPHW_BA, 0x00C, 0x00070, 0x0, "Strider-50 Core BA"},
+ {HPHW_BA, 0x00D, 0x00070, 0x0, "Strider-33 Core BA"},
+ {HPHW_BA, 0x00E, 0x00070, 0x0, "Trailways-50 Core BA"},
+ {HPHW_BA, 0x00F, 0x00070, 0x0, "Trailways-33 Core BA"},
+ {HPHW_BA, 0x010, 0x00070, 0x0, "Pace Core BA"},
+ {HPHW_BA, 0x011, 0x00070, 0x0, "Sidewinder Core BA"},
+ {HPHW_BA, 0x019, 0x00070, 0x0, "Scorpio Sr. Core BA"},
+ {HPHW_BA, 0x020, 0x00070, 0x0, "Scorpio 100 Core BA"},
+ {HPHW_BA, 0x021, 0x00070, 0x0, "Spectra 50 Core BA"},
+ {HPHW_BA, 0x022, 0x00070, 0x0, "Spectra 75 Core BA"},
+ {HPHW_BA, 0x023, 0x00070, 0x0, "Spectra 100 Core BA"},
+ {HPHW_BA, 0x024, 0x00070, 0x0, "Fast Pace Core BA"},
+ {HPHW_BA, 0x026, 0x00070, 0x0, "CoralII Jaguar Core BA"},
+ {HPHW_BA, 0x004, 0x00076, 0x0, "Cobra EISA BA"},
+ {HPHW_BA, 0x005, 0x00076, 0x0, "Coral EISA BA"},
+ {HPHW_BA, 0x007, 0x00076, 0x0, "Scorpio EISA BA"},
+ {HPHW_BA, 0x00A, 0x00076, 0x0, "CoralII EISA BA"},
+ {HPHW_BA, 0x00B, 0x00076, 0x0, "Scorpio Jr. EISA BA"},
+ {HPHW_BA, 0x00C, 0x00076, 0x0, "Strider-50 Core EISA"},
+ {HPHW_BA, 0x00D, 0x00076, 0x0, "Strider-33 Core EISA"},
+ {HPHW_BA, 0x00E, 0x00076, 0x0, "Trailways-50 Core EISA"},
+ {HPHW_BA, 0x00F, 0x00076, 0x0, "Trailways-33 Core EISA"},
+ {HPHW_BA, 0x010, 0x00076, 0x0, "Pace Core EISA"},
+ {HPHW_BA, 0x019, 0x00076, 0x0, "Scorpio Sr. EISA BA"},
+ {HPHW_BA, 0x020, 0x00076, 0x0, "Scorpio 100 EISA BA"},
+ {HPHW_BA, 0x021, 0x00076, 0x0, "Spectra 50 EISA BA"},
+ {HPHW_BA, 0x022, 0x00076, 0x0, "Spectra 75 EISA BA"},
+ {HPHW_BA, 0x023, 0x00076, 0x0, "Spectra 100 EISA BA"},
+ {HPHW_BA, 0x026, 0x00076, 0x0, "CoralII Jaguar EISA BA"},
+ {HPHW_BA, 0x010, 0x00078, 0x0, "Pace VME BA"},
+ {HPHW_BA, 0x011, 0x00078, 0x0, "Sidewinder VME BA"},
+ {HPHW_BA, 0x01A, 0x00078, 0x0, "Anole 64 VME BA"},
+ {HPHW_BA, 0x01B, 0x00078, 0x0, "Anole 100 VME BA"},
+ {HPHW_BA, 0x024, 0x00078, 0x0, "Fast Pace VME BA"},
+ {HPHW_BA, 0x034, 0x00078, 0x0, "Anole T VME BA"},
+ {HPHW_BA, 0x04A, 0x00078, 0x0, "Anole L2 132 VME BA"},
+ {HPHW_BA, 0x04C, 0x00078, 0x0, "Anole L2 165 VME BA"},
+ {HPHW_BA, 0x011, 0x00081, 0x0, "WB-96 Core BA"},
+ {HPHW_BA, 0x012, 0x00081, 0x0, "Orville UX Core BA"},
+ {HPHW_BA, 0x013, 0x00081, 0x0, "Wilbur UX Core BA"},
+ {HPHW_BA, 0x014, 0x00081, 0x0, "WB-80 Core BA"},
+ {HPHW_BA, 0x015, 0x00081, 0x0, "KittyHawk GSY Core BA"},
+ {HPHW_BA, 0x016, 0x00081, 0x0, "Gecko Core BA"},
+ {HPHW_BA, 0x018, 0x00081, 0x0, "Gecko Optional BA"},
+ {HPHW_BA, 0x01A, 0x00081, 0x0, "Anole 64 Core BA"},
+ {HPHW_BA, 0x01B, 0x00081, 0x0, "Anole 100 Core BA"},
+ {HPHW_BA, 0x01C, 0x00081, 0x0, "Gecko 80 Core BA"},
+ {HPHW_BA, 0x01D, 0x00081, 0x0, "Gecko 100 Core BA"},
+ {HPHW_BA, 0x01F, 0x00081, 0x0, "SkyHawk 100/120 Core BA"},
+ {HPHW_BA, 0x027, 0x00081, 0x0, "Piranha 100 Core BA"},
+ {HPHW_BA, 0x028, 0x00081, 0x0, "Mirage Jr Core BA"},
+ {HPHW_BA, 0x029, 0x00081, 0x0, "Mirage Core BA"},
+ {HPHW_BA, 0x02A, 0x00081, 0x0, "Electra Core BA"},
+ {HPHW_BA, 0x02B, 0x00081, 0x0, "Mirage 80 Core BA"},
+ {HPHW_BA, 0x02C, 0x00081, 0x0, "Mirage 100+ Core BA"},
+ {HPHW_BA, 0x02E, 0x00081, 0x0, "UL 350 Lasi Core BA"},
+ {HPHW_BA, 0x02F, 0x00081, 0x0, "UL 550 Lasi Core BA"},
+ {HPHW_BA, 0x032, 0x00081, 0x0, "Raven T' Core BA"},
+ {HPHW_BA, 0x033, 0x00081, 0x0, "Anole T Core BA"},
+ {HPHW_BA, 0x034, 0x00081, 0x0, "SAIC L-80 Core BA"},
+ {HPHW_BA, 0x035, 0x00081, 0x0, "PCX-L2 712/132 Core BA"},
+ {HPHW_BA, 0x036, 0x00081, 0x0, "PCX-L2 712/160 Core BA"},
+ {HPHW_BA, 0x03B, 0x00081, 0x0, "Raven U/L2 Core BA"},
+ {HPHW_BA, 0x03C, 0x00081, 0x0, "Merlin 132 Core BA"},
+ {HPHW_BA, 0x03D, 0x00081, 0x0, "Merlin 160 Core BA"},
+ {HPHW_BA, 0x03E, 0x00081, 0x0, "Merlin+ 132 Core BA"},
+ {HPHW_BA, 0x03F, 0x00081, 0x0, "Merlin+ 180 Core BA"},
+ {HPHW_BA, 0x044, 0x00081, 0x0, "Mohawk Core BA"},
+ {HPHW_BA, 0x045, 0x00081, 0x0, "Rocky1 Core BA"},
+ {HPHW_BA, 0x046, 0x00081, 0x0, "Rocky2 120 Core BA"},
+ {HPHW_BA, 0x047, 0x00081, 0x0, "Rocky2 150 Core BA"},
+ {HPHW_BA, 0x04B, 0x00081, 0x0, "Anole L2 132 Core BA"},
+ {HPHW_BA, 0x04D, 0x00081, 0x0, "Anole L2 165 Core BA"},
+ {HPHW_BA, 0x04E, 0x00081, 0x0, "Kiji L2 132 Core BA"},
+ {HPHW_BA, 0x050, 0x00081, 0x0, "Merlin Jr 132 Core BA"},
+ {HPHW_BA, 0x051, 0x00081, 0x0, "Firehawk Core BA"},
+ {HPHW_BA, 0x056, 0x00081, 0x0, "Raven+ w SE FWSCSI Core BA"},
+ {HPHW_BA, 0x057, 0x00081, 0x0, "Raven+ w Diff FWSCSI Core BA"},
+ {HPHW_BA, 0x058, 0x00081, 0x0, "FireHawk 200 Core BA"},
+ {HPHW_BA, 0x05C, 0x00081, 0x0, "SummitHawk 230 Core BA"},
+ {HPHW_BA, 0x05E, 0x00081, 0x0, "Staccato 132 Core BA"},
+ {HPHW_BA, 0x05E, 0x00081, 0x0, "Staccato 180 Core BA"},
+ {HPHW_BA, 0x05F, 0x00081, 0x0, "Staccato 180 Lasi"},
+ {HPHW_BA, 0x800, 0x00081, 0x0, "Hitachi Tiny 64 Core BA"},
+ {HPHW_BA, 0x801, 0x00081, 0x0, "Hitachi Tiny 80 Core BA"},
+ {HPHW_BA, 0x004, 0x0008B, 0x0, "Anole Optional PCMCIA BA"},
+ {HPHW_BA, 0x004, 0x0008E, 0x0, "GSC ITR Wax BA"},
+ {HPHW_BA, 0x00C, 0x0008E, 0x0, "Gecko Optional Wax BA"},
+ {HPHW_BA, 0x010, 0x0008E, 0x0, "Pace Wax BA"},
+ {HPHW_BA, 0x011, 0x0008E, 0x0, "SuperPace Wax BA"},
+ {HPHW_BA, 0x012, 0x0008E, 0x0, "Mirage Jr Wax BA"},
+ {HPHW_BA, 0x013, 0x0008E, 0x0, "Mirage Wax BA"},
+ {HPHW_BA, 0x014, 0x0008E, 0x0, "Electra Wax BA"},
+ {HPHW_BA, 0x017, 0x0008E, 0x0, "Raven Backplane Wax BA"},
+ {HPHW_BA, 0x01E, 0x0008E, 0x0, "Raven T' Wax BA"},
+ {HPHW_BA, 0x01F, 0x0008E, 0x0, "SkyHawk Wax BA"},
+ {HPHW_BA, 0x023, 0x0008E, 0x0, "Rocky1 Wax BA"},
+ {HPHW_BA, 0x02B, 0x0008E, 0x0, "Mirage 80 Wax BA"},
+ {HPHW_BA, 0x02C, 0x0008E, 0x0, "Mirage 100+ Wax BA"},
+ {HPHW_BA, 0x030, 0x0008E, 0x0, "UL 350 Core Wax BA"},
+ {HPHW_BA, 0x031, 0x0008E, 0x0, "UL 550 Core Wax BA"},
+ {HPHW_BA, 0x034, 0x0008E, 0x0, "SAIC L-80 Wax BA"},
+ {HPHW_BA, 0x03A, 0x0008E, 0x0, "Merlin+ Wax BA"},
+ {HPHW_BA, 0x040, 0x0008E, 0x0, "Merlin 132 Wax BA"},
+ {HPHW_BA, 0x041, 0x0008E, 0x0, "Merlin 160 Wax BA"},
+ {HPHW_BA, 0x043, 0x0008E, 0x0, "Merlin 132/160 Wax BA"},
+ {HPHW_BA, 0x052, 0x0008E, 0x0, "Raven+ Hi Power Backplane w/EISA Wax BA"},
+ {HPHW_BA, 0x054, 0x0008E, 0x0, "Raven+ Lo Power Backplane w/EISA Wax BA"},
+ {HPHW_BA, 0x059, 0x0008E, 0x0, "FireHawk 200 Wax BA"},
+ {HPHW_BA, 0x05A, 0x0008E, 0x0, "Raven+ L2 Backplane w/EISA Wax BA"},
+ {HPHW_BA, 0x05D, 0x0008E, 0x0, "SummitHawk Wax BA"},
+ {HPHW_BA, 0x800, 0x0008E, 0x0, "Hitachi Tiny 64 Wax BA"},
+ {HPHW_BA, 0x801, 0x0008E, 0x0, "Hitachi Tiny 80 Wax BA"},
+ {HPHW_BA, 0x011, 0x00090, 0x0, "SuperPace Wax EISA BA"},
+ {HPHW_BA, 0x017, 0x00090, 0x0, "Raven Backplane Wax EISA BA"},
+ {HPHW_BA, 0x01E, 0x00090, 0x0, "Raven T' Wax EISA BA"},
+ {HPHW_BA, 0x01F, 0x00090, 0x0, "SkyHawk 100/120 Wax EISA BA"},
+ {HPHW_BA, 0x027, 0x00090, 0x0, "Piranha 100 Wax EISA BA"},
+ {HPHW_BA, 0x028, 0x00090, 0x0, "Mirage Jr Wax EISA BA"},
+ {HPHW_BA, 0x029, 0x00090, 0x0, "Mirage Wax EISA BA"},
+ {HPHW_BA, 0x02A, 0x00090, 0x0, "Electra Wax EISA BA"},
+ {HPHW_BA, 0x02B, 0x00090, 0x0, "Mirage 80 Wax EISA BA"},
+ {HPHW_BA, 0x02C, 0x00090, 0x0, "Mirage 100+ Wax EISA BA"},
+ {HPHW_BA, 0x030, 0x00090, 0x0, "UL 350 Wax EISA BA"},
+ {HPHW_BA, 0x031, 0x00090, 0x0, "UL 550 Wax EISA BA"},
+ {HPHW_BA, 0x034, 0x00090, 0x0, "SAIC L-80 Wax EISA BA"},
+ {HPHW_BA, 0x03A, 0x00090, 0x0, "Merlin+ Wax EISA BA"},
+ {HPHW_BA, 0x040, 0x00090, 0x0, "Merlin 132 Wax EISA BA"},
+ {HPHW_BA, 0x041, 0x00090, 0x0, "Merlin 160 Wax EISA BA"},
+ {HPHW_BA, 0x043, 0x00090, 0x0, "Merlin 132/160 Wax EISA BA"},
+ {HPHW_BA, 0x052, 0x00090, 0x0, "Raven Hi Power Backplane Wax EISA BA"},
+ {HPHW_BA, 0x054, 0x00090, 0x0, "Raven Lo Power Backplane Wax EISA BA"},
+ {HPHW_BA, 0x059, 0x00090, 0x0, "FireHawk 200 Wax EISA BA"},
+ {HPHW_BA, 0x05A, 0x00090, 0x0, "Raven L2 Backplane Wax EISA BA"},
+ {HPHW_BA, 0x05D, 0x00090, 0x0, "SummitHawk Wax EISA BA"},
+ {HPHW_BA, 0x800, 0x00090, 0x0, "Hitachi Tiny 64 Wax EISA BA"},
+ {HPHW_BA, 0x801, 0x00090, 0x0, "Hitachi Tiny 80 Wax EISA BA"},
+ {HPHW_BA, 0x01A, 0x00093, 0x0, "Anole 64 TIMI BA"},
+ {HPHW_BA, 0x01B, 0x00093, 0x0, "Anole 100 TIMI BA"},
+ {HPHW_BA, 0x034, 0x00093, 0x0, "Anole T TIMI BA"},
+ {HPHW_BA, 0x04A, 0x00093, 0x0, "Anole L2 132 TIMI BA"},
+ {HPHW_BA, 0x04C, 0x00093, 0x0, "Anole L2 165 TIMI BA"},
+ {HPHW_BA, 0x582, 0x000A5, 0x00, "Epic PCI Bridge"},
+ {HPHW_BCPORT, 0x504, 0x00000, 0x00, "Phantom PseudoBC GSC+ Port"},
+ {HPHW_BCPORT, 0x505, 0x00000, 0x00, "Phantom PseudoBC GSC+ Port"},
+ {HPHW_BCPORT, 0x503, 0x0000C, 0x00, "Java BC GSC+ Port"},
+ {HPHW_BCPORT, 0x57F, 0x0000C, 0x00, "Hitachi Ghostview GSC+ Port"},
+ {HPHW_BCPORT, 0x501, 0x0000C, 0x00, "U2-IOA BC GSC+ Port"},
+ {HPHW_BCPORT, 0x502, 0x0000C, 0x00, "Uturn-IOA BC GSC+ Port"},
+ {HPHW_BCPORT, 0x780, 0x0000C, 0x00, "Astro BC Ropes Port"},
+ {HPHW_BCPORT, 0x506, 0x0000C, 0x00, "NEC-IOS BC HSC Port"},
+ {HPHW_BCPORT, 0x004, 0x0000C, 0x00, "Cheetah BC SMB Port"},
+ {HPHW_BCPORT, 0x006, 0x0000C, 0x00, "Cheetah BC MID_BUS Port"},
+ {HPHW_BCPORT, 0x005, 0x0000C, 0x00, "Condor BC MID_BUS Port"},
+ {HPHW_BCPORT, 0x100, 0x0000C, 0x00, "Condor BC HP-PB Port"},
+ {HPHW_BCPORT, 0x184, 0x0000C, 0x00, "Summit BC Port"},
+ {HPHW_BCPORT, 0x101, 0x0000C, 0x00, "Summit BC HP-PB Port"},
+ {HPHW_BCPORT, 0x102, 0x0000C, 0x00, "HP-PB Port (prefetch)"},
+ {HPHW_BCPORT, 0x500, 0x0000C, 0x00, "Gecko BOA BC GSC+ Port"},
+ {HPHW_BCPORT, 0x103, 0x0000C, 0x00, "Gecko BOA BC HP-PB Port"},
+ {HPHW_BCPORT, 0x507, 0x0000C, 0x00, "Keyaki BC GSC+ Port"},
+ {HPHW_BCPORT, 0x508, 0x0000C, 0x00, "Keyaki-DX BC GSC+ Port"},
+ {HPHW_BCPORT, 0x584, 0x0000C, 0x10, "DEW BC Runway Port"},
+ {HPHW_BCPORT, 0x800, 0x0000C, 0x10, "DEW BC Merced Port"},
+ {HPHW_BCPORT, 0x801, 0x0000C, 0x10, "SMC Bus Interface Merced Bus0"},
+ {HPHW_BCPORT, 0x802, 0x0000C, 0x10, "SMC Bus INterface Merced Bus1"},
+ {HPHW_BCPORT, 0x803, 0x0000C, 0x10, "IKE I/O BC Merced Port"},
+ {HPHW_BCPORT, 0x781, 0x0000C, 0x00, "IKE I/O BC Ropes Port"},
+ {HPHW_BCPORT, 0x804, 0x0000C, 0x10, "REO I/O BC Merced Port"},
+ {HPHW_BCPORT, 0x782, 0x0000C, 0x00, "REO I/O BC Ropes Port"},
+ {HPHW_BCPORT, 0x784, 0x0000C, 0x00, "Pluto I/O BC Ropes Port"},
+ {HPHW_BRIDGE, 0x05D, 0x0000A, 0x00, "SummitHawk Dino PCI Bridge"},
+ {HPHW_BRIDGE, 0x680, 0x0000A, 0x00, "Dino PCI Bridge"},
+ {HPHW_BRIDGE, 0x682, 0x0000A, 0x00, "Cujo PCI Bridge"},
+ {HPHW_BRIDGE, 0x782, 0x0000A, 0x00, "Elroy PCI Bridge"},
+ {HPHW_BRIDGE, 0x583, 0x000A5, 0x00, "Saga PCI Bridge"},
+ {HPHW_BRIDGE, 0x783, 0x0000A, 0x00, "Mercury PCI Bridge"},
+ {HPHW_BRIDGE, 0x784, 0x0000A, 0x00, "Quicksilver AGP Bridge"},
+ {HPHW_B_DMA, 0x004, 0x00018, 0x00, "Parallel I/O"},
+ {HPHW_B_DMA, 0x004, 0x00019, 0x00, "Parallel RDB"},
+ {HPHW_B_DMA, 0x004, 0x00020, 0x80, "MID_BUS PSI"},
+ {HPHW_B_DMA, 0x004, 0x0002F, 0x80, "HP-PB Transit PSI (36960A)"},
+ {HPHW_B_DMA, 0x008, 0x00051, 0x80, "HP-PB Transit 802.3"},
+ {HPHW_B_DMA, 0x004, 0x00052, 0x80, "Miura LAN/Console (J2146A)"},
+ {HPHW_B_DMA, 0x008, 0x00058, 0x80, "HP-PB Transit 802.4"},
+ {HPHW_B_DMA, 0x005, 0x00060, 0x80, "KittyHawk CSY Core LAN/Console"},
+ {HPHW_B_DMA, 0x014, 0x00060, 0x80, "Diablo LAN/Console"},
+ {HPHW_B_DMA, 0x054, 0x00060, 0x80, "Countach LAN/Console"},
+ {HPHW_B_DMA, 0x004, 0x00094, 0x80, "KittyHawk GSC+ Exerciser"},
+ {HPHW_B_DMA, 0x004, 0x00100, 0x80, "HP-PB HF Interface"},
+ {HPHW_B_DMA, 0x000, 0x00206, 0x80, "MELCO HMPHA"},
+ {HPHW_B_DMA, 0x005, 0x00206, 0x80, "MELCO HMPHA_10"},
+ {HPHW_B_DMA, 0x006, 0x00206, 0x80, "MELCO HMQHA"},
+ {HPHW_B_DMA, 0x007, 0x00206, 0x80, "MELCO HMQHA_10"},
+ {HPHW_B_DMA, 0x004, 0x207, 0x80, "MELCO HNDWA MDWS-70"},
+ {HPHW_CIO, 0x004, 0x00010, 0x00, "VLSI CIO"},
+ {HPHW_CIO, 0x005, 0x00010, 0x00, "Silverfox CIO"},
+ {HPHW_CIO, 0x006, 0x00010, 0x00, "Emerald CIO"},
+ {HPHW_CIO, 0x008, 0x00010, 0x00, "Discrete CIO"},
+ {HPHW_CONSOLE, 0x004, 0x0001C, 0x00, "Cheetah console"},
+ {HPHW_CONSOLE, 0x005, 0x0001C, 0x00, "Emerald console"},
+ {HPHW_CONSOLE, 0x01A, 0x0001F, 0x00, "Jason/Anole 64 Null Console"},
+ {HPHW_CONSOLE, 0x01B, 0x0001F, 0x00, "Jason/Anole 100 Null Console"},
+ {HPHW_FABRIC, 0x004, 0x000AA, 0x80, "Halfdome DNA Central Agent"},
+ {HPHW_FABRIC, 0x005, 0x000AA, 0x80, "Keystone DNA Central Agent"},
+ {HPHW_FABRIC, 0x007, 0x000AA, 0x80, "Caribe DNA Central Agent"},
+ {HPHW_FABRIC, 0x004, 0x000AB, 0x00, "Halfdome TOGO Fabric Crossbar"},
+ {HPHW_FABRIC, 0x005, 0x000AB, 0x00, "Keystone TOGO Fabric Crossbar"},
+ {HPHW_FABRIC, 0x004, 0x000AC, 0x00, "Halfdome Sakura Fabric Router"},
+ {HPHW_FIO, 0x025, 0x0002E, 0x80, "Armyknife Optional X.25"},
+ {HPHW_FIO, 0x004, 0x0004F, 0x0, "8-Port X.25 EISA-ACC (AMSO)"},
+ {HPHW_FIO, 0x004, 0x00071, 0x0, "Cobra Core SCSI"},
+ {HPHW_FIO, 0x005, 0x00071, 0x0, "Coral Core SCSI"},
+ {HPHW_FIO, 0x006, 0x00071, 0x0, "Bushmaster Core SCSI"},
+ {HPHW_FIO, 0x007, 0x00071, 0x0, "Scorpio Core SCSI"},
+ {HPHW_FIO, 0x008, 0x00071, 0x0, "Flounder Core SCSI"},
+ {HPHW_FIO, 0x009, 0x00071, 0x0, "Outfield Core SCSI"},
+ {HPHW_FIO, 0x00A, 0x00071, 0x0, "CoralII Core SCSI"},
+ {HPHW_FIO, 0x00B, 0x00071, 0x0, "Scorpio Jr. Core SCSI"},
+ {HPHW_FIO, 0x00C, 0x00071, 0x0, "Strider-50 Core SCSI"},
+ {HPHW_FIO, 0x00D, 0x00071, 0x0, "Strider-33 Core SCSI"},
+ {HPHW_FIO, 0x00E, 0x00071, 0x0, "Trailways-50 Core SCSI"},
+ {HPHW_FIO, 0x00F, 0x00071, 0x0, "Trailways-33 Core SCSI"},
+ {HPHW_FIO, 0x010, 0x00071, 0x0, "Pace Core SCSI"},
+ {HPHW_FIO, 0x011, 0x00071, 0x0, "Sidewinder Core SCSI"},
+ {HPHW_FIO, 0x019, 0x00071, 0x0, "Scorpio Sr. Core SCSI"},
+ {HPHW_FIO, 0x020, 0x00071, 0x0, "Scorpio 100 Core SCSI"},
+ {HPHW_FIO, 0x021, 0x00071, 0x0, "Spectra 50 Core SCSI"},
+ {HPHW_FIO, 0x022, 0x00071, 0x0, "Spectra 75 Core SCSI"},
+ {HPHW_FIO, 0x023, 0x00071, 0x0, "Spectra 100 Core SCSI"},
+ {HPHW_FIO, 0x024, 0x00071, 0x0, "Fast Pace Core SCSI"},
+ {HPHW_FIO, 0x026, 0x00071, 0x0, "CoralII Jaguar Core SCSI"},
+ {HPHW_FIO, 0x004, 0x00072, 0x0, "Cobra Core LAN (802.3)"},
+ {HPHW_FIO, 0x005, 0x00072, 0x0, "Coral Core LAN (802.3)"},
+ {HPHW_FIO, 0x006, 0x00072, 0x0, "Bushmaster Core LAN (802.3)"},
+ {HPHW_FIO, 0x007, 0x00072, 0x0, "Scorpio Core LAN (802.3)"},
+ {HPHW_FIO, 0x008, 0x00072, 0x0, "Flounder Core LAN (802.3)"},
+ {HPHW_FIO, 0x009, 0x00072, 0x0, "Outfield Core LAN (802.3)"},
+ {HPHW_FIO, 0x00A, 0x00072, 0x0, "CoralII Core LAN (802.3)"},
+ {HPHW_FIO, 0x00B, 0x00072, 0x0, "Scorpio Jr. Core LAN (802.3)"},
+ {HPHW_FIO, 0x00C, 0x00072, 0x0, "Strider-50 Core LAN (802.3)"},
+ {HPHW_FIO, 0x00D, 0x00072, 0x0, "Strider-33 Core LAN (802.3)"},
+ {HPHW_FIO, 0x00E, 0x00072, 0x0, "Trailways-50 Core LAN (802.3)"},
+ {HPHW_FIO, 0x00F, 0x00072, 0x0, "Trailways-33 Core LAN (802.3)"},
+ {HPHW_FIO, 0x010, 0x00072, 0x0, "Pace Core LAN (802.3)"},
+ {HPHW_FIO, 0x011, 0x00072, 0x0, "Sidewinder Core LAN (802.3)"},
+ {HPHW_FIO, 0x019, 0x00072, 0x0, "Scorpio Sr. Core LAN (802.3)"},
+ {HPHW_FIO, 0x020, 0x00072, 0x0, "Scorpio 100 Core LAN (802.3)"},
+ {HPHW_FIO, 0x021, 0x00072, 0x0, "Spectra 50 Core LAN (802.3)"},
+ {HPHW_FIO, 0x022, 0x00072, 0x0, "Spectra 75 Core LAN (802.3)"},
+ {HPHW_FIO, 0x023, 0x00072, 0x0, "Spectra 100 Core LAN (802.3)"},
+ {HPHW_FIO, 0x024, 0x00072, 0x0, "Fast Pace Core LAN (802.3)"},
+ {HPHW_FIO, 0x026, 0x00072, 0x0, "CoralII Jaguar Core LAN (802.3)"},
+ {HPHW_FIO, 0x004, 0x00073, 0x0, "Cobra Core HIL"},
+ {HPHW_FIO, 0x005, 0x00073, 0x0, "Coral Core HIL"},
+ {HPHW_FIO, 0x006, 0x00073, 0x0, "Bushmaster Core HIL"},
+ {HPHW_FIO, 0x007, 0x00073, 0x0, "Scorpio Core HIL"},
+ {HPHW_FIO, 0x008, 0x00073, 0x0, "Flounder Core HIL"},
+ {HPHW_FIO, 0x009, 0x00073, 0x0, "Outfield Core HIL"},
+ {HPHW_FIO, 0x00A, 0x00073, 0x0, "CoralII Core HIL"},
+ {HPHW_FIO, 0x00B, 0x00073, 0x0, "Scorpio Jr. Core HIL"},
+ {HPHW_FIO, 0x00C, 0x00073, 0x0, "Strider-50 Core HIL"},
+ {HPHW_FIO, 0x00D, 0x00073, 0x0, "Strider-33 Core HIL"},
+ {HPHW_FIO, 0x00E, 0x00073, 0x0, "Trailways-50 Core HIL"},
+ {HPHW_FIO, 0x00F, 0x00073, 0x0, "Trailways-33 Core HIL"},
+ {HPHW_FIO, 0x010, 0x00073, 0x0, "Pace Core HIL"},
+ {HPHW_FIO, 0x011, 0x00073, 0xcc, "SuperPace Wax HIL"},
+ {HPHW_FIO, 0x012, 0x00073, 0x0, "Mirage Jr Wax HIL"},
+ {HPHW_FIO, 0x013, 0x00073, 0x0, "Mirage 100 Wax HIL"},
+ {HPHW_FIO, 0x014, 0x00073, 0x0, "Electra Wax HIL"},
+ {HPHW_FIO, 0x017, 0x00073, 0x0, "Raven Backplane Wax HIL"},
+ {HPHW_FIO, 0x019, 0x00073, 0x0, "Scorpio Sr. Core HIL"},
+ {HPHW_FIO, 0x01E, 0x00073, 0x0, "Raven T' Wax HIL"},
+ {HPHW_FIO, 0x01F, 0x00073, 0x0, "SkyHawk 100/120 Wax HIL"},
+ {HPHW_FIO, 0x020, 0x00073, 0x0, "Scorpio 100 Core HIL"},
+ {HPHW_FIO, 0x021, 0x00073, 0x0, "Spectra 50 Core HIL"},
+ {HPHW_FIO, 0x022, 0x00073, 0x0, "Spectra 75 Core HIL"},
+ {HPHW_FIO, 0x023, 0x00073, 0x0, "Spectra 100 Core HIL"},
+ {HPHW_FIO, 0x024, 0x00073, 0x0, "Fast Pace Core HIL"},
+ {HPHW_FIO, 0x026, 0x00073, 0x0, "CoralII Jaguar Core HIL"},
+ {HPHW_FIO, 0x02B, 0x00073, 0x0, "Mirage 80 Wax HIL"},
+ {HPHW_FIO, 0x02C, 0x00073, 0x0, "Mirage 100+ Wax HIL"},
+ {HPHW_FIO, 0x03A, 0x00073, 0x0, "Merlin+ Wax HIL"},
+ {HPHW_FIO, 0x040, 0x00073, 0x0, "Merlin 132 Wax HIL"},
+ {HPHW_FIO, 0x041, 0x00073, 0x0, "Merlin 160 Wax HIL"},
+ {HPHW_FIO, 0x043, 0x00073, 0x0, "Merlin 132/160 Wax HIL"},
+ {HPHW_FIO, 0x052, 0x00073, 0x0, "Raven+ Hi Power Backplane w/EISA Wax HIL"},
+ {HPHW_FIO, 0x053, 0x00073, 0x0, "Raven+ Hi Power Backplane wo/EISA Wax HIL"},
+ {HPHW_FIO, 0x054, 0x00073, 0x0, "Raven+ Lo Power Backplane w/EISA Wax HIL"},
+ {HPHW_FIO, 0x055, 0x00073, 0x0, "Raven+ Lo Power Backplane wo/EISA Wax HIL"},
+ {HPHW_FIO, 0x059, 0x00073, 0x0, "FireHawk 200 Wax HIL"},
+ {HPHW_FIO, 0x05A, 0x00073, 0x0, "Raven+ L2 Backplane w/EISA Wax HIL"},
+ {HPHW_FIO, 0x05B, 0x00073, 0x0, "Raven+ L2 Backplane wo/EISA Wax HIL"},
+ {HPHW_FIO, 0x05D, 0x00073, 0x0, "SummitHawk Wax HIL"},
+ {HPHW_FIO, 0x800, 0x00073, 0x0, "Hitachi Tiny 64 Wax HIL"},
+ {HPHW_FIO, 0x801, 0x00073, 0x0, "Hitachi Tiny 80 Wax HIL"},
+ {HPHW_FIO, 0x004, 0x00074, 0x0, "Cobra Core Centronics"},
+ {HPHW_FIO, 0x005, 0x00074, 0x0, "Coral Core Centronics"},
+ {HPHW_FIO, 0x006, 0x00074, 0x0, "Bushmaster Core Centronics"},
+ {HPHW_FIO, 0x007, 0x00074, 0x0, "Scorpio Core Centronics"},
+ {HPHW_FIO, 0x008, 0x00074, 0x0, "Flounder Core Centronics"},
+ {HPHW_FIO, 0x009, 0x00074, 0x0, "Outfield Core Centronics"},
+ {HPHW_FIO, 0x00A, 0x00074, 0x0, "CoralII Core Centronics"},
+ {HPHW_FIO, 0x00B, 0x00074, 0x0, "Scorpio Jr. Core Centronics"},
+ {HPHW_FIO, 0x00C, 0x00074, 0x0, "Strider-50 Core Centronics"},
+ {HPHW_FIO, 0x00D, 0x00074, 0x0, "Strider-33 Core Centronics"},
+ {HPHW_FIO, 0x00E, 0x00074, 0x0, "Trailways-50 Core Centronics"},
+ {HPHW_FIO, 0x00F, 0x00074, 0x0, "Trailways-33 Core Centronics"},
+ {HPHW_FIO, 0x010, 0x00074, 0x0, "Pace Core Centronics"},
+ {HPHW_FIO, 0x011, 0x00074, 0x0, "Sidewinder Core Centronics"},
+ {HPHW_FIO, 0x015, 0x00074, 0x0, "KittyHawk GSY Core Centronics"},
+ {HPHW_FIO, 0x016, 0x00074, 0x0, "Gecko Core Centronics"},
+ {HPHW_FIO, 0x019, 0x00074, 0x0, "Scorpio Sr. Core Centronics"},
+ {HPHW_FIO, 0x01A, 0x00074, 0x0, "Anole 64 Core Centronics"},
+ {HPHW_FIO, 0x01B, 0x00074, 0x0, "Anole 100 Core Centronics"},
+ {HPHW_FIO, 0x01C, 0x00074, 0x0, "Gecko 80 Core Centronics"},
+ {HPHW_FIO, 0x01D, 0x00074, 0x0, "Gecko 100 Core Centronics"},
+ {HPHW_FIO, 0x01F, 0x00074, 0x0, "SkyHawk 100/120 Core Centronics"},
+ {HPHW_FIO, 0x020, 0x00074, 0x0, "Scorpio 100 Core Centronics"},
+ {HPHW_FIO, 0x021, 0x00074, 0x0, "Spectra 50 Core Centronics"},
+ {HPHW_FIO, 0x022, 0x00074, 0x0, "Spectra 75 Core Centronics"},
+ {HPHW_FIO, 0x023, 0x00074, 0x0, "Spectra 100 Core Centronics"},
+ {HPHW_FIO, 0x024, 0x00074, 0x0, "Fast Pace Core Centronics"},
+ {HPHW_FIO, 0x026, 0x00074, 0x0, "CoralII Jaguar Core Centronics"},
+ {HPHW_FIO, 0x027, 0x00074, 0x0, "Piranha 100 Core Centronics"},
+ {HPHW_FIO, 0x028, 0x00074, 0x0, "Mirage Jr Core Centronics"},
+ {HPHW_FIO, 0x029, 0x00074, 0x0, "Mirage Core Centronics"},
+ {HPHW_FIO, 0x02A, 0x00074, 0x0, "Electra Core Centronics"},
+ {HPHW_FIO, 0x02B, 0x00074, 0x0, "Mirage 80 Core Centronics"},
+ {HPHW_FIO, 0x02C, 0x00074, 0x0, "Mirage 100+ Core Centronics"},
+ {HPHW_FIO, 0x02E, 0x00074, 0x0, "UL 350 Core Centronics"},
+ {HPHW_FIO, 0x02F, 0x00074, 0x0, "UL 550 Core Centronics"},
+ {HPHW_FIO, 0x032, 0x00074, 0x0, "Raven T' Core Centronics"},
+ {HPHW_FIO, 0x033, 0x00074, 0x0, "Anole T Core Centronics"},
+ {HPHW_FIO, 0x034, 0x00074, 0x0, "SAIC L-80 Core Centronics"},
+ {HPHW_FIO, 0x035, 0x00074, 0x0, "PCX-L2 712/132 Core Centronics"},
+ {HPHW_FIO, 0x036, 0x00074, 0x0, "PCX-L2 712/160 Core Centronics"},
+ {HPHW_FIO, 0x03B, 0x00074, 0x0, "Raven U/L2 Core Centronics"},
+ {HPHW_FIO, 0x03C, 0x00074, 0x0, "Merlin 132 Core Centronics"},
+ {HPHW_FIO, 0x03D, 0x00074, 0x0, "Merlin 160 Core Centronics"},
+ {HPHW_FIO, 0x03E, 0x00074, 0x0, "Merlin+ 132 Core Centronics"},
+ {HPHW_FIO, 0x03F, 0x00074, 0x0, "Merlin+ 180 Core Centronics"},
+ {HPHW_FIO, 0x044, 0x00074, 0x0, "Mohawk Core Centronics"},
+ {HPHW_FIO, 0x045, 0x00074, 0x0, "Rocky1 Core Centronics"},
+ {HPHW_FIO, 0x046, 0x00074, 0x0, "Rocky2 120 Core Centronics"},
+ {HPHW_FIO, 0x047, 0x00074, 0x0, "Rocky2 150 Core Centronics"},
+ {HPHW_FIO, 0x04B, 0x00074, 0x0, "Anole L2 132 Core Centronics"},
+ {HPHW_FIO, 0x04D, 0x00074, 0x0, "Anole L2 165 Core Centronics"},
+ {HPHW_FIO, 0x050, 0x00074, 0x0, "Merlin Jr 132 Core Centronics"},
+ {HPHW_FIO, 0x051, 0x00074, 0x0, "Firehawk Core Centronics"},
+ {HPHW_FIO, 0x056, 0x00074, 0x0, "Raven+ w SE FWSCSI Core Centronics"},
+ {HPHW_FIO, 0x057, 0x00074, 0x0, "Raven+ w Diff FWSCSI Core Centronics"},
+ {HPHW_FIO, 0x058, 0x00074, 0x0, "FireHawk 200 Core Centronics"},
+ {HPHW_FIO, 0x05C, 0x00074, 0x0, "SummitHawk 230 Core Centronics"},
+ {HPHW_FIO, 0x800, 0x00074, 0x0, "Hitachi Tiny 64 Core Centronics"},
+ {HPHW_FIO, 0x801, 0x00074, 0x0, "Hitachi Tiny 80 Core Centronics"},
+ {HPHW_FIO, 0x004, 0x00075, 0x0, "Cobra Core RS-232"},
+ {HPHW_FIO, 0x005, 0x00075, 0x0, "Coral Core RS-232"},
+ {HPHW_FIO, 0x006, 0x00075, 0x0, "Bushmaster Core RS-232"},
+ {HPHW_FIO, 0x007, 0x00075, 0x0, "Scorpio Core RS-232"},
+ {HPHW_FIO, 0x008, 0x00075, 0x0, "Flounder Core RS-232"},
+ {HPHW_FIO, 0x009, 0x00075, 0x0, "Outfield Core RS-232"},
+ {HPHW_FIO, 0x00A, 0x00075, 0x0, "CoralII Core RS-232"},
+ {HPHW_FIO, 0x00B, 0x00075, 0x0, "Scorpio Jr. Core RS-232"},
+ {HPHW_FIO, 0x00C, 0x00075, 0x0, "Strider-50 Core RS-232"},
+ {HPHW_FIO, 0x00D, 0x00075, 0x0, "Strider-33 Core RS-232"},
+ {HPHW_FIO, 0x00E, 0x00075, 0x0, "Trailways-50 Core RS-232"},
+ {HPHW_FIO, 0x00F, 0x00075, 0x0, "Trailways-33 Core RS-232"},
+ {HPHW_FIO, 0x010, 0x00075, 0x0, "Pace Core RS-232"},
+ {HPHW_FIO, 0x011, 0x00075, 0x0, "Sidewinder Core RS-232"},
+ {HPHW_FIO, 0x019, 0x00075, 0x0, "Scorpio Sr. Core RS-232"},
+ {HPHW_FIO, 0x020, 0x00075, 0x0, "Scorpio 100 Core RS-232"},
+ {HPHW_FIO, 0x021, 0x00075, 0x0, "Spectra 50 Core RS-232"},
+ {HPHW_FIO, 0x022, 0x00075, 0x0, "Spectra 75 Core RS-232"},
+ {HPHW_FIO, 0x023, 0x00075, 0x0, "Spectra 100 Core RS-232"},
+ {HPHW_FIO, 0x024, 0x00075, 0x0, "Fast Pace Core RS-232"},
+ {HPHW_FIO, 0x026, 0x00075, 0x0, "CoralII Jaguar Core RS-232"},
+ {HPHW_FIO, 0x004, 0x00077, 0x0, "Coral SGC Graphics"},
+ {HPHW_FIO, 0x005, 0x00077, 0x0, "Hyperdrive Optional Graphics"},
+ {HPHW_FIO, 0x006, 0x00077, 0x0, "Stinger Optional Graphics"},
+ {HPHW_FIO, 0x007, 0x00077, 0x0, "Scorpio Builtin Graphics"},
+ {HPHW_FIO, 0x008, 0x00077, 0x0, "Anole Hyperdrive Optional Graphics"},
+ {HPHW_FIO, 0x009, 0x00077, 0x0, "Thunder II graphics EISA form"},
+ {HPHW_FIO, 0x00A, 0x00077, 0x0, "Thunder II graphics GSA form"},
+ {HPHW_FIO, 0x00B, 0x00077, 0x0, "Scorpio Jr Builtin Graphics"},
+ {HPHW_FIO, 0x00C, 0x00077, 0x0, "Strider-50 SSC Graphics"},
+ {HPHW_FIO, 0x00D, 0x00077, 0x0, "Strider-33 SSC Graphics"},
+ {HPHW_FIO, 0x00E, 0x00077, 0x0, "Trailways-50 SSC Graphics"},
+ {HPHW_FIO, 0x00F, 0x00077, 0x0, "Trailways-33 SSC Graphics"},
+ {HPHW_FIO, 0x010, 0x00077, 0x0, "Pace SGC Graphics"},
+ {HPHW_FIO, 0x011, 0x00077, 0x0, "Mohawk Opt. 2D Graphics (Kid)"},
+ {HPHW_FIO, 0x012, 0x00077, 0x0, "Raven Opt. 2D Graphics (Goat)"},
+ {HPHW_FIO, 0x016, 0x00077, 0x0, "Lego 24 SCG Graphics"},
+ {HPHW_FIO, 0x017, 0x00077, 0x0, "Lego 24Z SCG Graphics"},
+ {HPHW_FIO, 0x018, 0x00077, 0x0, "Lego 48Z SCG Graphics"},
+ {HPHW_FIO, 0x019, 0x00077, 0x0, "Scorpio Sr Builtin Graphics"},
+ {HPHW_FIO, 0x020, 0x00077, 0x0, "Scorpio 100 Builtin Graphics"},
+ {HPHW_FIO, 0x021, 0x00077, 0x0, "Spectra 50 Builtin Graphics"},
+ {HPHW_FIO, 0x022, 0x00077, 0x0, "Spectra 75 Builtin Graphics"},
+ {HPHW_FIO, 0x023, 0x00077, 0x0, "Spectra 100 Builtin Graphics"},
+ {HPHW_FIO, 0x024, 0x00077, 0x0, "Fast Pace SGC Graphics"},
+ {HPHW_FIO, 0x006, 0x0007A, 0x0, "Bushmaster Audio"},
+ {HPHW_FIO, 0x008, 0x0007A, 0x0, "Flounder Audio"},
+ {HPHW_FIO, 0x004, 0x0007B, 0x0, "UL Optional Audio"},
+ {HPHW_FIO, 0x007, 0x0007B, 0x0, "Scorpio Audio"},
+ {HPHW_FIO, 0x00B, 0x0007B, 0x0, "Scorpio Jr. Audio"},
+ {HPHW_FIO, 0x00C, 0x0007B, 0x0, "Strider-50 Audio"},
+ {HPHW_FIO, 0x00D, 0x0007B, 0x0, "Strider-33 Audio"},
+ {HPHW_FIO, 0x00E, 0x0007B, 0x0, "Trailways-50 Audio"},
+ {HPHW_FIO, 0x00F, 0x0007B, 0x0, "Trailways-33 Audio"},
+ {HPHW_FIO, 0x015, 0x0007B, 0x0, "KittyHawk GSY Core Audio"},
+ {HPHW_FIO, 0x016, 0x0007B, 0x0, "Gecko Audio"},
+ {HPHW_FIO, 0x019, 0x0007B, 0x0, "Scorpio Sr. Audio"},
+ {HPHW_FIO, 0x01A, 0x0007B, 0x0, "Anole 64 Audio"},
+ {HPHW_FIO, 0x01B, 0x0007B, 0x0, "Anole 100 Audio"},
+ {HPHW_FIO, 0x01C, 0x0007B, 0x0, "Gecko 80 Audio"},
+ {HPHW_FIO, 0x01D, 0x0007B, 0x0, "Gecko 100 Audio"},
+ {HPHW_FIO, 0x01F, 0x0007B, 0x0, "SkyHawk 100/120 Audio"},
+ {HPHW_FIO, 0x020, 0x0007B, 0x0, "Scorpio 100 Audio"},
+ {HPHW_FIO, 0x021, 0x0007B, 0x0, "Spectra 50 Audio"},
+ {HPHW_FIO, 0x022, 0x0007B, 0x0, "Spectra 75 Audio"},
+ {HPHW_FIO, 0x023, 0x0007B, 0x0, "Spectra 100 Audio"},
+ {HPHW_FIO, 0x028, 0x0007B, 0x0, "Mirage Jr Audio"},
+ {HPHW_FIO, 0x029, 0x0007B, 0x0, "Mirage Audio"},
+ {HPHW_FIO, 0x02A, 0x0007B, 0x0, "Electra Audio"},
+ {HPHW_FIO, 0x02B, 0x0007B, 0x0, "Mirage 80 Audio"},
+ {HPHW_FIO, 0x02C, 0x0007B, 0x0, "Mirage 100+ Audio"},
+ {HPHW_FIO, 0x032, 0x0007B, 0x0, "Raven T' Audio"},
+ {HPHW_FIO, 0x034, 0x0007B, 0x0, "SAIC L-80 Audio"},
+ {HPHW_FIO, 0x035, 0x0007B, 0x0, "PCX-L2 712/132 Core Audio"},
+ {HPHW_FIO, 0x036, 0x0007B, 0x0, "PCX-L2 712/160 Core Audio"},
+ {HPHW_FIO, 0x03B, 0x0007B, 0x0, "Raven U/L2 Core Audio"},
+ {HPHW_FIO, 0x03C, 0x0007B, 0x0, "Merlin 132 Core Audio"},
+ {HPHW_FIO, 0x03D, 0x0007B, 0x0, "Merlin 160 Core Audio"},
+ {HPHW_FIO, 0x03E, 0x0007B, 0x0, "Merlin+ 132 Core Audio"},
+ {HPHW_FIO, 0x03F, 0x0007B, 0x0, "Merlin+ 180 Core Audio"},
+ {HPHW_FIO, 0x044, 0x0007B, 0x0, "Mohawk Core Audio"},
+ {HPHW_FIO, 0x046, 0x0007B, 0x0, "Rocky2 120 Core Audio"},
+ {HPHW_FIO, 0x047, 0x0007B, 0x0, "Rocky2 150 Core Audio"},
+ {HPHW_FIO, 0x04B, 0x0007B, 0x0, "Anole L2 132 Core Audio"},
+ {HPHW_FIO, 0x04D, 0x0007B, 0x0, "Anole L2 165 Core Audio"},
+ {HPHW_FIO, 0x04E, 0x0007B, 0x0, "Kiji L2 132 Core Audio"},
+ {HPHW_FIO, 0x050, 0x0007B, 0x0, "Merlin Jr 132 Core Audio"},
+ {HPHW_FIO, 0x051, 0x0007B, 0x0, "Firehawk Audio"},
+ {HPHW_FIO, 0x056, 0x0007B, 0x0, "Raven+ w SE FWSCSI Core Audio"},
+ {HPHW_FIO, 0x057, 0x0007B, 0x0, "Raven+ w Diff FWSCSI Core Audio"},
+ {HPHW_FIO, 0x058, 0x0007B, 0x0, "FireHawk 200 Audio"},
+ {HPHW_FIO, 0x05C, 0x0007B, 0x0, "SummitHawk 230 Core Audio"},
+ {HPHW_FIO, 0x800, 0x0007B, 0x0, "Hitachi Tiny 64 Audio"},
+ {HPHW_FIO, 0x801, 0x0007B, 0x0, "Hitachi Tiny 80 Audio"},
+ {HPHW_FIO, 0x009, 0x0007C, 0x0, "Outfield FW SCSI"},
+ {HPHW_FIO, 0x00A, 0x0007C, 0x0, "CoralII FW SCSI"},
+ {HPHW_FIO, 0x026, 0x0007C, 0x0, "CoralII Jaguar FW SCSI"},
+ {HPHW_FIO, 0x009, 0x0007D, 0x0, "Outfield FDDI"},
+ {HPHW_FIO, 0x00A, 0x0007D, 0x0, "CoralII FDDI"},
+ {HPHW_FIO, 0x026, 0x0007D, 0x0, "CoralII Jaguar FDDI"},
+ {HPHW_FIO, 0x010, 0x0007E, 0x0, "Pace Audio"},
+ {HPHW_FIO, 0x024, 0x0007E, 0x0, "Fast Pace Audio"},
+ {HPHW_FIO, 0x009, 0x0007F, 0x0, "Outfield Audio"},
+ {HPHW_FIO, 0x00A, 0x0007F, 0x0, "CoralII Audio"},
+ {HPHW_FIO, 0x026, 0x0007F, 0x0, "CoralII Jaguar Audio"},
+ {HPHW_FIO, 0x010, 0x00080, 0x0, "Pace Core HPIB"},
+ {HPHW_FIO, 0x024, 0x00080, 0x0, "Fast Pace Core HPIB"},
+ {HPHW_FIO, 0x015, 0x00082, 0x0, "KittyHawk GSY Core SCSI"},
+ {HPHW_FIO, 0x016, 0x00082, 0x0, "Gecko Core SCSI"},
+ {HPHW_FIO, 0x01A, 0x00082, 0x0, "Anole 64 Core SCSI"},
+ {HPHW_FIO, 0x01B, 0x00082, 0x0, "Anole 100 Core SCSI"},
+ {HPHW_FIO, 0x01C, 0x00082, 0x0, "Gecko 80 Core SCSI"},
+ {HPHW_FIO, 0x01D, 0x00082, 0x0, "Gecko 100 Core SCSI"},
+ {HPHW_FIO, 0x01F, 0x00082, 0x0, "SkyHawk 100/120 Core SCSI"},
+ {HPHW_FIO, 0x027, 0x00082, 0x0, "Piranha 100 Core SCSI"},
+ {HPHW_FIO, 0x028, 0x00082, 0x0, "Mirage Jr Core SCSI"},
+ {HPHW_FIO, 0x029, 0x00082, 0x0, "Mirage Core SCSI"},
+ {HPHW_FIO, 0x02A, 0x00082, 0x0, "Electra Core SCSI"},
+ {HPHW_FIO, 0x02B, 0x00082, 0x0, "Mirage 80 Core SCSI"},
+ {HPHW_FIO, 0x02C, 0x00082, 0x0, "Mirage 100+ Core SCSI"},
+ {HPHW_FIO, 0x02E, 0x00082, 0x0, "UL 350 Core SCSI"},
+ {HPHW_FIO, 0x02F, 0x00082, 0x0, "UL 550 Core SCSI"},
+ {HPHW_FIO, 0x032, 0x00082, 0x0, "Raven T' Core SCSI"},
+ {HPHW_FIO, 0x033, 0x00082, 0x0, "Anole T Core SCSI"},
+ {HPHW_FIO, 0x034, 0x00082, 0x0, "SAIC L-80 Core SCSI"},
+ {HPHW_FIO, 0x035, 0x00082, 0x0, "PCX-L2 712/132 Core SCSI"},
+ {HPHW_FIO, 0x036, 0x00082, 0x0, "PCX-L2 712/160 Core SCSI"},
+ {HPHW_FIO, 0x03B, 0x00082, 0x0, "Raven U/L2 Core SCSI"},
+ {HPHW_FIO, 0x03C, 0x00082, 0x0, "Merlin 132 Core SCSI"},
+ {HPHW_FIO, 0x03D, 0x00082, 0x0, "Merlin 160 Core SCSI"},
+ {HPHW_FIO, 0x03E, 0x00082, 0x0, "Merlin+ 132 Core SCSI"},
+ {HPHW_FIO, 0x03F, 0x00082, 0x0, "Merlin+ 180 Core SCSI"},
+ {HPHW_FIO, 0x044, 0x00082, 0x0, "Mohawk Core SCSI"},
+ {HPHW_FIO, 0x045, 0x00082, 0x0, "Rocky1 Core SCSI"},
+ {HPHW_FIO, 0x046, 0x00082, 0x0, "Rocky2 120 Core SCSI"},
+ {HPHW_FIO, 0x047, 0x00082, 0x0, "Rocky2 150 Core SCSI"},
+ {HPHW_FIO, 0x04B, 0x00082, 0x0, "Anole L2 132 Core SCSI"},
+ {HPHW_FIO, 0x04D, 0x00082, 0x0, "Anole L2 165 Core SCSI"},
+ {HPHW_FIO, 0x04E, 0x00082, 0x0, "Kiji L2 132 Core SCSI"},
+ {HPHW_FIO, 0x050, 0x00082, 0x0, "Merlin Jr 132 Core SCSI"},
+ {HPHW_FIO, 0x051, 0x00082, 0x0, "Firehawk Core SCSI"},
+ {HPHW_FIO, 0x056, 0x00082, 0x0, "Raven+ w SE FWSCSI Core SCSI"},
+ {HPHW_FIO, 0x057, 0x00082, 0x0, "Raven+ w Diff FWSCSI Core SCSI"},
+ {HPHW_FIO, 0x058, 0x00082, 0x0, "FireHawk 200 Core SCSI"},
+ {HPHW_FIO, 0x05C, 0x00082, 0x0, "SummitHawk 230 Core SCSI"},
+ {HPHW_FIO, 0x05E, 0x00082, 0x0, "Staccato 132 Core SCSI"},
+ {HPHW_FIO, 0x05F, 0x00082, 0x0, "Staccato 180 Core SCSI"},
+ {HPHW_FIO, 0x800, 0x00082, 0x0, "Hitachi Tiny 64 Core SCSI"},
+ {HPHW_FIO, 0x801, 0x00082, 0x0, "Hitachi Tiny 80 Core SCSI"},
+ {HPHW_FIO, 0x016, 0x00083, 0x0, "Gecko Core PC Floppy"},
+ {HPHW_FIO, 0x01C, 0x00083, 0x0, "Gecko 80 Core PC Floppy"},
+ {HPHW_FIO, 0x01D, 0x00083, 0x0, "Gecko 100 Core PC Floppy"},
+ {HPHW_FIO, 0x051, 0x00083, 0x0, "Firehawk Core PC Floppy"},
+ {HPHW_FIO, 0x058, 0x00083, 0x0, "FireHawk 200 Core PC Floppy"},
+ {HPHW_FIO, 0x027, 0x00083, 0x0, "Piranha 100 Core PC Floppy"},
+ {HPHW_FIO, 0x028, 0x00083, 0x0, "Mirage Jr Core PC Floppy"},
+ {HPHW_FIO, 0x029, 0x00083, 0x0, "Mirage Core PC Floppy"},
+ {HPHW_FIO, 0x02A, 0x00083, 0x0, "Electra Core PC Floppy"},
+ {HPHW_FIO, 0x02B, 0x00083, 0x0, "Mirage 80 Core PC Floppy"},
+ {HPHW_FIO, 0x02C, 0x00083, 0x0, "Mirage 100+ Core PC Floppy"},
+ {HPHW_FIO, 0x02E, 0x00083, 0x0, "UL 350 Core PC Floppy"},
+ {HPHW_FIO, 0x02F, 0x00083, 0x0, "UL 550 Core PC Floppy"},
+ {HPHW_FIO, 0x032, 0x00083, 0x0, "Raven T' Core PC Floppy"},
+ {HPHW_FIO, 0x034, 0x00083, 0x0, "SAIC L-80 Core PC Floppy"},
+ {HPHW_FIO, 0x035, 0x00083, 0x0, "PCX-L2 712/132 Core Floppy"},
+ {HPHW_FIO, 0x036, 0x00083, 0x0, "PCX-L2 712/160 Core Floppy"},
+ {HPHW_FIO, 0x03B, 0x00083, 0x0, "Raven U/L2 Core PC Floppy"},
+ {HPHW_FIO, 0x03C, 0x00083, 0x0, "Merlin 132 Core PC Floppy"},
+ {HPHW_FIO, 0x03D, 0x00083, 0x0, "Merlin 160 Core PC Floppy"},
+ {HPHW_FIO, 0x03E, 0x00083, 0x0, "Merlin+ 132 Core PC Floppy"},
+ {HPHW_FIO, 0x03F, 0x00083, 0x0, "Merlin+ 180 Core PC Floppy"},
+ {HPHW_FIO, 0x045, 0x00083, 0x0, "Rocky1 Core PC Floppy"},
+ {HPHW_FIO, 0x046, 0x00083, 0x0, "Rocky2 120 Core PC Floppy"},
+ {HPHW_FIO, 0x047, 0x00083, 0x0, "Rocky2 150 Core PC Floppy"},
+ {HPHW_FIO, 0x04E, 0x00083, 0x0, "Kiji L2 132 Core PC Floppy"},
+ {HPHW_FIO, 0x050, 0x00083, 0x0, "Merlin Jr 132 Core PC Floppy"},
+ {HPHW_FIO, 0x056, 0x00083, 0x0, "Raven+ w SE FWSCSI Core PC Floppy"},
+ {HPHW_FIO, 0x057, 0x00083, 0x0, "Raven+ w Diff FWSCSI Core PC Floppy"},
+ {HPHW_FIO, 0x800, 0x00083, 0x0, "Hitachi Tiny 64 Core PC Floppy"},
+ {HPHW_FIO, 0x801, 0x00083, 0x0, "Hitachi Tiny 80 Core PC Floppy"},
+ {HPHW_FIO, 0x015, 0x00084, 0x0, "KittyHawk GSY Core PS/2 Port"},
+ {HPHW_FIO, 0x016, 0x00084, 0x0, "Gecko Core PS/2 Port"},
+ {HPHW_FIO, 0x018, 0x00084, 0x0, "Gecko Optional PS/2 Port"},
+ {HPHW_FIO, 0x01A, 0x00084, 0x0, "Anole 64 Core PS/2 Port"},
+ {HPHW_FIO, 0x01B, 0x00084, 0x0, "Anole 100 Core PS/2 Port"},
+ {HPHW_FIO, 0x01C, 0x00084, 0x0, "Gecko 80 Core PS/2 Port"},
+ {HPHW_FIO, 0x01D, 0x00084, 0x0, "Gecko 100 Core PS/2 Port"},
+ {HPHW_FIO, 0x01F, 0x00084, 0x0, "SkyHawk 100/120 Core PS/2 Port"},
+ {HPHW_FIO, 0x027, 0x00084, 0x0, "Piranha 100 Core PS/2 Port"},
+ {HPHW_FIO, 0x028, 0x00084, 0x0, "Mirage Jr Core PS/2 Port"},
+ {HPHW_FIO, 0x029, 0x00084, 0x0, "Mirage Core PS/2 Port"},
+ {HPHW_FIO, 0x02A, 0x00084, 0x0, "Electra Core PS/2 Port"},
+ {HPHW_FIO, 0x02B, 0x00084, 0x0, "Mirage 80 Core PS/2 Port"},
+ {HPHW_FIO, 0x02C, 0x00084, 0x0, "Mirage 100+ Core PS/2 Port"},
+ {HPHW_FIO, 0x02E, 0x00084, 0x0, "UL 350 Core PS/2 Port"},
+ {HPHW_FIO, 0x02F, 0x00084, 0x0, "UL 550 Core PS/2 Port"},
+ {HPHW_FIO, 0x032, 0x00084, 0x0, "Raven T' Core PS/2 Port"},
+ {HPHW_FIO, 0x033, 0x00084, 0x0, "Anole T Core PS/2 Port"},
+ {HPHW_FIO, 0x034, 0x00084, 0x0, "SAIC L-80 Core PS/2 Port"},
+ {HPHW_FIO, 0x035, 0x00084, 0x0, "PCX-L2 712/132 Core PS/2 Port"},
+ {HPHW_FIO, 0x036, 0x00084, 0x0, "PCX-L2 712/160 Core PS/2 Port"},
+ {HPHW_FIO, 0x03B, 0x00084, 0x0, "Raven U/L2 Core PS/2 Port"},
+ {HPHW_FIO, 0x03C, 0x00084, 0x0, "Merlin 132 Core PS/2 Port"},
+ {HPHW_FIO, 0x03D, 0x00084, 0x0, "Merlin 160 Core PS/2 Port"},
+ {HPHW_FIO, 0x03E, 0x00084, 0x0, "Merlin+ 132 Core PS/2 Port"},
+ {HPHW_FIO, 0x03F, 0x00084, 0x0, "Merlin+ 180 Core PS/2 Port"},
+ {HPHW_FIO, 0x044, 0x00084, 0x0, "Mohawk Core PS/2 Port"},
+ {HPHW_FIO, 0x045, 0x00084, 0x0, "Rocky1 Core PS/2 Port"},
+ {HPHW_FIO, 0x046, 0x00084, 0x0, "Rocky2 120 Core PS/2 Port"},
+ {HPHW_FIO, 0x047, 0x00084, 0x0, "Rocky2 150 Core PS/2 Port"},
+ {HPHW_FIO, 0x048, 0x00084, 0x0, "Rocky2 120 Dino PS/2 Port"},
+ {HPHW_FIO, 0x049, 0x00084, 0x0, "Rocky2 150 Dino PS/2 Port"},
+ {HPHW_FIO, 0x04B, 0x00084, 0x0, "Anole L2 132 Core PS/2 Port"},
+ {HPHW_FIO, 0x04D, 0x00084, 0x0, "Anole L2 165 Core PS/2 Port"},
+ {HPHW_FIO, 0x04E, 0x00084, 0x0, "Kiji L2 132 Core PS/2 Port"},
+ {HPHW_FIO, 0x050, 0x00084, 0x0, "Merlin Jr 132 Core PS/2 Port"},
+ {HPHW_FIO, 0x051, 0x00084, 0x0, "Firehawk Core PS/2 Port"},
+ {HPHW_FIO, 0x056, 0x00084, 0x0, "Raven+ w SE FWSCSI Core PS/2 Port"},
+ {HPHW_FIO, 0x057, 0x00084, 0x0, "Raven+ w Diff FWSCSI Core PS/2 Port"},
+ {HPHW_FIO, 0x058, 0x00084, 0x0, "FireHawk 200 Core PS/2 Port"},
+ {HPHW_FIO, 0x05C, 0x00084, 0x0, "SummitHawk 230 Core PS/2 Port"},
+ {HPHW_FIO, 0x800, 0x00084, 0x0, "Hitachi Tiny 64 Core PS/2 Port"},
+ {HPHW_FIO, 0x801, 0x00084, 0x0, "Hitachi Tiny 80 Core PS/2 Port"},
+ {HPHW_FIO, 0x004, 0x00085, 0x0, "Solo GSC Optional Graphics"},
+ {HPHW_FIO, 0x005, 0x00085, 0x0, "Duet GSC Optional Graphics"},
+ {HPHW_FIO, 0x008, 0x00085, 0x0, "Anole Artist Optional Graphics"},
+ {HPHW_FIO, 0x010, 0x00085, 0x0, "Mirage 80 GSC Builtin Graphics"},
+ {HPHW_FIO, 0x011, 0x00085, 0x0, "Mirage 100+ GSC Builtin Graphics"},
+ {HPHW_FIO, 0x012, 0x00085, 0x0, "Mirage Jr GSC Builtin Graphics"},
+ {HPHW_FIO, 0x013, 0x00085, 0x0, "Mirage GSC Builtin Graphics"},
+ {HPHW_FIO, 0x014, 0x00085, 0x0, "Electra GSC Builtin Graphics"},
+ {HPHW_FIO, 0x016, 0x00085, 0x0, "Gecko GSC Core Graphics"},
+ {HPHW_FIO, 0x017, 0x00085, 0x0, "Gecko GSC Optional Graphics"},
+ {HPHW_FIO, 0x01A, 0x00085, 0x0, "Anole 64 Artist Builtin Graphics"},
+ {HPHW_FIO, 0x01B, 0x00085, 0x0, "Anole 100 Artist Builtin Graphics"},
+ {HPHW_FIO, 0x01C, 0x00085, 0x0, "Gecko 80 GSC Core Graphics"},
+ {HPHW_FIO, 0x01D, 0x00085, 0x0, "Gecko 100 GSC Core Graphics"},
+ {HPHW_FIO, 0x032, 0x00085, 0x0, "Raven T' GSC Core Graphics"},
+ {HPHW_FIO, 0x033, 0x00085, 0x0, "Anole T Artist Builtin Graphics"},
+ {HPHW_FIO, 0x034, 0x00085, 0x0, "SAIC L-80 GSC Core Graphics"},
+ {HPHW_FIO, 0x035, 0x00085, 0x0, "PCX-L2 712/132 Core Graphics"},
+ {HPHW_FIO, 0x036, 0x00085, 0x0, "PCX-L2 712/160 Core Graphics"},
+ {HPHW_FIO, 0x03B, 0x00085, 0x0, "Raven U/L2 Core Graphics"},
+ {HPHW_FIO, 0x03C, 0x00085, 0x0, "Merlin 132 Core Graphics"},
+ {HPHW_FIO, 0x03D, 0x00085, 0x0, "Merlin 160 Core Graphics"},
+ {HPHW_FIO, 0x03E, 0x00085, 0x0, "Merlin+ 132 Core Graphics"},
+ {HPHW_FIO, 0x03F, 0x00085, 0x0, "Merlin+ 180 Core Graphics"},
+ {HPHW_FIO, 0x045, 0x00085, 0x0, "Rocky1 Core Graphics"},
+ {HPHW_FIO, 0x046, 0x00085, 0x0, "Rocky2 120 Core Graphics"},
+ {HPHW_FIO, 0x047, 0x00085, 0x0, "Rocky2 150 Core Graphics"},
+ {HPHW_FIO, 0x04B, 0x00085, 0x0, "Anole L2 132 Core Graphics"},
+ {HPHW_FIO, 0x04D, 0x00085, 0x0, "Anole L2 165 Core Graphics"},
+ {HPHW_FIO, 0x04E, 0x00085, 0x0, "Kiji L2 132 Core Graphics"},
+ {HPHW_FIO, 0x050, 0x00085, 0x0, "Merlin Jr 132 Core Graphics"},
+ {HPHW_FIO, 0x056, 0x00085, 0x0, "Raven+ w SE FWSCSI Core Graphics"},
+ {HPHW_FIO, 0x057, 0x00085, 0x0, "Raven+ w Diff FWSCSI Core Graphics"},
+ {HPHW_FIO, 0x800, 0x00085, 0x0, "Hitachi Tiny 64 Core Graphics"},
+ {HPHW_FIO, 0x801, 0x00085, 0x0, "Hitachi Tiny 80 Core Graphics"},
+ {HPHW_FIO, 0x004, 0x00086, 0x0, "GSC IBM Token Ring"},
+ {HPHW_FIO, 0x015, 0x00087, 0x0, "Gecko Optional ISDN"},
+ {HPHW_FIO, 0x016, 0x00087, 0x0, "Gecko Core ISDN"},
+ {HPHW_FIO, 0x01C, 0x00087, 0x0, "Gecko 80 Core ISDN"},
+ {HPHW_FIO, 0x01D, 0x00087, 0x0, "Gecko 100 Core ISDN"},
+ {HPHW_FIO, 0x010, 0x00088, 0x0, "Pace VME Networking"},
+ {HPHW_FIO, 0x011, 0x00088, 0x0, "Sidewinder VME Networking"},
+ {HPHW_FIO, 0x01A, 0x00088, 0x0, "Anole 64 VME Networking"},
+ {HPHW_FIO, 0x01B, 0x00088, 0x0, "Anole 100 VME Networking"},
+ {HPHW_FIO, 0x024, 0x00088, 0x0, "Fast Pace VME Networking"},
+ {HPHW_FIO, 0x034, 0x00088, 0x0, "Anole T VME Networking"},
+ {HPHW_FIO, 0x04A, 0x00088, 0x0, "Anole L2 132 VME Networking"},
+ {HPHW_FIO, 0x04C, 0x00088, 0x0, "Anole L2 165 VME Networking"},
+ {HPHW_FIO, 0x011, 0x0008A, 0x0, "WB-96 Core LAN (802.3)"},
+ {HPHW_FIO, 0x012, 0x0008A, 0x0, "Orville Core LAN (802.3)"},
+ {HPHW_FIO, 0x013, 0x0008A, 0x0, "Wilbur Core LAN (802.3)"},
+ {HPHW_FIO, 0x014, 0x0008A, 0x0, "WB-80 Core LAN (802.3)"},
+ {HPHW_FIO, 0x015, 0x0008A, 0x0, "KittyHawk GSY Core LAN (802.3)"},
+ {HPHW_FIO, 0x016, 0x0008A, 0x0, "Gecko Core LAN (802.3)"},
+ {HPHW_FIO, 0x018, 0x0008A, 0x0, "Gecko Optional LAN (802.3)"},
+ {HPHW_FIO, 0x01A, 0x0008A, 0x0, "Anole 64 Core LAN (802.3)"},
+ {HPHW_FIO, 0x01B, 0x0008A, 0x0, "Anole 100 Core LAN (802.3)"},
+ {HPHW_FIO, 0x01C, 0x0008A, 0x0, "Gecko 80 Core LAN (802.3)"},
+ {HPHW_FIO, 0x01D, 0x0008A, 0x0, "Gecko 100 Core LAN (802.3)"},
+ {HPHW_FIO, 0x01F, 0x0008A, 0x0, "SkyHawk 100/120 Core LAN (802.3)"},
+ {HPHW_FIO, 0x027, 0x0008A, 0x0, "Piranha 100 Core LAN (802.3)"},
+ {HPHW_FIO, 0x028, 0x0008A, 0x0, "Mirage Jr Core LAN (802.3)"},
+ {HPHW_FIO, 0x029, 0x0008A, 0x0, "Mirage Core LAN (802.3)"},
+ {HPHW_FIO, 0x02A, 0x0008A, 0x0, "Electra Core LAN (802.3)"},
+ {HPHW_FIO, 0x02B, 0x0008A, 0x0, "Mirage 80 Core LAN (802.3)"},
+ {HPHW_FIO, 0x02C, 0x0008A, 0x0, "Mirage 100+ Core LAN (802.3)"},
+ {HPHW_FIO, 0x02E, 0x0008A, 0x0, "UL 350 Core LAN (802.3)"},
+ {HPHW_FIO, 0x02F, 0x0008A, 0x0, "UL 350 Core LAN (802.3)"},
+ {HPHW_FIO, 0x032, 0x0008A, 0x0, "Raven T' Core LAN (802.3)"},
+ {HPHW_FIO, 0x033, 0x0008A, 0x0, "Anole T Core LAN (802.3)"},
+ {HPHW_FIO, 0x034, 0x0008A, 0x0, "SAIC L-80 Core LAN (802.3)"},
+ {HPHW_FIO, 0x035, 0x0008A, 0x0, "PCX-L2 712/132 Core LAN (802.3)"},
+ {HPHW_FIO, 0x036, 0x0008A, 0x0, "PCX-L2 712/160 Core LAN (802.3)"},
+ {HPHW_FIO, 0x03B, 0x0008A, 0x0, "Raven U/L2 Core LAN (802.3)"},
+ {HPHW_FIO, 0x03C, 0x0008A, 0x0, "Merlin 132 Core LAN (802.3)"},
+ {HPHW_FIO, 0x03D, 0x0008A, 0x0, "Merlin 160 Core LAN (802.3)"},
+ {HPHW_FIO, 0x044, 0x0008A, 0x0, "Mohawk Core LAN (802.3)"},
+ {HPHW_FIO, 0x045, 0x0008A, 0x0, "Rocky1 Core LAN (802.3)"},
+ {HPHW_FIO, 0x046, 0x0008A, 0x0, "Rocky2 120 Core LAN (802.3)"},
+ {HPHW_FIO, 0x047, 0x0008A, 0x0, "Rocky2 150 Core LAN (802.3)"},
+ {HPHW_FIO, 0x04B, 0x0008A, 0x0, "Anole L2 132 Core LAN (802.3)"},
+ {HPHW_FIO, 0x04D, 0x0008A, 0x0, "Anole L2 165 Core LAN (802.3)"},
+ {HPHW_FIO, 0x04E, 0x0008A, 0x0, "Kiji L2 132 Core LAN (802.3)"},
+ {HPHW_FIO, 0x050, 0x0008A, 0x0, "Merlin Jr 132 Core LAN (802.3)"},
+ {HPHW_FIO, 0x058, 0x0008A, 0x0, "FireHawk 200 Core LAN (802.3)"},
+ {HPHW_FIO, 0x800, 0x0008A, 0x0, "Hitachi Tiny 64 Core LAN (802.3)"},
+ {HPHW_FIO, 0x801, 0x0008A, 0x0, "Hitachi Tiny 80 Core LAN (802.3)"},
+ {HPHW_FIO, 0x004, 0x0008C, 0x0, "SkyHawk 100/120 Wax RS-232"},
+ {HPHW_FIO, 0x005, 0x0008C, 0x0, "SAIC L-80 Wax RS-232"},
+ {HPHW_FIO, 0x006, 0x0008C, 0x0, "Raven U/L2 Dino RS-232"},
+ {HPHW_FIO, 0x007, 0x0008C, 0x0, "Dino RS-232"},
+ {HPHW_FIO, 0x008, 0x0008C, 0x0, "Merlin 132 Dino RS-232"},
+ {HPHW_FIO, 0x009, 0x0008C, 0x0, "Merlin 160 Dino RS-232"},
+ {HPHW_FIO, 0x00A, 0x0008C, 0x0, "Merlin Jr 132 Dino RS-232"},
+ {HPHW_FIO, 0x010, 0x0008C, 0x0, "Mirage 80 Wax RS-232"},
+ {HPHW_FIO, 0x011, 0x0008C, 0x0, "Mirage 100+ Wax RS-232"},
+ {HPHW_FIO, 0x012, 0x0008C, 0x0, "Mirage Jr Wax RS-232"},
+ {HPHW_FIO, 0x013, 0x0008C, 0x0, "Mirage Wax RS-232"},
+ {HPHW_FIO, 0x014, 0x0008C, 0x0, "Electra Wax RS-232"},
+ {HPHW_FIO, 0x015, 0x0008C, 0x0, "KittyHawk GSY Core RS-232"},
+ {HPHW_FIO, 0x016, 0x0008C, 0x0, "Gecko Core RS-232"},
+ {HPHW_FIO, 0x017, 0x0008C, 0x0, "Raven Backplane RS-232"},
+ {HPHW_FIO, 0x018, 0x0008C, 0x0, "Gecko Optional RS-232"},
+ {HPHW_FIO, 0x019, 0x0008C, 0x0, "Merlin+ 180 Dino RS-232"},
+ {HPHW_FIO, 0x01A, 0x0008C, 0x0, "Anole 64 Core RS-232"},
+ {HPHW_FIO, 0x01B, 0x0008C, 0x0, "Anole 100 Core RS-232"},
+ {HPHW_FIO, 0x01C, 0x0008C, 0x0, "Gecko 80 Core RS-232"},
+ {HPHW_FIO, 0x01D, 0x0008C, 0x0, "Gecko 100 Core RS-232"},
+ {HPHW_FIO, 0x01E, 0x0008C, 0x0, "Raven T' Wax RS-232"},
+ {HPHW_FIO, 0x01F, 0x0008C, 0x0, "SkyHawk 100/120 Core RS-232"},
+ {HPHW_FIO, 0x020, 0x0008C, 0x0, "Anole 64 Timi RS-232"},
+ {HPHW_FIO, 0x021, 0x0008C, 0x0, "Anole 100 Timi RS-232"},
+ {HPHW_FIO, 0x022, 0x0008C, 0x0, "Merlin+ 132 Dino RS-232"},
+ {HPHW_FIO, 0x023, 0x0008C, 0x0, "Rocky1 Wax RS-232"},
+ {HPHW_FIO, 0x025, 0x0008C, 0x0, "Armyknife Optional RS-232"},
+ {HPHW_FIO, 0x026, 0x0008C, 0x0, "Piranha 100 Wax RS-232"},
+ {HPHW_FIO, 0x027, 0x0008C, 0x0, "Piranha 100 Core RS-232"},
+ {HPHW_FIO, 0x028, 0x0008C, 0x0, "Mirage Jr Core RS-232"},
+ {HPHW_FIO, 0x029, 0x0008C, 0x0, "Mirage Core RS-232"},
+ {HPHW_FIO, 0x02A, 0x0008C, 0x0, "Electra Core RS-232"},
+ {HPHW_FIO, 0x02B, 0x0008C, 0x0, "Mirage 80 Core RS-232"},
+ {HPHW_FIO, 0x02C, 0x0008C, 0x0, "Mirage 100+ Core RS-232"},
+ {HPHW_FIO, 0x02E, 0x0008C, 0x0, "UL 350 Lasi Core RS-232"},
+ {HPHW_FIO, 0x02F, 0x0008C, 0x0, "UL 550 Lasi Core RS-232"},
+ {HPHW_FIO, 0x030, 0x0008C, 0x0, "UL 350 Wax Core RS-232"},
+ {HPHW_FIO, 0x031, 0x0008C, 0x0, "UL 550 Wax Core RS-232"},
+ {HPHW_FIO, 0x032, 0x0008C, 0x0, "Raven T' Lasi Core RS-232"},
+ {HPHW_FIO, 0x033, 0x0008C, 0x0, "Anole T Core RS-232"},
+ {HPHW_FIO, 0x034, 0x0008C, 0x0, "SAIC L-80 Core RS-232"},
+ {HPHW_FIO, 0x035, 0x0008C, 0x0, "PCX-L2 712/132 Core RS-232"},
+ {HPHW_FIO, 0x036, 0x0008C, 0x0, "PCX-L2 712/160 Core RS-232"},
+ {HPHW_FIO, 0x03A, 0x0008C, 0x0, "Merlin+ Wax RS-232"},
+ {HPHW_FIO, 0x03B, 0x0008C, 0x0, "Raven U/L2 Core RS-232"},
+ {HPHW_FIO, 0x03C, 0x0008C, 0x0, "Merlin 132 Core RS-232"},
+ {HPHW_FIO, 0x03D, 0x0008C, 0x0, "Merlin 160 Core RS-232"},
+ {HPHW_FIO, 0x03E, 0x0008C, 0x0, "Merlin+ 132 Core RS-232"},
+ {HPHW_FIO, 0x03F, 0x0008C, 0x0, "Merlin+ 180 Core RS-232"},
+ {HPHW_FIO, 0x040, 0x0008C, 0x0, "Merlin 132 Wax RS-232"},
+ {HPHW_FIO, 0x041, 0x0008C, 0x0, "Merlin 160 Wax RS-232"},
+ {HPHW_FIO, 0x043, 0x0008C, 0x0, "Merlin 132/160 Wax RS-232"},
+ {HPHW_FIO, 0x044, 0x0008C, 0x0, "Mohawk Core RS-232"},
+ {HPHW_FIO, 0x045, 0x0008C, 0x0, "Rocky1 Core RS-232"},
+ {HPHW_FIO, 0x046, 0x0008C, 0x0, "Rocky2 120 Core RS-232"},
+ {HPHW_FIO, 0x047, 0x0008C, 0x0, "Rocky2 150 Core RS-232"},
+ {HPHW_FIO, 0x048, 0x0008C, 0x0, "Rocky2 120 Dino RS-232"},
+ {HPHW_FIO, 0x049, 0x0008C, 0x0, "Rocky2 150 Dino RS-232"},
+ {HPHW_FIO, 0x04A, 0x0008C, 0x0, "Anole L2 132 TIMI RS-232"},
+ {HPHW_FIO, 0x04B, 0x0008C, 0x0, "Anole L2 l32 Core RS-232"},
+ {HPHW_FIO, 0x04C, 0x0008D, 0x0, "Anole L2 165 TIMI RS-232"},
+ {HPHW_FIO, 0x04D, 0x0008C, 0x0, "Anole L2 165 Core RS-232"},
+ {HPHW_FIO, 0x04E, 0x0008C, 0x0, "Kiji L2 132 Core RS-232"},
+ {HPHW_FIO, 0x04F, 0x0008C, 0x0, "Kiji L2 132 Dino RS-232"},
+ {HPHW_FIO, 0x050, 0x0008C, 0x0, "Merlin Jr 132 Core RS-232"},
+ {HPHW_FIO, 0x051, 0x0008C, 0x0, "Firehawk Core RS-232"},
+ {HPHW_FIO, 0x052, 0x0008C, 0x0, "Raven+ Hi Power Backplane w EISA RS-232"},
+ {HPHW_FIO, 0x053, 0x0008C, 0x0, "Raven+ Hi Power Backplane w/o EISA RS-232"},
+ {HPHW_FIO, 0x054, 0x0008C, 0x0, "Raven+ Lo Power Backplane w EISA RS-232"},
+ {HPHW_FIO, 0x055, 0x0008C, 0x0, "Raven+ Lo Power Backplane w/o EISA RS-232"},
+ {HPHW_FIO, 0x056, 0x0008C, 0x0, "Raven+ w SE FWSCSI Core RS-232"},
+ {HPHW_FIO, 0x057, 0x0008C, 0x0, "Raven+ w Diff FWSCSI Core RS-232"},
+ {HPHW_FIO, 0x058, 0x0008C, 0x0, "FireHawk 200 Core RS-232"},
+ {HPHW_FIO, 0x059, 0x0008C, 0x0, "FireHawk 200 Wax RS-232"},
+ {HPHW_FIO, 0x05A, 0x0008C, 0x0, "Raven+ L2 Backplane w EISA RS-232"},
+ {HPHW_FIO, 0x05B, 0x0008C, 0x0, "Raven+ L2 Backplane w/o EISA RS-232"},
+ {HPHW_FIO, 0x05D, 0x0008C, 0x0, "SummitHawk Dino RS-232"},
+ {HPHW_FIO, 0x05E, 0x0008C, 0x0, "Staccato 132 Core LAN RS-232"},
+ {HPHW_FIO, 0x05F, 0x0008C, 0x0, "Staccato 180 Core LAN RS-232"},
+ {HPHW_FIO, 0x800, 0x0008C, 0x0, "Hitachi Tiny 64 Core RS-232"},
+ {HPHW_FIO, 0x801, 0x0008C, 0x0, "Hitachi Tiny 80 Core RS-232"},
+ {HPHW_FIO, 0x015, 0x0008D, 0x0, "Gecko Optional RJ-16"},
+ {HPHW_FIO, 0x016, 0x0008D, 0x0, "Gecko Core RJ-16"},
+ {HPHW_FIO, 0x01C, 0x0008D, 0x0, "Gecko 80 Core RJ-16"},
+ {HPHW_FIO, 0x01D, 0x0008D, 0x0, "Gecko 100 Core RJ-16"},
+ {HPHW_FIO, 0x004, 0x0008F, 0x0, "Anole Boot Rom"},
+ {HPHW_FIO, 0x005, 0x0008F, 0x0, "Rocky1 Boot Rom"},
+ {HPHW_FIO, 0x006, 0x0008F, 0x0, "Rocky2 120 Boot Rom"},
+ {HPHW_FIO, 0x007, 0x0008F, 0x0, "Rocky2 150 Boot Rom"},
+ {HPHW_FIO, 0x01B, 0x0008F, 0x0, "Anole 100 Boot Rom"},
+ {HPHW_FIO, 0x006, 0x00096, 0x0, "Raven U/L2 Dino PS/2 Port"},
+ {HPHW_FIO, 0x007, 0x00096, 0x0, "Dino PS/2 Port"},
+ {HPHW_FIO, 0x008, 0x00096, 0x0, "Merlin 132 Dino PS/2 Port"},
+ {HPHW_FIO, 0x009, 0x00096, 0x0, "Merlin 160 Dino PS/2 Port"},
+ {HPHW_FIO, 0x00A, 0x00096, 0x0, "Merlin Jr 132 Dino PS/2 Port"},
+ {HPHW_FIO, 0x019, 0x00096, 0x0, "Merlin+ 180 Dino PS/2 Port"},
+ {HPHW_FIO, 0x022, 0x00096, 0x0, "Merlin+ 132 Dino PS/2 Port"},
+ {HPHW_FIO, 0x004, 0x00097, 0x0, "Cascade EISA 100VG LAN"},
+ {HPHW_FIO, 0x023, 0x00099, 0x0, "Rocky1 Wax HPIB"},
+ {HPHW_FIO, 0x048, 0x00099, 0x0, "Rocky2 120 Clark/Dino HPIB"},
+ {HPHW_FIO, 0x049, 0x00099, 0x0, "Rocky2 150 Clark/Dino HPIB"},
+ {HPHW_FIO, 0x004, 0x000A1, 0x0, "SPP2000 Console TTY"},
+ {HPHW_FIO, 0x004, 0x000A2, 0x0, "Forte Core PCI 10/100BT LAN"},
+ {HPHW_FIO, 0x005, 0x000A2, 0x0, "AllegroLow PCI 10/100BT LAN"},
+ {HPHW_FIO, 0x006, 0x000A2, 0x0, "AllegroHIgh Core PCI 10/100BT LAN"},
+ {HPHW_FIO, 0x007, 0x000A2, 0x0, "PCI Plug-in LAN"},
+ {HPHW_FIO, 0x00A, 0x000A2, 0x0, "Lego 360 Core PCI 10/100BT LAN"},
+ {HPHW_FIO, 0x03E, 0x000A2, 0x0, "Merlin+ 132 Core PCI LAN"},
+ {HPHW_FIO, 0x03F, 0x000A2, 0x0, "Merlin+ 180 Core PCI LAN"},
+ {HPHW_FIO, 0x056, 0x000A2, 0x0, "Raven+ w SE FWSCSI Core PCI LAN"},
+ {HPHW_FIO, 0x057, 0x000A2, 0x0, "Raven+ w Diff FWSCSI Core PCI LAN"},
+ {HPHW_FIO, 0x05E, 0x000A2, 0x0, "Staccato 132 PCI LAN"},
+ {HPHW_FIO, 0x05F, 0x000A2, 0x0, "Staccato 180 PCI LAN"},
+ {HPHW_FIO, 0x004, 0x000A3, 0x0, "Forte Core PCI LVD Ultra2 SCSI"},
+ {HPHW_FIO, 0x004, 0x000A3, 0x0, "Forte Core PCI SE UltraSCSI"},
+ {HPHW_FIO, 0x004, 0x000A3, 0x0, "Forte Core PCI IDE/ATAPI CD-ROM"},
+ {HPHW_FIO, 0x005, 0x000A3, 0x0, "AllegroLow Core PCI LVD Ultra2 SCSI"},
+ {HPHW_FIO, 0x005, 0x000A3, 0x0, "AllegroLow Core PCI IDE/ATAPI CD-ROM"},
+ {HPHW_FIO, 0x006, 0x000A3, 0x0, "AllegroHigh Core PCI LVD Ultra2 SCSI"},
+ {HPHW_FIO, 0x006, 0x000A3, 0x0, "AllegroHigh Core PCI IDE/ATAPI CD-ROM"},
+ {HPHW_FIO, 0x007, 0x000A3, 0x0, "PCI Plug-in Disk"},
+ {HPHW_FIO, 0x008, 0x000A3, 0x0, "A5158A S FC Tachlite HBA"},
+ {HPHW_FIO, 0x009, 0x000A3, 0x0, "A5157A D FC HBA"},
+ {HPHW_FIO, 0x00A, 0x000A3, 0x0, "Lego 360 Core PCI LVD Ultra2 SCSI"},
+ {HPHW_FIO, 0x00A, 0x000A3, 0x0, "Lego 360 Core PCI NSE UltraSCSI"},
+ {HPHW_FIO, 0x00A, 0x000A3, 0x0, "Lego 360 Core PCI WSE UltraSCSI"},
+ {HPHW_FIO, 0x00A, 0x000A3, 0x0, "Lego 360 Core PCI IDE/ATAPI CD-ROM"},
+ {HPHW_FIO, 0x03E, 0x000A3, 0x0, "Merlin+ 132 Core SE FWSCSI PCI Disk"},
+ {HPHW_FIO, 0x03F, 0x000A3, 0x0, "Merlin+ 180 Core SE FWSCSI PCI Disk"},
+ {HPHW_FIO, 0x056, 0x000A3, 0x0, "Raven+ w SE FWSCSI Core PCI Disk"},
+ {HPHW_FIO, 0x057, 0x000A3, 0x0, "Raven+ w Diff FWSCSI Core PCI Disk"},
+ {HPHW_FIO, 0x004, 0x000A4, 0x0, "SPP2000 Core BA"},
+ {HPHW_FIO, 0x004, 0x000A6, 0x0, "Sonic Ethernet 802.3 Card"},
+ {HPHW_FIO, 0x004, 0x000A9, 0x00, "Forte Core PCI SuperIO RS-232"},
+ {HPHW_FIO, 0x004, 0x000A9, 0x00, "Forte Core PCI USB KB"},
+ {HPHW_FIO, 0x005, 0x000A9, 0x00, "AllegroLow Core PCI SuperIO RS-232"},
+ {HPHW_FIO, 0x005, 0x000A9, 0x00, "AllegroLow Core PCI USB KB"},
+ {HPHW_FIO, 0x006, 0x000A9, 0x00, "AllegroHigh Core PCI SuperIO RS-232"},
+ {HPHW_FIO, 0x006, 0x000A9, 0x00, "AllegroHigh Core PCI USB KB"},
+ {HPHW_FIO, 0x007, 0x000A9, 0x0, "Miscellaneous PCI Plug-in"},
+ {HPHW_FIO, 0x00A, 0x000A9, 0x0, "Lego 360 Core PCI SuperIO RS-232"},
+ {HPHW_FIO, 0x00A, 0x000A9, 0x0, "Lego 360 Core PCI USB KB"},
+ {HPHW_FIO, 0x004, 0x00320, 0x0, "Metheus Frame Buffer"},
+ {HPHW_FIO, 0x004, 0x00340, 0x0, "BARCO CX4500 VME Grphx Cnsl"},
+ {HPHW_FIO, 0x004, 0x00360, 0x0, "Hughes TOG VME FDDI"},
+ {HPHW_FIO, 0x076, 0x000AD, 0x0, "Crestone Peak Core RS-232"},
+ {HPHW_FIO, 0x077, 0x000AD, 0x0, "Crestone Peak Fast Core RS-232"},
+ {HPHW_IOA, 0x185, 0x0000B, 0x00, "Java BC Summit Port"},
+ {HPHW_IOA, 0x1FF, 0x0000B, 0x00, "Hitachi Ghostview Summit Port"},
+ {HPHW_IOA, 0x580, 0x0000B, 0x10, "U2-IOA BC Runway Port"},
+ {HPHW_IOA, 0x581, 0x0000B, 0x10, "Uturn-IOA BC Runway Port"},
+ {HPHW_IOA, 0x582, 0x0000B, 0x10, "Astro BC Runway Port"},
+ {HPHW_IOA, 0x700, 0x0000B, 0x00, "NEC-IOS BC System Bus Port"},
+ {HPHW_IOA, 0x880, 0x0000C, 0x10, "Pluto BC McKinley Port"},
+ {HPHW_MEMORY, 0x002, 0x00008, 0x00, "MID_BUS"},
+ {HPHW_MEMORY, 0x063, 0x00009, 0x00, "712/132 L2 Upgrade"},
+ {HPHW_MEMORY, 0x064, 0x00009, 0x00, "712/160 L2 Upgrade"},
+ {HPHW_MEMORY, 0x065, 0x00009, 0x00, "715/132 L2 Upgrade"},
+ {HPHW_MEMORY, 0x066, 0x00009, 0x00, "715/160 L2 Upgrade"},
+ {HPHW_MEMORY, 0x0AF, 0x00009, 0x00, "Everest Mako Memory"},
+ {HPHW_OTHER, 0x004, 0x00030, 0x00, "Master"},
+ {HPHW_OTHER, 0x004, 0x00034, 0x00, "Slave"},
+ {HPHW_OTHER, 0x004, 0x00038, 0x00, "EDU"},
+ {HPHW_OTHER, 0x004, 0x00049, 0x00, "LGB Control"},
+ {HPHW_MC, 0x004, 0x000C0, 0x00, "BMC IPMI Mgmt Ctlr"},
+ {HPHW_FAULTY, 0, } /* Special Marker for last entry */
+};
+
+
+static struct hp_cpu_type_mask {
+ unsigned short model;
+ unsigned short mask;
+ enum cpu_type cpu;
+} hp_cpu_type_mask_list[] __initdata = {
+
+ { 0x0000, 0x0ff0, pcx }, /* 0x0000 - 0x000f */
+ { 0x0048, 0x0ff0, pcxl }, /* 0x0040 - 0x004f */
+ { 0x0080, 0x0ff0, pcx }, /* 0x0080 - 0x008f */
+ { 0x0100, 0x0ff0, pcx }, /* 0x0100 - 0x010f */
+ { 0x0182, 0x0ffe, pcx }, /* 0x0182 - 0x0183 */
+ { 0x0182, 0x0ffe, pcxt }, /* 0x0182 - 0x0183 */
+ { 0x0184, 0x0fff, pcxu }, /* 0x0184 - 0x0184 */
+ { 0x0200, 0x0ffe, pcxs }, /* 0x0200 - 0x0201 */
+ { 0x0202, 0x0fff, pcxs }, /* 0x0202 - 0x0202 */
+ { 0x0203, 0x0fff, pcxt }, /* 0x0203 - 0x0203 */
+ { 0x0204, 0x0ffc, pcxt }, /* 0x0204 - 0x0207 */
+ { 0x0280, 0x0ffc, pcxs }, /* 0x0280 - 0x0283 */
+ { 0x0284, 0x0ffc, pcxt }, /* 0x0284 - 0x0287 */
+ { 0x0288, 0x0fff, pcxt }, /* 0x0288 - 0x0288 */
+ { 0x0300, 0x0ffc, pcxs }, /* 0x0300 - 0x0303 */
+ { 0x0310, 0x0ff0, pcxt }, /* 0x0310 - 0x031f */
+ { 0x0320, 0x0ff0, pcxt }, /* 0x0320 - 0x032f */
+ { 0x0400, 0x0ff0, pcxt }, /* 0x0400 - 0x040f */
+ { 0x0480, 0x0ff0, pcxl }, /* 0x0480 - 0x048f */
+ { 0x0500, 0x0ff0, pcxl2 }, /* 0x0500 - 0x050f */
+ { 0x0510, 0x0ff0, pcxl2 }, /* 0x0510 - 0x051f */
+ { 0x0580, 0x0ff8, pcxt_ }, /* 0x0580 - 0x0587 */
+ { 0x0588, 0x0ffc, pcxt_ }, /* 0x0588 - 0x058b */
+ { 0x058c, 0x0ffe, pcxt_ }, /* 0x058c - 0x058d */
+ { 0x058e, 0x0fff, pcxt_ }, /* 0x058e - 0x058e */
+ { 0x058f, 0x0fff, pcxu }, /* 0x058f - 0x058f */
+ { 0x0590, 0x0ffe, pcxu }, /* 0x0590 - 0x0591 */
+ { 0x0592, 0x0fff, pcxt_ }, /* 0x0592 - 0x0592 */
+ { 0x0593, 0x0fff, pcxu }, /* 0x0593 - 0x0593 */
+ { 0x0594, 0x0ffc, pcxu }, /* 0x0594 - 0x0597 */
+ { 0x0598, 0x0ffe, pcxu_ }, /* 0x0598 - 0x0599 */
+ { 0x059a, 0x0ffe, pcxu }, /* 0x059a - 0x059b */
+ { 0x059c, 0x0fff, pcxu }, /* 0x059c - 0x059c */
+ { 0x059d, 0x0fff, pcxu_ }, /* 0x059d - 0x059d */
+ { 0x059e, 0x0fff, pcxt_ }, /* 0x059e - 0x059e */
+ { 0x059f, 0x0fff, pcxu }, /* 0x059f - 0x059f */
+ { 0x05a0, 0x0ffe, pcxt_ }, /* 0x05a0 - 0x05a1 */
+ { 0x05a2, 0x0ffe, pcxu }, /* 0x05a2 - 0x05a3 */
+ { 0x05a4, 0x0ffc, pcxu }, /* 0x05a4 - 0x05a7 */
+ { 0x05a8, 0x0ffc, pcxu }, /* 0x05a8 - 0x05ab */
+ { 0x05ad, 0x0fff, pcxu_ }, /* 0x05ad - 0x05ad */
+ { 0x05ae, 0x0ffe, pcxu_ }, /* 0x05ae - 0x05af */
+ { 0x05b0, 0x0ffe, pcxu_ }, /* 0x05b0 - 0x05b1 */
+ { 0x05b2, 0x0fff, pcxu_ }, /* 0x05b2 - 0x05b2 */
+ { 0x05b3, 0x0fff, pcxu }, /* 0x05b3 - 0x05b3 */
+ { 0x05b4, 0x0fff, pcxw }, /* 0x05b4 - 0x05b4 */
+ { 0x05b5, 0x0fff, pcxu_ }, /* 0x05b5 - 0x05b5 */
+ { 0x05b6, 0x0ffe, pcxu_ }, /* 0x05b6 - 0x05b7 */
+ { 0x05b8, 0x0ffe, pcxu_ }, /* 0x05b8 - 0x05b9 */
+ { 0x05ba, 0x0fff, pcxu_ }, /* 0x05ba - 0x05ba */
+ { 0x05bb, 0x0fff, pcxw }, /* 0x05bb - 0x05bb */
+ { 0x05bc, 0x0ffc, pcxw }, /* 0x05bc - 0x05bf */
+ { 0x05c0, 0x0ffc, pcxw }, /* 0x05c0 - 0x05c3 */
+ { 0x05c4, 0x0ffe, pcxw }, /* 0x05c4 - 0x05c5 */
+ { 0x05c6, 0x0fff, pcxw }, /* 0x05c6 - 0x05c6 */
+ { 0x05c7, 0x0fff, pcxw_ }, /* 0x05c7 - 0x05c7 */
+ { 0x05c8, 0x0ffc, pcxw }, /* 0x05c8 - 0x05cb */
+ { 0x05cc, 0x0ffe, pcxw }, /* 0x05cc - 0x05cd */
+ { 0x05ce, 0x0ffe, pcxw_ }, /* 0x05ce - 0x05cf */
+ { 0x05d0, 0x0ffc, pcxw_ }, /* 0x05d0 - 0x05d3 */
+ { 0x05d4, 0x0ffe, pcxw_ }, /* 0x05d4 - 0x05d5 */
+ { 0x05d6, 0x0fff, pcxw }, /* 0x05d6 - 0x05d6 */
+ { 0x05d7, 0x0fff, pcxw_ }, /* 0x05d7 - 0x05d7 */
+ { 0x05d8, 0x0ffc, pcxw_ }, /* 0x05d8 - 0x05db */
+ { 0x05dc, 0x0ffe, pcxw2 }, /* 0x05dc - 0x05dd */
+ { 0x05de, 0x0fff, pcxw_ }, /* 0x05de - 0x05de */
+ { 0x05df, 0x0fff, pcxw2 }, /* 0x05df - 0x05df */
+ { 0x05e0, 0x0ffc, pcxw2 }, /* 0x05e0 - 0x05e3 */
+ { 0x05e4, 0x0fff, pcxw2 }, /* 0x05e4 - 0x05e4 */
+ { 0x05e5, 0x0fff, pcxw_ }, /* 0x05e5 - 0x05e5 */
+ { 0x05e6, 0x0ffe, pcxw2 }, /* 0x05e6 - 0x05e7 */
+ { 0x05e8, 0x0ff8, pcxw2 }, /* 0x05e8 - 0x05ef */
+ { 0x05f0, 0x0ff0, pcxw2 }, /* 0x05f0 - 0x05ff */
+ { 0x0600, 0x0fe0, pcxl }, /* 0x0600 - 0x061f */
+ { 0x0880, 0x0ff0, mako }, /* 0x0880 - 0x088f */
+ { 0x0890, 0x0ff0, mako2 }, /* 0x0890 - 0x089f */
+ { 0x0000, 0x0000, pcx } /* terminate table */
+};
+
+const char * const cpu_name_version[][2] = {
+ [pcx] = { "PA7000 (PCX)", "1.0" },
+ [pcxs] = { "PA7000 (PCX-S)", "1.1a" },
+ [pcxt] = { "PA7100 (PCX-T)", "1.1b" },
+ [pcxt_] = { "PA7200 (PCX-T')", "1.1c" },
+ [pcxl] = { "PA7100LC (PCX-L)", "1.1d" },
+ [pcxl2] = { "PA7300LC (PCX-L2)","1.1e" },
+ [pcxu] = { "PA8000 (PCX-U)", "2.0" },
+ [pcxu_] = { "PA8200 (PCX-U+)", "2.0" },
+ [pcxw] = { "PA8500 (PCX-W)", "2.0" },
+ [pcxw_] = { "PA8600 (PCX-W+)", "2.0" },
+ [pcxw2] = { "PA8700 (PCX-W2)", "2.0" },
+ [mako] = { "PA8800 (Mako)", "2.0" },
+ [mako2] = { "PA8900 (Shortfin)","2.0" }
+};
+
+const char * __init parisc_hardware_description(struct parisc_device_id *id)
+{
+ struct hp_hardware *listptr;
+
+ for (listptr = hp_hardware_list; listptr->hw_type != HPHW_FAULTY; listptr++) {
+ if ((listptr->hw_type == id->hw_type) &&
+ (listptr->hversion == id->hversion) &&
+ (listptr->sversion == id->sversion)){
+ return listptr->name;
+ }
+ }
+
+ /*
+ * ok, the above hardware table isn't complete, and we haven't found
+ * our device in this table. So let's now try to find a generic name
+ * to describe the given hardware...
+ */
+ switch (id->hw_type) {
+ case HPHW_NPROC:
+ return "Unknown machine";
+
+ case HPHW_A_DIRECT:
+ switch (id->sversion) {
+ case 0x0D: return "MUX port";
+ case 0x0E: return "RS-232 port";
+ }
+ break;
+
+ case HPHW_MEMORY:
+ return "Memory";
+
+ }
+
+ return "unknown device";
+}
+
+
+/* Interpret hversion (ret[0]) from PDC_MODEL(4)/PDC_MODEL_INFO(0) */
+enum cpu_type __init
+parisc_get_cpu_type(unsigned long hversion)
+{
+ struct hp_cpu_type_mask *ptr;
+ unsigned short model = ((unsigned short) (hversion)) >> 4;
+
+ for (ptr = hp_cpu_type_mask_list; 0 != ptr->mask; ptr++) {
+ if (ptr->model == (model & ptr->mask))
+ return ptr->cpu;
+ }
+ panic("could not identify CPU type\n");
+
+ return pcx; /* not reached: */
+}
+
diff --git a/arch/parisc/kernel/head.S b/arch/parisc/kernel/head.S
new file mode 100644
index 000000000..96e0264ac
--- /dev/null
+++ b/arch/parisc/kernel/head.S
@@ -0,0 +1,443 @@
+/* This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1999-2007 by Helge Deller <deller@gmx.de>
+ * Copyright 1999 SuSE GmbH (Philipp Rumpf)
+ * Copyright 1999 Philipp Rumpf (prumpf@tux.org)
+ * Copyright 2000 Hewlett Packard (Paul Bame, bame@puffin.external.hp.com)
+ * Copyright (C) 2001 Grant Grundler (Hewlett Packard)
+ * Copyright (C) 2004 Kyle McMartin <kyle@debian.org>
+ *
+ * Initial Version 04-23-1999 by Helge Deller <deller@gmx.de>
+ */
+
+#include <asm/asm-offsets.h>
+#include <asm/psw.h>
+#include <asm/pdc.h>
+
+#include <asm/assembly.h>
+
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <linux/pgtable.h>
+
+ .level 1.1
+
+ __INITDATA
+ENTRY(boot_args)
+ .word 0 /* arg0 */
+ .word 0 /* arg1 */
+ .word 0 /* arg2 */
+ .word 0 /* arg3 */
+END(boot_args)
+
+ __HEAD
+
+ .align 4
+ .import init_task,data
+ .import init_stack,data
+ .import fault_vector_20,code /* IVA parisc 2.0 32 bit */
+#ifndef CONFIG_64BIT
+ .import fault_vector_11,code /* IVA parisc 1.1 32 bit */
+ .import $global$ /* forward declaration */
+#endif /*!CONFIG_64BIT*/
+ENTRY(parisc_kernel_start)
+ .proc
+ .callinfo
+
+ /* Make sure sr4-sr7 are set to zero for the kernel address space */
+ mtsp %r0,%sr4
+ mtsp %r0,%sr5
+ mtsp %r0,%sr6
+ mtsp %r0,%sr7
+
+ /* Clear BSS (shouldn't the boot loader do this?) */
+
+ .import __bss_start,data
+ .import __bss_stop,data
+
+ load32 PA(__bss_start),%r3
+ load32 PA(__bss_stop),%r4
+$bss_loop:
+ cmpb,<<,n %r3,%r4,$bss_loop
+ stw,ma %r0,4(%r3)
+
+ /* Save away the arguments the boot loader passed in (32 bit args) */
+ load32 PA(boot_args),%r1
+ stw,ma %arg0,4(%r1)
+ stw,ma %arg1,4(%r1)
+ stw,ma %arg2,4(%r1)
+ stw,ma %arg3,4(%r1)
+
+#if defined(CONFIG_PA20)
+ /* check for 64-bit capable CPU as required by current kernel */
+ ldi 32,%r10
+ mtctl %r10,%cr11
+ .level 2.0
+ mfctl,w %cr11,%r10
+ .level 1.1
+ comib,<>,n 0,%r10,$cpu_ok
+
+ load32 PA(msg1),%arg0
+ ldi msg1_end-msg1,%arg1
+$iodc_panic:
+ copy %arg0, %r10
+ copy %arg1, %r11
+ load32 PA(init_stack),%sp
+#define MEM_CONS 0x3A0
+ ldw MEM_CONS+32(%r0),%arg0 // HPA
+ ldi ENTRY_IO_COUT,%arg1
+ ldw MEM_CONS+36(%r0),%arg2 // SPA
+ ldw MEM_CONS+8(%r0),%arg3 // layers
+ load32 PA(__bss_start),%r1
+ stw %r1,-52(%sp) // arg4
+ stw %r0,-56(%sp) // arg5
+ stw %r10,-60(%sp) // arg6 = ptr to text
+ stw %r11,-64(%sp) // arg7 = len
+ stw %r0,-68(%sp) // arg8
+ load32 PA(.iodc_panic_ret), %rp
+ ldw MEM_CONS+40(%r0),%r1 // ENTRY_IODC
+ bv,n (%r1)
+.iodc_panic_ret:
+ b . /* wait endless with ... */
+ or %r10,%r10,%r10 /* qemu idle sleep */
+msg1: .ascii "Can't boot kernel which was built for PA8x00 CPUs on this machine.\r\n"
+msg1_end:
+
+$cpu_ok:
+#endif
+
+ .level PA_ASM_LEVEL
+
+ /* Initialize startup VM. Just map first 16/32 MB of memory */
+ load32 PA(swapper_pg_dir),%r4
+ mtctl %r4,%cr24 /* Initialize kernel root pointer */
+ mtctl %r4,%cr25 /* Initialize user root pointer */
+
+#if CONFIG_PGTABLE_LEVELS == 3
+ /* Set pmd in pgd */
+ load32 PA(pmd0),%r5
+ shrd %r5,PxD_VALUE_SHIFT,%r3
+ ldo (PxD_FLAG_PRESENT+PxD_FLAG_VALID)(%r3),%r3
+ stw %r3,ASM_PGD_ENTRY*ASM_PGD_ENTRY_SIZE(%r4)
+ ldo ASM_PMD_ENTRY*ASM_PMD_ENTRY_SIZE(%r5),%r4
+#else
+ /* 2-level page table, so pmd == pgd */
+ ldo ASM_PGD_ENTRY*ASM_PGD_ENTRY_SIZE(%r4),%r4
+#endif
+
+ /* Fill in pmd with enough pte directories */
+ load32 PA(pg0),%r1
+ SHRREG %r1,PxD_VALUE_SHIFT,%r3
+ ldo (PxD_FLAG_PRESENT+PxD_FLAG_VALID)(%r3),%r3
+
+ ldi ASM_PT_INITIAL,%r1
+
+1:
+ stw %r3,0(%r4)
+ ldo (PAGE_SIZE >> PxD_VALUE_SHIFT)(%r3),%r3
+ addib,> -1,%r1,1b
+#if CONFIG_PGTABLE_LEVELS == 3
+ ldo ASM_PMD_ENTRY_SIZE(%r4),%r4
+#else
+ ldo ASM_PGD_ENTRY_SIZE(%r4),%r4
+#endif
+
+
+ /* Now initialize the PTEs themselves. We use RWX for
+ * everything ... it will get remapped correctly later */
+ ldo 0+_PAGE_KERNEL_RWX(%r0),%r3 /* Hardwired 0 phys addr start */
+ load32 (1<<(KERNEL_INITIAL_ORDER-PAGE_SHIFT)),%r11 /* PFN count */
+ load32 PA(pg0),%r1
+
+$pgt_fill_loop:
+ STREGM %r3,ASM_PTE_ENTRY_SIZE(%r1)
+ ldo (1<<PFN_PTE_SHIFT)(%r3),%r3 /* add one PFN */
+ addib,> -1,%r11,$pgt_fill_loop
+ nop
+
+ /* Load the return address...er...crash 'n burn */
+ copy %r0,%r2
+
+ /* And the RFI Target address too */
+ load32 start_parisc,%r11
+
+ /* And the initial task pointer */
+ load32 init_task,%r6
+ mtctl %r6,%cr30
+
+ /* And the stack pointer too */
+ load32 init_stack,%sp
+ tophys_r1 %sp
+#if defined(CONFIG_64BIT) && defined(CONFIG_FUNCTION_TRACER)
+ .import _mcount,data
+ /* initialize mcount FPTR */
+ /* Get the global data pointer */
+ loadgp
+ load32 PA(_mcount), %r10
+ std %dp,0x18(%r10)
+#endif
+
+#define MEM_PDC_LO 0x388
+#define MEM_PDC_HI 0x35C
+#ifdef CONFIG_64BIT
+ /* Get PDCE_PROC for monarch CPU. */
+ ldw MEM_PDC_LO(%r0),%r3
+ ldw MEM_PDC_HI(%r0),%r10
+ depd %r10, 31, 32, %r3 /* move to upper word */
+#endif
+
+
+#ifdef CONFIG_SMP
+ /* Set the smp rendezvous address into page zero.
+ ** It would be safer to do this in init_smp_config() but
+ ** it's just way easier to deal with here because
+ ** of 64-bit function ptrs and the address is local to this file.
+ */
+ load32 PA(smp_slave_stext),%r10
+ stw %r10,0x10(%r0) /* MEM_RENDEZ */
+ stw %r0,0x28(%r0) /* MEM_RENDEZ_HI - assume addr < 4GB */
+
+ /* FALLTHROUGH */
+ .procend
+
+#ifdef CONFIG_HOTPLUG_CPU
+ /* common_stext is far away in another section... jump there */
+ load32 PA(common_stext), %rp
+ bv,n (%rp)
+
+ /* common_stext and smp_slave_stext needs to be in text section */
+ .text
+#endif
+
+ /*
+ ** Code Common to both Monarch and Slave processors.
+ ** Entry:
+ **
+ ** 1.1:
+ ** %r11 must contain RFI target address.
+ ** %r25/%r26 args to pass to target function
+ ** %r2 in case rfi target decides it didn't like something
+ **
+ ** 2.0w:
+ ** %r3 PDCE_PROC address
+ ** %r11 RFI target address
+ **
+ ** Caller must init: SR4-7, %sp, %r10, %cr24/25,
+ */
+common_stext:
+ .proc
+ .callinfo
+#else
+ /* Clear PDC entry point - we won't use it */
+ stw %r0,0x10(%r0) /* MEM_RENDEZ */
+ stw %r0,0x28(%r0) /* MEM_RENDEZ_HI */
+#endif /*CONFIG_SMP*/
+
+#ifdef CONFIG_64BIT
+ mfctl %cr30,%r6 /* PCX-W2 firmware bug */
+ tophys_r1 %r6
+
+ /* Save the rfi target address */
+ STREG %r11, TASK_PT_GR11(%r6)
+ /* Switch to wide mode Superdome doesn't support narrow PDC
+ ** calls.
+ */
+1: mfia %rp /* clear upper part of pcoq */
+ ldo 2f-1b(%rp),%rp
+ depdi 0,31,32,%rp
+ bv (%rp)
+ ssm PSW_SM_W,%r0
+
+ /* Set Wide mode as the "Default" (eg for traps)
+ ** First trap occurs *right* after (or part of) rfi for slave CPUs.
+ ** Someday, palo might not do this for the Monarch either.
+ */
+2:
+
+ ldo PDC_PSW(%r0),%arg0 /* 21 */
+ ldo PDC_PSW_SET_DEFAULTS(%r0),%arg1 /* 2 */
+ ldo PDC_PSW_WIDE_BIT(%r0),%arg2 /* 2 */
+ load32 PA(stext_pdc_ret), %rp
+ bv (%r3)
+ copy %r0,%arg3
+
+stext_pdc_ret:
+ LDREG TASK_PT_GR11(%r6), %r11
+ tovirt_r1 %r6
+ mtctl %r6,%cr30 /* restore task thread info */
+#endif
+
+#ifndef CONFIG_64BIT
+ /* clear all BTLBs */
+ ldi PDC_BLOCK_TLB,%arg0
+ load32 PA(stext_pdc_btlb_ret), %rp
+ ldw MEM_PDC_LO(%r0),%r3
+ bv (%r3)
+ ldi PDC_BTLB_PURGE_ALL,%arg1
+stext_pdc_btlb_ret:
+#endif
+
+ /* PARANOID: clear user scratch/user space SR's */
+ mtsp %r0,%sr0
+ mtsp %r0,%sr1
+ mtsp %r0,%sr2
+ mtsp %r0,%sr3
+
+ /* Initialize Protection Registers */
+ mtctl %r0,%cr8
+ mtctl %r0,%cr9
+ mtctl %r0,%cr12
+ mtctl %r0,%cr13
+
+ /* Initialize the global data pointer */
+ loadgp
+
+ /* Set up our interrupt table. HPMCs might not work after this!
+ *
+ * We need to install the correct iva for PA1.1 or PA2.0. The
+ * following short sequence of instructions can determine this
+ * (without being illegal on a PA1.1 machine).
+ */
+#ifndef CONFIG_64BIT
+ ldi 32,%r10
+ mtctl %r10,%cr11
+ .level 2.0
+ mfctl,w %cr11,%r10
+ .level 1.1
+ comib,<>,n 0,%r10,$is_pa20
+ ldil L%PA(fault_vector_11),%r10
+ b $install_iva
+ ldo R%PA(fault_vector_11)(%r10),%r10
+
+$is_pa20:
+ .level PA_ASM_LEVEL /* restore 1.1 || 2.0w */
+#endif /*!CONFIG_64BIT*/
+ load32 PA(fault_vector_20),%r10
+
+$install_iva:
+ mtctl %r10,%cr14
+
+ b aligned_rfi /* Prepare to RFI! Man all the cannons! */
+ nop
+
+ .align 128
+aligned_rfi:
+ pcxt_ssm_bug
+
+ copy %r3, %arg0 /* PDCE_PROC for smp_callin() */
+
+ rsm PSW_SM_QUIET,%r0 /* off troublesome PSW bits */
+ /* Don't need NOPs, have 8 compliant insn before rfi */
+
+ mtctl %r0,%cr17 /* Clear IIASQ tail */
+ mtctl %r0,%cr17 /* Clear IIASQ head */
+
+ /* Load RFI target into PC queue */
+ mtctl %r11,%cr18 /* IIAOQ head */
+ ldo 4(%r11),%r11
+ mtctl %r11,%cr18 /* IIAOQ tail */
+
+ load32 KERNEL_PSW,%r10
+ mtctl %r10,%ipsw
+
+ tovirt_r1 %sp
+
+ /* Jump through hyperspace to Virt Mode */
+ rfi
+ nop
+
+ .procend
+
+#ifdef CONFIG_SMP
+
+ .import smp_init_current_idle_task,data
+ .import smp_callin,code
+
+#ifndef CONFIG_64BIT
+smp_callin_rtn:
+ .proc
+ .callinfo
+ break 1,1 /* Break if returned from start_secondary */
+ nop
+ nop
+ .procend
+#endif /*!CONFIG_64BIT*/
+
+/***************************************************************************
+* smp_slave_stext is executed by all non-monarch Processors when the Monarch
+* pokes the slave CPUs in smp.c:smp_boot_cpus().
+*
+* Once here, registers values are initialized in order to branch to virtual
+* mode. Once all available/eligible CPUs are in virtual mode, all are
+* released and start out by executing their own idle task.
+*****************************************************************************/
+smp_slave_stext:
+ .proc
+ .callinfo
+
+ /*
+ ** Initialize Space registers
+ */
+ mtsp %r0,%sr4
+ mtsp %r0,%sr5
+ mtsp %r0,%sr6
+ mtsp %r0,%sr7
+
+#ifdef CONFIG_64BIT
+ /*
+ * Enable Wide mode early, in case the task_struct for the idle
+ * task in smp_init_current_idle_task was allocated above 4GB.
+ */
+1: mfia %rp /* clear upper part of pcoq */
+ ldo 2f-1b(%rp),%rp
+ depdi 0,31,32,%rp
+ bv (%rp)
+ ssm PSW_SM_W,%r0
+2:
+#endif
+
+ /* Initialize the SP - monarch sets up smp_init_current_idle_task */
+ load32 PA(smp_init_current_idle_task),%r6
+ LDREG 0(%r6),%r6
+ mtctl %r6,%cr30
+ tophys_r1 %r6
+ LDREG TASK_STACK(%r6),%sp
+ tophys_r1 %sp
+ ldo FRAME_SIZE(%sp),%sp
+
+ /* point CPU to kernel page tables */
+ load32 PA(swapper_pg_dir),%r4
+ mtctl %r4,%cr24 /* Initialize kernel root pointer */
+ mtctl %r4,%cr25 /* Initialize user root pointer */
+
+#ifdef CONFIG_64BIT
+ /* Setup PDCE_PROC entry */
+ copy %arg0,%r3
+#else
+ /* Load RFI *return* address in case smp_callin bails */
+ load32 smp_callin_rtn,%r2
+#endif
+
+ /* Load RFI target address. */
+ load32 smp_callin,%r11
+
+ /* ok...common code can handle the rest */
+ b common_stext
+ nop
+
+ .procend
+#endif /* CONFIG_SMP */
+
+#ifndef CONFIG_64BIT
+ .section .data..ro_after_init
+
+ .align 4
+ .export $global$,data
+
+ .type $global$,@object
+ .size $global$,4
+$global$:
+ .word 0
+#endif /*!CONFIG_64BIT*/
diff --git a/arch/parisc/kernel/hpmc.S b/arch/parisc/kernel/hpmc.S
new file mode 100644
index 000000000..eb2e4bd67
--- /dev/null
+++ b/arch/parisc/kernel/hpmc.S
@@ -0,0 +1,289 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * HPMC (High Priority Machine Check) handler.
+ *
+ * Copyright (C) 1999 Philipp Rumpf <prumpf@tux.org>
+ * Copyright (C) 1999 Hewlett-Packard (Frank Rowand)
+ * Copyright (C) 2000 Hewlett-Packard (John Marvin)
+ */
+
+
+/*
+ * This HPMC handler retrieves the HPMC pim data, resets IO and
+ * returns to the default trap handler with code set to 1 (HPMC).
+ * The default trap handler calls handle interruption, which
+ * does a stack and register dump. This at least allows kernel
+ * developers to get back to C code in virtual mode, where they
+ * have the option to examine and print values from memory that
+ * would help in debugging an HPMC caused by a software bug.
+ *
+ * There is more to do here:
+ *
+ * 1) On MP systems we need to synchronize processors
+ * before calling pdc/iodc.
+ * 2) We should be checking the system state and not
+ * returning to the fault handler if things are really
+ * bad.
+ *
+ */
+
+ .level 1.1
+
+#include <asm/assembly.h>
+#include <asm/pdc.h>
+#include <asm/psw.h>
+
+#include <linux/linkage.h>
+#include <linux/init.h>
+
+ /*
+ * stack for os_hpmc, the HPMC handler.
+ * buffer for IODC procedures (for the HPMC handler).
+ *
+ * IODC requires 7K byte stack. That leaves 1K byte for os_hpmc.
+ */
+
+ .import toc_stack,data
+#define hpmc_stack toc_stack /* re-use the TOC stack */
+
+#define HPMC_IODC_BUF_SIZE 0x8000
+
+ __PAGE_ALIGNED_BSS
+ .align 4096
+hpmc_iodc_buf:
+ .block HPMC_IODC_BUF_SIZE
+
+ .section .bss
+ .align 8
+hpmc_raddr:
+ .block 128
+
+#define HPMC_PIM_DATA_SIZE 896 /* Enough to hold all architected 2.0 state */
+
+ .section .bss
+ .align 8
+ENTRY(hpmc_pim_data)
+ .block HPMC_PIM_DATA_SIZE
+END(hpmc_pim_data)
+
+ .text
+
+ .import intr_save, code
+ .align 16
+ENTRY(os_hpmc)
+.os_hpmc:
+
+ /*
+ * registers modified:
+ *
+ * Using callee saves registers without saving them. The
+ * original values are in the pim dump if we need them.
+ *
+ * r2 (rp) return pointer
+ * r3 address of PDCE_PROC
+ * r4 scratch
+ * r5 scratch
+ * r23 (arg3) procedure arg
+ * r24 (arg2) procedure arg
+ * r25 (arg1) procedure arg
+ * r26 (arg0) procedure arg
+ * r30 (sp) stack pointer
+ *
+ * registers read:
+ *
+ * r26 contains address of PDCE_PROC on entry
+ * r28 (ret0) return value from procedure
+ */
+
+ copy arg0, %r3 /* save address of PDCE_PROC */
+
+ /*
+ * disable nested HPMCs
+ *
+ * Increment os_hpmc checksum to invalidate it.
+ * Do this before turning the PSW M bit off.
+ */
+
+ mfctl %cr14, %r4
+ ldw 52(%r4),%r5
+ addi 1,%r5,%r5
+ stw %r5,52(%r4)
+
+ /* MP_FIXME: synchronize all processors. */
+
+ /* Setup stack pointer. */
+
+ load32 PA(hpmc_stack),sp
+
+ ldo 128(sp),sp /* leave room for arguments */
+
+ /*
+ * Most PDC routines require that the M bit be off.
+ * So turn on the Q bit and turn off the M bit.
+ */
+
+ ldi PSW_SM_Q,%r4 /* PSW Q on, PSW M off */
+ mtctl %r4,ipsw
+ mtctl %r0,pcsq
+ mtctl %r0,pcsq
+ load32 PA(os_hpmc_1),%r4
+ mtctl %r4,pcoq
+ ldo 4(%r4),%r4
+ mtctl %r4,pcoq
+ rfi
+ nop
+
+os_hpmc_1:
+
+ /* Call PDC_PIM to get HPMC pim info */
+
+ /*
+ * Note that on some newer boxes, PDC_PIM must be called
+ * before PDC_IO if you want IO to be reset. PDC_PIM sets
+ * a flag that PDC_IO examines.
+ */
+
+ ldo PDC_PIM(%r0), arg0
+ ldo PDC_PIM_HPMC(%r0),arg1 /* Transfer HPMC data */
+ load32 PA(hpmc_raddr),arg2
+ load32 PA(hpmc_pim_data),arg3
+ load32 HPMC_PIM_DATA_SIZE,%r4
+ stw %r4,-52(sp)
+
+ ldil L%PA(os_hpmc_2), rp
+ bv (r3) /* call pdce_proc */
+ ldo R%PA(os_hpmc_2)(rp), rp
+
+os_hpmc_2:
+ comib,<> 0,ret0, os_hpmc_fail
+
+ /* Reset IO by calling the hversion dependent PDC_IO routine */
+
+ ldo PDC_IO(%r0),arg0
+ ldo 0(%r0),arg1 /* log IO errors */
+ ldo 0(%r0),arg2 /* reserved */
+ ldo 0(%r0),arg3 /* reserved */
+ stw %r0,-52(sp) /* reserved */
+
+ ldil L%PA(os_hpmc_3),rp
+ bv (%r3) /* call pdce_proc */
+ ldo R%PA(os_hpmc_3)(rp),rp
+
+os_hpmc_3:
+
+ /* FIXME? Check for errors from PDC_IO (-1 might be OK) */
+
+ /*
+ * Initialize the IODC console device (HPA,SPA, path etc.
+ * are stored on page 0.
+ */
+
+ /*
+ * Load IODC into hpmc_iodc_buf by calling PDC_IODC.
+ * Note that PDC_IODC handles flushing the appropriate
+ * data and instruction cache lines.
+ */
+
+ ldo PDC_IODC(%r0),arg0
+ ldo PDC_IODC_READ(%r0),arg1
+ load32 PA(hpmc_raddr),arg2
+ ldw BOOT_CONSOLE_HPA_OFFSET(%r0),arg3 /* console hpa */
+ ldo PDC_IODC_RI_INIT(%r0),%r4
+ stw %r4,-52(sp)
+ load32 PA(hpmc_iodc_buf),%r4
+ stw %r4,-56(sp)
+ load32 HPMC_IODC_BUF_SIZE,%r4
+ stw %r4,-60(sp)
+
+ ldil L%PA(os_hpmc_4),rp
+ bv (%r3) /* call pdce_proc */
+ ldo R%PA(os_hpmc_4)(rp),rp
+
+os_hpmc_4:
+ comib,<> 0,ret0,os_hpmc_fail
+
+ /* Call the entry init (just loaded by PDC_IODC) */
+
+ ldw BOOT_CONSOLE_HPA_OFFSET(%r0),arg0 /* console hpa */
+ ldo ENTRY_INIT_MOD_DEV(%r0), arg1
+ ldw BOOT_CONSOLE_SPA_OFFSET(%r0),arg2 /* console spa */
+ depi 0,31,11,arg2 /* clear bits 21-31 */
+ ldo BOOT_CONSOLE_PATH_OFFSET(%r0),arg3 /* console path */
+ load32 PA(hpmc_raddr),%r4
+ stw %r4, -52(sp)
+ stw %r0, -56(sp) /* HV */
+ stw %r0, -60(sp) /* HV */
+ stw %r0, -64(sp) /* HV */
+ stw %r0, -68(sp) /* lang, must be zero */
+
+ load32 PA(hpmc_iodc_buf),%r5
+ ldil L%PA(os_hpmc_5),rp
+ bv (%r5)
+ ldo R%PA(os_hpmc_5)(rp),rp
+
+os_hpmc_5:
+ comib,<> 0,ret0,os_hpmc_fail
+
+ /* Prepare to call intr_save */
+
+ /*
+ * Load kernel page directory (load into user also, since
+ * we don't intend to ever return to user land anyway)
+ */
+
+ load32 PA(swapper_pg_dir),%r4
+ mtctl %r4,%cr24 /* Initialize kernel root pointer */
+ mtctl %r4,%cr25 /* Initialize user root pointer */
+
+ /* Clear sr4-sr7 */
+
+ mtsp %r0, %sr4
+ mtsp %r0, %sr5
+ mtsp %r0, %sr6
+ mtsp %r0, %sr7
+
+ tovirt_r1 %r30 /* make sp virtual */
+
+ rsm PSW_SM_Q,%r0 /* Clear Q bit */
+ ldi 1,%r8 /* Set trap code to "1" for HPMC */
+ load32 PA(intr_save),%r1
+ be 0(%sr7,%r1)
+ nop
+
+os_hpmc_fail:
+
+ /*
+ * Reset the system
+ *
+ * Some systems may lockup from a broadcast reset, so try the
+ * hversion PDC_BROADCAST_RESET() first.
+ * MP_FIXME: reset all processors if more than one central bus.
+ */
+
+ /* PDC_BROADCAST_RESET() */
+
+ ldo PDC_BROADCAST_RESET(%r0),arg0
+ ldo 0(%r0),arg1 /* do reset */
+
+ ldil L%PA(os_hpmc_6),rp
+ bv (%r3) /* call pdce_proc */
+ ldo R%PA(os_hpmc_6)(rp),rp
+
+os_hpmc_6:
+
+ /*
+ * possible return values:
+ * -1 non-existent procedure
+ * -2 non-existent option
+ * -16 unaligned stack
+ *
+ * If call returned, do a broadcast reset.
+ */
+
+ ldil L%0xfffc0000,%r4 /* IO_BROADCAST */
+ ldo 5(%r0),%r5
+ stw %r5,48(%r4) /* CMD_RESET to IO_COMMAND offset */
+
+ b .
+ nop
+ .align 16 /* make function length multiple of 16 bytes */
diff --git a/arch/parisc/kernel/inventory.c b/arch/parisc/kernel/inventory.c
new file mode 100644
index 000000000..7ab2f2a54
--- /dev/null
+++ b/arch/parisc/kernel/inventory.c
@@ -0,0 +1,674 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * inventory.c
+ *
+ * Copyright (c) 1999 The Puffin Group (David Kennedy and Alex deVries)
+ * Copyright (c) 2001 Matthew Wilcox for Hewlett-Packard
+ *
+ * These are the routines to discover what hardware exists in this box.
+ * This task is complicated by there being 3 different ways of
+ * performing an inventory, depending largely on the age of the box.
+ * The recommended way to do this is to check to see whether the machine
+ * is a `Snake' first, then try System Map, then try PAT. We try System
+ * Map before checking for a Snake -- this probably doesn't cause any
+ * problems, but...
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/platform_device.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/mmzone.h>
+#include <asm/pdc.h>
+#include <asm/pdcpat.h>
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/parisc-device.h>
+#include <asm/tlbflush.h>
+
+/*
+** Debug options
+** DEBUG_PAT Dump details which PDC PAT provides about ranges/devices.
+*/
+#undef DEBUG_PAT
+
+int pdc_type __ro_after_init = PDC_TYPE_ILLEGAL;
+
+/* cell number and location (PAT firmware only) */
+unsigned long parisc_cell_num __ro_after_init;
+unsigned long parisc_cell_loc __ro_after_init;
+unsigned long parisc_pat_pdc_cap __ro_after_init;
+
+
+void __init setup_pdc(void)
+{
+ long status;
+ unsigned int bus_id;
+ struct pdc_system_map_mod_info module_result;
+ struct pdc_module_path module_path;
+ struct pdc_model model;
+#ifdef CONFIG_64BIT
+ struct pdc_pat_cell_num cell_info;
+#endif
+
+ /* Determine the pdc "type" used on this machine */
+
+ printk(KERN_INFO "Determining PDC firmware type: ");
+
+ status = pdc_system_map_find_mods(&module_result, &module_path, 0);
+ if (status == PDC_OK) {
+ pdc_type = PDC_TYPE_SYSTEM_MAP;
+ pr_cont("System Map.\n");
+ return;
+ }
+
+ /*
+ * If the machine doesn't support PDC_SYSTEM_MAP then either it
+ * is a pdc pat box, or it is an older box. All 64 bit capable
+ * machines are either pdc pat boxes or they support PDC_SYSTEM_MAP.
+ */
+
+ /*
+ * TODO: We should test for 64 bit capability and give a
+ * clearer message.
+ */
+
+#ifdef CONFIG_64BIT
+ status = pdc_pat_cell_get_number(&cell_info);
+ if (status == PDC_OK) {
+ unsigned long legacy_rev, pat_rev;
+ pdc_type = PDC_TYPE_PAT;
+ pr_cont("64 bit PAT.\n");
+ parisc_cell_num = cell_info.cell_num;
+ parisc_cell_loc = cell_info.cell_loc;
+ pr_info("PAT: Running on cell %lu and location %lu.\n",
+ parisc_cell_num, parisc_cell_loc);
+ status = pdc_pat_pd_get_pdc_revisions(&legacy_rev,
+ &pat_rev, &parisc_pat_pdc_cap);
+ pr_info("PAT: legacy revision 0x%lx, pat_rev 0x%lx, pdc_cap 0x%lx, S-PTLB %d, HPMC_RENDEZ %d.\n",
+ legacy_rev, pat_rev, parisc_pat_pdc_cap,
+ parisc_pat_pdc_cap
+ & PDC_PAT_CAPABILITY_BIT_SIMULTANEOUS_PTLB ? 1:0,
+ parisc_pat_pdc_cap
+ & PDC_PAT_CAPABILITY_BIT_PDC_HPMC_RENDEZ ? 1:0);
+ return;
+ }
+#endif
+
+ /* Check the CPU's bus ID. There's probably a better test. */
+
+ status = pdc_model_info(&model);
+
+ bus_id = (model.hversion >> (4 + 7)) & 0x1f;
+
+ switch (bus_id) {
+ case 0x4: /* 720, 730, 750, 735, 755 */
+ case 0x6: /* 705, 710 */
+ case 0x7: /* 715, 725 */
+ case 0x8: /* 745, 747, 742 */
+ case 0xA: /* 712 and similar */
+ case 0xC: /* 715/64, at least */
+
+ pdc_type = PDC_TYPE_SNAKE;
+ pr_cont("Snake.\n");
+ return;
+
+ default: /* Everything else */
+
+ pr_cont("Unsupported.\n");
+ panic("If this is a 64-bit machine, please try a 64-bit kernel.\n");
+ }
+}
+
+#define PDC_PAGE_ADJ_SHIFT (PAGE_SHIFT - 12) /* pdc pages are always 4k */
+
+static void __init
+set_pmem_entry(physmem_range_t *pmem_ptr, unsigned long start,
+ unsigned long pages4k)
+{
+ /* Rather than aligning and potentially throwing away
+ * memory, we'll assume that any ranges are already
+ * nicely aligned with any reasonable page size, and
+ * panic if they are not (it's more likely that the
+ * pdc info is bad in this case).
+ */
+
+ if (unlikely( ((start & (PAGE_SIZE - 1)) != 0)
+ || ((pages4k & ((1UL << PDC_PAGE_ADJ_SHIFT) - 1)) != 0) )) {
+
+ panic("Memory range doesn't align with page size!\n");
+ }
+
+ pmem_ptr->start_pfn = (start >> PAGE_SHIFT);
+ pmem_ptr->pages = (pages4k >> PDC_PAGE_ADJ_SHIFT);
+}
+
+static void __init pagezero_memconfig(void)
+{
+ unsigned long npages;
+
+ /* Use the 32 bit information from page zero to create a single
+ * entry in the pmem_ranges[] table.
+ *
+ * We currently don't support machines with contiguous memory
+ * >= 4 Gb, who report that memory using 64 bit only fields
+ * on page zero. It's not worth doing until it can be tested,
+ * and it is not clear we can support those machines for other
+ * reasons.
+ *
+ * If that support is done in the future, this is where it
+ * should be done.
+ */
+
+ npages = (PAGE_ALIGN(PAGE0->imm_max_mem) >> PAGE_SHIFT);
+ set_pmem_entry(pmem_ranges,0UL,npages);
+ npmem_ranges = 1;
+}
+
+#ifdef CONFIG_64BIT
+
+/* All of the PDC PAT specific code is 64-bit only */
+
+/*
+** The module object is filled via PDC_PAT_CELL[Return Cell Module].
+** If a module is found, register module will get the IODC bytes via
+** pdc_iodc_read() using the PA view of conf_base_addr for the hpa parameter.
+**
+** The IO view can be used by PDC_PAT_CELL[Return Cell Module]
+** only for SBAs and LBAs. This view will cause an invalid
+** argument error for all other cell module types.
+**
+*/
+
+static int __init
+pat_query_module(ulong pcell_loc, ulong mod_index)
+{
+ pdc_pat_cell_mod_maddr_block_t *pa_pdc_cell;
+ unsigned long bytecnt;
+ unsigned long temp; /* 64-bit scratch value */
+ long status; /* PDC return value status */
+ struct parisc_device *dev;
+
+ pa_pdc_cell = kmalloc(sizeof (*pa_pdc_cell), GFP_KERNEL);
+ if (!pa_pdc_cell)
+ panic("couldn't allocate memory for PDC_PAT_CELL!");
+
+ /* return cell module (PA or Processor view) */
+ status = pdc_pat_cell_module(&bytecnt, pcell_loc, mod_index,
+ PA_VIEW, pa_pdc_cell);
+
+ if (status != PDC_OK) {
+ /* no more cell modules or error */
+ kfree(pa_pdc_cell);
+ return status;
+ }
+
+ temp = pa_pdc_cell->cba;
+ dev = alloc_pa_dev(PAT_GET_CBA(temp), &(pa_pdc_cell->mod_path));
+ if (!dev) {
+ kfree(pa_pdc_cell);
+ return PDC_OK;
+ }
+
+ /* alloc_pa_dev sets dev->hpa */
+
+ /*
+ ** save parameters in the parisc_device
+ ** (The idea being the device driver will call pdc_pat_cell_module()
+ ** and store the results in its own data structure.)
+ */
+ dev->pcell_loc = pcell_loc;
+ dev->mod_index = mod_index;
+
+ /* save generic info returned from the call */
+ /* REVISIT: who is the consumer of this? not sure yet... */
+ dev->mod_info = pa_pdc_cell->mod_info; /* pass to PAT_GET_ENTITY() */
+ dev->pmod_loc = pa_pdc_cell->mod_location;
+ dev->mod0 = pa_pdc_cell->mod[0];
+
+ register_parisc_device(dev); /* advertise device */
+
+#ifdef DEBUG_PAT
+ /* dump what we see so far... */
+ switch (PAT_GET_ENTITY(dev->mod_info)) {
+ pdc_pat_cell_mod_maddr_block_t io_pdc_cell;
+ unsigned long i;
+
+ case PAT_ENTITY_PROC:
+ printk(KERN_DEBUG "PAT_ENTITY_PROC: id_eid 0x%lx\n",
+ pa_pdc_cell->mod[0]);
+ break;
+
+ case PAT_ENTITY_MEM:
+ printk(KERN_DEBUG
+ "PAT_ENTITY_MEM: amount 0x%lx min_gni_base 0x%lx min_gni_len 0x%lx\n",
+ pa_pdc_cell->mod[0], pa_pdc_cell->mod[1],
+ pa_pdc_cell->mod[2]);
+ break;
+ case PAT_ENTITY_CA:
+ printk(KERN_DEBUG "PAT_ENTITY_CA: %ld\n", pcell_loc);
+ break;
+
+ case PAT_ENTITY_PBC:
+ printk(KERN_DEBUG "PAT_ENTITY_PBC: ");
+ goto print_ranges;
+
+ case PAT_ENTITY_SBA:
+ printk(KERN_DEBUG "PAT_ENTITY_SBA: ");
+ goto print_ranges;
+
+ case PAT_ENTITY_LBA:
+ printk(KERN_DEBUG "PAT_ENTITY_LBA: ");
+
+ print_ranges:
+ pdc_pat_cell_module(&bytecnt, pcell_loc, mod_index,
+ IO_VIEW, &io_pdc_cell);
+ printk(KERN_DEBUG "ranges %ld\n", pa_pdc_cell->mod[1]);
+ for (i = 0; i < pa_pdc_cell->mod[1]; i++) {
+ printk(KERN_DEBUG
+ " PA_VIEW %ld: 0x%016lx 0x%016lx 0x%016lx\n",
+ i, pa_pdc_cell->mod[2 + i * 3], /* type */
+ pa_pdc_cell->mod[3 + i * 3], /* start */
+ pa_pdc_cell->mod[4 + i * 3]); /* finish (ie end) */
+ printk(KERN_DEBUG
+ " IO_VIEW %ld: 0x%016lx 0x%016lx 0x%016lx\n",
+ i, io_pdc_cell.mod[2 + i * 3], /* type */
+ io_pdc_cell.mod[3 + i * 3], /* start */
+ io_pdc_cell.mod[4 + i * 3]); /* finish (ie end) */
+ }
+ printk(KERN_DEBUG "\n");
+ break;
+ }
+#endif /* DEBUG_PAT */
+
+ kfree(pa_pdc_cell);
+
+ return PDC_OK;
+}
+
+
+/* pat pdc can return information about a variety of different
+ * types of memory (e.g. firmware,i/o, etc) but we only care about
+ * the usable physical ram right now. Since the firmware specific
+ * information is allocated on the stack, we'll be generous, in
+ * case there is a lot of other information we don't care about.
+ */
+
+#define PAT_MAX_RANGES (4 * MAX_PHYSMEM_RANGES)
+
+static void __init pat_memconfig(void)
+{
+ unsigned long actual_len;
+ struct pdc_pat_pd_addr_map_entry mem_table[PAT_MAX_RANGES+1];
+ struct pdc_pat_pd_addr_map_entry *mtbl_ptr;
+ physmem_range_t *pmem_ptr;
+ long status;
+ int entries;
+ unsigned long length;
+ int i;
+
+ length = (PAT_MAX_RANGES + 1) * sizeof(struct pdc_pat_pd_addr_map_entry);
+
+ status = pdc_pat_pd_get_addr_map(&actual_len, mem_table, length, 0L);
+
+ if ((status != PDC_OK)
+ || ((actual_len % sizeof(struct pdc_pat_pd_addr_map_entry)) != 0)) {
+
+ /* The above pdc call shouldn't fail, but, just in
+ * case, just use the PAGE0 info.
+ */
+
+ printk("\n\n\n");
+ printk(KERN_WARNING "WARNING! Could not get full memory configuration. "
+ "All memory may not be used!\n\n\n");
+ pagezero_memconfig();
+ return;
+ }
+
+ entries = actual_len / sizeof(struct pdc_pat_pd_addr_map_entry);
+
+ if (entries > PAT_MAX_RANGES) {
+ printk(KERN_WARNING "This Machine has more memory ranges than we support!\n");
+ printk(KERN_WARNING "Some memory may not be used!\n");
+ }
+
+ /* Copy information into the firmware independent pmem_ranges
+ * array, skipping types we don't care about. Notice we said
+ * "may" above. We'll use all the entries that were returned.
+ */
+
+ npmem_ranges = 0;
+ mtbl_ptr = mem_table;
+ pmem_ptr = pmem_ranges; /* Global firmware independent table */
+ for (i = 0; i < entries; i++,mtbl_ptr++) {
+ if ( (mtbl_ptr->entry_type != PAT_MEMORY_DESCRIPTOR)
+ || (mtbl_ptr->memory_type != PAT_MEMTYPE_MEMORY)
+ || (mtbl_ptr->pages == 0)
+ || ( (mtbl_ptr->memory_usage != PAT_MEMUSE_GENERAL)
+ && (mtbl_ptr->memory_usage != PAT_MEMUSE_GI)
+ && (mtbl_ptr->memory_usage != PAT_MEMUSE_GNI) ) ) {
+
+ continue;
+ }
+
+ if (npmem_ranges == MAX_PHYSMEM_RANGES) {
+ printk(KERN_WARNING "This Machine has more memory ranges than we support!\n");
+ printk(KERN_WARNING "Some memory will not be used!\n");
+ break;
+ }
+
+ set_pmem_entry(pmem_ptr++,mtbl_ptr->paddr,mtbl_ptr->pages);
+ npmem_ranges++;
+ }
+}
+
+static int __init pat_inventory(void)
+{
+ int status;
+ ulong mod_index = 0;
+ struct pdc_pat_cell_num cell_info;
+
+ /*
+ ** Note: Prelude (and it's successors: Lclass, A400/500) only
+ ** implement PDC_PAT_CELL sub-options 0 and 2.
+ */
+ status = pdc_pat_cell_get_number(&cell_info);
+ if (status != PDC_OK) {
+ return 0;
+ }
+
+#ifdef DEBUG_PAT
+ printk(KERN_DEBUG "CELL_GET_NUMBER: 0x%lx 0x%lx\n", cell_info.cell_num,
+ cell_info.cell_loc);
+#endif
+
+ while (PDC_OK == pat_query_module(cell_info.cell_loc, mod_index)) {
+ mod_index++;
+ }
+
+ return mod_index;
+}
+
+/* We only look for extended memory ranges on a 64 bit capable box */
+static void __init sprockets_memconfig(void)
+{
+ struct pdc_memory_table_raddr r_addr;
+ struct pdc_memory_table mem_table[MAX_PHYSMEM_RANGES];
+ struct pdc_memory_table *mtbl_ptr;
+ physmem_range_t *pmem_ptr;
+ long status;
+ int entries;
+ int i;
+
+ status = pdc_mem_mem_table(&r_addr,mem_table,
+ (unsigned long)MAX_PHYSMEM_RANGES);
+
+ if (status != PDC_OK) {
+
+ /* The above pdc call only works on boxes with sprockets
+ * firmware (newer B,C,J class). Other non PAT PDC machines
+ * do support more than 3.75 Gb of memory, but we don't
+ * support them yet.
+ */
+
+ pagezero_memconfig();
+ return;
+ }
+
+ if (r_addr.entries_total > MAX_PHYSMEM_RANGES) {
+ printk(KERN_WARNING "This Machine has more memory ranges than we support!\n");
+ printk(KERN_WARNING "Some memory will not be used!\n");
+ }
+
+ entries = (int)r_addr.entries_returned;
+
+ npmem_ranges = 0;
+ mtbl_ptr = mem_table;
+ pmem_ptr = pmem_ranges; /* Global firmware independent table */
+ for (i = 0; i < entries; i++,mtbl_ptr++) {
+ set_pmem_entry(pmem_ptr++,mtbl_ptr->paddr,mtbl_ptr->pages);
+ npmem_ranges++;
+ }
+}
+
+#else /* !CONFIG_64BIT */
+
+#define pat_inventory() do { } while (0)
+#define pat_memconfig() do { } while (0)
+#define sprockets_memconfig() pagezero_memconfig()
+
+#endif /* !CONFIG_64BIT */
+
+
+#ifndef CONFIG_PA20
+
+/* Code to support Snake machines (7[2350], 7[235]5, 715/Scorpio) */
+
+static struct parisc_device * __init
+legacy_create_device(struct pdc_memory_map *r_addr,
+ struct pdc_module_path *module_path)
+{
+ struct parisc_device *dev;
+ int status = pdc_mem_map_hpa(r_addr, module_path);
+ if (status != PDC_OK)
+ return NULL;
+
+ dev = alloc_pa_dev(r_addr->hpa, &module_path->path);
+ if (dev == NULL)
+ return NULL;
+
+ register_parisc_device(dev);
+ return dev;
+}
+
+/**
+ * snake_inventory
+ *
+ * Before PDC_SYSTEM_MAP was invented, the PDC_MEM_MAP call was used.
+ * To use it, we initialise the mod_path.bc to 0xff and try all values of
+ * mod to get the HPA for the top-level devices. Bus adapters may have
+ * sub-devices which are discovered by setting bc[5] to 0 and bc[4] to the
+ * module, then trying all possible functions.
+ */
+static void __init snake_inventory(void)
+{
+ int mod;
+ for (mod = 0; mod < 16; mod++) {
+ struct parisc_device *dev;
+ struct pdc_module_path module_path;
+ struct pdc_memory_map r_addr;
+ unsigned int func;
+
+ memset(module_path.path.bc, 0xff, 6);
+ module_path.path.mod = mod;
+ dev = legacy_create_device(&r_addr, &module_path);
+ if ((!dev) || (dev->id.hw_type != HPHW_BA))
+ continue;
+
+ memset(module_path.path.bc, 0xff, 4);
+ module_path.path.bc[4] = mod;
+
+ for (func = 0; func < 16; func++) {
+ module_path.path.bc[5] = 0;
+ module_path.path.mod = func;
+ legacy_create_device(&r_addr, &module_path);
+ }
+ }
+}
+
+#else /* CONFIG_PA20 */
+#define snake_inventory() do { } while (0)
+#endif /* CONFIG_PA20 */
+
+/* Common 32/64 bit based code goes here */
+
+/**
+ * add_system_map_addresses - Add additional addresses to the parisc device.
+ * @dev: The parisc device.
+ * @num_addrs: Then number of addresses to add;
+ * @module_instance: The system_map module instance.
+ *
+ * This function adds any additional addresses reported by the system_map
+ * firmware to the parisc device.
+ */
+static void __init
+add_system_map_addresses(struct parisc_device *dev, int num_addrs,
+ int module_instance)
+{
+ int i;
+ long status;
+ struct pdc_system_map_addr_info addr_result;
+
+ dev->addr = kmalloc_array(num_addrs, sizeof(*dev->addr), GFP_KERNEL);
+ if(!dev->addr) {
+ printk(KERN_ERR "%s %s(): memory allocation failure\n",
+ __FILE__, __func__);
+ return;
+ }
+
+ for(i = 1; i <= num_addrs; ++i) {
+ status = pdc_system_map_find_addrs(&addr_result,
+ module_instance, i);
+ if(PDC_OK == status) {
+ dev->addr[dev->num_addrs] = (unsigned long)addr_result.mod_addr;
+ dev->num_addrs++;
+ } else {
+ printk(KERN_WARNING
+ "Bad PDC_FIND_ADDRESS status return (%ld) for index %d\n",
+ status, i);
+ }
+ }
+}
+
+/**
+ * system_map_inventory - Retrieve firmware devices via SYSTEM_MAP.
+ *
+ * This function attempts to retrieve and register all the devices firmware
+ * knows about via the SYSTEM_MAP PDC call.
+ */
+static void __init system_map_inventory(void)
+{
+ int i;
+ long status = PDC_OK;
+
+ for (i = 0; i < 256; i++) {
+ struct parisc_device *dev;
+ struct pdc_system_map_mod_info module_result;
+ struct pdc_module_path module_path;
+
+ status = pdc_system_map_find_mods(&module_result,
+ &module_path, i);
+ if ((status == PDC_BAD_PROC) || (status == PDC_NE_MOD))
+ break;
+ if (status != PDC_OK)
+ continue;
+
+ dev = alloc_pa_dev(module_result.mod_addr, &module_path.path);
+ if (!dev)
+ continue;
+
+ register_parisc_device(dev);
+
+ /* if available, get the additional addresses for a module */
+ if (!module_result.add_addrs)
+ continue;
+
+ add_system_map_addresses(dev, module_result.add_addrs, i);
+ }
+
+ walk_central_bus();
+ return;
+}
+
+void __init do_memory_inventory(void)
+{
+ switch (pdc_type) {
+
+ case PDC_TYPE_PAT:
+ pat_memconfig();
+ break;
+
+ case PDC_TYPE_SYSTEM_MAP:
+ sprockets_memconfig();
+ break;
+
+ case PDC_TYPE_SNAKE:
+ pagezero_memconfig();
+ return;
+
+ default:
+ panic("Unknown PDC type!\n");
+ }
+
+ if (npmem_ranges == 0 || pmem_ranges[0].start_pfn != 0) {
+ printk(KERN_WARNING "Bad memory configuration returned!\n");
+ printk(KERN_WARNING "Some memory may not be used!\n");
+ pagezero_memconfig();
+ }
+}
+
+void __init do_device_inventory(void)
+{
+ printk(KERN_INFO "Searching for devices...\n");
+
+ init_parisc_bus();
+
+ switch (pdc_type) {
+
+ case PDC_TYPE_PAT:
+ pat_inventory();
+ break;
+
+ case PDC_TYPE_SYSTEM_MAP:
+ system_map_inventory();
+ break;
+
+ case PDC_TYPE_SNAKE:
+ snake_inventory();
+ break;
+
+ default:
+ panic("Unknown PDC type!\n");
+ }
+ printk(KERN_INFO "Found devices:\n");
+ print_parisc_devices();
+
+#if defined(CONFIG_64BIT) && defined(CONFIG_SMP)
+ pa_serialize_tlb_flushes = machine_has_merced_bus();
+ if (pa_serialize_tlb_flushes)
+ pr_info("Merced bus found: Enable PxTLB serialization.\n");
+#endif
+
+#if defined(CONFIG_FW_CFG_SYSFS)
+ if (running_on_qemu) {
+ struct resource res[3] = {0,};
+ unsigned int base;
+
+ base = ((unsigned long long) PAGE0->pad0[2] << 32)
+ | PAGE0->pad0[3]; /* SeaBIOS stored it here */
+
+ res[0].name = "fw_cfg";
+ res[0].start = base;
+ res[0].end = base + 8 - 1;
+ res[0].flags = IORESOURCE_MEM;
+
+ res[1].name = "ctrl";
+ res[1].start = 0;
+ res[1].flags = IORESOURCE_REG;
+
+ res[2].name = "data";
+ res[2].start = 4;
+ res[2].flags = IORESOURCE_REG;
+
+ if (base) {
+ pr_info("Found qemu fw_cfg interface at %#08x\n", base);
+ platform_device_register_simple("fw_cfg",
+ PLATFORM_DEVID_NONE, res, 3);
+ }
+ }
+#endif
+}
diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c
new file mode 100644
index 000000000..2f81bfd4f
--- /dev/null
+++ b/arch/parisc/kernel/irq.c
@@ -0,0 +1,579 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Code to handle x86 style IRQs plus some generic interrupt stuff.
+ *
+ * Copyright (C) 1992 Linus Torvalds
+ * Copyright (C) 1994, 1995, 1996, 1997, 1998 Ralf Baechle
+ * Copyright (C) 1999 SuSE GmbH (Philipp Rumpf, prumpf@tux.org)
+ * Copyright (C) 1999-2000 Grant Grundler
+ * Copyright (c) 2005 Matthew Wilcox
+ */
+#include <linux/bitops.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel_stat.h>
+#include <linux/seq_file.h>
+#include <linux/types.h>
+#include <linux/sched/task_stack.h>
+#include <asm/io.h>
+
+#include <asm/softirq_stack.h>
+#include <asm/smp.h>
+#include <asm/ldcw.h>
+
+#undef PARISC_IRQ_CR16_COUNTS
+
+#define EIEM_MASK(irq) (1UL<<(CPU_IRQ_MAX - irq))
+
+/* Bits in EIEM correlate with cpu_irq_action[].
+** Numbered *Big Endian*! (ie bit 0 is MSB)
+*/
+static volatile unsigned long cpu_eiem = 0;
+
+/*
+** local ACK bitmap ... habitually set to 1, but reset to zero
+** between ->ack() and ->end() of the interrupt to prevent
+** re-interruption of a processing interrupt.
+*/
+static DEFINE_PER_CPU(unsigned long, local_ack_eiem) = ~0UL;
+
+static void cpu_mask_irq(struct irq_data *d)
+{
+ unsigned long eirr_bit = EIEM_MASK(d->irq);
+
+ cpu_eiem &= ~eirr_bit;
+ /* Do nothing on the other CPUs. If they get this interrupt,
+ * The & cpu_eiem in the do_cpu_irq_mask() ensures they won't
+ * handle it, and the set_eiem() at the bottom will ensure it
+ * then gets disabled */
+}
+
+static void __cpu_unmask_irq(unsigned int irq)
+{
+ unsigned long eirr_bit = EIEM_MASK(irq);
+
+ cpu_eiem |= eirr_bit;
+
+ /* This is just a simple NOP IPI. But what it does is cause
+ * all the other CPUs to do a set_eiem(cpu_eiem) at the end
+ * of the interrupt handler */
+ smp_send_all_nop();
+}
+
+static void cpu_unmask_irq(struct irq_data *d)
+{
+ __cpu_unmask_irq(d->irq);
+}
+
+void cpu_ack_irq(struct irq_data *d)
+{
+ unsigned long mask = EIEM_MASK(d->irq);
+ int cpu = smp_processor_id();
+
+ /* Clear in EIEM so we can no longer process */
+ per_cpu(local_ack_eiem, cpu) &= ~mask;
+
+ /* disable the interrupt */
+ set_eiem(cpu_eiem & per_cpu(local_ack_eiem, cpu));
+
+ /* and now ack it */
+ mtctl(mask, 23);
+}
+
+void cpu_eoi_irq(struct irq_data *d)
+{
+ unsigned long mask = EIEM_MASK(d->irq);
+ int cpu = smp_processor_id();
+
+ /* set it in the eiems---it's no longer in process */
+ per_cpu(local_ack_eiem, cpu) |= mask;
+
+ /* enable the interrupt */
+ set_eiem(cpu_eiem & per_cpu(local_ack_eiem, cpu));
+}
+
+#ifdef CONFIG_SMP
+int cpu_check_affinity(struct irq_data *d, const struct cpumask *dest)
+{
+ int cpu_dest;
+
+ /* timer and ipi have to always be received on all CPUs */
+ if (irqd_is_per_cpu(d))
+ return -EINVAL;
+
+ cpu_dest = cpumask_first_and(dest, cpu_online_mask);
+ if (cpu_dest >= nr_cpu_ids)
+ cpu_dest = cpumask_first(cpu_online_mask);
+
+ return cpu_dest;
+}
+#endif
+
+static struct irq_chip cpu_interrupt_type = {
+ .name = "CPU",
+ .irq_mask = cpu_mask_irq,
+ .irq_unmask = cpu_unmask_irq,
+ .irq_ack = cpu_ack_irq,
+ .irq_eoi = cpu_eoi_irq,
+ /* XXX: Needs to be written. We managed without it so far, but
+ * we really ought to write it.
+ */
+ .irq_retrigger = NULL,
+};
+
+DEFINE_PER_CPU_SHARED_ALIGNED(irq_cpustat_t, irq_stat);
+#define irq_stats(x) (&per_cpu(irq_stat, x))
+
+/*
+ * /proc/interrupts printing for arch specific interrupts
+ */
+int arch_show_interrupts(struct seq_file *p, int prec)
+{
+ int j;
+
+#ifdef CONFIG_DEBUG_STACKOVERFLOW
+ seq_printf(p, "%*s: ", prec, "STK");
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ", irq_stats(j)->kernel_stack_usage);
+ seq_puts(p, " Kernel stack usage\n");
+# ifdef CONFIG_IRQSTACKS
+ seq_printf(p, "%*s: ", prec, "IST");
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ", irq_stats(j)->irq_stack_usage);
+ seq_puts(p, " Interrupt stack usage\n");
+# endif
+#endif
+#ifdef CONFIG_SMP
+ if (num_online_cpus() > 1) {
+ seq_printf(p, "%*s: ", prec, "RES");
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ", irq_stats(j)->irq_resched_count);
+ seq_puts(p, " Rescheduling interrupts\n");
+ seq_printf(p, "%*s: ", prec, "CAL");
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ", irq_stats(j)->irq_call_count);
+ seq_puts(p, " Function call interrupts\n");
+ }
+#endif
+ seq_printf(p, "%*s: ", prec, "UAH");
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ", irq_stats(j)->irq_unaligned_count);
+ seq_puts(p, " Unaligned access handler traps\n");
+ seq_printf(p, "%*s: ", prec, "FPA");
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ", irq_stats(j)->irq_fpassist_count);
+ seq_puts(p, " Floating point assist traps\n");
+ seq_printf(p, "%*s: ", prec, "TLB");
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ", irq_stats(j)->irq_tlb_count);
+ seq_puts(p, " TLB shootdowns\n");
+ return 0;
+}
+
+int show_interrupts(struct seq_file *p, void *v)
+{
+ int i = *(loff_t *) v, j;
+ unsigned long flags;
+
+ if (i == 0) {
+ seq_puts(p, " ");
+ for_each_online_cpu(j)
+ seq_printf(p, " CPU%d", j);
+
+#ifdef PARISC_IRQ_CR16_COUNTS
+ seq_printf(p, " [min/avg/max] (CPU cycle counts)");
+#endif
+ seq_putc(p, '\n');
+ }
+
+ if (i < NR_IRQS) {
+ struct irq_desc *desc = irq_to_desc(i);
+ struct irqaction *action;
+
+ raw_spin_lock_irqsave(&desc->lock, flags);
+ action = desc->action;
+ if (!action)
+ goto skip;
+ seq_printf(p, "%3d: ", i);
+
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ", irq_desc_kstat_cpu(desc, j));
+
+ seq_printf(p, " %14s", irq_desc_get_chip(desc)->name);
+#ifndef PARISC_IRQ_CR16_COUNTS
+ seq_printf(p, " %s", action->name);
+
+ while ((action = action->next))
+ seq_printf(p, ", %s", action->name);
+#else
+ for ( ;action; action = action->next) {
+ unsigned int k, avg, min, max;
+
+ min = max = action->cr16_hist[0];
+
+ for (avg = k = 0; k < PARISC_CR16_HIST_SIZE; k++) {
+ int hist = action->cr16_hist[k];
+
+ if (hist) {
+ avg += hist;
+ } else
+ break;
+
+ if (hist > max) max = hist;
+ if (hist < min) min = hist;
+ }
+
+ avg /= k;
+ seq_printf(p, " %s[%d/%d/%d]", action->name,
+ min,avg,max);
+ }
+#endif
+
+ seq_putc(p, '\n');
+ skip:
+ raw_spin_unlock_irqrestore(&desc->lock, flags);
+ }
+
+ if (i == NR_IRQS)
+ arch_show_interrupts(p, 3);
+
+ return 0;
+}
+
+
+
+/*
+** The following form a "set": Virtual IRQ, Transaction Address, Trans Data.
+** Respectively, these map to IRQ region+EIRR, Processor HPA, EIRR bit.
+**
+** To use txn_XXX() interfaces, get a Virtual IRQ first.
+** Then use that to get the Transaction address and data.
+*/
+
+int cpu_claim_irq(unsigned int irq, struct irq_chip *type, void *data)
+{
+ if (irq_has_action(irq))
+ return -EBUSY;
+ if (irq_get_chip(irq) != &cpu_interrupt_type)
+ return -EBUSY;
+
+ /* for iosapic interrupts */
+ if (type) {
+ irq_set_chip_and_handler(irq, type, handle_percpu_irq);
+ irq_set_chip_data(irq, data);
+ __cpu_unmask_irq(irq);
+ }
+ return 0;
+}
+
+int txn_claim_irq(int irq)
+{
+ return cpu_claim_irq(irq, NULL, NULL) ? -1 : irq;
+}
+
+/*
+ * The bits_wide parameter accommodates the limitations of the HW/SW which
+ * use these bits:
+ * Legacy PA I/O (GSC/NIO): 5 bits (architected EIM register)
+ * V-class (EPIC): 6 bits
+ * N/L/A-class (iosapic): 8 bits
+ * PCI 2.2 MSI: 16 bits
+ * Some PCI devices: 32 bits (Symbios SCSI/ATM/HyperFabric)
+ *
+ * On the service provider side:
+ * o PA 1.1 (and PA2.0 narrow mode) 5-bits (width of EIR register)
+ * o PA 2.0 wide mode 6-bits (per processor)
+ * o IA64 8-bits (0-256 total)
+ *
+ * So a Legacy PA I/O device on a PA 2.0 box can't use all the bits supported
+ * by the processor...and the N/L-class I/O subsystem supports more bits than
+ * PA2.0 has. The first case is the problem.
+ */
+int txn_alloc_irq(unsigned int bits_wide)
+{
+ int irq;
+
+ /* never return irq 0 cause that's the interval timer */
+ for (irq = CPU_IRQ_BASE + 1; irq <= CPU_IRQ_MAX; irq++) {
+ if (cpu_claim_irq(irq, NULL, NULL) < 0)
+ continue;
+ if ((irq - CPU_IRQ_BASE) >= (1 << bits_wide))
+ continue;
+ return irq;
+ }
+
+ /* unlikely, but be prepared */
+ return -1;
+}
+
+
+unsigned long txn_affinity_addr(unsigned int irq, int cpu)
+{
+#ifdef CONFIG_SMP
+ struct irq_data *d = irq_get_irq_data(irq);
+ irq_data_update_affinity(d, cpumask_of(cpu));
+#endif
+
+ return per_cpu(cpu_data, cpu).txn_addr;
+}
+
+
+unsigned long txn_alloc_addr(unsigned int virt_irq)
+{
+ static int next_cpu = -1;
+
+ next_cpu++; /* assign to "next" CPU we want this bugger on */
+
+ /* validate entry */
+ while ((next_cpu < nr_cpu_ids) &&
+ (!per_cpu(cpu_data, next_cpu).txn_addr ||
+ !cpu_online(next_cpu)))
+ next_cpu++;
+
+ if (next_cpu >= nr_cpu_ids)
+ next_cpu = 0; /* nothing else, assign monarch */
+
+ return txn_affinity_addr(virt_irq, next_cpu);
+}
+
+
+unsigned int txn_alloc_data(unsigned int virt_irq)
+{
+ return virt_irq - CPU_IRQ_BASE;
+}
+
+static inline int eirr_to_irq(unsigned long eirr)
+{
+ int bit = fls_long(eirr);
+ return (BITS_PER_LONG - bit) + TIMER_IRQ;
+}
+
+#ifdef CONFIG_IRQSTACKS
+/*
+ * IRQ STACK - used for irq handler
+ */
+#ifdef CONFIG_64BIT
+#define IRQ_STACK_SIZE (4096 << 4) /* 64k irq stack size */
+#else
+#define IRQ_STACK_SIZE (4096 << 3) /* 32k irq stack size */
+#endif
+
+union irq_stack_union {
+ unsigned long stack[IRQ_STACK_SIZE/sizeof(unsigned long)];
+ volatile unsigned int slock[4];
+ volatile unsigned int lock[1];
+};
+
+static DEFINE_PER_CPU(union irq_stack_union, irq_stack_union) = {
+ .slock = { 1,1,1,1 },
+ };
+#endif
+
+
+int sysctl_panic_on_stackoverflow = 1;
+
+static inline void stack_overflow_check(struct pt_regs *regs)
+{
+#ifdef CONFIG_DEBUG_STACKOVERFLOW
+ #define STACK_MARGIN (256*6)
+
+ unsigned long stack_start = (unsigned long) task_stack_page(current);
+ unsigned long sp = regs->gr[30];
+ unsigned long stack_usage;
+ unsigned int *last_usage;
+ int cpu = smp_processor_id();
+
+ /* if sr7 != 0, we interrupted a userspace process which we do not want
+ * to check for stack overflow. We will only check the kernel stack. */
+ if (regs->sr[7])
+ return;
+
+ /* exit if already in panic */
+ if (sysctl_panic_on_stackoverflow < 0)
+ return;
+
+ /* calculate kernel stack usage */
+ stack_usage = sp - stack_start;
+#ifdef CONFIG_IRQSTACKS
+ if (likely(stack_usage <= THREAD_SIZE))
+ goto check_kernel_stack; /* found kernel stack */
+
+ /* check irq stack usage */
+ stack_start = (unsigned long) &per_cpu(irq_stack_union, cpu).stack;
+ stack_usage = sp - stack_start;
+
+ last_usage = &per_cpu(irq_stat.irq_stack_usage, cpu);
+ if (unlikely(stack_usage > *last_usage))
+ *last_usage = stack_usage;
+
+ if (likely(stack_usage < (IRQ_STACK_SIZE - STACK_MARGIN)))
+ return;
+
+ pr_emerg("stackcheck: %s will most likely overflow irq stack "
+ "(sp:%lx, stk bottom-top:%lx-%lx)\n",
+ current->comm, sp, stack_start, stack_start + IRQ_STACK_SIZE);
+ goto panic_check;
+
+check_kernel_stack:
+#endif
+
+ /* check kernel stack usage */
+ last_usage = &per_cpu(irq_stat.kernel_stack_usage, cpu);
+
+ if (unlikely(stack_usage > *last_usage))
+ *last_usage = stack_usage;
+
+ if (likely(stack_usage < (THREAD_SIZE - STACK_MARGIN)))
+ return;
+
+ pr_emerg("stackcheck: %s will most likely overflow kernel stack "
+ "(sp:%lx, stk bottom-top:%lx-%lx)\n",
+ current->comm, sp, stack_start, stack_start + THREAD_SIZE);
+
+#ifdef CONFIG_IRQSTACKS
+panic_check:
+#endif
+ if (sysctl_panic_on_stackoverflow) {
+ sysctl_panic_on_stackoverflow = -1; /* disable further checks */
+ panic("low stack detected by irq handler - check messages\n");
+ }
+#endif
+}
+
+#ifdef CONFIG_IRQSTACKS
+/* in entry.S: */
+void call_on_stack(unsigned long p1, void *func, unsigned long new_stack);
+
+static void execute_on_irq_stack(void *func, unsigned long param1)
+{
+ union irq_stack_union *union_ptr;
+ unsigned long irq_stack;
+ volatile unsigned int *irq_stack_in_use;
+
+ union_ptr = &per_cpu(irq_stack_union, smp_processor_id());
+ irq_stack = (unsigned long) &union_ptr->stack;
+ irq_stack = ALIGN(irq_stack + sizeof(irq_stack_union.slock),
+ FRAME_ALIGN); /* align for stack frame usage */
+
+ /* We may be called recursive. If we are already using the irq stack,
+ * just continue to use it. Use spinlocks to serialize
+ * the irq stack usage.
+ */
+ irq_stack_in_use = (volatile unsigned int *)__ldcw_align(union_ptr);
+ if (!__ldcw(irq_stack_in_use)) {
+ void (*direct_call)(unsigned long p1) = func;
+
+ /* We are using the IRQ stack already.
+ * Do direct call on current stack. */
+ direct_call(param1);
+ return;
+ }
+
+ /* This is where we switch to the IRQ stack. */
+ call_on_stack(param1, func, irq_stack);
+
+ /* free up irq stack usage. */
+ *irq_stack_in_use = 1;
+}
+
+#ifdef CONFIG_SOFTIRQ_ON_OWN_STACK
+void do_softirq_own_stack(void)
+{
+ execute_on_irq_stack(__do_softirq, 0);
+}
+#endif
+#endif /* CONFIG_IRQSTACKS */
+
+/* ONLY called from entry.S:intr_extint() */
+asmlinkage void do_cpu_irq_mask(struct pt_regs *regs)
+{
+ struct pt_regs *old_regs;
+ unsigned long eirr_val;
+ int irq, cpu = smp_processor_id();
+ struct irq_data *irq_data;
+#ifdef CONFIG_SMP
+ cpumask_t dest;
+#endif
+
+ old_regs = set_irq_regs(regs);
+ local_irq_disable();
+ irq_enter();
+
+ eirr_val = mfctl(23) & cpu_eiem & per_cpu(local_ack_eiem, cpu);
+ if (!eirr_val)
+ goto set_out;
+ irq = eirr_to_irq(eirr_val);
+
+ irq_data = irq_get_irq_data(irq);
+
+ /* Filter out spurious interrupts, mostly from serial port at bootup */
+ if (unlikely(!irq_desc_has_action(irq_data_to_desc(irq_data))))
+ goto set_out;
+
+#ifdef CONFIG_SMP
+ cpumask_copy(&dest, irq_data_get_affinity_mask(irq_data));
+ if (irqd_is_per_cpu(irq_data) &&
+ !cpumask_test_cpu(smp_processor_id(), &dest)) {
+ int cpu = cpumask_first(&dest);
+
+ printk(KERN_DEBUG "redirecting irq %d from CPU %d to %d\n",
+ irq, smp_processor_id(), cpu);
+ gsc_writel(irq + CPU_IRQ_BASE,
+ per_cpu(cpu_data, cpu).hpa);
+ goto set_out;
+ }
+#endif
+ stack_overflow_check(regs);
+
+#ifdef CONFIG_IRQSTACKS
+ execute_on_irq_stack(&generic_handle_irq, irq);
+#else
+ generic_handle_irq(irq);
+#endif /* CONFIG_IRQSTACKS */
+
+ out:
+ irq_exit();
+ set_irq_regs(old_regs);
+ return;
+
+ set_out:
+ set_eiem(cpu_eiem & per_cpu(local_ack_eiem, cpu));
+ goto out;
+}
+
+static void claim_cpu_irqs(void)
+{
+ unsigned long flags = IRQF_TIMER | IRQF_PERCPU | IRQF_IRQPOLL;
+ int i;
+
+ for (i = CPU_IRQ_BASE; i <= CPU_IRQ_MAX; i++) {
+ irq_set_chip_and_handler(i, &cpu_interrupt_type,
+ handle_percpu_irq);
+ }
+
+ irq_set_handler(TIMER_IRQ, handle_percpu_irq);
+ if (request_irq(TIMER_IRQ, timer_interrupt, flags, "timer", NULL))
+ pr_err("Failed to register timer interrupt\n");
+#ifdef CONFIG_SMP
+ irq_set_handler(IPI_IRQ, handle_percpu_irq);
+ if (request_irq(IPI_IRQ, ipi_interrupt, IRQF_PERCPU, "IPI", NULL))
+ pr_err("Failed to register IPI interrupt\n");
+#endif
+}
+
+void init_IRQ(void)
+{
+ local_irq_disable(); /* PARANOID - should already be disabled */
+ mtctl(~0UL, 23); /* EIRR : clear all pending external intr */
+#ifdef CONFIG_SMP
+ if (!cpu_eiem) {
+ claim_cpu_irqs();
+ cpu_eiem = EIEM_MASK(IPI_IRQ) | EIEM_MASK(TIMER_IRQ);
+ }
+#else
+ claim_cpu_irqs();
+ cpu_eiem = EIEM_MASK(TIMER_IRQ);
+#endif
+ set_eiem(cpu_eiem); /* EIEM : enable all external intr */
+}
diff --git a/arch/parisc/kernel/jump_label.c b/arch/parisc/kernel/jump_label.c
new file mode 100644
index 000000000..e253b1345
--- /dev/null
+++ b/arch/parisc/kernel/jump_label.c
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2019 Helge Deller <deller@gmx.de>
+ *
+ * Based on arch/arm64/kernel/jump_label.c
+ */
+#include <linux/kernel.h>
+#include <linux/jump_label.h>
+#include <linux/bug.h>
+#include <asm/alternative.h>
+#include <asm/patch.h>
+
+static inline int reassemble_17(int as17)
+{
+ return (((as17 & 0x10000) >> 16) |
+ ((as17 & 0x0f800) << 5) |
+ ((as17 & 0x00400) >> 8) |
+ ((as17 & 0x003ff) << 3));
+}
+
+void arch_jump_label_transform(struct jump_entry *entry,
+ enum jump_label_type type)
+{
+ void *addr = (void *)jump_entry_code(entry);
+ u32 insn;
+
+ if (type == JUMP_LABEL_JMP) {
+ void *target = (void *)jump_entry_target(entry);
+ int distance = target - addr;
+ /*
+ * Encode the PA1.1 "b,n" instruction with a 17-bit
+ * displacement. In case we hit the BUG(), we could use
+ * another branch instruction with a 22-bit displacement on
+ * 64-bit CPUs instead. But this seems sufficient for now.
+ */
+ distance -= 8;
+ BUG_ON(distance > 262143 || distance < -262144);
+ insn = 0xe8000002 | reassemble_17(distance >> 2);
+ } else {
+ insn = INSN_NOP;
+ }
+
+ patch_text(addr, insn);
+}
diff --git a/arch/parisc/kernel/kexec.c b/arch/parisc/kernel/kexec.c
new file mode 100644
index 000000000..db57345a9
--- /dev/null
+++ b/arch/parisc/kernel/kexec.c
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/kernel.h>
+#include <linux/console.h>
+#include <linux/kexec.h>
+#include <linux/delay.h>
+#include <linux/reboot.h>
+
+#include <asm/cacheflush.h>
+#include <asm/sections.h>
+
+extern void relocate_new_kernel(unsigned long head,
+ unsigned long start,
+ unsigned long phys);
+
+extern const unsigned int relocate_new_kernel_size;
+extern unsigned int kexec_initrd_start_offset;
+extern unsigned int kexec_initrd_end_offset;
+extern unsigned int kexec_cmdline_offset;
+extern unsigned int kexec_free_mem_offset;
+
+static void kexec_show_segment_info(const struct kimage *kimage,
+ unsigned long n)
+{
+ pr_debug(" segment[%lu]: %016lx - %016lx, 0x%lx bytes, %lu pages\n",
+ n,
+ kimage->segment[n].mem,
+ kimage->segment[n].mem + kimage->segment[n].memsz,
+ (unsigned long)kimage->segment[n].memsz,
+ (unsigned long)kimage->segment[n].memsz / PAGE_SIZE);
+}
+
+static void kexec_image_info(const struct kimage *kimage)
+{
+ unsigned long i;
+
+ pr_debug("kexec kimage info:\n");
+ pr_debug(" type: %d\n", kimage->type);
+ pr_debug(" start: %lx\n", kimage->start);
+ pr_debug(" head: %lx\n", kimage->head);
+ pr_debug(" nr_segments: %lu\n", kimage->nr_segments);
+
+ for (i = 0; i < kimage->nr_segments; i++)
+ kexec_show_segment_info(kimage, i);
+
+#ifdef CONFIG_KEXEC_FILE
+ if (kimage->file_mode) {
+ pr_debug("cmdline: %.*s\n", (int)kimage->cmdline_buf_len,
+ kimage->cmdline_buf);
+ }
+#endif
+}
+
+void machine_kexec_cleanup(struct kimage *kimage)
+{
+}
+
+void machine_crash_shutdown(struct pt_regs *regs)
+{
+}
+
+void machine_shutdown(void)
+{
+ smp_send_stop();
+ while (num_online_cpus() > 1) {
+ cpu_relax();
+ mdelay(1);
+ }
+}
+
+void machine_kexec(struct kimage *image)
+{
+#ifdef CONFIG_64BIT
+ Elf64_Fdesc desc;
+#endif
+ void (*reloc)(unsigned long head,
+ unsigned long start,
+ unsigned long phys);
+
+ unsigned long phys = page_to_phys(image->control_code_page);
+ void *virt = (void *)__fix_to_virt(FIX_TEXT_KEXEC);
+ struct kimage_arch *arch = &image->arch;
+
+ set_fixmap(FIX_TEXT_KEXEC, phys);
+
+ flush_cache_all();
+
+#ifdef CONFIG_64BIT
+ reloc = (void *)&desc;
+ desc.addr = (long long)virt;
+#else
+ reloc = (void *)virt;
+#endif
+
+ memcpy(virt, dereference_function_descriptor(relocate_new_kernel),
+ relocate_new_kernel_size);
+
+ *(unsigned long *)(virt + kexec_cmdline_offset) = arch->cmdline;
+ *(unsigned long *)(virt + kexec_initrd_start_offset) = arch->initrd_start;
+ *(unsigned long *)(virt + kexec_initrd_end_offset) = arch->initrd_end;
+ *(unsigned long *)(virt + kexec_free_mem_offset) = PAGE0->mem_free;
+
+ flush_cache_all();
+ flush_tlb_all();
+ local_irq_disable();
+
+ reloc(image->head & PAGE_MASK, image->start, phys);
+}
+
+int machine_kexec_prepare(struct kimage *image)
+{
+ kexec_image_info(image);
+ return 0;
+}
diff --git a/arch/parisc/kernel/kexec_file.c b/arch/parisc/kernel/kexec_file.c
new file mode 100644
index 000000000..8c534204f
--- /dev/null
+++ b/arch/parisc/kernel/kexec_file.c
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Load ELF vmlinux file for the kexec_file_load syscall.
+ *
+ * Copyright (c) 2019 Sven Schnelle <svens@stackframe.org>
+ *
+ */
+#include <linux/elf.h>
+#include <linux/kexec.h>
+#include <linux/libfdt.h>
+#include <linux/module.h>
+#include <linux/of_fdt.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+static void *elf_load(struct kimage *image, char *kernel_buf,
+ unsigned long kernel_len, char *initrd,
+ unsigned long initrd_len, char *cmdline,
+ unsigned long cmdline_len)
+{
+ int ret, i;
+ unsigned long kernel_load_addr;
+ struct elfhdr ehdr;
+ struct kexec_elf_info elf_info;
+ struct kexec_buf kbuf = { .image = image, .buf_min = 0,
+ .buf_max = -1UL, };
+
+ ret = kexec_build_elf_info(kernel_buf, kernel_len, &ehdr, &elf_info);
+ if (ret)
+ goto out;
+
+ ret = kexec_elf_load(image, &ehdr, &elf_info, &kbuf, &kernel_load_addr);
+ if (ret)
+ goto out;
+
+ image->start = __pa(elf_info.ehdr->e_entry);
+
+ for (i = 0; i < image->nr_segments; i++)
+ image->segment[i].mem = __pa(image->segment[i].mem);
+
+ pr_debug("Loaded the kernel at 0x%lx, entry at 0x%lx\n",
+ kernel_load_addr, image->start);
+
+ if (initrd != NULL) {
+ kbuf.buffer = initrd;
+ kbuf.bufsz = kbuf.memsz = initrd_len;
+ kbuf.buf_align = PAGE_SIZE;
+ kbuf.top_down = false;
+ kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+ ret = kexec_add_buffer(&kbuf);
+ if (ret)
+ goto out;
+
+ pr_debug("Loaded initrd at 0x%lx\n", kbuf.mem);
+ image->arch.initrd_start = kbuf.mem;
+ image->arch.initrd_end = kbuf.mem + initrd_len;
+ }
+
+ if (cmdline != NULL) {
+ kbuf.buffer = cmdline;
+ kbuf.bufsz = kbuf.memsz = ALIGN(cmdline_len, 8);
+ kbuf.buf_align = PAGE_SIZE;
+ kbuf.top_down = false;
+ kbuf.buf_min = PAGE0->mem_free + PAGE_SIZE;
+ kbuf.buf_max = kernel_load_addr;
+ kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
+ ret = kexec_add_buffer(&kbuf);
+ if (ret)
+ goto out;
+
+ pr_debug("Loaded cmdline at 0x%lx\n", kbuf.mem);
+ image->arch.cmdline = kbuf.mem;
+ }
+out:
+ return NULL;
+}
+
+const struct kexec_file_ops kexec_elf_ops = {
+ .probe = kexec_elf_probe,
+ .load = elf_load,
+};
+
+const struct kexec_file_ops * const kexec_file_loaders[] = {
+ &kexec_elf_ops,
+ NULL
+};
diff --git a/arch/parisc/kernel/kgdb.c b/arch/parisc/kernel/kgdb.c
new file mode 100644
index 000000000..b16fa9bac
--- /dev/null
+++ b/arch/parisc/kernel/kgdb.c
@@ -0,0 +1,210 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * PA-RISC KGDB support
+ *
+ * Copyright (c) 2019 Sven Schnelle <svens@stackframe.org>
+ * Copyright (c) 2022 Helge Deller <deller@gmx.de>
+ *
+ */
+
+#include <linux/kgdb.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/notifier.h>
+#include <linux/kdebug.h>
+#include <linux/uaccess.h>
+#include <asm/ptrace.h>
+#include <asm/traps.h>
+#include <asm/processor.h>
+#include <asm/patch.h>
+#include <asm/cacheflush.h>
+
+const struct kgdb_arch arch_kgdb_ops = {
+ .gdb_bpt_instr = { 0x03, 0xff, 0xa0, 0x1f }
+};
+
+static int __kgdb_notify(struct die_args *args, unsigned long cmd)
+{
+ struct pt_regs *regs = args->regs;
+
+ if (kgdb_handle_exception(1, args->signr, cmd, regs))
+ return NOTIFY_DONE;
+ return NOTIFY_STOP;
+}
+
+static int kgdb_notify(struct notifier_block *self,
+ unsigned long cmd, void *ptr)
+{
+ unsigned long flags;
+ int ret;
+
+ local_irq_save(flags);
+ ret = __kgdb_notify(ptr, cmd);
+ local_irq_restore(flags);
+
+ return ret;
+}
+
+static struct notifier_block kgdb_notifier = {
+ .notifier_call = kgdb_notify,
+ .priority = -INT_MAX,
+};
+
+int kgdb_arch_init(void)
+{
+ return register_die_notifier(&kgdb_notifier);
+}
+
+void kgdb_arch_exit(void)
+{
+ unregister_die_notifier(&kgdb_notifier);
+}
+
+void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+ struct parisc_gdb_regs *gr = (struct parisc_gdb_regs *)gdb_regs;
+
+ memset(gr, 0, sizeof(struct parisc_gdb_regs));
+
+ memcpy(gr->gpr, regs->gr, sizeof(gr->gpr));
+ memcpy(gr->fr, regs->fr, sizeof(gr->fr));
+
+ gr->sr0 = regs->sr[0];
+ gr->sr1 = regs->sr[1];
+ gr->sr2 = regs->sr[2];
+ gr->sr3 = regs->sr[3];
+ gr->sr4 = regs->sr[4];
+ gr->sr5 = regs->sr[5];
+ gr->sr6 = regs->sr[6];
+ gr->sr7 = regs->sr[7];
+
+ gr->sar = regs->sar;
+ gr->iir = regs->iir;
+ gr->isr = regs->isr;
+ gr->ior = regs->ior;
+ gr->ipsw = regs->ipsw;
+ gr->cr27 = regs->cr27;
+
+ gr->iaoq_f = regs->iaoq[0];
+ gr->iasq_f = regs->iasq[0];
+
+ gr->iaoq_b = regs->iaoq[1];
+ gr->iasq_b = regs->iasq[1];
+}
+
+void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+ struct parisc_gdb_regs *gr = (struct parisc_gdb_regs *)gdb_regs;
+
+
+ memcpy(regs->gr, gr->gpr, sizeof(regs->gr));
+ memcpy(regs->fr, gr->fr, sizeof(regs->fr));
+
+ regs->sr[0] = gr->sr0;
+ regs->sr[1] = gr->sr1;
+ regs->sr[2] = gr->sr2;
+ regs->sr[3] = gr->sr3;
+ regs->sr[4] = gr->sr4;
+ regs->sr[5] = gr->sr5;
+ regs->sr[6] = gr->sr6;
+ regs->sr[7] = gr->sr7;
+
+ regs->sar = gr->sar;
+ regs->iir = gr->iir;
+ regs->isr = gr->isr;
+ regs->ior = gr->ior;
+ regs->ipsw = gr->ipsw;
+ regs->cr27 = gr->cr27;
+
+ regs->iaoq[0] = gr->iaoq_f;
+ regs->iasq[0] = gr->iasq_f;
+
+ regs->iaoq[1] = gr->iaoq_b;
+ regs->iasq[1] = gr->iasq_b;
+}
+
+void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs,
+ struct task_struct *task)
+{
+ struct pt_regs *regs = task_pt_regs(task);
+ unsigned long gr30, iaoq;
+
+ gr30 = regs->gr[30];
+ iaoq = regs->iaoq[0];
+
+ regs->gr[30] = regs->ksp;
+ regs->iaoq[0] = regs->kpc;
+ pt_regs_to_gdb_regs(gdb_regs, regs);
+
+ regs->gr[30] = gr30;
+ regs->iaoq[0] = iaoq;
+
+}
+
+static void step_instruction_queue(struct pt_regs *regs)
+{
+ regs->iaoq[0] = regs->iaoq[1];
+ regs->iaoq[1] += 4;
+}
+
+void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long ip)
+{
+ regs->iaoq[0] = ip;
+ regs->iaoq[1] = ip + 4;
+}
+
+int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt)
+{
+ int ret = copy_from_kernel_nofault(bpt->saved_instr,
+ (char *)bpt->bpt_addr, BREAK_INSTR_SIZE);
+ if (ret)
+ return ret;
+
+ __patch_text((void *)bpt->bpt_addr,
+ *(unsigned int *)&arch_kgdb_ops.gdb_bpt_instr);
+ return ret;
+}
+
+int kgdb_arch_remove_breakpoint(struct kgdb_bkpt *bpt)
+{
+ __patch_text((void *)bpt->bpt_addr, *(unsigned int *)&bpt->saved_instr);
+ return 0;
+}
+
+int kgdb_arch_handle_exception(int trap, int signo,
+ int err_code, char *inbuf, char *outbuf,
+ struct pt_regs *regs)
+{
+ unsigned long addr;
+ char *p = inbuf + 1;
+
+ switch (inbuf[0]) {
+ case 'D':
+ case 'c':
+ case 'k':
+ kgdb_contthread = NULL;
+ kgdb_single_step = 0;
+
+ if (kgdb_hex2long(&p, &addr))
+ kgdb_arch_set_pc(regs, addr);
+ else if (trap == 9 && regs->iir ==
+ PARISC_KGDB_COMPILED_BREAK_INSN)
+ step_instruction_queue(regs);
+ return 0;
+ case 's':
+ kgdb_single_step = 1;
+ if (kgdb_hex2long(&p, &addr)) {
+ kgdb_arch_set_pc(regs, addr);
+ } else if (trap == 9 && regs->iir ==
+ PARISC_KGDB_COMPILED_BREAK_INSN) {
+ step_instruction_queue(regs);
+ mtctl(-1, 0);
+ } else {
+ mtctl(0, 0);
+ }
+ regs->gr[0] |= PSW_R;
+ return 0;
+
+ }
+ return -1;
+}
diff --git a/arch/parisc/kernel/kprobes.c b/arch/parisc/kernel/kprobes.c
new file mode 100644
index 000000000..6e0b86652
--- /dev/null
+++ b/arch/parisc/kernel/kprobes.c
@@ -0,0 +1,228 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * arch/parisc/kernel/kprobes.c
+ *
+ * PA-RISC kprobes implementation
+ *
+ * Copyright (c) 2019 Sven Schnelle <svens@stackframe.org>
+ * Copyright (c) 2022 Helge Deller <deller@gmx.de>
+ */
+
+#include <linux/types.h>
+#include <linux/kprobes.h>
+#include <linux/slab.h>
+#include <asm/cacheflush.h>
+#include <asm/patch.h>
+
+DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
+DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
+
+int __kprobes arch_prepare_kprobe(struct kprobe *p)
+{
+ if ((unsigned long)p->addr & 3UL)
+ return -EINVAL;
+
+ p->ainsn.insn = get_insn_slot();
+ if (!p->ainsn.insn)
+ return -ENOMEM;
+
+ /*
+ * Set up new instructions. Second break instruction will
+ * trigger call of parisc_kprobe_ss_handler().
+ */
+ p->opcode = *p->addr;
+ p->ainsn.insn[0] = p->opcode;
+ p->ainsn.insn[1] = PARISC_KPROBES_BREAK_INSN2;
+
+ flush_insn_slot(p);
+ return 0;
+}
+
+void __kprobes arch_remove_kprobe(struct kprobe *p)
+{
+ if (!p->ainsn.insn)
+ return;
+
+ free_insn_slot(p->ainsn.insn, 0);
+ p->ainsn.insn = NULL;
+}
+
+void __kprobes arch_arm_kprobe(struct kprobe *p)
+{
+ patch_text(p->addr, PARISC_KPROBES_BREAK_INSN);
+}
+
+void __kprobes arch_disarm_kprobe(struct kprobe *p)
+{
+ patch_text(p->addr, p->opcode);
+}
+
+static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb)
+{
+ kcb->prev_kprobe.kp = kprobe_running();
+ kcb->prev_kprobe.status = kcb->kprobe_status;
+}
+
+static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb)
+{
+ __this_cpu_write(current_kprobe, kcb->prev_kprobe.kp);
+ kcb->kprobe_status = kcb->prev_kprobe.status;
+}
+
+static inline void __kprobes set_current_kprobe(struct kprobe *p)
+{
+ __this_cpu_write(current_kprobe, p);
+}
+
+static void __kprobes setup_singlestep(struct kprobe *p,
+ struct kprobe_ctlblk *kcb, struct pt_regs *regs)
+{
+ kcb->iaoq[0] = regs->iaoq[0];
+ kcb->iaoq[1] = regs->iaoq[1];
+ instruction_pointer_set(regs, (unsigned long)p->ainsn.insn);
+}
+
+int __kprobes parisc_kprobe_break_handler(struct pt_regs *regs)
+{
+ struct kprobe *p;
+ struct kprobe_ctlblk *kcb;
+
+ preempt_disable();
+
+ kcb = get_kprobe_ctlblk();
+ p = get_kprobe((unsigned long *)regs->iaoq[0]);
+
+ if (!p) {
+ preempt_enable_no_resched();
+ return 0;
+ }
+
+ if (kprobe_running()) {
+ /*
+ * We have reentered the kprobe_handler, since another kprobe
+ * was hit while within the handler, we save the original
+ * kprobes and single step on the instruction of the new probe
+ * without calling any user handlers to avoid recursive
+ * kprobes.
+ */
+ save_previous_kprobe(kcb);
+ set_current_kprobe(p);
+ kprobes_inc_nmissed_count(p);
+ setup_singlestep(p, kcb, regs);
+ kcb->kprobe_status = KPROBE_REENTER;
+ return 1;
+ }
+
+ set_current_kprobe(p);
+ kcb->kprobe_status = KPROBE_HIT_ACTIVE;
+
+ /* If we have no pre-handler or it returned 0, we continue with
+ * normal processing. If we have a pre-handler and it returned
+ * non-zero - which means user handler setup registers to exit
+ * to another instruction, we must skip the single stepping.
+ */
+
+ if (!p->pre_handler || !p->pre_handler(p, regs)) {
+ setup_singlestep(p, kcb, regs);
+ kcb->kprobe_status = KPROBE_HIT_SS;
+ } else {
+ reset_current_kprobe();
+ preempt_enable_no_resched();
+ }
+ return 1;
+}
+
+int __kprobes parisc_kprobe_ss_handler(struct pt_regs *regs)
+{
+ struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+ struct kprobe *p = kprobe_running();
+
+ if (!p)
+ return 0;
+
+ if (regs->iaoq[0] != (unsigned long)p->ainsn.insn+4)
+ return 0;
+
+ /* restore back original saved kprobe variables and continue */
+ if (kcb->kprobe_status == KPROBE_REENTER) {
+ restore_previous_kprobe(kcb);
+ return 1;
+ }
+
+ /* for absolute branch instructions we can copy iaoq_b. for relative
+ * branch instructions we need to calculate the new address based on the
+ * difference between iaoq_f and iaoq_b. We cannot use iaoq_b without
+ * modifications because it's based on our ainsn.insn address.
+ */
+
+ if (p->post_handler)
+ p->post_handler(p, regs, 0);
+
+ switch (regs->iir >> 26) {
+ case 0x38: /* BE */
+ case 0x39: /* BE,L */
+ case 0x3a: /* BV */
+ case 0x3b: /* BVE */
+ /* for absolute branches, regs->iaoq[1] has already the right
+ * address
+ */
+ regs->iaoq[0] = kcb->iaoq[1];
+ break;
+ default:
+ regs->iaoq[0] = kcb->iaoq[1];
+ regs->iaoq[1] = regs->iaoq[0] + 4;
+ break;
+ }
+ kcb->kprobe_status = KPROBE_HIT_SSDONE;
+ reset_current_kprobe();
+ return 1;
+}
+
+void __kretprobe_trampoline(void)
+{
+ asm volatile("nop");
+ asm volatile("nop");
+}
+
+static int __kprobes trampoline_probe_handler(struct kprobe *p,
+ struct pt_regs *regs);
+
+static struct kprobe trampoline_p = {
+ .pre_handler = trampoline_probe_handler
+};
+
+static int __kprobes trampoline_probe_handler(struct kprobe *p,
+ struct pt_regs *regs)
+{
+ __kretprobe_trampoline_handler(regs, NULL);
+
+ return 1;
+}
+
+void arch_kretprobe_fixup_return(struct pt_regs *regs,
+ kprobe_opcode_t *correct_ret_addr)
+{
+ regs->gr[2] = (unsigned long)correct_ret_addr;
+}
+
+void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
+ struct pt_regs *regs)
+{
+ ri->ret_addr = (kprobe_opcode_t *)regs->gr[2];
+ ri->fp = NULL;
+
+ /* Replace the return addr with trampoline addr. */
+ regs->gr[2] = (unsigned long)trampoline_p.addr;
+}
+
+int __kprobes arch_trampoline_kprobe(struct kprobe *p)
+{
+ return p->addr == trampoline_p.addr;
+}
+
+int __init arch_init_kprobes(void)
+{
+ trampoline_p.addr = (kprobe_opcode_t *)
+ dereference_function_descriptor(__kretprobe_trampoline);
+ return register_kprobe(&trampoline_p);
+}
diff --git a/arch/parisc/kernel/module.c b/arch/parisc/kernel/module.c
new file mode 100644
index 000000000..d214bbe3c
--- /dev/null
+++ b/arch/parisc/kernel/module.c
@@ -0,0 +1,973 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* Kernel dynamically loadable module help for PARISC.
+ *
+ * The best reference for this stuff is probably the Processor-
+ * Specific ELF Supplement for PA-RISC:
+ * https://parisc.wiki.kernel.org/index.php/File:Elf-pa-hp.pdf
+ *
+ * Linux/PA-RISC Project
+ * Copyright (C) 2003 Randolph Chung <tausq at debian . org>
+ * Copyright (C) 2008 Helge Deller <deller@gmx.de>
+ *
+ * Notes:
+ * - PLT stub handling
+ * On 32bit (and sometimes 64bit) and with big kernel modules like xfs or
+ * ipv6 the relocation types R_PARISC_PCREL17F and R_PARISC_PCREL22F may
+ * fail to reach their PLT stub if we only create one big stub array for
+ * all sections at the beginning of the core or init section.
+ * Instead we now insert individual PLT stub entries directly in front of
+ * of the code sections where the stubs are actually called.
+ * This reduces the distance between the PCREL location and the stub entry
+ * so that the relocations can be fulfilled.
+ * While calculating the final layout of the kernel module in memory, the
+ * kernel module loader calls arch_mod_section_prepend() to request the
+ * to be reserved amount of memory in front of each individual section.
+ *
+ * - SEGREL32 handling
+ * We are not doing SEGREL32 handling correctly. According to the ABI, we
+ * should do a value offset, like this:
+ * if (in_init(me, (void *)val))
+ * val -= (uint32_t)me->mem[MOD_INIT_TEXT].base;
+ * else
+ * val -= (uint32_t)me->mem[MOD_TEXT].base;
+ * However, SEGREL32 is used only for PARISC unwind entries, and we want
+ * those entries to have an absolute address, and not just an offset.
+ *
+ * The unwind table mechanism has the ability to specify an offset for
+ * the unwind table; however, because we split off the init functions into
+ * a different piece of memory, it is not possible to do this using a
+ * single offset. Instead, we use the above hack for now.
+ */
+
+#include <linux/moduleloader.h>
+#include <linux/elf.h>
+#include <linux/vmalloc.h>
+#include <linux/fs.h>
+#include <linux/ftrace.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/bug.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+
+#include <asm/unwind.h>
+#include <asm/sections.h>
+
+#define RELOC_REACHABLE(val, bits) \
+ (( ( !((val) & (1<<((bits)-1))) && ((val)>>(bits)) != 0 ) || \
+ ( ((val) & (1<<((bits)-1))) && ((val)>>(bits)) != (((__typeof__(val))(~0))>>((bits)+2)))) ? \
+ 0 : 1)
+
+#define CHECK_RELOC(val, bits) \
+ if (!RELOC_REACHABLE(val, bits)) { \
+ printk(KERN_ERR "module %s relocation of symbol %s is out of range (0x%lx in %d bits)\n", \
+ me->name, strtab + sym->st_name, (unsigned long)val, bits); \
+ return -ENOEXEC; \
+ }
+
+/* Maximum number of GOT entries. We use a long displacement ldd from
+ * the bottom of the table, which has a maximum signed displacement of
+ * 0x3fff; however, since we're only going forward, this becomes
+ * 0x1fff, and thus, since each GOT entry is 8 bytes long we can have
+ * at most 1023 entries.
+ * To overcome this 14bit displacement with some kernel modules, we'll
+ * use instead the unusal 16bit displacement method (see reassemble_16a)
+ * which gives us a maximum positive displacement of 0x7fff, and as such
+ * allows us to allocate up to 4095 GOT entries. */
+#define MAX_GOTS 4095
+
+#ifndef CONFIG_64BIT
+struct got_entry {
+ Elf32_Addr addr;
+};
+
+struct stub_entry {
+ Elf32_Word insns[2]; /* each stub entry has two insns */
+};
+#else
+struct got_entry {
+ Elf64_Addr addr;
+};
+
+struct stub_entry {
+ Elf64_Word insns[4]; /* each stub entry has four insns */
+};
+#endif
+
+/* Field selection types defined by hppa */
+#define rnd(x) (((x)+0x1000)&~0x1fff)
+/* fsel: full 32 bits */
+#define fsel(v,a) ((v)+(a))
+/* lsel: select left 21 bits */
+#define lsel(v,a) (((v)+(a))>>11)
+/* rsel: select right 11 bits */
+#define rsel(v,a) (((v)+(a))&0x7ff)
+/* lrsel with rounding of addend to nearest 8k */
+#define lrsel(v,a) (((v)+rnd(a))>>11)
+/* rrsel with rounding of addend to nearest 8k */
+#define rrsel(v,a) ((((v)+rnd(a))&0x7ff)+((a)-rnd(a)))
+
+#define mask(x,sz) ((x) & ~((1<<(sz))-1))
+
+
+/* The reassemble_* functions prepare an immediate value for
+ insertion into an opcode. pa-risc uses all sorts of weird bitfields
+ in the instruction to hold the value. */
+static inline int sign_unext(int x, int len)
+{
+ int len_ones;
+
+ len_ones = (1 << len) - 1;
+ return x & len_ones;
+}
+
+static inline int low_sign_unext(int x, int len)
+{
+ int sign, temp;
+
+ sign = (x >> (len-1)) & 1;
+ temp = sign_unext(x, len-1);
+ return (temp << 1) | sign;
+}
+
+static inline int reassemble_14(int as14)
+{
+ return (((as14 & 0x1fff) << 1) |
+ ((as14 & 0x2000) >> 13));
+}
+
+static inline int reassemble_16a(int as16)
+{
+ int s, t;
+
+ /* Unusual 16-bit encoding, for wide mode only. */
+ t = (as16 << 1) & 0xffff;
+ s = (as16 & 0x8000);
+ return (t ^ s ^ (s >> 1)) | (s >> 15);
+}
+
+
+static inline int reassemble_17(int as17)
+{
+ return (((as17 & 0x10000) >> 16) |
+ ((as17 & 0x0f800) << 5) |
+ ((as17 & 0x00400) >> 8) |
+ ((as17 & 0x003ff) << 3));
+}
+
+static inline int reassemble_21(int as21)
+{
+ return (((as21 & 0x100000) >> 20) |
+ ((as21 & 0x0ffe00) >> 8) |
+ ((as21 & 0x000180) << 7) |
+ ((as21 & 0x00007c) << 14) |
+ ((as21 & 0x000003) << 12));
+}
+
+static inline int reassemble_22(int as22)
+{
+ return (((as22 & 0x200000) >> 21) |
+ ((as22 & 0x1f0000) << 5) |
+ ((as22 & 0x00f800) << 5) |
+ ((as22 & 0x000400) >> 8) |
+ ((as22 & 0x0003ff) << 3));
+}
+
+void *module_alloc(unsigned long size)
+{
+ /* using RWX means less protection for modules, but it's
+ * easier than trying to map the text, data, init_text and
+ * init_data correctly */
+ return __vmalloc_node_range(size, 1, VMALLOC_START, VMALLOC_END,
+ GFP_KERNEL,
+ PAGE_KERNEL_RWX, 0, NUMA_NO_NODE,
+ __builtin_return_address(0));
+}
+
+#ifndef CONFIG_64BIT
+static inline unsigned long count_gots(const Elf_Rela *rela, unsigned long n)
+{
+ return 0;
+}
+
+static inline unsigned long count_fdescs(const Elf_Rela *rela, unsigned long n)
+{
+ return 0;
+}
+
+static inline unsigned long count_stubs(const Elf_Rela *rela, unsigned long n)
+{
+ unsigned long cnt = 0;
+
+ for (; n > 0; n--, rela++)
+ {
+ switch (ELF32_R_TYPE(rela->r_info)) {
+ case R_PARISC_PCREL17F:
+ case R_PARISC_PCREL22F:
+ cnt++;
+ }
+ }
+
+ return cnt;
+}
+#else
+static inline unsigned long count_gots(const Elf_Rela *rela, unsigned long n)
+{
+ unsigned long cnt = 0;
+
+ for (; n > 0; n--, rela++)
+ {
+ switch (ELF64_R_TYPE(rela->r_info)) {
+ case R_PARISC_LTOFF21L:
+ case R_PARISC_LTOFF14R:
+ case R_PARISC_PCREL22F:
+ cnt++;
+ }
+ }
+
+ return cnt;
+}
+
+static inline unsigned long count_fdescs(const Elf_Rela *rela, unsigned long n)
+{
+ unsigned long cnt = 0;
+
+ for (; n > 0; n--, rela++)
+ {
+ switch (ELF64_R_TYPE(rela->r_info)) {
+ case R_PARISC_FPTR64:
+ cnt++;
+ }
+ }
+
+ return cnt;
+}
+
+static inline unsigned long count_stubs(const Elf_Rela *rela, unsigned long n)
+{
+ unsigned long cnt = 0;
+
+ for (; n > 0; n--, rela++)
+ {
+ switch (ELF64_R_TYPE(rela->r_info)) {
+ case R_PARISC_PCREL22F:
+ cnt++;
+ }
+ }
+
+ return cnt;
+}
+#endif
+
+void module_arch_freeing_init(struct module *mod)
+{
+ kfree(mod->arch.section);
+ mod->arch.section = NULL;
+}
+
+/* Additional bytes needed in front of individual sections */
+unsigned int arch_mod_section_prepend(struct module *mod,
+ unsigned int section)
+{
+ /* size needed for all stubs of this section (including
+ * one additional for correct alignment of the stubs) */
+ return (mod->arch.section[section].stub_entries + 1)
+ * sizeof(struct stub_entry);
+}
+
+#define CONST
+int module_frob_arch_sections(CONST Elf_Ehdr *hdr,
+ CONST Elf_Shdr *sechdrs,
+ CONST char *secstrings,
+ struct module *me)
+{
+ unsigned long gots = 0, fdescs = 0, len;
+ unsigned int i;
+ struct module_memory *mod_mem;
+
+ len = hdr->e_shnum * sizeof(me->arch.section[0]);
+ me->arch.section = kzalloc(len, GFP_KERNEL);
+ if (!me->arch.section)
+ return -ENOMEM;
+
+ for (i = 1; i < hdr->e_shnum; i++) {
+ const Elf_Rela *rels = (void *)sechdrs[i].sh_addr;
+ unsigned long nrels = sechdrs[i].sh_size / sizeof(*rels);
+ unsigned int count, s;
+
+ if (strncmp(secstrings + sechdrs[i].sh_name,
+ ".PARISC.unwind", 14) == 0)
+ me->arch.unwind_section = i;
+
+ if (sechdrs[i].sh_type != SHT_RELA)
+ continue;
+
+ /* some of these are not relevant for 32-bit/64-bit
+ * we leave them here to make the code common. the
+ * compiler will do its thing and optimize out the
+ * stuff we don't need
+ */
+ gots += count_gots(rels, nrels);
+ fdescs += count_fdescs(rels, nrels);
+
+ /* XXX: By sorting the relocs and finding duplicate entries
+ * we could reduce the number of necessary stubs and save
+ * some memory. */
+ count = count_stubs(rels, nrels);
+ if (!count)
+ continue;
+
+ /* so we need relocation stubs. reserve necessary memory. */
+ /* sh_info gives the section for which we need to add stubs. */
+ s = sechdrs[i].sh_info;
+
+ /* each code section should only have one relocation section */
+ WARN_ON(me->arch.section[s].stub_entries);
+
+ /* store number of stubs we need for this section */
+ me->arch.section[s].stub_entries += count;
+ }
+
+ mod_mem = &me->mem[MOD_TEXT];
+ /* align things a bit */
+ mod_mem->size = ALIGN(mod_mem->size, 16);
+ me->arch.got_offset = mod_mem->size;
+ mod_mem->size += gots * sizeof(struct got_entry);
+
+ mod_mem->size = ALIGN(mod_mem->size, 16);
+ me->arch.fdesc_offset = mod_mem->size;
+ mod_mem->size += fdescs * sizeof(Elf_Fdesc);
+
+ me->arch.got_max = gots;
+ me->arch.fdesc_max = fdescs;
+
+ return 0;
+}
+
+#ifdef CONFIG_64BIT
+static Elf64_Word get_got(struct module *me, unsigned long value, long addend)
+{
+ unsigned int i;
+ struct got_entry *got;
+
+ value += addend;
+
+ BUG_ON(value == 0);
+
+ got = me->mem[MOD_TEXT].base + me->arch.got_offset;
+ for (i = 0; got[i].addr; i++)
+ if (got[i].addr == value)
+ goto out;
+
+ BUG_ON(++me->arch.got_count > me->arch.got_max);
+
+ got[i].addr = value;
+ out:
+ pr_debug("GOT ENTRY %d[%lx] val %lx\n", i, i*sizeof(struct got_entry),
+ value);
+ return i * sizeof(struct got_entry);
+}
+#endif /* CONFIG_64BIT */
+
+#ifdef CONFIG_64BIT
+static Elf_Addr get_fdesc(struct module *me, unsigned long value)
+{
+ Elf_Fdesc *fdesc = me->mem[MOD_TEXT].base + me->arch.fdesc_offset;
+
+ if (!value) {
+ printk(KERN_ERR "%s: zero OPD requested!\n", me->name);
+ return 0;
+ }
+
+ /* Look for existing fdesc entry. */
+ while (fdesc->addr) {
+ if (fdesc->addr == value)
+ return (Elf_Addr)fdesc;
+ fdesc++;
+ }
+
+ BUG_ON(++me->arch.fdesc_count > me->arch.fdesc_max);
+
+ /* Create new one */
+ fdesc->addr = value;
+ fdesc->gp = (Elf_Addr)me->mem[MOD_TEXT].base + me->arch.got_offset;
+ return (Elf_Addr)fdesc;
+}
+#endif /* CONFIG_64BIT */
+
+enum elf_stub_type {
+ ELF_STUB_GOT,
+ ELF_STUB_MILLI,
+ ELF_STUB_DIRECT,
+};
+
+static Elf_Addr get_stub(struct module *me, unsigned long value, long addend,
+ enum elf_stub_type stub_type, Elf_Addr loc0, unsigned int targetsec)
+{
+ struct stub_entry *stub;
+ int __maybe_unused d;
+
+ /* initialize stub_offset to point in front of the section */
+ if (!me->arch.section[targetsec].stub_offset) {
+ loc0 -= (me->arch.section[targetsec].stub_entries + 1) *
+ sizeof(struct stub_entry);
+ /* get correct alignment for the stubs */
+ loc0 = ALIGN(loc0, sizeof(struct stub_entry));
+ me->arch.section[targetsec].stub_offset = loc0;
+ }
+
+ /* get address of stub entry */
+ stub = (void *) me->arch.section[targetsec].stub_offset;
+ me->arch.section[targetsec].stub_offset += sizeof(struct stub_entry);
+
+ /* do not write outside available stub area */
+ BUG_ON(0 == me->arch.section[targetsec].stub_entries--);
+
+
+#ifndef CONFIG_64BIT
+/* for 32-bit the stub looks like this:
+ * ldil L'XXX,%r1
+ * be,n R'XXX(%sr4,%r1)
+ */
+ //value = *(unsigned long *)((value + addend) & ~3); /* why? */
+
+ stub->insns[0] = 0x20200000; /* ldil L'XXX,%r1 */
+ stub->insns[1] = 0xe0202002; /* be,n R'XXX(%sr4,%r1) */
+
+ stub->insns[0] |= reassemble_21(lrsel(value, addend));
+ stub->insns[1] |= reassemble_17(rrsel(value, addend) / 4);
+
+#else
+/* for 64-bit we have three kinds of stubs:
+ * for normal function calls:
+ * ldd 0(%dp),%dp
+ * ldd 10(%dp), %r1
+ * bve (%r1)
+ * ldd 18(%dp), %dp
+ *
+ * for millicode:
+ * ldil 0, %r1
+ * ldo 0(%r1), %r1
+ * ldd 10(%r1), %r1
+ * bve,n (%r1)
+ *
+ * for direct branches (jumps between different section of the
+ * same module):
+ * ldil 0, %r1
+ * ldo 0(%r1), %r1
+ * bve,n (%r1)
+ */
+ switch (stub_type) {
+ case ELF_STUB_GOT:
+ d = get_got(me, value, addend);
+ if (d <= 15) {
+ /* Format 5 */
+ stub->insns[0] = 0x0f6010db; /* ldd 0(%dp),%dp */
+ stub->insns[0] |= low_sign_unext(d, 5) << 16;
+ } else {
+ /* Format 3 */
+ stub->insns[0] = 0x537b0000; /* ldd 0(%dp),%dp */
+ stub->insns[0] |= reassemble_16a(d);
+ }
+ stub->insns[1] = 0x53610020; /* ldd 10(%dp),%r1 */
+ stub->insns[2] = 0xe820d000; /* bve (%r1) */
+ stub->insns[3] = 0x537b0030; /* ldd 18(%dp),%dp */
+ break;
+ case ELF_STUB_MILLI:
+ stub->insns[0] = 0x20200000; /* ldil 0,%r1 */
+ stub->insns[1] = 0x34210000; /* ldo 0(%r1), %r1 */
+ stub->insns[2] = 0x50210020; /* ldd 10(%r1),%r1 */
+ stub->insns[3] = 0xe820d002; /* bve,n (%r1) */
+
+ stub->insns[0] |= reassemble_21(lrsel(value, addend));
+ stub->insns[1] |= reassemble_14(rrsel(value, addend));
+ break;
+ case ELF_STUB_DIRECT:
+ stub->insns[0] = 0x20200000; /* ldil 0,%r1 */
+ stub->insns[1] = 0x34210000; /* ldo 0(%r1), %r1 */
+ stub->insns[2] = 0xe820d002; /* bve,n (%r1) */
+
+ stub->insns[0] |= reassemble_21(lrsel(value, addend));
+ stub->insns[1] |= reassemble_14(rrsel(value, addend));
+ break;
+ }
+
+#endif
+
+ return (Elf_Addr)stub;
+}
+
+#ifndef CONFIG_64BIT
+int apply_relocate_add(Elf_Shdr *sechdrs,
+ const char *strtab,
+ unsigned int symindex,
+ unsigned int relsec,
+ struct module *me)
+{
+ int i;
+ Elf32_Rela *rel = (void *)sechdrs[relsec].sh_addr;
+ Elf32_Sym *sym;
+ Elf32_Word *loc;
+ Elf32_Addr val;
+ Elf32_Sword addend;
+ Elf32_Addr dot;
+ Elf_Addr loc0;
+ unsigned int targetsec = sechdrs[relsec].sh_info;
+ //unsigned long dp = (unsigned long)$global$;
+ register unsigned long dp asm ("r27");
+
+ pr_debug("Applying relocate section %u to %u\n", relsec,
+ targetsec);
+ for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
+ /* This is where to make the change */
+ loc = (void *)sechdrs[targetsec].sh_addr
+ + rel[i].r_offset;
+ /* This is the start of the target section */
+ loc0 = sechdrs[targetsec].sh_addr;
+ /* This is the symbol it is referring to */
+ sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
+ + ELF32_R_SYM(rel[i].r_info);
+ if (!sym->st_value) {
+ printk(KERN_WARNING "%s: Unknown symbol %s\n",
+ me->name, strtab + sym->st_name);
+ return -ENOENT;
+ }
+ //dot = (sechdrs[relsec].sh_addr + rel->r_offset) & ~0x03;
+ dot = (Elf32_Addr)loc & ~0x03;
+
+ val = sym->st_value;
+ addend = rel[i].r_addend;
+
+#if 0
+#define r(t) ELF32_R_TYPE(rel[i].r_info)==t ? #t :
+ pr_debug("Symbol %s loc 0x%x val 0x%x addend 0x%x: %s\n",
+ strtab + sym->st_name,
+ (uint32_t)loc, val, addend,
+ r(R_PARISC_PLABEL32)
+ r(R_PARISC_DIR32)
+ r(R_PARISC_DIR21L)
+ r(R_PARISC_DIR14R)
+ r(R_PARISC_SEGREL32)
+ r(R_PARISC_DPREL21L)
+ r(R_PARISC_DPREL14R)
+ r(R_PARISC_PCREL17F)
+ r(R_PARISC_PCREL22F)
+ "UNKNOWN");
+#undef r
+#endif
+
+ switch (ELF32_R_TYPE(rel[i].r_info)) {
+ case R_PARISC_PLABEL32:
+ /* 32-bit function address */
+ /* no function descriptors... */
+ *loc = fsel(val, addend);
+ break;
+ case R_PARISC_DIR32:
+ /* direct 32-bit ref */
+ *loc = fsel(val, addend);
+ break;
+ case R_PARISC_DIR21L:
+ /* left 21 bits of effective address */
+ val = lrsel(val, addend);
+ *loc = mask(*loc, 21) | reassemble_21(val);
+ break;
+ case R_PARISC_DIR14R:
+ /* right 14 bits of effective address */
+ val = rrsel(val, addend);
+ *loc = mask(*loc, 14) | reassemble_14(val);
+ break;
+ case R_PARISC_SEGREL32:
+ /* 32-bit segment relative address */
+ /* See note about special handling of SEGREL32 at
+ * the beginning of this file.
+ */
+ *loc = fsel(val, addend);
+ break;
+ case R_PARISC_SECREL32:
+ /* 32-bit section relative address. */
+ *loc = fsel(val, addend);
+ break;
+ case R_PARISC_DPREL21L:
+ /* left 21 bit of relative address */
+ val = lrsel(val - dp, addend);
+ *loc = mask(*loc, 21) | reassemble_21(val);
+ break;
+ case R_PARISC_DPREL14R:
+ /* right 14 bit of relative address */
+ val = rrsel(val - dp, addend);
+ *loc = mask(*loc, 14) | reassemble_14(val);
+ break;
+ case R_PARISC_PCREL17F:
+ /* 17-bit PC relative address */
+ /* calculate direct call offset */
+ val += addend;
+ val = (val - dot - 8)/4;
+ if (!RELOC_REACHABLE(val, 17)) {
+ /* direct distance too far, create
+ * stub entry instead */
+ val = get_stub(me, sym->st_value, addend,
+ ELF_STUB_DIRECT, loc0, targetsec);
+ val = (val - dot - 8)/4;
+ CHECK_RELOC(val, 17);
+ }
+ *loc = (*loc & ~0x1f1ffd) | reassemble_17(val);
+ break;
+ case R_PARISC_PCREL22F:
+ /* 22-bit PC relative address; only defined for pa20 */
+ /* calculate direct call offset */
+ val += addend;
+ val = (val - dot - 8)/4;
+ if (!RELOC_REACHABLE(val, 22)) {
+ /* direct distance too far, create
+ * stub entry instead */
+ val = get_stub(me, sym->st_value, addend,
+ ELF_STUB_DIRECT, loc0, targetsec);
+ val = (val - dot - 8)/4;
+ CHECK_RELOC(val, 22);
+ }
+ *loc = (*loc & ~0x3ff1ffd) | reassemble_22(val);
+ break;
+ case R_PARISC_PCREL32:
+ /* 32-bit PC relative address */
+ *loc = val - dot - 8 + addend;
+ break;
+
+ default:
+ printk(KERN_ERR "module %s: Unknown relocation: %u\n",
+ me->name, ELF32_R_TYPE(rel[i].r_info));
+ return -ENOEXEC;
+ }
+ }
+
+ return 0;
+}
+
+#else
+int apply_relocate_add(Elf_Shdr *sechdrs,
+ const char *strtab,
+ unsigned int symindex,
+ unsigned int relsec,
+ struct module *me)
+{
+ int i;
+ Elf64_Rela *rel = (void *)sechdrs[relsec].sh_addr;
+ Elf64_Sym *sym;
+ Elf64_Word *loc;
+ Elf64_Xword *loc64;
+ Elf64_Addr val;
+ Elf64_Sxword addend;
+ Elf64_Addr dot;
+ Elf_Addr loc0;
+ unsigned int targetsec = sechdrs[relsec].sh_info;
+
+ pr_debug("Applying relocate section %u to %u\n", relsec,
+ targetsec);
+ for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
+ /* This is where to make the change */
+ loc = (void *)sechdrs[targetsec].sh_addr
+ + rel[i].r_offset;
+ /* This is the start of the target section */
+ loc0 = sechdrs[targetsec].sh_addr;
+ /* This is the symbol it is referring to */
+ sym = (Elf64_Sym *)sechdrs[symindex].sh_addr
+ + ELF64_R_SYM(rel[i].r_info);
+ if (!sym->st_value) {
+ printk(KERN_WARNING "%s: Unknown symbol %s\n",
+ me->name, strtab + sym->st_name);
+ return -ENOENT;
+ }
+ //dot = (sechdrs[relsec].sh_addr + rel->r_offset) & ~0x03;
+ dot = (Elf64_Addr)loc & ~0x03;
+ loc64 = (Elf64_Xword *)loc;
+
+ val = sym->st_value;
+ addend = rel[i].r_addend;
+
+#if 0
+#define r(t) ELF64_R_TYPE(rel[i].r_info)==t ? #t :
+ printk("Symbol %s loc %p val 0x%Lx addend 0x%Lx: %s\n",
+ strtab + sym->st_name,
+ loc, val, addend,
+ r(R_PARISC_LTOFF14R)
+ r(R_PARISC_LTOFF21L)
+ r(R_PARISC_PCREL22F)
+ r(R_PARISC_DIR64)
+ r(R_PARISC_SEGREL32)
+ r(R_PARISC_FPTR64)
+ "UNKNOWN");
+#undef r
+#endif
+
+ switch (ELF64_R_TYPE(rel[i].r_info)) {
+ case R_PARISC_LTOFF21L:
+ /* LT-relative; left 21 bits */
+ val = get_got(me, val, addend);
+ pr_debug("LTOFF21L Symbol %s loc %p val %llx\n",
+ strtab + sym->st_name,
+ loc, val);
+ val = lrsel(val, 0);
+ *loc = mask(*loc, 21) | reassemble_21(val);
+ break;
+ case R_PARISC_LTOFF14R:
+ /* L(ltoff(val+addend)) */
+ /* LT-relative; right 14 bits */
+ val = get_got(me, val, addend);
+ val = rrsel(val, 0);
+ pr_debug("LTOFF14R Symbol %s loc %p val %llx\n",
+ strtab + sym->st_name,
+ loc, val);
+ *loc = mask(*loc, 14) | reassemble_14(val);
+ break;
+ case R_PARISC_PCREL22F:
+ /* PC-relative; 22 bits */
+ pr_debug("PCREL22F Symbol %s loc %p val %llx\n",
+ strtab + sym->st_name,
+ loc, val);
+ val += addend;
+ /* can we reach it locally? */
+ if (within_module(val, me)) {
+ /* this is the case where the symbol is local
+ * to the module, but in a different section,
+ * so stub the jump in case it's more than 22
+ * bits away */
+ val = (val - dot - 8)/4;
+ if (!RELOC_REACHABLE(val, 22)) {
+ /* direct distance too far, create
+ * stub entry instead */
+ val = get_stub(me, sym->st_value,
+ addend, ELF_STUB_DIRECT,
+ loc0, targetsec);
+ } else {
+ /* Ok, we can reach it directly. */
+ val = sym->st_value;
+ val += addend;
+ }
+ } else {
+ val = sym->st_value;
+ if (strncmp(strtab + sym->st_name, "$$", 2)
+ == 0)
+ val = get_stub(me, val, addend, ELF_STUB_MILLI,
+ loc0, targetsec);
+ else
+ val = get_stub(me, val, addend, ELF_STUB_GOT,
+ loc0, targetsec);
+ }
+ pr_debug("STUB FOR %s loc %px, val %llx+%llx at %llx\n",
+ strtab + sym->st_name, loc, sym->st_value,
+ addend, val);
+ val = (val - dot - 8)/4;
+ CHECK_RELOC(val, 22);
+ *loc = (*loc & ~0x3ff1ffd) | reassemble_22(val);
+ break;
+ case R_PARISC_PCREL32:
+ /* 32-bit PC relative address */
+ *loc = val - dot - 8 + addend;
+ break;
+ case R_PARISC_PCREL64:
+ /* 64-bit PC relative address */
+ *loc64 = val - dot - 8 + addend;
+ break;
+ case R_PARISC_DIR64:
+ /* 64-bit effective address */
+ *loc64 = val + addend;
+ break;
+ case R_PARISC_SEGREL32:
+ /* 32-bit segment relative address */
+ /* See note about special handling of SEGREL32 at
+ * the beginning of this file.
+ */
+ *loc = fsel(val, addend);
+ break;
+ case R_PARISC_SECREL32:
+ /* 32-bit section relative address. */
+ *loc = fsel(val, addend);
+ break;
+ case R_PARISC_FPTR64:
+ /* 64-bit function address */
+ if (within_module(val + addend, me)) {
+ *loc64 = get_fdesc(me, val+addend);
+ pr_debug("FDESC for %s at %llx points to %llx\n",
+ strtab + sym->st_name, *loc64,
+ ((Elf_Fdesc *)*loc64)->addr);
+ } else {
+ /* if the symbol is not local to this
+ * module then val+addend is a pointer
+ * to the function descriptor */
+ pr_debug("Non local FPTR64 Symbol %s loc %p val %llx\n",
+ strtab + sym->st_name,
+ loc, val);
+ *loc64 = val + addend;
+ }
+ break;
+
+ default:
+ printk(KERN_ERR "module %s: Unknown relocation: %Lu\n",
+ me->name, ELF64_R_TYPE(rel[i].r_info));
+ return -ENOEXEC;
+ }
+ }
+ return 0;
+}
+#endif
+
+static void
+register_unwind_table(struct module *me,
+ const Elf_Shdr *sechdrs)
+{
+ unsigned char *table, *end;
+ unsigned long gp;
+
+ if (!me->arch.unwind_section)
+ return;
+
+ table = (unsigned char *)sechdrs[me->arch.unwind_section].sh_addr;
+ end = table + sechdrs[me->arch.unwind_section].sh_size;
+ gp = (Elf_Addr)me->mem[MOD_TEXT].base + me->arch.got_offset;
+
+ pr_debug("register_unwind_table(), sect = %d at 0x%p - 0x%p (gp=0x%lx)\n",
+ me->arch.unwind_section, table, end, gp);
+ me->arch.unwind = unwind_table_add(me->name, 0, gp, table, end);
+}
+
+static void
+deregister_unwind_table(struct module *me)
+{
+ if (me->arch.unwind)
+ unwind_table_remove(me->arch.unwind);
+}
+
+int module_finalize(const Elf_Ehdr *hdr,
+ const Elf_Shdr *sechdrs,
+ struct module *me)
+{
+ int i;
+ unsigned long nsyms;
+ const char *strtab = NULL;
+ const Elf_Shdr *s;
+ char *secstrings;
+ int symindex __maybe_unused = -1;
+ Elf_Sym *newptr, *oldptr;
+ Elf_Shdr *symhdr = NULL;
+#ifdef DEBUG
+ Elf_Fdesc *entry;
+ u32 *addr;
+
+ entry = (Elf_Fdesc *)me->init;
+ printk("FINALIZE, ->init FPTR is %p, GP %lx ADDR %lx\n", entry,
+ entry->gp, entry->addr);
+ addr = (u32 *)entry->addr;
+ printk("INSNS: %x %x %x %x\n",
+ addr[0], addr[1], addr[2], addr[3]);
+ printk("got entries used %ld, gots max %ld\n"
+ "fdescs used %ld, fdescs max %ld\n",
+ me->arch.got_count, me->arch.got_max,
+ me->arch.fdesc_count, me->arch.fdesc_max);
+#endif
+
+ register_unwind_table(me, sechdrs);
+
+ /* haven't filled in me->symtab yet, so have to find it
+ * ourselves */
+ for (i = 1; i < hdr->e_shnum; i++) {
+ if(sechdrs[i].sh_type == SHT_SYMTAB
+ && (sechdrs[i].sh_flags & SHF_ALLOC)) {
+ int strindex = sechdrs[i].sh_link;
+ symindex = i;
+ /* FIXME: AWFUL HACK
+ * The cast is to drop the const from
+ * the sechdrs pointer */
+ symhdr = (Elf_Shdr *)&sechdrs[i];
+ strtab = (char *)sechdrs[strindex].sh_addr;
+ break;
+ }
+ }
+
+ pr_debug("module %s: strtab %p, symhdr %p\n",
+ me->name, strtab, symhdr);
+
+ if(me->arch.got_count > MAX_GOTS) {
+ printk(KERN_ERR "%s: Global Offset Table overflow (used %ld, allowed %d)\n",
+ me->name, me->arch.got_count, MAX_GOTS);
+ return -EINVAL;
+ }
+
+ kfree(me->arch.section);
+ me->arch.section = NULL;
+
+ /* no symbol table */
+ if(symhdr == NULL)
+ return 0;
+
+ oldptr = (void *)symhdr->sh_addr;
+ newptr = oldptr + 1; /* we start counting at 1 */
+ nsyms = symhdr->sh_size / sizeof(Elf_Sym);
+ pr_debug("OLD num_symtab %lu\n", nsyms);
+
+ for (i = 1; i < nsyms; i++) {
+ oldptr++; /* note, count starts at 1 so preincrement */
+ if(strncmp(strtab + oldptr->st_name,
+ ".L", 2) == 0)
+ continue;
+
+ if(newptr != oldptr)
+ *newptr++ = *oldptr;
+ else
+ newptr++;
+
+ }
+ nsyms = newptr - (Elf_Sym *)symhdr->sh_addr;
+ pr_debug("NEW num_symtab %lu\n", nsyms);
+ symhdr->sh_size = nsyms * sizeof(Elf_Sym);
+
+ /* find .altinstructions section */
+ secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+ for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
+ void *aseg = (void *) s->sh_addr;
+ char *secname = secstrings + s->sh_name;
+
+ if (!strcmp(".altinstructions", secname))
+ /* patch .altinstructions */
+ apply_alternatives(aseg, aseg + s->sh_size, me->name);
+
+#ifdef CONFIG_DYNAMIC_FTRACE
+ /* For 32 bit kernels we're compiling modules with
+ * -ffunction-sections so we must relocate the addresses in the
+ * ftrace callsite section.
+ */
+ if (symindex != -1 && !strcmp(secname, FTRACE_CALLSITE_SECTION)) {
+ int err;
+ if (s->sh_type == SHT_REL)
+ err = apply_relocate((Elf_Shdr *)sechdrs,
+ strtab, symindex,
+ s - sechdrs, me);
+ else if (s->sh_type == SHT_RELA)
+ err = apply_relocate_add((Elf_Shdr *)sechdrs,
+ strtab, symindex,
+ s - sechdrs, me);
+ if (err)
+ return err;
+ }
+#endif
+ }
+ return 0;
+}
+
+void module_arch_cleanup(struct module *mod)
+{
+ deregister_unwind_table(mod);
+}
+
+#ifdef CONFIG_64BIT
+void *dereference_module_function_descriptor(struct module *mod, void *ptr)
+{
+ unsigned long start_opd = (Elf64_Addr)mod->mem[MOD_TEXT].base +
+ mod->arch.fdesc_offset;
+ unsigned long end_opd = start_opd +
+ mod->arch.fdesc_count * sizeof(Elf64_Fdesc);
+
+ if (ptr < (void *)start_opd || ptr >= (void *)end_opd)
+ return ptr;
+
+ return dereference_function_descriptor(ptr);
+}
+#endif
diff --git a/arch/parisc/kernel/pacache.S b/arch/parisc/kernel/pacache.S
new file mode 100644
index 000000000..541370d14
--- /dev/null
+++ b/arch/parisc/kernel/pacache.S
@@ -0,0 +1,1295 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * PARISC TLB and cache flushing support
+ * Copyright (C) 2000-2001 Hewlett-Packard (John Marvin)
+ * Copyright (C) 2001 Matthew Wilcox (willy at parisc-linux.org)
+ * Copyright (C) 2002 Richard Hirst (rhirst with parisc-linux.org)
+ */
+
+/*
+ * NOTE: fdc,fic, and pdc instructions that use base register modification
+ * should only use index and base registers that are not shadowed,
+ * so that the fast path emulation in the non access miss handler
+ * can be used.
+ */
+
+#ifdef CONFIG_64BIT
+ .level 2.0w
+#else
+ .level 2.0
+#endif
+
+#include <asm/psw.h>
+#include <asm/assembly.h>
+#include <asm/cache.h>
+#include <asm/ldcw.h>
+#include <asm/alternative.h>
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <linux/pgtable.h>
+
+ .section .text.hot
+ .align 16
+
+ENTRY_CFI(flush_tlb_all_local)
+ /*
+ * The pitlbe and pdtlbe instructions should only be used to
+ * flush the entire tlb. Also, there needs to be no intervening
+ * tlb operations, e.g. tlb misses, so the operation needs
+ * to happen in real mode with all interruptions disabled.
+ */
+
+ /* pcxt_ssm_bug - relied upon translation! PA 2.0 Arch. F-4 and F-5 */
+ rsm PSW_SM_I, %r19 /* save I-bit state */
+ load32 PA(1f), %r1
+ nop
+ nop
+ nop
+ nop
+ nop
+
+ rsm PSW_SM_Q, %r0 /* prep to load iia queue */
+ mtctl %r0, %cr17 /* Clear IIASQ tail */
+ mtctl %r0, %cr17 /* Clear IIASQ head */
+ mtctl %r1, %cr18 /* IIAOQ head */
+ ldo 4(%r1), %r1
+ mtctl %r1, %cr18 /* IIAOQ tail */
+ load32 REAL_MODE_PSW, %r1
+ mtctl %r1, %ipsw
+ rfi
+ nop
+
+1: load32 PA(cache_info), %r1
+
+ /* Flush Instruction Tlb */
+
+88: LDREG ITLB_SID_BASE(%r1), %r20
+ LDREG ITLB_SID_STRIDE(%r1), %r21
+ LDREG ITLB_SID_COUNT(%r1), %r22
+ LDREG ITLB_OFF_BASE(%r1), %arg0
+ LDREG ITLB_OFF_STRIDE(%r1), %arg1
+ LDREG ITLB_OFF_COUNT(%r1), %arg2
+ LDREG ITLB_LOOP(%r1), %arg3
+
+ addib,COND(=) -1, %arg3, fitoneloop /* Preadjust and test */
+ movb,<,n %arg3, %r31, fitdone /* If loop < 0, skip */
+ copy %arg0, %r28 /* Init base addr */
+
+fitmanyloop: /* Loop if LOOP >= 2 */
+ mtsp %r20, %sr1
+ add %r21, %r20, %r20 /* increment space */
+ copy %arg2, %r29 /* Init middle loop count */
+
+fitmanymiddle: /* Loop if LOOP >= 2 */
+ addib,COND(>) -1, %r31, fitmanymiddle /* Adjusted inner loop decr */
+ pitlbe %r0(%sr1, %r28)
+ pitlbe,m %arg1(%sr1, %r28) /* Last pitlbe and addr adjust */
+ addib,COND(>) -1, %r29, fitmanymiddle /* Middle loop decr */
+ copy %arg3, %r31 /* Re-init inner loop count */
+
+ movb,tr %arg0, %r28, fitmanyloop /* Re-init base addr */
+ addib,COND(<=),n -1, %r22, fitdone /* Outer loop count decr */
+
+fitoneloop: /* Loop if LOOP = 1 */
+ mtsp %r20, %sr1
+ copy %arg0, %r28 /* init base addr */
+ copy %arg2, %r29 /* init middle loop count */
+
+fitonemiddle: /* Loop if LOOP = 1 */
+ addib,COND(>) -1, %r29, fitonemiddle /* Middle loop count decr */
+ pitlbe,m %arg1(%sr1, %r28) /* pitlbe for one loop */
+
+ addib,COND(>) -1, %r22, fitoneloop /* Outer loop count decr */
+ add %r21, %r20, %r20 /* increment space */
+
+fitdone:
+ ALTERNATIVE(88b, fitdone, ALT_COND_NO_SPLIT_TLB, INSN_NOP)
+
+ /* Flush Data Tlb */
+
+ LDREG DTLB_SID_BASE(%r1), %r20
+ LDREG DTLB_SID_STRIDE(%r1), %r21
+ LDREG DTLB_SID_COUNT(%r1), %r22
+ LDREG DTLB_OFF_BASE(%r1), %arg0
+ LDREG DTLB_OFF_STRIDE(%r1), %arg1
+ LDREG DTLB_OFF_COUNT(%r1), %arg2
+ LDREG DTLB_LOOP(%r1), %arg3
+
+ addib,COND(=) -1, %arg3, fdtoneloop /* Preadjust and test */
+ movb,<,n %arg3, %r31, fdtdone /* If loop < 0, skip */
+ copy %arg0, %r28 /* Init base addr */
+
+fdtmanyloop: /* Loop if LOOP >= 2 */
+ mtsp %r20, %sr1
+ add %r21, %r20, %r20 /* increment space */
+ copy %arg2, %r29 /* Init middle loop count */
+
+fdtmanymiddle: /* Loop if LOOP >= 2 */
+ addib,COND(>) -1, %r31, fdtmanymiddle /* Adjusted inner loop decr */
+ pdtlbe %r0(%sr1, %r28)
+ pdtlbe,m %arg1(%sr1, %r28) /* Last pdtlbe and addr adjust */
+ addib,COND(>) -1, %r29, fdtmanymiddle /* Middle loop decr */
+ copy %arg3, %r31 /* Re-init inner loop count */
+
+ movb,tr %arg0, %r28, fdtmanyloop /* Re-init base addr */
+ addib,COND(<=),n -1, %r22,fdtdone /* Outer loop count decr */
+
+fdtoneloop: /* Loop if LOOP = 1 */
+ mtsp %r20, %sr1
+ copy %arg0, %r28 /* init base addr */
+ copy %arg2, %r29 /* init middle loop count */
+
+fdtonemiddle: /* Loop if LOOP = 1 */
+ addib,COND(>) -1, %r29, fdtonemiddle /* Middle loop count decr */
+ pdtlbe,m %arg1(%sr1, %r28) /* pdtlbe for one loop */
+
+ addib,COND(>) -1, %r22, fdtoneloop /* Outer loop count decr */
+ add %r21, %r20, %r20 /* increment space */
+
+
+fdtdone:
+ /*
+ * Switch back to virtual mode
+ */
+ /* pcxt_ssm_bug */
+ rsm PSW_SM_I, %r0
+ load32 2f, %r1
+ nop
+ nop
+ nop
+ nop
+ nop
+
+ rsm PSW_SM_Q, %r0 /* prep to load iia queue */
+ mtctl %r0, %cr17 /* Clear IIASQ tail */
+ mtctl %r0, %cr17 /* Clear IIASQ head */
+ mtctl %r1, %cr18 /* IIAOQ head */
+ ldo 4(%r1), %r1
+ mtctl %r1, %cr18 /* IIAOQ tail */
+ load32 KERNEL_PSW, %r1
+ or %r1, %r19, %r1 /* I-bit to state on entry */
+ mtctl %r1, %ipsw /* restore I-bit (entire PSW) */
+ rfi
+ nop
+
+2: bv %r0(%r2)
+ nop
+
+ /*
+ * When running in qemu, drop whole flush_tlb_all_local function and
+ * replace by one pdtlbe instruction, for which QEMU will drop all
+ * local TLB entries.
+ */
+3: pdtlbe %r0(%sr1,%r0)
+ bv,n %r0(%r2)
+ ALTERNATIVE_CODE(flush_tlb_all_local, 2, ALT_COND_RUN_ON_QEMU, 3b)
+ENDPROC_CFI(flush_tlb_all_local)
+
+ .import cache_info,data
+
+ENTRY_CFI(flush_instruction_cache_local)
+88: load32 cache_info, %r1
+
+ /* Flush Instruction Cache */
+
+ LDREG ICACHE_BASE(%r1), %arg0
+ LDREG ICACHE_STRIDE(%r1), %arg1
+ LDREG ICACHE_COUNT(%r1), %arg2
+ LDREG ICACHE_LOOP(%r1), %arg3
+ rsm PSW_SM_I, %r22 /* No mmgt ops during loop*/
+ mtsp %r0, %sr1
+ addib,COND(=) -1, %arg3, fioneloop /* Preadjust and test */
+ movb,<,n %arg3, %r31, fisync /* If loop < 0, do sync */
+
+fimanyloop: /* Loop if LOOP >= 2 */
+ addib,COND(>) -1, %r31, fimanyloop /* Adjusted inner loop decr */
+ fice %r0(%sr1, %arg0)
+ fice,m %arg1(%sr1, %arg0) /* Last fice and addr adjust */
+ movb,tr %arg3, %r31, fimanyloop /* Re-init inner loop count */
+ addib,COND(<=),n -1, %arg2, fisync /* Outer loop decr */
+
+fioneloop: /* Loop if LOOP = 1 */
+ /* Some implementations may flush with a single fice instruction */
+ cmpib,COND(>>=),n 15, %arg2, fioneloop2
+
+fioneloop1:
+ fice,m %arg1(%sr1, %arg0)
+ fice,m %arg1(%sr1, %arg0)
+ fice,m %arg1(%sr1, %arg0)
+ fice,m %arg1(%sr1, %arg0)
+ fice,m %arg1(%sr1, %arg0)
+ fice,m %arg1(%sr1, %arg0)
+ fice,m %arg1(%sr1, %arg0)
+ fice,m %arg1(%sr1, %arg0)
+ fice,m %arg1(%sr1, %arg0)
+ fice,m %arg1(%sr1, %arg0)
+ fice,m %arg1(%sr1, %arg0)
+ fice,m %arg1(%sr1, %arg0)
+ fice,m %arg1(%sr1, %arg0)
+ fice,m %arg1(%sr1, %arg0)
+ fice,m %arg1(%sr1, %arg0)
+ addib,COND(>) -16, %arg2, fioneloop1
+ fice,m %arg1(%sr1, %arg0)
+
+ /* Check if done */
+ cmpb,COND(=),n %arg2, %r0, fisync /* Predict branch taken */
+
+fioneloop2:
+ addib,COND(>) -1, %arg2, fioneloop2 /* Outer loop count decr */
+ fice,m %arg1(%sr1, %arg0) /* Fice for one loop */
+
+fisync:
+ sync
+ mtsm %r22 /* restore I-bit */
+89: ALTERNATIVE(88b, 89b, ALT_COND_NO_ICACHE, INSN_NOP)
+ bv %r0(%r2)
+ nop
+ENDPROC_CFI(flush_instruction_cache_local)
+
+
+ .import cache_info, data
+ENTRY_CFI(flush_data_cache_local)
+88: load32 cache_info, %r1
+
+ /* Flush Data Cache */
+
+ LDREG DCACHE_BASE(%r1), %arg0
+ LDREG DCACHE_STRIDE(%r1), %arg1
+ LDREG DCACHE_COUNT(%r1), %arg2
+ LDREG DCACHE_LOOP(%r1), %arg3
+ rsm PSW_SM_I, %r22 /* No mmgt ops during loop*/
+ mtsp %r0, %sr1
+ addib,COND(=) -1, %arg3, fdoneloop /* Preadjust and test */
+ movb,<,n %arg3, %r31, fdsync /* If loop < 0, do sync */
+
+fdmanyloop: /* Loop if LOOP >= 2 */
+ addib,COND(>) -1, %r31, fdmanyloop /* Adjusted inner loop decr */
+ fdce %r0(%sr1, %arg0)
+ fdce,m %arg1(%sr1, %arg0) /* Last fdce and addr adjust */
+ movb,tr %arg3, %r31, fdmanyloop /* Re-init inner loop count */
+ addib,COND(<=),n -1, %arg2, fdsync /* Outer loop decr */
+
+fdoneloop: /* Loop if LOOP = 1 */
+ /* Some implementations may flush with a single fdce instruction */
+ cmpib,COND(>>=),n 15, %arg2, fdoneloop2
+
+fdoneloop1:
+ fdce,m %arg1(%sr1, %arg0)
+ fdce,m %arg1(%sr1, %arg0)
+ fdce,m %arg1(%sr1, %arg0)
+ fdce,m %arg1(%sr1, %arg0)
+ fdce,m %arg1(%sr1, %arg0)
+ fdce,m %arg1(%sr1, %arg0)
+ fdce,m %arg1(%sr1, %arg0)
+ fdce,m %arg1(%sr1, %arg0)
+ fdce,m %arg1(%sr1, %arg0)
+ fdce,m %arg1(%sr1, %arg0)
+ fdce,m %arg1(%sr1, %arg0)
+ fdce,m %arg1(%sr1, %arg0)
+ fdce,m %arg1(%sr1, %arg0)
+ fdce,m %arg1(%sr1, %arg0)
+ fdce,m %arg1(%sr1, %arg0)
+ addib,COND(>) -16, %arg2, fdoneloop1
+ fdce,m %arg1(%sr1, %arg0)
+
+ /* Check if done */
+ cmpb,COND(=),n %arg2, %r0, fdsync /* Predict branch taken */
+
+fdoneloop2:
+ addib,COND(>) -1, %arg2, fdoneloop2 /* Outer loop count decr */
+ fdce,m %arg1(%sr1, %arg0) /* Fdce for one loop */
+
+fdsync:
+ sync
+ mtsm %r22 /* restore I-bit */
+89: ALTERNATIVE(88b, 89b, ALT_COND_NO_DCACHE, INSN_NOP)
+ bv %r0(%r2)
+ nop
+ENDPROC_CFI(flush_data_cache_local)
+
+/* Clear page using kernel mapping. */
+
+ENTRY_CFI(clear_page_asm)
+#ifdef CONFIG_64BIT
+
+ /* Unroll the loop. */
+ ldi (PAGE_SIZE / 128), %r1
+
+1:
+ std %r0, 0(%r26)
+ std %r0, 8(%r26)
+ std %r0, 16(%r26)
+ std %r0, 24(%r26)
+ std %r0, 32(%r26)
+ std %r0, 40(%r26)
+ std %r0, 48(%r26)
+ std %r0, 56(%r26)
+ std %r0, 64(%r26)
+ std %r0, 72(%r26)
+ std %r0, 80(%r26)
+ std %r0, 88(%r26)
+ std %r0, 96(%r26)
+ std %r0, 104(%r26)
+ std %r0, 112(%r26)
+ std %r0, 120(%r26)
+
+ /* Note reverse branch hint for addib is taken. */
+ addib,COND(>),n -1, %r1, 1b
+ ldo 128(%r26), %r26
+
+#else
+
+ /*
+ * Note that until (if) we start saving the full 64-bit register
+ * values on interrupt, we can't use std on a 32 bit kernel.
+ */
+ ldi (PAGE_SIZE / 64), %r1
+
+1:
+ stw %r0, 0(%r26)
+ stw %r0, 4(%r26)
+ stw %r0, 8(%r26)
+ stw %r0, 12(%r26)
+ stw %r0, 16(%r26)
+ stw %r0, 20(%r26)
+ stw %r0, 24(%r26)
+ stw %r0, 28(%r26)
+ stw %r0, 32(%r26)
+ stw %r0, 36(%r26)
+ stw %r0, 40(%r26)
+ stw %r0, 44(%r26)
+ stw %r0, 48(%r26)
+ stw %r0, 52(%r26)
+ stw %r0, 56(%r26)
+ stw %r0, 60(%r26)
+
+ addib,COND(>),n -1, %r1, 1b
+ ldo 64(%r26), %r26
+#endif
+ bv %r0(%r2)
+ nop
+ENDPROC_CFI(clear_page_asm)
+
+/* Copy page using kernel mapping. */
+
+ENTRY_CFI(copy_page_asm)
+#ifdef CONFIG_64BIT
+ /* PA8x00 CPUs can consume 2 loads or 1 store per cycle.
+ * Unroll the loop by hand and arrange insn appropriately.
+ * Prefetch doesn't improve performance on rp3440.
+ * GCC probably can do this just as well...
+ */
+
+ ldi (PAGE_SIZE / 128), %r1
+
+1: ldd 0(%r25), %r19
+ ldd 8(%r25), %r20
+
+ ldd 16(%r25), %r21
+ ldd 24(%r25), %r22
+ std %r19, 0(%r26)
+ std %r20, 8(%r26)
+
+ ldd 32(%r25), %r19
+ ldd 40(%r25), %r20
+ std %r21, 16(%r26)
+ std %r22, 24(%r26)
+
+ ldd 48(%r25), %r21
+ ldd 56(%r25), %r22
+ std %r19, 32(%r26)
+ std %r20, 40(%r26)
+
+ ldd 64(%r25), %r19
+ ldd 72(%r25), %r20
+ std %r21, 48(%r26)
+ std %r22, 56(%r26)
+
+ ldd 80(%r25), %r21
+ ldd 88(%r25), %r22
+ std %r19, 64(%r26)
+ std %r20, 72(%r26)
+
+ ldd 96(%r25), %r19
+ ldd 104(%r25), %r20
+ std %r21, 80(%r26)
+ std %r22, 88(%r26)
+
+ ldd 112(%r25), %r21
+ ldd 120(%r25), %r22
+ ldo 128(%r25), %r25
+ std %r19, 96(%r26)
+ std %r20, 104(%r26)
+
+ std %r21, 112(%r26)
+ std %r22, 120(%r26)
+
+ /* Note reverse branch hint for addib is taken. */
+ addib,COND(>),n -1, %r1, 1b
+ ldo 128(%r26), %r26
+
+#else
+
+ /*
+ * This loop is optimized for PCXL/PCXL2 ldw/ldw and stw/stw
+ * bundles (very restricted rules for bundling).
+ * Note that until (if) we start saving
+ * the full 64 bit register values on interrupt, we can't
+ * use ldd/std on a 32 bit kernel.
+ */
+ ldw 0(%r25), %r19
+ ldi (PAGE_SIZE / 64), %r1
+
+1:
+ ldw 4(%r25), %r20
+ ldw 8(%r25), %r21
+ ldw 12(%r25), %r22
+ stw %r19, 0(%r26)
+ stw %r20, 4(%r26)
+ stw %r21, 8(%r26)
+ stw %r22, 12(%r26)
+ ldw 16(%r25), %r19
+ ldw 20(%r25), %r20
+ ldw 24(%r25), %r21
+ ldw 28(%r25), %r22
+ stw %r19, 16(%r26)
+ stw %r20, 20(%r26)
+ stw %r21, 24(%r26)
+ stw %r22, 28(%r26)
+ ldw 32(%r25), %r19
+ ldw 36(%r25), %r20
+ ldw 40(%r25), %r21
+ ldw 44(%r25), %r22
+ stw %r19, 32(%r26)
+ stw %r20, 36(%r26)
+ stw %r21, 40(%r26)
+ stw %r22, 44(%r26)
+ ldw 48(%r25), %r19
+ ldw 52(%r25), %r20
+ ldw 56(%r25), %r21
+ ldw 60(%r25), %r22
+ stw %r19, 48(%r26)
+ stw %r20, 52(%r26)
+ ldo 64(%r25), %r25
+ stw %r21, 56(%r26)
+ stw %r22, 60(%r26)
+ ldo 64(%r26), %r26
+ addib,COND(>),n -1, %r1, 1b
+ ldw 0(%r25), %r19
+#endif
+ bv %r0(%r2)
+ nop
+ENDPROC_CFI(copy_page_asm)
+
+/*
+ * NOTE: Code in clear_user_page has a hard coded dependency on the
+ * maximum alias boundary being 4 Mb. We've been assured by the
+ * parisc chip designers that there will not ever be a parisc
+ * chip with a larger alias boundary (Never say never :-) ).
+ *
+ * Yah, what about the PA8800 and PA8900 processors?
+ *
+ * Subtle: the dtlb miss handlers support the temp alias region by
+ * "knowing" that if a dtlb miss happens within the temp alias
+ * region it must have occurred while in clear_user_page. Since
+ * this routine makes use of processor local translations, we
+ * don't want to insert them into the kernel page table. Instead,
+ * we load up some general registers (they need to be registers
+ * which aren't shadowed) with the physical page numbers (preshifted
+ * for tlb insertion) needed to insert the translations. When we
+ * miss on the translation, the dtlb miss handler inserts the
+ * translation into the tlb using these values:
+ *
+ * %r26 physical address of "to" translation
+ * %r23 physical address of "from" translation
+ */
+
+ /*
+ * copy_user_page_asm() performs a page copy using mappings
+ * equivalent to the user page mappings. It can be used to
+ * implement copy_user_page() but unfortunately both the `from'
+ * and `to' pages need to be flushed through mappings equivalent
+ * to the user mappings after the copy because the kernel accesses
+ * the `from' page through the kmap kernel mapping and the `to'
+ * page needs to be flushed since code can be copied. As a
+ * result, this implementation is less efficient than the simpler
+ * copy using the kernel mapping. It only needs the `from' page
+ * to flushed via the user mapping. The kunmap routines handle
+ * the flushes needed for the kernel mapping.
+ *
+ * I'm still keeping this around because it may be possible to
+ * use it if more information is passed into copy_user_page().
+ * Have to do some measurements to see if it is worthwhile to
+ * lobby for such a change.
+ *
+ */
+
+ENTRY_CFI(copy_user_page_asm)
+ /* Convert virtual `to' and `from' addresses to physical addresses.
+ Move `from' physical address to non shadowed register. */
+ ldil L%(__PAGE_OFFSET), %r1
+ sub %r26, %r1, %r26
+ sub %r25, %r1, %r23
+
+ ldil L%(TMPALIAS_MAP_START), %r28
+ dep_safe %r24, 31,TMPALIAS_SIZE_BITS, %r28 /* Form aliased virtual address 'to' */
+ depi_safe 0, 31,PAGE_SHIFT, %r28 /* Clear any offset bits */
+ copy %r28, %r29
+ depi_safe 1, 31-TMPALIAS_SIZE_BITS,1, %r29 /* Form aliased virtual address 'from' */
+
+ /* Purge any old translations */
+
+#ifdef CONFIG_PA20
+ pdtlb,l %r0(%r28)
+ pdtlb,l %r0(%r29)
+#else
+0: pdtlb %r0(%r28)
+1: pdtlb %r0(%r29)
+ ALTERNATIVE(0b, 0b+4, ALT_COND_NO_SMP, INSN_PxTLB)
+ ALTERNATIVE(1b, 1b+4, ALT_COND_NO_SMP, INSN_PxTLB)
+#endif
+
+#ifdef CONFIG_64BIT
+ /* PA8x00 CPUs can consume 2 loads or 1 store per cycle.
+ * Unroll the loop by hand and arrange insn appropriately.
+ * GCC probably can do this just as well.
+ */
+
+ ldd 0(%r29), %r19
+ ldi (PAGE_SIZE / 128), %r1
+
+1: ldd 8(%r29), %r20
+
+ ldd 16(%r29), %r21
+ ldd 24(%r29), %r22
+ std %r19, 0(%r28)
+ std %r20, 8(%r28)
+
+ ldd 32(%r29), %r19
+ ldd 40(%r29), %r20
+ std %r21, 16(%r28)
+ std %r22, 24(%r28)
+
+ ldd 48(%r29), %r21
+ ldd 56(%r29), %r22
+ std %r19, 32(%r28)
+ std %r20, 40(%r28)
+
+ ldd 64(%r29), %r19
+ ldd 72(%r29), %r20
+ std %r21, 48(%r28)
+ std %r22, 56(%r28)
+
+ ldd 80(%r29), %r21
+ ldd 88(%r29), %r22
+ std %r19, 64(%r28)
+ std %r20, 72(%r28)
+
+ ldd 96(%r29), %r19
+ ldd 104(%r29), %r20
+ std %r21, 80(%r28)
+ std %r22, 88(%r28)
+
+ ldd 112(%r29), %r21
+ ldd 120(%r29), %r22
+ std %r19, 96(%r28)
+ std %r20, 104(%r28)
+
+ ldo 128(%r29), %r29
+ std %r21, 112(%r28)
+ std %r22, 120(%r28)
+ ldo 128(%r28), %r28
+
+ /* conditional branches nullify on forward taken branch, and on
+ * non-taken backward branch. Note that .+4 is a backwards branch.
+ * The ldd should only get executed if the branch is taken.
+ */
+ addib,COND(>),n -1, %r1, 1b /* bundle 10 */
+ ldd 0(%r29), %r19 /* start next loads */
+
+#else
+ ldi (PAGE_SIZE / 64), %r1
+
+ /*
+ * This loop is optimized for PCXL/PCXL2 ldw/ldw and stw/stw
+ * bundles (very restricted rules for bundling). It probably
+ * does OK on PCXU and better, but we could do better with
+ * ldd/std instructions. Note that until (if) we start saving
+ * the full 64 bit register values on interrupt, we can't
+ * use ldd/std on a 32 bit kernel.
+ */
+
+1: ldw 0(%r29), %r19
+ ldw 4(%r29), %r20
+ ldw 8(%r29), %r21
+ ldw 12(%r29), %r22
+ stw %r19, 0(%r28)
+ stw %r20, 4(%r28)
+ stw %r21, 8(%r28)
+ stw %r22, 12(%r28)
+ ldw 16(%r29), %r19
+ ldw 20(%r29), %r20
+ ldw 24(%r29), %r21
+ ldw 28(%r29), %r22
+ stw %r19, 16(%r28)
+ stw %r20, 20(%r28)
+ stw %r21, 24(%r28)
+ stw %r22, 28(%r28)
+ ldw 32(%r29), %r19
+ ldw 36(%r29), %r20
+ ldw 40(%r29), %r21
+ ldw 44(%r29), %r22
+ stw %r19, 32(%r28)
+ stw %r20, 36(%r28)
+ stw %r21, 40(%r28)
+ stw %r22, 44(%r28)
+ ldw 48(%r29), %r19
+ ldw 52(%r29), %r20
+ ldw 56(%r29), %r21
+ ldw 60(%r29), %r22
+ stw %r19, 48(%r28)
+ stw %r20, 52(%r28)
+ stw %r21, 56(%r28)
+ stw %r22, 60(%r28)
+ ldo 64(%r28), %r28
+
+ addib,COND(>) -1, %r1,1b
+ ldo 64(%r29), %r29
+#endif
+
+ bv %r0(%r2)
+ nop
+ENDPROC_CFI(copy_user_page_asm)
+
+ENTRY_CFI(clear_user_page_asm)
+ tophys_r1 %r26
+
+ ldil L%(TMPALIAS_MAP_START), %r28
+ dep_safe %r25, 31,TMPALIAS_SIZE_BITS, %r28 /* Form aliased virtual address 'to' */
+ depi_safe 0, 31,PAGE_SHIFT, %r28 /* Clear any offset bits */
+
+ /* Purge any old translation */
+
+#ifdef CONFIG_PA20
+ pdtlb,l %r0(%r28)
+#else
+0: pdtlb %r0(%r28)
+ ALTERNATIVE(0b, 0b+4, ALT_COND_NO_SMP, INSN_PxTLB)
+#endif
+
+#ifdef CONFIG_64BIT
+ ldi (PAGE_SIZE / 128), %r1
+
+ /* PREFETCH (Write) has not (yet) been proven to help here */
+ /* #define PREFETCHW_OP ldd 256(%0), %r0 */
+
+1: std %r0, 0(%r28)
+ std %r0, 8(%r28)
+ std %r0, 16(%r28)
+ std %r0, 24(%r28)
+ std %r0, 32(%r28)
+ std %r0, 40(%r28)
+ std %r0, 48(%r28)
+ std %r0, 56(%r28)
+ std %r0, 64(%r28)
+ std %r0, 72(%r28)
+ std %r0, 80(%r28)
+ std %r0, 88(%r28)
+ std %r0, 96(%r28)
+ std %r0, 104(%r28)
+ std %r0, 112(%r28)
+ std %r0, 120(%r28)
+ addib,COND(>) -1, %r1, 1b
+ ldo 128(%r28), %r28
+
+#else /* ! CONFIG_64BIT */
+ ldi (PAGE_SIZE / 64), %r1
+
+1: stw %r0, 0(%r28)
+ stw %r0, 4(%r28)
+ stw %r0, 8(%r28)
+ stw %r0, 12(%r28)
+ stw %r0, 16(%r28)
+ stw %r0, 20(%r28)
+ stw %r0, 24(%r28)
+ stw %r0, 28(%r28)
+ stw %r0, 32(%r28)
+ stw %r0, 36(%r28)
+ stw %r0, 40(%r28)
+ stw %r0, 44(%r28)
+ stw %r0, 48(%r28)
+ stw %r0, 52(%r28)
+ stw %r0, 56(%r28)
+ stw %r0, 60(%r28)
+ addib,COND(>) -1, %r1, 1b
+ ldo 64(%r28), %r28
+#endif /* CONFIG_64BIT */
+
+ bv %r0(%r2)
+ nop
+ENDPROC_CFI(clear_user_page_asm)
+
+ENTRY_CFI(flush_dcache_page_asm)
+ ldil L%(TMPALIAS_MAP_START), %r28
+ dep_safe %r25, 31,TMPALIAS_SIZE_BITS, %r28 /* Form aliased virtual address 'to' */
+ depi_safe 0, 31,PAGE_SHIFT, %r28 /* Clear any offset bits */
+
+ /* Purge any old translation */
+
+#ifdef CONFIG_PA20
+ pdtlb,l %r0(%r28)
+#else
+0: pdtlb %r0(%r28)
+ ALTERNATIVE(0b, 0b+4, ALT_COND_NO_SMP, INSN_PxTLB)
+#endif
+
+88: ldil L%dcache_stride, %r1
+ ldw R%dcache_stride(%r1), r31
+
+#ifdef CONFIG_64BIT
+ depdi,z 1, 63-PAGE_SHIFT,1, %r25
+#else
+ depwi,z 1, 31-PAGE_SHIFT,1, %r25
+#endif
+ add %r28, %r25, %r25
+ sub %r25, r31, %r25
+
+1: fdc,m r31(%r28)
+ fdc,m r31(%r28)
+ fdc,m r31(%r28)
+ fdc,m r31(%r28)
+ fdc,m r31(%r28)
+ fdc,m r31(%r28)
+ fdc,m r31(%r28)
+ fdc,m r31(%r28)
+ fdc,m r31(%r28)
+ fdc,m r31(%r28)
+ fdc,m r31(%r28)
+ fdc,m r31(%r28)
+ fdc,m r31(%r28)
+ fdc,m r31(%r28)
+ fdc,m r31(%r28)
+ cmpb,COND(>>) %r25, %r28, 1b /* predict taken */
+ fdc,m r31(%r28)
+
+89: ALTERNATIVE(88b, 89b, ALT_COND_NO_DCACHE, INSN_NOP)
+ sync
+ bv %r0(%r2)
+ nop
+ENDPROC_CFI(flush_dcache_page_asm)
+
+ENTRY_CFI(purge_dcache_page_asm)
+ ldil L%(TMPALIAS_MAP_START), %r28
+ dep_safe %r25, 31,TMPALIAS_SIZE_BITS, %r28 /* Form aliased virtual address 'to' */
+ depi_safe 0, 31,PAGE_SHIFT, %r28 /* Clear any offset bits */
+
+ /* Purge any old translation */
+
+#ifdef CONFIG_PA20
+ pdtlb,l %r0(%r28)
+#else
+0: pdtlb %r0(%r28)
+ ALTERNATIVE(0b, 0b+4, ALT_COND_NO_SMP, INSN_PxTLB)
+#endif
+
+88: ldil L%dcache_stride, %r1
+ ldw R%dcache_stride(%r1), r31
+
+#ifdef CONFIG_64BIT
+ depdi,z 1, 63-PAGE_SHIFT,1, %r25
+#else
+ depwi,z 1, 31-PAGE_SHIFT,1, %r25
+#endif
+ add %r28, %r25, %r25
+ sub %r25, r31, %r25
+
+1: pdc,m r31(%r28)
+ pdc,m r31(%r28)
+ pdc,m r31(%r28)
+ pdc,m r31(%r28)
+ pdc,m r31(%r28)
+ pdc,m r31(%r28)
+ pdc,m r31(%r28)
+ pdc,m r31(%r28)
+ pdc,m r31(%r28)
+ pdc,m r31(%r28)
+ pdc,m r31(%r28)
+ pdc,m r31(%r28)
+ pdc,m r31(%r28)
+ pdc,m r31(%r28)
+ pdc,m r31(%r28)
+ cmpb,COND(>>) %r25, %r28, 1b /* predict taken */
+ pdc,m r31(%r28)
+
+89: ALTERNATIVE(88b, 89b, ALT_COND_NO_DCACHE, INSN_NOP)
+ sync
+ bv %r0(%r2)
+ nop
+ENDPROC_CFI(purge_dcache_page_asm)
+
+ENTRY_CFI(flush_icache_page_asm)
+ ldil L%(TMPALIAS_MAP_START), %r28
+ dep_safe %r25, 31,TMPALIAS_SIZE_BITS, %r28 /* Form aliased virtual address 'to' */
+ depi_safe 0, 31,PAGE_SHIFT, %r28 /* Clear any offset bits */
+
+ /* Purge any old translation. Note that the FIC instruction
+ * may use either the instruction or data TLB. Given that we
+ * have a flat address space, it's not clear which TLB will be
+ * used. So, we purge both entries. */
+
+#ifdef CONFIG_PA20
+ pdtlb,l %r0(%r28)
+1: pitlb,l %r0(%sr4,%r28)
+ ALTERNATIVE(1b, 1b+4, ALT_COND_NO_SPLIT_TLB, INSN_NOP)
+#else
+0: pdtlb %r0(%r28)
+1: pitlb %r0(%sr4,%r28)
+ ALTERNATIVE(0b, 0b+4, ALT_COND_NO_SMP, INSN_PxTLB)
+ ALTERNATIVE(1b, 1b+4, ALT_COND_NO_SMP, INSN_PxTLB)
+ ALTERNATIVE(1b, 1b+4, ALT_COND_NO_SPLIT_TLB, INSN_NOP)
+#endif
+
+88: ldil L%icache_stride, %r1
+ ldw R%icache_stride(%r1), %r31
+
+#ifdef CONFIG_64BIT
+ depdi,z 1, 63-PAGE_SHIFT,1, %r25
+#else
+ depwi,z 1, 31-PAGE_SHIFT,1, %r25
+#endif
+ add %r28, %r25, %r25
+ sub %r25, %r31, %r25
+
+ /* fic only has the type 26 form on PA1.1, requiring an
+ * explicit space specification, so use %sr4 */
+1: fic,m %r31(%sr4,%r28)
+ fic,m %r31(%sr4,%r28)
+ fic,m %r31(%sr4,%r28)
+ fic,m %r31(%sr4,%r28)
+ fic,m %r31(%sr4,%r28)
+ fic,m %r31(%sr4,%r28)
+ fic,m %r31(%sr4,%r28)
+ fic,m %r31(%sr4,%r28)
+ fic,m %r31(%sr4,%r28)
+ fic,m %r31(%sr4,%r28)
+ fic,m %r31(%sr4,%r28)
+ fic,m %r31(%sr4,%r28)
+ fic,m %r31(%sr4,%r28)
+ fic,m %r31(%sr4,%r28)
+ fic,m %r31(%sr4,%r28)
+ cmpb,COND(>>) %r25, %r28, 1b /* predict taken */
+ fic,m %r31(%sr4,%r28)
+
+89: ALTERNATIVE(88b, 89b, ALT_COND_NO_ICACHE, INSN_NOP)
+ sync
+ bv %r0(%r2)
+ nop
+ENDPROC_CFI(flush_icache_page_asm)
+
+ENTRY_CFI(flush_kernel_dcache_page_asm)
+88: ldil L%dcache_stride, %r1
+ ldw R%dcache_stride(%r1), %r23
+ depi_safe 0, 31,PAGE_SHIFT, %r26 /* Clear any offset bits */
+
+#ifdef CONFIG_64BIT
+ depdi,z 1, 63-PAGE_SHIFT,1, %r25
+#else
+ depwi,z 1, 31-PAGE_SHIFT,1, %r25
+#endif
+ add %r26, %r25, %r25
+ sub %r25, %r23, %r25
+
+1: fdc,m %r23(%r26)
+ fdc,m %r23(%r26)
+ fdc,m %r23(%r26)
+ fdc,m %r23(%r26)
+ fdc,m %r23(%r26)
+ fdc,m %r23(%r26)
+ fdc,m %r23(%r26)
+ fdc,m %r23(%r26)
+ fdc,m %r23(%r26)
+ fdc,m %r23(%r26)
+ fdc,m %r23(%r26)
+ fdc,m %r23(%r26)
+ fdc,m %r23(%r26)
+ fdc,m %r23(%r26)
+ fdc,m %r23(%r26)
+ cmpb,COND(>>) %r25, %r26, 1b /* predict taken */
+ fdc,m %r23(%r26)
+
+89: ALTERNATIVE(88b, 89b, ALT_COND_NO_DCACHE, INSN_NOP)
+ sync
+ bv %r0(%r2)
+ nop
+ENDPROC_CFI(flush_kernel_dcache_page_asm)
+
+ENTRY_CFI(purge_kernel_dcache_page_asm)
+88: ldil L%dcache_stride, %r1
+ ldw R%dcache_stride(%r1), %r23
+ depi_safe 0, 31,PAGE_SHIFT, %r26 /* Clear any offset bits */
+
+#ifdef CONFIG_64BIT
+ depdi,z 1, 63-PAGE_SHIFT,1, %r25
+#else
+ depwi,z 1, 31-PAGE_SHIFT,1, %r25
+#endif
+ add %r26, %r25, %r25
+ sub %r25, %r23, %r25
+
+1: pdc,m %r23(%r26)
+ pdc,m %r23(%r26)
+ pdc,m %r23(%r26)
+ pdc,m %r23(%r26)
+ pdc,m %r23(%r26)
+ pdc,m %r23(%r26)
+ pdc,m %r23(%r26)
+ pdc,m %r23(%r26)
+ pdc,m %r23(%r26)
+ pdc,m %r23(%r26)
+ pdc,m %r23(%r26)
+ pdc,m %r23(%r26)
+ pdc,m %r23(%r26)
+ pdc,m %r23(%r26)
+ pdc,m %r23(%r26)
+ cmpb,COND(>>) %r25, %r26, 1b /* predict taken */
+ pdc,m %r23(%r26)
+
+89: ALTERNATIVE(88b, 89b, ALT_COND_NO_DCACHE, INSN_NOP)
+ sync
+ bv %r0(%r2)
+ nop
+ENDPROC_CFI(purge_kernel_dcache_page_asm)
+
+ENTRY_CFI(flush_user_dcache_range_asm)
+88: ldil L%dcache_stride, %r1
+ ldw R%dcache_stride(%r1), %r23
+ ldo -1(%r23), %r21
+ ANDCM %r26, %r21, %r26
+
+#ifdef CONFIG_64BIT
+ depd,z %r23, 59, 60, %r21
+#else
+ depw,z %r23, 27, 28, %r21
+#endif
+ add %r26, %r21, %r22
+ cmpb,COND(>>),n %r22, %r25, 2f /* predict not taken */
+1: add %r22, %r21, %r22
+ fdc,m %r23(%sr3, %r26)
+ fdc,m %r23(%sr3, %r26)
+ fdc,m %r23(%sr3, %r26)
+ fdc,m %r23(%sr3, %r26)
+ fdc,m %r23(%sr3, %r26)
+ fdc,m %r23(%sr3, %r26)
+ fdc,m %r23(%sr3, %r26)
+ fdc,m %r23(%sr3, %r26)
+ fdc,m %r23(%sr3, %r26)
+ fdc,m %r23(%sr3, %r26)
+ fdc,m %r23(%sr3, %r26)
+ fdc,m %r23(%sr3, %r26)
+ fdc,m %r23(%sr3, %r26)
+ fdc,m %r23(%sr3, %r26)
+ fdc,m %r23(%sr3, %r26)
+ cmpb,COND(<<=) %r22, %r25, 1b /* predict taken */
+ fdc,m %r23(%sr3, %r26)
+
+2: cmpb,COND(>>),n %r25, %r26, 2b
+ fdc,m %r23(%sr3, %r26)
+
+89: ALTERNATIVE(88b, 89b, ALT_COND_NO_DCACHE, INSN_NOP)
+ sync
+ bv %r0(%r2)
+ nop
+ENDPROC_CFI(flush_user_dcache_range_asm)
+
+ENTRY_CFI(flush_kernel_dcache_range_asm)
+88: ldil L%dcache_stride, %r1
+ ldw R%dcache_stride(%r1), %r23
+ ldo -1(%r23), %r21
+ ANDCM %r26, %r21, %r26
+
+#ifdef CONFIG_64BIT
+ depd,z %r23, 59, 60, %r21
+#else
+ depw,z %r23, 27, 28, %r21
+#endif
+ add %r26, %r21, %r22
+ cmpb,COND(>>),n %r22, %r25, 2f /* predict not taken */
+1: add %r22, %r21, %r22
+ fdc,m %r23(%r26)
+ fdc,m %r23(%r26)
+ fdc,m %r23(%r26)
+ fdc,m %r23(%r26)
+ fdc,m %r23(%r26)
+ fdc,m %r23(%r26)
+ fdc,m %r23(%r26)
+ fdc,m %r23(%r26)
+ fdc,m %r23(%r26)
+ fdc,m %r23(%r26)
+ fdc,m %r23(%r26)
+ fdc,m %r23(%r26)
+ fdc,m %r23(%r26)
+ fdc,m %r23(%r26)
+ fdc,m %r23(%r26)
+ cmpb,COND(<<=) %r22, %r25, 1b /* predict taken */
+ fdc,m %r23(%r26)
+
+2: cmpb,COND(>>),n %r25, %r26, 2b /* predict taken */
+ fdc,m %r23(%r26)
+
+ sync
+89: ALTERNATIVE(88b, 89b, ALT_COND_NO_DCACHE, INSN_NOP)
+ bv %r0(%r2)
+ nop
+ENDPROC_CFI(flush_kernel_dcache_range_asm)
+
+ENTRY_CFI(purge_kernel_dcache_range_asm)
+88: ldil L%dcache_stride, %r1
+ ldw R%dcache_stride(%r1), %r23
+ ldo -1(%r23), %r21
+ ANDCM %r26, %r21, %r26
+
+#ifdef CONFIG_64BIT
+ depd,z %r23, 59, 60, %r21
+#else
+ depw,z %r23, 27, 28, %r21
+#endif
+ add %r26, %r21, %r22
+ cmpb,COND(>>),n %r22, %r25, 2f /* predict not taken */
+1: add %r22, %r21, %r22
+ pdc,m %r23(%r26)
+ pdc,m %r23(%r26)
+ pdc,m %r23(%r26)
+ pdc,m %r23(%r26)
+ pdc,m %r23(%r26)
+ pdc,m %r23(%r26)
+ pdc,m %r23(%r26)
+ pdc,m %r23(%r26)
+ pdc,m %r23(%r26)
+ pdc,m %r23(%r26)
+ pdc,m %r23(%r26)
+ pdc,m %r23(%r26)
+ pdc,m %r23(%r26)
+ pdc,m %r23(%r26)
+ pdc,m %r23(%r26)
+ cmpb,COND(<<=) %r22, %r25, 1b /* predict taken */
+ pdc,m %r23(%r26)
+
+2: cmpb,COND(>>),n %r25, %r26, 2b /* predict taken */
+ pdc,m %r23(%r26)
+
+ sync
+89: ALTERNATIVE(88b, 89b, ALT_COND_NO_DCACHE, INSN_NOP)
+ bv %r0(%r2)
+ nop
+ENDPROC_CFI(purge_kernel_dcache_range_asm)
+
+ENTRY_CFI(flush_user_icache_range_asm)
+88: ldil L%icache_stride, %r1
+ ldw R%icache_stride(%r1), %r23
+ ldo -1(%r23), %r21
+ ANDCM %r26, %r21, %r26
+
+#ifdef CONFIG_64BIT
+ depd,z %r23, 59, 60, %r21
+#else
+ depw,z %r23, 27, 28, %r21
+#endif
+ add %r26, %r21, %r22
+ cmpb,COND(>>),n %r22, %r25, 2f /* predict not taken */
+1: add %r22, %r21, %r22
+ fic,m %r23(%sr3, %r26)
+ fic,m %r23(%sr3, %r26)
+ fic,m %r23(%sr3, %r26)
+ fic,m %r23(%sr3, %r26)
+ fic,m %r23(%sr3, %r26)
+ fic,m %r23(%sr3, %r26)
+ fic,m %r23(%sr3, %r26)
+ fic,m %r23(%sr3, %r26)
+ fic,m %r23(%sr3, %r26)
+ fic,m %r23(%sr3, %r26)
+ fic,m %r23(%sr3, %r26)
+ fic,m %r23(%sr3, %r26)
+ fic,m %r23(%sr3, %r26)
+ fic,m %r23(%sr3, %r26)
+ fic,m %r23(%sr3, %r26)
+ cmpb,COND(<<=) %r22, %r25, 1b /* predict taken */
+ fic,m %r23(%sr3, %r26)
+
+2: cmpb,COND(>>),n %r25, %r26, 2b
+ fic,m %r23(%sr3, %r26)
+
+89: ALTERNATIVE(88b, 89b, ALT_COND_NO_ICACHE, INSN_NOP)
+ sync
+ bv %r0(%r2)
+ nop
+ENDPROC_CFI(flush_user_icache_range_asm)
+
+ENTRY_CFI(flush_kernel_icache_page)
+88: ldil L%icache_stride, %r1
+ ldw R%icache_stride(%r1), %r23
+
+#ifdef CONFIG_64BIT
+ depdi,z 1, 63-PAGE_SHIFT,1, %r25
+#else
+ depwi,z 1, 31-PAGE_SHIFT,1, %r25
+#endif
+ add %r26, %r25, %r25
+ sub %r25, %r23, %r25
+
+
+1: fic,m %r23(%sr4, %r26)
+ fic,m %r23(%sr4, %r26)
+ fic,m %r23(%sr4, %r26)
+ fic,m %r23(%sr4, %r26)
+ fic,m %r23(%sr4, %r26)
+ fic,m %r23(%sr4, %r26)
+ fic,m %r23(%sr4, %r26)
+ fic,m %r23(%sr4, %r26)
+ fic,m %r23(%sr4, %r26)
+ fic,m %r23(%sr4, %r26)
+ fic,m %r23(%sr4, %r26)
+ fic,m %r23(%sr4, %r26)
+ fic,m %r23(%sr4, %r26)
+ fic,m %r23(%sr4, %r26)
+ fic,m %r23(%sr4, %r26)
+ cmpb,COND(>>) %r25, %r26, 1b /* predict taken */
+ fic,m %r23(%sr4, %r26)
+
+89: ALTERNATIVE(88b, 89b, ALT_COND_NO_ICACHE, INSN_NOP)
+ sync
+ bv %r0(%r2)
+ nop
+ENDPROC_CFI(flush_kernel_icache_page)
+
+ENTRY_CFI(flush_kernel_icache_range_asm)
+88: ldil L%icache_stride, %r1
+ ldw R%icache_stride(%r1), %r23
+ ldo -1(%r23), %r21
+ ANDCM %r26, %r21, %r26
+
+#ifdef CONFIG_64BIT
+ depd,z %r23, 59, 60, %r21
+#else
+ depw,z %r23, 27, 28, %r21
+#endif
+ add %r26, %r21, %r22
+ cmpb,COND(>>),n %r22, %r25, 2f /* predict not taken */
+1: add %r22, %r21, %r22
+ fic,m %r23(%sr4, %r26)
+ fic,m %r23(%sr4, %r26)
+ fic,m %r23(%sr4, %r26)
+ fic,m %r23(%sr4, %r26)
+ fic,m %r23(%sr4, %r26)
+ fic,m %r23(%sr4, %r26)
+ fic,m %r23(%sr4, %r26)
+ fic,m %r23(%sr4, %r26)
+ fic,m %r23(%sr4, %r26)
+ fic,m %r23(%sr4, %r26)
+ fic,m %r23(%sr4, %r26)
+ fic,m %r23(%sr4, %r26)
+ fic,m %r23(%sr4, %r26)
+ fic,m %r23(%sr4, %r26)
+ fic,m %r23(%sr4, %r26)
+ cmpb,COND(<<=) %r22, %r25, 1b /* predict taken */
+ fic,m %r23(%sr4, %r26)
+
+2: cmpb,COND(>>),n %r25, %r26, 2b /* predict taken */
+ fic,m %r23(%sr4, %r26)
+
+89: ALTERNATIVE(88b, 89b, ALT_COND_NO_ICACHE, INSN_NOP)
+ sync
+ bv %r0(%r2)
+ nop
+ENDPROC_CFI(flush_kernel_icache_range_asm)
+
+ .text
+
+ /* align should cover use of rfi in disable_sr_hashing_asm and
+ * srdis_done.
+ */
+ .align 256
+ENTRY_CFI(disable_sr_hashing_asm)
+ /*
+ * Switch to real mode
+ */
+ /* pcxt_ssm_bug */
+ rsm PSW_SM_I, %r0
+ load32 PA(1f), %r1
+ nop
+ nop
+ nop
+ nop
+ nop
+
+ rsm PSW_SM_Q, %r0 /* prep to load iia queue */
+ mtctl %r0, %cr17 /* Clear IIASQ tail */
+ mtctl %r0, %cr17 /* Clear IIASQ head */
+ mtctl %r1, %cr18 /* IIAOQ head */
+ ldo 4(%r1), %r1
+ mtctl %r1, %cr18 /* IIAOQ tail */
+ load32 REAL_MODE_PSW, %r1
+ mtctl %r1, %ipsw
+ rfi
+ nop
+
+1: cmpib,=,n SRHASH_PCXST, %r26,srdis_pcxs
+ cmpib,=,n SRHASH_PCXL, %r26,srdis_pcxl
+ cmpib,=,n SRHASH_PA20, %r26,srdis_pa20
+ b,n srdis_done
+
+srdis_pcxs:
+
+ /* Disable Space Register Hashing for PCXS,PCXT,PCXT' */
+
+ .word 0x141c1a00 /* mfdiag %dr0, %r28 */
+ .word 0x141c1a00 /* must issue twice */
+ depwi 0,18,1, %r28 /* Clear DHE (dcache hash enable) */
+ depwi 0,20,1, %r28 /* Clear IHE (icache hash enable) */
+ .word 0x141c1600 /* mtdiag %r28, %dr0 */
+ .word 0x141c1600 /* must issue twice */
+ b,n srdis_done
+
+srdis_pcxl:
+
+ /* Disable Space Register Hashing for PCXL */
+
+ .word 0x141c0600 /* mfdiag %dr0, %r28 */
+ depwi 0,28,2, %r28 /* Clear DHASH_EN & IHASH_EN */
+ .word 0x141c0240 /* mtdiag %r28, %dr0 */
+ b,n srdis_done
+
+srdis_pa20:
+
+ /* Disable Space Register Hashing for PCXU,PCXU+,PCXW,PCXW+,PCXW2 */
+
+ .word 0x144008bc /* mfdiag %dr2, %r28 */
+ depdi 0, 54,1, %r28 /* clear DIAG_SPHASH_ENAB (bit 54) */
+ .word 0x145c1840 /* mtdiag %r28, %dr2 */
+
+
+srdis_done:
+ /* Switch back to virtual mode */
+ rsm PSW_SM_I, %r0 /* prep to load iia queue */
+ load32 2f, %r1
+ nop
+ nop
+ nop
+ nop
+ nop
+
+ rsm PSW_SM_Q, %r0 /* prep to load iia queue */
+ mtctl %r0, %cr17 /* Clear IIASQ tail */
+ mtctl %r0, %cr17 /* Clear IIASQ head */
+ mtctl %r1, %cr18 /* IIAOQ head */
+ ldo 4(%r1), %r1
+ mtctl %r1, %cr18 /* IIAOQ tail */
+ load32 KERNEL_PSW, %r1
+ mtctl %r1, %ipsw
+ rfi
+ nop
+
+2: bv %r0(%r2)
+ nop
+ENDPROC_CFI(disable_sr_hashing_asm)
+
+ .end
diff --git a/arch/parisc/kernel/parisc_ksyms.c b/arch/parisc/kernel/parisc_ksyms.c
new file mode 100644
index 000000000..6f0c92e81
--- /dev/null
+++ b/arch/parisc/kernel/parisc_ksyms.c
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Architecture-specific kernel symbols
+ *
+ * Copyright (C) 2000-2001 Richard Hirst <rhirst with parisc-linux.org>
+ * Copyright (C) 2001 Dave Kennedy
+ * Copyright (C) 2001 Paul Bame <bame at parisc-linux.org>
+ * Copyright (C) 2001-2003 Grant Grundler <grundler with parisc-linux.org>
+ * Copyright (C) 2002-2003 Matthew Wilcox <willy at parisc-linux.org>
+ * Copyright (C) 2002 Randolph Chung <tausq at parisc-linux.org>
+ * Copyright (C) 2002-2007 Helge Deller <deller with parisc-linux.org>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/syscalls.h>
+#include <linux/libgcc.h>
+
+#include <linux/string.h>
+EXPORT_SYMBOL(memset);
+
+#include <linux/atomic.h>
+EXPORT_SYMBOL(__xchg8);
+EXPORT_SYMBOL(__xchg32);
+EXPORT_SYMBOL(__cmpxchg_u32);
+EXPORT_SYMBOL(__cmpxchg_u64);
+#ifdef CONFIG_SMP
+EXPORT_SYMBOL(__atomic_hash);
+#endif
+#ifdef CONFIG_64BIT
+EXPORT_SYMBOL(__xchg64);
+#endif
+
+#include <linux/uaccess.h>
+EXPORT_SYMBOL(lclear_user);
+
+#ifndef CONFIG_64BIT
+/* Needed so insmod can set dp value */
+extern int $global$;
+EXPORT_SYMBOL($global$);
+#endif
+
+#include <asm/io.h>
+EXPORT_SYMBOL(memcpy_toio);
+EXPORT_SYMBOL(memcpy_fromio);
+EXPORT_SYMBOL(memset_io);
+
+extern void $$divI(void);
+extern void $$divU(void);
+extern void $$remI(void);
+extern void $$remU(void);
+extern void $$mulI(void);
+extern void $$divU_3(void);
+extern void $$divU_5(void);
+extern void $$divU_6(void);
+extern void $$divU_9(void);
+extern void $$divU_10(void);
+extern void $$divU_12(void);
+extern void $$divU_7(void);
+extern void $$divU_14(void);
+extern void $$divU_15(void);
+extern void $$divI_3(void);
+extern void $$divI_5(void);
+extern void $$divI_6(void);
+extern void $$divI_7(void);
+extern void $$divI_9(void);
+extern void $$divI_10(void);
+extern void $$divI_12(void);
+extern void $$divI_14(void);
+extern void $$divI_15(void);
+
+EXPORT_SYMBOL($$divI);
+EXPORT_SYMBOL($$divU);
+EXPORT_SYMBOL($$remI);
+EXPORT_SYMBOL($$remU);
+EXPORT_SYMBOL($$mulI);
+EXPORT_SYMBOL($$divU_3);
+EXPORT_SYMBOL($$divU_5);
+EXPORT_SYMBOL($$divU_6);
+EXPORT_SYMBOL($$divU_9);
+EXPORT_SYMBOL($$divU_10);
+EXPORT_SYMBOL($$divU_12);
+EXPORT_SYMBOL($$divU_7);
+EXPORT_SYMBOL($$divU_14);
+EXPORT_SYMBOL($$divU_15);
+EXPORT_SYMBOL($$divI_3);
+EXPORT_SYMBOL($$divI_5);
+EXPORT_SYMBOL($$divI_6);
+EXPORT_SYMBOL($$divI_7);
+EXPORT_SYMBOL($$divI_9);
+EXPORT_SYMBOL($$divI_10);
+EXPORT_SYMBOL($$divI_12);
+EXPORT_SYMBOL($$divI_14);
+EXPORT_SYMBOL($$divI_15);
+
+EXPORT_SYMBOL(__ashrdi3);
+EXPORT_SYMBOL(__ashldi3);
+EXPORT_SYMBOL(__lshrdi3);
+EXPORT_SYMBOL(__muldi3);
+EXPORT_SYMBOL(__ucmpdi2);
+
+asmlinkage void * __canonicalize_funcptr_for_compare(void *);
+EXPORT_SYMBOL(__canonicalize_funcptr_for_compare);
+
+#ifdef CONFIG_64BIT
+extern void __divdi3(void);
+extern void __udivdi3(void);
+extern void __umoddi3(void);
+extern void __moddi3(void);
+
+EXPORT_SYMBOL(__divdi3);
+EXPORT_SYMBOL(__udivdi3);
+EXPORT_SYMBOL(__umoddi3);
+EXPORT_SYMBOL(__moddi3);
+#endif
+
+#ifndef CONFIG_64BIT
+extern void $$dyncall(void);
+EXPORT_SYMBOL($$dyncall);
+#endif
+
+#ifdef CONFIG_FUNCTION_TRACER
+extern void _mcount(void);
+EXPORT_SYMBOL(_mcount);
+#endif
+
+/* from pacache.S -- needed for clear/copy_page */
+EXPORT_SYMBOL(clear_page_asm);
+EXPORT_SYMBOL(copy_page_asm);
diff --git a/arch/parisc/kernel/patch.c b/arch/parisc/kernel/patch.c
new file mode 100644
index 000000000..e59574f65
--- /dev/null
+++ b/arch/parisc/kernel/patch.c
@@ -0,0 +1,130 @@
+// SPDX-License-Identifier: GPL-2.0
+ /*
+ * functions to patch RO kernel text during runtime
+ *
+ * Copyright (c) 2019 Sven Schnelle <svens@stackframe.org>
+ */
+
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/kprobes.h>
+#include <linux/mm.h>
+#include <linux/stop_machine.h>
+
+#include <asm/cacheflush.h>
+#include <asm/fixmap.h>
+#include <asm/patch.h>
+
+struct patch {
+ void *addr;
+ u32 *insn;
+ unsigned int len;
+};
+
+static DEFINE_RAW_SPINLOCK(patch_lock);
+
+static void __kprobes *patch_map(void *addr, int fixmap, unsigned long *flags,
+ int *need_unmap)
+{
+ unsigned long uintaddr = (uintptr_t) addr;
+ bool module = !core_kernel_text(uintaddr);
+ struct page *page;
+
+ *need_unmap = 0;
+ if (module && IS_ENABLED(CONFIG_STRICT_MODULE_RWX))
+ page = vmalloc_to_page(addr);
+ else if (!module && IS_ENABLED(CONFIG_STRICT_KERNEL_RWX))
+ page = virt_to_page(addr);
+ else
+ return addr;
+
+ *need_unmap = 1;
+ set_fixmap(fixmap, page_to_phys(page));
+ raw_spin_lock_irqsave(&patch_lock, *flags);
+
+ return (void *) (__fix_to_virt(fixmap) + (uintaddr & ~PAGE_MASK));
+}
+
+static void __kprobes patch_unmap(int fixmap, unsigned long *flags)
+{
+ clear_fixmap(fixmap);
+
+ raw_spin_unlock_irqrestore(&patch_lock, *flags);
+}
+
+void __kprobes __patch_text_multiple(void *addr, u32 *insn, unsigned int len)
+{
+ unsigned long start = (unsigned long)addr;
+ unsigned long end = (unsigned long)addr + len;
+ unsigned long flags;
+ u32 *p, *fixmap;
+ int mapped;
+
+ /* Make sure we don't have any aliases in cache */
+ flush_kernel_dcache_range_asm(start, end);
+ flush_kernel_icache_range_asm(start, end);
+ flush_tlb_kernel_range(start, end);
+
+ p = fixmap = patch_map(addr, FIX_TEXT_POKE0, &flags, &mapped);
+
+ while (len >= 4) {
+ *p++ = *insn++;
+ addr += sizeof(u32);
+ len -= sizeof(u32);
+ if (len && offset_in_page(addr) == 0) {
+ /*
+ * We're crossing a page boundary, so
+ * need to remap
+ */
+ flush_kernel_dcache_range_asm((unsigned long)fixmap,
+ (unsigned long)p);
+ flush_tlb_kernel_range((unsigned long)fixmap,
+ (unsigned long)p);
+ if (mapped)
+ patch_unmap(FIX_TEXT_POKE0, &flags);
+ p = fixmap = patch_map(addr, FIX_TEXT_POKE0, &flags,
+ &mapped);
+ }
+ }
+
+ flush_kernel_dcache_range_asm((unsigned long)fixmap, (unsigned long)p);
+ flush_tlb_kernel_range((unsigned long)fixmap, (unsigned long)p);
+ if (mapped)
+ patch_unmap(FIX_TEXT_POKE0, &flags);
+}
+
+void __kprobes __patch_text(void *addr, u32 insn)
+{
+ __patch_text_multiple(addr, &insn, sizeof(insn));
+}
+
+static int __kprobes patch_text_stop_machine(void *data)
+{
+ struct patch *patch = data;
+
+ __patch_text_multiple(patch->addr, patch->insn, patch->len);
+ return 0;
+}
+
+void __kprobes patch_text(void *addr, unsigned int insn)
+{
+ struct patch patch = {
+ .addr = addr,
+ .insn = &insn,
+ .len = sizeof(insn),
+ };
+
+ stop_machine_cpuslocked(patch_text_stop_machine, &patch, NULL);
+}
+
+void __kprobes patch_text_multiple(void *addr, u32 *insn, unsigned int len)
+{
+
+ struct patch patch = {
+ .addr = addr,
+ .insn = insn,
+ .len = len
+ };
+
+ stop_machine_cpuslocked(patch_text_stop_machine, &patch, NULL);
+}
diff --git a/arch/parisc/kernel/pci-dma.c b/arch/parisc/kernel/pci-dma.c
new file mode 100644
index 000000000..bf9f192c8
--- /dev/null
+++ b/arch/parisc/kernel/pci-dma.c
@@ -0,0 +1,464 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+** PARISC 1.1 Dynamic DMA mapping support.
+** This implementation is for PA-RISC platforms that do not support
+** I/O TLBs (aka DMA address translation hardware).
+** See Documentation/core-api/dma-api-howto.rst for interface definitions.
+**
+** (c) Copyright 1999,2000 Hewlett-Packard Company
+** (c) Copyright 2000 Grant Grundler
+** (c) Copyright 2000 Philipp Rumpf <prumpf@tux.org>
+** (c) Copyright 2000 John Marvin
+**
+** "leveraged" from 2.3.47: arch/ia64/kernel/pci-dma.c.
+** (I assume it's from David Mosberger-Tang but there was no Copyright)
+**
+** AFAIK, all PA7100LC and PA7300LC platforms can use this code.
+**
+** - ggg
+*/
+
+#include <linux/init.h>
+#include <linux/gfp.h>
+#include <linux/mm.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/dma-direct.h>
+#include <linux/dma-map-ops.h>
+
+#include <asm/cacheflush.h>
+#include <asm/dma.h> /* for DMA_CHUNK_SIZE */
+#include <asm/io.h>
+#include <asm/page.h> /* get_order */
+#include <linux/uaccess.h>
+#include <asm/tlbflush.h> /* for purge_tlb_*() macros */
+
+static struct proc_dir_entry * proc_gsc_root __read_mostly = NULL;
+static unsigned long pcxl_used_bytes __read_mostly;
+static unsigned long pcxl_used_pages __read_mostly;
+
+unsigned long pcxl_dma_start __ro_after_init; /* pcxl dma mapping area start */
+static DEFINE_SPINLOCK(pcxl_res_lock);
+static char *pcxl_res_map;
+static int pcxl_res_hint;
+static int pcxl_res_size;
+
+#ifdef DEBUG_PCXL_RESOURCE
+#define DBG_RES(x...) printk(x)
+#else
+#define DBG_RES(x...)
+#endif
+
+
+/*
+** Dump a hex representation of the resource map.
+*/
+
+#ifdef DUMP_RESMAP
+static
+void dump_resmap(void)
+{
+ u_long *res_ptr = (unsigned long *)pcxl_res_map;
+ u_long i = 0;
+
+ printk("res_map: ");
+ for(; i < (pcxl_res_size / sizeof(unsigned long)); ++i, ++res_ptr)
+ printk("%08lx ", *res_ptr);
+
+ printk("\n");
+}
+#else
+static inline void dump_resmap(void) {;}
+#endif
+
+static inline int map_pte_uncached(pte_t * pte,
+ unsigned long vaddr,
+ unsigned long size, unsigned long *paddr_ptr)
+{
+ unsigned long end;
+ unsigned long orig_vaddr = vaddr;
+
+ vaddr &= ~PMD_MASK;
+ end = vaddr + size;
+ if (end > PMD_SIZE)
+ end = PMD_SIZE;
+ do {
+ unsigned long flags;
+
+ if (!pte_none(*pte))
+ printk(KERN_ERR "map_pte_uncached: page already exists\n");
+ purge_tlb_start(flags);
+ set_pte(pte, __mk_pte(*paddr_ptr, PAGE_KERNEL_UNC));
+ pdtlb(SR_KERNEL, orig_vaddr);
+ purge_tlb_end(flags);
+ vaddr += PAGE_SIZE;
+ orig_vaddr += PAGE_SIZE;
+ (*paddr_ptr) += PAGE_SIZE;
+ pte++;
+ } while (vaddr < end);
+ return 0;
+}
+
+static inline int map_pmd_uncached(pmd_t * pmd, unsigned long vaddr,
+ unsigned long size, unsigned long *paddr_ptr)
+{
+ unsigned long end;
+ unsigned long orig_vaddr = vaddr;
+
+ vaddr &= ~PGDIR_MASK;
+ end = vaddr + size;
+ if (end > PGDIR_SIZE)
+ end = PGDIR_SIZE;
+ do {
+ pte_t * pte = pte_alloc_kernel(pmd, vaddr);
+ if (!pte)
+ return -ENOMEM;
+ if (map_pte_uncached(pte, orig_vaddr, end - vaddr, paddr_ptr))
+ return -ENOMEM;
+ vaddr = (vaddr + PMD_SIZE) & PMD_MASK;
+ orig_vaddr += PMD_SIZE;
+ pmd++;
+ } while (vaddr < end);
+ return 0;
+}
+
+static inline int map_uncached_pages(unsigned long vaddr, unsigned long size,
+ unsigned long paddr)
+{
+ pgd_t * dir;
+ unsigned long end = vaddr + size;
+
+ dir = pgd_offset_k(vaddr);
+ do {
+ p4d_t *p4d;
+ pud_t *pud;
+ pmd_t *pmd;
+
+ p4d = p4d_offset(dir, vaddr);
+ pud = pud_offset(p4d, vaddr);
+ pmd = pmd_alloc(NULL, pud, vaddr);
+
+ if (!pmd)
+ return -ENOMEM;
+ if (map_pmd_uncached(pmd, vaddr, end - vaddr, &paddr))
+ return -ENOMEM;
+ vaddr = vaddr + PGDIR_SIZE;
+ dir++;
+ } while (vaddr && (vaddr < end));
+ return 0;
+}
+
+static inline void unmap_uncached_pte(pmd_t * pmd, unsigned long vaddr,
+ unsigned long size)
+{
+ pte_t * pte;
+ unsigned long end;
+ unsigned long orig_vaddr = vaddr;
+
+ if (pmd_none(*pmd))
+ return;
+ if (pmd_bad(*pmd)) {
+ pmd_ERROR(*pmd);
+ pmd_clear(pmd);
+ return;
+ }
+ pte = pte_offset_kernel(pmd, vaddr);
+ vaddr &= ~PMD_MASK;
+ end = vaddr + size;
+ if (end > PMD_SIZE)
+ end = PMD_SIZE;
+ do {
+ unsigned long flags;
+ pte_t page = *pte;
+
+ pte_clear(&init_mm, vaddr, pte);
+ purge_tlb_start(flags);
+ pdtlb(SR_KERNEL, orig_vaddr);
+ purge_tlb_end(flags);
+ vaddr += PAGE_SIZE;
+ orig_vaddr += PAGE_SIZE;
+ pte++;
+ if (pte_none(page) || pte_present(page))
+ continue;
+ printk(KERN_CRIT "Whee.. Swapped out page in kernel page table\n");
+ } while (vaddr < end);
+}
+
+static inline void unmap_uncached_pmd(pgd_t * dir, unsigned long vaddr,
+ unsigned long size)
+{
+ pmd_t * pmd;
+ unsigned long end;
+ unsigned long orig_vaddr = vaddr;
+
+ if (pgd_none(*dir))
+ return;
+ if (pgd_bad(*dir)) {
+ pgd_ERROR(*dir);
+ pgd_clear(dir);
+ return;
+ }
+ pmd = pmd_offset(pud_offset(p4d_offset(dir, vaddr), vaddr), vaddr);
+ vaddr &= ~PGDIR_MASK;
+ end = vaddr + size;
+ if (end > PGDIR_SIZE)
+ end = PGDIR_SIZE;
+ do {
+ unmap_uncached_pte(pmd, orig_vaddr, end - vaddr);
+ vaddr = (vaddr + PMD_SIZE) & PMD_MASK;
+ orig_vaddr += PMD_SIZE;
+ pmd++;
+ } while (vaddr < end);
+}
+
+static void unmap_uncached_pages(unsigned long vaddr, unsigned long size)
+{
+ pgd_t * dir;
+ unsigned long end = vaddr + size;
+
+ dir = pgd_offset_k(vaddr);
+ do {
+ unmap_uncached_pmd(dir, vaddr, end - vaddr);
+ vaddr = vaddr + PGDIR_SIZE;
+ dir++;
+ } while (vaddr && (vaddr < end));
+}
+
+#define PCXL_SEARCH_LOOP(idx, mask, size) \
+ for(; res_ptr < res_end; ++res_ptr) \
+ { \
+ if(0 == ((*res_ptr) & mask)) { \
+ *res_ptr |= mask; \
+ idx = (int)((u_long)res_ptr - (u_long)pcxl_res_map); \
+ pcxl_res_hint = idx + (size >> 3); \
+ goto resource_found; \
+ } \
+ }
+
+#define PCXL_FIND_FREE_MAPPING(idx, mask, size) { \
+ u##size *res_ptr = (u##size *)&(pcxl_res_map[pcxl_res_hint & ~((size >> 3) - 1)]); \
+ u##size *res_end = (u##size *)&pcxl_res_map[pcxl_res_size]; \
+ PCXL_SEARCH_LOOP(idx, mask, size); \
+ res_ptr = (u##size *)&pcxl_res_map[0]; \
+ PCXL_SEARCH_LOOP(idx, mask, size); \
+}
+
+static unsigned long
+pcxl_alloc_range(size_t size)
+{
+ int res_idx;
+ u_long mask, flags;
+ unsigned int pages_needed = size >> PAGE_SHIFT;
+
+ mask = (u_long) -1L;
+ mask >>= BITS_PER_LONG - pages_needed;
+
+ DBG_RES("pcxl_alloc_range() size: %d pages_needed %d pages_mask 0x%08lx\n",
+ size, pages_needed, mask);
+
+ spin_lock_irqsave(&pcxl_res_lock, flags);
+
+ if(pages_needed <= 8) {
+ PCXL_FIND_FREE_MAPPING(res_idx, mask, 8);
+ } else if(pages_needed <= 16) {
+ PCXL_FIND_FREE_MAPPING(res_idx, mask, 16);
+ } else if(pages_needed <= 32) {
+ PCXL_FIND_FREE_MAPPING(res_idx, mask, 32);
+ } else {
+ panic("%s: pcxl_alloc_range() Too many pages to map.\n",
+ __FILE__);
+ }
+
+ dump_resmap();
+ panic("%s: pcxl_alloc_range() out of dma mapping resources\n",
+ __FILE__);
+
+resource_found:
+
+ DBG_RES("pcxl_alloc_range() res_idx %d mask 0x%08lx res_hint: %d\n",
+ res_idx, mask, pcxl_res_hint);
+
+ pcxl_used_pages += pages_needed;
+ pcxl_used_bytes += ((pages_needed >> 3) ? (pages_needed >> 3) : 1);
+
+ spin_unlock_irqrestore(&pcxl_res_lock, flags);
+
+ dump_resmap();
+
+ /*
+ ** return the corresponding vaddr in the pcxl dma map
+ */
+ return (pcxl_dma_start + (res_idx << (PAGE_SHIFT + 3)));
+}
+
+#define PCXL_FREE_MAPPINGS(idx, m, size) \
+ u##size *res_ptr = (u##size *)&(pcxl_res_map[(idx) + (((size >> 3) - 1) & (~((size >> 3) - 1)))]); \
+ /* BUG_ON((*res_ptr & m) != m); */ \
+ *res_ptr &= ~m;
+
+/*
+** clear bits in the pcxl resource map
+*/
+static void
+pcxl_free_range(unsigned long vaddr, size_t size)
+{
+ u_long mask, flags;
+ unsigned int res_idx = (vaddr - pcxl_dma_start) >> (PAGE_SHIFT + 3);
+ unsigned int pages_mapped = size >> PAGE_SHIFT;
+
+ mask = (u_long) -1L;
+ mask >>= BITS_PER_LONG - pages_mapped;
+
+ DBG_RES("pcxl_free_range() res_idx: %d size: %d pages_mapped %d mask 0x%08lx\n",
+ res_idx, size, pages_mapped, mask);
+
+ spin_lock_irqsave(&pcxl_res_lock, flags);
+
+ if(pages_mapped <= 8) {
+ PCXL_FREE_MAPPINGS(res_idx, mask, 8);
+ } else if(pages_mapped <= 16) {
+ PCXL_FREE_MAPPINGS(res_idx, mask, 16);
+ } else if(pages_mapped <= 32) {
+ PCXL_FREE_MAPPINGS(res_idx, mask, 32);
+ } else {
+ panic("%s: pcxl_free_range() Too many pages to unmap.\n",
+ __FILE__);
+ }
+
+ pcxl_used_pages -= (pages_mapped ? pages_mapped : 1);
+ pcxl_used_bytes -= ((pages_mapped >> 3) ? (pages_mapped >> 3) : 1);
+
+ spin_unlock_irqrestore(&pcxl_res_lock, flags);
+
+ dump_resmap();
+}
+
+static int __maybe_unused proc_pcxl_dma_show(struct seq_file *m, void *v)
+{
+#if 0
+ u_long i = 0;
+ unsigned long *res_ptr = (u_long *)pcxl_res_map;
+#endif
+ unsigned long total_pages = pcxl_res_size << 3; /* 8 bits per byte */
+
+ seq_printf(m, "\nDMA Mapping Area size : %d bytes (%ld pages)\n",
+ PCXL_DMA_MAP_SIZE, total_pages);
+
+ seq_printf(m, "Resource bitmap : %d bytes\n", pcxl_res_size);
+
+ seq_puts(m, " total: free: used: % used:\n");
+ seq_printf(m, "blocks %8d %8ld %8ld %8ld%%\n", pcxl_res_size,
+ pcxl_res_size - pcxl_used_bytes, pcxl_used_bytes,
+ (pcxl_used_bytes * 100) / pcxl_res_size);
+
+ seq_printf(m, "pages %8ld %8ld %8ld %8ld%%\n", total_pages,
+ total_pages - pcxl_used_pages, pcxl_used_pages,
+ (pcxl_used_pages * 100 / total_pages));
+
+#if 0
+ seq_puts(m, "\nResource bitmap:");
+
+ for(; i < (pcxl_res_size / sizeof(u_long)); ++i, ++res_ptr) {
+ if ((i & 7) == 0)
+ seq_puts(m,"\n ");
+ seq_printf(m, "%s %08lx", buf, *res_ptr);
+ }
+#endif
+ seq_putc(m, '\n');
+ return 0;
+}
+
+static int __init
+pcxl_dma_init(void)
+{
+ if (pcxl_dma_start == 0)
+ return 0;
+
+ pcxl_res_size = PCXL_DMA_MAP_SIZE >> (PAGE_SHIFT + 3);
+ pcxl_res_hint = 0;
+ pcxl_res_map = (char *)__get_free_pages(GFP_KERNEL,
+ get_order(pcxl_res_size));
+ memset(pcxl_res_map, 0, pcxl_res_size);
+ proc_gsc_root = proc_mkdir("bus/gsc", NULL);
+ if (!proc_gsc_root)
+ printk(KERN_WARNING
+ "pcxl_dma_init: Unable to create gsc /proc dir entry\n");
+ else {
+ struct proc_dir_entry* ent;
+ ent = proc_create_single("pcxl_dma", 0, proc_gsc_root,
+ proc_pcxl_dma_show);
+ if (!ent)
+ printk(KERN_WARNING
+ "pci-dma.c: Unable to create pcxl_dma /proc entry.\n");
+ }
+ return 0;
+}
+
+__initcall(pcxl_dma_init);
+
+void *arch_dma_alloc(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t gfp, unsigned long attrs)
+{
+ unsigned long vaddr;
+ unsigned long paddr;
+ int order;
+
+ if (boot_cpu_data.cpu_type != pcxl2 && boot_cpu_data.cpu_type != pcxl)
+ return NULL;
+
+ order = get_order(size);
+ size = 1 << (order + PAGE_SHIFT);
+ vaddr = pcxl_alloc_range(size);
+ paddr = __get_free_pages(gfp | __GFP_ZERO, order);
+ flush_kernel_dcache_range(paddr, size);
+ paddr = __pa(paddr);
+ map_uncached_pages(vaddr, size, paddr);
+ *dma_handle = (dma_addr_t) paddr;
+
+ return (void *)vaddr;
+}
+
+void arch_dma_free(struct device *dev, size_t size, void *vaddr,
+ dma_addr_t dma_handle, unsigned long attrs)
+{
+ int order = get_order(size);
+
+ WARN_ON_ONCE(boot_cpu_data.cpu_type != pcxl2 &&
+ boot_cpu_data.cpu_type != pcxl);
+
+ size = 1 << (order + PAGE_SHIFT);
+ unmap_uncached_pages((unsigned long)vaddr, size);
+ pcxl_free_range((unsigned long)vaddr, size);
+
+ free_pages((unsigned long)__va(dma_handle), order);
+}
+
+void arch_sync_dma_for_device(phys_addr_t paddr, size_t size,
+ enum dma_data_direction dir)
+{
+ /*
+ * fdc: The data cache line is written back to memory, if and only if
+ * it is dirty, and then invalidated from the data cache.
+ */
+ flush_kernel_dcache_range((unsigned long)phys_to_virt(paddr), size);
+}
+
+void arch_sync_dma_for_cpu(phys_addr_t paddr, size_t size,
+ enum dma_data_direction dir)
+{
+ unsigned long addr = (unsigned long) phys_to_virt(paddr);
+
+ switch (dir) {
+ case DMA_TO_DEVICE:
+ case DMA_BIDIRECTIONAL:
+ flush_kernel_dcache_range(addr, size);
+ return;
+ case DMA_FROM_DEVICE:
+ purge_kernel_dcache_range_asm(addr, addr + size);
+ return;
+ default:
+ BUG();
+ }
+}
diff --git a/arch/parisc/kernel/pci.c b/arch/parisc/kernel/pci.c
new file mode 100644
index 000000000..cf285b17a
--- /dev/null
+++ b/arch/parisc/kernel/pci.c
@@ -0,0 +1,268 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1997, 1998 Ralf Baechle
+ * Copyright (C) 1999 SuSE GmbH
+ * Copyright (C) 1999-2001 Hewlett-Packard Company
+ * Copyright (C) 1999-2001 Grant Grundler
+ */
+#include <linux/eisa.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/types.h>
+
+#include <asm/io.h>
+#include <asm/superio.h>
+
+#define DEBUG_RESOURCES 0
+#define DEBUG_CONFIG 0
+
+#if DEBUG_CONFIG
+# define DBGC(x...) printk(KERN_DEBUG x)
+#else
+# define DBGC(x...)
+#endif
+
+
+#if DEBUG_RESOURCES
+#define DBG_RES(x...) printk(KERN_DEBUG x)
+#else
+#define DBG_RES(x...)
+#endif
+
+struct pci_port_ops *pci_port __ro_after_init;
+struct pci_bios_ops *pci_bios __ro_after_init;
+
+static int pci_hba_count __ro_after_init;
+
+/* parisc_pci_hba used by pci_port->in/out() ops to lookup bus data. */
+#define PCI_HBA_MAX 32
+static struct pci_hba_data *parisc_pci_hba[PCI_HBA_MAX] __ro_after_init;
+
+
+/********************************************************************
+**
+** I/O port space support
+**
+*********************************************************************/
+
+/* EISA port numbers and PCI port numbers share the same interface. Some
+ * machines have both EISA and PCI adapters installed. Rather than turn
+ * pci_port into an array, we reserve bus 0 for EISA and call the EISA
+ * routines if the access is to a port on bus 0. We don't want to fix
+ * EISA and ISA drivers which assume port space is <= 0xffff.
+ */
+
+#ifdef CONFIG_EISA
+#define EISA_IN(size) if (EISA_bus && (b == 0)) return eisa_in##size(addr)
+#define EISA_OUT(size) if (EISA_bus && (b == 0)) return eisa_out##size(d, addr)
+#else
+#define EISA_IN(size)
+#define EISA_OUT(size)
+#endif
+
+#define PCI_PORT_IN(type, size) \
+u##size in##type (int addr) \
+{ \
+ int b = PCI_PORT_HBA(addr); \
+ EISA_IN(size); \
+ if (!parisc_pci_hba[b]) return (u##size) -1; \
+ return pci_port->in##type(parisc_pci_hba[b], PCI_PORT_ADDR(addr)); \
+} \
+EXPORT_SYMBOL(in##type);
+
+PCI_PORT_IN(b, 8)
+PCI_PORT_IN(w, 16)
+PCI_PORT_IN(l, 32)
+
+
+#define PCI_PORT_OUT(type, size) \
+void out##type (u##size d, int addr) \
+{ \
+ int b = PCI_PORT_HBA(addr); \
+ EISA_OUT(size); \
+ if (!parisc_pci_hba[b]) return; \
+ pci_port->out##type(parisc_pci_hba[b], PCI_PORT_ADDR(addr), d); \
+} \
+EXPORT_SYMBOL(out##type);
+
+PCI_PORT_OUT(b, 8)
+PCI_PORT_OUT(w, 16)
+PCI_PORT_OUT(l, 32)
+
+
+
+/*
+ * BIOS32 replacement.
+ */
+static int __init pcibios_init(void)
+{
+ if (!pci_bios)
+ return -1;
+
+ if (pci_bios->init) {
+ pci_bios->init();
+ } else {
+ printk(KERN_WARNING "pci_bios != NULL but init() is!\n");
+ }
+
+ /* Set the CLS for PCI as early as possible. */
+ pci_cache_line_size = pci_dfl_cache_line_size;
+
+ return 0;
+}
+
+
+/* Called from pci_do_scan_bus() *after* walking a bus but before walking PPBs. */
+void pcibios_fixup_bus(struct pci_bus *bus)
+{
+ if (pci_bios->fixup_bus) {
+ pci_bios->fixup_bus(bus);
+ } else {
+ printk(KERN_WARNING "pci_bios != NULL but fixup_bus() is!\n");
+ }
+}
+
+
+/*
+ * Called by pci_set_master() - a driver interface.
+ *
+ * Legacy PDC guarantees to set:
+ * Map Memory BAR's into PA IO space.
+ * Map Expansion ROM BAR into one common PA IO space per bus.
+ * Map IO BAR's into PCI IO space.
+ * Command (see below)
+ * Cache Line Size
+ * Latency Timer
+ * Interrupt Line
+ * PPB: secondary latency timer, io/mmio base/limit,
+ * bus numbers, bridge control
+ *
+ */
+void pcibios_set_master(struct pci_dev *dev)
+{
+ u8 lat;
+
+ /* If someone already mucked with this, don't touch it. */
+ pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
+ if (lat >= 16) return;
+
+ /*
+ ** HP generally has fewer devices on the bus than other architectures.
+ ** upper byte is PCI_LATENCY_TIMER.
+ */
+ pci_write_config_word(dev, PCI_CACHE_LINE_SIZE,
+ (0x80 << 8) | pci_cache_line_size);
+}
+
+/*
+ * pcibios_init_bridge() initializes cache line and default latency
+ * for pci controllers and pci-pci bridges
+ */
+void __ref pcibios_init_bridge(struct pci_dev *dev)
+{
+ unsigned short bridge_ctl, bridge_ctl_new;
+
+ /* We deal only with pci controllers and pci-pci bridges. */
+ if (!dev || (dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)
+ return;
+
+ /* PCI-PCI bridge - set the cache line and default latency
+ * (32) for primary and secondary buses.
+ */
+ pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 32);
+
+ pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &bridge_ctl);
+
+ bridge_ctl_new = bridge_ctl | PCI_BRIDGE_CTL_PARITY |
+ PCI_BRIDGE_CTL_SERR | PCI_BRIDGE_CTL_MASTER_ABORT;
+ dev_info(&dev->dev, "Changing bridge control from 0x%08x to 0x%08x\n",
+ bridge_ctl, bridge_ctl_new);
+
+ pci_write_config_word(dev, PCI_BRIDGE_CONTROL, bridge_ctl_new);
+}
+
+/*
+ * pcibios align resources() is called every time generic PCI code
+ * wants to generate a new address. The process of looking for
+ * an available address, each candidate is first "aligned" and
+ * then checked if the resource is available until a match is found.
+ *
+ * Since we are just checking candidates, don't use any fields other
+ * than res->start.
+ */
+resource_size_t pcibios_align_resource(void *data, const struct resource *res,
+ resource_size_t size, resource_size_t alignment)
+{
+ resource_size_t mask, align, start = res->start;
+
+ DBG_RES("pcibios_align_resource(%s, (%p) [%lx,%lx]/%x, 0x%lx, 0x%lx)\n",
+ pci_name(((struct pci_dev *) data)),
+ res->parent, res->start, res->end,
+ (int) res->flags, size, alignment);
+
+ /* If it's not IO, then it's gotta be MEM */
+ align = (res->flags & IORESOURCE_IO) ? PCIBIOS_MIN_IO : PCIBIOS_MIN_MEM;
+
+ /* Align to largest of MIN or input size */
+ mask = max(alignment, align) - 1;
+ start += mask;
+ start &= ~mask;
+
+ return start;
+}
+
+/*
+ * A driver is enabling the device. We make sure that all the appropriate
+ * bits are set to allow the device to operate as the driver is expecting.
+ * We enable the port IO and memory IO bits if the device has any BARs of
+ * that type, and we enable the PERR and SERR bits unconditionally.
+ * Drivers that do not need parity (eg graphics and possibly networking)
+ * can clear these bits if they want.
+ */
+int pcibios_enable_device(struct pci_dev *dev, int mask)
+{
+ int err;
+ u16 cmd, old_cmd;
+
+ err = pci_enable_resources(dev, mask);
+ if (err < 0)
+ return err;
+
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ old_cmd = cmd;
+
+ cmd |= (PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
+
+#if 0
+ /* If bridge/bus controller has FBB enabled, child must too. */
+ if (dev->bus->bridge_ctl & PCI_BRIDGE_CTL_FAST_BACK)
+ cmd |= PCI_COMMAND_FAST_BACK;
+#endif
+
+ if (cmd != old_cmd) {
+ dev_info(&dev->dev, "enabling SERR and PARITY (%04x -> %04x)\n",
+ old_cmd, cmd);
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+ }
+ return 0;
+}
+
+
+/* PA-RISC specific */
+void pcibios_register_hba(struct pci_hba_data *hba)
+{
+ if (pci_hba_count >= PCI_HBA_MAX) {
+ printk(KERN_ERR "PCI: Too many Host Bus Adapters\n");
+ return;
+ }
+
+ parisc_pci_hba[pci_hba_count] = hba;
+ hba->hba_num = pci_hba_count++;
+}
+
+subsys_initcall(pcibios_init);
diff --git a/arch/parisc/kernel/pdc_chassis.c b/arch/parisc/kernel/pdc_chassis.c
new file mode 100644
index 000000000..d477d0177
--- /dev/null
+++ b/arch/parisc/kernel/pdc_chassis.c
@@ -0,0 +1,290 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * interfaces to Chassis Codes via PDC (firmware)
+ *
+ * Copyright (C) 2002 Laurent Canet <canetl@esiee.fr>
+ * Copyright (C) 2002-2006 Thibaut VARENE <varenet@parisc-linux.org>
+ *
+ * TODO: poll chassis warns, trigger (configurable) machine shutdown when
+ * needed.
+ * Find out how to get Chassis warnings out of PAT boxes?
+ */
+
+#undef PDC_CHASSIS_DEBUG
+#ifdef PDC_CHASSIS_DEBUG
+#define DPRINTK(fmt, args...) printk(fmt, ## args)
+#else
+#define DPRINTK(fmt, args...)
+#endif
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/panic_notifier.h>
+#include <linux/reboot.h>
+#include <linux/notifier.h>
+#include <linux/cache.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
+#include <asm/pdc_chassis.h>
+#include <asm/processor.h>
+#include <asm/pdc.h>
+#include <asm/pdcpat.h>
+#include <asm/led.h>
+
+#define PDC_CHASSIS_VER "0.05"
+
+#ifdef CONFIG_PDC_CHASSIS
+static unsigned int pdc_chassis_enabled __read_mostly = 1;
+
+
+/**
+ * pdc_chassis_setup() - Enable/disable pdc_chassis code at boot time.
+ * @str: configuration param: 0 to disable chassis log
+ * @return 1
+ */
+
+static int __init pdc_chassis_setup(char *str)
+{
+ /*panic_timeout = simple_strtoul(str, NULL, 0);*/
+ get_option(&str, &pdc_chassis_enabled);
+ return 1;
+}
+__setup("pdcchassis=", pdc_chassis_setup);
+
+
+/**
+ * pdc_chassis_checkold() - Checks for old PDC_CHASSIS compatibility
+ *
+ * Currently, only E class and A180 are known to work with this.
+ * Inspired by Christoph Plattner
+ */
+#if 0
+static void __init pdc_chassis_checkold(void)
+{
+ switch(CPU_HVERSION) {
+ case 0x480: /* E25 */
+ case 0x481: /* E35 */
+ case 0x482: /* E45 */
+ case 0x483: /* E55 */
+ case 0x516: /* A180 */
+ break;
+
+ default:
+ break;
+ }
+ DPRINTK(KERN_DEBUG "%s: pdc_chassis_checkold(); pdc_chassis_old = %d\n", __FILE__, pdc_chassis_old);
+}
+#endif
+
+/**
+ * pdc_chassis_panic_event() - Called by the panic handler.
+ * @this: unused
+ * @event: unused
+ * @ptr: unused
+ *
+ * As soon as a panic occurs, we should inform the PDC.
+ */
+
+static int pdc_chassis_panic_event(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ pdc_chassis_send_status(PDC_CHASSIS_DIRECT_PANIC);
+ return NOTIFY_DONE;
+}
+
+
+static struct notifier_block pdc_chassis_panic_block = {
+ .notifier_call = pdc_chassis_panic_event,
+ .priority = INT_MAX,
+};
+
+
+/**
+ * pdc_chassis_reboot_event() - Called by the reboot handler.
+ * @this: unused
+ * @event: unused
+ * @ptr: unused
+ *
+ * As soon as a reboot occurs, we should inform the PDC.
+ */
+
+static int pdc_chassis_reboot_event(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ pdc_chassis_send_status(PDC_CHASSIS_DIRECT_SHUTDOWN);
+ return NOTIFY_DONE;
+}
+
+
+static struct notifier_block pdc_chassis_reboot_block = {
+ .notifier_call = pdc_chassis_reboot_event,
+ .priority = INT_MAX,
+};
+#endif /* CONFIG_PDC_CHASSIS */
+
+
+/**
+ * parisc_pdc_chassis_init() - Called at boot time.
+ */
+
+void __init parisc_pdc_chassis_init(void)
+{
+#ifdef CONFIG_PDC_CHASSIS
+ if (likely(pdc_chassis_enabled)) {
+ DPRINTK(KERN_DEBUG "%s: parisc_pdc_chassis_init()\n", __FILE__);
+
+ /* Let see if we have something to handle... */
+ printk(KERN_INFO "Enabling %s chassis codes support v%s\n",
+ is_pdc_pat() ? "PDC_PAT" : "regular",
+ PDC_CHASSIS_VER);
+
+ /* initialize panic notifier chain */
+ atomic_notifier_chain_register(&panic_notifier_list,
+ &pdc_chassis_panic_block);
+
+ /* initialize reboot notifier chain */
+ register_reboot_notifier(&pdc_chassis_reboot_block);
+ }
+#endif /* CONFIG_PDC_CHASSIS */
+}
+
+
+/**
+ * pdc_chassis_send_status() - Sends a predefined message to the chassis,
+ * and changes the front panel LEDs according to the new system state
+ * @message: Type of message, one of PDC_CHASSIS_DIRECT_* values.
+ *
+ * Only machines with 64 bits PDC PAT and those reported in
+ * pdc_chassis_checkold() are supported atm.
+ *
+ * returns 0 if no error, -1 if no supported PDC is present or invalid message,
+ * else returns the appropriate PDC error code.
+ *
+ * For a list of predefined messages, see asm-parisc/pdc_chassis.h
+ */
+
+int pdc_chassis_send_status(int message)
+{
+ /* Maybe we should do that in an other way ? */
+ int retval = 0;
+#ifdef CONFIG_PDC_CHASSIS
+ if (likely(pdc_chassis_enabled)) {
+
+ DPRINTK(KERN_DEBUG "%s: pdc_chassis_send_status(%d)\n", __FILE__, message);
+
+#ifdef CONFIG_64BIT
+ if (is_pdc_pat()) {
+ switch(message) {
+ case PDC_CHASSIS_DIRECT_BSTART:
+ retval = pdc_pat_chassis_send_log(PDC_CHASSIS_PMSG_BSTART, PDC_CHASSIS_LSTATE_RUN_NORMAL);
+ break;
+
+ case PDC_CHASSIS_DIRECT_BCOMPLETE:
+ retval = pdc_pat_chassis_send_log(PDC_CHASSIS_PMSG_BCOMPLETE, PDC_CHASSIS_LSTATE_RUN_NORMAL);
+ break;
+
+ case PDC_CHASSIS_DIRECT_SHUTDOWN:
+ retval = pdc_pat_chassis_send_log(PDC_CHASSIS_PMSG_SHUTDOWN, PDC_CHASSIS_LSTATE_NONOS);
+ break;
+
+ case PDC_CHASSIS_DIRECT_PANIC:
+ retval = pdc_pat_chassis_send_log(PDC_CHASSIS_PMSG_PANIC, PDC_CHASSIS_LSTATE_RUN_CRASHREC);
+ break;
+
+ case PDC_CHASSIS_DIRECT_LPMC:
+ retval = pdc_pat_chassis_send_log(PDC_CHASSIS_PMSG_LPMC, PDC_CHASSIS_LSTATE_RUN_SYSINT);
+ break;
+
+ case PDC_CHASSIS_DIRECT_HPMC:
+ retval = pdc_pat_chassis_send_log(PDC_CHASSIS_PMSG_HPMC, PDC_CHASSIS_LSTATE_RUN_NCRIT);
+ break;
+
+ default:
+ retval = -1;
+ }
+ } else retval = -1;
+#else
+ if (1) {
+ switch (message) {
+ case PDC_CHASSIS_DIRECT_BSTART:
+ retval = pdc_chassis_disp(PDC_CHASSIS_DISP_DATA(OSTAT_INIT));
+ break;
+
+ case PDC_CHASSIS_DIRECT_BCOMPLETE:
+ retval = pdc_chassis_disp(PDC_CHASSIS_DISP_DATA(OSTAT_RUN));
+ break;
+
+ case PDC_CHASSIS_DIRECT_SHUTDOWN:
+ retval = pdc_chassis_disp(PDC_CHASSIS_DISP_DATA(OSTAT_SHUT));
+ break;
+
+ case PDC_CHASSIS_DIRECT_HPMC:
+ case PDC_CHASSIS_DIRECT_PANIC:
+ retval = pdc_chassis_disp(PDC_CHASSIS_DISP_DATA(OSTAT_FLT));
+ break;
+
+ case PDC_CHASSIS_DIRECT_LPMC:
+ retval = pdc_chassis_disp(PDC_CHASSIS_DISP_DATA(OSTAT_WARN));
+ break;
+
+ default:
+ retval = -1;
+ }
+ } else retval = -1;
+#endif /* CONFIG_64BIT */
+ } /* if (pdc_chassis_enabled) */
+
+ /* if system has LCD display, update current string */
+ if (retval != -1 && IS_ENABLED(CONFIG_CHASSIS_LCD_LED))
+ lcd_print(NULL);
+
+#endif /* CONFIG_PDC_CHASSIS */
+ return retval;
+}
+
+#ifdef CONFIG_PDC_CHASSIS_WARN
+#ifdef CONFIG_PROC_FS
+static int pdc_chassis_warn_show(struct seq_file *m, void *v)
+{
+ unsigned long warn;
+ u32 warnreg;
+
+ if (pdc_chassis_warn(&warn) != PDC_OK)
+ return -EIO;
+
+ warnreg = (warn & 0xFFFFFFFF);
+
+ if ((warnreg >> 24) & 0xFF)
+ seq_printf(m, "Chassis component failure! (eg fan or PSU): 0x%.2x\n",
+ (warnreg >> 24) & 0xFF);
+
+ seq_printf(m, "Battery: %s\n", (warnreg & 0x04) ? "Low!" : "OK");
+ seq_printf(m, "Temp low: %s\n", (warnreg & 0x02) ? "Exceeded!" : "OK");
+ seq_printf(m, "Temp mid: %s\n", (warnreg & 0x01) ? "Exceeded!" : "OK");
+ return 0;
+}
+
+static int __init pdc_chassis_create_procfs(void)
+{
+ unsigned long test;
+ int ret;
+
+ ret = pdc_chassis_warn(&test);
+ if ((ret == PDC_BAD_PROC) || (ret == PDC_BAD_OPTION)) {
+ /* seems that some boxes (eg L1000) do not implement this */
+ printk(KERN_INFO "Chassis warnings not supported.\n");
+ return 0;
+ }
+
+ printk(KERN_INFO "Enabling PDC chassis warnings support v%s\n",
+ PDC_CHASSIS_VER);
+ proc_create_single("chassis", 0400, NULL, pdc_chassis_warn_show);
+ return 0;
+}
+
+__initcall(pdc_chassis_create_procfs);
+
+#endif /* CONFIG_PROC_FS */
+#endif /* CONFIG_PDC_CHASSIS_WARN */
diff --git a/arch/parisc/kernel/pdc_cons.c b/arch/parisc/kernel/pdc_cons.c
new file mode 100644
index 000000000..cf3bf8232
--- /dev/null
+++ b/arch/parisc/kernel/pdc_cons.c
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * PDC early console support - use PDC firmware to dump text via boot console
+ *
+ * Copyright (C) 2001-2022 Helge Deller <deller@gmx.de>
+ */
+
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/serial_core.h>
+#include <linux/kgdb.h>
+#include <asm/page.h> /* for PAGE0 */
+#include <asm/pdc.h> /* for iodc_call() proto and friends */
+
+static void pdc_console_write(struct console *co, const char *s, unsigned count)
+{
+ int i = 0;
+
+ do {
+ i += pdc_iodc_print(s + i, count - i);
+ } while (i < count);
+}
+
+#ifdef CONFIG_KGDB
+static int kgdb_pdc_read_char(void)
+{
+ int c = pdc_iodc_getc();
+
+ return (c <= 0) ? NO_POLL_CHAR : c;
+}
+
+static void kgdb_pdc_write_char(u8 chr)
+{
+ /* no need to print char as it's shown on standard console */
+ /* pdc_iodc_print(&chr, 1); */
+}
+
+static struct kgdb_io kgdb_pdc_io_ops = {
+ .name = "kgdb_pdc",
+ .read_char = kgdb_pdc_read_char,
+ .write_char = kgdb_pdc_write_char,
+};
+#endif
+
+static int __init pdc_earlycon_setup(struct earlycon_device *device,
+ const char *opt)
+{
+ struct console *earlycon_console;
+
+ /* If the console is duplex then copy the COUT parameters to CIN. */
+ if (PAGE0->mem_cons.cl_class == CL_DUPLEX)
+ memcpy(&PAGE0->mem_kbd, &PAGE0->mem_cons, sizeof(PAGE0->mem_cons));
+
+ earlycon_console = device->con;
+ earlycon_console->write = pdc_console_write;
+ device->port.iotype = UPIO_MEM32BE;
+
+#ifdef CONFIG_KGDB
+ kgdb_register_io_module(&kgdb_pdc_io_ops);
+#endif
+
+ return 0;
+}
+
+EARLYCON_DECLARE(pdc, pdc_earlycon_setup);
diff --git a/arch/parisc/kernel/pdt.c b/arch/parisc/kernel/pdt.c
new file mode 100644
index 000000000..0f9b3b591
--- /dev/null
+++ b/arch/parisc/kernel/pdt.c
@@ -0,0 +1,361 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Page Deallocation Table (PDT) support
+ *
+ * The Page Deallocation Table (PDT) is maintained by firmware and holds a
+ * list of memory addresses in which memory errors were detected.
+ * The list contains both single-bit (correctable) and double-bit
+ * (uncorrectable) errors.
+ *
+ * Copyright 2017 by Helge Deller <deller@gmx.de>
+ *
+ * possible future enhancements:
+ * - add userspace interface via procfs or sysfs to clear PDT
+ */
+
+#include <linux/memblock.h>
+#include <linux/seq_file.h>
+#include <linux/kthread.h>
+#include <linux/proc_fs.h>
+#include <linux/initrd.h>
+#include <linux/pgtable.h>
+#include <linux/mm.h>
+
+#include <asm/pdc.h>
+#include <asm/pdcpat.h>
+#include <asm/sections.h>
+#include <asm/pgtable.h>
+
+enum pdt_access_type {
+ PDT_NONE,
+ PDT_PDC,
+ PDT_PAT_NEW,
+ PDT_PAT_CELL
+};
+
+static enum pdt_access_type pdt_type;
+
+/* PDT poll interval: 1 minute if errors, 5 minutes if everything OK. */
+#define PDT_POLL_INTERVAL_DEFAULT (5*60*HZ)
+#define PDT_POLL_INTERVAL_SHORT (1*60*HZ)
+static unsigned long pdt_poll_interval = PDT_POLL_INTERVAL_DEFAULT;
+
+/* global PDT status information */
+static struct pdc_mem_retinfo pdt_status;
+
+#define MAX_PDT_TABLE_SIZE PAGE_SIZE
+#define MAX_PDT_ENTRIES (MAX_PDT_TABLE_SIZE / sizeof(unsigned long))
+static unsigned long pdt_entry[MAX_PDT_ENTRIES] __page_aligned_bss;
+
+/*
+ * Constants for the pdt_entry format:
+ * A pdt_entry holds the physical address in bits 0-57, bits 58-61 are
+ * reserved, bit 62 is the perm bit and bit 63 is the error_type bit.
+ * The perm bit indicates whether the error have been verified as a permanent
+ * error (value of 1) or has not been verified, and may be transient (value
+ * of 0). The error_type bit indicates whether the error is a single bit error
+ * (value of 1) or a multiple bit error.
+ * On non-PAT machines phys_addr is encoded in bits 0-59 and error_type in bit
+ * 63. Those machines don't provide the perm bit.
+ */
+
+#define PDT_ADDR_PHYS_MASK (pdt_type != PDT_PDC ? ~0x3f : ~0x0f)
+#define PDT_ADDR_PERM_ERR (pdt_type != PDT_PDC ? 2UL : 0UL)
+#define PDT_ADDR_SINGLE_ERR 1UL
+
+/* report PDT entries via /proc/meminfo */
+void arch_report_meminfo(struct seq_file *m)
+{
+ if (pdt_type == PDT_NONE)
+ return;
+
+ seq_printf(m, "PDT_max_entries: %7lu\n",
+ pdt_status.pdt_size);
+ seq_printf(m, "PDT_cur_entries: %7lu\n",
+ pdt_status.pdt_entries);
+}
+
+static int get_info_pat_new(void)
+{
+ struct pdc_pat_mem_retinfo pat_rinfo;
+ int ret;
+
+ /* newer PAT machines like C8000 report info for all cells */
+ if (is_pdc_pat())
+ ret = pdc_pat_mem_pdt_info(&pat_rinfo);
+ else
+ return PDC_BAD_PROC;
+
+ pdt_status.pdt_size = pat_rinfo.max_pdt_entries;
+ pdt_status.pdt_entries = pat_rinfo.current_pdt_entries;
+ pdt_status.pdt_status = 0;
+ pdt_status.first_dbe_loc = pat_rinfo.first_dbe_loc;
+ pdt_status.good_mem = pat_rinfo.good_mem;
+
+ return ret;
+}
+
+static int get_info_pat_cell(void)
+{
+ struct pdc_pat_mem_cell_pdt_retinfo cell_rinfo;
+ int ret;
+
+ /* older PAT machines like rp5470 report cell info only */
+ if (is_pdc_pat())
+ ret = pdc_pat_mem_pdt_cell_info(&cell_rinfo, parisc_cell_num);
+ else
+ return PDC_BAD_PROC;
+
+ pdt_status.pdt_size = cell_rinfo.max_pdt_entries;
+ pdt_status.pdt_entries = cell_rinfo.current_pdt_entries;
+ pdt_status.pdt_status = 0;
+ pdt_status.first_dbe_loc = cell_rinfo.first_dbe_loc;
+ pdt_status.good_mem = cell_rinfo.good_mem;
+
+ return ret;
+}
+
+static void report_mem_err(unsigned long pde)
+{
+ struct pdc_pat_mem_phys_mem_location loc;
+ unsigned long addr;
+ char dimm_txt[32];
+
+ addr = pde & PDT_ADDR_PHYS_MASK;
+
+ /* show DIMM slot description on PAT machines */
+ if (is_pdc_pat()) {
+ pdc_pat_mem_get_dimm_phys_location(&loc, addr);
+ sprintf(dimm_txt, "DIMM slot %02x, ", loc.dimm_slot);
+ } else
+ dimm_txt[0] = 0;
+
+ pr_warn("PDT: BAD MEMORY at 0x%08lx, %s%s%s-bit error.\n",
+ addr, dimm_txt,
+ pde & PDT_ADDR_PERM_ERR ? "permanent ":"",
+ pde & PDT_ADDR_SINGLE_ERR ? "single":"multi");
+}
+
+
+/*
+ * pdc_pdt_init()
+ *
+ * Initialize kernel PDT structures, read initial PDT table from firmware,
+ * report all current PDT entries and mark bad memory with memblock_reserve()
+ * to avoid that the kernel will use broken memory areas.
+ *
+ */
+void __init pdc_pdt_init(void)
+{
+ int ret, i;
+ unsigned long entries;
+ struct pdc_mem_read_pdt pdt_read_ret;
+
+ pdt_type = PDT_PAT_NEW;
+ ret = get_info_pat_new();
+
+ if (ret != PDC_OK) {
+ pdt_type = PDT_PAT_CELL;
+ ret = get_info_pat_cell();
+ }
+
+ if (ret != PDC_OK) {
+ pdt_type = PDT_PDC;
+ /* non-PAT machines provide the standard PDC call */
+ ret = pdc_mem_pdt_info(&pdt_status);
+ }
+
+ if (ret != PDC_OK) {
+ pdt_type = PDT_NONE;
+ pr_info("PDT: Firmware does not provide any page deallocation"
+ " information.\n");
+ return;
+ }
+
+ entries = pdt_status.pdt_entries;
+ if (WARN_ON(entries > MAX_PDT_ENTRIES))
+ entries = pdt_status.pdt_entries = MAX_PDT_ENTRIES;
+
+ pr_info("PDT: type %s, size %lu, entries %lu, status %lu, dbe_loc 0x%lx,"
+ " good_mem %lu MB\n",
+ pdt_type == PDT_PDC ? __stringify(PDT_PDC) :
+ pdt_type == PDT_PAT_CELL ? __stringify(PDT_PAT_CELL)
+ : __stringify(PDT_PAT_NEW),
+ pdt_status.pdt_size, pdt_status.pdt_entries,
+ pdt_status.pdt_status, pdt_status.first_dbe_loc,
+ pdt_status.good_mem / 1024 / 1024);
+
+ if (entries == 0) {
+ pr_info("PDT: Firmware reports all memory OK.\n");
+ return;
+ }
+
+ if (pdt_status.first_dbe_loc &&
+ pdt_status.first_dbe_loc <= __pa((unsigned long)&_end))
+ pr_crit("CRITICAL: Bad memory inside kernel image memory area!\n");
+
+ pr_warn("PDT: Firmware reports %lu entries of faulty memory:\n",
+ entries);
+
+ if (pdt_type == PDT_PDC)
+ ret = pdc_mem_pdt_read_entries(&pdt_read_ret, pdt_entry);
+ else {
+#ifdef CONFIG_64BIT
+ struct pdc_pat_mem_read_pd_retinfo pat_pret;
+
+ if (pdt_type == PDT_PAT_CELL)
+ ret = pdc_pat_mem_read_cell_pdt(&pat_pret, pdt_entry,
+ MAX_PDT_ENTRIES);
+ else
+ ret = pdc_pat_mem_read_pd_pdt(&pat_pret, pdt_entry,
+ MAX_PDT_TABLE_SIZE, 0);
+#else
+ ret = PDC_BAD_PROC;
+#endif
+ }
+
+ if (ret != PDC_OK) {
+ pdt_type = PDT_NONE;
+ pr_warn("PDT: Get PDT entries failed with %d\n", ret);
+ return;
+ }
+
+ for (i = 0; i < pdt_status.pdt_entries; i++) {
+ unsigned long addr;
+
+ report_mem_err(pdt_entry[i]);
+
+ addr = pdt_entry[i] & PDT_ADDR_PHYS_MASK;
+ if (IS_ENABLED(CONFIG_BLK_DEV_INITRD) &&
+ addr >= initrd_start && addr < initrd_end)
+ pr_crit("CRITICAL: initrd possibly broken "
+ "due to bad memory!\n");
+
+ /* mark memory page bad */
+ memblock_reserve(pdt_entry[i] & PAGE_MASK, PAGE_SIZE);
+ num_poisoned_pages_inc(addr >> PAGE_SHIFT);
+ }
+}
+
+
+/*
+ * This is the PDT kernel thread main loop.
+ */
+
+static int pdt_mainloop(void *unused)
+{
+ struct pdc_mem_read_pdt pdt_read_ret;
+ struct pdc_pat_mem_read_pd_retinfo pat_pret __maybe_unused;
+ unsigned long old_num_entries;
+ unsigned long *bad_mem_ptr;
+ int num, ret;
+
+ for (;;) {
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ old_num_entries = pdt_status.pdt_entries;
+
+ schedule_timeout(pdt_poll_interval);
+ if (kthread_should_stop())
+ break;
+
+ /* Do we have new PDT entries? */
+ switch (pdt_type) {
+ case PDT_PAT_NEW:
+ ret = get_info_pat_new();
+ break;
+ case PDT_PAT_CELL:
+ ret = get_info_pat_cell();
+ break;
+ default:
+ ret = pdc_mem_pdt_info(&pdt_status);
+ break;
+ }
+
+ if (ret != PDC_OK) {
+ pr_warn("PDT: unexpected failure %d\n", ret);
+ return -EINVAL;
+ }
+
+ /* if no new PDT entries, just wait again */
+ num = pdt_status.pdt_entries - old_num_entries;
+ if (num <= 0)
+ continue;
+
+ /* decrease poll interval in case we found memory errors */
+ if (pdt_status.pdt_entries &&
+ pdt_poll_interval == PDT_POLL_INTERVAL_DEFAULT)
+ pdt_poll_interval = PDT_POLL_INTERVAL_SHORT;
+
+ /* limit entries to get */
+ if (num > MAX_PDT_ENTRIES) {
+ num = MAX_PDT_ENTRIES;
+ pdt_status.pdt_entries = old_num_entries + num;
+ }
+
+ /* get new entries */
+ switch (pdt_type) {
+#ifdef CONFIG_64BIT
+ case PDT_PAT_CELL:
+ if (pdt_status.pdt_entries > MAX_PDT_ENTRIES) {
+ pr_crit("PDT: too many entries.\n");
+ return -ENOMEM;
+ }
+ ret = pdc_pat_mem_read_cell_pdt(&pat_pret, pdt_entry,
+ MAX_PDT_ENTRIES);
+ bad_mem_ptr = &pdt_entry[old_num_entries];
+ break;
+ case PDT_PAT_NEW:
+ ret = pdc_pat_mem_read_pd_pdt(&pat_pret,
+ pdt_entry,
+ num * sizeof(unsigned long),
+ old_num_entries * sizeof(unsigned long));
+ bad_mem_ptr = &pdt_entry[0];
+ break;
+#endif
+ default:
+ ret = pdc_mem_pdt_read_entries(&pdt_read_ret,
+ pdt_entry);
+ bad_mem_ptr = &pdt_entry[old_num_entries];
+ break;
+ }
+
+ /* report and mark memory broken */
+ while (num--) {
+ unsigned long pde = *bad_mem_ptr++;
+
+ report_mem_err(pde);
+
+#ifdef CONFIG_MEMORY_FAILURE
+ if ((pde & PDT_ADDR_PERM_ERR) ||
+ ((pde & PDT_ADDR_SINGLE_ERR) == 0))
+ memory_failure(pde >> PAGE_SHIFT, 0);
+ else
+ soft_offline_page(pde >> PAGE_SHIFT, 0);
+#else
+ pr_crit("PDT: memory error at 0x%lx ignored.\n"
+ "Rebuild kernel with CONFIG_MEMORY_FAILURE=y "
+ "for real handling.\n",
+ pde & PDT_ADDR_PHYS_MASK);
+#endif
+
+ }
+ }
+
+ return 0;
+}
+
+
+static int __init pdt_initcall(void)
+{
+ struct task_struct *kpdtd_task;
+
+ if (pdt_type == PDT_NONE)
+ return -ENODEV;
+
+ kpdtd_task = kthread_run(pdt_mainloop, NULL, "kpdtd");
+
+ return PTR_ERR_OR_ZERO(kpdtd_task);
+}
+
+late_initcall(pdt_initcall);
diff --git a/arch/parisc/kernel/perf.c b/arch/parisc/kernel/perf.c
new file mode 100644
index 000000000..b0f081687
--- /dev/null
+++ b/arch/parisc/kernel/perf.c
@@ -0,0 +1,838 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Parisc performance counters
+ * Copyright (C) 2001 Randolph Chung <tausq@debian.org>
+ *
+ * This code is derived, with permission, from HP/UX sources.
+ */
+
+/*
+ * Edited comment from original sources:
+ *
+ * This driver programs the PCX-U/PCX-W performance counters
+ * on the PA-RISC 2.0 chips. The driver keeps all images now
+ * internally to the kernel to hopefully eliminate the possibility
+ * of a bad image halting the CPU. Also, there are different
+ * images for the PCX-W and later chips vs the PCX-U chips.
+ *
+ * Only 1 process is allowed to access the driver at any time,
+ * so the only protection that is needed is at open and close.
+ * A variable "perf_enabled" is used to hold the state of the
+ * driver. The spinlock "perf_lock" is used to protect the
+ * modification of the state during open/close operations so
+ * multiple processes don't get into the driver simultaneously.
+ *
+ * This driver accesses the processor directly vs going through
+ * the PDC INTRIGUE calls. This is done to eliminate bugs introduced
+ * in various PDC revisions. The code is much more maintainable
+ * and reliable this way vs having to debug on every version of PDC
+ * on every box.
+ */
+
+#include <linux/capability.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/miscdevice.h>
+#include <linux/spinlock.h>
+
+#include <linux/uaccess.h>
+#include <asm/perf.h>
+#include <asm/parisc-device.h>
+#include <asm/processor.h>
+#include <asm/runway.h>
+#include <asm/io.h> /* for __raw_read() */
+
+#include "perf_images.h"
+
+#define MAX_RDR_WORDS 24
+#define PERF_VERSION 2 /* derived from hpux's PI v2 interface */
+
+/* definition of RDR regs */
+struct rdr_tbl_ent {
+ uint16_t width;
+ uint8_t num_words;
+ uint8_t write_control;
+};
+
+static int perf_processor_interface __read_mostly = UNKNOWN_INTF;
+static int perf_enabled __read_mostly;
+static DEFINE_SPINLOCK(perf_lock);
+static struct parisc_device *cpu_device __read_mostly;
+
+/* RDRs to write for PCX-W */
+static const int perf_rdrs_W[] =
+ { 0, 1, 4, 5, 6, 15, 16, 17, 18, 20, 21, 22, 23, 24, 25, -1 };
+
+/* RDRs to write for PCX-U */
+static const int perf_rdrs_U[] =
+ { 0, 1, 4, 5, 6, 7, 16, 17, 18, 20, 21, 22, 23, 24, 25, -1 };
+
+/* RDR register descriptions for PCX-W */
+static const struct rdr_tbl_ent perf_rdr_tbl_W[] = {
+ { 19, 1, 8 }, /* RDR 0 */
+ { 16, 1, 16 }, /* RDR 1 */
+ { 72, 2, 0 }, /* RDR 2 */
+ { 81, 2, 0 }, /* RDR 3 */
+ { 328, 6, 0 }, /* RDR 4 */
+ { 160, 3, 0 }, /* RDR 5 */
+ { 336, 6, 0 }, /* RDR 6 */
+ { 164, 3, 0 }, /* RDR 7 */
+ { 0, 0, 0 }, /* RDR 8 */
+ { 35, 1, 0 }, /* RDR 9 */
+ { 6, 1, 0 }, /* RDR 10 */
+ { 18, 1, 0 }, /* RDR 11 */
+ { 13, 1, 0 }, /* RDR 12 */
+ { 8, 1, 0 }, /* RDR 13 */
+ { 8, 1, 0 }, /* RDR 14 */
+ { 8, 1, 0 }, /* RDR 15 */
+ { 1530, 24, 0 }, /* RDR 16 */
+ { 16, 1, 0 }, /* RDR 17 */
+ { 4, 1, 0 }, /* RDR 18 */
+ { 0, 0, 0 }, /* RDR 19 */
+ { 152, 3, 24 }, /* RDR 20 */
+ { 152, 3, 24 }, /* RDR 21 */
+ { 233, 4, 48 }, /* RDR 22 */
+ { 233, 4, 48 }, /* RDR 23 */
+ { 71, 2, 0 }, /* RDR 24 */
+ { 71, 2, 0 }, /* RDR 25 */
+ { 11, 1, 0 }, /* RDR 26 */
+ { 18, 1, 0 }, /* RDR 27 */
+ { 128, 2, 0 }, /* RDR 28 */
+ { 0, 0, 0 }, /* RDR 29 */
+ { 16, 1, 0 }, /* RDR 30 */
+ { 16, 1, 0 }, /* RDR 31 */
+};
+
+/* RDR register descriptions for PCX-U */
+static const struct rdr_tbl_ent perf_rdr_tbl_U[] = {
+ { 19, 1, 8 }, /* RDR 0 */
+ { 32, 1, 16 }, /* RDR 1 */
+ { 20, 1, 0 }, /* RDR 2 */
+ { 0, 0, 0 }, /* RDR 3 */
+ { 344, 6, 0 }, /* RDR 4 */
+ { 176, 3, 0 }, /* RDR 5 */
+ { 336, 6, 0 }, /* RDR 6 */
+ { 0, 0, 0 }, /* RDR 7 */
+ { 0, 0, 0 }, /* RDR 8 */
+ { 0, 0, 0 }, /* RDR 9 */
+ { 28, 1, 0 }, /* RDR 10 */
+ { 33, 1, 0 }, /* RDR 11 */
+ { 0, 0, 0 }, /* RDR 12 */
+ { 230, 4, 0 }, /* RDR 13 */
+ { 32, 1, 0 }, /* RDR 14 */
+ { 128, 2, 0 }, /* RDR 15 */
+ { 1494, 24, 0 }, /* RDR 16 */
+ { 18, 1, 0 }, /* RDR 17 */
+ { 4, 1, 0 }, /* RDR 18 */
+ { 0, 0, 0 }, /* RDR 19 */
+ { 158, 3, 24 }, /* RDR 20 */
+ { 158, 3, 24 }, /* RDR 21 */
+ { 194, 4, 48 }, /* RDR 22 */
+ { 194, 4, 48 }, /* RDR 23 */
+ { 71, 2, 0 }, /* RDR 24 */
+ { 71, 2, 0 }, /* RDR 25 */
+ { 28, 1, 0 }, /* RDR 26 */
+ { 33, 1, 0 }, /* RDR 27 */
+ { 88, 2, 0 }, /* RDR 28 */
+ { 32, 1, 0 }, /* RDR 29 */
+ { 24, 1, 0 }, /* RDR 30 */
+ { 16, 1, 0 }, /* RDR 31 */
+};
+
+/*
+ * A non-zero write_control in the above tables is a byte offset into
+ * this array.
+ */
+static const uint64_t perf_bitmasks[] = {
+ 0x0000000000000000ul, /* first dbl word must be zero */
+ 0xfdffe00000000000ul, /* RDR0 bitmask */
+ 0x003f000000000000ul, /* RDR1 bitmask */
+ 0x00fffffffffffffful, /* RDR20-RDR21 bitmask (152 bits) */
+ 0xfffffffffffffffful,
+ 0xfffffffc00000000ul,
+ 0xfffffffffffffffful, /* RDR22-RDR23 bitmask (233 bits) */
+ 0xfffffffffffffffful,
+ 0xfffffffffffffffcul,
+ 0xff00000000000000ul
+};
+
+/*
+ * Write control bitmasks for Pa-8700 processor given
+ * some things have changed slightly.
+ */
+static const uint64_t perf_bitmasks_piranha[] = {
+ 0x0000000000000000ul, /* first dbl word must be zero */
+ 0xfdffe00000000000ul, /* RDR0 bitmask */
+ 0x003f000000000000ul, /* RDR1 bitmask */
+ 0x00fffffffffffffful, /* RDR20-RDR21 bitmask (158 bits) */
+ 0xfffffffffffffffful,
+ 0xfffffffc00000000ul,
+ 0xfffffffffffffffful, /* RDR22-RDR23 bitmask (210 bits) */
+ 0xfffffffffffffffful,
+ 0xfffffffffffffffful,
+ 0xfffc000000000000ul
+};
+
+static const uint64_t *bitmask_array; /* array of bitmasks to use */
+
+/******************************************************************************
+ * Function Prototypes
+ *****************************************************************************/
+static int perf_config(uint32_t *image_ptr);
+static int perf_release(struct inode *inode, struct file *file);
+static int perf_open(struct inode *inode, struct file *file);
+static ssize_t perf_read(struct file *file, char __user *buf, size_t cnt, loff_t *ppos);
+static ssize_t perf_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos);
+static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+static void perf_start_counters(void);
+static int perf_stop_counters(uint32_t *raddr);
+static const struct rdr_tbl_ent * perf_rdr_get_entry(uint32_t rdr_num);
+static int perf_rdr_read_ubuf(uint32_t rdr_num, uint64_t *buffer);
+static int perf_rdr_clear(uint32_t rdr_num);
+static int perf_write_image(uint64_t *memaddr);
+static void perf_rdr_write(uint32_t rdr_num, uint64_t *buffer);
+
+/* External Assembly Routines */
+extern uint64_t perf_rdr_shift_in_W (uint32_t rdr_num, uint16_t width);
+extern uint64_t perf_rdr_shift_in_U (uint32_t rdr_num, uint16_t width);
+extern void perf_rdr_shift_out_W (uint32_t rdr_num, uint64_t buffer);
+extern void perf_rdr_shift_out_U (uint32_t rdr_num, uint64_t buffer);
+extern void perf_intrigue_enable_perf_counters (void);
+extern void perf_intrigue_disable_perf_counters (void);
+
+/******************************************************************************
+ * Function Definitions
+ *****************************************************************************/
+
+
+/*
+ * configure:
+ *
+ * Configure the cpu with a given data image. First turn off the counters,
+ * then download the image, then turn the counters back on.
+ */
+static int perf_config(uint32_t *image_ptr)
+{
+ long error;
+ uint32_t raddr[4];
+
+ /* Stop the counters*/
+ error = perf_stop_counters(raddr);
+ if (error != 0) {
+ printk("perf_config: perf_stop_counters = %ld\n", error);
+ return -EINVAL;
+ }
+
+printk("Preparing to write image\n");
+ /* Write the image to the chip */
+ error = perf_write_image((uint64_t *)image_ptr);
+ if (error != 0) {
+ printk("perf_config: DOWNLOAD = %ld\n", error);
+ return -EINVAL;
+ }
+
+printk("Preparing to start counters\n");
+
+ /* Start the counters */
+ perf_start_counters();
+
+ return sizeof(uint32_t);
+}
+
+/*
+ * Open the device and initialize all of its memory. The device is only
+ * opened once, but can be "queried" by multiple processes that know its
+ * file descriptor.
+ */
+static int perf_open(struct inode *inode, struct file *file)
+{
+ spin_lock(&perf_lock);
+ if (perf_enabled) {
+ spin_unlock(&perf_lock);
+ return -EBUSY;
+ }
+ perf_enabled = 1;
+ spin_unlock(&perf_lock);
+
+ return 0;
+}
+
+/*
+ * Close the device.
+ */
+static int perf_release(struct inode *inode, struct file *file)
+{
+ spin_lock(&perf_lock);
+ perf_enabled = 0;
+ spin_unlock(&perf_lock);
+
+ return 0;
+}
+
+/*
+ * Read does nothing for this driver
+ */
+static ssize_t perf_read(struct file *file, char __user *buf, size_t cnt, loff_t *ppos)
+{
+ return 0;
+}
+
+/*
+ * write:
+ *
+ * This routine downloads the image to the chip. It must be
+ * called on the processor that the download should happen
+ * on.
+ */
+static ssize_t perf_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ size_t image_size __maybe_unused;
+ uint32_t image_type;
+ uint32_t interface_type;
+ uint32_t test;
+
+ if (perf_processor_interface == ONYX_INTF)
+ image_size = PCXU_IMAGE_SIZE;
+ else if (perf_processor_interface == CUDA_INTF)
+ image_size = PCXW_IMAGE_SIZE;
+ else
+ return -EFAULT;
+
+ if (!perfmon_capable())
+ return -EACCES;
+
+ if (count != sizeof(uint32_t))
+ return -EIO;
+
+ if (copy_from_user(&image_type, buf, sizeof(uint32_t)))
+ return -EFAULT;
+
+ /* Get the interface type and test type */
+ interface_type = (image_type >> 16) & 0xffff;
+ test = (image_type & 0xffff);
+
+ /* Make sure everything makes sense */
+
+ /* First check the machine type is correct for
+ the requested image */
+ if (((perf_processor_interface == CUDA_INTF) &&
+ (interface_type != CUDA_INTF)) ||
+ ((perf_processor_interface == ONYX_INTF) &&
+ (interface_type != ONYX_INTF)))
+ return -EINVAL;
+
+ /* Next check to make sure the requested image
+ is valid */
+ if (((interface_type == CUDA_INTF) &&
+ (test >= MAX_CUDA_IMAGES)) ||
+ ((interface_type == ONYX_INTF) &&
+ (test >= MAX_ONYX_IMAGES)))
+ return -EINVAL;
+
+ /* Copy the image into the processor */
+ if (interface_type == CUDA_INTF)
+ return perf_config(cuda_images[test]);
+ else
+ return perf_config(onyx_images[test]);
+
+ return count;
+}
+
+/*
+ * Patch the images that need to know the IVA addresses.
+ */
+static void perf_patch_images(void)
+{
+#if 0 /* FIXME!! */
+/*
+ * NOTE: this routine is VERY specific to the current TLB image.
+ * If the image is changed, this routine might also need to be changed.
+ */
+ extern void $i_itlb_miss_2_0();
+ extern void $i_dtlb_miss_2_0();
+ extern void PA2_0_iva();
+
+ /*
+ * We can only use the lower 32-bits, the upper 32-bits should be 0
+ * anyway given this is in the kernel
+ */
+ uint32_t itlb_addr = (uint32_t)&($i_itlb_miss_2_0);
+ uint32_t dtlb_addr = (uint32_t)&($i_dtlb_miss_2_0);
+ uint32_t IVAaddress = (uint32_t)&PA2_0_iva;
+
+ if (perf_processor_interface == ONYX_INTF) {
+ /* clear last 2 bytes */
+ onyx_images[TLBMISS][15] &= 0xffffff00;
+ /* set 2 bytes */
+ onyx_images[TLBMISS][15] |= (0x000000ff&((dtlb_addr) >> 24));
+ onyx_images[TLBMISS][16] = (dtlb_addr << 8)&0xffffff00;
+ onyx_images[TLBMISS][17] = itlb_addr;
+
+ /* clear last 2 bytes */
+ onyx_images[TLBHANDMISS][15] &= 0xffffff00;
+ /* set 2 bytes */
+ onyx_images[TLBHANDMISS][15] |= (0x000000ff&((dtlb_addr) >> 24));
+ onyx_images[TLBHANDMISS][16] = (dtlb_addr << 8)&0xffffff00;
+ onyx_images[TLBHANDMISS][17] = itlb_addr;
+
+ /* clear last 2 bytes */
+ onyx_images[BIG_CPI][15] &= 0xffffff00;
+ /* set 2 bytes */
+ onyx_images[BIG_CPI][15] |= (0x000000ff&((dtlb_addr) >> 24));
+ onyx_images[BIG_CPI][16] = (dtlb_addr << 8)&0xffffff00;
+ onyx_images[BIG_CPI][17] = itlb_addr;
+
+ onyx_images[PANIC][15] &= 0xffffff00; /* clear last 2 bytes */
+ onyx_images[PANIC][15] |= (0x000000ff&((IVAaddress) >> 24)); /* set 2 bytes */
+ onyx_images[PANIC][16] = (IVAaddress << 8)&0xffffff00;
+
+
+ } else if (perf_processor_interface == CUDA_INTF) {
+ /* Cuda interface */
+ cuda_images[TLBMISS][16] =
+ (cuda_images[TLBMISS][16]&0xffff0000) |
+ ((dtlb_addr >> 8)&0x0000ffff);
+ cuda_images[TLBMISS][17] =
+ ((dtlb_addr << 24)&0xff000000) | ((itlb_addr >> 16)&0x000000ff);
+ cuda_images[TLBMISS][18] = (itlb_addr << 16)&0xffff0000;
+
+ cuda_images[TLBHANDMISS][16] =
+ (cuda_images[TLBHANDMISS][16]&0xffff0000) |
+ ((dtlb_addr >> 8)&0x0000ffff);
+ cuda_images[TLBHANDMISS][17] =
+ ((dtlb_addr << 24)&0xff000000) | ((itlb_addr >> 16)&0x000000ff);
+ cuda_images[TLBHANDMISS][18] = (itlb_addr << 16)&0xffff0000;
+
+ cuda_images[BIG_CPI][16] =
+ (cuda_images[BIG_CPI][16]&0xffff0000) |
+ ((dtlb_addr >> 8)&0x0000ffff);
+ cuda_images[BIG_CPI][17] =
+ ((dtlb_addr << 24)&0xff000000) | ((itlb_addr >> 16)&0x000000ff);
+ cuda_images[BIG_CPI][18] = (itlb_addr << 16)&0xffff0000;
+ } else {
+ /* Unknown type */
+ }
+#endif
+}
+
+
+/*
+ * ioctl routine
+ * All routines effect the processor that they are executed on. Thus you
+ * must be running on the processor that you wish to change.
+ */
+
+static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ long error_start;
+ uint32_t raddr[4];
+ int error = 0;
+
+ switch (cmd) {
+
+ case PA_PERF_ON:
+ /* Start the counters */
+ perf_start_counters();
+ break;
+
+ case PA_PERF_OFF:
+ error_start = perf_stop_counters(raddr);
+ if (error_start != 0) {
+ printk(KERN_ERR "perf_off: perf_stop_counters = %ld\n", error_start);
+ error = -EFAULT;
+ break;
+ }
+
+ /* copy out the Counters */
+ if (copy_to_user((void __user *)arg, raddr,
+ sizeof (raddr)) != 0) {
+ error = -EFAULT;
+ break;
+ }
+ break;
+
+ case PA_PERF_VERSION:
+ /* Return the version # */
+ error = put_user(PERF_VERSION, (int *)arg);
+ break;
+
+ default:
+ error = -ENOTTY;
+ }
+
+ return error;
+}
+
+static const struct file_operations perf_fops = {
+ .llseek = no_llseek,
+ .read = perf_read,
+ .write = perf_write,
+ .unlocked_ioctl = perf_ioctl,
+ .compat_ioctl = perf_ioctl,
+ .open = perf_open,
+ .release = perf_release
+};
+
+static struct miscdevice perf_dev = {
+ MISC_DYNAMIC_MINOR,
+ PA_PERF_DEV,
+ &perf_fops
+};
+
+/*
+ * Initialize the module
+ */
+static int __init perf_init(void)
+{
+ int ret;
+
+ /* Determine correct processor interface to use */
+ bitmask_array = perf_bitmasks;
+
+ if (boot_cpu_data.cpu_type == pcxu ||
+ boot_cpu_data.cpu_type == pcxu_) {
+ perf_processor_interface = ONYX_INTF;
+ } else if (boot_cpu_data.cpu_type == pcxw ||
+ boot_cpu_data.cpu_type == pcxw_ ||
+ boot_cpu_data.cpu_type == pcxw2 ||
+ boot_cpu_data.cpu_type == mako ||
+ boot_cpu_data.cpu_type == mako2) {
+ perf_processor_interface = CUDA_INTF;
+ if (boot_cpu_data.cpu_type == pcxw2 ||
+ boot_cpu_data.cpu_type == mako ||
+ boot_cpu_data.cpu_type == mako2)
+ bitmask_array = perf_bitmasks_piranha;
+ } else {
+ perf_processor_interface = UNKNOWN_INTF;
+ printk("Performance monitoring counters not supported on this processor\n");
+ return -ENODEV;
+ }
+
+ ret = misc_register(&perf_dev);
+ if (ret) {
+ printk(KERN_ERR "Performance monitoring counters: "
+ "cannot register misc device.\n");
+ return ret;
+ }
+
+ /* Patch the images to match the system */
+ perf_patch_images();
+
+ /* TODO: this only lets us access the first cpu.. what to do for SMP? */
+ cpu_device = per_cpu(cpu_data, 0).dev;
+ printk("Performance monitoring counters enabled for %s\n",
+ per_cpu(cpu_data, 0).dev->name);
+
+ return 0;
+}
+device_initcall(perf_init);
+
+/*
+ * perf_start_counters(void)
+ *
+ * Start the counters.
+ */
+static void perf_start_counters(void)
+{
+ /* Enable performance monitor counters */
+ perf_intrigue_enable_perf_counters();
+}
+
+/*
+ * perf_stop_counters
+ *
+ * Stop the performance counters and save counts
+ * in a per_processor array.
+ */
+static int perf_stop_counters(uint32_t *raddr)
+{
+ uint64_t userbuf[MAX_RDR_WORDS];
+
+ /* Disable performance counters */
+ perf_intrigue_disable_perf_counters();
+
+ if (perf_processor_interface == ONYX_INTF) {
+ uint64_t tmp64;
+ /*
+ * Read the counters
+ */
+ if (!perf_rdr_read_ubuf(16, userbuf))
+ return -13;
+
+ /* Counter0 is bits 1398 to 1429 */
+ tmp64 = (userbuf[21] << 22) & 0x00000000ffc00000;
+ tmp64 |= (userbuf[22] >> 42) & 0x00000000003fffff;
+ /* OR sticky0 (bit 1430) to counter0 bit 32 */
+ tmp64 |= (userbuf[22] >> 10) & 0x0000000080000000;
+ raddr[0] = (uint32_t)tmp64;
+
+ /* Counter1 is bits 1431 to 1462 */
+ tmp64 = (userbuf[22] >> 9) & 0x00000000ffffffff;
+ /* OR sticky1 (bit 1463) to counter1 bit 32 */
+ tmp64 |= (userbuf[22] << 23) & 0x0000000080000000;
+ raddr[1] = (uint32_t)tmp64;
+
+ /* Counter2 is bits 1464 to 1495 */
+ tmp64 = (userbuf[22] << 24) & 0x00000000ff000000;
+ tmp64 |= (userbuf[23] >> 40) & 0x0000000000ffffff;
+ /* OR sticky2 (bit 1496) to counter2 bit 32 */
+ tmp64 |= (userbuf[23] >> 8) & 0x0000000080000000;
+ raddr[2] = (uint32_t)tmp64;
+
+ /* Counter3 is bits 1497 to 1528 */
+ tmp64 = (userbuf[23] >> 7) & 0x00000000ffffffff;
+ /* OR sticky3 (bit 1529) to counter3 bit 32 */
+ tmp64 |= (userbuf[23] << 25) & 0x0000000080000000;
+ raddr[3] = (uint32_t)tmp64;
+
+ /*
+ * Zero out the counters
+ */
+
+ /*
+ * The counters and sticky-bits comprise the last 132 bits
+ * (1398 - 1529) of RDR16 on a U chip. We'll zero these
+ * out the easy way: zero out last 10 bits of dword 21,
+ * all of dword 22 and 58 bits (plus 6 don't care bits) of
+ * dword 23.
+ */
+ userbuf[21] &= 0xfffffffffffffc00ul; /* 0 to last 10 bits */
+ userbuf[22] = 0;
+ userbuf[23] = 0;
+
+ /*
+ * Write back the zeroed bytes + the image given
+ * the read was destructive.
+ */
+ perf_rdr_write(16, userbuf);
+ } else {
+
+ /*
+ * Read RDR-15 which contains the counters and sticky bits
+ */
+ if (!perf_rdr_read_ubuf(15, userbuf)) {
+ return -13;
+ }
+
+ /*
+ * Clear out the counters
+ */
+ perf_rdr_clear(15);
+
+ /*
+ * Copy the counters
+ */
+ raddr[0] = (uint32_t)((userbuf[0] >> 32) & 0x00000000ffffffffUL);
+ raddr[1] = (uint32_t)(userbuf[0] & 0x00000000ffffffffUL);
+ raddr[2] = (uint32_t)((userbuf[1] >> 32) & 0x00000000ffffffffUL);
+ raddr[3] = (uint32_t)(userbuf[1] & 0x00000000ffffffffUL);
+ }
+
+ return 0;
+}
+
+/*
+ * perf_rdr_get_entry
+ *
+ * Retrieve a pointer to the description of what this
+ * RDR contains.
+ */
+static const struct rdr_tbl_ent * perf_rdr_get_entry(uint32_t rdr_num)
+{
+ if (perf_processor_interface == ONYX_INTF) {
+ return &perf_rdr_tbl_U[rdr_num];
+ } else {
+ return &perf_rdr_tbl_W[rdr_num];
+ }
+}
+
+/*
+ * perf_rdr_read_ubuf
+ *
+ * Read the RDR value into the buffer specified.
+ */
+static int perf_rdr_read_ubuf(uint32_t rdr_num, uint64_t *buffer)
+{
+ uint64_t data, data_mask = 0;
+ uint32_t width, xbits, i;
+ const struct rdr_tbl_ent *tentry;
+
+ tentry = perf_rdr_get_entry(rdr_num);
+ if ((width = tentry->width) == 0)
+ return 0;
+
+ /* Clear out buffer */
+ i = tentry->num_words;
+ while (i--) {
+ buffer[i] = 0;
+ }
+
+ /* Check for bits an even number of 64 */
+ if ((xbits = width & 0x03f) != 0) {
+ data_mask = 1;
+ data_mask <<= (64 - xbits);
+ data_mask--;
+ }
+
+ /* Grab all of the data */
+ i = tentry->num_words;
+ while (i--) {
+
+ if (perf_processor_interface == ONYX_INTF) {
+ data = perf_rdr_shift_in_U(rdr_num, width);
+ } else {
+ data = perf_rdr_shift_in_W(rdr_num, width);
+ }
+ if (xbits) {
+ buffer[i] |= (data << (64 - xbits));
+ if (i) {
+ buffer[i-1] |= ((data >> xbits) & data_mask);
+ }
+ } else {
+ buffer[i] = data;
+ }
+ }
+
+ return 1;
+}
+
+/*
+ * perf_rdr_clear
+ *
+ * Zero out the given RDR register
+ */
+static int perf_rdr_clear(uint32_t rdr_num)
+{
+ const struct rdr_tbl_ent *tentry;
+ int32_t i;
+
+ tentry = perf_rdr_get_entry(rdr_num);
+
+ if (tentry->width == 0) {
+ return -1;
+ }
+
+ i = tentry->num_words;
+ while (i--) {
+ if (perf_processor_interface == ONYX_INTF) {
+ perf_rdr_shift_out_U(rdr_num, 0UL);
+ } else {
+ perf_rdr_shift_out_W(rdr_num, 0UL);
+ }
+ }
+
+ return 0;
+}
+
+
+/*
+ * perf_write_image
+ *
+ * Write the given image out to the processor
+ */
+static int perf_write_image(uint64_t *memaddr)
+{
+ uint64_t buffer[MAX_RDR_WORDS];
+ uint64_t *bptr;
+ uint32_t dwords;
+ const uint32_t *intrigue_rdr;
+ const uint64_t *intrigue_bitmask;
+ uint64_t tmp64;
+ void __iomem *runway;
+ const struct rdr_tbl_ent *tentry;
+ int i;
+
+ /* Clear out counters */
+ if (perf_processor_interface == ONYX_INTF) {
+
+ perf_rdr_clear(16);
+
+ /* Toggle performance monitor */
+ perf_intrigue_enable_perf_counters();
+ perf_intrigue_disable_perf_counters();
+
+ intrigue_rdr = perf_rdrs_U;
+ } else {
+ perf_rdr_clear(15);
+ intrigue_rdr = perf_rdrs_W;
+ }
+
+ /* Write all RDRs */
+ while (*intrigue_rdr != -1) {
+ tentry = perf_rdr_get_entry(*intrigue_rdr);
+ perf_rdr_read_ubuf(*intrigue_rdr, buffer);
+ bptr = &buffer[0];
+ dwords = tentry->num_words;
+ if (tentry->write_control) {
+ intrigue_bitmask = &bitmask_array[tentry->write_control >> 3];
+ while (dwords--) {
+ tmp64 = *intrigue_bitmask & *memaddr++;
+ tmp64 |= (~(*intrigue_bitmask++)) & *bptr;
+ *bptr++ = tmp64;
+ }
+ } else {
+ while (dwords--) {
+ *bptr++ = *memaddr++;
+ }
+ }
+
+ perf_rdr_write(*intrigue_rdr, buffer);
+ intrigue_rdr++;
+ }
+
+ /*
+ * Now copy out the Runway stuff which is not in RDRs
+ */
+
+ if (cpu_device == NULL)
+ {
+ printk(KERN_ERR "write_image: cpu_device not yet initialized!\n");
+ return -1;
+ }
+
+ runway = ioremap(cpu_device->hpa.start, 4096);
+ if (!runway) {
+ pr_err("perf_write_image: ioremap failed!\n");
+ return -ENOMEM;
+ }
+
+ /* Merge intrigue bits into Runway STATUS 0 */
+ tmp64 = __raw_readq(runway + RUNWAY_STATUS) & 0xffecfffffffffffful;
+ __raw_writeq(tmp64 | (*memaddr++ & 0x0013000000000000ul),
+ runway + RUNWAY_STATUS);
+
+ /* Write RUNWAY DEBUG registers */
+ for (i = 0; i < 8; i++) {
+ __raw_writeq(*memaddr++, runway + RUNWAY_DEBUG);
+ }
+
+ return 0;
+}
+
+/*
+ * perf_rdr_write
+ *
+ * Write the given RDR register with the contents
+ * of the given buffer.
+ */
+static void perf_rdr_write(uint32_t rdr_num, uint64_t *buffer)
+{
+ const struct rdr_tbl_ent *tentry;
+ int32_t i;
+
+printk("perf_rdr_write\n");
+ tentry = perf_rdr_get_entry(rdr_num);
+ if (tentry->width == 0) { return; }
+
+ i = tentry->num_words;
+ while (i--) {
+ if (perf_processor_interface == ONYX_INTF) {
+ perf_rdr_shift_out_U(rdr_num, buffer[i]);
+ } else {
+ perf_rdr_shift_out_W(rdr_num, buffer[i]);
+ }
+ }
+printk("perf_rdr_write done\n");
+}
diff --git a/arch/parisc/kernel/perf_asm.S b/arch/parisc/kernel/perf_asm.S
new file mode 100644
index 000000000..8fceabb1a
--- /dev/null
+++ b/arch/parisc/kernel/perf_asm.S
@@ -0,0 +1,1679 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/* low-level asm for "intrigue" (PA8500-8700 CPU perf counters)
+ *
+ * Copyright (C) 2001 Randolph Chung <tausq at parisc-linux.org>
+ * Copyright (C) 2001 Hewlett-Packard (Grant Grundler)
+ */
+
+#include <asm/assembly.h>
+
+#include <linux/init.h>
+#include <linux/linkage.h>
+
+#ifdef CONFIG_64BIT
+ .level 2.0w
+#endif /* CONFIG_64BIT */
+
+#define MTDIAG_1(gr) .word 0x14201840 + gr*0x10000
+#define MTDIAG_2(gr) .word 0x14401840 + gr*0x10000
+#define MFDIAG_1(gr) .word 0x142008A0 + gr
+#define MFDIAG_2(gr) .word 0x144008A0 + gr
+#define STDIAG(dr) .word 0x14000AA0 + dr*0x200000
+#define SFDIAG(dr) .word 0x14000BA0 + dr*0x200000
+#define DR2_SLOW_RET 53
+
+
+;
+; Enable the performance counters
+;
+; The coprocessor only needs to be enabled when
+; starting/stopping the coprocessor with the pmenb/pmdis.
+;
+ .text
+
+ENTRY(perf_intrigue_enable_perf_counters)
+ .proc
+ .callinfo frame=0,NO_CALLS
+ .entry
+
+ ldi 0x20,%r25 ; load up perfmon bit
+ mfctl ccr,%r26 ; get coprocessor register
+ or %r25,%r26,%r26 ; set bit
+ mtctl %r26,ccr ; turn on performance coprocessor
+ pmenb ; enable performance monitor
+ ssm 0,0 ; dummy op to ensure completion
+ sync ; follow ERS
+ andcm %r26,%r25,%r26 ; clear bit now
+ mtctl %r26,ccr ; turn off performance coprocessor
+ nop ; NOPs as specified in ERS
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ bve (%r2)
+ nop
+ .exit
+ .procend
+ENDPROC(perf_intrigue_enable_perf_counters)
+
+ENTRY(perf_intrigue_disable_perf_counters)
+ .proc
+ .callinfo frame=0,NO_CALLS
+ .entry
+ ldi 0x20,%r25 ; load up perfmon bit
+ mfctl ccr,%r26 ; get coprocessor register
+ or %r25,%r26,%r26 ; set bit
+ mtctl %r26,ccr ; turn on performance coprocessor
+ pmdis ; disable performance monitor
+ ssm 0,0 ; dummy op to ensure completion
+ andcm %r26,%r25,%r26 ; clear bit now
+ bve (%r2)
+ mtctl %r26,ccr ; turn off performance coprocessor
+ .exit
+ .procend
+ENDPROC(perf_intrigue_disable_perf_counters)
+
+;***********************************************************************
+;*
+;* Name: perf_rdr_shift_in_W
+;*
+;* Description:
+;* This routine shifts data in from the RDR in arg0 and returns
+;* the result in ret0. If the RDR is <= 64 bits in length, it
+;* is shifted shifted backup immediately. This is to compensate
+;* for RDR10 which has bits that preclude PDC stack operations
+;* when they are in the wrong state.
+;*
+;* Arguments:
+;* arg0 : rdr to be read
+;* arg1 : bit length of rdr
+;*
+;* Returns:
+;* ret0 = next 64 bits of rdr data from staging register
+;*
+;* Register usage:
+;* arg0 : rdr to be read
+;* arg1 : bit length of rdr
+;* %r24 - original DR2 value
+;* %r1 - scratch
+;* %r29 - scratch
+;*
+;* Returns:
+;* ret0 = RDR data (right justified)
+;*
+;***********************************************************************
+
+ENTRY(perf_rdr_shift_in_W)
+ .proc
+ .callinfo frame=0,NO_CALLS
+ .entry
+;
+; read(shift in) the RDR.
+;
+
+; NOTE: The PCX-W ERS states that DR2_SLOW_RET must be set before any
+; shifting is done, from or to, remote diagnose registers.
+;
+
+ depdi,z 1,DR2_SLOW_RET,1,%r29
+ MFDIAG_2 (24)
+ or %r24,%r29,%r29
+ MTDIAG_2 (29) ; set DR2_SLOW_RET
+
+ nop
+ nop
+ nop
+ nop
+
+;
+; Cacheline start (32-byte cacheline)
+;
+ nop
+ nop
+ nop
+ extrd,u arg1,63,6,%r1 ; setup shift amount by bits to move
+
+ mtsar %r1
+ shladd arg0,2,%r0,%r1 ; %r1 = 4 * RDR number
+ blr %r1,%r0 ; branch to 8-instruction sequence
+ nop
+
+;
+; Cacheline start (32-byte cacheline)
+;
+
+ ;
+ ; RDR 0 sequence
+ ;
+ SFDIAG (0)
+ ssm 0,0
+ MFDIAG_1 (28)
+ shrpd ret0,%r0,%sar,%r1
+ MTDIAG_1 (1) ; mtdiag %dr1, %r1
+ STDIAG (0)
+ ssm 0,0
+ b,n perf_rdr_shift_in_W_leave
+
+ ;
+ ; RDR 1 sequence
+ ;
+ sync
+ ssm 0,0
+ SFDIAG (1)
+ ssm 0,0
+ MFDIAG_1 (28)
+ ssm 0,0
+ b,n perf_rdr_shift_in_W_leave
+ nop
+
+ ;
+ ; RDR 2 read sequence
+ ;
+ SFDIAG (2)
+ ssm 0,0
+ MFDIAG_1 (28)
+ shrpd ret0,%r0,%sar,%r1
+ MTDIAG_1 (1)
+ STDIAG (2)
+ ssm 0,0
+ b,n perf_rdr_shift_in_W_leave
+
+ ;
+ ; RDR 3 read sequence
+ ;
+ b,n perf_rdr_shift_in_W_leave
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+
+ ;
+ ; RDR 4 read sequence
+ ;
+ sync
+ ssm 0,0
+ SFDIAG (4)
+ ssm 0,0
+ MFDIAG_1 (28)
+ b,n perf_rdr_shift_in_W_leave
+ ssm 0,0
+ nop
+
+ ;
+ ; RDR 5 read sequence
+ ;
+ sync
+ ssm 0,0
+ SFDIAG (5)
+ ssm 0,0
+ MFDIAG_1 (28)
+ b,n perf_rdr_shift_in_W_leave
+ ssm 0,0
+ nop
+
+ ;
+ ; RDR 6 read sequence
+ ;
+ sync
+ ssm 0,0
+ SFDIAG (6)
+ ssm 0,0
+ MFDIAG_1 (28)
+ b,n perf_rdr_shift_in_W_leave
+ ssm 0,0
+ nop
+
+ ;
+ ; RDR 7 read sequence
+ ;
+ b,n perf_rdr_shift_in_W_leave
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+
+ ;
+ ; RDR 8 read sequence
+ ;
+ b,n perf_rdr_shift_in_W_leave
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+
+ ;
+ ; RDR 9 read sequence
+ ;
+ b,n perf_rdr_shift_in_W_leave
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+
+ ;
+ ; RDR 10 read sequence
+ ;
+ SFDIAG (10)
+ ssm 0,0
+ MFDIAG_1 (28)
+ shrpd ret0,%r0,%sar,%r1
+ MTDIAG_1 (1)
+ STDIAG (10)
+ ssm 0,0
+ b,n perf_rdr_shift_in_W_leave
+
+ ;
+ ; RDR 11 read sequence
+ ;
+ SFDIAG (11)
+ ssm 0,0
+ MFDIAG_1 (28)
+ shrpd ret0,%r0,%sar,%r1
+ MTDIAG_1 (1)
+ STDIAG (11)
+ ssm 0,0
+ b,n perf_rdr_shift_in_W_leave
+
+ ;
+ ; RDR 12 read sequence
+ ;
+ b,n perf_rdr_shift_in_W_leave
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+
+ ;
+ ; RDR 13 read sequence
+ ;
+ sync
+ ssm 0,0
+ SFDIAG (13)
+ ssm 0,0
+ MFDIAG_1 (28)
+ b,n perf_rdr_shift_in_W_leave
+ ssm 0,0
+ nop
+
+ ;
+ ; RDR 14 read sequence
+ ;
+ SFDIAG (14)
+ ssm 0,0
+ MFDIAG_1 (28)
+ shrpd ret0,%r0,%sar,%r1
+ MTDIAG_1 (1)
+ STDIAG (14)
+ ssm 0,0
+ b,n perf_rdr_shift_in_W_leave
+
+ ;
+ ; RDR 15 read sequence
+ ;
+ sync
+ ssm 0,0
+ SFDIAG (15)
+ ssm 0,0
+ MFDIAG_1 (28)
+ ssm 0,0
+ b,n perf_rdr_shift_in_W_leave
+ nop
+
+ ;
+ ; RDR 16 read sequence
+ ;
+ sync
+ ssm 0,0
+ SFDIAG (16)
+ ssm 0,0
+ MFDIAG_1 (28)
+ b,n perf_rdr_shift_in_W_leave
+ ssm 0,0
+ nop
+
+ ;
+ ; RDR 17 read sequence
+ ;
+ SFDIAG (17)
+ ssm 0,0
+ MFDIAG_1 (28)
+ shrpd ret0,%r0,%sar,%r1
+ MTDIAG_1 (1)
+ STDIAG (17)
+ ssm 0,0
+ b,n perf_rdr_shift_in_W_leave
+
+ ;
+ ; RDR 18 read sequence
+ ;
+ SFDIAG (18)
+ ssm 0,0
+ MFDIAG_1 (28)
+ shrpd ret0,%r0,%sar,%r1
+ MTDIAG_1 (1)
+ STDIAG (18)
+ ssm 0,0
+ b,n perf_rdr_shift_in_W_leave
+
+ ;
+ ; RDR 19 read sequence
+ ;
+ b,n perf_rdr_shift_in_W_leave
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+
+ ;
+ ; RDR 20 read sequence
+ ;
+ sync
+ ssm 0,0
+ SFDIAG (20)
+ ssm 0,0
+ MFDIAG_1 (28)
+ b,n perf_rdr_shift_in_W_leave
+ ssm 0,0
+ nop
+
+ ;
+ ; RDR 21 read sequence
+ ;
+ sync
+ ssm 0,0
+ SFDIAG (21)
+ ssm 0,0
+ MFDIAG_1 (28)
+ b,n perf_rdr_shift_in_W_leave
+ ssm 0,0
+ nop
+
+ ;
+ ; RDR 22 read sequence
+ ;
+ sync
+ ssm 0,0
+ SFDIAG (22)
+ ssm 0,0
+ MFDIAG_1 (28)
+ b,n perf_rdr_shift_in_W_leave
+ ssm 0,0
+ nop
+
+ ;
+ ; RDR 23 read sequence
+ ;
+ sync
+ ssm 0,0
+ SFDIAG (23)
+ ssm 0,0
+ MFDIAG_1 (28)
+ b,n perf_rdr_shift_in_W_leave
+ ssm 0,0
+ nop
+
+ ;
+ ; RDR 24 read sequence
+ ;
+ sync
+ ssm 0,0
+ SFDIAG (24)
+ ssm 0,0
+ MFDIAG_1 (28)
+ b,n perf_rdr_shift_in_W_leave
+ ssm 0,0
+ nop
+
+ ;
+ ; RDR 25 read sequence
+ ;
+ sync
+ ssm 0,0
+ SFDIAG (25)
+ ssm 0,0
+ MFDIAG_1 (28)
+ b,n perf_rdr_shift_in_W_leave
+ ssm 0,0
+ nop
+
+ ;
+ ; RDR 26 read sequence
+ ;
+ SFDIAG (26)
+ ssm 0,0
+ MFDIAG_1 (28)
+ shrpd ret0,%r0,%sar,%r1
+ MTDIAG_1 (1)
+ STDIAG (26)
+ ssm 0,0
+ b,n perf_rdr_shift_in_W_leave
+
+ ;
+ ; RDR 27 read sequence
+ ;
+ SFDIAG (27)
+ ssm 0,0
+ MFDIAG_1 (28)
+ shrpd ret0,%r0,%sar,%r1
+ MTDIAG_1 (1)
+ STDIAG (27)
+ ssm 0,0
+ b,n perf_rdr_shift_in_W_leave
+
+ ;
+ ; RDR 28 read sequence
+ ;
+ sync
+ ssm 0,0
+ SFDIAG (28)
+ ssm 0,0
+ MFDIAG_1 (28)
+ b,n perf_rdr_shift_in_W_leave
+ ssm 0,0
+ nop
+
+ ;
+ ; RDR 29 read sequence
+ ;
+ sync
+ ssm 0,0
+ SFDIAG (29)
+ ssm 0,0
+ MFDIAG_1 (28)
+ b,n perf_rdr_shift_in_W_leave
+ ssm 0,0
+ nop
+
+ ;
+ ; RDR 30 read sequence
+ ;
+ SFDIAG (30)
+ ssm 0,0
+ MFDIAG_1 (28)
+ shrpd ret0,%r0,%sar,%r1
+ MTDIAG_1 (1)
+ STDIAG (30)
+ ssm 0,0
+ b,n perf_rdr_shift_in_W_leave
+
+ ;
+ ; RDR 31 read sequence
+ ;
+ sync
+ ssm 0,0
+ SFDIAG (31)
+ ssm 0,0
+ MFDIAG_1 (28)
+ nop
+ ssm 0,0
+ nop
+
+ ;
+ ; Fallthrough
+ ;
+
+perf_rdr_shift_in_W_leave:
+ bve (%r2)
+ .exit
+ MTDIAG_2 (24) ; restore DR2
+ .procend
+ENDPROC(perf_rdr_shift_in_W)
+
+
+;***********************************************************************
+;*
+;* Name: perf_rdr_shift_out_W
+;*
+;* Description:
+;* This routine moves data to the RDR's. The double-word that
+;* arg1 points to is loaded and moved into the staging register.
+;* Then the STDIAG instruction for the RDR # in arg0 is called
+;* to move the data to the RDR.
+;*
+;* Arguments:
+;* arg0 = rdr number
+;* arg1 = 64-bit value to write
+;* %r24 - DR2 | DR2_SLOW_RET
+;* %r23 - original DR2 value
+;*
+;* Returns:
+;* None
+;*
+;* Register usage:
+;*
+;***********************************************************************
+
+ENTRY(perf_rdr_shift_out_W)
+ .proc
+ .callinfo frame=0,NO_CALLS
+ .entry
+;
+; NOTE: The PCX-W ERS states that DR2_SLOW_RET must be set before any
+; shifting is done, from or to, the remote diagnose registers.
+;
+
+ depdi,z 1,DR2_SLOW_RET,1,%r24
+ MFDIAG_2 (23)
+ or %r24,%r23,%r24
+ MTDIAG_2 (24) ; set DR2_SLOW_RET
+ MTDIAG_1 (25) ; data to the staging register
+ shladd arg0,2,%r0,%r1 ; %r1 = 4 * RDR number
+ blr %r1,%r0 ; branch to 8-instruction sequence
+ nop
+
+ ;
+ ; RDR 0 write sequence
+ ;
+ sync ; RDR 0 write sequence
+ ssm 0,0
+ STDIAG (0)
+ ssm 0,0
+ b,n perf_rdr_shift_out_W_leave
+ nop
+ ssm 0,0
+ nop
+
+ ;
+ ; RDR 1 write sequence
+ ;
+ sync
+ ssm 0,0
+ STDIAG (1)
+ ssm 0,0
+ b,n perf_rdr_shift_out_W_leave
+ nop
+ ssm 0,0
+ nop
+
+ ;
+ ; RDR 2 write sequence
+ ;
+ sync
+ ssm 0,0
+ STDIAG (2)
+ ssm 0,0
+ b,n perf_rdr_shift_out_W_leave
+ nop
+ ssm 0,0
+ nop
+
+ ;
+ ; RDR 3 write sequence
+ ;
+ sync
+ ssm 0,0
+ STDIAG (3)
+ ssm 0,0
+ b,n perf_rdr_shift_out_W_leave
+ nop
+ ssm 0,0
+ nop
+
+ ;
+ ; RDR 4 write sequence
+ ;
+ sync
+ ssm 0,0
+ STDIAG (4)
+ ssm 0,0
+ b,n perf_rdr_shift_out_W_leave
+ nop
+ ssm 0,0
+ nop
+
+ ;
+ ; RDR 5 write sequence
+ ;
+ sync
+ ssm 0,0
+ STDIAG (5)
+ ssm 0,0
+ b,n perf_rdr_shift_out_W_leave
+ nop
+ ssm 0,0
+ nop
+
+ ;
+ ; RDR 6 write sequence
+ ;
+ sync
+ ssm 0,0
+ STDIAG (6)
+ ssm 0,0
+ b,n perf_rdr_shift_out_W_leave
+ nop
+ ssm 0,0
+ nop
+
+ ;
+ ; RDR 7 write sequence
+ ;
+ sync
+ ssm 0,0
+ STDIAG (7)
+ ssm 0,0
+ b,n perf_rdr_shift_out_W_leave
+ nop
+ ssm 0,0
+ nop
+
+ ;
+ ; RDR 8 write sequence
+ ;
+ sync
+ ssm 0,0
+ STDIAG (8)
+ ssm 0,0
+ b,n perf_rdr_shift_out_W_leave
+ nop
+ ssm 0,0
+ nop
+
+ ;
+ ; RDR 9 write sequence
+ ;
+ sync
+ ssm 0,0
+ STDIAG (9)
+ ssm 0,0
+ b,n perf_rdr_shift_out_W_leave
+ nop
+ ssm 0,0
+ nop
+
+ ;
+ ; RDR 10 write sequence
+ ;
+ sync
+ ssm 0,0
+ STDIAG (10)
+ STDIAG (26)
+ ssm 0,0
+ b,n perf_rdr_shift_out_W_leave
+ ssm 0,0
+ nop
+
+ ;
+ ; RDR 11 write sequence
+ ;
+ sync
+ ssm 0,0
+ STDIAG (11)
+ STDIAG (27)
+ ssm 0,0
+ b,n perf_rdr_shift_out_W_leave
+ ssm 0,0
+ nop
+
+ ;
+ ; RDR 12 write sequence
+ ;
+ sync
+ ssm 0,0
+ STDIAG (12)
+ ssm 0,0
+ b,n perf_rdr_shift_out_W_leave
+ nop
+ ssm 0,0
+ nop
+
+ ;
+ ; RDR 13 write sequence
+ ;
+ sync
+ ssm 0,0
+ STDIAG (13)
+ ssm 0,0
+ b,n perf_rdr_shift_out_W_leave
+ nop
+ ssm 0,0
+ nop
+
+ ;
+ ; RDR 14 write sequence
+ ;
+ sync
+ ssm 0,0
+ STDIAG (14)
+ ssm 0,0
+ b,n perf_rdr_shift_out_W_leave
+ nop
+ ssm 0,0
+ nop
+
+ ;
+ ; RDR 15 write sequence
+ ;
+ sync
+ ssm 0,0
+ STDIAG (15)
+ ssm 0,0
+ b,n perf_rdr_shift_out_W_leave
+ nop
+ ssm 0,0
+ nop
+
+ ;
+ ; RDR 16 write sequence
+ ;
+ sync
+ ssm 0,0
+ STDIAG (16)
+ ssm 0,0
+ b,n perf_rdr_shift_out_W_leave
+ nop
+ ssm 0,0
+ nop
+
+ ;
+ ; RDR 17 write sequence
+ ;
+ sync
+ ssm 0,0
+ STDIAG (17)
+ ssm 0,0
+ b,n perf_rdr_shift_out_W_leave
+ nop
+ ssm 0,0
+ nop
+
+ ;
+ ; RDR 18 write sequence
+ ;
+ sync
+ ssm 0,0
+ STDIAG (18)
+ ssm 0,0
+ b,n perf_rdr_shift_out_W_leave
+ nop
+ ssm 0,0
+ nop
+
+ ;
+ ; RDR 19 write sequence
+ ;
+ sync
+ ssm 0,0
+ STDIAG (19)
+ ssm 0,0
+ b,n perf_rdr_shift_out_W_leave
+ nop
+ ssm 0,0
+ nop
+
+ ;
+ ; RDR 20 write sequence
+ ;
+ sync
+ ssm 0,0
+ STDIAG (20)
+ ssm 0,0
+ b,n perf_rdr_shift_out_W_leave
+ nop
+ ssm 0,0
+ nop
+
+ ;
+ ; RDR 21 write sequence
+ ;
+ sync
+ ssm 0,0
+ STDIAG (21)
+ ssm 0,0
+ b,n perf_rdr_shift_out_W_leave
+ nop
+ ssm 0,0
+ nop
+
+ ;
+ ; RDR 22 write sequence
+ ;
+ sync
+ ssm 0,0
+ STDIAG (22)
+ ssm 0,0
+ b,n perf_rdr_shift_out_W_leave
+ nop
+ ssm 0,0
+ nop
+
+ ;
+ ; RDR 23 write sequence
+ ;
+ sync
+ ssm 0,0
+ STDIAG (23)
+ ssm 0,0
+ b,n perf_rdr_shift_out_W_leave
+ nop
+ ssm 0,0
+ nop
+
+ ;
+ ; RDR 24 write sequence
+ ;
+ sync
+ ssm 0,0
+ STDIAG (24)
+ ssm 0,0
+ b,n perf_rdr_shift_out_W_leave
+ nop
+ ssm 0,0
+ nop
+
+ ;
+ ; RDR 25 write sequence
+ ;
+ sync
+ ssm 0,0
+ STDIAG (25)
+ ssm 0,0
+ b,n perf_rdr_shift_out_W_leave
+ nop
+ ssm 0,0
+ nop
+
+ ;
+ ; RDR 26 write sequence
+ ;
+ sync
+ ssm 0,0
+ STDIAG (10)
+ STDIAG (26)
+ ssm 0,0
+ b,n perf_rdr_shift_out_W_leave
+ ssm 0,0
+ nop
+
+ ;
+ ; RDR 27 write sequence
+ ;
+ sync
+ ssm 0,0
+ STDIAG (11)
+ STDIAG (27)
+ ssm 0,0
+ b,n perf_rdr_shift_out_W_leave
+ ssm 0,0
+ nop
+
+ ;
+ ; RDR 28 write sequence
+ ;
+ sync
+ ssm 0,0
+ STDIAG (28)
+ ssm 0,0
+ b,n perf_rdr_shift_out_W_leave
+ nop
+ ssm 0,0
+ nop
+
+ ;
+ ; RDR 29 write sequence
+ ;
+ sync
+ ssm 0,0
+ STDIAG (29)
+ ssm 0,0
+ b,n perf_rdr_shift_out_W_leave
+ nop
+ ssm 0,0
+ nop
+
+ ;
+ ; RDR 30 write sequence
+ ;
+ sync
+ ssm 0,0
+ STDIAG (30)
+ ssm 0,0
+ b,n perf_rdr_shift_out_W_leave
+ nop
+ ssm 0,0
+ nop
+
+ ;
+ ; RDR 31 write sequence
+ ;
+ sync
+ ssm 0,0
+ STDIAG (31)
+ ssm 0,0
+ b,n perf_rdr_shift_out_W_leave
+ nop
+ ssm 0,0
+ nop
+
+perf_rdr_shift_out_W_leave:
+ bve (%r2)
+ .exit
+ MTDIAG_2 (23) ; restore DR2
+ .procend
+ENDPROC(perf_rdr_shift_out_W)
+
+
+;***********************************************************************
+;*
+;* Name: rdr_shift_in_U
+;*
+;* Description:
+;* This routine shifts data in from the RDR in arg0 and returns
+;* the result in ret0. If the RDR is <= 64 bits in length, it
+;* is shifted shifted backup immediately. This is to compensate
+;* for RDR10 which has bits that preclude PDC stack operations
+;* when they are in the wrong state.
+;*
+;* Arguments:
+;* arg0 : rdr to be read
+;* arg1 : bit length of rdr
+;*
+;* Returns:
+;* ret0 = next 64 bits of rdr data from staging register
+;*
+;* Register usage:
+;* arg0 : rdr to be read
+;* arg1 : bit length of rdr
+;* %r24 - original DR2 value
+;* %r23 - DR2 | DR2_SLOW_RET
+;* %r1 - scratch
+;*
+;***********************************************************************
+
+ENTRY(perf_rdr_shift_in_U)
+ .proc
+ .callinfo frame=0,NO_CALLS
+ .entry
+
+; read(shift in) the RDR.
+;
+; NOTE: The PCX-U ERS states that DR2_SLOW_RET must be set before any
+; shifting is done, from or to, remote diagnose registers.
+
+ depdi,z 1,DR2_SLOW_RET,1,%r29
+ MFDIAG_2 (24)
+ or %r24,%r29,%r29
+ MTDIAG_2 (29) ; set DR2_SLOW_RET
+
+ nop
+ nop
+ nop
+ nop
+
+;
+; Start of next 32-byte cacheline
+;
+ nop
+ nop
+ nop
+ extrd,u arg1,63,6,%r1
+
+ mtsar %r1
+ shladd arg0,2,%r0,%r1 ; %r1 = 4 * RDR number
+ blr %r1,%r0 ; branch to 8-instruction sequence
+ nop
+
+;
+; Start of next 32-byte cacheline
+;
+ SFDIAG (0) ; RDR 0 read sequence
+ ssm 0,0
+ MFDIAG_1 (28)
+ shrpd ret0,%r0,%sar,%r1
+ MTDIAG_1 (1)
+ STDIAG (0)
+ ssm 0,0
+ b,n perf_rdr_shift_in_U_leave
+
+ SFDIAG (1) ; RDR 1 read sequence
+ ssm 0,0
+ MFDIAG_1 (28)
+ shrpd ret0,%r0,%sar,%r1
+ MTDIAG_1 (1)
+ STDIAG (1)
+ ssm 0,0
+ b,n perf_rdr_shift_in_U_leave
+
+ sync ; RDR 2 read sequence
+ ssm 0,0
+ SFDIAG (4)
+ ssm 0,0
+ MFDIAG_1 (28)
+ b,n perf_rdr_shift_in_U_leave
+ ssm 0,0
+ nop
+
+ sync ; RDR 3 read sequence
+ ssm 0,0
+ SFDIAG (3)
+ ssm 0,0
+ MFDIAG_1 (28)
+ b,n perf_rdr_shift_in_U_leave
+ ssm 0,0
+ nop
+
+ sync ; RDR 4 read sequence
+ ssm 0,0
+ SFDIAG (4)
+ ssm 0,0
+ MFDIAG_1 (28)
+ b,n perf_rdr_shift_in_U_leave
+ ssm 0,0
+ nop
+
+ sync ; RDR 5 read sequence
+ ssm 0,0
+ SFDIAG (5)
+ ssm 0,0
+ MFDIAG_1 (28)
+ b,n perf_rdr_shift_in_U_leave
+ ssm 0,0
+ nop
+
+ sync ; RDR 6 read sequence
+ ssm 0,0
+ SFDIAG (6)
+ ssm 0,0
+ MFDIAG_1 (28)
+ b,n perf_rdr_shift_in_U_leave
+ ssm 0,0
+ nop
+
+ sync ; RDR 7 read sequence
+ ssm 0,0
+ SFDIAG (7)
+ ssm 0,0
+ MFDIAG_1 (28)
+ b,n perf_rdr_shift_in_U_leave
+ ssm 0,0
+ nop
+
+ b,n perf_rdr_shift_in_U_leave
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+
+ SFDIAG (9) ; RDR 9 read sequence
+ ssm 0,0
+ MFDIAG_1 (28)
+ shrpd ret0,%r0,%sar,%r1
+ MTDIAG_1 (1)
+ STDIAG (9)
+ ssm 0,0
+ b,n perf_rdr_shift_in_U_leave
+
+ SFDIAG (10) ; RDR 10 read sequence
+ ssm 0,0
+ MFDIAG_1 (28)
+ shrpd ret0,%r0,%sar,%r1
+ MTDIAG_1 (1)
+ STDIAG (10)
+ ssm 0,0
+ b,n perf_rdr_shift_in_U_leave
+
+ SFDIAG (11) ; RDR 11 read sequence
+ ssm 0,0
+ MFDIAG_1 (28)
+ shrpd ret0,%r0,%sar,%r1
+ MTDIAG_1 (1)
+ STDIAG (11)
+ ssm 0,0
+ b,n perf_rdr_shift_in_U_leave
+
+ SFDIAG (12) ; RDR 12 read sequence
+ ssm 0,0
+ MFDIAG_1 (28)
+ shrpd ret0,%r0,%sar,%r1
+ MTDIAG_1 (1)
+ STDIAG (12)
+ ssm 0,0
+ b,n perf_rdr_shift_in_U_leave
+
+ SFDIAG (13) ; RDR 13 read sequence
+ ssm 0,0
+ MFDIAG_1 (28)
+ shrpd ret0,%r0,%sar,%r1
+ MTDIAG_1 (1)
+ STDIAG (13)
+ ssm 0,0
+ b,n perf_rdr_shift_in_U_leave
+
+ SFDIAG (14) ; RDR 14 read sequence
+ ssm 0,0
+ MFDIAG_1 (28)
+ shrpd ret0,%r0,%sar,%r1
+ MTDIAG_1 (1)
+ STDIAG (14)
+ ssm 0,0
+ b,n perf_rdr_shift_in_U_leave
+
+ SFDIAG (15) ; RDR 15 read sequence
+ ssm 0,0
+ MFDIAG_1 (28)
+ shrpd ret0,%r0,%sar,%r1
+ MTDIAG_1 (1)
+ STDIAG (15)
+ ssm 0,0
+ b,n perf_rdr_shift_in_U_leave
+
+ sync ; RDR 16 read sequence
+ ssm 0,0
+ SFDIAG (16)
+ ssm 0,0
+ MFDIAG_1 (28)
+ b,n perf_rdr_shift_in_U_leave
+ ssm 0,0
+ nop
+
+ SFDIAG (17) ; RDR 17 read sequence
+ ssm 0,0
+ MFDIAG_1 (28)
+ shrpd ret0,%r0,%sar,%r1
+ MTDIAG_1 (1)
+ STDIAG (17)
+ ssm 0,0
+ b,n perf_rdr_shift_in_U_leave
+
+ SFDIAG (18) ; RDR 18 read sequence
+ ssm 0,0
+ MFDIAG_1 (28)
+ shrpd ret0,%r0,%sar,%r1
+ MTDIAG_1 (1)
+ STDIAG (18)
+ ssm 0,0
+ b,n perf_rdr_shift_in_U_leave
+
+ b,n perf_rdr_shift_in_U_leave
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+
+ sync ; RDR 20 read sequence
+ ssm 0,0
+ SFDIAG (20)
+ ssm 0,0
+ MFDIAG_1 (28)
+ b,n perf_rdr_shift_in_U_leave
+ ssm 0,0
+ nop
+
+ sync ; RDR 21 read sequence
+ ssm 0,0
+ SFDIAG (21)
+ ssm 0,0
+ MFDIAG_1 (28)
+ b,n perf_rdr_shift_in_U_leave
+ ssm 0,0
+ nop
+
+ sync ; RDR 22 read sequence
+ ssm 0,0
+ SFDIAG (22)
+ ssm 0,0
+ MFDIAG_1 (28)
+ b,n perf_rdr_shift_in_U_leave
+ ssm 0,0
+ nop
+
+ sync ; RDR 23 read sequence
+ ssm 0,0
+ SFDIAG (23)
+ ssm 0,0
+ MFDIAG_1 (28)
+ b,n perf_rdr_shift_in_U_leave
+ ssm 0,0
+ nop
+
+ sync ; RDR 24 read sequence
+ ssm 0,0
+ SFDIAG (24)
+ ssm 0,0
+ MFDIAG_1 (28)
+ b,n perf_rdr_shift_in_U_leave
+ ssm 0,0
+ nop
+
+ sync ; RDR 25 read sequence
+ ssm 0,0
+ SFDIAG (25)
+ ssm 0,0
+ MFDIAG_1 (28)
+ b,n perf_rdr_shift_in_U_leave
+ ssm 0,0
+ nop
+
+ SFDIAG (26) ; RDR 26 read sequence
+ ssm 0,0
+ MFDIAG_1 (28)
+ shrpd ret0,%r0,%sar,%r1
+ MTDIAG_1 (1)
+ STDIAG (26)
+ ssm 0,0
+ b,n perf_rdr_shift_in_U_leave
+
+ SFDIAG (27) ; RDR 27 read sequence
+ ssm 0,0
+ MFDIAG_1 (28)
+ shrpd ret0,%r0,%sar,%r1
+ MTDIAG_1 (1)
+ STDIAG (27)
+ ssm 0,0
+ b,n perf_rdr_shift_in_U_leave
+
+ sync ; RDR 28 read sequence
+ ssm 0,0
+ SFDIAG (28)
+ ssm 0,0
+ MFDIAG_1 (28)
+ b,n perf_rdr_shift_in_U_leave
+ ssm 0,0
+ nop
+
+ b,n perf_rdr_shift_in_U_leave
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+
+ SFDIAG (30) ; RDR 30 read sequence
+ ssm 0,0
+ MFDIAG_1 (28)
+ shrpd ret0,%r0,%sar,%r1
+ MTDIAG_1 (1)
+ STDIAG (30)
+ ssm 0,0
+ b,n perf_rdr_shift_in_U_leave
+
+ SFDIAG (31) ; RDR 31 read sequence
+ ssm 0,0
+ MFDIAG_1 (28)
+ shrpd ret0,%r0,%sar,%r1
+ MTDIAG_1 (1)
+ STDIAG (31)
+ ssm 0,0
+ b,n perf_rdr_shift_in_U_leave
+ nop
+
+perf_rdr_shift_in_U_leave:
+ bve (%r2)
+ .exit
+ MTDIAG_2 (24) ; restore DR2
+ .procend
+ENDPROC(perf_rdr_shift_in_U)
+
+;***********************************************************************
+;*
+;* Name: rdr_shift_out_U
+;*
+;* Description:
+;* This routine moves data to the RDR's. The double-word that
+;* arg1 points to is loaded and moved into the staging register.
+;* Then the STDIAG instruction for the RDR # in arg0 is called
+;* to move the data to the RDR.
+;*
+;* Arguments:
+;* arg0 = rdr target
+;* arg1 = buffer pointer
+;*
+;* Returns:
+;* None
+;*
+;* Register usage:
+;* arg0 = rdr target
+;* arg1 = buffer pointer
+;* %r24 - DR2 | DR2_SLOW_RET
+;* %r23 - original DR2 value
+;*
+;***********************************************************************
+
+ENTRY(perf_rdr_shift_out_U)
+ .proc
+ .callinfo frame=0,NO_CALLS
+ .entry
+
+;
+; NOTE: The PCX-U ERS states that DR2_SLOW_RET must be set before any
+; shifting is done, from or to, the remote diagnose registers.
+;
+
+ depdi,z 1,DR2_SLOW_RET,1,%r24
+ MFDIAG_2 (23)
+ or %r24,%r23,%r24
+ MTDIAG_2 (24) ; set DR2_SLOW_RET
+
+ MTDIAG_1 (25) ; data to the staging register
+ shladd arg0,2,%r0,%r1 ; %r1 = 4 * RDR number
+ blr %r1,%r0 ; branch to 8-instruction sequence
+ nop
+
+;
+; 32-byte cachline aligned
+;
+
+ sync ; RDR 0 write sequence
+ ssm 0,0
+ STDIAG (0)
+ ssm 0,0
+ b,n perf_rdr_shift_out_U_leave
+ nop
+ ssm 0,0
+ nop
+
+ sync ; RDR 1 write sequence
+ ssm 0,0
+ STDIAG (1)
+ ssm 0,0
+ b,n perf_rdr_shift_out_U_leave
+ nop
+ ssm 0,0
+ nop
+
+ sync ; RDR 2 write sequence
+ ssm 0,0
+ STDIAG (2)
+ ssm 0,0
+ b,n perf_rdr_shift_out_U_leave
+ nop
+ ssm 0,0
+ nop
+
+ sync ; RDR 3 write sequence
+ ssm 0,0
+ STDIAG (3)
+ ssm 0,0
+ b,n perf_rdr_shift_out_U_leave
+ nop
+ ssm 0,0
+ nop
+
+ sync ; RDR 4 write sequence
+ ssm 0,0
+ STDIAG (4)
+ ssm 0,0
+ b,n perf_rdr_shift_out_U_leave
+ nop
+ ssm 0,0
+ nop
+
+ sync ; RDR 5 write sequence
+ ssm 0,0
+ STDIAG (5)
+ ssm 0,0
+ b,n perf_rdr_shift_out_U_leave
+ nop
+ ssm 0,0
+ nop
+
+ sync ; RDR 6 write sequence
+ ssm 0,0
+ STDIAG (6)
+ ssm 0,0
+ b,n perf_rdr_shift_out_U_leave
+ nop
+ ssm 0,0
+ nop
+
+ sync ; RDR 7 write sequence
+ ssm 0,0
+ STDIAG (7)
+ ssm 0,0
+ b,n perf_rdr_shift_out_U_leave
+ nop
+ ssm 0,0
+ nop
+
+ sync ; RDR 8 write sequence
+ ssm 0,0
+ STDIAG (8)
+ ssm 0,0
+ b,n perf_rdr_shift_out_U_leave
+ nop
+ ssm 0,0
+ nop
+
+ sync ; RDR 9 write sequence
+ ssm 0,0
+ STDIAG (9)
+ ssm 0,0
+ b,n perf_rdr_shift_out_U_leave
+ nop
+ ssm 0,0
+ nop
+
+ sync ; RDR 10 write sequence
+ ssm 0,0
+ STDIAG (10)
+ ssm 0,0
+ b,n perf_rdr_shift_out_U_leave
+ nop
+ ssm 0,0
+ nop
+
+ sync ; RDR 11 write sequence
+ ssm 0,0
+ STDIAG (11)
+ ssm 0,0
+ b,n perf_rdr_shift_out_U_leave
+ nop
+ ssm 0,0
+ nop
+
+ sync ; RDR 12 write sequence
+ ssm 0,0
+ STDIAG (12)
+ ssm 0,0
+ b,n perf_rdr_shift_out_U_leave
+ nop
+ ssm 0,0
+ nop
+
+ sync ; RDR 13 write sequence
+ ssm 0,0
+ STDIAG (13)
+ ssm 0,0
+ b,n perf_rdr_shift_out_U_leave
+ nop
+ ssm 0,0
+ nop
+
+ sync ; RDR 14 write sequence
+ ssm 0,0
+ STDIAG (14)
+ ssm 0,0
+ b,n perf_rdr_shift_out_U_leave
+ nop
+ ssm 0,0
+ nop
+
+ sync ; RDR 15 write sequence
+ ssm 0,0
+ STDIAG (15)
+ ssm 0,0
+ b,n perf_rdr_shift_out_U_leave
+ nop
+ ssm 0,0
+ nop
+
+ sync ; RDR 16 write sequence
+ ssm 0,0
+ STDIAG (16)
+ ssm 0,0
+ b,n perf_rdr_shift_out_U_leave
+ nop
+ ssm 0,0
+ nop
+
+ sync ; RDR 17 write sequence
+ ssm 0,0
+ STDIAG (17)
+ ssm 0,0
+ b,n perf_rdr_shift_out_U_leave
+ nop
+ ssm 0,0
+ nop
+
+ sync ; RDR 18 write sequence
+ ssm 0,0
+ STDIAG (18)
+ ssm 0,0
+ b,n perf_rdr_shift_out_U_leave
+ nop
+ ssm 0,0
+ nop
+
+ sync ; RDR 19 write sequence
+ ssm 0,0
+ STDIAG (19)
+ ssm 0,0
+ b,n perf_rdr_shift_out_U_leave
+ nop
+ ssm 0,0
+ nop
+
+ sync ; RDR 20 write sequence
+ ssm 0,0
+ STDIAG (20)
+ ssm 0,0
+ b,n perf_rdr_shift_out_U_leave
+ nop
+ ssm 0,0
+ nop
+
+ sync ; RDR 21 write sequence
+ ssm 0,0
+ STDIAG (21)
+ ssm 0,0
+ b,n perf_rdr_shift_out_U_leave
+ nop
+ ssm 0,0
+ nop
+
+ sync ; RDR 22 write sequence
+ ssm 0,0
+ STDIAG (22)
+ ssm 0,0
+ b,n perf_rdr_shift_out_U_leave
+ nop
+ ssm 0,0
+ nop
+
+ sync ; RDR 23 write sequence
+ ssm 0,0
+ STDIAG (23)
+ ssm 0,0
+ b,n perf_rdr_shift_out_U_leave
+ nop
+ ssm 0,0
+ nop
+
+ sync ; RDR 24 write sequence
+ ssm 0,0
+ STDIAG (24)
+ ssm 0,0
+ b,n perf_rdr_shift_out_U_leave
+ nop
+ ssm 0,0
+ nop
+
+ sync ; RDR 25 write sequence
+ ssm 0,0
+ STDIAG (25)
+ ssm 0,0
+ b,n perf_rdr_shift_out_U_leave
+ nop
+ ssm 0,0
+ nop
+
+ sync ; RDR 26 write sequence
+ ssm 0,0
+ STDIAG (26)
+ ssm 0,0
+ b,n perf_rdr_shift_out_U_leave
+ nop
+ ssm 0,0
+ nop
+
+ sync ; RDR 27 write sequence
+ ssm 0,0
+ STDIAG (27)
+ ssm 0,0
+ b,n perf_rdr_shift_out_U_leave
+ nop
+ ssm 0,0
+ nop
+
+ sync ; RDR 28 write sequence
+ ssm 0,0
+ STDIAG (28)
+ ssm 0,0
+ b,n perf_rdr_shift_out_U_leave
+ nop
+ ssm 0,0
+ nop
+
+ sync ; RDR 29 write sequence
+ ssm 0,0
+ STDIAG (29)
+ ssm 0,0
+ b,n perf_rdr_shift_out_U_leave
+ nop
+ ssm 0,0
+ nop
+
+ sync ; RDR 30 write sequence
+ ssm 0,0
+ STDIAG (30)
+ ssm 0,0
+ b,n perf_rdr_shift_out_U_leave
+ nop
+ ssm 0,0
+ nop
+
+ sync ; RDR 31 write sequence
+ ssm 0,0
+ STDIAG (31)
+ ssm 0,0
+ b,n perf_rdr_shift_out_U_leave
+ nop
+ ssm 0,0
+ nop
+
+perf_rdr_shift_out_U_leave:
+ bve (%r2)
+ .exit
+ MTDIAG_2 (23) ; restore DR2
+ .procend
+ENDPROC(perf_rdr_shift_out_U)
+
diff --git a/arch/parisc/kernel/perf_images.h b/arch/parisc/kernel/perf_images.h
new file mode 100644
index 000000000..7afa2fd55
--- /dev/null
+++ b/arch/parisc/kernel/perf_images.h
@@ -0,0 +1,3125 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Imagine for use with the Onyx (PCX-U) CPU interface
+ *
+ * Copyright (C) 2001 Randolph Chung <tausq at parisc-linux.org>
+ * Copyright (C) 2001 Hewlett-Packard (Grant Grundler)
+ */
+#ifndef PERF_IMAGES_H
+#define PERF_IMAGES_H
+
+/* Magic numbers taken without modification from HPUX stuff */
+
+#define PCXU_IMAGE_SIZE 584
+
+static uint32_t onyx_images[][PCXU_IMAGE_SIZE/sizeof(uint32_t)] __ro_after_init = {
+/*
+ * CPI:
+ *
+ * Counts the following:
+ *
+ * ctr0 : total cycles
+ * ctr1 : total cycles where nothing retired
+ * ctr2 : total instructions retired, including nullified
+ * ctr3 : total instructions retired, less nullified instructions
+ */
+ {
+ 0x4c00c000, 0x00000000, 0x00060000, 0x00000000,
+ 0xe0e0e0e0, 0x004e0004, 0x07ffffff, 0xffc01380,
+ 0x0101ffff, 0xfffff104, 0xe000c07f, 0xfffffffc,
+ 0x01380010, 0x1fffffff, 0xff000000, 0x00000000,
+ 0x00000fff, 0xff00000f, 0xffff0000, 0x0fffff00,
+ 0x000fffff, 0x00000000, 0x00000000, 0x00ffffff,
+ 0xfffff000, 0x0000000f, 0xffffffff, 0xff000000,
+ 0x0000ffff, 0xfffffff0, 0x00000000, 0x0fffffff,
+ 0xffff0000, 0x00000000, 0x6fffffff, 0xffffffff,
+ 0xfff55fff, 0xffffffff, 0xffffffff, 0xf0000000,
+ 0xf0000030, 0x00003c00, 0x067f080c, 0x02019fc0,
+ 0x02804067, 0xf0009030, 0x19fc002c, 0x40067f08,
+ 0x0c12019f, 0xc0028440, 0x67f00091, 0x3019fc00,
+ 0x2fc007ff, 0xf800f001, 0xfffe003c, 0x007fff80,
+ 0x0f001fff, 0xe003c007, 0xfff800f0, 0x01fffe00,
+ 0x3c007fff, 0x800f001f, 0xffe003c0, 0x07fff800,
+ 0xf001fffe, 0x003c007f, 0xff800f00, 0x1fffe003,
+ 0xc007fff8, 0x00f001ff, 0xfe003c00, 0x7fff800f,
+ 0x001fffe0, 0x03c007ff, 0xf800f001, 0xfffe003c,
+ 0x007fff80, 0x0f001fff, 0xe003c007, 0xfff800f0,
+ 0x01fffe00, 0x3c007fff, 0x800f001f, 0xffe00000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x6fff0000, 0x00000000, 0x60000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xfffffc00, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xfffffc00, 0x00000000,
+ 0xffffaaaa, 0xffffffff, 0xf3ffffff, 0xffffffff,
+ 0xfdffffff, 0xffffffff, 0xfe000000, 0x00000000,
+ 0xffffaaaa, 0xffffffff, 0xf3ffffff, 0xffffffff,
+ 0xfdffffff, 0xffffffff, 0xfe000000, 0x00000000,
+ 0xffffffff, 0xfffff9ff, 0xfe000000, 0x00000000,
+ 0xffffffff, 0xfffff9ff, 0xfe000000, 0x00000000,
+ 0x00030000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff},
+
+/* Bus utilization image (bus_util)
+ *
+ * ctr0 : counts address valid cycles
+ * ctr1 : counts data valid cycles
+ * ctr2 : counts overflow from counter 0
+ * ctr3 : counts overflow from counter 1
+ */
+ {
+ 0x0c01e000, 0x00000000, 0x00060000, 0x00000000,
+ 0xefefefef, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xff000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffff0000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xf0000000,
+ 0x0000000c, 0x00003c00, 0x07930000, 0x0041e4c0,
+ 0x01002079, 0x3000800c, 0x1e4c0030, 0x00279300,
+ 0x010049e4, 0xc0014022, 0x79300090, 0x0c9e4c00,
+ 0x34004793, 0x00020051, 0xe4c00180, 0x24793000,
+ 0xa00d1e4c, 0x00380067, 0x93000300, 0x59e4c001,
+ 0xc0267930, 0x00b00d9e, 0x4c003fff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffc00,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xffff0000, 0x00000000, 0xf0000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xfffffc00, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xfffffc00, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xf3ffffff, 0xffffffff,
+ 0xfdffffff, 0xffffffff, 0xfe000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xf3ffffff, 0xffffffff,
+ 0xfdffffff, 0xffffffff, 0xfe000000, 0x00000000,
+ 0xffffffff, 0xfffff9ff, 0xfe000000, 0x00000000,
+ 0xffffffff, 0xfffff9ff, 0xfe000000, 0x00000000,
+ 0x00100000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff },
+
+/*
+ * TLB counts (same as tlbStats image):
+ *
+ * Counts the following:
+ *
+ * ctr0: DTLB misses
+ * ctr1: ITLB misses
+ * ctr2: total cycles in the miss handlers
+ * ctr3: total cycles
+ */
+
+ {
+ 0x0c00c000, 0x00000000, 0x00060000, 0x00000000,
+ 0xe7e7e0e0, 0x004e0004, 0x07ffffff, 0xffc01380,
+ 0x0101ffff, 0xfffff104, 0xe000c06a, 0xafffc85c,
+ 0x01380010, 0x1fffffff, 0xff000000, 0x00000000,
+ 0x01b9e000, 0x0001b8c0, 0x00000000, 0x0fffff00,
+ 0x000fffff, 0x00000000, 0x00000000, 0x00400000,
+ 0x00001000, 0x00000004, 0x00000000, 0x01000000,
+ 0x0000ffff, 0xfffffff0, 0x00000000, 0x0fffffff,
+ 0xffff0000, 0x00000000, 0x6fffffff, 0xffffffff,
+ 0xfff55ff5, 0xffffffff, 0xffffffff, 0xf0000000,
+ 0xf0000000, 0x00003c00, 0x01ff0001, 0x08007fc2,
+ 0x02c1001f, 0xf0807100, 0x1bfc200c, 0x4806ff00,
+ 0x03f001ff, 0xfe003c00, 0x7fff800f, 0x001fffe0,
+ 0x03c007ff, 0xf800f001, 0xfffe003c, 0x007fff80,
+ 0x0f001fff, 0xe003c007, 0xfff800f0, 0x01fffe00,
+ 0x3c007fff, 0x800f001f, 0xffe003c0, 0x07fff800,
+ 0xf001fffe, 0x003c007f, 0xff800f00, 0x1fffe003,
+ 0xc007fff8, 0x00f001ff, 0xfe003c00, 0x7fff800f,
+ 0x001fffe0, 0x03c007ff, 0xf800f001, 0xfffe003c,
+ 0x007fff80, 0x0f001fff, 0xe003c007, 0xfff800f0,
+ 0x01fffe00, 0x3c007fff, 0x800f001f, 0xffe00000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x6fff0000, 0x00000000, 0x60000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xfffffc00, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xfffffc00, 0x00000000,
+ 0xffffaaaa, 0xffffffff, 0xf3ffffff, 0xffffffff,
+ 0xfdffffff, 0xffffffff, 0xfe000000, 0x00000000,
+ 0xffffaaaa, 0xffffffff, 0xf3ffffff, 0xffffffff,
+ 0xfdffffff, 0xffffffff, 0xfe000000, 0x00000000,
+ 0xffffffff, 0xfffff9ff, 0xfe000000, 0x00000000,
+ 0xffffffff, 0xfffff9ff, 0xfe000000, 0x00000000,
+ 0x00030000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff },
+
+/* tlbHandMiss
+ *
+ * ctr0: counts TLB misses
+ * ctr1: counts dmisses inside tlb miss handlers
+ * ctr2: counts cycles in the tlb miss handlers
+ * ctr3: counts overflows of ctr2
+ */
+{
+0x1c00c000,00000000,0x00060000,00000000,
+0xe7e7e0e0,0x004e0004,0x07ffffff,0xffc01380,
+0x0101ffff,0xfffff104,0xe000c06a,0xafffc85c,
+0x01380010,0x1fffffff,0xff000000,00000000,
+0x01b9e000,0x0001b8c0,00000000,0x0fffff00,
+0x000fffff,00000000,00000000,0x00400000,
+0x00001000,0x00000004,00000000,0x01000000,
+0x0000ffff,0xfffffff0,00000000,0x0fffffff,
+0xffff0000,00000000,0x6fffffff,0xffffffff,
+0xfff55ff5,0xffffffff,0xffffffff,0xf0000000,
+0xf0000000,0x00003c00,0x01fd0000,0x08007f42,
+0x0281001f,0xd080a100,0x19f42008,0x44067d08,
+0x0612019f,0x400084c0,0x67d00060,0x0047f400,
+0x042011fd,0x080b0404,0x7f4202c4,0x0167d080,
+0x311059f4,0x201c4816,0x7d000313,0x059f4001,
+0xfc007fff,0x800f001f,0xffe003c0,0x07fff800,
+0xf001fffe,0x003c007f,0xff800f00,0x1fffe003,
+0xc007fff8,0x00f001ff,0xfe003c00,0x7fff800f,
+0x001fffe0,0x03c007ff,0xf800f001,0xfffe003c,
+0x007fff80,0x0f001fff,0xe003c007,0xfff800f0,
+0x01fffe00,0x3c007fff,0x800f001f,0xffe00000,
+00000000,00000000,00000000,00000000,
+0x6fff0000,00000000,0x60000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff},
+
+/* branch_taken image (ptkn image)
+ *
+ * ctr0: overflow for ctr1
+ * ctr1: predicted taken branches, actually taken
+ * ctr2: all predicted taken branches (nullfied or not)
+ * ctr3: overflow for ctr2
+ */
+
+ {
+ 0xcc01e000, 0x00000000, 0x00060000, 0x00000000,
+ 0xa08080a0, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xff000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffff0000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xf0000000,
+ 0xf0000000, 0x00003c00, 0x04f90000, 0x02013e40,
+ 0x0081004f, 0x90004060, 0x13e40018, 0x0024f900,
+ 0x0802093e, 0x40028102, 0x4f9000c0, 0x6093e400,
+ 0x380014f9, 0x00010205, 0x3e4000c1, 0x014f9000,
+ 0x506053e4, 0x001c0034, 0xf9000902, 0x0d3e4002,
+ 0xc1034f90, 0x00d060d3, 0xe4003fff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffc00,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xffff0000, 0x00000000, 0xf0000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xfffffc00, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xfffffc00, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xf3ffffff, 0xffffffff,
+ 0xfdffffff, 0xffffffff, 0xfe000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xf3ffffff, 0xffffffff,
+ 0xfdffffff, 0xffffffff, 0xfe000000, 0x00000000,
+ 0xffffffff, 0xfffff9ff, 0xfe000000, 0x00000000,
+ 0xffffffff, 0xfffff9ff, 0xfe000000, 0x00000000,
+ 0x00030000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff },
+
+/* branch_nottaken (pntkn image)
+ *
+ * ctr0: overflow for ctr1
+ * ctr1: counts branches predicted not-taken, but actually taken
+ * ctr2: counts all predictable branches predicted not-taken
+ * ctr3: overflow for ctr2
+ */
+{
+0xcc01e000,00000000,0x00060000,00000000,
+0xc0c0c0e0,0xffb1fffb,0xfff7ffff,0xffffffff,
+0xffffffff,0xfffffffb,0x1fffbfff,0x7fffffff,
+0xfcc7ffff,0xffdffffa,0x5f000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0xf0000060,0x00003c00,0x04f90000,0x02013e40,
+0x0081004f,0x90004060,0x13e40018,0x0024f900,
+0x0802093e,0x40028102,0x4f9000c0,0x6093e400,
+0x380014f9,0x00010205,0x3e4000c1,0x014f9000,
+0x506053e4,0x001c0034,0xf9000902,0x0d3e4002,
+0xc1034f90,0x00d060d3,0xe4003fff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0xffff0000,00000000,0xf0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff},
+
+
+/* imiss image
+ *
+ * ctr0 : counts imiss aligned on 0
+ * ctr1 : counts imiss aligned on 4
+ * ctr2 : counts imiss aligned on 8
+ * ctr3 : counts imiss aligned on C
+ */
+ {
+ 0x0c00c000, 0x00000000, 0x00010000, 0x00000000,
+ 0xe7ebedee, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xff000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffff0000, 0x00000000, 0x6fffffff, 0xffffffff,
+ 0xfff55fff, 0xffffffff, 0xffffffff, 0xf0000000,
+ 0xf0000000, 0x00003c00, 0x007f0000, 0x01001fc0,
+ 0x00408007, 0xf0002030, 0x01fc000c, 0x10007f00,
+ 0x0405001f, 0xc0014180, 0x07f00060, 0x7001fc00,
+ 0x1c20007f, 0x00080900, 0x1fc00242, 0x8007f000,
+ 0xa0b001fc, 0x002c3000, 0x7f000c0d, 0x001fc003,
+ 0x438007f0, 0x00e0f001, 0xfc003fff, 0xfffff800,
+ 0xfffffffe, 0x003fffff, 0xff800fff, 0xffffe003,
+ 0xfffffff8, 0x00ffffff, 0xfe003fff, 0xffff800f,
+ 0xffffffe0, 0x03ffffff, 0xf800ffff, 0xfffe003f,
+ 0xffffff80, 0x0fffffff, 0xe003ffff, 0xfff800ff,
+ 0xfffffe00, 0x3fffffff, 0x800fffff, 0xffe00000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x6fff0000, 0x00000000, 0x60000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xfffffc00, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xfffffc00, 0x00000000,
+ 0xffffaaaa, 0xffffffff, 0xf3ffffff, 0xffffffff,
+ 0xfdffffff, 0xffffffff, 0xfe000000, 0x00000000,
+ 0xffffaaaa, 0xffffffff, 0xf3ffffff, 0xffffffff,
+ 0xfdffffff, 0xffffffff, 0xfe000000, 0x00000000,
+ 0xffffffff, 0xfffff9ff, 0xfe000000, 0x00000000,
+ 0xffffffff, 0xfffff9ff, 0xfe000000, 0x00000000,
+ 0x00030000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff},
+
+/* dmiss image
+ *
+ * ctr0 : counts cycles
+ * ctr1 : counts cycles where something retired
+ * ctr2 : counts dmisses
+ * ctr3 : (same as ctr2)
+ */
+ {
+ 0x3c00c000, 0x00000000, 0x00060000, 0x00000000,
+ 0xe0e0e0e0, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xff000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffff0000, 0x00000000, 0x6fffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xf0000000,
+ 0xf0000000, 0x00003c04, 0x007f0009, 0x02001fc0,
+ 0x0280c007, 0xf000b040, 0x01fc0030, 0x14007f00,
+ 0x0d06001f, 0xc00381c0, 0x07f000f0, 0x8001fc00,
+ 0x2024007f, 0x00090a00, 0x1fc00282, 0xc007f000,
+ 0xb0c001fc, 0x00303400, 0x7f000d0e, 0x001fc003,
+ 0x83c007f0, 0x00f00001, 0xfc0023ff, 0xfffff800,
+ 0xfffffffe, 0x003fffff, 0xff800fff, 0xffffe003,
+ 0xfffffff8, 0x00ffffff, 0xfe003fff, 0xffff800f,
+ 0xffffffe0, 0x03ffffff, 0xf800ffff, 0xfffe003f,
+ 0xffffff80, 0x0fffffff, 0xe003ffff, 0xfff800ff,
+ 0xfffffe00, 0x3fffffff, 0x800fffff, 0xffe00000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x6fff0000, 0x00000000, 0x60000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xfffffc00, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xfffffc00, 0x00000000,
+ 0xffffaaaa, 0xffffffff, 0xf3ffffff, 0xffffffff,
+ 0xfdffffff, 0xffffffff, 0xfe000000, 0x00000000,
+ 0xffffaaaa, 0xffffffff, 0xf3ffffff, 0xffffffff,
+ 0xfdffffff, 0xffffffff, 0xfe000000, 0x00000000,
+ 0xffffffff, 0xfffff9ff, 0xfe000000, 0x00000000,
+ 0xffffffff, 0xfffff9ff, 0xfe000000, 0x00000000,
+ 0x00030000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff },
+
+/* dcmiss
+ *
+ * ctr0: counts store instructions retired
+ * ctr1: counts load instructions retired
+ * ctr2: counts dmisses
+ * ctr3: counts READ_SHARED_OR_PRIV and READ_PRIVATE transactions on Runway
+ */
+{
+0x2c90c000,00000000,0x00060000,00000000,
+0xe0e0e0e0,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0x6fffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0xf00000e8,0x00003c02,0x00bf0001,0x02002fc0,
+0x0080a00b,0xf0003040,0x02fc0010,0x1200bf00,
+0x0506002f,0xc00181a0,0x0bf00070,0x8002fc00,
+0x202200bf,0x00090a00,0x2fc00282,0xa00bf000,
+0xb0c002fc,0x00303200,0xbf000d0e,0x002fc003,
+0x83a00bf0,0x00ffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0x6fff0000,00000000,0x60000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0x55555555,0xd5555555,
+0x55555555,0x75555555,0x5e1ffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00100000,00000000,0xf8000000,00000000,
+00000000,00000000,0xf4000000,00000000,
+0xffffffff,0xffffffff,0x00ffffff,0xffffffff,
+00000000,00000000,0x00ffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* big_cpi
+ *
+ * ctr0: counts total cycles
+ * ctr1: counts overflows of ctr0 (for greater than 32-bit values)
+ * ctr2: counts overflows of ctr3 (for greater than 32-bit values)
+ * ctr3: counts unnullified instructions retired
+ */
+{
+0x0c00c000,00000000,0x00060000,00000000,
+0xe7e7e0e0,0x004e0004,0x07ffffff,0xffc01380,
+0x0101ffff,0xfffff104,0xe000c06a,0xafffc85c,
+0x01380010,0x1fffffff,0xff000000,00000000,
+0x01b9e000,0x0001b8c0,00000000,0x0fffff00,
+0x000fffff,00000000,00000000,0x00400000,
+0x00001000,0x00000004,00000000,0x01000000,
+0x0000ffff,0xfffffff0,00000000,0x0fffffff,
+0xffff0000,00000000,0x6fffffff,0xffffffff,
+0xfff55ff5,0xffffffff,0xffffffff,0xf0000000,
+0xf0000010,0x00003c00,0x01760008,0x00025d80,
+0x02800417,0x6000c001,0x25d80038,0x04017600,
+0x0901025d,0x8002c044,0x176000d0,0x1125d800,
+0x3c2001f6,0x08080400,0x7d820203,0x001f6080,
+0x804027d8,0x20282009,0xf6080a0c,0x027d8202,
+0x81041f60,0x80c08107,0xd8203030,0x41f6080c,
+0x04127d82,0x0382049f,0x6080e0c1,0x27d82038,
+0x4006f608,0x081011bd,0x82030400,0xef6080a1,
+0x013bd820,0x384806f6,0x00081211,0xbd800304,
+0x80ef6000,0xa1213bd8,0x003bc007,0xfff800f0,
+0x01fffe00,0x3c007fff,0x800f001f,0xffe00000,
+00000000,00000000,00000000,00000000,
+0x6fff0000,00000000,0x60000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* big_ls
+ *
+ * ctr0:counts the total number of cycles for which local_stall_A1 is asserted.
+ * ctr1: is the overflow for counter 0.
+ * ctr2: counts IFLUSH_AV
+ * ctr3: is the overflow for counter 2.
+ */
+{
+0x0c000000,00000000,0x00060000,00000000,
+0xefefefef,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0x0fffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+00000000,0x00029408,0x02f50002,0x0800bd40,
+0x0202802f,0x5000a000,0x4bd40004,0x0812f500,
+0x030804bd,0x40024281,0x2f5000b0,0x010bd400,
+0x100842f5,0x00060810,0xbd400302,0x842f5000,
+0xe0014bd4,0x00140852,0xf5000708,0x14bd4003,
+0x42852f50,0x00ff001f,0xffe003c0,0x07fff800,
+0xf001fffe,0x003c007f,0xff800f00,0x1fffe003,
+0xc007fff8,0x00f001ff,0xfe003c00,0x7fff800f,
+0x001fffe0,0x03c007ff,0xf800f001,0xfffe003c,
+0x007fff80,0x0f001fff,0xe003c007,0xfff800f0,
+0x01fffe00,0x3c007fff,0x800f001f,0xffe00000,
+00000000,00000000,00000000,00000000,
+0x0df70000,00000000,00000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* br_abort
+ *
+ * ctr0: counts BRAD_STALLH
+ * ctr1: counts ONE_QUAD
+ * ctr2: counts BR0_ABRT
+ * ctr3: counts BR1_ABRT
+ */
+{
+0x0c002000,00000000,0x00060000,00000000,
+0xe0e0e0e0,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffa5ffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0x1fffffff,0xffffffff,
+0xfff7fff7,0xffffffff,0xffffffff,0xf0000000,
+00000000,0x0003f800,0x007f000e,0x01001fc0,
+0x03c08007,0xf000c030,0x01fc0034,0x10007f00,
+0x0a05001f,0xc002c180,0x07f00080,0x7001fc00,
+0x2420007f,0x00060900,0x1fc001c2,0x8007f000,
+0x40b001fc,0x00143000,0x7f00020d,0x001fc000,
+0xc38007f0,0x0000f001,0xfc0007ff,0xfffff800,
+0xfffffffe,0x003fffff,0xff800fff,0xffffe003,
+0xfffffff8,0x00ffffff,0xfe003fff,0xffff800f,
+0xffffffe0,0x03ffffff,0xf800ffff,0xfffe003f,
+0xffffff80,0x0fffffff,0xe003ffff,0xfff800ff,
+0xfffffe00,0x3fffffff,0x800fffff,0xffe00000,
+00000000,00000000,00000000,00000000,
+0x1a250000,00000000,0x10000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff},
+
+/* isnt
+ *
+ * ctr0: counts the total number of cycles for which iside_notrans is asserted
+ * ctr1: counts the number of times iside_notrans is asserted for 1-4 cycles
+ * ctr2: counts the number of times iside_notrans is asserted for 5-7 cycles
+ * ctr3: counts the number of times iside_notrans is asserted for > 7 cycles
+ */
+{
+0x0c018000,00000000,0x00060000,00000000,
+0xefefefef,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xcfffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+00000000,0x00021c20,0x03ff0808,0x1800ffc4,
+0x0204003f,0xf0004280,0x0ffc6020,0x8003ff00,
+0x043800ff,0xc8020c00,0x3ff00044,0x800ffca0,
+0x210003ff,0x00045800,0xffcc0214,0x003ff000,
+0x26800ffc,0xe0218003,0xff000278,0x00ffd002,
+0x1c003ff0,0x0028800f,0xfd002200,0x03ff0001,
+0xf001fffe,0x003c007f,0xff800f00,0x1fffe003,
+0xc007fff8,0x00f001ff,0xfe003c00,0x7fff800f,
+0x001fffe0,0x03c007ff,0xf800f001,0xfffe003c,
+0x007fff80,0x0f001fff,0xe003c007,0xfff800f0,
+0x01fffe00,0x3c007fff,0x800f001f,0xffe00000,
+00000000,00000000,00000000,00000000,
+0xcdff0000,00000000,0xc0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff},
+
+/* quadrant
+ *
+ * ctr0: Total number of instructions in quadrant 0
+ * ctr1: Total number of instructions in quadrant 1
+ * ctr2: Total number of instructions in quadrant 2
+ * ctr3: Total number of instructions in quadrant 3
+ * Works only with 32-bit
+ */
+
+ {
+ 0x0c01e000, 0x00000000, 0x00060000, 0x00000000,
+ 0xe0e0e0e0, 0x004e0004, 0x07ffffff, 0xffc01380,
+ 0x0101ffff, 0xfffff004, 0xe000407f, 0xfffffffc,
+ 0x01380010, 0x1fffffff, 0xff000000, 0x00000000,
+ 0x00000fff, 0xff00000f, 0xffff0000, 0x0fffff00,
+ 0x000fffff, 0x00000000, 0x00000000, 0x00ffffff,
+ 0xffcff000, 0x0000040f, 0xfffffffc, 0xff000000,
+ 0x0080ffff, 0xffffcff0, 0x0000000c, 0x0fffffff,
+ 0xfcff0000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xfff55ff5, 0x5fffffff, 0xffffffff, 0xf0000000,
+ 0xf00000f0, 0x00003c00, 0x007f0000, 0x01001fc0,
+ 0x00408007, 0xf0002030, 0x01fc000c, 0x10007f00,
+ 0x0405001f, 0xc0014180, 0x07f00060, 0x7001fc00,
+ 0x1c20007f, 0x00080900, 0x1fc00242, 0x8007f000,
+ 0xa0b001fc, 0x002c3000, 0x7f000c0d, 0x001fc003,
+ 0x438007f0, 0x00e0f001, 0xfc003fff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xfffffc00,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xffff0000, 0x00000000, 0xf0000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xfffffc00, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xfffffc00, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xf3ffffff, 0xffffffff,
+ 0xfdffffff, 0xffffffff, 0xfe000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xf3ffffff, 0xffffffff,
+ 0xfdffffff, 0xffffffff, 0xfe000000, 0x00000000,
+ 0xffffffff, 0xfffff9ff, 0xfe000000, 0x00000000,
+ 0xffffffff, 0xfffff9ff, 0xfe000000, 0x00000000,
+ 0x00030000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff},
+
+/* rw_pdfet (READ_PRIV transactions)
+ *
+ * ctr0: counts address valid cycles
+ * ctr1: counts *all* data valid cycles
+ * ctr2: is the overflow from counter 0
+ * ctr3: is the overflow from counter 1
+ */
+{
+0x0c01e000,00000000,0x00060000,00000000,
+0xefefefef,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0x0000000c,0x00003c00,0x07930000,0x0041e4c0,
+0x01002079,0x3000800c,0x1e4c0030,0x00279300,
+0x010049e4,0xc0014022,0x79300090,0x0c9e4c00,
+0x34004793,0x00020051,0xe4c00180,0x24793000,
+0xa00d1e4c,0x00380067,0x93000300,0x59e4c001,
+0xc0267930,0x00b00d9e,0x4c003fff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0xffff0000,00000000,0xf0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00100000,00000000,0xf8000000,00000000,
+00000000,00000000,00000000,00000000,
+0xffffffff,0xffffffff,0x00ffffff,0xffffffff,
+00000000,00000000,00000000,00000000,
+0xffffffff,0xffffffff},
+
+/* rw_wdfet (WRITEBACKS)
+ *
+ * ctr0: counts address valid cycles
+ * ctr1: counts *all* data valid cycles
+ * ctr2: is the overflow from counter 0
+ * ctr3: is the overflow from counter 1
+ */
+{
+0x0c01e000,00000000,0x00060000,00000000,
+0xefefefef,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0x0000000c,0x00003c00,0x07930000,0x0041e4c0,
+0x01002079,0x3000800c,0x1e4c0030,0x00279300,
+0x010049e4,0xc0014022,0x79300090,0x0c9e4c00,
+0x34004793,0x00020051,0xe4c00180,0x24793000,
+0xa00d1e4c,0x00380067,0x93000300,0x59e4c001,
+0xc0267930,0x00b00d9e,0x4c003fff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0xffff0000,00000000,0xf0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00100000,00000000,0x98000000,00000000,
+00000000,00000000,00000000,00000000,
+0xffffffff,0xffffffff,0x00ffffff,0xffffffff,
+00000000,00000000,00000000,00000000,
+0xffffffff,0xffffffff},
+
+/* shlib_cpi
+ *
+ * ctr0: Total number of instructions in quad 0
+ * ctr1: Total number of CPU clock cycles in quad 0
+ * ctr2: total instructions without nullified
+ * ctr3: total number of CPU clock cycles
+ */
+ {
+ 0x0c01e000, 0x00000000, 0x00060000, 0x00000000,
+ 0xe0e0e0e0, 0x004e0004, 0x07ffffff, 0xffc01380,
+ 0x0101ffff, 0xfffff004, 0xe000407f, 0xfffffffc,
+ 0x01380010, 0x1fffffff, 0xff000000, 0x00000000,
+ 0x00000fff, 0xff00000f, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0x00000000, 0x00000000, 0x00ffffff,
+ 0xffcff000, 0x0000000f, 0xfffffffc, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffff0000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xfff77ff5, 0x7fffffff, 0xffffffff, 0xf0000000,
+ 0xf00000a0, 0x00003c00, 0x01ff0005, 0x08007fc0,
+ 0x03c1001f, 0xf08030c0, 0x07fc203c, 0x4001ff08,
+ 0x0118007f, 0xc003c500, 0x1ff08031, 0xc007fc00,
+ 0x3fffffff, 0xf800ffff, 0xfffe003f, 0xffffff80,
+ 0x0fffffff, 0xe003ffff, 0xfff800ff, 0xfffffe00,
+ 0x3fffffff, 0x800fffff, 0xffe003ff, 0xfffff800,
+ 0xfffffffe, 0x003fffff, 0xff800fff, 0xffffe003,
+ 0xfffffff8, 0x00ffffff, 0xfe003fff, 0xffff800f,
+ 0xffffffe0, 0x03ffffff, 0xf800ffff, 0xfffe003f,
+ 0xffffff80, 0x0fffffff, 0xe003ffff, 0xfff800ff,
+ 0xfffffe00, 0x3fffffff, 0x800fffff, 0xffe00000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xffff0000, 0x00000000, 0xf0000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xfffffc00, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xfffffc00, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xf3ffffff, 0xffffffff,
+ 0xfdffffff, 0xffffffff, 0xfe000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xf3ffffff, 0xffffffff,
+ 0xfdffffff, 0xffffffff, 0xfe000000, 0x00000000,
+ 0xffffffff, 0xfffff9ff, 0xfe000000, 0x00000000,
+ 0xffffffff, 0xfffff9ff, 0xfe000000, 0x00000000,
+ 0x00030000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff},
+
+
+/* addr_inv_abort_alu
+ *
+ * ctr0: counts ABORT_ALU0L
+ * ctr1: counts ABORT_ALU1L
+ * ctr2: counts ADDR0_INVALID
+ * ctr3: counts ADDR1_INVALID
+ */
+
+{
+0x0c00c000,00000000,0x00060000,00000000,
+0xe0e0e0e0,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffa5ffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0x6fffffff,0xffffffff,
+0xfff7fff7,0xffffffff,0xffffffff,0xf0000000,
+00000000,0x0003f800,0x007f000d,0x01001fc0,
+0x03008007,0xf000f030,0x01fc0038,0x10007f00,
+0x0905001f,0xc0020180,0x07f000b0,0x7001fc00,
+0x2820007f,0x00050900,0x1fc00102,0x8007f000,
+0x70b001fc,0x00183000,0x7f00010d,0x001fc000,
+0x038007f0,0x0030f001,0xfc000bff,0xfffff800,
+0xfffffffe,0x003fffff,0xff800fff,0xffffe003,
+0xfffffff8,0x00ffffff,0xfe003fff,0xffff800f,
+0xffffffe0,0x03ffffff,0xf800ffff,0xfffe003f,
+0xffffff80,0x0fffffff,0xe003ffff,0xfff800ff,
+0xfffffe00,0x3fffffff,0x800fffff,0xffe00000,
+00000000,00000000,00000000,00000000,
+0x65380000,00000000,0x60000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+
+
+/* brad_stall
+ *
+ * ctr0: counts the total number of cycles for which brad_stall is asserted
+ * ctr1: counts the number of times brad_stall is asserted for 1-4 cycles
+ * ctr2: counts the number of times brad_stall is asserted for 5-7 cycles
+ * ctr3: counts the number of times brad_stall is asserted for > 7 cycles
+ */
+{
+0x0c002000,00000000,0x00060000,00000000,
+0xefefefef,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0x1fffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+00000000,0x00021c20,0x03ff0808,0x1800ffc4,
+0x0204003f,0xf0004280,0x0ffc6020,0x8003ff00,
+0x043800ff,0xc8020c00,0x3ff00044,0x800ffca0,
+0x210003ff,0x00045800,0xffcc0214,0x003ff000,
+0x26800ffc,0xe0218003,0xff000278,0x00ffd002,
+0x1c003ff0,0x0028800f,0xfd002200,0x03ff0001,
+0xf001fffe,0x003c007f,0xff800f00,0x1fffe003,
+0xc007fff8,0x00f001ff,0xfe003c00,0x7fff800f,
+0x001fffe0,0x03c007ff,0xf800f001,0xfffe003c,
+0x007fff80,0x0f001fff,0xe003c007,0xfff800f0,
+0x01fffe00,0x3c007fff,0x800f001f,0xffe00000,
+00000000,00000000,00000000,00000000,
+0x1bff0000,00000000,0x10000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff},
+
+/* cntl_in_pipel
+ *
+ * ctr0: counts the total number of cycles for which cntl_in_pipel is asserted
+ * ctr1: counts the number of times cntl_in_pipel is asserted for 1-4 cycles
+ * ctr2: counts the number of times cntl_in_pipel is asserted for 5-7 cycles
+ * ctr3: counts the number of times cntl_in_pipel is asserted for > 7 cycles
+ */
+{
+0x0c006000,00000000,0x00060000,00000000,
+0xefefefef,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0x3fffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+00000000,0x00021c00,0x03ff0808,0x1000ffc4,
+0x0206003f,0xf0004200,0x0ffc6020,0xa003ff00,
+0x043000ff,0xc8020e00,0x3ff00044,0x000ffca0,
+0x212003ff,0x00045000,0xffcc0216,0x003ff000,
+0x26000ffc,0xe021a003,0xff000270,0x00ffd002,
+0x1e003ff0,0x0028000f,0xfd002220,0x03ff0001,
+0xf001fffe,0x003c007f,0xff800f00,0x1fffe003,
+0xc007fff8,0x00f001ff,0xfe003c00,0x7fff800f,
+0x001fffe0,0x03c007ff,0xf800f001,0xfffe003c,
+0x007fff80,0x0f001fff,0xe003c007,0xfff800f0,
+0x01fffe00,0x3c007fff,0x800f001f,0xffe00000,
+00000000,00000000,00000000,00000000,
+0x3fff0000,00000000,0x30000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+
+/* dsnt_xfh
+ *
+ * ctr0: counts dside_notrans
+ * ctr1: counts xfhang
+ * ctr2: is the overflow for ctr0
+ * ctr3: is the overflow for ctr1
+ */
+{
+0x0c018000,00000000,0x00060000,00000000,
+0xefefefef,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xcfffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+00000000,0x00030000,0x01f30000,0x00087cc0,
+0x0040041f,0x30002001,0x87cc000c,0x1001f300,
+0x0404087c,0xc0014104,0x1f300060,0x4187cc00,
+0x1c2001f3,0x00080808,0x7cc00242,0x041f3000,
+0xa08187cc,0x002c3001,0xf3000c0c,0x087cc003,
+0x43041f30,0x00e0c187,0xcc003fc0,0x07fff800,
+0xf001fffe,0x003c007f,0xff800f00,0x1fffe003,
+0xc007fff8,0x00f001ff,0xfe003c00,0x7fff800f,
+0x001fffe0,0x03c007ff,0xf800f001,0xfffe003c,
+0x007fff80,0x0f001fff,0xe003c007,0xfff800f0,
+0x01fffe00,0x3c007fff,0x800f001f,0xffe00000,
+00000000,00000000,00000000,00000000,
+0xcb3f0000,00000000,0xc0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* fet_sig1
+ *
+ * ctr0: counts ICORE_AV
+ * ctr1: counts ITRANS_STALL
+ * ctr2: counts SEL_PCQH
+ * ctr3: counts OUT_OF_CONTEXT
+ */
+{
+0x0c000000,00000000,0x00060000,00000000,
+0xe0e0e0e0,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffa5ffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0x0fffffff,0xffffffff,
+0xfff7fff7,0xffffffff,0xffffffff,0xf0000000,
+00000000,0x0003f800,0x007f000e,0x01001fc0,
+0x03c08007,0xf000c030,0x01fc0034,0x10007f00,
+0x0a05001f,0xc002c180,0x07f00080,0x7001fc00,
+0x2420007f,0x00060900,0x1fc001c2,0x8007f000,
+0x40b001fc,0x00143000,0x7f00020d,0x001fc000,
+0xc38007f0,0x0000f001,0xfc0007ff,0xfffff800,
+0xfffffffe,0x003fffff,0xff800fff,0xffffe003,
+0xfffffff8,0x00ffffff,0xfe003fff,0xffff800f,
+0xffffffe0,0x03ffffff,0xf800ffff,0xfffe003f,
+0xffffff80,0x0fffffff,0xe003ffff,0xfff800ff,
+0xfffffe00,0x3fffffff,0x800fffff,0xffe00000,
+00000000,00000000,00000000,00000000,
+0x07c10000,00000000,00000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff},
+
+/* fet_sig2
+ *
+ * ctr0: counts ICORE_AV
+ * ctr1: counts IRTN_AV
+ * ctr2: counts ADDRESS_INC
+ * ctr3: counts ADDRESS_DEC
+ */
+{
+0x0c000000,00000000,0x00060000,00000000,
+0xe0e0e0e0,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffa5ffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0x0fffffff,0xffffffff,
+0xfff7fff7,0xffffffff,0xffffffff,0xf0000000,
+00000000,0x0003f800,0x007f000e,0x01001fc0,
+0x03c08007,0xf000c030,0x01fc0034,0x10007f00,
+0x0a05001f,0xc002c180,0x07f00080,0x7001fc00,
+0x2420007f,0x00060900,0x1fc001c2,0x8007f000,
+0x40b001fc,0x00143000,0x7f00020d,0x001fc000,
+0xc38007f0,0x0000f001,0xfc0007ff,0xfffff800,
+0xfffffffe,0x003fffff,0xff800fff,0xffffe003,
+0xfffffff8,0x00ffffff,0xfe003fff,0xffff800f,
+0xffffffe0,0x03ffffff,0xf800ffff,0xfffe003f,
+0xffffff80,0x0fffffff,0xe003ffff,0xfff800ff,
+0xfffffe00,0x3fffffff,0x800fffff,0xffe00000,
+00000000,00000000,00000000,00000000,
+0x06930000,00000000,00000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* g7_1
+ *
+ * ctr0: counts HIT_RETRY0
+ * ctr1: counts HIT_RETRY1
+ * ctr2: counts GO_TAG_E
+ * ctr3: counts GO_TAG_O
+ */
+{
+0x0c00e000,00000000,0x00060000,00000000,
+0xe0e0e0e0,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffa5ffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0x7fffffff,0xffffffff,
+0xfff7fff7,0xffffffff,0xffffffff,0xf0000000,
+00000000,0x0003f800,0x007f000e,0x01001fc0,
+0x03c08007,0xf000c030,0x01fc0034,0x10007f00,
+0x0a05001f,0xc002c180,0x07f00080,0x7001fc00,
+0x2420007f,0x00060900,0x1fc001c2,0x8007f000,
+0x40b001fc,0x00143000,0x7f00020d,0x001fc000,
+0xc38007f0,0x0000f001,0xfc0007ff,0xfffff800,
+0xfffffffe,0x003fffff,0xff800fff,0xffffe003,
+0xfffffff8,0x00ffffff,0xfe003fff,0xffff800f,
+0xffffffe0,0x03ffffff,0xf800ffff,0xfffe003f,
+0xffffff80,0x0fffffff,0xe003ffff,0xfff800ff,
+0xfffffe00,0x3fffffff,0x800fffff,0xffe00000,
+00000000,00000000,00000000,00000000,
+0x71c10000,00000000,0x70000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* g7_2
+ *
+ * ctr0: counts HIT_DM0
+ * ctr1: counts HIT_DM1
+ * ctr2: counts GO_STORE_E
+ * ctr3: counts GO_STORE_O
+ */
+{
+0x0c00e000,00000000,0x00060000,00000000,
+0xe0e0e0e0,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffa5ffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0x7fffffff,0xffffffff,
+0xfff7fff7,0xffffffff,0xffffffff,0xf0000000,
+00000000,0x0003f800,0x007f000e,0x01001fc0,
+0x03c08007,0xf000c030,0x01fc0034,0x10007f00,
+0x0a05001f,0xc002c180,0x07f00080,0x7001fc00,
+0x2420007f,0x00060900,0x1fc001c2,0x8007f000,
+0x40b001fc,0x00143000,0x7f00020d,0x001fc000,
+0xc38007f0,0x0000f001,0xfc0007ff,0xfffff800,
+0xfffffffe,0x003fffff,0xff800fff,0xffffe003,
+0xfffffff8,0x00ffffff,0xfe003fff,0xffff800f,
+0xffffffe0,0x03ffffff,0xf800ffff,0xfffe003f,
+0xffffff80,0x0fffffff,0xe003ffff,0xfff800ff,
+0xfffffe00,0x3fffffff,0x800fffff,0xffe00000,
+00000000,00000000,00000000,00000000,
+0x72930000,00000000,0x70000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* g7_3
+ *
+ * ctr0: counts HIT_DV0
+ * ctr1: counts HIT_DV1
+ * ctr2: counts STBYPT_E (load bypasses from store queue)
+ * ctr3: counts STBYPT_O
+ */
+{
+0x0c00e000,00000000,0x00060000,00000000,
+0xe0e0e0e0,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffa5ffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0x7fffffff,0xffffffff,
+0xfff7fff7,0xffffffff,0xffffffff,0xf0000000,
+00000000,0x0003f800,0x007f0002,0x01001fc0,
+0x00c08007,0xf0000030,0x01fc0004,0x10007f00,
+0x0605001f,0xc001c180,0x07f00040,0x7001fc00,
+0x1420007f,0x000a0900,0x1fc002c2,0x8007f000,
+0x80b001fc,0x00243000,0x7f000e0d,0x001fc003,
+0xc38007f0,0x00c0f001,0xfc0037ff,0xfffff800,
+0xfffffffe,0x003fffff,0xff800fff,0xffffe003,
+0xfffffff8,0x00ffffff,0xfe003fff,0xffff800f,
+0xffffffe0,0x03ffffff,0xf800ffff,0xfffe003f,
+0xffffff80,0x0fffffff,0xe003ffff,0xfff800ff,
+0xfffffe00,0x3fffffff,0x800fffff,0xffe00000,
+00000000,00000000,00000000,00000000,
+0x77250000,00000000,0x70000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* g7_4
+ *
+ * ctr0: counts HIT_DIRTY0
+ * ctr1: counts HIT_DIRTY1
+ * ctr2: counts CA_BYP_E (quick launch)
+ * ctr3: counts CA_BYP_O
+ */
+{
+0x0c00e000,00000000,0x00060000,00000000,
+0xe0e0e0e0,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffa5ffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0x7fffffff,0xffffffff,
+0xfff7fff7,0xffffffff,0xffffffff,0xf0000000,
+00000000,0x0003f800,0x007f000e,0x01001fc0,
+0x03c08007,0xf000c030,0x01fc0034,0x10007f00,
+0x0a05001f,0xc002c180,0x07f00080,0x7001fc00,
+0x2420007f,0x00060900,0x1fc001c2,0x8007f000,
+0x40b001fc,0x00143000,0x7f00020d,0x001fc000,
+0xc38007f0,0x0000f001,0xfc0007ff,0xfffff800,
+0xfffffffe,0x003fffff,0xff800fff,0xffffe003,
+0xfffffff8,0x00ffffff,0xfe003fff,0xffff800f,
+0xffffffe0,0x03ffffff,0xf800ffff,0xfffe003f,
+0xffffff80,0x0fffffff,0xe003ffff,0xfff800ff,
+0xfffffe00,0x3fffffff,0x800fffff,0xffe00000,
+00000000,00000000,00000000,00000000,
+0x7bb70000,00000000,0x70000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+
+/* mpb_labort
+ *
+ * ctr0: counts L_ABORT_ALU0L
+ * ctr1: counts L_ABORT_ALU1L
+ * ctr2: counts MPB0H
+ * ctr3: counts MPB1H
+ */
+{
+0x0c00c000,00000000,0x00060000,00000000,
+0xe0e0e0e0,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffa5ffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0x6fffffff,0xffffffff,
+0xfff7fff7,0xffffffff,0xffffffff,0xf0000000,
+00000000,0x0003f800,0x007f000e,0x01001fc0,
+0x03c08007,0xf000c030,0x01fc0034,0x10007f00,
+0x0a05001f,0xc002c180,0x07f00080,0x7001fc00,
+0x2420007f,0x00060900,0x1fc001c2,0x8007f000,
+0x40b001fc,0x00143000,0x7f00020d,0x001fc000,
+0xc38007f0,0x0000f001,0xfc0007ff,0xfffff800,
+0xfffffffe,0x003fffff,0xff800fff,0xffffe003,
+0xfffffff8,0x00ffffff,0xfe003fff,0xffff800f,
+0xffffffe0,0x03ffffff,0xf800ffff,0xfffe003f,
+0xffffff80,0x0fffffff,0xe003ffff,0xfff800ff,
+0xfffffe00,0x3fffffff,0x800fffff,0xffe00000,
+00000000,00000000,00000000,00000000,
+0x605c0000,00000000,0x60000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffaaaa,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* panic
+ *
+ * ctr0: is the overflow for counter 1
+ * ctr1: counts traps and RFI's
+ * ctr2: counts panic traps
+ * ctr3: is the overflow for counter 2
+ */
+{
+0x0c002000,00000000,0x00060000,00000000,
+0xe7efe0e0,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffffc,
+0x41380030,0x1aabfff2,0x17000000,00000000,
+0x01b80000,0x3effffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,00000000,0x00400000,
+0x00001fff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0x1fffffff,0xffffffff,
+0xfff7fff7,0xffffffff,0xffffffff,0xf0000000,
+0xb0000000,0x00012c04,0x05790804,0x14013e44,
+0x0008004f,0x90000040,0x15e46000,0xc0047920,
+0x004a003e,0x40011080,0x0f900024,0x4003e460,
+0x00c80479,0x00023301,0x1e400100,0x4157d080,
+0x514053f4,0x40048014,0xfd000104,0x055f4600,
+0x4c0147d2,0x0014a043,0xf4001508,0x10fd0003,
+0x44043f46,0x004c8147,0xd0003330,0x51f40014,
+0x04257908,0x0c14093e,0x44020802,0x4f900080,
+0x4095e460,0x20c02479,0x20084a08,0x3e400310,
+0x820f9000,0xa44083e4,0x6020c824,0x79000a33,
+0x091e4003,0x3c007fff,0x800f001f,0xffe00000,
+00000000,00000000,00000000,00000000,
+0x10400000,00000000,0x10000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* rare_inst
+ *
+ * ctr0: counts sync and syncdma instructions
+ * ctr1: counts pxtlbx,x instructions
+ * ctr2: counts ixtlbt instructions
+ * ctr3: counts cycles
+ */
+{
+0x0c01e000,00000000,0x00060000,00000000,
+0xe0e0e0e0,0x004e000c,0x000843fc,0x85c09380,
+0x0121ebfd,0xff217124,0xe0004000,0x943fc85f,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0xe00000e0,0x00003c00,0x007f0001,0x01001fc0,
+0x00408007,0xf0003030,0x01fc000c,0x10007f00,
+0x0505001f,0xc0014180,0x07f00070,0x7001fc00,
+0x1c20007f,0x00090900,0x1fc00242,0x8007f000,
+0xb0b001fc,0x002c3000,0x7f000d0d,0x001fc003,
+0x438007f0,0x00f0f001,0xfc003fff,0xfffff800,
+0xfffffffe,0x003fffff,0xff800fff,0xffffe003,
+0xfffffff8,0x00ffffff,0xfe003fff,0xffff800f,
+0xffffffe0,0x03ffffff,0xf800ffff,0xfffe003f,
+0xffffff80,0x0fffffff,0xe003ffff,0xfff800ff,
+0xfffffe00,0x3fffffff,0x800fffff,0xffe00000,
+00000000,00000000,00000000,00000000,
+0xffff0000,00000000,0xf0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* rw_dfet (for D-cache misses and writebacks)
+ *
+ * ctr0: counts address valid cycles
+ * ctr1: counts *all* data valid cycles
+ * ctr2: is the overflow from counter 0
+ * ctr3: is the overflow from counter 1
+ */
+{
+0x0c01e000,00000000,0x00060000,00000000,
+0xefefefef,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0x0000000c,0x00003c00,0x07930000,0x0041e4c0,
+0x01002079,0x3000800c,0x1e4c0030,0x00279300,
+0x010049e4,0xc0014022,0x79300090,0x0c9e4c00,
+0x34004793,0x00020051,0xe4c00180,0x24793000,
+0xa00d1e4c,0x00380067,0x93000300,0x59e4c001,
+0xc0267930,0x00b00d9e,0x4c003fff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0xffff0000,00000000,0xf0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00100000,00000000,0xf0000000,00000000,
+00000000,00000000,0x98000000,00000000,
+0xffffffff,0xffffffff,0x0fffffff,0xffffffff,
+00000000,00000000,0x00ffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* rw_ifet (I-cache misses -- actually dumb READ transactions)
+ *
+ * ctr0: counts address valid cycles
+ * ctr1: counts *all* data valid cycles
+ * ctr2: is the overflow from counter 0
+ * ctr3: is the overflow from counter 1
+ */
+{
+0x0c01e000,00000000,0x00060000,00000000,
+0xefefefef,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0x0000000c,0x00003c00,0x07930000,0x0041e4c0,
+0x01002079,0x3000800c,0x1e4c0030,0x00279300,
+0x010049e4,0xc0014022,0x79300090,0x0c9e4c00,
+0x34004793,0x00020051,0xe4c00180,0x24793000,
+0xa00d1e4c,0x00380067,0x93000300,0x59e4c001,
+0xc0267930,0x00b00d9e,0x4c003fff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0xffff0000,00000000,0xf0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00100000,00000000,0xd0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0x00ffffff,0xffffffff,
+0xffffffff,0xffffffff,00000000,00000000,
+0xffffffff,0xffffffff },
+
+
+/* rw_sdfet (READ_SHARED_OR_PRIVATE transactions)
+ *
+ * ctr0: counts address valid cycles
+ * ctr1: counts *all* data valid cycles
+ * ctr2: is the overflow from counter 0
+ * ctr3: is the overflow from counter 1
+ */
+{
+0x0c01e000,00000000,0x00060000,00000000,
+0xefefefef,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0x0000000c,0x00003c00,0x07930000,0x0041e4c0,
+0x01002079,0x3000800c,0x1e4c0030,0x00279300,
+0x010049e4,0xc0014022,0x79300090,0x0c9e4c00,
+0x34004793,0x00020051,0xe4c00180,0x24793000,
+0xa00d1e4c,0x00380067,0x93000300,0x59e4c001,
+0xc0267930,0x00b00d9e,0x4c003fff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0xffff0000,00000000,0xf0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00100000,00000000,0xf4000000,00000000,
+00000000,00000000,00000000,00000000,
+0xffffffff,0xffffffff,0x00ffffff,0xffffffff,
+00000000,00000000,00000000,00000000,
+0xffffffff,0xffffffff },
+
+
+/* spec_ifet
+ *
+ * ICORE_AV fires for every request which the Instruction Fetch Unit sends
+ * to the Runway Interface Block. Hence, this counts all I-misses, speculative
+ * or not, but does *not* include I-cache prefetches, which are generated by
+ * RIB.
+ * IRTN_AV fires twice for every I-cache miss returning from RIB to the IFU.
+ * It will not fire if a second I-cache miss is issued from the IFU to RIB
+ * before the first returns. Therefore, if the IRTN_AV count is much less
+ * than 2x the ICORE_AV count, many speculative I-cache misses are occurring
+ * which are "discovered" to be incorrect fairly quickly.
+ * The ratio of I-cache miss transactions on Runway to the ICORE_AV count is
+ * a measure of the effectiveness of instruction prefetching. This ratio
+ * should be between 1 and 2. If it is close to 1, most prefetches are
+ * eventually called for by the IFU; if it is close to 2, almost no prefetches
+ * are useful and they are wasted bus traffic.
+ *
+ * ctr0: counts ICORE_AV
+ * ctr1: counts IRTN_AV
+ * ctr2: counts all non-coherent READ transactions on Runway. (TTYPE D0)
+ * This should be just I-cache miss and I-prefetch transactions.
+ * ctr3: counts total processor cycles
+ */
+{
+0x0c000000,00000000,0x00060000,00000000,
+0xefefefef,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0x0fffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0x00000008,0x00030c00,0x01bf0001,0x00806fc0,
+0x00c1001b,0xf0005048,0x06fc001c,0x2001bf00,
+0x0908806f,0xc002c300,0x1bf000d0,0xc806fc00,
+0x3fffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0x06bf0000,00000000,00000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00110000,00000000,0xd0ffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0x00ffffff,0xffffffff,
+0xffffffff,0xffffffff,00000000,00000000,
+0xffffffff,0xffffffff },
+
+/* st_cond0
+ *
+ * ctr0: is the overflow for ctr1
+ * ctr1: counts major ops 0C and 0E (fp ops, not fmac or fmpyadd)
+ * ctr2: counts B,L (including long and push) and GATE (including nullified),
+ * predicted not-taken
+ * ctr3: is the overflow for ctr2
+ */
+{
+0x4c01e000,00000000,0x00060000,00000000,
+0xe0e0c0e0,0xffffffff,0xffffffff,0xffc13380,
+0x0101ffff,0xffa1f057,0xe000407f,0xdfffc87f,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0xf0000060,0x00003c00,0x04f90000,0x02013e40,
+0x0081004f,0x90004060,0x13e40018,0x0024f900,
+0x0802093e,0x40028102,0x4f9000c0,0x6093e400,
+0x380014f9,0x00010205,0x3e4000c1,0x014f9000,
+0x506053e4,0x001c0034,0xf9000902,0x0d3e4002,
+0xc1034f90,0x00d060d3,0xe4003fff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0xffff0000,00000000,0xf0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* st_cond1
+ *
+ * ctr0: is the overflow for ctr1
+ * ctr1: counts major ops 1x (most of the load/stores)
+ * ctr2: counts CMPB (dw) predicted not-taken
+ * ctr3: is the overflow for ctr2
+ */
+{
+0x4c01e000,00000000,0x00060000,00000000,
+0xe0e0c0e0,0xffffffff,0xffffffff,0xffc01b80,
+0x0101ffff,0xffb7f03d,0xe000407f,0xffffc8ff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0xf0000060,0x00003c00,0x04f90000,0x02013e40,
+0x0081004f,0x90004060,0x13e40018,0x0024f900,
+0x0802093e,0x40028102,0x4f9000c0,0x6093e400,
+0x380014f9,0x00010205,0x3e4000c1,0x014f9000,
+0x506053e4,0x001c0034,0xf9000902,0x0d3e4002,
+0xc1034f90,0x00d060d3,0xe4003fff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0xffff0000,00000000,0xf0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* st_cond2
+ *
+ * ctr0: is the overflow for ctr1
+ * ctr1: counts major op 03
+ * ctr2: counts CMPIB (dw) predicted not taken.
+ * ctr3: is the overflow for ctr2
+ */
+{
+0x4c01e000,00000000,0x00060000,00000000,
+0xe0e0c0e0,0xffffffff,0xffffffff,0xffc09780,
+0x0101ffff,0xff21f077,0xe000407f,0xffffc87f,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0xf0000060,0x00003c00,0x04f90000,0x02013e40,
+0x0081004f,0x90004060,0x13e40018,0x0024f900,
+0x0802093e,0x40028102,0x4f9000c0,0x6093e400,
+0x380014f9,0x00010205,0x3e4000c1,0x014f9000,
+0x506053e4,0x001c0034,0xf9000902,0x0d3e4002,
+0xc1034f90,0x00d060d3,0xe4003fff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0xffff0000,00000000,0xf0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* st_cond3
+ *
+ * ctr0: is the overflow for ctr1
+ * ctr1: counts major ops 06 & 26
+ * ctr2: counts BB, BVB, MOVB, MOVIB (incl. nullified) predicted not-taken
+ * ctr3: is the overflow for ctr2
+ */
+{
+0x4c01e000,00000000,0x00060000,00000000,
+0xe0e0c0e0,0xffffffff,0xffffffff,0xffc03780,
+0x0101ffff,0xff29f016,0xe000407f,0xffffe97f,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0xf0000060,0x00003c00,0x04f90000,0x02013e40,
+0x0081004f,0x90004060,0x13e40018,0x0024f900,
+0x0802093e,0x40028102,0x4f9000c0,0x6093e400,
+0x380014f9,0x00010205,0x3e4000c1,0x014f9000,
+0x506053e4,0x001c0034,0xf9000902,0x0d3e4002,
+0xc1034f90,0x00d060d3,0xe4003fff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0xffff0000,00000000,0xf0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* st_cond4
+ *
+ * ctr0: is the overflow for ctr1
+ * ctr1: counts major op 2E
+ * ctr2: counts CMPB, CMPIB, ADDB, ADDIB (incl. nullified) predicted not-taken
+ * ctr3: is the overflow for ctr2
+ */
+{
+0x4c01e000,00000000,0x00060000,00000000,
+0xe0e0c0e0,0xffffffff,0xffffffff,0xffc17780,
+0x0101ffff,0xff21f014,0xe000407f,0xffffe9ff,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0xf0000060,0x00003c00,0x04f90000,0x02013e40,
+0x0081004f,0x90004060,0x13e40018,0x0024f900,
+0x0802093e,0x40028102,0x4f9000c0,0x6093e400,
+0x380014f9,0x00010205,0x3e4000c1,0x014f9000,
+0x506053e4,0x001c0034,0xf9000902,0x0d3e4002,
+0xc1034f90,0x00d060d3,0xe4003fff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0xffff0000,00000000,0xf0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* st_unpred0
+ *
+ * ctr0: is the overflow for ctr1
+ * ctr1: counts BE and BE,L
+ * ctr2: counts BE and BE,L including nullified
+ * ctr3: is the overflow for ctr2
+ */
+{
+0x4c01e000,00000000,0x00060000,00000000,
+0xe0c0c0e0,0xffffffff,0xffffffff,0xffdf5bbf,
+0xffffffff,0xff25f7d6,0xefffffff,0xffffc97f,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0xf0000060,0x00003c00,0x04f90000,0x02013e40,
+0x0081004f,0x90004060,0x13e40018,0x0024f900,
+0x0802093e,0x40028102,0x4f9000c0,0x6093e400,
+0x380014f9,0x00010205,0x3e4000c1,0x014f9000,
+0x506053e4,0x001c0034,0xf9000902,0x0d3e4002,
+0xc1034f90,0x00d060d3,0xe4003fff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0xffff0000,00000000,0xf0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* st_unpred1
+ *
+ * ctr0: is the overflow for ctr1
+ * ctr1: counts BLR, BV, BVE, BVE,L
+ * ctr2: counts BLR, BV, BVE, BVE,L including nullified
+ * ctr3: is the overflow for ctr2
+ */
+{
+0x4c01e000,00000000,0x00060000,00000000,
+0xe0c0c0e0,0xffffffff,0xffffffff,0xffc15f80,
+0x0501ff7f,0xff21f057,0xe001407f,0xdfffc87f,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0xf0000060,0x00003c00,0x04f90000,0x02013e40,
+0x0081004f,0x90004060,0x13e40018,0x0024f900,
+0x0802093e,0x40028102,0x4f9000c0,0x6093e400,
+0x380014f9,0x00010205,0x3e4000c1,0x014f9000,
+0x506053e4,0x001c0034,0xf9000902,0x0d3e4002,
+0xc1034f90,0x00d060d3,0xe4003fff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0xffff0000,00000000,0xf0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+/* unpred
+ *
+ * ctr0: counts non-nullified unpredictable branches
+ * ctr1: is the overflow for ctr0
+ * ctr2: counts all unpredictable branches (nullified or not)
+ * ctr3: is the overflow for ctr2
+ */
+{
+0xcc01e000,00000000,0x00060000,00000000,
+0x20202020,0xff31ffff,0xfff7fffe,0x97ffcc7f,
+0xfffffdff,0xffa5fff3,0x1fffffff,0x7fffe97f,
+0xffffffff,0xffffffff,0xff000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffff0000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xf0000000,
+0xf00000a0,0x00003c00,0x02f50000,0x0004bd40,
+0x0040802f,0x50002020,0x4bd4000c,0x0042f500,
+0x040014bd,0x40014084,0x2f500060,0x214bd400,
+0x1c2002f5,0x00080804,0xbd400242,0x802f5000,
+0xa0a04bd4,0x002c2042,0xf5000c08,0x14bd4003,
+0x42842f50,0x00e0a14b,0xd4003fff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xfffffc00,
+00000000,00000000,00000000,00000000,
+0xffff0000,00000000,0xf0000000,00000000,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xfffffc00,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xfffffc00,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xffffffff,0xf3ffffff,0xffffffff,
+0xfdffffff,0xffffffff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0xffffffff,0xfffff9ff,0xfe000000,00000000,
+0x00030000,00000000,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff,0xffffffff,0xffffffff,
+0xffffffff,0xffffffff },
+
+
+/* go_store
+ *
+ * ctr0: Overflow for counter 2
+ * ctr1: Overflow for counter 3
+ * ctr2: count of GO_STORE_E signal
+ * ctr3: count of GO_STORE_O signal
+ */
+
+ {
+ 0x0c00e000, 0x00000000, 0x00060000, 0x00000000,
+ 0xe0e0e0e0, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffa5ffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xff000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffff0000, 0x00000000, 0x7fffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xf0000000,
+ 0x00000000, 0x0000c000, 0x067c0000, 0x01019f00,
+ 0x00408067, 0xc0002030, 0x19f0000c, 0x000e7c00,
+ 0x0401039f, 0x00014080, 0xe7c00060, 0x3039f000,
+ 0x1c00167c, 0x00080105, 0x9f000240, 0x8167c000,
+ 0xa03059f0, 0x002c001e, 0x7c000c01, 0x079f0003,
+ 0x4081e7c0, 0x00e03079, 0xf0003fc0, 0x07fff800,
+ 0xf001fffe, 0x003c007f, 0xff800f00, 0x1fffe003,
+ 0xc007fff8, 0x00f001ff, 0xfe003c00, 0x7fff800f,
+ 0x001fffe0, 0x03c007ff, 0xf800f001, 0xfffe003c,
+ 0x007fff80, 0x0f001fff, 0xe003c007, 0xfff800f0,
+ 0x01fffe00, 0x3c007fff, 0x800f001f, 0xffe00000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x70130000, 0x00000000, 0x70000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xfffffc00, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xfffffc00, 0x00000000,
+ 0xffffaaaa, 0xffffffff, 0xf3ffffff, 0xffffffff,
+ 0xfdffffff, 0xffffffff, 0xfe000000, 0x00000000,
+ 0xffffaaaa, 0xffffffff, 0xf3ffffff, 0xffffffff,
+ 0xfdffffff, 0xffffffff, 0xfe000000, 0x00000000,
+ 0xffffffff, 0xfffff9ff, 0xfe000000, 0x00000000,
+ 0xffffffff, 0xfffff9ff, 0xfe000000, 0x00000000,
+ 0x00030000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff
+ },
+
+
+/* shlib_call
+ *
+ * ctr0: SharedLib call Depth1
+ * ctr1: SharedLib call Depth2
+ * ctr2: SharedLib call Depth3
+ * ctr3: SharedLib call Depth>3
+ */
+ {
+ 0x0c01e000, 0x00000000, 0x00060000, 0x00000000,
+ 0xe0e0e0e0, 0xc76fa005, 0x07dd7e9c, 0x87115b80,
+ 0x01100200, 0x07200004, 0xe000407f, 0xfffffffc,
+ 0x01380010, 0x1fffffff, 0xff000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffff0000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xf0000000,
+ 0xf0000000, 0x00003c20, 0x01ff0808, 0x04007fc0,
+ 0x0003001f, 0xf0000180, 0x07fc4010, 0x5001ff00,
+ 0x001c007f, 0xc2000a00, 0x1ff18022, 0x4007fc20,
+ 0x00b001ff, 0x10003800, 0x7fc8004d, 0x001ff100,
+ 0x03c007fc, 0x60012001, 0xff280144, 0x007fc600,
+ 0x13001ff2, 0x00058007, 0xfcc00550, 0x01ff2000,
+ 0x5c007fca, 0x001a001f, 0xf3801640, 0x07fca001,
+ 0xb001ff30, 0x0078007f, 0xd0005d00, 0x1ff30007,
+ 0xc007fce0, 0x022001ff, 0x48018400, 0x7fce0023,
+ 0x001ff400, 0x098007fd, 0x20065001, 0xff40009c,
+ 0x007fd200, 0x3fffffff, 0x800fffff, 0xffe00000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0xffff0000, 0x00000000, 0xf0000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xfffffc00, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xfffffc00, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xf3ffffff, 0xffffffff,
+ 0xfdffffff, 0xffffffff, 0xfe000000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xf3ffffff, 0xffffffff,
+ 0xfdffffff, 0xffffffff, 0xfe000000, 0x00000000,
+ 0xffffffff, 0xfffff9ff, 0xfe000000, 0x00000000,
+ 0xffffffff, 0xfffff9ff, 0xfe000000, 0x00000000,
+ 0x00030000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff
+ }
+};
+#define PCXW_IMAGE_SIZE 576
+
+static uint32_t cuda_images[][PCXW_IMAGE_SIZE/sizeof(uint32_t)] __ro_after_init = {
+/*
+ * CPI: FROM CPI.IDF (Image 0)
+ *
+ * Counts the following:
+ *
+ * ctr0 : total cycles
+ * ctr1 : total cycles where nothing retired
+ * ctr2 : total instructions retired, including nullified
+ * ctr3 : total instructions retired, less nullified instructions
+ */
+ {
+ 0x4c00c000, 0x00000000, 0x00060000, 0x00000000,
+ 0xe0e0e0e0, 0x00001fff, 0xfc00007f, 0xfff00001,
+ 0xffffc000, 0x07ffff00, 0x07ffffff, 0x6007ffff,
+ 0xff0007ff, 0xffff0007, 0xffffff00, 0x00000000,
+ 0x60f00000, 0x0fffff00, 0x000fffff, 0x00000fff,
+ 0xff00000f, 0xffff0000, 0x00000000, 0x00ffffff,
+ 0xfffff000, 0x0000000f, 0xffffffff, 0xff000000,
+ 0x0000ffff, 0xfffffff0, 0x00000000, 0x0fffffff,
+ 0xffff0000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00270000, 0x00000055,
+ 0x0200000e, 0x4d300000, 0x00000000, 0x0ff00002,
+ 0x70000000, 0x00000020, 0x0000e400, 0x00000ff0,
+ 0x00000000, 0x00000000, 0x00000055, 0xffffff00,
+ 0x00000000, 0x0000ff00, 0x00000000, 0x0f000000,
+ 0x0000055f, 0xfffff000, 0x00000000, 0x000ff000,
+ 0x00000000, 0x00000000, 0x000055ff, 0xffff0000,
+ 0x00000000, 0x00ff0000, 0x00000000, 0xf0000000,
+ 0x000055ff, 0xffff0000, 0x00000000, 0x00ff0000,
+ 0x00000000, 0x00000000, 0x00055fff, 0xfff00000,
+ 0x00000000, 0x0ff00000, 0x00000030, 0x00000000,
+ 0x00157fff, 0xffc00000, 0x034c0000, 0x00000000,
+ 0x03fc0000, 0x00000000, 0x6fff0000, 0x00000000,
+ 0x60000000, 0x00000000, 0x00ffffff, 0xff3fffff,
+ 0xffffffff, 0xffcfffff, 0xfff7fbfc, 0x00000000,
+ 0x00ffffff, 0xff3fffff, 0xffffffff, 0xffcfffff,
+ 0xfff7fbfc, 0x00000000, 0xffffafff, 0xffffff3f,
+ 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+ 0x00000000, 0x00000000, 0xffffafff, 0xffffff3f,
+ 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+ 0x00000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+ 0xfe000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+ 0xfe000000, 0x00000000, 0x00030000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ },
+
+/* Bus utilization image FROM BUS_UTIL.IDF (Image 1)
+ *
+ * ctr0 : counts address valid cycles
+ * ctr1 : counts data valid cycles
+ * ctr2 : counts overflow from counter 0
+ * ctr3 : counts overflow from counter 1
+ */
+ {
+ 0x0c01e000, 0x00000000, 0x00060000, 0x00000000,
+ 0xefefefef, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffff00, 0x00000000,
+ 0xf0ffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffff0000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffff0000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00001b00, 0xaa000000,
+ 0x00000001, 0x30700000, 0x00055aaf, 0xf0000000,
+ 0x01b00000, 0x00000000, 0x00001037, 0x00000000,
+ 0x55aaff00, 0x00c00000, 0x1b55aa00, 0x00000000,
+ 0x0001fff0, 0xcfffff00, 0x00000000, 0x0f0fffff,
+ 0xffffffff, 0xffffffff, 0x30ffff0c, 0xfffff000,
+ 0x00000000, 0x00ffffff, 0xffffffff, 0xfffffff3,
+ 0x0ffff0cf, 0xffff0000, 0x00000000, 0x00ffffff,
+ 0xffffffff, 0xfffffff3, 0x0ffff0cf, 0xffff0000,
+ 0x00000000, 0x0fffffff, 0xffffffff, 0xffffff30,
+ 0xfff70000, 0x000055aa, 0xff000000, 0x000006d5,
+ 0x40000000, 0x00000000, 0x731c0000, 0x000156ab,
+ 0xfc000000, 0x00000000, 0xffff0000, 0x00000000,
+ 0xf0000000, 0x00000000, 0x00ffffff, 0xff3fffff,
+ 0xffffffff, 0xffcfffff, 0xfff7fbfc, 0x00000000,
+ 0x00ffffff, 0xff3fffff, 0xffffffff, 0xffcfffff,
+ 0xfff7fbfc, 0x00000000, 0xffffffff, 0xffffff3f,
+ 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffff3f,
+ 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+ 0x00000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+ 0xfe000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+ 0xfe000000, 0x00000000, 0x00100000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ },
+
+/*
+ * TLB counts: FROM TLBSTATS.IDF (Image 2)
+ *
+ * Counts the following:
+ *
+ * ctr0: DTLB misses
+ * ctr1: ITLB misses
+ * ctr2: total cycles in the miss handlers
+ * ctr3: total cycles
+ */
+
+ {
+ 0x0c00c000, 0x00000000, 0x00060000, 0x00000000,
+ 0xe7e7e0e0, 0x00001fff, 0xfc00007f, 0xfff00001,
+ 0xfff00000, 0x07ffff00, 0x07ffffff, 0x6007ffff,
+ 0xa00007ff, 0xffff0007, 0xffffff00, 0x00000000,
+ 0x603001c1, 0xe0000001, 0xc0c00000, 0x00000fff,
+ 0xff00000f, 0xffff0000, 0x00000000, 0x00400000,
+ 0x00001000, 0x00000004, 0x00000000, 0x01000000,
+ 0x0000ffff, 0xfffffff0, 0x00000000, 0x0fffffff,
+ 0xffff0000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00800000, 0x00153f7f,
+ 0x55000000, 0xaf800000, 0xc0000000, 0x0403f240,
+ 0x00000000, 0x00001010, 0x00004700, 0x00000ff0,
+ 0x00000000, 0x00000000, 0x00000055, 0xffffff00,
+ 0x00000000, 0x0000ff00, 0x00000000, 0x0f000000,
+ 0x0000055f, 0xfffff000, 0x00000000, 0x000ff000,
+ 0x00000000, 0x00000000, 0x000055ff, 0xffff0000,
+ 0x00000000, 0x00ff0000, 0x00000000, 0xf0000000,
+ 0x000055ff, 0xffff0000, 0x00000000, 0x00ff0000,
+ 0x00000000, 0x00000000, 0x00055fff, 0xfff00000,
+ 0x00000000, 0x0ff00000, 0x00000000, 0x00000000,
+ 0x00157fff, 0xffc00000, 0x00000000, 0x3fc00000,
+ 0x00040000, 0x00000000, 0x6fff0000, 0x00000000,
+ 0x60000000, 0x00000000, 0x00ffffff, 0xff3fffff,
+ 0xffffffff, 0xffcfffff, 0xfff7fbfc, 0x00000000,
+ 0x00ffffff, 0xff3fffff, 0xffffffff, 0xffcfffff,
+ 0xfff7fbfc, 0x00000000, 0xffffafff, 0xffffff3f,
+ 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+ 0x00000000, 0x00000000, 0xffffafff, 0xffffff3f,
+ 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+ 0x00000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+ 0xfe000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+ 0xfe000000, 0x00000000, 0x00030000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ },
+
+/* tlbhandler FROM tlbHandMiss.idf (Image 3)
+ *
+ * ctr0: TLB misses
+ * ctr1: dmisses inside the TLB miss handler
+ * ctr2: cycles in the TLB miss handler
+ * ctr3: overflow of ctr2
+ */
+ {
+ 0x1c00c000, 0x00000000, 0x00060000, 0x00000000,
+ 0xe7e7e0e0, 0x00001fff, 0xfc00007f, 0xfff00001,
+ 0xfff00000, 0x07ffff00, 0x07ffffff, 0x6007ffff,
+ 0xa00007ff, 0xffff0007, 0xffffff00, 0x00000000,
+ 0x603001c1, 0xe0000001, 0xc0c00000, 0x00000fff,
+ 0xff00000f, 0xffff0000, 0x00000000, 0x00400000,
+ 0x00001000, 0x00000004, 0x00000000, 0x01000000,
+ 0x0000ffff, 0xfffffff0, 0x00000000, 0x0fffffff,
+ 0xffff0000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x006c0000, 0x01000054,
+ 0x02000002, 0xc3200000, 0xc00aa000, 0x0c03f240,
+ 0x00000000, 0x00001010, 0x000044f4, 0x00000c00,
+ 0xaa0000f0, 0x0f0000b0, 0x00005005, 0x0f5f0000,
+ 0x0001f000, 0x0000ff00, 0x00000000, 0x0f000000,
+ 0x0000055f, 0xfffff000, 0x00000000, 0x000ff000,
+ 0x00000000, 0x00000000, 0x000055ff, 0xffff0000,
+ 0x00000000, 0x00ff0000, 0x00000000, 0xf0000000,
+ 0x000055ff, 0xffff0000, 0x00000000, 0x00ff0000,
+ 0x00000000, 0x00000000, 0x00055fff, 0xfff00000,
+ 0x00000000, 0x0ff00a00, 0x000f0000, 0x24004000,
+ 0x15400001, 0x40c00003, 0x3da00000, 0x0002a800,
+ 0x00ff0000, 0x00000000, 0x6fff0000, 0x00000000,
+ 0x60000000, 0x00000000, 0x00ffffff, 0xff3fffff,
+ 0xffffffff, 0xffcfffff, 0xfff7fbfc, 0x00000000,
+ 0x00ffffff, 0xff3fffff, 0xffffffff, 0xffcfffff,
+ 0xfff7fbfc, 0x00000000, 0xffffafff, 0xffffff3f,
+ 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+ 0x00000000, 0x00000000, 0xffffafff, 0xffffff3f,
+ 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+ 0x00000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+ 0xfe000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+ 0xfe000000, 0x00000000, 0x00030000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ },
+
+/* branch_taken image FROM PTKN.IDF (Image 4)
+ *
+ * ctr0: mispredicted branches
+ * ctr1: predicted taken branches, actually taken
+ * ctr2: predicted taken branches (includes nullfied)
+ * ctr3: all branches
+ */
+
+ {
+ 0xcc01e000, 0x00000000, 0x00000000, 0x00000000,
+ 0xa08080a0, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xfffffeff, 0xfffeffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffff00, 0x00000000,
+ 0xf4ffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffff0000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffff0000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xd22d0000, 0x00000000,
+ 0x0000000b, 0x46000000, 0x00000000, 0x0ffff900,
+ 0x90000000, 0x00000000, 0x0000907e, 0x00000000,
+ 0x000000ff, 0xff00bfdf, 0x03030303, 0x03030000,
+ 0x000dbfff, 0xffffff00, 0x00000000, 0x0f0fffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xfffff000,
+ 0x00000000, 0x00ffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffff0000, 0x00000000, 0xf0ffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0000,
+ 0x00000000, 0x0fffffff, 0xffffffff, 0xffffffff,
+ 0xffff5555, 0x55500000, 0x003f3ff0, 0x2766c000,
+ 0x00000000, 0x00000002, 0x67840000, 0x00000000,
+ 0x03fffc00, 0x00000000, 0xffff0000, 0x00000000,
+ 0xf0000000, 0x00000000, 0x00ffffff, 0xff3fffff,
+ 0xffffffff, 0xffcfffff, 0xfff7fbfc, 0x00000000,
+ 0x00ffffff, 0xff3fffff, 0xffffffff, 0xffcfffff,
+ 0xfff7fbfc, 0x00000000, 0xffffffff, 0xffffff3f,
+ 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffff3f,
+ 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+ 0x00000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+ 0xfe000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+ 0xfe000000, 0x00000000, 0x00030000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ },
+
+/* branch_nottaken FROM PNTKN.IDF (Image 5)
+ *
+ * ctr0: mispredicted branches
+ * ctr1: branches predicted not-taken, but actually taken
+ * ctr2: branches predicted not-taken (includes nullified)
+ * ctr3: all branches
+ */
+ {
+ 0xcc01e000, 0x00000000, 0x00000000, 0x00000000,
+ 0xe0c0c0e0, 0xffffffff, 0xffffffff, 0xffefffff,
+ 0xffffbfff, 0xfffffeff, 0xfffeffff, 0xfffffeff,
+ 0xfffffffe, 0xffffffff, 0xffffff00, 0x00000000,
+ 0xf4ffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffff0000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffff0000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xd22d0000, 0x00000000,
+ 0x0000000b, 0x46000000, 0x00000000, 0x0ffff900,
+ 0x90000000, 0x00000000, 0x0000907e, 0x00000000,
+ 0x000000ff, 0xff00bfdf, 0x03030303, 0x03030000,
+ 0x000dbfff, 0xffffff00, 0x00000000, 0x0f0fffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xfffff000,
+ 0x00000000, 0x00ffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffff0000, 0x00000000, 0xf0ffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0000,
+ 0x00000000, 0x0fffffff, 0xffffffff, 0xffffffff,
+ 0xffff5555, 0x55500000, 0x003f3ff0, 0x2766c000,
+ 0x00000000, 0x00000002, 0x67840000, 0x00000000,
+ 0x03fffc00, 0x00000000, 0xffff0000, 0x00000000,
+ 0xf0000000, 0x00000000, 0x00ffffff, 0xff3fffff,
+ 0xffffffff, 0xffcfffff, 0xfff7fbfc, 0x00000000,
+ 0x00ffffff, 0xff3fffff, 0xffffffff, 0xffcfffff,
+ 0xfff7fbfc, 0x00000000, 0xffffffff, 0xffffff3f,
+ 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffff3f,
+ 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+ 0x00000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+ 0xfe000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+ 0xfe000000, 0x00000000, 0x00030000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ },
+
+/* IMISS image (Image 6)
+ *
+ * ctr0 : icache misses for retired instructions
+ * ctr1 : total cycles
+ * ctr2 : dcache misses for retired instructions
+ * ctr3 : number of retired instructions
+ */
+ {
+ 0x2801e000, 0x00000000, 0x00010000, 0x00000000,
+ 0x00001000, 0xffffffff, 0xffffffff, 0xfff00fff,
+ 0xfffa3fff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffff00, 0x00000000,
+ 0xf0ffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffff0000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffff0000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xf2fdf0f0, 0xf0f0f0f0,
+ 0xffffffff, 0xf6c00000, 0x00000000, 0x0ff55800,
+ 0x90000000, 0x00000000, 0x0000b0ff, 0xfffffff0,
+ 0x00000003, 0x0100bfff, 0x3f3f3f3f, 0x3f3f5555,
+ 0x555fffff, 0xffffff00, 0x00000000, 0x000fffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xfffff000,
+ 0x00000000, 0x00ffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffff0000, 0x00000000, 0xf0ffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0000,
+ 0x00000000, 0x0fffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xfff00000, 0x000301b0, 0x2fefcfcf,
+ 0xcfcfcfcf, 0xd5555557, 0xf7b40000, 0x00000000,
+ 0x03c14000, 0x00000000, 0xffff0000, 0x00000000,
+ 0xf0000000, 0x00000000, 0x00ffffff, 0xff3fffff,
+ 0xffffffff, 0xffcfffff, 0xfff6fb7c, 0x00000000,
+ 0x00ffffff, 0xff3fffff, 0xffffffff, 0xffcfffff,
+ 0xfff6fb7c, 0x00000000, 0xffff0fff, 0xffffff3f,
+ 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+ 0x00000000, 0x00000000, 0xffff0fff, 0xffffff3f,
+ 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+ 0x00000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+ 0xfe000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+ 0xfe000000, 0x00000000, 0x00130000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ },
+
+/* DMISS image (Image 7)
+ *
+ * ctr0 : icache misses for retired instructions
+ * ctr1 : total cycles
+ * ctr2 : dcache misses for retired instructions
+ * ctr3 : number of retired instructions
+ */
+ {
+ 0x2801e000, 0x00000000, 0x00010000, 0x00000000,
+ 0x00001000, 0xffffffff, 0xffffffff, 0xfff00fff,
+ 0xfffa3fff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffff00, 0x00000000,
+ 0xf0ffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffff0000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffff0000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xf2fdf0f0, 0xf0f0f0f0,
+ 0xffffffff, 0xf6c00000, 0x00000000, 0x0ff55800,
+ 0x90000000, 0x00000000, 0x0000b0ff, 0xfffffff0,
+ 0x00000003, 0x0100bfff, 0x3f3f3f3f, 0x3f3f5555,
+ 0x555fffff, 0xffffff00, 0x00000000, 0x000fffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xfffff000,
+ 0x00000000, 0x00ffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffff0000, 0x00000000, 0xf0ffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0000,
+ 0x00000000, 0x0fffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xfff00000, 0x000301b0, 0x2fefcfcf,
+ 0xcfcfcfcf, 0xd5555557, 0xf7b40000, 0x00000000,
+ 0x03c14000, 0x00000000, 0xffff0000, 0x00000000,
+ 0xf0000000, 0x00000000, 0x00ffffff, 0xff3fffff,
+ 0xffffffff, 0xffcfffff, 0xfff6fb7c, 0x00000000,
+ 0x00ffffff, 0xff3fffff, 0xffffffff, 0xffcfffff,
+ 0xfff6fb7c, 0x00000000, 0xffff0fff, 0xffffff3f,
+ 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+ 0x00000000, 0x00000000, 0xffff0fff, 0xffffff3f,
+ 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+ 0x00000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+ 0xfe000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+ 0xfe000000, 0x00000000, 0x00130000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ },
+
+/* dmiss_access image FROM DMISS_RATIO.IDF (Image 8)
+ *
+ * ctr0 : all loads and stores that retire (even lines)
+ * ctr1 : all loads and stores that retire (odd lines)
+ * ctr2 : dcache misses of retired loads/stores
+ * ctr3 : all READ_PRIV and READ_SHAR_OR_PRIV on Runway
+ * (Speculative and Non-Speculative)
+ */
+ {
+ 0x2d81e000, 0x00000000, 0x00000000, 0x00000000,
+ 0x10101010, 0x00ffffff, 0xa003ffff, 0xfe800fff,
+ 0xfffa003f, 0xffffe8ff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffff00, 0x00000000,
+ 0xf0ffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffff0000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffff0000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xd2280a00, 0x00000000,
+ 0x0000000b, 0x46000000, 0x00000005, 0x555ff900,
+ 0x80200000, 0x00000000, 0x0000907e, 0x00000000,
+ 0x00005555, 0xff80bf8b, 0xab030303, 0x03030000,
+ 0x000dbfff, 0xffffff00, 0x00000000, 0x000fffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xfffff000,
+ 0x00000000, 0x00ffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffff0000, 0x00000000, 0xf0ffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0000,
+ 0x00000000, 0x0fffffff, 0xffffffff, 0xffffffff,
+ 0xffff5555, 0x55500000, 0x15153fe0, 0x27628880,
+ 0x00000000, 0x00000002, 0x67840000, 0x00000001,
+ 0x5557fc00, 0x00000000, 0xffff0000, 0x00000000,
+ 0xf0000000, 0x00000000, 0x00ffffff, 0xff3fffff,
+ 0xffffffff, 0xffcfffff, 0xfff6fb7c, 0x00000000,
+ 0x00ffffff, 0xff3fffff, 0xffffffff, 0xffcfffff,
+ 0xfff6fb7c, 0x00000000, 0xffff0fff, 0xffffff3f,
+ 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+ 0x00000000, 0x00000000, 0xffff0fff, 0xffffff3f,
+ 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+ 0x00000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+ 0xfe000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+ 0xfe000000, 0x00000000, 0x00110000, 0x00000000,
+ 0xf4ffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xf8ffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0x00ffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0x00ffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ },
+
+
+/* big_cpi image (Image 9)
+ *
+ * ctr0 : Total number of CPU clock cycles.
+ * ctr1 : Unused
+ * ctr2 : Unused
+ * ctr3 : Total number of Non-Nullified instructions retired.
+ */
+ {
+ 0x0c00c000, 0x00000000, 0x00060000, 0x00000000,
+ 0xe7e7e0e0, 0x00001fff, 0xfc00007f, 0xfff00001,
+ 0xfff00000, 0x07ffff00, 0x07ffffff, 0x6007ffff,
+ 0xa00007ff, 0xffff0007, 0xffffff00, 0x00000000,
+ 0x603001c1, 0xe0000001, 0xc0c00000, 0x00000fff,
+ 0xff00000f, 0xffff0000, 0x00000000, 0x00400000,
+ 0x00001000, 0x00000004, 0x00000000, 0x01000000,
+ 0x0000ffff, 0xfffffff0, 0x00000000, 0x0fffffff,
+ 0xffff0000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00550005, 0x00220000,
+ 0x0000000c, 0x71f00000, 0x00f00aa0, 0x0aaff000,
+ 0x00005002, 0x20000000, 0x0000c413, 0x00000c0f,
+ 0x00aa0000, 0xff00b600, 0x000500a0, 0x00000300,
+ 0x000cc3f0, 0x0000c0f0, 0x0aa0000f, 0xff000000,
+ 0x011000a0, 0x05503000, 0x00d03700, 0x00000f00,
+ 0xaa005500, 0x00000000, 0x000055ff, 0xffff0000,
+ 0x00000000, 0x00ff0000, 0x00000000, 0xf000aa00,
+ 0x11000a00, 0x55000000, 0x0d037000, 0x00c0f00a,
+ 0xa0055000, 0x0db00005, 0x5002a000, 0x00300000,
+ 0xf40f0000, 0x0c0f00aa, 0x0000ff10, 0x27400000,
+ 0x00008000, 0x00c00003, 0x037c0000, 0x003c02a8,
+ 0x02abfc00, 0x00000000, 0x6fff0000, 0x00000000,
+ 0x60000000, 0x00000000, 0x00ffffff, 0xff3fffff,
+ 0xffffffff, 0xffcfffff, 0xfff7fbfc, 0x00000000,
+ 0x00ffffff, 0xff3fffff, 0xffffffff, 0xffcfffff,
+ 0xfff7fbfc, 0x00000000, 0xffffafff, 0xffffff3f,
+ 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+ 0x00000000, 0x00000000, 0xffffafff, 0xffffff3f,
+ 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+ 0x00000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+ 0xfe000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+ 0xfe000000, 0x00000000, 0x00030000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ },
+
+/* big_ls image (Image 10)
+ *
+ * ctr0 : Total number of CPU clock cycles during which local_stall_A1 is asserted
+ * ctr1 : Overflow of Counter 0
+ * ctr2 : Total number of IFLUSH_AV
+ * ctr3 : Overflow of Counter 2
+ */
+ {
+ 0x0c000000, 0x00000000, 0x00060000, 0x00000000,
+ 0xefefefef, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffff00, 0x00000000,
+ 0x00ffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffff0000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffff0000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x28880001, 0x54000000,
+ 0x00000004, 0xb6200000, 0x000aaaa0, 0x05555288,
+ 0x80000010, 0x00000000, 0x0000486e, 0x00000000,
+ 0xaaaa0055, 0x55002888, 0x00545401, 0x03030000,
+ 0x0007b000, 0x0000ff00, 0x00000000, 0x05000000,
+ 0x0000055f, 0xfffff000, 0x00000000, 0x000ff000,
+ 0x00000000, 0x00000000, 0x000055ff, 0xffff0000,
+ 0x00000000, 0x00ff0000, 0x00000000, 0x00000000,
+ 0x000055ff, 0xffff0000, 0x00000000, 0x00ff0000,
+ 0x00000000, 0xa0000000, 0x00055fff, 0xfff00000,
+ 0x00aa0000, 0x05502a2a, 0x00151500, 0x0a220015,
+ 0x40400000, 0x00000001, 0xe2980000, 0x0002aaa8,
+ 0x01555400, 0x00000000, 0x0df70000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00ffffff, 0xff3fffff,
+ 0xffffffff, 0xffcfffff, 0xfff7fbfc, 0x00000000,
+ 0x00ffffff, 0xff3fffff, 0xffffffff, 0xffcfffff,
+ 0xfff7fbfc, 0x00000000, 0xffffffff, 0xffffff3f,
+ 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffff3f,
+ 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+ 0x00000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+ 0xfe000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+ 0xfe000000, 0x00000000, 0x00030000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ },
+
+/* br_abort image (Image 12)
+ *
+ * ctr0 : Total number of BRAD_STALLH
+ * ctr1 : Total number of ONE_QUAD
+ * ctr2 : Total number of BR0_ABRT
+ * ctr3 : Total number of BR1_ABRT
+ */
+
+ {
+ 0x0c002000, 0x00000000, 0x00060000, 0x00000000,
+ 0xe0e0e0e0, 0xffffffff, 0xffffffff, 0xff0fffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffff00, 0x00000000,
+ 0x1077ffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffff0000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffff0000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x551b0000, 0x00000000,
+ 0x0000000c, 0xd4f00000, 0x00000000, 0x0ffff001,
+ 0xb0000000, 0x00000000, 0x0000fd4c, 0x00000000,
+ 0x000000ff, 0xff00ff1b, 0x00000000, 0x00000000,
+ 0x0000d000, 0x0000ff00, 0x00000000, 0x0e0fffff,
+ 0xffffffff, 0xfffff000, 0x00000000, 0x000ff000,
+ 0x00000000, 0x00ffffff, 0xffffffff, 0xffff0000,
+ 0x00000000, 0x00ff0000, 0x00000000, 0x00ffffff,
+ 0xffffffff, 0xffff0000, 0x00000000, 0x00ff0000,
+ 0x00000000, 0xffffffff, 0xffffffff, 0xfff00000,
+ 0x00400000, 0x00000000, 0x00ffff00, 0x2a86c000,
+ 0x00000000, 0x00000000, 0xf50c0000, 0x00000000,
+ 0x03fffc00, 0x00000000, 0x1a250000, 0x00000000,
+ 0x10000000, 0x00000000, 0x00ffffff, 0xff3fffff,
+ 0xffffffff, 0xffcfffff, 0xfff7fbfc, 0x00000000,
+ 0x00ffffff, 0xff3fffff, 0xffffffff, 0xffcfffff,
+ 0xfff7fbfc, 0x00000000, 0xffffafff, 0xffffff3f,
+ 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+ 0x00000000, 0x00000000, 0xffffafff, 0xffffff3f,
+ 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+ 0x00000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+ 0xfe000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+ 0xfe000000, 0x00000000, 0x00030000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ },
+
+
+/* isnt image (Image 13)
+ *
+ * ctr0 : Total number of cycles for which iside_notrans is asserted.
+ * ctr1 : Total number of times iside_notrans is asserted for 1-4 cycles.
+ * ctr2 : Total number of times iside_notrans is asserted for 5-7 cycles.
+ * ctr3 : Total number of times iside_notrans is asserted for > 7 cycles.
+ */
+
+ {
+ 0x0c018000, 0x00000000, 0x00060000, 0x00000000,
+ 0xefefefef, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffff00, 0x00000000,
+ 0xc0ffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffff0000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffff0000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x22000000, 0x000001bc,
+ 0x10000006, 0x00900000, 0x50000000, 0x00055a20,
+ 0x00000000, 0x00016060, 0x0000c021, 0x00000540,
+ 0x00000000, 0x55002200, 0x00000000, 0x56bc4000,
+ 0x00048000, 0x0000ff00, 0x00000000, 0x17000000,
+ 0x0000055f, 0xfffff000, 0x00000000, 0x000ff000,
+ 0x00000000, 0x00000000, 0x000055ff, 0xffff0000,
+ 0x00000000, 0x00ff0000, 0x00000000, 0x00000000,
+ 0x000055ff, 0xffff0000, 0x00000000, 0x00ff0000,
+ 0x00000000, 0x80000000, 0x00015bf3, 0xf5500000,
+ 0x02210000, 0x00100000, 0x00005500, 0x08800000,
+ 0x00001545, 0x85000001, 0x80240000, 0x11000000,
+ 0x00015400, 0x00000000, 0xcdff0000, 0x00000000,
+ 0xc0000000, 0x00000000, 0x00ffffff, 0xff3fffff,
+ 0xffffffff, 0xffcfffff, 0xfff7fbfc, 0x00000000,
+ 0x00ffffff, 0xff3fffff, 0xffffffff, 0xffcfffff,
+ 0xfff7fbfc, 0x00000000, 0xffffffff, 0xffffff3f,
+ 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffff3f,
+ 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+ 0x00000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+ 0xfe000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+ 0xfe000000, 0x00000000, 0x00030000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ },
+
+/* quadrant image (image 14)
+ *
+ * ctr0 : Total number of instructions in quadrant 0.
+ * ctr1 : Total number of instructions in quadrant 1.
+ * ctr2 : Total number of instructions in quadrant 2.
+ * ctr3 : Total number of instructions in quadrant 3.
+ *
+ * Only works for 32-bit applications.
+ */
+
+ {
+ 0x0c01e000, 0x00000000, 0x00060000, 0x00000000,
+ 0xe0e0e0e0, 0x00001fff, 0xfc00007f, 0xfff00001,
+ 0xffffc000, 0x07ffff00, 0x07ffffff, 0x0007ffff,
+ 0xff0007ff, 0xffff0007, 0xffffff00, 0x00000000,
+ 0xf0000000, 0x0fffff00, 0x000fffff, 0x00000fff,
+ 0xff00000f, 0xffff0000, 0x00000000, 0x00ffffff,
+ 0xffcff000, 0x0000040f, 0xfffffffc, 0xff000000,
+ 0x0080ffff, 0xffffcff0, 0x0000000c, 0x0fffffff,
+ 0xfcff0000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x551b0000, 0x00000000,
+ 0x00000003, 0x17000000, 0x00000000, 0x0ffff001,
+ 0xb0000000, 0x00000000, 0x00000173, 0x00000000,
+ 0x000000ff, 0xff00ff1b, 0x00000000, 0x00000000,
+ 0x000f1ff0, 0xcfffff00, 0x00000000, 0x0f0fffff,
+ 0xffffffff, 0xffffffff, 0x30ffff0c, 0xfffff000,
+ 0x00000000, 0x00ffffff, 0xffffffff, 0xfffffff3,
+ 0x0ffff0cf, 0xffff0000, 0x00000000, 0xf0ffffff,
+ 0xffffffff, 0xfffffff3, 0x0ffff0cf, 0xffff0000,
+ 0x00000000, 0x0fffffff, 0xffffffff, 0xffffff30,
+ 0xff7f0000, 0x00000000, 0x00fffff0, 0x2a86c000,
+ 0x00000000, 0x00000003, 0x05f00000, 0x00000000,
+ 0x03fffc00, 0x00000000, 0xffff0000, 0x00000000,
+ 0xf0000000, 0x00000000, 0x00ffffff, 0xff3fffff,
+ 0xffffffff, 0xffcfffff, 0xfff7fbfc, 0x00000000,
+ 0x00ffffff, 0xff3fffff, 0xffffffff, 0xffcfffff,
+ 0xfff7fbfc, 0x00000000, 0xffffffff, 0xffffff3f,
+ 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffff3f,
+ 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+ 0x00000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+ 0xfe000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+ 0xfe000000, 0x00000000, 0x00030000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ },
+
+/* rw_pdfet image (Image 15)
+ *
+ * ctr0 : Total of all READ_PRIV address valid cycles.
+ * ctr1 : Total of all READ_PRIV data valid cycles.
+ * ctr2 : Overflow of Counter 0.
+ * ctr3 : Overflow of Counter 1.
+ */
+
+ {
+ 0x0c01e000, 0x00000000, 0x00060000, 0x00000000,
+ 0xefefefef, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffff00, 0x00000000,
+ 0xf0ffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffff0000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffff0000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00001b00, 0xaa000000,
+ 0x00000001, 0x30700000, 0x00055aaf, 0xf0000000,
+ 0x01b00000, 0x00000000, 0x00001037, 0x00000000,
+ 0x55aaff00, 0x00c00000, 0x1b55aa00, 0x00000000,
+ 0x0001fff0, 0xcfffff00, 0x00000000, 0x0f0fffff,
+ 0xffffffff, 0xffffffff, 0x30ffff0c, 0xfffff000,
+ 0x00000000, 0x00ffffff, 0xffffffff, 0xfffffff3,
+ 0x0ffff0cf, 0xffff0000, 0x00000000, 0x00ffffff,
+ 0xffffffff, 0xfffffff3, 0x0ffff0cf, 0xffff0000,
+ 0x00000000, 0x0fffffff, 0xffffffff, 0xffffff30,
+ 0xfff70000, 0x000055aa, 0xff000000, 0x000006d5,
+ 0x40000000, 0x00000000, 0x731c0000, 0x000156ab,
+ 0xfc000000, 0x00000000, 0xffff0000, 0x00000000,
+ 0xf0000000, 0x00000000, 0x00ffffff, 0xff3fffff,
+ 0xffffffff, 0xffcfffff, 0xfff7fbfc, 0x00000000,
+ 0x00ffffff, 0xff3fffff, 0xffffffff, 0xffcfffff,
+ 0xfff7fbfc, 0x00000000, 0xffffffff, 0xffffff3f,
+ 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffff3f,
+ 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+ 0x00000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+ 0xfe000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+ 0xfe000000, 0x00000000, 0x00100000, 0x00000000,
+ 0xf8000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00ffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ },
+
+
+/* rw_wdfet image (Image 16)
+ *
+ * ctr0 : Counts total number of writeback transactions.
+ * ctr1 : Total number of data valid Runway cycles.
+ * ctr2 : Overflow of Counter 0.
+ * ctr3 : Overflow of Counter 1.
+ */
+
+ {
+ 0x0c01e000, 0x00000000, 0x00060000, 0x00000000,
+ 0xefefefef, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffff00, 0x00000000,
+ 0xf0ffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffff0000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffff0000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00001b00, 0xaa000000,
+ 0x00000001, 0x30700000, 0x00055aaf, 0xf0000000,
+ 0x01b00000, 0x00000000, 0x00001037, 0x00000000,
+ 0x55aaff00, 0x00c00000, 0x1b55aa00, 0x00000000,
+ 0x0001fff0, 0xcfffff00, 0x00000000, 0x0f0fffff,
+ 0xffffffff, 0xffffffff, 0x30ffff0c, 0xfffff000,
+ 0x00000000, 0x00ffffff, 0xffffffff, 0xfffffff3,
+ 0x0ffff0cf, 0xffff0000, 0x00000000, 0x00ffffff,
+ 0xffffffff, 0xfffffff3, 0x0ffff0cf, 0xffff0000,
+ 0x00000000, 0x0fffffff, 0xffffffff, 0xffffff30,
+ 0xfff70000, 0x000055aa, 0xff000000, 0x000006d5,
+ 0x40000000, 0x00000000, 0x731c0000, 0x000156ab,
+ 0xfc000000, 0x00000000, 0xffff0000, 0x00000000,
+ 0xf0000000, 0x00000000, 0x00ffffff, 0xff3fffff,
+ 0xffffffff, 0xffcfffff, 0xfff7fbfc, 0x00000000,
+ 0x00ffffff, 0xff3fffff, 0xffffffff, 0xffcfffff,
+ 0xfff7fbfc, 0x00000000, 0xffffffff, 0xffffff3f,
+ 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffff3f,
+ 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+ 0x00000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+ 0xfe000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+ 0xfe000000, 0x00000000, 0x00100000, 0x00000000,
+ 0x98000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ 0x00ffffff, 0xffffffff, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+ },
+
+/* shlib_cpi image (Image 17)
+ *
+ * ctr0 : Total number of instructions in quadrant 0.
+ * ctr1 : Total number of CPU clock cycles in quadrant 0.
+ * ctr2 : Total number of Non-Nullified instructions retired.
+ * ctr3 : Total number of CPU clock cycles.
+ *
+ * Only works for 32-bit shared libraries.
+ */
+
+ {
+ 0x0c01e000, 0x00000000, 0x00060000, 0x00000000,
+ 0xe0e0e0e0, 0x00001fff, 0xfc00007f, 0xfff00001,
+ 0xffffc000, 0x07ffff00, 0x07ffffff, 0x0007ffff,
+ 0xff0007ff, 0xffff0007, 0xffffff00, 0x00000000,
+ 0xf0150000, 0x0fffff00, 0x000fffff, 0xffffffff,
+ 0xffffffff, 0xffff0000, 0x00000000, 0x00ffffff,
+ 0xffcff000, 0x0000000f, 0xfffffffc, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffff0000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x27000000, 0x00000055,
+ 0x02000005, 0x7f500000, 0xc0000000, 0x000ff270,
+ 0x00000000, 0x00000000, 0x00007700, 0x00000ff0,
+ 0x00000000, 0x0000ffff, 0xffffffff, 0xffffff00,
+ 0x00000000, 0x0000ff00, 0x00000000, 0x0f0fffff,
+ 0xffffffff, 0xfffff000, 0x00000000, 0x000ff000,
+ 0x00000000, 0x00ffffff, 0xffffffff, 0xffff0000,
+ 0x00000000, 0x00ff0000, 0x00000000, 0xf0ffffff,
+ 0xffffffff, 0xffff0000, 0x00000000, 0x00ff0000,
+ 0x00000000, 0x0fffffff, 0xffffffff, 0xfff00000,
+ 0x00000000, 0x0ff00000, 0x000000a0, 0x3fffffff,
+ 0xffffffff, 0xffc00000, 0x03d40000, 0x20000000,
+ 0x0003fc00, 0x00000000, 0xffff0000, 0x00000000,
+ 0xf0000000, 0x00000000, 0x00ffffff, 0xff3fffff,
+ 0xffffffff, 0xffcfffff, 0xfff7fbfc, 0x00000000,
+ 0x00ffffff, 0xff3fffff, 0xffffffff, 0xffcfffff,
+ 0xfff7fbfc, 0x00000000, 0xffffffff, 0xffffff3f,
+ 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+ 0x00000000, 0x00000000, 0xffffffff, 0xffffff3f,
+ 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+ 0x00000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+ 0xfe000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+ 0xfe000000, 0x00000000, 0x00030000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ },
+
+/* flop image (Image 18)
+ *
+ * ctr0 : Total number of floating point instructions (opcode = 0xc).
+ * ctr1 : Total number of floating point instructions (opcode = 0xe, 0x6, 0x2e, 0x26).
+ * ctr2 : Unused
+ * ctr3 : Unused
+ */
+
+ {
+ 0x0001e000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00001010, 0x33ffffff, 0x006fffff, 0xfc5fffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffff00, 0x00000000,
+ 0xf0ffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffff0000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffff0000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xd22d0000, 0x00000000,
+ 0x0000000b, 0x46000000, 0x00000000, 0x0ffff900,
+ 0x90000000, 0x00000000, 0x0000907e, 0x00000000,
+ 0x000000ff, 0xff00bfdf, 0x03030303, 0x03030000,
+ 0x000dbfff, 0xffffff00, 0x00000000, 0x000fffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xfffff000,
+ 0x00000000, 0x00ffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffff0000, 0x00000000, 0xf0ffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0000,
+ 0x00000000, 0x0fffffff, 0xffffffff, 0xffffffff,
+ 0xffff5555, 0x55500000, 0x003f3ff0, 0x2766c000,
+ 0x00000000, 0x00000002, 0x67840000, 0x00000000,
+ 0x03fffc00, 0x00000000, 0xffff0000, 0x00000000,
+ 0xf0000000, 0x00000000, 0x00ffffff, 0xff3fffff,
+ 0xffffffff, 0xffcfffff, 0xfff6fb7c, 0x00000000,
+ 0x00ffffff, 0xff3fffff, 0xffffffff, 0xffcfffff,
+ 0xfff6fb7c, 0x00000000, 0xffff0fff, 0xffffff3f,
+ 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+ 0x00000000, 0x00000000, 0xffff0fff, 0xffffff3f,
+ 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+ 0x00000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+ 0xfe000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+ 0xfe000000, 0x00000000, 0x00130000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ },
+
+/* cachemiss image FROM I_D_MISSES.IDF (Image 19)
+ *
+ * ctr0 : icache misses for retired instructions
+ * ctr1 : total cycles
+ * ctr2 : dcache misses for retired instructions
+ * ctr3 : number of retired instructions
+ */
+ {
+ 0x2801e000, 0x00000000, 0x00010000, 0x00000000,
+ 0x00001000, 0xffffffff, 0xffffffff, 0xfff00fff,
+ 0xfffa3fff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffff00, 0x00000000,
+ 0xf0ffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffff0000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffff0000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xf2fdf0f0, 0xf0f0f0f0,
+ 0xffffffff, 0xf6c00000, 0x00000000, 0x0ff55800,
+ 0x90000000, 0x00000000, 0x0000b0ff, 0xfffffff0,
+ 0x00000003, 0x0100bfff, 0x3f3f3f3f, 0x3f3f5555,
+ 0x555fffff, 0xffffff00, 0x00000000, 0x000fffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xfffff000,
+ 0x00000000, 0x00ffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffff0000, 0x00000000, 0xf0ffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0000,
+ 0x00000000, 0x0fffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xfff00000, 0x000301b0, 0x2fefcfcf,
+ 0xcfcfcfcf, 0xd5555557, 0xf7b40000, 0x00000000,
+ 0x03c14000, 0x00000000, 0xffff0000, 0x00000000,
+ 0xf0000000, 0x00000000, 0x00ffffff, 0xff3fffff,
+ 0xffffffff, 0xffcfffff, 0xfff6fb7c, 0x00000000,
+ 0x00ffffff, 0xff3fffff, 0xffffffff, 0xffcfffff,
+ 0xfff6fb7c, 0x00000000, 0xffff0fff, 0xffffff3f,
+ 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+ 0x00000000, 0x00000000, 0xffff0fff, 0xffffff3f,
+ 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+ 0x00000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+ 0xfe000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+ 0xfe000000, 0x00000000, 0x00130000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ },
+
+/* branch FROM br_report3.idf
+ *
+ * ctr0 : Total number of mispredicted branches.
+ * ctr1 : Some Non-Nullified unpredictable branches.
+ * ctr2 : Total number of branches (Nullified + Non-Nullified)
+ * (Unpredicted+ Predicted Taken +Predicted Not Taken).
+ * Total of All Branches.
+ * ctr3 : Remaining Non-Nullified unpredictable branches.
+ */
+ {
+ 0x4001e000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0xffffffff, 0xff9fffff, 0xfe0fffff,
+ 0xffffbaff, 0xfdffc0ff, 0xfffdffff, 0xfffffeff,
+ 0xffffffff, 0xffffffff, 0xffffff00, 0x00000000,
+ 0xf4ffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffff0000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffff0000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xd22d0000, 0x00000000,
+ 0x0000000b, 0x46000000, 0x00000000, 0x0ffff900,
+ 0x90000000, 0x00000000, 0x0000907e, 0x00000000,
+ 0x000000ff, 0xff00bfdf, 0x03030303, 0x03030000,
+ 0x000dbfff, 0xffffff00, 0x00000000, 0x000fffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xfffff000,
+ 0x00000000, 0x00ffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffff0000, 0x00000000, 0xf0ffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0000,
+ 0x00000000, 0x0fffffff, 0xffffffff, 0xffffffff,
+ 0xffff5555, 0x55500000, 0x003f3ff0, 0x2766c000,
+ 0x00000000, 0x00000002, 0x67840000, 0x00000000,
+ 0x03fffc00, 0x00000000, 0xffff0000, 0x00000000,
+ 0xf0000000, 0x00000000, 0x00ffffff, 0xff3fffff,
+ 0xffffffff, 0xffcfffff, 0xfff6fb7c, 0x00000000,
+ 0x00ffffff, 0xff3fffff, 0xffffffff, 0xffcfffff,
+ 0xfff6fb7c, 0x00000000, 0xffff0fff, 0xffffff3f,
+ 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+ 0x00000000, 0x00000000, 0xffff0fff, 0xffffff3f,
+ 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+ 0x00000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+ 0xfe000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+ 0xfe000000, 0x00000000, 0x00130000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ },
+
+/* crstack FROM crs_report.idf
+ *
+ * ctr0: correctly predicted branches by the pop_latch
+ * ctr1: some procedure returns
+ * ctr2: all branches, (includes nullified)
+ * ctr3: remaining procedure returns
+ */
+ {
+ 0x4001e000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0xffffffff, 0xffa10300, 0x000fffff,
+ 0xffffbaf8, 0x3000007f, 0xffffffff, 0xfffffeff,
+ 0xff7fffff, 0xffffffff, 0xffffff00, 0x00000000,
+ 0xf2ffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffff0000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffff0000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xd22d0000, 0x00000000,
+ 0x0000000b, 0x46000000, 0x00000000, 0x0ffff900,
+ 0x90000000, 0x00000000, 0x0000907e, 0x00000000,
+ 0x000000ff, 0xff00bfdf, 0x03030303, 0x03030000,
+ 0x000dbfff, 0xffffff00, 0x00000000, 0x000fffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xfffff000,
+ 0x00000000, 0x00ffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffff0000, 0x00000000, 0xf0ffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0000,
+ 0x00000000, 0x0fffffff, 0xffffffff, 0xffffffff,
+ 0xffff5555, 0x55500000, 0x003f3ff0, 0x2766c000,
+ 0x00000000, 0x00000002, 0x67840000, 0x00000000,
+ 0x03fffc00, 0x00000000, 0xffff0000, 0x00000000,
+ 0xf0000000, 0x00000000, 0x00ffffff, 0xff3fffff,
+ 0xffffffff, 0xffcfffff, 0xfff6fb7c, 0x00000000,
+ 0x00ffffff, 0xff3fffff, 0xffffffff, 0xffcfffff,
+ 0xfff6fb7c, 0x00000000, 0xffff0fff, 0xffffff3f,
+ 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+ 0x00000000, 0x00000000, 0xffff0fff, 0xffffff3f,
+ 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+ 0x00000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+ 0xfe000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+ 0xfe000000, 0x00000000, 0x00130000, 0x00000000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ },
+
+/* icache_report image
+ *
+ * ctr0 : Icache misses actually used by the core.
+ * ctr1 : ICORE_AV (Icache misses the core THINKS it needs, including fetching down speculative paths).
+ * ctr2 : READs on Runway (Icache misses that made it out to Runway, including
+ * prefetches).
+ * ctr3 : Prefetch returns (1x and 2x).
+ */
+ {
+ 0x00000000, 0x00000000, 0x00010000, 0x00000000,
+ 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffff00, 0x00000000,
+ 0x00ffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffff0000, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffff0000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0xd2002d00, 0x00000000,
+ 0x0000000b, 0x46000000, 0x0000000f, 0xf00ff900,
+ 0x00900000, 0x00000000, 0x0000907e, 0x00000000,
+ 0x0000ff00, 0xff83bf03, 0xdf030303, 0x03030000,
+ 0x000dbfff, 0xffffff00, 0x00000000, 0x000fffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xfffff000,
+ 0x00000000, 0x00ffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffff0000, 0x00000000, 0x80ffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0000,
+ 0x00000000, 0x4fffffff, 0xffffffff, 0xffffffff,
+ 0xffff5555, 0x55500000, 0x3f003f80, 0x274026c0,
+ 0x00000000, 0x00000002, 0x67840000, 0x00000003,
+ 0xfc03fc00, 0x00000000, 0x0eff0000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00ffffff, 0xff3fffff,
+ 0xffffffff, 0xffcfffff, 0xfff6fb7c, 0x00000000,
+ 0x00ffffff, 0xff3fffff, 0xffffffff, 0xffcfffff,
+ 0xfff6fb7c, 0x00000000, 0xffff0fff, 0xffffff3f,
+ 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+ 0x00000000, 0x00000000, 0xffff0fff, 0xffffff3f,
+ 0xffffffff, 0xffffff7f, 0xffffffff, 0xfffffefc,
+ 0x00000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+ 0xfe000000, 0x00000000, 0xffffffff, 0xfffff9ff,
+ 0xfe000000, 0x00000000, 0x00130000, 0x00000000,
+ 0xd0ffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0x00ffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+
+ }
+
+};
+
+#endif
diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c
new file mode 100644
index 000000000..ed93bd8c1
--- /dev/null
+++ b/arch/parisc/kernel/process.c
@@ -0,0 +1,280 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * PARISC Architecture-dependent parts of process handling
+ * based on the work for i386
+ *
+ * Copyright (C) 1999-2003 Matthew Wilcox <willy at parisc-linux.org>
+ * Copyright (C) 2000 Martin K Petersen <mkp at mkp.net>
+ * Copyright (C) 2000 John Marvin <jsm at parisc-linux.org>
+ * Copyright (C) 2000 David Huggins-Daines <dhd with pobox.org>
+ * Copyright (C) 2000-2003 Paul Bame <bame at parisc-linux.org>
+ * Copyright (C) 2000 Philipp Rumpf <prumpf with tux.org>
+ * Copyright (C) 2000 David Kennedy <dkennedy with linuxcare.com>
+ * Copyright (C) 2000 Richard Hirst <rhirst with parisc-linux.org>
+ * Copyright (C) 2000 Grant Grundler <grundler with parisc-linux.org>
+ * Copyright (C) 2001 Alan Modra <amodra at parisc-linux.org>
+ * Copyright (C) 2001-2002 Ryan Bradetich <rbrad at parisc-linux.org>
+ * Copyright (C) 2001-2014 Helge Deller <deller@gmx.de>
+ * Copyright (C) 2002 Randolph Chung <tausq with parisc-linux.org>
+ */
+#include <linux/elf.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/cpu.h>
+#include <linux/module.h>
+#include <linux/personality.h>
+#include <linux/ptrace.h>
+#include <linux/reboot.h>
+#include <linux/sched.h>
+#include <linux/sched/debug.h>
+#include <linux/sched/task.h>
+#include <linux/sched/task_stack.h>
+#include <linux/slab.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/kallsyms.h>
+#include <linux/uaccess.h>
+#include <linux/rcupdate.h>
+#include <linux/random.h>
+#include <linux/nmi.h>
+#include <linux/sched/hotplug.h>
+
+#include <asm/io.h>
+#include <asm/asm-offsets.h>
+#include <asm/assembly.h>
+#include <asm/pdc.h>
+#include <asm/pdc_chassis.h>
+#include <asm/unwind.h>
+#include <asm/sections.h>
+#include <asm/cacheflush.h>
+
+#define COMMAND_GLOBAL F_EXTEND(0xfffe0030)
+#define CMD_RESET 5 /* reset any module */
+
+/*
+** The Wright Brothers and Gecko systems have a H/W problem
+** (Lasi...'nuf said) may cause a broadcast reset to lockup
+** the system. An HVERSION dependent PDC call was developed
+** to perform a "safe", platform specific broadcast reset instead
+** of kludging up all the code.
+**
+** Older machines which do not implement PDC_BROADCAST_RESET will
+** return (with an error) and the regular broadcast reset can be
+** issued. Obviously, if the PDC does implement PDC_BROADCAST_RESET
+** the PDC call will not return (the system will be reset).
+*/
+void machine_restart(char *cmd)
+{
+#ifdef FASTBOOT_SELFTEST_SUPPORT
+ /*
+ ** If user has modified the Firmware Selftest Bitmap,
+ ** run the tests specified in the bitmap after the
+ ** system is rebooted w/PDC_DO_RESET.
+ **
+ ** ftc_bitmap = 0x1AUL "Skip destructive memory tests"
+ **
+ ** Using "directed resets" at each processor with the MEM_TOC
+ ** vector cleared will also avoid running destructive
+ ** memory self tests. (Not implemented yet)
+ */
+ if (ftc_bitmap) {
+ pdc_do_firm_test_reset(ftc_bitmap);
+ }
+#endif
+ /* set up a new led state on systems shipped with a LED State panel */
+ pdc_chassis_send_status(PDC_CHASSIS_DIRECT_SHUTDOWN);
+
+ /* "Normal" system reset */
+ pdc_do_reset();
+
+ /* Nope...box should reset with just CMD_RESET now */
+ gsc_writel(CMD_RESET, COMMAND_GLOBAL);
+
+ /* Wait for RESET to lay us to rest. */
+ while (1) ;
+
+}
+
+/*
+ * This routine is called from sys_reboot to actually turn off the
+ * machine
+ */
+void machine_power_off(void)
+{
+ /* Put the soft power button back under hardware control.
+ * If the user had already pressed the power button, the
+ * following call will immediately power off. */
+ pdc_soft_power_button(0);
+
+ pdc_chassis_send_status(PDC_CHASSIS_DIRECT_SHUTDOWN);
+
+ /* ipmi_poweroff may have been installed. */
+ do_kernel_power_off();
+
+ /* It seems we have no way to power the system off via
+ * software. The user has to press the button himself. */
+
+ printk("Power off or press RETURN to reboot.\n");
+
+ /* prevent soft lockup/stalled CPU messages for endless loop. */
+ rcu_sysrq_start();
+ lockup_detector_soft_poweroff();
+ while (1) {
+ /* reboot if user presses RETURN key */
+ if (pdc_iodc_getc() == 13) {
+ printk("Rebooting...\n");
+ machine_restart(NULL);
+ }
+ }
+}
+
+void (*pm_power_off)(void);
+EXPORT_SYMBOL(pm_power_off);
+
+void machine_halt(void)
+{
+ machine_power_off();
+}
+
+void flush_thread(void)
+{
+ /* Only needs to handle fpu stuff or perf monitors.
+ ** REVISIT: several arches implement a "lazy fpu state".
+ */
+}
+
+/*
+ * Idle thread support
+ *
+ * Detect when running on QEMU with SeaBIOS PDC Firmware and let
+ * QEMU idle the host too.
+ */
+
+int running_on_qemu __ro_after_init;
+EXPORT_SYMBOL(running_on_qemu);
+
+/*
+ * Called from the idle thread for the CPU which has been shutdown.
+ */
+void __noreturn arch_cpu_idle_dead(void)
+{
+#ifdef CONFIG_HOTPLUG_CPU
+ idle_task_exit();
+
+ local_irq_disable();
+
+ /* Tell the core that this CPU is now safe to dispose of. */
+ cpuhp_ap_report_dead();
+
+ /* Ensure that the cache lines are written out. */
+ flush_cache_all_local();
+ flush_tlb_all_local(NULL);
+
+ /* Let PDC firmware put CPU into firmware idle loop. */
+ __pdc_cpu_rendezvous();
+
+ pr_warn("PDC does not provide rendezvous function.\n");
+#endif
+ while (1);
+}
+
+void __cpuidle arch_cpu_idle(void)
+{
+ /* nop on real hardware, qemu will idle sleep. */
+ asm volatile("or %%r10,%%r10,%%r10\n":::);
+}
+
+static int __init parisc_idle_init(void)
+{
+ if (!running_on_qemu)
+ cpu_idle_poll_ctrl(1);
+
+ return 0;
+}
+arch_initcall(parisc_idle_init);
+
+/*
+ * Copy architecture-specific thread state
+ */
+int
+copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
+{
+ unsigned long clone_flags = args->flags;
+ unsigned long usp = args->stack;
+ unsigned long tls = args->tls;
+ struct pt_regs *cregs = &(p->thread.regs);
+ void *stack = task_stack_page(p);
+
+ /* We have to use void * instead of a function pointer, because
+ * function pointers aren't a pointer to the function on 64-bit.
+ * Make them const so the compiler knows they live in .text */
+ extern void * const ret_from_kernel_thread;
+ extern void * const child_return;
+
+ if (unlikely(args->fn)) {
+ /* kernel thread */
+ memset(cregs, 0, sizeof(struct pt_regs));
+ if (args->idle) /* idle thread */
+ return 0;
+ /* Must exit via ret_from_kernel_thread in order
+ * to call schedule_tail()
+ */
+ cregs->ksp = (unsigned long) stack + FRAME_SIZE + PT_SZ_ALGN;
+ cregs->kpc = (unsigned long) &ret_from_kernel_thread;
+ /*
+ * Copy function and argument to be called from
+ * ret_from_kernel_thread.
+ */
+#ifdef CONFIG_64BIT
+ cregs->gr[27] = ((unsigned long *)args->fn)[3];
+ cregs->gr[26] = ((unsigned long *)args->fn)[2];
+#else
+ cregs->gr[26] = (unsigned long) args->fn;
+#endif
+ cregs->gr[25] = (unsigned long) args->fn_arg;
+ } else {
+ /* user thread */
+ /* usp must be word aligned. This also prevents users from
+ * passing in the value 1 (which is the signal for a special
+ * return for a kernel thread) */
+ if (usp) {
+ usp = ALIGN(usp, 4);
+ if (likely(usp))
+ cregs->gr[30] = usp;
+ }
+ cregs->ksp = (unsigned long) stack + FRAME_SIZE;
+ cregs->kpc = (unsigned long) &child_return;
+
+ /* Setup thread TLS area */
+ if (clone_flags & CLONE_SETTLS)
+ cregs->cr27 = tls;
+ }
+
+ return 0;
+}
+
+unsigned long
+__get_wchan(struct task_struct *p)
+{
+ struct unwind_frame_info info;
+ unsigned long ip;
+ int count = 0;
+
+ /*
+ * These bracket the sleeping functions..
+ */
+
+ unwind_frame_init_from_blocked_task(&info, p);
+ do {
+ if (unwind_once(&info) < 0)
+ return 0;
+ if (task_is_running(p))
+ return 0;
+ ip = info.ip;
+ if (!in_sched_functions(ip))
+ return ip;
+ } while (count++ < MAX_UNWIND_ENTRIES);
+ return 0;
+}
diff --git a/arch/parisc/kernel/processor.c b/arch/parisc/kernel/processor.c
new file mode 100644
index 000000000..1fc89fa2c
--- /dev/null
+++ b/arch/parisc/kernel/processor.c
@@ -0,0 +1,486 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Initial setup-routines for HP 9000 based hardware.
+ *
+ * Copyright (C) 1991, 1992, 1995 Linus Torvalds
+ * Modifications for PA-RISC (C) 1999-2008 Helge Deller <deller@gmx.de>
+ * Modifications copyright 1999 SuSE GmbH (Philipp Rumpf)
+ * Modifications copyright 2000 Martin K. Petersen <mkp@mkp.net>
+ * Modifications copyright 2000 Philipp Rumpf <prumpf@tux.org>
+ * Modifications copyright 2001 Ryan Bradetich <rbradetich@uswest.net>
+ *
+ * Initial PA-RISC Version: 04-23-1999 by Helge Deller
+ */
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include <linux/random.h>
+#include <linux/slab.h>
+#include <linux/cpu.h>
+#include <asm/topology.h>
+#include <asm/param.h>
+#include <asm/cache.h>
+#include <asm/hardware.h> /* for register_parisc_driver() stuff */
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/pdc.h>
+#include <asm/smp.h>
+#include <asm/pdcpat.h>
+#include <asm/irq.h> /* for struct irq_region */
+#include <asm/parisc-device.h>
+
+struct system_cpuinfo_parisc boot_cpu_data __ro_after_init;
+EXPORT_SYMBOL(boot_cpu_data);
+#ifdef CONFIG_PA8X00
+int _parisc_requires_coherency __ro_after_init;
+EXPORT_SYMBOL(_parisc_requires_coherency);
+#endif
+
+DEFINE_PER_CPU(struct cpuinfo_parisc, cpu_data);
+
+/*
+** PARISC CPU driver - claim "device" and initialize CPU data structures.
+**
+** Consolidate per CPU initialization into (mostly) one module.
+** Monarch CPU will initialize boot_cpu_data which shouldn't
+** change once the system has booted.
+**
+** The callback *should* do per-instance initialization of
+** everything including the monarch. "Per CPU" init code in
+** setup.c:start_parisc() has migrated here and start_parisc()
+** will call register_parisc_driver(&cpu_driver) before calling do_inventory().
+**
+** The goal of consolidating CPU initialization into one place is
+** to make sure all CPUs get initialized the same way.
+** The code path not shared is how PDC hands control of the CPU to the OS.
+** The initialization of OS data structures is the same (done below).
+*/
+
+/**
+ * init_percpu_prof - enable/setup per cpu profiling hooks.
+ * @cpunum: The processor instance.
+ *
+ * FIXME: doesn't do much yet...
+ */
+static void
+init_percpu_prof(unsigned long cpunum)
+{
+}
+
+
+/**
+ * processor_probe - Determine if processor driver should claim this device.
+ * @dev: The device which has been found.
+ *
+ * Determine if processor driver should claim this chip (return 0) or not
+ * (return 1). If so, initialize the chip and tell other partners in crime
+ * they have work to do.
+ */
+static int __init processor_probe(struct parisc_device *dev)
+{
+ unsigned long txn_addr;
+ unsigned long cpuid;
+ struct cpuinfo_parisc *p;
+ struct pdc_pat_cpu_num cpu_info = { };
+
+#ifdef CONFIG_SMP
+ if (num_online_cpus() >= nr_cpu_ids) {
+ printk(KERN_INFO "num_online_cpus() >= nr_cpu_ids\n");
+ return 1;
+ }
+#else
+ if (boot_cpu_data.cpu_count > 0) {
+ printk(KERN_INFO "CONFIG_SMP=n ignoring additional CPUs\n");
+ return 1;
+ }
+#endif
+
+ /* logical CPU ID and update global counter
+ * May get overwritten by PAT code.
+ */
+ cpuid = boot_cpu_data.cpu_count;
+ txn_addr = dev->hpa.start; /* for legacy PDC */
+ cpu_info.cpu_num = cpu_info.cpu_loc = cpuid;
+
+#ifdef CONFIG_64BIT
+ if (is_pdc_pat()) {
+ ulong status;
+ unsigned long bytecnt;
+ pdc_pat_cell_mod_maddr_block_t *pa_pdc_cell;
+
+ pa_pdc_cell = kmalloc(sizeof (*pa_pdc_cell), GFP_KERNEL);
+ if (!pa_pdc_cell)
+ panic("couldn't allocate memory for PDC_PAT_CELL!");
+
+ status = pdc_pat_cell_module(&bytecnt, dev->pcell_loc,
+ dev->mod_index, PA_VIEW, pa_pdc_cell);
+
+ BUG_ON(PDC_OK != status);
+
+ /* verify it's the same as what do_pat_inventory() found */
+ BUG_ON(dev->mod_info != pa_pdc_cell->mod_info);
+ BUG_ON(dev->pmod_loc != pa_pdc_cell->mod_location);
+
+ txn_addr = pa_pdc_cell->mod[0]; /* id_eid for IO sapic */
+
+ kfree(pa_pdc_cell);
+
+ /* get the cpu number */
+ status = pdc_pat_cpu_get_number(&cpu_info, dev->hpa.start);
+ BUG_ON(PDC_OK != status);
+
+ pr_info("Logical CPU #%lu is physical cpu #%lu at location "
+ "0x%lx with hpa %pa\n",
+ cpuid, cpu_info.cpu_num, cpu_info.cpu_loc,
+ &dev->hpa.start);
+
+#undef USE_PAT_CPUID
+#ifdef USE_PAT_CPUID
+/* We need contiguous numbers for cpuid. Firmware's notion
+ * of cpuid is for physical CPUs and we just don't care yet.
+ * We'll care when we need to query PAT PDC about a CPU *after*
+ * boot time (ie shutdown a CPU from an OS perspective).
+ */
+ if (cpu_info.cpu_num >= NR_CPUS) {
+ printk(KERN_WARNING "IGNORING CPU at %pa,"
+ " cpu_slot_id > NR_CPUS"
+ " (%ld > %d)\n",
+ &dev->hpa.start, cpu_info.cpu_num, NR_CPUS);
+ /* Ignore CPU since it will only crash */
+ boot_cpu_data.cpu_count--;
+ return 1;
+ } else {
+ cpuid = cpu_info.cpu_num;
+ }
+#endif
+ }
+#endif
+
+ p = &per_cpu(cpu_data, cpuid);
+ boot_cpu_data.cpu_count++;
+
+ /* initialize counters - CPU 0 gets it_value set in time_init() */
+ if (cpuid)
+ memset(p, 0, sizeof(struct cpuinfo_parisc));
+
+ p->dev = dev; /* Save IODC data in case we need it */
+ p->hpa = dev->hpa.start; /* save CPU hpa */
+ p->cpuid = cpuid; /* save CPU id */
+ p->txn_addr = txn_addr; /* save CPU IRQ address */
+ p->cpu_num = cpu_info.cpu_num;
+ p->cpu_loc = cpu_info.cpu_loc;
+
+ set_cpu_possible(cpuid, true);
+ store_cpu_topology(cpuid);
+
+#ifdef CONFIG_SMP
+ /*
+ ** FIXME: review if any other initialization is clobbered
+ ** for boot_cpu by the above memset().
+ */
+ init_percpu_prof(cpuid);
+#endif
+
+ /*
+ ** CONFIG_SMP: init_smp_config() will attempt to get CPUs into
+ ** OS control. RENDEZVOUS is the default state - see mem_set above.
+ ** p->state = STATE_RENDEZVOUS;
+ */
+
+#if 0
+ /* CPU 0 IRQ table is statically allocated/initialized */
+ if (cpuid) {
+ struct irqaction actions[];
+
+ /*
+ ** itimer and ipi IRQ handlers are statically initialized in
+ ** arch/parisc/kernel/irq.c. ie Don't need to register them.
+ */
+ actions = kmalloc(sizeof(struct irqaction)*MAX_CPU_IRQ, GFP_ATOMIC);
+ if (!actions) {
+ /* not getting it's own table, share with monarch */
+ actions = cpu_irq_actions[0];
+ }
+
+ cpu_irq_actions[cpuid] = actions;
+ }
+#endif
+
+ /*
+ * Bring this CPU up now! (ignore bootstrap cpuid == 0)
+ */
+#ifdef CONFIG_SMP
+ if (cpuid) {
+ set_cpu_present(cpuid, true);
+ add_cpu(cpuid);
+ }
+#endif
+
+ return 0;
+}
+
+/**
+ * collect_boot_cpu_data - Fill the boot_cpu_data structure.
+ *
+ * This function collects and stores the generic processor information
+ * in the boot_cpu_data structure.
+ */
+void __init collect_boot_cpu_data(void)
+{
+ unsigned long cr16_seed;
+ char orig_prod_num[64], current_prod_num[64], serial_no[64];
+
+ memset(&boot_cpu_data, 0, sizeof(boot_cpu_data));
+
+ cr16_seed = get_cycles();
+ add_device_randomness(&cr16_seed, sizeof(cr16_seed));
+
+ boot_cpu_data.cpu_hz = 100 * PAGE0->mem_10msec; /* Hz of this PARISC */
+
+ /* get CPU-Model Information... */
+#define p ((unsigned long *)&boot_cpu_data.pdc.model)
+ if (pdc_model_info(&boot_cpu_data.pdc.model) == PDC_OK) {
+ printk(KERN_INFO
+ "model %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+ p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8]);
+
+ add_device_randomness(&boot_cpu_data.pdc.model,
+ sizeof(boot_cpu_data.pdc.model));
+ }
+#undef p
+
+ if (pdc_model_versions(&boot_cpu_data.pdc.versions, 0) == PDC_OK) {
+ printk(KERN_INFO "vers %08lx\n",
+ boot_cpu_data.pdc.versions);
+
+ add_device_randomness(&boot_cpu_data.pdc.versions,
+ sizeof(boot_cpu_data.pdc.versions));
+ }
+
+ if (pdc_model_cpuid(&boot_cpu_data.pdc.cpuid) == PDC_OK) {
+ printk(KERN_INFO "CPUID vers %ld rev %ld (0x%08lx)\n",
+ (boot_cpu_data.pdc.cpuid >> 5) & 127,
+ boot_cpu_data.pdc.cpuid & 31,
+ boot_cpu_data.pdc.cpuid);
+
+ add_device_randomness(&boot_cpu_data.pdc.cpuid,
+ sizeof(boot_cpu_data.pdc.cpuid));
+ }
+
+ if (pdc_model_capabilities(&boot_cpu_data.pdc.capabilities) == PDC_OK)
+ printk(KERN_INFO "capabilities 0x%lx\n",
+ boot_cpu_data.pdc.capabilities);
+
+ if (pdc_model_sysmodel(OS_ID_HPUX, boot_cpu_data.pdc.sys_model_name) == PDC_OK)
+ pr_info("HP-UX model name: %s\n",
+ boot_cpu_data.pdc.sys_model_name);
+
+ serial_no[0] = 0;
+ if (pdc_model_sysmodel(OS_ID_MPEXL, serial_no) == PDC_OK &&
+ serial_no[0])
+ pr_info("MPE/iX model name: %s\n", serial_no);
+
+ dump_stack_set_arch_desc("%s", boot_cpu_data.pdc.sys_model_name);
+
+ boot_cpu_data.hversion = boot_cpu_data.pdc.model.hversion;
+ boot_cpu_data.sversion = boot_cpu_data.pdc.model.sversion;
+
+ boot_cpu_data.cpu_type = parisc_get_cpu_type(boot_cpu_data.hversion);
+ boot_cpu_data.cpu_name = cpu_name_version[boot_cpu_data.cpu_type][0];
+ boot_cpu_data.family_name = cpu_name_version[boot_cpu_data.cpu_type][1];
+
+#ifdef CONFIG_PA8X00
+ _parisc_requires_coherency = (boot_cpu_data.cpu_type == mako) ||
+ (boot_cpu_data.cpu_type == mako2);
+#endif
+
+ if (pdc_model_platform_info(orig_prod_num, current_prod_num, serial_no) == PDC_OK) {
+ printk(KERN_INFO "product %s, original product %s, S/N: %s\n",
+ current_prod_num[0] ? current_prod_num : "n/a",
+ orig_prod_num, serial_no);
+ add_device_randomness(orig_prod_num, strlen(orig_prod_num));
+ add_device_randomness(current_prod_num, strlen(current_prod_num));
+ add_device_randomness(serial_no, strlen(serial_no));
+ }
+}
+
+
+/**
+ * init_per_cpu - Handle individual processor initializations.
+ * @cpunum: logical processor number.
+ *
+ * This function handles initialization for *every* CPU
+ * in the system:
+ *
+ * o Set "default" CPU width for trap handlers
+ *
+ * o Enable FP coprocessor
+ * REVISIT: this could be done in the "code 22" trap handler.
+ * (frowands idea - that way we know which processes need FP
+ * registers saved on the interrupt stack.)
+ * NEWS FLASH: wide kernels need FP coprocessor enabled to handle
+ * formatted printing of %lx for example (double divides I think)
+ *
+ * o Enable CPU profiling hooks.
+ */
+int init_per_cpu(int cpunum)
+{
+ int ret;
+ struct pdc_coproc_cfg coproc_cfg;
+
+ set_firmware_width();
+ ret = pdc_coproc_cfg(&coproc_cfg);
+
+ if(ret >= 0 && coproc_cfg.ccr_functional) {
+ mtctl(coproc_cfg.ccr_functional, 10); /* 10 == Coprocessor Control Reg */
+
+ /* FWIW, FP rev/model is a more accurate way to determine
+ ** CPU type. CPU rev/model has some ambiguous cases.
+ */
+ per_cpu(cpu_data, cpunum).fp_rev = coproc_cfg.revision;
+ per_cpu(cpu_data, cpunum).fp_model = coproc_cfg.model;
+
+ if (cpunum == 0)
+ printk(KERN_INFO "FP[%d] enabled: Rev %ld Model %ld\n",
+ cpunum, coproc_cfg.revision, coproc_cfg.model);
+
+ /*
+ ** store status register to stack (hopefully aligned)
+ ** and clear the T-bit.
+ */
+ asm volatile ("fstd %fr0,8(%sp)");
+
+ } else {
+ printk(KERN_WARNING "WARNING: No FP CoProcessor?!"
+ " (coproc_cfg.ccr_functional == 0x%lx, expected 0xc0)\n"
+#ifdef CONFIG_64BIT
+ "Halting Machine - FP required\n"
+#endif
+ , coproc_cfg.ccr_functional);
+#ifdef CONFIG_64BIT
+ mdelay(100); /* previous chars get pushed to console */
+ panic("FP CoProc not reported");
+#endif
+ }
+
+ /* FUTURE: Enable Performance Monitor : ccr bit 0x20 */
+ init_percpu_prof(cpunum);
+
+ btlb_init_per_cpu();
+
+ return ret;
+}
+
+/*
+ * Display CPU info for all CPUs.
+ */
+int
+show_cpuinfo (struct seq_file *m, void *v)
+{
+ unsigned long cpu;
+ char cpu_name[60], *p;
+
+ /* strip PA path from CPU name to not confuse lscpu */
+ strlcpy(cpu_name, per_cpu(cpu_data, 0).dev->name, sizeof(cpu_name));
+ p = strrchr(cpu_name, '[');
+ if (p)
+ *(--p) = 0;
+
+ for_each_online_cpu(cpu) {
+#ifdef CONFIG_SMP
+ const struct cpuinfo_parisc *cpuinfo = &per_cpu(cpu_data, cpu);
+
+ if (0 == cpuinfo->hpa)
+ continue;
+#endif
+ seq_printf(m, "processor\t: %lu\n"
+ "cpu family\t: PA-RISC %s\n",
+ cpu, boot_cpu_data.family_name);
+
+ seq_printf(m, "cpu\t\t: %s\n", boot_cpu_data.cpu_name );
+
+ /* cpu MHz */
+ seq_printf(m, "cpu MHz\t\t: %d.%06d\n",
+ boot_cpu_data.cpu_hz / 1000000,
+ boot_cpu_data.cpu_hz % 1000000 );
+
+#ifdef CONFIG_GENERIC_ARCH_TOPOLOGY
+ seq_printf(m, "physical id\t: %d\n",
+ topology_physical_package_id(cpu));
+ seq_printf(m, "siblings\t: %d\n",
+ cpumask_weight(topology_core_cpumask(cpu)));
+ seq_printf(m, "core id\t\t: %d\n", topology_core_id(cpu));
+#endif
+
+ seq_printf(m, "capabilities\t:");
+ if (boot_cpu_data.pdc.capabilities & PDC_MODEL_OS32)
+ seq_puts(m, " os32");
+ if (boot_cpu_data.pdc.capabilities & PDC_MODEL_OS64)
+ seq_puts(m, " os64");
+ if (boot_cpu_data.pdc.capabilities & PDC_MODEL_IOPDIR_FDC)
+ seq_puts(m, " iopdir_fdc");
+ switch (boot_cpu_data.pdc.capabilities & PDC_MODEL_NVA_MASK) {
+ case PDC_MODEL_NVA_SUPPORTED:
+ seq_puts(m, " nva_supported");
+ break;
+ case PDC_MODEL_NVA_SLOW:
+ seq_puts(m, " nva_slow");
+ break;
+ case PDC_MODEL_NVA_UNSUPPORTED:
+ seq_puts(m, " needs_equivalent_aliasing");
+ break;
+ }
+ seq_printf(m, " (0x%02lx)\n", boot_cpu_data.pdc.capabilities);
+
+ seq_printf(m, "model\t\t: %s - %s\n",
+ boot_cpu_data.pdc.sys_model_name,
+ cpu_name);
+
+ seq_printf(m, "hversion\t: 0x%08x\n"
+ "sversion\t: 0x%08x\n",
+ boot_cpu_data.hversion,
+ boot_cpu_data.sversion );
+
+ /* print cachesize info */
+ show_cache_info(m);
+
+ seq_printf(m, "bogomips\t: %lu.%02lu\n",
+ loops_per_jiffy / (500000 / HZ),
+ loops_per_jiffy / (5000 / HZ) % 100);
+
+ seq_printf(m, "software id\t: %ld\n\n",
+ boot_cpu_data.pdc.model.sw_id);
+ }
+ return 0;
+}
+
+static const struct parisc_device_id processor_tbl[] __initconst = {
+ { HPHW_NPROC, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, SVERSION_ANY_ID },
+ { 0, }
+};
+
+static struct parisc_driver cpu_driver __refdata = {
+ .name = "CPU",
+ .id_table = processor_tbl,
+ .probe = processor_probe
+};
+
+/**
+ * processor_init - Processor initialization procedure.
+ *
+ * Register this driver.
+ */
+void __init processor_init(void)
+{
+ unsigned int cpu;
+
+ reset_cpu_topology();
+
+ /* reset possible mask. We will mark those which are possible. */
+ for_each_possible_cpu(cpu)
+ set_cpu_possible(cpu, false);
+
+ register_parisc_driver(&cpu_driver);
+}
diff --git a/arch/parisc/kernel/ptrace.c b/arch/parisc/kernel/ptrace.c
new file mode 100644
index 000000000..ceb45f51d
--- /dev/null
+++ b/arch/parisc/kernel/ptrace.c
@@ -0,0 +1,793 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Kernel support for the ptrace() and syscall tracing interfaces.
+ *
+ * Copyright (C) 2000 Hewlett-Packard Co, Linuxcare Inc.
+ * Copyright (C) 2000 Matthew Wilcox <matthew@wil.cx>
+ * Copyright (C) 2000 David Huggins-Daines <dhd@debian.org>
+ * Copyright (C) 2008-2016 Helge Deller <deller@gmx.de>
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/elf.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+#include <linux/personality.h>
+#include <linux/regset.h>
+#include <linux/security.h>
+#include <linux/seccomp.h>
+#include <linux/compat.h>
+#include <linux/signal.h>
+#include <linux/audit.h>
+
+#include <linux/uaccess.h>
+#include <asm/processor.h>
+#include <asm/asm-offsets.h>
+
+/* PSW bits we allow the debugger to modify */
+#define USER_PSW_BITS (PSW_N | PSW_B | PSW_V | PSW_CB)
+
+#define CREATE_TRACE_POINTS
+#include <trace/events/syscalls.h>
+
+/*
+ * These are our native regset flavors.
+ */
+enum parisc_regset {
+ REGSET_GENERAL,
+ REGSET_FP
+};
+
+/*
+ * Called by kernel/ptrace.c when detaching..
+ *
+ * Make sure single step bits etc are not set.
+ */
+void ptrace_disable(struct task_struct *task)
+{
+ clear_tsk_thread_flag(task, TIF_SINGLESTEP);
+ clear_tsk_thread_flag(task, TIF_BLOCKSTEP);
+
+ /* make sure the trap bits are not set */
+ pa_psw(task)->r = 0;
+ pa_psw(task)->t = 0;
+ pa_psw(task)->h = 0;
+ pa_psw(task)->l = 0;
+}
+
+/*
+ * The following functions are called by ptrace_resume() when
+ * enabling or disabling single/block tracing.
+ */
+void user_disable_single_step(struct task_struct *task)
+{
+ ptrace_disable(task);
+}
+
+void user_enable_single_step(struct task_struct *task)
+{
+ clear_tsk_thread_flag(task, TIF_BLOCKSTEP);
+ set_tsk_thread_flag(task, TIF_SINGLESTEP);
+
+ if (pa_psw(task)->n) {
+ /* Nullified, just crank over the queue. */
+ task_regs(task)->iaoq[0] = task_regs(task)->iaoq[1];
+ task_regs(task)->iasq[0] = task_regs(task)->iasq[1];
+ task_regs(task)->iaoq[1] = task_regs(task)->iaoq[0] + 4;
+ pa_psw(task)->n = 0;
+ pa_psw(task)->x = 0;
+ pa_psw(task)->y = 0;
+ pa_psw(task)->z = 0;
+ pa_psw(task)->b = 0;
+ ptrace_disable(task);
+ /* Don't wake up the task, but let the
+ parent know something happened. */
+ force_sig_fault_to_task(SIGTRAP, TRAP_TRACE,
+ (void __user *) (task_regs(task)->iaoq[0] & ~3),
+ task);
+ /* notify_parent(task, SIGCHLD); */
+ return;
+ }
+
+ /* Enable recovery counter traps. The recovery counter
+ * itself will be set to zero on a task switch. If the
+ * task is suspended on a syscall then the syscall return
+ * path will overwrite the recovery counter with a suitable
+ * value such that it traps once back in user space. We
+ * disable interrupts in the tasks PSW here also, to avoid
+ * interrupts while the recovery counter is decrementing.
+ */
+ pa_psw(task)->r = 1;
+ pa_psw(task)->t = 0;
+ pa_psw(task)->h = 0;
+ pa_psw(task)->l = 0;
+}
+
+void user_enable_block_step(struct task_struct *task)
+{
+ clear_tsk_thread_flag(task, TIF_SINGLESTEP);
+ set_tsk_thread_flag(task, TIF_BLOCKSTEP);
+
+ /* Enable taken branch trap. */
+ pa_psw(task)->r = 0;
+ pa_psw(task)->t = 1;
+ pa_psw(task)->h = 0;
+ pa_psw(task)->l = 0;
+}
+
+long arch_ptrace(struct task_struct *child, long request,
+ unsigned long addr, unsigned long data)
+{
+ unsigned long __user *datap = (unsigned long __user *)data;
+ unsigned long tmp;
+ long ret = -EIO;
+
+ unsigned long user_regs_struct_size = sizeof(struct user_regs_struct);
+#ifdef CONFIG_64BIT
+ if (is_compat_task())
+ user_regs_struct_size /= 2;
+#endif
+
+ switch (request) {
+
+ /* Read the word at location addr in the USER area. For ptraced
+ processes, the kernel saves all regs on a syscall. */
+ case PTRACE_PEEKUSR:
+ if ((addr & (sizeof(unsigned long)-1)) ||
+ addr >= sizeof(struct pt_regs))
+ break;
+ tmp = *(unsigned long *) ((char *) task_regs(child) + addr);
+ ret = put_user(tmp, datap);
+ break;
+
+ /* Write the word at location addr in the USER area. This will need
+ to change when the kernel no longer saves all regs on a syscall.
+ FIXME. There is a problem at the moment in that r3-r18 are only
+ saved if the process is ptraced on syscall entry, and even then
+ those values are overwritten by actual register values on syscall
+ exit. */
+ case PTRACE_POKEUSR:
+ /* Some register values written here may be ignored in
+ * entry.S:syscall_restore_rfi; e.g. iaoq is written with
+ * r31/r31+4, and not with the values in pt_regs.
+ */
+ if (addr == PT_PSW) {
+ /* Allow writing to Nullify, Divide-step-correction,
+ * and carry/borrow bits.
+ * BEWARE, if you set N, and then single step, it won't
+ * stop on the nullified instruction.
+ */
+ data &= USER_PSW_BITS;
+ task_regs(child)->gr[0] &= ~USER_PSW_BITS;
+ task_regs(child)->gr[0] |= data;
+ ret = 0;
+ break;
+ }
+
+ if ((addr & (sizeof(unsigned long)-1)) ||
+ addr >= sizeof(struct pt_regs))
+ break;
+ if (addr == PT_IAOQ0 || addr == PT_IAOQ1) {
+ data |= PRIV_USER; /* ensure userspace privilege */
+ }
+ if ((addr >= PT_GR1 && addr <= PT_GR31) ||
+ addr == PT_IAOQ0 || addr == PT_IAOQ1 ||
+ (addr >= PT_FR0 && addr <= PT_FR31 + 4) ||
+ addr == PT_SAR) {
+ *(unsigned long *) ((char *) task_regs(child) + addr) = data;
+ ret = 0;
+ }
+ break;
+
+ case PTRACE_GETREGS: /* Get all gp regs from the child. */
+ return copy_regset_to_user(child,
+ task_user_regset_view(current),
+ REGSET_GENERAL,
+ 0, user_regs_struct_size,
+ datap);
+
+ case PTRACE_SETREGS: /* Set all gp regs in the child. */
+ return copy_regset_from_user(child,
+ task_user_regset_view(current),
+ REGSET_GENERAL,
+ 0, user_regs_struct_size,
+ datap);
+
+ case PTRACE_GETFPREGS: /* Get the child FPU state. */
+ return copy_regset_to_user(child,
+ task_user_regset_view(current),
+ REGSET_FP,
+ 0, sizeof(struct user_fp_struct),
+ datap);
+
+ case PTRACE_SETFPREGS: /* Set the child FPU state. */
+ return copy_regset_from_user(child,
+ task_user_regset_view(current),
+ REGSET_FP,
+ 0, sizeof(struct user_fp_struct),
+ datap);
+
+ default:
+ ret = ptrace_request(child, request, addr, data);
+ break;
+ }
+
+ return ret;
+}
+
+
+#ifdef CONFIG_COMPAT
+
+/* This function is needed to translate 32 bit pt_regs offsets in to
+ * 64 bit pt_regs offsets. For example, a 32 bit gdb under a 64 bit kernel
+ * will request offset 12 if it wants gr3, but the lower 32 bits of
+ * the 64 bit kernels view of gr3 will be at offset 28 (3*8 + 4).
+ * This code relies on a 32 bit pt_regs being comprised of 32 bit values
+ * except for the fp registers which (a) are 64 bits, and (b) follow
+ * the gr registers at the start of pt_regs. The 32 bit pt_regs should
+ * be half the size of the 64 bit pt_regs, plus 32*4 to allow for fr[]
+ * being 64 bit in both cases.
+ */
+
+static compat_ulong_t translate_usr_offset(compat_ulong_t offset)
+{
+ compat_ulong_t pos;
+
+ if (offset < 32*4) /* gr[0..31] */
+ pos = offset * 2 + 4;
+ else if (offset < 32*4+32*8) /* fr[0] ... fr[31] */
+ pos = (offset - 32*4) + PT_FR0;
+ else if (offset < sizeof(struct pt_regs)/2 + 32*4) /* sr[0] ... ipsw */
+ pos = (offset - 32*4 - 32*8) * 2 + PT_SR0 + 4;
+ else
+ pos = sizeof(struct pt_regs);
+
+ return pos;
+}
+
+long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
+ compat_ulong_t addr, compat_ulong_t data)
+{
+ compat_uint_t tmp;
+ long ret = -EIO;
+
+ switch (request) {
+
+ case PTRACE_PEEKUSR:
+ if (addr & (sizeof(compat_uint_t)-1))
+ break;
+ addr = translate_usr_offset(addr);
+ if (addr >= sizeof(struct pt_regs))
+ break;
+
+ tmp = *(compat_uint_t *) ((char *) task_regs(child) + addr);
+ ret = put_user(tmp, (compat_uint_t *) (unsigned long) data);
+ break;
+
+ /* Write the word at location addr in the USER area. This will need
+ to change when the kernel no longer saves all regs on a syscall.
+ FIXME. There is a problem at the moment in that r3-r18 are only
+ saved if the process is ptraced on syscall entry, and even then
+ those values are overwritten by actual register values on syscall
+ exit. */
+ case PTRACE_POKEUSR:
+ /* Some register values written here may be ignored in
+ * entry.S:syscall_restore_rfi; e.g. iaoq is written with
+ * r31/r31+4, and not with the values in pt_regs.
+ */
+ if (addr == PT_PSW) {
+ /* Since PT_PSW==0, it is valid for 32 bit processes
+ * under 64 bit kernels as well.
+ */
+ ret = arch_ptrace(child, request, addr, data);
+ } else {
+ if (addr & (sizeof(compat_uint_t)-1))
+ break;
+ addr = translate_usr_offset(addr);
+ if (addr >= sizeof(struct pt_regs))
+ break;
+ if (addr == PT_IAOQ0+4 || addr == PT_IAOQ1+4) {
+ data |= PRIV_USER; /* ensure userspace privilege */
+ }
+ if (addr >= PT_FR0 && addr <= PT_FR31 + 4) {
+ /* Special case, fp regs are 64 bits anyway */
+ *(__u32 *) ((char *) task_regs(child) + addr) = data;
+ ret = 0;
+ }
+ else if ((addr >= PT_GR1+4 && addr <= PT_GR31+4) ||
+ addr == PT_IAOQ0+4 || addr == PT_IAOQ1+4 ||
+ addr == PT_SAR+4) {
+ /* Zero the top 32 bits */
+ *(__u32 *) ((char *) task_regs(child) + addr - 4) = 0;
+ *(__u32 *) ((char *) task_regs(child) + addr) = data;
+ ret = 0;
+ }
+ }
+ break;
+ case PTRACE_GETREGS:
+ case PTRACE_SETREGS:
+ case PTRACE_GETFPREGS:
+ case PTRACE_SETFPREGS:
+ return arch_ptrace(child, request, addr, data);
+
+ default:
+ ret = compat_ptrace_request(child, request, addr, data);
+ break;
+ }
+
+ return ret;
+}
+#endif
+
+long do_syscall_trace_enter(struct pt_regs *regs)
+{
+ if (test_thread_flag(TIF_SYSCALL_TRACE)) {
+ int rc = ptrace_report_syscall_entry(regs);
+
+ /*
+ * As tracesys_next does not set %r28 to -ENOSYS
+ * when %r20 is set to -1, initialize it here.
+ */
+ regs->gr[28] = -ENOSYS;
+
+ if (rc) {
+ /*
+ * A nonzero return code from
+ * ptrace_report_syscall_entry() tells us
+ * to prevent the syscall execution. Skip
+ * the syscall call and the syscall restart handling.
+ *
+ * Note that the tracer may also just change
+ * regs->gr[20] to an invalid syscall number,
+ * that is handled by tracesys_next.
+ */
+ regs->gr[20] = -1UL;
+ return -1;
+ }
+ }
+
+ /* Do the secure computing check after ptrace. */
+ if (secure_computing() == -1)
+ return -1;
+
+#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS
+ if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
+ trace_sys_enter(regs, regs->gr[20]);
+#endif
+
+#ifdef CONFIG_64BIT
+ if (!is_compat_task())
+ audit_syscall_entry(regs->gr[20], regs->gr[26], regs->gr[25],
+ regs->gr[24], regs->gr[23]);
+ else
+#endif
+ audit_syscall_entry(regs->gr[20] & 0xffffffff,
+ regs->gr[26] & 0xffffffff,
+ regs->gr[25] & 0xffffffff,
+ regs->gr[24] & 0xffffffff,
+ regs->gr[23] & 0xffffffff);
+
+ /*
+ * Sign extend the syscall number to 64bit since it may have been
+ * modified by a compat ptrace call
+ */
+ return (int) ((u32) regs->gr[20]);
+}
+
+void do_syscall_trace_exit(struct pt_regs *regs)
+{
+ int stepping = test_thread_flag(TIF_SINGLESTEP) ||
+ test_thread_flag(TIF_BLOCKSTEP);
+
+ audit_syscall_exit(regs);
+
+#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS
+ if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
+ trace_sys_exit(regs, regs->gr[20]);
+#endif
+
+ if (stepping || test_thread_flag(TIF_SYSCALL_TRACE))
+ ptrace_report_syscall_exit(regs, stepping);
+}
+
+
+/*
+ * regset functions.
+ */
+
+static int fpr_get(struct task_struct *target,
+ const struct user_regset *regset,
+ struct membuf to)
+{
+ struct pt_regs *regs = task_regs(target);
+
+ return membuf_write(&to, regs->fr, ELF_NFPREG * sizeof(__u64));
+}
+
+static int fpr_set(struct task_struct *target,
+ const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ const void *kbuf, const void __user *ubuf)
+{
+ struct pt_regs *regs = task_regs(target);
+ const __u64 *k = kbuf;
+ const __u64 __user *u = ubuf;
+ __u64 reg;
+
+ pos /= sizeof(reg);
+ count /= sizeof(reg);
+
+ if (kbuf)
+ for (; count > 0 && pos < ELF_NFPREG; --count)
+ regs->fr[pos++] = *k++;
+ else
+ for (; count > 0 && pos < ELF_NFPREG; --count) {
+ if (__get_user(reg, u++))
+ return -EFAULT;
+ regs->fr[pos++] = reg;
+ }
+
+ kbuf = k;
+ ubuf = u;
+ pos *= sizeof(reg);
+ count *= sizeof(reg);
+ user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+ ELF_NFPREG * sizeof(reg), -1);
+ return 0;
+}
+
+#define RI(reg) (offsetof(struct user_regs_struct,reg) / sizeof(long))
+
+static unsigned long get_reg(struct pt_regs *regs, int num)
+{
+ switch (num) {
+ case RI(gr[0]) ... RI(gr[31]): return regs->gr[num - RI(gr[0])];
+ case RI(sr[0]) ... RI(sr[7]): return regs->sr[num - RI(sr[0])];
+ case RI(iasq[0]): return regs->iasq[0];
+ case RI(iasq[1]): return regs->iasq[1];
+ case RI(iaoq[0]): return regs->iaoq[0];
+ case RI(iaoq[1]): return regs->iaoq[1];
+ case RI(sar): return regs->sar;
+ case RI(iir): return regs->iir;
+ case RI(isr): return regs->isr;
+ case RI(ior): return regs->ior;
+ case RI(ipsw): return regs->ipsw;
+ case RI(cr27): return regs->cr27;
+ case RI(cr0): return mfctl(0);
+ case RI(cr24): return mfctl(24);
+ case RI(cr25): return mfctl(25);
+ case RI(cr26): return mfctl(26);
+ case RI(cr28): return mfctl(28);
+ case RI(cr29): return mfctl(29);
+ case RI(cr30): return mfctl(30);
+ case RI(cr31): return mfctl(31);
+ case RI(cr8): return mfctl(8);
+ case RI(cr9): return mfctl(9);
+ case RI(cr12): return mfctl(12);
+ case RI(cr13): return mfctl(13);
+ case RI(cr10): return mfctl(10);
+ case RI(cr15): return mfctl(15);
+ default: return 0;
+ }
+}
+
+static void set_reg(struct pt_regs *regs, int num, unsigned long val)
+{
+ switch (num) {
+ case RI(gr[0]): /*
+ * PSW is in gr[0].
+ * Allow writing to Nullify, Divide-step-correction,
+ * and carry/borrow bits.
+ * BEWARE, if you set N, and then single step, it won't
+ * stop on the nullified instruction.
+ */
+ val &= USER_PSW_BITS;
+ regs->gr[0] &= ~USER_PSW_BITS;
+ regs->gr[0] |= val;
+ return;
+ case RI(gr[1]) ... RI(gr[31]):
+ regs->gr[num - RI(gr[0])] = val;
+ return;
+ case RI(iaoq[0]):
+ case RI(iaoq[1]):
+ /* set 2 lowest bits to ensure userspace privilege: */
+ regs->iaoq[num - RI(iaoq[0])] = val | PRIV_USER;
+ return;
+ case RI(sar): regs->sar = val;
+ return;
+ default: return;
+#if 0
+ /* do not allow to change any of the following registers (yet) */
+ case RI(sr[0]) ... RI(sr[7]): return regs->sr[num - RI(sr[0])];
+ case RI(iasq[0]): return regs->iasq[0];
+ case RI(iasq[1]): return regs->iasq[1];
+ case RI(iir): return regs->iir;
+ case RI(isr): return regs->isr;
+ case RI(ior): return regs->ior;
+ case RI(ipsw): return regs->ipsw;
+ case RI(cr27): return regs->cr27;
+ case cr0, cr24, cr25, cr26, cr27, cr28, cr29, cr30, cr31;
+ case cr8, cr9, cr12, cr13, cr10, cr15;
+#endif
+ }
+}
+
+static int gpr_get(struct task_struct *target,
+ const struct user_regset *regset,
+ struct membuf to)
+{
+ struct pt_regs *regs = task_regs(target);
+ unsigned int pos;
+
+ for (pos = 0; pos < ELF_NGREG; pos++)
+ membuf_store(&to, get_reg(regs, pos));
+ return 0;
+}
+
+static int gpr_set(struct task_struct *target,
+ const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ const void *kbuf, const void __user *ubuf)
+{
+ struct pt_regs *regs = task_regs(target);
+ const unsigned long *k = kbuf;
+ const unsigned long __user *u = ubuf;
+ unsigned long reg;
+
+ pos /= sizeof(reg);
+ count /= sizeof(reg);
+
+ if (kbuf)
+ for (; count > 0 && pos < ELF_NGREG; --count)
+ set_reg(regs, pos++, *k++);
+ else
+ for (; count > 0 && pos < ELF_NGREG; --count) {
+ if (__get_user(reg, u++))
+ return -EFAULT;
+ set_reg(regs, pos++, reg);
+ }
+
+ kbuf = k;
+ ubuf = u;
+ pos *= sizeof(reg);
+ count *= sizeof(reg);
+ user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+ ELF_NGREG * sizeof(reg), -1);
+ return 0;
+}
+
+static const struct user_regset native_regsets[] = {
+ [REGSET_GENERAL] = {
+ .core_note_type = NT_PRSTATUS, .n = ELF_NGREG,
+ .size = sizeof(long), .align = sizeof(long),
+ .regset_get = gpr_get, .set = gpr_set
+ },
+ [REGSET_FP] = {
+ .core_note_type = NT_PRFPREG, .n = ELF_NFPREG,
+ .size = sizeof(__u64), .align = sizeof(__u64),
+ .regset_get = fpr_get, .set = fpr_set
+ }
+};
+
+static const struct user_regset_view user_parisc_native_view = {
+ .name = "parisc", .e_machine = ELF_ARCH, .ei_osabi = ELFOSABI_LINUX,
+ .regsets = native_regsets, .n = ARRAY_SIZE(native_regsets)
+};
+
+#ifdef CONFIG_64BIT
+static int gpr32_get(struct task_struct *target,
+ const struct user_regset *regset,
+ struct membuf to)
+{
+ struct pt_regs *regs = task_regs(target);
+ unsigned int pos;
+
+ for (pos = 0; pos < ELF_NGREG; pos++)
+ membuf_store(&to, (compat_ulong_t)get_reg(regs, pos));
+
+ return 0;
+}
+
+static int gpr32_set(struct task_struct *target,
+ const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ const void *kbuf, const void __user *ubuf)
+{
+ struct pt_regs *regs = task_regs(target);
+ const compat_ulong_t *k = kbuf;
+ const compat_ulong_t __user *u = ubuf;
+ compat_ulong_t reg;
+
+ pos /= sizeof(reg);
+ count /= sizeof(reg);
+
+ if (kbuf)
+ for (; count > 0 && pos < ELF_NGREG; --count)
+ set_reg(regs, pos++, *k++);
+ else
+ for (; count > 0 && pos < ELF_NGREG; --count) {
+ if (__get_user(reg, u++))
+ return -EFAULT;
+ set_reg(regs, pos++, reg);
+ }
+
+ kbuf = k;
+ ubuf = u;
+ pos *= sizeof(reg);
+ count *= sizeof(reg);
+ user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+ ELF_NGREG * sizeof(reg), -1);
+ return 0;
+}
+
+/*
+ * These are the regset flavors matching the 32bit native set.
+ */
+static const struct user_regset compat_regsets[] = {
+ [REGSET_GENERAL] = {
+ .core_note_type = NT_PRSTATUS, .n = ELF_NGREG,
+ .size = sizeof(compat_long_t), .align = sizeof(compat_long_t),
+ .regset_get = gpr32_get, .set = gpr32_set
+ },
+ [REGSET_FP] = {
+ .core_note_type = NT_PRFPREG, .n = ELF_NFPREG,
+ .size = sizeof(__u64), .align = sizeof(__u64),
+ .regset_get = fpr_get, .set = fpr_set
+ }
+};
+
+static const struct user_regset_view user_parisc_compat_view = {
+ .name = "parisc", .e_machine = EM_PARISC, .ei_osabi = ELFOSABI_LINUX,
+ .regsets = compat_regsets, .n = ARRAY_SIZE(compat_regsets)
+};
+#endif /* CONFIG_64BIT */
+
+const struct user_regset_view *task_user_regset_view(struct task_struct *task)
+{
+ BUILD_BUG_ON(sizeof(struct user_regs_struct)/sizeof(long) != ELF_NGREG);
+ BUILD_BUG_ON(sizeof(struct user_fp_struct)/sizeof(__u64) != ELF_NFPREG);
+#ifdef CONFIG_64BIT
+ if (is_compat_task())
+ return &user_parisc_compat_view;
+#endif
+ return &user_parisc_native_view;
+}
+
+
+/* HAVE_REGS_AND_STACK_ACCESS_API feature */
+
+struct pt_regs_offset {
+ const char *name;
+ int offset;
+};
+
+#define REG_OFFSET_NAME(r) {.name = #r, .offset = offsetof(struct pt_regs, r)}
+#define REG_OFFSET_INDEX(r,i) {.name = #r#i, .offset = offsetof(struct pt_regs, r[i])}
+#define REG_OFFSET_END {.name = NULL, .offset = 0}
+
+static const struct pt_regs_offset regoffset_table[] = {
+ REG_OFFSET_INDEX(gr,0),
+ REG_OFFSET_INDEX(gr,1),
+ REG_OFFSET_INDEX(gr,2),
+ REG_OFFSET_INDEX(gr,3),
+ REG_OFFSET_INDEX(gr,4),
+ REG_OFFSET_INDEX(gr,5),
+ REG_OFFSET_INDEX(gr,6),
+ REG_OFFSET_INDEX(gr,7),
+ REG_OFFSET_INDEX(gr,8),
+ REG_OFFSET_INDEX(gr,9),
+ REG_OFFSET_INDEX(gr,10),
+ REG_OFFSET_INDEX(gr,11),
+ REG_OFFSET_INDEX(gr,12),
+ REG_OFFSET_INDEX(gr,13),
+ REG_OFFSET_INDEX(gr,14),
+ REG_OFFSET_INDEX(gr,15),
+ REG_OFFSET_INDEX(gr,16),
+ REG_OFFSET_INDEX(gr,17),
+ REG_OFFSET_INDEX(gr,18),
+ REG_OFFSET_INDEX(gr,19),
+ REG_OFFSET_INDEX(gr,20),
+ REG_OFFSET_INDEX(gr,21),
+ REG_OFFSET_INDEX(gr,22),
+ REG_OFFSET_INDEX(gr,23),
+ REG_OFFSET_INDEX(gr,24),
+ REG_OFFSET_INDEX(gr,25),
+ REG_OFFSET_INDEX(gr,26),
+ REG_OFFSET_INDEX(gr,27),
+ REG_OFFSET_INDEX(gr,28),
+ REG_OFFSET_INDEX(gr,29),
+ REG_OFFSET_INDEX(gr,30),
+ REG_OFFSET_INDEX(gr,31),
+ REG_OFFSET_INDEX(sr,0),
+ REG_OFFSET_INDEX(sr,1),
+ REG_OFFSET_INDEX(sr,2),
+ REG_OFFSET_INDEX(sr,3),
+ REG_OFFSET_INDEX(sr,4),
+ REG_OFFSET_INDEX(sr,5),
+ REG_OFFSET_INDEX(sr,6),
+ REG_OFFSET_INDEX(sr,7),
+ REG_OFFSET_INDEX(iasq,0),
+ REG_OFFSET_INDEX(iasq,1),
+ REG_OFFSET_INDEX(iaoq,0),
+ REG_OFFSET_INDEX(iaoq,1),
+ REG_OFFSET_NAME(cr27),
+ REG_OFFSET_NAME(ksp),
+ REG_OFFSET_NAME(kpc),
+ REG_OFFSET_NAME(sar),
+ REG_OFFSET_NAME(iir),
+ REG_OFFSET_NAME(isr),
+ REG_OFFSET_NAME(ior),
+ REG_OFFSET_NAME(ipsw),
+ REG_OFFSET_END,
+};
+
+/**
+ * regs_query_register_offset() - query register offset from its name
+ * @name: the name of a register
+ *
+ * regs_query_register_offset() returns the offset of a register in struct
+ * pt_regs from its name. If the name is invalid, this returns -EINVAL;
+ */
+int regs_query_register_offset(const char *name)
+{
+ const struct pt_regs_offset *roff;
+ for (roff = regoffset_table; roff->name != NULL; roff++)
+ if (!strcmp(roff->name, name))
+ return roff->offset;
+ return -EINVAL;
+}
+
+/**
+ * regs_query_register_name() - query register name from its offset
+ * @offset: the offset of a register in struct pt_regs.
+ *
+ * regs_query_register_name() returns the name of a register from its
+ * offset in struct pt_regs. If the @offset is invalid, this returns NULL;
+ */
+const char *regs_query_register_name(unsigned int offset)
+{
+ const struct pt_regs_offset *roff;
+ for (roff = regoffset_table; roff->name != NULL; roff++)
+ if (roff->offset == offset)
+ return roff->name;
+ return NULL;
+}
+
+/**
+ * regs_within_kernel_stack() - check the address in the stack
+ * @regs: pt_regs which contains kernel stack pointer.
+ * @addr: address which is checked.
+ *
+ * regs_within_kernel_stack() checks @addr is within the kernel stack page(s).
+ * If @addr is within the kernel stack, it returns true. If not, returns false.
+ */
+int regs_within_kernel_stack(struct pt_regs *regs, unsigned long addr)
+{
+ return ((addr & ~(THREAD_SIZE - 1)) ==
+ (kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1)));
+}
+
+/**
+ * regs_get_kernel_stack_nth() - get Nth entry of the stack
+ * @regs: pt_regs which contains kernel stack pointer.
+ * @n: stack entry number.
+ *
+ * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which
+ * is specified by @regs. If the @n th entry is NOT in the kernel stack,
+ * this returns 0.
+ */
+unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, unsigned int n)
+{
+ unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs);
+
+ addr -= n;
+
+ if (!regs_within_kernel_stack(regs, (unsigned long)addr))
+ return 0;
+
+ return *addr;
+}
diff --git a/arch/parisc/kernel/real2.S b/arch/parisc/kernel/real2.S
new file mode 100644
index 000000000..509d18b8e
--- /dev/null
+++ b/arch/parisc/kernel/real2.S
@@ -0,0 +1,292 @@
+/*
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2000 Hewlett Packard (Paul Bame bame@puffin.external.hp.com)
+ *
+ */
+
+#include <asm/pdc.h>
+#include <asm/psw.h>
+#include <asm/assembly.h>
+#include <asm/asm-offsets.h>
+
+#include <linux/linkage.h>
+
+ .export real_stack
+ .export real64_stack
+ __PAGE_ALIGNED_BSS
+real_stack:
+real64_stack:
+ .block 8192
+
+#define N_SAVED_REGS 9
+ .section .bss
+save_cr_space:
+ .block REG_SZ * N_SAVED_REGS
+save_cr_end:
+
+
+/************************ 32-bit real-mode calls ***********************/
+/* This can be called in both narrow and wide kernels */
+
+ .text
+
+ /* unsigned long real32_call_asm(unsigned int *sp,
+ * unsigned int *arg0p,
+ * unsigned int iodc_fn)
+ * sp is value of stack pointer to adopt before calling PDC (virt)
+ * arg0p points to where saved arg values may be found
+ * iodc_fn is the IODC function to call
+ */
+
+ENTRY_CFI(real32_call_asm)
+ STREG %rp, -RP_OFFSET(%sp) /* save RP */
+#ifdef CONFIG_64BIT
+ callee_save
+ ldo 2*REG_SZ(%sp), %sp /* room for a couple more saves */
+ STREG %r27, -1*REG_SZ(%sp)
+ STREG %r29, -2*REG_SZ(%sp)
+#endif
+ STREG %sp, -REG_SZ(%arg0) /* save SP on real-mode stack */
+ copy %arg0, %sp /* adopt the real-mode SP */
+
+ /* save iodc_fn */
+ copy %arg2, %r31
+
+ /* load up the arg registers from the saved arg area */
+ /* 32-bit calling convention passes first 4 args in registers */
+ ldw 0(%arg1), %arg0 /* note overwriting arg0 */
+ ldw -8(%arg1), %arg2
+ ldw -12(%arg1), %arg3
+ ldw -4(%arg1), %arg1 /* obviously must do this one last! */
+
+ tophys_r1 %sp
+
+ b,l rfi_virt2real,%r2
+ nop
+
+ b,l save_control_regs,%r2 /* modifies r1, r2, r28 */
+ nop
+
+#ifdef CONFIG_64BIT
+ rsm PSW_SM_W, %r0 /* go narrow */
+#endif
+
+ load32 PA(ric_ret), %r2
+ bv 0(%r31)
+ nop
+ric_ret:
+#ifdef CONFIG_64BIT
+ ssm PSW_SM_W, %r0 /* go wide */
+#endif
+ /* restore CRs before going virtual in case we page fault */
+ b,l restore_control_regs, %r2 /* modifies r1, r2, r26 */
+ nop
+
+ b,l rfi_real2virt,%r2
+ nop
+
+ tovirt_r1 %sp
+ LDREG -REG_SZ(%sp), %sp /* restore SP */
+#ifdef CONFIG_64BIT
+ LDREG -1*REG_SZ(%sp), %r27
+ LDREG -2*REG_SZ(%sp), %r29
+ ldo -2*REG_SZ(%sp), %sp
+ callee_rest
+#endif
+ LDREG -RP_OFFSET(%sp), %rp /* restore RP */
+ bv 0(%rp)
+ nop
+ENDPROC_CFI(real32_call_asm)
+
+
+# define PUSH_CR(r, where) mfctl r, %r1 ! STREG,ma %r1, REG_SZ(where)
+# define POP_CR(r, where) LDREG,mb -REG_SZ(where), %r1 ! mtctl %r1, r
+
+ .text
+ENTRY_CFI(save_control_regs)
+ load32 PA(save_cr_space), %r28
+ PUSH_CR(%cr24, %r28)
+ PUSH_CR(%cr25, %r28)
+ PUSH_CR(%cr26, %r28)
+ PUSH_CR(%cr27, %r28)
+ PUSH_CR(%cr28, %r28)
+ PUSH_CR(%cr29, %r28)
+ PUSH_CR(%cr30, %r28)
+ PUSH_CR(%cr31, %r28)
+ PUSH_CR(%cr15, %r28)
+ bv 0(%r2)
+ nop
+ENDPROC_CFI(save_control_regs)
+
+ENTRY_CFI(restore_control_regs)
+ load32 PA(save_cr_end), %r26
+ POP_CR(%cr15, %r26)
+ POP_CR(%cr31, %r26)
+ POP_CR(%cr30, %r26)
+ POP_CR(%cr29, %r26)
+ POP_CR(%cr28, %r26)
+ POP_CR(%cr27, %r26)
+ POP_CR(%cr26, %r26)
+ POP_CR(%cr25, %r26)
+ POP_CR(%cr24, %r26)
+ bv 0(%r2)
+ nop
+ENDPROC_CFI(restore_control_regs)
+
+/* rfi_virt2real() and rfi_real2virt() could perhaps be adapted for
+ * more general-purpose use by the several places which need RFIs
+ */
+ .text
+ .align 128
+ENTRY_CFI(rfi_virt2real)
+#if !defined(BOOTLOADER)
+ /* switch to real mode... */
+ rsm PSW_SM_I,%r0
+ load32 PA(rfi_v2r_1), %r1
+ nop
+ nop
+ nop
+ nop
+ nop
+
+ rsm PSW_SM_Q,%r0 /* disable Q & I bits to load iia queue */
+ mtctl %r0, %cr17 /* Clear IIASQ tail */
+ mtctl %r0, %cr17 /* Clear IIASQ head */
+ mtctl %r1, %cr18 /* IIAOQ head */
+ ldo 4(%r1), %r1
+ mtctl %r1, %cr18 /* IIAOQ tail */
+ load32 REAL_MODE_PSW, %r1
+ mtctl %r1, %cr22
+ rfi
+
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+rfi_v2r_1:
+ tophys_r1 %r2
+#endif /* defined(BOOTLOADER) */
+ bv 0(%r2)
+ nop
+ENDPROC_CFI(rfi_virt2real)
+
+ .text
+ .align 128
+ENTRY_CFI(rfi_real2virt)
+#if !defined(BOOTLOADER)
+ rsm PSW_SM_I,%r0
+ load32 (rfi_r2v_1), %r1
+ nop
+ nop
+ nop
+ nop
+ nop
+
+ rsm PSW_SM_Q,%r0 /* disable Q bit to load iia queue */
+ mtctl %r0, %cr17 /* Clear IIASQ tail */
+ mtctl %r0, %cr17 /* Clear IIASQ head */
+ mtctl %r1, %cr18 /* IIAOQ head */
+ ldo 4(%r1), %r1
+ mtctl %r1, %cr18 /* IIAOQ tail */
+ load32 KERNEL_PSW, %r1
+ mtctl %r1, %cr22
+ rfi
+
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+rfi_r2v_1:
+ tovirt_r1 %r2
+#endif /* defined(BOOTLOADER) */
+ bv 0(%r2)
+ nop
+ENDPROC_CFI(rfi_real2virt)
+
+#ifdef CONFIG_64BIT
+
+/************************ 64-bit real-mode calls ***********************/
+/* This is only usable in wide kernels right now and will probably stay so */
+ .text
+ /* unsigned long real64_call_asm(unsigned long *sp,
+ * unsigned long *arg0p,
+ * unsigned long fn)
+ * sp is value of stack pointer to adopt before calling PDC (virt)
+ * arg0p points to where saved arg values may be found
+ * iodc_fn is the IODC function to call
+ */
+ENTRY_CFI(real64_call_asm)
+ std %rp, -0x10(%sp) /* save RP */
+ std %sp, -8(%arg0) /* save SP on real-mode stack */
+ copy %arg0, %sp /* adopt the real-mode SP */
+
+ /* save fn */
+ copy %arg2, %r31
+
+ /* load up the arg registers from the saved arg area */
+ /* 32-bit calling convention passes first 4 args in registers */
+ ldd 0*REG_SZ(%arg1), %arg0 /* note overwriting arg0 */
+ ldd 2*REG_SZ(%arg1), %arg2
+ ldd 3*REG_SZ(%arg1), %arg3
+ ldd 4*REG_SZ(%arg1), %r22
+ ldd 5*REG_SZ(%arg1), %r21
+ ldd 6*REG_SZ(%arg1), %r20
+ ldd 7*REG_SZ(%arg1), %r19
+ ldd 1*REG_SZ(%arg1), %arg1 /* do this one last! */
+
+ /* set up real-mode stack and real-mode ap */
+ tophys_r1 %sp
+ ldo -16(%sp), %r29 /* Reference param save area */
+
+ b,l rfi_virt2real,%r2
+ nop
+
+ b,l save_control_regs,%r2 /* modifies r1, r2, r28 */
+ nop
+
+ load32 PA(r64_ret), %r2
+ bv 0(%r31)
+ nop
+r64_ret:
+ /* restore CRs before going virtual in case we page fault */
+ b,l restore_control_regs, %r2 /* modifies r1, r2, r26 */
+ nop
+
+ b,l rfi_real2virt,%r2
+ nop
+
+ tovirt_r1 %sp
+ ldd -8(%sp), %sp /* restore SP */
+ ldd -0x10(%sp), %rp /* restore RP */
+ bv 0(%rp)
+ nop
+ENDPROC_CFI(real64_call_asm)
+
+#endif
+
+ .text
+ /* http://lists.parisc-linux.org/hypermail/parisc-linux/10916.html
+ ** GCC 3.3 and later has a new function in libgcc.a for
+ ** comparing function pointers.
+ */
+ENTRY_CFI(__canonicalize_funcptr_for_compare)
+#ifdef CONFIG_64BIT
+ bve (%r2)
+#else
+ bv %r0(%r2)
+#endif
+ copy %r26,%r28
+ENDPROC_CFI(__canonicalize_funcptr_for_compare)
+
diff --git a/arch/parisc/kernel/relocate_kernel.S b/arch/parisc/kernel/relocate_kernel.S
new file mode 100644
index 000000000..2561e52b8
--- /dev/null
+++ b/arch/parisc/kernel/relocate_kernel.S
@@ -0,0 +1,149 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#include <linux/linkage.h>
+#include <linux/kexec.h>
+
+#include <asm/assembly.h>
+#include <asm/asm-offsets.h>
+#include <asm/page.h>
+#include <asm/setup.h>
+#include <asm/psw.h>
+
+.level PA_ASM_LEVEL
+
+.macro kexec_param name
+.align 8
+ENTRY(kexec\()_\name)
+#ifdef CONFIG_64BIT
+ .dword 0
+#else
+ .word 0
+#endif
+
+ENTRY(kexec\()_\name\()_offset)
+ .word kexec\()_\name - relocate_new_kernel
+.endm
+
+.text
+
+/* args:
+ * r26 - kimage->head
+ * r25 - start address of kernel
+ * r24 - physical address of relocate code
+ */
+
+ENTRY_CFI(relocate_new_kernel)
+0: copy %arg1, %rp
+ /* disable I and Q bit, so we are allowed to execute RFI */
+ rsm PSW_SM_I, %r0
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+
+ rsm PSW_SM_Q, %r0
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+
+ /*
+ * After return-from-interrupt, we want to run without Code/Data
+ * translation enabled just like on a normal boot.
+ */
+
+ /* calculate new physical execution address */
+ ldo 1f-0b(%arg2), %r1
+ mtctl %r0, %cr17 /* IIASQ */
+ mtctl %r0, %cr17 /* IIASQ */
+ mtctl %r1, %cr18 /* IIAOQ */
+ ldo 4(%r1),%r1
+ mtctl %r1, %cr18 /* IIAOQ */
+#ifdef CONFIG_64BIT
+ depdi,z 1, PSW_W_BIT, 1, %r1
+ mtctl %r1, %cr22 /* IPSW */
+#else
+ mtctl %r0, %cr22 /* IPSW */
+#endif
+ /* lets go... */
+ rfi
+1: nop
+ nop
+
+.Lloop:
+ LDREG,ma REG_SZ(%arg0), %r3
+ /* If crash kernel, no copy needed */
+ cmpib,COND(=),n 0,%r3,boot
+
+ bb,<,n %r3, 31 - IND_DONE_BIT, boot
+ bb,>=,n %r3, 31 - IND_INDIRECTION_BIT, .Lnotind
+ /* indirection, load and restart */
+ movb %r3, %arg0, .Lloop
+ depi 0, 31, PAGE_SHIFT, %arg0
+
+.Lnotind:
+ bb,>=,n %r3, 31 - IND_DESTINATION_BIT, .Lnotdest
+ b .Lloop
+ copy %r3, %r20
+
+.Lnotdest:
+ bb,>= %r3, 31 - IND_SOURCE_BIT, .Lloop
+ depi 0, 31, PAGE_SHIFT, %r3
+ copy %r3, %r21
+
+ /* copy page */
+ copy %r0, %r18
+ zdepi 1, 31 - PAGE_SHIFT, 1, %r18
+ add %r20, %r18, %r17
+
+ depi 0, 31, PAGE_SHIFT, %r20
+.Lcopy:
+ copy %r20, %r12
+ LDREG,ma REG_SZ(%r21), %r8
+ LDREG,ma REG_SZ(%r21), %r9
+ LDREG,ma REG_SZ(%r21), %r10
+ LDREG,ma REG_SZ(%r21), %r11
+ STREG,ma %r8, REG_SZ(%r20)
+ STREG,ma %r9, REG_SZ(%r20)
+ STREG,ma %r10, REG_SZ(%r20)
+ STREG,ma %r11, REG_SZ(%r20)
+
+#ifndef CONFIG_64BIT
+ LDREG,ma REG_SZ(%r21), %r8
+ LDREG,ma REG_SZ(%r21), %r9
+ LDREG,ma REG_SZ(%r21), %r10
+ LDREG,ma REG_SZ(%r21), %r11
+ STREG,ma %r8, REG_SZ(%r20)
+ STREG,ma %r9, REG_SZ(%r20)
+ STREG,ma %r10, REG_SZ(%r20)
+ STREG,ma %r11, REG_SZ(%r20)
+#endif
+
+ fdc %r0(%r12)
+ cmpb,COND(<<) %r20,%r17,.Lcopy
+ fic (%sr4, %r12)
+ b,n .Lloop
+
+boot:
+ mtctl %r0, %cr15
+
+ LDREG kexec_free_mem-0b(%arg2), %arg0
+ LDREG kexec_cmdline-0b(%arg2), %arg1
+ LDREG kexec_initrd_end-0b(%arg2), %arg3
+ LDREG kexec_initrd_start-0b(%arg2), %arg2
+ bv,n %r0(%rp)
+
+ENDPROC_CFI(relocate_new_kernel);
+
+ENTRY(relocate_new_kernel_size)
+ .word relocate_new_kernel_size - relocate_new_kernel
+
+kexec_param cmdline
+kexec_param initrd_start
+kexec_param initrd_end
+kexec_param free_mem
diff --git a/arch/parisc/kernel/setup.c b/arch/parisc/kernel/setup.c
new file mode 100644
index 000000000..2f434f2da
--- /dev/null
+++ b/arch/parisc/kernel/setup.c
@@ -0,0 +1,310 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Initial setup-routines for HP 9000 based hardware.
+ *
+ * Copyright (C) 1991, 1992, 1995 Linus Torvalds
+ * Modifications for PA-RISC (C) 1999 Helge Deller <deller@gmx.de>
+ * Modifications copyright 1999 SuSE GmbH (Philipp Rumpf)
+ * Modifications copyright 2000 Martin K. Petersen <mkp@mkp.net>
+ * Modifications copyright 2000 Philipp Rumpf <prumpf@tux.org>
+ * Modifications copyright 2001 Ryan Bradetich <rbradetich@uswest.net>
+ *
+ * Initial PA-RISC Version: 04-23-1999 by Helge Deller
+ */
+
+#include <linux/kernel.h>
+#include <linux/initrd.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/seq_file.h>
+#define PCI_DEBUG
+#include <linux/pci.h>
+#undef PCI_DEBUG
+#include <linux/proc_fs.h>
+#include <linux/export.h>
+#include <linux/sched.h>
+#include <linux/sched/clock.h>
+#include <linux/start_kernel.h>
+
+#include <asm/cacheflush.h>
+#include <asm/processor.h>
+#include <asm/sections.h>
+#include <asm/pdc.h>
+#include <asm/led.h>
+#include <asm/pdc_chassis.h>
+#include <asm/io.h>
+#include <asm/setup.h>
+#include <asm/unwind.h>
+#include <asm/smp.h>
+
+static char __initdata command_line[COMMAND_LINE_SIZE];
+
+static void __init setup_cmdline(char **cmdline_p)
+{
+ extern unsigned int boot_args[];
+ char *p;
+
+ *cmdline_p = command_line;
+
+ /* boot_args[0] is free-mem start, boot_args[1] is ptr to command line */
+ if (boot_args[0] < 64)
+ return; /* return if called from hpux boot loader */
+
+ /* Collect stuff passed in from the boot loader */
+ strscpy(boot_command_line, (char *)__va(boot_args[1]),
+ COMMAND_LINE_SIZE);
+
+ /* autodetect console type (if not done by palo yet) */
+ p = boot_command_line;
+ if (!str_has_prefix(p, "console=") && !strstr(p, " console=")) {
+ strlcat(p, " console=", COMMAND_LINE_SIZE);
+ if (PAGE0->mem_cons.cl_class == CL_DUPLEX)
+ strlcat(p, "ttyS0", COMMAND_LINE_SIZE);
+ else
+ strlcat(p, "tty0", COMMAND_LINE_SIZE);
+ }
+
+ /* default to use early console */
+ if (!strstr(p, "earlycon"))
+ strlcat(p, " earlycon=pdc", COMMAND_LINE_SIZE);
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ /* did palo pass us a ramdisk? */
+ if (boot_args[2] != 0) {
+ initrd_start = (unsigned long)__va(boot_args[2]);
+ initrd_end = (unsigned long)__va(boot_args[3]);
+ }
+#endif
+
+ strscpy(command_line, boot_command_line, COMMAND_LINE_SIZE);
+}
+
+#ifdef CONFIG_PA11
+static void __init dma_ops_init(void)
+{
+ switch (boot_cpu_data.cpu_type) {
+ case pcx:
+ /*
+ * We've got way too many dependencies on 1.1 semantics
+ * to support 1.0 boxes at this point.
+ */
+ panic( "PA-RISC Linux currently only supports machines that conform to\n"
+ "the PA-RISC 1.1 or 2.0 architecture specification.\n");
+
+ case pcxl2:
+ default:
+ break;
+ }
+}
+#endif
+
+void __init setup_arch(char **cmdline_p)
+{
+#ifdef CONFIG_64BIT
+ extern int parisc_narrow_firmware;
+#endif
+ unwind_init();
+
+ init_per_cpu(smp_processor_id()); /* Set Modes & Enable FP */
+
+#ifdef CONFIG_64BIT
+ printk(KERN_INFO "The 64-bit Kernel has started...\n");
+#else
+ printk(KERN_INFO "The 32-bit Kernel has started...\n");
+#endif
+
+ printk(KERN_INFO "Kernel default page size is %d KB. Huge pages ",
+ (int)(PAGE_SIZE / 1024));
+#ifdef CONFIG_HUGETLB_PAGE
+ printk(KERN_CONT "enabled with %d MB physical and %d MB virtual size",
+ 1 << (REAL_HPAGE_SHIFT - 20), 1 << (HPAGE_SHIFT - 20));
+#else
+ printk(KERN_CONT "disabled");
+#endif
+ printk(KERN_CONT ".\n");
+
+ /*
+ * Check if initial kernel page mappings are sufficient.
+ * panic early if not, else we may access kernel functions
+ * and variables which can't be reached.
+ */
+ if (__pa((unsigned long) &_end) >= KERNEL_INITIAL_SIZE)
+ panic("KERNEL_INITIAL_ORDER too small!");
+
+#ifdef CONFIG_64BIT
+ if(parisc_narrow_firmware) {
+ printk(KERN_INFO "Kernel is using PDC in 32-bit mode.\n");
+ }
+#endif
+ setup_pdc();
+ setup_cmdline(cmdline_p);
+ collect_boot_cpu_data();
+ do_memory_inventory(); /* probe for physical memory */
+ parisc_cache_init();
+ paging_init();
+
+#ifdef CONFIG_PA11
+ dma_ops_init();
+#endif
+
+ clear_sched_clock_stable();
+}
+
+/*
+ * Display CPU info for all CPUs.
+ */
+static void *
+c_start (struct seq_file *m, loff_t *pos)
+{
+ /* Looks like the caller will call repeatedly until we return
+ * 0, signaling EOF perhaps. This could be used to sequence
+ * through CPUs for example. Since we print all cpu info in our
+ * show_cpuinfo() disregarding 'pos' (which I assume is 'v' above)
+ * we only allow for one "position". */
+ return ((long)*pos < 1) ? (void *)1 : NULL;
+}
+
+static void *
+c_next (struct seq_file *m, void *v, loff_t *pos)
+{
+ ++*pos;
+ return c_start(m, pos);
+}
+
+static void
+c_stop (struct seq_file *m, void *v)
+{
+}
+
+const struct seq_operations cpuinfo_op = {
+ .start = c_start,
+ .next = c_next,
+ .stop = c_stop,
+ .show = show_cpuinfo
+};
+
+static struct resource central_bus = {
+ .name = "Central Bus",
+ .start = F_EXTEND(0xfff80000),
+ .end = F_EXTEND(0xfffaffff),
+ .flags = IORESOURCE_MEM,
+};
+
+static struct resource local_broadcast = {
+ .name = "Local Broadcast",
+ .start = F_EXTEND(0xfffb0000),
+ .end = F_EXTEND(0xfffdffff),
+ .flags = IORESOURCE_MEM,
+};
+
+static struct resource global_broadcast = {
+ .name = "Global Broadcast",
+ .start = F_EXTEND(0xfffe0000),
+ .end = F_EXTEND(0xffffffff),
+ .flags = IORESOURCE_MEM,
+};
+
+static int __init parisc_init_resources(void)
+{
+ int result;
+
+ result = request_resource(&iomem_resource, &central_bus);
+ if (result < 0) {
+ printk(KERN_ERR
+ "%s: failed to claim %s address space!\n",
+ __FILE__, central_bus.name);
+ return result;
+ }
+
+ result = request_resource(&iomem_resource, &local_broadcast);
+ if (result < 0) {
+ printk(KERN_ERR
+ "%s: failed to claim %s address space!\n",
+ __FILE__, local_broadcast.name);
+ return result;
+ }
+
+ result = request_resource(&iomem_resource, &global_broadcast);
+ if (result < 0) {
+ printk(KERN_ERR
+ "%s: failed to claim %s address space!\n",
+ __FILE__, global_broadcast.name);
+ return result;
+ }
+
+ return 0;
+}
+
+static int __init parisc_init(void)
+{
+ u32 osid = (OS_ID_LINUX << 16);
+
+ parisc_init_resources();
+ do_device_inventory(); /* probe for hardware */
+
+ parisc_pdc_chassis_init();
+
+ /* set up a new led state on systems shipped LED State panel */
+ pdc_chassis_send_status(PDC_CHASSIS_DIRECT_BSTART);
+
+ /* tell PDC we're Linux. Nevermind failure. */
+ pdc_stable_write(0x40, &osid, sizeof(osid));
+
+ /* start with known state */
+ flush_cache_all_local();
+ flush_tlb_all_local(NULL);
+
+ processor_init();
+#ifdef CONFIG_SMP
+ pr_info("CPU(s): %d out of %d %s at %d.%06d MHz online\n",
+ num_online_cpus(), num_present_cpus(),
+#else
+ pr_info("CPU(s): 1 x %s at %d.%06d MHz\n",
+#endif
+ boot_cpu_data.cpu_name,
+ boot_cpu_data.cpu_hz / 1000000,
+ boot_cpu_data.cpu_hz % 1000000 );
+
+#if defined(CONFIG_64BIT) && defined(CONFIG_SMP)
+ /* Don't serialize TLB flushes if we run on one CPU only. */
+ if (num_online_cpus() == 1)
+ pa_serialize_tlb_flushes = 0;
+#endif
+
+ apply_alternatives_all();
+ parisc_setup_cache_timing();
+ return 0;
+}
+arch_initcall(parisc_init);
+
+void __init start_parisc(void)
+{
+ int ret, cpunum;
+ struct pdc_coproc_cfg coproc_cfg;
+
+ /* check QEMU/SeaBIOS marker in PAGE0 */
+ running_on_qemu = (memcmp(&PAGE0->pad0, "SeaBIOS", 8) == 0);
+
+ cpunum = smp_processor_id();
+
+ init_cpu_topology();
+
+ set_firmware_width_unlocked();
+
+ ret = pdc_coproc_cfg_unlocked(&coproc_cfg);
+ if (ret >= 0 && coproc_cfg.ccr_functional) {
+ mtctl(coproc_cfg.ccr_functional, 10);
+
+ per_cpu(cpu_data, cpunum).fp_rev = coproc_cfg.revision;
+ per_cpu(cpu_data, cpunum).fp_model = coproc_cfg.model;
+
+ asm volatile ("fstd %fr0,8(%sp)");
+ } else {
+ panic("must have an fpu to boot linux");
+ }
+
+ early_trap_init(); /* initialize checksum of fault_vector */
+
+ start_kernel();
+ // not reached
+}
diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c
new file mode 100644
index 000000000..e8d27def6
--- /dev/null
+++ b/arch/parisc/kernel/signal.c
@@ -0,0 +1,589 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * PA-RISC architecture-specific signal handling support.
+ *
+ * Copyright (C) 2000 David Huggins-Daines <dhd@debian.org>
+ * Copyright (C) 2000 Linuxcare, Inc.
+ * Copyright (C) 2000-2022 Helge Deller <deller@gmx.de>
+ * Copyright (C) 2022 John David Anglin <dave.anglin@bell.net>
+ *
+ * Based on the ia64, i386, and alpha versions.
+ */
+
+#include <linux/sched.h>
+#include <linux/sched/debug.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/ptrace.h>
+#include <linux/resume_user_mode.h>
+#include <linux/unistd.h>
+#include <linux/stddef.h>
+#include <linux/compat.h>
+#include <linux/elf.h>
+#include <asm/ucontext.h>
+#include <asm/rt_sigframe.h>
+#include <linux/uaccess.h>
+#include <asm/cacheflush.h>
+#include <asm/asm-offsets.h>
+#include <asm/vdso.h>
+
+#ifdef CONFIG_COMPAT
+#include "signal32.h"
+#endif
+
+#define DEBUG_SIG 0
+#define DEBUG_SIG_LEVEL 2
+
+#if DEBUG_SIG
+#define DBG(LEVEL, ...) \
+ ((DEBUG_SIG_LEVEL >= LEVEL) \
+ ? printk(__VA_ARGS__) : (void) 0)
+#else
+#define DBG(LEVEL, ...)
+#endif
+
+/* gcc will complain if a pointer is cast to an integer of different
+ * size. If you really need to do this (and we do for an ELF32 user
+ * application in an ELF64 kernel) then you have to do a cast to an
+ * integer of the same size first. The A() macro accomplishes
+ * this. */
+#define A(__x) ((unsigned long)(__x))
+
+/*
+ * Do a signal return - restore sigcontext.
+ */
+
+static long
+restore_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs)
+{
+ long err = 0;
+
+ err |= __copy_from_user(regs->gr, sc->sc_gr, sizeof(regs->gr));
+ err |= __copy_from_user(regs->fr, sc->sc_fr, sizeof(regs->fr));
+ err |= __copy_from_user(regs->iaoq, sc->sc_iaoq, sizeof(regs->iaoq));
+ err |= __copy_from_user(regs->iasq, sc->sc_iasq, sizeof(regs->iasq));
+ err |= __get_user(regs->sar, &sc->sc_sar);
+ DBG(2, "%s: iaoq is %#lx / %#lx\n",
+ __func__, regs->iaoq[0], regs->iaoq[1]);
+ DBG(2, "%s: r28 is %ld\n", __func__, regs->gr[28]);
+ return err;
+}
+
+asmlinkage void
+sys_rt_sigreturn(struct pt_regs *regs, int in_syscall)
+{
+ struct rt_sigframe __user *frame;
+ sigset_t set;
+ unsigned long usp = (regs->gr[30] & ~(0x01UL));
+ unsigned long sigframe_size = PARISC_RT_SIGFRAME_SIZE;
+#ifdef CONFIG_64BIT
+ struct compat_rt_sigframe __user * compat_frame;
+
+ if (is_compat_task())
+ sigframe_size = PARISC_RT_SIGFRAME_SIZE32;
+#endif
+
+ current->restart_block.fn = do_no_restart_syscall;
+
+ /* Unwind the user stack to get the rt_sigframe structure. */
+ frame = (struct rt_sigframe __user *)
+ (usp - sigframe_size);
+ DBG(2, "%s: frame is %p pid %d\n", __func__, frame, task_pid_nr(current));
+
+ regs->orig_r28 = 1; /* no restarts for sigreturn */
+
+#ifdef CONFIG_64BIT
+ compat_frame = (struct compat_rt_sigframe __user *)frame;
+
+ if (is_compat_task()) {
+ if (get_compat_sigset(&set, &compat_frame->uc.uc_sigmask))
+ goto give_sigsegv;
+ } else
+#endif
+ {
+ if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
+ goto give_sigsegv;
+ }
+
+ set_current_blocked(&set);
+
+ /* Good thing we saved the old gr[30], eh? */
+#ifdef CONFIG_64BIT
+ if (is_compat_task()) {
+ DBG(1, "%s: compat_frame->uc.uc_mcontext 0x%p\n",
+ __func__, &compat_frame->uc.uc_mcontext);
+// FIXME: Load upper half from register file
+ if (restore_sigcontext32(&compat_frame->uc.uc_mcontext,
+ &compat_frame->regs, regs))
+ goto give_sigsegv;
+ DBG(1, "%s: usp %#08lx stack 0x%p\n",
+ __func__, usp, &compat_frame->uc.uc_stack);
+ if (compat_restore_altstack(&compat_frame->uc.uc_stack))
+ goto give_sigsegv;
+ } else
+#endif
+ {
+ DBG(1, "%s: frame->uc.uc_mcontext 0x%p\n",
+ __func__, &frame->uc.uc_mcontext);
+ if (restore_sigcontext(&frame->uc.uc_mcontext, regs))
+ goto give_sigsegv;
+ DBG(1, "%s: usp %#08lx stack 0x%p\n",
+ __func__, usp, &frame->uc.uc_stack);
+ if (restore_altstack(&frame->uc.uc_stack))
+ goto give_sigsegv;
+ }
+
+
+
+ /* If we are on the syscall path IAOQ will not be restored, and
+ * if we are on the interrupt path we must not corrupt gr31.
+ */
+ if (in_syscall)
+ regs->gr[31] = regs->iaoq[0];
+
+ return;
+
+give_sigsegv:
+ DBG(1, "%s: Sending SIGSEGV\n", __func__);
+ force_sig(SIGSEGV);
+ return;
+}
+
+/*
+ * Set up a signal frame.
+ */
+
+static inline void __user *
+get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
+{
+ /*FIXME: ELF32 vs. ELF64 has different frame_size, but since we
+ don't use the parameter it doesn't matter */
+
+ DBG(1, "%s: ka = %#lx, sp = %#lx, frame_size = %zu\n",
+ __func__, (unsigned long)ka, sp, frame_size);
+
+ /* Align alternate stack and reserve 64 bytes for the signal
+ handler's frame marker. */
+ if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! sas_ss_flags(sp))
+ sp = (current->sas_ss_sp + 0x7f) & ~0x3f; /* Stacks grow up! */
+
+ DBG(1, "%s: Returning sp = %#lx\n", __func__, (unsigned long)sp);
+ return (void __user *) sp; /* Stacks grow up. Fun. */
+}
+
+static long
+setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, long in_syscall)
+
+{
+ unsigned long flags = 0;
+ long err = 0;
+
+ if (on_sig_stack((unsigned long) sc))
+ flags |= PARISC_SC_FLAG_ONSTACK;
+ if (in_syscall) {
+ flags |= PARISC_SC_FLAG_IN_SYSCALL;
+ /* regs->iaoq is undefined in the syscall return path */
+ err |= __put_user(regs->gr[31], &sc->sc_iaoq[0]);
+ err |= __put_user(regs->gr[31]+4, &sc->sc_iaoq[1]);
+ err |= __put_user(regs->sr[3], &sc->sc_iasq[0]);
+ err |= __put_user(regs->sr[3], &sc->sc_iasq[1]);
+ DBG(1, "%s: iaoq %#lx / %#lx (in syscall)\n",
+ __func__, regs->gr[31], regs->gr[31]+4);
+ } else {
+ err |= __copy_to_user(sc->sc_iaoq, regs->iaoq, sizeof(regs->iaoq));
+ err |= __copy_to_user(sc->sc_iasq, regs->iasq, sizeof(regs->iasq));
+ DBG(1, "%s: iaoq %#lx / %#lx (not in syscall)\n",
+ __func__, regs->iaoq[0], regs->iaoq[1]);
+ }
+
+ err |= __put_user(flags, &sc->sc_flags);
+ err |= __copy_to_user(sc->sc_gr, regs->gr, sizeof(regs->gr));
+ err |= __copy_to_user(sc->sc_fr, regs->fr, sizeof(regs->fr));
+ err |= __put_user(regs->sar, &sc->sc_sar);
+ DBG(1, "%s: r28 is %ld\n", __func__, regs->gr[28]);
+
+ return err;
+}
+
+static long
+setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs,
+ long in_syscall)
+{
+ struct rt_sigframe __user *frame;
+ unsigned long rp, usp;
+ unsigned long haddr, sigframe_size;
+ unsigned long start;
+ int err = 0;
+#ifdef CONFIG_64BIT
+ struct compat_rt_sigframe __user * compat_frame;
+#endif
+
+ usp = (regs->gr[30] & ~(0x01UL));
+ sigframe_size = PARISC_RT_SIGFRAME_SIZE;
+#ifdef CONFIG_64BIT
+ if (is_compat_task()) {
+ /* The gcc alloca implementation leaves garbage in the upper 32 bits of sp */
+ usp = (compat_uint_t)usp;
+ sigframe_size = PARISC_RT_SIGFRAME_SIZE32;
+ }
+#endif
+ frame = get_sigframe(&ksig->ka, usp, sigframe_size);
+
+ DBG(1, "%s: frame %p info %p\n", __func__, frame, &ksig->info);
+
+ start = (unsigned long) frame;
+ if (start >= TASK_SIZE_MAX - sigframe_size)
+ return -EFAULT;
+
+#ifdef CONFIG_64BIT
+
+ compat_frame = (struct compat_rt_sigframe __user *)frame;
+
+ if (is_compat_task()) {
+ DBG(1, "%s: frame->info = 0x%p\n", __func__, &compat_frame->info);
+ err |= copy_siginfo_to_user32(&compat_frame->info, &ksig->info);
+ err |= __compat_save_altstack( &compat_frame->uc.uc_stack, regs->gr[30]);
+ DBG(1, "%s: frame->uc = 0x%p\n", __func__, &compat_frame->uc);
+ DBG(1, "%s: frame->uc.uc_mcontext = 0x%p\n",
+ __func__, &compat_frame->uc.uc_mcontext);
+ err |= setup_sigcontext32(&compat_frame->uc.uc_mcontext,
+ &compat_frame->regs, regs, in_syscall);
+ err |= put_compat_sigset(&compat_frame->uc.uc_sigmask, set,
+ sizeof(compat_sigset_t));
+ } else
+#endif
+ {
+ DBG(1, "%s: frame->info = 0x%p\n", __func__, &frame->info);
+ err |= copy_siginfo_to_user(&frame->info, &ksig->info);
+ err |= __save_altstack(&frame->uc.uc_stack, regs->gr[30]);
+ DBG(1, "%s: frame->uc = 0x%p\n", __func__, &frame->uc);
+ DBG(1, "%s: frame->uc.uc_mcontext = 0x%p\n",
+ __func__, &frame->uc.uc_mcontext);
+ err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, in_syscall);
+ /* FIXME: Should probably be converted as well for the compat case */
+ err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+ }
+
+ if (err)
+ return -EFAULT;
+
+#ifdef CONFIG_64BIT
+ if (!is_compat_task())
+ rp = VDSO64_SYMBOL(current, sigtramp_rt);
+ else
+#endif
+ rp = VDSO32_SYMBOL(current, sigtramp_rt);
+
+ if (in_syscall)
+ rp += 4*4; /* skip 4 instructions and start at ldi 1,%r25 */
+
+ haddr = A(ksig->ka.sa.sa_handler);
+ /* The sa_handler may be a pointer to a function descriptor */
+#ifdef CONFIG_64BIT
+ if (is_compat_task()) {
+#endif
+ if (haddr & PA_PLABEL_FDESC) {
+ Elf32_Fdesc fdesc;
+ Elf32_Fdesc __user *ufdesc = (Elf32_Fdesc __user *)A(haddr & ~3);
+
+ err = __copy_from_user(&fdesc, ufdesc, sizeof(fdesc));
+
+ if (err)
+ return -EFAULT;
+
+ haddr = fdesc.addr;
+ regs->gr[19] = fdesc.gp;
+ }
+#ifdef CONFIG_64BIT
+ } else {
+ Elf64_Fdesc fdesc;
+ Elf64_Fdesc __user *ufdesc = (Elf64_Fdesc __user *)A(haddr & ~3);
+
+ err = __copy_from_user(&fdesc, ufdesc, sizeof(fdesc));
+
+ if (err)
+ return -EFAULT;
+
+ haddr = fdesc.addr;
+ regs->gr[19] = fdesc.gp;
+ DBG(1, "%s: 64 bit signal, exe=%#lx, r19=%#lx, in_syscall=%d\n",
+ __func__, haddr, regs->gr[19], in_syscall);
+ }
+#endif
+
+ /* The syscall return path will create IAOQ values from r31.
+ */
+ if (in_syscall) {
+ regs->gr[31] = haddr;
+#ifdef CONFIG_64BIT
+ if (!test_thread_flag(TIF_32BIT))
+ sigframe_size |= 1; /* XXX ???? */
+#endif
+ } else {
+ unsigned long psw = USER_PSW;
+#ifdef CONFIG_64BIT
+ if (!test_thread_flag(TIF_32BIT))
+ psw |= PSW_W;
+#endif
+
+ /* If we are singlestepping, arrange a trap to be delivered
+ when we return to userspace. Note the semantics -- we
+ should trap before the first insn in the handler is
+ executed. Ref:
+ http://sources.redhat.com/ml/gdb/2004-11/msg00245.html
+ */
+ if (pa_psw(current)->r) {
+ pa_psw(current)->r = 0;
+ psw |= PSW_R;
+ mtctl(-1, 0);
+ }
+
+ regs->gr[0] = psw;
+ regs->iaoq[0] = haddr | PRIV_USER;
+ regs->iaoq[1] = regs->iaoq[0] + 4;
+ }
+
+ regs->gr[2] = rp; /* userland return pointer */
+ regs->gr[26] = ksig->sig; /* signal number */
+
+#ifdef CONFIG_64BIT
+ if (is_compat_task()) {
+ regs->gr[25] = A(&compat_frame->info); /* siginfo pointer */
+ regs->gr[24] = A(&compat_frame->uc); /* ucontext pointer */
+ } else
+#endif
+ {
+ regs->gr[25] = A(&frame->info); /* siginfo pointer */
+ regs->gr[24] = A(&frame->uc); /* ucontext pointer */
+ }
+
+ DBG(1, "%s: making sigreturn frame: %#lx + %#lx = %#lx\n", __func__,
+ regs->gr[30], sigframe_size,
+ regs->gr[30] + sigframe_size);
+ /* Raise the user stack pointer to make a proper call frame. */
+ regs->gr[30] = (A(frame) + sigframe_size);
+
+
+ DBG(1, "%s: sig deliver (%s,%d) frame=0x%p sp=%#lx iaoq=%#lx/%#lx rp=%#lx\n",
+ __func__, current->comm, current->pid, frame, regs->gr[30],
+ regs->iaoq[0], regs->iaoq[1], rp);
+
+ return 0;
+}
+
+/*
+ * OK, we're invoking a handler.
+ */
+
+static void
+handle_signal(struct ksignal *ksig, struct pt_regs *regs, long in_syscall)
+{
+ int ret;
+ sigset_t *oldset = sigmask_to_save();
+
+ DBG(1, "%s: sig=%d, ka=%p, info=%p, oldset=%p, regs=%p\n",
+ __func__, ksig->sig, &ksig->ka, &ksig->info, oldset, regs);
+
+ /* Set up the stack frame */
+ ret = setup_rt_frame(ksig, oldset, regs, in_syscall);
+
+ signal_setup_done(ret, ksig, test_thread_flag(TIF_SINGLESTEP) ||
+ test_thread_flag(TIF_BLOCKSTEP));
+
+ DBG(1, "%s: Exit (success), regs->gr[28] = %ld\n",
+ __func__, regs->gr[28]);
+}
+
+/*
+ * Check how the syscall number gets loaded into %r20 within
+ * the delay branch in userspace and adjust as needed.
+ */
+
+static void check_syscallno_in_delay_branch(struct pt_regs *regs)
+{
+ u32 opcode, source_reg;
+ u32 __user *uaddr;
+ int err;
+
+ /* Usually we don't have to restore %r20 (the system call number)
+ * because it gets loaded in the delay slot of the branch external
+ * instruction via the ldi instruction.
+ * In some cases a register-to-register copy instruction might have
+ * been used instead, in which case we need to copy the syscall
+ * number into the source register before returning to userspace.
+ */
+
+ /* A syscall is just a branch, so all we have to do is fiddle the
+ * return pointer so that the ble instruction gets executed again.
+ */
+ regs->gr[31] -= 8; /* delayed branching */
+
+ /* Get assembler opcode of code in delay branch */
+ uaddr = (u32 __user *) ((regs->gr[31] & ~3) + 4);
+ err = get_user(opcode, uaddr);
+ if (err)
+ return;
+
+ /* Check if delay branch uses "ldi int,%r20" */
+ if ((opcode & 0xffff0000) == 0x34140000)
+ return; /* everything ok, just return */
+
+ /* Check if delay branch uses "nop" */
+ if (opcode == INSN_NOP)
+ return;
+
+ /* Check if delay branch uses "copy %rX,%r20" */
+ if ((opcode & 0xffe0ffff) == 0x08000254) {
+ source_reg = (opcode >> 16) & 31;
+ regs->gr[source_reg] = regs->gr[20];
+ return;
+ }
+
+ pr_warn("syscall restart: %s (pid %d): unexpected opcode 0x%08x\n",
+ current->comm, task_pid_nr(current), opcode);
+}
+
+static inline void
+syscall_restart(struct pt_regs *regs, struct k_sigaction *ka)
+{
+ if (regs->orig_r28)
+ return;
+ regs->orig_r28 = 1; /* no more restarts */
+
+ DBG(1, "%s: orig_r28 = %ld pid %d r20 %ld\n",
+ __func__, regs->orig_r28, task_pid_nr(current), regs->gr[20]);
+
+ /* Check the return code */
+ switch (regs->gr[28]) {
+ case -ERESTART_RESTARTBLOCK:
+ case -ERESTARTNOHAND:
+ DBG(1, "%s: ERESTARTNOHAND: returning -EINTR\n", __func__);
+ regs->gr[28] = -EINTR;
+ break;
+ case -ERESTARTSYS:
+ if (!(ka->sa.sa_flags & SA_RESTART)) {
+ DBG(1, "%s: ERESTARTSYS: putting -EINTR pid %d\n",
+ __func__, task_pid_nr(current));
+ regs->gr[28] = -EINTR;
+ break;
+ }
+ fallthrough;
+ case -ERESTARTNOINTR:
+ DBG(1, "%s: %ld\n", __func__, regs->gr[28]);
+ check_syscallno_in_delay_branch(regs);
+ break;
+ }
+}
+
+static inline void
+insert_restart_trampoline(struct pt_regs *regs)
+{
+ if (regs->orig_r28)
+ return;
+ regs->orig_r28 = 1; /* no more restarts */
+
+ DBG(2, "%s: gr28 = %ld pid %d\n",
+ __func__, regs->gr[28], task_pid_nr(current));
+
+ switch (regs->gr[28]) {
+ case -ERESTART_RESTARTBLOCK: {
+ /* Restart the system call - no handlers present */
+ unsigned int *usp = (unsigned int *)regs->gr[30];
+ unsigned long rp;
+ long err = 0;
+
+ /* check that we don't exceed the stack */
+ if (A(&usp[0]) >= TASK_SIZE_MAX - 5 * sizeof(int))
+ return;
+
+ /* Call trampoline in vdso to restart the syscall
+ * with __NR_restart_syscall.
+ * Original return addresses are on stack like this:
+ *
+ * 0: <return address (orig r31)>
+ * 4: <2nd half for 64-bit>
+ */
+#ifdef CONFIG_64BIT
+ if (!is_compat_task()) {
+ err |= put_user(regs->gr[31] >> 32, &usp[0]);
+ err |= put_user(regs->gr[31] & 0xffffffff, &usp[1]);
+ rp = VDSO64_SYMBOL(current, restart_syscall);
+ } else
+#endif
+ {
+ err |= put_user(regs->gr[31], &usp[0]);
+ rp = VDSO32_SYMBOL(current, restart_syscall);
+ }
+ WARN_ON(err);
+
+ regs->gr[31] = rp;
+ DBG(1, "%s: ERESTART_RESTARTBLOCK\n", __func__);
+ return;
+ }
+ case -EINTR:
+ /* ok, was handled before and should be returned. */
+ break;
+ case -ERESTARTNOHAND:
+ case -ERESTARTSYS:
+ case -ERESTARTNOINTR:
+ DBG(1, "%s: Type %ld\n", __func__, regs->gr[28]);
+ check_syscallno_in_delay_branch(regs);
+ return;
+ default:
+ break;
+ }
+}
+
+/*
+ * We need to be able to restore the syscall arguments (r21-r26) to
+ * restart syscalls. Thus, the syscall path should save them in the
+ * pt_regs structure (it's okay to do so since they are caller-save
+ * registers). As noted below, the syscall number gets restored for
+ * us due to the magic of delayed branching.
+ */
+static void do_signal(struct pt_regs *regs, long in_syscall)
+{
+ struct ksignal ksig;
+ int restart_syscall;
+ bool has_handler;
+
+ has_handler = get_signal(&ksig);
+
+ restart_syscall = 0;
+ if (in_syscall)
+ restart_syscall = 1;
+
+ if (has_handler) {
+ /* Restart a system call if necessary. */
+ if (restart_syscall)
+ syscall_restart(regs, &ksig.ka);
+
+ handle_signal(&ksig, regs, in_syscall);
+ DBG(1, "%s: Handled signal pid %d\n",
+ __func__, task_pid_nr(current));
+ return;
+ }
+
+ /* Do we need to restart the system call? */
+ if (restart_syscall)
+ insert_restart_trampoline(regs);
+
+ DBG(1, "%s: Exit (not delivered), regs->gr[28] = %ld orig_r28 = %ld pid %d\n",
+ __func__, regs->gr[28], regs->orig_r28, task_pid_nr(current));
+
+ restore_saved_sigmask();
+}
+
+asmlinkage void do_notify_resume(struct pt_regs *regs, long in_syscall)
+{
+ if (test_thread_flag(TIF_SIGPENDING) ||
+ test_thread_flag(TIF_NOTIFY_SIGNAL))
+ do_signal(regs, in_syscall);
+
+ if (test_thread_flag(TIF_NOTIFY_RESUME))
+ resume_user_mode_work(regs);
+}
diff --git a/arch/parisc/kernel/signal32.c b/arch/parisc/kernel/signal32.c
new file mode 100644
index 000000000..9a5ba57ad
--- /dev/null
+++ b/arch/parisc/kernel/signal32.c
@@ -0,0 +1,248 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* Signal support for 32-bit kernel builds
+ *
+ * Copyright (C) 2001 Matthew Wilcox <willy at parisc-linux.org>
+ * Copyright (C) 2006 Kyle McMartin <kyle at parisc-linux.org>
+ *
+ * Code was mostly borrowed from kernel/signal.c.
+ * See kernel/signal.c for additional Copyrights.
+ */
+
+#include <linux/compat.h>
+#include <linux/module.h>
+#include <linux/unistd.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/syscalls.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+
+#include <linux/uaccess.h>
+
+#include "signal32.h"
+
+#define DEBUG_COMPAT_SIG 0
+#define DEBUG_COMPAT_SIG_LEVEL 2
+
+#if DEBUG_COMPAT_SIG
+#define DBG(LEVEL, ...) \
+ ((DEBUG_COMPAT_SIG_LEVEL >= LEVEL) \
+ ? printk(__VA_ARGS__) : (void) 0)
+#else
+#define DBG(LEVEL, ...)
+#endif
+
+long
+restore_sigcontext32(struct compat_sigcontext __user *sc, struct compat_regfile __user * rf,
+ struct pt_regs *regs)
+{
+ long err = 0;
+ compat_uint_t compat_reg;
+ compat_uint_t compat_regt;
+ int regn;
+
+ /* When loading 32-bit values into 64-bit registers make
+ sure to clear the upper 32-bits */
+ DBG(2,"restore_sigcontext32: PER_LINUX32 process\n");
+ DBG(2,"restore_sigcontext32: sc = 0x%p, rf = 0x%p, regs = 0x%p\n", sc, rf, regs);
+ DBG(2,"restore_sigcontext32: compat_sigcontext is %#lx bytes\n", sizeof(*sc));
+ for(regn=0; regn < 32; regn++){
+ err |= __get_user(compat_reg,&sc->sc_gr[regn]);
+ regs->gr[regn] = compat_reg;
+ /* Load upper half */
+ err |= __get_user(compat_regt,&rf->rf_gr[regn]);
+ regs->gr[regn] = ((u64)compat_regt << 32) | (u64)compat_reg;
+ DBG(3,"restore_sigcontext32: gr%02d = %#lx (%#x / %#x)\n",
+ regn, regs->gr[regn], compat_regt, compat_reg);
+ }
+ DBG(2,"restore_sigcontext32: sc->sc_fr = 0x%p (%#lx)\n",sc->sc_fr, sizeof(sc->sc_fr));
+ /* XXX: BE WARNED FR's are 64-BIT! */
+ err |= __copy_from_user(regs->fr, sc->sc_fr, sizeof(regs->fr));
+
+ /* Better safe than sorry, pass __get_user two things of
+ the same size and let gcc do the upward conversion to
+ 64-bits */
+ err |= __get_user(compat_reg, &sc->sc_iaoq[0]);
+ /* Load upper half */
+ err |= __get_user(compat_regt, &rf->rf_iaoq[0]);
+ regs->iaoq[0] = ((u64)compat_regt << 32) | (u64)compat_reg;
+ DBG(2,"restore_sigcontext32: upper half of iaoq[0] = %#lx\n", compat_regt);
+ DBG(2,"restore_sigcontext32: sc->sc_iaoq[0] = %p => %#x\n",
+ &sc->sc_iaoq[0], compat_reg);
+
+ err |= __get_user(compat_reg, &sc->sc_iaoq[1]);
+ /* Load upper half */
+ err |= __get_user(compat_regt, &rf->rf_iaoq[1]);
+ regs->iaoq[1] = ((u64)compat_regt << 32) | (u64)compat_reg;
+ DBG(2,"restore_sigcontext32: upper half of iaoq[1] = %#lx\n", compat_regt);
+ DBG(2,"restore_sigcontext32: sc->sc_iaoq[1] = %p => %#x\n",
+ &sc->sc_iaoq[1],compat_reg);
+ DBG(2,"restore_sigcontext32: iaoq is %#lx / %#lx\n",
+ regs->iaoq[0],regs->iaoq[1]);
+
+ err |= __get_user(compat_reg, &sc->sc_iasq[0]);
+ /* Load the upper half for iasq */
+ err |= __get_user(compat_regt, &rf->rf_iasq[0]);
+ regs->iasq[0] = ((u64)compat_regt << 32) | (u64)compat_reg;
+ DBG(2,"restore_sigcontext32: upper half of iasq[0] = %#lx\n", compat_regt);
+
+ err |= __get_user(compat_reg, &sc->sc_iasq[1]);
+ /* Load the upper half for iasq */
+ err |= __get_user(compat_regt, &rf->rf_iasq[1]);
+ regs->iasq[1] = ((u64)compat_regt << 32) | (u64)compat_reg;
+ DBG(2,"restore_sigcontext32: upper half of iasq[1] = %#lx\n", compat_regt);
+ DBG(2,"restore_sigcontext32: iasq is %#lx / %#lx\n",
+ regs->iasq[0],regs->iasq[1]);
+
+ err |= __get_user(compat_reg, &sc->sc_sar);
+ /* Load the upper half for sar */
+ err |= __get_user(compat_regt, &rf->rf_sar);
+ regs->sar = ((u64)compat_regt << 32) | (u64)compat_reg;
+ DBG(2,"restore_sigcontext32: upper_half & sar = %#lx\n", compat_regt);
+ DBG(2,"restore_sigcontext32: sar is %#lx\n", regs->sar);
+ DBG(2,"restore_sigcontext32: r28 is %ld\n", regs->gr[28]);
+
+ return err;
+}
+
+/*
+ * Set up the sigcontext structure for this process.
+ * This is not an easy task if the kernel is 64-bit, it will require
+ * that we examine the process personality to determine if we need to
+ * truncate for a 32-bit userspace.
+ */
+long
+setup_sigcontext32(struct compat_sigcontext __user *sc, struct compat_regfile __user * rf,
+ struct pt_regs *regs, int in_syscall)
+{
+ compat_int_t flags = 0;
+ long err = 0;
+ compat_uint_t compat_reg;
+ compat_uint_t compat_regb;
+ int regn;
+
+ if (on_sig_stack((unsigned long) sc))
+ flags |= PARISC_SC_FLAG_ONSTACK;
+
+ if (in_syscall) {
+
+ DBG(1,"setup_sigcontext32: in_syscall\n");
+
+ flags |= PARISC_SC_FLAG_IN_SYSCALL;
+ /* Truncate gr31 */
+ compat_reg = (compat_uint_t)(regs->gr[31]);
+ /* regs->iaoq is undefined in the syscall return path */
+ err |= __put_user(compat_reg, &sc->sc_iaoq[0]);
+ DBG(2,"setup_sigcontext32: sc->sc_iaoq[0] = %p <= %#x\n",
+ &sc->sc_iaoq[0], compat_reg);
+
+ /* Store upper half */
+ compat_reg = (compat_uint_t)(regs->gr[31] >> 32);
+ err |= __put_user(compat_reg, &rf->rf_iaoq[0]);
+ DBG(2,"setup_sigcontext32: upper half iaoq[0] = %#x\n", compat_reg);
+
+
+ compat_reg = (compat_uint_t)(regs->gr[31]+4);
+ err |= __put_user(compat_reg, &sc->sc_iaoq[1]);
+ DBG(2,"setup_sigcontext32: sc->sc_iaoq[1] = %p <= %#x\n",
+ &sc->sc_iaoq[1], compat_reg);
+ /* Store upper half */
+ compat_reg = (compat_uint_t)((regs->gr[31]+4) >> 32);
+ err |= __put_user(compat_reg, &rf->rf_iaoq[1]);
+ DBG(2,"setup_sigcontext32: upper half iaoq[1] = %#x\n", compat_reg);
+
+ /* Truncate sr3 */
+ compat_reg = (compat_uint_t)(regs->sr[3]);
+ err |= __put_user(compat_reg, &sc->sc_iasq[0]);
+ err |= __put_user(compat_reg, &sc->sc_iasq[1]);
+
+ /* Store upper half */
+ compat_reg = (compat_uint_t)(regs->sr[3] >> 32);
+ err |= __put_user(compat_reg, &rf->rf_iasq[0]);
+ err |= __put_user(compat_reg, &rf->rf_iasq[1]);
+
+ DBG(2,"setup_sigcontext32: upper half iasq[0] = %#x\n", compat_reg);
+ DBG(2,"setup_sigcontext32: upper half iasq[1] = %#x\n", compat_reg);
+ DBG(1,"setup_sigcontext32: iaoq %#lx / %#lx\n",
+ regs->gr[31], regs->gr[31]+4);
+
+ } else {
+
+ compat_reg = (compat_uint_t)(regs->iaoq[0]);
+ err |= __put_user(compat_reg, &sc->sc_iaoq[0]);
+ DBG(2,"setup_sigcontext32: sc->sc_iaoq[0] = %p <= %#x\n",
+ &sc->sc_iaoq[0], compat_reg);
+ /* Store upper half */
+ compat_reg = (compat_uint_t)(regs->iaoq[0] >> 32);
+ err |= __put_user(compat_reg, &rf->rf_iaoq[0]);
+ DBG(2,"setup_sigcontext32: upper half iaoq[0] = %#x\n", compat_reg);
+
+ compat_reg = (compat_uint_t)(regs->iaoq[1]);
+ err |= __put_user(compat_reg, &sc->sc_iaoq[1]);
+ DBG(2,"setup_sigcontext32: sc->sc_iaoq[1] = %p <= %#x\n",
+ &sc->sc_iaoq[1], compat_reg);
+ /* Store upper half */
+ compat_reg = (compat_uint_t)(regs->iaoq[1] >> 32);
+ err |= __put_user(compat_reg, &rf->rf_iaoq[1]);
+ DBG(2,"setup_sigcontext32: upper half iaoq[1] = %#x\n", compat_reg);
+
+
+ compat_reg = (compat_uint_t)(regs->iasq[0]);
+ err |= __put_user(compat_reg, &sc->sc_iasq[0]);
+ DBG(2,"setup_sigcontext32: sc->sc_iasq[0] = %p <= %#x\n",
+ &sc->sc_iasq[0], compat_reg);
+ /* Store upper half */
+ compat_reg = (compat_uint_t)(regs->iasq[0] >> 32);
+ err |= __put_user(compat_reg, &rf->rf_iasq[0]);
+ DBG(2,"setup_sigcontext32: upper half iasq[0] = %#x\n", compat_reg);
+
+
+ compat_reg = (compat_uint_t)(regs->iasq[1]);
+ err |= __put_user(compat_reg, &sc->sc_iasq[1]);
+ DBG(2,"setup_sigcontext32: sc->sc_iasq[1] = %p <= %#x\n",
+ &sc->sc_iasq[1], compat_reg);
+ /* Store upper half */
+ compat_reg = (compat_uint_t)(regs->iasq[1] >> 32);
+ err |= __put_user(compat_reg, &rf->rf_iasq[1]);
+ DBG(2,"setup_sigcontext32: upper half iasq[1] = %#x\n", compat_reg);
+
+ /* Print out the IAOQ for debugging */
+ DBG(1,"setup_sigcontext32: ia0q %#lx / %#lx\n",
+ regs->iaoq[0], regs->iaoq[1]);
+ }
+
+ err |= __put_user(flags, &sc->sc_flags);
+
+ DBG(1,"setup_sigcontext32: Truncating general registers.\n");
+
+ for(regn=0; regn < 32; regn++){
+ /* Truncate a general register */
+ compat_reg = (compat_uint_t)(regs->gr[regn]);
+ err |= __put_user(compat_reg, &sc->sc_gr[regn]);
+ /* Store upper half */
+ compat_regb = (compat_uint_t)(regs->gr[regn] >> 32);
+ err |= __put_user(compat_regb, &rf->rf_gr[regn]);
+
+ /* DEBUG: Write out the "upper / lower" register data */
+ DBG(2,"setup_sigcontext32: gr%02d = %#x / %#x\n", regn,
+ compat_regb, compat_reg);
+ }
+
+ /* Copy the floating point registers (same size)
+ XXX: BE WARNED FR's are 64-BIT! */
+ DBG(1,"setup_sigcontext32: Copying from regs to sc, "
+ "sc->sc_fr size = %#lx, regs->fr size = %#lx\n",
+ sizeof(regs->fr), sizeof(sc->sc_fr));
+ err |= __copy_to_user(sc->sc_fr, regs->fr, sizeof(regs->fr));
+
+ compat_reg = (compat_uint_t)(regs->sar);
+ err |= __put_user(compat_reg, &sc->sc_sar);
+ DBG(2,"setup_sigcontext32: sar is %#x\n", compat_reg);
+ /* Store upper half */
+ compat_reg = (compat_uint_t)(regs->sar >> 32);
+ err |= __put_user(compat_reg, &rf->rf_sar);
+ DBG(2,"setup_sigcontext32: upper half sar = %#x\n", compat_reg);
+ DBG(1,"setup_sigcontext32: r28 is %ld\n", regs->gr[28]);
+
+ return err;
+}
diff --git a/arch/parisc/kernel/signal32.h b/arch/parisc/kernel/signal32.h
new file mode 100644
index 000000000..c03eb1ed4
--- /dev/null
+++ b/arch/parisc/kernel/signal32.h
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2001 Matthew Wilcox <willy at parisc-linux.org>
+ * Copyright (C) 2003 Carlos O'Donell <carlos at parisc-linux.org>
+ */
+#ifndef _PARISC64_KERNEL_SIGNAL32_H
+#define _PARISC64_KERNEL_SIGNAL32_H
+
+#include <linux/compat.h>
+
+/* 32-bit ucontext as seen from an 64-bit kernel */
+struct compat_ucontext {
+ compat_uint_t uc_flags;
+ compat_uptr_t uc_link;
+ compat_stack_t uc_stack; /* struct compat_sigaltstack (12 bytes)*/
+ /* FIXME: Pad out to get uc_mcontext to start at an 8-byte aligned boundary */
+ compat_uint_t pad[1];
+ struct compat_sigcontext uc_mcontext;
+ compat_sigset_t uc_sigmask; /* mask last for extensibility */
+};
+
+/* ELF32 signal handling */
+
+/* In a deft move of uber-hackery, we decide to carry the top half of all
+ * 64-bit registers in a non-portable, non-ABI, hidden structure.
+ * Userspace can read the hidden structure if it *wants* but is never
+ * guaranteed to be in the same place. In fact the uc_sigmask from the
+ * ucontext_t structure may push the hidden register file downards
+ */
+struct compat_regfile {
+ /* Upper half of all the 64-bit registers that were truncated
+ on a copy to a 32-bit userspace */
+ compat_int_t rf_gr[32];
+ compat_int_t rf_iasq[2];
+ compat_int_t rf_iaoq[2];
+ compat_int_t rf_sar;
+};
+
+struct compat_rt_sigframe {
+ unsigned int tramp[2]; /* holds original return address */
+ compat_siginfo_t info;
+ struct compat_ucontext uc;
+ /* Hidden location of truncated registers, *must* be last. */
+ struct compat_regfile regs;
+};
+
+/*
+ * The 32-bit ABI wants at least 48 bytes for a function call frame:
+ * 16 bytes for arg0-arg3, and 32 bytes for magic (the only part of
+ * which Linux/parisc uses is sp-20 for the saved return pointer...)
+ * Then, the stack pointer must be rounded to a cache line (64 bytes).
+ */
+#define SIGFRAME32 64
+#define FUNCTIONCALLFRAME32 48
+#define PARISC_RT_SIGFRAME_SIZE32 (((sizeof(struct compat_rt_sigframe) + FUNCTIONCALLFRAME32) + SIGFRAME32) & -SIGFRAME32)
+
+long restore_sigcontext32(struct compat_sigcontext __user *sc,
+ struct compat_regfile __user *rf,
+ struct pt_regs *regs);
+long setup_sigcontext32(struct compat_sigcontext __user *sc,
+ struct compat_regfile __user *rf,
+ struct pt_regs *regs, int in_syscall);
+
+#endif
diff --git a/arch/parisc/kernel/smp.c b/arch/parisc/kernel/smp.c
new file mode 100644
index 000000000..2019c1f04
--- /dev/null
+++ b/arch/parisc/kernel/smp.c
@@ -0,0 +1,513 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+** SMP Support
+**
+** Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
+** Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com>
+** Copyright (C) 2001,2004 Grant Grundler <grundler@parisc-linux.org>
+**
+** Lots of stuff stolen from arch/alpha/kernel/smp.c
+** ...and then parisc stole from arch/ia64/kernel/smp.c. Thanks David! :^)
+**
+** Thanks to John Curry and Ullas Ponnadi. I learned a lot from their work.
+** -grant (1/12/2001)
+**
+*/
+#include <linux/types.h>
+#include <linux/spinlock.h>
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched/mm.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/smp.h>
+#include <linux/kernel_stat.h>
+#include <linux/mm.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+#include <linux/ftrace.h>
+#include <linux/cpu.h>
+#include <linux/kgdb.h>
+#include <linux/sched/hotplug.h>
+
+#include <linux/atomic.h>
+#include <asm/current.h>
+#include <asm/delay.h>
+#include <asm/tlbflush.h>
+
+#include <asm/io.h>
+#include <asm/irq.h> /* for CPU_IRQ_REGION and friends */
+#include <asm/mmu_context.h>
+#include <asm/page.h>
+#include <asm/processor.h>
+#include <asm/ptrace.h>
+#include <asm/unistd.h>
+#include <asm/cacheflush.h>
+
+#undef DEBUG_SMP
+#ifdef DEBUG_SMP
+static int smp_debug_lvl = 0;
+#define smp_debug(lvl, printargs...) \
+ if (lvl >= smp_debug_lvl) \
+ printk(printargs);
+#else
+#define smp_debug(lvl, ...) do { } while(0)
+#endif /* DEBUG_SMP */
+
+volatile struct task_struct *smp_init_current_idle_task;
+
+/* track which CPU is booting */
+static volatile int cpu_now_booting;
+
+static DEFINE_PER_CPU(spinlock_t, ipi_lock);
+
+enum ipi_message_type {
+ IPI_NOP=0,
+ IPI_RESCHEDULE=1,
+ IPI_CALL_FUNC,
+ IPI_CPU_START,
+ IPI_CPU_STOP,
+ IPI_CPU_TEST,
+#ifdef CONFIG_KGDB
+ IPI_ENTER_KGDB,
+#endif
+};
+
+
+/********** SMP inter processor interrupt and communication routines */
+
+#undef PER_CPU_IRQ_REGION
+#ifdef PER_CPU_IRQ_REGION
+/* XXX REVISIT Ignore for now.
+** *May* need this "hook" to register IPI handler
+** once we have perCPU ExtIntr switch tables.
+*/
+static void
+ipi_init(int cpuid)
+{
+#error verify IRQ_OFFSET(IPI_IRQ) is ipi_interrupt() in new IRQ region
+
+ if(cpu_online(cpuid) )
+ {
+ switch_to_idle_task(current);
+ }
+
+ return;
+}
+#endif
+
+
+/*
+** Yoink this CPU from the runnable list...
+**
+*/
+static void
+halt_processor(void)
+{
+ /* REVISIT : redirect I/O Interrupts to another CPU? */
+ /* REVISIT : does PM *know* this CPU isn't available? */
+ set_cpu_online(smp_processor_id(), false);
+ local_irq_disable();
+ __pdc_cpu_rendezvous();
+ for (;;)
+ ;
+}
+
+
+irqreturn_t __irq_entry
+ipi_interrupt(int irq, void *dev_id)
+{
+ int this_cpu = smp_processor_id();
+ struct cpuinfo_parisc *p = &per_cpu(cpu_data, this_cpu);
+ unsigned long ops;
+ unsigned long flags;
+
+ for (;;) {
+ spinlock_t *lock = &per_cpu(ipi_lock, this_cpu);
+ spin_lock_irqsave(lock, flags);
+ ops = p->pending_ipi;
+ p->pending_ipi = 0;
+ spin_unlock_irqrestore(lock, flags);
+
+ mb(); /* Order bit clearing and data access. */
+
+ if (!ops)
+ break;
+
+ while (ops) {
+ unsigned long which = ffz(~ops);
+
+ ops &= ~(1 << which);
+
+ switch (which) {
+ case IPI_NOP:
+ smp_debug(100, KERN_DEBUG "CPU%d IPI_NOP\n", this_cpu);
+ break;
+
+ case IPI_RESCHEDULE:
+ smp_debug(100, KERN_DEBUG "CPU%d IPI_RESCHEDULE\n", this_cpu);
+ inc_irq_stat(irq_resched_count);
+ scheduler_ipi();
+ break;
+
+ case IPI_CALL_FUNC:
+ smp_debug(100, KERN_DEBUG "CPU%d IPI_CALL_FUNC\n", this_cpu);
+ inc_irq_stat(irq_call_count);
+ generic_smp_call_function_interrupt();
+ break;
+
+ case IPI_CPU_START:
+ smp_debug(100, KERN_DEBUG "CPU%d IPI_CPU_START\n", this_cpu);
+ break;
+
+ case IPI_CPU_STOP:
+ smp_debug(100, KERN_DEBUG "CPU%d IPI_CPU_STOP\n", this_cpu);
+ halt_processor();
+ break;
+
+ case IPI_CPU_TEST:
+ smp_debug(100, KERN_DEBUG "CPU%d is alive!\n", this_cpu);
+ break;
+#ifdef CONFIG_KGDB
+ case IPI_ENTER_KGDB:
+ smp_debug(100, KERN_DEBUG "CPU%d ENTER_KGDB\n", this_cpu);
+ kgdb_nmicallback(raw_smp_processor_id(), get_irq_regs());
+ break;
+#endif
+ default:
+ printk(KERN_CRIT "Unknown IPI num on CPU%d: %lu\n",
+ this_cpu, which);
+ return IRQ_NONE;
+ } /* Switch */
+
+ /* before doing more, let in any pending interrupts */
+ if (ops) {
+ local_irq_enable();
+ local_irq_disable();
+ }
+ } /* while (ops) */
+ }
+ return IRQ_HANDLED;
+}
+
+
+static inline void
+ipi_send(int cpu, enum ipi_message_type op)
+{
+ struct cpuinfo_parisc *p = &per_cpu(cpu_data, cpu);
+ spinlock_t *lock = &per_cpu(ipi_lock, cpu);
+ unsigned long flags;
+
+ spin_lock_irqsave(lock, flags);
+ p->pending_ipi |= 1 << op;
+ gsc_writel(IPI_IRQ - CPU_IRQ_BASE, p->hpa);
+ spin_unlock_irqrestore(lock, flags);
+}
+
+static void
+send_IPI_mask(const struct cpumask *mask, enum ipi_message_type op)
+{
+ int cpu;
+
+ for_each_cpu(cpu, mask)
+ ipi_send(cpu, op);
+}
+
+static inline void
+send_IPI_single(int dest_cpu, enum ipi_message_type op)
+{
+ BUG_ON(dest_cpu == NO_PROC_ID);
+
+ ipi_send(dest_cpu, op);
+}
+
+static inline void
+send_IPI_allbutself(enum ipi_message_type op)
+{
+ int i;
+
+ preempt_disable();
+ for_each_online_cpu(i) {
+ if (i != smp_processor_id())
+ send_IPI_single(i, op);
+ }
+ preempt_enable();
+}
+
+#ifdef CONFIG_KGDB
+void kgdb_roundup_cpus(void)
+{
+ send_IPI_allbutself(IPI_ENTER_KGDB);
+}
+#endif
+
+inline void
+smp_send_stop(void) { send_IPI_allbutself(IPI_CPU_STOP); }
+
+void
+arch_smp_send_reschedule(int cpu) { send_IPI_single(cpu, IPI_RESCHEDULE); }
+
+void
+smp_send_all_nop(void)
+{
+ send_IPI_allbutself(IPI_NOP);
+}
+
+void arch_send_call_function_ipi_mask(const struct cpumask *mask)
+{
+ send_IPI_mask(mask, IPI_CALL_FUNC);
+}
+
+void arch_send_call_function_single_ipi(int cpu)
+{
+ send_IPI_single(cpu, IPI_CALL_FUNC);
+}
+
+/*
+ * Called by secondaries to update state and initialize CPU registers.
+ */
+static void
+smp_cpu_init(int cpunum)
+{
+ /* Set modes and Enable floating point coprocessor */
+ init_per_cpu(cpunum);
+
+ disable_sr_hashing();
+
+ mb();
+
+ /* Well, support 2.4 linux scheme as well. */
+ if (cpu_online(cpunum)) {
+ extern void machine_halt(void); /* arch/parisc.../process.c */
+
+ printk(KERN_CRIT "CPU#%d already initialized!\n", cpunum);
+ machine_halt();
+ }
+
+ notify_cpu_starting(cpunum);
+
+ set_cpu_online(cpunum, true);
+
+ /* Initialise the idle task for this CPU */
+ mmgrab(&init_mm);
+ current->active_mm = &init_mm;
+ BUG_ON(current->mm);
+ enter_lazy_tlb(&init_mm, current);
+
+ init_IRQ(); /* make sure no IRQs are enabled or pending */
+ start_cpu_itimer();
+}
+
+
+/*
+ * Slaves start using C here. Indirectly called from smp_slave_stext.
+ * Do what start_kernel() and main() do for boot strap processor (aka monarch)
+ */
+void smp_callin(unsigned long pdce_proc)
+{
+ int slave_id = cpu_now_booting;
+
+#ifdef CONFIG_64BIT
+ WARN_ON(((unsigned long)(PAGE0->mem_pdc_hi) << 32
+ | PAGE0->mem_pdc) != pdce_proc);
+#endif
+
+ smp_cpu_init(slave_id);
+
+ flush_cache_all_local(); /* start with known state */
+ flush_tlb_all_local(NULL);
+
+ local_irq_enable(); /* Interrupts have been off until now */
+
+ cpu_startup_entry(CPUHP_AP_ONLINE_IDLE);
+
+ /* NOTREACHED */
+ panic("smp_callin() AAAAaaaaahhhh....\n");
+}
+
+/*
+ * Bring one cpu online.
+ */
+static int smp_boot_one_cpu(int cpuid, struct task_struct *idle)
+{
+ const struct cpuinfo_parisc *p = &per_cpu(cpu_data, cpuid);
+ long timeout;
+
+#ifdef CONFIG_HOTPLUG_CPU
+ int i;
+
+ /* reset irq statistics for this CPU */
+ memset(&per_cpu(irq_stat, cpuid), 0, sizeof(irq_cpustat_t));
+ for (i = 0; i < NR_IRQS; i++) {
+ struct irq_desc *desc = irq_to_desc(i);
+
+ if (desc && desc->kstat_irqs)
+ *per_cpu_ptr(desc->kstat_irqs, cpuid) = 0;
+ }
+#endif
+
+ /* wait until last booting CPU has started. */
+ while (cpu_now_booting)
+ ;
+
+ /* Let _start know what logical CPU we're booting
+ ** (offset into init_tasks[],cpu_data[])
+ */
+ cpu_now_booting = cpuid;
+
+ /*
+ ** boot strap code needs to know the task address since
+ ** it also contains the process stack.
+ */
+ smp_init_current_idle_task = idle ;
+ mb();
+
+ printk(KERN_INFO "Releasing cpu %d now, hpa=%lx\n", cpuid, p->hpa);
+
+ /*
+ ** This gets PDC to release the CPU from a very tight loop.
+ **
+ ** From the PA-RISC 2.0 Firmware Architecture Reference Specification:
+ ** "The MEM_RENDEZ vector specifies the location of OS_RENDEZ which
+ ** is executed after receiving the rendezvous signal (an interrupt to
+ ** EIR{0}). MEM_RENDEZ is valid only when it is nonzero and the
+ ** contents of memory are valid."
+ */
+ gsc_writel(TIMER_IRQ - CPU_IRQ_BASE, p->hpa);
+ mb();
+
+ /*
+ * OK, wait a bit for that CPU to finish staggering about.
+ * Slave will set a bit when it reaches smp_cpu_init().
+ * Once the "monarch CPU" sees the bit change, it can move on.
+ */
+ for (timeout = 0; timeout < 10000; timeout++) {
+ if(cpu_online(cpuid)) {
+ /* Which implies Slave has started up */
+ cpu_now_booting = 0;
+ goto alive ;
+ }
+ udelay(100);
+ barrier();
+ }
+ printk(KERN_CRIT "SMP: CPU:%d is stuck.\n", cpuid);
+ return -1;
+
+alive:
+ /* Remember the Slave data */
+ smp_debug(100, KERN_DEBUG "SMP: CPU:%d came alive after %ld _us\n",
+ cpuid, timeout * 100);
+ return 0;
+}
+
+void __init smp_prepare_boot_cpu(void)
+{
+ int bootstrap_processor = per_cpu(cpu_data, 0).cpuid;
+
+ /* Setup BSP mappings */
+ printk(KERN_INFO "SMP: bootstrap CPU ID is %d\n", bootstrap_processor);
+
+ set_cpu_online(bootstrap_processor, true);
+ set_cpu_present(bootstrap_processor, true);
+}
+
+
+
+/*
+** inventory.c:do_inventory() hasn't yet been run and thus we
+** don't 'discover' the additional CPUs until later.
+*/
+void __init smp_prepare_cpus(unsigned int max_cpus)
+{
+ int cpu;
+
+ for_each_possible_cpu(cpu)
+ spin_lock_init(&per_cpu(ipi_lock, cpu));
+
+ init_cpu_present(cpumask_of(0));
+}
+
+
+void __init smp_cpus_done(unsigned int cpu_max)
+{
+}
+
+
+int __cpu_up(unsigned int cpu, struct task_struct *tidle)
+{
+ if (cpu_online(cpu))
+ return 0;
+
+ if (num_online_cpus() < nr_cpu_ids &&
+ num_online_cpus() < setup_max_cpus &&
+ smp_boot_one_cpu(cpu, tidle))
+ return -EIO;
+
+ return cpu_online(cpu) ? 0 : -EIO;
+}
+
+/*
+ * __cpu_disable runs on the processor to be shutdown.
+ */
+int __cpu_disable(void)
+{
+#ifdef CONFIG_HOTPLUG_CPU
+ unsigned int cpu = smp_processor_id();
+
+ remove_cpu_topology(cpu);
+
+ /*
+ * Take this CPU offline. Once we clear this, we can't return,
+ * and we must not schedule until we're ready to give up the cpu.
+ */
+ set_cpu_online(cpu, false);
+
+ /* Find a new timesync master */
+ if (cpu == time_keeper_id) {
+ time_keeper_id = cpumask_first(cpu_online_mask);
+ pr_info("CPU %d is now promoted to time-keeper master\n", time_keeper_id);
+ }
+
+ disable_percpu_irq(IPI_IRQ);
+
+ irq_migrate_all_off_this_cpu();
+
+ flush_cache_all_local();
+ flush_tlb_all_local(NULL);
+
+ /* disable all irqs, including timer irq */
+ local_irq_disable();
+
+ /* wait for next timer irq ... */
+ mdelay(1000/HZ+100);
+
+ /* ... and then clear all pending external irqs */
+ set_eiem(0);
+ mtctl(~0UL, CR_EIRR);
+ mfctl(CR_EIRR);
+ mtctl(0, CR_EIRR);
+#endif
+ return 0;
+}
+
+/*
+ * called on the thread which is asking for a CPU to be shutdown -
+ * waits until shutdown has completed, or it is timed out.
+ */
+void __cpu_die(unsigned int cpu)
+{
+ pdc_cpu_rendezvous_lock();
+}
+
+void arch_cpuhp_cleanup_dead_cpu(unsigned int cpu)
+{
+ pr_info("CPU%u: is shutting down\n", cpu);
+
+ /* set task's state to interruptible sleep */
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout((IS_ENABLED(CONFIG_64BIT) ? 8:2) * HZ);
+
+ pdc_cpu_rendezvous_unlock();
+}
diff --git a/arch/parisc/kernel/stacktrace.c b/arch/parisc/kernel/stacktrace.c
new file mode 100644
index 000000000..023834ef5
--- /dev/null
+++ b/arch/parisc/kernel/stacktrace.c
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Stack trace management functions
+ *
+ * Copyright (C) 2009-2021 Helge Deller <deller@gmx.de>
+ * based on arch/x86/kernel/stacktrace.c by Ingo Molnar <mingo@redhat.com>
+ * and parisc unwind functions by Randolph Chung <tausq@debian.org>
+ *
+ * TODO: Userspace stacktrace (CONFIG_USER_STACKTRACE_SUPPORT)
+ */
+#include <linux/kernel.h>
+#include <linux/stacktrace.h>
+
+#include <asm/unwind.h>
+
+static void notrace walk_stackframe(struct task_struct *task,
+ struct pt_regs *regs, bool (*fn)(void *, unsigned long), void *cookie)
+{
+ struct unwind_frame_info info;
+
+ unwind_frame_init_task(&info, task, NULL);
+ while (1) {
+ if (unwind_once(&info) < 0 || info.ip == 0)
+ break;
+
+ if (__kernel_text_address(info.ip))
+ if (!fn(cookie, info.ip))
+ break;
+ }
+}
+
+void arch_stack_walk(stack_trace_consume_fn consume_entry, void *cookie,
+ struct task_struct *task, struct pt_regs *regs)
+{
+ walk_stackframe(task, regs, consume_entry, cookie);
+}
+
+int arch_stack_walk_reliable(stack_trace_consume_fn consume_entry, void *cookie,
+ struct task_struct *task)
+{
+ walk_stackframe(task, NULL, consume_entry, cookie);
+ return 1;
+}
diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c
new file mode 100644
index 000000000..98af719d5
--- /dev/null
+++ b/arch/parisc/kernel/sys_parisc.c
@@ -0,0 +1,404 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+/*
+ * PARISC specific syscalls
+ *
+ * Copyright (C) 1999-2003 Matthew Wilcox <willy at parisc-linux.org>
+ * Copyright (C) 2000-2003 Paul Bame <bame at parisc-linux.org>
+ * Copyright (C) 2001 Thomas Bogendoerfer <tsbogend at parisc-linux.org>
+ * Copyright (C) 1999-2020 Helge Deller <deller@gmx.de>
+ */
+
+#include <linux/uaccess.h>
+#include <asm/elf.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/linkage.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/sched/signal.h>
+#include <linux/sched/mm.h>
+#include <linux/shm.h>
+#include <linux/syscalls.h>
+#include <linux/utsname.h>
+#include <linux/personality.h>
+#include <linux/random.h>
+#include <linux/compat.h>
+#include <linux/elf-randomize.h>
+
+/*
+ * Construct an artificial page offset for the mapping based on the physical
+ * address of the kernel file mapping variable.
+ */
+#define GET_FILP_PGOFF(filp) \
+ (filp ? (((unsigned long) filp->f_mapping) >> 8) \
+ & ((SHM_COLOUR-1) >> PAGE_SHIFT) : 0UL)
+
+static unsigned long shared_align_offset(unsigned long filp_pgoff,
+ unsigned long pgoff)
+{
+ return (filp_pgoff + pgoff) << PAGE_SHIFT;
+}
+
+static inline unsigned long COLOR_ALIGN(unsigned long addr,
+ unsigned long filp_pgoff, unsigned long pgoff)
+{
+ unsigned long base = (addr+SHM_COLOUR-1) & ~(SHM_COLOUR-1);
+ unsigned long off = (SHM_COLOUR-1) &
+ shared_align_offset(filp_pgoff, pgoff);
+ return base + off;
+}
+
+
+#define STACK_SIZE_DEFAULT (USER_WIDE_MODE \
+ ? (1 << 30) /* 1 GB */ \
+ : (CONFIG_STACK_MAX_DEFAULT_SIZE_MB*1024*1024))
+
+unsigned long calc_max_stack_size(unsigned long stack_max)
+{
+#ifdef CONFIG_COMPAT
+ if (!USER_WIDE_MODE && (stack_max == COMPAT_RLIM_INFINITY))
+ stack_max = STACK_SIZE_DEFAULT;
+ else
+#endif
+ if (stack_max == RLIM_INFINITY)
+ stack_max = STACK_SIZE_DEFAULT;
+
+ return stack_max;
+}
+
+
+/*
+ * Top of mmap area (just below the process stack).
+ */
+
+/*
+ * When called from arch_get_unmapped_area(), rlim_stack will be NULL,
+ * indicating that "current" should be used instead of a passed-in
+ * value from the exec bprm as done with arch_pick_mmap_layout().
+ */
+unsigned long mmap_upper_limit(struct rlimit *rlim_stack)
+{
+ unsigned long stack_base;
+
+ /* Limit stack size - see setup_arg_pages() in fs/exec.c */
+ stack_base = rlim_stack ? rlim_stack->rlim_max
+ : rlimit_max(RLIMIT_STACK);
+
+ stack_base = calc_max_stack_size(stack_base);
+
+ /* Add space for stack randomization. */
+ if (current->flags & PF_RANDOMIZE)
+ stack_base += (STACK_RND_MASK << PAGE_SHIFT);
+
+ return PAGE_ALIGN(STACK_TOP - stack_base);
+}
+
+enum mmap_allocation_direction {UP, DOWN};
+
+static unsigned long arch_get_unmapped_area_common(struct file *filp,
+ unsigned long addr, unsigned long len, unsigned long pgoff,
+ unsigned long flags, enum mmap_allocation_direction dir)
+{
+ struct mm_struct *mm = current->mm;
+ struct vm_area_struct *vma, *prev;
+ unsigned long filp_pgoff;
+ int do_color_align;
+ struct vm_unmapped_area_info info;
+
+ if (unlikely(len > TASK_SIZE))
+ return -ENOMEM;
+
+ do_color_align = 0;
+ if (filp || (flags & MAP_SHARED))
+ do_color_align = 1;
+ filp_pgoff = GET_FILP_PGOFF(filp);
+
+ if (flags & MAP_FIXED) {
+ /* Even MAP_FIXED mappings must reside within TASK_SIZE */
+ if (TASK_SIZE - len < addr)
+ return -EINVAL;
+
+ if ((flags & MAP_SHARED) && filp &&
+ (addr - shared_align_offset(filp_pgoff, pgoff))
+ & (SHM_COLOUR - 1))
+ return -EINVAL;
+ return addr;
+ }
+
+ if (addr) {
+ if (do_color_align)
+ addr = COLOR_ALIGN(addr, filp_pgoff, pgoff);
+ else
+ addr = PAGE_ALIGN(addr);
+
+ vma = find_vma_prev(mm, addr, &prev);
+ if (TASK_SIZE - len >= addr &&
+ (!vma || addr + len <= vm_start_gap(vma)) &&
+ (!prev || addr >= vm_end_gap(prev)))
+ return addr;
+ }
+
+ info.length = len;
+ info.align_mask = do_color_align ? (PAGE_MASK & (SHM_COLOUR - 1)) : 0;
+ info.align_offset = shared_align_offset(filp_pgoff, pgoff);
+
+ if (dir == DOWN) {
+ info.flags = VM_UNMAPPED_AREA_TOPDOWN;
+ info.low_limit = PAGE_SIZE;
+ info.high_limit = mm->mmap_base;
+ addr = vm_unmapped_area(&info);
+ if (!(addr & ~PAGE_MASK))
+ return addr;
+ VM_BUG_ON(addr != -ENOMEM);
+
+ /*
+ * A failed mmap() very likely causes application failure,
+ * so fall back to the bottom-up function here. This scenario
+ * can happen with large stack limits and large mmap()
+ * allocations.
+ */
+ }
+
+ info.flags = 0;
+ info.low_limit = mm->mmap_base;
+ info.high_limit = mmap_upper_limit(NULL);
+ return vm_unmapped_area(&info);
+}
+
+unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
+ unsigned long len, unsigned long pgoff, unsigned long flags)
+{
+ return arch_get_unmapped_area_common(filp,
+ addr, len, pgoff, flags, UP);
+}
+
+unsigned long arch_get_unmapped_area_topdown(struct file *filp,
+ unsigned long addr, unsigned long len, unsigned long pgoff,
+ unsigned long flags)
+{
+ return arch_get_unmapped_area_common(filp,
+ addr, len, pgoff, flags, DOWN);
+}
+
+asmlinkage unsigned long sys_mmap2(unsigned long addr, unsigned long len,
+ unsigned long prot, unsigned long flags, unsigned long fd,
+ unsigned long pgoff)
+{
+ /* Make sure the shift for mmap2 is constant (12), no matter what PAGE_SIZE
+ we have. */
+ return ksys_mmap_pgoff(addr, len, prot, flags, fd,
+ pgoff >> (PAGE_SHIFT - 12));
+}
+
+asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
+ unsigned long prot, unsigned long flags, unsigned long fd,
+ unsigned long offset)
+{
+ if (!(offset & ~PAGE_MASK)) {
+ return ksys_mmap_pgoff(addr, len, prot, flags, fd,
+ offset >> PAGE_SHIFT);
+ } else {
+ return -EINVAL;
+ }
+}
+
+/* Fucking broken ABI */
+
+#ifdef CONFIG_64BIT
+asmlinkage long parisc_truncate64(const char __user * path,
+ unsigned int high, unsigned int low)
+{
+ return ksys_truncate(path, (long)high << 32 | low);
+}
+
+asmlinkage long parisc_ftruncate64(unsigned int fd,
+ unsigned int high, unsigned int low)
+{
+ return ksys_ftruncate(fd, (long)high << 32 | low);
+}
+
+/* stubs for the benefit of the syscall_table since truncate64 and truncate
+ * are identical on LP64 */
+asmlinkage long sys_truncate64(const char __user * path, unsigned long length)
+{
+ return ksys_truncate(path, length);
+}
+asmlinkage long sys_ftruncate64(unsigned int fd, unsigned long length)
+{
+ return ksys_ftruncate(fd, length);
+}
+asmlinkage long sys_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+ return sys_fcntl(fd, cmd, arg);
+}
+#else
+
+asmlinkage long parisc_truncate64(const char __user * path,
+ unsigned int high, unsigned int low)
+{
+ return ksys_truncate(path, (loff_t)high << 32 | low);
+}
+
+asmlinkage long parisc_ftruncate64(unsigned int fd,
+ unsigned int high, unsigned int low)
+{
+ return sys_ftruncate64(fd, (loff_t)high << 32 | low);
+}
+#endif
+
+asmlinkage ssize_t parisc_pread64(unsigned int fd, char __user *buf, size_t count,
+ unsigned int high, unsigned int low)
+{
+ return ksys_pread64(fd, buf, count, (loff_t)high << 32 | low);
+}
+
+asmlinkage ssize_t parisc_pwrite64(unsigned int fd, const char __user *buf,
+ size_t count, unsigned int high, unsigned int low)
+{
+ return ksys_pwrite64(fd, buf, count, (loff_t)high << 32 | low);
+}
+
+asmlinkage ssize_t parisc_readahead(int fd, unsigned int high, unsigned int low,
+ size_t count)
+{
+ return ksys_readahead(fd, (loff_t)high << 32 | low, count);
+}
+
+asmlinkage long parisc_fadvise64_64(int fd,
+ unsigned int high_off, unsigned int low_off,
+ unsigned int high_len, unsigned int low_len, int advice)
+{
+ return ksys_fadvise64_64(fd, (loff_t)high_off << 32 | low_off,
+ (loff_t)high_len << 32 | low_len, advice);
+}
+
+asmlinkage long parisc_sync_file_range(int fd,
+ u32 hi_off, u32 lo_off, u32 hi_nbytes, u32 lo_nbytes,
+ unsigned int flags)
+{
+ return ksys_sync_file_range(fd, (loff_t)hi_off << 32 | lo_off,
+ (loff_t)hi_nbytes << 32 | lo_nbytes, flags);
+}
+
+asmlinkage long parisc_fallocate(int fd, int mode, u32 offhi, u32 offlo,
+ u32 lenhi, u32 lenlo)
+{
+ return ksys_fallocate(fd, mode, ((u64)offhi << 32) | offlo,
+ ((u64)lenhi << 32) | lenlo);
+}
+
+asmlinkage long parisc_personality(unsigned long personality)
+{
+ long err;
+
+ if (personality(current->personality) == PER_LINUX32
+ && personality(personality) == PER_LINUX)
+ personality = (personality & ~PER_MASK) | PER_LINUX32;
+
+ err = sys_personality(personality);
+ if (personality(err) == PER_LINUX32)
+ err = (err & ~PER_MASK) | PER_LINUX;
+
+ return err;
+}
+
+/*
+ * Up to kernel v5.9 we defined O_NONBLOCK as 000200004,
+ * since then O_NONBLOCK is defined as 000200000.
+ *
+ * The following wrapper functions mask out the old
+ * O_NDELAY bit from calls which use O_NONBLOCK.
+ *
+ * XXX: Remove those in year 2022 (or later)?
+ */
+
+#define O_NONBLOCK_OLD 000200004
+#define O_NONBLOCK_MASK_OUT (O_NONBLOCK_OLD & ~O_NONBLOCK)
+
+static int FIX_O_NONBLOCK(int flags)
+{
+ if ((flags & O_NONBLOCK_MASK_OUT) &&
+ !test_thread_flag(TIF_NONBLOCK_WARNING)) {
+ set_thread_flag(TIF_NONBLOCK_WARNING);
+ pr_warn("%s(%d) uses a deprecated O_NONBLOCK value."
+ " Please recompile with newer glibc.\n",
+ current->comm, current->pid);
+ }
+ return flags & ~O_NONBLOCK_MASK_OUT;
+}
+
+asmlinkage long parisc_timerfd_create(int clockid, int flags)
+{
+ flags = FIX_O_NONBLOCK(flags);
+ return sys_timerfd_create(clockid, flags);
+}
+
+asmlinkage long parisc_signalfd4(int ufd, sigset_t __user *user_mask,
+ size_t sizemask, int flags)
+{
+ flags = FIX_O_NONBLOCK(flags);
+ return sys_signalfd4(ufd, user_mask, sizemask, flags);
+}
+
+#ifdef CONFIG_COMPAT
+asmlinkage long parisc_compat_signalfd4(int ufd,
+ compat_sigset_t __user *user_mask,
+ compat_size_t sizemask, int flags)
+{
+ flags = FIX_O_NONBLOCK(flags);
+ return compat_sys_signalfd4(ufd, user_mask, sizemask, flags);
+}
+#endif
+
+asmlinkage long parisc_eventfd2(unsigned int count, int flags)
+{
+ flags = FIX_O_NONBLOCK(flags);
+ return sys_eventfd2(count, flags);
+}
+
+asmlinkage long parisc_userfaultfd(int flags)
+{
+ flags = FIX_O_NONBLOCK(flags);
+ return sys_userfaultfd(flags);
+}
+
+asmlinkage long parisc_pipe2(int __user *fildes, int flags)
+{
+ flags = FIX_O_NONBLOCK(flags);
+ return sys_pipe2(fildes, flags);
+}
+
+asmlinkage long parisc_inotify_init1(int flags)
+{
+ flags = FIX_O_NONBLOCK(flags);
+ return sys_inotify_init1(flags);
+}
+
+/*
+ * madvise() wrapper
+ *
+ * Up to kernel v6.1 parisc has different values than all other
+ * platforms for the MADV_xxx flags listed below.
+ * To keep binary compatibility with existing userspace programs
+ * translate the former values to the new values.
+ *
+ * XXX: Remove this wrapper in year 2025 (or later)
+ */
+
+asmlinkage notrace long parisc_madvise(unsigned long start, size_t len_in, int behavior)
+{
+ switch (behavior) {
+ case 65: behavior = MADV_MERGEABLE; break;
+ case 66: behavior = MADV_UNMERGEABLE; break;
+ case 67: behavior = MADV_HUGEPAGE; break;
+ case 68: behavior = MADV_NOHUGEPAGE; break;
+ case 69: behavior = MADV_DONTDUMP; break;
+ case 70: behavior = MADV_DODUMP; break;
+ case 71: behavior = MADV_WIPEONFORK; break;
+ case 72: behavior = MADV_KEEPONFORK; break;
+ case 73: behavior = MADV_COLLAPSE; break;
+ }
+
+ return sys_madvise(start, len_in, behavior);
+}
diff --git a/arch/parisc/kernel/sys_parisc32.c b/arch/parisc/kernel/sys_parisc32.c
new file mode 100644
index 000000000..2a12a547b
--- /dev/null
+++ b/arch/parisc/kernel/sys_parisc32.c
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * sys_parisc32.c: Conversion between 32bit and 64bit native syscalls.
+ *
+ * Copyright (C) 2000-2001 Hewlett Packard Company
+ * Copyright (C) 2000 John Marvin
+ * Copyright (C) 2001 Matthew Wilcox
+ * Copyright (C) 2014 Helge Deller <deller@gmx.de>
+ *
+ * These routines maintain argument size conversion between 32bit and 64bit
+ * environment. Based heavily on sys_ia32.c and sys_sparc32.c.
+ */
+
+#include <linux/compat.h>
+#include <linux/kernel.h>
+#include <linux/syscalls.h>
+
+
+asmlinkage long sys32_unimplemented(int r26, int r25, int r24, int r23,
+ int r22, int r21, int r20)
+{
+ printk(KERN_ERR "%s(%d): Unimplemented 32 on 64 syscall #%d!\n",
+ current->comm, current->pid, r20);
+ return -ENOSYS;
+}
+
+asmlinkage long sys32_fanotify_mark(compat_int_t fanotify_fd, compat_uint_t flags,
+ compat_uint_t mask0, compat_uint_t mask1, compat_int_t dfd,
+ const char __user * pathname)
+{
+ return sys_fanotify_mark(fanotify_fd, flags,
+ ((__u64)mask1 << 32) | mask0,
+ dfd, pathname);
+}
diff --git a/arch/parisc/kernel/syscall.S b/arch/parisc/kernel/syscall.S
new file mode 100644
index 000000000..1f51aa9c8
--- /dev/null
+++ b/arch/parisc/kernel/syscall.S
@@ -0,0 +1,1358 @@
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * System call entry code / Linux gateway page
+ * Copyright (c) Matthew Wilcox 1999 <willy@infradead.org>
+ * Licensed under the GNU GPL.
+ * thanks to Philipp Rumpf, Mike Shaver and various others
+ * sorry about the wall, puffin..
+ */
+
+/*
+How does the Linux gateway page on PA-RISC work?
+------------------------------------------------
+The Linux gateway page on PA-RISC is "special".
+It actually has PAGE_GATEWAY bits set (this is linux terminology; in parisc
+terminology it's Execute, promote to PL0) in the page map. So anything
+executing on this page executes with kernel level privilege (there's more to it
+than that: to have this happen, you also have to use a branch with a ,gate
+completer to activate the privilege promotion). The upshot is that everything
+that runs on the gateway page runs at kernel privilege but with the current
+user process address space (although you have access to kernel space via %sr2).
+For the 0x100 syscall entry, we redo the space registers to point to the kernel
+address space (preserving the user address space in %sr3), move to wide mode if
+required, save the user registers and branch into the kernel syscall entry
+point. For all the other functions, we execute at kernel privilege but don't
+flip address spaces. The basic upshot of this is that these code snippets are
+executed atomically (because the kernel can't be pre-empted) and they may
+perform architecturally forbidden (to PL3) operations (like setting control
+registers).
+*/
+
+
+#include <asm/asm-offsets.h>
+#include <asm/unistd.h>
+#include <asm/errno.h>
+#include <asm/page.h>
+#include <asm/psw.h>
+#include <asm/thread_info.h>
+#include <asm/assembly.h>
+#include <asm/processor.h>
+#include <asm/cache.h>
+#include <asm/spinlock_types.h>
+
+#include <linux/linkage.h>
+
+ /* We fill the empty parts of the gateway page with
+ * something that will kill the kernel or a
+ * userspace application.
+ */
+#define KILL_INSN break 0,0
+
+ .level PA_ASM_LEVEL
+
+ .macro lws_pagefault_disable reg1,reg2
+ mfctl %cr30, \reg2
+ ldo TASK_PAGEFAULT_DISABLED(\reg2), \reg2
+ ldw 0(%sr2,\reg2), \reg1
+ ldo 1(\reg1), \reg1
+ stw \reg1, 0(%sr2,\reg2)
+ .endm
+
+ .macro lws_pagefault_enable reg1,reg2
+ mfctl %cr30, \reg2
+ ldo TASK_PAGEFAULT_DISABLED(\reg2), \reg2
+ ldw 0(%sr2,\reg2), \reg1
+ ldo -1(\reg1), \reg1
+ stw \reg1, 0(%sr2,\reg2)
+ .endm
+
+ /* raise exception if spinlock content is not zero or
+ * __ARCH_SPIN_LOCK_UNLOCKED_VAL */
+ .macro spinlock_check spin_val,tmpreg
+#ifdef CONFIG_LIGHTWEIGHT_SPINLOCK_CHECK
+ ldi __ARCH_SPIN_LOCK_UNLOCKED_VAL, \tmpreg
+ andcm,= \spin_val, \tmpreg, %r0
+ .word SPINLOCK_BREAK_INSN
+#endif
+ .endm
+
+ .text
+
+ .import syscall_exit,code
+ .import syscall_exit_rfi,code
+
+ /* Linux gateway page is aliased to virtual page 0 in the kernel
+ * address space. Since it is a gateway page it cannot be
+ * dereferenced, so null pointers will still fault. We start
+ * the actual entry point at 0x100. We put break instructions
+ * at the beginning of the page to trap null indirect function
+ * pointers.
+ */
+
+ .align PAGE_SIZE
+ENTRY(linux_gateway_page)
+
+ /* ADDRESS 0x00 to 0xb0 = 176 bytes / 4 bytes per insn = 44 insns */
+ .rept 44
+ KILL_INSN
+ .endr
+
+ /* ADDRESS 0xb0 to 0xb8, lws uses two insns for entry */
+ /* Light-weight-syscall entry must always be located at 0xb0 */
+ /* WARNING: Keep this number updated with table size changes */
+#define __NR_lws_entries (5)
+
+lws_entry:
+ gate lws_start, %r0 /* increase privilege */
+ depi PRIV_USER, 31, 2, %r31 /* Ensure we return into user mode. */
+
+ /* Fill from 0xb8 to 0xe0 */
+ .rept 10
+ KILL_INSN
+ .endr
+
+ /* This function MUST be located at 0xe0 for glibc's threading
+ mechanism to work. DO NOT MOVE THIS CODE EVER! */
+set_thread_pointer:
+ gate .+8, %r0 /* increase privilege */
+ depi PRIV_USER, 31, 2, %r31 /* Ensure we return into user mode. */
+ be 0(%sr7,%r31) /* return to user space */
+ mtctl %r26, %cr27 /* move arg0 to the control register */
+
+ /* Increase the chance of trapping if random jumps occur to this
+ address, fill from 0xf0 to 0x100 */
+ .rept 4
+ KILL_INSN
+ .endr
+
+/* This address must remain fixed at 0x100 for glibc's syscalls to work */
+ .align LINUX_GATEWAY_ADDR
+linux_gateway_entry:
+ gate .+8, %r0 /* become privileged */
+ mtsp %r0,%sr4 /* get kernel space into sr4 */
+ mtsp %r0,%sr5 /* get kernel space into sr5 */
+ mtsp %r0,%sr6 /* get kernel space into sr6 */
+
+#ifdef CONFIG_64BIT
+ /* Store W bit on entry to the syscall in case it's a wide userland
+ * process. */
+ ssm PSW_SM_W, %r1
+ extrd,u %r1,PSW_W_BIT,1,%r1
+ /* sp must be aligned on 4, so deposit the W bit setting into
+ * the bottom of sp temporarily */
+ or,ev %r1,%r30,%r30
+ b,n 1f
+ /* The top halves of argument registers must be cleared on syscall
+ * entry from narrow executable.
+ */
+ depdi 0, 31, 32, %r26
+ depdi 0, 31, 32, %r25
+ depdi 0, 31, 32, %r24
+ depdi 0, 31, 32, %r23
+ depdi 0, 31, 32, %r22
+ depdi 0, 31, 32, %r21
+1:
+#endif
+
+ /* We use a rsm/ssm pair to prevent sr3 from being clobbered
+ * by external interrupts.
+ */
+ mfsp %sr7,%r1 /* save user sr7 */
+ rsm PSW_SM_I, %r0 /* disable interrupts */
+ mtsp %r1,%sr3 /* and store it in sr3 */
+
+ mfctl %cr30,%r1
+ xor %r1,%r30,%r30 /* ye olde xor trick */
+ xor %r1,%r30,%r1
+ xor %r1,%r30,%r30
+
+ LDREG TASK_STACK(%r30),%r30 /* set up kernel stack */
+ ldo FRAME_SIZE(%r30),%r30
+ /* N.B.: It is critical that we don't set sr7 to 0 until r30
+ * contains a valid kernel stack pointer. It is also
+ * critical that we don't start using the kernel stack
+ * until after sr7 has been set to 0.
+ */
+
+ mtsp %r0,%sr7 /* get kernel space into sr7 */
+ ssm PSW_SM_I, %r0 /* enable interrupts */
+ STREGM %r1,FRAME_SIZE(%r30) /* save r1 (usp) here for now */
+ mfctl %cr30,%r1 /* get task ptr in %r1 */
+
+ /* Save some registers for sigcontext and potential task
+ switch (see entry.S for the details of which ones are
+ saved/restored). TASK_PT_PSW is zeroed so we can see whether
+ a process is on a syscall or not. For an interrupt the real
+ PSW value is stored. This is needed for gdb and sys_ptrace. */
+ STREG %r0, TASK_PT_PSW(%r1)
+ STREG %r2, TASK_PT_GR2(%r1) /* preserve rp */
+ STREG %r19, TASK_PT_GR19(%r1)
+
+ LDREGM -FRAME_SIZE(%r30), %r2 /* get users sp back */
+#ifdef CONFIG_64BIT
+ extrd,u %r2,63,1,%r19 /* W hidden in bottom bit */
+#if 0
+ xor %r19,%r2,%r2 /* clear bottom bit */
+ depd,z %r19,1,1,%r19
+ std %r19,TASK_PT_PSW(%r1)
+#endif
+#endif
+ STREG %r2, TASK_PT_GR30(%r1) /* ... and save it */
+
+ STREG %r20, TASK_PT_GR20(%r1) /* Syscall number */
+ STREG %r21, TASK_PT_GR21(%r1)
+ STREG %r22, TASK_PT_GR22(%r1)
+ STREG %r23, TASK_PT_GR23(%r1) /* 4th argument */
+ STREG %r24, TASK_PT_GR24(%r1) /* 3rd argument */
+ STREG %r25, TASK_PT_GR25(%r1) /* 2nd argument */
+ STREG %r26, TASK_PT_GR26(%r1) /* 1st argument */
+ STREG %r27, TASK_PT_GR27(%r1) /* user dp */
+ STREG %r28, TASK_PT_GR28(%r1) /* return value 0 */
+ STREG %r0, TASK_PT_ORIG_R28(%r1) /* don't prohibit restarts */
+ STREG %r29, TASK_PT_GR29(%r1) /* return value 1 */
+ STREG %r31, TASK_PT_GR31(%r1) /* preserve syscall return ptr */
+
+ ldo TASK_PT_FR0(%r1), %r27 /* save fpregs from the kernel */
+ save_fp %r27 /* or potential task switch */
+
+ mfctl %cr11, %r27 /* i.e. SAR */
+ STREG %r27, TASK_PT_SAR(%r1)
+
+ loadgp
+
+#ifdef CONFIG_64BIT
+ ldo -16(%r30),%r29 /* Reference param save area */
+ copy %r19,%r2 /* W bit back to r2 */
+#else
+ /* no need to save these on stack in wide mode because the first 8
+ * args are passed in registers */
+ stw %r22, -52(%r30) /* 5th argument */
+ stw %r21, -56(%r30) /* 6th argument */
+#endif
+
+ /* Are we being ptraced? */
+ mfctl %cr30, %r1
+ LDREG TASK_TI_FLAGS(%r1),%r1
+ ldi _TIF_SYSCALL_TRACE_MASK, %r19
+ and,COND(=) %r1, %r19, %r0
+ b,n .Ltracesys
+
+ /* Note! We cannot use the syscall table that is mapped
+ nearby since the gateway page is mapped execute-only. */
+
+#ifdef CONFIG_64BIT
+ ldil L%sys_call_table, %r1
+ or,= %r2,%r2,%r2
+ addil L%(sys_call_table64-sys_call_table), %r1
+ ldo R%sys_call_table(%r1), %r19
+ or,= %r2,%r2,%r2
+ ldo R%sys_call_table64(%r1), %r19
+#else
+ load32 sys_call_table, %r19
+#endif
+ comiclr,>> __NR_Linux_syscalls, %r20, %r0
+ b,n .Lsyscall_nosys
+
+ LDREGX %r20(%r19), %r19
+
+ /* If this is a sys_rt_sigreturn call, and the signal was received
+ * when not in_syscall, then we want to return via syscall_exit_rfi,
+ * not syscall_exit. Signal no. in r20, in_syscall in r25 (see
+ * trampoline code in signal.c).
+ */
+ ldi __NR_rt_sigreturn,%r2
+ comb,= %r2,%r20,.Lrt_sigreturn
+.Lin_syscall:
+ ldil L%syscall_exit,%r2
+ be 0(%sr7,%r19)
+ ldo R%syscall_exit(%r2),%r2
+.Lrt_sigreturn:
+ comib,<> 0,%r25,.Lin_syscall
+ ldil L%syscall_exit_rfi,%r2
+ be 0(%sr7,%r19)
+ ldo R%syscall_exit_rfi(%r2),%r2
+
+ /* Note! Because we are not running where we were linked, any
+ calls to functions external to this file must be indirect. To
+ be safe, we apply the opposite rule to functions within this
+ file, with local labels given to them to ensure correctness. */
+
+.Lsyscall_nosys:
+syscall_nosys:
+ ldil L%syscall_exit,%r1
+ be R%syscall_exit(%sr7,%r1)
+ ldo -ENOSYS(%r0),%r28 /* set errno */
+
+
+/* Warning! This trace code is a virtual duplicate of the code above so be
+ * sure to maintain both! */
+.Ltracesys:
+tracesys:
+ /* Need to save more registers so the debugger can see where we
+ * are. This saves only the lower 8 bits of PSW, so that the C
+ * bit is still clear on syscalls, and the D bit is set if this
+ * full register save path has been executed. We check the D
+ * bit on syscall_return_rfi to determine which registers to
+ * restore. An interrupt results in a full PSW saved with the
+ * C bit set, a non-straced syscall entry results in C and D clear
+ * in the saved PSW.
+ */
+ mfctl %cr30,%r1 /* get task ptr */
+ ssm 0,%r2
+ STREG %r2,TASK_PT_PSW(%r1) /* Lower 8 bits only!! */
+ mfsp %sr0,%r2
+ STREG %r2,TASK_PT_SR0(%r1)
+ mfsp %sr1,%r2
+ STREG %r2,TASK_PT_SR1(%r1)
+ mfsp %sr2,%r2
+ STREG %r2,TASK_PT_SR2(%r1)
+ mfsp %sr3,%r2
+ STREG %r2,TASK_PT_SR3(%r1)
+ STREG %r2,TASK_PT_SR4(%r1)
+ STREG %r2,TASK_PT_SR5(%r1)
+ STREG %r2,TASK_PT_SR6(%r1)
+ STREG %r2,TASK_PT_SR7(%r1)
+ STREG %r2,TASK_PT_IASQ0(%r1)
+ STREG %r2,TASK_PT_IASQ1(%r1)
+ LDREG TASK_PT_GR31(%r1),%r2
+ STREG %r2,TASK_PT_IAOQ0(%r1)
+ ldo 4(%r2),%r2
+ STREG %r2,TASK_PT_IAOQ1(%r1)
+ ldo TASK_REGS(%r1),%r2
+ /* reg_save %r2 */
+ STREG %r3,PT_GR3(%r2)
+ STREG %r4,PT_GR4(%r2)
+ STREG %r5,PT_GR5(%r2)
+ STREG %r6,PT_GR6(%r2)
+ STREG %r7,PT_GR7(%r2)
+ STREG %r8,PT_GR8(%r2)
+ STREG %r9,PT_GR9(%r2)
+ STREG %r10,PT_GR10(%r2)
+ STREG %r11,PT_GR11(%r2)
+ STREG %r12,PT_GR12(%r2)
+ STREG %r13,PT_GR13(%r2)
+ STREG %r14,PT_GR14(%r2)
+ STREG %r15,PT_GR15(%r2)
+ STREG %r16,PT_GR16(%r2)
+ STREG %r17,PT_GR17(%r2)
+ STREG %r18,PT_GR18(%r2)
+ /* Finished saving things for the debugger */
+
+ copy %r2,%r26
+ ldil L%do_syscall_trace_enter,%r1
+ ldil L%tracesys_next,%r2
+ be R%do_syscall_trace_enter(%sr7,%r1)
+ ldo R%tracesys_next(%r2),%r2
+
+tracesys_next:
+ /* do_syscall_trace_enter either returned the syscallno, or -1L,
+ * so we skip restoring the PT_GR20 below, since we pulled it from
+ * task->thread.regs.gr[20] above.
+ */
+ copy %ret0,%r20
+
+ mfctl %cr30,%r1 /* get task ptr */
+ LDREG TASK_PT_GR28(%r1), %r28 /* Restore return value */
+ LDREG TASK_PT_GR26(%r1), %r26 /* Restore the users args */
+ LDREG TASK_PT_GR25(%r1), %r25
+ LDREG TASK_PT_GR24(%r1), %r24
+ LDREG TASK_PT_GR23(%r1), %r23
+ LDREG TASK_PT_GR22(%r1), %r22
+ LDREG TASK_PT_GR21(%r1), %r21
+#ifdef CONFIG_64BIT
+ ldo -16(%r30),%r29 /* Reference param save area */
+#else
+ stw %r22, -52(%r30) /* 5th argument */
+ stw %r21, -56(%r30) /* 6th argument */
+#endif
+
+ cmpib,COND(=),n -1,%r20,tracesys_exit /* seccomp may have returned -1 */
+ comiclr,>> __NR_Linux_syscalls, %r20, %r0
+ b,n .Ltracesys_nosys
+
+ /* Note! We cannot use the syscall table that is mapped
+ nearby since the gateway page is mapped execute-only. */
+
+#ifdef CONFIG_64BIT
+ LDREG TASK_PT_GR30(%r1), %r19 /* get users sp back */
+ extrd,u %r19,63,1,%r2 /* W hidden in bottom bit */
+
+ ldil L%sys_call_table, %r1
+ or,= %r2,%r2,%r2
+ addil L%(sys_call_table64-sys_call_table), %r1
+ ldo R%sys_call_table(%r1), %r19
+ or,= %r2,%r2,%r2
+ ldo R%sys_call_table64(%r1), %r19
+#else
+ load32 sys_call_table, %r19
+#endif
+
+ LDREGX %r20(%r19), %r19
+
+ /* If this is a sys_rt_sigreturn call, and the signal was received
+ * when not in_syscall, then we want to return via syscall_exit_rfi,
+ * not syscall_exit. Signal no. in r20, in_syscall in r25 (see
+ * trampoline code in signal.c).
+ */
+ ldi __NR_rt_sigreturn,%r2
+ comb,= %r2,%r20,.Ltrace_rt_sigreturn
+.Ltrace_in_syscall:
+ ldil L%tracesys_exit,%r2
+ be 0(%sr7,%r19)
+ ldo R%tracesys_exit(%r2),%r2
+
+.Ltracesys_nosys:
+ ldo -ENOSYS(%r0),%r28 /* set errno */
+
+ /* Do *not* call this function on the gateway page, because it
+ makes a direct call to syscall_trace. */
+
+tracesys_exit:
+ mfctl %cr30,%r1 /* get task ptr */
+#ifdef CONFIG_64BIT
+ ldo -16(%r30),%r29 /* Reference param save area */
+#endif
+ ldo TASK_REGS(%r1),%r26
+ BL do_syscall_trace_exit,%r2
+ STREG %r28,TASK_PT_GR28(%r1) /* save return value now */
+ mfctl %cr30,%r1 /* get task ptr */
+ LDREG TASK_PT_GR28(%r1), %r28 /* Restore return val. */
+
+ ldil L%syscall_exit,%r1
+ be,n R%syscall_exit(%sr7,%r1)
+
+.Ltrace_rt_sigreturn:
+ comib,<> 0,%r25,.Ltrace_in_syscall
+ ldil L%tracesys_sigexit,%r2
+ be 0(%sr7,%r19)
+ ldo R%tracesys_sigexit(%r2),%r2
+
+tracesys_sigexit:
+ mfctl %cr30,%r1 /* get task ptr */
+#ifdef CONFIG_64BIT
+ ldo -16(%r30),%r29 /* Reference param save area */
+#endif
+ BL do_syscall_trace_exit,%r2
+ ldo TASK_REGS(%r1),%r26
+
+ ldil L%syscall_exit_rfi,%r1
+ be,n R%syscall_exit_rfi(%sr7,%r1)
+
+
+ /*********************************************************
+ 32/64-bit Light-Weight-Syscall ABI
+
+ * - Indicates a hint for userspace inline asm
+ implementations.
+
+ Syscall number (caller-saves)
+ - %r20
+ * In asm clobber.
+
+ Argument registers (caller-saves)
+ - %r26, %r25, %r24, %r23, %r22
+ * In asm input.
+
+ Return registers (caller-saves)
+ - %r28 (return), %r21 (errno)
+ * In asm output.
+
+ Caller-saves registers
+ - %r1, %r27, %r29
+ - %r2 (return pointer)
+ - %r31 (ble link register)
+ * In asm clobber.
+
+ Callee-saves registers
+ - %r3-%r18
+ - %r30 (stack pointer)
+ * Not in asm clobber.
+
+ If userspace is 32-bit:
+ Callee-saves registers
+ - %r19 (32-bit PIC register)
+
+ Differences from 32-bit calling convention:
+ - Syscall number in %r20
+ - Additional argument register %r22 (arg4)
+ - Callee-saves %r19.
+
+ If userspace is 64-bit:
+ Callee-saves registers
+ - %r27 (64-bit PIC register)
+
+ Differences from 64-bit calling convention:
+ - Syscall number in %r20
+ - Additional argument register %r22 (arg4)
+ - Callee-saves %r27.
+
+ Error codes returned by entry path:
+
+ ENOSYS - r20 was an invalid LWS number.
+
+ *********************************************************/
+lws_start:
+
+#ifdef CONFIG_64BIT
+ ssm PSW_SM_W, %r1
+ extrd,u %r1,PSW_W_BIT,1,%r1
+ /* sp must be aligned on 4, so deposit the W bit setting into
+ * the bottom of sp temporarily */
+ or,od %r1,%r30,%r30
+
+ /* Clip LWS number to a 32-bit value for 32-bit processes */
+ depdi 0, 31, 32, %r20
+#endif
+
+ /* Is the lws entry number valid? */
+ comiclr,>> __NR_lws_entries, %r20, %r0
+ b,n lws_exit_nosys
+
+ /* Load table start */
+ ldil L%lws_table, %r1
+ ldo R%lws_table(%r1), %r28 /* Scratch use of r28 */
+ LDREGX %r20(%sr2,r28), %r21 /* Scratch use of r21 */
+
+ /* Jump to lws, lws table pointers already relocated */
+ be,n 0(%sr2,%r21)
+
+lws_exit_noerror:
+ lws_pagefault_enable %r1,%r21
+ ldi __ARCH_SPIN_LOCK_UNLOCKED_VAL, %r21
+ stw,ma %r21, 0(%sr2,%r20)
+ ssm PSW_SM_I, %r0
+ b lws_exit
+ copy %r0, %r21
+
+lws_wouldblock:
+ ssm PSW_SM_I, %r0
+ ldo 2(%r0), %r28
+ b lws_exit
+ ldo -EAGAIN(%r0), %r21
+
+lws_pagefault:
+ lws_pagefault_enable %r1,%r21
+ ldi __ARCH_SPIN_LOCK_UNLOCKED_VAL, %r21
+ stw,ma %r21, 0(%sr2,%r20)
+ ssm PSW_SM_I, %r0
+ ldo 3(%r0),%r28
+ b lws_exit
+ ldo -EAGAIN(%r0),%r21
+
+lws_fault:
+ ldo 1(%r0),%r28
+ b lws_exit
+ ldo -EFAULT(%r0),%r21
+
+lws_exit_nosys:
+ ldo -ENOSYS(%r0),%r21
+ /* Fall through: Return to userspace */
+
+lws_exit:
+#ifdef CONFIG_64BIT
+ /* decide whether to reset the wide mode bit
+ *
+ * For a syscall, the W bit is stored in the lowest bit
+ * of sp. Extract it and reset W if it is zero */
+ extrd,u,*<> %r30,63,1,%r1
+ rsm PSW_SM_W, %r0
+ /* now reset the lowest bit of sp if it was set */
+ xor %r30,%r1,%r30
+#endif
+ be,n 0(%sr7, %r31)
+
+
+
+ /***************************************************
+ Implementing 32bit CAS as an atomic operation:
+
+ %r26 - Address to examine
+ %r25 - Old value to check (old)
+ %r24 - New value to set (new)
+ %r28 - Return prev through this register.
+ %r21 - Kernel error code
+
+ %r21 returns the following error codes:
+ EAGAIN - CAS is busy, ldcw failed, try again.
+ EFAULT - Read or write failed.
+
+ If EAGAIN is returned, %r28 indicates the busy reason:
+ r28 == 1 - CAS is busy. lock contended.
+ r28 == 2 - CAS is busy. ldcw failed.
+ r28 == 3 - CAS is busy. page fault.
+
+ Scratch: r20, r28, r1
+
+ ****************************************************/
+
+ /* ELF64 Process entry path */
+lws_compare_and_swap64:
+#ifdef CONFIG_64BIT
+ b,n lws_compare_and_swap
+#else
+ /* If we are not a 64-bit kernel, then we don't
+ * have 64-bit input registers, and calling
+ * the 64-bit LWS CAS returns ENOSYS.
+ */
+ b,n lws_exit_nosys
+#endif
+
+ /* ELF32/ELF64 Process entry path */
+lws_compare_and_swap32:
+#ifdef CONFIG_64BIT
+ /* Wide mode user process? */
+ bb,<,n %sp, 31, lws_compare_and_swap
+
+ /* Clip all the input registers for 32-bit processes */
+ depdi 0, 31, 32, %r26
+ depdi 0, 31, 32, %r25
+ depdi 0, 31, 32, %r24
+#endif
+
+lws_compare_and_swap:
+ /* Trigger memory reference interruptions without writing to memory */
+1: ldw 0(%r26), %r28
+2: stbys,e %r0, 0(%r26)
+
+ /* Calculate 8-bit hash index from virtual address */
+ extru_safe %r26, 27, 8, %r20
+
+ /* Load start of lock table */
+ ldil L%lws_lock_start, %r28
+ ldo R%lws_lock_start(%r28), %r28
+
+ /* Find lock to use, the hash index is one of 0 to
+ 255, multiplied by 16 (keep it 16-byte aligned)
+ and add to the lock table offset. */
+ shlw %r20, 4, %r20
+ add %r20, %r28, %r20
+
+ rsm PSW_SM_I, %r0 /* Disable interrupts */
+
+ /* Try to acquire the lock */
+ LDCW 0(%sr2,%r20), %r28
+ spinlock_check %r28, %r21
+ comclr,<> %r0, %r28, %r0
+ b,n lws_wouldblock
+
+ /* Disable page faults to prevent sleeping in critical region */
+ lws_pagefault_disable %r21,%r28
+
+ /*
+ prev = *addr;
+ if ( prev == old )
+ *addr = new;
+ return prev;
+ */
+
+ /* NOTES:
+ This all works because intr_do_signal
+ and schedule both check the return iasq
+ and see that we are on the kernel page
+ so this process is never scheduled off
+ or is ever sent any signal of any sort,
+ thus it is wholly atomic from usrspace's
+ perspective
+ */
+ /* The load and store could fail */
+3: ldw 0(%r26), %r28
+ sub,<> %r28, %r25, %r0
+4: stw %r24, 0(%r26)
+ b,n lws_exit_noerror
+
+ /* A fault occurred on load or stbys,e store */
+5: b,n lws_fault
+ ASM_EXCEPTIONTABLE_ENTRY(1b-linux_gateway_page, 5b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(2b-linux_gateway_page, 5b-linux_gateway_page)
+
+ /* A page fault occurred in critical region */
+6: b,n lws_pagefault
+ ASM_EXCEPTIONTABLE_ENTRY(3b-linux_gateway_page, 6b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(4b-linux_gateway_page, 6b-linux_gateway_page)
+
+
+ /***************************************************
+ New CAS implementation which uses pointers and variable size
+ information. The value pointed by old and new MUST NOT change
+ while performing CAS. The lock only protects the value at %r26.
+
+ %r26 - Address to examine
+ %r25 - Pointer to the value to check (old)
+ %r24 - Pointer to the value to set (new)
+ %r23 - Size of the variable (0/1/2/3 for 8/16/32/64 bit)
+ %r28 - Return non-zero on failure
+ %r21 - Kernel error code
+
+ %r21 returns the following error codes:
+ EAGAIN - CAS is busy, ldcw failed, try again.
+ EFAULT - Read or write failed.
+
+ If EAGAIN is returned, %r28 indicates the busy reason:
+ r28 == 1 - CAS is busy. lock contended.
+ r28 == 2 - CAS is busy. ldcw failed.
+ r28 == 3 - CAS is busy. page fault.
+
+ Scratch: r20, r22, r28, r29, r1, fr4 (32bit for 64bit CAS only)
+
+ ****************************************************/
+
+lws_compare_and_swap_2:
+#ifdef CONFIG_64BIT
+ /* Wide mode user process? */
+ bb,<,n %sp, 31, cas2_begin
+
+ /* Clip the input registers for 32-bit processes. We don't
+ need to clip %r23 as we only use it for word operations */
+ depdi 0, 31, 32, %r26
+ depdi 0, 31, 32, %r25
+ depdi 0, 31, 32, %r24
+#endif
+
+cas2_begin:
+ /* Check the validity of the size pointer */
+ subi,>>= 3, %r23, %r0
+ b,n lws_exit_nosys
+
+ /* Jump to the functions which will load the old and new values into
+ registers depending on the their size */
+ shlw %r23, 2, %r29
+ blr %r29, %r0
+ nop
+
+ /* 8-bit load */
+1: ldb 0(%r25), %r25
+ b cas2_lock_start
+2: ldb 0(%r24), %r24
+ nop
+ nop
+ nop
+ nop
+ nop
+
+ /* 16-bit load */
+3: ldh 0(%r25), %r25
+ b cas2_lock_start
+4: ldh 0(%r24), %r24
+ nop
+ nop
+ nop
+ nop
+ nop
+
+ /* 32-bit load */
+5: ldw 0(%r25), %r25
+ b cas2_lock_start
+6: ldw 0(%r24), %r24
+ nop
+ nop
+ nop
+ nop
+ nop
+
+ /* 64-bit load */
+#ifdef CONFIG_64BIT
+7: ldd 0(%r25), %r25
+8: ldd 0(%r24), %r24
+#else
+ /* Load old value into r22/r23 - high/low */
+7: ldw 0(%r25), %r22
+8: ldw 4(%r25), %r23
+ /* Load new value into fr4 for atomic store later */
+9: flddx 0(%r24), %fr4
+#endif
+
+cas2_lock_start:
+ /* Trigger memory reference interruptions without writing to memory */
+ copy %r26, %r28
+ depi_safe 0, 31, 2, %r28
+10: ldw 0(%r28), %r1
+11: stbys,e %r0, 0(%r28)
+
+ /* Calculate 8-bit hash index from virtual address */
+ extru_safe %r26, 27, 8, %r20
+
+ /* Load start of lock table */
+ ldil L%lws_lock_start, %r28
+ ldo R%lws_lock_start(%r28), %r28
+
+ /* Find lock to use, the hash index is one of 0 to
+ 255, multiplied by 16 (keep it 16-byte aligned)
+ and add to the lock table offset. */
+ shlw %r20, 4, %r20
+ add %r20, %r28, %r20
+
+ rsm PSW_SM_I, %r0 /* Disable interrupts */
+
+ /* Try to acquire the lock */
+ LDCW 0(%sr2,%r20), %r28
+ spinlock_check %r28, %r21
+ comclr,<> %r0, %r28, %r0
+ b,n lws_wouldblock
+
+ /* Disable page faults to prevent sleeping in critical region */
+ lws_pagefault_disable %r21,%r28
+
+ /*
+ prev = *addr;
+ if ( prev == old )
+ *addr = new;
+ return prev;
+ */
+
+ /* NOTES:
+ This all works because intr_do_signal
+ and schedule both check the return iasq
+ and see that we are on the kernel page
+ so this process is never scheduled off
+ or is ever sent any signal of any sort,
+ thus it is wholly atomic from usrspace's
+ perspective
+ */
+
+ /* Jump to the correct function */
+ blr %r29, %r0
+ /* Set %r28 as non-zero for now */
+ ldo 1(%r0),%r28
+
+ /* 8-bit CAS */
+12: ldb 0(%r26), %r29
+ sub,= %r29, %r25, %r0
+ b,n lws_exit_noerror
+13: stb %r24, 0(%r26)
+ b lws_exit_noerror
+ copy %r0, %r28
+ nop
+ nop
+
+ /* 16-bit CAS */
+14: ldh 0(%r26), %r29
+ sub,= %r29, %r25, %r0
+ b,n lws_exit_noerror
+15: sth %r24, 0(%r26)
+ b lws_exit_noerror
+ copy %r0, %r28
+ nop
+ nop
+
+ /* 32-bit CAS */
+16: ldw 0(%r26), %r29
+ sub,= %r29, %r25, %r0
+ b,n lws_exit_noerror
+17: stw %r24, 0(%r26)
+ b lws_exit_noerror
+ copy %r0, %r28
+ nop
+ nop
+
+ /* 64-bit CAS */
+#ifdef CONFIG_64BIT
+18: ldd 0(%r26), %r29
+ sub,*= %r29, %r25, %r0
+ b,n lws_exit_noerror
+19: std %r24, 0(%r26)
+ copy %r0, %r28
+#else
+ /* Compare first word */
+18: ldw 0(%r26), %r29
+ sub,= %r29, %r22, %r0
+ b,n lws_exit_noerror
+ /* Compare second word */
+19: ldw 4(%r26), %r29
+ sub,= %r29, %r23, %r0
+ b,n lws_exit_noerror
+ /* Perform the store */
+20: fstdx %fr4, 0(%r26)
+ copy %r0, %r28
+#endif
+ b lws_exit_noerror
+ copy %r0, %r28
+
+ /* A fault occurred on load or stbys,e store */
+30: b,n lws_fault
+ ASM_EXCEPTIONTABLE_ENTRY(1b-linux_gateway_page, 30b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(2b-linux_gateway_page, 30b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(3b-linux_gateway_page, 30b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(4b-linux_gateway_page, 30b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(5b-linux_gateway_page, 30b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(6b-linux_gateway_page, 30b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(7b-linux_gateway_page, 30b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(8b-linux_gateway_page, 30b-linux_gateway_page)
+#ifndef CONFIG_64BIT
+ ASM_EXCEPTIONTABLE_ENTRY(9b-linux_gateway_page, 30b-linux_gateway_page)
+#endif
+
+ ASM_EXCEPTIONTABLE_ENTRY(10b-linux_gateway_page, 30b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(11b-linux_gateway_page, 30b-linux_gateway_page)
+
+ /* A page fault occurred in critical region */
+31: b,n lws_pagefault
+ ASM_EXCEPTIONTABLE_ENTRY(12b-linux_gateway_page, 31b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(13b-linux_gateway_page, 31b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(14b-linux_gateway_page, 31b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(15b-linux_gateway_page, 31b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(16b-linux_gateway_page, 31b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(17b-linux_gateway_page, 31b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(18b-linux_gateway_page, 31b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(19b-linux_gateway_page, 31b-linux_gateway_page)
+#ifndef CONFIG_64BIT
+ ASM_EXCEPTIONTABLE_ENTRY(20b-linux_gateway_page, 31b-linux_gateway_page)
+#endif
+
+
+ /***************************************************
+ LWS atomic exchange.
+
+ %r26 - Exchange address
+ %r25 - Size of the variable (0/1/2/3 for 8/16/32/64 bit)
+ %r24 - Address of new value
+ %r23 - Address of old value
+ %r28 - Return non-zero on failure
+ %r21 - Kernel error code
+
+ %r21 returns the following error codes:
+ EAGAIN - CAS is busy, ldcw failed, try again.
+ EFAULT - Read or write failed.
+
+ If EAGAIN is returned, %r28 indicates the busy reason:
+ r28 == 1 - CAS is busy. lock contended.
+ r28 == 2 - CAS is busy. ldcw failed.
+ r28 == 3 - CAS is busy. page fault.
+
+ Scratch: r20, r1
+
+ ****************************************************/
+
+lws_atomic_xchg:
+#ifdef CONFIG_64BIT
+ /* Wide mode user process? */
+ bb,<,n %sp, 31, atomic_xchg_begin
+
+ /* Clip the input registers for 32-bit processes. We don't
+ need to clip %r23 as we only use it for word operations */
+ depdi 0, 31, 32, %r26
+ depdi 0, 31, 32, %r25
+ depdi 0, 31, 32, %r24
+ depdi 0, 31, 32, %r23
+#endif
+
+atomic_xchg_begin:
+ /* Check the validity of the size pointer */
+ subi,>>= 3, %r25, %r0
+ b,n lws_exit_nosys
+
+ /* Jump to the functions which will load the old and new values into
+ registers depending on the their size */
+ shlw %r25, 2, %r1
+ blr %r1, %r0
+ nop
+
+ /* Perform exception checks */
+
+ /* 8-bit exchange */
+1: ldb 0(%r24), %r20
+ copy %r23, %r20
+ depi_safe 0, 31, 2, %r20
+ b atomic_xchg_start
+2: stbys,e %r0, 0(%r20)
+ nop
+ nop
+ nop
+
+ /* 16-bit exchange */
+3: ldh 0(%r24), %r20
+ copy %r23, %r20
+ depi_safe 0, 31, 2, %r20
+ b atomic_xchg_start
+4: stbys,e %r0, 0(%r20)
+ nop
+ nop
+ nop
+
+ /* 32-bit exchange */
+5: ldw 0(%r24), %r20
+ b atomic_xchg_start
+6: stbys,e %r0, 0(%r23)
+ nop
+ nop
+ nop
+ nop
+ nop
+
+ /* 64-bit exchange */
+#ifdef CONFIG_64BIT
+7: ldd 0(%r24), %r20
+8: stdby,e %r0, 0(%r23)
+#else
+7: ldw 0(%r24), %r20
+8: ldw 4(%r24), %r20
+ copy %r23, %r20
+ depi_safe 0, 31, 2, %r20
+9: stbys,e %r0, 0(%r20)
+10: stbys,e %r0, 4(%r20)
+#endif
+
+atomic_xchg_start:
+ /* Trigger memory reference interruptions without writing to memory */
+ copy %r26, %r28
+ depi_safe 0, 31, 2, %r28
+11: ldw 0(%r28), %r1
+12: stbys,e %r0, 0(%r28)
+
+ /* Calculate 8-bit hash index from virtual address */
+ extru_safe %r26, 27, 8, %r20
+
+ /* Load start of lock table */
+ ldil L%lws_lock_start, %r28
+ ldo R%lws_lock_start(%r28), %r28
+
+ /* Find lock to use, the hash index is one of 0 to
+ 255, multiplied by 16 (keep it 16-byte aligned)
+ and add to the lock table offset. */
+ shlw %r20, 4, %r20
+ add %r20, %r28, %r20
+
+ rsm PSW_SM_I, %r0 /* Disable interrupts */
+
+ /* Try to acquire the lock */
+ LDCW 0(%sr2,%r20), %r28
+ spinlock_check %r28, %r21
+ comclr,<> %r0, %r28, %r0
+ b,n lws_wouldblock
+
+ /* Disable page faults to prevent sleeping in critical region */
+ lws_pagefault_disable %r21,%r28
+
+ /* NOTES:
+ This all works because intr_do_signal
+ and schedule both check the return iasq
+ and see that we are on the kernel page
+ so this process is never scheduled off
+ or is ever sent any signal of any sort,
+ thus it is wholly atomic from userspace's
+ perspective
+ */
+
+ /* Jump to the correct function */
+ blr %r1, %r0
+ /* Set %r28 as non-zero for now */
+ ldo 1(%r0),%r28
+
+ /* 8-bit exchange */
+14: ldb 0(%r26), %r1
+15: stb %r1, 0(%r23)
+15: ldb 0(%r24), %r1
+17: stb %r1, 0(%r26)
+ b lws_exit_noerror
+ copy %r0, %r28
+ nop
+ nop
+
+ /* 16-bit exchange */
+18: ldh 0(%r26), %r1
+19: sth %r1, 0(%r23)
+20: ldh 0(%r24), %r1
+21: sth %r1, 0(%r26)
+ b lws_exit_noerror
+ copy %r0, %r28
+ nop
+ nop
+
+ /* 32-bit exchange */
+22: ldw 0(%r26), %r1
+23: stw %r1, 0(%r23)
+24: ldw 0(%r24), %r1
+25: stw %r1, 0(%r26)
+ b lws_exit_noerror
+ copy %r0, %r28
+ nop
+ nop
+
+ /* 64-bit exchange */
+#ifdef CONFIG_64BIT
+26: ldd 0(%r26), %r1
+27: std %r1, 0(%r23)
+28: ldd 0(%r24), %r1
+29: std %r1, 0(%r26)
+#else
+26: flddx 0(%r26), %fr4
+27: fstdx %fr4, 0(%r23)
+28: flddx 0(%r24), %fr4
+29: fstdx %fr4, 0(%r26)
+#endif
+ b lws_exit_noerror
+ copy %r0, %r28
+
+ /* A fault occurred on load or stbys,e store */
+30: b,n lws_fault
+ ASM_EXCEPTIONTABLE_ENTRY(1b-linux_gateway_page, 30b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(2b-linux_gateway_page, 30b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(3b-linux_gateway_page, 30b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(4b-linux_gateway_page, 30b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(5b-linux_gateway_page, 30b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(6b-linux_gateway_page, 30b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(7b-linux_gateway_page, 30b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(8b-linux_gateway_page, 30b-linux_gateway_page)
+#ifndef CONFIG_64BIT
+ ASM_EXCEPTIONTABLE_ENTRY(9b-linux_gateway_page, 30b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(10b-linux_gateway_page, 30b-linux_gateway_page)
+#endif
+
+ ASM_EXCEPTIONTABLE_ENTRY(11b-linux_gateway_page, 30b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(12b-linux_gateway_page, 30b-linux_gateway_page)
+
+ /* A page fault occurred in critical region */
+31: b,n lws_pagefault
+ ASM_EXCEPTIONTABLE_ENTRY(14b-linux_gateway_page, 31b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(15b-linux_gateway_page, 31b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(16b-linux_gateway_page, 31b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(17b-linux_gateway_page, 31b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(18b-linux_gateway_page, 31b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(19b-linux_gateway_page, 31b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(20b-linux_gateway_page, 31b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(21b-linux_gateway_page, 31b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(22b-linux_gateway_page, 31b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(23b-linux_gateway_page, 31b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(24b-linux_gateway_page, 31b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(25b-linux_gateway_page, 31b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(26b-linux_gateway_page, 31b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(27b-linux_gateway_page, 31b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(28b-linux_gateway_page, 31b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(29b-linux_gateway_page, 31b-linux_gateway_page)
+
+ /***************************************************
+ LWS atomic store.
+
+ %r26 - Address to store
+ %r25 - Size of the variable (0/1/2/3 for 8/16/32/64 bit)
+ %r24 - Address of value to store
+ %r28 - Return non-zero on failure
+ %r21 - Kernel error code
+
+ %r21 returns the following error codes:
+ EAGAIN - CAS is busy, ldcw failed, try again.
+ EFAULT - Read or write failed.
+
+ If EAGAIN is returned, %r28 indicates the busy reason:
+ r28 == 1 - CAS is busy. lock contended.
+ r28 == 2 - CAS is busy. ldcw failed.
+ r28 == 3 - CAS is busy. page fault.
+
+ Scratch: r20, r1
+
+ ****************************************************/
+
+lws_atomic_store:
+#ifdef CONFIG_64BIT
+ /* Wide mode user process? */
+ bb,<,n %sp, 31, atomic_store_begin
+
+ /* Clip the input registers for 32-bit processes. We don't
+ need to clip %r23 as we only use it for word operations */
+ depdi 0, 31, 32, %r26
+ depdi 0, 31, 32, %r25
+ depdi 0, 31, 32, %r24
+#endif
+
+atomic_store_begin:
+ /* Check the validity of the size pointer */
+ subi,>>= 3, %r25, %r0
+ b,n lws_exit_nosys
+
+ shlw %r25, 1, %r1
+ blr %r1, %r0
+ nop
+
+ /* Perform exception checks */
+
+ /* 8-bit store */
+1: ldb 0(%r24), %r20
+ b,n atomic_store_start
+ nop
+ nop
+
+ /* 16-bit store */
+2: ldh 0(%r24), %r20
+ b,n atomic_store_start
+ nop
+ nop
+
+ /* 32-bit store */
+3: ldw 0(%r24), %r20
+ b,n atomic_store_start
+ nop
+ nop
+
+ /* 64-bit store */
+#ifdef CONFIG_64BIT
+4: ldd 0(%r24), %r20
+#else
+4: ldw 0(%r24), %r20
+5: ldw 4(%r24), %r20
+#endif
+
+atomic_store_start:
+ /* Trigger memory reference interruptions without writing to memory */
+ copy %r26, %r28
+ depi_safe 0, 31, 2, %r28
+6: ldw 0(%r28), %r1
+7: stbys,e %r0, 0(%r28)
+
+ /* Calculate 8-bit hash index from virtual address */
+ extru_safe %r26, 27, 8, %r20
+
+ /* Load start of lock table */
+ ldil L%lws_lock_start, %r28
+ ldo R%lws_lock_start(%r28), %r28
+
+ /* Find lock to use, the hash index is one of 0 to
+ 255, multiplied by 16 (keep it 16-byte aligned)
+ and add to the lock table offset. */
+ shlw %r20, 4, %r20
+ add %r20, %r28, %r20
+
+ rsm PSW_SM_I, %r0 /* Disable interrupts */
+
+ /* Try to acquire the lock */
+ LDCW 0(%sr2,%r20), %r28
+ spinlock_check %r28, %r21
+ comclr,<> %r0, %r28, %r0
+ b,n lws_wouldblock
+
+ /* Disable page faults to prevent sleeping in critical region */
+ lws_pagefault_disable %r21,%r28
+
+ /* NOTES:
+ This all works because intr_do_signal
+ and schedule both check the return iasq
+ and see that we are on the kernel page
+ so this process is never scheduled off
+ or is ever sent any signal of any sort,
+ thus it is wholly atomic from userspace's
+ perspective
+ */
+
+ /* Jump to the correct function */
+ blr %r1, %r0
+ /* Set %r28 as non-zero for now */
+ ldo 1(%r0),%r28
+
+ /* 8-bit store */
+9: ldb 0(%r24), %r1
+10: stb %r1, 0(%r26)
+ b lws_exit_noerror
+ copy %r0, %r28
+
+ /* 16-bit store */
+11: ldh 0(%r24), %r1
+12: sth %r1, 0(%r26)
+ b lws_exit_noerror
+ copy %r0, %r28
+
+ /* 32-bit store */
+13: ldw 0(%r24), %r1
+14: stw %r1, 0(%r26)
+ b lws_exit_noerror
+ copy %r0, %r28
+
+ /* 64-bit store */
+#ifdef CONFIG_64BIT
+15: ldd 0(%r24), %r1
+16: std %r1, 0(%r26)
+#else
+15: flddx 0(%r24), %fr4
+16: fstdx %fr4, 0(%r26)
+#endif
+ b lws_exit_noerror
+ copy %r0, %r28
+
+ /* A fault occurred on load or stbys,e store */
+30: b,n lws_fault
+ ASM_EXCEPTIONTABLE_ENTRY(1b-linux_gateway_page, 30b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(2b-linux_gateway_page, 30b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(3b-linux_gateway_page, 30b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(4b-linux_gateway_page, 30b-linux_gateway_page)
+#ifndef CONFIG_64BIT
+ ASM_EXCEPTIONTABLE_ENTRY(5b-linux_gateway_page, 30b-linux_gateway_page)
+#endif
+
+ ASM_EXCEPTIONTABLE_ENTRY(6b-linux_gateway_page, 30b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(7b-linux_gateway_page, 30b-linux_gateway_page)
+
+ /* A page fault occurred in critical region */
+31: b,n lws_pagefault
+ ASM_EXCEPTIONTABLE_ENTRY(9b-linux_gateway_page, 31b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(10b-linux_gateway_page, 31b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(11b-linux_gateway_page, 31b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(12b-linux_gateway_page, 31b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(13b-linux_gateway_page, 31b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(14b-linux_gateway_page, 31b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(15b-linux_gateway_page, 31b-linux_gateway_page)
+ ASM_EXCEPTIONTABLE_ENTRY(16b-linux_gateway_page, 31b-linux_gateway_page)
+
+ /* Make sure nothing else is placed on this page */
+ .align PAGE_SIZE
+END(linux_gateway_page)
+ENTRY(end_linux_gateway_page)
+
+ /* Relocate symbols assuming linux_gateway_page is mapped
+ to virtual address 0x0 */
+
+#define LWS_ENTRY(_name_) ASM_ULONG_INSN (lws_##_name_ - linux_gateway_page)
+
+ .section .rodata,"a"
+
+ .align 8
+ /* Light-weight-syscall table */
+ /* Start of lws table. */
+ENTRY(lws_table)
+ LWS_ENTRY(compare_and_swap32) /* 0 - ELF32 Atomic 32bit CAS */
+ LWS_ENTRY(compare_and_swap64) /* 1 - ELF64 Atomic 32bit CAS */
+ LWS_ENTRY(compare_and_swap_2) /* 2 - Atomic 64bit CAS */
+ LWS_ENTRY(atomic_xchg) /* 3 - Atomic Exchange */
+ LWS_ENTRY(atomic_store) /* 4 - Atomic Store */
+END(lws_table)
+ /* End of lws table */
+
+#ifdef CONFIG_64BIT
+#define __SYSCALL_WITH_COMPAT(nr, native, compat) __SYSCALL(nr, compat)
+#else
+#define __SYSCALL_WITH_COMPAT(nr, native, compat) __SYSCALL(nr, native)
+#endif
+#define __SYSCALL(nr, entry) ASM_ULONG_INSN entry
+ .align 8
+ENTRY(sys_call_table)
+ .export sys_call_table,data
+#include <asm/syscall_table_32.h> /* 32-bit syscalls */
+END(sys_call_table)
+
+#ifdef CONFIG_64BIT
+ .align 8
+ENTRY(sys_call_table64)
+#include <asm/syscall_table_64.h> /* 64-bit syscalls */
+END(sys_call_table64)
+#endif
+
+ /*
+ All light-weight-syscall atomic operations
+ will use this set of locks
+
+ NOTE: The lws_lock_start symbol must be
+ at least 16-byte aligned for safe use
+ with ldcw.
+ */
+ .section .data
+ .align L1_CACHE_BYTES
+ENTRY(lws_lock_start)
+ /* lws locks */
+ .rept 256
+ /* Keep locks aligned at 16-bytes */
+ .word __ARCH_SPIN_LOCK_UNLOCKED_VAL
+ .word 0
+ .word 0
+ .word 0
+ .endr
+END(lws_lock_start)
+ .previous
+
+.end
diff --git a/arch/parisc/kernel/syscalls/Makefile b/arch/parisc/kernel/syscalls/Makefile
new file mode 100644
index 000000000..8440c16df
--- /dev/null
+++ b/arch/parisc/kernel/syscalls/Makefile
@@ -0,0 +1,33 @@
+# SPDX-License-Identifier: GPL-2.0
+kapi := arch/$(SRCARCH)/include/generated/asm
+uapi := arch/$(SRCARCH)/include/generated/uapi/asm
+
+$(shell mkdir -p $(uapi) $(kapi))
+
+syscall := $(src)/syscall.tbl
+syshdr := $(srctree)/scripts/syscallhdr.sh
+systbl := $(srctree)/scripts/syscalltbl.sh
+
+quiet_cmd_syshdr = SYSHDR $@
+ cmd_syshdr = $(CONFIG_SHELL) $(syshdr) --emit-nr --abis common,$* $< $@
+
+quiet_cmd_systbl = SYSTBL $@
+ cmd_systbl = $(CONFIG_SHELL) $(systbl) --abis common,$* $< $@
+
+$(uapi)/unistd_%.h: $(syscall) $(syshdr) FORCE
+ $(call if_changed,syshdr)
+
+$(kapi)/syscall_table_%.h: $(syscall) $(systbl) FORCE
+ $(call if_changed,systbl)
+
+uapisyshdr-y += unistd_32.h unistd_64.h
+kapisyshdr-y += syscall_table_32.h \
+ syscall_table_64.h
+
+uapisyshdr-y := $(addprefix $(uapi)/, $(uapisyshdr-y))
+kapisyshdr-y := $(addprefix $(kapi)/, $(kapisyshdr-y))
+targets += $(addprefix ../../../../, $(uapisyshdr-y) $(kapisyshdr-y))
+
+PHONY += all
+all: $(uapisyshdr-y) $(kapisyshdr-y)
+ @:
diff --git a/arch/parisc/kernel/syscalls/syscall.tbl b/arch/parisc/kernel/syscalls/syscall.tbl
new file mode 100644
index 000000000..e97c175b5
--- /dev/null
+++ b/arch/parisc/kernel/syscalls/syscall.tbl
@@ -0,0 +1,453 @@
+# SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note
+#
+# system call numbers and entry vectors for parisc
+#
+# The format is:
+# <number> <abi> <name> <entry point> <compat entry point>
+#
+# The <abi> can be common, 64, or 32 for this file.
+#
+0 common restart_syscall sys_restart_syscall
+1 common exit sys_exit
+2 common fork sys_fork_wrapper
+3 common read sys_read
+4 common write sys_write
+5 common open sys_open compat_sys_open
+6 common close sys_close
+7 common waitpid sys_waitpid
+8 common creat sys_creat
+9 common link sys_link
+10 common unlink sys_unlink
+11 common execve sys_execve compat_sys_execve
+12 common chdir sys_chdir
+13 32 time sys_time32
+13 64 time sys_time
+14 common mknod sys_mknod
+15 common chmod sys_chmod
+16 common lchown sys_lchown
+17 common socket sys_socket
+18 common stat sys_newstat compat_sys_newstat
+19 common lseek sys_lseek compat_sys_lseek
+20 common getpid sys_getpid
+21 common mount sys_mount
+22 common bind sys_bind
+23 common setuid sys_setuid
+24 common getuid sys_getuid
+25 32 stime sys_stime32
+25 64 stime sys_stime
+26 common ptrace sys_ptrace compat_sys_ptrace
+27 common alarm sys_alarm
+28 common fstat sys_newfstat compat_sys_newfstat
+29 common pause sys_pause
+30 32 utime sys_utime32
+30 64 utime sys_utime
+31 common connect sys_connect
+32 common listen sys_listen
+33 common access sys_access
+34 common nice sys_nice
+35 common accept sys_accept
+36 common sync sys_sync
+37 common kill sys_kill
+38 common rename sys_rename
+39 common mkdir sys_mkdir
+40 common rmdir sys_rmdir
+41 common dup sys_dup
+42 common pipe sys_pipe
+43 common times sys_times compat_sys_times
+44 common getsockname sys_getsockname
+45 common brk sys_brk
+46 common setgid sys_setgid
+47 common getgid sys_getgid
+48 common signal sys_signal
+49 common geteuid sys_geteuid
+50 common getegid sys_getegid
+51 common acct sys_acct
+52 common umount2 sys_umount
+53 common getpeername sys_getpeername
+54 common ioctl sys_ioctl compat_sys_ioctl
+55 common fcntl sys_fcntl compat_sys_fcntl
+56 common socketpair sys_socketpair
+57 common setpgid sys_setpgid
+58 common send sys_send
+59 common uname sys_newuname
+60 common umask sys_umask
+61 common chroot sys_chroot
+62 common ustat sys_ustat compat_sys_ustat
+63 common dup2 sys_dup2
+64 common getppid sys_getppid
+65 common getpgrp sys_getpgrp
+66 common setsid sys_setsid
+67 common pivot_root sys_pivot_root
+68 common sgetmask sys_sgetmask sys32_unimplemented
+69 common ssetmask sys_ssetmask sys32_unimplemented
+70 common setreuid sys_setreuid
+71 common setregid sys_setregid
+72 common mincore sys_mincore
+73 common sigpending sys_sigpending compat_sys_sigpending
+74 common sethostname sys_sethostname
+75 common setrlimit sys_setrlimit compat_sys_setrlimit
+76 common getrlimit sys_getrlimit compat_sys_getrlimit
+77 common getrusage sys_getrusage compat_sys_getrusage
+78 common gettimeofday sys_gettimeofday compat_sys_gettimeofday
+79 common settimeofday sys_settimeofday compat_sys_settimeofday
+80 common getgroups sys_getgroups
+81 common setgroups sys_setgroups
+82 common sendto sys_sendto
+83 common symlink sys_symlink
+84 common lstat sys_newlstat compat_sys_newlstat
+85 common readlink sys_readlink
+86 common uselib sys_ni_syscall
+87 common swapon sys_swapon
+88 common reboot sys_reboot
+89 common mmap2 sys_mmap2
+90 common mmap sys_mmap
+91 common munmap sys_munmap
+92 common truncate sys_truncate compat_sys_truncate
+93 common ftruncate sys_ftruncate compat_sys_ftruncate
+94 common fchmod sys_fchmod
+95 common fchown sys_fchown
+96 common getpriority sys_getpriority
+97 common setpriority sys_setpriority
+98 common recv sys_recv
+99 common statfs sys_statfs compat_sys_statfs
+100 common fstatfs sys_fstatfs compat_sys_fstatfs
+101 common stat64 sys_stat64
+# 102 was socketcall
+103 common syslog sys_syslog
+104 common setitimer sys_setitimer compat_sys_setitimer
+105 common getitimer sys_getitimer compat_sys_getitimer
+106 common capget sys_capget
+107 common capset sys_capset
+108 32 pread64 parisc_pread64
+108 64 pread64 sys_pread64
+109 32 pwrite64 parisc_pwrite64
+109 64 pwrite64 sys_pwrite64
+110 common getcwd sys_getcwd
+111 common vhangup sys_vhangup
+112 common fstat64 sys_fstat64
+113 common vfork sys_vfork_wrapper
+114 common wait4 sys_wait4 compat_sys_wait4
+115 common swapoff sys_swapoff
+116 common sysinfo sys_sysinfo compat_sys_sysinfo
+117 common shutdown sys_shutdown
+118 common fsync sys_fsync
+119 common madvise parisc_madvise
+120 common clone sys_clone_wrapper
+121 common setdomainname sys_setdomainname
+122 common sendfile sys_sendfile compat_sys_sendfile
+123 common recvfrom sys_recvfrom
+124 32 adjtimex sys_adjtimex_time32
+124 64 adjtimex sys_adjtimex
+125 common mprotect sys_mprotect
+126 common sigprocmask sys_sigprocmask compat_sys_sigprocmask
+# 127 was create_module
+128 common init_module sys_init_module
+129 common delete_module sys_delete_module
+# 130 was get_kernel_syms
+131 common quotactl sys_quotactl
+132 common getpgid sys_getpgid
+133 common fchdir sys_fchdir
+134 common bdflush sys_ni_syscall
+135 common sysfs sys_sysfs
+136 32 personality parisc_personality
+136 64 personality sys_personality
+# 137 was afs_syscall
+138 common setfsuid sys_setfsuid
+139 common setfsgid sys_setfsgid
+140 common _llseek sys_llseek
+141 common getdents sys_getdents compat_sys_getdents
+142 common _newselect sys_select compat_sys_select
+143 common flock sys_flock
+144 common msync sys_msync
+145 common readv sys_readv
+146 common writev sys_writev
+147 common getsid sys_getsid
+148 common fdatasync sys_fdatasync
+149 common _sysctl sys_ni_syscall
+150 common mlock sys_mlock
+151 common munlock sys_munlock
+152 common mlockall sys_mlockall
+153 common munlockall sys_munlockall
+154 common sched_setparam sys_sched_setparam
+155 common sched_getparam sys_sched_getparam
+156 common sched_setscheduler sys_sched_setscheduler
+157 common sched_getscheduler sys_sched_getscheduler
+158 common sched_yield sys_sched_yield
+159 common sched_get_priority_max sys_sched_get_priority_max
+160 common sched_get_priority_min sys_sched_get_priority_min
+161 32 sched_rr_get_interval sys_sched_rr_get_interval_time32
+161 64 sched_rr_get_interval sys_sched_rr_get_interval
+162 32 nanosleep sys_nanosleep_time32
+162 64 nanosleep sys_nanosleep
+163 common mremap sys_mremap
+164 common setresuid sys_setresuid
+165 common getresuid sys_getresuid
+166 common sigaltstack sys_sigaltstack compat_sys_sigaltstack
+# 167 was query_module
+168 common poll sys_poll
+# 169 was nfsservctl
+170 common setresgid sys_setresgid
+171 common getresgid sys_getresgid
+172 common prctl sys_prctl
+173 common rt_sigreturn sys_rt_sigreturn_wrapper
+174 common rt_sigaction sys_rt_sigaction compat_sys_rt_sigaction
+175 common rt_sigprocmask sys_rt_sigprocmask compat_sys_rt_sigprocmask
+176 common rt_sigpending sys_rt_sigpending compat_sys_rt_sigpending
+177 32 rt_sigtimedwait sys_rt_sigtimedwait_time32 compat_sys_rt_sigtimedwait_time32
+177 64 rt_sigtimedwait sys_rt_sigtimedwait
+178 common rt_sigqueueinfo sys_rt_sigqueueinfo compat_sys_rt_sigqueueinfo
+179 common rt_sigsuspend sys_rt_sigsuspend compat_sys_rt_sigsuspend
+180 common chown sys_chown
+181 common setsockopt sys_setsockopt sys_setsockopt
+182 common getsockopt sys_getsockopt sys_getsockopt
+183 common sendmsg sys_sendmsg compat_sys_sendmsg
+184 common recvmsg sys_recvmsg compat_sys_recvmsg
+185 common semop sys_semop
+186 common semget sys_semget
+187 common semctl sys_semctl compat_sys_semctl
+188 common msgsnd sys_msgsnd compat_sys_msgsnd
+189 common msgrcv sys_msgrcv compat_sys_msgrcv
+190 common msgget sys_msgget
+191 common msgctl sys_msgctl compat_sys_msgctl
+192 common shmat sys_shmat compat_sys_shmat
+193 common shmdt sys_shmdt
+194 common shmget sys_shmget
+195 common shmctl sys_shmctl compat_sys_shmctl
+# 196 was getpmsg
+# 197 was putpmsg
+198 common lstat64 sys_lstat64
+199 32 truncate64 parisc_truncate64
+199 64 truncate64 sys_truncate64
+200 32 ftruncate64 parisc_ftruncate64
+200 64 ftruncate64 sys_ftruncate64
+201 common getdents64 sys_getdents64
+202 common fcntl64 sys_fcntl64 compat_sys_fcntl64
+# 203 was attrctl
+# 204 was acl_get
+# 205 was acl_set
+206 common gettid sys_gettid
+207 32 readahead parisc_readahead
+207 64 readahead sys_readahead
+208 common tkill sys_tkill
+209 common sendfile64 sys_sendfile64 compat_sys_sendfile64
+210 32 futex sys_futex_time32
+210 64 futex sys_futex
+211 common sched_setaffinity sys_sched_setaffinity compat_sys_sched_setaffinity
+212 common sched_getaffinity sys_sched_getaffinity compat_sys_sched_getaffinity
+# 213 was set_thread_area
+# 214 was get_thread_area
+215 common io_setup sys_io_setup compat_sys_io_setup
+216 common io_destroy sys_io_destroy
+217 32 io_getevents sys_io_getevents_time32
+217 64 io_getevents sys_io_getevents
+218 common io_submit sys_io_submit compat_sys_io_submit
+219 common io_cancel sys_io_cancel
+# 220 was alloc_hugepages
+# 221 was free_hugepages
+222 common exit_group sys_exit_group
+223 common lookup_dcookie sys_lookup_dcookie compat_sys_lookup_dcookie
+224 common epoll_create sys_epoll_create
+225 common epoll_ctl sys_epoll_ctl
+226 common epoll_wait sys_epoll_wait
+227 common remap_file_pages sys_remap_file_pages
+228 32 semtimedop sys_semtimedop_time32
+228 64 semtimedop sys_semtimedop
+229 common mq_open sys_mq_open compat_sys_mq_open
+230 common mq_unlink sys_mq_unlink
+231 32 mq_timedsend sys_mq_timedsend_time32
+231 64 mq_timedsend sys_mq_timedsend
+232 32 mq_timedreceive sys_mq_timedreceive_time32
+232 64 mq_timedreceive sys_mq_timedreceive
+233 common mq_notify sys_mq_notify compat_sys_mq_notify
+234 common mq_getsetattr sys_mq_getsetattr compat_sys_mq_getsetattr
+235 common waitid sys_waitid compat_sys_waitid
+236 32 fadvise64_64 parisc_fadvise64_64
+236 64 fadvise64_64 sys_fadvise64_64
+237 common set_tid_address sys_set_tid_address
+238 common setxattr sys_setxattr
+239 common lsetxattr sys_lsetxattr
+240 common fsetxattr sys_fsetxattr
+241 common getxattr sys_getxattr
+242 common lgetxattr sys_lgetxattr
+243 common fgetxattr sys_fgetxattr
+244 common listxattr sys_listxattr
+245 common llistxattr sys_llistxattr
+246 common flistxattr sys_flistxattr
+247 common removexattr sys_removexattr
+248 common lremovexattr sys_lremovexattr
+249 common fremovexattr sys_fremovexattr
+250 common timer_create sys_timer_create compat_sys_timer_create
+251 32 timer_settime sys_timer_settime32
+251 64 timer_settime sys_timer_settime
+252 32 timer_gettime sys_timer_gettime32
+252 64 timer_gettime sys_timer_gettime
+253 common timer_getoverrun sys_timer_getoverrun
+254 common timer_delete sys_timer_delete
+255 32 clock_settime sys_clock_settime32
+255 64 clock_settime sys_clock_settime
+256 32 clock_gettime sys_clock_gettime32
+256 64 clock_gettime sys_clock_gettime
+257 32 clock_getres sys_clock_getres_time32
+257 64 clock_getres sys_clock_getres
+258 32 clock_nanosleep sys_clock_nanosleep_time32
+258 64 clock_nanosleep sys_clock_nanosleep
+259 common tgkill sys_tgkill
+260 common mbind sys_mbind
+261 common get_mempolicy sys_get_mempolicy
+262 common set_mempolicy sys_set_mempolicy
+# 263 was vserver
+264 common add_key sys_add_key
+265 common request_key sys_request_key
+266 common keyctl sys_keyctl compat_sys_keyctl
+267 common ioprio_set sys_ioprio_set
+268 common ioprio_get sys_ioprio_get
+269 common inotify_init sys_inotify_init
+270 common inotify_add_watch sys_inotify_add_watch
+271 common inotify_rm_watch sys_inotify_rm_watch
+272 common migrate_pages sys_migrate_pages
+273 32 pselect6 sys_pselect6_time32 compat_sys_pselect6_time32
+273 64 pselect6 sys_pselect6
+274 32 ppoll sys_ppoll_time32 compat_sys_ppoll_time32
+274 64 ppoll sys_ppoll
+275 common openat sys_openat compat_sys_openat
+276 common mkdirat sys_mkdirat
+277 common mknodat sys_mknodat
+278 common fchownat sys_fchownat
+279 32 futimesat sys_futimesat_time32
+279 64 futimesat sys_futimesat
+280 common fstatat64 sys_fstatat64
+281 common unlinkat sys_unlinkat
+282 common renameat sys_renameat
+283 common linkat sys_linkat
+284 common symlinkat sys_symlinkat
+285 common readlinkat sys_readlinkat
+286 common fchmodat sys_fchmodat
+287 common faccessat sys_faccessat
+288 common unshare sys_unshare
+289 common set_robust_list sys_set_robust_list compat_sys_set_robust_list
+290 common get_robust_list sys_get_robust_list compat_sys_get_robust_list
+291 common splice sys_splice
+292 32 sync_file_range parisc_sync_file_range
+292 64 sync_file_range sys_sync_file_range
+293 common tee sys_tee
+294 common vmsplice sys_vmsplice
+295 common move_pages sys_move_pages
+296 common getcpu sys_getcpu
+297 common epoll_pwait sys_epoll_pwait compat_sys_epoll_pwait
+298 common statfs64 sys_statfs64 compat_sys_statfs64
+299 common fstatfs64 sys_fstatfs64 compat_sys_fstatfs64
+300 common kexec_load sys_kexec_load compat_sys_kexec_load
+301 32 utimensat sys_utimensat_time32
+301 64 utimensat sys_utimensat
+302 common signalfd sys_signalfd compat_sys_signalfd
+# 303 was timerfd
+304 common eventfd sys_eventfd
+305 32 fallocate parisc_fallocate
+305 64 fallocate sys_fallocate
+306 common timerfd_create parisc_timerfd_create
+307 32 timerfd_settime sys_timerfd_settime32
+307 64 timerfd_settime sys_timerfd_settime
+308 32 timerfd_gettime sys_timerfd_gettime32
+308 64 timerfd_gettime sys_timerfd_gettime
+309 common signalfd4 parisc_signalfd4 parisc_compat_signalfd4
+310 common eventfd2 parisc_eventfd2
+311 common epoll_create1 sys_epoll_create1
+312 common dup3 sys_dup3
+313 common pipe2 parisc_pipe2
+314 common inotify_init1 parisc_inotify_init1
+315 common preadv sys_preadv compat_sys_preadv
+316 common pwritev sys_pwritev compat_sys_pwritev
+317 common rt_tgsigqueueinfo sys_rt_tgsigqueueinfo compat_sys_rt_tgsigqueueinfo
+318 common perf_event_open sys_perf_event_open
+319 32 recvmmsg sys_recvmmsg_time32 compat_sys_recvmmsg_time32
+319 64 recvmmsg sys_recvmmsg
+320 common accept4 sys_accept4
+321 common prlimit64 sys_prlimit64
+322 common fanotify_init sys_fanotify_init
+323 common fanotify_mark sys_fanotify_mark sys32_fanotify_mark
+324 32 clock_adjtime sys_clock_adjtime32
+324 64 clock_adjtime sys_clock_adjtime
+325 common name_to_handle_at sys_name_to_handle_at
+326 common open_by_handle_at sys_open_by_handle_at compat_sys_open_by_handle_at
+327 common syncfs sys_syncfs
+328 common setns sys_setns
+329 common sendmmsg sys_sendmmsg compat_sys_sendmmsg
+330 common process_vm_readv sys_process_vm_readv
+331 common process_vm_writev sys_process_vm_writev
+332 common kcmp sys_kcmp
+333 common finit_module sys_finit_module
+334 common sched_setattr sys_sched_setattr
+335 common sched_getattr sys_sched_getattr
+336 32 utimes sys_utimes_time32
+336 64 utimes sys_utimes
+337 common renameat2 sys_renameat2
+338 common seccomp sys_seccomp
+339 common getrandom sys_getrandom
+340 common memfd_create sys_memfd_create
+341 common bpf sys_bpf
+342 common execveat sys_execveat compat_sys_execveat
+343 common membarrier sys_membarrier
+344 common userfaultfd parisc_userfaultfd
+345 common mlock2 sys_mlock2
+346 common copy_file_range sys_copy_file_range
+347 common preadv2 sys_preadv2 compat_sys_preadv2
+348 common pwritev2 sys_pwritev2 compat_sys_pwritev2
+349 common statx sys_statx
+350 32 io_pgetevents sys_io_pgetevents_time32 compat_sys_io_pgetevents
+350 64 io_pgetevents sys_io_pgetevents
+351 common pkey_mprotect sys_pkey_mprotect
+352 common pkey_alloc sys_pkey_alloc
+353 common pkey_free sys_pkey_free
+354 common rseq sys_rseq
+355 common kexec_file_load sys_kexec_file_load sys_kexec_file_load
+356 common cacheflush sys_cacheflush
+# up to 402 is unassigned and reserved for arch specific syscalls
+403 32 clock_gettime64 sys_clock_gettime sys_clock_gettime
+404 32 clock_settime64 sys_clock_settime sys_clock_settime
+405 32 clock_adjtime64 sys_clock_adjtime sys_clock_adjtime
+406 32 clock_getres_time64 sys_clock_getres sys_clock_getres
+407 32 clock_nanosleep_time64 sys_clock_nanosleep sys_clock_nanosleep
+408 32 timer_gettime64 sys_timer_gettime sys_timer_gettime
+409 32 timer_settime64 sys_timer_settime sys_timer_settime
+410 32 timerfd_gettime64 sys_timerfd_gettime sys_timerfd_gettime
+411 32 timerfd_settime64 sys_timerfd_settime sys_timerfd_settime
+412 32 utimensat_time64 sys_utimensat sys_utimensat
+413 32 pselect6_time64 sys_pselect6 compat_sys_pselect6_time64
+414 32 ppoll_time64 sys_ppoll compat_sys_ppoll_time64
+416 32 io_pgetevents_time64 sys_io_pgetevents compat_sys_io_pgetevents_time64
+417 32 recvmmsg_time64 sys_recvmmsg compat_sys_recvmmsg_time64
+418 32 mq_timedsend_time64 sys_mq_timedsend sys_mq_timedsend
+419 32 mq_timedreceive_time64 sys_mq_timedreceive sys_mq_timedreceive
+420 32 semtimedop_time64 sys_semtimedop sys_semtimedop
+421 32 rt_sigtimedwait_time64 sys_rt_sigtimedwait compat_sys_rt_sigtimedwait_time64
+422 32 futex_time64 sys_futex sys_futex
+423 32 sched_rr_get_interval_time64 sys_sched_rr_get_interval sys_sched_rr_get_interval
+424 common pidfd_send_signal sys_pidfd_send_signal
+425 common io_uring_setup sys_io_uring_setup
+426 common io_uring_enter sys_io_uring_enter
+427 common io_uring_register sys_io_uring_register
+428 common open_tree sys_open_tree
+429 common move_mount sys_move_mount
+430 common fsopen sys_fsopen
+431 common fsconfig sys_fsconfig
+432 common fsmount sys_fsmount
+433 common fspick sys_fspick
+434 common pidfd_open sys_pidfd_open
+435 common clone3 sys_clone3_wrapper
+436 common close_range sys_close_range
+437 common openat2 sys_openat2
+438 common pidfd_getfd sys_pidfd_getfd
+439 common faccessat2 sys_faccessat2
+440 common process_madvise sys_process_madvise
+441 common epoll_pwait2 sys_epoll_pwait2 compat_sys_epoll_pwait2
+442 common mount_setattr sys_mount_setattr
+443 common quotactl_fd sys_quotactl_fd
+444 common landlock_create_ruleset sys_landlock_create_ruleset
+445 common landlock_add_rule sys_landlock_add_rule
+446 common landlock_restrict_self sys_landlock_restrict_self
+# 447 reserved for memfd_secret
+448 common process_mrelease sys_process_mrelease
+449 common futex_waitv sys_futex_waitv
+450 common set_mempolicy_home_node sys_set_mempolicy_home_node
+451 common cachestat sys_cachestat
+452 common fchmodat2 sys_fchmodat2
diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c
new file mode 100644
index 000000000..9714fbd7c
--- /dev/null
+++ b/arch/parisc/kernel/time.c
@@ -0,0 +1,269 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * linux/arch/parisc/kernel/time.c
+ *
+ * Copyright (C) 1991, 1992, 1995 Linus Torvalds
+ * Modifications for ARM (C) 1994, 1995, 1996,1997 Russell King
+ * Copyright (C) 1999 SuSE GmbH, (Philipp Rumpf, prumpf@tux.org)
+ *
+ * 1994-07-02 Alan Modra
+ * fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime
+ * 1998-12-20 Updated NTP code according to technical memorandum Jan '96
+ * "A Kernel Model for Precision Timekeeping" by Dave Mills
+ */
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/rtc.h>
+#include <linux/sched.h>
+#include <linux/sched/clock.h>
+#include <linux/sched_clock.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/profile.h>
+#include <linux/clocksource.h>
+#include <linux/platform_device.h>
+#include <linux/ftrace.h>
+
+#include <linux/uaccess.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/page.h>
+#include <asm/param.h>
+#include <asm/pdc.h>
+#include <asm/led.h>
+
+#include <linux/timex.h>
+
+int time_keeper_id __read_mostly; /* CPU used for timekeeping. */
+
+static unsigned long clocktick __ro_after_init; /* timer cycles per tick */
+
+/*
+ * We keep time on PA-RISC Linux by using the Interval Timer which is
+ * a pair of registers; one is read-only and one is write-only; both
+ * accessed through CR16. The read-only register is 32 or 64 bits wide,
+ * and increments by 1 every CPU clock tick. The architecture only
+ * guarantees us a rate between 0.5 and 2, but all implementations use a
+ * rate of 1. The write-only register is 32-bits wide. When the lowest
+ * 32 bits of the read-only register compare equal to the write-only
+ * register, it raises a maskable external interrupt. Each processor has
+ * an Interval Timer of its own and they are not synchronised.
+ *
+ * We want to generate an interrupt every 1/HZ seconds. So we program
+ * CR16 to interrupt every @clocktick cycles. The it_value in cpu_data
+ * is programmed with the intended time of the next tick. We can be
+ * held off for an arbitrarily long period of time by interrupts being
+ * disabled, so we may miss one or more ticks.
+ */
+irqreturn_t __irq_entry timer_interrupt(int irq, void *dev_id)
+{
+ unsigned long now;
+ unsigned long next_tick;
+ unsigned long ticks_elapsed = 0;
+ unsigned int cpu = smp_processor_id();
+ struct cpuinfo_parisc *cpuinfo = &per_cpu(cpu_data, cpu);
+
+ /* gcc can optimize for "read-only" case with a local clocktick */
+ unsigned long cpt = clocktick;
+
+ /* Initialize next_tick to the old expected tick time. */
+ next_tick = cpuinfo->it_value;
+
+ /* Calculate how many ticks have elapsed. */
+ now = mfctl(16);
+ do {
+ ++ticks_elapsed;
+ next_tick += cpt;
+ } while (next_tick - now > cpt);
+
+ /* Store (in CR16 cycles) up to when we are accounting right now. */
+ cpuinfo->it_value = next_tick;
+
+ /* Go do system house keeping. */
+ if (IS_ENABLED(CONFIG_SMP) && (cpu != time_keeper_id))
+ ticks_elapsed = 0;
+ legacy_timer_tick(ticks_elapsed);
+
+ /* Skip clockticks on purpose if we know we would miss those.
+ * The new CR16 must be "later" than current CR16 otherwise
+ * itimer would not fire until CR16 wrapped - e.g 4 seconds
+ * later on a 1Ghz processor. We'll account for the missed
+ * ticks on the next timer interrupt.
+ * We want IT to fire modulo clocktick even if we miss/skip some.
+ * But those interrupts don't in fact get delivered that regularly.
+ *
+ * "next_tick - now" will always give the difference regardless
+ * if one or the other wrapped. If "now" is "bigger" we'll end up
+ * with a very large unsigned number.
+ */
+ now = mfctl(16);
+ while (next_tick - now > cpt)
+ next_tick += cpt;
+
+ /* Program the IT when to deliver the next interrupt.
+ * Only bottom 32-bits of next_tick are writable in CR16!
+ * Timer interrupt will be delivered at least a few hundred cycles
+ * after the IT fires, so if we are too close (<= 8000 cycles) to the
+ * next cycle, simply skip it.
+ */
+ if (next_tick - now <= 8000)
+ next_tick += cpt;
+ mtctl(next_tick, 16);
+
+ return IRQ_HANDLED;
+}
+
+
+unsigned long profile_pc(struct pt_regs *regs)
+{
+ unsigned long pc = instruction_pointer(regs);
+
+ if (regs->gr[0] & PSW_N)
+ pc -= 4;
+
+#ifdef CONFIG_SMP
+ if (in_lock_functions(pc))
+ pc = regs->gr[2];
+#endif
+
+ return pc;
+}
+EXPORT_SYMBOL(profile_pc);
+
+
+/* clock source code */
+
+static u64 notrace read_cr16(struct clocksource *cs)
+{
+ return get_cycles();
+}
+
+static struct clocksource clocksource_cr16 = {
+ .name = "cr16",
+ .rating = 300,
+ .read = read_cr16,
+ .mask = CLOCKSOURCE_MASK(BITS_PER_LONG),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+void start_cpu_itimer(void)
+{
+ unsigned int cpu = smp_processor_id();
+ unsigned long next_tick = mfctl(16) + clocktick;
+
+ mtctl(next_tick, 16); /* kick off Interval Timer (CR16) */
+
+ per_cpu(cpu_data, cpu).it_value = next_tick;
+}
+
+#if IS_ENABLED(CONFIG_RTC_DRV_GENERIC)
+static int rtc_generic_get_time(struct device *dev, struct rtc_time *tm)
+{
+ struct pdc_tod tod_data;
+
+ memset(tm, 0, sizeof(*tm));
+ if (pdc_tod_read(&tod_data) < 0)
+ return -EOPNOTSUPP;
+
+ /* we treat tod_sec as unsigned, so this can work until year 2106 */
+ rtc_time64_to_tm(tod_data.tod_sec, tm);
+ return 0;
+}
+
+static int rtc_generic_set_time(struct device *dev, struct rtc_time *tm)
+{
+ time64_t secs = rtc_tm_to_time64(tm);
+ int ret;
+
+ /* hppa has Y2K38 problem: pdc_tod_set() takes an u32 value! */
+ ret = pdc_tod_set(secs, 0);
+ if (ret != 0) {
+ pr_warn("pdc_tod_set(%lld) returned error %d\n", secs, ret);
+ if (ret == PDC_INVALID_ARG)
+ return -EINVAL;
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static const struct rtc_class_ops rtc_generic_ops = {
+ .read_time = rtc_generic_get_time,
+ .set_time = rtc_generic_set_time,
+};
+
+static int __init rtc_init(void)
+{
+ struct platform_device *pdev;
+
+ pdev = platform_device_register_data(NULL, "rtc-generic", -1,
+ &rtc_generic_ops,
+ sizeof(rtc_generic_ops));
+
+ return PTR_ERR_OR_ZERO(pdev);
+}
+device_initcall(rtc_init);
+#endif
+
+void read_persistent_clock64(struct timespec64 *ts)
+{
+ static struct pdc_tod tod_data;
+ if (pdc_tod_read(&tod_data) == 0) {
+ ts->tv_sec = tod_data.tod_sec;
+ ts->tv_nsec = tod_data.tod_usec * 1000;
+ } else {
+ printk(KERN_ERR "Error reading tod clock\n");
+ ts->tv_sec = 0;
+ ts->tv_nsec = 0;
+ }
+}
+
+
+static u64 notrace read_cr16_sched_clock(void)
+{
+ return get_cycles();
+}
+
+
+/*
+ * timer interrupt and sched_clock() initialization
+ */
+
+void __init time_init(void)
+{
+ unsigned long cr16_hz;
+
+ clocktick = (100 * PAGE0->mem_10msec) / HZ;
+ start_cpu_itimer(); /* get CPU 0 started */
+
+ cr16_hz = 100 * PAGE0->mem_10msec; /* Hz */
+
+ /* register as sched_clock source */
+ sched_clock_register(read_cr16_sched_clock, BITS_PER_LONG, cr16_hz);
+}
+
+static int __init init_cr16_clocksource(void)
+{
+ /*
+ * The cr16 interval timers are not synchronized across CPUs.
+ */
+ if (num_online_cpus() > 1 && !running_on_qemu) {
+ clocksource_cr16.name = "cr16_unstable";
+ clocksource_cr16.flags = CLOCK_SOURCE_UNSTABLE;
+ clocksource_cr16.rating = 0;
+ }
+
+ /* register at clocksource framework */
+ clocksource_register_hz(&clocksource_cr16,
+ 100 * PAGE0->mem_10msec);
+
+ return 0;
+}
+
+device_initcall(init_cr16_clocksource);
diff --git a/arch/parisc/kernel/toc.c b/arch/parisc/kernel/toc.c
new file mode 100644
index 000000000..e4b48d07a
--- /dev/null
+++ b/arch/parisc/kernel/toc.c
@@ -0,0 +1,126 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/kernel.h>
+#include <linux/kgdb.h>
+#include <linux/printk.h>
+#include <linux/sched/debug.h>
+#include <linux/delay.h>
+#include <linux/reboot.h>
+
+#include <asm/pdc.h>
+#include <asm/pdc_chassis.h>
+#include <asm/ldcw.h>
+#include <asm/processor.h>
+
+static unsigned int __aligned(16) toc_lock = 1;
+DEFINE_PER_CPU_PAGE_ALIGNED(char [16384], toc_stack) __visible;
+
+static void toc20_to_pt_regs(struct pt_regs *regs, struct pdc_toc_pim_20 *toc)
+{
+ int i;
+
+ regs->gr[0] = (unsigned long)toc->cr[22];
+
+ for (i = 1; i < 32; i++)
+ regs->gr[i] = (unsigned long)toc->gr[i];
+
+ for (i = 0; i < 8; i++)
+ regs->sr[i] = (unsigned long)toc->sr[i];
+
+ regs->iasq[0] = (unsigned long)toc->cr[17];
+ regs->iasq[1] = (unsigned long)toc->iasq_back;
+ regs->iaoq[0] = (unsigned long)toc->cr[18];
+ regs->iaoq[1] = (unsigned long)toc->iaoq_back;
+
+ regs->sar = (unsigned long)toc->cr[11];
+ regs->iir = (unsigned long)toc->cr[19];
+ regs->isr = (unsigned long)toc->cr[20];
+ regs->ior = (unsigned long)toc->cr[21];
+}
+
+static void toc11_to_pt_regs(struct pt_regs *regs, struct pdc_toc_pim_11 *toc)
+{
+ int i;
+
+ regs->gr[0] = toc->cr[22];
+
+ for (i = 1; i < 32; i++)
+ regs->gr[i] = toc->gr[i];
+
+ for (i = 0; i < 8; i++)
+ regs->sr[i] = toc->sr[i];
+
+ regs->iasq[0] = toc->cr[17];
+ regs->iasq[1] = toc->iasq_back;
+ regs->iaoq[0] = toc->cr[18];
+ regs->iaoq[1] = toc->iaoq_back;
+
+ regs->sar = toc->cr[11];
+ regs->iir = toc->cr[19];
+ regs->isr = toc->cr[20];
+ regs->ior = toc->cr[21];
+}
+
+void notrace __noreturn __cold toc_intr(struct pt_regs *regs)
+{
+ struct pdc_toc_pim_20 pim_data20;
+ struct pdc_toc_pim_11 pim_data11;
+
+ /* verify we wrote regs to the correct stack */
+ BUG_ON(regs != (struct pt_regs *)&per_cpu(toc_stack, raw_smp_processor_id()));
+
+ if (boot_cpu_data.cpu_type >= pcxu) {
+ if (pdc_pim_toc20(&pim_data20))
+ panic("Failed to get PIM data");
+ toc20_to_pt_regs(regs, &pim_data20);
+ } else {
+ if (pdc_pim_toc11(&pim_data11))
+ panic("Failed to get PIM data");
+ toc11_to_pt_regs(regs, &pim_data11);
+ }
+
+#ifdef CONFIG_KGDB
+ nmi_enter();
+
+ if (atomic_read(&kgdb_active) != -1)
+ kgdb_nmicallback(raw_smp_processor_id(), regs);
+ kgdb_handle_exception(9, SIGTRAP, 0, regs);
+#endif
+
+ /* serialize output, otherwise all CPUs write backtrace at once */
+ while (__ldcw(&toc_lock) == 0)
+ ; /* wait */
+ show_regs(regs);
+ toc_lock = 1; /* release lock for next CPU */
+
+ if (raw_smp_processor_id() != 0)
+ while (1) ; /* all but monarch CPU will wait endless. */
+
+ /* give other CPUs time to show their backtrace */
+ mdelay(2000);
+
+ machine_restart("TOC");
+
+ /* should never reach this */
+ panic("TOC");
+}
+
+static __init int setup_toc(void)
+{
+ unsigned int csum = 0;
+ unsigned long toc_code = (unsigned long)dereference_function_descriptor(toc_handler);
+ int i;
+
+ PAGE0->vec_toc = __pa(toc_code) & 0xffffffff;
+#ifdef CONFIG_64BIT
+ PAGE0->vec_toc_hi = __pa(toc_code) >> 32;
+#endif
+ PAGE0->vec_toclen = toc_handler_size;
+
+ for (i = 0; i < toc_handler_size/4; i++)
+ csum += ((u32 *)toc_code)[i];
+ toc_handler_csum = -csum;
+ pr_info("TOC handler registered\n");
+ return 0;
+}
+early_initcall(setup_toc);
diff --git a/arch/parisc/kernel/toc_asm.S b/arch/parisc/kernel/toc_asm.S
new file mode 100644
index 000000000..570f5cef5
--- /dev/null
+++ b/arch/parisc/kernel/toc_asm.S
@@ -0,0 +1,75 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/* TOC (Transfer of Control) handler. */
+
+ .level 1.1
+
+#include <asm/assembly.h>
+#include <linux/threads.h>
+#include <linux/linkage.h>
+
+ .text
+ .import toc_intr,code
+ .import toc_stack,data
+ .align 16
+ENTRY_CFI(toc_handler)
+ load32 PA(toc_stack),%sp
+
+#ifdef CONFIG_SMP
+ /* get per-cpu toc_stack address. */
+ mfctl %cr30, %r1
+ tophys %r1,%r2 /* task_struct */
+ LDREG TASK_TI_CPU(%r2),%r4 /* cpu */
+ load32 PA(__per_cpu_offset),%r1
+ LDREGX %r4(%r1),%r4
+ add %r4,%sp,%sp
+#endif
+
+ /*
+ * setup pt_regs on stack and save the
+ * floating point registers. PIM_TOC doesn't
+ * save fp registers, so we're doing it here.
+ */
+ copy %sp,%arg0
+ ldo PT_SZ_ALGN(%sp), %sp
+
+ /* clear pt_regs */
+ copy %arg0,%r1
+0: cmpb,<<,n %r1,%sp,0b
+ stw,ma %r0,4(%r1)
+
+ ldo PT_FR0(%arg0),%r25
+ save_fp %r25
+
+ /* go virtual */
+ load32 PA(swapper_pg_dir),%r4
+ mtctl %r4,%cr24
+ mtctl %r4,%cr25
+
+ /* Clear sr4-sr7 */
+ mtsp %r0, %sr4
+ mtsp %r0, %sr5
+ mtsp %r0, %sr6
+ mtsp %r0, %sr7
+
+ tovirt_r1 %sp
+ tovirt_r1 %arg0
+ virt_map
+
+ loadgp
+
+#ifdef CONFIG_64BIT
+ ldo -16(%sp),%r29
+#endif
+ load32 toc_intr,%r1
+ be 0(%sr7,%r1)
+ nop
+ENDPROC_CFI(toc_handler)
+
+ /*
+ * keep this checksum here, as it is part of the toc_handler
+ * spanned by toc_handler_size (all words in toc_handler are
+ * added in PDC and the sum must equal to zero.
+ */
+SYM_DATA(toc_handler_csum, .long 0)
+SYM_DATA(toc_handler_size, .long . - toc_handler)
diff --git a/arch/parisc/kernel/topology.c b/arch/parisc/kernel/topology.c
new file mode 100644
index 000000000..b9d845e31
--- /dev/null
+++ b/arch/parisc/kernel/topology.c
@@ -0,0 +1,87 @@
+/*
+ * arch/parisc/kernel/topology.c
+ *
+ * Copyright (C) 2017 Helge Deller <deller@gmx.de>
+ *
+ * based on arch/arm/kernel/topology.c
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/percpu.h>
+#include <linux/sched.h>
+#include <linux/sched/topology.h>
+#include <linux/cpu.h>
+
+#include <asm/topology.h>
+#include <asm/sections.h>
+
+static DEFINE_PER_CPU(struct cpu, cpu_devices);
+
+/*
+ * store_cpu_topology is called at boot when only one cpu is running
+ * and with the mutex cpu_hotplug.lock locked, when several cpus have booted,
+ * which prevents simultaneous write access to cpu_topology array
+ */
+void store_cpu_topology(unsigned int cpuid)
+{
+ struct cpu_topology *cpuid_topo = &cpu_topology[cpuid];
+ struct cpuinfo_parisc *p;
+ int max_socket = -1;
+ unsigned long cpu;
+
+ /* If the cpu topology has been already set, just return */
+ if (cpuid_topo->core_id != -1)
+ return;
+
+#ifdef CONFIG_HOTPLUG_CPU
+ per_cpu(cpu_devices, cpuid).hotpluggable = 1;
+#endif
+ if (register_cpu(&per_cpu(cpu_devices, cpuid), cpuid))
+ pr_warn("Failed to register CPU%d device", cpuid);
+
+ /* create cpu topology mapping */
+ cpuid_topo->thread_id = -1;
+ cpuid_topo->core_id = 0;
+
+ p = &per_cpu(cpu_data, cpuid);
+ for_each_online_cpu(cpu) {
+ const struct cpuinfo_parisc *cpuinfo = &per_cpu(cpu_data, cpu);
+
+ if (cpu == cpuid) /* ignore current cpu */
+ continue;
+
+ if (cpuinfo->cpu_loc == p->cpu_loc) {
+ cpuid_topo->core_id = cpu_topology[cpu].core_id;
+ if (p->cpu_loc) {
+ cpuid_topo->core_id++;
+ cpuid_topo->package_id = cpu_topology[cpu].package_id;
+ continue;
+ }
+ }
+
+ if (cpuid_topo->package_id == -1)
+ max_socket = max(max_socket, cpu_topology[cpu].package_id);
+ }
+
+ if (cpuid_topo->package_id == -1)
+ cpuid_topo->package_id = max_socket + 1;
+
+ update_siblings_masks(cpuid);
+
+ pr_info("CPU%u: cpu core %d of socket %d\n",
+ cpuid,
+ cpu_topology[cpuid].core_id,
+ cpu_topology[cpuid].package_id);
+}
+
+/*
+ * init_cpu_topology is called at boot when only one cpu is running
+ * which prevent simultaneous write access to cpu_topology array
+ */
+void __init init_cpu_topology(void)
+{
+ reset_cpu_topology();
+}
diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c
new file mode 100644
index 000000000..1107ca819
--- /dev/null
+++ b/arch/parisc/kernel/traps.c
@@ -0,0 +1,859 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * linux/arch/parisc/traps.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright (C) 1999, 2000 Philipp Rumpf <prumpf@tux.org>
+ */
+
+/*
+ * 'Traps.c' handles hardware traps and faults after we have saved some
+ * state in 'asm.s'.
+ */
+
+#include <linux/sched.h>
+#include <linux/sched/debug.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/smp.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/console.h>
+#include <linux/bug.h>
+#include <linux/ratelimit.h>
+#include <linux/uaccess.h>
+#include <linux/kdebug.h>
+#include <linux/kfence.h>
+
+#include <asm/assembly.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/traps.h>
+#include <asm/unaligned.h>
+#include <linux/atomic.h>
+#include <asm/smp.h>
+#include <asm/pdc.h>
+#include <asm/pdc_chassis.h>
+#include <asm/unwind.h>
+#include <asm/tlbflush.h>
+#include <asm/cacheflush.h>
+#include <linux/kgdb.h>
+#include <linux/kprobes.h>
+
+#if defined(CONFIG_LIGHTWEIGHT_SPINLOCK_CHECK)
+#include <asm/spinlock.h>
+#endif
+
+#include "../math-emu/math-emu.h" /* for handle_fpe() */
+
+static void parisc_show_stack(struct task_struct *task,
+ struct pt_regs *regs, const char *loglvl);
+
+static int printbinary(char *buf, unsigned long x, int nbits)
+{
+ unsigned long mask = 1UL << (nbits - 1);
+ while (mask != 0) {
+ *buf++ = (mask & x ? '1' : '0');
+ mask >>= 1;
+ }
+ *buf = '\0';
+
+ return nbits;
+}
+
+#ifdef CONFIG_64BIT
+#define RFMT "%016lx"
+#else
+#define RFMT "%08lx"
+#endif
+#define FFMT "%016llx" /* fpregs are 64-bit always */
+
+#define PRINTREGS(lvl,r,f,fmt,x) \
+ printk("%s%s%02d-%02d " fmt " " fmt " " fmt " " fmt "\n", \
+ lvl, f, (x), (x+3), (r)[(x)+0], (r)[(x)+1], \
+ (r)[(x)+2], (r)[(x)+3])
+
+static void print_gr(const char *level, struct pt_regs *regs)
+{
+ int i;
+ char buf[64];
+
+ printk("%s\n", level);
+ printk("%s YZrvWESTHLNXBCVMcbcbcbcbOGFRQPDI\n", level);
+ printbinary(buf, regs->gr[0], 32);
+ printk("%sPSW: %s %s\n", level, buf, print_tainted());
+
+ for (i = 0; i < 32; i += 4)
+ PRINTREGS(level, regs->gr, "r", RFMT, i);
+}
+
+static void print_fr(const char *level, struct pt_regs *regs)
+{
+ int i;
+ char buf[64];
+ struct { u32 sw[2]; } s;
+
+ /* FR are 64bit everywhere. Need to use asm to get the content
+ * of fpsr/fper1, and we assume that we won't have a FP Identify
+ * in our way, otherwise we're screwed.
+ * The fldd is used to restore the T-bit if there was one, as the
+ * store clears it anyway.
+ * PA2.0 book says "thou shall not use fstw on FPSR/FPERs" - T-Bone */
+ asm volatile ("fstd %%fr0,0(%1) \n\t"
+ "fldd 0(%1),%%fr0 \n\t"
+ : "=m" (s) : "r" (&s) : "r0");
+
+ printk("%s\n", level);
+ printk("%s VZOUICununcqcqcqcqcqcrmunTDVZOUI\n", level);
+ printbinary(buf, s.sw[0], 32);
+ printk("%sFPSR: %s\n", level, buf);
+ printk("%sFPER1: %08x\n", level, s.sw[1]);
+
+ /* here we'll print fr0 again, tho it'll be meaningless */
+ for (i = 0; i < 32; i += 4)
+ PRINTREGS(level, regs->fr, "fr", FFMT, i);
+}
+
+void show_regs(struct pt_regs *regs)
+{
+ int i, user;
+ const char *level;
+ unsigned long cr30, cr31;
+
+ user = user_mode(regs);
+ level = user ? KERN_DEBUG : KERN_CRIT;
+
+ show_regs_print_info(level);
+
+ print_gr(level, regs);
+
+ for (i = 0; i < 8; i += 4)
+ PRINTREGS(level, regs->sr, "sr", RFMT, i);
+
+ if (user)
+ print_fr(level, regs);
+
+ cr30 = mfctl(30);
+ cr31 = mfctl(31);
+ printk("%s\n", level);
+ printk("%sIASQ: " RFMT " " RFMT " IAOQ: " RFMT " " RFMT "\n",
+ level, regs->iasq[0], regs->iasq[1], regs->iaoq[0], regs->iaoq[1]);
+ printk("%s IIR: %08lx ISR: " RFMT " IOR: " RFMT "\n",
+ level, regs->iir, regs->isr, regs->ior);
+ printk("%s CPU: %8d CR30: " RFMT " CR31: " RFMT "\n",
+ level, task_cpu(current), cr30, cr31);
+ printk("%s ORIG_R28: " RFMT "\n", level, regs->orig_r28);
+
+ if (user) {
+ printk("%s IAOQ[0]: " RFMT "\n", level, regs->iaoq[0]);
+ printk("%s IAOQ[1]: " RFMT "\n", level, regs->iaoq[1]);
+ printk("%s RP(r2): " RFMT "\n", level, regs->gr[2]);
+ } else {
+ printk("%s IAOQ[0]: %pS\n", level, (void *) regs->iaoq[0]);
+ printk("%s IAOQ[1]: %pS\n", level, (void *) regs->iaoq[1]);
+ printk("%s RP(r2): %pS\n", level, (void *) regs->gr[2]);
+
+ parisc_show_stack(current, regs, KERN_DEFAULT);
+ }
+}
+
+static DEFINE_RATELIMIT_STATE(_hppa_rs,
+ DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST);
+
+#define parisc_printk_ratelimited(critical, regs, fmt, ...) { \
+ if ((critical || show_unhandled_signals) && __ratelimit(&_hppa_rs)) { \
+ printk(fmt, ##__VA_ARGS__); \
+ show_regs(regs); \
+ } \
+}
+
+
+static void do_show_stack(struct unwind_frame_info *info, const char *loglvl)
+{
+ int i = 1;
+
+ printk("%sBacktrace:\n", loglvl);
+ while (i <= MAX_UNWIND_ENTRIES) {
+ if (unwind_once(info) < 0 || info->ip == 0)
+ break;
+
+ if (__kernel_text_address(info->ip)) {
+ printk("%s [<" RFMT ">] %pS\n",
+ loglvl, info->ip, (void *) info->ip);
+ i++;
+ }
+ }
+ printk("%s\n", loglvl);
+}
+
+static void parisc_show_stack(struct task_struct *task,
+ struct pt_regs *regs, const char *loglvl)
+{
+ struct unwind_frame_info info;
+
+ unwind_frame_init_task(&info, task, regs);
+
+ do_show_stack(&info, loglvl);
+}
+
+void show_stack(struct task_struct *t, unsigned long *sp, const char *loglvl)
+{
+ parisc_show_stack(t, NULL, loglvl);
+}
+
+int is_valid_bugaddr(unsigned long iaoq)
+{
+ return 1;
+}
+
+void die_if_kernel(char *str, struct pt_regs *regs, long err)
+{
+ if (user_mode(regs)) {
+ if (err == 0)
+ return; /* STFU */
+
+ parisc_printk_ratelimited(1, regs,
+ KERN_CRIT "%s (pid %d): %s (code %ld) at " RFMT "\n",
+ current->comm, task_pid_nr(current), str, err, regs->iaoq[0]);
+
+ return;
+ }
+
+ bust_spinlocks(1);
+
+ oops_enter();
+
+ /* Amuse the user in a SPARC fashion */
+ if (err) printk(KERN_CRIT
+ " _______________________________ \n"
+ " < Your System ate a SPARC! Gah! >\n"
+ " ------------------------------- \n"
+ " \\ ^__^\n"
+ " (__)\\ )\\/\\\n"
+ " U ||----w |\n"
+ " || ||\n");
+
+ /* unlock the pdc lock if necessary */
+ pdc_emergency_unlock();
+
+ if (err)
+ printk(KERN_CRIT "%s (pid %d): %s (code %ld)\n",
+ current->comm, task_pid_nr(current), str, err);
+
+ /* Wot's wrong wif bein' racy? */
+ if (current->thread.flags & PARISC_KERNEL_DEATH) {
+ printk(KERN_CRIT "%s() recursion detected.\n", __func__);
+ local_irq_enable();
+ while (1);
+ }
+ current->thread.flags |= PARISC_KERNEL_DEATH;
+
+ show_regs(regs);
+ dump_stack();
+ add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
+
+ if (in_interrupt())
+ panic("Fatal exception in interrupt");
+
+ if (panic_on_oops)
+ panic("Fatal exception");
+
+ oops_exit();
+ make_task_dead(SIGSEGV);
+}
+
+/* gdb uses break 4,8 */
+#define GDB_BREAK_INSN 0x10004
+static void handle_gdb_break(struct pt_regs *regs, int wot)
+{
+ force_sig_fault(SIGTRAP, wot,
+ (void __user *) (regs->iaoq[0] & ~3));
+}
+
+static void handle_break(struct pt_regs *regs)
+{
+ unsigned iir = regs->iir;
+
+ if (unlikely(iir == PARISC_BUG_BREAK_INSN && !user_mode(regs))) {
+ /* check if a BUG() or WARN() trapped here. */
+ enum bug_trap_type tt;
+ tt = report_bug(regs->iaoq[0] & ~3, regs);
+ if (tt == BUG_TRAP_TYPE_WARN) {
+ regs->iaoq[0] += 4;
+ regs->iaoq[1] += 4;
+ return; /* return to next instruction when WARN_ON(). */
+ }
+ die_if_kernel("Unknown kernel breakpoint", regs,
+ (tt == BUG_TRAP_TYPE_NONE) ? 9 : 0);
+ }
+
+#ifdef CONFIG_KPROBES
+ if (unlikely(iir == PARISC_KPROBES_BREAK_INSN && !user_mode(regs))) {
+ parisc_kprobe_break_handler(regs);
+ return;
+ }
+ if (unlikely(iir == PARISC_KPROBES_BREAK_INSN2 && !user_mode(regs))) {
+ parisc_kprobe_ss_handler(regs);
+ return;
+ }
+#endif
+
+#ifdef CONFIG_KGDB
+ if (unlikely((iir == PARISC_KGDB_COMPILED_BREAK_INSN ||
+ iir == PARISC_KGDB_BREAK_INSN)) && !user_mode(regs)) {
+ kgdb_handle_exception(9, SIGTRAP, 0, regs);
+ return;
+ }
+#endif
+
+#ifdef CONFIG_LIGHTWEIGHT_SPINLOCK_CHECK
+ if ((iir == SPINLOCK_BREAK_INSN) && !user_mode(regs)) {
+ die_if_kernel("Spinlock was trashed", regs, 1);
+ }
+#endif
+
+ if (unlikely(iir != GDB_BREAK_INSN))
+ parisc_printk_ratelimited(0, regs,
+ KERN_DEBUG "break %d,%d: pid=%d command='%s'\n",
+ iir & 31, (iir>>13) & ((1<<13)-1),
+ task_pid_nr(current), current->comm);
+
+ /* send standard GDB signal */
+ handle_gdb_break(regs, TRAP_BRKPT);
+}
+
+static void default_trap(int code, struct pt_regs *regs)
+{
+ printk(KERN_ERR "Trap %d on CPU %d\n", code, smp_processor_id());
+ show_regs(regs);
+}
+
+static void transfer_pim_to_trap_frame(struct pt_regs *regs)
+{
+ register int i;
+ extern unsigned int hpmc_pim_data[];
+ struct pdc_hpmc_pim_11 *pim_narrow;
+ struct pdc_hpmc_pim_20 *pim_wide;
+
+ if (boot_cpu_data.cpu_type >= pcxu) {
+
+ pim_wide = (struct pdc_hpmc_pim_20 *)hpmc_pim_data;
+
+ /*
+ * Note: The following code will probably generate a
+ * bunch of truncation error warnings from the compiler.
+ * Could be handled with an ifdef, but perhaps there
+ * is a better way.
+ */
+
+ regs->gr[0] = pim_wide->cr[22];
+
+ for (i = 1; i < 32; i++)
+ regs->gr[i] = pim_wide->gr[i];
+
+ for (i = 0; i < 32; i++)
+ regs->fr[i] = pim_wide->fr[i];
+
+ for (i = 0; i < 8; i++)
+ regs->sr[i] = pim_wide->sr[i];
+
+ regs->iasq[0] = pim_wide->cr[17];
+ regs->iasq[1] = pim_wide->iasq_back;
+ regs->iaoq[0] = pim_wide->cr[18];
+ regs->iaoq[1] = pim_wide->iaoq_back;
+
+ regs->sar = pim_wide->cr[11];
+ regs->iir = pim_wide->cr[19];
+ regs->isr = pim_wide->cr[20];
+ regs->ior = pim_wide->cr[21];
+ }
+ else {
+ pim_narrow = (struct pdc_hpmc_pim_11 *)hpmc_pim_data;
+
+ regs->gr[0] = pim_narrow->cr[22];
+
+ for (i = 1; i < 32; i++)
+ regs->gr[i] = pim_narrow->gr[i];
+
+ for (i = 0; i < 32; i++)
+ regs->fr[i] = pim_narrow->fr[i];
+
+ for (i = 0; i < 8; i++)
+ regs->sr[i] = pim_narrow->sr[i];
+
+ regs->iasq[0] = pim_narrow->cr[17];
+ regs->iasq[1] = pim_narrow->iasq_back;
+ regs->iaoq[0] = pim_narrow->cr[18];
+ regs->iaoq[1] = pim_narrow->iaoq_back;
+
+ regs->sar = pim_narrow->cr[11];
+ regs->iir = pim_narrow->cr[19];
+ regs->isr = pim_narrow->cr[20];
+ regs->ior = pim_narrow->cr[21];
+ }
+
+ /*
+ * The following fields only have meaning if we came through
+ * another path. So just zero them here.
+ */
+
+ regs->ksp = 0;
+ regs->kpc = 0;
+ regs->orig_r28 = 0;
+}
+
+
+/*
+ * This routine is called as a last resort when everything else
+ * has gone clearly wrong. We get called for faults in kernel space,
+ * and HPMC's.
+ */
+void parisc_terminate(char *msg, struct pt_regs *regs, int code, unsigned long offset)
+{
+ static DEFINE_SPINLOCK(terminate_lock);
+
+ (void)notify_die(DIE_OOPS, msg, regs, 0, code, SIGTRAP);
+ bust_spinlocks(1);
+
+ set_eiem(0);
+ local_irq_disable();
+ spin_lock(&terminate_lock);
+
+ /* unlock the pdc lock if necessary */
+ pdc_emergency_unlock();
+
+ /* Not all paths will gutter the processor... */
+ switch(code){
+
+ case 1:
+ transfer_pim_to_trap_frame(regs);
+ break;
+
+ default:
+ break;
+
+ }
+
+ {
+ /* show_stack(NULL, (unsigned long *)regs->gr[30]); */
+ struct unwind_frame_info info;
+ unwind_frame_init(&info, current, regs);
+ do_show_stack(&info, KERN_CRIT);
+ }
+
+ printk("\n");
+ pr_crit("%s: Code=%d (%s) at addr " RFMT "\n",
+ msg, code, trap_name(code), offset);
+ show_regs(regs);
+
+ spin_unlock(&terminate_lock);
+
+ /* put soft power button back under hardware control;
+ * if the user had pressed it once at any time, the
+ * system will shut down immediately right here. */
+ pdc_soft_power_button(0);
+
+ /* Call kernel panic() so reboot timeouts work properly
+ * FIXME: This function should be on the list of
+ * panic notifiers, and we should call panic
+ * directly from the location that we wish.
+ * e.g. We should not call panic from
+ * parisc_terminate, but rather the other way around.
+ * This hack works, prints the panic message twice,
+ * and it enables reboot timers!
+ */
+ panic(msg);
+}
+
+void notrace handle_interruption(int code, struct pt_regs *regs)
+{
+ unsigned long fault_address = 0;
+ unsigned long fault_space = 0;
+ int si_code;
+
+ if (!irqs_disabled_flags(regs->gr[0]))
+ local_irq_enable();
+
+ /* Security check:
+ * If the priority level is still user, and the
+ * faulting space is not equal to the active space
+ * then the user is attempting something in a space
+ * that does not belong to them. Kill the process.
+ *
+ * This is normally the situation when the user
+ * attempts to jump into the kernel space at the
+ * wrong offset, be it at the gateway page or a
+ * random location.
+ *
+ * We cannot normally signal the process because it
+ * could *be* on the gateway page, and processes
+ * executing on the gateway page can't have signals
+ * delivered.
+ *
+ * We merely readjust the address into the users
+ * space, at a destination address of zero, and
+ * allow processing to continue.
+ */
+ if (((unsigned long)regs->iaoq[0] & 3) &&
+ ((unsigned long)regs->iasq[0] != (unsigned long)regs->sr[7])) {
+ /* Kill the user process later */
+ regs->iaoq[0] = 0 | 3;
+ regs->iaoq[1] = regs->iaoq[0] + 4;
+ regs->iasq[0] = regs->iasq[1] = regs->sr[7];
+ regs->gr[0] &= ~PSW_B;
+ return;
+ }
+
+#if 0
+ printk(KERN_CRIT "Interruption # %d\n", code);
+#endif
+
+ switch(code) {
+
+ case 1:
+ /* High-priority machine check (HPMC) */
+
+ /* set up a new led state on systems shipped with a LED State panel */
+ pdc_chassis_send_status(PDC_CHASSIS_DIRECT_HPMC);
+
+ parisc_terminate("High Priority Machine Check (HPMC)",
+ regs, code, 0);
+ /* NOT REACHED */
+
+ case 2:
+ /* Power failure interrupt */
+ printk(KERN_CRIT "Power failure interrupt !\n");
+ return;
+
+ case 3:
+ /* Recovery counter trap */
+ regs->gr[0] &= ~PSW_R;
+
+#ifdef CONFIG_KGDB
+ if (kgdb_single_step) {
+ kgdb_handle_exception(0, SIGTRAP, 0, regs);
+ return;
+ }
+#endif
+
+ if (user_space(regs))
+ handle_gdb_break(regs, TRAP_TRACE);
+ /* else this must be the start of a syscall - just let it run */
+ return;
+
+ case 5:
+ /* Low-priority machine check */
+ pdc_chassis_send_status(PDC_CHASSIS_DIRECT_LPMC);
+
+ flush_cache_all();
+ flush_tlb_all();
+ default_trap(code, regs);
+ return;
+
+ case PARISC_ITLB_TRAP:
+ /* Instruction TLB miss fault/Instruction page fault */
+ fault_address = regs->iaoq[0];
+ fault_space = regs->iasq[0];
+ break;
+
+ case 8:
+ /* Illegal instruction trap */
+ die_if_kernel("Illegal instruction", regs, code);
+ si_code = ILL_ILLOPC;
+ goto give_sigill;
+
+ case 9:
+ /* Break instruction trap */
+ handle_break(regs);
+ return;
+
+ case 10:
+ /* Privileged operation trap */
+ die_if_kernel("Privileged operation", regs, code);
+ si_code = ILL_PRVOPC;
+ goto give_sigill;
+
+ case 11:
+ /* Privileged register trap */
+ if ((regs->iir & 0xffdfffe0) == 0x034008a0) {
+
+ /* This is a MFCTL cr26/cr27 to gr instruction.
+ * PCXS traps on this, so we need to emulate it.
+ */
+
+ if (regs->iir & 0x00200000)
+ regs->gr[regs->iir & 0x1f] = mfctl(27);
+ else
+ regs->gr[regs->iir & 0x1f] = mfctl(26);
+
+ regs->iaoq[0] = regs->iaoq[1];
+ regs->iaoq[1] += 4;
+ regs->iasq[0] = regs->iasq[1];
+ return;
+ }
+
+ die_if_kernel("Privileged register usage", regs, code);
+ si_code = ILL_PRVREG;
+ give_sigill:
+ force_sig_fault(SIGILL, si_code,
+ (void __user *) regs->iaoq[0]);
+ return;
+
+ case 12:
+ /* Overflow Trap, let the userland signal handler do the cleanup */
+ force_sig_fault(SIGFPE, FPE_INTOVF,
+ (void __user *) regs->iaoq[0]);
+ return;
+
+ case 13:
+ /* Conditional Trap
+ The condition succeeds in an instruction which traps
+ on condition */
+ if(user_mode(regs)){
+ /* Let userspace app figure it out from the insn pointed
+ * to by si_addr.
+ */
+ force_sig_fault(SIGFPE, FPE_CONDTRAP,
+ (void __user *) regs->iaoq[0]);
+ return;
+ }
+ /* The kernel doesn't want to handle condition codes */
+ break;
+
+ case 14:
+ /* Assist Exception Trap, i.e. floating point exception. */
+ die_if_kernel("Floating point exception", regs, 0); /* quiet */
+ __inc_irq_stat(irq_fpassist_count);
+ handle_fpe(regs);
+ return;
+
+ case 15:
+ /* Data TLB miss fault/Data page fault */
+ fallthrough;
+ case 16:
+ /* Non-access instruction TLB miss fault */
+ /* The instruction TLB entry needed for the target address of the FIC
+ is absent, and hardware can't find it, so we get to cleanup */
+ fallthrough;
+ case 17:
+ /* Non-access data TLB miss fault/Non-access data page fault */
+ /* FIXME:
+ Still need to add slow path emulation code here!
+ If the insn used a non-shadow register, then the tlb
+ handlers could not have their side-effect (e.g. probe
+ writing to a target register) emulated since rfir would
+ erase the changes to said register. Instead we have to
+ setup everything, call this function we are in, and emulate
+ by hand. Technically we need to emulate:
+ fdc,fdce,pdc,"fic,4f",prober,probeir,probew, probeiw
+ */
+ if (code == 17 && handle_nadtlb_fault(regs))
+ return;
+ fault_address = regs->ior;
+ fault_space = regs->isr;
+ break;
+
+ case 18:
+ /* PCXS only -- later cpu's split this into types 26,27 & 28 */
+ /* Check for unaligned access */
+ if (check_unaligned(regs)) {
+ handle_unaligned(regs);
+ return;
+ }
+ fallthrough;
+ case 26:
+ /* PCXL: Data memory access rights trap */
+ fault_address = regs->ior;
+ fault_space = regs->isr;
+ break;
+
+ case 19:
+ /* Data memory break trap */
+ regs->gr[0] |= PSW_X; /* So we can single-step over the trap */
+ fallthrough;
+ case 21:
+ /* Page reference trap */
+ handle_gdb_break(regs, TRAP_HWBKPT);
+ return;
+
+ case 25:
+ /* Taken branch trap */
+ regs->gr[0] &= ~PSW_T;
+ if (user_space(regs))
+ handle_gdb_break(regs, TRAP_BRANCH);
+ /* else this must be the start of a syscall - just let it
+ * run.
+ */
+ return;
+
+ case 7:
+ /* Instruction access rights */
+ /* PCXL: Instruction memory protection trap */
+
+ /*
+ * This could be caused by either: 1) a process attempting
+ * to execute within a vma that does not have execute
+ * permission, or 2) an access rights violation caused by a
+ * flush only translation set up by ptep_get_and_clear().
+ * So we check the vma permissions to differentiate the two.
+ * If the vma indicates we have execute permission, then
+ * the cause is the latter one. In this case, we need to
+ * call do_page_fault() to fix the problem.
+ */
+
+ if (user_mode(regs)) {
+ struct vm_area_struct *vma;
+
+ mmap_read_lock(current->mm);
+ vma = find_vma(current->mm,regs->iaoq[0]);
+ if (vma && (regs->iaoq[0] >= vma->vm_start)
+ && (vma->vm_flags & VM_EXEC)) {
+
+ fault_address = regs->iaoq[0];
+ fault_space = regs->iasq[0];
+
+ mmap_read_unlock(current->mm);
+ break; /* call do_page_fault() */
+ }
+ mmap_read_unlock(current->mm);
+ }
+ /* CPU could not fetch instruction, so clear stale IIR value. */
+ regs->iir = 0xbaadf00d;
+ fallthrough;
+ case 27:
+ /* Data memory protection ID trap */
+ if (code == 27 && !user_mode(regs) &&
+ fixup_exception(regs))
+ return;
+
+ die_if_kernel("Protection id trap", regs, code);
+ force_sig_fault(SIGSEGV, SEGV_MAPERR,
+ (code == 7)?
+ ((void __user *) regs->iaoq[0]) :
+ ((void __user *) regs->ior));
+ return;
+
+ case 28:
+ /* Unaligned data reference trap */
+ handle_unaligned(regs);
+ return;
+
+ default:
+ if (user_mode(regs)) {
+ parisc_printk_ratelimited(0, regs, KERN_DEBUG
+ "handle_interruption() pid=%d command='%s'\n",
+ task_pid_nr(current), current->comm);
+ /* SIGBUS, for lack of a better one. */
+ force_sig_fault(SIGBUS, BUS_OBJERR,
+ (void __user *)regs->ior);
+ return;
+ }
+ pdc_chassis_send_status(PDC_CHASSIS_DIRECT_PANIC);
+
+ parisc_terminate("Unexpected interruption", regs, code, 0);
+ /* NOT REACHED */
+ }
+
+ if (user_mode(regs)) {
+ if ((fault_space >> SPACEID_SHIFT) != (regs->sr[7] >> SPACEID_SHIFT)) {
+ parisc_printk_ratelimited(0, regs, KERN_DEBUG
+ "User fault %d on space 0x%08lx, pid=%d command='%s'\n",
+ code, fault_space,
+ task_pid_nr(current), current->comm);
+ force_sig_fault(SIGSEGV, SEGV_MAPERR,
+ (void __user *)regs->ior);
+ return;
+ }
+ }
+ else {
+
+ /*
+ * The kernel should never fault on its own address space,
+ * unless pagefault_disable() was called before.
+ */
+
+ if (faulthandler_disabled() || fault_space == 0)
+ {
+ /* Clean up and return if in exception table. */
+ if (fixup_exception(regs))
+ return;
+ /* Clean up and return if handled by kfence. */
+ if (kfence_handle_page_fault(fault_address,
+ parisc_acctyp(code, regs->iir) == VM_WRITE, regs))
+ return;
+ pdc_chassis_send_status(PDC_CHASSIS_DIRECT_PANIC);
+ parisc_terminate("Kernel Fault", regs, code, fault_address);
+ }
+ }
+
+ do_page_fault(regs, code, fault_address);
+}
+
+
+static void __init initialize_ivt(const void *iva)
+{
+ extern const u32 os_hpmc[];
+
+ int i;
+ u32 check = 0;
+ u32 *ivap;
+ u32 instr;
+
+ if (strcmp((const char *)iva, "cows can fly"))
+ panic("IVT invalid");
+
+ ivap = (u32 *)iva;
+
+ for (i = 0; i < 8; i++)
+ *ivap++ = 0;
+
+ /*
+ * Use PDC_INSTR firmware function to get instruction that invokes
+ * PDCE_CHECK in HPMC handler. See programming note at page 1-31 of
+ * the PA 1.1 Firmware Architecture document.
+ */
+ if (pdc_instr(&instr) == PDC_OK)
+ ivap[0] = instr;
+
+ /*
+ * Rules for the checksum of the HPMC handler:
+ * 1. The IVA does not point to PDC/PDH space (ie: the OS has installed
+ * its own IVA).
+ * 2. The word at IVA + 32 is nonzero.
+ * 3. If Length (IVA + 60) is not zero, then Length (IVA + 60) and
+ * Address (IVA + 56) are word-aligned.
+ * 4. The checksum of the 8 words starting at IVA + 32 plus the sum of
+ * the Length/4 words starting at Address is zero.
+ */
+
+ /* Setup IVA and compute checksum for HPMC handler */
+ ivap[6] = (u32)__pa(os_hpmc);
+
+ for (i=0; i<8; i++)
+ check += ivap[i];
+
+ ivap[5] = -check;
+ pr_debug("initialize_ivt: IVA[6] = 0x%08x\n", ivap[6]);
+}
+
+
+/* early_trap_init() is called before we set up kernel mappings and
+ * write-protect the kernel */
+void __init early_trap_init(void)
+{
+ extern const void fault_vector_20;
+
+#ifndef CONFIG_64BIT
+ extern const void fault_vector_11;
+ initialize_ivt(&fault_vector_11);
+#endif
+
+ initialize_ivt(&fault_vector_20);
+}
diff --git a/arch/parisc/kernel/unaligned.c b/arch/parisc/kernel/unaligned.c
new file mode 100644
index 000000000..ce25acfe4
--- /dev/null
+++ b/arch/parisc/kernel/unaligned.c
@@ -0,0 +1,674 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Unaligned memory access handler
+ *
+ * Copyright (C) 2001 Randolph Chung <tausq@debian.org>
+ * Copyright (C) 2022 Helge Deller <deller@gmx.de>
+ * Significantly tweaked by LaMont Jones <lamont@debian.org>
+ */
+
+#include <linux/sched/signal.h>
+#include <linux/signal.h>
+#include <linux/ratelimit.h>
+#include <linux/uaccess.h>
+#include <linux/sysctl.h>
+#include <asm/unaligned.h>
+#include <asm/hardirq.h>
+#include <asm/traps.h>
+
+/* #define DEBUG_UNALIGNED 1 */
+
+#ifdef DEBUG_UNALIGNED
+#define DPRINTF(fmt, args...) do { printk(KERN_DEBUG "%s:%d:%s ", __FILE__, __LINE__, __func__ ); printk(KERN_DEBUG fmt, ##args ); } while (0)
+#else
+#define DPRINTF(fmt, args...)
+#endif
+
+#define RFMT "%#08lx"
+
+/* 1111 1100 0000 0000 0001 0011 1100 0000 */
+#define OPCODE1(a,b,c) ((a)<<26|(b)<<12|(c)<<6)
+#define OPCODE2(a,b) ((a)<<26|(b)<<1)
+#define OPCODE3(a,b) ((a)<<26|(b)<<2)
+#define OPCODE4(a) ((a)<<26)
+#define OPCODE1_MASK OPCODE1(0x3f,1,0xf)
+#define OPCODE2_MASK OPCODE2(0x3f,1)
+#define OPCODE3_MASK OPCODE3(0x3f,1)
+#define OPCODE4_MASK OPCODE4(0x3f)
+
+/* skip LDB - never unaligned (index) */
+#define OPCODE_LDH_I OPCODE1(0x03,0,0x1)
+#define OPCODE_LDW_I OPCODE1(0x03,0,0x2)
+#define OPCODE_LDD_I OPCODE1(0x03,0,0x3)
+#define OPCODE_LDDA_I OPCODE1(0x03,0,0x4)
+#define OPCODE_LDCD_I OPCODE1(0x03,0,0x5)
+#define OPCODE_LDWA_I OPCODE1(0x03,0,0x6)
+#define OPCODE_LDCW_I OPCODE1(0x03,0,0x7)
+/* skip LDB - never unaligned (short) */
+#define OPCODE_LDH_S OPCODE1(0x03,1,0x1)
+#define OPCODE_LDW_S OPCODE1(0x03,1,0x2)
+#define OPCODE_LDD_S OPCODE1(0x03,1,0x3)
+#define OPCODE_LDDA_S OPCODE1(0x03,1,0x4)
+#define OPCODE_LDCD_S OPCODE1(0x03,1,0x5)
+#define OPCODE_LDWA_S OPCODE1(0x03,1,0x6)
+#define OPCODE_LDCW_S OPCODE1(0x03,1,0x7)
+/* skip STB - never unaligned */
+#define OPCODE_STH OPCODE1(0x03,1,0x9)
+#define OPCODE_STW OPCODE1(0x03,1,0xa)
+#define OPCODE_STD OPCODE1(0x03,1,0xb)
+/* skip STBY - never unaligned */
+/* skip STDBY - never unaligned */
+#define OPCODE_STWA OPCODE1(0x03,1,0xe)
+#define OPCODE_STDA OPCODE1(0x03,1,0xf)
+
+#define OPCODE_FLDWX OPCODE1(0x09,0,0x0)
+#define OPCODE_FLDWXR OPCODE1(0x09,0,0x1)
+#define OPCODE_FSTWX OPCODE1(0x09,0,0x8)
+#define OPCODE_FSTWXR OPCODE1(0x09,0,0x9)
+#define OPCODE_FLDWS OPCODE1(0x09,1,0x0)
+#define OPCODE_FLDWSR OPCODE1(0x09,1,0x1)
+#define OPCODE_FSTWS OPCODE1(0x09,1,0x8)
+#define OPCODE_FSTWSR OPCODE1(0x09,1,0x9)
+#define OPCODE_FLDDX OPCODE1(0x0b,0,0x0)
+#define OPCODE_FSTDX OPCODE1(0x0b,0,0x8)
+#define OPCODE_FLDDS OPCODE1(0x0b,1,0x0)
+#define OPCODE_FSTDS OPCODE1(0x0b,1,0x8)
+
+#define OPCODE_LDD_L OPCODE2(0x14,0)
+#define OPCODE_FLDD_L OPCODE2(0x14,1)
+#define OPCODE_STD_L OPCODE2(0x1c,0)
+#define OPCODE_FSTD_L OPCODE2(0x1c,1)
+
+#define OPCODE_LDW_M OPCODE3(0x17,1)
+#define OPCODE_FLDW_L OPCODE3(0x17,0)
+#define OPCODE_FSTW_L OPCODE3(0x1f,0)
+#define OPCODE_STW_M OPCODE3(0x1f,1)
+
+#define OPCODE_LDH_L OPCODE4(0x11)
+#define OPCODE_LDW_L OPCODE4(0x12)
+#define OPCODE_LDWM OPCODE4(0x13)
+#define OPCODE_STH_L OPCODE4(0x19)
+#define OPCODE_STW_L OPCODE4(0x1A)
+#define OPCODE_STWM OPCODE4(0x1B)
+
+#define MAJOR_OP(i) (((i)>>26)&0x3f)
+#define R1(i) (((i)>>21)&0x1f)
+#define R2(i) (((i)>>16)&0x1f)
+#define R3(i) ((i)&0x1f)
+#define FR3(i) ((((i)&0x1f)<<1)|(((i)>>6)&1))
+#define IM(i,n) (((i)>>1&((1<<(n-1))-1))|((i)&1?((0-1L)<<(n-1)):0))
+#define IM5_2(i) IM((i)>>16,5)
+#define IM5_3(i) IM((i),5)
+#define IM14(i) IM((i),14)
+
+#define ERR_NOTHANDLED -1
+
+int unaligned_enabled __read_mostly = 1;
+
+static int emulate_ldh(struct pt_regs *regs, int toreg)
+{
+ unsigned long saddr = regs->ior;
+ unsigned long val = 0, temp1;
+ ASM_EXCEPTIONTABLE_VAR(ret);
+
+ DPRINTF("load " RFMT ":" RFMT " to r%d for 2 bytes\n",
+ regs->isr, regs->ior, toreg);
+
+ __asm__ __volatile__ (
+" mtsp %4, %%sr1\n"
+"1: ldbs 0(%%sr1,%3), %2\n"
+"2: ldbs 1(%%sr1,%3), %0\n"
+" depw %2, 23, 24, %0\n"
+"3: \n"
+ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b)
+ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b)
+ : "+r" (val), "+r" (ret), "=&r" (temp1)
+ : "r" (saddr), "r" (regs->isr) );
+
+ DPRINTF("val = " RFMT "\n", val);
+
+ if (toreg)
+ regs->gr[toreg] = val;
+
+ return ret;
+}
+
+static int emulate_ldw(struct pt_regs *regs, int toreg, int flop)
+{
+ unsigned long saddr = regs->ior;
+ unsigned long val = 0, temp1, temp2;
+ ASM_EXCEPTIONTABLE_VAR(ret);
+
+ DPRINTF("load " RFMT ":" RFMT " to r%d for 4 bytes\n",
+ regs->isr, regs->ior, toreg);
+
+ __asm__ __volatile__ (
+" zdep %4,28,2,%2\n" /* r19=(ofs&3)*8 */
+" mtsp %5, %%sr1\n"
+" depw %%r0,31,2,%4\n"
+"1: ldw 0(%%sr1,%4),%0\n"
+"2: ldw 4(%%sr1,%4),%3\n"
+" subi 32,%2,%2\n"
+" mtctl %2,11\n"
+" vshd %0,%3,%0\n"
+"3: \n"
+ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b)
+ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b)
+ : "+r" (val), "+r" (ret), "=&r" (temp1), "=&r" (temp2)
+ : "r" (saddr), "r" (regs->isr) );
+
+ DPRINTF("val = " RFMT "\n", val);
+
+ if (flop)
+ ((__u32*)(regs->fr))[toreg] = val;
+ else if (toreg)
+ regs->gr[toreg] = val;
+
+ return ret;
+}
+static int emulate_ldd(struct pt_regs *regs, int toreg, int flop)
+{
+ unsigned long saddr = regs->ior;
+ __u64 val = 0;
+ ASM_EXCEPTIONTABLE_VAR(ret);
+
+ DPRINTF("load " RFMT ":" RFMT " to r%d for 8 bytes\n",
+ regs->isr, regs->ior, toreg);
+
+ if (!IS_ENABLED(CONFIG_64BIT) && !flop)
+ return ERR_NOTHANDLED;
+
+#ifdef CONFIG_64BIT
+ __asm__ __volatile__ (
+" depd,z %3,60,3,%%r19\n" /* r19=(ofs&7)*8 */
+" mtsp %4, %%sr1\n"
+" depd %%r0,63,3,%3\n"
+"1: ldd 0(%%sr1,%3),%0\n"
+"2: ldd 8(%%sr1,%3),%%r20\n"
+" subi 64,%%r19,%%r19\n"
+" mtsar %%r19\n"
+" shrpd %0,%%r20,%%sar,%0\n"
+"3: \n"
+ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b)
+ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b)
+ : "=r" (val), "+r" (ret)
+ : "0" (val), "r" (saddr), "r" (regs->isr)
+ : "r19", "r20" );
+#else
+ {
+ unsigned long shift, temp1;
+ __asm__ __volatile__ (
+" zdep %2,29,2,%3\n" /* r19=(ofs&3)*8 */
+" mtsp %5, %%sr1\n"
+" dep %%r0,31,2,%2\n"
+"1: ldw 0(%%sr1,%2),%0\n"
+"2: ldw 4(%%sr1,%2),%R0\n"
+"3: ldw 8(%%sr1,%2),%4\n"
+" subi 32,%3,%3\n"
+" mtsar %3\n"
+" vshd %0,%R0,%0\n"
+" vshd %R0,%4,%R0\n"
+"4: \n"
+ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 4b)
+ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 4b)
+ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(3b, 4b)
+ : "+r" (val), "+r" (ret), "+r" (saddr), "=&r" (shift), "=&r" (temp1)
+ : "r" (regs->isr) );
+ }
+#endif
+
+ DPRINTF("val = 0x%llx\n", val);
+
+ if (flop)
+ regs->fr[toreg] = val;
+ else if (toreg)
+ regs->gr[toreg] = val;
+
+ return ret;
+}
+
+static int emulate_sth(struct pt_regs *regs, int frreg)
+{
+ unsigned long val = regs->gr[frreg], temp1;
+ ASM_EXCEPTIONTABLE_VAR(ret);
+
+ if (!frreg)
+ val = 0;
+
+ DPRINTF("store r%d (" RFMT ") to " RFMT ":" RFMT " for 2 bytes\n", frreg,
+ val, regs->isr, regs->ior);
+
+ __asm__ __volatile__ (
+" mtsp %4, %%sr1\n"
+" extrw,u %2, 23, 8, %1\n"
+"1: stb %1, 0(%%sr1, %3)\n"
+"2: stb %2, 1(%%sr1, %3)\n"
+"3: \n"
+ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b)
+ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b)
+ : "+r" (ret), "=&r" (temp1)
+ : "r" (val), "r" (regs->ior), "r" (regs->isr) );
+
+ return ret;
+}
+
+static int emulate_stw(struct pt_regs *regs, int frreg, int flop)
+{
+ unsigned long val;
+ ASM_EXCEPTIONTABLE_VAR(ret);
+
+ if (flop)
+ val = ((__u32*)(regs->fr))[frreg];
+ else if (frreg)
+ val = regs->gr[frreg];
+ else
+ val = 0;
+
+ DPRINTF("store r%d (" RFMT ") to " RFMT ":" RFMT " for 4 bytes\n", frreg,
+ val, regs->isr, regs->ior);
+
+
+ __asm__ __volatile__ (
+" mtsp %3, %%sr1\n"
+" zdep %2, 28, 2, %%r19\n"
+" dep %%r0, 31, 2, %2\n"
+" mtsar %%r19\n"
+" depwi,z -2, %%sar, 32, %%r19\n"
+"1: ldw 0(%%sr1,%2),%%r20\n"
+"2: ldw 4(%%sr1,%2),%%r21\n"
+" vshd %%r0, %1, %%r22\n"
+" vshd %1, %%r0, %%r1\n"
+" and %%r20, %%r19, %%r20\n"
+" andcm %%r21, %%r19, %%r21\n"
+" or %%r22, %%r20, %%r20\n"
+" or %%r1, %%r21, %%r21\n"
+" stw %%r20,0(%%sr1,%2)\n"
+" stw %%r21,4(%%sr1,%2)\n"
+"3: \n"
+ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b)
+ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b)
+ : "+r" (ret)
+ : "r" (val), "r" (regs->ior), "r" (regs->isr)
+ : "r19", "r20", "r21", "r22", "r1" );
+
+ return ret;
+}
+static int emulate_std(struct pt_regs *regs, int frreg, int flop)
+{
+ __u64 val;
+ ASM_EXCEPTIONTABLE_VAR(ret);
+
+ if (flop)
+ val = regs->fr[frreg];
+ else if (frreg)
+ val = regs->gr[frreg];
+ else
+ val = 0;
+
+ DPRINTF("store r%d (0x%016llx) to " RFMT ":" RFMT " for 8 bytes\n", frreg,
+ val, regs->isr, regs->ior);
+
+ if (!IS_ENABLED(CONFIG_64BIT) && !flop)
+ return ERR_NOTHANDLED;
+
+#ifdef CONFIG_64BIT
+ __asm__ __volatile__ (
+" mtsp %3, %%sr1\n"
+" depd,z %2, 60, 3, %%r19\n"
+" depd %%r0, 63, 3, %2\n"
+" mtsar %%r19\n"
+" depdi,z -2, %%sar, 64, %%r19\n"
+"1: ldd 0(%%sr1,%2),%%r20\n"
+"2: ldd 8(%%sr1,%2),%%r21\n"
+" shrpd %%r0, %1, %%sar, %%r22\n"
+" shrpd %1, %%r0, %%sar, %%r1\n"
+" and %%r20, %%r19, %%r20\n"
+" andcm %%r21, %%r19, %%r21\n"
+" or %%r22, %%r20, %%r20\n"
+" or %%r1, %%r21, %%r21\n"
+"3: std %%r20,0(%%sr1,%2)\n"
+"4: std %%r21,8(%%sr1,%2)\n"
+"5: \n"
+ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 5b)
+ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 5b)
+ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(3b, 5b)
+ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(4b, 5b)
+ : "+r" (ret)
+ : "r" (val), "r" (regs->ior), "r" (regs->isr)
+ : "r19", "r20", "r21", "r22", "r1" );
+#else
+ {
+ __asm__ __volatile__ (
+" mtsp %3, %%sr1\n"
+" zdep %R1, 29, 2, %%r19\n"
+" dep %%r0, 31, 2, %2\n"
+" mtsar %%r19\n"
+" zvdepi -2, 32, %%r19\n"
+"1: ldw 0(%%sr1,%2),%%r20\n"
+"2: ldw 8(%%sr1,%2),%%r21\n"
+" vshd %1, %R1, %%r1\n"
+" vshd %%r0, %1, %1\n"
+" vshd %R1, %%r0, %R1\n"
+" and %%r20, %%r19, %%r20\n"
+" andcm %%r21, %%r19, %%r21\n"
+" or %1, %%r20, %1\n"
+" or %R1, %%r21, %R1\n"
+"3: stw %1,0(%%sr1,%2)\n"
+"4: stw %%r1,4(%%sr1,%2)\n"
+"5: stw %R1,8(%%sr1,%2)\n"
+"6: \n"
+ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 6b)
+ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 6b)
+ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(3b, 6b)
+ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(4b, 6b)
+ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(5b, 6b)
+ : "+r" (ret)
+ : "r" (val), "r" (regs->ior), "r" (regs->isr)
+ : "r19", "r20", "r21", "r1" );
+ }
+#endif
+
+ return ret;
+}
+
+void handle_unaligned(struct pt_regs *regs)
+{
+ static DEFINE_RATELIMIT_STATE(ratelimit, 5 * HZ, 5);
+ unsigned long newbase = R1(regs->iir)?regs->gr[R1(regs->iir)]:0;
+ int modify = 0;
+ int ret = ERR_NOTHANDLED;
+
+ __inc_irq_stat(irq_unaligned_count);
+
+ /* log a message with pacing */
+ if (user_mode(regs)) {
+ if (current->thread.flags & PARISC_UAC_SIGBUS) {
+ goto force_sigbus;
+ }
+
+ if (!(current->thread.flags & PARISC_UAC_NOPRINT) &&
+ __ratelimit(&ratelimit)) {
+ printk(KERN_WARNING "%s(%d): unaligned access to " RFMT
+ " at ip " RFMT " (iir " RFMT ")\n",
+ current->comm, task_pid_nr(current), regs->ior,
+ regs->iaoq[0], regs->iir);
+#ifdef DEBUG_UNALIGNED
+ show_regs(regs);
+#endif
+ }
+
+ if (!unaligned_enabled)
+ goto force_sigbus;
+ }
+
+ /* handle modification - OK, it's ugly, see the instruction manual */
+ switch (MAJOR_OP(regs->iir))
+ {
+ case 0x03:
+ case 0x09:
+ case 0x0b:
+ if (regs->iir&0x20)
+ {
+ modify = 1;
+ if (regs->iir&0x1000) /* short loads */
+ if (regs->iir&0x200)
+ newbase += IM5_3(regs->iir);
+ else
+ newbase += IM5_2(regs->iir);
+ else if (regs->iir&0x2000) /* scaled indexed */
+ {
+ int shift=0;
+ switch (regs->iir & OPCODE1_MASK)
+ {
+ case OPCODE_LDH_I:
+ shift= 1; break;
+ case OPCODE_LDW_I:
+ shift= 2; break;
+ case OPCODE_LDD_I:
+ case OPCODE_LDDA_I:
+ shift= 3; break;
+ }
+ newbase += (R2(regs->iir)?regs->gr[R2(regs->iir)]:0)<<shift;
+ } else /* simple indexed */
+ newbase += (R2(regs->iir)?regs->gr[R2(regs->iir)]:0);
+ }
+ break;
+ case 0x13:
+ case 0x1b:
+ modify = 1;
+ newbase += IM14(regs->iir);
+ break;
+ case 0x14:
+ case 0x1c:
+ if (regs->iir&8)
+ {
+ modify = 1;
+ newbase += IM14(regs->iir&~0xe);
+ }
+ break;
+ case 0x16:
+ case 0x1e:
+ modify = 1;
+ newbase += IM14(regs->iir&6);
+ break;
+ case 0x17:
+ case 0x1f:
+ if (regs->iir&4)
+ {
+ modify = 1;
+ newbase += IM14(regs->iir&~4);
+ }
+ break;
+ }
+
+ /* TODO: make this cleaner... */
+ switch (regs->iir & OPCODE1_MASK)
+ {
+ case OPCODE_LDH_I:
+ case OPCODE_LDH_S:
+ ret = emulate_ldh(regs, R3(regs->iir));
+ break;
+
+ case OPCODE_LDW_I:
+ case OPCODE_LDWA_I:
+ case OPCODE_LDW_S:
+ case OPCODE_LDWA_S:
+ ret = emulate_ldw(regs, R3(regs->iir), 0);
+ break;
+
+ case OPCODE_STH:
+ ret = emulate_sth(regs, R2(regs->iir));
+ break;
+
+ case OPCODE_STW:
+ case OPCODE_STWA:
+ ret = emulate_stw(regs, R2(regs->iir), 0);
+ break;
+
+#ifdef CONFIG_64BIT
+ case OPCODE_LDD_I:
+ case OPCODE_LDDA_I:
+ case OPCODE_LDD_S:
+ case OPCODE_LDDA_S:
+ ret = emulate_ldd(regs, R3(regs->iir), 0);
+ break;
+
+ case OPCODE_STD:
+ case OPCODE_STDA:
+ ret = emulate_std(regs, R2(regs->iir), 0);
+ break;
+#endif
+
+ case OPCODE_FLDWX:
+ case OPCODE_FLDWS:
+ case OPCODE_FLDWXR:
+ case OPCODE_FLDWSR:
+ ret = emulate_ldw(regs, FR3(regs->iir), 1);
+ break;
+
+ case OPCODE_FLDDX:
+ case OPCODE_FLDDS:
+ ret = emulate_ldd(regs, R3(regs->iir), 1);
+ break;
+
+ case OPCODE_FSTWX:
+ case OPCODE_FSTWS:
+ case OPCODE_FSTWXR:
+ case OPCODE_FSTWSR:
+ ret = emulate_stw(regs, FR3(regs->iir), 1);
+ break;
+
+ case OPCODE_FSTDX:
+ case OPCODE_FSTDS:
+ ret = emulate_std(regs, R3(regs->iir), 1);
+ break;
+
+ case OPCODE_LDCD_I:
+ case OPCODE_LDCW_I:
+ case OPCODE_LDCD_S:
+ case OPCODE_LDCW_S:
+ ret = ERR_NOTHANDLED; /* "undefined", but lets kill them. */
+ break;
+ }
+ switch (regs->iir & OPCODE2_MASK)
+ {
+ case OPCODE_FLDD_L:
+ ret = emulate_ldd(regs,R2(regs->iir),1);
+ break;
+ case OPCODE_FSTD_L:
+ ret = emulate_std(regs, R2(regs->iir),1);
+ break;
+#ifdef CONFIG_64BIT
+ case OPCODE_LDD_L:
+ ret = emulate_ldd(regs, R2(regs->iir),0);
+ break;
+ case OPCODE_STD_L:
+ ret = emulate_std(regs, R2(regs->iir),0);
+ break;
+#endif
+ }
+ switch (regs->iir & OPCODE3_MASK)
+ {
+ case OPCODE_FLDW_L:
+ ret = emulate_ldw(regs, R2(regs->iir), 1);
+ break;
+ case OPCODE_LDW_M:
+ ret = emulate_ldw(regs, R2(regs->iir), 0);
+ break;
+
+ case OPCODE_FSTW_L:
+ ret = emulate_stw(regs, R2(regs->iir),1);
+ break;
+ case OPCODE_STW_M:
+ ret = emulate_stw(regs, R2(regs->iir),0);
+ break;
+ }
+ switch (regs->iir & OPCODE4_MASK)
+ {
+ case OPCODE_LDH_L:
+ ret = emulate_ldh(regs, R2(regs->iir));
+ break;
+ case OPCODE_LDW_L:
+ case OPCODE_LDWM:
+ ret = emulate_ldw(regs, R2(regs->iir),0);
+ break;
+ case OPCODE_STH_L:
+ ret = emulate_sth(regs, R2(regs->iir));
+ break;
+ case OPCODE_STW_L:
+ case OPCODE_STWM:
+ ret = emulate_stw(regs, R2(regs->iir),0);
+ break;
+ }
+
+ if (ret == 0 && modify && R1(regs->iir))
+ regs->gr[R1(regs->iir)] = newbase;
+
+
+ if (ret == ERR_NOTHANDLED)
+ printk(KERN_CRIT "Not-handled unaligned insn 0x%08lx\n", regs->iir);
+
+ DPRINTF("ret = %d\n", ret);
+
+ if (ret)
+ {
+ /*
+ * The unaligned handler failed.
+ * If we were called by __get_user() or __put_user() jump
+ * to it's exception fixup handler instead of crashing.
+ */
+ if (!user_mode(regs) && fixup_exception(regs))
+ return;
+
+ printk(KERN_CRIT "Unaligned handler failed, ret = %d\n", ret);
+ die_if_kernel("Unaligned data reference", regs, 28);
+
+ if (ret == -EFAULT)
+ {
+ force_sig_fault(SIGSEGV, SEGV_MAPERR,
+ (void __user *)regs->ior);
+ }
+ else
+ {
+force_sigbus:
+ /* couldn't handle it ... */
+ force_sig_fault(SIGBUS, BUS_ADRALN,
+ (void __user *)regs->ior);
+ }
+
+ return;
+ }
+
+ /* else we handled it, let life go on. */
+ regs->gr[0]|=PSW_N;
+}
+
+/*
+ * NB: check_unaligned() is only used for PCXS processors right
+ * now, so we only check for PA1.1 encodings at this point.
+ */
+
+int
+check_unaligned(struct pt_regs *regs)
+{
+ unsigned long align_mask;
+
+ /* Get alignment mask */
+
+ align_mask = 0UL;
+ switch (regs->iir & OPCODE1_MASK) {
+
+ case OPCODE_LDH_I:
+ case OPCODE_LDH_S:
+ case OPCODE_STH:
+ align_mask = 1UL;
+ break;
+
+ case OPCODE_LDW_I:
+ case OPCODE_LDWA_I:
+ case OPCODE_LDW_S:
+ case OPCODE_LDWA_S:
+ case OPCODE_STW:
+ case OPCODE_STWA:
+ align_mask = 3UL;
+ break;
+
+ default:
+ switch (regs->iir & OPCODE4_MASK) {
+ case OPCODE_LDH_L:
+ case OPCODE_STH_L:
+ align_mask = 1UL;
+ break;
+ case OPCODE_LDW_L:
+ case OPCODE_LDWM:
+ case OPCODE_STW_L:
+ case OPCODE_STWM:
+ align_mask = 3UL;
+ break;
+ }
+ break;
+ }
+
+ return (int)(regs->ior & align_mask);
+}
+
diff --git a/arch/parisc/kernel/unwind.c b/arch/parisc/kernel/unwind.c
new file mode 100644
index 000000000..27ae40a44
--- /dev/null
+++ b/arch/parisc/kernel/unwind.c
@@ -0,0 +1,491 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Kernel unwinding support
+ *
+ * (c) 2002-2004 Randolph Chung <tausq@debian.org>
+ *
+ * Derived partially from the IA64 implementation. The PA-RISC
+ * Runtime Architecture Document is also a useful reference to
+ * understand what is happening here
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/sort.h>
+#include <linux/sched/task_stack.h>
+
+#include <linux/uaccess.h>
+#include <asm/assembly.h>
+#include <asm/asm-offsets.h>
+#include <asm/ptrace.h>
+
+#include <asm/unwind.h>
+#include <asm/switch_to.h>
+#include <asm/sections.h>
+#include <asm/ftrace.h>
+
+/* #define DEBUG 1 */
+#ifdef DEBUG
+#define dbg(x...) pr_debug(x)
+#else
+#define dbg(x...) do { } while (0)
+#endif
+
+#define KERNEL_START (KERNEL_BINARY_TEXT_START)
+
+extern struct unwind_table_entry __start___unwind[];
+extern struct unwind_table_entry __stop___unwind[];
+
+static DEFINE_SPINLOCK(unwind_lock);
+/*
+ * the kernel unwind block is not dynamically allocated so that
+ * we can call unwind_init as early in the bootup process as
+ * possible (before the slab allocator is initialized)
+ */
+static struct unwind_table kernel_unwind_table __ro_after_init;
+static LIST_HEAD(unwind_tables);
+
+static inline const struct unwind_table_entry *
+find_unwind_entry_in_table(const struct unwind_table *table, unsigned long addr)
+{
+ const struct unwind_table_entry *e = NULL;
+ unsigned long lo, hi, mid;
+
+ lo = 0;
+ hi = table->length - 1;
+
+ while (lo <= hi) {
+ mid = (hi - lo) / 2 + lo;
+ e = &table->table[mid];
+ if (addr < e->region_start)
+ hi = mid - 1;
+ else if (addr > e->region_end)
+ lo = mid + 1;
+ else
+ return e;
+ }
+
+ return NULL;
+}
+
+static const struct unwind_table_entry *
+find_unwind_entry(unsigned long addr)
+{
+ struct unwind_table *table;
+ const struct unwind_table_entry *e = NULL;
+
+ if (addr >= kernel_unwind_table.start &&
+ addr <= kernel_unwind_table.end)
+ e = find_unwind_entry_in_table(&kernel_unwind_table, addr);
+ else {
+ unsigned long flags;
+
+ spin_lock_irqsave(&unwind_lock, flags);
+ list_for_each_entry(table, &unwind_tables, list) {
+ if (addr >= table->start &&
+ addr <= table->end)
+ e = find_unwind_entry_in_table(table, addr);
+ if (e) {
+ /* Move-to-front to exploit common traces */
+ list_move(&table->list, &unwind_tables);
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&unwind_lock, flags);
+ }
+
+ return e;
+}
+
+static void
+unwind_table_init(struct unwind_table *table, const char *name,
+ unsigned long base_addr, unsigned long gp,
+ void *table_start, void *table_end)
+{
+ struct unwind_table_entry *start = table_start;
+ struct unwind_table_entry *end =
+ (struct unwind_table_entry *)table_end - 1;
+
+ table->name = name;
+ table->base_addr = base_addr;
+ table->gp = gp;
+ table->start = base_addr + start->region_start;
+ table->end = base_addr + end->region_end;
+ table->table = (struct unwind_table_entry *)table_start;
+ table->length = end - start + 1;
+ INIT_LIST_HEAD(&table->list);
+
+ for (; start <= end; start++) {
+ if (start < end &&
+ start->region_end > (start+1)->region_start) {
+ pr_warn("Out of order unwind entry! %px and %px\n",
+ start, start+1);
+ }
+
+ start->region_start += base_addr;
+ start->region_end += base_addr;
+ }
+}
+
+static int cmp_unwind_table_entry(const void *a, const void *b)
+{
+ return ((const struct unwind_table_entry *)a)->region_start
+ - ((const struct unwind_table_entry *)b)->region_start;
+}
+
+static void
+unwind_table_sort(struct unwind_table_entry *start,
+ struct unwind_table_entry *finish)
+{
+ sort(start, finish - start, sizeof(struct unwind_table_entry),
+ cmp_unwind_table_entry, NULL);
+}
+
+struct unwind_table *
+unwind_table_add(const char *name, unsigned long base_addr,
+ unsigned long gp,
+ void *start, void *end)
+{
+ struct unwind_table *table;
+ unsigned long flags;
+ struct unwind_table_entry *s = (struct unwind_table_entry *)start;
+ struct unwind_table_entry *e = (struct unwind_table_entry *)end;
+
+ unwind_table_sort(s, e);
+
+ table = kmalloc(sizeof(struct unwind_table), GFP_USER);
+ if (table == NULL)
+ return NULL;
+ unwind_table_init(table, name, base_addr, gp, start, end);
+ spin_lock_irqsave(&unwind_lock, flags);
+ list_add_tail(&table->list, &unwind_tables);
+ spin_unlock_irqrestore(&unwind_lock, flags);
+
+ return table;
+}
+
+void unwind_table_remove(struct unwind_table *table)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&unwind_lock, flags);
+ list_del(&table->list);
+ spin_unlock_irqrestore(&unwind_lock, flags);
+
+ kfree(table);
+}
+
+/* Called from setup_arch to import the kernel unwind info */
+int __init unwind_init(void)
+{
+ long start __maybe_unused, stop __maybe_unused;
+ register unsigned long gp __asm__ ("r27");
+
+ start = (long)&__start___unwind[0];
+ stop = (long)&__stop___unwind[0];
+
+ dbg("unwind_init: start = 0x%lx, end = 0x%lx, entries = %lu\n",
+ start, stop,
+ (stop - start) / sizeof(struct unwind_table_entry));
+
+ unwind_table_init(&kernel_unwind_table, "kernel", KERNEL_START,
+ gp,
+ &__start___unwind[0], &__stop___unwind[0]);
+#if 0
+ {
+ int i;
+ for (i = 0; i < 10; i++)
+ {
+ printk("region 0x%x-0x%x\n",
+ __start___unwind[i].region_start,
+ __start___unwind[i].region_end);
+ }
+ }
+#endif
+ return 0;
+}
+
+static bool pc_is_kernel_fn(unsigned long pc, void *fn)
+{
+ return (unsigned long)dereference_kernel_function_descriptor(fn) == pc;
+}
+
+static int unwind_special(struct unwind_frame_info *info, unsigned long pc, int frame_size)
+{
+ /*
+ * We have to use void * instead of a function pointer, because
+ * function pointers aren't a pointer to the function on 64-bit.
+ * Make them const so the compiler knows they live in .text
+ * Note: We could use dereference_kernel_function_descriptor()
+ * instead but we want to keep it simple here.
+ */
+ extern void * const ret_from_kernel_thread;
+ extern void * const syscall_exit;
+ extern void * const intr_return;
+ extern void * const _switch_to_ret;
+#ifdef CONFIG_IRQSTACKS
+ extern void * const _call_on_stack;
+#endif /* CONFIG_IRQSTACKS */
+ void *ptr;
+
+ ptr = dereference_kernel_function_descriptor(&handle_interruption);
+ if (pc_is_kernel_fn(pc, ptr)) {
+ struct pt_regs *regs = (struct pt_regs *)(info->sp - frame_size - PT_SZ_ALGN);
+ dbg("Unwinding through handle_interruption()\n");
+ info->prev_sp = regs->gr[30];
+ info->prev_ip = regs->iaoq[0];
+ return 1;
+ }
+
+ if (pc_is_kernel_fn(pc, ret_from_kernel_thread) ||
+ pc_is_kernel_fn(pc, syscall_exit)) {
+ info->prev_sp = info->prev_ip = 0;
+ return 1;
+ }
+
+ if (pc_is_kernel_fn(pc, intr_return)) {
+ struct pt_regs *regs;
+
+ dbg("Found intr_return()\n");
+ regs = (struct pt_regs *)(info->sp - PT_SZ_ALGN);
+ info->prev_sp = regs->gr[30];
+ info->prev_ip = regs->iaoq[0];
+ info->rp = regs->gr[2];
+ return 1;
+ }
+
+ if (pc_is_kernel_fn(pc, _switch_to) ||
+ pc_is_kernel_fn(pc, _switch_to_ret)) {
+ info->prev_sp = info->sp - CALLEE_SAVE_FRAME_SIZE;
+ info->prev_ip = *(unsigned long *)(info->prev_sp - RP_OFFSET);
+ return 1;
+ }
+
+#ifdef CONFIG_IRQSTACKS
+ if (pc_is_kernel_fn(pc, _call_on_stack)) {
+ info->prev_sp = *(unsigned long *)(info->sp - FRAME_SIZE - REG_SZ);
+ info->prev_ip = *(unsigned long *)(info->sp - FRAME_SIZE - RP_OFFSET);
+ return 1;
+ }
+#endif
+ return 0;
+}
+
+static void unwind_frame_regs(struct unwind_frame_info *info)
+{
+ const struct unwind_table_entry *e;
+ unsigned long npc;
+ unsigned int insn;
+ long frame_size = 0;
+ int looking_for_rp, rpoffset = 0;
+
+ e = find_unwind_entry(info->ip);
+ if (e == NULL) {
+ unsigned long sp;
+
+ dbg("Cannot find unwind entry for %pS; forced unwinding\n",
+ (void *) info->ip);
+
+ /* Since we are doing the unwinding blind, we don't know if
+ we are adjusting the stack correctly or extracting the rp
+ correctly. The rp is checked to see if it belongs to the
+ kernel text section, if not we assume we don't have a
+ correct stack frame and we continue to unwind the stack.
+ This is not quite correct, and will fail for loadable
+ modules. */
+ sp = info->sp & ~63;
+ do {
+ unsigned long tmp;
+
+ info->prev_sp = sp - 64;
+ info->prev_ip = 0;
+
+ /* Check if stack is inside kernel stack area */
+ if ((info->prev_sp - (unsigned long) task_stack_page(info->t))
+ >= THREAD_SIZE) {
+ info->prev_sp = 0;
+ break;
+ }
+
+ if (copy_from_kernel_nofault(&tmp,
+ (void *)info->prev_sp - RP_OFFSET, sizeof(tmp)))
+ break;
+ info->prev_ip = tmp;
+ sp = info->prev_sp;
+ } while (!kernel_text_address(info->prev_ip));
+
+ info->rp = 0;
+
+ dbg("analyzing func @ %lx with no unwind info, setting "
+ "prev_sp=%lx prev_ip=%lx\n", info->ip,
+ info->prev_sp, info->prev_ip);
+ } else {
+ dbg("e->start = 0x%x, e->end = 0x%x, Save_SP = %d, "
+ "Save_RP = %d, Millicode = %d size = %u\n",
+ e->region_start, e->region_end, e->Save_SP, e->Save_RP,
+ e->Millicode, e->Total_frame_size);
+
+ looking_for_rp = e->Save_RP;
+
+ for (npc = e->region_start;
+ (frame_size < (e->Total_frame_size << 3) ||
+ looking_for_rp) &&
+ npc < info->ip;
+ npc += 4) {
+
+ insn = *(unsigned int *)npc;
+
+ if ((insn & 0xffffc001) == 0x37de0000 ||
+ (insn & 0xffe00001) == 0x6fc00000) {
+ /* ldo X(sp), sp, or stwm X,D(sp) */
+ frame_size += (insn & 0x3fff) >> 1;
+ dbg("analyzing func @ %lx, insn=%08x @ "
+ "%lx, frame_size = %ld\n", info->ip,
+ insn, npc, frame_size);
+ } else if ((insn & 0xffe00009) == 0x73c00008) {
+ /* std,ma X,D(sp) */
+ frame_size += ((insn >> 4) & 0x3ff) << 3;
+ dbg("analyzing func @ %lx, insn=%08x @ "
+ "%lx, frame_size = %ld\n", info->ip,
+ insn, npc, frame_size);
+ } else if (insn == 0x6bc23fd9) {
+ /* stw rp,-20(sp) */
+ rpoffset = 20;
+ looking_for_rp = 0;
+ dbg("analyzing func @ %lx, insn=stw rp,"
+ "-20(sp) @ %lx\n", info->ip, npc);
+ } else if (insn == 0x0fc212c1) {
+ /* std rp,-16(sr0,sp) */
+ rpoffset = 16;
+ looking_for_rp = 0;
+ dbg("analyzing func @ %lx, insn=std rp,"
+ "-16(sp) @ %lx\n", info->ip, npc);
+ }
+ }
+
+ if (frame_size > e->Total_frame_size << 3)
+ frame_size = e->Total_frame_size << 3;
+
+ if (!unwind_special(info, e->region_start, frame_size)) {
+ info->prev_sp = info->sp - frame_size;
+ if (e->Millicode)
+ info->rp = info->r31;
+ else if (rpoffset)
+ info->rp = *(unsigned long *)(info->prev_sp - rpoffset);
+ info->prev_ip = info->rp;
+ info->rp = 0;
+ }
+
+ dbg("analyzing func @ %lx, setting prev_sp=%lx "
+ "prev_ip=%lx npc=%lx\n", info->ip, info->prev_sp,
+ info->prev_ip, npc);
+ }
+}
+
+void unwind_frame_init(struct unwind_frame_info *info, struct task_struct *t,
+ struct pt_regs *regs)
+{
+ memset(info, 0, sizeof(struct unwind_frame_info));
+ info->t = t;
+ info->sp = regs->gr[30];
+ info->ip = regs->iaoq[0];
+ info->rp = regs->gr[2];
+ info->r31 = regs->gr[31];
+
+ dbg("(%d) Start unwind from sp=%08lx ip=%08lx\n",
+ t ? (int)t->pid : -1, info->sp, info->ip);
+}
+
+void unwind_frame_init_from_blocked_task(struct unwind_frame_info *info, struct task_struct *t)
+{
+ struct pt_regs *r = &t->thread.regs;
+ struct pt_regs *r2;
+
+ r2 = kmalloc(sizeof(struct pt_regs), GFP_ATOMIC);
+ if (!r2)
+ return;
+ *r2 = *r;
+ r2->gr[30] = r->ksp;
+ r2->iaoq[0] = r->kpc;
+ unwind_frame_init(info, t, r2);
+ kfree(r2);
+}
+
+#define get_parisc_stackpointer() ({ \
+ unsigned long sp; \
+ __asm__("copy %%r30, %0" : "=r"(sp)); \
+ (sp); \
+})
+
+void unwind_frame_init_task(struct unwind_frame_info *info,
+ struct task_struct *task, struct pt_regs *regs)
+{
+ task = task ? task : current;
+
+ if (task == current) {
+ struct pt_regs r;
+
+ if (!regs) {
+ memset(&r, 0, sizeof(r));
+ r.iaoq[0] = _THIS_IP_;
+ r.gr[2] = _RET_IP_;
+ r.gr[30] = get_parisc_stackpointer();
+ regs = &r;
+ }
+ unwind_frame_init(info, task, regs);
+ } else {
+ unwind_frame_init_from_blocked_task(info, task);
+ }
+}
+
+int unwind_once(struct unwind_frame_info *next_frame)
+{
+ unwind_frame_regs(next_frame);
+
+ if (next_frame->prev_sp == 0 ||
+ next_frame->prev_ip == 0)
+ return -1;
+
+ next_frame->sp = next_frame->prev_sp;
+ next_frame->ip = next_frame->prev_ip;
+ next_frame->prev_sp = 0;
+ next_frame->prev_ip = 0;
+
+ dbg("(%d) Continue unwind to sp=%08lx ip=%08lx\n",
+ next_frame->t ? (int)next_frame->t->pid : -1,
+ next_frame->sp, next_frame->ip);
+
+ return 0;
+}
+
+int unwind_to_user(struct unwind_frame_info *info)
+{
+ int ret;
+
+ do {
+ ret = unwind_once(info);
+ } while (!ret && !(info->ip & 3));
+
+ return ret;
+}
+
+unsigned long return_address(unsigned int level)
+{
+ struct unwind_frame_info info;
+
+ /* initialize unwind info */
+ unwind_frame_init_task(&info, current, NULL);
+
+ /* unwind stack */
+ level += 2;
+ do {
+ if (unwind_once(&info) < 0 || info.ip == 0)
+ return 0;
+ if (!kernel_text_address(info.ip))
+ return 0;
+ } while (info.ip && level--);
+
+ return info.ip;
+}
diff --git a/arch/parisc/kernel/vdso.c b/arch/parisc/kernel/vdso.c
new file mode 100644
index 000000000..c5cbfce7a
--- /dev/null
+++ b/arch/parisc/kernel/vdso.c
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022 Helge Deller <deller@gmx.de>
+ *
+ * based on arch/s390/kernel/vdso.c which is
+ * Copyright IBM Corp. 2008
+ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
+ */
+
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/elf.h>
+#include <linux/timekeeper_internal.h>
+#include <linux/compat.h>
+#include <linux/nsproxy.h>
+#include <linux/time_namespace.h>
+#include <linux/random.h>
+
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/sections.h>
+#include <asm/vdso.h>
+#include <asm/cacheflush.h>
+
+extern char vdso32_start, vdso32_end;
+extern char vdso64_start, vdso64_end;
+
+static int vdso_mremap(const struct vm_special_mapping *sm,
+ struct vm_area_struct *vma)
+{
+ current->mm->context.vdso_base = vma->vm_start;
+ return 0;
+}
+
+#ifdef CONFIG_64BIT
+static struct vm_special_mapping vdso64_mapping = {
+ .name = "[vdso]",
+ .mremap = vdso_mremap,
+};
+#endif
+
+static struct vm_special_mapping vdso32_mapping = {
+ .name = "[vdso]",
+ .mremap = vdso_mremap,
+};
+
+/*
+ * This is called from binfmt_elf, we create the special vma for the
+ * vDSO and insert it into the mm struct tree
+ */
+int arch_setup_additional_pages(struct linux_binprm *bprm,
+ int executable_stack)
+{
+
+ unsigned long vdso_text_start, vdso_text_len, map_base;
+ struct vm_special_mapping *vdso_mapping;
+ struct mm_struct *mm = current->mm;
+ struct vm_area_struct *vma;
+ int rc;
+
+ if (mmap_write_lock_killable(mm))
+ return -EINTR;
+
+#ifdef CONFIG_64BIT
+ if (!is_compat_task()) {
+ vdso_text_len = &vdso64_end - &vdso64_start;
+ vdso_mapping = &vdso64_mapping;
+ } else
+#endif
+ {
+ vdso_text_len = &vdso32_end - &vdso32_start;
+ vdso_mapping = &vdso32_mapping;
+ }
+
+ map_base = mm->mmap_base;
+ if (current->flags & PF_RANDOMIZE)
+ map_base -= get_random_u32_below(0x20) * PAGE_SIZE;
+
+ vdso_text_start = get_unmapped_area(NULL, map_base, vdso_text_len, 0, 0);
+
+ /* VM_MAYWRITE for COW so gdb can set breakpoints */
+ vma = _install_special_mapping(mm, vdso_text_start, vdso_text_len,
+ VM_READ|VM_EXEC|
+ VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
+ vdso_mapping);
+ if (IS_ERR(vma)) {
+ do_munmap(mm, vdso_text_start, PAGE_SIZE, NULL);
+ rc = PTR_ERR(vma);
+ } else {
+ current->mm->context.vdso_base = vdso_text_start;
+ rc = 0;
+ }
+
+ mmap_write_unlock(mm);
+ return rc;
+}
+
+static struct page ** __init vdso_setup_pages(void *start, void *end)
+{
+ int pages = (end - start) >> PAGE_SHIFT;
+ struct page **pagelist;
+ int i;
+
+ pagelist = kcalloc(pages + 1, sizeof(struct page *), GFP_KERNEL);
+ if (!pagelist)
+ panic("%s: Cannot allocate page list for VDSO", __func__);
+ for (i = 0; i < pages; i++)
+ pagelist[i] = virt_to_page(start + i * PAGE_SIZE);
+ return pagelist;
+}
+
+static int __init vdso_init(void)
+{
+#ifdef CONFIG_64BIT
+ vdso64_mapping.pages = vdso_setup_pages(&vdso64_start, &vdso64_end);
+#endif
+ if (IS_ENABLED(CONFIG_COMPAT) || !IS_ENABLED(CONFIG_64BIT))
+ vdso32_mapping.pages = vdso_setup_pages(&vdso32_start, &vdso32_end);
+ return 0;
+}
+arch_initcall(vdso_init);
diff --git a/arch/parisc/kernel/vdso32/Makefile b/arch/parisc/kernel/vdso32/Makefile
new file mode 100644
index 000000000..4459a48d2
--- /dev/null
+++ b/arch/parisc/kernel/vdso32/Makefile
@@ -0,0 +1,53 @@
+# List of files in the vdso, has to be asm only for now
+
+obj-vdso32 = note.o sigtramp.o restart_syscall.o
+
+# Build rules
+
+targets := $(obj-vdso32) vdso32.so
+obj-vdso32 := $(addprefix $(obj)/, $(obj-vdso32))
+
+ccflags-y := -shared -fno-common -fbuiltin -mno-fast-indirect-calls -O2 -mno-long-calls
+# -march=1.1 -mschedule=7100LC
+ccflags-y += -nostdlib -Wl,-soname=linux-vdso32.so.1 \
+ $(call ld-option, -Wl$(comma)--hash-style=sysv)
+asflags-y := -D__VDSO32__ -s
+
+KBUILD_AFLAGS += -DBUILD_VDSO
+KBUILD_CFLAGS += -DBUILD_VDSO -DDISABLE_BRANCH_PROFILING
+
+VDSO_LIBGCC := $(shell $(CROSS32CC) -print-libgcc-file-name)
+
+obj-y += vdso32_wrapper.o
+extra-y += vdso32.lds
+CPPFLAGS_vdso32.lds += -P -C # -U$(ARCH)
+
+$(obj)/vdso32_wrapper.o : $(obj)/vdso32.so FORCE
+
+# Force dependency (incbin is bad)
+# link rule for the .so file, .lds has to be first
+$(obj)/vdso32.so: $(src)/vdso32.lds $(obj-vdso32) $(obj-cvdso32) $(VDSO_LIBGCC) FORCE
+ $(call if_changed,vdso32ld)
+
+# assembly rules for the .S files
+$(obj-vdso32): %.o: %.S FORCE
+ $(call if_changed_dep,vdso32as)
+
+$(obj-cvdso32): %.o: %.c FORCE
+ $(call if_changed_dep,vdso32cc)
+
+# actual build commands
+quiet_cmd_vdso32ld = VDSO32L $@
+ cmd_vdso32ld = $(CROSS32CC) $(c_flags) -Wl,-T $(filter-out FORCE, $^) -o $@
+quiet_cmd_vdso32as = VDSO32A $@
+ cmd_vdso32as = $(CROSS32CC) $(a_flags) -c -o $@ $<
+quiet_cmd_vdso32cc = VDSO32C $@
+ cmd_vdso32cc = $(CROSS32CC) $(c_flags) -c -fPIC -mno-fast-indirect-calls -o $@ $<
+
+# Generate VDSO offsets using helper script
+gen-vdsosym := $(srctree)/$(src)/gen_vdso_offsets.sh
+quiet_cmd_vdsosym = VDSOSYM $@
+ cmd_vdsosym = $(NM) $< | $(gen-vdsosym) | LC_ALL=C sort > $@
+
+include/generated/vdso32-offsets.h: $(obj)/vdso32.so FORCE
+ $(call if_changed,vdsosym)
diff --git a/arch/parisc/kernel/vdso32/gen_vdso_offsets.sh b/arch/parisc/kernel/vdso32/gen_vdso_offsets.sh
new file mode 100755
index 000000000..da39d6cff
--- /dev/null
+++ b/arch/parisc/kernel/vdso32/gen_vdso_offsets.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+
+#
+# Match symbols in the DSO that look like VDSO_*; produce a header file
+# of constant offsets into the shared object.
+#
+# Doing this inside the Makefile will break the $(filter-out) function,
+# causing Kbuild to rebuild the vdso-offsets header file every time.
+#
+# Inspired by arm64 version.
+#
+
+LC_ALL=C
+sed -n 's/\([0-9a-f]*\) . __kernel_\(.*\)/\#define vdso32_offset_\2\t0x\1/p'
diff --git a/arch/parisc/kernel/vdso32/note.S b/arch/parisc/kernel/vdso32/note.S
new file mode 100644
index 000000000..bb350918b
--- /dev/null
+++ b/arch/parisc/kernel/vdso32/note.S
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * This supplies .note.* sections to go into the PT_NOTE inside the vDSO text.
+ * Here we can supply some information useful to userland.
+ */
+
+#include <linux/uts.h>
+#include <linux/version.h>
+
+#define ASM_ELF_NOTE_BEGIN(name, flags, vendor, type) \
+ .section name, flags; \
+ .balign 4; \
+ .long 1f - 0f; /* name length */ \
+ .long 3f - 2f; /* data length */ \
+ .long type; /* note type */ \
+0: .asciz vendor; /* vendor name */ \
+1: .balign 4; \
+2:
+
+#define ASM_ELF_NOTE_END \
+3: .balign 4; /* pad out section */ \
+ .previous
+
+ ASM_ELF_NOTE_BEGIN(".note.kernel-version", "a", UTS_SYSNAME, 0)
+ .long LINUX_VERSION_CODE
+ ASM_ELF_NOTE_END
diff --git a/arch/parisc/kernel/vdso32/restart_syscall.S b/arch/parisc/kernel/vdso32/restart_syscall.S
new file mode 100644
index 000000000..7e82008d7
--- /dev/null
+++ b/arch/parisc/kernel/vdso32/restart_syscall.S
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Syscall restart trampoline for 32 and 64 bits processes.
+ *
+ * Copyright (C) 2018-2022 Helge Deller <deller@gmx.de>
+ * Copyright (C) 2022 John David Anglin <dave.anglin@bell.net>
+ */
+
+#include <asm/unistd.h>
+#include <asm/vdso.h>
+
+#include <linux/linkage.h>
+
+ .text
+
+ENTRY_CFI(__kernel_restart_syscall)
+ /*
+ * Setup a trampoline to restart the syscall
+ * with __NR_restart_syscall
+ */
+
+ /* load return pointer */
+#if defined(__VDSO64__)
+ ldd 0(%sp), %r31
+#elif defined(__VDSO32__)
+ ldw 0(%sp), %r31
+#endif
+
+ be 0x100(%sr2, %r0)
+ ldi __NR_restart_syscall, %r20
+
+ENDPROC_CFI(__kernel_restart_syscall)
diff --git a/arch/parisc/kernel/vdso32/sigtramp.S b/arch/parisc/kernel/vdso32/sigtramp.S
new file mode 100644
index 000000000..192da7077
--- /dev/null
+++ b/arch/parisc/kernel/vdso32/sigtramp.S
@@ -0,0 +1,195 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Signal trampolines for 32 bit processes.
+ *
+ * Copyright (C) 2006 Randolph Chung <tausq@debian.org>
+ * Copyright (C) 2018-2022 Helge Deller <deller@gmx.de>
+ * Copyright (C) 2022 John David Anglin <dave.anglin@bell.net>
+ */
+#include <asm/unistd.h>
+#include <linux/linkage.h>
+#include <generated/asm-offsets.h>
+
+ .text
+
+/* Gdb expects the trampoline is on the stack and the pc is offset from
+ a 64-byte boundary by 0, 4 or 5 instructions. Since the vdso trampoline
+ is not on the stack, we need a new variant with different offsets and
+ data to tell gdb where to find the signal context on the stack.
+
+ Here we put the offset to the context data at the start of the trampoline
+ region and offset the first trampoline by 2 instructions. Please do
+ not change the trampoline as the code in gdb depends on the following
+ instruction sequence exactly.
+ */
+ .align 64
+ .word SIGFRAME_CONTEXT_REGS32
+
+/* The nop here is a hack. The dwarf2 unwind routines subtract 1 from
+ the return address to get an address in the middle of the presumed
+ call instruction. Since we don't have a call here, we artifically
+ extend the range covered by the unwind info by adding a nop before
+ the real start.
+ */
+ nop
+
+ .globl __kernel_sigtramp_rt
+ .type __kernel_sigtramp_rt, @function
+__kernel_sigtramp_rt:
+ .proc
+ .callinfo FRAME=ASM_SIGFRAME_SIZE32,CALLS,SAVE_RP
+ .entry
+
+.Lsigrt_start = . - 4
+0: ldi 0, %r25 /* (in_syscall=0) */
+ ldi __NR_rt_sigreturn, %r20
+ ble 0x100(%sr2, %r0)
+ nop
+
+1: ldi 1, %r25 /* (in_syscall=1) */
+ ldi __NR_rt_sigreturn, %r20
+ ble 0x100(%sr2, %r0)
+ nop
+.Lsigrt_end:
+ .exit
+ .procend
+ .size __kernel_sigtramp_rt,.-__kernel_sigtramp_rt
+
+
+ .section .eh_frame,"a",@progbits
+
+/* This is where the mcontext_t struct can be found on the stack. */
+#define PTREGS SIGFRAME_CONTEXT_REGS32 /* 32-bit process offset is -672 */
+
+/* Register REGNO can be found at offset OFS of the mcontext_t structure. */
+ .macro rsave regno,ofs
+ .byte 0x05 /* DW_CFA_offset_extended */
+ .uleb128 \regno; /* regno */
+ .uleb128 \ofs /* factored offset */
+ .endm
+
+.Lcie:
+ .long .Lcie_end - .Lcie_start
+.Lcie_start:
+ .long 0 /* CIE ID */
+ .byte 1 /* Version number */
+ .stringz "zRS" /* NUL-terminated augmentation string */
+ .uleb128 4 /* Code alignment factor */
+ .sleb128 4 /* Data alignment factor */
+ .byte 89 /* Return address register column, iaoq[0] */
+ .uleb128 1 /* Augmentation value length */
+ .byte 0x1b /* DW_EH_PE_pcrel | DW_EH_PE_sdata4. */
+ .byte 0x0f /* DW_CFA_def_cfa_expresion */
+ .uleb128 9f - 1f /* length */
+1:
+ .byte 0x8e /* DW_OP_breg30 */
+ .sleb128 PTREGS
+9:
+ .balign 4
+.Lcie_end:
+
+ .long .Lfde0_end - .Lfde0_start
+.Lfde0_start:
+ .long .Lfde0_start - .Lcie /* CIE pointer. */
+ .long .Lsigrt_start - . /* PC start, length */
+ .long .Lsigrt_end - .Lsigrt_start
+ .uleb128 0 /* Augmentation */
+
+ /* General registers */
+ rsave 1, 2
+ rsave 2, 3
+ rsave 3, 4
+ rsave 4, 5
+ rsave 5, 6
+ rsave 6, 7
+ rsave 7, 8
+ rsave 8, 9
+ rsave 9, 10
+ rsave 10, 11
+ rsave 11, 12
+ rsave 12, 13
+ rsave 13, 14
+ rsave 14, 15
+ rsave 15, 16
+ rsave 16, 17
+ rsave 17, 18
+ rsave 18, 19
+ rsave 19, 20
+ rsave 20, 21
+ rsave 21, 22
+ rsave 22, 23
+ rsave 23, 24
+ rsave 24, 25
+ rsave 25, 26
+ rsave 26, 27
+ rsave 27, 28
+ rsave 28, 29
+ rsave 29, 30
+ rsave 30, 31
+ rsave 31, 32
+
+ /* Floating-point registers */
+ rsave 32, 42
+ rsave 33, 43
+ rsave 34, 44
+ rsave 35, 45
+ rsave 36, 46
+ rsave 37, 47
+ rsave 38, 48
+ rsave 39, 49
+ rsave 40, 50
+ rsave 41, 51
+ rsave 42, 52
+ rsave 43, 53
+ rsave 44, 54
+ rsave 45, 55
+ rsave 46, 56
+ rsave 47, 57
+ rsave 48, 58
+ rsave 49, 59
+ rsave 50, 60
+ rsave 51, 61
+ rsave 52, 62
+ rsave 53, 63
+ rsave 54, 64
+ rsave 55, 65
+ rsave 56, 66
+ rsave 57, 67
+ rsave 58, 68
+ rsave 59, 69
+ rsave 60, 70
+ rsave 61, 71
+ rsave 62, 72
+ rsave 63, 73
+ rsave 64, 74
+ rsave 65, 75
+ rsave 66, 76
+ rsave 67, 77
+ rsave 68, 78
+ rsave 69, 79
+ rsave 70, 80
+ rsave 71, 81
+ rsave 72, 82
+ rsave 73, 83
+ rsave 74, 84
+ rsave 75, 85
+ rsave 76, 86
+ rsave 77, 87
+ rsave 78, 88
+ rsave 79, 89
+ rsave 80, 90
+ rsave 81, 91
+ rsave 82, 92
+ rsave 83, 93
+ rsave 84, 94
+ rsave 85, 95
+ rsave 86, 96
+ rsave 87, 97
+
+ /* SAR register */
+ rsave 88, 102
+
+ /* iaoq[0] return address register */
+ rsave 89, 100
+ .balign 4
+.Lfde0_end:
diff --git a/arch/parisc/kernel/vdso32/vdso32.lds.S b/arch/parisc/kernel/vdso32/vdso32.lds.S
new file mode 100644
index 000000000..d4aff3af5
--- /dev/null
+++ b/arch/parisc/kernel/vdso32/vdso32.lds.S
@@ -0,0 +1,111 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * This is the infamous ld script for the 32 bits vdso library
+ */
+#include <asm/vdso.h>
+#include <asm/page.h>
+
+/* Default link addresses for the vDSOs */
+OUTPUT_FORMAT("elf32-hppa-linux")
+OUTPUT_ARCH(hppa)
+ENTRY(_start)
+
+SECTIONS
+{
+ . = VDSO_LBASE + SIZEOF_HEADERS;
+ .hash : { *(.hash) } :text
+ .gnu.hash : { *(.gnu.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .gnu.version : { *(.gnu.version) }
+ .gnu.version_d : { *(.gnu.version_d) }
+ .gnu.version_r : { *(.gnu.version_r) }
+
+ .note : { *(.note.*) } :text :note
+
+ . = ALIGN (16);
+ .text :
+ {
+ *(.text .stub .text.* .gnu.linkonce.t.*)
+ }
+ PROVIDE (__etext = .);
+ PROVIDE (_etext = .);
+ PROVIDE (etext = .);
+
+ /* Other stuff is appended to the text segment: */
+ .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+ .rodata1 : { *(.rodata1) }
+ .rodata2 : { *(.data.rel.ro) }
+
+ .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr
+ .eh_frame : { KEEP (*(.eh_frame)) } :text
+ .gcc_except_table : { *(.gcc_except_table) }
+ .fixup : { *(.fixup) }
+
+ .dynamic : { *(.dynamic) } :text :dynamic
+ .plt : { *(.plt) }
+ .got : { *(.got) }
+
+ _end = .;
+ __end = .;
+ PROVIDE (end = .);
+
+
+ /* Stabs debugging sections are here too
+ */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ .stab.excl 0 : { *(.stab.excl) }
+ .stab.exclstr 0 : { *(.stab.exclstr) }
+ .stab.index 0 : { *(.stab.index) }
+ .stab.indexstr 0 : { *(.stab.indexstr) }
+ .comment 0 : { *(.comment) }
+ .debug 0 : { *(.debug) }
+ .line 0 : { *(.line) }
+
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+
+ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
+ .debug_abbrev 0 : { *(.debug_abbrev) }
+ .debug_line 0 : { *(.debug_line) }
+ .debug_frame 0 : { *(.debug_frame) }
+ .debug_str 0 : { *(.debug_str) }
+ .debug_loc 0 : { *(.debug_loc) }
+ .debug_macinfo 0 : { *(.debug_macinfo) }
+
+ .debug_weaknames 0 : { *(.debug_weaknames) }
+ .debug_funcnames 0 : { *(.debug_funcnames) }
+ .debug_typenames 0 : { *(.debug_typenames) }
+ .debug_varnames 0 : { *(.debug_varnames) }
+
+ /DISCARD/ : { *(.note.GNU-stack) }
+ /DISCARD/ : { *(.data .data.* .gnu.linkonce.d.* .sdata*) }
+ /DISCARD/ : { *(.bss .sbss .dynbss .dynsbss) }
+}
+
+
+PHDRS
+{
+ text PT_LOAD FILEHDR PHDRS FLAGS(5); /* PF_R|PF_X */
+ note PT_NOTE FLAGS(4); /* PF_R */
+ dynamic PT_DYNAMIC FLAGS(4); /* PF_R */
+ eh_frame_hdr PT_GNU_EH_FRAME;
+}
+
+
+/*
+ * This controls what symbols we export from the DSO.
+ */
+VERSION
+{
+ VDSO_VERSION_STRING {
+ global:
+ __kernel_sigtramp_rt32;
+ __kernel_restart_syscall32;
+ local: *;
+ };
+}
diff --git a/arch/parisc/kernel/vdso32/vdso32_wrapper.S b/arch/parisc/kernel/vdso32/vdso32_wrapper.S
new file mode 100644
index 000000000..5ac06093e
--- /dev/null
+++ b/arch/parisc/kernel/vdso32/vdso32_wrapper.S
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#include <linux/linkage.h>
+#include <asm/page.h>
+
+ __PAGE_ALIGNED_DATA
+
+ .globl vdso32_start, vdso32_end
+ .balign PAGE_SIZE
+vdso32_start:
+ .incbin "arch/parisc/kernel/vdso32/vdso32.so"
+ .balign PAGE_SIZE
+vdso32_end:
+
+ .previous
diff --git a/arch/parisc/kernel/vdso64/Makefile b/arch/parisc/kernel/vdso64/Makefile
new file mode 100644
index 000000000..f3d604579
--- /dev/null
+++ b/arch/parisc/kernel/vdso64/Makefile
@@ -0,0 +1,48 @@
+# List of files in the vdso, has to be asm only for now
+
+obj-vdso64 = note.o sigtramp.o restart_syscall.o
+
+# Build rules
+
+targets := $(obj-vdso64) vdso64.so
+obj-vdso64 := $(addprefix $(obj)/, $(obj-vdso64))
+
+
+ccflags-y := -shared -fno-common -fno-builtin
+ccflags-y += -nostdlib -Wl,-soname=linux-vdso64.so.1 \
+ $(call ld-option, -Wl$(comma)--hash-style=sysv)
+asflags-y := -D__VDSO64__ -s
+
+KBUILD_AFLAGS += -DBUILD_VDSO
+KBUILD_CFLAGS += -DBUILD_VDSO -DDISABLE_BRANCH_PROFILING
+
+VDSO_LIBGCC := $(shell $(CC) -print-libgcc-file-name)
+
+obj-y += vdso64_wrapper.o
+extra-y += vdso64.lds
+CPPFLAGS_vdso64.lds += -P -C -U$(ARCH)
+
+$(obj)/vdso64_wrapper.o : $(obj)/vdso64.so FORCE
+
+# Force dependency (incbin is bad)
+# link rule for the .so file, .lds has to be first
+$(obj)/vdso64.so: $(src)/vdso64.lds $(obj-vdso64) $(VDSO_LIBGCC) FORCE
+ $(call if_changed,vdso64ld)
+
+# assembly rules for the .S files
+$(obj-vdso64): %.o: %.S FORCE
+ $(call if_changed_dep,vdso64as)
+
+# actual build commands
+quiet_cmd_vdso64ld = VDSO64L $@
+ cmd_vdso64ld = $(CC) $(c_flags) -Wl,-T $(filter-out FORCE, $^) -o $@
+quiet_cmd_vdso64as = VDSO64A $@
+ cmd_vdso64as = $(CC) $(a_flags) -c -o $@ $<
+
+# Generate VDSO offsets using helper script
+gen-vdsosym := $(srctree)/$(src)/gen_vdso_offsets.sh
+quiet_cmd_vdsosym = VDSOSYM $@
+ cmd_vdsosym = $(NM) $< | $(gen-vdsosym) | LC_ALL=C sort > $@
+
+include/generated/vdso64-offsets.h: $(obj)/vdso64.so FORCE
+ $(call if_changed,vdsosym)
diff --git a/arch/parisc/kernel/vdso64/gen_vdso_offsets.sh b/arch/parisc/kernel/vdso64/gen_vdso_offsets.sh
new file mode 100755
index 000000000..37f05cb38
--- /dev/null
+++ b/arch/parisc/kernel/vdso64/gen_vdso_offsets.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+
+#
+# Match symbols in the DSO that look like VDSO_*; produce a header file
+# of constant offsets into the shared object.
+#
+# Doing this inside the Makefile will break the $(filter-out) function,
+# causing Kbuild to rebuild the vdso-offsets header file every time.
+#
+# Inspired by arm64 version.
+#
+
+LC_ALL=C
+sed -n 's/\([0-9a-f]*\) . __kernel_\(.*\)/\#define vdso64_offset_\2\t0x\1/p'
diff --git a/arch/parisc/kernel/vdso64/note.S b/arch/parisc/kernel/vdso64/note.S
new file mode 100644
index 000000000..bd1fa2359
--- /dev/null
+++ b/arch/parisc/kernel/vdso64/note.S
@@ -0,0 +1,2 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#include "../vdso32/note.S"
diff --git a/arch/parisc/kernel/vdso64/restart_syscall.S b/arch/parisc/kernel/vdso64/restart_syscall.S
new file mode 100644
index 000000000..83004451f
--- /dev/null
+++ b/arch/parisc/kernel/vdso64/restart_syscall.S
@@ -0,0 +1,3 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#include "../vdso32/restart_syscall.S"
diff --git a/arch/parisc/kernel/vdso64/sigtramp.S b/arch/parisc/kernel/vdso64/sigtramp.S
new file mode 100644
index 000000000..66a6d2b24
--- /dev/null
+++ b/arch/parisc/kernel/vdso64/sigtramp.S
@@ -0,0 +1,166 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Signal trampolines for 64 bit processes.
+ *
+ * Copyright (C) 2006 Randolph Chung <tausq@debian.org>
+ * Copyright (C) 2018-2022 Helge Deller <deller@gmx.de>
+ * Copyright (C) 2022 John David Anglin <dave.anglin@bell.net>
+ */
+#include <asm/unistd.h>
+#include <linux/linkage.h>
+#include <generated/asm-offsets.h>
+
+ .text
+
+/* Gdb expects the trampoline is on the stack and the pc is offset from
+ a 64-byte boundary by 0, 4 or 5 instructions. Since the vdso trampoline
+ is not on the stack, we need a new variant with different offsets and
+ data to tell gdb where to find the signal context on the stack.
+
+ Here we put the offset to the context data at the start of the trampoline
+ region and offset the first trampoline by 2 instructions. Please do
+ not change the trampoline as the code in gdb depends on the following
+ instruction sequence exactly.
+ */
+ .align 64
+ .word SIGFRAME_CONTEXT_REGS
+
+/* The nop here is a hack. The dwarf2 unwind routines subtract 1 from
+ the return address to get an address in the middle of the presumed
+ call instruction. Since we don't have a call here, we artifically
+ extend the range covered by the unwind info by adding a nop before
+ the real start.
+ */
+ nop
+
+ .globl __kernel_sigtramp_rt
+ .type __kernel_sigtramp_rt, @function
+__kernel_sigtramp_rt:
+ .proc
+ .callinfo FRAME=ASM_SIGFRAME_SIZE,CALLS,SAVE_RP
+ .entry
+
+.Lsigrt_start = . - 4
+0: ldi 0, %r25 /* (in_syscall=0) */
+ ldi __NR_rt_sigreturn, %r20
+ ble 0x100(%sr2, %r0)
+ nop
+
+1: ldi 1, %r25 /* (in_syscall=1) */
+ ldi __NR_rt_sigreturn, %r20
+ ble 0x100(%sr2, %r0)
+ nop
+.Lsigrt_end:
+ .exit
+ .procend
+ .size __kernel_sigtramp_rt,.-__kernel_sigtramp_rt
+
+ .section .eh_frame,"a",@progbits
+
+/* This is where the mcontext_t struct can be found on the stack. */
+#define PTREGS SIGFRAME_CONTEXT_REGS /* 64-bit process offset is -720 */
+
+/* Register REGNO can be found at offset OFS of the mcontext_t structure. */
+ .macro rsave regno,ofs
+ .byte 0x05 /* DW_CFA_offset_extended */
+ .uleb128 \regno; /* regno */
+ .uleb128 \ofs /* factored offset */
+ .endm
+
+.Lcie:
+ .long .Lcie_end - .Lcie_start
+.Lcie_start:
+ .long 0 /* CIE ID */
+ .byte 1 /* Version number */
+ .stringz "zRS" /* NUL-terminated augmentation string */
+ .uleb128 4 /* Code alignment factor */
+ .sleb128 8 /* Data alignment factor */
+ .byte 61 /* Return address register column, iaoq[0] */
+ .uleb128 1 /* Augmentation value length */
+ .byte 0x1b /* DW_EH_PE_pcrel | DW_EH_PE_sdata4. */
+ .byte 0x0f /* DW_CFA_def_cfa_expresion */
+ .uleb128 9f - 1f /* length */
+1:
+ .byte 0x8e /* DW_OP_breg30 */
+ .sleb128 PTREGS
+9:
+ .balign 8
+.Lcie_end:
+
+ .long .Lfde0_end - .Lfde0_start
+.Lfde0_start:
+ .long .Lfde0_start - .Lcie /* CIE pointer. */
+ .long .Lsigrt_start - . /* PC start, length */
+ .long .Lsigrt_end - .Lsigrt_start
+ .uleb128 0 /* Augmentation */
+
+ /* General registers */
+ rsave 1, 2
+ rsave 2, 3
+ rsave 3, 4
+ rsave 4, 5
+ rsave 5, 6
+ rsave 6, 7
+ rsave 7, 8
+ rsave 8, 9
+ rsave 9, 10
+ rsave 10, 11
+ rsave 11, 12
+ rsave 12, 13
+ rsave 13, 14
+ rsave 14, 15
+ rsave 15, 16
+ rsave 16, 17
+ rsave 17, 18
+ rsave 18, 19
+ rsave 19, 20
+ rsave 20, 21
+ rsave 21, 22
+ rsave 22, 23
+ rsave 23, 24
+ rsave 24, 25
+ rsave 25, 26
+ rsave 26, 27
+ rsave 27, 28
+ rsave 28, 29
+ rsave 29, 30
+ rsave 30, 31
+ rsave 31, 32
+
+ /* Floating-point registers */
+ rsave 32, 36
+ rsave 33, 37
+ rsave 34, 38
+ rsave 35, 39
+ rsave 36, 40
+ rsave 37, 41
+ rsave 38, 42
+ rsave 39, 43
+ rsave 40, 44
+ rsave 41, 45
+ rsave 42, 46
+ rsave 43, 47
+ rsave 44, 48
+ rsave 45, 49
+ rsave 46, 50
+ rsave 47, 51
+ rsave 48, 52
+ rsave 49, 53
+ rsave 50, 54
+ rsave 51, 55
+ rsave 52, 56
+ rsave 53, 57
+ rsave 54, 58
+ rsave 55, 59
+ rsave 56, 60
+ rsave 57, 61
+ rsave 58, 62
+ rsave 59, 63
+
+ /* SAR register */
+ rsave 60, 67
+
+ /* iaoq[0] return address register */
+ rsave 61, 65
+ .balign 8
+.Lfde0_end:
diff --git a/arch/parisc/kernel/vdso64/vdso64.lds.S b/arch/parisc/kernel/vdso64/vdso64.lds.S
new file mode 100644
index 000000000..de1fb4b19
--- /dev/null
+++ b/arch/parisc/kernel/vdso64/vdso64.lds.S
@@ -0,0 +1,109 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * This is the infamous ld script for the 64 bits vdso library
+ */
+#include <asm/vdso.h>
+
+/* Default link addresses for the vDSOs */
+OUTPUT_FORMAT("elf64-hppa-linux")
+OUTPUT_ARCH(hppa:hppa2.0w)
+ENTRY(_start)
+
+SECTIONS
+{
+ . = VDSO_LBASE + SIZEOF_HEADERS;
+ .hash : { *(.hash) } :text
+ .gnu.hash : { *(.gnu.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .gnu.version : { *(.gnu.version) }
+ .gnu.version_d : { *(.gnu.version_d) }
+ .gnu.version_r : { *(.gnu.version_r) }
+
+ .note : { *(.note.*) } :text :note
+
+ . = ALIGN (16);
+ .text :
+ {
+ *(.text .stub .text.* .gnu.linkonce.t.*)
+ }
+ PROVIDE (__etext = .);
+ PROVIDE (_etext = .);
+ PROVIDE (etext = .);
+
+ /* Other stuff is appended to the text segment: */
+ .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+ .rodata1 : { *(.rodata1) }
+
+ .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr
+ .eh_frame : { KEEP (*(.eh_frame)) } :text
+ .gcc_except_table : { *(.gcc_except_table) }
+ .fixup : { *(.fixup) }
+
+ .dynamic : { *(.dynamic) } :text :dynamic
+ .plt : { *(.plt) }
+ .got : { *(.got) }
+
+ _end = .;
+ __end = .;
+ PROVIDE (end = .);
+
+
+ /* Stabs debugging sections are here too
+ */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ .stab.excl 0 : { *(.stab.excl) }
+ .stab.exclstr 0 : { *(.stab.exclstr) }
+ .stab.index 0 : { *(.stab.index) }
+ .stab.indexstr 0 : { *(.stab.indexstr) }
+ .comment 0 : { *(.comment) }
+ .debug 0 : { *(.debug) }
+ .line 0 : { *(.line) }
+
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+
+ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
+ .debug_abbrev 0 : { *(.debug_abbrev) }
+ .debug_line 0 : { *(.debug_line) }
+ .debug_frame 0 : { *(.debug_frame) }
+ .debug_str 0 : { *(.debug_str) }
+ .debug_loc 0 : { *(.debug_loc) }
+ .debug_macinfo 0 : { *(.debug_macinfo) }
+
+ .debug_weaknames 0 : { *(.debug_weaknames) }
+ .debug_funcnames 0 : { *(.debug_funcnames) }
+ .debug_typenames 0 : { *(.debug_typenames) }
+ .debug_varnames 0 : { *(.debug_varnames) }
+
+ /DISCARD/ : { *(.note.GNU-stack) }
+ /DISCARD/ : { *(.data .data.* .gnu.linkonce.d.* .sdata*) }
+ /DISCARD/ : { *(.bss .sbss .dynbss .dynsbss) }
+}
+
+
+PHDRS
+{
+ text PT_LOAD FILEHDR PHDRS FLAGS(5); /* PF_R|PF_X */
+ note PT_NOTE FLAGS(4); /* PF_R */
+ dynamic PT_DYNAMIC FLAGS(4); /* PF_R */
+ eh_frame_hdr PT_GNU_EH_FRAME;
+}
+
+
+/*
+ * This controls what symbols we export from the DSO.
+ */
+VERSION
+{
+ VDSO_VERSION_STRING {
+ global:
+ __kernel_sigtramp_rt64;
+ __kernel_restart_syscall64;
+ local: *;
+ };
+}
diff --git a/arch/parisc/kernel/vdso64/vdso64_wrapper.S b/arch/parisc/kernel/vdso64/vdso64_wrapper.S
new file mode 100644
index 000000000..66f929482
--- /dev/null
+++ b/arch/parisc/kernel/vdso64/vdso64_wrapper.S
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#include <linux/linkage.h>
+#include <asm/page.h>
+
+ __PAGE_ALIGNED_DATA
+
+ .globl vdso64_start, vdso64_end
+ .balign PAGE_SIZE
+vdso64_start:
+ .incbin "arch/parisc/kernel/vdso64/vdso64.so"
+ .balign PAGE_SIZE
+vdso64_end:
+
+ .previous
diff --git a/arch/parisc/kernel/vmlinux.lds.S b/arch/parisc/kernel/vmlinux.lds.S
new file mode 100644
index 000000000..548051b0b
--- /dev/null
+++ b/arch/parisc/kernel/vmlinux.lds.S
@@ -0,0 +1,186 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Kernel link layout for various "sections"
+ *
+ * Copyright (C) 1999-2003 Matthew Wilcox <willy at parisc-linux.org>
+ * Copyright (C) 2000-2003 Paul Bame <bame at parisc-linux.org>
+ * Copyright (C) 2000 John Marvin <jsm at parisc-linux.org>
+ * Copyright (C) 2000 Michael Ang <mang with subcarrier.org>
+ * Copyright (C) 2002 Randolph Chung <tausq with parisc-linux.org>
+ * Copyright (C) 2003 James Bottomley <jejb with parisc-linux.org>
+ * Copyright (C) 2006-2013 Helge Deller <deller@gmx.de>
+ */
+
+/*
+ * Put page table entries (swapper_pg_dir) as the first thing in .bss. This
+ * will ensure that it has .bss alignment (PAGE_SIZE).
+ */
+#define BSS_FIRST_SECTIONS *(.data..vm0.pmd) \
+ *(.data..vm0.pgd) \
+ *(.data..vm0.pte)
+
+#define CC_USING_PATCHABLE_FUNCTION_ENTRY
+#define RO_EXCEPTION_TABLE_ALIGN 8
+
+#include <asm-generic/vmlinux.lds.h>
+
+/* needed for the processor specific cache alignment size */
+#include <asm/cache.h>
+#include <asm/page.h>
+#include <asm/asm-offsets.h>
+#include <asm/thread_info.h>
+
+/* ld script to make hppa Linux kernel */
+#ifndef CONFIG_64BIT
+OUTPUT_FORMAT("elf32-hppa-linux")
+OUTPUT_ARCH(hppa)
+#else
+OUTPUT_FORMAT("elf64-hppa-linux")
+OUTPUT_ARCH(hppa:hppa2.0w)
+#endif
+
+#define EXIT_TEXT_SECTIONS() .exit.text : { EXIT_TEXT }
+#if !defined(CONFIG_64BIT) || defined(CONFIG_MLONGCALLS)
+#define MLONGCALL_KEEP(x)
+#define MLONGCALL_DISCARD(x) x
+#else
+#define MLONGCALL_KEEP(x) x
+#define MLONGCALL_DISCARD(x)
+#endif
+
+ENTRY(parisc_kernel_start)
+#ifndef CONFIG_64BIT
+jiffies = jiffies_64 + 4;
+#else
+jiffies = jiffies_64;
+#endif
+SECTIONS
+{
+ . = KERNEL_BINARY_TEXT_START;
+
+ __init_begin = .;
+ HEAD_TEXT_SECTION
+ MLONGCALL_DISCARD(INIT_TEXT_SECTION(8))
+
+ . = ALIGN(PAGE_SIZE);
+ INIT_DATA_SECTION(PAGE_SIZE)
+ MLONGCALL_DISCARD(EXIT_TEXT_SECTIONS())
+ .exit.data :
+ {
+ EXIT_DATA
+ }
+ PERCPU_SECTION(8)
+ . = ALIGN(4);
+ .altinstructions : {
+ __alt_instructions = .;
+ *(.altinstructions)
+ __alt_instructions_end = .;
+ }
+ . = ALIGN(HUGEPAGE_SIZE);
+ __init_end = .;
+ /* freed after init ends here */
+
+ _text = .; /* Text and read-only data */
+ _stext = .;
+ MLONGCALL_KEEP(INIT_TEXT_SECTION(8))
+ .text ALIGN(PAGE_SIZE) : {
+ TEXT_TEXT
+ LOCK_TEXT
+ SCHED_TEXT
+ KPROBES_TEXT
+ IRQENTRY_TEXT
+ SOFTIRQENTRY_TEXT
+ *(.text.do_softirq)
+ *(.text.sys_exit)
+ *(.text.do_sigaltstack)
+ *(.text.do_fork)
+ *(.text.div)
+ *($$*) /* millicode routines */
+ *(.text.*)
+ *(.fixup)
+ *(.lock.text) /* out-of-line lock text */
+ *(.gnu.warning)
+ }
+ MLONGCALL_KEEP(EXIT_TEXT_SECTIONS())
+ . = ALIGN(PAGE_SIZE);
+ _etext = .;
+ /* End of text section */
+
+ /* Start of data section */
+ _sdata = .;
+
+ /* Architecturally we need to keep __gp below 0x1000000 and thus
+ * in front of RO_DATA() which stores lots of tracepoint
+ * and ftrace symbols. */
+#ifdef CONFIG_64BIT
+ . = ALIGN(16);
+ /* Linkage tables */
+ .opd : {
+ __start_opd = .;
+ *(.opd)
+ __end_opd = .;
+ } PROVIDE (__gp = .);
+ .plt : {
+ *(.plt)
+ }
+ .dlt : {
+ *(.dlt)
+ }
+#endif
+
+ RO_DATA(8)
+
+ /* unwind info */
+ . = ALIGN(4);
+ .PARISC.unwind : {
+ __start___unwind = .;
+ *(.PARISC.unwind)
+ __stop___unwind = .;
+ }
+
+ /* writeable */
+ /* Make sure this is page aligned so
+ * that we can properly leave these
+ * as writable
+ */
+ . = ALIGN(HUGEPAGE_SIZE);
+ data_start = .;
+
+ /* Data */
+ RW_DATA(L1_CACHE_BYTES, PAGE_SIZE, PAGE_SIZE)
+
+ /* PA-RISC locks requires 16-byte alignment */
+ . = ALIGN(16);
+ .data..lock_aligned : {
+ *(.data..lock_aligned)
+ }
+
+ /* End of data section */
+ . = ALIGN(PAGE_SIZE);
+ _edata = .;
+
+ /* BSS */
+ BSS_SECTION(PAGE_SIZE, PAGE_SIZE, PAGE_SIZE)
+
+ . = ALIGN(HUGEPAGE_SIZE);
+ _end = . ;
+
+ STABS_DEBUG
+ ELF_DETAILS
+ .note 0 : { *(.note) }
+
+ /* Sections to be discarded */
+ DISCARDS
+ /DISCARD/ : {
+#ifdef CONFIG_64BIT
+ /* temporary hack until binutils is fixed to not emit these
+ * for static binaries
+ */
+ *(.interp)
+ *(.dynsym)
+ *(.dynstr)
+ *(.dynamic)
+ *(.hash)
+ *(.gnu.hash)
+#endif
+ }
+}
diff --git a/arch/parisc/lib/Makefile b/arch/parisc/lib/Makefile
new file mode 100644
index 000000000..7b197667f
--- /dev/null
+++ b/arch/parisc/lib/Makefile
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Makefile for parisc-specific library files
+#
+
+lib-y := lusercopy.o bitops.o checksum.o io.o memset.o memcpy.o \
+ ucmpdi2.o delay.o
+
+obj-y := iomap.o
diff --git a/arch/parisc/lib/bitops.c b/arch/parisc/lib/bitops.c
new file mode 100644
index 000000000..36a314199
--- /dev/null
+++ b/arch/parisc/lib/bitops.c
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * bitops.c: atomic operations which got too long to be inlined all over
+ * the place.
+ *
+ * Copyright 1999 Philipp Rumpf (prumpf@tux.org)
+ * Copyright 2000 Grant Grundler (grundler@cup.hp.com)
+ */
+
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/atomic.h>
+
+#ifdef CONFIG_SMP
+arch_spinlock_t __atomic_hash[ATOMIC_HASH_SIZE] __lock_aligned = {
+ [0 ... (ATOMIC_HASH_SIZE-1)] = __ARCH_SPIN_LOCK_UNLOCKED
+};
+#endif
+
+#ifdef CONFIG_64BIT
+unsigned long notrace __xchg64(unsigned long x, volatile unsigned long *ptr)
+{
+ unsigned long temp, flags;
+
+ _atomic_spin_lock_irqsave(ptr, flags);
+ temp = *ptr;
+ *ptr = x;
+ _atomic_spin_unlock_irqrestore(ptr, flags);
+ return temp;
+}
+#endif
+
+unsigned long notrace __xchg32(int x, volatile int *ptr)
+{
+ unsigned long flags;
+ long temp;
+
+ _atomic_spin_lock_irqsave(ptr, flags);
+ temp = (long) *ptr; /* XXX - sign extension wanted? */
+ *ptr = x;
+ _atomic_spin_unlock_irqrestore(ptr, flags);
+ return (unsigned long)temp;
+}
+
+
+unsigned long notrace __xchg8(char x, volatile char *ptr)
+{
+ unsigned long flags;
+ long temp;
+
+ _atomic_spin_lock_irqsave(ptr, flags);
+ temp = (long) *ptr; /* XXX - sign extension wanted? */
+ *ptr = x;
+ _atomic_spin_unlock_irqrestore(ptr, flags);
+ return (unsigned long)temp;
+}
+
+
+u64 notrace __cmpxchg_u64(volatile u64 *ptr, u64 old, u64 new)
+{
+ unsigned long flags;
+ u64 prev;
+
+ _atomic_spin_lock_irqsave(ptr, flags);
+ if ((prev = *ptr) == old)
+ *ptr = new;
+ _atomic_spin_unlock_irqrestore(ptr, flags);
+ return prev;
+}
+
+unsigned long notrace __cmpxchg_u32(volatile unsigned int *ptr, unsigned int old, unsigned int new)
+{
+ unsigned long flags;
+ unsigned int prev;
+
+ _atomic_spin_lock_irqsave(ptr, flags);
+ if ((prev = *ptr) == old)
+ *ptr = new;
+ _atomic_spin_unlock_irqrestore(ptr, flags);
+ return (unsigned long)prev;
+}
+
+u8 notrace __cmpxchg_u8(volatile u8 *ptr, u8 old, u8 new)
+{
+ unsigned long flags;
+ u8 prev;
+
+ _atomic_spin_lock_irqsave(ptr, flags);
+ if ((prev = *ptr) == old)
+ *ptr = new;
+ _atomic_spin_unlock_irqrestore(ptr, flags);
+ return prev;
+}
diff --git a/arch/parisc/lib/checksum.c b/arch/parisc/lib/checksum.c
new file mode 100644
index 000000000..4818f3db8
--- /dev/null
+++ b/arch/parisc/lib/checksum.c
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * MIPS specific IP/TCP/UDP checksumming routines
+ *
+ * Authors: Ralf Baechle, <ralf@waldorf-gmbh.de>
+ * Lots of code moved from tcp.c and ip.c; see those files
+ * for more names.
+ */
+#include <linux/module.h>
+#include <linux/types.h>
+
+#include <net/checksum.h>
+#include <asm/byteorder.h>
+#include <asm/string.h>
+#include <linux/uaccess.h>
+
+#define addc(_t,_r) \
+ __asm__ __volatile__ ( \
+" add %0, %1, %0\n" \
+" addc %0, %%r0, %0\n" \
+ : "=r"(_t) \
+ : "r"(_r), "0"(_t));
+
+static inline unsigned short from32to16(unsigned int x)
+{
+ /* 32 bits --> 16 bits + carry */
+ x = (x & 0xffff) + (x >> 16);
+ /* 16 bits + carry --> 16 bits including carry */
+ x = (x & 0xffff) + (x >> 16);
+ return (unsigned short)x;
+}
+
+static inline unsigned int do_csum(const unsigned char * buff, int len)
+{
+ int odd, count;
+ unsigned int result = 0;
+
+ if (len <= 0)
+ goto out;
+ odd = 1 & (unsigned long) buff;
+ if (odd) {
+ result = be16_to_cpu(*buff);
+ len--;
+ buff++;
+ }
+ count = len >> 1; /* nr of 16-bit words.. */
+ if (count) {
+ if (2 & (unsigned long) buff) {
+ result += *(unsigned short *) buff;
+ count--;
+ len -= 2;
+ buff += 2;
+ }
+ count >>= 1; /* nr of 32-bit words.. */
+ if (count) {
+ while (count >= 4) {
+ unsigned int r1, r2, r3, r4;
+ r1 = *(unsigned int *)(buff + 0);
+ r2 = *(unsigned int *)(buff + 4);
+ r3 = *(unsigned int *)(buff + 8);
+ r4 = *(unsigned int *)(buff + 12);
+ addc(result, r1);
+ addc(result, r2);
+ addc(result, r3);
+ addc(result, r4);
+ count -= 4;
+ buff += 16;
+ }
+ while (count) {
+ unsigned int w = *(unsigned int *) buff;
+ count--;
+ buff += 4;
+ addc(result, w);
+ }
+ result = (result & 0xffff) + (result >> 16);
+ }
+ if (len & 2) {
+ result += *(unsigned short *) buff;
+ buff += 2;
+ }
+ }
+ if (len & 1)
+ result += le16_to_cpu(*buff);
+ result = from32to16(result);
+ if (odd)
+ result = swab16(result);
+out:
+ return result;
+}
+
+/*
+ * computes a partial checksum, e.g. for TCP/UDP fragments
+ */
+/*
+ * why bother folding?
+ */
+__wsum csum_partial(const void *buff, int len, __wsum sum)
+{
+ unsigned int result = do_csum(buff, len);
+ addc(result, sum);
+ return (__force __wsum)from32to16(result);
+}
+
+EXPORT_SYMBOL(csum_partial);
diff --git a/arch/parisc/lib/delay.c b/arch/parisc/lib/delay.c
new file mode 100644
index 000000000..66e506520
--- /dev/null
+++ b/arch/parisc/lib/delay.c
@@ -0,0 +1,72 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Precise Delay Loops for parisc
+ *
+ * based on code by:
+ * Copyright (C) 1993 Linus Torvalds
+ * Copyright (C) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ * Copyright (C) 2008 Jiri Hladky <hladky _dot_ jiri _at_ gmail _dot_ com>
+ *
+ * parisc implementation:
+ * Copyright (C) 2013 Helge Deller <deller@gmx.de>
+ */
+
+
+#include <linux/module.h>
+#include <linux/preempt.h>
+#include <linux/init.h>
+
+#include <asm/delay.h>
+#include <asm/special_insns.h> /* for mfctl() */
+#include <asm/processor.h> /* for boot_cpu_data */
+
+/* CR16 based delay: */
+static void __cr16_delay(unsigned long __loops)
+{
+ /*
+ * Note: Due to unsigned math, cr16 rollovers shouldn't be
+ * a problem here. However, on 32 bit, we need to make sure
+ * we don't pass in too big a value. The current default
+ * value of MAX_UDELAY_MS should help prevent this.
+ */
+ u32 bclock, now, loops = __loops;
+ int cpu;
+
+ preempt_disable();
+ cpu = smp_processor_id();
+ bclock = mfctl(16);
+ for (;;) {
+ now = mfctl(16);
+ if ((now - bclock) >= loops)
+ break;
+
+ /* Allow RT tasks to run */
+ preempt_enable();
+ asm volatile(" nop\n");
+ barrier();
+ preempt_disable();
+
+ /*
+ * It is possible that we moved to another CPU, and
+ * since CR16's are per-cpu we need to calculate
+ * that. The delay must guarantee that we wait "at
+ * least" the amount of time. Being moved to another
+ * CPU could make the wait longer but we just need to
+ * make sure we waited long enough. Rebalance the
+ * counter for this CPU.
+ */
+ if (unlikely(cpu != smp_processor_id())) {
+ loops -= (now - bclock);
+ cpu = smp_processor_id();
+ bclock = mfctl(16);
+ }
+ }
+ preempt_enable();
+}
+
+
+void __udelay(unsigned long usecs)
+{
+ __cr16_delay(usecs * ((unsigned long)boot_cpu_data.cpu_hz / 1000000UL));
+}
+EXPORT_SYMBOL(__udelay);
diff --git a/arch/parisc/lib/io.c b/arch/parisc/lib/io.c
new file mode 100644
index 000000000..7c00496b4
--- /dev/null
+++ b/arch/parisc/lib/io.c
@@ -0,0 +1,489 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * arch/parisc/lib/io.c
+ *
+ * Copyright (c) Matthew Wilcox 2001 for Hewlett-Packard
+ * Copyright (c) Randolph Chung 2001 <tausq@debian.org>
+ *
+ * IO accessing functions which shouldn't be inlined because they're too big
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/io.h>
+
+/* Copies a block of memory to a device in an efficient manner.
+ * Assumes the device can cope with 32-bit transfers. If it can't,
+ * don't use this function.
+ */
+void memcpy_toio(volatile void __iomem *dst, const void *src, int count)
+{
+ if (((unsigned long)dst & 3) != ((unsigned long)src & 3))
+ goto bytecopy;
+ while ((unsigned long)dst & 3) {
+ writeb(*(char *)src, dst++);
+ src++;
+ count--;
+ }
+ while (count > 3) {
+ __raw_writel(*(u32 *)src, dst);
+ src += 4;
+ dst += 4;
+ count -= 4;
+ }
+ bytecopy:
+ while (count--) {
+ writeb(*(char *)src, dst++);
+ src++;
+ }
+}
+
+/*
+** Copies a block of memory from a device in an efficient manner.
+** Assumes the device can cope with 32-bit transfers. If it can't,
+** don't use this function.
+**
+** CR16 counts on C3000 reading 256 bytes from Symbios 896 RAM:
+** 27341/64 = 427 cyc per int
+** 61311/128 = 478 cyc per short
+** 122637/256 = 479 cyc per byte
+** Ergo bus latencies dominant (not transfer size).
+** Minimize total number of transfers at cost of CPU cycles.
+** TODO: only look at src alignment and adjust the stores to dest.
+*/
+void memcpy_fromio(void *dst, const volatile void __iomem *src, int count)
+{
+ /* first compare alignment of src/dst */
+ if ( (((unsigned long)dst ^ (unsigned long)src) & 1) || (count < 2) )
+ goto bytecopy;
+
+ if ( (((unsigned long)dst ^ (unsigned long)src) & 2) || (count < 4) )
+ goto shortcopy;
+
+ /* Then check for misaligned start address */
+ if ((unsigned long)src & 1) {
+ *(u8 *)dst = readb(src);
+ src++;
+ dst++;
+ count--;
+ if (count < 2) goto bytecopy;
+ }
+
+ if ((unsigned long)src & 2) {
+ *(u16 *)dst = __raw_readw(src);
+ src += 2;
+ dst += 2;
+ count -= 2;
+ }
+
+ while (count > 3) {
+ *(u32 *)dst = __raw_readl(src);
+ dst += 4;
+ src += 4;
+ count -= 4;
+ }
+
+ shortcopy:
+ while (count > 1) {
+ *(u16 *)dst = __raw_readw(src);
+ src += 2;
+ dst += 2;
+ count -= 2;
+ }
+
+ bytecopy:
+ while (count--) {
+ *(char *)dst = readb(src);
+ src++;
+ dst++;
+ }
+}
+
+/* Sets a block of memory on a device to a given value.
+ * Assumes the device can cope with 32-bit transfers. If it can't,
+ * don't use this function.
+ */
+void memset_io(volatile void __iomem *addr, unsigned char val, int count)
+{
+ u32 val32 = (val << 24) | (val << 16) | (val << 8) | val;
+ while ((unsigned long)addr & 3) {
+ writeb(val, addr++);
+ count--;
+ }
+ while (count > 3) {
+ __raw_writel(val32, addr);
+ addr += 4;
+ count -= 4;
+ }
+ while (count--) {
+ writeb(val, addr++);
+ }
+}
+
+/*
+ * Read COUNT 8-bit bytes from port PORT into memory starting at
+ * SRC.
+ */
+void insb (unsigned long port, void *dst, unsigned long count)
+{
+ unsigned char *p;
+
+ p = (unsigned char *)dst;
+
+ while (((unsigned long)p) & 0x3) {
+ if (!count)
+ return;
+ count--;
+ *p = inb(port);
+ p++;
+ }
+
+ while (count >= 4) {
+ unsigned int w;
+ count -= 4;
+ w = inb(port) << 24;
+ w |= inb(port) << 16;
+ w |= inb(port) << 8;
+ w |= inb(port);
+ *(unsigned int *) p = w;
+ p += 4;
+ }
+
+ while (count) {
+ --count;
+ *p = inb(port);
+ p++;
+ }
+}
+
+
+/*
+ * Read COUNT 16-bit words from port PORT into memory starting at
+ * SRC. SRC must be at least short aligned. This is used by the
+ * IDE driver to read disk sectors. Performance is important, but
+ * the interfaces seems to be slow: just using the inlined version
+ * of the inw() breaks things.
+ */
+void insw (unsigned long port, void *dst, unsigned long count)
+{
+ unsigned int l = 0, l2;
+ unsigned char *p;
+
+ p = (unsigned char *)dst;
+
+ if (!count)
+ return;
+
+ switch (((unsigned long)p) & 0x3)
+ {
+ case 0x00: /* Buffer 32-bit aligned */
+ while (count>=2) {
+
+ count -= 2;
+ l = cpu_to_le16(inw(port)) << 16;
+ l |= cpu_to_le16(inw(port));
+ *(unsigned int *)p = l;
+ p += 4;
+ }
+ if (count) {
+ *(unsigned short *)p = cpu_to_le16(inw(port));
+ }
+ break;
+
+ case 0x02: /* Buffer 16-bit aligned */
+ *(unsigned short *)p = cpu_to_le16(inw(port));
+ p += 2;
+ count--;
+ while (count>=2) {
+
+ count -= 2;
+ l = cpu_to_le16(inw(port)) << 16;
+ l |= cpu_to_le16(inw(port));
+ *(unsigned int *)p = l;
+ p += 4;
+ }
+ if (count) {
+ *(unsigned short *)p = cpu_to_le16(inw(port));
+ }
+ break;
+
+ case 0x01: /* Buffer 8-bit aligned */
+ case 0x03:
+ /* I don't bother with 32bit transfers
+ * in this case, 16bit will have to do -- DE */
+ --count;
+
+ l = cpu_to_le16(inw(port));
+ *p = l >> 8;
+ p++;
+ while (count--)
+ {
+ l2 = cpu_to_le16(inw(port));
+ *(unsigned short *)p = (l & 0xff) << 8 | (l2 >> 8);
+ p += 2;
+ l = l2;
+ }
+ *p = l & 0xff;
+ break;
+ }
+}
+
+
+
+/*
+ * Read COUNT 32-bit words from port PORT into memory starting at
+ * SRC. Now works with any alignment in SRC. Performance is important,
+ * but the interfaces seems to be slow: just using the inlined version
+ * of the inl() breaks things.
+ */
+void insl (unsigned long port, void *dst, unsigned long count)
+{
+ unsigned int l = 0, l2;
+ unsigned char *p;
+
+ p = (unsigned char *)dst;
+
+ if (!count)
+ return;
+
+ switch (((unsigned long) dst) & 0x3)
+ {
+ case 0x00: /* Buffer 32-bit aligned */
+ while (count--)
+ {
+ *(unsigned int *)p = cpu_to_le32(inl(port));
+ p += 4;
+ }
+ break;
+
+ case 0x02: /* Buffer 16-bit aligned */
+ --count;
+
+ l = cpu_to_le32(inl(port));
+ *(unsigned short *)p = l >> 16;
+ p += 2;
+
+ while (count--)
+ {
+ l2 = cpu_to_le32(inl(port));
+ *(unsigned int *)p = (l & 0xffff) << 16 | (l2 >> 16);
+ p += 4;
+ l = l2;
+ }
+ *(unsigned short *)p = l & 0xffff;
+ break;
+ case 0x01: /* Buffer 8-bit aligned */
+ --count;
+
+ l = cpu_to_le32(inl(port));
+ *(unsigned char *)p = l >> 24;
+ p++;
+ *(unsigned short *)p = (l >> 8) & 0xffff;
+ p += 2;
+ while (count--)
+ {
+ l2 = cpu_to_le32(inl(port));
+ *(unsigned int *)p = (l & 0xff) << 24 | (l2 >> 8);
+ p += 4;
+ l = l2;
+ }
+ *p = l & 0xff;
+ break;
+ case 0x03: /* Buffer 8-bit aligned */
+ --count;
+
+ l = cpu_to_le32(inl(port));
+ *p = l >> 24;
+ p++;
+ while (count--)
+ {
+ l2 = cpu_to_le32(inl(port));
+ *(unsigned int *)p = (l & 0xffffff) << 8 | l2 >> 24;
+ p += 4;
+ l = l2;
+ }
+ *(unsigned short *)p = (l >> 8) & 0xffff;
+ p += 2;
+ *p = l & 0xff;
+ break;
+ }
+}
+
+
+/*
+ * Like insb but in the opposite direction.
+ * Don't worry as much about doing aligned memory transfers:
+ * doing byte reads the "slow" way isn't nearly as slow as
+ * doing byte writes the slow way (no r-m-w cycle).
+ */
+void outsb(unsigned long port, const void * src, unsigned long count)
+{
+ const unsigned char *p;
+
+ p = (const unsigned char *)src;
+ while (count) {
+ count--;
+ outb(*p, port);
+ p++;
+ }
+}
+
+/*
+ * Like insw but in the opposite direction. This is used by the IDE
+ * driver to write disk sectors. Performance is important, but the
+ * interfaces seems to be slow: just using the inlined version of the
+ * outw() breaks things.
+ */
+void outsw (unsigned long port, const void *src, unsigned long count)
+{
+ unsigned int l = 0, l2;
+ const unsigned char *p;
+
+ p = (const unsigned char *)src;
+
+ if (!count)
+ return;
+
+ switch (((unsigned long)p) & 0x3)
+ {
+ case 0x00: /* Buffer 32-bit aligned */
+ while (count>=2) {
+ count -= 2;
+ l = *(unsigned int *)p;
+ p += 4;
+ outw(le16_to_cpu(l >> 16), port);
+ outw(le16_to_cpu(l & 0xffff), port);
+ }
+ if (count) {
+ outw(le16_to_cpu(*(unsigned short*)p), port);
+ }
+ break;
+
+ case 0x02: /* Buffer 16-bit aligned */
+
+ outw(le16_to_cpu(*(unsigned short*)p), port);
+ p += 2;
+ count--;
+
+ while (count>=2) {
+ count -= 2;
+ l = *(unsigned int *)p;
+ p += 4;
+ outw(le16_to_cpu(l >> 16), port);
+ outw(le16_to_cpu(l & 0xffff), port);
+ }
+ if (count) {
+ outw(le16_to_cpu(*(unsigned short *)p), port);
+ }
+ break;
+
+ case 0x01: /* Buffer 8-bit aligned */
+ /* I don't bother with 32bit transfers
+ * in this case, 16bit will have to do -- DE */
+
+ l = *p << 8;
+ p++;
+ count--;
+ while (count)
+ {
+ count--;
+ l2 = *(unsigned short *)p;
+ p += 2;
+ outw(le16_to_cpu(l | l2 >> 8), port);
+ l = l2 << 8;
+ }
+ l2 = *(unsigned char *)p;
+ outw (le16_to_cpu(l | l2>>8), port);
+ break;
+
+ }
+}
+
+
+/*
+ * Like insl but in the opposite direction. This is used by the IDE
+ * driver to write disk sectors. Works with any alignment in SRC.
+ * Performance is important, but the interfaces seems to be slow:
+ * just using the inlined version of the outl() breaks things.
+ */
+void outsl (unsigned long port, const void *src, unsigned long count)
+{
+ unsigned int l = 0, l2;
+ const unsigned char *p;
+
+ p = (const unsigned char *)src;
+
+ if (!count)
+ return;
+
+ switch (((unsigned long)p) & 0x3)
+ {
+ case 0x00: /* Buffer 32-bit aligned */
+ while (count--)
+ {
+ outl(le32_to_cpu(*(unsigned int *)p), port);
+ p += 4;
+ }
+ break;
+
+ case 0x02: /* Buffer 16-bit aligned */
+ --count;
+
+ l = *(unsigned short *)p;
+ p += 2;
+
+ while (count--)
+ {
+ l2 = *(unsigned int *)p;
+ p += 4;
+ outl (le32_to_cpu(l << 16 | l2 >> 16), port);
+ l = l2;
+ }
+ l2 = *(unsigned short *)p;
+ outl (le32_to_cpu(l << 16 | l2), port);
+ break;
+ case 0x01: /* Buffer 8-bit aligned */
+ --count;
+
+ l = *p << 24;
+ p++;
+ l |= *(unsigned short *)p << 8;
+ p += 2;
+
+ while (count--)
+ {
+ l2 = *(unsigned int *)p;
+ p += 4;
+ outl (le32_to_cpu(l | l2 >> 24), port);
+ l = l2 << 8;
+ }
+ l2 = *p;
+ outl (le32_to_cpu(l | l2), port);
+ break;
+ case 0x03: /* Buffer 8-bit aligned */
+ --count;
+
+ l = *p << 24;
+ p++;
+
+ while (count--)
+ {
+ l2 = *(unsigned int *)p;
+ p += 4;
+ outl (le32_to_cpu(l | l2 >> 8), port);
+ l = l2 << 24;
+ }
+ l2 = *(unsigned short *)p << 16;
+ p += 2;
+ l2 |= *p;
+ outl (le32_to_cpu(l | l2), port);
+ break;
+ }
+}
+
+EXPORT_SYMBOL(insb);
+EXPORT_SYMBOL(insw);
+EXPORT_SYMBOL(insl);
+EXPORT_SYMBOL(outsb);
+EXPORT_SYMBOL(outsw);
+EXPORT_SYMBOL(outsl);
diff --git a/arch/parisc/lib/iomap.c b/arch/parisc/lib/iomap.c
new file mode 100644
index 000000000..915c0c4da
--- /dev/null
+++ b/arch/parisc/lib/iomap.c
@@ -0,0 +1,551 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * iomap.c - Implement iomap interface for PA-RISC
+ * Copyright (c) 2004 Matthew Wilcox
+ */
+
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/export.h>
+#include <asm/io.h>
+
+/*
+ * The iomap space on 32-bit PA-RISC is intended to look like this:
+ * 00000000-7fffffff virtual mapped IO
+ * 80000000-8fffffff ISA/EISA port space that can't be virtually mapped
+ * 90000000-9fffffff Dino port space
+ * a0000000-afffffff Astro port space
+ * b0000000-bfffffff PAT port space
+ * c0000000-cfffffff non-swapped memory IO
+ * f0000000-ffffffff legacy IO memory pointers
+ *
+ * For the moment, here's what it looks like:
+ * 80000000-8fffffff All ISA/EISA port space
+ * f0000000-ffffffff legacy IO memory pointers
+ *
+ * On 64-bit, everything is extended, so:
+ * 8000000000000000-8fffffffffffffff All ISA/EISA port space
+ * f000000000000000-ffffffffffffffff legacy IO memory pointers
+ */
+
+/*
+ * Technically, this should be 'if (VMALLOC_START < addr < VMALLOC_END),
+ * but that's slow and we know it'll be within the first 2GB.
+ */
+#ifdef CONFIG_64BIT
+#define INDIRECT_ADDR(addr) (((unsigned long)(addr) & 1UL<<63) != 0)
+#define ADDR_TO_REGION(addr) (((unsigned long)addr >> 60) & 7)
+#define IOPORT_MAP_BASE (8UL << 60)
+#else
+#define INDIRECT_ADDR(addr) (((unsigned long)(addr) & 1UL<<31) != 0)
+#define ADDR_TO_REGION(addr) (((unsigned long)addr >> 28) & 7)
+#define IOPORT_MAP_BASE (8UL << 28)
+#endif
+
+struct iomap_ops {
+ unsigned int (*read8)(const void __iomem *);
+ unsigned int (*read16)(const void __iomem *);
+ unsigned int (*read16be)(const void __iomem *);
+ unsigned int (*read32)(const void __iomem *);
+ unsigned int (*read32be)(const void __iomem *);
+#ifdef CONFIG_64BIT
+ u64 (*read64)(const void __iomem *);
+ u64 (*read64be)(const void __iomem *);
+#endif
+ void (*write8)(u8, void __iomem *);
+ void (*write16)(u16, void __iomem *);
+ void (*write16be)(u16, void __iomem *);
+ void (*write32)(u32, void __iomem *);
+ void (*write32be)(u32, void __iomem *);
+#ifdef CONFIG_64BIT
+ void (*write64)(u64, void __iomem *);
+ void (*write64be)(u64, void __iomem *);
+#endif
+ void (*read8r)(const void __iomem *, void *, unsigned long);
+ void (*read16r)(const void __iomem *, void *, unsigned long);
+ void (*read32r)(const void __iomem *, void *, unsigned long);
+ void (*write8r)(void __iomem *, const void *, unsigned long);
+ void (*write16r)(void __iomem *, const void *, unsigned long);
+ void (*write32r)(void __iomem *, const void *, unsigned long);
+};
+
+/* Generic ioport ops. To be replaced later by specific dino/elroy/wax code */
+
+#define ADDR2PORT(addr) ((unsigned long __force)(addr) & 0xffffff)
+
+static unsigned int ioport_read8(const void __iomem *addr)
+{
+ return inb(ADDR2PORT(addr));
+}
+
+static unsigned int ioport_read16(const void __iomem *addr)
+{
+ return inw(ADDR2PORT(addr));
+}
+
+static unsigned int ioport_read32(const void __iomem *addr)
+{
+ return inl(ADDR2PORT(addr));
+}
+
+static void ioport_write8(u8 datum, void __iomem *addr)
+{
+ outb(datum, ADDR2PORT(addr));
+}
+
+static void ioport_write16(u16 datum, void __iomem *addr)
+{
+ outw(datum, ADDR2PORT(addr));
+}
+
+static void ioport_write32(u32 datum, void __iomem *addr)
+{
+ outl(datum, ADDR2PORT(addr));
+}
+
+static void ioport_read8r(const void __iomem *addr, void *dst, unsigned long count)
+{
+ insb(ADDR2PORT(addr), dst, count);
+}
+
+static void ioport_read16r(const void __iomem *addr, void *dst, unsigned long count)
+{
+ insw(ADDR2PORT(addr), dst, count);
+}
+
+static void ioport_read32r(const void __iomem *addr, void *dst, unsigned long count)
+{
+ insl(ADDR2PORT(addr), dst, count);
+}
+
+static void ioport_write8r(void __iomem *addr, const void *s, unsigned long n)
+{
+ outsb(ADDR2PORT(addr), s, n);
+}
+
+static void ioport_write16r(void __iomem *addr, const void *s, unsigned long n)
+{
+ outsw(ADDR2PORT(addr), s, n);
+}
+
+static void ioport_write32r(void __iomem *addr, const void *s, unsigned long n)
+{
+ outsl(ADDR2PORT(addr), s, n);
+}
+
+static const struct iomap_ops ioport_ops = {
+ .read8 = ioport_read8,
+ .read16 = ioport_read16,
+ .read16be = ioport_read16,
+ .read32 = ioport_read32,
+ .read32be = ioport_read32,
+ .write8 = ioport_write8,
+ .write16 = ioport_write16,
+ .write16be = ioport_write16,
+ .write32 = ioport_write32,
+ .write32be = ioport_write32,
+ .read8r = ioport_read8r,
+ .read16r = ioport_read16r,
+ .read32r = ioport_read32r,
+ .write8r = ioport_write8r,
+ .write16r = ioport_write16r,
+ .write32r = ioport_write32r,
+};
+
+/* Legacy I/O memory ops */
+
+static unsigned int iomem_read8(const void __iomem *addr)
+{
+ return readb(addr);
+}
+
+static unsigned int iomem_read16(const void __iomem *addr)
+{
+ return readw(addr);
+}
+
+static unsigned int iomem_read16be(const void __iomem *addr)
+{
+ return __raw_readw(addr);
+}
+
+static unsigned int iomem_read32(const void __iomem *addr)
+{
+ return readl(addr);
+}
+
+static unsigned int iomem_read32be(const void __iomem *addr)
+{
+ return __raw_readl(addr);
+}
+
+#ifdef CONFIG_64BIT
+static u64 iomem_read64(const void __iomem *addr)
+{
+ return readq(addr);
+}
+
+static u64 iomem_read64be(const void __iomem *addr)
+{
+ return __raw_readq(addr);
+}
+#endif
+
+static void iomem_write8(u8 datum, void __iomem *addr)
+{
+ writeb(datum, addr);
+}
+
+static void iomem_write16(u16 datum, void __iomem *addr)
+{
+ writew(datum, addr);
+}
+
+static void iomem_write16be(u16 datum, void __iomem *addr)
+{
+ __raw_writew(datum, addr);
+}
+
+static void iomem_write32(u32 datum, void __iomem *addr)
+{
+ writel(datum, addr);
+}
+
+static void iomem_write32be(u32 datum, void __iomem *addr)
+{
+ __raw_writel(datum, addr);
+}
+
+#ifdef CONFIG_64BIT
+static void iomem_write64(u64 datum, void __iomem *addr)
+{
+ writeq(datum, addr);
+}
+
+static void iomem_write64be(u64 datum, void __iomem *addr)
+{
+ __raw_writeq(datum, addr);
+}
+#endif
+
+static void iomem_read8r(const void __iomem *addr, void *dst, unsigned long count)
+{
+ while (count--) {
+ *(u8 *)dst = __raw_readb(addr);
+ dst++;
+ }
+}
+
+static void iomem_read16r(const void __iomem *addr, void *dst, unsigned long count)
+{
+ while (count--) {
+ *(u16 *)dst = __raw_readw(addr);
+ dst += 2;
+ }
+}
+
+static void iomem_read32r(const void __iomem *addr, void *dst, unsigned long count)
+{
+ while (count--) {
+ *(u32 *)dst = __raw_readl(addr);
+ dst += 4;
+ }
+}
+
+static void iomem_write8r(void __iomem *addr, const void *s, unsigned long n)
+{
+ while (n--) {
+ __raw_writeb(*(u8 *)s, addr);
+ s++;
+ }
+}
+
+static void iomem_write16r(void __iomem *addr, const void *s, unsigned long n)
+{
+ while (n--) {
+ __raw_writew(*(u16 *)s, addr);
+ s += 2;
+ }
+}
+
+static void iomem_write32r(void __iomem *addr, const void *s, unsigned long n)
+{
+ while (n--) {
+ __raw_writel(*(u32 *)s, addr);
+ s += 4;
+ }
+}
+
+static const struct iomap_ops iomem_ops = {
+ .read8 = iomem_read8,
+ .read16 = iomem_read16,
+ .read16be = iomem_read16be,
+ .read32 = iomem_read32,
+ .read32be = iomem_read32be,
+#ifdef CONFIG_64BIT
+ .read64 = iomem_read64,
+ .read64be = iomem_read64be,
+#endif
+ .write8 = iomem_write8,
+ .write16 = iomem_write16,
+ .write16be = iomem_write16be,
+ .write32 = iomem_write32,
+ .write32be = iomem_write32be,
+#ifdef CONFIG_64BIT
+ .write64 = iomem_write64,
+ .write64be = iomem_write64be,
+#endif
+ .read8r = iomem_read8r,
+ .read16r = iomem_read16r,
+ .read32r = iomem_read32r,
+ .write8r = iomem_write8r,
+ .write16r = iomem_write16r,
+ .write32r = iomem_write32r,
+};
+
+static const struct iomap_ops *iomap_ops[8] = {
+ [0] = &ioport_ops,
+ [7] = &iomem_ops
+};
+
+
+unsigned int ioread8(const void __iomem *addr)
+{
+ if (unlikely(INDIRECT_ADDR(addr)))
+ return iomap_ops[ADDR_TO_REGION(addr)]->read8(addr);
+ return *((u8 *)addr);
+}
+
+unsigned int ioread16(const void __iomem *addr)
+{
+ if (unlikely(INDIRECT_ADDR(addr)))
+ return iomap_ops[ADDR_TO_REGION(addr)]->read16(addr);
+ return le16_to_cpup((u16 *)addr);
+}
+
+unsigned int ioread16be(const void __iomem *addr)
+{
+ if (unlikely(INDIRECT_ADDR(addr)))
+ return iomap_ops[ADDR_TO_REGION(addr)]->read16be(addr);
+ return *((u16 *)addr);
+}
+
+unsigned int ioread32(const void __iomem *addr)
+{
+ if (unlikely(INDIRECT_ADDR(addr)))
+ return iomap_ops[ADDR_TO_REGION(addr)]->read32(addr);
+ return le32_to_cpup((u32 *)addr);
+}
+
+unsigned int ioread32be(const void __iomem *addr)
+{
+ if (unlikely(INDIRECT_ADDR(addr)))
+ return iomap_ops[ADDR_TO_REGION(addr)]->read32be(addr);
+ return *((u32 *)addr);
+}
+
+#ifdef CONFIG_64BIT
+u64 ioread64(const void __iomem *addr)
+{
+ if (unlikely(INDIRECT_ADDR(addr)))
+ return iomap_ops[ADDR_TO_REGION(addr)]->read64(addr);
+ return le64_to_cpup((u64 *)addr);
+}
+
+u64 ioread64be(const void __iomem *addr)
+{
+ if (unlikely(INDIRECT_ADDR(addr)))
+ return iomap_ops[ADDR_TO_REGION(addr)]->read64be(addr);
+ return *((u64 *)addr);
+}
+#endif
+
+void iowrite8(u8 datum, void __iomem *addr)
+{
+ if (unlikely(INDIRECT_ADDR(addr))) {
+ iomap_ops[ADDR_TO_REGION(addr)]->write8(datum, addr);
+ } else {
+ *((u8 *)addr) = datum;
+ }
+}
+
+void iowrite16(u16 datum, void __iomem *addr)
+{
+ if (unlikely(INDIRECT_ADDR(addr))) {
+ iomap_ops[ADDR_TO_REGION(addr)]->write16(datum, addr);
+ } else {
+ *((u16 *)addr) = cpu_to_le16(datum);
+ }
+}
+
+void iowrite16be(u16 datum, void __iomem *addr)
+{
+ if (unlikely(INDIRECT_ADDR(addr))) {
+ iomap_ops[ADDR_TO_REGION(addr)]->write16be(datum, addr);
+ } else {
+ *((u16 *)addr) = datum;
+ }
+}
+
+void iowrite32(u32 datum, void __iomem *addr)
+{
+ if (unlikely(INDIRECT_ADDR(addr))) {
+ iomap_ops[ADDR_TO_REGION(addr)]->write32(datum, addr);
+ } else {
+ *((u32 *)addr) = cpu_to_le32(datum);
+ }
+}
+
+void iowrite32be(u32 datum, void __iomem *addr)
+{
+ if (unlikely(INDIRECT_ADDR(addr))) {
+ iomap_ops[ADDR_TO_REGION(addr)]->write32be(datum, addr);
+ } else {
+ *((u32 *)addr) = datum;
+ }
+}
+
+#ifdef CONFIG_64BIT
+void iowrite64(u64 datum, void __iomem *addr)
+{
+ if (unlikely(INDIRECT_ADDR(addr))) {
+ iomap_ops[ADDR_TO_REGION(addr)]->write64(datum, addr);
+ } else {
+ *((u64 *)addr) = cpu_to_le64(datum);
+ }
+}
+
+void iowrite64be(u64 datum, void __iomem *addr)
+{
+ if (unlikely(INDIRECT_ADDR(addr))) {
+ iomap_ops[ADDR_TO_REGION(addr)]->write64be(datum, addr);
+ } else {
+ *((u64 *)addr) = datum;
+ }
+}
+#endif
+
+/* Repeating interfaces */
+
+void ioread8_rep(const void __iomem *addr, void *dst, unsigned long count)
+{
+ if (unlikely(INDIRECT_ADDR(addr))) {
+ iomap_ops[ADDR_TO_REGION(addr)]->read8r(addr, dst, count);
+ } else {
+ while (count--) {
+ *(u8 *)dst = *(u8 *)addr;
+ dst++;
+ }
+ }
+}
+
+void ioread16_rep(const void __iomem *addr, void *dst, unsigned long count)
+{
+ if (unlikely(INDIRECT_ADDR(addr))) {
+ iomap_ops[ADDR_TO_REGION(addr)]->read16r(addr, dst, count);
+ } else {
+ while (count--) {
+ *(u16 *)dst = *(u16 *)addr;
+ dst += 2;
+ }
+ }
+}
+
+void ioread32_rep(const void __iomem *addr, void *dst, unsigned long count)
+{
+ if (unlikely(INDIRECT_ADDR(addr))) {
+ iomap_ops[ADDR_TO_REGION(addr)]->read32r(addr, dst, count);
+ } else {
+ while (count--) {
+ *(u32 *)dst = *(u32 *)addr;
+ dst += 4;
+ }
+ }
+}
+
+void iowrite8_rep(void __iomem *addr, const void *src, unsigned long count)
+{
+ if (unlikely(INDIRECT_ADDR(addr))) {
+ iomap_ops[ADDR_TO_REGION(addr)]->write8r(addr, src, count);
+ } else {
+ while (count--) {
+ *(u8 *)addr = *(u8 *)src;
+ src++;
+ }
+ }
+}
+
+void iowrite16_rep(void __iomem *addr, const void *src, unsigned long count)
+{
+ if (unlikely(INDIRECT_ADDR(addr))) {
+ iomap_ops[ADDR_TO_REGION(addr)]->write16r(addr, src, count);
+ } else {
+ while (count--) {
+ *(u16 *)addr = *(u16 *)src;
+ src += 2;
+ }
+ }
+}
+
+void iowrite32_rep(void __iomem *addr, const void *src, unsigned long count)
+{
+ if (unlikely(INDIRECT_ADDR(addr))) {
+ iomap_ops[ADDR_TO_REGION(addr)]->write32r(addr, src, count);
+ } else {
+ while (count--) {
+ *(u32 *)addr = *(u32 *)src;
+ src += 4;
+ }
+ }
+}
+
+/* Mapping interfaces */
+
+void __iomem *ioport_map(unsigned long port, unsigned int nr)
+{
+ return (void __iomem *)(IOPORT_MAP_BASE | port);
+}
+
+void ioport_unmap(void __iomem *addr)
+{
+ if (!INDIRECT_ADDR(addr)) {
+ iounmap(addr);
+ }
+}
+
+#ifdef CONFIG_PCI
+void pci_iounmap(struct pci_dev *dev, void __iomem * addr)
+{
+ if (!INDIRECT_ADDR(addr)) {
+ iounmap(addr);
+ }
+}
+EXPORT_SYMBOL(pci_iounmap);
+#endif
+
+EXPORT_SYMBOL(ioread8);
+EXPORT_SYMBOL(ioread16);
+EXPORT_SYMBOL(ioread16be);
+EXPORT_SYMBOL(ioread32);
+EXPORT_SYMBOL(ioread32be);
+#ifdef CONFIG_64BIT
+EXPORT_SYMBOL(ioread64);
+EXPORT_SYMBOL(ioread64be);
+#endif
+EXPORT_SYMBOL(iowrite8);
+EXPORT_SYMBOL(iowrite16);
+EXPORT_SYMBOL(iowrite16be);
+EXPORT_SYMBOL(iowrite32);
+EXPORT_SYMBOL(iowrite32be);
+#ifdef CONFIG_64BIT
+EXPORT_SYMBOL(iowrite64);
+EXPORT_SYMBOL(iowrite64be);
+#endif
+EXPORT_SYMBOL(ioread8_rep);
+EXPORT_SYMBOL(ioread16_rep);
+EXPORT_SYMBOL(ioread32_rep);
+EXPORT_SYMBOL(iowrite8_rep);
+EXPORT_SYMBOL(iowrite16_rep);
+EXPORT_SYMBOL(iowrite32_rep);
+EXPORT_SYMBOL(ioport_map);
+EXPORT_SYMBOL(ioport_unmap);
diff --git a/arch/parisc/lib/lusercopy.S b/arch/parisc/lib/lusercopy.S
new file mode 100644
index 000000000..b428d29e4
--- /dev/null
+++ b/arch/parisc/lib/lusercopy.S
@@ -0,0 +1,362 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * User Space Access Routines
+ *
+ * Copyright (C) 2000-2002 Hewlett-Packard (John Marvin)
+ * Copyright (C) 2000 Richard Hirst <rhirst with parisc-linux.org>
+ * Copyright (C) 2001 Matthieu Delahaye <delahaym at esiee.fr>
+ * Copyright (C) 2003 Randolph Chung <tausq with parisc-linux.org>
+ * Copyright (C) 2017 Helge Deller <deller@gmx.de>
+ * Copyright (C) 2017 John David Anglin <dave.anglin@bell.net>
+ */
+
+/*
+ * These routines still have plenty of room for optimization
+ * (word & doubleword load/store, dual issue, store hints, etc.).
+ */
+
+/*
+ * The following routines assume that space register 3 (sr3) contains
+ * the space id associated with the current users address space.
+ */
+
+
+ .text
+
+#include <asm/assembly.h>
+#include <asm/errno.h>
+#include <linux/linkage.h>
+
+ /*
+ * unsigned long lclear_user(void *to, unsigned long n)
+ *
+ * Returns 0 for success.
+ * otherwise, returns number of bytes not transferred.
+ */
+
+ENTRY_CFI(lclear_user)
+ comib,=,n 0,%r25,$lclu_done
+$lclu_loop:
+ addib,<> -1,%r25,$lclu_loop
+1: stbs,ma %r0,1(%sr3,%r26)
+
+$lclu_done:
+ bv %r0(%r2)
+ copy %r25,%r28
+
+2: b $lclu_done
+ ldo 1(%r25),%r25
+
+ ASM_EXCEPTIONTABLE_ENTRY(1b,2b)
+ENDPROC_CFI(lclear_user)
+
+
+/*
+ * unsigned long pa_memcpy(void *dstp, const void *srcp, unsigned long len)
+ *
+ * Inputs:
+ * - sr1 already contains space of source region
+ * - sr2 already contains space of destination region
+ *
+ * Returns:
+ * - number of bytes that could not be copied.
+ * On success, this will be zero.
+ *
+ * This code is based on a C-implementation of a copy routine written by
+ * Randolph Chung, which in turn was derived from the glibc.
+ *
+ * Several strategies are tried to try to get the best performance for various
+ * conditions. In the optimal case, we copy by loops that copy 32- or 16-bytes
+ * at a time using general registers. Unaligned copies are handled either by
+ * aligning the destination and then using shift-and-write method, or in a few
+ * cases by falling back to a byte-at-a-time copy.
+ *
+ * Testing with various alignments and buffer sizes shows that this code is
+ * often >10x faster than a simple byte-at-a-time copy, even for strangely
+ * aligned operands. It is interesting to note that the glibc version of memcpy
+ * (written in C) is actually quite fast already. This routine is able to beat
+ * it by 30-40% for aligned copies because of the loop unrolling, but in some
+ * cases the glibc version is still slightly faster. This lends more
+ * credibility that gcc can generate very good code as long as we are careful.
+ *
+ * Possible optimizations:
+ * - add cache prefetching
+ * - try not to use the post-increment address modifiers; they may create
+ * additional interlocks. Assumption is that those were only efficient on old
+ * machines (pre PA8000 processors)
+ */
+
+ dst = arg0
+ src = arg1
+ len = arg2
+ end = arg3
+ t1 = r19
+ t2 = r20
+ t3 = r21
+ t4 = r22
+ srcspc = sr1
+ dstspc = sr2
+
+ t0 = r1
+ a1 = t1
+ a2 = t2
+ a3 = t3
+ a0 = t4
+
+ save_src = ret0
+ save_dst = ret1
+ save_len = r31
+
+ENTRY_CFI(pa_memcpy)
+ /* Last destination address */
+ add dst,len,end
+
+ /* short copy with less than 16 bytes? */
+ cmpib,COND(>>=),n 15,len,.Lbyte_loop
+
+ /* same alignment? */
+ xor src,dst,t0
+ extru t0,31,2,t1
+ cmpib,<>,n 0,t1,.Lunaligned_copy
+
+#ifdef CONFIG_64BIT
+ /* only do 64-bit copies if we can get aligned. */
+ extru t0,31,3,t1
+ cmpib,<>,n 0,t1,.Lalign_loop32
+
+ /* loop until we are 64-bit aligned */
+.Lalign_loop64:
+ extru dst,31,3,t1
+ cmpib,=,n 0,t1,.Lcopy_loop_16_start
+20: ldb,ma 1(srcspc,src),t1
+21: stb,ma t1,1(dstspc,dst)
+ b .Lalign_loop64
+ ldo -1(len),len
+
+ ASM_EXCEPTIONTABLE_ENTRY(20b,.Lcopy_done)
+ ASM_EXCEPTIONTABLE_ENTRY(21b,.Lcopy_done)
+
+.Lcopy_loop_16_start:
+ ldi 31,t0
+.Lcopy_loop_16:
+ cmpb,COND(>>=),n t0,len,.Lword_loop
+
+10: ldd 0(srcspc,src),t1
+11: ldd 8(srcspc,src),t2
+ ldo 16(src),src
+12: std,ma t1,8(dstspc,dst)
+13: std,ma t2,8(dstspc,dst)
+14: ldd 0(srcspc,src),t1
+15: ldd 8(srcspc,src),t2
+ ldo 16(src),src
+16: std,ma t1,8(dstspc,dst)
+17: std,ma t2,8(dstspc,dst)
+
+ ASM_EXCEPTIONTABLE_ENTRY(10b,.Lcopy_done)
+ ASM_EXCEPTIONTABLE_ENTRY(11b,.Lcopy16_fault)
+ ASM_EXCEPTIONTABLE_ENTRY(12b,.Lcopy_done)
+ ASM_EXCEPTIONTABLE_ENTRY(13b,.Lcopy_done)
+ ASM_EXCEPTIONTABLE_ENTRY(14b,.Lcopy_done)
+ ASM_EXCEPTIONTABLE_ENTRY(15b,.Lcopy16_fault)
+ ASM_EXCEPTIONTABLE_ENTRY(16b,.Lcopy_done)
+ ASM_EXCEPTIONTABLE_ENTRY(17b,.Lcopy_done)
+
+ b .Lcopy_loop_16
+ ldo -32(len),len
+
+.Lword_loop:
+ cmpib,COND(>>=),n 3,len,.Lbyte_loop
+20: ldw,ma 4(srcspc,src),t1
+21: stw,ma t1,4(dstspc,dst)
+ b .Lword_loop
+ ldo -4(len),len
+
+ ASM_EXCEPTIONTABLE_ENTRY(20b,.Lcopy_done)
+ ASM_EXCEPTIONTABLE_ENTRY(21b,.Lcopy_done)
+
+#endif /* CONFIG_64BIT */
+
+ /* loop until we are 32-bit aligned */
+.Lalign_loop32:
+ extru dst,31,2,t1
+ cmpib,=,n 0,t1,.Lcopy_loop_8
+20: ldb,ma 1(srcspc,src),t1
+21: stb,ma t1,1(dstspc,dst)
+ b .Lalign_loop32
+ ldo -1(len),len
+
+ ASM_EXCEPTIONTABLE_ENTRY(20b,.Lcopy_done)
+ ASM_EXCEPTIONTABLE_ENTRY(21b,.Lcopy_done)
+
+
+.Lcopy_loop_8:
+ cmpib,COND(>>=),n 15,len,.Lbyte_loop
+
+10: ldw 0(srcspc,src),t1
+11: ldw 4(srcspc,src),t2
+12: stw,ma t1,4(dstspc,dst)
+13: stw,ma t2,4(dstspc,dst)
+14: ldw 8(srcspc,src),t1
+15: ldw 12(srcspc,src),t2
+ ldo 16(src),src
+16: stw,ma t1,4(dstspc,dst)
+17: stw,ma t2,4(dstspc,dst)
+
+ ASM_EXCEPTIONTABLE_ENTRY(10b,.Lcopy_done)
+ ASM_EXCEPTIONTABLE_ENTRY(11b,.Lcopy8_fault)
+ ASM_EXCEPTIONTABLE_ENTRY(12b,.Lcopy_done)
+ ASM_EXCEPTIONTABLE_ENTRY(13b,.Lcopy_done)
+ ASM_EXCEPTIONTABLE_ENTRY(14b,.Lcopy_done)
+ ASM_EXCEPTIONTABLE_ENTRY(15b,.Lcopy8_fault)
+ ASM_EXCEPTIONTABLE_ENTRY(16b,.Lcopy_done)
+ ASM_EXCEPTIONTABLE_ENTRY(17b,.Lcopy_done)
+
+ b .Lcopy_loop_8
+ ldo -16(len),len
+
+.Lbyte_loop:
+ cmpclr,COND(<>) len,%r0,%r0
+ b,n .Lcopy_done
+20: ldb 0(srcspc,src),t1
+ ldo 1(src),src
+21: stb,ma t1,1(dstspc,dst)
+ b .Lbyte_loop
+ ldo -1(len),len
+
+ ASM_EXCEPTIONTABLE_ENTRY(20b,.Lcopy_done)
+ ASM_EXCEPTIONTABLE_ENTRY(21b,.Lcopy_done)
+
+.Lcopy_done:
+ bv %r0(%r2)
+ sub end,dst,ret0
+
+
+ /* src and dst are not aligned the same way. */
+ /* need to go the hard way */
+.Lunaligned_copy:
+ /* align until dst is 32bit-word-aligned */
+ extru dst,31,2,t1
+ cmpib,=,n 0,t1,.Lcopy_dstaligned
+20: ldb 0(srcspc,src),t1
+ ldo 1(src),src
+21: stb,ma t1,1(dstspc,dst)
+ b .Lunaligned_copy
+ ldo -1(len),len
+
+ ASM_EXCEPTIONTABLE_ENTRY(20b,.Lcopy_done)
+ ASM_EXCEPTIONTABLE_ENTRY(21b,.Lcopy_done)
+
+.Lcopy_dstaligned:
+
+ /* store src, dst and len in safe place */
+ copy src,save_src
+ copy dst,save_dst
+ copy len,save_len
+
+ /* len now needs give number of words to copy */
+ SHRREG len,2,len
+
+ /*
+ * Copy from a not-aligned src to an aligned dst using shifts.
+ * Handles 4 words per loop.
+ */
+
+ depw,z src,28,2,t0
+ subi 32,t0,t0
+ mtsar t0
+ extru len,31,2,t0
+ cmpib,= 2,t0,.Lcase2
+ /* Make src aligned by rounding it down. */
+ depi 0,31,2,src
+
+ cmpiclr,<> 3,t0,%r0
+ b,n .Lcase3
+ cmpiclr,<> 1,t0,%r0
+ b,n .Lcase1
+.Lcase0:
+ cmpb,COND(=) %r0,len,.Lcda_finish
+ nop
+
+1: ldw,ma 4(srcspc,src), a3
+ ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
+1: ldw,ma 4(srcspc,src), a0
+ ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
+ b,n .Ldo3
+.Lcase1:
+1: ldw,ma 4(srcspc,src), a2
+ ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
+1: ldw,ma 4(srcspc,src), a3
+ ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
+ ldo -1(len),len
+ cmpb,COND(=),n %r0,len,.Ldo0
+.Ldo4:
+1: ldw,ma 4(srcspc,src), a0
+ ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
+ shrpw a2, a3, %sar, t0
+1: stw,ma t0, 4(dstspc,dst)
+ ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcopy_done)
+.Ldo3:
+1: ldw,ma 4(srcspc,src), a1
+ ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
+ shrpw a3, a0, %sar, t0
+1: stw,ma t0, 4(dstspc,dst)
+ ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcopy_done)
+.Ldo2:
+1: ldw,ma 4(srcspc,src), a2
+ ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
+ shrpw a0, a1, %sar, t0
+1: stw,ma t0, 4(dstspc,dst)
+ ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcopy_done)
+.Ldo1:
+1: ldw,ma 4(srcspc,src), a3
+ ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
+ shrpw a1, a2, %sar, t0
+1: stw,ma t0, 4(dstspc,dst)
+ ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcopy_done)
+ ldo -4(len),len
+ cmpb,COND(<>) %r0,len,.Ldo4
+ nop
+.Ldo0:
+ shrpw a2, a3, %sar, t0
+1: stw,ma t0, 4(dstspc,dst)
+ ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcopy_done)
+
+.Lcda_rdfault:
+.Lcda_finish:
+ /* calculate new src, dst and len and jump to byte-copy loop */
+ sub dst,save_dst,t0
+ add save_src,t0,src
+ b .Lbyte_loop
+ sub save_len,t0,len
+
+.Lcase3:
+1: ldw,ma 4(srcspc,src), a0
+ ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
+1: ldw,ma 4(srcspc,src), a1
+ ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
+ b .Ldo2
+ ldo 1(len),len
+.Lcase2:
+1: ldw,ma 4(srcspc,src), a1
+ ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
+1: ldw,ma 4(srcspc,src), a2
+ ASM_EXCEPTIONTABLE_ENTRY(1b,.Lcda_rdfault)
+ b .Ldo1
+ ldo 2(len),len
+
+
+ /* fault exception fixup handlers: */
+#ifdef CONFIG_64BIT
+.Lcopy16_fault:
+ b .Lcopy_done
+10: std,ma t1,8(dstspc,dst)
+ ASM_EXCEPTIONTABLE_ENTRY(10b,.Lcopy_done)
+#endif
+
+.Lcopy8_fault:
+ b .Lcopy_done
+10: stw,ma t1,4(dstspc,dst)
+ ASM_EXCEPTIONTABLE_ENTRY(10b,.Lcopy_done)
+ENDPROC_CFI(pa_memcpy)
+
+ .end
diff --git a/arch/parisc/lib/memcpy.c b/arch/parisc/lib/memcpy.c
new file mode 100644
index 000000000..5fc0c852c
--- /dev/null
+++ b/arch/parisc/lib/memcpy.c
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Optimized memory copy routines.
+ *
+ * Copyright (C) 2004 Randolph Chung <tausq@debian.org>
+ * Copyright (C) 2013-2017 Helge Deller <deller@gmx.de>
+ *
+ * Portions derived from the GNU C Library
+ * Copyright (C) 1991, 1997, 2003 Free Software Foundation, Inc.
+ */
+
+#include <linux/module.h>
+#include <linux/compiler.h>
+#include <linux/uaccess.h>
+
+#define get_user_space() mfsp(SR_USER)
+#define get_kernel_space() SR_KERNEL
+
+/* Returns 0 for success, otherwise, returns number of bytes not transferred. */
+extern unsigned long pa_memcpy(void *dst, const void *src,
+ unsigned long len);
+
+unsigned long raw_copy_to_user(void __user *dst, const void *src,
+ unsigned long len)
+{
+ mtsp(get_kernel_space(), SR_TEMP1);
+ mtsp(get_user_space(), SR_TEMP2);
+ return pa_memcpy((void __force *)dst, src, len);
+}
+EXPORT_SYMBOL(raw_copy_to_user);
+
+unsigned long raw_copy_from_user(void *dst, const void __user *src,
+ unsigned long len)
+{
+ mtsp(get_user_space(), SR_TEMP1);
+ mtsp(get_kernel_space(), SR_TEMP2);
+ return pa_memcpy(dst, (void __force *)src, len);
+}
+EXPORT_SYMBOL(raw_copy_from_user);
+
+void * memcpy(void * dst,const void *src, size_t count)
+{
+ mtsp(get_kernel_space(), SR_TEMP1);
+ mtsp(get_kernel_space(), SR_TEMP2);
+ pa_memcpy(dst, src, count);
+ return dst;
+}
+
+EXPORT_SYMBOL(memcpy);
+
+bool copy_from_kernel_nofault_allowed(const void *unsafe_src, size_t size)
+{
+ if ((unsigned long)unsafe_src < PAGE_SIZE)
+ return false;
+ /* check for I/O space F_EXTEND(0xfff00000) access as well? */
+ return true;
+}
diff --git a/arch/parisc/lib/memset.c b/arch/parisc/lib/memset.c
new file mode 100644
index 000000000..133e48098
--- /dev/null
+++ b/arch/parisc/lib/memset.c
@@ -0,0 +1,72 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#include <linux/types.h>
+#include <asm/string.h>
+
+#define OPSIZ (BITS_PER_LONG/8)
+typedef unsigned long op_t;
+
+void *
+memset (void *dstpp, int sc, size_t len)
+{
+ unsigned int c = sc;
+ long int dstp = (long int) dstpp;
+
+ if (len >= 8)
+ {
+ size_t xlen;
+ op_t cccc;
+
+ cccc = (unsigned char) c;
+ cccc |= cccc << 8;
+ cccc |= cccc << 16;
+ if (OPSIZ > 4)
+ /* Do the shift in two steps to avoid warning if long has 32 bits. */
+ cccc |= (cccc << 16) << 16;
+
+ /* There are at least some bytes to set.
+ No need to test for LEN == 0 in this alignment loop. */
+ while (dstp % OPSIZ != 0)
+ {
+ ((unsigned char *) dstp)[0] = c;
+ dstp += 1;
+ len -= 1;
+ }
+
+ /* Write 8 `op_t' per iteration until less than 8 `op_t' remain. */
+ xlen = len / (OPSIZ * 8);
+ while (xlen > 0)
+ {
+ ((op_t *) dstp)[0] = cccc;
+ ((op_t *) dstp)[1] = cccc;
+ ((op_t *) dstp)[2] = cccc;
+ ((op_t *) dstp)[3] = cccc;
+ ((op_t *) dstp)[4] = cccc;
+ ((op_t *) dstp)[5] = cccc;
+ ((op_t *) dstp)[6] = cccc;
+ ((op_t *) dstp)[7] = cccc;
+ dstp += 8 * OPSIZ;
+ xlen -= 1;
+ }
+ len %= OPSIZ * 8;
+
+ /* Write 1 `op_t' per iteration until less than OPSIZ bytes remain. */
+ xlen = len / OPSIZ;
+ while (xlen > 0)
+ {
+ ((op_t *) dstp)[0] = cccc;
+ dstp += OPSIZ;
+ xlen -= 1;
+ }
+ len %= OPSIZ;
+ }
+
+ /* Write the last few bytes. */
+ while (len > 0)
+ {
+ ((unsigned char *) dstp)[0] = c;
+ dstp += 1;
+ len -= 1;
+ }
+
+ return dstpp;
+}
diff --git a/arch/parisc/lib/ucmpdi2.c b/arch/parisc/lib/ucmpdi2.c
new file mode 100644
index 000000000..9d8b4dbae
--- /dev/null
+++ b/arch/parisc/lib/ucmpdi2.c
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/module.h>
+#include <linux/libgcc.h>
+
+union ull_union {
+ unsigned long long ull;
+ struct {
+ unsigned int high;
+ unsigned int low;
+ } ui;
+};
+
+word_type __ucmpdi2(unsigned long long a, unsigned long long b)
+{
+ union ull_union au = {.ull = a};
+ union ull_union bu = {.ull = b};
+
+ if (au.ui.high < bu.ui.high)
+ return 0;
+ else if (au.ui.high > bu.ui.high)
+ return 2;
+ if (au.ui.low < bu.ui.low)
+ return 0;
+ else if (au.ui.low > bu.ui.low)
+ return 2;
+ return 1;
+}
diff --git a/arch/parisc/math-emu/Makefile b/arch/parisc/math-emu/Makefile
new file mode 100644
index 000000000..7b64740e1
--- /dev/null
+++ b/arch/parisc/math-emu/Makefile
@@ -0,0 +1,22 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for the linux/parisc floating point code
+#
+
+# See arch/parisc/math-emu/README
+ccflags-y := -Wno-parentheses -Wno-implicit-function-declaration \
+ -Wno-uninitialized -Wno-strict-prototypes -Wno-return-type \
+ -Wno-implicit-int -Wno-missing-prototypes -Wno-missing-declarations \
+ -Wno-old-style-definition -Wno-unused-but-set-variable
+
+obj-y := frnd.o driver.o decode_exc.o fpudispatch.o denormal.o \
+ dfmpy.o sfmpy.o sfsqrt.o dfsqrt.o dfadd.o fmpyfadd.o \
+ sfadd.o dfsub.o sfsub.o fcnvfxt.o fcnvff.o fcnvxf.o \
+ fcnvfx.o fcnvuf.o fcnvfu.o fcnvfut.o dfdiv.o sfdiv.o \
+ dfrem.o sfrem.o dfcmp.o sfcmp.o
+
+# Math emulation code beyond the FRND is required for 712/80i and
+# other very old or stripped-down PA-RISC CPUs -- not currently supported
+
+obj-$(CONFIG_MATH_EMULATION) += unimplemented-math-emulation.o
+CFLAGS_REMOVE_fpudispatch.o = -Wimplicit-fallthrough
diff --git a/arch/parisc/math-emu/README b/arch/parisc/math-emu/README
new file mode 100644
index 000000000..1a0124ef0
--- /dev/null
+++ b/arch/parisc/math-emu/README
@@ -0,0 +1,11 @@
+All files except driver.c are snapshots from the HP-UX kernel. They've
+been modified as little as possible. Even though they don't fit the
+Linux coding style, please leave them in their funny format just in case
+someone in the future, with access to HP-UX source code, is generous
+enough to update our copies with later changes from HP-UX -- it'll
+make their 'diff' job easier if our code is relatively unmodified.
+
+Required Disclaimer: Hewlett-Packard makes no implied or expressed
+warranties about this code nor any promises to maintain or test it
+in any way. This copy of this snapshot is no longer the property
+of Hewlett-Packard.
diff --git a/arch/parisc/math-emu/cnv_float.h b/arch/parisc/math-emu/cnv_float.h
new file mode 100644
index 000000000..ef783a383
--- /dev/null
+++ b/arch/parisc/math-emu/cnv_float.h
@@ -0,0 +1,363 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ */
+
+#ifdef __NO_PA_HDRS
+ PA header file -- do not include this header file for non-PA builds.
+#endif
+
+/*
+ * Some more constants
+ */
+#define SGL_FX_MAX_EXP 30
+#define DBL_FX_MAX_EXP 62
+#define QUAD_FX_MAX_EXP 126
+
+#define Dintp1(object) (object)
+#define Dintp2(object) (object)
+
+#define Duintp1(object) (object)
+#define Duintp2(object) (object)
+
+#define Qintp0(object) (object)
+#define Qintp1(object) (object)
+#define Qintp2(object) (object)
+#define Qintp3(object) (object)
+
+
+/*
+ * These macros will be used specifically by the convert instructions.
+ *
+ *
+ * Single format macros
+ */
+
+#define Sgl_to_dbl_exponent(src_exponent,dest) \
+ Deposit_dexponent(dest,src_exponent+(DBL_BIAS-SGL_BIAS))
+
+#define Sgl_to_dbl_mantissa(src_mantissa,destA,destB) \
+ Deposit_dmantissap1(destA,src_mantissa>>3); \
+ Dmantissap2(destB) = src_mantissa << 29
+
+#define Sgl_isinexact_to_fix(sgl_value,exponent) \
+ ((exponent < (SGL_P - 1)) ? \
+ (Sall(sgl_value) << (SGL_EXP_LENGTH + 1 + exponent)) : FALSE)
+
+#define Int_isinexact_to_sgl(int_value) ((int_value << 33 - SGL_EXP_LENGTH) != 0)
+
+#define Sgl_roundnearest_from_int(int_value,sgl_value) \
+ if (int_value & 1<<(SGL_EXP_LENGTH - 2)) /* round bit */ \
+ if (((int_value << 34 - SGL_EXP_LENGTH) != 0) || Slow(sgl_value)) \
+ Sall(sgl_value)++
+
+#define Dint_isinexact_to_sgl(dint_valueA,dint_valueB) \
+ (((Dintp1(dint_valueA) << 33 - SGL_EXP_LENGTH) != 0) || Dintp2(dint_valueB))
+
+#define Sgl_roundnearest_from_dint(dint_valueA,dint_valueB,sgl_value) \
+ if (Dintp1(dint_valueA) & 1<<(SGL_EXP_LENGTH - 2)) \
+ if (((Dintp1(dint_valueA) << 34 - SGL_EXP_LENGTH) != 0) || \
+ Dintp2(dint_valueB) || Slow(sgl_value)) Sall(sgl_value)++
+
+#define Dint_isinexact_to_dbl(dint_value) \
+ (Dintp2(dint_value) << 33 - DBL_EXP_LENGTH)
+
+#define Dbl_roundnearest_from_dint(dint_opndB,dbl_opndA,dbl_opndB) \
+ if (Dintp2(dint_opndB) & 1<<(DBL_EXP_LENGTH - 2)) \
+ if ((Dintp2(dint_opndB) << 34 - DBL_EXP_LENGTH) || Dlowp2(dbl_opndB)) \
+ if ((++Dallp2(dbl_opndB))==0) Dallp1(dbl_opndA)++
+
+#define Sgl_isone_roundbit(sgl_value,exponent) \
+ ((Sall(sgl_value) << (SGL_EXP_LENGTH + 1 + exponent)) >> 31)
+
+#define Sgl_isone_stickybit(sgl_value,exponent) \
+ (exponent < (SGL_P - 2) ? \
+ Sall(sgl_value) << (SGL_EXP_LENGTH + 2 + exponent) : FALSE)
+
+
+/*
+ * Double format macros
+ */
+
+#define Dbl_to_sgl_exponent(src_exponent,dest) \
+ dest = src_exponent + (SGL_BIAS - DBL_BIAS)
+
+#define Dbl_to_sgl_mantissa(srcA,srcB,dest,inexact,guard,sticky,odd) \
+ Shiftdouble(Dmantissap1(srcA),Dmantissap2(srcB),29,dest); \
+ guard = Dbit3p2(srcB); \
+ sticky = Dallp2(srcB)<<4; \
+ inexact = guard | sticky; \
+ odd = Dbit2p2(srcB)
+
+#define Dbl_to_sgl_denormalized(srcA,srcB,exp,dest,inexact,guard,sticky,odd,tiny) \
+ Deposit_dexponent(srcA,1); \
+ tiny = TRUE; \
+ if (exp >= -2) { \
+ if (exp == 0) { \
+ inexact = Dallp2(srcB) << 3; \
+ guard = inexact >> 31; \
+ sticky = inexact << 1; \
+ Shiftdouble(Dmantissap1(srcA),Dmantissap2(srcB),29,dest); \
+ odd = dest << 31; \
+ if (inexact) { \
+ switch(Rounding_mode()) { \
+ case ROUNDPLUS: \
+ if (Dbl_iszero_sign(srcA)) { \
+ dest++; \
+ if (Sgl_isone_hidden(dest)) \
+ tiny = FALSE; \
+ dest--; \
+ } \
+ break; \
+ case ROUNDMINUS: \
+ if (Dbl_isone_sign(srcA)) { \
+ dest++; \
+ if (Sgl_isone_hidden(dest)) \
+ tiny = FALSE; \
+ dest--; \
+ } \
+ break; \
+ case ROUNDNEAREST: \
+ if (guard && (sticky || odd)) { \
+ dest++; \
+ if (Sgl_isone_hidden(dest)) \
+ tiny = FALSE; \
+ dest--; \
+ } \
+ break; \
+ } \
+ } \
+ /* shift right by one to get correct result */ \
+ guard = odd; \
+ sticky = inexact; \
+ inexact |= guard; \
+ dest >>= 1; \
+ Deposit_dsign(srcA,0); \
+ Shiftdouble(Dallp1(srcA),Dallp2(srcB),30,dest); \
+ odd = dest << 31; \
+ } \
+ else { \
+ inexact = Dallp2(srcB) << (2 + exp); \
+ guard = inexact >> 31; \
+ sticky = inexact << 1; \
+ Deposit_dsign(srcA,0); \
+ if (exp == -2) dest = Dallp1(srcA); \
+ else Variable_shift_double(Dallp1(srcA),Dallp2(srcB),30-exp,dest); \
+ odd = dest << 31; \
+ } \
+ } \
+ else { \
+ Deposit_dsign(srcA,0); \
+ if (exp > (1 - SGL_P)) { \
+ dest = Dallp1(srcA) >> (- 2 - exp); \
+ inexact = Dallp1(srcA) << (34 + exp); \
+ guard = inexact >> 31; \
+ sticky = (inexact << 1) | Dallp2(srcB); \
+ inexact |= Dallp2(srcB); \
+ odd = dest << 31; \
+ } \
+ else { \
+ dest = 0; \
+ inexact = Dallp1(srcA) | Dallp2(srcB); \
+ if (exp == (1 - SGL_P)) { \
+ guard = Dhidden(srcA); \
+ sticky = Dmantissap1(srcA) | Dallp2(srcB); \
+ } \
+ else { \
+ guard = 0; \
+ sticky = inexact; \
+ } \
+ odd = 0; \
+ } \
+ } \
+ exp = 0
+
+#define Dbl_isinexact_to_fix(dbl_valueA,dbl_valueB,exponent) \
+ (exponent < (DBL_P-33) ? \
+ Dallp2(dbl_valueB) || Dallp1(dbl_valueA) << (DBL_EXP_LENGTH+1+exponent) : \
+ (exponent < (DBL_P-1) ? Dallp2(dbl_valueB) << (exponent + (33-DBL_P)) : \
+ FALSE))
+
+#define Dbl_isoverflow_to_int(exponent,dbl_valueA,dbl_valueB) \
+ ((exponent > SGL_FX_MAX_EXP + 1) || Dsign(dbl_valueA)==0 || \
+ Dmantissap1(dbl_valueA)!=0 || (Dallp2(dbl_valueB)>>21)!=0 )
+
+#define Dbl_isone_roundbit(dbl_valueA,dbl_valueB,exponent) \
+ ((exponent < (DBL_P - 33) ? \
+ Dallp1(dbl_valueA) >> ((30 - DBL_EXP_LENGTH) - exponent) : \
+ Dallp2(dbl_valueB) >> ((DBL_P - 2) - exponent)) & 1)
+
+#define Dbl_isone_stickybit(dbl_valueA,dbl_valueB,exponent) \
+ (exponent < (DBL_P-34) ? \
+ (Dallp2(dbl_valueB) || Dallp1(dbl_valueA)<<(DBL_EXP_LENGTH+2+exponent)) : \
+ (exponent<(DBL_P-2) ? (Dallp2(dbl_valueB) << (exponent + (34-DBL_P))) : \
+ FALSE))
+
+
+/* Int macros */
+
+#define Int_from_sgl_mantissa(sgl_value,exponent) \
+ Sall(sgl_value) = \
+ (unsigned)(Sall(sgl_value) << SGL_EXP_LENGTH)>>(31 - exponent)
+
+#define Int_from_dbl_mantissa(dbl_valueA,dbl_valueB,exponent) \
+ Shiftdouble(Dallp1(dbl_valueA),Dallp2(dbl_valueB),22,Dallp1(dbl_valueA)); \
+ if (exponent < 31) Dallp1(dbl_valueA) >>= 30 - exponent; \
+ else Dallp1(dbl_valueA) <<= 1
+
+#define Int_negate(int_value) int_value = -int_value
+
+
+/* Dint macros */
+
+#define Dint_from_sgl_mantissa(sgl_value,exponent,dresultA,dresultB) \
+ {Sall(sgl_value) <<= SGL_EXP_LENGTH; /* left-justify */ \
+ if (exponent <= 31) { \
+ Dintp1(dresultA) = 0; \
+ Dintp2(dresultB) = (unsigned)Sall(sgl_value) >> (31 - exponent); \
+ } \
+ else { \
+ Dintp1(dresultA) = Sall(sgl_value) >> (63 - exponent); \
+ Dintp2(dresultB) = Sall(sgl_value) << (exponent - 31); \
+ }}
+
+
+#define Dint_from_dbl_mantissa(dbl_valueA,dbl_valueB,exponent,destA,destB) \
+ {if (exponent < 32) { \
+ Dintp1(destA) = 0; \
+ if (exponent <= 20) \
+ Dintp2(destB) = Dallp1(dbl_valueA) >> 20-exponent; \
+ else Variable_shift_double(Dallp1(dbl_valueA),Dallp2(dbl_valueB), \
+ 52-exponent,Dintp2(destB)); \
+ } \
+ else { \
+ if (exponent <= 52) { \
+ Dintp1(destA) = Dallp1(dbl_valueA) >> 52-exponent; \
+ if (exponent == 52) Dintp2(destB) = Dallp2(dbl_valueB); \
+ else Variable_shift_double(Dallp1(dbl_valueA),Dallp2(dbl_valueB), \
+ 52-exponent,Dintp2(destB)); \
+ } \
+ else { \
+ Variable_shift_double(Dallp1(dbl_valueA),Dallp2(dbl_valueB), \
+ 84-exponent,Dintp1(destA)); \
+ Dintp2(destB) = Dallp2(dbl_valueB) << exponent-52; \
+ } \
+ }}
+
+#define Dint_setzero(dresultA,dresultB) \
+ Dintp1(dresultA) = 0; \
+ Dintp2(dresultB) = 0
+
+#define Dint_setone_sign(dresultA,dresultB) \
+ Dintp1(dresultA) = ~Dintp1(dresultA); \
+ if ((Dintp2(dresultB) = -Dintp2(dresultB)) == 0) Dintp1(dresultA)++
+
+#define Dint_set_minint(dresultA,dresultB) \
+ Dintp1(dresultA) = (unsigned int)1<<31; \
+ Dintp2(dresultB) = 0
+
+#define Dint_isone_lowp2(dresultB) (Dintp2(dresultB) & 01)
+
+#define Dint_increment(dresultA,dresultB) \
+ if ((++Dintp2(dresultB))==0) Dintp1(dresultA)++
+
+#define Dint_decrement(dresultA,dresultB) \
+ if ((Dintp2(dresultB)--)==0) Dintp1(dresultA)--
+
+#define Dint_negate(dresultA,dresultB) \
+ Dintp1(dresultA) = ~Dintp1(dresultA); \
+ if ((Dintp2(dresultB) = -Dintp2(dresultB))==0) Dintp1(dresultA)++
+
+#define Dint_copyfromptr(src,destA,destB) \
+ Dintp1(destA) = src->wd0; \
+ Dintp2(destB) = src->wd1
+#define Dint_copytoptr(srcA,srcB,dest) \
+ dest->wd0 = Dintp1(srcA); \
+ dest->wd1 = Dintp2(srcB)
+
+
+/* other macros */
+
+#define Find_ms_one_bit(value, position) \
+ { \
+ int var; \
+ for (var=8; var >=1; var >>= 1) { \
+ if (value >> 32 - position) \
+ position -= var; \
+ else position += var; \
+ } \
+ if ((value >> 32 - position) == 0) \
+ position--; \
+ else position -= 2; \
+ }
+
+
+/*
+ * Unsigned int macros
+ */
+#define Duint_copyfromptr(src,destA,destB) \
+ Dint_copyfromptr(src,destA,destB)
+#define Duint_copytoptr(srcA,srcB,dest) \
+ Dint_copytoptr(srcA,srcB,dest)
+
+#define Suint_isinexact_to_sgl(int_value) \
+ (int_value << 32 - SGL_EXP_LENGTH)
+
+#define Sgl_roundnearest_from_suint(suint_value,sgl_value) \
+ if (suint_value & 1<<(SGL_EXP_LENGTH - 1)) /* round bit */ \
+ if ((suint_value << 33 - SGL_EXP_LENGTH) || Slow(sgl_value)) \
+ Sall(sgl_value)++
+
+#define Duint_isinexact_to_sgl(duint_valueA,duint_valueB) \
+ ((Duintp1(duint_valueA) << 32 - SGL_EXP_LENGTH) || Duintp2(duint_valueB))
+
+#define Sgl_roundnearest_from_duint(duint_valueA,duint_valueB,sgl_value) \
+ if (Duintp1(duint_valueA) & 1<<(SGL_EXP_LENGTH - 1)) \
+ if ((Duintp1(duint_valueA) << 33 - SGL_EXP_LENGTH) || \
+ Duintp2(duint_valueB) || Slow(sgl_value)) Sall(sgl_value)++
+
+#define Duint_isinexact_to_dbl(duint_value) \
+ (Duintp2(duint_value) << 32 - DBL_EXP_LENGTH)
+
+#define Dbl_roundnearest_from_duint(duint_opndB,dbl_opndA,dbl_opndB) \
+ if (Duintp2(duint_opndB) & 1<<(DBL_EXP_LENGTH - 1)) \
+ if ((Duintp2(duint_opndB) << 33 - DBL_EXP_LENGTH) || Dlowp2(dbl_opndB)) \
+ if ((++Dallp2(dbl_opndB))==0) Dallp1(dbl_opndA)++
+
+#define Suint_from_sgl_mantissa(src,exponent,result) \
+ Sall(result) = (unsigned)(Sall(src) << SGL_EXP_LENGTH)>>(31 - exponent)
+
+#define Sgl_isinexact_to_unsigned(sgl_value,exponent) \
+ Sgl_isinexact_to_fix(sgl_value,exponent)
+
+#define Duint_from_sgl_mantissa(sgl_value,exponent,dresultA,dresultB) \
+ {unsigned int val = Sall(sgl_value) << SGL_EXP_LENGTH; \
+ if (exponent <= 31) { \
+ Dintp1(dresultA) = 0; \
+ Dintp2(dresultB) = val >> (31 - exponent); \
+ } \
+ else { \
+ Dintp1(dresultA) = val >> (63 - exponent); \
+ Dintp2(dresultB) = exponent <= 62 ? val << (exponent - 31) : 0; \
+ } \
+ }
+
+#define Duint_setzero(dresultA,dresultB) \
+ Dint_setzero(dresultA,dresultB)
+
+#define Duint_increment(dresultA,dresultB) Dint_increment(dresultA,dresultB)
+
+#define Duint_isone_lowp2(dresultB) Dint_isone_lowp2(dresultB)
+
+#define Suint_from_dbl_mantissa(srcA,srcB,exponent,dest) \
+ Shiftdouble(Dallp1(srcA),Dallp2(srcB),21,dest); \
+ dest = (unsigned)dest >> 31 - exponent
+
+#define Dbl_isinexact_to_unsigned(dbl_valueA,dbl_valueB,exponent) \
+ Dbl_isinexact_to_fix(dbl_valueA,dbl_valueB,exponent)
+
+#define Duint_from_dbl_mantissa(dbl_valueA,dbl_valueB,exponent,destA,destB) \
+ Dint_from_dbl_mantissa(dbl_valueA,dbl_valueB,exponent,destA,destB)
diff --git a/arch/parisc/math-emu/dbl_float.h b/arch/parisc/math-emu/dbl_float.h
new file mode 100644
index 000000000..e57fee8e1
--- /dev/null
+++ b/arch/parisc/math-emu/dbl_float.h
@@ -0,0 +1,834 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ */
+#ifdef __NO_PA_HDRS
+ PA header file -- do not include this header file for non-PA builds.
+#endif
+
+/* 32-bit word grabbing functions */
+#define Dbl_firstword(value) Dallp1(value)
+#define Dbl_secondword(value) Dallp2(value)
+#define Dbl_thirdword(value) dummy_location
+#define Dbl_fourthword(value) dummy_location
+
+#define Dbl_sign(object) Dsign(object)
+#define Dbl_exponent(object) Dexponent(object)
+#define Dbl_signexponent(object) Dsignexponent(object)
+#define Dbl_mantissap1(object) Dmantissap1(object)
+#define Dbl_mantissap2(object) Dmantissap2(object)
+#define Dbl_exponentmantissap1(object) Dexponentmantissap1(object)
+#define Dbl_allp1(object) Dallp1(object)
+#define Dbl_allp2(object) Dallp2(object)
+
+/* dbl_and_signs ANDs the sign bits of each argument and puts the result
+ * into the first argument. dbl_or_signs ors those same sign bits */
+#define Dbl_and_signs( src1dst, src2) \
+ Dallp1(src1dst) = (Dallp1(src2)|~((unsigned int)1<<31)) & Dallp1(src1dst)
+#define Dbl_or_signs( src1dst, src2) \
+ Dallp1(src1dst) = (Dallp1(src2)&((unsigned int)1<<31)) | Dallp1(src1dst)
+
+/* The hidden bit is always the low bit of the exponent */
+#define Dbl_clear_exponent_set_hidden(srcdst) Deposit_dexponent(srcdst,1)
+#define Dbl_clear_signexponent_set_hidden(srcdst) \
+ Deposit_dsignexponent(srcdst,1)
+#define Dbl_clear_sign(srcdst) Dallp1(srcdst) &= ~((unsigned int)1<<31)
+#define Dbl_clear_signexponent(srcdst) \
+ Dallp1(srcdst) &= Dmantissap1((unsigned int)-1)
+
+/* Exponent field for doubles has already been cleared and may be
+ * included in the shift. Here we need to generate two double width
+ * variable shifts. The insignificant bits can be ignored.
+ * MTSAR f(varamount)
+ * VSHD srcdst.high,srcdst.low => srcdst.low
+ * VSHD 0,srcdst.high => srcdst.high
+ * This is very difficult to model with C expressions since the shift amount
+ * could exceed 32. */
+/* varamount must be less than 64 */
+#define Dbl_rightshift(srcdstA, srcdstB, varamount) \
+ {if((varamount) >= 32) { \
+ Dallp2(srcdstB) = Dallp1(srcdstA) >> (varamount-32); \
+ Dallp1(srcdstA)=0; \
+ } \
+ else if(varamount > 0) { \
+ Variable_shift_double(Dallp1(srcdstA), Dallp2(srcdstB), \
+ (varamount), Dallp2(srcdstB)); \
+ Dallp1(srcdstA) >>= varamount; \
+ } }
+/* varamount must be less than 64 */
+#define Dbl_rightshift_exponentmantissa(srcdstA, srcdstB, varamount) \
+ {if((varamount) >= 32) { \
+ Dallp2(srcdstB) = Dexponentmantissap1(srcdstA) >> (varamount-32); \
+ Dallp1(srcdstA) &= ((unsigned int)1<<31); /* clear expmant field */ \
+ } \
+ else if(varamount > 0) { \
+ Variable_shift_double(Dexponentmantissap1(srcdstA), Dallp2(srcdstB), \
+ (varamount), Dallp2(srcdstB)); \
+ Deposit_dexponentmantissap1(srcdstA, \
+ (Dexponentmantissap1(srcdstA)>>varamount)); \
+ } }
+/* varamount must be less than 64 */
+#define Dbl_leftshift(srcdstA, srcdstB, varamount) \
+ {if((varamount) >= 32) { \
+ Dallp1(srcdstA) = Dallp2(srcdstB) << (varamount-32); \
+ Dallp2(srcdstB)=0; \
+ } \
+ else { \
+ if ((varamount) > 0) { \
+ Dallp1(srcdstA) = (Dallp1(srcdstA) << (varamount)) | \
+ (Dallp2(srcdstB) >> (32-(varamount))); \
+ Dallp2(srcdstB) <<= varamount; \
+ } \
+ } }
+#define Dbl_leftshiftby1_withextent(lefta,leftb,right,resulta,resultb) \
+ Shiftdouble(Dallp1(lefta), Dallp2(leftb), 31, Dallp1(resulta)); \
+ Shiftdouble(Dallp2(leftb), Extall(right), 31, Dallp2(resultb))
+
+#define Dbl_rightshiftby1_withextent(leftb,right,dst) \
+ Extall(dst) = (Dallp2(leftb) << 31) | ((unsigned int)Extall(right) >> 1) | \
+ Extlow(right)
+
+#define Dbl_arithrightshiftby1(srcdstA,srcdstB) \
+ Shiftdouble(Dallp1(srcdstA),Dallp2(srcdstB),1,Dallp2(srcdstB));\
+ Dallp1(srcdstA) = (int)Dallp1(srcdstA) >> 1
+
+/* Sign extend the sign bit with an integer destination */
+#define Dbl_signextendedsign(value) Dsignedsign(value)
+
+#define Dbl_isone_hidden(dbl_value) (Is_dhidden(dbl_value)!=0)
+/* Singles and doubles may include the sign and exponent fields. The
+ * hidden bit and the hidden overflow must be included. */
+#define Dbl_increment(dbl_valueA,dbl_valueB) \
+ if( (Dallp2(dbl_valueB) += 1) == 0 ) Dallp1(dbl_valueA) += 1
+#define Dbl_increment_mantissa(dbl_valueA,dbl_valueB) \
+ if( (Dmantissap2(dbl_valueB) += 1) == 0 ) \
+ Deposit_dmantissap1(dbl_valueA,dbl_valueA+1)
+#define Dbl_decrement(dbl_valueA,dbl_valueB) \
+ if( Dallp2(dbl_valueB) == 0 ) Dallp1(dbl_valueA) -= 1; \
+ Dallp2(dbl_valueB) -= 1
+
+#define Dbl_isone_sign(dbl_value) (Is_dsign(dbl_value)!=0)
+#define Dbl_isone_hiddenoverflow(dbl_value) (Is_dhiddenoverflow(dbl_value)!=0)
+#define Dbl_isone_lowmantissap1(dbl_valueA) (Is_dlowp1(dbl_valueA)!=0)
+#define Dbl_isone_lowmantissap2(dbl_valueB) (Is_dlowp2(dbl_valueB)!=0)
+#define Dbl_isone_signaling(dbl_value) (Is_dsignaling(dbl_value)!=0)
+#define Dbl_is_signalingnan(dbl_value) (Dsignalingnan(dbl_value)==0xfff)
+#define Dbl_isnotzero(dbl_valueA,dbl_valueB) \
+ (Dallp1(dbl_valueA) || Dallp2(dbl_valueB))
+#define Dbl_isnotzero_hiddenhigh7mantissa(dbl_value) \
+ (Dhiddenhigh7mantissa(dbl_value)!=0)
+#define Dbl_isnotzero_exponent(dbl_value) (Dexponent(dbl_value)!=0)
+#define Dbl_isnotzero_mantissa(dbl_valueA,dbl_valueB) \
+ (Dmantissap1(dbl_valueA) || Dmantissap2(dbl_valueB))
+#define Dbl_isnotzero_mantissap1(dbl_valueA) (Dmantissap1(dbl_valueA)!=0)
+#define Dbl_isnotzero_mantissap2(dbl_valueB) (Dmantissap2(dbl_valueB)!=0)
+#define Dbl_isnotzero_exponentmantissa(dbl_valueA,dbl_valueB) \
+ (Dexponentmantissap1(dbl_valueA) || Dmantissap2(dbl_valueB))
+#define Dbl_isnotzero_low4p2(dbl_value) (Dlow4p2(dbl_value)!=0)
+#define Dbl_iszero(dbl_valueA,dbl_valueB) (Dallp1(dbl_valueA)==0 && \
+ Dallp2(dbl_valueB)==0)
+#define Dbl_iszero_allp1(dbl_value) (Dallp1(dbl_value)==0)
+#define Dbl_iszero_allp2(dbl_value) (Dallp2(dbl_value)==0)
+#define Dbl_iszero_hidden(dbl_value) (Is_dhidden(dbl_value)==0)
+#define Dbl_iszero_hiddenoverflow(dbl_value) (Is_dhiddenoverflow(dbl_value)==0)
+#define Dbl_iszero_hiddenhigh3mantissa(dbl_value) \
+ (Dhiddenhigh3mantissa(dbl_value)==0)
+#define Dbl_iszero_hiddenhigh7mantissa(dbl_value) \
+ (Dhiddenhigh7mantissa(dbl_value)==0)
+#define Dbl_iszero_sign(dbl_value) (Is_dsign(dbl_value)==0)
+#define Dbl_iszero_exponent(dbl_value) (Dexponent(dbl_value)==0)
+#define Dbl_iszero_mantissa(dbl_valueA,dbl_valueB) \
+ (Dmantissap1(dbl_valueA)==0 && Dmantissap2(dbl_valueB)==0)
+#define Dbl_iszero_exponentmantissa(dbl_valueA,dbl_valueB) \
+ (Dexponentmantissap1(dbl_valueA)==0 && Dmantissap2(dbl_valueB)==0)
+#define Dbl_isinfinity_exponent(dbl_value) \
+ (Dexponent(dbl_value)==DBL_INFINITY_EXPONENT)
+#define Dbl_isnotinfinity_exponent(dbl_value) \
+ (Dexponent(dbl_value)!=DBL_INFINITY_EXPONENT)
+#define Dbl_isinfinity(dbl_valueA,dbl_valueB) \
+ (Dexponent(dbl_valueA)==DBL_INFINITY_EXPONENT && \
+ Dmantissap1(dbl_valueA)==0 && Dmantissap2(dbl_valueB)==0)
+#define Dbl_isnan(dbl_valueA,dbl_valueB) \
+ (Dexponent(dbl_valueA)==DBL_INFINITY_EXPONENT && \
+ (Dmantissap1(dbl_valueA)!=0 || Dmantissap2(dbl_valueB)!=0))
+#define Dbl_isnotnan(dbl_valueA,dbl_valueB) \
+ (Dexponent(dbl_valueA)!=DBL_INFINITY_EXPONENT || \
+ (Dmantissap1(dbl_valueA)==0 && Dmantissap2(dbl_valueB)==0))
+
+#define Dbl_islessthan(dbl_op1a,dbl_op1b,dbl_op2a,dbl_op2b) \
+ (Dallp1(dbl_op1a) < Dallp1(dbl_op2a) || \
+ (Dallp1(dbl_op1a) == Dallp1(dbl_op2a) && \
+ Dallp2(dbl_op1b) < Dallp2(dbl_op2b)))
+#define Dbl_isgreaterthan(dbl_op1a,dbl_op1b,dbl_op2a,dbl_op2b) \
+ (Dallp1(dbl_op1a) > Dallp1(dbl_op2a) || \
+ (Dallp1(dbl_op1a) == Dallp1(dbl_op2a) && \
+ Dallp2(dbl_op1b) > Dallp2(dbl_op2b)))
+#define Dbl_isnotlessthan(dbl_op1a,dbl_op1b,dbl_op2a,dbl_op2b) \
+ (Dallp1(dbl_op1a) > Dallp1(dbl_op2a) || \
+ (Dallp1(dbl_op1a) == Dallp1(dbl_op2a) && \
+ Dallp2(dbl_op1b) >= Dallp2(dbl_op2b)))
+#define Dbl_isnotgreaterthan(dbl_op1a,dbl_op1b,dbl_op2a,dbl_op2b) \
+ (Dallp1(dbl_op1a) < Dallp1(dbl_op2a) || \
+ (Dallp1(dbl_op1a) == Dallp1(dbl_op2a) && \
+ Dallp2(dbl_op1b) <= Dallp2(dbl_op2b)))
+#define Dbl_isequal(dbl_op1a,dbl_op1b,dbl_op2a,dbl_op2b) \
+ ((Dallp1(dbl_op1a) == Dallp1(dbl_op2a)) && \
+ (Dallp2(dbl_op1b) == Dallp2(dbl_op2b)))
+
+#define Dbl_leftshiftby8(dbl_valueA,dbl_valueB) \
+ Shiftdouble(Dallp1(dbl_valueA),Dallp2(dbl_valueB),24,Dallp1(dbl_valueA)); \
+ Dallp2(dbl_valueB) <<= 8
+#define Dbl_leftshiftby7(dbl_valueA,dbl_valueB) \
+ Shiftdouble(Dallp1(dbl_valueA),Dallp2(dbl_valueB),25,Dallp1(dbl_valueA)); \
+ Dallp2(dbl_valueB) <<= 7
+#define Dbl_leftshiftby4(dbl_valueA,dbl_valueB) \
+ Shiftdouble(Dallp1(dbl_valueA),Dallp2(dbl_valueB),28,Dallp1(dbl_valueA)); \
+ Dallp2(dbl_valueB) <<= 4
+#define Dbl_leftshiftby3(dbl_valueA,dbl_valueB) \
+ Shiftdouble(Dallp1(dbl_valueA),Dallp2(dbl_valueB),29,Dallp1(dbl_valueA)); \
+ Dallp2(dbl_valueB) <<= 3
+#define Dbl_leftshiftby2(dbl_valueA,dbl_valueB) \
+ Shiftdouble(Dallp1(dbl_valueA),Dallp2(dbl_valueB),30,Dallp1(dbl_valueA)); \
+ Dallp2(dbl_valueB) <<= 2
+#define Dbl_leftshiftby1(dbl_valueA,dbl_valueB) \
+ Shiftdouble(Dallp1(dbl_valueA),Dallp2(dbl_valueB),31,Dallp1(dbl_valueA)); \
+ Dallp2(dbl_valueB) <<= 1
+
+#define Dbl_rightshiftby8(dbl_valueA,dbl_valueB) \
+ Shiftdouble(Dallp1(dbl_valueA),Dallp2(dbl_valueB),8,Dallp2(dbl_valueB)); \
+ Dallp1(dbl_valueA) >>= 8
+#define Dbl_rightshiftby4(dbl_valueA,dbl_valueB) \
+ Shiftdouble(Dallp1(dbl_valueA),Dallp2(dbl_valueB),4,Dallp2(dbl_valueB)); \
+ Dallp1(dbl_valueA) >>= 4
+#define Dbl_rightshiftby2(dbl_valueA,dbl_valueB) \
+ Shiftdouble(Dallp1(dbl_valueA),Dallp2(dbl_valueB),2,Dallp2(dbl_valueB)); \
+ Dallp1(dbl_valueA) >>= 2
+#define Dbl_rightshiftby1(dbl_valueA,dbl_valueB) \
+ Shiftdouble(Dallp1(dbl_valueA),Dallp2(dbl_valueB),1,Dallp2(dbl_valueB)); \
+ Dallp1(dbl_valueA) >>= 1
+
+/* This magnitude comparison uses the signless first words and
+ * the regular part2 words. The comparison is graphically:
+ *
+ * 1st greater? -------------
+ * |
+ * 1st less?-----------------+---------
+ * | |
+ * 2nd greater or equal----->| |
+ * False True
+ */
+#define Dbl_ismagnitudeless(leftB,rightB,signlessleft,signlessright) \
+ ((signlessleft <= signlessright) && \
+ ( (signlessleft < signlessright) || (Dallp2(leftB)<Dallp2(rightB)) ))
+
+#define Dbl_copytoint_exponentmantissap1(src,dest) \
+ dest = Dexponentmantissap1(src)
+
+/* A quiet NaN has the high mantissa bit clear and at least on other (in this
+ * case the adjacent bit) bit set. */
+#define Dbl_set_quiet(dbl_value) Deposit_dhigh2mantissa(dbl_value,1)
+#define Dbl_set_exponent(dbl_value, exp) Deposit_dexponent(dbl_value,exp)
+
+#define Dbl_set_mantissa(desta,destb,valuea,valueb) \
+ Deposit_dmantissap1(desta,valuea); \
+ Dmantissap2(destb) = Dmantissap2(valueb)
+#define Dbl_set_mantissap1(desta,valuea) \
+ Deposit_dmantissap1(desta,valuea)
+#define Dbl_set_mantissap2(destb,valueb) \
+ Dmantissap2(destb) = Dmantissap2(valueb)
+
+#define Dbl_set_exponentmantissa(desta,destb,valuea,valueb) \
+ Deposit_dexponentmantissap1(desta,valuea); \
+ Dmantissap2(destb) = Dmantissap2(valueb)
+#define Dbl_set_exponentmantissap1(dest,value) \
+ Deposit_dexponentmantissap1(dest,value)
+
+#define Dbl_copyfromptr(src,desta,destb) \
+ Dallp1(desta) = src->wd0; \
+ Dallp2(destb) = src->wd1
+#define Dbl_copytoptr(srca,srcb,dest) \
+ dest->wd0 = Dallp1(srca); \
+ dest->wd1 = Dallp2(srcb)
+
+/* An infinity is represented with the max exponent and a zero mantissa */
+#define Dbl_setinfinity_exponent(dbl_value) \
+ Deposit_dexponent(dbl_value,DBL_INFINITY_EXPONENT)
+#define Dbl_setinfinity_exponentmantissa(dbl_valueA,dbl_valueB) \
+ Deposit_dexponentmantissap1(dbl_valueA, \
+ (DBL_INFINITY_EXPONENT << (32-(1+DBL_EXP_LENGTH)))); \
+ Dmantissap2(dbl_valueB) = 0
+#define Dbl_setinfinitypositive(dbl_valueA,dbl_valueB) \
+ Dallp1(dbl_valueA) \
+ = (DBL_INFINITY_EXPONENT << (32-(1+DBL_EXP_LENGTH))); \
+ Dmantissap2(dbl_valueB) = 0
+#define Dbl_setinfinitynegative(dbl_valueA,dbl_valueB) \
+ Dallp1(dbl_valueA) = ((unsigned int)1<<31) | \
+ (DBL_INFINITY_EXPONENT << (32-(1+DBL_EXP_LENGTH))); \
+ Dmantissap2(dbl_valueB) = 0
+#define Dbl_setinfinity(dbl_valueA,dbl_valueB,sign) \
+ Dallp1(dbl_valueA) = ((unsigned int)sign << 31) | \
+ (DBL_INFINITY_EXPONENT << (32-(1+DBL_EXP_LENGTH))); \
+ Dmantissap2(dbl_valueB) = 0
+
+#define Dbl_sethigh4bits(dbl_value, extsign) Deposit_dhigh4p1(dbl_value,extsign)
+#define Dbl_set_sign(dbl_value,sign) Deposit_dsign(dbl_value,sign)
+#define Dbl_invert_sign(dbl_value) Deposit_dsign(dbl_value,~Dsign(dbl_value))
+#define Dbl_setone_sign(dbl_value) Deposit_dsign(dbl_value,1)
+#define Dbl_setone_lowmantissap2(dbl_value) Deposit_dlowp2(dbl_value,1)
+#define Dbl_setzero_sign(dbl_value) Dallp1(dbl_value) &= 0x7fffffff
+#define Dbl_setzero_exponent(dbl_value) \
+ Dallp1(dbl_value) &= 0x800fffff
+#define Dbl_setzero_mantissa(dbl_valueA,dbl_valueB) \
+ Dallp1(dbl_valueA) &= 0xfff00000; \
+ Dallp2(dbl_valueB) = 0
+#define Dbl_setzero_mantissap1(dbl_value) Dallp1(dbl_value) &= 0xfff00000
+#define Dbl_setzero_mantissap2(dbl_value) Dallp2(dbl_value) = 0
+#define Dbl_setzero_exponentmantissa(dbl_valueA,dbl_valueB) \
+ Dallp1(dbl_valueA) &= 0x80000000; \
+ Dallp2(dbl_valueB) = 0
+#define Dbl_setzero_exponentmantissap1(dbl_valueA) \
+ Dallp1(dbl_valueA) &= 0x80000000
+#define Dbl_setzero(dbl_valueA,dbl_valueB) \
+ Dallp1(dbl_valueA) = 0; Dallp2(dbl_valueB) = 0
+#define Dbl_setzerop1(dbl_value) Dallp1(dbl_value) = 0
+#define Dbl_setzerop2(dbl_value) Dallp2(dbl_value) = 0
+#define Dbl_setnegativezero(dbl_value) \
+ Dallp1(dbl_value) = (unsigned int)1 << 31; Dallp2(dbl_value) = 0
+#define Dbl_setnegativezerop1(dbl_value) Dallp1(dbl_value) = (unsigned int)1<<31
+
+/* Use the following macro for both overflow & underflow conditions */
+#define ovfl -
+#define unfl +
+#define Dbl_setwrapped_exponent(dbl_value,exponent,op) \
+ Deposit_dexponent(dbl_value,(exponent op DBL_WRAP))
+
+#define Dbl_setlargestpositive(dbl_valueA,dbl_valueB) \
+ Dallp1(dbl_valueA) = ((DBL_EMAX+DBL_BIAS) << (32-(1+DBL_EXP_LENGTH))) \
+ | ((1<<(32-(1+DBL_EXP_LENGTH))) - 1 ); \
+ Dallp2(dbl_valueB) = 0xFFFFFFFF
+#define Dbl_setlargestnegative(dbl_valueA,dbl_valueB) \
+ Dallp1(dbl_valueA) = ((DBL_EMAX+DBL_BIAS) << (32-(1+DBL_EXP_LENGTH))) \
+ | ((1<<(32-(1+DBL_EXP_LENGTH))) - 1 ) \
+ | ((unsigned int)1<<31); \
+ Dallp2(dbl_valueB) = 0xFFFFFFFF
+#define Dbl_setlargest_exponentmantissa(dbl_valueA,dbl_valueB) \
+ Deposit_dexponentmantissap1(dbl_valueA, \
+ (((DBL_EMAX+DBL_BIAS) << (32-(1+DBL_EXP_LENGTH))) \
+ | ((1<<(32-(1+DBL_EXP_LENGTH))) - 1 ))); \
+ Dallp2(dbl_valueB) = 0xFFFFFFFF
+
+#define Dbl_setnegativeinfinity(dbl_valueA,dbl_valueB) \
+ Dallp1(dbl_valueA) = ((1<<DBL_EXP_LENGTH) | DBL_INFINITY_EXPONENT) \
+ << (32-(1+DBL_EXP_LENGTH)) ; \
+ Dallp2(dbl_valueB) = 0
+#define Dbl_setlargest(dbl_valueA,dbl_valueB,sign) \
+ Dallp1(dbl_valueA) = ((unsigned int)sign << 31) | \
+ ((DBL_EMAX+DBL_BIAS) << (32-(1+DBL_EXP_LENGTH))) | \
+ ((1 << (32-(1+DBL_EXP_LENGTH))) - 1 ); \
+ Dallp2(dbl_valueB) = 0xFFFFFFFF
+
+
+/* The high bit is always zero so arithmetic or logical shifts will work. */
+#define Dbl_right_align(srcdstA,srcdstB,shift,extent) \
+ if( shift >= 32 ) \
+ { \
+ /* Big shift requires examining the portion shift off \
+ the end to properly set inexact. */ \
+ if(shift < 64) \
+ { \
+ if(shift > 32) \
+ { \
+ Variable_shift_double(Dallp1(srcdstA),Dallp2(srcdstB), \
+ shift-32, Extall(extent)); \
+ if(Dallp2(srcdstB) << 64 - (shift)) Ext_setone_low(extent); \
+ } \
+ else Extall(extent) = Dallp2(srcdstB); \
+ Dallp2(srcdstB) = Dallp1(srcdstA) >> (shift - 32); \
+ } \
+ else \
+ { \
+ Extall(extent) = Dallp1(srcdstA); \
+ if(Dallp2(srcdstB)) Ext_setone_low(extent); \
+ Dallp2(srcdstB) = 0; \
+ } \
+ Dallp1(srcdstA) = 0; \
+ } \
+ else \
+ { \
+ /* Small alignment is simpler. Extension is easily set. */ \
+ if (shift > 0) \
+ { \
+ Extall(extent) = Dallp2(srcdstB) << 32 - (shift); \
+ Variable_shift_double(Dallp1(srcdstA),Dallp2(srcdstB),shift, \
+ Dallp2(srcdstB)); \
+ Dallp1(srcdstA) >>= shift; \
+ } \
+ else Extall(extent) = 0; \
+ }
+
+/*
+ * Here we need to shift the result right to correct for an overshift
+ * (due to the exponent becoming negative) during normalization.
+ */
+#define Dbl_fix_overshift(srcdstA,srcdstB,shift,extent) \
+ Extall(extent) = Dallp2(srcdstB) << 32 - (shift); \
+ Dallp2(srcdstB) = (Dallp1(srcdstA) << 32 - (shift)) | \
+ (Dallp2(srcdstB) >> (shift)); \
+ Dallp1(srcdstA) = Dallp1(srcdstA) >> shift
+
+#define Dbl_hiddenhigh3mantissa(dbl_value) Dhiddenhigh3mantissa(dbl_value)
+#define Dbl_hidden(dbl_value) Dhidden(dbl_value)
+#define Dbl_lowmantissap2(dbl_value) Dlowp2(dbl_value)
+
+/* The left argument is never smaller than the right argument */
+#define Dbl_subtract(lefta,leftb,righta,rightb,resulta,resultb) \
+ if( Dallp2(rightb) > Dallp2(leftb) ) Dallp1(lefta)--; \
+ Dallp2(resultb) = Dallp2(leftb) - Dallp2(rightb); \
+ Dallp1(resulta) = Dallp1(lefta) - Dallp1(righta)
+
+/* Subtract right augmented with extension from left augmented with zeros and
+ * store into result and extension. */
+#define Dbl_subtract_withextension(lefta,leftb,righta,rightb,extent,resulta,resultb) \
+ Dbl_subtract(lefta,leftb,righta,rightb,resulta,resultb); \
+ if( (Extall(extent) = 0-Extall(extent)) ) \
+ { \
+ if((Dallp2(resultb)--) == 0) Dallp1(resulta)--; \
+ }
+
+#define Dbl_addition(lefta,leftb,righta,rightb,resulta,resultb) \
+ /* If the sum of the low words is less than either source, then \
+ * an overflow into the next word occurred. */ \
+ Dallp1(resulta) = Dallp1(lefta) + Dallp1(righta); \
+ if((Dallp2(resultb) = Dallp2(leftb) + Dallp2(rightb)) < Dallp2(rightb)) \
+ Dallp1(resulta)++
+
+#define Dbl_xortointp1(left,right,result) \
+ result = Dallp1(left) XOR Dallp1(right)
+
+#define Dbl_xorfromintp1(left,right,result) \
+ Dallp1(result) = left XOR Dallp1(right)
+
+#define Dbl_swap_lower(left,right) \
+ Dallp2(left) = Dallp2(left) XOR Dallp2(right); \
+ Dallp2(right) = Dallp2(left) XOR Dallp2(right); \
+ Dallp2(left) = Dallp2(left) XOR Dallp2(right)
+
+/* Need to Initialize */
+#define Dbl_makequietnan(desta,destb) \
+ Dallp1(desta) = ((DBL_EMAX+DBL_BIAS)+1)<< (32-(1+DBL_EXP_LENGTH)) \
+ | (1<<(32-(1+DBL_EXP_LENGTH+2))); \
+ Dallp2(destb) = 0
+#define Dbl_makesignalingnan(desta,destb) \
+ Dallp1(desta) = ((DBL_EMAX+DBL_BIAS)+1)<< (32-(1+DBL_EXP_LENGTH)) \
+ | (1<<(32-(1+DBL_EXP_LENGTH+1))); \
+ Dallp2(destb) = 0
+
+#define Dbl_normalize(dbl_opndA,dbl_opndB,exponent) \
+ while(Dbl_iszero_hiddenhigh7mantissa(dbl_opndA)) { \
+ Dbl_leftshiftby8(dbl_opndA,dbl_opndB); \
+ exponent -= 8; \
+ } \
+ if(Dbl_iszero_hiddenhigh3mantissa(dbl_opndA)) { \
+ Dbl_leftshiftby4(dbl_opndA,dbl_opndB); \
+ exponent -= 4; \
+ } \
+ while(Dbl_iszero_hidden(dbl_opndA)) { \
+ Dbl_leftshiftby1(dbl_opndA,dbl_opndB); \
+ exponent -= 1; \
+ }
+
+#define Twoword_add(src1dstA,src1dstB,src2A,src2B) \
+ /* \
+ * want this macro to generate: \
+ * ADD src1dstB,src2B,src1dstB; \
+ * ADDC src1dstA,src2A,src1dstA; \
+ */ \
+ if ((src1dstB) + (src2B) < (src1dstB)) Dallp1(src1dstA)++; \
+ Dallp1(src1dstA) += (src2A); \
+ Dallp2(src1dstB) += (src2B)
+
+#define Twoword_subtract(src1dstA,src1dstB,src2A,src2B) \
+ /* \
+ * want this macro to generate: \
+ * SUB src1dstB,src2B,src1dstB; \
+ * SUBB src1dstA,src2A,src1dstA; \
+ */ \
+ if ((src1dstB) < (src2B)) Dallp1(src1dstA)--; \
+ Dallp1(src1dstA) -= (src2A); \
+ Dallp2(src1dstB) -= (src2B)
+
+#define Dbl_setoverflow(resultA,resultB) \
+ /* set result to infinity or largest number */ \
+ switch (Rounding_mode()) { \
+ case ROUNDPLUS: \
+ if (Dbl_isone_sign(resultA)) { \
+ Dbl_setlargestnegative(resultA,resultB); \
+ } \
+ else { \
+ Dbl_setinfinitypositive(resultA,resultB); \
+ } \
+ break; \
+ case ROUNDMINUS: \
+ if (Dbl_iszero_sign(resultA)) { \
+ Dbl_setlargestpositive(resultA,resultB); \
+ } \
+ else { \
+ Dbl_setinfinitynegative(resultA,resultB); \
+ } \
+ break; \
+ case ROUNDNEAREST: \
+ Dbl_setinfinity_exponentmantissa(resultA,resultB); \
+ break; \
+ case ROUNDZERO: \
+ Dbl_setlargest_exponentmantissa(resultA,resultB); \
+ }
+
+#define Dbl_denormalize(opndp1,opndp2,exponent,guard,sticky,inexact) \
+ Dbl_clear_signexponent_set_hidden(opndp1); \
+ if (exponent >= (1-DBL_P)) { \
+ if (exponent >= -31) { \
+ guard = (Dallp2(opndp2) >> -exponent) & 1; \
+ if (exponent < 0) sticky |= Dallp2(opndp2) << (32+exponent); \
+ if (exponent > -31) { \
+ Variable_shift_double(opndp1,opndp2,1-exponent,opndp2); \
+ Dallp1(opndp1) >>= 1-exponent; \
+ } \
+ else { \
+ Dallp2(opndp2) = Dallp1(opndp1); \
+ Dbl_setzerop1(opndp1); \
+ } \
+ } \
+ else { \
+ guard = (Dallp1(opndp1) >> -32-exponent) & 1; \
+ if (exponent == -32) sticky |= Dallp2(opndp2); \
+ else sticky |= (Dallp2(opndp2) | Dallp1(opndp1) << 64+exponent); \
+ Dallp2(opndp2) = Dallp1(opndp1) >> -31-exponent; \
+ Dbl_setzerop1(opndp1); \
+ } \
+ inexact = guard | sticky; \
+ } \
+ else { \
+ guard = 0; \
+ sticky |= (Dallp1(opndp1) | Dallp2(opndp2)); \
+ Dbl_setzero(opndp1,opndp2); \
+ inexact = sticky; \
+ }
+
+/*
+ * The fused multiply add instructions requires a double extended format,
+ * with 106 bits of mantissa.
+ */
+#define DBLEXT_THRESHOLD 106
+
+#define Dblext_setzero(valA,valB,valC,valD) \
+ Dextallp1(valA) = 0; Dextallp2(valB) = 0; \
+ Dextallp3(valC) = 0; Dextallp4(valD) = 0
+
+
+#define Dblext_isnotzero_mantissap3(valC) (Dextallp3(valC)!=0)
+#define Dblext_isnotzero_mantissap4(valD) (Dextallp3(valD)!=0)
+#define Dblext_isone_lowp2(val) (Dextlowp2(val)!=0)
+#define Dblext_isone_highp3(val) (Dexthighp3(val)!=0)
+#define Dblext_isnotzero_low31p3(val) (Dextlow31p3(val)!=0)
+#define Dblext_iszero(valA,valB,valC,valD) (Dextallp1(valA)==0 && \
+ Dextallp2(valB)==0 && Dextallp3(valC)==0 && Dextallp4(valD)==0)
+
+#define Dblext_copy(srca,srcb,srcc,srcd,desta,destb,destc,destd) \
+ Dextallp1(desta) = Dextallp4(srca); \
+ Dextallp2(destb) = Dextallp4(srcb); \
+ Dextallp3(destc) = Dextallp4(srcc); \
+ Dextallp4(destd) = Dextallp4(srcd)
+
+#define Dblext_swap_lower(leftp2,leftp3,leftp4,rightp2,rightp3,rightp4) \
+ Dextallp2(leftp2) = Dextallp2(leftp2) XOR Dextallp2(rightp2); \
+ Dextallp2(rightp2) = Dextallp2(leftp2) XOR Dextallp2(rightp2); \
+ Dextallp2(leftp2) = Dextallp2(leftp2) XOR Dextallp2(rightp2); \
+ Dextallp3(leftp3) = Dextallp3(leftp3) XOR Dextallp3(rightp3); \
+ Dextallp3(rightp3) = Dextallp3(leftp3) XOR Dextallp3(rightp3); \
+ Dextallp3(leftp3) = Dextallp3(leftp3) XOR Dextallp3(rightp3); \
+ Dextallp4(leftp4) = Dextallp4(leftp4) XOR Dextallp4(rightp4); \
+ Dextallp4(rightp4) = Dextallp4(leftp4) XOR Dextallp4(rightp4); \
+ Dextallp4(leftp4) = Dextallp4(leftp4) XOR Dextallp4(rightp4)
+
+#define Dblext_setone_lowmantissap4(dbl_value) Deposit_dextlowp4(dbl_value,1)
+
+/* The high bit is always zero so arithmetic or logical shifts will work. */
+#define Dblext_right_align(srcdstA,srcdstB,srcdstC,srcdstD,shift) \
+ {int shiftamt, sticky; \
+ shiftamt = shift % 32; \
+ sticky = 0; \
+ switch (shift/32) { \
+ case 0: if (shiftamt > 0) { \
+ sticky = Dextallp4(srcdstD) << 32 - (shiftamt); \
+ Variable_shift_double(Dextallp3(srcdstC), \
+ Dextallp4(srcdstD),shiftamt,Dextallp4(srcdstD)); \
+ Variable_shift_double(Dextallp2(srcdstB), \
+ Dextallp3(srcdstC),shiftamt,Dextallp3(srcdstC)); \
+ Variable_shift_double(Dextallp1(srcdstA), \
+ Dextallp2(srcdstB),shiftamt,Dextallp2(srcdstB)); \
+ Dextallp1(srcdstA) >>= shiftamt; \
+ } \
+ break; \
+ case 1: if (shiftamt > 0) { \
+ sticky = (Dextallp3(srcdstC) << 31 - shiftamt) | \
+ Dextallp4(srcdstD); \
+ Variable_shift_double(Dextallp2(srcdstB), \
+ Dextallp3(srcdstC),shiftamt,Dextallp4(srcdstD)); \
+ Variable_shift_double(Dextallp1(srcdstA), \
+ Dextallp2(srcdstB),shiftamt,Dextallp3(srcdstC)); \
+ } \
+ else { \
+ sticky = Dextallp4(srcdstD); \
+ Dextallp4(srcdstD) = Dextallp3(srcdstC); \
+ Dextallp3(srcdstC) = Dextallp2(srcdstB); \
+ } \
+ Dextallp2(srcdstB) = Dextallp1(srcdstA) >> shiftamt; \
+ Dextallp1(srcdstA) = 0; \
+ break; \
+ case 2: if (shiftamt > 0) { \
+ sticky = (Dextallp2(srcdstB) << 31 - shiftamt) | \
+ Dextallp3(srcdstC) | Dextallp4(srcdstD); \
+ Variable_shift_double(Dextallp1(srcdstA), \
+ Dextallp2(srcdstB),shiftamt,Dextallp4(srcdstD)); \
+ } \
+ else { \
+ sticky = Dextallp3(srcdstC) | Dextallp4(srcdstD); \
+ Dextallp4(srcdstD) = Dextallp2(srcdstB); \
+ } \
+ Dextallp3(srcdstC) = Dextallp1(srcdstA) >> shiftamt; \
+ Dextallp1(srcdstA) = Dextallp2(srcdstB) = 0; \
+ break; \
+ case 3: if (shiftamt > 0) { \
+ sticky = (Dextallp1(srcdstA) << 31 - shiftamt) | \
+ Dextallp2(srcdstB) | Dextallp3(srcdstC) | \
+ Dextallp4(srcdstD); \
+ } \
+ else { \
+ sticky = Dextallp2(srcdstB) | Dextallp3(srcdstC) | \
+ Dextallp4(srcdstD); \
+ } \
+ Dextallp4(srcdstD) = Dextallp1(srcdstA) >> shiftamt; \
+ Dextallp1(srcdstA) = Dextallp2(srcdstB) = 0; \
+ Dextallp3(srcdstC) = 0; \
+ break; \
+ } \
+ if (sticky) Dblext_setone_lowmantissap4(srcdstD); \
+ }
+
+/* The left argument is never smaller than the right argument */
+#define Dblext_subtract(lefta,leftb,leftc,leftd,righta,rightb,rightc,rightd,resulta,resultb,resultc,resultd) \
+ if( Dextallp4(rightd) > Dextallp4(leftd) ) \
+ if( (Dextallp3(leftc)--) == 0) \
+ if( (Dextallp2(leftb)--) == 0) Dextallp1(lefta)--; \
+ Dextallp4(resultd) = Dextallp4(leftd) - Dextallp4(rightd); \
+ if( Dextallp3(rightc) > Dextallp3(leftc) ) \
+ if( (Dextallp2(leftb)--) == 0) Dextallp1(lefta)--; \
+ Dextallp3(resultc) = Dextallp3(leftc) - Dextallp3(rightc); \
+ if( Dextallp2(rightb) > Dextallp2(leftb) ) Dextallp1(lefta)--; \
+ Dextallp2(resultb) = Dextallp2(leftb) - Dextallp2(rightb); \
+ Dextallp1(resulta) = Dextallp1(lefta) - Dextallp1(righta)
+
+#define Dblext_addition(lefta,leftb,leftc,leftd,righta,rightb,rightc,rightd,resulta,resultb,resultc,resultd) \
+ /* If the sum of the low words is less than either source, then \
+ * an overflow into the next word occurred. */ \
+ if ((Dextallp4(resultd) = Dextallp4(leftd)+Dextallp4(rightd)) < \
+ Dextallp4(rightd)) \
+ if((Dextallp3(resultc) = Dextallp3(leftc)+Dextallp3(rightc)+1) <= \
+ Dextallp3(rightc)) \
+ if((Dextallp2(resultb) = Dextallp2(leftb)+Dextallp2(rightb)+1) \
+ <= Dextallp2(rightb)) \
+ Dextallp1(resulta) = Dextallp1(lefta)+Dextallp1(righta)+1; \
+ else Dextallp1(resulta) = Dextallp1(lefta)+Dextallp1(righta); \
+ else \
+ if ((Dextallp2(resultb) = Dextallp2(leftb)+Dextallp2(rightb)) < \
+ Dextallp2(rightb)) \
+ Dextallp1(resulta) = Dextallp1(lefta)+Dextallp1(righta)+1; \
+ else Dextallp1(resulta) = Dextallp1(lefta)+Dextallp1(righta); \
+ else \
+ if ((Dextallp3(resultc) = Dextallp3(leftc)+Dextallp3(rightc)) < \
+ Dextallp3(rightc)) \
+ if ((Dextallp2(resultb) = Dextallp2(leftb)+Dextallp2(rightb)+1) \
+ <= Dextallp2(rightb)) \
+ Dextallp1(resulta) = Dextallp1(lefta)+Dextallp1(righta)+1; \
+ else Dextallp1(resulta) = Dextallp1(lefta)+Dextallp1(righta); \
+ else \
+ if ((Dextallp2(resultb) = Dextallp2(leftb)+Dextallp2(rightb)) < \
+ Dextallp2(rightb)) \
+ Dextallp1(resulta) = Dextallp1(lefta)+Dextallp1(righta)+1; \
+ else Dextallp1(resulta) = Dextallp1(lefta)+Dextallp1(righta)
+
+
+#define Dblext_arithrightshiftby1(srcdstA,srcdstB,srcdstC,srcdstD) \
+ Shiftdouble(Dextallp3(srcdstC),Dextallp4(srcdstD),1,Dextallp4(srcdstD)); \
+ Shiftdouble(Dextallp2(srcdstB),Dextallp3(srcdstC),1,Dextallp3(srcdstC)); \
+ Shiftdouble(Dextallp1(srcdstA),Dextallp2(srcdstB),1,Dextallp2(srcdstB)); \
+ Dextallp1(srcdstA) = (int)Dextallp1(srcdstA) >> 1
+
+#define Dblext_leftshiftby8(valA,valB,valC,valD) \
+ Shiftdouble(Dextallp1(valA),Dextallp2(valB),24,Dextallp1(valA)); \
+ Shiftdouble(Dextallp2(valB),Dextallp3(valC),24,Dextallp2(valB)); \
+ Shiftdouble(Dextallp3(valC),Dextallp4(valD),24,Dextallp3(valC)); \
+ Dextallp4(valD) <<= 8
+#define Dblext_leftshiftby4(valA,valB,valC,valD) \
+ Shiftdouble(Dextallp1(valA),Dextallp2(valB),28,Dextallp1(valA)); \
+ Shiftdouble(Dextallp2(valB),Dextallp3(valC),28,Dextallp2(valB)); \
+ Shiftdouble(Dextallp3(valC),Dextallp4(valD),28,Dextallp3(valC)); \
+ Dextallp4(valD) <<= 4
+#define Dblext_leftshiftby3(valA,valB,valC,valD) \
+ Shiftdouble(Dextallp1(valA),Dextallp2(valB),29,Dextallp1(valA)); \
+ Shiftdouble(Dextallp2(valB),Dextallp3(valC),29,Dextallp2(valB)); \
+ Shiftdouble(Dextallp3(valC),Dextallp4(valD),29,Dextallp3(valC)); \
+ Dextallp4(valD) <<= 3
+#define Dblext_leftshiftby2(valA,valB,valC,valD) \
+ Shiftdouble(Dextallp1(valA),Dextallp2(valB),30,Dextallp1(valA)); \
+ Shiftdouble(Dextallp2(valB),Dextallp3(valC),30,Dextallp2(valB)); \
+ Shiftdouble(Dextallp3(valC),Dextallp4(valD),30,Dextallp3(valC)); \
+ Dextallp4(valD) <<= 2
+#define Dblext_leftshiftby1(valA,valB,valC,valD) \
+ Shiftdouble(Dextallp1(valA),Dextallp2(valB),31,Dextallp1(valA)); \
+ Shiftdouble(Dextallp2(valB),Dextallp3(valC),31,Dextallp2(valB)); \
+ Shiftdouble(Dextallp3(valC),Dextallp4(valD),31,Dextallp3(valC)); \
+ Dextallp4(valD) <<= 1
+
+#define Dblext_rightshiftby4(valueA,valueB,valueC,valueD) \
+ Shiftdouble(Dextallp3(valueC),Dextallp4(valueD),4,Dextallp4(valueD)); \
+ Shiftdouble(Dextallp2(valueB),Dextallp3(valueC),4,Dextallp3(valueC)); \
+ Shiftdouble(Dextallp1(valueA),Dextallp2(valueB),4,Dextallp2(valueB)); \
+ Dextallp1(valueA) >>= 4
+#define Dblext_rightshiftby1(valueA,valueB,valueC,valueD) \
+ Shiftdouble(Dextallp3(valueC),Dextallp4(valueD),1,Dextallp4(valueD)); \
+ Shiftdouble(Dextallp2(valueB),Dextallp3(valueC),1,Dextallp3(valueC)); \
+ Shiftdouble(Dextallp1(valueA),Dextallp2(valueB),1,Dextallp2(valueB)); \
+ Dextallp1(valueA) >>= 1
+
+#define Dblext_xortointp1(left,right,result) Dbl_xortointp1(left,right,result)
+
+#define Dblext_xorfromintp1(left,right,result) \
+ Dbl_xorfromintp1(left,right,result)
+
+#define Dblext_copytoint_exponentmantissap1(src,dest) \
+ Dbl_copytoint_exponentmantissap1(src,dest)
+
+#define Dblext_ismagnitudeless(leftB,rightB,signlessleft,signlessright) \
+ Dbl_ismagnitudeless(leftB,rightB,signlessleft,signlessright)
+
+#define Dbl_copyto_dblext(src1,src2,dest1,dest2,dest3,dest4) \
+ Dextallp1(dest1) = Dallp1(src1); Dextallp2(dest2) = Dallp2(src2); \
+ Dextallp3(dest3) = 0; Dextallp4(dest4) = 0
+
+#define Dblext_set_sign(dbl_value,sign) Dbl_set_sign(dbl_value,sign)
+#define Dblext_clear_signexponent_set_hidden(srcdst) \
+ Dbl_clear_signexponent_set_hidden(srcdst)
+#define Dblext_clear_signexponent(srcdst) Dbl_clear_signexponent(srcdst)
+#define Dblext_clear_sign(srcdst) Dbl_clear_sign(srcdst)
+#define Dblext_isone_hidden(dbl_value) Dbl_isone_hidden(dbl_value)
+
+/*
+ * The Fourword_add() macro assumes that integers are 4 bytes in size.
+ * It will break if this is not the case.
+ */
+
+#define Fourword_add(src1dstA,src1dstB,src1dstC,src1dstD,src2A,src2B,src2C,src2D) \
+ /* \
+ * want this macro to generate: \
+ * ADD src1dstD,src2D,src1dstD; \
+ * ADDC src1dstC,src2C,src1dstC; \
+ * ADDC src1dstB,src2B,src1dstB; \
+ * ADDC src1dstA,src2A,src1dstA; \
+ */ \
+ if ((unsigned int)(src1dstD += (src2D)) < (unsigned int)(src2D)) { \
+ if ((unsigned int)(src1dstC += (src2C) + 1) <= \
+ (unsigned int)(src2C)) { \
+ if ((unsigned int)(src1dstB += (src2B) + 1) <= \
+ (unsigned int)(src2B)) src1dstA++; \
+ } \
+ else if ((unsigned int)(src1dstB += (src2B)) < \
+ (unsigned int)(src2B)) src1dstA++; \
+ } \
+ else { \
+ if ((unsigned int)(src1dstC += (src2C)) < \
+ (unsigned int)(src2C)) { \
+ if ((unsigned int)(src1dstB += (src2B) + 1) <= \
+ (unsigned int)(src2B)) src1dstA++; \
+ } \
+ else if ((unsigned int)(src1dstB += (src2B)) < \
+ (unsigned int)(src2B)) src1dstA++; \
+ } \
+ src1dstA += (src2A)
+
+#define Dblext_denormalize(opndp1,opndp2,opndp3,opndp4,exponent,is_tiny) \
+ {int shiftamt, sticky; \
+ is_tiny = TRUE; \
+ if (exponent == 0 && (Dextallp3(opndp3) || Dextallp4(opndp4))) { \
+ switch (Rounding_mode()) { \
+ case ROUNDPLUS: \
+ if (Dbl_iszero_sign(opndp1)) { \
+ Dbl_increment(opndp1,opndp2); \
+ if (Dbl_isone_hiddenoverflow(opndp1)) \
+ is_tiny = FALSE; \
+ Dbl_decrement(opndp1,opndp2); \
+ } \
+ break; \
+ case ROUNDMINUS: \
+ if (Dbl_isone_sign(opndp1)) { \
+ Dbl_increment(opndp1,opndp2); \
+ if (Dbl_isone_hiddenoverflow(opndp1)) \
+ is_tiny = FALSE; \
+ Dbl_decrement(opndp1,opndp2); \
+ } \
+ break; \
+ case ROUNDNEAREST: \
+ if (Dblext_isone_highp3(opndp3) && \
+ (Dblext_isone_lowp2(opndp2) || \
+ Dblext_isnotzero_low31p3(opndp3))) { \
+ Dbl_increment(opndp1,opndp2); \
+ if (Dbl_isone_hiddenoverflow(opndp1)) \
+ is_tiny = FALSE; \
+ Dbl_decrement(opndp1,opndp2); \
+ } \
+ break; \
+ } \
+ } \
+ Dblext_clear_signexponent_set_hidden(opndp1); \
+ if (exponent >= (1-QUAD_P)) { \
+ shiftamt = (1-exponent) % 32; \
+ switch((1-exponent)/32) { \
+ case 0: sticky = Dextallp4(opndp4) << 32-(shiftamt); \
+ Variableshiftdouble(opndp3,opndp4,shiftamt,opndp4); \
+ Variableshiftdouble(opndp2,opndp3,shiftamt,opndp3); \
+ Variableshiftdouble(opndp1,opndp2,shiftamt,opndp2); \
+ Dextallp1(opndp1) >>= shiftamt; \
+ break; \
+ case 1: sticky = (Dextallp3(opndp3) << 32-(shiftamt)) | \
+ Dextallp4(opndp4); \
+ Variableshiftdouble(opndp2,opndp3,shiftamt,opndp4); \
+ Variableshiftdouble(opndp1,opndp2,shiftamt,opndp3); \
+ Dextallp2(opndp2) = Dextallp1(opndp1) >> shiftamt; \
+ Dextallp1(opndp1) = 0; \
+ break; \
+ case 2: sticky = (Dextallp2(opndp2) << 32-(shiftamt)) | \
+ Dextallp3(opndp3) | Dextallp4(opndp4); \
+ Variableshiftdouble(opndp1,opndp2,shiftamt,opndp4); \
+ Dextallp3(opndp3) = Dextallp1(opndp1) >> shiftamt; \
+ Dextallp1(opndp1) = Dextallp2(opndp2) = 0; \
+ break; \
+ case 3: sticky = (Dextallp1(opndp1) << 32-(shiftamt)) | \
+ Dextallp2(opndp2) | Dextallp3(opndp3) | \
+ Dextallp4(opndp4); \
+ Dextallp4(opndp4) = Dextallp1(opndp1) >> shiftamt; \
+ Dextallp1(opndp1) = Dextallp2(opndp2) = 0; \
+ Dextallp3(opndp3) = 0; \
+ break; \
+ } \
+ } \
+ else { \
+ sticky = Dextallp1(opndp1) | Dextallp2(opndp2) | \
+ Dextallp3(opndp3) | Dextallp4(opndp4); \
+ Dblext_setzero(opndp1,opndp2,opndp3,opndp4); \
+ } \
+ if (sticky) Dblext_setone_lowmantissap4(opndp4); \
+ exponent = 0; \
+ }
diff --git a/arch/parisc/math-emu/decode_exc.c b/arch/parisc/math-emu/decode_exc.c
new file mode 100644
index 000000000..d41ddb343
--- /dev/null
+++ b/arch/parisc/math-emu/decode_exc.c
@@ -0,0 +1,357 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ */
+/*
+ * BEGIN_DESC
+ *
+ * File:
+ * @(#) pa/fp/decode_exc.c $ Revision: $
+ *
+ * Purpose:
+ * <<please update with a synopsis of the functionality provided by this file>>
+ *
+ * External Interfaces:
+ * <<the following list was autogenerated, please review>>
+ * decode_fpu(Fpu_register, trap_counts)
+ *
+ * Internal Interfaces:
+ * <<please update>>
+ *
+ * Theory:
+ * <<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+#include <linux/kernel.h>
+#include "float.h"
+#include "sgl_float.h"
+#include "dbl_float.h"
+#include "cnv_float.h"
+/* #include "types.h" */
+#include <asm/signal.h>
+#include <asm/siginfo.h>
+/* #include <machine/sys/mdep_private.h> */
+
+#undef Fpustatus_register
+#define Fpustatus_register Fpu_register[0]
+
+/* General definitions */
+#define DOESTRAP 1
+#define NOTRAP 0
+#define SIGNALCODE(signal, code) ((signal) << 24 | (code))
+#define copropbit 1<<31-2 /* bit position 2 */
+#define opclass 9 /* bits 21 & 22 */
+#define fmtbits 11 /* bits 19 & 20 */
+#define df 13 /* bits 17 & 18 */
+#define twobits 3 /* mask low-order 2 bits */
+#define fivebits 31 /* mask low-order 5 bits */
+#define MAX_EXCP_REG 7 /* number of excpeption registers to check */
+
+/* Exception register definitions */
+#define Excp_type(index) Exceptiontype(Fpu_register[index])
+#define Excp_instr(index) Instructionfield(Fpu_register[index])
+#define Clear_excp_register(index) Allexception(Fpu_register[index]) = 0
+#define Excp_format() \
+ (current_ir >> ((current_ir>>opclass & twobits) == 1 ? df : fmtbits) & twobits)
+
+/* Miscellaneous definitions */
+#define Fpu_sgl(index) Fpu_register[index*2]
+
+#define Fpu_dblp1(index) Fpu_register[index*2]
+#define Fpu_dblp2(index) Fpu_register[(index*2)+1]
+
+#define Fpu_quadp1(index) Fpu_register[index*2]
+#define Fpu_quadp2(index) Fpu_register[(index*2)+1]
+#define Fpu_quadp3(index) Fpu_register[(index*2)+2]
+#define Fpu_quadp4(index) Fpu_register[(index*2)+3]
+
+/* Single precision floating-point definitions */
+#ifndef Sgl_decrement
+# define Sgl_decrement(sgl_value) Sall(sgl_value)--
+#endif
+
+/* Double precision floating-point definitions */
+#ifndef Dbl_decrement
+# define Dbl_decrement(dbl_valuep1,dbl_valuep2) \
+ if ((Dallp2(dbl_valuep2)--) == 0) Dallp1(dbl_valuep1)--
+#endif
+
+
+#define update_trap_counts(Fpu_register, aflags, bflags, trap_counts) { \
+ aflags=(Fpu_register[0])>>27; /* assumes zero fill. 32 bit */ \
+ Fpu_register[0] |= bflags; \
+}
+
+u_int
+decode_fpu(unsigned int Fpu_register[], unsigned int trap_counts[])
+{
+ unsigned int current_ir, excp;
+ int target, exception_index = 1;
+ boolean inexact;
+ unsigned int aflags;
+ unsigned int bflags;
+ unsigned int excptype;
+
+
+ /* Keep stats on how many floating point exceptions (based on type)
+ * that happen. Want to keep this overhead low, but still provide
+ * some information to the customer. All exits from this routine
+ * need to restore Fpu_register[0]
+ */
+
+ bflags=(Fpu_register[0] & 0xf8000000);
+ Fpu_register[0] &= 0x07ffffff;
+
+ /* exception_index is used to index the exception register queue. It
+ * always points at the last register that contains a valid exception. A
+ * zero value implies no exceptions (also the initialized value). Setting
+ * the T-bit resets the exception_index to zero.
+ */
+
+ /*
+ * Check for reserved-op exception. A reserved-op exception does not
+ * set any exception registers nor does it set the T-bit. If the T-bit
+ * is not set then a reserved-op exception occurred.
+ *
+ * At some point, we may want to report reserved op exceptions as
+ * illegal instructions.
+ */
+
+ if (!Is_tbit_set()) {
+ update_trap_counts(Fpu_register, aflags, bflags, trap_counts);
+ return SIGNALCODE(SIGILL, ILL_COPROC);
+ }
+
+ /*
+ * Is a coprocessor op.
+ *
+ * Now we need to determine what type of exception occurred.
+ */
+ for (exception_index=1; exception_index<=MAX_EXCP_REG; exception_index++) {
+ current_ir = Excp_instr(exception_index);
+ /*
+ * On PA89: there are 5 different unimplemented exception
+ * codes: 0x1, 0x9, 0xb, 0x3, and 0x23. PA-RISC 2.0 adds
+ * another, 0x2b. Only these have the low order bit set.
+ */
+ excptype = Excp_type(exception_index);
+ if (excptype & UNIMPLEMENTEDEXCEPTION) {
+ /*
+ * Clear T-bit and exception register so that
+ * we can tell if a trap really occurs while
+ * emulating the instruction.
+ */
+ Clear_tbit();
+ Clear_excp_register(exception_index);
+ /*
+ * Now emulate this instruction. If a trap occurs,
+ * fpudispatch will return a non-zero number
+ */
+ excp = fpudispatch(current_ir,excptype,0,Fpu_register);
+ /* accumulate the status flags, don't lose them as in hpux */
+ if (excp) {
+ /*
+ * We now need to make sure that the T-bit and the
+ * exception register contain the correct values
+ * before continuing.
+ */
+ /*
+ * Set t-bit since it might still be needed for a
+ * subsequent real trap (I don't understand fully -PB)
+ */
+ Set_tbit();
+ /* some of the following code uses
+ * Excp_type(exception_index) so fix that up */
+ Set_exceptiontype_and_instr_field(excp,current_ir,
+ Fpu_register[exception_index]);
+ if (excp == UNIMPLEMENTEDEXCEPTION) {
+ /*
+ * it is really unimplemented, so restore the
+ * TIMEX extended unimplemented exception code
+ */
+ excp = excptype;
+ update_trap_counts(Fpu_register, aflags, bflags,
+ trap_counts);
+ return SIGNALCODE(SIGILL, ILL_COPROC);
+ }
+ /* some of the following code uses excptype, so
+ * fix that up too */
+ excptype = excp;
+ }
+ /* handle exceptions other than the real UNIMPLIMENTED the
+ * same way as if the hardware had caused them */
+ if (excp == NOEXCEPTION)
+ /* For now use 'break', should technically be 'continue' */
+ break;
+ }
+
+ /*
+ * In PA89, the underflow exception has been extended to encode
+ * additional information. The exception looks like pp01x0,
+ * where x is 1 if inexact and pp represent the inexact bit (I)
+ * and the round away bit (RA)
+ */
+ if (excptype & UNDERFLOWEXCEPTION) {
+ /* check for underflow trap enabled */
+ if (Is_underflowtrap_enabled()) {
+ update_trap_counts(Fpu_register, aflags, bflags,
+ trap_counts);
+ return SIGNALCODE(SIGFPE, FPE_FLTUND);
+ } else {
+ /*
+ * Isn't a real trap; we need to
+ * return the default value.
+ */
+ target = current_ir & fivebits;
+#ifndef lint
+ if (Ibit(Fpu_register[exception_index])) inexact = TRUE;
+ else inexact = FALSE;
+#endif
+ switch (Excp_format()) {
+ case SGL:
+ /*
+ * If ra (round-away) is set, will
+ * want to undo the rounding done
+ * by the hardware.
+ */
+ if (Rabit(Fpu_register[exception_index]))
+ Sgl_decrement(Fpu_sgl(target));
+
+ /* now denormalize */
+ sgl_denormalize(&Fpu_sgl(target),&inexact,Rounding_mode());
+ break;
+ case DBL:
+ /*
+ * If ra (round-away) is set, will
+ * want to undo the rounding done
+ * by the hardware.
+ */
+ if (Rabit(Fpu_register[exception_index]))
+ Dbl_decrement(Fpu_dblp1(target),Fpu_dblp2(target));
+
+ /* now denormalize */
+ dbl_denormalize(&Fpu_dblp1(target),&Fpu_dblp2(target),
+ &inexact,Rounding_mode());
+ break;
+ }
+ if (inexact) Set_underflowflag();
+ /*
+ * Underflow can generate an inexact
+ * exception. If inexact trap is enabled,
+ * want to do an inexact trap, otherwise
+ * set inexact flag.
+ */
+ if (inexact && Is_inexacttrap_enabled()) {
+ /*
+ * Set exception field of exception register
+ * to inexact, parm field to zero.
+ * Underflow bit should be cleared.
+ */
+ Set_exceptiontype(Fpu_register[exception_index],
+ INEXACTEXCEPTION);
+ Set_parmfield(Fpu_register[exception_index],0);
+ update_trap_counts(Fpu_register, aflags, bflags,
+ trap_counts);
+ return SIGNALCODE(SIGFPE, FPE_FLTRES);
+ }
+ else {
+ /*
+ * Exception register needs to be cleared.
+ * Inexact flag needs to be set if inexact.
+ */
+ Clear_excp_register(exception_index);
+ if (inexact) Set_inexactflag();
+ }
+ }
+ continue;
+ }
+ switch(Excp_type(exception_index)) {
+ case OVERFLOWEXCEPTION:
+ case OVERFLOWEXCEPTION | INEXACTEXCEPTION:
+ /* check for overflow trap enabled */
+ update_trap_counts(Fpu_register, aflags, bflags,
+ trap_counts);
+ if (Is_overflowtrap_enabled()) {
+ update_trap_counts(Fpu_register, aflags, bflags,
+ trap_counts);
+ return SIGNALCODE(SIGFPE, FPE_FLTOVF);
+ } else {
+ /*
+ * Isn't a real trap; we need to
+ * return the default value.
+ */
+ target = current_ir & fivebits;
+ switch (Excp_format()) {
+ case SGL:
+ Sgl_setoverflow(Fpu_sgl(target));
+ break;
+ case DBL:
+ Dbl_setoverflow(Fpu_dblp1(target),Fpu_dblp2(target));
+ break;
+ }
+ Set_overflowflag();
+ /*
+ * Overflow always generates an inexact
+ * exception. If inexact trap is enabled,
+ * want to do an inexact trap, otherwise
+ * set inexact flag.
+ */
+ if (Is_inexacttrap_enabled()) {
+ /*
+ * Set exception field of exception
+ * register to inexact. Overflow
+ * bit should be cleared.
+ */
+ Set_exceptiontype(Fpu_register[exception_index],
+ INEXACTEXCEPTION);
+ update_trap_counts(Fpu_register, aflags, bflags,
+ trap_counts);
+ return SIGNALCODE(SIGFPE, FPE_FLTRES);
+ }
+ else {
+ /*
+ * Exception register needs to be cleared.
+ * Inexact flag needs to be set.
+ */
+ Clear_excp_register(exception_index);
+ Set_inexactflag();
+ }
+ }
+ break;
+ case INVALIDEXCEPTION:
+ case OPC_2E_INVALIDEXCEPTION:
+ update_trap_counts(Fpu_register, aflags, bflags, trap_counts);
+ return SIGNALCODE(SIGFPE, FPE_FLTINV);
+ case DIVISIONBYZEROEXCEPTION:
+ update_trap_counts(Fpu_register, aflags, bflags, trap_counts);
+ Clear_excp_register(exception_index);
+ return SIGNALCODE(SIGFPE, FPE_FLTDIV);
+ case INEXACTEXCEPTION:
+ update_trap_counts(Fpu_register, aflags, bflags, trap_counts);
+ return SIGNALCODE(SIGFPE, FPE_FLTRES);
+ default:
+ update_trap_counts(Fpu_register, aflags, bflags, trap_counts);
+ printk("%s(%d) Unknown FPU exception 0x%x\n", __FILE__,
+ __LINE__, Excp_type(exception_index));
+ return SIGNALCODE(SIGILL, ILL_COPROC);
+ case NOEXCEPTION: /* no exception */
+ /*
+ * Clear exception register in case
+ * other fields are non-zero.
+ */
+ Clear_excp_register(exception_index);
+ break;
+ }
+ }
+ /*
+ * No real exceptions occurred.
+ */
+ Clear_tbit();
+ update_trap_counts(Fpu_register, aflags, bflags, trap_counts);
+ return(NOTRAP);
+}
diff --git a/arch/parisc/math-emu/denormal.c b/arch/parisc/math-emu/denormal.c
new file mode 100644
index 000000000..7f1a60d59
--- /dev/null
+++ b/arch/parisc/math-emu/denormal.c
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ */
+/*
+ * BEGIN_DESC
+ *
+ * File:
+ * @(#) pa/fp/denormal.c $ Revision: $
+ *
+ * Purpose:
+ * <<please update with a synopsis of the functionality provided by this file>>
+ *
+ * External Interfaces:
+ * <<the following list was autogenerated, please review>>
+ * dbl_denormalize(dbl_opndp1,dbl_opndp2,inexactflag,rmode)
+ * sgl_denormalize(sgl_opnd,inexactflag,rmode)
+ *
+ * Internal Interfaces:
+ * <<please update>>
+ *
+ * Theory:
+ * <<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+
+#include "float.h"
+#include "sgl_float.h"
+#include "dbl_float.h"
+#include "hppa.h"
+#include <linux/kernel.h>
+/* #include <machine/sys/mdep_private.h> */
+
+#undef Fpustatus_register
+#define Fpustatus_register Fpu_register[0]
+
+void
+sgl_denormalize(unsigned int *sgl_opnd, boolean *inexactflag, int rmode)
+{
+ unsigned int opnd;
+ int sign, exponent;
+ boolean guardbit = FALSE, stickybit, inexact;
+
+ opnd = *sgl_opnd;
+ stickybit = *inexactflag;
+ exponent = Sgl_exponent(opnd) - SGL_WRAP;
+ sign = Sgl_sign(opnd);
+ Sgl_denormalize(opnd,exponent,guardbit,stickybit,inexact);
+ if (inexact) {
+ switch (rmode) {
+ case ROUNDPLUS:
+ if (sign == 0) {
+ Sgl_increment(opnd);
+ }
+ break;
+ case ROUNDMINUS:
+ if (sign != 0) {
+ Sgl_increment(opnd);
+ }
+ break;
+ case ROUNDNEAREST:
+ if (guardbit && (stickybit ||
+ Sgl_isone_lowmantissa(opnd))) {
+ Sgl_increment(opnd);
+ }
+ break;
+ }
+ }
+ Sgl_set_sign(opnd,sign);
+ *sgl_opnd = opnd;
+ *inexactflag = inexact;
+ return;
+}
+
+void
+dbl_denormalize(unsigned int *dbl_opndp1,
+ unsigned int * dbl_opndp2,
+ boolean *inexactflag,
+ int rmode)
+{
+ unsigned int opndp1, opndp2;
+ int sign, exponent;
+ boolean guardbit = FALSE, stickybit, inexact;
+
+ opndp1 = *dbl_opndp1;
+ opndp2 = *dbl_opndp2;
+ stickybit = *inexactflag;
+ exponent = Dbl_exponent(opndp1) - DBL_WRAP;
+ sign = Dbl_sign(opndp1);
+ Dbl_denormalize(opndp1,opndp2,exponent,guardbit,stickybit,inexact);
+ if (inexact) {
+ switch (rmode) {
+ case ROUNDPLUS:
+ if (sign == 0) {
+ Dbl_increment(opndp1,opndp2);
+ }
+ break;
+ case ROUNDMINUS:
+ if (sign != 0) {
+ Dbl_increment(opndp1,opndp2);
+ }
+ break;
+ case ROUNDNEAREST:
+ if (guardbit && (stickybit ||
+ Dbl_isone_lowmantissap2(opndp2))) {
+ Dbl_increment(opndp1,opndp2);
+ }
+ break;
+ }
+ }
+ Dbl_set_sign(opndp1,sign);
+ *dbl_opndp1 = opndp1;
+ *dbl_opndp2 = opndp2;
+ *inexactflag = inexact;
+ return;
+}
diff --git a/arch/parisc/math-emu/dfadd.c b/arch/parisc/math-emu/dfadd.c
new file mode 100644
index 000000000..00e561d4a
--- /dev/null
+++ b/arch/parisc/math-emu/dfadd.c
@@ -0,0 +1,511 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ */
+/*
+ * BEGIN_DESC
+ *
+ * File:
+ * @(#) pa/spmath/dfadd.c $Revision: 1.1 $
+ *
+ * Purpose:
+ * Double_add: add two double precision values.
+ *
+ * External Interfaces:
+ * dbl_fadd(leftptr, rightptr, dstptr, status)
+ *
+ * Internal Interfaces:
+ *
+ * Theory:
+ * <<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "dbl_float.h"
+
+/*
+ * Double_add: add two double precision values.
+ */
+dbl_fadd(
+ dbl_floating_point *leftptr,
+ dbl_floating_point *rightptr,
+ dbl_floating_point *dstptr,
+ unsigned int *status)
+{
+ register unsigned int signless_upper_left, signless_upper_right, save;
+ register unsigned int leftp1, leftp2, rightp1, rightp2, extent;
+ register unsigned int resultp1 = 0, resultp2 = 0;
+
+ register int result_exponent, right_exponent, diff_exponent;
+ register int sign_save, jumpsize;
+ register boolean inexact = FALSE;
+ register boolean underflowtrap;
+
+ /* Create local copies of the numbers */
+ Dbl_copyfromptr(leftptr,leftp1,leftp2);
+ Dbl_copyfromptr(rightptr,rightp1,rightp2);
+
+ /* A zero "save" helps discover equal operands (for later), *
+ * and is used in swapping operands (if needed). */
+ Dbl_xortointp1(leftp1,rightp1,/*to*/save);
+
+ /*
+ * check first operand for NaN's or infinity
+ */
+ if ((result_exponent = Dbl_exponent(leftp1)) == DBL_INFINITY_EXPONENT)
+ {
+ if (Dbl_iszero_mantissa(leftp1,leftp2))
+ {
+ if (Dbl_isnotnan(rightp1,rightp2))
+ {
+ if (Dbl_isinfinity(rightp1,rightp2) && save!=0)
+ {
+ /*
+ * invalid since operands are opposite signed infinity's
+ */
+ if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+ Set_invalidflag();
+ Dbl_makequietnan(resultp1,resultp2);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /*
+ * return infinity
+ */
+ Dbl_copytoptr(leftp1,leftp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ }
+ else
+ {
+ /*
+ * is NaN; signaling or quiet?
+ */
+ if (Dbl_isone_signaling(leftp1))
+ {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Dbl_set_quiet(leftp1);
+ }
+ /*
+ * is second operand a signaling NaN?
+ */
+ else if (Dbl_is_signalingnan(rightp1))
+ {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Dbl_set_quiet(rightp1);
+ Dbl_copytoptr(rightp1,rightp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /*
+ * return quiet NaN
+ */
+ Dbl_copytoptr(leftp1,leftp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ } /* End left NaN or Infinity processing */
+ /*
+ * check second operand for NaN's or infinity
+ */
+ if (Dbl_isinfinity_exponent(rightp1))
+ {
+ if (Dbl_iszero_mantissa(rightp1,rightp2))
+ {
+ /* return infinity */
+ Dbl_copytoptr(rightp1,rightp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /*
+ * is NaN; signaling or quiet?
+ */
+ if (Dbl_isone_signaling(rightp1))
+ {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Dbl_set_quiet(rightp1);
+ }
+ /*
+ * return quiet NaN
+ */
+ Dbl_copytoptr(rightp1,rightp2,dstptr);
+ return(NOEXCEPTION);
+ } /* End right NaN or Infinity processing */
+
+ /* Invariant: Must be dealing with finite numbers */
+
+ /* Compare operands by removing the sign */
+ Dbl_copytoint_exponentmantissap1(leftp1,signless_upper_left);
+ Dbl_copytoint_exponentmantissap1(rightp1,signless_upper_right);
+
+ /* sign difference selects add or sub operation. */
+ if(Dbl_ismagnitudeless(leftp2,rightp2,signless_upper_left,signless_upper_right))
+ {
+ /* Set the left operand to the larger one by XOR swap *
+ * First finish the first word using "save" */
+ Dbl_xorfromintp1(save,rightp1,/*to*/rightp1);
+ Dbl_xorfromintp1(save,leftp1,/*to*/leftp1);
+ Dbl_swap_lower(leftp2,rightp2);
+ result_exponent = Dbl_exponent(leftp1);
+ }
+ /* Invariant: left is not smaller than right. */
+
+ if((right_exponent = Dbl_exponent(rightp1)) == 0)
+ {
+ /* Denormalized operands. First look for zeroes */
+ if(Dbl_iszero_mantissa(rightp1,rightp2))
+ {
+ /* right is zero */
+ if(Dbl_iszero_exponentmantissa(leftp1,leftp2))
+ {
+ /* Both operands are zeros */
+ if(Is_rounding_mode(ROUNDMINUS))
+ {
+ Dbl_or_signs(leftp1,/*with*/rightp1);
+ }
+ else
+ {
+ Dbl_and_signs(leftp1,/*with*/rightp1);
+ }
+ }
+ else
+ {
+ /* Left is not a zero and must be the result. Trapped
+ * underflows are signaled if left is denormalized. Result
+ * is always exact. */
+ if( (result_exponent == 0) && Is_underflowtrap_enabled() )
+ {
+ /* need to normalize results mantissa */
+ sign_save = Dbl_signextendedsign(leftp1);
+ Dbl_leftshiftby1(leftp1,leftp2);
+ Dbl_normalize(leftp1,leftp2,result_exponent);
+ Dbl_set_sign(leftp1,/*using*/sign_save);
+ Dbl_setwrapped_exponent(leftp1,result_exponent,unfl);
+ Dbl_copytoptr(leftp1,leftp2,dstptr);
+ /* inexact = FALSE */
+ return(UNDERFLOWEXCEPTION);
+ }
+ }
+ Dbl_copytoptr(leftp1,leftp2,dstptr);
+ return(NOEXCEPTION);
+ }
+
+ /* Neither are zeroes */
+ Dbl_clear_sign(rightp1); /* Exponent is already cleared */
+ if(result_exponent == 0 )
+ {
+ /* Both operands are denormalized. The result must be exact
+ * and is simply calculated. A sum could become normalized and a
+ * difference could cancel to a true zero. */
+ if( (/*signed*/int) save < 0 )
+ {
+ Dbl_subtract(leftp1,leftp2,/*minus*/rightp1,rightp2,
+ /*into*/resultp1,resultp2);
+ if(Dbl_iszero_mantissa(resultp1,resultp2))
+ {
+ if(Is_rounding_mode(ROUNDMINUS))
+ {
+ Dbl_setone_sign(resultp1);
+ }
+ else
+ {
+ Dbl_setzero_sign(resultp1);
+ }
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ }
+ else
+ {
+ Dbl_addition(leftp1,leftp2,rightp1,rightp2,
+ /*into*/resultp1,resultp2);
+ if(Dbl_isone_hidden(resultp1))
+ {
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ }
+ if(Is_underflowtrap_enabled())
+ {
+ /* need to normalize result */
+ sign_save = Dbl_signextendedsign(resultp1);
+ Dbl_leftshiftby1(resultp1,resultp2);
+ Dbl_normalize(resultp1,resultp2,result_exponent);
+ Dbl_set_sign(resultp1,/*using*/sign_save);
+ Dbl_setwrapped_exponent(resultp1,result_exponent,unfl);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ /* inexact = FALSE */
+ return(UNDERFLOWEXCEPTION);
+ }
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ right_exponent = 1; /* Set exponent to reflect different bias
+ * with denormalized numbers. */
+ }
+ else
+ {
+ Dbl_clear_signexponent_set_hidden(rightp1);
+ }
+ Dbl_clear_exponent_set_hidden(leftp1);
+ diff_exponent = result_exponent - right_exponent;
+
+ /*
+ * Special case alignment of operands that would force alignment
+ * beyond the extent of the extension. A further optimization
+ * could special case this but only reduces the path length for this
+ * infrequent case.
+ */
+ if(diff_exponent > DBL_THRESHOLD)
+ {
+ diff_exponent = DBL_THRESHOLD;
+ }
+
+ /* Align right operand by shifting to right */
+ Dbl_right_align(/*operand*/rightp1,rightp2,/*shifted by*/diff_exponent,
+ /*and lower to*/extent);
+
+ /* Treat sum and difference of the operands separately. */
+ if( (/*signed*/int) save < 0 )
+ {
+ /*
+ * Difference of the two operands. Their can be no overflow. A
+ * borrow can occur out of the hidden bit and force a post
+ * normalization phase.
+ */
+ Dbl_subtract_withextension(leftp1,leftp2,/*minus*/rightp1,rightp2,
+ /*with*/extent,/*into*/resultp1,resultp2);
+ if(Dbl_iszero_hidden(resultp1))
+ {
+ /* Handle normalization */
+ /* A straight forward algorithm would now shift the result
+ * and extension left until the hidden bit becomes one. Not
+ * all of the extension bits need participate in the shift.
+ * Only the two most significant bits (round and guard) are
+ * needed. If only a single shift is needed then the guard
+ * bit becomes a significant low order bit and the extension
+ * must participate in the rounding. If more than a single
+ * shift is needed, then all bits to the right of the guard
+ * bit are zeros, and the guard bit may or may not be zero. */
+ sign_save = Dbl_signextendedsign(resultp1);
+ Dbl_leftshiftby1_withextent(resultp1,resultp2,extent,resultp1,resultp2);
+
+ /* Need to check for a zero result. The sign and exponent
+ * fields have already been zeroed. The more efficient test
+ * of the full object can be used.
+ */
+ if(Dbl_iszero(resultp1,resultp2))
+ /* Must have been "x-x" or "x+(-x)". */
+ {
+ if(Is_rounding_mode(ROUNDMINUS)) Dbl_setone_sign(resultp1);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ result_exponent--;
+ /* Look to see if normalization is finished. */
+ if(Dbl_isone_hidden(resultp1))
+ {
+ if(result_exponent==0)
+ {
+ /* Denormalized, exponent should be zero. Left operand *
+ * was normalized, so extent (guard, round) was zero */
+ goto underflow;
+ }
+ else
+ {
+ /* No further normalization is needed. */
+ Dbl_set_sign(resultp1,/*using*/sign_save);
+ Ext_leftshiftby1(extent);
+ goto round;
+ }
+ }
+
+ /* Check for denormalized, exponent should be zero. Left *
+ * operand was normalized, so extent (guard, round) was zero */
+ if(!(underflowtrap = Is_underflowtrap_enabled()) &&
+ result_exponent==0) goto underflow;
+
+ /* Shift extension to complete one bit of normalization and
+ * update exponent. */
+ Ext_leftshiftby1(extent);
+
+ /* Discover first one bit to determine shift amount. Use a
+ * modified binary search. We have already shifted the result
+ * one position right and still not found a one so the remainder
+ * of the extension must be zero and simplifies rounding. */
+ /* Scan bytes */
+ while(Dbl_iszero_hiddenhigh7mantissa(resultp1))
+ {
+ Dbl_leftshiftby8(resultp1,resultp2);
+ if((result_exponent -= 8) <= 0 && !underflowtrap)
+ goto underflow;
+ }
+ /* Now narrow it down to the nibble */
+ if(Dbl_iszero_hiddenhigh3mantissa(resultp1))
+ {
+ /* The lower nibble contains the normalizing one */
+ Dbl_leftshiftby4(resultp1,resultp2);
+ if((result_exponent -= 4) <= 0 && !underflowtrap)
+ goto underflow;
+ }
+ /* Select case were first bit is set (already normalized)
+ * otherwise select the proper shift. */
+ if((jumpsize = Dbl_hiddenhigh3mantissa(resultp1)) > 7)
+ {
+ /* Already normalized */
+ if(result_exponent <= 0) goto underflow;
+ Dbl_set_sign(resultp1,/*using*/sign_save);
+ Dbl_set_exponent(resultp1,/*using*/result_exponent);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ Dbl_sethigh4bits(resultp1,/*using*/sign_save);
+ switch(jumpsize)
+ {
+ case 1:
+ {
+ Dbl_leftshiftby3(resultp1,resultp2);
+ result_exponent -= 3;
+ break;
+ }
+ case 2:
+ case 3:
+ {
+ Dbl_leftshiftby2(resultp1,resultp2);
+ result_exponent -= 2;
+ break;
+ }
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ {
+ Dbl_leftshiftby1(resultp1,resultp2);
+ result_exponent -= 1;
+ break;
+ }
+ }
+ if(result_exponent > 0)
+ {
+ Dbl_set_exponent(resultp1,/*using*/result_exponent);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION); /* Sign bit is already set */
+ }
+ /* Fixup potential underflows */
+ underflow:
+ if(Is_underflowtrap_enabled())
+ {
+ Dbl_set_sign(resultp1,sign_save);
+ Dbl_setwrapped_exponent(resultp1,result_exponent,unfl);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ /* inexact = FALSE */
+ return(UNDERFLOWEXCEPTION);
+ }
+ /*
+ * Since we cannot get an inexact denormalized result,
+ * we can now return.
+ */
+ Dbl_fix_overshift(resultp1,resultp2,(1-result_exponent),extent);
+ Dbl_clear_signexponent(resultp1);
+ Dbl_set_sign(resultp1,sign_save);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ } /* end if(hidden...)... */
+ /* Fall through and round */
+ } /* end if(save < 0)... */
+ else
+ {
+ /* Add magnitudes */
+ Dbl_addition(leftp1,leftp2,rightp1,rightp2,/*to*/resultp1,resultp2);
+ if(Dbl_isone_hiddenoverflow(resultp1))
+ {
+ /* Prenormalization required. */
+ Dbl_rightshiftby1_withextent(resultp2,extent,extent);
+ Dbl_arithrightshiftby1(resultp1,resultp2);
+ result_exponent++;
+ } /* end if hiddenoverflow... */
+ } /* end else ...add magnitudes... */
+
+ /* Round the result. If the extension is all zeros,then the result is
+ * exact. Otherwise round in the correct direction. No underflow is
+ * possible. If a postnormalization is necessary, then the mantissa is
+ * all zeros so no shift is needed. */
+ round:
+ if(Ext_isnotzero(extent))
+ {
+ inexact = TRUE;
+ switch(Rounding_mode())
+ {
+ case ROUNDNEAREST: /* The default. */
+ if(Ext_isone_sign(extent))
+ {
+ /* at least 1/2 ulp */
+ if(Ext_isnotzero_lower(extent) ||
+ Dbl_isone_lowmantissap2(resultp2))
+ {
+ /* either exactly half way and odd or more than 1/2ulp */
+ Dbl_increment(resultp1,resultp2);
+ }
+ }
+ break;
+
+ case ROUNDPLUS:
+ if(Dbl_iszero_sign(resultp1))
+ {
+ /* Round up positive results */
+ Dbl_increment(resultp1,resultp2);
+ }
+ break;
+
+ case ROUNDMINUS:
+ if(Dbl_isone_sign(resultp1))
+ {
+ /* Round down negative results */
+ Dbl_increment(resultp1,resultp2);
+ }
+
+ case ROUNDZERO:;
+ /* truncate is simple */
+ } /* end switch... */
+ if(Dbl_isone_hiddenoverflow(resultp1)) result_exponent++;
+ }
+ if(result_exponent == DBL_INFINITY_EXPONENT)
+ {
+ /* Overflow */
+ if(Is_overflowtrap_enabled())
+ {
+ Dbl_setwrapped_exponent(resultp1,result_exponent,ovfl);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ if (inexact)
+ if (Is_inexacttrap_enabled())
+ return(OVERFLOWEXCEPTION | INEXACTEXCEPTION);
+ else Set_inexactflag();
+ return(OVERFLOWEXCEPTION);
+ }
+ else
+ {
+ inexact = TRUE;
+ Set_overflowflag();
+ Dbl_setoverflow(resultp1,resultp2);
+ }
+ }
+ else Dbl_set_exponent(resultp1,result_exponent);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ if(inexact)
+ if(Is_inexacttrap_enabled())
+ return(INEXACTEXCEPTION);
+ else Set_inexactflag();
+ return(NOEXCEPTION);
+}
diff --git a/arch/parisc/math-emu/dfcmp.c b/arch/parisc/math-emu/dfcmp.c
new file mode 100644
index 000000000..ae4b49744
--- /dev/null
+++ b/arch/parisc/math-emu/dfcmp.c
@@ -0,0 +1,168 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ */
+/*
+ * BEGIN_DESC
+ *
+ * File:
+ * @(#) pa/spmath/dfcmp.c $Revision: 1.1 $
+ *
+ * Purpose:
+ * dbl_cmp: compare two values
+ *
+ * External Interfaces:
+ * dbl_fcmp(leftptr, rightptr, cond, status)
+ *
+ * Internal Interfaces:
+ *
+ * Theory:
+ * <<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+
+#include "float.h"
+#include "dbl_float.h"
+
+/*
+ * dbl_cmp: compare two values
+ */
+int
+dbl_fcmp (dbl_floating_point * leftptr, dbl_floating_point * rightptr,
+ unsigned int cond, unsigned int *status)
+
+ /* The predicate to be tested */
+
+ {
+ register unsigned int leftp1, leftp2, rightp1, rightp2;
+ register int xorresult;
+
+ /* Create local copies of the numbers */
+ Dbl_copyfromptr(leftptr,leftp1,leftp2);
+ Dbl_copyfromptr(rightptr,rightp1,rightp2);
+ /*
+ * Test for NaN
+ */
+ if( (Dbl_exponent(leftp1) == DBL_INFINITY_EXPONENT)
+ || (Dbl_exponent(rightp1) == DBL_INFINITY_EXPONENT) )
+ {
+ /* Check if a NaN is involved. Signal an invalid exception when
+ * comparing a signaling NaN or when comparing quiet NaNs and the
+ * low bit of the condition is set */
+ if( ((Dbl_exponent(leftp1) == DBL_INFINITY_EXPONENT)
+ && Dbl_isnotzero_mantissa(leftp1,leftp2)
+ && (Exception(cond) || Dbl_isone_signaling(leftp1)))
+ ||
+ ((Dbl_exponent(rightp1) == DBL_INFINITY_EXPONENT)
+ && Dbl_isnotzero_mantissa(rightp1,rightp2)
+ && (Exception(cond) || Dbl_isone_signaling(rightp1))) )
+ {
+ if( Is_invalidtrap_enabled() ) {
+ Set_status_cbit(Unordered(cond));
+ return(INVALIDEXCEPTION);
+ }
+ else Set_invalidflag();
+ Set_status_cbit(Unordered(cond));
+ return(NOEXCEPTION);
+ }
+ /* All the exceptional conditions are handled, now special case
+ NaN compares */
+ else if( ((Dbl_exponent(leftp1) == DBL_INFINITY_EXPONENT)
+ && Dbl_isnotzero_mantissa(leftp1,leftp2))
+ ||
+ ((Dbl_exponent(rightp1) == DBL_INFINITY_EXPONENT)
+ && Dbl_isnotzero_mantissa(rightp1,rightp2)) )
+ {
+ /* NaNs always compare unordered. */
+ Set_status_cbit(Unordered(cond));
+ return(NOEXCEPTION);
+ }
+ /* infinities will drop down to the normal compare mechanisms */
+ }
+ /* First compare for unequal signs => less or greater or
+ * special equal case */
+ Dbl_xortointp1(leftp1,rightp1,xorresult);
+ if( xorresult < 0 )
+ {
+ /* left negative => less, left positive => greater.
+ * equal is possible if both operands are zeros. */
+ if( Dbl_iszero_exponentmantissa(leftp1,leftp2)
+ && Dbl_iszero_exponentmantissa(rightp1,rightp2) )
+ {
+ Set_status_cbit(Equal(cond));
+ }
+ else if( Dbl_isone_sign(leftp1) )
+ {
+ Set_status_cbit(Lessthan(cond));
+ }
+ else
+ {
+ Set_status_cbit(Greaterthan(cond));
+ }
+ }
+ /* Signs are the same. Treat negative numbers separately
+ * from the positives because of the reversed sense. */
+ else if(Dbl_isequal(leftp1,leftp2,rightp1,rightp2))
+ {
+ Set_status_cbit(Equal(cond));
+ }
+ else if( Dbl_iszero_sign(leftp1) )
+ {
+ /* Positive compare */
+ if( Dbl_allp1(leftp1) < Dbl_allp1(rightp1) )
+ {
+ Set_status_cbit(Lessthan(cond));
+ }
+ else if( Dbl_allp1(leftp1) > Dbl_allp1(rightp1) )
+ {
+ Set_status_cbit(Greaterthan(cond));
+ }
+ else
+ {
+ /* Equal first parts. Now we must use unsigned compares to
+ * resolve the two possibilities. */
+ if( Dbl_allp2(leftp2) < Dbl_allp2(rightp2) )
+ {
+ Set_status_cbit(Lessthan(cond));
+ }
+ else
+ {
+ Set_status_cbit(Greaterthan(cond));
+ }
+ }
+ }
+ else
+ {
+ /* Negative compare. Signed or unsigned compares
+ * both work the same. That distinction is only
+ * important when the sign bits differ. */
+ if( Dbl_allp1(leftp1) > Dbl_allp1(rightp1) )
+ {
+ Set_status_cbit(Lessthan(cond));
+ }
+ else if( Dbl_allp1(leftp1) < Dbl_allp1(rightp1) )
+ {
+ Set_status_cbit(Greaterthan(cond));
+ }
+ else
+ {
+ /* Equal first parts. Now we must use unsigned compares to
+ * resolve the two possibilities. */
+ if( Dbl_allp2(leftp2) > Dbl_allp2(rightp2) )
+ {
+ Set_status_cbit(Lessthan(cond));
+ }
+ else
+ {
+ Set_status_cbit(Greaterthan(cond));
+ }
+ }
+ }
+ return(NOEXCEPTION);
+ }
diff --git a/arch/parisc/math-emu/dfdiv.c b/arch/parisc/math-emu/dfdiv.c
new file mode 100644
index 000000000..239150dbe
--- /dev/null
+++ b/arch/parisc/math-emu/dfdiv.c
@@ -0,0 +1,387 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ */
+/*
+ * BEGIN_DESC
+ *
+ * File:
+ * @(#) pa/spmath/dfdiv.c $Revision: 1.1 $
+ *
+ * Purpose:
+ * Double Precision Floating-point Divide
+ *
+ * External Interfaces:
+ * dbl_fdiv(srcptr1,srcptr2,dstptr,status)
+ *
+ * Internal Interfaces:
+ *
+ * Theory:
+ * <<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "dbl_float.h"
+
+/*
+ * Double Precision Floating-point Divide
+ */
+
+int
+dbl_fdiv (dbl_floating_point * srcptr1, dbl_floating_point * srcptr2,
+ dbl_floating_point * dstptr, unsigned int *status)
+{
+ register unsigned int opnd1p1, opnd1p2, opnd2p1, opnd2p2;
+ register unsigned int opnd3p1, opnd3p2, resultp1, resultp2;
+ register int dest_exponent, count;
+ register boolean inexact = FALSE, guardbit = FALSE, stickybit = FALSE;
+ boolean is_tiny;
+
+ Dbl_copyfromptr(srcptr1,opnd1p1,opnd1p2);
+ Dbl_copyfromptr(srcptr2,opnd2p1,opnd2p2);
+ /*
+ * set sign bit of result
+ */
+ if (Dbl_sign(opnd1p1) ^ Dbl_sign(opnd2p1))
+ Dbl_setnegativezerop1(resultp1);
+ else Dbl_setzerop1(resultp1);
+ /*
+ * check first operand for NaN's or infinity
+ */
+ if (Dbl_isinfinity_exponent(opnd1p1)) {
+ if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
+ if (Dbl_isnotnan(opnd2p1,opnd2p2)) {
+ if (Dbl_isinfinity(opnd2p1,opnd2p2)) {
+ /*
+ * invalid since both operands
+ * are infinity
+ */
+ if (Is_invalidtrap_enabled())
+ return(INVALIDEXCEPTION);
+ Set_invalidflag();
+ Dbl_makequietnan(resultp1,resultp2);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /*
+ * return infinity
+ */
+ Dbl_setinfinity_exponentmantissa(resultp1,resultp2);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ }
+ else {
+ /*
+ * is NaN; signaling or quiet?
+ */
+ if (Dbl_isone_signaling(opnd1p1)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled())
+ return(INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Dbl_set_quiet(opnd1p1);
+ }
+ /*
+ * is second operand a signaling NaN?
+ */
+ else if (Dbl_is_signalingnan(opnd2p1)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled())
+ return(INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Dbl_set_quiet(opnd2p1);
+ Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /*
+ * return quiet NaN
+ */
+ Dbl_copytoptr(opnd1p1,opnd1p2,dstptr);
+ return(NOEXCEPTION);
+ }
+ }
+ /*
+ * check second operand for NaN's or infinity
+ */
+ if (Dbl_isinfinity_exponent(opnd2p1)) {
+ if (Dbl_iszero_mantissa(opnd2p1,opnd2p2)) {
+ /*
+ * return zero
+ */
+ Dbl_setzero_exponentmantissa(resultp1,resultp2);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /*
+ * is NaN; signaling or quiet?
+ */
+ if (Dbl_isone_signaling(opnd2p1)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Dbl_set_quiet(opnd2p1);
+ }
+ /*
+ * return quiet NaN
+ */
+ Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /*
+ * check for division by zero
+ */
+ if (Dbl_iszero_exponentmantissa(opnd2p1,opnd2p2)) {
+ if (Dbl_iszero_exponentmantissa(opnd1p1,opnd1p2)) {
+ /* invalid since both operands are zero */
+ if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+ Set_invalidflag();
+ Dbl_makequietnan(resultp1,resultp2);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ if (Is_divisionbyzerotrap_enabled())
+ return(DIVISIONBYZEROEXCEPTION);
+ Set_divisionbyzeroflag();
+ Dbl_setinfinity_exponentmantissa(resultp1,resultp2);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /*
+ * Generate exponent
+ */
+ dest_exponent = Dbl_exponent(opnd1p1) - Dbl_exponent(opnd2p1) + DBL_BIAS;
+
+ /*
+ * Generate mantissa
+ */
+ if (Dbl_isnotzero_exponent(opnd1p1)) {
+ /* set hidden bit */
+ Dbl_clear_signexponent_set_hidden(opnd1p1);
+ }
+ else {
+ /* check for zero */
+ if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
+ Dbl_setzero_exponentmantissa(resultp1,resultp2);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /* is denormalized, want to normalize */
+ Dbl_clear_signexponent(opnd1p1);
+ Dbl_leftshiftby1(opnd1p1,opnd1p2);
+ Dbl_normalize(opnd1p1,opnd1p2,dest_exponent);
+ }
+ /* opnd2 needs to have hidden bit set with msb in hidden bit */
+ if (Dbl_isnotzero_exponent(opnd2p1)) {
+ Dbl_clear_signexponent_set_hidden(opnd2p1);
+ }
+ else {
+ /* is denormalized; want to normalize */
+ Dbl_clear_signexponent(opnd2p1);
+ Dbl_leftshiftby1(opnd2p1,opnd2p2);
+ while (Dbl_iszero_hiddenhigh7mantissa(opnd2p1)) {
+ dest_exponent+=8;
+ Dbl_leftshiftby8(opnd2p1,opnd2p2);
+ }
+ if (Dbl_iszero_hiddenhigh3mantissa(opnd2p1)) {
+ dest_exponent+=4;
+ Dbl_leftshiftby4(opnd2p1,opnd2p2);
+ }
+ while (Dbl_iszero_hidden(opnd2p1)) {
+ dest_exponent++;
+ Dbl_leftshiftby1(opnd2p1,opnd2p2);
+ }
+ }
+
+ /* Divide the source mantissas */
+
+ /*
+ * A non-restoring divide algorithm is used.
+ */
+ Twoword_subtract(opnd1p1,opnd1p2,opnd2p1,opnd2p2);
+ Dbl_setzero(opnd3p1,opnd3p2);
+ for (count=1; count <= DBL_P && (opnd1p1 || opnd1p2); count++) {
+ Dbl_leftshiftby1(opnd1p1,opnd1p2);
+ Dbl_leftshiftby1(opnd3p1,opnd3p2);
+ if (Dbl_iszero_sign(opnd1p1)) {
+ Dbl_setone_lowmantissap2(opnd3p2);
+ Twoword_subtract(opnd1p1,opnd1p2,opnd2p1,opnd2p2);
+ }
+ else {
+ Twoword_add(opnd1p1, opnd1p2, opnd2p1, opnd2p2);
+ }
+ }
+ if (count <= DBL_P) {
+ Dbl_leftshiftby1(opnd3p1,opnd3p2);
+ Dbl_setone_lowmantissap2(opnd3p2);
+ Dbl_leftshift(opnd3p1,opnd3p2,(DBL_P-count));
+ if (Dbl_iszero_hidden(opnd3p1)) {
+ Dbl_leftshiftby1(opnd3p1,opnd3p2);
+ dest_exponent--;
+ }
+ }
+ else {
+ if (Dbl_iszero_hidden(opnd3p1)) {
+ /* need to get one more bit of result */
+ Dbl_leftshiftby1(opnd1p1,opnd1p2);
+ Dbl_leftshiftby1(opnd3p1,opnd3p2);
+ if (Dbl_iszero_sign(opnd1p1)) {
+ Dbl_setone_lowmantissap2(opnd3p2);
+ Twoword_subtract(opnd1p1,opnd1p2,opnd2p1,opnd2p2);
+ }
+ else {
+ Twoword_add(opnd1p1,opnd1p2,opnd2p1,opnd2p2);
+ }
+ dest_exponent--;
+ }
+ if (Dbl_iszero_sign(opnd1p1)) guardbit = TRUE;
+ stickybit = Dbl_allp1(opnd1p1) || Dbl_allp2(opnd1p2);
+ }
+ inexact = guardbit | stickybit;
+
+ /*
+ * round result
+ */
+ if (inexact && (dest_exponent > 0 || Is_underflowtrap_enabled())) {
+ Dbl_clear_signexponent(opnd3p1);
+ switch (Rounding_mode()) {
+ case ROUNDPLUS:
+ if (Dbl_iszero_sign(resultp1))
+ Dbl_increment(opnd3p1,opnd3p2);
+ break;
+ case ROUNDMINUS:
+ if (Dbl_isone_sign(resultp1))
+ Dbl_increment(opnd3p1,opnd3p2);
+ break;
+ case ROUNDNEAREST:
+ if (guardbit && (stickybit ||
+ Dbl_isone_lowmantissap2(opnd3p2))) {
+ Dbl_increment(opnd3p1,opnd3p2);
+ }
+ }
+ if (Dbl_isone_hidden(opnd3p1)) dest_exponent++;
+ }
+ Dbl_set_mantissa(resultp1,resultp2,opnd3p1,opnd3p2);
+
+ /*
+ * Test for overflow
+ */
+ if (dest_exponent >= DBL_INFINITY_EXPONENT) {
+ /* trap if OVERFLOWTRAP enabled */
+ if (Is_overflowtrap_enabled()) {
+ /*
+ * Adjust bias of result
+ */
+ Dbl_setwrapped_exponent(resultp1,dest_exponent,ovfl);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ if (inexact)
+ if (Is_inexacttrap_enabled())
+ return(OVERFLOWEXCEPTION | INEXACTEXCEPTION);
+ else Set_inexactflag();
+ return(OVERFLOWEXCEPTION);
+ }
+ Set_overflowflag();
+ /* set result to infinity or largest number */
+ Dbl_setoverflow(resultp1,resultp2);
+ inexact = TRUE;
+ }
+ /*
+ * Test for underflow
+ */
+ else if (dest_exponent <= 0) {
+ /* trap if UNDERFLOWTRAP enabled */
+ if (Is_underflowtrap_enabled()) {
+ /*
+ * Adjust bias of result
+ */
+ Dbl_setwrapped_exponent(resultp1,dest_exponent,unfl);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ if (inexact)
+ if (Is_inexacttrap_enabled())
+ return(UNDERFLOWEXCEPTION | INEXACTEXCEPTION);
+ else Set_inexactflag();
+ return(UNDERFLOWEXCEPTION);
+ }
+
+ /* Determine if should set underflow flag */
+ is_tiny = TRUE;
+ if (dest_exponent == 0 && inexact) {
+ switch (Rounding_mode()) {
+ case ROUNDPLUS:
+ if (Dbl_iszero_sign(resultp1)) {
+ Dbl_increment(opnd3p1,opnd3p2);
+ if (Dbl_isone_hiddenoverflow(opnd3p1))
+ is_tiny = FALSE;
+ Dbl_decrement(opnd3p1,opnd3p2);
+ }
+ break;
+ case ROUNDMINUS:
+ if (Dbl_isone_sign(resultp1)) {
+ Dbl_increment(opnd3p1,opnd3p2);
+ if (Dbl_isone_hiddenoverflow(opnd3p1))
+ is_tiny = FALSE;
+ Dbl_decrement(opnd3p1,opnd3p2);
+ }
+ break;
+ case ROUNDNEAREST:
+ if (guardbit && (stickybit ||
+ Dbl_isone_lowmantissap2(opnd3p2))) {
+ Dbl_increment(opnd3p1,opnd3p2);
+ if (Dbl_isone_hiddenoverflow(opnd3p1))
+ is_tiny = FALSE;
+ Dbl_decrement(opnd3p1,opnd3p2);
+ }
+ break;
+ }
+ }
+
+ /*
+ * denormalize result or set to signed zero
+ */
+ stickybit = inexact;
+ Dbl_denormalize(opnd3p1,opnd3p2,dest_exponent,guardbit,
+ stickybit,inexact);
+
+ /* return rounded number */
+ if (inexact) {
+ switch (Rounding_mode()) {
+ case ROUNDPLUS:
+ if (Dbl_iszero_sign(resultp1)) {
+ Dbl_increment(opnd3p1,opnd3p2);
+ }
+ break;
+ case ROUNDMINUS:
+ if (Dbl_isone_sign(resultp1)) {
+ Dbl_increment(opnd3p1,opnd3p2);
+ }
+ break;
+ case ROUNDNEAREST:
+ if (guardbit && (stickybit ||
+ Dbl_isone_lowmantissap2(opnd3p2))) {
+ Dbl_increment(opnd3p1,opnd3p2);
+ }
+ break;
+ }
+ if (is_tiny) Set_underflowflag();
+ }
+ Dbl_set_exponentmantissa(resultp1,resultp2,opnd3p1,opnd3p2);
+ }
+ else Dbl_set_exponent(resultp1,dest_exponent);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+
+ /* check for inexact */
+ if (inexact) {
+ if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+ else Set_inexactflag();
+ }
+ return(NOEXCEPTION);
+}
diff --git a/arch/parisc/math-emu/dfmpy.c b/arch/parisc/math-emu/dfmpy.c
new file mode 100644
index 000000000..87e0ce849
--- /dev/null
+++ b/arch/parisc/math-emu/dfmpy.c
@@ -0,0 +1,381 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ */
+/*
+ * BEGIN_DESC
+ *
+ * File:
+ * @(#) pa/spmath/dfmpy.c $Revision: 1.1 $
+ *
+ * Purpose:
+ * Double Precision Floating-point Multiply
+ *
+ * External Interfaces:
+ * dbl_fmpy(srcptr1,srcptr2,dstptr,status)
+ *
+ * Internal Interfaces:
+ *
+ * Theory:
+ * <<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "dbl_float.h"
+
+/*
+ * Double Precision Floating-point Multiply
+ */
+
+int
+dbl_fmpy(
+ dbl_floating_point *srcptr1,
+ dbl_floating_point *srcptr2,
+ dbl_floating_point *dstptr,
+ unsigned int *status)
+{
+ register unsigned int opnd1p1, opnd1p2, opnd2p1, opnd2p2;
+ register unsigned int opnd3p1, opnd3p2, resultp1, resultp2;
+ register int dest_exponent, count;
+ register boolean inexact = FALSE, guardbit = FALSE, stickybit = FALSE;
+ boolean is_tiny;
+
+ Dbl_copyfromptr(srcptr1,opnd1p1,opnd1p2);
+ Dbl_copyfromptr(srcptr2,opnd2p1,opnd2p2);
+
+ /*
+ * set sign bit of result
+ */
+ if (Dbl_sign(opnd1p1) ^ Dbl_sign(opnd2p1))
+ Dbl_setnegativezerop1(resultp1);
+ else Dbl_setzerop1(resultp1);
+ /*
+ * check first operand for NaN's or infinity
+ */
+ if (Dbl_isinfinity_exponent(opnd1p1)) {
+ if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
+ if (Dbl_isnotnan(opnd2p1,opnd2p2)) {
+ if (Dbl_iszero_exponentmantissa(opnd2p1,opnd2p2)) {
+ /*
+ * invalid since operands are infinity
+ * and zero
+ */
+ if (Is_invalidtrap_enabled())
+ return(INVALIDEXCEPTION);
+ Set_invalidflag();
+ Dbl_makequietnan(resultp1,resultp2);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /*
+ * return infinity
+ */
+ Dbl_setinfinity_exponentmantissa(resultp1,resultp2);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ }
+ else {
+ /*
+ * is NaN; signaling or quiet?
+ */
+ if (Dbl_isone_signaling(opnd1p1)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled())
+ return(INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Dbl_set_quiet(opnd1p1);
+ }
+ /*
+ * is second operand a signaling NaN?
+ */
+ else if (Dbl_is_signalingnan(opnd2p1)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled())
+ return(INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Dbl_set_quiet(opnd2p1);
+ Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /*
+ * return quiet NaN
+ */
+ Dbl_copytoptr(opnd1p1,opnd1p2,dstptr);
+ return(NOEXCEPTION);
+ }
+ }
+ /*
+ * check second operand for NaN's or infinity
+ */
+ if (Dbl_isinfinity_exponent(opnd2p1)) {
+ if (Dbl_iszero_mantissa(opnd2p1,opnd2p2)) {
+ if (Dbl_iszero_exponentmantissa(opnd1p1,opnd1p2)) {
+ /* invalid since operands are zero & infinity */
+ if (Is_invalidtrap_enabled())
+ return(INVALIDEXCEPTION);
+ Set_invalidflag();
+ Dbl_makequietnan(opnd2p1,opnd2p2);
+ Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /*
+ * return infinity
+ */
+ Dbl_setinfinity_exponentmantissa(resultp1,resultp2);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /*
+ * is NaN; signaling or quiet?
+ */
+ if (Dbl_isone_signaling(opnd2p1)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Dbl_set_quiet(opnd2p1);
+ }
+ /*
+ * return quiet NaN
+ */
+ Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /*
+ * Generate exponent
+ */
+ dest_exponent = Dbl_exponent(opnd1p1) + Dbl_exponent(opnd2p1) -DBL_BIAS;
+
+ /*
+ * Generate mantissa
+ */
+ if (Dbl_isnotzero_exponent(opnd1p1)) {
+ /* set hidden bit */
+ Dbl_clear_signexponent_set_hidden(opnd1p1);
+ }
+ else {
+ /* check for zero */
+ if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
+ Dbl_setzero_exponentmantissa(resultp1,resultp2);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /* is denormalized, adjust exponent */
+ Dbl_clear_signexponent(opnd1p1);
+ Dbl_leftshiftby1(opnd1p1,opnd1p2);
+ Dbl_normalize(opnd1p1,opnd1p2,dest_exponent);
+ }
+ /* opnd2 needs to have hidden bit set with msb in hidden bit */
+ if (Dbl_isnotzero_exponent(opnd2p1)) {
+ Dbl_clear_signexponent_set_hidden(opnd2p1);
+ }
+ else {
+ /* check for zero */
+ if (Dbl_iszero_mantissa(opnd2p1,opnd2p2)) {
+ Dbl_setzero_exponentmantissa(resultp1,resultp2);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /* is denormalized; want to normalize */
+ Dbl_clear_signexponent(opnd2p1);
+ Dbl_leftshiftby1(opnd2p1,opnd2p2);
+ Dbl_normalize(opnd2p1,opnd2p2,dest_exponent);
+ }
+
+ /* Multiply two source mantissas together */
+
+ /* make room for guard bits */
+ Dbl_leftshiftby7(opnd2p1,opnd2p2);
+ Dbl_setzero(opnd3p1,opnd3p2);
+ /*
+ * Four bits at a time are inspected in each loop, and a
+ * simple shift and add multiply algorithm is used.
+ */
+ for (count=1;count<=DBL_P;count+=4) {
+ stickybit |= Dlow4p2(opnd3p2);
+ Dbl_rightshiftby4(opnd3p1,opnd3p2);
+ if (Dbit28p2(opnd1p2)) {
+ /* Twoword_add should be an ADDC followed by an ADD. */
+ Twoword_add(opnd3p1, opnd3p2, opnd2p1<<3 | opnd2p2>>29,
+ opnd2p2<<3);
+ }
+ if (Dbit29p2(opnd1p2)) {
+ Twoword_add(opnd3p1, opnd3p2, opnd2p1<<2 | opnd2p2>>30,
+ opnd2p2<<2);
+ }
+ if (Dbit30p2(opnd1p2)) {
+ Twoword_add(opnd3p1, opnd3p2, opnd2p1<<1 | opnd2p2>>31,
+ opnd2p2<<1);
+ }
+ if (Dbit31p2(opnd1p2)) {
+ Twoword_add(opnd3p1, opnd3p2, opnd2p1, opnd2p2);
+ }
+ Dbl_rightshiftby4(opnd1p1,opnd1p2);
+ }
+ if (Dbit3p1(opnd3p1)==0) {
+ Dbl_leftshiftby1(opnd3p1,opnd3p2);
+ }
+ else {
+ /* result mantissa >= 2. */
+ dest_exponent++;
+ }
+ /* check for denormalized result */
+ while (Dbit3p1(opnd3p1)==0) {
+ Dbl_leftshiftby1(opnd3p1,opnd3p2);
+ dest_exponent--;
+ }
+ /*
+ * check for guard, sticky and inexact bits
+ */
+ stickybit |= Dallp2(opnd3p2) << 25;
+ guardbit = (Dallp2(opnd3p2) << 24) >> 31;
+ inexact = guardbit | stickybit;
+
+ /* align result mantissa */
+ Dbl_rightshiftby8(opnd3p1,opnd3p2);
+
+ /*
+ * round result
+ */
+ if (inexact && (dest_exponent>0 || Is_underflowtrap_enabled())) {
+ Dbl_clear_signexponent(opnd3p1);
+ switch (Rounding_mode()) {
+ case ROUNDPLUS:
+ if (Dbl_iszero_sign(resultp1))
+ Dbl_increment(opnd3p1,opnd3p2);
+ break;
+ case ROUNDMINUS:
+ if (Dbl_isone_sign(resultp1))
+ Dbl_increment(opnd3p1,opnd3p2);
+ break;
+ case ROUNDNEAREST:
+ if (guardbit) {
+ if (stickybit || Dbl_isone_lowmantissap2(opnd3p2))
+ Dbl_increment(opnd3p1,opnd3p2);
+ }
+ }
+ if (Dbl_isone_hidden(opnd3p1)) dest_exponent++;
+ }
+ Dbl_set_mantissa(resultp1,resultp2,opnd3p1,opnd3p2);
+
+ /*
+ * Test for overflow
+ */
+ if (dest_exponent >= DBL_INFINITY_EXPONENT) {
+ /* trap if OVERFLOWTRAP enabled */
+ if (Is_overflowtrap_enabled()) {
+ /*
+ * Adjust bias of result
+ */
+ Dbl_setwrapped_exponent(resultp1,dest_exponent,ovfl);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ if (inexact)
+ if (Is_inexacttrap_enabled())
+ return (OVERFLOWEXCEPTION | INEXACTEXCEPTION);
+ else Set_inexactflag();
+ return (OVERFLOWEXCEPTION);
+ }
+ inexact = TRUE;
+ Set_overflowflag();
+ /* set result to infinity or largest number */
+ Dbl_setoverflow(resultp1,resultp2);
+ }
+ /*
+ * Test for underflow
+ */
+ else if (dest_exponent <= 0) {
+ /* trap if UNDERFLOWTRAP enabled */
+ if (Is_underflowtrap_enabled()) {
+ /*
+ * Adjust bias of result
+ */
+ Dbl_setwrapped_exponent(resultp1,dest_exponent,unfl);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ if (inexact)
+ if (Is_inexacttrap_enabled())
+ return (UNDERFLOWEXCEPTION | INEXACTEXCEPTION);
+ else Set_inexactflag();
+ return (UNDERFLOWEXCEPTION);
+ }
+
+ /* Determine if should set underflow flag */
+ is_tiny = TRUE;
+ if (dest_exponent == 0 && inexact) {
+ switch (Rounding_mode()) {
+ case ROUNDPLUS:
+ if (Dbl_iszero_sign(resultp1)) {
+ Dbl_increment(opnd3p1,opnd3p2);
+ if (Dbl_isone_hiddenoverflow(opnd3p1))
+ is_tiny = FALSE;
+ Dbl_decrement(opnd3p1,opnd3p2);
+ }
+ break;
+ case ROUNDMINUS:
+ if (Dbl_isone_sign(resultp1)) {
+ Dbl_increment(opnd3p1,opnd3p2);
+ if (Dbl_isone_hiddenoverflow(opnd3p1))
+ is_tiny = FALSE;
+ Dbl_decrement(opnd3p1,opnd3p2);
+ }
+ break;
+ case ROUNDNEAREST:
+ if (guardbit && (stickybit ||
+ Dbl_isone_lowmantissap2(opnd3p2))) {
+ Dbl_increment(opnd3p1,opnd3p2);
+ if (Dbl_isone_hiddenoverflow(opnd3p1))
+ is_tiny = FALSE;
+ Dbl_decrement(opnd3p1,opnd3p2);
+ }
+ break;
+ }
+ }
+
+ /*
+ * denormalize result or set to signed zero
+ */
+ stickybit = inexact;
+ Dbl_denormalize(opnd3p1,opnd3p2,dest_exponent,guardbit,
+ stickybit,inexact);
+
+ /* return zero or smallest number */
+ if (inexact) {
+ switch (Rounding_mode()) {
+ case ROUNDPLUS:
+ if (Dbl_iszero_sign(resultp1)) {
+ Dbl_increment(opnd3p1,opnd3p2);
+ }
+ break;
+ case ROUNDMINUS:
+ if (Dbl_isone_sign(resultp1)) {
+ Dbl_increment(opnd3p1,opnd3p2);
+ }
+ break;
+ case ROUNDNEAREST:
+ if (guardbit && (stickybit ||
+ Dbl_isone_lowmantissap2(opnd3p2))) {
+ Dbl_increment(opnd3p1,opnd3p2);
+ }
+ break;
+ }
+ if (is_tiny) Set_underflowflag();
+ }
+ Dbl_set_exponentmantissa(resultp1,resultp2,opnd3p1,opnd3p2);
+ }
+ else Dbl_set_exponent(resultp1,dest_exponent);
+ /* check for inexact */
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ if (inexact) {
+ if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+ else Set_inexactflag();
+ }
+ return(NOEXCEPTION);
+}
diff --git a/arch/parisc/math-emu/dfrem.c b/arch/parisc/math-emu/dfrem.c
new file mode 100644
index 000000000..9243a5954
--- /dev/null
+++ b/arch/parisc/math-emu/dfrem.c
@@ -0,0 +1,284 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ */
+/*
+ * BEGIN_DESC
+ *
+ * File:
+ * @(#) pa/spmath/dfrem.c $Revision: 1.1 $
+ *
+ * Purpose:
+ * Double Precision Floating-point Remainder
+ *
+ * External Interfaces:
+ * dbl_frem(srcptr1,srcptr2,dstptr,status)
+ *
+ * Internal Interfaces:
+ *
+ * Theory:
+ * <<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+
+#include "float.h"
+#include "dbl_float.h"
+
+/*
+ * Double Precision Floating-point Remainder
+ */
+
+int
+dbl_frem (dbl_floating_point * srcptr1, dbl_floating_point * srcptr2,
+ dbl_floating_point * dstptr, unsigned int *status)
+{
+ register unsigned int opnd1p1, opnd1p2, opnd2p1, opnd2p2;
+ register unsigned int resultp1, resultp2;
+ register int opnd1_exponent, opnd2_exponent, dest_exponent, stepcount;
+ register boolean roundup = FALSE;
+
+ Dbl_copyfromptr(srcptr1,opnd1p1,opnd1p2);
+ Dbl_copyfromptr(srcptr2,opnd2p1,opnd2p2);
+ /*
+ * check first operand for NaN's or infinity
+ */
+ if ((opnd1_exponent = Dbl_exponent(opnd1p1)) == DBL_INFINITY_EXPONENT) {
+ if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
+ if (Dbl_isnotnan(opnd2p1,opnd2p2)) {
+ /* invalid since first operand is infinity */
+ if (Is_invalidtrap_enabled())
+ return(INVALIDEXCEPTION);
+ Set_invalidflag();
+ Dbl_makequietnan(resultp1,resultp2);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ }
+ else {
+ /*
+ * is NaN; signaling or quiet?
+ */
+ if (Dbl_isone_signaling(opnd1p1)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled())
+ return(INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Dbl_set_quiet(opnd1p1);
+ }
+ /*
+ * is second operand a signaling NaN?
+ */
+ else if (Dbl_is_signalingnan(opnd2p1)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled())
+ return(INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Dbl_set_quiet(opnd2p1);
+ Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /*
+ * return quiet NaN
+ */
+ Dbl_copytoptr(opnd1p1,opnd1p2,dstptr);
+ return(NOEXCEPTION);
+ }
+ }
+ /*
+ * check second operand for NaN's or infinity
+ */
+ if ((opnd2_exponent = Dbl_exponent(opnd2p1)) == DBL_INFINITY_EXPONENT) {
+ if (Dbl_iszero_mantissa(opnd2p1,opnd2p2)) {
+ /*
+ * return first operand
+ */
+ Dbl_copytoptr(opnd1p1,opnd1p2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /*
+ * is NaN; signaling or quiet?
+ */
+ if (Dbl_isone_signaling(opnd2p1)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Dbl_set_quiet(opnd2p1);
+ }
+ /*
+ * return quiet NaN
+ */
+ Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /*
+ * check second operand for zero
+ */
+ if (Dbl_iszero_exponentmantissa(opnd2p1,opnd2p2)) {
+ /* invalid since second operand is zero */
+ if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+ Set_invalidflag();
+ Dbl_makequietnan(resultp1,resultp2);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+
+ /*
+ * get sign of result
+ */
+ resultp1 = opnd1p1;
+
+ /*
+ * check for denormalized operands
+ */
+ if (opnd1_exponent == 0) {
+ /* check for zero */
+ if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
+ Dbl_copytoptr(opnd1p1,opnd1p2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /* normalize, then continue */
+ opnd1_exponent = 1;
+ Dbl_normalize(opnd1p1,opnd1p2,opnd1_exponent);
+ }
+ else {
+ Dbl_clear_signexponent_set_hidden(opnd1p1);
+ }
+ if (opnd2_exponent == 0) {
+ /* normalize, then continue */
+ opnd2_exponent = 1;
+ Dbl_normalize(opnd2p1,opnd2p2,opnd2_exponent);
+ }
+ else {
+ Dbl_clear_signexponent_set_hidden(opnd2p1);
+ }
+
+ /* find result exponent and divide step loop count */
+ dest_exponent = opnd2_exponent - 1;
+ stepcount = opnd1_exponent - opnd2_exponent;
+
+ /*
+ * check for opnd1/opnd2 < 1
+ */
+ if (stepcount < 0) {
+ /*
+ * check for opnd1/opnd2 > 1/2
+ *
+ * In this case n will round to 1, so
+ * r = opnd1 - opnd2
+ */
+ if (stepcount == -1 &&
+ Dbl_isgreaterthan(opnd1p1,opnd1p2,opnd2p1,opnd2p2)) {
+ /* set sign */
+ Dbl_allp1(resultp1) = ~Dbl_allp1(resultp1);
+ /* align opnd2 with opnd1 */
+ Dbl_leftshiftby1(opnd2p1,opnd2p2);
+ Dbl_subtract(opnd2p1,opnd2p2,opnd1p1,opnd1p2,
+ opnd2p1,opnd2p2);
+ /* now normalize */
+ while (Dbl_iszero_hidden(opnd2p1)) {
+ Dbl_leftshiftby1(opnd2p1,opnd2p2);
+ dest_exponent--;
+ }
+ Dbl_set_exponentmantissa(resultp1,resultp2,opnd2p1,opnd2p2);
+ goto testforunderflow;
+ }
+ /*
+ * opnd1/opnd2 <= 1/2
+ *
+ * In this case n will round to zero, so
+ * r = opnd1
+ */
+ Dbl_set_exponentmantissa(resultp1,resultp2,opnd1p1,opnd1p2);
+ dest_exponent = opnd1_exponent;
+ goto testforunderflow;
+ }
+
+ /*
+ * Generate result
+ *
+ * Do iterative subtract until remainder is less than operand 2.
+ */
+ while (stepcount-- > 0 && (Dbl_allp1(opnd1p1) || Dbl_allp2(opnd1p2))) {
+ if (Dbl_isnotlessthan(opnd1p1,opnd1p2,opnd2p1,opnd2p2)) {
+ Dbl_subtract(opnd1p1,opnd1p2,opnd2p1,opnd2p2,opnd1p1,opnd1p2);
+ }
+ Dbl_leftshiftby1(opnd1p1,opnd1p2);
+ }
+ /*
+ * Do last subtract, then determine which way to round if remainder
+ * is exactly 1/2 of opnd2
+ */
+ if (Dbl_isnotlessthan(opnd1p1,opnd1p2,opnd2p1,opnd2p2)) {
+ Dbl_subtract(opnd1p1,opnd1p2,opnd2p1,opnd2p2,opnd1p1,opnd1p2);
+ roundup = TRUE;
+ }
+ if (stepcount > 0 || Dbl_iszero(opnd1p1,opnd1p2)) {
+ /* division is exact, remainder is zero */
+ Dbl_setzero_exponentmantissa(resultp1,resultp2);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+
+ /*
+ * Check for cases where opnd1/opnd2 < n
+ *
+ * In this case the result's sign will be opposite that of
+ * opnd1. The mantissa also needs some correction.
+ */
+ Dbl_leftshiftby1(opnd1p1,opnd1p2);
+ if (Dbl_isgreaterthan(opnd1p1,opnd1p2,opnd2p1,opnd2p2)) {
+ Dbl_invert_sign(resultp1);
+ Dbl_leftshiftby1(opnd2p1,opnd2p2);
+ Dbl_subtract(opnd2p1,opnd2p2,opnd1p1,opnd1p2,opnd1p1,opnd1p2);
+ }
+ /* check for remainder being exactly 1/2 of opnd2 */
+ else if (Dbl_isequal(opnd1p1,opnd1p2,opnd2p1,opnd2p2) && roundup) {
+ Dbl_invert_sign(resultp1);
+ }
+
+ /* normalize result's mantissa */
+ while (Dbl_iszero_hidden(opnd1p1)) {
+ dest_exponent--;
+ Dbl_leftshiftby1(opnd1p1,opnd1p2);
+ }
+ Dbl_set_exponentmantissa(resultp1,resultp2,opnd1p1,opnd1p2);
+
+ /*
+ * Test for underflow
+ */
+ testforunderflow:
+ if (dest_exponent <= 0) {
+ /* trap if UNDERFLOWTRAP enabled */
+ if (Is_underflowtrap_enabled()) {
+ /*
+ * Adjust bias of result
+ */
+ Dbl_setwrapped_exponent(resultp1,dest_exponent,unfl);
+ /* frem is always exact */
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(UNDERFLOWEXCEPTION);
+ }
+ /*
+ * denormalize result or set to signed zero
+ */
+ if (dest_exponent >= (1 - DBL_P)) {
+ Dbl_rightshift_exponentmantissa(resultp1,resultp2,
+ 1-dest_exponent);
+ }
+ else {
+ Dbl_setzero_exponentmantissa(resultp1,resultp2);
+ }
+ }
+ else Dbl_set_exponent(resultp1,dest_exponent);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+}
diff --git a/arch/parisc/math-emu/dfsqrt.c b/arch/parisc/math-emu/dfsqrt.c
new file mode 100644
index 000000000..63d339c81
--- /dev/null
+++ b/arch/parisc/math-emu/dfsqrt.c
@@ -0,0 +1,182 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ */
+/*
+ * BEGIN_DESC
+ *
+ * File:
+ * @(#) pa/spmath/dfsqrt.c $Revision: 1.1 $
+ *
+ * Purpose:
+ * Double Floating-point Square Root
+ *
+ * External Interfaces:
+ * dbl_fsqrt(srcptr,nullptr,dstptr,status)
+ *
+ * Internal Interfaces:
+ *
+ * Theory:
+ * <<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "dbl_float.h"
+
+/*
+ * Double Floating-point Square Root
+ */
+
+/*ARGSUSED*/
+unsigned int
+dbl_fsqrt(
+ dbl_floating_point *srcptr,
+ unsigned int *nullptr,
+ dbl_floating_point *dstptr,
+ unsigned int *status)
+{
+ register unsigned int srcp1, srcp2, resultp1, resultp2;
+ register unsigned int newbitp1, newbitp2, sump1, sump2;
+ register int src_exponent;
+ register boolean guardbit = FALSE, even_exponent;
+
+ Dbl_copyfromptr(srcptr,srcp1,srcp2);
+ /*
+ * check source operand for NaN or infinity
+ */
+ if ((src_exponent = Dbl_exponent(srcp1)) == DBL_INFINITY_EXPONENT) {
+ /*
+ * is signaling NaN?
+ */
+ if (Dbl_isone_signaling(srcp1)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Dbl_set_quiet(srcp1);
+ }
+ /*
+ * Return quiet NaN or positive infinity.
+ * Fall through to negative test if negative infinity.
+ */
+ if (Dbl_iszero_sign(srcp1) ||
+ Dbl_isnotzero_mantissa(srcp1,srcp2)) {
+ Dbl_copytoptr(srcp1,srcp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ }
+
+ /*
+ * check for zero source operand
+ */
+ if (Dbl_iszero_exponentmantissa(srcp1,srcp2)) {
+ Dbl_copytoptr(srcp1,srcp2,dstptr);
+ return(NOEXCEPTION);
+ }
+
+ /*
+ * check for negative source operand
+ */
+ if (Dbl_isone_sign(srcp1)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Dbl_makequietnan(srcp1,srcp2);
+ Dbl_copytoptr(srcp1,srcp2,dstptr);
+ return(NOEXCEPTION);
+ }
+
+ /*
+ * Generate result
+ */
+ if (src_exponent > 0) {
+ even_exponent = Dbl_hidden(srcp1);
+ Dbl_clear_signexponent_set_hidden(srcp1);
+ }
+ else {
+ /* normalize operand */
+ Dbl_clear_signexponent(srcp1);
+ src_exponent++;
+ Dbl_normalize(srcp1,srcp2,src_exponent);
+ even_exponent = src_exponent & 1;
+ }
+ if (even_exponent) {
+ /* exponent is even */
+ /* Add comment here. Explain why odd exponent needs correction */
+ Dbl_leftshiftby1(srcp1,srcp2);
+ }
+ /*
+ * Add comment here. Explain following algorithm.
+ *
+ * Trust me, it works.
+ *
+ */
+ Dbl_setzero(resultp1,resultp2);
+ Dbl_allp1(newbitp1) = 1 << (DBL_P - 32);
+ Dbl_setzero_mantissap2(newbitp2);
+ while (Dbl_isnotzero(newbitp1,newbitp2) && Dbl_isnotzero(srcp1,srcp2)) {
+ Dbl_addition(resultp1,resultp2,newbitp1,newbitp2,sump1,sump2);
+ if(Dbl_isnotgreaterthan(sump1,sump2,srcp1,srcp2)) {
+ Dbl_leftshiftby1(newbitp1,newbitp2);
+ /* update result */
+ Dbl_addition(resultp1,resultp2,newbitp1,newbitp2,
+ resultp1,resultp2);
+ Dbl_subtract(srcp1,srcp2,sump1,sump2,srcp1,srcp2);
+ Dbl_rightshiftby2(newbitp1,newbitp2);
+ }
+ else {
+ Dbl_rightshiftby1(newbitp1,newbitp2);
+ }
+ Dbl_leftshiftby1(srcp1,srcp2);
+ }
+ /* correct exponent for pre-shift */
+ if (even_exponent) {
+ Dbl_rightshiftby1(resultp1,resultp2);
+ }
+
+ /* check for inexact */
+ if (Dbl_isnotzero(srcp1,srcp2)) {
+ if (!even_exponent && Dbl_islessthan(resultp1,resultp2,srcp1,srcp2)) {
+ Dbl_increment(resultp1,resultp2);
+ }
+ guardbit = Dbl_lowmantissap2(resultp2);
+ Dbl_rightshiftby1(resultp1,resultp2);
+
+ /* now round result */
+ switch (Rounding_mode()) {
+ case ROUNDPLUS:
+ Dbl_increment(resultp1,resultp2);
+ break;
+ case ROUNDNEAREST:
+ /* stickybit is always true, so guardbit
+ * is enough to determine rounding */
+ if (guardbit) {
+ Dbl_increment(resultp1,resultp2);
+ }
+ break;
+ }
+ /* increment result exponent by 1 if mantissa overflowed */
+ if (Dbl_isone_hiddenoverflow(resultp1)) src_exponent+=2;
+
+ if (Is_inexacttrap_enabled()) {
+ Dbl_set_exponent(resultp1,
+ ((src_exponent-DBL_BIAS)>>1)+DBL_BIAS);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(INEXACTEXCEPTION);
+ }
+ else Set_inexactflag();
+ }
+ else {
+ Dbl_rightshiftby1(resultp1,resultp2);
+ }
+ Dbl_set_exponent(resultp1,((src_exponent-DBL_BIAS)>>1)+DBL_BIAS);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+}
diff --git a/arch/parisc/math-emu/dfsub.c b/arch/parisc/math-emu/dfsub.c
new file mode 100644
index 000000000..4f0378228
--- /dev/null
+++ b/arch/parisc/math-emu/dfsub.c
@@ -0,0 +1,513 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ */
+/*
+ * BEGIN_DESC
+ *
+ * File:
+ * @(#) pa/spmath/dfsub.c $Revision: 1.1 $
+ *
+ * Purpose:
+ * Double_subtract: subtract two double precision values.
+ *
+ * External Interfaces:
+ * dbl_fsub(leftptr, rightptr, dstptr, status)
+ *
+ * Internal Interfaces:
+ *
+ * Theory:
+ * <<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "dbl_float.h"
+
+/*
+ * Double_subtract: subtract two double precision values.
+ */
+int
+dbl_fsub(
+ dbl_floating_point *leftptr,
+ dbl_floating_point *rightptr,
+ dbl_floating_point *dstptr,
+ unsigned int *status)
+ {
+ register unsigned int signless_upper_left, signless_upper_right, save;
+ register unsigned int leftp1, leftp2, rightp1, rightp2, extent;
+ register unsigned int resultp1 = 0, resultp2 = 0;
+
+ register int result_exponent, right_exponent, diff_exponent;
+ register int sign_save, jumpsize;
+ register boolean inexact = FALSE, underflowtrap;
+
+ /* Create local copies of the numbers */
+ Dbl_copyfromptr(leftptr,leftp1,leftp2);
+ Dbl_copyfromptr(rightptr,rightp1,rightp2);
+
+ /* A zero "save" helps discover equal operands (for later), *
+ * and is used in swapping operands (if needed). */
+ Dbl_xortointp1(leftp1,rightp1,/*to*/save);
+
+ /*
+ * check first operand for NaN's or infinity
+ */
+ if ((result_exponent = Dbl_exponent(leftp1)) == DBL_INFINITY_EXPONENT)
+ {
+ if (Dbl_iszero_mantissa(leftp1,leftp2))
+ {
+ if (Dbl_isnotnan(rightp1,rightp2))
+ {
+ if (Dbl_isinfinity(rightp1,rightp2) && save==0)
+ {
+ /*
+ * invalid since operands are same signed infinity's
+ */
+ if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+ Set_invalidflag();
+ Dbl_makequietnan(resultp1,resultp2);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /*
+ * return infinity
+ */
+ Dbl_copytoptr(leftp1,leftp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ }
+ else
+ {
+ /*
+ * is NaN; signaling or quiet?
+ */
+ if (Dbl_isone_signaling(leftp1))
+ {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Dbl_set_quiet(leftp1);
+ }
+ /*
+ * is second operand a signaling NaN?
+ */
+ else if (Dbl_is_signalingnan(rightp1))
+ {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Dbl_set_quiet(rightp1);
+ Dbl_copytoptr(rightp1,rightp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /*
+ * return quiet NaN
+ */
+ Dbl_copytoptr(leftp1,leftp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ } /* End left NaN or Infinity processing */
+ /*
+ * check second operand for NaN's or infinity
+ */
+ if (Dbl_isinfinity_exponent(rightp1))
+ {
+ if (Dbl_iszero_mantissa(rightp1,rightp2))
+ {
+ /* return infinity */
+ Dbl_invert_sign(rightp1);
+ Dbl_copytoptr(rightp1,rightp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /*
+ * is NaN; signaling or quiet?
+ */
+ if (Dbl_isone_signaling(rightp1))
+ {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Dbl_set_quiet(rightp1);
+ }
+ /*
+ * return quiet NaN
+ */
+ Dbl_copytoptr(rightp1,rightp2,dstptr);
+ return(NOEXCEPTION);
+ } /* End right NaN or Infinity processing */
+
+ /* Invariant: Must be dealing with finite numbers */
+
+ /* Compare operands by removing the sign */
+ Dbl_copytoint_exponentmantissap1(leftp1,signless_upper_left);
+ Dbl_copytoint_exponentmantissap1(rightp1,signless_upper_right);
+
+ /* sign difference selects add or sub operation. */
+ if(Dbl_ismagnitudeless(leftp2,rightp2,signless_upper_left,signless_upper_right))
+ {
+ /* Set the left operand to the larger one by XOR swap *
+ * First finish the first word using "save" */
+ Dbl_xorfromintp1(save,rightp1,/*to*/rightp1);
+ Dbl_xorfromintp1(save,leftp1,/*to*/leftp1);
+ Dbl_swap_lower(leftp2,rightp2);
+ result_exponent = Dbl_exponent(leftp1);
+ Dbl_invert_sign(leftp1);
+ }
+ /* Invariant: left is not smaller than right. */
+
+ if((right_exponent = Dbl_exponent(rightp1)) == 0)
+ {
+ /* Denormalized operands. First look for zeroes */
+ if(Dbl_iszero_mantissa(rightp1,rightp2))
+ {
+ /* right is zero */
+ if(Dbl_iszero_exponentmantissa(leftp1,leftp2))
+ {
+ /* Both operands are zeros */
+ Dbl_invert_sign(rightp1);
+ if(Is_rounding_mode(ROUNDMINUS))
+ {
+ Dbl_or_signs(leftp1,/*with*/rightp1);
+ }
+ else
+ {
+ Dbl_and_signs(leftp1,/*with*/rightp1);
+ }
+ }
+ else
+ {
+ /* Left is not a zero and must be the result. Trapped
+ * underflows are signaled if left is denormalized. Result
+ * is always exact. */
+ if( (result_exponent == 0) && Is_underflowtrap_enabled() )
+ {
+ /* need to normalize results mantissa */
+ sign_save = Dbl_signextendedsign(leftp1);
+ Dbl_leftshiftby1(leftp1,leftp2);
+ Dbl_normalize(leftp1,leftp2,result_exponent);
+ Dbl_set_sign(leftp1,/*using*/sign_save);
+ Dbl_setwrapped_exponent(leftp1,result_exponent,unfl);
+ Dbl_copytoptr(leftp1,leftp2,dstptr);
+ /* inexact = FALSE */
+ return(UNDERFLOWEXCEPTION);
+ }
+ }
+ Dbl_copytoptr(leftp1,leftp2,dstptr);
+ return(NOEXCEPTION);
+ }
+
+ /* Neither are zeroes */
+ Dbl_clear_sign(rightp1); /* Exponent is already cleared */
+ if(result_exponent == 0 )
+ {
+ /* Both operands are denormalized. The result must be exact
+ * and is simply calculated. A sum could become normalized and a
+ * difference could cancel to a true zero. */
+ if( (/*signed*/int) save >= 0 )
+ {
+ Dbl_subtract(leftp1,leftp2,/*minus*/rightp1,rightp2,
+ /*into*/resultp1,resultp2);
+ if(Dbl_iszero_mantissa(resultp1,resultp2))
+ {
+ if(Is_rounding_mode(ROUNDMINUS))
+ {
+ Dbl_setone_sign(resultp1);
+ }
+ else
+ {
+ Dbl_setzero_sign(resultp1);
+ }
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ }
+ else
+ {
+ Dbl_addition(leftp1,leftp2,rightp1,rightp2,
+ /*into*/resultp1,resultp2);
+ if(Dbl_isone_hidden(resultp1))
+ {
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ }
+ if(Is_underflowtrap_enabled())
+ {
+ /* need to normalize result */
+ sign_save = Dbl_signextendedsign(resultp1);
+ Dbl_leftshiftby1(resultp1,resultp2);
+ Dbl_normalize(resultp1,resultp2,result_exponent);
+ Dbl_set_sign(resultp1,/*using*/sign_save);
+ Dbl_setwrapped_exponent(resultp1,result_exponent,unfl);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ /* inexact = FALSE */
+ return(UNDERFLOWEXCEPTION);
+ }
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ right_exponent = 1; /* Set exponent to reflect different bias
+ * with denormalized numbers. */
+ }
+ else
+ {
+ Dbl_clear_signexponent_set_hidden(rightp1);
+ }
+ Dbl_clear_exponent_set_hidden(leftp1);
+ diff_exponent = result_exponent - right_exponent;
+
+ /*
+ * Special case alignment of operands that would force alignment
+ * beyond the extent of the extension. A further optimization
+ * could special case this but only reduces the path length for this
+ * infrequent case.
+ */
+ if(diff_exponent > DBL_THRESHOLD)
+ {
+ diff_exponent = DBL_THRESHOLD;
+ }
+
+ /* Align right operand by shifting to right */
+ Dbl_right_align(/*operand*/rightp1,rightp2,/*shifted by*/diff_exponent,
+ /*and lower to*/extent);
+
+ /* Treat sum and difference of the operands separately. */
+ if( (/*signed*/int) save >= 0 )
+ {
+ /*
+ * Difference of the two operands. Their can be no overflow. A
+ * borrow can occur out of the hidden bit and force a post
+ * normalization phase.
+ */
+ Dbl_subtract_withextension(leftp1,leftp2,/*minus*/rightp1,rightp2,
+ /*with*/extent,/*into*/resultp1,resultp2);
+ if(Dbl_iszero_hidden(resultp1))
+ {
+ /* Handle normalization */
+ /* A straight forward algorithm would now shift the result
+ * and extension left until the hidden bit becomes one. Not
+ * all of the extension bits need participate in the shift.
+ * Only the two most significant bits (round and guard) are
+ * needed. If only a single shift is needed then the guard
+ * bit becomes a significant low order bit and the extension
+ * must participate in the rounding. If more than a single
+ * shift is needed, then all bits to the right of the guard
+ * bit are zeros, and the guard bit may or may not be zero. */
+ sign_save = Dbl_signextendedsign(resultp1);
+ Dbl_leftshiftby1_withextent(resultp1,resultp2,extent,resultp1,resultp2);
+
+ /* Need to check for a zero result. The sign and exponent
+ * fields have already been zeroed. The more efficient test
+ * of the full object can be used.
+ */
+ if(Dbl_iszero(resultp1,resultp2))
+ /* Must have been "x-x" or "x+(-x)". */
+ {
+ if(Is_rounding_mode(ROUNDMINUS)) Dbl_setone_sign(resultp1);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ result_exponent--;
+ /* Look to see if normalization is finished. */
+ if(Dbl_isone_hidden(resultp1))
+ {
+ if(result_exponent==0)
+ {
+ /* Denormalized, exponent should be zero. Left operand *
+ * was normalized, so extent (guard, round) was zero */
+ goto underflow;
+ }
+ else
+ {
+ /* No further normalization is needed. */
+ Dbl_set_sign(resultp1,/*using*/sign_save);
+ Ext_leftshiftby1(extent);
+ goto round;
+ }
+ }
+
+ /* Check for denormalized, exponent should be zero. Left *
+ * operand was normalized, so extent (guard, round) was zero */
+ if(!(underflowtrap = Is_underflowtrap_enabled()) &&
+ result_exponent==0) goto underflow;
+
+ /* Shift extension to complete one bit of normalization and
+ * update exponent. */
+ Ext_leftshiftby1(extent);
+
+ /* Discover first one bit to determine shift amount. Use a
+ * modified binary search. We have already shifted the result
+ * one position right and still not found a one so the remainder
+ * of the extension must be zero and simplifies rounding. */
+ /* Scan bytes */
+ while(Dbl_iszero_hiddenhigh7mantissa(resultp1))
+ {
+ Dbl_leftshiftby8(resultp1,resultp2);
+ if((result_exponent -= 8) <= 0 && !underflowtrap)
+ goto underflow;
+ }
+ /* Now narrow it down to the nibble */
+ if(Dbl_iszero_hiddenhigh3mantissa(resultp1))
+ {
+ /* The lower nibble contains the normalizing one */
+ Dbl_leftshiftby4(resultp1,resultp2);
+ if((result_exponent -= 4) <= 0 && !underflowtrap)
+ goto underflow;
+ }
+ /* Select case were first bit is set (already normalized)
+ * otherwise select the proper shift. */
+ if((jumpsize = Dbl_hiddenhigh3mantissa(resultp1)) > 7)
+ {
+ /* Already normalized */
+ if(result_exponent <= 0) goto underflow;
+ Dbl_set_sign(resultp1,/*using*/sign_save);
+ Dbl_set_exponent(resultp1,/*using*/result_exponent);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ Dbl_sethigh4bits(resultp1,/*using*/sign_save);
+ switch(jumpsize)
+ {
+ case 1:
+ {
+ Dbl_leftshiftby3(resultp1,resultp2);
+ result_exponent -= 3;
+ break;
+ }
+ case 2:
+ case 3:
+ {
+ Dbl_leftshiftby2(resultp1,resultp2);
+ result_exponent -= 2;
+ break;
+ }
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ {
+ Dbl_leftshiftby1(resultp1,resultp2);
+ result_exponent -= 1;
+ break;
+ }
+ }
+ if(result_exponent > 0)
+ {
+ Dbl_set_exponent(resultp1,/*using*/result_exponent);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION); /* Sign bit is already set */
+ }
+ /* Fixup potential underflows */
+ underflow:
+ if(Is_underflowtrap_enabled())
+ {
+ Dbl_set_sign(resultp1,sign_save);
+ Dbl_setwrapped_exponent(resultp1,result_exponent,unfl);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ /* inexact = FALSE */
+ return(UNDERFLOWEXCEPTION);
+ }
+ /*
+ * Since we cannot get an inexact denormalized result,
+ * we can now return.
+ */
+ Dbl_fix_overshift(resultp1,resultp2,(1-result_exponent),extent);
+ Dbl_clear_signexponent(resultp1);
+ Dbl_set_sign(resultp1,sign_save);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ } /* end if(hidden...)... */
+ /* Fall through and round */
+ } /* end if(save >= 0)... */
+ else
+ {
+ /* Subtract magnitudes */
+ Dbl_addition(leftp1,leftp2,rightp1,rightp2,/*to*/resultp1,resultp2);
+ if(Dbl_isone_hiddenoverflow(resultp1))
+ {
+ /* Prenormalization required. */
+ Dbl_rightshiftby1_withextent(resultp2,extent,extent);
+ Dbl_arithrightshiftby1(resultp1,resultp2);
+ result_exponent++;
+ } /* end if hiddenoverflow... */
+ } /* end else ...subtract magnitudes... */
+
+ /* Round the result. If the extension is all zeros,then the result is
+ * exact. Otherwise round in the correct direction. No underflow is
+ * possible. If a postnormalization is necessary, then the mantissa is
+ * all zeros so no shift is needed. */
+ round:
+ if(Ext_isnotzero(extent))
+ {
+ inexact = TRUE;
+ switch(Rounding_mode())
+ {
+ case ROUNDNEAREST: /* The default. */
+ if(Ext_isone_sign(extent))
+ {
+ /* at least 1/2 ulp */
+ if(Ext_isnotzero_lower(extent) ||
+ Dbl_isone_lowmantissap2(resultp2))
+ {
+ /* either exactly half way and odd or more than 1/2ulp */
+ Dbl_increment(resultp1,resultp2);
+ }
+ }
+ break;
+
+ case ROUNDPLUS:
+ if(Dbl_iszero_sign(resultp1))
+ {
+ /* Round up positive results */
+ Dbl_increment(resultp1,resultp2);
+ }
+ break;
+
+ case ROUNDMINUS:
+ if(Dbl_isone_sign(resultp1))
+ {
+ /* Round down negative results */
+ Dbl_increment(resultp1,resultp2);
+ }
+
+ case ROUNDZERO:;
+ /* truncate is simple */
+ } /* end switch... */
+ if(Dbl_isone_hiddenoverflow(resultp1)) result_exponent++;
+ }
+ if(result_exponent == DBL_INFINITY_EXPONENT)
+ {
+ /* Overflow */
+ if(Is_overflowtrap_enabled())
+ {
+ Dbl_setwrapped_exponent(resultp1,result_exponent,ovfl);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ if (inexact)
+ if (Is_inexacttrap_enabled())
+ return(OVERFLOWEXCEPTION | INEXACTEXCEPTION);
+ else Set_inexactflag();
+ return(OVERFLOWEXCEPTION);
+ }
+ else
+ {
+ inexact = TRUE;
+ Set_overflowflag();
+ Dbl_setoverflow(resultp1,resultp2);
+ }
+ }
+ else Dbl_set_exponent(resultp1,result_exponent);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ if(inexact)
+ if(Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+ else Set_inexactflag();
+ return(NOEXCEPTION);
+ }
diff --git a/arch/parisc/math-emu/driver.c b/arch/parisc/math-emu/driver.c
new file mode 100644
index 000000000..6ce427b58
--- /dev/null
+++ b/arch/parisc/math-emu/driver.c
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ */
+/*
+ * linux/arch/math-emu/driver.c.c
+ *
+ * decodes and dispatches unimplemented FPU instructions
+ *
+ * Copyright (C) 1999, 2000 Philipp Rumpf <prumpf@tux.org>
+ * Copyright (C) 2001 Hewlett-Packard <bame@debian.org>
+ */
+
+#include <linux/sched/signal.h>
+
+#include "float.h"
+#include "math-emu.h"
+
+
+#define fptpos 31
+#define fpr1pos 10
+#define extru(r,pos,len) (((r) >> (31-(pos))) & (( 1 << (len)) - 1))
+
+#define FPUDEBUG 0
+
+/* Format of the floating-point exception registers. */
+struct exc_reg {
+ unsigned int exception : 6;
+ unsigned int ei : 26;
+};
+
+/* Macros for grabbing bits of the instruction format from the 'ei'
+ field above. */
+/* Major opcode 0c and 0e */
+#define FP0CE_UID(i) (((i) >> 6) & 3)
+#define FP0CE_CLASS(i) (((i) >> 9) & 3)
+#define FP0CE_SUBOP(i) (((i) >> 13) & 7)
+#define FP0CE_SUBOP1(i) (((i) >> 15) & 7) /* Class 1 subopcode */
+#define FP0C_FORMAT(i) (((i) >> 11) & 3)
+#define FP0E_FORMAT(i) (((i) >> 11) & 1)
+
+/* Major opcode 0c, uid 2 (performance monitoring) */
+#define FPPM_SUBOP(i) (((i) >> 9) & 0x1f)
+
+/* Major opcode 2e (fused operations). */
+#define FP2E_SUBOP(i) (((i) >> 5) & 1)
+#define FP2E_FORMAT(i) (((i) >> 11) & 1)
+
+/* Major opcode 26 (FMPYSUB) */
+/* Major opcode 06 (FMPYADD) */
+#define FPx6_FORMAT(i) ((i) & 0x1f)
+
+/* Flags and enable bits of the status word. */
+#define FPSW_FLAGS(w) ((w) >> 27)
+#define FPSW_ENABLE(w) ((w) & 0x1f)
+#define FPSW_V (1<<4)
+#define FPSW_Z (1<<3)
+#define FPSW_O (1<<2)
+#define FPSW_U (1<<1)
+#define FPSW_I (1<<0)
+
+/* Handle a floating point exception. Return zero if the faulting
+ instruction can be completed successfully. */
+int
+handle_fpe(struct pt_regs *regs)
+{
+ extern void printbinary(unsigned long x, int nbits);
+ unsigned int orig_sw, sw;
+ int signalcode;
+ /* need an intermediate copy of float regs because FPU emulation
+ * code expects an artificial last entry which contains zero
+ *
+ * also, the passed in fr registers contain one word that defines
+ * the fpu type. the fpu type information is constructed
+ * inside the emulation code
+ */
+ __u64 frcopy[36];
+
+ memcpy(frcopy, regs->fr, sizeof regs->fr);
+ frcopy[32] = 0;
+
+ memcpy(&orig_sw, frcopy, sizeof(orig_sw));
+
+ if (FPUDEBUG) {
+ printk(KERN_DEBUG "FP VZOUICxxxxCQCQCQCQCQCRMxxTDVZOUI ->\n ");
+ printbinary(orig_sw, 32);
+ printk(KERN_DEBUG "\n");
+ }
+
+ signalcode = decode_fpu(frcopy, 0x666);
+
+ /* Status word = FR0L. */
+ memcpy(&sw, frcopy, sizeof(sw));
+ if (FPUDEBUG) {
+ printk(KERN_DEBUG "VZOUICxxxxCQCQCQCQCQCRMxxTDVZOUI decode_fpu returns %d|0x%x\n",
+ signalcode >> 24, signalcode & 0xffffff);
+ printbinary(sw, 32);
+ printk(KERN_DEBUG "\n");
+ }
+
+ memcpy(regs->fr, frcopy, sizeof regs->fr);
+ if (signalcode != 0) {
+ force_sig_fault(signalcode >> 24, signalcode & 0xffffff,
+ (void __user *) regs->iaoq[0]);
+ return -1;
+ }
+
+ return signalcode ? -1 : 0;
+}
diff --git a/arch/parisc/math-emu/fcnvff.c b/arch/parisc/math-emu/fcnvff.c
new file mode 100644
index 000000000..0530e6127
--- /dev/null
+++ b/arch/parisc/math-emu/fcnvff.c
@@ -0,0 +1,296 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ */
+/*
+ * BEGIN_DESC
+ *
+ * File:
+ * @(#) pa/spmath/fcnvff.c $Revision: 1.1 $
+ *
+ * Purpose:
+ * Single Floating-point to Double Floating-point
+ * Double Floating-point to Single Floating-point
+ *
+ * External Interfaces:
+ * dbl_to_sgl_fcnvff(srcptr,nullptr,dstptr,status)
+ * sgl_to_dbl_fcnvff(srcptr,nullptr,dstptr,status)
+ *
+ * Internal Interfaces:
+ *
+ * Theory:
+ * <<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+#include "dbl_float.h"
+#include "cnv_float.h"
+
+/*
+ * Single Floating-point to Double Floating-point
+ */
+/*ARGSUSED*/
+int
+sgl_to_dbl_fcnvff(
+ sgl_floating_point *srcptr,
+ unsigned int *nullptr,
+ dbl_floating_point *dstptr,
+ unsigned int *status)
+{
+ register unsigned int src, resultp1, resultp2;
+ register int src_exponent;
+
+ src = *srcptr;
+ src_exponent = Sgl_exponent(src);
+ Dbl_allp1(resultp1) = Sgl_all(src); /* set sign of result */
+ /*
+ * Test for NaN or infinity
+ */
+ if (src_exponent == SGL_INFINITY_EXPONENT) {
+ /*
+ * determine if NaN or infinity
+ */
+ if (Sgl_iszero_mantissa(src)) {
+ /*
+ * is infinity; want to return double infinity
+ */
+ Dbl_setinfinity_exponentmantissa(resultp1,resultp2);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ else {
+ /*
+ * is NaN; signaling or quiet?
+ */
+ if (Sgl_isone_signaling(src)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled())
+ return(INVALIDEXCEPTION);
+ /* make NaN quiet */
+ else {
+ Set_invalidflag();
+ Sgl_set_quiet(src);
+ }
+ }
+ /*
+ * NaN is quiet, return as double NaN
+ */
+ Dbl_setinfinity_exponent(resultp1);
+ Sgl_to_dbl_mantissa(src,resultp1,resultp2);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ }
+ /*
+ * Test for zero or denormalized
+ */
+ if (src_exponent == 0) {
+ /*
+ * determine if zero or denormalized
+ */
+ if (Sgl_isnotzero_mantissa(src)) {
+ /*
+ * is denormalized; want to normalize
+ */
+ Sgl_clear_signexponent(src);
+ Sgl_leftshiftby1(src);
+ Sgl_normalize(src,src_exponent);
+ Sgl_to_dbl_exponent(src_exponent,resultp1);
+ Sgl_to_dbl_mantissa(src,resultp1,resultp2);
+ }
+ else {
+ Dbl_setzero_exponentmantissa(resultp1,resultp2);
+ }
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /*
+ * No special cases, just complete the conversion
+ */
+ Sgl_to_dbl_exponent(src_exponent, resultp1);
+ Sgl_to_dbl_mantissa(Sgl_mantissa(src), resultp1,resultp2);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+}
+
+/*
+ * Double Floating-point to Single Floating-point
+ */
+/*ARGSUSED*/
+int
+dbl_to_sgl_fcnvff(
+ dbl_floating_point *srcptr,
+ unsigned int *nullptr,
+ sgl_floating_point *dstptr,
+ unsigned int *status)
+{
+ register unsigned int srcp1, srcp2, result;
+ register int src_exponent, dest_exponent, dest_mantissa;
+ register boolean inexact = FALSE, guardbit = FALSE, stickybit = FALSE;
+ register boolean lsb_odd = FALSE;
+ boolean is_tiny = FALSE;
+
+ Dbl_copyfromptr(srcptr,srcp1,srcp2);
+ src_exponent = Dbl_exponent(srcp1);
+ Sgl_all(result) = Dbl_allp1(srcp1); /* set sign of result */
+ /*
+ * Test for NaN or infinity
+ */
+ if (src_exponent == DBL_INFINITY_EXPONENT) {
+ /*
+ * determine if NaN or infinity
+ */
+ if (Dbl_iszero_mantissa(srcp1,srcp2)) {
+ /*
+ * is infinity; want to return single infinity
+ */
+ Sgl_setinfinity_exponentmantissa(result);
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+ /*
+ * is NaN; signaling or quiet?
+ */
+ if (Dbl_isone_signaling(srcp1)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+ else {
+ Set_invalidflag();
+ /* make NaN quiet */
+ Dbl_set_quiet(srcp1);
+ }
+ }
+ /*
+ * NaN is quiet, return as single NaN
+ */
+ Sgl_setinfinity_exponent(result);
+ Sgl_set_mantissa(result,Dallp1(srcp1)<<3 | Dallp2(srcp2)>>29);
+ if (Sgl_iszero_mantissa(result)) Sgl_set_quiet(result);
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+ /*
+ * Generate result
+ */
+ Dbl_to_sgl_exponent(src_exponent,dest_exponent);
+ if (dest_exponent > 0) {
+ Dbl_to_sgl_mantissa(srcp1,srcp2,dest_mantissa,inexact,guardbit,
+ stickybit,lsb_odd);
+ }
+ else {
+ if (Dbl_iszero_exponentmantissa(srcp1,srcp2)){
+ Sgl_setzero_exponentmantissa(result);
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+ if (Is_underflowtrap_enabled()) {
+ Dbl_to_sgl_mantissa(srcp1,srcp2,dest_mantissa,inexact,
+ guardbit,stickybit,lsb_odd);
+ }
+ else {
+ /* compute result, determine inexact info,
+ * and set Underflowflag if appropriate
+ */
+ Dbl_to_sgl_denormalized(srcp1,srcp2,dest_exponent,
+ dest_mantissa,inexact,guardbit,stickybit,lsb_odd,
+ is_tiny);
+ }
+ }
+ /*
+ * Now round result if not exact
+ */
+ if (inexact) {
+ switch (Rounding_mode()) {
+ case ROUNDPLUS:
+ if (Sgl_iszero_sign(result)) dest_mantissa++;
+ break;
+ case ROUNDMINUS:
+ if (Sgl_isone_sign(result)) dest_mantissa++;
+ break;
+ case ROUNDNEAREST:
+ if (guardbit) {
+ if (stickybit || lsb_odd) dest_mantissa++;
+ }
+ }
+ }
+ Sgl_set_exponentmantissa(result,dest_mantissa);
+
+ /*
+ * check for mantissa overflow after rounding
+ */
+ if ((dest_exponent>0 || Is_underflowtrap_enabled()) &&
+ Sgl_isone_hidden(result)) dest_exponent++;
+
+ /*
+ * Test for overflow
+ */
+ if (dest_exponent >= SGL_INFINITY_EXPONENT) {
+ /* trap if OVERFLOWTRAP enabled */
+ if (Is_overflowtrap_enabled()) {
+ /*
+ * Check for gross overflow
+ */
+ if (dest_exponent >= SGL_INFINITY_EXPONENT+SGL_WRAP)
+ return(UNIMPLEMENTEDEXCEPTION);
+
+ /*
+ * Adjust bias of result
+ */
+ Sgl_setwrapped_exponent(result,dest_exponent,ovfl);
+ *dstptr = result;
+ if (inexact)
+ if (Is_inexacttrap_enabled())
+ return(OVERFLOWEXCEPTION|INEXACTEXCEPTION);
+ else Set_inexactflag();
+ return(OVERFLOWEXCEPTION);
+ }
+ Set_overflowflag();
+ inexact = TRUE;
+ /* set result to infinity or largest number */
+ Sgl_setoverflow(result);
+ }
+ /*
+ * Test for underflow
+ */
+ else if (dest_exponent <= 0) {
+ /* trap if UNDERFLOWTRAP enabled */
+ if (Is_underflowtrap_enabled()) {
+ /*
+ * Check for gross underflow
+ */
+ if (dest_exponent <= -(SGL_WRAP))
+ return(UNIMPLEMENTEDEXCEPTION);
+ /*
+ * Adjust bias of result
+ */
+ Sgl_setwrapped_exponent(result,dest_exponent,unfl);
+ *dstptr = result;
+ if (inexact)
+ if (Is_inexacttrap_enabled())
+ return(UNDERFLOWEXCEPTION|INEXACTEXCEPTION);
+ else Set_inexactflag();
+ return(UNDERFLOWEXCEPTION);
+ }
+ /*
+ * result is denormalized or signed zero
+ */
+ if (inexact && is_tiny) Set_underflowflag();
+
+ }
+ else Sgl_set_exponent(result,dest_exponent);
+ *dstptr = result;
+ /*
+ * Trap if inexact trap is enabled
+ */
+ if (inexact)
+ if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+ else Set_inexactflag();
+ return(NOEXCEPTION);
+}
diff --git a/arch/parisc/math-emu/fcnvfu.c b/arch/parisc/math-emu/fcnvfu.c
new file mode 100644
index 000000000..c971618a6
--- /dev/null
+++ b/arch/parisc/math-emu/fcnvfu.c
@@ -0,0 +1,523 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ */
+/*
+ * BEGIN_DESC
+ *
+ * File:
+ * @(#) pa/spmath/fcnvfu.c $Revision: 1.1 $
+ *
+ * Purpose:
+ * Floating-point to Unsigned Fixed-point Converts
+ *
+ * External Interfaces:
+ * dbl_to_dbl_fcnvfu(srcptr,nullptr,dstptr,status)
+ * dbl_to_sgl_fcnvfu(srcptr,nullptr,dstptr,status)
+ * sgl_to_dbl_fcnvfu(srcptr,nullptr,dstptr,status)
+ * sgl_to_sgl_fcnvfu(srcptr,nullptr,dstptr,status)
+ *
+ * Internal Interfaces:
+ *
+ * Theory:
+ * <<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+#include "dbl_float.h"
+#include "cnv_float.h"
+
+/************************************************************************
+ * Floating-point to Unsigned Fixed-point Converts *
+ ************************************************************************/
+
+/*
+ * Single Floating-point to Single Unsigned Fixed
+ */
+/*ARGSUSED*/
+int
+sgl_to_sgl_fcnvfu(
+ sgl_floating_point *srcptr,
+ unsigned int *nullptr,
+ unsigned int *dstptr,
+ unsigned int *status)
+{
+ register unsigned int src, result;
+ register int src_exponent;
+ register boolean inexact = FALSE;
+
+ src = *srcptr;
+ src_exponent = Sgl_exponent(src) - SGL_BIAS;
+
+ /*
+ * Test for overflow
+ */
+ if (src_exponent > SGL_FX_MAX_EXP + 1) {
+ if (Sgl_isone_sign(src)) {
+ result = 0;
+ } else {
+ result = 0xffffffff;
+ }
+ if (Is_invalidtrap_enabled()) {
+ return(INVALIDEXCEPTION);
+ }
+ Set_invalidflag();
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+ /*
+ * Generate result
+ */
+ if (src_exponent >= 0) {
+ /*
+ * Check sign.
+ * If negative, trap unimplemented.
+ */
+ if (Sgl_isone_sign(src)) {
+ result = 0;
+ if (Is_invalidtrap_enabled()) {
+ return(INVALIDEXCEPTION);
+ }
+ Set_invalidflag();
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+ Sgl_clear_signexponent_set_hidden(src);
+ Suint_from_sgl_mantissa(src,src_exponent,result);
+
+ /* check for inexact */
+ if (Sgl_isinexact_to_unsigned(src,src_exponent)) {
+ inexact = TRUE;
+ /* round result */
+ switch (Rounding_mode()) {
+ case ROUNDPLUS:
+ result++;
+ break;
+ case ROUNDMINUS: /* never negative */
+ break;
+ case ROUNDNEAREST:
+ if (Sgl_isone_roundbit(src,src_exponent) &&
+ (Sgl_isone_stickybit(src,src_exponent) ||
+ (result & 1))) {
+ result++;
+ }
+ break;
+ }
+ }
+ } else {
+ result = 0;
+
+ /* check for inexact */
+ if (Sgl_isnotzero_exponentmantissa(src)) {
+ inexact = TRUE;
+ /* round result */
+ switch (Rounding_mode()) {
+ case ROUNDPLUS:
+ if (Sgl_iszero_sign(src)) {
+ result++;
+ }
+ break;
+ case ROUNDMINUS:
+ if (Sgl_isone_sign(src)) {
+ result = 0;
+ if (Is_invalidtrap_enabled()) {
+ return(INVALIDEXCEPTION);
+ }
+ Set_invalidflag();
+ inexact = FALSE;
+ }
+ break;
+ case ROUNDNEAREST:
+ if (src_exponent == -1 &&
+ Sgl_isnotzero_mantissa(src)) {
+ if (Sgl_isone_sign(src)) {
+ result = 0;
+ if (Is_invalidtrap_enabled()) {
+ return(INVALIDEXCEPTION);
+ }
+ Set_invalidflag();
+ inexact = FALSE;
+ }
+ else result++;
+ }
+ break;
+ }
+ }
+ }
+ *dstptr = result;
+ if (inexact) {
+ if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+ else Set_inexactflag();
+ }
+ return(NOEXCEPTION);
+}
+
+/*
+ * Single Floating-point to Double Unsigned Fixed
+ */
+/*ARGSUSED*/
+int
+sgl_to_dbl_fcnvfu(
+ sgl_floating_point *srcptr,
+ unsigned int *nullptr,
+ dbl_unsigned *dstptr,
+ unsigned int *status)
+{
+ register int src_exponent;
+ register unsigned int src, resultp1, resultp2;
+ register boolean inexact = FALSE;
+
+ src = *srcptr;
+ src_exponent = Sgl_exponent(src) - SGL_BIAS;
+
+ /*
+ * Test for overflow
+ */
+ if (src_exponent > DBL_FX_MAX_EXP + 1) {
+ if (Sgl_isone_sign(src)) {
+ resultp1 = resultp2 = 0;
+ } else {
+ resultp1 = resultp2 = 0xffffffff;
+ }
+ if (Is_invalidtrap_enabled()) {
+ return(INVALIDEXCEPTION);
+ }
+ Set_invalidflag();
+ Duint_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /*
+ * Generate result
+ */
+ if (src_exponent >= 0) {
+ /*
+ * Check sign.
+ * If negative, trap unimplemented.
+ */
+ if (Sgl_isone_sign(src)) {
+ resultp1 = resultp2 = 0;
+ if (Is_invalidtrap_enabled()) {
+ return(INVALIDEXCEPTION);
+ }
+ Set_invalidflag();
+ Duint_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ Sgl_clear_signexponent_set_hidden(src);
+ Duint_from_sgl_mantissa(src,src_exponent,resultp1,resultp2);
+
+ /* check for inexact */
+ if (Sgl_isinexact_to_unsigned(src,src_exponent)) {
+ inexact = TRUE;
+ /* round result */
+ switch (Rounding_mode()) {
+ case ROUNDPLUS:
+ Duint_increment(resultp1,resultp2);
+ break;
+ case ROUNDMINUS: /* never negative */
+ break;
+ case ROUNDNEAREST:
+ if (Sgl_isone_roundbit(src,src_exponent) &&
+ (Sgl_isone_stickybit(src,src_exponent) ||
+ Duint_isone_lowp2(resultp2))) {
+ Duint_increment(resultp1,resultp2);
+ }
+ break;
+ }
+ }
+ } else {
+ Duint_setzero(resultp1,resultp2);
+
+ /* check for inexact */
+ if (Sgl_isnotzero_exponentmantissa(src)) {
+ inexact = TRUE;
+ /* round result */
+ switch (Rounding_mode()) {
+ case ROUNDPLUS:
+ if (Sgl_iszero_sign(src)) {
+ Duint_increment(resultp1,resultp2);
+ }
+ break;
+ case ROUNDMINUS:
+ if (Sgl_isone_sign(src)) {
+ resultp1 = resultp2 = 0;
+ if (Is_invalidtrap_enabled()) {
+ return(INVALIDEXCEPTION);
+ }
+ Set_invalidflag();
+ inexact = FALSE;
+ }
+ break;
+ case ROUNDNEAREST:
+ if (src_exponent == -1 &&
+ Sgl_isnotzero_mantissa(src)) {
+ if (Sgl_isone_sign(src)) {
+ resultp1 = 0;
+ resultp2 = 0;
+ if (Is_invalidtrap_enabled()) {
+ return(INVALIDEXCEPTION);
+ }
+ Set_invalidflag();
+ inexact = FALSE;
+ }
+ else Duint_increment(resultp1,resultp2);
+ }
+ }
+ }
+ }
+ Duint_copytoptr(resultp1,resultp2,dstptr);
+ if (inexact) {
+ if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+ else Set_inexactflag();
+ }
+ return(NOEXCEPTION);
+}
+
+/*
+ * Double Floating-point to Single Unsigned Fixed
+ */
+/*ARGSUSED*/
+int
+dbl_to_sgl_fcnvfu (dbl_floating_point * srcptr, unsigned int *nullptr,
+ unsigned int *dstptr, unsigned int *status)
+{
+ register unsigned int srcp1, srcp2, result;
+ register int src_exponent;
+ register boolean inexact = FALSE;
+
+ Dbl_copyfromptr(srcptr,srcp1,srcp2);
+ src_exponent = Dbl_exponent(srcp1) - DBL_BIAS;
+
+ /*
+ * Test for overflow
+ */
+ if (src_exponent > SGL_FX_MAX_EXP + 1) {
+ if (Dbl_isone_sign(srcp1)) {
+ result = 0;
+ } else {
+ result = 0xffffffff;
+ }
+ if (Is_invalidtrap_enabled()) {
+ return(INVALIDEXCEPTION);
+ }
+ Set_invalidflag();
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+ /*
+ * Generate result
+ */
+ if (src_exponent >= 0) {
+ /*
+ * Check sign.
+ * If negative, trap unimplemented.
+ */
+ if (Dbl_isone_sign(srcp1)) {
+ result = 0;
+ if (Is_invalidtrap_enabled()) {
+ return(INVALIDEXCEPTION);
+ }
+ Set_invalidflag();
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+ Dbl_clear_signexponent_set_hidden(srcp1);
+ Suint_from_dbl_mantissa(srcp1,srcp2,src_exponent,result);
+
+ /* check for inexact */
+ if (Dbl_isinexact_to_unsigned(srcp1,srcp2,src_exponent)) {
+ inexact = TRUE;
+ /* round result */
+ switch (Rounding_mode()) {
+ case ROUNDPLUS:
+ result++;
+ break;
+ case ROUNDMINUS: /* never negative */
+ break;
+ case ROUNDNEAREST:
+ if(Dbl_isone_roundbit(srcp1,srcp2,src_exponent) &&
+ (Dbl_isone_stickybit(srcp1,srcp2,src_exponent)||
+ result&1))
+ result++;
+ break;
+ }
+ /* check for overflow */
+ if (result == 0) {
+ result = 0xffffffff;
+ if (Is_invalidtrap_enabled()) {
+ return(INVALIDEXCEPTION);
+ }
+ Set_invalidflag();
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+ }
+ } else {
+ result = 0;
+
+ /* check for inexact */
+ if (Dbl_isnotzero_exponentmantissa(srcp1,srcp2)) {
+ inexact = TRUE;
+ /* round result */
+ switch (Rounding_mode()) {
+ case ROUNDPLUS:
+ if (Dbl_iszero_sign(srcp1)) result++;
+ break;
+ case ROUNDMINUS:
+ if (Dbl_isone_sign(srcp1)) {
+ result = 0;
+ if (Is_invalidtrap_enabled()) {
+ return(INVALIDEXCEPTION);
+ }
+ Set_invalidflag();
+ inexact = FALSE;
+ }
+ break;
+ case ROUNDNEAREST:
+ if (src_exponent == -1 &&
+ Dbl_isnotzero_mantissa(srcp1,srcp2))
+ if (Dbl_isone_sign(srcp1)) {
+ result = 0;
+ if (Is_invalidtrap_enabled()) {
+ return(INVALIDEXCEPTION);
+ }
+ Set_invalidflag();
+ inexact = FALSE;
+ }
+ else result++;
+ }
+ }
+ }
+ *dstptr = result;
+ if (inexact) {
+ if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+ else Set_inexactflag();
+ }
+ return(NOEXCEPTION);
+}
+
+/*
+ * Double Floating-point to Double Unsigned Fixed
+ */
+/*ARGSUSED*/
+int
+dbl_to_dbl_fcnvfu (dbl_floating_point * srcptr, unsigned int *nullptr,
+ dbl_unsigned * dstptr, unsigned int *status)
+{
+ register int src_exponent;
+ register unsigned int srcp1, srcp2, resultp1, resultp2;
+ register boolean inexact = FALSE;
+
+ Dbl_copyfromptr(srcptr,srcp1,srcp2);
+ src_exponent = Dbl_exponent(srcp1) - DBL_BIAS;
+
+ /*
+ * Test for overflow
+ */
+ if (src_exponent > DBL_FX_MAX_EXP + 1) {
+ if (Dbl_isone_sign(srcp1)) {
+ resultp1 = resultp2 = 0;
+ } else {
+ resultp1 = resultp2 = 0xffffffff;
+ }
+ if (Is_invalidtrap_enabled()) {
+ return(INVALIDEXCEPTION);
+ }
+ Set_invalidflag();
+ Duint_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+
+ /*
+ * Generate result
+ */
+ if (src_exponent >= 0) {
+ /*
+ * Check sign.
+ * If negative, trap unimplemented.
+ */
+ if (Dbl_isone_sign(srcp1)) {
+ resultp1 = resultp2 = 0;
+ if (Is_invalidtrap_enabled()) {
+ return(INVALIDEXCEPTION);
+ }
+ Set_invalidflag();
+ Duint_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ Dbl_clear_signexponent_set_hidden(srcp1);
+ Duint_from_dbl_mantissa(srcp1,srcp2,src_exponent,resultp1,
+ resultp2);
+
+ /* check for inexact */
+ if (Dbl_isinexact_to_unsigned(srcp1,srcp2,src_exponent)) {
+ inexact = TRUE;
+ /* round result */
+ switch (Rounding_mode()) {
+ case ROUNDPLUS:
+ Duint_increment(resultp1,resultp2);
+ break;
+ case ROUNDMINUS: /* never negative */
+ break;
+ case ROUNDNEAREST:
+ if(Dbl_isone_roundbit(srcp1,srcp2,src_exponent))
+ if(Dbl_isone_stickybit(srcp1,srcp2,src_exponent) ||
+ Duint_isone_lowp2(resultp2))
+ Duint_increment(resultp1,resultp2);
+ }
+ }
+ } else {
+ Duint_setzero(resultp1,resultp2);
+
+ /* check for inexact */
+ if (Dbl_isnotzero_exponentmantissa(srcp1,srcp2)) {
+ inexact = TRUE;
+ /* round result */
+ switch (Rounding_mode()) {
+ case ROUNDPLUS:
+ if (Dbl_iszero_sign(srcp1)) {
+ Duint_increment(resultp1,resultp2);
+ }
+ break;
+ case ROUNDMINUS:
+ if (Dbl_isone_sign(srcp1)) {
+ resultp1 = resultp2 = 0;
+ if (Is_invalidtrap_enabled()) {
+ return(INVALIDEXCEPTION);
+ }
+ Set_invalidflag();
+ inexact = FALSE;
+ }
+ break;
+ case ROUNDNEAREST:
+ if (src_exponent == -1 &&
+ Dbl_isnotzero_mantissa(srcp1,srcp2))
+ if (Dbl_iszero_sign(srcp1)) {
+ Duint_increment(resultp1,resultp2);
+ } else {
+ resultp1 = 0;
+ resultp2 = 0;
+ if (Is_invalidtrap_enabled()) {
+ return(INVALIDEXCEPTION);
+ }
+ Set_invalidflag();
+ inexact = FALSE;
+ }
+ }
+ }
+ }
+ Duint_copytoptr(resultp1,resultp2,dstptr);
+ if (inexact) {
+ if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+ else Set_inexactflag();
+ }
+ return(NOEXCEPTION);
+}
+
diff --git a/arch/parisc/math-emu/fcnvfut.c b/arch/parisc/math-emu/fcnvfut.c
new file mode 100644
index 000000000..5b657f852
--- /dev/null
+++ b/arch/parisc/math-emu/fcnvfut.c
@@ -0,0 +1,319 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ */
+/*
+ * BEGIN_DESC
+ *
+ * File:
+ * @(#) pa/spmath/fcnvfut.c $Revision: 1.1 $
+ *
+ * Purpose:
+ * Floating-point to Unsigned Fixed-point Converts with Truncation
+ *
+ * External Interfaces:
+ * dbl_to_dbl_fcnvfut(srcptr,nullptr,dstptr,status)
+ * dbl_to_sgl_fcnvfut(srcptr,nullptr,dstptr,status)
+ * sgl_to_dbl_fcnvfut(srcptr,nullptr,dstptr,status)
+ * sgl_to_sgl_fcnvfut(srcptr,nullptr,dstptr,status)
+ *
+ * Internal Interfaces:
+ *
+ * Theory:
+ * <<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+#include "dbl_float.h"
+#include "cnv_float.h"
+
+/************************************************************************
+ * Floating-point to Unsigned Fixed-point Converts with Truncation *
+ ************************************************************************/
+
+/*
+ * Convert single floating-point to single fixed-point format
+ * with truncated result
+ */
+/*ARGSUSED*/
+int
+sgl_to_sgl_fcnvfut (sgl_floating_point * srcptr, unsigned int *nullptr,
+ unsigned int *dstptr, unsigned int *status)
+{
+ register unsigned int src, result;
+ register int src_exponent;
+
+ src = *srcptr;
+ src_exponent = Sgl_exponent(src) - SGL_BIAS;
+
+ /*
+ * Test for overflow
+ */
+ if (src_exponent > SGL_FX_MAX_EXP + 1) {
+ if (Sgl_isone_sign(src)) {
+ result = 0;
+ } else {
+ result = 0xffffffff;
+ }
+ if (Is_invalidtrap_enabled()) {
+ return(INVALIDEXCEPTION);
+ }
+ Set_invalidflag();
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+ /*
+ * Generate result
+ */
+ if (src_exponent >= 0) {
+ /*
+ * Check sign.
+ * If negative, trap unimplemented.
+ */
+ if (Sgl_isone_sign(src)) {
+ result = 0;
+ if (Is_invalidtrap_enabled()) {
+ return(INVALIDEXCEPTION);
+ }
+ Set_invalidflag();
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+ Sgl_clear_signexponent_set_hidden(src);
+ Suint_from_sgl_mantissa(src,src_exponent,result);
+ *dstptr = result;
+
+ /* check for inexact */
+ if (Sgl_isinexact_to_unsigned(src,src_exponent)) {
+ if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+ else Set_inexactflag();
+ }
+ }
+ else {
+ *dstptr = 0;
+
+ /* check for inexact */
+ if (Sgl_isnotzero_exponentmantissa(src)) {
+ if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+ else Set_inexactflag();
+ }
+ }
+ return(NOEXCEPTION);
+}
+
+/*
+ * Single Floating-point to Double Unsigned Fixed
+ */
+/*ARGSUSED*/
+int
+sgl_to_dbl_fcnvfut (sgl_floating_point * srcptr, unsigned int *nullptr,
+ dbl_unsigned * dstptr, unsigned int *status)
+{
+ register int src_exponent;
+ register unsigned int src, resultp1, resultp2;
+
+ src = *srcptr;
+ src_exponent = Sgl_exponent(src) - SGL_BIAS;
+
+ /*
+ * Test for overflow
+ */
+ if (src_exponent > DBL_FX_MAX_EXP + 1) {
+ if (Sgl_isone_sign(src)) {
+ resultp1 = resultp2 = 0;
+ } else {
+ resultp1 = resultp2 = 0xffffffff;
+ }
+ if (Is_invalidtrap_enabled()) {
+ return(INVALIDEXCEPTION);
+ }
+ Set_invalidflag();
+ Duint_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /*
+ * Generate result
+ */
+ if (src_exponent >= 0) {
+ /*
+ * Check sign.
+ * If negative, trap unimplemented.
+ */
+ if (Sgl_isone_sign(src)) {
+ resultp1 = resultp2 = 0;
+ if (Is_invalidtrap_enabled()) {
+ return(INVALIDEXCEPTION);
+ }
+ Set_invalidflag();
+ Duint_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ Sgl_clear_signexponent_set_hidden(src);
+ Duint_from_sgl_mantissa(src,src_exponent,resultp1,resultp2);
+ Duint_copytoptr(resultp1,resultp2,dstptr);
+
+ /* check for inexact */
+ if (Sgl_isinexact_to_unsigned(src,src_exponent)) {
+ if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+ else Set_inexactflag();
+ }
+ }
+ else {
+ Duint_setzero(resultp1,resultp2);
+ Duint_copytoptr(resultp1,resultp2,dstptr);
+
+ /* check for inexact */
+ if (Sgl_isnotzero_exponentmantissa(src)) {
+ if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+ else Set_inexactflag();
+ }
+ }
+ return(NOEXCEPTION);
+}
+
+/*
+ * Double Floating-point to Single Unsigned Fixed
+ */
+/*ARGSUSED*/
+int
+dbl_to_sgl_fcnvfut (dbl_floating_point * srcptr, unsigned int *nullptr,
+ unsigned int *dstptr, unsigned int *status)
+{
+ register unsigned int srcp1, srcp2, result;
+ register int src_exponent;
+
+ Dbl_copyfromptr(srcptr,srcp1,srcp2);
+ src_exponent = Dbl_exponent(srcp1) - DBL_BIAS;
+
+ /*
+ * Test for overflow
+ */
+ if (src_exponent > SGL_FX_MAX_EXP + 1) {
+ if (Dbl_isone_sign(srcp1)) {
+ result = 0;
+ } else {
+ result = 0xffffffff;
+ }
+ if (Is_invalidtrap_enabled()) {
+ return(INVALIDEXCEPTION);
+ }
+ Set_invalidflag();
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+ /*
+ * Generate result
+ */
+ if (src_exponent >= 0) {
+ /*
+ * Check sign.
+ * If negative, trap unimplemented.
+ */
+ if (Dbl_isone_sign(srcp1)) {
+ result = 0;
+ if (Is_invalidtrap_enabled()) {
+ return(INVALIDEXCEPTION);
+ }
+ Set_invalidflag();
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+ Dbl_clear_signexponent_set_hidden(srcp1);
+ Suint_from_dbl_mantissa(srcp1,srcp2,src_exponent,result);
+ *dstptr = result;
+
+ /* check for inexact */
+ if (Dbl_isinexact_to_unsigned(srcp1,srcp2,src_exponent)) {
+ if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+ else Set_inexactflag();
+ }
+ }
+ else {
+ *dstptr = 0;
+
+ /* check for inexact */
+ if (Dbl_isnotzero_exponentmantissa(srcp1,srcp2)) {
+ if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+ else Set_inexactflag();
+ }
+ }
+ return(NOEXCEPTION);
+}
+
+/*
+ * Double Floating-point to Double Unsigned Fixed
+ */
+/*ARGSUSED*/
+int
+dbl_to_dbl_fcnvfut (dbl_floating_point * srcptr, unsigned int *nullptr,
+ dbl_unsigned * dstptr, unsigned int *status)
+{
+ register int src_exponent;
+ register unsigned int srcp1, srcp2, resultp1, resultp2;
+
+ Dbl_copyfromptr(srcptr,srcp1,srcp2);
+ src_exponent = Dbl_exponent(srcp1) - DBL_BIAS;
+
+ /*
+ * Test for overflow
+ */
+ if (src_exponent > DBL_FX_MAX_EXP + 1) {
+ if (Dbl_isone_sign(srcp1)) {
+ resultp1 = resultp2 = 0;
+ } else {
+ resultp1 = resultp2 = 0xffffffff;
+ }
+ if (Is_invalidtrap_enabled()) {
+ return(INVALIDEXCEPTION);
+ }
+ Set_invalidflag();
+ Duint_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /*
+ * Generate result
+ */
+ if (src_exponent >= 0) {
+ /*
+ * Check sign.
+ * If negative, trap unimplemented.
+ */
+ if (Dbl_isone_sign(srcp1)) {
+ resultp1 = resultp2 = 0;
+ if (Is_invalidtrap_enabled()) {
+ return(INVALIDEXCEPTION);
+ }
+ Set_invalidflag();
+ Duint_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ Dbl_clear_signexponent_set_hidden(srcp1);
+ Duint_from_dbl_mantissa(srcp1,srcp2,src_exponent,
+ resultp1,resultp2);
+ Duint_copytoptr(resultp1,resultp2,dstptr);
+
+ /* check for inexact */
+ if (Dbl_isinexact_to_unsigned(srcp1,srcp2,src_exponent)) {
+ if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+ else Set_inexactflag();
+ }
+ }
+ else {
+ Duint_setzero(resultp1,resultp2);
+ Duint_copytoptr(resultp1,resultp2,dstptr);
+
+ /* check for inexact */
+ if (Dbl_isnotzero_exponentmantissa(srcp1,srcp2)) {
+ if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+ else Set_inexactflag();
+ }
+ }
+ return(NOEXCEPTION);
+}
diff --git a/arch/parisc/math-emu/fcnvfx.c b/arch/parisc/math-emu/fcnvfx.c
new file mode 100644
index 000000000..5e153078d
--- /dev/null
+++ b/arch/parisc/math-emu/fcnvfx.c
@@ -0,0 +1,488 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ */
+/*
+ * BEGIN_DESC
+ *
+ * File:
+ * @(#) pa/spmath/fcnvfx.c $Revision: 1.1 $
+ *
+ * Purpose:
+ * Single Floating-point to Single Fixed-point
+ * Single Floating-point to Double Fixed-point
+ * Double Floating-point to Single Fixed-point
+ * Double Floating-point to Double Fixed-point
+ *
+ * External Interfaces:
+ * dbl_to_dbl_fcnvfx(srcptr,nullptr,dstptr,status)
+ * dbl_to_sgl_fcnvfx(srcptr,nullptr,dstptr,status)
+ * sgl_to_dbl_fcnvfx(srcptr,nullptr,dstptr,status)
+ * sgl_to_sgl_fcnvfx(srcptr,nullptr,dstptr,status)
+ *
+ * Internal Interfaces:
+ *
+ * Theory:
+ * <<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+#include "dbl_float.h"
+#include "cnv_float.h"
+
+/*
+ * Single Floating-point to Single Fixed-point
+ */
+/*ARGSUSED*/
+int
+sgl_to_sgl_fcnvfx(
+ sgl_floating_point *srcptr,
+ sgl_floating_point *nullptr,
+ int *dstptr,
+ sgl_floating_point *status)
+{
+ register unsigned int src, temp;
+ register int src_exponent, result;
+ register boolean inexact = FALSE;
+
+ src = *srcptr;
+ src_exponent = Sgl_exponent(src) - SGL_BIAS;
+
+ /*
+ * Test for overflow
+ */
+ if (src_exponent > SGL_FX_MAX_EXP) {
+ /* check for MININT */
+ if ((src_exponent > SGL_FX_MAX_EXP + 1) ||
+ Sgl_isnotzero_mantissa(src) || Sgl_iszero_sign(src)) {
+ if (Sgl_iszero_sign(src)) result = 0x7fffffff;
+ else result = 0x80000000;
+
+ if (Is_invalidtrap_enabled()) {
+ return(INVALIDEXCEPTION);
+ }
+ Set_invalidflag();
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+ }
+ /*
+ * Generate result
+ */
+ if (src_exponent >= 0) {
+ temp = src;
+ Sgl_clear_signexponent_set_hidden(temp);
+ Int_from_sgl_mantissa(temp,src_exponent);
+ if (Sgl_isone_sign(src)) result = -Sgl_all(temp);
+ else result = Sgl_all(temp);
+
+ /* check for inexact */
+ if (Sgl_isinexact_to_fix(src,src_exponent)) {
+ inexact = TRUE;
+ /* round result */
+ switch (Rounding_mode()) {
+ case ROUNDPLUS:
+ if (Sgl_iszero_sign(src)) result++;
+ break;
+ case ROUNDMINUS:
+ if (Sgl_isone_sign(src)) result--;
+ break;
+ case ROUNDNEAREST:
+ if (Sgl_isone_roundbit(src,src_exponent)) {
+ if (Sgl_isone_stickybit(src,src_exponent)
+ || (Sgl_isone_lowmantissa(temp)))
+ if (Sgl_iszero_sign(src)) result++;
+ else result--;
+ }
+ }
+ }
+ }
+ else {
+ result = 0;
+
+ /* check for inexact */
+ if (Sgl_isnotzero_exponentmantissa(src)) {
+ inexact = TRUE;
+ /* round result */
+ switch (Rounding_mode()) {
+ case ROUNDPLUS:
+ if (Sgl_iszero_sign(src)) result++;
+ break;
+ case ROUNDMINUS:
+ if (Sgl_isone_sign(src)) result--;
+ break;
+ case ROUNDNEAREST:
+ if (src_exponent == -1)
+ if (Sgl_isnotzero_mantissa(src))
+ if (Sgl_iszero_sign(src)) result++;
+ else result--;
+ }
+ }
+ }
+ *dstptr = result;
+ if (inexact) {
+ if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+ else Set_inexactflag();
+ }
+ return(NOEXCEPTION);
+}
+
+/*
+ * Single Floating-point to Double Fixed-point
+ */
+/*ARGSUSED*/
+int
+sgl_to_dbl_fcnvfx(
+ sgl_floating_point *srcptr,
+ unsigned int *nullptr,
+ dbl_integer *dstptr,
+ unsigned int *status)
+{
+ register int src_exponent, resultp1;
+ register unsigned int src, temp, resultp2;
+ register boolean inexact = FALSE;
+
+ src = *srcptr;
+ src_exponent = Sgl_exponent(src) - SGL_BIAS;
+
+ /*
+ * Test for overflow
+ */
+ if (src_exponent > DBL_FX_MAX_EXP) {
+ /* check for MININT */
+ if ((src_exponent > DBL_FX_MAX_EXP + 1) ||
+ Sgl_isnotzero_mantissa(src) || Sgl_iszero_sign(src)) {
+ if (Sgl_iszero_sign(src)) {
+ resultp1 = 0x7fffffff;
+ resultp2 = 0xffffffff;
+ }
+ else {
+ resultp1 = 0x80000000;
+ resultp2 = 0;
+ }
+ if (Is_invalidtrap_enabled()) {
+ return(INVALIDEXCEPTION);
+ }
+ Set_invalidflag();
+ Dint_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ Dint_set_minint(resultp1,resultp2);
+ Dint_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /*
+ * Generate result
+ */
+ if (src_exponent >= 0) {
+ temp = src;
+ Sgl_clear_signexponent_set_hidden(temp);
+ Dint_from_sgl_mantissa(temp,src_exponent,resultp1,resultp2);
+ if (Sgl_isone_sign(src)) {
+ Dint_setone_sign(resultp1,resultp2);
+ }
+
+ /* check for inexact */
+ if (Sgl_isinexact_to_fix(src,src_exponent)) {
+ inexact = TRUE;
+ /* round result */
+ switch (Rounding_mode()) {
+ case ROUNDPLUS:
+ if (Sgl_iszero_sign(src)) {
+ Dint_increment(resultp1,resultp2);
+ }
+ break;
+ case ROUNDMINUS:
+ if (Sgl_isone_sign(src)) {
+ Dint_decrement(resultp1,resultp2);
+ }
+ break;
+ case ROUNDNEAREST:
+ if (Sgl_isone_roundbit(src,src_exponent))
+ if (Sgl_isone_stickybit(src,src_exponent) ||
+ (Dint_isone_lowp2(resultp2)))
+ if (Sgl_iszero_sign(src)) {
+ Dint_increment(resultp1,resultp2);
+ }
+ else {
+ Dint_decrement(resultp1,resultp2);
+ }
+ }
+ }
+ }
+ else {
+ Dint_setzero(resultp1,resultp2);
+
+ /* check for inexact */
+ if (Sgl_isnotzero_exponentmantissa(src)) {
+ inexact = TRUE;
+ /* round result */
+ switch (Rounding_mode()) {
+ case ROUNDPLUS:
+ if (Sgl_iszero_sign(src)) {
+ Dint_increment(resultp1,resultp2);
+ }
+ break;
+ case ROUNDMINUS:
+ if (Sgl_isone_sign(src)) {
+ Dint_decrement(resultp1,resultp2);
+ }
+ break;
+ case ROUNDNEAREST:
+ if (src_exponent == -1)
+ if (Sgl_isnotzero_mantissa(src))
+ if (Sgl_iszero_sign(src)) {
+ Dint_increment(resultp1,resultp2);
+ }
+ else {
+ Dint_decrement(resultp1,resultp2);
+ }
+ }
+ }
+ }
+ Dint_copytoptr(resultp1,resultp2,dstptr);
+ if (inexact) {
+ if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+ else Set_inexactflag();
+ }
+ return(NOEXCEPTION);
+}
+
+/*
+ * Double Floating-point to Single Fixed-point
+ */
+/*ARGSUSED*/
+int
+dbl_to_sgl_fcnvfx(
+ dbl_floating_point *srcptr,
+ unsigned int *nullptr,
+ int *dstptr,
+ unsigned int *status)
+{
+ register unsigned int srcp1,srcp2, tempp1,tempp2;
+ register int src_exponent, result;
+ register boolean inexact = FALSE;
+
+ Dbl_copyfromptr(srcptr,srcp1,srcp2);
+ src_exponent = Dbl_exponent(srcp1) - DBL_BIAS;
+
+ /*
+ * Test for overflow
+ */
+ if (src_exponent > SGL_FX_MAX_EXP) {
+ /* check for MININT */
+ if (Dbl_isoverflow_to_int(src_exponent,srcp1,srcp2)) {
+ if (Dbl_iszero_sign(srcp1)) result = 0x7fffffff;
+ else result = 0x80000000;
+
+ if (Is_invalidtrap_enabled()) {
+ return(INVALIDEXCEPTION);
+ }
+ Set_invalidflag();
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+ }
+ /*
+ * Generate result
+ */
+ if (src_exponent >= 0) {
+ tempp1 = srcp1;
+ tempp2 = srcp2;
+ Dbl_clear_signexponent_set_hidden(tempp1);
+ Int_from_dbl_mantissa(tempp1,tempp2,src_exponent);
+ if (Dbl_isone_sign(srcp1) && (src_exponent <= SGL_FX_MAX_EXP))
+ result = -Dbl_allp1(tempp1);
+ else result = Dbl_allp1(tempp1);
+
+ /* check for inexact */
+ if (Dbl_isinexact_to_fix(srcp1,srcp2,src_exponent)) {
+ inexact = TRUE;
+ /* round result */
+ switch (Rounding_mode()) {
+ case ROUNDPLUS:
+ if (Dbl_iszero_sign(srcp1)) result++;
+ break;
+ case ROUNDMINUS:
+ if (Dbl_isone_sign(srcp1)) result--;
+ break;
+ case ROUNDNEAREST:
+ if (Dbl_isone_roundbit(srcp1,srcp2,src_exponent))
+ if (Dbl_isone_stickybit(srcp1,srcp2,src_exponent) ||
+ (Dbl_isone_lowmantissap1(tempp1)))
+ if (Dbl_iszero_sign(srcp1)) result++;
+ else result--;
+ }
+ /* check for overflow */
+ if ((Dbl_iszero_sign(srcp1) && result < 0) ||
+ (Dbl_isone_sign(srcp1) && result > 0)) {
+
+ if (Dbl_iszero_sign(srcp1)) result = 0x7fffffff;
+ else result = 0x80000000;
+
+ if (Is_invalidtrap_enabled()) {
+ return(INVALIDEXCEPTION);
+ }
+ Set_invalidflag();
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+ }
+ }
+ else {
+ result = 0;
+
+ /* check for inexact */
+ if (Dbl_isnotzero_exponentmantissa(srcp1,srcp2)) {
+ inexact = TRUE;
+ /* round result */
+ switch (Rounding_mode()) {
+ case ROUNDPLUS:
+ if (Dbl_iszero_sign(srcp1)) result++;
+ break;
+ case ROUNDMINUS:
+ if (Dbl_isone_sign(srcp1)) result--;
+ break;
+ case ROUNDNEAREST:
+ if (src_exponent == -1)
+ if (Dbl_isnotzero_mantissa(srcp1,srcp2))
+ if (Dbl_iszero_sign(srcp1)) result++;
+ else result--;
+ }
+ }
+ }
+ *dstptr = result;
+ if (inexact) {
+ if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+ else Set_inexactflag();
+ }
+ return(NOEXCEPTION);
+}
+
+/*
+ * Double Floating-point to Double Fixed-point
+ */
+/*ARGSUSED*/
+int
+dbl_to_dbl_fcnvfx(
+ dbl_floating_point *srcptr,
+ unsigned int *nullptr,
+ dbl_integer *dstptr,
+ unsigned int *status)
+{
+ register int src_exponent, resultp1;
+ register unsigned int srcp1, srcp2, tempp1, tempp2, resultp2;
+ register boolean inexact = FALSE;
+
+ Dbl_copyfromptr(srcptr,srcp1,srcp2);
+ src_exponent = Dbl_exponent(srcp1) - DBL_BIAS;
+
+ /*
+ * Test for overflow
+ */
+ if (src_exponent > DBL_FX_MAX_EXP) {
+ /* check for MININT */
+ if ((src_exponent > DBL_FX_MAX_EXP + 1) ||
+ Dbl_isnotzero_mantissa(srcp1,srcp2) || Dbl_iszero_sign(srcp1)) {
+ if (Dbl_iszero_sign(srcp1)) {
+ resultp1 = 0x7fffffff;
+ resultp2 = 0xffffffff;
+ }
+ else {
+ resultp1 = 0x80000000;
+ resultp2 = 0;
+ }
+ if (Is_invalidtrap_enabled()) {
+ return(INVALIDEXCEPTION);
+ }
+ Set_invalidflag();
+ Dint_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ }
+
+ /*
+ * Generate result
+ */
+ if (src_exponent >= 0) {
+ tempp1 = srcp1;
+ tempp2 = srcp2;
+ Dbl_clear_signexponent_set_hidden(tempp1);
+ Dint_from_dbl_mantissa(tempp1,tempp2,src_exponent,resultp1,
+ resultp2);
+ if (Dbl_isone_sign(srcp1)) {
+ Dint_setone_sign(resultp1,resultp2);
+ }
+
+ /* check for inexact */
+ if (Dbl_isinexact_to_fix(srcp1,srcp2,src_exponent)) {
+ inexact = TRUE;
+ /* round result */
+ switch (Rounding_mode()) {
+ case ROUNDPLUS:
+ if (Dbl_iszero_sign(srcp1)) {
+ Dint_increment(resultp1,resultp2);
+ }
+ break;
+ case ROUNDMINUS:
+ if (Dbl_isone_sign(srcp1)) {
+ Dint_decrement(resultp1,resultp2);
+ }
+ break;
+ case ROUNDNEAREST:
+ if (Dbl_isone_roundbit(srcp1,srcp2,src_exponent))
+ if (Dbl_isone_stickybit(srcp1,srcp2,src_exponent) ||
+ (Dint_isone_lowp2(resultp2)))
+ if (Dbl_iszero_sign(srcp1)) {
+ Dint_increment(resultp1,resultp2);
+ }
+ else {
+ Dint_decrement(resultp1,resultp2);
+ }
+ }
+ }
+ }
+ else {
+ Dint_setzero(resultp1,resultp2);
+
+ /* check for inexact */
+ if (Dbl_isnotzero_exponentmantissa(srcp1,srcp2)) {
+ inexact = TRUE;
+ /* round result */
+ switch (Rounding_mode()) {
+ case ROUNDPLUS:
+ if (Dbl_iszero_sign(srcp1)) {
+ Dint_increment(resultp1,resultp2);
+ }
+ break;
+ case ROUNDMINUS:
+ if (Dbl_isone_sign(srcp1)) {
+ Dint_decrement(resultp1,resultp2);
+ }
+ break;
+ case ROUNDNEAREST:
+ if (src_exponent == -1)
+ if (Dbl_isnotzero_mantissa(srcp1,srcp2))
+ if (Dbl_iszero_sign(srcp1)) {
+ Dint_increment(resultp1,resultp2);
+ }
+ else {
+ Dint_decrement(resultp1,resultp2);
+ }
+ }
+ }
+ }
+ Dint_copytoptr(resultp1,resultp2,dstptr);
+ if (inexact) {
+ if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+ else Set_inexactflag();
+ }
+ return(NOEXCEPTION);
+}
diff --git a/arch/parisc/math-emu/fcnvfxt.c b/arch/parisc/math-emu/fcnvfxt.c
new file mode 100644
index 000000000..ebec31e40
--- /dev/null
+++ b/arch/parisc/math-emu/fcnvfxt.c
@@ -0,0 +1,315 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ */
+/*
+ * BEGIN_DESC
+ *
+ * File:
+ * @(#) pa/spmath/fcnvfxt.c $Revision: 1.1 $
+ *
+ * Purpose:
+ * Single Floating-point to Single Fixed-point /w truncated result
+ * Single Floating-point to Double Fixed-point /w truncated result
+ * Double Floating-point to Single Fixed-point /w truncated result
+ * Double Floating-point to Double Fixed-point /w truncated result
+ *
+ * External Interfaces:
+ * dbl_to_dbl_fcnvfxt(srcptr,nullptr,dstptr,status)
+ * dbl_to_sgl_fcnvfxt(srcptr,nullptr,dstptr,status)
+ * sgl_to_dbl_fcnvfxt(srcptr,nullptr,dstptr,status)
+ * sgl_to_sgl_fcnvfxt(srcptr,nullptr,dstptr,status)
+ *
+ * Internal Interfaces:
+ *
+ * Theory:
+ * <<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+#include "dbl_float.h"
+#include "cnv_float.h"
+
+/*
+ * Convert single floating-point to single fixed-point format
+ * with truncated result
+ */
+/*ARGSUSED*/
+int
+sgl_to_sgl_fcnvfxt(
+ sgl_floating_point *srcptr,
+ unsigned int *nullptr,
+ int *dstptr,
+ unsigned int *status)
+{
+ register unsigned int src, temp;
+ register int src_exponent, result;
+
+ src = *srcptr;
+ src_exponent = Sgl_exponent(src) - SGL_BIAS;
+
+ /*
+ * Test for overflow
+ */
+ if (src_exponent > SGL_FX_MAX_EXP) {
+ /* check for MININT */
+ if ((src_exponent > SGL_FX_MAX_EXP + 1) ||
+ Sgl_isnotzero_mantissa(src) || Sgl_iszero_sign(src)) {
+ if (Sgl_iszero_sign(src)) result = 0x7fffffff;
+ else result = 0x80000000;
+
+ if (Is_invalidtrap_enabled()) {
+ return(INVALIDEXCEPTION);
+ }
+ Set_invalidflag();
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+ }
+ /*
+ * Generate result
+ */
+ if (src_exponent >= 0) {
+ temp = src;
+ Sgl_clear_signexponent_set_hidden(temp);
+ Int_from_sgl_mantissa(temp,src_exponent);
+ if (Sgl_isone_sign(src)) result = -Sgl_all(temp);
+ else result = Sgl_all(temp);
+ *dstptr = result;
+
+ /* check for inexact */
+ if (Sgl_isinexact_to_fix(src,src_exponent)) {
+ if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+ else Set_inexactflag();
+ }
+ }
+ else {
+ *dstptr = 0;
+
+ /* check for inexact */
+ if (Sgl_isnotzero_exponentmantissa(src)) {
+ if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+ else Set_inexactflag();
+ }
+ }
+ return(NOEXCEPTION);
+}
+
+/*
+ * Single Floating-point to Double Fixed-point
+ */
+/*ARGSUSED*/
+int
+sgl_to_dbl_fcnvfxt(
+ sgl_floating_point *srcptr,
+ unsigned int *nullptr,
+ dbl_integer *dstptr,
+ unsigned int *status)
+{
+ register int src_exponent, resultp1;
+ register unsigned int src, temp, resultp2;
+
+ src = *srcptr;
+ src_exponent = Sgl_exponent(src) - SGL_BIAS;
+
+ /*
+ * Test for overflow
+ */
+ if (src_exponent > DBL_FX_MAX_EXP) {
+ /* check for MININT */
+ if ((src_exponent > DBL_FX_MAX_EXP + 1) ||
+ Sgl_isnotzero_mantissa(src) || Sgl_iszero_sign(src)) {
+ if (Sgl_iszero_sign(src)) {
+ resultp1 = 0x7fffffff;
+ resultp2 = 0xffffffff;
+ }
+ else {
+ resultp1 = 0x80000000;
+ resultp2 = 0;
+ }
+ if (Is_invalidtrap_enabled()) {
+ return(INVALIDEXCEPTION);
+ }
+ Set_invalidflag();
+ Dint_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ Dint_set_minint(resultp1,resultp2);
+ Dint_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /*
+ * Generate result
+ */
+ if (src_exponent >= 0) {
+ temp = src;
+ Sgl_clear_signexponent_set_hidden(temp);
+ Dint_from_sgl_mantissa(temp,src_exponent,resultp1,resultp2);
+ if (Sgl_isone_sign(src)) {
+ Dint_setone_sign(resultp1,resultp2);
+ }
+ Dint_copytoptr(resultp1,resultp2,dstptr);
+
+ /* check for inexact */
+ if (Sgl_isinexact_to_fix(src,src_exponent)) {
+ if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+ else Set_inexactflag();
+ }
+ }
+ else {
+ Dint_setzero(resultp1,resultp2);
+ Dint_copytoptr(resultp1,resultp2,dstptr);
+
+ /* check for inexact */
+ if (Sgl_isnotzero_exponentmantissa(src)) {
+ if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+ else Set_inexactflag();
+ }
+ }
+ return(NOEXCEPTION);
+}
+
+/*
+ * Double Floating-point to Single Fixed-point
+ */
+/*ARGSUSED*/
+int
+dbl_to_sgl_fcnvfxt(
+ dbl_floating_point *srcptr,
+ unsigned int *nullptr,
+ int *dstptr,
+ unsigned int *status)
+{
+ register unsigned int srcp1, srcp2, tempp1, tempp2;
+ register int src_exponent, result;
+
+ Dbl_copyfromptr(srcptr,srcp1,srcp2);
+ src_exponent = Dbl_exponent(srcp1) - DBL_BIAS;
+
+ /*
+ * Test for overflow
+ */
+ if (src_exponent > SGL_FX_MAX_EXP) {
+ /* check for MININT */
+ if (Dbl_isoverflow_to_int(src_exponent,srcp1,srcp2)) {
+ if (Dbl_iszero_sign(srcp1)) result = 0x7fffffff;
+ else result = 0x80000000;
+
+ if (Is_invalidtrap_enabled()) {
+ return(INVALIDEXCEPTION);
+ }
+ Set_invalidflag();
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+ }
+ /*
+ * Generate result
+ */
+ if (src_exponent >= 0) {
+ tempp1 = srcp1;
+ tempp2 = srcp2;
+ Dbl_clear_signexponent_set_hidden(tempp1);
+ Int_from_dbl_mantissa(tempp1,tempp2,src_exponent);
+ if (Dbl_isone_sign(srcp1) && (src_exponent <= SGL_FX_MAX_EXP))
+ result = -Dbl_allp1(tempp1);
+ else result = Dbl_allp1(tempp1);
+ *dstptr = result;
+
+ /* check for inexact */
+ if (Dbl_isinexact_to_fix(srcp1,srcp2,src_exponent)) {
+ if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+ else Set_inexactflag();
+ }
+ }
+ else {
+ *dstptr = 0;
+
+ /* check for inexact */
+ if (Dbl_isnotzero_exponentmantissa(srcp1,srcp2)) {
+ if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+ else Set_inexactflag();
+ }
+ }
+ return(NOEXCEPTION);
+}
+
+/*
+ * Double Floating-point to Double Fixed-point
+ */
+/*ARGSUSED*/
+int
+dbl_to_dbl_fcnvfxt(
+ dbl_floating_point *srcptr,
+ unsigned int *nullptr,
+ dbl_integer *dstptr,
+ unsigned int *status)
+{
+ register int src_exponent, resultp1;
+ register unsigned int srcp1, srcp2, tempp1, tempp2, resultp2;
+
+ Dbl_copyfromptr(srcptr,srcp1,srcp2);
+ src_exponent = Dbl_exponent(srcp1) - DBL_BIAS;
+
+ /*
+ * Test for overflow
+ */
+ if (src_exponent > DBL_FX_MAX_EXP) {
+ /* check for MININT */
+ if ((src_exponent > DBL_FX_MAX_EXP + 1) ||
+ Dbl_isnotzero_mantissa(srcp1,srcp2) || Dbl_iszero_sign(srcp1)) {
+ if (Dbl_iszero_sign(srcp1)) {
+ resultp1 = 0x7fffffff;
+ resultp2 = 0xffffffff;
+ }
+ else {
+ resultp1 = 0x80000000;
+ resultp2 = 0;
+ }
+ if (Is_invalidtrap_enabled()) {
+ return(INVALIDEXCEPTION);
+ }
+ Set_invalidflag();
+ Dint_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ }
+ /*
+ * Generate result
+ */
+ if (src_exponent >= 0) {
+ tempp1 = srcp1;
+ tempp2 = srcp2;
+ Dbl_clear_signexponent_set_hidden(tempp1);
+ Dint_from_dbl_mantissa(tempp1,tempp2,src_exponent,
+ resultp1,resultp2);
+ if (Dbl_isone_sign(srcp1)) {
+ Dint_setone_sign(resultp1,resultp2);
+ }
+ Dint_copytoptr(resultp1,resultp2,dstptr);
+
+ /* check for inexact */
+ if (Dbl_isinexact_to_fix(srcp1,srcp2,src_exponent)) {
+ if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+ else Set_inexactflag();
+ }
+ }
+ else {
+ Dint_setzero(resultp1,resultp2);
+ Dint_copytoptr(resultp1,resultp2,dstptr);
+
+ /* check for inexact */
+ if (Dbl_isnotzero_exponentmantissa(srcp1,srcp2)) {
+ if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+ else Set_inexactflag();
+ }
+ }
+ return(NOEXCEPTION);
+}
diff --git a/arch/parisc/math-emu/fcnvuf.c b/arch/parisc/math-emu/fcnvuf.c
new file mode 100644
index 000000000..c54978a0a
--- /dev/null
+++ b/arch/parisc/math-emu/fcnvuf.c
@@ -0,0 +1,305 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ */
+/*
+ * BEGIN_DESC
+ *
+ * File:
+ * @(#) pa/spmath/fcnvuf.c $Revision: 1.1 $
+ *
+ * Purpose:
+ * Fixed point to Floating-point Converts
+ *
+ * External Interfaces:
+ * dbl_to_dbl_fcnvuf(srcptr,nullptr,dstptr,status)
+ * dbl_to_sgl_fcnvuf(srcptr,nullptr,dstptr,status)
+ * sgl_to_dbl_fcnvuf(srcptr,nullptr,dstptr,status)
+ * sgl_to_sgl_fcnvuf(srcptr,nullptr,dstptr,status)
+ *
+ * Internal Interfaces:
+ *
+ * Theory:
+ * <<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+#include "dbl_float.h"
+#include "cnv_float.h"
+
+/************************************************************************
+ * Fixed point to Floating-point Converts *
+ ************************************************************************/
+
+/*
+ * Convert Single Unsigned Fixed to Single Floating-point format
+ */
+
+int
+sgl_to_sgl_fcnvuf(
+ unsigned int *srcptr,
+ unsigned int *nullptr,
+ sgl_floating_point *dstptr,
+ unsigned int *status)
+{
+ register unsigned int src, result = 0;
+ register int dst_exponent;
+
+ src = *srcptr;
+
+ /* Check for zero */
+ if (src == 0) {
+ Sgl_setzero(result);
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+ /*
+ * Generate exponent and normalized mantissa
+ */
+ dst_exponent = 16; /* initialize for normalization */
+ /*
+ * Check word for most significant bit set. Returns
+ * a value in dst_exponent indicating the bit position,
+ * between -1 and 30.
+ */
+ Find_ms_one_bit(src,dst_exponent);
+ /* left justify source, with msb at bit position 0 */
+ src <<= dst_exponent+1;
+ Sgl_set_mantissa(result, src >> SGL_EXP_LENGTH);
+ Sgl_set_exponent(result, 30+SGL_BIAS - dst_exponent);
+
+ /* check for inexact */
+ if (Suint_isinexact_to_sgl(src)) {
+ switch (Rounding_mode()) {
+ case ROUNDPLUS:
+ Sgl_increment(result);
+ break;
+ case ROUNDMINUS: /* never negative */
+ break;
+ case ROUNDNEAREST:
+ Sgl_roundnearest_from_suint(src,result);
+ break;
+ }
+ if (Is_inexacttrap_enabled()) {
+ *dstptr = result;
+ return(INEXACTEXCEPTION);
+ }
+ else Set_inexactflag();
+ }
+ *dstptr = result;
+ return(NOEXCEPTION);
+}
+
+/*
+ * Single Unsigned Fixed to Double Floating-point
+ */
+
+int
+sgl_to_dbl_fcnvuf(
+ unsigned int *srcptr,
+ unsigned int *nullptr,
+ dbl_floating_point *dstptr,
+ unsigned int *status)
+{
+ register int dst_exponent;
+ register unsigned int src, resultp1 = 0, resultp2 = 0;
+
+ src = *srcptr;
+
+ /* Check for zero */
+ if (src == 0) {
+ Dbl_setzero(resultp1,resultp2);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /*
+ * Generate exponent and normalized mantissa
+ */
+ dst_exponent = 16; /* initialize for normalization */
+ /*
+ * Check word for most significant bit set. Returns
+ * a value in dst_exponent indicating the bit position,
+ * between -1 and 30.
+ */
+ Find_ms_one_bit(src,dst_exponent);
+ /* left justify source, with msb at bit position 0 */
+ src <<= dst_exponent+1;
+ Dbl_set_mantissap1(resultp1, src >> DBL_EXP_LENGTH);
+ Dbl_set_mantissap2(resultp2, src << (32-DBL_EXP_LENGTH));
+ Dbl_set_exponent(resultp1, (30+DBL_BIAS) - dst_exponent);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+}
+
+/*
+ * Double Unsigned Fixed to Single Floating-point
+ */
+
+int
+dbl_to_sgl_fcnvuf(
+ dbl_unsigned *srcptr,
+ unsigned int *nullptr,
+ sgl_floating_point *dstptr,
+ unsigned int *status)
+{
+ int dst_exponent;
+ unsigned int srcp1, srcp2, result = 0;
+
+ Duint_copyfromptr(srcptr,srcp1,srcp2);
+
+ /* Check for zero */
+ if (srcp1 == 0 && srcp2 == 0) {
+ Sgl_setzero(result);
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+ /*
+ * Generate exponent and normalized mantissa
+ */
+ dst_exponent = 16; /* initialize for normalization */
+ if (srcp1 == 0) {
+ /*
+ * Check word for most significant bit set. Returns
+ * a value in dst_exponent indicating the bit position,
+ * between -1 and 30.
+ */
+ Find_ms_one_bit(srcp2,dst_exponent);
+ /* left justify source, with msb at bit position 0 */
+ srcp1 = srcp2 << dst_exponent+1;
+ srcp2 = 0;
+ /*
+ * since msb set is in second word, need to
+ * adjust bit position count
+ */
+ dst_exponent += 32;
+ }
+ else {
+ /*
+ * Check word for most significant bit set. Returns
+ * a value in dst_exponent indicating the bit position,
+ * between -1 and 30.
+ *
+ */
+ Find_ms_one_bit(srcp1,dst_exponent);
+ /* left justify source, with msb at bit position 0 */
+ if (dst_exponent >= 0) {
+ Variable_shift_double(srcp1,srcp2,(31-dst_exponent),
+ srcp1);
+ srcp2 <<= dst_exponent+1;
+ }
+ }
+ Sgl_set_mantissa(result, srcp1 >> SGL_EXP_LENGTH);
+ Sgl_set_exponent(result, (62+SGL_BIAS) - dst_exponent);
+
+ /* check for inexact */
+ if (Duint_isinexact_to_sgl(srcp1,srcp2)) {
+ switch (Rounding_mode()) {
+ case ROUNDPLUS:
+ Sgl_increment(result);
+ break;
+ case ROUNDMINUS: /* never negative */
+ break;
+ case ROUNDNEAREST:
+ Sgl_roundnearest_from_duint(srcp1,srcp2,result);
+ break;
+ }
+ if (Is_inexacttrap_enabled()) {
+ *dstptr = result;
+ return(INEXACTEXCEPTION);
+ }
+ else Set_inexactflag();
+ }
+ *dstptr = result;
+ return(NOEXCEPTION);
+}
+
+/*
+ * Double Unsigned Fixed to Double Floating-point
+ */
+
+int
+dbl_to_dbl_fcnvuf(
+ dbl_unsigned *srcptr,
+ unsigned int *nullptr,
+ dbl_floating_point *dstptr,
+ unsigned int *status)
+{
+ register int dst_exponent;
+ register unsigned int srcp1, srcp2, resultp1 = 0, resultp2 = 0;
+
+ Duint_copyfromptr(srcptr,srcp1,srcp2);
+
+ /* Check for zero */
+ if (srcp1 == 0 && srcp2 ==0) {
+ Dbl_setzero(resultp1,resultp2);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /*
+ * Generate exponent and normalized mantissa
+ */
+ dst_exponent = 16; /* initialize for normalization */
+ if (srcp1 == 0) {
+ /*
+ * Check word for most significant bit set. Returns
+ * a value in dst_exponent indicating the bit position,
+ * between -1 and 30.
+ */
+ Find_ms_one_bit(srcp2,dst_exponent);
+ /* left justify source, with msb at bit position 0 */
+ srcp1 = srcp2 << dst_exponent+1;
+ srcp2 = 0;
+ /*
+ * since msb set is in second word, need to
+ * adjust bit position count
+ */
+ dst_exponent += 32;
+ }
+ else {
+ /*
+ * Check word for most significant bit set. Returns
+ * a value in dst_exponent indicating the bit position,
+ * between -1 and 30.
+ */
+ Find_ms_one_bit(srcp1,dst_exponent);
+ /* left justify source, with msb at bit position 0 */
+ if (dst_exponent >= 0) {
+ Variable_shift_double(srcp1,srcp2,(31-dst_exponent),
+ srcp1);
+ srcp2 <<= dst_exponent+1;
+ }
+ }
+ Dbl_set_mantissap1(resultp1, srcp1 >> DBL_EXP_LENGTH);
+ Shiftdouble(srcp1,srcp2,DBL_EXP_LENGTH,resultp2);
+ Dbl_set_exponent(resultp1, (62+DBL_BIAS) - dst_exponent);
+
+ /* check for inexact */
+ if (Duint_isinexact_to_dbl(srcp2)) {
+ switch (Rounding_mode()) {
+ case ROUNDPLUS:
+ Dbl_increment(resultp1,resultp2);
+ break;
+ case ROUNDMINUS: /* never negative */
+ break;
+ case ROUNDNEAREST:
+ Dbl_roundnearest_from_duint(srcp2,resultp1,
+ resultp2);
+ break;
+ }
+ if (Is_inexacttrap_enabled()) {
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(INEXACTEXCEPTION);
+ }
+ else Set_inexactflag();
+ }
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+}
+
diff --git a/arch/parisc/math-emu/fcnvxf.c b/arch/parisc/math-emu/fcnvxf.c
new file mode 100644
index 000000000..694017971
--- /dev/null
+++ b/arch/parisc/math-emu/fcnvxf.c
@@ -0,0 +1,373 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ */
+/*
+ * BEGIN_DESC
+ *
+ * File:
+ * @(#) pa/spmath/fcnvxf.c $Revision: 1.1 $
+ *
+ * Purpose:
+ * Single Fixed-point to Single Floating-point
+ * Single Fixed-point to Double Floating-point
+ * Double Fixed-point to Single Floating-point
+ * Double Fixed-point to Double Floating-point
+ *
+ * External Interfaces:
+ * dbl_to_dbl_fcnvxf(srcptr,nullptr,dstptr,status)
+ * dbl_to_sgl_fcnvxf(srcptr,nullptr,dstptr,status)
+ * sgl_to_dbl_fcnvxf(srcptr,nullptr,dstptr,status)
+ * sgl_to_sgl_fcnvxf(srcptr,nullptr,dstptr,status)
+ *
+ * Internal Interfaces:
+ *
+ * Theory:
+ * <<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+#include "dbl_float.h"
+#include "cnv_float.h"
+
+/*
+ * Convert single fixed-point to single floating-point format
+ */
+
+int
+sgl_to_sgl_fcnvxf(
+ int *srcptr,
+ unsigned int *nullptr,
+ sgl_floating_point *dstptr,
+ unsigned int *status)
+{
+ register int src, dst_exponent;
+ register unsigned int result = 0;
+
+ src = *srcptr;
+ /*
+ * set sign bit of result and get magnitude of source
+ */
+ if (src < 0) {
+ Sgl_setone_sign(result);
+ Int_negate(src);
+ }
+ else {
+ Sgl_setzero_sign(result);
+ /* Check for zero */
+ if (src == 0) {
+ Sgl_setzero(result);
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+ }
+ /*
+ * Generate exponent and normalized mantissa
+ */
+ dst_exponent = 16; /* initialize for normalization */
+ /*
+ * Check word for most significant bit set. Returns
+ * a value in dst_exponent indicating the bit position,
+ * between -1 and 30.
+ */
+ Find_ms_one_bit(src,dst_exponent);
+ /* left justify source, with msb at bit position 1 */
+ if (dst_exponent >= 0) src <<= dst_exponent;
+ else src = 1 << 30;
+ Sgl_set_mantissa(result, src >> (SGL_EXP_LENGTH-1));
+ Sgl_set_exponent(result, 30+SGL_BIAS - dst_exponent);
+
+ /* check for inexact */
+ if (Int_isinexact_to_sgl(src)) {
+ switch (Rounding_mode()) {
+ case ROUNDPLUS:
+ if (Sgl_iszero_sign(result))
+ Sgl_increment(result);
+ break;
+ case ROUNDMINUS:
+ if (Sgl_isone_sign(result))
+ Sgl_increment(result);
+ break;
+ case ROUNDNEAREST:
+ Sgl_roundnearest_from_int(src,result);
+ }
+ if (Is_inexacttrap_enabled()) {
+ *dstptr = result;
+ return(INEXACTEXCEPTION);
+ }
+ else Set_inexactflag();
+ }
+ *dstptr = result;
+ return(NOEXCEPTION);
+}
+
+/*
+ * Single Fixed-point to Double Floating-point
+ */
+
+int
+sgl_to_dbl_fcnvxf(
+ int *srcptr,
+ unsigned int *nullptr,
+ dbl_floating_point *dstptr,
+ unsigned int *status)
+{
+ register int src, dst_exponent;
+ register unsigned int resultp1 = 0, resultp2 = 0;
+
+ src = *srcptr;
+ /*
+ * set sign bit of result and get magnitude of source
+ */
+ if (src < 0) {
+ Dbl_setone_sign(resultp1);
+ Int_negate(src);
+ }
+ else {
+ Dbl_setzero_sign(resultp1);
+ /* Check for zero */
+ if (src == 0) {
+ Dbl_setzero(resultp1,resultp2);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ }
+ /*
+ * Generate exponent and normalized mantissa
+ */
+ dst_exponent = 16; /* initialize for normalization */
+ /*
+ * Check word for most significant bit set. Returns
+ * a value in dst_exponent indicating the bit position,
+ * between -1 and 30.
+ */
+ Find_ms_one_bit(src,dst_exponent);
+ /* left justify source, with msb at bit position 1 */
+ if (dst_exponent >= 0) src <<= dst_exponent;
+ else src = 1 << 30;
+ Dbl_set_mantissap1(resultp1, src >> DBL_EXP_LENGTH - 1);
+ Dbl_set_mantissap2(resultp2, src << (33-DBL_EXP_LENGTH));
+ Dbl_set_exponent(resultp1, (30+DBL_BIAS) - dst_exponent);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+}
+
+/*
+ * Double Fixed-point to Single Floating-point
+ */
+
+int
+dbl_to_sgl_fcnvxf(
+ dbl_integer *srcptr,
+ unsigned int *nullptr,
+ sgl_floating_point *dstptr,
+ unsigned int *status)
+{
+ int dst_exponent, srcp1;
+ unsigned int result = 0, srcp2;
+
+ Dint_copyfromptr(srcptr,srcp1,srcp2);
+ /*
+ * set sign bit of result and get magnitude of source
+ */
+ if (srcp1 < 0) {
+ Sgl_setone_sign(result);
+ Dint_negate(srcp1,srcp2);
+ }
+ else {
+ Sgl_setzero_sign(result);
+ /* Check for zero */
+ if (srcp1 == 0 && srcp2 == 0) {
+ Sgl_setzero(result);
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+ }
+ /*
+ * Generate exponent and normalized mantissa
+ */
+ dst_exponent = 16; /* initialize for normalization */
+ if (srcp1 == 0) {
+ /*
+ * Check word for most significant bit set. Returns
+ * a value in dst_exponent indicating the bit position,
+ * between -1 and 30.
+ */
+ Find_ms_one_bit(srcp2,dst_exponent);
+ /* left justify source, with msb at bit position 1 */
+ if (dst_exponent >= 0) {
+ srcp1 = srcp2 << dst_exponent;
+ srcp2 = 0;
+ }
+ else {
+ srcp1 = srcp2 >> 1;
+ srcp2 <<= 31;
+ }
+ /*
+ * since msb set is in second word, need to
+ * adjust bit position count
+ */
+ dst_exponent += 32;
+ }
+ else {
+ /*
+ * Check word for most significant bit set. Returns
+ * a value in dst_exponent indicating the bit position,
+ * between -1 and 30.
+ *
+ */
+ Find_ms_one_bit(srcp1,dst_exponent);
+ /* left justify source, with msb at bit position 1 */
+ if (dst_exponent > 0) {
+ Variable_shift_double(srcp1,srcp2,(32-dst_exponent),
+ srcp1);
+ srcp2 <<= dst_exponent;
+ }
+ /*
+ * If dst_exponent = 0, we don't need to shift anything.
+ * If dst_exponent = -1, src = - 2**63 so we won't need to
+ * shift srcp2.
+ */
+ else srcp1 >>= -(dst_exponent);
+ }
+ Sgl_set_mantissa(result, srcp1 >> SGL_EXP_LENGTH - 1);
+ Sgl_set_exponent(result, (62+SGL_BIAS) - dst_exponent);
+
+ /* check for inexact */
+ if (Dint_isinexact_to_sgl(srcp1,srcp2)) {
+ switch (Rounding_mode()) {
+ case ROUNDPLUS:
+ if (Sgl_iszero_sign(result))
+ Sgl_increment(result);
+ break;
+ case ROUNDMINUS:
+ if (Sgl_isone_sign(result))
+ Sgl_increment(result);
+ break;
+ case ROUNDNEAREST:
+ Sgl_roundnearest_from_dint(srcp1,srcp2,result);
+ }
+ if (Is_inexacttrap_enabled()) {
+ *dstptr = result;
+ return(INEXACTEXCEPTION);
+ }
+ else Set_inexactflag();
+ }
+ *dstptr = result;
+ return(NOEXCEPTION);
+}
+
+/*
+ * Double Fixed-point to Double Floating-point
+ */
+
+int
+dbl_to_dbl_fcnvxf(
+ dbl_integer *srcptr,
+ unsigned int *nullptr,
+ dbl_floating_point *dstptr,
+ unsigned int *status)
+{
+ register int srcp1, dst_exponent;
+ register unsigned int srcp2, resultp1 = 0, resultp2 = 0;
+
+ Dint_copyfromptr(srcptr,srcp1,srcp2);
+ /*
+ * set sign bit of result and get magnitude of source
+ */
+ if (srcp1 < 0) {
+ Dbl_setone_sign(resultp1);
+ Dint_negate(srcp1,srcp2);
+ }
+ else {
+ Dbl_setzero_sign(resultp1);
+ /* Check for zero */
+ if (srcp1 == 0 && srcp2 ==0) {
+ Dbl_setzero(resultp1,resultp2);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ }
+ /*
+ * Generate exponent and normalized mantissa
+ */
+ dst_exponent = 16; /* initialize for normalization */
+ if (srcp1 == 0) {
+ /*
+ * Check word for most significant bit set. Returns
+ * a value in dst_exponent indicating the bit position,
+ * between -1 and 30.
+ */
+ Find_ms_one_bit(srcp2,dst_exponent);
+ /* left justify source, with msb at bit position 1 */
+ if (dst_exponent >= 0) {
+ srcp1 = srcp2 << dst_exponent;
+ srcp2 = 0;
+ }
+ else {
+ srcp1 = srcp2 >> 1;
+ srcp2 <<= 31;
+ }
+ /*
+ * since msb set is in second word, need to
+ * adjust bit position count
+ */
+ dst_exponent += 32;
+ }
+ else {
+ /*
+ * Check word for most significant bit set. Returns
+ * a value in dst_exponent indicating the bit position,
+ * between -1 and 30.
+ */
+ Find_ms_one_bit(srcp1,dst_exponent);
+ /* left justify source, with msb at bit position 1 */
+ if (dst_exponent > 0) {
+ Variable_shift_double(srcp1,srcp2,(32-dst_exponent),
+ srcp1);
+ srcp2 <<= dst_exponent;
+ }
+ /*
+ * If dst_exponent = 0, we don't need to shift anything.
+ * If dst_exponent = -1, src = - 2**63 so we won't need to
+ * shift srcp2.
+ */
+ else srcp1 >>= -(dst_exponent);
+ }
+ Dbl_set_mantissap1(resultp1, srcp1 >> (DBL_EXP_LENGTH-1));
+ Shiftdouble(srcp1,srcp2,DBL_EXP_LENGTH-1,resultp2);
+ Dbl_set_exponent(resultp1, (62+DBL_BIAS) - dst_exponent);
+
+ /* check for inexact */
+ if (Dint_isinexact_to_dbl(srcp2)) {
+ switch (Rounding_mode()) {
+ case ROUNDPLUS:
+ if (Dbl_iszero_sign(resultp1)) {
+ Dbl_increment(resultp1,resultp2);
+ }
+ break;
+ case ROUNDMINUS:
+ if (Dbl_isone_sign(resultp1)) {
+ Dbl_increment(resultp1,resultp2);
+ }
+ break;
+ case ROUNDNEAREST:
+ Dbl_roundnearest_from_dint(srcp2,resultp1,
+ resultp2);
+ }
+ if (Is_inexacttrap_enabled()) {
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(INEXACTEXCEPTION);
+ }
+ else Set_inexactflag();
+ }
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+}
diff --git a/arch/parisc/math-emu/float.h b/arch/parisc/math-emu/float.h
new file mode 100644
index 000000000..531bbda5e
--- /dev/null
+++ b/arch/parisc/math-emu/float.h
@@ -0,0 +1,568 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ */
+/*
+ * BEGIN_DESC
+ *
+ * File:
+ * @(#) pa/spmath/float.h $Revision: 1.1 $
+ *
+ * Purpose:
+ * <<please update with a synopis of the functionality provided by this file>>
+ *
+ * BE header: no
+ *
+ * Shipped: yes
+ * /usr/conf/pa/spmath/float.h
+ *
+ * END_DESC
+*/
+
+#ifdef __NO_PA_HDRS
+ PA header file -- do not include this header file for non-PA builds.
+#endif
+
+#include "fpbits.h"
+#include "hppa.h"
+/*
+ * Want to pick up the FPU capability flags, not the PDC structures.
+ * 'LOCORE' isn't really true in this case, but we don't want the C structures
+ * so it suits our purposes
+ */
+#define LOCORE
+#include "fpu.h"
+
+/*
+ * Declare the basic structures for the 3 different
+ * floating-point precisions.
+ *
+ * Single number
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |s| exp | mantissa |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ */
+#define Sall(object) (object)
+#define Ssign(object) Bitfield_extract( 0, 1,object)
+#define Ssignedsign(object) Bitfield_signed_extract( 0, 1,object)
+#define Sexponent(object) Bitfield_extract( 1, 8,object)
+#define Smantissa(object) Bitfield_mask( 9, 23,object)
+#define Ssignaling(object) Bitfield_extract( 9, 1,object)
+#define Ssignalingnan(object) Bitfield_extract( 1, 9,object)
+#define Shigh2mantissa(object) Bitfield_extract( 9, 2,object)
+#define Sexponentmantissa(object) Bitfield_mask( 1, 31,object)
+#define Ssignexponent(object) Bitfield_extract( 0, 9,object)
+#define Shidden(object) Bitfield_extract( 8, 1,object)
+#define Shiddenoverflow(object) Bitfield_extract( 7, 1,object)
+#define Shiddenhigh7mantissa(object) Bitfield_extract( 8, 8,object)
+#define Shiddenhigh3mantissa(object) Bitfield_extract( 8, 4,object)
+#define Slow(object) Bitfield_mask( 31, 1,object)
+#define Slow4(object) Bitfield_mask( 28, 4,object)
+#define Slow31(object) Bitfield_mask( 1, 31,object)
+#define Shigh31(object) Bitfield_extract( 0, 31,object)
+#define Ssignedhigh31(object) Bitfield_signed_extract( 0, 31,object)
+#define Shigh4(object) Bitfield_extract( 0, 4,object)
+#define Sbit24(object) Bitfield_extract( 24, 1,object)
+#define Sbit28(object) Bitfield_extract( 28, 1,object)
+#define Sbit29(object) Bitfield_extract( 29, 1,object)
+#define Sbit30(object) Bitfield_extract( 30, 1,object)
+#define Sbit31(object) Bitfield_mask( 31, 1,object)
+
+#define Deposit_ssign(object,value) Bitfield_deposit(value,0,1,object)
+#define Deposit_sexponent(object,value) Bitfield_deposit(value,1,8,object)
+#define Deposit_smantissa(object,value) Bitfield_deposit(value,9,23,object)
+#define Deposit_shigh2mantissa(object,value) Bitfield_deposit(value,9,2,object)
+#define Deposit_sexponentmantissa(object,value) \
+ Bitfield_deposit(value,1,31,object)
+#define Deposit_ssignexponent(object,value) Bitfield_deposit(value,0,9,object)
+#define Deposit_slow(object,value) Bitfield_deposit(value,31,1,object)
+#define Deposit_shigh4(object,value) Bitfield_deposit(value,0,4,object)
+
+#define Is_ssign(object) Bitfield_mask( 0, 1,object)
+#define Is_ssignaling(object) Bitfield_mask( 9, 1,object)
+#define Is_shidden(object) Bitfield_mask( 8, 1,object)
+#define Is_shiddenoverflow(object) Bitfield_mask( 7, 1,object)
+#define Is_slow(object) Bitfield_mask( 31, 1,object)
+#define Is_sbit24(object) Bitfield_mask( 24, 1,object)
+#define Is_sbit28(object) Bitfield_mask( 28, 1,object)
+#define Is_sbit29(object) Bitfield_mask( 29, 1,object)
+#define Is_sbit30(object) Bitfield_mask( 30, 1,object)
+#define Is_sbit31(object) Bitfield_mask( 31, 1,object)
+
+/*
+ * Double number.
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |s| exponent | mantissa part 1 |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ *
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | mantissa part 2 |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ */
+#define Dallp1(object) (object)
+#define Dsign(object) Bitfield_extract( 0, 1,object)
+#define Dsignedsign(object) Bitfield_signed_extract( 0, 1,object)
+#define Dexponent(object) Bitfield_extract( 1, 11,object)
+#define Dmantissap1(object) Bitfield_mask( 12, 20,object)
+#define Dsignaling(object) Bitfield_extract( 12, 1,object)
+#define Dsignalingnan(object) Bitfield_extract( 1, 12,object)
+#define Dhigh2mantissa(object) Bitfield_extract( 12, 2,object)
+#define Dexponentmantissap1(object) Bitfield_mask( 1, 31,object)
+#define Dsignexponent(object) Bitfield_extract( 0, 12,object)
+#define Dhidden(object) Bitfield_extract( 11, 1,object)
+#define Dhiddenoverflow(object) Bitfield_extract( 10, 1,object)
+#define Dhiddenhigh7mantissa(object) Bitfield_extract( 11, 8,object)
+#define Dhiddenhigh3mantissa(object) Bitfield_extract( 11, 4,object)
+#define Dlowp1(object) Bitfield_mask( 31, 1,object)
+#define Dlow31p1(object) Bitfield_mask( 1, 31,object)
+#define Dhighp1(object) Bitfield_extract( 0, 1,object)
+#define Dhigh4p1(object) Bitfield_extract( 0, 4,object)
+#define Dhigh31p1(object) Bitfield_extract( 0, 31,object)
+#define Dsignedhigh31p1(object) Bitfield_signed_extract( 0, 31,object)
+#define Dbit3p1(object) Bitfield_extract( 3, 1,object)
+
+#define Deposit_dsign(object,value) Bitfield_deposit(value,0,1,object)
+#define Deposit_dexponent(object,value) Bitfield_deposit(value,1,11,object)
+#define Deposit_dmantissap1(object,value) Bitfield_deposit(value,12,20,object)
+#define Deposit_dhigh2mantissa(object,value) Bitfield_deposit(value,12,2,object)
+#define Deposit_dexponentmantissap1(object,value) \
+ Bitfield_deposit(value,1,31,object)
+#define Deposit_dsignexponent(object,value) Bitfield_deposit(value,0,12,object)
+#define Deposit_dlowp1(object,value) Bitfield_deposit(value,31,1,object)
+#define Deposit_dhigh4p1(object,value) Bitfield_deposit(value,0,4,object)
+
+#define Is_dsign(object) Bitfield_mask( 0, 1,object)
+#define Is_dsignaling(object) Bitfield_mask( 12, 1,object)
+#define Is_dhidden(object) Bitfield_mask( 11, 1,object)
+#define Is_dhiddenoverflow(object) Bitfield_mask( 10, 1,object)
+#define Is_dlowp1(object) Bitfield_mask( 31, 1,object)
+#define Is_dhighp1(object) Bitfield_mask( 0, 1,object)
+#define Is_dbit3p1(object) Bitfield_mask( 3, 1,object)
+
+#define Dallp2(object) (object)
+#define Dmantissap2(object) (object)
+#define Dlowp2(object) Bitfield_mask( 31, 1,object)
+#define Dlow4p2(object) Bitfield_mask( 28, 4,object)
+#define Dlow31p2(object) Bitfield_mask( 1, 31,object)
+#define Dhighp2(object) Bitfield_extract( 0, 1,object)
+#define Dhigh31p2(object) Bitfield_extract( 0, 31,object)
+#define Dbit2p2(object) Bitfield_extract( 2, 1,object)
+#define Dbit3p2(object) Bitfield_extract( 3, 1,object)
+#define Dbit21p2(object) Bitfield_extract( 21, 1,object)
+#define Dbit28p2(object) Bitfield_extract( 28, 1,object)
+#define Dbit29p2(object) Bitfield_extract( 29, 1,object)
+#define Dbit30p2(object) Bitfield_extract( 30, 1,object)
+#define Dbit31p2(object) Bitfield_mask( 31, 1,object)
+
+#define Deposit_dlowp2(object,value) Bitfield_deposit(value,31,1,object)
+
+#define Is_dlowp2(object) Bitfield_mask( 31, 1,object)
+#define Is_dhighp2(object) Bitfield_mask( 0, 1,object)
+#define Is_dbit2p2(object) Bitfield_mask( 2, 1,object)
+#define Is_dbit3p2(object) Bitfield_mask( 3, 1,object)
+#define Is_dbit21p2(object) Bitfield_mask( 21, 1,object)
+#define Is_dbit28p2(object) Bitfield_mask( 28, 1,object)
+#define Is_dbit29p2(object) Bitfield_mask( 29, 1,object)
+#define Is_dbit30p2(object) Bitfield_mask( 30, 1,object)
+#define Is_dbit31p2(object) Bitfield_mask( 31, 1,object)
+
+/*
+ * Quad number.
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |s| exponent | mantissa part 1 |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ *
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | mantissa part 2 |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ *
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | mantissa part 3 |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ *
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | mantissa part 4 |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ */
+typedef struct
+ {
+ union
+ {
+ struct { unsigned qallp1; } u_qallp1;
+/* Not needed for now...
+ Bitfield_extract( 0, 1,u_qsign,qsign)
+ Bitfield_signed_extract( 0, 1,u_qsignedsign,qsignedsign)
+ Bitfield_extract( 1, 15,u_qexponent,qexponent)
+ Bitfield_extract(16, 16,u_qmantissap1,qmantissap1)
+ Bitfield_extract(16, 1,u_qsignaling,qsignaling)
+ Bitfield_extract(1, 16,u_qsignalingnan,qsignalingnan)
+ Bitfield_extract(16, 2,u_qhigh2mantissa,qhigh2mantissa)
+ Bitfield_extract( 1, 31,u_qexponentmantissap1,qexponentmantissap1)
+ Bitfield_extract( 0, 16,u_qsignexponent,qsignexponent)
+ Bitfield_extract(15, 1,u_qhidden,qhidden)
+ Bitfield_extract(14, 1,u_qhiddenoverflow,qhiddenoverflow)
+ Bitfield_extract(15, 8,u_qhiddenhigh7mantissa,qhiddenhigh7mantissa)
+ Bitfield_extract(15, 4,u_qhiddenhigh3mantissa,qhiddenhigh3mantissa)
+ Bitfield_extract(31, 1,u_qlowp1,qlowp1)
+ Bitfield_extract( 1, 31,u_qlow31p1,qlow31p1)
+ Bitfield_extract( 0, 1,u_qhighp1,qhighp1)
+ Bitfield_extract( 0, 4,u_qhigh4p1,qhigh4p1)
+ Bitfield_extract( 0, 31,u_qhigh31p1,qhigh31p1)
+ */
+ } quad_u1;
+ union
+ {
+ struct { unsigned qallp2; } u_qallp2;
+ /* Not needed for now...
+ Bitfield_extract(31, 1,u_qlowp2,qlowp2)
+ Bitfield_extract( 1, 31,u_qlow31p2,qlow31p2)
+ Bitfield_extract( 0, 1,u_qhighp2,qhighp2)
+ Bitfield_extract( 0, 31,u_qhigh31p2,qhigh31p2)
+ */
+ } quad_u2;
+ union
+ {
+ struct { unsigned qallp3; } u_qallp3;
+ /* Not needed for now...
+ Bitfield_extract(31, 1,u_qlowp3,qlowp3)
+ Bitfield_extract( 1, 31,u_qlow31p3,qlow31p3)
+ Bitfield_extract( 0, 1,u_qhighp3,qhighp3)
+ Bitfield_extract( 0, 31,u_qhigh31p3,qhigh31p3)
+ */
+ } quad_u3;
+ union
+ {
+ struct { unsigned qallp4; } u_qallp4;
+ /* Not need for now...
+ Bitfield_extract(31, 1,u_qlowp4,qlowp4)
+ Bitfield_extract( 1, 31,u_qlow31p4,qlow31p4)
+ Bitfield_extract( 0, 1,u_qhighp4,qhighp4)
+ Bitfield_extract( 0, 31,u_qhigh31p4,qhigh31p4)
+ */
+ } quad_u4;
+ } quad_floating_point;
+
+/* Extension - An additional structure to hold the guard, round and
+ * sticky bits during computations.
+ */
+#define Extall(object) (object)
+#define Extsign(object) Bitfield_extract( 0, 1,object)
+#define Exthigh31(object) Bitfield_extract( 0, 31,object)
+#define Extlow31(object) Bitfield_extract( 1, 31,object)
+#define Extlow(object) Bitfield_extract( 31, 1,object)
+
+/*
+ * Single extended - The upper word is just like single precision,
+ * but one additional word of mantissa is needed.
+ */
+#define Sextallp1(object) (object)
+#define Sextallp2(object) (object)
+#define Sextlowp1(object) Bitfield_extract( 31, 1,object)
+#define Sexthighp2(object) Bitfield_extract( 0, 1,object)
+#define Sextlow31p2(object) Bitfield_extract( 1, 31,object)
+#define Sexthiddenoverflow(object) Bitfield_extract( 4, 1,object)
+#define Is_sexthiddenoverflow(object) Bitfield_mask( 4, 1,object)
+
+/*
+ * Double extended - The upper two words are just like double precision,
+ * but two additional words of mantissa are needed.
+ */
+#define Dextallp1(object) (object)
+#define Dextallp2(object) (object)
+#define Dextallp3(object) (object)
+#define Dextallp4(object) (object)
+#define Dextlowp2(object) Bitfield_extract( 31, 1,object)
+#define Dexthighp3(object) Bitfield_extract( 0, 1,object)
+#define Dextlow31p3(object) Bitfield_extract( 1, 31,object)
+#define Dexthiddenoverflow(object) Bitfield_extract( 10, 1,object)
+#define Is_dexthiddenoverflow(object) Bitfield_mask( 10, 1,object)
+#define Deposit_dextlowp4(object,value) Bitfield_deposit(value,31,1,object)
+
+/*
+ * Declare the basic structures for the 3 different
+ * fixed-point precisions.
+ *
+ * Single number
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |s| integer |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ */
+typedef int sgl_integer;
+
+/*
+ * Double number.
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |s| high integer |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ *
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | low integer |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ */
+struct dint {
+ int wd0;
+ unsigned int wd1;
+};
+
+struct dblwd {
+ unsigned int wd0;
+ unsigned int wd1;
+};
+
+/*
+ * Quad number.
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |s| integer part1 |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ *
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | integer part 2 |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ *
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | integer part 3 |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ *
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | integer part 4 |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ */
+
+struct quadwd {
+ int wd0;
+ unsigned int wd1;
+ unsigned int wd2;
+ unsigned int wd3;
+};
+
+typedef struct quadwd quad_integer;
+
+
+/* useful typedefs */
+typedef unsigned int sgl_floating_point;
+typedef struct dblwd dbl_floating_point;
+typedef struct dint dbl_integer;
+typedef struct dblwd dbl_unsigned;
+
+/*
+ * Define the different precisions' parameters.
+ */
+#define SGL_BITLENGTH 32
+#define SGL_EMAX 127
+#define SGL_EMIN (-126)
+#define SGL_BIAS 127
+#define SGL_WRAP 192
+#define SGL_INFINITY_EXPONENT (SGL_EMAX+SGL_BIAS+1)
+#define SGL_THRESHOLD 32
+#define SGL_EXP_LENGTH 8
+#define SGL_P 24
+
+#define DBL_BITLENGTH 64
+#define DBL_EMAX 1023
+#define DBL_EMIN (-1022)
+#define DBL_BIAS 1023
+#define DBL_WRAP 1536
+#define DBL_INFINITY_EXPONENT (DBL_EMAX+DBL_BIAS+1)
+#define DBL_THRESHOLD 64
+#define DBL_EXP_LENGTH 11
+#define DBL_P 53
+
+#define QUAD_BITLENGTH 128
+#define QUAD_EMAX 16383
+#define QUAD_EMIN (-16382)
+#define QUAD_BIAS 16383
+#define QUAD_WRAP 24576
+#define QUAD_INFINITY_EXPONENT (QUAD_EMAX+QUAD_BIAS+1)
+#define QUAD_P 113
+
+/* Boolean Values etc. */
+#define FALSE 0
+#define TRUE (!FALSE)
+#define NOT !
+#define XOR ^
+
+/* other constants */
+#undef NULL
+#define NULL 0
+#define NIL 0
+#define SGL 0
+#define DBL 1
+#define BADFMT 2
+#define QUAD 3
+
+
+/* Types */
+typedef int boolean;
+typedef int FORMAT;
+typedef int VOID;
+
+
+/* Declare status register equivalent to FPUs architecture.
+ *
+ * 0 1 2 3 4 5 6 7 8 910 1 2 3 4 5 6 7 8 920 1 2 3 4 5 6 7 8 930 1
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |V|Z|O|U|I|C| rsv | model | version |RM |rsv|T|r|V|Z|O|U|I|
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ */
+#define Cbit(object) Bitfield_extract( 5, 1,object)
+#define Tbit(object) Bitfield_extract( 25, 1,object)
+#define Roundingmode(object) Bitfield_extract( 21, 2,object)
+#define Invalidtrap(object) Bitfield_extract( 27, 1,object)
+#define Divisionbyzerotrap(object) Bitfield_extract( 28, 1,object)
+#define Overflowtrap(object) Bitfield_extract( 29, 1,object)
+#define Underflowtrap(object) Bitfield_extract( 30, 1,object)
+#define Inexacttrap(object) Bitfield_extract( 31, 1,object)
+#define Invalidflag(object) Bitfield_extract( 0, 1,object)
+#define Divisionbyzeroflag(object) Bitfield_extract( 1, 1,object)
+#define Overflowflag(object) Bitfield_extract( 2, 1,object)
+#define Underflowflag(object) Bitfield_extract( 3, 1,object)
+#define Inexactflag(object) Bitfield_extract( 4, 1,object)
+#define Allflags(object) Bitfield_extract( 0, 5,object)
+
+/* Definitions relevant to the status register */
+
+/* Rounding Modes */
+#define ROUNDNEAREST 0
+#define ROUNDZERO 1
+#define ROUNDPLUS 2
+#define ROUNDMINUS 3
+
+/* Exceptions */
+#define NOEXCEPTION 0x0
+#define INVALIDEXCEPTION 0x20
+#define DIVISIONBYZEROEXCEPTION 0x10
+#define OVERFLOWEXCEPTION 0x08
+#define UNDERFLOWEXCEPTION 0x04
+#define INEXACTEXCEPTION 0x02
+#define UNIMPLEMENTEDEXCEPTION 0x01
+
+/* New exceptions for the 2E Opcode */
+#define OPC_2E_INVALIDEXCEPTION 0x30
+#define OPC_2E_OVERFLOWEXCEPTION 0x18
+#define OPC_2E_UNDERFLOWEXCEPTION 0x0c
+#define OPC_2E_INEXACTEXCEPTION 0x12
+
+/* Declare exception registers equivalent to FPUs architecture
+ *
+ * 0 1 2 3 4 5 6 7 8 910 1 2 3 4 5 6 7 8 920 1 2 3 4 5 6 7 8 930 1
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * |excepttype | r1 | r2/ext | operation |parm |n| t/cond |
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ */
+#define Allexception(object) (object)
+#define Exceptiontype(object) Bitfield_extract( 0, 6,object)
+#define Instructionfield(object) Bitfield_mask( 6,26,object)
+#define Parmfield(object) Bitfield_extract( 23, 3,object)
+#define Rabit(object) Bitfield_extract( 24, 1,object)
+#define Ibit(object) Bitfield_extract( 25, 1,object)
+
+#define Set_exceptiontype(object,value) Bitfield_deposit(value, 0, 6,object)
+#define Set_parmfield(object,value) Bitfield_deposit(value, 23, 3,object)
+#define Set_exceptiontype_and_instr_field(exception,instruction,object) \
+ object = exception << 26 | instruction
+
+/* Declare the condition field
+ *
+ * 0 1 2 3 4 5 6 7 8 910 1 2 3 4 5 6 7 8 920 1 2 3 4 5 6 7 8 930 1
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ * | |G|L|E|U|X|
+ * +-------+-------+-------+-------+-------+-------+-------+-------+
+ */
+#define Greaterthanbit(object) Bitfield_extract( 27, 1,object)
+#define Lessthanbit(object) Bitfield_extract( 28, 1,object)
+#define Equalbit(object) Bitfield_extract( 29, 1,object)
+#define Unorderedbit(object) Bitfield_extract( 30, 1,object)
+#define Exceptionbit(object) Bitfield_extract( 31, 1,object)
+
+/* An alias name for the status register */
+#define Fpustatus_register (*status)
+
+/**************************************************
+ * Status register referencing and manipulation. *
+ **************************************************/
+
+/* Rounding mode */
+#define Rounding_mode() Roundingmode(Fpustatus_register)
+#define Is_rounding_mode(rmode) \
+ (Roundingmode(Fpustatus_register) == rmode)
+#define Set_rounding_mode(value) \
+ Bitfield_deposit(value,21,2,Fpustatus_register)
+
+/* Boolean testing of the trap enable bits */
+#define Is_invalidtrap_enabled() Invalidtrap(Fpustatus_register)
+#define Is_divisionbyzerotrap_enabled() Divisionbyzerotrap(Fpustatus_register)
+#define Is_overflowtrap_enabled() Overflowtrap(Fpustatus_register)
+#define Is_underflowtrap_enabled() Underflowtrap(Fpustatus_register)
+#define Is_inexacttrap_enabled() Inexacttrap(Fpustatus_register)
+
+/* Set the indicated flags in the status register */
+#define Set_invalidflag() Bitfield_deposit(1,0,1,Fpustatus_register)
+#define Set_divisionbyzeroflag() Bitfield_deposit(1,1,1,Fpustatus_register)
+#define Set_overflowflag() Bitfield_deposit(1,2,1,Fpustatus_register)
+#define Set_underflowflag() Bitfield_deposit(1,3,1,Fpustatus_register)
+#define Set_inexactflag() Bitfield_deposit(1,4,1,Fpustatus_register)
+
+#define Clear_all_flags() Bitfield_deposit(0,0,5,Fpustatus_register)
+
+/* Manipulate the trap and condition code bits (tbit and cbit) */
+#define Set_tbit() Bitfield_deposit(1,25,1,Fpustatus_register)
+#define Clear_tbit() Bitfield_deposit(0,25,1,Fpustatus_register)
+#define Is_tbit_set() Tbit(Fpustatus_register)
+#define Is_cbit_set() Cbit(Fpustatus_register)
+
+#define Set_status_cbit(value) \
+ Bitfield_deposit(value,5,1,Fpustatus_register)
+
+/*******************************
+ * Condition field referencing *
+ *******************************/
+#define Unordered(cond) Unorderedbit(cond)
+#define Equal(cond) Equalbit(cond)
+#define Lessthan(cond) Lessthanbit(cond)
+#define Greaterthan(cond) Greaterthanbit(cond)
+#define Exception(cond) Exceptionbit(cond)
+
+
+/* Defines for the extension */
+#define Ext_isone_sign(extent) (Extsign(extent))
+#define Ext_isnotzero(extent) \
+ (Extall(extent))
+#define Ext_isnotzero_lower(extent) \
+ (Extlow31(extent))
+#define Ext_leftshiftby1(extent) \
+ Extall(extent) <<= 1
+#define Ext_negate(extent) \
+ (int )Extall(extent) = 0 - (int )Extall(extent)
+#define Ext_setone_low(extent) Bitfield_deposit(1,31,1,extent)
+#define Ext_setzero(extent) Extall(extent) = 0
+
+typedef int operation;
+
+/* error messages */
+
+#define NONE 0
+#define UNDEFFPINST 1
+
+/* Function definitions: opcode, opclass */
+#define FTEST (1<<2) | 0
+#define FCPY (2<<2) | 0
+#define FABS (3<<2) | 0
+#define FSQRT (4<<2) | 0
+#define FRND (5<<2) | 0
+
+#define FCNVFF (0<<2) | 1
+#define FCNVXF (1<<2) | 1
+#define FCNVFX (2<<2) | 1
+#define FCNVFXT (3<<2) | 1
+
+#define FCMP (0<<2) | 2
+
+#define FADD (0<<2) | 3
+#define FSUB (1<<2) | 3
+#define FMPY (2<<2) | 3
+#define FDIV (3<<2) | 3
+#define FREM (4<<2) | 3
+
diff --git a/arch/parisc/math-emu/fmpyfadd.c b/arch/parisc/math-emu/fmpyfadd.c
new file mode 100644
index 000000000..029f9bbfe
--- /dev/null
+++ b/arch/parisc/math-emu/fmpyfadd.c
@@ -0,0 +1,2642 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ */
+/*
+ * BEGIN_DESC
+ *
+ * File:
+ * @(#) pa/spmath/fmpyfadd.c $Revision: 1.1 $
+ *
+ * Purpose:
+ * Double Floating-point Multiply Fused Add
+ * Double Floating-point Multiply Negate Fused Add
+ * Single Floating-point Multiply Fused Add
+ * Single Floating-point Multiply Negate Fused Add
+ *
+ * External Interfaces:
+ * dbl_fmpyfadd(src1ptr,src2ptr,src3ptr,status,dstptr)
+ * dbl_fmpynfadd(src1ptr,src2ptr,src3ptr,status,dstptr)
+ * sgl_fmpyfadd(src1ptr,src2ptr,src3ptr,status,dstptr)
+ * sgl_fmpynfadd(src1ptr,src2ptr,src3ptr,status,dstptr)
+ *
+ * Internal Interfaces:
+ *
+ * Theory:
+ * <<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+#include "dbl_float.h"
+
+
+/*
+ * Double Floating-point Multiply Fused Add
+ */
+
+int
+dbl_fmpyfadd(
+ dbl_floating_point *src1ptr,
+ dbl_floating_point *src2ptr,
+ dbl_floating_point *src3ptr,
+ unsigned int *status,
+ dbl_floating_point *dstptr)
+{
+ unsigned int opnd1p1, opnd1p2, opnd2p1, opnd2p2, opnd3p1, opnd3p2;
+ register unsigned int tmpresp1, tmpresp2, tmpresp3, tmpresp4;
+ unsigned int rightp1, rightp2, rightp3, rightp4;
+ unsigned int resultp1, resultp2 = 0, resultp3 = 0, resultp4 = 0;
+ register int mpy_exponent, add_exponent, count;
+ boolean inexact = FALSE, is_tiny = FALSE;
+
+ unsigned int signlessleft1, signlessright1, save;
+ register int result_exponent, diff_exponent;
+ int sign_save, jumpsize;
+
+ Dbl_copyfromptr(src1ptr,opnd1p1,opnd1p2);
+ Dbl_copyfromptr(src2ptr,opnd2p1,opnd2p2);
+ Dbl_copyfromptr(src3ptr,opnd3p1,opnd3p2);
+
+ /*
+ * set sign bit of result of multiply
+ */
+ if (Dbl_sign(opnd1p1) ^ Dbl_sign(opnd2p1))
+ Dbl_setnegativezerop1(resultp1);
+ else Dbl_setzerop1(resultp1);
+
+ /*
+ * Generate multiply exponent
+ */
+ mpy_exponent = Dbl_exponent(opnd1p1) + Dbl_exponent(opnd2p1) - DBL_BIAS;
+
+ /*
+ * check first operand for NaN's or infinity
+ */
+ if (Dbl_isinfinity_exponent(opnd1p1)) {
+ if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
+ if (Dbl_isnotnan(opnd2p1,opnd2p2) &&
+ Dbl_isnotnan(opnd3p1,opnd3p2)) {
+ if (Dbl_iszero_exponentmantissa(opnd2p1,opnd2p2)) {
+ /*
+ * invalid since operands are infinity
+ * and zero
+ */
+ if (Is_invalidtrap_enabled())
+ return(OPC_2E_INVALIDEXCEPTION);
+ Set_invalidflag();
+ Dbl_makequietnan(resultp1,resultp2);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /*
+ * Check third operand for infinity with a
+ * sign opposite of the multiply result
+ */
+ if (Dbl_isinfinity(opnd3p1,opnd3p2) &&
+ (Dbl_sign(resultp1) ^ Dbl_sign(opnd3p1))) {
+ /*
+ * invalid since attempting a magnitude
+ * subtraction of infinities
+ */
+ if (Is_invalidtrap_enabled())
+ return(OPC_2E_INVALIDEXCEPTION);
+ Set_invalidflag();
+ Dbl_makequietnan(resultp1,resultp2);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+
+ /*
+ * return infinity
+ */
+ Dbl_setinfinity_exponentmantissa(resultp1,resultp2);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ }
+ else {
+ /*
+ * is NaN; signaling or quiet?
+ */
+ if (Dbl_isone_signaling(opnd1p1)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled())
+ return(OPC_2E_INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Dbl_set_quiet(opnd1p1);
+ }
+ /*
+ * is second operand a signaling NaN?
+ */
+ else if (Dbl_is_signalingnan(opnd2p1)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled())
+ return(OPC_2E_INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Dbl_set_quiet(opnd2p1);
+ Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /*
+ * is third operand a signaling NaN?
+ */
+ else if (Dbl_is_signalingnan(opnd3p1)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled())
+ return(OPC_2E_INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Dbl_set_quiet(opnd3p1);
+ Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /*
+ * return quiet NaN
+ */
+ Dbl_copytoptr(opnd1p1,opnd1p2,dstptr);
+ return(NOEXCEPTION);
+ }
+ }
+
+ /*
+ * check second operand for NaN's or infinity
+ */
+ if (Dbl_isinfinity_exponent(opnd2p1)) {
+ if (Dbl_iszero_mantissa(opnd2p1,opnd2p2)) {
+ if (Dbl_isnotnan(opnd3p1,opnd3p2)) {
+ if (Dbl_iszero_exponentmantissa(opnd1p1,opnd1p2)) {
+ /*
+ * invalid since multiply operands are
+ * zero & infinity
+ */
+ if (Is_invalidtrap_enabled())
+ return(OPC_2E_INVALIDEXCEPTION);
+ Set_invalidflag();
+ Dbl_makequietnan(opnd2p1,opnd2p2);
+ Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
+ return(NOEXCEPTION);
+ }
+
+ /*
+ * Check third operand for infinity with a
+ * sign opposite of the multiply result
+ */
+ if (Dbl_isinfinity(opnd3p1,opnd3p2) &&
+ (Dbl_sign(resultp1) ^ Dbl_sign(opnd3p1))) {
+ /*
+ * invalid since attempting a magnitude
+ * subtraction of infinities
+ */
+ if (Is_invalidtrap_enabled())
+ return(OPC_2E_INVALIDEXCEPTION);
+ Set_invalidflag();
+ Dbl_makequietnan(resultp1,resultp2);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+
+ /*
+ * return infinity
+ */
+ Dbl_setinfinity_exponentmantissa(resultp1,resultp2);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ }
+ else {
+ /*
+ * is NaN; signaling or quiet?
+ */
+ if (Dbl_isone_signaling(opnd2p1)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled())
+ return(OPC_2E_INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Dbl_set_quiet(opnd2p1);
+ }
+ /*
+ * is third operand a signaling NaN?
+ */
+ else if (Dbl_is_signalingnan(opnd3p1)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled())
+ return(OPC_2E_INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Dbl_set_quiet(opnd3p1);
+ Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /*
+ * return quiet NaN
+ */
+ Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
+ return(NOEXCEPTION);
+ }
+ }
+
+ /*
+ * check third operand for NaN's or infinity
+ */
+ if (Dbl_isinfinity_exponent(opnd3p1)) {
+ if (Dbl_iszero_mantissa(opnd3p1,opnd3p2)) {
+ /* return infinity */
+ Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+ return(NOEXCEPTION);
+ } else {
+ /*
+ * is NaN; signaling or quiet?
+ */
+ if (Dbl_isone_signaling(opnd3p1)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled())
+ return(OPC_2E_INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Dbl_set_quiet(opnd3p1);
+ }
+ /*
+ * return quiet NaN
+ */
+ Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+ return(NOEXCEPTION);
+ }
+ }
+
+ /*
+ * Generate multiply mantissa
+ */
+ if (Dbl_isnotzero_exponent(opnd1p1)) {
+ /* set hidden bit */
+ Dbl_clear_signexponent_set_hidden(opnd1p1);
+ }
+ else {
+ /* check for zero */
+ if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
+ /*
+ * Perform the add opnd3 with zero here.
+ */
+ if (Dbl_iszero_exponentmantissa(opnd3p1,opnd3p2)) {
+ if (Is_rounding_mode(ROUNDMINUS)) {
+ Dbl_or_signs(opnd3p1,resultp1);
+ } else {
+ Dbl_and_signs(opnd3p1,resultp1);
+ }
+ }
+ /*
+ * Now let's check for trapped underflow case.
+ */
+ else if (Dbl_iszero_exponent(opnd3p1) &&
+ Is_underflowtrap_enabled()) {
+ /* need to normalize results mantissa */
+ sign_save = Dbl_signextendedsign(opnd3p1);
+ result_exponent = 0;
+ Dbl_leftshiftby1(opnd3p1,opnd3p2);
+ Dbl_normalize(opnd3p1,opnd3p2,result_exponent);
+ Dbl_set_sign(opnd3p1,/*using*/sign_save);
+ Dbl_setwrapped_exponent(opnd3p1,result_exponent,
+ unfl);
+ Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+ /* inexact = FALSE */
+ return(OPC_2E_UNDERFLOWEXCEPTION);
+ }
+ Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /* is denormalized, adjust exponent */
+ Dbl_clear_signexponent(opnd1p1);
+ Dbl_leftshiftby1(opnd1p1,opnd1p2);
+ Dbl_normalize(opnd1p1,opnd1p2,mpy_exponent);
+ }
+ /* opnd2 needs to have hidden bit set with msb in hidden bit */
+ if (Dbl_isnotzero_exponent(opnd2p1)) {
+ Dbl_clear_signexponent_set_hidden(opnd2p1);
+ }
+ else {
+ /* check for zero */
+ if (Dbl_iszero_mantissa(opnd2p1,opnd2p2)) {
+ /*
+ * Perform the add opnd3 with zero here.
+ */
+ if (Dbl_iszero_exponentmantissa(opnd3p1,opnd3p2)) {
+ if (Is_rounding_mode(ROUNDMINUS)) {
+ Dbl_or_signs(opnd3p1,resultp1);
+ } else {
+ Dbl_and_signs(opnd3p1,resultp1);
+ }
+ }
+ /*
+ * Now let's check for trapped underflow case.
+ */
+ else if (Dbl_iszero_exponent(opnd3p1) &&
+ Is_underflowtrap_enabled()) {
+ /* need to normalize results mantissa */
+ sign_save = Dbl_signextendedsign(opnd3p1);
+ result_exponent = 0;
+ Dbl_leftshiftby1(opnd3p1,opnd3p2);
+ Dbl_normalize(opnd3p1,opnd3p2,result_exponent);
+ Dbl_set_sign(opnd3p1,/*using*/sign_save);
+ Dbl_setwrapped_exponent(opnd3p1,result_exponent,
+ unfl);
+ Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+ /* inexact = FALSE */
+ return(OPC_2E_UNDERFLOWEXCEPTION);
+ }
+ Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /* is denormalized; want to normalize */
+ Dbl_clear_signexponent(opnd2p1);
+ Dbl_leftshiftby1(opnd2p1,opnd2p2);
+ Dbl_normalize(opnd2p1,opnd2p2,mpy_exponent);
+ }
+
+ /* Multiply the first two source mantissas together */
+
+ /*
+ * The intermediate result will be kept in tmpres,
+ * which needs enough room for 106 bits of mantissa,
+ * so lets call it a Double extended.
+ */
+ Dblext_setzero(tmpresp1,tmpresp2,tmpresp3,tmpresp4);
+
+ /*
+ * Four bits at a time are inspected in each loop, and a
+ * simple shift and add multiply algorithm is used.
+ */
+ for (count = DBL_P-1; count >= 0; count -= 4) {
+ Dblext_rightshiftby4(tmpresp1,tmpresp2,tmpresp3,tmpresp4);
+ if (Dbit28p2(opnd1p2)) {
+ /* Fourword_add should be an ADD followed by 3 ADDC's */
+ Fourword_add(tmpresp1, tmpresp2, tmpresp3, tmpresp4,
+ opnd2p1<<3 | opnd2p2>>29, opnd2p2<<3, 0, 0);
+ }
+ if (Dbit29p2(opnd1p2)) {
+ Fourword_add(tmpresp1, tmpresp2, tmpresp3, tmpresp4,
+ opnd2p1<<2 | opnd2p2>>30, opnd2p2<<2, 0, 0);
+ }
+ if (Dbit30p2(opnd1p2)) {
+ Fourword_add(tmpresp1, tmpresp2, tmpresp3, tmpresp4,
+ opnd2p1<<1 | opnd2p2>>31, opnd2p2<<1, 0, 0);
+ }
+ if (Dbit31p2(opnd1p2)) {
+ Fourword_add(tmpresp1, tmpresp2, tmpresp3, tmpresp4,
+ opnd2p1, opnd2p2, 0, 0);
+ }
+ Dbl_rightshiftby4(opnd1p1,opnd1p2);
+ }
+ if (Is_dexthiddenoverflow(tmpresp1)) {
+ /* result mantissa >= 2 (mantissa overflow) */
+ mpy_exponent++;
+ Dblext_rightshiftby1(tmpresp1,tmpresp2,tmpresp3,tmpresp4);
+ }
+
+ /*
+ * Restore the sign of the mpy result which was saved in resultp1.
+ * The exponent will continue to be kept in mpy_exponent.
+ */
+ Dblext_set_sign(tmpresp1,Dbl_sign(resultp1));
+
+ /*
+ * No rounding is required, since the result of the multiply
+ * is exact in the extended format.
+ */
+
+ /*
+ * Now we are ready to perform the add portion of the operation.
+ *
+ * The exponents need to be kept as integers for now, since the
+ * multiply result might not fit into the exponent field. We
+ * can't overflow or underflow because of this yet, since the
+ * add could bring the final result back into range.
+ */
+ add_exponent = Dbl_exponent(opnd3p1);
+
+ /*
+ * Check for denormalized or zero add operand.
+ */
+ if (add_exponent == 0) {
+ /* check for zero */
+ if (Dbl_iszero_mantissa(opnd3p1,opnd3p2)) {
+ /* right is zero */
+ /* Left can't be zero and must be result.
+ *
+ * The final result is now in tmpres and mpy_exponent,
+ * and needs to be rounded and squeezed back into
+ * double precision format from double extended.
+ */
+ result_exponent = mpy_exponent;
+ Dblext_copy(tmpresp1,tmpresp2,tmpresp3,tmpresp4,
+ resultp1,resultp2,resultp3,resultp4);
+ sign_save = Dbl_signextendedsign(resultp1);/*save sign*/
+ goto round;
+ }
+
+ /*
+ * Neither are zeroes.
+ * Adjust exponent and normalize add operand.
+ */
+ sign_save = Dbl_signextendedsign(opnd3p1); /* save sign */
+ Dbl_clear_signexponent(opnd3p1);
+ Dbl_leftshiftby1(opnd3p1,opnd3p2);
+ Dbl_normalize(opnd3p1,opnd3p2,add_exponent);
+ Dbl_set_sign(opnd3p1,sign_save); /* restore sign */
+ } else {
+ Dbl_clear_exponent_set_hidden(opnd3p1);
+ }
+ /*
+ * Copy opnd3 to the double extended variable called right.
+ */
+ Dbl_copyto_dblext(opnd3p1,opnd3p2,rightp1,rightp2,rightp3,rightp4);
+
+ /*
+ * A zero "save" helps discover equal operands (for later),
+ * and is used in swapping operands (if needed).
+ */
+ Dblext_xortointp1(tmpresp1,rightp1,/*to*/save);
+
+ /*
+ * Compare magnitude of operands.
+ */
+ Dblext_copytoint_exponentmantissap1(tmpresp1,signlessleft1);
+ Dblext_copytoint_exponentmantissap1(rightp1,signlessright1);
+ if (mpy_exponent < add_exponent || mpy_exponent == add_exponent &&
+ Dblext_ismagnitudeless(tmpresp2,rightp2,signlessleft1,signlessright1)){
+ /*
+ * Set the left operand to the larger one by XOR swap.
+ * First finish the first word "save".
+ */
+ Dblext_xorfromintp1(save,rightp1,/*to*/rightp1);
+ Dblext_xorfromintp1(save,tmpresp1,/*to*/tmpresp1);
+ Dblext_swap_lower(tmpresp2,tmpresp3,tmpresp4,
+ rightp2,rightp3,rightp4);
+ /* also setup exponents used in rest of routine */
+ diff_exponent = add_exponent - mpy_exponent;
+ result_exponent = add_exponent;
+ } else {
+ /* also setup exponents used in rest of routine */
+ diff_exponent = mpy_exponent - add_exponent;
+ result_exponent = mpy_exponent;
+ }
+ /* Invariant: left is not smaller than right. */
+
+ /*
+ * Special case alignment of operands that would force alignment
+ * beyond the extent of the extension. A further optimization
+ * could special case this but only reduces the path length for
+ * this infrequent case.
+ */
+ if (diff_exponent > DBLEXT_THRESHOLD) {
+ diff_exponent = DBLEXT_THRESHOLD;
+ }
+
+ /* Align right operand by shifting it to the right */
+ Dblext_clear_sign(rightp1);
+ Dblext_right_align(rightp1,rightp2,rightp3,rightp4,
+ /*shifted by*/diff_exponent);
+
+ /* Treat sum and difference of the operands separately. */
+ if ((int)save < 0) {
+ /*
+ * Difference of the two operands. Overflow can occur if the
+ * multiply overflowed. A borrow can occur out of the hidden
+ * bit and force a post normalization phase.
+ */
+ Dblext_subtract(tmpresp1,tmpresp2,tmpresp3,tmpresp4,
+ rightp1,rightp2,rightp3,rightp4,
+ resultp1,resultp2,resultp3,resultp4);
+ sign_save = Dbl_signextendedsign(resultp1);
+ if (Dbl_iszero_hidden(resultp1)) {
+ /* Handle normalization */
+ /* A straightforward algorithm would now shift the
+ * result and extension left until the hidden bit
+ * becomes one. Not all of the extension bits need
+ * participate in the shift. Only the two most
+ * significant bits (round and guard) are needed.
+ * If only a single shift is needed then the guard
+ * bit becomes a significant low order bit and the
+ * extension must participate in the rounding.
+ * If more than a single shift is needed, then all
+ * bits to the right of the guard bit are zeros,
+ * and the guard bit may or may not be zero. */
+ Dblext_leftshiftby1(resultp1,resultp2,resultp3,
+ resultp4);
+
+ /* Need to check for a zero result. The sign and
+ * exponent fields have already been zeroed. The more
+ * efficient test of the full object can be used.
+ */
+ if(Dblext_iszero(resultp1,resultp2,resultp3,resultp4)){
+ /* Must have been "x-x" or "x+(-x)". */
+ if (Is_rounding_mode(ROUNDMINUS))
+ Dbl_setone_sign(resultp1);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ result_exponent--;
+
+ /* Look to see if normalization is finished. */
+ if (Dbl_isone_hidden(resultp1)) {
+ /* No further normalization is needed */
+ goto round;
+ }
+
+ /* Discover first one bit to determine shift amount.
+ * Use a modified binary search. We have already
+ * shifted the result one position right and still
+ * not found a one so the remainder of the extension
+ * must be zero and simplifies rounding. */
+ /* Scan bytes */
+ while (Dbl_iszero_hiddenhigh7mantissa(resultp1)) {
+ Dblext_leftshiftby8(resultp1,resultp2,resultp3,resultp4);
+ result_exponent -= 8;
+ }
+ /* Now narrow it down to the nibble */
+ if (Dbl_iszero_hiddenhigh3mantissa(resultp1)) {
+ /* The lower nibble contains the
+ * normalizing one */
+ Dblext_leftshiftby4(resultp1,resultp2,resultp3,resultp4);
+ result_exponent -= 4;
+ }
+ /* Select case where first bit is set (already
+ * normalized) otherwise select the proper shift. */
+ jumpsize = Dbl_hiddenhigh3mantissa(resultp1);
+ if (jumpsize <= 7) switch(jumpsize) {
+ case 1:
+ Dblext_leftshiftby3(resultp1,resultp2,resultp3,
+ resultp4);
+ result_exponent -= 3;
+ break;
+ case 2:
+ case 3:
+ Dblext_leftshiftby2(resultp1,resultp2,resultp3,
+ resultp4);
+ result_exponent -= 2;
+ break;
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ Dblext_leftshiftby1(resultp1,resultp2,resultp3,
+ resultp4);
+ result_exponent -= 1;
+ break;
+ }
+ } /* end if (hidden...)... */
+ /* Fall through and round */
+ } /* end if (save < 0)... */
+ else {
+ /* Add magnitudes */
+ Dblext_addition(tmpresp1,tmpresp2,tmpresp3,tmpresp4,
+ rightp1,rightp2,rightp3,rightp4,
+ /*to*/resultp1,resultp2,resultp3,resultp4);
+ sign_save = Dbl_signextendedsign(resultp1);
+ if (Dbl_isone_hiddenoverflow(resultp1)) {
+ /* Prenormalization required. */
+ Dblext_arithrightshiftby1(resultp1,resultp2,resultp3,
+ resultp4);
+ result_exponent++;
+ } /* end if hiddenoverflow... */
+ } /* end else ...add magnitudes... */
+
+ /* Round the result. If the extension and lower two words are
+ * all zeros, then the result is exact. Otherwise round in the
+ * correct direction. Underflow is possible. If a postnormalization
+ * is necessary, then the mantissa is all zeros so no shift is needed.
+ */
+ round:
+ if (result_exponent <= 0 && !Is_underflowtrap_enabled()) {
+ Dblext_denormalize(resultp1,resultp2,resultp3,resultp4,
+ result_exponent,is_tiny);
+ }
+ Dbl_set_sign(resultp1,/*using*/sign_save);
+ if (Dblext_isnotzero_mantissap3(resultp3) ||
+ Dblext_isnotzero_mantissap4(resultp4)) {
+ inexact = TRUE;
+ switch(Rounding_mode()) {
+ case ROUNDNEAREST: /* The default. */
+ if (Dblext_isone_highp3(resultp3)) {
+ /* at least 1/2 ulp */
+ if (Dblext_isnotzero_low31p3(resultp3) ||
+ Dblext_isnotzero_mantissap4(resultp4) ||
+ Dblext_isone_lowp2(resultp2)) {
+ /* either exactly half way and odd or
+ * more than 1/2ulp */
+ Dbl_increment(resultp1,resultp2);
+ }
+ }
+ break;
+
+ case ROUNDPLUS:
+ if (Dbl_iszero_sign(resultp1)) {
+ /* Round up positive results */
+ Dbl_increment(resultp1,resultp2);
+ }
+ break;
+
+ case ROUNDMINUS:
+ if (Dbl_isone_sign(resultp1)) {
+ /* Round down negative results */
+ Dbl_increment(resultp1,resultp2);
+ }
+
+ case ROUNDZERO:;
+ /* truncate is simple */
+ } /* end switch... */
+ if (Dbl_isone_hiddenoverflow(resultp1)) result_exponent++;
+ }
+ if (result_exponent >= DBL_INFINITY_EXPONENT) {
+ /* trap if OVERFLOWTRAP enabled */
+ if (Is_overflowtrap_enabled()) {
+ /*
+ * Adjust bias of result
+ */
+ Dbl_setwrapped_exponent(resultp1,result_exponent,ovfl);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ if (inexact)
+ if (Is_inexacttrap_enabled())
+ return (OPC_2E_OVERFLOWEXCEPTION |
+ OPC_2E_INEXACTEXCEPTION);
+ else Set_inexactflag();
+ return (OPC_2E_OVERFLOWEXCEPTION);
+ }
+ inexact = TRUE;
+ Set_overflowflag();
+ /* set result to infinity or largest number */
+ Dbl_setoverflow(resultp1,resultp2);
+
+ } else if (result_exponent <= 0) { /* underflow case */
+ if (Is_underflowtrap_enabled()) {
+ /*
+ * Adjust bias of result
+ */
+ Dbl_setwrapped_exponent(resultp1,result_exponent,unfl);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ if (inexact)
+ if (Is_inexacttrap_enabled())
+ return (OPC_2E_UNDERFLOWEXCEPTION |
+ OPC_2E_INEXACTEXCEPTION);
+ else Set_inexactflag();
+ return(OPC_2E_UNDERFLOWEXCEPTION);
+ }
+ else if (inexact && is_tiny) Set_underflowflag();
+ }
+ else Dbl_set_exponent(resultp1,result_exponent);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ if (inexact)
+ if (Is_inexacttrap_enabled()) return(OPC_2E_INEXACTEXCEPTION);
+ else Set_inexactflag();
+ return(NOEXCEPTION);
+}
+
+/*
+ * Double Floating-point Multiply Negate Fused Add
+ */
+
+dbl_fmpynfadd(src1ptr,src2ptr,src3ptr,status,dstptr)
+
+dbl_floating_point *src1ptr, *src2ptr, *src3ptr, *dstptr;
+unsigned int *status;
+{
+ unsigned int opnd1p1, opnd1p2, opnd2p1, opnd2p2, opnd3p1, opnd3p2;
+ register unsigned int tmpresp1, tmpresp2, tmpresp3, tmpresp4;
+ unsigned int rightp1, rightp2, rightp3, rightp4;
+ unsigned int resultp1, resultp2 = 0, resultp3 = 0, resultp4 = 0;
+ register int mpy_exponent, add_exponent, count;
+ boolean inexact = FALSE, is_tiny = FALSE;
+
+ unsigned int signlessleft1, signlessright1, save;
+ register int result_exponent, diff_exponent;
+ int sign_save, jumpsize;
+
+ Dbl_copyfromptr(src1ptr,opnd1p1,opnd1p2);
+ Dbl_copyfromptr(src2ptr,opnd2p1,opnd2p2);
+ Dbl_copyfromptr(src3ptr,opnd3p1,opnd3p2);
+
+ /*
+ * set sign bit of result of multiply
+ */
+ if (Dbl_sign(opnd1p1) ^ Dbl_sign(opnd2p1))
+ Dbl_setzerop1(resultp1);
+ else
+ Dbl_setnegativezerop1(resultp1);
+
+ /*
+ * Generate multiply exponent
+ */
+ mpy_exponent = Dbl_exponent(opnd1p1) + Dbl_exponent(opnd2p1) - DBL_BIAS;
+
+ /*
+ * check first operand for NaN's or infinity
+ */
+ if (Dbl_isinfinity_exponent(opnd1p1)) {
+ if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
+ if (Dbl_isnotnan(opnd2p1,opnd2p2) &&
+ Dbl_isnotnan(opnd3p1,opnd3p2)) {
+ if (Dbl_iszero_exponentmantissa(opnd2p1,opnd2p2)) {
+ /*
+ * invalid since operands are infinity
+ * and zero
+ */
+ if (Is_invalidtrap_enabled())
+ return(OPC_2E_INVALIDEXCEPTION);
+ Set_invalidflag();
+ Dbl_makequietnan(resultp1,resultp2);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /*
+ * Check third operand for infinity with a
+ * sign opposite of the multiply result
+ */
+ if (Dbl_isinfinity(opnd3p1,opnd3p2) &&
+ (Dbl_sign(resultp1) ^ Dbl_sign(opnd3p1))) {
+ /*
+ * invalid since attempting a magnitude
+ * subtraction of infinities
+ */
+ if (Is_invalidtrap_enabled())
+ return(OPC_2E_INVALIDEXCEPTION);
+ Set_invalidflag();
+ Dbl_makequietnan(resultp1,resultp2);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+
+ /*
+ * return infinity
+ */
+ Dbl_setinfinity_exponentmantissa(resultp1,resultp2);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ }
+ else {
+ /*
+ * is NaN; signaling or quiet?
+ */
+ if (Dbl_isone_signaling(opnd1p1)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled())
+ return(OPC_2E_INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Dbl_set_quiet(opnd1p1);
+ }
+ /*
+ * is second operand a signaling NaN?
+ */
+ else if (Dbl_is_signalingnan(opnd2p1)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled())
+ return(OPC_2E_INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Dbl_set_quiet(opnd2p1);
+ Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /*
+ * is third operand a signaling NaN?
+ */
+ else if (Dbl_is_signalingnan(opnd3p1)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled())
+ return(OPC_2E_INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Dbl_set_quiet(opnd3p1);
+ Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /*
+ * return quiet NaN
+ */
+ Dbl_copytoptr(opnd1p1,opnd1p2,dstptr);
+ return(NOEXCEPTION);
+ }
+ }
+
+ /*
+ * check second operand for NaN's or infinity
+ */
+ if (Dbl_isinfinity_exponent(opnd2p1)) {
+ if (Dbl_iszero_mantissa(opnd2p1,opnd2p2)) {
+ if (Dbl_isnotnan(opnd3p1,opnd3p2)) {
+ if (Dbl_iszero_exponentmantissa(opnd1p1,opnd1p2)) {
+ /*
+ * invalid since multiply operands are
+ * zero & infinity
+ */
+ if (Is_invalidtrap_enabled())
+ return(OPC_2E_INVALIDEXCEPTION);
+ Set_invalidflag();
+ Dbl_makequietnan(opnd2p1,opnd2p2);
+ Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
+ return(NOEXCEPTION);
+ }
+
+ /*
+ * Check third operand for infinity with a
+ * sign opposite of the multiply result
+ */
+ if (Dbl_isinfinity(opnd3p1,opnd3p2) &&
+ (Dbl_sign(resultp1) ^ Dbl_sign(opnd3p1))) {
+ /*
+ * invalid since attempting a magnitude
+ * subtraction of infinities
+ */
+ if (Is_invalidtrap_enabled())
+ return(OPC_2E_INVALIDEXCEPTION);
+ Set_invalidflag();
+ Dbl_makequietnan(resultp1,resultp2);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+
+ /*
+ * return infinity
+ */
+ Dbl_setinfinity_exponentmantissa(resultp1,resultp2);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ }
+ else {
+ /*
+ * is NaN; signaling or quiet?
+ */
+ if (Dbl_isone_signaling(opnd2p1)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled())
+ return(OPC_2E_INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Dbl_set_quiet(opnd2p1);
+ }
+ /*
+ * is third operand a signaling NaN?
+ */
+ else if (Dbl_is_signalingnan(opnd3p1)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled())
+ return(OPC_2E_INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Dbl_set_quiet(opnd3p1);
+ Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /*
+ * return quiet NaN
+ */
+ Dbl_copytoptr(opnd2p1,opnd2p2,dstptr);
+ return(NOEXCEPTION);
+ }
+ }
+
+ /*
+ * check third operand for NaN's or infinity
+ */
+ if (Dbl_isinfinity_exponent(opnd3p1)) {
+ if (Dbl_iszero_mantissa(opnd3p1,opnd3p2)) {
+ /* return infinity */
+ Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+ return(NOEXCEPTION);
+ } else {
+ /*
+ * is NaN; signaling or quiet?
+ */
+ if (Dbl_isone_signaling(opnd3p1)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled())
+ return(OPC_2E_INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Dbl_set_quiet(opnd3p1);
+ }
+ /*
+ * return quiet NaN
+ */
+ Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+ return(NOEXCEPTION);
+ }
+ }
+
+ /*
+ * Generate multiply mantissa
+ */
+ if (Dbl_isnotzero_exponent(opnd1p1)) {
+ /* set hidden bit */
+ Dbl_clear_signexponent_set_hidden(opnd1p1);
+ }
+ else {
+ /* check for zero */
+ if (Dbl_iszero_mantissa(opnd1p1,opnd1p2)) {
+ /*
+ * Perform the add opnd3 with zero here.
+ */
+ if (Dbl_iszero_exponentmantissa(opnd3p1,opnd3p2)) {
+ if (Is_rounding_mode(ROUNDMINUS)) {
+ Dbl_or_signs(opnd3p1,resultp1);
+ } else {
+ Dbl_and_signs(opnd3p1,resultp1);
+ }
+ }
+ /*
+ * Now let's check for trapped underflow case.
+ */
+ else if (Dbl_iszero_exponent(opnd3p1) &&
+ Is_underflowtrap_enabled()) {
+ /* need to normalize results mantissa */
+ sign_save = Dbl_signextendedsign(opnd3p1);
+ result_exponent = 0;
+ Dbl_leftshiftby1(opnd3p1,opnd3p2);
+ Dbl_normalize(opnd3p1,opnd3p2,result_exponent);
+ Dbl_set_sign(opnd3p1,/*using*/sign_save);
+ Dbl_setwrapped_exponent(opnd3p1,result_exponent,
+ unfl);
+ Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+ /* inexact = FALSE */
+ return(OPC_2E_UNDERFLOWEXCEPTION);
+ }
+ Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /* is denormalized, adjust exponent */
+ Dbl_clear_signexponent(opnd1p1);
+ Dbl_leftshiftby1(opnd1p1,opnd1p2);
+ Dbl_normalize(opnd1p1,opnd1p2,mpy_exponent);
+ }
+ /* opnd2 needs to have hidden bit set with msb in hidden bit */
+ if (Dbl_isnotzero_exponent(opnd2p1)) {
+ Dbl_clear_signexponent_set_hidden(opnd2p1);
+ }
+ else {
+ /* check for zero */
+ if (Dbl_iszero_mantissa(opnd2p1,opnd2p2)) {
+ /*
+ * Perform the add opnd3 with zero here.
+ */
+ if (Dbl_iszero_exponentmantissa(opnd3p1,opnd3p2)) {
+ if (Is_rounding_mode(ROUNDMINUS)) {
+ Dbl_or_signs(opnd3p1,resultp1);
+ } else {
+ Dbl_and_signs(opnd3p1,resultp1);
+ }
+ }
+ /*
+ * Now let's check for trapped underflow case.
+ */
+ else if (Dbl_iszero_exponent(opnd3p1) &&
+ Is_underflowtrap_enabled()) {
+ /* need to normalize results mantissa */
+ sign_save = Dbl_signextendedsign(opnd3p1);
+ result_exponent = 0;
+ Dbl_leftshiftby1(opnd3p1,opnd3p2);
+ Dbl_normalize(opnd3p1,opnd3p2,result_exponent);
+ Dbl_set_sign(opnd3p1,/*using*/sign_save);
+ Dbl_setwrapped_exponent(opnd3p1,result_exponent,
+ unfl);
+ Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+ /* inexact = FALSE */
+ return(OPC_2E_UNDERFLOWEXCEPTION);
+ }
+ Dbl_copytoptr(opnd3p1,opnd3p2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /* is denormalized; want to normalize */
+ Dbl_clear_signexponent(opnd2p1);
+ Dbl_leftshiftby1(opnd2p1,opnd2p2);
+ Dbl_normalize(opnd2p1,opnd2p2,mpy_exponent);
+ }
+
+ /* Multiply the first two source mantissas together */
+
+ /*
+ * The intermediate result will be kept in tmpres,
+ * which needs enough room for 106 bits of mantissa,
+ * so lets call it a Double extended.
+ */
+ Dblext_setzero(tmpresp1,tmpresp2,tmpresp3,tmpresp4);
+
+ /*
+ * Four bits at a time are inspected in each loop, and a
+ * simple shift and add multiply algorithm is used.
+ */
+ for (count = DBL_P-1; count >= 0; count -= 4) {
+ Dblext_rightshiftby4(tmpresp1,tmpresp2,tmpresp3,tmpresp4);
+ if (Dbit28p2(opnd1p2)) {
+ /* Fourword_add should be an ADD followed by 3 ADDC's */
+ Fourword_add(tmpresp1, tmpresp2, tmpresp3, tmpresp4,
+ opnd2p1<<3 | opnd2p2>>29, opnd2p2<<3, 0, 0);
+ }
+ if (Dbit29p2(opnd1p2)) {
+ Fourword_add(tmpresp1, tmpresp2, tmpresp3, tmpresp4,
+ opnd2p1<<2 | opnd2p2>>30, opnd2p2<<2, 0, 0);
+ }
+ if (Dbit30p2(opnd1p2)) {
+ Fourword_add(tmpresp1, tmpresp2, tmpresp3, tmpresp4,
+ opnd2p1<<1 | opnd2p2>>31, opnd2p2<<1, 0, 0);
+ }
+ if (Dbit31p2(opnd1p2)) {
+ Fourword_add(tmpresp1, tmpresp2, tmpresp3, tmpresp4,
+ opnd2p1, opnd2p2, 0, 0);
+ }
+ Dbl_rightshiftby4(opnd1p1,opnd1p2);
+ }
+ if (Is_dexthiddenoverflow(tmpresp1)) {
+ /* result mantissa >= 2 (mantissa overflow) */
+ mpy_exponent++;
+ Dblext_rightshiftby1(tmpresp1,tmpresp2,tmpresp3,tmpresp4);
+ }
+
+ /*
+ * Restore the sign of the mpy result which was saved in resultp1.
+ * The exponent will continue to be kept in mpy_exponent.
+ */
+ Dblext_set_sign(tmpresp1,Dbl_sign(resultp1));
+
+ /*
+ * No rounding is required, since the result of the multiply
+ * is exact in the extended format.
+ */
+
+ /*
+ * Now we are ready to perform the add portion of the operation.
+ *
+ * The exponents need to be kept as integers for now, since the
+ * multiply result might not fit into the exponent field. We
+ * can't overflow or underflow because of this yet, since the
+ * add could bring the final result back into range.
+ */
+ add_exponent = Dbl_exponent(opnd3p1);
+
+ /*
+ * Check for denormalized or zero add operand.
+ */
+ if (add_exponent == 0) {
+ /* check for zero */
+ if (Dbl_iszero_mantissa(opnd3p1,opnd3p2)) {
+ /* right is zero */
+ /* Left can't be zero and must be result.
+ *
+ * The final result is now in tmpres and mpy_exponent,
+ * and needs to be rounded and squeezed back into
+ * double precision format from double extended.
+ */
+ result_exponent = mpy_exponent;
+ Dblext_copy(tmpresp1,tmpresp2,tmpresp3,tmpresp4,
+ resultp1,resultp2,resultp3,resultp4);
+ sign_save = Dbl_signextendedsign(resultp1);/*save sign*/
+ goto round;
+ }
+
+ /*
+ * Neither are zeroes.
+ * Adjust exponent and normalize add operand.
+ */
+ sign_save = Dbl_signextendedsign(opnd3p1); /* save sign */
+ Dbl_clear_signexponent(opnd3p1);
+ Dbl_leftshiftby1(opnd3p1,opnd3p2);
+ Dbl_normalize(opnd3p1,opnd3p2,add_exponent);
+ Dbl_set_sign(opnd3p1,sign_save); /* restore sign */
+ } else {
+ Dbl_clear_exponent_set_hidden(opnd3p1);
+ }
+ /*
+ * Copy opnd3 to the double extended variable called right.
+ */
+ Dbl_copyto_dblext(opnd3p1,opnd3p2,rightp1,rightp2,rightp3,rightp4);
+
+ /*
+ * A zero "save" helps discover equal operands (for later),
+ * and is used in swapping operands (if needed).
+ */
+ Dblext_xortointp1(tmpresp1,rightp1,/*to*/save);
+
+ /*
+ * Compare magnitude of operands.
+ */
+ Dblext_copytoint_exponentmantissap1(tmpresp1,signlessleft1);
+ Dblext_copytoint_exponentmantissap1(rightp1,signlessright1);
+ if (mpy_exponent < add_exponent || mpy_exponent == add_exponent &&
+ Dblext_ismagnitudeless(tmpresp2,rightp2,signlessleft1,signlessright1)){
+ /*
+ * Set the left operand to the larger one by XOR swap.
+ * First finish the first word "save".
+ */
+ Dblext_xorfromintp1(save,rightp1,/*to*/rightp1);
+ Dblext_xorfromintp1(save,tmpresp1,/*to*/tmpresp1);
+ Dblext_swap_lower(tmpresp2,tmpresp3,tmpresp4,
+ rightp2,rightp3,rightp4);
+ /* also setup exponents used in rest of routine */
+ diff_exponent = add_exponent - mpy_exponent;
+ result_exponent = add_exponent;
+ } else {
+ /* also setup exponents used in rest of routine */
+ diff_exponent = mpy_exponent - add_exponent;
+ result_exponent = mpy_exponent;
+ }
+ /* Invariant: left is not smaller than right. */
+
+ /*
+ * Special case alignment of operands that would force alignment
+ * beyond the extent of the extension. A further optimization
+ * could special case this but only reduces the path length for
+ * this infrequent case.
+ */
+ if (diff_exponent > DBLEXT_THRESHOLD) {
+ diff_exponent = DBLEXT_THRESHOLD;
+ }
+
+ /* Align right operand by shifting it to the right */
+ Dblext_clear_sign(rightp1);
+ Dblext_right_align(rightp1,rightp2,rightp3,rightp4,
+ /*shifted by*/diff_exponent);
+
+ /* Treat sum and difference of the operands separately. */
+ if ((int)save < 0) {
+ /*
+ * Difference of the two operands. Overflow can occur if the
+ * multiply overflowed. A borrow can occur out of the hidden
+ * bit and force a post normalization phase.
+ */
+ Dblext_subtract(tmpresp1,tmpresp2,tmpresp3,tmpresp4,
+ rightp1,rightp2,rightp3,rightp4,
+ resultp1,resultp2,resultp3,resultp4);
+ sign_save = Dbl_signextendedsign(resultp1);
+ if (Dbl_iszero_hidden(resultp1)) {
+ /* Handle normalization */
+ /* A straightforward algorithm would now shift the
+ * result and extension left until the hidden bit
+ * becomes one. Not all of the extension bits need
+ * participate in the shift. Only the two most
+ * significant bits (round and guard) are needed.
+ * If only a single shift is needed then the guard
+ * bit becomes a significant low order bit and the
+ * extension must participate in the rounding.
+ * If more than a single shift is needed, then all
+ * bits to the right of the guard bit are zeros,
+ * and the guard bit may or may not be zero. */
+ Dblext_leftshiftby1(resultp1,resultp2,resultp3,
+ resultp4);
+
+ /* Need to check for a zero result. The sign and
+ * exponent fields have already been zeroed. The more
+ * efficient test of the full object can be used.
+ */
+ if (Dblext_iszero(resultp1,resultp2,resultp3,resultp4)) {
+ /* Must have been "x-x" or "x+(-x)". */
+ if (Is_rounding_mode(ROUNDMINUS))
+ Dbl_setone_sign(resultp1);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ result_exponent--;
+
+ /* Look to see if normalization is finished. */
+ if (Dbl_isone_hidden(resultp1)) {
+ /* No further normalization is needed */
+ goto round;
+ }
+
+ /* Discover first one bit to determine shift amount.
+ * Use a modified binary search. We have already
+ * shifted the result one position right and still
+ * not found a one so the remainder of the extension
+ * must be zero and simplifies rounding. */
+ /* Scan bytes */
+ while (Dbl_iszero_hiddenhigh7mantissa(resultp1)) {
+ Dblext_leftshiftby8(resultp1,resultp2,resultp3,resultp4);
+ result_exponent -= 8;
+ }
+ /* Now narrow it down to the nibble */
+ if (Dbl_iszero_hiddenhigh3mantissa(resultp1)) {
+ /* The lower nibble contains the
+ * normalizing one */
+ Dblext_leftshiftby4(resultp1,resultp2,resultp3,resultp4);
+ result_exponent -= 4;
+ }
+ /* Select case where first bit is set (already
+ * normalized) otherwise select the proper shift. */
+ jumpsize = Dbl_hiddenhigh3mantissa(resultp1);
+ if (jumpsize <= 7) switch(jumpsize) {
+ case 1:
+ Dblext_leftshiftby3(resultp1,resultp2,resultp3,
+ resultp4);
+ result_exponent -= 3;
+ break;
+ case 2:
+ case 3:
+ Dblext_leftshiftby2(resultp1,resultp2,resultp3,
+ resultp4);
+ result_exponent -= 2;
+ break;
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ Dblext_leftshiftby1(resultp1,resultp2,resultp3,
+ resultp4);
+ result_exponent -= 1;
+ break;
+ }
+ } /* end if (hidden...)... */
+ /* Fall through and round */
+ } /* end if (save < 0)... */
+ else {
+ /* Add magnitudes */
+ Dblext_addition(tmpresp1,tmpresp2,tmpresp3,tmpresp4,
+ rightp1,rightp2,rightp3,rightp4,
+ /*to*/resultp1,resultp2,resultp3,resultp4);
+ sign_save = Dbl_signextendedsign(resultp1);
+ if (Dbl_isone_hiddenoverflow(resultp1)) {
+ /* Prenormalization required. */
+ Dblext_arithrightshiftby1(resultp1,resultp2,resultp3,
+ resultp4);
+ result_exponent++;
+ } /* end if hiddenoverflow... */
+ } /* end else ...add magnitudes... */
+
+ /* Round the result. If the extension and lower two words are
+ * all zeros, then the result is exact. Otherwise round in the
+ * correct direction. Underflow is possible. If a postnormalization
+ * is necessary, then the mantissa is all zeros so no shift is needed.
+ */
+ round:
+ if (result_exponent <= 0 && !Is_underflowtrap_enabled()) {
+ Dblext_denormalize(resultp1,resultp2,resultp3,resultp4,
+ result_exponent,is_tiny);
+ }
+ Dbl_set_sign(resultp1,/*using*/sign_save);
+ if (Dblext_isnotzero_mantissap3(resultp3) ||
+ Dblext_isnotzero_mantissap4(resultp4)) {
+ inexact = TRUE;
+ switch(Rounding_mode()) {
+ case ROUNDNEAREST: /* The default. */
+ if (Dblext_isone_highp3(resultp3)) {
+ /* at least 1/2 ulp */
+ if (Dblext_isnotzero_low31p3(resultp3) ||
+ Dblext_isnotzero_mantissap4(resultp4) ||
+ Dblext_isone_lowp2(resultp2)) {
+ /* either exactly half way and odd or
+ * more than 1/2ulp */
+ Dbl_increment(resultp1,resultp2);
+ }
+ }
+ break;
+
+ case ROUNDPLUS:
+ if (Dbl_iszero_sign(resultp1)) {
+ /* Round up positive results */
+ Dbl_increment(resultp1,resultp2);
+ }
+ break;
+
+ case ROUNDMINUS:
+ if (Dbl_isone_sign(resultp1)) {
+ /* Round down negative results */
+ Dbl_increment(resultp1,resultp2);
+ }
+
+ case ROUNDZERO:;
+ /* truncate is simple */
+ } /* end switch... */
+ if (Dbl_isone_hiddenoverflow(resultp1)) result_exponent++;
+ }
+ if (result_exponent >= DBL_INFINITY_EXPONENT) {
+ /* Overflow */
+ if (Is_overflowtrap_enabled()) {
+ /*
+ * Adjust bias of result
+ */
+ Dbl_setwrapped_exponent(resultp1,result_exponent,ovfl);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ if (inexact)
+ if (Is_inexacttrap_enabled())
+ return (OPC_2E_OVERFLOWEXCEPTION |
+ OPC_2E_INEXACTEXCEPTION);
+ else Set_inexactflag();
+ return (OPC_2E_OVERFLOWEXCEPTION);
+ }
+ inexact = TRUE;
+ Set_overflowflag();
+ Dbl_setoverflow(resultp1,resultp2);
+ } else if (result_exponent <= 0) { /* underflow case */
+ if (Is_underflowtrap_enabled()) {
+ /*
+ * Adjust bias of result
+ */
+ Dbl_setwrapped_exponent(resultp1,result_exponent,unfl);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ if (inexact)
+ if (Is_inexacttrap_enabled())
+ return (OPC_2E_UNDERFLOWEXCEPTION |
+ OPC_2E_INEXACTEXCEPTION);
+ else Set_inexactflag();
+ return(OPC_2E_UNDERFLOWEXCEPTION);
+ }
+ else if (inexact && is_tiny) Set_underflowflag();
+ }
+ else Dbl_set_exponent(resultp1,result_exponent);
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ if (inexact)
+ if (Is_inexacttrap_enabled()) return(OPC_2E_INEXACTEXCEPTION);
+ else Set_inexactflag();
+ return(NOEXCEPTION);
+}
+
+/*
+ * Single Floating-point Multiply Fused Add
+ */
+
+sgl_fmpyfadd(src1ptr,src2ptr,src3ptr,status,dstptr)
+
+sgl_floating_point *src1ptr, *src2ptr, *src3ptr, *dstptr;
+unsigned int *status;
+{
+ unsigned int opnd1, opnd2, opnd3;
+ register unsigned int tmpresp1, tmpresp2;
+ unsigned int rightp1, rightp2;
+ unsigned int resultp1, resultp2 = 0;
+ register int mpy_exponent, add_exponent, count;
+ boolean inexact = FALSE, is_tiny = FALSE;
+
+ unsigned int signlessleft1, signlessright1, save;
+ register int result_exponent, diff_exponent;
+ int sign_save, jumpsize;
+
+ Sgl_copyfromptr(src1ptr,opnd1);
+ Sgl_copyfromptr(src2ptr,opnd2);
+ Sgl_copyfromptr(src3ptr,opnd3);
+
+ /*
+ * set sign bit of result of multiply
+ */
+ if (Sgl_sign(opnd1) ^ Sgl_sign(opnd2))
+ Sgl_setnegativezero(resultp1);
+ else Sgl_setzero(resultp1);
+
+ /*
+ * Generate multiply exponent
+ */
+ mpy_exponent = Sgl_exponent(opnd1) + Sgl_exponent(opnd2) - SGL_BIAS;
+
+ /*
+ * check first operand for NaN's or infinity
+ */
+ if (Sgl_isinfinity_exponent(opnd1)) {
+ if (Sgl_iszero_mantissa(opnd1)) {
+ if (Sgl_isnotnan(opnd2) && Sgl_isnotnan(opnd3)) {
+ if (Sgl_iszero_exponentmantissa(opnd2)) {
+ /*
+ * invalid since operands are infinity
+ * and zero
+ */
+ if (Is_invalidtrap_enabled())
+ return(OPC_2E_INVALIDEXCEPTION);
+ Set_invalidflag();
+ Sgl_makequietnan(resultp1);
+ Sgl_copytoptr(resultp1,dstptr);
+ return(NOEXCEPTION);
+ }
+ /*
+ * Check third operand for infinity with a
+ * sign opposite of the multiply result
+ */
+ if (Sgl_isinfinity(opnd3) &&
+ (Sgl_sign(resultp1) ^ Sgl_sign(opnd3))) {
+ /*
+ * invalid since attempting a magnitude
+ * subtraction of infinities
+ */
+ if (Is_invalidtrap_enabled())
+ return(OPC_2E_INVALIDEXCEPTION);
+ Set_invalidflag();
+ Sgl_makequietnan(resultp1);
+ Sgl_copytoptr(resultp1,dstptr);
+ return(NOEXCEPTION);
+ }
+
+ /*
+ * return infinity
+ */
+ Sgl_setinfinity_exponentmantissa(resultp1);
+ Sgl_copytoptr(resultp1,dstptr);
+ return(NOEXCEPTION);
+ }
+ }
+ else {
+ /*
+ * is NaN; signaling or quiet?
+ */
+ if (Sgl_isone_signaling(opnd1)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled())
+ return(OPC_2E_INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Sgl_set_quiet(opnd1);
+ }
+ /*
+ * is second operand a signaling NaN?
+ */
+ else if (Sgl_is_signalingnan(opnd2)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled())
+ return(OPC_2E_INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Sgl_set_quiet(opnd2);
+ Sgl_copytoptr(opnd2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /*
+ * is third operand a signaling NaN?
+ */
+ else if (Sgl_is_signalingnan(opnd3)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled())
+ return(OPC_2E_INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Sgl_set_quiet(opnd3);
+ Sgl_copytoptr(opnd3,dstptr);
+ return(NOEXCEPTION);
+ }
+ /*
+ * return quiet NaN
+ */
+ Sgl_copytoptr(opnd1,dstptr);
+ return(NOEXCEPTION);
+ }
+ }
+
+ /*
+ * check second operand for NaN's or infinity
+ */
+ if (Sgl_isinfinity_exponent(opnd2)) {
+ if (Sgl_iszero_mantissa(opnd2)) {
+ if (Sgl_isnotnan(opnd3)) {
+ if (Sgl_iszero_exponentmantissa(opnd1)) {
+ /*
+ * invalid since multiply operands are
+ * zero & infinity
+ */
+ if (Is_invalidtrap_enabled())
+ return(OPC_2E_INVALIDEXCEPTION);
+ Set_invalidflag();
+ Sgl_makequietnan(opnd2);
+ Sgl_copytoptr(opnd2,dstptr);
+ return(NOEXCEPTION);
+ }
+
+ /*
+ * Check third operand for infinity with a
+ * sign opposite of the multiply result
+ */
+ if (Sgl_isinfinity(opnd3) &&
+ (Sgl_sign(resultp1) ^ Sgl_sign(opnd3))) {
+ /*
+ * invalid since attempting a magnitude
+ * subtraction of infinities
+ */
+ if (Is_invalidtrap_enabled())
+ return(OPC_2E_INVALIDEXCEPTION);
+ Set_invalidflag();
+ Sgl_makequietnan(resultp1);
+ Sgl_copytoptr(resultp1,dstptr);
+ return(NOEXCEPTION);
+ }
+
+ /*
+ * return infinity
+ */
+ Sgl_setinfinity_exponentmantissa(resultp1);
+ Sgl_copytoptr(resultp1,dstptr);
+ return(NOEXCEPTION);
+ }
+ }
+ else {
+ /*
+ * is NaN; signaling or quiet?
+ */
+ if (Sgl_isone_signaling(opnd2)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled())
+ return(OPC_2E_INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Sgl_set_quiet(opnd2);
+ }
+ /*
+ * is third operand a signaling NaN?
+ */
+ else if (Sgl_is_signalingnan(opnd3)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled())
+ return(OPC_2E_INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Sgl_set_quiet(opnd3);
+ Sgl_copytoptr(opnd3,dstptr);
+ return(NOEXCEPTION);
+ }
+ /*
+ * return quiet NaN
+ */
+ Sgl_copytoptr(opnd2,dstptr);
+ return(NOEXCEPTION);
+ }
+ }
+
+ /*
+ * check third operand for NaN's or infinity
+ */
+ if (Sgl_isinfinity_exponent(opnd3)) {
+ if (Sgl_iszero_mantissa(opnd3)) {
+ /* return infinity */
+ Sgl_copytoptr(opnd3,dstptr);
+ return(NOEXCEPTION);
+ } else {
+ /*
+ * is NaN; signaling or quiet?
+ */
+ if (Sgl_isone_signaling(opnd3)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled())
+ return(OPC_2E_INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Sgl_set_quiet(opnd3);
+ }
+ /*
+ * return quiet NaN
+ */
+ Sgl_copytoptr(opnd3,dstptr);
+ return(NOEXCEPTION);
+ }
+ }
+
+ /*
+ * Generate multiply mantissa
+ */
+ if (Sgl_isnotzero_exponent(opnd1)) {
+ /* set hidden bit */
+ Sgl_clear_signexponent_set_hidden(opnd1);
+ }
+ else {
+ /* check for zero */
+ if (Sgl_iszero_mantissa(opnd1)) {
+ /*
+ * Perform the add opnd3 with zero here.
+ */
+ if (Sgl_iszero_exponentmantissa(opnd3)) {
+ if (Is_rounding_mode(ROUNDMINUS)) {
+ Sgl_or_signs(opnd3,resultp1);
+ } else {
+ Sgl_and_signs(opnd3,resultp1);
+ }
+ }
+ /*
+ * Now let's check for trapped underflow case.
+ */
+ else if (Sgl_iszero_exponent(opnd3) &&
+ Is_underflowtrap_enabled()) {
+ /* need to normalize results mantissa */
+ sign_save = Sgl_signextendedsign(opnd3);
+ result_exponent = 0;
+ Sgl_leftshiftby1(opnd3);
+ Sgl_normalize(opnd3,result_exponent);
+ Sgl_set_sign(opnd3,/*using*/sign_save);
+ Sgl_setwrapped_exponent(opnd3,result_exponent,
+ unfl);
+ Sgl_copytoptr(opnd3,dstptr);
+ /* inexact = FALSE */
+ return(OPC_2E_UNDERFLOWEXCEPTION);
+ }
+ Sgl_copytoptr(opnd3,dstptr);
+ return(NOEXCEPTION);
+ }
+ /* is denormalized, adjust exponent */
+ Sgl_clear_signexponent(opnd1);
+ Sgl_leftshiftby1(opnd1);
+ Sgl_normalize(opnd1,mpy_exponent);
+ }
+ /* opnd2 needs to have hidden bit set with msb in hidden bit */
+ if (Sgl_isnotzero_exponent(opnd2)) {
+ Sgl_clear_signexponent_set_hidden(opnd2);
+ }
+ else {
+ /* check for zero */
+ if (Sgl_iszero_mantissa(opnd2)) {
+ /*
+ * Perform the add opnd3 with zero here.
+ */
+ if (Sgl_iszero_exponentmantissa(opnd3)) {
+ if (Is_rounding_mode(ROUNDMINUS)) {
+ Sgl_or_signs(opnd3,resultp1);
+ } else {
+ Sgl_and_signs(opnd3,resultp1);
+ }
+ }
+ /*
+ * Now let's check for trapped underflow case.
+ */
+ else if (Sgl_iszero_exponent(opnd3) &&
+ Is_underflowtrap_enabled()) {
+ /* need to normalize results mantissa */
+ sign_save = Sgl_signextendedsign(opnd3);
+ result_exponent = 0;
+ Sgl_leftshiftby1(opnd3);
+ Sgl_normalize(opnd3,result_exponent);
+ Sgl_set_sign(opnd3,/*using*/sign_save);
+ Sgl_setwrapped_exponent(opnd3,result_exponent,
+ unfl);
+ Sgl_copytoptr(opnd3,dstptr);
+ /* inexact = FALSE */
+ return(OPC_2E_UNDERFLOWEXCEPTION);
+ }
+ Sgl_copytoptr(opnd3,dstptr);
+ return(NOEXCEPTION);
+ }
+ /* is denormalized; want to normalize */
+ Sgl_clear_signexponent(opnd2);
+ Sgl_leftshiftby1(opnd2);
+ Sgl_normalize(opnd2,mpy_exponent);
+ }
+
+ /* Multiply the first two source mantissas together */
+
+ /*
+ * The intermediate result will be kept in tmpres,
+ * which needs enough room for 106 bits of mantissa,
+ * so lets call it a Double extended.
+ */
+ Sglext_setzero(tmpresp1,tmpresp2);
+
+ /*
+ * Four bits at a time are inspected in each loop, and a
+ * simple shift and add multiply algorithm is used.
+ */
+ for (count = SGL_P-1; count >= 0; count -= 4) {
+ Sglext_rightshiftby4(tmpresp1,tmpresp2);
+ if (Sbit28(opnd1)) {
+ /* Twoword_add should be an ADD followed by 2 ADDC's */
+ Twoword_add(tmpresp1, tmpresp2, opnd2<<3, 0);
+ }
+ if (Sbit29(opnd1)) {
+ Twoword_add(tmpresp1, tmpresp2, opnd2<<2, 0);
+ }
+ if (Sbit30(opnd1)) {
+ Twoword_add(tmpresp1, tmpresp2, opnd2<<1, 0);
+ }
+ if (Sbit31(opnd1)) {
+ Twoword_add(tmpresp1, tmpresp2, opnd2, 0);
+ }
+ Sgl_rightshiftby4(opnd1);
+ }
+ if (Is_sexthiddenoverflow(tmpresp1)) {
+ /* result mantissa >= 2 (mantissa overflow) */
+ mpy_exponent++;
+ Sglext_rightshiftby4(tmpresp1,tmpresp2);
+ } else {
+ Sglext_rightshiftby3(tmpresp1,tmpresp2);
+ }
+
+ /*
+ * Restore the sign of the mpy result which was saved in resultp1.
+ * The exponent will continue to be kept in mpy_exponent.
+ */
+ Sglext_set_sign(tmpresp1,Sgl_sign(resultp1));
+
+ /*
+ * No rounding is required, since the result of the multiply
+ * is exact in the extended format.
+ */
+
+ /*
+ * Now we are ready to perform the add portion of the operation.
+ *
+ * The exponents need to be kept as integers for now, since the
+ * multiply result might not fit into the exponent field. We
+ * can't overflow or underflow because of this yet, since the
+ * add could bring the final result back into range.
+ */
+ add_exponent = Sgl_exponent(opnd3);
+
+ /*
+ * Check for denormalized or zero add operand.
+ */
+ if (add_exponent == 0) {
+ /* check for zero */
+ if (Sgl_iszero_mantissa(opnd3)) {
+ /* right is zero */
+ /* Left can't be zero and must be result.
+ *
+ * The final result is now in tmpres and mpy_exponent,
+ * and needs to be rounded and squeezed back into
+ * double precision format from double extended.
+ */
+ result_exponent = mpy_exponent;
+ Sglext_copy(tmpresp1,tmpresp2,resultp1,resultp2);
+ sign_save = Sgl_signextendedsign(resultp1);/*save sign*/
+ goto round;
+ }
+
+ /*
+ * Neither are zeroes.
+ * Adjust exponent and normalize add operand.
+ */
+ sign_save = Sgl_signextendedsign(opnd3); /* save sign */
+ Sgl_clear_signexponent(opnd3);
+ Sgl_leftshiftby1(opnd3);
+ Sgl_normalize(opnd3,add_exponent);
+ Sgl_set_sign(opnd3,sign_save); /* restore sign */
+ } else {
+ Sgl_clear_exponent_set_hidden(opnd3);
+ }
+ /*
+ * Copy opnd3 to the double extended variable called right.
+ */
+ Sgl_copyto_sglext(opnd3,rightp1,rightp2);
+
+ /*
+ * A zero "save" helps discover equal operands (for later),
+ * and is used in swapping operands (if needed).
+ */
+ Sglext_xortointp1(tmpresp1,rightp1,/*to*/save);
+
+ /*
+ * Compare magnitude of operands.
+ */
+ Sglext_copytoint_exponentmantissa(tmpresp1,signlessleft1);
+ Sglext_copytoint_exponentmantissa(rightp1,signlessright1);
+ if (mpy_exponent < add_exponent || mpy_exponent == add_exponent &&
+ Sglext_ismagnitudeless(signlessleft1,signlessright1)) {
+ /*
+ * Set the left operand to the larger one by XOR swap.
+ * First finish the first word "save".
+ */
+ Sglext_xorfromintp1(save,rightp1,/*to*/rightp1);
+ Sglext_xorfromintp1(save,tmpresp1,/*to*/tmpresp1);
+ Sglext_swap_lower(tmpresp2,rightp2);
+ /* also setup exponents used in rest of routine */
+ diff_exponent = add_exponent - mpy_exponent;
+ result_exponent = add_exponent;
+ } else {
+ /* also setup exponents used in rest of routine */
+ diff_exponent = mpy_exponent - add_exponent;
+ result_exponent = mpy_exponent;
+ }
+ /* Invariant: left is not smaller than right. */
+
+ /*
+ * Special case alignment of operands that would force alignment
+ * beyond the extent of the extension. A further optimization
+ * could special case this but only reduces the path length for
+ * this infrequent case.
+ */
+ if (diff_exponent > SGLEXT_THRESHOLD) {
+ diff_exponent = SGLEXT_THRESHOLD;
+ }
+
+ /* Align right operand by shifting it to the right */
+ Sglext_clear_sign(rightp1);
+ Sglext_right_align(rightp1,rightp2,/*shifted by*/diff_exponent);
+
+ /* Treat sum and difference of the operands separately. */
+ if ((int)save < 0) {
+ /*
+ * Difference of the two operands. Overflow can occur if the
+ * multiply overflowed. A borrow can occur out of the hidden
+ * bit and force a post normalization phase.
+ */
+ Sglext_subtract(tmpresp1,tmpresp2, rightp1,rightp2,
+ resultp1,resultp2);
+ sign_save = Sgl_signextendedsign(resultp1);
+ if (Sgl_iszero_hidden(resultp1)) {
+ /* Handle normalization */
+ /* A straightforward algorithm would now shift the
+ * result and extension left until the hidden bit
+ * becomes one. Not all of the extension bits need
+ * participate in the shift. Only the two most
+ * significant bits (round and guard) are needed.
+ * If only a single shift is needed then the guard
+ * bit becomes a significant low order bit and the
+ * extension must participate in the rounding.
+ * If more than a single shift is needed, then all
+ * bits to the right of the guard bit are zeros,
+ * and the guard bit may or may not be zero. */
+ Sglext_leftshiftby1(resultp1,resultp2);
+
+ /* Need to check for a zero result. The sign and
+ * exponent fields have already been zeroed. The more
+ * efficient test of the full object can be used.
+ */
+ if (Sglext_iszero(resultp1,resultp2)) {
+ /* Must have been "x-x" or "x+(-x)". */
+ if (Is_rounding_mode(ROUNDMINUS))
+ Sgl_setone_sign(resultp1);
+ Sgl_copytoptr(resultp1,dstptr);
+ return(NOEXCEPTION);
+ }
+ result_exponent--;
+
+ /* Look to see if normalization is finished. */
+ if (Sgl_isone_hidden(resultp1)) {
+ /* No further normalization is needed */
+ goto round;
+ }
+
+ /* Discover first one bit to determine shift amount.
+ * Use a modified binary search. We have already
+ * shifted the result one position right and still
+ * not found a one so the remainder of the extension
+ * must be zero and simplifies rounding. */
+ /* Scan bytes */
+ while (Sgl_iszero_hiddenhigh7mantissa(resultp1)) {
+ Sglext_leftshiftby8(resultp1,resultp2);
+ result_exponent -= 8;
+ }
+ /* Now narrow it down to the nibble */
+ if (Sgl_iszero_hiddenhigh3mantissa(resultp1)) {
+ /* The lower nibble contains the
+ * normalizing one */
+ Sglext_leftshiftby4(resultp1,resultp2);
+ result_exponent -= 4;
+ }
+ /* Select case where first bit is set (already
+ * normalized) otherwise select the proper shift. */
+ jumpsize = Sgl_hiddenhigh3mantissa(resultp1);
+ if (jumpsize <= 7) switch(jumpsize) {
+ case 1:
+ Sglext_leftshiftby3(resultp1,resultp2);
+ result_exponent -= 3;
+ break;
+ case 2:
+ case 3:
+ Sglext_leftshiftby2(resultp1,resultp2);
+ result_exponent -= 2;
+ break;
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ Sglext_leftshiftby1(resultp1,resultp2);
+ result_exponent -= 1;
+ break;
+ }
+ } /* end if (hidden...)... */
+ /* Fall through and round */
+ } /* end if (save < 0)... */
+ else {
+ /* Add magnitudes */
+ Sglext_addition(tmpresp1,tmpresp2,
+ rightp1,rightp2, /*to*/resultp1,resultp2);
+ sign_save = Sgl_signextendedsign(resultp1);
+ if (Sgl_isone_hiddenoverflow(resultp1)) {
+ /* Prenormalization required. */
+ Sglext_arithrightshiftby1(resultp1,resultp2);
+ result_exponent++;
+ } /* end if hiddenoverflow... */
+ } /* end else ...add magnitudes... */
+
+ /* Round the result. If the extension and lower two words are
+ * all zeros, then the result is exact. Otherwise round in the
+ * correct direction. Underflow is possible. If a postnormalization
+ * is necessary, then the mantissa is all zeros so no shift is needed.
+ */
+ round:
+ if (result_exponent <= 0 && !Is_underflowtrap_enabled()) {
+ Sglext_denormalize(resultp1,resultp2,result_exponent,is_tiny);
+ }
+ Sgl_set_sign(resultp1,/*using*/sign_save);
+ if (Sglext_isnotzero_mantissap2(resultp2)) {
+ inexact = TRUE;
+ switch(Rounding_mode()) {
+ case ROUNDNEAREST: /* The default. */
+ if (Sglext_isone_highp2(resultp2)) {
+ /* at least 1/2 ulp */
+ if (Sglext_isnotzero_low31p2(resultp2) ||
+ Sglext_isone_lowp1(resultp1)) {
+ /* either exactly half way and odd or
+ * more than 1/2ulp */
+ Sgl_increment(resultp1);
+ }
+ }
+ break;
+
+ case ROUNDPLUS:
+ if (Sgl_iszero_sign(resultp1)) {
+ /* Round up positive results */
+ Sgl_increment(resultp1);
+ }
+ break;
+
+ case ROUNDMINUS:
+ if (Sgl_isone_sign(resultp1)) {
+ /* Round down negative results */
+ Sgl_increment(resultp1);
+ }
+
+ case ROUNDZERO:;
+ /* truncate is simple */
+ } /* end switch... */
+ if (Sgl_isone_hiddenoverflow(resultp1)) result_exponent++;
+ }
+ if (result_exponent >= SGL_INFINITY_EXPONENT) {
+ /* Overflow */
+ if (Is_overflowtrap_enabled()) {
+ /*
+ * Adjust bias of result
+ */
+ Sgl_setwrapped_exponent(resultp1,result_exponent,ovfl);
+ Sgl_copytoptr(resultp1,dstptr);
+ if (inexact)
+ if (Is_inexacttrap_enabled())
+ return (OPC_2E_OVERFLOWEXCEPTION |
+ OPC_2E_INEXACTEXCEPTION);
+ else Set_inexactflag();
+ return (OPC_2E_OVERFLOWEXCEPTION);
+ }
+ inexact = TRUE;
+ Set_overflowflag();
+ Sgl_setoverflow(resultp1);
+ } else if (result_exponent <= 0) { /* underflow case */
+ if (Is_underflowtrap_enabled()) {
+ /*
+ * Adjust bias of result
+ */
+ Sgl_setwrapped_exponent(resultp1,result_exponent,unfl);
+ Sgl_copytoptr(resultp1,dstptr);
+ if (inexact)
+ if (Is_inexacttrap_enabled())
+ return (OPC_2E_UNDERFLOWEXCEPTION |
+ OPC_2E_INEXACTEXCEPTION);
+ else Set_inexactflag();
+ return(OPC_2E_UNDERFLOWEXCEPTION);
+ }
+ else if (inexact && is_tiny) Set_underflowflag();
+ }
+ else Sgl_set_exponent(resultp1,result_exponent);
+ Sgl_copytoptr(resultp1,dstptr);
+ if (inexact)
+ if (Is_inexacttrap_enabled()) return(OPC_2E_INEXACTEXCEPTION);
+ else Set_inexactflag();
+ return(NOEXCEPTION);
+}
+
+/*
+ * Single Floating-point Multiply Negate Fused Add
+ */
+
+sgl_fmpynfadd(src1ptr,src2ptr,src3ptr,status,dstptr)
+
+sgl_floating_point *src1ptr, *src2ptr, *src3ptr, *dstptr;
+unsigned int *status;
+{
+ unsigned int opnd1, opnd2, opnd3;
+ register unsigned int tmpresp1, tmpresp2;
+ unsigned int rightp1, rightp2;
+ unsigned int resultp1, resultp2 = 0;
+ register int mpy_exponent, add_exponent, count;
+ boolean inexact = FALSE, is_tiny = FALSE;
+
+ unsigned int signlessleft1, signlessright1, save;
+ register int result_exponent, diff_exponent;
+ int sign_save, jumpsize;
+
+ Sgl_copyfromptr(src1ptr,opnd1);
+ Sgl_copyfromptr(src2ptr,opnd2);
+ Sgl_copyfromptr(src3ptr,opnd3);
+
+ /*
+ * set sign bit of result of multiply
+ */
+ if (Sgl_sign(opnd1) ^ Sgl_sign(opnd2))
+ Sgl_setzero(resultp1);
+ else
+ Sgl_setnegativezero(resultp1);
+
+ /*
+ * Generate multiply exponent
+ */
+ mpy_exponent = Sgl_exponent(opnd1) + Sgl_exponent(opnd2) - SGL_BIAS;
+
+ /*
+ * check first operand for NaN's or infinity
+ */
+ if (Sgl_isinfinity_exponent(opnd1)) {
+ if (Sgl_iszero_mantissa(opnd1)) {
+ if (Sgl_isnotnan(opnd2) && Sgl_isnotnan(opnd3)) {
+ if (Sgl_iszero_exponentmantissa(opnd2)) {
+ /*
+ * invalid since operands are infinity
+ * and zero
+ */
+ if (Is_invalidtrap_enabled())
+ return(OPC_2E_INVALIDEXCEPTION);
+ Set_invalidflag();
+ Sgl_makequietnan(resultp1);
+ Sgl_copytoptr(resultp1,dstptr);
+ return(NOEXCEPTION);
+ }
+ /*
+ * Check third operand for infinity with a
+ * sign opposite of the multiply result
+ */
+ if (Sgl_isinfinity(opnd3) &&
+ (Sgl_sign(resultp1) ^ Sgl_sign(opnd3))) {
+ /*
+ * invalid since attempting a magnitude
+ * subtraction of infinities
+ */
+ if (Is_invalidtrap_enabled())
+ return(OPC_2E_INVALIDEXCEPTION);
+ Set_invalidflag();
+ Sgl_makequietnan(resultp1);
+ Sgl_copytoptr(resultp1,dstptr);
+ return(NOEXCEPTION);
+ }
+
+ /*
+ * return infinity
+ */
+ Sgl_setinfinity_exponentmantissa(resultp1);
+ Sgl_copytoptr(resultp1,dstptr);
+ return(NOEXCEPTION);
+ }
+ }
+ else {
+ /*
+ * is NaN; signaling or quiet?
+ */
+ if (Sgl_isone_signaling(opnd1)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled())
+ return(OPC_2E_INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Sgl_set_quiet(opnd1);
+ }
+ /*
+ * is second operand a signaling NaN?
+ */
+ else if (Sgl_is_signalingnan(opnd2)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled())
+ return(OPC_2E_INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Sgl_set_quiet(opnd2);
+ Sgl_copytoptr(opnd2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /*
+ * is third operand a signaling NaN?
+ */
+ else if (Sgl_is_signalingnan(opnd3)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled())
+ return(OPC_2E_INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Sgl_set_quiet(opnd3);
+ Sgl_copytoptr(opnd3,dstptr);
+ return(NOEXCEPTION);
+ }
+ /*
+ * return quiet NaN
+ */
+ Sgl_copytoptr(opnd1,dstptr);
+ return(NOEXCEPTION);
+ }
+ }
+
+ /*
+ * check second operand for NaN's or infinity
+ */
+ if (Sgl_isinfinity_exponent(opnd2)) {
+ if (Sgl_iszero_mantissa(opnd2)) {
+ if (Sgl_isnotnan(opnd3)) {
+ if (Sgl_iszero_exponentmantissa(opnd1)) {
+ /*
+ * invalid since multiply operands are
+ * zero & infinity
+ */
+ if (Is_invalidtrap_enabled())
+ return(OPC_2E_INVALIDEXCEPTION);
+ Set_invalidflag();
+ Sgl_makequietnan(opnd2);
+ Sgl_copytoptr(opnd2,dstptr);
+ return(NOEXCEPTION);
+ }
+
+ /*
+ * Check third operand for infinity with a
+ * sign opposite of the multiply result
+ */
+ if (Sgl_isinfinity(opnd3) &&
+ (Sgl_sign(resultp1) ^ Sgl_sign(opnd3))) {
+ /*
+ * invalid since attempting a magnitude
+ * subtraction of infinities
+ */
+ if (Is_invalidtrap_enabled())
+ return(OPC_2E_INVALIDEXCEPTION);
+ Set_invalidflag();
+ Sgl_makequietnan(resultp1);
+ Sgl_copytoptr(resultp1,dstptr);
+ return(NOEXCEPTION);
+ }
+
+ /*
+ * return infinity
+ */
+ Sgl_setinfinity_exponentmantissa(resultp1);
+ Sgl_copytoptr(resultp1,dstptr);
+ return(NOEXCEPTION);
+ }
+ }
+ else {
+ /*
+ * is NaN; signaling or quiet?
+ */
+ if (Sgl_isone_signaling(opnd2)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled())
+ return(OPC_2E_INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Sgl_set_quiet(opnd2);
+ }
+ /*
+ * is third operand a signaling NaN?
+ */
+ else if (Sgl_is_signalingnan(opnd3)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled())
+ return(OPC_2E_INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Sgl_set_quiet(opnd3);
+ Sgl_copytoptr(opnd3,dstptr);
+ return(NOEXCEPTION);
+ }
+ /*
+ * return quiet NaN
+ */
+ Sgl_copytoptr(opnd2,dstptr);
+ return(NOEXCEPTION);
+ }
+ }
+
+ /*
+ * check third operand for NaN's or infinity
+ */
+ if (Sgl_isinfinity_exponent(opnd3)) {
+ if (Sgl_iszero_mantissa(opnd3)) {
+ /* return infinity */
+ Sgl_copytoptr(opnd3,dstptr);
+ return(NOEXCEPTION);
+ } else {
+ /*
+ * is NaN; signaling or quiet?
+ */
+ if (Sgl_isone_signaling(opnd3)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled())
+ return(OPC_2E_INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Sgl_set_quiet(opnd3);
+ }
+ /*
+ * return quiet NaN
+ */
+ Sgl_copytoptr(opnd3,dstptr);
+ return(NOEXCEPTION);
+ }
+ }
+
+ /*
+ * Generate multiply mantissa
+ */
+ if (Sgl_isnotzero_exponent(opnd1)) {
+ /* set hidden bit */
+ Sgl_clear_signexponent_set_hidden(opnd1);
+ }
+ else {
+ /* check for zero */
+ if (Sgl_iszero_mantissa(opnd1)) {
+ /*
+ * Perform the add opnd3 with zero here.
+ */
+ if (Sgl_iszero_exponentmantissa(opnd3)) {
+ if (Is_rounding_mode(ROUNDMINUS)) {
+ Sgl_or_signs(opnd3,resultp1);
+ } else {
+ Sgl_and_signs(opnd3,resultp1);
+ }
+ }
+ /*
+ * Now let's check for trapped underflow case.
+ */
+ else if (Sgl_iszero_exponent(opnd3) &&
+ Is_underflowtrap_enabled()) {
+ /* need to normalize results mantissa */
+ sign_save = Sgl_signextendedsign(opnd3);
+ result_exponent = 0;
+ Sgl_leftshiftby1(opnd3);
+ Sgl_normalize(opnd3,result_exponent);
+ Sgl_set_sign(opnd3,/*using*/sign_save);
+ Sgl_setwrapped_exponent(opnd3,result_exponent,
+ unfl);
+ Sgl_copytoptr(opnd3,dstptr);
+ /* inexact = FALSE */
+ return(OPC_2E_UNDERFLOWEXCEPTION);
+ }
+ Sgl_copytoptr(opnd3,dstptr);
+ return(NOEXCEPTION);
+ }
+ /* is denormalized, adjust exponent */
+ Sgl_clear_signexponent(opnd1);
+ Sgl_leftshiftby1(opnd1);
+ Sgl_normalize(opnd1,mpy_exponent);
+ }
+ /* opnd2 needs to have hidden bit set with msb in hidden bit */
+ if (Sgl_isnotzero_exponent(opnd2)) {
+ Sgl_clear_signexponent_set_hidden(opnd2);
+ }
+ else {
+ /* check for zero */
+ if (Sgl_iszero_mantissa(opnd2)) {
+ /*
+ * Perform the add opnd3 with zero here.
+ */
+ if (Sgl_iszero_exponentmantissa(opnd3)) {
+ if (Is_rounding_mode(ROUNDMINUS)) {
+ Sgl_or_signs(opnd3,resultp1);
+ } else {
+ Sgl_and_signs(opnd3,resultp1);
+ }
+ }
+ /*
+ * Now let's check for trapped underflow case.
+ */
+ else if (Sgl_iszero_exponent(opnd3) &&
+ Is_underflowtrap_enabled()) {
+ /* need to normalize results mantissa */
+ sign_save = Sgl_signextendedsign(opnd3);
+ result_exponent = 0;
+ Sgl_leftshiftby1(opnd3);
+ Sgl_normalize(opnd3,result_exponent);
+ Sgl_set_sign(opnd3,/*using*/sign_save);
+ Sgl_setwrapped_exponent(opnd3,result_exponent,
+ unfl);
+ Sgl_copytoptr(opnd3,dstptr);
+ /* inexact = FALSE */
+ return(OPC_2E_UNDERFLOWEXCEPTION);
+ }
+ Sgl_copytoptr(opnd3,dstptr);
+ return(NOEXCEPTION);
+ }
+ /* is denormalized; want to normalize */
+ Sgl_clear_signexponent(opnd2);
+ Sgl_leftshiftby1(opnd2);
+ Sgl_normalize(opnd2,mpy_exponent);
+ }
+
+ /* Multiply the first two source mantissas together */
+
+ /*
+ * The intermediate result will be kept in tmpres,
+ * which needs enough room for 106 bits of mantissa,
+ * so lets call it a Double extended.
+ */
+ Sglext_setzero(tmpresp1,tmpresp2);
+
+ /*
+ * Four bits at a time are inspected in each loop, and a
+ * simple shift and add multiply algorithm is used.
+ */
+ for (count = SGL_P-1; count >= 0; count -= 4) {
+ Sglext_rightshiftby4(tmpresp1,tmpresp2);
+ if (Sbit28(opnd1)) {
+ /* Twoword_add should be an ADD followed by 2 ADDC's */
+ Twoword_add(tmpresp1, tmpresp2, opnd2<<3, 0);
+ }
+ if (Sbit29(opnd1)) {
+ Twoword_add(tmpresp1, tmpresp2, opnd2<<2, 0);
+ }
+ if (Sbit30(opnd1)) {
+ Twoword_add(tmpresp1, tmpresp2, opnd2<<1, 0);
+ }
+ if (Sbit31(opnd1)) {
+ Twoword_add(tmpresp1, tmpresp2, opnd2, 0);
+ }
+ Sgl_rightshiftby4(opnd1);
+ }
+ if (Is_sexthiddenoverflow(tmpresp1)) {
+ /* result mantissa >= 2 (mantissa overflow) */
+ mpy_exponent++;
+ Sglext_rightshiftby4(tmpresp1,tmpresp2);
+ } else {
+ Sglext_rightshiftby3(tmpresp1,tmpresp2);
+ }
+
+ /*
+ * Restore the sign of the mpy result which was saved in resultp1.
+ * The exponent will continue to be kept in mpy_exponent.
+ */
+ Sglext_set_sign(tmpresp1,Sgl_sign(resultp1));
+
+ /*
+ * No rounding is required, since the result of the multiply
+ * is exact in the extended format.
+ */
+
+ /*
+ * Now we are ready to perform the add portion of the operation.
+ *
+ * The exponents need to be kept as integers for now, since the
+ * multiply result might not fit into the exponent field. We
+ * can't overflow or underflow because of this yet, since the
+ * add could bring the final result back into range.
+ */
+ add_exponent = Sgl_exponent(opnd3);
+
+ /*
+ * Check for denormalized or zero add operand.
+ */
+ if (add_exponent == 0) {
+ /* check for zero */
+ if (Sgl_iszero_mantissa(opnd3)) {
+ /* right is zero */
+ /* Left can't be zero and must be result.
+ *
+ * The final result is now in tmpres and mpy_exponent,
+ * and needs to be rounded and squeezed back into
+ * double precision format from double extended.
+ */
+ result_exponent = mpy_exponent;
+ Sglext_copy(tmpresp1,tmpresp2,resultp1,resultp2);
+ sign_save = Sgl_signextendedsign(resultp1);/*save sign*/
+ goto round;
+ }
+
+ /*
+ * Neither are zeroes.
+ * Adjust exponent and normalize add operand.
+ */
+ sign_save = Sgl_signextendedsign(opnd3); /* save sign */
+ Sgl_clear_signexponent(opnd3);
+ Sgl_leftshiftby1(opnd3);
+ Sgl_normalize(opnd3,add_exponent);
+ Sgl_set_sign(opnd3,sign_save); /* restore sign */
+ } else {
+ Sgl_clear_exponent_set_hidden(opnd3);
+ }
+ /*
+ * Copy opnd3 to the double extended variable called right.
+ */
+ Sgl_copyto_sglext(opnd3,rightp1,rightp2);
+
+ /*
+ * A zero "save" helps discover equal operands (for later),
+ * and is used in swapping operands (if needed).
+ */
+ Sglext_xortointp1(tmpresp1,rightp1,/*to*/save);
+
+ /*
+ * Compare magnitude of operands.
+ */
+ Sglext_copytoint_exponentmantissa(tmpresp1,signlessleft1);
+ Sglext_copytoint_exponentmantissa(rightp1,signlessright1);
+ if (mpy_exponent < add_exponent || mpy_exponent == add_exponent &&
+ Sglext_ismagnitudeless(signlessleft1,signlessright1)) {
+ /*
+ * Set the left operand to the larger one by XOR swap.
+ * First finish the first word "save".
+ */
+ Sglext_xorfromintp1(save,rightp1,/*to*/rightp1);
+ Sglext_xorfromintp1(save,tmpresp1,/*to*/tmpresp1);
+ Sglext_swap_lower(tmpresp2,rightp2);
+ /* also setup exponents used in rest of routine */
+ diff_exponent = add_exponent - mpy_exponent;
+ result_exponent = add_exponent;
+ } else {
+ /* also setup exponents used in rest of routine */
+ diff_exponent = mpy_exponent - add_exponent;
+ result_exponent = mpy_exponent;
+ }
+ /* Invariant: left is not smaller than right. */
+
+ /*
+ * Special case alignment of operands that would force alignment
+ * beyond the extent of the extension. A further optimization
+ * could special case this but only reduces the path length for
+ * this infrequent case.
+ */
+ if (diff_exponent > SGLEXT_THRESHOLD) {
+ diff_exponent = SGLEXT_THRESHOLD;
+ }
+
+ /* Align right operand by shifting it to the right */
+ Sglext_clear_sign(rightp1);
+ Sglext_right_align(rightp1,rightp2,/*shifted by*/diff_exponent);
+
+ /* Treat sum and difference of the operands separately. */
+ if ((int)save < 0) {
+ /*
+ * Difference of the two operands. Overflow can occur if the
+ * multiply overflowed. A borrow can occur out of the hidden
+ * bit and force a post normalization phase.
+ */
+ Sglext_subtract(tmpresp1,tmpresp2, rightp1,rightp2,
+ resultp1,resultp2);
+ sign_save = Sgl_signextendedsign(resultp1);
+ if (Sgl_iszero_hidden(resultp1)) {
+ /* Handle normalization */
+ /* A straightforward algorithm would now shift the
+ * result and extension left until the hidden bit
+ * becomes one. Not all of the extension bits need
+ * participate in the shift. Only the two most
+ * significant bits (round and guard) are needed.
+ * If only a single shift is needed then the guard
+ * bit becomes a significant low order bit and the
+ * extension must participate in the rounding.
+ * If more than a single shift is needed, then all
+ * bits to the right of the guard bit are zeros,
+ * and the guard bit may or may not be zero. */
+ Sglext_leftshiftby1(resultp1,resultp2);
+
+ /* Need to check for a zero result. The sign and
+ * exponent fields have already been zeroed. The more
+ * efficient test of the full object can be used.
+ */
+ if (Sglext_iszero(resultp1,resultp2)) {
+ /* Must have been "x-x" or "x+(-x)". */
+ if (Is_rounding_mode(ROUNDMINUS))
+ Sgl_setone_sign(resultp1);
+ Sgl_copytoptr(resultp1,dstptr);
+ return(NOEXCEPTION);
+ }
+ result_exponent--;
+
+ /* Look to see if normalization is finished. */
+ if (Sgl_isone_hidden(resultp1)) {
+ /* No further normalization is needed */
+ goto round;
+ }
+
+ /* Discover first one bit to determine shift amount.
+ * Use a modified binary search. We have already
+ * shifted the result one position right and still
+ * not found a one so the remainder of the extension
+ * must be zero and simplifies rounding. */
+ /* Scan bytes */
+ while (Sgl_iszero_hiddenhigh7mantissa(resultp1)) {
+ Sglext_leftshiftby8(resultp1,resultp2);
+ result_exponent -= 8;
+ }
+ /* Now narrow it down to the nibble */
+ if (Sgl_iszero_hiddenhigh3mantissa(resultp1)) {
+ /* The lower nibble contains the
+ * normalizing one */
+ Sglext_leftshiftby4(resultp1,resultp2);
+ result_exponent -= 4;
+ }
+ /* Select case where first bit is set (already
+ * normalized) otherwise select the proper shift. */
+ jumpsize = Sgl_hiddenhigh3mantissa(resultp1);
+ if (jumpsize <= 7) switch(jumpsize) {
+ case 1:
+ Sglext_leftshiftby3(resultp1,resultp2);
+ result_exponent -= 3;
+ break;
+ case 2:
+ case 3:
+ Sglext_leftshiftby2(resultp1,resultp2);
+ result_exponent -= 2;
+ break;
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ Sglext_leftshiftby1(resultp1,resultp2);
+ result_exponent -= 1;
+ break;
+ }
+ } /* end if (hidden...)... */
+ /* Fall through and round */
+ } /* end if (save < 0)... */
+ else {
+ /* Add magnitudes */
+ Sglext_addition(tmpresp1,tmpresp2,
+ rightp1,rightp2, /*to*/resultp1,resultp2);
+ sign_save = Sgl_signextendedsign(resultp1);
+ if (Sgl_isone_hiddenoverflow(resultp1)) {
+ /* Prenormalization required. */
+ Sglext_arithrightshiftby1(resultp1,resultp2);
+ result_exponent++;
+ } /* end if hiddenoverflow... */
+ } /* end else ...add magnitudes... */
+
+ /* Round the result. If the extension and lower two words are
+ * all zeros, then the result is exact. Otherwise round in the
+ * correct direction. Underflow is possible. If a postnormalization
+ * is necessary, then the mantissa is all zeros so no shift is needed.
+ */
+ round:
+ if (result_exponent <= 0 && !Is_underflowtrap_enabled()) {
+ Sglext_denormalize(resultp1,resultp2,result_exponent,is_tiny);
+ }
+ Sgl_set_sign(resultp1,/*using*/sign_save);
+ if (Sglext_isnotzero_mantissap2(resultp2)) {
+ inexact = TRUE;
+ switch(Rounding_mode()) {
+ case ROUNDNEAREST: /* The default. */
+ if (Sglext_isone_highp2(resultp2)) {
+ /* at least 1/2 ulp */
+ if (Sglext_isnotzero_low31p2(resultp2) ||
+ Sglext_isone_lowp1(resultp1)) {
+ /* either exactly half way and odd or
+ * more than 1/2ulp */
+ Sgl_increment(resultp1);
+ }
+ }
+ break;
+
+ case ROUNDPLUS:
+ if (Sgl_iszero_sign(resultp1)) {
+ /* Round up positive results */
+ Sgl_increment(resultp1);
+ }
+ break;
+
+ case ROUNDMINUS:
+ if (Sgl_isone_sign(resultp1)) {
+ /* Round down negative results */
+ Sgl_increment(resultp1);
+ }
+
+ case ROUNDZERO:;
+ /* truncate is simple */
+ } /* end switch... */
+ if (Sgl_isone_hiddenoverflow(resultp1)) result_exponent++;
+ }
+ if (result_exponent >= SGL_INFINITY_EXPONENT) {
+ /* Overflow */
+ if (Is_overflowtrap_enabled()) {
+ /*
+ * Adjust bias of result
+ */
+ Sgl_setwrapped_exponent(resultp1,result_exponent,ovfl);
+ Sgl_copytoptr(resultp1,dstptr);
+ if (inexact)
+ if (Is_inexacttrap_enabled())
+ return (OPC_2E_OVERFLOWEXCEPTION |
+ OPC_2E_INEXACTEXCEPTION);
+ else Set_inexactflag();
+ return (OPC_2E_OVERFLOWEXCEPTION);
+ }
+ inexact = TRUE;
+ Set_overflowflag();
+ Sgl_setoverflow(resultp1);
+ } else if (result_exponent <= 0) { /* underflow case */
+ if (Is_underflowtrap_enabled()) {
+ /*
+ * Adjust bias of result
+ */
+ Sgl_setwrapped_exponent(resultp1,result_exponent,unfl);
+ Sgl_copytoptr(resultp1,dstptr);
+ if (inexact)
+ if (Is_inexacttrap_enabled())
+ return (OPC_2E_UNDERFLOWEXCEPTION |
+ OPC_2E_INEXACTEXCEPTION);
+ else Set_inexactflag();
+ return(OPC_2E_UNDERFLOWEXCEPTION);
+ }
+ else if (inexact && is_tiny) Set_underflowflag();
+ }
+ else Sgl_set_exponent(resultp1,result_exponent);
+ Sgl_copytoptr(resultp1,dstptr);
+ if (inexact)
+ if (Is_inexacttrap_enabled()) return(OPC_2E_INEXACTEXCEPTION);
+ else Set_inexactflag();
+ return(NOEXCEPTION);
+}
+
diff --git a/arch/parisc/math-emu/fpbits.h b/arch/parisc/math-emu/fpbits.h
new file mode 100644
index 000000000..b46bddb9a
--- /dev/null
+++ b/arch/parisc/math-emu/fpbits.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ */
+
+#ifdef __NO_PA_HDRS
+ PA header file -- do not include this header file for non-PA builds.
+#endif
+
+
+/*
+ * These macros are designed to be portable to all machines that have
+ * a wordsize greater than or equal to 32 bits that support the portable
+ * C compiler and the standard C preprocessor. Wordsize (default 32)
+ * and bitfield assignment (default left-to-right, unlike VAX, PDP-11)
+ * should be predefined using the constants HOSTWDSZ and BITFRL and
+ * the C compiler "-D" flag (e.g., -DHOSTWDSZ=36 -DBITFLR for the DEC-20).
+ * Note that the macro arguments assume that the integer being referenced
+ * is a 32-bit integer (right-justified on the 20) and that bit 0 is the
+ * most significant bit.
+ */
+
+#ifndef HOSTWDSZ
+#define HOSTWDSZ 32
+#endif
+
+
+/*########################### Macros ######################################*/
+
+/*-------------------------------------------------------------------------
+ * NewDeclareBitField_Reference - Declare a structure similar to the simulator
+ * function "DeclBitfR" except its use is restricted to occur within a larger
+ * enclosing structure or union definition. This declaration is an unnamed
+ * structure with the argument, name, as the member name and the argument,
+ * uname, as the element name.
+ *----------------------------------------------------------------------- */
+#define Bitfield_extract(start, length, object) \
+ ((object) >> (HOSTWDSZ - (start) - (length)) & \
+ ((unsigned)-1 >> (HOSTWDSZ - (length))))
+
+#define Bitfield_signed_extract(start, length, object) \
+ ((int)((object) << start) >> (HOSTWDSZ - (length)))
+
+#define Bitfield_mask(start, len, object) \
+ ((object) & (((unsigned)-1 >> (HOSTWDSZ-len)) << (HOSTWDSZ-start-len)))
+
+#define Bitfield_deposit(value,start,len,object) object = \
+ ((object) & ~(((unsigned)-1 >> (HOSTWDSZ-len)) << (HOSTWDSZ-start-len))) | \
+ (((value) & ((unsigned)-1 >> (HOSTWDSZ-len))) << (HOSTWDSZ-start-len))
diff --git a/arch/parisc/math-emu/fpu.h b/arch/parisc/math-emu/fpu.h
new file mode 100644
index 000000000..dec951d40
--- /dev/null
+++ b/arch/parisc/math-emu/fpu.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ */
+
+#ifndef _MACHINE_FPU_INCLUDED /* allows multiple inclusion */
+#define _MACHINE_FPU_INCLUDED
+
+#define PA83_FPU_FLAG 0x00000001
+#define PA89_FPU_FLAG 0x00000002
+#define PA2_0_FPU_FLAG 0x00000010
+
+#define TIMEX_EXTEN_FLAG 0x00000004
+
+#define ROLEX_EXTEN_FLAG 0x00000008
+#define COPR_FP 0x00000080 /* Floating point -- Coprocessor 0 */
+#define SFU_MPY_DIVIDE 0x00008000 /* Multiply/Divide __ SFU 0 */
+
+#define EM_FPU_TYPE_OFFSET 272
+
+/* version of EMULATION software for COPR,0,0 instruction */
+#define EMULATION_VERSION 4
+
+/*
+ * The only way to differentiate between TIMEX and ROLEX (or PCX-S and PCX-T)
+ * is through the potential type field from the PDC_MODEL call.
+ * The following flags are used to assist this differentiation.
+ */
+
+#define ROLEX_POTENTIAL_KEY_FLAGS PDC_MODEL_CPU_KEY_WORD_TO_IO
+#define TIMEX_POTENTIAL_KEY_FLAGS (PDC_MODEL_CPU_KEY_QUAD_STORE | \
+ PDC_MODEL_CPU_KEY_RECIP_SQRT)
+
+#endif /* ! _MACHINE_FPU_INCLUDED */
diff --git a/arch/parisc/math-emu/fpudispatch.c b/arch/parisc/math-emu/fpudispatch.c
new file mode 100644
index 000000000..01ed13322
--- /dev/null
+++ b/arch/parisc/math-emu/fpudispatch.c
@@ -0,0 +1,1480 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ */
+/*
+ * BEGIN_DESC
+ *
+ * File:
+ * @(#) pa/fp/fpudispatch.c $Revision: 1.1 $
+ *
+ * Purpose:
+ * <<please update with a synopsis of the functionality provided by this file>>
+ *
+ * External Interfaces:
+ * <<the following list was autogenerated, please review>>
+ * emfpudispatch(ir, dummy1, dummy2, fpregs)
+ * fpudispatch(ir, excp_code, holder, fpregs)
+ *
+ * Internal Interfaces:
+ * <<the following list was autogenerated, please review>>
+ * static u_int decode_06(u_int, u_int *)
+ * static u_int decode_0c(u_int, u_int, u_int, u_int *)
+ * static u_int decode_0e(u_int, u_int, u_int, u_int *)
+ * static u_int decode_26(u_int, u_int *)
+ * static u_int decode_2e(u_int, u_int *)
+ * static void update_status_cbit(u_int *, u_int, u_int, u_int)
+ *
+ * Theory:
+ * <<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+#define FPUDEBUG 0
+
+#include "float.h"
+#include <linux/bug.h>
+#include <linux/kernel.h>
+#include <asm/processor.h>
+/* #include <sys/debug.h> */
+/* #include <machine/sys/mdep_private.h> */
+
+#define COPR_INST 0x30000000
+
+/*
+ * definition of extru macro. If pos and len are constants, the compiler
+ * will generate an extru instruction when optimized
+ */
+#define extru(r,pos,len) (((r) >> (31-(pos))) & (( 1 << (len)) - 1))
+/* definitions of bit field locations in the instruction */
+#define fpmajorpos 5
+#define fpr1pos 10
+#define fpr2pos 15
+#define fptpos 31
+#define fpsubpos 18
+#define fpclass1subpos 16
+#define fpclasspos 22
+#define fpfmtpos 20
+#define fpdfpos 18
+#define fpnulpos 26
+/*
+ * the following are the extra bits for the 0E major op
+ */
+#define fpxr1pos 24
+#define fpxr2pos 19
+#define fpxtpos 25
+#define fpxpos 23
+#define fp0efmtpos 20
+/*
+ * the following are for the multi-ops
+ */
+#define fprm1pos 10
+#define fprm2pos 15
+#define fptmpos 31
+#define fprapos 25
+#define fptapos 20
+#define fpmultifmt 26
+/*
+ * the following are for the fused FP instructions
+ */
+ /* fprm1pos 10 */
+ /* fprm2pos 15 */
+#define fpraupos 18
+#define fpxrm2pos 19
+ /* fpfmtpos 20 */
+#define fpralpos 23
+#define fpxrm1pos 24
+ /* fpxtpos 25 */
+#define fpfusedsubop 26
+ /* fptpos 31 */
+
+/*
+ * offset to constant zero in the FP emulation registers
+ */
+#define fpzeroreg (32*sizeof(double)/sizeof(u_int))
+
+/*
+ * extract the major opcode from the instruction
+ */
+#define get_major(op) extru(op,fpmajorpos,6)
+/*
+ * extract the two bit class field from the FP instruction. The class is at bit
+ * positions 21-22
+ */
+#define get_class(op) extru(op,fpclasspos,2)
+/*
+ * extract the 3 bit subop field. For all but class 1 instructions, it is
+ * located at bit positions 16-18
+ */
+#define get_subop(op) extru(op,fpsubpos,3)
+/*
+ * extract the 2 or 3 bit subop field from class 1 instructions. It is located
+ * at bit positions 15-16 (PA1.1) or 14-16 (PA2.0)
+ */
+#define get_subop1_PA1_1(op) extru(op,fpclass1subpos,2) /* PA89 (1.1) fmt */
+#define get_subop1_PA2_0(op) extru(op,fpclass1subpos,3) /* PA 2.0 fmt */
+
+/* definitions of unimplemented exceptions */
+#define MAJOR_0C_EXCP 0x09
+#define MAJOR_0E_EXCP 0x0b
+#define MAJOR_06_EXCP 0x03
+#define MAJOR_26_EXCP 0x23
+#define MAJOR_2E_EXCP 0x2b
+#define PA83_UNIMP_EXCP 0x01
+
+/*
+ * Special Defines for TIMEX specific code
+ */
+
+#define FPU_TYPE_FLAG_POS (EM_FPU_TYPE_OFFSET>>2)
+#define TIMEX_ROLEX_FPU_MASK (TIMEX_EXTEN_FLAG|ROLEX_EXTEN_FLAG)
+
+/*
+ * Static function definitions
+ */
+#define _PROTOTYPES
+#if defined(_PROTOTYPES) || defined(_lint)
+static u_int decode_0c(u_int, u_int, u_int, u_int *);
+static u_int decode_0e(u_int, u_int, u_int, u_int *);
+static u_int decode_06(u_int, u_int *);
+static u_int decode_26(u_int, u_int *);
+static u_int decode_2e(u_int, u_int *);
+static void update_status_cbit(u_int *, u_int, u_int, u_int);
+#else /* !_PROTOTYPES&&!_lint */
+static u_int decode_0c();
+static u_int decode_0e();
+static u_int decode_06();
+static u_int decode_26();
+static u_int decode_2e();
+static void update_status_cbit();
+#endif /* _PROTOTYPES&&!_lint */
+
+#define VASSERT(x)
+
+static void parisc_linux_get_fpu_type(u_int fpregs[])
+{
+ /* on pa-linux the fpu type is not filled in by the
+ * caller; it is constructed here
+ */
+ if (boot_cpu_data.cpu_type == pcxs)
+ fpregs[FPU_TYPE_FLAG_POS] = TIMEX_EXTEN_FLAG;
+ else if (boot_cpu_data.cpu_type == pcxt ||
+ boot_cpu_data.cpu_type == pcxt_)
+ fpregs[FPU_TYPE_FLAG_POS] = ROLEX_EXTEN_FLAG;
+ else if (boot_cpu_data.cpu_type >= pcxu)
+ fpregs[FPU_TYPE_FLAG_POS] = PA2_0_FPU_FLAG;
+}
+
+/*
+ * this routine will decode the excepting floating point instruction and
+ * call the appropriate emulation routine.
+ * It is called by decode_fpu with the following parameters:
+ * fpudispatch(current_ir, unimplemented_code, 0, &Fpu_register)
+ * where current_ir is the instruction to be emulated,
+ * unimplemented_code is the exception_code that the hardware generated
+ * and &Fpu_register is the address of emulated FP reg 0.
+ */
+u_int
+fpudispatch(u_int ir, u_int excp_code, u_int holder, u_int fpregs[])
+{
+ u_int class, subop;
+ u_int fpu_type_flags;
+
+ /* All FP emulation code assumes that ints are 4-bytes in length */
+ VASSERT(sizeof(int) == 4);
+
+ parisc_linux_get_fpu_type(fpregs);
+
+ fpu_type_flags=fpregs[FPU_TYPE_FLAG_POS]; /* get fpu type flags */
+
+ class = get_class(ir);
+ if (class == 1) {
+ if (fpu_type_flags & PA2_0_FPU_FLAG)
+ subop = get_subop1_PA2_0(ir);
+ else
+ subop = get_subop1_PA1_1(ir);
+ }
+ else
+ subop = get_subop(ir);
+
+ if (FPUDEBUG) printk("class %d subop %d\n", class, subop);
+
+ switch (excp_code) {
+ case MAJOR_0C_EXCP:
+ case PA83_UNIMP_EXCP:
+ return(decode_0c(ir,class,subop,fpregs));
+ case MAJOR_0E_EXCP:
+ return(decode_0e(ir,class,subop,fpregs));
+ case MAJOR_06_EXCP:
+ return(decode_06(ir,fpregs));
+ case MAJOR_26_EXCP:
+ return(decode_26(ir,fpregs));
+ case MAJOR_2E_EXCP:
+ return(decode_2e(ir,fpregs));
+ default:
+ /* "crashme Night Gallery painting nr 2. (asm_crash.s).
+ * This was fixed for multi-user kernels, but
+ * workstation kernels had a panic here. This allowed
+ * any arbitrary user to panic the kernel by executing
+ * setting the FP exception registers to strange values
+ * and generating an emulation trap. The emulation and
+ * exception code must never be able to panic the
+ * kernel.
+ */
+ return(UNIMPLEMENTEDEXCEPTION);
+ }
+}
+
+/*
+ * this routine is called by $emulation_trap to emulate a coprocessor
+ * instruction if one doesn't exist
+ */
+u_int
+emfpudispatch(u_int ir, u_int dummy1, u_int dummy2, u_int fpregs[])
+{
+ u_int class, subop, major;
+ u_int fpu_type_flags;
+
+ /* All FP emulation code assumes that ints are 4-bytes in length */
+ VASSERT(sizeof(int) == 4);
+
+ fpu_type_flags=fpregs[FPU_TYPE_FLAG_POS]; /* get fpu type flags */
+
+ major = get_major(ir);
+ class = get_class(ir);
+ if (class == 1) {
+ if (fpu_type_flags & PA2_0_FPU_FLAG)
+ subop = get_subop1_PA2_0(ir);
+ else
+ subop = get_subop1_PA1_1(ir);
+ }
+ else
+ subop = get_subop(ir);
+ switch (major) {
+ case 0x0C:
+ return(decode_0c(ir,class,subop,fpregs));
+ case 0x0E:
+ return(decode_0e(ir,class,subop,fpregs));
+ case 0x06:
+ return(decode_06(ir,fpregs));
+ case 0x26:
+ return(decode_26(ir,fpregs));
+ case 0x2E:
+ return(decode_2e(ir,fpregs));
+ default:
+ return(PA83_UNIMP_EXCP);
+ }
+}
+
+
+static u_int
+decode_0c(u_int ir, u_int class, u_int subop, u_int fpregs[])
+{
+ u_int r1,r2,t; /* operand register offsets */
+ u_int fmt; /* also sf for class 1 conversions */
+ u_int df; /* for class 1 conversions */
+ u_int *status;
+ u_int retval, local_status;
+ u_int fpu_type_flags;
+
+ if (ir == COPR_INST) {
+ fpregs[0] = EMULATION_VERSION << 11;
+ return(NOEXCEPTION);
+ }
+ status = &fpregs[0]; /* fp status register */
+ local_status = fpregs[0]; /* and local copy */
+ r1 = extru(ir,fpr1pos,5) * sizeof(double)/sizeof(u_int);
+ if (r1 == 0) /* map fr0 source to constant zero */
+ r1 = fpzeroreg;
+ t = extru(ir,fptpos,5) * sizeof(double)/sizeof(u_int);
+ if (t == 0 && class != 2) /* don't allow fr0 as a dest */
+ return(MAJOR_0C_EXCP);
+ fmt = extru(ir,fpfmtpos,2); /* get fmt completer */
+
+ switch (class) {
+ case 0:
+ switch (subop) {
+ case 0: /* COPR 0,0 emulated above*/
+ case 1:
+ return(MAJOR_0C_EXCP);
+ case 2: /* FCPY */
+ switch (fmt) {
+ case 2: /* illegal */
+ return(MAJOR_0C_EXCP);
+ case 3: /* quad */
+ t &= ~3; /* force to even reg #s */
+ r1 &= ~3;
+ fpregs[t+3] = fpregs[r1+3];
+ fpregs[t+2] = fpregs[r1+2];
+ fallthrough;
+ case 1: /* double */
+ fpregs[t+1] = fpregs[r1+1];
+ fallthrough;
+ case 0: /* single */
+ fpregs[t] = fpregs[r1];
+ return(NOEXCEPTION);
+ }
+ BUG();
+ case 3: /* FABS */
+ switch (fmt) {
+ case 2: /* illegal */
+ return(MAJOR_0C_EXCP);
+ case 3: /* quad */
+ t &= ~3; /* force to even reg #s */
+ r1 &= ~3;
+ fpregs[t+3] = fpregs[r1+3];
+ fpregs[t+2] = fpregs[r1+2];
+ fallthrough;
+ case 1: /* double */
+ fpregs[t+1] = fpregs[r1+1];
+ fallthrough;
+ case 0: /* single */
+ /* copy and clear sign bit */
+ fpregs[t] = fpregs[r1] & 0x7fffffff;
+ return(NOEXCEPTION);
+ }
+ BUG();
+ case 6: /* FNEG */
+ switch (fmt) {
+ case 2: /* illegal */
+ return(MAJOR_0C_EXCP);
+ case 3: /* quad */
+ t &= ~3; /* force to even reg #s */
+ r1 &= ~3;
+ fpregs[t+3] = fpregs[r1+3];
+ fpregs[t+2] = fpregs[r1+2];
+ fallthrough;
+ case 1: /* double */
+ fpregs[t+1] = fpregs[r1+1];
+ fallthrough;
+ case 0: /* single */
+ /* copy and invert sign bit */
+ fpregs[t] = fpregs[r1] ^ 0x80000000;
+ return(NOEXCEPTION);
+ }
+ BUG();
+ case 7: /* FNEGABS */
+ switch (fmt) {
+ case 2: /* illegal */
+ return(MAJOR_0C_EXCP);
+ case 3: /* quad */
+ t &= ~3; /* force to even reg #s */
+ r1 &= ~3;
+ fpregs[t+3] = fpregs[r1+3];
+ fpregs[t+2] = fpregs[r1+2];
+ fallthrough;
+ case 1: /* double */
+ fpregs[t+1] = fpregs[r1+1];
+ fallthrough;
+ case 0: /* single */
+ /* copy and set sign bit */
+ fpregs[t] = fpregs[r1] | 0x80000000;
+ return(NOEXCEPTION);
+ }
+ BUG();
+ case 4: /* FSQRT */
+ switch (fmt) {
+ case 0:
+ return(sgl_fsqrt(&fpregs[r1],0,
+ &fpregs[t],status));
+ case 1:
+ return(dbl_fsqrt(&fpregs[r1],0,
+ &fpregs[t],status));
+ case 2:
+ case 3: /* quad not implemented */
+ return(MAJOR_0C_EXCP);
+ }
+ BUG();
+ case 5: /* FRND */
+ switch (fmt) {
+ case 0:
+ return(sgl_frnd(&fpregs[r1],0,
+ &fpregs[t],status));
+ case 1:
+ return(dbl_frnd(&fpregs[r1],0,
+ &fpregs[t],status));
+ case 2:
+ case 3: /* quad not implemented */
+ return(MAJOR_0C_EXCP);
+ }
+ } /* end of switch (subop) */
+ BUG();
+ case 1: /* class 1 */
+ df = extru(ir,fpdfpos,2); /* get dest format */
+ if ((df & 2) || (fmt & 2)) {
+ /*
+ * fmt's 2 and 3 are illegal of not implemented
+ * quad conversions
+ */
+ return(MAJOR_0C_EXCP);
+ }
+ /*
+ * encode source and dest formats into 2 bits.
+ * high bit is source, low bit is dest.
+ * bit = 1 --> double precision
+ */
+ fmt = (fmt << 1) | df;
+ switch (subop) {
+ case 0: /* FCNVFF */
+ switch(fmt) {
+ case 0: /* sgl/sgl */
+ return(MAJOR_0C_EXCP);
+ case 1: /* sgl/dbl */
+ return(sgl_to_dbl_fcnvff(&fpregs[r1],0,
+ &fpregs[t],status));
+ case 2: /* dbl/sgl */
+ return(dbl_to_sgl_fcnvff(&fpregs[r1],0,
+ &fpregs[t],status));
+ case 3: /* dbl/dbl */
+ return(MAJOR_0C_EXCP);
+ }
+ BUG();
+ case 1: /* FCNVXF */
+ switch(fmt) {
+ case 0: /* sgl/sgl */
+ return(sgl_to_sgl_fcnvxf(&fpregs[r1],0,
+ &fpregs[t],status));
+ case 1: /* sgl/dbl */
+ return(sgl_to_dbl_fcnvxf(&fpregs[r1],0,
+ &fpregs[t],status));
+ case 2: /* dbl/sgl */
+ return(dbl_to_sgl_fcnvxf(&fpregs[r1],0,
+ &fpregs[t],status));
+ case 3: /* dbl/dbl */
+ return(dbl_to_dbl_fcnvxf(&fpregs[r1],0,
+ &fpregs[t],status));
+ }
+ BUG();
+ case 2: /* FCNVFX */
+ switch(fmt) {
+ case 0: /* sgl/sgl */
+ return(sgl_to_sgl_fcnvfx(&fpregs[r1],0,
+ &fpregs[t],status));
+ case 1: /* sgl/dbl */
+ return(sgl_to_dbl_fcnvfx(&fpregs[r1],0,
+ &fpregs[t],status));
+ case 2: /* dbl/sgl */
+ return(dbl_to_sgl_fcnvfx(&fpregs[r1],0,
+ &fpregs[t],status));
+ case 3: /* dbl/dbl */
+ return(dbl_to_dbl_fcnvfx(&fpregs[r1],0,
+ &fpregs[t],status));
+ }
+ BUG();
+ case 3: /* FCNVFXT */
+ switch(fmt) {
+ case 0: /* sgl/sgl */
+ return(sgl_to_sgl_fcnvfxt(&fpregs[r1],0,
+ &fpregs[t],status));
+ case 1: /* sgl/dbl */
+ return(sgl_to_dbl_fcnvfxt(&fpregs[r1],0,
+ &fpregs[t],status));
+ case 2: /* dbl/sgl */
+ return(dbl_to_sgl_fcnvfxt(&fpregs[r1],0,
+ &fpregs[t],status));
+ case 3: /* dbl/dbl */
+ return(dbl_to_dbl_fcnvfxt(&fpregs[r1],0,
+ &fpregs[t],status));
+ }
+ BUG();
+ case 5: /* FCNVUF (PA2.0 only) */
+ switch(fmt) {
+ case 0: /* sgl/sgl */
+ return(sgl_to_sgl_fcnvuf(&fpregs[r1],0,
+ &fpregs[t],status));
+ case 1: /* sgl/dbl */
+ return(sgl_to_dbl_fcnvuf(&fpregs[r1],0,
+ &fpregs[t],status));
+ case 2: /* dbl/sgl */
+ return(dbl_to_sgl_fcnvuf(&fpregs[r1],0,
+ &fpregs[t],status));
+ case 3: /* dbl/dbl */
+ return(dbl_to_dbl_fcnvuf(&fpregs[r1],0,
+ &fpregs[t],status));
+ }
+ BUG();
+ case 6: /* FCNVFU (PA2.0 only) */
+ switch(fmt) {
+ case 0: /* sgl/sgl */
+ return(sgl_to_sgl_fcnvfu(&fpregs[r1],0,
+ &fpregs[t],status));
+ case 1: /* sgl/dbl */
+ return(sgl_to_dbl_fcnvfu(&fpregs[r1],0,
+ &fpregs[t],status));
+ case 2: /* dbl/sgl */
+ return(dbl_to_sgl_fcnvfu(&fpregs[r1],0,
+ &fpregs[t],status));
+ case 3: /* dbl/dbl */
+ return(dbl_to_dbl_fcnvfu(&fpregs[r1],0,
+ &fpregs[t],status));
+ }
+ BUG();
+ case 7: /* FCNVFUT (PA2.0 only) */
+ switch(fmt) {
+ case 0: /* sgl/sgl */
+ return(sgl_to_sgl_fcnvfut(&fpregs[r1],0,
+ &fpregs[t],status));
+ case 1: /* sgl/dbl */
+ return(sgl_to_dbl_fcnvfut(&fpregs[r1],0,
+ &fpregs[t],status));
+ case 2: /* dbl/sgl */
+ return(dbl_to_sgl_fcnvfut(&fpregs[r1],0,
+ &fpregs[t],status));
+ case 3: /* dbl/dbl */
+ return(dbl_to_dbl_fcnvfut(&fpregs[r1],0,
+ &fpregs[t],status));
+ }
+ BUG();
+ case 4: /* undefined */
+ return(MAJOR_0C_EXCP);
+ } /* end of switch subop */
+ BUG();
+ case 2: /* class 2 */
+ fpu_type_flags=fpregs[FPU_TYPE_FLAG_POS];
+ r2 = extru(ir, fpr2pos, 5) * sizeof(double)/sizeof(u_int);
+ if (r2 == 0)
+ r2 = fpzeroreg;
+ if (fpu_type_flags & PA2_0_FPU_FLAG) {
+ /* FTEST if nullify bit set, otherwise FCMP */
+ if (extru(ir, fpnulpos, 1)) { /* FTEST */
+ switch (fmt) {
+ case 0:
+ /*
+ * arg0 is not used
+ * second param is the t field used for
+ * ftest,acc and ftest,rej
+ * third param is the subop (y-field)
+ */
+ BUG();
+ /* Unsupported
+ * return(ftest(0L,extru(ir,fptpos,5),
+ * &fpregs[0],subop));
+ */
+ case 1:
+ case 2:
+ case 3:
+ return(MAJOR_0C_EXCP);
+ }
+ } else { /* FCMP */
+ switch (fmt) {
+ case 0:
+ retval = sgl_fcmp(&fpregs[r1],
+ &fpregs[r2],extru(ir,fptpos,5),
+ &local_status);
+ update_status_cbit(status,local_status,
+ fpu_type_flags, subop);
+ return(retval);
+ case 1:
+ retval = dbl_fcmp(&fpregs[r1],
+ &fpregs[r2],extru(ir,fptpos,5),
+ &local_status);
+ update_status_cbit(status,local_status,
+ fpu_type_flags, subop);
+ return(retval);
+ case 2: /* illegal */
+ case 3: /* quad not implemented */
+ return(MAJOR_0C_EXCP);
+ }
+ }
+ } /* end of if for PA2.0 */
+ else { /* PA1.0 & PA1.1 */
+ switch (subop) {
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ return(MAJOR_0C_EXCP);
+ case 0: /* FCMP */
+ switch (fmt) {
+ case 0:
+ retval = sgl_fcmp(&fpregs[r1],
+ &fpregs[r2],extru(ir,fptpos,5),
+ &local_status);
+ update_status_cbit(status,local_status,
+ fpu_type_flags, subop);
+ return(retval);
+ case 1:
+ retval = dbl_fcmp(&fpregs[r1],
+ &fpregs[r2],extru(ir,fptpos,5),
+ &local_status);
+ update_status_cbit(status,local_status,
+ fpu_type_flags, subop);
+ return(retval);
+ case 2: /* illegal */
+ case 3: /* quad not implemented */
+ return(MAJOR_0C_EXCP);
+ }
+ BUG();
+ case 1: /* FTEST */
+ switch (fmt) {
+ case 0:
+ /*
+ * arg0 is not used
+ * second param is the t field used for
+ * ftest,acc and ftest,rej
+ * third param is the subop (y-field)
+ */
+ BUG();
+ /* unsupported
+ * return(ftest(0L,extru(ir,fptpos,5),
+ * &fpregs[0],subop));
+ */
+ case 1:
+ case 2:
+ case 3:
+ return(MAJOR_0C_EXCP);
+ }
+ BUG();
+ } /* end of switch subop */
+ } /* end of else for PA1.0 & PA1.1 */
+ BUG();
+ case 3: /* class 3 */
+ r2 = extru(ir,fpr2pos,5) * sizeof(double)/sizeof(u_int);
+ if (r2 == 0)
+ r2 = fpzeroreg;
+ switch (subop) {
+ case 5:
+ case 6:
+ case 7:
+ return(MAJOR_0C_EXCP);
+
+ case 0: /* FADD */
+ switch (fmt) {
+ case 0:
+ return(sgl_fadd(&fpregs[r1],&fpregs[r2],
+ &fpregs[t],status));
+ case 1:
+ return(dbl_fadd(&fpregs[r1],&fpregs[r2],
+ &fpregs[t],status));
+ case 2: /* illegal */
+ case 3: /* quad not implemented */
+ return(MAJOR_0C_EXCP);
+ }
+ BUG();
+ case 1: /* FSUB */
+ switch (fmt) {
+ case 0:
+ return(sgl_fsub(&fpregs[r1],&fpregs[r2],
+ &fpregs[t],status));
+ case 1:
+ return(dbl_fsub(&fpregs[r1],&fpregs[r2],
+ &fpregs[t],status));
+ case 2: /* illegal */
+ case 3: /* quad not implemented */
+ return(MAJOR_0C_EXCP);
+ }
+ BUG();
+ case 2: /* FMPY */
+ switch (fmt) {
+ case 0:
+ return(sgl_fmpy(&fpregs[r1],&fpregs[r2],
+ &fpregs[t],status));
+ case 1:
+ return(dbl_fmpy(&fpregs[r1],&fpregs[r2],
+ &fpregs[t],status));
+ case 2: /* illegal */
+ case 3: /* quad not implemented */
+ return(MAJOR_0C_EXCP);
+ }
+ BUG();
+ case 3: /* FDIV */
+ switch (fmt) {
+ case 0:
+ return(sgl_fdiv(&fpregs[r1],&fpregs[r2],
+ &fpregs[t],status));
+ case 1:
+ return(dbl_fdiv(&fpregs[r1],&fpregs[r2],
+ &fpregs[t],status));
+ case 2: /* illegal */
+ case 3: /* quad not implemented */
+ return(MAJOR_0C_EXCP);
+ }
+ BUG();
+ case 4: /* FREM */
+ switch (fmt) {
+ case 0:
+ return(sgl_frem(&fpregs[r1],&fpregs[r2],
+ &fpregs[t],status));
+ case 1:
+ return(dbl_frem(&fpregs[r1],&fpregs[r2],
+ &fpregs[t],status));
+ case 2: /* illegal */
+ case 3: /* quad not implemented */
+ return(MAJOR_0C_EXCP);
+ }
+ BUG();
+ } /* end of class 3 switch */
+ } /* end of switch(class) */
+
+ /* If we get here, something is really wrong! */
+ return(MAJOR_0C_EXCP);
+}
+
+static u_int
+decode_0e(ir,class,subop,fpregs)
+u_int ir,class,subop;
+u_int fpregs[];
+{
+ u_int r1,r2,t; /* operand register offsets */
+ u_int fmt; /* also sf for class 1 conversions */
+ u_int df; /* dest format for class 1 conversions */
+ u_int *status;
+ u_int retval, local_status;
+ u_int fpu_type_flags;
+
+ status = &fpregs[0];
+ local_status = fpregs[0];
+ r1 = ((extru(ir,fpr1pos,5)<<1)|(extru(ir,fpxr1pos,1)));
+ if (r1 == 0)
+ r1 = fpzeroreg;
+ t = ((extru(ir,fptpos,5)<<1)|(extru(ir,fpxtpos,1)));
+ if (t == 0 && class != 2)
+ return(MAJOR_0E_EXCP);
+ if (class < 2) /* class 0 or 1 has 2 bit fmt */
+ fmt = extru(ir,fpfmtpos,2);
+ else /* class 2 and 3 have 1 bit fmt */
+ fmt = extru(ir,fp0efmtpos,1);
+ /*
+ * An undefined combination, double precision accessing the
+ * right half of a FPR, can get us into trouble.
+ * Let's just force proper alignment on it.
+ */
+ if (fmt == DBL) {
+ r1 &= ~1;
+ if (class != 1)
+ t &= ~1;
+ }
+
+ switch (class) {
+ case 0:
+ switch (subop) {
+ case 0: /* unimplemented */
+ case 1:
+ return(MAJOR_0E_EXCP);
+ case 2: /* FCPY */
+ switch (fmt) {
+ case 2:
+ case 3:
+ return(MAJOR_0E_EXCP);
+ case 1: /* double */
+ fpregs[t+1] = fpregs[r1+1];
+ fallthrough;
+ case 0: /* single */
+ fpregs[t] = fpregs[r1];
+ return(NOEXCEPTION);
+ }
+ BUG();
+ case 3: /* FABS */
+ switch (fmt) {
+ case 2:
+ case 3:
+ return(MAJOR_0E_EXCP);
+ case 1: /* double */
+ fpregs[t+1] = fpregs[r1+1];
+ fallthrough;
+ case 0: /* single */
+ fpregs[t] = fpregs[r1] & 0x7fffffff;
+ return(NOEXCEPTION);
+ }
+ BUG();
+ case 6: /* FNEG */
+ switch (fmt) {
+ case 2:
+ case 3:
+ return(MAJOR_0E_EXCP);
+ case 1: /* double */
+ fpregs[t+1] = fpregs[r1+1];
+ fallthrough;
+ case 0: /* single */
+ fpregs[t] = fpregs[r1] ^ 0x80000000;
+ return(NOEXCEPTION);
+ }
+ BUG();
+ case 7: /* FNEGABS */
+ switch (fmt) {
+ case 2:
+ case 3:
+ return(MAJOR_0E_EXCP);
+ case 1: /* double */
+ fpregs[t+1] = fpregs[r1+1];
+ fallthrough;
+ case 0: /* single */
+ fpregs[t] = fpregs[r1] | 0x80000000;
+ return(NOEXCEPTION);
+ }
+ BUG();
+ case 4: /* FSQRT */
+ switch (fmt) {
+ case 0:
+ return(sgl_fsqrt(&fpregs[r1],0,
+ &fpregs[t], status));
+ case 1:
+ return(dbl_fsqrt(&fpregs[r1],0,
+ &fpregs[t], status));
+ case 2:
+ case 3:
+ return(MAJOR_0E_EXCP);
+ }
+ BUG();
+ case 5: /* FRMD */
+ switch (fmt) {
+ case 0:
+ return(sgl_frnd(&fpregs[r1],0,
+ &fpregs[t], status));
+ case 1:
+ return(dbl_frnd(&fpregs[r1],0,
+ &fpregs[t], status));
+ case 2:
+ case 3:
+ return(MAJOR_0E_EXCP);
+ }
+ } /* end of switch (subop */
+ BUG();
+ case 1: /* class 1 */
+ df = extru(ir,fpdfpos,2); /* get dest format */
+ /*
+ * Fix Crashme problem (writing to 31R in double precision)
+ * here too.
+ */
+ if (df == DBL) {
+ t &= ~1;
+ }
+ if ((df & 2) || (fmt & 2))
+ return(MAJOR_0E_EXCP);
+
+ fmt = (fmt << 1) | df;
+ switch (subop) {
+ case 0: /* FCNVFF */
+ switch(fmt) {
+ case 0: /* sgl/sgl */
+ return(MAJOR_0E_EXCP);
+ case 1: /* sgl/dbl */
+ return(sgl_to_dbl_fcnvff(&fpregs[r1],0,
+ &fpregs[t],status));
+ case 2: /* dbl/sgl */
+ return(dbl_to_sgl_fcnvff(&fpregs[r1],0,
+ &fpregs[t],status));
+ case 3: /* dbl/dbl */
+ return(MAJOR_0E_EXCP);
+ }
+ BUG();
+ case 1: /* FCNVXF */
+ switch(fmt) {
+ case 0: /* sgl/sgl */
+ return(sgl_to_sgl_fcnvxf(&fpregs[r1],0,
+ &fpregs[t],status));
+ case 1: /* sgl/dbl */
+ return(sgl_to_dbl_fcnvxf(&fpregs[r1],0,
+ &fpregs[t],status));
+ case 2: /* dbl/sgl */
+ return(dbl_to_sgl_fcnvxf(&fpregs[r1],0,
+ &fpregs[t],status));
+ case 3: /* dbl/dbl */
+ return(dbl_to_dbl_fcnvxf(&fpregs[r1],0,
+ &fpregs[t],status));
+ }
+ BUG();
+ case 2: /* FCNVFX */
+ switch(fmt) {
+ case 0: /* sgl/sgl */
+ return(sgl_to_sgl_fcnvfx(&fpregs[r1],0,
+ &fpregs[t],status));
+ case 1: /* sgl/dbl */
+ return(sgl_to_dbl_fcnvfx(&fpregs[r1],0,
+ &fpregs[t],status));
+ case 2: /* dbl/sgl */
+ return(dbl_to_sgl_fcnvfx(&fpregs[r1],0,
+ &fpregs[t],status));
+ case 3: /* dbl/dbl */
+ return(dbl_to_dbl_fcnvfx(&fpregs[r1],0,
+ &fpregs[t],status));
+ }
+ BUG();
+ case 3: /* FCNVFXT */
+ switch(fmt) {
+ case 0: /* sgl/sgl */
+ return(sgl_to_sgl_fcnvfxt(&fpregs[r1],0,
+ &fpregs[t],status));
+ case 1: /* sgl/dbl */
+ return(sgl_to_dbl_fcnvfxt(&fpregs[r1],0,
+ &fpregs[t],status));
+ case 2: /* dbl/sgl */
+ return(dbl_to_sgl_fcnvfxt(&fpregs[r1],0,
+ &fpregs[t],status));
+ case 3: /* dbl/dbl */
+ return(dbl_to_dbl_fcnvfxt(&fpregs[r1],0,
+ &fpregs[t],status));
+ }
+ BUG();
+ case 5: /* FCNVUF (PA2.0 only) */
+ switch(fmt) {
+ case 0: /* sgl/sgl */
+ return(sgl_to_sgl_fcnvuf(&fpregs[r1],0,
+ &fpregs[t],status));
+ case 1: /* sgl/dbl */
+ return(sgl_to_dbl_fcnvuf(&fpregs[r1],0,
+ &fpregs[t],status));
+ case 2: /* dbl/sgl */
+ return(dbl_to_sgl_fcnvuf(&fpregs[r1],0,
+ &fpregs[t],status));
+ case 3: /* dbl/dbl */
+ return(dbl_to_dbl_fcnvuf(&fpregs[r1],0,
+ &fpregs[t],status));
+ }
+ BUG();
+ case 6: /* FCNVFU (PA2.0 only) */
+ switch(fmt) {
+ case 0: /* sgl/sgl */
+ return(sgl_to_sgl_fcnvfu(&fpregs[r1],0,
+ &fpregs[t],status));
+ case 1: /* sgl/dbl */
+ return(sgl_to_dbl_fcnvfu(&fpregs[r1],0,
+ &fpregs[t],status));
+ case 2: /* dbl/sgl */
+ return(dbl_to_sgl_fcnvfu(&fpregs[r1],0,
+ &fpregs[t],status));
+ case 3: /* dbl/dbl */
+ return(dbl_to_dbl_fcnvfu(&fpregs[r1],0,
+ &fpregs[t],status));
+ }
+ BUG();
+ case 7: /* FCNVFUT (PA2.0 only) */
+ switch(fmt) {
+ case 0: /* sgl/sgl */
+ return(sgl_to_sgl_fcnvfut(&fpregs[r1],0,
+ &fpregs[t],status));
+ case 1: /* sgl/dbl */
+ return(sgl_to_dbl_fcnvfut(&fpregs[r1],0,
+ &fpregs[t],status));
+ case 2: /* dbl/sgl */
+ return(dbl_to_sgl_fcnvfut(&fpregs[r1],0,
+ &fpregs[t],status));
+ case 3: /* dbl/dbl */
+ return(dbl_to_dbl_fcnvfut(&fpregs[r1],0,
+ &fpregs[t],status));
+ }
+ BUG();
+ case 4: /* undefined */
+ return(MAJOR_0C_EXCP);
+ } /* end of switch subop */
+ BUG();
+ case 2: /* class 2 */
+ /*
+ * Be careful out there.
+ * Crashme can generate cases where FR31R is specified
+ * as the source or target of a double precision operation.
+ * Since we just pass the address of the floating-point
+ * register to the emulation routines, this can cause
+ * corruption of fpzeroreg.
+ */
+ if (fmt == DBL)
+ r2 = (extru(ir,fpr2pos,5)<<1);
+ else
+ r2 = ((extru(ir,fpr2pos,5)<<1)|(extru(ir,fpxr2pos,1)));
+ fpu_type_flags=fpregs[FPU_TYPE_FLAG_POS];
+ if (r2 == 0)
+ r2 = fpzeroreg;
+ if (fpu_type_flags & PA2_0_FPU_FLAG) {
+ /* FTEST if nullify bit set, otherwise FCMP */
+ if (extru(ir, fpnulpos, 1)) { /* FTEST */
+ /* not legal */
+ return(MAJOR_0E_EXCP);
+ } else { /* FCMP */
+ switch (fmt) {
+ /*
+ * fmt is only 1 bit long
+ */
+ case 0:
+ retval = sgl_fcmp(&fpregs[r1],
+ &fpregs[r2],extru(ir,fptpos,5),
+ &local_status);
+ update_status_cbit(status,local_status,
+ fpu_type_flags, subop);
+ return(retval);
+ case 1:
+ retval = dbl_fcmp(&fpregs[r1],
+ &fpregs[r2],extru(ir,fptpos,5),
+ &local_status);
+ update_status_cbit(status,local_status,
+ fpu_type_flags, subop);
+ return(retval);
+ }
+ }
+ } /* end of if for PA2.0 */
+ else { /* PA1.0 & PA1.1 */
+ switch (subop) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ return(MAJOR_0E_EXCP);
+ case 0: /* FCMP */
+ switch (fmt) {
+ /*
+ * fmt is only 1 bit long
+ */
+ case 0:
+ retval = sgl_fcmp(&fpregs[r1],
+ &fpregs[r2],extru(ir,fptpos,5),
+ &local_status);
+ update_status_cbit(status,local_status,
+ fpu_type_flags, subop);
+ return(retval);
+ case 1:
+ retval = dbl_fcmp(&fpregs[r1],
+ &fpregs[r2],extru(ir,fptpos,5),
+ &local_status);
+ update_status_cbit(status,local_status,
+ fpu_type_flags, subop);
+ return(retval);
+ }
+ } /* end of switch subop */
+ } /* end of else for PA1.0 & PA1.1 */
+ BUG();
+ case 3: /* class 3 */
+ /*
+ * Be careful out there.
+ * Crashme can generate cases where FR31R is specified
+ * as the source or target of a double precision operation.
+ * Since we just pass the address of the floating-point
+ * register to the emulation routines, this can cause
+ * corruption of fpzeroreg.
+ */
+ if (fmt == DBL)
+ r2 = (extru(ir,fpr2pos,5)<<1);
+ else
+ r2 = ((extru(ir,fpr2pos,5)<<1)|(extru(ir,fpxr2pos,1)));
+ if (r2 == 0)
+ r2 = fpzeroreg;
+ switch (subop) {
+ case 5:
+ case 6:
+ case 7:
+ return(MAJOR_0E_EXCP);
+
+ /*
+ * Note that fmt is only 1 bit for class 3 */
+ case 0: /* FADD */
+ switch (fmt) {
+ case 0:
+ return(sgl_fadd(&fpregs[r1],&fpregs[r2],
+ &fpregs[t],status));
+ case 1:
+ return(dbl_fadd(&fpregs[r1],&fpregs[r2],
+ &fpregs[t],status));
+ }
+ BUG();
+ case 1: /* FSUB */
+ switch (fmt) {
+ case 0:
+ return(sgl_fsub(&fpregs[r1],&fpregs[r2],
+ &fpregs[t],status));
+ case 1:
+ return(dbl_fsub(&fpregs[r1],&fpregs[r2],
+ &fpregs[t],status));
+ }
+ BUG();
+ case 2: /* FMPY or XMPYU */
+ /*
+ * check for integer multiply (x bit set)
+ */
+ if (extru(ir,fpxpos,1)) {
+ /*
+ * emulate XMPYU
+ */
+ switch (fmt) {
+ case 0:
+ /*
+ * bad instruction if t specifies
+ * the right half of a register
+ */
+ if (t & 1)
+ return(MAJOR_0E_EXCP);
+ BUG();
+ /* unsupported
+ * impyu(&fpregs[r1],&fpregs[r2],
+ * &fpregs[t]);
+ */
+ return(NOEXCEPTION);
+ case 1:
+ return(MAJOR_0E_EXCP);
+ }
+ }
+ else { /* FMPY */
+ switch (fmt) {
+ case 0:
+ return(sgl_fmpy(&fpregs[r1],
+ &fpregs[r2],&fpregs[t],status));
+ case 1:
+ return(dbl_fmpy(&fpregs[r1],
+ &fpregs[r2],&fpregs[t],status));
+ }
+ }
+ BUG();
+ case 3: /* FDIV */
+ switch (fmt) {
+ case 0:
+ return(sgl_fdiv(&fpregs[r1],&fpregs[r2],
+ &fpregs[t],status));
+ case 1:
+ return(dbl_fdiv(&fpregs[r1],&fpregs[r2],
+ &fpregs[t],status));
+ }
+ BUG();
+ case 4: /* FREM */
+ switch (fmt) {
+ case 0:
+ return(sgl_frem(&fpregs[r1],&fpregs[r2],
+ &fpregs[t],status));
+ case 1:
+ return(dbl_frem(&fpregs[r1],&fpregs[r2],
+ &fpregs[t],status));
+ }
+ } /* end of class 3 switch */
+ } /* end of switch(class) */
+
+ /* If we get here, something is really wrong! */
+ return(MAJOR_0E_EXCP);
+}
+
+
+/*
+ * routine to decode the 06 (FMPYADD and FMPYCFXT) instruction
+ */
+static u_int
+decode_06(ir,fpregs)
+u_int ir;
+u_int fpregs[];
+{
+ u_int rm1, rm2, tm, ra, ta; /* operands */
+ u_int fmt;
+ u_int error = 0;
+ u_int status;
+ u_int fpu_type_flags;
+ union {
+ double dbl;
+ float flt;
+ struct { u_int i1; u_int i2; } ints;
+ } mtmp, atmp;
+
+
+ status = fpregs[0]; /* use a local copy of status reg */
+ fpu_type_flags=fpregs[FPU_TYPE_FLAG_POS]; /* get fpu type flags */
+ fmt = extru(ir, fpmultifmt, 1); /* get sgl/dbl flag */
+ if (fmt == 0) { /* DBL */
+ rm1 = extru(ir, fprm1pos, 5) * sizeof(double)/sizeof(u_int);
+ if (rm1 == 0)
+ rm1 = fpzeroreg;
+ rm2 = extru(ir, fprm2pos, 5) * sizeof(double)/sizeof(u_int);
+ if (rm2 == 0)
+ rm2 = fpzeroreg;
+ tm = extru(ir, fptmpos, 5) * sizeof(double)/sizeof(u_int);
+ if (tm == 0)
+ return(MAJOR_06_EXCP);
+ ra = extru(ir, fprapos, 5) * sizeof(double)/sizeof(u_int);
+ ta = extru(ir, fptapos, 5) * sizeof(double)/sizeof(u_int);
+ if (ta == 0)
+ return(MAJOR_06_EXCP);
+
+ if (fpu_type_flags & TIMEX_ROLEX_FPU_MASK) {
+
+ if (ra == 0) {
+ /* special case FMPYCFXT, see sgl case below */
+ if (dbl_fmpy(&fpregs[rm1],&fpregs[rm2],
+ &mtmp.ints.i1,&status))
+ error = 1;
+ if (dbl_to_sgl_fcnvfxt(&fpregs[ta],
+ &atmp.ints.i1,&atmp.ints.i1,&status))
+ error = 1;
+ }
+ else {
+
+ if (dbl_fmpy(&fpregs[rm1],&fpregs[rm2],&mtmp.ints.i1,
+ &status))
+ error = 1;
+ if (dbl_fadd(&fpregs[ta], &fpregs[ra], &atmp.ints.i1,
+ &status))
+ error = 1;
+ }
+ }
+
+ else
+
+ {
+ if (ra == 0)
+ ra = fpzeroreg;
+
+ if (dbl_fmpy(&fpregs[rm1],&fpregs[rm2],&mtmp.ints.i1,
+ &status))
+ error = 1;
+ if (dbl_fadd(&fpregs[ta], &fpregs[ra], &atmp.ints.i1,
+ &status))
+ error = 1;
+
+ }
+
+ if (error)
+ return(MAJOR_06_EXCP);
+ else {
+ /* copy results */
+ fpregs[tm] = mtmp.ints.i1;
+ fpregs[tm+1] = mtmp.ints.i2;
+ fpregs[ta] = atmp.ints.i1;
+ fpregs[ta+1] = atmp.ints.i2;
+ fpregs[0] = status;
+ return(NOEXCEPTION);
+ }
+ }
+ else { /* SGL */
+ /*
+ * calculate offsets for single precision numbers
+ * See table 6-14 in PA-89 architecture for mapping
+ */
+ rm1 = (extru(ir,fprm1pos,4) | 0x10 ) << 1; /* get offset */
+ rm1 |= extru(ir,fprm1pos-4,1); /* add right word offset */
+
+ rm2 = (extru(ir,fprm2pos,4) | 0x10 ) << 1; /* get offset */
+ rm2 |= extru(ir,fprm2pos-4,1); /* add right word offset */
+
+ tm = (extru(ir,fptmpos,4) | 0x10 ) << 1; /* get offset */
+ tm |= extru(ir,fptmpos-4,1); /* add right word offset */
+
+ ra = (extru(ir,fprapos,4) | 0x10 ) << 1; /* get offset */
+ ra |= extru(ir,fprapos-4,1); /* add right word offset */
+
+ ta = (extru(ir,fptapos,4) | 0x10 ) << 1; /* get offset */
+ ta |= extru(ir,fptapos-4,1); /* add right word offset */
+
+ if (ra == 0x20 &&(fpu_type_flags & TIMEX_ROLEX_FPU_MASK)) {
+ /* special case FMPYCFXT (really 0)
+ * This instruction is only present on the Timex and
+ * Rolex fpu's in so if it is the special case and
+ * one of these fpu's we run the FMPYCFXT instruction
+ */
+ if (sgl_fmpy(&fpregs[rm1],&fpregs[rm2],&mtmp.ints.i1,
+ &status))
+ error = 1;
+ if (sgl_to_sgl_fcnvfxt(&fpregs[ta],&atmp.ints.i1,
+ &atmp.ints.i1,&status))
+ error = 1;
+ }
+ else {
+ if (sgl_fmpy(&fpregs[rm1],&fpregs[rm2],&mtmp.ints.i1,
+ &status))
+ error = 1;
+ if (sgl_fadd(&fpregs[ta], &fpregs[ra], &atmp.ints.i1,
+ &status))
+ error = 1;
+ }
+ if (error)
+ return(MAJOR_06_EXCP);
+ else {
+ /* copy results */
+ fpregs[tm] = mtmp.ints.i1;
+ fpregs[ta] = atmp.ints.i1;
+ fpregs[0] = status;
+ return(NOEXCEPTION);
+ }
+ }
+}
+
+/*
+ * routine to decode the 26 (FMPYSUB) instruction
+ */
+static u_int
+decode_26(ir,fpregs)
+u_int ir;
+u_int fpregs[];
+{
+ u_int rm1, rm2, tm, ra, ta; /* operands */
+ u_int fmt;
+ u_int error = 0;
+ u_int status;
+ union {
+ double dbl;
+ float flt;
+ struct { u_int i1; u_int i2; } ints;
+ } mtmp, atmp;
+
+
+ status = fpregs[0];
+ fmt = extru(ir, fpmultifmt, 1); /* get sgl/dbl flag */
+ if (fmt == 0) { /* DBL */
+ rm1 = extru(ir, fprm1pos, 5) * sizeof(double)/sizeof(u_int);
+ if (rm1 == 0)
+ rm1 = fpzeroreg;
+ rm2 = extru(ir, fprm2pos, 5) * sizeof(double)/sizeof(u_int);
+ if (rm2 == 0)
+ rm2 = fpzeroreg;
+ tm = extru(ir, fptmpos, 5) * sizeof(double)/sizeof(u_int);
+ if (tm == 0)
+ return(MAJOR_26_EXCP);
+ ra = extru(ir, fprapos, 5) * sizeof(double)/sizeof(u_int);
+ if (ra == 0)
+ return(MAJOR_26_EXCP);
+ ta = extru(ir, fptapos, 5) * sizeof(double)/sizeof(u_int);
+ if (ta == 0)
+ return(MAJOR_26_EXCP);
+
+ if (dbl_fmpy(&fpregs[rm1],&fpregs[rm2],&mtmp.ints.i1,&status))
+ error = 1;
+ if (dbl_fsub(&fpregs[ta], &fpregs[ra], &atmp.ints.i1,&status))
+ error = 1;
+ if (error)
+ return(MAJOR_26_EXCP);
+ else {
+ /* copy results */
+ fpregs[tm] = mtmp.ints.i1;
+ fpregs[tm+1] = mtmp.ints.i2;
+ fpregs[ta] = atmp.ints.i1;
+ fpregs[ta+1] = atmp.ints.i2;
+ fpregs[0] = status;
+ return(NOEXCEPTION);
+ }
+ }
+ else { /* SGL */
+ /*
+ * calculate offsets for single precision numbers
+ * See table 6-14 in PA-89 architecture for mapping
+ */
+ rm1 = (extru(ir,fprm1pos,4) | 0x10 ) << 1; /* get offset */
+ rm1 |= extru(ir,fprm1pos-4,1); /* add right word offset */
+
+ rm2 = (extru(ir,fprm2pos,4) | 0x10 ) << 1; /* get offset */
+ rm2 |= extru(ir,fprm2pos-4,1); /* add right word offset */
+
+ tm = (extru(ir,fptmpos,4) | 0x10 ) << 1; /* get offset */
+ tm |= extru(ir,fptmpos-4,1); /* add right word offset */
+
+ ra = (extru(ir,fprapos,4) | 0x10 ) << 1; /* get offset */
+ ra |= extru(ir,fprapos-4,1); /* add right word offset */
+
+ ta = (extru(ir,fptapos,4) | 0x10 ) << 1; /* get offset */
+ ta |= extru(ir,fptapos-4,1); /* add right word offset */
+
+ if (sgl_fmpy(&fpregs[rm1],&fpregs[rm2],&mtmp.ints.i1,&status))
+ error = 1;
+ if (sgl_fsub(&fpregs[ta], &fpregs[ra], &atmp.ints.i1,&status))
+ error = 1;
+ if (error)
+ return(MAJOR_26_EXCP);
+ else {
+ /* copy results */
+ fpregs[tm] = mtmp.ints.i1;
+ fpregs[ta] = atmp.ints.i1;
+ fpregs[0] = status;
+ return(NOEXCEPTION);
+ }
+ }
+
+}
+
+/*
+ * routine to decode the 2E (FMPYFADD,FMPYNFADD) instructions
+ */
+static u_int
+decode_2e(ir,fpregs)
+u_int ir;
+u_int fpregs[];
+{
+ u_int rm1, rm2, ra, t; /* operands */
+ u_int fmt;
+
+ fmt = extru(ir,fpfmtpos,1); /* get fmt completer */
+ if (fmt == DBL) { /* DBL */
+ rm1 = extru(ir,fprm1pos,5) * sizeof(double)/sizeof(u_int);
+ if (rm1 == 0)
+ rm1 = fpzeroreg;
+ rm2 = extru(ir,fprm2pos,5) * sizeof(double)/sizeof(u_int);
+ if (rm2 == 0)
+ rm2 = fpzeroreg;
+ ra = ((extru(ir,fpraupos,3)<<2)|(extru(ir,fpralpos,3)>>1)) *
+ sizeof(double)/sizeof(u_int);
+ if (ra == 0)
+ ra = fpzeroreg;
+ t = extru(ir,fptpos,5) * sizeof(double)/sizeof(u_int);
+ if (t == 0)
+ return(MAJOR_2E_EXCP);
+
+ if (extru(ir,fpfusedsubop,1)) { /* fmpyfadd or fmpynfadd? */
+ return(dbl_fmpynfadd(&fpregs[rm1], &fpregs[rm2],
+ &fpregs[ra], &fpregs[0], &fpregs[t]));
+ } else {
+ return(dbl_fmpyfadd(&fpregs[rm1], &fpregs[rm2],
+ &fpregs[ra], &fpregs[0], &fpregs[t]));
+ }
+ } /* end DBL */
+ else { /* SGL */
+ rm1 = (extru(ir,fprm1pos,5)<<1)|(extru(ir,fpxrm1pos,1));
+ if (rm1 == 0)
+ rm1 = fpzeroreg;
+ rm2 = (extru(ir,fprm2pos,5)<<1)|(extru(ir,fpxrm2pos,1));
+ if (rm2 == 0)
+ rm2 = fpzeroreg;
+ ra = (extru(ir,fpraupos,3)<<3)|extru(ir,fpralpos,3);
+ if (ra == 0)
+ ra = fpzeroreg;
+ t = ((extru(ir,fptpos,5)<<1)|(extru(ir,fpxtpos,1)));
+ if (t == 0)
+ return(MAJOR_2E_EXCP);
+
+ if (extru(ir,fpfusedsubop,1)) { /* fmpyfadd or fmpynfadd? */
+ return(sgl_fmpynfadd(&fpregs[rm1], &fpregs[rm2],
+ &fpregs[ra], &fpregs[0], &fpregs[t]));
+ } else {
+ return(sgl_fmpyfadd(&fpregs[rm1], &fpregs[rm2],
+ &fpregs[ra], &fpregs[0], &fpregs[t]));
+ }
+ } /* end SGL */
+}
+
+/*
+ * update_status_cbit
+ *
+ * This routine returns the correct FP status register value in
+ * *status, based on the C-bit & V-bit returned by the FCMP
+ * emulation routine in new_status. The architecture type
+ * (PA83, PA89 or PA2.0) is available in fpu_type. The y_field
+ * and the architecture type are used to determine what flavor
+ * of FCMP is being emulated.
+ */
+static void
+update_status_cbit(status, new_status, fpu_type, y_field)
+u_int *status, new_status;
+u_int fpu_type;
+u_int y_field;
+{
+ /*
+ * For PA89 FPU's which implement the Compare Queue and
+ * for PA2.0 FPU's, update the Compare Queue if the y-field = 0,
+ * otherwise update the specified bit in the Compare Array.
+ * Note that the y-field will always be 0 for non-PA2.0 FPU's.
+ */
+ if ((fpu_type & TIMEX_EXTEN_FLAG) ||
+ (fpu_type & ROLEX_EXTEN_FLAG) ||
+ (fpu_type & PA2_0_FPU_FLAG)) {
+ if (y_field == 0) {
+ *status = ((*status & 0x04000000) >> 5) | /* old Cbit */
+ ((*status & 0x003ff000) >> 1) | /* old CQ */
+ (new_status & 0xffc007ff); /* all other bits*/
+ } else {
+ *status = (*status & 0x04000000) | /* old Cbit */
+ ((new_status & 0x04000000) >> (y_field+4)) |
+ (new_status & ~0x04000000 & /* other bits */
+ ~(0x04000000 >> (y_field+4)));
+ }
+ }
+ /* if PA83, just update the C-bit */
+ else {
+ *status = new_status;
+ }
+}
diff --git a/arch/parisc/math-emu/frnd.c b/arch/parisc/math-emu/frnd.c
new file mode 100644
index 000000000..0b0e8493e
--- /dev/null
+++ b/arch/parisc/math-emu/frnd.c
@@ -0,0 +1,239 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ */
+/*
+ * BEGIN_DESC
+ *
+ * Purpose:
+ * Single Floating-point Round to Integer
+ * Double Floating-point Round to Integer
+ * Quad Floating-point Round to Integer (returns unimplemented)
+ *
+ * External Interfaces:
+ * dbl_frnd(srcptr,nullptr,dstptr,status)
+ * sgl_frnd(srcptr,nullptr,dstptr,status)
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+#include "dbl_float.h"
+#include "cnv_float.h"
+
+/*
+ * Single Floating-point Round to Integer
+ */
+
+/*ARGSUSED*/
+int
+sgl_frnd(sgl_floating_point *srcptr,
+ unsigned int *nullptr,
+ sgl_floating_point *dstptr,
+ unsigned int *status)
+{
+ register unsigned int src, result;
+ register int src_exponent;
+ register boolean inexact = FALSE;
+
+ src = *srcptr;
+ /*
+ * check source operand for NaN or infinity
+ */
+ if ((src_exponent = Sgl_exponent(src)) == SGL_INFINITY_EXPONENT) {
+ /*
+ * is signaling NaN?
+ */
+ if (Sgl_isone_signaling(src)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Sgl_set_quiet(src);
+ }
+ /*
+ * return quiet NaN or infinity
+ */
+ *dstptr = src;
+ return(NOEXCEPTION);
+ }
+ /*
+ * Need to round?
+ */
+ if ((src_exponent -= SGL_BIAS) >= SGL_P - 1) {
+ *dstptr = src;
+ return(NOEXCEPTION);
+ }
+ /*
+ * Generate result
+ */
+ if (src_exponent >= 0) {
+ Sgl_clear_exponent_set_hidden(src);
+ result = src;
+ Sgl_rightshift(result,(SGL_P-1) - (src_exponent));
+ /* check for inexact */
+ if (Sgl_isinexact_to_fix(src,src_exponent)) {
+ inexact = TRUE;
+ /* round result */
+ switch (Rounding_mode()) {
+ case ROUNDPLUS:
+ if (Sgl_iszero_sign(src)) Sgl_increment(result);
+ break;
+ case ROUNDMINUS:
+ if (Sgl_isone_sign(src)) Sgl_increment(result);
+ break;
+ case ROUNDNEAREST:
+ if (Sgl_isone_roundbit(src,src_exponent))
+ if (Sgl_isone_stickybit(src,src_exponent)
+ || (Sgl_isone_lowmantissa(result)))
+ Sgl_increment(result);
+ }
+ }
+ Sgl_leftshift(result,(SGL_P-1) - (src_exponent));
+ if (Sgl_isone_hiddenoverflow(result))
+ Sgl_set_exponent(result,src_exponent + (SGL_BIAS+1));
+ else Sgl_set_exponent(result,src_exponent + SGL_BIAS);
+ }
+ else {
+ result = src; /* set sign */
+ Sgl_setzero_exponentmantissa(result);
+ /* check for inexact */
+ if (Sgl_isnotzero_exponentmantissa(src)) {
+ inexact = TRUE;
+ /* round result */
+ switch (Rounding_mode()) {
+ case ROUNDPLUS:
+ if (Sgl_iszero_sign(src))
+ Sgl_set_exponent(result,SGL_BIAS);
+ break;
+ case ROUNDMINUS:
+ if (Sgl_isone_sign(src))
+ Sgl_set_exponent(result,SGL_BIAS);
+ break;
+ case ROUNDNEAREST:
+ if (src_exponent == -1)
+ if (Sgl_isnotzero_mantissa(src))
+ Sgl_set_exponent(result,SGL_BIAS);
+ }
+ }
+ }
+ *dstptr = result;
+ if (inexact) {
+ if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+ else Set_inexactflag();
+ }
+ return(NOEXCEPTION);
+}
+
+/*
+ * Double Floating-point Round to Integer
+ */
+
+/*ARGSUSED*/
+int
+dbl_frnd(
+ dbl_floating_point *srcptr,
+ unsigned int *nullptr,
+ dbl_floating_point *dstptr,
+ unsigned int *status)
+{
+ register unsigned int srcp1, srcp2, resultp1, resultp2;
+ register int src_exponent;
+ register boolean inexact = FALSE;
+
+ Dbl_copyfromptr(srcptr,srcp1,srcp2);
+ /*
+ * check source operand for NaN or infinity
+ */
+ if ((src_exponent = Dbl_exponent(srcp1)) == DBL_INFINITY_EXPONENT) {
+ /*
+ * is signaling NaN?
+ */
+ if (Dbl_isone_signaling(srcp1)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Dbl_set_quiet(srcp1);
+ }
+ /*
+ * return quiet NaN or infinity
+ */
+ Dbl_copytoptr(srcp1,srcp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /*
+ * Need to round?
+ */
+ if ((src_exponent -= DBL_BIAS) >= DBL_P - 1) {
+ Dbl_copytoptr(srcp1,srcp2,dstptr);
+ return(NOEXCEPTION);
+ }
+ /*
+ * Generate result
+ */
+ if (src_exponent >= 0) {
+ Dbl_clear_exponent_set_hidden(srcp1);
+ resultp1 = srcp1;
+ resultp2 = srcp2;
+ Dbl_rightshift(resultp1,resultp2,(DBL_P-1) - (src_exponent));
+ /* check for inexact */
+ if (Dbl_isinexact_to_fix(srcp1,srcp2,src_exponent)) {
+ inexact = TRUE;
+ /* round result */
+ switch (Rounding_mode()) {
+ case ROUNDPLUS:
+ if (Dbl_iszero_sign(srcp1))
+ Dbl_increment(resultp1,resultp2);
+ break;
+ case ROUNDMINUS:
+ if (Dbl_isone_sign(srcp1))
+ Dbl_increment(resultp1,resultp2);
+ break;
+ case ROUNDNEAREST:
+ if (Dbl_isone_roundbit(srcp1,srcp2,src_exponent))
+ if (Dbl_isone_stickybit(srcp1,srcp2,src_exponent)
+ || (Dbl_isone_lowmantissap2(resultp2)))
+ Dbl_increment(resultp1,resultp2);
+ }
+ }
+ Dbl_leftshift(resultp1,resultp2,(DBL_P-1) - (src_exponent));
+ if (Dbl_isone_hiddenoverflow(resultp1))
+ Dbl_set_exponent(resultp1,src_exponent + (DBL_BIAS+1));
+ else Dbl_set_exponent(resultp1,src_exponent + DBL_BIAS);
+ }
+ else {
+ resultp1 = srcp1; /* set sign */
+ Dbl_setzero_exponentmantissa(resultp1,resultp2);
+ /* check for inexact */
+ if (Dbl_isnotzero_exponentmantissa(srcp1,srcp2)) {
+ inexact = TRUE;
+ /* round result */
+ switch (Rounding_mode()) {
+ case ROUNDPLUS:
+ if (Dbl_iszero_sign(srcp1))
+ Dbl_set_exponent(resultp1,DBL_BIAS);
+ break;
+ case ROUNDMINUS:
+ if (Dbl_isone_sign(srcp1))
+ Dbl_set_exponent(resultp1,DBL_BIAS);
+ break;
+ case ROUNDNEAREST:
+ if (src_exponent == -1)
+ if (Dbl_isnotzero_mantissa(srcp1,srcp2))
+ Dbl_set_exponent(resultp1,DBL_BIAS);
+ }
+ }
+ }
+ Dbl_copytoptr(resultp1,resultp2,dstptr);
+ if (inexact) {
+ if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+ else Set_inexactflag();
+ }
+ return(NOEXCEPTION);
+}
diff --git a/arch/parisc/math-emu/hppa.h b/arch/parisc/math-emu/hppa.h
new file mode 100644
index 000000000..b25b266c9
--- /dev/null
+++ b/arch/parisc/math-emu/hppa.h
@@ -0,0 +1,29 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ */
+
+#ifdef __NO_PA_HDRS
+ PA header file -- do not include this header file for non-PA builds.
+#endif
+
+
+/* amount is assumed to be a constant between 0 and 32 (non-inclusive) */
+#define Shiftdouble(left,right,amount,dest) \
+ /* int left, right, amount, dest; */ \
+ dest = ((left) << (32-(amount))) | ((unsigned int)(right) >> (amount))
+
+/* amount must be less than 32 */
+#define Variableshiftdouble(left,right,amount,dest) \
+ /* unsigned int left, right; int amount, dest; */ \
+ if (amount == 0) dest = right; \
+ else dest = ((((unsigned) left)&0x7fffffff) << (32-(amount))) | \
+ ((unsigned) right >> (amount))
+
+/* amount must be between 0 and 32 (non-inclusive) */
+#define Variable_shift_double(left,right,amount,dest) \
+ /* unsigned int left, right; int amount, dest; */ \
+ dest = (left << (32-(amount))) | ((unsigned) right >> (amount))
diff --git a/arch/parisc/math-emu/math-emu.h b/arch/parisc/math-emu/math-emu.h
new file mode 100644
index 000000000..a7b6fac16
--- /dev/null
+++ b/arch/parisc/math-emu/math-emu.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ */
+#ifndef _PARISC_MATH_EMU_H
+#define _PARISC_MATH_EMU_H
+
+#include <asm/ptrace.h>
+extern int handle_fpe(struct pt_regs *regs);
+
+#endif
diff --git a/arch/parisc/math-emu/sfadd.c b/arch/parisc/math-emu/sfadd.c
new file mode 100644
index 000000000..9b98c874d
--- /dev/null
+++ b/arch/parisc/math-emu/sfadd.c
@@ -0,0 +1,505 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ */
+/*
+ * BEGIN_DESC
+ *
+ * File:
+ * @(#) pa/spmath/sfadd.c $Revision: 1.1 $
+ *
+ * Purpose:
+ * Single_add: add two single precision values.
+ *
+ * External Interfaces:
+ * sgl_fadd(leftptr, rightptr, dstptr, status)
+ *
+ * Internal Interfaces:
+ *
+ * Theory:
+ * <<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+
+/*
+ * Single_add: add two single precision values.
+ */
+int
+sgl_fadd(
+ sgl_floating_point *leftptr,
+ sgl_floating_point *rightptr,
+ sgl_floating_point *dstptr,
+ unsigned int *status)
+ {
+ register unsigned int left, right, result, extent;
+ register unsigned int signless_upper_left, signless_upper_right, save;
+
+
+ register int result_exponent, right_exponent, diff_exponent;
+ register int sign_save, jumpsize;
+ register boolean inexact = FALSE;
+ register boolean underflowtrap;
+
+ /* Create local copies of the numbers */
+ left = *leftptr;
+ right = *rightptr;
+
+ /* A zero "save" helps discover equal operands (for later), *
+ * and is used in swapping operands (if needed). */
+ Sgl_xortointp1(left,right,/*to*/save);
+
+ /*
+ * check first operand for NaN's or infinity
+ */
+ if ((result_exponent = Sgl_exponent(left)) == SGL_INFINITY_EXPONENT)
+ {
+ if (Sgl_iszero_mantissa(left))
+ {
+ if (Sgl_isnotnan(right))
+ {
+ if (Sgl_isinfinity(right) && save!=0)
+ {
+ /*
+ * invalid since operands are opposite signed infinity's
+ */
+ if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+ Set_invalidflag();
+ Sgl_makequietnan(result);
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+ /*
+ * return infinity
+ */
+ *dstptr = left;
+ return(NOEXCEPTION);
+ }
+ }
+ else
+ {
+ /*
+ * is NaN; signaling or quiet?
+ */
+ if (Sgl_isone_signaling(left))
+ {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Sgl_set_quiet(left);
+ }
+ /*
+ * is second operand a signaling NaN?
+ */
+ else if (Sgl_is_signalingnan(right))
+ {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Sgl_set_quiet(right);
+ *dstptr = right;
+ return(NOEXCEPTION);
+ }
+ /*
+ * return quiet NaN
+ */
+ *dstptr = left;
+ return(NOEXCEPTION);
+ }
+ } /* End left NaN or Infinity processing */
+ /*
+ * check second operand for NaN's or infinity
+ */
+ if (Sgl_isinfinity_exponent(right))
+ {
+ if (Sgl_iszero_mantissa(right))
+ {
+ /* return infinity */
+ *dstptr = right;
+ return(NOEXCEPTION);
+ }
+ /*
+ * is NaN; signaling or quiet?
+ */
+ if (Sgl_isone_signaling(right))
+ {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Sgl_set_quiet(right);
+ }
+ /*
+ * return quiet NaN
+ */
+ *dstptr = right;
+ return(NOEXCEPTION);
+ } /* End right NaN or Infinity processing */
+
+ /* Invariant: Must be dealing with finite numbers */
+
+ /* Compare operands by removing the sign */
+ Sgl_copytoint_exponentmantissa(left,signless_upper_left);
+ Sgl_copytoint_exponentmantissa(right,signless_upper_right);
+
+ /* sign difference selects add or sub operation. */
+ if(Sgl_ismagnitudeless(signless_upper_left,signless_upper_right))
+ {
+ /* Set the left operand to the larger one by XOR swap *
+ * First finish the first word using "save" */
+ Sgl_xorfromintp1(save,right,/*to*/right);
+ Sgl_xorfromintp1(save,left,/*to*/left);
+ result_exponent = Sgl_exponent(left);
+ }
+ /* Invariant: left is not smaller than right. */
+
+ if((right_exponent = Sgl_exponent(right)) == 0)
+ {
+ /* Denormalized operands. First look for zeroes */
+ if(Sgl_iszero_mantissa(right))
+ {
+ /* right is zero */
+ if(Sgl_iszero_exponentmantissa(left))
+ {
+ /* Both operands are zeros */
+ if(Is_rounding_mode(ROUNDMINUS))
+ {
+ Sgl_or_signs(left,/*with*/right);
+ }
+ else
+ {
+ Sgl_and_signs(left,/*with*/right);
+ }
+ }
+ else
+ {
+ /* Left is not a zero and must be the result. Trapped
+ * underflows are signaled if left is denormalized. Result
+ * is always exact. */
+ if( (result_exponent == 0) && Is_underflowtrap_enabled() )
+ {
+ /* need to normalize results mantissa */
+ sign_save = Sgl_signextendedsign(left);
+ Sgl_leftshiftby1(left);
+ Sgl_normalize(left,result_exponent);
+ Sgl_set_sign(left,/*using*/sign_save);
+ Sgl_setwrapped_exponent(left,result_exponent,unfl);
+ *dstptr = left;
+ return(UNDERFLOWEXCEPTION);
+ }
+ }
+ *dstptr = left;
+ return(NOEXCEPTION);
+ }
+
+ /* Neither are zeroes */
+ Sgl_clear_sign(right); /* Exponent is already cleared */
+ if(result_exponent == 0 )
+ {
+ /* Both operands are denormalized. The result must be exact
+ * and is simply calculated. A sum could become normalized and a
+ * difference could cancel to a true zero. */
+ if( (/*signed*/int) save < 0 )
+ {
+ Sgl_subtract(left,/*minus*/right,/*into*/result);
+ if(Sgl_iszero_mantissa(result))
+ {
+ if(Is_rounding_mode(ROUNDMINUS))
+ {
+ Sgl_setone_sign(result);
+ }
+ else
+ {
+ Sgl_setzero_sign(result);
+ }
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+ }
+ else
+ {
+ Sgl_addition(left,right,/*into*/result);
+ if(Sgl_isone_hidden(result))
+ {
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+ }
+ if(Is_underflowtrap_enabled())
+ {
+ /* need to normalize result */
+ sign_save = Sgl_signextendedsign(result);
+ Sgl_leftshiftby1(result);
+ Sgl_normalize(result,result_exponent);
+ Sgl_set_sign(result,/*using*/sign_save);
+ Sgl_setwrapped_exponent(result,result_exponent,unfl);
+ *dstptr = result;
+ return(UNDERFLOWEXCEPTION);
+ }
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+ right_exponent = 1; /* Set exponent to reflect different bias
+ * with denormalized numbers. */
+ }
+ else
+ {
+ Sgl_clear_signexponent_set_hidden(right);
+ }
+ Sgl_clear_exponent_set_hidden(left);
+ diff_exponent = result_exponent - right_exponent;
+
+ /*
+ * Special case alignment of operands that would force alignment
+ * beyond the extent of the extension. A further optimization
+ * could special case this but only reduces the path length for this
+ * infrequent case.
+ */
+ if(diff_exponent > SGL_THRESHOLD)
+ {
+ diff_exponent = SGL_THRESHOLD;
+ }
+
+ /* Align right operand by shifting to right */
+ Sgl_right_align(/*operand*/right,/*shifted by*/diff_exponent,
+ /*and lower to*/extent);
+
+ /* Treat sum and difference of the operands separately. */
+ if( (/*signed*/int) save < 0 )
+ {
+ /*
+ * Difference of the two operands. Their can be no overflow. A
+ * borrow can occur out of the hidden bit and force a post
+ * normalization phase.
+ */
+ Sgl_subtract_withextension(left,/*minus*/right,/*with*/extent,/*into*/result);
+ if(Sgl_iszero_hidden(result))
+ {
+ /* Handle normalization */
+ /* A straightforward algorithm would now shift the result
+ * and extension left until the hidden bit becomes one. Not
+ * all of the extension bits need participate in the shift.
+ * Only the two most significant bits (round and guard) are
+ * needed. If only a single shift is needed then the guard
+ * bit becomes a significant low order bit and the extension
+ * must participate in the rounding. If more than a single
+ * shift is needed, then all bits to the right of the guard
+ * bit are zeros, and the guard bit may or may not be zero. */
+ sign_save = Sgl_signextendedsign(result);
+ Sgl_leftshiftby1_withextent(result,extent,result);
+
+ /* Need to check for a zero result. The sign and exponent
+ * fields have already been zeroed. The more efficient test
+ * of the full object can be used.
+ */
+ if(Sgl_iszero(result))
+ /* Must have been "x-x" or "x+(-x)". */
+ {
+ if(Is_rounding_mode(ROUNDMINUS)) Sgl_setone_sign(result);
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+ result_exponent--;
+ /* Look to see if normalization is finished. */
+ if(Sgl_isone_hidden(result))
+ {
+ if(result_exponent==0)
+ {
+ /* Denormalized, exponent should be zero. Left operand *
+ * was normalized, so extent (guard, round) was zero */
+ goto underflow;
+ }
+ else
+ {
+ /* No further normalization is needed. */
+ Sgl_set_sign(result,/*using*/sign_save);
+ Ext_leftshiftby1(extent);
+ goto round;
+ }
+ }
+
+ /* Check for denormalized, exponent should be zero. Left *
+ * operand was normalized, so extent (guard, round) was zero */
+ if(!(underflowtrap = Is_underflowtrap_enabled()) &&
+ result_exponent==0) goto underflow;
+
+ /* Shift extension to complete one bit of normalization and
+ * update exponent. */
+ Ext_leftshiftby1(extent);
+
+ /* Discover first one bit to determine shift amount. Use a
+ * modified binary search. We have already shifted the result
+ * one position right and still not found a one so the remainder
+ * of the extension must be zero and simplifies rounding. */
+ /* Scan bytes */
+ while(Sgl_iszero_hiddenhigh7mantissa(result))
+ {
+ Sgl_leftshiftby8(result);
+ if((result_exponent -= 8) <= 0 && !underflowtrap)
+ goto underflow;
+ }
+ /* Now narrow it down to the nibble */
+ if(Sgl_iszero_hiddenhigh3mantissa(result))
+ {
+ /* The lower nibble contains the normalizing one */
+ Sgl_leftshiftby4(result);
+ if((result_exponent -= 4) <= 0 && !underflowtrap)
+ goto underflow;
+ }
+ /* Select case were first bit is set (already normalized)
+ * otherwise select the proper shift. */
+ if((jumpsize = Sgl_hiddenhigh3mantissa(result)) > 7)
+ {
+ /* Already normalized */
+ if(result_exponent <= 0) goto underflow;
+ Sgl_set_sign(result,/*using*/sign_save);
+ Sgl_set_exponent(result,/*using*/result_exponent);
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+ Sgl_sethigh4bits(result,/*using*/sign_save);
+ switch(jumpsize)
+ {
+ case 1:
+ {
+ Sgl_leftshiftby3(result);
+ result_exponent -= 3;
+ break;
+ }
+ case 2:
+ case 3:
+ {
+ Sgl_leftshiftby2(result);
+ result_exponent -= 2;
+ break;
+ }
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ {
+ Sgl_leftshiftby1(result);
+ result_exponent -= 1;
+ break;
+ }
+ }
+ if(result_exponent > 0)
+ {
+ Sgl_set_exponent(result,/*using*/result_exponent);
+ *dstptr = result;
+ return(NOEXCEPTION); /* Sign bit is already set */
+ }
+ /* Fixup potential underflows */
+ underflow:
+ if(Is_underflowtrap_enabled())
+ {
+ Sgl_set_sign(result,sign_save);
+ Sgl_setwrapped_exponent(result,result_exponent,unfl);
+ *dstptr = result;
+ /* inexact = FALSE; */
+ return(UNDERFLOWEXCEPTION);
+ }
+ /*
+ * Since we cannot get an inexact denormalized result,
+ * we can now return.
+ */
+ Sgl_right_align(result,/*by*/(1-result_exponent),extent);
+ Sgl_clear_signexponent(result);
+ Sgl_set_sign(result,sign_save);
+ *dstptr = result;
+ return(NOEXCEPTION);
+ } /* end if(hidden...)... */
+ /* Fall through and round */
+ } /* end if(save < 0)... */
+ else
+ {
+ /* Add magnitudes */
+ Sgl_addition(left,right,/*to*/result);
+ if(Sgl_isone_hiddenoverflow(result))
+ {
+ /* Prenormalization required. */
+ Sgl_rightshiftby1_withextent(result,extent,extent);
+ Sgl_arithrightshiftby1(result);
+ result_exponent++;
+ } /* end if hiddenoverflow... */
+ } /* end else ...add magnitudes... */
+
+ /* Round the result. If the extension is all zeros,then the result is
+ * exact. Otherwise round in the correct direction. No underflow is
+ * possible. If a postnormalization is necessary, then the mantissa is
+ * all zeros so no shift is needed. */
+ round:
+ if(Ext_isnotzero(extent))
+ {
+ inexact = TRUE;
+ switch(Rounding_mode())
+ {
+ case ROUNDNEAREST: /* The default. */
+ if(Ext_isone_sign(extent))
+ {
+ /* at least 1/2 ulp */
+ if(Ext_isnotzero_lower(extent) ||
+ Sgl_isone_lowmantissa(result))
+ {
+ /* either exactly half way and odd or more than 1/2ulp */
+ Sgl_increment(result);
+ }
+ }
+ break;
+
+ case ROUNDPLUS:
+ if(Sgl_iszero_sign(result))
+ {
+ /* Round up positive results */
+ Sgl_increment(result);
+ }
+ break;
+
+ case ROUNDMINUS:
+ if(Sgl_isone_sign(result))
+ {
+ /* Round down negative results */
+ Sgl_increment(result);
+ }
+
+ case ROUNDZERO:;
+ /* truncate is simple */
+ } /* end switch... */
+ if(Sgl_isone_hiddenoverflow(result)) result_exponent++;
+ }
+ if(result_exponent == SGL_INFINITY_EXPONENT)
+ {
+ /* Overflow */
+ if(Is_overflowtrap_enabled())
+ {
+ Sgl_setwrapped_exponent(result,result_exponent,ovfl);
+ *dstptr = result;
+ if (inexact)
+ if (Is_inexacttrap_enabled())
+ return(OVERFLOWEXCEPTION | INEXACTEXCEPTION);
+ else Set_inexactflag();
+ return(OVERFLOWEXCEPTION);
+ }
+ else
+ {
+ Set_overflowflag();
+ inexact = TRUE;
+ Sgl_setoverflow(result);
+ }
+ }
+ else Sgl_set_exponent(result,result_exponent);
+ *dstptr = result;
+ if(inexact)
+ if(Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+ else Set_inexactflag();
+ return(NOEXCEPTION);
+ }
diff --git a/arch/parisc/math-emu/sfcmp.c b/arch/parisc/math-emu/sfcmp.c
new file mode 100644
index 000000000..4a708f6c6
--- /dev/null
+++ b/arch/parisc/math-emu/sfcmp.c
@@ -0,0 +1,142 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ */
+/*
+ * BEGIN_DESC
+ *
+ * File:
+ * @(#) pa/spmath/sfcmp.c $Revision: 1.1 $
+ *
+ * Purpose:
+ * sgl_cmp: compare two values
+ *
+ * External Interfaces:
+ * sgl_fcmp(leftptr, rightptr, cond, status)
+ *
+ * Internal Interfaces:
+ *
+ * Theory:
+ * <<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+
+/*
+ * sgl_cmp: compare two values
+ */
+int
+sgl_fcmp (sgl_floating_point * leftptr, sgl_floating_point * rightptr,
+ unsigned int cond, unsigned int *status)
+
+ /* The predicate to be tested */
+
+ {
+ register unsigned int left, right;
+ register int xorresult;
+
+ /* Create local copies of the numbers */
+ left = *leftptr;
+ right = *rightptr;
+
+ /*
+ * Test for NaN
+ */
+ if( (Sgl_exponent(left) == SGL_INFINITY_EXPONENT)
+ || (Sgl_exponent(right) == SGL_INFINITY_EXPONENT) )
+ {
+ /* Check if a NaN is involved. Signal an invalid exception when
+ * comparing a signaling NaN or when comparing quiet NaNs and the
+ * low bit of the condition is set */
+ if( ( (Sgl_exponent(left) == SGL_INFINITY_EXPONENT)
+ && Sgl_isnotzero_mantissa(left)
+ && (Exception(cond) || Sgl_isone_signaling(left)))
+ ||
+ ( (Sgl_exponent(right) == SGL_INFINITY_EXPONENT)
+ && Sgl_isnotzero_mantissa(right)
+ && (Exception(cond) || Sgl_isone_signaling(right)) ) )
+ {
+ if( Is_invalidtrap_enabled() ) {
+ Set_status_cbit(Unordered(cond));
+ return(INVALIDEXCEPTION);
+ }
+ else Set_invalidflag();
+ Set_status_cbit(Unordered(cond));
+ return(NOEXCEPTION);
+ }
+ /* All the exceptional conditions are handled, now special case
+ NaN compares */
+ else if( ((Sgl_exponent(left) == SGL_INFINITY_EXPONENT)
+ && Sgl_isnotzero_mantissa(left))
+ ||
+ ((Sgl_exponent(right) == SGL_INFINITY_EXPONENT)
+ && Sgl_isnotzero_mantissa(right)) )
+ {
+ /* NaNs always compare unordered. */
+ Set_status_cbit(Unordered(cond));
+ return(NOEXCEPTION);
+ }
+ /* infinities will drop down to the normal compare mechanisms */
+ }
+ /* First compare for unequal signs => less or greater or
+ * special equal case */
+ Sgl_xortointp1(left,right,xorresult);
+ if( xorresult < 0 )
+ {
+ /* left negative => less, left positive => greater.
+ * equal is possible if both operands are zeros. */
+ if( Sgl_iszero_exponentmantissa(left)
+ && Sgl_iszero_exponentmantissa(right) )
+ {
+ Set_status_cbit(Equal(cond));
+ }
+ else if( Sgl_isone_sign(left) )
+ {
+ Set_status_cbit(Lessthan(cond));
+ }
+ else
+ {
+ Set_status_cbit(Greaterthan(cond));
+ }
+ }
+ /* Signs are the same. Treat negative numbers separately
+ * from the positives because of the reversed sense. */
+ else if( Sgl_all(left) == Sgl_all(right) )
+ {
+ Set_status_cbit(Equal(cond));
+ }
+ else if( Sgl_iszero_sign(left) )
+ {
+ /* Positive compare */
+ if( Sgl_all(left) < Sgl_all(right) )
+ {
+ Set_status_cbit(Lessthan(cond));
+ }
+ else
+ {
+ Set_status_cbit(Greaterthan(cond));
+ }
+ }
+ else
+ {
+ /* Negative compare. Signed or unsigned compares
+ * both work the same. That distinction is only
+ * important when the sign bits differ. */
+ if( Sgl_all(left) > Sgl_all(right) )
+ {
+ Set_status_cbit(Lessthan(cond));
+ }
+ else
+ {
+ Set_status_cbit(Greaterthan(cond));
+ }
+ }
+ return(NOEXCEPTION);
+ }
diff --git a/arch/parisc/math-emu/sfdiv.c b/arch/parisc/math-emu/sfdiv.c
new file mode 100644
index 000000000..f1b439365
--- /dev/null
+++ b/arch/parisc/math-emu/sfdiv.c
@@ -0,0 +1,379 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ */
+/*
+ * BEGIN_DESC
+ *
+ * File:
+ * @(#) pa/spmath/sfdiv.c $Revision: 1.1 $
+ *
+ * Purpose:
+ * Single Precision Floating-point Divide
+ *
+ * External Interfaces:
+ * sgl_fdiv(srcptr1,srcptr2,dstptr,status)
+ *
+ * Internal Interfaces:
+ *
+ * Theory:
+ * <<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+
+/*
+ * Single Precision Floating-point Divide
+ */
+
+int
+sgl_fdiv (sgl_floating_point * srcptr1, sgl_floating_point * srcptr2,
+ sgl_floating_point * dstptr, unsigned int *status)
+{
+ register unsigned int opnd1, opnd2, opnd3, result;
+ register int dest_exponent, count;
+ register boolean inexact = FALSE, guardbit = FALSE, stickybit = FALSE;
+ boolean is_tiny;
+
+ opnd1 = *srcptr1;
+ opnd2 = *srcptr2;
+ /*
+ * set sign bit of result
+ */
+ if (Sgl_sign(opnd1) ^ Sgl_sign(opnd2)) Sgl_setnegativezero(result);
+ else Sgl_setzero(result);
+ /*
+ * check first operand for NaN's or infinity
+ */
+ if (Sgl_isinfinity_exponent(opnd1)) {
+ if (Sgl_iszero_mantissa(opnd1)) {
+ if (Sgl_isnotnan(opnd2)) {
+ if (Sgl_isinfinity(opnd2)) {
+ /*
+ * invalid since both operands
+ * are infinity
+ */
+ if (Is_invalidtrap_enabled())
+ return(INVALIDEXCEPTION);
+ Set_invalidflag();
+ Sgl_makequietnan(result);
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+ /*
+ * return infinity
+ */
+ Sgl_setinfinity_exponentmantissa(result);
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+ }
+ else {
+ /*
+ * is NaN; signaling or quiet?
+ */
+ if (Sgl_isone_signaling(opnd1)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled())
+ return(INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Sgl_set_quiet(opnd1);
+ }
+ /*
+ * is second operand a signaling NaN?
+ */
+ else if (Sgl_is_signalingnan(opnd2)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled())
+ return(INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Sgl_set_quiet(opnd2);
+ *dstptr = opnd2;
+ return(NOEXCEPTION);
+ }
+ /*
+ * return quiet NaN
+ */
+ *dstptr = opnd1;
+ return(NOEXCEPTION);
+ }
+ }
+ /*
+ * check second operand for NaN's or infinity
+ */
+ if (Sgl_isinfinity_exponent(opnd2)) {
+ if (Sgl_iszero_mantissa(opnd2)) {
+ /*
+ * return zero
+ */
+ Sgl_setzero_exponentmantissa(result);
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+ /*
+ * is NaN; signaling or quiet?
+ */
+ if (Sgl_isone_signaling(opnd2)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Sgl_set_quiet(opnd2);
+ }
+ /*
+ * return quiet NaN
+ */
+ *dstptr = opnd2;
+ return(NOEXCEPTION);
+ }
+ /*
+ * check for division by zero
+ */
+ if (Sgl_iszero_exponentmantissa(opnd2)) {
+ if (Sgl_iszero_exponentmantissa(opnd1)) {
+ /* invalid since both operands are zero */
+ if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+ Set_invalidflag();
+ Sgl_makequietnan(result);
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+ if (Is_divisionbyzerotrap_enabled())
+ return(DIVISIONBYZEROEXCEPTION);
+ Set_divisionbyzeroflag();
+ Sgl_setinfinity_exponentmantissa(result);
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+ /*
+ * Generate exponent
+ */
+ dest_exponent = Sgl_exponent(opnd1) - Sgl_exponent(opnd2) + SGL_BIAS;
+
+ /*
+ * Generate mantissa
+ */
+ if (Sgl_isnotzero_exponent(opnd1)) {
+ /* set hidden bit */
+ Sgl_clear_signexponent_set_hidden(opnd1);
+ }
+ else {
+ /* check for zero */
+ if (Sgl_iszero_mantissa(opnd1)) {
+ Sgl_setzero_exponentmantissa(result);
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+ /* is denormalized; want to normalize */
+ Sgl_clear_signexponent(opnd1);
+ Sgl_leftshiftby1(opnd1);
+ Sgl_normalize(opnd1,dest_exponent);
+ }
+ /* opnd2 needs to have hidden bit set with msb in hidden bit */
+ if (Sgl_isnotzero_exponent(opnd2)) {
+ Sgl_clear_signexponent_set_hidden(opnd2);
+ }
+ else {
+ /* is denormalized; want to normalize */
+ Sgl_clear_signexponent(opnd2);
+ Sgl_leftshiftby1(opnd2);
+ while(Sgl_iszero_hiddenhigh7mantissa(opnd2)) {
+ Sgl_leftshiftby8(opnd2);
+ dest_exponent += 8;
+ }
+ if(Sgl_iszero_hiddenhigh3mantissa(opnd2)) {
+ Sgl_leftshiftby4(opnd2);
+ dest_exponent += 4;
+ }
+ while(Sgl_iszero_hidden(opnd2)) {
+ Sgl_leftshiftby1(opnd2);
+ dest_exponent += 1;
+ }
+ }
+
+ /* Divide the source mantissas */
+
+ /*
+ * A non_restoring divide algorithm is used.
+ */
+ Sgl_subtract(opnd1,opnd2,opnd1);
+ Sgl_setzero(opnd3);
+ for (count=1;count<=SGL_P && Sgl_all(opnd1);count++) {
+ Sgl_leftshiftby1(opnd1);
+ Sgl_leftshiftby1(opnd3);
+ if (Sgl_iszero_sign(opnd1)) {
+ Sgl_setone_lowmantissa(opnd3);
+ Sgl_subtract(opnd1,opnd2,opnd1);
+ }
+ else Sgl_addition(opnd1,opnd2,opnd1);
+ }
+ if (count <= SGL_P) {
+ Sgl_leftshiftby1(opnd3);
+ Sgl_setone_lowmantissa(opnd3);
+ Sgl_leftshift(opnd3,SGL_P-count);
+ if (Sgl_iszero_hidden(opnd3)) {
+ Sgl_leftshiftby1(opnd3);
+ dest_exponent--;
+ }
+ }
+ else {
+ if (Sgl_iszero_hidden(opnd3)) {
+ /* need to get one more bit of result */
+ Sgl_leftshiftby1(opnd1);
+ Sgl_leftshiftby1(opnd3);
+ if (Sgl_iszero_sign(opnd1)) {
+ Sgl_setone_lowmantissa(opnd3);
+ Sgl_subtract(opnd1,opnd2,opnd1);
+ }
+ else Sgl_addition(opnd1,opnd2,opnd1);
+ dest_exponent--;
+ }
+ if (Sgl_iszero_sign(opnd1)) guardbit = TRUE;
+ stickybit = Sgl_all(opnd1);
+ }
+ inexact = guardbit | stickybit;
+
+ /*
+ * round result
+ */
+ if (inexact && (dest_exponent > 0 || Is_underflowtrap_enabled())) {
+ Sgl_clear_signexponent(opnd3);
+ switch (Rounding_mode()) {
+ case ROUNDPLUS:
+ if (Sgl_iszero_sign(result))
+ Sgl_increment_mantissa(opnd3);
+ break;
+ case ROUNDMINUS:
+ if (Sgl_isone_sign(result))
+ Sgl_increment_mantissa(opnd3);
+ break;
+ case ROUNDNEAREST:
+ if (guardbit) {
+ if (stickybit || Sgl_isone_lowmantissa(opnd3))
+ Sgl_increment_mantissa(opnd3);
+ }
+ }
+ if (Sgl_isone_hidden(opnd3)) dest_exponent++;
+ }
+ Sgl_set_mantissa(result,opnd3);
+
+ /*
+ * Test for overflow
+ */
+ if (dest_exponent >= SGL_INFINITY_EXPONENT) {
+ /* trap if OVERFLOWTRAP enabled */
+ if (Is_overflowtrap_enabled()) {
+ /*
+ * Adjust bias of result
+ */
+ Sgl_setwrapped_exponent(result,dest_exponent,ovfl);
+ *dstptr = result;
+ if (inexact)
+ if (Is_inexacttrap_enabled())
+ return(OVERFLOWEXCEPTION | INEXACTEXCEPTION);
+ else Set_inexactflag();
+ return(OVERFLOWEXCEPTION);
+ }
+ Set_overflowflag();
+ /* set result to infinity or largest number */
+ Sgl_setoverflow(result);
+ inexact = TRUE;
+ }
+ /*
+ * Test for underflow
+ */
+ else if (dest_exponent <= 0) {
+ /* trap if UNDERFLOWTRAP enabled */
+ if (Is_underflowtrap_enabled()) {
+ /*
+ * Adjust bias of result
+ */
+ Sgl_setwrapped_exponent(result,dest_exponent,unfl);
+ *dstptr = result;
+ if (inexact)
+ if (Is_inexacttrap_enabled())
+ return(UNDERFLOWEXCEPTION | INEXACTEXCEPTION);
+ else Set_inexactflag();
+ return(UNDERFLOWEXCEPTION);
+ }
+
+ /* Determine if should set underflow flag */
+ is_tiny = TRUE;
+ if (dest_exponent == 0 && inexact) {
+ switch (Rounding_mode()) {
+ case ROUNDPLUS:
+ if (Sgl_iszero_sign(result)) {
+ Sgl_increment(opnd3);
+ if (Sgl_isone_hiddenoverflow(opnd3))
+ is_tiny = FALSE;
+ Sgl_decrement(opnd3);
+ }
+ break;
+ case ROUNDMINUS:
+ if (Sgl_isone_sign(result)) {
+ Sgl_increment(opnd3);
+ if (Sgl_isone_hiddenoverflow(opnd3))
+ is_tiny = FALSE;
+ Sgl_decrement(opnd3);
+ }
+ break;
+ case ROUNDNEAREST:
+ if (guardbit && (stickybit ||
+ Sgl_isone_lowmantissa(opnd3))) {
+ Sgl_increment(opnd3);
+ if (Sgl_isone_hiddenoverflow(opnd3))
+ is_tiny = FALSE;
+ Sgl_decrement(opnd3);
+ }
+ break;
+ }
+ }
+
+ /*
+ * denormalize result or set to signed zero
+ */
+ stickybit = inexact;
+ Sgl_denormalize(opnd3,dest_exponent,guardbit,stickybit,inexact);
+
+ /* return rounded number */
+ if (inexact) {
+ switch (Rounding_mode()) {
+ case ROUNDPLUS:
+ if (Sgl_iszero_sign(result)) {
+ Sgl_increment(opnd3);
+ }
+ break;
+ case ROUNDMINUS:
+ if (Sgl_isone_sign(result)) {
+ Sgl_increment(opnd3);
+ }
+ break;
+ case ROUNDNEAREST:
+ if (guardbit && (stickybit ||
+ Sgl_isone_lowmantissa(opnd3))) {
+ Sgl_increment(opnd3);
+ }
+ break;
+ }
+ if (is_tiny) Set_underflowflag();
+ }
+ Sgl_set_exponentmantissa(result,opnd3);
+ }
+ else Sgl_set_exponent(result,dest_exponent);
+ *dstptr = result;
+ /* check for inexact */
+ if (inexact) {
+ if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+ else Set_inexactflag();
+ }
+ return(NOEXCEPTION);
+}
diff --git a/arch/parisc/math-emu/sfmpy.c b/arch/parisc/math-emu/sfmpy.c
new file mode 100644
index 000000000..7f4518679
--- /dev/null
+++ b/arch/parisc/math-emu/sfmpy.c
@@ -0,0 +1,367 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ */
+/*
+ * BEGIN_DESC
+ *
+ * File:
+ * @(#) pa/spmath/sfmpy.c $Revision: 1.1 $
+ *
+ * Purpose:
+ * Single Precision Floating-point Multiply
+ *
+ * External Interfaces:
+ * sgl_fmpy(srcptr1,srcptr2,dstptr,status)
+ *
+ * Internal Interfaces:
+ *
+ * Theory:
+ * <<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+
+/*
+ * Single Precision Floating-point Multiply
+ */
+
+int
+sgl_fmpy(
+ sgl_floating_point *srcptr1,
+ sgl_floating_point *srcptr2,
+ sgl_floating_point *dstptr,
+ unsigned int *status)
+{
+ register unsigned int opnd1, opnd2, opnd3, result;
+ register int dest_exponent, count;
+ register boolean inexact = FALSE, guardbit = FALSE, stickybit = FALSE;
+ boolean is_tiny;
+
+ opnd1 = *srcptr1;
+ opnd2 = *srcptr2;
+ /*
+ * set sign bit of result
+ */
+ if (Sgl_sign(opnd1) ^ Sgl_sign(opnd2)) Sgl_setnegativezero(result);
+ else Sgl_setzero(result);
+ /*
+ * check first operand for NaN's or infinity
+ */
+ if (Sgl_isinfinity_exponent(opnd1)) {
+ if (Sgl_iszero_mantissa(opnd1)) {
+ if (Sgl_isnotnan(opnd2)) {
+ if (Sgl_iszero_exponentmantissa(opnd2)) {
+ /*
+ * invalid since operands are infinity
+ * and zero
+ */
+ if (Is_invalidtrap_enabled())
+ return(INVALIDEXCEPTION);
+ Set_invalidflag();
+ Sgl_makequietnan(result);
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+ /*
+ * return infinity
+ */
+ Sgl_setinfinity_exponentmantissa(result);
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+ }
+ else {
+ /*
+ * is NaN; signaling or quiet?
+ */
+ if (Sgl_isone_signaling(opnd1)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled())
+ return(INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Sgl_set_quiet(opnd1);
+ }
+ /*
+ * is second operand a signaling NaN?
+ */
+ else if (Sgl_is_signalingnan(opnd2)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled())
+ return(INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Sgl_set_quiet(opnd2);
+ *dstptr = opnd2;
+ return(NOEXCEPTION);
+ }
+ /*
+ * return quiet NaN
+ */
+ *dstptr = opnd1;
+ return(NOEXCEPTION);
+ }
+ }
+ /*
+ * check second operand for NaN's or infinity
+ */
+ if (Sgl_isinfinity_exponent(opnd2)) {
+ if (Sgl_iszero_mantissa(opnd2)) {
+ if (Sgl_iszero_exponentmantissa(opnd1)) {
+ /* invalid since operands are zero & infinity */
+ if (Is_invalidtrap_enabled())
+ return(INVALIDEXCEPTION);
+ Set_invalidflag();
+ Sgl_makequietnan(opnd2);
+ *dstptr = opnd2;
+ return(NOEXCEPTION);
+ }
+ /*
+ * return infinity
+ */
+ Sgl_setinfinity_exponentmantissa(result);
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+ /*
+ * is NaN; signaling or quiet?
+ */
+ if (Sgl_isone_signaling(opnd2)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+
+ /* make NaN quiet */
+ Set_invalidflag();
+ Sgl_set_quiet(opnd2);
+ }
+ /*
+ * return quiet NaN
+ */
+ *dstptr = opnd2;
+ return(NOEXCEPTION);
+ }
+ /*
+ * Generate exponent
+ */
+ dest_exponent = Sgl_exponent(opnd1) + Sgl_exponent(opnd2) - SGL_BIAS;
+
+ /*
+ * Generate mantissa
+ */
+ if (Sgl_isnotzero_exponent(opnd1)) {
+ /* set hidden bit */
+ Sgl_clear_signexponent_set_hidden(opnd1);
+ }
+ else {
+ /* check for zero */
+ if (Sgl_iszero_mantissa(opnd1)) {
+ Sgl_setzero_exponentmantissa(result);
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+ /* is denormalized, adjust exponent */
+ Sgl_clear_signexponent(opnd1);
+ Sgl_leftshiftby1(opnd1);
+ Sgl_normalize(opnd1,dest_exponent);
+ }
+ /* opnd2 needs to have hidden bit set with msb in hidden bit */
+ if (Sgl_isnotzero_exponent(opnd2)) {
+ Sgl_clear_signexponent_set_hidden(opnd2);
+ }
+ else {
+ /* check for zero */
+ if (Sgl_iszero_mantissa(opnd2)) {
+ Sgl_setzero_exponentmantissa(result);
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+ /* is denormalized; want to normalize */
+ Sgl_clear_signexponent(opnd2);
+ Sgl_leftshiftby1(opnd2);
+ Sgl_normalize(opnd2,dest_exponent);
+ }
+
+ /* Multiply two source mantissas together */
+
+ Sgl_leftshiftby4(opnd2); /* make room for guard bits */
+ Sgl_setzero(opnd3);
+ /*
+ * Four bits at a time are inspected in each loop, and a
+ * simple shift and add multiply algorithm is used.
+ */
+ for (count=1;count<SGL_P;count+=4) {
+ stickybit |= Slow4(opnd3);
+ Sgl_rightshiftby4(opnd3);
+ if (Sbit28(opnd1)) Sall(opnd3) += (Sall(opnd2) << 3);
+ if (Sbit29(opnd1)) Sall(opnd3) += (Sall(opnd2) << 2);
+ if (Sbit30(opnd1)) Sall(opnd3) += (Sall(opnd2) << 1);
+ if (Sbit31(opnd1)) Sall(opnd3) += Sall(opnd2);
+ Sgl_rightshiftby4(opnd1);
+ }
+ /* make sure result is left-justified */
+ if (Sgl_iszero_sign(opnd3)) {
+ Sgl_leftshiftby1(opnd3);
+ }
+ else {
+ /* result mantissa >= 2. */
+ dest_exponent++;
+ }
+ /* check for denormalized result */
+ while (Sgl_iszero_sign(opnd3)) {
+ Sgl_leftshiftby1(opnd3);
+ dest_exponent--;
+ }
+ /*
+ * check for guard, sticky and inexact bits
+ */
+ stickybit |= Sgl_all(opnd3) << (SGL_BITLENGTH - SGL_EXP_LENGTH + 1);
+ guardbit = Sbit24(opnd3);
+ inexact = guardbit | stickybit;
+
+ /* re-align mantissa */
+ Sgl_rightshiftby8(opnd3);
+
+ /*
+ * round result
+ */
+ if (inexact && (dest_exponent>0 || Is_underflowtrap_enabled())) {
+ Sgl_clear_signexponent(opnd3);
+ switch (Rounding_mode()) {
+ case ROUNDPLUS:
+ if (Sgl_iszero_sign(result))
+ Sgl_increment(opnd3);
+ break;
+ case ROUNDMINUS:
+ if (Sgl_isone_sign(result))
+ Sgl_increment(opnd3);
+ break;
+ case ROUNDNEAREST:
+ if (guardbit) {
+ if (stickybit || Sgl_isone_lowmantissa(opnd3))
+ Sgl_increment(opnd3);
+ }
+ }
+ if (Sgl_isone_hidden(opnd3)) dest_exponent++;
+ }
+ Sgl_set_mantissa(result,opnd3);
+
+ /*
+ * Test for overflow
+ */
+ if (dest_exponent >= SGL_INFINITY_EXPONENT) {
+ /* trap if OVERFLOWTRAP enabled */
+ if (Is_overflowtrap_enabled()) {
+ /*
+ * Adjust bias of result
+ */
+ Sgl_setwrapped_exponent(result,dest_exponent,ovfl);
+ *dstptr = result;
+ if (inexact)
+ if (Is_inexacttrap_enabled())
+ return(OVERFLOWEXCEPTION | INEXACTEXCEPTION);
+ else Set_inexactflag();
+ return(OVERFLOWEXCEPTION);
+ }
+ inexact = TRUE;
+ Set_overflowflag();
+ /* set result to infinity or largest number */
+ Sgl_setoverflow(result);
+ }
+ /*
+ * Test for underflow
+ */
+ else if (dest_exponent <= 0) {
+ /* trap if UNDERFLOWTRAP enabled */
+ if (Is_underflowtrap_enabled()) {
+ /*
+ * Adjust bias of result
+ */
+ Sgl_setwrapped_exponent(result,dest_exponent,unfl);
+ *dstptr = result;
+ if (inexact)
+ if (Is_inexacttrap_enabled())
+ return(UNDERFLOWEXCEPTION | INEXACTEXCEPTION);
+ else Set_inexactflag();
+ return(UNDERFLOWEXCEPTION);
+ }
+
+ /* Determine if should set underflow flag */
+ is_tiny = TRUE;
+ if (dest_exponent == 0 && inexact) {
+ switch (Rounding_mode()) {
+ case ROUNDPLUS:
+ if (Sgl_iszero_sign(result)) {
+ Sgl_increment(opnd3);
+ if (Sgl_isone_hiddenoverflow(opnd3))
+ is_tiny = FALSE;
+ Sgl_decrement(opnd3);
+ }
+ break;
+ case ROUNDMINUS:
+ if (Sgl_isone_sign(result)) {
+ Sgl_increment(opnd3);
+ if (Sgl_isone_hiddenoverflow(opnd3))
+ is_tiny = FALSE;
+ Sgl_decrement(opnd3);
+ }
+ break;
+ case ROUNDNEAREST:
+ if (guardbit && (stickybit ||
+ Sgl_isone_lowmantissa(opnd3))) {
+ Sgl_increment(opnd3);
+ if (Sgl_isone_hiddenoverflow(opnd3))
+ is_tiny = FALSE;
+ Sgl_decrement(opnd3);
+ }
+ break;
+ }
+ }
+
+ /*
+ * denormalize result or set to signed zero
+ */
+ stickybit = inexact;
+ Sgl_denormalize(opnd3,dest_exponent,guardbit,stickybit,inexact);
+
+ /* return zero or smallest number */
+ if (inexact) {
+ switch (Rounding_mode()) {
+ case ROUNDPLUS:
+ if (Sgl_iszero_sign(result)) {
+ Sgl_increment(opnd3);
+ }
+ break;
+ case ROUNDMINUS:
+ if (Sgl_isone_sign(result)) {
+ Sgl_increment(opnd3);
+ }
+ break;
+ case ROUNDNEAREST:
+ if (guardbit && (stickybit ||
+ Sgl_isone_lowmantissa(opnd3))) {
+ Sgl_increment(opnd3);
+ }
+ break;
+ }
+ if (is_tiny) Set_underflowflag();
+ }
+ Sgl_set_exponentmantissa(result,opnd3);
+ }
+ else Sgl_set_exponent(result,dest_exponent);
+ *dstptr = result;
+
+ /* check for inexact */
+ if (inexact) {
+ if (Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+ else Set_inexactflag();
+ }
+ return(NOEXCEPTION);
+}
diff --git a/arch/parisc/math-emu/sfrem.c b/arch/parisc/math-emu/sfrem.c
new file mode 100644
index 000000000..4ac88d829
--- /dev/null
+++ b/arch/parisc/math-emu/sfrem.c
@@ -0,0 +1,277 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ */
+/*
+ * BEGIN_DESC
+ *
+ * File:
+ * @(#) pa/spmath/sfrem.c $Revision: 1.1 $
+ *
+ * Purpose:
+ * Single Precision Floating-point Remainder
+ *
+ * External Interfaces:
+ * sgl_frem(srcptr1,srcptr2,dstptr,status)
+ *
+ * Internal Interfaces:
+ *
+ * Theory:
+ * <<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+
+#include "float.h"
+#include "sgl_float.h"
+
+/*
+ * Single Precision Floating-point Remainder
+ */
+
+int
+sgl_frem (sgl_floating_point * srcptr1, sgl_floating_point * srcptr2,
+ sgl_floating_point * dstptr, unsigned int *status)
+{
+ register unsigned int opnd1, opnd2, result;
+ register int opnd1_exponent, opnd2_exponent, dest_exponent, stepcount;
+ register boolean roundup = FALSE;
+
+ opnd1 = *srcptr1;
+ opnd2 = *srcptr2;
+ /*
+ * check first operand for NaN's or infinity
+ */
+ if ((opnd1_exponent = Sgl_exponent(opnd1)) == SGL_INFINITY_EXPONENT) {
+ if (Sgl_iszero_mantissa(opnd1)) {
+ if (Sgl_isnotnan(opnd2)) {
+ /* invalid since first operand is infinity */
+ if (Is_invalidtrap_enabled())
+ return(INVALIDEXCEPTION);
+ Set_invalidflag();
+ Sgl_makequietnan(result);
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+ }
+ else {
+ /*
+ * is NaN; signaling or quiet?
+ */
+ if (Sgl_isone_signaling(opnd1)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled())
+ return(INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Sgl_set_quiet(opnd1);
+ }
+ /*
+ * is second operand a signaling NaN?
+ */
+ else if (Sgl_is_signalingnan(opnd2)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled())
+ return(INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Sgl_set_quiet(opnd2);
+ *dstptr = opnd2;
+ return(NOEXCEPTION);
+ }
+ /*
+ * return quiet NaN
+ */
+ *dstptr = opnd1;
+ return(NOEXCEPTION);
+ }
+ }
+ /*
+ * check second operand for NaN's or infinity
+ */
+ if ((opnd2_exponent = Sgl_exponent(opnd2)) == SGL_INFINITY_EXPONENT) {
+ if (Sgl_iszero_mantissa(opnd2)) {
+ /*
+ * return first operand
+ */
+ *dstptr = opnd1;
+ return(NOEXCEPTION);
+ }
+ /*
+ * is NaN; signaling or quiet?
+ */
+ if (Sgl_isone_signaling(opnd2)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Sgl_set_quiet(opnd2);
+ }
+ /*
+ * return quiet NaN
+ */
+ *dstptr = opnd2;
+ return(NOEXCEPTION);
+ }
+ /*
+ * check second operand for zero
+ */
+ if (Sgl_iszero_exponentmantissa(opnd2)) {
+ /* invalid since second operand is zero */
+ if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+ Set_invalidflag();
+ Sgl_makequietnan(result);
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+
+ /*
+ * get sign of result
+ */
+ result = opnd1;
+
+ /*
+ * check for denormalized operands
+ */
+ if (opnd1_exponent == 0) {
+ /* check for zero */
+ if (Sgl_iszero_mantissa(opnd1)) {
+ *dstptr = opnd1;
+ return(NOEXCEPTION);
+ }
+ /* normalize, then continue */
+ opnd1_exponent = 1;
+ Sgl_normalize(opnd1,opnd1_exponent);
+ }
+ else {
+ Sgl_clear_signexponent_set_hidden(opnd1);
+ }
+ if (opnd2_exponent == 0) {
+ /* normalize, then continue */
+ opnd2_exponent = 1;
+ Sgl_normalize(opnd2,opnd2_exponent);
+ }
+ else {
+ Sgl_clear_signexponent_set_hidden(opnd2);
+ }
+
+ /* find result exponent and divide step loop count */
+ dest_exponent = opnd2_exponent - 1;
+ stepcount = opnd1_exponent - opnd2_exponent;
+
+ /*
+ * check for opnd1/opnd2 < 1
+ */
+ if (stepcount < 0) {
+ /*
+ * check for opnd1/opnd2 > 1/2
+ *
+ * In this case n will round to 1, so
+ * r = opnd1 - opnd2
+ */
+ if (stepcount == -1 && Sgl_isgreaterthan(opnd1,opnd2)) {
+ Sgl_all(result) = ~Sgl_all(result); /* set sign */
+ /* align opnd2 with opnd1 */
+ Sgl_leftshiftby1(opnd2);
+ Sgl_subtract(opnd2,opnd1,opnd2);
+ /* now normalize */
+ while (Sgl_iszero_hidden(opnd2)) {
+ Sgl_leftshiftby1(opnd2);
+ dest_exponent--;
+ }
+ Sgl_set_exponentmantissa(result,opnd2);
+ goto testforunderflow;
+ }
+ /*
+ * opnd1/opnd2 <= 1/2
+ *
+ * In this case n will round to zero, so
+ * r = opnd1
+ */
+ Sgl_set_exponentmantissa(result,opnd1);
+ dest_exponent = opnd1_exponent;
+ goto testforunderflow;
+ }
+
+ /*
+ * Generate result
+ *
+ * Do iterative subtract until remainder is less than operand 2.
+ */
+ while (stepcount-- > 0 && Sgl_all(opnd1)) {
+ if (Sgl_isnotlessthan(opnd1,opnd2))
+ Sgl_subtract(opnd1,opnd2,opnd1);
+ Sgl_leftshiftby1(opnd1);
+ }
+ /*
+ * Do last subtract, then determine which way to round if remainder
+ * is exactly 1/2 of opnd2
+ */
+ if (Sgl_isnotlessthan(opnd1,opnd2)) {
+ Sgl_subtract(opnd1,opnd2,opnd1);
+ roundup = TRUE;
+ }
+ if (stepcount > 0 || Sgl_iszero(opnd1)) {
+ /* division is exact, remainder is zero */
+ Sgl_setzero_exponentmantissa(result);
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+
+ /*
+ * Check for cases where opnd1/opnd2 < n
+ *
+ * In this case the result's sign will be opposite that of
+ * opnd1. The mantissa also needs some correction.
+ */
+ Sgl_leftshiftby1(opnd1);
+ if (Sgl_isgreaterthan(opnd1,opnd2)) {
+ Sgl_invert_sign(result);
+ Sgl_subtract((opnd2<<1),opnd1,opnd1);
+ }
+ /* check for remainder being exactly 1/2 of opnd2 */
+ else if (Sgl_isequal(opnd1,opnd2) && roundup) {
+ Sgl_invert_sign(result);
+ }
+
+ /* normalize result's mantissa */
+ while (Sgl_iszero_hidden(opnd1)) {
+ dest_exponent--;
+ Sgl_leftshiftby1(opnd1);
+ }
+ Sgl_set_exponentmantissa(result,opnd1);
+
+ /*
+ * Test for underflow
+ */
+ testforunderflow:
+ if (dest_exponent <= 0) {
+ /* trap if UNDERFLOWTRAP enabled */
+ if (Is_underflowtrap_enabled()) {
+ /*
+ * Adjust bias of result
+ */
+ Sgl_setwrapped_exponent(result,dest_exponent,unfl);
+ *dstptr = result;
+ /* frem is always exact */
+ return(UNDERFLOWEXCEPTION);
+ }
+ /*
+ * denormalize result or set to signed zero
+ */
+ if (dest_exponent >= (1 - SGL_P)) {
+ Sgl_rightshift_exponentmantissa(result,1-dest_exponent);
+ }
+ else {
+ Sgl_setzero_exponentmantissa(result);
+ }
+ }
+ else Sgl_set_exponent(result,dest_exponent);
+ *dstptr = result;
+ return(NOEXCEPTION);
+}
diff --git a/arch/parisc/math-emu/sfsqrt.c b/arch/parisc/math-emu/sfsqrt.c
new file mode 100644
index 000000000..bd6a84f46
--- /dev/null
+++ b/arch/parisc/math-emu/sfsqrt.c
@@ -0,0 +1,174 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ */
+/*
+ * BEGIN_DESC
+ *
+ * File:
+ * @(#) pa/spmath/sfsqrt.c $Revision: 1.1 $
+ *
+ * Purpose:
+ * Single Floating-point Square Root
+ *
+ * External Interfaces:
+ * sgl_fsqrt(srcptr,nullptr,dstptr,status)
+ *
+ * Internal Interfaces:
+ *
+ * Theory:
+ * <<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+
+/*
+ * Single Floating-point Square Root
+ */
+
+/*ARGSUSED*/
+unsigned int
+sgl_fsqrt(
+ sgl_floating_point *srcptr,
+ unsigned int *nullptr,
+ sgl_floating_point *dstptr,
+ unsigned int *status)
+{
+ register unsigned int src, result;
+ register int src_exponent;
+ register unsigned int newbit, sum;
+ register boolean guardbit = FALSE, even_exponent;
+
+ src = *srcptr;
+ /*
+ * check source operand for NaN or infinity
+ */
+ if ((src_exponent = Sgl_exponent(src)) == SGL_INFINITY_EXPONENT) {
+ /*
+ * is signaling NaN?
+ */
+ if (Sgl_isone_signaling(src)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Sgl_set_quiet(src);
+ }
+ /*
+ * Return quiet NaN or positive infinity.
+ * Fall through to negative test if negative infinity.
+ */
+ if (Sgl_iszero_sign(src) || Sgl_isnotzero_mantissa(src)) {
+ *dstptr = src;
+ return(NOEXCEPTION);
+ }
+ }
+
+ /*
+ * check for zero source operand
+ */
+ if (Sgl_iszero_exponentmantissa(src)) {
+ *dstptr = src;
+ return(NOEXCEPTION);
+ }
+
+ /*
+ * check for negative source operand
+ */
+ if (Sgl_isone_sign(src)) {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Sgl_makequietnan(src);
+ *dstptr = src;
+ return(NOEXCEPTION);
+ }
+
+ /*
+ * Generate result
+ */
+ if (src_exponent > 0) {
+ even_exponent = Sgl_hidden(src);
+ Sgl_clear_signexponent_set_hidden(src);
+ }
+ else {
+ /* normalize operand */
+ Sgl_clear_signexponent(src);
+ src_exponent++;
+ Sgl_normalize(src,src_exponent);
+ even_exponent = src_exponent & 1;
+ }
+ if (even_exponent) {
+ /* exponent is even */
+ /* Add comment here. Explain why odd exponent needs correction */
+ Sgl_leftshiftby1(src);
+ }
+ /*
+ * Add comment here. Explain following algorithm.
+ *
+ * Trust me, it works.
+ *
+ */
+ Sgl_setzero(result);
+ newbit = 1 << SGL_P;
+ while (newbit && Sgl_isnotzero(src)) {
+ Sgl_addition(result,newbit,sum);
+ if(sum <= Sgl_all(src)) {
+ /* update result */
+ Sgl_addition(result,(newbit<<1),result);
+ Sgl_subtract(src,sum,src);
+ }
+ Sgl_rightshiftby1(newbit);
+ Sgl_leftshiftby1(src);
+ }
+ /* correct exponent for pre-shift */
+ if (even_exponent) {
+ Sgl_rightshiftby1(result);
+ }
+
+ /* check for inexact */
+ if (Sgl_isnotzero(src)) {
+ if (!even_exponent && Sgl_islessthan(result,src))
+ Sgl_increment(result);
+ guardbit = Sgl_lowmantissa(result);
+ Sgl_rightshiftby1(result);
+
+ /* now round result */
+ switch (Rounding_mode()) {
+ case ROUNDPLUS:
+ Sgl_increment(result);
+ break;
+ case ROUNDNEAREST:
+ /* stickybit is always true, so guardbit
+ * is enough to determine rounding */
+ if (guardbit) {
+ Sgl_increment(result);
+ }
+ break;
+ }
+ /* increment result exponent by 1 if mantissa overflowed */
+ if (Sgl_isone_hiddenoverflow(result)) src_exponent+=2;
+
+ if (Is_inexacttrap_enabled()) {
+ Sgl_set_exponent(result,
+ ((src_exponent-SGL_BIAS)>>1)+SGL_BIAS);
+ *dstptr = result;
+ return(INEXACTEXCEPTION);
+ }
+ else Set_inexactflag();
+ }
+ else {
+ Sgl_rightshiftby1(result);
+ }
+ Sgl_set_exponent(result,((src_exponent-SGL_BIAS)>>1)+SGL_BIAS);
+ *dstptr = result;
+ return(NOEXCEPTION);
+}
diff --git a/arch/parisc/math-emu/sfsub.c b/arch/parisc/math-emu/sfsub.c
new file mode 100644
index 000000000..29d9eed09
--- /dev/null
+++ b/arch/parisc/math-emu/sfsub.c
@@ -0,0 +1,508 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ */
+/*
+ * BEGIN_DESC
+ *
+ * File:
+ * @(#) pa/spmath/sfsub.c $Revision: 1.1 $
+ *
+ * Purpose:
+ * Single_subtract: subtract two single precision values.
+ *
+ * External Interfaces:
+ * sgl_fsub(leftptr, rightptr, dstptr, status)
+ *
+ * Internal Interfaces:
+ *
+ * Theory:
+ * <<please update with a overview of the operation of this file>>
+ *
+ * END_DESC
+*/
+
+
+#include "float.h"
+#include "sgl_float.h"
+
+/*
+ * Single_subtract: subtract two single precision values.
+ */
+int
+sgl_fsub(
+ sgl_floating_point *leftptr,
+ sgl_floating_point *rightptr,
+ sgl_floating_point *dstptr,
+ unsigned int *status)
+ {
+ register unsigned int left, right, result, extent;
+ register unsigned int signless_upper_left, signless_upper_right, save;
+
+ register int result_exponent, right_exponent, diff_exponent;
+ register int sign_save, jumpsize;
+ register boolean inexact = FALSE, underflowtrap;
+
+ /* Create local copies of the numbers */
+ left = *leftptr;
+ right = *rightptr;
+
+ /* A zero "save" helps discover equal operands (for later), *
+ * and is used in swapping operands (if needed). */
+ Sgl_xortointp1(left,right,/*to*/save);
+
+ /*
+ * check first operand for NaN's or infinity
+ */
+ if ((result_exponent = Sgl_exponent(left)) == SGL_INFINITY_EXPONENT)
+ {
+ if (Sgl_iszero_mantissa(left))
+ {
+ if (Sgl_isnotnan(right))
+ {
+ if (Sgl_isinfinity(right) && save==0)
+ {
+ /*
+ * invalid since operands are same signed infinity's
+ */
+ if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+ Set_invalidflag();
+ Sgl_makequietnan(result);
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+ /*
+ * return infinity
+ */
+ *dstptr = left;
+ return(NOEXCEPTION);
+ }
+ }
+ else
+ {
+ /*
+ * is NaN; signaling or quiet?
+ */
+ if (Sgl_isone_signaling(left))
+ {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Sgl_set_quiet(left);
+ }
+ /*
+ * is second operand a signaling NaN?
+ */
+ else if (Sgl_is_signalingnan(right))
+ {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Sgl_set_quiet(right);
+ *dstptr = right;
+ return(NOEXCEPTION);
+ }
+ /*
+ * return quiet NaN
+ */
+ *dstptr = left;
+ return(NOEXCEPTION);
+ }
+ } /* End left NaN or Infinity processing */
+ /*
+ * check second operand for NaN's or infinity
+ */
+ if (Sgl_isinfinity_exponent(right))
+ {
+ if (Sgl_iszero_mantissa(right))
+ {
+ /* return infinity */
+ Sgl_invert_sign(right);
+ *dstptr = right;
+ return(NOEXCEPTION);
+ }
+ /*
+ * is NaN; signaling or quiet?
+ */
+ if (Sgl_isone_signaling(right))
+ {
+ /* trap if INVALIDTRAP enabled */
+ if (Is_invalidtrap_enabled()) return(INVALIDEXCEPTION);
+ /* make NaN quiet */
+ Set_invalidflag();
+ Sgl_set_quiet(right);
+ }
+ /*
+ * return quiet NaN
+ */
+ *dstptr = right;
+ return(NOEXCEPTION);
+ } /* End right NaN or Infinity processing */
+
+ /* Invariant: Must be dealing with finite numbers */
+
+ /* Compare operands by removing the sign */
+ Sgl_copytoint_exponentmantissa(left,signless_upper_left);
+ Sgl_copytoint_exponentmantissa(right,signless_upper_right);
+
+ /* sign difference selects sub or add operation. */
+ if(Sgl_ismagnitudeless(signless_upper_left,signless_upper_right))
+ {
+ /* Set the left operand to the larger one by XOR swap *
+ * First finish the first word using "save" */
+ Sgl_xorfromintp1(save,right,/*to*/right);
+ Sgl_xorfromintp1(save,left,/*to*/left);
+ result_exponent = Sgl_exponent(left);
+ Sgl_invert_sign(left);
+ }
+ /* Invariant: left is not smaller than right. */
+
+ if((right_exponent = Sgl_exponent(right)) == 0)
+ {
+ /* Denormalized operands. First look for zeroes */
+ if(Sgl_iszero_mantissa(right))
+ {
+ /* right is zero */
+ if(Sgl_iszero_exponentmantissa(left))
+ {
+ /* Both operands are zeros */
+ Sgl_invert_sign(right);
+ if(Is_rounding_mode(ROUNDMINUS))
+ {
+ Sgl_or_signs(left,/*with*/right);
+ }
+ else
+ {
+ Sgl_and_signs(left,/*with*/right);
+ }
+ }
+ else
+ {
+ /* Left is not a zero and must be the result. Trapped
+ * underflows are signaled if left is denormalized. Result
+ * is always exact. */
+ if( (result_exponent == 0) && Is_underflowtrap_enabled() )
+ {
+ /* need to normalize results mantissa */
+ sign_save = Sgl_signextendedsign(left);
+ Sgl_leftshiftby1(left);
+ Sgl_normalize(left,result_exponent);
+ Sgl_set_sign(left,/*using*/sign_save);
+ Sgl_setwrapped_exponent(left,result_exponent,unfl);
+ *dstptr = left;
+ /* inexact = FALSE */
+ return(UNDERFLOWEXCEPTION);
+ }
+ }
+ *dstptr = left;
+ return(NOEXCEPTION);
+ }
+
+ /* Neither are zeroes */
+ Sgl_clear_sign(right); /* Exponent is already cleared */
+ if(result_exponent == 0 )
+ {
+ /* Both operands are denormalized. The result must be exact
+ * and is simply calculated. A sum could become normalized and a
+ * difference could cancel to a true zero. */
+ if( (/*signed*/int) save >= 0 )
+ {
+ Sgl_subtract(left,/*minus*/right,/*into*/result);
+ if(Sgl_iszero_mantissa(result))
+ {
+ if(Is_rounding_mode(ROUNDMINUS))
+ {
+ Sgl_setone_sign(result);
+ }
+ else
+ {
+ Sgl_setzero_sign(result);
+ }
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+ }
+ else
+ {
+ Sgl_addition(left,right,/*into*/result);
+ if(Sgl_isone_hidden(result))
+ {
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+ }
+ if(Is_underflowtrap_enabled())
+ {
+ /* need to normalize result */
+ sign_save = Sgl_signextendedsign(result);
+ Sgl_leftshiftby1(result);
+ Sgl_normalize(result,result_exponent);
+ Sgl_set_sign(result,/*using*/sign_save);
+ Sgl_setwrapped_exponent(result,result_exponent,unfl);
+ *dstptr = result;
+ /* inexact = FALSE */
+ return(UNDERFLOWEXCEPTION);
+ }
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+ right_exponent = 1; /* Set exponent to reflect different bias
+ * with denormalized numbers. */
+ }
+ else
+ {
+ Sgl_clear_signexponent_set_hidden(right);
+ }
+ Sgl_clear_exponent_set_hidden(left);
+ diff_exponent = result_exponent - right_exponent;
+
+ /*
+ * Special case alignment of operands that would force alignment
+ * beyond the extent of the extension. A further optimization
+ * could special case this but only reduces the path length for this
+ * infrequent case.
+ */
+ if(diff_exponent > SGL_THRESHOLD)
+ {
+ diff_exponent = SGL_THRESHOLD;
+ }
+
+ /* Align right operand by shifting to right */
+ Sgl_right_align(/*operand*/right,/*shifted by*/diff_exponent,
+ /*and lower to*/extent);
+
+ /* Treat sum and difference of the operands separately. */
+ if( (/*signed*/int) save >= 0 )
+ {
+ /*
+ * Difference of the two operands. Their can be no overflow. A
+ * borrow can occur out of the hidden bit and force a post
+ * normalization phase.
+ */
+ Sgl_subtract_withextension(left,/*minus*/right,/*with*/extent,/*into*/result);
+ if(Sgl_iszero_hidden(result))
+ {
+ /* Handle normalization */
+ /* A straightforward algorithm would now shift the result
+ * and extension left until the hidden bit becomes one. Not
+ * all of the extension bits need participate in the shift.
+ * Only the two most significant bits (round and guard) are
+ * needed. If only a single shift is needed then the guard
+ * bit becomes a significant low order bit and the extension
+ * must participate in the rounding. If more than a single
+ * shift is needed, then all bits to the right of the guard
+ * bit are zeros, and the guard bit may or may not be zero. */
+ sign_save = Sgl_signextendedsign(result);
+ Sgl_leftshiftby1_withextent(result,extent,result);
+
+ /* Need to check for a zero result. The sign and exponent
+ * fields have already been zeroed. The more efficient test
+ * of the full object can be used.
+ */
+ if(Sgl_iszero(result))
+ /* Must have been "x-x" or "x+(-x)". */
+ {
+ if(Is_rounding_mode(ROUNDMINUS)) Sgl_setone_sign(result);
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+ result_exponent--;
+ /* Look to see if normalization is finished. */
+ if(Sgl_isone_hidden(result))
+ {
+ if(result_exponent==0)
+ {
+ /* Denormalized, exponent should be zero. Left operand *
+ * was normalized, so extent (guard, round) was zero */
+ goto underflow;
+ }
+ else
+ {
+ /* No further normalization is needed. */
+ Sgl_set_sign(result,/*using*/sign_save);
+ Ext_leftshiftby1(extent);
+ goto round;
+ }
+ }
+
+ /* Check for denormalized, exponent should be zero. Left *
+ * operand was normalized, so extent (guard, round) was zero */
+ if(!(underflowtrap = Is_underflowtrap_enabled()) &&
+ result_exponent==0) goto underflow;
+
+ /* Shift extension to complete one bit of normalization and
+ * update exponent. */
+ Ext_leftshiftby1(extent);
+
+ /* Discover first one bit to determine shift amount. Use a
+ * modified binary search. We have already shifted the result
+ * one position right and still not found a one so the remainder
+ * of the extension must be zero and simplifies rounding. */
+ /* Scan bytes */
+ while(Sgl_iszero_hiddenhigh7mantissa(result))
+ {
+ Sgl_leftshiftby8(result);
+ if((result_exponent -= 8) <= 0 && !underflowtrap)
+ goto underflow;
+ }
+ /* Now narrow it down to the nibble */
+ if(Sgl_iszero_hiddenhigh3mantissa(result))
+ {
+ /* The lower nibble contains the normalizing one */
+ Sgl_leftshiftby4(result);
+ if((result_exponent -= 4) <= 0 && !underflowtrap)
+ goto underflow;
+ }
+ /* Select case were first bit is set (already normalized)
+ * otherwise select the proper shift. */
+ if((jumpsize = Sgl_hiddenhigh3mantissa(result)) > 7)
+ {
+ /* Already normalized */
+ if(result_exponent <= 0) goto underflow;
+ Sgl_set_sign(result,/*using*/sign_save);
+ Sgl_set_exponent(result,/*using*/result_exponent);
+ *dstptr = result;
+ return(NOEXCEPTION);
+ }
+ Sgl_sethigh4bits(result,/*using*/sign_save);
+ switch(jumpsize)
+ {
+ case 1:
+ {
+ Sgl_leftshiftby3(result);
+ result_exponent -= 3;
+ break;
+ }
+ case 2:
+ case 3:
+ {
+ Sgl_leftshiftby2(result);
+ result_exponent -= 2;
+ break;
+ }
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ {
+ Sgl_leftshiftby1(result);
+ result_exponent -= 1;
+ break;
+ }
+ }
+ if(result_exponent > 0)
+ {
+ Sgl_set_exponent(result,/*using*/result_exponent);
+ *dstptr = result; /* Sign bit is already set */
+ return(NOEXCEPTION);
+ }
+ /* Fixup potential underflows */
+ underflow:
+ if(Is_underflowtrap_enabled())
+ {
+ Sgl_set_sign(result,sign_save);
+ Sgl_setwrapped_exponent(result,result_exponent,unfl);
+ *dstptr = result;
+ /* inexact = FALSE */
+ return(UNDERFLOWEXCEPTION);
+ }
+ /*
+ * Since we cannot get an inexact denormalized result,
+ * we can now return.
+ */
+ Sgl_right_align(result,/*by*/(1-result_exponent),extent);
+ Sgl_clear_signexponent(result);
+ Sgl_set_sign(result,sign_save);
+ *dstptr = result;
+ return(NOEXCEPTION);
+ } /* end if(hidden...)... */
+ /* Fall through and round */
+ } /* end if(save >= 0)... */
+ else
+ {
+ /* Add magnitudes */
+ Sgl_addition(left,right,/*to*/result);
+ if(Sgl_isone_hiddenoverflow(result))
+ {
+ /* Prenormalization required. */
+ Sgl_rightshiftby1_withextent(result,extent,extent);
+ Sgl_arithrightshiftby1(result);
+ result_exponent++;
+ } /* end if hiddenoverflow... */
+ } /* end else ...sub magnitudes... */
+
+ /* Round the result. If the extension is all zeros,then the result is
+ * exact. Otherwise round in the correct direction. No underflow is
+ * possible. If a postnormalization is necessary, then the mantissa is
+ * all zeros so no shift is needed. */
+ round:
+ if(Ext_isnotzero(extent))
+ {
+ inexact = TRUE;
+ switch(Rounding_mode())
+ {
+ case ROUNDNEAREST: /* The default. */
+ if(Ext_isone_sign(extent))
+ {
+ /* at least 1/2 ulp */
+ if(Ext_isnotzero_lower(extent) ||
+ Sgl_isone_lowmantissa(result))
+ {
+ /* either exactly half way and odd or more than 1/2ulp */
+ Sgl_increment(result);
+ }
+ }
+ break;
+
+ case ROUNDPLUS:
+ if(Sgl_iszero_sign(result))
+ {
+ /* Round up positive results */
+ Sgl_increment(result);
+ }
+ break;
+
+ case ROUNDMINUS:
+ if(Sgl_isone_sign(result))
+ {
+ /* Round down negative results */
+ Sgl_increment(result);
+ }
+
+ case ROUNDZERO:;
+ /* truncate is simple */
+ } /* end switch... */
+ if(Sgl_isone_hiddenoverflow(result)) result_exponent++;
+ }
+ if(result_exponent == SGL_INFINITY_EXPONENT)
+ {
+ /* Overflow */
+ if(Is_overflowtrap_enabled())
+ {
+ Sgl_setwrapped_exponent(result,result_exponent,ovfl);
+ *dstptr = result;
+ if (inexact)
+ if (Is_inexacttrap_enabled())
+ return(OVERFLOWEXCEPTION | INEXACTEXCEPTION);
+ else Set_inexactflag();
+ return(OVERFLOWEXCEPTION);
+ }
+ else
+ {
+ Set_overflowflag();
+ inexact = TRUE;
+ Sgl_setoverflow(result);
+ }
+ }
+ else Sgl_set_exponent(result,result_exponent);
+ *dstptr = result;
+ if(inexact)
+ if(Is_inexacttrap_enabled()) return(INEXACTEXCEPTION);
+ else Set_inexactflag();
+ return(NOEXCEPTION);
+ }
diff --git a/arch/parisc/math-emu/sgl_float.h b/arch/parisc/math-emu/sgl_float.h
new file mode 100644
index 000000000..6ec2662cc
--- /dev/null
+++ b/arch/parisc/math-emu/sgl_float.h
@@ -0,0 +1,473 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Linux/PA-RISC Project (http://www.parisc-linux.org/)
+ *
+ * Floating-point emulation code
+ * Copyright (C) 2001 Hewlett-Packard (Paul Bame) <bame@debian.org>
+ */
+
+#ifdef __NO_PA_HDRS
+ PA header file -- do not include this header file for non-PA builds.
+#endif
+
+/* 32-bit word grabbing functions */
+#define Sgl_firstword(value) Sall(value)
+#define Sgl_secondword(value) dummy_location
+#define Sgl_thirdword(value) dummy_location
+#define Sgl_fourthword(value) dummy_location
+
+#define Sgl_sign(object) Ssign(object)
+#define Sgl_exponent(object) Sexponent(object)
+#define Sgl_signexponent(object) Ssignexponent(object)
+#define Sgl_mantissa(object) Smantissa(object)
+#define Sgl_exponentmantissa(object) Sexponentmantissa(object)
+#define Sgl_all(object) Sall(object)
+
+/* sgl_and_signs ANDs the sign bits of each argument and puts the result
+ * into the first argument. sgl_or_signs ors those same sign bits */
+#define Sgl_and_signs( src1dst, src2) \
+ Sall(src1dst) = (Sall(src2)|~((unsigned int)1<<31)) & Sall(src1dst)
+#define Sgl_or_signs( src1dst, src2) \
+ Sall(src1dst) = (Sall(src2)&((unsigned int)1<<31)) | Sall(src1dst)
+
+/* The hidden bit is always the low bit of the exponent */
+#define Sgl_clear_exponent_set_hidden(srcdst) Deposit_sexponent(srcdst,1)
+#define Sgl_clear_signexponent_set_hidden(srcdst) \
+ Deposit_ssignexponent(srcdst,1)
+#define Sgl_clear_sign(srcdst) Sall(srcdst) &= ~((unsigned int)1<<31)
+#define Sgl_clear_signexponent(srcdst) Sall(srcdst) &= 0x007fffff
+
+/* varamount must be less than 32 for the next three functions */
+#define Sgl_rightshift(srcdst, varamount) \
+ Sall(srcdst) >>= varamount
+#define Sgl_leftshift(srcdst, varamount) \
+ Sall(srcdst) <<= varamount
+#define Sgl_rightshift_exponentmantissa(srcdst, varamount) \
+ Sall(srcdst) = \
+ (Sexponentmantissa(srcdst) >> varamount) | \
+ (Sall(srcdst) & ((unsigned int)1<<31))
+
+#define Sgl_leftshiftby1_withextent(left,right,result) \
+ Shiftdouble(Sall(left),Extall(right),31,Sall(result))
+
+#define Sgl_rightshiftby1_withextent(left,right,dst) \
+ Shiftdouble(Sall(left),Extall(right),1,Extall(right))
+#define Sgl_arithrightshiftby1(srcdst) \
+ Sall(srcdst) = (int)Sall(srcdst) >> 1
+
+/* Sign extend the sign bit with an integer destination */
+#define Sgl_signextendedsign(value) Ssignedsign(value)
+
+#define Sgl_isone_hidden(sgl_value) (Shidden(sgl_value))
+#define Sgl_increment(sgl_value) Sall(sgl_value) += 1
+#define Sgl_increment_mantissa(sgl_value) \
+ Deposit_smantissa(sgl_value,sgl_value+1)
+#define Sgl_decrement(sgl_value) Sall(sgl_value) -= 1
+
+#define Sgl_isone_sign(sgl_value) (Is_ssign(sgl_value)!=0)
+#define Sgl_isone_hiddenoverflow(sgl_value) \
+ (Is_shiddenoverflow(sgl_value)!=0)
+#define Sgl_isone_lowmantissa(sgl_value) (Is_slow(sgl_value)!=0)
+#define Sgl_isone_signaling(sgl_value) (Is_ssignaling(sgl_value)!=0)
+#define Sgl_is_signalingnan(sgl_value) (Ssignalingnan(sgl_value)==0x1ff)
+#define Sgl_isnotzero(sgl_value) (Sall(sgl_value)!=0)
+#define Sgl_isnotzero_hiddenhigh7mantissa(sgl_value) \
+ (Shiddenhigh7mantissa(sgl_value)!=0)
+#define Sgl_isnotzero_low4(sgl_value) (Slow4(sgl_value)!=0)
+#define Sgl_isnotzero_exponent(sgl_value) (Sexponent(sgl_value)!=0)
+#define Sgl_isnotzero_mantissa(sgl_value) (Smantissa(sgl_value)!=0)
+#define Sgl_isnotzero_exponentmantissa(sgl_value) \
+ (Sexponentmantissa(sgl_value)!=0)
+#define Sgl_iszero(sgl_value) (Sall(sgl_value)==0)
+#define Sgl_iszero_signaling(sgl_value) (Is_ssignaling(sgl_value)==0)
+#define Sgl_iszero_hidden(sgl_value) (Is_shidden(sgl_value)==0)
+#define Sgl_iszero_hiddenoverflow(sgl_value) \
+ (Is_shiddenoverflow(sgl_value)==0)
+#define Sgl_iszero_hiddenhigh3mantissa(sgl_value) \
+ (Shiddenhigh3mantissa(sgl_value)==0)
+#define Sgl_iszero_hiddenhigh7mantissa(sgl_value) \
+ (Shiddenhigh7mantissa(sgl_value)==0)
+#define Sgl_iszero_sign(sgl_value) (Is_ssign(sgl_value)==0)
+#define Sgl_iszero_exponent(sgl_value) (Sexponent(sgl_value)==0)
+#define Sgl_iszero_mantissa(sgl_value) (Smantissa(sgl_value)==0)
+#define Sgl_iszero_exponentmantissa(sgl_value) \
+ (Sexponentmantissa(sgl_value)==0)
+#define Sgl_isinfinity_exponent(sgl_value) \
+ (Sgl_exponent(sgl_value)==SGL_INFINITY_EXPONENT)
+#define Sgl_isnotinfinity_exponent(sgl_value) \
+ (Sgl_exponent(sgl_value)!=SGL_INFINITY_EXPONENT)
+#define Sgl_isinfinity(sgl_value) \
+ (Sgl_exponent(sgl_value)==SGL_INFINITY_EXPONENT && \
+ Sgl_mantissa(sgl_value)==0)
+#define Sgl_isnan(sgl_value) \
+ (Sgl_exponent(sgl_value)==SGL_INFINITY_EXPONENT && \
+ Sgl_mantissa(sgl_value)!=0)
+#define Sgl_isnotnan(sgl_value) \
+ (Sgl_exponent(sgl_value)!=SGL_INFINITY_EXPONENT || \
+ Sgl_mantissa(sgl_value)==0)
+#define Sgl_islessthan(sgl_op1,sgl_op2) \
+ (Sall(sgl_op1) < Sall(sgl_op2))
+#define Sgl_isgreaterthan(sgl_op1,sgl_op2) \
+ (Sall(sgl_op1) > Sall(sgl_op2))
+#define Sgl_isnotlessthan(sgl_op1,sgl_op2) \
+ (Sall(sgl_op1) >= Sall(sgl_op2))
+#define Sgl_isequal(sgl_op1,sgl_op2) \
+ (Sall(sgl_op1) == Sall(sgl_op2))
+
+#define Sgl_leftshiftby8(sgl_value) \
+ Sall(sgl_value) <<= 8
+#define Sgl_leftshiftby4(sgl_value) \
+ Sall(sgl_value) <<= 4
+#define Sgl_leftshiftby3(sgl_value) \
+ Sall(sgl_value) <<= 3
+#define Sgl_leftshiftby2(sgl_value) \
+ Sall(sgl_value) <<= 2
+#define Sgl_leftshiftby1(sgl_value) \
+ Sall(sgl_value) <<= 1
+#define Sgl_rightshiftby1(sgl_value) \
+ Sall(sgl_value) >>= 1
+#define Sgl_rightshiftby4(sgl_value) \
+ Sall(sgl_value) >>= 4
+#define Sgl_rightshiftby8(sgl_value) \
+ Sall(sgl_value) >>= 8
+
+#define Sgl_ismagnitudeless(signlessleft,signlessright) \
+/* unsigned int signlessleft, signlessright; */ \
+ (signlessleft < signlessright)
+
+
+#define Sgl_copytoint_exponentmantissa(source,dest) \
+ dest = Sexponentmantissa(source)
+
+/* A quiet NaN has the high mantissa bit clear and at least on other (in this
+ * case the adjacent bit) bit set. */
+#define Sgl_set_quiet(sgl_value) Deposit_shigh2mantissa(sgl_value,1)
+#define Sgl_set_exponent(sgl_value,exp) Deposit_sexponent(sgl_value,exp)
+
+#define Sgl_set_mantissa(dest,value) Deposit_smantissa(dest,value)
+#define Sgl_set_exponentmantissa(dest,value) \
+ Deposit_sexponentmantissa(dest,value)
+
+/* An infinity is represented with the max exponent and a zero mantissa */
+#define Sgl_setinfinity_exponent(sgl_value) \
+ Deposit_sexponent(sgl_value,SGL_INFINITY_EXPONENT)
+#define Sgl_setinfinity_exponentmantissa(sgl_value) \
+ Deposit_sexponentmantissa(sgl_value, \
+ (SGL_INFINITY_EXPONENT << (32-(1+SGL_EXP_LENGTH))))
+#define Sgl_setinfinitypositive(sgl_value) \
+ Sall(sgl_value) = (SGL_INFINITY_EXPONENT << (32-(1+SGL_EXP_LENGTH)))
+#define Sgl_setinfinitynegative(sgl_value) \
+ Sall(sgl_value) = (SGL_INFINITY_EXPONENT << (32-(1+SGL_EXP_LENGTH))) \
+ | ((unsigned int)1<<31)
+#define Sgl_setinfinity(sgl_value,sign) \
+ Sall(sgl_value) = (SGL_INFINITY_EXPONENT << (32-(1+SGL_EXP_LENGTH))) | \
+ ((unsigned int)sign << 31)
+#define Sgl_sethigh4bits(sgl_value, extsign) \
+ Deposit_shigh4(sgl_value,extsign)
+#define Sgl_set_sign(sgl_value,sign) Deposit_ssign(sgl_value,sign)
+#define Sgl_invert_sign(sgl_value) \
+ Deposit_ssign(sgl_value,~Ssign(sgl_value))
+#define Sgl_setone_sign(sgl_value) Deposit_ssign(sgl_value,1)
+#define Sgl_setone_lowmantissa(sgl_value) Deposit_slow(sgl_value,1)
+#define Sgl_setzero_sign(sgl_value) Sall(sgl_value) &= 0x7fffffff
+#define Sgl_setzero_exponent(sgl_value) Sall(sgl_value) &= 0x807fffff
+#define Sgl_setzero_mantissa(sgl_value) Sall(sgl_value) &= 0xff800000
+#define Sgl_setzero_exponentmantissa(sgl_value) Sall(sgl_value) &= 0x80000000
+#define Sgl_setzero(sgl_value) Sall(sgl_value) = 0
+#define Sgl_setnegativezero(sgl_value) Sall(sgl_value) = (unsigned int)1 << 31
+
+/* Use following macro for both overflow & underflow conditions */
+#define ovfl -
+#define unfl +
+#define Sgl_setwrapped_exponent(sgl_value,exponent,op) \
+ Deposit_sexponent(sgl_value,(exponent op SGL_WRAP))
+
+#define Sgl_setlargestpositive(sgl_value) \
+ Sall(sgl_value) = ((SGL_EMAX+SGL_BIAS) << (32-(1+SGL_EXP_LENGTH))) \
+ | ((1<<(32-(1+SGL_EXP_LENGTH))) - 1 )
+#define Sgl_setlargestnegative(sgl_value) \
+ Sall(sgl_value) = ((SGL_EMAX+SGL_BIAS) << (32-(1+SGL_EXP_LENGTH))) \
+ | ((1<<(32-(1+SGL_EXP_LENGTH))) - 1 ) \
+ | ((unsigned int)1<<31)
+
+#define Sgl_setnegativeinfinity(sgl_value) \
+ Sall(sgl_value) = \
+ ((1<<SGL_EXP_LENGTH) | SGL_INFINITY_EXPONENT) << (32-(1+SGL_EXP_LENGTH))
+#define Sgl_setlargest(sgl_value,sign) \
+ Sall(sgl_value) = (unsigned int)sign << 31 | \
+ (((SGL_EMAX+SGL_BIAS) << (32-(1+SGL_EXP_LENGTH))) \
+ | ((1 << (32-(1+SGL_EXP_LENGTH))) - 1 ))
+#define Sgl_setlargest_exponentmantissa(sgl_value) \
+ Sall(sgl_value) = Sall(sgl_value) & ((unsigned int)1<<31) | \
+ (((SGL_EMAX+SGL_BIAS) << (32-(1+SGL_EXP_LENGTH))) \
+ | ((1 << (32-(1+SGL_EXP_LENGTH))) - 1 ))
+
+/* The high bit is always zero so arithmetic or logical shifts will work. */
+#define Sgl_right_align(srcdst,shift,extent) \
+ /* sgl_floating_point srcdst; int shift; extension extent */ \
+ if (shift < 32) { \
+ Extall(extent) = Sall(srcdst) << (32-(shift)); \
+ Sall(srcdst) >>= shift; \
+ } \
+ else { \
+ Extall(extent) = Sall(srcdst); \
+ Sall(srcdst) = 0; \
+ }
+#define Sgl_hiddenhigh3mantissa(sgl_value) Shiddenhigh3mantissa(sgl_value)
+#define Sgl_hidden(sgl_value) Shidden(sgl_value)
+#define Sgl_lowmantissa(sgl_value) Slow(sgl_value)
+
+/* The left argument is never smaller than the right argument */
+#define Sgl_subtract(sgl_left,sgl_right,sgl_result) \
+ Sall(sgl_result) = Sall(sgl_left) - Sall(sgl_right)
+
+/* Subtract right augmented with extension from left augmented with zeros and
+ * store into result and extension. */
+#define Sgl_subtract_withextension(left,right,extent,result) \
+ /* sgl_floating_point left,right,result; extension extent */ \
+ Sgl_subtract(left,right,result); \
+ if((Extall(extent) = 0-Extall(extent))) \
+ Sall(result) = Sall(result)-1
+
+#define Sgl_addition(sgl_left,sgl_right,sgl_result) \
+ Sall(sgl_result) = Sall(sgl_left) + Sall(sgl_right)
+
+#define Sgl_xortointp1(left,right,result) \
+ result = Sall(left) XOR Sall(right);
+
+#define Sgl_xorfromintp1(left,right,result) \
+ Sall(result) = left XOR Sall(right)
+
+/* Need to Initialize */
+#define Sgl_makequietnan(dest) \
+ Sall(dest) = ((SGL_EMAX+SGL_BIAS)+1)<< (32-(1+SGL_EXP_LENGTH)) \
+ | (1<<(32-(1+SGL_EXP_LENGTH+2)))
+#define Sgl_makesignalingnan(dest) \
+ Sall(dest) = ((SGL_EMAX+SGL_BIAS)+1)<< (32-(1+SGL_EXP_LENGTH)) \
+ | (1<<(32-(1+SGL_EXP_LENGTH+1)))
+
+#define Sgl_normalize(sgl_opnd,exponent) \
+ while(Sgl_iszero_hiddenhigh7mantissa(sgl_opnd)) { \
+ Sgl_leftshiftby8(sgl_opnd); \
+ exponent -= 8; \
+ } \
+ if(Sgl_iszero_hiddenhigh3mantissa(sgl_opnd)) { \
+ Sgl_leftshiftby4(sgl_opnd); \
+ exponent -= 4; \
+ } \
+ while(Sgl_iszero_hidden(sgl_opnd)) { \
+ Sgl_leftshiftby1(sgl_opnd); \
+ exponent -= 1; \
+ }
+
+#define Sgl_setoverflow(sgl_opnd) \
+ /* set result to infinity or largest number */ \
+ switch (Rounding_mode()) { \
+ case ROUNDPLUS: \
+ if (Sgl_isone_sign(sgl_opnd)) { \
+ Sgl_setlargestnegative(sgl_opnd); \
+ } \
+ else { \
+ Sgl_setinfinitypositive(sgl_opnd); \
+ } \
+ break; \
+ case ROUNDMINUS: \
+ if (Sgl_iszero_sign(sgl_opnd)) { \
+ Sgl_setlargestpositive(sgl_opnd); \
+ } \
+ else { \
+ Sgl_setinfinitynegative(sgl_opnd); \
+ } \
+ break; \
+ case ROUNDNEAREST: \
+ Sgl_setinfinity_exponentmantissa(sgl_opnd); \
+ break; \
+ case ROUNDZERO: \
+ Sgl_setlargest_exponentmantissa(sgl_opnd); \
+ }
+
+#define Sgl_denormalize(opnd,exponent,guard,sticky,inexact) \
+ Sgl_clear_signexponent_set_hidden(opnd); \
+ if (exponent >= (1 - SGL_P)) { \
+ guard = (Sall(opnd) >> -exponent) & 1; \
+ if (exponent < 0) sticky |= Sall(opnd) << (32+exponent); \
+ inexact = guard | sticky; \
+ Sall(opnd) >>= (1-exponent); \
+ } \
+ else { \
+ guard = 0; \
+ sticky |= Sall(opnd); \
+ inexact = sticky; \
+ Sgl_setzero(opnd); \
+ }
+
+/*
+ * The fused multiply add instructions requires a single extended format,
+ * with 48 bits of mantissa.
+ */
+#define SGLEXT_THRESHOLD 48
+
+#define Sglext_setzero(valA,valB) \
+ Sextallp1(valA) = 0; Sextallp2(valB) = 0
+
+#define Sglext_isnotzero_mantissap2(valB) (Sextallp2(valB)!=0)
+#define Sglext_isone_lowp1(val) (Sextlowp1(val)!=0)
+#define Sglext_isone_highp2(val) (Sexthighp2(val)!=0)
+#define Sglext_isnotzero_low31p2(val) (Sextlow31p2(val)!=0)
+#define Sglext_iszero(valA,valB) (Sextallp1(valA)==0 && Sextallp2(valB)==0)
+
+#define Sgl_copytoptr(src,destptr) *destptr = src
+#define Sgl_copyfromptr(srcptr,dest) dest = *srcptr
+#define Sglext_copy(srca,srcb,desta,destb) \
+ Sextallp1(desta) = Sextallp1(srca); \
+ Sextallp2(destb) = Sextallp2(srcb)
+#define Sgl_copyto_sglext(src1,dest1,dest2) \
+ Sextallp1(dest1) = Sall(src1); Sextallp2(dest2) = 0
+
+#define Sglext_swap_lower(leftp2,rightp2) \
+ Sextallp2(leftp2) = Sextallp2(leftp2) XOR Sextallp2(rightp2); \
+ Sextallp2(rightp2) = Sextallp2(leftp2) XOR Sextallp2(rightp2); \
+ Sextallp2(leftp2) = Sextallp2(leftp2) XOR Sextallp2(rightp2)
+
+#define Sglext_setone_lowmantissap2(value) Deposit_dlowp2(value,1)
+
+/* The high bit is always zero so arithmetic or logical shifts will work. */
+#define Sglext_right_align(srcdstA,srcdstB,shift) \
+ {int shiftamt, sticky; \
+ shiftamt = shift % 32; \
+ sticky = 0; \
+ switch (shift/32) { \
+ case 0: if (shiftamt > 0) { \
+ sticky = Sextallp2(srcdstB) << 32 - (shiftamt); \
+ Variable_shift_double(Sextallp1(srcdstA), \
+ Sextallp2(srcdstB),shiftamt,Sextallp2(srcdstB)); \
+ Sextallp1(srcdstA) >>= shiftamt; \
+ } \
+ break; \
+ case 1: if (shiftamt > 0) { \
+ sticky = (Sextallp1(srcdstA) << 32 - (shiftamt)) | \
+ Sextallp2(srcdstB); \
+ } \
+ else { \
+ sticky = Sextallp2(srcdstB); \
+ } \
+ Sextallp2(srcdstB) = Sextallp1(srcdstA) >> shiftamt; \
+ Sextallp1(srcdstA) = 0; \
+ break; \
+ } \
+ if (sticky) Sglext_setone_lowmantissap2(srcdstB); \
+ }
+
+/* The left argument is never smaller than the right argument */
+#define Sglext_subtract(lefta,leftb,righta,rightb,resulta,resultb) \
+ if( Sextallp2(rightb) > Sextallp2(leftb) ) Sextallp1(lefta)--; \
+ Sextallp2(resultb) = Sextallp2(leftb) - Sextallp2(rightb); \
+ Sextallp1(resulta) = Sextallp1(lefta) - Sextallp1(righta)
+
+#define Sglext_addition(lefta,leftb,righta,rightb,resulta,resultb) \
+ /* If the sum of the low words is less than either source, then \
+ * an overflow into the next word occurred. */ \
+ if ((Sextallp2(resultb) = Sextallp2(leftb)+Sextallp2(rightb)) < \
+ Sextallp2(rightb)) \
+ Sextallp1(resulta) = Sextallp1(lefta)+Sextallp1(righta)+1; \
+ else Sextallp1(resulta) = Sextallp1(lefta)+Sextallp1(righta)
+
+
+#define Sglext_arithrightshiftby1(srcdstA,srcdstB) \
+ Shiftdouble(Sextallp1(srcdstA),Sextallp2(srcdstB),1,Sextallp2(srcdstB)); \
+ Sextallp1(srcdstA) = (int)Sextallp1(srcdstA) >> 1
+
+#define Sglext_leftshiftby8(valA,valB) \
+ Shiftdouble(Sextallp1(valA),Sextallp2(valB),24,Sextallp1(valA)); \
+ Sextallp2(valB) <<= 8
+#define Sglext_leftshiftby4(valA,valB) \
+ Shiftdouble(Sextallp1(valA),Sextallp2(valB),28,Sextallp1(valA)); \
+ Sextallp2(valB) <<= 4
+#define Sglext_leftshiftby3(valA,valB) \
+ Shiftdouble(Sextallp1(valA),Sextallp2(valB),29,Sextallp1(valA)); \
+ Sextallp2(valB) <<= 3
+#define Sglext_leftshiftby2(valA,valB) \
+ Shiftdouble(Sextallp1(valA),Sextallp2(valB),30,Sextallp1(valA)); \
+ Sextallp2(valB) <<= 2
+#define Sglext_leftshiftby1(valA,valB) \
+ Shiftdouble(Sextallp1(valA),Sextallp2(valB),31,Sextallp1(valA)); \
+ Sextallp2(valB) <<= 1
+
+#define Sglext_rightshiftby4(valueA,valueB) \
+ Shiftdouble(Sextallp1(valueA),Sextallp2(valueB),4,Sextallp2(valueB)); \
+ Sextallp1(valueA) >>= 4
+#define Sglext_rightshiftby3(valueA,valueB) \
+ Shiftdouble(Sextallp1(valueA),Sextallp2(valueB),3,Sextallp2(valueB)); \
+ Sextallp1(valueA) >>= 3
+#define Sglext_rightshiftby1(valueA,valueB) \
+ Shiftdouble(Sextallp1(valueA),Sextallp2(valueB),1,Sextallp2(valueB)); \
+ Sextallp1(valueA) >>= 1
+
+#define Sglext_xortointp1(left,right,result) Sgl_xortointp1(left,right,result)
+#define Sglext_xorfromintp1(left,right,result) \
+ Sgl_xorfromintp1(left,right,result)
+#define Sglext_copytoint_exponentmantissa(src,dest) \
+ Sgl_copytoint_exponentmantissa(src,dest)
+#define Sglext_ismagnitudeless(signlessleft,signlessright) \
+ Sgl_ismagnitudeless(signlessleft,signlessright)
+
+#define Sglext_set_sign(dbl_value,sign) Sgl_set_sign(dbl_value,sign)
+#define Sglext_clear_signexponent_set_hidden(srcdst) \
+ Sgl_clear_signexponent_set_hidden(srcdst)
+#define Sglext_clear_signexponent(srcdst) Sgl_clear_signexponent(srcdst)
+#define Sglext_clear_sign(srcdst) Sgl_clear_sign(srcdst)
+#define Sglext_isone_hidden(dbl_value) Sgl_isone_hidden(dbl_value)
+
+#define Sglext_denormalize(opndp1,opndp2,exponent,is_tiny) \
+ {int sticky; \
+ is_tiny = TRUE; \
+ if (exponent == 0 && Sextallp2(opndp2)) { \
+ switch (Rounding_mode()) { \
+ case ROUNDPLUS: \
+ if (Sgl_iszero_sign(opndp1)) \
+ if (Sgl_isone_hiddenoverflow(opndp1 + 1)) \
+ is_tiny = FALSE; \
+ break; \
+ case ROUNDMINUS: \
+ if (Sgl_isone_sign(opndp1)) { \
+ if (Sgl_isone_hiddenoverflow(opndp1 + 1)) \
+ is_tiny = FALSE; \
+ } \
+ break; \
+ case ROUNDNEAREST: \
+ if (Sglext_isone_highp2(opndp2) && \
+ (Sglext_isone_lowp1(opndp1) || \
+ Sglext_isnotzero_low31p2(opndp2))) \
+ if (Sgl_isone_hiddenoverflow(opndp1 + 1)) \
+ is_tiny = FALSE; \
+ break; \
+ } \
+ } \
+ Sglext_clear_signexponent_set_hidden(opndp1); \
+ if (exponent >= (1-DBL_P)) { \
+ if (exponent >= -31) { \
+ if (exponent > -31) { \
+ sticky = Sextallp2(opndp2) << 31+exponent; \
+ Variable_shift_double(opndp1,opndp2,1-exponent,opndp2); \
+ Sextallp1(opndp1) >>= 1-exponent; \
+ } \
+ else { \
+ sticky = Sextallp2(opndp2); \
+ Sextallp2(opndp2) = Sextallp1(opndp1); \
+ Sextallp1(opndp1) = 0; \
+ } \
+ } \
+ else { \
+ sticky = (Sextallp1(opndp1) << 31+exponent) | \
+ Sextallp2(opndp2); \
+ Sextallp2(opndp2) = Sextallp1(opndp1) >> -31-exponent; \
+ Sextallp1(opndp1) = 0; \
+ } \
+ } \
+ else { \
+ sticky = Sextallp1(opndp1) | Sextallp2(opndp2); \
+ Sglext_setzero(opndp1,opndp2); \
+ } \
+ if (sticky) Sglext_setone_lowmantissap2(opndp2); \
+ exponent = 0; \
+ }
diff --git a/arch/parisc/mm/Makefile b/arch/parisc/mm/Makefile
new file mode 100644
index 000000000..ffdb5c0a8
--- /dev/null
+++ b/arch/parisc/mm/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Makefile for arch/parisc/mm
+#
+
+obj-y := init.o fault.o ioremap.o fixmap.o
+obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
diff --git a/arch/parisc/mm/fault.c b/arch/parisc/mm/fault.c
new file mode 100644
index 000000000..2fe5b4498
--- /dev/null
+++ b/arch/parisc/mm/fault.c
@@ -0,0 +1,526 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ *
+ * Copyright (C) 1995, 1996, 1997, 1998 by Ralf Baechle
+ * Copyright 1999 SuSE GmbH (Philipp Rumpf, prumpf@tux.org)
+ * Copyright 1999 Hewlett Packard Co.
+ *
+ */
+
+#include <linux/mm.h>
+#include <linux/ptrace.h>
+#include <linux/sched.h>
+#include <linux/sched/debug.h>
+#include <linux/interrupt.h>
+#include <linux/extable.h>
+#include <linux/uaccess.h>
+#include <linux/hugetlb.h>
+#include <linux/perf_event.h>
+
+#include <asm/traps.h>
+
+#define DEBUG_NATLB 0
+
+/* Various important other fields */
+#define bit22set(x) (x & 0x00000200)
+#define bits23_25set(x) (x & 0x000001c0)
+#define isGraphicsFlushRead(x) ((x & 0xfc003fdf) == 0x04001a80)
+ /* extended opcode is 0x6a */
+
+#define BITSSET 0x1c0 /* for identifying LDCW */
+
+
+int show_unhandled_signals = 1;
+
+/*
+ * parisc_acctyp(unsigned int inst) --
+ * Given a PA-RISC memory access instruction, determine if the
+ * instruction would perform a memory read or memory write
+ * operation.
+ *
+ * This function assumes that the given instruction is a memory access
+ * instruction (i.e. you should really only call it if you know that
+ * the instruction has generated some sort of a memory access fault).
+ *
+ * Returns:
+ * VM_READ if read operation
+ * VM_WRITE if write operation
+ * VM_EXEC if execute operation
+ */
+unsigned long
+parisc_acctyp(unsigned long code, unsigned int inst)
+{
+ if (code == 6 || code == 16)
+ return VM_EXEC;
+
+ switch (inst & 0xf0000000) {
+ case 0x40000000: /* load */
+ case 0x50000000: /* new load */
+ return VM_READ;
+
+ case 0x60000000: /* store */
+ case 0x70000000: /* new store */
+ return VM_WRITE;
+
+ case 0x20000000: /* coproc */
+ case 0x30000000: /* coproc2 */
+ if (bit22set(inst))
+ return VM_WRITE;
+ fallthrough;
+
+ case 0x0: /* indexed/memory management */
+ if (bit22set(inst)) {
+ /*
+ * Check for the 'Graphics Flush Read' instruction.
+ * It resembles an FDC instruction, except for bits
+ * 20 and 21. Any combination other than zero will
+ * utilize the block mover functionality on some
+ * older PA-RISC platforms. The case where a block
+ * move is performed from VM to graphics IO space
+ * should be treated as a READ.
+ *
+ * The significance of bits 20,21 in the FDC
+ * instruction is:
+ *
+ * 00 Flush data cache (normal instruction behavior)
+ * 01 Graphics flush write (IO space -> VM)
+ * 10 Graphics flush read (VM -> IO space)
+ * 11 Graphics flush read/write (VM <-> IO space)
+ */
+ if (isGraphicsFlushRead(inst))
+ return VM_READ;
+ return VM_WRITE;
+ } else {
+ /*
+ * Check for LDCWX and LDCWS (semaphore instructions).
+ * If bits 23 through 25 are all 1's it is one of
+ * the above two instructions and is a write.
+ *
+ * Note: With the limited bits we are looking at,
+ * this will also catch PROBEW and PROBEWI. However,
+ * these should never get in here because they don't
+ * generate exceptions of the type:
+ * Data TLB miss fault/data page fault
+ * Data memory protection trap
+ */
+ if (bits23_25set(inst) == BITSSET)
+ return VM_WRITE;
+ }
+ return VM_READ; /* Default */
+ }
+ return VM_READ; /* Default */
+}
+
+#undef bit22set
+#undef bits23_25set
+#undef isGraphicsFlushRead
+#undef BITSSET
+
+
+#if 0
+/* This is the treewalk to find a vma which is the highest that has
+ * a start < addr. We're using find_vma_prev instead right now, but
+ * we might want to use this at some point in the future. Probably
+ * not, but I want it committed to CVS so I don't lose it :-)
+ */
+ while (tree != vm_avl_empty) {
+ if (tree->vm_start > addr) {
+ tree = tree->vm_avl_left;
+ } else {
+ prev = tree;
+ if (prev->vm_next == NULL)
+ break;
+ if (prev->vm_next->vm_start > addr)
+ break;
+ tree = tree->vm_avl_right;
+ }
+ }
+#endif
+
+int fixup_exception(struct pt_regs *regs)
+{
+ const struct exception_table_entry *fix;
+
+ fix = search_exception_tables(regs->iaoq[0]);
+ if (fix) {
+ /*
+ * Fix up get_user() and put_user().
+ * ASM_EXCEPTIONTABLE_ENTRY_EFAULT() sets the least-significant
+ * bit in the relative address of the fixup routine to indicate
+ * that gr[ASM_EXCEPTIONTABLE_REG] should be loaded with
+ * -EFAULT to report a userspace access error.
+ */
+ if (fix->fixup & 1) {
+ regs->gr[ASM_EXCEPTIONTABLE_REG] = -EFAULT;
+
+ /* zero target register for get_user() */
+ if (parisc_acctyp(0, regs->iir) == VM_READ) {
+ int treg = regs->iir & 0x1f;
+ BUG_ON(treg == 0);
+ regs->gr[treg] = 0;
+ }
+ }
+
+ regs->iaoq[0] = (unsigned long)&fix->fixup + fix->fixup;
+ regs->iaoq[0] &= ~3;
+ /*
+ * NOTE: In some cases the faulting instruction
+ * may be in the delay slot of a branch. We
+ * don't want to take the branch, so we don't
+ * increment iaoq[1], instead we set it to be
+ * iaoq[0]+4, and clear the B bit in the PSW
+ */
+ regs->iaoq[1] = regs->iaoq[0] + 4;
+ regs->gr[0] &= ~PSW_B; /* IPSW in gr[0] */
+
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * parisc hardware trap list
+ *
+ * Documented in section 3 "Addressing and Access Control" of the
+ * "PA-RISC 1.1 Architecture and Instruction Set Reference Manual"
+ * https://parisc.wiki.kernel.org/index.php/File:Pa11_acd.pdf
+ *
+ * For implementation see handle_interruption() in traps.c
+ */
+static const char * const trap_description[] = {
+ [1] = "High-priority machine check (HPMC)",
+ [2] = "Power failure interrupt",
+ [3] = "Recovery counter trap",
+ [5] = "Low-priority machine check",
+ [6] = "Instruction TLB miss fault",
+ [7] = "Instruction access rights / protection trap",
+ [8] = "Illegal instruction trap",
+ [9] = "Break instruction trap",
+ [10] = "Privileged operation trap",
+ [11] = "Privileged register trap",
+ [12] = "Overflow trap",
+ [13] = "Conditional trap",
+ [14] = "FP Assist Exception trap",
+ [15] = "Data TLB miss fault",
+ [16] = "Non-access ITLB miss fault",
+ [17] = "Non-access DTLB miss fault",
+ [18] = "Data memory protection/unaligned access trap",
+ [19] = "Data memory break trap",
+ [20] = "TLB dirty bit trap",
+ [21] = "Page reference trap",
+ [22] = "Assist emulation trap",
+ [25] = "Taken branch trap",
+ [26] = "Data memory access rights trap",
+ [27] = "Data memory protection ID trap",
+ [28] = "Unaligned data reference trap",
+};
+
+const char *trap_name(unsigned long code)
+{
+ const char *t = NULL;
+
+ if (code < ARRAY_SIZE(trap_description))
+ t = trap_description[code];
+
+ return t ? t : "Unknown trap";
+}
+
+/*
+ * Print out info about fatal segfaults, if the show_unhandled_signals
+ * sysctl is set:
+ */
+static inline void
+show_signal_msg(struct pt_regs *regs, unsigned long code,
+ unsigned long address, struct task_struct *tsk,
+ struct vm_area_struct *vma)
+{
+ if (!unhandled_signal(tsk, SIGSEGV))
+ return;
+
+ if (!printk_ratelimit())
+ return;
+
+ pr_warn("\n");
+ pr_warn("do_page_fault() command='%s' type=%lu address=0x%08lx",
+ tsk->comm, code, address);
+ print_vma_addr(KERN_CONT " in ", regs->iaoq[0]);
+
+ pr_cont("\ntrap #%lu: %s%c", code, trap_name(code),
+ vma ? ',':'\n');
+
+ if (vma)
+ pr_cont(" vm_start = 0x%08lx, vm_end = 0x%08lx\n",
+ vma->vm_start, vma->vm_end);
+
+ show_regs(regs);
+}
+
+void do_page_fault(struct pt_regs *regs, unsigned long code,
+ unsigned long address)
+{
+ struct vm_area_struct *vma, *prev_vma;
+ struct task_struct *tsk;
+ struct mm_struct *mm;
+ unsigned long acc_type;
+ vm_fault_t fault = 0;
+ unsigned int flags;
+ char *msg;
+
+ tsk = current;
+ mm = tsk->mm;
+ if (!mm) {
+ msg = "Page fault: no context";
+ goto no_context;
+ }
+
+ flags = FAULT_FLAG_DEFAULT;
+ if (user_mode(regs))
+ flags |= FAULT_FLAG_USER;
+
+ acc_type = parisc_acctyp(code, regs->iir);
+ if (acc_type & VM_WRITE)
+ flags |= FAULT_FLAG_WRITE;
+ perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS, 1, regs, address);
+retry:
+ mmap_read_lock(mm);
+ vma = find_vma_prev(mm, address, &prev_vma);
+ if (!vma || address < vma->vm_start) {
+ if (!prev_vma || !(prev_vma->vm_flags & VM_GROWSUP))
+ goto bad_area;
+ vma = expand_stack(mm, address);
+ if (!vma)
+ goto bad_area_nosemaphore;
+ }
+
+/*
+ * Ok, we have a good vm_area for this memory access. We still need to
+ * check the access permissions.
+ */
+
+ if ((vma->vm_flags & acc_type) != acc_type)
+ goto bad_area;
+
+ /*
+ * If for any reason at all we couldn't handle the fault, make
+ * sure we exit gracefully rather than endlessly redo the
+ * fault.
+ */
+
+ fault = handle_mm_fault(vma, address, flags, regs);
+
+ if (fault_signal_pending(fault, regs)) {
+ if (!user_mode(regs)) {
+ msg = "Page fault: fault signal on kernel memory";
+ goto no_context;
+ }
+ return;
+ }
+
+ /* The fault is fully completed (including releasing mmap lock) */
+ if (fault & VM_FAULT_COMPLETED)
+ return;
+
+ if (unlikely(fault & VM_FAULT_ERROR)) {
+ /*
+ * We hit a shared mapping outside of the file, or some
+ * other thing happened to us that made us unable to
+ * handle the page fault gracefully.
+ */
+ if (fault & VM_FAULT_OOM)
+ goto out_of_memory;
+ else if (fault & VM_FAULT_SIGSEGV)
+ goto bad_area;
+ else if (fault & (VM_FAULT_SIGBUS|VM_FAULT_HWPOISON|
+ VM_FAULT_HWPOISON_LARGE))
+ goto bad_area;
+ BUG();
+ }
+ if (fault & VM_FAULT_RETRY) {
+ /*
+ * No need to mmap_read_unlock(mm) as we would
+ * have already released it in __lock_page_or_retry
+ * in mm/filemap.c.
+ */
+ flags |= FAULT_FLAG_TRIED;
+ goto retry;
+ }
+ mmap_read_unlock(mm);
+ return;
+
+/*
+ * Something tried to access memory that isn't in our memory map..
+ */
+bad_area:
+ mmap_read_unlock(mm);
+
+bad_area_nosemaphore:
+ if (user_mode(regs)) {
+ int signo, si_code;
+
+ switch (code) {
+ case 15: /* Data TLB miss fault/Data page fault */
+ /* send SIGSEGV when outside of vma */
+ if (!vma ||
+ address < vma->vm_start || address >= vma->vm_end) {
+ signo = SIGSEGV;
+ si_code = SEGV_MAPERR;
+ break;
+ }
+
+ /* send SIGSEGV for wrong permissions */
+ if ((vma->vm_flags & acc_type) != acc_type) {
+ signo = SIGSEGV;
+ si_code = SEGV_ACCERR;
+ break;
+ }
+
+ /* probably address is outside of mapped file */
+ fallthrough;
+ case 17: /* NA data TLB miss / page fault */
+ case 18: /* Unaligned access - PCXS only */
+ signo = SIGBUS;
+ si_code = (code == 18) ? BUS_ADRALN : BUS_ADRERR;
+ break;
+ case 16: /* Non-access instruction TLB miss fault */
+ case 26: /* PCXL: Data memory access rights trap */
+ default:
+ signo = SIGSEGV;
+ si_code = (code == 26) ? SEGV_ACCERR : SEGV_MAPERR;
+ break;
+ }
+#ifdef CONFIG_MEMORY_FAILURE
+ if (fault & (VM_FAULT_HWPOISON|VM_FAULT_HWPOISON_LARGE)) {
+ unsigned int lsb = 0;
+ printk(KERN_ERR
+ "MCE: Killing %s:%d due to hardware memory corruption fault at %08lx\n",
+ tsk->comm, tsk->pid, address);
+ /*
+ * Either small page or large page may be poisoned.
+ * In other words, VM_FAULT_HWPOISON_LARGE and
+ * VM_FAULT_HWPOISON are mutually exclusive.
+ */
+ if (fault & VM_FAULT_HWPOISON_LARGE)
+ lsb = hstate_index_to_shift(VM_FAULT_GET_HINDEX(fault));
+ else if (fault & VM_FAULT_HWPOISON)
+ lsb = PAGE_SHIFT;
+
+ force_sig_mceerr(BUS_MCEERR_AR, (void __user *) address,
+ lsb);
+ return;
+ }
+#endif
+ show_signal_msg(regs, code, address, tsk, vma);
+
+ force_sig_fault(signo, si_code, (void __user *) address);
+ return;
+ }
+ msg = "Page fault: bad address";
+
+no_context:
+
+ if (!user_mode(regs) && fixup_exception(regs)) {
+ return;
+ }
+
+ parisc_terminate(msg, regs, code, address);
+
+out_of_memory:
+ mmap_read_unlock(mm);
+ if (!user_mode(regs)) {
+ msg = "Page fault: out of memory";
+ goto no_context;
+ }
+ pagefault_out_of_memory();
+}
+
+/* Handle non-access data TLB miss faults.
+ *
+ * For probe instructions, accesses to userspace are considered allowed
+ * if they lie in a valid VMA and the access type matches. We are not
+ * allowed to handle MM faults here so there may be situations where an
+ * actual access would fail even though a probe was successful.
+ */
+int
+handle_nadtlb_fault(struct pt_regs *regs)
+{
+ unsigned long insn = regs->iir;
+ int breg, treg, xreg, val = 0;
+ struct vm_area_struct *vma;
+ struct task_struct *tsk;
+ struct mm_struct *mm;
+ unsigned long address;
+ unsigned long acc_type;
+
+ switch (insn & 0x380) {
+ case 0x280:
+ /* FDC instruction */
+ fallthrough;
+ case 0x380:
+ /* PDC and FIC instructions */
+ if (DEBUG_NATLB && printk_ratelimit()) {
+ pr_warn("WARNING: nullifying cache flush/purge instruction\n");
+ show_regs(regs);
+ }
+ if (insn & 0x20) {
+ /* Base modification */
+ breg = (insn >> 21) & 0x1f;
+ xreg = (insn >> 16) & 0x1f;
+ if (breg && xreg)
+ regs->gr[breg] += regs->gr[xreg];
+ }
+ regs->gr[0] |= PSW_N;
+ return 1;
+
+ case 0x180:
+ /* PROBE instruction */
+ treg = insn & 0x1f;
+ if (regs->isr) {
+ tsk = current;
+ mm = tsk->mm;
+ if (mm) {
+ /* Search for VMA */
+ address = regs->ior;
+ mmap_read_lock(mm);
+ vma = vma_lookup(mm, address);
+ mmap_read_unlock(mm);
+
+ /*
+ * Check if access to the VMA is okay.
+ * We don't allow for stack expansion.
+ */
+ acc_type = (insn & 0x40) ? VM_WRITE : VM_READ;
+ if (vma
+ && (vma->vm_flags & acc_type) == acc_type)
+ val = 1;
+ }
+ }
+ if (treg)
+ regs->gr[treg] = val;
+ regs->gr[0] |= PSW_N;
+ return 1;
+
+ case 0x300:
+ /* LPA instruction */
+ if (insn & 0x20) {
+ /* Base modification */
+ breg = (insn >> 21) & 0x1f;
+ xreg = (insn >> 16) & 0x1f;
+ if (breg && xreg)
+ regs->gr[breg] += regs->gr[xreg];
+ }
+ treg = insn & 0x1f;
+ if (treg)
+ regs->gr[treg] = 0;
+ regs->gr[0] |= PSW_N;
+ return 1;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
diff --git a/arch/parisc/mm/fixmap.c b/arch/parisc/mm/fixmap.c
new file mode 100644
index 000000000..ae3493dae
--- /dev/null
+++ b/arch/parisc/mm/fixmap.c
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * fixmaps for parisc
+ *
+ * Copyright (c) 2019 Sven Schnelle <svens@stackframe.org>
+ */
+
+#include <linux/kprobes.h>
+#include <linux/mm.h>
+#include <asm/cacheflush.h>
+#include <asm/fixmap.h>
+
+void notrace set_fixmap(enum fixed_addresses idx, phys_addr_t phys)
+{
+ unsigned long vaddr = __fix_to_virt(idx);
+ pgd_t *pgd = pgd_offset_k(vaddr);
+ p4d_t *p4d = p4d_offset(pgd, vaddr);
+ pud_t *pud = pud_offset(p4d, vaddr);
+ pmd_t *pmd = pmd_offset(pud, vaddr);
+ pte_t *pte;
+
+ pte = pte_offset_kernel(pmd, vaddr);
+ set_pte_at(&init_mm, vaddr, pte, __mk_pte(phys, PAGE_KERNEL_RWX));
+ flush_tlb_kernel_range(vaddr, vaddr + PAGE_SIZE);
+}
+
+void notrace clear_fixmap(enum fixed_addresses idx)
+{
+ unsigned long vaddr = __fix_to_virt(idx);
+ pte_t *pte = virt_to_kpte(vaddr);
+
+ if (WARN_ON(pte_none(*pte)))
+ return;
+
+ pte_clear(&init_mm, vaddr, pte);
+
+ flush_tlb_kernel_range(vaddr, vaddr + PAGE_SIZE);
+}
diff --git a/arch/parisc/mm/hugetlbpage.c b/arch/parisc/mm/hugetlbpage.c
new file mode 100644
index 000000000..a9f7e21f6
--- /dev/null
+++ b/arch/parisc/mm/hugetlbpage.c
@@ -0,0 +1,193 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * PARISC64 Huge TLB page support.
+ *
+ * This parisc implementation is heavily based on the SPARC and x86 code.
+ *
+ * Copyright (C) 2015 Helge Deller <deller@gmx.de>
+ */
+
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/sched/mm.h>
+#include <linux/hugetlb.h>
+#include <linux/pagemap.h>
+#include <linux/sysctl.h>
+
+#include <asm/mman.h>
+#include <asm/tlb.h>
+#include <asm/tlbflush.h>
+#include <asm/cacheflush.h>
+#include <asm/mmu_context.h>
+
+
+unsigned long
+hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
+ unsigned long len, unsigned long pgoff, unsigned long flags)
+{
+ struct hstate *h = hstate_file(file);
+
+ if (len & ~huge_page_mask(h))
+ return -EINVAL;
+ if (len > TASK_SIZE)
+ return -ENOMEM;
+
+ if (flags & MAP_FIXED)
+ if (prepare_hugepage_range(file, addr, len))
+ return -EINVAL;
+
+ if (addr)
+ addr = ALIGN(addr, huge_page_size(h));
+
+ /* we need to make sure the colouring is OK */
+ return arch_get_unmapped_area(file, addr, len, pgoff, flags);
+}
+
+
+pte_t *huge_pte_alloc(struct mm_struct *mm, struct vm_area_struct *vma,
+ unsigned long addr, unsigned long sz)
+{
+ pgd_t *pgd;
+ p4d_t *p4d;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte = NULL;
+
+ /* We must align the address, because our caller will run
+ * set_huge_pte_at() on whatever we return, which writes out
+ * all of the sub-ptes for the hugepage range. So we have
+ * to give it the first such sub-pte.
+ */
+ addr &= HPAGE_MASK;
+
+ pgd = pgd_offset(mm, addr);
+ p4d = p4d_offset(pgd, addr);
+ pud = pud_alloc(mm, p4d, addr);
+ if (pud) {
+ pmd = pmd_alloc(mm, pud, addr);
+ if (pmd)
+ pte = pte_alloc_huge(mm, pmd, addr);
+ }
+ return pte;
+}
+
+pte_t *huge_pte_offset(struct mm_struct *mm,
+ unsigned long addr, unsigned long sz)
+{
+ pgd_t *pgd;
+ p4d_t *p4d;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte = NULL;
+
+ addr &= HPAGE_MASK;
+
+ pgd = pgd_offset(mm, addr);
+ if (!pgd_none(*pgd)) {
+ p4d = p4d_offset(pgd, addr);
+ if (!p4d_none(*p4d)) {
+ pud = pud_offset(p4d, addr);
+ if (!pud_none(*pud)) {
+ pmd = pmd_offset(pud, addr);
+ if (!pmd_none(*pmd))
+ pte = pte_offset_huge(pmd, addr);
+ }
+ }
+ }
+ return pte;
+}
+
+/* Purge data and instruction TLB entries. Must be called holding
+ * the pa_tlb_lock. The TLB purge instructions are slow on SMP
+ * machines since the purge must be broadcast to all CPUs.
+ */
+static inline void purge_tlb_entries_huge(struct mm_struct *mm, unsigned long addr)
+{
+ int i;
+
+ /* We may use multiple physical huge pages (e.g. 2x1 MB) to emulate
+ * Linux standard huge pages (e.g. 2 MB) */
+ BUILD_BUG_ON(REAL_HPAGE_SHIFT > HPAGE_SHIFT);
+
+ addr &= HPAGE_MASK;
+ addr |= _HUGE_PAGE_SIZE_ENCODING_DEFAULT;
+
+ for (i = 0; i < (1 << (HPAGE_SHIFT-REAL_HPAGE_SHIFT)); i++) {
+ purge_tlb_entries(mm, addr);
+ addr += (1UL << REAL_HPAGE_SHIFT);
+ }
+}
+
+/* __set_huge_pte_at() must be called holding the pa_tlb_lock. */
+static void __set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t entry)
+{
+ unsigned long addr_start;
+ int i;
+
+ addr &= HPAGE_MASK;
+ addr_start = addr;
+
+ for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) {
+ set_pte(ptep, entry);
+ ptep++;
+
+ addr += PAGE_SIZE;
+ pte_val(entry) += PAGE_SIZE;
+ }
+
+ purge_tlb_entries_huge(mm, addr_start);
+}
+
+void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t entry, unsigned long sz)
+{
+ __set_huge_pte_at(mm, addr, ptep, entry);
+}
+
+
+pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep)
+{
+ pte_t entry;
+
+ entry = *ptep;
+ __set_huge_pte_at(mm, addr, ptep, __pte(0));
+
+ return entry;
+}
+
+
+void huge_ptep_set_wrprotect(struct mm_struct *mm,
+ unsigned long addr, pte_t *ptep)
+{
+ pte_t old_pte;
+
+ old_pte = *ptep;
+ __set_huge_pte_at(mm, addr, ptep, pte_wrprotect(old_pte));
+}
+
+int huge_ptep_set_access_flags(struct vm_area_struct *vma,
+ unsigned long addr, pte_t *ptep,
+ pte_t pte, int dirty)
+{
+ int changed;
+ struct mm_struct *mm = vma->vm_mm;
+
+ changed = !pte_same(*ptep, pte);
+ if (changed) {
+ __set_huge_pte_at(mm, addr, ptep, pte);
+ }
+ return changed;
+}
+
+
+int pmd_huge(pmd_t pmd)
+{
+ return 0;
+}
+
+int pud_huge(pud_t pud)
+{
+ return 0;
+}
diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c
new file mode 100644
index 000000000..a2a3e89f2
--- /dev/null
+++ b/arch/parisc/mm/init.c
@@ -0,0 +1,993 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * linux/arch/parisc/mm/init.c
+ *
+ * Copyright (C) 1995 Linus Torvalds
+ * Copyright 1999 SuSE GmbH
+ * changed by Philipp Rumpf
+ * Copyright 1999 Philipp Rumpf (prumpf@tux.org)
+ * Copyright 2004 Randolph Chung (tausq@debian.org)
+ * Copyright 2006-2007 Helge Deller (deller@gmx.de)
+ *
+ */
+
+
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/memblock.h>
+#include <linux/gfp.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/initrd.h>
+#include <linux/swap.h>
+#include <linux/unistd.h>
+#include <linux/nodemask.h> /* for node_online_map */
+#include <linux/pagemap.h> /* for release_pages */
+#include <linux/compat.h>
+
+#include <asm/pgalloc.h>
+#include <asm/tlb.h>
+#include <asm/pdc_chassis.h>
+#include <asm/mmzone.h>
+#include <asm/sections.h>
+#include <asm/msgbuf.h>
+#include <asm/sparsemem.h>
+#include <asm/asm-offsets.h>
+
+extern int data_start;
+extern void parisc_kernel_start(void); /* Kernel entry point in head.S */
+
+#if CONFIG_PGTABLE_LEVELS == 3
+pmd_t pmd0[PTRS_PER_PMD] __section(".data..vm0.pmd") __attribute__ ((aligned(PAGE_SIZE)));
+#endif
+
+pgd_t swapper_pg_dir[PTRS_PER_PGD] __section(".data..vm0.pgd") __attribute__ ((aligned(PAGE_SIZE)));
+pte_t pg0[PT_INITIAL * PTRS_PER_PTE] __section(".data..vm0.pte") __attribute__ ((aligned(PAGE_SIZE)));
+
+static struct resource data_resource = {
+ .name = "Kernel data",
+ .flags = IORESOURCE_BUSY | IORESOURCE_SYSTEM_RAM,
+};
+
+static struct resource code_resource = {
+ .name = "Kernel code",
+ .flags = IORESOURCE_BUSY | IORESOURCE_SYSTEM_RAM,
+};
+
+static struct resource pdcdata_resource = {
+ .name = "PDC data (Page Zero)",
+ .start = 0,
+ .end = 0x9ff,
+ .flags = IORESOURCE_BUSY | IORESOURCE_MEM,
+};
+
+static struct resource sysram_resources[MAX_PHYSMEM_RANGES] __ro_after_init;
+
+/* The following array is initialized from the firmware specific
+ * information retrieved in kernel/inventory.c.
+ */
+
+physmem_range_t pmem_ranges[MAX_PHYSMEM_RANGES] __initdata;
+int npmem_ranges __initdata;
+
+#ifdef CONFIG_64BIT
+#define MAX_MEM (1UL << MAX_PHYSMEM_BITS)
+#else /* !CONFIG_64BIT */
+#define MAX_MEM (3584U*1024U*1024U)
+#endif /* !CONFIG_64BIT */
+
+static unsigned long mem_limit __read_mostly = MAX_MEM;
+
+static void __init mem_limit_func(void)
+{
+ char *cp, *end;
+ unsigned long limit;
+
+ /* We need this before __setup() functions are called */
+
+ limit = MAX_MEM;
+ for (cp = boot_command_line; *cp; ) {
+ if (memcmp(cp, "mem=", 4) == 0) {
+ cp += 4;
+ limit = memparse(cp, &end);
+ if (end != cp)
+ break;
+ cp = end;
+ } else {
+ while (*cp != ' ' && *cp)
+ ++cp;
+ while (*cp == ' ')
+ ++cp;
+ }
+ }
+
+ if (limit < mem_limit)
+ mem_limit = limit;
+}
+
+#define MAX_GAP (0x40000000UL >> PAGE_SHIFT)
+
+static void __init setup_bootmem(void)
+{
+ unsigned long mem_max;
+#ifndef CONFIG_SPARSEMEM
+ physmem_range_t pmem_holes[MAX_PHYSMEM_RANGES - 1];
+ int npmem_holes;
+#endif
+ int i, sysram_resource_count;
+
+ disable_sr_hashing(); /* Turn off space register hashing */
+
+ /*
+ * Sort the ranges. Since the number of ranges is typically
+ * small, and performance is not an issue here, just do
+ * a simple insertion sort.
+ */
+
+ for (i = 1; i < npmem_ranges; i++) {
+ int j;
+
+ for (j = i; j > 0; j--) {
+ if (pmem_ranges[j-1].start_pfn <
+ pmem_ranges[j].start_pfn) {
+
+ break;
+ }
+ swap(pmem_ranges[j-1], pmem_ranges[j]);
+ }
+ }
+
+#ifndef CONFIG_SPARSEMEM
+ /*
+ * Throw out ranges that are too far apart (controlled by
+ * MAX_GAP).
+ */
+
+ for (i = 1; i < npmem_ranges; i++) {
+ if (pmem_ranges[i].start_pfn -
+ (pmem_ranges[i-1].start_pfn +
+ pmem_ranges[i-1].pages) > MAX_GAP) {
+ npmem_ranges = i;
+ printk("Large gap in memory detected (%ld pages). "
+ "Consider turning on CONFIG_SPARSEMEM\n",
+ pmem_ranges[i].start_pfn -
+ (pmem_ranges[i-1].start_pfn +
+ pmem_ranges[i-1].pages));
+ break;
+ }
+ }
+#endif
+
+ /* Print the memory ranges */
+ pr_info("Memory Ranges:\n");
+
+ for (i = 0; i < npmem_ranges; i++) {
+ struct resource *res = &sysram_resources[i];
+ unsigned long start;
+ unsigned long size;
+
+ size = (pmem_ranges[i].pages << PAGE_SHIFT);
+ start = (pmem_ranges[i].start_pfn << PAGE_SHIFT);
+ pr_info("%2d) Start 0x%016lx End 0x%016lx Size %6ld MB\n",
+ i, start, start + (size - 1), size >> 20);
+
+ /* request memory resource */
+ res->name = "System RAM";
+ res->start = start;
+ res->end = start + size - 1;
+ res->flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY;
+ request_resource(&iomem_resource, res);
+ }
+
+ sysram_resource_count = npmem_ranges;
+
+ /*
+ * For 32 bit kernels we limit the amount of memory we can
+ * support, in order to preserve enough kernel address space
+ * for other purposes. For 64 bit kernels we don't normally
+ * limit the memory, but this mechanism can be used to
+ * artificially limit the amount of memory (and it is written
+ * to work with multiple memory ranges).
+ */
+
+ mem_limit_func(); /* check for "mem=" argument */
+
+ mem_max = 0;
+ for (i = 0; i < npmem_ranges; i++) {
+ unsigned long rsize;
+
+ rsize = pmem_ranges[i].pages << PAGE_SHIFT;
+ if ((mem_max + rsize) > mem_limit) {
+ printk(KERN_WARNING "Memory truncated to %ld MB\n", mem_limit >> 20);
+ if (mem_max == mem_limit)
+ npmem_ranges = i;
+ else {
+ pmem_ranges[i].pages = (mem_limit >> PAGE_SHIFT)
+ - (mem_max >> PAGE_SHIFT);
+ npmem_ranges = i + 1;
+ mem_max = mem_limit;
+ }
+ break;
+ }
+ mem_max += rsize;
+ }
+
+ printk(KERN_INFO "Total Memory: %ld MB\n",mem_max >> 20);
+
+#ifndef CONFIG_SPARSEMEM
+ /* Merge the ranges, keeping track of the holes */
+ {
+ unsigned long end_pfn;
+ unsigned long hole_pages;
+
+ npmem_holes = 0;
+ end_pfn = pmem_ranges[0].start_pfn + pmem_ranges[0].pages;
+ for (i = 1; i < npmem_ranges; i++) {
+
+ hole_pages = pmem_ranges[i].start_pfn - end_pfn;
+ if (hole_pages) {
+ pmem_holes[npmem_holes].start_pfn = end_pfn;
+ pmem_holes[npmem_holes++].pages = hole_pages;
+ end_pfn += hole_pages;
+ }
+ end_pfn += pmem_ranges[i].pages;
+ }
+
+ pmem_ranges[0].pages = end_pfn - pmem_ranges[0].start_pfn;
+ npmem_ranges = 1;
+ }
+#endif
+
+ /*
+ * Initialize and free the full range of memory in each range.
+ */
+
+ max_pfn = 0;
+ for (i = 0; i < npmem_ranges; i++) {
+ unsigned long start_pfn;
+ unsigned long npages;
+ unsigned long start;
+ unsigned long size;
+
+ start_pfn = pmem_ranges[i].start_pfn;
+ npages = pmem_ranges[i].pages;
+
+ start = start_pfn << PAGE_SHIFT;
+ size = npages << PAGE_SHIFT;
+
+ /* add system RAM memblock */
+ memblock_add(start, size);
+
+ if ((start_pfn + npages) > max_pfn)
+ max_pfn = start_pfn + npages;
+ }
+
+ /*
+ * We can't use memblock top-down allocations because we only
+ * created the initial mapping up to KERNEL_INITIAL_SIZE in
+ * the assembly bootup code.
+ */
+ memblock_set_bottom_up(true);
+
+ /* IOMMU is always used to access "high mem" on those boxes
+ * that can support enough mem that a PCI device couldn't
+ * directly DMA to any physical addresses.
+ * ISA DMA support will need to revisit this.
+ */
+ max_low_pfn = max_pfn;
+
+ /* reserve PAGE0 pdc memory, kernel text/data/bss & bootmap */
+
+#define PDC_CONSOLE_IO_IODC_SIZE 32768
+
+ memblock_reserve(0UL, (unsigned long)(PAGE0->mem_free +
+ PDC_CONSOLE_IO_IODC_SIZE));
+ memblock_reserve(__pa(KERNEL_BINARY_TEXT_START),
+ (unsigned long)(_end - KERNEL_BINARY_TEXT_START));
+
+#ifndef CONFIG_SPARSEMEM
+
+ /* reserve the holes */
+
+ for (i = 0; i < npmem_holes; i++) {
+ memblock_reserve((pmem_holes[i].start_pfn << PAGE_SHIFT),
+ (pmem_holes[i].pages << PAGE_SHIFT));
+ }
+#endif
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (initrd_start) {
+ printk(KERN_INFO "initrd: %08lx-%08lx\n", initrd_start, initrd_end);
+ if (__pa(initrd_start) < mem_max) {
+ unsigned long initrd_reserve;
+
+ if (__pa(initrd_end) > mem_max) {
+ initrd_reserve = mem_max - __pa(initrd_start);
+ } else {
+ initrd_reserve = initrd_end - initrd_start;
+ }
+ initrd_below_start_ok = 1;
+ printk(KERN_INFO "initrd: reserving %08lx-%08lx (mem_max %08lx)\n", __pa(initrd_start), __pa(initrd_start) + initrd_reserve, mem_max);
+
+ memblock_reserve(__pa(initrd_start), initrd_reserve);
+ }
+ }
+#endif
+
+ data_resource.start = virt_to_phys(&data_start);
+ data_resource.end = virt_to_phys(_end) - 1;
+ code_resource.start = virt_to_phys(_text);
+ code_resource.end = virt_to_phys(&data_start)-1;
+
+ /* We don't know which region the kernel will be in, so try
+ * all of them.
+ */
+ for (i = 0; i < sysram_resource_count; i++) {
+ struct resource *res = &sysram_resources[i];
+ request_resource(res, &code_resource);
+ request_resource(res, &data_resource);
+ }
+ request_resource(&sysram_resources[0], &pdcdata_resource);
+
+ /* Initialize Page Deallocation Table (PDT) and check for bad memory. */
+ pdc_pdt_init();
+
+ memblock_allow_resize();
+ memblock_dump_all();
+}
+
+static bool kernel_set_to_readonly;
+
+static void __ref map_pages(unsigned long start_vaddr,
+ unsigned long start_paddr, unsigned long size,
+ pgprot_t pgprot, int force)
+{
+ pmd_t *pmd;
+ pte_t *pg_table;
+ unsigned long end_paddr;
+ unsigned long start_pmd;
+ unsigned long start_pte;
+ unsigned long tmp1;
+ unsigned long tmp2;
+ unsigned long address;
+ unsigned long vaddr;
+ unsigned long ro_start;
+ unsigned long ro_end;
+ unsigned long kernel_start, kernel_end;
+
+ ro_start = __pa((unsigned long)_text);
+ ro_end = __pa((unsigned long)&data_start);
+ kernel_start = __pa((unsigned long)&__init_begin);
+ kernel_end = __pa((unsigned long)&_end);
+
+ end_paddr = start_paddr + size;
+
+ /* for 2-level configuration PTRS_PER_PMD is 0 so start_pmd will be 0 */
+ start_pmd = ((start_vaddr >> PMD_SHIFT) & (PTRS_PER_PMD - 1));
+ start_pte = ((start_vaddr >> PAGE_SHIFT) & (PTRS_PER_PTE - 1));
+
+ address = start_paddr;
+ vaddr = start_vaddr;
+ while (address < end_paddr) {
+ pgd_t *pgd = pgd_offset_k(vaddr);
+ p4d_t *p4d = p4d_offset(pgd, vaddr);
+ pud_t *pud = pud_offset(p4d, vaddr);
+
+#if CONFIG_PGTABLE_LEVELS == 3
+ if (pud_none(*pud)) {
+ pmd = memblock_alloc(PAGE_SIZE << PMD_TABLE_ORDER,
+ PAGE_SIZE << PMD_TABLE_ORDER);
+ if (!pmd)
+ panic("pmd allocation failed.\n");
+ pud_populate(NULL, pud, pmd);
+ }
+#endif
+
+ pmd = pmd_offset(pud, vaddr);
+ for (tmp1 = start_pmd; tmp1 < PTRS_PER_PMD; tmp1++, pmd++) {
+ if (pmd_none(*pmd)) {
+ pg_table = memblock_alloc(PAGE_SIZE, PAGE_SIZE);
+ if (!pg_table)
+ panic("page table allocation failed\n");
+ pmd_populate_kernel(NULL, pmd, pg_table);
+ }
+
+ pg_table = pte_offset_kernel(pmd, vaddr);
+ for (tmp2 = start_pte; tmp2 < PTRS_PER_PTE; tmp2++, pg_table++) {
+ pte_t pte;
+ pgprot_t prot;
+ bool huge = false;
+
+ if (force) {
+ prot = pgprot;
+ } else if (address < kernel_start || address >= kernel_end) {
+ /* outside kernel memory */
+ prot = PAGE_KERNEL;
+ } else if (!kernel_set_to_readonly) {
+ /* still initializing, allow writing to RO memory */
+ prot = PAGE_KERNEL_RWX;
+ huge = true;
+ } else if (address >= ro_start) {
+ /* Code (ro) and Data areas */
+ prot = (address < ro_end) ?
+ PAGE_KERNEL_EXEC : PAGE_KERNEL;
+ huge = true;
+ } else {
+ prot = PAGE_KERNEL;
+ }
+
+ pte = __mk_pte(address, prot);
+ if (huge)
+ pte = pte_mkhuge(pte);
+
+ if (address >= end_paddr)
+ break;
+
+ set_pte(pg_table, pte);
+
+ address += PAGE_SIZE;
+ vaddr += PAGE_SIZE;
+ }
+ start_pte = 0;
+
+ if (address >= end_paddr)
+ break;
+ }
+ start_pmd = 0;
+ }
+}
+
+void __init set_kernel_text_rw(int enable_read_write)
+{
+ unsigned long start = (unsigned long) __init_begin;
+ unsigned long end = (unsigned long) &data_start;
+
+ map_pages(start, __pa(start), end-start,
+ PAGE_KERNEL_RWX, enable_read_write ? 1:0);
+
+ /* force the kernel to see the new page table entries */
+ flush_cache_all();
+ flush_tlb_all();
+}
+
+void free_initmem(void)
+{
+ unsigned long init_begin = (unsigned long)__init_begin;
+ unsigned long init_end = (unsigned long)__init_end;
+ unsigned long kernel_end = (unsigned long)&_end;
+
+ /* Remap kernel text and data, but do not touch init section yet. */
+ kernel_set_to_readonly = true;
+ map_pages(init_end, __pa(init_end), kernel_end - init_end,
+ PAGE_KERNEL, 0);
+
+ /* The init text pages are marked R-X. We have to
+ * flush the icache and mark them RW-
+ *
+ * Do a dummy remap of the data section first (the data
+ * section is already PAGE_KERNEL) to pull in the TLB entries
+ * for map_kernel */
+ map_pages(init_begin, __pa(init_begin), init_end - init_begin,
+ PAGE_KERNEL_RWX, 1);
+ /* now remap at PAGE_KERNEL since the TLB is pre-primed to execute
+ * map_pages */
+ map_pages(init_begin, __pa(init_begin), init_end - init_begin,
+ PAGE_KERNEL, 1);
+
+ /* force the kernel to see the new TLB entries */
+ __flush_tlb_range(0, init_begin, kernel_end);
+
+ /* finally dump all the instructions which were cached, since the
+ * pages are no-longer executable */
+ flush_icache_range(init_begin, init_end);
+
+ free_initmem_default(POISON_FREE_INITMEM);
+
+ /* set up a new led state on systems shipped LED State panel */
+ pdc_chassis_send_status(PDC_CHASSIS_DIRECT_BCOMPLETE);
+}
+
+
+#ifdef CONFIG_STRICT_KERNEL_RWX
+void mark_rodata_ro(void)
+{
+ /* rodata memory was already mapped with KERNEL_RO access rights by
+ pagetable_init() and map_pages(). No need to do additional stuff here */
+ unsigned long roai_size = __end_ro_after_init - __start_ro_after_init;
+
+ pr_info("Write protected read-only-after-init data: %luk\n", roai_size >> 10);
+}
+#endif
+
+
+/*
+ * Just an arbitrary offset to serve as a "hole" between mapping areas
+ * (between top of physical memory and a potential pcxl dma mapping
+ * area, and below the vmalloc mapping area).
+ *
+ * The current 32K value just means that there will be a 32K "hole"
+ * between mapping areas. That means that any out-of-bounds memory
+ * accesses will hopefully be caught. The vmalloc() routines leaves
+ * a hole of 4kB between each vmalloced area for the same reason.
+ */
+
+ /* Leave room for gateway page expansion */
+#if KERNEL_MAP_START < GATEWAY_PAGE_SIZE
+#error KERNEL_MAP_START is in gateway reserved region
+#endif
+#define MAP_START (KERNEL_MAP_START)
+
+#define VM_MAP_OFFSET (32*1024)
+#define SET_MAP_OFFSET(x) ((void *)(((unsigned long)(x) + VM_MAP_OFFSET) \
+ & ~(VM_MAP_OFFSET-1)))
+
+void *parisc_vmalloc_start __ro_after_init;
+EXPORT_SYMBOL(parisc_vmalloc_start);
+
+void __init mem_init(void)
+{
+ /* Do sanity checks on IPC (compat) structures */
+ BUILD_BUG_ON(sizeof(struct ipc64_perm) != 48);
+#ifndef CONFIG_64BIT
+ BUILD_BUG_ON(sizeof(struct semid64_ds) != 80);
+ BUILD_BUG_ON(sizeof(struct msqid64_ds) != 104);
+ BUILD_BUG_ON(sizeof(struct shmid64_ds) != 104);
+#endif
+#ifdef CONFIG_COMPAT
+ BUILD_BUG_ON(sizeof(struct compat_ipc64_perm) != sizeof(struct ipc64_perm));
+ BUILD_BUG_ON(sizeof(struct compat_semid64_ds) != 80);
+ BUILD_BUG_ON(sizeof(struct compat_msqid64_ds) != 104);
+ BUILD_BUG_ON(sizeof(struct compat_shmid64_ds) != 104);
+#endif
+
+ /* Do sanity checks on page table constants */
+ BUILD_BUG_ON(PTE_ENTRY_SIZE != sizeof(pte_t));
+ BUILD_BUG_ON(PMD_ENTRY_SIZE != sizeof(pmd_t));
+ BUILD_BUG_ON(PGD_ENTRY_SIZE != sizeof(pgd_t));
+ BUILD_BUG_ON(PAGE_SHIFT + BITS_PER_PTE + BITS_PER_PMD + BITS_PER_PGD
+ > BITS_PER_LONG);
+#if CONFIG_PGTABLE_LEVELS == 3
+ BUILD_BUG_ON(PT_INITIAL > PTRS_PER_PMD);
+#else
+ BUILD_BUG_ON(PT_INITIAL > PTRS_PER_PGD);
+#endif
+
+#ifdef CONFIG_64BIT
+ /* avoid ldil_%L() asm statements to sign-extend into upper 32-bits */
+ BUILD_BUG_ON(__PAGE_OFFSET >= 0x80000000);
+ BUILD_BUG_ON(TMPALIAS_MAP_START >= 0x80000000);
+#endif
+
+ high_memory = __va((max_pfn << PAGE_SHIFT));
+ set_max_mapnr(max_low_pfn);
+ memblock_free_all();
+
+#ifdef CONFIG_PA11
+ if (boot_cpu_data.cpu_type == pcxl2 || boot_cpu_data.cpu_type == pcxl) {
+ pcxl_dma_start = (unsigned long)SET_MAP_OFFSET(MAP_START);
+ parisc_vmalloc_start = SET_MAP_OFFSET(pcxl_dma_start
+ + PCXL_DMA_MAP_SIZE);
+ } else
+#endif
+ parisc_vmalloc_start = SET_MAP_OFFSET(MAP_START);
+
+#if 0
+ /*
+ * Do not expose the virtual kernel memory layout to userspace.
+ * But keep code for debugging purposes.
+ */
+ printk("virtual kernel memory layout:\n"
+ " vmalloc : 0x%px - 0x%px (%4ld MB)\n"
+ " fixmap : 0x%px - 0x%px (%4ld kB)\n"
+ " memory : 0x%px - 0x%px (%4ld MB)\n"
+ " .init : 0x%px - 0x%px (%4ld kB)\n"
+ " .data : 0x%px - 0x%px (%4ld kB)\n"
+ " .text : 0x%px - 0x%px (%4ld kB)\n",
+
+ (void*)VMALLOC_START, (void*)VMALLOC_END,
+ (VMALLOC_END - VMALLOC_START) >> 20,
+
+ (void *)FIXMAP_START, (void *)(FIXMAP_START + FIXMAP_SIZE),
+ (unsigned long)(FIXMAP_SIZE / 1024),
+
+ __va(0), high_memory,
+ ((unsigned long)high_memory - (unsigned long)__va(0)) >> 20,
+
+ __init_begin, __init_end,
+ ((unsigned long)__init_end - (unsigned long)__init_begin) >> 10,
+
+ _etext, _edata,
+ ((unsigned long)_edata - (unsigned long)_etext) >> 10,
+
+ _text, _etext,
+ ((unsigned long)_etext - (unsigned long)_text) >> 10);
+#endif
+}
+
+unsigned long *empty_zero_page __ro_after_init;
+EXPORT_SYMBOL(empty_zero_page);
+
+/*
+ * pagetable_init() sets up the page tables
+ *
+ * Note that gateway_init() places the Linux gateway page at page 0.
+ * Since gateway pages cannot be dereferenced this has the desirable
+ * side effect of trapping those pesky NULL-reference errors in the
+ * kernel.
+ */
+static void __init pagetable_init(void)
+{
+ int range;
+
+ /* Map each physical memory range to its kernel vaddr */
+
+ for (range = 0; range < npmem_ranges; range++) {
+ unsigned long start_paddr;
+ unsigned long size;
+
+ start_paddr = pmem_ranges[range].start_pfn << PAGE_SHIFT;
+ size = pmem_ranges[range].pages << PAGE_SHIFT;
+
+ map_pages((unsigned long)__va(start_paddr), start_paddr,
+ size, PAGE_KERNEL, 0);
+ }
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (initrd_end && initrd_end > mem_limit) {
+ printk(KERN_INFO "initrd: mapping %08lx-%08lx\n", initrd_start, initrd_end);
+ map_pages(initrd_start, __pa(initrd_start),
+ initrd_end - initrd_start, PAGE_KERNEL, 0);
+ }
+#endif
+
+ empty_zero_page = memblock_alloc(PAGE_SIZE, PAGE_SIZE);
+ if (!empty_zero_page)
+ panic("zero page allocation failed.\n");
+
+}
+
+static void __init gateway_init(void)
+{
+ unsigned long linux_gateway_page_addr;
+ /* FIXME: This is 'const' in order to trick the compiler
+ into not treating it as DP-relative data. */
+ extern void * const linux_gateway_page;
+
+ linux_gateway_page_addr = LINUX_GATEWAY_ADDR & PAGE_MASK;
+
+ /*
+ * Setup Linux Gateway page.
+ *
+ * The Linux gateway page will reside in kernel space (on virtual
+ * page 0), so it doesn't need to be aliased into user space.
+ */
+
+ map_pages(linux_gateway_page_addr, __pa(&linux_gateway_page),
+ PAGE_SIZE, PAGE_GATEWAY, 1);
+}
+
+static void __init fixmap_init(void)
+{
+ unsigned long addr = FIXMAP_START;
+ unsigned long end = FIXMAP_START + FIXMAP_SIZE;
+ pgd_t *pgd = pgd_offset_k(addr);
+ p4d_t *p4d = p4d_offset(pgd, addr);
+ pud_t *pud = pud_offset(p4d, addr);
+ pmd_t *pmd;
+
+ BUILD_BUG_ON(FIXMAP_SIZE > PMD_SIZE);
+
+#if CONFIG_PGTABLE_LEVELS == 3
+ if (pud_none(*pud)) {
+ pmd = memblock_alloc(PAGE_SIZE << PMD_TABLE_ORDER,
+ PAGE_SIZE << PMD_TABLE_ORDER);
+ if (!pmd)
+ panic("fixmap: pmd allocation failed.\n");
+ pud_populate(NULL, pud, pmd);
+ }
+#endif
+
+ pmd = pmd_offset(pud, addr);
+ do {
+ pte_t *pte = memblock_alloc(PAGE_SIZE, PAGE_SIZE);
+ if (!pte)
+ panic("fixmap: pte allocation failed.\n");
+
+ pmd_populate_kernel(&init_mm, pmd, pte);
+
+ addr += PAGE_SIZE;
+ } while (addr < end);
+}
+
+static void __init parisc_bootmem_free(void)
+{
+ unsigned long max_zone_pfn[MAX_NR_ZONES] = { 0, };
+
+ max_zone_pfn[0] = memblock_end_of_DRAM();
+
+ free_area_init(max_zone_pfn);
+}
+
+void __init paging_init(void)
+{
+ setup_bootmem();
+ pagetable_init();
+ gateway_init();
+ fixmap_init();
+ flush_cache_all_local(); /* start with known state */
+ flush_tlb_all_local(NULL);
+
+ sparse_init();
+ parisc_bootmem_free();
+}
+
+static void alloc_btlb(unsigned long start, unsigned long end, int *slot,
+ unsigned long entry_info)
+{
+ const int slot_max = btlb_info.fixed_range_info.num_comb;
+ int min_num_pages = btlb_info.min_size;
+ unsigned long size;
+
+ /* map at minimum 4 pages */
+ if (min_num_pages < 4)
+ min_num_pages = 4;
+
+ size = HUGEPAGE_SIZE;
+ while (start < end && *slot < slot_max && size >= PAGE_SIZE) {
+ /* starting address must have same alignment as size! */
+ /* if correctly aligned and fits in double size, increase */
+ if (((start & (2 * size - 1)) == 0) &&
+ (end - start) >= (2 * size)) {
+ size <<= 1;
+ continue;
+ }
+ /* if current size alignment is too big, try smaller size */
+ if ((start & (size - 1)) != 0) {
+ size >>= 1;
+ continue;
+ }
+ if ((end - start) >= size) {
+ if ((size >> PAGE_SHIFT) >= min_num_pages)
+ pdc_btlb_insert(start >> PAGE_SHIFT, __pa(start) >> PAGE_SHIFT,
+ size >> PAGE_SHIFT, entry_info, *slot);
+ (*slot)++;
+ start += size;
+ continue;
+ }
+ size /= 2;
+ continue;
+ }
+}
+
+void btlb_init_per_cpu(void)
+{
+ unsigned long s, t, e;
+ int slot;
+
+ /* BTLBs are not available on 64-bit CPUs */
+ if (IS_ENABLED(CONFIG_PA20))
+ return;
+ else if (pdc_btlb_info(&btlb_info) < 0) {
+ memset(&btlb_info, 0, sizeof btlb_info);
+ }
+
+ /* insert BLTLBs for code and data segments */
+ s = (uintptr_t) dereference_function_descriptor(&_stext);
+ e = (uintptr_t) dereference_function_descriptor(&_etext);
+ t = (uintptr_t) dereference_function_descriptor(&_sdata);
+ BUG_ON(t != e);
+
+ /* code segments */
+ slot = 0;
+ alloc_btlb(s, e, &slot, 0x13800000);
+
+ /* sanity check */
+ t = (uintptr_t) dereference_function_descriptor(&_edata);
+ e = (uintptr_t) dereference_function_descriptor(&__bss_start);
+ BUG_ON(t != e);
+
+ /* data segments */
+ s = (uintptr_t) dereference_function_descriptor(&_sdata);
+ e = (uintptr_t) dereference_function_descriptor(&__bss_stop);
+ alloc_btlb(s, e, &slot, 0x11800000);
+}
+
+#ifdef CONFIG_PA20
+
+/*
+ * Currently, all PA20 chips have 18 bit protection IDs, which is the
+ * limiting factor (space ids are 32 bits).
+ */
+
+#define NR_SPACE_IDS 262144
+
+#else
+
+/*
+ * Currently we have a one-to-one relationship between space IDs and
+ * protection IDs. Older parisc chips (PCXS, PCXT, PCXL, PCXL2) only
+ * support 15 bit protection IDs, so that is the limiting factor.
+ * PCXT' has 18 bit protection IDs, but only 16 bit spaceids, so it's
+ * probably not worth the effort for a special case here.
+ */
+
+#define NR_SPACE_IDS 32768
+
+#endif /* !CONFIG_PA20 */
+
+#define RECYCLE_THRESHOLD (NR_SPACE_IDS / 2)
+#define SID_ARRAY_SIZE (NR_SPACE_IDS / (8 * sizeof(long)))
+
+static unsigned long space_id[SID_ARRAY_SIZE] = { 1 }; /* disallow space 0 */
+static unsigned long dirty_space_id[SID_ARRAY_SIZE];
+static unsigned long space_id_index;
+static unsigned long free_space_ids = NR_SPACE_IDS - 1;
+static unsigned long dirty_space_ids;
+
+static DEFINE_SPINLOCK(sid_lock);
+
+unsigned long alloc_sid(void)
+{
+ unsigned long index;
+
+ spin_lock(&sid_lock);
+
+ if (free_space_ids == 0) {
+ if (dirty_space_ids != 0) {
+ spin_unlock(&sid_lock);
+ flush_tlb_all(); /* flush_tlb_all() calls recycle_sids() */
+ spin_lock(&sid_lock);
+ }
+ BUG_ON(free_space_ids == 0);
+ }
+
+ free_space_ids--;
+
+ index = find_next_zero_bit(space_id, NR_SPACE_IDS, space_id_index);
+ space_id[BIT_WORD(index)] |= BIT_MASK(index);
+ space_id_index = index;
+
+ spin_unlock(&sid_lock);
+
+ return index << SPACEID_SHIFT;
+}
+
+void free_sid(unsigned long spaceid)
+{
+ unsigned long index = spaceid >> SPACEID_SHIFT;
+ unsigned long *dirty_space_offset, mask;
+
+ dirty_space_offset = &dirty_space_id[BIT_WORD(index)];
+ mask = BIT_MASK(index);
+
+ spin_lock(&sid_lock);
+
+ BUG_ON(*dirty_space_offset & mask); /* attempt to free space id twice */
+
+ *dirty_space_offset |= mask;
+ dirty_space_ids++;
+
+ spin_unlock(&sid_lock);
+}
+
+
+#ifdef CONFIG_SMP
+static void get_dirty_sids(unsigned long *ndirtyptr,unsigned long *dirty_array)
+{
+ int i;
+
+ /* NOTE: sid_lock must be held upon entry */
+
+ *ndirtyptr = dirty_space_ids;
+ if (dirty_space_ids != 0) {
+ for (i = 0; i < SID_ARRAY_SIZE; i++) {
+ dirty_array[i] = dirty_space_id[i];
+ dirty_space_id[i] = 0;
+ }
+ dirty_space_ids = 0;
+ }
+
+ return;
+}
+
+static void recycle_sids(unsigned long ndirty,unsigned long *dirty_array)
+{
+ int i;
+
+ /* NOTE: sid_lock must be held upon entry */
+
+ if (ndirty != 0) {
+ for (i = 0; i < SID_ARRAY_SIZE; i++) {
+ space_id[i] ^= dirty_array[i];
+ }
+
+ free_space_ids += ndirty;
+ space_id_index = 0;
+ }
+}
+
+#else /* CONFIG_SMP */
+
+static void recycle_sids(void)
+{
+ int i;
+
+ /* NOTE: sid_lock must be held upon entry */
+
+ if (dirty_space_ids != 0) {
+ for (i = 0; i < SID_ARRAY_SIZE; i++) {
+ space_id[i] ^= dirty_space_id[i];
+ dirty_space_id[i] = 0;
+ }
+
+ free_space_ids += dirty_space_ids;
+ dirty_space_ids = 0;
+ space_id_index = 0;
+ }
+}
+#endif
+
+/*
+ * flush_tlb_all() calls recycle_sids(), since whenever the entire tlb is
+ * purged, we can safely reuse the space ids that were released but
+ * not flushed from the tlb.
+ */
+
+#ifdef CONFIG_SMP
+
+static unsigned long recycle_ndirty;
+static unsigned long recycle_dirty_array[SID_ARRAY_SIZE];
+static unsigned int recycle_inuse;
+
+void flush_tlb_all(void)
+{
+ int do_recycle;
+
+ do_recycle = 0;
+ spin_lock(&sid_lock);
+ __inc_irq_stat(irq_tlb_count);
+ if (dirty_space_ids > RECYCLE_THRESHOLD) {
+ BUG_ON(recycle_inuse); /* FIXME: Use a semaphore/wait queue here */
+ get_dirty_sids(&recycle_ndirty,recycle_dirty_array);
+ recycle_inuse++;
+ do_recycle++;
+ }
+ spin_unlock(&sid_lock);
+ on_each_cpu(flush_tlb_all_local, NULL, 1);
+ if (do_recycle) {
+ spin_lock(&sid_lock);
+ recycle_sids(recycle_ndirty,recycle_dirty_array);
+ recycle_inuse = 0;
+ spin_unlock(&sid_lock);
+ }
+}
+#else
+void flush_tlb_all(void)
+{
+ spin_lock(&sid_lock);
+ __inc_irq_stat(irq_tlb_count);
+ flush_tlb_all_local(NULL);
+ recycle_sids();
+ spin_unlock(&sid_lock);
+}
+#endif
+
+static const pgprot_t protection_map[16] = {
+ [VM_NONE] = PAGE_NONE,
+ [VM_READ] = PAGE_READONLY,
+ [VM_WRITE] = PAGE_NONE,
+ [VM_WRITE | VM_READ] = PAGE_READONLY,
+ [VM_EXEC] = PAGE_EXECREAD,
+ [VM_EXEC | VM_READ] = PAGE_EXECREAD,
+ [VM_EXEC | VM_WRITE] = PAGE_EXECREAD,
+ [VM_EXEC | VM_WRITE | VM_READ] = PAGE_EXECREAD,
+ [VM_SHARED] = PAGE_NONE,
+ [VM_SHARED | VM_READ] = PAGE_READONLY,
+ [VM_SHARED | VM_WRITE] = PAGE_WRITEONLY,
+ [VM_SHARED | VM_WRITE | VM_READ] = PAGE_SHARED,
+ [VM_SHARED | VM_EXEC] = PAGE_EXECREAD,
+ [VM_SHARED | VM_EXEC | VM_READ] = PAGE_EXECREAD,
+ [VM_SHARED | VM_EXEC | VM_WRITE] = PAGE_RWX,
+ [VM_SHARED | VM_EXEC | VM_WRITE | VM_READ] = PAGE_RWX
+};
+DECLARE_VM_GET_PAGE_PROT
diff --git a/arch/parisc/mm/ioremap.c b/arch/parisc/mm/ioremap.c
new file mode 100644
index 000000000..fd996472d
--- /dev/null
+++ b/arch/parisc/mm/ioremap.c
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * arch/parisc/mm/ioremap.c
+ *
+ * (C) Copyright 1995 1996 Linus Torvalds
+ * (C) Copyright 2001-2019 Helge Deller <deller@gmx.de>
+ * (C) Copyright 2005 Kyle McMartin <kyle@parisc-linux.org>
+ */
+
+#include <linux/vmalloc.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+
+void __iomem *ioremap_prot(phys_addr_t phys_addr, size_t size,
+ unsigned long prot)
+{
+#ifdef CONFIG_EISA
+ unsigned long end = phys_addr + size - 1;
+ /* Support EISA addresses */
+ if ((phys_addr >= 0x00080000 && end < 0x000fffff) ||
+ (phys_addr >= 0x00500000 && end < 0x03bfffff))
+ phys_addr |= F_EXTEND(0xfc000000);
+#endif
+
+ /*
+ * Don't allow anybody to remap normal RAM that we're using..
+ */
+ if (phys_addr < virt_to_phys(high_memory)) {
+ char *t_addr, *t_end;
+ struct page *page;
+
+ t_addr = __va(phys_addr);
+ t_end = t_addr + (size - 1);
+
+ for (page = virt_to_page(t_addr);
+ page <= virt_to_page(t_end); page++) {
+ if(!PageReserved(page))
+ return NULL;
+ }
+ }
+
+ return generic_ioremap_prot(phys_addr, size, __pgprot(prot));
+}
+EXPORT_SYMBOL(ioremap_prot);
diff --git a/arch/parisc/net/Makefile b/arch/parisc/net/Makefile
new file mode 100644
index 000000000..22b12024d
--- /dev/null
+++ b/arch/parisc/net/Makefile
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+obj-$(CONFIG_BPF_JIT) += bpf_jit_core.o
+
+ifeq ($(CONFIG_64BIT),y)
+ obj-$(CONFIG_BPF_JIT) += bpf_jit_comp64.o
+else
+ obj-$(CONFIG_BPF_JIT) += bpf_jit_comp32.o
+endif
diff --git a/arch/parisc/net/bpf_jit.h b/arch/parisc/net/bpf_jit.h
new file mode 100644
index 000000000..8b8896959
--- /dev/null
+++ b/arch/parisc/net/bpf_jit.h
@@ -0,0 +1,479 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Common functionality for PARISC32 and PARISC64 BPF JIT compilers
+ *
+ * Copyright (c) 2023 Helge Deller <deller@gmx.de>
+ *
+ */
+
+#ifndef _BPF_JIT_H
+#define _BPF_JIT_H
+
+#include <linux/bpf.h>
+#include <linux/filter.h>
+#include <asm/cacheflush.h>
+
+#define HPPA_JIT_DEBUG 0
+#define HPPA_JIT_REBOOT 0
+#define HPPA_JIT_DUMP 0
+
+#define OPTIMIZE_HPPA 1 /* enable some asm optimizations */
+// echo 1 > /proc/sys/net/core/bpf_jit_enable
+
+#define HPPA_R(nr) nr /* use HPPA register #nr */
+
+enum {
+ HPPA_REG_ZERO = 0, /* The constant value 0 */
+ HPPA_REG_R1 = 1, /* used for addil */
+ HPPA_REG_RP = 2, /* Return address */
+
+ HPPA_REG_ARG7 = 19, /* ARG4-7 used in 64-bit ABI */
+ HPPA_REG_ARG6 = 20,
+ HPPA_REG_ARG5 = 21,
+ HPPA_REG_ARG4 = 22,
+
+ HPPA_REG_ARG3 = 23, /* ARG0-3 in 32- and 64-bit ABI */
+ HPPA_REG_ARG2 = 24,
+ HPPA_REG_ARG1 = 25,
+ HPPA_REG_ARG0 = 26,
+ HPPA_REG_GP = 27, /* Global pointer */
+ HPPA_REG_RET0 = 28, /* Return value, HI in 32-bit */
+ HPPA_REG_RET1 = 29, /* Return value, LOW in 32-bit */
+ HPPA_REG_SP = 30, /* Stack pointer */
+ HPPA_REG_R31 = 31,
+
+#ifdef CONFIG_64BIT
+ HPPA_REG_TCC = 3,
+ HPPA_REG_TCC_SAVED = 4,
+ HPPA_REG_TCC_IN_INIT = HPPA_REG_R31,
+#else
+ HPPA_REG_TCC = 18,
+ HPPA_REG_TCC_SAVED = 17,
+ HPPA_REG_TCC_IN_INIT = HPPA_REG_R31,
+#endif
+
+ HPPA_REG_T0 = HPPA_REG_R1, /* Temporaries */
+ HPPA_REG_T1 = HPPA_REG_R31,
+ HPPA_REG_T2 = HPPA_REG_ARG4,
+#ifndef CONFIG_64BIT
+ HPPA_REG_T3 = HPPA_REG_ARG5, /* not used in 64-bit */
+ HPPA_REG_T4 = HPPA_REG_ARG6,
+ HPPA_REG_T5 = HPPA_REG_ARG7,
+#endif
+};
+
+struct hppa_jit_context {
+ struct bpf_prog *prog;
+ u32 *insns; /* HPPA insns */
+ int ninsns;
+ int reg_seen_collect;
+ int reg_seen;
+ int body_len;
+ int epilogue_offset;
+ int prologue_len;
+ int *offset; /* BPF to HPPA */
+};
+
+#define REG_SET_SEEN(ctx, nr) { if (ctx->reg_seen_collect) ctx->reg_seen |= BIT(nr); }
+#define REG_SET_SEEN_ALL(ctx) { if (ctx->reg_seen_collect) ctx->reg_seen = -1; }
+#define REG_FORCE_SEEN(ctx, nr) { ctx->reg_seen |= BIT(nr); }
+#define REG_WAS_SEEN(ctx, nr) (ctx->reg_seen & BIT(nr))
+#define REG_ALL_SEEN(ctx) (ctx->reg_seen == -1)
+
+#define HPPA_INSN_SIZE 4 /* bytes per HPPA asm instruction */
+#define REG_SIZE REG_SZ /* bytes per native "long" word */
+
+/* subtract hppa displacement on branches which is .+8 */
+#define HPPA_BRANCH_DISPLACEMENT 2 /* instructions */
+
+/* asm statement indicator to execute delay slot */
+#define EXEC_NEXT_INSTR 0
+#define NOP_NEXT_INSTR 1
+
+#define im11(val) (((u32)(val)) & 0x07ff)
+
+#define hppa_ldil(addr, reg) \
+ hppa_t5_insn(0x08, reg, ((u32)(addr)) >> 11) /* ldil im21,reg */
+#define hppa_addil(addr, reg) \
+ hppa_t5_insn(0x0a, reg, ((u32)(addr)) >> 11) /* addil im21,reg -> result in gr1 */
+#define hppa_ldo(im14, reg, target) \
+ hppa_t1_insn(0x0d, reg, target, im14) /* ldo val14(reg),target */
+#define hppa_ldi(im14, reg) \
+ hppa_ldo(im14, HPPA_REG_ZERO, reg) /* ldi val14,reg */
+#define hppa_or(reg1, reg2, target) \
+ hppa_t6_insn(0x02, reg2, reg1, 0, 0, 0x09, target) /* or reg1,reg2,target */
+#define hppa_or_cond(reg1, reg2, cond, f, target) \
+ hppa_t6_insn(0x02, reg2, reg1, cond, f, 0x09, target)
+#define hppa_and(reg1, reg2, target) \
+ hppa_t6_insn(0x02, reg2, reg1, 0, 0, 0x08, target) /* and reg1,reg2,target */
+#define hppa_and_cond(reg1, reg2, cond, f, target) \
+ hppa_t6_insn(0x02, reg2, reg1, cond, f, 0x08, target)
+#define hppa_xor(reg1, reg2, target) \
+ hppa_t6_insn(0x02, reg2, reg1, 0, 0, 0x0a, target) /* xor reg1,reg2,target */
+#define hppa_add(reg1, reg2, target) \
+ hppa_t6_insn(0x02, reg2, reg1, 0, 0, 0x18, target) /* add reg1,reg2,target */
+#define hppa_addc(reg1, reg2, target) \
+ hppa_t6_insn(0x02, reg2, reg1, 0, 0, 0x1c, target) /* add,c reg1,reg2,target */
+#define hppa_sub(reg1, reg2, target) \
+ hppa_t6_insn(0x02, reg2, reg1, 0, 0, 0x10, target) /* sub reg1,reg2,target */
+#define hppa_subb(reg1, reg2, target) \
+ hppa_t6_insn(0x02, reg2, reg1, 0, 0, 0x14, target) /* sub,b reg1,reg2,target */
+#define hppa_nop() \
+ hppa_or(0,0,0) /* nop: or 0,0,0 */
+#define hppa_addi(val11, reg, target) \
+ hppa_t7_insn(0x2d, reg, target, val11) /* addi im11,reg,target */
+#define hppa_subi(val11, reg, target) \
+ hppa_t7_insn(0x25, reg, target, val11) /* subi im11,reg,target */
+#define hppa_copy(reg, target) \
+ hppa_or(reg, HPPA_REG_ZERO, target) /* copy reg,target */
+#define hppa_ldw(val14, reg, target) \
+ hppa_t1_insn(0x12, reg, target, val14) /* ldw im14(reg),target */
+#define hppa_ldb(val14, reg, target) \
+ hppa_t1_insn(0x10, reg, target, val14) /* ldb im14(reg),target */
+#define hppa_ldh(val14, reg, target) \
+ hppa_t1_insn(0x11, reg, target, val14) /* ldh im14(reg),target */
+#define hppa_stw(reg, val14, base) \
+ hppa_t1_insn(0x1a, base, reg, val14) /* stw reg,im14(base) */
+#define hppa_stb(reg, val14, base) \
+ hppa_t1_insn(0x18, base, reg, val14) /* stb reg,im14(base) */
+#define hppa_sth(reg, val14, base) \
+ hppa_t1_insn(0x19, base, reg, val14) /* sth reg,im14(base) */
+#define hppa_stwma(reg, val14, base) \
+ hppa_t1_insn(0x1b, base, reg, val14) /* stw,ma reg,im14(base) */
+#define hppa_bv(reg, base, nop) \
+ hppa_t11_insn(0x3a, base, reg, 0x06, 0, nop) /* bv(,n) reg(base) */
+#define hppa_be(offset, base) \
+ hppa_t12_insn(0x38, base, offset, 0x00, 1) /* be,n offset(0,base) */
+#define hppa_be_l(offset, base, nop) \
+ hppa_t12_insn(0x39, base, offset, 0x00, nop) /* ble(,nop) offset(0,base) */
+#define hppa_mtctl(reg, cr) \
+ hppa_t21_insn(0x00, cr, reg, 0xc2, 0) /* mtctl reg,cr */
+#define hppa_mtsar(reg) \
+ hppa_mtctl(reg, 11) /* mtsar reg */
+#define hppa_zdep(r, p, len, target) \
+ hppa_t10_insn(0x35, target, r, 0, 2, p, len) /* zdep r,a,b,t */
+#define hppa_shl(r, len, target) \
+ hppa_zdep(r, len, len, lo(rd))
+#define hppa_depwz(r, p, len, target) \
+ hppa_t10_insn(0x35, target, r, 0, 3, 31-(p), 32-(len)) /* depw,z r,p,len,ret1 */
+#define hppa_depwz_sar(reg, target) \
+ hppa_t1_insn(0x35, target, reg, 0) /* depw,z reg,sar,32,target */
+#define hppa_shrpw_sar(reg, target) \
+ hppa_t10_insn(0x34, reg, 0, 0, 0, 0, target) /* shrpw r0,reg,sar,target */
+#define hppa_shrpw(r1, r2, p, target) \
+ hppa_t10_insn(0x34, r2, r1, 0, 2, 31-(p), target) /* shrpw r1,r2,p,target */
+#define hppa_shd(r1, r2, p, target) \
+ hppa_t10_insn(0x34, r2, r1, 0, 2, 31-(p), target) /* shrpw r1,r2,p,tarfer */
+#define hppa_extrws_sar(reg, target) \
+ hppa_t10_insn(0x34, reg, target, 0, 5, 0, 0) /* extrw,s reg,sar,32,ret0 */
+#define hppa_extrws(reg, p, len, target) \
+ hppa_t10_insn(0x34, reg, target, 0, 7, p, len) /* extrw,s reg,p,len,target */
+#define hppa_extru(r, p, len, target) \
+ hppa_t10_insn(0x34, r, target, 0, 6, p, 32-(len))
+#define hppa_shr(r, len, target) \
+ hppa_extru(r, 31-(len), 32-(len), target)
+#define hppa_bl(imm17, rp) \
+ hppa_t12_insn(0x3a, rp, imm17, 0x00, 1) /* bl,n target_addr,rp */
+#define hppa_sh2add(r1, r2, target) \
+ hppa_t6_insn(0x02, r2, r1, 0, 0, 0x1a, target) /* sh2add r1,r2,target */
+
+#define hppa_combt(r1, r2, target_addr, condition, nop) \
+ hppa_t11_insn(IS_ENABLED(CONFIG_64BIT) ? 0x27 : 0x20, \
+ r2, r1, condition, target_addr, nop) /* combt,cond,n r1,r2,addr */
+#define hppa_beq(r1, r2, target_addr) \
+ hppa_combt(r1, r2, target_addr, 1, NOP_NEXT_INSTR)
+#define hppa_blt(r1, r2, target_addr) \
+ hppa_combt(r1, r2, target_addr, 2, NOP_NEXT_INSTR)
+#define hppa_ble(r1, r2, target_addr) \
+ hppa_combt(r1, r2, target_addr, 3, NOP_NEXT_INSTR)
+#define hppa_bltu(r1, r2, target_addr) \
+ hppa_combt(r1, r2, target_addr, 4, NOP_NEXT_INSTR)
+#define hppa_bleu(r1, r2, target_addr) \
+ hppa_combt(r1, r2, target_addr, 5, NOP_NEXT_INSTR)
+
+#define hppa_combf(r1, r2, target_addr, condition, nop) \
+ hppa_t11_insn(IS_ENABLED(CONFIG_64BIT) ? 0x2f : 0x22, \
+ r2, r1, condition, target_addr, nop) /* combf,cond,n r1,r2,addr */
+#define hppa_bne(r1, r2, target_addr) \
+ hppa_combf(r1, r2, target_addr, 1, NOP_NEXT_INSTR)
+#define hppa_bge(r1, r2, target_addr) \
+ hppa_combf(r1, r2, target_addr, 2, NOP_NEXT_INSTR)
+#define hppa_bgt(r1, r2, target_addr) \
+ hppa_combf(r1, r2, target_addr, 3, NOP_NEXT_INSTR)
+#define hppa_bgeu(r1, r2, target_addr) \
+ hppa_combf(r1, r2, target_addr, 4, NOP_NEXT_INSTR)
+#define hppa_bgtu(r1, r2, target_addr) \
+ hppa_combf(r1, r2, target_addr, 5, NOP_NEXT_INSTR)
+
+/* 64-bit instructions */
+#ifdef CONFIG_64BIT
+#define hppa64_ldd_reg(reg, b, target) \
+ hppa_t10_insn(0x03, b, reg, 0, 0, 3<<1, target)
+#define hppa64_ldd_im5(im5, b, target) \
+ hppa_t10_insn(0x03, b, low_sign_unext(im5,5), 0, 1<<2, 3<<1, target)
+#define hppa64_ldd_im16(im16, b, target) \
+ hppa_t10_insn(0x14, b, target, 0, 0, 0, 0) | re_assemble_16(im16)
+#define hppa64_std_im5(src, im5, b) \
+ hppa_t10_insn(0x03, b, src, 0, 1<<2, 0xB<<1, low_sign_unext(im5,5))
+#define hppa64_std_im16(src, im16, b) \
+ hppa_t10_insn(0x1c, b, src, 0, 0, 0, 0) | re_assemble_16(im16)
+#define hppa64_bl_long(offs22) \
+ hppa_t12_L_insn(0x3a, offs22, 1)
+#define hppa64_mtsarcm(reg) \
+ hppa_t21_insn(0x00, 11, reg, 0xc6, 0)
+#define hppa64_shrpd_sar(reg, target) \
+ hppa_t10_insn(0x34, reg, 0, 0, 0, 1<<4, target)
+#define hppa64_shladd(r1, sa, r2, target) \
+ hppa_t6_insn(0x02, r2, r1, 0, 0, 1<<4|1<<3|sa, target)
+#define hppa64_depdz_sar(reg, target) \
+ hppa_t21_insn(0x35, target, reg, 3<<3, 0)
+#define hppa_extrd_sar(reg, target, se) \
+ hppa_t10_insn(0x34, reg, target, 0, 0, 0, 0) | 2<<11 | (se&1)<<10 | 1<<9 | 1<<8
+#define hppa64_bve_l_rp(base) \
+ (0x3a << 26) | (base << 21) | 0xf000
+#define hppa64_permh_3210(r, target) \
+ (0x3e << 26) | (r << 21) | (r << 16) | (target) | 0x00006900
+#define hppa64_hshl(r, sa, target) \
+ (0x3e << 26) | (0 << 21) | (r << 16) | (sa << 6) | (target) | 0x00008800
+#define hppa64_hshr_u(r, sa, target) \
+ (0x3e << 26) | (r << 21) | (0 << 16) | (sa << 6) | (target) | 0x0000c800
+#endif
+
+struct hppa_jit_data {
+ struct bpf_binary_header *header;
+ u8 *image;
+ struct hppa_jit_context ctx;
+};
+
+static inline void bpf_fill_ill_insns(void *area, unsigned int size)
+{
+ memset(area, 0, size);
+}
+
+static inline void bpf_flush_icache(void *start, void *end)
+{
+ flush_icache_range((unsigned long)start, (unsigned long)end);
+}
+
+/* Emit a 4-byte HPPA instruction. */
+static inline void emit(const u32 insn, struct hppa_jit_context *ctx)
+{
+ if (ctx->insns) {
+ ctx->insns[ctx->ninsns] = insn;
+ }
+
+ ctx->ninsns++;
+}
+
+static inline int epilogue_offset(struct hppa_jit_context *ctx)
+{
+ int to = ctx->epilogue_offset, from = ctx->ninsns;
+
+ return (to - from);
+}
+
+/* Return -1 or inverted cond. */
+static inline int invert_bpf_cond(u8 cond)
+{
+ switch (cond) {
+ case BPF_JEQ:
+ return BPF_JNE;
+ case BPF_JGT:
+ return BPF_JLE;
+ case BPF_JLT:
+ return BPF_JGE;
+ case BPF_JGE:
+ return BPF_JLT;
+ case BPF_JLE:
+ return BPF_JGT;
+ case BPF_JNE:
+ return BPF_JEQ;
+ case BPF_JSGT:
+ return BPF_JSLE;
+ case BPF_JSLT:
+ return BPF_JSGE;
+ case BPF_JSGE:
+ return BPF_JSLT;
+ case BPF_JSLE:
+ return BPF_JSGT;
+ }
+ return -1;
+}
+
+
+static inline signed long hppa_offset(int insn, int off, struct hppa_jit_context *ctx)
+{
+ signed long from, to;
+
+ off++; /* BPF branch is from PC+1 */
+ from = (insn > 0) ? ctx->offset[insn - 1] : 0;
+ to = (insn + off > 0) ? ctx->offset[insn + off - 1] : 0;
+ return (to - from);
+}
+
+/* does the signed value fits into a given number of bits ? */
+static inline int check_bits_int(signed long val, int bits)
+{
+ return ((val >= 0) && ((val >> bits) == 0)) ||
+ ((val < 0) && (((~((u32)val)) >> (bits-1)) == 0));
+}
+
+/* can the signed value be used in relative code ? */
+static inline int relative_bits_ok(signed long val, int bits)
+{
+ return ((val >= 0) && (val < (1UL << (bits-1)))) || /* XXX */
+ ((val < 0) && (((~((unsigned long)val)) >> (bits-1)) == 0)
+ && (val & (1UL << (bits-1))));
+}
+
+/* can the signed value be used in relative branches ? */
+static inline int relative_branch_ok(signed long val, int bits)
+{
+ return ((val >= 0) && (val < (1UL << (bits-2)))) || /* XXX */
+ ((val < 0) && (((~((unsigned long)val)) < (1UL << (bits-2))))
+ && (val & (1UL << (bits-1))));
+}
+
+
+#define is_5b_int(val) check_bits_int(val, 5)
+
+static inline unsigned sign_unext(unsigned x, unsigned len)
+{
+ unsigned len_ones;
+
+ len_ones = (1 << len) - 1;
+ return x & len_ones;
+}
+
+static inline unsigned low_sign_unext(unsigned x, unsigned len)
+{
+ unsigned temp;
+ unsigned sign;
+
+ sign = (x >> (len-1)) & 1;
+ temp = sign_unext (x, len-1);
+ return (temp << 1) | sign;
+}
+
+static inline unsigned re_assemble_12(unsigned as12)
+{
+ return (( (as12 & 0x800) >> 11)
+ | ((as12 & 0x400) >> (10 - 2))
+ | ((as12 & 0x3ff) << (1 + 2)));
+}
+
+static inline unsigned re_assemble_14(unsigned as14)
+{
+ return (( (as14 & 0x1fff) << 1)
+ | ((as14 & 0x2000) >> 13));
+}
+
+#ifdef CONFIG_64BIT
+static inline unsigned re_assemble_16(unsigned as16)
+{
+ unsigned s, t;
+
+ /* Unusual 16-bit encoding, for wide mode only. */
+ t = (as16 << 1) & 0xffff;
+ s = (as16 & 0x8000);
+ return (t ^ s ^ (s >> 1)) | (s >> 15);
+}
+#endif
+
+static inline unsigned re_assemble_17(unsigned as17)
+{
+ return (( (as17 & 0x10000) >> 16)
+ | ((as17 & 0x0f800) << (16 - 11))
+ | ((as17 & 0x00400) >> (10 - 2))
+ | ((as17 & 0x003ff) << (1 + 2)));
+}
+
+static inline unsigned re_assemble_21(unsigned as21)
+{
+ return (( (as21 & 0x100000) >> 20)
+ | ((as21 & 0x0ffe00) >> 8)
+ | ((as21 & 0x000180) << 7)
+ | ((as21 & 0x00007c) << 14)
+ | ((as21 & 0x000003) << 12));
+}
+
+static inline unsigned re_assemble_22(unsigned as22)
+{
+ return (( (as22 & 0x200000) >> 21)
+ | ((as22 & 0x1f0000) << (21 - 16))
+ | ((as22 & 0x00f800) << (16 - 11))
+ | ((as22 & 0x000400) >> (10 - 2))
+ | ((as22 & 0x0003ff) << (1 + 2)));
+}
+
+/* Various HPPA instruction formats. */
+/* see https://parisc.wiki.kernel.org/images-parisc/6/68/Pa11_acd.pdf, appendix C */
+
+static inline u32 hppa_t1_insn(u8 opcode, u8 b, u8 r, s16 im14)
+{
+ return ((opcode << 26) | (b << 21) | (r << 16) | re_assemble_14(im14));
+}
+
+static inline u32 hppa_t5_insn(u8 opcode, u8 tr, u32 val21)
+{
+ return ((opcode << 26) | (tr << 21) | re_assemble_21(val21));
+}
+
+static inline u32 hppa_t6_insn(u8 opcode, u8 r2, u8 r1, u8 c, u8 f, u8 ext6, u16 t)
+{
+ return ((opcode << 26) | (r2 << 21) | (r1 << 16) | (c << 13) | (f << 12) |
+ (ext6 << 6) | t);
+}
+
+/* 7. Arithmetic immediate */
+static inline u32 hppa_t7_insn(u8 opcode, u8 r, u8 t, u32 im11)
+{
+ return ((opcode << 26) | (r << 21) | (t << 16) | low_sign_unext(im11, 11));
+}
+
+/* 10. Shift instructions */
+static inline u32 hppa_t10_insn(u8 opcode, u8 r2, u8 r1, u8 c, u8 ext3, u8 cp, u8 t)
+{
+ return ((opcode << 26) | (r2 << 21) | (r1 << 16) | (c << 13) |
+ (ext3 << 10) | (cp << 5) | t);
+}
+
+/* 11. Conditional branch instructions */
+static inline u32 hppa_t11_insn(u8 opcode, u8 r2, u8 r1, u8 c, u32 w, u8 nop)
+{
+ u32 ra = re_assemble_12(w);
+ // ra = low_sign_unext(w,11) | (w & (1<<10)
+ return ((opcode << 26) | (r2 << 21) | (r1 << 16) | (c << 13) | (nop << 1) | ra);
+}
+
+/* 12. Branch instructions */
+static inline u32 hppa_t12_insn(u8 opcode, u8 rp, u32 w, u8 ext3, u8 nop)
+{
+ return ((opcode << 26) | (rp << 21) | (ext3 << 13) | (nop << 1) | re_assemble_17(w));
+}
+
+static inline u32 hppa_t12_L_insn(u8 opcode, u32 w, u8 nop)
+{
+ return ((opcode << 26) | (0x05 << 13) | (nop << 1) | re_assemble_22(w));
+}
+
+/* 21. Move to control register */
+static inline u32 hppa_t21_insn(u8 opcode, u8 r2, u8 r1, u8 ext8, u8 t)
+{
+ return ((opcode << 26) | (r2 << 21) | (r1 << 16) | (ext8 << 5) | t);
+}
+
+/* Helper functions called by jit code on HPPA32 and HPPA64. */
+
+u64 hppa_div64(u64 div, u64 divisor);
+u64 hppa_div64_rem(u64 div, u64 divisor);
+
+/* Helper functions that emit HPPA instructions when possible. */
+
+void bpf_jit_build_prologue(struct hppa_jit_context *ctx);
+void bpf_jit_build_epilogue(struct hppa_jit_context *ctx);
+
+int bpf_jit_emit_insn(const struct bpf_insn *insn, struct hppa_jit_context *ctx,
+ bool extra_pass);
+
+#endif /* _BPF_JIT_H */
diff --git a/arch/parisc/net/bpf_jit_comp32.c b/arch/parisc/net/bpf_jit_comp32.c
new file mode 100644
index 000000000..5ff0cf925
--- /dev/null
+++ b/arch/parisc/net/bpf_jit_comp32.c
@@ -0,0 +1,1615 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * BPF JIT compiler for PA-RISC (32-bit)
+ *
+ * Copyright (c) 2023 Helge Deller <deller@gmx.de>
+ *
+ * The code is based on the BPF JIT compiler for RV64 by Björn Töpel and
+ * the BPF JIT compiler for 32-bit ARM by Shubham Bansal and Mircea Gherzan.
+ */
+
+#include <linux/bpf.h>
+#include <linux/filter.h>
+#include <linux/libgcc.h>
+#include "bpf_jit.h"
+
+/*
+ * Stack layout during BPF program execution (note: stack grows up):
+ *
+ * high
+ * HPPA32 sp => +----------+ <= HPPA32 fp
+ * | saved sp |
+ * | saved rp |
+ * | ... | HPPA32 callee-saved registers
+ * | curr args|
+ * | local var|
+ * +----------+ <= (sp - 4 * NR_SAVED_REGISTERS)
+ * | lo(R9) |
+ * | hi(R9) |
+ * | lo(FP) | JIT scratch space for BPF registers
+ * | hi(FP) |
+ * | ... |
+ * +----------+ <= (sp - 4 * NR_SAVED_REGISTERS
+ * | | - 4 * BPF_JIT_SCRATCH_REGS)
+ * | |
+ * | ... | BPF program stack
+ * | |
+ * | ... | Function call stack
+ * | |
+ * +----------+
+ * low
+ */
+
+enum {
+ /* Stack layout - these are offsets from top of JIT scratch space. */
+ BPF_R8_HI,
+ BPF_R8_LO,
+ BPF_R9_HI,
+ BPF_R9_LO,
+ BPF_FP_HI,
+ BPF_FP_LO,
+ BPF_AX_HI,
+ BPF_AX_LO,
+ BPF_R0_TEMP_HI,
+ BPF_R0_TEMP_LO,
+ BPF_JIT_SCRATCH_REGS,
+};
+
+/* Number of callee-saved registers stored to stack: rp, r3-r18. */
+#define NR_SAVED_REGISTERS (18 - 3 + 1 + 8)
+
+/* Offset from fp for BPF registers stored on stack. */
+#define STACK_OFFSET(k) (- (NR_SAVED_REGISTERS + k + 1))
+#define STACK_ALIGN FRAME_SIZE
+
+#define EXIT_PTR_LOAD(reg) hppa_ldw(-0x08, HPPA_REG_SP, reg)
+#define EXIT_PTR_STORE(reg) hppa_stw(reg, -0x08, HPPA_REG_SP)
+#define EXIT_PTR_JUMP(reg, nop) hppa_bv(HPPA_REG_ZERO, reg, nop)
+
+#define TMP_REG_1 (MAX_BPF_JIT_REG + 0)
+#define TMP_REG_2 (MAX_BPF_JIT_REG + 1)
+#define TMP_REG_R0 (MAX_BPF_JIT_REG + 2)
+
+static const s8 regmap[][2] = {
+ /* Return value from in-kernel function, and exit value from eBPF. */
+ [BPF_REG_0] = {HPPA_REG_RET0, HPPA_REG_RET1}, /* HI/LOW */
+
+ /* Arguments from eBPF program to in-kernel function. */
+ [BPF_REG_1] = {HPPA_R(3), HPPA_R(4)},
+ [BPF_REG_2] = {HPPA_R(5), HPPA_R(6)},
+ [BPF_REG_3] = {HPPA_R(7), HPPA_R(8)},
+ [BPF_REG_4] = {HPPA_R(9), HPPA_R(10)},
+ [BPF_REG_5] = {HPPA_R(11), HPPA_R(12)},
+
+ [BPF_REG_6] = {HPPA_R(13), HPPA_R(14)},
+ [BPF_REG_7] = {HPPA_R(15), HPPA_R(16)},
+ /*
+ * Callee-saved registers that in-kernel function will preserve.
+ * Stored on the stack.
+ */
+ [BPF_REG_8] = {STACK_OFFSET(BPF_R8_HI), STACK_OFFSET(BPF_R8_LO)},
+ [BPF_REG_9] = {STACK_OFFSET(BPF_R9_HI), STACK_OFFSET(BPF_R9_LO)},
+
+ /* Read-only frame pointer to access BPF stack. Not needed. */
+ [BPF_REG_FP] = {STACK_OFFSET(BPF_FP_HI), STACK_OFFSET(BPF_FP_LO)},
+
+ /* Temporary register for blinding constants. Stored on the stack. */
+ [BPF_REG_AX] = {STACK_OFFSET(BPF_AX_HI), STACK_OFFSET(BPF_AX_LO)},
+ /*
+ * Temporary registers used by the JIT to operate on registers stored
+ * on the stack. Save t0 and t1 to be used as temporaries in generated
+ * code.
+ */
+ [TMP_REG_1] = {HPPA_REG_T3, HPPA_REG_T2},
+ [TMP_REG_2] = {HPPA_REG_T5, HPPA_REG_T4},
+
+ /* temporary space for BPF_R0 during libgcc and millicode calls */
+ [TMP_REG_R0] = {STACK_OFFSET(BPF_R0_TEMP_HI), STACK_OFFSET(BPF_R0_TEMP_LO)},
+};
+
+static s8 hi(const s8 *r)
+{
+ return r[0];
+}
+
+static s8 lo(const s8 *r)
+{
+ return r[1];
+}
+
+static void emit_hppa_copy(const s8 rs, const s8 rd, struct hppa_jit_context *ctx)
+{
+ REG_SET_SEEN(ctx, rd);
+ if (OPTIMIZE_HPPA && (rs == rd))
+ return;
+ REG_SET_SEEN(ctx, rs);
+ emit(hppa_copy(rs, rd), ctx);
+}
+
+static void emit_hppa_xor(const s8 r1, const s8 r2, const s8 r3, struct hppa_jit_context *ctx)
+{
+ REG_SET_SEEN(ctx, r1);
+ REG_SET_SEEN(ctx, r2);
+ REG_SET_SEEN(ctx, r3);
+ if (OPTIMIZE_HPPA && (r1 == r2)) {
+ emit(hppa_copy(HPPA_REG_ZERO, r3), ctx);
+ } else {
+ emit(hppa_xor(r1, r2, r3), ctx);
+ }
+}
+
+static void emit_imm(const s8 rd, s32 imm, struct hppa_jit_context *ctx)
+{
+ u32 lower = im11(imm);
+
+ REG_SET_SEEN(ctx, rd);
+ if (OPTIMIZE_HPPA && relative_bits_ok(imm, 14)) {
+ emit(hppa_ldi(imm, rd), ctx);
+ return;
+ }
+ emit(hppa_ldil(imm, rd), ctx);
+ if (OPTIMIZE_HPPA && (lower == 0))
+ return;
+ emit(hppa_ldo(lower, rd, rd), ctx);
+}
+
+static void emit_imm32(const s8 *rd, s32 imm, struct hppa_jit_context *ctx)
+{
+ /* Emit immediate into lower bits. */
+ REG_SET_SEEN(ctx, lo(rd));
+ emit_imm(lo(rd), imm, ctx);
+
+ /* Sign-extend into upper bits. */
+ REG_SET_SEEN(ctx, hi(rd));
+ if (imm >= 0)
+ emit_hppa_copy(HPPA_REG_ZERO, hi(rd), ctx);
+ else
+ emit(hppa_ldi(-1, hi(rd)), ctx);
+}
+
+static void emit_imm64(const s8 *rd, s32 imm_hi, s32 imm_lo,
+ struct hppa_jit_context *ctx)
+{
+ emit_imm(hi(rd), imm_hi, ctx);
+ emit_imm(lo(rd), imm_lo, ctx);
+}
+
+static void __build_epilogue(bool is_tail_call, struct hppa_jit_context *ctx)
+{
+ const s8 *r0 = regmap[BPF_REG_0];
+ int i;
+
+ if (is_tail_call) {
+ /*
+ * goto *(t0 + 4);
+ * Skips first instruction of prologue which initializes tail
+ * call counter. Assumes t0 contains address of target program,
+ * see emit_bpf_tail_call.
+ */
+ emit(hppa_ldo(1 * HPPA_INSN_SIZE, HPPA_REG_T0, HPPA_REG_T0), ctx);
+ emit(hppa_bv(HPPA_REG_ZERO, HPPA_REG_T0, EXEC_NEXT_INSTR), ctx);
+ /* in delay slot: */
+ emit(hppa_copy(HPPA_REG_TCC, HPPA_REG_TCC_IN_INIT), ctx);
+
+ return;
+ }
+
+ /* load epilogue function pointer and jump to it. */
+ /* exit point is either directly below, or the outest TCC exit function */
+ emit(EXIT_PTR_LOAD(HPPA_REG_RP), ctx);
+ emit(EXIT_PTR_JUMP(HPPA_REG_RP, NOP_NEXT_INSTR), ctx);
+
+ /* NOTE: we are 32-bit and big-endian, so return lower 32-bit value */
+ emit_hppa_copy(lo(r0), HPPA_REG_RET0, ctx);
+
+ /* Restore callee-saved registers. */
+ for (i = 3; i <= 18; i++) {
+ if (OPTIMIZE_HPPA && !REG_WAS_SEEN(ctx, HPPA_R(i)))
+ continue;
+ emit(hppa_ldw(-REG_SIZE * (8 + (i-3)), HPPA_REG_SP, HPPA_R(i)), ctx);
+ }
+
+ /* load original return pointer (stored by outest TCC function) */
+ emit(hppa_ldw(-0x14, HPPA_REG_SP, HPPA_REG_RP), ctx);
+ emit(hppa_bv(HPPA_REG_ZERO, HPPA_REG_RP, EXEC_NEXT_INSTR), ctx);
+ /* in delay slot: */
+ emit(hppa_ldw(-0x04, HPPA_REG_SP, HPPA_REG_SP), ctx);
+}
+
+static bool is_stacked(s8 reg)
+{
+ return reg < 0;
+}
+
+static const s8 *bpf_get_reg64_offset(const s8 *reg, const s8 *tmp,
+ u16 offset_sp, struct hppa_jit_context *ctx)
+{
+ if (is_stacked(hi(reg))) {
+ emit(hppa_ldw(REG_SIZE * hi(reg) - offset_sp, HPPA_REG_SP, hi(tmp)), ctx);
+ emit(hppa_ldw(REG_SIZE * lo(reg) - offset_sp, HPPA_REG_SP, lo(tmp)), ctx);
+ reg = tmp;
+ }
+ REG_SET_SEEN(ctx, hi(reg));
+ REG_SET_SEEN(ctx, lo(reg));
+ return reg;
+}
+
+static const s8 *bpf_get_reg64(const s8 *reg, const s8 *tmp,
+ struct hppa_jit_context *ctx)
+{
+ return bpf_get_reg64_offset(reg, tmp, 0, ctx);
+}
+
+static const s8 *bpf_get_reg64_ref(const s8 *reg, const s8 *tmp,
+ bool must_load, struct hppa_jit_context *ctx)
+{
+ if (!OPTIMIZE_HPPA)
+ return bpf_get_reg64(reg, tmp, ctx);
+
+ if (is_stacked(hi(reg))) {
+ if (must_load)
+ emit(hppa_ldw(REG_SIZE * hi(reg), HPPA_REG_SP, hi(tmp)), ctx);
+ reg = tmp;
+ }
+ REG_SET_SEEN(ctx, hi(reg));
+ REG_SET_SEEN(ctx, lo(reg));
+ return reg;
+}
+
+
+static void bpf_put_reg64(const s8 *reg, const s8 *src,
+ struct hppa_jit_context *ctx)
+{
+ if (is_stacked(hi(reg))) {
+ emit(hppa_stw(hi(src), REG_SIZE * hi(reg), HPPA_REG_SP), ctx);
+ emit(hppa_stw(lo(src), REG_SIZE * lo(reg), HPPA_REG_SP), ctx);
+ }
+}
+
+static void bpf_save_R0(struct hppa_jit_context *ctx)
+{
+ bpf_put_reg64(regmap[TMP_REG_R0], regmap[BPF_REG_0], ctx);
+}
+
+static void bpf_restore_R0(struct hppa_jit_context *ctx)
+{
+ bpf_get_reg64(regmap[TMP_REG_R0], regmap[BPF_REG_0], ctx);
+}
+
+
+static const s8 *bpf_get_reg32(const s8 *reg, const s8 *tmp,
+ struct hppa_jit_context *ctx)
+{
+ if (is_stacked(lo(reg))) {
+ emit(hppa_ldw(REG_SIZE * lo(reg), HPPA_REG_SP, lo(tmp)), ctx);
+ reg = tmp;
+ }
+ REG_SET_SEEN(ctx, lo(reg));
+ return reg;
+}
+
+static const s8 *bpf_get_reg32_ref(const s8 *reg, const s8 *tmp,
+ struct hppa_jit_context *ctx)
+{
+ if (!OPTIMIZE_HPPA)
+ return bpf_get_reg32(reg, tmp, ctx);
+
+ if (is_stacked(hi(reg))) {
+ reg = tmp;
+ }
+ REG_SET_SEEN(ctx, lo(reg));
+ return reg;
+}
+
+static void bpf_put_reg32(const s8 *reg, const s8 *src,
+ struct hppa_jit_context *ctx)
+{
+ if (is_stacked(lo(reg))) {
+ REG_SET_SEEN(ctx, lo(src));
+ emit(hppa_stw(lo(src), REG_SIZE * lo(reg), HPPA_REG_SP), ctx);
+ if (1 && !ctx->prog->aux->verifier_zext) {
+ REG_SET_SEEN(ctx, hi(reg));
+ emit(hppa_stw(HPPA_REG_ZERO, REG_SIZE * hi(reg), HPPA_REG_SP), ctx);
+ }
+ } else if (1 && !ctx->prog->aux->verifier_zext) {
+ REG_SET_SEEN(ctx, hi(reg));
+ emit_hppa_copy(HPPA_REG_ZERO, hi(reg), ctx);
+ }
+}
+
+/* extern hppa millicode functions */
+extern void $$mulI(void);
+extern void $$divU(void);
+extern void $$remU(void);
+
+static void emit_call_millicode(void *func, const s8 arg0,
+ const s8 arg1, u8 opcode, struct hppa_jit_context *ctx)
+{
+ u32 func_addr;
+
+ emit_hppa_copy(arg0, HPPA_REG_ARG0, ctx);
+ emit_hppa_copy(arg1, HPPA_REG_ARG1, ctx);
+
+ /* libcgcc overwrites HPPA_REG_RET0/1, save temp. in dest. */
+ if (arg0 != HPPA_REG_RET1)
+ bpf_save_R0(ctx);
+
+ func_addr = (uintptr_t) dereference_function_descriptor(func);
+ emit(hppa_ldil(func_addr, HPPA_REG_R31), ctx);
+ /* skip the following be_l instruction if divisor is zero. */
+ if (BPF_OP(opcode) == BPF_DIV || BPF_OP(opcode) == BPF_MOD) {
+ if (BPF_OP(opcode) == BPF_DIV)
+ emit_hppa_copy(HPPA_REG_ZERO, HPPA_REG_RET1, ctx);
+ else
+ emit_hppa_copy(HPPA_REG_ARG0, HPPA_REG_RET1, ctx);
+ emit(hppa_or_cond(HPPA_REG_ARG1, HPPA_REG_ZERO, 1, 0, HPPA_REG_ZERO), ctx);
+ }
+ /* Note: millicode functions use r31 as return pointer instead of rp */
+ emit(hppa_be_l(im11(func_addr) >> 2, HPPA_REG_R31, NOP_NEXT_INSTR), ctx);
+ emit(hppa_nop(), ctx); /* this nop is needed here for delay slot */
+
+ /* Note: millicode functions return result in RET1, not RET0 */
+ emit_hppa_copy(HPPA_REG_RET1, arg0, ctx);
+
+ /* restore HPPA_REG_RET0/1, temp. save in dest. */
+ if (arg0 != HPPA_REG_RET1)
+ bpf_restore_R0(ctx);
+}
+
+static void emit_call_libgcc_ll(void *func, const s8 *arg0,
+ const s8 *arg1, u8 opcode, struct hppa_jit_context *ctx)
+{
+ u32 func_addr;
+
+ emit_hppa_copy(lo(arg0), HPPA_REG_ARG0, ctx);
+ emit_hppa_copy(hi(arg0), HPPA_REG_ARG1, ctx);
+ emit_hppa_copy(lo(arg1), HPPA_REG_ARG2, ctx);
+ emit_hppa_copy(hi(arg1), HPPA_REG_ARG3, ctx);
+
+ /* libcgcc overwrites HPPA_REG_RET0/_RET1, so keep copy of R0 on stack */
+ if (hi(arg0) != HPPA_REG_RET0)
+ bpf_save_R0(ctx);
+
+ /* prepare stack */
+ emit(hppa_ldo(2 * FRAME_SIZE, HPPA_REG_SP, HPPA_REG_SP), ctx);
+
+ func_addr = (uintptr_t) dereference_function_descriptor(func);
+ emit(hppa_ldil(func_addr, HPPA_REG_R31), ctx);
+ /* zero out the following be_l instruction if divisor is 0 (and set default values) */
+ if (BPF_OP(opcode) == BPF_DIV || BPF_OP(opcode) == BPF_MOD) {
+ emit_hppa_copy(HPPA_REG_ZERO, HPPA_REG_RET0, ctx);
+ if (BPF_OP(opcode) == BPF_DIV)
+ emit_hppa_copy(HPPA_REG_ZERO, HPPA_REG_RET1, ctx);
+ else
+ emit_hppa_copy(HPPA_REG_ARG0, HPPA_REG_RET1, ctx);
+ emit(hppa_or_cond(HPPA_REG_ARG2, HPPA_REG_ARG3, 1, 0, HPPA_REG_ZERO), ctx);
+ }
+ emit(hppa_be_l(im11(func_addr) >> 2, HPPA_REG_R31, EXEC_NEXT_INSTR), ctx);
+ emit_hppa_copy(HPPA_REG_R31, HPPA_REG_RP, ctx);
+
+ /* restore stack */
+ emit(hppa_ldo(-2 * FRAME_SIZE, HPPA_REG_SP, HPPA_REG_SP), ctx);
+
+ emit_hppa_copy(HPPA_REG_RET0, hi(arg0), ctx);
+ emit_hppa_copy(HPPA_REG_RET1, lo(arg0), ctx);
+
+ /* restore HPPA_REG_RET0/_RET1 */
+ if (hi(arg0) != HPPA_REG_RET0)
+ bpf_restore_R0(ctx);
+}
+
+static void emit_jump(s32 paoff, bool force_far,
+ struct hppa_jit_context *ctx)
+{
+ unsigned long pc, addr;
+
+ /* Note: allocate 2 instructions for jumps if force_far is set. */
+ if (relative_bits_ok(paoff - HPPA_BRANCH_DISPLACEMENT, 17)) {
+ /* use BL,short branch followed by nop() */
+ emit(hppa_bl(paoff - HPPA_BRANCH_DISPLACEMENT, HPPA_REG_ZERO), ctx);
+ if (force_far)
+ emit(hppa_nop(), ctx);
+ return;
+ }
+
+ pc = (uintptr_t) &ctx->insns[ctx->ninsns];
+ addr = pc + (paoff * HPPA_INSN_SIZE);
+ emit(hppa_ldil(addr, HPPA_REG_R31), ctx);
+ emit(hppa_be_l(im11(addr) >> 2, HPPA_REG_R31, NOP_NEXT_INSTR), ctx); // be,l,n addr(sr4,r31), %sr0, %r31
+}
+
+static void emit_alu_i64(const s8 *dst, s32 imm,
+ struct hppa_jit_context *ctx, const u8 op)
+{
+ const s8 *tmp1 = regmap[TMP_REG_1];
+ const s8 *rd;
+
+ if (0 && op == BPF_MOV)
+ rd = bpf_get_reg64_ref(dst, tmp1, false, ctx);
+ else
+ rd = bpf_get_reg64(dst, tmp1, ctx);
+
+ /* dst = dst OP imm */
+ switch (op) {
+ case BPF_MOV:
+ emit_imm32(rd, imm, ctx);
+ break;
+ case BPF_AND:
+ emit_imm(HPPA_REG_T0, imm, ctx);
+ emit(hppa_and(lo(rd), HPPA_REG_T0, lo(rd)), ctx);
+ if (imm >= 0)
+ emit_hppa_copy(HPPA_REG_ZERO, hi(rd), ctx);
+ break;
+ case BPF_OR:
+ emit_imm(HPPA_REG_T0, imm, ctx);
+ emit(hppa_or(lo(rd), HPPA_REG_T0, lo(rd)), ctx);
+ if (imm < 0)
+ emit_imm(hi(rd), -1, ctx);
+ break;
+ case BPF_XOR:
+ emit_imm(HPPA_REG_T0, imm, ctx);
+ emit_hppa_xor(lo(rd), HPPA_REG_T0, lo(rd), ctx);
+ if (imm < 0) {
+ emit_imm(HPPA_REG_T0, -1, ctx);
+ emit_hppa_xor(hi(rd), HPPA_REG_T0, hi(rd), ctx);
+ }
+ break;
+ case BPF_LSH:
+ if (imm == 0)
+ break;
+ if (imm > 32) {
+ imm -= 32;
+ emit(hppa_zdep(lo(rd), imm, imm, hi(rd)), ctx);
+ emit_hppa_copy(HPPA_REG_ZERO, lo(rd), ctx);
+ } else if (imm == 32) {
+ emit_hppa_copy(lo(rd), hi(rd), ctx);
+ emit_hppa_copy(HPPA_REG_ZERO, lo(rd), ctx);
+ } else {
+ emit(hppa_shd(hi(rd), lo(rd), 32 - imm, hi(rd)), ctx);
+ emit(hppa_zdep(lo(rd), imm, imm, lo(rd)), ctx);
+ }
+ break;
+ case BPF_RSH:
+ if (imm == 0)
+ break;
+ if (imm > 32) {
+ imm -= 32;
+ emit(hppa_shr(hi(rd), imm, lo(rd)), ctx);
+ emit_hppa_copy(HPPA_REG_ZERO, hi(rd), ctx);
+ } else if (imm == 32) {
+ emit_hppa_copy(hi(rd), lo(rd), ctx);
+ emit_hppa_copy(HPPA_REG_ZERO, hi(rd), ctx);
+ } else {
+ emit(hppa_shrpw(hi(rd), lo(rd), imm, lo(rd)), ctx);
+ emit(hppa_shr(hi(rd), imm, hi(rd)), ctx);
+ }
+ break;
+ case BPF_ARSH:
+ if (imm == 0)
+ break;
+ if (imm > 32) {
+ imm -= 32;
+ emit(hppa_extrws(hi(rd), 31 - imm, imm, lo(rd)), ctx);
+ emit(hppa_extrws(hi(rd), 0, 31, hi(rd)), ctx);
+ } else if (imm == 32) {
+ emit_hppa_copy(hi(rd), lo(rd), ctx);
+ emit(hppa_extrws(hi(rd), 0, 31, hi(rd)), ctx);
+ } else {
+ emit(hppa_shrpw(hi(rd), lo(rd), imm, lo(rd)), ctx);
+ emit(hppa_extrws(hi(rd), 31 - imm, imm, hi(rd)), ctx);
+ }
+ break;
+ default:
+ WARN_ON(1);
+ }
+
+ bpf_put_reg64(dst, rd, ctx);
+}
+
+static void emit_alu_i32(const s8 *dst, s32 imm,
+ struct hppa_jit_context *ctx, const u8 op)
+{
+ const s8 *tmp1 = regmap[TMP_REG_1];
+ const s8 *rd = bpf_get_reg32(dst, tmp1, ctx);
+
+ if (op == BPF_MOV)
+ rd = bpf_get_reg32_ref(dst, tmp1, ctx);
+ else
+ rd = bpf_get_reg32(dst, tmp1, ctx);
+
+ /* dst = dst OP imm */
+ switch (op) {
+ case BPF_MOV:
+ emit_imm(lo(rd), imm, ctx);
+ break;
+ case BPF_ADD:
+ emit_imm(HPPA_REG_T0, imm, ctx);
+ emit(hppa_add(lo(rd), HPPA_REG_T0, lo(rd)), ctx);
+ break;
+ case BPF_SUB:
+ emit_imm(HPPA_REG_T0, imm, ctx);
+ emit(hppa_sub(lo(rd), HPPA_REG_T0, lo(rd)), ctx);
+ break;
+ case BPF_AND:
+ emit_imm(HPPA_REG_T0, imm, ctx);
+ emit(hppa_and(lo(rd), HPPA_REG_T0, lo(rd)), ctx);
+ break;
+ case BPF_OR:
+ emit_imm(HPPA_REG_T0, imm, ctx);
+ emit(hppa_or(lo(rd), HPPA_REG_T0, lo(rd)), ctx);
+ break;
+ case BPF_XOR:
+ emit_imm(HPPA_REG_T0, imm, ctx);
+ emit_hppa_xor(lo(rd), HPPA_REG_T0, lo(rd), ctx);
+ break;
+ case BPF_LSH:
+ if (imm != 0)
+ emit(hppa_zdep(lo(rd), imm, imm, lo(rd)), ctx);
+ break;
+ case BPF_RSH:
+ if (imm != 0)
+ emit(hppa_shr(lo(rd), imm, lo(rd)), ctx);
+ break;
+ case BPF_ARSH:
+ if (imm != 0)
+ emit(hppa_extrws(lo(rd), 31 - imm, imm, lo(rd)), ctx);
+ break;
+ default:
+ WARN_ON(1);
+ }
+
+ bpf_put_reg32(dst, rd, ctx);
+}
+
+static void emit_alu_r64(const s8 *dst, const s8 *src,
+ struct hppa_jit_context *ctx, const u8 op)
+{
+ const s8 *tmp1 = regmap[TMP_REG_1];
+ const s8 *tmp2 = regmap[TMP_REG_2];
+ const s8 *rd;
+ const s8 *rs = bpf_get_reg64(src, tmp2, ctx);
+
+ if (op == BPF_MOV)
+ rd = bpf_get_reg64_ref(dst, tmp1, false, ctx);
+ else
+ rd = bpf_get_reg64(dst, tmp1, ctx);
+
+ /* dst = dst OP src */
+ switch (op) {
+ case BPF_MOV:
+ emit_hppa_copy(lo(rs), lo(rd), ctx);
+ emit_hppa_copy(hi(rs), hi(rd), ctx);
+ break;
+ case BPF_ADD:
+ emit(hppa_add(lo(rd), lo(rs), lo(rd)), ctx);
+ emit(hppa_addc(hi(rd), hi(rs), hi(rd)), ctx);
+ break;
+ case BPF_SUB:
+ emit(hppa_sub(lo(rd), lo(rs), lo(rd)), ctx);
+ emit(hppa_subb(hi(rd), hi(rs), hi(rd)), ctx);
+ break;
+ case BPF_AND:
+ emit(hppa_and(lo(rd), lo(rs), lo(rd)), ctx);
+ emit(hppa_and(hi(rd), hi(rs), hi(rd)), ctx);
+ break;
+ case BPF_OR:
+ emit(hppa_or(lo(rd), lo(rs), lo(rd)), ctx);
+ emit(hppa_or(hi(rd), hi(rs), hi(rd)), ctx);
+ break;
+ case BPF_XOR:
+ emit_hppa_xor(lo(rd), lo(rs), lo(rd), ctx);
+ emit_hppa_xor(hi(rd), hi(rs), hi(rd), ctx);
+ break;
+ case BPF_MUL:
+ emit_call_libgcc_ll(__muldi3, rd, rs, op, ctx);
+ break;
+ case BPF_DIV:
+ emit_call_libgcc_ll(&hppa_div64, rd, rs, op, ctx);
+ break;
+ case BPF_MOD:
+ emit_call_libgcc_ll(&hppa_div64_rem, rd, rs, op, ctx);
+ break;
+ case BPF_LSH:
+ emit_call_libgcc_ll(__ashldi3, rd, rs, op, ctx);
+ break;
+ case BPF_RSH:
+ emit_call_libgcc_ll(__lshrdi3, rd, rs, op, ctx);
+ break;
+ case BPF_ARSH:
+ emit_call_libgcc_ll(__ashrdi3, rd, rs, op, ctx);
+ break;
+ case BPF_NEG:
+ emit(hppa_sub(HPPA_REG_ZERO, lo(rd), lo(rd)), ctx);
+ emit(hppa_subb(HPPA_REG_ZERO, hi(rd), hi(rd)), ctx);
+ break;
+ default:
+ WARN_ON(1);
+ }
+
+ bpf_put_reg64(dst, rd, ctx);
+}
+
+static void emit_alu_r32(const s8 *dst, const s8 *src,
+ struct hppa_jit_context *ctx, const u8 op)
+{
+ const s8 *tmp1 = regmap[TMP_REG_1];
+ const s8 *tmp2 = regmap[TMP_REG_2];
+ const s8 *rd;
+ const s8 *rs = bpf_get_reg32(src, tmp2, ctx);
+
+ if (op == BPF_MOV)
+ rd = bpf_get_reg32_ref(dst, tmp1, ctx);
+ else
+ rd = bpf_get_reg32(dst, tmp1, ctx);
+
+ /* dst = dst OP src */
+ switch (op) {
+ case BPF_MOV:
+ emit_hppa_copy(lo(rs), lo(rd), ctx);
+ break;
+ case BPF_ADD:
+ emit(hppa_add(lo(rd), lo(rs), lo(rd)), ctx);
+ break;
+ case BPF_SUB:
+ emit(hppa_sub(lo(rd), lo(rs), lo(rd)), ctx);
+ break;
+ case BPF_AND:
+ emit(hppa_and(lo(rd), lo(rs), lo(rd)), ctx);
+ break;
+ case BPF_OR:
+ emit(hppa_or(lo(rd), lo(rs), lo(rd)), ctx);
+ break;
+ case BPF_XOR:
+ emit_hppa_xor(lo(rd), lo(rs), lo(rd), ctx);
+ break;
+ case BPF_MUL:
+ emit_call_millicode($$mulI, lo(rd), lo(rs), op, ctx);
+ break;
+ case BPF_DIV:
+ emit_call_millicode($$divU, lo(rd), lo(rs), op, ctx);
+ break;
+ case BPF_MOD:
+ emit_call_millicode($$remU, lo(rd), lo(rs), op, ctx);
+ break;
+ case BPF_LSH:
+ emit(hppa_subi(0x1f, lo(rs), HPPA_REG_T0), ctx);
+ emit(hppa_mtsar(HPPA_REG_T0), ctx);
+ emit(hppa_depwz_sar(lo(rd), lo(rd)), ctx);
+ break;
+ case BPF_RSH:
+ emit(hppa_mtsar(lo(rs)), ctx);
+ emit(hppa_shrpw_sar(lo(rd), lo(rd)), ctx);
+ break;
+ case BPF_ARSH: /* sign extending arithmetic shift right */
+ // emit(hppa_beq(lo(rs), HPPA_REG_ZERO, 2), ctx);
+ emit(hppa_subi(0x1f, lo(rs), HPPA_REG_T0), ctx);
+ emit(hppa_mtsar(HPPA_REG_T0), ctx);
+ emit(hppa_extrws_sar(lo(rd), lo(rd)), ctx);
+ break;
+ case BPF_NEG:
+ emit(hppa_sub(HPPA_REG_ZERO, lo(rd), lo(rd)), ctx); // sub r0,rd,rd
+ break;
+ default:
+ WARN_ON(1);
+ }
+
+ bpf_put_reg32(dst, rd, ctx);
+}
+
+static int emit_branch_r64(const s8 *src1, const s8 *src2, s32 paoff,
+ struct hppa_jit_context *ctx, const u8 op)
+{
+ int e, s = ctx->ninsns;
+ const s8 *tmp1 = regmap[TMP_REG_1];
+ const s8 *tmp2 = regmap[TMP_REG_2];
+
+ const s8 *rs1 = bpf_get_reg64(src1, tmp1, ctx);
+ const s8 *rs2 = bpf_get_reg64(src2, tmp2, ctx);
+
+ /*
+ * NO_JUMP skips over the rest of the instructions and the
+ * emit_jump, meaning the BPF branch is not taken.
+ * JUMP skips directly to the emit_jump, meaning
+ * the BPF branch is taken.
+ *
+ * The fallthrough case results in the BPF branch being taken.
+ */
+#define NO_JUMP(idx) (2 + (idx) - 1)
+#define JUMP(idx) (0 + (idx) - 1)
+
+ switch (op) {
+ case BPF_JEQ:
+ emit(hppa_bne(hi(rs1), hi(rs2), NO_JUMP(1)), ctx);
+ emit(hppa_bne(lo(rs1), lo(rs2), NO_JUMP(0)), ctx);
+ break;
+ case BPF_JGT:
+ emit(hppa_bgtu(hi(rs1), hi(rs2), JUMP(2)), ctx);
+ emit(hppa_bltu(hi(rs1), hi(rs2), NO_JUMP(1)), ctx);
+ emit(hppa_bleu(lo(rs1), lo(rs2), NO_JUMP(0)), ctx);
+ break;
+ case BPF_JLT:
+ emit(hppa_bltu(hi(rs1), hi(rs2), JUMP(2)), ctx);
+ emit(hppa_bgtu(hi(rs1), hi(rs2), NO_JUMP(1)), ctx);
+ emit(hppa_bgeu(lo(rs1), lo(rs2), NO_JUMP(0)), ctx);
+ break;
+ case BPF_JGE:
+ emit(hppa_bgtu(hi(rs1), hi(rs2), JUMP(2)), ctx);
+ emit(hppa_bltu(hi(rs1), hi(rs2), NO_JUMP(1)), ctx);
+ emit(hppa_bltu(lo(rs1), lo(rs2), NO_JUMP(0)), ctx);
+ break;
+ case BPF_JLE:
+ emit(hppa_bltu(hi(rs1), hi(rs2), JUMP(2)), ctx);
+ emit(hppa_bgtu(hi(rs1), hi(rs2), NO_JUMP(1)), ctx);
+ emit(hppa_bgtu(lo(rs1), lo(rs2), NO_JUMP(0)), ctx);
+ break;
+ case BPF_JNE:
+ emit(hppa_bne(hi(rs1), hi(rs2), JUMP(1)), ctx);
+ emit(hppa_beq(lo(rs1), lo(rs2), NO_JUMP(0)), ctx);
+ break;
+ case BPF_JSGT:
+ emit(hppa_bgt(hi(rs1), hi(rs2), JUMP(2)), ctx);
+ emit(hppa_blt(hi(rs1), hi(rs2), NO_JUMP(1)), ctx);
+ emit(hppa_bleu(lo(rs1), lo(rs2), NO_JUMP(0)), ctx);
+ break;
+ case BPF_JSLT:
+ emit(hppa_blt(hi(rs1), hi(rs2), JUMP(2)), ctx);
+ emit(hppa_bgt(hi(rs1), hi(rs2), NO_JUMP(1)), ctx);
+ emit(hppa_bgeu(lo(rs1), lo(rs2), NO_JUMP(0)), ctx);
+ break;
+ case BPF_JSGE:
+ emit(hppa_bgt(hi(rs1), hi(rs2), JUMP(2)), ctx);
+ emit(hppa_blt(hi(rs1), hi(rs2), NO_JUMP(1)), ctx);
+ emit(hppa_bltu(lo(rs1), lo(rs2), NO_JUMP(0)), ctx);
+ break;
+ case BPF_JSLE:
+ emit(hppa_blt(hi(rs1), hi(rs2), JUMP(2)), ctx);
+ emit(hppa_bgt(hi(rs1), hi(rs2), NO_JUMP(1)), ctx);
+ emit(hppa_bgtu(lo(rs1), lo(rs2), NO_JUMP(0)), ctx);
+ break;
+ case BPF_JSET:
+ emit(hppa_and(hi(rs1), hi(rs2), HPPA_REG_T0), ctx);
+ emit(hppa_and(lo(rs1), lo(rs2), HPPA_REG_T1), ctx);
+ emit(hppa_bne(HPPA_REG_T0, HPPA_REG_ZERO, JUMP(1)), ctx);
+ emit(hppa_beq(HPPA_REG_T1, HPPA_REG_ZERO, NO_JUMP(0)), ctx);
+ break;
+ default:
+ WARN_ON(1);
+ }
+
+#undef NO_JUMP
+#undef JUMP
+
+ e = ctx->ninsns;
+ /* Adjust for extra insns. */
+ paoff -= (e - s);
+ emit_jump(paoff, true, ctx);
+ return 0;
+}
+
+static int emit_bcc(u8 op, u8 rd, u8 rs, int paoff, struct hppa_jit_context *ctx)
+{
+ int e, s;
+ bool far = false;
+ int off;
+
+ if (op == BPF_JSET) {
+ /*
+ * BPF_JSET is a special case: it has no inverse so we always
+ * treat it as a far branch.
+ */
+ emit(hppa_and(rd, rs, HPPA_REG_T0), ctx);
+ paoff -= 1; /* reduce offset due to hppa_and() above */
+ rd = HPPA_REG_T0;
+ rs = HPPA_REG_ZERO;
+ op = BPF_JNE;
+ }
+
+ s = ctx->ninsns;
+
+ if (!relative_bits_ok(paoff - HPPA_BRANCH_DISPLACEMENT, 12)) {
+ op = invert_bpf_cond(op);
+ far = true;
+ }
+
+ /*
+ * For a far branch, the condition is negated and we jump over the
+ * branch itself, and the three instructions from emit_jump.
+ * For a near branch, just use paoff.
+ */
+ off = far ? (HPPA_BRANCH_DISPLACEMENT - 1) : paoff - HPPA_BRANCH_DISPLACEMENT;
+
+ switch (op) {
+ /* IF (dst COND src) JUMP off */
+ case BPF_JEQ:
+ emit(hppa_beq(rd, rs, off), ctx);
+ break;
+ case BPF_JGT:
+ emit(hppa_bgtu(rd, rs, off), ctx);
+ break;
+ case BPF_JLT:
+ emit(hppa_bltu(rd, rs, off), ctx);
+ break;
+ case BPF_JGE:
+ emit(hppa_bgeu(rd, rs, off), ctx);
+ break;
+ case BPF_JLE:
+ emit(hppa_bleu(rd, rs, off), ctx);
+ break;
+ case BPF_JNE:
+ emit(hppa_bne(rd, rs, off), ctx);
+ break;
+ case BPF_JSGT:
+ emit(hppa_bgt(rd, rs, off), ctx);
+ break;
+ case BPF_JSLT:
+ emit(hppa_blt(rd, rs, off), ctx);
+ break;
+ case BPF_JSGE:
+ emit(hppa_bge(rd, rs, off), ctx);
+ break;
+ case BPF_JSLE:
+ emit(hppa_ble(rd, rs, off), ctx);
+ break;
+ default:
+ WARN_ON(1);
+ }
+
+ if (far) {
+ e = ctx->ninsns;
+ /* Adjust for extra insns. */
+ paoff -= (e - s);
+ emit_jump(paoff, true, ctx);
+ }
+ return 0;
+}
+
+static int emit_branch_r32(const s8 *src1, const s8 *src2, s32 paoff,
+ struct hppa_jit_context *ctx, const u8 op)
+{
+ int e, s = ctx->ninsns;
+ const s8 *tmp1 = regmap[TMP_REG_1];
+ const s8 *tmp2 = regmap[TMP_REG_2];
+
+ const s8 *rs1 = bpf_get_reg32(src1, tmp1, ctx);
+ const s8 *rs2 = bpf_get_reg32(src2, tmp2, ctx);
+
+ e = ctx->ninsns;
+ /* Adjust for extra insns. */
+ paoff -= (e - s);
+
+ if (emit_bcc(op, lo(rs1), lo(rs2), paoff, ctx))
+ return -1;
+
+ return 0;
+}
+
+static void emit_call(bool fixed, u64 addr, struct hppa_jit_context *ctx)
+{
+ const s8 *tmp = regmap[TMP_REG_1];
+ const s8 *r0 = regmap[BPF_REG_0];
+ const s8 *reg;
+ const int offset_sp = 2 * STACK_ALIGN;
+
+ /* prepare stack */
+ emit(hppa_ldo(offset_sp, HPPA_REG_SP, HPPA_REG_SP), ctx);
+
+ /* load R1 & R2 in registers, R3-R5 to stack. */
+ reg = bpf_get_reg64_offset(regmap[BPF_REG_5], tmp, offset_sp, ctx);
+ emit(hppa_stw(hi(reg), -0x48, HPPA_REG_SP), ctx);
+ emit(hppa_stw(lo(reg), -0x44, HPPA_REG_SP), ctx);
+
+ reg = bpf_get_reg64_offset(regmap[BPF_REG_4], tmp, offset_sp, ctx);
+ emit(hppa_stw(hi(reg), -0x40, HPPA_REG_SP), ctx);
+ emit(hppa_stw(lo(reg), -0x3c, HPPA_REG_SP), ctx);
+
+ reg = bpf_get_reg64_offset(regmap[BPF_REG_3], tmp, offset_sp, ctx);
+ emit(hppa_stw(hi(reg), -0x38, HPPA_REG_SP), ctx);
+ emit(hppa_stw(lo(reg), -0x34, HPPA_REG_SP), ctx);
+
+ reg = bpf_get_reg64_offset(regmap[BPF_REG_2], tmp, offset_sp, ctx);
+ emit_hppa_copy(hi(reg), HPPA_REG_ARG3, ctx);
+ emit_hppa_copy(lo(reg), HPPA_REG_ARG2, ctx);
+
+ reg = bpf_get_reg64_offset(regmap[BPF_REG_1], tmp, offset_sp, ctx);
+ emit_hppa_copy(hi(reg), HPPA_REG_ARG1, ctx);
+ emit_hppa_copy(lo(reg), HPPA_REG_ARG0, ctx);
+
+ /* backup TCC */
+ if (REG_WAS_SEEN(ctx, HPPA_REG_TCC))
+ emit(hppa_copy(HPPA_REG_TCC, HPPA_REG_TCC_SAVED), ctx);
+
+ /*
+ * Use ldil() to load absolute address. Don't use emit_imm as the
+ * number of emitted instructions should not depend on the value of
+ * addr.
+ */
+ emit(hppa_ldil(addr, HPPA_REG_R31), ctx);
+ emit(hppa_be_l(im11(addr) >> 2, HPPA_REG_R31, EXEC_NEXT_INSTR), ctx);
+ /* set return address in delay slot */
+ emit_hppa_copy(HPPA_REG_R31, HPPA_REG_RP, ctx);
+
+ /* restore TCC */
+ if (REG_WAS_SEEN(ctx, HPPA_REG_TCC))
+ emit(hppa_copy(HPPA_REG_TCC_SAVED, HPPA_REG_TCC), ctx);
+
+ /* restore stack */
+ emit(hppa_ldo(-offset_sp, HPPA_REG_SP, HPPA_REG_SP), ctx);
+
+ /* set return value. */
+ emit_hppa_copy(HPPA_REG_RET0, hi(r0), ctx);
+ emit_hppa_copy(HPPA_REG_RET1, lo(r0), ctx);
+}
+
+static int emit_bpf_tail_call(int insn, struct hppa_jit_context *ctx)
+{
+ /*
+ * R1 -> &ctx
+ * R2 -> &array
+ * R3 -> index
+ */
+ int off;
+ const s8 *arr_reg = regmap[BPF_REG_2];
+ const s8 *idx_reg = regmap[BPF_REG_3];
+ struct bpf_array bpfa;
+ struct bpf_prog bpfp;
+
+ /* get address of TCC main exit function for error case into rp */
+ emit(EXIT_PTR_LOAD(HPPA_REG_RP), ctx);
+
+ /* max_entries = array->map.max_entries; */
+ off = offsetof(struct bpf_array, map.max_entries);
+ BUILD_BUG_ON(sizeof(bpfa.map.max_entries) != 4);
+ emit(hppa_ldw(off, lo(arr_reg), HPPA_REG_T1), ctx);
+
+ /*
+ * if (index >= max_entries)
+ * goto out;
+ */
+ emit(hppa_bltu(lo(idx_reg), HPPA_REG_T1, 2 - HPPA_BRANCH_DISPLACEMENT), ctx);
+ emit(EXIT_PTR_JUMP(HPPA_REG_RP, NOP_NEXT_INSTR), ctx);
+
+ /*
+ * if (--tcc < 0)
+ * goto out;
+ */
+ REG_FORCE_SEEN(ctx, HPPA_REG_TCC);
+ emit(hppa_ldo(-1, HPPA_REG_TCC, HPPA_REG_TCC), ctx);
+ emit(hppa_bge(HPPA_REG_TCC, HPPA_REG_ZERO, 2 - HPPA_BRANCH_DISPLACEMENT), ctx);
+ emit(EXIT_PTR_JUMP(HPPA_REG_RP, NOP_NEXT_INSTR), ctx);
+
+ /*
+ * prog = array->ptrs[index];
+ * if (!prog)
+ * goto out;
+ */
+ BUILD_BUG_ON(sizeof(bpfa.ptrs[0]) != 4);
+ emit(hppa_sh2add(lo(idx_reg), lo(arr_reg), HPPA_REG_T0), ctx);
+ off = offsetof(struct bpf_array, ptrs);
+ BUILD_BUG_ON(!relative_bits_ok(off, 11));
+ emit(hppa_ldw(off, HPPA_REG_T0, HPPA_REG_T0), ctx);
+ emit(hppa_bne(HPPA_REG_T0, HPPA_REG_ZERO, 2 - HPPA_BRANCH_DISPLACEMENT), ctx);
+ emit(EXIT_PTR_JUMP(HPPA_REG_RP, NOP_NEXT_INSTR), ctx);
+
+ /*
+ * tcc = temp_tcc;
+ * goto *(prog->bpf_func + 4);
+ */
+ off = offsetof(struct bpf_prog, bpf_func);
+ BUILD_BUG_ON(!relative_bits_ok(off, 11));
+ BUILD_BUG_ON(sizeof(bpfp.bpf_func) != 4);
+ emit(hppa_ldw(off, HPPA_REG_T0, HPPA_REG_T0), ctx);
+ /* Epilogue jumps to *(t0 + 4). */
+ __build_epilogue(true, ctx);
+ return 0;
+}
+
+static int emit_load_r64(const s8 *dst, const s8 *src, s16 off,
+ struct hppa_jit_context *ctx, const u8 size)
+{
+ const s8 *tmp1 = regmap[TMP_REG_1];
+ const s8 *tmp2 = regmap[TMP_REG_2];
+ const s8 *rd = bpf_get_reg64_ref(dst, tmp1, ctx->prog->aux->verifier_zext, ctx);
+ const s8 *rs = bpf_get_reg64(src, tmp2, ctx);
+ s8 srcreg;
+
+ /* need to calculate address since offset does not fit in 14 bits? */
+ if (relative_bits_ok(off, 14))
+ srcreg = lo(rs);
+ else {
+ /* need to use R1 here, since addil puts result into R1 */
+ srcreg = HPPA_REG_R1;
+ emit(hppa_addil(off, lo(rs)), ctx);
+ off = im11(off);
+ }
+
+ /* LDX: dst = *(size *)(src + off) */
+ switch (size) {
+ case BPF_B:
+ emit(hppa_ldb(off + 0, srcreg, lo(rd)), ctx);
+ if (!ctx->prog->aux->verifier_zext)
+ emit_hppa_copy(HPPA_REG_ZERO, hi(rd), ctx);
+ break;
+ case BPF_H:
+ emit(hppa_ldh(off + 0, srcreg, lo(rd)), ctx);
+ if (!ctx->prog->aux->verifier_zext)
+ emit_hppa_copy(HPPA_REG_ZERO, hi(rd), ctx);
+ break;
+ case BPF_W:
+ emit(hppa_ldw(off + 0, srcreg, lo(rd)), ctx);
+ if (!ctx->prog->aux->verifier_zext)
+ emit_hppa_copy(HPPA_REG_ZERO, hi(rd), ctx);
+ break;
+ case BPF_DW:
+ emit(hppa_ldw(off + 0, srcreg, hi(rd)), ctx);
+ emit(hppa_ldw(off + 4, srcreg, lo(rd)), ctx);
+ break;
+ }
+
+ bpf_put_reg64(dst, rd, ctx);
+ return 0;
+}
+
+static int emit_store_r64(const s8 *dst, const s8 *src, s16 off,
+ struct hppa_jit_context *ctx, const u8 size,
+ const u8 mode)
+{
+ const s8 *tmp1 = regmap[TMP_REG_1];
+ const s8 *tmp2 = regmap[TMP_REG_2];
+ const s8 *rd = bpf_get_reg64(dst, tmp1, ctx);
+ const s8 *rs = bpf_get_reg64(src, tmp2, ctx);
+ s8 dstreg;
+
+ /* need to calculate address since offset does not fit in 14 bits? */
+ if (relative_bits_ok(off, 14))
+ dstreg = lo(rd);
+ else {
+ /* need to use R1 here, since addil puts result into R1 */
+ dstreg = HPPA_REG_R1;
+ emit(hppa_addil(off, lo(rd)), ctx);
+ off = im11(off);
+ }
+
+ /* ST: *(size *)(dst + off) = imm */
+ switch (size) {
+ case BPF_B:
+ emit(hppa_stb(lo(rs), off + 0, dstreg), ctx);
+ break;
+ case BPF_H:
+ emit(hppa_sth(lo(rs), off + 0, dstreg), ctx);
+ break;
+ case BPF_W:
+ emit(hppa_stw(lo(rs), off + 0, dstreg), ctx);
+ break;
+ case BPF_DW:
+ emit(hppa_stw(hi(rs), off + 0, dstreg), ctx);
+ emit(hppa_stw(lo(rs), off + 4, dstreg), ctx);
+ break;
+ }
+
+ return 0;
+}
+
+static void emit_rev16(const s8 rd, struct hppa_jit_context *ctx)
+{
+ emit(hppa_extru(rd, 23, 8, HPPA_REG_T1), ctx);
+ emit(hppa_depwz(rd, 23, 8, HPPA_REG_T1), ctx);
+ emit(hppa_extru(HPPA_REG_T1, 31, 16, rd), ctx);
+}
+
+static void emit_rev32(const s8 rs, const s8 rd, struct hppa_jit_context *ctx)
+{
+ emit(hppa_shrpw(rs, rs, 16, HPPA_REG_T1), ctx);
+ emit(hppa_depwz(HPPA_REG_T1, 15, 8, HPPA_REG_T1), ctx);
+ emit(hppa_shrpw(rs, HPPA_REG_T1, 8, rd), ctx);
+}
+
+static void emit_zext64(const s8 *dst, struct hppa_jit_context *ctx)
+{
+ const s8 *rd;
+ const s8 *tmp1 = regmap[TMP_REG_1];
+
+ rd = bpf_get_reg64(dst, tmp1, ctx);
+ emit_hppa_copy(HPPA_REG_ZERO, hi(rd), ctx);
+ bpf_put_reg64(dst, rd, ctx);
+}
+
+int bpf_jit_emit_insn(const struct bpf_insn *insn, struct hppa_jit_context *ctx,
+ bool extra_pass)
+{
+ bool is64 = BPF_CLASS(insn->code) == BPF_ALU64 ||
+ BPF_CLASS(insn->code) == BPF_JMP;
+ int s, e, paoff, i = insn - ctx->prog->insnsi;
+ u8 code = insn->code;
+ s16 off = insn->off;
+ s32 imm = insn->imm;
+
+ const s8 *dst = regmap[insn->dst_reg];
+ const s8 *src = regmap[insn->src_reg];
+ const s8 *tmp1 = regmap[TMP_REG_1];
+ const s8 *tmp2 = regmap[TMP_REG_2];
+
+ if (0) printk("CLASS %03d CODE %#02x ALU64:%d BPF_SIZE %#02x "
+ "BPF_CODE %#02x src_reg %d dst_reg %d\n",
+ BPF_CLASS(code), code, (code & BPF_ALU64) ? 1:0, BPF_SIZE(code),
+ BPF_OP(code), insn->src_reg, insn->dst_reg);
+
+ switch (code) {
+ /* dst = src */
+ case BPF_ALU64 | BPF_MOV | BPF_X:
+
+ case BPF_ALU64 | BPF_ADD | BPF_X:
+ case BPF_ALU64 | BPF_ADD | BPF_K:
+
+ case BPF_ALU64 | BPF_SUB | BPF_X:
+ case BPF_ALU64 | BPF_SUB | BPF_K:
+
+ case BPF_ALU64 | BPF_AND | BPF_X:
+ case BPF_ALU64 | BPF_OR | BPF_X:
+ case BPF_ALU64 | BPF_XOR | BPF_X:
+
+ case BPF_ALU64 | BPF_MUL | BPF_X:
+ case BPF_ALU64 | BPF_MUL | BPF_K:
+
+ case BPF_ALU64 | BPF_DIV | BPF_X:
+ case BPF_ALU64 | BPF_DIV | BPF_K:
+
+ case BPF_ALU64 | BPF_MOD | BPF_X:
+ case BPF_ALU64 | BPF_MOD | BPF_K:
+
+ case BPF_ALU64 | BPF_LSH | BPF_X:
+ case BPF_ALU64 | BPF_RSH | BPF_X:
+ case BPF_ALU64 | BPF_ARSH | BPF_X:
+ if (BPF_SRC(code) == BPF_K) {
+ emit_imm32(tmp2, imm, ctx);
+ src = tmp2;
+ }
+ emit_alu_r64(dst, src, ctx, BPF_OP(code));
+ break;
+
+ /* dst = -dst */
+ case BPF_ALU64 | BPF_NEG:
+ emit_alu_r64(dst, tmp2, ctx, BPF_OP(code));
+ break;
+
+ case BPF_ALU64 | BPF_MOV | BPF_K:
+ case BPF_ALU64 | BPF_AND | BPF_K:
+ case BPF_ALU64 | BPF_OR | BPF_K:
+ case BPF_ALU64 | BPF_XOR | BPF_K:
+ case BPF_ALU64 | BPF_LSH | BPF_K:
+ case BPF_ALU64 | BPF_RSH | BPF_K:
+ case BPF_ALU64 | BPF_ARSH | BPF_K:
+ emit_alu_i64(dst, imm, ctx, BPF_OP(code));
+ break;
+
+ case BPF_ALU | BPF_MOV | BPF_X:
+ if (imm == 1) {
+ /* Special mov32 for zext. */
+ emit_zext64(dst, ctx);
+ break;
+ }
+ fallthrough;
+ /* dst = dst OP src */
+ case BPF_ALU | BPF_ADD | BPF_X:
+ case BPF_ALU | BPF_SUB | BPF_X:
+ case BPF_ALU | BPF_AND | BPF_X:
+ case BPF_ALU | BPF_OR | BPF_X:
+ case BPF_ALU | BPF_XOR | BPF_X:
+
+ case BPF_ALU | BPF_MUL | BPF_X:
+ case BPF_ALU | BPF_MUL | BPF_K:
+
+ case BPF_ALU | BPF_DIV | BPF_X:
+ case BPF_ALU | BPF_DIV | BPF_K:
+
+ case BPF_ALU | BPF_MOD | BPF_X:
+ case BPF_ALU | BPF_MOD | BPF_K:
+
+ case BPF_ALU | BPF_LSH | BPF_X:
+ case BPF_ALU | BPF_RSH | BPF_X:
+ case BPF_ALU | BPF_ARSH | BPF_X:
+ if (BPF_SRC(code) == BPF_K) {
+ emit_imm32(tmp2, imm, ctx);
+ src = tmp2;
+ }
+ emit_alu_r32(dst, src, ctx, BPF_OP(code));
+ break;
+
+ /* dst = dst OP imm */
+ case BPF_ALU | BPF_MOV | BPF_K:
+ case BPF_ALU | BPF_ADD | BPF_K:
+ case BPF_ALU | BPF_SUB | BPF_K:
+ case BPF_ALU | BPF_AND | BPF_K:
+ case BPF_ALU | BPF_OR | BPF_K:
+ case BPF_ALU | BPF_XOR | BPF_K:
+ case BPF_ALU | BPF_LSH | BPF_K:
+ case BPF_ALU | BPF_RSH | BPF_K:
+ case BPF_ALU | BPF_ARSH | BPF_K:
+ /*
+ * mul,div,mod are handled in the BPF_X case.
+ */
+ emit_alu_i32(dst, imm, ctx, BPF_OP(code));
+ break;
+
+ /* dst = -dst */
+ case BPF_ALU | BPF_NEG:
+ /*
+ * src is ignored---choose tmp2 as a dummy register since it
+ * is not on the stack.
+ */
+ emit_alu_r32(dst, tmp2, ctx, BPF_OP(code));
+ break;
+
+ /* dst = BSWAP##imm(dst) */
+ case BPF_ALU | BPF_END | BPF_FROM_BE:
+ {
+ const s8 *rd = bpf_get_reg64(dst, tmp1, ctx);
+
+ switch (imm) {
+ case 16:
+ /* zero-extend 16 bits into 64 bits */
+ emit(hppa_extru(lo(rd), 31, 16, lo(rd)), ctx);
+ fallthrough;
+ case 32:
+ /* zero-extend 32 bits into 64 bits */
+ if (!ctx->prog->aux->verifier_zext)
+ emit_hppa_copy(HPPA_REG_ZERO, hi(rd), ctx);
+ break;
+ case 64:
+ /* Do nothing. */
+ break;
+ default:
+ pr_err("bpf-jit: BPF_END imm %d invalid\n", imm);
+ return -1;
+ }
+
+ bpf_put_reg64(dst, rd, ctx);
+ break;
+ }
+
+ case BPF_ALU | BPF_END | BPF_FROM_LE:
+ {
+ const s8 *rd = bpf_get_reg64(dst, tmp1, ctx);
+
+ switch (imm) {
+ case 16:
+ emit_rev16(lo(rd), ctx);
+ if (!ctx->prog->aux->verifier_zext)
+ emit_hppa_copy(HPPA_REG_ZERO, hi(rd), ctx);
+ break;
+ case 32:
+ emit_rev32(lo(rd), lo(rd), ctx);
+ if (!ctx->prog->aux->verifier_zext)
+ emit_hppa_copy(HPPA_REG_ZERO, hi(rd), ctx);
+ break;
+ case 64:
+ /* Swap upper and lower halves, then each half. */
+ emit_hppa_copy(hi(rd), HPPA_REG_T0, ctx);
+ emit_rev32(lo(rd), hi(rd), ctx);
+ emit_rev32(HPPA_REG_T0, lo(rd), ctx);
+ break;
+ default:
+ pr_err("bpf-jit: BPF_END imm %d invalid\n", imm);
+ return -1;
+ }
+
+ bpf_put_reg64(dst, rd, ctx);
+ break;
+ }
+ /* JUMP off */
+ case BPF_JMP | BPF_JA:
+ paoff = hppa_offset(i, off, ctx);
+ emit_jump(paoff, false, ctx);
+ break;
+ /* function call */
+ case BPF_JMP | BPF_CALL:
+ {
+ bool fixed;
+ int ret;
+ u64 addr;
+
+ ret = bpf_jit_get_func_addr(ctx->prog, insn, extra_pass, &addr,
+ &fixed);
+ if (ret < 0)
+ return ret;
+ emit_call(fixed, addr, ctx);
+ break;
+ }
+ /* tail call */
+ case BPF_JMP | BPF_TAIL_CALL:
+ REG_SET_SEEN_ALL(ctx);
+ if (emit_bpf_tail_call(i, ctx))
+ return -1;
+ break;
+ /* IF (dst COND imm) JUMP off */
+ case BPF_JMP | BPF_JEQ | BPF_X:
+ case BPF_JMP | BPF_JEQ | BPF_K:
+ case BPF_JMP32 | BPF_JEQ | BPF_X:
+ case BPF_JMP32 | BPF_JEQ | BPF_K:
+
+ case BPF_JMP | BPF_JNE | BPF_X:
+ case BPF_JMP | BPF_JNE | BPF_K:
+ case BPF_JMP32 | BPF_JNE | BPF_X:
+ case BPF_JMP32 | BPF_JNE | BPF_K:
+
+ case BPF_JMP | BPF_JLE | BPF_X:
+ case BPF_JMP | BPF_JLE | BPF_K:
+ case BPF_JMP32 | BPF_JLE | BPF_X:
+ case BPF_JMP32 | BPF_JLE | BPF_K:
+
+ case BPF_JMP | BPF_JLT | BPF_X:
+ case BPF_JMP | BPF_JLT | BPF_K:
+ case BPF_JMP32 | BPF_JLT | BPF_X:
+ case BPF_JMP32 | BPF_JLT | BPF_K:
+
+ case BPF_JMP | BPF_JGE | BPF_X:
+ case BPF_JMP | BPF_JGE | BPF_K:
+ case BPF_JMP32 | BPF_JGE | BPF_X:
+ case BPF_JMP32 | BPF_JGE | BPF_K:
+
+ case BPF_JMP | BPF_JGT | BPF_X:
+ case BPF_JMP | BPF_JGT | BPF_K:
+ case BPF_JMP32 | BPF_JGT | BPF_X:
+ case BPF_JMP32 | BPF_JGT | BPF_K:
+
+ case BPF_JMP | BPF_JSLE | BPF_X:
+ case BPF_JMP | BPF_JSLE | BPF_K:
+ case BPF_JMP32 | BPF_JSLE | BPF_X:
+ case BPF_JMP32 | BPF_JSLE | BPF_K:
+
+ case BPF_JMP | BPF_JSLT | BPF_X:
+ case BPF_JMP | BPF_JSLT | BPF_K:
+ case BPF_JMP32 | BPF_JSLT | BPF_X:
+ case BPF_JMP32 | BPF_JSLT | BPF_K:
+
+ case BPF_JMP | BPF_JSGE | BPF_X:
+ case BPF_JMP | BPF_JSGE | BPF_K:
+ case BPF_JMP32 | BPF_JSGE | BPF_X:
+ case BPF_JMP32 | BPF_JSGE | BPF_K:
+
+ case BPF_JMP | BPF_JSGT | BPF_X:
+ case BPF_JMP | BPF_JSGT | BPF_K:
+ case BPF_JMP32 | BPF_JSGT | BPF_X:
+ case BPF_JMP32 | BPF_JSGT | BPF_K:
+
+ case BPF_JMP | BPF_JSET | BPF_X:
+ case BPF_JMP | BPF_JSET | BPF_K:
+ case BPF_JMP32 | BPF_JSET | BPF_X:
+ case BPF_JMP32 | BPF_JSET | BPF_K:
+ paoff = hppa_offset(i, off, ctx);
+ if (BPF_SRC(code) == BPF_K) {
+ s = ctx->ninsns;
+ emit_imm32(tmp2, imm, ctx);
+ src = tmp2;
+ e = ctx->ninsns;
+ paoff -= (e - s);
+ }
+ if (is64)
+ emit_branch_r64(dst, src, paoff, ctx, BPF_OP(code));
+ else
+ emit_branch_r32(dst, src, paoff, ctx, BPF_OP(code));
+ break;
+ /* function return */
+ case BPF_JMP | BPF_EXIT:
+ if (i == ctx->prog->len - 1)
+ break;
+ /* load epilogue function pointer and jump to it. */
+ emit(EXIT_PTR_LOAD(HPPA_REG_RP), ctx);
+ emit(EXIT_PTR_JUMP(HPPA_REG_RP, NOP_NEXT_INSTR), ctx);
+ break;
+
+ /* dst = imm64 */
+ case BPF_LD | BPF_IMM | BPF_DW:
+ {
+ struct bpf_insn insn1 = insn[1];
+ u32 upper = insn1.imm;
+ u32 lower = imm;
+ const s8 *rd = bpf_get_reg64_ref(dst, tmp1, false, ctx);
+
+ if (0 && bpf_pseudo_func(insn)) {
+ WARN_ON(upper); /* we are 32-bit! */
+ upper = 0;
+ lower = (uintptr_t) dereference_function_descriptor(lower);
+ }
+
+ emit_imm64(rd, upper, lower, ctx);
+ bpf_put_reg64(dst, rd, ctx);
+ return 1;
+ }
+
+ /* LDX: dst = *(size *)(src + off) */
+ case BPF_LDX | BPF_MEM | BPF_B:
+ case BPF_LDX | BPF_MEM | BPF_H:
+ case BPF_LDX | BPF_MEM | BPF_W:
+ case BPF_LDX | BPF_MEM | BPF_DW:
+ if (emit_load_r64(dst, src, off, ctx, BPF_SIZE(code)))
+ return -1;
+ break;
+
+ /* speculation barrier */
+ case BPF_ST | BPF_NOSPEC:
+ break;
+
+ /* ST: *(size *)(dst + off) = imm */
+ case BPF_ST | BPF_MEM | BPF_B:
+ case BPF_ST | BPF_MEM | BPF_H:
+ case BPF_ST | BPF_MEM | BPF_W:
+ case BPF_ST | BPF_MEM | BPF_DW:
+
+ case BPF_STX | BPF_MEM | BPF_B:
+ case BPF_STX | BPF_MEM | BPF_H:
+ case BPF_STX | BPF_MEM | BPF_W:
+ case BPF_STX | BPF_MEM | BPF_DW:
+ if (BPF_CLASS(code) == BPF_ST) {
+ emit_imm32(tmp2, imm, ctx);
+ src = tmp2;
+ }
+
+ if (emit_store_r64(dst, src, off, ctx, BPF_SIZE(code),
+ BPF_MODE(code)))
+ return -1;
+ break;
+
+ case BPF_STX | BPF_ATOMIC | BPF_W:
+ case BPF_STX | BPF_ATOMIC | BPF_DW:
+ pr_info_once(
+ "bpf-jit: not supported: atomic operation %02x ***\n",
+ insn->imm);
+ return -EFAULT;
+
+ default:
+ pr_err("bpf-jit: unknown opcode %02x\n", code);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+void bpf_jit_build_prologue(struct hppa_jit_context *ctx)
+{
+ const s8 *tmp = regmap[TMP_REG_1];
+ const s8 *dst, *reg;
+ int stack_adjust = 0;
+ int i;
+ unsigned long addr;
+ int bpf_stack_adjust;
+
+ /*
+ * stack on hppa grows up, so if tail calls are used we need to
+ * allocate the maximum stack size
+ */
+ if (REG_ALL_SEEN(ctx))
+ bpf_stack_adjust = MAX_BPF_STACK;
+ else
+ bpf_stack_adjust = ctx->prog->aux->stack_depth;
+ bpf_stack_adjust = round_up(bpf_stack_adjust, STACK_ALIGN);
+
+ /* make space for callee-saved registers. */
+ stack_adjust += NR_SAVED_REGISTERS * REG_SIZE;
+ /* make space for BPF registers on stack. */
+ stack_adjust += BPF_JIT_SCRATCH_REGS * REG_SIZE;
+ /* make space for BPF stack. */
+ stack_adjust += bpf_stack_adjust;
+ /* round up for stack alignment. */
+ stack_adjust = round_up(stack_adjust, STACK_ALIGN);
+
+ /*
+ * The first instruction sets the tail-call-counter (TCC) register.
+ * This instruction is skipped by tail calls.
+ * Use a temporary register instead of a caller-saved register initially.
+ */
+ emit(hppa_ldi(MAX_TAIL_CALL_CNT, HPPA_REG_TCC_IN_INIT), ctx);
+
+ /*
+ * skip all initializations when called as BPF TAIL call.
+ */
+ emit(hppa_ldi(MAX_TAIL_CALL_CNT, HPPA_REG_R1), ctx);
+ emit(hppa_bne(HPPA_REG_TCC_IN_INIT, HPPA_REG_R1, ctx->prologue_len - 2 - HPPA_BRANCH_DISPLACEMENT), ctx);
+
+ /* set up hppa stack frame. */
+ emit_hppa_copy(HPPA_REG_SP, HPPA_REG_R1, ctx); // copy sp,r1 (=prev_sp)
+ emit(hppa_ldo(stack_adjust, HPPA_REG_SP, HPPA_REG_SP), ctx); // ldo stack_adjust(sp),sp (increase stack)
+ emit(hppa_stw(HPPA_REG_R1, -REG_SIZE, HPPA_REG_SP), ctx); // stw prev_sp,-0x04(sp)
+ emit(hppa_stw(HPPA_REG_RP, -0x14, HPPA_REG_SP), ctx); // stw rp,-0x14(sp)
+
+ REG_FORCE_SEEN(ctx, HPPA_REG_T0);
+ REG_FORCE_SEEN(ctx, HPPA_REG_T1);
+ REG_FORCE_SEEN(ctx, HPPA_REG_T2);
+ REG_FORCE_SEEN(ctx, HPPA_REG_T3);
+ REG_FORCE_SEEN(ctx, HPPA_REG_T4);
+ REG_FORCE_SEEN(ctx, HPPA_REG_T5);
+
+ /* save callee-save registers. */
+ for (i = 3; i <= 18; i++) {
+ if (OPTIMIZE_HPPA && !REG_WAS_SEEN(ctx, HPPA_R(i)))
+ continue;
+ emit(hppa_stw(HPPA_R(i), -REG_SIZE * (8 + (i-3)), HPPA_REG_SP), ctx); // stw ri,-save_area(sp)
+ }
+
+ /*
+ * now really set the tail call counter (TCC) register.
+ */
+ if (REG_WAS_SEEN(ctx, HPPA_REG_TCC))
+ emit(hppa_ldi(MAX_TAIL_CALL_CNT, HPPA_REG_TCC), ctx);
+
+ /*
+ * save epilogue function pointer for outer TCC call chain.
+ * The main TCC call stores the final RP on stack.
+ */
+ addr = (uintptr_t) &ctx->insns[ctx->epilogue_offset];
+ /* skip first two instructions of exit function, which jump to exit */
+ addr += 2 * HPPA_INSN_SIZE;
+ emit(hppa_ldil(addr, HPPA_REG_T2), ctx);
+ emit(hppa_ldo(im11(addr), HPPA_REG_T2, HPPA_REG_T2), ctx);
+ emit(EXIT_PTR_STORE(HPPA_REG_T2), ctx);
+
+ /* load R1 & R2 from registers, R3-R5 from stack. */
+ /* use HPPA_REG_R1 which holds the old stack value */
+ dst = regmap[BPF_REG_5];
+ reg = bpf_get_reg64_ref(dst, tmp, false, ctx);
+ if (REG_WAS_SEEN(ctx, lo(reg)) | REG_WAS_SEEN(ctx, hi(reg))) {
+ if (REG_WAS_SEEN(ctx, hi(reg)))
+ emit(hppa_ldw(-0x48, HPPA_REG_R1, hi(reg)), ctx);
+ if (REG_WAS_SEEN(ctx, lo(reg)))
+ emit(hppa_ldw(-0x44, HPPA_REG_R1, lo(reg)), ctx);
+ bpf_put_reg64(dst, tmp, ctx);
+ }
+
+ dst = regmap[BPF_REG_4];
+ reg = bpf_get_reg64_ref(dst, tmp, false, ctx);
+ if (REG_WAS_SEEN(ctx, lo(reg)) | REG_WAS_SEEN(ctx, hi(reg))) {
+ if (REG_WAS_SEEN(ctx, hi(reg)))
+ emit(hppa_ldw(-0x40, HPPA_REG_R1, hi(reg)), ctx);
+ if (REG_WAS_SEEN(ctx, lo(reg)))
+ emit(hppa_ldw(-0x3c, HPPA_REG_R1, lo(reg)), ctx);
+ bpf_put_reg64(dst, tmp, ctx);
+ }
+
+ dst = regmap[BPF_REG_3];
+ reg = bpf_get_reg64_ref(dst, tmp, false, ctx);
+ if (REG_WAS_SEEN(ctx, lo(reg)) | REG_WAS_SEEN(ctx, hi(reg))) {
+ if (REG_WAS_SEEN(ctx, hi(reg)))
+ emit(hppa_ldw(-0x38, HPPA_REG_R1, hi(reg)), ctx);
+ if (REG_WAS_SEEN(ctx, lo(reg)))
+ emit(hppa_ldw(-0x34, HPPA_REG_R1, lo(reg)), ctx);
+ bpf_put_reg64(dst, tmp, ctx);
+ }
+
+ dst = regmap[BPF_REG_2];
+ reg = bpf_get_reg64_ref(dst, tmp, false, ctx);
+ if (REG_WAS_SEEN(ctx, lo(reg)) | REG_WAS_SEEN(ctx, hi(reg))) {
+ if (REG_WAS_SEEN(ctx, hi(reg)))
+ emit_hppa_copy(HPPA_REG_ARG3, hi(reg), ctx);
+ if (REG_WAS_SEEN(ctx, lo(reg)))
+ emit_hppa_copy(HPPA_REG_ARG2, lo(reg), ctx);
+ bpf_put_reg64(dst, tmp, ctx);
+ }
+
+ dst = regmap[BPF_REG_1];
+ reg = bpf_get_reg64_ref(dst, tmp, false, ctx);
+ if (REG_WAS_SEEN(ctx, lo(reg)) | REG_WAS_SEEN(ctx, hi(reg))) {
+ if (REG_WAS_SEEN(ctx, hi(reg)))
+ emit_hppa_copy(HPPA_REG_ARG1, hi(reg), ctx);
+ if (REG_WAS_SEEN(ctx, lo(reg)))
+ emit_hppa_copy(HPPA_REG_ARG0, lo(reg), ctx);
+ bpf_put_reg64(dst, tmp, ctx);
+ }
+
+ /* Set up BPF frame pointer. */
+ dst = regmap[BPF_REG_FP];
+ reg = bpf_get_reg64_ref(dst, tmp, false, ctx);
+ if (REG_WAS_SEEN(ctx, lo(reg)) | REG_WAS_SEEN(ctx, hi(reg))) {
+ if (REG_WAS_SEEN(ctx, lo(reg)))
+ emit(hppa_ldo(-REG_SIZE * (NR_SAVED_REGISTERS + BPF_JIT_SCRATCH_REGS),
+ HPPA_REG_SP, lo(reg)), ctx);
+ if (REG_WAS_SEEN(ctx, hi(reg)))
+ emit_hppa_copy(HPPA_REG_ZERO, hi(reg), ctx);
+ bpf_put_reg64(dst, tmp, ctx);
+ }
+
+ emit(hppa_nop(), ctx);
+}
+
+void bpf_jit_build_epilogue(struct hppa_jit_context *ctx)
+{
+ __build_epilogue(false, ctx);
+}
diff --git a/arch/parisc/net/bpf_jit_comp64.c b/arch/parisc/net/bpf_jit_comp64.c
new file mode 100644
index 000000000..54b0d5e25
--- /dev/null
+++ b/arch/parisc/net/bpf_jit_comp64.c
@@ -0,0 +1,1209 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * BPF JIT compiler for PA-RISC (64-bit)
+ *
+ * Copyright(c) 2023 Helge Deller <deller@gmx.de>
+ *
+ * The code is based on the BPF JIT compiler for RV64 by Björn Töpel.
+ *
+ * TODO:
+ * - check if bpf_jit_needs_zext() is needed (currently enabled)
+ * - implement arch_prepare_bpf_trampoline(), poke(), ...
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bpf.h>
+#include <linux/filter.h>
+#include <linux/libgcc.h>
+#include "bpf_jit.h"
+
+static const int regmap[] = {
+ [BPF_REG_0] = HPPA_REG_RET0,
+ [BPF_REG_1] = HPPA_R(5),
+ [BPF_REG_2] = HPPA_R(6),
+ [BPF_REG_3] = HPPA_R(7),
+ [BPF_REG_4] = HPPA_R(8),
+ [BPF_REG_5] = HPPA_R(9),
+ [BPF_REG_6] = HPPA_R(10),
+ [BPF_REG_7] = HPPA_R(11),
+ [BPF_REG_8] = HPPA_R(12),
+ [BPF_REG_9] = HPPA_R(13),
+ [BPF_REG_FP] = HPPA_R(14),
+ [BPF_REG_AX] = HPPA_R(15),
+};
+
+/*
+ * Stack layout during BPF program execution (note: stack grows up):
+ *
+ * high
+ * HPPA64 sp => +----------+ <= HPPA64 fp
+ * | saved sp |
+ * | saved rp |
+ * | ... | HPPA64 callee-saved registers
+ * | curr args|
+ * | local var|
+ * +----------+ <= (BPF FP)
+ * | |
+ * | ... | BPF program stack
+ * | |
+ * | ... | Function call stack
+ * | |
+ * +----------+
+ * low
+ */
+
+/* Offset from fp for BPF registers stored on stack. */
+#define STACK_ALIGN FRAME_SIZE
+
+#define EXIT_PTR_LOAD(reg) hppa64_ldd_im16(-FRAME_SIZE, HPPA_REG_SP, reg)
+#define EXIT_PTR_STORE(reg) hppa64_std_im16(reg, -FRAME_SIZE, HPPA_REG_SP)
+#define EXIT_PTR_JUMP(reg, nop) hppa_bv(HPPA_REG_ZERO, reg, nop)
+
+static u8 bpf_to_hppa_reg(int bpf_reg, struct hppa_jit_context *ctx)
+{
+ u8 reg = regmap[bpf_reg];
+
+ REG_SET_SEEN(ctx, reg);
+ return reg;
+};
+
+static void emit_hppa_copy(const s8 rs, const s8 rd, struct hppa_jit_context *ctx)
+{
+ REG_SET_SEEN(ctx, rd);
+ if (OPTIMIZE_HPPA && (rs == rd))
+ return;
+ REG_SET_SEEN(ctx, rs);
+ emit(hppa_copy(rs, rd), ctx);
+}
+
+static void emit_hppa64_depd(u8 src, u8 pos, u8 len, u8 target, bool no_zero, struct hppa_jit_context *ctx)
+{
+ int c;
+
+ pos &= (BITS_PER_LONG - 1);
+ pos = 63 - pos;
+ len = 64 - len;
+ c = (len < 32) ? 0x4 : 0;
+ c |= (pos >= 32) ? 0x2 : 0;
+ c |= (no_zero) ? 0x1 : 0;
+ emit(hppa_t10_insn(0x3c, target, src, 0, c, pos & 0x1f, len & 0x1f), ctx);
+}
+
+static void emit_hppa64_shld(u8 src, int num, u8 target, struct hppa_jit_context *ctx)
+{
+ emit_hppa64_depd(src, 63-num, 64-num, target, 0, ctx);
+}
+
+static void emit_hppa64_extrd(u8 src, u8 pos, u8 len, u8 target, bool signed_op, struct hppa_jit_context *ctx)
+{
+ int c;
+
+ pos &= (BITS_PER_LONG - 1);
+ len = 64 - len;
+ c = (len < 32) ? 0x4 : 0;
+ c |= (pos >= 32) ? 0x2 : 0;
+ c |= signed_op ? 0x1 : 0;
+ emit(hppa_t10_insn(0x36, src, target, 0, c, pos & 0x1f, len & 0x1f), ctx);
+}
+
+static void emit_hppa64_extrw(u8 src, u8 pos, u8 len, u8 target, bool signed_op, struct hppa_jit_context *ctx)
+{
+ int c;
+
+ pos &= (32 - 1);
+ len = 32 - len;
+ c = 0x06 | (signed_op ? 1 : 0);
+ emit(hppa_t10_insn(0x34, src, target, 0, c, pos, len), ctx);
+}
+
+#define emit_hppa64_zext32(r, target, ctx) \
+ emit_hppa64_extrd(r, 63, 32, target, false, ctx)
+#define emit_hppa64_sext32(r, target, ctx) \
+ emit_hppa64_extrd(r, 63, 32, target, true, ctx)
+
+static void emit_hppa64_shrd(u8 src, int num, u8 target, bool signed_op, struct hppa_jit_context *ctx)
+{
+ emit_hppa64_extrd(src, 63-num, 64-num, target, signed_op, ctx);
+}
+
+static void emit_hppa64_shrw(u8 src, int num, u8 target, bool signed_op, struct hppa_jit_context *ctx)
+{
+ emit_hppa64_extrw(src, 31-num, 32-num, target, signed_op, ctx);
+}
+
+/* Emit variable-length instructions for 32-bit imm */
+static void emit_imm32(u8 rd, s32 imm, struct hppa_jit_context *ctx)
+{
+ u32 lower = im11(imm);
+
+ REG_SET_SEEN(ctx, rd);
+ if (OPTIMIZE_HPPA && relative_bits_ok(imm, 14)) {
+ emit(hppa_ldi(imm, rd), ctx);
+ return;
+ }
+ if (OPTIMIZE_HPPA && lower == imm) {
+ emit(hppa_ldo(lower, HPPA_REG_ZERO, rd), ctx);
+ return;
+ }
+ emit(hppa_ldil(imm, rd), ctx);
+ if (OPTIMIZE_HPPA && (lower == 0))
+ return;
+ emit(hppa_ldo(lower, rd, rd), ctx);
+}
+
+static bool is_32b_int(s64 val)
+{
+ return val == (s32) val;
+}
+
+/* Emit variable-length instructions for 64-bit imm */
+static void emit_imm(u8 rd, s64 imm, u8 tmpreg, struct hppa_jit_context *ctx)
+{
+ u32 upper32;
+
+ /* get lower 32-bits into rd, sign extended */
+ emit_imm32(rd, imm, ctx);
+
+ /* do we have upper 32-bits too ? */
+ if (OPTIMIZE_HPPA && is_32b_int(imm))
+ return;
+
+ /* load upper 32-bits into lower tmpreg and deposit into rd */
+ upper32 = imm >> 32;
+ if (upper32 || !OPTIMIZE_HPPA) {
+ emit_imm32(tmpreg, upper32, ctx);
+ emit_hppa64_depd(tmpreg, 31, 32, rd, 1, ctx);
+ } else
+ emit_hppa64_depd(HPPA_REG_ZERO, 31, 32, rd, 1, ctx);
+
+}
+
+static int emit_jump(signed long paoff, bool force_far,
+ struct hppa_jit_context *ctx)
+{
+ unsigned long pc, addr;
+
+ /* Note: Use 2 instructions for jumps if force_far is set. */
+ if (relative_bits_ok(paoff - HPPA_BRANCH_DISPLACEMENT, 22)) {
+ /* use BL,long branch followed by nop() */
+ emit(hppa64_bl_long(paoff - HPPA_BRANCH_DISPLACEMENT), ctx);
+ if (force_far)
+ emit(hppa_nop(), ctx);
+ return 0;
+ }
+
+ pc = (uintptr_t) &ctx->insns[ctx->ninsns];
+ addr = pc + (paoff * HPPA_INSN_SIZE);
+ /* even the 64-bit kernel runs in memory below 4GB */
+ if (WARN_ON_ONCE(addr >> 32))
+ return -E2BIG;
+ emit(hppa_ldil(addr, HPPA_REG_R31), ctx);
+ emit(hppa_be_l(im11(addr) >> 2, HPPA_REG_R31, NOP_NEXT_INSTR), ctx);
+ return 0;
+}
+
+static void __build_epilogue(bool is_tail_call, struct hppa_jit_context *ctx)
+{
+ int i;
+
+ if (is_tail_call) {
+ /*
+ * goto *(t0 + 4);
+ * Skips first instruction of prologue which initializes tail
+ * call counter. Assumes t0 contains address of target program,
+ * see emit_bpf_tail_call.
+ */
+ emit(hppa_ldo(1 * HPPA_INSN_SIZE, HPPA_REG_T0, HPPA_REG_T0), ctx);
+ emit(hppa_bv(HPPA_REG_ZERO, HPPA_REG_T0, EXEC_NEXT_INSTR), ctx);
+ /* in delay slot: */
+ emit(hppa_copy(HPPA_REG_TCC, HPPA_REG_TCC_IN_INIT), ctx);
+
+ return;
+ }
+
+ /* load epilogue function pointer and jump to it. */
+ /* exit point is either at next instruction, or the outest TCC exit function */
+ emit(EXIT_PTR_LOAD(HPPA_REG_RP), ctx);
+ emit(EXIT_PTR_JUMP(HPPA_REG_RP, NOP_NEXT_INSTR), ctx);
+
+ /* NOTE: we are 64-bit and big-endian, so return lower sign-extended 32-bit value */
+ emit_hppa64_sext32(regmap[BPF_REG_0], HPPA_REG_RET0, ctx);
+
+ /* Restore callee-saved registers. */
+ for (i = 3; i <= 15; i++) {
+ if (OPTIMIZE_HPPA && !REG_WAS_SEEN(ctx, HPPA_R(i)))
+ continue;
+ emit(hppa64_ldd_im16(-REG_SIZE * i, HPPA_REG_SP, HPPA_R(i)), ctx);
+ }
+
+ /* load original return pointer (stored by outest TCC function) */
+ emit(hppa64_ldd_im16(-2*REG_SIZE, HPPA_REG_SP, HPPA_REG_RP), ctx);
+ emit(hppa_bv(HPPA_REG_ZERO, HPPA_REG_RP, EXEC_NEXT_INSTR), ctx);
+ /* in delay slot: */
+ emit(hppa64_ldd_im5(-REG_SIZE, HPPA_REG_SP, HPPA_REG_SP), ctx);
+
+ emit(hppa_nop(), ctx); // XXX WARUM einer zu wenig ??
+}
+
+static int emit_branch(u8 op, u8 rd, u8 rs, signed long paoff,
+ struct hppa_jit_context *ctx)
+{
+ int e, s;
+ bool far = false;
+ int off;
+
+ if (op == BPF_JSET) {
+ /*
+ * BPF_JSET is a special case: it has no inverse so translate
+ * to and() function and compare against zero
+ */
+ emit(hppa_and(rd, rs, HPPA_REG_T0), ctx);
+ paoff -= 1; /* reduce offset due to hppa_and() above */
+ rd = HPPA_REG_T0;
+ rs = HPPA_REG_ZERO;
+ op = BPF_JNE;
+ }
+
+ /* set start after BPF_JSET */
+ s = ctx->ninsns;
+
+ if (!relative_branch_ok(paoff - HPPA_BRANCH_DISPLACEMENT + 1, 12)) {
+ op = invert_bpf_cond(op);
+ far = true;
+ }
+
+ /*
+ * For a far branch, the condition is negated and we jump over the
+ * branch itself, and the two instructions from emit_jump.
+ * For a near branch, just use paoff.
+ */
+ off = far ? (2 - HPPA_BRANCH_DISPLACEMENT) : paoff - HPPA_BRANCH_DISPLACEMENT;
+
+ switch (op) {
+ /* IF (dst COND src) JUMP off */
+ case BPF_JEQ:
+ emit(hppa_beq(rd, rs, off), ctx);
+ break;
+ case BPF_JGT:
+ emit(hppa_bgtu(rd, rs, off), ctx);
+ break;
+ case BPF_JLT:
+ emit(hppa_bltu(rd, rs, off), ctx);
+ break;
+ case BPF_JGE:
+ emit(hppa_bgeu(rd, rs, off), ctx);
+ break;
+ case BPF_JLE:
+ emit(hppa_bleu(rd, rs, off), ctx);
+ break;
+ case BPF_JNE:
+ emit(hppa_bne(rd, rs, off), ctx);
+ break;
+ case BPF_JSGT:
+ emit(hppa_bgt(rd, rs, off), ctx);
+ break;
+ case BPF_JSLT:
+ emit(hppa_blt(rd, rs, off), ctx);
+ break;
+ case BPF_JSGE:
+ emit(hppa_bge(rd, rs, off), ctx);
+ break;
+ case BPF_JSLE:
+ emit(hppa_ble(rd, rs, off), ctx);
+ break;
+ default:
+ WARN_ON(1);
+ }
+
+ if (far) {
+ int ret;
+ e = ctx->ninsns;
+ /* Adjust for extra insns. */
+ paoff -= (e - s);
+ ret = emit_jump(paoff, true, ctx);
+ if (ret)
+ return ret;
+ } else {
+ /*
+ * always allocate 2 nops instead of the far branch to
+ * reduce translation loops
+ */
+ emit(hppa_nop(), ctx);
+ emit(hppa_nop(), ctx);
+ }
+ return 0;
+}
+
+static void emit_zext_32(u8 reg, struct hppa_jit_context *ctx)
+{
+ emit_hppa64_zext32(reg, reg, ctx);
+}
+
+static void emit_bpf_tail_call(int insn, struct hppa_jit_context *ctx)
+{
+ /*
+ * R1 -> &ctx
+ * R2 -> &array
+ * R3 -> index
+ */
+ int off;
+ const s8 arr_reg = regmap[BPF_REG_2];
+ const s8 idx_reg = regmap[BPF_REG_3];
+ struct bpf_array bpfa;
+ struct bpf_prog bpfp;
+
+ /* if there is any tail call, we need to save & restore all registers */
+ REG_SET_SEEN_ALL(ctx);
+
+ /* get address of TCC main exit function for error case into rp */
+ emit(EXIT_PTR_LOAD(HPPA_REG_RP), ctx);
+
+ /* max_entries = array->map.max_entries; */
+ off = offsetof(struct bpf_array, map.max_entries);
+ BUILD_BUG_ON(sizeof(bpfa.map.max_entries) != 4);
+ emit(hppa_ldw(off, arr_reg, HPPA_REG_T1), ctx);
+
+ /*
+ * if (index >= max_entries)
+ * goto out;
+ */
+ emit(hppa_bltu(idx_reg, HPPA_REG_T1, 2 - HPPA_BRANCH_DISPLACEMENT), ctx);
+ emit(EXIT_PTR_JUMP(HPPA_REG_RP, NOP_NEXT_INSTR), ctx);
+
+ /*
+ * if (--tcc < 0)
+ * goto out;
+ */
+ REG_FORCE_SEEN(ctx, HPPA_REG_TCC);
+ emit(hppa_ldo(-1, HPPA_REG_TCC, HPPA_REG_TCC), ctx);
+ emit(hppa_bge(HPPA_REG_TCC, HPPA_REG_ZERO, 2 - HPPA_BRANCH_DISPLACEMENT), ctx);
+ emit(EXIT_PTR_JUMP(HPPA_REG_RP, NOP_NEXT_INSTR), ctx);
+
+ /*
+ * prog = array->ptrs[index];
+ * if (!prog)
+ * goto out;
+ */
+ BUILD_BUG_ON(sizeof(bpfa.ptrs[0]) != 8);
+ emit(hppa64_shladd(idx_reg, 3, arr_reg, HPPA_REG_T0), ctx);
+ off = offsetof(struct bpf_array, ptrs);
+ BUILD_BUG_ON(off < 16);
+ emit(hppa64_ldd_im16(off, HPPA_REG_T0, HPPA_REG_T0), ctx);
+ emit(hppa_bne(HPPA_REG_T0, HPPA_REG_ZERO, 2 - HPPA_BRANCH_DISPLACEMENT), ctx);
+ emit(EXIT_PTR_JUMP(HPPA_REG_RP, NOP_NEXT_INSTR), ctx);
+
+ /*
+ * tcc = temp_tcc;
+ * goto *(prog->bpf_func + 4);
+ */
+ off = offsetof(struct bpf_prog, bpf_func);
+ BUILD_BUG_ON(off < 16);
+ BUILD_BUG_ON(sizeof(bpfp.bpf_func) != 8);
+ emit(hppa64_ldd_im16(off, HPPA_REG_T0, HPPA_REG_T0), ctx);
+ /* Epilogue jumps to *(t0 + 4). */
+ __build_epilogue(true, ctx);
+}
+
+static void init_regs(u8 *rd, u8 *rs, const struct bpf_insn *insn,
+ struct hppa_jit_context *ctx)
+{
+ u8 code = insn->code;
+
+ switch (code) {
+ case BPF_JMP | BPF_JA:
+ case BPF_JMP | BPF_CALL:
+ case BPF_JMP | BPF_EXIT:
+ case BPF_JMP | BPF_TAIL_CALL:
+ break;
+ default:
+ *rd = bpf_to_hppa_reg(insn->dst_reg, ctx);
+ }
+
+ if (code & (BPF_ALU | BPF_X) || code & (BPF_ALU64 | BPF_X) ||
+ code & (BPF_JMP | BPF_X) || code & (BPF_JMP32 | BPF_X) ||
+ code & BPF_LDX || code & BPF_STX)
+ *rs = bpf_to_hppa_reg(insn->src_reg, ctx);
+}
+
+static void emit_zext_32_rd_rs(u8 *rd, u8 *rs, struct hppa_jit_context *ctx)
+{
+ emit_hppa64_zext32(*rd, HPPA_REG_T2, ctx);
+ *rd = HPPA_REG_T2;
+ emit_hppa64_zext32(*rs, HPPA_REG_T1, ctx);
+ *rs = HPPA_REG_T1;
+}
+
+static void emit_sext_32_rd_rs(u8 *rd, u8 *rs, struct hppa_jit_context *ctx)
+{
+ emit_hppa64_sext32(*rd, HPPA_REG_T2, ctx);
+ *rd = HPPA_REG_T2;
+ emit_hppa64_sext32(*rs, HPPA_REG_T1, ctx);
+ *rs = HPPA_REG_T1;
+}
+
+static void emit_zext_32_rd_t1(u8 *rd, struct hppa_jit_context *ctx)
+{
+ emit_hppa64_zext32(*rd, HPPA_REG_T2, ctx);
+ *rd = HPPA_REG_T2;
+ emit_zext_32(HPPA_REG_T1, ctx);
+}
+
+static void emit_sext_32_rd(u8 *rd, struct hppa_jit_context *ctx)
+{
+ emit_hppa64_sext32(*rd, HPPA_REG_T2, ctx);
+ *rd = HPPA_REG_T2;
+}
+
+static bool is_signed_bpf_cond(u8 cond)
+{
+ return cond == BPF_JSGT || cond == BPF_JSLT ||
+ cond == BPF_JSGE || cond == BPF_JSLE;
+}
+
+static void emit_call(u64 addr, bool fixed, struct hppa_jit_context *ctx)
+{
+ const int offset_sp = 2*FRAME_SIZE;
+
+ emit(hppa_ldo(offset_sp, HPPA_REG_SP, HPPA_REG_SP), ctx);
+
+ emit_hppa_copy(regmap[BPF_REG_1], HPPA_REG_ARG0, ctx);
+ emit_hppa_copy(regmap[BPF_REG_2], HPPA_REG_ARG1, ctx);
+ emit_hppa_copy(regmap[BPF_REG_3], HPPA_REG_ARG2, ctx);
+ emit_hppa_copy(regmap[BPF_REG_4], HPPA_REG_ARG3, ctx);
+ emit_hppa_copy(regmap[BPF_REG_5], HPPA_REG_ARG4, ctx);
+
+ /* Backup TCC. */
+ REG_FORCE_SEEN(ctx, HPPA_REG_TCC_SAVED);
+ if (REG_WAS_SEEN(ctx, HPPA_REG_TCC))
+ emit(hppa_copy(HPPA_REG_TCC, HPPA_REG_TCC_SAVED), ctx);
+
+ /*
+ * Use ldil() to load absolute address. Don't use emit_imm as the
+ * number of emitted instructions should not depend on the value of
+ * addr.
+ */
+ WARN_ON(addr >> 32);
+ /* load function address and gp from Elf64_Fdesc descriptor */
+ emit(hppa_ldil(addr, HPPA_REG_R31), ctx);
+ emit(hppa_ldo(im11(addr), HPPA_REG_R31, HPPA_REG_R31), ctx);
+ emit(hppa64_ldd_im16(offsetof(struct elf64_fdesc, addr),
+ HPPA_REG_R31, HPPA_REG_RP), ctx);
+ emit(hppa64_bve_l_rp(HPPA_REG_RP), ctx);
+ emit(hppa64_ldd_im16(offsetof(struct elf64_fdesc, gp),
+ HPPA_REG_R31, HPPA_REG_GP), ctx);
+
+ /* Restore TCC. */
+ if (REG_WAS_SEEN(ctx, HPPA_REG_TCC))
+ emit(hppa_copy(HPPA_REG_TCC_SAVED, HPPA_REG_TCC), ctx);
+
+ emit(hppa_ldo(-offset_sp, HPPA_REG_SP, HPPA_REG_SP), ctx);
+
+ /* Set return value. */
+ emit_hppa_copy(HPPA_REG_RET0, regmap[BPF_REG_0], ctx);
+}
+
+static void emit_call_libgcc_ll(void *func, const s8 arg0,
+ const s8 arg1, u8 opcode, struct hppa_jit_context *ctx)
+{
+ u64 func_addr;
+
+ if (BPF_CLASS(opcode) == BPF_ALU) {
+ emit_hppa64_zext32(arg0, HPPA_REG_ARG0, ctx);
+ emit_hppa64_zext32(arg1, HPPA_REG_ARG1, ctx);
+ } else {
+ emit_hppa_copy(arg0, HPPA_REG_ARG0, ctx);
+ emit_hppa_copy(arg1, HPPA_REG_ARG1, ctx);
+ }
+
+ /* libcgcc overwrites HPPA_REG_RET0, so keep copy in HPPA_REG_TCC_SAVED */
+ if (arg0 != HPPA_REG_RET0) {
+ REG_SET_SEEN(ctx, HPPA_REG_TCC_SAVED);
+ emit(hppa_copy(HPPA_REG_RET0, HPPA_REG_TCC_SAVED), ctx);
+ }
+
+ /* set up stack */
+ emit(hppa_ldo(FRAME_SIZE, HPPA_REG_SP, HPPA_REG_SP), ctx);
+
+ func_addr = (uintptr_t) func;
+ /* load function func_address and gp from Elf64_Fdesc descriptor */
+ emit_imm(HPPA_REG_R31, func_addr, arg0, ctx);
+ emit(hppa64_ldd_im16(offsetof(struct elf64_fdesc, addr),
+ HPPA_REG_R31, HPPA_REG_RP), ctx);
+ /* skip the following bve_l instruction if divisor is 0. */
+ if (BPF_OP(opcode) == BPF_DIV || BPF_OP(opcode) == BPF_MOD) {
+ if (BPF_OP(opcode) == BPF_DIV)
+ emit_hppa_copy(HPPA_REG_ZERO, HPPA_REG_RET0, ctx);
+ else {
+ emit_hppa_copy(HPPA_REG_ARG0, HPPA_REG_RET0, ctx);
+ }
+ emit(hppa_beq(HPPA_REG_ARG1, HPPA_REG_ZERO, 2 - HPPA_BRANCH_DISPLACEMENT), ctx);
+ }
+ emit(hppa64_bve_l_rp(HPPA_REG_RP), ctx);
+ emit(hppa64_ldd_im16(offsetof(struct elf64_fdesc, gp),
+ HPPA_REG_R31, HPPA_REG_GP), ctx);
+
+ emit(hppa_ldo(-FRAME_SIZE, HPPA_REG_SP, HPPA_REG_SP), ctx);
+
+ emit_hppa_copy(HPPA_REG_RET0, arg0, ctx);
+
+ /* restore HPPA_REG_RET0 */
+ if (arg0 != HPPA_REG_RET0)
+ emit(hppa_copy(HPPA_REG_TCC_SAVED, HPPA_REG_RET0), ctx);
+}
+
+static void emit_store(const s8 rd, const s8 rs, s16 off,
+ struct hppa_jit_context *ctx, const u8 size,
+ const u8 mode)
+{
+ s8 dstreg;
+
+ /* need to calculate address since offset does not fit in 14 bits? */
+ if (relative_bits_ok(off, 14))
+ dstreg = rd;
+ else {
+ /* need to use R1 here, since addil puts result into R1 */
+ dstreg = HPPA_REG_R1;
+ emit(hppa_addil(off, rd), ctx);
+ off = im11(off);
+ }
+
+ switch (size) {
+ case BPF_B:
+ emit(hppa_stb(rs, off, dstreg), ctx);
+ break;
+ case BPF_H:
+ emit(hppa_sth(rs, off, dstreg), ctx);
+ break;
+ case BPF_W:
+ emit(hppa_stw(rs, off, dstreg), ctx);
+ break;
+ case BPF_DW:
+ if (off & 7) {
+ emit(hppa_ldo(off, dstreg, HPPA_REG_R1), ctx);
+ emit(hppa64_std_im5(rs, 0, HPPA_REG_R1), ctx);
+ } else if (off >= -16 && off <= 15)
+ emit(hppa64_std_im5(rs, off, dstreg), ctx);
+ else
+ emit(hppa64_std_im16(rs, off, dstreg), ctx);
+ break;
+ }
+}
+
+int bpf_jit_emit_insn(const struct bpf_insn *insn, struct hppa_jit_context *ctx,
+ bool extra_pass)
+{
+ bool is64 = BPF_CLASS(insn->code) == BPF_ALU64 ||
+ BPF_CLASS(insn->code) == BPF_JMP;
+ int s, e, ret, i = insn - ctx->prog->insnsi;
+ s64 paoff;
+ struct bpf_prog_aux *aux = ctx->prog->aux;
+ u8 rd = -1, rs = -1, code = insn->code;
+ s16 off = insn->off;
+ s32 imm = insn->imm;
+
+ init_regs(&rd, &rs, insn, ctx);
+
+ switch (code) {
+ /* dst = src */
+ case BPF_ALU | BPF_MOV | BPF_X:
+ case BPF_ALU64 | BPF_MOV | BPF_X:
+ if (imm == 1) {
+ /* Special mov32 for zext */
+ emit_zext_32(rd, ctx);
+ break;
+ }
+ if (!is64 && !aux->verifier_zext)
+ emit_hppa64_zext32(rs, rd, ctx);
+ else
+ emit_hppa_copy(rs, rd, ctx);
+ break;
+
+ /* dst = dst OP src */
+ case BPF_ALU | BPF_ADD | BPF_X:
+ case BPF_ALU64 | BPF_ADD | BPF_X:
+ emit(hppa_add(rd, rs, rd), ctx);
+ if (!is64 && !aux->verifier_zext)
+ emit_zext_32(rd, ctx);
+ break;
+ case BPF_ALU | BPF_SUB | BPF_X:
+ case BPF_ALU64 | BPF_SUB | BPF_X:
+ emit(hppa_sub(rd, rs, rd), ctx);
+ if (!is64 && !aux->verifier_zext)
+ emit_zext_32(rd, ctx);
+ break;
+ case BPF_ALU | BPF_AND | BPF_X:
+ case BPF_ALU64 | BPF_AND | BPF_X:
+ emit(hppa_and(rd, rs, rd), ctx);
+ if (!is64 && !aux->verifier_zext)
+ emit_zext_32(rd, ctx);
+ break;
+ case BPF_ALU | BPF_OR | BPF_X:
+ case BPF_ALU64 | BPF_OR | BPF_X:
+ emit(hppa_or(rd, rs, rd), ctx);
+ if (!is64 && !aux->verifier_zext)
+ emit_zext_32(rd, ctx);
+ break;
+ case BPF_ALU | BPF_XOR | BPF_X:
+ case BPF_ALU64 | BPF_XOR | BPF_X:
+ emit(hppa_xor(rd, rs, rd), ctx);
+ if (!is64 && !aux->verifier_zext && rs != rd)
+ emit_zext_32(rd, ctx);
+ break;
+ case BPF_ALU | BPF_MUL | BPF_K:
+ case BPF_ALU64 | BPF_MUL | BPF_K:
+ emit_imm(HPPA_REG_T1, is64 ? (s64)(s32)imm : (u32)imm, HPPA_REG_T2, ctx);
+ rs = HPPA_REG_T1;
+ fallthrough;
+ case BPF_ALU | BPF_MUL | BPF_X:
+ case BPF_ALU64 | BPF_MUL | BPF_X:
+ emit_call_libgcc_ll(__muldi3, rd, rs, code, ctx);
+ if (!is64 && !aux->verifier_zext)
+ emit_zext_32(rd, ctx);
+ break;
+ case BPF_ALU | BPF_DIV | BPF_K:
+ case BPF_ALU64 | BPF_DIV | BPF_K:
+ emit_imm(HPPA_REG_T1, is64 ? (s64)(s32)imm : (u32)imm, HPPA_REG_T2, ctx);
+ rs = HPPA_REG_T1;
+ fallthrough;
+ case BPF_ALU | BPF_DIV | BPF_X:
+ case BPF_ALU64 | BPF_DIV | BPF_X:
+ emit_call_libgcc_ll(&hppa_div64, rd, rs, code, ctx);
+ if (!is64 && !aux->verifier_zext)
+ emit_zext_32(rd, ctx);
+ break;
+ case BPF_ALU | BPF_MOD | BPF_K:
+ case BPF_ALU64 | BPF_MOD | BPF_K:
+ emit_imm(HPPA_REG_T1, is64 ? (s64)(s32)imm : (u32)imm, HPPA_REG_T2, ctx);
+ rs = HPPA_REG_T1;
+ fallthrough;
+ case BPF_ALU | BPF_MOD | BPF_X:
+ case BPF_ALU64 | BPF_MOD | BPF_X:
+ emit_call_libgcc_ll(&hppa_div64_rem, rd, rs, code, ctx);
+ if (!is64 && !aux->verifier_zext)
+ emit_zext_32(rd, ctx);
+ break;
+
+ case BPF_ALU | BPF_LSH | BPF_X:
+ case BPF_ALU64 | BPF_LSH | BPF_X:
+ emit_hppa64_sext32(rs, HPPA_REG_T0, ctx);
+ emit(hppa64_mtsarcm(HPPA_REG_T0), ctx);
+ if (is64)
+ emit(hppa64_depdz_sar(rd, rd), ctx);
+ else
+ emit(hppa_depwz_sar(rd, rd), ctx);
+ if (!is64 && !aux->verifier_zext)
+ emit_zext_32(rd, ctx);
+ break;
+ case BPF_ALU | BPF_RSH | BPF_X:
+ case BPF_ALU64 | BPF_RSH | BPF_X:
+ emit(hppa_mtsar(rs), ctx);
+ if (is64)
+ emit(hppa64_shrpd_sar(rd, rd), ctx);
+ else
+ emit(hppa_shrpw_sar(rd, rd), ctx);
+ if (!is64 && !aux->verifier_zext)
+ emit_zext_32(rd, ctx);
+ break;
+ case BPF_ALU | BPF_ARSH | BPF_X:
+ case BPF_ALU64 | BPF_ARSH | BPF_X:
+ emit_hppa64_sext32(rs, HPPA_REG_T0, ctx);
+ emit(hppa64_mtsarcm(HPPA_REG_T0), ctx);
+ if (is64)
+ emit(hppa_extrd_sar(rd, rd, 1), ctx);
+ else
+ emit(hppa_extrws_sar(rd, rd), ctx);
+ if (!is64 && !aux->verifier_zext)
+ emit_zext_32(rd, ctx);
+ break;
+
+ /* dst = -dst */
+ case BPF_ALU | BPF_NEG:
+ case BPF_ALU64 | BPF_NEG:
+ emit(hppa_sub(HPPA_REG_ZERO, rd, rd), ctx);
+ if (!is64 && !aux->verifier_zext)
+ emit_zext_32(rd, ctx);
+ break;
+
+ /* dst = BSWAP##imm(dst) */
+ case BPF_ALU | BPF_END | BPF_FROM_BE:
+ switch (imm) {
+ case 16:
+ /* zero-extend 16 bits into 64 bits */
+ emit_hppa64_depd(HPPA_REG_ZERO, 63-16, 64-16, rd, 1, ctx);
+ break;
+ case 32:
+ if (!aux->verifier_zext)
+ emit_zext_32(rd, ctx);
+ break;
+ case 64:
+ /* Do nothing */
+ break;
+ }
+ break;
+
+ case BPF_ALU | BPF_END | BPF_FROM_LE:
+ switch (imm) {
+ case 16:
+ emit(hppa_extru(rd, 31 - 8, 8, HPPA_REG_T1), ctx);
+ emit(hppa_depwz(rd, 23, 8, HPPA_REG_T1), ctx);
+ emit(hppa_extru(HPPA_REG_T1, 31, 16, rd), ctx);
+ emit_hppa64_extrd(HPPA_REG_T1, 63, 16, rd, 0, ctx);
+ break;
+ case 32:
+ emit(hppa_shrpw(rd, rd, 16, HPPA_REG_T1), ctx);
+ emit_hppa64_depd(HPPA_REG_T1, 63-16, 8, HPPA_REG_T1, 1, ctx);
+ emit(hppa_shrpw(rd, HPPA_REG_T1, 8, HPPA_REG_T1), ctx);
+ emit_hppa64_extrd(HPPA_REG_T1, 63, 32, rd, 0, ctx);
+ break;
+ case 64:
+ emit(hppa64_permh_3210(rd, HPPA_REG_T1), ctx);
+ emit(hppa64_hshl(HPPA_REG_T1, 8, HPPA_REG_T2), ctx);
+ emit(hppa64_hshr_u(HPPA_REG_T1, 8, HPPA_REG_T1), ctx);
+ emit(hppa_or(HPPA_REG_T2, HPPA_REG_T1, rd), ctx);
+ break;
+ default:
+ pr_err("bpf-jit: BPF_END imm %d invalid\n", imm);
+ return -1;
+ }
+ break;
+
+ /* dst = imm */
+ case BPF_ALU | BPF_MOV | BPF_K:
+ case BPF_ALU64 | BPF_MOV | BPF_K:
+ emit_imm(rd, imm, HPPA_REG_T2, ctx);
+ if (!is64 && !aux->verifier_zext)
+ emit_zext_32(rd, ctx);
+ break;
+
+ /* dst = dst OP imm */
+ case BPF_ALU | BPF_ADD | BPF_K:
+ case BPF_ALU64 | BPF_ADD | BPF_K:
+ if (relative_bits_ok(imm, 14)) {
+ emit(hppa_ldo(imm, rd, rd), ctx);
+ } else {
+ emit_imm(HPPA_REG_T1, imm, HPPA_REG_T2, ctx);
+ emit(hppa_add(rd, HPPA_REG_T1, rd), ctx);
+ }
+ if (!is64 && !aux->verifier_zext)
+ emit_zext_32(rd, ctx);
+ break;
+ case BPF_ALU | BPF_SUB | BPF_K:
+ case BPF_ALU64 | BPF_SUB | BPF_K:
+ if (relative_bits_ok(-imm, 14)) {
+ emit(hppa_ldo(-imm, rd, rd), ctx);
+ } else {
+ emit_imm(HPPA_REG_T1, imm, HPPA_REG_T2, ctx);
+ emit(hppa_sub(rd, HPPA_REG_T1, rd), ctx);
+ }
+ if (!is64 && !aux->verifier_zext)
+ emit_zext_32(rd, ctx);
+ break;
+ case BPF_ALU | BPF_AND | BPF_K:
+ case BPF_ALU64 | BPF_AND | BPF_K:
+ emit_imm(HPPA_REG_T1, imm, HPPA_REG_T2, ctx);
+ emit(hppa_and(rd, HPPA_REG_T1, rd), ctx);
+ if (!is64 && !aux->verifier_zext)
+ emit_zext_32(rd, ctx);
+ break;
+ case BPF_ALU | BPF_OR | BPF_K:
+ case BPF_ALU64 | BPF_OR | BPF_K:
+ emit_imm(HPPA_REG_T1, imm, HPPA_REG_T2, ctx);
+ emit(hppa_or(rd, HPPA_REG_T1, rd), ctx);
+ if (!is64 && !aux->verifier_zext)
+ emit_zext_32(rd, ctx);
+ break;
+ case BPF_ALU | BPF_XOR | BPF_K:
+ case BPF_ALU64 | BPF_XOR | BPF_K:
+ emit_imm(HPPA_REG_T1, imm, HPPA_REG_T2, ctx);
+ emit(hppa_xor(rd, HPPA_REG_T1, rd), ctx);
+ if (!is64 && !aux->verifier_zext)
+ emit_zext_32(rd, ctx);
+ break;
+ case BPF_ALU | BPF_LSH | BPF_K:
+ case BPF_ALU64 | BPF_LSH | BPF_K:
+ if (imm != 0) {
+ emit_hppa64_shld(rd, imm, rd, ctx);
+ }
+
+ if (!is64 && !aux->verifier_zext)
+ emit_zext_32(rd, ctx);
+ break;
+ case BPF_ALU | BPF_RSH | BPF_K:
+ case BPF_ALU64 | BPF_RSH | BPF_K:
+ if (imm != 0) {
+ if (is64)
+ emit_hppa64_shrd(rd, imm, rd, false, ctx);
+ else
+ emit_hppa64_shrw(rd, imm, rd, false, ctx);
+ }
+
+ if (!is64 && !aux->verifier_zext)
+ emit_zext_32(rd, ctx);
+ break;
+ case BPF_ALU | BPF_ARSH | BPF_K:
+ case BPF_ALU64 | BPF_ARSH | BPF_K:
+ if (imm != 0) {
+ if (is64)
+ emit_hppa64_shrd(rd, imm, rd, true, ctx);
+ else
+ emit_hppa64_shrw(rd, imm, rd, true, ctx);
+ }
+
+ if (!is64 && !aux->verifier_zext)
+ emit_zext_32(rd, ctx);
+ break;
+
+ /* JUMP off */
+ case BPF_JMP | BPF_JA:
+ paoff = hppa_offset(i, off, ctx);
+ ret = emit_jump(paoff, false, ctx);
+ if (ret)
+ return ret;
+ break;
+
+ /* IF (dst COND src) JUMP off */
+ case BPF_JMP | BPF_JEQ | BPF_X:
+ case BPF_JMP32 | BPF_JEQ | BPF_X:
+ case BPF_JMP | BPF_JGT | BPF_X:
+ case BPF_JMP32 | BPF_JGT | BPF_X:
+ case BPF_JMP | BPF_JLT | BPF_X:
+ case BPF_JMP32 | BPF_JLT | BPF_X:
+ case BPF_JMP | BPF_JGE | BPF_X:
+ case BPF_JMP32 | BPF_JGE | BPF_X:
+ case BPF_JMP | BPF_JLE | BPF_X:
+ case BPF_JMP32 | BPF_JLE | BPF_X:
+ case BPF_JMP | BPF_JNE | BPF_X:
+ case BPF_JMP32 | BPF_JNE | BPF_X:
+ case BPF_JMP | BPF_JSGT | BPF_X:
+ case BPF_JMP32 | BPF_JSGT | BPF_X:
+ case BPF_JMP | BPF_JSLT | BPF_X:
+ case BPF_JMP32 | BPF_JSLT | BPF_X:
+ case BPF_JMP | BPF_JSGE | BPF_X:
+ case BPF_JMP32 | BPF_JSGE | BPF_X:
+ case BPF_JMP | BPF_JSLE | BPF_X:
+ case BPF_JMP32 | BPF_JSLE | BPF_X:
+ case BPF_JMP | BPF_JSET | BPF_X:
+ case BPF_JMP32 | BPF_JSET | BPF_X:
+ paoff = hppa_offset(i, off, ctx);
+ if (!is64) {
+ s = ctx->ninsns;
+ if (is_signed_bpf_cond(BPF_OP(code)))
+ emit_sext_32_rd_rs(&rd, &rs, ctx);
+ else
+ emit_zext_32_rd_rs(&rd, &rs, ctx);
+ e = ctx->ninsns;
+
+ /* Adjust for extra insns */
+ paoff -= (e - s);
+ }
+ if (BPF_OP(code) == BPF_JSET) {
+ /* Adjust for and */
+ paoff -= 1;
+ emit(hppa_and(rs, rd, HPPA_REG_T1), ctx);
+ emit_branch(BPF_JNE, HPPA_REG_T1, HPPA_REG_ZERO, paoff,
+ ctx);
+ } else {
+ emit_branch(BPF_OP(code), rd, rs, paoff, ctx);
+ }
+ break;
+
+ /* IF (dst COND imm) JUMP off */
+ case BPF_JMP | BPF_JEQ | BPF_K:
+ case BPF_JMP32 | BPF_JEQ | BPF_K:
+ case BPF_JMP | BPF_JGT | BPF_K:
+ case BPF_JMP32 | BPF_JGT | BPF_K:
+ case BPF_JMP | BPF_JLT | BPF_K:
+ case BPF_JMP32 | BPF_JLT | BPF_K:
+ case BPF_JMP | BPF_JGE | BPF_K:
+ case BPF_JMP32 | BPF_JGE | BPF_K:
+ case BPF_JMP | BPF_JLE | BPF_K:
+ case BPF_JMP32 | BPF_JLE | BPF_K:
+ case BPF_JMP | BPF_JNE | BPF_K:
+ case BPF_JMP32 | BPF_JNE | BPF_K:
+ case BPF_JMP | BPF_JSGT | BPF_K:
+ case BPF_JMP32 | BPF_JSGT | BPF_K:
+ case BPF_JMP | BPF_JSLT | BPF_K:
+ case BPF_JMP32 | BPF_JSLT | BPF_K:
+ case BPF_JMP | BPF_JSGE | BPF_K:
+ case BPF_JMP32 | BPF_JSGE | BPF_K:
+ case BPF_JMP | BPF_JSLE | BPF_K:
+ case BPF_JMP32 | BPF_JSLE | BPF_K:
+ paoff = hppa_offset(i, off, ctx);
+ s = ctx->ninsns;
+ if (imm) {
+ emit_imm(HPPA_REG_T1, imm, HPPA_REG_T2, ctx);
+ rs = HPPA_REG_T1;
+ } else {
+ rs = HPPA_REG_ZERO;
+ }
+ if (!is64) {
+ if (is_signed_bpf_cond(BPF_OP(code)))
+ emit_sext_32_rd(&rd, ctx);
+ else
+ emit_zext_32_rd_t1(&rd, ctx);
+ }
+ e = ctx->ninsns;
+
+ /* Adjust for extra insns */
+ paoff -= (e - s);
+ emit_branch(BPF_OP(code), rd, rs, paoff, ctx);
+ break;
+ case BPF_JMP | BPF_JSET | BPF_K:
+ case BPF_JMP32 | BPF_JSET | BPF_K:
+ paoff = hppa_offset(i, off, ctx);
+ s = ctx->ninsns;
+ emit_imm(HPPA_REG_T1, imm, HPPA_REG_T2, ctx);
+ emit(hppa_and(HPPA_REG_T1, rd, HPPA_REG_T1), ctx);
+ /* For jset32, we should clear the upper 32 bits of t1, but
+ * sign-extension is sufficient here and saves one instruction,
+ * as t1 is used only in comparison against zero.
+ */
+ if (!is64 && imm < 0)
+ emit_hppa64_sext32(HPPA_REG_T1, HPPA_REG_T1, ctx);
+ e = ctx->ninsns;
+ paoff -= (e - s);
+ emit_branch(BPF_JNE, HPPA_REG_T1, HPPA_REG_ZERO, paoff, ctx);
+ break;
+ /* function call */
+ case BPF_JMP | BPF_CALL:
+ {
+ bool fixed_addr;
+ u64 addr;
+
+ ret = bpf_jit_get_func_addr(ctx->prog, insn, extra_pass,
+ &addr, &fixed_addr);
+ if (ret < 0)
+ return ret;
+
+ REG_SET_SEEN_ALL(ctx);
+ emit_call(addr, fixed_addr, ctx);
+ break;
+ }
+ /* tail call */
+ case BPF_JMP | BPF_TAIL_CALL:
+ emit_bpf_tail_call(i, ctx);
+ break;
+
+ /* function return */
+ case BPF_JMP | BPF_EXIT:
+ if (i == ctx->prog->len - 1)
+ break;
+
+ paoff = epilogue_offset(ctx);
+ ret = emit_jump(paoff, false, ctx);
+ if (ret)
+ return ret;
+ break;
+
+ /* dst = imm64 */
+ case BPF_LD | BPF_IMM | BPF_DW:
+ {
+ struct bpf_insn insn1 = insn[1];
+ u64 imm64 = (u64)insn1.imm << 32 | (u32)imm;
+ if (bpf_pseudo_func(insn))
+ imm64 = (uintptr_t)dereference_function_descriptor((void*)imm64);
+ emit_imm(rd, imm64, HPPA_REG_T2, ctx);
+
+ return 1;
+ }
+
+ /* LDX: dst = *(size *)(src + off) */
+ case BPF_LDX | BPF_MEM | BPF_B:
+ case BPF_LDX | BPF_MEM | BPF_H:
+ case BPF_LDX | BPF_MEM | BPF_W:
+ case BPF_LDX | BPF_MEM | BPF_DW:
+ case BPF_LDX | BPF_PROBE_MEM | BPF_B:
+ case BPF_LDX | BPF_PROBE_MEM | BPF_H:
+ case BPF_LDX | BPF_PROBE_MEM | BPF_W:
+ case BPF_LDX | BPF_PROBE_MEM | BPF_DW:
+ {
+ u8 srcreg;
+
+ /* need to calculate address since offset does not fit in 14 bits? */
+ if (relative_bits_ok(off, 14))
+ srcreg = rs;
+ else {
+ /* need to use R1 here, since addil puts result into R1 */
+ srcreg = HPPA_REG_R1;
+ BUG_ON(rs == HPPA_REG_R1);
+ BUG_ON(rd == HPPA_REG_R1);
+ emit(hppa_addil(off, rs), ctx);
+ off = im11(off);
+ }
+
+ switch (BPF_SIZE(code)) {
+ case BPF_B:
+ emit(hppa_ldb(off, srcreg, rd), ctx);
+ if (insn_is_zext(&insn[1]))
+ return 1;
+ break;
+ case BPF_H:
+ emit(hppa_ldh(off, srcreg, rd), ctx);
+ if (insn_is_zext(&insn[1]))
+ return 1;
+ break;
+ case BPF_W:
+ emit(hppa_ldw(off, srcreg, rd), ctx);
+ if (insn_is_zext(&insn[1]))
+ return 1;
+ break;
+ case BPF_DW:
+ if (off & 7) {
+ emit(hppa_ldo(off, srcreg, HPPA_REG_R1), ctx);
+ emit(hppa64_ldd_reg(HPPA_REG_ZERO, HPPA_REG_R1, rd), ctx);
+ } else if (off >= -16 && off <= 15)
+ emit(hppa64_ldd_im5(off, srcreg, rd), ctx);
+ else
+ emit(hppa64_ldd_im16(off, srcreg, rd), ctx);
+ break;
+ }
+ break;
+ }
+ /* speculation barrier */
+ case BPF_ST | BPF_NOSPEC:
+ break;
+
+ /* ST: *(size *)(dst + off) = imm */
+ /* STX: *(size *)(dst + off) = src */
+ case BPF_ST | BPF_MEM | BPF_B:
+ case BPF_ST | BPF_MEM | BPF_H:
+ case BPF_ST | BPF_MEM | BPF_W:
+ case BPF_ST | BPF_MEM | BPF_DW:
+
+ case BPF_STX | BPF_MEM | BPF_B:
+ case BPF_STX | BPF_MEM | BPF_H:
+ case BPF_STX | BPF_MEM | BPF_W:
+ case BPF_STX | BPF_MEM | BPF_DW:
+ if (BPF_CLASS(code) == BPF_ST) {
+ emit_imm(HPPA_REG_T2, imm, HPPA_REG_T1, ctx);
+ rs = HPPA_REG_T2;
+ }
+
+ emit_store(rd, rs, off, ctx, BPF_SIZE(code), BPF_MODE(code));
+ break;
+
+ case BPF_STX | BPF_ATOMIC | BPF_W:
+ case BPF_STX | BPF_ATOMIC | BPF_DW:
+ pr_info_once(
+ "bpf-jit: not supported: atomic operation %02x ***\n",
+ insn->imm);
+ return -EFAULT;
+
+ default:
+ pr_err("bpf-jit: unknown opcode %02x\n", code);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+void bpf_jit_build_prologue(struct hppa_jit_context *ctx)
+{
+ int bpf_stack_adjust, stack_adjust, i;
+ unsigned long addr;
+ s8 reg;
+
+ /*
+ * stack on hppa grows up, so if tail calls are used we need to
+ * allocate the maximum stack size
+ */
+ if (REG_ALL_SEEN(ctx))
+ bpf_stack_adjust = MAX_BPF_STACK;
+ else
+ bpf_stack_adjust = ctx->prog->aux->stack_depth;
+ bpf_stack_adjust = round_up(bpf_stack_adjust, STACK_ALIGN);
+
+ stack_adjust = FRAME_SIZE + bpf_stack_adjust;
+ stack_adjust = round_up(stack_adjust, STACK_ALIGN);
+
+ /*
+ * NOTE: We construct an Elf64_Fdesc descriptor here.
+ * The first 4 words initialize the TCC and compares them.
+ * Then follows the virtual address of the eBPF function,
+ * and the gp for this function.
+ *
+ * The first instruction sets the tail-call-counter (TCC) register.
+ * This instruction is skipped by tail calls.
+ * Use a temporary register instead of a caller-saved register initially.
+ */
+ REG_FORCE_SEEN(ctx, HPPA_REG_TCC_IN_INIT);
+ emit(hppa_ldi(MAX_TAIL_CALL_CNT, HPPA_REG_TCC_IN_INIT), ctx);
+
+ /*
+ * Skip all initializations when called as BPF TAIL call.
+ */
+ emit(hppa_ldi(MAX_TAIL_CALL_CNT, HPPA_REG_R1), ctx);
+ emit(hppa_beq(HPPA_REG_TCC_IN_INIT, HPPA_REG_R1, 6 - HPPA_BRANCH_DISPLACEMENT), ctx);
+ emit(hppa64_bl_long(ctx->prologue_len - 3 - HPPA_BRANCH_DISPLACEMENT), ctx);
+
+ /* store entry address of this eBPF function */
+ addr = (uintptr_t) &ctx->insns[0];
+ emit(addr >> 32, ctx);
+ emit(addr & 0xffffffff, ctx);
+
+ /* store gp of this eBPF function */
+ asm("copy %%r27,%0" : "=r" (addr) );
+ emit(addr >> 32, ctx);
+ emit(addr & 0xffffffff, ctx);
+
+ /* Set up hppa stack frame. */
+ emit_hppa_copy(HPPA_REG_SP, HPPA_REG_R1, ctx);
+ emit(hppa_ldo(stack_adjust, HPPA_REG_SP, HPPA_REG_SP), ctx);
+ emit(hppa64_std_im5 (HPPA_REG_R1, -REG_SIZE, HPPA_REG_SP), ctx);
+ emit(hppa64_std_im16(HPPA_REG_RP, -2*REG_SIZE, HPPA_REG_SP), ctx);
+
+ /* Save callee-save registers. */
+ for (i = 3; i <= 15; i++) {
+ if (OPTIMIZE_HPPA && !REG_WAS_SEEN(ctx, HPPA_R(i)))
+ continue;
+ emit(hppa64_std_im16(HPPA_R(i), -REG_SIZE * i, HPPA_REG_SP), ctx);
+ }
+
+ /* load function parameters; load all if we use tail functions */
+ #define LOAD_PARAM(arg, dst) \
+ if (REG_WAS_SEEN(ctx, regmap[dst]) || \
+ REG_WAS_SEEN(ctx, HPPA_REG_TCC)) \
+ emit_hppa_copy(arg, regmap[dst], ctx)
+ LOAD_PARAM(HPPA_REG_ARG0, BPF_REG_1);
+ LOAD_PARAM(HPPA_REG_ARG1, BPF_REG_2);
+ LOAD_PARAM(HPPA_REG_ARG2, BPF_REG_3);
+ LOAD_PARAM(HPPA_REG_ARG3, BPF_REG_4);
+ LOAD_PARAM(HPPA_REG_ARG4, BPF_REG_5);
+ #undef LOAD_PARAM
+
+ REG_FORCE_SEEN(ctx, HPPA_REG_T0);
+ REG_FORCE_SEEN(ctx, HPPA_REG_T1);
+ REG_FORCE_SEEN(ctx, HPPA_REG_T2);
+
+ /*
+ * Now really set the tail call counter (TCC) register.
+ */
+ if (REG_WAS_SEEN(ctx, HPPA_REG_TCC))
+ emit(hppa_ldi(MAX_TAIL_CALL_CNT, HPPA_REG_TCC), ctx);
+
+ /*
+ * Save epilogue function pointer for outer TCC call chain.
+ * The main TCC call stores the final RP on stack.
+ */
+ addr = (uintptr_t) &ctx->insns[ctx->epilogue_offset];
+ /* skip first two instructions which jump to exit */
+ addr += 2 * HPPA_INSN_SIZE;
+ emit_imm(HPPA_REG_T2, addr, HPPA_REG_T1, ctx);
+ emit(EXIT_PTR_STORE(HPPA_REG_T2), ctx);
+
+ /* Set up BPF frame pointer. */
+ reg = regmap[BPF_REG_FP]; /* -> HPPA_REG_FP */
+ if (REG_WAS_SEEN(ctx, reg)) {
+ emit(hppa_ldo(-FRAME_SIZE, HPPA_REG_SP, reg), ctx);
+ }
+}
+
+void bpf_jit_build_epilogue(struct hppa_jit_context *ctx)
+{
+ __build_epilogue(false, ctx);
+}
+
+bool bpf_jit_supports_kfunc_call(void)
+{
+ return true;
+}
diff --git a/arch/parisc/net/bpf_jit_core.c b/arch/parisc/net/bpf_jit_core.c
new file mode 100644
index 000000000..d6ee2fd45
--- /dev/null
+++ b/arch/parisc/net/bpf_jit_core.c
@@ -0,0 +1,201 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Common functionality for HPPA32 and HPPA64 BPF JIT compilers
+ *
+ * Copyright (c) 2023 Helge Deller <deller@gmx.de>
+ *
+ */
+
+#include <linux/bpf.h>
+#include <linux/filter.h>
+#include "bpf_jit.h"
+
+/* Number of iterations to try until offsets converge. */
+#define NR_JIT_ITERATIONS 35
+
+static int build_body(struct hppa_jit_context *ctx, bool extra_pass, int *offset)
+{
+ const struct bpf_prog *prog = ctx->prog;
+ int i;
+
+ ctx->reg_seen_collect = true;
+ for (i = 0; i < prog->len; i++) {
+ const struct bpf_insn *insn = &prog->insnsi[i];
+ int ret;
+
+ ret = bpf_jit_emit_insn(insn, ctx, extra_pass);
+ /* BPF_LD | BPF_IMM | BPF_DW: skip the next instruction. */
+ if (ret > 0)
+ i++;
+ if (offset)
+ offset[i] = ctx->ninsns;
+ if (ret < 0)
+ return ret;
+ }
+ ctx->reg_seen_collect = false;
+ return 0;
+}
+
+bool bpf_jit_needs_zext(void)
+{
+ return true;
+}
+
+struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
+{
+ unsigned int prog_size = 0, extable_size = 0;
+ bool tmp_blinded = false, extra_pass = false;
+ struct bpf_prog *tmp, *orig_prog = prog;
+ int pass = 0, prev_ninsns = 0, prologue_len, i;
+ struct hppa_jit_data *jit_data;
+ struct hppa_jit_context *ctx;
+
+ if (!prog->jit_requested)
+ return orig_prog;
+
+ tmp = bpf_jit_blind_constants(prog);
+ if (IS_ERR(tmp))
+ return orig_prog;
+ if (tmp != prog) {
+ tmp_blinded = true;
+ prog = tmp;
+ }
+
+ jit_data = prog->aux->jit_data;
+ if (!jit_data) {
+ jit_data = kzalloc(sizeof(*jit_data), GFP_KERNEL);
+ if (!jit_data) {
+ prog = orig_prog;
+ goto out;
+ }
+ prog->aux->jit_data = jit_data;
+ }
+
+ ctx = &jit_data->ctx;
+
+ if (ctx->offset) {
+ extra_pass = true;
+ prog_size = sizeof(*ctx->insns) * ctx->ninsns;
+ goto skip_init_ctx;
+ }
+
+ ctx->prog = prog;
+ ctx->offset = kcalloc(prog->len, sizeof(int), GFP_KERNEL);
+ if (!ctx->offset) {
+ prog = orig_prog;
+ goto out_offset;
+ }
+ for (i = 0; i < prog->len; i++) {
+ prev_ninsns += 20;
+ ctx->offset[i] = prev_ninsns;
+ }
+
+ for (i = 0; i < NR_JIT_ITERATIONS; i++) {
+ pass++;
+ ctx->ninsns = 0;
+ if (build_body(ctx, extra_pass, ctx->offset)) {
+ prog = orig_prog;
+ goto out_offset;
+ }
+ ctx->body_len = ctx->ninsns;
+ bpf_jit_build_prologue(ctx);
+ ctx->prologue_len = ctx->ninsns - ctx->body_len;
+ ctx->epilogue_offset = ctx->ninsns;
+ bpf_jit_build_epilogue(ctx);
+
+ if (ctx->ninsns == prev_ninsns) {
+ if (jit_data->header)
+ break;
+ /* obtain the actual image size */
+ extable_size = prog->aux->num_exentries *
+ sizeof(struct exception_table_entry);
+ prog_size = sizeof(*ctx->insns) * ctx->ninsns;
+
+ jit_data->header =
+ bpf_jit_binary_alloc(prog_size + extable_size,
+ &jit_data->image,
+ sizeof(u32),
+ bpf_fill_ill_insns);
+ if (!jit_data->header) {
+ prog = orig_prog;
+ goto out_offset;
+ }
+
+ ctx->insns = (u32 *)jit_data->image;
+ /*
+ * Now, when the image is allocated, the image can
+ * potentially shrink more (auipc/jalr -> jal).
+ */
+ }
+ prev_ninsns = ctx->ninsns;
+ }
+
+ if (i == NR_JIT_ITERATIONS) {
+ pr_err("bpf-jit: image did not converge in <%d passes!\n", i);
+ if (jit_data->header)
+ bpf_jit_binary_free(jit_data->header);
+ prog = orig_prog;
+ goto out_offset;
+ }
+
+ if (extable_size)
+ prog->aux->extable = (void *)ctx->insns + prog_size;
+
+skip_init_ctx:
+ pass++;
+ ctx->ninsns = 0;
+
+ bpf_jit_build_prologue(ctx);
+ if (build_body(ctx, extra_pass, NULL)) {
+ bpf_jit_binary_free(jit_data->header);
+ prog = orig_prog;
+ goto out_offset;
+ }
+ bpf_jit_build_epilogue(ctx);
+
+ if (HPPA_JIT_DEBUG || bpf_jit_enable > 1) {
+ if (HPPA_JIT_DUMP)
+ bpf_jit_dump(prog->len, prog_size, pass, ctx->insns);
+ if (HPPA_JIT_REBOOT)
+ { extern int machine_restart(char *); machine_restart(""); }
+ }
+
+ prog->bpf_func = (void *)ctx->insns;
+ prog->jited = 1;
+ prog->jited_len = prog_size;
+
+ bpf_flush_icache(jit_data->header, ctx->insns + ctx->ninsns);
+
+ if (!prog->is_func || extra_pass) {
+ bpf_jit_binary_lock_ro(jit_data->header);
+ prologue_len = ctx->epilogue_offset - ctx->body_len;
+ for (i = 0; i < prog->len; i++)
+ ctx->offset[i] += prologue_len;
+ bpf_prog_fill_jited_linfo(prog, ctx->offset);
+out_offset:
+ kfree(ctx->offset);
+ kfree(jit_data);
+ prog->aux->jit_data = NULL;
+ }
+out:
+ if (HPPA_JIT_REBOOT)
+ { extern int machine_restart(char *); machine_restart(""); }
+
+ if (tmp_blinded)
+ bpf_jit_prog_release_other(prog, prog == orig_prog ?
+ tmp : orig_prog);
+ return prog;
+}
+
+u64 hppa_div64(u64 div, u64 divisor)
+{
+ div = div64_u64(div, divisor);
+ return div;
+}
+
+u64 hppa_div64_rem(u64 div, u64 divisor)
+{
+ u64 rem;
+ div64_u64_rem(div, divisor, &rem);
+ return rem;
+}
diff --git a/arch/parisc/video/Makefile b/arch/parisc/video/Makefile
new file mode 100644
index 000000000..16a73cce4
--- /dev/null
+++ b/arch/parisc/video/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+obj-$(CONFIG_STI_CORE) += fbdev.o
diff --git a/arch/parisc/video/fbdev.c b/arch/parisc/video/fbdev.c
new file mode 100644
index 000000000..137561d98
--- /dev/null
+++ b/arch/parisc/video/fbdev.c
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
+ * Copyright (C) 2001-2020 Helge Deller <deller@gmx.de>
+ * Copyright (C) 2001-2002 Thomas Bogendoerfer <tsbogend@alpha.franken.de>
+ */
+
+#include <linux/fb.h>
+#include <linux/module.h>
+
+#include <video/sticore.h>
+
+int fb_is_primary_device(struct fb_info *info)
+{
+ struct sti_struct *sti;
+
+ sti = sti_get_rom(0);
+
+ /* if no built-in graphics card found, allow any fb driver as default */
+ if (!sti)
+ return true;
+
+ /* return true if it's the default built-in framebuffer driver */
+ return (sti->info == info);
+}
+EXPORT_SYMBOL(fb_is_primary_device);