summaryrefslogtreecommitdiff
path: root/arch/sparc
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc')
-rw-r--r--arch/sparc/Kconfig525
-rw-r--r--arch/sparc/Kconfig.debug26
-rw-r--r--arch/sparc/Makefile97
-rw-r--r--arch/sparc/boot/.gitignore8
-rw-r--r--arch/sparc/boot/Makefile38
-rw-r--r--arch/sparc/boot/piggyback_32.c (renamed from arch/sparc/boot/piggyback.c)0
-rw-r--r--arch/sparc/boot/piggyback_64.c109
-rw-r--r--arch/sparc/configs/sparc32_defconfig (renamed from arch/sparc/defconfig)0
-rw-r--r--arch/sparc/configs/sparc64_defconfig1705
-rw-r--r--arch/sparc/include/asm/Kbuild2
-rw-r--r--arch/sparc/include/asm/asm.h40
-rw-r--r--arch/sparc/include/asm/atomic_64.h7
-rw-r--r--arch/sparc/include/asm/bitops_64.h5
-rw-r--r--arch/sparc/include/asm/device.h12
-rw-r--r--arch/sparc/include/asm/hypervisor.h24
-rw-r--r--arch/sparc/include/asm/irq_32.h1
-rw-r--r--arch/sparc/include/asm/irq_64.h3
-rw-r--r--arch/sparc/include/asm/irqflags_64.h6
-rw-r--r--arch/sparc/include/asm/module.h32
-rw-r--r--arch/sparc/include/asm/module_32.h7
-rw-r--r--arch/sparc/include/asm/module_64.h7
-rw-r--r--arch/sparc/include/asm/openprom_32.h6
-rw-r--r--arch/sparc/include/asm/oplib_32.h8
-rw-r--r--arch/sparc/include/asm/pil.h9
-rw-r--r--arch/sparc/include/asm/ptrace_32.h10
-rw-r--r--arch/sparc/include/asm/ptrace_64.h9
-rw-r--r--arch/sparc/include/asm/scatterlist.h33
-rw-r--r--arch/sparc/include/asm/scatterlist_32.h26
-rw-r--r--arch/sparc/include/asm/scatterlist_64.h27
-rw-r--r--arch/sparc/include/asm/sections.h16
-rw-r--r--arch/sparc/include/asm/sections_32.h6
-rw-r--r--arch/sparc/include/asm/sections_64.h9
-rw-r--r--arch/sparc/include/asm/spinlock_64.h31
-rw-r--r--arch/sparc/include/asm/spitfire.h4
-rw-r--r--arch/sparc/include/asm/system_32.h5
-rw-r--r--arch/sparc/include/asm/system_64.h46
-rw-r--r--arch/sparc/include/asm/tsb.h6
-rw-r--r--arch/sparc/include/asm/ttable.h15
-rw-r--r--arch/sparc/include/asm/unistd.h446
-rw-r--r--arch/sparc/include/asm/unistd_32.h385
-rw-r--r--arch/sparc/include/asm/unistd_64.h380
-rw-r--r--arch/sparc/kernel/.gitignore1
-rw-r--r--arch/sparc/kernel/Makefile117
-rw-r--r--arch/sparc/kernel/asm-offsets.c19
-rw-r--r--arch/sparc/kernel/audit.c83
-rw-r--r--arch/sparc/kernel/auxio_32.c (renamed from arch/sparc/kernel/auxio.c)0
-rw-r--r--arch/sparc/kernel/auxio_64.c149
-rw-r--r--arch/sparc/kernel/central.c268
-rw-r--r--arch/sparc/kernel/cherrs.S579
-rw-r--r--arch/sparc/kernel/chmc.c863
-rw-r--r--arch/sparc/kernel/compat_audit.c43
-rw-r--r--arch/sparc/kernel/cpu.c413
-rw-r--r--arch/sparc/kernel/devices.c2
-rw-r--r--arch/sparc/kernel/ds.c1244
-rw-r--r--arch/sparc/kernel/dtlb_miss.S39
-rw-r--r--arch/sparc/kernel/dtlb_prot.S54
-rw-r--r--arch/sparc/kernel/ebus.c257
-rw-r--r--arch/sparc/kernel/entry.h229
-rw-r--r--arch/sparc/kernel/etrap_32.S (renamed from arch/sparc/kernel/etrap.S)0
-rw-r--r--arch/sparc/kernel/etrap_64.S236
-rw-r--r--arch/sparc/kernel/fpu_traps.S384
-rw-r--r--arch/sparc/kernel/ftrace.c76
-rw-r--r--arch/sparc/kernel/getsetcc.S24
-rw-r--r--arch/sparc/kernel/head_32.S (renamed from arch/sparc/kernel/head.S)2
-rw-r--r--arch/sparc/kernel/head_64.S900
-rw-r--r--arch/sparc/kernel/helpers.S63
-rw-r--r--arch/sparc/kernel/hvapi.c193
-rw-r--r--arch/sparc/kernel/hvcalls.S800
-rw-r--r--arch/sparc/kernel/hvtramp.S140
-rw-r--r--arch/sparc/kernel/idprom.c67
-rw-r--r--arch/sparc/kernel/init_task.c4
-rw-r--r--arch/sparc/kernel/iommu.c866
-rw-r--r--arch/sparc/kernel/iommu_common.h59
-rw-r--r--arch/sparc/kernel/ioport.c4
-rw-r--r--arch/sparc/kernel/irq_32.c (renamed from arch/sparc/kernel/irq.c)7
-rw-r--r--arch/sparc/kernel/irq_64.c1104
-rw-r--r--arch/sparc/kernel/itlb_miss.S39
-rw-r--r--arch/sparc/kernel/ivec.S51
-rw-r--r--arch/sparc/kernel/kernel.h31
-rw-r--r--arch/sparc/kernel/kgdb_32.c (renamed from arch/sparc/kernel/kgdb.c)0
-rw-r--r--arch/sparc/kernel/kgdb_64.c186
-rw-r--r--arch/sparc/kernel/kprobes.c593
-rw-r--r--arch/sparc/kernel/kstack.h60
-rw-r--r--arch/sparc/kernel/ktlb.S304
-rw-r--r--arch/sparc/kernel/ldc.c2378
-rw-r--r--arch/sparc/kernel/mdesc.c917
-rw-r--r--arch/sparc/kernel/misctrap.S97
-rw-r--r--arch/sparc/kernel/module.c140
-rw-r--r--arch/sparc/kernel/muldiv.c5
-rw-r--r--arch/sparc/kernel/of_device_32.c (renamed from arch/sparc/kernel/of_device.c)0
-rw-r--r--arch/sparc/kernel/of_device_64.c898
-rw-r--r--arch/sparc/kernel/pci.c1095
-rw-r--r--arch/sparc/kernel/pci_common.c545
-rw-r--r--arch/sparc/kernel/pci_fire.c521
-rw-r--r--arch/sparc/kernel/pci_impl.h185
-rw-r--r--arch/sparc/kernel/pci_msi.c447
-rw-r--r--arch/sparc/kernel/pci_psycho.c618
-rw-r--r--arch/sparc/kernel/pci_sabre.c609
-rw-r--r--arch/sparc/kernel/pci_schizo.c1504
-rw-r--r--arch/sparc/kernel/pci_sun4v.c1033
-rw-r--r--arch/sparc/kernel/pci_sun4v.h92
-rw-r--r--arch/sparc/kernel/pci_sun4v_asm.S362
-rw-r--r--arch/sparc/kernel/pcic.c2
-rw-r--r--arch/sparc/kernel/pmc.c18
-rw-r--r--arch/sparc/kernel/power.c75
-rw-r--r--arch/sparc/kernel/process_32.c (renamed from arch/sparc/kernel/process.c)2
-rw-r--r--arch/sparc/kernel/process_64.c812
-rw-r--r--arch/sparc/kernel/prom.h29
-rw-r--r--arch/sparc/kernel/prom_32.c (renamed from arch/sparc/kernel/prom.c)287
-rw-r--r--arch/sparc/kernel/prom_64.c571
-rw-r--r--arch/sparc/kernel/prom_common.c326
-rw-r--r--arch/sparc/kernel/prom_irqtrans.c842
-rw-r--r--arch/sparc/kernel/psycho_common.c470
-rw-r--r--arch/sparc/kernel/psycho_common.h48
-rw-r--r--arch/sparc/kernel/ptrace_32.c (renamed from arch/sparc/kernel/ptrace.c)0
-rw-r--r--arch/sparc/kernel/ptrace_64.c1090
-rw-r--r--arch/sparc/kernel/reboot.c53
-rw-r--r--arch/sparc/kernel/rtrap_32.S (renamed from arch/sparc/kernel/rtrap.S)0
-rw-r--r--arch/sparc/kernel/rtrap_64.S450
-rw-r--r--arch/sparc/kernel/sbus.c674
-rw-r--r--arch/sparc/kernel/setup_32.c (renamed from arch/sparc/kernel/setup.c)9
-rw-r--r--arch/sparc/kernel/setup_64.c429
-rw-r--r--arch/sparc/kernel/signal32.c899
-rw-r--r--arch/sparc/kernel/signal_32.c (renamed from arch/sparc/kernel/signal.c)0
-rw-r--r--arch/sparc/kernel/signal_64.c617
-rw-r--r--arch/sparc/kernel/smp_32.c (renamed from arch/sparc/kernel/smp.c)0
-rw-r--r--arch/sparc/kernel/smp_64.c1408
-rw-r--r--arch/sparc/kernel/sparc_ksyms_32.c (renamed from arch/sparc/kernel/sparc_ksyms.c)4
-rw-r--r--arch/sparc/kernel/sparc_ksyms_64.c284
-rw-r--r--arch/sparc/kernel/spiterrs.S245
-rw-r--r--arch/sparc/kernel/sstate.c127
-rw-r--r--arch/sparc/kernel/stacktrace.c64
-rw-r--r--arch/sparc/kernel/starfire.c116
-rw-r--r--arch/sparc/kernel/sun4c_irq.c2
-rw-r--r--arch/sparc/kernel/sun4d_irq.c3
-rw-r--r--arch/sparc/kernel/sun4m_irq.c2
-rw-r--r--arch/sparc/kernel/sun4v_ivec.S341
-rw-r--r--arch/sparc/kernel/sun4v_tlb_miss.S428
-rw-r--r--arch/sparc/kernel/sys32.S367
-rw-r--r--arch/sparc/kernel/sys_sparc32.c682
-rw-r--r--arch/sparc/kernel/sys_sparc_32.c (renamed from arch/sparc/kernel/sys_sparc.c)0
-rw-r--r--arch/sparc/kernel/sys_sparc_64.c914
-rw-r--r--arch/sparc/kernel/syscalls.S279
-rw-r--r--arch/sparc/kernel/sysfs.c314
-rw-r--r--arch/sparc/kernel/systbls.h51
-rw-r--r--arch/sparc/kernel/systbls_32.S (renamed from arch/sparc/kernel/systbls.S)0
-rw-r--r--arch/sparc/kernel/systbls_64.S159
-rw-r--r--arch/sparc/kernel/time_32.c (renamed from arch/sparc/kernel/time.c)0
-rw-r--r--arch/sparc/kernel/time_64.c862
-rw-r--r--arch/sparc/kernel/trampoline_32.S (renamed from arch/sparc/kernel/trampoline.S)0
-rw-r--r--arch/sparc/kernel/trampoline_64.S417
-rw-r--r--arch/sparc/kernel/traps_32.c (renamed from arch/sparc/kernel/traps.c)34
-rw-r--r--arch/sparc/kernel/traps_64.c2600
-rw-r--r--arch/sparc/kernel/tsb.S552
-rw-r--r--arch/sparc/kernel/ttable.S266
-rw-r--r--arch/sparc/kernel/una_asm_32.S (renamed from arch/sparc/kernel/una_asm.S)0
-rw-r--r--arch/sparc/kernel/una_asm_64.S146
-rw-r--r--arch/sparc/kernel/unaligned_32.c (renamed from arch/sparc/kernel/unaligned.c)0
-rw-r--r--arch/sparc/kernel/unaligned_64.c690
-rw-r--r--arch/sparc/kernel/us2e_cpufreq.c413
-rw-r--r--arch/sparc/kernel/us3_cpufreq.c274
-rw-r--r--arch/sparc/kernel/utrap.S29
-rw-r--r--arch/sparc/kernel/vio.c451
-rw-r--r--arch/sparc/kernel/viohs.c822
-rw-r--r--arch/sparc/kernel/visemul.c890
-rw-r--r--arch/sparc/kernel/vmlinux.lds.S109
-rw-r--r--arch/sparc/kernel/winfixup.S156
-rw-r--r--arch/sparc/lib/GENbzero.S160
-rw-r--r--arch/sparc/lib/GENcopy_from_user.S34
-rw-r--r--arch/sparc/lib/GENcopy_to_user.S38
-rw-r--r--arch/sparc/lib/GENmemcpy.S121
-rw-r--r--arch/sparc/lib/GENpage.S77
-rw-r--r--arch/sparc/lib/GENpatch.S33
-rw-r--r--arch/sparc/lib/Makefile47
-rw-r--r--arch/sparc/lib/NG2copy_from_user.S40
-rw-r--r--arch/sparc/lib/NG2copy_to_user.S49
-rw-r--r--arch/sparc/lib/NG2memcpy.S520
-rw-r--r--arch/sparc/lib/NG2page.S61
-rw-r--r--arch/sparc/lib/NG2patch.S33
-rw-r--r--arch/sparc/lib/NGbzero.S164
-rw-r--r--arch/sparc/lib/NGcopy_from_user.S37
-rw-r--r--arch/sparc/lib/NGcopy_to_user.S40
-rw-r--r--arch/sparc/lib/NGmemcpy.S425
-rw-r--r--arch/sparc/lib/NGpage.S99
-rw-r--r--arch/sparc/lib/NGpatch.S33
-rw-r--r--arch/sparc/lib/PeeCeeI.c203
-rw-r--r--arch/sparc/lib/U1copy_from_user.S33
-rw-r--r--arch/sparc/lib/U1copy_to_user.S33
-rw-r--r--arch/sparc/lib/U1memcpy.S563
-rw-r--r--arch/sparc/lib/U3copy_from_user.S22
-rw-r--r--arch/sparc/lib/U3copy_to_user.S33
-rw-r--r--arch/sparc/lib/U3memcpy.S422
-rw-r--r--arch/sparc/lib/U3patch.S33
-rw-r--r--arch/sparc/lib/VISsave.S144
-rw-r--r--arch/sparc/lib/atomic_32.S (renamed from arch/sparc/lib/atomic.S)0
-rw-r--r--arch/sparc/lib/atomic_64.S138
-rw-r--r--arch/sparc/lib/bitops.S141
-rw-r--r--arch/sparc/lib/bzero.S158
-rw-r--r--arch/sparc/lib/checksum_32.S (renamed from arch/sparc/lib/checksum.S)0
-rw-r--r--arch/sparc/lib/checksum_64.S173
-rw-r--r--arch/sparc/lib/clear_page.S103
-rw-r--r--arch/sparc/lib/copy_in_user.S119
-rw-r--r--arch/sparc/lib/copy_page.S250
-rw-r--r--arch/sparc/lib/csum_copy.S309
-rw-r--r--arch/sparc/lib/csum_copy_from_user.S21
-rw-r--r--arch/sparc/lib/csum_copy_to_user.S21
-rw-r--r--arch/sparc/lib/ipcsum.S34
-rw-r--r--arch/sparc/lib/mcount.S143
-rw-r--r--arch/sparc/lib/memcmp.S329
-rw-r--r--arch/sparc/lib/memmove.S31
-rw-r--r--arch/sparc/lib/memscan_32.S (renamed from arch/sparc/lib/memscan.S)0
-rw-r--r--arch/sparc/lib/memscan_64.S129
-rw-r--r--arch/sparc/lib/rwsem_32.S (renamed from arch/sparc/lib/rwsem.S)0
-rw-r--r--arch/sparc/lib/rwsem_64.S163
-rw-r--r--arch/sparc/lib/strlen.S79
-rw-r--r--arch/sparc/lib/strlen_user_32.S (renamed from arch/sparc/lib/strlen_user.S)0
-rw-r--r--arch/sparc/lib/strlen_user_64.S95
-rw-r--r--arch/sparc/lib/strncmp_32.S (renamed from arch/sparc/lib/strncmp.S)0
-rw-r--r--arch/sparc/lib/strncmp_64.S32
-rw-r--r--arch/sparc/lib/strncpy_from_user_32.S (renamed from arch/sparc/lib/strncpy_from_user.S)0
-rw-r--r--arch/sparc/lib/strncpy_from_user_64.S135
-rw-r--r--arch/sparc/lib/user_fixup.c66
-rw-r--r--arch/sparc/lib/xor.S652
-rw-r--r--arch/sparc/math-emu/Makefile6
-rw-r--r--arch/sparc/math-emu/ashldi3.S36
-rw-r--r--arch/sparc/math-emu/math_32.c (renamed from arch/sparc/math-emu/math.c)2
-rw-r--r--arch/sparc/math-emu/math_64.c513
-rw-r--r--arch/sparc/math-emu/sfp-util_32.h (renamed from arch/sparc/math-emu/sfp-util.h)0
-rw-r--r--arch/sparc/math-emu/sfp-util_64.h120
-rw-r--r--arch/sparc/mm/Makefile24
-rw-r--r--arch/sparc/mm/fault_32.c (renamed from arch/sparc/mm/fault.c)0
-rw-r--r--arch/sparc/mm/fault_64.c440
-rw-r--r--arch/sparc/mm/generic_32.c (renamed from arch/sparc/mm/generic.c)0
-rw-r--r--arch/sparc/mm/generic_64.c163
-rw-r--r--arch/sparc/mm/hugetlbpage.c357
-rw-r--r--arch/sparc/mm/init_32.c (renamed from arch/sparc/mm/init.c)14
-rw-r--r--arch/sparc/mm/init_64.c2360
-rw-r--r--arch/sparc/mm/init_64.h49
-rw-r--r--arch/sparc/mm/io-unit.c8
-rw-r--r--arch/sparc/mm/iommu.c16
-rw-r--r--arch/sparc/mm/srmmu.c25
-rw-r--r--arch/sparc/mm/sun4c.c12
-rw-r--r--arch/sparc/mm/tlb.c97
-rw-r--r--arch/sparc/mm/tsb.c503
-rw-r--r--arch/sparc/mm/ultra.S767
-rw-r--r--arch/sparc/oprofile/init.c229
-rw-r--r--arch/sparc/prom/Makefile19
-rw-r--r--arch/sparc/prom/bootstr_32.c (renamed from arch/sparc/prom/bootstr.c)0
-rw-r--r--arch/sparc/prom/bootstr_64.c40
-rw-r--r--arch/sparc/prom/cif.S48
-rw-r--r--arch/sparc/prom/console_32.c (renamed from arch/sparc/prom/console.c)0
-rw-r--r--arch/sparc/prom/console_64.c74
-rw-r--r--arch/sparc/prom/devops_32.c (renamed from arch/sparc/prom/devops.c)0
-rw-r--r--arch/sparc/prom/devops_64.c41
-rw-r--r--arch/sparc/prom/init_32.c (renamed from arch/sparc/prom/init.c)0
-rw-r--r--arch/sparc/prom/init_64.c57
-rw-r--r--arch/sparc/prom/misc_32.c (renamed from arch/sparc/prom/misc.c)2
-rw-r--r--arch/sparc/prom/misc_64.c335
-rw-r--r--arch/sparc/prom/p1275.c151
-rw-r--r--arch/sparc/prom/printf.c5
-rw-r--r--arch/sparc/prom/tree_32.c (renamed from arch/sparc/prom/tree.c)6
-rw-r--r--arch/sparc/prom/tree_64.c299
262 files changed, 59813 insertions, 2157 deletions
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index e594559c8dba..0a94d9c9cde1 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -4,21 +4,116 @@
mainmenu "Linux/SPARC Kernel Configuration"
+config SPARC
+ bool
+ default y
+ select HAVE_IDE
+ select HAVE_OPROFILE
+ select HAVE_ARCH_KGDB if !SMP || SPARC64
+ select HAVE_ARCH_TRACEHOOK
+ select ARCH_WANT_OPTIONAL_GPIOLIB
+ select RTC_CLASS
+ select RTC_DRV_M48T59
+
+# Identify this as a Sparc32 build
+config SPARC32
+ bool
+ default y if ARCH = "sparc"
+ help
+ SPARC is a family of RISC microprocessors designed and marketed by
+ Sun Microsystems, incorporated. They are very widely found in Sun
+ workstations and clones. This port covers the original 32-bit SPARC;
+ it is old and stable and usually considered one of the "big three"
+ along with the Intel and Alpha ports. The UltraLinux project
+ maintains both the SPARC32 and SPARC64 ports; its web page is
+ available at <http://www.ultralinux.org/>.
+
+config SPARC64
+ bool
+ default y if ARCH = "sparc64"
+ select ARCH_SUPPORTS_MSI
+ select HAVE_FUNCTION_TRACER
+ select HAVE_KRETPROBES
+ select HAVE_KPROBES
+ select HAVE_LMB
+ select USE_GENERIC_SMP_HELPERS if SMP
+ select RTC_DRV_CMOS
+ select RTC_DRV_BQ4802
+ select RTC_DRV_SUN4V
+ select RTC_DRV_STARFIRE
+
+config ARCH_DEFCONFIG
+ string
+ default "arch/sparc/configs/sparc32_defconfig" if SPARC32
+ default "arch/sparc/configs/sparc64_defconfig" if SPARC64
+
+# CONFIG_BITS can be used at source level to get 32/64 bits
+config BITS
+ int
+ default 32 if SPARC32
+ default 64 if SPARC64
+
+config 64BIT
+ def_bool y if SPARC64
+
+config GENERIC_TIME
+ bool
+ default y if SPARC64
+
+config GENERIC_CMOS_UPDATE
+ bool
+ default y if SPARC64
+
+config GENERIC_CLOCKEVENTS
+ bool
+ default y if SPARC64
+
+config IOMMU_HELPER
+ bool
+ default y if SPARC64
+
+config QUICKLIST
+ bool
+ default y if SPARC64
+
+config STACKTRACE_SUPPORT
+ bool
+ default y if SPARC64
+
+config LOCKDEP_SUPPORT
+ bool
+ default y if SPARC64
+
+config HAVE_LATENCYTOP_SUPPORT
+ bool
+ default y if SPARC64
+
+config AUDIT_ARCH
+ bool
+ default y
+
+config HAVE_SETUP_PER_CPU_AREA
+ def_bool y if SPARC64
+
+config GENERIC_HARDIRQS_NO__DO_IRQ
+ bool
+ def_bool y if SPARC64
+
config MMU
bool
default y
config HIGHMEM
bool
- default y
+ default y if SPARC32
config ZONE_DMA
bool
- default y
+ default y if SPARC32
config GENERIC_ISA_DMA
bool
- default y
+ default y if SPARC32
config GENERIC_GPIO
bool
@@ -31,15 +126,11 @@ config ARCH_NO_VIRT_TO_BUS
config OF
def_bool y
-config HZ
- int
- default 100
-
source "init/Kconfig"
source "kernel/Kconfig.freezer"
-menu "General machine setup"
+menu "Processor type and features"
config SMP
bool "Symmetric multi-processing support (does not work on sun4/sun4c)"
@@ -64,82 +155,269 @@ config SMP
If you don't know what to do here, say N.
config NR_CPUS
- int "Maximum number of CPUs (2-32)"
- range 2 32
+ int "Maximum number of CPUs"
depends on SMP
- default "32"
+ range 2 32 if SPARC32
+ range 2 1024 if SPARC64
+ default 32 if SPARC32
+ default 64 if SPARC64
-config SPARC
+source kernel/Kconfig.hz
+
+config RWSEM_GENERIC_SPINLOCK
+ bool
+ default y if SPARC32
+
+config RWSEM_XCHGADD_ALGORITHM
+ bool
+ default y if SPARC64
+
+config GENERIC_FIND_NEXT_BIT
bool
default y
- select HAVE_IDE
- select HAVE_OPROFILE
- select HAVE_ARCH_KGDB if !SMP
- select HAVE_ARCH_TRACEHOOK
- select ARCH_WANT_OPTIONAL_GPIOLIB
- select RTC_CLASS
- select RTC_DRV_M48T59
-# Identify this as a Sparc32 build
-config SPARC32
+config GENERIC_HWEIGHT
+ bool
+ default y if !ULTRA_HAS_POPULATION_COUNT
+
+config GENERIC_CALIBRATE_DELAY
bool
default y
- help
- SPARC is a family of RISC microprocessors designed and marketed by
- Sun Microsystems, incorporated. They are very widely found in Sun
- workstations and clones. This port covers the original 32-bit SPARC;
- it is old and stable and usually considered one of the "big three"
- along with the Intel and Alpha ports. The UltraLinux project
- maintains both the SPARC32 and SPARC64 ports; its web page is
- available at <http://www.ultralinux.org/>.
-# Global things across all Sun machines.
-config ISA
+config ARCH_MAY_HAVE_PC_FDC
bool
- help
- ISA is found on Espresso only and is not supported currently.
- Say N
+ default y
-config EISA
+config ARCH_HAS_ILOG2_U32
bool
+ default n
+
+config ARCH_HAS_ILOG2_U64
+ bool
+ default n
+
+config EMULATED_CMPXCHG
+ bool
+ default y if SPARC32
help
- EISA is not supported.
- Say N
+ Sparc32 does not have a CAS instruction like sparc64. cmpxchg()
+ is emulated, and therefore it is not completely atomic.
-config MCA
+# Makefile helpers
+config SPARC32_SMP
+ bool
+ default y
+ depends on SPARC32 && SMP
+
+config SPARC64_SMP
bool
+ default y
+ depends on SPARC64 && SMP
+
+choice
+ prompt "Kernel page size" if SPARC64
+ default SPARC64_PAGE_SIZE_8KB
+
+config SPARC64_PAGE_SIZE_8KB
+ bool "8KB"
help
- MCA is not supported.
- Say N
+ This lets you select the page size of the kernel.
-config PCMCIA
- tristate
- ---help---
- Say Y here if you want to attach PCMCIA- or PC-cards to your Linux
- computer. These are credit-card size devices such as network cards,
- modems or hard drives often used with laptops computers. There are
- actually two varieties of these cards: the older 16 bit PCMCIA cards
- and the newer 32 bit CardBus cards. If you want to use CardBus
- cards, you need to say Y here and also to "CardBus support" below.
+ 8KB and 64KB work quite well, since SPARC ELF sections
+ provide for up to 64KB alignment.
- To use your PC-cards, you will need supporting software from David
- Hinds' pcmcia-cs package (see the file <file:Documentation/Changes>
- for location). Please also read the PCMCIA-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ If you don't know what to do, choose 8KB.
- To compile this driver as modules, choose M here: the
- modules will be called pcmcia_core and ds.
+config SPARC64_PAGE_SIZE_64KB
+ bool "64KB"
-config SBUS
+endchoice
+
+config SECCOMP
+ bool "Enable seccomp to safely compute untrusted bytecode"
+ depends on SPARC64 && PROC_FS
+ default y
+ help
+ This kernel feature is useful for number crunching applications
+ that may need to compute untrusted bytecode during their
+ execution. By using pipes or other transports made available to
+ the process as file descriptors supporting the read/write
+ syscalls, it's possible to isolate those applications in
+ their own address space using seccomp. Once seccomp is
+ enabled via /proc/<pid>/seccomp, it cannot be disabled
+ and the task is only allowed to execute a few safe syscalls
+ defined by each seccomp mode.
+
+ If unsure, say Y. Only embedded should say N here.
+
+config HOTPLUG_CPU
+ bool "Support for hot-pluggable CPUs"
+ depends on SPARC64 && SMP
+ select HOTPLUG
+ help
+ Say Y here to experiment with turning CPUs off and on. CPUs
+ can be controlled through /sys/devices/system/cpu/cpu#.
+ Say N if you want to disable CPU hotplug.
+
+config GENERIC_HARDIRQS
bool
+ default y if SPARC64
+
+source "kernel/time/Kconfig"
+
+if SPARC64
+source "drivers/cpufreq/Kconfig"
+
+config US3_FREQ
+ tristate "UltraSPARC-III CPU Frequency driver"
+ depends on CPU_FREQ
+ select CPU_FREQ_TABLE
+ help
+ This adds the CPUFreq driver for UltraSPARC-III processors.
+
+ For details, take a look at <file:Documentation/cpu-freq>.
+
+ If in doubt, say N.
+
+config US2E_FREQ
+ tristate "UltraSPARC-IIe CPU Frequency driver"
+ depends on CPU_FREQ
+ select CPU_FREQ_TABLE
+ help
+ This adds the CPUFreq driver for UltraSPARC-IIe processors.
+
+ For details, take a look at <file:Documentation/cpu-freq>.
+
+ If in doubt, say N.
+
+endif
+
+config US3_MC
+ tristate "UltraSPARC-III Memory Controller driver"
+ depends on SPARC64
default y
+ help
+ This adds a driver for the UltraSPARC-III memory controller.
+ Loading this driver allows exact mnemonic strings to be
+ printed in the event of a memory error, so that the faulty DIMM
+ on the motherboard can be matched to the error.
-config SBUSCHAR
+ If in doubt, say Y, as this information can be very useful.
+
+# Global things across all Sun machines.
+config GENERIC_LOCKBREAK
bool
default y
+ depends on SPARC64 && SMP && PREEMPT
+
+choice
+ prompt "SPARC64 Huge TLB Page Size"
+ depends on SPARC64 && HUGETLB_PAGE
+ default HUGETLB_PAGE_SIZE_4MB
+
+config HUGETLB_PAGE_SIZE_4MB
+ bool "4MB"
+
+config HUGETLB_PAGE_SIZE_512K
+ bool "512K"
+
+config HUGETLB_PAGE_SIZE_64K
+ depends on !SPARC64_PAGE_SIZE_64KB
+ bool "64K"
+
+endchoice
+
+config NUMA
+ bool "NUMA support"
+ depends on SPARC64 && SMP
+
+config NODES_SHIFT
+ int
+ default "4"
+ depends on NEED_MULTIPLE_NODES
+
+# Some NUMA nodes have memory ranges that span
+# other nodes. Even though a pfn is valid and
+# between a node's start and end pfns, it may not
+# reside on that node. See memmap_init_zone()
+# for details.
+config NODES_SPAN_OTHER_NODES
+ def_bool y
+ depends on NEED_MULTIPLE_NODES
+
+config ARCH_POPULATES_NODE_MAP
+ def_bool y if SPARC64
+
+config ARCH_SELECT_MEMORY_MODEL
+ def_bool y if SPARC64
+
+config ARCH_SPARSEMEM_ENABLE
+ def_bool y if SPARC64
+ select SPARSEMEM_VMEMMAP_ENABLE
+
+config ARCH_SPARSEMEM_DEFAULT
+ def_bool y if SPARC64
+
+source "mm/Kconfig"
+
+config SCHED_SMT
+ bool "SMT (Hyperthreading) scheduler support"
+ depends on SPARC64 && SMP
+ default y
+ help
+ SMT scheduler support improves the CPU scheduler's decision making
+ when dealing with SPARC cpus at a cost of slightly increased overhead
+ in some places. If unsure say N here.
+
+config SCHED_MC
+ bool "Multi-core scheduler support"
+ depends on SPARC64 && SMP
+ default y
+ 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.
+
+if SPARC64
+source "kernel/Kconfig.preempt"
+endif
+
+config CMDLINE_BOOL
+ bool "Default bootloader kernel arguments"
+ depends on SPARC64
+
+config CMDLINE
+ string "Initial kernel command string"
+ depends on CMDLINE_BOOL
+ default "console=ttyS0,9600 root=/dev/sda1"
+ help
+ Say Y here if you want to be able to pass default arguments to
+ the kernel. This will be overridden by the bootloader, if you
+ use one (such as SILO). This is most useful if you want to boot
+ a kernel from TFTP, and want default options to be available
+ with having them passed on the command line.
+
+ NOTE: This option WILL override the PROM bootargs setting!
+
+config SUN_PM
+ bool
+ default y if SPARC32
+ help
+ Enable power management and CPU standby features on supported
+ SPARC platforms.
+
+config SPARC_LED
+ tristate "Sun4m LED driver"
+ depends on SPARC32
+ help
+ This driver toggles the front-panel LED on sun4m systems
+ in a user-specifiable manner. Its state can be probed
+ by reading /proc/led and its blinking mode can be changed
+ via writes to /proc/led
config SERIAL_CONSOLE
bool
+ depends on SPARC32
default y
---help---
If you say Y here, it will be possible to use a serial port as the
@@ -161,71 +439,66 @@ config SERIAL_CONSOLE
If unsure, say N.
-config SUN_AUXIO
- bool
- default y
-
-config SUN_IO
- bool
- default y
-
-config RWSEM_GENERIC_SPINLOCK
- bool
- default y
+endmenu
-config RWSEM_XCHGADD_ALGORITHM
+menu "Bus options (PCI etc.)"
+config ISA
bool
+ help
+ ISA is found on Espresso only and is not supported currently.
-config GENERIC_FIND_NEXT_BIT
+config ISAPNP
bool
- default y
+ help
+ ISAPNP is not supported
-config GENERIC_HWEIGHT
+config EISA
bool
- default y
+ help
+ EISA is not supported.
-config GENERIC_CALIBRATE_DELAY
+config MCA
bool
- default y
+ help
+ MCA is not supported.
-config ARCH_MAY_HAVE_PC_FDC
+config SBUS
bool
default y
-config ARCH_HAS_ILOG2_U32
- bool
- default n
-
-config ARCH_HAS_ILOG2_U64
- bool
- default n
-
-config EMULATED_CMPXCHG
+config SBUSCHAR
bool
default y
- help
- Sparc32 does not have a CAS instruction like sparc64. cmpxchg()
- is emulated, and therefore it is not completely atomic.
-config SUN_PM
- bool
- default y
+config SUN_LDOMS
+ bool "Sun Logical Domains support"
+ depends on SPARC64
help
- Enable power management and CPU standby features on supported
- SPARC platforms.
+ Say Y here is you want to support virtual devices via
+ Logical Domains.
config PCI
bool "Support for PCI and PS/2 keyboard/mouse"
help
+ Find out whether your system includes a PCI bus. PCI is the name of
+ a bus system, i.e. the way the CPU talks to the other stuff inside
+ your box. If you say Y here, the kernel will include drivers and
+ infrastructure code to support PCI bus devices.
+
CONFIG_PCI is needed for all JavaStation's (including MrCoffee),
CP-1200, JavaEngine-1, Corona, Red October, and Serengeti SGSC.
All of these platforms are extremely obscure, so say N if unsure.
+config PCI_DOMAINS
+ def_bool PCI if SPARC64
+
config PCI_SYSCALL
def_bool PCI
source "drivers/pci/Kconfig"
+source "drivers/pcmcia/Kconfig"
+
config SUN_OPENPROMFS
tristate "Openprom tree appears in /proc/openprom"
help
@@ -239,17 +512,33 @@ config SUN_OPENPROMFS
Only choose N if you know in advance that you will not need to modify
OpenPROM settings on the running system.
-config SPARC_LED
- tristate "Sun4m LED driver"
- help
- This driver toggles the front-panel LED on sun4m systems
- in a user-specifiable manner. Its state can be probed
- by reading /proc/led and its blinking mode can be changed
- via writes to /proc/led
+# Makefile helpers
+config SPARC32_PCI
+ bool
+ default y
+ depends on SPARC32 && PCI
+
+config SPARC64_PCI
+ bool
+ default y
+ depends on SPARC64 && PCI
+
+endmenu
+
+menu "Executable file formats"
source "fs/Kconfig.binfmt"
-source "mm/Kconfig"
+config COMPAT
+ bool
+ depends on SPARC64
+ default y
+ select COMPAT_BINFMT_ELF
+
+config SYSVIPC_COMPAT
+ bool
+ depends on COMPAT && SYSVIPC
+ default y
endmenu
@@ -259,40 +548,6 @@ source "drivers/Kconfig"
source "drivers/sbus/char/Kconfig"
-# This one must be before the filesystem configs. -DaveM
-
-menu "Unix98 PTY support"
-
-config UNIX98_PTYS
- bool "Unix98 PTY support"
- ---help---
- A pseudo terminal (PTY) is a software device consisting of two
- halves: a master and a slave. The slave device behaves identical to
- a physical terminal; the master device is used by a process to
- read data from and write data to the slave, thereby emulating a
- terminal. Typical programs for the master side are telnet servers
- and xterms.
-
- Linux has traditionally used the BSD-like names /dev/ptyxx for
- masters and /dev/ttyxx for slaves of pseudo terminals. This scheme
- has a number of problems. The GNU C library glibc 2.1 and later,
- however, supports the Unix98 naming standard: in order to acquire a
- pseudo terminal, a process opens /dev/ptmx; the number of the pseudo
- terminal is then made available to the process and the pseudo
- terminal slave can be accessed as /dev/pts/<number>. What was
- traditionally /dev/ttyp2 will then be /dev/pts/2, for example.
-
- The entries in /dev/pts/ are created on the fly by a virtual
- file system; therefore, if you say Y here you should say Y to
- "/dev/pts file system for Unix98 PTYs" as well.
-
- If you want to say Y here, you need to have the C library glibc 2.1
- or later (equal to libc-6.1, check with "ls -l /lib/libc.so.*").
- Read the instructions in <file:Documentation/Changes> pertaining to
- pseudo terminals. It's safe to say N.
-
-endmenu
-
source "fs/Kconfig"
source "arch/sparc/Kconfig.debug"
diff --git a/arch/sparc/Kconfig.debug b/arch/sparc/Kconfig.debug
index 87dd496f15eb..b8a15e271bfa 100644
--- a/arch/sparc/Kconfig.debug
+++ b/arch/sparc/Kconfig.debug
@@ -15,4 +15,30 @@ config DEBUG_STACK_USAGE
This option will slow down process creation somewhat.
+config DEBUG_DCFLUSH
+ bool "D-cache flush debugging"
+ depends on SPARC64 && DEBUG_KERNEL
+
+config STACK_DEBUG
+ bool "Stack Overflow Detection Support"
+
+config DEBUG_PAGEALLOC
+ bool "Debug page memory allocations"
+ depends on SPARC64 && DEBUG_KERNEL && !HIBERNATION
+ help
+ Unmap pages from the kernel linear mapping after free_pages().
+ This results in a large slowdown, but helps to find certain types
+ of memory corruptions.
+
+config MCOUNT
+ bool
+ depends on SPARC64
+ depends on STACK_DEBUG || FUNCTION_TRACER
+ default y
+
+config FRAME_POINTER
+ bool
+ depends on MCOUNT
+ default y
+
endmenu
diff --git a/arch/sparc/Makefile b/arch/sparc/Makefile
index 9592889a6fd0..2003ded054c2 100644
--- a/arch/sparc/Makefile
+++ b/arch/sparc/Makefile
@@ -2,18 +2,31 @@
# sparc/Makefile
#
# Makefile for the architecture dependent flags and dependencies on the
-# Sparc.
+# Sparc and sparc64.
#
-# Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
+# Copyright (C) 1994,1996,1998 David S. Miller (davem@caip.rutgers.edu)
+# Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz)
+
+# We are not yet configured - so test on arch
+ifeq ($(ARCH),sparc)
+ KBUILD_DEFCONFIG := sparc32_defconfig
+else
+ KBUILD_DEFCONFIG := sparc64_defconfig
+endif
+
+ifeq ($(CONFIG_SPARC32),y)
+#####
+# sparc32
#
#
# Uncomment the first KBUILD_CFLAGS if you are doing kgdb source level
# debugging of the kernel to get the proper debugging information.
-AS := $(AS) -32
-LDFLAGS := -m elf32_sparc
-CHECKFLAGS += -D__sparc__
+AS := $(AS) -32
+LDFLAGS := -m elf32_sparc
+CHECKFLAGS += -D__sparc__
+export BITS := 32
#KBUILD_CFLAGS += -g -pipe -fcall-used-g5 -fcall-used-g7
KBUILD_CFLAGS += -m32 -pipe -mno-fpu -fcall-used-g5 -fcall-used-g7
@@ -25,38 +38,60 @@ CPPFLAGS_vmlinux.lds += -m32
# Actual linking is done with "make image".
LDFLAGS_vmlinux = -r
-head-y := arch/sparc/kernel/head.o arch/sparc/kernel/init_task.o
-HEAD_Y := $(head-y)
+# Default target
+all: zImage
+
+
+else
+#####
+# sparc64
+#
-core-y += arch/sparc/kernel/ arch/sparc/mm/ arch/sparc/math-emu/
-libs-y += arch/sparc/prom/ arch/sparc/lib/
+CHECKFLAGS += -D__sparc__ -D__sparc_v9__ -D__arch64__ -m64
+
+# Undefine sparc when processing vmlinux.lds - it is used
+# And teach CPP we are doing 64 bit builds (for this case)
+CPPFLAGS_vmlinux.lds += -m64 -Usparc
+LDFLAGS := -m elf64_sparc
+export BITS := 64
+
+KBUILD_CFLAGS += -m64 -pipe -mno-fpu -mcpu=ultrasparc -mcmodel=medlow \
+ -ffixed-g4 -ffixed-g5 -fcall-used-g7 -Wno-sign-compare \
+ -Wa,--undeclared-regs
+KBUILD_CFLAGS += $(call cc-option,-mtune=ultrasparc3)
+KBUILD_AFLAGS += -m64 -mcpu=ultrasparc -Wa,--undeclared-regs
+
+ifeq ($(CONFIG_MCOUNT),y)
+ KBUILD_CFLAGS += -pg
+endif
+
+endif
+
+head-y := arch/sparc/kernel/head_$(BITS).o
+head-y += arch/sparc/kernel/init_task.o
+
+core-y += arch/sparc/kernel/
+core-y += arch/sparc/mm/ arch/sparc/math-emu/
+
+libs-y += arch/sparc/prom/
+libs-y += arch/sparc/lib/
drivers-$(CONFIG_OPROFILE) += arch/sparc/oprofile/
# Export what is needed by arch/sparc/boot/Makefile
-# Renaming is done to avoid confusing pattern matching rules in 2.5.45 (multy-)
-INIT_Y := $(patsubst %/, %/built-in.o, $(init-y))
-CORE_Y := $(core-y)
-CORE_Y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/
-CORE_Y := $(patsubst %/, %/built-in.o, $(CORE_Y))
-DRIVERS_Y := $(patsubst %/, %/built-in.o, $(drivers-y))
-NET_Y := $(patsubst %/, %/built-in.o, $(net-y))
-LIBS_Y1 := $(patsubst %/, %/lib.a, $(libs-y))
-LIBS_Y2 := $(patsubst %/, %/built-in.o, $(libs-y))
-LIBS_Y := $(LIBS_Y1) $(LIBS_Y2)
+export VMLINUX_INIT VMLINUX_MAIN
+VMLINUX_INIT := $(head-y) $(init-y)
+VMLINUX_MAIN := $(core-y) kernel/ mm/ fs/ ipc/ security/ crypto/ block/
+VMLINUX_MAIN += $(patsubst %/, %/lib.a, $(libs-y)) $(libs-y)
+VMLINUX_MAIN += $(drivers-y) $(net-y)
ifdef CONFIG_KALLSYMS
-kallsyms.o := .tmp_kallsyms2.o
+export kallsyms.o := .tmp_kallsyms2.o
endif
-export INIT_Y CORE_Y DRIVERS_Y NET_Y LIBS_Y HEAD_Y kallsyms.o
-
-# Default target
-all: zImage
-
boot := arch/sparc/boot
-image zImage tftpboot.img: vmlinux
+image zImage tftpboot.img vmlinux.aout: vmlinux
$(Q)$(MAKE) $(build)=$(boot) $(boot)/$@
archclean:
@@ -65,11 +100,17 @@ archclean:
# This is the image used for packaging
KBUILD_IMAGE := $(boot)/zImage
-CLEAN_FILES += arch/$(ARCH)/boot/System.map
-
# Don't use tabs in echo arguments.
+ifeq ($(ARCH),sparc)
define archhelp
echo '* image - kernel image ($(boot)/image)'
echo '* zImage - stripped kernel image ($(boot)/zImage)'
echo ' tftpboot.img - image prepared for tftp'
endef
+else
+define archhelp
+ echo '* vmlinux - Standard sparc64 kernel'
+ echo ' vmlinux.aout - a.out kernel for sparc64'
+ echo ' tftpboot.img - image prepared for tftp'
+endef
+endif
diff --git a/arch/sparc/boot/.gitignore b/arch/sparc/boot/.gitignore
new file mode 100644
index 000000000000..fc6f3986c76c
--- /dev/null
+++ b/arch/sparc/boot/.gitignore
@@ -0,0 +1,8 @@
+btfix.S
+btfixupprep
+image
+zImage
+tftpboot.img
+vmlinux.aout
+piggyback
+
diff --git a/arch/sparc/boot/Makefile b/arch/sparc/boot/Makefile
index 3e77a9f52248..96041a8d39e8 100644
--- a/arch/sparc/boot/Makefile
+++ b/arch/sparc/boot/Makefile
@@ -6,13 +6,16 @@
ROOT_IMG := /usr/src/root.img
ELFTOAOUT := elftoaout
-hostprogs-y := piggyback btfixupprep
-targets := tftpboot.img btfix.o btfix.S image
+hostprogs-y := piggyback_32 piggyback_64 btfixupprep
+targets := tftpboot.img btfix.o btfix.S image zImage vmlinux.aout
+clean-files := System.map
quiet_cmd_elftoaout = ELFTOAOUT $@
cmd_elftoaout = $(ELFTOAOUT) $(obj)/image -o $@
+
+ifeq ($(CONFIG_SPARC32),y)
quiet_cmd_piggy = PIGGY $@
- cmd_piggy = $(obj)/piggyback $@ $(obj)/System.map $(ROOT_IMG)
+ cmd_piggy = $(obj)/piggyback_32 $@ $(obj)/System.map $(ROOT_IMG)
quiet_cmd_btfix = BTFIX $@
cmd_btfix = $(OBJDUMP) -x vmlinux | $(obj)/btfixupprep > $@
quiet_cmd_sysmap = SYSMAP $(obj)/System.map
@@ -37,8 +40,8 @@ define rule_image
echo 'cmd_$@ := $(cmd_image)' > $(@D)/.$(@F).cmd
endef
-BTOBJS := $(HEAD_Y) $(INIT_Y)
-BTLIBS := $(CORE_Y) $(LIBS_Y) $(DRIVERS_Y) $(NET_Y)
+BTOBJS := $(patsubst %/, %/built-in.o, $(VMLINUX_INIT))
+BTLIBS := $(patsubst %/, %/built-in.o, $(VMLINUX_MAIN))
LDFLAGS_image := -T arch/sparc/kernel/vmlinux.lds $(BTOBJS) \
--start-group $(BTLIBS) --end-group \
$(kallsyms.o) $(obj)/btfix.o
@@ -61,3 +64,28 @@ $(obj)/tftpboot.img: $(obj)/piggyback $(obj)/System.map $(obj)/image FORCE
$(obj)/btfix.S: $(obj)/btfixupprep vmlinux FORCE
$(call if_changed,btfix)
+
+endif
+
+ifeq ($(CONFIG_SPARC64),y)
+quiet_cmd_piggy = PIGGY $@
+ cmd_piggy = $(obj)/piggyback_64 $@ System.map $(ROOT_IMG)
+quiet_cmd_strip = STRIP $@
+ cmd_strip = $(STRIP) -R .comment -R .note -K sun4u_init -K _end -K _start vmlinux -o $@
+
+
+# Actual linking
+$(obj)/image: vmlinux FORCE
+ $(call if_changed,strip)
+ @echo ' kernel: $@ is ready'
+
+$(obj)/tftpboot.img: vmlinux $(obj)/piggyback_64 System.map $(ROOT_IMG) FORCE
+ $(call if_changed,elftoaout)
+ $(call if_changed,piggy)
+ @echo ' kernel: $@ is ready'
+
+$(obj)/vmlinux.aout: vmlinux FORCE
+ $(call if_changed,elftoaout)
+ @echo ' kernel: $@ is ready'
+endif
+
diff --git a/arch/sparc/boot/piggyback.c b/arch/sparc/boot/piggyback_32.c
index c9f500c1a8b2..c9f500c1a8b2 100644
--- a/arch/sparc/boot/piggyback.c
+++ b/arch/sparc/boot/piggyback_32.c
diff --git a/arch/sparc/boot/piggyback_64.c b/arch/sparc/boot/piggyback_64.c
new file mode 100644
index 000000000000..de364bfed0bb
--- /dev/null
+++ b/arch/sparc/boot/piggyback_64.c
@@ -0,0 +1,109 @@
+/*
+ Simple utility to make a single-image install kernel with initial ramdisk
+ for Sparc64 tftpbooting without need to set up nfs.
+
+ Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+/* Note: run this on an a.out kernel (use elftoaout for it), as PROM looks for a.out image onlly
+ usage: piggyback vmlinux System.map tail, where tail is gzipped fs of the initial ramdisk */
+
+void die(char *str)
+{
+ perror (str);
+ exit(1);
+}
+
+int main(int argc,char **argv)
+{
+ char buffer [1024], *q, *r;
+ unsigned int i, j, k, start, end, offset;
+ FILE *map;
+ struct stat s;
+ int image, tail;
+
+ if (stat (argv[3], &s) < 0) die (argv[3]);
+ map = fopen (argv[2], "r");
+ if (!map) die(argv[2]);
+ while (fgets (buffer, 1024, map)) {
+ if (!strcmp (buffer + 19, "_start\n"))
+ start = strtoul (buffer + 8, NULL, 16);
+ else if (!strcmp (buffer + 19, "_end\n"))
+ end = strtoul (buffer + 8, NULL, 16);
+ }
+ fclose (map);
+ if ((image = open(argv[1],O_RDWR)) < 0) die(argv[1]);
+ if (read(image,buffer,512) != 512) die(argv[1]);
+ if (!memcmp (buffer, "\177ELF", 4)) {
+ unsigned int *p = (unsigned int *)(buffer + *(unsigned int *)(buffer + 28));
+
+ i = p[1] + *(unsigned int *)(buffer + 24) - p[2];
+ if (lseek(image,i,0) < 0) die("lseek");
+ if (read(image,buffer,512) != 512) die(argv[1]);
+ j = 0;
+ } else if (*(unsigned int *)buffer == 0x01030107) {
+ i = j = 32;
+ } else {
+ fprintf (stderr, "Not ELF nor a.out. Don't blame me.\n");
+ exit(1);
+ }
+ k = i;
+ if (j == 32 && buffer[40] == 'H' && buffer[41] == 'd' && buffer[42] == 'r' && buffer[43] == 'S') {
+ offset = 40 + 10;
+ } else {
+ i += ((*(unsigned short *)(buffer + j + 2))<<2) - 512;
+ if (lseek(image,i,0) < 0) die("lseek");
+ if (read(image,buffer,1024) != 1024) die(argv[1]);
+ for (q = buffer, r = q + 512; q < r; q += 4) {
+ if (*q == 'H' && q[1] == 'd' && q[2] == 'r' && q[3] == 'S')
+ break;
+ }
+ if (q == r) {
+ fprintf (stderr, "Couldn't find headers signature in the kernel.\n");
+ exit(1);
+ }
+ offset = i + (q - buffer) + 10;
+ }
+ if (lseek(image, offset, 0) < 0) die ("lseek");
+ *(unsigned *)buffer = 0;
+ *(unsigned *)(buffer + 4) = 0x01000000;
+ *(unsigned *)(buffer + 8) = ((end + 32 + 8191) & ~8191);
+ *(unsigned *)(buffer + 12) = s.st_size;
+ if (write(image,buffer+2,14) != 14) die (argv[1]);
+ if (lseek(image, 4, 0) < 0) die ("lseek");
+ *(unsigned *)buffer = ((end + 32 + 8191) & ~8191) - (start & ~0x3fffffUL) + s.st_size;
+ *(unsigned *)(buffer + 4) = 0;
+ *(unsigned *)(buffer + 8) = 0;
+ if (write(image,buffer,12) != 12) die (argv[1]);
+ if (lseek(image, k - start + ((end + 32 + 8191) & ~8191), 0) < 0) die ("lseek");
+ if ((tail = open(argv[3],O_RDONLY)) < 0) die(argv[3]);
+ while ((i = read (tail,buffer,1024)) > 0)
+ if (write(image,buffer,i) != i) die (argv[1]);
+ if (close(image) < 0) die("close");
+ if (close(tail) < 0) die("close");
+ return 0;
+}
diff --git a/arch/sparc/defconfig b/arch/sparc/configs/sparc32_defconfig
index 2e3a149ea0e7..2e3a149ea0e7 100644
--- a/arch/sparc/defconfig
+++ b/arch/sparc/configs/sparc32_defconfig
diff --git a/arch/sparc/configs/sparc64_defconfig b/arch/sparc/configs/sparc64_defconfig
new file mode 100644
index 000000000000..05d19a3e590f
--- /dev/null
+++ b/arch/sparc/configs/sparc64_defconfig
@@ -0,0 +1,1705 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.28-rc4
+# Mon Nov 10 12:35:09 2008
+#
+CONFIG_SPARC=y
+CONFIG_SPARC64=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_64BIT=y
+CONFIG_MMU=y
+CONFIG_IOMMU_HELPER=y
+CONFIG_QUICKLIST=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_AUDIT_ARCH=y
+CONFIG_HAVE_SETUP_PER_CPU_AREA=y
+CONFIG_ARCH_NO_VIRT_TO_BUS=y
+CONFIG_OF=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=18
+# CONFIG_CGROUPS is not set
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+CONFIG_RELAY=y
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_PCI_QUIRKS=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+CONFIG_PROFILING=y
+# CONFIG_MARKERS is not set
+CONFIG_OPROFILE=m
+CONFIG_HAVE_OPROFILE=y
+CONFIG_KPROBES=y
+CONFIG_KRETPROBES=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_USE_GENERIC_SMP_HELPERS=y
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_KMOD=y
+CONFIG_STOP_MACHINE=y
+CONFIG_BLOCK=y
+CONFIG_BLK_DEV_IO_TRACE=y
+CONFIG_BLK_DEV_BSG=y
+# CONFIG_BLK_DEV_INTEGRITY is not set
+CONFIG_BLOCK_COMPAT=y
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+CONFIG_CLASSIC_RCU=y
+# CONFIG_FREEZER is not set
+
+#
+# Processor type and features
+#
+CONFIG_SPARC64_PAGE_SIZE_8KB=y
+# CONFIG_SPARC64_PAGE_SIZE_64KB is not set
+CONFIG_SECCOMP=y
+CONFIG_HZ_100=y
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=100
+CONFIG_SCHED_HRTICK=y
+CONFIG_HOTPLUG_CPU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_SMP=y
+CONFIG_NR_CPUS=64
+# CONFIG_CPU_FREQ is not set
+CONFIG_US3_MC=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_HUGETLB_PAGE_SIZE_4MB=y
+# CONFIG_HUGETLB_PAGE_SIZE_512K is not set
+# CONFIG_HUGETLB_PAGE_SIZE_64K is not set
+CONFIG_NUMA=y
+CONFIG_NODES_SHIFT=4
+CONFIG_NODES_SPAN_OTHER_NODES=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+CONFIG_SELECT_MEMORY_MODEL=y
+# CONFIG_FLATMEM_MANUAL is not set
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+CONFIG_SPARSEMEM_MANUAL=y
+CONFIG_SPARSEMEM=y
+CONFIG_NEED_MULTIPLE_NODES=y
+CONFIG_HAVE_MEMORY_PRESENT=y
+CONFIG_SPARSEMEM_EXTREME=y
+CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y
+CONFIG_SPARSEMEM_VMEMMAP=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_MIGRATION=y
+CONFIG_RESOURCES_64BIT=y
+CONFIG_PHYS_ADDR_T_64BIT=y
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_NR_QUICK=1
+CONFIG_UNEVICTABLE_LRU=y
+CONFIG_SBUS=y
+CONFIG_SBUSCHAR=y
+CONFIG_SUN_AUXIO=y
+CONFIG_SUN_IO=y
+CONFIG_SUN_LDOMS=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_SYSCALL=y
+CONFIG_ARCH_SUPPORTS_MSI=y
+CONFIG_PCI_MSI=y
+# CONFIG_PCI_LEGACY is not set
+# CONFIG_PCI_DEBUG is not set
+CONFIG_SUN_OPENPROMFS=m
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_COMPAT_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_HAVE_AOUT is not set
+CONFIG_BINFMT_MISC=m
+CONFIG_COMPAT=y
+CONFIG_SYSVIPC_COMPAT=y
+CONFIG_SCHED_SMT=y
+CONFIG_SCHED_MC=y
+# CONFIG_PREEMPT_NONE is not set
+CONFIG_PREEMPT_VOLUNTARY=y
+# CONFIG_PREEMPT is not set
+# CONFIG_CMDLINE_BOOL is not set
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=m
+# CONFIG_XFRM_SUB_POLICY is not set
+CONFIG_XFRM_MIGRATE=y
+# CONFIG_XFRM_STATISTICS is not set
+CONFIG_XFRM_IPCOMP=y
+CONFIG_NET_KEY=m
+CONFIG_NET_KEY_MIGRATE=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+CONFIG_NET_IPGRE_BROADCAST=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_ARPD=y
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+CONFIG_INET_IPCOMP=y
+CONFIG_INET_XFRM_TUNNEL=y
+CONFIG_INET_TUNNEL=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_LRO=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+CONFIG_IPV6=m
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_IPV6_OPTIMISTIC_DAD=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+# CONFIG_IPV6_MIP6 is not set
+CONFIG_INET6_XFRM_TUNNEL=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
+CONFIG_INET6_XFRM_MODE_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_BEET=m
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=m
+CONFIG_IPV6_NDISC_NODETYPE=y
+CONFIG_IPV6_TUNNEL=m
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_IPV6_MROUTE is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+CONFIG_IP_DCCP=m
+CONFIG_INET_DCCP_DIAG=m
+CONFIG_IP_DCCP_ACKVEC=y
+
+#
+# DCCP CCIDs Configuration (EXPERIMENTAL)
+#
+CONFIG_IP_DCCP_CCID2=m
+# CONFIG_IP_DCCP_CCID2_DEBUG is not set
+CONFIG_IP_DCCP_CCID3=m
+# CONFIG_IP_DCCP_CCID3_DEBUG is not set
+CONFIG_IP_DCCP_CCID3_RTO=100
+CONFIG_IP_DCCP_TFRC_LIB=m
+
+#
+# DCCP Kernel Hacking
+#
+# CONFIG_IP_DCCP_DEBUG is not set
+# CONFIG_NET_DCCPPROBE is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+CONFIG_VLAN_8021Q=m
+# CONFIG_VLAN_8021Q_GVRP is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+CONFIG_NET_PKTGEN=m
+CONFIG_NET_TCPPROBE=m
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_PHONET is not set
+CONFIG_WIRELESS=y
+# CONFIG_CFG80211 is not set
+CONFIG_WIRELESS_OLD_REGULATORY=y
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
+# CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+CONFIG_CONNECTOR=m
+# CONFIG_MTD is not set
+CONFIG_OF_DEVICE=y
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
+# CONFIG_BLK_DEV_RAM is not set
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_CDROM_PKTCDVD_BUFFERS=8
+CONFIG_CDROM_PKTCDVD_WCACHE=y
+CONFIG_ATA_OVER_ETH=m
+CONFIG_SUNVDC=m
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_HP_ILO is not set
+CONFIG_HAVE_IDE=y
+CONFIG_IDE=y
+
+#
+# Please see Documentation/ide/ide.txt for help/info on IDE drives
+#
+CONFIG_IDE_TIMINGS=y
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_IDE_GD=y
+CONFIG_IDE_GD_ATA=y
+# CONFIG_IDE_GD_ATAPI is not set
+CONFIG_BLK_DEV_IDECD=y
+CONFIG_BLK_DEV_IDECD_VERBOSE_ERRORS=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+CONFIG_IDE_PROC_FS=y
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_BLK_DEV_PLATFORM is not set
+CONFIG_BLK_DEV_IDEDMA_SFF=y
+
+#
+# PCI IDE chipsets support
+#
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_PCIBUS_ORDER=y
+# CONFIG_BLK_DEV_GENERIC is not set
+# CONFIG_BLK_DEV_OPTI621 is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_AEC62XX is not set
+CONFIG_BLK_DEV_ALI15X3=y
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_JMICRON is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_IT8213 is not set
+# CONFIG_BLK_DEV_IT821X is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_BLK_DEV_TC86C001 is not set
+CONFIG_BLK_DEV_IDEDMA=y
+
+#
+# SCSI device support
+#
+CONFIG_RAID_ATTRS=m
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+CONFIG_SCSI_NETLINK=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=m
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+CONFIG_SCSI_CONSTANTS=y
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+CONFIG_SCSI_SPI_ATTRS=y
+CONFIG_SCSI_FC_ATTRS=y
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_MVSAS is not set
+# CONFIG_SCSI_STEX is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLOGICPTI is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_SUNESP is not set
+# CONFIG_SCSI_SRP is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_ATA is not set
+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_MD_RAID5_RESHAPE is not set
+CONFIG_MD_MULTIPATH=m
+# CONFIG_MD_FAULTY is not set
+CONFIG_BLK_DEV_DM=m
+# CONFIG_DM_DEBUG is not set
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+# CONFIG_DM_MULTIPATH is not set
+# CONFIG_DM_DELAY is not set
+# CONFIG_DM_UEVENT is not set
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# Enable only one of the two stacks, unless you know what you are doing
+#
+# CONFIG_FIREWIRE is not set
+# CONFIG_IEEE1394 is not set
+# CONFIG_I2O is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_ARCNET is not set
+CONFIG_PHYLIB=m
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=m
+# CONFIG_SUNLANCE is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNBMAC is not set
+# CONFIG_SUNQE is not set
+# CONFIG_SUNGEM is not set
+CONFIG_CASSINI=m
+CONFIG_SUNVNET=m
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_EEPRO100 is not set
+# CONFIG_E100 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_R6040 is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_SC92031 is not set
+# CONFIG_ATL2 is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+CONFIG_E1000=m
+# CONFIG_E1000E is not set
+# CONFIG_IP1000 is not set
+# CONFIG_IGB is not set
+# CONFIG_MYRI_SBUS is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_VIA_VELOCITY is not set
+CONFIG_TIGON3=m
+CONFIG_BNX2=m
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+# CONFIG_ATL1E is not set
+# CONFIG_JME is not set
+CONFIG_NETDEV_10000=y
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_CHELSIO_T3 is not set
+# CONFIG_ENIC is not set
+# CONFIG_IXGBE is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
+CONFIG_NIU=m
+# CONFIG_MLX4_EN is not set
+# CONFIG_MLX4_CORE is not set
+# CONFIG_TEHUTI is not set
+# CONFIG_BNX2X is not set
+# CONFIG_QLGE is not set
+# CONFIG_SFC is not set
+# CONFIG_TR is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE=m
+CONFIG_PPPOE=m
+# CONFIG_PPPOL2TP is not set
+# CONFIG_SLIP is not set
+CONFIG_SLHC=m
+# CONFIG_NET_FC is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+CONFIG_KEYBOARD_SUNKBD=y
+CONFIG_KEYBOARD_LKKBD=m
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+CONFIG_MOUSE_PS2_LIFEBOOK=y
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+# CONFIG_MOUSE_PS2_ELANTECH is not set
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
+CONFIG_MOUSE_SERIAL=y
+# CONFIG_MOUSE_APPLETOUCH is not set
+# CONFIG_MOUSE_BCM5974 is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+CONFIG_INPUT_MISC=y
+CONFIG_INPUT_SPARCSPKR=y
+# CONFIG_INPUT_ATI_REMOTE is not set
+# CONFIG_INPUT_ATI_REMOTE2 is not set
+# CONFIG_INPUT_KEYSPAN_REMOTE is not set
+# CONFIG_INPUT_POWERMATE is not set
+# CONFIG_INPUT_YEALINK is not set
+# CONFIG_INPUT_CM109 is not set
+# CONFIG_INPUT_UINPUT is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+# CONFIG_SERIO_SERPORT is not set
+CONFIG_SERIO_PCIPS2=m
+CONFIG_SERIO_LIBPS2=y
+CONFIG_SERIO_RAW=m
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_DEVKMEM is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_NOZOMI is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_SUNCORE=y
+# CONFIG_SERIAL_SUNZILOG is not set
+CONFIG_SERIAL_SUNSU=y
+CONFIG_SERIAL_SUNSU_CONSOLE=y
+CONFIG_SERIAL_SUNSAB=y
+CONFIG_SERIAL_SUNSAB_CONSOLE=y
+CONFIG_SERIAL_SUNHV=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+CONFIG_HW_RANDOM=m
+CONFIG_HW_RANDOM_N2RNG=m
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_DEVPORT=y
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+# CONFIG_I2C_CHARDEV is not set
+CONFIG_I2C_HELPER_AUTO=y
+CONFIG_I2C_ALGOBIT=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# PC SMBus host controller drivers
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_ISCH is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Graphics adapter I2C/DDC channel drivers
+#
+# CONFIG_I2C_VOODOO3 is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_AT24 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+# CONFIG_SPI is not set
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+# CONFIG_GPIOLIB is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_AD7414 is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ADT7470 is not set
+# CONFIG_SENSORS_ADT7473 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_I5K_AMB is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_DME1737 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_ADS7828 is not set
+# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_VT8231 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83L786NG is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_SENSORS_ULTRA45 is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+# CONFIG_WATCHDOG is not set
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB_POSSIBLE=y
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_REGULATOR is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_DRM is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+CONFIG_FB_DDC=y
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_CIRRUS is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_UVESA is not set
+CONFIG_FB_SBUS=y
+# CONFIG_FB_BW2 is not set
+# CONFIG_FB_CG3 is not set
+CONFIG_FB_CG6=y
+CONFIG_FB_FFB=y
+# CONFIG_FB_TCX is not set
+# CONFIG_FB_CG14 is not set
+# CONFIG_FB_P9100 is not set
+# CONFIG_FB_LEO is not set
+CONFIG_FB_XVR500=y
+CONFIG_FB_XVR2500=y
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_NVIDIA is not set
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_MATROX is not set
+CONFIG_FB_RADEON=y
+CONFIG_FB_RADEON_I2C=y
+# CONFIG_FB_RADEON_BACKLIGHT is not set
+# CONFIG_FB_RADEON_DEBUG is not set
+# CONFIG_FB_ATY128 is not set
+CONFIG_FB_ATY=y
+CONFIG_FB_ATY_CT=y
+# CONFIG_FB_ATY_GENERIC_LCD is not set
+CONFIG_FB_ATY_GX=y
+# CONFIG_FB_ATY_BACKLIGHT is not set
+# CONFIG_FB_S3 is not set
+# CONFIG_FB_SAVAGE is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_VIA is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_KYRO is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_VT8623 is not set
+# CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_ARK is not set
+# CONFIG_FB_PM3 is not set
+# CONFIG_FB_CARMINE is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_PROM_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FONTS=y
+# CONFIG_FONT_8x8 is not set
+# CONFIG_FONT_8x16 is not set
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+CONFIG_FONT_SUN8x16=y
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+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_LOGO_SUN_CLUT224=y
+CONFIG_SOUND=m
+CONFIG_SOUND_OSS_CORE=y
+CONFIG_SND=m
+CONFIG_SND_TIMER=m
+CONFIG_SND_PCM=m
+CONFIG_SND_RAWMIDI=m
+CONFIG_SND_SEQUENCER=m
+CONFIG_SND_SEQ_DUMMY=m
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=m
+CONFIG_SND_PCM_OSS=m
+CONFIG_SND_PCM_OSS_PLUGINS=y
+CONFIG_SND_SEQUENCER_OSS=y
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+CONFIG_SND_VMASTER=y
+CONFIG_SND_MPU401_UART=m
+CONFIG_SND_AC97_CODEC=m
+CONFIG_SND_DRIVERS=y
+CONFIG_SND_DUMMY=m
+CONFIG_SND_VIRMIDI=m
+CONFIG_SND_MTPAV=m
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+# CONFIG_SND_AC97_POWER_SAVE is not set
+CONFIG_SND_PCI=y
+# CONFIG_SND_AD1889 is not set
+# CONFIG_SND_ALS300 is not set
+CONFIG_SND_ALI5451=m
+# CONFIG_SND_ATIIXP is not set
+# CONFIG_SND_ATIIXP_MODEM is not set
+# CONFIG_SND_AU8810 is not set
+# CONFIG_SND_AU8820 is not set
+# CONFIG_SND_AU8830 is not set
+# CONFIG_SND_AW2 is not set
+# CONFIG_SND_AZT3328 is not set
+# CONFIG_SND_BT87X is not set
+# CONFIG_SND_CA0106 is not set
+# CONFIG_SND_CMIPCI is not set
+# CONFIG_SND_OXYGEN is not set
+# CONFIG_SND_CS4281 is not set
+# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_DARLA20 is not set
+# CONFIG_SND_GINA20 is not set
+# CONFIG_SND_LAYLA20 is not set
+# CONFIG_SND_DARLA24 is not set
+# CONFIG_SND_GINA24 is not set
+# CONFIG_SND_LAYLA24 is not set
+# CONFIG_SND_MONA is not set
+# CONFIG_SND_MIA is not set
+# CONFIG_SND_ECHO3G is not set
+# CONFIG_SND_INDIGO is not set
+# CONFIG_SND_INDIGOIO is not set
+# CONFIG_SND_INDIGODJ is not set
+# CONFIG_SND_EMU10K1 is not set
+# CONFIG_SND_EMU10K1X is not set
+# CONFIG_SND_ENS1370 is not set
+# CONFIG_SND_ENS1371 is not set
+# CONFIG_SND_ES1938 is not set
+# CONFIG_SND_ES1968 is not set
+# CONFIG_SND_FM801 is not set
+# CONFIG_SND_HDA_INTEL is not set
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_HDSPM is not set
+# CONFIG_SND_HIFIER is not set
+# CONFIG_SND_ICE1712 is not set
+# CONFIG_SND_ICE1724 is not set
+# CONFIG_SND_INTEL8X0 is not set
+# CONFIG_SND_INTEL8X0M is not set
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_MAESTRO3 is not set
+# CONFIG_SND_MIXART is not set
+# CONFIG_SND_NM256 is not set
+# CONFIG_SND_PCXHR is not set
+# CONFIG_SND_RIPTIDE is not set
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
+# CONFIG_SND_SONICVIBES is not set
+# CONFIG_SND_TRIDENT is not set
+# CONFIG_SND_VIA82XX is not set
+# CONFIG_SND_VIA82XX_MODEM is not set
+# CONFIG_SND_VIRTUOSO is not set
+# CONFIG_SND_VX222 is not set
+# CONFIG_SND_YMFPCI is not set
+CONFIG_SND_USB=y
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_CAIAQ is not set
+CONFIG_SND_SPARC=y
+# CONFIG_SND_SUN_AMD7930 is not set
+CONFIG_SND_SUN_CS4231=m
+# CONFIG_SND_SUN_DBRI is not set
+# CONFIG_SND_SOC is not set
+# CONFIG_SOUND_PRIME is not set
+CONFIG_AC97_BUS=m
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+CONFIG_USB_HIDDEV=y
+
+#
+# Special HID drivers
+#
+CONFIG_HID_COMPAT=y
+CONFIG_HID_A4TECH=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_BELKIN=y
+CONFIG_HID_BRIGHT=y
+CONFIG_HID_CHERRY=y
+CONFIG_HID_CHICONY=y
+CONFIG_HID_CYPRESS=y
+CONFIG_HID_DELL=y
+CONFIG_HID_EZKEY=y
+CONFIG_HID_GYRATION=y
+CONFIG_HID_LOGITECH=y
+# CONFIG_LOGITECH_FF is not set
+# CONFIG_LOGIRUMBLEPAD2_FF is not set
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MONTEREY=y
+CONFIG_HID_PANTHERLORD=y
+# CONFIG_PANTHERLORD_FF is not set
+CONFIG_HID_PETALYNX=y
+CONFIG_HID_SAMSUNG=y
+CONFIG_HID_SONY=y
+CONFIG_HID_SUNPLUS=y
+# CONFIG_THRUSTMASTER_FF is not set
+# CONFIG_ZEROPLUS_FF is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_MON is not set
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+CONFIG_USB_EHCI_HCD=m
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+CONFIG_USB_UHCI_HCD=m
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_WHCI_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
+# CONFIG_USB_GADGET is not set
+# CONFIG_UWB is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_INFINIBAND is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+CONFIG_RTC_DRV_CMOS=y
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+CONFIG_RTC_DRV_M48T59=y
+CONFIG_RTC_DRV_BQ4802=y
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_SUN4V=y
+CONFIG_RTC_DRV_STARFIRE=y
+# CONFIG_DMADEVICES is not set
+# CONFIG_UIO is not set
+# CONFIG_STAGING is not set
+CONFIG_STAGING_EXCLUDE_BUILD=y
+
+#
+# Misc Linux/SPARC drivers
+#
+CONFIG_SUN_OPENPROMIO=y
+# CONFIG_OBP_FLASH is not set
+# CONFIG_TADPOLE_TS102_UCTRL is not set
+# CONFIG_BBC_I2C is not set
+# CONFIG_ENVCTRL is not set
+# CONFIG_DISPLAY7SEG is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+# CONFIG_EXT4_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_FILE_LOCKING=y
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+CONFIG_HUGETLBFS=y
+CONFIG_HUGETLB_PAGE=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_ECRYPT_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+CONFIG_SUN_PARTITION=y
+CONFIG_NLS=m
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_PRINTK_TIME=y
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=2048
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+# CONFIG_SCHED_DEBUG is not set
+CONFIG_SCHEDSTATS=y
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+CONFIG_DEBUG_MEMORY_INIT=y
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_KPROBES_SANITY_TEST is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_LKDTM is not set
+# CONFIG_FAULT_INJECTION is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+
+#
+# Tracers
+#
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_DCFLUSH is not set
+# CONFIG_STACK_DEBUG is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+# CONFIG_KEYS_DEBUG_PROC_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_XOR_BLOCKS=m
+CONFIG_ASYNC_CORE=m
+CONFIG_ASYNC_MEMCPY=m
+CONFIG_ASYNC_XOR=m
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_AEAD=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_RNG=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_GF128MUL=m
+CONFIG_CRYPTO_NULL=m
+# CONFIG_CRYPTO_CRYPTD is not set
+CONFIG_CRYPTO_AUTHENC=y
+CONFIG_CRYPTO_TEST=m
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_LRW=m
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_XTS=m
+
+#
+# Hash modes
+#
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_XCBC=y
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=m
+CONFIG_CRYPTO_MD4=y
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_MICHAEL_MIC=m
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_WP512=m
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_CAMELLIA=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_FCRYPT=m
+CONFIG_CRYPTO_KHAZAD=m
+# CONFIG_CRYPTO_SALSA20 is not set
+CONFIG_CRYPTO_SEED=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_TWOFISH_COMMON=m
+
+#
+# Compression
+#
+CONFIG_CRYPTO_DEFLATE=y
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_CRYPTO_DEV_HIFN_795X is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=m
+CONFIG_CRC16=m
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_HAVE_LMB=y
diff --git a/arch/sparc/include/asm/Kbuild b/arch/sparc/include/asm/Kbuild
index 2d2769d766ec..89c260aab45c 100644
--- a/arch/sparc/include/asm/Kbuild
+++ b/arch/sparc/include/asm/Kbuild
@@ -15,8 +15,6 @@ header-y += signal_32.h
header-y += signal_64.h
header-y += stat_32.h
header-y += stat_64.h
-header-y += unistd_32.h
-header-y += unistd_64.h
header-y += apc.h
header-y += asi.h
diff --git a/arch/sparc/include/asm/asm.h b/arch/sparc/include/asm/asm.h
new file mode 100644
index 000000000000..e8e1d94b4cc9
--- /dev/null
+++ b/arch/sparc/include/asm/asm.h
@@ -0,0 +1,40 @@
+#ifndef _SPARC_ASM_H
+#define _SPARC_ASM_H
+
+/* Macros to assist the sharing of assembler code between 32-bit and
+ * 64-bit sparc.
+ */
+
+#ifdef CONFIG_SPARC64
+#define BRANCH32(TYPE, PREDICT, DEST) \
+ TYPE,PREDICT %icc, DEST
+#define BRANCH32_ANNUL(TYPE, PREDICT, DEST) \
+ TYPE,a,PREDICT %icc, DEST
+#define BRANCH_REG_ZERO(PREDICT, REG, DEST) \
+ brz,PREDICT REG, DEST
+#define BRANCH_REG_ZERO_ANNUL(PREDICT, REG, DEST) \
+ brz,a,PREDICT REG, DEST
+#define BRANCH_REG_NOT_ZERO(PREDICT, REG, DEST) \
+ brnz,PREDICT REG, DEST
+#define BRANCH_REG_NOT_ZERO_ANNUL(PREDICT, REG, DEST) \
+ brnz,a,PREDICT REG, DEST
+#else
+#define BRANCH32(TYPE, PREDICT, DEST) \
+ TYPE DEST
+#define BRANCH32_ANNUL(TYPE, PREDICT, DEST) \
+ TYPE,a DEST
+#define BRANCH_REG_ZERO(PREDICT, REG, DEST) \
+ cmp REG, 0; \
+ be DEST
+#define BRANCH_REG_ZERO_ANNUL(PREDICT, REG, DEST) \
+ cmp REG, 0; \
+ be,a DEST
+#define BRANCH_REG_NOT_ZERO(PREDICT, REG, DEST) \
+ cmp REG, 0; \
+ bne DEST
+#define BRANCH_REG_NOT_ZERO_ANNUL(PREDICT, REG, DEST) \
+ cmp REG, 0; \
+ bne,a DEST
+#endif
+
+#endif /* _SPARC_ASM_H */
diff --git a/arch/sparc/include/asm/atomic_64.h b/arch/sparc/include/asm/atomic_64.h
index 2c71ec4a3b18..5982c5ae7f07 100644
--- a/arch/sparc/include/asm/atomic_64.h
+++ b/arch/sparc/include/asm/atomic_64.h
@@ -112,17 +112,10 @@ static inline int atomic64_add_unless(atomic64_t *v, long a, long u)
#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
/* Atomic operations are already serializing */
-#ifdef CONFIG_SMP
-#define smp_mb__before_atomic_dec() membar_storeload_loadload();
-#define smp_mb__after_atomic_dec() membar_storeload_storestore();
-#define smp_mb__before_atomic_inc() membar_storeload_loadload();
-#define smp_mb__after_atomic_inc() membar_storeload_storestore();
-#else
#define smp_mb__before_atomic_dec() barrier()
#define smp_mb__after_atomic_dec() barrier()
#define smp_mb__before_atomic_inc() barrier()
#define smp_mb__after_atomic_inc() barrier()
-#endif
#include <asm-generic/atomic.h>
#endif /* !(__ARCH_SPARC64_ATOMIC__) */
diff --git a/arch/sparc/include/asm/bitops_64.h b/arch/sparc/include/asm/bitops_64.h
index bb87b8080220..e72ac9cdfb98 100644
--- a/arch/sparc/include/asm/bitops_64.h
+++ b/arch/sparc/include/asm/bitops_64.h
@@ -23,13 +23,8 @@ extern void change_bit(unsigned long nr, volatile unsigned long *addr);
#include <asm-generic/bitops/non-atomic.h>
-#ifdef CONFIG_SMP
-#define smp_mb__before_clear_bit() membar_storeload_loadload()
-#define smp_mb__after_clear_bit() membar_storeload_storestore()
-#else
#define smp_mb__before_clear_bit() barrier()
#define smp_mb__after_clear_bit() barrier()
-#endif
#include <asm-generic/bitops/ffz.h>
#include <asm-generic/bitops/__ffs.h>
diff --git a/arch/sparc/include/asm/device.h b/arch/sparc/include/asm/device.h
index 19790eb99cc6..3702e087df2c 100644
--- a/arch/sparc/include/asm/device.h
+++ b/arch/sparc/include/asm/device.h
@@ -20,4 +20,16 @@ struct dev_archdata {
int numa_node;
};
+static inline void dev_archdata_set_node(struct dev_archdata *ad,
+ struct device_node *np)
+{
+ ad->prom_node = np;
+}
+
+static inline struct device_node *
+dev_archdata_get_node(const struct dev_archdata *ad)
+{
+ return ad->prom_node;
+}
+
#endif /* _ASM_SPARC_DEVICE_H */
diff --git a/arch/sparc/include/asm/hypervisor.h b/arch/sparc/include/asm/hypervisor.h
index 109ae24ba242..bafe5a631b6d 100644
--- a/arch/sparc/include/asm/hypervisor.h
+++ b/arch/sparc/include/asm/hypervisor.h
@@ -2713,6 +2713,30 @@ extern unsigned long sun4v_ldc_revoke(unsigned long channel,
*/
#define HV_FAST_SET_PERFREG 0x101
+#define HV_N2_PERF_SPARC_CTL 0x0
+#define HV_N2_PERF_DRAM_CTL0 0x1
+#define HV_N2_PERF_DRAM_CNT0 0x2
+#define HV_N2_PERF_DRAM_CTL1 0x3
+#define HV_N2_PERF_DRAM_CNT1 0x4
+#define HV_N2_PERF_DRAM_CTL2 0x5
+#define HV_N2_PERF_DRAM_CNT2 0x6
+#define HV_N2_PERF_DRAM_CTL3 0x7
+#define HV_N2_PERF_DRAM_CNT3 0x8
+
+#define HV_FAST_N2_GET_PERFREG 0x104
+#define HV_FAST_N2_SET_PERFREG 0x105
+
+#ifndef __ASSEMBLY__
+extern unsigned long sun4v_niagara_getperf(unsigned long reg,
+ unsigned long *val);
+extern unsigned long sun4v_niagara_setperf(unsigned long reg,
+ unsigned long val);
+extern unsigned long sun4v_niagara2_getperf(unsigned long reg,
+ unsigned long *val);
+extern unsigned long sun4v_niagara2_setperf(unsigned long reg,
+ unsigned long val);
+#endif
+
/* MMU statistics services.
*
* The hypervisor maintains MMU statistics and privileged code provides
diff --git a/arch/sparc/include/asm/irq_32.h b/arch/sparc/include/asm/irq_32.h
index fe205cc444b8..ea43057d4763 100644
--- a/arch/sparc/include/asm/irq_32.h
+++ b/arch/sparc/include/asm/irq_32.h
@@ -12,4 +12,5 @@
#define irq_canonicalize(irq) (irq)
+extern void __init init_IRQ(void);
#endif
diff --git a/arch/sparc/include/asm/irq_64.h b/arch/sparc/include/asm/irq_64.h
index 71673eca3660..d47d4a1955a9 100644
--- a/arch/sparc/include/asm/irq_64.h
+++ b/arch/sparc/include/asm/irq_64.h
@@ -66,6 +66,9 @@ extern void virt_irq_free(unsigned int virt_irq);
extern void __init init_IRQ(void);
extern void fixup_irqs(void);
+extern int register_perfctr_intr(void (*handler)(struct pt_regs *));
+extern void release_perfctr_intr(void (*handler)(struct pt_regs *));
+
static inline void set_softint(unsigned long bits)
{
__asm__ __volatile__("wr %0, 0x0, %%set_softint"
diff --git a/arch/sparc/include/asm/irqflags_64.h b/arch/sparc/include/asm/irqflags_64.h
index bb42e59162aa..8b49bf920df3 100644
--- a/arch/sparc/include/asm/irqflags_64.h
+++ b/arch/sparc/include/asm/irqflags_64.h
@@ -10,6 +10,8 @@
#ifndef _ASM_IRQFLAGS_H
#define _ASM_IRQFLAGS_H
+#include <asm/pil.h>
+
#ifndef __ASSEMBLY__
static inline unsigned long __raw_local_save_flags(void)
@@ -40,9 +42,9 @@ static inline void raw_local_irq_restore(unsigned long flags)
static inline void raw_local_irq_disable(void)
{
__asm__ __volatile__(
- "wrpr 15, %%pil"
+ "wrpr %0, %%pil"
: /* no outputs */
- : /* no inputs */
+ : "i" (PIL_NORMAL_MAX)
: "memory"
);
}
diff --git a/arch/sparc/include/asm/module.h b/arch/sparc/include/asm/module.h
index e82cf9a3e60e..ff8e02d80334 100644
--- a/arch/sparc/include/asm/module.h
+++ b/arch/sparc/include/asm/module.h
@@ -1,8 +1,24 @@
-#ifndef ___ASM_SPARC_MODULE_H
-#define ___ASM_SPARC_MODULE_H
-#if defined(__sparc__) && defined(__arch64__)
-#include <asm/module_64.h>
-#else
-#include <asm/module_32.h>
-#endif
-#endif
+#ifndef __SPARC_MODULE_H
+#define __SPARC_MODULE_H
+struct mod_arch_specific { };
+
+/*
+ * Use some preprocessor magic to define the correct symbol
+ * for sparc32 and sparc64.
+ * Elf_Addr becomes Elf32_Addr for sparc32 and Elf64_Addr for sparc64
+ */
+#define ___ELF(a, b, c) a##b##c
+#define __ELF(a, b, c) ___ELF(a, b, c)
+#define _Elf(t) __ELF(Elf, CONFIG_BITS, t)
+#define _ELF(t) __ELF(ELF, CONFIG_BITS, t)
+
+#define Elf_Shdr _Elf(_Shdr)
+#define Elf_Sym _Elf(_Sym)
+#define Elf_Ehdr _Elf(_Ehdr)
+#define Elf_Rela _Elf(_Rela)
+#define Elf_Addr _Elf(_Addr)
+
+#define ELF_R_SYM _ELF(_R_SYM)
+#define ELF_R_TYPE _ELF(_R_TYPE)
+
+#endif /* __SPARC_MODULE_H */
diff --git a/arch/sparc/include/asm/module_32.h b/arch/sparc/include/asm/module_32.h
deleted file mode 100644
index cbd9e67b0c0b..000000000000
--- a/arch/sparc/include/asm/module_32.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef _ASM_SPARC_MODULE_H
-#define _ASM_SPARC_MODULE_H
-struct mod_arch_specific { };
-#define Elf_Shdr Elf32_Shdr
-#define Elf_Sym Elf32_Sym
-#define Elf_Ehdr Elf32_Ehdr
-#endif /* _ASM_SPARC_MODULE_H */
diff --git a/arch/sparc/include/asm/module_64.h b/arch/sparc/include/asm/module_64.h
deleted file mode 100644
index 3d77ba465783..000000000000
--- a/arch/sparc/include/asm/module_64.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef _ASM_SPARC64_MODULE_H
-#define _ASM_SPARC64_MODULE_H
-struct mod_arch_specific { };
-#define Elf_Shdr Elf64_Shdr
-#define Elf_Sym Elf64_Sym
-#define Elf_Ehdr Elf64_Ehdr
-#endif /* _ASM_SPARC64_MODULE_H */
diff --git a/arch/sparc/include/asm/openprom_32.h b/arch/sparc/include/asm/openprom_32.h
index 8b1649f29ed9..875da3552d80 100644
--- a/arch/sparc/include/asm/openprom_32.h
+++ b/arch/sparc/include/asm/openprom_32.h
@@ -170,9 +170,9 @@ struct linux_romvec {
struct linux_nodeops {
int (*no_nextnode)(int node);
int (*no_child)(int node);
- int (*no_proplen)(int node, char *name);
- int (*no_getprop)(int node, char *name, char *val);
- int (*no_setprop)(int node, char *name, char *val, int len);
+ int (*no_proplen)(int node, const char *name);
+ int (*no_getprop)(int node, const char *name, char *val);
+ int (*no_setprop)(int node, const char *name, char *val, int len);
char * (*no_nextprop)(int node, char *name);
};
diff --git a/arch/sparc/include/asm/oplib_32.h b/arch/sparc/include/asm/oplib_32.h
index 699da05235c8..73d45521db04 100644
--- a/arch/sparc/include/asm/oplib_32.h
+++ b/arch/sparc/include/asm/oplib_32.h
@@ -136,7 +136,7 @@ extern char prom_getchar(void);
extern void prom_putchar(char character);
/* Prom's internal routines, don't use in kernel/boot code. */
-extern void prom_printf(char *fmt, ...);
+extern void prom_printf(const char *fmt, ...);
extern void prom_write(const char *buf, unsigned int len);
/* Multiprocessor operations... */
@@ -199,12 +199,12 @@ extern int prom_getsibling(int node);
/* Get the length, at the passed node, of the given property type.
* Returns -1 on error (ie. no such property at this node).
*/
-extern int prom_getproplen(int thisnode, char *property);
+extern int prom_getproplen(int thisnode, const char *property);
/* Fetch the requested property using the given buffer. Returns
* the number of bytes the prom put into your buffer or -1 on error.
*/
-extern int __must_check prom_getproperty(int thisnode, char *property,
+extern int __must_check prom_getproperty(int thisnode, const char *property,
char *prop_buffer, int propbuf_size);
/* Acquire an integer property. */
@@ -246,7 +246,7 @@ extern int prom_node_has_property(int node, char *property);
/* Set the indicated property at the given node with the passed value.
* Returns the number of bytes of your value that the prom took.
*/
-extern int prom_setprop(int node, char *prop_name, char *prop_value,
+extern int prom_setprop(int node, const char *prop_name, char *prop_value,
int value_size);
extern int prom_pathtoinode(char *path);
diff --git a/arch/sparc/include/asm/pil.h b/arch/sparc/include/asm/pil.h
index 71819bb943fc..d573820c0ff4 100644
--- a/arch/sparc/include/asm/pil.h
+++ b/arch/sparc/include/asm/pil.h
@@ -10,7 +10,12 @@
*
* In fact any XCALL which has to etrap/rtrap has a problem because
* it is difficult to prevent rtrap from running BH's, and that would
- * need to be done if the XCALL arrived while %pil==15.
+ * need to be done if the XCALL arrived while %pil==PIL_NORMAL_MAX.
+ *
+ * Finally, in order to handle profiling events even when a
+ * local_irq_disable() is in progress, we only disable up to level 14
+ * interrupts. Profile counter overflow interrupts arrive at level
+ * 15.
*/
#define PIL_SMP_CALL_FUNC 1
#define PIL_SMP_RECEIVE_SIGNAL 2
@@ -18,5 +23,7 @@
#define PIL_SMP_CTX_NEW_VERSION 4
#define PIL_DEVICE_IRQ 5
#define PIL_SMP_CALL_FUNC_SNGL 6
+#define PIL_NORMAL_MAX 14
+#define PIL_NMI 15
#endif /* !(_SPARC64_PIL_H) */
diff --git a/arch/sparc/include/asm/ptrace_32.h b/arch/sparc/include/asm/ptrace_32.h
index d409c4f21a5c..4cef450167dd 100644
--- a/arch/sparc/include/asm/ptrace_32.h
+++ b/arch/sparc/include/asm/ptrace_32.h
@@ -62,6 +62,8 @@ struct sparc_stackf {
#ifdef __KERNEL__
+#include <asm/system.h>
+
static inline bool pt_regs_is_syscall(struct pt_regs *regs)
{
return (regs->psr & PSR_SYSCALL);
@@ -72,6 +74,14 @@ static inline bool pt_regs_clear_syscall(struct pt_regs *regs)
return (regs->psr &= ~PSR_SYSCALL);
}
+#define arch_ptrace_stop_needed(exit_code, info) \
+({ flush_user_windows(); \
+ current_thread_info()->w_saved != 0; \
+})
+
+#define arch_ptrace_stop(exit_code, info) \
+ synchronize_user_stack()
+
#define user_mode(regs) (!((regs)->psr & PSR_PS))
#define instruction_pointer(regs) ((regs)->pc)
#define user_stack_pointer(regs) ((regs)->u_regs[UREG_FP])
diff --git a/arch/sparc/include/asm/ptrace_64.h b/arch/sparc/include/asm/ptrace_64.h
index 84e969f06afe..cd6fbfc20435 100644
--- a/arch/sparc/include/asm/ptrace_64.h
+++ b/arch/sparc/include/asm/ptrace_64.h
@@ -114,6 +114,7 @@ struct sparc_trapf {
#ifdef __KERNEL__
#include <linux/threads.h>
+#include <asm/system.h>
static inline int pt_regs_trap_type(struct pt_regs *regs)
{
@@ -130,6 +131,14 @@ static inline bool pt_regs_clear_syscall(struct pt_regs *regs)
return (regs->tstate &= ~TSTATE_SYSCALL);
}
+#define arch_ptrace_stop_needed(exit_code, info) \
+({ flush_user_windows(); \
+ get_thread_wsaved() != 0; \
+})
+
+#define arch_ptrace_stop(exit_code, info) \
+ synchronize_user_stack()
+
struct global_reg_snapshot {
unsigned long tstate;
unsigned long tpc;
diff --git a/arch/sparc/include/asm/scatterlist.h b/arch/sparc/include/asm/scatterlist.h
index ec21a4517641..e580f5581c88 100644
--- a/arch/sparc/include/asm/scatterlist.h
+++ b/arch/sparc/include/asm/scatterlist.h
@@ -1,8 +1,27 @@
-#ifndef ___ASM_SPARC_SCATTERLIST_H
-#define ___ASM_SPARC_SCATTERLIST_H
-#if defined(__sparc__) && defined(__arch64__)
-#include <asm/scatterlist_64.h>
-#else
-#include <asm/scatterlist_32.h>
-#endif
+#ifndef _SPARC_SCATTERLIST_H
+#define _SPARC_SCATTERLIST_H
+
+#include <asm/page.h>
+#include <asm/types.h>
+
+struct scatterlist {
+#ifdef CONFIG_DEBUG_SG
+ unsigned long sg_magic;
#endif
+ unsigned long page_link;
+ unsigned int offset;
+
+ unsigned int length;
+
+ dma_addr_t dma_address;
+ __u32 dma_length;
+};
+
+#define sg_dma_address(sg) ((sg)->dma_address)
+#define sg_dma_len(sg) ((sg)->dma_length)
+
+#define ISA_DMA_THRESHOLD (~0UL)
+
+#define ARCH_HAS_SG_CHAIN
+
+#endif /* !(_SPARC_SCATTERLIST_H) */
diff --git a/arch/sparc/include/asm/scatterlist_32.h b/arch/sparc/include/asm/scatterlist_32.h
deleted file mode 100644
index c82609ca1d0f..000000000000
--- a/arch/sparc/include/asm/scatterlist_32.h
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifndef _SPARC_SCATTERLIST_H
-#define _SPARC_SCATTERLIST_H
-
-#include <linux/types.h>
-
-struct scatterlist {
-#ifdef CONFIG_DEBUG_SG
- unsigned long sg_magic;
-#endif
- unsigned long page_link;
- unsigned int offset;
-
- unsigned int length;
-
- __u32 dvma_address; /* A place to hang host-specific addresses at. */
- __u32 dvma_length;
-};
-
-#define sg_dma_address(sg) ((sg)->dvma_address)
-#define sg_dma_len(sg) ((sg)->dvma_length)
-
-#define ISA_DMA_THRESHOLD (~0UL)
-
-#define ARCH_HAS_SG_CHAIN
-
-#endif /* !(_SPARC_SCATTERLIST_H) */
diff --git a/arch/sparc/include/asm/scatterlist_64.h b/arch/sparc/include/asm/scatterlist_64.h
deleted file mode 100644
index 81bd058f9382..000000000000
--- a/arch/sparc/include/asm/scatterlist_64.h
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef _SPARC64_SCATTERLIST_H
-#define _SPARC64_SCATTERLIST_H
-
-#include <asm/page.h>
-#include <asm/types.h>
-
-struct scatterlist {
-#ifdef CONFIG_DEBUG_SG
- unsigned long sg_magic;
-#endif
- unsigned long page_link;
- unsigned int offset;
-
- unsigned int length;
-
- dma_addr_t dma_address;
- __u32 dma_length;
-};
-
-#define sg_dma_address(sg) ((sg)->dma_address)
-#define sg_dma_len(sg) ((sg)->dma_length)
-
-#define ISA_DMA_THRESHOLD (~0UL)
-
-#define ARCH_HAS_SG_CHAIN
-
-#endif /* !(_SPARC64_SCATTERLIST_H) */
diff --git a/arch/sparc/include/asm/sections.h b/arch/sparc/include/asm/sections.h
index c7c69b00967f..0b0553bbd8a0 100644
--- a/arch/sparc/include/asm/sections.h
+++ b/arch/sparc/include/asm/sections.h
@@ -1,8 +1,10 @@
-#ifndef ___ASM_SPARC_SECTIONS_H
-#define ___ASM_SPARC_SECTIONS_H
-#if defined(__sparc__) && defined(__arch64__)
-#include <asm/sections_64.h>
-#else
-#include <asm/sections_32.h>
-#endif
+#ifndef __SPARC_SECTIONS_H
+#define __SPARC_SECTIONS_H
+
+/* nothing to see, move along */
+#include <asm-generic/sections.h>
+
+/* sparc entry point */
+extern char _start[];
+
#endif
diff --git a/arch/sparc/include/asm/sections_32.h b/arch/sparc/include/asm/sections_32.h
deleted file mode 100644
index 6832841df051..000000000000
--- a/arch/sparc/include/asm/sections_32.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _SPARC_SECTIONS_H
-#define _SPARC_SECTIONS_H
-
-#include <asm-generic/sections.h>
-
-#endif
diff --git a/arch/sparc/include/asm/sections_64.h b/arch/sparc/include/asm/sections_64.h
deleted file mode 100644
index 3f4b9fdc28d0..000000000000
--- a/arch/sparc/include/asm/sections_64.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef _SPARC64_SECTIONS_H
-#define _SPARC64_SECTIONS_H
-
-/* nothing to see, move along */
-#include <asm-generic/sections.h>
-
-extern char _start[];
-
-#endif
diff --git a/arch/sparc/include/asm/spinlock_64.h b/arch/sparc/include/asm/spinlock_64.h
index 120cfe4577c7..c4d274d330e9 100644
--- a/arch/sparc/include/asm/spinlock_64.h
+++ b/arch/sparc/include/asm/spinlock_64.h
@@ -13,17 +13,12 @@
* and rebuild your kernel.
*/
-/* All of these locking primitives are expected to work properly
- * even in an RMO memory model, which currently is what the kernel
- * runs in.
- *
- * There is another issue. Because we play games to save cycles
- * in the non-contention case, we need to be extra careful about
- * branch targets into the "spinning" code. They live in their
- * own section, but the newer V9 branches have a shorter range
- * than the traditional 32-bit sparc branch variants. The rule
- * is that the branches that go into and out of the spinner sections
- * must be pre-V9 branches.
+/* Because we play games to save cycles in the non-contention case, we
+ * need to be extra careful about branch targets into the "spinning"
+ * code. They live in their own section, but the newer V9 branches
+ * have a shorter range than the traditional 32-bit sparc branch
+ * variants. The rule is that the branches that go into and out of
+ * the spinner sections must be pre-V9 branches.
*/
#define __raw_spin_is_locked(lp) ((lp)->lock != 0)
@@ -38,12 +33,10 @@ static inline void __raw_spin_lock(raw_spinlock_t *lock)
__asm__ __volatile__(
"1: ldstub [%1], %0\n"
-" membar #StoreLoad | #StoreStore\n"
" brnz,pn %0, 2f\n"
" nop\n"
" .subsection 2\n"
"2: ldub [%1], %0\n"
-" membar #LoadLoad\n"
" brnz,pt %0, 2b\n"
" nop\n"
" ba,a,pt %%xcc, 1b\n"
@@ -59,7 +52,6 @@ static inline int __raw_spin_trylock(raw_spinlock_t *lock)
__asm__ __volatile__(
" ldstub [%1], %0\n"
-" membar #StoreLoad | #StoreStore"
: "=r" (result)
: "r" (lock)
: "memory");
@@ -70,7 +62,6 @@ static inline int __raw_spin_trylock(raw_spinlock_t *lock)
static inline void __raw_spin_unlock(raw_spinlock_t *lock)
{
__asm__ __volatile__(
-" membar #StoreStore | #LoadStore\n"
" stb %%g0, [%0]"
: /* No outputs */
: "r" (lock)
@@ -83,14 +74,12 @@ static inline void __raw_spin_lock_flags(raw_spinlock_t *lock, unsigned long fla
__asm__ __volatile__(
"1: ldstub [%2], %0\n"
-" membar #StoreLoad | #StoreStore\n"
" brnz,pn %0, 2f\n"
" nop\n"
" .subsection 2\n"
"2: rdpr %%pil, %1\n"
" wrpr %3, %%pil\n"
"3: ldub [%2], %0\n"
-" membar #LoadLoad\n"
" brnz,pt %0, 3b\n"
" nop\n"
" ba,pt %%xcc, 1b\n"
@@ -113,12 +102,10 @@ static void inline __read_lock(raw_rwlock_t *lock)
"4: add %0, 1, %1\n"
" cas [%2], %0, %1\n"
" cmp %0, %1\n"
-" membar #StoreLoad | #StoreStore\n"
" bne,pn %%icc, 1b\n"
" nop\n"
" .subsection 2\n"
"2: ldsw [%2], %0\n"
-" membar #LoadLoad\n"
" brlz,pt %0, 2b\n"
" nop\n"
" ba,a,pt %%xcc, 4b\n"
@@ -139,7 +126,6 @@ static int inline __read_trylock(raw_rwlock_t *lock)
" add %0, 1, %1\n"
" cas [%2], %0, %1\n"
" cmp %0, %1\n"
-" membar #StoreLoad | #StoreStore\n"
" bne,pn %%icc, 1b\n"
" mov 1, %0\n"
"2:"
@@ -155,7 +141,6 @@ static void inline __read_unlock(raw_rwlock_t *lock)
unsigned long tmp1, tmp2;
__asm__ __volatile__(
-" membar #StoreLoad | #LoadLoad\n"
"1: lduw [%2], %0\n"
" sub %0, 1, %1\n"
" cas [%2], %0, %1\n"
@@ -179,12 +164,10 @@ static void inline __write_lock(raw_rwlock_t *lock)
"4: or %0, %3, %1\n"
" cas [%2], %0, %1\n"
" cmp %0, %1\n"
-" membar #StoreLoad | #StoreStore\n"
" bne,pn %%icc, 1b\n"
" nop\n"
" .subsection 2\n"
"2: lduw [%2], %0\n"
-" membar #LoadLoad\n"
" brnz,pt %0, 2b\n"
" nop\n"
" ba,a,pt %%xcc, 4b\n"
@@ -197,7 +180,6 @@ static void inline __write_lock(raw_rwlock_t *lock)
static void inline __write_unlock(raw_rwlock_t *lock)
{
__asm__ __volatile__(
-" membar #LoadStore | #StoreStore\n"
" stw %%g0, [%0]"
: /* no outputs */
: "r" (lock)
@@ -217,7 +199,6 @@ static int inline __write_trylock(raw_rwlock_t *lock)
" or %0, %4, %1\n"
" cas [%3], %0, %1\n"
" cmp %0, %1\n"
-" membar #StoreLoad | #StoreStore\n"
" bne,pn %%icc, 1b\n"
" nop\n"
" mov 1, %2\n"
diff --git a/arch/sparc/include/asm/spitfire.h b/arch/sparc/include/asm/spitfire.h
index 985ea7e31992..f0d0c40c44da 100644
--- a/arch/sparc/include/asm/spitfire.h
+++ b/arch/sparc/include/asm/spitfire.h
@@ -6,6 +6,8 @@
#ifndef _SPARC64_SPITFIRE_H
#define _SPARC64_SPITFIRE_H
+#ifdef CONFIG_SPARC64
+
#include <asm/asi.h>
/* The following register addresses are accessible via ASI_DMMU
@@ -338,5 +340,5 @@ static inline void cheetah_put_itlb_data(int entry, unsigned long data)
}
#endif /* !(__ASSEMBLY__) */
-
+#endif /* CONFIG_SPARC64 */
#endif /* !(_SPARC64_SPITFIRE_H) */
diff --git a/arch/sparc/include/asm/system_32.h b/arch/sparc/include/asm/system_32.h
index 8623fc48fe24..79c1ae2b42a3 100644
--- a/arch/sparc/include/asm/system_32.h
+++ b/arch/sparc/include/asm/system_32.h
@@ -15,6 +15,11 @@
#include <linux/irqflags.h>
+static inline unsigned int probe_irq_mask(unsigned long val)
+{
+ return 0;
+}
+
/*
* Sparc (general) CPU types
*/
diff --git a/arch/sparc/include/asm/system_64.h b/arch/sparc/include/asm/system_64.h
index 8759f2a1b837..6c077816ab28 100644
--- a/arch/sparc/include/asm/system_64.h
+++ b/arch/sparc/include/asm/system_64.h
@@ -59,20 +59,9 @@ do { __asm__ __volatile__("ba,pt %%xcc, 1f\n\t" \
: : : "memory"); \
} while (0)
-#define mb() \
- membar_safe("#LoadLoad | #LoadStore | #StoreStore | #StoreLoad")
-#define rmb() \
- membar_safe("#LoadLoad")
-#define wmb() \
- membar_safe("#StoreStore")
-#define membar_storeload() \
- membar_safe("#StoreLoad")
-#define membar_storeload_storestore() \
- membar_safe("#StoreLoad | #StoreStore")
-#define membar_storeload_loadload() \
- membar_safe("#StoreLoad | #LoadLoad")
-#define membar_storestore_loadstore() \
- membar_safe("#StoreStore | #LoadStore")
+#define mb() membar_safe("#StoreLoad")
+#define rmb() __asm__ __volatile__("":::"memory")
+#define wmb() __asm__ __volatile__("":::"memory")
#endif
@@ -80,20 +69,20 @@ do { __asm__ __volatile__("ba,pt %%xcc, 1f\n\t" \
#define read_barrier_depends() do { } while(0)
#define set_mb(__var, __value) \
- do { __var = __value; membar_storeload_storestore(); } while(0)
+ do { __var = __value; membar_safe("#StoreLoad"); } while(0)
#ifdef CONFIG_SMP
#define smp_mb() mb()
#define smp_rmb() rmb()
#define smp_wmb() wmb()
-#define smp_read_barrier_depends() read_barrier_depends()
#else
#define smp_mb() __asm__ __volatile__("":::"memory")
#define smp_rmb() __asm__ __volatile__("":::"memory")
#define smp_wmb() __asm__ __volatile__("":::"memory")
-#define smp_read_barrier_depends() do { } while(0)
#endif
+#define smp_read_barrier_depends() do { } while(0)
+
#define flushi(addr) __asm__ __volatile__ ("flush %0" : : "r" (addr) : "memory")
#define flushw_all() __asm__ __volatile__("flushw")
@@ -107,11 +96,12 @@ do { __asm__ __volatile__("ba,pt %%xcc, 1f\n\t" \
* arch/sparc64/kernel/smp.c:smp_percpu_timer_interrupt()
* for more information.
*/
-#define reset_pic() \
- __asm__ __volatile__("ba,pt %xcc, 99f\n\t" \
+#define write_pic(__p) \
+ __asm__ __volatile__("ba,pt %%xcc, 99f\n\t" \
".align 64\n" \
- "99:wr %g0, 0x0, %pic\n\t" \
- "rd %pic, %g0")
+ "99:wr %0, 0x0, %%pic\n\t" \
+ "rd %%pic, %%g0" : : "r" (__p))
+#define reset_pic() write_pic(0)
#ifndef __ASSEMBLY__
@@ -170,6 +160,7 @@ do { if (test_thread_flag(TIF_PERFCTR)) { \
"stb %%o5, [%%g6 + %5]\n\t" \
"rdpr %%cwp, %%o5\n\t" \
"stb %%o5, [%%g6 + %8]\n\t" \
+ "wrpr %%g0, 15, %%pil\n\t" \
"mov %4, %%g6\n\t" \
"ldub [%4 + %8], %%g1\n\t" \
"wrpr %%g1, %%cwp\n\t" \
@@ -180,6 +171,7 @@ do { if (test_thread_flag(TIF_PERFCTR)) { \
"ldx [%%sp + 2047 + 0x70], %%i6\n\t" \
"ldx [%%sp + 2047 + 0x78], %%i7\n\t" \
"ldx [%%g6 + %9], %%g4\n\t" \
+ "wrpr %%g0, 14, %%pil\n\t" \
"brz,pt %%o7, switch_to_pc\n\t" \
" mov %%g7, %0\n\t" \
"sethi %%hi(ret_from_syscall), %%g1\n\t" \
@@ -209,14 +201,12 @@ static inline unsigned long xchg32(__volatile__ unsigned int *m, unsigned int va
unsigned long tmp1, tmp2;
__asm__ __volatile__(
-" membar #StoreLoad | #LoadLoad\n"
" mov %0, %1\n"
"1: lduw [%4], %2\n"
" cas [%4], %2, %0\n"
" cmp %2, %0\n"
" bne,a,pn %%icc, 1b\n"
" mov %1, %0\n"
-" membar #StoreLoad | #StoreStore\n"
: "=&r" (val), "=&r" (tmp1), "=&r" (tmp2)
: "0" (val), "r" (m)
: "cc", "memory");
@@ -228,14 +218,12 @@ static inline unsigned long xchg64(__volatile__ unsigned long *m, unsigned long
unsigned long tmp1, tmp2;
__asm__ __volatile__(
-" membar #StoreLoad | #LoadLoad\n"
" mov %0, %1\n"
"1: ldx [%4], %2\n"
" casx [%4], %2, %0\n"
" cmp %2, %0\n"
" bne,a,pn %%xcc, 1b\n"
" mov %1, %0\n"
-" membar #StoreLoad | #StoreStore\n"
: "=&r" (val), "=&r" (tmp1), "=&r" (tmp2)
: "0" (val), "r" (m)
: "cc", "memory");
@@ -272,9 +260,7 @@ extern void die_if_kernel(char *str, struct pt_regs *regs) __attribute__ ((noret
static inline unsigned long
__cmpxchg_u32(volatile int *m, int old, int new)
{
- __asm__ __volatile__("membar #StoreLoad | #LoadLoad\n"
- "cas [%2], %3, %0\n\t"
- "membar #StoreLoad | #StoreStore"
+ __asm__ __volatile__("cas [%2], %3, %0"
: "=&r" (new)
: "0" (new), "r" (m), "r" (old)
: "memory");
@@ -285,9 +271,7 @@ __cmpxchg_u32(volatile int *m, int old, int new)
static inline unsigned long
__cmpxchg_u64(volatile long *m, unsigned long old, unsigned long new)
{
- __asm__ __volatile__("membar #StoreLoad | #LoadLoad\n"
- "casx [%2], %3, %0\n\t"
- "membar #StoreLoad | #StoreStore"
+ __asm__ __volatile__("casx [%2], %3, %0"
: "=&r" (new)
: "0" (new), "r" (m), "r" (old)
: "memory");
diff --git a/arch/sparc/include/asm/tsb.h b/arch/sparc/include/asm/tsb.h
index 76e4299dd9bc..83c571d8c8a7 100644
--- a/arch/sparc/include/asm/tsb.h
+++ b/arch/sparc/include/asm/tsb.h
@@ -50,8 +50,6 @@
#define TSB_TAG_INVALID_BIT 46
#define TSB_TAG_INVALID_HIGH (1 << (TSB_TAG_INVALID_BIT - 32))
-#define TSB_MEMBAR membar #StoreStore
-
/* Some cpus support physical address quad loads. We want to use
* those if possible so we don't need to hard-lock the TSB mapping
* into the TLB. We encode some instruction patching in order to
@@ -128,13 +126,11 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;
cmp REG1, REG2; \
bne,pn %icc, 99b; \
nop; \
- TSB_MEMBAR
#define TSB_WRITE(TSB, TTE, TAG) \
add TSB, 0x8, TSB; \
TSB_STORE(TSB, TTE); \
sub TSB, 0x8, TSB; \
- TSB_MEMBAR; \
TSB_STORE(TSB, TAG);
#define KTSB_LOAD_QUAD(TSB, REG) \
@@ -153,13 +149,11 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;
cmp REG1, REG2; \
bne,pn %icc, 99b; \
nop; \
- TSB_MEMBAR
#define KTSB_WRITE(TSB, TTE, TAG) \
add TSB, 0x8, TSB; \
stxa TTE, [TSB] ASI_N; \
sub TSB, 0x8, TSB; \
- TSB_MEMBAR; \
stxa TAG, [TSB] ASI_N;
/* Do a kernel page table walk. Leaves physical PTE pointer in
diff --git a/arch/sparc/include/asm/ttable.h b/arch/sparc/include/asm/ttable.h
index 5708ba2719fb..48f2807d3265 100644
--- a/arch/sparc/include/asm/ttable.h
+++ b/arch/sparc/include/asm/ttable.h
@@ -2,6 +2,7 @@
#define _SPARC64_TTABLE_H
#include <asm/utrap.h>
+#include <asm/pil.h>
#ifdef __ASSEMBLY__
#include <asm/thread_info.h>
@@ -123,7 +124,7 @@
#define TRAP_IRQ(routine, level) \
rdpr %pil, %g2; \
- wrpr %g0, 15, %pil; \
+ wrpr %g0, PIL_NORMAL_MAX, %pil; \
sethi %hi(1f-4), %g7; \
ba,pt %xcc, etrap_irq; \
or %g7, %lo(1f-4), %g7; \
@@ -143,7 +144,7 @@
#define TRAP_IRQ(routine, level) \
rdpr %pil, %g2; \
- wrpr %g0, 15, %pil; \
+ wrpr %g0, PIL_NORMAL_MAX, %pil; \
ba,pt %xcc, etrap_irq; \
rd %pc, %g7; \
mov level, %o0; \
@@ -153,6 +154,16 @@
#endif
+#define TRAP_NMI_IRQ(routine, level) \
+ rdpr %pil, %g2; \
+ wrpr %g0, PIL_NMI, %pil; \
+ ba,pt %xcc, etrap_irq; \
+ rd %pc, %g7; \
+ mov level, %o0; \
+ call routine; \
+ add %sp, PTREGS_OFF, %o1; \
+ ba,a,pt %xcc, rtrap_nmi;
+
#define TRAP_IVEC TRAP_NOSAVE(do_ivec)
#define BTRAP(lvl) TRAP_ARG(bad_trap, lvl)
diff --git a/arch/sparc/include/asm/unistd.h b/arch/sparc/include/asm/unistd.h
index 4207fb362da0..031f038b19f7 100644
--- a/arch/sparc/include/asm/unistd.h
+++ b/arch/sparc/include/asm/unistd.h
@@ -1,8 +1,444 @@
-#ifndef ___ASM_SPARC_UNISTD_H
-#define ___ASM_SPARC_UNISTD_H
-#if defined(__sparc__) && defined(__arch64__)
-#include <asm/unistd_64.h>
+#ifndef _SPARC_UNISTD_H
+#define _SPARC_UNISTD_H
+
+/*
+ * System calls under the Sparc.
+ *
+ * Don't be scared by the ugly clobbers, it is the only way I can
+ * think of right now to force the arguments into fixed registers
+ * before the trap into the system call with gcc 'asm' statements.
+ *
+ * Copyright (C) 1995, 2007 David S. Miller (davem@davemloft.net)
+ *
+ * SunOS compatibility based upon preliminary work which is:
+ *
+ * Copyright (C) 1995 Adrian M. Rodriguez (adrian@remus.rutgers.edu)
+ */
+#ifndef __32bit_syscall_numbers__
+#ifndef __arch64__
+#define __32bit_syscall_numbers__
+#endif
+#endif
+
+#define __NR_restart_syscall 0 /* Linux Specific */
+#define __NR_exit 1 /* Common */
+#define __NR_fork 2 /* Common */
+#define __NR_read 3 /* Common */
+#define __NR_write 4 /* Common */
+#define __NR_open 5 /* Common */
+#define __NR_close 6 /* Common */
+#define __NR_wait4 7 /* Common */
+#define __NR_creat 8 /* Common */
+#define __NR_link 9 /* Common */
+#define __NR_unlink 10 /* Common */
+#define __NR_execv 11 /* SunOS Specific */
+#define __NR_chdir 12 /* Common */
+#define __NR_chown 13 /* Common */
+#define __NR_mknod 14 /* Common */
+#define __NR_chmod 15 /* Common */
+#define __NR_lchown 16 /* Common */
+#define __NR_brk 17 /* Common */
+#define __NR_perfctr 18 /* Performance counter operations */
+#define __NR_lseek 19 /* Common */
+#define __NR_getpid 20 /* Common */
+#define __NR_capget 21 /* Linux Specific */
+#define __NR_capset 22 /* Linux Specific */
+#define __NR_setuid 23 /* Implemented via setreuid in SunOS */
+#define __NR_getuid 24 /* Common */
+#define __NR_vmsplice 25 /* ENOSYS under SunOS */
+#define __NR_ptrace 26 /* Common */
+#define __NR_alarm 27 /* Implemented via setitimer in SunOS */
+#define __NR_sigaltstack 28 /* Common */
+#define __NR_pause 29 /* Is sigblock(0)->sigpause() in SunOS */
+#define __NR_utime 30 /* Implemented via utimes() under SunOS */
+#ifdef __32bit_syscall_numbers__
+#define __NR_lchown32 31 /* Linux sparc32 specific */
+#define __NR_fchown32 32 /* Linux sparc32 specific */
+#endif
+#define __NR_access 33 /* Common */
+#define __NR_nice 34 /* Implemented via get/setpriority() in SunOS */
+#ifdef __32bit_syscall_numbers__
+#define __NR_chown32 35 /* Linux sparc32 specific */
+#endif
+#define __NR_sync 36 /* Common */
+#define __NR_kill 37 /* Common */
+#define __NR_stat 38 /* Common */
+#define __NR_sendfile 39 /* Linux Specific */
+#define __NR_lstat 40 /* Common */
+#define __NR_dup 41 /* Common */
+#define __NR_pipe 42 /* Common */
+#define __NR_times 43 /* Implemented via getrusage() in SunOS */
+#ifdef __32bit_syscall_numbers__
+#define __NR_getuid32 44 /* Linux sparc32 specific */
+#endif
+#define __NR_umount2 45 /* Linux Specific */
+#define __NR_setgid 46 /* Implemented via setregid() in SunOS */
+#define __NR_getgid 47 /* Common */
+#define __NR_signal 48 /* Implemented via sigvec() in SunOS */
+#define __NR_geteuid 49 /* SunOS calls getuid() */
+#define __NR_getegid 50 /* SunOS calls getgid() */
+#define __NR_acct 51 /* Common */
+#ifdef __32bit_syscall_numbers__
+#define __NR_getgid32 53 /* Linux sparc32 specific */
+#else
+#define __NR_memory_ordering 52 /* Linux Specific */
+#endif
+#define __NR_ioctl 54 /* Common */
+#define __NR_reboot 55 /* Common */
+#ifdef __32bit_syscall_numbers__
+#define __NR_mmap2 56 /* Linux sparc32 Specific */
+#endif
+#define __NR_symlink 57 /* Common */
+#define __NR_readlink 58 /* Common */
+#define __NR_execve 59 /* Common */
+#define __NR_umask 60 /* Common */
+#define __NR_chroot 61 /* Common */
+#define __NR_fstat 62 /* Common */
+#define __NR_fstat64 63 /* Linux Specific */
+#define __NR_getpagesize 64 /* Common */
+#define __NR_msync 65 /* Common in newer 1.3.x revs... */
+#define __NR_vfork 66 /* Common */
+#define __NR_pread64 67 /* Linux Specific */
+#define __NR_pwrite64 68 /* Linux Specific */
+#ifdef __32bit_syscall_numbers__
+#define __NR_geteuid32 69 /* Linux sparc32, sbrk under SunOS */
+#define __NR_getegid32 70 /* Linux sparc32, sstk under SunOS */
+#endif
+#define __NR_mmap 71 /* Common */
+#ifdef __32bit_syscall_numbers__
+#define __NR_setreuid32 72 /* Linux sparc32, vadvise under SunOS */
+#endif
+#define __NR_munmap 73 /* Common */
+#define __NR_mprotect 74 /* Common */
+#define __NR_madvise 75 /* Common */
+#define __NR_vhangup 76 /* Common */
+#ifdef __32bit_syscall_numbers__
+#define __NR_truncate64 77 /* Linux sparc32 Specific */
+#endif
+#define __NR_mincore 78 /* Common */
+#define __NR_getgroups 79 /* Common */
+#define __NR_setgroups 80 /* Common */
+#define __NR_getpgrp 81 /* Common */
+#ifdef __32bit_syscall_numbers__
+#define __NR_setgroups32 82 /* Linux sparc32, setpgrp under SunOS */
+#endif
+#define __NR_setitimer 83 /* Common */
+#ifdef __32bit_syscall_numbers__
+#define __NR_ftruncate64 84 /* Linux sparc32 Specific */
+#endif
+#define __NR_swapon 85 /* Common */
+#define __NR_getitimer 86 /* Common */
+#ifdef __32bit_syscall_numbers__
+#define __NR_setuid32 87 /* Linux sparc32, gethostname under SunOS */
+#endif
+#define __NR_sethostname 88 /* Common */
+#ifdef __32bit_syscall_numbers__
+#define __NR_setgid32 89 /* Linux sparc32, getdtablesize under SunOS */
+#endif
+#define __NR_dup2 90 /* Common */
+#ifdef __32bit_syscall_numbers__
+#define __NR_setfsuid32 91 /* Linux sparc32, getdopt under SunOS */
+#endif
+#define __NR_fcntl 92 /* Common */
+#define __NR_select 93 /* Common */
+#ifdef __32bit_syscall_numbers__
+#define __NR_setfsgid32 94 /* Linux sparc32, setdopt under SunOS */
+#endif
+#define __NR_fsync 95 /* Common */
+#define __NR_setpriority 96 /* Common */
+#define __NR_socket 97 /* Common */
+#define __NR_connect 98 /* Common */
+#define __NR_accept 99 /* Common */
+#define __NR_getpriority 100 /* Common */
+#define __NR_rt_sigreturn 101 /* Linux Specific */
+#define __NR_rt_sigaction 102 /* Linux Specific */
+#define __NR_rt_sigprocmask 103 /* Linux Specific */
+#define __NR_rt_sigpending 104 /* Linux Specific */
+#define __NR_rt_sigtimedwait 105 /* Linux Specific */
+#define __NR_rt_sigqueueinfo 106 /* Linux Specific */
+#define __NR_rt_sigsuspend 107 /* Linux Specific */
+#ifdef __32bit_syscall_numbers__
+#define __NR_setresuid32 108 /* Linux Specific, sigvec under SunOS */
+#define __NR_getresuid32 109 /* Linux Specific, sigblock under SunOS */
+#define __NR_setresgid32 110 /* Linux Specific, sigsetmask under SunOS */
+#define __NR_getresgid32 111 /* Linux Specific, sigpause under SunOS */
+#define __NR_setregid32 112 /* Linux sparc32, sigstack under SunOS */
+#else
+#define __NR_setresuid 108 /* Linux Specific, sigvec under SunOS */
+#define __NR_getresuid 109 /* Linux Specific, sigblock under SunOS */
+#define __NR_setresgid 110 /* Linux Specific, sigsetmask under SunOS */
+#define __NR_getresgid 111 /* Linux Specific, sigpause under SunOS */
+#endif
+#define __NR_recvmsg 113 /* Common */
+#define __NR_sendmsg 114 /* Common */
+#ifdef __32bit_syscall_numbers__
+#define __NR_getgroups32 115 /* Linux sparc32, vtrace under SunOS */
+#endif
+#define __NR_gettimeofday 116 /* Common */
+#define __NR_getrusage 117 /* Common */
+#define __NR_getsockopt 118 /* Common */
+#define __NR_getcwd 119 /* Linux Specific */
+#define __NR_readv 120 /* Common */
+#define __NR_writev 121 /* Common */
+#define __NR_settimeofday 122 /* Common */
+#define __NR_fchown 123 /* Common */
+#define __NR_fchmod 124 /* Common */
+#define __NR_recvfrom 125 /* Common */
+#define __NR_setreuid 126 /* Common */
+#define __NR_setregid 127 /* Common */
+#define __NR_rename 128 /* Common */
+#define __NR_truncate 129 /* Common */
+#define __NR_ftruncate 130 /* Common */
+#define __NR_flock 131 /* Common */
+#define __NR_lstat64 132 /* Linux Specific */
+#define __NR_sendto 133 /* Common */
+#define __NR_shutdown 134 /* Common */
+#define __NR_socketpair 135 /* Common */
+#define __NR_mkdir 136 /* Common */
+#define __NR_rmdir 137 /* Common */
+#define __NR_utimes 138 /* SunOS Specific */
+#define __NR_stat64 139 /* Linux Specific */
+#define __NR_sendfile64 140 /* adjtime under SunOS */
+#define __NR_getpeername 141 /* Common */
+#define __NR_futex 142 /* gethostid under SunOS */
+#define __NR_gettid 143 /* ENOSYS under SunOS */
+#define __NR_getrlimit 144 /* Common */
+#define __NR_setrlimit 145 /* Common */
+#define __NR_pivot_root 146 /* Linux Specific, killpg under SunOS */
+#define __NR_prctl 147 /* ENOSYS under SunOS */
+#define __NR_pciconfig_read 148 /* ENOSYS under SunOS */
+#define __NR_pciconfig_write 149 /* ENOSYS under SunOS */
+#define __NR_getsockname 150 /* Common */
+#define __NR_inotify_init 151 /* Linux specific */
+#define __NR_inotify_add_watch 152 /* Linux specific */
+#define __NR_poll 153 /* Common */
+#define __NR_getdents64 154 /* Linux specific */
+#ifdef __32bit_syscall_numbers__
+#define __NR_fcntl64 155 /* Linux sparc32 Specific */
+#endif
+#define __NR_inotify_rm_watch 156 /* Linux specific */
+#define __NR_statfs 157 /* Common */
+#define __NR_fstatfs 158 /* Common */
+#define __NR_umount 159 /* Common */
+#define __NR_sched_set_affinity 160 /* Linux specific, async_daemon under SunOS */
+#define __NR_sched_get_affinity 161 /* Linux specific, getfh under SunOS */
+#define __NR_getdomainname 162 /* SunOS Specific */
+#define __NR_setdomainname 163 /* Common */
+#ifndef __32bit_syscall_numbers__
+#define __NR_utrap_install 164 /* SYSV ABI/v9 required */
+#endif
+#define __NR_quotactl 165 /* Common */
+#define __NR_set_tid_address 166 /* Linux specific, exportfs under SunOS */
+#define __NR_mount 167 /* Common */
+#define __NR_ustat 168 /* Common */
+#define __NR_setxattr 169 /* SunOS: semsys */
+#define __NR_lsetxattr 170 /* SunOS: msgsys */
+#define __NR_fsetxattr 171 /* SunOS: shmsys */
+#define __NR_getxattr 172 /* SunOS: auditsys */
+#define __NR_lgetxattr 173 /* SunOS: rfssys */
+#define __NR_getdents 174 /* Common */
+#define __NR_setsid 175 /* Common */
+#define __NR_fchdir 176 /* Common */
+#define __NR_fgetxattr 177 /* SunOS: fchroot */
+#define __NR_listxattr 178 /* SunOS: vpixsys */
+#define __NR_llistxattr 179 /* SunOS: aioread */
+#define __NR_flistxattr 180 /* SunOS: aiowrite */
+#define __NR_removexattr 181 /* SunOS: aiowait */
+#define __NR_lremovexattr 182 /* SunOS: aiocancel */
+#define __NR_sigpending 183 /* Common */
+#define __NR_query_module 184 /* Linux Specific */
+#define __NR_setpgid 185 /* Common */
+#define __NR_fremovexattr 186 /* SunOS: pathconf */
+#define __NR_tkill 187 /* SunOS: fpathconf */
+#define __NR_exit_group 188 /* Linux specific, sysconf undef SunOS */
+#define __NR_uname 189 /* Linux Specific */
+#define __NR_init_module 190 /* Linux Specific */
+#define __NR_personality 191 /* Linux Specific */
+#define __NR_remap_file_pages 192 /* Linux Specific */
+#define __NR_epoll_create 193 /* Linux Specific */
+#define __NR_epoll_ctl 194 /* Linux Specific */
+#define __NR_epoll_wait 195 /* Linux Specific */
+#define __NR_ioprio_set 196 /* Linux Specific */
+#define __NR_getppid 197 /* Linux Specific */
+#define __NR_sigaction 198 /* Linux Specific */
+#define __NR_sgetmask 199 /* Linux Specific */
+#define __NR_ssetmask 200 /* Linux Specific */
+#define __NR_sigsuspend 201 /* Linux Specific */
+#define __NR_oldlstat 202 /* Linux Specific */
+#define __NR_uselib 203 /* Linux Specific */
+#define __NR_readdir 204 /* Linux Specific */
+#define __NR_readahead 205 /* Linux Specific */
+#define __NR_socketcall 206 /* Linux Specific */
+#define __NR_syslog 207 /* Linux Specific */
+#define __NR_lookup_dcookie 208 /* Linux Specific */
+#define __NR_fadvise64 209 /* Linux Specific */
+#define __NR_fadvise64_64 210 /* Linux Specific */
+#define __NR_tgkill 211 /* Linux Specific */
+#define __NR_waitpid 212 /* Linux Specific */
+#define __NR_swapoff 213 /* Linux Specific */
+#define __NR_sysinfo 214 /* Linux Specific */
+#define __NR_ipc 215 /* Linux Specific */
+#define __NR_sigreturn 216 /* Linux Specific */
+#define __NR_clone 217 /* Linux Specific */
+#define __NR_ioprio_get 218 /* Linux Specific */
+#define __NR_adjtimex 219 /* Linux Specific */
+#define __NR_sigprocmask 220 /* Linux Specific */
+#define __NR_create_module 221 /* Linux Specific */
+#define __NR_delete_module 222 /* Linux Specific */
+#define __NR_get_kernel_syms 223 /* Linux Specific */
+#define __NR_getpgid 224 /* Linux Specific */
+#define __NR_bdflush 225 /* Linux Specific */
+#define __NR_sysfs 226 /* Linux Specific */
+#define __NR_afs_syscall 227 /* Linux Specific */
+#define __NR_setfsuid 228 /* Linux Specific */
+#define __NR_setfsgid 229 /* Linux Specific */
+#define __NR__newselect 230 /* Linux Specific */
+#ifdef __32bit_syscall_numbers__
+#define __NR_time 231 /* Linux Specific */
#else
-#include <asm/unistd_32.h>
+#ifdef __KERNEL__
+#define __NR_time 231 /* Linux sparc32 */
+#endif
+#endif
+#define __NR_splice 232 /* Linux Specific */
+#define __NR_stime 233 /* Linux Specific */
+#define __NR_statfs64 234 /* Linux Specific */
+#define __NR_fstatfs64 235 /* Linux Specific */
+#define __NR__llseek 236 /* Linux Specific */
+#define __NR_mlock 237
+#define __NR_munlock 238
+#define __NR_mlockall 239
+#define __NR_munlockall 240
+#define __NR_sched_setparam 241
+#define __NR_sched_getparam 242
+#define __NR_sched_setscheduler 243
+#define __NR_sched_getscheduler 244
+#define __NR_sched_yield 245
+#define __NR_sched_get_priority_max 246
+#define __NR_sched_get_priority_min 247
+#define __NR_sched_rr_get_interval 248
+#define __NR_nanosleep 249
+#define __NR_mremap 250
+#define __NR__sysctl 251
+#define __NR_getsid 252
+#define __NR_fdatasync 253
+#define __NR_nfsservctl 254
+#define __NR_sync_file_range 255
+#define __NR_clock_settime 256
+#define __NR_clock_gettime 257
+#define __NR_clock_getres 258
+#define __NR_clock_nanosleep 259
+#define __NR_sched_getaffinity 260
+#define __NR_sched_setaffinity 261
+#define __NR_timer_settime 262
+#define __NR_timer_gettime 263
+#define __NR_timer_getoverrun 264
+#define __NR_timer_delete 265
+#define __NR_timer_create 266
+/* #define __NR_vserver 267 Reserved for VSERVER */
+#define __NR_io_setup 268
+#define __NR_io_destroy 269
+#define __NR_io_submit 270
+#define __NR_io_cancel 271
+#define __NR_io_getevents 272
+#define __NR_mq_open 273
+#define __NR_mq_unlink 274
+#define __NR_mq_timedsend 275
+#define __NR_mq_timedreceive 276
+#define __NR_mq_notify 277
+#define __NR_mq_getsetattr 278
+#define __NR_waitid 279
+#define __NR_tee 280
+#define __NR_add_key 281
+#define __NR_request_key 282
+#define __NR_keyctl 283
+#define __NR_openat 284
+#define __NR_mkdirat 285
+#define __NR_mknodat 286
+#define __NR_fchownat 287
+#define __NR_futimesat 288
+#define __NR_fstatat64 289
+#define __NR_unlinkat 290
+#define __NR_renameat 291
+#define __NR_linkat 292
+#define __NR_symlinkat 293
+#define __NR_readlinkat 294
+#define __NR_fchmodat 295
+#define __NR_faccessat 296
+#define __NR_pselect6 297
+#define __NR_ppoll 298
+#define __NR_unshare 299
+#define __NR_set_robust_list 300
+#define __NR_get_robust_list 301
+#define __NR_migrate_pages 302
+#define __NR_mbind 303
+#define __NR_get_mempolicy 304
+#define __NR_set_mempolicy 305
+#define __NR_kexec_load 306
+#define __NR_move_pages 307
+#define __NR_getcpu 308
+#define __NR_epoll_pwait 309
+#define __NR_utimensat 310
+#define __NR_signalfd 311
+#define __NR_timerfd_create 312
+#define __NR_eventfd 313
+#define __NR_fallocate 314
+#define __NR_timerfd_settime 315
+#define __NR_timerfd_gettime 316
+#define __NR_signalfd4 317
+#define __NR_eventfd2 318
+#define __NR_epoll_create1 319
+#define __NR_dup3 320
+#define __NR_pipe2 321
+#define __NR_inotify_init1 322
+#define __NR_accept4 323
+
+#define NR_SYSCALLS 324
+
+#ifdef __32bit_syscall_numbers__
+/* Sparc 32-bit only has the "setresuid32", "getresuid32" variants,
+ * it never had the plain ones and there is no value to adding those
+ * old versions into the syscall table.
+ */
+#define __IGNORE_setresuid
+#define __IGNORE_getresuid
+#define __IGNORE_setresgid
+#define __IGNORE_getresgid
#endif
+
+#ifdef __KERNEL__
+#define __ARCH_WANT_IPC_PARSE_VERSION
+#define __ARCH_WANT_OLD_READDIR
+#define __ARCH_WANT_STAT64
+#define __ARCH_WANT_SYS_ALARM
+#define __ARCH_WANT_SYS_GETHOSTNAME
+#define __ARCH_WANT_SYS_PAUSE
+#define __ARCH_WANT_SYS_SGETMASK
+#define __ARCH_WANT_SYS_SIGNAL
+#define __ARCH_WANT_SYS_TIME
+#define __ARCH_WANT_SYS_UTIME
+#define __ARCH_WANT_SYS_WAITPID
+#define __ARCH_WANT_SYS_SOCKETCALL
+#define __ARCH_WANT_SYS_FADVISE64
+#define __ARCH_WANT_SYS_GETPGRP
+#define __ARCH_WANT_SYS_LLSEEK
+#define __ARCH_WANT_SYS_NICE
+#define __ARCH_WANT_SYS_OLDUMOUNT
+#define __ARCH_WANT_SYS_SIGPENDING
+#define __ARCH_WANT_SYS_SIGPROCMASK
+#define __ARCH_WANT_SYS_RT_SIGSUSPEND
+#ifndef __32bit_syscall_numbers__
+#define __ARCH_WANT_COMPAT_SYS_TIME
+#define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
#endif
+
+/*
+ * "Conditional" syscalls
+ *
+ * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
+ * but it doesn't work on all toolchains, so we just do it by hand
+ */
+#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
+
+#endif /* __KERNEL__ */
+#endif /* _SPARC_UNISTD_H */
diff --git a/arch/sparc/include/asm/unistd_32.h b/arch/sparc/include/asm/unistd_32.h
deleted file mode 100644
index 0d13d2a4c76f..000000000000
--- a/arch/sparc/include/asm/unistd_32.h
+++ /dev/null
@@ -1,385 +0,0 @@
-#ifndef _SPARC_UNISTD_H
-#define _SPARC_UNISTD_H
-
-/*
- * System calls under the Sparc.
- *
- * Don't be scared by the ugly clobbers, it is the only way I can
- * think of right now to force the arguments into fixed registers
- * before the trap into the system call with gcc 'asm' statements.
- *
- * Copyright (C) 1995, 2007 David S. Miller (davem@davemloft.net)
- *
- * SunOS compatibility based upon preliminary work which is:
- *
- * Copyright (C) 1995 Adrian M. Rodriguez (adrian@remus.rutgers.edu)
- */
-
-#define __NR_restart_syscall 0 /* Linux Specific */
-#define __NR_exit 1 /* Common */
-#define __NR_fork 2 /* Common */
-#define __NR_read 3 /* Common */
-#define __NR_write 4 /* Common */
-#define __NR_open 5 /* Common */
-#define __NR_close 6 /* Common */
-#define __NR_wait4 7 /* Common */
-#define __NR_creat 8 /* Common */
-#define __NR_link 9 /* Common */
-#define __NR_unlink 10 /* Common */
-#define __NR_execv 11 /* SunOS Specific */
-#define __NR_chdir 12 /* Common */
-#define __NR_chown 13 /* Common */
-#define __NR_mknod 14 /* Common */
-#define __NR_chmod 15 /* Common */
-#define __NR_lchown 16 /* Common */
-#define __NR_brk 17 /* Common */
-#define __NR_perfctr 18 /* Performance counter operations */
-#define __NR_lseek 19 /* Common */
-#define __NR_getpid 20 /* Common */
-#define __NR_capget 21 /* Linux Specific */
-#define __NR_capset 22 /* Linux Specific */
-#define __NR_setuid 23 /* Implemented via setreuid in SunOS */
-#define __NR_getuid 24 /* Common */
-#define __NR_vmsplice 25 /* ENOSYS under SunOS */
-#define __NR_ptrace 26 /* Common */
-#define __NR_alarm 27 /* Implemented via setitimer in SunOS */
-#define __NR_sigaltstack 28 /* Common */
-#define __NR_pause 29 /* Is sigblock(0)->sigpause() in SunOS */
-#define __NR_utime 30 /* Implemented via utimes() under SunOS */
-#define __NR_lchown32 31 /* Linux sparc32 specific */
-#define __NR_fchown32 32 /* Linux sparc32 specific */
-#define __NR_access 33 /* Common */
-#define __NR_nice 34 /* Implemented via get/setpriority() in SunOS */
-#define __NR_chown32 35 /* Linux sparc32 specific */
-#define __NR_sync 36 /* Common */
-#define __NR_kill 37 /* Common */
-#define __NR_stat 38 /* Common */
-#define __NR_sendfile 39 /* Linux Specific */
-#define __NR_lstat 40 /* Common */
-#define __NR_dup 41 /* Common */
-#define __NR_pipe 42 /* Common */
-#define __NR_times 43 /* Implemented via getrusage() in SunOS */
-#define __NR_getuid32 44 /* Linux sparc32 specific */
-#define __NR_umount2 45 /* Linux Specific */
-#define __NR_setgid 46 /* Implemented via setregid() in SunOS */
-#define __NR_getgid 47 /* Common */
-#define __NR_signal 48 /* Implemented via sigvec() in SunOS */
-#define __NR_geteuid 49 /* SunOS calls getuid() */
-#define __NR_getegid 50 /* SunOS calls getgid() */
-#define __NR_acct 51 /* Common */
-/* #define __NR_memory_ordering 52 Linux sparc64 specific */
-#define __NR_getgid32 53 /* Linux sparc32 specific */
-#define __NR_ioctl 54 /* Common */
-#define __NR_reboot 55 /* Common */
-#define __NR_mmap2 56 /* Linux sparc32 Specific */
-#define __NR_symlink 57 /* Common */
-#define __NR_readlink 58 /* Common */
-#define __NR_execve 59 /* Common */
-#define __NR_umask 60 /* Common */
-#define __NR_chroot 61 /* Common */
-#define __NR_fstat 62 /* Common */
-#define __NR_fstat64 63 /* Linux Specific */
-#define __NR_getpagesize 64 /* Common */
-#define __NR_msync 65 /* Common in newer 1.3.x revs... */
-#define __NR_vfork 66 /* Common */
-#define __NR_pread64 67 /* Linux Specific */
-#define __NR_pwrite64 68 /* Linux Specific */
-#define __NR_geteuid32 69 /* Linux sparc32, sbrk under SunOS */
-#define __NR_getegid32 70 /* Linux sparc32, sstk under SunOS */
-#define __NR_mmap 71 /* Common */
-#define __NR_setreuid32 72 /* Linux sparc32, vadvise under SunOS */
-#define __NR_munmap 73 /* Common */
-#define __NR_mprotect 74 /* Common */
-#define __NR_madvise 75 /* Common */
-#define __NR_vhangup 76 /* Common */
-#define __NR_truncate64 77 /* Linux sparc32 Specific */
-#define __NR_mincore 78 /* Common */
-#define __NR_getgroups 79 /* Common */
-#define __NR_setgroups 80 /* Common */
-#define __NR_getpgrp 81 /* Common */
-#define __NR_setgroups32 82 /* Linux sparc32, setpgrp under SunOS */
-#define __NR_setitimer 83 /* Common */
-#define __NR_ftruncate64 84 /* Linux sparc32 Specific */
-#define __NR_swapon 85 /* Common */
-#define __NR_getitimer 86 /* Common */
-#define __NR_setuid32 87 /* Linux sparc32, gethostname under SunOS */
-#define __NR_sethostname 88 /* Common */
-#define __NR_setgid32 89 /* Linux sparc32, getdtablesize under SunOS */
-#define __NR_dup2 90 /* Common */
-#define __NR_setfsuid32 91 /* Linux sparc32, getdopt under SunOS */
-#define __NR_fcntl 92 /* Common */
-#define __NR_select 93 /* Common */
-#define __NR_setfsgid32 94 /* Linux sparc32, setdopt under SunOS */
-#define __NR_fsync 95 /* Common */
-#define __NR_setpriority 96 /* Common */
-#define __NR_socket 97 /* Common */
-#define __NR_connect 98 /* Common */
-#define __NR_accept 99 /* Common */
-#define __NR_getpriority 100 /* Common */
-#define __NR_rt_sigreturn 101 /* Linux Specific */
-#define __NR_rt_sigaction 102 /* Linux Specific */
-#define __NR_rt_sigprocmask 103 /* Linux Specific */
-#define __NR_rt_sigpending 104 /* Linux Specific */
-#define __NR_rt_sigtimedwait 105 /* Linux Specific */
-#define __NR_rt_sigqueueinfo 106 /* Linux Specific */
-#define __NR_rt_sigsuspend 107 /* Linux Specific */
-#define __NR_setresuid32 108 /* Linux Specific, sigvec under SunOS */
-#define __NR_getresuid32 109 /* Linux Specific, sigblock under SunOS */
-#define __NR_setresgid32 110 /* Linux Specific, sigsetmask under SunOS */
-#define __NR_getresgid32 111 /* Linux Specific, sigpause under SunOS */
-#define __NR_setregid32 112 /* Linux sparc32, sigstack under SunOS */
-#define __NR_recvmsg 113 /* Common */
-#define __NR_sendmsg 114 /* Common */
-#define __NR_getgroups32 115 /* Linux sparc32, vtrace under SunOS */
-#define __NR_gettimeofday 116 /* Common */
-#define __NR_getrusage 117 /* Common */
-#define __NR_getsockopt 118 /* Common */
-#define __NR_getcwd 119 /* Linux Specific */
-#define __NR_readv 120 /* Common */
-#define __NR_writev 121 /* Common */
-#define __NR_settimeofday 122 /* Common */
-#define __NR_fchown 123 /* Common */
-#define __NR_fchmod 124 /* Common */
-#define __NR_recvfrom 125 /* Common */
-#define __NR_setreuid 126 /* Common */
-#define __NR_setregid 127 /* Common */
-#define __NR_rename 128 /* Common */
-#define __NR_truncate 129 /* Common */
-#define __NR_ftruncate 130 /* Common */
-#define __NR_flock 131 /* Common */
-#define __NR_lstat64 132 /* Linux Specific */
-#define __NR_sendto 133 /* Common */
-#define __NR_shutdown 134 /* Common */
-#define __NR_socketpair 135 /* Common */
-#define __NR_mkdir 136 /* Common */
-#define __NR_rmdir 137 /* Common */
-#define __NR_utimes 138 /* SunOS Specific */
-#define __NR_stat64 139 /* Linux Specific */
-#define __NR_sendfile64 140 /* adjtime under SunOS */
-#define __NR_getpeername 141 /* Common */
-#define __NR_futex 142 /* gethostid under SunOS */
-#define __NR_gettid 143 /* ENOSYS under SunOS */
-#define __NR_getrlimit 144 /* Common */
-#define __NR_setrlimit 145 /* Common */
-#define __NR_pivot_root 146 /* Linux Specific, killpg under SunOS */
-#define __NR_prctl 147 /* ENOSYS under SunOS */
-#define __NR_pciconfig_read 148 /* ENOSYS under SunOS */
-#define __NR_pciconfig_write 149 /* ENOSYS under SunOS */
-#define __NR_getsockname 150 /* Common */
-#define __NR_inotify_init 151 /* Linux specific */
-#define __NR_inotify_add_watch 152 /* Linux specific */
-#define __NR_poll 153 /* Common */
-#define __NR_getdents64 154 /* Linux specific */
-#define __NR_fcntl64 155 /* Linux sparc32 Specific */
-#define __NR_inotify_rm_watch 156 /* Linux specific */
-#define __NR_statfs 157 /* Common */
-#define __NR_fstatfs 158 /* Common */
-#define __NR_umount 159 /* Common */
-#define __NR_sched_set_affinity 160 /* Linux specific, async_daemon under SunOS */
-#define __NR_sched_get_affinity 161 /* Linux specific, getfh under SunOS */
-#define __NR_getdomainname 162 /* SunOS Specific */
-#define __NR_setdomainname 163 /* Common */
-/* #define __NR_utrap_install 164 Linux sparc64 specific */
-#define __NR_quotactl 165 /* Common */
-#define __NR_set_tid_address 166 /* Linux specific, exportfs under SunOS */
-#define __NR_mount 167 /* Common */
-#define __NR_ustat 168 /* Common */
-#define __NR_setxattr 169 /* SunOS: semsys */
-#define __NR_lsetxattr 170 /* SunOS: msgsys */
-#define __NR_fsetxattr 171 /* SunOS: shmsys */
-#define __NR_getxattr 172 /* SunOS: auditsys */
-#define __NR_lgetxattr 173 /* SunOS: rfssys */
-#define __NR_getdents 174 /* Common */
-#define __NR_setsid 175 /* Common */
-#define __NR_fchdir 176 /* Common */
-#define __NR_fgetxattr 177 /* SunOS: fchroot */
-#define __NR_listxattr 178 /* SunOS: vpixsys */
-#define __NR_llistxattr 179 /* SunOS: aioread */
-#define __NR_flistxattr 180 /* SunOS: aiowrite */
-#define __NR_removexattr 181 /* SunOS: aiowait */
-#define __NR_lremovexattr 182 /* SunOS: aiocancel */
-#define __NR_sigpending 183 /* Common */
-#define __NR_query_module 184 /* Linux Specific */
-#define __NR_setpgid 185 /* Common */
-#define __NR_fremovexattr 186 /* SunOS: pathconf */
-#define __NR_tkill 187 /* SunOS: fpathconf */
-#define __NR_exit_group 188 /* Linux specific, sysconf undef SunOS */
-#define __NR_uname 189 /* Linux Specific */
-#define __NR_init_module 190 /* Linux Specific */
-#define __NR_personality 191 /* Linux Specific */
-#define __NR_remap_file_pages 192 /* Linux Specific */
-#define __NR_epoll_create 193 /* Linux Specific */
-#define __NR_epoll_ctl 194 /* Linux Specific */
-#define __NR_epoll_wait 195 /* Linux Specific */
-#define __NR_ioprio_set 196 /* Linux Specific */
-#define __NR_getppid 197 /* Linux Specific */
-#define __NR_sigaction 198 /* Linux Specific */
-#define __NR_sgetmask 199 /* Linux Specific */
-#define __NR_ssetmask 200 /* Linux Specific */
-#define __NR_sigsuspend 201 /* Linux Specific */
-#define __NR_oldlstat 202 /* Linux Specific */
-#define __NR_uselib 203 /* Linux Specific */
-#define __NR_readdir 204 /* Linux Specific */
-#define __NR_readahead 205 /* Linux Specific */
-#define __NR_socketcall 206 /* Linux Specific */
-#define __NR_syslog 207 /* Linux Specific */
-#define __NR_lookup_dcookie 208 /* Linux Specific */
-#define __NR_fadvise64 209 /* Linux Specific */
-#define __NR_fadvise64_64 210 /* Linux Specific */
-#define __NR_tgkill 211 /* Linux Specific */
-#define __NR_waitpid 212 /* Linux Specific */
-#define __NR_swapoff 213 /* Linux Specific */
-#define __NR_sysinfo 214 /* Linux Specific */
-#define __NR_ipc 215 /* Linux Specific */
-#define __NR_sigreturn 216 /* Linux Specific */
-#define __NR_clone 217 /* Linux Specific */
-#define __NR_ioprio_get 218 /* Linux Specific */
-#define __NR_adjtimex 219 /* Linux Specific */
-#define __NR_sigprocmask 220 /* Linux Specific */
-#define __NR_create_module 221 /* Linux Specific */
-#define __NR_delete_module 222 /* Linux Specific */
-#define __NR_get_kernel_syms 223 /* Linux Specific */
-#define __NR_getpgid 224 /* Linux Specific */
-#define __NR_bdflush 225 /* Linux Specific */
-#define __NR_sysfs 226 /* Linux Specific */
-#define __NR_afs_syscall 227 /* Linux Specific */
-#define __NR_setfsuid 228 /* Linux Specific */
-#define __NR_setfsgid 229 /* Linux Specific */
-#define __NR__newselect 230 /* Linux Specific */
-#define __NR_time 231 /* Linux Specific */
-#define __NR_splice 232 /* Linux Specific */
-#define __NR_stime 233 /* Linux Specific */
-#define __NR_statfs64 234 /* Linux Specific */
-#define __NR_fstatfs64 235 /* Linux Specific */
-#define __NR__llseek 236 /* Linux Specific */
-#define __NR_mlock 237
-#define __NR_munlock 238
-#define __NR_mlockall 239
-#define __NR_munlockall 240
-#define __NR_sched_setparam 241
-#define __NR_sched_getparam 242
-#define __NR_sched_setscheduler 243
-#define __NR_sched_getscheduler 244
-#define __NR_sched_yield 245
-#define __NR_sched_get_priority_max 246
-#define __NR_sched_get_priority_min 247
-#define __NR_sched_rr_get_interval 248
-#define __NR_nanosleep 249
-#define __NR_mremap 250
-#define __NR__sysctl 251
-#define __NR_getsid 252
-#define __NR_fdatasync 253
-#define __NR_nfsservctl 254
-#define __NR_sync_file_range 255
-#define __NR_clock_settime 256
-#define __NR_clock_gettime 257
-#define __NR_clock_getres 258
-#define __NR_clock_nanosleep 259
-#define __NR_sched_getaffinity 260
-#define __NR_sched_setaffinity 261
-#define __NR_timer_settime 262
-#define __NR_timer_gettime 263
-#define __NR_timer_getoverrun 264
-#define __NR_timer_delete 265
-#define __NR_timer_create 266
-/* #define __NR_vserver 267 Reserved for VSERVER */
-#define __NR_io_setup 268
-#define __NR_io_destroy 269
-#define __NR_io_submit 270
-#define __NR_io_cancel 271
-#define __NR_io_getevents 272
-#define __NR_mq_open 273
-#define __NR_mq_unlink 274
-#define __NR_mq_timedsend 275
-#define __NR_mq_timedreceive 276
-#define __NR_mq_notify 277
-#define __NR_mq_getsetattr 278
-#define __NR_waitid 279
-#define __NR_tee 280
-#define __NR_add_key 281
-#define __NR_request_key 282
-#define __NR_keyctl 283
-#define __NR_openat 284
-#define __NR_mkdirat 285
-#define __NR_mknodat 286
-#define __NR_fchownat 287
-#define __NR_futimesat 288
-#define __NR_fstatat64 289
-#define __NR_unlinkat 290
-#define __NR_renameat 291
-#define __NR_linkat 292
-#define __NR_symlinkat 293
-#define __NR_readlinkat 294
-#define __NR_fchmodat 295
-#define __NR_faccessat 296
-#define __NR_pselect6 297
-#define __NR_ppoll 298
-#define __NR_unshare 299
-#define __NR_set_robust_list 300
-#define __NR_get_robust_list 301
-#define __NR_migrate_pages 302
-#define __NR_mbind 303
-#define __NR_get_mempolicy 304
-#define __NR_set_mempolicy 305
-#define __NR_kexec_load 306
-#define __NR_move_pages 307
-#define __NR_getcpu 308
-#define __NR_epoll_pwait 309
-#define __NR_utimensat 310
-#define __NR_signalfd 311
-#define __NR_timerfd_create 312
-#define __NR_eventfd 313
-#define __NR_fallocate 314
-#define __NR_timerfd_settime 315
-#define __NR_timerfd_gettime 316
-#define __NR_signalfd4 317
-#define __NR_eventfd2 318
-#define __NR_epoll_create1 319
-#define __NR_dup3 320
-#define __NR_pipe2 321
-#define __NR_inotify_init1 322
-#define __NR_accept4 323
-
-#define NR_SYSCALLS 324
-
-/* Sparc 32-bit only has the "setresuid32", "getresuid32" variants,
- * it never had the plain ones and there is no value to adding those
- * old versions into the syscall table.
- */
-#define __IGNORE_setresuid
-#define __IGNORE_getresuid
-#define __IGNORE_setresgid
-#define __IGNORE_getresgid
-
-#ifdef __KERNEL__
-#define __ARCH_WANT_IPC_PARSE_VERSION
-#define __ARCH_WANT_OLD_READDIR
-#define __ARCH_WANT_STAT64
-#define __ARCH_WANT_SYS_ALARM
-#define __ARCH_WANT_SYS_GETHOSTNAME
-#define __ARCH_WANT_SYS_PAUSE
-#define __ARCH_WANT_SYS_SGETMASK
-#define __ARCH_WANT_SYS_SIGNAL
-#define __ARCH_WANT_SYS_TIME
-#define __ARCH_WANT_SYS_UTIME
-#define __ARCH_WANT_SYS_WAITPID
-#define __ARCH_WANT_SYS_SOCKETCALL
-#define __ARCH_WANT_SYS_FADVISE64
-#define __ARCH_WANT_SYS_GETPGRP
-#define __ARCH_WANT_SYS_LLSEEK
-#define __ARCH_WANT_SYS_NICE
-#define __ARCH_WANT_SYS_OLDUMOUNT
-#define __ARCH_WANT_SYS_SIGPENDING
-#define __ARCH_WANT_SYS_SIGPROCMASK
-#define __ARCH_WANT_SYS_RT_SIGSUSPEND
-
-/*
- * "Conditional" syscalls
- *
- * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
- * but it doesn't work on all toolchains, so we just do it by hand
- */
-#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
-
-#endif /* __KERNEL__ */
-#endif /* _SPARC_UNISTD_H */
diff --git a/arch/sparc/include/asm/unistd_64.h b/arch/sparc/include/asm/unistd_64.h
deleted file mode 100644
index fa5d3c0343c7..000000000000
--- a/arch/sparc/include/asm/unistd_64.h
+++ /dev/null
@@ -1,380 +0,0 @@
-#ifndef _SPARC64_UNISTD_H
-#define _SPARC64_UNISTD_H
-
-/*
- * System calls under the Sparc.
- *
- * Don't be scared by the ugly clobbers, it is the only way I can
- * think of right now to force the arguments into fixed registers
- * before the trap into the system call with gcc 'asm' statements.
- *
- * Copyright (C) 1995, 2007 David S. Miller (davem@davemloft.net)
- *
- * SunOS compatibility based upon preliminary work which is:
- *
- * Copyright (C) 1995 Adrian M. Rodriguez (adrian@remus.rutgers.edu)
- */
-
-#define __NR_restart_syscall 0 /* Linux Specific */
-#define __NR_exit 1 /* Common */
-#define __NR_fork 2 /* Common */
-#define __NR_read 3 /* Common */
-#define __NR_write 4 /* Common */
-#define __NR_open 5 /* Common */
-#define __NR_close 6 /* Common */
-#define __NR_wait4 7 /* Common */
-#define __NR_creat 8 /* Common */
-#define __NR_link 9 /* Common */
-#define __NR_unlink 10 /* Common */
-#define __NR_execv 11 /* SunOS Specific */
-#define __NR_chdir 12 /* Common */
-#define __NR_chown 13 /* Common */
-#define __NR_mknod 14 /* Common */
-#define __NR_chmod 15 /* Common */
-#define __NR_lchown 16 /* Common */
-#define __NR_brk 17 /* Common */
-#define __NR_perfctr 18 /* Performance counter operations */
-#define __NR_lseek 19 /* Common */
-#define __NR_getpid 20 /* Common */
-#define __NR_capget 21 /* Linux Specific */
-#define __NR_capset 22 /* Linux Specific */
-#define __NR_setuid 23 /* Implemented via setreuid in SunOS */
-#define __NR_getuid 24 /* Common */
-#define __NR_vmsplice 25 /* ENOSYS under SunOS */
-#define __NR_ptrace 26 /* Common */
-#define __NR_alarm 27 /* Implemented via setitimer in SunOS */
-#define __NR_sigaltstack 28 /* Common */
-#define __NR_pause 29 /* Is sigblock(0)->sigpause() in SunOS */
-#define __NR_utime 30 /* Implemented via utimes() under SunOS */
-/* #define __NR_lchown32 31 Linux sparc32 specific */
-/* #define __NR_fchown32 32 Linux sparc32 specific */
-#define __NR_access 33 /* Common */
-#define __NR_nice 34 /* Implemented via get/setpriority() in SunOS */
-/* #define __NR_chown32 35 Linux sparc32 specific */
-#define __NR_sync 36 /* Common */
-#define __NR_kill 37 /* Common */
-#define __NR_stat 38 /* Common */
-#define __NR_sendfile 39 /* Linux Specific */
-#define __NR_lstat 40 /* Common */
-#define __NR_dup 41 /* Common */
-#define __NR_pipe 42 /* Common */
-#define __NR_times 43 /* Implemented via getrusage() in SunOS */
-/* #define __NR_getuid32 44 Linux sparc32 specific */
-#define __NR_umount2 45 /* Linux Specific */
-#define __NR_setgid 46 /* Implemented via setregid() in SunOS */
-#define __NR_getgid 47 /* Common */
-#define __NR_signal 48 /* Implemented via sigvec() in SunOS */
-#define __NR_geteuid 49 /* SunOS calls getuid() */
-#define __NR_getegid 50 /* SunOS calls getgid() */
-#define __NR_acct 51 /* Common */
-#define __NR_memory_ordering 52 /* Linux Specific */
-/* #define __NR_getgid32 53 Linux sparc32 specific */
-#define __NR_ioctl 54 /* Common */
-#define __NR_reboot 55 /* Common */
-/* #define __NR_mmap2 56 Linux sparc32 Specific */
-#define __NR_symlink 57 /* Common */
-#define __NR_readlink 58 /* Common */
-#define __NR_execve 59 /* Common */
-#define __NR_umask 60 /* Common */
-#define __NR_chroot 61 /* Common */
-#define __NR_fstat 62 /* Common */
-#define __NR_fstat64 63 /* Linux Specific */
-#define __NR_getpagesize 64 /* Common */
-#define __NR_msync 65 /* Common in newer 1.3.x revs... */
-#define __NR_vfork 66 /* Common */
-#define __NR_pread64 67 /* Linux Specific */
-#define __NR_pwrite64 68 /* Linux Specific */
-/* #define __NR_geteuid32 69 Linux sparc32, sbrk under SunOS */
-/* #define __NR_getegid32 70 Linux sparc32, sstk under SunOS */
-#define __NR_mmap 71 /* Common */
-/* #define __NR_setreuid32 72 Linux sparc32, vadvise under SunOS */
-#define __NR_munmap 73 /* Common */
-#define __NR_mprotect 74 /* Common */
-#define __NR_madvise 75 /* Common */
-#define __NR_vhangup 76 /* Common */
-/* #define __NR_truncate64 77 Linux sparc32 Specific */
-#define __NR_mincore 78 /* Common */
-#define __NR_getgroups 79 /* Common */
-#define __NR_setgroups 80 /* Common */
-#define __NR_getpgrp 81 /* Common */
-/* #define __NR_setgroups32 82 Linux sparc32, setpgrp under SunOS */
-#define __NR_setitimer 83 /* Common */
-/* #define __NR_ftruncate64 84 Linux sparc32 Specific */
-#define __NR_swapon 85 /* Common */
-#define __NR_getitimer 86 /* Common */
-/* #define __NR_setuid32 87 Linux sparc32, gethostname under SunOS */
-#define __NR_sethostname 88 /* Common */
-/* #define __NR_setgid32 89 Linux sparc32, getdtablesize under SunOS */
-#define __NR_dup2 90 /* Common */
-/* #define __NR_setfsuid32 91 Linux sparc32, getdopt under SunOS */
-#define __NR_fcntl 92 /* Common */
-#define __NR_select 93 /* Common */
-/* #define __NR_setfsgid32 94 Linux sparc32, setdopt under SunOS */
-#define __NR_fsync 95 /* Common */
-#define __NR_setpriority 96 /* Common */
-#define __NR_socket 97 /* Common */
-#define __NR_connect 98 /* Common */
-#define __NR_accept 99 /* Common */
-#define __NR_getpriority 100 /* Common */
-#define __NR_rt_sigreturn 101 /* Linux Specific */
-#define __NR_rt_sigaction 102 /* Linux Specific */
-#define __NR_rt_sigprocmask 103 /* Linux Specific */
-#define __NR_rt_sigpending 104 /* Linux Specific */
-#define __NR_rt_sigtimedwait 105 /* Linux Specific */
-#define __NR_rt_sigqueueinfo 106 /* Linux Specific */
-#define __NR_rt_sigsuspend 107 /* Linux Specific */
-#define __NR_setresuid 108 /* Linux Specific, sigvec under SunOS */
-#define __NR_getresuid 109 /* Linux Specific, sigblock under SunOS */
-#define __NR_setresgid 110 /* Linux Specific, sigsetmask under SunOS */
-#define __NR_getresgid 111 /* Linux Specific, sigpause under SunOS */
-/* #define __NR_setregid32 75 Linux sparc32, sigstack under SunOS */
-#define __NR_recvmsg 113 /* Common */
-#define __NR_sendmsg 114 /* Common */
-/* #define __NR_getgroups32 115 Linux sparc32, vtrace under SunOS */
-#define __NR_gettimeofday 116 /* Common */
-#define __NR_getrusage 117 /* Common */
-#define __NR_getsockopt 118 /* Common */
-#define __NR_getcwd 119 /* Linux Specific */
-#define __NR_readv 120 /* Common */
-#define __NR_writev 121 /* Common */
-#define __NR_settimeofday 122 /* Common */
-#define __NR_fchown 123 /* Common */
-#define __NR_fchmod 124 /* Common */
-#define __NR_recvfrom 125 /* Common */
-#define __NR_setreuid 126 /* Common */
-#define __NR_setregid 127 /* Common */
-#define __NR_rename 128 /* Common */
-#define __NR_truncate 129 /* Common */
-#define __NR_ftruncate 130 /* Common */
-#define __NR_flock 131 /* Common */
-#define __NR_lstat64 132 /* Linux Specific */
-#define __NR_sendto 133 /* Common */
-#define __NR_shutdown 134 /* Common */
-#define __NR_socketpair 135 /* Common */
-#define __NR_mkdir 136 /* Common */
-#define __NR_rmdir 137 /* Common */
-#define __NR_utimes 138 /* SunOS Specific */
-#define __NR_stat64 139 /* Linux Specific */
-#define __NR_sendfile64 140 /* adjtime under SunOS */
-#define __NR_getpeername 141 /* Common */
-#define __NR_futex 142 /* gethostid under SunOS */
-#define __NR_gettid 143 /* ENOSYS under SunOS */
-#define __NR_getrlimit 144 /* Common */
-#define __NR_setrlimit 145 /* Common */
-#define __NR_pivot_root 146 /* Linux Specific, killpg under SunOS */
-#define __NR_prctl 147 /* ENOSYS under SunOS */
-#define __NR_pciconfig_read 148 /* ENOSYS under SunOS */
-#define __NR_pciconfig_write 149 /* ENOSYS under SunOS */
-#define __NR_getsockname 150 /* Common */
-#define __NR_inotify_init 151 /* Linux specific */
-#define __NR_inotify_add_watch 152 /* Linux specific */
-#define __NR_poll 153 /* Common */
-#define __NR_getdents64 154 /* Linux specific */
-/* #define __NR_fcntl64 155 Linux sparc32 Specific */
-#define __NR_inotify_rm_watch 156 /* Linux specific */
-#define __NR_statfs 157 /* Common */
-#define __NR_fstatfs 158 /* Common */
-#define __NR_umount 159 /* Common */
-#define __NR_sched_set_affinity 160 /* Linux specific, async_daemon under SunOS */
-#define __NR_sched_get_affinity 161 /* Linux specific, getfh under SunOS */
-#define __NR_getdomainname 162 /* SunOS Specific */
-#define __NR_setdomainname 163 /* Common */
-#define __NR_utrap_install 164 /* SYSV ABI/v9 required */
-#define __NR_quotactl 165 /* Common */
-#define __NR_set_tid_address 166 /* Linux specific, exportfs under SunOS */
-#define __NR_mount 167 /* Common */
-#define __NR_ustat 168 /* Common */
-#define __NR_setxattr 169 /* SunOS: semsys */
-#define __NR_lsetxattr 170 /* SunOS: msgsys */
-#define __NR_fsetxattr 171 /* SunOS: shmsys */
-#define __NR_getxattr 172 /* SunOS: auditsys */
-#define __NR_lgetxattr 173 /* SunOS: rfssys */
-#define __NR_getdents 174 /* Common */
-#define __NR_setsid 175 /* Common */
-#define __NR_fchdir 176 /* Common */
-#define __NR_fgetxattr 177 /* SunOS: fchroot */
-#define __NR_listxattr 178 /* SunOS: vpixsys */
-#define __NR_llistxattr 179 /* SunOS: aioread */
-#define __NR_flistxattr 180 /* SunOS: aiowrite */
-#define __NR_removexattr 181 /* SunOS: aiowait */
-#define __NR_lremovexattr 182 /* SunOS: aiocancel */
-#define __NR_sigpending 183 /* Common */
-#define __NR_query_module 184 /* Linux Specific */
-#define __NR_setpgid 185 /* Common */
-#define __NR_fremovexattr 186 /* SunOS: pathconf */
-#define __NR_tkill 187 /* SunOS: fpathconf */
-#define __NR_exit_group 188 /* Linux specific, sysconf undef SunOS */
-#define __NR_uname 189 /* Linux Specific */
-#define __NR_init_module 190 /* Linux Specific */
-#define __NR_personality 191 /* Linux Specific */
-#define __NR_remap_file_pages 192 /* Linux Specific */
-#define __NR_epoll_create 193 /* Linux Specific */
-#define __NR_epoll_ctl 194 /* Linux Specific */
-#define __NR_epoll_wait 195 /* Linux Specific */
-#define __NR_ioprio_set 196 /* Linux Specific */
-#define __NR_getppid 197 /* Linux Specific */
-#define __NR_sigaction 198 /* Linux Specific */
-#define __NR_sgetmask 199 /* Linux Specific */
-#define __NR_ssetmask 200 /* Linux Specific */
-#define __NR_sigsuspend 201 /* Linux Specific */
-#define __NR_oldlstat 202 /* Linux Specific */
-#define __NR_uselib 203 /* Linux Specific */
-#define __NR_readdir 204 /* Linux Specific */
-#define __NR_readahead 205 /* Linux Specific */
-#define __NR_socketcall 206 /* Linux Specific */
-#define __NR_syslog 207 /* Linux Specific */
-#define __NR_lookup_dcookie 208 /* Linux Specific */
-#define __NR_fadvise64 209 /* Linux Specific */
-#define __NR_fadvise64_64 210 /* Linux Specific */
-#define __NR_tgkill 211 /* Linux Specific */
-#define __NR_waitpid 212 /* Linux Specific */
-#define __NR_swapoff 213 /* Linux Specific */
-#define __NR_sysinfo 214 /* Linux Specific */
-#define __NR_ipc 215 /* Linux Specific */
-#define __NR_sigreturn 216 /* Linux Specific */
-#define __NR_clone 217 /* Linux Specific */
-#define __NR_ioprio_get 218 /* Linux Specific */
-#define __NR_adjtimex 219 /* Linux Specific */
-#define __NR_sigprocmask 220 /* Linux Specific */
-#define __NR_create_module 221 /* Linux Specific */
-#define __NR_delete_module 222 /* Linux Specific */
-#define __NR_get_kernel_syms 223 /* Linux Specific */
-#define __NR_getpgid 224 /* Linux Specific */
-#define __NR_bdflush 225 /* Linux Specific */
-#define __NR_sysfs 226 /* Linux Specific */
-#define __NR_afs_syscall 227 /* Linux Specific */
-#define __NR_setfsuid 228 /* Linux Specific */
-#define __NR_setfsgid 229 /* Linux Specific */
-#define __NR__newselect 230 /* Linux Specific */
-#ifdef __KERNEL__
-#define __NR_time 231 /* Linux sparc32 */
-#endif
-#define __NR_splice 232 /* Linux Specific */
-#define __NR_stime 233 /* Linux Specific */
-#define __NR_statfs64 234 /* Linux Specific */
-#define __NR_fstatfs64 235 /* Linux Specific */
-#define __NR__llseek 236 /* Linux Specific */
-#define __NR_mlock 237
-#define __NR_munlock 238
-#define __NR_mlockall 239
-#define __NR_munlockall 240
-#define __NR_sched_setparam 241
-#define __NR_sched_getparam 242
-#define __NR_sched_setscheduler 243
-#define __NR_sched_getscheduler 244
-#define __NR_sched_yield 245
-#define __NR_sched_get_priority_max 246
-#define __NR_sched_get_priority_min 247
-#define __NR_sched_rr_get_interval 248
-#define __NR_nanosleep 249
-#define __NR_mremap 250
-#define __NR__sysctl 251
-#define __NR_getsid 252
-#define __NR_fdatasync 253
-#define __NR_nfsservctl 254
-#define __NR_sync_file_range 255
-#define __NR_clock_settime 256
-#define __NR_clock_gettime 257
-#define __NR_clock_getres 258
-#define __NR_clock_nanosleep 259
-#define __NR_sched_getaffinity 260
-#define __NR_sched_setaffinity 261
-#define __NR_timer_settime 262
-#define __NR_timer_gettime 263
-#define __NR_timer_getoverrun 264
-#define __NR_timer_delete 265
-#define __NR_timer_create 266
-/* #define __NR_vserver 267 Reserved for VSERVER */
-#define __NR_io_setup 268
-#define __NR_io_destroy 269
-#define __NR_io_submit 270
-#define __NR_io_cancel 271
-#define __NR_io_getevents 272
-#define __NR_mq_open 273
-#define __NR_mq_unlink 274
-#define __NR_mq_timedsend 275
-#define __NR_mq_timedreceive 276
-#define __NR_mq_notify 277
-#define __NR_mq_getsetattr 278
-#define __NR_waitid 279
-#define __NR_tee 280
-#define __NR_add_key 281
-#define __NR_request_key 282
-#define __NR_keyctl 283
-#define __NR_openat 284
-#define __NR_mkdirat 285
-#define __NR_mknodat 286
-#define __NR_fchownat 287
-#define __NR_futimesat 288
-#define __NR_fstatat64 289
-#define __NR_unlinkat 290
-#define __NR_renameat 291
-#define __NR_linkat 292
-#define __NR_symlinkat 293
-#define __NR_readlinkat 294
-#define __NR_fchmodat 295
-#define __NR_faccessat 296
-#define __NR_pselect6 297
-#define __NR_ppoll 298
-#define __NR_unshare 299
-#define __NR_set_robust_list 300
-#define __NR_get_robust_list 301
-#define __NR_migrate_pages 302
-#define __NR_mbind 303
-#define __NR_get_mempolicy 304
-#define __NR_set_mempolicy 305
-#define __NR_kexec_load 306
-#define __NR_move_pages 307
-#define __NR_getcpu 308
-#define __NR_epoll_pwait 309
-#define __NR_utimensat 310
-#define __NR_signalfd 311
-#define __NR_timerfd_create 312
-#define __NR_eventfd 313
-#define __NR_fallocate 314
-#define __NR_timerfd_settime 315
-#define __NR_timerfd_gettime 316
-#define __NR_signalfd4 317
-#define __NR_eventfd2 318
-#define __NR_epoll_create1 319
-#define __NR_dup3 320
-#define __NR_pipe2 321
-#define __NR_inotify_init1 322
-#define __NR_accept4 323
-
-#define NR_SYSCALLS 324
-
-#ifdef __KERNEL__
-#define __ARCH_WANT_IPC_PARSE_VERSION
-#define __ARCH_WANT_OLD_READDIR
-#define __ARCH_WANT_STAT64
-#define __ARCH_WANT_SYS_ALARM
-#define __ARCH_WANT_SYS_GETHOSTNAME
-#define __ARCH_WANT_SYS_PAUSE
-#define __ARCH_WANT_SYS_SGETMASK
-#define __ARCH_WANT_SYS_SIGNAL
-#define __ARCH_WANT_SYS_TIME
-#define __ARCH_WANT_COMPAT_SYS_TIME
-#define __ARCH_WANT_SYS_UTIME
-#define __ARCH_WANT_SYS_WAITPID
-#define __ARCH_WANT_SYS_SOCKETCALL
-#define __ARCH_WANT_SYS_FADVISE64
-#define __ARCH_WANT_SYS_GETPGRP
-#define __ARCH_WANT_SYS_LLSEEK
-#define __ARCH_WANT_SYS_NICE
-#define __ARCH_WANT_SYS_OLDUMOUNT
-#define __ARCH_WANT_SYS_SIGPENDING
-#define __ARCH_WANT_SYS_SIGPROCMASK
-#define __ARCH_WANT_SYS_RT_SIGSUSPEND
-#define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
-
-/*
- * "Conditional" syscalls
- *
- * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
- * but it doesn't work on all toolchains, so we just do it by hand
- */
-#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
-
-#endif /* __KERNEL__ */
-#endif /* _SPARC64_UNISTD_H */
diff --git a/arch/sparc/kernel/.gitignore b/arch/sparc/kernel/.gitignore
new file mode 100644
index 000000000000..c5f676c3c224
--- /dev/null
+++ b/arch/sparc/kernel/.gitignore
@@ -0,0 +1 @@
+vmlinux.lds
diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile
index 2d6582095099..53adcaa0348b 100644
--- a/arch/sparc/kernel/Makefile
+++ b/arch/sparc/kernel/Makefile
@@ -2,25 +2,98 @@
# Makefile for the linux kernel.
#
-extra-y := head.o init_task.o vmlinux.lds
-
-EXTRA_AFLAGS := -ansi
-
-IRQ_OBJS := irq.o sun4m_irq.o sun4c_irq.o sun4d_irq.o
-obj-y := entry.o wof.o wuf.o etrap.o rtrap.o traps.o $(IRQ_OBJS) \
- process.o signal.o ioport.o setup.o idprom.o \
- sys_sparc.o systbls.o \
- time.o windows.o cpu.o devices.o \
- tadpole.o tick14.o ptrace.o \
- unaligned.o una_asm.o muldiv.o \
- prom.o of_device.o devres.o dma.o
-
-devres-y = ../../../kernel/irq/devres.o
-
-obj-$(CONFIG_PCI) += pcic.o
-obj-$(CONFIG_SMP) += trampoline.o smp.o sun4m_smp.o sun4d_smp.o
-obj-$(CONFIG_SUN_AUXIO) += auxio.o
-obj-$(CONFIG_SUN_PM) += apc.o pmc.o
-obj-$(CONFIG_MODULES) += module.o sparc_ksyms.o
-obj-$(CONFIG_SPARC_LED) += led.o
-obj-$(CONFIG_KGDB) += kgdb.o
+asflags-y := -ansi
+ccflags-y := -Werror
+
+extra-y := head_$(BITS).o
+extra-y += init_task.o
+extra-y += vmlinux.lds
+
+obj-$(CONFIG_SPARC32) += entry.o wof.o wuf.o
+obj-$(CONFIG_SPARC32) += etrap_32.o
+obj-$(CONFIG_SPARC32) += rtrap_32.o
+obj-y += traps_$(BITS).o
+
+# IRQ
+obj-y += irq_$(BITS).o
+obj-$(CONFIG_SPARC32) += sun4m_irq.o sun4c_irq.o sun4d_irq.o
+
+obj-y += process_$(BITS).o
+obj-y += signal_$(BITS).o
+obj-$(CONFIG_SPARC32) += ioport.o
+obj-y += setup_$(BITS).o
+obj-y += idprom.o
+obj-y += sys_sparc_$(BITS).o
+obj-$(CONFIG_SPARC32) += systbls_32.o
+obj-y += time_$(BITS).o
+obj-$(CONFIG_SPARC32) += windows.o
+obj-y += cpu.o
+obj-$(CONFIG_SPARC32) += devices.o
+obj-$(CONFIG_SPARC32) += tadpole.o
+obj-$(CONFIG_SPARC32) += tick14.o
+obj-y += ptrace_$(BITS).o
+obj-y += unaligned_$(BITS).o
+obj-y += una_asm_$(BITS).o
+obj-$(CONFIG_SPARC32) += muldiv.o
+obj-y += prom_common.o
+obj-y += prom_$(BITS).o
+obj-y += of_device_$(BITS).o
+obj-$(CONFIG_SPARC64) += prom_irqtrans.o
+
+obj-$(CONFIG_SPARC64) += reboot.o
+obj-$(CONFIG_SPARC64) += sysfs.o
+obj-$(CONFIG_SPARC64) += iommu.o
+obj-$(CONFIG_SPARC64) += central.o
+obj-$(CONFIG_SPARC64) += starfire.o
+obj-$(CONFIG_SPARC64) += power.o
+obj-$(CONFIG_SPARC64) += sbus.o
+obj-$(CONFIG_SPARC64) += ebus.o
+obj-$(CONFIG_SPARC64) += visemul.o
+obj-$(CONFIG_SPARC64) += hvapi.o
+obj-$(CONFIG_SPARC64) += sstate.o
+obj-$(CONFIG_SPARC64) += mdesc.o
+
+# sparc32 do not use GENERIC_HARDIRQS but uses the generic devres implementation
+obj-$(CONFIG_SPARC32) += devres.o
+devres-y := ../../../kernel/irq/devres.o
+
+obj-$(CONFIG_SPARC32) += dma.o
+
+obj-$(CONFIG_SPARC32_PCI) += pcic.o
+
+obj-$(CONFIG_SMP) += trampoline_$(BITS).o smp_$(BITS).o
+obj-$(CONFIG_SPARC32_SMP) += sun4m_smp.o sun4d_smp.o
+obj-$(CONFIG_SPARC64_SMP) += hvtramp.o
+
+obj-y += auxio_$(BITS).o
+obj-$(CONFIG_SUN_PM) += apc.o pmc.o
+
+obj-$(CONFIG_MODULES) += module.o
+obj-$(CONFIG_MODULES) += sparc_ksyms_$(BITS).o
+obj-$(CONFIG_SPARC_LED) += led.o
+obj-$(CONFIG_KGDB) += kgdb_$(BITS).o
+
+
+obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o
+CFLAGS_REMOVE_ftrace.o := -pg
+
+obj-$(CONFIG_STACKTRACE) += stacktrace.o
+# sparc64 PCI
+obj-$(CONFIG_SPARC64_PCI) += pci.o pci_common.o psycho_common.o
+obj-$(CONFIG_SPARC64_PCI) += pci_psycho.o pci_sabre.o pci_schizo.o
+obj-$(CONFIG_SPARC64_PCI) += pci_sun4v.o pci_sun4v_asm.o pci_fire.o
+obj-$(CONFIG_PCI_MSI) += pci_msi.o
+
+obj-$(CONFIG_COMPAT) += sys32.o sys_sparc32.o signal32.o
+
+# sparc64 cpufreq
+obj-$(CONFIG_US3_FREQ) += us3_cpufreq.o
+obj-$(CONFIG_US2E_FREQ) += us2e_cpufreq.o
+obj-$(CONFIG_US3_MC) += chmc.o
+
+obj-$(CONFIG_KPROBES) += kprobes.o
+obj-$(CONFIG_SUN_LDOMS) += ldc.o vio.o viohs.o ds.o
+
+obj-$(CONFIG_AUDIT) += audit.o
+audit--$(CONFIG_AUDIT) := compat_audit.o
+obj-$(CONFIG_COMPAT) += $(audit--y)
diff --git a/arch/sparc/kernel/asm-offsets.c b/arch/sparc/kernel/asm-offsets.c
index b5bb99ed892c..68f7e1118e9b 100644
--- a/arch/sparc/kernel/asm-offsets.c
+++ b/arch/sparc/kernel/asm-offsets.c
@@ -14,15 +14,28 @@
// #include <linux/mm.h>
#include <linux/kbuild.h>
-int foo(void)
+#ifdef CONFIG_SPARC32
+int sparc32_foo(void)
{
- DEFINE(AOFF_task_thread, offsetof(struct task_struct, thread));
- BLANK();
DEFINE(AOFF_thread_fork_kpsr,
offsetof(struct thread_struct, fork_kpsr));
+ return 0;
+}
+#else
+int sparc64_foo(void)
+{
+ return 0;
+}
+#endif
+
+int foo(void)
+{
+ BLANK();
+ DEFINE(AOFF_task_thread, offsetof(struct task_struct, thread));
BLANK();
DEFINE(AOFF_mm_context, offsetof(struct mm_struct, context));
/* DEFINE(NUM_USER_SEGMENTS, TASK_SIZE>>28); */
return 0;
}
+
diff --git a/arch/sparc/kernel/audit.c b/arch/sparc/kernel/audit.c
new file mode 100644
index 000000000000..8fff0ac63d56
--- /dev/null
+++ b/arch/sparc/kernel/audit.c
@@ -0,0 +1,83 @@
+#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_SPARC)
+ return 1;
+#endif
+ return 0;
+}
+
+int audit_classify_syscall(int abi, unsigned syscall)
+{
+#ifdef CONFIG_COMPAT
+ extern int sparc32_classify_syscall(unsigned);
+ if (abi == AUDIT_ARCH_SPARC)
+ return sparc32_classify_syscall(syscall);
+#endif
+ switch(syscall) {
+ case __NR_open:
+ return 2;
+ case __NR_openat:
+ return 3;
+ case __NR_socketcall:
+ return 4;
+ case __NR_execve:
+ return 5;
+ default:
+ return 0;
+ }
+}
+
+static int __init audit_classes_init(void)
+{
+#ifdef CONFIG_COMPAT
+ extern __u32 sparc32_dir_class[];
+ extern __u32 sparc32_write_class[];
+ extern __u32 sparc32_read_class[];
+ extern __u32 sparc32_chattr_class[];
+ extern __u32 sparc32_signal_class[];
+ audit_register_class(AUDIT_CLASS_WRITE_32, sparc32_write_class);
+ audit_register_class(AUDIT_CLASS_READ_32, sparc32_read_class);
+ audit_register_class(AUDIT_CLASS_DIR_WRITE_32, sparc32_dir_class);
+ audit_register_class(AUDIT_CLASS_CHATTR_32, sparc32_chattr_class);
+ audit_register_class(AUDIT_CLASS_SIGNAL_32, sparc32_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/sparc/kernel/auxio.c b/arch/sparc/kernel/auxio_32.c
index 09c857215a52..09c857215a52 100644
--- a/arch/sparc/kernel/auxio.c
+++ b/arch/sparc/kernel/auxio_32.c
diff --git a/arch/sparc/kernel/auxio_64.c b/arch/sparc/kernel/auxio_64.c
new file mode 100644
index 000000000000..8b67347d4221
--- /dev/null
+++ b/arch/sparc/kernel/auxio_64.c
@@ -0,0 +1,149 @@
+/* auxio.c: Probing for the Sparc AUXIO register at boot time.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ *
+ * Refactoring for unified NCR/PCIO support 2002 Eric Brower (ebrower@usa.net)
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/of_device.h>
+
+#include <asm/prom.h>
+#include <asm/io.h>
+#include <asm/auxio.h>
+
+void __iomem *auxio_register = NULL;
+EXPORT_SYMBOL(auxio_register);
+
+enum auxio_type {
+ AUXIO_TYPE_NODEV,
+ AUXIO_TYPE_SBUS,
+ AUXIO_TYPE_EBUS
+};
+
+static enum auxio_type auxio_devtype = AUXIO_TYPE_NODEV;
+static DEFINE_SPINLOCK(auxio_lock);
+
+static void __auxio_rmw(u8 bits_on, u8 bits_off, int ebus)
+{
+ if (auxio_register) {
+ unsigned long flags;
+ u8 regval, newval;
+
+ spin_lock_irqsave(&auxio_lock, flags);
+
+ regval = (ebus ?
+ (u8) readl(auxio_register) :
+ sbus_readb(auxio_register));
+ newval = regval | bits_on;
+ newval &= ~bits_off;
+ if (!ebus)
+ newval &= ~AUXIO_AUX1_MASK;
+ if (ebus)
+ writel((u32) newval, auxio_register);
+ else
+ sbus_writeb(newval, auxio_register);
+
+ spin_unlock_irqrestore(&auxio_lock, flags);
+ }
+}
+
+static void __auxio_set_bit(u8 bit, int on, int ebus)
+{
+ u8 bits_on = (ebus ? AUXIO_PCIO_LED : AUXIO_AUX1_LED);
+ u8 bits_off = 0;
+
+ if (!on) {
+ u8 tmp = bits_off;
+ bits_off = bits_on;
+ bits_on = tmp;
+ }
+ __auxio_rmw(bits_on, bits_off, ebus);
+}
+
+void auxio_set_led(int on)
+{
+ int ebus = auxio_devtype == AUXIO_TYPE_EBUS;
+ u8 bit;
+
+ bit = (ebus ? AUXIO_PCIO_LED : AUXIO_AUX1_LED);
+ __auxio_set_bit(bit, on, ebus);
+}
+
+static void __auxio_sbus_set_lte(int on)
+{
+ __auxio_set_bit(AUXIO_AUX1_LTE, on, 0);
+}
+
+void auxio_set_lte(int on)
+{
+ switch(auxio_devtype) {
+ case AUXIO_TYPE_SBUS:
+ __auxio_sbus_set_lte(on);
+ break;
+ case AUXIO_TYPE_EBUS:
+ /* FALL-THROUGH */
+ default:
+ break;
+ }
+}
+
+static struct of_device_id __initdata auxio_match[] = {
+ {
+ .name = "auxio",
+ },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, auxio_match);
+
+static int __devinit auxio_probe(struct of_device *dev, const struct of_device_id *match)
+{
+ struct device_node *dp = dev->node;
+ unsigned long size;
+
+ if (!strcmp(dp->parent->name, "ebus")) {
+ auxio_devtype = AUXIO_TYPE_EBUS;
+ size = sizeof(u32);
+ } else if (!strcmp(dp->parent->name, "sbus")) {
+ auxio_devtype = AUXIO_TYPE_SBUS;
+ size = 1;
+ } else {
+ printk("auxio: Unknown parent bus type [%s]\n",
+ dp->parent->name);
+ return -ENODEV;
+ }
+ auxio_register = of_ioremap(&dev->resource[0], 0, size, "auxio");
+ if (!auxio_register)
+ return -ENODEV;
+
+ printk(KERN_INFO "AUXIO: Found device at %s\n",
+ dp->full_name);
+
+ if (auxio_devtype == AUXIO_TYPE_EBUS)
+ auxio_set_led(AUXIO_LED_ON);
+
+ return 0;
+}
+
+static struct of_platform_driver auxio_driver = {
+ .match_table = auxio_match,
+ .probe = auxio_probe,
+ .driver = {
+ .name = "auxio",
+ },
+};
+
+static int __init auxio_init(void)
+{
+ return of_register_driver(&auxio_driver, &of_platform_bus_type);
+}
+
+/* Must be after subsys_initcall() so that busses are probed. Must
+ * be before device_initcall() because things like the floppy driver
+ * need to use the AUXIO register.
+ */
+fs_initcall(auxio_init);
diff --git a/arch/sparc/kernel/central.c b/arch/sparc/kernel/central.c
new file mode 100644
index 000000000000..05f1c916db06
--- /dev/null
+++ b/arch/sparc/kernel/central.c
@@ -0,0 +1,268 @@
+/* central.c: Central FHC driver for Sunfire/Starfire/Wildfire.
+ *
+ * Copyright (C) 1997, 1999, 2008 David S. Miller (davem@davemloft.net)
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+#include <asm/fhc.h>
+#include <asm/upa.h>
+
+struct clock_board {
+ void __iomem *clock_freq_regs;
+ void __iomem *clock_regs;
+ void __iomem *clock_ver_reg;
+ int num_slots;
+ struct resource leds_resource;
+ struct platform_device leds_pdev;
+};
+
+struct fhc {
+ void __iomem *pregs;
+ bool central;
+ bool jtag_master;
+ int board_num;
+ struct resource leds_resource;
+ struct platform_device leds_pdev;
+};
+
+static int __devinit clock_board_calc_nslots(struct clock_board *p)
+{
+ u8 reg = upa_readb(p->clock_regs + CLOCK_STAT1) & 0xc0;
+
+ switch (reg) {
+ case 0x40:
+ return 16;
+
+ case 0xc0:
+ return 8;
+
+ case 0x80:
+ reg = 0;
+ if (p->clock_ver_reg)
+ reg = upa_readb(p->clock_ver_reg);
+ if (reg) {
+ if (reg & 0x80)
+ return 4;
+ else
+ return 5;
+ }
+ /* Fallthrough */
+ default:
+ return 4;
+ }
+}
+
+static int __devinit clock_board_probe(struct of_device *op,
+ const struct of_device_id *match)
+{
+ struct clock_board *p = kzalloc(sizeof(*p), GFP_KERNEL);
+ int err = -ENOMEM;
+
+ if (!p) {
+ printk(KERN_ERR "clock_board: Cannot allocate struct clock_board\n");
+ goto out;
+ }
+
+ p->clock_freq_regs = of_ioremap(&op->resource[0], 0,
+ resource_size(&op->resource[0]),
+ "clock_board_freq");
+ if (!p->clock_freq_regs) {
+ printk(KERN_ERR "clock_board: Cannot map clock_freq_regs\n");
+ goto out_free;
+ }
+
+ p->clock_regs = of_ioremap(&op->resource[1], 0,
+ resource_size(&op->resource[1]),
+ "clock_board_regs");
+ if (!p->clock_regs) {
+ printk(KERN_ERR "clock_board: Cannot map clock_regs\n");
+ goto out_unmap_clock_freq_regs;
+ }
+
+ if (op->resource[2].flags) {
+ p->clock_ver_reg = of_ioremap(&op->resource[2], 0,
+ resource_size(&op->resource[2]),
+ "clock_ver_reg");
+ if (!p->clock_ver_reg) {
+ printk(KERN_ERR "clock_board: Cannot map clock_ver_reg\n");
+ goto out_unmap_clock_regs;
+ }
+ }
+
+ p->num_slots = clock_board_calc_nslots(p);
+
+ p->leds_resource.start = (unsigned long)
+ (p->clock_regs + CLOCK_CTRL);
+ p->leds_resource.end = p->leds_resource.end;
+ p->leds_resource.name = "leds";
+
+ p->leds_pdev.name = "sunfire-clockboard-leds";
+ p->leds_pdev.resource = &p->leds_resource;
+ p->leds_pdev.num_resources = 1;
+ p->leds_pdev.dev.parent = &op->dev;
+
+ err = platform_device_register(&p->leds_pdev);
+ if (err) {
+ printk(KERN_ERR "clock_board: Could not register LEDS "
+ "platform device\n");
+ goto out_unmap_clock_ver_reg;
+ }
+
+ printk(KERN_INFO "clock_board: Detected %d slot Enterprise system.\n",
+ p->num_slots);
+
+ err = 0;
+out:
+ return err;
+
+out_unmap_clock_ver_reg:
+ if (p->clock_ver_reg)
+ of_iounmap(&op->resource[2], p->clock_ver_reg,
+ resource_size(&op->resource[2]));
+
+out_unmap_clock_regs:
+ of_iounmap(&op->resource[1], p->clock_regs,
+ resource_size(&op->resource[1]));
+
+out_unmap_clock_freq_regs:
+ of_iounmap(&op->resource[0], p->clock_freq_regs,
+ resource_size(&op->resource[0]));
+
+out_free:
+ kfree(p);
+ goto out;
+}
+
+static struct of_device_id __initdata clock_board_match[] = {
+ {
+ .name = "clock-board",
+ },
+ {},
+};
+
+static struct of_platform_driver clock_board_driver = {
+ .match_table = clock_board_match,
+ .probe = clock_board_probe,
+ .driver = {
+ .name = "clock_board",
+ },
+};
+
+static int __devinit fhc_probe(struct of_device *op,
+ const struct of_device_id *match)
+{
+ struct fhc *p = kzalloc(sizeof(*p), GFP_KERNEL);
+ int err = -ENOMEM;
+ u32 reg;
+
+ if (!p) {
+ printk(KERN_ERR "fhc: Cannot allocate struct fhc\n");
+ goto out;
+ }
+
+ if (!strcmp(op->node->parent->name, "central"))
+ p->central = true;
+
+ p->pregs = of_ioremap(&op->resource[0], 0,
+ resource_size(&op->resource[0]),
+ "fhc_pregs");
+ if (!p->pregs) {
+ printk(KERN_ERR "fhc: Cannot map pregs\n");
+ goto out_free;
+ }
+
+ if (p->central) {
+ reg = upa_readl(p->pregs + FHC_PREGS_BSR);
+ p->board_num = ((reg >> 16) & 1) | ((reg >> 12) & 0x0e);
+ } else {
+ p->board_num = of_getintprop_default(op->node, "board#", -1);
+ if (p->board_num == -1) {
+ printk(KERN_ERR "fhc: No board# property\n");
+ goto out_unmap_pregs;
+ }
+ if (upa_readl(p->pregs + FHC_PREGS_JCTRL) & FHC_JTAG_CTRL_MENAB)
+ p->jtag_master = true;
+ }
+
+ if (!p->central) {
+ p->leds_resource.start = (unsigned long)
+ (p->pregs + FHC_PREGS_CTRL);
+ p->leds_resource.end = p->leds_resource.end;
+ p->leds_resource.name = "leds";
+
+ p->leds_pdev.name = "sunfire-fhc-leds";
+ p->leds_pdev.resource = &p->leds_resource;
+ p->leds_pdev.num_resources = 1;
+ p->leds_pdev.dev.parent = &op->dev;
+
+ err = platform_device_register(&p->leds_pdev);
+ if (err) {
+ printk(KERN_ERR "fhc: Could not register LEDS "
+ "platform device\n");
+ goto out_unmap_pregs;
+ }
+ }
+ reg = upa_readl(p->pregs + FHC_PREGS_CTRL);
+
+ if (!p->central)
+ reg |= FHC_CONTROL_IXIST;
+
+ reg &= ~(FHC_CONTROL_AOFF |
+ FHC_CONTROL_BOFF |
+ FHC_CONTROL_SLINE);
+
+ upa_writel(reg, p->pregs + FHC_PREGS_CTRL);
+ upa_readl(p->pregs + FHC_PREGS_CTRL);
+
+ reg = upa_readl(p->pregs + FHC_PREGS_ID);
+ printk(KERN_INFO "fhc: Board #%d, Version[%x] PartID[%x] Manuf[%x] %s\n",
+ p->board_num,
+ (reg & FHC_ID_VERS) >> 28,
+ (reg & FHC_ID_PARTID) >> 12,
+ (reg & FHC_ID_MANUF) >> 1,
+ (p->jtag_master ?
+ "(JTAG Master)" :
+ (p->central ? "(Central)" : "")));
+
+ err = 0;
+
+out:
+ return err;
+
+out_unmap_pregs:
+ of_iounmap(&op->resource[0], p->pregs, resource_size(&op->resource[0]));
+
+out_free:
+ kfree(p);
+ goto out;
+}
+
+static struct of_device_id __initdata fhc_match[] = {
+ {
+ .name = "fhc",
+ },
+ {},
+};
+
+static struct of_platform_driver fhc_driver = {
+ .match_table = fhc_match,
+ .probe = fhc_probe,
+ .driver = {
+ .name = "fhc",
+ },
+};
+
+static int __init sunfire_init(void)
+{
+ (void) of_register_driver(&fhc_driver, &of_platform_bus_type);
+ (void) of_register_driver(&clock_board_driver, &of_platform_bus_type);
+ return 0;
+}
+
+subsys_initcall(sunfire_init);
diff --git a/arch/sparc/kernel/cherrs.S b/arch/sparc/kernel/cherrs.S
new file mode 100644
index 000000000000..4ee1ad420862
--- /dev/null
+++ b/arch/sparc/kernel/cherrs.S
@@ -0,0 +1,579 @@
+ /* These get patched into the trap table at boot time
+ * once we know we have a cheetah processor.
+ */
+ .globl cheetah_fecc_trap_vector
+ .type cheetah_fecc_trap_vector,#function
+cheetah_fecc_trap_vector:
+ membar #Sync
+ ldxa [%g0] ASI_DCU_CONTROL_REG, %g1
+ andn %g1, DCU_DC | DCU_IC, %g1
+ stxa %g1, [%g0] ASI_DCU_CONTROL_REG
+ membar #Sync
+ sethi %hi(cheetah_fast_ecc), %g2
+ jmpl %g2 + %lo(cheetah_fast_ecc), %g0
+ mov 0, %g1
+ .size cheetah_fecc_trap_vector,.-cheetah_fecc_trap_vector
+
+ .globl cheetah_fecc_trap_vector_tl1
+ .type cheetah_fecc_trap_vector_tl1,#function
+cheetah_fecc_trap_vector_tl1:
+ membar #Sync
+ ldxa [%g0] ASI_DCU_CONTROL_REG, %g1
+ andn %g1, DCU_DC | DCU_IC, %g1
+ stxa %g1, [%g0] ASI_DCU_CONTROL_REG
+ membar #Sync
+ sethi %hi(cheetah_fast_ecc), %g2
+ jmpl %g2 + %lo(cheetah_fast_ecc), %g0
+ mov 1, %g1
+ .size cheetah_fecc_trap_vector_tl1,.-cheetah_fecc_trap_vector_tl1
+
+ .globl cheetah_cee_trap_vector
+ .type cheetah_cee_trap_vector,#function
+cheetah_cee_trap_vector:
+ membar #Sync
+ ldxa [%g0] ASI_DCU_CONTROL_REG, %g1
+ andn %g1, DCU_IC, %g1
+ stxa %g1, [%g0] ASI_DCU_CONTROL_REG
+ membar #Sync
+ sethi %hi(cheetah_cee), %g2
+ jmpl %g2 + %lo(cheetah_cee), %g0
+ mov 0, %g1
+ .size cheetah_cee_trap_vector,.-cheetah_cee_trap_vector
+
+ .globl cheetah_cee_trap_vector_tl1
+ .type cheetah_cee_trap_vector_tl1,#function
+cheetah_cee_trap_vector_tl1:
+ membar #Sync
+ ldxa [%g0] ASI_DCU_CONTROL_REG, %g1
+ andn %g1, DCU_IC, %g1
+ stxa %g1, [%g0] ASI_DCU_CONTROL_REG
+ membar #Sync
+ sethi %hi(cheetah_cee), %g2
+ jmpl %g2 + %lo(cheetah_cee), %g0
+ mov 1, %g1
+ .size cheetah_cee_trap_vector_tl1,.-cheetah_cee_trap_vector_tl1
+
+ .globl cheetah_deferred_trap_vector
+ .type cheetah_deferred_trap_vector,#function
+cheetah_deferred_trap_vector:
+ membar #Sync
+ ldxa [%g0] ASI_DCU_CONTROL_REG, %g1;
+ andn %g1, DCU_DC | DCU_IC, %g1;
+ stxa %g1, [%g0] ASI_DCU_CONTROL_REG;
+ membar #Sync;
+ sethi %hi(cheetah_deferred_trap), %g2
+ jmpl %g2 + %lo(cheetah_deferred_trap), %g0
+ mov 0, %g1
+ .size cheetah_deferred_trap_vector,.-cheetah_deferred_trap_vector
+
+ .globl cheetah_deferred_trap_vector_tl1
+ .type cheetah_deferred_trap_vector_tl1,#function
+cheetah_deferred_trap_vector_tl1:
+ membar #Sync;
+ ldxa [%g0] ASI_DCU_CONTROL_REG, %g1;
+ andn %g1, DCU_DC | DCU_IC, %g1;
+ stxa %g1, [%g0] ASI_DCU_CONTROL_REG;
+ membar #Sync;
+ sethi %hi(cheetah_deferred_trap), %g2
+ jmpl %g2 + %lo(cheetah_deferred_trap), %g0
+ mov 1, %g1
+ .size cheetah_deferred_trap_vector_tl1,.-cheetah_deferred_trap_vector_tl1
+
+ /* Cheetah+ specific traps. These are for the new I/D cache parity
+ * error traps. The first argument to cheetah_plus_parity_handler
+ * is encoded as follows:
+ *
+ * Bit0: 0=dcache,1=icache
+ * Bit1: 0=recoverable,1=unrecoverable
+ */
+ .globl cheetah_plus_dcpe_trap_vector
+ .type cheetah_plus_dcpe_trap_vector,#function
+cheetah_plus_dcpe_trap_vector:
+ membar #Sync
+ sethi %hi(do_cheetah_plus_data_parity), %g7
+ jmpl %g7 + %lo(do_cheetah_plus_data_parity), %g0
+ nop
+ nop
+ nop
+ nop
+ nop
+ .size cheetah_plus_dcpe_trap_vector,.-cheetah_plus_dcpe_trap_vector
+
+ .type do_cheetah_plus_data_parity,#function
+do_cheetah_plus_data_parity:
+ rdpr %pil, %g2
+ wrpr %g0, PIL_NORMAL_MAX, %pil
+ ba,pt %xcc, etrap_irq
+ rd %pc, %g7
+#ifdef CONFIG_TRACE_IRQFLAGS
+ call trace_hardirqs_off
+ nop
+#endif
+ mov 0x0, %o0
+ call cheetah_plus_parity_error
+ add %sp, PTREGS_OFF, %o1
+ ba,a,pt %xcc, rtrap_irq
+ .size do_cheetah_plus_data_parity,.-do_cheetah_plus_data_parity
+
+ .globl cheetah_plus_dcpe_trap_vector_tl1
+ .type cheetah_plus_dcpe_trap_vector_tl1,#function
+cheetah_plus_dcpe_trap_vector_tl1:
+ membar #Sync
+ wrpr PSTATE_IG | PSTATE_PEF | PSTATE_PRIV, %pstate
+ sethi %hi(do_dcpe_tl1), %g3
+ jmpl %g3 + %lo(do_dcpe_tl1), %g0
+ nop
+ nop
+ nop
+ nop
+ .size cheetah_plus_dcpe_trap_vector_tl1,.-cheetah_plus_dcpe_trap_vector_tl1
+
+ .globl cheetah_plus_icpe_trap_vector
+ .type cheetah_plus_icpe_trap_vector,#function
+cheetah_plus_icpe_trap_vector:
+ membar #Sync
+ sethi %hi(do_cheetah_plus_insn_parity), %g7
+ jmpl %g7 + %lo(do_cheetah_plus_insn_parity), %g0
+ nop
+ nop
+ nop
+ nop
+ nop
+ .size cheetah_plus_icpe_trap_vector,.-cheetah_plus_icpe_trap_vector
+
+ .type do_cheetah_plus_insn_parity,#function
+do_cheetah_plus_insn_parity:
+ rdpr %pil, %g2
+ wrpr %g0, PIL_NORMAL_MAX, %pil
+ ba,pt %xcc, etrap_irq
+ rd %pc, %g7
+#ifdef CONFIG_TRACE_IRQFLAGS
+ call trace_hardirqs_off
+ nop
+#endif
+ mov 0x1, %o0
+ call cheetah_plus_parity_error
+ add %sp, PTREGS_OFF, %o1
+ ba,a,pt %xcc, rtrap_irq
+ .size do_cheetah_plus_insn_parity,.-do_cheetah_plus_insn_parity
+
+ .globl cheetah_plus_icpe_trap_vector_tl1
+ .type cheetah_plus_icpe_trap_vector_tl1,#function
+cheetah_plus_icpe_trap_vector_tl1:
+ membar #Sync
+ wrpr PSTATE_IG | PSTATE_PEF | PSTATE_PRIV, %pstate
+ sethi %hi(do_icpe_tl1), %g3
+ jmpl %g3 + %lo(do_icpe_tl1), %g0
+ nop
+ nop
+ nop
+ nop
+ .size cheetah_plus_icpe_trap_vector_tl1,.-cheetah_plus_icpe_trap_vector_tl1
+
+ /* If we take one of these traps when tl >= 1, then we
+ * jump to interrupt globals. If some trap level above us
+ * was also using interrupt globals, we cannot recover.
+ * We may use all interrupt global registers except %g6.
+ */
+ .globl do_dcpe_tl1
+ .type do_dcpe_tl1,#function
+do_dcpe_tl1:
+ rdpr %tl, %g1 ! Save original trap level
+ mov 1, %g2 ! Setup TSTATE checking loop
+ sethi %hi(TSTATE_IG), %g3 ! TSTATE mask bit
+1: wrpr %g2, %tl ! Set trap level to check
+ rdpr %tstate, %g4 ! Read TSTATE for this level
+ andcc %g4, %g3, %g0 ! Interrupt globals in use?
+ bne,a,pn %xcc, do_dcpe_tl1_fatal ! Yep, irrecoverable
+ wrpr %g1, %tl ! Restore original trap level
+ add %g2, 1, %g2 ! Next trap level
+ cmp %g2, %g1 ! Hit them all yet?
+ ble,pt %icc, 1b ! Not yet
+ nop
+ wrpr %g1, %tl ! Restore original trap level
+do_dcpe_tl1_nonfatal: /* Ok we may use interrupt globals safely. */
+ sethi %hi(dcache_parity_tl1_occurred), %g2
+ lduw [%g2 + %lo(dcache_parity_tl1_occurred)], %g1
+ add %g1, 1, %g1
+ stw %g1, [%g2 + %lo(dcache_parity_tl1_occurred)]
+ /* Reset D-cache parity */
+ sethi %hi(1 << 16), %g1 ! D-cache size
+ mov (1 << 5), %g2 ! D-cache line size
+ sub %g1, %g2, %g1 ! Move down 1 cacheline
+1: srl %g1, 14, %g3 ! Compute UTAG
+ membar #Sync
+ stxa %g3, [%g1] ASI_DCACHE_UTAG
+ membar #Sync
+ sub %g2, 8, %g3 ! 64-bit data word within line
+2: membar #Sync
+ stxa %g0, [%g1 + %g3] ASI_DCACHE_DATA
+ membar #Sync
+ subcc %g3, 8, %g3 ! Next 64-bit data word
+ bge,pt %icc, 2b
+ nop
+ subcc %g1, %g2, %g1 ! Next cacheline
+ bge,pt %icc, 1b
+ nop
+ ba,pt %xcc, dcpe_icpe_tl1_common
+ nop
+
+do_dcpe_tl1_fatal:
+ sethi %hi(1f), %g7
+ ba,pt %xcc, etraptl1
+1: or %g7, %lo(1b), %g7
+ mov 0x2, %o0
+ call cheetah_plus_parity_error
+ add %sp, PTREGS_OFF, %o1
+ ba,pt %xcc, rtrap
+ nop
+ .size do_dcpe_tl1,.-do_dcpe_tl1
+
+ .globl do_icpe_tl1
+ .type do_icpe_tl1,#function
+do_icpe_tl1:
+ rdpr %tl, %g1 ! Save original trap level
+ mov 1, %g2 ! Setup TSTATE checking loop
+ sethi %hi(TSTATE_IG), %g3 ! TSTATE mask bit
+1: wrpr %g2, %tl ! Set trap level to check
+ rdpr %tstate, %g4 ! Read TSTATE for this level
+ andcc %g4, %g3, %g0 ! Interrupt globals in use?
+ bne,a,pn %xcc, do_icpe_tl1_fatal ! Yep, irrecoverable
+ wrpr %g1, %tl ! Restore original trap level
+ add %g2, 1, %g2 ! Next trap level
+ cmp %g2, %g1 ! Hit them all yet?
+ ble,pt %icc, 1b ! Not yet
+ nop
+ wrpr %g1, %tl ! Restore original trap level
+do_icpe_tl1_nonfatal: /* Ok we may use interrupt globals safely. */
+ sethi %hi(icache_parity_tl1_occurred), %g2
+ lduw [%g2 + %lo(icache_parity_tl1_occurred)], %g1
+ add %g1, 1, %g1
+ stw %g1, [%g2 + %lo(icache_parity_tl1_occurred)]
+ /* Flush I-cache */
+ sethi %hi(1 << 15), %g1 ! I-cache size
+ mov (1 << 5), %g2 ! I-cache line size
+ sub %g1, %g2, %g1
+1: or %g1, (2 << 3), %g3
+ stxa %g0, [%g3] ASI_IC_TAG
+ membar #Sync
+ subcc %g1, %g2, %g1
+ bge,pt %icc, 1b
+ nop
+ ba,pt %xcc, dcpe_icpe_tl1_common
+ nop
+
+do_icpe_tl1_fatal:
+ sethi %hi(1f), %g7
+ ba,pt %xcc, etraptl1
+1: or %g7, %lo(1b), %g7
+ mov 0x3, %o0
+ call cheetah_plus_parity_error
+ add %sp, PTREGS_OFF, %o1
+ ba,pt %xcc, rtrap
+ nop
+ .size do_icpe_tl1,.-do_icpe_tl1
+
+ .type dcpe_icpe_tl1_common,#function
+dcpe_icpe_tl1_common:
+ /* Flush D-cache, re-enable D/I caches in DCU and finally
+ * retry the trapping instruction.
+ */
+ sethi %hi(1 << 16), %g1 ! D-cache size
+ mov (1 << 5), %g2 ! D-cache line size
+ sub %g1, %g2, %g1
+1: stxa %g0, [%g1] ASI_DCACHE_TAG
+ membar #Sync
+ subcc %g1, %g2, %g1
+ bge,pt %icc, 1b
+ nop
+ ldxa [%g0] ASI_DCU_CONTROL_REG, %g1
+ or %g1, (DCU_DC | DCU_IC), %g1
+ stxa %g1, [%g0] ASI_DCU_CONTROL_REG
+ membar #Sync
+ retry
+ .size dcpe_icpe_tl1_common,.-dcpe_icpe_tl1_common
+
+ /* Capture I/D/E-cache state into per-cpu error scoreboard.
+ *
+ * %g1: (TL>=0) ? 1 : 0
+ * %g2: scratch
+ * %g3: scratch
+ * %g4: AFSR
+ * %g5: AFAR
+ * %g6: unused, will have current thread ptr after etrap
+ * %g7: scratch
+ */
+ .type __cheetah_log_error,#function
+__cheetah_log_error:
+ /* Put "TL1" software bit into AFSR. */
+ and %g1, 0x1, %g1
+ sllx %g1, 63, %g2
+ or %g4, %g2, %g4
+
+ /* Get log entry pointer for this cpu at this trap level. */
+ BRANCH_IF_JALAPENO(g2,g3,50f)
+ ldxa [%g0] ASI_SAFARI_CONFIG, %g2
+ srlx %g2, 17, %g2
+ ba,pt %xcc, 60f
+ and %g2, 0x3ff, %g2
+
+50: ldxa [%g0] ASI_JBUS_CONFIG, %g2
+ srlx %g2, 17, %g2
+ and %g2, 0x1f, %g2
+
+60: sllx %g2, 9, %g2
+ sethi %hi(cheetah_error_log), %g3
+ ldx [%g3 + %lo(cheetah_error_log)], %g3
+ brz,pn %g3, 80f
+ nop
+
+ add %g3, %g2, %g3
+ sllx %g1, 8, %g1
+ add %g3, %g1, %g1
+
+ /* %g1 holds pointer to the top of the logging scoreboard */
+ ldx [%g1 + 0x0], %g7
+ cmp %g7, -1
+ bne,pn %xcc, 80f
+ nop
+
+ stx %g4, [%g1 + 0x0]
+ stx %g5, [%g1 + 0x8]
+ add %g1, 0x10, %g1
+
+ /* %g1 now points to D-cache logging area */
+ set 0x3ff8, %g2 /* DC_addr mask */
+ and %g5, %g2, %g2 /* DC_addr bits of AFAR */
+ srlx %g5, 12, %g3
+ or %g3, 1, %g3 /* PHYS tag + valid */
+
+10: ldxa [%g2] ASI_DCACHE_TAG, %g7
+ cmp %g3, %g7 /* TAG match? */
+ bne,pt %xcc, 13f
+ nop
+
+ /* Yep, what we want, capture state. */
+ stx %g2, [%g1 + 0x20]
+ stx %g7, [%g1 + 0x28]
+
+ /* A membar Sync is required before and after utag access. */
+ membar #Sync
+ ldxa [%g2] ASI_DCACHE_UTAG, %g7
+ membar #Sync
+ stx %g7, [%g1 + 0x30]
+ ldxa [%g2] ASI_DCACHE_SNOOP_TAG, %g7
+ stx %g7, [%g1 + 0x38]
+ clr %g3
+
+12: ldxa [%g2 + %g3] ASI_DCACHE_DATA, %g7
+ stx %g7, [%g1]
+ add %g3, (1 << 5), %g3
+ cmp %g3, (4 << 5)
+ bl,pt %xcc, 12b
+ add %g1, 0x8, %g1
+
+ ba,pt %xcc, 20f
+ add %g1, 0x20, %g1
+
+13: sethi %hi(1 << 14), %g7
+ add %g2, %g7, %g2
+ srlx %g2, 14, %g7
+ cmp %g7, 4
+ bl,pt %xcc, 10b
+ nop
+
+ add %g1, 0x40, %g1
+
+ /* %g1 now points to I-cache logging area */
+20: set 0x1fe0, %g2 /* IC_addr mask */
+ and %g5, %g2, %g2 /* IC_addr bits of AFAR */
+ sllx %g2, 1, %g2 /* IC_addr[13:6]==VA[12:5] */
+ srlx %g5, (13 - 8), %g3 /* Make PTAG */
+ andn %g3, 0xff, %g3 /* Mask off undefined bits */
+
+21: ldxa [%g2] ASI_IC_TAG, %g7
+ andn %g7, 0xff, %g7
+ cmp %g3, %g7
+ bne,pt %xcc, 23f
+ nop
+
+ /* Yep, what we want, capture state. */
+ stx %g2, [%g1 + 0x40]
+ stx %g7, [%g1 + 0x48]
+ add %g2, (1 << 3), %g2
+ ldxa [%g2] ASI_IC_TAG, %g7
+ add %g2, (1 << 3), %g2
+ stx %g7, [%g1 + 0x50]
+ ldxa [%g2] ASI_IC_TAG, %g7
+ add %g2, (1 << 3), %g2
+ stx %g7, [%g1 + 0x60]
+ ldxa [%g2] ASI_IC_TAG, %g7
+ stx %g7, [%g1 + 0x68]
+ sub %g2, (3 << 3), %g2
+ ldxa [%g2] ASI_IC_STAG, %g7
+ stx %g7, [%g1 + 0x58]
+ clr %g3
+ srlx %g2, 2, %g2
+
+22: ldxa [%g2 + %g3] ASI_IC_INSTR, %g7
+ stx %g7, [%g1]
+ add %g3, (1 << 3), %g3
+ cmp %g3, (8 << 3)
+ bl,pt %xcc, 22b
+ add %g1, 0x8, %g1
+
+ ba,pt %xcc, 30f
+ add %g1, 0x30, %g1
+
+23: sethi %hi(1 << 14), %g7
+ add %g2, %g7, %g2
+ srlx %g2, 14, %g7
+ cmp %g7, 4
+ bl,pt %xcc, 21b
+ nop
+
+ add %g1, 0x70, %g1
+
+ /* %g1 now points to E-cache logging area */
+30: andn %g5, (32 - 1), %g2
+ stx %g2, [%g1 + 0x20]
+ ldxa [%g2] ASI_EC_TAG_DATA, %g7
+ stx %g7, [%g1 + 0x28]
+ ldxa [%g2] ASI_EC_R, %g0
+ clr %g3
+
+31: ldxa [%g3] ASI_EC_DATA, %g7
+ stx %g7, [%g1 + %g3]
+ add %g3, 0x8, %g3
+ cmp %g3, 0x20
+
+ bl,pt %xcc, 31b
+ nop
+80:
+ rdpr %tt, %g2
+ cmp %g2, 0x70
+ be c_fast_ecc
+ cmp %g2, 0x63
+ be c_cee
+ nop
+ ba,pt %xcc, c_deferred
+ .size __cheetah_log_error,.-__cheetah_log_error
+
+ /* Cheetah FECC trap handling, we get here from tl{0,1}_fecc
+ * in the trap table. That code has done a memory barrier
+ * and has disabled both the I-cache and D-cache in the DCU
+ * control register. The I-cache is disabled so that we may
+ * capture the corrupted cache line, and the D-cache is disabled
+ * because corrupt data may have been placed there and we don't
+ * want to reference it.
+ *
+ * %g1 is one if this trap occurred at %tl >= 1.
+ *
+ * Next, we turn off error reporting so that we don't recurse.
+ */
+ .globl cheetah_fast_ecc
+ .type cheetah_fast_ecc,#function
+cheetah_fast_ecc:
+ ldxa [%g0] ASI_ESTATE_ERROR_EN, %g2
+ andn %g2, ESTATE_ERROR_NCEEN | ESTATE_ERROR_CEEN, %g2
+ stxa %g2, [%g0] ASI_ESTATE_ERROR_EN
+ membar #Sync
+
+ /* Fetch and clear AFSR/AFAR */
+ ldxa [%g0] ASI_AFSR, %g4
+ ldxa [%g0] ASI_AFAR, %g5
+ stxa %g4, [%g0] ASI_AFSR
+ membar #Sync
+
+ ba,pt %xcc, __cheetah_log_error
+ nop
+ .size cheetah_fast_ecc,.-cheetah_fast_ecc
+
+ .type c_fast_ecc,#function
+c_fast_ecc:
+ rdpr %pil, %g2
+ wrpr %g0, PIL_NORMAL_MAX, %pil
+ ba,pt %xcc, etrap_irq
+ rd %pc, %g7
+#ifdef CONFIG_TRACE_IRQFLAGS
+ call trace_hardirqs_off
+ nop
+#endif
+ mov %l4, %o1
+ mov %l5, %o2
+ call cheetah_fecc_handler
+ add %sp, PTREGS_OFF, %o0
+ ba,a,pt %xcc, rtrap_irq
+ .size c_fast_ecc,.-c_fast_ecc
+
+ /* Our caller has disabled I-cache and performed membar Sync. */
+ .globl cheetah_cee
+ .type cheetah_cee,#function
+cheetah_cee:
+ ldxa [%g0] ASI_ESTATE_ERROR_EN, %g2
+ andn %g2, ESTATE_ERROR_CEEN, %g2
+ stxa %g2, [%g0] ASI_ESTATE_ERROR_EN
+ membar #Sync
+
+ /* Fetch and clear AFSR/AFAR */
+ ldxa [%g0] ASI_AFSR, %g4
+ ldxa [%g0] ASI_AFAR, %g5
+ stxa %g4, [%g0] ASI_AFSR
+ membar #Sync
+
+ ba,pt %xcc, __cheetah_log_error
+ nop
+ .size cheetah_cee,.-cheetah_cee
+
+ .type c_cee,#function
+c_cee:
+ rdpr %pil, %g2
+ wrpr %g0, PIL_NORMAL_MAX, %pil
+ ba,pt %xcc, etrap_irq
+ rd %pc, %g7
+#ifdef CONFIG_TRACE_IRQFLAGS
+ call trace_hardirqs_off
+ nop
+#endif
+ mov %l4, %o1
+ mov %l5, %o2
+ call cheetah_cee_handler
+ add %sp, PTREGS_OFF, %o0
+ ba,a,pt %xcc, rtrap_irq
+ .size c_cee,.-c_cee
+
+ /* Our caller has disabled I-cache+D-cache and performed membar Sync. */
+ .globl cheetah_deferred_trap
+ .type cheetah_deferred_trap,#function
+cheetah_deferred_trap:
+ ldxa [%g0] ASI_ESTATE_ERROR_EN, %g2
+ andn %g2, ESTATE_ERROR_NCEEN | ESTATE_ERROR_CEEN, %g2
+ stxa %g2, [%g0] ASI_ESTATE_ERROR_EN
+ membar #Sync
+
+ /* Fetch and clear AFSR/AFAR */
+ ldxa [%g0] ASI_AFSR, %g4
+ ldxa [%g0] ASI_AFAR, %g5
+ stxa %g4, [%g0] ASI_AFSR
+ membar #Sync
+
+ ba,pt %xcc, __cheetah_log_error
+ nop
+ .size cheetah_deferred_trap,.-cheetah_deferred_trap
+
+ .type c_deferred,#function
+c_deferred:
+ rdpr %pil, %g2
+ wrpr %g0, PIL_NORMAL_MAX, %pil
+ ba,pt %xcc, etrap_irq
+ rd %pc, %g7
+#ifdef CONFIG_TRACE_IRQFLAGS
+ call trace_hardirqs_off
+ nop
+#endif
+ mov %l4, %o1
+ mov %l5, %o2
+ call cheetah_deferred_handler
+ add %sp, PTREGS_OFF, %o0
+ ba,a,pt %xcc, rtrap_irq
+ .size c_deferred,.-c_deferred
diff --git a/arch/sparc/kernel/chmc.c b/arch/sparc/kernel/chmc.c
new file mode 100644
index 000000000000..3b9f4d6e14a9
--- /dev/null
+++ b/arch/sparc/kernel/chmc.c
@@ -0,0 +1,863 @@
+/* chmc.c: Driver for UltraSPARC-III memory controller.
+ *
+ * Copyright (C) 2001, 2007, 2008 David S. Miller (davem@davemloft.net)
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <asm/spitfire.h>
+#include <asm/chmctrl.h>
+#include <asm/cpudata.h>
+#include <asm/oplib.h>
+#include <asm/prom.h>
+#include <asm/head.h>
+#include <asm/io.h>
+#include <asm/memctrl.h>
+
+#define DRV_MODULE_NAME "chmc"
+#define PFX DRV_MODULE_NAME ": "
+#define DRV_MODULE_VERSION "0.2"
+
+MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
+MODULE_DESCRIPTION("UltraSPARC-III memory controller driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_MODULE_VERSION);
+
+static int mc_type;
+#define MC_TYPE_SAFARI 1
+#define MC_TYPE_JBUS 2
+
+static dimm_printer_t us3mc_dimm_printer;
+
+#define CHMCTRL_NDGRPS 2
+#define CHMCTRL_NDIMMS 4
+
+#define CHMC_DIMMS_PER_MC (CHMCTRL_NDGRPS * CHMCTRL_NDIMMS)
+
+/* OBP memory-layout property format. */
+struct chmc_obp_map {
+ unsigned char dimm_map[144];
+ unsigned char pin_map[576];
+};
+
+#define DIMM_LABEL_SZ 8
+
+struct chmc_obp_mem_layout {
+ /* One max 8-byte string label per DIMM. Usually
+ * this matches the label on the motherboard where
+ * that DIMM resides.
+ */
+ char dimm_labels[CHMC_DIMMS_PER_MC][DIMM_LABEL_SZ];
+
+ /* If symmetric use map[0], else it is
+ * asymmetric and map[1] should be used.
+ */
+ char symmetric;
+
+ struct chmc_obp_map map[2];
+};
+
+#define CHMCTRL_NBANKS 4
+
+struct chmc_bank_info {
+ struct chmc *p;
+ int bank_id;
+
+ u64 raw_reg;
+ int valid;
+ int uk;
+ int um;
+ int lk;
+ int lm;
+ int interleave;
+ unsigned long base;
+ unsigned long size;
+};
+
+struct chmc {
+ struct list_head list;
+ int portid;
+
+ struct chmc_obp_mem_layout layout_prop;
+ int layout_size;
+
+ void __iomem *regs;
+
+ u64 timing_control1;
+ u64 timing_control2;
+ u64 timing_control3;
+ u64 timing_control4;
+ u64 memaddr_control;
+
+ struct chmc_bank_info logical_banks[CHMCTRL_NBANKS];
+};
+
+#define JBUSMC_REGS_SIZE 8
+
+#define JB_MC_REG1_DIMM2_BANK3 0x8000000000000000UL
+#define JB_MC_REG1_DIMM1_BANK1 0x4000000000000000UL
+#define JB_MC_REG1_DIMM2_BANK2 0x2000000000000000UL
+#define JB_MC_REG1_DIMM1_BANK0 0x1000000000000000UL
+#define JB_MC_REG1_XOR 0x0000010000000000UL
+#define JB_MC_REG1_ADDR_GEN_2 0x000000e000000000UL
+#define JB_MC_REG1_ADDR_GEN_2_SHIFT 37
+#define JB_MC_REG1_ADDR_GEN_1 0x0000001c00000000UL
+#define JB_MC_REG1_ADDR_GEN_1_SHIFT 34
+#define JB_MC_REG1_INTERLEAVE 0x0000000001800000UL
+#define JB_MC_REG1_INTERLEAVE_SHIFT 23
+#define JB_MC_REG1_DIMM2_PTYPE 0x0000000000200000UL
+#define JB_MC_REG1_DIMM2_PTYPE_SHIFT 21
+#define JB_MC_REG1_DIMM1_PTYPE 0x0000000000100000UL
+#define JB_MC_REG1_DIMM1_PTYPE_SHIFT 20
+
+#define PART_TYPE_X8 0
+#define PART_TYPE_X4 1
+
+#define INTERLEAVE_NONE 0
+#define INTERLEAVE_SAME 1
+#define INTERLEAVE_INTERNAL 2
+#define INTERLEAVE_BOTH 3
+
+#define ADDR_GEN_128MB 0
+#define ADDR_GEN_256MB 1
+#define ADDR_GEN_512MB 2
+#define ADDR_GEN_1GB 3
+
+#define JB_NUM_DIMM_GROUPS 2
+#define JB_NUM_DIMMS_PER_GROUP 2
+#define JB_NUM_DIMMS (JB_NUM_DIMM_GROUPS * JB_NUM_DIMMS_PER_GROUP)
+
+struct jbusmc_obp_map {
+ unsigned char dimm_map[18];
+ unsigned char pin_map[144];
+};
+
+struct jbusmc_obp_mem_layout {
+ /* One max 8-byte string label per DIMM. Usually
+ * this matches the label on the motherboard where
+ * that DIMM resides.
+ */
+ char dimm_labels[JB_NUM_DIMMS][DIMM_LABEL_SZ];
+
+ /* If symmetric use map[0], else it is
+ * asymmetric and map[1] should be used.
+ */
+ char symmetric;
+
+ struct jbusmc_obp_map map;
+
+ char _pad;
+};
+
+struct jbusmc_dimm_group {
+ struct jbusmc *controller;
+ int index;
+ u64 base_addr;
+ u64 size;
+};
+
+struct jbusmc {
+ void __iomem *regs;
+ u64 mc_reg_1;
+ u32 portid;
+ struct jbusmc_obp_mem_layout layout;
+ int layout_len;
+ int num_dimm_groups;
+ struct jbusmc_dimm_group dimm_groups[JB_NUM_DIMM_GROUPS];
+ struct list_head list;
+};
+
+static DEFINE_SPINLOCK(mctrl_list_lock);
+static LIST_HEAD(mctrl_list);
+
+static void mc_list_add(struct list_head *list)
+{
+ spin_lock(&mctrl_list_lock);
+ list_add(list, &mctrl_list);
+ spin_unlock(&mctrl_list_lock);
+}
+
+static void mc_list_del(struct list_head *list)
+{
+ spin_lock(&mctrl_list_lock);
+ list_del_init(list);
+ spin_unlock(&mctrl_list_lock);
+}
+
+#define SYNDROME_MIN -1
+#define SYNDROME_MAX 144
+
+/* Covert syndrome code into the way the bits are positioned
+ * on the bus.
+ */
+static int syndrome_to_qword_code(int syndrome_code)
+{
+ if (syndrome_code < 128)
+ syndrome_code += 16;
+ else if (syndrome_code < 128 + 9)
+ syndrome_code -= (128 - 7);
+ else if (syndrome_code < (128 + 9 + 3))
+ syndrome_code -= (128 + 9 - 4);
+ else
+ syndrome_code -= (128 + 9 + 3);
+ return syndrome_code;
+}
+
+/* All this magic has to do with how a cache line comes over the wire
+ * on Safari and JBUS. A 64-bit line comes over in 1 or more quadword
+ * cycles, each of which transmit ECC/MTAG info as well as the actual
+ * data.
+ */
+#define L2_LINE_SIZE 64
+#define L2_LINE_ADDR_MSK (L2_LINE_SIZE - 1)
+#define QW_PER_LINE 4
+#define QW_BYTES (L2_LINE_SIZE / QW_PER_LINE)
+#define QW_BITS 144
+#define SAFARI_LAST_BIT (576 - 1)
+#define JBUS_LAST_BIT (144 - 1)
+
+static void get_pin_and_dimm_str(int syndrome_code, unsigned long paddr,
+ int *pin_p, char **dimm_str_p, void *_prop,
+ int base_dimm_offset)
+{
+ int qword_code = syndrome_to_qword_code(syndrome_code);
+ int cache_line_offset;
+ int offset_inverse;
+ int dimm_map_index;
+ int map_val;
+
+ if (mc_type == MC_TYPE_JBUS) {
+ struct jbusmc_obp_mem_layout *p = _prop;
+
+ /* JBUS */
+ cache_line_offset = qword_code;
+ offset_inverse = (JBUS_LAST_BIT - cache_line_offset);
+ dimm_map_index = offset_inverse / 8;
+ map_val = p->map.dimm_map[dimm_map_index];
+ map_val = ((map_val >> ((7 - (offset_inverse & 7)))) & 1);
+ *dimm_str_p = p->dimm_labels[base_dimm_offset + map_val];
+ *pin_p = p->map.pin_map[cache_line_offset];
+ } else {
+ struct chmc_obp_mem_layout *p = _prop;
+ struct chmc_obp_map *mp;
+ int qword;
+
+ /* Safari */
+ if (p->symmetric)
+ mp = &p->map[0];
+ else
+ mp = &p->map[1];
+
+ qword = (paddr & L2_LINE_ADDR_MSK) / QW_BYTES;
+ cache_line_offset = ((3 - qword) * QW_BITS) + qword_code;
+ offset_inverse = (SAFARI_LAST_BIT - cache_line_offset);
+ dimm_map_index = offset_inverse >> 2;
+ map_val = mp->dimm_map[dimm_map_index];
+ map_val = ((map_val >> ((3 - (offset_inverse & 3)) << 1)) & 0x3);
+ *dimm_str_p = p->dimm_labels[base_dimm_offset + map_val];
+ *pin_p = mp->pin_map[cache_line_offset];
+ }
+}
+
+static struct jbusmc_dimm_group *jbusmc_find_dimm_group(unsigned long phys_addr)
+{
+ struct jbusmc *p;
+
+ list_for_each_entry(p, &mctrl_list, list) {
+ int i;
+
+ for (i = 0; i < p->num_dimm_groups; i++) {
+ struct jbusmc_dimm_group *dp = &p->dimm_groups[i];
+
+ if (phys_addr < dp->base_addr ||
+ (dp->base_addr + dp->size) <= phys_addr)
+ continue;
+
+ return dp;
+ }
+ }
+ return NULL;
+}
+
+static int jbusmc_print_dimm(int syndrome_code,
+ unsigned long phys_addr,
+ char *buf, int buflen)
+{
+ struct jbusmc_obp_mem_layout *prop;
+ struct jbusmc_dimm_group *dp;
+ struct jbusmc *p;
+ int first_dimm;
+
+ dp = jbusmc_find_dimm_group(phys_addr);
+ if (dp == NULL ||
+ syndrome_code < SYNDROME_MIN ||
+ syndrome_code > SYNDROME_MAX) {
+ buf[0] = '?';
+ buf[1] = '?';
+ buf[2] = '?';
+ buf[3] = '\0';
+ }
+ p = dp->controller;
+ prop = &p->layout;
+
+ first_dimm = dp->index * JB_NUM_DIMMS_PER_GROUP;
+
+ if (syndrome_code != SYNDROME_MIN) {
+ char *dimm_str;
+ int pin;
+
+ get_pin_and_dimm_str(syndrome_code, phys_addr, &pin,
+ &dimm_str, prop, first_dimm);
+ sprintf(buf, "%s, pin %3d", dimm_str, pin);
+ } else {
+ int dimm;
+
+ /* Multi-bit error, we just dump out all the
+ * dimm labels associated with this dimm group.
+ */
+ for (dimm = 0; dimm < JB_NUM_DIMMS_PER_GROUP; dimm++) {
+ sprintf(buf, "%s ",
+ prop->dimm_labels[first_dimm + dimm]);
+ buf += strlen(buf);
+ }
+ }
+
+ return 0;
+}
+
+static u64 __devinit jbusmc_dimm_group_size(u64 base,
+ const struct linux_prom64_registers *mem_regs,
+ int num_mem_regs)
+{
+ u64 max = base + (8UL * 1024 * 1024 * 1024);
+ u64 max_seen = base;
+ int i;
+
+ for (i = 0; i < num_mem_regs; i++) {
+ const struct linux_prom64_registers *ent;
+ u64 this_base;
+ u64 this_end;
+
+ ent = &mem_regs[i];
+ this_base = ent->phys_addr;
+ this_end = this_base + ent->reg_size;
+ if (base < this_base || base >= this_end)
+ continue;
+ if (this_end > max)
+ this_end = max;
+ if (this_end > max_seen)
+ max_seen = this_end;
+ }
+
+ return max_seen - base;
+}
+
+static void __devinit jbusmc_construct_one_dimm_group(struct jbusmc *p,
+ unsigned long index,
+ const struct linux_prom64_registers *mem_regs,
+ int num_mem_regs)
+{
+ struct jbusmc_dimm_group *dp = &p->dimm_groups[index];
+
+ dp->controller = p;
+ dp->index = index;
+
+ dp->base_addr = (p->portid * (64UL * 1024 * 1024 * 1024));
+ dp->base_addr += (index * (8UL * 1024 * 1024 * 1024));
+ dp->size = jbusmc_dimm_group_size(dp->base_addr, mem_regs, num_mem_regs);
+}
+
+static void __devinit jbusmc_construct_dimm_groups(struct jbusmc *p,
+ const struct linux_prom64_registers *mem_regs,
+ int num_mem_regs)
+{
+ if (p->mc_reg_1 & JB_MC_REG1_DIMM1_BANK0) {
+ jbusmc_construct_one_dimm_group(p, 0, mem_regs, num_mem_regs);
+ p->num_dimm_groups++;
+ }
+ if (p->mc_reg_1 & JB_MC_REG1_DIMM2_BANK2) {
+ jbusmc_construct_one_dimm_group(p, 1, mem_regs, num_mem_regs);
+ p->num_dimm_groups++;
+ }
+}
+
+static int __devinit jbusmc_probe(struct of_device *op,
+ const struct of_device_id *match)
+{
+ const struct linux_prom64_registers *mem_regs;
+ struct device_node *mem_node;
+ int err, len, num_mem_regs;
+ struct jbusmc *p;
+ const u32 *prop;
+ const void *ml;
+
+ err = -ENODEV;
+ mem_node = of_find_node_by_path("/memory");
+ if (!mem_node) {
+ printk(KERN_ERR PFX "Cannot find /memory node.\n");
+ goto out;
+ }
+ mem_regs = of_get_property(mem_node, "reg", &len);
+ if (!mem_regs) {
+ printk(KERN_ERR PFX "Cannot get reg property of /memory node.\n");
+ goto out;
+ }
+ num_mem_regs = len / sizeof(*mem_regs);
+
+ err = -ENOMEM;
+ p = kzalloc(sizeof(*p), GFP_KERNEL);
+ if (!p) {
+ printk(KERN_ERR PFX "Cannot allocate struct jbusmc.\n");
+ goto out;
+ }
+
+ INIT_LIST_HEAD(&p->list);
+
+ err = -ENODEV;
+ prop = of_get_property(op->node, "portid", &len);
+ if (!prop || len != 4) {
+ printk(KERN_ERR PFX "Cannot find portid.\n");
+ goto out_free;
+ }
+
+ p->portid = *prop;
+
+ prop = of_get_property(op->node, "memory-control-register-1", &len);
+ if (!prop || len != 8) {
+ printk(KERN_ERR PFX "Cannot get memory control register 1.\n");
+ goto out_free;
+ }
+
+ p->mc_reg_1 = ((u64)prop[0] << 32) | (u64) prop[1];
+
+ err = -ENOMEM;
+ p->regs = of_ioremap(&op->resource[0], 0, JBUSMC_REGS_SIZE, "jbusmc");
+ if (!p->regs) {
+ printk(KERN_ERR PFX "Cannot map jbusmc regs.\n");
+ goto out_free;
+ }
+
+ err = -ENODEV;
+ ml = of_get_property(op->node, "memory-layout", &p->layout_len);
+ if (!ml) {
+ printk(KERN_ERR PFX "Cannot get memory layout property.\n");
+ goto out_iounmap;
+ }
+ if (p->layout_len > sizeof(p->layout)) {
+ printk(KERN_ERR PFX "Unexpected memory-layout size %d\n",
+ p->layout_len);
+ goto out_iounmap;
+ }
+ memcpy(&p->layout, ml, p->layout_len);
+
+ jbusmc_construct_dimm_groups(p, mem_regs, num_mem_regs);
+
+ mc_list_add(&p->list);
+
+ printk(KERN_INFO PFX "UltraSPARC-IIIi memory controller at %s\n",
+ op->node->full_name);
+
+ dev_set_drvdata(&op->dev, p);
+
+ err = 0;
+
+out:
+ return err;
+
+out_iounmap:
+ of_iounmap(&op->resource[0], p->regs, JBUSMC_REGS_SIZE);
+
+out_free:
+ kfree(p);
+ goto out;
+}
+
+/* Does BANK decode PHYS_ADDR? */
+static int chmc_bank_match(struct chmc_bank_info *bp, unsigned long phys_addr)
+{
+ unsigned long upper_bits = (phys_addr & PA_UPPER_BITS) >> PA_UPPER_BITS_SHIFT;
+ unsigned long lower_bits = (phys_addr & PA_LOWER_BITS) >> PA_LOWER_BITS_SHIFT;
+
+ /* Bank must be enabled to match. */
+ if (bp->valid == 0)
+ return 0;
+
+ /* Would BANK match upper bits? */
+ upper_bits ^= bp->um; /* What bits are different? */
+ upper_bits = ~upper_bits; /* Invert. */
+ upper_bits |= bp->uk; /* What bits don't matter for matching? */
+ upper_bits = ~upper_bits; /* Invert. */
+
+ if (upper_bits)
+ return 0;
+
+ /* Would BANK match lower bits? */
+ lower_bits ^= bp->lm; /* What bits are different? */
+ lower_bits = ~lower_bits; /* Invert. */
+ lower_bits |= bp->lk; /* What bits don't matter for matching? */
+ lower_bits = ~lower_bits; /* Invert. */
+
+ if (lower_bits)
+ return 0;
+
+ /* I always knew you'd be the one. */
+ return 1;
+}
+
+/* Given PHYS_ADDR, search memory controller banks for a match. */
+static struct chmc_bank_info *chmc_find_bank(unsigned long phys_addr)
+{
+ struct chmc *p;
+
+ list_for_each_entry(p, &mctrl_list, list) {
+ int bank_no;
+
+ for (bank_no = 0; bank_no < CHMCTRL_NBANKS; bank_no++) {
+ struct chmc_bank_info *bp;
+
+ bp = &p->logical_banks[bank_no];
+ if (chmc_bank_match(bp, phys_addr))
+ return bp;
+ }
+ }
+
+ return NULL;
+}
+
+/* This is the main purpose of this driver. */
+static int chmc_print_dimm(int syndrome_code,
+ unsigned long phys_addr,
+ char *buf, int buflen)
+{
+ struct chmc_bank_info *bp;
+ struct chmc_obp_mem_layout *prop;
+ int bank_in_controller, first_dimm;
+
+ bp = chmc_find_bank(phys_addr);
+ if (bp == NULL ||
+ syndrome_code < SYNDROME_MIN ||
+ syndrome_code > SYNDROME_MAX) {
+ buf[0] = '?';
+ buf[1] = '?';
+ buf[2] = '?';
+ buf[3] = '\0';
+ return 0;
+ }
+
+ prop = &bp->p->layout_prop;
+ bank_in_controller = bp->bank_id & (CHMCTRL_NBANKS - 1);
+ first_dimm = (bank_in_controller & (CHMCTRL_NDGRPS - 1));
+ first_dimm *= CHMCTRL_NDIMMS;
+
+ if (syndrome_code != SYNDROME_MIN) {
+ char *dimm_str;
+ int pin;
+
+ get_pin_and_dimm_str(syndrome_code, phys_addr, &pin,
+ &dimm_str, prop, first_dimm);
+ sprintf(buf, "%s, pin %3d", dimm_str, pin);
+ } else {
+ int dimm;
+
+ /* Multi-bit error, we just dump out all the
+ * dimm labels associated with this bank.
+ */
+ for (dimm = 0; dimm < CHMCTRL_NDIMMS; dimm++) {
+ sprintf(buf, "%s ",
+ prop->dimm_labels[first_dimm + dimm]);
+ buf += strlen(buf);
+ }
+ }
+ return 0;
+}
+
+/* Accessing the registers is slightly complicated. If you want
+ * to get at the memory controller which is on the same processor
+ * the code is executing, you must use special ASI load/store else
+ * you go through the global mapping.
+ */
+static u64 chmc_read_mcreg(struct chmc *p, unsigned long offset)
+{
+ unsigned long ret, this_cpu;
+
+ preempt_disable();
+
+ this_cpu = real_hard_smp_processor_id();
+
+ if (p->portid == this_cpu) {
+ __asm__ __volatile__("ldxa [%1] %2, %0"
+ : "=r" (ret)
+ : "r" (offset), "i" (ASI_MCU_CTRL_REG));
+ } else {
+ __asm__ __volatile__("ldxa [%1] %2, %0"
+ : "=r" (ret)
+ : "r" (p->regs + offset),
+ "i" (ASI_PHYS_BYPASS_EC_E));
+ }
+
+ preempt_enable();
+
+ return ret;
+}
+
+#if 0 /* currently unused */
+static void chmc_write_mcreg(struct chmc *p, unsigned long offset, u64 val)
+{
+ if (p->portid == smp_processor_id()) {
+ __asm__ __volatile__("stxa %0, [%1] %2"
+ : : "r" (val),
+ "r" (offset), "i" (ASI_MCU_CTRL_REG));
+ } else {
+ __asm__ __volatile__("ldxa %0, [%1] %2"
+ : : "r" (val),
+ "r" (p->regs + offset),
+ "i" (ASI_PHYS_BYPASS_EC_E));
+ }
+}
+#endif
+
+static void chmc_interpret_one_decode_reg(struct chmc *p, int which_bank, u64 val)
+{
+ struct chmc_bank_info *bp = &p->logical_banks[which_bank];
+
+ bp->p = p;
+ bp->bank_id = (CHMCTRL_NBANKS * p->portid) + which_bank;
+ bp->raw_reg = val;
+ bp->valid = (val & MEM_DECODE_VALID) >> MEM_DECODE_VALID_SHIFT;
+ bp->uk = (val & MEM_DECODE_UK) >> MEM_DECODE_UK_SHIFT;
+ bp->um = (val & MEM_DECODE_UM) >> MEM_DECODE_UM_SHIFT;
+ bp->lk = (val & MEM_DECODE_LK) >> MEM_DECODE_LK_SHIFT;
+ bp->lm = (val & MEM_DECODE_LM) >> MEM_DECODE_LM_SHIFT;
+
+ bp->base = (bp->um);
+ bp->base &= ~(bp->uk);
+ bp->base <<= PA_UPPER_BITS_SHIFT;
+
+ switch(bp->lk) {
+ case 0xf:
+ default:
+ bp->interleave = 1;
+ break;
+
+ case 0xe:
+ bp->interleave = 2;
+ break;
+
+ case 0xc:
+ bp->interleave = 4;
+ break;
+
+ case 0x8:
+ bp->interleave = 8;
+ break;
+
+ case 0x0:
+ bp->interleave = 16;
+ break;
+ };
+
+ /* UK[10] is reserved, and UK[11] is not set for the SDRAM
+ * bank size definition.
+ */
+ bp->size = (((unsigned long)bp->uk &
+ ((1UL << 10UL) - 1UL)) + 1UL) << PA_UPPER_BITS_SHIFT;
+ bp->size /= bp->interleave;
+}
+
+static void chmc_fetch_decode_regs(struct chmc *p)
+{
+ if (p->layout_size == 0)
+ return;
+
+ chmc_interpret_one_decode_reg(p, 0,
+ chmc_read_mcreg(p, CHMCTRL_DECODE1));
+ chmc_interpret_one_decode_reg(p, 1,
+ chmc_read_mcreg(p, CHMCTRL_DECODE2));
+ chmc_interpret_one_decode_reg(p, 2,
+ chmc_read_mcreg(p, CHMCTRL_DECODE3));
+ chmc_interpret_one_decode_reg(p, 3,
+ chmc_read_mcreg(p, CHMCTRL_DECODE4));
+}
+
+static int __devinit chmc_probe(struct of_device *op,
+ const struct of_device_id *match)
+{
+ struct device_node *dp = op->node;
+ unsigned long ver;
+ const void *pval;
+ int len, portid;
+ struct chmc *p;
+ int err;
+
+ err = -ENODEV;
+ __asm__ ("rdpr %%ver, %0" : "=r" (ver));
+ if ((ver >> 32UL) == __JALAPENO_ID ||
+ (ver >> 32UL) == __SERRANO_ID)
+ goto out;
+
+ portid = of_getintprop_default(dp, "portid", -1);
+ if (portid == -1)
+ goto out;
+
+ pval = of_get_property(dp, "memory-layout", &len);
+ if (pval && len > sizeof(p->layout_prop)) {
+ printk(KERN_ERR PFX "Unexpected memory-layout property "
+ "size %d.\n", len);
+ goto out;
+ }
+
+ err = -ENOMEM;
+ p = kzalloc(sizeof(*p), GFP_KERNEL);
+ if (!p) {
+ printk(KERN_ERR PFX "Could not allocate struct chmc.\n");
+ goto out;
+ }
+
+ p->portid = portid;
+ p->layout_size = len;
+ if (!pval)
+ p->layout_size = 0;
+ else
+ memcpy(&p->layout_prop, pval, len);
+
+ p->regs = of_ioremap(&op->resource[0], 0, 0x48, "chmc");
+ if (!p->regs) {
+ printk(KERN_ERR PFX "Could not map registers.\n");
+ goto out_free;
+ }
+
+ if (p->layout_size != 0UL) {
+ p->timing_control1 = chmc_read_mcreg(p, CHMCTRL_TCTRL1);
+ p->timing_control2 = chmc_read_mcreg(p, CHMCTRL_TCTRL2);
+ p->timing_control3 = chmc_read_mcreg(p, CHMCTRL_TCTRL3);
+ p->timing_control4 = chmc_read_mcreg(p, CHMCTRL_TCTRL4);
+ p->memaddr_control = chmc_read_mcreg(p, CHMCTRL_MACTRL);
+ }
+
+ chmc_fetch_decode_regs(p);
+
+ mc_list_add(&p->list);
+
+ printk(KERN_INFO PFX "UltraSPARC-III memory controller at %s [%s]\n",
+ dp->full_name,
+ (p->layout_size ? "ACTIVE" : "INACTIVE"));
+
+ dev_set_drvdata(&op->dev, p);
+
+ err = 0;
+
+out:
+ return err;
+
+out_free:
+ kfree(p);
+ goto out;
+}
+
+static int __devinit us3mc_probe(struct of_device *op,
+ const struct of_device_id *match)
+{
+ if (mc_type == MC_TYPE_SAFARI)
+ return chmc_probe(op, match);
+ else if (mc_type == MC_TYPE_JBUS)
+ return jbusmc_probe(op, match);
+ return -ENODEV;
+}
+
+static void __devexit chmc_destroy(struct of_device *op, struct chmc *p)
+{
+ list_del(&p->list);
+ of_iounmap(&op->resource[0], p->regs, 0x48);
+ kfree(p);
+}
+
+static void __devexit jbusmc_destroy(struct of_device *op, struct jbusmc *p)
+{
+ mc_list_del(&p->list);
+ of_iounmap(&op->resource[0], p->regs, JBUSMC_REGS_SIZE);
+ kfree(p);
+}
+
+static int __devexit us3mc_remove(struct of_device *op)
+{
+ void *p = dev_get_drvdata(&op->dev);
+
+ if (p) {
+ if (mc_type == MC_TYPE_SAFARI)
+ chmc_destroy(op, p);
+ else if (mc_type == MC_TYPE_JBUS)
+ jbusmc_destroy(op, p);
+ }
+ return 0;
+}
+
+static const struct of_device_id us3mc_match[] = {
+ {
+ .name = "memory-controller",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, us3mc_match);
+
+static struct of_platform_driver us3mc_driver = {
+ .name = "us3mc",
+ .match_table = us3mc_match,
+ .probe = us3mc_probe,
+ .remove = __devexit_p(us3mc_remove),
+};
+
+static inline bool us3mc_platform(void)
+{
+ if (tlb_type == cheetah || tlb_type == cheetah_plus)
+ return true;
+ return false;
+}
+
+static int __init us3mc_init(void)
+{
+ unsigned long ver;
+ int ret;
+
+ if (!us3mc_platform())
+ return -ENODEV;
+
+ __asm__ __volatile__("rdpr %%ver, %0" : "=r" (ver));
+ if ((ver >> 32UL) == __JALAPENO_ID ||
+ (ver >> 32UL) == __SERRANO_ID) {
+ mc_type = MC_TYPE_JBUS;
+ us3mc_dimm_printer = jbusmc_print_dimm;
+ } else {
+ mc_type = MC_TYPE_SAFARI;
+ us3mc_dimm_printer = chmc_print_dimm;
+ }
+
+ ret = register_dimm_printer(us3mc_dimm_printer);
+
+ if (!ret) {
+ ret = of_register_driver(&us3mc_driver, &of_bus_type);
+ if (ret)
+ unregister_dimm_printer(us3mc_dimm_printer);
+ }
+ return ret;
+}
+
+static void __exit us3mc_cleanup(void)
+{
+ if (us3mc_platform()) {
+ unregister_dimm_printer(us3mc_dimm_printer);
+ of_unregister_driver(&us3mc_driver);
+ }
+}
+
+module_init(us3mc_init);
+module_exit(us3mc_cleanup);
diff --git a/arch/sparc/kernel/compat_audit.c b/arch/sparc/kernel/compat_audit.c
new file mode 100644
index 000000000000..d865575b25bf
--- /dev/null
+++ b/arch/sparc/kernel/compat_audit.c
@@ -0,0 +1,43 @@
+#define __32bit_syscall_numbers__
+#include <asm/unistd.h>
+
+unsigned sparc32_dir_class[] = {
+#include <asm-generic/audit_dir_write.h>
+~0U
+};
+
+unsigned sparc32_chattr_class[] = {
+#include <asm-generic/audit_change_attr.h>
+~0U
+};
+
+unsigned sparc32_write_class[] = {
+#include <asm-generic/audit_write.h>
+~0U
+};
+
+unsigned sparc32_read_class[] = {
+#include <asm-generic/audit_read.h>
+~0U
+};
+
+unsigned sparc32_signal_class[] = {
+#include <asm-generic/audit_signal.h>
+~0U
+};
+
+int sparc32_classify_syscall(unsigned syscall)
+{
+ switch(syscall) {
+ case __NR_open:
+ return 2;
+ case __NR_openat:
+ return 3;
+ case __NR_socketcall:
+ return 4;
+ case __NR_execve:
+ return 5;
+ default:
+ return 1;
+ }
+}
diff --git a/arch/sparc/kernel/cpu.c b/arch/sparc/kernel/cpu.c
index 1fc17f59c6bf..6c2da2420f76 100644
--- a/arch/sparc/kernel/cpu.c
+++ b/arch/sparc/kernel/cpu.c
@@ -8,6 +8,8 @@
#include <linux/init.h>
#include <linux/smp.h>
#include <linux/threads.h>
+
+#include <asm/spitfire.h>
#include <asm/oplib.h>
#include <asm/page.h>
#include <asm/head.h>
@@ -15,153 +17,322 @@
#include <asm/mbus.h>
#include <asm/cpudata.h>
+#include "kernel.h"
+
DEFINE_PER_CPU(cpuinfo_sparc, __cpu_data) = { 0 };
-struct cpu_iu_info {
- int psr_impl;
- int psr_vers;
- char* cpu_name; /* should be enough I hope... */
+struct cpu_info {
+ int psr_vers;
+ const char *name;
+};
+
+struct fpu_info {
+ int fp_vers;
+ const char *name;
};
-struct cpu_fp_info {
- int psr_impl;
- int fp_vers;
- char* fp_name;
+#define NOCPU 8
+#define NOFPU 8
+
+struct manufacturer_info {
+ int psr_impl;
+ struct cpu_info cpu_info[NOCPU];
+ struct fpu_info fpu_info[NOFPU];
};
+#define CPU(ver, _name) \
+{ .psr_vers = ver, .name = _name }
+
+#define FPU(ver, _name) \
+{ .fp_vers = ver, .name = _name }
+
+static const struct manufacturer_info __initconst manufacturer_info[] = {
+{
+ 0,
+ /* Sun4/100, 4/200, SLC */
+ .cpu_info = {
+ CPU(0, "Fujitsu MB86900/1A or LSI L64831 SparcKIT-40"),
+ /* borned STP1012PGA */
+ CPU(4, "Fujitsu MB86904"),
+ CPU(5, "Fujitsu TurboSparc MB86907"),
+ CPU(-1, NULL)
+ },
+ .fpu_info = {
+ FPU(0, "Fujitsu MB86910 or Weitek WTL1164/5"),
+ FPU(1, "Fujitsu MB86911 or Weitek WTL1164/5 or LSI L64831"),
+ FPU(2, "LSI Logic L64802 or Texas Instruments ACT8847"),
+ /* SparcStation SLC, SparcStation1 */
+ FPU(3, "Weitek WTL3170/2"),
+ /* SPARCstation-5 */
+ FPU(4, "Lsi Logic/Meiko L64804 or compatible"),
+ FPU(-1, NULL)
+ }
+},{
+ 1,
+ .cpu_info = {
+ /* SparcStation2, SparcServer 490 & 690 */
+ CPU(0, "LSI Logic Corporation - L64811"),
+ /* SparcStation2 */
+ CPU(1, "Cypress/ROSS CY7C601"),
+ /* Embedded controller */
+ CPU(3, "Cypress/ROSS CY7C611"),
+ /* Ross Technologies HyperSparc */
+ CPU(0xf, "ROSS HyperSparc RT620"),
+ CPU(0xe, "ROSS HyperSparc RT625 or RT626"),
+ CPU(-1, NULL)
+ },
+ .fpu_info = {
+ FPU(0, "ROSS HyperSparc combined IU/FPU"),
+ FPU(1, "Lsi Logic L64814"),
+ FPU(2, "Texas Instruments TMS390-C602A"),
+ FPU(3, "Cypress CY7C602 FPU"),
+ FPU(-1, NULL)
+ }
+},{
+ 2,
+ .cpu_info = {
+ /* ECL Implementation, CRAY S-MP Supercomputer... AIEEE! */
+ /* Someone please write the code to support this beast! ;) */
+ CPU(0, "Bipolar Integrated Technology - B5010"),
+ CPU(-1, NULL)
+ },
+ .fpu_info = {
+ FPU(-1, NULL)
+ }
+},{
+ 3,
+ .cpu_info = {
+ CPU(0, "LSI Logic Corporation - unknown-type"),
+ CPU(-1, NULL)
+ },
+ .fpu_info = {
+ FPU(-1, NULL)
+ }
+},{
+ 4,
+ .cpu_info = {
+ CPU(0, "Texas Instruments, Inc. - SuperSparc-(II)"),
+ /* SparcClassic -- borned STP1010TAB-50*/
+ CPU(1, "Texas Instruments, Inc. - MicroSparc"),
+ CPU(2, "Texas Instruments, Inc. - MicroSparc II"),
+ CPU(3, "Texas Instruments, Inc. - SuperSparc 51"),
+ CPU(4, "Texas Instruments, Inc. - SuperSparc 61"),
+ CPU(5, "Texas Instruments, Inc. - unknown"),
+ CPU(-1, NULL)
+ },
+ .fpu_info = {
+ /* SuperSparc 50 module */
+ FPU(0, "SuperSparc on-chip FPU"),
+ /* SparcClassic */
+ FPU(4, "TI MicroSparc on chip FPU"),
+ FPU(-1, NULL)
+ }
+},{
+ 5,
+ .cpu_info = {
+ CPU(0, "Matsushita - MN10501"),
+ CPU(-1, NULL)
+ },
+ .fpu_info = {
+ FPU(0, "Matsushita MN10501"),
+ FPU(-1, NULL)
+ }
+},{
+ 6,
+ .cpu_info = {
+ CPU(0, "Philips Corporation - unknown"),
+ CPU(-1, NULL)
+ },
+ .fpu_info = {
+ FPU(-1, NULL)
+ }
+},{
+ 7,
+ .cpu_info = {
+ CPU(0, "Harvest VLSI Design Center, Inc. - unknown"),
+ CPU(-1, NULL)
+ },
+ .fpu_info = {
+ FPU(-1, NULL)
+ }
+},{
+ 8,
+ .cpu_info = {
+ CPU(0, "Systems and Processes Engineering Corporation (SPEC)"),
+ CPU(-1, NULL)
+ },
+ .fpu_info = {
+ FPU(-1, NULL)
+ }
+},{
+ 9,
+ .cpu_info = {
+ /* Gallium arsenide 200MHz, BOOOOGOOOOMIPS!!! */
+ CPU(0, "Fujitsu or Weitek Power-UP"),
+ CPU(1, "Fujitsu or Weitek Power-UP"),
+ CPU(2, "Fujitsu or Weitek Power-UP"),
+ CPU(3, "Fujitsu or Weitek Power-UP"),
+ CPU(-1, NULL)
+ },
+ .fpu_info = {
+ FPU(3, "Fujitsu or Weitek on-chip FPU"),
+ FPU(-1, NULL)
+ }
+},{
+ 0x17,
+ .cpu_info = {
+ CPU(0x10, "TI UltraSparc I (SpitFire)"),
+ CPU(0x11, "TI UltraSparc II (BlackBird)"),
+ CPU(0x12, "TI UltraSparc IIi (Sabre)"),
+ CPU(0x13, "TI UltraSparc IIe (Hummingbird)"),
+ CPU(-1, NULL)
+ },
+ .fpu_info = {
+ FPU(0x10, "UltraSparc I integrated FPU"),
+ FPU(0x11, "UltraSparc II integrated FPU"),
+ FPU(0x12, "UltraSparc IIi integrated FPU"),
+ FPU(0x13, "UltraSparc IIe integrated FPU"),
+ FPU(-1, NULL)
+ }
+},{
+ 0x22,
+ .cpu_info = {
+ CPU(0x10, "TI UltraSparc I (SpitFire)"),
+ CPU(-1, NULL)
+ },
+ .fpu_info = {
+ FPU(0x10, "UltraSparc I integrated FPU"),
+ FPU(-1, NULL)
+ }
+},{
+ 0x3e,
+ .cpu_info = {
+ CPU(0x14, "TI UltraSparc III (Cheetah)"),
+ CPU(0x15, "TI UltraSparc III+ (Cheetah+)"),
+ CPU(0x16, "TI UltraSparc IIIi (Jalapeno)"),
+ CPU(0x18, "TI UltraSparc IV (Jaguar)"),
+ CPU(0x19, "TI UltraSparc IV+ (Panther)"),
+ CPU(0x22, "TI UltraSparc IIIi+ (Serrano)"),
+ CPU(-1, NULL)
+ },
+ .fpu_info = {
+ FPU(0x14, "UltraSparc III integrated FPU"),
+ FPU(0x15, "UltraSparc III+ integrated FPU"),
+ FPU(0x16, "UltraSparc IIIi integrated FPU"),
+ FPU(0x18, "UltraSparc IV integrated FPU"),
+ FPU(0x19, "UltraSparc IV+ integrated FPU"),
+ FPU(0x22, "UltraSparc IIIi+ integrated FPU"),
+ FPU(-1, NULL)
+ }
+}};
+
/* In order to get the fpu type correct, you need to take the IDPROM's
* machine type value into consideration too. I will fix this.
*/
-static struct cpu_fp_info linux_sparc_fpu[] = {
- { 0, 0, "Fujitsu MB86910 or Weitek WTL1164/5"},
- { 0, 1, "Fujitsu MB86911 or Weitek WTL1164/5 or LSI L64831"},
- { 0, 2, "LSI Logic L64802 or Texas Instruments ACT8847"},
- /* SparcStation SLC, SparcStation1 */
- { 0, 3, "Weitek WTL3170/2"},
- /* SPARCstation-5 */
- { 0, 4, "Lsi Logic/Meiko L64804 or compatible"},
- { 0, 5, "reserved"},
- { 0, 6, "reserved"},
- { 0, 7, "No FPU"},
- { 1, 0, "ROSS HyperSparc combined IU/FPU"},
- { 1, 1, "Lsi Logic L64814"},
- { 1, 2, "Texas Instruments TMS390-C602A"},
- { 1, 3, "Cypress CY7C602 FPU"},
- { 1, 4, "reserved"},
- { 1, 5, "reserved"},
- { 1, 6, "reserved"},
- { 1, 7, "No FPU"},
- { 2, 0, "BIT B5010 or B5110/20 or B5210"},
- { 2, 1, "reserved"},
- { 2, 2, "reserved"},
- { 2, 3, "reserved"},
- { 2, 4, "reserved"},
- { 2, 5, "reserved"},
- { 2, 6, "reserved"},
- { 2, 7, "No FPU"},
- /* SuperSparc 50 module */
- { 4, 0, "SuperSparc on-chip FPU"},
- /* SparcClassic */
- { 4, 4, "TI MicroSparc on chip FPU"},
- { 5, 0, "Matsushita MN10501"},
- { 5, 1, "reserved"},
- { 5, 2, "reserved"},
- { 5, 3, "reserved"},
- { 5, 4, "reserved"},
- { 5, 5, "reserved"},
- { 5, 6, "reserved"},
- { 5, 7, "No FPU"},
- { 9, 3, "Fujitsu or Weitek on-chip FPU"},
-};
-#define NSPARCFPU ARRAY_SIZE(linux_sparc_fpu)
-
-static struct cpu_iu_info linux_sparc_chips[] = {
- /* Sun4/100, 4/200, SLC */
- { 0, 0, "Fujitsu MB86900/1A or LSI L64831 SparcKIT-40"},
- /* borned STP1012PGA */
- { 0, 4, "Fujitsu MB86904"},
- { 0, 5, "Fujitsu TurboSparc MB86907"},
- /* SparcStation2, SparcServer 490 & 690 */
- { 1, 0, "LSI Logic Corporation - L64811"},
- /* SparcStation2 */
- { 1, 1, "Cypress/ROSS CY7C601"},
- /* Embedded controller */
- { 1, 3, "Cypress/ROSS CY7C611"},
- /* Ross Technologies HyperSparc */
- { 1, 0xf, "ROSS HyperSparc RT620"},
- { 1, 0xe, "ROSS HyperSparc RT625 or RT626"},
- /* ECL Implementation, CRAY S-MP Supercomputer... AIEEE! */
- /* Someone please write the code to support this beast! ;) */
- { 2, 0, "Bipolar Integrated Technology - B5010"},
- { 3, 0, "LSI Logic Corporation - unknown-type"},
- { 4, 0, "Texas Instruments, Inc. - SuperSparc-(II)"},
- /* SparcClassic -- borned STP1010TAB-50*/
- { 4, 1, "Texas Instruments, Inc. - MicroSparc"},
- { 4, 2, "Texas Instruments, Inc. - MicroSparc II"},
- { 4, 3, "Texas Instruments, Inc. - SuperSparc 51"},
- { 4, 4, "Texas Instruments, Inc. - SuperSparc 61"},
- { 4, 5, "Texas Instruments, Inc. - unknown"},
- { 5, 0, "Matsushita - MN10501"},
- { 6, 0, "Philips Corporation - unknown"},
- { 7, 0, "Harvest VLSI Design Center, Inc. - unknown"},
- /* Gallium arsenide 200MHz, BOOOOGOOOOMIPS!!! */
- { 8, 0, "Systems and Processes Engineering Corporation (SPEC)"},
- { 9, 0, "Fujitsu or Weitek Power-UP"},
- { 9, 1, "Fujitsu or Weitek Power-UP"},
- { 9, 2, "Fujitsu or Weitek Power-UP"},
- { 9, 3, "Fujitsu or Weitek Power-UP"},
- { 0xa, 0, "UNKNOWN CPU-VENDOR/TYPE"},
- { 0xb, 0, "UNKNOWN CPU-VENDOR/TYPE"},
- { 0xc, 0, "UNKNOWN CPU-VENDOR/TYPE"},
- { 0xd, 0, "UNKNOWN CPU-VENDOR/TYPE"},
- { 0xe, 0, "UNKNOWN CPU-VENDOR/TYPE"},
- { 0xf, 0, "UNKNOWN CPU-VENDOR/TYPE"},
-};
+const char *sparc_cpu_type;
+const char *sparc_fpu_type;
-#define NSPARCCHIPS ARRAY_SIZE(linux_sparc_chips)
+unsigned int fsr_storage;
-char *sparc_cpu_type;
-char *sparc_fpu_type;
+static void set_cpu_and_fpu(int psr_impl, int psr_vers, int fpu_vers)
+{
+ sparc_cpu_type = NULL;
+ sparc_fpu_type = NULL;
+ if (psr_impl < ARRAY_SIZE(manufacturer_info))
+ {
+ const struct cpu_info *cpu;
+ const struct fpu_info *fpu;
-unsigned int fsr_storage;
+ cpu = &manufacturer_info[psr_impl].cpu_info[0];
+ while (cpu->psr_vers != -1)
+ {
+ if (cpu->psr_vers == psr_vers) {
+ sparc_cpu_type = cpu->name;
+ sparc_fpu_type = "No FPU";
+ break;
+ }
+ cpu++;
+ }
+ fpu = &manufacturer_info[psr_impl].fpu_info[0];
+ while (fpu->fp_vers != -1)
+ {
+ if (fpu->fp_vers == fpu_vers) {
+ sparc_fpu_type = fpu->name;
+ break;
+ }
+ fpu++;
+ }
+ }
+ if (sparc_cpu_type == NULL)
+ {
+ printk(KERN_ERR "CPU: Unknown chip, impl[0x%x] vers[0x%x]\n",
+ psr_impl, psr_vers);
+ sparc_cpu_type = "Unknown CPU";
+ }
+ if (sparc_fpu_type == NULL)
+ {
+ printk(KERN_ERR "FPU: Unknown chip, impl[0x%x] vers[0x%x]\n",
+ psr_impl, fpu_vers);
+ sparc_fpu_type = "Unknown FPU";
+ }
+}
+#ifdef CONFIG_SPARC32
void __cpuinit cpu_probe(void)
{
int psr_impl, psr_vers, fpu_vers;
- int i, psr;
+ int psr;
- psr_impl = ((get_psr()>>28)&0xf);
- psr_vers = ((get_psr()>>24)&0xf);
+ psr_impl = ((get_psr() >> 28) & 0xf);
+ psr_vers = ((get_psr() >> 24) & 0xf);
psr = get_psr();
put_psr(psr | PSR_EF);
- fpu_vers = ((get_fsr()>>17)&0x7);
+ fpu_vers = ((get_fsr() >> 17) & 0x7);
put_psr(psr);
- for(i = 0; i<NSPARCCHIPS; i++) {
- if(linux_sparc_chips[i].psr_impl == psr_impl)
- if(linux_sparc_chips[i].psr_vers == psr_vers) {
- sparc_cpu_type = linux_sparc_chips[i].cpu_name;
- break;
- }
- }
+ set_cpu_and_fpu(psr_impl, psr_vers, fpu_vers);
+}
+#else
+static void __init sun4v_cpu_probe(void)
+{
+ switch (sun4v_chip_type) {
+ case SUN4V_CHIP_NIAGARA1:
+ sparc_cpu_type = "UltraSparc T1 (Niagara)";
+ sparc_fpu_type = "UltraSparc T1 integrated FPU";
+ break;
- if(i==NSPARCCHIPS)
- printk("DEBUG: psr.impl = 0x%x psr.vers = 0x%x\n", psr_impl,
- psr_vers);
+ case SUN4V_CHIP_NIAGARA2:
+ sparc_cpu_type = "UltraSparc T2 (Niagara2)";
+ sparc_fpu_type = "UltraSparc T2 integrated FPU";
+ break;
- for(i = 0; i<NSPARCFPU; i++) {
- if(linux_sparc_fpu[i].psr_impl == psr_impl)
- if(linux_sparc_fpu[i].fp_vers == fpu_vers) {
- sparc_fpu_type = linux_sparc_fpu[i].fp_name;
- break;
- }
+ default:
+ printk(KERN_WARNING "CPU: Unknown sun4v cpu type [%s]\n",
+ prom_cpu_compatible);
+ sparc_cpu_type = "Unknown SUN4V CPU";
+ sparc_fpu_type = "Unknown SUN4V FPU";
+ break;
}
+}
+
+static int __init cpu_type_probe(void)
+{
+ if (tlb_type == hypervisor) {
+ sun4v_cpu_probe();
+ } else {
+ unsigned long ver;
+ int manuf, impl;
- if(i == NSPARCFPU) {
- printk("DEBUG: psr.impl = 0x%x fsr.vers = 0x%x\n", psr_impl,
- fpu_vers);
- sparc_fpu_type = linux_sparc_fpu[31].fp_name;
+ __asm__ __volatile__("rdpr %%ver, %0" : "=r" (ver));
+
+ manuf = ((ver >> 48) & 0xffff);
+ impl = ((ver >> 32) & 0xffff);
+ set_cpu_and_fpu(manuf, impl, impl);
}
+ return 0;
}
+
+arch_initcall(cpu_type_probe);
+#endif
diff --git a/arch/sparc/kernel/devices.c b/arch/sparc/kernel/devices.c
index ad656b044b8c..b171ae8de90d 100644
--- a/arch/sparc/kernel/devices.c
+++ b/arch/sparc/kernel/devices.c
@@ -133,14 +133,12 @@ void __init device_scan(void)
#endif /* !CONFIG_SMP */
cpu_probe();
-#ifdef CONFIG_SUN_AUXIO
{
extern void auxio_probe(void);
extern void auxio_power_probe(void);
auxio_probe();
auxio_power_probe();
}
-#endif
clock_stop_probe();
if (ARCH_SUN4C)
diff --git a/arch/sparc/kernel/ds.c b/arch/sparc/kernel/ds.c
new file mode 100644
index 000000000000..f52e0534d91d
--- /dev/null
+++ b/arch/sparc/kernel/ds.c
@@ -0,0 +1,1244 @@
+/* ds.c: Domain Services driver for Logical Domains
+ *
+ * Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/kthread.h>
+#include <linux/reboot.h>
+#include <linux/cpu.h>
+
+#include <asm/ldc.h>
+#include <asm/vio.h>
+#include <asm/mdesc.h>
+#include <asm/head.h>
+#include <asm/irq.h>
+
+#define DRV_MODULE_NAME "ds"
+#define PFX DRV_MODULE_NAME ": "
+#define DRV_MODULE_VERSION "1.0"
+#define DRV_MODULE_RELDATE "Jul 11, 2007"
+
+static char version[] __devinitdata =
+ DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
+MODULE_AUTHOR("David S. Miller (davem@davemloft.net)");
+MODULE_DESCRIPTION("Sun LDOM domain services driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_MODULE_VERSION);
+
+struct ds_msg_tag {
+ __u32 type;
+#define DS_INIT_REQ 0x00
+#define DS_INIT_ACK 0x01
+#define DS_INIT_NACK 0x02
+#define DS_REG_REQ 0x03
+#define DS_REG_ACK 0x04
+#define DS_REG_NACK 0x05
+#define DS_UNREG_REQ 0x06
+#define DS_UNREG_ACK 0x07
+#define DS_UNREG_NACK 0x08
+#define DS_DATA 0x09
+#define DS_NACK 0x0a
+
+ __u32 len;
+};
+
+/* Result codes */
+#define DS_OK 0x00
+#define DS_REG_VER_NACK 0x01
+#define DS_REG_DUP 0x02
+#define DS_INV_HDL 0x03
+#define DS_TYPE_UNKNOWN 0x04
+
+struct ds_version {
+ __u16 major;
+ __u16 minor;
+};
+
+struct ds_ver_req {
+ struct ds_msg_tag tag;
+ struct ds_version ver;
+};
+
+struct ds_ver_ack {
+ struct ds_msg_tag tag;
+ __u16 minor;
+};
+
+struct ds_ver_nack {
+ struct ds_msg_tag tag;
+ __u16 major;
+};
+
+struct ds_reg_req {
+ struct ds_msg_tag tag;
+ __u64 handle;
+ __u16 major;
+ __u16 minor;
+ char svc_id[0];
+};
+
+struct ds_reg_ack {
+ struct ds_msg_tag tag;
+ __u64 handle;
+ __u16 minor;
+};
+
+struct ds_reg_nack {
+ struct ds_msg_tag tag;
+ __u64 handle;
+ __u16 major;
+};
+
+struct ds_unreg_req {
+ struct ds_msg_tag tag;
+ __u64 handle;
+};
+
+struct ds_unreg_ack {
+ struct ds_msg_tag tag;
+ __u64 handle;
+};
+
+struct ds_unreg_nack {
+ struct ds_msg_tag tag;
+ __u64 handle;
+};
+
+struct ds_data {
+ struct ds_msg_tag tag;
+ __u64 handle;
+};
+
+struct ds_data_nack {
+ struct ds_msg_tag tag;
+ __u64 handle;
+ __u64 result;
+};
+
+struct ds_info;
+struct ds_cap_state {
+ __u64 handle;
+
+ void (*data)(struct ds_info *dp,
+ struct ds_cap_state *cp,
+ void *buf, int len);
+
+ const char *service_id;
+
+ u8 state;
+#define CAP_STATE_UNKNOWN 0x00
+#define CAP_STATE_REG_SENT 0x01
+#define CAP_STATE_REGISTERED 0x02
+};
+
+static void md_update_data(struct ds_info *dp, struct ds_cap_state *cp,
+ void *buf, int len);
+static void domain_shutdown_data(struct ds_info *dp,
+ struct ds_cap_state *cp,
+ void *buf, int len);
+static void domain_panic_data(struct ds_info *dp,
+ struct ds_cap_state *cp,
+ void *buf, int len);
+#ifdef CONFIG_HOTPLUG_CPU
+static void dr_cpu_data(struct ds_info *dp,
+ struct ds_cap_state *cp,
+ void *buf, int len);
+#endif
+static void ds_pri_data(struct ds_info *dp,
+ struct ds_cap_state *cp,
+ void *buf, int len);
+static void ds_var_data(struct ds_info *dp,
+ struct ds_cap_state *cp,
+ void *buf, int len);
+
+static struct ds_cap_state ds_states_template[] = {
+ {
+ .service_id = "md-update",
+ .data = md_update_data,
+ },
+ {
+ .service_id = "domain-shutdown",
+ .data = domain_shutdown_data,
+ },
+ {
+ .service_id = "domain-panic",
+ .data = domain_panic_data,
+ },
+#ifdef CONFIG_HOTPLUG_CPU
+ {
+ .service_id = "dr-cpu",
+ .data = dr_cpu_data,
+ },
+#endif
+ {
+ .service_id = "pri",
+ .data = ds_pri_data,
+ },
+ {
+ .service_id = "var-config",
+ .data = ds_var_data,
+ },
+ {
+ .service_id = "var-config-backup",
+ .data = ds_var_data,
+ },
+};
+
+static DEFINE_SPINLOCK(ds_lock);
+
+struct ds_info {
+ struct ldc_channel *lp;
+ u8 hs_state;
+#define DS_HS_START 0x01
+#define DS_HS_DONE 0x02
+
+ u64 id;
+
+ void *rcv_buf;
+ int rcv_buf_len;
+
+ struct ds_cap_state *ds_states;
+ int num_ds_states;
+
+ struct ds_info *next;
+};
+
+static struct ds_info *ds_info_list;
+
+static struct ds_cap_state *find_cap(struct ds_info *dp, u64 handle)
+{
+ unsigned int index = handle >> 32;
+
+ if (index >= dp->num_ds_states)
+ return NULL;
+ return &dp->ds_states[index];
+}
+
+static struct ds_cap_state *find_cap_by_string(struct ds_info *dp,
+ const char *name)
+{
+ int i;
+
+ for (i = 0; i < dp->num_ds_states; i++) {
+ if (strcmp(dp->ds_states[i].service_id, name))
+ continue;
+
+ return &dp->ds_states[i];
+ }
+ return NULL;
+}
+
+static int __ds_send(struct ldc_channel *lp, void *data, int len)
+{
+ int err, limit = 1000;
+
+ err = -EINVAL;
+ while (limit-- > 0) {
+ err = ldc_write(lp, data, len);
+ if (!err || (err != -EAGAIN))
+ break;
+ udelay(1);
+ }
+
+ return err;
+}
+
+static int ds_send(struct ldc_channel *lp, void *data, int len)
+{
+ unsigned long flags;
+ int err;
+
+ spin_lock_irqsave(&ds_lock, flags);
+ err = __ds_send(lp, data, len);
+ spin_unlock_irqrestore(&ds_lock, flags);
+
+ return err;
+}
+
+struct ds_md_update_req {
+ __u64 req_num;
+};
+
+struct ds_md_update_res {
+ __u64 req_num;
+ __u32 result;
+};
+
+static void md_update_data(struct ds_info *dp,
+ struct ds_cap_state *cp,
+ void *buf, int len)
+{
+ struct ldc_channel *lp = dp->lp;
+ struct ds_data *dpkt = buf;
+ struct ds_md_update_req *rp;
+ struct {
+ struct ds_data data;
+ struct ds_md_update_res res;
+ } pkt;
+
+ rp = (struct ds_md_update_req *) (dpkt + 1);
+
+ printk(KERN_INFO "ds-%lu: Machine description update.\n", dp->id);
+
+ mdesc_update();
+
+ memset(&pkt, 0, sizeof(pkt));
+ pkt.data.tag.type = DS_DATA;
+ pkt.data.tag.len = sizeof(pkt) - sizeof(struct ds_msg_tag);
+ pkt.data.handle = cp->handle;
+ pkt.res.req_num = rp->req_num;
+ pkt.res.result = DS_OK;
+
+ ds_send(lp, &pkt, sizeof(pkt));
+}
+
+struct ds_shutdown_req {
+ __u64 req_num;
+ __u32 ms_delay;
+};
+
+struct ds_shutdown_res {
+ __u64 req_num;
+ __u32 result;
+ char reason[1];
+};
+
+static void domain_shutdown_data(struct ds_info *dp,
+ struct ds_cap_state *cp,
+ void *buf, int len)
+{
+ struct ldc_channel *lp = dp->lp;
+ struct ds_data *dpkt = buf;
+ struct ds_shutdown_req *rp;
+ struct {
+ struct ds_data data;
+ struct ds_shutdown_res res;
+ } pkt;
+
+ rp = (struct ds_shutdown_req *) (dpkt + 1);
+
+ printk(KERN_ALERT "ds-%lu: Shutdown request from "
+ "LDOM manager received.\n", dp->id);
+
+ memset(&pkt, 0, sizeof(pkt));
+ pkt.data.tag.type = DS_DATA;
+ pkt.data.tag.len = sizeof(pkt) - sizeof(struct ds_msg_tag);
+ pkt.data.handle = cp->handle;
+ pkt.res.req_num = rp->req_num;
+ pkt.res.result = DS_OK;
+ pkt.res.reason[0] = 0;
+
+ ds_send(lp, &pkt, sizeof(pkt));
+
+ orderly_poweroff(true);
+}
+
+struct ds_panic_req {
+ __u64 req_num;
+};
+
+struct ds_panic_res {
+ __u64 req_num;
+ __u32 result;
+ char reason[1];
+};
+
+static void domain_panic_data(struct ds_info *dp,
+ struct ds_cap_state *cp,
+ void *buf, int len)
+{
+ struct ldc_channel *lp = dp->lp;
+ struct ds_data *dpkt = buf;
+ struct ds_panic_req *rp;
+ struct {
+ struct ds_data data;
+ struct ds_panic_res res;
+ } pkt;
+
+ rp = (struct ds_panic_req *) (dpkt + 1);
+
+ printk(KERN_ALERT "ds-%lu: Panic request from "
+ "LDOM manager received.\n", dp->id);
+
+ memset(&pkt, 0, sizeof(pkt));
+ pkt.data.tag.type = DS_DATA;
+ pkt.data.tag.len = sizeof(pkt) - sizeof(struct ds_msg_tag);
+ pkt.data.handle = cp->handle;
+ pkt.res.req_num = rp->req_num;
+ pkt.res.result = DS_OK;
+ pkt.res.reason[0] = 0;
+
+ ds_send(lp, &pkt, sizeof(pkt));
+
+ panic("PANIC requested by LDOM manager.");
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+struct dr_cpu_tag {
+ __u64 req_num;
+ __u32 type;
+#define DR_CPU_CONFIGURE 0x43
+#define DR_CPU_UNCONFIGURE 0x55
+#define DR_CPU_FORCE_UNCONFIGURE 0x46
+#define DR_CPU_STATUS 0x53
+
+/* Responses */
+#define DR_CPU_OK 0x6f
+#define DR_CPU_ERROR 0x65
+
+ __u32 num_records;
+};
+
+struct dr_cpu_resp_entry {
+ __u32 cpu;
+ __u32 result;
+#define DR_CPU_RES_OK 0x00
+#define DR_CPU_RES_FAILURE 0x01
+#define DR_CPU_RES_BLOCKED 0x02
+#define DR_CPU_RES_CPU_NOT_RESPONDING 0x03
+#define DR_CPU_RES_NOT_IN_MD 0x04
+
+ __u32 stat;
+#define DR_CPU_STAT_NOT_PRESENT 0x00
+#define DR_CPU_STAT_UNCONFIGURED 0x01
+#define DR_CPU_STAT_CONFIGURED 0x02
+
+ __u32 str_off;
+};
+
+static void __dr_cpu_send_error(struct ds_info *dp,
+ struct ds_cap_state *cp,
+ struct ds_data *data)
+{
+ struct dr_cpu_tag *tag = (struct dr_cpu_tag *) (data + 1);
+ struct {
+ struct ds_data data;
+ struct dr_cpu_tag tag;
+ } pkt;
+ int msg_len;
+
+ memset(&pkt, 0, sizeof(pkt));
+ pkt.data.tag.type = DS_DATA;
+ pkt.data.handle = cp->handle;
+ pkt.tag.req_num = tag->req_num;
+ pkt.tag.type = DR_CPU_ERROR;
+ pkt.tag.num_records = 0;
+
+ msg_len = (sizeof(struct ds_data) +
+ sizeof(struct dr_cpu_tag));
+
+ pkt.data.tag.len = msg_len - sizeof(struct ds_msg_tag);
+
+ __ds_send(dp->lp, &pkt, msg_len);
+}
+
+static void dr_cpu_send_error(struct ds_info *dp,
+ struct ds_cap_state *cp,
+ struct ds_data *data)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ds_lock, flags);
+ __dr_cpu_send_error(dp, cp, data);
+ spin_unlock_irqrestore(&ds_lock, flags);
+}
+
+#define CPU_SENTINEL 0xffffffff
+
+static void purge_dups(u32 *list, u32 num_ents)
+{
+ unsigned int i;
+
+ for (i = 0; i < num_ents; i++) {
+ u32 cpu = list[i];
+ unsigned int j;
+
+ if (cpu == CPU_SENTINEL)
+ continue;
+
+ for (j = i + 1; j < num_ents; j++) {
+ if (list[j] == cpu)
+ list[j] = CPU_SENTINEL;
+ }
+ }
+}
+
+static int dr_cpu_size_response(int ncpus)
+{
+ return (sizeof(struct ds_data) +
+ sizeof(struct dr_cpu_tag) +
+ (sizeof(struct dr_cpu_resp_entry) * ncpus));
+}
+
+static void dr_cpu_init_response(struct ds_data *resp, u64 req_num,
+ u64 handle, int resp_len, int ncpus,
+ cpumask_t *mask, u32 default_stat)
+{
+ struct dr_cpu_resp_entry *ent;
+ struct dr_cpu_tag *tag;
+ int i, cpu;
+
+ tag = (struct dr_cpu_tag *) (resp + 1);
+ ent = (struct dr_cpu_resp_entry *) (tag + 1);
+
+ resp->tag.type = DS_DATA;
+ resp->tag.len = resp_len - sizeof(struct ds_msg_tag);
+ resp->handle = handle;
+ tag->req_num = req_num;
+ tag->type = DR_CPU_OK;
+ tag->num_records = ncpus;
+
+ i = 0;
+ for_each_cpu_mask(cpu, *mask) {
+ ent[i].cpu = cpu;
+ ent[i].result = DR_CPU_RES_OK;
+ ent[i].stat = default_stat;
+ i++;
+ }
+ BUG_ON(i != ncpus);
+}
+
+static void dr_cpu_mark(struct ds_data *resp, int cpu, int ncpus,
+ u32 res, u32 stat)
+{
+ struct dr_cpu_resp_entry *ent;
+ struct dr_cpu_tag *tag;
+ int i;
+
+ tag = (struct dr_cpu_tag *) (resp + 1);
+ ent = (struct dr_cpu_resp_entry *) (tag + 1);
+
+ for (i = 0; i < ncpus; i++) {
+ if (ent[i].cpu != cpu)
+ continue;
+ ent[i].result = res;
+ ent[i].stat = stat;
+ break;
+ }
+}
+
+static int __cpuinit dr_cpu_configure(struct ds_info *dp,
+ struct ds_cap_state *cp,
+ u64 req_num,
+ cpumask_t *mask)
+{
+ struct ds_data *resp;
+ int resp_len, ncpus, cpu;
+ unsigned long flags;
+
+ ncpus = cpus_weight(*mask);
+ resp_len = dr_cpu_size_response(ncpus);
+ resp = kzalloc(resp_len, GFP_KERNEL);
+ if (!resp)
+ return -ENOMEM;
+
+ dr_cpu_init_response(resp, req_num, cp->handle,
+ resp_len, ncpus, mask,
+ DR_CPU_STAT_CONFIGURED);
+
+ mdesc_fill_in_cpu_data(*mask);
+
+ for_each_cpu_mask(cpu, *mask) {
+ int err;
+
+ printk(KERN_INFO "ds-%lu: Starting cpu %d...\n",
+ dp->id, cpu);
+ err = cpu_up(cpu);
+ if (err) {
+ __u32 res = DR_CPU_RES_FAILURE;
+ __u32 stat = DR_CPU_STAT_UNCONFIGURED;
+
+ if (!cpu_present(cpu)) {
+ /* CPU not present in MD */
+ res = DR_CPU_RES_NOT_IN_MD;
+ stat = DR_CPU_STAT_NOT_PRESENT;
+ } else if (err == -ENODEV) {
+ /* CPU did not call in successfully */
+ res = DR_CPU_RES_CPU_NOT_RESPONDING;
+ }
+
+ printk(KERN_INFO "ds-%lu: CPU startup failed err=%d\n",
+ dp->id, err);
+ dr_cpu_mark(resp, cpu, ncpus, res, stat);
+ }
+ }
+
+ spin_lock_irqsave(&ds_lock, flags);
+ __ds_send(dp->lp, resp, resp_len);
+ spin_unlock_irqrestore(&ds_lock, flags);
+
+ kfree(resp);
+
+ /* Redistribute IRQs, taking into account the new cpus. */
+ fixup_irqs();
+
+ return 0;
+}
+
+static int dr_cpu_unconfigure(struct ds_info *dp,
+ struct ds_cap_state *cp,
+ u64 req_num,
+ cpumask_t *mask)
+{
+ struct ds_data *resp;
+ int resp_len, ncpus, cpu;
+ unsigned long flags;
+
+ ncpus = cpus_weight(*mask);
+ resp_len = dr_cpu_size_response(ncpus);
+ resp = kzalloc(resp_len, GFP_KERNEL);
+ if (!resp)
+ return -ENOMEM;
+
+ dr_cpu_init_response(resp, req_num, cp->handle,
+ resp_len, ncpus, mask,
+ DR_CPU_STAT_UNCONFIGURED);
+
+ for_each_cpu_mask(cpu, *mask) {
+ int err;
+
+ printk(KERN_INFO "ds-%lu: Shutting down cpu %d...\n",
+ dp->id, cpu);
+ err = cpu_down(cpu);
+ if (err)
+ dr_cpu_mark(resp, cpu, ncpus,
+ DR_CPU_RES_FAILURE,
+ DR_CPU_STAT_CONFIGURED);
+ }
+
+ spin_lock_irqsave(&ds_lock, flags);
+ __ds_send(dp->lp, resp, resp_len);
+ spin_unlock_irqrestore(&ds_lock, flags);
+
+ kfree(resp);
+
+ return 0;
+}
+
+static void __cpuinit dr_cpu_data(struct ds_info *dp,
+ struct ds_cap_state *cp,
+ void *buf, int len)
+{
+ struct ds_data *data = buf;
+ struct dr_cpu_tag *tag = (struct dr_cpu_tag *) (data + 1);
+ u32 *cpu_list = (u32 *) (tag + 1);
+ u64 req_num = tag->req_num;
+ cpumask_t mask;
+ unsigned int i;
+ int err;
+
+ switch (tag->type) {
+ case DR_CPU_CONFIGURE:
+ case DR_CPU_UNCONFIGURE:
+ case DR_CPU_FORCE_UNCONFIGURE:
+ break;
+
+ default:
+ dr_cpu_send_error(dp, cp, data);
+ return;
+ }
+
+ purge_dups(cpu_list, tag->num_records);
+
+ cpus_clear(mask);
+ for (i = 0; i < tag->num_records; i++) {
+ if (cpu_list[i] == CPU_SENTINEL)
+ continue;
+
+ if (cpu_list[i] < NR_CPUS)
+ cpu_set(cpu_list[i], mask);
+ }
+
+ if (tag->type == DR_CPU_CONFIGURE)
+ err = dr_cpu_configure(dp, cp, req_num, &mask);
+ else
+ err = dr_cpu_unconfigure(dp, cp, req_num, &mask);
+
+ if (err)
+ dr_cpu_send_error(dp, cp, data);
+}
+#endif /* CONFIG_HOTPLUG_CPU */
+
+struct ds_pri_msg {
+ __u64 req_num;
+ __u64 type;
+#define DS_PRI_REQUEST 0x00
+#define DS_PRI_DATA 0x01
+#define DS_PRI_UPDATE 0x02
+};
+
+static void ds_pri_data(struct ds_info *dp,
+ struct ds_cap_state *cp,
+ void *buf, int len)
+{
+ struct ds_data *dpkt = buf;
+ struct ds_pri_msg *rp;
+
+ rp = (struct ds_pri_msg *) (dpkt + 1);
+
+ printk(KERN_INFO "ds-%lu: PRI REQ [%lx:%lx], len=%d\n",
+ dp->id, rp->req_num, rp->type, len);
+}
+
+struct ds_var_hdr {
+ __u32 type;
+#define DS_VAR_SET_REQ 0x00
+#define DS_VAR_DELETE_REQ 0x01
+#define DS_VAR_SET_RESP 0x02
+#define DS_VAR_DELETE_RESP 0x03
+};
+
+struct ds_var_set_msg {
+ struct ds_var_hdr hdr;
+ char name_and_value[0];
+};
+
+struct ds_var_delete_msg {
+ struct ds_var_hdr hdr;
+ char name[0];
+};
+
+struct ds_var_resp {
+ struct ds_var_hdr hdr;
+ __u32 result;
+#define DS_VAR_SUCCESS 0x00
+#define DS_VAR_NO_SPACE 0x01
+#define DS_VAR_INVALID_VAR 0x02
+#define DS_VAR_INVALID_VAL 0x03
+#define DS_VAR_NOT_PRESENT 0x04
+};
+
+static DEFINE_MUTEX(ds_var_mutex);
+static int ds_var_doorbell;
+static int ds_var_response;
+
+static void ds_var_data(struct ds_info *dp,
+ struct ds_cap_state *cp,
+ void *buf, int len)
+{
+ struct ds_data *dpkt = buf;
+ struct ds_var_resp *rp;
+
+ rp = (struct ds_var_resp *) (dpkt + 1);
+
+ if (rp->hdr.type != DS_VAR_SET_RESP &&
+ rp->hdr.type != DS_VAR_DELETE_RESP)
+ return;
+
+ ds_var_response = rp->result;
+ wmb();
+ ds_var_doorbell = 1;
+}
+
+void ldom_set_var(const char *var, const char *value)
+{
+ struct ds_cap_state *cp;
+ struct ds_info *dp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ds_lock, flags);
+ cp = NULL;
+ for (dp = ds_info_list; dp; dp = dp->next) {
+ struct ds_cap_state *tmp;
+
+ tmp = find_cap_by_string(dp, "var-config");
+ if (tmp && tmp->state == CAP_STATE_REGISTERED) {
+ cp = tmp;
+ break;
+ }
+ }
+ if (!cp) {
+ for (dp = ds_info_list; dp; dp = dp->next) {
+ struct ds_cap_state *tmp;
+
+ tmp = find_cap_by_string(dp, "var-config-backup");
+ if (tmp && tmp->state == CAP_STATE_REGISTERED) {
+ cp = tmp;
+ break;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&ds_lock, flags);
+
+ if (cp) {
+ union {
+ struct {
+ struct ds_data data;
+ struct ds_var_set_msg msg;
+ } header;
+ char all[512];
+ } pkt;
+ char *base, *p;
+ int msg_len, loops;
+
+ memset(&pkt, 0, sizeof(pkt));
+ pkt.header.data.tag.type = DS_DATA;
+ pkt.header.data.handle = cp->handle;
+ pkt.header.msg.hdr.type = DS_VAR_SET_REQ;
+ base = p = &pkt.header.msg.name_and_value[0];
+ strcpy(p, var);
+ p += strlen(var) + 1;
+ strcpy(p, value);
+ p += strlen(value) + 1;
+
+ msg_len = (sizeof(struct ds_data) +
+ sizeof(struct ds_var_set_msg) +
+ (p - base));
+ msg_len = (msg_len + 3) & ~3;
+ pkt.header.data.tag.len = msg_len - sizeof(struct ds_msg_tag);
+
+ mutex_lock(&ds_var_mutex);
+
+ spin_lock_irqsave(&ds_lock, flags);
+ ds_var_doorbell = 0;
+ ds_var_response = -1;
+
+ __ds_send(dp->lp, &pkt, msg_len);
+ spin_unlock_irqrestore(&ds_lock, flags);
+
+ loops = 1000;
+ while (ds_var_doorbell == 0) {
+ if (loops-- < 0)
+ break;
+ barrier();
+ udelay(100);
+ }
+
+ mutex_unlock(&ds_var_mutex);
+
+ if (ds_var_doorbell == 0 ||
+ ds_var_response != DS_VAR_SUCCESS)
+ printk(KERN_ERR "ds-%lu: var-config [%s:%s] "
+ "failed, response(%d).\n",
+ dp->id, var, value,
+ ds_var_response);
+ } else {
+ printk(KERN_ERR PFX "var-config not registered so "
+ "could not set (%s) variable to (%s).\n",
+ var, value);
+ }
+}
+
+void ldom_reboot(const char *boot_command)
+{
+ /* Don't bother with any of this if the boot_command
+ * is empty.
+ */
+ if (boot_command && strlen(boot_command)) {
+ char full_boot_str[256];
+
+ strcpy(full_boot_str, "boot ");
+ strcpy(full_boot_str + strlen("boot "), boot_command);
+
+ ldom_set_var("reboot-command", full_boot_str);
+ }
+ sun4v_mach_sir();
+}
+
+void ldom_power_off(void)
+{
+ sun4v_mach_exit(0);
+}
+
+static void ds_conn_reset(struct ds_info *dp)
+{
+ printk(KERN_ERR "ds-%lu: ds_conn_reset() from %p\n",
+ dp->id, __builtin_return_address(0));
+}
+
+static int register_services(struct ds_info *dp)
+{
+ struct ldc_channel *lp = dp->lp;
+ int i;
+
+ for (i = 0; i < dp->num_ds_states; i++) {
+ struct {
+ struct ds_reg_req req;
+ u8 id_buf[256];
+ } pbuf;
+ struct ds_cap_state *cp = &dp->ds_states[i];
+ int err, msg_len;
+ u64 new_count;
+
+ if (cp->state == CAP_STATE_REGISTERED)
+ continue;
+
+ new_count = sched_clock() & 0xffffffff;
+ cp->handle = ((u64) i << 32) | new_count;
+
+ msg_len = (sizeof(struct ds_reg_req) +
+ strlen(cp->service_id));
+
+ memset(&pbuf, 0, sizeof(pbuf));
+ pbuf.req.tag.type = DS_REG_REQ;
+ pbuf.req.tag.len = (msg_len - sizeof(struct ds_msg_tag));
+ pbuf.req.handle = cp->handle;
+ pbuf.req.major = 1;
+ pbuf.req.minor = 0;
+ strcpy(pbuf.req.svc_id, cp->service_id);
+
+ err = __ds_send(lp, &pbuf, msg_len);
+ if (err > 0)
+ cp->state = CAP_STATE_REG_SENT;
+ }
+ return 0;
+}
+
+static int ds_handshake(struct ds_info *dp, struct ds_msg_tag *pkt)
+{
+
+ if (dp->hs_state == DS_HS_START) {
+ if (pkt->type != DS_INIT_ACK)
+ goto conn_reset;
+
+ dp->hs_state = DS_HS_DONE;
+
+ return register_services(dp);
+ }
+
+ if (dp->hs_state != DS_HS_DONE)
+ goto conn_reset;
+
+ if (pkt->type == DS_REG_ACK) {
+ struct ds_reg_ack *ap = (struct ds_reg_ack *) pkt;
+ struct ds_cap_state *cp = find_cap(dp, ap->handle);
+
+ if (!cp) {
+ printk(KERN_ERR "ds-%lu: REG ACK for unknown "
+ "handle %lx\n", dp->id, ap->handle);
+ return 0;
+ }
+ printk(KERN_INFO "ds-%lu: Registered %s service.\n",
+ dp->id, cp->service_id);
+ cp->state = CAP_STATE_REGISTERED;
+ } else if (pkt->type == DS_REG_NACK) {
+ struct ds_reg_nack *np = (struct ds_reg_nack *) pkt;
+ struct ds_cap_state *cp = find_cap(dp, np->handle);
+
+ if (!cp) {
+ printk(KERN_ERR "ds-%lu: REG NACK for "
+ "unknown handle %lx\n",
+ dp->id, np->handle);
+ return 0;
+ }
+ cp->state = CAP_STATE_UNKNOWN;
+ }
+
+ return 0;
+
+conn_reset:
+ ds_conn_reset(dp);
+ return -ECONNRESET;
+}
+
+static void __send_ds_nack(struct ds_info *dp, u64 handle)
+{
+ struct ds_data_nack nack = {
+ .tag = {
+ .type = DS_NACK,
+ .len = (sizeof(struct ds_data_nack) -
+ sizeof(struct ds_msg_tag)),
+ },
+ .handle = handle,
+ .result = DS_INV_HDL,
+ };
+
+ __ds_send(dp->lp, &nack, sizeof(nack));
+}
+
+static LIST_HEAD(ds_work_list);
+static DECLARE_WAIT_QUEUE_HEAD(ds_wait);
+
+struct ds_queue_entry {
+ struct list_head list;
+ struct ds_info *dp;
+ int req_len;
+ int __pad;
+ u64 req[0];
+};
+
+static void process_ds_work(void)
+{
+ struct ds_queue_entry *qp, *tmp;
+ unsigned long flags;
+ LIST_HEAD(todo);
+
+ spin_lock_irqsave(&ds_lock, flags);
+ list_splice_init(&ds_work_list, &todo);
+ spin_unlock_irqrestore(&ds_lock, flags);
+
+ list_for_each_entry_safe(qp, tmp, &todo, list) {
+ struct ds_data *dpkt = (struct ds_data *) qp->req;
+ struct ds_info *dp = qp->dp;
+ struct ds_cap_state *cp = find_cap(dp, dpkt->handle);
+ int req_len = qp->req_len;
+
+ if (!cp) {
+ printk(KERN_ERR "ds-%lu: Data for unknown "
+ "handle %lu\n",
+ dp->id, dpkt->handle);
+
+ spin_lock_irqsave(&ds_lock, flags);
+ __send_ds_nack(dp, dpkt->handle);
+ spin_unlock_irqrestore(&ds_lock, flags);
+ } else {
+ cp->data(dp, cp, dpkt, req_len);
+ }
+
+ list_del(&qp->list);
+ kfree(qp);
+ }
+}
+
+static int ds_thread(void *__unused)
+{
+ DEFINE_WAIT(wait);
+
+ while (1) {
+ prepare_to_wait(&ds_wait, &wait, TASK_INTERRUPTIBLE);
+ if (list_empty(&ds_work_list))
+ schedule();
+ finish_wait(&ds_wait, &wait);
+
+ if (kthread_should_stop())
+ break;
+
+ process_ds_work();
+ }
+
+ return 0;
+}
+
+static int ds_data(struct ds_info *dp, struct ds_msg_tag *pkt, int len)
+{
+ struct ds_data *dpkt = (struct ds_data *) pkt;
+ struct ds_queue_entry *qp;
+
+ qp = kmalloc(sizeof(struct ds_queue_entry) + len, GFP_ATOMIC);
+ if (!qp) {
+ __send_ds_nack(dp, dpkt->handle);
+ } else {
+ qp->dp = dp;
+ memcpy(&qp->req, pkt, len);
+ list_add_tail(&qp->list, &ds_work_list);
+ wake_up(&ds_wait);
+ }
+ return 0;
+}
+
+static void ds_up(struct ds_info *dp)
+{
+ struct ldc_channel *lp = dp->lp;
+ struct ds_ver_req req;
+ int err;
+
+ req.tag.type = DS_INIT_REQ;
+ req.tag.len = sizeof(req) - sizeof(struct ds_msg_tag);
+ req.ver.major = 1;
+ req.ver.minor = 0;
+
+ err = __ds_send(lp, &req, sizeof(req));
+ if (err > 0)
+ dp->hs_state = DS_HS_START;
+}
+
+static void ds_reset(struct ds_info *dp)
+{
+ int i;
+
+ dp->hs_state = 0;
+
+ for (i = 0; i < dp->num_ds_states; i++) {
+ struct ds_cap_state *cp = &dp->ds_states[i];
+
+ cp->state = CAP_STATE_UNKNOWN;
+ }
+}
+
+static void ds_event(void *arg, int event)
+{
+ struct ds_info *dp = arg;
+ struct ldc_channel *lp = dp->lp;
+ unsigned long flags;
+ int err;
+
+ spin_lock_irqsave(&ds_lock, flags);
+
+ if (event == LDC_EVENT_UP) {
+ ds_up(dp);
+ spin_unlock_irqrestore(&ds_lock, flags);
+ return;
+ }
+
+ if (event == LDC_EVENT_RESET) {
+ ds_reset(dp);
+ spin_unlock_irqrestore(&ds_lock, flags);
+ return;
+ }
+
+ if (event != LDC_EVENT_DATA_READY) {
+ printk(KERN_WARNING "ds-%lu: Unexpected LDC event %d\n",
+ dp->id, event);
+ spin_unlock_irqrestore(&ds_lock, flags);
+ return;
+ }
+
+ err = 0;
+ while (1) {
+ struct ds_msg_tag *tag;
+
+ err = ldc_read(lp, dp->rcv_buf, sizeof(*tag));
+
+ if (unlikely(err < 0)) {
+ if (err == -ECONNRESET)
+ ds_conn_reset(dp);
+ break;
+ }
+ if (err == 0)
+ break;
+
+ tag = dp->rcv_buf;
+ err = ldc_read(lp, tag + 1, tag->len);
+
+ if (unlikely(err < 0)) {
+ if (err == -ECONNRESET)
+ ds_conn_reset(dp);
+ break;
+ }
+ if (err < tag->len)
+ break;
+
+ if (tag->type < DS_DATA)
+ err = ds_handshake(dp, dp->rcv_buf);
+ else
+ err = ds_data(dp, dp->rcv_buf,
+ sizeof(*tag) + err);
+ if (err == -ECONNRESET)
+ break;
+ }
+
+ spin_unlock_irqrestore(&ds_lock, flags);
+}
+
+static int __devinit ds_probe(struct vio_dev *vdev,
+ const struct vio_device_id *id)
+{
+ static int ds_version_printed;
+ struct ldc_channel_config ds_cfg = {
+ .event = ds_event,
+ .mtu = 4096,
+ .mode = LDC_MODE_STREAM,
+ };
+ struct mdesc_handle *hp;
+ struct ldc_channel *lp;
+ struct ds_info *dp;
+ const u64 *val;
+ int err, i;
+
+ if (ds_version_printed++ == 0)
+ printk(KERN_INFO "%s", version);
+
+ dp = kzalloc(sizeof(*dp), GFP_KERNEL);
+ err = -ENOMEM;
+ if (!dp)
+ goto out_err;
+
+ hp = mdesc_grab();
+ val = mdesc_get_property(hp, vdev->mp, "id", NULL);
+ if (val)
+ dp->id = *val;
+ mdesc_release(hp);
+
+ dp->rcv_buf = kzalloc(4096, GFP_KERNEL);
+ if (!dp->rcv_buf)
+ goto out_free_dp;
+
+ dp->rcv_buf_len = 4096;
+
+ dp->ds_states = kzalloc(sizeof(ds_states_template),
+ GFP_KERNEL);
+ if (!dp->ds_states)
+ goto out_free_rcv_buf;
+
+ memcpy(dp->ds_states, ds_states_template,
+ sizeof(ds_states_template));
+ dp->num_ds_states = ARRAY_SIZE(ds_states_template);
+
+ for (i = 0; i < dp->num_ds_states; i++)
+ dp->ds_states[i].handle = ((u64)i << 32);
+
+ ds_cfg.tx_irq = vdev->tx_irq;
+ ds_cfg.rx_irq = vdev->rx_irq;
+
+ lp = ldc_alloc(vdev->channel_id, &ds_cfg, dp);
+ if (IS_ERR(lp)) {
+ err = PTR_ERR(lp);
+ goto out_free_ds_states;
+ }
+ dp->lp = lp;
+
+ err = ldc_bind(lp, "DS");
+ if (err)
+ goto out_free_ldc;
+
+ spin_lock_irq(&ds_lock);
+ dp->next = ds_info_list;
+ ds_info_list = dp;
+ spin_unlock_irq(&ds_lock);
+
+ return err;
+
+out_free_ldc:
+ ldc_free(dp->lp);
+
+out_free_ds_states:
+ kfree(dp->ds_states);
+
+out_free_rcv_buf:
+ kfree(dp->rcv_buf);
+
+out_free_dp:
+ kfree(dp);
+
+out_err:
+ return err;
+}
+
+static int ds_remove(struct vio_dev *vdev)
+{
+ return 0;
+}
+
+static struct vio_device_id __initdata ds_match[] = {
+ {
+ .type = "domain-services-port",
+ },
+ {},
+};
+
+static struct vio_driver ds_driver = {
+ .id_table = ds_match,
+ .probe = ds_probe,
+ .remove = ds_remove,
+ .driver = {
+ .name = "ds",
+ .owner = THIS_MODULE,
+ }
+};
+
+static int __init ds_init(void)
+{
+ kthread_run(ds_thread, NULL, "kldomd");
+
+ return vio_register_driver(&ds_driver);
+}
+
+subsys_initcall(ds_init);
diff --git a/arch/sparc/kernel/dtlb_miss.S b/arch/sparc/kernel/dtlb_miss.S
new file mode 100644
index 000000000000..09a6a15a7105
--- /dev/null
+++ b/arch/sparc/kernel/dtlb_miss.S
@@ -0,0 +1,39 @@
+/* DTLB ** ICACHE line 1: Context 0 check and TSB load */
+ ldxa [%g0] ASI_DMMU_TSB_8KB_PTR, %g1 ! Get TSB 8K pointer
+ ldxa [%g0] ASI_DMMU, %g6 ! Get TAG TARGET
+ srlx %g6, 48, %g5 ! Get context
+ sllx %g6, 22, %g6 ! Zero out context
+ brz,pn %g5, kvmap_dtlb ! Context 0 processing
+ srlx %g6, 22, %g6 ! Delay slot
+ TSB_LOAD_QUAD(%g1, %g4) ! Load TSB entry
+ cmp %g4, %g6 ! Compare TAG
+
+/* DTLB ** ICACHE line 2: TSB compare and TLB load */
+ bne,pn %xcc, tsb_miss_dtlb ! Miss
+ mov FAULT_CODE_DTLB, %g3
+ stxa %g5, [%g0] ASI_DTLB_DATA_IN ! Load TLB
+ retry ! Trap done
+ nop
+ nop
+ nop
+ nop
+
+/* DTLB ** ICACHE line 3: */
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+
+/* DTLB ** ICACHE line 4: */
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
diff --git a/arch/sparc/kernel/dtlb_prot.S b/arch/sparc/kernel/dtlb_prot.S
new file mode 100644
index 000000000000..b2c2c5be281c
--- /dev/null
+++ b/arch/sparc/kernel/dtlb_prot.S
@@ -0,0 +1,54 @@
+/*
+ * dtlb_prot.S: DTLB protection trap strategy.
+ * This is included directly into the trap table.
+ *
+ * Copyright (C) 1996,1998 David S. Miller (davem@redhat.com)
+ * Copyright (C) 1997,1998 Jakub Jelinek (jj@ultra.linux.cz)
+ */
+
+/* Ways we can get here:
+ *
+ * [TL == 0] 1) User stores to readonly pages.
+ * [TL == 0] 2) Nucleus stores to user readonly pages.
+ * [TL > 0] 3) Nucleus stores to user readonly stack frame.
+ */
+
+/* PROT ** ICACHE line 1: User DTLB protection trap */
+ mov TLB_SFSR, %g1
+ stxa %g0, [%g1] ASI_DMMU ! Clear FaultValid bit
+ membar #Sync ! Synchronize stores
+ rdpr %pstate, %g5 ! Move into alt-globals
+ wrpr %g5, PSTATE_AG|PSTATE_MG, %pstate
+ rdpr %tl, %g1 ! Need a winfixup?
+ cmp %g1, 1 ! Trap level >1?
+ mov TLB_TAG_ACCESS, %g4 ! For reload of vaddr
+
+/* PROT ** ICACHE line 2: More real fault processing */
+ bgu,pn %xcc, winfix_trampoline ! Yes, perform winfixup
+ ldxa [%g4] ASI_DMMU, %g5 ! Put tagaccess in %g5
+ ba,pt %xcc, sparc64_realfault_common ! Nope, normal fault
+ mov FAULT_CODE_DTLB | FAULT_CODE_WRITE, %g4
+ nop
+ nop
+ nop
+ nop
+
+/* PROT ** ICACHE line 3: Unused... */
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+
+/* PROT ** ICACHE line 4: Unused... */
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
diff --git a/arch/sparc/kernel/ebus.c b/arch/sparc/kernel/ebus.c
new file mode 100644
index 000000000000..77dbf6d45faf
--- /dev/null
+++ b/arch/sparc/kernel/ebus.c
@@ -0,0 +1,257 @@
+/* ebus.c: EBUS DMA library code.
+ *
+ * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be)
+ * Copyright (C) 1999 David S. Miller (davem@redhat.com)
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+
+#include <asm/ebus_dma.h>
+#include <asm/io.h>
+
+#define EBDMA_CSR 0x00UL /* Control/Status */
+#define EBDMA_ADDR 0x04UL /* DMA Address */
+#define EBDMA_COUNT 0x08UL /* DMA Count */
+
+#define EBDMA_CSR_INT_PEND 0x00000001
+#define EBDMA_CSR_ERR_PEND 0x00000002
+#define EBDMA_CSR_DRAIN 0x00000004
+#define EBDMA_CSR_INT_EN 0x00000010
+#define EBDMA_CSR_RESET 0x00000080
+#define EBDMA_CSR_WRITE 0x00000100
+#define EBDMA_CSR_EN_DMA 0x00000200
+#define EBDMA_CSR_CYC_PEND 0x00000400
+#define EBDMA_CSR_DIAG_RD_DONE 0x00000800
+#define EBDMA_CSR_DIAG_WR_DONE 0x00001000
+#define EBDMA_CSR_EN_CNT 0x00002000
+#define EBDMA_CSR_TC 0x00004000
+#define EBDMA_CSR_DIS_CSR_DRN 0x00010000
+#define EBDMA_CSR_BURST_SZ_MASK 0x000c0000
+#define EBDMA_CSR_BURST_SZ_1 0x00080000
+#define EBDMA_CSR_BURST_SZ_4 0x00000000
+#define EBDMA_CSR_BURST_SZ_8 0x00040000
+#define EBDMA_CSR_BURST_SZ_16 0x000c0000
+#define EBDMA_CSR_DIAG_EN 0x00100000
+#define EBDMA_CSR_DIS_ERR_PEND 0x00400000
+#define EBDMA_CSR_TCI_DIS 0x00800000
+#define EBDMA_CSR_EN_NEXT 0x01000000
+#define EBDMA_CSR_DMA_ON 0x02000000
+#define EBDMA_CSR_A_LOADED 0x04000000
+#define EBDMA_CSR_NA_LOADED 0x08000000
+#define EBDMA_CSR_DEV_ID_MASK 0xf0000000
+
+#define EBUS_DMA_RESET_TIMEOUT 10000
+
+static void __ebus_dma_reset(struct ebus_dma_info *p, int no_drain)
+{
+ int i;
+ u32 val = 0;
+
+ writel(EBDMA_CSR_RESET, p->regs + EBDMA_CSR);
+ udelay(1);
+
+ if (no_drain)
+ return;
+
+ for (i = EBUS_DMA_RESET_TIMEOUT; i > 0; i--) {
+ val = readl(p->regs + EBDMA_CSR);
+
+ if (!(val & (EBDMA_CSR_DRAIN | EBDMA_CSR_CYC_PEND)))
+ break;
+ udelay(10);
+ }
+}
+
+static irqreturn_t ebus_dma_irq(int irq, void *dev_id)
+{
+ struct ebus_dma_info *p = dev_id;
+ unsigned long flags;
+ u32 csr = 0;
+
+ spin_lock_irqsave(&p->lock, flags);
+ csr = readl(p->regs + EBDMA_CSR);
+ writel(csr, p->regs + EBDMA_CSR);
+ spin_unlock_irqrestore(&p->lock, flags);
+
+ if (csr & EBDMA_CSR_ERR_PEND) {
+ printk(KERN_CRIT "ebus_dma(%s): DMA error!\n", p->name);
+ p->callback(p, EBUS_DMA_EVENT_ERROR, p->client_cookie);
+ return IRQ_HANDLED;
+ } else if (csr & EBDMA_CSR_INT_PEND) {
+ p->callback(p,
+ (csr & EBDMA_CSR_TC) ?
+ EBUS_DMA_EVENT_DMA : EBUS_DMA_EVENT_DEVICE,
+ p->client_cookie);
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+
+}
+
+int ebus_dma_register(struct ebus_dma_info *p)
+{
+ u32 csr;
+
+ if (!p->regs)
+ return -EINVAL;
+ if (p->flags & ~(EBUS_DMA_FLAG_USE_EBDMA_HANDLER |
+ EBUS_DMA_FLAG_TCI_DISABLE))
+ return -EINVAL;
+ if ((p->flags & EBUS_DMA_FLAG_USE_EBDMA_HANDLER) && !p->callback)
+ return -EINVAL;
+ if (!strlen(p->name))
+ return -EINVAL;
+
+ __ebus_dma_reset(p, 1);
+
+ csr = EBDMA_CSR_BURST_SZ_16 | EBDMA_CSR_EN_CNT;
+
+ if (p->flags & EBUS_DMA_FLAG_TCI_DISABLE)
+ csr |= EBDMA_CSR_TCI_DIS;
+
+ writel(csr, p->regs + EBDMA_CSR);
+
+ return 0;
+}
+EXPORT_SYMBOL(ebus_dma_register);
+
+int ebus_dma_irq_enable(struct ebus_dma_info *p, int on)
+{
+ unsigned long flags;
+ u32 csr;
+
+ if (on) {
+ if (p->flags & EBUS_DMA_FLAG_USE_EBDMA_HANDLER) {
+ if (request_irq(p->irq, ebus_dma_irq, IRQF_SHARED, p->name, p))
+ return -EBUSY;
+ }
+
+ spin_lock_irqsave(&p->lock, flags);
+ csr = readl(p->regs + EBDMA_CSR);
+ csr |= EBDMA_CSR_INT_EN;
+ writel(csr, p->regs + EBDMA_CSR);
+ spin_unlock_irqrestore(&p->lock, flags);
+ } else {
+ spin_lock_irqsave(&p->lock, flags);
+ csr = readl(p->regs + EBDMA_CSR);
+ csr &= ~EBDMA_CSR_INT_EN;
+ writel(csr, p->regs + EBDMA_CSR);
+ spin_unlock_irqrestore(&p->lock, flags);
+
+ if (p->flags & EBUS_DMA_FLAG_USE_EBDMA_HANDLER) {
+ free_irq(p->irq, p);
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(ebus_dma_irq_enable);
+
+void ebus_dma_unregister(struct ebus_dma_info *p)
+{
+ unsigned long flags;
+ u32 csr;
+ int irq_on = 0;
+
+ spin_lock_irqsave(&p->lock, flags);
+ csr = readl(p->regs + EBDMA_CSR);
+ if (csr & EBDMA_CSR_INT_EN) {
+ csr &= ~EBDMA_CSR_INT_EN;
+ writel(csr, p->regs + EBDMA_CSR);
+ irq_on = 1;
+ }
+ spin_unlock_irqrestore(&p->lock, flags);
+
+ if (irq_on)
+ free_irq(p->irq, p);
+}
+EXPORT_SYMBOL(ebus_dma_unregister);
+
+int ebus_dma_request(struct ebus_dma_info *p, dma_addr_t bus_addr, size_t len)
+{
+ unsigned long flags;
+ u32 csr;
+ int err;
+
+ if (len >= (1 << 24))
+ return -EINVAL;
+
+ spin_lock_irqsave(&p->lock, flags);
+ csr = readl(p->regs + EBDMA_CSR);
+ err = -EINVAL;
+ if (!(csr & EBDMA_CSR_EN_DMA))
+ goto out;
+ err = -EBUSY;
+ if (csr & EBDMA_CSR_NA_LOADED)
+ goto out;
+
+ writel(len, p->regs + EBDMA_COUNT);
+ writel(bus_addr, p->regs + EBDMA_ADDR);
+ err = 0;
+
+out:
+ spin_unlock_irqrestore(&p->lock, flags);
+
+ return err;
+}
+EXPORT_SYMBOL(ebus_dma_request);
+
+void ebus_dma_prepare(struct ebus_dma_info *p, int write)
+{
+ unsigned long flags;
+ u32 csr;
+
+ spin_lock_irqsave(&p->lock, flags);
+ __ebus_dma_reset(p, 0);
+
+ csr = (EBDMA_CSR_INT_EN |
+ EBDMA_CSR_EN_CNT |
+ EBDMA_CSR_BURST_SZ_16 |
+ EBDMA_CSR_EN_NEXT);
+
+ if (write)
+ csr |= EBDMA_CSR_WRITE;
+ if (p->flags & EBUS_DMA_FLAG_TCI_DISABLE)
+ csr |= EBDMA_CSR_TCI_DIS;
+
+ writel(csr, p->regs + EBDMA_CSR);
+
+ spin_unlock_irqrestore(&p->lock, flags);
+}
+EXPORT_SYMBOL(ebus_dma_prepare);
+
+unsigned int ebus_dma_residue(struct ebus_dma_info *p)
+{
+ return readl(p->regs + EBDMA_COUNT);
+}
+EXPORT_SYMBOL(ebus_dma_residue);
+
+unsigned int ebus_dma_addr(struct ebus_dma_info *p)
+{
+ return readl(p->regs + EBDMA_ADDR);
+}
+EXPORT_SYMBOL(ebus_dma_addr);
+
+void ebus_dma_enable(struct ebus_dma_info *p, int on)
+{
+ unsigned long flags;
+ u32 orig_csr, csr;
+
+ spin_lock_irqsave(&p->lock, flags);
+ orig_csr = csr = readl(p->regs + EBDMA_CSR);
+ if (on)
+ csr |= EBDMA_CSR_EN_DMA;
+ else
+ csr &= ~EBDMA_CSR_EN_DMA;
+ if ((orig_csr & EBDMA_CSR_EN_DMA) !=
+ (csr & EBDMA_CSR_EN_DMA))
+ writel(csr, p->regs + EBDMA_CSR);
+ spin_unlock_irqrestore(&p->lock, flags);
+}
+EXPORT_SYMBOL(ebus_dma_enable);
diff --git a/arch/sparc/kernel/entry.h b/arch/sparc/kernel/entry.h
new file mode 100644
index 000000000000..4f53a2395ac6
--- /dev/null
+++ b/arch/sparc/kernel/entry.h
@@ -0,0 +1,229 @@
+#ifndef _ENTRY_H
+#define _ENTRY_H
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+
+/* irq */
+extern void handler_irq(int irq, struct pt_regs *regs);
+
+#ifdef CONFIG_SPARC32
+/* traps */
+extern void do_hw_interrupt(struct pt_regs *regs, unsigned long type);
+extern void do_illegal_instruction(struct pt_regs *regs, unsigned long pc,
+ unsigned long npc, unsigned long psr);
+
+extern void do_priv_instruction(struct pt_regs *regs, unsigned long pc,
+ unsigned long npc, unsigned long psr);
+extern void do_memaccess_unaligned(struct pt_regs *regs, unsigned long pc,
+ unsigned long npc,
+ unsigned long psr);
+extern void do_fpd_trap(struct pt_regs *regs, unsigned long pc,
+ unsigned long npc, unsigned long psr);
+extern void do_fpe_trap(struct pt_regs *regs, unsigned long pc,
+ unsigned long npc, unsigned long psr);
+extern void handle_tag_overflow(struct pt_regs *regs, unsigned long pc,
+ unsigned long npc, unsigned long psr);
+extern void handle_watchpoint(struct pt_regs *regs, unsigned long pc,
+ unsigned long npc, unsigned long psr);
+extern void handle_reg_access(struct pt_regs *regs, unsigned long pc,
+ unsigned long npc, unsigned long psr);
+extern void handle_cp_disabled(struct pt_regs *regs, unsigned long pc,
+ unsigned long npc, unsigned long psr);
+extern void handle_cp_exception(struct pt_regs *regs, unsigned long pc,
+ unsigned long npc, unsigned long psr);
+
+
+
+/* entry.S */
+extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
+ void *fpqueue, unsigned long *fpqdepth);
+extern void fpload(unsigned long *fpregs, unsigned long *fsr);
+
+#else /* CONFIG_SPARC32 */
+extern void __init per_cpu_patch(void);
+extern void __init sun4v_patch(void);
+extern void __init boot_cpu_id_too_large(int cpu);
+extern unsigned int dcache_parity_tl1_occurred;
+extern unsigned int icache_parity_tl1_occurred;
+
+extern asmlinkage void update_perfctrs(void);
+extern asmlinkage void sparc_breakpoint(struct pt_regs *regs);
+extern void timer_interrupt(int irq, struct pt_regs *regs);
+
+extern void do_notify_resume(struct pt_regs *regs,
+ unsigned long orig_i0,
+ unsigned long thread_info_flags);
+
+extern asmlinkage int syscall_trace_enter(struct pt_regs *regs);
+extern asmlinkage void syscall_trace_leave(struct pt_regs *regs);
+
+extern void bad_trap_tl1(struct pt_regs *regs, long lvl);
+
+extern void do_fpe_common(struct pt_regs *regs);
+extern void do_fpieee(struct pt_regs *regs);
+extern void do_fpother(struct pt_regs *regs);
+extern void do_tof(struct pt_regs *regs);
+extern void do_div0(struct pt_regs *regs);
+extern void do_illegal_instruction(struct pt_regs *regs);
+extern void mem_address_unaligned(struct pt_regs *regs,
+ unsigned long sfar,
+ unsigned long sfsr);
+extern void sun4v_do_mna(struct pt_regs *regs,
+ unsigned long addr,
+ unsigned long type_ctx);
+extern void do_privop(struct pt_regs *regs);
+extern void do_privact(struct pt_regs *regs);
+extern void do_cee(struct pt_regs *regs);
+extern void do_cee_tl1(struct pt_regs *regs);
+extern void do_dae_tl1(struct pt_regs *regs);
+extern void do_iae_tl1(struct pt_regs *regs);
+extern void do_div0_tl1(struct pt_regs *regs);
+extern void do_fpdis_tl1(struct pt_regs *regs);
+extern void do_fpieee_tl1(struct pt_regs *regs);
+extern void do_fpother_tl1(struct pt_regs *regs);
+extern void do_ill_tl1(struct pt_regs *regs);
+extern void do_irq_tl1(struct pt_regs *regs);
+extern void do_lddfmna_tl1(struct pt_regs *regs);
+extern void do_stdfmna_tl1(struct pt_regs *regs);
+extern void do_paw(struct pt_regs *regs);
+extern void do_paw_tl1(struct pt_regs *regs);
+extern void do_vaw(struct pt_regs *regs);
+extern void do_vaw_tl1(struct pt_regs *regs);
+extern void do_tof_tl1(struct pt_regs *regs);
+extern void do_getpsr(struct pt_regs *regs);
+
+extern void spitfire_insn_access_exception(struct pt_regs *regs,
+ unsigned long sfsr,
+ unsigned long sfar);
+extern void spitfire_insn_access_exception_tl1(struct pt_regs *regs,
+ unsigned long sfsr,
+ unsigned long sfar);
+extern void spitfire_data_access_exception(struct pt_regs *regs,
+ unsigned long sfsr,
+ unsigned long sfar);
+extern void spitfire_data_access_exception_tl1(struct pt_regs *regs,
+ unsigned long sfsr,
+ unsigned long sfar);
+extern void spitfire_access_error(struct pt_regs *regs,
+ unsigned long status_encoded,
+ unsigned long afar);
+
+extern void cheetah_fecc_handler(struct pt_regs *regs,
+ unsigned long afsr,
+ unsigned long afar);
+extern void cheetah_cee_handler(struct pt_regs *regs,
+ unsigned long afsr,
+ unsigned long afar);
+extern void cheetah_deferred_handler(struct pt_regs *regs,
+ unsigned long afsr,
+ unsigned long afar);
+extern void cheetah_plus_parity_error(int type, struct pt_regs *regs);
+
+extern void sun4v_insn_access_exception(struct pt_regs *regs,
+ unsigned long addr,
+ unsigned long type_ctx);
+extern void sun4v_insn_access_exception_tl1(struct pt_regs *regs,
+ unsigned long addr,
+ unsigned long type_ctx);
+extern void sun4v_data_access_exception(struct pt_regs *regs,
+ unsigned long addr,
+ unsigned long type_ctx);
+extern void sun4v_data_access_exception_tl1(struct pt_regs *regs,
+ unsigned long addr,
+ unsigned long type_ctx);
+extern void sun4v_resum_error(struct pt_regs *regs,
+ unsigned long offset);
+extern void sun4v_resum_overflow(struct pt_regs *regs);
+extern void sun4v_nonresum_error(struct pt_regs *regs,
+ unsigned long offset);
+extern void sun4v_nonresum_overflow(struct pt_regs *regs);
+
+extern unsigned long sun4v_err_itlb_vaddr;
+extern unsigned long sun4v_err_itlb_ctx;
+extern unsigned long sun4v_err_itlb_pte;
+extern unsigned long sun4v_err_itlb_error;
+
+extern void sun4v_itlb_error_report(struct pt_regs *regs, int tl);
+
+extern unsigned long sun4v_err_dtlb_vaddr;
+extern unsigned long sun4v_err_dtlb_ctx;
+extern unsigned long sun4v_err_dtlb_pte;
+extern unsigned long sun4v_err_dtlb_error;
+
+extern void sun4v_dtlb_error_report(struct pt_regs *regs, int tl);
+extern void hypervisor_tlbop_error(unsigned long err,
+ unsigned long op);
+extern void hypervisor_tlbop_error_xcall(unsigned long err,
+ unsigned long op);
+
+/* WARNING: The error trap handlers in assembly know the precise
+ * layout of the following structure.
+ *
+ * C-level handlers in traps.c use this information to log the
+ * error and then determine how to recover (if possible).
+ */
+struct cheetah_err_info {
+/*0x00*/u64 afsr;
+/*0x08*/u64 afar;
+
+ /* D-cache state */
+/*0x10*/u64 dcache_data[4]; /* The actual data */
+/*0x30*/u64 dcache_index; /* D-cache index */
+/*0x38*/u64 dcache_tag; /* D-cache tag/valid */
+/*0x40*/u64 dcache_utag; /* D-cache microtag */
+/*0x48*/u64 dcache_stag; /* D-cache snooptag */
+
+ /* I-cache state */
+/*0x50*/u64 icache_data[8]; /* The actual insns + predecode */
+/*0x90*/u64 icache_index; /* I-cache index */
+/*0x98*/u64 icache_tag; /* I-cache phys tag */
+/*0xa0*/u64 icache_utag; /* I-cache microtag */
+/*0xa8*/u64 icache_stag; /* I-cache snooptag */
+/*0xb0*/u64 icache_upper; /* I-cache upper-tag */
+/*0xb8*/u64 icache_lower; /* I-cache lower-tag */
+
+ /* E-cache state */
+/*0xc0*/u64 ecache_data[4]; /* 32 bytes from staging registers */
+/*0xe0*/u64 ecache_index; /* E-cache index */
+/*0xe8*/u64 ecache_tag; /* E-cache tag/state */
+
+/*0xf0*/u64 __pad[32 - 30];
+};
+#define CHAFSR_INVALID ((u64)-1L)
+
+/* This is allocated at boot time based upon the largest hardware
+ * cpu ID in the system. We allocate two entries per cpu, one for
+ * TL==0 logging and one for TL >= 1 logging.
+ */
+extern struct cheetah_err_info *cheetah_error_log;
+
+/* UPA nodes send interrupt packet to UltraSparc with first data reg
+ * value low 5 (7 on Starfire) bits holding the IRQ identifier being
+ * delivered. We must translate this into a non-vector IRQ so we can
+ * set the softint on this cpu.
+ *
+ * To make processing these packets efficient and race free we use
+ * an array of irq buckets below. The interrupt vector handler in
+ * entry.S feeds incoming packets into per-cpu pil-indexed lists.
+ *
+ * If you make changes to ino_bucket, please update hand coded assembler
+ * of the vectored interrupt trap handler(s) in entry.S and sun4v_ivec.S
+ */
+struct ino_bucket {
+/*0x00*/unsigned long __irq_chain_pa;
+
+ /* Virtual interrupt number assigned to this INO. */
+/*0x08*/unsigned int __virt_irq;
+/*0x0c*/unsigned int __pad;
+};
+
+extern struct ino_bucket *ivector_table;
+extern unsigned long ivector_table_pa;
+
+extern void init_irqwork_curcpu(void);
+extern void __cpuinit sun4v_register_mondo_queues(int this_cpu);
+
+#endif /* CONFIG_SPARC32 */
+#endif /* _ENTRY_H */
diff --git a/arch/sparc/kernel/etrap.S b/arch/sparc/kernel/etrap_32.S
index e806fcdc46db..e806fcdc46db 100644
--- a/arch/sparc/kernel/etrap.S
+++ b/arch/sparc/kernel/etrap_32.S
diff --git a/arch/sparc/kernel/etrap_64.S b/arch/sparc/kernel/etrap_64.S
new file mode 100644
index 000000000000..786b185e6e3f
--- /dev/null
+++ b/arch/sparc/kernel/etrap_64.S
@@ -0,0 +1,236 @@
+/*
+ * etrap.S: Preparing for entry into the kernel on Sparc V9.
+ *
+ * Copyright (C) 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997, 1998, 1999 Jakub Jelinek (jj@ultra.linux.cz)
+ */
+
+
+#include <asm/asi.h>
+#include <asm/pstate.h>
+#include <asm/ptrace.h>
+#include <asm/page.h>
+#include <asm/spitfire.h>
+#include <asm/head.h>
+#include <asm/processor.h>
+#include <asm/mmu.h>
+
+#define TASK_REGOFF (THREAD_SIZE-TRACEREG_SZ-STACKFRAME_SZ)
+#define ETRAP_PSTATE1 (PSTATE_TSO | PSTATE_PRIV)
+#define ETRAP_PSTATE2 \
+ (PSTATE_TSO | PSTATE_PEF | PSTATE_PRIV | PSTATE_IE)
+
+/*
+ * On entry, %g7 is return address - 0x4.
+ * %g4 and %g5 will be preserved %l4 and %l5 respectively.
+ */
+
+ .text
+ .align 64
+ .globl etrap_syscall, etrap, etrap_irq, etraptl1
+etrap: rdpr %pil, %g2
+etrap_irq: clr %g3
+etrap_syscall: TRAP_LOAD_THREAD_REG(%g6, %g1)
+ rdpr %tstate, %g1
+ or %g1, %g3, %g1
+ sllx %g2, 20, %g3
+ andcc %g1, TSTATE_PRIV, %g0
+ or %g1, %g3, %g1
+ bne,pn %xcc, 1f
+ sub %sp, STACKFRAME_SZ+TRACEREG_SZ-STACK_BIAS, %g2
+ wrpr %g0, 7, %cleanwin
+
+ sethi %hi(TASK_REGOFF), %g2
+ sethi %hi(TSTATE_PEF), %g3
+ or %g2, %lo(TASK_REGOFF), %g2
+ and %g1, %g3, %g3
+ brnz,pn %g3, 1f
+ add %g6, %g2, %g2
+ wr %g0, 0, %fprs
+1: rdpr %tpc, %g3
+
+ stx %g1, [%g2 + STACKFRAME_SZ + PT_V9_TSTATE]
+ rdpr %tnpc, %g1
+ stx %g3, [%g2 + STACKFRAME_SZ + PT_V9_TPC]
+ rd %y, %g3
+ stx %g1, [%g2 + STACKFRAME_SZ + PT_V9_TNPC]
+ rdpr %tt, %g1
+ st %g3, [%g2 + STACKFRAME_SZ + PT_V9_Y]
+ sethi %hi(PT_REGS_MAGIC), %g3
+ or %g3, %g1, %g1
+ st %g1, [%g2 + STACKFRAME_SZ + PT_V9_MAGIC]
+
+ rdpr %cansave, %g1
+ brnz,pt %g1, etrap_save
+ nop
+
+ rdpr %cwp, %g1
+ add %g1, 2, %g1
+ wrpr %g1, %cwp
+ be,pt %xcc, etrap_user_spill
+ mov ASI_AIUP, %g3
+
+ rdpr %otherwin, %g3
+ brz %g3, etrap_kernel_spill
+ mov ASI_AIUS, %g3
+
+etrap_user_spill:
+
+ wr %g3, 0x0, %asi
+ ldx [%g6 + TI_FLAGS], %g3
+ and %g3, _TIF_32BIT, %g3
+ brnz,pt %g3, etrap_user_spill_32bit
+ nop
+ ba,a,pt %xcc, etrap_user_spill_64bit
+
+etrap_save: save %g2, -STACK_BIAS, %sp
+ mov %g6, %l6
+
+ bne,pn %xcc, 3f
+ mov PRIMARY_CONTEXT, %l4
+ rdpr %canrestore, %g3
+ rdpr %wstate, %g2
+ wrpr %g0, 0, %canrestore
+ sll %g2, 3, %g2
+ mov 1, %l5
+ stb %l5, [%l6 + TI_FPDEPTH]
+
+ wrpr %g3, 0, %otherwin
+ wrpr %g2, 0, %wstate
+ sethi %hi(sparc64_kern_pri_context), %g2
+ ldx [%g2 + %lo(sparc64_kern_pri_context)], %g3
+
+661: stxa %g3, [%l4] ASI_DMMU
+ .section .sun4v_1insn_patch, "ax"
+ .word 661b
+ stxa %g3, [%l4] ASI_MMU
+ .previous
+
+ sethi %hi(KERNBASE), %l4
+ flush %l4
+ mov ASI_AIUS, %l7
+2: mov %g4, %l4
+ mov %g5, %l5
+ add %g7, 4, %l2
+
+ /* Go to trap time globals so we can save them. */
+661: wrpr %g0, ETRAP_PSTATE1, %pstate
+ .section .sun4v_1insn_patch, "ax"
+ .word 661b
+ SET_GL(0)
+ .previous
+
+ stx %g1, [%sp + PTREGS_OFF + PT_V9_G1]
+ stx %g2, [%sp + PTREGS_OFF + PT_V9_G2]
+ sllx %l7, 24, %l7
+ stx %g3, [%sp + PTREGS_OFF + PT_V9_G3]
+ rdpr %cwp, %l0
+ stx %g4, [%sp + PTREGS_OFF + PT_V9_G4]
+ stx %g5, [%sp + PTREGS_OFF + PT_V9_G5]
+ stx %g6, [%sp + PTREGS_OFF + PT_V9_G6]
+ stx %g7, [%sp + PTREGS_OFF + PT_V9_G7]
+ or %l7, %l0, %l7
+ sethi %hi(TSTATE_TSO | TSTATE_PEF), %l0
+ or %l7, %l0, %l7
+ wrpr %l2, %tnpc
+ wrpr %l7, (TSTATE_PRIV | TSTATE_IE), %tstate
+ stx %i0, [%sp + PTREGS_OFF + PT_V9_I0]
+ stx %i1, [%sp + PTREGS_OFF + PT_V9_I1]
+ stx %i2, [%sp + PTREGS_OFF + PT_V9_I2]
+ stx %i3, [%sp + PTREGS_OFF + PT_V9_I3]
+ stx %i4, [%sp + PTREGS_OFF + PT_V9_I4]
+ stx %i5, [%sp + PTREGS_OFF + PT_V9_I5]
+ stx %i6, [%sp + PTREGS_OFF + PT_V9_I6]
+ mov %l6, %g6
+ stx %i7, [%sp + PTREGS_OFF + PT_V9_I7]
+ LOAD_PER_CPU_BASE(%g5, %g6, %g4, %g3, %l1)
+ ldx [%g6 + TI_TASK], %g4
+ done
+
+3: mov ASI_P, %l7
+ ldub [%l6 + TI_FPDEPTH], %l5
+ add %l6, TI_FPSAVED + 1, %l4
+ srl %l5, 1, %l3
+ add %l5, 2, %l5
+ stb %l5, [%l6 + TI_FPDEPTH]
+ ba,pt %xcc, 2b
+ stb %g0, [%l4 + %l3]
+ nop
+
+etraptl1: /* Save tstate/tpc/tnpc of TL 1-->4 and the tl register itself.
+ * We place this right after pt_regs on the trap stack.
+ * The layout is:
+ * 0x00 TL1's TSTATE
+ * 0x08 TL1's TPC
+ * 0x10 TL1's TNPC
+ * 0x18 TL1's TT
+ * ...
+ * 0x58 TL4's TT
+ * 0x60 TL
+ */
+ TRAP_LOAD_THREAD_REG(%g6, %g1)
+ sub %sp, ((4 * 8) * 4) + 8, %g2
+ rdpr %tl, %g1
+
+ wrpr %g0, 1, %tl
+ rdpr %tstate, %g3
+ stx %g3, [%g2 + STACK_BIAS + 0x00]
+ rdpr %tpc, %g3
+ stx %g3, [%g2 + STACK_BIAS + 0x08]
+ rdpr %tnpc, %g3
+ stx %g3, [%g2 + STACK_BIAS + 0x10]
+ rdpr %tt, %g3
+ stx %g3, [%g2 + STACK_BIAS + 0x18]
+
+ wrpr %g0, 2, %tl
+ rdpr %tstate, %g3
+ stx %g3, [%g2 + STACK_BIAS + 0x20]
+ rdpr %tpc, %g3
+ stx %g3, [%g2 + STACK_BIAS + 0x28]
+ rdpr %tnpc, %g3
+ stx %g3, [%g2 + STACK_BIAS + 0x30]
+ rdpr %tt, %g3
+ stx %g3, [%g2 + STACK_BIAS + 0x38]
+
+ sethi %hi(is_sun4v), %g3
+ lduw [%g3 + %lo(is_sun4v)], %g3
+ brnz,pn %g3, finish_tl1_capture
+ nop
+
+ wrpr %g0, 3, %tl
+ rdpr %tstate, %g3
+ stx %g3, [%g2 + STACK_BIAS + 0x40]
+ rdpr %tpc, %g3
+ stx %g3, [%g2 + STACK_BIAS + 0x48]
+ rdpr %tnpc, %g3
+ stx %g3, [%g2 + STACK_BIAS + 0x50]
+ rdpr %tt, %g3
+ stx %g3, [%g2 + STACK_BIAS + 0x58]
+
+ wrpr %g0, 4, %tl
+ rdpr %tstate, %g3
+ stx %g3, [%g2 + STACK_BIAS + 0x60]
+ rdpr %tpc, %g3
+ stx %g3, [%g2 + STACK_BIAS + 0x68]
+ rdpr %tnpc, %g3
+ stx %g3, [%g2 + STACK_BIAS + 0x70]
+ rdpr %tt, %g3
+ stx %g3, [%g2 + STACK_BIAS + 0x78]
+
+ stx %g1, [%g2 + STACK_BIAS + 0x80]
+
+finish_tl1_capture:
+ wrpr %g0, 1, %tl
+661: nop
+ .section .sun4v_1insn_patch, "ax"
+ .word 661b
+ SET_GL(1)
+ .previous
+
+ rdpr %tstate, %g1
+ sub %g2, STACKFRAME_SZ + TRACEREG_SZ - STACK_BIAS, %g2
+ ba,pt %xcc, 1b
+ andcc %g1, TSTATE_PRIV, %g0
+
+#undef TASK_REGOFF
+#undef ETRAP_PSTATE1
diff --git a/arch/sparc/kernel/fpu_traps.S b/arch/sparc/kernel/fpu_traps.S
new file mode 100644
index 000000000000..a6864826a4bd
--- /dev/null
+++ b/arch/sparc/kernel/fpu_traps.S
@@ -0,0 +1,384 @@
+ /* This is trivial with the new code... */
+ .globl do_fpdis
+ .type do_fpdis,#function
+do_fpdis:
+ sethi %hi(TSTATE_PEF), %g4
+ rdpr %tstate, %g5
+ andcc %g5, %g4, %g0
+ be,pt %xcc, 1f
+ nop
+ rd %fprs, %g5
+ andcc %g5, FPRS_FEF, %g0
+ be,pt %xcc, 1f
+ nop
+
+ /* Legal state when DCR_IFPOE is set in Cheetah %dcr. */
+ sethi %hi(109f), %g7
+ ba,pt %xcc, etrap
+109: or %g7, %lo(109b), %g7
+ add %g0, %g0, %g0
+ ba,a,pt %xcc, rtrap
+
+1: TRAP_LOAD_THREAD_REG(%g6, %g1)
+ ldub [%g6 + TI_FPSAVED], %g5
+ wr %g0, FPRS_FEF, %fprs
+ andcc %g5, FPRS_FEF, %g0
+ be,a,pt %icc, 1f
+ clr %g7
+ ldx [%g6 + TI_GSR], %g7
+1: andcc %g5, FPRS_DL, %g0
+ bne,pn %icc, 2f
+ fzero %f0
+ andcc %g5, FPRS_DU, %g0
+ bne,pn %icc, 1f
+ fzero %f2
+ faddd %f0, %f2, %f4
+ fmuld %f0, %f2, %f6
+ faddd %f0, %f2, %f8
+ fmuld %f0, %f2, %f10
+ faddd %f0, %f2, %f12
+ fmuld %f0, %f2, %f14
+ faddd %f0, %f2, %f16
+ fmuld %f0, %f2, %f18
+ faddd %f0, %f2, %f20
+ fmuld %f0, %f2, %f22
+ faddd %f0, %f2, %f24
+ fmuld %f0, %f2, %f26
+ faddd %f0, %f2, %f28
+ fmuld %f0, %f2, %f30
+ faddd %f0, %f2, %f32
+ fmuld %f0, %f2, %f34
+ faddd %f0, %f2, %f36
+ fmuld %f0, %f2, %f38
+ faddd %f0, %f2, %f40
+ fmuld %f0, %f2, %f42
+ faddd %f0, %f2, %f44
+ fmuld %f0, %f2, %f46
+ faddd %f0, %f2, %f48
+ fmuld %f0, %f2, %f50
+ faddd %f0, %f2, %f52
+ fmuld %f0, %f2, %f54
+ faddd %f0, %f2, %f56
+ fmuld %f0, %f2, %f58
+ b,pt %xcc, fpdis_exit2
+ faddd %f0, %f2, %f60
+1: mov SECONDARY_CONTEXT, %g3
+ add %g6, TI_FPREGS + 0x80, %g1
+ faddd %f0, %f2, %f4
+ fmuld %f0, %f2, %f6
+
+661: ldxa [%g3] ASI_DMMU, %g5
+ .section .sun4v_1insn_patch, "ax"
+ .word 661b
+ ldxa [%g3] ASI_MMU, %g5
+ .previous
+
+ sethi %hi(sparc64_kern_sec_context), %g2
+ ldx [%g2 + %lo(sparc64_kern_sec_context)], %g2
+
+661: stxa %g2, [%g3] ASI_DMMU
+ .section .sun4v_1insn_patch, "ax"
+ .word 661b
+ stxa %g2, [%g3] ASI_MMU
+ .previous
+
+ membar #Sync
+ add %g6, TI_FPREGS + 0xc0, %g2
+ faddd %f0, %f2, %f8
+ fmuld %f0, %f2, %f10
+ membar #Sync
+ ldda [%g1] ASI_BLK_S, %f32
+ ldda [%g2] ASI_BLK_S, %f48
+ membar #Sync
+ faddd %f0, %f2, %f12
+ fmuld %f0, %f2, %f14
+ faddd %f0, %f2, %f16
+ fmuld %f0, %f2, %f18
+ faddd %f0, %f2, %f20
+ fmuld %f0, %f2, %f22
+ faddd %f0, %f2, %f24
+ fmuld %f0, %f2, %f26
+ faddd %f0, %f2, %f28
+ fmuld %f0, %f2, %f30
+ b,pt %xcc, fpdis_exit
+ nop
+2: andcc %g5, FPRS_DU, %g0
+ bne,pt %icc, 3f
+ fzero %f32
+ mov SECONDARY_CONTEXT, %g3
+ fzero %f34
+
+661: ldxa [%g3] ASI_DMMU, %g5
+ .section .sun4v_1insn_patch, "ax"
+ .word 661b
+ ldxa [%g3] ASI_MMU, %g5
+ .previous
+
+ add %g6, TI_FPREGS, %g1
+ sethi %hi(sparc64_kern_sec_context), %g2
+ ldx [%g2 + %lo(sparc64_kern_sec_context)], %g2
+
+661: stxa %g2, [%g3] ASI_DMMU
+ .section .sun4v_1insn_patch, "ax"
+ .word 661b
+ stxa %g2, [%g3] ASI_MMU
+ .previous
+
+ membar #Sync
+ add %g6, TI_FPREGS + 0x40, %g2
+ faddd %f32, %f34, %f36
+ fmuld %f32, %f34, %f38
+ membar #Sync
+ ldda [%g1] ASI_BLK_S, %f0
+ ldda [%g2] ASI_BLK_S, %f16
+ membar #Sync
+ faddd %f32, %f34, %f40
+ fmuld %f32, %f34, %f42
+ faddd %f32, %f34, %f44
+ fmuld %f32, %f34, %f46
+ faddd %f32, %f34, %f48
+ fmuld %f32, %f34, %f50
+ faddd %f32, %f34, %f52
+ fmuld %f32, %f34, %f54
+ faddd %f32, %f34, %f56
+ fmuld %f32, %f34, %f58
+ faddd %f32, %f34, %f60
+ fmuld %f32, %f34, %f62
+ ba,pt %xcc, fpdis_exit
+ nop
+3: mov SECONDARY_CONTEXT, %g3
+ add %g6, TI_FPREGS, %g1
+
+661: ldxa [%g3] ASI_DMMU, %g5
+ .section .sun4v_1insn_patch, "ax"
+ .word 661b
+ ldxa [%g3] ASI_MMU, %g5
+ .previous
+
+ sethi %hi(sparc64_kern_sec_context), %g2
+ ldx [%g2 + %lo(sparc64_kern_sec_context)], %g2
+
+661: stxa %g2, [%g3] ASI_DMMU
+ .section .sun4v_1insn_patch, "ax"
+ .word 661b
+ stxa %g2, [%g3] ASI_MMU
+ .previous
+
+ membar #Sync
+ mov 0x40, %g2
+ membar #Sync
+ ldda [%g1] ASI_BLK_S, %f0
+ ldda [%g1 + %g2] ASI_BLK_S, %f16
+ add %g1, 0x80, %g1
+ ldda [%g1] ASI_BLK_S, %f32
+ ldda [%g1 + %g2] ASI_BLK_S, %f48
+ membar #Sync
+fpdis_exit:
+
+661: stxa %g5, [%g3] ASI_DMMU
+ .section .sun4v_1insn_patch, "ax"
+ .word 661b
+ stxa %g5, [%g3] ASI_MMU
+ .previous
+
+ membar #Sync
+fpdis_exit2:
+ wr %g7, 0, %gsr
+ ldx [%g6 + TI_XFSR], %fsr
+ rdpr %tstate, %g3
+ or %g3, %g4, %g3 ! anal...
+ wrpr %g3, %tstate
+ wr %g0, FPRS_FEF, %fprs ! clean DU/DL bits
+ retry
+ .size do_fpdis,.-do_fpdis
+
+ .align 32
+ .type fp_other_bounce,#function
+fp_other_bounce:
+ call do_fpother
+ add %sp, PTREGS_OFF, %o0
+ ba,pt %xcc, rtrap
+ nop
+ .size fp_other_bounce,.-fp_other_bounce
+
+ .align 32
+ .globl do_fpother_check_fitos
+ .type do_fpother_check_fitos,#function
+do_fpother_check_fitos:
+ TRAP_LOAD_THREAD_REG(%g6, %g1)
+ sethi %hi(fp_other_bounce - 4), %g7
+ or %g7, %lo(fp_other_bounce - 4), %g7
+
+ /* NOTE: Need to preserve %g7 until we fully commit
+ * to the fitos fixup.
+ */
+ stx %fsr, [%g6 + TI_XFSR]
+ rdpr %tstate, %g3
+ andcc %g3, TSTATE_PRIV, %g0
+ bne,pn %xcc, do_fptrap_after_fsr
+ nop
+ ldx [%g6 + TI_XFSR], %g3
+ srlx %g3, 14, %g1
+ and %g1, 7, %g1
+ cmp %g1, 2 ! Unfinished FP-OP
+ bne,pn %xcc, do_fptrap_after_fsr
+ sethi %hi(1 << 23), %g1 ! Inexact
+ andcc %g3, %g1, %g0
+ bne,pn %xcc, do_fptrap_after_fsr
+ rdpr %tpc, %g1
+ lduwa [%g1] ASI_AIUP, %g3 ! This cannot ever fail
+#define FITOS_MASK 0xc1f83fe0
+#define FITOS_COMPARE 0x81a01880
+ sethi %hi(FITOS_MASK), %g1
+ or %g1, %lo(FITOS_MASK), %g1
+ and %g3, %g1, %g1
+ sethi %hi(FITOS_COMPARE), %g2
+ or %g2, %lo(FITOS_COMPARE), %g2
+ cmp %g1, %g2
+ bne,pn %xcc, do_fptrap_after_fsr
+ nop
+ std %f62, [%g6 + TI_FPREGS + (62 * 4)]
+ sethi %hi(fitos_table_1), %g1
+ and %g3, 0x1f, %g2
+ or %g1, %lo(fitos_table_1), %g1
+ sllx %g2, 2, %g2
+ jmpl %g1 + %g2, %g0
+ ba,pt %xcc, fitos_emul_continue
+
+fitos_table_1:
+ fitod %f0, %f62
+ fitod %f1, %f62
+ fitod %f2, %f62
+ fitod %f3, %f62
+ fitod %f4, %f62
+ fitod %f5, %f62
+ fitod %f6, %f62
+ fitod %f7, %f62
+ fitod %f8, %f62
+ fitod %f9, %f62
+ fitod %f10, %f62
+ fitod %f11, %f62
+ fitod %f12, %f62
+ fitod %f13, %f62
+ fitod %f14, %f62
+ fitod %f15, %f62
+ fitod %f16, %f62
+ fitod %f17, %f62
+ fitod %f18, %f62
+ fitod %f19, %f62
+ fitod %f20, %f62
+ fitod %f21, %f62
+ fitod %f22, %f62
+ fitod %f23, %f62
+ fitod %f24, %f62
+ fitod %f25, %f62
+ fitod %f26, %f62
+ fitod %f27, %f62
+ fitod %f28, %f62
+ fitod %f29, %f62
+ fitod %f30, %f62
+ fitod %f31, %f62
+
+fitos_emul_continue:
+ sethi %hi(fitos_table_2), %g1
+ srl %g3, 25, %g2
+ or %g1, %lo(fitos_table_2), %g1
+ and %g2, 0x1f, %g2
+ sllx %g2, 2, %g2
+ jmpl %g1 + %g2, %g0
+ ba,pt %xcc, fitos_emul_fini
+
+fitos_table_2:
+ fdtos %f62, %f0
+ fdtos %f62, %f1
+ fdtos %f62, %f2
+ fdtos %f62, %f3
+ fdtos %f62, %f4
+ fdtos %f62, %f5
+ fdtos %f62, %f6
+ fdtos %f62, %f7
+ fdtos %f62, %f8
+ fdtos %f62, %f9
+ fdtos %f62, %f10
+ fdtos %f62, %f11
+ fdtos %f62, %f12
+ fdtos %f62, %f13
+ fdtos %f62, %f14
+ fdtos %f62, %f15
+ fdtos %f62, %f16
+ fdtos %f62, %f17
+ fdtos %f62, %f18
+ fdtos %f62, %f19
+ fdtos %f62, %f20
+ fdtos %f62, %f21
+ fdtos %f62, %f22
+ fdtos %f62, %f23
+ fdtos %f62, %f24
+ fdtos %f62, %f25
+ fdtos %f62, %f26
+ fdtos %f62, %f27
+ fdtos %f62, %f28
+ fdtos %f62, %f29
+ fdtos %f62, %f30
+ fdtos %f62, %f31
+
+fitos_emul_fini:
+ ldd [%g6 + TI_FPREGS + (62 * 4)], %f62
+ done
+ .size do_fpother_check_fitos,.-do_fpother_check_fitos
+
+ .align 32
+ .globl do_fptrap
+ .type do_fptrap,#function
+do_fptrap:
+ TRAP_LOAD_THREAD_REG(%g6, %g1)
+ stx %fsr, [%g6 + TI_XFSR]
+do_fptrap_after_fsr:
+ ldub [%g6 + TI_FPSAVED], %g3
+ rd %fprs, %g1
+ or %g3, %g1, %g3
+ stb %g3, [%g6 + TI_FPSAVED]
+ rd %gsr, %g3
+ stx %g3, [%g6 + TI_GSR]
+ mov SECONDARY_CONTEXT, %g3
+
+661: ldxa [%g3] ASI_DMMU, %g5
+ .section .sun4v_1insn_patch, "ax"
+ .word 661b
+ ldxa [%g3] ASI_MMU, %g5
+ .previous
+
+ sethi %hi(sparc64_kern_sec_context), %g2
+ ldx [%g2 + %lo(sparc64_kern_sec_context)], %g2
+
+661: stxa %g2, [%g3] ASI_DMMU
+ .section .sun4v_1insn_patch, "ax"
+ .word 661b
+ stxa %g2, [%g3] ASI_MMU
+ .previous
+
+ membar #Sync
+ add %g6, TI_FPREGS, %g2
+ andcc %g1, FPRS_DL, %g0
+ be,pn %icc, 4f
+ mov 0x40, %g3
+ stda %f0, [%g2] ASI_BLK_S
+ stda %f16, [%g2 + %g3] ASI_BLK_S
+ andcc %g1, FPRS_DU, %g0
+ be,pn %icc, 5f
+4: add %g2, 128, %g2
+ stda %f32, [%g2] ASI_BLK_S
+ stda %f48, [%g2 + %g3] ASI_BLK_S
+5: mov SECONDARY_CONTEXT, %g1
+ membar #Sync
+
+661: stxa %g5, [%g1] ASI_DMMU
+ .section .sun4v_1insn_patch, "ax"
+ .word 661b
+ stxa %g5, [%g1] ASI_MMU
+ .previous
+
+ membar #Sync
+ ba,pt %xcc, etrap
+ wr %g0, 0, %fprs
+ .size do_fptrap,.-do_fptrap
diff --git a/arch/sparc/kernel/ftrace.c b/arch/sparc/kernel/ftrace.c
new file mode 100644
index 000000000000..d0218e73f982
--- /dev/null
+++ b/arch/sparc/kernel/ftrace.c
@@ -0,0 +1,76 @@
+#include <linux/spinlock.h>
+#include <linux/hardirq.h>
+#include <linux/ftrace.h>
+#include <linux/percpu.h>
+#include <linux/init.h>
+#include <linux/list.h>
+
+#include <asm/ftrace.h>
+
+static const u32 ftrace_nop = 0x01000000;
+
+unsigned char *ftrace_nop_replace(void)
+{
+ return (char *)&ftrace_nop;
+}
+
+unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr)
+{
+ static u32 call;
+ s32 off;
+
+ off = ((s32)addr - (s32)ip);
+ call = 0x40000000 | ((u32)off >> 2);
+
+ return (unsigned char *) &call;
+}
+
+int
+ftrace_modify_code(unsigned long ip, unsigned char *old_code,
+ unsigned char *new_code)
+{
+ u32 old = *(u32 *)old_code;
+ u32 new = *(u32 *)new_code;
+ u32 replaced;
+ int faulted;
+
+ __asm__ __volatile__(
+ "1: cas [%[ip]], %[old], %[new]\n"
+ " flush %[ip]\n"
+ " mov 0, %[faulted]\n"
+ "2:\n"
+ " .section .fixup,#alloc,#execinstr\n"
+ " .align 4\n"
+ "3: sethi %%hi(2b), %[faulted]\n"
+ " jmpl %[faulted] + %%lo(2b), %%g0\n"
+ " mov 1, %[faulted]\n"
+ " .previous\n"
+ " .section __ex_table,\"a\"\n"
+ " .align 4\n"
+ " .word 1b, 3b\n"
+ " .previous\n"
+ : "=r" (replaced), [faulted] "=r" (faulted)
+ : [new] "0" (new), [old] "r" (old), [ip] "r" (ip)
+ : "memory");
+
+ if (replaced != old && replaced != new)
+ faulted = 2;
+
+ return faulted;
+}
+
+int ftrace_update_ftrace_func(ftrace_func_t func)
+{
+ unsigned long ip = (unsigned long)(&ftrace_call);
+ unsigned char old[MCOUNT_INSN_SIZE], *new;
+
+ memcpy(old, &ftrace_call, MCOUNT_INSN_SIZE);
+ new = ftrace_call_replace(ip, (unsigned long)func);
+ return ftrace_modify_code(ip, old, new);
+}
+
+int __init ftrace_dyn_arch_init(void *data)
+{
+ ftrace_mcount_set(data);
+ return 0;
+}
diff --git a/arch/sparc/kernel/getsetcc.S b/arch/sparc/kernel/getsetcc.S
new file mode 100644
index 000000000000..a14d272d2061
--- /dev/null
+++ b/arch/sparc/kernel/getsetcc.S
@@ -0,0 +1,24 @@
+ .globl getcc
+ .type getcc,#function
+getcc:
+ ldx [%o0 + PT_V9_TSTATE], %o1
+ srlx %o1, 32, %o1
+ and %o1, 0xf, %o1
+ retl
+ stx %o1, [%o0 + PT_V9_G1]
+ .size getcc,.-getcc
+
+ .globl setcc
+ .type setcc,#function
+setcc:
+ ldx [%o0 + PT_V9_TSTATE], %o1
+ ldx [%o0 + PT_V9_G1], %o2
+ or %g0, %ulo(TSTATE_ICC), %o3
+ sllx %o3, 32, %o3
+ andn %o1, %o3, %o1
+ sllx %o2, 32, %o2
+ and %o2, %o3, %o2
+ or %o1, %o2, %o1
+ retl
+ stx %o1, [%o0 + PT_V9_TSTATE]
+ .size setcc,.-setcc
diff --git a/arch/sparc/kernel/head.S b/arch/sparc/kernel/head_32.S
index 51b40426f9c6..f0b4b516304f 100644
--- a/arch/sparc/kernel/head.S
+++ b/arch/sparc/kernel/head_32.S
@@ -990,7 +990,7 @@ sun4c_continue_boot:
/* Zero out our BSS section. */
set __bss_start , %o0 ! First address of BSS
- set end , %o1 ! Last address of BSS
+ set _end , %o1 ! Last address of BSS
add %o0, 0x1, %o0
1:
stb %g0, [%o0]
diff --git a/arch/sparc/kernel/head_64.S b/arch/sparc/kernel/head_64.S
new file mode 100644
index 000000000000..8ffee714f932
--- /dev/null
+++ b/arch/sparc/kernel/head_64.S
@@ -0,0 +1,900 @@
+/* head.S: Initial boot code for the Sparc64 port of Linux.
+ *
+ * Copyright (C) 1996, 1997, 2007 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1996 David Sitsky (David.Sitsky@anu.edu.au)
+ * Copyright (C) 1997, 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ */
+
+#include <linux/version.h>
+#include <linux/errno.h>
+#include <linux/threads.h>
+#include <linux/init.h>
+#include <linux/linkage.h>
+#include <asm/thread_info.h>
+#include <asm/asi.h>
+#include <asm/pstate.h>
+#include <asm/ptrace.h>
+#include <asm/spitfire.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/errno.h>
+#include <asm/signal.h>
+#include <asm/processor.h>
+#include <asm/lsu.h>
+#include <asm/dcr.h>
+#include <asm/dcu.h>
+#include <asm/head.h>
+#include <asm/ttable.h>
+#include <asm/mmu.h>
+#include <asm/cpudata.h>
+#include <asm/pil.h>
+#include <asm/estate.h>
+#include <asm/sfafsr.h>
+#include <asm/unistd.h>
+
+/* This section from from _start to sparc64_boot_end should fit into
+ * 0x0000000000404000 to 0x0000000000408000.
+ */
+ .text
+ .globl start, _start, stext, _stext
+_start:
+start:
+_stext:
+stext:
+! 0x0000000000404000
+ b sparc64_boot
+ flushw /* Flush register file. */
+
+/* This stuff has to be in sync with SILO and other potential boot loaders
+ * Fields should be kept upward compatible and whenever any change is made,
+ * HdrS version should be incremented.
+ */
+ .global root_flags, ram_flags, root_dev
+ .global sparc_ramdisk_image, sparc_ramdisk_size
+ .global sparc_ramdisk_image64
+
+ .ascii "HdrS"
+ .word LINUX_VERSION_CODE
+
+ /* History:
+ *
+ * 0x0300 : Supports being located at other than 0x4000
+ * 0x0202 : Supports kernel params string
+ * 0x0201 : Supports reboot_command
+ */
+ .half 0x0301 /* HdrS version */
+
+root_flags:
+ .half 1
+root_dev:
+ .half 0
+ram_flags:
+ .half 0
+sparc_ramdisk_image:
+ .word 0
+sparc_ramdisk_size:
+ .word 0
+ .xword reboot_command
+ .xword bootstr_info
+sparc_ramdisk_image64:
+ .xword 0
+ .word _end
+
+ /* PROM cif handler code address is in %o4. */
+sparc64_boot:
+ mov %o4, %l7
+
+ /* We need to remap the kernel. Use position independant
+ * code to remap us to KERNBASE.
+ *
+ * SILO can invoke us with 32-bit address masking enabled,
+ * so make sure that's clear.
+ */
+ rdpr %pstate, %g1
+ andn %g1, PSTATE_AM, %g1
+ wrpr %g1, 0x0, %pstate
+ ba,a,pt %xcc, 1f
+
+ .globl prom_finddev_name, prom_chosen_path, prom_root_node
+ .globl prom_getprop_name, prom_mmu_name, prom_peer_name
+ .globl prom_callmethod_name, prom_translate_name, prom_root_compatible
+ .globl prom_map_name, prom_unmap_name, prom_mmu_ihandle_cache
+ .globl prom_boot_mapped_pc, prom_boot_mapping_mode
+ .globl prom_boot_mapping_phys_high, prom_boot_mapping_phys_low
+ .globl prom_compatible_name, prom_cpu_path, prom_cpu_compatible
+ .globl is_sun4v, sun4v_chip_type, prom_set_trap_table_name
+prom_peer_name:
+ .asciz "peer"
+prom_compatible_name:
+ .asciz "compatible"
+prom_finddev_name:
+ .asciz "finddevice"
+prom_chosen_path:
+ .asciz "/chosen"
+prom_cpu_path:
+ .asciz "/cpu"
+prom_getprop_name:
+ .asciz "getprop"
+prom_mmu_name:
+ .asciz "mmu"
+prom_callmethod_name:
+ .asciz "call-method"
+prom_translate_name:
+ .asciz "translate"
+prom_map_name:
+ .asciz "map"
+prom_unmap_name:
+ .asciz "unmap"
+prom_set_trap_table_name:
+ .asciz "SUNW,set-trap-table"
+prom_sun4v_name:
+ .asciz "sun4v"
+prom_niagara_prefix:
+ .asciz "SUNW,UltraSPARC-T"
+ .align 4
+prom_root_compatible:
+ .skip 64
+prom_cpu_compatible:
+ .skip 64
+prom_root_node:
+ .word 0
+prom_mmu_ihandle_cache:
+ .word 0
+prom_boot_mapped_pc:
+ .word 0
+prom_boot_mapping_mode:
+ .word 0
+ .align 8
+prom_boot_mapping_phys_high:
+ .xword 0
+prom_boot_mapping_phys_low:
+ .xword 0
+is_sun4v:
+ .word 0
+sun4v_chip_type:
+ .word SUN4V_CHIP_INVALID
+1:
+ rd %pc, %l0
+
+ mov (1b - prom_peer_name), %l1
+ sub %l0, %l1, %l1
+ mov 0, %l2
+
+ /* prom_root_node = prom_peer(0) */
+ stx %l1, [%sp + 2047 + 128 + 0x00] ! service, "peer"
+ mov 1, %l3
+ stx %l3, [%sp + 2047 + 128 + 0x08] ! num_args, 1
+ stx %l3, [%sp + 2047 + 128 + 0x10] ! num_rets, 1
+ stx %l2, [%sp + 2047 + 128 + 0x18] ! arg1, 0
+ stx %g0, [%sp + 2047 + 128 + 0x20] ! ret1
+ call %l7
+ add %sp, (2047 + 128), %o0 ! argument array
+
+ ldx [%sp + 2047 + 128 + 0x20], %l4 ! prom root node
+ mov (1b - prom_root_node), %l1
+ sub %l0, %l1, %l1
+ stw %l4, [%l1]
+
+ mov (1b - prom_getprop_name), %l1
+ mov (1b - prom_compatible_name), %l2
+ mov (1b - prom_root_compatible), %l5
+ sub %l0, %l1, %l1
+ sub %l0, %l2, %l2
+ sub %l0, %l5, %l5
+
+ /* prom_getproperty(prom_root_node, "compatible",
+ * &prom_root_compatible, 64)
+ */
+ stx %l1, [%sp + 2047 + 128 + 0x00] ! service, "getprop"
+ mov 4, %l3
+ stx %l3, [%sp + 2047 + 128 + 0x08] ! num_args, 4
+ mov 1, %l3
+ stx %l3, [%sp + 2047 + 128 + 0x10] ! num_rets, 1
+ stx %l4, [%sp + 2047 + 128 + 0x18] ! arg1, prom_root_node
+ stx %l2, [%sp + 2047 + 128 + 0x20] ! arg2, "compatible"
+ stx %l5, [%sp + 2047 + 128 + 0x28] ! arg3, &prom_root_compatible
+ mov 64, %l3
+ stx %l3, [%sp + 2047 + 128 + 0x30] ! arg4, size
+ stx %g0, [%sp + 2047 + 128 + 0x38] ! ret1
+ call %l7
+ add %sp, (2047 + 128), %o0 ! argument array
+
+ mov (1b - prom_finddev_name), %l1
+ mov (1b - prom_chosen_path), %l2
+ mov (1b - prom_boot_mapped_pc), %l3
+ sub %l0, %l1, %l1
+ sub %l0, %l2, %l2
+ sub %l0, %l3, %l3
+ stw %l0, [%l3]
+ sub %sp, (192 + 128), %sp
+
+ /* chosen_node = prom_finddevice("/chosen") */
+ stx %l1, [%sp + 2047 + 128 + 0x00] ! service, "finddevice"
+ mov 1, %l3
+ stx %l3, [%sp + 2047 + 128 + 0x08] ! num_args, 1
+ stx %l3, [%sp + 2047 + 128 + 0x10] ! num_rets, 1
+ stx %l2, [%sp + 2047 + 128 + 0x18] ! arg1, "/chosen"
+ stx %g0, [%sp + 2047 + 128 + 0x20] ! ret1
+ call %l7
+ add %sp, (2047 + 128), %o0 ! argument array
+
+ ldx [%sp + 2047 + 128 + 0x20], %l4 ! chosen device node
+
+ mov (1b - prom_getprop_name), %l1
+ mov (1b - prom_mmu_name), %l2
+ mov (1b - prom_mmu_ihandle_cache), %l5
+ sub %l0, %l1, %l1
+ sub %l0, %l2, %l2
+ sub %l0, %l5, %l5
+
+ /* prom_mmu_ihandle_cache = prom_getint(chosen_node, "mmu") */
+ stx %l1, [%sp + 2047 + 128 + 0x00] ! service, "getprop"
+ mov 4, %l3
+ stx %l3, [%sp + 2047 + 128 + 0x08] ! num_args, 4
+ mov 1, %l3
+ stx %l3, [%sp + 2047 + 128 + 0x10] ! num_rets, 1
+ stx %l4, [%sp + 2047 + 128 + 0x18] ! arg1, chosen_node
+ stx %l2, [%sp + 2047 + 128 + 0x20] ! arg2, "mmu"
+ stx %l5, [%sp + 2047 + 128 + 0x28] ! arg3, &prom_mmu_ihandle_cache
+ mov 4, %l3
+ stx %l3, [%sp + 2047 + 128 + 0x30] ! arg4, sizeof(arg3)
+ stx %g0, [%sp + 2047 + 128 + 0x38] ! ret1
+ call %l7
+ add %sp, (2047 + 128), %o0 ! argument array
+
+ mov (1b - prom_callmethod_name), %l1
+ mov (1b - prom_translate_name), %l2
+ sub %l0, %l1, %l1
+ sub %l0, %l2, %l2
+ lduw [%l5], %l5 ! prom_mmu_ihandle_cache
+
+ stx %l1, [%sp + 2047 + 128 + 0x00] ! service, "call-method"
+ mov 3, %l3
+ stx %l3, [%sp + 2047 + 128 + 0x08] ! num_args, 3
+ mov 5, %l3
+ stx %l3, [%sp + 2047 + 128 + 0x10] ! num_rets, 5
+ stx %l2, [%sp + 2047 + 128 + 0x18] ! arg1: "translate"
+ stx %l5, [%sp + 2047 + 128 + 0x20] ! arg2: prom_mmu_ihandle_cache
+ /* PAGE align */
+ srlx %l0, 13, %l3
+ sllx %l3, 13, %l3
+ stx %l3, [%sp + 2047 + 128 + 0x28] ! arg3: vaddr, our PC
+ stx %g0, [%sp + 2047 + 128 + 0x30] ! res1
+ stx %g0, [%sp + 2047 + 128 + 0x38] ! res2
+ stx %g0, [%sp + 2047 + 128 + 0x40] ! res3
+ stx %g0, [%sp + 2047 + 128 + 0x48] ! res4
+ stx %g0, [%sp + 2047 + 128 + 0x50] ! res5
+ call %l7
+ add %sp, (2047 + 128), %o0 ! argument array
+
+ ldx [%sp + 2047 + 128 + 0x40], %l1 ! translation mode
+ mov (1b - prom_boot_mapping_mode), %l4
+ sub %l0, %l4, %l4
+ stw %l1, [%l4]
+ mov (1b - prom_boot_mapping_phys_high), %l4
+ sub %l0, %l4, %l4
+ ldx [%sp + 2047 + 128 + 0x48], %l2 ! physaddr high
+ stx %l2, [%l4 + 0x0]
+ ldx [%sp + 2047 + 128 + 0x50], %l3 ! physaddr low
+ /* 4MB align */
+ srlx %l3, 22, %l3
+ sllx %l3, 22, %l3
+ stx %l3, [%l4 + 0x8]
+
+ /* Leave service as-is, "call-method" */
+ mov 7, %l3
+ stx %l3, [%sp + 2047 + 128 + 0x08] ! num_args, 7
+ mov 1, %l3
+ stx %l3, [%sp + 2047 + 128 + 0x10] ! num_rets, 1
+ mov (1b - prom_map_name), %l3
+ sub %l0, %l3, %l3
+ stx %l3, [%sp + 2047 + 128 + 0x18] ! arg1: "map"
+ /* Leave arg2 as-is, prom_mmu_ihandle_cache */
+ mov -1, %l3
+ stx %l3, [%sp + 2047 + 128 + 0x28] ! arg3: mode (-1 default)
+ /* 4MB align the kernel image size. */
+ set (_end - KERNBASE), %l3
+ set ((4 * 1024 * 1024) - 1), %l4
+ add %l3, %l4, %l3
+ andn %l3, %l4, %l3
+ stx %l3, [%sp + 2047 + 128 + 0x30] ! arg4: roundup(ksize, 4MB)
+ sethi %hi(KERNBASE), %l3
+ stx %l3, [%sp + 2047 + 128 + 0x38] ! arg5: vaddr (KERNBASE)
+ stx %g0, [%sp + 2047 + 128 + 0x40] ! arg6: empty
+ mov (1b - prom_boot_mapping_phys_low), %l3
+ sub %l0, %l3, %l3
+ ldx [%l3], %l3
+ stx %l3, [%sp + 2047 + 128 + 0x48] ! arg7: phys addr
+ call %l7
+ add %sp, (2047 + 128), %o0 ! argument array
+
+ add %sp, (192 + 128), %sp
+
+ sethi %hi(prom_root_compatible), %g1
+ or %g1, %lo(prom_root_compatible), %g1
+ sethi %hi(prom_sun4v_name), %g7
+ or %g7, %lo(prom_sun4v_name), %g7
+ mov 5, %g3
+90: ldub [%g7], %g2
+ ldub [%g1], %g4
+ cmp %g2, %g4
+ bne,pn %icc, 80f
+ add %g7, 1, %g7
+ subcc %g3, 1, %g3
+ bne,pt %xcc, 90b
+ add %g1, 1, %g1
+
+ sethi %hi(is_sun4v), %g1
+ or %g1, %lo(is_sun4v), %g1
+ mov 1, %g7
+ stw %g7, [%g1]
+
+ /* cpu_node = prom_finddevice("/cpu") */
+ mov (1b - prom_finddev_name), %l1
+ mov (1b - prom_cpu_path), %l2
+ sub %l0, %l1, %l1
+ sub %l0, %l2, %l2
+ sub %sp, (192 + 128), %sp
+
+ stx %l1, [%sp + 2047 + 128 + 0x00] ! service, "finddevice"
+ mov 1, %l3
+ stx %l3, [%sp + 2047 + 128 + 0x08] ! num_args, 1
+ stx %l3, [%sp + 2047 + 128 + 0x10] ! num_rets, 1
+ stx %l2, [%sp + 2047 + 128 + 0x18] ! arg1, "/cpu"
+ stx %g0, [%sp + 2047 + 128 + 0x20] ! ret1
+ call %l7
+ add %sp, (2047 + 128), %o0 ! argument array
+
+ ldx [%sp + 2047 + 128 + 0x20], %l4 ! cpu device node
+
+ mov (1b - prom_getprop_name), %l1
+ mov (1b - prom_compatible_name), %l2
+ mov (1b - prom_cpu_compatible), %l5
+ sub %l0, %l1, %l1
+ sub %l0, %l2, %l2
+ sub %l0, %l5, %l5
+
+ /* prom_getproperty(cpu_node, "compatible",
+ * &prom_cpu_compatible, 64)
+ */
+ stx %l1, [%sp + 2047 + 128 + 0x00] ! service, "getprop"
+ mov 4, %l3
+ stx %l3, [%sp + 2047 + 128 + 0x08] ! num_args, 4
+ mov 1, %l3
+ stx %l3, [%sp + 2047 + 128 + 0x10] ! num_rets, 1
+ stx %l4, [%sp + 2047 + 128 + 0x18] ! arg1, cpu_node
+ stx %l2, [%sp + 2047 + 128 + 0x20] ! arg2, "compatible"
+ stx %l5, [%sp + 2047 + 128 + 0x28] ! arg3, &prom_cpu_compatible
+ mov 64, %l3
+ stx %l3, [%sp + 2047 + 128 + 0x30] ! arg4, size
+ stx %g0, [%sp + 2047 + 128 + 0x38] ! ret1
+ call %l7
+ add %sp, (2047 + 128), %o0 ! argument array
+
+ add %sp, (192 + 128), %sp
+
+ sethi %hi(prom_cpu_compatible), %g1
+ or %g1, %lo(prom_cpu_compatible), %g1
+ sethi %hi(prom_niagara_prefix), %g7
+ or %g7, %lo(prom_niagara_prefix), %g7
+ mov 17, %g3
+90: ldub [%g7], %g2
+ ldub [%g1], %g4
+ cmp %g2, %g4
+ bne,pn %icc, 4f
+ add %g7, 1, %g7
+ subcc %g3, 1, %g3
+ bne,pt %xcc, 90b
+ add %g1, 1, %g1
+
+ sethi %hi(prom_cpu_compatible), %g1
+ or %g1, %lo(prom_cpu_compatible), %g1
+ ldub [%g1 + 17], %g2
+ cmp %g2, '1'
+ be,pt %xcc, 5f
+ mov SUN4V_CHIP_NIAGARA1, %g4
+ cmp %g2, '2'
+ be,pt %xcc, 5f
+ mov SUN4V_CHIP_NIAGARA2, %g4
+4:
+ mov SUN4V_CHIP_UNKNOWN, %g4
+5: sethi %hi(sun4v_chip_type), %g2
+ or %g2, %lo(sun4v_chip_type), %g2
+ stw %g4, [%g2]
+
+80:
+ BRANCH_IF_SUN4V(g1, jump_to_sun4u_init)
+ BRANCH_IF_CHEETAH_BASE(g1,g7,cheetah_boot)
+ BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g1,g7,cheetah_plus_boot)
+ ba,pt %xcc, spitfire_boot
+ nop
+
+cheetah_plus_boot:
+ /* Preserve OBP chosen DCU and DCR register settings. */
+ ba,pt %xcc, cheetah_generic_boot
+ nop
+
+cheetah_boot:
+ mov DCR_BPE | DCR_RPE | DCR_SI | DCR_IFPOE | DCR_MS, %g1
+ wr %g1, %asr18
+
+ sethi %uhi(DCU_ME|DCU_RE|DCU_HPE|DCU_SPE|DCU_SL|DCU_WE), %g7
+ or %g7, %ulo(DCU_ME|DCU_RE|DCU_HPE|DCU_SPE|DCU_SL|DCU_WE), %g7
+ sllx %g7, 32, %g7
+ or %g7, DCU_DM | DCU_IM | DCU_DC | DCU_IC, %g7
+ stxa %g7, [%g0] ASI_DCU_CONTROL_REG
+ membar #Sync
+
+cheetah_generic_boot:
+ mov TSB_EXTENSION_P, %g3
+ stxa %g0, [%g3] ASI_DMMU
+ stxa %g0, [%g3] ASI_IMMU
+ membar #Sync
+
+ mov TSB_EXTENSION_S, %g3
+ stxa %g0, [%g3] ASI_DMMU
+ membar #Sync
+
+ mov TSB_EXTENSION_N, %g3
+ stxa %g0, [%g3] ASI_DMMU
+ stxa %g0, [%g3] ASI_IMMU
+ membar #Sync
+
+ ba,a,pt %xcc, jump_to_sun4u_init
+
+spitfire_boot:
+ /* Typically PROM has already enabled both MMU's and both on-chip
+ * caches, but we do it here anyway just to be paranoid.
+ */
+ mov (LSU_CONTROL_IC|LSU_CONTROL_DC|LSU_CONTROL_IM|LSU_CONTROL_DM), %g1
+ stxa %g1, [%g0] ASI_LSU_CONTROL
+ membar #Sync
+
+jump_to_sun4u_init:
+ /*
+ * Make sure we are in privileged mode, have address masking,
+ * using the ordinary globals and have enabled floating
+ * point.
+ *
+ * Again, typically PROM has left %pil at 13 or similar, and
+ * (PSTATE_PRIV | PSTATE_PEF | PSTATE_IE) in %pstate.
+ */
+ wrpr %g0, (PSTATE_PRIV|PSTATE_PEF|PSTATE_IE), %pstate
+ wr %g0, 0, %fprs
+
+ set sun4u_init, %g2
+ jmpl %g2 + %g0, %g0
+ nop
+
+ .section .text.init.refok
+sun4u_init:
+ BRANCH_IF_SUN4V(g1, sun4v_init)
+
+ /* Set ctx 0 */
+ mov PRIMARY_CONTEXT, %g7
+ stxa %g0, [%g7] ASI_DMMU
+ membar #Sync
+
+ mov SECONDARY_CONTEXT, %g7
+ stxa %g0, [%g7] ASI_DMMU
+ membar #Sync
+
+ ba,pt %xcc, sun4u_continue
+ nop
+
+sun4v_init:
+ /* Set ctx 0 */
+ mov PRIMARY_CONTEXT, %g7
+ stxa %g0, [%g7] ASI_MMU
+ membar #Sync
+
+ mov SECONDARY_CONTEXT, %g7
+ stxa %g0, [%g7] ASI_MMU
+ membar #Sync
+ ba,pt %xcc, niagara_tlb_fixup
+ nop
+
+sun4u_continue:
+ BRANCH_IF_ANY_CHEETAH(g1, g7, cheetah_tlb_fixup)
+
+ ba,pt %xcc, spitfire_tlb_fixup
+ nop
+
+niagara_tlb_fixup:
+ mov 3, %g2 /* Set TLB type to hypervisor. */
+ sethi %hi(tlb_type), %g1
+ stw %g2, [%g1 + %lo(tlb_type)]
+
+ /* Patch copy/clear ops. */
+ sethi %hi(sun4v_chip_type), %g1
+ lduw [%g1 + %lo(sun4v_chip_type)], %g1
+ cmp %g1, SUN4V_CHIP_NIAGARA1
+ be,pt %xcc, niagara_patch
+ cmp %g1, SUN4V_CHIP_NIAGARA2
+ be,pt %xcc, niagara2_patch
+ nop
+
+ call generic_patch_copyops
+ nop
+ call generic_patch_bzero
+ nop
+ call generic_patch_pageops
+ nop
+
+ ba,a,pt %xcc, 80f
+niagara2_patch:
+ call niagara2_patch_copyops
+ nop
+ call niagara_patch_bzero
+ nop
+ call niagara2_patch_pageops
+ nop
+
+ ba,a,pt %xcc, 80f
+
+niagara_patch:
+ call niagara_patch_copyops
+ nop
+ call niagara_patch_bzero
+ nop
+ call niagara_patch_pageops
+ nop
+
+80:
+ /* Patch TLB/cache ops. */
+ call hypervisor_patch_cachetlbops
+ nop
+
+ ba,pt %xcc, tlb_fixup_done
+ nop
+
+cheetah_tlb_fixup:
+ mov 2, %g2 /* Set TLB type to cheetah+. */
+ BRANCH_IF_CHEETAH_PLUS_OR_FOLLOWON(g1,g7,1f)
+
+ mov 1, %g2 /* Set TLB type to cheetah. */
+
+1: sethi %hi(tlb_type), %g1
+ stw %g2, [%g1 + %lo(tlb_type)]
+
+ /* Patch copy/page operations to cheetah optimized versions. */
+ call cheetah_patch_copyops
+ nop
+ call cheetah_patch_copy_page
+ nop
+ call cheetah_patch_cachetlbops
+ nop
+
+ ba,pt %xcc, tlb_fixup_done
+ nop
+
+spitfire_tlb_fixup:
+ /* Set TLB type to spitfire. */
+ mov 0, %g2
+ sethi %hi(tlb_type), %g1
+ stw %g2, [%g1 + %lo(tlb_type)]
+
+tlb_fixup_done:
+ sethi %hi(init_thread_union), %g6
+ or %g6, %lo(init_thread_union), %g6
+ ldx [%g6 + TI_TASK], %g4
+ mov %sp, %l6
+
+ wr %g0, ASI_P, %asi
+ mov 1, %g1
+ sllx %g1, THREAD_SHIFT, %g1
+ sub %g1, (STACKFRAME_SZ + STACK_BIAS), %g1
+ add %g6, %g1, %sp
+ mov 0, %fp
+
+ /* Set per-cpu pointer initially to zero, this makes
+ * the boot-cpu use the in-kernel-image per-cpu areas
+ * before setup_per_cpu_area() is invoked.
+ */
+ clr %g5
+
+ wrpr %g0, 0, %wstate
+ wrpr %g0, 0x0, %tl
+
+ /* Clear the bss */
+ sethi %hi(__bss_start), %o0
+ or %o0, %lo(__bss_start), %o0
+ sethi %hi(_end), %o1
+ or %o1, %lo(_end), %o1
+ call __bzero
+ sub %o1, %o0, %o1
+
+#ifdef CONFIG_LOCKDEP
+ /* We have this call this super early, as even prom_init can grab
+ * spinlocks and thus call into the lockdep code.
+ */
+ call lockdep_init
+ nop
+#endif
+
+ mov %l6, %o1 ! OpenPROM stack
+ call prom_init
+ mov %l7, %o0 ! OpenPROM cif handler
+
+ /* Initialize current_thread_info()->cpu as early as possible.
+ * In order to do that accurately we have to patch up the get_cpuid()
+ * assembler sequences. And that, in turn, requires that we know
+ * if we are on a Starfire box or not. While we're here, patch up
+ * the sun4v sequences as well.
+ */
+ call check_if_starfire
+ nop
+ call per_cpu_patch
+ nop
+ call sun4v_patch
+ nop
+
+#ifdef CONFIG_SMP
+ call hard_smp_processor_id
+ nop
+ cmp %o0, NR_CPUS
+ blu,pt %xcc, 1f
+ nop
+ call boot_cpu_id_too_large
+ nop
+ /* Not reached... */
+
+1:
+ /* If we boot on a non-zero cpu, all of the per-cpu
+ * variable references we make before setting up the
+ * per-cpu areas will use a bogus offset. Put a
+ * compensating factor into __per_cpu_base to handle
+ * this cleanly.
+ *
+ * What the per-cpu code calculates is:
+ *
+ * __per_cpu_base + (cpu << __per_cpu_shift)
+ *
+ * These two variables are zero initially, so to
+ * make it all cancel out to zero we need to put
+ * "0 - (cpu << 0)" into __per_cpu_base so that the
+ * above formula evaluates to zero.
+ *
+ * We cannot even perform a printk() until this stuff
+ * is setup as that calls cpu_clock() which uses
+ * per-cpu variables.
+ */
+ sub %g0, %o0, %o1
+ sethi %hi(__per_cpu_base), %o2
+ stx %o1, [%o2 + %lo(__per_cpu_base)]
+#else
+ mov 0, %o0
+#endif
+ sth %o0, [%g6 + TI_CPU]
+
+ call prom_init_report
+ nop
+
+ /* Off we go.... */
+ call start_kernel
+ nop
+ /* Not reached... */
+
+ .previous
+
+ /* This is meant to allow the sharing of this code between
+ * boot processor invocation (via setup_tba() below) and
+ * secondary processor startup (via trampoline.S). The
+ * former does use this code, the latter does not yet due
+ * to some complexities. That should be fixed up at some
+ * point.
+ *
+ * There used to be enormous complexity wrt. transferring
+ * over from the firwmare's trap table to the Linux kernel's.
+ * For example, there was a chicken & egg problem wrt. building
+ * the OBP page tables, yet needing to be on the Linux kernel
+ * trap table (to translate PAGE_OFFSET addresses) in order to
+ * do that.
+ *
+ * We now handle OBP tlb misses differently, via linear lookups
+ * into the prom_trans[] array. So that specific problem no
+ * longer exists. Yet, unfortunately there are still some issues
+ * preventing trampoline.S from using this code... ho hum.
+ */
+ .globl setup_trap_table
+setup_trap_table:
+ save %sp, -192, %sp
+
+ /* Force interrupts to be disabled. */
+ rdpr %pstate, %l0
+ andn %l0, PSTATE_IE, %o1
+ wrpr %o1, 0x0, %pstate
+ rdpr %pil, %l1
+ wrpr %g0, PIL_NORMAL_MAX, %pil
+
+ /* Make the firmware call to jump over to the Linux trap table. */
+ sethi %hi(is_sun4v), %o0
+ lduw [%o0 + %lo(is_sun4v)], %o0
+ brz,pt %o0, 1f
+ nop
+
+ TRAP_LOAD_TRAP_BLOCK(%g2, %g3)
+ add %g2, TRAP_PER_CPU_FAULT_INFO, %g2
+ stxa %g2, [%g0] ASI_SCRATCHPAD
+
+ /* Compute physical address:
+ *
+ * paddr = kern_base + (mmfsa_vaddr - KERNBASE)
+ */
+ sethi %hi(KERNBASE), %g3
+ sub %g2, %g3, %g2
+ sethi %hi(kern_base), %g3
+ ldx [%g3 + %lo(kern_base)], %g3
+ add %g2, %g3, %o1
+ sethi %hi(sparc64_ttable_tl0), %o0
+
+ set prom_set_trap_table_name, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x00]
+ mov 2, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x08]
+ mov 0, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x10]
+ stx %o0, [%sp + 2047 + 128 + 0x18]
+ stx %o1, [%sp + 2047 + 128 + 0x20]
+ sethi %hi(p1275buf), %g2
+ or %g2, %lo(p1275buf), %g2
+ ldx [%g2 + 0x08], %o1
+ call %o1
+ add %sp, (2047 + 128), %o0
+
+ ba,pt %xcc, 2f
+ nop
+
+1: sethi %hi(sparc64_ttable_tl0), %o0
+ set prom_set_trap_table_name, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x00]
+ mov 1, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x08]
+ mov 0, %g2
+ stx %g2, [%sp + 2047 + 128 + 0x10]
+ stx %o0, [%sp + 2047 + 128 + 0x18]
+ sethi %hi(p1275buf), %g2
+ or %g2, %lo(p1275buf), %g2
+ ldx [%g2 + 0x08], %o1
+ call %o1
+ add %sp, (2047 + 128), %o0
+
+ /* Start using proper page size encodings in ctx register. */
+2: sethi %hi(sparc64_kern_pri_context), %g3
+ ldx [%g3 + %lo(sparc64_kern_pri_context)], %g2
+
+ mov PRIMARY_CONTEXT, %g1
+
+661: stxa %g2, [%g1] ASI_DMMU
+ .section .sun4v_1insn_patch, "ax"
+ .word 661b
+ stxa %g2, [%g1] ASI_MMU
+ .previous
+
+ membar #Sync
+
+ BRANCH_IF_SUN4V(o2, 1f)
+
+ /* Kill PROM timer */
+ sethi %hi(0x80000000), %o2
+ sllx %o2, 32, %o2
+ wr %o2, 0, %tick_cmpr
+
+ BRANCH_IF_ANY_CHEETAH(o2, o3, 1f)
+
+ ba,pt %xcc, 2f
+ nop
+
+ /* Disable STICK_INT interrupts. */
+1:
+ sethi %hi(0x80000000), %o2
+ sllx %o2, 32, %o2
+ wr %o2, %asr25
+
+2:
+ wrpr %g0, %g0, %wstate
+
+ call init_irqwork_curcpu
+ nop
+
+ /* Now we can restore interrupt state. */
+ wrpr %l0, 0, %pstate
+ wrpr %l1, 0x0, %pil
+
+ ret
+ restore
+
+ .globl setup_tba
+setup_tba:
+ save %sp, -192, %sp
+
+ /* The boot processor is the only cpu which invokes this
+ * routine, the other cpus set things up via trampoline.S.
+ * So save the OBP trap table address here.
+ */
+ rdpr %tba, %g7
+ sethi %hi(prom_tba), %o1
+ or %o1, %lo(prom_tba), %o1
+ stx %g7, [%o1]
+
+ call setup_trap_table
+ nop
+
+ ret
+ restore
+sparc64_boot_end:
+
+#include "etrap_64.S"
+#include "rtrap_64.S"
+#include "winfixup.S"
+#include "fpu_traps.S"
+#include "ivec.S"
+#include "getsetcc.S"
+#include "utrap.S"
+#include "spiterrs.S"
+#include "cherrs.S"
+#include "misctrap.S"
+#include "syscalls.S"
+#include "helpers.S"
+#include "hvcalls.S"
+#include "sun4v_tlb_miss.S"
+#include "sun4v_ivec.S"
+#include "ktlb.S"
+#include "tsb.S"
+
+/*
+ * The following skip makes sure the trap table in ttable.S is aligned
+ * on a 32K boundary as required by the v9 specs for TBA register.
+ *
+ * We align to a 32K boundary, then we have the 32K kernel TSB,
+ * the 64K kernel 4MB TSB, and then the 32K aligned trap table.
+ */
+1:
+ .skip 0x4000 + _start - 1b
+
+! 0x0000000000408000
+
+ .globl swapper_tsb
+swapper_tsb:
+ .skip (32 * 1024)
+
+ .globl swapper_4m_tsb
+swapper_4m_tsb:
+ .skip (64 * 1024)
+
+! 0x0000000000420000
+
+ /* Some care needs to be exercised if you try to move the
+ * location of the trap table relative to other things. For
+ * one thing there are br* instructions in some of the
+ * trap table entires which branch back to code in ktlb.S
+ * Those instructions can only handle a signed 16-bit
+ * displacement.
+ *
+ * There is a binutils bug (bugzilla #4558) which causes
+ * the relocation overflow checks for such instructions to
+ * not be done correctly. So bintuils will not notice the
+ * error and will instead write junk into the relocation and
+ * you'll have an unbootable kernel.
+ */
+#include "ttable.S"
+
+! 0x0000000000428000
+
+#include "systbls_64.S"
+
+ .data
+ .align 8
+ .globl prom_tba, tlb_type
+prom_tba: .xword 0
+tlb_type: .word 0 /* Must NOT end up in BSS */
+ .section ".fixup",#alloc,#execinstr
+
+ .globl __ret_efault, __retl_efault
+__ret_efault:
+ ret
+ restore %g0, -EFAULT, %o0
+__retl_efault:
+ retl
+ mov -EFAULT, %o0
diff --git a/arch/sparc/kernel/helpers.S b/arch/sparc/kernel/helpers.S
new file mode 100644
index 000000000000..314dd0c9fc5b
--- /dev/null
+++ b/arch/sparc/kernel/helpers.S
@@ -0,0 +1,63 @@
+ .align 32
+ .globl __flushw_user
+ .type __flushw_user,#function
+__flushw_user:
+ rdpr %otherwin, %g1
+ brz,pn %g1, 2f
+ clr %g2
+1: save %sp, -128, %sp
+ rdpr %otherwin, %g1
+ brnz,pt %g1, 1b
+ add %g2, 1, %g2
+1: sub %g2, 1, %g2
+ brnz,pt %g2, 1b
+ restore %g0, %g0, %g0
+2: retl
+ nop
+ .size __flushw_user,.-__flushw_user
+
+ /* Flush %fp and %i7 to the stack for all register
+ * windows active inside of the cpu. This allows
+ * show_stack_trace() to avoid using an expensive
+ * 'flushw'.
+ */
+ .globl stack_trace_flush
+ .type stack_trace_flush,#function
+stack_trace_flush:
+ rdpr %pstate, %o0
+ wrpr %o0, PSTATE_IE, %pstate
+
+ rdpr %cwp, %g1
+ rdpr %canrestore, %g2
+ sub %g1, 1, %g3
+
+1: brz,pn %g2, 2f
+ sub %g2, 1, %g2
+ wrpr %g3, %cwp
+ stx %fp, [%sp + STACK_BIAS + RW_V9_I6]
+ stx %i7, [%sp + STACK_BIAS + RW_V9_I7]
+ ba,pt %xcc, 1b
+ sub %g3, 1, %g3
+
+2: wrpr %g1, %cwp
+ wrpr %o0, %pstate
+
+ retl
+ nop
+ .size stack_trace_flush,.-stack_trace_flush
+
+#ifdef CONFIG_SMP
+ .globl hard_smp_processor_id
+ .type hard_smp_processor_id,#function
+hard_smp_processor_id:
+#endif
+ .globl real_hard_smp_processor_id
+ .type real_hard_smp_processor_id,#function
+real_hard_smp_processor_id:
+ __GET_CPUID(%o0)
+ retl
+ nop
+#ifdef CONFIG_SMP
+ .size hard_smp_processor_id,.-hard_smp_processor_id
+#endif
+ .size real_hard_smp_processor_id,.-real_hard_smp_processor_id
diff --git a/arch/sparc/kernel/hvapi.c b/arch/sparc/kernel/hvapi.c
new file mode 100644
index 000000000000..1d272c3b5740
--- /dev/null
+++ b/arch/sparc/kernel/hvapi.c
@@ -0,0 +1,193 @@
+/* hvapi.c: Hypervisor API management.
+ *
+ * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+
+#include <asm/hypervisor.h>
+#include <asm/oplib.h>
+
+/* If the hypervisor indicates that the API setting
+ * calls are unsupported, by returning HV_EBADTRAP or
+ * HV_ENOTSUPPORTED, we assume that API groups with the
+ * PRE_API flag set are major 1 minor 0.
+ */
+struct api_info {
+ unsigned long group;
+ unsigned long major;
+ unsigned long minor;
+ unsigned int refcnt;
+ unsigned int flags;
+#define FLAG_PRE_API 0x00000001
+};
+
+static struct api_info api_table[] = {
+ { .group = HV_GRP_SUN4V, .flags = FLAG_PRE_API },
+ { .group = HV_GRP_CORE, .flags = FLAG_PRE_API },
+ { .group = HV_GRP_INTR, },
+ { .group = HV_GRP_SOFT_STATE, },
+ { .group = HV_GRP_PCI, .flags = FLAG_PRE_API },
+ { .group = HV_GRP_LDOM, },
+ { .group = HV_GRP_SVC_CHAN, .flags = FLAG_PRE_API },
+ { .group = HV_GRP_NCS, .flags = FLAG_PRE_API },
+ { .group = HV_GRP_RNG, },
+ { .group = HV_GRP_NIAG_PERF, .flags = FLAG_PRE_API },
+ { .group = HV_GRP_FIRE_PERF, },
+ { .group = HV_GRP_N2_CPU, },
+ { .group = HV_GRP_NIU, },
+ { .group = HV_GRP_VF_CPU, },
+ { .group = HV_GRP_DIAG, .flags = FLAG_PRE_API },
+};
+
+static DEFINE_SPINLOCK(hvapi_lock);
+
+static struct api_info *__get_info(unsigned long group)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(api_table); i++) {
+ if (api_table[i].group == group)
+ return &api_table[i];
+ }
+ return NULL;
+}
+
+static void __get_ref(struct api_info *p)
+{
+ p->refcnt++;
+}
+
+static void __put_ref(struct api_info *p)
+{
+ if (--p->refcnt == 0) {
+ unsigned long ignore;
+
+ sun4v_set_version(p->group, 0, 0, &ignore);
+ p->major = p->minor = 0;
+ }
+}
+
+/* Register a hypervisor API specification. It indicates the
+ * API group and desired major+minor.
+ *
+ * If an existing API registration exists '0' (success) will
+ * be returned if it is compatible with the one being registered.
+ * Otherwise a negative error code will be returned.
+ *
+ * Otherwise an attempt will be made to negotiate the requested
+ * API group/major/minor with the hypervisor, and errors returned
+ * if that does not succeed.
+ */
+int sun4v_hvapi_register(unsigned long group, unsigned long major,
+ unsigned long *minor)
+{
+ struct api_info *p;
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&hvapi_lock, flags);
+ p = __get_info(group);
+ ret = -EINVAL;
+ if (p) {
+ if (p->refcnt) {
+ ret = -EINVAL;
+ if (p->major == major) {
+ *minor = p->minor;
+ ret = 0;
+ }
+ } else {
+ unsigned long actual_minor;
+ unsigned long hv_ret;
+
+ hv_ret = sun4v_set_version(group, major, *minor,
+ &actual_minor);
+ ret = -EINVAL;
+ if (hv_ret == HV_EOK) {
+ *minor = actual_minor;
+ p->major = major;
+ p->minor = actual_minor;
+ ret = 0;
+ } else if (hv_ret == HV_EBADTRAP ||
+ hv_ret == HV_ENOTSUPPORTED) {
+ if (p->flags & FLAG_PRE_API) {
+ if (major == 1) {
+ p->major = 1;
+ p->minor = 0;
+ *minor = 0;
+ ret = 0;
+ }
+ }
+ }
+ }
+
+ if (ret == 0)
+ __get_ref(p);
+ }
+ spin_unlock_irqrestore(&hvapi_lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL(sun4v_hvapi_register);
+
+void sun4v_hvapi_unregister(unsigned long group)
+{
+ struct api_info *p;
+ unsigned long flags;
+
+ spin_lock_irqsave(&hvapi_lock, flags);
+ p = __get_info(group);
+ if (p)
+ __put_ref(p);
+ spin_unlock_irqrestore(&hvapi_lock, flags);
+}
+EXPORT_SYMBOL(sun4v_hvapi_unregister);
+
+int sun4v_hvapi_get(unsigned long group,
+ unsigned long *major,
+ unsigned long *minor)
+{
+ struct api_info *p;
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&hvapi_lock, flags);
+ ret = -EINVAL;
+ p = __get_info(group);
+ if (p && p->refcnt) {
+ *major = p->major;
+ *minor = p->minor;
+ ret = 0;
+ }
+ spin_unlock_irqrestore(&hvapi_lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL(sun4v_hvapi_get);
+
+void __init sun4v_hvapi_init(void)
+{
+ unsigned long group, major, minor;
+
+ group = HV_GRP_SUN4V;
+ major = 1;
+ minor = 0;
+ if (sun4v_hvapi_register(group, major, &minor))
+ goto bad;
+
+ group = HV_GRP_CORE;
+ major = 1;
+ minor = 1;
+ if (sun4v_hvapi_register(group, major, &minor))
+ goto bad;
+
+ return;
+
+bad:
+ prom_printf("HVAPI: Cannot register API group "
+ "%lx with major(%u) minor(%u)\n",
+ group, major, minor);
+ prom_halt();
+}
diff --git a/arch/sparc/kernel/hvcalls.S b/arch/sparc/kernel/hvcalls.S
new file mode 100644
index 000000000000..8a5f35ffb15e
--- /dev/null
+++ b/arch/sparc/kernel/hvcalls.S
@@ -0,0 +1,800 @@
+ /* %o0: devhandle
+ * %o1: devino
+ *
+ * returns %o0: sysino
+ */
+ENTRY(sun4v_devino_to_sysino)
+ mov HV_FAST_INTR_DEVINO2SYSINO, %o5
+ ta HV_FAST_TRAP
+ retl
+ mov %o1, %o0
+ENDPROC(sun4v_devino_to_sysino)
+
+ /* %o0: sysino
+ *
+ * returns %o0: intr_enabled (HV_INTR_{DISABLED,ENABLED})
+ */
+ENTRY(sun4v_intr_getenabled)
+ mov HV_FAST_INTR_GETENABLED, %o5
+ ta HV_FAST_TRAP
+ retl
+ mov %o1, %o0
+ENDPROC(sun4v_intr_getenabled)
+
+ /* %o0: sysino
+ * %o1: intr_enabled (HV_INTR_{DISABLED,ENABLED})
+ */
+ENTRY(sun4v_intr_setenabled)
+ mov HV_FAST_INTR_SETENABLED, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ENDPROC(sun4v_intr_setenabled)
+
+ /* %o0: sysino
+ *
+ * returns %o0: intr_state (HV_INTR_STATE_*)
+ */
+ENTRY(sun4v_intr_getstate)
+ mov HV_FAST_INTR_GETSTATE, %o5
+ ta HV_FAST_TRAP
+ retl
+ mov %o1, %o0
+ENDPROC(sun4v_intr_getstate)
+
+ /* %o0: sysino
+ * %o1: intr_state (HV_INTR_STATE_*)
+ */
+ENTRY(sun4v_intr_setstate)
+ mov HV_FAST_INTR_SETSTATE, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ENDPROC(sun4v_intr_setstate)
+
+ /* %o0: sysino
+ *
+ * returns %o0: cpuid
+ */
+ENTRY(sun4v_intr_gettarget)
+ mov HV_FAST_INTR_GETTARGET, %o5
+ ta HV_FAST_TRAP
+ retl
+ mov %o1, %o0
+ENDPROC(sun4v_intr_gettarget)
+
+ /* %o0: sysino
+ * %o1: cpuid
+ */
+ENTRY(sun4v_intr_settarget)
+ mov HV_FAST_INTR_SETTARGET, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ENDPROC(sun4v_intr_settarget)
+
+ /* %o0: cpuid
+ * %o1: pc
+ * %o2: rtba
+ * %o3: arg0
+ *
+ * returns %o0: status
+ */
+ENTRY(sun4v_cpu_start)
+ mov HV_FAST_CPU_START, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ENDPROC(sun4v_cpu_start)
+
+ /* %o0: cpuid
+ *
+ * returns %o0: status
+ */
+ENTRY(sun4v_cpu_stop)
+ mov HV_FAST_CPU_STOP, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ENDPROC(sun4v_cpu_stop)
+
+ /* returns %o0: status */
+ENTRY(sun4v_cpu_yield)
+ mov HV_FAST_CPU_YIELD, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ENDPROC(sun4v_cpu_yield)
+
+ /* %o0: type
+ * %o1: queue paddr
+ * %o2: num queue entries
+ *
+ * returns %o0: status
+ */
+ENTRY(sun4v_cpu_qconf)
+ mov HV_FAST_CPU_QCONF, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ENDPROC(sun4v_cpu_qconf)
+
+ /* %o0: num cpus in cpu list
+ * %o1: cpu list paddr
+ * %o2: mondo block paddr
+ *
+ * returns %o0: status
+ */
+ENTRY(sun4v_cpu_mondo_send)
+ mov HV_FAST_CPU_MONDO_SEND, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ENDPROC(sun4v_cpu_mondo_send)
+
+ /* %o0: CPU ID
+ *
+ * returns %o0: -status if status non-zero, else
+ * %o0: cpu state as HV_CPU_STATE_*
+ */
+ENTRY(sun4v_cpu_state)
+ mov HV_FAST_CPU_STATE, %o5
+ ta HV_FAST_TRAP
+ brnz,pn %o0, 1f
+ sub %g0, %o0, %o0
+ mov %o1, %o0
+1: retl
+ nop
+ENDPROC(sun4v_cpu_state)
+
+ /* %o0: virtual address
+ * %o1: must be zero
+ * %o2: TTE
+ * %o3: HV_MMU_* flags
+ *
+ * returns %o0: status
+ */
+ENTRY(sun4v_mmu_map_perm_addr)
+ mov HV_FAST_MMU_MAP_PERM_ADDR, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ENDPROC(sun4v_mmu_map_perm_addr)
+
+ /* %o0: number of TSB descriptions
+ * %o1: TSB descriptions real address
+ *
+ * returns %o0: status
+ */
+ENTRY(sun4v_mmu_tsb_ctx0)
+ mov HV_FAST_MMU_TSB_CTX0, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ENDPROC(sun4v_mmu_tsb_ctx0)
+
+ /* %o0: API group number
+ * %o1: pointer to unsigned long major number storage
+ * %o2: pointer to unsigned long minor number storage
+ *
+ * returns %o0: status
+ */
+ENTRY(sun4v_get_version)
+ mov HV_CORE_GET_VER, %o5
+ mov %o1, %o3
+ mov %o2, %o4
+ ta HV_CORE_TRAP
+ stx %o1, [%o3]
+ retl
+ stx %o2, [%o4]
+ENDPROC(sun4v_get_version)
+
+ /* %o0: API group number
+ * %o1: desired major number
+ * %o2: desired minor number
+ * %o3: pointer to unsigned long actual minor number storage
+ *
+ * returns %o0: status
+ */
+ENTRY(sun4v_set_version)
+ mov HV_CORE_SET_VER, %o5
+ mov %o3, %o4
+ ta HV_CORE_TRAP
+ retl
+ stx %o1, [%o4]
+ENDPROC(sun4v_set_version)
+
+ /* %o0: pointer to unsigned long time
+ *
+ * returns %o0: status
+ */
+ENTRY(sun4v_tod_get)
+ mov %o0, %o4
+ mov HV_FAST_TOD_GET, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%o4]
+ retl
+ nop
+ENDPROC(sun4v_tod_get)
+
+ /* %o0: time
+ *
+ * returns %o0: status
+ */
+ENTRY(sun4v_tod_set)
+ mov HV_FAST_TOD_SET, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ENDPROC(sun4v_tod_set)
+
+ /* %o0: pointer to unsigned long status
+ *
+ * returns %o0: signed character
+ */
+ENTRY(sun4v_con_getchar)
+ mov %o0, %o4
+ mov HV_FAST_CONS_GETCHAR, %o5
+ clr %o0
+ clr %o1
+ ta HV_FAST_TRAP
+ stx %o0, [%o4]
+ retl
+ sra %o1, 0, %o0
+ENDPROC(sun4v_con_getchar)
+
+ /* %o0: signed long character
+ *
+ * returns %o0: status
+ */
+ENTRY(sun4v_con_putchar)
+ mov HV_FAST_CONS_PUTCHAR, %o5
+ ta HV_FAST_TRAP
+ retl
+ sra %o0, 0, %o0
+ENDPROC(sun4v_con_putchar)
+
+ /* %o0: buffer real address
+ * %o1: buffer size
+ * %o2: pointer to unsigned long bytes_read
+ *
+ * returns %o0: status
+ */
+ENTRY(sun4v_con_read)
+ mov %o2, %o4
+ mov HV_FAST_CONS_READ, %o5
+ ta HV_FAST_TRAP
+ brnz %o0, 1f
+ cmp %o1, -1 /* break */
+ be,a,pn %icc, 1f
+ mov %o1, %o0
+ cmp %o1, -2 /* hup */
+ be,a,pn %icc, 1f
+ mov %o1, %o0
+ stx %o1, [%o4]
+1: retl
+ nop
+ENDPROC(sun4v_con_read)
+
+ /* %o0: buffer real address
+ * %o1: buffer size
+ * %o2: pointer to unsigned long bytes_written
+ *
+ * returns %o0: status
+ */
+ENTRY(sun4v_con_write)
+ mov %o2, %o4
+ mov HV_FAST_CONS_WRITE, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%o4]
+ retl
+ nop
+ENDPROC(sun4v_con_write)
+
+ /* %o0: soft state
+ * %o1: address of description string
+ *
+ * returns %o0: status
+ */
+ENTRY(sun4v_mach_set_soft_state)
+ mov HV_FAST_MACH_SET_SOFT_STATE, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ENDPROC(sun4v_mach_set_soft_state)
+
+ /* %o0: exit code
+ *
+ * Does not return.
+ */
+ENTRY(sun4v_mach_exit)
+ mov HV_FAST_MACH_EXIT, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ENDPROC(sun4v_mach_exit)
+
+ /* %o0: buffer real address
+ * %o1: buffer length
+ * %o2: pointer to unsigned long real_buf_len
+ *
+ * returns %o0: status
+ */
+ENTRY(sun4v_mach_desc)
+ mov %o2, %o4
+ mov HV_FAST_MACH_DESC, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%o4]
+ retl
+ nop
+ENDPROC(sun4v_mach_desc)
+
+ /* %o0: new timeout in milliseconds
+ * %o1: pointer to unsigned long orig_timeout
+ *
+ * returns %o0: status
+ */
+ENTRY(sun4v_mach_set_watchdog)
+ mov %o1, %o4
+ mov HV_FAST_MACH_SET_WATCHDOG, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%o4]
+ retl
+ nop
+ENDPROC(sun4v_mach_set_watchdog)
+
+ /* No inputs and does not return. */
+ENTRY(sun4v_mach_sir)
+ mov %o1, %o4
+ mov HV_FAST_MACH_SIR, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%o4]
+ retl
+ nop
+ENDPROC(sun4v_mach_sir)
+
+ /* %o0: channel
+ * %o1: ra
+ * %o2: num_entries
+ *
+ * returns %o0: status
+ */
+ENTRY(sun4v_ldc_tx_qconf)
+ mov HV_FAST_LDC_TX_QCONF, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ENDPROC(sun4v_ldc_tx_qconf)
+
+ /* %o0: channel
+ * %o1: pointer to unsigned long ra
+ * %o2: pointer to unsigned long num_entries
+ *
+ * returns %o0: status
+ */
+ENTRY(sun4v_ldc_tx_qinfo)
+ mov %o1, %g1
+ mov %o2, %g2
+ mov HV_FAST_LDC_TX_QINFO, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%g1]
+ stx %o2, [%g2]
+ retl
+ nop
+ENDPROC(sun4v_ldc_tx_qinfo)
+
+ /* %o0: channel
+ * %o1: pointer to unsigned long head_off
+ * %o2: pointer to unsigned long tail_off
+ * %o2: pointer to unsigned long chan_state
+ *
+ * returns %o0: status
+ */
+ENTRY(sun4v_ldc_tx_get_state)
+ mov %o1, %g1
+ mov %o2, %g2
+ mov %o3, %g3
+ mov HV_FAST_LDC_TX_GET_STATE, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%g1]
+ stx %o2, [%g2]
+ stx %o3, [%g3]
+ retl
+ nop
+ENDPROC(sun4v_ldc_tx_get_state)
+
+ /* %o0: channel
+ * %o1: tail_off
+ *
+ * returns %o0: status
+ */
+ENTRY(sun4v_ldc_tx_set_qtail)
+ mov HV_FAST_LDC_TX_SET_QTAIL, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ENDPROC(sun4v_ldc_tx_set_qtail)
+
+ /* %o0: channel
+ * %o1: ra
+ * %o2: num_entries
+ *
+ * returns %o0: status
+ */
+ENTRY(sun4v_ldc_rx_qconf)
+ mov HV_FAST_LDC_RX_QCONF, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ENDPROC(sun4v_ldc_rx_qconf)
+
+ /* %o0: channel
+ * %o1: pointer to unsigned long ra
+ * %o2: pointer to unsigned long num_entries
+ *
+ * returns %o0: status
+ */
+ENTRY(sun4v_ldc_rx_qinfo)
+ mov %o1, %g1
+ mov %o2, %g2
+ mov HV_FAST_LDC_RX_QINFO, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%g1]
+ stx %o2, [%g2]
+ retl
+ nop
+ENDPROC(sun4v_ldc_rx_qinfo)
+
+ /* %o0: channel
+ * %o1: pointer to unsigned long head_off
+ * %o2: pointer to unsigned long tail_off
+ * %o2: pointer to unsigned long chan_state
+ *
+ * returns %o0: status
+ */
+ENTRY(sun4v_ldc_rx_get_state)
+ mov %o1, %g1
+ mov %o2, %g2
+ mov %o3, %g3
+ mov HV_FAST_LDC_RX_GET_STATE, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%g1]
+ stx %o2, [%g2]
+ stx %o3, [%g3]
+ retl
+ nop
+ENDPROC(sun4v_ldc_rx_get_state)
+
+ /* %o0: channel
+ * %o1: head_off
+ *
+ * returns %o0: status
+ */
+ENTRY(sun4v_ldc_rx_set_qhead)
+ mov HV_FAST_LDC_RX_SET_QHEAD, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ENDPROC(sun4v_ldc_rx_set_qhead)
+
+ /* %o0: channel
+ * %o1: ra
+ * %o2: num_entries
+ *
+ * returns %o0: status
+ */
+ENTRY(sun4v_ldc_set_map_table)
+ mov HV_FAST_LDC_SET_MAP_TABLE, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ENDPROC(sun4v_ldc_set_map_table)
+
+ /* %o0: channel
+ * %o1: pointer to unsigned long ra
+ * %o2: pointer to unsigned long num_entries
+ *
+ * returns %o0: status
+ */
+ENTRY(sun4v_ldc_get_map_table)
+ mov %o1, %g1
+ mov %o2, %g2
+ mov HV_FAST_LDC_GET_MAP_TABLE, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%g1]
+ stx %o2, [%g2]
+ retl
+ nop
+ENDPROC(sun4v_ldc_get_map_table)
+
+ /* %o0: channel
+ * %o1: dir_code
+ * %o2: tgt_raddr
+ * %o3: lcl_raddr
+ * %o4: len
+ * %o5: pointer to unsigned long actual_len
+ *
+ * returns %o0: status
+ */
+ENTRY(sun4v_ldc_copy)
+ mov %o5, %g1
+ mov HV_FAST_LDC_COPY, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%g1]
+ retl
+ nop
+ENDPROC(sun4v_ldc_copy)
+
+ /* %o0: channel
+ * %o1: cookie
+ * %o2: pointer to unsigned long ra
+ * %o3: pointer to unsigned long perm
+ *
+ * returns %o0: status
+ */
+ENTRY(sun4v_ldc_mapin)
+ mov %o2, %g1
+ mov %o3, %g2
+ mov HV_FAST_LDC_MAPIN, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%g1]
+ stx %o2, [%g2]
+ retl
+ nop
+ENDPROC(sun4v_ldc_mapin)
+
+ /* %o0: ra
+ *
+ * returns %o0: status
+ */
+ENTRY(sun4v_ldc_unmap)
+ mov HV_FAST_LDC_UNMAP, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ENDPROC(sun4v_ldc_unmap)
+
+ /* %o0: channel
+ * %o1: cookie
+ * %o2: mte_cookie
+ *
+ * returns %o0: status
+ */
+ENTRY(sun4v_ldc_revoke)
+ mov HV_FAST_LDC_REVOKE, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ENDPROC(sun4v_ldc_revoke)
+
+ /* %o0: device handle
+ * %o1: device INO
+ * %o2: pointer to unsigned long cookie
+ *
+ * returns %o0: status
+ */
+ENTRY(sun4v_vintr_get_cookie)
+ mov %o2, %g1
+ mov HV_FAST_VINTR_GET_COOKIE, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%g1]
+ retl
+ nop
+ENDPROC(sun4v_vintr_get_cookie)
+
+ /* %o0: device handle
+ * %o1: device INO
+ * %o2: cookie
+ *
+ * returns %o0: status
+ */
+ENTRY(sun4v_vintr_set_cookie)
+ mov HV_FAST_VINTR_SET_COOKIE, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ENDPROC(sun4v_vintr_set_cookie)
+
+ /* %o0: device handle
+ * %o1: device INO
+ * %o2: pointer to unsigned long valid_state
+ *
+ * returns %o0: status
+ */
+ENTRY(sun4v_vintr_get_valid)
+ mov %o2, %g1
+ mov HV_FAST_VINTR_GET_VALID, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%g1]
+ retl
+ nop
+ENDPROC(sun4v_vintr_get_valid)
+
+ /* %o0: device handle
+ * %o1: device INO
+ * %o2: valid_state
+ *
+ * returns %o0: status
+ */
+ENTRY(sun4v_vintr_set_valid)
+ mov HV_FAST_VINTR_SET_VALID, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ENDPROC(sun4v_vintr_set_valid)
+
+ /* %o0: device handle
+ * %o1: device INO
+ * %o2: pointer to unsigned long state
+ *
+ * returns %o0: status
+ */
+ENTRY(sun4v_vintr_get_state)
+ mov %o2, %g1
+ mov HV_FAST_VINTR_GET_STATE, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%g1]
+ retl
+ nop
+ENDPROC(sun4v_vintr_get_state)
+
+ /* %o0: device handle
+ * %o1: device INO
+ * %o2: state
+ *
+ * returns %o0: status
+ */
+ENTRY(sun4v_vintr_set_state)
+ mov HV_FAST_VINTR_SET_STATE, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ENDPROC(sun4v_vintr_set_state)
+
+ /* %o0: device handle
+ * %o1: device INO
+ * %o2: pointer to unsigned long cpuid
+ *
+ * returns %o0: status
+ */
+ENTRY(sun4v_vintr_get_target)
+ mov %o2, %g1
+ mov HV_FAST_VINTR_GET_TARGET, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%g1]
+ retl
+ nop
+ENDPROC(sun4v_vintr_get_target)
+
+ /* %o0: device handle
+ * %o1: device INO
+ * %o2: cpuid
+ *
+ * returns %o0: status
+ */
+ENTRY(sun4v_vintr_set_target)
+ mov HV_FAST_VINTR_SET_TARGET, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ENDPROC(sun4v_vintr_set_target)
+
+ /* %o0: NCS sub-function
+ * %o1: sub-function arg real-address
+ * %o2: sub-function arg size
+ *
+ * returns %o0: status
+ */
+ENTRY(sun4v_ncs_request)
+ mov HV_FAST_NCS_REQUEST, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ENDPROC(sun4v_ncs_request)
+
+ENTRY(sun4v_svc_send)
+ save %sp, -192, %sp
+ mov %i0, %o0
+ mov %i1, %o1
+ mov %i2, %o2
+ mov HV_FAST_SVC_SEND, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%i3]
+ ret
+ restore
+ENDPROC(sun4v_svc_send)
+
+ENTRY(sun4v_svc_recv)
+ save %sp, -192, %sp
+ mov %i0, %o0
+ mov %i1, %o1
+ mov %i2, %o2
+ mov HV_FAST_SVC_RECV, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%i3]
+ ret
+ restore
+ENDPROC(sun4v_svc_recv)
+
+ENTRY(sun4v_svc_getstatus)
+ mov HV_FAST_SVC_GETSTATUS, %o5
+ mov %o1, %o4
+ ta HV_FAST_TRAP
+ stx %o1, [%o4]
+ retl
+ nop
+ENDPROC(sun4v_svc_getstatus)
+
+ENTRY(sun4v_svc_setstatus)
+ mov HV_FAST_SVC_SETSTATUS, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ENDPROC(sun4v_svc_setstatus)
+
+ENTRY(sun4v_svc_clrstatus)
+ mov HV_FAST_SVC_CLRSTATUS, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ENDPROC(sun4v_svc_clrstatus)
+
+ENTRY(sun4v_mmustat_conf)
+ mov %o1, %o4
+ mov HV_FAST_MMUSTAT_CONF, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%o4]
+ retl
+ nop
+ENDPROC(sun4v_mmustat_conf)
+
+ENTRY(sun4v_mmustat_info)
+ mov %o0, %o4
+ mov HV_FAST_MMUSTAT_INFO, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%o4]
+ retl
+ nop
+ENDPROC(sun4v_mmustat_info)
+
+ENTRY(sun4v_mmu_demap_all)
+ clr %o0
+ clr %o1
+ mov HV_MMU_ALL, %o2
+ mov HV_FAST_MMU_DEMAP_ALL, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ENDPROC(sun4v_mmu_demap_all)
+
+ENTRY(sun4v_niagara_getperf)
+ mov %o0, %o4
+ mov HV_FAST_GET_PERFREG, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%o4]
+ retl
+ nop
+ENDPROC(sun4v_niagara_getperf)
+
+ENTRY(sun4v_niagara_setperf)
+ mov HV_FAST_SET_PERFREG, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ENDPROC(sun4v_niagara_setperf)
+
+ENTRY(sun4v_niagara2_getperf)
+ mov %o0, %o4
+ mov HV_FAST_N2_GET_PERFREG, %o5
+ ta HV_FAST_TRAP
+ stx %o1, [%o4]
+ retl
+ nop
+ENDPROC(sun4v_niagara2_getperf)
+
+ENTRY(sun4v_niagara2_setperf)
+ mov HV_FAST_N2_SET_PERFREG, %o5
+ ta HV_FAST_TRAP
+ retl
+ nop
+ENDPROC(sun4v_niagara2_setperf)
diff --git a/arch/sparc/kernel/hvtramp.S b/arch/sparc/kernel/hvtramp.S
new file mode 100644
index 000000000000..9365432904d6
--- /dev/null
+++ b/arch/sparc/kernel/hvtramp.S
@@ -0,0 +1,140 @@
+/* hvtramp.S: Hypervisor start-cpu trampoline code.
+ *
+ * Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/init.h>
+
+#include <asm/thread_info.h>
+#include <asm/hypervisor.h>
+#include <asm/scratchpad.h>
+#include <asm/spitfire.h>
+#include <asm/hvtramp.h>
+#include <asm/pstate.h>
+#include <asm/ptrace.h>
+#include <asm/head.h>
+#include <asm/asi.h>
+#include <asm/pil.h>
+
+ __CPUINIT
+ .align 8
+ .globl hv_cpu_startup, hv_cpu_startup_end
+
+ /* This code executes directly out of the hypervisor
+ * with physical addressing (va==pa). %o0 contains
+ * our client argument which for Linux points to
+ * a descriptor data structure which defines the
+ * MMU entries we need to load up.
+ *
+ * After we set things up we enable the MMU and call
+ * into the kernel.
+ *
+ * First setup basic privileged cpu state.
+ */
+hv_cpu_startup:
+ SET_GL(0)
+ wrpr %g0, PIL_NORMAL_MAX, %pil
+ wrpr %g0, 0, %canrestore
+ wrpr %g0, 0, %otherwin
+ wrpr %g0, 6, %cansave
+ wrpr %g0, 6, %cleanwin
+ wrpr %g0, 0, %cwp
+ wrpr %g0, 0, %wstate
+ wrpr %g0, 0, %tl
+
+ sethi %hi(sparc64_ttable_tl0), %g1
+ wrpr %g1, %tba
+
+ mov %o0, %l0
+
+ lduw [%l0 + HVTRAMP_DESCR_CPU], %g1
+ mov SCRATCHPAD_CPUID, %g2
+ stxa %g1, [%g2] ASI_SCRATCHPAD
+
+ ldx [%l0 + HVTRAMP_DESCR_FAULT_INFO_VA], %g2
+ stxa %g2, [%g0] ASI_SCRATCHPAD
+
+ mov 0, %l1
+ lduw [%l0 + HVTRAMP_DESCR_NUM_MAPPINGS], %l2
+ add %l0, HVTRAMP_DESCR_MAPS, %l3
+
+1: ldx [%l3 + HVTRAMP_MAPPING_VADDR], %o0
+ clr %o1
+ ldx [%l3 + HVTRAMP_MAPPING_TTE], %o2
+ mov HV_MMU_IMMU | HV_MMU_DMMU, %o3
+ mov HV_FAST_MMU_MAP_PERM_ADDR, %o5
+ ta HV_FAST_TRAP
+
+ brnz,pn %o0, 80f
+ nop
+
+ add %l1, 1, %l1
+ cmp %l1, %l2
+ blt,a,pt %xcc, 1b
+ add %l3, HVTRAMP_MAPPING_SIZE, %l3
+
+ ldx [%l0 + HVTRAMP_DESCR_FAULT_INFO_PA], %o0
+ mov HV_FAST_MMU_FAULT_AREA_CONF, %o5
+ ta HV_FAST_TRAP
+
+ brnz,pn %o0, 80f
+ nop
+
+ wrpr %g0, (PSTATE_PRIV | PSTATE_PEF), %pstate
+
+ ldx [%l0 + HVTRAMP_DESCR_THREAD_REG], %l6
+
+ mov 1, %o0
+ set 1f, %o1
+ mov HV_FAST_MMU_ENABLE, %o5
+ ta HV_FAST_TRAP
+
+ ba,pt %xcc, 80f
+ nop
+
+1:
+ wr %g0, 0, %fprs
+ wr %g0, ASI_P, %asi
+
+ mov PRIMARY_CONTEXT, %g7
+ stxa %g0, [%g7] ASI_MMU
+ membar #Sync
+
+ mov SECONDARY_CONTEXT, %g7
+ stxa %g0, [%g7] ASI_MMU
+ membar #Sync
+
+ mov %l6, %g6
+ ldx [%g6 + TI_TASK], %g4
+
+ mov 1, %g5
+ sllx %g5, THREAD_SHIFT, %g5
+ sub %g5, (STACKFRAME_SZ + STACK_BIAS), %g5
+ add %g6, %g5, %sp
+ mov 0, %fp
+
+ call init_irqwork_curcpu
+ nop
+ call hard_smp_processor_id
+ nop
+
+ call sun4v_register_mondo_queues
+ nop
+
+ call init_cur_cpu_trap
+ mov %g6, %o0
+
+ wrpr %g0, (PSTATE_PRIV | PSTATE_PEF | PSTATE_IE), %pstate
+
+ call smp_callin
+ nop
+ call cpu_idle
+ mov 0, %o0
+ call cpu_panic
+ nop
+
+80: ba,pt %xcc, 80b
+ nop
+
+ .align 8
+hv_cpu_startup_end:
diff --git a/arch/sparc/kernel/idprom.c b/arch/sparc/kernel/idprom.c
index 223a6582e1e2..c16135e0c151 100644
--- a/arch/sparc/kernel/idprom.c
+++ b/arch/sparc/kernel/idprom.c
@@ -11,35 +11,37 @@
#include <asm/oplib.h>
#include <asm/idprom.h>
-#include <asm/machines.h> /* Fun with Sun released architectures. */
struct idprom *idprom;
static struct idprom idprom_buffer;
+#ifdef CONFIG_SPARC32
+#include <asm/machines.h> /* Fun with Sun released architectures. */
+
/* Here is the master table of Sun machines which use some implementation
* of the Sparc CPU and have a meaningful IDPROM machtype value that we
* know about. See asm-sparc/machines.h for empirical constants.
*/
static struct Sun_Machine_Models Sun_Machines[NUM_SUN_MACHINES] = {
/* First, Sun4's */
-{ "Sun 4/100 Series", (SM_SUN4 | SM_4_110) },
-{ "Sun 4/200 Series", (SM_SUN4 | SM_4_260) },
-{ "Sun 4/300 Series", (SM_SUN4 | SM_4_330) },
-{ "Sun 4/400 Series", (SM_SUN4 | SM_4_470) },
+{ .name = "Sun 4/100 Series", .id_machtype = (SM_SUN4 | SM_4_110) },
+{ .name = "Sun 4/200 Series", .id_machtype = (SM_SUN4 | SM_4_260) },
+{ .name = "Sun 4/300 Series", .id_machtype = (SM_SUN4 | SM_4_330) },
+{ .name = "Sun 4/400 Series", .id_machtype = (SM_SUN4 | SM_4_470) },
/* Now, Sun4c's */
-{ "Sun4c SparcStation 1", (SM_SUN4C | SM_4C_SS1) },
-{ "Sun4c SparcStation IPC", (SM_SUN4C | SM_4C_IPC) },
-{ "Sun4c SparcStation 1+", (SM_SUN4C | SM_4C_SS1PLUS) },
-{ "Sun4c SparcStation SLC", (SM_SUN4C | SM_4C_SLC) },
-{ "Sun4c SparcStation 2", (SM_SUN4C | SM_4C_SS2) },
-{ "Sun4c SparcStation ELC", (SM_SUN4C | SM_4C_ELC) },
-{ "Sun4c SparcStation IPX", (SM_SUN4C | SM_4C_IPX) },
+{ .name = "Sun4c SparcStation 1", .id_machtype = (SM_SUN4C | SM_4C_SS1) },
+{ .name = "Sun4c SparcStation IPC", .id_machtype = (SM_SUN4C | SM_4C_IPC) },
+{ .name = "Sun4c SparcStation 1+", .id_machtype = (SM_SUN4C | SM_4C_SS1PLUS) },
+{ .name = "Sun4c SparcStation SLC", .id_machtype = (SM_SUN4C | SM_4C_SLC) },
+{ .name = "Sun4c SparcStation 2", .id_machtype = (SM_SUN4C | SM_4C_SS2) },
+{ .name = "Sun4c SparcStation ELC", .id_machtype = (SM_SUN4C | SM_4C_ELC) },
+{ .name = "Sun4c SparcStation IPX", .id_machtype = (SM_SUN4C | SM_4C_IPX) },
/* Finally, early Sun4m's */
-{ "Sun4m SparcSystem600", (SM_SUN4M | SM_4M_SS60) },
-{ "Sun4m SparcStation10/20", (SM_SUN4M | SM_4M_SS50) },
-{ "Sun4m SparcStation5", (SM_SUN4M | SM_4M_SS40) },
+{ .name = "Sun4m SparcSystem600", .id_machtype = (SM_SUN4M | SM_4M_SS60) },
+{ .name = "Sun4m SparcStation10/20", .id_machtype = (SM_SUN4M | SM_4M_SS50) },
+{ .name = "Sun4m SparcStation5", .id_machtype = (SM_SUN4M | SM_4M_SS40) },
/* One entry for the OBP arch's which are sun4d, sun4e, and newer sun4m's */
-{ "Sun4M OBP based system", (SM_SUN4M_OBP | 0x0) } };
+{ .name = "Sun4M OBP based system", .id_machtype = (SM_SUN4M_OBP | 0x0) } };
static void __init display_system_type(unsigned char machtype)
{
@@ -47,21 +49,25 @@ static void __init display_system_type(unsigned char machtype)
register int i;
for (i = 0; i < NUM_SUN_MACHINES; i++) {
- if(Sun_Machines[i].id_machtype == machtype) {
+ if (Sun_Machines[i].id_machtype == machtype) {
if (machtype != (SM_SUN4M_OBP | 0x00) ||
prom_getproperty(prom_root_node, "banner-name",
sysname, sizeof(sysname)) <= 0)
- printk("TYPE: %s\n", Sun_Machines[i].name);
+ printk(KERN_WARNING "TYPE: %s\n",
+ Sun_Machines[i].name);
else
- printk("TYPE: %s\n", sysname);
+ printk(KERN_WARNING "TYPE: %s\n", sysname);
return;
}
}
- prom_printf("IDPROM: Bogus id_machtype value, 0x%x\n", machtype);
- prom_halt();
+ prom_printf("IDPROM: Warning, bogus id_machtype value, 0x%x\n", machtype);
}
-
+#else
+static void __init display_system_type(unsigned char machtype)
+{
+}
+#endif
/* Calculate the IDPROM checksum (xor of the data bytes). */
static unsigned char __init calc_idprom_cksum(struct idprom *idprom)
{
@@ -80,21 +86,14 @@ void __init idprom_init(void)
idprom = &idprom_buffer;
- if (idprom->id_format != 0x01) {
- prom_printf("IDPROM: Unknown format type!\n");
- prom_halt();
- }
+ if (idprom->id_format != 0x01)
+ prom_printf("IDPROM: Warning, unknown format type!\n");
- if (idprom->id_cksum != calc_idprom_cksum(idprom)) {
- prom_printf("IDPROM: Checksum failure (nvram=%x, calc=%x)!\n",
+ if (idprom->id_cksum != calc_idprom_cksum(idprom))
+ prom_printf("IDPROM: Warning, checksum failure (nvram=%x, calc=%x)!\n",
idprom->id_cksum, calc_idprom_cksum(idprom));
- prom_halt();
- }
display_system_type(idprom->id_machtype);
- printk("Ethernet address: %x:%x:%x:%x:%x:%x\n",
- idprom->id_ethaddr[0], idprom->id_ethaddr[1],
- idprom->id_ethaddr[2], idprom->id_ethaddr[3],
- idprom->id_ethaddr[4], idprom->id_ethaddr[5]);
+ printk(KERN_WARNING "Ethernet address: %pM\n", idprom->id_ethaddr);
}
diff --git a/arch/sparc/kernel/init_task.c b/arch/sparc/kernel/init_task.c
index 8e64ebc445ef..f28cb8278e98 100644
--- a/arch/sparc/kernel/init_task.c
+++ b/arch/sparc/kernel/init_task.c
@@ -8,7 +8,6 @@
#include <asm/pgtable.h>
#include <asm/uaccess.h>
-static struct fs_struct init_fs = INIT_FS;
static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
struct mm_struct init_mm = INIT_MM(init_mm);
@@ -23,6 +22,5 @@ EXPORT_SYMBOL(init_task);
* in etrap.S which assumes it.
*/
union thread_union init_thread_union
- __attribute__((section (".text\"\n\t#")))
- __attribute__((aligned (THREAD_SIZE)))
+ __attribute__((section (".data.init_task")))
= { INIT_THREAD_INFO(init_task) };
diff --git a/arch/sparc/kernel/iommu.c b/arch/sparc/kernel/iommu.c
new file mode 100644
index 000000000000..1cc1995531e2
--- /dev/null
+++ b/arch/sparc/kernel/iommu.c
@@ -0,0 +1,866 @@
+/* iommu.c: Generic sparc64 IOMMU support.
+ *
+ * Copyright (C) 1999, 2007, 2008 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1999, 2000 Jakub Jelinek (jakub@redhat.com)
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/iommu-helper.h>
+
+#ifdef CONFIG_PCI
+#include <linux/pci.h>
+#endif
+
+#include <asm/iommu.h>
+
+#include "iommu_common.h"
+
+#define STC_CTXMATCH_ADDR(STC, CTX) \
+ ((STC)->strbuf_ctxmatch_base + ((CTX) << 3))
+#define STC_FLUSHFLAG_INIT(STC) \
+ (*((STC)->strbuf_flushflag) = 0UL)
+#define STC_FLUSHFLAG_SET(STC) \
+ (*((STC)->strbuf_flushflag) != 0UL)
+
+#define iommu_read(__reg) \
+({ u64 __ret; \
+ __asm__ __volatile__("ldxa [%1] %2, %0" \
+ : "=r" (__ret) \
+ : "r" (__reg), "i" (ASI_PHYS_BYPASS_EC_E) \
+ : "memory"); \
+ __ret; \
+})
+#define iommu_write(__reg, __val) \
+ __asm__ __volatile__("stxa %0, [%1] %2" \
+ : /* no outputs */ \
+ : "r" (__val), "r" (__reg), \
+ "i" (ASI_PHYS_BYPASS_EC_E))
+
+/* Must be invoked under the IOMMU lock. */
+static void iommu_flushall(struct iommu *iommu)
+{
+ if (iommu->iommu_flushinv) {
+ iommu_write(iommu->iommu_flushinv, ~(u64)0);
+ } else {
+ unsigned long tag;
+ int entry;
+
+ tag = iommu->iommu_tags;
+ for (entry = 0; entry < 16; entry++) {
+ iommu_write(tag, 0);
+ tag += 8;
+ }
+
+ /* Ensure completion of previous PIO writes. */
+ (void) iommu_read(iommu->write_complete_reg);
+ }
+}
+
+#define IOPTE_CONSISTENT(CTX) \
+ (IOPTE_VALID | IOPTE_CACHE | \
+ (((CTX) << 47) & IOPTE_CONTEXT))
+
+#define IOPTE_STREAMING(CTX) \
+ (IOPTE_CONSISTENT(CTX) | IOPTE_STBUF)
+
+/* Existing mappings are never marked invalid, instead they
+ * are pointed to a dummy page.
+ */
+#define IOPTE_IS_DUMMY(iommu, iopte) \
+ ((iopte_val(*iopte) & IOPTE_PAGE) == (iommu)->dummy_page_pa)
+
+static inline void iopte_make_dummy(struct iommu *iommu, iopte_t *iopte)
+{
+ unsigned long val = iopte_val(*iopte);
+
+ val &= ~IOPTE_PAGE;
+ val |= iommu->dummy_page_pa;
+
+ iopte_val(*iopte) = val;
+}
+
+/* Based almost entirely upon the ppc64 iommu allocator. If you use the 'handle'
+ * facility it must all be done in one pass while under the iommu lock.
+ *
+ * On sun4u platforms, we only flush the IOMMU once every time we've passed
+ * over the entire page table doing allocations. Therefore we only ever advance
+ * the hint and cannot backtrack it.
+ */
+unsigned long iommu_range_alloc(struct device *dev,
+ struct iommu *iommu,
+ unsigned long npages,
+ unsigned long *handle)
+{
+ unsigned long n, end, start, limit, boundary_size;
+ struct iommu_arena *arena = &iommu->arena;
+ int pass = 0;
+
+ /* This allocator was derived from x86_64's bit string search */
+
+ /* Sanity check */
+ if (unlikely(npages == 0)) {
+ if (printk_ratelimit())
+ WARN_ON(1);
+ return DMA_ERROR_CODE;
+ }
+
+ if (handle && *handle)
+ start = *handle;
+ else
+ start = arena->hint;
+
+ limit = arena->limit;
+
+ /* The case below can happen if we have a small segment appended
+ * to a large, or when the previous alloc was at the very end of
+ * the available space. If so, go back to the beginning and flush.
+ */
+ if (start >= limit) {
+ start = 0;
+ if (iommu->flush_all)
+ iommu->flush_all(iommu);
+ }
+
+ again:
+
+ if (dev)
+ boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1,
+ 1 << IO_PAGE_SHIFT);
+ else
+ boundary_size = ALIGN(1UL << 32, 1 << IO_PAGE_SHIFT);
+
+ n = iommu_area_alloc(arena->map, limit, start, npages,
+ iommu->page_table_map_base >> IO_PAGE_SHIFT,
+ boundary_size >> IO_PAGE_SHIFT, 0);
+ if (n == -1) {
+ if (likely(pass < 1)) {
+ /* First failure, rescan from the beginning. */
+ start = 0;
+ if (iommu->flush_all)
+ iommu->flush_all(iommu);
+ pass++;
+ goto again;
+ } else {
+ /* Second failure, give up */
+ return DMA_ERROR_CODE;
+ }
+ }
+
+ end = n + npages;
+
+ arena->hint = end;
+
+ /* Update handle for SG allocations */
+ if (handle)
+ *handle = end;
+
+ return n;
+}
+
+void iommu_range_free(struct iommu *iommu, dma_addr_t dma_addr, unsigned long npages)
+{
+ struct iommu_arena *arena = &iommu->arena;
+ unsigned long entry;
+
+ entry = (dma_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT;
+
+ iommu_area_free(arena->map, entry, npages);
+}
+
+int iommu_table_init(struct iommu *iommu, int tsbsize,
+ u32 dma_offset, u32 dma_addr_mask,
+ int numa_node)
+{
+ unsigned long i, order, sz, num_tsb_entries;
+ struct page *page;
+
+ num_tsb_entries = tsbsize / sizeof(iopte_t);
+
+ /* Setup initial software IOMMU state. */
+ spin_lock_init(&iommu->lock);
+ iommu->ctx_lowest_free = 1;
+ iommu->page_table_map_base = dma_offset;
+ iommu->dma_addr_mask = dma_addr_mask;
+
+ /* Allocate and initialize the free area map. */
+ sz = num_tsb_entries / 8;
+ sz = (sz + 7UL) & ~7UL;
+ iommu->arena.map = kmalloc_node(sz, GFP_KERNEL, numa_node);
+ if (!iommu->arena.map) {
+ printk(KERN_ERR "IOMMU: Error, kmalloc(arena.map) failed.\n");
+ return -ENOMEM;
+ }
+ memset(iommu->arena.map, 0, sz);
+ iommu->arena.limit = num_tsb_entries;
+
+ if (tlb_type != hypervisor)
+ iommu->flush_all = iommu_flushall;
+
+ /* Allocate and initialize the dummy page which we
+ * set inactive IO PTEs to point to.
+ */
+ page = alloc_pages_node(numa_node, GFP_KERNEL, 0);
+ if (!page) {
+ printk(KERN_ERR "IOMMU: Error, gfp(dummy_page) failed.\n");
+ goto out_free_map;
+ }
+ iommu->dummy_page = (unsigned long) page_address(page);
+ memset((void *)iommu->dummy_page, 0, PAGE_SIZE);
+ iommu->dummy_page_pa = (unsigned long) __pa(iommu->dummy_page);
+
+ /* Now allocate and setup the IOMMU page table itself. */
+ order = get_order(tsbsize);
+ page = alloc_pages_node(numa_node, GFP_KERNEL, order);
+ if (!page) {
+ printk(KERN_ERR "IOMMU: Error, gfp(tsb) failed.\n");
+ goto out_free_dummy_page;
+ }
+ iommu->page_table = (iopte_t *)page_address(page);
+
+ for (i = 0; i < num_tsb_entries; i++)
+ iopte_make_dummy(iommu, &iommu->page_table[i]);
+
+ return 0;
+
+out_free_dummy_page:
+ free_page(iommu->dummy_page);
+ iommu->dummy_page = 0UL;
+
+out_free_map:
+ kfree(iommu->arena.map);
+ iommu->arena.map = NULL;
+
+ return -ENOMEM;
+}
+
+static inline iopte_t *alloc_npages(struct device *dev, struct iommu *iommu,
+ unsigned long npages)
+{
+ unsigned long entry;
+
+ entry = iommu_range_alloc(dev, iommu, npages, NULL);
+ if (unlikely(entry == DMA_ERROR_CODE))
+ return NULL;
+
+ return iommu->page_table + entry;
+}
+
+static int iommu_alloc_ctx(struct iommu *iommu)
+{
+ int lowest = iommu->ctx_lowest_free;
+ int sz = IOMMU_NUM_CTXS - lowest;
+ int n = find_next_zero_bit(iommu->ctx_bitmap, sz, lowest);
+
+ if (unlikely(n == sz)) {
+ n = find_next_zero_bit(iommu->ctx_bitmap, lowest, 1);
+ if (unlikely(n == lowest)) {
+ printk(KERN_WARNING "IOMMU: Ran out of contexts.\n");
+ n = 0;
+ }
+ }
+ if (n)
+ __set_bit(n, iommu->ctx_bitmap);
+
+ return n;
+}
+
+static inline void iommu_free_ctx(struct iommu *iommu, int ctx)
+{
+ if (likely(ctx)) {
+ __clear_bit(ctx, iommu->ctx_bitmap);
+ if (ctx < iommu->ctx_lowest_free)
+ iommu->ctx_lowest_free = ctx;
+ }
+}
+
+static void *dma_4u_alloc_coherent(struct device *dev, size_t size,
+ dma_addr_t *dma_addrp, gfp_t gfp)
+{
+ unsigned long flags, order, first_page;
+ struct iommu *iommu;
+ struct page *page;
+ int npages, nid;
+ iopte_t *iopte;
+ void *ret;
+
+ size = IO_PAGE_ALIGN(size);
+ order = get_order(size);
+ if (order >= 10)
+ return NULL;
+
+ nid = dev->archdata.numa_node;
+ page = alloc_pages_node(nid, gfp, order);
+ if (unlikely(!page))
+ return NULL;
+
+ first_page = (unsigned long) page_address(page);
+ memset((char *)first_page, 0, PAGE_SIZE << order);
+
+ iommu = dev->archdata.iommu;
+
+ spin_lock_irqsave(&iommu->lock, flags);
+ iopte = alloc_npages(dev, iommu, size >> IO_PAGE_SHIFT);
+ spin_unlock_irqrestore(&iommu->lock, flags);
+
+ if (unlikely(iopte == NULL)) {
+ free_pages(first_page, order);
+ return NULL;
+ }
+
+ *dma_addrp = (iommu->page_table_map_base +
+ ((iopte - iommu->page_table) << IO_PAGE_SHIFT));
+ ret = (void *) first_page;
+ npages = size >> IO_PAGE_SHIFT;
+ first_page = __pa(first_page);
+ while (npages--) {
+ iopte_val(*iopte) = (IOPTE_CONSISTENT(0UL) |
+ IOPTE_WRITE |
+ (first_page & IOPTE_PAGE));
+ iopte++;
+ first_page += IO_PAGE_SIZE;
+ }
+
+ return ret;
+}
+
+static void dma_4u_free_coherent(struct device *dev, size_t size,
+ void *cpu, dma_addr_t dvma)
+{
+ struct iommu *iommu;
+ iopte_t *iopte;
+ unsigned long flags, order, npages;
+
+ npages = IO_PAGE_ALIGN(size) >> IO_PAGE_SHIFT;
+ iommu = dev->archdata.iommu;
+ iopte = iommu->page_table +
+ ((dvma - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
+
+ spin_lock_irqsave(&iommu->lock, flags);
+
+ iommu_range_free(iommu, dvma, npages);
+
+ spin_unlock_irqrestore(&iommu->lock, flags);
+
+ order = get_order(size);
+ if (order < 10)
+ free_pages((unsigned long)cpu, order);
+}
+
+static dma_addr_t dma_4u_map_single(struct device *dev, void *ptr, size_t sz,
+ enum dma_data_direction direction)
+{
+ struct iommu *iommu;
+ struct strbuf *strbuf;
+ iopte_t *base;
+ unsigned long flags, npages, oaddr;
+ unsigned long i, base_paddr, ctx;
+ u32 bus_addr, ret;
+ unsigned long iopte_protection;
+
+ iommu = dev->archdata.iommu;
+ strbuf = dev->archdata.stc;
+
+ if (unlikely(direction == DMA_NONE))
+ goto bad_no_ctx;
+
+ oaddr = (unsigned long)ptr;
+ npages = IO_PAGE_ALIGN(oaddr + sz) - (oaddr & IO_PAGE_MASK);
+ npages >>= IO_PAGE_SHIFT;
+
+ spin_lock_irqsave(&iommu->lock, flags);
+ base = alloc_npages(dev, iommu, npages);
+ ctx = 0;
+ if (iommu->iommu_ctxflush)
+ ctx = iommu_alloc_ctx(iommu);
+ spin_unlock_irqrestore(&iommu->lock, flags);
+
+ if (unlikely(!base))
+ goto bad;
+
+ bus_addr = (iommu->page_table_map_base +
+ ((base - iommu->page_table) << IO_PAGE_SHIFT));
+ ret = bus_addr | (oaddr & ~IO_PAGE_MASK);
+ base_paddr = __pa(oaddr & IO_PAGE_MASK);
+ if (strbuf->strbuf_enabled)
+ iopte_protection = IOPTE_STREAMING(ctx);
+ else
+ iopte_protection = IOPTE_CONSISTENT(ctx);
+ if (direction != DMA_TO_DEVICE)
+ iopte_protection |= IOPTE_WRITE;
+
+ for (i = 0; i < npages; i++, base++, base_paddr += IO_PAGE_SIZE)
+ iopte_val(*base) = iopte_protection | base_paddr;
+
+ return ret;
+
+bad:
+ iommu_free_ctx(iommu, ctx);
+bad_no_ctx:
+ if (printk_ratelimit())
+ WARN_ON(1);
+ return DMA_ERROR_CODE;
+}
+
+static void strbuf_flush(struct strbuf *strbuf, struct iommu *iommu,
+ u32 vaddr, unsigned long ctx, unsigned long npages,
+ enum dma_data_direction direction)
+{
+ int limit;
+
+ if (strbuf->strbuf_ctxflush &&
+ iommu->iommu_ctxflush) {
+ unsigned long matchreg, flushreg;
+ u64 val;
+
+ flushreg = strbuf->strbuf_ctxflush;
+ matchreg = STC_CTXMATCH_ADDR(strbuf, ctx);
+
+ iommu_write(flushreg, ctx);
+ val = iommu_read(matchreg);
+ val &= 0xffff;
+ if (!val)
+ goto do_flush_sync;
+
+ while (val) {
+ if (val & 0x1)
+ iommu_write(flushreg, ctx);
+ val >>= 1;
+ }
+ val = iommu_read(matchreg);
+ if (unlikely(val)) {
+ printk(KERN_WARNING "strbuf_flush: ctx flush "
+ "timeout matchreg[%lx] ctx[%lx]\n",
+ val, ctx);
+ goto do_page_flush;
+ }
+ } else {
+ unsigned long i;
+
+ do_page_flush:
+ for (i = 0; i < npages; i++, vaddr += IO_PAGE_SIZE)
+ iommu_write(strbuf->strbuf_pflush, vaddr);
+ }
+
+do_flush_sync:
+ /* If the device could not have possibly put dirty data into
+ * the streaming cache, no flush-flag synchronization needs
+ * to be performed.
+ */
+ if (direction == DMA_TO_DEVICE)
+ return;
+
+ STC_FLUSHFLAG_INIT(strbuf);
+ iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa);
+ (void) iommu_read(iommu->write_complete_reg);
+
+ limit = 100000;
+ while (!STC_FLUSHFLAG_SET(strbuf)) {
+ limit--;
+ if (!limit)
+ break;
+ udelay(1);
+ rmb();
+ }
+ if (!limit)
+ printk(KERN_WARNING "strbuf_flush: flushflag timeout "
+ "vaddr[%08x] ctx[%lx] npages[%ld]\n",
+ vaddr, ctx, npages);
+}
+
+static void dma_4u_unmap_single(struct device *dev, dma_addr_t bus_addr,
+ size_t sz, enum dma_data_direction direction)
+{
+ struct iommu *iommu;
+ struct strbuf *strbuf;
+ iopte_t *base;
+ unsigned long flags, npages, ctx, i;
+
+ if (unlikely(direction == DMA_NONE)) {
+ if (printk_ratelimit())
+ WARN_ON(1);
+ return;
+ }
+
+ iommu = dev->archdata.iommu;
+ strbuf = dev->archdata.stc;
+
+ npages = IO_PAGE_ALIGN(bus_addr + sz) - (bus_addr & IO_PAGE_MASK);
+ npages >>= IO_PAGE_SHIFT;
+ base = iommu->page_table +
+ ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
+ bus_addr &= IO_PAGE_MASK;
+
+ spin_lock_irqsave(&iommu->lock, flags);
+
+ /* Record the context, if any. */
+ ctx = 0;
+ if (iommu->iommu_ctxflush)
+ ctx = (iopte_val(*base) & IOPTE_CONTEXT) >> 47UL;
+
+ /* Step 1: Kick data out of streaming buffers if necessary. */
+ if (strbuf->strbuf_enabled)
+ strbuf_flush(strbuf, iommu, bus_addr, ctx,
+ npages, direction);
+
+ /* Step 2: Clear out TSB entries. */
+ for (i = 0; i < npages; i++)
+ iopte_make_dummy(iommu, base + i);
+
+ iommu_range_free(iommu, bus_addr, npages);
+
+ iommu_free_ctx(iommu, ctx);
+
+ spin_unlock_irqrestore(&iommu->lock, flags);
+}
+
+static int dma_4u_map_sg(struct device *dev, struct scatterlist *sglist,
+ int nelems, enum dma_data_direction direction)
+{
+ struct scatterlist *s, *outs, *segstart;
+ unsigned long flags, handle, prot, ctx;
+ dma_addr_t dma_next = 0, dma_addr;
+ unsigned int max_seg_size;
+ unsigned long seg_boundary_size;
+ int outcount, incount, i;
+ struct strbuf *strbuf;
+ struct iommu *iommu;
+ unsigned long base_shift;
+
+ BUG_ON(direction == DMA_NONE);
+
+ iommu = dev->archdata.iommu;
+ strbuf = dev->archdata.stc;
+ if (nelems == 0 || !iommu)
+ return 0;
+
+ spin_lock_irqsave(&iommu->lock, flags);
+
+ ctx = 0;
+ if (iommu->iommu_ctxflush)
+ ctx = iommu_alloc_ctx(iommu);
+
+ if (strbuf->strbuf_enabled)
+ prot = IOPTE_STREAMING(ctx);
+ else
+ prot = IOPTE_CONSISTENT(ctx);
+ if (direction != DMA_TO_DEVICE)
+ prot |= IOPTE_WRITE;
+
+ outs = s = segstart = &sglist[0];
+ outcount = 1;
+ incount = nelems;
+ handle = 0;
+
+ /* Init first segment length for backout at failure */
+ outs->dma_length = 0;
+
+ max_seg_size = dma_get_max_seg_size(dev);
+ seg_boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1,
+ IO_PAGE_SIZE) >> IO_PAGE_SHIFT;
+ base_shift = iommu->page_table_map_base >> IO_PAGE_SHIFT;
+ for_each_sg(sglist, s, nelems, i) {
+ unsigned long paddr, npages, entry, out_entry = 0, slen;
+ iopte_t *base;
+
+ slen = s->length;
+ /* Sanity check */
+ if (slen == 0) {
+ dma_next = 0;
+ continue;
+ }
+ /* Allocate iommu entries for that segment */
+ paddr = (unsigned long) SG_ENT_PHYS_ADDRESS(s);
+ npages = iommu_num_pages(paddr, slen, IO_PAGE_SIZE);
+ entry = iommu_range_alloc(dev, iommu, npages, &handle);
+
+ /* Handle failure */
+ if (unlikely(entry == DMA_ERROR_CODE)) {
+ if (printk_ratelimit())
+ printk(KERN_INFO "iommu_alloc failed, iommu %p paddr %lx"
+ " npages %lx\n", iommu, paddr, npages);
+ goto iommu_map_failed;
+ }
+
+ base = iommu->page_table + entry;
+
+ /* Convert entry to a dma_addr_t */
+ dma_addr = iommu->page_table_map_base +
+ (entry << IO_PAGE_SHIFT);
+ dma_addr |= (s->offset & ~IO_PAGE_MASK);
+
+ /* Insert into HW table */
+ paddr &= IO_PAGE_MASK;
+ while (npages--) {
+ iopte_val(*base) = prot | paddr;
+ base++;
+ paddr += IO_PAGE_SIZE;
+ }
+
+ /* If we are in an open segment, try merging */
+ if (segstart != s) {
+ /* We cannot merge if:
+ * - allocated dma_addr isn't contiguous to previous allocation
+ */
+ if ((dma_addr != dma_next) ||
+ (outs->dma_length + s->length > max_seg_size) ||
+ (is_span_boundary(out_entry, base_shift,
+ seg_boundary_size, outs, s))) {
+ /* Can't merge: create a new segment */
+ segstart = s;
+ outcount++;
+ outs = sg_next(outs);
+ } else {
+ outs->dma_length += s->length;
+ }
+ }
+
+ if (segstart == s) {
+ /* This is a new segment, fill entries */
+ outs->dma_address = dma_addr;
+ outs->dma_length = slen;
+ out_entry = entry;
+ }
+
+ /* Calculate next page pointer for contiguous check */
+ dma_next = dma_addr + slen;
+ }
+
+ spin_unlock_irqrestore(&iommu->lock, flags);
+
+ if (outcount < incount) {
+ outs = sg_next(outs);
+ outs->dma_address = DMA_ERROR_CODE;
+ outs->dma_length = 0;
+ }
+
+ return outcount;
+
+iommu_map_failed:
+ for_each_sg(sglist, s, nelems, i) {
+ if (s->dma_length != 0) {
+ unsigned long vaddr, npages, entry, j;
+ iopte_t *base;
+
+ vaddr = s->dma_address & IO_PAGE_MASK;
+ npages = iommu_num_pages(s->dma_address, s->dma_length,
+ IO_PAGE_SIZE);
+ iommu_range_free(iommu, vaddr, npages);
+
+ entry = (vaddr - iommu->page_table_map_base)
+ >> IO_PAGE_SHIFT;
+ base = iommu->page_table + entry;
+
+ for (j = 0; j < npages; j++)
+ iopte_make_dummy(iommu, base + j);
+
+ s->dma_address = DMA_ERROR_CODE;
+ s->dma_length = 0;
+ }
+ if (s == outs)
+ break;
+ }
+ spin_unlock_irqrestore(&iommu->lock, flags);
+
+ return 0;
+}
+
+/* If contexts are being used, they are the same in all of the mappings
+ * we make for a particular SG.
+ */
+static unsigned long fetch_sg_ctx(struct iommu *iommu, struct scatterlist *sg)
+{
+ unsigned long ctx = 0;
+
+ if (iommu->iommu_ctxflush) {
+ iopte_t *base;
+ u32 bus_addr;
+
+ bus_addr = sg->dma_address & IO_PAGE_MASK;
+ base = iommu->page_table +
+ ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
+
+ ctx = (iopte_val(*base) & IOPTE_CONTEXT) >> 47UL;
+ }
+ return ctx;
+}
+
+static void dma_4u_unmap_sg(struct device *dev, struct scatterlist *sglist,
+ int nelems, enum dma_data_direction direction)
+{
+ unsigned long flags, ctx;
+ struct scatterlist *sg;
+ struct strbuf *strbuf;
+ struct iommu *iommu;
+
+ BUG_ON(direction == DMA_NONE);
+
+ iommu = dev->archdata.iommu;
+ strbuf = dev->archdata.stc;
+
+ ctx = fetch_sg_ctx(iommu, sglist);
+
+ spin_lock_irqsave(&iommu->lock, flags);
+
+ sg = sglist;
+ while (nelems--) {
+ dma_addr_t dma_handle = sg->dma_address;
+ unsigned int len = sg->dma_length;
+ unsigned long npages, entry;
+ iopte_t *base;
+ int i;
+
+ if (!len)
+ break;
+ npages = iommu_num_pages(dma_handle, len, IO_PAGE_SIZE);
+ iommu_range_free(iommu, dma_handle, npages);
+
+ entry = ((dma_handle - iommu->page_table_map_base)
+ >> IO_PAGE_SHIFT);
+ base = iommu->page_table + entry;
+
+ dma_handle &= IO_PAGE_MASK;
+ if (strbuf->strbuf_enabled)
+ strbuf_flush(strbuf, iommu, dma_handle, ctx,
+ npages, direction);
+
+ for (i = 0; i < npages; i++)
+ iopte_make_dummy(iommu, base + i);
+
+ sg = sg_next(sg);
+ }
+
+ iommu_free_ctx(iommu, ctx);
+
+ spin_unlock_irqrestore(&iommu->lock, flags);
+}
+
+static void dma_4u_sync_single_for_cpu(struct device *dev,
+ dma_addr_t bus_addr, size_t sz,
+ enum dma_data_direction direction)
+{
+ struct iommu *iommu;
+ struct strbuf *strbuf;
+ unsigned long flags, ctx, npages;
+
+ iommu = dev->archdata.iommu;
+ strbuf = dev->archdata.stc;
+
+ if (!strbuf->strbuf_enabled)
+ return;
+
+ spin_lock_irqsave(&iommu->lock, flags);
+
+ npages = IO_PAGE_ALIGN(bus_addr + sz) - (bus_addr & IO_PAGE_MASK);
+ npages >>= IO_PAGE_SHIFT;
+ bus_addr &= IO_PAGE_MASK;
+
+ /* Step 1: Record the context, if any. */
+ ctx = 0;
+ if (iommu->iommu_ctxflush &&
+ strbuf->strbuf_ctxflush) {
+ iopte_t *iopte;
+
+ iopte = iommu->page_table +
+ ((bus_addr - iommu->page_table_map_base)>>IO_PAGE_SHIFT);
+ ctx = (iopte_val(*iopte) & IOPTE_CONTEXT) >> 47UL;
+ }
+
+ /* Step 2: Kick data out of streaming buffers. */
+ strbuf_flush(strbuf, iommu, bus_addr, ctx, npages, direction);
+
+ spin_unlock_irqrestore(&iommu->lock, flags);
+}
+
+static void dma_4u_sync_sg_for_cpu(struct device *dev,
+ struct scatterlist *sglist, int nelems,
+ enum dma_data_direction direction)
+{
+ struct iommu *iommu;
+ struct strbuf *strbuf;
+ unsigned long flags, ctx, npages, i;
+ struct scatterlist *sg, *sgprv;
+ u32 bus_addr;
+
+ iommu = dev->archdata.iommu;
+ strbuf = dev->archdata.stc;
+
+ if (!strbuf->strbuf_enabled)
+ return;
+
+ spin_lock_irqsave(&iommu->lock, flags);
+
+ /* Step 1: Record the context, if any. */
+ ctx = 0;
+ if (iommu->iommu_ctxflush &&
+ strbuf->strbuf_ctxflush) {
+ iopte_t *iopte;
+
+ iopte = iommu->page_table +
+ ((sglist[0].dma_address - iommu->page_table_map_base) >> IO_PAGE_SHIFT);
+ ctx = (iopte_val(*iopte) & IOPTE_CONTEXT) >> 47UL;
+ }
+
+ /* Step 2: Kick data out of streaming buffers. */
+ bus_addr = sglist[0].dma_address & IO_PAGE_MASK;
+ sgprv = NULL;
+ for_each_sg(sglist, sg, nelems, i) {
+ if (sg->dma_length == 0)
+ break;
+ sgprv = sg;
+ }
+
+ npages = (IO_PAGE_ALIGN(sgprv->dma_address + sgprv->dma_length)
+ - bus_addr) >> IO_PAGE_SHIFT;
+ strbuf_flush(strbuf, iommu, bus_addr, ctx, npages, direction);
+
+ spin_unlock_irqrestore(&iommu->lock, flags);
+}
+
+static const struct dma_ops sun4u_dma_ops = {
+ .alloc_coherent = dma_4u_alloc_coherent,
+ .free_coherent = dma_4u_free_coherent,
+ .map_single = dma_4u_map_single,
+ .unmap_single = dma_4u_unmap_single,
+ .map_sg = dma_4u_map_sg,
+ .unmap_sg = dma_4u_unmap_sg,
+ .sync_single_for_cpu = dma_4u_sync_single_for_cpu,
+ .sync_sg_for_cpu = dma_4u_sync_sg_for_cpu,
+};
+
+const struct dma_ops *dma_ops = &sun4u_dma_ops;
+EXPORT_SYMBOL(dma_ops);
+
+int dma_supported(struct device *dev, u64 device_mask)
+{
+ struct iommu *iommu = dev->archdata.iommu;
+ u64 dma_addr_mask = iommu->dma_addr_mask;
+
+ if (device_mask >= (1UL << 32UL))
+ return 0;
+
+ if ((device_mask & dma_addr_mask) == dma_addr_mask)
+ return 1;
+
+#ifdef CONFIG_PCI
+ if (dev->bus == &pci_bus_type)
+ return pci_dma_supported(to_pci_dev(dev), device_mask);
+#endif
+
+ return 0;
+}
+EXPORT_SYMBOL(dma_supported);
+
+int dma_set_mask(struct device *dev, u64 dma_mask)
+{
+#ifdef CONFIG_PCI
+ if (dev->bus == &pci_bus_type)
+ return pci_set_dma_mask(to_pci_dev(dev), dma_mask);
+#endif
+ return -EINVAL;
+}
+EXPORT_SYMBOL(dma_set_mask);
diff --git a/arch/sparc/kernel/iommu_common.h b/arch/sparc/kernel/iommu_common.h
new file mode 100644
index 000000000000..591f5879039c
--- /dev/null
+++ b/arch/sparc/kernel/iommu_common.h
@@ -0,0 +1,59 @@
+/* iommu_common.h: UltraSparc SBUS/PCI common iommu declarations.
+ *
+ * Copyright (C) 1999, 2008 David S. Miller (davem@davemloft.net)
+ */
+
+#ifndef _IOMMU_COMMON_H
+#define _IOMMU_COMMON_H
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/scatterlist.h>
+#include <linux/device.h>
+#include <linux/iommu-helper.h>
+
+#include <asm/iommu.h>
+#include <asm/scatterlist.h>
+
+/*
+ * These give mapping size of each iommu pte/tlb.
+ */
+#define IO_PAGE_SHIFT 13
+#define IO_PAGE_SIZE (1UL << IO_PAGE_SHIFT)
+#define IO_PAGE_MASK (~(IO_PAGE_SIZE-1))
+#define IO_PAGE_ALIGN(addr) ALIGN(addr, IO_PAGE_SIZE)
+
+#define IO_TSB_ENTRIES (128*1024)
+#define IO_TSB_SIZE (IO_TSB_ENTRIES * 8)
+
+/*
+ * This is the hardwired shift in the iotlb tag/data parts.
+ */
+#define IOMMU_PAGE_SHIFT 13
+
+#define SG_ENT_PHYS_ADDRESS(SG) (__pa(sg_virt((SG))))
+
+static inline int is_span_boundary(unsigned long entry,
+ unsigned long shift,
+ unsigned long boundary_size,
+ struct scatterlist *outs,
+ struct scatterlist *sg)
+{
+ unsigned long paddr = SG_ENT_PHYS_ADDRESS(outs);
+ int nr = iommu_num_pages(paddr, outs->dma_length + sg->length,
+ IO_PAGE_SIZE);
+
+ return iommu_is_span_boundary(entry, nr, shift, boundary_size);
+}
+
+extern unsigned long iommu_range_alloc(struct device *dev,
+ struct iommu *iommu,
+ unsigned long npages,
+ unsigned long *handle);
+extern void iommu_range_free(struct iommu *iommu,
+ dma_addr_t dma_addr,
+ unsigned long npages);
+
+#endif /* _IOMMU_COMMON_H */
diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c
index 4f025b36934b..7ce14f05eb48 100644
--- a/arch/sparc/kernel/ioport.c
+++ b/arch/sparc/kernel/ioport.c
@@ -552,8 +552,8 @@ int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sgl, int nents,
/* IIep is write-through, not flushing. */
for_each_sg(sgl, sg, nents, n) {
BUG_ON(page_address(sg_page(sg)) == NULL);
- sg->dvma_address = virt_to_phys(sg_virt(sg));
- sg->dvma_length = sg->length;
+ sg->dma_address = virt_to_phys(sg_virt(sg));
+ sg->dma_length = sg->length;
}
return nents;
}
diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq_32.c
index 93e1d1c65290..f3488c45d57a 100644
--- a/arch/sparc/kernel/irq.c
+++ b/arch/sparc/kernel/irq_32.c
@@ -46,6 +46,7 @@
#include <asm/cacheflush.h>
#include <asm/irq_regs.h>
+#include "kernel.h"
#include "irq.h"
#ifdef CONFIG_SMP
@@ -592,19 +593,19 @@ EXPORT_SYMBOL(request_irq);
void disable_irq_nosync(unsigned int irq)
{
- return __disable_irq(irq);
+ __disable_irq(irq);
}
EXPORT_SYMBOL(disable_irq_nosync);
void disable_irq(unsigned int irq)
{
- return __disable_irq(irq);
+ __disable_irq(irq);
}
EXPORT_SYMBOL(disable_irq);
void enable_irq(unsigned int irq)
{
- return __enable_irq(irq);
+ __enable_irq(irq);
}
EXPORT_SYMBOL(enable_irq);
diff --git a/arch/sparc/kernel/irq_64.c b/arch/sparc/kernel/irq_64.c
new file mode 100644
index 000000000000..cab8e0286871
--- /dev/null
+++ b/arch/sparc/kernel/irq_64.c
@@ -0,0 +1,1104 @@
+/* irq.c: UltraSparc IRQ handling/init/registry.
+ *
+ * Copyright (C) 1997, 2007, 2008 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
+ * Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz)
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/linkage.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/kernel_stat.h>
+#include <linux/signal.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/random.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/bootmem.h>
+#include <linux/irq.h>
+
+#include <asm/ptrace.h>
+#include <asm/processor.h>
+#include <asm/atomic.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/iommu.h>
+#include <asm/upa.h>
+#include <asm/oplib.h>
+#include <asm/prom.h>
+#include <asm/timer.h>
+#include <asm/smp.h>
+#include <asm/starfire.h>
+#include <asm/uaccess.h>
+#include <asm/cache.h>
+#include <asm/cpudata.h>
+#include <asm/auxio.h>
+#include <asm/head.h>
+#include <asm/hypervisor.h>
+#include <asm/cacheflush.h>
+
+#include "entry.h"
+
+#define NUM_IVECS (IMAP_INR + 1)
+
+struct ino_bucket *ivector_table;
+unsigned long ivector_table_pa;
+
+/* On several sun4u processors, it is illegal to mix bypass and
+ * non-bypass accesses. Therefore we access all INO buckets
+ * using bypass accesses only.
+ */
+static unsigned long bucket_get_chain_pa(unsigned long bucket_pa)
+{
+ unsigned long ret;
+
+ __asm__ __volatile__("ldxa [%1] %2, %0"
+ : "=&r" (ret)
+ : "r" (bucket_pa +
+ offsetof(struct ino_bucket,
+ __irq_chain_pa)),
+ "i" (ASI_PHYS_USE_EC));
+
+ return ret;
+}
+
+static void bucket_clear_chain_pa(unsigned long bucket_pa)
+{
+ __asm__ __volatile__("stxa %%g0, [%0] %1"
+ : /* no outputs */
+ : "r" (bucket_pa +
+ offsetof(struct ino_bucket,
+ __irq_chain_pa)),
+ "i" (ASI_PHYS_USE_EC));
+}
+
+static unsigned int bucket_get_virt_irq(unsigned long bucket_pa)
+{
+ unsigned int ret;
+
+ __asm__ __volatile__("lduwa [%1] %2, %0"
+ : "=&r" (ret)
+ : "r" (bucket_pa +
+ offsetof(struct ino_bucket,
+ __virt_irq)),
+ "i" (ASI_PHYS_USE_EC));
+
+ return ret;
+}
+
+static void bucket_set_virt_irq(unsigned long bucket_pa,
+ unsigned int virt_irq)
+{
+ __asm__ __volatile__("stwa %0, [%1] %2"
+ : /* no outputs */
+ : "r" (virt_irq),
+ "r" (bucket_pa +
+ offsetof(struct ino_bucket,
+ __virt_irq)),
+ "i" (ASI_PHYS_USE_EC));
+}
+
+#define irq_work_pa(__cpu) &(trap_block[(__cpu)].irq_worklist_pa)
+
+static struct {
+ unsigned int dev_handle;
+ unsigned int dev_ino;
+ unsigned int in_use;
+} virt_irq_table[NR_IRQS];
+static DEFINE_SPINLOCK(virt_irq_alloc_lock);
+
+unsigned char virt_irq_alloc(unsigned int dev_handle,
+ unsigned int dev_ino)
+{
+ unsigned long flags;
+ unsigned char ent;
+
+ BUILD_BUG_ON(NR_IRQS >= 256);
+
+ spin_lock_irqsave(&virt_irq_alloc_lock, flags);
+
+ for (ent = 1; ent < NR_IRQS; ent++) {
+ if (!virt_irq_table[ent].in_use)
+ break;
+ }
+ if (ent >= NR_IRQS) {
+ printk(KERN_ERR "IRQ: Out of virtual IRQs.\n");
+ ent = 0;
+ } else {
+ virt_irq_table[ent].dev_handle = dev_handle;
+ virt_irq_table[ent].dev_ino = dev_ino;
+ virt_irq_table[ent].in_use = 1;
+ }
+
+ spin_unlock_irqrestore(&virt_irq_alloc_lock, flags);
+
+ return ent;
+}
+
+#ifdef CONFIG_PCI_MSI
+void virt_irq_free(unsigned int virt_irq)
+{
+ unsigned long flags;
+
+ if (virt_irq >= NR_IRQS)
+ return;
+
+ spin_lock_irqsave(&virt_irq_alloc_lock, flags);
+
+ virt_irq_table[virt_irq].in_use = 0;
+
+ spin_unlock_irqrestore(&virt_irq_alloc_lock, flags);
+}
+#endif
+
+/*
+ * /proc/interrupts printing:
+ */
+
+int show_interrupts(struct seq_file *p, void *v)
+{
+ int i = *(loff_t *) v, j;
+ struct irqaction * action;
+ unsigned long flags;
+
+ if (i == 0) {
+ seq_printf(p, " ");
+ for_each_online_cpu(j)
+ seq_printf(p, "CPU%d ",j);
+ seq_putc(p, '\n');
+ }
+
+ if (i < NR_IRQS) {
+ spin_lock_irqsave(&irq_desc[i].lock, flags);
+ action = irq_desc[i].action;
+ if (!action)
+ goto skip;
+ seq_printf(p, "%3d: ",i);
+#ifndef CONFIG_SMP
+ seq_printf(p, "%10u ", kstat_irqs(i));
+#else
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
+#endif
+ seq_printf(p, " %9s", irq_desc[i].chip->typename);
+ seq_printf(p, " %s", action->name);
+
+ for (action=action->next; action; action = action->next)
+ seq_printf(p, ", %s", action->name);
+
+ seq_putc(p, '\n');
+skip:
+ spin_unlock_irqrestore(&irq_desc[i].lock, flags);
+ }
+ return 0;
+}
+
+static unsigned int sun4u_compute_tid(unsigned long imap, unsigned long cpuid)
+{
+ unsigned int tid;
+
+ if (this_is_starfire) {
+ tid = starfire_translate(imap, cpuid);
+ tid <<= IMAP_TID_SHIFT;
+ tid &= IMAP_TID_UPA;
+ } else {
+ if (tlb_type == cheetah || tlb_type == cheetah_plus) {
+ unsigned long ver;
+
+ __asm__ ("rdpr %%ver, %0" : "=r" (ver));
+ if ((ver >> 32UL) == __JALAPENO_ID ||
+ (ver >> 32UL) == __SERRANO_ID) {
+ tid = cpuid << IMAP_TID_SHIFT;
+ tid &= IMAP_TID_JBUS;
+ } else {
+ unsigned int a = cpuid & 0x1f;
+ unsigned int n = (cpuid >> 5) & 0x1f;
+
+ tid = ((a << IMAP_AID_SHIFT) |
+ (n << IMAP_NID_SHIFT));
+ tid &= (IMAP_AID_SAFARI |
+ IMAP_NID_SAFARI);;
+ }
+ } else {
+ tid = cpuid << IMAP_TID_SHIFT;
+ tid &= IMAP_TID_UPA;
+ }
+ }
+
+ return tid;
+}
+
+struct irq_handler_data {
+ unsigned long iclr;
+ unsigned long imap;
+
+ void (*pre_handler)(unsigned int, void *, void *);
+ void *arg1;
+ void *arg2;
+};
+
+#ifdef CONFIG_SMP
+static int irq_choose_cpu(unsigned int virt_irq)
+{
+ cpumask_t mask = irq_desc[virt_irq].affinity;
+ int cpuid;
+
+ if (cpus_equal(mask, CPU_MASK_ALL)) {
+ static int irq_rover;
+ static DEFINE_SPINLOCK(irq_rover_lock);
+ unsigned long flags;
+
+ /* Round-robin distribution... */
+ do_round_robin:
+ spin_lock_irqsave(&irq_rover_lock, flags);
+
+ while (!cpu_online(irq_rover)) {
+ if (++irq_rover >= NR_CPUS)
+ irq_rover = 0;
+ }
+ cpuid = irq_rover;
+ do {
+ if (++irq_rover >= NR_CPUS)
+ irq_rover = 0;
+ } while (!cpu_online(irq_rover));
+
+ spin_unlock_irqrestore(&irq_rover_lock, flags);
+ } else {
+ cpumask_t tmp;
+
+ cpus_and(tmp, cpu_online_map, mask);
+
+ if (cpus_empty(tmp))
+ goto do_round_robin;
+
+ cpuid = first_cpu(tmp);
+ }
+
+ return cpuid;
+}
+#else
+static int irq_choose_cpu(unsigned int virt_irq)
+{
+ return real_hard_smp_processor_id();
+}
+#endif
+
+static void sun4u_irq_enable(unsigned int virt_irq)
+{
+ struct irq_handler_data *data = get_irq_chip_data(virt_irq);
+
+ if (likely(data)) {
+ unsigned long cpuid, imap, val;
+ unsigned int tid;
+
+ cpuid = irq_choose_cpu(virt_irq);
+ imap = data->imap;
+
+ tid = sun4u_compute_tid(imap, cpuid);
+
+ val = upa_readq(imap);
+ val &= ~(IMAP_TID_UPA | IMAP_TID_JBUS |
+ IMAP_AID_SAFARI | IMAP_NID_SAFARI);
+ val |= tid | IMAP_VALID;
+ upa_writeq(val, imap);
+ upa_writeq(ICLR_IDLE, data->iclr);
+ }
+}
+
+static void sun4u_set_affinity(unsigned int virt_irq,
+ const struct cpumask *mask)
+{
+ sun4u_irq_enable(virt_irq);
+}
+
+static void sun4u_irq_disable(unsigned int virt_irq)
+{
+ struct irq_handler_data *data = get_irq_chip_data(virt_irq);
+
+ if (likely(data)) {
+ unsigned long imap = data->imap;
+ unsigned long tmp = upa_readq(imap);
+
+ tmp &= ~IMAP_VALID;
+ upa_writeq(tmp, imap);
+ }
+}
+
+static void sun4u_irq_eoi(unsigned int virt_irq)
+{
+ struct irq_handler_data *data = get_irq_chip_data(virt_irq);
+ struct irq_desc *desc = irq_desc + virt_irq;
+
+ if (unlikely(desc->status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+ return;
+
+ if (likely(data))
+ upa_writeq(ICLR_IDLE, data->iclr);
+}
+
+static void sun4v_irq_enable(unsigned int virt_irq)
+{
+ unsigned int ino = virt_irq_table[virt_irq].dev_ino;
+ unsigned long cpuid = irq_choose_cpu(virt_irq);
+ int err;
+
+ err = sun4v_intr_settarget(ino, cpuid);
+ if (err != HV_EOK)
+ printk(KERN_ERR "sun4v_intr_settarget(%x,%lu): "
+ "err(%d)\n", ino, cpuid, err);
+ err = sun4v_intr_setstate(ino, HV_INTR_STATE_IDLE);
+ if (err != HV_EOK)
+ printk(KERN_ERR "sun4v_intr_setstate(%x): "
+ "err(%d)\n", ino, err);
+ err = sun4v_intr_setenabled(ino, HV_INTR_ENABLED);
+ if (err != HV_EOK)
+ printk(KERN_ERR "sun4v_intr_setenabled(%x): err(%d)\n",
+ ino, err);
+}
+
+static void sun4v_set_affinity(unsigned int virt_irq,
+ const struct cpumask *mask)
+{
+ unsigned int ino = virt_irq_table[virt_irq].dev_ino;
+ unsigned long cpuid = irq_choose_cpu(virt_irq);
+ int err;
+
+ err = sun4v_intr_settarget(ino, cpuid);
+ if (err != HV_EOK)
+ printk(KERN_ERR "sun4v_intr_settarget(%x,%lu): "
+ "err(%d)\n", ino, cpuid, err);
+}
+
+static void sun4v_irq_disable(unsigned int virt_irq)
+{
+ unsigned int ino = virt_irq_table[virt_irq].dev_ino;
+ int err;
+
+ err = sun4v_intr_setenabled(ino, HV_INTR_DISABLED);
+ if (err != HV_EOK)
+ printk(KERN_ERR "sun4v_intr_setenabled(%x): "
+ "err(%d)\n", ino, err);
+}
+
+static void sun4v_irq_eoi(unsigned int virt_irq)
+{
+ unsigned int ino = virt_irq_table[virt_irq].dev_ino;
+ struct irq_desc *desc = irq_desc + virt_irq;
+ int err;
+
+ if (unlikely(desc->status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+ return;
+
+ err = sun4v_intr_setstate(ino, HV_INTR_STATE_IDLE);
+ if (err != HV_EOK)
+ printk(KERN_ERR "sun4v_intr_setstate(%x): "
+ "err(%d)\n", ino, err);
+}
+
+static void sun4v_virq_enable(unsigned int virt_irq)
+{
+ unsigned long cpuid, dev_handle, dev_ino;
+ int err;
+
+ cpuid = irq_choose_cpu(virt_irq);
+
+ dev_handle = virt_irq_table[virt_irq].dev_handle;
+ dev_ino = virt_irq_table[virt_irq].dev_ino;
+
+ err = sun4v_vintr_set_target(dev_handle, dev_ino, cpuid);
+ if (err != HV_EOK)
+ printk(KERN_ERR "sun4v_vintr_set_target(%lx,%lx,%lu): "
+ "err(%d)\n",
+ dev_handle, dev_ino, cpuid, err);
+ err = sun4v_vintr_set_state(dev_handle, dev_ino,
+ HV_INTR_STATE_IDLE);
+ if (err != HV_EOK)
+ printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx,"
+ "HV_INTR_STATE_IDLE): err(%d)\n",
+ dev_handle, dev_ino, err);
+ err = sun4v_vintr_set_valid(dev_handle, dev_ino,
+ HV_INTR_ENABLED);
+ if (err != HV_EOK)
+ printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx,"
+ "HV_INTR_ENABLED): err(%d)\n",
+ dev_handle, dev_ino, err);
+}
+
+static void sun4v_virt_set_affinity(unsigned int virt_irq,
+ const struct cpumask *mask)
+{
+ unsigned long cpuid, dev_handle, dev_ino;
+ int err;
+
+ cpuid = irq_choose_cpu(virt_irq);
+
+ dev_handle = virt_irq_table[virt_irq].dev_handle;
+ dev_ino = virt_irq_table[virt_irq].dev_ino;
+
+ err = sun4v_vintr_set_target(dev_handle, dev_ino, cpuid);
+ if (err != HV_EOK)
+ printk(KERN_ERR "sun4v_vintr_set_target(%lx,%lx,%lu): "
+ "err(%d)\n",
+ dev_handle, dev_ino, cpuid, err);
+}
+
+static void sun4v_virq_disable(unsigned int virt_irq)
+{
+ unsigned long dev_handle, dev_ino;
+ int err;
+
+ dev_handle = virt_irq_table[virt_irq].dev_handle;
+ dev_ino = virt_irq_table[virt_irq].dev_ino;
+
+ err = sun4v_vintr_set_valid(dev_handle, dev_ino,
+ HV_INTR_DISABLED);
+ if (err != HV_EOK)
+ printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx,"
+ "HV_INTR_DISABLED): err(%d)\n",
+ dev_handle, dev_ino, err);
+}
+
+static void sun4v_virq_eoi(unsigned int virt_irq)
+{
+ struct irq_desc *desc = irq_desc + virt_irq;
+ unsigned long dev_handle, dev_ino;
+ int err;
+
+ if (unlikely(desc->status & (IRQ_DISABLED|IRQ_INPROGRESS)))
+ return;
+
+ dev_handle = virt_irq_table[virt_irq].dev_handle;
+ dev_ino = virt_irq_table[virt_irq].dev_ino;
+
+ err = sun4v_vintr_set_state(dev_handle, dev_ino,
+ HV_INTR_STATE_IDLE);
+ if (err != HV_EOK)
+ printk(KERN_ERR "sun4v_vintr_set_state(%lx,%lx,"
+ "HV_INTR_STATE_IDLE): err(%d)\n",
+ dev_handle, dev_ino, err);
+}
+
+static struct irq_chip sun4u_irq = {
+ .typename = "sun4u",
+ .enable = sun4u_irq_enable,
+ .disable = sun4u_irq_disable,
+ .eoi = sun4u_irq_eoi,
+ .set_affinity = sun4u_set_affinity,
+};
+
+static struct irq_chip sun4v_irq = {
+ .typename = "sun4v",
+ .enable = sun4v_irq_enable,
+ .disable = sun4v_irq_disable,
+ .eoi = sun4v_irq_eoi,
+ .set_affinity = sun4v_set_affinity,
+};
+
+static struct irq_chip sun4v_virq = {
+ .typename = "vsun4v",
+ .enable = sun4v_virq_enable,
+ .disable = sun4v_virq_disable,
+ .eoi = sun4v_virq_eoi,
+ .set_affinity = sun4v_virt_set_affinity,
+};
+
+static void pre_flow_handler(unsigned int virt_irq,
+ struct irq_desc *desc)
+{
+ struct irq_handler_data *data = get_irq_chip_data(virt_irq);
+ unsigned int ino = virt_irq_table[virt_irq].dev_ino;
+
+ data->pre_handler(ino, data->arg1, data->arg2);
+
+ handle_fasteoi_irq(virt_irq, desc);
+}
+
+void irq_install_pre_handler(int virt_irq,
+ void (*func)(unsigned int, void *, void *),
+ void *arg1, void *arg2)
+{
+ struct irq_handler_data *data = get_irq_chip_data(virt_irq);
+ struct irq_desc *desc = irq_desc + virt_irq;
+
+ data->pre_handler = func;
+ data->arg1 = arg1;
+ data->arg2 = arg2;
+
+ desc->handle_irq = pre_flow_handler;
+}
+
+unsigned int build_irq(int inofixup, unsigned long iclr, unsigned long imap)
+{
+ struct ino_bucket *bucket;
+ struct irq_handler_data *data;
+ unsigned int virt_irq;
+ int ino;
+
+ BUG_ON(tlb_type == hypervisor);
+
+ ino = (upa_readq(imap) & (IMAP_IGN | IMAP_INO)) + inofixup;
+ bucket = &ivector_table[ino];
+ virt_irq = bucket_get_virt_irq(__pa(bucket));
+ if (!virt_irq) {
+ virt_irq = virt_irq_alloc(0, ino);
+ bucket_set_virt_irq(__pa(bucket), virt_irq);
+ set_irq_chip_and_handler_name(virt_irq,
+ &sun4u_irq,
+ handle_fasteoi_irq,
+ "IVEC");
+ }
+
+ data = get_irq_chip_data(virt_irq);
+ if (unlikely(data))
+ goto out;
+
+ data = kzalloc(sizeof(struct irq_handler_data), GFP_ATOMIC);
+ if (unlikely(!data)) {
+ prom_printf("IRQ: kzalloc(irq_handler_data) failed.\n");
+ prom_halt();
+ }
+ set_irq_chip_data(virt_irq, data);
+
+ data->imap = imap;
+ data->iclr = iclr;
+
+out:
+ return virt_irq;
+}
+
+static unsigned int sun4v_build_common(unsigned long sysino,
+ struct irq_chip *chip)
+{
+ struct ino_bucket *bucket;
+ struct irq_handler_data *data;
+ unsigned int virt_irq;
+
+ BUG_ON(tlb_type != hypervisor);
+
+ bucket = &ivector_table[sysino];
+ virt_irq = bucket_get_virt_irq(__pa(bucket));
+ if (!virt_irq) {
+ virt_irq = virt_irq_alloc(0, sysino);
+ bucket_set_virt_irq(__pa(bucket), virt_irq);
+ set_irq_chip_and_handler_name(virt_irq, chip,
+ handle_fasteoi_irq,
+ "IVEC");
+ }
+
+ data = get_irq_chip_data(virt_irq);
+ if (unlikely(data))
+ goto out;
+
+ data = kzalloc(sizeof(struct irq_handler_data), GFP_ATOMIC);
+ if (unlikely(!data)) {
+ prom_printf("IRQ: kzalloc(irq_handler_data) failed.\n");
+ prom_halt();
+ }
+ set_irq_chip_data(virt_irq, data);
+
+ /* Catch accidental accesses to these things. IMAP/ICLR handling
+ * is done by hypervisor calls on sun4v platforms, not by direct
+ * register accesses.
+ */
+ data->imap = ~0UL;
+ data->iclr = ~0UL;
+
+out:
+ return virt_irq;
+}
+
+unsigned int sun4v_build_irq(u32 devhandle, unsigned int devino)
+{
+ unsigned long sysino = sun4v_devino_to_sysino(devhandle, devino);
+
+ return sun4v_build_common(sysino, &sun4v_irq);
+}
+
+unsigned int sun4v_build_virq(u32 devhandle, unsigned int devino)
+{
+ struct irq_handler_data *data;
+ unsigned long hv_err, cookie;
+ struct ino_bucket *bucket;
+ struct irq_desc *desc;
+ unsigned int virt_irq;
+
+ bucket = kzalloc(sizeof(struct ino_bucket), GFP_ATOMIC);
+ if (unlikely(!bucket))
+ return 0;
+ __flush_dcache_range((unsigned long) bucket,
+ ((unsigned long) bucket +
+ sizeof(struct ino_bucket)));
+
+ virt_irq = virt_irq_alloc(devhandle, devino);
+ bucket_set_virt_irq(__pa(bucket), virt_irq);
+
+ set_irq_chip_and_handler_name(virt_irq, &sun4v_virq,
+ handle_fasteoi_irq,
+ "IVEC");
+
+ data = kzalloc(sizeof(struct irq_handler_data), GFP_ATOMIC);
+ if (unlikely(!data))
+ return 0;
+
+ /* In order to make the LDC channel startup sequence easier,
+ * especially wrt. locking, we do not let request_irq() enable
+ * the interrupt.
+ */
+ desc = irq_desc + virt_irq;
+ desc->status |= IRQ_NOAUTOEN;
+
+ set_irq_chip_data(virt_irq, data);
+
+ /* Catch accidental accesses to these things. IMAP/ICLR handling
+ * is done by hypervisor calls on sun4v platforms, not by direct
+ * register accesses.
+ */
+ data->imap = ~0UL;
+ data->iclr = ~0UL;
+
+ cookie = ~__pa(bucket);
+ hv_err = sun4v_vintr_set_cookie(devhandle, devino, cookie);
+ if (hv_err) {
+ prom_printf("IRQ: Fatal, cannot set cookie for [%x:%x] "
+ "err=%lu\n", devhandle, devino, hv_err);
+ prom_halt();
+ }
+
+ return virt_irq;
+}
+
+void ack_bad_irq(unsigned int virt_irq)
+{
+ unsigned int ino = virt_irq_table[virt_irq].dev_ino;
+
+ if (!ino)
+ ino = 0xdeadbeef;
+
+ printk(KERN_CRIT "Unexpected IRQ from ino[%x] virt_irq[%u]\n",
+ ino, virt_irq);
+}
+
+void *hardirq_stack[NR_CPUS];
+void *softirq_stack[NR_CPUS];
+
+static __attribute__((always_inline)) void *set_hardirq_stack(void)
+{
+ void *orig_sp, *sp = hardirq_stack[smp_processor_id()];
+
+ __asm__ __volatile__("mov %%sp, %0" : "=r" (orig_sp));
+ if (orig_sp < sp ||
+ orig_sp > (sp + THREAD_SIZE)) {
+ sp += THREAD_SIZE - 192 - STACK_BIAS;
+ __asm__ __volatile__("mov %0, %%sp" : : "r" (sp));
+ }
+
+ return orig_sp;
+}
+static __attribute__((always_inline)) void restore_hardirq_stack(void *orig_sp)
+{
+ __asm__ __volatile__("mov %0, %%sp" : : "r" (orig_sp));
+}
+
+void handler_irq(int irq, struct pt_regs *regs)
+{
+ unsigned long pstate, bucket_pa;
+ struct pt_regs *old_regs;
+ void *orig_sp;
+
+ clear_softint(1 << irq);
+
+ old_regs = set_irq_regs(regs);
+ irq_enter();
+
+ /* Grab an atomic snapshot of the pending IVECs. */
+ __asm__ __volatile__("rdpr %%pstate, %0\n\t"
+ "wrpr %0, %3, %%pstate\n\t"
+ "ldx [%2], %1\n\t"
+ "stx %%g0, [%2]\n\t"
+ "wrpr %0, 0x0, %%pstate\n\t"
+ : "=&r" (pstate), "=&r" (bucket_pa)
+ : "r" (irq_work_pa(smp_processor_id())),
+ "i" (PSTATE_IE)
+ : "memory");
+
+ orig_sp = set_hardirq_stack();
+
+ while (bucket_pa) {
+ struct irq_desc *desc;
+ unsigned long next_pa;
+ unsigned int virt_irq;
+
+ next_pa = bucket_get_chain_pa(bucket_pa);
+ virt_irq = bucket_get_virt_irq(bucket_pa);
+ bucket_clear_chain_pa(bucket_pa);
+
+ desc = irq_desc + virt_irq;
+
+ desc->handle_irq(virt_irq, desc);
+
+ bucket_pa = next_pa;
+ }
+
+ restore_hardirq_stack(orig_sp);
+
+ irq_exit();
+ set_irq_regs(old_regs);
+}
+
+void do_softirq(void)
+{
+ unsigned long flags;
+
+ if (in_interrupt())
+ return;
+
+ local_irq_save(flags);
+
+ if (local_softirq_pending()) {
+ void *orig_sp, *sp = softirq_stack[smp_processor_id()];
+
+ sp += THREAD_SIZE - 192 - STACK_BIAS;
+
+ __asm__ __volatile__("mov %%sp, %0\n\t"
+ "mov %1, %%sp"
+ : "=&r" (orig_sp)
+ : "r" (sp));
+ __do_softirq();
+ __asm__ __volatile__("mov %0, %%sp"
+ : : "r" (orig_sp));
+ }
+
+ local_irq_restore(flags);
+}
+
+static void unhandled_perf_irq(struct pt_regs *regs)
+{
+ unsigned long pcr, pic;
+
+ read_pcr(pcr);
+ read_pic(pic);
+
+ write_pcr(0);
+
+ printk(KERN_EMERG "CPU %d: Got unexpected perf counter IRQ.\n",
+ smp_processor_id());
+ printk(KERN_EMERG "CPU %d: PCR[%016lx] PIC[%016lx]\n",
+ smp_processor_id(), pcr, pic);
+}
+
+/* Almost a direct copy of the powerpc PMC code. */
+static DEFINE_SPINLOCK(perf_irq_lock);
+static void *perf_irq_owner_caller; /* mostly for debugging */
+static void (*perf_irq)(struct pt_regs *regs) = unhandled_perf_irq;
+
+/* Invoked from level 15 PIL handler in trap table. */
+void perfctr_irq(int irq, struct pt_regs *regs)
+{
+ clear_softint(1 << irq);
+ perf_irq(regs);
+}
+
+int register_perfctr_intr(void (*handler)(struct pt_regs *))
+{
+ int ret;
+
+ if (!handler)
+ return -EINVAL;
+
+ spin_lock(&perf_irq_lock);
+ if (perf_irq != unhandled_perf_irq) {
+ printk(KERN_WARNING "register_perfctr_intr: "
+ "perf IRQ busy (reserved by caller %p)\n",
+ perf_irq_owner_caller);
+ ret = -EBUSY;
+ goto out;
+ }
+
+ perf_irq_owner_caller = __builtin_return_address(0);
+ perf_irq = handler;
+
+ ret = 0;
+out:
+ spin_unlock(&perf_irq_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(register_perfctr_intr);
+
+void release_perfctr_intr(void (*handler)(struct pt_regs *))
+{
+ spin_lock(&perf_irq_lock);
+ perf_irq_owner_caller = NULL;
+ perf_irq = unhandled_perf_irq;
+ spin_unlock(&perf_irq_lock);
+}
+EXPORT_SYMBOL_GPL(release_perfctr_intr);
+
+#ifdef CONFIG_HOTPLUG_CPU
+void fixup_irqs(void)
+{
+ unsigned int irq;
+
+ for (irq = 0; irq < NR_IRQS; irq++) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&irq_desc[irq].lock, flags);
+ if (irq_desc[irq].action &&
+ !(irq_desc[irq].status & IRQ_PER_CPU)) {
+ if (irq_desc[irq].chip->set_affinity)
+ irq_desc[irq].chip->set_affinity(irq,
+ &irq_desc[irq].affinity);
+ }
+ spin_unlock_irqrestore(&irq_desc[irq].lock, flags);
+ }
+
+ tick_ops->disable_irq();
+}
+#endif
+
+struct sun5_timer {
+ u64 count0;
+ u64 limit0;
+ u64 count1;
+ u64 limit1;
+};
+
+static struct sun5_timer *prom_timers;
+static u64 prom_limit0, prom_limit1;
+
+static void map_prom_timers(void)
+{
+ struct device_node *dp;
+ const unsigned int *addr;
+
+ /* PROM timer node hangs out in the top level of device siblings... */
+ dp = of_find_node_by_path("/");
+ dp = dp->child;
+ while (dp) {
+ if (!strcmp(dp->name, "counter-timer"))
+ break;
+ dp = dp->sibling;
+ }
+
+ /* Assume if node is not present, PROM uses different tick mechanism
+ * which we should not care about.
+ */
+ if (!dp) {
+ prom_timers = (struct sun5_timer *) 0;
+ return;
+ }
+
+ /* If PROM is really using this, it must be mapped by him. */
+ addr = of_get_property(dp, "address", NULL);
+ if (!addr) {
+ prom_printf("PROM does not have timer mapped, trying to continue.\n");
+ prom_timers = (struct sun5_timer *) 0;
+ return;
+ }
+ prom_timers = (struct sun5_timer *) ((unsigned long)addr[0]);
+}
+
+static void kill_prom_timer(void)
+{
+ if (!prom_timers)
+ return;
+
+ /* Save them away for later. */
+ prom_limit0 = prom_timers->limit0;
+ prom_limit1 = prom_timers->limit1;
+
+ /* Just as in sun4c/sun4m PROM uses timer which ticks at IRQ 14.
+ * We turn both off here just to be paranoid.
+ */
+ prom_timers->limit0 = 0;
+ prom_timers->limit1 = 0;
+
+ /* Wheee, eat the interrupt packet too... */
+ __asm__ __volatile__(
+" mov 0x40, %%g2\n"
+" ldxa [%%g0] %0, %%g1\n"
+" ldxa [%%g2] %1, %%g1\n"
+" stxa %%g0, [%%g0] %0\n"
+" membar #Sync\n"
+ : /* no outputs */
+ : "i" (ASI_INTR_RECEIVE), "i" (ASI_INTR_R)
+ : "g1", "g2");
+}
+
+void notrace init_irqwork_curcpu(void)
+{
+ int cpu = hard_smp_processor_id();
+
+ trap_block[cpu].irq_worklist_pa = 0UL;
+}
+
+/* Please be very careful with register_one_mondo() and
+ * sun4v_register_mondo_queues().
+ *
+ * On SMP this gets invoked from the CPU trampoline before
+ * the cpu has fully taken over the trap table from OBP,
+ * and it's kernel stack + %g6 thread register state is
+ * not fully cooked yet.
+ *
+ * Therefore you cannot make any OBP calls, not even prom_printf,
+ * from these two routines.
+ */
+static void __cpuinit register_one_mondo(unsigned long paddr, unsigned long type, unsigned long qmask)
+{
+ unsigned long num_entries = (qmask + 1) / 64;
+ unsigned long status;
+
+ status = sun4v_cpu_qconf(type, paddr, num_entries);
+ if (status != HV_EOK) {
+ prom_printf("SUN4V: sun4v_cpu_qconf(%lu:%lx:%lu) failed, "
+ "err %lu\n", type, paddr, num_entries, status);
+ prom_halt();
+ }
+}
+
+void __cpuinit notrace sun4v_register_mondo_queues(int this_cpu)
+{
+ struct trap_per_cpu *tb = &trap_block[this_cpu];
+
+ register_one_mondo(tb->cpu_mondo_pa, HV_CPU_QUEUE_CPU_MONDO,
+ tb->cpu_mondo_qmask);
+ register_one_mondo(tb->dev_mondo_pa, HV_CPU_QUEUE_DEVICE_MONDO,
+ tb->dev_mondo_qmask);
+ register_one_mondo(tb->resum_mondo_pa, HV_CPU_QUEUE_RES_ERROR,
+ tb->resum_qmask);
+ register_one_mondo(tb->nonresum_mondo_pa, HV_CPU_QUEUE_NONRES_ERROR,
+ tb->nonresum_qmask);
+}
+
+static void __init alloc_one_mondo(unsigned long *pa_ptr, unsigned long qmask)
+{
+ unsigned long size = PAGE_ALIGN(qmask + 1);
+ void *p = __alloc_bootmem(size, size, 0);
+ if (!p) {
+ prom_printf("SUN4V: Error, cannot allocate mondo queue.\n");
+ prom_halt();
+ }
+
+ *pa_ptr = __pa(p);
+}
+
+static void __init alloc_one_kbuf(unsigned long *pa_ptr, unsigned long qmask)
+{
+ unsigned long size = PAGE_ALIGN(qmask + 1);
+ void *p = __alloc_bootmem(size, size, 0);
+
+ if (!p) {
+ prom_printf("SUN4V: Error, cannot allocate kbuf page.\n");
+ prom_halt();
+ }
+
+ *pa_ptr = __pa(p);
+}
+
+static void __init init_cpu_send_mondo_info(struct trap_per_cpu *tb)
+{
+#ifdef CONFIG_SMP
+ void *page;
+
+ BUILD_BUG_ON((NR_CPUS * sizeof(u16)) > (PAGE_SIZE - 64));
+
+ page = alloc_bootmem_pages(PAGE_SIZE);
+ if (!page) {
+ prom_printf("SUN4V: Error, cannot allocate cpu mondo page.\n");
+ prom_halt();
+ }
+
+ tb->cpu_mondo_block_pa = __pa(page);
+ tb->cpu_list_pa = __pa(page + 64);
+#endif
+}
+
+/* Allocate mondo and error queues for all possible cpus. */
+static void __init sun4v_init_mondo_queues(void)
+{
+ int cpu;
+
+ for_each_possible_cpu(cpu) {
+ struct trap_per_cpu *tb = &trap_block[cpu];
+
+ alloc_one_mondo(&tb->cpu_mondo_pa, tb->cpu_mondo_qmask);
+ alloc_one_mondo(&tb->dev_mondo_pa, tb->dev_mondo_qmask);
+ alloc_one_mondo(&tb->resum_mondo_pa, tb->resum_qmask);
+ alloc_one_kbuf(&tb->resum_kernel_buf_pa, tb->resum_qmask);
+ alloc_one_mondo(&tb->nonresum_mondo_pa, tb->nonresum_qmask);
+ alloc_one_kbuf(&tb->nonresum_kernel_buf_pa,
+ tb->nonresum_qmask);
+ }
+}
+
+static void __init init_send_mondo_info(void)
+{
+ int cpu;
+
+ for_each_possible_cpu(cpu) {
+ struct trap_per_cpu *tb = &trap_block[cpu];
+
+ init_cpu_send_mondo_info(tb);
+ }
+}
+
+static struct irqaction timer_irq_action = {
+ .name = "timer",
+};
+
+/* Only invoked on boot processor. */
+void __init init_IRQ(void)
+{
+ unsigned long size;
+
+ map_prom_timers();
+ kill_prom_timer();
+
+ size = sizeof(struct ino_bucket) * NUM_IVECS;
+ ivector_table = alloc_bootmem(size);
+ if (!ivector_table) {
+ prom_printf("Fatal error, cannot allocate ivector_table\n");
+ prom_halt();
+ }
+ __flush_dcache_range((unsigned long) ivector_table,
+ ((unsigned long) ivector_table) + size);
+
+ ivector_table_pa = __pa(ivector_table);
+
+ if (tlb_type == hypervisor)
+ sun4v_init_mondo_queues();
+
+ init_send_mondo_info();
+
+ if (tlb_type == hypervisor) {
+ /* Load up the boot cpu's entries. */
+ sun4v_register_mondo_queues(hard_smp_processor_id());
+ }
+
+ /* We need to clear any IRQ's pending in the soft interrupt
+ * registers, a spurious one could be left around from the
+ * PROM timer which we just disabled.
+ */
+ clear_softint(get_softint());
+
+ /* Now that ivector table is initialized, it is safe
+ * to receive IRQ vector traps. We will normally take
+ * one or two right now, in case some device PROM used
+ * to boot us wants to speak to us. We just ignore them.
+ */
+ __asm__ __volatile__("rdpr %%pstate, %%g1\n\t"
+ "or %%g1, %0, %%g1\n\t"
+ "wrpr %%g1, 0x0, %%pstate"
+ : /* No outputs */
+ : "i" (PSTATE_IE)
+ : "g1");
+
+ irq_desc[0].action = &timer_irq_action;
+}
diff --git a/arch/sparc/kernel/itlb_miss.S b/arch/sparc/kernel/itlb_miss.S
new file mode 100644
index 000000000000..5a8377b54955
--- /dev/null
+++ b/arch/sparc/kernel/itlb_miss.S
@@ -0,0 +1,39 @@
+/* ITLB ** ICACHE line 1: Context 0 check and TSB load */
+ ldxa [%g0] ASI_IMMU_TSB_8KB_PTR, %g1 ! Get TSB 8K pointer
+ ldxa [%g0] ASI_IMMU, %g6 ! Get TAG TARGET
+ srlx %g6, 48, %g5 ! Get context
+ sllx %g6, 22, %g6 ! Zero out context
+ brz,pn %g5, kvmap_itlb ! Context 0 processing
+ srlx %g6, 22, %g6 ! Delay slot
+ TSB_LOAD_QUAD(%g1, %g4) ! Load TSB entry
+ cmp %g4, %g6 ! Compare TAG
+
+/* ITLB ** ICACHE line 2: TSB compare and TLB load */
+ bne,pn %xcc, tsb_miss_itlb ! Miss
+ mov FAULT_CODE_ITLB, %g3
+ sethi %hi(_PAGE_EXEC_4U), %g4
+ andcc %g5, %g4, %g0 ! Executable?
+ be,pn %xcc, tsb_do_fault
+ nop ! Delay slot, fill me
+ stxa %g5, [%g0] ASI_ITLB_DATA_IN ! Load TLB
+ retry ! Trap done
+
+/* ITLB ** ICACHE line 3: */
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+
+/* ITLB ** ICACHE line 4: */
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
diff --git a/arch/sparc/kernel/ivec.S b/arch/sparc/kernel/ivec.S
new file mode 100644
index 000000000000..d29f92ebca5e
--- /dev/null
+++ b/arch/sparc/kernel/ivec.S
@@ -0,0 +1,51 @@
+ /* The registers for cross calls will be:
+ *
+ * DATA 0: [low 32-bits] Address of function to call, jmp to this
+ * [high 32-bits] MMU Context Argument 0, place in %g5
+ * DATA 1: Address Argument 1, place in %g1
+ * DATA 2: Address Argument 2, place in %g7
+ *
+ * With this method we can do most of the cross-call tlb/cache
+ * flushing very quickly.
+ */
+ .align 32
+ .globl do_ivec
+ .type do_ivec,#function
+do_ivec:
+ mov 0x40, %g3
+ ldxa [%g3 + %g0] ASI_INTR_R, %g3
+ sethi %hi(KERNBASE), %g4
+ cmp %g3, %g4
+ bgeu,pn %xcc, do_ivec_xcall
+ srlx %g3, 32, %g5
+ stxa %g0, [%g0] ASI_INTR_RECEIVE
+ membar #Sync
+
+ sethi %hi(ivector_table_pa), %g2
+ ldx [%g2 + %lo(ivector_table_pa)], %g2
+ sllx %g3, 4, %g3
+ add %g2, %g3, %g3
+
+ TRAP_LOAD_IRQ_WORK_PA(%g6, %g1)
+
+ ldx [%g6], %g5
+ stxa %g5, [%g3] ASI_PHYS_USE_EC
+ stx %g3, [%g6]
+ wr %g0, 1 << PIL_DEVICE_IRQ, %set_softint
+ retry
+do_ivec_xcall:
+ mov 0x50, %g1
+ ldxa [%g1 + %g0] ASI_INTR_R, %g1
+ srl %g3, 0, %g3
+
+ mov 0x60, %g7
+ ldxa [%g7 + %g0] ASI_INTR_R, %g7
+ stxa %g0, [%g0] ASI_INTR_RECEIVE
+ membar #Sync
+ ba,pt %xcc, 1f
+ nop
+
+ .align 32
+1: jmpl %g3, %g0
+ nop
+ .size do_ivec,.-do_ivec
diff --git a/arch/sparc/kernel/kernel.h b/arch/sparc/kernel/kernel.h
new file mode 100644
index 000000000000..81a972e8d8ea
--- /dev/null
+++ b/arch/sparc/kernel/kernel.h
@@ -0,0 +1,31 @@
+#ifndef __SPARC_KERNEL_H
+#define __SPARC_KERNEL_H
+
+#include <linux/interrupt.h>
+
+/* cpu.c */
+extern const char *sparc_cpu_type;
+extern const char *sparc_fpu_type;
+
+extern unsigned int fsr_storage;
+
+#ifdef CONFIG_SPARC32
+/* cpu.c */
+extern void cpu_probe(void);
+
+/* traps_32.c */
+extern void handle_hw_divzero(struct pt_regs *regs, unsigned long pc,
+ unsigned long npc, unsigned long psr);
+/* muldiv.c */
+extern int do_user_muldiv (struct pt_regs *, unsigned long);
+
+/* irq_32.c */
+extern struct irqaction static_irqaction[];
+extern int static_irq_count;
+extern spinlock_t irq_action_lock;
+
+extern void unexpected_irq(int irq, void *dev_id, struct pt_regs * regs);
+
+#else /* CONFIG_SPARC32 */
+#endif /* CONFIG_SPARC32 */
+#endif /* !(__SPARC_KERNEL_H) */
diff --git a/arch/sparc/kernel/kgdb.c b/arch/sparc/kernel/kgdb_32.c
index 757805ce02ee..757805ce02ee 100644
--- a/arch/sparc/kernel/kgdb.c
+++ b/arch/sparc/kernel/kgdb_32.c
diff --git a/arch/sparc/kernel/kgdb_64.c b/arch/sparc/kernel/kgdb_64.c
new file mode 100644
index 000000000000..fefbe6dc51be
--- /dev/null
+++ b/arch/sparc/kernel/kgdb_64.c
@@ -0,0 +1,186 @@
+/* kgdb.c: KGDB support for 64-bit sparc.
+ *
+ * Copyright (C) 2008 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kgdb.h>
+#include <linux/kdebug.h>
+
+#include <asm/kdebug.h>
+#include <asm/ptrace.h>
+#include <asm/irq.h>
+
+void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+ struct reg_window *win;
+ int i;
+
+ gdb_regs[GDB_G0] = 0;
+ for (i = 0; i < 15; i++)
+ gdb_regs[GDB_G1 + i] = regs->u_regs[UREG_G1 + i];
+
+ win = (struct reg_window *) (regs->u_regs[UREG_FP] + STACK_BIAS);
+ for (i = 0; i < 8; i++)
+ gdb_regs[GDB_L0 + i] = win->locals[i];
+ for (i = 0; i < 8; i++)
+ gdb_regs[GDB_I0 + i] = win->ins[i];
+
+ for (i = GDB_F0; i <= GDB_F62; i++)
+ gdb_regs[i] = 0;
+
+ gdb_regs[GDB_PC] = regs->tpc;
+ gdb_regs[GDB_NPC] = regs->tnpc;
+ gdb_regs[GDB_STATE] = regs->tstate;
+ gdb_regs[GDB_FSR] = 0;
+ gdb_regs[GDB_FPRS] = 0;
+ gdb_regs[GDB_Y] = regs->y;
+}
+
+void sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p)
+{
+ struct thread_info *t = task_thread_info(p);
+ extern unsigned int switch_to_pc;
+ extern unsigned int ret_from_syscall;
+ struct reg_window *win;
+ unsigned long pc, cwp;
+ int i;
+
+ for (i = GDB_G0; i < GDB_G6; i++)
+ gdb_regs[i] = 0;
+ gdb_regs[GDB_G6] = (unsigned long) t;
+ gdb_regs[GDB_G7] = (unsigned long) p;
+ for (i = GDB_O0; i < GDB_SP; i++)
+ gdb_regs[i] = 0;
+ gdb_regs[GDB_SP] = t->ksp;
+ gdb_regs[GDB_O7] = 0;
+
+ win = (struct reg_window *) (t->ksp + STACK_BIAS);
+ for (i = 0; i < 8; i++)
+ gdb_regs[GDB_L0 + i] = win->locals[i];
+ for (i = 0; i < 8; i++)
+ gdb_regs[GDB_I0 + i] = win->ins[i];
+
+ for (i = GDB_F0; i <= GDB_F62; i++)
+ gdb_regs[i] = 0;
+
+ if (t->new_child)
+ pc = (unsigned long) &ret_from_syscall;
+ else
+ pc = (unsigned long) &switch_to_pc;
+
+ gdb_regs[GDB_PC] = pc;
+ gdb_regs[GDB_NPC] = pc + 4;
+
+ cwp = __thread_flag_byte_ptr(t)[TI_FLAG_BYTE_CWP];
+
+ gdb_regs[GDB_STATE] = (TSTATE_PRIV | TSTATE_IE | cwp);
+ gdb_regs[GDB_FSR] = 0;
+ gdb_regs[GDB_FPRS] = 0;
+ gdb_regs[GDB_Y] = 0;
+}
+
+void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs)
+{
+ struct reg_window *win;
+ int i;
+
+ for (i = 0; i < 15; i++)
+ regs->u_regs[UREG_G1 + i] = gdb_regs[GDB_G1 + i];
+
+ /* If the TSTATE register is changing, we have to preserve
+ * the CWP field, otherwise window save/restore explodes.
+ */
+ if (regs->tstate != gdb_regs[GDB_STATE]) {
+ unsigned long cwp = regs->tstate & TSTATE_CWP;
+
+ regs->tstate = (gdb_regs[GDB_STATE] & ~TSTATE_CWP) | cwp;
+ }
+
+ regs->tpc = gdb_regs[GDB_PC];
+ regs->tnpc = gdb_regs[GDB_NPC];
+ regs->y = gdb_regs[GDB_Y];
+
+ win = (struct reg_window *) (regs->u_regs[UREG_FP] + STACK_BIAS);
+ for (i = 0; i < 8; i++)
+ win->locals[i] = gdb_regs[GDB_L0 + i];
+ for (i = 0; i < 8; i++)
+ win->ins[i] = gdb_regs[GDB_I0 + i];
+}
+
+#ifdef CONFIG_SMP
+void smp_kgdb_capture_client(struct pt_regs *regs)
+{
+ unsigned long flags;
+
+ __asm__ __volatile__("rdpr %%pstate, %0\n\t"
+ "wrpr %0, %1, %%pstate"
+ : "=r" (flags)
+ : "i" (PSTATE_IE));
+
+ flushw_all();
+
+ if (atomic_read(&kgdb_active) != -1)
+ kgdb_nmicallback(raw_smp_processor_id(), regs);
+
+ __asm__ __volatile__("wrpr %0, 0, %%pstate"
+ : : "r" (flags));
+}
+#endif
+
+int kgdb_arch_handle_exception(int e_vector, int signo, int err_code,
+ char *remcomInBuffer, char *remcomOutBuffer,
+ struct pt_regs *linux_regs)
+{
+ unsigned long addr;
+ char *ptr;
+
+ switch (remcomInBuffer[0]) {
+ case 'c':
+ /* try to read optional parameter, pc unchanged if no parm */
+ ptr = &remcomInBuffer[1];
+ if (kgdb_hex2long(&ptr, &addr)) {
+ linux_regs->tpc = addr;
+ linux_regs->tnpc = addr + 4;
+ }
+ /* fallthru */
+
+ case 'D':
+ case 'k':
+ if (linux_regs->tpc == (unsigned long) arch_kgdb_breakpoint) {
+ linux_regs->tpc = linux_regs->tnpc;
+ linux_regs->tnpc += 4;
+ }
+ return 0;
+ }
+ return -1;
+}
+
+asmlinkage void kgdb_trap(unsigned long trap_level, struct pt_regs *regs)
+{
+ unsigned long flags;
+
+ if (user_mode(regs)) {
+ bad_trap(regs, trap_level);
+ return;
+ }
+
+ flushw_all();
+
+ local_irq_save(flags);
+ kgdb_handle_exception(0x172, SIGTRAP, 0, regs);
+ local_irq_restore(flags);
+}
+
+int kgdb_arch_init(void)
+{
+ return 0;
+}
+
+void kgdb_arch_exit(void)
+{
+}
+
+struct kgdb_arch arch_kgdb_ops = {
+ /* Breakpoint instruction: ta 0x72 */
+ .gdb_bpt_instr = { 0x91, 0xd0, 0x20, 0x72 },
+};
diff --git a/arch/sparc/kernel/kprobes.c b/arch/sparc/kernel/kprobes.c
new file mode 100644
index 000000000000..201a6e547e4a
--- /dev/null
+++ b/arch/sparc/kernel/kprobes.c
@@ -0,0 +1,593 @@
+/* arch/sparc64/kernel/kprobes.c
+ *
+ * Copyright (C) 2004 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/kprobes.h>
+#include <linux/module.h>
+#include <linux/kdebug.h>
+#include <asm/signal.h>
+#include <asm/cacheflush.h>
+#include <asm/uaccess.h>
+
+/* We do not have hardware single-stepping on sparc64.
+ * So we implement software single-stepping with breakpoint
+ * traps. The top-level scheme is similar to that used
+ * in the x86 kprobes implementation.
+ *
+ * In the kprobe->ainsn.insn[] array we store the original
+ * instruction at index zero and a break instruction at
+ * index one.
+ *
+ * When we hit a kprobe we:
+ * - Run the pre-handler
+ * - Remember "regs->tnpc" and interrupt level stored in
+ * "regs->tstate" so we can restore them later
+ * - Disable PIL interrupts
+ * - Set regs->tpc to point to kprobe->ainsn.insn[0]
+ * - Set regs->tnpc to point to kprobe->ainsn.insn[1]
+ * - Mark that we are actively in a kprobe
+ *
+ * At this point we wait for the second breakpoint at
+ * kprobe->ainsn.insn[1] to hit. When it does we:
+ * - Run the post-handler
+ * - Set regs->tpc to "remembered" regs->tnpc stored above,
+ * restore the PIL interrupt level in "regs->tstate" as well
+ * - Make any adjustments necessary to regs->tnpc in order
+ * to handle relative branches correctly. See below.
+ * - Mark that we are no longer actively in a kprobe.
+ */
+
+DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
+DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
+
+struct kretprobe_blackpoint kretprobe_blacklist[] = {{NULL, NULL}};
+
+int __kprobes arch_prepare_kprobe(struct kprobe *p)
+{
+ p->ainsn.insn[0] = *p->addr;
+ flushi(&p->ainsn.insn[0]);
+
+ p->ainsn.insn[1] = BREAKPOINT_INSTRUCTION_2;
+ flushi(&p->ainsn.insn[1]);
+
+ p->opcode = *p->addr;
+ return 0;
+}
+
+void __kprobes arch_arm_kprobe(struct kprobe *p)
+{
+ *p->addr = BREAKPOINT_INSTRUCTION;
+ flushi(p->addr);
+}
+
+void __kprobes arch_disarm_kprobe(struct kprobe *p)
+{
+ *p->addr = p->opcode;
+ flushi(p->addr);
+}
+
+static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb)
+{
+ kcb->prev_kprobe.kp = kprobe_running();
+ kcb->prev_kprobe.status = kcb->kprobe_status;
+ kcb->prev_kprobe.orig_tnpc = kcb->kprobe_orig_tnpc;
+ kcb->prev_kprobe.orig_tstate_pil = kcb->kprobe_orig_tstate_pil;
+}
+
+static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb)
+{
+ __get_cpu_var(current_kprobe) = kcb->prev_kprobe.kp;
+ kcb->kprobe_status = kcb->prev_kprobe.status;
+ kcb->kprobe_orig_tnpc = kcb->prev_kprobe.orig_tnpc;
+ kcb->kprobe_orig_tstate_pil = kcb->prev_kprobe.orig_tstate_pil;
+}
+
+static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs,
+ struct kprobe_ctlblk *kcb)
+{
+ __get_cpu_var(current_kprobe) = p;
+ kcb->kprobe_orig_tnpc = regs->tnpc;
+ kcb->kprobe_orig_tstate_pil = (regs->tstate & TSTATE_PIL);
+}
+
+static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs,
+ struct kprobe_ctlblk *kcb)
+{
+ regs->tstate |= TSTATE_PIL;
+
+ /*single step inline, if it a breakpoint instruction*/
+ if (p->opcode == BREAKPOINT_INSTRUCTION) {
+ regs->tpc = (unsigned long) p->addr;
+ regs->tnpc = kcb->kprobe_orig_tnpc;
+ } else {
+ regs->tpc = (unsigned long) &p->ainsn.insn[0];
+ regs->tnpc = (unsigned long) &p->ainsn.insn[1];
+ }
+}
+
+static int __kprobes kprobe_handler(struct pt_regs *regs)
+{
+ struct kprobe *p;
+ void *addr = (void *) regs->tpc;
+ int ret = 0;
+ struct kprobe_ctlblk *kcb;
+
+ /*
+ * We don't want to be preempted for the entire
+ * duration of kprobe processing
+ */
+ preempt_disable();
+ kcb = get_kprobe_ctlblk();
+
+ if (kprobe_running()) {
+ p = get_kprobe(addr);
+ if (p) {
+ if (kcb->kprobe_status == KPROBE_HIT_SS) {
+ regs->tstate = ((regs->tstate & ~TSTATE_PIL) |
+ kcb->kprobe_orig_tstate_pil);
+ goto no_kprobe;
+ }
+ /* We have reentered the kprobe_handler(), since
+ * another probe was hit while within the handler.
+ * We here save the original kprobes variables and
+ * just single step on the instruction of the new probe
+ * without calling any user handlers.
+ */
+ save_previous_kprobe(kcb);
+ set_current_kprobe(p, regs, kcb);
+ kprobes_inc_nmissed_count(p);
+ kcb->kprobe_status = KPROBE_REENTER;
+ prepare_singlestep(p, regs, kcb);
+ return 1;
+ } else {
+ if (*(u32 *)addr != BREAKPOINT_INSTRUCTION) {
+ /* The breakpoint instruction was removed by
+ * another cpu right after we hit, no further
+ * handling of this interrupt is appropriate
+ */
+ ret = 1;
+ goto no_kprobe;
+ }
+ p = __get_cpu_var(current_kprobe);
+ if (p->break_handler && p->break_handler(p, regs))
+ goto ss_probe;
+ }
+ goto no_kprobe;
+ }
+
+ p = get_kprobe(addr);
+ if (!p) {
+ if (*(u32 *)addr != BREAKPOINT_INSTRUCTION) {
+ /*
+ * The breakpoint instruction was removed right
+ * after we hit it. Another cpu has removed
+ * either a probepoint or a debugger breakpoint
+ * at this address. In either case, no further
+ * handling of this interrupt is appropriate.
+ */
+ ret = 1;
+ }
+ /* Not one of ours: let kernel handle it */
+ goto no_kprobe;
+ }
+
+ set_current_kprobe(p, regs, kcb);
+ kcb->kprobe_status = KPROBE_HIT_ACTIVE;
+ if (p->pre_handler && p->pre_handler(p, regs))
+ return 1;
+
+ss_probe:
+ prepare_singlestep(p, regs, kcb);
+ kcb->kprobe_status = KPROBE_HIT_SS;
+ return 1;
+
+no_kprobe:
+ preempt_enable_no_resched();
+ return ret;
+}
+
+/* If INSN is a relative control transfer instruction,
+ * return the corrected branch destination value.
+ *
+ * regs->tpc and regs->tnpc still hold the values of the
+ * program counters at the time of trap due to the execution
+ * of the BREAKPOINT_INSTRUCTION_2 at p->ainsn.insn[1]
+ *
+ */
+static unsigned long __kprobes relbranch_fixup(u32 insn, struct kprobe *p,
+ struct pt_regs *regs)
+{
+ unsigned long real_pc = (unsigned long) p->addr;
+
+ /* Branch not taken, no mods necessary. */
+ if (regs->tnpc == regs->tpc + 0x4UL)
+ return real_pc + 0x8UL;
+
+ /* The three cases are call, branch w/prediction,
+ * and traditional branch.
+ */
+ if ((insn & 0xc0000000) == 0x40000000 ||
+ (insn & 0xc1c00000) == 0x00400000 ||
+ (insn & 0xc1c00000) == 0x00800000) {
+ unsigned long ainsn_addr;
+
+ ainsn_addr = (unsigned long) &p->ainsn.insn[0];
+
+ /* The instruction did all the work for us
+ * already, just apply the offset to the correct
+ * instruction location.
+ */
+ return (real_pc + (regs->tnpc - ainsn_addr));
+ }
+
+ /* It is jmpl or some other absolute PC modification instruction,
+ * leave NPC as-is.
+ */
+ return regs->tnpc;
+}
+
+/* If INSN is an instruction which writes it's PC location
+ * into a destination register, fix that up.
+ */
+static void __kprobes retpc_fixup(struct pt_regs *regs, u32 insn,
+ unsigned long real_pc)
+{
+ unsigned long *slot = NULL;
+
+ /* Simplest case is 'call', which always uses %o7 */
+ if ((insn & 0xc0000000) == 0x40000000) {
+ slot = &regs->u_regs[UREG_I7];
+ }
+
+ /* 'jmpl' encodes the register inside of the opcode */
+ if ((insn & 0xc1f80000) == 0x81c00000) {
+ unsigned long rd = ((insn >> 25) & 0x1f);
+
+ if (rd <= 15) {
+ slot = &regs->u_regs[rd];
+ } else {
+ /* Hard case, it goes onto the stack. */
+ flushw_all();
+
+ rd -= 16;
+ slot = (unsigned long *)
+ (regs->u_regs[UREG_FP] + STACK_BIAS);
+ slot += rd;
+ }
+ }
+ if (slot != NULL)
+ *slot = real_pc;
+}
+
+/*
+ * Called after single-stepping. p->addr is the address of the
+ * instruction which has been replaced by the breakpoint
+ * instruction. To avoid the SMP problems that can occur when we
+ * temporarily put back the original opcode to single-step, we
+ * single-stepped a copy of the instruction. The address of this
+ * copy is &p->ainsn.insn[0].
+ *
+ * This function prepares to return from the post-single-step
+ * breakpoint trap.
+ */
+static void __kprobes resume_execution(struct kprobe *p,
+ struct pt_regs *regs, struct kprobe_ctlblk *kcb)
+{
+ u32 insn = p->ainsn.insn[0];
+
+ regs->tnpc = relbranch_fixup(insn, p, regs);
+
+ /* This assignment must occur after relbranch_fixup() */
+ regs->tpc = kcb->kprobe_orig_tnpc;
+
+ retpc_fixup(regs, insn, (unsigned long) p->addr);
+
+ regs->tstate = ((regs->tstate & ~TSTATE_PIL) |
+ kcb->kprobe_orig_tstate_pil);
+}
+
+static int __kprobes post_kprobe_handler(struct pt_regs *regs)
+{
+ struct kprobe *cur = kprobe_running();
+ struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+
+ if (!cur)
+ return 0;
+
+ if ((kcb->kprobe_status != KPROBE_REENTER) && cur->post_handler) {
+ kcb->kprobe_status = KPROBE_HIT_SSDONE;
+ cur->post_handler(cur, regs, 0);
+ }
+
+ resume_execution(cur, regs, kcb);
+
+ /*Restore back the original saved kprobes variables and continue. */
+ if (kcb->kprobe_status == KPROBE_REENTER) {
+ restore_previous_kprobe(kcb);
+ goto out;
+ }
+ reset_current_kprobe();
+out:
+ preempt_enable_no_resched();
+
+ return 1;
+}
+
+int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr)
+{
+ struct kprobe *cur = kprobe_running();
+ struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+ const struct exception_table_entry *entry;
+
+ switch(kcb->kprobe_status) {
+ case KPROBE_HIT_SS:
+ case KPROBE_REENTER:
+ /*
+ * We are here because the instruction being single
+ * stepped caused a page fault. We reset the current
+ * kprobe and the tpc points back to the probe address
+ * and allow the page fault handler to continue as a
+ * normal page fault.
+ */
+ regs->tpc = (unsigned long)cur->addr;
+ regs->tnpc = kcb->kprobe_orig_tnpc;
+ regs->tstate = ((regs->tstate & ~TSTATE_PIL) |
+ kcb->kprobe_orig_tstate_pil);
+ if (kcb->kprobe_status == KPROBE_REENTER)
+ restore_previous_kprobe(kcb);
+ else
+ reset_current_kprobe();
+ preempt_enable_no_resched();
+ break;
+ case KPROBE_HIT_ACTIVE:
+ case KPROBE_HIT_SSDONE:
+ /*
+ * We increment the nmissed count for accounting,
+ * we can also use npre/npostfault count for accouting
+ * these specific fault cases.
+ */
+ kprobes_inc_nmissed_count(cur);
+
+ /*
+ * We come here because instructions in the pre/post
+ * handler caused the page_fault, this could happen
+ * if handler tries to access user space by
+ * copy_from_user(), get_user() etc. Let the
+ * user-specified handler try to fix it first.
+ */
+ if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
+ return 1;
+
+ /*
+ * In case the user-specified fault handler returned
+ * zero, try to fix up.
+ */
+
+ entry = search_exception_tables(regs->tpc);
+ if (entry) {
+ regs->tpc = entry->fixup;
+ regs->tnpc = regs->tpc + 4;
+ return 1;
+ }
+
+ /*
+ * fixup_exception() could not handle it,
+ * Let do_page_fault() fix it.
+ */
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ * Wrapper routine to for handling exceptions.
+ */
+int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
+ unsigned long val, void *data)
+{
+ struct die_args *args = (struct die_args *)data;
+ int ret = NOTIFY_DONE;
+
+ if (args->regs && user_mode(args->regs))
+ return ret;
+
+ switch (val) {
+ case DIE_DEBUG:
+ if (kprobe_handler(args->regs))
+ ret = NOTIFY_STOP;
+ break;
+ case DIE_DEBUG_2:
+ if (post_kprobe_handler(args->regs))
+ ret = NOTIFY_STOP;
+ break;
+ default:
+ break;
+ }
+ return ret;
+}
+
+asmlinkage void __kprobes kprobe_trap(unsigned long trap_level,
+ struct pt_regs *regs)
+{
+ BUG_ON(trap_level != 0x170 && trap_level != 0x171);
+
+ if (user_mode(regs)) {
+ local_irq_enable();
+ bad_trap(regs, trap_level);
+ return;
+ }
+
+ /* trap_level == 0x170 --> ta 0x70
+ * trap_level == 0x171 --> ta 0x71
+ */
+ if (notify_die((trap_level == 0x170) ? DIE_DEBUG : DIE_DEBUG_2,
+ (trap_level == 0x170) ? "debug" : "debug_2",
+ regs, 0, trap_level, SIGTRAP) != NOTIFY_STOP)
+ bad_trap(regs, trap_level);
+}
+
+/* Jprobes support. */
+int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
+{
+ struct jprobe *jp = container_of(p, struct jprobe, kp);
+ struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+
+ memcpy(&(kcb->jprobe_saved_regs), regs, sizeof(*regs));
+
+ regs->tpc = (unsigned long) jp->entry;
+ regs->tnpc = ((unsigned long) jp->entry) + 0x4UL;
+ regs->tstate |= TSTATE_PIL;
+
+ return 1;
+}
+
+void __kprobes jprobe_return(void)
+{
+ struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+ register unsigned long orig_fp asm("g1");
+
+ orig_fp = kcb->jprobe_saved_regs.u_regs[UREG_FP];
+ __asm__ __volatile__("\n"
+"1: cmp %%sp, %0\n\t"
+ "blu,a,pt %%xcc, 1b\n\t"
+ " restore\n\t"
+ ".globl jprobe_return_trap_instruction\n"
+"jprobe_return_trap_instruction:\n\t"
+ "ta 0x70"
+ : /* no outputs */
+ : "r" (orig_fp));
+}
+
+extern void jprobe_return_trap_instruction(void);
+
+int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
+{
+ u32 *addr = (u32 *) regs->tpc;
+ struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+
+ if (addr == (u32 *) jprobe_return_trap_instruction) {
+ memcpy(regs, &(kcb->jprobe_saved_regs), sizeof(*regs));
+ preempt_enable_no_resched();
+ return 1;
+ }
+ return 0;
+}
+
+/* The value stored in the return address register is actually 2
+ * instructions before where the callee will return to.
+ * Sequences usually look something like this
+ *
+ * call some_function <--- return register points here
+ * nop <--- call delay slot
+ * whatever <--- where callee returns to
+ *
+ * To keep trampoline_probe_handler logic simpler, we normalize the
+ * value kept in ri->ret_addr so we don't need to keep adjusting it
+ * back and forth.
+ */
+void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
+ struct pt_regs *regs)
+{
+ ri->ret_addr = (kprobe_opcode_t *)(regs->u_regs[UREG_RETPC] + 8);
+
+ /* Replace the return addr with trampoline addr */
+ regs->u_regs[UREG_RETPC] =
+ ((unsigned long)kretprobe_trampoline) - 8;
+}
+
+/*
+ * Called when the probe at kretprobe trampoline is hit
+ */
+int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
+{
+ struct kretprobe_instance *ri = NULL;
+ struct hlist_head *head, empty_rp;
+ struct hlist_node *node, *tmp;
+ unsigned long flags, orig_ret_address = 0;
+ unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline;
+
+ INIT_HLIST_HEAD(&empty_rp);
+ kretprobe_hash_lock(current, &head, &flags);
+
+ /*
+ * It is possible to have multiple instances associated with a given
+ * task either because an multiple functions in the call path
+ * have a return probe installed on them, and/or more then one return
+ * return probe was registered for a target function.
+ *
+ * We can handle this because:
+ * - instances are always inserted at the head of the list
+ * - when multiple return probes are registered for the same
+ * function, the first instance's ret_addr will point to the
+ * real return address, and all the rest will point to
+ * kretprobe_trampoline
+ */
+ hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
+ if (ri->task != current)
+ /* another task is sharing our hash bucket */
+ continue;
+
+ if (ri->rp && ri->rp->handler)
+ ri->rp->handler(ri, regs);
+
+ orig_ret_address = (unsigned long)ri->ret_addr;
+ recycle_rp_inst(ri, &empty_rp);
+
+ if (orig_ret_address != trampoline_address)
+ /*
+ * This is the real return address. Any other
+ * instances associated with this task are for
+ * other calls deeper on the call stack
+ */
+ break;
+ }
+
+ kretprobe_assert(ri, orig_ret_address, trampoline_address);
+ regs->tpc = orig_ret_address;
+ regs->tnpc = orig_ret_address + 4;
+
+ reset_current_kprobe();
+ kretprobe_hash_unlock(current, &flags);
+ preempt_enable_no_resched();
+
+ hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) {
+ hlist_del(&ri->hlist);
+ kfree(ri);
+ }
+ /*
+ * By returning a non-zero value, we are telling
+ * kprobe_handler() that we don't want the post_handler
+ * to run (and have re-enabled preemption)
+ */
+ return 1;
+}
+
+void kretprobe_trampoline_holder(void)
+{
+ asm volatile(".global kretprobe_trampoline\n"
+ "kretprobe_trampoline:\n"
+ "\tnop\n"
+ "\tnop\n");
+}
+static struct kprobe trampoline_p = {
+ .addr = (kprobe_opcode_t *) &kretprobe_trampoline,
+ .pre_handler = trampoline_probe_handler
+};
+
+int __init arch_init_kprobes(void)
+{
+ return register_kprobe(&trampoline_p);
+}
+
+int __kprobes arch_trampoline_kprobe(struct kprobe *p)
+{
+ if (p->addr == (kprobe_opcode_t *)&kretprobe_trampoline)
+ return 1;
+
+ return 0;
+}
diff --git a/arch/sparc/kernel/kstack.h b/arch/sparc/kernel/kstack.h
new file mode 100644
index 000000000000..4248d969272f
--- /dev/null
+++ b/arch/sparc/kernel/kstack.h
@@ -0,0 +1,60 @@
+#ifndef _KSTACK_H
+#define _KSTACK_H
+
+#include <linux/thread_info.h>
+#include <linux/sched.h>
+#include <asm/ptrace.h>
+#include <asm/irq.h>
+
+/* SP must be STACK_BIAS adjusted already. */
+static inline bool kstack_valid(struct thread_info *tp, unsigned long sp)
+{
+ unsigned long base = (unsigned long) tp;
+
+ if (sp >= (base + sizeof(struct thread_info)) &&
+ sp <= (base + THREAD_SIZE - sizeof(struct sparc_stackf)))
+ return true;
+
+ if (hardirq_stack[tp->cpu]) {
+ base = (unsigned long) hardirq_stack[tp->cpu];
+ if (sp >= base &&
+ sp <= (base + THREAD_SIZE - sizeof(struct sparc_stackf)))
+ return true;
+ base = (unsigned long) softirq_stack[tp->cpu];
+ if (sp >= base &&
+ sp <= (base + THREAD_SIZE - sizeof(struct sparc_stackf)))
+ return true;
+ }
+ return false;
+}
+
+/* Does "regs" point to a valid pt_regs trap frame? */
+static inline bool kstack_is_trap_frame(struct thread_info *tp, struct pt_regs *regs)
+{
+ unsigned long base = (unsigned long) tp;
+ unsigned long addr = (unsigned long) regs;
+
+ if (addr >= base &&
+ addr <= (base + THREAD_SIZE - sizeof(*regs)))
+ goto check_magic;
+
+ if (hardirq_stack[tp->cpu]) {
+ base = (unsigned long) hardirq_stack[tp->cpu];
+ if (addr >= base &&
+ addr <= (base + THREAD_SIZE - sizeof(*regs)))
+ goto check_magic;
+ base = (unsigned long) softirq_stack[tp->cpu];
+ if (addr >= base &&
+ addr <= (base + THREAD_SIZE - sizeof(*regs)))
+ goto check_magic;
+ }
+ return false;
+
+check_magic:
+ if ((regs->magic & ~0x1ff) == PT_REGS_MAGIC)
+ return true;
+ return false;
+
+}
+
+#endif /* _KSTACK_H */
diff --git a/arch/sparc/kernel/ktlb.S b/arch/sparc/kernel/ktlb.S
new file mode 100644
index 000000000000..cef8defcd7a9
--- /dev/null
+++ b/arch/sparc/kernel/ktlb.S
@@ -0,0 +1,304 @@
+/* arch/sparc64/kernel/ktlb.S: Kernel mapping TLB miss handling.
+ *
+ * Copyright (C) 1995, 1997, 2005, 2008 David S. Miller <davem@davemloft.net>
+ * Copyright (C) 1996 Eddie C. Dost (ecd@brainaid.de)
+ * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
+ * Copyright (C) 1996,98,99 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <asm/head.h>
+#include <asm/asi.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/tsb.h>
+
+ .text
+ .align 32
+
+kvmap_itlb:
+ /* g6: TAG TARGET */
+ mov TLB_TAG_ACCESS, %g4
+ ldxa [%g4] ASI_IMMU, %g4
+
+ /* sun4v_itlb_miss branches here with the missing virtual
+ * address already loaded into %g4
+ */
+kvmap_itlb_4v:
+
+kvmap_itlb_nonlinear:
+ /* Catch kernel NULL pointer calls. */
+ sethi %hi(PAGE_SIZE), %g5
+ cmp %g4, %g5
+ bleu,pn %xcc, kvmap_dtlb_longpath
+ nop
+
+ KERN_TSB_LOOKUP_TL1(%g4, %g6, %g5, %g1, %g2, %g3, kvmap_itlb_load)
+
+kvmap_itlb_tsb_miss:
+ sethi %hi(LOW_OBP_ADDRESS), %g5
+ cmp %g4, %g5
+ blu,pn %xcc, kvmap_itlb_vmalloc_addr
+ mov 0x1, %g5
+ sllx %g5, 32, %g5
+ cmp %g4, %g5
+ blu,pn %xcc, kvmap_itlb_obp
+ nop
+
+kvmap_itlb_vmalloc_addr:
+ KERN_PGTABLE_WALK(%g4, %g5, %g2, kvmap_itlb_longpath)
+
+ KTSB_LOCK_TAG(%g1, %g2, %g7)
+
+ /* Load and check PTE. */
+ ldxa [%g5] ASI_PHYS_USE_EC, %g5
+ mov 1, %g7
+ sllx %g7, TSB_TAG_INVALID_BIT, %g7
+ brgez,a,pn %g5, kvmap_itlb_longpath
+ KTSB_STORE(%g1, %g7)
+
+ KTSB_WRITE(%g1, %g5, %g6)
+
+ /* fallthrough to TLB load */
+
+kvmap_itlb_load:
+
+661: stxa %g5, [%g0] ASI_ITLB_DATA_IN
+ retry
+ .section .sun4v_2insn_patch, "ax"
+ .word 661b
+ nop
+ nop
+ .previous
+
+ /* For sun4v the ASI_ITLB_DATA_IN store and the retry
+ * instruction get nop'd out and we get here to branch
+ * to the sun4v tlb load code. The registers are setup
+ * as follows:
+ *
+ * %g4: vaddr
+ * %g5: PTE
+ * %g6: TAG
+ *
+ * The sun4v TLB load wants the PTE in %g3 so we fix that
+ * up here.
+ */
+ ba,pt %xcc, sun4v_itlb_load
+ mov %g5, %g3
+
+kvmap_itlb_longpath:
+
+661: rdpr %pstate, %g5
+ wrpr %g5, PSTATE_AG | PSTATE_MG, %pstate
+ .section .sun4v_2insn_patch, "ax"
+ .word 661b
+ SET_GL(1)
+ nop
+ .previous
+
+ rdpr %tpc, %g5
+ ba,pt %xcc, sparc64_realfault_common
+ mov FAULT_CODE_ITLB, %g4
+
+kvmap_itlb_obp:
+ OBP_TRANS_LOOKUP(%g4, %g5, %g2, %g3, kvmap_itlb_longpath)
+
+ KTSB_LOCK_TAG(%g1, %g2, %g7)
+
+ KTSB_WRITE(%g1, %g5, %g6)
+
+ ba,pt %xcc, kvmap_itlb_load
+ nop
+
+kvmap_dtlb_obp:
+ OBP_TRANS_LOOKUP(%g4, %g5, %g2, %g3, kvmap_dtlb_longpath)
+
+ KTSB_LOCK_TAG(%g1, %g2, %g7)
+
+ KTSB_WRITE(%g1, %g5, %g6)
+
+ ba,pt %xcc, kvmap_dtlb_load
+ nop
+
+ .align 32
+kvmap_dtlb_tsb4m_load:
+ KTSB_LOCK_TAG(%g1, %g2, %g7)
+ KTSB_WRITE(%g1, %g5, %g6)
+ ba,pt %xcc, kvmap_dtlb_load
+ nop
+
+kvmap_dtlb:
+ /* %g6: TAG TARGET */
+ mov TLB_TAG_ACCESS, %g4
+ ldxa [%g4] ASI_DMMU, %g4
+
+ /* sun4v_dtlb_miss branches here with the missing virtual
+ * address already loaded into %g4
+ */
+kvmap_dtlb_4v:
+ brgez,pn %g4, kvmap_dtlb_nonlinear
+ nop
+
+#ifdef CONFIG_DEBUG_PAGEALLOC
+ /* Index through the base page size TSB even for linear
+ * mappings when using page allocation debugging.
+ */
+ KERN_TSB_LOOKUP_TL1(%g4, %g6, %g5, %g1, %g2, %g3, kvmap_dtlb_load)
+#else
+ /* Correct TAG_TARGET is already in %g6, check 4mb TSB. */
+ KERN_TSB4M_LOOKUP_TL1(%g6, %g5, %g1, %g2, %g3, kvmap_dtlb_load)
+#endif
+ /* TSB entry address left in %g1, lookup linear PTE.
+ * Must preserve %g1 and %g6 (TAG).
+ */
+kvmap_dtlb_tsb4m_miss:
+ sethi %hi(kpte_linear_bitmap), %g2
+ or %g2, %lo(kpte_linear_bitmap), %g2
+
+ /* Clear the PAGE_OFFSET top virtual bits, then shift
+ * down to get a 256MB physical address index.
+ */
+ sllx %g4, 21, %g5
+ mov 1, %g7
+ srlx %g5, 21 + 28, %g5
+
+ /* Don't try this at home kids... this depends upon srlx
+ * only taking the low 6 bits of the shift count in %g5.
+ */
+ sllx %g7, %g5, %g7
+
+ /* Divide by 64 to get the offset into the bitmask. */
+ srlx %g5, 6, %g5
+ sllx %g5, 3, %g5
+
+ /* kern_linear_pte_xor[((mask & bit) ? 1 : 0)] */
+ ldx [%g2 + %g5], %g2
+ andcc %g2, %g7, %g0
+ sethi %hi(kern_linear_pte_xor), %g5
+ or %g5, %lo(kern_linear_pte_xor), %g5
+ bne,a,pt %xcc, 1f
+ add %g5, 8, %g5
+
+1: ldx [%g5], %g2
+
+ .globl kvmap_linear_patch
+kvmap_linear_patch:
+ ba,pt %xcc, kvmap_dtlb_tsb4m_load
+ xor %g2, %g4, %g5
+
+kvmap_dtlb_vmalloc_addr:
+ KERN_PGTABLE_WALK(%g4, %g5, %g2, kvmap_dtlb_longpath)
+
+ KTSB_LOCK_TAG(%g1, %g2, %g7)
+
+ /* Load and check PTE. */
+ ldxa [%g5] ASI_PHYS_USE_EC, %g5
+ mov 1, %g7
+ sllx %g7, TSB_TAG_INVALID_BIT, %g7
+ brgez,a,pn %g5, kvmap_dtlb_longpath
+ KTSB_STORE(%g1, %g7)
+
+ KTSB_WRITE(%g1, %g5, %g6)
+
+ /* fallthrough to TLB load */
+
+kvmap_dtlb_load:
+
+661: stxa %g5, [%g0] ASI_DTLB_DATA_IN ! Reload TLB
+ retry
+ .section .sun4v_2insn_patch, "ax"
+ .word 661b
+ nop
+ nop
+ .previous
+
+ /* For sun4v the ASI_DTLB_DATA_IN store and the retry
+ * instruction get nop'd out and we get here to branch
+ * to the sun4v tlb load code. The registers are setup
+ * as follows:
+ *
+ * %g4: vaddr
+ * %g5: PTE
+ * %g6: TAG
+ *
+ * The sun4v TLB load wants the PTE in %g3 so we fix that
+ * up here.
+ */
+ ba,pt %xcc, sun4v_dtlb_load
+ mov %g5, %g3
+
+#ifdef CONFIG_SPARSEMEM_VMEMMAP
+kvmap_vmemmap:
+ sub %g4, %g5, %g5
+ srlx %g5, 22, %g5
+ sethi %hi(vmemmap_table), %g1
+ sllx %g5, 3, %g5
+ or %g1, %lo(vmemmap_table), %g1
+ ba,pt %xcc, kvmap_dtlb_load
+ ldx [%g1 + %g5], %g5
+#endif
+
+kvmap_dtlb_nonlinear:
+ /* Catch kernel NULL pointer derefs. */
+ sethi %hi(PAGE_SIZE), %g5
+ cmp %g4, %g5
+ bleu,pn %xcc, kvmap_dtlb_longpath
+ nop
+
+#ifdef CONFIG_SPARSEMEM_VMEMMAP
+ /* Do not use the TSB for vmemmap. */
+ mov (VMEMMAP_BASE >> 24), %g5
+ sllx %g5, 24, %g5
+ cmp %g4,%g5
+ bgeu,pn %xcc, kvmap_vmemmap
+ nop
+#endif
+
+ KERN_TSB_LOOKUP_TL1(%g4, %g6, %g5, %g1, %g2, %g3, kvmap_dtlb_load)
+
+kvmap_dtlb_tsbmiss:
+ sethi %hi(MODULES_VADDR), %g5
+ cmp %g4, %g5
+ blu,pn %xcc, kvmap_dtlb_longpath
+ mov (VMALLOC_END >> 24), %g5
+ sllx %g5, 24, %g5
+ cmp %g4, %g5
+ bgeu,pn %xcc, kvmap_dtlb_longpath
+ nop
+
+kvmap_check_obp:
+ sethi %hi(LOW_OBP_ADDRESS), %g5
+ cmp %g4, %g5
+ blu,pn %xcc, kvmap_dtlb_vmalloc_addr
+ mov 0x1, %g5
+ sllx %g5, 32, %g5
+ cmp %g4, %g5
+ blu,pn %xcc, kvmap_dtlb_obp
+ nop
+ ba,pt %xcc, kvmap_dtlb_vmalloc_addr
+ nop
+
+kvmap_dtlb_longpath:
+
+661: rdpr %pstate, %g5
+ wrpr %g5, PSTATE_AG | PSTATE_MG, %pstate
+ .section .sun4v_2insn_patch, "ax"
+ .word 661b
+ SET_GL(1)
+ ldxa [%g0] ASI_SCRATCHPAD, %g5
+ .previous
+
+ rdpr %tl, %g3
+ cmp %g3, 1
+
+661: mov TLB_TAG_ACCESS, %g4
+ ldxa [%g4] ASI_DMMU, %g5
+ .section .sun4v_2insn_patch, "ax"
+ .word 661b
+ ldx [%g5 + HV_FAULT_D_ADDR_OFFSET], %g5
+ nop
+ .previous
+
+ be,pt %xcc, sparc64_realfault_common
+ mov FAULT_CODE_DTLB, %g4
+ ba,pt %xcc, winfix_trampoline
+ nop
diff --git a/arch/sparc/kernel/ldc.c b/arch/sparc/kernel/ldc.c
new file mode 100644
index 000000000000..d68982330f66
--- /dev/null
+++ b/arch/sparc/kernel/ldc.c
@@ -0,0 +1,2378 @@
+/* ldc.c: Logical Domain Channel link-layer protocol driver.
+ *
+ * Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/scatterlist.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/init.h>
+
+#include <asm/hypervisor.h>
+#include <asm/iommu.h>
+#include <asm/page.h>
+#include <asm/ldc.h>
+#include <asm/mdesc.h>
+
+#define DRV_MODULE_NAME "ldc"
+#define PFX DRV_MODULE_NAME ": "
+#define DRV_MODULE_VERSION "1.1"
+#define DRV_MODULE_RELDATE "July 22, 2008"
+
+static char version[] __devinitdata =
+ DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
+#define LDC_PACKET_SIZE 64
+
+/* Packet header layout for unreliable and reliable mode frames.
+ * When in RAW mode, packets are simply straight 64-byte payloads
+ * with no headers.
+ */
+struct ldc_packet {
+ u8 type;
+#define LDC_CTRL 0x01
+#define LDC_DATA 0x02
+#define LDC_ERR 0x10
+
+ u8 stype;
+#define LDC_INFO 0x01
+#define LDC_ACK 0x02
+#define LDC_NACK 0x04
+
+ u8 ctrl;
+#define LDC_VERS 0x01 /* Link Version */
+#define LDC_RTS 0x02 /* Request To Send */
+#define LDC_RTR 0x03 /* Ready To Receive */
+#define LDC_RDX 0x04 /* Ready for Data eXchange */
+#define LDC_CTRL_MSK 0x0f
+
+ u8 env;
+#define LDC_LEN 0x3f
+#define LDC_FRAG_MASK 0xc0
+#define LDC_START 0x40
+#define LDC_STOP 0x80
+
+ u32 seqid;
+
+ union {
+ u8 u_data[LDC_PACKET_SIZE - 8];
+ struct {
+ u32 pad;
+ u32 ackid;
+ u8 r_data[LDC_PACKET_SIZE - 8 - 8];
+ } r;
+ } u;
+};
+
+struct ldc_version {
+ u16 major;
+ u16 minor;
+};
+
+/* Ordered from largest major to lowest. */
+static struct ldc_version ver_arr[] = {
+ { .major = 1, .minor = 0 },
+};
+
+#define LDC_DEFAULT_MTU (4 * LDC_PACKET_SIZE)
+#define LDC_DEFAULT_NUM_ENTRIES (PAGE_SIZE / LDC_PACKET_SIZE)
+
+struct ldc_channel;
+
+struct ldc_mode_ops {
+ int (*write)(struct ldc_channel *, const void *, unsigned int);
+ int (*read)(struct ldc_channel *, void *, unsigned int);
+};
+
+static const struct ldc_mode_ops raw_ops;
+static const struct ldc_mode_ops nonraw_ops;
+static const struct ldc_mode_ops stream_ops;
+
+int ldom_domaining_enabled;
+
+struct ldc_iommu {
+ /* Protects arena alloc/free. */
+ spinlock_t lock;
+ struct iommu_arena arena;
+ struct ldc_mtable_entry *page_table;
+};
+
+struct ldc_channel {
+ /* Protects all operations that depend upon channel state. */
+ spinlock_t lock;
+
+ unsigned long id;
+
+ u8 *mssbuf;
+ u32 mssbuf_len;
+ u32 mssbuf_off;
+
+ struct ldc_packet *tx_base;
+ unsigned long tx_head;
+ unsigned long tx_tail;
+ unsigned long tx_num_entries;
+ unsigned long tx_ra;
+
+ unsigned long tx_acked;
+
+ struct ldc_packet *rx_base;
+ unsigned long rx_head;
+ unsigned long rx_tail;
+ unsigned long rx_num_entries;
+ unsigned long rx_ra;
+
+ u32 rcv_nxt;
+ u32 snd_nxt;
+
+ unsigned long chan_state;
+
+ struct ldc_channel_config cfg;
+ void *event_arg;
+
+ const struct ldc_mode_ops *mops;
+
+ struct ldc_iommu iommu;
+
+ struct ldc_version ver;
+
+ u8 hs_state;
+#define LDC_HS_CLOSED 0x00
+#define LDC_HS_OPEN 0x01
+#define LDC_HS_GOTVERS 0x02
+#define LDC_HS_SENTRTR 0x03
+#define LDC_HS_GOTRTR 0x04
+#define LDC_HS_COMPLETE 0x10
+
+ u8 flags;
+#define LDC_FLAG_ALLOCED_QUEUES 0x01
+#define LDC_FLAG_REGISTERED_QUEUES 0x02
+#define LDC_FLAG_REGISTERED_IRQS 0x04
+#define LDC_FLAG_RESET 0x10
+
+ u8 mss;
+ u8 state;
+
+#define LDC_IRQ_NAME_MAX 32
+ char rx_irq_name[LDC_IRQ_NAME_MAX];
+ char tx_irq_name[LDC_IRQ_NAME_MAX];
+
+ struct hlist_head mh_list;
+
+ struct hlist_node list;
+};
+
+#define ldcdbg(TYPE, f, a...) \
+do { if (lp->cfg.debug & LDC_DEBUG_##TYPE) \
+ printk(KERN_INFO PFX "ID[%lu] " f, lp->id, ## a); \
+} while (0)
+
+static const char *state_to_str(u8 state)
+{
+ switch (state) {
+ case LDC_STATE_INVALID:
+ return "INVALID";
+ case LDC_STATE_INIT:
+ return "INIT";
+ case LDC_STATE_BOUND:
+ return "BOUND";
+ case LDC_STATE_READY:
+ return "READY";
+ case LDC_STATE_CONNECTED:
+ return "CONNECTED";
+ default:
+ return "<UNKNOWN>";
+ }
+}
+
+static void ldc_set_state(struct ldc_channel *lp, u8 state)
+{
+ ldcdbg(STATE, "STATE (%s) --> (%s)\n",
+ state_to_str(lp->state),
+ state_to_str(state));
+
+ lp->state = state;
+}
+
+static unsigned long __advance(unsigned long off, unsigned long num_entries)
+{
+ off += LDC_PACKET_SIZE;
+ if (off == (num_entries * LDC_PACKET_SIZE))
+ off = 0;
+
+ return off;
+}
+
+static unsigned long rx_advance(struct ldc_channel *lp, unsigned long off)
+{
+ return __advance(off, lp->rx_num_entries);
+}
+
+static unsigned long tx_advance(struct ldc_channel *lp, unsigned long off)
+{
+ return __advance(off, lp->tx_num_entries);
+}
+
+static struct ldc_packet *handshake_get_tx_packet(struct ldc_channel *lp,
+ unsigned long *new_tail)
+{
+ struct ldc_packet *p;
+ unsigned long t;
+
+ t = tx_advance(lp, lp->tx_tail);
+ if (t == lp->tx_head)
+ return NULL;
+
+ *new_tail = t;
+
+ p = lp->tx_base;
+ return p + (lp->tx_tail / LDC_PACKET_SIZE);
+}
+
+/* When we are in reliable or stream mode, have to track the next packet
+ * we haven't gotten an ACK for in the TX queue using tx_acked. We have
+ * to be careful not to stomp over the queue past that point. During
+ * the handshake, we don't have TX data packets pending in the queue
+ * and that's why handshake_get_tx_packet() need not be mindful of
+ * lp->tx_acked.
+ */
+static unsigned long head_for_data(struct ldc_channel *lp)
+{
+ if (lp->cfg.mode == LDC_MODE_STREAM)
+ return lp->tx_acked;
+ return lp->tx_head;
+}
+
+static int tx_has_space_for(struct ldc_channel *lp, unsigned int size)
+{
+ unsigned long limit, tail, new_tail, diff;
+ unsigned int mss;
+
+ limit = head_for_data(lp);
+ tail = lp->tx_tail;
+ new_tail = tx_advance(lp, tail);
+ if (new_tail == limit)
+ return 0;
+
+ if (limit > new_tail)
+ diff = limit - new_tail;
+ else
+ diff = (limit +
+ ((lp->tx_num_entries * LDC_PACKET_SIZE) - new_tail));
+ diff /= LDC_PACKET_SIZE;
+ mss = lp->mss;
+
+ if (diff * mss < size)
+ return 0;
+
+ return 1;
+}
+
+static struct ldc_packet *data_get_tx_packet(struct ldc_channel *lp,
+ unsigned long *new_tail)
+{
+ struct ldc_packet *p;
+ unsigned long h, t;
+
+ h = head_for_data(lp);
+ t = tx_advance(lp, lp->tx_tail);
+ if (t == h)
+ return NULL;
+
+ *new_tail = t;
+
+ p = lp->tx_base;
+ return p + (lp->tx_tail / LDC_PACKET_SIZE);
+}
+
+static int set_tx_tail(struct ldc_channel *lp, unsigned long tail)
+{
+ unsigned long orig_tail = lp->tx_tail;
+ int limit = 1000;
+
+ lp->tx_tail = tail;
+ while (limit-- > 0) {
+ unsigned long err;
+
+ err = sun4v_ldc_tx_set_qtail(lp->id, tail);
+ if (!err)
+ return 0;
+
+ if (err != HV_EWOULDBLOCK) {
+ lp->tx_tail = orig_tail;
+ return -EINVAL;
+ }
+ udelay(1);
+ }
+
+ lp->tx_tail = orig_tail;
+ return -EBUSY;
+}
+
+/* This just updates the head value in the hypervisor using
+ * a polling loop with a timeout. The caller takes care of
+ * upating software state representing the head change, if any.
+ */
+static int __set_rx_head(struct ldc_channel *lp, unsigned long head)
+{
+ int limit = 1000;
+
+ while (limit-- > 0) {
+ unsigned long err;
+
+ err = sun4v_ldc_rx_set_qhead(lp->id, head);
+ if (!err)
+ return 0;
+
+ if (err != HV_EWOULDBLOCK)
+ return -EINVAL;
+
+ udelay(1);
+ }
+
+ return -EBUSY;
+}
+
+static int send_tx_packet(struct ldc_channel *lp,
+ struct ldc_packet *p,
+ unsigned long new_tail)
+{
+ BUG_ON(p != (lp->tx_base + (lp->tx_tail / LDC_PACKET_SIZE)));
+
+ return set_tx_tail(lp, new_tail);
+}
+
+static struct ldc_packet *handshake_compose_ctrl(struct ldc_channel *lp,
+ u8 stype, u8 ctrl,
+ void *data, int dlen,
+ unsigned long *new_tail)
+{
+ struct ldc_packet *p = handshake_get_tx_packet(lp, new_tail);
+
+ if (p) {
+ memset(p, 0, sizeof(*p));
+ p->type = LDC_CTRL;
+ p->stype = stype;
+ p->ctrl = ctrl;
+ if (data)
+ memcpy(p->u.u_data, data, dlen);
+ }
+ return p;
+}
+
+static int start_handshake(struct ldc_channel *lp)
+{
+ struct ldc_packet *p;
+ struct ldc_version *ver;
+ unsigned long new_tail;
+
+ ver = &ver_arr[0];
+
+ ldcdbg(HS, "SEND VER INFO maj[%u] min[%u]\n",
+ ver->major, ver->minor);
+
+ p = handshake_compose_ctrl(lp, LDC_INFO, LDC_VERS,
+ ver, sizeof(*ver), &new_tail);
+ if (p) {
+ int err = send_tx_packet(lp, p, new_tail);
+ if (!err)
+ lp->flags &= ~LDC_FLAG_RESET;
+ return err;
+ }
+ return -EBUSY;
+}
+
+static int send_version_nack(struct ldc_channel *lp,
+ u16 major, u16 minor)
+{
+ struct ldc_packet *p;
+ struct ldc_version ver;
+ unsigned long new_tail;
+
+ ver.major = major;
+ ver.minor = minor;
+
+ p = handshake_compose_ctrl(lp, LDC_NACK, LDC_VERS,
+ &ver, sizeof(ver), &new_tail);
+ if (p) {
+ ldcdbg(HS, "SEND VER NACK maj[%u] min[%u]\n",
+ ver.major, ver.minor);
+
+ return send_tx_packet(lp, p, new_tail);
+ }
+ return -EBUSY;
+}
+
+static int send_version_ack(struct ldc_channel *lp,
+ struct ldc_version *vp)
+{
+ struct ldc_packet *p;
+ unsigned long new_tail;
+
+ p = handshake_compose_ctrl(lp, LDC_ACK, LDC_VERS,
+ vp, sizeof(*vp), &new_tail);
+ if (p) {
+ ldcdbg(HS, "SEND VER ACK maj[%u] min[%u]\n",
+ vp->major, vp->minor);
+
+ return send_tx_packet(lp, p, new_tail);
+ }
+ return -EBUSY;
+}
+
+static int send_rts(struct ldc_channel *lp)
+{
+ struct ldc_packet *p;
+ unsigned long new_tail;
+
+ p = handshake_compose_ctrl(lp, LDC_INFO, LDC_RTS, NULL, 0,
+ &new_tail);
+ if (p) {
+ p->env = lp->cfg.mode;
+ p->seqid = 0;
+ lp->rcv_nxt = 0;
+
+ ldcdbg(HS, "SEND RTS env[0x%x] seqid[0x%x]\n",
+ p->env, p->seqid);
+
+ return send_tx_packet(lp, p, new_tail);
+ }
+ return -EBUSY;
+}
+
+static int send_rtr(struct ldc_channel *lp)
+{
+ struct ldc_packet *p;
+ unsigned long new_tail;
+
+ p = handshake_compose_ctrl(lp, LDC_INFO, LDC_RTR, NULL, 0,
+ &new_tail);
+ if (p) {
+ p->env = lp->cfg.mode;
+ p->seqid = 0;
+
+ ldcdbg(HS, "SEND RTR env[0x%x] seqid[0x%x]\n",
+ p->env, p->seqid);
+
+ return send_tx_packet(lp, p, new_tail);
+ }
+ return -EBUSY;
+}
+
+static int send_rdx(struct ldc_channel *lp)
+{
+ struct ldc_packet *p;
+ unsigned long new_tail;
+
+ p = handshake_compose_ctrl(lp, LDC_INFO, LDC_RDX, NULL, 0,
+ &new_tail);
+ if (p) {
+ p->env = 0;
+ p->seqid = ++lp->snd_nxt;
+ p->u.r.ackid = lp->rcv_nxt;
+
+ ldcdbg(HS, "SEND RDX env[0x%x] seqid[0x%x] ackid[0x%x]\n",
+ p->env, p->seqid, p->u.r.ackid);
+
+ return send_tx_packet(lp, p, new_tail);
+ }
+ return -EBUSY;
+}
+
+static int send_data_nack(struct ldc_channel *lp, struct ldc_packet *data_pkt)
+{
+ struct ldc_packet *p;
+ unsigned long new_tail;
+ int err;
+
+ p = data_get_tx_packet(lp, &new_tail);
+ if (!p)
+ return -EBUSY;
+ memset(p, 0, sizeof(*p));
+ p->type = data_pkt->type;
+ p->stype = LDC_NACK;
+ p->ctrl = data_pkt->ctrl & LDC_CTRL_MSK;
+ p->seqid = lp->snd_nxt + 1;
+ p->u.r.ackid = lp->rcv_nxt;
+
+ ldcdbg(HS, "SEND DATA NACK type[0x%x] ctl[0x%x] seq[0x%x] ack[0x%x]\n",
+ p->type, p->ctrl, p->seqid, p->u.r.ackid);
+
+ err = send_tx_packet(lp, p, new_tail);
+ if (!err)
+ lp->snd_nxt++;
+
+ return err;
+}
+
+static int ldc_abort(struct ldc_channel *lp)
+{
+ unsigned long hv_err;
+
+ ldcdbg(STATE, "ABORT\n");
+
+ /* We report but do not act upon the hypervisor errors because
+ * there really isn't much we can do if they fail at this point.
+ */
+ hv_err = sun4v_ldc_tx_qconf(lp->id, lp->tx_ra, lp->tx_num_entries);
+ if (hv_err)
+ printk(KERN_ERR PFX "ldc_abort: "
+ "sun4v_ldc_tx_qconf(%lx,%lx,%lx) failed, err=%lu\n",
+ lp->id, lp->tx_ra, lp->tx_num_entries, hv_err);
+
+ hv_err = sun4v_ldc_tx_get_state(lp->id,
+ &lp->tx_head,
+ &lp->tx_tail,
+ &lp->chan_state);
+ if (hv_err)
+ printk(KERN_ERR PFX "ldc_abort: "
+ "sun4v_ldc_tx_get_state(%lx,...) failed, err=%lu\n",
+ lp->id, hv_err);
+
+ hv_err = sun4v_ldc_rx_qconf(lp->id, lp->rx_ra, lp->rx_num_entries);
+ if (hv_err)
+ printk(KERN_ERR PFX "ldc_abort: "
+ "sun4v_ldc_rx_qconf(%lx,%lx,%lx) failed, err=%lu\n",
+ lp->id, lp->rx_ra, lp->rx_num_entries, hv_err);
+
+ /* Refetch the RX queue state as well, because we could be invoked
+ * here in the queue processing context.
+ */
+ hv_err = sun4v_ldc_rx_get_state(lp->id,
+ &lp->rx_head,
+ &lp->rx_tail,
+ &lp->chan_state);
+ if (hv_err)
+ printk(KERN_ERR PFX "ldc_abort: "
+ "sun4v_ldc_rx_get_state(%lx,...) failed, err=%lu\n",
+ lp->id, hv_err);
+
+ return -ECONNRESET;
+}
+
+static struct ldc_version *find_by_major(u16 major)
+{
+ struct ldc_version *ret = NULL;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ver_arr); i++) {
+ struct ldc_version *v = &ver_arr[i];
+ if (v->major <= major) {
+ ret = v;
+ break;
+ }
+ }
+ return ret;
+}
+
+static int process_ver_info(struct ldc_channel *lp, struct ldc_version *vp)
+{
+ struct ldc_version *vap;
+ int err;
+
+ ldcdbg(HS, "GOT VERSION INFO major[%x] minor[%x]\n",
+ vp->major, vp->minor);
+
+ if (lp->hs_state == LDC_HS_GOTVERS) {
+ lp->hs_state = LDC_HS_OPEN;
+ memset(&lp->ver, 0, sizeof(lp->ver));
+ }
+
+ vap = find_by_major(vp->major);
+ if (!vap) {
+ err = send_version_nack(lp, 0, 0);
+ } else if (vap->major != vp->major) {
+ err = send_version_nack(lp, vap->major, vap->minor);
+ } else {
+ struct ldc_version ver = *vp;
+ if (ver.minor > vap->minor)
+ ver.minor = vap->minor;
+ err = send_version_ack(lp, &ver);
+ if (!err) {
+ lp->ver = ver;
+ lp->hs_state = LDC_HS_GOTVERS;
+ }
+ }
+ if (err)
+ return ldc_abort(lp);
+
+ return 0;
+}
+
+static int process_ver_ack(struct ldc_channel *lp, struct ldc_version *vp)
+{
+ ldcdbg(HS, "GOT VERSION ACK major[%x] minor[%x]\n",
+ vp->major, vp->minor);
+
+ if (lp->hs_state == LDC_HS_GOTVERS) {
+ if (lp->ver.major != vp->major ||
+ lp->ver.minor != vp->minor)
+ return ldc_abort(lp);
+ } else {
+ lp->ver = *vp;
+ lp->hs_state = LDC_HS_GOTVERS;
+ }
+ if (send_rts(lp))
+ return ldc_abort(lp);
+ return 0;
+}
+
+static int process_ver_nack(struct ldc_channel *lp, struct ldc_version *vp)
+{
+ struct ldc_version *vap;
+
+ if ((vp->major == 0 && vp->minor == 0) ||
+ !(vap = find_by_major(vp->major))) {
+ return ldc_abort(lp);
+ } else {
+ struct ldc_packet *p;
+ unsigned long new_tail;
+
+ p = handshake_compose_ctrl(lp, LDC_INFO, LDC_VERS,
+ vap, sizeof(*vap),
+ &new_tail);
+ if (p)
+ return send_tx_packet(lp, p, new_tail);
+ else
+ return ldc_abort(lp);
+ }
+}
+
+static int process_version(struct ldc_channel *lp,
+ struct ldc_packet *p)
+{
+ struct ldc_version *vp;
+
+ vp = (struct ldc_version *) p->u.u_data;
+
+ switch (p->stype) {
+ case LDC_INFO:
+ return process_ver_info(lp, vp);
+
+ case LDC_ACK:
+ return process_ver_ack(lp, vp);
+
+ case LDC_NACK:
+ return process_ver_nack(lp, vp);
+
+ default:
+ return ldc_abort(lp);
+ }
+}
+
+static int process_rts(struct ldc_channel *lp,
+ struct ldc_packet *p)
+{
+ ldcdbg(HS, "GOT RTS stype[%x] seqid[%x] env[%x]\n",
+ p->stype, p->seqid, p->env);
+
+ if (p->stype != LDC_INFO ||
+ lp->hs_state != LDC_HS_GOTVERS ||
+ p->env != lp->cfg.mode)
+ return ldc_abort(lp);
+
+ lp->snd_nxt = p->seqid;
+ lp->rcv_nxt = p->seqid;
+ lp->hs_state = LDC_HS_SENTRTR;
+ if (send_rtr(lp))
+ return ldc_abort(lp);
+
+ return 0;
+}
+
+static int process_rtr(struct ldc_channel *lp,
+ struct ldc_packet *p)
+{
+ ldcdbg(HS, "GOT RTR stype[%x] seqid[%x] env[%x]\n",
+ p->stype, p->seqid, p->env);
+
+ if (p->stype != LDC_INFO ||
+ p->env != lp->cfg.mode)
+ return ldc_abort(lp);
+
+ lp->snd_nxt = p->seqid;
+ lp->hs_state = LDC_HS_COMPLETE;
+ ldc_set_state(lp, LDC_STATE_CONNECTED);
+ send_rdx(lp);
+
+ return LDC_EVENT_UP;
+}
+
+static int rx_seq_ok(struct ldc_channel *lp, u32 seqid)
+{
+ return lp->rcv_nxt + 1 == seqid;
+}
+
+static int process_rdx(struct ldc_channel *lp,
+ struct ldc_packet *p)
+{
+ ldcdbg(HS, "GOT RDX stype[%x] seqid[%x] env[%x] ackid[%x]\n",
+ p->stype, p->seqid, p->env, p->u.r.ackid);
+
+ if (p->stype != LDC_INFO ||
+ !(rx_seq_ok(lp, p->seqid)))
+ return ldc_abort(lp);
+
+ lp->rcv_nxt = p->seqid;
+
+ lp->hs_state = LDC_HS_COMPLETE;
+ ldc_set_state(lp, LDC_STATE_CONNECTED);
+
+ return LDC_EVENT_UP;
+}
+
+static int process_control_frame(struct ldc_channel *lp,
+ struct ldc_packet *p)
+{
+ switch (p->ctrl) {
+ case LDC_VERS:
+ return process_version(lp, p);
+
+ case LDC_RTS:
+ return process_rts(lp, p);
+
+ case LDC_RTR:
+ return process_rtr(lp, p);
+
+ case LDC_RDX:
+ return process_rdx(lp, p);
+
+ default:
+ return ldc_abort(lp);
+ }
+}
+
+static int process_error_frame(struct ldc_channel *lp,
+ struct ldc_packet *p)
+{
+ return ldc_abort(lp);
+}
+
+static int process_data_ack(struct ldc_channel *lp,
+ struct ldc_packet *ack)
+{
+ unsigned long head = lp->tx_acked;
+ u32 ackid = ack->u.r.ackid;
+
+ while (1) {
+ struct ldc_packet *p = lp->tx_base + (head / LDC_PACKET_SIZE);
+
+ head = tx_advance(lp, head);
+
+ if (p->seqid == ackid) {
+ lp->tx_acked = head;
+ return 0;
+ }
+ if (head == lp->tx_tail)
+ return ldc_abort(lp);
+ }
+
+ return 0;
+}
+
+static void send_events(struct ldc_channel *lp, unsigned int event_mask)
+{
+ if (event_mask & LDC_EVENT_RESET)
+ lp->cfg.event(lp->event_arg, LDC_EVENT_RESET);
+ if (event_mask & LDC_EVENT_UP)
+ lp->cfg.event(lp->event_arg, LDC_EVENT_UP);
+ if (event_mask & LDC_EVENT_DATA_READY)
+ lp->cfg.event(lp->event_arg, LDC_EVENT_DATA_READY);
+}
+
+static irqreturn_t ldc_rx(int irq, void *dev_id)
+{
+ struct ldc_channel *lp = dev_id;
+ unsigned long orig_state, hv_err, flags;
+ unsigned int event_mask;
+
+ spin_lock_irqsave(&lp->lock, flags);
+
+ orig_state = lp->chan_state;
+ hv_err = sun4v_ldc_rx_get_state(lp->id,
+ &lp->rx_head,
+ &lp->rx_tail,
+ &lp->chan_state);
+
+ ldcdbg(RX, "RX state[0x%02lx:0x%02lx] head[0x%04lx] tail[0x%04lx]\n",
+ orig_state, lp->chan_state, lp->rx_head, lp->rx_tail);
+
+ event_mask = 0;
+
+ if (lp->cfg.mode == LDC_MODE_RAW &&
+ lp->chan_state == LDC_CHANNEL_UP) {
+ lp->hs_state = LDC_HS_COMPLETE;
+ ldc_set_state(lp, LDC_STATE_CONNECTED);
+
+ event_mask |= LDC_EVENT_UP;
+
+ orig_state = lp->chan_state;
+ }
+
+ /* If we are in reset state, flush the RX queue and ignore
+ * everything.
+ */
+ if (lp->flags & LDC_FLAG_RESET) {
+ (void) __set_rx_head(lp, lp->rx_tail);
+ goto out;
+ }
+
+ /* Once we finish the handshake, we let the ldc_read()
+ * paths do all of the control frame and state management.
+ * Just trigger the callback.
+ */
+ if (lp->hs_state == LDC_HS_COMPLETE) {
+handshake_complete:
+ if (lp->chan_state != orig_state) {
+ unsigned int event = LDC_EVENT_RESET;
+
+ if (lp->chan_state == LDC_CHANNEL_UP)
+ event = LDC_EVENT_UP;
+
+ event_mask |= event;
+ }
+ if (lp->rx_head != lp->rx_tail)
+ event_mask |= LDC_EVENT_DATA_READY;
+
+ goto out;
+ }
+
+ if (lp->chan_state != orig_state)
+ goto out;
+
+ while (lp->rx_head != lp->rx_tail) {
+ struct ldc_packet *p;
+ unsigned long new;
+ int err;
+
+ p = lp->rx_base + (lp->rx_head / LDC_PACKET_SIZE);
+
+ switch (p->type) {
+ case LDC_CTRL:
+ err = process_control_frame(lp, p);
+ if (err > 0)
+ event_mask |= err;
+ break;
+
+ case LDC_DATA:
+ event_mask |= LDC_EVENT_DATA_READY;
+ err = 0;
+ break;
+
+ case LDC_ERR:
+ err = process_error_frame(lp, p);
+ break;
+
+ default:
+ err = ldc_abort(lp);
+ break;
+ }
+
+ if (err < 0)
+ break;
+
+ new = lp->rx_head;
+ new += LDC_PACKET_SIZE;
+ if (new == (lp->rx_num_entries * LDC_PACKET_SIZE))
+ new = 0;
+ lp->rx_head = new;
+
+ err = __set_rx_head(lp, new);
+ if (err < 0) {
+ (void) ldc_abort(lp);
+ break;
+ }
+ if (lp->hs_state == LDC_HS_COMPLETE)
+ goto handshake_complete;
+ }
+
+out:
+ spin_unlock_irqrestore(&lp->lock, flags);
+
+ send_events(lp, event_mask);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t ldc_tx(int irq, void *dev_id)
+{
+ struct ldc_channel *lp = dev_id;
+ unsigned long flags, hv_err, orig_state;
+ unsigned int event_mask = 0;
+
+ spin_lock_irqsave(&lp->lock, flags);
+
+ orig_state = lp->chan_state;
+ hv_err = sun4v_ldc_tx_get_state(lp->id,
+ &lp->tx_head,
+ &lp->tx_tail,
+ &lp->chan_state);
+
+ ldcdbg(TX, " TX state[0x%02lx:0x%02lx] head[0x%04lx] tail[0x%04lx]\n",
+ orig_state, lp->chan_state, lp->tx_head, lp->tx_tail);
+
+ if (lp->cfg.mode == LDC_MODE_RAW &&
+ lp->chan_state == LDC_CHANNEL_UP) {
+ lp->hs_state = LDC_HS_COMPLETE;
+ ldc_set_state(lp, LDC_STATE_CONNECTED);
+
+ event_mask |= LDC_EVENT_UP;
+ }
+
+ spin_unlock_irqrestore(&lp->lock, flags);
+
+ send_events(lp, event_mask);
+
+ return IRQ_HANDLED;
+}
+
+/* XXX ldc_alloc() and ldc_free() needs to run under a mutex so
+ * XXX that addition and removal from the ldc_channel_list has
+ * XXX atomicity, otherwise the __ldc_channel_exists() check is
+ * XXX totally pointless as another thread can slip into ldc_alloc()
+ * XXX and add a channel with the same ID. There also needs to be
+ * XXX a spinlock for ldc_channel_list.
+ */
+static HLIST_HEAD(ldc_channel_list);
+
+static int __ldc_channel_exists(unsigned long id)
+{
+ struct ldc_channel *lp;
+ struct hlist_node *n;
+
+ hlist_for_each_entry(lp, n, &ldc_channel_list, list) {
+ if (lp->id == id)
+ return 1;
+ }
+ return 0;
+}
+
+static int alloc_queue(const char *name, unsigned long num_entries,
+ struct ldc_packet **base, unsigned long *ra)
+{
+ unsigned long size, order;
+ void *q;
+
+ size = num_entries * LDC_PACKET_SIZE;
+ order = get_order(size);
+
+ q = (void *) __get_free_pages(GFP_KERNEL, order);
+ if (!q) {
+ printk(KERN_ERR PFX "Alloc of %s queue failed with "
+ "size=%lu order=%lu\n", name, size, order);
+ return -ENOMEM;
+ }
+
+ memset(q, 0, PAGE_SIZE << order);
+
+ *base = q;
+ *ra = __pa(q);
+
+ return 0;
+}
+
+static void free_queue(unsigned long num_entries, struct ldc_packet *q)
+{
+ unsigned long size, order;
+
+ if (!q)
+ return;
+
+ size = num_entries * LDC_PACKET_SIZE;
+ order = get_order(size);
+
+ free_pages((unsigned long)q, order);
+}
+
+/* XXX Make this configurable... XXX */
+#define LDC_IOTABLE_SIZE (8 * 1024)
+
+static int ldc_iommu_init(struct ldc_channel *lp)
+{
+ unsigned long sz, num_tsb_entries, tsbsize, order;
+ struct ldc_iommu *iommu = &lp->iommu;
+ struct ldc_mtable_entry *table;
+ unsigned long hv_err;
+ int err;
+
+ num_tsb_entries = LDC_IOTABLE_SIZE;
+ tsbsize = num_tsb_entries * sizeof(struct ldc_mtable_entry);
+
+ spin_lock_init(&iommu->lock);
+
+ sz = num_tsb_entries / 8;
+ sz = (sz + 7UL) & ~7UL;
+ iommu->arena.map = kzalloc(sz, GFP_KERNEL);
+ if (!iommu->arena.map) {
+ printk(KERN_ERR PFX "Alloc of arena map failed, sz=%lu\n", sz);
+ return -ENOMEM;
+ }
+
+ iommu->arena.limit = num_tsb_entries;
+
+ order = get_order(tsbsize);
+
+ table = (struct ldc_mtable_entry *)
+ __get_free_pages(GFP_KERNEL, order);
+ err = -ENOMEM;
+ if (!table) {
+ printk(KERN_ERR PFX "Alloc of MTE table failed, "
+ "size=%lu order=%lu\n", tsbsize, order);
+ goto out_free_map;
+ }
+
+ memset(table, 0, PAGE_SIZE << order);
+
+ iommu->page_table = table;
+
+ hv_err = sun4v_ldc_set_map_table(lp->id, __pa(table),
+ num_tsb_entries);
+ err = -EINVAL;
+ if (hv_err)
+ goto out_free_table;
+
+ return 0;
+
+out_free_table:
+ free_pages((unsigned long) table, order);
+ iommu->page_table = NULL;
+
+out_free_map:
+ kfree(iommu->arena.map);
+ iommu->arena.map = NULL;
+
+ return err;
+}
+
+static void ldc_iommu_release(struct ldc_channel *lp)
+{
+ struct ldc_iommu *iommu = &lp->iommu;
+ unsigned long num_tsb_entries, tsbsize, order;
+
+ (void) sun4v_ldc_set_map_table(lp->id, 0, 0);
+
+ num_tsb_entries = iommu->arena.limit;
+ tsbsize = num_tsb_entries * sizeof(struct ldc_mtable_entry);
+ order = get_order(tsbsize);
+
+ free_pages((unsigned long) iommu->page_table, order);
+ iommu->page_table = NULL;
+
+ kfree(iommu->arena.map);
+ iommu->arena.map = NULL;
+}
+
+struct ldc_channel *ldc_alloc(unsigned long id,
+ const struct ldc_channel_config *cfgp,
+ void *event_arg)
+{
+ struct ldc_channel *lp;
+ const struct ldc_mode_ops *mops;
+ unsigned long dummy1, dummy2, hv_err;
+ u8 mss, *mssbuf;
+ int err;
+
+ err = -ENODEV;
+ if (!ldom_domaining_enabled)
+ goto out_err;
+
+ err = -EINVAL;
+ if (!cfgp)
+ goto out_err;
+
+ switch (cfgp->mode) {
+ case LDC_MODE_RAW:
+ mops = &raw_ops;
+ mss = LDC_PACKET_SIZE;
+ break;
+
+ case LDC_MODE_UNRELIABLE:
+ mops = &nonraw_ops;
+ mss = LDC_PACKET_SIZE - 8;
+ break;
+
+ case LDC_MODE_STREAM:
+ mops = &stream_ops;
+ mss = LDC_PACKET_SIZE - 8 - 8;
+ break;
+
+ default:
+ goto out_err;
+ }
+
+ if (!cfgp->event || !event_arg || !cfgp->rx_irq || !cfgp->tx_irq)
+ goto out_err;
+
+ hv_err = sun4v_ldc_tx_qinfo(id, &dummy1, &dummy2);
+ err = -ENODEV;
+ if (hv_err == HV_ECHANNEL)
+ goto out_err;
+
+ err = -EEXIST;
+ if (__ldc_channel_exists(id))
+ goto out_err;
+
+ mssbuf = NULL;
+
+ lp = kzalloc(sizeof(*lp), GFP_KERNEL);
+ err = -ENOMEM;
+ if (!lp)
+ goto out_err;
+
+ spin_lock_init(&lp->lock);
+
+ lp->id = id;
+
+ err = ldc_iommu_init(lp);
+ if (err)
+ goto out_free_ldc;
+
+ lp->mops = mops;
+ lp->mss = mss;
+
+ lp->cfg = *cfgp;
+ if (!lp->cfg.mtu)
+ lp->cfg.mtu = LDC_DEFAULT_MTU;
+
+ if (lp->cfg.mode == LDC_MODE_STREAM) {
+ mssbuf = kzalloc(lp->cfg.mtu, GFP_KERNEL);
+ if (!mssbuf) {
+ err = -ENOMEM;
+ goto out_free_iommu;
+ }
+ lp->mssbuf = mssbuf;
+ }
+
+ lp->event_arg = event_arg;
+
+ /* XXX allow setting via ldc_channel_config to override defaults
+ * XXX or use some formula based upon mtu
+ */
+ lp->tx_num_entries = LDC_DEFAULT_NUM_ENTRIES;
+ lp->rx_num_entries = LDC_DEFAULT_NUM_ENTRIES;
+
+ err = alloc_queue("TX", lp->tx_num_entries,
+ &lp->tx_base, &lp->tx_ra);
+ if (err)
+ goto out_free_mssbuf;
+
+ err = alloc_queue("RX", lp->rx_num_entries,
+ &lp->rx_base, &lp->rx_ra);
+ if (err)
+ goto out_free_txq;
+
+ lp->flags |= LDC_FLAG_ALLOCED_QUEUES;
+
+ lp->hs_state = LDC_HS_CLOSED;
+ ldc_set_state(lp, LDC_STATE_INIT);
+
+ INIT_HLIST_NODE(&lp->list);
+ hlist_add_head(&lp->list, &ldc_channel_list);
+
+ INIT_HLIST_HEAD(&lp->mh_list);
+
+ return lp;
+
+out_free_txq:
+ free_queue(lp->tx_num_entries, lp->tx_base);
+
+out_free_mssbuf:
+ if (mssbuf)
+ kfree(mssbuf);
+
+out_free_iommu:
+ ldc_iommu_release(lp);
+
+out_free_ldc:
+ kfree(lp);
+
+out_err:
+ return ERR_PTR(err);
+}
+EXPORT_SYMBOL(ldc_alloc);
+
+void ldc_free(struct ldc_channel *lp)
+{
+ if (lp->flags & LDC_FLAG_REGISTERED_IRQS) {
+ free_irq(lp->cfg.rx_irq, lp);
+ free_irq(lp->cfg.tx_irq, lp);
+ }
+
+ if (lp->flags & LDC_FLAG_REGISTERED_QUEUES) {
+ sun4v_ldc_tx_qconf(lp->id, 0, 0);
+ sun4v_ldc_rx_qconf(lp->id, 0, 0);
+ lp->flags &= ~LDC_FLAG_REGISTERED_QUEUES;
+ }
+ if (lp->flags & LDC_FLAG_ALLOCED_QUEUES) {
+ free_queue(lp->tx_num_entries, lp->tx_base);
+ free_queue(lp->rx_num_entries, lp->rx_base);
+ lp->flags &= ~LDC_FLAG_ALLOCED_QUEUES;
+ }
+
+ hlist_del(&lp->list);
+
+ if (lp->mssbuf)
+ kfree(lp->mssbuf);
+
+ ldc_iommu_release(lp);
+
+ kfree(lp);
+}
+EXPORT_SYMBOL(ldc_free);
+
+/* Bind the channel. This registers the LDC queues with
+ * the hypervisor and puts the channel into a pseudo-listening
+ * state. This does not initiate a handshake, ldc_connect() does
+ * that.
+ */
+int ldc_bind(struct ldc_channel *lp, const char *name)
+{
+ unsigned long hv_err, flags;
+ int err = -EINVAL;
+
+ if (!name ||
+ (lp->state != LDC_STATE_INIT))
+ return -EINVAL;
+
+ snprintf(lp->rx_irq_name, LDC_IRQ_NAME_MAX, "%s RX", name);
+ snprintf(lp->tx_irq_name, LDC_IRQ_NAME_MAX, "%s TX", name);
+
+ err = request_irq(lp->cfg.rx_irq, ldc_rx,
+ IRQF_SAMPLE_RANDOM | IRQF_SHARED,
+ lp->rx_irq_name, lp);
+ if (err)
+ return err;
+
+ err = request_irq(lp->cfg.tx_irq, ldc_tx,
+ IRQF_SAMPLE_RANDOM | IRQF_SHARED,
+ lp->tx_irq_name, lp);
+ if (err) {
+ free_irq(lp->cfg.rx_irq, lp);
+ return err;
+ }
+
+
+ spin_lock_irqsave(&lp->lock, flags);
+
+ enable_irq(lp->cfg.rx_irq);
+ enable_irq(lp->cfg.tx_irq);
+
+ lp->flags |= LDC_FLAG_REGISTERED_IRQS;
+
+ err = -ENODEV;
+ hv_err = sun4v_ldc_tx_qconf(lp->id, 0, 0);
+ if (hv_err)
+ goto out_free_irqs;
+
+ hv_err = sun4v_ldc_tx_qconf(lp->id, lp->tx_ra, lp->tx_num_entries);
+ if (hv_err)
+ goto out_free_irqs;
+
+ hv_err = sun4v_ldc_rx_qconf(lp->id, 0, 0);
+ if (hv_err)
+ goto out_unmap_tx;
+
+ hv_err = sun4v_ldc_rx_qconf(lp->id, lp->rx_ra, lp->rx_num_entries);
+ if (hv_err)
+ goto out_unmap_tx;
+
+ lp->flags |= LDC_FLAG_REGISTERED_QUEUES;
+
+ hv_err = sun4v_ldc_tx_get_state(lp->id,
+ &lp->tx_head,
+ &lp->tx_tail,
+ &lp->chan_state);
+ err = -EBUSY;
+ if (hv_err)
+ goto out_unmap_rx;
+
+ lp->tx_acked = lp->tx_head;
+
+ lp->hs_state = LDC_HS_OPEN;
+ ldc_set_state(lp, LDC_STATE_BOUND);
+
+ spin_unlock_irqrestore(&lp->lock, flags);
+
+ return 0;
+
+out_unmap_rx:
+ lp->flags &= ~LDC_FLAG_REGISTERED_QUEUES;
+ sun4v_ldc_rx_qconf(lp->id, 0, 0);
+
+out_unmap_tx:
+ sun4v_ldc_tx_qconf(lp->id, 0, 0);
+
+out_free_irqs:
+ lp->flags &= ~LDC_FLAG_REGISTERED_IRQS;
+ free_irq(lp->cfg.tx_irq, lp);
+ free_irq(lp->cfg.rx_irq, lp);
+
+ spin_unlock_irqrestore(&lp->lock, flags);
+
+ return err;
+}
+EXPORT_SYMBOL(ldc_bind);
+
+int ldc_connect(struct ldc_channel *lp)
+{
+ unsigned long flags;
+ int err;
+
+ if (lp->cfg.mode == LDC_MODE_RAW)
+ return -EINVAL;
+
+ spin_lock_irqsave(&lp->lock, flags);
+
+ if (!(lp->flags & LDC_FLAG_ALLOCED_QUEUES) ||
+ !(lp->flags & LDC_FLAG_REGISTERED_QUEUES) ||
+ lp->hs_state != LDC_HS_OPEN)
+ err = -EINVAL;
+ else
+ err = start_handshake(lp);
+
+ spin_unlock_irqrestore(&lp->lock, flags);
+
+ return err;
+}
+EXPORT_SYMBOL(ldc_connect);
+
+int ldc_disconnect(struct ldc_channel *lp)
+{
+ unsigned long hv_err, flags;
+ int err;
+
+ if (lp->cfg.mode == LDC_MODE_RAW)
+ return -EINVAL;
+
+ if (!(lp->flags & LDC_FLAG_ALLOCED_QUEUES) ||
+ !(lp->flags & LDC_FLAG_REGISTERED_QUEUES))
+ return -EINVAL;
+
+ spin_lock_irqsave(&lp->lock, flags);
+
+ err = -ENODEV;
+ hv_err = sun4v_ldc_tx_qconf(lp->id, 0, 0);
+ if (hv_err)
+ goto out_err;
+
+ hv_err = sun4v_ldc_tx_qconf(lp->id, lp->tx_ra, lp->tx_num_entries);
+ if (hv_err)
+ goto out_err;
+
+ hv_err = sun4v_ldc_rx_qconf(lp->id, 0, 0);
+ if (hv_err)
+ goto out_err;
+
+ hv_err = sun4v_ldc_rx_qconf(lp->id, lp->rx_ra, lp->rx_num_entries);
+ if (hv_err)
+ goto out_err;
+
+ ldc_set_state(lp, LDC_STATE_BOUND);
+ lp->hs_state = LDC_HS_OPEN;
+ lp->flags |= LDC_FLAG_RESET;
+
+ spin_unlock_irqrestore(&lp->lock, flags);
+
+ return 0;
+
+out_err:
+ sun4v_ldc_tx_qconf(lp->id, 0, 0);
+ sun4v_ldc_rx_qconf(lp->id, 0, 0);
+ free_irq(lp->cfg.tx_irq, lp);
+ free_irq(lp->cfg.rx_irq, lp);
+ lp->flags &= ~(LDC_FLAG_REGISTERED_IRQS |
+ LDC_FLAG_REGISTERED_QUEUES);
+ ldc_set_state(lp, LDC_STATE_INIT);
+
+ spin_unlock_irqrestore(&lp->lock, flags);
+
+ return err;
+}
+EXPORT_SYMBOL(ldc_disconnect);
+
+int ldc_state(struct ldc_channel *lp)
+{
+ return lp->state;
+}
+EXPORT_SYMBOL(ldc_state);
+
+static int write_raw(struct ldc_channel *lp, const void *buf, unsigned int size)
+{
+ struct ldc_packet *p;
+ unsigned long new_tail;
+ int err;
+
+ if (size > LDC_PACKET_SIZE)
+ return -EMSGSIZE;
+
+ p = data_get_tx_packet(lp, &new_tail);
+ if (!p)
+ return -EAGAIN;
+
+ memcpy(p, buf, size);
+
+ err = send_tx_packet(lp, p, new_tail);
+ if (!err)
+ err = size;
+
+ return err;
+}
+
+static int read_raw(struct ldc_channel *lp, void *buf, unsigned int size)
+{
+ struct ldc_packet *p;
+ unsigned long hv_err, new;
+ int err;
+
+ if (size < LDC_PACKET_SIZE)
+ return -EINVAL;
+
+ hv_err = sun4v_ldc_rx_get_state(lp->id,
+ &lp->rx_head,
+ &lp->rx_tail,
+ &lp->chan_state);
+ if (hv_err)
+ return ldc_abort(lp);
+
+ if (lp->chan_state == LDC_CHANNEL_DOWN ||
+ lp->chan_state == LDC_CHANNEL_RESETTING)
+ return -ECONNRESET;
+
+ if (lp->rx_head == lp->rx_tail)
+ return 0;
+
+ p = lp->rx_base + (lp->rx_head / LDC_PACKET_SIZE);
+ memcpy(buf, p, LDC_PACKET_SIZE);
+
+ new = rx_advance(lp, lp->rx_head);
+ lp->rx_head = new;
+
+ err = __set_rx_head(lp, new);
+ if (err < 0)
+ err = -ECONNRESET;
+ else
+ err = LDC_PACKET_SIZE;
+
+ return err;
+}
+
+static const struct ldc_mode_ops raw_ops = {
+ .write = write_raw,
+ .read = read_raw,
+};
+
+static int write_nonraw(struct ldc_channel *lp, const void *buf,
+ unsigned int size)
+{
+ unsigned long hv_err, tail;
+ unsigned int copied;
+ u32 seq;
+ int err;
+
+ hv_err = sun4v_ldc_tx_get_state(lp->id, &lp->tx_head, &lp->tx_tail,
+ &lp->chan_state);
+ if (unlikely(hv_err))
+ return -EBUSY;
+
+ if (unlikely(lp->chan_state != LDC_CHANNEL_UP))
+ return ldc_abort(lp);
+
+ if (!tx_has_space_for(lp, size))
+ return -EAGAIN;
+
+ seq = lp->snd_nxt;
+ copied = 0;
+ tail = lp->tx_tail;
+ while (copied < size) {
+ struct ldc_packet *p = lp->tx_base + (tail / LDC_PACKET_SIZE);
+ u8 *data = ((lp->cfg.mode == LDC_MODE_UNRELIABLE) ?
+ p->u.u_data :
+ p->u.r.r_data);
+ int data_len;
+
+ p->type = LDC_DATA;
+ p->stype = LDC_INFO;
+ p->ctrl = 0;
+
+ data_len = size - copied;
+ if (data_len > lp->mss)
+ data_len = lp->mss;
+
+ BUG_ON(data_len > LDC_LEN);
+
+ p->env = (data_len |
+ (copied == 0 ? LDC_START : 0) |
+ (data_len == size - copied ? LDC_STOP : 0));
+
+ p->seqid = ++seq;
+
+ ldcdbg(DATA, "SENT DATA [%02x:%02x:%02x:%02x:%08x]\n",
+ p->type,
+ p->stype,
+ p->ctrl,
+ p->env,
+ p->seqid);
+
+ memcpy(data, buf, data_len);
+ buf += data_len;
+ copied += data_len;
+
+ tail = tx_advance(lp, tail);
+ }
+
+ err = set_tx_tail(lp, tail);
+ if (!err) {
+ lp->snd_nxt = seq;
+ err = size;
+ }
+
+ return err;
+}
+
+static int rx_bad_seq(struct ldc_channel *lp, struct ldc_packet *p,
+ struct ldc_packet *first_frag)
+{
+ int err;
+
+ if (first_frag)
+ lp->rcv_nxt = first_frag->seqid - 1;
+
+ err = send_data_nack(lp, p);
+ if (err)
+ return err;
+
+ err = __set_rx_head(lp, lp->rx_tail);
+ if (err < 0)
+ return ldc_abort(lp);
+
+ return 0;
+}
+
+static int data_ack_nack(struct ldc_channel *lp, struct ldc_packet *p)
+{
+ if (p->stype & LDC_ACK) {
+ int err = process_data_ack(lp, p);
+ if (err)
+ return err;
+ }
+ if (p->stype & LDC_NACK)
+ return ldc_abort(lp);
+
+ return 0;
+}
+
+static int rx_data_wait(struct ldc_channel *lp, unsigned long cur_head)
+{
+ unsigned long dummy;
+ int limit = 1000;
+
+ ldcdbg(DATA, "DATA WAIT cur_head[%lx] rx_head[%lx] rx_tail[%lx]\n",
+ cur_head, lp->rx_head, lp->rx_tail);
+ while (limit-- > 0) {
+ unsigned long hv_err;
+
+ hv_err = sun4v_ldc_rx_get_state(lp->id,
+ &dummy,
+ &lp->rx_tail,
+ &lp->chan_state);
+ if (hv_err)
+ return ldc_abort(lp);
+
+ if (lp->chan_state == LDC_CHANNEL_DOWN ||
+ lp->chan_state == LDC_CHANNEL_RESETTING)
+ return -ECONNRESET;
+
+ if (cur_head != lp->rx_tail) {
+ ldcdbg(DATA, "DATA WAIT DONE "
+ "head[%lx] tail[%lx] chan_state[%lx]\n",
+ dummy, lp->rx_tail, lp->chan_state);
+ return 0;
+ }
+
+ udelay(1);
+ }
+ return -EAGAIN;
+}
+
+static int rx_set_head(struct ldc_channel *lp, unsigned long head)
+{
+ int err = __set_rx_head(lp, head);
+
+ if (err < 0)
+ return ldc_abort(lp);
+
+ lp->rx_head = head;
+ return 0;
+}
+
+static void send_data_ack(struct ldc_channel *lp)
+{
+ unsigned long new_tail;
+ struct ldc_packet *p;
+
+ p = data_get_tx_packet(lp, &new_tail);
+ if (likely(p)) {
+ int err;
+
+ memset(p, 0, sizeof(*p));
+ p->type = LDC_DATA;
+ p->stype = LDC_ACK;
+ p->ctrl = 0;
+ p->seqid = lp->snd_nxt + 1;
+ p->u.r.ackid = lp->rcv_nxt;
+
+ err = send_tx_packet(lp, p, new_tail);
+ if (!err)
+ lp->snd_nxt++;
+ }
+}
+
+static int read_nonraw(struct ldc_channel *lp, void *buf, unsigned int size)
+{
+ struct ldc_packet *first_frag;
+ unsigned long hv_err, new;
+ int err, copied;
+
+ hv_err = sun4v_ldc_rx_get_state(lp->id,
+ &lp->rx_head,
+ &lp->rx_tail,
+ &lp->chan_state);
+ if (hv_err)
+ return ldc_abort(lp);
+
+ if (lp->chan_state == LDC_CHANNEL_DOWN ||
+ lp->chan_state == LDC_CHANNEL_RESETTING)
+ return -ECONNRESET;
+
+ if (lp->rx_head == lp->rx_tail)
+ return 0;
+
+ first_frag = NULL;
+ copied = err = 0;
+ new = lp->rx_head;
+ while (1) {
+ struct ldc_packet *p;
+ int pkt_len;
+
+ BUG_ON(new == lp->rx_tail);
+ p = lp->rx_base + (new / LDC_PACKET_SIZE);
+
+ ldcdbg(RX, "RX read pkt[%02x:%02x:%02x:%02x:%08x:%08x] "
+ "rcv_nxt[%08x]\n",
+ p->type,
+ p->stype,
+ p->ctrl,
+ p->env,
+ p->seqid,
+ p->u.r.ackid,
+ lp->rcv_nxt);
+
+ if (unlikely(!rx_seq_ok(lp, p->seqid))) {
+ err = rx_bad_seq(lp, p, first_frag);
+ copied = 0;
+ break;
+ }
+
+ if (p->type & LDC_CTRL) {
+ err = process_control_frame(lp, p);
+ if (err < 0)
+ break;
+ err = 0;
+ }
+
+ lp->rcv_nxt = p->seqid;
+
+ if (!(p->type & LDC_DATA)) {
+ new = rx_advance(lp, new);
+ goto no_data;
+ }
+ if (p->stype & (LDC_ACK | LDC_NACK)) {
+ err = data_ack_nack(lp, p);
+ if (err)
+ break;
+ }
+ if (!(p->stype & LDC_INFO)) {
+ new = rx_advance(lp, new);
+ err = rx_set_head(lp, new);
+ if (err)
+ break;
+ goto no_data;
+ }
+
+ pkt_len = p->env & LDC_LEN;
+
+ /* Every initial packet starts with the START bit set.
+ *
+ * Singleton packets will have both START+STOP set.
+ *
+ * Fragments will have START set in the first frame, STOP
+ * set in the last frame, and neither bit set in middle
+ * frames of the packet.
+ *
+ * Therefore if we are at the beginning of a packet and
+ * we don't see START, or we are in the middle of a fragmented
+ * packet and do see START, we are unsynchronized and should
+ * flush the RX queue.
+ */
+ if ((first_frag == NULL && !(p->env & LDC_START)) ||
+ (first_frag != NULL && (p->env & LDC_START))) {
+ if (!first_frag)
+ new = rx_advance(lp, new);
+
+ err = rx_set_head(lp, new);
+ if (err)
+ break;
+
+ if (!first_frag)
+ goto no_data;
+ }
+ if (!first_frag)
+ first_frag = p;
+
+ if (pkt_len > size - copied) {
+ /* User didn't give us a big enough buffer,
+ * what to do? This is a pretty serious error.
+ *
+ * Since we haven't updated the RX ring head to
+ * consume any of the packets, signal the error
+ * to the user and just leave the RX ring alone.
+ *
+ * This seems the best behavior because this allows
+ * a user of the LDC layer to start with a small
+ * RX buffer for ldc_read() calls and use -EMSGSIZE
+ * as a cue to enlarge it's read buffer.
+ */
+ err = -EMSGSIZE;
+ break;
+ }
+
+ /* Ok, we are gonna eat this one. */
+ new = rx_advance(lp, new);
+
+ memcpy(buf,
+ (lp->cfg.mode == LDC_MODE_UNRELIABLE ?
+ p->u.u_data : p->u.r.r_data), pkt_len);
+ buf += pkt_len;
+ copied += pkt_len;
+
+ if (p->env & LDC_STOP)
+ break;
+
+no_data:
+ if (new == lp->rx_tail) {
+ err = rx_data_wait(lp, new);
+ if (err)
+ break;
+ }
+ }
+
+ if (!err)
+ err = rx_set_head(lp, new);
+
+ if (err && first_frag)
+ lp->rcv_nxt = first_frag->seqid - 1;
+
+ if (!err) {
+ err = copied;
+ if (err > 0 && lp->cfg.mode != LDC_MODE_UNRELIABLE)
+ send_data_ack(lp);
+ }
+
+ return err;
+}
+
+static const struct ldc_mode_ops nonraw_ops = {
+ .write = write_nonraw,
+ .read = read_nonraw,
+};
+
+static int write_stream(struct ldc_channel *lp, const void *buf,
+ unsigned int size)
+{
+ if (size > lp->cfg.mtu)
+ size = lp->cfg.mtu;
+ return write_nonraw(lp, buf, size);
+}
+
+static int read_stream(struct ldc_channel *lp, void *buf, unsigned int size)
+{
+ if (!lp->mssbuf_len) {
+ int err = read_nonraw(lp, lp->mssbuf, lp->cfg.mtu);
+ if (err < 0)
+ return err;
+
+ lp->mssbuf_len = err;
+ lp->mssbuf_off = 0;
+ }
+
+ if (size > lp->mssbuf_len)
+ size = lp->mssbuf_len;
+ memcpy(buf, lp->mssbuf + lp->mssbuf_off, size);
+
+ lp->mssbuf_off += size;
+ lp->mssbuf_len -= size;
+
+ return size;
+}
+
+static const struct ldc_mode_ops stream_ops = {
+ .write = write_stream,
+ .read = read_stream,
+};
+
+int ldc_write(struct ldc_channel *lp, const void *buf, unsigned int size)
+{
+ unsigned long flags;
+ int err;
+
+ if (!buf)
+ return -EINVAL;
+
+ if (!size)
+ return 0;
+
+ spin_lock_irqsave(&lp->lock, flags);
+
+ if (lp->hs_state != LDC_HS_COMPLETE)
+ err = -ENOTCONN;
+ else
+ err = lp->mops->write(lp, buf, size);
+
+ spin_unlock_irqrestore(&lp->lock, flags);
+
+ return err;
+}
+EXPORT_SYMBOL(ldc_write);
+
+int ldc_read(struct ldc_channel *lp, void *buf, unsigned int size)
+{
+ unsigned long flags;
+ int err;
+
+ if (!buf)
+ return -EINVAL;
+
+ if (!size)
+ return 0;
+
+ spin_lock_irqsave(&lp->lock, flags);
+
+ if (lp->hs_state != LDC_HS_COMPLETE)
+ err = -ENOTCONN;
+ else
+ err = lp->mops->read(lp, buf, size);
+
+ spin_unlock_irqrestore(&lp->lock, flags);
+
+ return err;
+}
+EXPORT_SYMBOL(ldc_read);
+
+static long arena_alloc(struct ldc_iommu *iommu, unsigned long npages)
+{
+ struct iommu_arena *arena = &iommu->arena;
+ unsigned long n, i, start, end, limit;
+ int pass;
+
+ limit = arena->limit;
+ start = arena->hint;
+ pass = 0;
+
+again:
+ n = find_next_zero_bit(arena->map, limit, start);
+ end = n + npages;
+ if (unlikely(end >= limit)) {
+ if (likely(pass < 1)) {
+ limit = start;
+ start = 0;
+ pass++;
+ goto again;
+ } else {
+ /* Scanned the whole thing, give up. */
+ return -1;
+ }
+ }
+
+ for (i = n; i < end; i++) {
+ if (test_bit(i, arena->map)) {
+ start = i + 1;
+ goto again;
+ }
+ }
+
+ for (i = n; i < end; i++)
+ __set_bit(i, arena->map);
+
+ arena->hint = end;
+
+ return n;
+}
+
+#define COOKIE_PGSZ_CODE 0xf000000000000000ULL
+#define COOKIE_PGSZ_CODE_SHIFT 60ULL
+
+static u64 pagesize_code(void)
+{
+ switch (PAGE_SIZE) {
+ default:
+ case (8ULL * 1024ULL):
+ return 0;
+ case (64ULL * 1024ULL):
+ return 1;
+ case (512ULL * 1024ULL):
+ return 2;
+ case (4ULL * 1024ULL * 1024ULL):
+ return 3;
+ case (32ULL * 1024ULL * 1024ULL):
+ return 4;
+ case (256ULL * 1024ULL * 1024ULL):
+ return 5;
+ }
+}
+
+static u64 make_cookie(u64 index, u64 pgsz_code, u64 page_offset)
+{
+ return ((pgsz_code << COOKIE_PGSZ_CODE_SHIFT) |
+ (index << PAGE_SHIFT) |
+ page_offset);
+}
+
+static u64 cookie_to_index(u64 cookie, unsigned long *shift)
+{
+ u64 szcode = cookie >> COOKIE_PGSZ_CODE_SHIFT;
+
+ cookie &= ~COOKIE_PGSZ_CODE;
+
+ *shift = szcode * 3;
+
+ return (cookie >> (13ULL + (szcode * 3ULL)));
+}
+
+static struct ldc_mtable_entry *alloc_npages(struct ldc_iommu *iommu,
+ unsigned long npages)
+{
+ long entry;
+
+ entry = arena_alloc(iommu, npages);
+ if (unlikely(entry < 0))
+ return NULL;
+
+ return iommu->page_table + entry;
+}
+
+static u64 perm_to_mte(unsigned int map_perm)
+{
+ u64 mte_base;
+
+ mte_base = pagesize_code();
+
+ if (map_perm & LDC_MAP_SHADOW) {
+ if (map_perm & LDC_MAP_R)
+ mte_base |= LDC_MTE_COPY_R;
+ if (map_perm & LDC_MAP_W)
+ mte_base |= LDC_MTE_COPY_W;
+ }
+ if (map_perm & LDC_MAP_DIRECT) {
+ if (map_perm & LDC_MAP_R)
+ mte_base |= LDC_MTE_READ;
+ if (map_perm & LDC_MAP_W)
+ mte_base |= LDC_MTE_WRITE;
+ if (map_perm & LDC_MAP_X)
+ mte_base |= LDC_MTE_EXEC;
+ }
+ if (map_perm & LDC_MAP_IO) {
+ if (map_perm & LDC_MAP_R)
+ mte_base |= LDC_MTE_IOMMU_R;
+ if (map_perm & LDC_MAP_W)
+ mte_base |= LDC_MTE_IOMMU_W;
+ }
+
+ return mte_base;
+}
+
+static int pages_in_region(unsigned long base, long len)
+{
+ int count = 0;
+
+ do {
+ unsigned long new = (base + PAGE_SIZE) & PAGE_MASK;
+
+ len -= (new - base);
+ base = new;
+ count++;
+ } while (len > 0);
+
+ return count;
+}
+
+struct cookie_state {
+ struct ldc_mtable_entry *page_table;
+ struct ldc_trans_cookie *cookies;
+ u64 mte_base;
+ u64 prev_cookie;
+ u32 pte_idx;
+ u32 nc;
+};
+
+static void fill_cookies(struct cookie_state *sp, unsigned long pa,
+ unsigned long off, unsigned long len)
+{
+ do {
+ unsigned long tlen, new = pa + PAGE_SIZE;
+ u64 this_cookie;
+
+ sp->page_table[sp->pte_idx].mte = sp->mte_base | pa;
+
+ tlen = PAGE_SIZE;
+ if (off)
+ tlen = PAGE_SIZE - off;
+ if (tlen > len)
+ tlen = len;
+
+ this_cookie = make_cookie(sp->pte_idx,
+ pagesize_code(), off);
+
+ off = 0;
+
+ if (this_cookie == sp->prev_cookie)