aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/Kconfig4
-rw-r--r--arch/powerpc/Kconfig.debug5
-rw-r--r--arch/powerpc/Makefile7
-rw-r--r--arch/powerpc/configs/cell_defconfig133
-rw-r--r--arch/powerpc/configs/mpc8540_ads_defconfig43
-rw-r--r--arch/powerpc/kernel/Makefile11
-rw-r--r--arch/powerpc/kernel/asm-offsets.c2
-rw-r--r--arch/powerpc/kernel/cpu_setup_6xx.S474
-rw-r--r--arch/powerpc/kernel/entry_32.S8
-rw-r--r--arch/powerpc/kernel/entry_64.S6
-rw-r--r--arch/powerpc/kernel/firmware.c4
-rw-r--r--arch/powerpc/kernel/head_64.S32
-rw-r--r--arch/powerpc/kernel/idle.c (renamed from arch/powerpc/kernel/idle_64.c)79
-rw-r--r--arch/powerpc/kernel/idle_6xx.S18
-rw-r--r--arch/powerpc/kernel/idle_power4.S38
-rw-r--r--arch/powerpc/kernel/l2cr_6xx.S471
-rw-r--r--arch/powerpc/kernel/legacy_serial.c42
-rw-r--r--arch/powerpc/kernel/module_32.c320
-rw-r--r--arch/powerpc/kernel/nvram_64.c7
-rw-r--r--arch/powerpc/kernel/paca.c21
-rw-r--r--arch/powerpc/kernel/pci_32.c4
-rw-r--r--arch/powerpc/kernel/pci_64.c1
-rw-r--r--arch/powerpc/kernel/perfmon_fsl_booke.c222
-rw-r--r--arch/powerpc/kernel/proc_ppc64.c3
-rw-r--r--arch/powerpc/kernel/process.c11
-rw-r--r--arch/powerpc/kernel/prom.c154
-rw-r--r--arch/powerpc/kernel/prom_init.c68
-rw-r--r--arch/powerpc/kernel/rtas-proc.c2
-rw-r--r--arch/powerpc/kernel/rtas.c4
-rw-r--r--arch/powerpc/kernel/setup-common.c68
-rw-r--r--arch/powerpc/kernel/setup_32.c73
-rw-r--r--arch/powerpc/kernel/setup_64.c72
-rw-r--r--arch/powerpc/kernel/signal_32.c1
-rw-r--r--arch/powerpc/kernel/signal_64.c3
-rw-r--r--arch/powerpc/kernel/swsusp_32.S349
-rw-r--r--arch/powerpc/kernel/syscalls.c1
-rw-r--r--arch/powerpc/kernel/sysfs.c6
-rw-r--r--arch/powerpc/kernel/tau_6xx.c271
-rw-r--r--arch/powerpc/kernel/traps.c35
-rw-r--r--arch/powerpc/kernel/vdso.c9
-rw-r--r--arch/powerpc/kernel/vmlinux.lds.S381
-rw-r--r--arch/powerpc/lib/sstep.c2
-rw-r--r--arch/powerpc/math-emu/Makefile13
-rw-r--r--arch/powerpc/math-emu/double.h129
-rw-r--r--arch/powerpc/math-emu/fabs.c18
-rw-r--r--arch/powerpc/math-emu/fadd.c38
-rw-r--r--arch/powerpc/math-emu/fadds.c39
-rw-r--r--arch/powerpc/math-emu/fcmpo.c46
-rw-r--r--arch/powerpc/math-emu/fcmpu.c42
-rw-r--r--arch/powerpc/math-emu/fctiw.c25
-rw-r--r--arch/powerpc/math-emu/fctiwz.c32
-rw-r--r--arch/powerpc/math-emu/fdiv.c53
-rw-r--r--arch/powerpc/math-emu/fdivs.c55
-rw-r--r--arch/powerpc/math-emu/fmadd.c48
-rw-r--r--arch/powerpc/math-emu/fmadds.c49
-rw-r--r--arch/powerpc/math-emu/fmr.c18
-rw-r--r--arch/powerpc/math-emu/fmsub.c51
-rw-r--r--arch/powerpc/math-emu/fmsubs.c52
-rw-r--r--arch/powerpc/math-emu/fmul.c42
-rw-r--r--arch/powerpc/math-emu/fmuls.c43
-rw-r--r--arch/powerpc/math-emu/fnabs.c18
-rw-r--r--arch/powerpc/math-emu/fneg.c18
-rw-r--r--arch/powerpc/math-emu/fnmadd.c51
-rw-r--r--arch/powerpc/math-emu/fnmadds.c52
-rw-r--r--arch/powerpc/math-emu/fnmsub.c54
-rw-r--r--arch/powerpc/math-emu/fnmsubs.c55
-rw-r--r--arch/powerpc/math-emu/fres.c12
-rw-r--r--arch/powerpc/math-emu/frsp.c25
-rw-r--r--arch/powerpc/math-emu/frsqrte.c12
-rw-r--r--arch/powerpc/math-emu/fsel.c38
-rw-r--r--arch/powerpc/math-emu/fsqrt.c37
-rw-r--r--arch/powerpc/math-emu/fsqrts.c38
-rw-r--r--arch/powerpc/math-emu/fsub.c41
-rw-r--r--arch/powerpc/math-emu/fsubs.c42
-rw-r--r--arch/powerpc/math-emu/lfd.c19
-rw-r--r--arch/powerpc/math-emu/lfs.c37
-rw-r--r--arch/powerpc/math-emu/math.c483
-rw-r--r--arch/powerpc/math-emu/mcrfs.c31
-rw-r--r--arch/powerpc/math-emu/mffs.c17
-rw-r--r--arch/powerpc/math-emu/mtfsb0.c18
-rw-r--r--arch/powerpc/math-emu/mtfsb1.c18
-rw-r--r--arch/powerpc/math-emu/mtfsf.c45
-rw-r--r--arch/powerpc/math-emu/mtfsfi.c23
-rw-r--r--arch/powerpc/math-emu/op-1.h245
-rw-r--r--arch/powerpc/math-emu/op-2.h433
-rw-r--r--arch/powerpc/math-emu/op-4.h297
-rw-r--r--arch/powerpc/math-emu/op-common.h688
-rw-r--r--arch/powerpc/math-emu/sfp-machine.h377
-rw-r--r--arch/powerpc/math-emu/single.h66
-rw-r--r--arch/powerpc/math-emu/soft-fp.h104
-rw-r--r--arch/powerpc/math-emu/stfd.c20
-rw-r--r--arch/powerpc/math-emu/stfiwx.c16
-rw-r--r--arch/powerpc/math-emu/stfs.c41
-rw-r--r--arch/powerpc/math-emu/types.c51
-rw-r--r--arch/powerpc/math-emu/udivmodti4.c191
-rw-r--r--arch/powerpc/mm/hash_utils_64.c7
-rw-r--r--arch/powerpc/mm/mem.c2
-rw-r--r--arch/powerpc/mm/numa.c2
-rw-r--r--arch/powerpc/platforms/85xx/Kconfig1
-rw-r--r--arch/powerpc/platforms/cell/Kconfig5
-rw-r--r--arch/powerpc/platforms/cell/Makefile10
-rw-r--r--arch/powerpc/platforms/cell/interrupt.c131
-rw-r--r--arch/powerpc/platforms/cell/interrupt.h2
-rw-r--r--arch/powerpc/platforms/cell/iommu.c16
-rw-r--r--arch/powerpc/platforms/cell/pervasive.c2
-rw-r--r--arch/powerpc/platforms/cell/setup.c11
-rw-r--r--arch/powerpc/platforms/cell/spider-pic.c108
-rw-r--r--arch/powerpc/platforms/cell/spu_base.c17
-rw-r--r--arch/powerpc/platforms/cell/spu_callbacks.c345
-rw-r--r--arch/powerpc/platforms/cell/spufs/backing_ops.c47
-rw-r--r--arch/powerpc/platforms/cell/spufs/context.c24
-rw-r--r--arch/powerpc/platforms/cell/spufs/file.c523
-rw-r--r--arch/powerpc/platforms/cell/spufs/hw_ops.c57
-rw-r--r--arch/powerpc/platforms/cell/spufs/inode.c6
-rw-r--r--arch/powerpc/platforms/cell/spufs/run.c91
-rw-r--r--arch/powerpc/platforms/cell/spufs/sched.c2
-rw-r--r--arch/powerpc/platforms/cell/spufs/spufs.h28
-rw-r--r--arch/powerpc/platforms/cell/spufs/switch.c3
-rw-r--r--arch/powerpc/platforms/chrp/chrp.h2
-rw-r--r--arch/powerpc/platforms/chrp/setup.c77
-rw-r--r--arch/powerpc/platforms/iseries/setup.c13
-rw-r--r--arch/powerpc/platforms/maple/setup.c10
-rw-r--r--arch/powerpc/platforms/powermac/bootx_init.c6
-rw-r--r--arch/powerpc/platforms/powermac/feature.c2
-rw-r--r--arch/powerpc/platforms/powermac/low_i2c.c3
-rw-r--r--arch/powerpc/platforms/powermac/nvram.c14
-rw-r--r--arch/powerpc/platforms/powermac/pci.c5
-rw-r--r--arch/powerpc/platforms/powermac/pfunc_base.c2
-rw-r--r--arch/powerpc/platforms/powermac/setup.c74
-rw-r--r--arch/powerpc/platforms/powermac/time.c4
-rw-r--r--arch/powerpc/platforms/powermac/udbg_scc.c2
-rw-r--r--arch/powerpc/platforms/pseries/eeh.c2
-rw-r--r--arch/powerpc/platforms/pseries/eeh_driver.c16
-rw-r--r--arch/powerpc/platforms/pseries/firmware.c2
-rw-r--r--arch/powerpc/platforms/pseries/hvconsole.c5
-rw-r--r--arch/powerpc/platforms/pseries/pci.c2
-rw-r--r--arch/powerpc/platforms/pseries/pci_dlpar.c11
-rw-r--r--arch/powerpc/platforms/pseries/ras.c2
-rw-r--r--arch/powerpc/platforms/pseries/reconfig.c5
-rw-r--r--arch/powerpc/platforms/pseries/rtasd.c3
-rw-r--r--arch/powerpc/platforms/pseries/setup.c231
-rw-r--r--arch/powerpc/platforms/pseries/xics.c2
142 files changed, 8842 insertions, 1064 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index a433b7126d33..2cdc35ce8045 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -491,7 +491,7 @@ config PPC601_SYNC_FIX
491 If in doubt, say Y here. 491 If in doubt, say Y here.
492 492
493config TAU 493config TAU
494 bool "Thermal Management Support" 494 bool "On-chip CPU temperature sensor support"
495 depends on 6xx 495 depends on 6xx
496 help 496 help
497 G3 and G4 processors have an on-chip temperature sensor called the 497 G3 and G4 processors have an on-chip temperature sensor called the
@@ -500,7 +500,7 @@ config TAU
500 on-die temperature in /proc/cpuinfo if the cpu supports it. 500 on-die temperature in /proc/cpuinfo if the cpu supports it.
501 501
502 Unfortunately, on some chip revisions, this sensor is very inaccurate 502 Unfortunately, on some chip revisions, this sensor is very inaccurate
503 and in some cases, does not work at all, so don't assume the cpu 503 and in many cases, does not work at all, so don't assume the cpu
504 temp is actually what /proc/cpuinfo says it is. 504 temp is actually what /proc/cpuinfo says it is.
505 505
506config TAU_INT 506config TAU_INT
diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug
index 9254806f7032..8d48e9e7162a 100644
--- a/arch/powerpc/Kconfig.debug
+++ b/arch/powerpc/Kconfig.debug
@@ -110,11 +110,6 @@ config SERIAL_TEXT_DEBUG
110 depends on 4xx || LOPEC || MV64X60 || PPLUS || PRPMC800 || \ 110 depends on 4xx || LOPEC || MV64X60 || PPLUS || PRPMC800 || \
111 PPC_GEN550 || PPC_MPC52xx 111 PPC_GEN550 || PPC_MPC52xx
112 112
113config PPC_OCP
114 bool
115 depends on IBM_OCP || XILINX_OCP
116 default y
117
118choice 113choice
119 prompt "Early debugging (dangerous)" 114 prompt "Early debugging (dangerous)"
120 bool 115 bool
diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
index 829e017b8a54..6ec84d37a337 100644
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -129,13 +129,8 @@ core-y += arch/powerpc/kernel/ \
129 arch/powerpc/lib/ \ 129 arch/powerpc/lib/ \
130 arch/powerpc/sysdev/ \ 130 arch/powerpc/sysdev/ \
131 arch/powerpc/platforms/ 131 arch/powerpc/platforms/
132core-$(CONFIG_PPC32) += arch/ppc/kernel/ 132core-$(CONFIG_MATH_EMULATION) += arch/powerpc/math-emu/
133core-$(CONFIG_MATH_EMULATION) += arch/ppc/math-emu/
134core-$(CONFIG_XMON) += arch/powerpc/xmon/ 133core-$(CONFIG_XMON) += arch/powerpc/xmon/
135core-$(CONFIG_APUS) += arch/ppc/amiga/
136drivers-$(CONFIG_8xx) += arch/ppc/8xx_io/
137drivers-$(CONFIG_4xx) += arch/ppc/4xx_io/
138drivers-$(CONFIG_CPM2) += arch/ppc/8260_io/
139 134
140drivers-$(CONFIG_OPROFILE) += arch/powerpc/oprofile/ 135drivers-$(CONFIG_OPROFILE) += arch/powerpc/oprofile/
141 136
diff --git a/arch/powerpc/configs/cell_defconfig b/arch/powerpc/configs/cell_defconfig
index 3c2acab63736..fe22e54ab2b0 100644
--- a/arch/powerpc/configs/cell_defconfig
+++ b/arch/powerpc/configs/cell_defconfig
@@ -1,7 +1,7 @@
1# 1#
2# Automatically generated make config: don't edit 2# Automatically generated make config: don't edit
3# Linux kernel version: 2.6.16-rc6 3# Linux kernel version: 2.6.16
4# Wed Mar 15 16:19:48 2006 4# Thu Mar 23 20:48:09 2006
5# 5#
6CONFIG_PPC64=y 6CONFIG_PPC64=y
7CONFIG_64BIT=y 7CONFIG_64BIT=y
@@ -30,6 +30,7 @@ CONFIG_POWER4=y
30CONFIG_PPC_FPU=y 30CONFIG_PPC_FPU=y
31CONFIG_ALTIVEC=y 31CONFIG_ALTIVEC=y
32CONFIG_PPC_STD_MMU=y 32CONFIG_PPC_STD_MMU=y
33CONFIG_VIRT_CPU_ACCOUNTING=y
33CONFIG_SMP=y 34CONFIG_SMP=y
34CONFIG_NR_CPUS=4 35CONFIG_NR_CPUS=4
35 36
@@ -51,7 +52,8 @@ CONFIG_SYSVIPC=y
51# CONFIG_BSD_PROCESS_ACCT is not set 52# CONFIG_BSD_PROCESS_ACCT is not set
52CONFIG_SYSCTL=y 53CONFIG_SYSCTL=y
53# CONFIG_AUDIT is not set 54# CONFIG_AUDIT is not set
54# CONFIG_IKCONFIG is not set 55CONFIG_IKCONFIG=y
56CONFIG_IKCONFIG_PROC=y
55# CONFIG_CPUSETS is not set 57# CONFIG_CPUSETS is not set
56CONFIG_INITRAMFS_SOURCE="" 58CONFIG_INITRAMFS_SOURCE=""
57CONFIG_CC_OPTIMIZE_FOR_SIZE=y 59CONFIG_CC_OPTIMIZE_FOR_SIZE=y
@@ -85,7 +87,7 @@ CONFIG_MODULE_UNLOAD=y
85CONFIG_OBSOLETE_MODPARM=y 87CONFIG_OBSOLETE_MODPARM=y
86# CONFIG_MODVERSIONS is not set 88# CONFIG_MODVERSIONS is not set
87# CONFIG_MODULE_SRCVERSION_ALL is not set 89# CONFIG_MODULE_SRCVERSION_ALL is not set
88# CONFIG_KMOD is not set 90CONFIG_KMOD=y
89CONFIG_STOP_MACHINE=y 91CONFIG_STOP_MACHINE=y
90 92
91# 93#
@@ -130,7 +132,8 @@ CONFIG_CELL_IIC=y
130# 132#
131# Cell Broadband Engine options 133# Cell Broadband Engine options
132# 134#
133CONFIG_SPU_FS=y 135CONFIG_SPU_FS=m
136CONFIG_SPUFS_MMAP=y
134 137
135# 138#
136# Kernel options 139# Kernel options
@@ -144,7 +147,7 @@ CONFIG_PREEMPT_NONE=y
144# CONFIG_PREEMPT is not set 147# CONFIG_PREEMPT is not set
145CONFIG_PREEMPT_BKL=y 148CONFIG_PREEMPT_BKL=y
146CONFIG_BINFMT_ELF=y 149CONFIG_BINFMT_ELF=y
147# CONFIG_BINFMT_MISC is not set 150CONFIG_BINFMT_MISC=m
148CONFIG_FORCE_MAX_ZONEORDER=13 151CONFIG_FORCE_MAX_ZONEORDER=13
149# CONFIG_IOMMU_VMERGE is not set 152# CONFIG_IOMMU_VMERGE is not set
150CONFIG_KEXEC=y 153CONFIG_KEXEC=y
@@ -155,13 +158,16 @@ CONFIG_ARCH_SELECT_MEMORY_MODEL=y
155CONFIG_ARCH_FLATMEM_ENABLE=y 158CONFIG_ARCH_FLATMEM_ENABLE=y
156CONFIG_ARCH_SPARSEMEM_ENABLE=y 159CONFIG_ARCH_SPARSEMEM_ENABLE=y
157CONFIG_SELECT_MEMORY_MODEL=y 160CONFIG_SELECT_MEMORY_MODEL=y
158CONFIG_FLATMEM_MANUAL=y 161# CONFIG_FLATMEM_MANUAL is not set
159# CONFIG_DISCONTIGMEM_MANUAL is not set 162# CONFIG_DISCONTIGMEM_MANUAL is not set
160# CONFIG_SPARSEMEM_MANUAL is not set 163CONFIG_SPARSEMEM_MANUAL=y
161CONFIG_FLATMEM=y 164CONFIG_SPARSEMEM=y
162CONFIG_FLAT_NODE_MEM_MAP=y 165CONFIG_HAVE_MEMORY_PRESENT=y
163# CONFIG_SPARSEMEM_STATIC is not set 166# CONFIG_SPARSEMEM_STATIC is not set
167CONFIG_SPARSEMEM_EXTREME=y
168# CONFIG_MEMORY_HOTPLUG is not set
164CONFIG_SPLIT_PTLOCK_CPUS=4 169CONFIG_SPLIT_PTLOCK_CPUS=4
170CONFIG_MIGRATION=y
165# CONFIG_PPC_64K_PAGES is not set 171# CONFIG_PPC_64K_PAGES is not set
166CONFIG_SCHED_SMT=y 172CONFIG_SCHED_SMT=y
167CONFIG_PROC_DEVICETREE=y 173CONFIG_PROC_DEVICETREE=y
@@ -232,6 +238,7 @@ CONFIG_TCP_CONG_BIC=y
232# CONFIG_IP_VS is not set 238# CONFIG_IP_VS is not set
233CONFIG_IPV6=y 239CONFIG_IPV6=y
234# CONFIG_IPV6_PRIVACY is not set 240# CONFIG_IPV6_PRIVACY is not set
241# CONFIG_IPV6_ROUTER_PREF is not set
235CONFIG_INET6_AH=m 242CONFIG_INET6_AH=m
236CONFIG_INET6_ESP=m 243CONFIG_INET6_ESP=m
237CONFIG_INET6_IPCOMP=m 244CONFIG_INET6_IPCOMP=m
@@ -244,25 +251,7 @@ CONFIG_NETFILTER=y
244# Core Netfilter Configuration 251# Core Netfilter Configuration
245# 252#
246# CONFIG_NETFILTER_NETLINK is not set 253# CONFIG_NETFILTER_NETLINK is not set
247CONFIG_NETFILTER_XTABLES=m 254# CONFIG_NETFILTER_XTABLES is not set
248CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
249CONFIG_NETFILTER_XT_TARGET_MARK=m
250CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
251CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
252CONFIG_NETFILTER_XT_MATCH_COMMENT=m
253CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
254# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
255CONFIG_NETFILTER_XT_MATCH_HELPER=m
256CONFIG_NETFILTER_XT_MATCH_LENGTH=m
257CONFIG_NETFILTER_XT_MATCH_LIMIT=m
258CONFIG_NETFILTER_XT_MATCH_MAC=m
259CONFIG_NETFILTER_XT_MATCH_MARK=m
260CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
261CONFIG_NETFILTER_XT_MATCH_REALM=m
262CONFIG_NETFILTER_XT_MATCH_SCTP=m
263CONFIG_NETFILTER_XT_MATCH_STATE=m
264CONFIG_NETFILTER_XT_MATCH_STRING=m
265CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
266 255
267# 256#
268# IP: Netfilter Configuration 257# IP: Netfilter Configuration
@@ -278,51 +267,13 @@ CONFIG_IP_NF_IRC=m
278CONFIG_IP_NF_TFTP=m 267CONFIG_IP_NF_TFTP=m
279CONFIG_IP_NF_AMANDA=m 268CONFIG_IP_NF_AMANDA=m
280# CONFIG_IP_NF_PPTP is not set 269# CONFIG_IP_NF_PPTP is not set
270# CONFIG_IP_NF_H323 is not set
281CONFIG_IP_NF_QUEUE=m 271CONFIG_IP_NF_QUEUE=m
282CONFIG_IP_NF_IPTABLES=m
283CONFIG_IP_NF_MATCH_IPRANGE=m
284CONFIG_IP_NF_MATCH_MULTIPORT=m
285CONFIG_IP_NF_MATCH_TOS=m
286CONFIG_IP_NF_MATCH_RECENT=m
287CONFIG_IP_NF_MATCH_ECN=m
288CONFIG_IP_NF_MATCH_DSCP=m
289CONFIG_IP_NF_MATCH_AH_ESP=m
290CONFIG_IP_NF_MATCH_TTL=m
291CONFIG_IP_NF_MATCH_OWNER=m
292CONFIG_IP_NF_MATCH_ADDRTYPE=m
293CONFIG_IP_NF_MATCH_HASHLIMIT=m
294CONFIG_IP_NF_MATCH_POLICY=m
295CONFIG_IP_NF_FILTER=m
296CONFIG_IP_NF_TARGET_REJECT=m
297CONFIG_IP_NF_TARGET_LOG=m
298CONFIG_IP_NF_TARGET_ULOG=m
299CONFIG_IP_NF_TARGET_TCPMSS=m
300CONFIG_IP_NF_NAT=m
301CONFIG_IP_NF_NAT_NEEDED=y
302CONFIG_IP_NF_TARGET_MASQUERADE=m
303CONFIG_IP_NF_TARGET_REDIRECT=m
304CONFIG_IP_NF_TARGET_NETMAP=m
305CONFIG_IP_NF_TARGET_SAME=m
306CONFIG_IP_NF_NAT_SNMP_BASIC=m
307CONFIG_IP_NF_NAT_IRC=m
308CONFIG_IP_NF_NAT_FTP=m
309CONFIG_IP_NF_NAT_TFTP=m
310CONFIG_IP_NF_NAT_AMANDA=m
311CONFIG_IP_NF_MANGLE=m
312CONFIG_IP_NF_TARGET_TOS=m
313CONFIG_IP_NF_TARGET_ECN=m
314CONFIG_IP_NF_TARGET_DSCP=m
315CONFIG_IP_NF_TARGET_TTL=m
316CONFIG_IP_NF_RAW=m
317CONFIG_IP_NF_ARPTABLES=m
318CONFIG_IP_NF_ARPFILTER=m
319CONFIG_IP_NF_ARP_MANGLE=m
320 272
321# 273#
322# IPv6: Netfilter Configuration (EXPERIMENTAL) 274# IPv6: Netfilter Configuration (EXPERIMENTAL)
323# 275#
324# CONFIG_IP6_NF_QUEUE is not set 276# CONFIG_IP6_NF_QUEUE is not set
325# CONFIG_IP6_NF_IPTABLES is not set
326 277
327# 278#
328# DCCP Configuration (EXPERIMENTAL) 279# DCCP Configuration (EXPERIMENTAL)
@@ -355,7 +306,6 @@ CONFIG_IP_NF_ARP_MANGLE=m
355# QoS and/or fair queueing 306# QoS and/or fair queueing
356# 307#
357# CONFIG_NET_SCHED is not set 308# CONFIG_NET_SCHED is not set
358CONFIG_NET_CLS_ROUTE=y
359 309
360# 310#
361# Network testing 311# Network testing
@@ -408,7 +358,7 @@ CONFIG_FW_LOADER=y
408# CONFIG_BLK_DEV_COW_COMMON is not set 358# CONFIG_BLK_DEV_COW_COMMON is not set
409CONFIG_BLK_DEV_LOOP=y 359CONFIG_BLK_DEV_LOOP=y
410# CONFIG_BLK_DEV_CRYPTOLOOP is not set 360# CONFIG_BLK_DEV_CRYPTOLOOP is not set
411CONFIG_BLK_DEV_NBD=y 361# CONFIG_BLK_DEV_NBD is not set
412# CONFIG_BLK_DEV_SX8 is not set 362# CONFIG_BLK_DEV_SX8 is not set
413CONFIG_BLK_DEV_RAM=y 363CONFIG_BLK_DEV_RAM=y
414CONFIG_BLK_DEV_RAM_COUNT=16 364CONFIG_BLK_DEV_RAM_COUNT=16
@@ -484,7 +434,23 @@ CONFIG_IDEDMA_AUTO=y
484# 434#
485# Multi-device support (RAID and LVM) 435# Multi-device support (RAID and LVM)
486# 436#
487# CONFIG_MD is not set 437CONFIG_MD=y
438CONFIG_BLK_DEV_MD=m
439CONFIG_MD_LINEAR=m
440CONFIG_MD_RAID0=m
441CONFIG_MD_RAID1=m
442# CONFIG_MD_RAID10 is not set
443# CONFIG_MD_RAID5 is not set
444# CONFIG_MD_RAID6 is not set
445# CONFIG_MD_MULTIPATH is not set
446# CONFIG_MD_FAULTY is not set
447CONFIG_BLK_DEV_DM=m
448CONFIG_DM_CRYPT=m
449CONFIG_DM_SNAPSHOT=m
450CONFIG_DM_MIRROR=m
451CONFIG_DM_ZERO=m
452CONFIG_DM_MULTIPATH=m
453# CONFIG_DM_MULTIPATH_EMC is not set
488 454
489# 455#
490# Fusion MPT device support 456# Fusion MPT device support
@@ -548,7 +514,7 @@ CONFIG_MII=y
548# CONFIG_ACENIC is not set 514# CONFIG_ACENIC is not set
549# CONFIG_DL2K is not set 515# CONFIG_DL2K is not set
550CONFIG_E1000=m 516CONFIG_E1000=m
551# CONFIG_E1000_NAPI is not set 517CONFIG_E1000_NAPI=y
552# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set 518# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
553# CONFIG_NS83820 is not set 519# CONFIG_NS83820 is not set
554# CONFIG_HAMACHI is not set 520# CONFIG_HAMACHI is not set
@@ -560,7 +526,7 @@ CONFIG_SKGE=m
560# CONFIG_SK98LIN is not set 526# CONFIG_SK98LIN is not set
561# CONFIG_TIGON3 is not set 527# CONFIG_TIGON3 is not set
562# CONFIG_BNX2 is not set 528# CONFIG_BNX2 is not set
563CONFIG_SPIDER_NET=y 529CONFIG_SPIDER_NET=m
564# CONFIG_MV643XX_ETH is not set 530# CONFIG_MV643XX_ETH is not set
565 531
566# 532#
@@ -678,6 +644,8 @@ CONFIG_SERIAL_CORE_CONSOLE=y
678# CONFIG_SERIAL_JSM is not set 644# CONFIG_SERIAL_JSM is not set
679CONFIG_UNIX98_PTYS=y 645CONFIG_UNIX98_PTYS=y
680# CONFIG_LEGACY_PTYS is not set 646# CONFIG_LEGACY_PTYS is not set
647CONFIG_HVC_DRIVER=y
648CONFIG_HVC_RTAS=y
681 649
682# 650#
683# IPMI 651# IPMI
@@ -694,14 +662,13 @@ CONFIG_WATCHDOG=y
694# Watchdog Device Drivers 662# Watchdog Device Drivers
695# 663#
696# CONFIG_SOFT_WATCHDOG is not set 664# CONFIG_SOFT_WATCHDOG is not set
697# CONFIG_WATCHDOG_RTAS is not set 665CONFIG_WATCHDOG_RTAS=y
698 666
699# 667#
700# PCI-based Watchdog Cards 668# PCI-based Watchdog Cards
701# 669#
702# CONFIG_PCIPCWATCHDOG is not set 670# CONFIG_PCIPCWATCHDOG is not set
703# CONFIG_WDTPCI is not set 671# CONFIG_WDTPCI is not set
704# CONFIG_RTC is not set
705CONFIG_GEN_RTC=y 672CONFIG_GEN_RTC=y
706# CONFIG_GEN_RTC_X is not set 673# CONFIG_GEN_RTC_X is not set
707# CONFIG_DTLK is not set 674# CONFIG_DTLK is not set
@@ -833,6 +800,7 @@ CONFIG_DUMMY_CONSOLE=y
833# 800#
834CONFIG_USB_ARCH_HAS_HCD=y 801CONFIG_USB_ARCH_HAS_HCD=y
835CONFIG_USB_ARCH_HAS_OHCI=y 802CONFIG_USB_ARCH_HAS_OHCI=y
803CONFIG_USB_ARCH_HAS_EHCI=y
836# CONFIG_USB is not set 804# CONFIG_USB is not set
837 805
838# 806#
@@ -852,7 +820,14 @@ CONFIG_USB_ARCH_HAS_OHCI=y
852# 820#
853# InfiniBand support 821# InfiniBand support
854# 822#
855# CONFIG_INFINIBAND is not set 823CONFIG_INFINIBAND=y
824CONFIG_INFINIBAND_USER_MAD=m
825CONFIG_INFINIBAND_USER_ACCESS=m
826CONFIG_INFINIBAND_MTHCA=m
827CONFIG_INFINIBAND_MTHCA_DEBUG=y
828CONFIG_INFINIBAND_IPOIB=m
829CONFIG_INFINIBAND_IPOIB_DEBUG=y
830CONFIG_INFINIBAND_IPOIB_DEBUG_DATA=y
856 831
857# 832#
858# EDAC - error detection and reporting (RAS) (EXPERIMENTAL) 833# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
@@ -1037,10 +1012,6 @@ CONFIG_CRC32=y
1037# CONFIG_LIBCRC32C is not set 1012# CONFIG_LIBCRC32C is not set
1038CONFIG_ZLIB_INFLATE=m 1013CONFIG_ZLIB_INFLATE=m
1039CONFIG_ZLIB_DEFLATE=m 1014CONFIG_ZLIB_DEFLATE=m
1040CONFIG_TEXTSEARCH=y
1041CONFIG_TEXTSEARCH_KMP=m
1042CONFIG_TEXTSEARCH_BM=m
1043CONFIG_TEXTSEARCH_FSM=m
1044 1015
1045# 1016#
1046# Instrumentation Support 1017# Instrumentation Support
@@ -1058,7 +1029,7 @@ CONFIG_LOG_BUF_SHIFT=15
1058CONFIG_DETECT_SOFTLOCKUP=y 1029CONFIG_DETECT_SOFTLOCKUP=y
1059# CONFIG_SCHEDSTATS is not set 1030# CONFIG_SCHEDSTATS is not set
1060# CONFIG_DEBUG_SLAB is not set 1031# CONFIG_DEBUG_SLAB is not set
1061# CONFIG_DEBUG_MUTEXES is not set 1032CONFIG_DEBUG_MUTEXES=y
1062# CONFIG_DEBUG_SPINLOCK is not set 1033# CONFIG_DEBUG_SPINLOCK is not set
1063CONFIG_DEBUG_SPINLOCK_SLEEP=y 1034CONFIG_DEBUG_SPINLOCK_SLEEP=y
1064# CONFIG_DEBUG_KOBJECT is not set 1035# CONFIG_DEBUG_KOBJECT is not set
diff --git a/arch/powerpc/configs/mpc8540_ads_defconfig b/arch/powerpc/configs/mpc8540_ads_defconfig
index 2a8290ee15c6..7f0780f1aa39 100644
--- a/arch/powerpc/configs/mpc8540_ads_defconfig
+++ b/arch/powerpc/configs/mpc8540_ads_defconfig
@@ -1,7 +1,7 @@
1# 1#
2# Automatically generated make config: don't edit 2# Automatically generated make config: don't edit
3# Linux kernel version: 3# Linux kernel version: 2.6.16
4# Sat Jan 14 15:57:54 2006 4# Mon Mar 27 23:37:36 2006
5# 5#
6# CONFIG_PPC64 is not set 6# CONFIG_PPC64 is not set
7CONFIG_PPC32=y 7CONFIG_PPC32=y
@@ -9,6 +9,7 @@ CONFIG_PPC_MERGE=y
9CONFIG_MMU=y 9CONFIG_MMU=y
10CONFIG_GENERIC_HARDIRQS=y 10CONFIG_GENERIC_HARDIRQS=y
11CONFIG_RWSEM_XCHGADD_ALGORITHM=y 11CONFIG_RWSEM_XCHGADD_ALGORITHM=y
12CONFIG_GENERIC_HWEIGHT=y
12CONFIG_GENERIC_CALIBRATE_DELAY=y 13CONFIG_GENERIC_CALIBRATE_DELAY=y
13CONFIG_PPC=y 14CONFIG_PPC=y
14CONFIG_EARLY_PRINTK=y 15CONFIG_EARLY_PRINTK=y
@@ -18,6 +19,7 @@ CONFIG_ARCH_MAY_HAVE_PC_FDC=y
18CONFIG_PPC_OF=y 19CONFIG_PPC_OF=y
19CONFIG_PPC_UDBG_16550=y 20CONFIG_PPC_UDBG_16550=y
20# CONFIG_GENERIC_TBSYNC is not set 21# CONFIG_GENERIC_TBSYNC is not set
22CONFIG_DEFAULT_UIMAGE=y
21 23
22# 24#
23# Processor support 25# Processor support
@@ -42,7 +44,6 @@ CONFIG_SPE=y
42# Code maturity level options 44# Code maturity level options
43# 45#
44CONFIG_EXPERIMENTAL=y 46CONFIG_EXPERIMENTAL=y
45CONFIG_CLEAN_COMPILE=y
46CONFIG_BROKEN_ON_SMP=y 47CONFIG_BROKEN_ON_SMP=y
47CONFIG_INIT_ENV_ARG_LIMIT=32 48CONFIG_INIT_ENV_ARG_LIMIT=32
48 49
@@ -58,6 +59,7 @@ CONFIG_SYSVIPC=y
58CONFIG_SYSCTL=y 59CONFIG_SYSCTL=y
59# CONFIG_AUDIT is not set 60# CONFIG_AUDIT is not set
60# CONFIG_IKCONFIG is not set 61# CONFIG_IKCONFIG is not set
62# CONFIG_RELAY is not set
61CONFIG_INITRAMFS_SOURCE="" 63CONFIG_INITRAMFS_SOURCE=""
62# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set 64# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
63CONFIG_EMBEDDED=y 65CONFIG_EMBEDDED=y
@@ -72,10 +74,6 @@ CONFIG_BASE_FULL=y
72CONFIG_FUTEX=y 74CONFIG_FUTEX=y
73CONFIG_EPOLL=y 75CONFIG_EPOLL=y
74CONFIG_SHMEM=y 76CONFIG_SHMEM=y
75CONFIG_CC_ALIGN_FUNCTIONS=0
76CONFIG_CC_ALIGN_LABELS=0
77CONFIG_CC_ALIGN_LOOPS=0
78CONFIG_CC_ALIGN_JUMPS=0
79CONFIG_SLAB=y 77CONFIG_SLAB=y
80# CONFIG_TINY_SHMEM is not set 78# CONFIG_TINY_SHMEM is not set
81CONFIG_BASE_SMALL=0 79CONFIG_BASE_SMALL=0
@@ -90,6 +88,8 @@ CONFIG_BASE_SMALL=0
90# Block layer 88# Block layer
91# 89#
92# CONFIG_LBD is not set 90# CONFIG_LBD is not set
91# CONFIG_BLK_DEV_IO_TRACE is not set
92# CONFIG_LSF is not set
93 93
94# 94#
95# IO Schedulers 95# IO Schedulers
@@ -183,6 +183,7 @@ CONFIG_NET=y
183# 183#
184# Networking options 184# Networking options
185# 185#
186# CONFIG_NETDEBUG is not set
186CONFIG_PACKET=y 187CONFIG_PACKET=y
187# CONFIG_PACKET_MMAP is not set 188# CONFIG_PACKET_MMAP is not set
188CONFIG_UNIX=y 189CONFIG_UNIX=y
@@ -220,6 +221,11 @@ CONFIG_TCP_CONG_BIC=y
220# SCTP Configuration (EXPERIMENTAL) 221# SCTP Configuration (EXPERIMENTAL)
221# 222#
222# CONFIG_IP_SCTP is not set 223# CONFIG_IP_SCTP is not set
224
225#
226# TIPC Configuration (EXPERIMENTAL)
227#
228# CONFIG_TIPC is not set
223# CONFIG_ATM is not set 229# CONFIG_ATM is not set
224# CONFIG_BRIDGE is not set 230# CONFIG_BRIDGE is not set
225# CONFIG_VLAN_8021Q is not set 231# CONFIG_VLAN_8021Q is not set
@@ -229,11 +235,6 @@ CONFIG_TCP_CONG_BIC=y
229# CONFIG_ATALK is not set 235# CONFIG_ATALK is not set
230# CONFIG_X25 is not set 236# CONFIG_X25 is not set
231# CONFIG_LAPB is not set 237# CONFIG_LAPB is not set
232
233#
234# TIPC Configuration (EXPERIMENTAL)
235#
236# CONFIG_TIPC is not set
237# CONFIG_NET_DIVERT is not set 238# CONFIG_NET_DIVERT is not set
238# CONFIG_ECONET is not set 239# CONFIG_ECONET is not set
239# CONFIG_WAN_ROUTER is not set 240# CONFIG_WAN_ROUTER is not set
@@ -487,6 +488,12 @@ CONFIG_GEN_RTC=y
487# CONFIG_I2C is not set 488# CONFIG_I2C is not set
488 489
489# 490#
491# SPI support
492#
493# CONFIG_SPI is not set
494# CONFIG_SPI_MASTER is not set
495
496#
490# Dallas's 1-wire bus 497# Dallas's 1-wire bus
491# 498#
492# CONFIG_W1 is not set 499# CONFIG_W1 is not set
@@ -496,6 +503,7 @@ CONFIG_GEN_RTC=y
496# 503#
497CONFIG_HWMON=y 504CONFIG_HWMON=y
498# CONFIG_HWMON_VID is not set 505# CONFIG_HWMON_VID is not set
506# CONFIG_SENSORS_F71805F is not set
499# CONFIG_HWMON_DEBUG_CHIP is not set 507# CONFIG_HWMON_DEBUG_CHIP is not set
500 508
501# 509#
@@ -503,10 +511,6 @@ CONFIG_HWMON=y
503# 511#
504 512
505# 513#
506# Multimedia Capabilities Port drivers
507#
508
509#
510# Multimedia devices 514# Multimedia devices
511# 515#
512# CONFIG_VIDEO_DEV is not set 516# CONFIG_VIDEO_DEV is not set
@@ -531,6 +535,7 @@ CONFIG_HWMON=y
531# 535#
532# CONFIG_USB_ARCH_HAS_HCD is not set 536# CONFIG_USB_ARCH_HAS_HCD is not set
533# CONFIG_USB_ARCH_HAS_OHCI is not set 537# CONFIG_USB_ARCH_HAS_OHCI is not set
538# CONFIG_USB_ARCH_HAS_EHCI is not set
534 539
535# 540#
536# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' 541# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
@@ -551,7 +556,7 @@ CONFIG_HWMON=y
551# 556#
552 557
553# 558#
554# SN Devices 559# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
555# 560#
556 561
557# 562#
@@ -603,7 +608,6 @@ CONFIG_SYSFS=y
603CONFIG_TMPFS=y 608CONFIG_TMPFS=y
604# CONFIG_HUGETLB_PAGE is not set 609# CONFIG_HUGETLB_PAGE is not set
605CONFIG_RAMFS=y 610CONFIG_RAMFS=y
606# CONFIG_RELAYFS_FS is not set
607# CONFIG_CONFIGFS_FS is not set 611# CONFIG_CONFIGFS_FS is not set
608 612
609# 613#
@@ -658,6 +662,7 @@ CONFIG_PARTITION_ADVANCED=y
658# CONFIG_SGI_PARTITION is not set 662# CONFIG_SGI_PARTITION is not set
659# CONFIG_ULTRIX_PARTITION is not set 663# CONFIG_ULTRIX_PARTITION is not set
660# CONFIG_SUN_PARTITION is not set 664# CONFIG_SUN_PARTITION is not set
665# CONFIG_KARMA_PARTITION is not set
661# CONFIG_EFI_PARTITION is not set 666# CONFIG_EFI_PARTITION is not set
662 667
663# 668#
@@ -695,6 +700,8 @@ CONFIG_DEBUG_MUTEXES=y
695# CONFIG_DEBUG_INFO is not set 700# CONFIG_DEBUG_INFO is not set
696# CONFIG_DEBUG_FS is not set 701# CONFIG_DEBUG_FS is not set
697# CONFIG_DEBUG_VM is not set 702# CONFIG_DEBUG_VM is not set
703# CONFIG_UNWIND_INFO is not set
704CONFIG_FORCED_INLINING=y
698# CONFIG_RCU_TORTURE_TEST is not set 705# CONFIG_RCU_TORTURE_TEST is not set
699# CONFIG_DEBUGGER is not set 706# CONFIG_DEBUGGER is not set
700# CONFIG_BDI_SWITCH is not set 707# CONFIG_BDI_SWITCH is not set
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index 80e9fe2632b8..0cc0995b81b0 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -12,12 +12,12 @@ endif
12 12
13obj-y := semaphore.o cputable.o ptrace.o syscalls.o \ 13obj-y := semaphore.o cputable.o ptrace.o syscalls.o \
14 irq.o align.o signal_32.o pmc.o vdso.o \ 14 irq.o align.o signal_32.o pmc.o vdso.o \
15 init_task.o process.o systbl.o 15 init_task.o process.o systbl.o idle.o
16obj-y += vdso32/ 16obj-y += vdso32/
17obj-$(CONFIG_PPC64) += setup_64.o binfmt_elf32.o sys_ppc32.o \ 17obj-$(CONFIG_PPC64) += setup_64.o binfmt_elf32.o sys_ppc32.o \
18 signal_64.o ptrace32.o \ 18 signal_64.o ptrace32.o \
19 paca.o cpu_setup_power4.o \ 19 paca.o cpu_setup_power4.o \
20 firmware.o sysfs.o idle_64.o 20 firmware.o sysfs.o
21obj-$(CONFIG_PPC64) += vdso64/ 21obj-$(CONFIG_PPC64) += vdso64/
22obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o 22obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o
23obj-$(CONFIG_POWER4) += idle_power4.o 23obj-$(CONFIG_POWER4) += idle_power4.o
@@ -34,6 +34,11 @@ obj-$(CONFIG_IBMEBUS) += ibmebus.o
34obj-$(CONFIG_GENERIC_TBSYNC) += smp-tbsync.o 34obj-$(CONFIG_GENERIC_TBSYNC) += smp-tbsync.o
35obj64-$(CONFIG_PPC_MULTIPLATFORM) += nvram_64.o 35obj64-$(CONFIG_PPC_MULTIPLATFORM) += nvram_64.o
36obj-$(CONFIG_CRASH_DUMP) += crash_dump.o 36obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
37obj-$(CONFIG_6xx) += idle_6xx.o l2cr_6xx.o cpu_setup_6xx.o
38obj-$(CONFIG_TAU) += tau_6xx.o
39obj32-$(CONFIG_SOFTWARE_SUSPEND) += swsusp_32.o
40obj32-$(CONFIG_MODULES) += module_32.o
41obj-$(CONFIG_E500) += perfmon_fsl_booke.o
37 42
38ifeq ($(CONFIG_PPC_MERGE),y) 43ifeq ($(CONFIG_PPC_MERGE),y)
39 44
@@ -51,7 +56,6 @@ obj-$(CONFIG_PPC64) += misc_64.o dma_64.o iommu.o
51obj-$(CONFIG_PPC_MULTIPLATFORM) += prom_init.o 56obj-$(CONFIG_PPC_MULTIPLATFORM) += prom_init.o
52obj-$(CONFIG_MODULES) += ppc_ksyms.o 57obj-$(CONFIG_MODULES) += ppc_ksyms.o
53obj-$(CONFIG_BOOTX_TEXT) += btext.o 58obj-$(CONFIG_BOOTX_TEXT) += btext.o
54obj-$(CONFIG_6xx) += idle_6xx.o
55obj-$(CONFIG_SMP) += smp.o 59obj-$(CONFIG_SMP) += smp.o
56obj-$(CONFIG_KPROBES) += kprobes.o 60obj-$(CONFIG_KPROBES) += kprobes.o
57obj-$(CONFIG_PPC_UDBG_16550) += legacy_serial.o udbg_16550.o 61obj-$(CONFIG_PPC_UDBG_16550) += legacy_serial.o udbg_16550.o
@@ -77,6 +81,7 @@ smpobj-$(CONFIG_SMP) += smp.o
77 81
78endif 82endif
79 83
84obj-$(CONFIG_PPC32) += $(obj32-y)
80obj-$(CONFIG_PPC64) += $(obj64-y) 85obj-$(CONFIG_PPC64) += $(obj64-y)
81 86
82extra-$(CONFIG_PPC_FPU) += fpu.o 87extra-$(CONFIG_PPC_FPU) += fpu.o
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 882889b15926..54b48f330051 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -105,8 +105,6 @@ int main(void)
105 DEFINE(ICACHEL1LINESIZE, offsetof(struct ppc64_caches, iline_size)); 105 DEFINE(ICACHEL1LINESIZE, offsetof(struct ppc64_caches, iline_size));
106 DEFINE(ICACHEL1LOGLINESIZE, offsetof(struct ppc64_caches, log_iline_size)); 106 DEFINE(ICACHEL1LOGLINESIZE, offsetof(struct ppc64_caches, log_iline_size));
107 DEFINE(ICACHEL1LINESPERPAGE, offsetof(struct ppc64_caches, ilines_per_page)); 107 DEFINE(ICACHEL1LINESPERPAGE, offsetof(struct ppc64_caches, ilines_per_page));
108 DEFINE(PLATFORM_LPAR, PLATFORM_LPAR);
109
110 /* paca */ 108 /* paca */
111 DEFINE(PACA_SIZE, sizeof(struct paca_struct)); 109 DEFINE(PACA_SIZE, sizeof(struct paca_struct));
112 DEFINE(PACAPACAINDEX, offsetof(struct paca_struct, paca_index)); 110 DEFINE(PACAPACAINDEX, offsetof(struct paca_struct, paca_index));
diff --git a/arch/powerpc/kernel/cpu_setup_6xx.S b/arch/powerpc/kernel/cpu_setup_6xx.S
new file mode 100644
index 000000000000..55ed7716636f
--- /dev/null
+++ b/arch/powerpc/kernel/cpu_setup_6xx.S
@@ -0,0 +1,474 @@
1/*
2 * This file contains low level CPU setup functions.
3 * Copyright (C) 2003 Benjamin Herrenschmidt (benh@kernel.crashing.org)
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version
8 * 2 of the License, or (at your option) any later version.
9 *
10 */
11
12#include <linux/config.h>
13#include <asm/processor.h>
14#include <asm/page.h>
15#include <asm/cputable.h>
16#include <asm/ppc_asm.h>
17#include <asm/asm-offsets.h>
18#include <asm/cache.h>
19
20_GLOBAL(__setup_cpu_603)
21 b setup_common_caches
22_GLOBAL(__setup_cpu_604)
23 mflr r4
24 bl setup_common_caches
25 bl setup_604_hid0
26 mtlr r4
27 blr
28_GLOBAL(__setup_cpu_750)
29 mflr r4
30 bl __init_fpu_registers
31 bl setup_common_caches
32 bl setup_750_7400_hid0
33 mtlr r4
34 blr
35_GLOBAL(__setup_cpu_750cx)
36 mflr r4
37 bl __init_fpu_registers
38 bl setup_common_caches
39 bl setup_750_7400_hid0
40 bl setup_750cx
41 mtlr r4
42 blr
43_GLOBAL(__setup_cpu_750fx)
44 mflr r4
45 bl __init_fpu_registers
46 bl setup_common_caches
47 bl setup_750_7400_hid0
48 bl setup_750fx
49 mtlr r4
50 blr
51_GLOBAL(__setup_cpu_7400)
52 mflr r4
53 bl __init_fpu_registers
54 bl setup_7400_workarounds
55 bl setup_common_caches
56 bl setup_750_7400_hid0
57 mtlr r4
58 blr
59_GLOBAL(__setup_cpu_7410)
60 mflr r4
61 bl __init_fpu_registers
62 bl setup_7410_workarounds
63 bl setup_common_caches
64 bl setup_750_7400_hid0
65 li r3,0
66 mtspr SPRN_L2CR2,r3
67 mtlr r4
68 blr
69_GLOBAL(__setup_cpu_745x)
70 mflr r4
71 bl setup_common_caches
72 bl setup_745x_specifics
73 mtlr r4
74 blr
75
76/* Enable caches for 603's, 604, 750 & 7400 */
77setup_common_caches:
78 mfspr r11,SPRN_HID0
79 andi. r0,r11,HID0_DCE
80 ori r11,r11,HID0_ICE|HID0_DCE
81 ori r8,r11,HID0_ICFI
82 bne 1f /* don't invalidate the D-cache */
83 ori r8,r8,HID0_DCI /* unless it wasn't enabled */
841: sync
85 mtspr SPRN_HID0,r8 /* enable and invalidate caches */
86 sync
87 mtspr SPRN_HID0,r11 /* enable caches */
88 sync
89 isync
90 blr
91
92/* 604, 604e, 604ev, ...
93 * Enable superscalar execution & branch history table
94 */
95setup_604_hid0:
96 mfspr r11,SPRN_HID0
97 ori r11,r11,HID0_SIED|HID0_BHTE
98 ori r8,r11,HID0_BTCD
99 sync
100 mtspr SPRN_HID0,r8 /* flush branch target address cache */
101 sync /* on 604e/604r */
102 mtspr SPRN_HID0,r11
103 sync
104 isync
105 blr
106
107/* 7400 <= rev 2.7 and 7410 rev = 1.0 suffer from some
108 * erratas we work around here.
109 * Moto MPC710CE.pdf describes them, those are errata
110 * #3, #4 and #5
111 * Note that we assume the firmware didn't choose to
112 * apply other workarounds (there are other ones documented
113 * in the .pdf). It appear that Apple firmware only works
114 * around #3 and with the same fix we use. We may want to
115 * check if the CPU is using 60x bus mode in which case
116 * the workaround for errata #4 is useless. Also, we may
117 * want to explicitely clear HID0_NOPDST as this is not
118 * needed once we have applied workaround #5 (though it's
119 * not set by Apple's firmware at least).
120 */
121setup_7400_workarounds:
122 mfpvr r3
123 rlwinm r3,r3,0,20,31
124 cmpwi 0,r3,0x0207
125 ble 1f
126 blr
127setup_7410_workarounds:
128 mfpvr r3
129 rlwinm r3,r3,0,20,31
130 cmpwi 0,r3,0x0100
131 bnelr
1321:
133 mfspr r11,SPRN_MSSSR0
134 /* Errata #3: Set L1OPQ_SIZE to 0x10 */
135 rlwinm r11,r11,0,9,6
136 oris r11,r11,0x0100
137 /* Errata #4: Set L2MQ_SIZE to 1 (check for MPX mode first ?) */
138 oris r11,r11,0x0002
139 /* Errata #5: Set DRLT_SIZE to 0x01 */
140 rlwinm r11,r11,0,5,2
141 oris r11,r11,0x0800
142 sync
143 mtspr SPRN_MSSSR0,r11
144 sync
145 isync
146 blr
147
148/* 740/750/7400/7410
149 * Enable Store Gathering (SGE), Address Brodcast (ABE),
150 * Branch History Table (BHTE), Branch Target ICache (BTIC)
151 * Dynamic Power Management (DPM), Speculative (SPD)
152 * Clear Instruction cache throttling (ICTC)
153 */
154setup_750_7400_hid0:
155 mfspr r11,SPRN_HID0
156 ori r11,r11,HID0_SGE | HID0_ABE | HID0_BHTE | HID0_BTIC
157 oris r11,r11,HID0_DPM@h
158BEGIN_FTR_SECTION
159 xori r11,r11,HID0_BTIC
160END_FTR_SECTION_IFSET(CPU_FTR_NO_BTIC)
161BEGIN_FTR_SECTION
162 xoris r11,r11,HID0_DPM@h /* disable dynamic power mgmt */
163END_FTR_SECTION_IFSET(CPU_FTR_NO_DPM)
164 li r3,HID0_SPD
165 andc r11,r11,r3 /* clear SPD: enable speculative */
166 li r3,0
167 mtspr SPRN_ICTC,r3 /* Instruction Cache Throttling off */
168 isync
169 mtspr SPRN_HID0,r11
170 sync
171 isync
172 blr
173
174/* 750cx specific
175 * Looks like we have to disable NAP feature for some PLL settings...
176 * (waiting for confirmation)
177 */
178setup_750cx:
179 mfspr r10, SPRN_HID1
180 rlwinm r10,r10,4,28,31
181 cmpwi cr0,r10,7
182 cmpwi cr1,r10,9
183 cmpwi cr2,r10,11
184 cror 4*cr0+eq,4*cr0+eq,4*cr1+eq
185 cror 4*cr0+eq,4*cr0+eq,4*cr2+eq
186 bnelr
187 lwz r6,CPU_SPEC_FEATURES(r5)
188 li r7,CPU_FTR_CAN_NAP
189 andc r6,r6,r7
190 stw r6,CPU_SPEC_FEATURES(r5)
191 blr
192
193/* 750fx specific
194 */
195setup_750fx:
196 blr
197
198/* MPC 745x
199 * Enable Store Gathering (SGE), Branch Folding (FOLD)
200 * Branch History Table (BHTE), Branch Target ICache (BTIC)
201 * Dynamic Power Management (DPM), Speculative (SPD)
202 * Ensure our data cache instructions really operate.
203 * Timebase has to be running or we wouldn't have made it here,
204 * just ensure we don't disable it.
205 * Clear Instruction cache throttling (ICTC)
206 * Enable L2 HW prefetch
207 */
208setup_745x_specifics:
209 /* We check for the presence of an L3 cache setup by
210 * the firmware. If any, we disable NAP capability as
211 * it's known to be bogus on rev 2.1 and earlier
212 */
213 mfspr r11,SPRN_L3CR
214 andis. r11,r11,L3CR_L3E@h
215 beq 1f
216 lwz r6,CPU_SPEC_FEATURES(r5)
217 andi. r0,r6,CPU_FTR_L3_DISABLE_NAP
218 beq 1f
219 li r7,CPU_FTR_CAN_NAP
220 andc r6,r6,r7
221 stw r6,CPU_SPEC_FEATURES(r5)
2221:
223 mfspr r11,SPRN_HID0
224
225 /* All of the bits we have to set.....
226 */
227 ori r11,r11,HID0_SGE | HID0_FOLD | HID0_BHTE
228 ori r11,r11,HID0_LRSTK | HID0_BTIC
229 oris r11,r11,HID0_DPM@h
230BEGIN_FTR_SECTION
231 xori r11,r11,HID0_BTIC
232END_FTR_SECTION_IFSET(CPU_FTR_NO_BTIC)
233BEGIN_FTR_SECTION
234 xoris r11,r11,HID0_DPM@h /* disable dynamic power mgmt */
235END_FTR_SECTION_IFSET(CPU_FTR_NO_DPM)
236
237 /* All of the bits we have to clear....
238 */
239 li r3,HID0_SPD | HID0_NOPDST | HID0_NOPTI
240 andc r11,r11,r3 /* clear SPD: enable speculative */
241 li r3,0
242
243 mtspr SPRN_ICTC,r3 /* Instruction Cache Throttling off */
244 isync
245 mtspr SPRN_HID0,r11
246 sync
247 isync
248
249 /* Enable L2 HW prefetch, if L2 is enabled
250 */
251 mfspr r3,SPRN_L2CR
252 andis. r3,r3,L2CR_L2E@h
253 beqlr
254 mfspr r3,SPRN_MSSCR0
255 ori r3,r3,3
256 sync
257 mtspr SPRN_MSSCR0,r3
258 sync
259 isync
260 blr
261
262/*
263 * Initialize the FPU registers. This is needed to work around an errata
264 * in some 750 cpus where using a not yet initialized FPU register after
265 * power on reset may hang the CPU
266 */
267_GLOBAL(__init_fpu_registers)
268 mfmsr r10
269 ori r11,r10,MSR_FP
270 mtmsr r11
271 isync
272 addis r9,r3,empty_zero_page@ha
273 addi r9,r9,empty_zero_page@l
274 REST_32FPRS(0,r9)
275 sync
276 mtmsr r10
277 isync
278 blr
279
280
281/* Definitions for the table use to save CPU states */
282#define CS_HID0 0
283#define CS_HID1 4
284#define CS_HID2 8
285#define CS_MSSCR0 12
286#define CS_MSSSR0 16
287#define CS_ICTRL 20
288#define CS_LDSTCR 24
289#define CS_LDSTDB 28
290#define CS_SIZE 32
291
292 .data
293 .balign L1_CACHE_BYTES
294cpu_state_storage:
295 .space CS_SIZE
296 .balign L1_CACHE_BYTES,0
297 .text
298
299/* Called in normal context to backup CPU 0 state. This
300 * does not include cache settings. This function is also
301 * called for machine sleep. This does not include the MMU
302 * setup, BATs, etc... but rather the "special" registers
303 * like HID0, HID1, MSSCR0, etc...
304 */
305_GLOBAL(__save_cpu_setup)
306 /* Some CR fields are volatile, we back it up all */
307 mfcr r7
308
309 /* Get storage ptr */
310 lis r5,cpu_state_storage@h
311 ori r5,r5,cpu_state_storage@l
312
313 /* Save HID0 (common to all CONFIG_6xx cpus) */
314 mfspr r3,SPRN_HID0
315 stw r3,CS_HID0(r5)
316
317 /* Now deal with CPU type dependent registers */
318 mfspr r3,SPRN_PVR
319 srwi r3,r3,16
320 cmplwi cr0,r3,0x8000 /* 7450 */
321 cmplwi cr1,r3,0x000c /* 7400 */
322 cmplwi cr2,r3,0x800c /* 7410 */
323 cmplwi cr3,r3,0x8001 /* 7455 */
324 cmplwi cr4,r3,0x8002 /* 7457 */
325 cmplwi cr5,r3,0x8003 /* 7447A */
326 cmplwi cr6,r3,0x7000 /* 750FX */
327 cmplwi cr7,r3,0x8004 /* 7448 */
328 /* cr1 is 7400 || 7410 */
329 cror 4*cr1+eq,4*cr1+eq,4*cr2+eq
330 /* cr0 is 74xx */
331 cror 4*cr0+eq,4*cr0+eq,4*cr3+eq
332 cror 4*cr0+eq,4*cr0+eq,4*cr4+eq
333 cror 4*cr0+eq,4*cr0+eq,4*cr1+eq
334 cror 4*cr0+eq,4*cr0+eq,4*cr5+eq
335 cror 4*cr0+eq,4*cr0+eq,4*cr7+eq
336 bne 1f
337 /* Backup 74xx specific regs */
338 mfspr r4,SPRN_MSSCR0
339 stw r4,CS_MSSCR0(r5)
340 mfspr r4,SPRN_MSSSR0
341 stw r4,CS_MSSSR0(r5)
342 beq cr1,1f
343 /* Backup 745x specific registers */
344 mfspr r4,SPRN_HID1
345 stw r4,CS_HID1(r5)
346 mfspr r4,SPRN_ICTRL
347 stw r4,CS_ICTRL(r5)
348 mfspr r4,SPRN_LDSTCR
349 stw r4,CS_LDSTCR(r5)
350 mfspr r4,SPRN_LDSTDB
351 stw r4,CS_LDSTDB(r5)
3521:
353 bne cr6,1f
354 /* Backup 750FX specific registers */
355 mfspr r4,SPRN_HID1
356 stw r4,CS_HID1(r5)
357 /* If rev 2.x, backup HID2 */
358 mfspr r3,SPRN_PVR
359 andi. r3,r3,0xff00
360 cmpwi cr0,r3,0x0200
361 bne 1f
362 mfspr r4,SPRN_HID2
363 stw r4,CS_HID2(r5)
3641:
365 mtcr r7
366 blr
367
368/* Called with no MMU context (typically MSR:IR/DR off) to
369 * restore CPU state as backed up by the previous
370 * function. This does not include cache setting
371 */
372_GLOBAL(__restore_cpu_setup)
373 /* Some CR fields are volatile, we back it up all */
374 mfcr r7
375
376 /* Get storage ptr */
377 lis r5,(cpu_state_storage-KERNELBASE)@h
378 ori r5,r5,cpu_state_storage@l
379
380 /* Restore HID0 */
381 lwz r3,CS_HID0(r5)
382 sync
383 isync
384 mtspr SPRN_HID0,r3
385 sync
386 isync
387
388 /* Now deal with CPU type dependent registers */
389 mfspr r3,SPRN_PVR
390 srwi r3,r3,16
391 cmplwi cr0,r3,0x8000 /* 7450 */
392 cmplwi cr1,r3,0x000c /* 7400 */
393 cmplwi cr2,r3,0x800c /* 7410 */
394 cmplwi cr3,r3,0x8001 /* 7455 */
395 cmplwi cr4,r3,0x8002 /* 7457 */
396 cmplwi cr5,r3,0x8003 /* 7447A */
397 cmplwi cr6,r3,0x7000 /* 750FX */
398 cmplwi cr7,r3,0x8004 /* 7448 */
399 /* cr1 is 7400 || 7410 */
400 cror 4*cr1+eq,4*cr1+eq,4*cr2+eq
401 /* cr0 is 74xx */
402 cror 4*cr0+eq,4*cr0+eq,4*cr3+eq
403 cror 4*cr0+eq,4*cr0+eq,4*cr4+eq
404 cror 4*cr0+eq,4*cr0+eq,4*cr1+eq
405 cror 4*cr0+eq,4*cr0+eq,4*cr5+eq
406 cror 4*cr0+eq,4*cr0+eq,4*cr7+eq
407 bne 2f
408 /* Restore 74xx specific regs */
409 lwz r4,CS_MSSCR0(r5)
410 sync
411 mtspr SPRN_MSSCR0,r4
412 sync
413 isync
414 lwz r4,CS_MSSSR0(r5)
415 sync
416 mtspr SPRN_MSSSR0,r4
417 sync
418 isync
419 bne cr2,1f
420 /* Clear 7410 L2CR2 */
421 li r4,0
422 mtspr SPRN_L2CR2,r4
4231: beq cr1,2f
424 /* Restore 745x specific registers */
425 lwz r4,CS_HID1(r5)
426 sync
427 mtspr SPRN_HID1,r4
428 isync
429 sync
430 lwz r4,CS_ICTRL(r5)
431 sync
432 mtspr SPRN_ICTRL,r4
433 isync
434 sync
435 lwz r4,CS_LDSTCR(r5)
436 sync
437 mtspr SPRN_LDSTCR,r4
438 isync
439 sync
440 lwz r4,CS_LDSTDB(r5)
441 sync
442 mtspr SPRN_LDSTDB,r4
443 isync
444 sync
4452: bne cr6,1f
446 /* Restore 750FX specific registers
447 * that is restore HID2 on rev 2.x and PLL config & switch
448 * to PLL 0 on all
449 */
450 /* If rev 2.x, restore HID2 with low voltage bit cleared */
451 mfspr r3,SPRN_PVR
452 andi. r3,r3,0xff00
453 cmpwi cr0,r3,0x0200
454 bne 4f
455 lwz r4,CS_HID2(r5)
456 rlwinm r4,r4,0,19,17
457 mtspr SPRN_HID2,r4
458 sync
4594:
460 lwz r4,CS_HID1(r5)
461 rlwinm r5,r4,0,16,14
462 mtspr SPRN_HID1,r5
463 /* Wait for PLL to stabilize */
464 mftbl r5
4653: mftbl r6
466 sub r6,r6,r5
467 cmplwi cr0,r6,10000
468 ble 3b
469 /* Setup final PLL */
470 mtspr SPRN_HID1,r4
4711:
472 mtcr r7
473 blr
474
diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S
index 4827ca1ec89b..b3a979467225 100644
--- a/arch/powerpc/kernel/entry_32.S
+++ b/arch/powerpc/kernel/entry_32.S
@@ -135,10 +135,10 @@ transfer_to_handler:
135 mfspr r11,SPRN_HID0 135 mfspr r11,SPRN_HID0
136 mtcr r11 136 mtcr r11
137BEGIN_FTR_SECTION 137BEGIN_FTR_SECTION
138 bt- 8,power_save_6xx_restore /* Check DOZE */ 138 bt- 8,4f /* Check DOZE */
139END_FTR_SECTION_IFSET(CPU_FTR_CAN_DOZE) 139END_FTR_SECTION_IFSET(CPU_FTR_CAN_DOZE)
140BEGIN_FTR_SECTION 140BEGIN_FTR_SECTION
141 bt- 9,power_save_6xx_restore /* Check NAP */ 141 bt- 9,4f /* Check NAP */
142END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP) 142END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP)
143#endif /* CONFIG_6xx */ 143#endif /* CONFIG_6xx */
144 .globl transfer_to_handler_cont 144 .globl transfer_to_handler_cont
@@ -157,6 +157,10 @@ transfer_to_handler_cont:
157 SYNC 157 SYNC
158 RFI /* jump to handler, enable MMU */ 158 RFI /* jump to handler, enable MMU */
159 159
160#ifdef CONFIG_6xx
1614: b power_save_6xx_restore
162#endif
163
160/* 164/*
161 * On kernel stack overflow, load up an initial stack pointer 165 * On kernel stack overflow, load up an initial stack pointer
162 * and call StackOverflow(regs), which should not return. 166 * and call StackOverflow(regs), which should not return.
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index 1060155d84c3..19ad5c6b1818 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -617,6 +617,12 @@ _GLOBAL(enter_rtas)
617 mfsrr1 r10 617 mfsrr1 r10
618 std r10,_SRR1(r1) 618 std r10,_SRR1(r1)
619 619
620 /* Temporary workaround to clear CR until RTAS can be modified to
621 * ignore all bits.
622 */
623 li r0,0
624 mtcr r0
625
620 /* There is no way it is acceptable to get here with interrupts enabled, 626 /* There is no way it is acceptable to get here with interrupts enabled,
621 * check it with the asm equivalent of WARN_ON 627 * check it with the asm equivalent of WARN_ON
622 */ 628 */
diff --git a/arch/powerpc/kernel/firmware.c b/arch/powerpc/kernel/firmware.c
index 4d37a3cb80f6..0bfe9061720a 100644
--- a/arch/powerpc/kernel/firmware.c
+++ b/arch/powerpc/kernel/firmware.c
@@ -14,7 +14,9 @@
14 */ 14 */
15 15
16#include <linux/config.h> 16#include <linux/config.h>
17#include <linux/module.h>
17 18
18#include <asm/firmware.h> 19#include <asm/firmware.h>
19 20
20unsigned long ppc64_firmware_features; 21unsigned long powerpc_firmware_features;
22EXPORT_SYMBOL_GPL(powerpc_firmware_features);
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S
index 35084f3a841b..a5ae04a57c78 100644
--- a/arch/powerpc/kernel/head_64.S
+++ b/arch/powerpc/kernel/head_64.S
@@ -1544,7 +1544,11 @@ _STATIC(__boot_from_prom)
1544 mr r28,r6 1544 mr r28,r6
1545 mr r27,r7 1545 mr r27,r7
1546 1546
1547 /* Align the stack to 16-byte boundary for broken yaboot */ 1547 /*
1548 * Align the stack to 16-byte boundary
1549 * Depending on the size and layout of the ELF sections in the initial
1550 * boot binary, the stack pointer will be unalignet on PowerMac
1551 */
1548 rldicr r1,r1,0,59 1552 rldicr r1,r1,0,59
1549 1553
1550 /* Make sure we are running in 64 bits mode */ 1554 /* Make sure we are running in 64 bits mode */
@@ -1847,21 +1851,6 @@ _STATIC(start_here_multiplatform)
1847 bl .__save_cpu_setup 1851 bl .__save_cpu_setup
1848 sync 1852 sync
1849 1853
1850 /* Setup a valid physical PACA pointer in SPRG3 for early_setup
1851 * note that boot_cpuid can always be 0 nowadays since there is
1852 * nowhere it can be initialized differently before we reach this
1853 * code
1854 */
1855 LOAD_REG_IMMEDIATE(r27, boot_cpuid)
1856 add r27,r27,r26
1857 lwz r27,0(r27)
1858
1859 LOAD_REG_IMMEDIATE(r24, paca) /* Get base vaddr of paca array */
1860 mulli r13,r27,PACA_SIZE /* Calculate vaddr of right paca */
1861 add r13,r13,r24 /* for this processor. */
1862 add r13,r13,r26 /* convert to physical addr */
1863 mtspr SPRN_SPRG3,r13
1864
1865 /* Do very early kernel initializations, including initial hash table, 1854 /* Do very early kernel initializations, including initial hash table,
1866 * stab and slb setup before we turn on relocation. */ 1855 * stab and slb setup before we turn on relocation. */
1867 1856
@@ -1930,6 +1919,17 @@ _STATIC(start_here_common)
1930 /* Not reached */ 1919 /* Not reached */
1931 BUG_OPCODE 1920 BUG_OPCODE
1932 1921
1922/* Put the paca pointer into r13 and SPRG3 */
1923_GLOBAL(setup_boot_paca)
1924 LOAD_REG_IMMEDIATE(r3, boot_cpuid)
1925 lwz r3,0(r3)
1926 LOAD_REG_IMMEDIATE(r4, paca) /* Get base vaddr of paca array */
1927 mulli r3,r3,PACA_SIZE /* Calculate vaddr of right paca */
1928 add r13,r3,r4 /* for this processor. */
1929 mtspr SPRN_SPRG3,r13
1930
1931 blr
1932
1933/* 1933/*
1934 * We put a few things here that have to be page-aligned. 1934 * We put a few things here that have to be page-aligned.
1935 * This stuff goes at the beginning of the bss, which is page-aligned. 1935 * This stuff goes at the beginning of the bss, which is page-aligned.
diff --git a/arch/powerpc/kernel/idle_64.c b/arch/powerpc/kernel/idle.c
index b879d3057ef8..e9f321d74d85 100644
--- a/arch/powerpc/kernel/idle_64.c
+++ b/arch/powerpc/kernel/idle.c
@@ -2,13 +2,17 @@
2 * Idle daemon for PowerPC. Idle daemon will handle any action 2 * Idle daemon for PowerPC. Idle daemon will handle any action
3 * that needs to be taken when the system becomes idle. 3 * that needs to be taken when the system becomes idle.
4 * 4 *
5 * Originally Written by Cort Dougan (cort@cs.nmt.edu) 5 * Originally written by Cort Dougan (cort@cs.nmt.edu).
6 * Subsequent 32-bit hacking by Tom Rini, Armin Kuster,
7 * Paul Mackerras and others.
6 * 8 *
7 * iSeries supported added by Mike Corrigan <mikejc@us.ibm.com> 9 * iSeries supported added by Mike Corrigan <mikejc@us.ibm.com>
8 * 10 *
9 * Additional shared processor, SMT, and firmware support 11 * Additional shared processor, SMT, and firmware support
10 * Copyright (c) 2003 Dave Engebretsen <engebret@us.ibm.com> 12 * Copyright (c) 2003 Dave Engebretsen <engebret@us.ibm.com>
11 * 13 *
14 * 32-bit and 64-bit versions merged by Paul Mackerras <paulus@samba.org>
15 *
12 * This program is free software; you can redistribute it and/or 16 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License 17 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 18 * as published by the Free Software Foundation; either version
@@ -29,18 +33,43 @@
29#include <asm/machdep.h> 33#include <asm/machdep.h>
30#include <asm/smp.h> 34#include <asm/smp.h>
31 35
32extern void power4_idle(void); 36#ifdef CONFIG_HOTPLUG_CPU
37#define cpu_should_die() (cpu_is_offline(smp_processor_id()) && \
38 system_state == SYSTEM_RUNNING)
39#else
40#define cpu_should_die() 0
41#endif
33 42
34void default_idle(void) 43/*
44 * The body of the idle task.
45 */
46void cpu_idle(void)
35{ 47{
36 unsigned int cpu = smp_processor_id(); 48 if (ppc_md.idle_loop)
37 set_thread_flag(TIF_POLLING_NRFLAG); 49 ppc_md.idle_loop(); /* doesn't return */
38 50
51 set_thread_flag(TIF_POLLING_NRFLAG);
39 while (1) { 52 while (1) {
40 if (!need_resched()) { 53 ppc64_runlatch_off();
41 while (!need_resched() && !cpu_is_offline(cpu)) {
42 ppc64_runlatch_off();
43 54
55 while (!need_resched() && !cpu_should_die()) {
56 if (ppc_md.power_save) {
57 clear_thread_flag(TIF_POLLING_NRFLAG);
58 /*
59 * smp_mb is so clearing of TIF_POLLING_NRFLAG
60 * is ordered w.r.t. need_resched() test.
61 */
62 smp_mb();
63 local_irq_disable();
64
65 /* check again after disabling irqs */
66 if (!need_resched() && !cpu_should_die())
67 ppc_md.power_save();
68
69 local_irq_enable();
70 set_thread_flag(TIF_POLLING_NRFLAG);
71
72 } else {
44 /* 73 /*
45 * Go into low thread priority and possibly 74 * Go into low thread priority and possibly
46 * low power mode. 75 * low power mode.
@@ -48,46 +77,18 @@ void default_idle(void)
48 HMT_low(); 77 HMT_low();
49 HMT_very_low(); 78 HMT_very_low();
50 } 79 }
51
52 HMT_medium();
53 } 80 }
54 81
82 HMT_medium();
55 ppc64_runlatch_on(); 83 ppc64_runlatch_on();
84 if (cpu_should_die())
85 cpu_die();
56 preempt_enable_no_resched(); 86 preempt_enable_no_resched();
57 schedule(); 87 schedule();
58 preempt_disable(); 88 preempt_disable();
59 if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING)
60 cpu_die();
61 } 89 }
62} 90}
63 91
64void native_idle(void)
65{
66 while (1) {
67 ppc64_runlatch_off();
68
69 if (!need_resched())
70 power4_idle();
71
72 if (need_resched()) {
73 ppc64_runlatch_on();
74 preempt_enable_no_resched();
75 schedule();
76 preempt_disable();
77 }
78
79 if (cpu_is_offline(smp_processor_id()) &&
80 system_state == SYSTEM_RUNNING)
81 cpu_die();
82 }
83}
84
85void cpu_idle(void)
86{
87 BUG_ON(NULL == ppc_md.idle_loop);
88 ppc_md.idle_loop();
89}
90
91int powersave_nap; 92int powersave_nap;
92 93
93#ifdef CONFIG_SYSCTL 94#ifdef CONFIG_SYSCTL
diff --git a/arch/powerpc/kernel/idle_6xx.S b/arch/powerpc/kernel/idle_6xx.S
index 444fdcc769f1..12a4efbaa08f 100644
--- a/arch/powerpc/kernel/idle_6xx.S
+++ b/arch/powerpc/kernel/idle_6xx.S
@@ -87,19 +87,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_CAN_NAP)
87 cmpwi 0,r3,0 87 cmpwi 0,r3,0
88 beqlr 88 beqlr
89 89
90 /* Clear MSR:EE */
91 mfmsr r7
92 rlwinm r0,r7,0,17,15
93 mtmsr r0
94
95 /* Check current_thread_info()->flags */
96 rlwinm r4,r1,0,0,18
97 lwz r4,TI_FLAGS(r4)
98 andi. r0,r4,_TIF_NEED_RESCHED
99 beq 1f
100 mtmsr r7 /* out of line this ? */
101 blr
1021:
103 /* Some pre-nap cleanups needed on some CPUs */ 90 /* Some pre-nap cleanups needed on some CPUs */
104 andis. r0,r3,HID0_NAP@h 91 andis. r0,r3,HID0_NAP@h
105 beq 2f 92 beq 2f
@@ -157,7 +144,8 @@ BEGIN_FTR_SECTION
157 DSSALL 144 DSSALL
158 sync 145 sync
159END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) 146END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
160 ori r7,r7,MSR_EE /* Could be ommited (already set) */ 147 mfmsr r7
148 ori r7,r7,MSR_EE
161 oris r7,r7,MSR_POW@h 149 oris r7,r7,MSR_POW@h
162 sync 150 sync
163 isync 151 isync
@@ -220,8 +208,6 @@ _GLOBAL(nap_save_msscr0)
220_GLOBAL(nap_save_hid1) 208_GLOBAL(nap_save_hid1)
221 .space 4*NR_CPUS 209 .space 4*NR_CPUS
222 210
223_GLOBAL(powersave_nap)
224 .long 0
225_GLOBAL(powersave_lowspeed) 211_GLOBAL(powersave_lowspeed)
226 .long 0 212 .long 0
227 213
diff --git a/arch/powerpc/kernel/idle_power4.S b/arch/powerpc/kernel/idle_power4.S
index c16b4afab582..6dad1c02496e 100644
--- a/arch/powerpc/kernel/idle_power4.S
+++ b/arch/powerpc/kernel/idle_power4.S
@@ -1,11 +1,5 @@
1/* 1/*
2 * This file contains the power_save function for 6xx & 7xxx CPUs 2 * This file contains the power_save function for 970-family CPUs.
3 * rewritten in assembler
4 *
5 * Warning ! This code assumes that if your machine has a 750fx
6 * it will have PLL 1 set to low speed mode (used during NAP/DOZE).
7 * if this is not the case some additional changes will have to
8 * be done to check a runtime var (a bit like powersave-nap)
9 * 3 *
10 * This program is free software; you can redistribute it and/or 4 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License 5 * modify it under the terms of the GNU General Public License
@@ -26,49 +20,23 @@
26 20
27 .text 21 .text
28 22
29/*
30 * Here is the power_save_6xx function. This could eventually be
31 * split into several functions & changing the function pointer
32 * depending on the various features.
33 */
34_GLOBAL(power4_idle) 23_GLOBAL(power4_idle)
35BEGIN_FTR_SECTION 24BEGIN_FTR_SECTION
36 blr 25 blr
37END_FTR_SECTION_IFCLR(CPU_FTR_CAN_NAP) 26END_FTR_SECTION_IFCLR(CPU_FTR_CAN_NAP)
38 /* We must dynamically check for the NAP feature as it
39 * can be cleared by CPU init after the fixups are done
40 */
41 LOAD_REG_ADDRBASE(r3,cur_cpu_spec)
42 ld r4,ADDROFF(cur_cpu_spec)(r3)
43 ld r4,CPU_SPEC_FEATURES(r4)
44 andi. r0,r4,CPU_FTR_CAN_NAP
45 beqlr
46 /* Now check if user or arch enabled NAP mode */ 27 /* Now check if user or arch enabled NAP mode */
47 LOAD_REG_ADDRBASE(r3,powersave_nap) 28 LOAD_REG_ADDRBASE(r3,powersave_nap)
48 lwz r4,ADDROFF(powersave_nap)(r3) 29 lwz r4,ADDROFF(powersave_nap)(r3)
49 cmpwi 0,r4,0 30 cmpwi 0,r4,0
50 beqlr 31 beqlr
51 32
52 /* Clear MSR:EE */
53 mfmsr r7
54 li r4,0
55 ori r4,r4,MSR_EE
56 andc r0,r7,r4
57 mtmsrd r0
58
59 /* Check current_thread_info()->flags */
60 clrrdi r4,r1,THREAD_SHIFT
61 ld r4,TI_FLAGS(r4)
62 andi. r0,r4,_TIF_NEED_RESCHED
63 beq 1f
64 mtmsrd r7 /* out of line this ? */
65 blr
661:
67 /* Go to NAP now */ 33 /* Go to NAP now */
68BEGIN_FTR_SECTION 34BEGIN_FTR_SECTION
69 DSSALL 35 DSSALL
70 sync 36 sync
71END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) 37END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
38 mfmsr r7
39 ori r7,r7,MSR_EE
72 oris r7,r7,MSR_POW@h 40 oris r7,r7,MSR_POW@h
73 sync 41 sync
74 isync 42 isync
diff --git a/arch/powerpc/kernel/l2cr_6xx.S b/arch/powerpc/kernel/l2cr_6xx.S
new file mode 100644
index 000000000000..d7f4e982b539
--- /dev/null
+++ b/arch/powerpc/kernel/l2cr_6xx.S
@@ -0,0 +1,471 @@
1/*
2 L2CR functions
3 Copyright © 1997-1998 by PowerLogix R & D, Inc.
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18*/
19/*
20 Thur, Dec. 12, 1998.
21 - First public release, contributed by PowerLogix.
22 ***********
23 Sat, Aug. 7, 1999.
24 - Terry: Made sure code disabled interrupts before running. (Previously
25 it was assumed interrupts were already disabled).
26 - Terry: Updated for tentative G4 support. 4MB of memory is now flushed
27 instead of 2MB. (Prob. only 3 is necessary).
28 - Terry: Updated for workaround to HID0[DPM] processor bug
29 during global invalidates.
30 ***********
31 Thu, July 13, 2000.
32 - Terry: Added isync to correct for an errata.
33
34 22 August 2001.
35 - DanM: Finally added the 7450 patch I've had for the past
36 several months. The L2CR is similar, but I'm going
37 to assume the user of this functions knows what they
38 are doing.
39
40 Author: Terry Greeniaus (tgree@phys.ualberta.ca)
41 Please e-mail updates to this file to me, thanks!
42*/
43#include <linux/config.h>
44#include <asm/processor.h>
45#include <asm/cputable.h>
46#include <asm/ppc_asm.h>
47#include <asm/cache.h>
48#include <asm/page.h>
49
50/* Usage:
51
52 When setting the L2CR register, you must do a few special
53 things. If you are enabling the cache, you must perform a
54 global invalidate. If you are disabling the cache, you must
55 flush the cache contents first. This routine takes care of
56 doing these things. When first enabling the cache, make sure
57 you pass in the L2CR you want, as well as passing in the
58 global invalidate bit set. A global invalidate will only be
59 performed if the L2I bit is set in applyThis. When enabling
60 the cache, you should also set the L2E bit in applyThis. If
61 you want to modify the L2CR contents after the cache has been
62 enabled, the recommended procedure is to first call
63 __setL2CR(0) to disable the cache and then call it again with
64 the new values for L2CR. Examples:
65
66 _setL2CR(0) - disables the cache
67 _setL2CR(0xB3A04000) - enables my G3 upgrade card:
68 - L2E set to turn on the cache
69 - L2SIZ set to 1MB
70 - L2CLK set to 1:1
71 - L2RAM set to pipelined synchronous late-write
72 - L2I set to perform a global invalidation
73 - L2OH set to 0.5 nS
74 - L2DF set because this upgrade card
75 requires it
76
77 A similar call should work for your card. You need to know
78 the correct setting for your card and then place them in the
79 fields I have outlined above. Other fields support optional
80 features, such as L2DO which caches only data, or L2TS which
81 causes cache pushes from the L1 cache to go to the L2 cache
82 instead of to main memory.
83
84IMPORTANT:
85 Starting with the 7450, the bits in this register have moved
86 or behave differently. The Enable, Parity Enable, Size,
87 and L2 Invalidate are the only bits that have not moved.
88 The size is read-only for these processors with internal L2
89 cache, and the invalidate is a control as well as status.
90 -- Dan
91
92*/
93/*
94 * Summary: this procedure ignores the L2I bit in the value passed in,
95 * flushes the cache if it was already enabled, always invalidates the
96 * cache, then enables the cache if the L2E bit is set in the value
97 * passed in.
98 * -- paulus.
99 */
100_GLOBAL(_set_L2CR)
101 /* Make sure this is a 750 or 7400 chip */
102BEGIN_FTR_SECTION
103 li r3,-1
104 blr
105END_FTR_SECTION_IFCLR(CPU_FTR_L2CR)
106
107 mflr r9
108
109 /* Stop DST streams */
110BEGIN_FTR_SECTION
111 DSSALL
112 sync
113END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
114
115 /* Turn off interrupts and data relocation. */
116 mfmsr r7 /* Save MSR in r7 */
117 rlwinm r4,r7,0,17,15
118 rlwinm r4,r4,0,28,26 /* Turn off DR bit */
119 sync
120 mtmsr r4
121 isync
122
123 /* Before we perform the global invalidation, we must disable dynamic
124 * power management via HID0[DPM] to work around a processor bug where
125 * DPM can possibly interfere with the state machine in the processor
126 * that invalidates the L2 cache tags.
127 */
128 mfspr r8,SPRN_HID0 /* Save HID0 in r8 */
129 rlwinm r4,r8,0,12,10 /* Turn off HID0[DPM] */
130 sync
131 mtspr SPRN_HID0,r4 /* Disable DPM */
132 sync
133
134 /* Get the current enable bit of the L2CR into r4 */
135 mfspr r4,SPRN_L2CR
136
137 /* Tweak some bits */
138 rlwinm r5,r3,0,0,0 /* r5 contains the new enable bit */
139 rlwinm r3,r3,0,11,9 /* Turn off the invalidate bit */
140 rlwinm r3,r3,0,1,31 /* Turn off the enable bit */
141
142 /* Check to see if we need to flush */
143 rlwinm. r4,r4,0,0,0
144 beq 2f
145
146 /* Flush the cache. First, read the first 4MB of memory (physical) to
147 * put new data in the cache. (Actually we only need
148 * the size of the L2 cache plus the size of the L1 cache, but 4MB will
149 * cover everything just to be safe).
150 */
151
152 /**** Might be a good idea to set L2DO here - to prevent instructions
153 from getting into the cache. But since we invalidate
154 the next time we enable the cache it doesn't really matter.
155 Don't do this unless you accomodate all processor variations.
156 The bit moved on the 7450.....
157 ****/
158
159BEGIN_FTR_SECTION
160 /* Disable L2 prefetch on some 745x and try to ensure
161 * L2 prefetch engines are idle. As explained by errata
162 * text, we can't be sure they are, we just hope very hard
163 * that well be enough (sic !). At least I noticed Apple
164 * doesn't even bother doing the dcbf's here...
165 */
166 mfspr r4,SPRN_MSSCR0
167 rlwinm r4,r4,0,0,29
168 sync
169 mtspr SPRN_MSSCR0,r4
170 sync
171 isync
172 lis r4,KERNELBASE@h
173 dcbf 0,r4
174 dcbf 0,r4
175 dcbf 0,r4
176 dcbf 0,r4
177END_FTR_SECTION_IFSET(CPU_FTR_SPEC7450)
178
179 /* TODO: use HW flush assist when available */
180
181 lis r4,0x0002
182 mtctr r4
183 li r4,0
1841:
185 lwzx r0,r0,r4
186 addi r4,r4,32 /* Go to start of next cache line */
187 bdnz 1b
188 isync
189
190 /* Now, flush the first 4MB of memory */
191 lis r4,0x0002
192 mtctr r4
193 li r4,0
194 sync
1951:
196 dcbf 0,r4
197 addi r4,r4,32 /* Go to start of next cache line */
198 bdnz 1b
199
2002:
201 /* Set up the L2CR configuration bits (and switch L2 off) */
202 /* CPU errata: Make sure the mtspr below is already in the
203 * L1 icache
204 */
205 b 20f
206 .balign L1_CACHE_BYTES
20722:
208 sync
209 mtspr SPRN_L2CR,r3
210 sync
211 b 23f
21220:
213 b 21f
21421: sync
215 isync
216 b 22b
217
21823:
219 /* Perform a global invalidation */
220 oris r3,r3,0x0020
221 sync
222 mtspr SPRN_L2CR,r3
223 sync
224 isync /* For errata */
225
226BEGIN_FTR_SECTION
227 /* On the 7450, we wait for the L2I bit to clear......
228 */
22910: mfspr r3,SPRN_L2CR
230 andis. r4,r3,0x0020
231 bne 10b
232 b 11f
233END_FTR_SECTION_IFSET(CPU_FTR_SPEC7450)
234
235 /* Wait for the invalidation to complete */
2363: mfspr r3,SPRN_L2CR
237 rlwinm. r4,r3,0,31,31
238 bne 3b
239
24011: rlwinm r3,r3,0,11,9 /* Turn off the L2I bit */
241 sync
242 mtspr SPRN_L2CR,r3
243 sync
244
245 /* See if we need to enable the cache */
246 cmplwi r5,0
247 beq 4f
248
249 /* Enable the cache */
250 oris r3,r3,0x8000
251 mtspr SPRN_L2CR,r3
252 sync
253
254 /* Enable L2 HW prefetch on 744x/745x */
255BEGIN_FTR_SECTION
256 mfspr r3,SPRN_MSSCR0
257 ori r3,r3,3
258 sync
259 mtspr SPRN_MSSCR0,r3
260 sync
261 isync
262END_FTR_SECTION_IFSET(CPU_FTR_SPEC7450)
2634:
264
265 /* Restore HID0[DPM] to whatever it was before */
266 sync
267 mtspr 1008,r8
268 sync
269
270 /* Restore MSR (restores EE and DR bits to original state) */
271 SYNC
272 mtmsr r7
273 isync
274
275 mtlr r9
276 blr
277
278_GLOBAL(_get_L2CR)
279 /* Return the L2CR contents */
280 li r3,0
281BEGIN_FTR_SECTION
282 mfspr r3,SPRN_L2CR
283END_FTR_SECTION_IFSET(CPU_FTR_L2CR)
284 blr
285
286
287/*
288 * Here is a similar routine for dealing with the L3 cache
289 * on the 745x family of chips
290 */
291
292_GLOBAL(_set_L3CR)
293 /* Make sure this is a 745x chip */
294BEGIN_FTR_SECTION
295 li r3,-1
296 blr
297END_FTR_SECTION_IFCLR(CPU_FTR_L3CR)
298
299 /* Turn off interrupts and data relocation. */
300 mfmsr r7 /* Save MSR in r7 */
301 rlwinm r4,r7,0,17,15
302 rlwinm r4,r4,0,28,26 /* Turn off DR bit */
303 sync
304 mtmsr r4
305 isync
306
307 /* Stop DST streams */
308 DSSALL
309 sync
310
311 /* Get the current enable bit of the L3CR into r4 */
312 mfspr r4,SPRN_L3CR
313
314 /* Tweak some bits */
315 rlwinm r5,r3,0,0,0 /* r5 contains the new enable bit */
316 rlwinm r3,r3,0,22,20 /* Turn off the invalidate bit */
317 rlwinm r3,r3,0,2,31 /* Turn off the enable & PE bits */
318 rlwinm r3,r3,0,5,3 /* Turn off the clken bit */
319 /* Check to see if we need to flush */
320 rlwinm. r4,r4,0,0,0
321 beq 2f
322
323 /* Flush the cache.
324 */
325
326 /* TODO: use HW flush assist */
327
328 lis r4,0x0008
329 mtctr r4
330 li r4,0
3311:
332 lwzx r0,r0,r4
333 dcbf 0,r4
334 addi r4,r4,32 /* Go to start of next cache line */
335 bdnz 1b
336
3372:
338 /* Set up the L3CR configuration bits (and switch L3 off) */
339 sync
340 mtspr SPRN_L3CR,r3
341 sync
342
343 oris r3,r3,L3CR_L3RES@h /* Set reserved bit 5 */
344 mtspr SPRN_L3CR,r3
345 sync
346 oris r3,r3,L3CR_L3CLKEN@h /* Set clken */
347 mtspr SPRN_L3CR,r3
348 sync
349
350 /* Wait for stabilize */
351 li r0,256
352 mtctr r0
3531: bdnz 1b
354
355 /* Perform a global invalidation */
356 ori r3,r3,0x0400
357 sync
358 mtspr SPRN_L3CR,r3
359 sync
360 isync
361
362 /* We wait for the L3I bit to clear...... */
36310: mfspr r3,SPRN_L3CR
364 andi. r4,r3,0x0400
365 bne 10b
366
367 /* Clear CLKEN */
368 rlwinm r3,r3,0,5,3 /* Turn off the clken bit */
369 mtspr SPRN_L3CR,r3
370 sync
371
372 /* Wait for stabilize */
373 li r0,256
374 mtctr r0
3751: bdnz 1b
376
377 /* See if we need to enable the cache */
378 cmplwi r5,0
379 beq 4f
380
381 /* Enable the cache */
382 oris r3,r3,(L3CR_L3E | L3CR_L3CLKEN)@h
383 mtspr SPRN_L3CR,r3
384 sync
385
386 /* Wait for stabilize */
387 li r0,256
388 mtctr r0
3891: bdnz 1b
390
391 /* Restore MSR (restores EE and DR bits to original state) */
3924: SYNC
393 mtmsr r7
394 isync
395 blr
396
397_GLOBAL(_get_L3CR)
398 /* Return the L3CR contents */
399 li r3,0
400BEGIN_FTR_SECTION
401 mfspr r3,SPRN_L3CR
402END_FTR_SECTION_IFSET(CPU_FTR_L3CR)
403 blr
404
405/* --- End of PowerLogix code ---
406 */
407
408
409/* flush_disable_L1() - Flush and disable L1 cache
410 *
411 * clobbers r0, r3, ctr, cr0
412 * Must be called with interrupts disabled and MMU enabled.
413 */
414_GLOBAL(__flush_disable_L1)
415 /* Stop pending alitvec streams and memory accesses */
416BEGIN_FTR_SECTION
417 DSSALL
418END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
419 sync
420
421 /* Load counter to 0x4000 cache lines (512k) and
422 * load cache with datas
423 */
424 li r3,0x4000 /* 512kB / 32B */
425 mtctr r3
426 lis r3,KERNELBASE@h
4271:
428 lwz r0,0(r3)
429 addi r3,r3,0x0020 /* Go to start of next cache line */
430 bdnz 1b
431 isync
432 sync
433
434 /* Now flush those cache lines */
435 li r3,0x4000 /* 512kB / 32B */
436 mtctr r3
437 lis r3,KERNELBASE@h
4381:
439 dcbf 0,r3
440 addi r3,r3,0x0020 /* Go to start of next cache line */
441 bdnz 1b
442 sync
443
444 /* We can now disable the L1 cache (HID0:DCE, HID0:ICE) */
445 mfspr r3,SPRN_HID0
446 rlwinm r3,r3,0,18,15
447 mtspr SPRN_HID0,r3
448 sync
449 isync
450 blr
451
452/* inval_enable_L1 - Invalidate and enable L1 cache
453 *
454 * Assumes L1 is already disabled and MSR:EE is off
455 *
456 * clobbers r3
457 */
458_GLOBAL(__inval_enable_L1)
459 /* Enable and then Flash inval the instruction & data cache */
460 mfspr r3,SPRN_HID0
461 ori r3,r3, HID0_ICE|HID0_ICFI|HID0_DCE|HID0_DCI
462 sync
463 isync
464 mtspr SPRN_HID0,r3
465 xori r3,r3, HID0_ICFI|HID0_DCI
466 mtspr SPRN_HID0,r3
467 sync
468
469 blr
470
471
diff --git a/arch/powerpc/kernel/legacy_serial.c b/arch/powerpc/kernel/legacy_serial.c
index c7a799a09516..6e67b5b49ba1 100644
--- a/arch/powerpc/kernel/legacy_serial.c
+++ b/arch/powerpc/kernel/legacy_serial.c
@@ -37,7 +37,7 @@ static int legacy_serial_console = -1;
37static int __init add_legacy_port(struct device_node *np, int want_index, 37static int __init add_legacy_port(struct device_node *np, int want_index,
38 int iotype, phys_addr_t base, 38 int iotype, phys_addr_t base,
39 phys_addr_t taddr, unsigned long irq, 39 phys_addr_t taddr, unsigned long irq,
40 unsigned int flags) 40 upf_t flags)
41{ 41{
42 u32 *clk, *spd, clock = BASE_BAUD * 16; 42 u32 *clk, *spd, clock = BASE_BAUD * 16;
43 int index; 43 int index;
@@ -113,7 +113,7 @@ static int __init add_legacy_soc_port(struct device_node *np,
113{ 113{
114 phys_addr_t addr; 114 phys_addr_t addr;
115 u32 *addrp; 115 u32 *addrp;
116 unsigned int flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ; 116 upf_t flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ;
117 117
118 /* We only support ports that have a clock frequency properly 118 /* We only support ports that have a clock frequency properly
119 * encoded in the device-tree. 119 * encoded in the device-tree.
@@ -236,6 +236,23 @@ static int __init add_legacy_pci_port(struct device_node *np,
236} 236}
237#endif 237#endif
238 238
239static void __init setup_legacy_serial_console(int console)
240{
241 struct legacy_serial_info *info =
242 &legacy_serial_infos[console];
243 void __iomem *addr;
244
245 if (info->taddr == 0)
246 return;
247 addr = ioremap(info->taddr, 0x1000);
248 if (addr == NULL)
249 return;
250 if (info->speed == 0)
251 info->speed = udbg_probe_uart_speed(addr, info->clock);
252 DBG("default console speed = %d\n", info->speed);
253 udbg_init_uart(addr, info->speed, info->clock);
254}
255
239/* 256/*
240 * This is called very early, as part of setup_system() or eventually 257 * This is called very early, as part of setup_system() or eventually
241 * setup_arch(), basically before anything else in this file. This function 258 * setup_arch(), basically before anything else in this file. This function
@@ -318,25 +335,8 @@ void __init find_legacy_serial_ports(void)
318#endif 335#endif
319 336
320 DBG("legacy_serial_console = %d\n", legacy_serial_console); 337 DBG("legacy_serial_console = %d\n", legacy_serial_console);
321 338 if (legacy_serial_console >= 0)
322 /* udbg is 64 bits only for now, that will change soon though ... */ 339 setup_legacy_serial_console(legacy_serial_console);
323 while (legacy_serial_console >= 0) {
324 struct legacy_serial_info *info =
325 &legacy_serial_infos[legacy_serial_console];
326 void __iomem *addr;
327
328 if (info->taddr == 0)
329 break;
330 addr = ioremap(info->taddr, 0x1000);
331 if (addr == NULL)
332 break;
333 if (info->speed == 0)
334 info->speed = udbg_probe_uart_speed(addr, info->clock);
335 DBG("default console speed = %d\n", info->speed);
336 udbg_init_uart(addr, info->speed, info->clock);
337 break;
338 }
339
340 DBG(" <- find_legacy_serial_port()\n"); 340 DBG(" <- find_legacy_serial_port()\n");
341} 341}
342 342
diff --git a/arch/powerpc/kernel/module_32.c b/arch/powerpc/kernel/module_32.c
new file mode 100644
index 000000000000..92f4e5f64f02
--- /dev/null
+++ b/arch/powerpc/kernel/module_32.c
@@ -0,0 +1,320 @@
1/* Kernel module help for PPC.
2 Copyright (C) 2001 Rusty Russell.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17*/
18#include <linux/module.h>
19#include <linux/moduleloader.h>
20#include <linux/elf.h>
21#include <linux/vmalloc.h>
22#include <linux/fs.h>
23#include <linux/string.h>
24#include <linux/kernel.h>
25#include <linux/cache.h>
26
27#if 0
28#define DEBUGP printk
29#else
30#define DEBUGP(fmt , ...)
31#endif
32
33LIST_HEAD(module_bug_list);
34
35void *module_alloc(unsigned long size)
36{
37 if (size == 0)
38 return NULL;
39 return vmalloc(size);
40}
41
42/* Free memory returned from module_alloc */
43void module_free(struct module *mod, void *module_region)
44{
45 vfree(module_region);
46 /* FIXME: If module_region == mod->init_region, trim exception
47 table entries. */
48}
49
50/* Count how many different relocations (different symbol, different
51 addend) */
52static unsigned int count_relocs(const Elf32_Rela *rela, unsigned int num)
53{
54 unsigned int i, j, ret = 0;
55
56 /* Sure, this is order(n^2), but it's usually short, and not
57 time critical */
58 for (i = 0; i < num; i++) {
59 for (j = 0; j < i; j++) {
60 /* If this addend appeared before, it's
61 already been counted */
62 if (ELF32_R_SYM(rela[i].r_info)
63 == ELF32_R_SYM(rela[j].r_info)
64 && rela[i].r_addend == rela[j].r_addend)
65 break;
66 }
67 if (j == i) ret++;
68 }
69 return ret;
70}
71
72/* Get the potential trampolines size required of the init and
73 non-init sections */
74static unsigned long get_plt_size(const Elf32_Ehdr *hdr,
75 const Elf32_Shdr *sechdrs,
76 const char *secstrings,
77 int is_init)
78{
79 unsigned long ret = 0;
80 unsigned i;
81
82 /* Everything marked ALLOC (this includes the exported
83 symbols) */
84 for (i = 1; i < hdr->e_shnum; i++) {
85 /* If it's called *.init*, and we're not init, we're
86 not interested */
87 if ((strstr(secstrings + sechdrs[i].sh_name, ".init") != 0)
88 != is_init)
89 continue;
90
91 /* We don't want to look at debug sections. */
92 if (strstr(secstrings + sechdrs[i].sh_name, ".debug") != 0)
93 continue;
94
95 if (sechdrs[i].sh_type == SHT_RELA) {
96 DEBUGP("Found relocations in section %u\n", i);
97 DEBUGP("Ptr: %p. Number: %u\n",
98 (void *)hdr + sechdrs[i].sh_offset,
99 sechdrs[i].sh_size / sizeof(Elf32_Rela));
100 ret += count_relocs((void *)hdr
101 + sechdrs[i].sh_offset,
102 sechdrs[i].sh_size
103 / sizeof(Elf32_Rela))
104 * sizeof(struct ppc_plt_entry);
105 }
106 }
107
108 return ret;
109}
110
111int module_frob_arch_sections(Elf32_Ehdr *hdr,
112 Elf32_Shdr *sechdrs,
113 char *secstrings,
114 struct module *me)
115{
116 unsigned int i;
117
118 /* Find .plt and .init.plt sections */
119 for (i = 0; i < hdr->e_shnum; i++) {
120 if (strcmp(secstrings + sechdrs[i].sh_name, ".init.plt") == 0)
121 me->arch.init_plt_section = i;
122 else if (strcmp(secstrings + sechdrs[i].sh_name, ".plt") == 0)
123 me->arch.core_plt_section = i;
124 }
125 if (!me->arch.core_plt_section || !me->arch.init_plt_section) {
126 printk("Module doesn't contain .plt or .init.plt sections.\n");
127 return -ENOEXEC;
128 }
129
130 /* Override their sizes */
131 sechdrs[me->arch.core_plt_section].sh_size
132 = get_plt_size(hdr, sechdrs, secstrings, 0);
133 sechdrs[me->arch.init_plt_section].sh_size
134 = get_plt_size(hdr, sechdrs, secstrings, 1);
135 return 0;
136}
137
138int apply_relocate(Elf32_Shdr *sechdrs,
139 const char *strtab,
140 unsigned int symindex,
141 unsigned int relsec,
142 struct module *module)
143{
144 printk(KERN_ERR "%s: Non-ADD RELOCATION unsupported\n",
145 module->name);
146 return -ENOEXEC;
147}
148
149static inline int entry_matches(struct ppc_plt_entry *entry, Elf32_Addr val)
150{
151 if (entry->jump[0] == 0x3d600000 + ((val + 0x8000) >> 16)
152 && entry->jump[1] == 0x396b0000 + (val & 0xffff))
153 return 1;
154 return 0;
155}
156
157/* Set up a trampoline in the PLT to bounce us to the distant function */
158static uint32_t do_plt_call(void *location,
159 Elf32_Addr val,
160 Elf32_Shdr *sechdrs,
161 struct module *mod)
162{
163 struct ppc_plt_entry *entry;
164
165 DEBUGP("Doing plt for call to 0x%x at 0x%x\n", val, (unsigned int)location);
166 /* Init, or core PLT? */
167 if (location >= mod->module_core
168 && location < mod->module_core + mod->core_size)
169 entry = (void *)sechdrs[mod->arch.core_plt_section].sh_addr;
170 else
171 entry = (void *)sechdrs[mod->arch.init_plt_section].sh_addr;
172
173 /* Find this entry, or if that fails, the next avail. entry */
174 while (entry->jump[0]) {
175 if (entry_matches(entry, val)) return (uint32_t)entry;
176 entry++;
177 }
178
179 /* Stolen from Paul Mackerras as well... */
180 entry->jump[0] = 0x3d600000+((val+0x8000)>>16); /* lis r11,sym@ha */
181 entry->jump[1] = 0x396b0000 + (val&0xffff); /* addi r11,r11,sym@l*/
182 entry->jump[2] = 0x7d6903a6; /* mtctr r11 */
183 entry->jump[3] = 0x4e800420; /* bctr */
184
185 DEBUGP("Initialized plt for 0x%x at %p\n", val, entry);
186 return (uint32_t)entry;
187}
188
189int apply_relocate_add(Elf32_Shdr *sechdrs,
190 const char *strtab,
191 unsigned int symindex,
192 unsigned int relsec,
193 struct module *module)
194{
195 unsigned int i;
196 Elf32_Rela *rela = (void *)sechdrs[relsec].sh_addr;
197 Elf32_Sym *sym;
198 uint32_t *location;
199 uint32_t value;
200
201 DEBUGP("Applying ADD relocate section %u to %u\n", relsec,
202 sechdrs[relsec].sh_info);
203 for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rela); i++) {
204 /* This is where to make the change */
205 location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
206 + rela[i].r_offset;
207 /* This is the symbol it is referring to. Note that all
208 undefined symbols have been resolved. */
209 sym = (Elf32_Sym *)sechdrs[symindex].sh_addr
210 + ELF32_R_SYM(rela[i].r_info);
211 /* `Everything is relative'. */
212 value = sym->st_value + rela[i].r_addend;
213
214 switch (ELF32_R_TYPE(rela[i].r_info)) {
215 case R_PPC_ADDR32:
216 /* Simply set it */
217 *(uint32_t *)location = value;
218 break;
219
220 case R_PPC_ADDR16_LO:
221 /* Low half of the symbol */
222 *(uint16_t *)location = value;
223 break;
224
225 case R_PPC_ADDR16_HA:
226 /* Sign-adjusted lower 16 bits: PPC ELF ABI says:
227 (((x >> 16) + ((x & 0x8000) ? 1 : 0))) & 0xFFFF.
228 This is the same, only sane.
229 */
230 *(uint16_t *)location = (value + 0x8000) >> 16;
231 break;
232
233 case R_PPC_REL24:
234 if ((int)(value - (uint32_t)location) < -0x02000000
235 || (int)(value - (uint32_t)location) >= 0x02000000)
236 value = do_plt_call(location, value,
237 sechdrs, module);
238
239 /* Only replace bits 2 through 26 */
240 DEBUGP("REL24 value = %08X. location = %08X\n",
241 value, (uint32_t)location);
242 DEBUGP("Location before: %08X.\n",
243 *(uint32_t *)location);
244 *(uint32_t *)location
245 = (*(uint32_t *)location & ~0x03fffffc)
246 | ((value - (uint32_t)location)
247 & 0x03fffffc);
248 DEBUGP("Location after: %08X.\n",
249 *(uint32_t *)location);
250 DEBUGP("ie. jump to %08X+%08X = %08X\n",
251 *(uint32_t *)location & 0x03fffffc,
252 (uint32_t)location,
253 (*(uint32_t *)location & 0x03fffffc)
254 + (uint32_t)location);
255 break;
256
257 case R_PPC_REL32:
258 /* 32-bit relative jump. */
259 *(uint32_t *)location = value - (uint32_t)location;
260 break;
261
262 default:
263 printk("%s: unknown ADD relocation: %u\n",
264 module->name,
265 ELF32_R_TYPE(rela[i].r_info));
266 return -ENOEXEC;
267 }
268 }
269 return 0;
270}
271
272int module_finalize(const Elf_Ehdr *hdr,
273 const Elf_Shdr *sechdrs,
274 struct module *me)
275{
276 char *secstrings;
277 unsigned int i;
278
279 me->arch.bug_table = NULL;
280 me->arch.num_bugs = 0;
281
282 /* Find the __bug_table section, if present */
283 secstrings = (char *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
284 for (i = 1; i < hdr->e_shnum; i++) {
285 if (strcmp(secstrings+sechdrs[i].sh_name, "__bug_table"))
286 continue;
287 me->arch.bug_table = (void *) sechdrs[i].sh_addr;
288 me->arch.num_bugs = sechdrs[i].sh_size / sizeof(struct bug_entry);
289 break;
290 }
291
292 /*
293 * Strictly speaking this should have a spinlock to protect against
294 * traversals, but since we only traverse on BUG()s, a spinlock
295 * could potentially lead to deadlock and thus be counter-productive.
296 */
297 list_add(&me->arch.bug_list, &module_bug_list);
298
299 return 0;
300}
301
302void module_arch_cleanup(struct module *mod)
303{
304 list_del(&mod->arch.bug_list);
305}
306
307struct bug_entry *module_find_bug(unsigned long bugaddr)
308{
309 struct mod_arch_specific *mod;
310 unsigned int i;
311 struct bug_entry *bug;
312
313 list_for_each_entry(mod, &module_bug_list, bug_list) {
314 bug = mod->bug_table;
315 for (i = 0; i < mod->num_bugs; ++i, ++bug)
316 if (bugaddr == bug->bug_addr)
317 return bug;
318 }
319 return NULL;
320}
diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c
index fd7db8d542db..ada50aa5b600 100644
--- a/arch/powerpc/kernel/nvram_64.c
+++ b/arch/powerpc/kernel/nvram_64.c
@@ -160,7 +160,7 @@ static int dev_nvram_ioctl(struct inode *inode, struct file *file,
160 case IOC_NVRAM_GET_OFFSET: { 160 case IOC_NVRAM_GET_OFFSET: {
161 int part, offset; 161 int part, offset;
162 162
163 if (_machine != PLATFORM_POWERMAC) 163 if (!machine_is(powermac))
164 return -EINVAL; 164 return -EINVAL;
165 if (copy_from_user(&part, (void __user*)arg, sizeof(part)) != 0) 165 if (copy_from_user(&part, (void __user*)arg, sizeof(part)) != 0)
166 return -EFAULT; 166 return -EFAULT;
@@ -174,8 +174,9 @@ static int dev_nvram_ioctl(struct inode *inode, struct file *file,
174 return 0; 174 return 0;
175 } 175 }
176#endif /* CONFIG_PPC_PMAC */ 176#endif /* CONFIG_PPC_PMAC */
177 default:
178 return -EINVAL;
177 } 179 }
178 return -EINVAL;
179} 180}
180 181
181struct file_operations nvram_fops = { 182struct file_operations nvram_fops = {
@@ -443,7 +444,7 @@ static int nvram_setup_partition(void)
443 * in our nvram, as Apple defined partitions use pretty much 444 * in our nvram, as Apple defined partitions use pretty much
444 * all of the space 445 * all of the space
445 */ 446 */
446 if (_machine == PLATFORM_POWERMAC) 447 if (machine_is(powermac))
447 return -ENOSPC; 448 return -ENOSPC;
448 449
449 /* see if we have an OS partition that meets our needs. 450 /* see if we have an OS partition that meets our needs.
diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c
index 5d1b708086bd..f505a8827e3e 100644
--- a/arch/powerpc/kernel/paca.c
+++ b/arch/powerpc/kernel/paca.c
@@ -56,14 +56,11 @@ struct lppaca lppaca[] = {
56 * processors. The processor VPD array needs one entry per physical 56 * processors. The processor VPD array needs one entry per physical
57 * processor (not thread). 57 * processor (not thread).
58 */ 58 */
59#define PACA_INIT_COMMON(number, start, asrr, asrv) \ 59#define PACA_INIT_COMMON(number) \
60 .lppaca_ptr = &lppaca[number], \ 60 .lppaca_ptr = &lppaca[number], \
61 .lock_token = 0x8000, \ 61 .lock_token = 0x8000, \
62 .paca_index = (number), /* Paca Index */ \ 62 .paca_index = (number), /* Paca Index */ \
63 .kernel_toc = (unsigned long)(&__toc_start) + 0x8000UL, \ 63 .kernel_toc = (unsigned long)(&__toc_start) + 0x8000UL, \
64 .stab_real = (asrr), /* Real pointer to segment table */ \
65 .stab_addr = (asrv), /* Virt pointer to segment table */ \
66 .cpu_start = (start), /* Processor start */ \
67 .hw_cpu_id = 0xffff, 64 .hw_cpu_id = 0xffff,
68 65
69#ifdef CONFIG_PPC_ISERIES 66#ifdef CONFIG_PPC_ISERIES
@@ -72,30 +69,20 @@ struct lppaca lppaca[] = {
72 69
73#define PACA_INIT(number) \ 70#define PACA_INIT(number) \
74{ \ 71{ \
75 PACA_INIT_COMMON(number, 0, 0, 0) \ 72 PACA_INIT_COMMON(number) \
76 PACA_INIT_ISERIES(number) \
77}
78
79#define BOOTCPU_PACA_INIT(number) \
80{ \
81 PACA_INIT_COMMON(number, 1, 0, (u64)&initial_stab) \
82 PACA_INIT_ISERIES(number) \ 73 PACA_INIT_ISERIES(number) \
83} 74}
84 75
85#else 76#else
86#define PACA_INIT(number) \ 77#define PACA_INIT(number) \
87{ \ 78{ \
88 PACA_INIT_COMMON(number, 0, 0, 0) \ 79 PACA_INIT_COMMON(number) \
89} 80}
90 81
91#define BOOTCPU_PACA_INIT(number) \
92{ \
93 PACA_INIT_COMMON(number, 1, STAB0_PHYS_ADDR, (u64)&initial_stab) \
94}
95#endif 82#endif
96 83
97struct paca_struct paca[] = { 84struct paca_struct paca[] = {
98 BOOTCPU_PACA_INIT(0), 85 PACA_INIT(0),
99#if NR_CPUS > 1 86#if NR_CPUS > 1
100 PACA_INIT( 1), PACA_INIT( 2), PACA_INIT( 3), 87 PACA_INIT( 1), PACA_INIT( 2), PACA_INIT( 3),
101#if NR_CPUS > 4 88#if NR_CPUS > 4
diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c
index 704c846b2b0f..b129d2e4b759 100644
--- a/arch/powerpc/kernel/pci_32.c
+++ b/arch/powerpc/kernel/pci_32.c
@@ -787,7 +787,7 @@ pci_busdev_to_OF_node(struct pci_bus *bus, int devfn)
787 * fix has to be done by making the remapping per-host and always 787 * fix has to be done by making the remapping per-host and always
788 * filling the pci_to_OF map. --BenH 788 * filling the pci_to_OF map. --BenH
789 */ 789 */
790 if (_machine == _MACH_Pmac && busnr >= 0xf0) 790 if (machine_is(powermac) && busnr >= 0xf0)
791 busnr -= 0xf0; 791 busnr -= 0xf0;
792 else 792 else
793#endif 793#endif
@@ -1728,7 +1728,7 @@ long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn)
1728 * (bus 0 is HT root), we return the AGP one instead. 1728 * (bus 0 is HT root), we return the AGP one instead.
1729 */ 1729 */
1730#ifdef CONFIG_PPC_PMAC 1730#ifdef CONFIG_PPC_PMAC
1731 if (_machine == _MACH_Pmac && machine_is_compatible("MacRISC4")) 1731 if (machine_is(powermac) && machine_is_compatible("MacRISC4"))
1732 if (bus == 0) 1732 if (bus == 0)
1733 bus = 0xf0; 1733 bus = 0xf0;
1734#endif /* CONFIG_PPC_PMAC */ 1734#endif /* CONFIG_PPC_PMAC */
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c
index ba92bab7cc2c..4c4449be81ce 100644
--- a/arch/powerpc/kernel/pci_64.c
+++ b/arch/powerpc/kernel/pci_64.c
@@ -78,6 +78,7 @@ int global_phb_number; /* Global phb counter */
78 78
79/* Cached ISA bridge dev. */ 79/* Cached ISA bridge dev. */
80struct pci_dev *ppc64_isabridge_dev = NULL; 80struct pci_dev *ppc64_isabridge_dev = NULL;
81EXPORT_SYMBOL_GPL(ppc64_isabridge_dev);
81 82
82static void fixup_broken_pcnet32(struct pci_dev* dev) 83static void fixup_broken_pcnet32(struct pci_dev* dev)
83{ 84{
diff --git a/arch/powerpc/kernel/perfmon_fsl_booke.c b/arch/powerpc/kernel/perfmon_fsl_booke.c
new file mode 100644
index 000000000000..32455dfcc36b
--- /dev/null
+++ b/arch/powerpc/kernel/perfmon_fsl_booke.c
@@ -0,0 +1,222 @@
1/* kernel/perfmon_fsl_booke.c
2 * Freescale Book-E Performance Monitor code
3 *
4 * Author: Andy Fleming
5 * Copyright (c) 2004 Freescale Semiconductor, Inc
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 */
12
13#include <linux/errno.h>
14#include <linux/sched.h>
15#include <linux/kernel.h>
16#include <linux/mm.h>
17#include <linux/stddef.h>
18#include <linux/unistd.h>
19#include <linux/ptrace.h>
20#include <linux/slab.h>
21#include <linux/user.h>
22#include <linux/a.out.h>
23#include <linux/interrupt.h>
24#include <linux/config.h>
25#include <linux/init.h>
26#include <linux/module.h>
27#include <linux/prctl.h>
28
29#include <asm/pgtable.h>
30#include <asm/uaccess.h>
31#include <asm/system.h>
32#include <asm/io.h>
33#include <asm/reg.h>
34#include <asm/xmon.h>
35#include <asm/pmc.h>
36
37static inline u32 get_pmlca(int ctr);
38static inline void set_pmlca(int ctr, u32 pmlca);
39
40static inline u32 get_pmlca(int ctr)
41{
42 u32 pmlca;
43
44 switch (ctr) {
45 case 0:
46 pmlca = mfpmr(PMRN_PMLCA0);
47 break;
48 case 1:
49 pmlca = mfpmr(PMRN_PMLCA1);
50 break;
51 case 2:
52 pmlca = mfpmr(PMRN_PMLCA2);
53 break;
54 case 3:
55 pmlca = mfpmr(PMRN_PMLCA3);
56 break;
57 default:
58 panic("Bad ctr number\n");
59 }
60
61 return pmlca;
62}
63
64static inline void set_pmlca(int ctr, u32 pmlca)
65{
66 switch (ctr) {
67 case 0:
68 mtpmr(PMRN_PMLCA0, pmlca);
69 break;
70 case 1:
71 mtpmr(PMRN_PMLCA1, pmlca);
72 break;
73 case 2:
74 mtpmr(PMRN_PMLCA2, pmlca);
75 break;
76 case 3:
77 mtpmr(PMRN_PMLCA3, pmlca);
78 break;
79 default:
80 panic("Bad ctr number\n");
81 }
82}
83
84void init_pmc_stop(int ctr)
85{
86 u32 pmlca = (PMLCA_FC | PMLCA_FCS | PMLCA_FCU |
87 PMLCA_FCM1 | PMLCA_FCM0);
88 u32 pmlcb = 0;
89
90 switch (ctr) {
91 case 0:
92 mtpmr(PMRN_PMLCA0, pmlca);
93 mtpmr(PMRN_PMLCB0, pmlcb);
94 break;
95 case 1:
96 mtpmr(PMRN_PMLCA1, pmlca);
97 mtpmr(PMRN_PMLCB1, pmlcb);
98 break;
99 case 2:
100 mtpmr(PMRN_PMLCA2, pmlca);
101 mtpmr(PMRN_PMLCB2, pmlcb);
102 break;
103 case 3:
104 mtpmr(PMRN_PMLCA3, pmlca);
105 mtpmr(PMRN_PMLCB3, pmlcb);
106 break;
107 default:
108 panic("Bad ctr number!\n");
109 }
110}
111
112void set_pmc_event(int ctr, int event)
113{
114 u32 pmlca;
115
116 pmlca = get_pmlca(ctr);
117
118 pmlca = (pmlca & ~PMLCA_EVENT_MASK) |
119 ((event << PMLCA_EVENT_SHIFT) &
120 PMLCA_EVENT_MASK);
121
122 set_pmlca(ctr, pmlca);
123}
124
125void set_pmc_user_kernel(int ctr, int user, int kernel)
126{
127 u32 pmlca;
128
129 pmlca = get_pmlca(ctr);
130
131 if(user)
132 pmlca &= ~PMLCA_FCU;
133 else
134 pmlca |= PMLCA_FCU;
135
136 if(kernel)
137 pmlca &= ~PMLCA_FCS;
138 else
139 pmlca |= PMLCA_FCS;
140
141 set_pmlca(ctr, pmlca);
142}
143
144void set_pmc_marked(int ctr, int mark0, int mark1)
145{
146 u32 pmlca = get_pmlca(ctr);
147
148 if(mark0)
149 pmlca &= ~PMLCA_FCM0;
150 else
151 pmlca |= PMLCA_FCM0;
152
153 if(mark1)
154 pmlca &= ~PMLCA_FCM1;
155 else
156 pmlca |= PMLCA_FCM1;
157
158 set_pmlca(ctr, pmlca);
159}
160
161void pmc_start_ctr(int ctr, int enable)
162{
163 u32 pmlca = get_pmlca(ctr);
164
165 pmlca &= ~PMLCA_FC;
166
167 if (enable)
168 pmlca |= PMLCA_CE;
169 else
170 pmlca &= ~PMLCA_CE;
171
172 set_pmlca(ctr, pmlca);
173}
174
175void pmc_start_ctrs(int enable)
176{
177 u32 pmgc0 = mfpmr(PMRN_PMGC0);
178
179 pmgc0 &= ~PMGC0_FAC;
180 pmgc0 |= PMGC0_FCECE;
181
182 if (enable)
183 pmgc0 |= PMGC0_PMIE;
184 else
185 pmgc0 &= ~PMGC0_PMIE;
186
187 mtpmr(PMRN_PMGC0, pmgc0);
188}
189
190void pmc_stop_ctrs(void)
191{
192 u32 pmgc0 = mfpmr(PMRN_PMGC0);
193
194 pmgc0 |= PMGC0_FAC;
195
196 pmgc0 &= ~(PMGC0_PMIE | PMGC0_FCECE);
197
198 mtpmr(PMRN_PMGC0, pmgc0);
199}
200
201void dump_pmcs(void)
202{
203 printk("pmgc0: %x\n", mfpmr(PMRN_PMGC0));
204 printk("pmc\t\tpmlca\t\tpmlcb\n");
205 printk("%8x\t%8x\t%8x\n", mfpmr(PMRN_PMC0),
206 mfpmr(PMRN_PMLCA0), mfpmr(PMRN_PMLCB0));
207 printk("%8x\t%8x\t%8x\n", mfpmr(PMRN_PMC1),
208 mfpmr(PMRN_PMLCA1), mfpmr(PMRN_PMLCB1));
209 printk("%8x\t%8x\t%8x\n", mfpmr(PMRN_PMC2),
210 mfpmr(PMRN_PMLCA2), mfpmr(PMRN_PMLCB2));
211 printk("%8x\t%8x\t%8x\n", mfpmr(PMRN_PMC3),
212 mfpmr(PMRN_PMLCA3), mfpmr(PMRN_PMLCB3));
213}
214
215EXPORT_SYMBOL(init_pmc_stop);
216EXPORT_SYMBOL(set_pmc_event);
217EXPORT_SYMBOL(set_pmc_user_kernel);
218EXPORT_SYMBOL(set_pmc_marked);
219EXPORT_SYMBOL(pmc_start_ctr);
220EXPORT_SYMBOL(pmc_start_ctrs);
221EXPORT_SYMBOL(pmc_stop_ctrs);
222EXPORT_SYMBOL(dump_pmcs);
diff --git a/arch/powerpc/kernel/proc_ppc64.c b/arch/powerpc/kernel/proc_ppc64.c
index 7ba42a405f41..3c2cf661f6d9 100644
--- a/arch/powerpc/kernel/proc_ppc64.c
+++ b/arch/powerpc/kernel/proc_ppc64.c
@@ -23,6 +23,7 @@
23#include <linux/slab.h> 23#include <linux/slab.h>
24#include <linux/kernel.h> 24#include <linux/kernel.h>
25 25
26#include <asm/machdep.h>
26#include <asm/vdso_datapage.h> 27#include <asm/vdso_datapage.h>
27#include <asm/rtas.h> 28#include <asm/rtas.h>
28#include <asm/uaccess.h> 29#include <asm/uaccess.h>
@@ -51,7 +52,7 @@ static int __init proc_ppc64_create(void)
51 if (!root) 52 if (!root)
52 return 1; 53 return 1;
53 54
54 if (!(platform_is_pseries() || _machine == PLATFORM_CELL)) 55 if (!machine_is(pseries) && !machine_is(cell))
55 return 0; 56 return 0;
56 57
57 if (!proc_mkdir("rtas", root)) 58 if (!proc_mkdir("rtas", root))
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index f698aa77127e..706090c99f47 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -45,6 +45,7 @@
45#include <asm/prom.h> 45#include <asm/prom.h>
46#include <asm/machdep.h> 46#include <asm/machdep.h>
47#include <asm/time.h> 47#include <asm/time.h>
48#include <asm/syscalls.h>
48#ifdef CONFIG_PPC64 49#ifdef CONFIG_PPC64
49#include <asm/firmware.h> 50#include <asm/firmware.h>
50#endif 51#endif
@@ -362,7 +363,11 @@ static void show_instructions(struct pt_regs *regs)
362 if (!(i % 8)) 363 if (!(i % 8))
363 printk("\n"); 364 printk("\n");
364 365
365 if (BAD_PC(pc) || __get_user(instr, (unsigned int *)pc)) { 366 /* We use __get_user here *only* to avoid an OOPS on a
367 * bad address because the pc *should* only be a
368 * kernel address.
369 */
370 if (BAD_PC(pc) || __get_user(instr, (unsigned int __user *)pc)) {
366 printk("XXXXXXXX "); 371 printk("XXXXXXXX ");
367 } else { 372 } else {
368 if (regs->nip == pc) 373 if (regs->nip == pc)
@@ -765,7 +770,7 @@ out:
765 return error; 770 return error;
766} 771}
767 772
768static int validate_sp(unsigned long sp, struct task_struct *p, 773int validate_sp(unsigned long sp, struct task_struct *p,
769 unsigned long nbytes) 774 unsigned long nbytes)
770{ 775{
771 unsigned long stack_page = (unsigned long)task_stack_page(p); 776 unsigned long stack_page = (unsigned long)task_stack_page(p);
@@ -803,6 +808,8 @@ static int validate_sp(unsigned long sp, struct task_struct *p,
803#define FRAME_MARKER 2 808#define FRAME_MARKER 2
804#endif 809#endif
805 810
811EXPORT_SYMBOL(validate_sp);
812
806unsigned long get_wchan(struct task_struct *p) 813unsigned long get_wchan(struct task_struct *p)
807{ 814{
808 unsigned long ip, sp; 815 unsigned long ip, sp;
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index d63cd562d9d5..4336390bcf34 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -383,14 +383,14 @@ static int __devinit finish_node_interrupts(struct device_node *np,
383 /* Apple uses bits in there in a different way, let's 383 /* Apple uses bits in there in a different way, let's
384 * only keep the real sense bit on macs 384 * only keep the real sense bit on macs
385 */ 385 */
386 if (_machine == PLATFORM_POWERMAC) 386 if (machine_is(powermac))
387 sense &= 0x1; 387 sense &= 0x1;
388 np->intrs[intrcount].sense = map_mpic_senses[sense]; 388 np->intrs[intrcount].sense = map_mpic_senses[sense];
389 } 389 }
390 390
391#ifdef CONFIG_PPC64 391#ifdef CONFIG_PPC64
392 /* We offset irq numbers for the u3 MPIC by 128 in PowerMac */ 392 /* We offset irq numbers for the u3 MPIC by 128 in PowerMac */
393 if (_machine == PLATFORM_POWERMAC && ic && ic->parent) { 393 if (machine_is(powermac) && ic && ic->parent) {
394 char *name = get_property(ic->parent, "name", NULL); 394 char *name = get_property(ic->parent, "name", NULL);
395 if (name && !strcmp(name, "u3")) 395 if (name && !strcmp(name, "u3"))
396 np->intrs[intrcount].line += 128; 396 np->intrs[intrcount].line += 128;
@@ -570,6 +570,18 @@ int __init of_scan_flat_dt(int (*it)(unsigned long node,
570 return rc; 570 return rc;
571} 571}
572 572
573unsigned long __init of_get_flat_dt_root(void)
574{
575 unsigned long p = ((unsigned long)initial_boot_params) +
576 initial_boot_params->off_dt_struct;
577
578 while(*((u32 *)p) == OF_DT_NOP)
579 p += 4;
580 BUG_ON (*((u32 *)p) != OF_DT_BEGIN_NODE);
581 p += 4;
582 return _ALIGN(p + strlen((char *)p) + 1, 4);
583}
584
573/** 585/**
574 * This function can be used within scan_flattened_dt callback to get 586 * This function can be used within scan_flattened_dt callback to get
575 * access to properties 587 * access to properties
@@ -612,6 +624,25 @@ void* __init of_get_flat_dt_prop(unsigned long node, const char *name,
612 } while(1); 624 } while(1);
613} 625}
614 626
627int __init of_flat_dt_is_compatible(unsigned long node, const char *compat)
628{
629 const char* cp;
630 unsigned long cplen, l;
631
632 cp = of_get_flat_dt_prop(node, "compatible", &cplen);
633 if (cp == NULL)
634 return 0;
635 while (cplen > 0) {
636 if (strncasecmp(cp, compat, strlen(compat)) == 0)
637 return 1;
638 l = strlen(cp) + 1;
639 cp += l;
640 cplen -= l;
641 }
642
643 return 0;
644}
645
615static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size, 646static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size,
616 unsigned long align) 647 unsigned long align)
617{ 648{
@@ -686,7 +717,7 @@ static unsigned long __init unflatten_dt_node(unsigned long mem,
686#ifdef DEBUG 717#ifdef DEBUG
687 if ((strlen(p) + l + 1) != allocl) { 718 if ((strlen(p) + l + 1) != allocl) {
688 DBG("%s: p: %d, l: %d, a: %d\n", 719 DBG("%s: p: %d, l: %d, a: %d\n",
689 pathp, strlen(p), l, allocl); 720 pathp, (int)strlen(p), l, allocl);
690 } 721 }
691#endif 722#endif
692 p += strlen(p); 723 p += strlen(p);
@@ -854,35 +885,73 @@ void __init unflatten_device_tree(void)
854 DBG(" <- unflatten_device_tree()\n"); 885 DBG(" <- unflatten_device_tree()\n");
855} 886}
856 887
857
858static int __init early_init_dt_scan_cpus(unsigned long node, 888static int __init early_init_dt_scan_cpus(unsigned long node,
859 const char *uname, int depth, void *data) 889 const char *uname, int depth,
890 void *data)
860{ 891{
892 static int logical_cpuid = 0;
893 char *type = of_get_flat_dt_prop(node, "device_type", NULL);
894#ifdef CONFIG_ALTIVEC
861 u32 *prop; 895 u32 *prop;
862 unsigned long size; 896#endif
863 char *type = of_get_flat_dt_prop(node, "device_type", &size); 897 u32 *intserv;
898 int i, nthreads;
899 unsigned long len;
900 int found = 0;
864 901
865 /* We are scanning "cpu" nodes only */ 902 /* We are scanning "cpu" nodes only */
866 if (type == NULL || strcmp(type, "cpu") != 0) 903 if (type == NULL || strcmp(type, "cpu") != 0)
867 return 0; 904 return 0;
868 905
869 boot_cpuid = 0; 906 /* Get physical cpuid */
870 boot_cpuid_phys = 0; 907 intserv = of_get_flat_dt_prop(node, "ibm,ppc-interrupt-server#s", &len);
871 if (initial_boot_params && initial_boot_params->version >= 2) { 908 if (intserv) {
872 /* version 2 of the kexec param format adds the phys cpuid 909 nthreads = len / sizeof(int);
873 * of booted proc.
874 */
875 boot_cpuid_phys = initial_boot_params->boot_cpuid_phys;
876 } else { 910 } else {
877 /* Check if it's the boot-cpu, set it's hw index now */ 911 intserv = of_get_flat_dt_prop(node, "reg", NULL);
878 if (of_get_flat_dt_prop(node, 912 nthreads = 1;
913 }
914
915 /*
916 * Now see if any of these threads match our boot cpu.
917 * NOTE: This must match the parsing done in smp_setup_cpu_maps.
918 */
919 for (i = 0; i < nthreads; i++) {
920 /*
921 * version 2 of the kexec param format adds the phys cpuid of
922 * booted proc.
923 */
924 if (initial_boot_params && initial_boot_params->version >= 2) {
925 if (intserv[i] ==
926 initial_boot_params->boot_cpuid_phys) {
927 found = 1;
928 break;
929 }
930 } else {
931 /*
932 * Check if it's the boot-cpu, set it's hw index now,
933 * unfortunately this format did not support booting
934 * off secondary threads.
935 */
936 if (of_get_flat_dt_prop(node,
879 "linux,boot-cpu", NULL) != NULL) { 937 "linux,boot-cpu", NULL) != NULL) {
880 prop = of_get_flat_dt_prop(node, "reg", NULL); 938 found = 1;
881 if (prop != NULL) 939 break;
882 boot_cpuid_phys = *prop; 940 }
883 } 941 }
942
943#ifdef CONFIG_SMP
944 /* logical cpu id is always 0 on UP kernels */
945 logical_cpuid++;
946#endif
947 }
948
949 if (found) {
950 DBG("boot cpu: logical %d physical %d\n", logical_cpuid,
951 intserv[i]);
952 boot_cpuid = logical_cpuid;
953 set_hard_smp_processor_id(boot_cpuid, intserv[i]);
884 } 954 }
885 set_hard_smp_processor_id(0, boot_cpuid_phys);
886 955
887#ifdef CONFIG_ALTIVEC 956#ifdef CONFIG_ALTIVEC
888 /* Check if we have a VMX and eventually update CPU features */ 957 /* Check if we have a VMX and eventually update CPU features */
@@ -901,16 +970,10 @@ static int __init early_init_dt_scan_cpus(unsigned long node,
901#endif /* CONFIG_ALTIVEC */ 970#endif /* CONFIG_ALTIVEC */
902 971
903#ifdef CONFIG_PPC_PSERIES 972#ifdef CONFIG_PPC_PSERIES
904 /* 973 if (nthreads > 1)
905 * Check for an SMT capable CPU and set the CPU feature. We do
906 * this by looking at the size of the ibm,ppc-interrupt-server#s
907 * property
908 */
909 prop = (u32 *)of_get_flat_dt_prop(node, "ibm,ppc-interrupt-server#s",
910 &size);
911 cur_cpu_spec->cpu_features &= ~CPU_FTR_SMT;
912 if (prop && ((size / sizeof(u32)) > 1))
913 cur_cpu_spec->cpu_features |= CPU_FTR_SMT; 974 cur_cpu_spec->cpu_features |= CPU_FTR_SMT;
975 else
976 cur_cpu_spec->cpu_features &= ~CPU_FTR_SMT;
914#endif 977#endif
915 978
916 return 0; 979 return 0;
@@ -919,7 +982,6 @@ static int __init early_init_dt_scan_cpus(unsigned long node,
919static int __init early_init_dt_scan_chosen(unsigned long node, 982static int __init early_init_dt_scan_chosen(unsigned long node,
920 const char *uname, int depth, void *data) 983 const char *uname, int depth, void *data)
921{ 984{
922 u32 *prop;
923 unsigned long *lprop; 985 unsigned long *lprop;
924 unsigned long l; 986 unsigned long l;
925 char *p; 987 char *p;
@@ -930,14 +992,6 @@ static int __init early_init_dt_scan_chosen(unsigned long node,
930 (strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0)) 992 (strcmp(uname, "chosen") != 0 && strcmp(uname, "chosen@0") != 0))
931 return 0; 993 return 0;
932 994
933 /* get platform type */
934 prop = (u32 *)of_get_flat_dt_prop(node, "linux,platform", NULL);
935 if (prop == NULL)
936 return 0;
937#ifdef CONFIG_PPC_MULTIPLATFORM
938 _machine = *prop;
939#endif
940
941#ifdef CONFIG_PPC64 995#ifdef CONFIG_PPC64
942 /* check if iommu is forced on or off */ 996 /* check if iommu is forced on or off */
943 if (of_get_flat_dt_prop(node, "linux,iommu-off", NULL) != NULL) 997 if (of_get_flat_dt_prop(node, "linux,iommu-off", NULL) != NULL)
@@ -964,15 +1018,15 @@ static int __init early_init_dt_scan_chosen(unsigned long node,
964 * set of RTAS infos now if available 1018 * set of RTAS infos now if available
965 */ 1019 */
966 { 1020 {
967 u64 *basep, *entryp; 1021 u64 *basep, *entryp, *sizep;
968 1022
969 basep = of_get_flat_dt_prop(node, "linux,rtas-base", NULL); 1023 basep = of_get_flat_dt_prop(node, "linux,rtas-base", NULL);
970 entryp = of_get_flat_dt_prop(node, "linux,rtas-entry", NULL); 1024 entryp = of_get_flat_dt_prop(node, "linux,rtas-entry", NULL);
971 prop = of_get_flat_dt_prop(node, "linux,rtas-size", NULL); 1025 sizep = of_get_flat_dt_prop(node, "linux,rtas-size", NULL);
972 if (basep && entryp && prop) { 1026 if (basep && entryp && sizep) {
973 rtas.base = *basep; 1027 rtas.base = *basep;
974 rtas.entry = *entryp; 1028 rtas.entry = *entryp;
975 rtas.size = *prop; 1029 rtas.size = *sizep;
976 } 1030 }
977 } 1031 }
978#endif /* CONFIG_PPC_RTAS */ 1032#endif /* CONFIG_PPC_RTAS */
@@ -1001,25 +1055,13 @@ static int __init early_init_dt_scan_chosen(unsigned long node,
1001 1055
1002 if (strstr(cmd_line, "mem=")) { 1056 if (strstr(cmd_line, "mem=")) {
1003 char *p, *q; 1057 char *p, *q;
1004 unsigned long maxmem = 0;
1005 1058
1006 for (q = cmd_line; (p = strstr(q, "mem=")) != 0; ) { 1059 for (q = cmd_line; (p = strstr(q, "mem=")) != 0; ) {
1007 q = p + 4; 1060 q = p + 4;
1008 if (p > cmd_line && p[-1] != ' ') 1061 if (p > cmd_line && p[-1] != ' ')
1009 continue; 1062 continue;
1010 maxmem = simple_strtoul(q, &q, 0); 1063 memory_limit = memparse(q, &q);
1011 if (*q == 'k' || *q == 'K') {
1012 maxmem <<= 10;
1013 ++q;
1014 } else if (*q == 'm' || *q == 'M') {
1015 maxmem <<= 20;
1016 ++q;
1017 } else if (*q == 'g' || *q == 'G') {
1018 maxmem <<= 30;
1019 ++q;
1020 }
1021 } 1064 }
1022 memory_limit = maxmem;
1023 } 1065 }
1024 1066
1025 /* break now */ 1067 /* break now */
@@ -1755,7 +1797,7 @@ static int of_finish_dynamic_node(struct device_node *node)
1755 /* We don't support that function on PowerMac, at least 1797 /* We don't support that function on PowerMac, at least
1756 * not yet 1798 * not yet
1757 */ 1799 */
1758 if (_machine == PLATFORM_POWERMAC) 1800 if (machine_is(powermac))
1759 return -ENODEV; 1801 return -ENODEV;
1760 1802
1761 /* fix up new node's linux_phandle field */ 1803 /* fix up new node's linux_phandle field */
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
index 813c2cd194c2..d66c5e77fcff 100644
--- a/arch/powerpc/kernel/prom_init.c
+++ b/arch/powerpc/kernel/prom_init.c
@@ -180,6 +180,16 @@ static unsigned long __initdata prom_tce_alloc_start;
180static unsigned long __initdata prom_tce_alloc_end; 180static unsigned long __initdata prom_tce_alloc_end;
181#endif 181#endif
182 182
183/* Platforms codes are now obsolete in the kernel. Now only used within this
184 * file and ultimately gone too. Feel free to change them if you need, they
185 * are not shared with anything outside of this file anymore
186 */
187#define PLATFORM_PSERIES 0x0100
188#define PLATFORM_PSERIES_LPAR 0x0101
189#define PLATFORM_LPAR 0x0001
190#define PLATFORM_POWERMAC 0x0400
191#define PLATFORM_GENERIC 0x0500
192
183static int __initdata of_platform; 193static int __initdata of_platform;
184 194
185static char __initdata prom_cmd_line[COMMAND_LINE_SIZE]; 195static char __initdata prom_cmd_line[COMMAND_LINE_SIZE];
@@ -397,6 +407,11 @@ static void __init __attribute__((noreturn)) prom_panic(const char *reason)
397 reason = PTRRELOC(reason); 407 reason = PTRRELOC(reason);
398#endif 408#endif
399 prom_print(reason); 409 prom_print(reason);
410 /* Do not call exit because it clears the screen on pmac
411 * it also causes some sort of double-fault on early pmacs */
412 if (RELOC(of_platform) == PLATFORM_POWERMAC)
413 asm("trap\n");
414
400 /* ToDo: should put up an SRC here on p/iSeries */ 415 /* ToDo: should put up an SRC here on p/iSeries */
401 call_prom("exit", 0, 0); 416 call_prom("exit", 0, 0);
402 417
@@ -1487,7 +1502,10 @@ static int __init prom_find_machine_type(void)
1487 int len, i = 0; 1502 int len, i = 0;
1488#ifdef CONFIG_PPC64 1503#ifdef CONFIG_PPC64
1489 phandle rtas; 1504 phandle rtas;
1505 int x;
1490#endif 1506#endif
1507
1508 /* Look for a PowerMac */
1491 len = prom_getprop(_prom->root, "compatible", 1509 len = prom_getprop(_prom->root, "compatible",
1492 compat, sizeof(compat)-1); 1510 compat, sizeof(compat)-1);
1493 if (len > 0) { 1511 if (len > 0) {
@@ -1500,28 +1518,36 @@ static int __init prom_find_machine_type(void)
1500 if (strstr(p, RELOC("Power Macintosh")) || 1518 if (strstr(p, RELOC("Power Macintosh")) ||
1501 strstr(p, RELOC("MacRISC"))) 1519 strstr(p, RELOC("MacRISC")))
1502 return PLATFORM_POWERMAC; 1520 return PLATFORM_POWERMAC;
1503#ifdef CONFIG_PPC64
1504 if (strstr(p, RELOC("Momentum,Maple")))
1505 return PLATFORM_MAPLE;
1506 if (strstr(p, RELOC("IBM,CPB")))
1507 return PLATFORM_CELL;
1508#endif
1509 i += sl + 1; 1521 i += sl + 1;
1510 } 1522 }
1511 } 1523 }
1512#ifdef CONFIG_PPC64 1524#ifdef CONFIG_PPC64
1525 /* If not a mac, try to figure out if it's an IBM pSeries or any other
1526 * PAPR compliant platform. We assume it is if :
1527 * - /device_type is "chrp" (please, do NOT use that for future
1528 * non-IBM designs !
1529 * - it has /rtas
1530 */
1531 len = prom_getprop(_prom->root, "model",
1532 compat, sizeof(compat)-1);
1533 if (len <= 0)
1534 return PLATFORM_GENERIC;
1535 compat[len] = 0;
1536 if (strcmp(compat, "chrp"))
1537 return PLATFORM_GENERIC;
1538
1513 /* Default to pSeries. We need to know if we are running LPAR */ 1539 /* Default to pSeries. We need to know if we are running LPAR */
1514 rtas = call_prom("finddevice", 1, 1, ADDR("/rtas")); 1540 rtas = call_prom("finddevice", 1, 1, ADDR("/rtas"));
1515 if (PHANDLE_VALID(rtas)) { 1541 if (!PHANDLE_VALID(rtas))
1516 int x = prom_getproplen(rtas, "ibm,hypertas-functions"); 1542 return PLATFORM_GENERIC;
1517 if (x != PROM_ERROR) { 1543 x = prom_getproplen(rtas, "ibm,hypertas-functions");
1518 prom_printf("Hypertas detected, assuming LPAR !\n"); 1544 if (x != PROM_ERROR) {
1519 return PLATFORM_PSERIES_LPAR; 1545 prom_printf("Hypertas detected, assuming LPAR !\n");
1520 } 1546 return PLATFORM_PSERIES_LPAR;
1521 } 1547 }
1522 return PLATFORM_PSERIES; 1548 return PLATFORM_PSERIES;
1523#else 1549#else
1524 return PLATFORM_CHRP; 1550 return PLATFORM_GENERIC;
1525#endif 1551#endif
1526} 1552}
1527 1553
@@ -2029,7 +2055,6 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
2029{ 2055{
2030 struct prom_t *_prom; 2056 struct prom_t *_prom;
2031 unsigned long hdr; 2057 unsigned long hdr;
2032 u32 getprop_rval;
2033 unsigned long offset = reloc_offset(); 2058 unsigned long offset = reloc_offset();
2034 2059
2035#ifdef CONFIG_PPC32 2060#ifdef CONFIG_PPC32
@@ -2060,6 +2085,12 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
2060 */ 2085 */
2061 prom_init_stdout(); 2086 prom_init_stdout();
2062 2087
2088 /*
2089 * Get default machine type. At this point, we do not differentiate
2090 * between pSeries SMP and pSeries LPAR
2091 */
2092 RELOC(of_platform) = prom_find_machine_type();
2093
2063 /* Bail if this is a kdump kernel. */ 2094 /* Bail if this is a kdump kernel. */
2064 if (PHYSICAL_START > 0) 2095 if (PHYSICAL_START > 0)
2065 prom_panic("Error: You can't boot a kdump kernel from OF!\n"); 2096 prom_panic("Error: You can't boot a kdump kernel from OF!\n");
@@ -2069,15 +2100,6 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4,
2069 */ 2100 */
2070 prom_check_initrd(r3, r4); 2101 prom_check_initrd(r3, r4);
2071 2102
2072 /*
2073 * Get default machine type. At this point, we do not differentiate
2074 * between pSeries SMP and pSeries LPAR
2075 */
2076 RELOC(of_platform) = prom_find_machine_type();
2077 getprop_rval = RELOC(of_platform);
2078 prom_setprop(_prom->chosen, "/chosen", "linux,platform",
2079 &getprop_rval, sizeof(getprop_rval));
2080
2081#ifdef CONFIG_PPC_PSERIES 2103#ifdef CONFIG_PPC_PSERIES
2082 /* 2104 /*
2083 * On pSeries, inform the firmware about our capabilities 2105 * On pSeries, inform the firmware about our capabilities
diff --git a/arch/powerpc/kernel/rtas-proc.c b/arch/powerpc/kernel/rtas-proc.c
index 1f03fb28cc0a..456286cf1d14 100644
--- a/arch/powerpc/kernel/rtas-proc.c
+++ b/arch/powerpc/kernel/rtas-proc.c
@@ -257,7 +257,7 @@ static int __init proc_rtas_init(void)
257{ 257{
258 struct proc_dir_entry *entry; 258 struct proc_dir_entry *entry;
259 259
260 if (_machine != PLATFORM_PSERIES && _machine != PLATFORM_PSERIES_LPAR) 260 if (!machine_is(pseries))
261 return 1; 261 return 1;
262 262
263 rtas_node = of_find_node_by_name(NULL, "rtas"); 263 rtas_node = of_find_node_by_name(NULL, "rtas");
diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c
index b5b2add7ad1e..4b78ee0e5867 100644
--- a/arch/powerpc/kernel/rtas.c
+++ b/arch/powerpc/kernel/rtas.c
@@ -25,6 +25,7 @@
25#include <asm/hvcall.h> 25#include <asm/hvcall.h>
26#include <asm/semaphore.h> 26#include <asm/semaphore.h>
27#include <asm/machdep.h> 27#include <asm/machdep.h>
28#include <asm/firmware.h>
28#include <asm/page.h> 29#include <asm/page.h>
29#include <asm/param.h> 30#include <asm/param.h>
30#include <asm/system.h> 31#include <asm/system.h>
@@ -32,6 +33,7 @@
32#include <asm/uaccess.h> 33#include <asm/uaccess.h>
33#include <asm/lmb.h> 34#include <asm/lmb.h>
34#include <asm/udbg.h> 35#include <asm/udbg.h>
36#include <asm/syscalls.h>
35 37
36struct rtas_t rtas = { 38struct rtas_t rtas = {
37 .lock = SPIN_LOCK_UNLOCKED 39 .lock = SPIN_LOCK_UNLOCKED
@@ -767,7 +769,7 @@ void __init rtas_initialize(void)
767 * the stop-self token if any 769 * the stop-self token if any
768 */ 770 */
769#ifdef CONFIG_PPC64 771#ifdef CONFIG_PPC64
770 if (_machine == PLATFORM_PSERIES_LPAR) { 772 if (machine_is(pseries) && firmware_has_feature(FW_FEATURE_LPAR)) {
771 rtas_region = min(lmb.rmo_size, RTAS_INSTANTIATE_MAX); 773 rtas_region = min(lmb.rmo_size, RTAS_INSTANTIATE_MAX);
772 ibm_suspend_me_token = rtas_token("ibm,suspend-me"); 774 ibm_suspend_me_token = rtas_token("ibm,suspend-me");
773 } 775 }
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c
index c1d62bf11f29..3473cb9cb0ab 100644
--- a/arch/powerpc/kernel/setup-common.c
+++ b/arch/powerpc/kernel/setup-common.c
@@ -9,6 +9,9 @@
9 * as published by the Free Software Foundation; either version 9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version. 10 * 2 of the License, or (at your option) any later version.
11 */ 11 */
12
13#undef DEBUG
14
12#include <linux/config.h> 15#include <linux/config.h>
13#include <linux/module.h> 16#include <linux/module.h>
14#include <linux/string.h> 17#include <linux/string.h>
@@ -41,6 +44,7 @@
41#include <asm/time.h> 44#include <asm/time.h>
42#include <asm/cputable.h> 45#include <asm/cputable.h>
43#include <asm/sections.h> 46#include <asm/sections.h>
47#include <asm/firmware.h>
44#include <asm/btext.h> 48#include <asm/btext.h>
45#include <asm/nvram.h> 49#include <asm/nvram.h>
46#include <asm/setup.h> 50#include <asm/setup.h>
@@ -56,8 +60,6 @@
56 60
57#include "setup.h" 61#include "setup.h"
58 62
59#undef DEBUG
60
61#ifdef DEBUG 63#ifdef DEBUG
62#include <asm/udbg.h> 64#include <asm/udbg.h>
63#define DBG(fmt...) udbg_printf(fmt) 65#define DBG(fmt...) udbg_printf(fmt)
@@ -65,10 +67,12 @@
65#define DBG(fmt...) 67#define DBG(fmt...)
66#endif 68#endif
67 69
68#ifdef CONFIG_PPC_MULTIPLATFORM 70/* The main machine-dep calls structure
69int _machine = 0; 71 */
70EXPORT_SYMBOL(_machine); 72struct machdep_calls ppc_md;
71#endif 73EXPORT_SYMBOL(ppc_md);
74struct machdep_calls *machine_id;
75EXPORT_SYMBOL(machine_id);
72 76
73unsigned long klimit = (unsigned long) _end; 77unsigned long klimit = (unsigned long) _end;
74 78
@@ -168,7 +172,8 @@ static int show_cpuinfo(struct seq_file *m, void *v)
168 bogosum/(500000/HZ), bogosum/(5000/HZ) % 100); 172 bogosum/(500000/HZ), bogosum/(5000/HZ) % 100);
169#endif /* CONFIG_SMP && CONFIG_PPC32 */ 173#endif /* CONFIG_SMP && CONFIG_PPC32 */
170 seq_printf(m, "timebase\t: %lu\n", ppc_tb_freq); 174 seq_printf(m, "timebase\t: %lu\n", ppc_tb_freq);
171 175 if (ppc_md.name)
176 seq_printf(m, "platform\t: %s\n", ppc_md.name);
172 if (ppc_md.show_cpuinfo != NULL) 177 if (ppc_md.show_cpuinfo != NULL)
173 ppc_md.show_cpuinfo(m); 178 ppc_md.show_cpuinfo(m);
174 179
@@ -352,12 +357,13 @@ void __init check_for_initrd(void)
352 * must be called before using this. 357 * must be called before using this.
353 * 358 *
354 * While we're here, we may as well set the "physical" cpu ids in the paca. 359 * While we're here, we may as well set the "physical" cpu ids in the paca.
360 *
361 * NOTE: This must match the parsing done in early_init_dt_scan_cpus.
355 */ 362 */
356void __init smp_setup_cpu_maps(void) 363void __init smp_setup_cpu_maps(void)
357{ 364{
358 struct device_node *dn = NULL; 365 struct device_node *dn = NULL;
359 int cpu = 0; 366 int cpu = 0;
360 int swap_cpuid = 0;
361 367
362 while ((dn = of_find_node_by_type(dn, "cpu")) && cpu < NR_CPUS) { 368 while ((dn = of_find_node_by_type(dn, "cpu")) && cpu < NR_CPUS) {
363 int *intserv; 369 int *intserv;
@@ -376,30 +382,17 @@ void __init smp_setup_cpu_maps(void)
376 for (j = 0; j < nthreads && cpu < NR_CPUS; j++) { 382 for (j = 0; j < nthreads && cpu < NR_CPUS; j++) {
377 cpu_set(cpu, cpu_present_map); 383 cpu_set(cpu, cpu_present_map);
378 set_hard_smp_processor_id(cpu, intserv[j]); 384 set_hard_smp_processor_id(cpu, intserv[j]);
379
380 if (intserv[j] == boot_cpuid_phys)
381 swap_cpuid = cpu;
382 cpu_set(cpu, cpu_possible_map); 385 cpu_set(cpu, cpu_possible_map);
383 cpu++; 386 cpu++;
384 } 387 }
385 } 388 }
386 389
387 /* Swap CPU id 0 with boot_cpuid_phys, so we can always assume that
388 * boot cpu is logical 0.
389 */
390 if (boot_cpuid_phys != get_hard_smp_processor_id(0)) {
391 u32 tmp;
392 tmp = get_hard_smp_processor_id(0);
393 set_hard_smp_processor_id(0, boot_cpuid_phys);
394 set_hard_smp_processor_id(swap_cpuid, tmp);
395 }
396
397#ifdef CONFIG_PPC64 390#ifdef CONFIG_PPC64
398 /* 391 /*
399 * On pSeries LPAR, we need to know how many cpus 392 * On pSeries LPAR, we need to know how many cpus
400 * could possibly be added to this partition. 393 * could possibly be added to this partition.
401 */ 394 */
402 if (_machine == PLATFORM_PSERIES_LPAR && 395 if (machine_is(pseries) && firmware_has_feature(FW_FEATURE_LPAR) &&
403 (dn = of_find_node_by_path("/rtas"))) { 396 (dn = of_find_node_by_path("/rtas"))) {
404 int num_addr_cell, num_size_cell, maxcpus; 397 int num_addr_cell, num_size_cell, maxcpus;
405 unsigned int *ireg; 398 unsigned int *ireg;
@@ -468,3 +461,34 @@ static int __init early_xmon(char *p)
468} 461}
469early_param("xmon", early_xmon); 462early_param("xmon", early_xmon);
470#endif 463#endif
464
465void probe_machine(void)
466{
467 extern struct machdep_calls __machine_desc_start;
468 extern struct machdep_calls __machine_desc_end;
469
470 /*
471 * Iterate all ppc_md structures until we find the proper
472 * one for the current machine type
473 */
474 DBG("Probing machine type ...\n");
475
476 for (machine_id = &__machine_desc_start;
477 machine_id < &__machine_desc_end;
478 machine_id++) {
479 DBG(" %s ...", machine_id->name);
480 memcpy(&ppc_md, machine_id, sizeof(struct machdep_calls));
481 if (ppc_md.probe()) {
482 DBG(" match !\n");
483 break;
484 }
485 DBG("\n");
486 }
487 /* What can we do if we didn't find ? */
488 if (machine_id >= &__machine_desc_end) {
489 DBG("No suitable machine found !\n");
490 for (;;);
491 }
492
493 printk(KERN_INFO "Using %s machine description\n", ppc_md.name);
494}
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index dc2770df25b3..ae9c33d70731 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -53,9 +53,6 @@
53extern void platform_init(void); 53extern void platform_init(void);
54extern void bootx_init(unsigned long r4, unsigned long phys); 54extern void bootx_init(unsigned long r4, unsigned long phys);
55 55
56extern void ppc6xx_idle(void);
57extern void power4_idle(void);
58
59boot_infos_t *boot_infos; 56boot_infos_t *boot_infos;
60struct ide_machdep_calls ppc_ide_md; 57struct ide_machdep_calls ppc_ide_md;
61 58
@@ -70,10 +67,6 @@ unsigned int DMA_MODE_WRITE;
70int have_of = 1; 67int have_of = 1;
71 68
72#ifdef CONFIG_PPC_MULTIPLATFORM 69#ifdef CONFIG_PPC_MULTIPLATFORM
73extern void prep_init(void);
74extern void pmac_init(void);
75extern void chrp_init(void);
76
77dev_t boot_dev; 70dev_t boot_dev;
78#endif /* CONFIG_PPC_MULTIPLATFORM */ 71#endif /* CONFIG_PPC_MULTIPLATFORM */
79 72
@@ -85,9 +78,6 @@ unsigned long SYSRQ_KEY = 0x54;
85unsigned long vgacon_remap_base; 78unsigned long vgacon_remap_base;
86#endif 79#endif
87 80
88struct machdep_calls ppc_md;
89EXPORT_SYMBOL(ppc_md);
90
91/* 81/*
92 * These are used in binfmt_elf.c to put aux entries on the stack 82 * These are used in binfmt_elf.c to put aux entries on the stack
93 * for each elf executable being started. 83 * for each elf executable being started.
@@ -111,7 +101,7 @@ unsigned long __init early_init(unsigned long dt_ptr)
111 101
112 /* First zero the BSS -- use memset_io, some platforms don't have 102 /* First zero the BSS -- use memset_io, some platforms don't have
113 * caches on yet */ 103 * caches on yet */
114 memset_io(PTRRELOC(&__bss_start), 0, _end - __bss_start); 104 memset_io((void __iomem *)PTRRELOC(&__bss_start), 0, _end - __bss_start);
115 105
116 /* 106 /*
117 * Identify the CPU type and fix up code sections 107 * Identify the CPU type and fix up code sections
@@ -123,48 +113,6 @@ unsigned long __init early_init(unsigned long dt_ptr)
123 return KERNELBASE + offset; 113 return KERNELBASE + offset;
124} 114}
125 115
126#ifdef CONFIG_PPC_MULTIPLATFORM
127/*
128 * The PPC_MULTIPLATFORM version of platform_init...
129 */
130void __init platform_init(void)
131{
132 /* if we didn't get any bootinfo telling us what we are... */
133 if (_machine == 0) {
134 /* prep boot loader tells us if we're prep or not */
135 if ( *(unsigned long *)(KERNELBASE) == (0xdeadc0de) )
136 _machine = _MACH_prep;
137 }
138
139#ifdef CONFIG_PPC_PREP
140 /* not much more to do here, if prep */
141 if (_machine == _MACH_prep) {
142 prep_init();
143 return;
144 }
145#endif
146
147#ifdef CONFIG_ADB
148 if (strstr(cmd_line, "adb_sync")) {
149 extern int __adb_probe_sync;
150 __adb_probe_sync = 1;
151 }
152#endif /* CONFIG_ADB */
153
154 switch (_machine) {
155#ifdef CONFIG_PPC_PMAC
156 case _MACH_Pmac:
157 pmac_init();
158 break;
159#endif
160#ifdef CONFIG_PPC_CHRP
161 case _MACH_chrp:
162 chrp_init();
163 break;
164#endif
165 }
166}
167#endif
168 116
169/* 117/*
170 * Find out what kind of machine we're on and save any data we need 118 * Find out what kind of machine we're on and save any data we need
@@ -190,11 +138,17 @@ void __init machine_init(unsigned long dt_ptr, unsigned long phys)
190 strlcpy(cmd_line, CONFIG_CMDLINE, sizeof(cmd_line)); 138 strlcpy(cmd_line, CONFIG_CMDLINE, sizeof(cmd_line));
191#endif /* CONFIG_CMDLINE */ 139#endif /* CONFIG_CMDLINE */
192 140
193 /* Base init based on machine type */ 141#ifdef CONFIG_PPC_MULTIPLATFORM
142 probe_machine();
143#else
144 /* Base init based on machine type. Obsoloete, please kill ! */
194 platform_init(); 145 platform_init();
146#endif
195 147
196#ifdef CONFIG_6xx 148#ifdef CONFIG_6xx
197 ppc_md.power_save = ppc6xx_idle; 149 if (cpu_has_feature(CPU_FTR_CAN_DOZE) ||
150 cpu_has_feature(CPU_FTR_CAN_NAP))
151 ppc_md.power_save = ppc6xx_idle;
198#endif 152#endif
199 153
200 if (ppc_md.progress) 154 if (ppc_md.progress)
@@ -352,12 +306,6 @@ void __init setup_arch(char **cmdline_p)
352 do_init_bootmem(); 306 do_init_bootmem();
353 if ( ppc_md.progress ) ppc_md.progress("setup_arch: bootmem", 0x3eab); 307 if ( ppc_md.progress ) ppc_md.progress("setup_arch: bootmem", 0x3eab);
354 308
355#ifdef CONFIG_PPC_OCP
356 /* Initialize OCP device list */
357 ocp_early_init();
358 if ( ppc_md.progress ) ppc_md.progress("ocp: exit", 0x3eab);
359#endif
360
361#ifdef CONFIG_DUMMY_CONSOLE 309#ifdef CONFIG_DUMMY_CONSOLE
362 conswitchp = &dummy_con; 310 conswitchp = &dummy_con;
363#endif 311#endif
@@ -366,7 +314,4 @@ void __init setup_arch(char **cmdline_p)
366 if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab); 314 if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab);
367 315
368 paging_init(); 316 paging_init();
369
370 /* this is for modules since _machine can be a define -- Cort */
371 ppc_md.ppc_machine = _machine;
372} 317}
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index e20c1fae3423..05b152299396 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -73,7 +73,6 @@
73 73
74int have_of = 1; 74int have_of = 1;
75int boot_cpuid = 0; 75int boot_cpuid = 0;
76int boot_cpuid_phys = 0;
77dev_t boot_dev; 76dev_t boot_dev;
78u64 ppc64_pft_size; 77u64 ppc64_pft_size;
79 78
@@ -96,11 +95,6 @@ int dcache_bsize;
96int icache_bsize; 95int icache_bsize;
97int ucache_bsize; 96int ucache_bsize;
98 97
99/* The main machine-dep calls structure
100 */
101struct machdep_calls ppc_md;
102EXPORT_SYMBOL(ppc_md);
103
104#ifdef CONFIG_MAGIC_SYSRQ 98#ifdef CONFIG_MAGIC_SYSRQ
105unsigned long SYSRQ_KEY; 99unsigned long SYSRQ_KEY;
106#endif /* CONFIG_MAGIC_SYSRQ */ 100#endif /* CONFIG_MAGIC_SYSRQ */
@@ -161,32 +155,6 @@ early_param("smt-enabled", early_smt_enabled);
161#define check_smt_enabled() 155#define check_smt_enabled()
162#endif /* CONFIG_SMP */ 156#endif /* CONFIG_SMP */
163 157
164extern struct machdep_calls pSeries_md;
165extern struct machdep_calls pmac_md;
166extern struct machdep_calls maple_md;
167extern struct machdep_calls cell_md;
168extern struct machdep_calls iseries_md;
169
170/* Ultimately, stuff them in an elf section like initcalls... */
171static struct machdep_calls __initdata *machines[] = {
172#ifdef CONFIG_PPC_PSERIES
173 &pSeries_md,
174#endif /* CONFIG_PPC_PSERIES */
175#ifdef CONFIG_PPC_PMAC
176 &pmac_md,
177#endif /* CONFIG_PPC_PMAC */
178#ifdef CONFIG_PPC_MAPLE
179 &maple_md,
180#endif /* CONFIG_PPC_MAPLE */
181#ifdef CONFIG_PPC_CELL
182 &cell_md,
183#endif
184#ifdef CONFIG_PPC_ISERIES
185 &iseries_md,
186#endif
187 NULL
188};
189
190/* 158/*
191 * Early initialization entry point. This is called by head.S 159 * Early initialization entry point. This is called by head.S
192 * with MMU translation disabled. We rely on the "feature" of 160 * with MMU translation disabled. We rely on the "feature" of
@@ -208,13 +176,10 @@ static struct machdep_calls __initdata *machines[] = {
208 176
209void __init early_setup(unsigned long dt_ptr) 177void __init early_setup(unsigned long dt_ptr)
210{ 178{
211 struct paca_struct *lpaca = get_paca();
212 static struct machdep_calls **mach;
213
214 /* Enable early debugging if any specified (see udbg.h) */ 179 /* Enable early debugging if any specified (see udbg.h) */
215 udbg_early_init(); 180 udbg_early_init();
216 181
217 DBG(" -> early_setup()\n"); 182 DBG(" -> early_setup(), dt_ptr: 0x%lx\n", dt_ptr);
218 183
219 /* 184 /*
220 * Do early initializations using the flattened device 185 * Do early initializations using the flattened device
@@ -223,22 +188,16 @@ void __init early_setup(unsigned long dt_ptr)
223 */ 188 */
224 early_init_devtree(__va(dt_ptr)); 189 early_init_devtree(__va(dt_ptr));
225 190
226 /* 191 /* Now we know the logical id of our boot cpu, setup the paca. */
227 * Iterate all ppc_md structures until we find the proper 192 setup_boot_paca();
228 * one for the current machine type
229 */
230 DBG("Probing machine type for platform %x...\n", _machine);
231 193
232 for (mach = machines; *mach; mach++) { 194 /* Fix up paca fields required for the boot cpu */
233 if ((*mach)->probe(_machine)) 195 get_paca()->cpu_start = 1;
234 break; 196 get_paca()->stab_real = __pa((u64)&initial_stab);
235 } 197 get_paca()->stab_addr = (u64)&initial_stab;
236 /* What can we do if we didn't find ? */ 198
237 if (*mach == NULL) { 199 /* Probe the machine type */
238 DBG("No suitable machine found !\n"); 200 probe_machine();
239 for (;;);
240 }
241 ppc_md = **mach;
242 201
243#ifdef CONFIG_CRASH_DUMP 202#ifdef CONFIG_CRASH_DUMP
244 kdump_setup(); 203 kdump_setup();
@@ -260,7 +219,7 @@ void __init early_setup(unsigned long dt_ptr)
260 if (cpu_has_feature(CPU_FTR_SLB)) 219 if (cpu_has_feature(CPU_FTR_SLB))
261 slb_initialize(); 220 slb_initialize();
262 else 221 else
263 stab_initialize(lpaca->stab_real); 222 stab_initialize(get_paca()->stab_real);
264 } 223 }
265 224
266 DBG(" <- early_setup()\n"); 225 DBG(" <- early_setup()\n");
@@ -340,7 +299,7 @@ static void __init initialize_cache_info(void)
340 const char *dc, *ic; 299 const char *dc, *ic;
341 300
342 /* Then read cache informations */ 301 /* Then read cache informations */
343 if (_machine == PLATFORM_POWERMAC) { 302 if (machine_is(powermac)) {
344 dc = "d-cache-block-size"; 303 dc = "d-cache-block-size";
345 ic = "i-cache-block-size"; 304 ic = "i-cache-block-size";
346 } else { 305 } else {
@@ -484,7 +443,6 @@ void __init setup_system(void)
484 printk("ppc64_pft_size = 0x%lx\n", ppc64_pft_size); 443 printk("ppc64_pft_size = 0x%lx\n", ppc64_pft_size);
485 printk("ppc64_interrupt_controller = 0x%ld\n", 444 printk("ppc64_interrupt_controller = 0x%ld\n",
486 ppc64_interrupt_controller); 445 ppc64_interrupt_controller);
487 printk("platform = 0x%x\n", _machine);
488 printk("physicalMemorySize = 0x%lx\n", lmb_phys_mem_size()); 446 printk("physicalMemorySize = 0x%lx\n", lmb_phys_mem_size());
489 printk("ppc64_caches.dcache_line_size = 0x%x\n", 447 printk("ppc64_caches.dcache_line_size = 0x%x\n",
490 ppc64_caches.dline_size); 448 ppc64_caches.dline_size);
@@ -602,12 +560,6 @@ void __init setup_arch(char **cmdline_p)
602 560
603 ppc_md.setup_arch(); 561 ppc_md.setup_arch();
604 562
605 /* Use the default idle loop if the platform hasn't provided one. */
606 if (NULL == ppc_md.idle_loop) {
607 ppc_md.idle_loop = default_idle;
608 printk(KERN_INFO "Using default idle loop\n");
609 }
610
611 paging_init(); 563 paging_init();
612 ppc64_boot_msg(0x15, "Setup Done"); 564 ppc64_boot_msg(0x15, "Setup Done");
613} 565}
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index d7a4e814974d..01e3c08cb550 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -42,6 +42,7 @@
42 42
43#include <asm/uaccess.h> 43#include <asm/uaccess.h>
44#include <asm/cacheflush.h> 44#include <asm/cacheflush.h>
45#include <asm/syscalls.h>
45#include <asm/sigcontext.h> 46#include <asm/sigcontext.h>
46#include <asm/vdso.h> 47#include <asm/vdso.h>
47#ifdef CONFIG_PPC64 48#ifdef CONFIG_PPC64
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c
index 47f910380a6a..27f65b95184d 100644
--- a/arch/powerpc/kernel/signal_64.c
+++ b/arch/powerpc/kernel/signal_64.c
@@ -33,6 +33,7 @@
33#include <asm/pgtable.h> 33#include <asm/pgtable.h>
34#include <asm/unistd.h> 34#include <asm/unistd.h>
35#include <asm/cacheflush.h> 35#include <asm/cacheflush.h>
36#include <asm/syscalls.h>
36#include <asm/vdso.h> 37#include <asm/vdso.h>
37 38
38#define DEBUG_SIG 0 39#define DEBUG_SIG 0
@@ -211,7 +212,7 @@ static inline void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs
211 /* Default to using normal stack */ 212 /* Default to using normal stack */
212 newsp = regs->gpr[1]; 213 newsp = regs->gpr[1];
213 214
214 if (ka->sa.sa_flags & SA_ONSTACK) { 215 if ((ka->sa.sa_flags & SA_ONSTACK) && current->sas_ss_size) {
215 if (! on_sig_stack(regs->gpr[1])) 216 if (! on_sig_stack(regs->gpr[1]))
216 newsp = (current->sas_ss_sp + current->sas_ss_size); 217 newsp = (current->sas_ss_sp + current->sas_ss_size);
217 } 218 }
diff --git a/arch/powerpc/kernel/swsusp_32.S b/arch/powerpc/kernel/swsusp_32.S
new file mode 100644
index 000000000000..69773cc1a85f
--- /dev/null
+++ b/arch/powerpc/kernel/swsusp_32.S
@@ -0,0 +1,349 @@
1#include <linux/config.h>
2#include <linux/threads.h>
3#include <asm/processor.h>
4#include <asm/page.h>
5#include <asm/cputable.h>
6#include <asm/thread_info.h>
7#include <asm/ppc_asm.h>
8#include <asm/asm-offsets.h>
9
10
11/*
12 * Structure for storing CPU registers on the save area.
13 */
14#define SL_SP 0
15#define SL_PC 4
16#define SL_MSR 8
17#define SL_SDR1 0xc
18#define SL_SPRG0 0x10 /* 4 sprg's */
19#define SL_DBAT0 0x20
20#define SL_IBAT0 0x28
21#define SL_DBAT1 0x30
22#define SL_IBAT1 0x38
23#define SL_DBAT2 0x40
24#define SL_IBAT2 0x48
25#define SL_DBAT3 0x50
26#define SL_IBAT3 0x58
27#define SL_TB 0x60
28#define SL_R2 0x68
29#define SL_CR 0x6c
30#define SL_LR 0x70
31#define SL_R12 0x74 /* r12 to r31 */
32#define SL_SIZE (SL_R12 + 80)
33
34 .section .data
35 .align 5
36
37_GLOBAL(swsusp_save_area)
38 .space SL_SIZE
39
40
41 .section .text
42 .align 5
43
44_GLOBAL(swsusp_arch_suspend)
45
46 lis r11,swsusp_save_area@h
47 ori r11,r11,swsusp_save_area@l
48
49 mflr r0
50 stw r0,SL_LR(r11)
51 mfcr r0
52 stw r0,SL_CR(r11)
53 stw r1,SL_SP(r11)
54 stw r2,SL_R2(r11)
55 stmw r12,SL_R12(r11)
56
57 /* Save MSR & SDR1 */
58 mfmsr r4
59 stw r4,SL_MSR(r11)
60 mfsdr1 r4
61 stw r4,SL_SDR1(r11)
62
63 /* Get a stable timebase and save it */
641: mftbu r4
65 stw r4,SL_TB(r11)
66 mftb r5
67 stw r5,SL_TB+4(r11)
68 mftbu r3
69 cmpw r3,r4
70 bne 1b
71
72 /* Save SPRGs */
73 mfsprg r4,0
74 stw r4,SL_SPRG0(r11)
75 mfsprg r4,1
76 stw r4,SL_SPRG0+4(r11)
77 mfsprg r4,2
78 stw r4,SL_SPRG0+8(r11)
79 mfsprg r4,3
80 stw r4,SL_SPRG0+12(r11)
81
82 /* Save BATs */
83 mfdbatu r4,0
84 stw r4,SL_DBAT0(r11)
85 mfdbatl r4,0
86 stw r4,SL_DBAT0+4(r11)
87 mfdbatu r4,1
88 stw r4,SL_DBAT1(r11)
89 mfdbatl r4,1
90 stw r4,SL_DBAT1+4(r11)
91 mfdbatu r4,2
92 stw r4,SL_DBAT2(r11)
93 mfdbatl r4,2
94 stw r4,SL_DBAT2+4(r11)
95 mfdbatu r4,3
96 stw r4,SL_DBAT3(r11)
97 mfdbatl r4,3
98 stw r4,SL_DBAT3+4(r11)
99 mfibatu r4,0
100 stw r4,SL_IBAT0(r11)
101 mfibatl r4,0
102 stw r4,SL_IBAT0+4(r11)
103 mfibatu r4,1
104 stw r4,SL_IBAT1(r11)
105 mfibatl r4,1
106 stw r4,SL_IBAT1+4(r11)
107 mfibatu r4,2
108 stw r4,SL_IBAT2(r11)
109 mfibatl r4,2
110 stw r4,SL_IBAT2+4(r11)
111 mfibatu r4,3
112 stw r4,SL_IBAT3(r11)
113 mfibatl r4,3
114 stw r4,SL_IBAT3+4(r11)
115
116#if 0
117 /* Backup various CPU config stuffs */
118 bl __save_cpu_setup
119#endif
120 /* Call the low level suspend stuff (we should probably have made
121 * a stackframe...
122 */
123 bl swsusp_save
124
125 /* Restore LR from the save area */
126 lis r11,swsusp_save_area@h
127 ori r11,r11,swsusp_save_area@l
128 lwz r0,SL_LR(r11)
129 mtlr r0
130
131 blr
132
133
134/* Resume code */
135_GLOBAL(swsusp_arch_resume)
136
137 /* Stop pending alitvec streams and memory accesses */
138BEGIN_FTR_SECTION
139 DSSALL
140END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
141 sync
142
143 /* Disable MSR:DR to make sure we don't take a TLB or
144 * hash miss during the copy, as our hash table will
145 * for a while be unuseable. For .text, we assume we are
146 * covered by a BAT. This works only for non-G5 at this
147 * point. G5 will need a better approach, possibly using
148 * a small temporary hash table filled with large mappings,
149 * disabling the MMU completely isn't a good option for
150 * performance reasons.
151 * (Note that 750's may have the same performance issue as
152 * the G5 in this case, we should investigate using moving
153 * BATs for these CPUs)
154 */
155 mfmsr r0
156 sync
157 rlwinm r0,r0,0,28,26 /* clear MSR_DR */
158 mtmsr r0
159 sync
160 isync
161
162 /* Load ptr the list of pages to copy in r3 */
163 lis r11,(pagedir_nosave - KERNELBASE)@h
164 ori r11,r11,pagedir_nosave@l
165 lwz r10,0(r11)
166
167 /* Copy the pages. This is a very basic implementation, to
168 * be replaced by something more cache efficient */
1691:
170 tophys(r3,r10)
171 li r0,256
172 mtctr r0
173 lwz r11,pbe_address(r3) /* source */
174 tophys(r5,r11)
175 lwz r10,pbe_orig_address(r3) /* destination */
176 tophys(r6,r10)
1772:
178 lwz r8,0(r5)
179 lwz r9,4(r5)
180 lwz r10,8(r5)
181 lwz r11,12(r5)
182 addi r5,r5,16
183 stw r8,0(r6)
184 stw r9,4(r6)
185 stw r10,8(r6)
186 stw r11,12(r6)
187 addi r6,r6,16
188 bdnz 2b
189 lwz r10,pbe_next(r3)
190 cmpwi 0,r10,0
191 bne 1b
192
193 /* Do a very simple cache flush/inval of the L1 to ensure
194 * coherency of the icache
195 */
196 lis r3,0x0002
197 mtctr r3
198 li r3, 0
1991:
200 lwz r0,0(r3)
201 addi r3,r3,0x0020
202 bdnz 1b
203 isync
204 sync
205
206 /* Now flush those cache lines */
207 lis r3,0x0002
208 mtctr r3
209 li r3, 0
2101:
211 dcbf 0,r3
212 addi r3,r3,0x0020
213 bdnz 1b
214 sync
215
216 /* Ok, we are now running with the kernel data of the old
217 * kernel fully restored. We can get to the save area
218 * easily now. As for the rest of the code, it assumes the
219 * loader kernel and the booted one are exactly identical
220 */
221 lis r11,swsusp_save_area@h
222 ori r11,r11,swsusp_save_area@l
223 tophys(r11,r11)
224
225#if 0
226 /* Restore various CPU config stuffs */
227 bl __restore_cpu_setup
228#endif
229 /* Restore the BATs, and SDR1. Then we can turn on the MMU.
230 * This is a bit hairy as we are running out of those BATs,
231 * but first, our code is probably in the icache, and we are
232 * writing the same value to the BAT, so that should be fine,
233 * though a better solution will have to be found long-term
234 */
235 lwz r4,SL_SDR1(r11)
236 mtsdr1 r4
237 lwz r4,SL_SPRG0(r11)
238 mtsprg 0,r4
239 lwz r4,SL_SPRG0+4(r11)
240 mtsprg 1,r4
241 lwz r4,SL_SPRG0+8(r11)
242 mtsprg 2,r4
243 lwz r4,SL_SPRG0+12(r11)
244 mtsprg 3,r4
245
246#if 0
247 lwz r4,SL_DBAT0(r11)
248 mtdbatu 0,r4
249 lwz r4,SL_DBAT0+4(r11)
250 mtdbatl 0,r4
251 lwz r4,SL_DBAT1(r11)
252 mtdbatu 1,r4
253 lwz r4,SL_DBAT1+4(r11)
254 mtdbatl 1,r4
255 lwz r4,SL_DBAT2(r11)
256 mtdbatu 2,r4
257 lwz r4,SL_DBAT2+4(r11)
258 mtdbatl 2,r4
259 lwz r4,SL_DBAT3(r11)
260 mtdbatu 3,r4
261 lwz r4,SL_DBAT3+4(r11)
262 mtdbatl 3,r4
263 lwz r4,SL_IBAT0(r11)
264 mtibatu 0,r4
265 lwz r4,SL_IBAT0+4(r11)
266 mtibatl 0,r4
267 lwz r4,SL_IBAT1(r11)
268 mtibatu 1,r4
269 lwz r4,SL_IBAT1+4(r11)
270 mtibatl 1,r4
271 lwz r4,SL_IBAT2(r11)
272 mtibatu 2,r4
273 lwz r4,SL_IBAT2+4(r11)
274 mtibatl 2,r4
275 lwz r4,SL_IBAT3(r11)
276 mtibatu 3,r4
277 lwz r4,SL_IBAT3+4(r11)
278 mtibatl 3,r4
279#endif
280
281BEGIN_FTR_SECTION
282 li r4,0
283 mtspr SPRN_DBAT4U,r4
284 mtspr SPRN_DBAT4L,r4
285 mtspr SPRN_DBAT5U,r4
286 mtspr SPRN_DBAT5L,r4
287 mtspr SPRN_DBAT6U,r4
288 mtspr SPRN_DBAT6L,r4
289 mtspr SPRN_DBAT7U,r4
290 mtspr SPRN_DBAT7L,r4
291 mtspr SPRN_IBAT4U,r4
292 mtspr SPRN_IBAT4L,r4
293 mtspr SPRN_IBAT5U,r4
294 mtspr SPRN_IBAT5L,r4
295 mtspr SPRN_IBAT6U,r4
296 mtspr SPRN_IBAT6L,r4
297 mtspr SPRN_IBAT7U,r4
298 mtspr SPRN_IBAT7L,r4
299END_FTR_SECTION_IFSET(CPU_FTR_HAS_HIGH_BATS)
300
301 /* Flush all TLBs */
302 lis r4,0x1000
3031: addic. r4,r4,-0x1000
304 tlbie r4
305 blt 1b
306 sync
307
308 /* restore the MSR and turn on the MMU */
309 lwz r3,SL_MSR(r11)
310 bl turn_on_mmu
311 tovirt(r11,r11)
312
313 /* Restore TB */
314 li r3,0
315 mttbl r3
316 lwz r3,SL_TB(r11)
317 lwz r4,SL_TB+4(r11)
318 mttbu r3
319 mttbl r4
320
321 /* Kick decrementer */
322 li r0,1
323 mtdec r0
324
325 /* Restore the callee-saved registers and return */
326 lwz r0,SL_CR(r11)
327 mtcr r0
328 lwz r2,SL_R2(r11)
329 lmw r12,SL_R12(r11)
330 lwz r1,SL_SP(r11)
331 lwz r0,SL_LR(r11)
332 mtlr r0
333
334 // XXX Note: we don't really need to call swsusp_resume
335
336 li r3,0
337 blr
338
339/* FIXME:This construct is actually not useful since we don't shut
340 * down the instruction MMU, we could just flip back MSR-DR on.
341 */
342turn_on_mmu:
343 mflr r4
344 mtsrr0 r4
345 mtsrr1 r3
346 sync
347 isync
348 rfi
349
diff --git a/arch/powerpc/kernel/syscalls.c b/arch/powerpc/kernel/syscalls.c
index ad895c99813b..9b69d99a9103 100644
--- a/arch/powerpc/kernel/syscalls.c
+++ b/arch/powerpc/kernel/syscalls.c
@@ -40,6 +40,7 @@
40#include <asm/uaccess.h> 40#include <asm/uaccess.h>
41#include <asm/ipc.h> 41#include <asm/ipc.h>
42#include <asm/semaphore.h> 42#include <asm/semaphore.h>
43#include <asm/syscalls.h>
43#include <asm/time.h> 44#include <asm/time.h>
44#include <asm/unistd.h> 45#include <asm/unistd.h>
45 46
diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c
index 0f0c3a9ae2e5..aca2f09cd842 100644
--- a/arch/powerpc/kernel/sysfs.c
+++ b/arch/powerpc/kernel/sysfs.c
@@ -65,11 +65,11 @@ static int __init smt_setup(void)
65 unsigned int cpu; 65 unsigned int cpu;
66 66
67 if (!cpu_has_feature(CPU_FTR_SMT)) 67 if (!cpu_has_feature(CPU_FTR_SMT))
68 return 1; 68 return -ENODEV;
69 69
70 options = find_path_device("/options"); 70 options = find_path_device("/options");
71 if (!options) 71 if (!options)
72 return 1; 72 return -ENODEV;
73 73
74 val = (unsigned int *)get_property(options, "ibm,smt-snooze-delay", 74 val = (unsigned int *)get_property(options, "ibm,smt-snooze-delay",
75 NULL); 75 NULL);
@@ -78,7 +78,7 @@ static int __init smt_setup(void)
78 per_cpu(smt_snooze_delay, cpu) = *val; 78 per_cpu(smt_snooze_delay, cpu) = *val;
79 } 79 }
80 80
81 return 1; 81 return 0;
82} 82}
83__initcall(smt_setup); 83__initcall(smt_setup);
84 84
diff --git a/arch/powerpc/kernel/tau_6xx.c b/arch/powerpc/kernel/tau_6xx.c
new file mode 100644
index 000000000000..26bd8ea35a4e
--- /dev/null
+++ b/arch/powerpc/kernel/tau_6xx.c
@@ -0,0 +1,271 @@
1/*
2 * temp.c Thermal management for cpu's with Thermal Assist Units
3 *
4 * Written by Troy Benjegerdes <hozer@drgw.net>
5 *
6 * TODO:
7 * dynamic power management to limit peak CPU temp (using ICTC)
8 * calibration???
9 *
10 * Silly, crazy ideas: use cpu load (from scheduler) and ICTC to extend battery
11 * life in portables, and add a 'performance/watt' metric somewhere in /proc
12 */
13
14#include <linux/config.h>
15#include <linux/errno.h>
16#include <linux/jiffies.h>
17#include <linux/kernel.h>
18#include <linux/param.h>
19#include <linux/string.h>
20#include <linux/mm.h>
21#include <linux/interrupt.h>
22#include <linux/init.h>
23
24#include <asm/io.h>
25#include <asm/reg.h>
26#include <asm/nvram.h>
27#include <asm/cache.h>
28#include <asm/8xx_immap.h>
29#include <asm/machdep.h>
30
31static struct tau_temp
32{
33 int interrupts;
34 unsigned char low;
35 unsigned char high;
36 unsigned char grew;
37} tau[NR_CPUS];
38
39struct timer_list tau_timer;
40
41#undef DEBUG
42
43/* TODO: put these in a /proc interface, with some sanity checks, and maybe
44 * dynamic adjustment to minimize # of interrupts */
45/* configurable values for step size and how much to expand the window when
46 * we get an interrupt. These are based on the limit that was out of range */
47#define step_size 2 /* step size when temp goes out of range */
48#define window_expand 1 /* expand the window by this much */
49/* configurable values for shrinking the window */
50#define shrink_timer 2*HZ /* period between shrinking the window */
51#define min_window 2 /* minimum window size, degrees C */
52
53void set_thresholds(unsigned long cpu)
54{
55#ifdef CONFIG_TAU_INT
56 /*
57 * setup THRM1,
58 * threshold, valid bit, enable interrupts, interrupt when below threshold
59 */
60 mtspr(SPRN_THRM1, THRM1_THRES(tau[cpu].low) | THRM1_V | THRM1_TIE | THRM1_TID);
61
62 /* setup THRM2,
63 * threshold, valid bit, enable interrupts, interrupt when above threshhold
64 */
65 mtspr (SPRN_THRM2, THRM1_THRES(tau[cpu].high) | THRM1_V | THRM1_TIE);
66#else
67 /* same thing but don't enable interrupts */
68 mtspr(SPRN_THRM1, THRM1_THRES(tau[cpu].low) | THRM1_V | THRM1_TID);
69 mtspr(SPRN_THRM2, THRM1_THRES(tau[cpu].high) | THRM1_V);
70#endif
71}
72
73void TAUupdate(int cpu)
74{
75 unsigned thrm;
76
77#ifdef DEBUG
78 printk("TAUupdate ");
79#endif
80
81 /* if both thresholds are crossed, the step_sizes cancel out
82 * and the window winds up getting expanded twice. */
83 if((thrm = mfspr(SPRN_THRM1)) & THRM1_TIV){ /* is valid? */
84 if(thrm & THRM1_TIN){ /* crossed low threshold */
85 if (tau[cpu].low >= step_size){
86 tau[cpu].low -= step_size;
87 tau[cpu].high -= (step_size - window_expand);
88 }
89 tau[cpu].grew = 1;
90#ifdef DEBUG
91 printk("low threshold crossed ");
92#endif
93 }
94 }
95 if((thrm = mfspr(SPRN_THRM2)) & THRM1_TIV){ /* is valid? */
96 if(thrm & THRM1_TIN){ /* crossed high threshold */
97 if (tau[cpu].high <= 127-step_size){
98 tau[cpu].low += (step_size - window_expand);
99 tau[cpu].high += step_size;
100 }
101 tau[cpu].grew = 1;
102#ifdef DEBUG
103 printk("high threshold crossed ");
104#endif
105 }
106 }
107
108#ifdef DEBUG
109 printk("grew = %d\n", tau[cpu].grew);
110#endif
111
112#ifndef CONFIG_TAU_INT /* tau_timeout will do this if not using interrupts */
113 set_thresholds(cpu);
114#endif
115
116}
117
118#ifdef CONFIG_TAU_INT
119/*
120 * TAU interrupts - called when we have a thermal assist unit interrupt
121 * with interrupts disabled
122 */
123
124void TAUException(struct pt_regs * regs)
125{
126 int cpu = smp_processor_id();
127
128 irq_enter();
129 tau[cpu].interrupts++;
130
131 TAUupdate(cpu);
132
133 irq_exit();
134}
135#endif /* CONFIG_TAU_INT */
136
137static void tau_timeout(void * info)
138{
139 int cpu;
140 unsigned long flags;
141 int size;
142 int shrink;
143
144 /* disabling interrupts *should* be okay */
145 local_irq_save(flags);
146 cpu = smp_processor_id();
147
148#ifndef CONFIG_TAU_INT
149 TAUupdate(cpu);
150#endif
151
152 size = tau[cpu].high - tau[cpu].low;
153 if (size > min_window && ! tau[cpu].grew) {
154 /* do an exponential shrink of half the amount currently over size */
155 shrink = (2 + size - min_window) / 4;
156 if (shrink) {
157 tau[cpu].low += shrink;
158 tau[cpu].high -= shrink;
159 } else { /* size must have been min_window + 1 */
160 tau[cpu].low += 1;
161#if 1 /* debug */
162 if ((tau[cpu].high - tau[cpu].low) != min_window){
163 printk(KERN_ERR "temp.c: line %d, logic error\n", __LINE__);
164 }
165#endif
166 }
167 }
168
169 tau[cpu].grew = 0;
170
171 set_thresholds(cpu);
172
173 /*
174 * Do the enable every time, since otherwise a bunch of (relatively)
175 * complex sleep code needs to be added. One mtspr every time
176 * tau_timeout is called is probably not a big deal.
177 *
178 * Enable thermal sensor and set up sample interval timer
179 * need 20 us to do the compare.. until a nice 'cpu_speed' function
180 * call is implemented, just assume a 500 mhz clock. It doesn't really
181 * matter if we take too long for a compare since it's all interrupt
182 * driven anyway.
183 *
184 * use a extra long time.. (60 us @ 500 mhz)
185 */
186 mtspr(SPRN_THRM3, THRM3_SITV(500*60) | THRM3_E);
187
188 local_irq_restore(flags);
189}
190
191static void tau_timeout_smp(unsigned long unused)
192{
193
194 /* schedule ourselves to be run again */
195 mod_timer(&tau_timer, jiffies + shrink_timer) ;
196 on_each_cpu(tau_timeout, NULL, 1, 0);
197}
198
199/*
200 * setup the TAU
201 *
202 * Set things up to use THRM1 as a temperature lower bound, and THRM2 as an upper bound.
203 * Start off at zero
204 */
205
206int tau_initialized = 0;
207
208void __init TAU_init_smp(void * info)
209{
210 unsigned long cpu = smp_processor_id();
211
212 /* set these to a reasonable value and let the timer shrink the
213 * window */
214 tau[cpu].low = 5;
215 tau[cpu].high = 120;
216
217 set_thresholds(cpu);
218}
219
220int __init TAU_init(void)
221{
222 /* We assume in SMP that if one CPU has TAU support, they
223 * all have it --BenH
224 */
225 if (!cpu_has_feature(CPU_FTR_TAU)) {
226 printk("Thermal assist unit not available\n");
227 tau_initialized = 0;
228 return 1;
229 }
230
231
232 /* first, set up the window shrinking timer */
233 init_timer(&tau_timer);
234 tau_timer.function = tau_timeout_smp;
235 tau_timer.expires = jiffies + shrink_timer;
236 add_timer(&tau_timer);
237
238 on_each_cpu(TAU_init_smp, NULL, 1, 0);
239
240 printk("Thermal assist unit ");
241#ifdef CONFIG_TAU_INT
242 printk("using interrupts, ");
243#else
244 printk("using timers, ");
245#endif
246 printk("shrink_timer: %d jiffies\n", shrink_timer);
247 tau_initialized = 1;
248
249 return 0;
250}
251
252__initcall(TAU_init);
253
254/*
255 * return current temp
256 */
257
258u32 cpu_temp_both(unsigned long cpu)
259{
260 return ((tau[cpu].high << 16) | tau[cpu].low);
261}
262
263int cpu_temp(unsigned long cpu)
264{
265 return ((tau[cpu].high + tau[cpu].low) / 2);
266}
267
268int tau_interrupts(unsigned long cpu)
269{
270 return (tau[cpu].interrupts);
271}
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 9763faab6739..4cbde211eb69 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -97,7 +97,6 @@ static DEFINE_SPINLOCK(die_lock);
97int die(const char *str, struct pt_regs *regs, long err) 97int die(const char *str, struct pt_regs *regs, long err)
98{ 98{
99 static int die_counter, crash_dump_start = 0; 99 static int die_counter, crash_dump_start = 0;
100 int nl = 0;
101 100
102 if (debugger(regs)) 101 if (debugger(regs))
103 return 1; 102 return 1;
@@ -106,7 +105,7 @@ int die(const char *str, struct pt_regs *regs, long err)
106 spin_lock_irq(&die_lock); 105 spin_lock_irq(&die_lock);
107 bust_spinlocks(1); 106 bust_spinlocks(1);
108#ifdef CONFIG_PMAC_BACKLIGHT 107#ifdef CONFIG_PMAC_BACKLIGHT
109 if (_machine == _MACH_Pmac) { 108 if (machine_is(powermac)) {
110 set_backlight_enable(1); 109 set_backlight_enable(1);
111 set_backlight_level(BACKLIGHT_MAX); 110 set_backlight_level(BACKLIGHT_MAX);
112 } 111 }
@@ -114,46 +113,18 @@ int die(const char *str, struct pt_regs *regs, long err)
114 printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter); 113 printk("Oops: %s, sig: %ld [#%d]\n", str, err, ++die_counter);
115#ifdef CONFIG_PREEMPT 114#ifdef CONFIG_PREEMPT
116 printk("PREEMPT "); 115 printk("PREEMPT ");
117 nl = 1;
118#endif 116#endif
119#ifdef CONFIG_SMP 117#ifdef CONFIG_SMP
120 printk("SMP NR_CPUS=%d ", NR_CPUS); 118 printk("SMP NR_CPUS=%d ", NR_CPUS);
121 nl = 1;
122#endif 119#endif
123#ifdef CONFIG_DEBUG_PAGEALLOC 120#ifdef CONFIG_DEBUG_PAGEALLOC
124 printk("DEBUG_PAGEALLOC "); 121 printk("DEBUG_PAGEALLOC ");
125 nl = 1;
126#endif 122#endif
127#ifdef CONFIG_NUMA 123#ifdef CONFIG_NUMA
128 printk("NUMA "); 124 printk("NUMA ");
129 nl = 1;
130#endif 125#endif
131#ifdef CONFIG_PPC64 126 printk("%s\n", ppc_md.name ? "" : ppc_md.name);
132 switch (_machine) { 127
133 case PLATFORM_PSERIES:
134 printk("PSERIES ");
135 nl = 1;
136 break;
137 case PLATFORM_PSERIES_LPAR:
138 printk("PSERIES LPAR ");
139 nl = 1;
140 break;
141 case PLATFORM_ISERIES_LPAR:
142 printk("ISERIES LPAR ");
143 nl = 1;
144 break;
145 case PLATFORM_POWERMAC:
146 printk("POWERMAC ");
147 nl = 1;
148 break;
149 case PLATFORM_CELL:
150 printk("CELL ");
151 nl = 1;
152 break;
153 }
154#endif
155 if (nl)
156 printk("\n");
157 print_modules(); 128 print_modules();
158 show_regs(regs); 129 show_regs(regs);
159 bust_spinlocks(0); 130 bust_spinlocks(0);
diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c
index ec8370368423..573afb68d69e 100644
--- a/arch/powerpc/kernel/vdso.c
+++ b/arch/powerpc/kernel/vdso.c
@@ -33,6 +33,7 @@
33#include <asm/machdep.h> 33#include <asm/machdep.h>
34#include <asm/cputable.h> 34#include <asm/cputable.h>
35#include <asm/sections.h> 35#include <asm/sections.h>
36#include <asm/firmware.h>
36#include <asm/vdso.h> 37#include <asm/vdso.h>
37#include <asm/vdso_datapage.h> 38#include <asm/vdso_datapage.h>
38 39
@@ -667,7 +668,13 @@ void __init vdso_init(void)
667 vdso_data->version.major = SYSTEMCFG_MAJOR; 668 vdso_data->version.major = SYSTEMCFG_MAJOR;
668 vdso_data->version.minor = SYSTEMCFG_MINOR; 669 vdso_data->version.minor = SYSTEMCFG_MINOR;
669 vdso_data->processor = mfspr(SPRN_PVR); 670 vdso_data->processor = mfspr(SPRN_PVR);
670 vdso_data->platform = _machine; 671 /*
672 * Fake the old platform number for pSeries and iSeries and add
673 * in LPAR bit if necessary
674 */
675 vdso_data->platform = machine_is(iseries) ? 0x200 : 0x100;
676 if (firmware_has_feature(FW_FEATURE_LPAR))
677 vdso_data->platform |= 1;
671 vdso_data->physicalMemorySize = lmb_phys_mem_size(); 678 vdso_data->physicalMemorySize = lmb_phys_mem_size();
672 vdso_data->dcache_size = ppc64_caches.dsize; 679 vdso_data->dcache_size = ppc64_caches.dsize;
673 vdso_data->dcache_line_size = ppc64_caches.dline_size; 680 vdso_data->dcache_line_size = ppc64_caches.dline_size;
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S
index 7fa7b15fd8e6..fe79c2584cb0 100644
--- a/arch/powerpc/kernel/vmlinux.lds.S
+++ b/arch/powerpc/kernel/vmlinux.lds.S
@@ -1,9 +1,11 @@
1#include <linux/config.h> 1#include <linux/config.h>
2#ifdef CONFIG_PPC64 2#ifdef CONFIG_PPC64
3#include <asm/page.h> 3#include <asm/page.h>
4#define PROVIDE32(x) PROVIDE(__unused__##x)
4#else 5#else
5#define PAGE_SIZE 4096 6#define PAGE_SIZE 4096
6#define KERNELBASE CONFIG_KERNEL_START 7#define KERNELBASE CONFIG_KERNEL_START
8#define PROVIDE32(x) PROVIDE(x)
7#endif 9#endif
8#include <asm-generic/vmlinux.lds.h> 10#include <asm-generic/vmlinux.lds.h>
9 11
@@ -18,43 +20,42 @@ jiffies = jiffies_64 + 4;
18#endif 20#endif
19SECTIONS 21SECTIONS
20{ 22{
21 /* Sections to be discarded. */ 23 /* Sections to be discarded. */
22 /DISCARD/ : { 24 /DISCARD/ : {
23 *(.exitcall.exit) 25 *(.exitcall.exit)
24 *(.exit.data) 26 *(.exit.data)
25 } 27 }
26
27 . = KERNELBASE;
28
29 /* Read-only sections, merged into text segment: */
30 .text : {
31 *(.text .text.*)
32 SCHED_TEXT
33 LOCK_TEXT
34 KPROBES_TEXT
35 *(.fixup)
36#ifdef CONFIG_PPC32
37 *(.got1)
38 __got2_start = .;
39 *(.got2)
40 __got2_end = .;
41#else
42 . = ALIGN(PAGE_SIZE);
43 _etext = .;
44#endif
45 }
46#ifdef CONFIG_PPC32
47 _etext = .;
48 PROVIDE (etext = .);
49 28
50 RODATA 29 . = KERNELBASE;
51 .fini : { *(.fini) } =0
52 .ctors : { *(.ctors) }
53 .dtors : { *(.dtors) }
54 30
55 .fixup : { *(.fixup) } 31/*
56#endif 32 * Text, read only data and other permanent read-only sections
33 */
34
35 /* Text and gots */
36 .text : {
37 *(.text .text.*)
38 SCHED_TEXT
39 LOCK_TEXT
40 KPROBES_TEXT
41 *(.fixup)
57 42
43#ifdef CONFIG_PPC32
44 *(.got1)
45 __got2_start = .;
46 *(.got2)
47 __got2_end = .;
48#endif /* CONFIG_PPC32 */
49
50 . = ALIGN(PAGE_SIZE);
51 _etext = .;
52 PROVIDE32 (etext = .);
53 }
54
55 /* Read-only data */
56 RODATA
57
58 /* Exception & bug tables */
58 __ex_table : { 59 __ex_table : {
59 __start___ex_table = .; 60 __start___ex_table = .;
60 *(__ex_table) 61 *(__ex_table)
@@ -67,192 +68,172 @@ SECTIONS
67 __stop___bug_table = .; 68 __stop___bug_table = .;
68 } 69 }
69 70
70#ifdef CONFIG_PPC64 71/*
72 * Init sections discarded at runtime
73 */
74 . = ALIGN(PAGE_SIZE);
75 __init_begin = .;
76
77 .init.text : {
78 _sinittext = .;
79 *(.init.text)
80 _einittext = .;
81 }
82
83 /* .exit.text is discarded at runtime, not link time,
84 * to deal with references from __bug_table
85 */
86 .exit.text : { *(.exit.text) }
87
88 .init.data : {
89 *(.init.data);
90 __vtop_table_begin = .;
91 *(.vtop_fixup);
92 __vtop_table_end = .;
93 __ptov_table_begin = .;
94 *(.ptov_fixup);
95 __ptov_table_end = .;
96 }
97
98 . = ALIGN(16);
99 .init.setup : {
100 __setup_start = .;
101 *(.init.setup)
102 __setup_end = .;
103 }
104
105 .initcall.init : {
106 __initcall_start = .;
107 *(.initcall1.init)
108 *(.initcall2.init)
109 *(.initcall3.init)
110 *(.initcall4.init)
111 *(.initcall5.init)
112 *(.initcall6.init)
113 *(.initcall7.init)
114 __initcall_end = .;
115 }
116
117 .con_initcall.init : {
118 __con_initcall_start = .;
119 *(.con_initcall.init)
120 __con_initcall_end = .;
121 }
122
123 SECURITY_INIT
124
125 . = ALIGN(8);
71 __ftr_fixup : { 126 __ftr_fixup : {
72 __start___ftr_fixup = .; 127 __start___ftr_fixup = .;
73 *(__ftr_fixup) 128 *(__ftr_fixup)
74 __stop___ftr_fixup = .; 129 __stop___ftr_fixup = .;
75 } 130 }
76 131
77 RODATA 132 . = ALIGN(PAGE_SIZE);
78#endif 133 .init.ramfs : {
134 __initramfs_start = .;
135 *(.init.ramfs)
136 __initramfs_end = .;
137 }
79 138
80#ifdef CONFIG_PPC32 139#ifdef CONFIG_PPC32
81 /* Read-write section, merged into data segment: */ 140 . = ALIGN(32);
82 . = ALIGN(PAGE_SIZE); 141#else
83 _sdata = .; 142 . = ALIGN(128);
84 .data :
85 {
86 *(.data)
87 *(.data1)
88 *(.sdata)
89 *(.sdata2)
90 *(.got.plt) *(.got)
91 *(.dynamic)
92 CONSTRUCTORS
93 }
94
95 . = ALIGN(PAGE_SIZE);
96 __nosave_begin = .;
97 .data_nosave : { *(.data.nosave) }
98 . = ALIGN(PAGE_SIZE);
99 __nosave_end = .;
100
101 . = ALIGN(32);
102 .data.cacheline_aligned : { *(.data.cacheline_aligned) }
103
104 _edata = .;
105 PROVIDE (edata = .);
106
107 . = ALIGN(8192);
108 .data.init_task : { *(.data.init_task) }
109#endif 143#endif
144 .data.percpu : {
145 __per_cpu_start = .;
146 *(.data.percpu)
147 __per_cpu_end = .;
148 }
110 149
111 /* will be freed after init */ 150 . = ALIGN(8);
112 . = ALIGN(PAGE_SIZE); 151 .machine.desc : {
113 __init_begin = .; 152 __machine_desc_start = . ;
114 .init.text : { 153 *(.machine.desc)
115 _sinittext = .; 154 __machine_desc_end = . ;
116 *(.init.text) 155 }
117 _einittext = .; 156
118 } 157 /* freed after init ends here */
119#ifdef CONFIG_PPC32 158 . = ALIGN(PAGE_SIZE);
120 /* .exit.text is discarded at runtime, not link time, 159 __init_end = .;
121 to deal with references from __bug_table */ 160
122 .exit.text : { *(.exit.text) } 161/*
123#endif 162 * And now the various read/write data
124 .init.data : { 163 */
125 *(.init.data); 164
126 __vtop_table_begin = .; 165 . = ALIGN(PAGE_SIZE);
127 *(.vtop_fixup); 166 _sdata = .;
128 __vtop_table_end = .;
129 __ptov_table_begin = .;
130 *(.ptov_fixup);
131 __ptov_table_end = .;
132 }
133
134 . = ALIGN(16);
135 .init.setup : {
136 __setup_start = .;
137 *(.init.setup)
138 __setup_end = .;
139 }
140
141 .initcall.init : {
142 __initcall_start = .;
143 *(.initcall1.init)
144 *(.initcall2.init)
145 *(.initcall3.init)
146 *(.initcall4.init)
147 *(.initcall5.init)
148 *(.initcall6.init)
149 *(.initcall7.init)
150 __initcall_end = .;
151 }
152
153 .con_initcall.init : {
154 __con_initcall_start = .;
155 *(.con_initcall.init)
156 __con_initcall_end = .;
157 }
158
159 SECURITY_INIT
160 167
161#ifdef CONFIG_PPC32 168#ifdef CONFIG_PPC32
162 __start___ftr_fixup = .; 169 .data :
163 __ftr_fixup : { *(__ftr_fixup) } 170 {
164 __stop___ftr_fixup = .; 171 *(.data)
172 *(.sdata)
173 *(.got.plt) *(.got)
174 }
165#else 175#else
166 . = ALIGN(PAGE_SIZE); 176 .data : {
167 .init.ramfs : { 177 *(.data .data.rel* .toc1)
168 __initramfs_start = .; 178 *(.branch_lt)
169 *(.init.ramfs) 179 }
170 __initramfs_end = .;
171 }
172#endif
173 180
174#ifdef CONFIG_PPC32 181 .opd : {
175 . = ALIGN(32); 182 *(.opd)
183 }
184
185 .got : {
186 __toc_start = .;
187 *(.got)
188 *(.toc)
189 }
176#endif 190#endif
177 .data.percpu : {
178 __per_cpu_start = .;
179 *(.data.percpu)
180 __per_cpu_end = .;
181 }
182 191
183 . = ALIGN(PAGE_SIZE); 192 . = ALIGN(PAGE_SIZE);
184#ifdef CONFIG_PPC64 193 _edata = .;
185 . = ALIGN(16384); 194 PROVIDE32 (edata = .);
186 __init_end = .; 195
187 /* freed after init ends here */ 196 /* The initial task and kernel stack */
188 197#ifdef CONFIG_PPC32
189 /* Read/write sections */ 198 . = ALIGN(8192);
190 . = ALIGN(PAGE_SIZE);
191 . = ALIGN(16384);
192 _sdata = .;
193 /* The initial task and kernel stack */
194 .data.init_task : {
195 *(.data.init_task)
196 }
197
198 . = ALIGN(PAGE_SIZE);
199 .data.page_aligned : {
200 *(.data.page_aligned)
201 }
202
203 .data.cacheline_aligned : {
204 *(.data.cacheline_aligned)
205 }
206
207 .data : {
208 *(.data .data.rel* .toc1)
209 *(.branch_lt)
210 }
211
212 .opd : {
213 *(.opd)
214 }
215
216 .got : {
217 __toc_start = .;
218 *(.got)
219 *(.toc)
220 . = ALIGN(PAGE_SIZE);
221 _edata = .;
222 }
223
224 . = ALIGN(PAGE_SIZE);
225#else 199#else
226 __initramfs_start = .; 200 . = ALIGN(16384);
227 .init.ramfs : { 201#endif
228 *(.init.ramfs) 202 .data.init_task : {
229 } 203 *(.data.init_task)
230 __initramfs_end = .; 204 }
231 205
232 . = ALIGN(4096); 206 . = ALIGN(PAGE_SIZE);
233 __init_end = .; 207 .data.page_aligned : {
208 *(.data.page_aligned)
209 }
234 210
235 . = ALIGN(4096); 211 .data.cacheline_aligned : {
236 _sextratext = .; 212 *(.data.cacheline_aligned)
237 _eextratext = .; 213 }
238 214
239 __bss_start = .; 215 . = ALIGN(PAGE_SIZE);
240#endif 216 __data_nosave : {
217 __nosave_begin = .;
218 *(.data.nosave)
219 . = ALIGN(PAGE_SIZE);
220 __nosave_end = .;
221 }
241 222
242 .bss : { 223/*
243 __bss_start = .; 224 * And finally the bss
244 *(.sbss) *(.scommon) 225 */
245 *(.dynbss) 226
246 *(.bss) 227 .bss : {
247 *(COMMON) 228 __bss_start = .;
248 __bss_stop = .; 229 *(.sbss) *(.scommon)
249 } 230 *(.dynbss)
231 *(.bss)
232 *(COMMON)
233 __bss_stop = .;
234 }
250 235
251#ifdef CONFIG_PPC64 236 . = ALIGN(PAGE_SIZE);
252 . = ALIGN(PAGE_SIZE); 237 _end = . ;
253#endif 238 PROVIDE32 (end = .);
254 _end = . ;
255#ifdef CONFIG_PPC32
256 PROVIDE (end = .);
257#endif
258} 239}
diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c
index 666c2aa55016..c251d9936612 100644
--- a/arch/powerpc/lib/sstep.c
+++ b/arch/powerpc/lib/sstep.c
@@ -18,7 +18,7 @@ extern char system_call_common[];
18 18
19#ifdef CONFIG_PPC64 19#ifdef CONFIG_PPC64
20/* Bits in SRR1 that are copied from MSR */ 20/* Bits in SRR1 that are copied from MSR */
21#define MSR_MASK 0xffffffff87c0ffff 21#define MSR_MASK 0xffffffff87c0ffffUL
22#else 22#else
23#define MSR_MASK 0x87c0ffff 23#define MSR_MASK 0x87c0ffff
24#endif 24#endif
diff --git a/arch/powerpc/math-emu/Makefile b/arch/powerpc/math-emu/Makefile
new file mode 100644
index 000000000000..754143e8936b
--- /dev/null
+++ b/arch/powerpc/math-emu/Makefile
@@ -0,0 +1,13 @@
1
2obj-y := math.o fmr.o lfd.o stfd.o
3
4obj-$(CONFIG_MATH_EMULATION) += fabs.o fadd.o fadds.o fcmpo.o fcmpu.o \
5 fctiw.o fctiwz.o fdiv.o fdivs.o \
6 fmadd.o fmadds.o fmsub.o fmsubs.o \
7 fmul.o fmuls.o fnabs.o fneg.o types.o \
8 fnmadd.o fnmadds.o fnmsub.o fnmsubs.o \
9 fres.o frsp.o frsqrte.o fsel.o lfs.o \
10 fsqrt.o fsqrts.o fsub.o fsubs.o \
11 mcrfs.o mffs.o mtfsb0.o mtfsb1.o \
12 mtfsf.o mtfsfi.o stfiwx.o stfs.o \
13 udivmodti4.o
diff --git a/arch/powerpc/math-emu/double.h b/arch/powerpc/math-emu/double.h
new file mode 100644
index 000000000000..ffba8b67f059
--- /dev/null
+++ b/arch/powerpc/math-emu/double.h
@@ -0,0 +1,129 @@
1/*
2 * Definitions for IEEE Double Precision
3 */
4
5#if _FP_W_TYPE_SIZE < 32
6#error "Here's a nickel kid. Go buy yourself a real computer."
7#endif
8
9#if _FP_W_TYPE_SIZE < 64
10#define _FP_FRACTBITS_D (2 * _FP_W_TYPE_SIZE)
11#else
12#define _FP_FRACTBITS_D _FP_W_TYPE_SIZE
13#endif
14
15#define _FP_FRACBITS_D 53
16#define _FP_FRACXBITS_D (_FP_FRACTBITS_D - _FP_FRACBITS_D)
17#define _FP_WFRACBITS_D (_FP_WORKBITS + _FP_FRACBITS_D)
18#define _FP_WFRACXBITS_D (_FP_FRACTBITS_D - _FP_WFRACBITS_D)
19#define _FP_EXPBITS_D 11
20#define _FP_EXPBIAS_D 1023
21#define _FP_EXPMAX_D 2047
22
23#define _FP_QNANBIT_D \
24 ((_FP_W_TYPE)1 << ((_FP_FRACBITS_D-2) % _FP_W_TYPE_SIZE))
25#define _FP_IMPLBIT_D \
26 ((_FP_W_TYPE)1 << ((_FP_FRACBITS_D-1) % _FP_W_TYPE_SIZE))
27#define _FP_OVERFLOW_D \
28 ((_FP_W_TYPE)1 << (_FP_WFRACBITS_D % _FP_W_TYPE_SIZE))
29
30#if _FP_W_TYPE_SIZE < 64
31
32union _FP_UNION_D
33{
34 double flt;
35 struct {
36#if __BYTE_ORDER == __BIG_ENDIAN
37 unsigned sign : 1;
38 unsigned exp : _FP_EXPBITS_D;
39 unsigned frac1 : _FP_FRACBITS_D - (_FP_IMPLBIT_D != 0) - _FP_W_TYPE_SIZE;
40 unsigned frac0 : _FP_W_TYPE_SIZE;
41#else
42 unsigned frac0 : _FP_W_TYPE_SIZE;
43 unsigned frac1 : _FP_FRACBITS_D - (_FP_IMPLBIT_D != 0) - _FP_W_TYPE_SIZE;
44 unsigned exp : _FP_EXPBITS_D;
45 unsigned sign : 1;
46#endif
47 } bits __attribute__((packed));
48};
49
50#define FP_DECL_D(X) _FP_DECL(2,X)
51#define FP_UNPACK_RAW_D(X,val) _FP_UNPACK_RAW_2(D,X,val)
52#define FP_PACK_RAW_D(val,X) _FP_PACK_RAW_2(D,val,X)
53
54#define FP_UNPACK_D(X,val) \
55 do { \
56 _FP_UNPACK_RAW_2(D,X,val); \
57 _FP_UNPACK_CANONICAL(D,2,X); \
58 } while (0)
59
60#define FP_PACK_D(val,X) \
61 do { \
62 _FP_PACK_CANONICAL(D,2,X); \
63 _FP_PACK_RAW_2(D,val,X); \
64 } while (0)
65
66#define FP_NEG_D(R,X) _FP_NEG(D,2,R,X)
67#define FP_ADD_D(R,X,Y) _FP_ADD(D,2,R,X,Y)
68#define FP_SUB_D(R,X,Y) _FP_SUB(D,2,R,X,Y)
69#define FP_MUL_D(R,X,Y) _FP_MUL(D,2,R,X,Y)
70#define FP_DIV_D(R,X,Y) _FP_DIV(D,2,R,X,Y)
71#define FP_SQRT_D(R,X) _FP_SQRT(D,2,R,X)
72
73#define FP_CMP_D(r,X,Y,un) _FP_CMP(D,2,r,X,Y,un)
74#define FP_CMP_EQ_D(r,X,Y) _FP_CMP_EQ(D,2,r,X,Y)
75
76#define FP_TO_INT_D(r,X,rsz,rsg) _FP_TO_INT(D,2,r,X,rsz,rsg)
77#define FP_FROM_INT_D(X,r,rs,rt) _FP_FROM_INT(D,2,X,r,rs,rt)
78
79#else
80
81union _FP_UNION_D
82{
83 double flt;
84 struct {
85#if __BYTE_ORDER == __BIG_ENDIAN
86 unsigned sign : 1;
87 unsigned exp : _FP_EXPBITS_D;
88 unsigned long frac : _FP_FRACBITS_D - (_FP_IMPLBIT_D != 0);
89#else
90 unsigned long frac : _FP_FRACBITS_D - (_FP_IMPLBIT_D != 0);
91 unsigned exp : _FP_EXPBITS_D;
92 unsigned sign : 1;
93#endif
94 } bits __attribute__((packed));
95};
96
97#define FP_DECL_D(X) _FP_DECL(1,X)
98#define FP_UNPACK_RAW_D(X,val) _FP_UNPACK_RAW_1(D,X,val)
99#define FP_PACK_RAW_D(val,X) _FP_PACK_RAW_1(D,val,X)
100
101#define FP_UNPACK_D(X,val) \
102 do { \
103 _FP_UNPACK_RAW_1(D,X,val); \
104 _FP_UNPACK_CANONICAL(D,1,X); \
105 } while (0)
106
107#define FP_PACK_D(val,X) \
108 do { \
109 _FP_PACK_CANONICAL(D,1,X); \
110 _FP_PACK_RAW_1(D,val,X); \
111 } while (0)
112
113#define FP_NEG_D(R,X) _FP_NEG(D,1,R,X)
114#define FP_ADD_D(R,X,Y) _FP_ADD(D,1,R,X,Y)
115#define FP_SUB_D(R,X,Y) _FP_SUB(D,1,R,X,Y)
116#define FP_MUL_D(R,X,Y) _FP_MUL(D,1,R,X,Y)
117#define FP_DIV_D(R,X,Y) _FP_DIV(D,1,R,X,Y)
118#define FP_SQRT_D(R,X) _FP_SQRT(D,1,R,X)
119
120/* The implementation of _FP_MUL_D and _FP_DIV_D should be chosen by
121 the target machine. */
122
123#define FP_CMP_D(r,X,Y,un) _FP_CMP(D,1,r,X,Y,un)
124#define FP_CMP_EQ_D(r,X,Y) _FP_CMP_EQ(D,1,r,X,Y)
125
126#define FP_TO_INT_D(r,X,rsz,rsg) _FP_TO_INT(D,1,r,X,rsz,rsg)
127#define FP_FROM_INT_D(X,r,rs,rt) _FP_FROM_INT(D,1,X,r,rs,rt)
128
129#endif /* W_TYPE_SIZE < 64 */
diff --git a/arch/powerpc/math-emu/fabs.c b/arch/powerpc/math-emu/fabs.c
new file mode 100644
index 000000000000..41f0617f3d3a
--- /dev/null
+++ b/arch/powerpc/math-emu/fabs.c
@@ -0,0 +1,18 @@
1#include <linux/types.h>
2#include <linux/errno.h>
3#include <asm/uaccess.h>
4
5int
6fabs(u32 *frD, u32 *frB)
7{
8 frD[0] = frB[0] & 0x7fffffff;
9 frD[1] = frB[1];
10
11#ifdef DEBUG
12 printk("%s: D %p, B %p: ", __FUNCTION__, frD, frB);
13 dump_double(frD);
14 printk("\n");
15#endif
16
17 return 0;
18}
diff --git a/arch/powerpc/math-emu/fadd.c b/arch/powerpc/math-emu/fadd.c
new file mode 100644
index 000000000000..fc8836488b64
--- /dev/null
+++ b/arch/powerpc/math-emu/fadd.c
@@ -0,0 +1,38 @@
1#include <linux/types.h>
2#include <linux/errno.h>
3#include <asm/uaccess.h>
4
5#include "soft-fp.h"
6#include "double.h"
7
8int
9fadd(void *frD, void *frA, void *frB)
10{
11 FP_DECL_D(A);
12 FP_DECL_D(B);
13 FP_DECL_D(R);
14 int ret = 0;
15
16#ifdef DEBUG
17 printk("%s: %p %p %p\n", __FUNCTION__, frD, frA, frB);
18#endif
19
20 __FP_UNPACK_D(A, frA);
21 __FP_UNPACK_D(B, frB);
22
23#ifdef DEBUG
24 printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
25 printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c);
26#endif
27
28 if (A_s != B_s && A_c == FP_CLS_INF && B_c == FP_CLS_INF)
29 ret |= EFLAG_VXISI;
30
31 FP_ADD_D(R, A, B);
32
33#ifdef DEBUG
34 printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
35#endif
36
37 return (ret | __FP_PACK_D(frD, R));
38}
diff --git a/arch/powerpc/math-emu/fadds.c b/arch/powerpc/math-emu/fadds.c
new file mode 100644
index 000000000000..93025b6c8f3c
--- /dev/null
+++ b/arch/powerpc/math-emu/fadds.c
@@ -0,0 +1,39 @@
1#include <linux/types.h>
2#include <linux/errno.h>
3#include <asm/uaccess.h>
4
5#include "soft-fp.h"
6#include "double.h"
7#include "single.h"
8
9int
10fadds(void *frD, void *frA, void *frB)
11{
12 FP_DECL_D(A);
13 FP_DECL_D(B);
14 FP_DECL_D(R);
15 int ret = 0;
16
17#ifdef DEBUG
18 printk("%s: %p %p %p\n", __FUNCTION__, frD, frA, frB);
19#endif
20
21 __FP_UNPACK_D(A, frA);
22 __FP_UNPACK_D(B, frB);
23
24#ifdef DEBUG
25 printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
26 printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c);
27#endif
28
29 if (A_s != B_s && A_c == FP_CLS_INF && B_c == FP_CLS_INF)
30 ret |= EFLAG_VXISI;
31
32 FP_ADD_D(R, A, B);
33
34#ifdef DEBUG
35 printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
36#endif
37
38 return (ret | __FP_PACK_DS(frD, R));
39}
diff --git a/arch/powerpc/math-emu/fcmpo.c b/arch/powerpc/math-emu/fcmpo.c
new file mode 100644
index 000000000000..4efac394b4cb
--- /dev/null
+++ b/arch/powerpc/math-emu/fcmpo.c
@@ -0,0 +1,46 @@
1#include <linux/types.h>
2#include <linux/errno.h>
3#include <asm/uaccess.h>
4
5#include "soft-fp.h"
6#include "double.h"
7
8int
9fcmpo(u32 *ccr, int crfD, void *frA, void *frB)
10{
11 FP_DECL_D(A);
12 FP_DECL_D(B);
13 int code[4] = { (1 << 3), (1 << 1), (1 << 2), (1 << 0) };
14 long cmp;
15 int ret = 0;
16
17#ifdef DEBUG
18 printk("%s: %p (%08x) %d %p %p\n", __FUNCTION__, ccr, *ccr, crfD, frA, frB);
19#endif
20
21 __FP_UNPACK_D(A, frA);
22 __FP_UNPACK_D(B, frB);
23
24#ifdef DEBUG
25 printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
26 printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c);
27#endif
28
29 if (A_c == FP_CLS_NAN || B_c == FP_CLS_NAN)
30 ret |= EFLAG_VXVC;
31
32 FP_CMP_D(cmp, A, B, 2);
33 cmp = code[(cmp + 1) & 3];
34
35 __FPU_FPSCR &= ~(0x1f000);
36 __FPU_FPSCR |= (cmp << 12);
37
38 *ccr &= ~(15 << ((7 - crfD) << 2));
39 *ccr |= (cmp << ((7 - crfD) << 2));
40
41#ifdef DEBUG
42 printk("CR: %08x\n", *ccr);
43#endif
44
45 return ret;
46}
diff --git a/arch/powerpc/math-emu/fcmpu.c b/arch/powerpc/math-emu/fcmpu.c
new file mode 100644
index 000000000000..b7e33176e618
--- /dev/null
+++ b/arch/powerpc/math-emu/fcmpu.c
@@ -0,0 +1,42 @@
1#include <linux/types.h>
2#include <linux/errno.h>
3#include <asm/uaccess.h>
4
5#include "soft-fp.h"
6#include "double.h"
7
8int
9fcmpu(u32 *ccr, int crfD, void *frA, void *frB)
10{
11 FP_DECL_D(A);
12 FP_DECL_D(B);
13 int code[4] = { (1 << 3), (1 << 1), (1 << 2), (1 << 0) };
14 long cmp;
15
16#ifdef DEBUG
17 printk("%s: %p (%08x) %d %p %p\n", __FUNCTION__, ccr, *ccr, crfD, frA, frB);
18#endif
19
20 __FP_UNPACK_D(A, frA);
21 __FP_UNPACK_D(B, frB);
22
23#ifdef DEBUG
24 printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
25 printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c);
26#endif
27
28 FP_CMP_D(cmp, A, B, 2);
29 cmp = code[(cmp + 1) & 3];
30
31 __FPU_FPSCR &= ~(0x1f000);
32 __FPU_FPSCR |= (cmp << 12);
33
34 *ccr &= ~(15 << ((7 - crfD) << 2));
35 *ccr |= (cmp << ((7 - crfD) << 2));
36
37#ifdef DEBUG
38 printk("CR: %08x\n", *ccr);
39#endif
40
41 return 0;
42}
diff --git a/arch/powerpc/math-emu/fctiw.c b/arch/powerpc/math-emu/fctiw.c
new file mode 100644
index 000000000000..3b3c98b840cf
--- /dev/null
+++ b/arch/powerpc/math-emu/fctiw.c
@@ -0,0 +1,25 @@
1#include <linux/types.h>
2#include <linux/errno.h>
3#include <asm/uaccess.h>
4
5#include "soft-fp.h"
6#include "double.h"
7
8int
9fctiw(u32 *frD, void *frB)
10{
11 FP_DECL_D(B);
12 unsigned int r;
13
14 __FP_UNPACK_D(B, frB);
15 FP_TO_INT_D(r, B, 32, 1);
16 frD[1] = r;
17
18#ifdef DEBUG
19 printk("%s: D %p, B %p: ", __FUNCTION__, frD, frB);
20 dump_double(frD);
21 printk("\n");
22#endif
23
24 return 0;
25}
diff --git a/arch/powerpc/math-emu/fctiwz.c b/arch/powerpc/math-emu/fctiwz.c
new file mode 100644
index 000000000000..7717eb6fcfb6
--- /dev/null
+++ b/arch/powerpc/math-emu/fctiwz.c
@@ -0,0 +1,32 @@
1#include <linux/types.h>
2#include <linux/errno.h>
3#include <asm/uaccess.h>
4
5#include "soft-fp.h"
6#include "double.h"
7
8int
9fctiwz(u32 *frD, void *frB)
10{
11 FP_DECL_D(B);
12 u32 fpscr;
13 unsigned int r;
14
15 fpscr = __FPU_FPSCR;
16 __FPU_FPSCR &= ~(3);
17 __FPU_FPSCR |= FP_RND_ZERO;
18
19 __FP_UNPACK_D(B, frB);
20 FP_TO_INT_D(r, B, 32, 1);
21 frD[1] = r;
22
23 __FPU_FPSCR = fpscr;
24
25#ifdef DEBUG
26 printk("%s: D %p, B %p: ", __FUNCTION__, frD, frB);
27 dump_double(frD);
28 printk("\n");
29#endif
30
31 return 0;
32}
diff --git a/arch/powerpc/math-emu/fdiv.c b/arch/powerpc/math-emu/fdiv.c
new file mode 100644
index 000000000000..f2fba825b2d0
--- /dev/null
+++ b/arch/powerpc/math-emu/fdiv.c
@@ -0,0 +1,53 @@
1#include <linux/types.h>
2#include <linux/errno.h>
3#include <asm/uaccess.h>
4
5#include "soft-fp.h"
6#include "double.h"
7
8int
9fdiv(void *frD, void *frA, void *frB)
10{
11 FP_DECL_D(A);
12 FP_DECL_D(B);
13 FP_DECL_D(R);
14 int ret = 0;
15
16#ifdef DEBUG
17 printk("%s: %p %p %p\n", __FUNCTION__, frD, frA, frB);
18#endif
19
20 __FP_UNPACK_D(A, frA);
21 __FP_UNPACK_D(B, frB);
22
23#ifdef DEBUG
24 printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
25 printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c);
26#endif
27
28 if (A_c == FP_CLS_ZERO && B_c == FP_CLS_ZERO) {
29 ret |= EFLAG_VXZDZ;
30#ifdef DEBUG
31 printk("%s: FPSCR_VXZDZ raised\n", __FUNCTION__);
32#endif
33 }
34 if (A_c == FP_CLS_INF && B_c == FP_CLS_INF) {
35 ret |= EFLAG_VXIDI;
36#ifdef DEBUG
37 printk("%s: FPSCR_VXIDI raised\n", __FUNCTION__);
38#endif
39 }
40
41 if (B_c == FP_CLS_ZERO && A_c != FP_CLS_ZERO) {
42 ret |= EFLAG_DIVZERO;
43 if (__FPU_TRAP_P(EFLAG_DIVZERO))
44 return ret;
45 }
46 FP_DIV_D(R, A, B);
47
48#ifdef DEBUG
49 printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
50#endif
51
52 return (ret | __FP_PACK_D(frD, R));
53}
diff --git a/arch/powerpc/math-emu/fdivs.c b/arch/powerpc/math-emu/fdivs.c
new file mode 100644
index 000000000000..b971196e3175
--- /dev/null
+++ b/arch/powerpc/math-emu/fdivs.c
@@ -0,0 +1,55 @@
1#include <linux/types.h>
2#include <linux/errno.h>
3#include <asm/uaccess.h>
4
5#include "soft-fp.h"
6#include "double.h"
7#include "single.h"
8
9int
10fdivs(void *frD, void *frA, void *frB)
11{
12 FP_DECL_D(A);
13 FP_DECL_D(B);
14 FP_DECL_D(R);
15 int ret = 0;
16
17#ifdef DEBUG
18 printk("%s: %p %p %p\n", __FUNCTION__, frD, frA, frB);
19#endif
20
21 __FP_UNPACK_D(A, frA);
22 __FP_UNPACK_D(B, frB);
23
24#ifdef DEBUG
25 printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
26 printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c);
27#endif
28
29 if (A_c == FP_CLS_ZERO && B_c == FP_CLS_ZERO) {
30 ret |= EFLAG_VXZDZ;
31#ifdef DEBUG
32 printk("%s: FPSCR_VXZDZ raised\n", __FUNCTION__);
33#endif
34 }
35 if (A_c == FP_CLS_INF && B_c == FP_CLS_INF) {
36 ret |= EFLAG_VXIDI;
37#ifdef DEBUG
38 printk("%s: FPSCR_VXIDI raised\n", __FUNCTION__);
39#endif
40 }
41
42 if (B_c == FP_CLS_ZERO && A_c != FP_CLS_ZERO) {
43 ret |= EFLAG_DIVZERO;
44 if (__FPU_TRAP_P(EFLAG_DIVZERO))
45 return ret;
46 }
47
48 FP_DIV_D(R, A, B);
49
50#ifdef DEBUG
51 printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
52#endif
53
54 return (ret | __FP_PACK_DS(frD, R));
55}
diff --git a/arch/powerpc/math-emu/fmadd.c b/arch/powerpc/math-emu/fmadd.c
new file mode 100644
index 000000000000..0a1dbce793e9
--- /dev/null
+++ b/arch/powerpc/math-emu/fmadd.c
@@ -0,0 +1,48 @@
1#include <linux/types.h>
2#include <linux/errno.h>
3#include <asm/uaccess.h>
4
5#include "soft-fp.h"
6#include "double.h"
7
8int
9fmadd(void *frD, void *frA, void *frB, void *frC)
10{
11 FP_DECL_D(R);
12 FP_DECL_D(A);
13 FP_DECL_D(B);
14 FP_DECL_D(C);
15 FP_DECL_D(T);
16 int ret = 0;
17
18#ifdef DEBUG
19 printk("%s: %p %p %p %p\n", __FUNCTION__, frD, frA, frB, frC);
20#endif
21
22 __FP_UNPACK_D(A, frA);
23 __FP_UNPACK_D(B, frB);
24 __FP_UNPACK_D(C, frC);
25
26#ifdef DEBUG
27 printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
28 printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c);
29 printk("C: %ld %lu %lu %ld (%ld)\n", C_s, C_f1, C_f0, C_e, C_c);
30#endif
31
32 if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) ||
33 (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF))
34 ret |= EFLAG_VXIMZ;
35
36 FP_MUL_D(T, A, C);
37
38 if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF)
39 ret |= EFLAG_VXISI;
40
41 FP_ADD_D(R, T, B);
42
43#ifdef DEBUG
44 printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
45#endif
46
47 return (ret | __FP_PACK_D(frD, R));
48}
diff --git a/arch/powerpc/math-emu/fmadds.c b/arch/powerpc/math-emu/fmadds.c
new file mode 100644
index 000000000000..0f70bba9445e
--- /dev/null
+++ b/arch/powerpc/math-emu/fmadds.c
@@ -0,0 +1,49 @@
1#include <linux/types.h>
2#include <linux/errno.h>
3#include <asm/uaccess.h>
4
5#include "soft-fp.h"
6#include "double.h"
7#include "single.h"
8
9int
10fmadds(void *frD, void *frA, void *frB, void *frC)
11{
12 FP_DECL_D(R);
13 FP_DECL_D(A);
14 FP_DECL_D(B);
15 FP_DECL_D(C);
16 FP_DECL_D(T);
17 int ret = 0;
18
19#ifdef DEBUG
20 printk("%s: %p %p %p %p\n", __FUNCTION__, frD, frA, frB, frC);
21#endif
22
23 __FP_UNPACK_D(A, frA);
24 __FP_UNPACK_D(B, frB);
25 __FP_UNPACK_D(C, frC);
26
27#ifdef DEBUG
28 printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
29 printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c);
30 printk("C: %ld %lu %lu %ld (%ld)\n", C_s, C_f1, C_f0, C_e, C_c);
31#endif
32
33 if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) ||
34 (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF))
35 ret |= EFLAG_VXIMZ;
36
37 FP_MUL_D(T, A, C);
38
39 if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF)
40 ret |= EFLAG_VXISI;
41
42 FP_ADD_D(R, T, B);
43
44#ifdef DEBUG
45 printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
46#endif
47
48 return (ret | __FP_PACK_DS(frD, R));
49}
diff --git a/arch/powerpc/math-emu/fmr.c b/arch/powerpc/math-emu/fmr.c
new file mode 100644
index 000000000000..28df700c0c7e
--- /dev/null
+++ b/arch/powerpc/math-emu/fmr.c
@@ -0,0 +1,18 @@
1#include <linux/types.h>
2#include <linux/errno.h>
3#include <asm/uaccess.h>
4
5int
6fmr(u32 *frD, u32 *frB)
7{
8 frD[0] = frB[0];
9 frD[1] = frB[1];
10
11#ifdef DEBUG
12 printk("%s: D %p, B %p: ", __FUNCTION__, frD, frB);
13 dump_double(frD);
14 printk("\n");
15#endif
16
17 return 0;
18}
diff --git a/arch/powerpc/math-emu/fmsub.c b/arch/powerpc/math-emu/fmsub.c
new file mode 100644
index 000000000000..203fd48a6fec
--- /dev/null
+++ b/arch/powerpc/math-emu/fmsub.c
@@ -0,0 +1,51 @@
1#include <linux/types.h>
2#include <linux/errno.h>
3#include <asm/uaccess.h>
4
5#include "soft-fp.h"
6#include "double.h"
7
8int
9fmsub(void *frD, void *frA, void *frB, void *frC)
10{
11 FP_DECL_D(R);
12 FP_DECL_D(A);
13 FP_DECL_D(B);
14 FP_DECL_D(C);
15 FP_DECL_D(T);
16 int ret = 0;
17
18#ifdef DEBUG
19 printk("%s: %p %p %p %p\n", __FUNCTION__, frD, frA, frB, frC);
20#endif
21
22 __FP_UNPACK_D(A, frA);
23 __FP_UNPACK_D(B, frB);
24 __FP_UNPACK_D(C, frC);
25
26#ifdef DEBUG
27 printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
28 printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c);
29 printk("C: %ld %lu %lu %ld (%ld)\n", C_s, C_f1, C_f0, C_e, C_c);
30#endif
31
32 if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) ||
33 (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF))
34 ret |= EFLAG_VXIMZ;
35
36 FP_MUL_D(T, A, C);
37
38 if (B_c != FP_CLS_NAN)
39 B_s ^= 1;
40
41 if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF)
42 ret |= EFLAG_VXISI;
43
44 FP_ADD_D(R, T, B);
45
46#ifdef DEBUG
47 printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
48#endif
49
50 return (ret | __FP_PACK_D(frD, R));
51}
diff --git a/arch/powerpc/math-emu/fmsubs.c b/arch/powerpc/math-emu/fmsubs.c
new file mode 100644
index 000000000000..8ce68624c189
--- /dev/null
+++ b/arch/powerpc/math-emu/fmsubs.c
@@ -0,0 +1,52 @@
1#include <linux/types.h>
2#include <linux/errno.h>
3#include <asm/uaccess.h>
4
5#include "soft-fp.h"
6#include "double.h"
7#include "single.h"
8
9int
10fmsubs(void *frD, void *frA, void *frB, void *frC)
11{
12 FP_DECL_D(R);
13 FP_DECL_D(A);
14 FP_DECL_D(B);
15 FP_DECL_D(C);
16 FP_DECL_D(T);
17 int ret = 0;
18
19#ifdef DEBUG
20 printk("%s: %p %p %p %p\n", __FUNCTION__, frD, frA, frB, frC);
21#endif
22
23 __FP_UNPACK_D(A, frA);
24 __FP_UNPACK_D(B, frB);
25 __FP_UNPACK_D(C, frC);
26
27#ifdef DEBUG
28 printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
29 printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c);
30 printk("C: %ld %lu %lu %ld (%ld)\n", C_s, C_f1, C_f0, C_e, C_c);
31#endif
32
33 if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) ||
34 (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF))
35 ret |= EFLAG_VXIMZ;
36
37 FP_MUL_D(T, A, C);
38
39 if (B_c != FP_CLS_NAN)
40 B_s ^= 1;
41
42 if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF)
43 ret |= EFLAG_VXISI;
44
45 FP_ADD_D(R, T, B);
46
47#ifdef DEBUG
48 printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
49#endif
50
51 return (ret | __FP_PACK_DS(frD, R));
52}
diff --git a/arch/powerpc/math-emu/fmul.c b/arch/powerpc/math-emu/fmul.c
new file mode 100644
index 000000000000..66c7e79aae2e
--- /dev/null
+++ b/arch/powerpc/math-emu/fmul.c
@@ -0,0 +1,42 @@
1#include <linux/types.h>
2#include <linux/errno.h>
3#include <asm/uaccess.h>
4
5#include "soft-fp.h"
6#include "double.h"
7
8int
9fmul(void *frD, void *frA, void *frB)
10{
11 FP_DECL_D(A);
12 FP_DECL_D(B);
13 FP_DECL_D(R);
14 int ret = 0;
15
16#ifdef DEBUG
17 printk("%s: %p %p %p\n", __FUNCTION__, frD, frA, frB);
18#endif
19
20 __FP_UNPACK_D(A, frA);
21 __FP_UNPACK_D(B, frB);
22
23#ifdef DEBUG
24 printk("A: %ld %lu %lu %ld (%ld) [%08lx.%08lx %lx]\n",
25 A_s, A_f1, A_f0, A_e, A_c, A_f1, A_f0, A_e + 1023);
26 printk("B: %ld %lu %lu %ld (%ld) [%08lx.%08lx %lx]\n",
27 B_s, B_f1, B_f0, B_e, B_c, B_f1, B_f0, B_e + 1023);
28#endif
29
30 if ((A_c == FP_CLS_INF && B_c == FP_CLS_ZERO) ||
31 (A_c == FP_CLS_ZERO && B_c == FP_CLS_INF))
32 ret |= EFLAG_VXIMZ;
33
34 FP_MUL_D(R, A, B);
35
36#ifdef DEBUG
37 printk("D: %ld %lu %lu %ld (%ld) [%08lx.%08lx %lx]\n",
38 R_s, R_f1, R_f0, R_e, R_c, R_f1, R_f0, R_e + 1023);
39#endif
40
41 return (ret | __FP_PACK_D(frD, R));
42}
diff --git a/arch/powerpc/math-emu/fmuls.c b/arch/powerpc/math-emu/fmuls.c
new file mode 100644
index 000000000000..26bc4278271c
--- /dev/null
+++ b/arch/powerpc/math-emu/fmuls.c
@@ -0,0 +1,43 @@
1#include <linux/types.h>
2#include <linux/errno.h>
3#include <asm/uaccess.h>
4
5#include "soft-fp.h"
6#include "double.h"
7#include "single.h"
8
9int
10fmuls(void *frD, void *frA, void *frB)
11{
12 FP_DECL_D(A);
13 FP_DECL_D(B);
14 FP_DECL_D(R);
15 int ret = 0;
16
17#ifdef DEBUG
18 printk("%s: %p %p %p\n", __FUNCTION__, frD, frA, frB);
19#endif
20
21 __FP_UNPACK_D(A, frA);
22 __FP_UNPACK_D(B, frB);
23
24#ifdef DEBUG
25 printk("A: %ld %lu %lu %ld (%ld) [%08lx.%08lx %lx]\n",
26 A_s, A_f1, A_f0, A_e, A_c, A_f1, A_f0, A_e + 1023);
27 printk("B: %ld %lu %lu %ld (%ld) [%08lx.%08lx %lx]\n",
28 B_s, B_f1, B_f0, B_e, B_c, B_f1, B_f0, B_e + 1023);
29#endif
30
31 if ((A_c == FP_CLS_INF && B_c == FP_CLS_ZERO) ||
32 (A_c == FP_CLS_ZERO && B_c == FP_CLS_INF))
33 ret |= EFLAG_VXIMZ;
34
35 FP_MUL_D(R, A, B);
36
37#ifdef DEBUG
38 printk("D: %ld %lu %lu %ld (%ld) [%08lx.%08lx %lx]\n",
39 R_s, R_f1, R_f0, R_e, R_c, R_f1, R_f0, R_e + 1023);
40#endif
41
42 return (ret | __FP_PACK_DS(frD, R));
43}
diff --git a/arch/powerpc/math-emu/fnabs.c b/arch/powerpc/math-emu/fnabs.c
new file mode 100644
index 000000000000..c6b913d179e0
--- /dev/null
+++ b/arch/powerpc/math-emu/fnabs.c
@@ -0,0 +1,18 @@
1#include <linux/types.h>
2#include <linux/errno.h>
3#include <asm/uaccess.h>
4
5int
6fnabs(u32 *frD, u32 *frB)
7{
8 frD[0] = frB[0] | 0x80000000;
9 frD[1] = frB[1];
10
11#ifdef DEBUG
12 printk("%s: D %p, B %p: ", __FUNCTION__, frD, frB);
13 dump_double(frD);
14 printk("\n");
15#endif
16
17 return 0;
18}
diff --git a/arch/powerpc/math-emu/fneg.c b/arch/powerpc/math-emu/fneg.c
new file mode 100644
index 000000000000..fe9a98deff69
--- /dev/null
+++ b/arch/powerpc/math-emu/fneg.c
@@ -0,0 +1,18 @@
1#include <linux/types.h>
2#include <linux/errno.h>
3#include <asm/uaccess.h>
4
5int
6fneg(u32 *frD, u32 *frB)
7{
8 frD[0] = frB[0] ^ 0x80000000;
9 frD[1] = frB[1];
10
11#ifdef DEBUG
12 printk("%s: D %p, B %p: ", __FUNCTION__, frD, frB);
13 dump_double(frD);
14 printk("\n");
15#endif
16
17 return 0;
18}
diff --git a/arch/powerpc/math-emu/fnmadd.c b/arch/powerpc/math-emu/fnmadd.c
new file mode 100644
index 000000000000..7f312276d920
--- /dev/null
+++ b/arch/powerpc/math-emu/fnmadd.c
@@ -0,0 +1,51 @@
1#include <linux/types.h>
2#include <linux/errno.h>
3#include <asm/uaccess.h>
4
5#include "soft-fp.h"
6#include "double.h"
7
8int
9fnmadd(void *frD, void *frA, void *frB, void *frC)
10{
11 FP_DECL_D(R);
12 FP_DECL_D(A);
13 FP_DECL_D(B);
14 FP_DECL_D(C);
15 FP_DECL_D(T);
16 int ret = 0;
17
18#ifdef DEBUG
19 printk("%s: %p %p %p %p\n", __FUNCTION__, frD, frA, frB, frC);
20#endif
21
22 __FP_UNPACK_D(A, frA);
23 __FP_UNPACK_D(B, frB);
24 __FP_UNPACK_D(C, frC);
25
26#ifdef DEBUG
27 printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
28 printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c);
29 printk("C: %ld %lu %lu %ld (%ld)\n", C_s, C_f1, C_f0, C_e, C_c);
30#endif
31
32 if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) ||
33 (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF))
34 ret |= EFLAG_VXIMZ;
35
36 FP_MUL_D(T, A, C);
37
38 if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF)
39 ret |= EFLAG_VXISI;
40
41 FP_ADD_D(R, T, B);
42
43 if (R_c != FP_CLS_NAN)
44 R_s ^= 1;
45
46#ifdef DEBUG
47 printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
48#endif
49
50 return (ret | __FP_PACK_D(frD, R));
51}
diff --git a/arch/powerpc/math-emu/fnmadds.c b/arch/powerpc/math-emu/fnmadds.c
new file mode 100644
index 000000000000..65454c9c70bc
--- /dev/null
+++ b/arch/powerpc/math-emu/fnmadds.c
@@ -0,0 +1,52 @@
1#include <linux/types.h>
2#include <linux/errno.h>
3#include <asm/uaccess.h>
4
5#include "soft-fp.h"
6#include "double.h"
7#include "single.h"
8
9int
10fnmadds(void *frD, void *frA, void *frB, void *frC)
11{
12 FP_DECL_D(R);
13 FP_DECL_D(A);
14 FP_DECL_D(B);
15 FP_DECL_D(C);
16 FP_DECL_D(T);
17 int ret = 0;
18
19#ifdef DEBUG
20 printk("%s: %p %p %p %p\n", __FUNCTION__, frD, frA, frB, frC);
21#endif
22
23 __FP_UNPACK_D(A, frA);
24 __FP_UNPACK_D(B, frB);
25 __FP_UNPACK_D(C, frC);
26
27#ifdef DEBUG
28 printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
29 printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c);
30 printk("C: %ld %lu %lu %ld (%ld)\n", C_s, C_f1, C_f0, C_e, C_c);
31#endif
32
33 if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) ||
34 (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF))
35 ret |= EFLAG_VXIMZ;
36
37 FP_MUL_D(T, A, C);
38
39 if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF)
40 ret |= EFLAG_VXISI;
41
42 FP_ADD_D(R, T, B);
43
44 if (R_c != FP_CLS_NAN)
45 R_s ^= 1;
46
47#ifdef DEBUG
48 printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
49#endif
50
51 return (ret | __FP_PACK_DS(frD, R));
52}
diff --git a/arch/powerpc/math-emu/fnmsub.c b/arch/powerpc/math-emu/fnmsub.c
new file mode 100644
index 000000000000..f1ca7482b5f0
--- /dev/null
+++ b/arch/powerpc/math-emu/fnmsub.c
@@ -0,0 +1,54 @@
1#include <linux/types.h>
2#include <linux/errno.h>
3#include <asm/uaccess.h>
4
5#include "soft-fp.h"
6#include "double.h"
7
8int
9fnmsub(void *frD, void *frA, void *frB, void *frC)
10{
11 FP_DECL_D(R);
12 FP_DECL_D(A);
13 FP_DECL_D(B);
14 FP_DECL_D(C);
15 FP_DECL_D(T);
16 int ret = 0;
17
18#ifdef DEBUG
19 printk("%s: %p %p %p %p\n", __FUNCTION__, frD, frA, frB, frC);
20#endif
21
22 __FP_UNPACK_D(A, frA);
23 __FP_UNPACK_D(B, frB);
24 __FP_UNPACK_D(C, frC);
25
26#ifdef DEBUG
27 printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
28 printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c);
29 printk("C: %ld %lu %lu %ld (%ld)\n", C_s, C_f1, C_f0, C_e, C_c);
30#endif
31
32 if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) ||
33 (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF))
34 ret |= EFLAG_VXIMZ;
35
36 FP_MUL_D(T, A, C);
37
38 if (B_c != FP_CLS_NAN)
39 B_s ^= 1;
40
41 if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF)
42 ret |= EFLAG_VXISI;
43
44 FP_ADD_D(R, T, B);
45
46 if (R_c != FP_CLS_NAN)
47 R_s ^= 1;
48
49#ifdef DEBUG
50 printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
51#endif
52
53 return (ret | __FP_PACK_D(frD, R));
54}
diff --git a/arch/powerpc/math-emu/fnmsubs.c b/arch/powerpc/math-emu/fnmsubs.c
new file mode 100644
index 000000000000..5c9a09a87dc7
--- /dev/null
+++ b/arch/powerpc/math-emu/fnmsubs.c
@@ -0,0 +1,55 @@
1#include <linux/types.h>
2#include <linux/errno.h>
3#include <asm/uaccess.h>
4
5#include "soft-fp.h"
6#include "double.h"
7#include "single.h"
8
9int
10fnmsubs(void *frD, void *frA, void *frB, void *frC)
11{
12 FP_DECL_D(R);
13 FP_DECL_D(A);
14 FP_DECL_D(B);
15 FP_DECL_D(C);
16 FP_DECL_D(T);
17 int ret = 0;
18
19#ifdef DEBUG
20 printk("%s: %p %p %p %p\n", __FUNCTION__, frD, frA, frB, frC);
21#endif
22
23 __FP_UNPACK_D(A, frA);
24 __FP_UNPACK_D(B, frB);
25 __FP_UNPACK_D(C, frC);
26
27#ifdef DEBUG
28 printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
29 printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c);
30 printk("C: %ld %lu %lu %ld (%ld)\n", C_s, C_f1, C_f0, C_e, C_c);
31#endif
32
33 if ((A_c == FP_CLS_INF && C_c == FP_CLS_ZERO) ||
34 (A_c == FP_CLS_ZERO && C_c == FP_CLS_INF))
35 ret |= EFLAG_VXIMZ;
36
37 FP_MUL_D(T, A, C);
38
39 if (B_c != FP_CLS_NAN)
40 B_s ^= 1;
41
42 if (T_s != B_s && T_c == FP_CLS_INF && B_c == FP_CLS_INF)
43 ret |= EFLAG_VXISI;
44
45 FP_ADD_D(R, T, B);
46
47 if (R_c != FP_CLS_NAN)
48 R_s ^= 1;
49
50#ifdef DEBUG
51 printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
52#endif
53
54 return (ret | __FP_PACK_DS(frD, R));
55}
diff --git a/arch/powerpc/math-emu/fres.c b/arch/powerpc/math-emu/fres.c
new file mode 100644
index 000000000000..ec11e46d20af
--- /dev/null
+++ b/arch/powerpc/math-emu/fres.c
@@ -0,0 +1,12 @@
1#include <linux/types.h>
2#include <linux/errno.h>
3#include <asm/uaccess.h>
4
5int
6fres(void *frD, void *frB)
7{
8#ifdef DEBUG
9 printk("%s: %p %p\n", __FUNCTION__, frD, frB);
10#endif
11 return -ENOSYS;
12}
diff --git a/arch/powerpc/math-emu/frsp.c b/arch/powerpc/math-emu/frsp.c
new file mode 100644
index 000000000000..d879b2a3d0c9
--- /dev/null
+++ b/arch/powerpc/math-emu/frsp.c
@@ -0,0 +1,25 @@
1#include <linux/types.h>
2#include <linux/errno.h>
3#include <asm/uaccess.h>
4
5#include "soft-fp.h"
6#include "double.h"
7#include "single.h"
8
9int
10frsp(void *frD, void *frB)
11{
12 FP_DECL_D(B);
13
14#ifdef DEBUG
15 printk("%s: D %p, B %p\n", __FUNCTION__, frD, frB);
16#endif
17
18 __FP_UNPACK_D(B, frB);
19
20#ifdef DEBUG
21 printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c);
22#endif
23
24 return __FP_PACK_DS(frD, B);
25}
diff --git a/arch/powerpc/math-emu/frsqrte.c b/arch/powerpc/math-emu/frsqrte.c
new file mode 100644
index 000000000000..a11ae1829850
--- /dev/null
+++ b/arch/powerpc/math-emu/frsqrte.c
@@ -0,0 +1,12 @@
1#include <linux/types.h>
2#include <linux/errno.h>
3#include <asm/uaccess.h>
4
5int
6frsqrte(void *frD, void *frB)
7{
8#ifdef DEBUG
9 printk("%s: %p %p\n", __FUNCTION__, frD, frB);
10#endif
11 return 0;
12}
diff --git a/arch/powerpc/math-emu/fsel.c b/arch/powerpc/math-emu/fsel.c
new file mode 100644
index 000000000000..e36e6e72819a
--- /dev/null
+++ b/arch/powerpc/math-emu/fsel.c
@@ -0,0 +1,38 @@
1#include <linux/types.h>
2#include <linux/errno.h>
3#include <asm/uaccess.h>
4
5#include "soft-fp.h"
6#include "double.h"
7
8int
9fsel(u32 *frD, void *frA, u32 *frB, u32 *frC)
10{
11 FP_DECL_D(A);
12
13#ifdef DEBUG
14 printk("%s: %p %p %p %p\n", __FUNCTION__, frD, frA, frB, frC);
15#endif
16
17 __FP_UNPACK_D(A, frA);
18
19#ifdef DEBUG
20 printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
21 printk("B: %08x %08x\n", frB[0], frB[1]);
22 printk("C: %08x %08x\n", frC[0], frC[1]);
23#endif
24
25 if (A_c == FP_CLS_NAN || (A_c != FP_CLS_ZERO && A_s)) {
26 frD[0] = frB[0];
27 frD[1] = frB[1];
28 } else {
29 frD[0] = frC[0];
30 frD[1] = frC[1];
31 }
32
33#ifdef DEBUG
34 printk("D: %08x.%08x\n", frD[0], frD[1]);
35#endif
36
37 return 0;
38}
diff --git a/arch/powerpc/math-emu/fsqrt.c b/arch/powerpc/math-emu/fsqrt.c
new file mode 100644
index 000000000000..6f8319f64a8a
--- /dev/null
+++ b/arch/powerpc/math-emu/fsqrt.c
@@ -0,0 +1,37 @@
1#include <linux/types.h>
2#include <linux/errno.h>
3#include <asm/uaccess.h>
4
5#include "soft-fp.h"
6#include "double.h"
7
8int
9fsqrt(void *frD, void *frB)
10{
11 FP_DECL_D(B);
12 FP_DECL_D(R);
13 int ret = 0;
14
15#ifdef DEBUG
16 printk("%s: %p %p %p %p\n", __FUNCTION__, frD, frB);
17#endif
18
19 __FP_UNPACK_D(B, frB);
20
21#ifdef DEBUG
22 printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c);
23#endif
24
25 if (B_s && B_c != FP_CLS_ZERO)
26 ret |= EFLAG_VXSQRT;
27 if (B_c == FP_CLS_NAN)
28 ret |= EFLAG_VXSNAN;
29
30 FP_SQRT_D(R, B);
31
32#ifdef DEBUG
33 printk("R: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
34#endif
35
36 return (ret | __FP_PACK_D(frD, R));
37}
diff --git a/arch/powerpc/math-emu/fsqrts.c b/arch/powerpc/math-emu/fsqrts.c
new file mode 100644
index 000000000000..3b2b1cf55c12
--- /dev/null
+++ b/arch/powerpc/math-emu/fsqrts.c
@@ -0,0 +1,38 @@
1#include <linux/types.h>
2#include <linux/errno.h>
3#include <asm/uaccess.h>
4
5#include "soft-fp.h"
6#include "double.h"
7#include "single.h"
8
9int
10fsqrts(void *frD, void *frB)
11{
12 FP_DECL_D(B);
13 FP_DECL_D(R);
14 int ret = 0;
15
16#ifdef DEBUG
17 printk("%s: %p %p %p %p\n", __FUNCTION__, frD, frB);
18#endif
19
20 __FP_UNPACK_D(B, frB);
21
22#ifdef DEBUG
23 printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c);
24#endif
25
26 if (B_s && B_c != FP_CLS_ZERO)
27 ret |= EFLAG_VXSQRT;
28 if (B_c == FP_CLS_NAN)
29 ret |= EFLAG_VXSNAN;
30
31 FP_SQRT_D(R, B);
32
33#ifdef DEBUG
34 printk("R: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
35#endif
36
37 return (ret | __FP_PACK_DS(frD, R));
38}
diff --git a/arch/powerpc/math-emu/fsub.c b/arch/powerpc/math-emu/fsub.c
new file mode 100644
index 000000000000..956679042bb2
--- /dev/null
+++ b/arch/powerpc/math-emu/fsub.c
@@ -0,0 +1,41 @@
1#include <linux/types.h>
2#include <linux/errno.h>
3#include <asm/uaccess.h>
4
5#include "soft-fp.h"
6#include "double.h"
7
8int
9fsub(void *frD, void *frA, void *frB)
10{
11 FP_DECL_D(A);
12 FP_DECL_D(B);
13 FP_DECL_D(R);
14 int ret = 0;
15
16#ifdef DEBUG
17 printk("%s: %p %p %p\n", __FUNCTION__, frD, frA, frB);
18#endif
19
20 __FP_UNPACK_D(A, frA);
21 __FP_UNPACK_D(B, frB);
22
23#ifdef DEBUG
24 printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
25 printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c);
26#endif
27
28 if (B_c != FP_CLS_NAN)
29 B_s ^= 1;
30
31 if (A_s != B_s && A_c == FP_CLS_INF && B_c == FP_CLS_INF)
32 ret |= EFLAG_VXISI;
33
34 FP_ADD_D(R, A, B);
35
36#ifdef DEBUG
37 printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
38#endif
39
40 return (ret | __FP_PACK_D(frD, R));
41}
diff --git a/arch/powerpc/math-emu/fsubs.c b/arch/powerpc/math-emu/fsubs.c
new file mode 100644
index 000000000000..3428117dfe8c
--- /dev/null
+++ b/arch/powerpc/math-emu/fsubs.c
@@ -0,0 +1,42 @@
1#include <linux/types.h>
2#include <linux/errno.h>
3#include <asm/uaccess.h>
4
5#include "soft-fp.h"
6#include "double.h"
7#include "single.h"
8
9int
10fsubs(void *frD, void *frA, void *frB)
11{
12 FP_DECL_D(A);
13 FP_DECL_D(B);
14 FP_DECL_D(R);
15 int ret = 0;
16
17#ifdef DEBUG
18 printk("%s: %p %p %p\n", __FUNCTION__, frD, frA, frB);
19#endif
20
21 __FP_UNPACK_D(A, frA);
22 __FP_UNPACK_D(B, frB);
23
24#ifdef DEBUG
25 printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
26 printk("B: %ld %lu %lu %ld (%ld)\n", B_s, B_f1, B_f0, B_e, B_c);
27#endif
28
29 if (B_c != FP_CLS_NAN)
30 B_s ^= 1;
31
32 if (A_s != B_s && A_c == FP_CLS_INF && B_c == FP_CLS_INF)
33 ret |= EFLAG_VXISI;
34
35 FP_ADD_D(R, A, B);
36
37#ifdef DEBUG
38 printk("D: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
39#endif
40
41 return (ret | __FP_PACK_DS(frD, R));
42}
diff --git a/arch/powerpc/math-emu/lfd.c b/arch/powerpc/math-emu/lfd.c
new file mode 100644
index 000000000000..7d38101c329b
--- /dev/null
+++ b/arch/powerpc/math-emu/lfd.c
@@ -0,0 +1,19 @@
1#include <linux/types.h>
2#include <linux/errno.h>
3#include <asm/uaccess.h>
4
5#include "sfp-machine.h"
6#include "double.h"
7
8int
9lfd(void *frD, void *ea)
10{
11 if (copy_from_user(frD, ea, sizeof(double)))
12 return -EFAULT;
13#ifdef DEBUG
14 printk("%s: D %p, ea %p: ", __FUNCTION__, frD, ea);
15 dump_double(frD);
16 printk("\n");
17#endif
18 return 0;
19}
diff --git a/arch/powerpc/math-emu/lfs.c b/arch/powerpc/math-emu/lfs.c
new file mode 100644
index 000000000000..c86dee3d7655
--- /dev/null
+++ b/arch/powerpc/math-emu/lfs.c
@@ -0,0 +1,37 @@
1#include <linux/types.h>
2#include <linux/errno.h>
3#include <asm/uaccess.h>
4
5#include "soft-fp.h"
6#include "double.h"
7#include "single.h"
8
9int
10lfs(void *frD, void *ea)
11{
12 FP_DECL_D(R);
13 FP_DECL_S(A);
14 float f;
15
16#ifdef DEBUG
17 printk("%s: D %p, ea %p\n", __FUNCTION__, frD, ea);
18#endif
19
20 if (copy_from_user(&f, ea, sizeof(float)))
21 return -EFAULT;
22
23 __FP_UNPACK_S(A, &f);
24
25#ifdef DEBUG
26 printk("A: %ld %lu %ld (%ld) [%08lx]\n", A_s, A_f, A_e, A_c,
27 *(unsigned long *)&f);
28#endif
29
30 FP_CONV(D, S, 2, 1, R, A);
31
32#ifdef DEBUG
33 printk("R: %ld %lu %lu %ld (%ld)\n", R_s, R_f1, R_f0, R_e, R_c);
34#endif
35
36 return __FP_PACK_D(frD, R);
37}
diff --git a/arch/powerpc/math-emu/math.c b/arch/powerpc/math-emu/math.c
new file mode 100644
index 000000000000..589153472761
--- /dev/null
+++ b/arch/powerpc/math-emu/math.c
@@ -0,0 +1,483 @@
1/*
2 * Copyright (C) 1999 Eddie C. Dost (ecd@atecom.com)
3 */
4
5#include <linux/config.h>
6#include <linux/types.h>
7#include <linux/sched.h>
8
9#include <asm/uaccess.h>
10#include <asm/reg.h>
11
12#include "sfp-machine.h"
13#include "double.h"
14
15#define FLOATFUNC(x) extern int x(void *, void *, void *, void *)
16
17FLOATFUNC(fadd);
18FLOATFUNC(fadds);
19FLOATFUNC(fdiv);
20FLOATFUNC(fdivs);
21FLOATFUNC(fmul);
22FLOATFUNC(fmuls);
23FLOATFUNC(fsub);
24FLOATFUNC(fsubs);
25
26FLOATFUNC(fmadd);
27FLOATFUNC(fmadds);
28FLOATFUNC(fmsub);
29FLOATFUNC(fmsubs);
30FLOATFUNC(fnmadd);
31FLOATFUNC(fnmadds);
32FLOATFUNC(fnmsub);
33FLOATFUNC(fnmsubs);
34
35FLOATFUNC(fctiw);
36FLOATFUNC(fctiwz);
37FLOATFUNC(frsp);
38
39FLOATFUNC(fcmpo);
40FLOATFUNC(fcmpu);
41
42FLOATFUNC(mcrfs);
43FLOATFUNC(mffs);
44FLOATFUNC(mtfsb0);
45FLOATFUNC(mtfsb1);
46FLOATFUNC(mtfsf);
47FLOATFUNC(mtfsfi);
48
49FLOATFUNC(lfd);
50FLOATFUNC(lfs);
51
52FLOATFUNC(stfd);
53FLOATFUNC(stfs);
54FLOATFUNC(stfiwx);
55
56FLOATFUNC(fabs);
57FLOATFUNC(fmr);
58FLOATFUNC(fnabs);
59FLOATFUNC(fneg);
60
61/* Optional */
62FLOATFUNC(fres);
63FLOATFUNC(frsqrte);
64FLOATFUNC(fsel);
65FLOATFUNC(fsqrt);
66FLOATFUNC(fsqrts);
67
68
69#define OP31 0x1f /* 31 */
70#define LFS 0x30 /* 48 */
71#define LFSU 0x31 /* 49 */
72#define LFD 0x32 /* 50 */
73#define LFDU 0x33 /* 51 */
74#define STFS 0x34 /* 52 */
75#define STFSU 0x35 /* 53 */
76#define STFD 0x36 /* 54 */
77#define STFDU 0x37 /* 55 */
78#define OP59 0x3b /* 59 */
79#define OP63 0x3f /* 63 */
80
81/* Opcode 31: */
82/* X-Form: */
83#define LFSX 0x217 /* 535 */
84#define LFSUX 0x237 /* 567 */
85#define LFDX 0x257 /* 599 */
86#define LFDUX 0x277 /* 631 */
87#define STFSX 0x297 /* 663 */
88#define STFSUX 0x2b7 /* 695 */
89#define STFDX 0x2d7 /* 727 */
90#define STFDUX 0x2f7 /* 759 */
91#define STFIWX 0x3d7 /* 983 */
92
93/* Opcode 59: */
94/* A-Form: */
95#define FDIVS 0x012 /* 18 */
96#define FSUBS 0x014 /* 20 */
97#define FADDS 0x015 /* 21 */
98#define FSQRTS 0x016 /* 22 */
99#define FRES 0x018 /* 24 */
100#define FMULS 0x019 /* 25 */
101#define FMSUBS 0x01c /* 28 */
102#define FMADDS 0x01d /* 29 */
103#define FNMSUBS 0x01e /* 30 */
104#define FNMADDS 0x01f /* 31 */
105
106/* Opcode 63: */
107/* A-Form: */
108#define FDIV 0x012 /* 18 */
109#define FSUB 0x014 /* 20 */
110#define FADD 0x015 /* 21 */
111#define FSQRT 0x016 /* 22 */
112#define FSEL 0x017 /* 23 */
113#define FMUL 0x019 /* 25 */
114#define FRSQRTE 0x01a /* 26 */
115#define FMSUB 0x01c /* 28 */
116#define FMADD 0x01d /* 29 */
117#define FNMSUB 0x01e /* 30 */
118#define FNMADD 0x01f /* 31 */
119
120/* X-Form: */
121#define FCMPU 0x000 /* 0 */
122#define FRSP 0x00c /* 12 */
123#define FCTIW 0x00e /* 14 */
124#define FCTIWZ 0x00f /* 15 */
125#define FCMPO 0x020 /* 32 */
126#define MTFSB1 0x026 /* 38 */
127#define FNEG 0x028 /* 40 */
128#define MCRFS 0x040 /* 64 */
129#define MTFSB0 0x046 /* 70 */
130#define FMR 0x048 /* 72 */
131#define MTFSFI 0x086 /* 134 */
132#define FNABS 0x088 /* 136 */
133#define FABS 0x108 /* 264 */
134#define MFFS 0x247 /* 583 */
135#define MTFSF 0x2c7 /* 711 */
136
137
138#define AB 2
139#define AC 3
140#define ABC 4
141#define D 5
142#define DU 6
143#define X 7
144#define XA 8
145#define XB 9
146#define XCR 11
147#define XCRB 12
148#define XCRI 13
149#define XCRL 16
150#define XE 14
151#define XEU 15
152#define XFLB 10
153
154#ifdef CONFIG_MATH_EMULATION
155static int
156record_exception(struct pt_regs *regs, int eflag)
157{
158 u32 fpscr;
159
160 fpscr = __FPU_FPSCR;
161
162 if (eflag) {
163 fpscr |= FPSCR_FX;
164 if (eflag & EFLAG_OVERFLOW)
165 fpscr |= FPSCR_OX;
166 if (eflag & EFLAG_UNDERFLOW)
167 fpscr |= FPSCR_UX;
168 if (eflag & EFLAG_DIVZERO)
169 fpscr |= FPSCR_ZX;
170 if (eflag & EFLAG_INEXACT)
171 fpscr |= FPSCR_XX;
172 if (eflag & EFLAG_VXSNAN)
173 fpscr |= FPSCR_VXSNAN;
174 if (eflag & EFLAG_VXISI)
175 fpscr |= FPSCR_VXISI;
176 if (eflag & EFLAG_VXIDI)
177 fpscr |= FPSCR_VXIDI;
178 if (eflag & EFLAG_VXZDZ)
179 fpscr |= FPSCR_VXZDZ;
180 if (eflag & EFLAG_VXIMZ)
181 fpscr |= FPSCR_VXIMZ;
182 if (eflag & EFLAG_VXVC)
183 fpscr |= FPSCR_VXVC;
184 if (eflag & EFLAG_VXSOFT)
185 fpscr |= FPSCR_VXSOFT;
186 if (eflag & EFLAG_VXSQRT)
187 fpscr |= FPSCR_VXSQRT;
188 if (eflag & EFLAG_VXCVI)
189 fpscr |= FPSCR_VXCVI;
190 }
191
192 fpscr &= ~(FPSCR_VX);
193 if (fpscr & (FPSCR_VXSNAN | FPSCR_VXISI | FPSCR_VXIDI |
194 FPSCR_VXZDZ | FPSCR_VXIMZ | FPSCR_VXVC |
195 FPSCR_VXSOFT | FPSCR_VXSQRT | FPSCR_VXCVI))
196 fpscr |= FPSCR_VX;
197
198 fpscr &= ~(FPSCR_FEX);
199 if (((fpscr & FPSCR_VX) && (fpscr & FPSCR_VE)) ||
200 ((fpscr & FPSCR_OX) && (fpscr & FPSCR_OE)) ||
201 ((fpscr & FPSCR_UX) && (fpscr & FPSCR_UE)) ||
202 ((fpscr & FPSCR_ZX) && (fpscr & FPSCR_ZE)) ||
203 ((fpscr & FPSCR_XX) && (fpscr & FPSCR_XE)))
204 fpscr |= FPSCR_FEX;
205
206 __FPU_FPSCR = fpscr;
207
208 return (fpscr & FPSCR_FEX) ? 1 : 0;
209}
210#endif /* CONFIG_MATH_EMULATION */
211
212int
213do_mathemu(struct pt_regs *regs)
214{
215 void *op0 = 0, *op1 = 0, *op2 = 0, *op3 = 0;
216 unsigned long pc = regs->nip;
217 signed short sdisp;
218 u32 insn = 0;
219 int idx = 0;
220#ifdef CONFIG_MATH_EMULATION
221 int (*func)(void *, void *, void *, void *);
222 int type = 0;
223 int eflag, trap;
224#endif
225
226 if (get_user(insn, (u32 *)pc))
227 return -EFAULT;
228
229#ifndef CONFIG_MATH_EMULATION
230 switch (insn >> 26) {
231 case LFD:
232 idx = (insn >> 16) & 0x1f;
233 sdisp = (insn & 0xffff);
234 op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
235 op1 = (void *)((idx ? regs->gpr[idx] : 0) + sdisp);
236 lfd(op0, op1, op2, op3);
237 break;
238 case LFDU:
239 idx = (insn >> 16) & 0x1f;
240 sdisp = (insn & 0xffff);
241 op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
242 op1 = (void *)((idx ? regs->gpr[idx] : 0) + sdisp);
243 lfd(op0, op1, op2, op3);
244 regs->gpr[idx] = (unsigned long)op1;
245 break;
246 case STFD:
247 idx = (insn >> 16) & 0x1f;
248 sdisp = (insn & 0xffff);
249 op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
250 op1 = (void *)((idx ? regs->gpr[idx] : 0) + sdisp);
251 stfd(op0, op1, op2, op3);
252 break;
253 case STFDU:
254 idx = (insn >> 16) & 0x1f;
255 sdisp = (insn & 0xffff);
256 op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
257 op1 = (void *)((idx ? regs->gpr[idx] : 0) + sdisp);
258 stfd(op0, op1, op2, op3);
259 regs->gpr[idx] = (unsigned long)op1;
260 break;
261 case OP63:
262 op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
263 op1 = (void *)&current->thread.fpr[(insn >> 11) & 0x1f];
264 fmr(op0, op1, op2, op3);
265 break;
266 default:
267 goto illegal;
268 }
269#else /* CONFIG_MATH_EMULATION */
270 switch (insn >> 26) {
271 case LFS: func = lfs; type = D; break;
272 case LFSU: func = lfs; type = DU; break;
273 case LFD: func = lfd; type = D; break;
274 case LFDU: func = lfd; type = DU; break;
275 case STFS: func = stfs; type = D; break;
276 case STFSU: func = stfs; type = DU; break;
277 case STFD: func = stfd; type = D; break;
278 case STFDU: func = stfd; type = DU; break;
279
280 case OP31:
281 switch ((insn >> 1) & 0x3ff) {
282 case LFSX: func = lfs; type = XE; break;
283 case LFSUX: func = lfs; type = XEU; break;
284 case LFDX: func = lfd; type = XE; break;
285 case LFDUX: func = lfd; type = XEU; break;
286 case STFSX: func = stfs; type = XE; break;
287 case STFSUX: func = stfs; type = XEU; break;
288 case STFDX: func = stfd; type = XE; break;
289 case STFDUX: func = stfd; type = XEU; break;
290 case STFIWX: func = stfiwx; type = XE; break;
291 default:
292 goto illegal;
293 }
294 break;
295
296 case OP59:
297 switch ((insn >> 1) & 0x1f) {
298 case FDIVS: func = fdivs; type = AB; break;
299 case FSUBS: func = fsubs; type = AB; break;
300 case FADDS: func = fadds; type = AB; break;
301 case FSQRTS: func = fsqrts; type = AB; break;
302 case FRES: func = fres; type = AB; break;
303 case FMULS: func = fmuls; type = AC; break;
304 case FMSUBS: func = fmsubs; type = ABC; break;
305 case FMADDS: func = fmadds; type = ABC; break;
306 case FNMSUBS: func = fnmsubs; type = ABC; break;
307 case FNMADDS: func = fnmadds; type = ABC; break;
308 default:
309 goto illegal;
310 }
311 break;
312
313 case OP63:
314 if (insn & 0x20) {
315 switch ((insn >> 1) & 0x1f) {
316 case FDIV: func = fdiv; type = AB; break;
317 case FSUB: func = fsub; type = AB; break;
318 case FADD: func = fadd; type = AB; break;
319 case FSQRT: func = fsqrt; type = AB; break;
320 case FSEL: func = fsel; type = ABC; break;
321 case FMUL: func = fmul; type = AC; break;
322 case FRSQRTE: func = frsqrte; type = AB; break;
323 case FMSUB: func = fmsub; type = ABC; break;
324 case FMADD: func = fmadd; type = ABC; break;
325 case FNMSUB: func = fnmsub; type = ABC; break;
326 case FNMADD: func = fnmadd; type = ABC; break;
327 default:
328 goto illegal;
329 }
330 break;
331 }
332
333 switch ((insn >> 1) & 0x3ff) {
334 case FCMPU: func = fcmpu; type = XCR; break;
335 case FRSP: func = frsp; type = XB; break;
336 case FCTIW: func = fctiw; type = XB; break;
337 case FCTIWZ: func = fctiwz; type = XB; break;
338 case FCMPO: func = fcmpo; type = XCR; break;
339 case MTFSB1: func = mtfsb1; type = XCRB; break;
340 case FNEG: func = fneg; type = XB; break;
341 case MCRFS: func = mcrfs; type = XCRL; break;
342 case MTFSB0: func = mtfsb0; type = XCRB; break;
343 case FMR: func = fmr; type = XB; break;
344 case MTFSFI: func = mtfsfi; type = XCRI; break;
345 case FNABS: func = fnabs; type = XB; break;
346 case FABS: func = fabs; type = XB; break;
347 case MFFS: func = mffs; type = X; break;
348 case MTFSF: func = mtfsf; type = XFLB; break;
349 default:
350 goto illegal;
351 }
352 break;
353
354 default:
355 goto illegal;
356 }
357
358 switch (type) {
359 case AB:
360 op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
361 op1 = (void *)&current->thread.fpr[(insn >> 16) & 0x1f];
362 op2 = (void *)&current->thread.fpr[(insn >> 11) & 0x1f];
363 break;
364
365 case AC:
366 op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
367 op1 = (void *)&current->thread.fpr[(insn >> 16) & 0x1f];
368 op2 = (void *)&current->thread.fpr[(insn >> 6) & 0x1f];
369 break;
370
371 case ABC:
372 op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
373 op1 = (void *)&current->thread.fpr[(insn >> 16) & 0x1f];
374 op2 = (void *)&current->thread.fpr[(insn >> 11) & 0x1f];
375 op3 = (void *)&current->thread.fpr[(insn >> 6) & 0x1f];
376 break;
377
378 case D:
379 idx = (insn >> 16) & 0x1f;
380 sdisp = (insn & 0xffff);
381 op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
382 op1 = (void *)((idx ? regs->gpr[idx] : 0) + sdisp);
383 break;
384
385 case DU:
386 idx = (insn >> 16) & 0x1f;
387 if (!idx)
388 goto illegal;
389
390 sdisp = (insn & 0xffff);
391 op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
392 op1 = (void *)(regs->gpr[idx] + sdisp);
393 break;
394
395 case X:
396 op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
397 break;
398
399 case XA:
400 op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
401 op1 = (void *)&current->thread.fpr[(insn >> 16) & 0x1f];
402 break;
403
404 case XB:
405 op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
406 op1 = (void *)&current->thread.fpr[(insn >> 11) & 0x1f];
407 break;
408
409 case XE:
410 idx = (insn >> 16) & 0x1f;
411 if (!idx)
412 goto illegal;
413
414 op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
415 op1 = (void *)(regs->gpr[idx] + regs->gpr[(insn >> 11) & 0x1f]);
416 break;
417
418 case XEU:
419 idx = (insn >> 16) & 0x1f;
420 op0 = (void *)&current->thread.fpr[(insn >> 21) & 0x1f];
421 op1 = (void *)((idx ? regs->gpr[idx] : 0)
422 + regs->gpr[(insn >> 11) & 0x1f]);
423 break;
424
425 case XCR:
426 op0 = (void *)&regs->ccr;
427 op1 = (void *)((insn >> 23) & 0x7);
428 op2 = (void *)&current->thread.fpr[(insn >> 16) & 0x1f];
429 op3 = (void *)&current->thread.fpr[(insn >> 11) & 0x1f];
430 break;
431
432 case XCRL:
433 op0 = (void *)&regs->ccr;
434 op1 = (void *)((insn >> 23) & 0x7);
435 op2 = (void *)((insn >> 18) & 0x7);
436 break;
437
438 case XCRB:
439 op0 = (void *)((insn >> 21) & 0x1f);
440 break;
441
442 case XCRI:
443 op0 = (void *)((insn >> 23) & 0x7);
444 op1 = (void *)((insn >> 12) & 0xf);
445 break;
446
447 case XFLB:
448 op0 = (void *)((insn >> 17) & 0xff);
449 op1 = (void *)&current->thread.fpr[(insn >> 11) & 0x1f];
450 break;
451
452 default:
453 goto illegal;
454 }
455
456 eflag = func(op0, op1, op2, op3);
457
458 if (insn & 1) {
459 regs->ccr &= ~(0x0f000000);
460 regs->ccr |= (__FPU_FPSCR >> 4) & 0x0f000000;
461 }
462
463 trap = record_exception(regs, eflag);
464 if (trap)
465 return 1;
466
467 switch (type) {
468 case DU:
469 case XEU:
470 regs->gpr[idx] = (unsigned long)op1;
471 break;
472
473 default:
474 break;
475 }
476#endif /* CONFIG_MATH_EMULATION */
477
478 regs->nip += 4;
479 return 0;
480
481illegal:
482 return -ENOSYS;
483}
diff --git a/arch/powerpc/math-emu/mcrfs.c b/arch/powerpc/math-emu/mcrfs.c
new file mode 100644
index 000000000000..106dd912914b
--- /dev/null
+++ b/arch/powerpc/math-emu/mcrfs.c
@@ -0,0 +1,31 @@
1#include <linux/types.h>
2#include <linux/errno.h>
3#include <asm/uaccess.h>
4
5#include "soft-fp.h"
6
7int
8mcrfs(u32 *ccr, u32 crfD, u32 crfS)
9{
10 u32 value, clear;
11
12#ifdef DEBUG
13 printk("%s: %p (%08x) %d %d\n", __FUNCTION__, ccr, *ccr, crfD, crfS);
14#endif
15
16 clear = 15 << ((7 - crfS) << 2);
17 if (!crfS)
18 clear = 0x90000000;
19
20 value = (__FPU_FPSCR >> ((7 - crfS) << 2)) & 15;
21 __FPU_FPSCR &= ~(clear);
22
23 *ccr &= ~(15 << ((7 - crfD) << 2));
24 *ccr |= (value << ((7 - crfD) << 2));
25
26#ifdef DEBUG
27 printk("CR: %08x\n", __FUNCTION__, *ccr);
28#endif
29
30 return 0;
31}
diff --git a/arch/powerpc/math-emu/mffs.c b/arch/powerpc/math-emu/mffs.c
new file mode 100644
index 000000000000..f477c9170e75
--- /dev/null
+++ b/arch/powerpc/math-emu/mffs.c
@@ -0,0 +1,17 @@
1#include <linux/types.h>
2#include <linux/errno.h>
3#include <asm/uaccess.h>
4
5#include "soft-fp.h"
6
7int
8mffs(u32 *frD)
9{
10 frD[1] = __FPU_FPSCR;
11
12#ifdef DEBUG
13 printk("%s: frD %p: %08x.%08x\n", __FUNCTION__, frD, frD[0], frD[1]);
14#endif
15
16 return 0;
17}
diff --git a/arch/powerpc/math-emu/mtfsb0.c b/arch/powerpc/math-emu/mtfsb0.c
new file mode 100644
index 000000000000..99bfd80f4af3
--- /dev/null
+++ b/arch/powerpc/math-emu/mtfsb0.c
@@ -0,0 +1,18 @@
1#include <linux/types.h>
2#include <linux/errno.h>
3#include <asm/uaccess.h>
4
5#include "soft-fp.h"
6
7int
8mtfsb0(int crbD)
9{
10 if ((crbD != 1) && (crbD != 2))
11 __FPU_FPSCR &= ~(1 << (31 - crbD));
12
13#ifdef DEBUG
14 printk("%s: %d %08lx\n", __FUNCTION__, crbD, __FPU_FPSCR);
15#endif
16
17 return 0;
18}
diff --git a/arch/powerpc/math-emu/mtfsb1.c b/arch/powerpc/math-emu/mtfsb1.c
new file mode 100644
index 000000000000..3d9e7ed92d2b
--- /dev/null
+++ b/arch/powerpc/math-emu/mtfsb1.c
@@ -0,0 +1,18 @@
1#include <linux/types.h>
2#include <linux/errno.h>
3#include <asm/uaccess.h>
4
5#include "soft-fp.h"
6
7int
8mtfsb1(int crbD)
9{
10 if ((crbD != 1) && (crbD != 2))
11 __FPU_FPSCR |= (1 << (31 - crbD));
12
13#ifdef DEBUG
14 printk("%s: %d %08lx\n", __FUNCTION__, crbD, __FPU_FPSCR);
15#endif
16
17 return 0;
18}
diff --git a/arch/powerpc/math-emu/mtfsf.c b/arch/powerpc/math-emu/mtfsf.c
new file mode 100644
index 000000000000..d70cf714994c
--- /dev/null
+++ b/arch/powerpc/math-emu/mtfsf.c
@@ -0,0 +1,45 @@
1#include <linux/types.h>
2#include <linux/errno.h>
3#include <asm/uaccess.h>
4
5#include "soft-fp.h"
6
7int
8mtfsf(unsigned int FM, u32 *frB)
9{
10 u32 mask;
11
12 if (FM == 0)
13 return 0;
14
15 if (FM == 0xff)
16 mask = 0x9fffffff;
17 else {
18 mask = 0;
19 if (FM & (1 << 0))
20 mask |= 0x90000000;
21 if (FM & (1 << 1))
22 mask |= 0x0f000000;
23 if (FM & (1 << 2))
24 mask |= 0x00f00000;
25 if (FM & (1 << 3))
26 mask |= 0x000f0000;
27 if (FM & (1 << 4))
28 mask |= 0x0000f000;
29 if (FM & (1 << 5))
30 mask |= 0x00000f00;
31 if (FM & (1 << 6))
32 mask |= 0x000000f0;
33 if (FM & (1 << 7))
34 mask |= 0x0000000f;
35 }
36
37 __FPU_FPSCR &= ~(mask);
38 __FPU_FPSCR |= (frB[1] & mask);
39
40#ifdef DEBUG
41 printk("%s: %02x %p: %08lx\n", __FUNCTION__, FM, frB, __FPU_FPSCR);
42#endif
43
44 return 0;
45}
diff --git a/arch/powerpc/math-emu/mtfsfi.c b/arch/powerpc/math-emu/mtfsfi.c
new file mode 100644
index 000000000000..71df854baa7e
--- /dev/null
+++ b/arch/powerpc/math-emu/mtfsfi.c
@@ -0,0 +1,23 @@
1#include <linux/types.h>
2#include <linux/errno.h>
3#include <asm/uaccess.h>
4
5#include "soft-fp.h"
6
7int
8mtfsfi(unsigned int crfD, unsigned int IMM)
9{
10 u32 mask = 0xf;
11
12 if (!crfD)
13 mask = 9;
14
15 __FPU_FPSCR &= ~(mask << ((7 - crfD) << 2));
16 __FPU_FPSCR |= (IMM & 0xf) << ((7 - crfD) << 2);
17
18#ifdef DEBUG
19 printk("%s: %d %x: %08lx\n", __FUNCTION__, crfD, IMM, __FPU_FPSCR);
20#endif
21
22 return 0;
23}
diff --git a/arch/powerpc/math-emu/op-1.h b/arch/powerpc/math-emu/op-1.h
new file mode 100644
index 000000000000..c92fa95f562e
--- /dev/null
+++ b/arch/powerpc/math-emu/op-1.h
@@ -0,0 +1,245 @@
1/*
2 * Basic one-word fraction declaration and manipulation.
3 */
4
5#define _FP_FRAC_DECL_1(X) _FP_W_TYPE X##_f
6#define _FP_FRAC_COPY_1(D,S) (D##_f = S##_f)
7#define _FP_FRAC_SET_1(X,I) (X##_f = I)
8#define _FP_FRAC_HIGH_1(X) (X##_f)
9#define _FP_FRAC_LOW_1(X) (X##_f)
10#define _FP_FRAC_WORD_1(X,w) (X##_f)
11
12#define _FP_FRAC_ADDI_1(X,I) (X##_f += I)
13#define _FP_FRAC_SLL_1(X,N) \
14 do { \
15 if (__builtin_constant_p(N) && (N) == 1) \
16 X##_f += X##_f; \
17 else \
18 X##_f <<= (N); \
19 } while (0)
20#define _FP_FRAC_SRL_1(X,N) (X##_f >>= N)
21
22/* Right shift with sticky-lsb. */
23#define _FP_FRAC_SRS_1(X,N,sz) __FP_FRAC_SRS_1(X##_f, N, sz)
24
25#define __FP_FRAC_SRS_1(X,N,sz) \
26 (X = (X >> (N) | (__builtin_constant_p(N) && (N) == 1 \
27 ? X & 1 : (X << (_FP_W_TYPE_SIZE - (N))) != 0)))
28
29#define _FP_FRAC_ADD_1(R,X,Y) (R##_f = X##_f + Y##_f)
30#define _FP_FRAC_SUB_1(R,X,Y) (R##_f = X##_f - Y##_f)
31#define _FP_FRAC_CLZ_1(z, X) __FP_CLZ(z, X##_f)
32
33/* Predicates */
34#define _FP_FRAC_NEGP_1(X) ((_FP_WS_TYPE)X##_f < 0)
35#define _FP_FRAC_ZEROP_1(X) (X##_f == 0)
36#define _FP_FRAC_OVERP_1(fs,X) (X##_f & _FP_OVERFLOW_##fs)
37#define _FP_FRAC_EQ_1(X, Y) (X##_f == Y##_f)
38#define _FP_FRAC_GE_1(X, Y) (X##_f >= Y##_f)
39#define _FP_FRAC_GT_1(X, Y) (X##_f > Y##_f)
40
41#define _FP_ZEROFRAC_1 0
42#define _FP_MINFRAC_1 1
43
44/*
45 * Unpack the raw bits of a native fp value. Do not classify or
46 * normalize the data.
47 */
48
49#define _FP_UNPACK_RAW_1(fs, X, val) \
50 do { \
51 union _FP_UNION_##fs _flo; _flo.flt = (val); \
52 \
53 X##_f = _flo.bits.frac; \
54 X##_e = _flo.bits.exp; \
55 X##_s = _flo.bits.sign; \
56 } while (0)
57
58
59/*
60 * Repack the raw bits of a native fp value.
61 */
62
63#define _FP_PACK_RAW_1(fs, val, X) \
64 do { \
65 union _FP_UNION_##fs _flo; \
66 \
67 _flo.bits.frac = X##_f; \
68 _flo.bits.exp = X##_e; \
69 _flo.bits.sign = X##_s; \
70 \
71 (val) = _flo.flt; \
72 } while (0)
73
74
75/*
76 * Multiplication algorithms:
77 */
78
79/* Basic. Assuming the host word size is >= 2*FRACBITS, we can do the
80 multiplication immediately. */
81
82#define _FP_MUL_MEAT_1_imm(fs, R, X, Y) \
83 do { \
84 R##_f = X##_f * Y##_f; \
85 /* Normalize since we know where the msb of the multiplicands \
86 were (bit B), we know that the msb of the of the product is \
87 at either 2B or 2B-1. */ \
88 _FP_FRAC_SRS_1(R, _FP_WFRACBITS_##fs-1, 2*_FP_WFRACBITS_##fs); \
89 } while (0)
90
91/* Given a 1W * 1W => 2W primitive, do the extended multiplication. */
92
93#define _FP_MUL_MEAT_1_wide(fs, R, X, Y, doit) \
94 do { \
95 _FP_W_TYPE _Z_f0, _Z_f1; \
96 doit(_Z_f1, _Z_f0, X##_f, Y##_f); \
97 /* Normalize since we know where the msb of the multiplicands \
98 were (bit B), we know that the msb of the of the product is \
99 at either 2B or 2B-1. */ \
100 _FP_FRAC_SRS_2(_Z, _FP_WFRACBITS_##fs-1, 2*_FP_WFRACBITS_##fs); \
101 R##_f = _Z_f0; \
102 } while (0)
103
104/* Finally, a simple widening multiply algorithm. What fun! */
105
106#define _FP_MUL_MEAT_1_hard(fs, R, X, Y) \
107 do { \
108 _FP_W_TYPE _xh, _xl, _yh, _yl, _z_f0, _z_f1, _a_f0, _a_f1; \
109 \
110 /* split the words in half */ \
111 _xh = X##_f >> (_FP_W_TYPE_SIZE/2); \
112 _xl = X##_f & (((_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE/2)) - 1); \
113 _yh = Y##_f >> (_FP_W_TYPE_SIZE/2); \
114 _yl = Y##_f & (((_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE/2)) - 1); \
115 \
116 /* multiply the pieces */ \
117 _z_f0 = _xl * _yl; \
118 _a_f0 = _xh * _yl; \
119 _a_f1 = _xl * _yh; \
120 _z_f1 = _xh * _yh; \
121 \
122 /* reassemble into two full words */ \
123 if ((_a_f0 += _a_f1) < _a_f1) \
124 _z_f1 += (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE/2); \
125 _a_f1 = _a_f0 >> (_FP_W_TYPE_SIZE/2); \
126 _a_f0 = _a_f0 << (_FP_W_TYPE_SIZE/2); \
127 _FP_FRAC_ADD_2(_z, _z, _a); \
128 \
129 /* normalize */ \
130 _FP_FRAC_SRS_2(_z, _FP_WFRACBITS_##fs - 1, 2*_FP_WFRACBITS_##fs); \
131 R##_f = _z_f0; \
132 } while (0)
133
134
135/*
136 * Division algorithms:
137 */
138
139/* Basic. Assuming the host word size is >= 2*FRACBITS, we can do the
140 division immediately. Give this macro either _FP_DIV_HELP_imm for
141 C primitives or _FP_DIV_HELP_ldiv for the ISO function. Which you
142 choose will depend on what the compiler does with divrem4. */
143
144#define _FP_DIV_MEAT_1_imm(fs, R, X, Y, doit) \
145 do { \
146 _FP_W_TYPE _q, _r; \
147 X##_f <<= (X##_f < Y##_f \
148 ? R##_e--, _FP_WFRACBITS_##fs \
149 : _FP_WFRACBITS_##fs - 1); \
150 doit(_q, _r, X##_f, Y##_f); \
151 R##_f = _q | (_r != 0); \
152 } while (0)
153
154/* GCC's longlong.h defines a 2W / 1W => (1W,1W) primitive udiv_qrnnd
155 that may be useful in this situation. This first is for a primitive
156 that requires normalization, the second for one that does not. Look
157 for UDIV_NEEDS_NORMALIZATION to tell which your machine needs. */
158
159#define _FP_DIV_MEAT_1_udiv_norm(fs, R, X, Y) \
160 do { \
161 _FP_W_TYPE _nh, _nl, _q, _r; \
162 \
163 /* Normalize Y -- i.e. make the most significant bit set. */ \
164 Y##_f <<= _FP_WFRACXBITS_##fs - 1; \
165 \
166 /* Shift X op correspondingly high, that is, up one full word. */ \
167 if (X##_f <= Y##_f) \
168 { \
169 _nl = 0; \
170 _nh = X##_f; \
171 } \
172 else \
173 { \
174 R##_e++; \
175 _nl = X##_f << (_FP_W_TYPE_SIZE-1); \
176 _nh = X##_f >> 1; \
177 } \
178 \
179 udiv_qrnnd(_q, _r, _nh, _nl, Y##_f); \
180 R##_f = _q | (_r != 0); \
181 } while (0)
182
183#define _FP_DIV_MEAT_1_udiv(fs, R, X, Y) \
184 do { \
185 _FP_W_TYPE _nh, _nl, _q, _r; \
186 if (X##_f < Y##_f) \
187 { \
188 R##_e--; \
189 _nl = X##_f << _FP_WFRACBITS_##fs; \
190 _nh = X##_f >> _FP_WFRACXBITS_##fs; \
191 } \
192 else \
193 { \
194 _nl = X##_f << (_FP_WFRACBITS_##fs - 1); \
195 _nh = X##_f >> (_FP_WFRACXBITS_##fs + 1); \
196 } \
197 udiv_qrnnd(_q, _r, _nh, _nl, Y##_f); \
198 R##_f = _q | (_r != 0); \
199 } while (0)
200
201
202/*
203 * Square root algorithms:
204 * We have just one right now, maybe Newton approximation
205 * should be added for those machines where division is fast.
206 */
207
208#define _FP_SQRT_MEAT_1(R, S, T, X, q) \
209 do { \
210 while (q) \
211 { \
212 T##_f = S##_f + q; \
213 if (T##_f <= X##_f) \
214 { \
215 S##_f = T##_f + q; \
216 X##_f -= T##_f; \
217 R##_f += q; \
218 } \
219 _FP_FRAC_SLL_1(X, 1); \
220 q >>= 1; \
221 } \
222 } while (0)
223
224/*
225 * Assembly/disassembly for converting to/from integral types.
226 * No shifting or overflow handled here.
227 */
228
229#define _FP_FRAC_ASSEMBLE_1(r, X, rsize) (r = X##_f)
230#define _FP_FRAC_DISASSEMBLE_1(X, r, rsize) (X##_f = r)
231
232
233/*
234 * Convert FP values between word sizes
235 */
236
237#define _FP_FRAC_CONV_1_1(dfs, sfs, D, S) \
238 do { \
239 D##_f = S##_f; \
240 if (_FP_WFRACBITS_##sfs > _FP_WFRACBITS_##dfs) \
241 _FP_FRAC_SRS_1(D, (_FP_WFRACBITS_##sfs-_FP_WFRACBITS_##dfs), \
242 _FP_WFRACBITS_##sfs); \
243 else \
244 D##_f <<= _FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs; \
245 } while (0)
diff --git a/arch/powerpc/math-emu/op-2.h b/arch/powerpc/math-emu/op-2.h
new file mode 100644
index 000000000000..b9b06b4c6ea1
--- /dev/null
+++ b/arch/powerpc/math-emu/op-2.h
@@ -0,0 +1,433 @@
1/*
2 * Basic two-word fraction declaration and manipulation.
3 */
4
5#define _FP_FRAC_DECL_2(X) _FP_W_TYPE X##_f0, X##_f1
6#define _FP_FRAC_COPY_2(D,S) (D##_f0 = S##_f0, D##_f1 = S##_f1)
7#define _FP_FRAC_SET_2(X,I) __FP_FRAC_SET_2(X, I)
8#define _FP_FRAC_HIGH_2(X) (X##_f1)
9#define _FP_FRAC_LOW_2(X) (X##_f0)
10#define _FP_FRAC_WORD_2(X,w) (X##_f##w)
11
12#define _FP_FRAC_SLL_2(X,N) \
13 do { \
14 if ((N) < _FP_W_TYPE_SIZE) \
15 { \
16 if (__builtin_constant_p(N) && (N) == 1) \
17 { \
18 X##_f1 = X##_f1 + X##_f1 + (((_FP_WS_TYPE)(X##_f0)) < 0); \
19 X##_f0 += X##_f0; \
20 } \
21 else \
22 { \
23 X##_f1 = X##_f1 << (N) | X##_f0 >> (_FP_W_TYPE_SIZE - (N)); \
24 X##_f0 <<= (N); \
25 } \
26 } \
27 else \
28 { \
29 X##_f1 = X##_f0 << ((N) - _FP_W_TYPE_SIZE); \
30 X##_f0 = 0; \
31 } \
32 } while (0)
33
34#define _FP_FRAC_SRL_2(X,N) \
35 do { \
36 if ((N) < _FP_W_TYPE_SIZE) \
37 { \
38 X##_f0 = X##_f0 >> (N) | X##_f1 << (_FP_W_TYPE_SIZE - (N)); \
39 X##_f1 >>= (N); \
40 } \
41 else \
42 { \
43 X##_f0 = X##_f1 >> ((N) - _FP_W_TYPE_SIZE); \
44 X##_f1 = 0; \
45 } \
46 } while (0)
47
48/* Right shift with sticky-lsb. */
49#define _FP_FRAC_SRS_2(X,N,sz) \
50 do { \
51 if ((N) < _FP_W_TYPE_SIZE) \
52 { \
53 X##_f0 = (X##_f1 << (_FP_W_TYPE_SIZE - (N)) | X##_f0 >> (N) | \
54 (__builtin_constant_p(N) && (N) == 1 \
55 ? X##_f0 & 1 \
56 : (X##_f0 << (_FP_W_TYPE_SIZE - (N))) != 0)); \
57 X##_f1 >>= (N); \
58 } \
59 else \
60 { \
61 X##_f0 = (X##_f1 >> ((N) - _FP_W_TYPE_SIZE) | \
62 (((X##_f1 << (sz - (N))) | X##_f0) != 0)); \
63 X##_f1 = 0; \
64 } \
65 } while (0)
66
67#define _FP_FRAC_ADDI_2(X,I) \
68 __FP_FRAC_ADDI_2(X##_f1, X##_f0, I)
69
70#define _FP_FRAC_ADD_2(R,X,Y) \
71 __FP_FRAC_ADD_2(R##_f1, R##_f0, X##_f1, X##_f0, Y##_f1, Y##_f0)
72
73#define _FP_FRAC_SUB_2(R,X,Y) \
74 __FP_FRAC_SUB_2(R##_f1, R##_f0, X##_f1, X##_f0, Y##_f1, Y##_f0)
75
76#define _FP_FRAC_CLZ_2(R,X) \
77 do { \
78 if (X##_f1) \
79 __FP_CLZ(R,X##_f1); \
80 else \
81 { \
82 __FP_CLZ(R,X##_f0); \
83 R += _FP_W_TYPE_SIZE; \
84 } \
85 } while(0)
86
87/* Predicates */
88#define _FP_FRAC_NEGP_2(X) ((_FP_WS_TYPE)X##_f1 < 0)
89#define _FP_FRAC_ZEROP_2(X) ((X##_f1 | X##_f0) == 0)
90#define _FP_FRAC_OVERP_2(fs,X) (X##_f1 & _FP_OVERFLOW_##fs)
91#define _FP_FRAC_EQ_2(X, Y) (X##_f1 == Y##_f1 && X##_f0 == Y##_f0)
92#define _FP_FRAC_GT_2(X, Y) \
93 ((X##_f1 > Y##_f1) || (X##_f1 == Y##_f1 && X##_f0 > Y##_f0))
94#define _FP_FRAC_GE_2(X, Y) \
95 ((X##_f1 > Y##_f1) || (X##_f1 == Y##_f1 && X##_f0 >= Y##_f0))
96
97#define _FP_ZEROFRAC_2 0, 0
98#define _FP_MINFRAC_2 0, 1
99
100/*
101 * Internals
102 */
103
104#define __FP_FRAC_SET_2(X,I1,I0) (X##_f0 = I0, X##_f1 = I1)
105
106#define __FP_CLZ_2(R, xh, xl) \
107 do { \
108 if (xh) \
109 __FP_CLZ(R,xl); \
110 else \
111 { \
112 __FP_CLZ(R,xl); \
113 R += _FP_W_TYPE_SIZE; \
114 } \
115 } while(0)
116
117#if 0
118
119#ifndef __FP_FRAC_ADDI_2
120#define __FP_FRAC_ADDI_2(xh, xl, i) \
121 (xh += ((xl += i) < i))
122#endif
123#ifndef __FP_FRAC_ADD_2
124#define __FP_FRAC_ADD_2(rh, rl, xh, xl, yh, yl) \
125 (rh = xh + yh + ((rl = xl + yl) < xl))
126#endif
127#ifndef __FP_FRAC_SUB_2
128#define __FP_FRAC_SUB_2(rh, rl, xh, xl, yh, yl) \
129 (rh = xh - yh - ((rl = xl - yl) > xl))
130#endif
131
132#else
133
134#undef __FP_FRAC_ADDI_2
135#define __FP_FRAC_ADDI_2(xh, xl, i) add_ssaaaa(xh, xl, xh, xl, 0, i)
136#undef __FP_FRAC_ADD_2
137#define __FP_FRAC_ADD_2 add_ssaaaa
138#undef __FP_FRAC_SUB_2
139#define __FP_FRAC_SUB_2 sub_ddmmss
140
141#endif
142
143/*
144 * Unpack the raw bits of a native fp value. Do not classify or
145 * normalize the data.
146 */
147
148#define _FP_UNPACK_RAW_2(fs, X, val) \
149 do { \
150 union _FP_UNION_##fs _flo; _flo.flt = (val); \
151 \
152 X##_f0 = _flo.bits.frac0; \
153 X##_f1 = _flo.bits.frac1; \
154 X##_e = _flo.bits.exp; \
155 X##_s = _flo.bits.sign; \
156 } while (0)
157
158
159/*
160 * Repack the raw bits of a native fp value.
161 */
162
163#define _FP_PACK_RAW_2(fs, val, X) \
164 do { \
165 union _FP_UNION_##fs _flo; \
166 \
167 _flo.bits.frac0 = X##_f0; \
168 _flo.bits.frac1 = X##_f1; \
169 _flo.bits.exp = X##_e; \
170 _flo.bits.sign = X##_s; \
171 \
172 (val) = _flo.flt; \
173 } while (0)
174
175
176/*
177 * Multiplication algorithms:
178 */
179
180/* Given a 1W * 1W => 2W primitive, do the extended multiplication. */
181
182#define _FP_MUL_MEAT_2_wide(fs, R, X, Y, doit) \
183 do { \
184 _FP_FRAC_DECL_4(_z); _FP_FRAC_DECL_2(_b); _FP_FRAC_DECL_2(_c); \
185 \
186 doit(_FP_FRAC_WORD_4(_z,1), _FP_FRAC_WORD_4(_z,0), X##_f0, Y##_f0); \
187 doit(_b_f1, _b_f0, X##_f0, Y##_f1); \
188 doit(_c_f1, _c_f0, X##_f1, Y##_f0); \
189 doit(_FP_FRAC_WORD_4(_z,3), _FP_FRAC_WORD_4(_z,2), X##_f1, Y##_f1); \
190 \
191 __FP_FRAC_ADD_4(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \
192 _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0), \
193 0, _b_f1, _b_f0, 0, \
194 _FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \
195 _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0)); \
196 __FP_FRAC_ADD_4(_FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \
197 _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0), \
198 0, _c_f1, _c_f0, 0, \
199 _FP_FRAC_WORD_4(_z,3),_FP_FRAC_WORD_4(_z,2), \
200 _FP_FRAC_WORD_4(_z,1),_FP_FRAC_WORD_4(_z,0)); \
201 \
202 /* Normalize since we know where the msb of the multiplicands \
203 were (bit B), we know that the msb of the of the product is \
204 at either 2B or 2B-1. */ \
205 _FP_FRAC_SRS_4(_z, _FP_WFRACBITS_##fs-1, 2*_FP_WFRACBITS_##fs); \
206 R##_f0 = _FP_FRAC_WORD_4(_z,0); \
207 R##_f1 = _FP_FRAC_WORD_4(_z,1); \
208 } while (0)
209
210/* This next macro appears to be totally broken. Fortunately nowhere
211 * seems to use it :-> The problem is that we define _z[4] but
212 * then use it in _FP_FRAC_SRS_4, which will attempt to access
213 * _z_f[n] which will cause an error. The fix probably involves
214 * declaring it with _FP_FRAC_DECL_4, see previous macro. -- PMM 02/1998
215 */
216#define _FP_MUL_MEAT_2_gmp(fs, R, X, Y) \
217 do { \
218 _FP_W_TYPE _x[2], _y[2], _z[4]; \
219 _x[0] = X##_f0; _x[1] = X##_f1; \
220 _y[0] = Y##_f0; _y[1] = Y##_f1; \
221 \
222 mpn_mul_n(_z, _x, _y, 2); \
223 \
224 /* Normalize since we know where the msb of the multiplicands \
225 were (bit B), we know that the msb of the of the product is \
226 at either 2B or 2B-1. */ \
227 _FP_FRAC_SRS_4(_z, _FP_WFRACBITS##_fs-1, 2*_FP_WFRACBITS_##fs); \
228 R##_f0 = _z[0]; \
229 R##_f1 = _z[1]; \
230 } while (0)
231
232
233/*
234 * Division algorithms:
235 * This seems to be giving me difficulties -- PMM
236 * Look, NetBSD seems to be able to comment algorithms. Can't you?
237 * I've thrown printks at the problem.
238 * This now appears to work, but I still don't really know why.
239 * Also, I don't think the result is properly normalised...
240 */
241
242#define _FP_DIV_MEAT_2_udiv_64(fs, R, X, Y) \
243 do { \
244 extern void _fp_udivmodti4(_FP_W_TYPE q[2], _FP_W_TYPE r[2], \
245 _FP_W_TYPE n1, _FP_W_TYPE n0, \
246 _FP_W_TYPE d1, _FP_W_TYPE d0); \
247 _FP_W_TYPE _n_f3, _n_f2, _n_f1, _n_f0, _r_f1, _r_f0; \
248 _FP_W_TYPE _q_f1, _q_f0, _m_f1, _m_f0; \
249 _FP_W_TYPE _rmem[2], _qmem[2]; \
250 /* I think this check is to ensure that the result is normalised. \
251 * Assuming X,Y normalised (ie in [1.0,2.0)) X/Y will be in \
252 * [0.5,2.0). Furthermore, it will be less than 1.0 iff X < Y. \
253 * In this case we tweak things. (this is based on comments in \
254 * the NetBSD FPU emulation code. ) \
255 * We know X,Y are normalised because we ensure this as part of \
256 * the unpacking process. -- PMM \
257 */ \
258 if (_FP_FRAC_GT_2(X, Y)) \
259 { \
260/* R##_e++; */ \
261 _n_f3 = X##_f1 >> 1; \
262 _n_f2 = X##_f1 << (_FP_W_TYPE_SIZE - 1) | X##_f0 >> 1; \
263 _n_f1 = X##_f0 << (_FP_W_TYPE_SIZE - 1); \
264 _n_f0 = 0; \
265 } \
266 else \
267 { \
268 R##_e--; \
269 _n_f3 = X##_f1; \
270 _n_f2 = X##_f0; \
271 _n_f1 = _n_f0 = 0; \
272 } \
273 \
274 /* Normalize, i.e. make the most significant bit of the \
275 denominator set. CHANGED: - 1 to nothing -- PMM */ \
276 _FP_FRAC_SLL_2(Y, _FP_WFRACXBITS_##fs /* -1 */); \
277 \
278 /* Do the 256/128 bit division given the 128-bit _fp_udivmodtf4 \
279 primitive snagged from libgcc2.c. */ \
280 \
281 _fp_udivmodti4(_qmem, _rmem, _n_f3, _n_f2, 0, Y##_f1); \
282 _q_f1 = _qmem[0]; \
283 umul_ppmm(_m_f1, _m_f0, _q_f1, Y##_f0); \
284 _r_f1 = _rmem[0]; \
285 _r_f0 = _n_f1; \
286 if (_FP_FRAC_GT_2(_m, _r)) \
287 { \
288 _q_f1--; \
289 _FP_FRAC_ADD_2(_r, _r, Y); \
290 if (_FP_FRAC_GE_2(_r, Y) && _FP_FRAC_GT_2(_m, _r)) \
291 { \
292 _q_f1--; \
293 _FP_FRAC_ADD_2(_r, _r, Y); \
294 } \
295 } \
296 _FP_FRAC_SUB_2(_r, _r, _m); \
297 \
298 _fp_udivmodti4(_qmem, _rmem, _r_f1, _r_f0, 0, Y##_f1); \
299 _q_f0 = _qmem[0]; \
300 umul_ppmm(_m_f1, _m_f0, _q_f0, Y##_f0); \
301 _r_f1 = _rmem[0]; \
302 _r_f0 = _n_f0; \
303 if (_FP_FRAC_GT_2(_m, _r)) \
304 { \
305 _q_f0--; \
306 _FP_FRAC_ADD_2(_r, _r, Y); \
307 if (_FP_FRAC_GE_2(_r, Y) && _FP_FRAC_GT_2(_m, _r)) \
308 { \
309 _q_f0--; \
310 _FP_FRAC_ADD_2(_r, _r, Y); \
311 } \
312 } \
313 _FP_FRAC_SUB_2(_r, _r, _m); \
314 \
315 R##_f1 = _q_f1; \
316 R##_f0 = _q_f0 | ((_r_f1 | _r_f0) != 0); \
317 /* adjust so answer is normalized again. I'm not sure what the \
318 * final sz param should be. In practice it's never used since \
319 * N is 1 which is always going to be < _FP_W_TYPE_SIZE... \
320 */ \
321 /* _FP_FRAC_SRS_2(R,1,_FP_WFRACBITS_##fs); */ \
322 } while (0)
323
324
325#define _FP_DIV_MEAT_2_gmp(fs, R, X, Y) \
326 do { \
327 _FP_W_TYPE _x[4], _y[2], _z[4]; \
328 _y[0] = Y##_f0; _y[1] = Y##_f1; \
329 _x[0] = _x[3] = 0; \
330 if (_FP_FRAC_GT_2(X, Y)) \
331 { \
332 R##_e++; \
333 _x[1] = (X##_f0 << (_FP_WFRACBITS-1 - _FP_W_TYPE_SIZE) | \
334 X##_f1 >> (_FP_W_TYPE_SIZE - \
335 (_FP_WFRACBITS-1 - _FP_W_TYPE_SIZE))); \
336 _x[2] = X##_f1 << (_FP_WFRACBITS-1 - _FP_W_TYPE_SIZE); \
337 } \
338 else \
339 { \
340 _x[1] = (X##_f0 << (_FP_WFRACBITS - _FP_W_TYPE_SIZE) | \
341 X##_f1 >> (_FP_W_TYPE_SIZE - \
342 (_FP_WFRACBITS - _FP_W_TYPE_SIZE))); \
343 _x[2] = X##_f1 << (_FP_WFRACBITS - _FP_W_TYPE_SIZE); \
344 } \
345 \
346 (void) mpn_divrem (_z, 0, _x, 4, _y, 2); \
347 R##_f1 = _z[1]; \
348 R##_f0 = _z[0] | ((_x[0] | _x[1]) != 0); \
349 } while (0)
350
351
352/*
353 * Square root algorithms:
354 * We have just one right now, maybe Newton approximation
355 * should be added for those machines where division is fast.
356 */
357
358#define _FP_SQRT_MEAT_2(R, S, T, X, q) \
359 do { \
360 while (q) \
361 { \
362 T##_f1 = S##_f1 + q; \
363 if (T##_f1 <= X##_f1) \
364 { \
365 S##_f1 = T##_f1 + q; \
366 X##_f1 -= T##_f1; \
367 R##_f1 += q; \
368 } \
369 _FP_FRAC_SLL_2(X, 1); \
370 q >>= 1; \
371 } \
372 q = (_FP_W_TYPE)1 << (_FP_W_TYPE_SIZE - 1); \
373 while (q) \
374 { \
375 T##_f0 = S##_f0 + q; \
376 T##_f1 = S##_f1; \
377 if (T##_f1 < X##_f1 || \
378 (T##_f1 == X##_f1 && T##_f0 < X##_f0)) \
379 { \
380 S##_f0 = T##_f0 + q; \
381 if (((_FP_WS_TYPE)T##_f0) < 0 && \
382 ((_FP_WS_TYPE)S##_f0) >= 0) \
383 S##_f1++; \
384 _FP_FRAC_SUB_2(X, X, T); \
385 R##_f0 += q; \
386 } \
387 _FP_FRAC_SLL_2(X, 1); \
388 q >>= 1; \
389 } \
390 } while (0)
391
392
393/*
394 * Assembly/disassembly for converting to/from integral types.
395 * No shifting or overflow handled here.
396 */
397
398#define _FP_FRAC_ASSEMBLE_2(r, X, rsize) \
399 do { \
400 if (rsize <= _FP_W_TYPE_SIZE) \
401 r = X##_f0; \
402 else \
403 { \
404 r = X##_f1; \
405 r <<= _FP_W_TYPE_SIZE; \
406 r += X##_f0; \
407 } \
408 } while (0)
409
410#define _FP_FRAC_DISASSEMBLE_2(X, r, rsize) \
411 do { \
412 X##_f0 = r; \
413 X##_f1 = (rsize <= _FP_W_TYPE_SIZE ? 0 : r >> _FP_W_TYPE_SIZE); \
414 } while (0)
415
416/*
417 * Convert FP values between word sizes
418 */
419
420#define _FP_FRAC_CONV_1_2(dfs, sfs, D, S) \
421 do { \
422 _FP_FRAC_SRS_2(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs), \
423 _FP_WFRACBITS_##sfs); \
424 D##_f = S##_f0; \
425 } while (0)
426
427#define _FP_FRAC_CONV_2_1(dfs, sfs, D, S) \
428 do { \
429 D##_f0 = S##_f; \
430 D##_f1 = 0; \
431 _FP_FRAC_SLL_2(D, (_FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs)); \
432 } while (0)
433
diff --git a/arch/powerpc/math-emu/op-4.h b/arch/powerpc/math-emu/op-4.h
new file mode 100644
index 000000000000..fcdd6d064c54
--- /dev/null
+++ b/arch/powerpc/math-emu/op-4.h
@@ -0,0 +1,297 @@
1/*
2 * Basic four-word fraction declaration and manipulation.
3 *
4 * When adding quadword support for 32 bit machines, we need
5 * to be a little careful as double multiply uses some of these
6 * macros: (in op-2.h)
7 * _FP_MUL_MEAT_2_wide() uses _FP_FRAC_DECL_4, _FP_FRAC_WORD_4,
8 * _FP_FRAC_ADD_4, _FP_FRAC_SRS_4
9 * _FP_MUL_MEAT_2_gmp() uses _FP_FRAC_SRS_4 (and should use
10 * _FP_FRAC_DECL_4: it appears to be broken and is not used
11 * anywhere anyway. )
12 *
13 * I've now fixed all the macros that were here from the sparc64 code.
14 * [*none* of the shift macros were correct!] -- PMM 02/1998
15 *
16 * The only quadword stuff that remains to be coded is:
17 * 1) the conversion to/from ints, which requires
18 * that we check (in op-common.h) that the following do the right thing
19 * for quadwords: _FP_TO_INT(Q,4,r,X,rsz,rsg), _FP_FROM_INT(Q,4,X,r,rs,rt)
20 * 2) multiply, divide and sqrt, which require:
21 * _FP_MUL_MEAT_4_*(R,X,Y), _FP_DIV_MEAT_4_*(R,X,Y), _FP_SQRT_MEAT_4(R,S,T,X,q),
22 * This also needs _FP_MUL_MEAT_Q and _FP_DIV_MEAT_Q to be defined to
23 * some suitable _FP_MUL_MEAT_4_* macros in sfp-machine.h.
24 * [we're free to choose whatever FP_MUL_MEAT_4_* macros we need for
25 * these; they are used nowhere else. ]
26 */
27
28#define _FP_FRAC_DECL_4(X) _FP_W_TYPE X##_f[4]
29#define _FP_FRAC_COPY_4(D,S) \
30 (D##_f[0] = S##_f[0], D##_f[1] = S##_f[1], \
31 D##_f[2] = S##_f[2], D##_f[3] = S##_f[3])
32/* The _FP_FRAC_SET_n(X,I) macro is intended for use with another
33 * macro such as _FP_ZEROFRAC_n which returns n comma separated values.
34 * The result is that we get an expansion of __FP_FRAC_SET_n(X,I0,I1,I2,I3)
35 * which just assigns the In values to the array X##_f[].
36 * This is why the number of parameters doesn't appear to match
37 * at first glance... -- PMM
38 */
39#define _FP_FRAC_SET_4(X,I) __FP_FRAC_SET_4(X, I)
40#define _FP_FRAC_HIGH_4(X) (X##_f[3])
41#define _FP_FRAC_LOW_4(X) (X##_f[0])
42#define _FP_FRAC_WORD_4(X,w) (X##_f[w])
43
44#define _FP_FRAC_SLL_4(X,N) \
45 do { \
46 _FP_I_TYPE _up, _down, _skip, _i; \
47 _skip = (N) / _FP_W_TYPE_SIZE; \
48 _up = (N) % _FP_W_TYPE_SIZE; \
49 _down = _FP_W_TYPE_SIZE - _up; \
50 for (_i = 3; _i > _skip; --_i) \
51 X##_f[_i] = X##_f[_i-_skip] << _up | X##_f[_i-_skip-1] >> _down; \
52/* bugfixed: was X##_f[_i] <<= _up; -- PMM 02/1998 */ \
53 X##_f[_i] = X##_f[0] << _up; \
54 for (--_i; _i >= 0; --_i) \
55 X##_f[_i] = 0; \
56 } while (0)
57
58/* This one was broken too */
59#define _FP_FRAC_SRL_4(X,N) \
60 do { \
61 _FP_I_TYPE _up, _down, _skip, _i; \
62 _skip = (N) / _FP_W_TYPE_SIZE; \
63 _down = (N) % _FP_W_TYPE_SIZE; \
64 _up = _FP_W_TYPE_SIZE - _down; \
65 for (_i = 0; _i < 3-_skip; ++_i) \
66 X##_f[_i] = X##_f[_i+_skip] >> _down | X##_f[_i+_skip+1] << _up; \
67 X##_f[_i] = X##_f[3] >> _down; \
68 for (++_i; _i < 4; ++_i) \
69 X##_f[_i] = 0; \
70 } while (0)
71
72
73/* Right shift with sticky-lsb.
74 * What this actually means is that we do a standard right-shift,
75 * but that if any of the bits that fall off the right hand side
76 * were one then we always set the LSbit.
77 */
78#define _FP_FRAC_SRS_4(X,N,size) \
79 do { \
80 _FP_I_TYPE _up, _down, _skip, _i; \
81 _FP_W_TYPE _s; \
82 _skip = (N) / _FP_W_TYPE_SIZE; \
83 _down = (N) % _FP_W_TYPE_SIZE; \
84 _up = _FP_W_TYPE_SIZE - _down; \
85 for (_s = _i = 0; _i < _skip; ++_i) \
86 _s |= X##_f[_i]; \
87 _s |= X##_f[_i] << _up; \
88/* s is now != 0 if we want to set the LSbit */ \
89 for (_i = 0; _i < 3-_skip; ++_i) \
90 X##_f[_i] = X##_f[_i+_skip] >> _down | X##_f[_i+_skip+1] << _up; \
91 X##_f[_i] = X##_f[3] >> _down; \
92 for (++_i; _i < 4; ++_i) \
93 X##_f[_i] = 0; \
94 /* don't fix the LSB until the very end when we're sure f[0] is stable */ \
95 X##_f[0] |= (_s != 0); \
96 } while (0)
97
98#define _FP_FRAC_ADD_4(R,X,Y) \
99 __FP_FRAC_ADD_4(R##_f[3], R##_f[2], R##_f[1], R##_f[0], \
100 X##_f[3], X##_f[2], X##_f[1], X##_f[0], \
101 Y##_f[3], Y##_f[2], Y##_f[1], Y##_f[0])
102
103#define _FP_FRAC_SUB_4(R,X,Y) \
104 __FP_FRAC_SUB_4(R##_f[3], R##_f[2], R##_f[1], R##_f[0], \
105 X##_f[3], X##_f[2], X##_f[1], X##_f[0], \
106 Y##_f[3], Y##_f[2], Y##_f[1], Y##_f[0])
107
108#define _FP_FRAC_ADDI_4(X,I) \
109 __FP_FRAC_ADDI_4(X##_f[3], X##_f[2], X##_f[1], X##_f[0], I)
110
111#define _FP_ZEROFRAC_4 0,0,0,0
112#define _FP_MINFRAC_4 0,0,0,1
113
114#define _FP_FRAC_ZEROP_4(X) ((X##_f[0] | X##_f[1] | X##_f[2] | X##_f[3]) == 0)
115#define _FP_FRAC_NEGP_4(X) ((_FP_WS_TYPE)X##_f[3] < 0)
116#define _FP_FRAC_OVERP_4(fs,X) (X##_f[0] & _FP_OVERFLOW_##fs)
117
118#define _FP_FRAC_EQ_4(X,Y) \
119 (X##_f[0] == Y##_f[0] && X##_f[1] == Y##_f[1] \
120 && X##_f[2] == Y##_f[2] && X##_f[3] == Y##_f[3])
121
122#define _FP_FRAC_GT_4(X,Y) \
123 (X##_f[3] > Y##_f[3] || \
124 (X##_f[3] == Y##_f[3] && (X##_f[2] > Y##_f[2] || \
125 (X##_f[2] == Y##_f[2] && (X##_f[1] > Y##_f[1] || \
126 (X##_f[1] == Y##_f[1] && X##_f[0] > Y##_f[0]) \
127 )) \
128 )) \
129 )
130
131#define _FP_FRAC_GE_4(X,Y) \
132 (X##_f[3] > Y##_f[3] || \
133 (X##_f[3] == Y##_f[3] && (X##_f[2] > Y##_f[2] || \
134 (X##_f[2] == Y##_f[2] && (X##_f[1] > Y##_f[1] || \
135 (X##_f[1] == Y##_f[1] && X##_f[0] >= Y##_f[0]) \
136 )) \
137 )) \
138 )
139
140
141#define _FP_FRAC_CLZ_4(R,X) \
142 do { \
143 if (X##_f[3]) \
144 { \
145 __FP_CLZ(R,X##_f[3]); \
146 } \
147 else if (X##_f[2]) \
148 { \
149 __FP_CLZ(R,X##_f[2]); \
150 R += _FP_W_TYPE_SIZE; \
151 } \
152 else if (X##_f[1]) \
153 { \
154 __FP_CLZ(R,X##_f[2]); \
155 R += _FP_W_TYPE_SIZE*2; \
156 } \
157 else \
158 { \
159 __FP_CLZ(R,X##_f[0]); \
160 R += _FP_W_TYPE_SIZE*3; \
161 } \
162 } while(0)
163
164
165#define _FP_UNPACK_RAW_4(fs, X, val) \
166 do { \
167 union _FP_UNION_##fs _flo; _flo.flt = (val); \
168 X##_f[0] = _flo.bits.frac0; \
169 X##_f[1] = _flo.bits.frac1; \
170 X##_f[2] = _flo.bits.frac2; \
171 X##_f[3] = _flo.bits.frac3; \
172 X##_e = _flo.bits.exp; \
173 X##_s = _flo.bits.sign; \
174 } while (0)
175
176#define _FP_PACK_RAW_4(fs, val, X) \
177 do { \
178 union _FP_UNION_##fs _flo; \
179 _flo.bits.frac0 = X##_f[0]; \
180 _flo.bits.frac1 = X##_f[1]; \
181 _flo.bits.frac2 = X##_f[2]; \
182 _flo.bits.frac3 = X##_f[3]; \
183 _flo.bits.exp = X##_e; \
184 _flo.bits.sign = X##_s; \
185 (val) = _flo.flt; \
186 } while (0)
187
188
189/*
190 * Internals
191 */
192
193#define __FP_FRAC_SET_4(X,I3,I2,I1,I0) \
194 (X##_f[3] = I3, X##_f[2] = I2, X##_f[1] = I1, X##_f[0] = I0)
195
196#ifndef __FP_FRAC_ADD_4
197#define __FP_FRAC_ADD_4(r3,r2,r1,r0,x3,x2,x1,x0,y3,y2,y1,y0) \
198 (r0 = x0 + y0, \
199 r1 = x1 + y1 + (r0 < x0), \
200 r2 = x2 + y2 + (r1 < x1), \
201 r3 = x3 + y3 + (r2 < x2))
202#endif
203
204#ifndef __FP_FRAC_SUB_4
205#define __FP_FRAC_SUB_4(r3,r2,r1,r0,x3,x2,x1,x0,y3,y2,y1,y0) \
206 (r0 = x0 - y0, \
207 r1 = x1 - y1 - (r0 > x0), \
208 r2 = x2 - y2 - (r1 > x1), \
209 r3 = x3 - y3 - (r2 > x2))
210#endif
211
212#ifndef __FP_FRAC_ADDI_4
213/* I always wanted to be a lisp programmer :-> */
214#define __FP_FRAC_ADDI_4(x3,x2,x1,x0,i) \
215 (x3 += ((x2 += ((x1 += ((x0 += i) < x0)) < x1) < x2)))
216#endif
217
218/* Convert FP values between word sizes. This appears to be more
219 * complicated than I'd have expected it to be, so these might be
220 * wrong... These macros are in any case somewhat bogus because they
221 * use information about what various FRAC_n variables look like
222 * internally [eg, that 2 word vars are X_f0 and x_f1]. But so do
223 * the ones in op-2.h and op-1.h.
224 */
225#define _FP_FRAC_CONV_1_4(dfs, sfs, D, S) \
226 do { \
227 _FP_FRAC_SRS_4(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs), \
228 _FP_WFRACBITS_##sfs); \
229 D##_f = S##_f[0]; \
230 } while (0)
231
232#define _FP_FRAC_CONV_2_4(dfs, sfs, D, S) \
233 do { \
234 _FP_FRAC_SRS_4(S, (_FP_WFRACBITS_##sfs - _FP_WFRACBITS_##dfs), \
235 _FP_WFRACBITS_##sfs); \
236 D##_f0 = S##_f[0]; \
237 D##_f1 = S##_f[1]; \
238 } while (0)
239
240/* Assembly/disassembly for converting to/from integral types.
241 * No shifting or overflow handled here.
242 */
243/* Put the FP value X into r, which is an integer of size rsize. */
244#define _FP_FRAC_ASSEMBLE_4(r, X, rsize) \
245 do { \
246 if (rsize <= _FP_W_TYPE_SIZE) \
247 r = X##_f[0]; \
248 else if (rsize <= 2*_FP_W_TYPE_SIZE) \
249 { \
250 r = X##_f[1]; \
251 r <<= _FP_W_TYPE_SIZE; \
252 r += X##_f[0]; \
253 } \
254 else \
255 { \
256 /* I'm feeling lazy so we deal with int == 3words (implausible)*/ \
257 /* and int == 4words as a single case. */ \
258 r = X##_f[3]; \
259 r <<= _FP_W_TYPE_SIZE; \
260 r += X##_f[2]; \
261 r <<= _FP_W_TYPE_SIZE; \
262 r += X##_f[1]; \
263 r <<= _FP_W_TYPE_SIZE; \
264 r += X##_f[0]; \
265 } \
266 } while (0)
267
268/* "No disassemble Number Five!" */
269/* move an integer of size rsize into X's fractional part. We rely on
270 * the _f[] array consisting of words of size _FP_W_TYPE_SIZE to avoid
271 * having to mask the values we store into it.
272 */
273#define _FP_FRAC_DISASSEMBLE_4(X, r, rsize) \
274 do { \
275 X##_f[0] = r; \
276 X##_f[1] = (rsize <= _FP_W_TYPE_SIZE ? 0 : r >> _FP_W_TYPE_SIZE); \
277 X##_f[2] = (rsize <= 2*_FP_W_TYPE_SIZE ? 0 : r >> 2*_FP_W_TYPE_SIZE); \
278 X##_f[3] = (rsize <= 3*_FP_W_TYPE_SIZE ? 0 : r >> 3*_FP_W_TYPE_SIZE); \
279 } while (0)
280
281#define _FP_FRAC_CONV_4_1(dfs, sfs, D, S) \
282 do { \
283 D##_f[0] = S##_f; \
284 D##_f[1] = D##_f[2] = D##_f[3] = 0; \
285 _FP_FRAC_SLL_4(D, (_FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs)); \
286 } while (0)
287
288#define _FP_FRAC_CONV_4_2(dfs, sfs, D, S) \
289 do { \
290 D##_f[0] = S##_f0; \
291 D##_f[1] = S##_f1; \
292 D##_f[2] = D##_f[3] = 0; \
293 _FP_FRAC_SLL_4(D, (_FP_WFRACBITS_##dfs - _FP_WFRACBITS_##sfs)); \
294 } while (0)
295
296/* FIXME! This has to be written */
297#define _FP_SQRT_MEAT_4(R, S, T, X, q)
diff --git a/arch/powerpc/math-emu/op-common.h b/arch/powerpc/math-emu/op-common.h
new file mode 100644
index 000000000000..afb82b6498ce
--- /dev/null
+++ b/arch/powerpc/math-emu/op-common.h
@@ -0,0 +1,688 @@
1#define _FP_DECL(wc, X) \
2 _FP_I_TYPE X##_c, X##_s, X##_e; \
3 _FP_FRAC_DECL_##wc(X)
4
5/*
6 * Finish truely unpacking a native fp value by classifying the kind
7 * of fp value and normalizing both the exponent and the fraction.
8 */
9
10#define _FP_UNPACK_CANONICAL(fs, wc, X) \
11do { \
12 switch (X##_e) \
13 { \
14 default: \
15 _FP_FRAC_HIGH_##wc(X) |= _FP_IMPLBIT_##fs; \
16 _FP_FRAC_SLL_##wc(X, _FP_WORKBITS); \
17 X##_e -= _FP_EXPBIAS_##fs; \
18 X##_c = FP_CLS_NORMAL; \
19 break; \
20 \
21 case 0: \
22 if (_FP_FRAC_ZEROP_##wc(X)) \
23 X##_c = FP_CLS_ZERO; \
24 else \
25 { \
26 /* a denormalized number */ \
27 _FP_I_TYPE _shift; \
28 _FP_FRAC_CLZ_##wc(_shift, X); \
29 _shift -= _FP_FRACXBITS_##fs; \
30 _FP_FRAC_SLL_##wc(X, (_shift+_FP_WORKBITS)); \
31 X##_e -= _FP_EXPBIAS_##fs - 1 + _shift; \
32 X##_c = FP_CLS_NORMAL; \
33 } \
34 break; \
35 \
36 case _FP_EXPMAX_##fs: \
37 if (_FP_FRAC_ZEROP_##wc(X)) \
38 X##_c = FP_CLS_INF; \
39 else \
40 /* we don't differentiate between signaling and quiet nans */ \
41 X##_c = FP_CLS_NAN; \
42 break; \
43 } \
44} while (0)
45
46
47/*
48 * Before packing the bits back into the native fp result, take care
49 * of such mundane things as rounding and overflow. Also, for some
50 * kinds of fp values, the original parts may not have been fully
51 * extracted -- but that is ok, we can regenerate them now.
52 */
53
54#define _FP_PACK_CANONICAL(fs, wc, X) \
55({int __ret = 0; \
56 switch (X##_c) \
57 { \
58 case FP_CLS_NORMAL: \
59 X##_e += _FP_EXPBIAS_##fs; \
60 if (X##_e > 0) \
61 { \
62 __ret |= _FP_ROUND(wc, X); \
63 if (_FP_FRAC_OVERP_##wc(fs, X)) \
64 { \
65 _FP_FRAC_SRL_##wc(X, (_FP_WORKBITS+1)); \
66 X##_e++; \
67 } \
68 else \
69 _FP_FRAC_SRL_##wc(X, _FP_WORKBITS); \
70 if (X##_e >= _FP_EXPMAX_##fs) \
71 { \
72 /* overflow to infinity */ \
73 X##_e = _FP_EXPMAX_##fs; \
74 _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \
75 __ret |= EFLAG_OVERFLOW; \
76 } \
77 } \
78 else \
79 { \
80 /* we've got a denormalized number */ \
81 X##_e = -X##_e + 1; \
82 if (X##_e <= _FP_WFRACBITS_##fs) \
83 { \
84 _FP_FRAC_SRS_##wc(X, X##_e, _FP_WFRACBITS_##fs); \
85 _FP_FRAC_SLL_##wc(X, 1); \
86 if (_FP_FRAC_OVERP_##wc(fs, X)) \
87 { \
88 X##_e = 1; \
89 _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \
90 } \
91 else \
92 { \
93 X##_e = 0; \
94 _FP_FRAC_SRL_##wc(X, _FP_WORKBITS+1); \
95 __ret |= EFLAG_UNDERFLOW; \
96 } \
97 } \
98 else \
99 { \
100 /* underflow to zero */ \
101 X##_e = 0; \
102 _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \
103 __ret |= EFLAG_UNDERFLOW; \
104 } \
105 } \
106 break; \
107 \
108 case FP_CLS_ZERO: \
109 X##_e = 0; \
110 _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \
111 break; \
112 \
113 case FP_CLS_INF: \
114 X##_e = _FP_EXPMAX_##fs; \
115 _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \
116 break; \
117 \
118 case FP_CLS_NAN: \
119 X##_e = _FP_EXPMAX_##fs; \
120 if (!_FP_KEEPNANFRACP) \
121 { \
122 _FP_FRAC_SET_##wc(X, _FP_NANFRAC_##fs); \
123 X##_s = 0; \
124 } \
125 else \
126 _FP_FRAC_HIGH_##wc(X) |= _FP_QNANBIT_##fs; \
127 break; \
128 } \
129 __ret; \
130})
131
132
133/*
134 * Main addition routine. The input values should be cooked.
135 */
136
137#define _FP_ADD(fs, wc, R, X, Y) \
138do { \
139 switch (_FP_CLS_COMBINE(X##_c, Y##_c)) \
140 { \
141 case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL): \
142 { \
143 /* shift the smaller number so that its exponent matches the larger */ \
144 _FP_I_TYPE diff = X##_e - Y##_e; \
145 \
146 if (diff < 0) \
147 { \
148 diff = -diff; \
149 if (diff <= _FP_WFRACBITS_##fs) \
150 _FP_FRAC_SRS_##wc(X, diff, _FP_WFRACBITS_##fs); \
151 else if (!_FP_FRAC_ZEROP_##wc(X)) \
152 _FP_FRAC_SET_##wc(X, _FP_MINFRAC_##wc); \
153 else \
154 _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \
155 R##_e = Y##_e; \
156 } \
157 else \
158 { \
159 if (diff > 0) \
160 { \
161 if (diff <= _FP_WFRACBITS_##fs) \
162 _FP_FRAC_SRS_##wc(Y, diff, _FP_WFRACBITS_##fs); \
163 else if (!_FP_FRAC_ZEROP_##wc(Y)) \
164 _FP_FRAC_SET_##wc(Y, _FP_MINFRAC_##wc); \
165 else \
166 _FP_FRAC_SET_##wc(Y, _FP_ZEROFRAC_##wc); \
167 } \
168 R##_e = X##_e; \
169 } \
170 \
171 R##_c = FP_CLS_NORMAL; \
172 \
173 if (X##_s == Y##_s) \
174 { \
175 R##_s = X##_s; \
176 _FP_FRAC_ADD_##wc(R, X, Y); \
177 if (_FP_FRAC_OVERP_##wc(fs, R)) \
178 { \
179 _FP_FRAC_SRS_##wc(R, 1, _FP_WFRACBITS_##fs); \
180 R##_e++; \
181 } \
182 } \
183 else \
184 { \
185 R##_s = X##_s; \
186 _FP_FRAC_SUB_##wc(R, X, Y); \
187 if (_FP_FRAC_ZEROP_##wc(R)) \
188 { \
189 /* return an exact zero */ \
190 if (FP_ROUNDMODE == FP_RND_MINF) \
191 R##_s |= Y##_s; \
192 else \
193 R##_s &= Y##_s; \
194 R##_c = FP_CLS_ZERO; \
195 } \
196 else \
197 { \
198 if (_FP_FRAC_NEGP_##wc(R)) \
199 { \
200 _FP_FRAC_SUB_##wc(R, Y, X); \
201 R##_s = Y##_s; \
202 } \
203 \
204 /* renormalize after subtraction */ \
205 _FP_FRAC_CLZ_##wc(diff, R); \
206 diff -= _FP_WFRACXBITS_##fs; \
207 if (diff) \
208 { \
209 R##_e -= diff; \
210 _FP_FRAC_SLL_##wc(R, diff); \
211 } \
212 } \
213 } \
214 break; \
215 } \
216 \
217 case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN): \
218 _FP_CHOOSENAN(fs, wc, R, X, Y); \
219 break; \
220 \
221 case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO): \
222 R##_e = X##_e; \
223 case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL): \
224 case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF): \
225 case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO): \
226 _FP_FRAC_COPY_##wc(R, X); \
227 R##_s = X##_s; \
228 R##_c = X##_c; \
229 break; \
230 \
231 case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL): \
232 R##_e = Y##_e; \
233 case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN): \
234 case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN): \
235 case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN): \
236 _FP_FRAC_COPY_##wc(R, Y); \
237 R##_s = Y##_s; \
238 R##_c = Y##_c; \
239 break; \
240 \
241 case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF): \
242 if (X##_s != Y##_s) \
243 { \
244 /* +INF + -INF => NAN */ \
245 _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs); \
246 R##_s = X##_s ^ Y##_s; \
247 R##_c = FP_CLS_NAN; \
248 break; \
249 } \
250 /* FALLTHRU */ \
251 \
252 case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL): \
253 case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO): \
254 R##_s = X##_s; \
255 R##_c = FP_CLS_INF; \
256 break; \
257 \
258 case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF): \
259 case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF): \
260 R##_s = Y##_s; \
261 R##_c = FP_CLS_INF; \
262 break; \
263 \
264 case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO): \
265 /* make sure the sign is correct */ \
266 if (FP_ROUNDMODE == FP_RND_MINF) \
267 R##_s = X##_s | Y##_s; \
268 else \
269 R##_s = X##_s & Y##_s; \
270 R##_c = FP_CLS_ZERO; \
271 break; \
272 \
273 default: \
274 abort(); \
275 } \
276} while (0)
277
278
279/*
280 * Main negation routine. FIXME -- when we care about setting exception
281 * bits reliably, this will not do. We should examine all of the fp classes.
282 */
283
284#define _FP_NEG(fs, wc, R, X) \
285 do { \
286 _FP_FRAC_COPY_##wc(R, X); \
287 R##_c = X##_c; \
288 R##_e = X##_e; \
289 R##_s = 1 ^ X##_s; \
290 } while (0)
291
292
293/*
294 * Main multiplication routine. The input values should be cooked.
295 */
296
297#define _FP_MUL(fs, wc, R, X, Y) \
298do { \
299 R##_s = X##_s ^ Y##_s; \
300 switch (_FP_CLS_COMBINE(X##_c, Y##_c)) \
301 { \
302 case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL): \
303 R##_c = FP_CLS_NORMAL; \
304 R##_e = X##_e + Y##_e + 1; \
305 \
306 _FP_MUL_MEAT_##fs(R,X,Y); \
307 \
308 if (_FP_FRAC_OVERP_##wc(fs, R)) \
309 _FP_FRAC_SRS_##wc(R, 1, _FP_WFRACBITS_##fs); \
310 else \
311 R##_e--; \
312 break; \
313 \
314 case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN): \
315 _FP_CHOOSENAN(fs, wc, R, X, Y); \
316 break; \
317 \
318 case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL): \
319 case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF): \
320 case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO): \
321 R##_s = X##_s; \
322 \
323 case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF): \
324 case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL): \
325 case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL): \
326 case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO): \
327 _FP_FRAC_COPY_##wc(R, X); \
328 R##_c = X##_c; \
329 break; \
330 \
331 case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN): \
332 case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN): \
333 case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN): \
334 R##_s = Y##_s; \
335 \
336 case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF): \
337 case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO): \
338 _FP_FRAC_COPY_##wc(R, Y); \
339 R##_c = Y##_c; \
340 break; \
341 \
342 case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO): \
343 case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF): \
344 R##_c = FP_CLS_NAN; \
345 _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs); \
346 break; \
347 \
348 default: \
349 abort(); \
350 } \
351} while (0)
352
353
354/*
355 * Main division routine. The input values should be cooked.
356 */
357
358#define _FP_DIV(fs, wc, R, X, Y) \
359do { \
360 R##_s = X##_s ^ Y##_s; \
361 switch (_FP_CLS_COMBINE(X##_c, Y##_c)) \
362 { \
363 case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NORMAL): \
364 R##_c = FP_CLS_NORMAL; \
365 R##_e = X##_e - Y##_e; \
366 \
367 _FP_DIV_MEAT_##fs(R,X,Y); \
368 break; \
369 \
370 case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NAN): \
371 _FP_CHOOSENAN(fs, wc, R, X, Y); \
372 break; \
373 \
374 case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_NORMAL): \
375 case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_INF): \
376 case _FP_CLS_COMBINE(FP_CLS_NAN,FP_CLS_ZERO): \
377 R##_s = X##_s; \
378 _FP_FRAC_COPY_##wc(R, X); \
379 R##_c = X##_c; \
380 break; \
381 \
382 case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_NAN): \
383 case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NAN): \
384 case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NAN): \
385 R##_s = Y##_s; \
386 _FP_FRAC_COPY_##wc(R, Y); \
387 R##_c = Y##_c; \
388 break; \
389 \
390 case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_INF): \
391 case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_INF): \
392 case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_NORMAL): \
393 R##_c = FP_CLS_ZERO; \
394 break; \
395 \
396 case _FP_CLS_COMBINE(FP_CLS_NORMAL,FP_CLS_ZERO): \
397 case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_ZERO): \
398 case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_NORMAL): \
399 R##_c = FP_CLS_INF; \
400 break; \
401 \
402 case _FP_CLS_COMBINE(FP_CLS_INF,FP_CLS_INF): \
403 case _FP_CLS_COMBINE(FP_CLS_ZERO,FP_CLS_ZERO): \
404 R##_c = FP_CLS_NAN; \
405 _FP_FRAC_SET_##wc(R, _FP_NANFRAC_##fs); \
406 break; \
407 \
408 default: \
409 abort(); \
410 } \
411} while (0)
412
413
414/*
415 * Main differential comparison routine. The inputs should be raw not
416 * cooked. The return is -1,0,1 for normal values, 2 otherwise.
417 */
418
419#define _FP_CMP(fs, wc, ret, X, Y, un) \
420 do { \
421 /* NANs are unordered */ \
422 if ((X##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(X)) \
423 || (Y##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(Y))) \
424 { \
425 ret = un; \
426 } \
427 else \
428 { \
429 int __x_zero = (!X##_e && _FP_FRAC_ZEROP_##wc(X)) ? 1 : 0; \
430 int __y_zero = (!Y##_e && _FP_FRAC_ZEROP_##wc(Y)) ? 1 : 0; \
431 \
432 if (__x_zero && __y_zero) \
433 ret = 0; \
434 else if (__x_zero) \
435 ret = Y##_s ? 1 : -1; \
436 else if (__y_zero) \
437 ret = X##_s ? -1 : 1; \
438 else if (X##_s != Y##_s) \
439 ret = X##_s ? -1 : 1; \
440 else if (X##_e > Y##_e) \
441 ret = X##_s ? -1 : 1; \
442 else if (X##_e < Y##_e) \
443 ret = X##_s ? 1 : -1; \
444 else if (_FP_FRAC_GT_##wc(X, Y)) \
445 ret = X##_s ? -1 : 1; \
446 else if (_FP_FRAC_GT_##wc(Y, X)) \
447 ret = X##_s ? 1 : -1; \
448 else \
449 ret = 0; \
450 } \
451 } while (0)
452
453
454/* Simplification for strict equality. */
455
456#define _FP_CMP_EQ(fs, wc, ret, X, Y) \
457 do { \
458 /* NANs are unordered */ \
459 if ((X##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(X)) \
460 || (Y##_e == _FP_EXPMAX_##fs && !_FP_FRAC_ZEROP_##wc(Y))) \
461 { \
462 ret = 1; \
463 } \
464 else \
465 { \
466 ret = !(X##_e == Y##_e \
467 && _FP_FRAC_EQ_##wc(X, Y) \
468 && (X##_s == Y##_s || !X##_e && _FP_FRAC_ZEROP_##wc(X))); \
469 } \
470 } while (0)
471
472/*
473 * Main square root routine. The input value should be cooked.
474 */
475
476#define _FP_SQRT(fs, wc, R, X) \
477do { \
478 _FP_FRAC_DECL_##wc(T); _FP_FRAC_DECL_##wc(S); \
479 _FP_W_TYPE q; \
480 switch (X##_c) \
481 { \
482 case FP_CLS_NAN: \
483 R##_s = 0; \
484 R##_c = FP_CLS_NAN; \
485 _FP_FRAC_SET_##wc(X, _FP_ZEROFRAC_##wc); \
486 break; \
487 case FP_CLS_INF: \
488 if (X##_s) \
489 { \
490 R##_s = 0; \
491 R##_c = FP_CLS_NAN; /* sNAN */ \
492 } \
493 else \
494 { \
495 R##_s = 0; \
496 R##_c = FP_CLS_INF; /* sqrt(+inf) = +inf */ \
497 } \
498 break; \
499 case FP_CLS_ZERO: \
500 R##_s = X##_s; \
501 R##_c = FP_CLS_ZERO; /* sqrt(+-0) = +-0 */ \
502 break; \
503 case FP_CLS_NORMAL: \
504 R##_s = 0; \
505 if (X##_s) \
506 { \
507 R##_c = FP_CLS_NAN; /* sNAN */ \
508 break; \
509 } \
510 R##_c = FP_CLS_NORMAL; \
511 if (X##_e & 1) \
512 _FP_FRAC_SLL_##wc(X, 1); \
513 R##_e = X##_e >> 1; \
514 _FP_FRAC_SET_##wc(S, _FP_ZEROFRAC_##wc); \
515 _FP_FRAC_SET_##wc(R, _FP_ZEROFRAC_##wc); \
516 q = _FP_OVERFLOW_##fs; \
517 _FP_FRAC_SLL_##wc(X, 1); \
518 _FP_SQRT_MEAT_##wc(R, S, T, X, q); \
519 _FP_FRAC_SRL_##wc(R, 1); \
520 } \
521 } while (0)
522
523/*
524 * Convert from FP to integer
525 */
526
527/* "When a NaN, infinity, large positive argument >= 2147483648.0, or
528 * large negative argument <= -2147483649.0 is converted to an integer,
529 * the invalid_current bit...should be set and fp_exception_IEEE_754 should
530 * be raised. If the floating point invalid trap is disabled, no trap occurs
531 * and a numerical result is generated: if the sign bit of the operand
532 * is 0, the result is 2147483647; if the sign bit of the operand is 1,
533 * the result is -2147483648."
534 * Similarly for conversion to extended ints, except that the boundaries
535 * are >= 2^63, <= -(2^63 + 1), and the results are 2^63 + 1 for s=0 and
536 * -2^63 for s=1.
537 * -- SPARC Architecture Manual V9, Appendix B, which specifies how
538 * SPARCs resolve implementation dependencies in the IEEE-754 spec.
539 * I don't believe that the code below follows this. I'm not even sure
540 * it's right!
541 * It doesn't cope with needing to convert to an n bit integer when there
542 * is no n bit integer type. Fortunately gcc provides long long so this
543 * isn't a problem for sparc32.
544 * I have, however, fixed its NaN handling to conform as above.
545 * -- PMM 02/1998
546 * NB: rsigned is not 'is r declared signed?' but 'should the value stored
547 * in r be signed or unsigned?'. r is always(?) declared unsigned.
548 * Comments below are mine, BTW -- PMM
549 */
550#define _FP_TO_INT(fs, wc, r, X, rsize, rsigned) \
551 do { \
552 switch (X##_c) \
553 { \
554 case FP_CLS_NORMAL: \
555 if (X##_e < 0) \
556 { \
557 /* case FP_CLS_NAN: see above! */ \
558 case FP_CLS_ZERO: \
559 r = 0; \
560 } \
561 else if (X##_e >= rsize - (rsigned != 0)) \
562 { /* overflow */ \
563 case FP_CLS_NAN: \
564 case FP_CLS_INF: \
565 if (rsigned) \
566 { \
567 r = 1; \
568 r <<= rsize - 1; \
569 r -= 1 - X##_s; \
570 } \
571 else \
572 { \
573 r = 0; \
574 if (!X##_s) \
575 r = ~r; \
576 } \
577 } \
578 else \
579 { \
580 if (_FP_W_TYPE_SIZE*wc < rsize) \
581 { \
582 _FP_FRAC_ASSEMBLE_##wc(r, X, rsize); \
583 r <<= X##_e - _FP_WFRACBITS_##fs; \
584 } \
585 else \
586 { \
587 if (X##_e >= _FP_WFRACBITS_##fs) \
588 _FP_FRAC_SLL_##wc(X, (X##_e - _FP_WFRACBITS_##fs + 1));\
589 else \
590 _FP_FRAC_SRL_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 1));\
591 _FP_FRAC_ASSEMBLE_##wc(r, X, rsize); \
592 } \
593 if (rsigned && X##_s) \
594 r = -r; \
595 } \
596 break; \
597 } \
598 } while (0)
599
600#define _FP_FROM_INT(fs, wc, X, r, rsize, rtype) \
601 do { \
602 if (r) \
603 { \
604 X##_c = FP_CLS_NORMAL; \
605 \
606 if ((X##_s = (r < 0))) \
607 r = -r; \
608 /* Note that `r' is now considered unsigned, so we don't have \
609 to worry about the single signed overflow case. */ \
610 \
611 if (rsize <= _FP_W_TYPE_SIZE) \
612 __FP_CLZ(X##_e, r); \
613 else \
614 __FP_CLZ_2(X##_e, (_FP_W_TYPE)(r >> _FP_W_TYPE_SIZE), \
615 (_FP_W_TYPE)r); \
616 if (rsize < _FP_W_TYPE_SIZE) \
617 X##_e -= (_FP_W_TYPE_SIZE - rsize); \
618 X##_e = rsize - X##_e - 1; \
619 \
620 if (_FP_FRACBITS_##fs < rsize && _FP_WFRACBITS_##fs < X##_e) \
621 __FP_FRAC_SRS_1(r, (X##_e - _FP_WFRACBITS_##fs), rsize); \
622 r &= ~((_FP_W_TYPE)1 << X##_e); \
623 _FP_FRAC_DISASSEMBLE_##wc(X, ((unsigned rtype)r), rsize); \
624 _FP_FRAC_SLL_##wc(X, (_FP_WFRACBITS_##fs - X##_e - 1)); \
625 } \
626 else \
627 { \
628 X##_c = FP_CLS_ZERO, X##_s = 0; \
629 } \
630 } while (0)
631
632
633#define FP_CONV(dfs,sfs,dwc,swc,D,S) \
634 do { \
635 _FP_FRAC_CONV_##dwc##_##swc(dfs, sfs, D, S); \
636 D##_e = S##_e; \
637 D##_c = S##_c; \
638 D##_s = S##_s; \
639 } while (0)
640
641/*
642 * Helper primitives.
643 */
644
645/* Count leading zeros in a word. */
646
647#ifndef __FP_CLZ
648#if _FP_W_TYPE_SIZE < 64
649/* this is just to shut the compiler up about shifts > word length -- PMM 02/1998 */
650#define __FP_CLZ(r, x) \
651 do { \
652 _FP_W_TYPE _t = (x); \
653 r = _FP_W_TYPE_SIZE - 1; \
654 if (_t > 0xffff) r -= 16; \
655 if (_t > 0xffff) _t >>= 16; \
656 if (_t > 0xff) r -= 8; \
657 if (_t > 0xff) _t >>= 8; \
658 if (_t & 0xf0) r -= 4; \
659 if (_t & 0xf0) _t >>= 4; \
660 if (_t & 0xc) r -= 2; \
661 if (_t & 0xc) _t >>= 2; \
662 if (_t & 0x2) r -= 1; \
663 } while (0)
664#else /* not _FP_W_TYPE_SIZE < 64 */
665#define __FP_CLZ(r, x) \
666 do { \
667 _FP_W_TYPE _t = (x); \
668 r = _FP_W_TYPE_SIZE - 1; \
669 if (_t > 0xffffffff) r -= 32; \
670 if (_t > 0xffffffff) _t >>= 32; \
671 if (_t > 0xffff) r -= 16; \
672 if (_t > 0xffff) _t >>= 16; \
673 if (_t > 0xff) r -= 8; \
674 if (_t > 0xff) _t >>= 8; \
675 if (_t & 0xf0) r -= 4; \
676 if (_t & 0xf0) _t >>= 4; \
677 if (_t & 0xc) r -= 2; \
678 if (_t & 0xc) _t >>= 2; \
679 if (_t & 0x2) r -= 1; \
680 } while (0)
681#endif /* not _FP_W_TYPE_SIZE < 64 */
682#endif /* ndef __FP_CLZ */
683
684#define _FP_DIV_HELP_imm(q, r, n, d) \
685 do { \
686 q = n / d, r = n % d; \
687 } while (0)
688
diff --git a/arch/powerpc/math-emu/sfp-machine.h b/arch/powerpc/math-emu/sfp-machine.h
new file mode 100644
index 000000000000..4b17d83cfcdd
--- /dev/null
+++ b/arch/powerpc/math-emu/sfp-machine.h
@@ -0,0 +1,377 @@
1/* Machine-dependent software floating-point definitions. PPC version.
2 Copyright (C) 1997 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with the GNU C Library; see the file COPYING.LIB. If
17 not, write to the Free Software Foundation, Inc.,
18 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
20 Actually, this is a PPC (32bit) version, written based on the
21 i386, sparc, and sparc64 versions, by me,
22 Peter Maydell (pmaydell@chiark.greenend.org.uk).
23 Comments are by and large also mine, although they may be inaccurate.
24
25 In picking out asm fragments I've gone with the lowest common
26 denominator, which also happens to be the hardware I have :->
27 That is, a SPARC without hardware multiply and divide.
28 */
29
30/* basic word size definitions */
31#define _FP_W_TYPE_SIZE 32
32#define _FP_W_TYPE unsigned long
33#define _FP_WS_TYPE signed long
34#define _FP_I_TYPE long
35
36#define __ll_B ((UWtype) 1 << (W_TYPE_SIZE / 2))
37#define __ll_lowpart(t) ((UWtype) (t) & (__ll_B - 1))
38#define __ll_highpart(t) ((UWtype) (t) >> (W_TYPE_SIZE / 2))
39
40/* You can optionally code some things like addition in asm. For
41 * example, i386 defines __FP_FRAC_ADD_2 as asm. If you don't
42 * then you get a fragment of C code [if you change an #ifdef 0
43 * in op-2.h] or a call to add_ssaaaa (see below).
44 * Good places to look for asm fragments to use are gcc and glibc.
45 * gcc's longlong.h is useful.
46 */
47
48/* We need to know how to multiply and divide. If the host word size
49 * is >= 2*fracbits you can use FP_MUL_MEAT_n_imm(t,R,X,Y) which
50 * codes the multiply with whatever gcc does to 'a * b'.
51 * _FP_MUL_MEAT_n_wide(t,R,X,Y,f) is used when you have an asm
52 * function that can multiply two 1W values and get a 2W result.
53 * Otherwise you're stuck with _FP_MUL_MEAT_n_hard(t,R,X,Y) which
54 * does bitshifting to avoid overflow.
55 * For division there is FP_DIV_MEAT_n_imm(t,R,X,Y,f) for word size
56 * >= 2*fracbits, where f is either _FP_DIV_HELP_imm or
57 * _FP_DIV_HELP_ldiv (see op-1.h).
58 * _FP_DIV_MEAT_udiv() is if you have asm to do 2W/1W => (1W, 1W).
59 * [GCC and glibc have longlong.h which has the asm macro udiv_qrnnd
60 * to do this.]
61 * In general, 'n' is the number of words required to hold the type,
62 * and 't' is either S, D or Q for single/double/quad.
63 * -- PMM
64 */
65/* Example: SPARC64:
66 * #define _FP_MUL_MEAT_S(R,X,Y) _FP_MUL_MEAT_1_imm(S,R,X,Y)
67 * #define _FP_MUL_MEAT_D(R,X,Y) _FP_MUL_MEAT_1_wide(D,R,X,Y,umul_ppmm)
68 * #define _FP_MUL_MEAT_Q(R,X,Y) _FP_MUL_MEAT_2_wide(Q,R,X,Y,umul_ppmm)
69 *
70 * #define _FP_DIV_MEAT_S(R,X,Y) _FP_DIV_MEAT_1_imm(S,R,X,Y,_FP_DIV_HELP_imm)
71 * #define _FP_DIV_MEAT_D(R,X,Y) _FP_DIV_MEAT_1_udiv(D,R,X,Y)
72 * #define _FP_DIV_MEAT_Q(R,X,Y) _FP_DIV_MEAT_2_udiv_64(Q,R,X,Y)
73 *
74 * Example: i386:
75 * #define _FP_MUL_MEAT_S(R,X,Y) _FP_MUL_MEAT_1_wide(S,R,X,Y,_i386_mul_32_64)
76 * #define _FP_MUL_MEAT_D(R,X,Y) _FP_MUL_MEAT_2_wide(D,R,X,Y,_i386_mul_32_64)
77 *
78 * #define _FP_DIV_MEAT_S(R,X,Y) _FP_DIV_MEAT_1_udiv(S,R,X,Y,_i386_div_64_32)
79 * #define _FP_DIV_MEAT_D(R,X,Y) _FP_DIV_MEAT_2_udiv_64(D,R,X,Y)
80 */
81
82#define _FP_MUL_MEAT_S(R,X,Y) _FP_MUL_MEAT_1_wide(S,R,X,Y,umul_ppmm)
83#define _FP_MUL_MEAT_D(R,X,Y) _FP_MUL_MEAT_2_wide(D,R,X,Y,umul_ppmm)
84
85#define _FP_DIV_MEAT_S(R,X,Y) _FP_DIV_MEAT_1_udiv(S,R,X,Y)
86#define _FP_DIV_MEAT_D(R,X,Y) _FP_DIV_MEAT_2_udiv_64(D,R,X,Y)
87
88/* These macros define what NaN looks like. They're supposed to expand to
89 * a comma-separated set of 32bit unsigned ints that encode NaN.
90 */
91#define _FP_NANFRAC_S _FP_QNANBIT_S
92#define _FP_NANFRAC_D _FP_QNANBIT_D, 0
93#define _FP_NANFRAC_Q _FP_QNANBIT_Q, 0, 0, 0
94
95#define _FP_KEEPNANFRACP 1
96
97/* This macro appears to be called when both X and Y are NaNs, and
98 * has to choose one and copy it to R. i386 goes for the larger of the
99 * two, sparc64 just picks Y. I don't understand this at all so I'll
100 * go with sparc64 because it's shorter :-> -- PMM
101 */
102#define _FP_CHOOSENAN(fs, wc, R, X, Y) \
103 do { \
104 R##_s = Y##_s; \
105 _FP_FRAC_COPY_##wc(R,Y); \
106 R##_c = FP_CLS_NAN; \
107 } while (0)
108
109
110extern void fp_unpack_d(long *, unsigned long *, unsigned long *,
111 long *, long *, void *);
112extern int fp_pack_d(void *, long, unsigned long, unsigned long, long, long);
113extern int fp_pack_ds(void *, long, unsigned long, unsigned long, long, long);
114
115#define __FP_UNPACK_RAW_1(fs, X, val) \
116 do { \
117 union _FP_UNION_##fs *_flo = \
118 (union _FP_UNION_##fs *)val; \
119 \
120 X##_f = _flo->bits.frac; \
121 X##_e = _flo->bits.exp; \
122 X##_s = _flo->bits.sign; \
123 } while (0)
124
125#define __FP_UNPACK_RAW_2(fs, X, val) \
126 do { \
127 union _FP_UNION_##fs *_flo = \
128 (union _FP_UNION_##fs *)val; \
129 \
130 X##_f0 = _flo->bits.frac0; \
131 X##_f1 = _flo->bits.frac1; \
132 X##_e = _flo->bits.exp; \
133 X##_s = _flo->bits.sign; \
134 } while (0)
135
136#define __FP_UNPACK_S(X,val) \
137 do { \
138 __FP_UNPACK_RAW_1(S,X,val); \
139 _FP_UNPACK_CANONICAL(S,1,X); \
140 } while (0)
141
142#define __FP_UNPACK_D(X,val) \
143 fp_unpack_d(&X##_s, &X##_f1, &X##_f0, &X##_e, &X##_c, val)
144
145#define __FP_PACK_RAW_1(fs, val, X) \
146 do { \
147 union _FP_UNION_##fs *_flo = \
148 (union _FP_UNION_##fs *)val; \
149 \
150 _flo->bits.frac = X##_f; \
151 _flo->bits.exp = X##_e; \
152 _flo->bits.sign = X##_s; \
153 } while (0)
154
155#define __FP_PACK_RAW_2(fs, val, X) \
156 do { \
157 union _FP_UNION_##fs *_flo = \
158 (union _FP_UNION_##fs *)val; \
159 \
160 _flo->bits.frac0 = X##_f0; \
161 _flo->bits.frac1 = X##_f1; \
162 _flo->bits.exp = X##_e; \
163 _flo->bits.sign = X##_s; \
164 } while (0)
165
166#include <linux/kernel.h>
167#include <linux/sched.h>
168
169#define __FPU_FPSCR (current->thread.fpscr.val)
170
171/* We only actually write to the destination register
172 * if exceptions signalled (if any) will not trap.
173 */
174#define __FPU_ENABLED_EXC \
175({ \
176 (__FPU_FPSCR >> 3) & 0x1f; \
177})
178
179#define __FPU_TRAP_P(bits) \
180 ((__FPU_ENABLED_EXC & (bits)) != 0)
181
182#define __FP_PACK_S(val,X) \
183({ int __exc = _FP_PACK_CANONICAL(S,1,X); \
184 if(!__exc || !__FPU_TRAP_P(__exc)) \
185 __FP_PACK_RAW_1(S,val,X); \
186 __exc; \
187})
188
189#define __FP_PACK_D(val,X) \
190 fp_pack_d(val, X##_s, X##_f1, X##_f0, X##_e, X##_c)
191
192#define __FP_PACK_DS(val,X) \
193 fp_pack_ds(val, X##_s, X##_f1, X##_f0, X##_e, X##_c)
194
195/* Obtain the current rounding mode. */
196#define FP_ROUNDMODE \
197({ \
198 __FPU_FPSCR & 0x3; \
199})
200
201/* the asm fragments go here: all these are taken from glibc-2.0.5's
202 * stdlib/longlong.h
203 */
204
205#include <linux/types.h>
206#include <asm/byteorder.h>
207
208/* add_ssaaaa is used in op-2.h and should be equivalent to
209 * #define add_ssaaaa(sh,sl,ah,al,bh,bl) (sh = ah+bh+ (( sl = al+bl) < al))
210 * add_ssaaaa(high_sum, low_sum, high_addend_1, low_addend_1,
211 * high_addend_2, low_addend_2) adds two UWtype integers, composed by
212 * HIGH_ADDEND_1 and LOW_ADDEND_1, and HIGH_ADDEND_2 and LOW_ADDEND_2
213 * respectively. The result is placed in HIGH_SUM and LOW_SUM. Overflow
214 * (i.e. carry out) is not stored anywhere, and is lost.
215 */
216#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
217 do { \
218 if (__builtin_constant_p (bh) && (bh) == 0) \
219 __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{aze|addze} %0,%2" \
220 : "=r" ((USItype)(sh)), \
221 "=&r" ((USItype)(sl)) \
222 : "%r" ((USItype)(ah)), \
223 "%r" ((USItype)(al)), \
224 "rI" ((USItype)(bl))); \
225 else if (__builtin_constant_p (bh) && (bh) ==~(USItype) 0) \
226 __asm__ ("{a%I4|add%I4c} %1,%3,%4\n\t{ame|addme} %0,%2" \
227 : "=r" ((USItype)(sh)), \
228 "=&r" ((USItype)(sl)) \
229 : "%r" ((USItype)(ah)), \
230 "%r" ((USItype)(al)), \
231 "rI" ((USItype)(bl))); \
232 else \
233 __asm__ ("{a%I5|add%I5c} %1,%4,%5\n\t{ae|adde} %0,%2,%3" \
234 : "=r" ((USItype)(sh)), \
235 "=&r" ((USItype)(sl)) \
236 : "%r" ((USItype)(ah)), \
237 "r" ((USItype)(bh)), \
238 "%r" ((USItype)(al)), \
239 "rI" ((USItype)(bl))); \
240 } while (0)
241
242/* sub_ddmmss is used in op-2.h and udivmodti4.c and should be equivalent to
243 * #define sub_ddmmss(sh, sl, ah, al, bh, bl) (sh = ah-bh - ((sl = al-bl) > al))
244 * sub_ddmmss(high_difference, low_difference, high_minuend, low_minuend,
245 * high_subtrahend, low_subtrahend) subtracts two two-word UWtype integers,
246 * composed by HIGH_MINUEND_1 and LOW_MINUEND_1, and HIGH_SUBTRAHEND_2 and
247 * LOW_SUBTRAHEND_2 respectively. The result is placed in HIGH_DIFFERENCE
248 * and LOW_DIFFERENCE. Overflow (i.e. carry out) is not stored anywhere,
249 * and is lost.
250 */
251#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
252 do { \
253 if (__builtin_constant_p (ah) && (ah) == 0) \
254 __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfze|subfze} %0,%2" \
255 : "=r" ((USItype)(sh)), \
256 "=&r" ((USItype)(sl)) \
257 : "r" ((USItype)(bh)), \
258 "rI" ((USItype)(al)), \
259 "r" ((USItype)(bl))); \
260 else if (__builtin_constant_p (ah) && (ah) ==~(USItype) 0) \
261 __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{sfme|subfme} %0,%2" \
262 : "=r" ((USItype)(sh)), \
263 "=&r" ((USItype)(sl)) \
264 : "r" ((USItype)(bh)), \
265 "rI" ((USItype)(al)), \
266 "r" ((USItype)(bl))); \
267 else if (__builtin_constant_p (bh) && (bh) == 0) \
268 __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{ame|addme} %0,%2" \
269 : "=r" ((USItype)(sh)), \
270 "=&r" ((USItype)(sl)) \
271 : "r" ((USItype)(ah)), \
272 "rI" ((USItype)(al)), \
273 "r" ((USItype)(bl))); \
274 else if (__builtin_constant_p (bh) && (bh) ==~(USItype) 0) \
275 __asm__ ("{sf%I3|subf%I3c} %1,%4,%3\n\t{aze|addze} %0,%2" \
276 : "=r" ((USItype)(sh)), \
277 "=&r" ((USItype)(sl)) \
278 : "r" ((USItype)(ah)), \
279 "rI" ((USItype)(al)), \
280 "r" ((USItype)(bl))); \
281 else \
282 __asm__ ("{sf%I4|subf%I4c} %1,%5,%4\n\t{sfe|subfe} %0,%3,%2" \
283 : "=r" ((USItype)(sh)), \
284 "=&r" ((USItype)(sl)) \
285 : "r" ((USItype)(ah)), \
286 "r" ((USItype)(bh)), \
287 "rI" ((USItype)(al)), \
288 "r" ((USItype)(bl))); \
289 } while (0)
290
291/* asm fragments for mul and div */
292
293/* umul_ppmm(high_prod, low_prod, multipler, multiplicand) multiplies two
294 * UWtype integers MULTIPLER and MULTIPLICAND, and generates a two UWtype
295 * word product in HIGH_PROD and LOW_PROD.
296 */
297#define umul_ppmm(ph, pl, m0, m1) \
298 do { \
299 USItype __m0 = (m0), __m1 = (m1); \
300 __asm__ ("mulhwu %0,%1,%2" \
301 : "=r" ((USItype)(ph)) \
302 : "%r" (__m0), \
303 "r" (__m1)); \
304 (pl) = __m0 * __m1; \
305 } while (0)
306
307/* udiv_qrnnd(quotient, remainder, high_numerator, low_numerator,
308 * denominator) divides a UDWtype, composed by the UWtype integers
309 * HIGH_NUMERATOR and LOW_NUMERATOR, by DENOMINATOR and places the quotient
310 * in QUOTIENT and the remainder in REMAINDER. HIGH_NUMERATOR must be less
311 * than DENOMINATOR for correct operation. If, in addition, the most
312 * significant bit of DENOMINATOR must be 1, then the pre-processor symbol
313 * UDIV_NEEDS_NORMALIZATION is defined to 1.
314 */
315#define udiv_qrnnd(q, r, n1, n0, d) \
316 do { \
317 UWtype __d1, __d0, __q1, __q0, __r1, __r0, __m; \
318 __d1 = __ll_highpart (d); \
319 __d0 = __ll_lowpart (d); \
320 \
321 __r1 = (n1) % __d1; \
322 __q1 = (n1) / __d1; \
323 __m = (UWtype) __q1 * __d0; \
324 __r1 = __r1 * __ll_B | __ll_highpart (n0); \
325 if (__r1 < __m) \
326 { \
327 __q1--, __r1 += (d); \
328 if (__r1 >= (d)) /* we didn't get carry when adding to __r1 */ \
329 if (__r1 < __m) \
330 __q1--, __r1 += (d); \
331 } \
332 __r1 -= __m; \
333 \
334 __r0 = __r1 % __d1; \
335 __q0 = __r1 / __d1; \
336 __m = (UWtype) __q0 * __d0; \
337 __r0 = __r0 * __ll_B | __ll_lowpart (n0); \
338 if (__r0 < __m) \
339 { \
340 __q0--, __r0 += (d); \
341 if (__r0 >= (d)) \
342 if (__r0 < __m) \
343 __q0--, __r0 += (d); \
344 } \
345 __r0 -= __m; \
346 \
347 (q) = (UWtype) __q1 * __ll_B | __q0; \
348 (r) = __r0; \
349 } while (0)
350
351#define UDIV_NEEDS_NORMALIZATION 1
352
353#define abort() \
354 return 0
355
356#ifdef __BIG_ENDIAN
357#define __BYTE_ORDER __BIG_ENDIAN
358#else
359#define __BYTE_ORDER __LITTLE_ENDIAN
360#endif
361
362/* Exception flags. */
363#define EFLAG_INVALID (1 << (31 - 2))
364#define EFLAG_OVERFLOW (1 << (31 - 3))
365#define EFLAG_UNDERFLOW (1 << (31 - 4))
366#define EFLAG_DIVZERO (1 << (31 - 5))
367#define EFLAG_INEXACT (1 << (31 - 6))
368
369#define EFLAG_VXSNAN (1 << (31 - 7))
370#define EFLAG_VXISI (1 << (31 - 8))
371#define EFLAG_VXIDI (1 << (31 - 9))
372#define EFLAG_VXZDZ (1 << (31 - 10))
373#define EFLAG_VXIMZ (1 << (31 - 11))
374#define EFLAG_VXVC (1 << (31 - 12))
375#define EFLAG_VXSOFT (1 << (31 - 21))
376#define EFLAG_VXSQRT (1 << (31 - 22))
377#define EFLAG_VXCVI (1 << (31 - 23))
diff --git a/arch/powerpc/math-emu/single.h b/arch/powerpc/math-emu/single.h
new file mode 100644
index 000000000000..f19d99451815
--- /dev/null
+++ b/arch/powerpc/math-emu/single.h
@@ -0,0 +1,66 @@
1/*
2 * Definitions for IEEE Single Precision
3 */
4
5#if _FP_W_TYPE_SIZE < 32
6#error "Here's a nickel kid. Go buy yourself a real computer."
7#endif
8
9#define _FP_FRACBITS_S 24
10#define _FP_FRACXBITS_S (_FP_W_TYPE_SIZE - _FP_FRACBITS_S)
11#define _FP_WFRACBITS_S (_FP_WORKBITS + _FP_FRACBITS_S)
12#define _FP_WFRACXBITS_S (_FP_W_TYPE_SIZE - _FP_WFRACBITS_S)
13#define _FP_EXPBITS_S 8
14#define _FP_EXPBIAS_S 127
15#define _FP_EXPMAX_S 255
16#define _FP_QNANBIT_S ((_FP_W_TYPE)1 << (_FP_FRACBITS_S-2))
17#define _FP_IMPLBIT_S ((_FP_W_TYPE)1 << (_FP_FRACBITS_S-1))
18#define _FP_OVERFLOW_S ((_FP_W_TYPE)1 << (_FP_WFRACBITS_S))
19
20/* The implementation of _FP_MUL_MEAT_S and _FP_DIV_MEAT_S should be
21 chosen by the target machine. */
22
23union _FP_UNION_S
24{
25 float flt;
26 struct {
27#if __BYTE_ORDER == __BIG_ENDIAN
28 unsigned sign : 1;
29 unsigned exp : _FP_EXPBITS_S;
30 unsigned frac : _FP_FRACBITS_S - (_FP_IMPLBIT_S != 0);
31#else
32 unsigned frac : _FP_FRACBITS_S - (_FP_IMPLBIT_S != 0);
33 unsigned exp : _FP_EXPBITS_S;
34 unsigned sign : 1;
35#endif
36 } bits __attribute__((packed));
37};
38
39#define FP_DECL_S(X) _FP_DECL(1,X)
40#define FP_UNPACK_RAW_S(X,val) _FP_UNPACK_RAW_1(S,X,val)
41#define FP_PACK_RAW_S(val,X) _FP_PACK_RAW_1(S,val,X)
42
43#define FP_UNPACK_S(X,val) \
44 do { \
45 _FP_UNPACK_RAW_1(S,X,val); \
46 _FP_UNPACK_CANONICAL(S,1,X); \
47 } while (0)
48
49#define FP_PACK_S(val,X) \
50 do { \
51 _FP_PACK_CANONICAL(S,1,X); \
52 _FP_PACK_RAW_1(S,val,X); \
53 } while (0)
54
55#define FP_NEG_S(R,X) _FP_NEG(S,1,R,X)
56#define FP_ADD_S(R,X,Y) _FP_ADD(S,1,R,X,Y)
57#define FP_SUB_S(R,X,Y) _FP_SUB(S,1,R,X,Y)
58#define FP_MUL_S(R,X,Y) _FP_MUL(S,1,R,X,Y)
59#define FP_DIV_S(R,X,Y) _FP_DIV(S,1,R,X,Y)
60#define FP_SQRT_S(R,X) _FP_SQRT(S,1,R,X)
61
62#define FP_CMP_S(r,X,Y,un) _FP_CMP(S,1,r,X,Y,un)
63#define FP_CMP_EQ_S(r,X,Y) _FP_CMP_EQ(S,1,r,X,Y)
64
65#define FP_TO_INT_S(r,X,rsz,rsg) _FP_TO_INT(S,1,r,X,rsz,rsg)
66#define FP_FROM_INT_S(X,r,rs,rt) _FP_FROM_INT(S,1,X,r,rs,rt)
diff --git a/arch/powerpc/math-emu/soft-fp.h b/arch/powerpc/math-emu/soft-fp.h
new file mode 100644
index 000000000000..cca39598f873
--- /dev/null
+++ b/arch/powerpc/math-emu/soft-fp.h
@@ -0,0 +1,104 @@
1#ifndef SOFT_FP_H
2#define SOFT_FP_H
3
4#include "sfp-machine.h"
5
6#define _FP_WORKBITS 3
7#define _FP_WORK_LSB ((_FP_W_TYPE)1 << 3)
8#define _FP_WORK_ROUND ((_FP_W_TYPE)1 << 2)
9#define _FP_WORK_GUARD ((_FP_W_TYPE)1 << 1)
10#define _FP_WORK_STICKY ((_FP_W_TYPE)1 << 0)
11
12#ifndef FP_RND_NEAREST
13# define FP_RND_NEAREST 0
14# define FP_RND_ZERO 1
15# define FP_RND_PINF 2
16# define FP_RND_MINF 3
17#ifndef FP_ROUNDMODE
18# define FP_ROUNDMODE FP_RND_NEAREST
19#endif
20#endif
21
22#define _FP_ROUND_NEAREST(wc, X) \
23({ int __ret = 0; \
24 int __frac = _FP_FRAC_LOW_##wc(X) & 15; \
25 if (__frac & 7) { \
26 __ret = EFLAG_INEXACT; \
27 if ((__frac & 7) != _FP_WORK_ROUND) \
28 _FP_FRAC_ADDI_##wc(X, _FP_WORK_ROUND); \
29 else if (__frac & _FP_WORK_LSB) \
30 _FP_FRAC_ADDI_##wc(X, _FP_WORK_ROUND); \
31 } \
32 __ret; \
33})
34
35#define _FP_ROUND_ZERO(wc, X) \
36({ int __ret = 0; \
37 if (_FP_FRAC_LOW_##wc(X) & 7) \
38 __ret = EFLAG_INEXACT; \
39 __ret; \
40})
41
42#define _FP_ROUND_PINF(wc, X) \
43({ int __ret = EFLAG_INEXACT; \
44 if (!X##_s && (_FP_FRAC_LOW_##wc(X) & 7)) \
45 _FP_FRAC_ADDI_##wc(X, _FP_WORK_LSB); \
46 else __ret = 0; \
47 __ret; \
48})
49
50#define _FP_ROUND_MINF(wc, X) \
51({ int __ret = EFLAG_INEXACT; \
52 if (X##_s && (_FP_FRAC_LOW_##wc(X) & 7)) \
53 _FP_FRAC_ADDI_##wc(X, _FP_WORK_LSB); \
54 else __ret = 0; \
55 __ret; \
56})
57
58#define _FP_ROUND(wc, X) \
59({ int __ret = 0; \
60 switch (FP_ROUNDMODE) \
61 { \
62 case FP_RND_NEAREST: \
63 __ret |= _FP_ROUND_NEAREST(wc,X); \
64 break; \
65 case FP_RND_ZERO: \
66 __ret |= _FP_ROUND_ZERO(wc,X); \
67 break; \
68 case FP_RND_PINF: \
69 __ret |= _FP_ROUND_PINF(wc,X); \
70 break; \
71 case FP_RND_MINF: \
72 __ret |= _FP_ROUND_MINF(wc,X); \
73 break; \
74 }; \
75 __ret; \
76})
77
78#define FP_CLS_NORMAL 0
79#define FP_CLS_ZERO 1
80#define FP_CLS_INF 2
81#define FP_CLS_NAN 3
82
83#define _FP_CLS_COMBINE(x,y) (((x) << 2) | (y))
84
85#include "op-1.h"
86#include "op-2.h"
87#include "op-4.h"
88#include "op-common.h"
89
90/* Sigh. Silly things longlong.h needs. */
91#define UWtype _FP_W_TYPE
92#define W_TYPE_SIZE _FP_W_TYPE_SIZE
93
94typedef int SItype __attribute__((mode(SI)));
95typedef int DItype __attribute__((mode(DI)));
96typedef unsigned int USItype __attribute__((mode(SI)));
97typedef unsigned int UDItype __attribute__((mode(DI)));
98#if _FP_W_TYPE_SIZE == 32
99typedef unsigned int UHWtype __attribute__((mode(HI)));
100#elif _FP_W_TYPE_SIZE == 64
101typedef USItype UHWtype;
102#endif
103
104#endif
diff --git a/arch/powerpc/math-emu/stfd.c b/arch/powerpc/math-emu/stfd.c
new file mode 100644
index 000000000000..3f8c2558a9e8
--- /dev/null
+++ b/arch/powerpc/math-emu/stfd.c
@@ -0,0 +1,20 @@
1#include <linux/types.h>
2#include <linux/errno.h>
3#include <asm/uaccess.h>
4
5int
6stfd(void *frS, void *ea)
7{
8#if 0
9#ifdef DEBUG
10 printk("%s: S %p, ea %p: ", __FUNCTION__, frS, ea);
11 dump_double(frS);
12 printk("\n");
13#endif
14#endif
15
16 if (copy_to_user(ea, frS, sizeof(double)))
17 return -EFAULT;
18
19 return 0;
20}
diff --git a/arch/powerpc/math-emu/stfiwx.c b/arch/powerpc/math-emu/stfiwx.c
new file mode 100644
index 000000000000..95caaeec6a08
--- /dev/null
+++ b/arch/powerpc/math-emu/stfiwx.c
@@ -0,0 +1,16 @@
1#include <linux/types.h>
2#include <linux/errno.h>
3#include <asm/uaccess.h>
4
5int
6stfiwx(u32 *frS, void *ea)
7{
8#ifdef DEBUG
9 printk("%s: %p %p\n", __FUNCTION__, frS, ea);
10#endif
11
12 if (copy_to_user(ea, &frS[1], sizeof(frS[1])))
13 return -EFAULT;
14
15 return 0;
16}
diff --git a/arch/powerpc/math-emu/stfs.c b/arch/powerpc/math-emu/stfs.c
new file mode 100644
index 000000000000..e87ca23c6dc3
--- /dev/null
+++ b/arch/powerpc/math-emu/stfs.c
@@ -0,0 +1,41 @@
1#include <linux/types.h>
2#include <linux/errno.h>
3#include <asm/uaccess.h>
4
5#include "soft-fp.h"
6#include "double.h"
7#include "single.h"
8
9int
10stfs(void *frS, void *ea)
11{
12 FP_DECL_D(A);
13 FP_DECL_S(R);
14 float f;
15 int err;
16
17#ifdef DEBUG
18 printk("%s: S %p, ea %p\n", __FUNCTION__, frS, ea);
19#endif
20
21 __FP_UNPACK_D(A, frS);
22
23#ifdef DEBUG
24 printk("A: %ld %lu %lu %ld (%ld)\n", A_s, A_f1, A_f0, A_e, A_c);
25#endif
26
27 FP_CONV(S, D, 1, 2, R, A);
28
29#ifdef DEBUG
30 printk("R: %ld %lu %ld (%ld)\n", R_s, R_f, R_e, R_c);
31#endif
32
33 err = _FP_PACK_CANONICAL(S, 1, R);
34 if (!err || !__FPU_TRAP_P(err)) {
35 __FP_PACK_RAW_1(S, &f, R);
36 if (copy_to_user(ea, &f, sizeof(float)))
37 return -EFAULT;
38 }
39
40 return err;
41}
diff --git a/arch/powerpc/math-emu/types.c b/arch/powerpc/math-emu/types.c
new file mode 100644
index 000000000000..e1ed15d829db
--- /dev/null
+++ b/arch/powerpc/math-emu/types.c
@@ -0,0 +1,51 @@
1#include "soft-fp.h"
2#include "double.h"
3#include "single.h"
4
5void
6fp_unpack_d(long *_s, unsigned long *_f1, unsigned long *_f0,
7 long *_e, long *_c, void *val)
8{
9 FP_DECL_D(X);
10
11 __FP_UNPACK_RAW_2(D, X, val);
12
13 _FP_UNPACK_CANONICAL(D, 2, X);
14
15 *_s = X_s;
16 *_f1 = X_f1;
17 *_f0 = X_f0;
18 *_e = X_e;
19 *_c = X_c;
20}
21
22int
23fp_pack_d(void *val, long X_s, unsigned long X_f1,
24 unsigned long X_f0, long X_e, long X_c)
25{
26 int exc;
27
28 exc = _FP_PACK_CANONICAL(D, 2, X);
29 if (!exc || !__FPU_TRAP_P(exc))
30 __FP_PACK_RAW_2(D, val, X);
31 return exc;
32}
33
34int
35fp_pack_ds(void *val, long X_s, unsigned long X_f1,
36 unsigned long X_f0, long X_e, long X_c)
37{
38 FP_DECL_S(__X);
39 int exc;
40
41 FP_CONV(S, D, 1, 2, __X, X);
42 exc = _FP_PACK_CANONICAL(S, 1, __X);
43 if (!exc || !__FPU_TRAP_P(exc)) {
44 _FP_UNPACK_CANONICAL(S, 1, __X);
45 FP_CONV(D, S, 2, 1, X, __X);
46 exc |= _FP_PACK_CANONICAL(D, 2, X);
47 if (!exc || !__FPU_TRAP_P(exc))
48 __FP_PACK_RAW_2(D, val, X);
49 }
50 return exc;
51}
diff --git a/arch/powerpc/math-emu/udivmodti4.c b/arch/powerpc/math-emu/udivmodti4.c
new file mode 100644
index 000000000000..7e112dc1e2f2
--- /dev/null
+++ b/arch/powerpc/math-emu/udivmodti4.c
@@ -0,0 +1,191 @@
1/* This has so very few changes over libgcc2's __udivmoddi4 it isn't funny. */
2
3#include "soft-fp.h"
4
5#undef count_leading_zeros
6#define count_leading_zeros __FP_CLZ
7
8void
9_fp_udivmodti4(_FP_W_TYPE q[2], _FP_W_TYPE r[2],
10 _FP_W_TYPE n1, _FP_W_TYPE n0,
11 _FP_W_TYPE d1, _FP_W_TYPE d0)
12{
13 _FP_W_TYPE q0, q1, r0, r1;
14 _FP_I_TYPE b, bm;
15
16 if (d1 == 0)
17 {
18#if !UDIV_NEEDS_NORMALIZATION
19 if (d0 > n1)
20 {
21 /* 0q = nn / 0D */
22
23 udiv_qrnnd (q0, n0, n1, n0, d0);
24 q1 = 0;
25
26 /* Remainder in n0. */
27 }
28 else
29 {
30 /* qq = NN / 0d */
31
32 if (d0 == 0)
33 d0 = 1 / d0; /* Divide intentionally by zero. */
34
35 udiv_qrnnd (q1, n1, 0, n1, d0);
36 udiv_qrnnd (q0, n0, n1, n0, d0);
37
38 /* Remainder in n0. */
39 }
40
41 r0 = n0;
42 r1 = 0;
43
44#else /* UDIV_NEEDS_NORMALIZATION */
45
46 if (d0 > n1)
47 {
48 /* 0q = nn / 0D */
49
50 count_leading_zeros (bm, d0);
51
52 if (bm != 0)
53 {
54 /* Normalize, i.e. make the most significant bit of the
55 denominator set. */
56
57 d0 = d0 << bm;
58 n1 = (n1 << bm) | (n0 >> (_FP_W_TYPE_SIZE - bm));
59 n0 = n0 << bm;
60 }
61
62 udiv_qrnnd (q0, n0, n1, n0, d0);
63 q1 = 0;
64
65 /* Remainder in n0 >> bm. */
66 }
67 else
68 {
69 /* qq = NN / 0d */
70
71 if (d0 == 0)
72 d0 = 1 / d0; /* Divide intentionally by zero. */
73
74 count_leading_zeros (bm, d0);
75
76 if (bm == 0)
77 {
78 /* From (n1 >= d0) /\ (the most significant bit of d0 is set),
79 conclude (the most significant bit of n1 is set) /\ (the
80 leading quotient digit q1 = 1).
81
82 This special case is necessary, not an optimization.
83 (Shifts counts of SI_TYPE_SIZE are undefined.) */
84
85 n1 -= d0;
86 q1 = 1;
87 }
88 else
89 {
90 _FP_W_TYPE n2;
91
92 /* Normalize. */
93
94 b = _FP_W_TYPE_SIZE - bm;
95
96 d0 = d0 << bm;
97 n2 = n1 >> b;
98 n1 = (n1 << bm) | (n0 >> b);
99 n0 = n0 << bm;
100
101 udiv_qrnnd (q1, n1, n2, n1, d0);
102 }
103
104 /* n1 != d0... */
105
106 udiv_qrnnd (q0, n0, n1, n0, d0);
107
108 /* Remainder in n0 >> bm. */
109 }
110
111 r0 = n0 >> bm;
112 r1 = 0;
113#endif /* UDIV_NEEDS_NORMALIZATION */
114 }
115 else
116 {
117 if (d1 > n1)
118 {
119 /* 00 = nn / DD */
120
121 q0 = 0;
122 q1 = 0;
123
124 /* Remainder in n1n0. */
125 r0 = n0;
126 r1 = n1;
127 }
128 else
129 {
130 /* 0q = NN / dd */
131
132 count_leading_zeros (bm, d1);
133 if (bm == 0)
134 {
135 /* From (n1 >= d1) /\ (the most significant bit of d1 is set),
136 conclude (the most significant bit of n1 is set) /\ (the
137 quotient digit q0 = 0 or 1).
138
139 This special case is necessary, not an optimization. */
140
141 /* The condition on the next line takes advantage of that
142 n1 >= d1 (true due to program flow). */
143 if (n1 > d1 || n0 >= d0)
144 {
145 q0 = 1;
146 sub_ddmmss (n1, n0, n1, n0, d1, d0);
147 }
148 else
149 q0 = 0;
150
151 q1 = 0;
152
153 r0 = n0;
154 r1 = n1;
155 }
156 else
157 {
158 _FP_W_TYPE m1, m0, n2;
159
160 /* Normalize. */
161
162 b = _FP_W_TYPE_SIZE - bm;
163
164 d1 = (d1 << bm) | (d0 >> b);
165 d0 = d0 << bm;
166 n2 = n1 >> b;
167 n1 = (n1 << bm) | (n0 >> b);
168 n0 = n0 << bm;
169
170 udiv_qrnnd (q0, n1, n2, n1, d1);
171 umul_ppmm (m1, m0, q0, d0);
172
173 if (m1 > n1 || (m1 == n1 && m0 > n0))
174 {
175 q0--;
176 sub_ddmmss (m1, m0, m1, m0, d1, d0);
177 }
178
179 q1 = 0;
180
181 /* Remainder in (n1n0 - m1m0) >> bm. */
182 sub_ddmmss (n1, n0, n1, n0, m1, m0);
183 r0 = (n1 << b) | (n0 >> bm);
184 r1 = n1 >> bm;
185 }
186 }
187 }
188
189 q[0] = q0; q[1] = q1;
190 r[0] = r0, r[1] = r1;
191}
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index 89b35c181314..c006d9039633 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -167,7 +167,7 @@ int htab_bolt_mapping(unsigned long vstart, unsigned long vend,
167 * normal insert callback here. 167 * normal insert callback here.
168 */ 168 */
169#ifdef CONFIG_PPC_ISERIES 169#ifdef CONFIG_PPC_ISERIES
170 if (_machine == PLATFORM_ISERIES_LPAR) 170 if (machine_is(iseries))
171 ret = iSeries_hpte_insert(hpteg, va, 171 ret = iSeries_hpte_insert(hpteg, va,
172 paddr, 172 paddr,
173 tmp_mode, 173 tmp_mode,
@@ -176,7 +176,7 @@ int htab_bolt_mapping(unsigned long vstart, unsigned long vend,
176 else 176 else
177#endif 177#endif
178#ifdef CONFIG_PPC_PSERIES 178#ifdef CONFIG_PPC_PSERIES
179 if (_machine & PLATFORM_LPAR) 179 if (machine_is(pseries) && firmware_has_feature(FW_FEATURE_LPAR))
180 ret = pSeries_lpar_hpte_insert(hpteg, va, 180 ret = pSeries_lpar_hpte_insert(hpteg, va,
181 paddr, 181 paddr,
182 tmp_mode, 182 tmp_mode,
@@ -295,8 +295,7 @@ static void __init htab_init_page_sizes(void)
295 * Not in the device-tree, let's fallback on known size 295 * Not in the device-tree, let's fallback on known size
296 * list for 16M capable GP & GR 296 * list for 16M capable GP & GR
297 */ 297 */
298 if ((_machine != PLATFORM_ISERIES_LPAR) && 298 if (cpu_has_feature(CPU_FTR_16M_PAGE) && !machine_is(iseries))
299 cpu_has_feature(CPU_FTR_16M_PAGE))
300 memcpy(mmu_psize_defs, mmu_psize_defaults_gp, 299 memcpy(mmu_psize_defs, mmu_psize_defaults_gp,
301 sizeof(mmu_psize_defaults_gp)); 300 sizeof(mmu_psize_defaults_gp));
302 found: 301 found:
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index 5e435a9c3431..741dd8802d49 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -342,7 +342,7 @@ void __init mem_init(void)
342#ifdef CONFIG_NEED_MULTIPLE_NODES 342#ifdef CONFIG_NEED_MULTIPLE_NODES
343 for_each_online_node(nid) { 343 for_each_online_node(nid) {
344 if (NODE_DATA(nid)->node_spanned_pages != 0) { 344 if (NODE_DATA(nid)->node_spanned_pages != 0) {
345 printk("freeing bootmem node %x\n", nid); 345 printk("freeing bootmem node %d\n", nid);
346 totalram_pages += 346 totalram_pages +=
347 free_all_bootmem_node(NODE_DATA(nid)); 347 free_all_bootmem_node(NODE_DATA(nid));
348 } 348 }
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
index e89b22aa539e..0a335f34974c 100644
--- a/arch/powerpc/mm/numa.c
+++ b/arch/powerpc/mm/numa.c
@@ -756,6 +756,7 @@ int hot_add_scn_to_nid(unsigned long scn_addr)
756 struct device_node *memory = NULL; 756 struct device_node *memory = NULL;
757 nodemask_t nodes; 757 nodemask_t nodes;
758 int default_nid = any_online_node(NODE_MASK_ALL); 758 int default_nid = any_online_node(NODE_MASK_ALL);
759 int nid;
759 760
760 if (!numa_enabled || (min_common_depth < 0)) 761 if (!numa_enabled || (min_common_depth < 0))
761 return default_nid; 762 return default_nid;
@@ -790,6 +791,7 @@ ha_new_range:
790 goto ha_new_range; 791 goto ha_new_range;
791 } 792 }
792 BUG(); /* section address should be found above */ 793 BUG(); /* section address should be found above */
794 return 0;
793 795
794 /* Temporary code to ensure that returned node is not empty */ 796 /* Temporary code to ensure that returned node is not empty */
795got_nid: 797got_nid:
diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig
index d3d0ff745e84..06e371282f57 100644
--- a/arch/powerpc/platforms/85xx/Kconfig
+++ b/arch/powerpc/platforms/85xx/Kconfig
@@ -7,6 +7,7 @@ choice
7 7
8config MPC8540_ADS 8config MPC8540_ADS
9 bool "Freescale MPC8540 ADS" 9 bool "Freescale MPC8540 ADS"
10 select DEFAULT_UIMAGE
10 help 11 help
11 This option enables support for the MPC 8540 ADS board 12 This option enables support for the MPC 8540 ADS board
12 13
diff --git a/arch/powerpc/platforms/cell/Kconfig b/arch/powerpc/platforms/cell/Kconfig
index 3157071e241c..c2a3db8edb0c 100644
--- a/arch/powerpc/platforms/cell/Kconfig
+++ b/arch/powerpc/platforms/cell/Kconfig
@@ -10,4 +10,9 @@ config SPU_FS
10 Units on machines implementing the Broadband Processor 10 Units on machines implementing the Broadband Processor
11 Architecture. 11 Architecture.
12 12
13config SPUFS_MMAP
14 bool
15 depends on SPU_FS && SPARSEMEM && !PPC_64K_PAGES
16 default y
17
13endmenu 18endmenu
diff --git a/arch/powerpc/platforms/cell/Makefile b/arch/powerpc/platforms/cell/Makefile
index 3b998a393e3f..e570bad06394 100644
--- a/arch/powerpc/platforms/cell/Makefile
+++ b/arch/powerpc/platforms/cell/Makefile
@@ -6,5 +6,11 @@ obj-$(CONFIG_SPU_FS) += spu-base.o spufs/
6 6
7spu-base-y += spu_base.o spu_priv1.o 7spu-base-y += spu_base.o spu_priv1.o
8 8
9builtin-spufs-$(CONFIG_SPU_FS) += spu_syscalls.o 9# needed only when building loadable spufs.ko
10obj-y += $(builtin-spufs-m) 10spufs-modular-$(CONFIG_SPU_FS) += spu_syscalls.o
11obj-y += $(spufs-modular-m)
12
13# always needed in kernel
14spufs-builtin-$(CONFIG_SPU_FS) += spu_callbacks.o
15obj-y += $(spufs-builtin-y) $(spufs-builtin-m)
16
diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c
index 63aa52acf441..ae62f5d5c31b 100644
--- a/arch/powerpc/platforms/cell/interrupt.c
+++ b/arch/powerpc/platforms/cell/interrupt.c
@@ -63,7 +63,24 @@ static DEFINE_PER_CPU(struct iic, iic);
63 63
64void iic_local_enable(void) 64void iic_local_enable(void)
65{ 65{
66 out_be64(&__get_cpu_var(iic).regs->prio, 0xff); 66 struct iic *iic = &__get_cpu_var(iic);
67 u64 tmp;
68
69 /*
70 * There seems to be a bug that is present in DD2.x CPUs
71 * and still only partially fixed in DD3.1.
72 * This bug causes a value written to the priority register
73 * not to make it there, resulting in a system hang unless we
74 * write it again.
75 * Masking with 0xf0 is done because the Cell BE does not
76 * implement the lower four bits of the interrupt priority,
77 * they always read back as zeroes, although future CPUs
78 * might implement different bits.
79 */
80 do {
81 out_be64(&iic->regs->prio, 0xff);
82 tmp = in_be64(&iic->regs->prio);
83 } while ((tmp & 0xf0) != 0xf0);
67} 84}
68 85
69void iic_local_disable(void) 86void iic_local_disable(void)
@@ -123,7 +140,7 @@ static int iic_external_get_irq(struct iic_pending_bits pending)
123 pending.class != 2) 140 pending.class != 2)
124 break; 141 break;
125 irq = IIC_EXT_OFFSET 142 irq = IIC_EXT_OFFSET
126 + spider_get_irq(pending.prio + node * IIC_NODE_STRIDE) 143 + spider_get_irq(node)
127 + node * IIC_NODE_STRIDE; 144 + node * IIC_NODE_STRIDE;
128 break; 145 break;
129 case 0x01 ... 0x04: 146 case 0x01 ... 0x04:
@@ -174,38 +191,98 @@ int iic_get_irq(struct pt_regs *regs)
174 return irq; 191 return irq;
175} 192}
176 193
177static int setup_iic(int cpu, struct iic *iic) 194/* hardcoded part to be compatible with older firmware */
195
196static int setup_iic_hardcoded(void)
178{ 197{
179 struct device_node *np; 198 struct device_node *np;
180 int nodeid = cpu / 2; 199 int nodeid, cpu;
181 unsigned long regs; 200 unsigned long regs;
201 struct iic *iic;
182 202
183 for (np = of_find_node_by_type(NULL, "cpu"); 203 for_each_cpu(cpu) {
184 np; 204 iic = &per_cpu(iic, cpu);
185 np = of_find_node_by_type(np, "cpu")) { 205 nodeid = cpu/2;
186 if (nodeid == *(int *)get_property(np, "node-id", NULL)) 206
187 break; 207 for (np = of_find_node_by_type(NULL, "cpu");
208 np;
209 np = of_find_node_by_type(np, "cpu")) {
210 if (nodeid == *(int *)get_property(np, "node-id", NULL))
211 break;
212 }
213
214 if (!np) {
215 printk(KERN_WARNING "IIC: CPU %d not found\n", cpu);
216 iic->regs = NULL;
217 iic->target_id = 0xff;
218 return -ENODEV;
219 }
220
221 regs = *(long *)get_property(np, "iic", NULL);
222
223 /* hack until we have decided on the devtree info */
224 regs += 0x400;
225 if (cpu & 1)
226 regs += 0x20;
227
228 printk(KERN_INFO "IIC for CPU %d at %lx\n", cpu, regs);
229 iic->regs = ioremap(regs, sizeof(struct iic_regs));
230 iic->target_id = (nodeid << 4) + ((cpu & 1) ? 0xf : 0xe);
188 } 231 }
189 232
190 if (!np) { 233 return 0;
191 printk(KERN_WARNING "IIC: CPU %d not found\n", cpu); 234}
192 iic->regs = NULL;
193 iic->target_id = 0xff;
194 return -ENODEV;
195 }
196 235
197 regs = *(long *)get_property(np, "iic", NULL); 236static int setup_iic(void)
237{
238 struct device_node *dn;
239 unsigned long *regs;
240 char *compatible;
241 unsigned *np, found = 0;
242 struct iic *iic = NULL;
243
244 for (dn = NULL; (dn = of_find_node_by_name(dn, "interrupt-controller"));) {
245 compatible = (char *)get_property(dn, "compatible", NULL);
246
247 if (!compatible) {
248 printk(KERN_WARNING "no compatible property found !\n");
249 continue;
250 }
198 251
199 /* hack until we have decided on the devtree info */ 252 if (strstr(compatible, "IBM,CBEA-Internal-Interrupt-Controller"))
200 regs += 0x400; 253 regs = (unsigned long *)get_property(dn,"reg", NULL);
201 if (cpu & 1) 254 else
202 regs += 0x20; 255 continue;
203 256
204 printk(KERN_DEBUG "IIC for CPU %d at %lx\n", cpu, regs); 257 if (!regs)
205 iic->regs = __ioremap(regs, sizeof(struct iic_regs), 258 printk(KERN_WARNING "IIC: no reg property\n");
206 _PAGE_NO_CACHE); 259
207 iic->target_id = (nodeid << 4) + ((cpu & 1) ? 0xf : 0xe); 260 np = (unsigned int *)get_property(dn, "ibm,interrupt-server-ranges", NULL);
208 return 0; 261
262 if (!np) {
263 printk(KERN_WARNING "IIC: CPU association not found\n");
264 iic->regs = NULL;
265 iic->target_id = 0xff;
266 return -ENODEV;
267 }
268
269 iic = &per_cpu(iic, np[0]);
270 iic->regs = ioremap(regs[0], sizeof(struct iic_regs));
271 iic->target_id = ((np[0] & 2) << 3) + ((np[0] & 1) ? 0xf : 0xe);
272 printk("IIC for CPU %d at %lx mapped to %p\n", np[0], regs[0], iic->regs);
273
274 iic = &per_cpu(iic, np[1]);
275 iic->regs = ioremap(regs[2], sizeof(struct iic_regs));
276 iic->target_id = ((np[1] & 2) << 3) + ((np[1] & 1) ? 0xf : 0xe);
277 printk("IIC for CPU %d at %lx mapped to %p\n", np[1], regs[2], iic->regs);
278
279 found++;
280 }
281
282 if (found)
283 return 0;
284 else
285 return -ENODEV;
209} 286}
210 287
211#ifdef CONFIG_SMP 288#ifdef CONFIG_SMP
@@ -283,10 +360,12 @@ void iic_init_IRQ(void)
283 int cpu, irq_offset; 360 int cpu, irq_offset;
284 struct iic *iic; 361 struct iic *iic;
285 362
363 if (setup_iic() < 0)
364 setup_iic_hardcoded();
365
286 irq_offset = 0; 366 irq_offset = 0;
287 for_each_cpu(cpu) { 367 for_each_cpu(cpu) {
288 iic = &per_cpu(iic, cpu); 368 iic = &per_cpu(iic, cpu);
289 setup_iic(cpu, iic);
290 if (iic->regs) 369 if (iic->regs)
291 out_be64(&iic->regs->prio, 0xff); 370 out_be64(&iic->regs->prio, 0xff);
292 } 371 }
diff --git a/arch/powerpc/platforms/cell/interrupt.h b/arch/powerpc/platforms/cell/interrupt.h
index a14bd38791c0..799f77d98f96 100644
--- a/arch/powerpc/platforms/cell/interrupt.h
+++ b/arch/powerpc/platforms/cell/interrupt.h
@@ -57,7 +57,7 @@ extern void iic_local_disable(void);
57extern u8 iic_get_target_id(int cpu); 57extern u8 iic_get_target_id(int cpu);
58 58
59extern void spider_init_IRQ(void); 59extern void spider_init_IRQ(void);
60extern int spider_get_irq(unsigned long int_pending); 60extern int spider_get_irq(int node);
61 61
62#endif 62#endif
63#endif /* ASM_CELL_PIC_H */ 63#endif /* ASM_CELL_PIC_H */
diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
index 46e7cb9c3e64..a49ceb799a8e 100644
--- a/arch/powerpc/platforms/cell/iommu.c
+++ b/arch/powerpc/platforms/cell/iommu.c
@@ -289,7 +289,7 @@ static void cell_do_map_iommu(struct cell_iommu *iommu,
289 ioc_base = iommu->mapped_base; 289 ioc_base = iommu->mapped_base;
290 ioc_mmio_base = iommu->mapped_mmio_base; 290 ioc_mmio_base = iommu->mapped_mmio_base;
291 291
292 for (real_address = 0, io_address = 0; 292 for (real_address = 0, io_address = map_start;
293 io_address <= map_start + map_size; 293 io_address <= map_start + map_size;
294 real_address += io_page_size, io_address += io_page_size) { 294 real_address += io_page_size, io_address += io_page_size) {
295 ioste = get_iost_entry(fake_iopt, io_address, io_page_size); 295 ioste = get_iost_entry(fake_iopt, io_address, io_page_size);
@@ -302,7 +302,7 @@ static void cell_do_map_iommu(struct cell_iommu *iommu,
302 set_iopt_cache(ioc_mmio_base, 302 set_iopt_cache(ioc_mmio_base,
303 get_ioc_hash_1way(ioste, io_address), 303 get_ioc_hash_1way(ioste, io_address),
304 get_ioc_tag(ioste, io_address), 304 get_ioc_tag(ioste, io_address),
305 get_iopt_entry(real_address-map_start, ioid, IOPT_PROT_RW)); 305 get_iopt_entry(real_address, ioid, IOPT_PROT_RW));
306 } 306 }
307} 307}
308 308
@@ -344,8 +344,8 @@ static int cell_map_iommu_hardcoded(int num_nodes)
344 344
345 /* node 0 */ 345 /* node 0 */
346 iommu = &cell_iommus[0]; 346 iommu = &cell_iommus[0];
347 iommu->mapped_base = __ioremap(0x20000511000, 0x1000, _PAGE_NO_CACHE); 347 iommu->mapped_base = ioremap(0x20000511000, 0x1000);
348 iommu->mapped_mmio_base = __ioremap(0x20000510000, 0x1000, _PAGE_NO_CACHE); 348 iommu->mapped_mmio_base = ioremap(0x20000510000, 0x1000);
349 349
350 enable_mapping(iommu->mapped_base, iommu->mapped_mmio_base); 350 enable_mapping(iommu->mapped_base, iommu->mapped_mmio_base);
351 351
@@ -357,8 +357,8 @@ static int cell_map_iommu_hardcoded(int num_nodes)
357 357
358 /* node 1 */ 358 /* node 1 */
359 iommu = &cell_iommus[1]; 359 iommu = &cell_iommus[1];
360 iommu->mapped_base = __ioremap(0x30000511000, 0x1000, _PAGE_NO_CACHE); 360 iommu->mapped_base = ioremap(0x30000511000, 0x1000);
361 iommu->mapped_mmio_base = __ioremap(0x30000510000, 0x1000, _PAGE_NO_CACHE); 361 iommu->mapped_mmio_base = ioremap(0x30000510000, 0x1000);
362 362
363 enable_mapping(iommu->mapped_base, iommu->mapped_mmio_base); 363 enable_mapping(iommu->mapped_base, iommu->mapped_mmio_base);
364 364
@@ -407,8 +407,8 @@ static int cell_map_iommu(void)
407 iommu->base = *base; 407 iommu->base = *base;
408 iommu->mmio_base = *mmio_base; 408 iommu->mmio_base = *mmio_base;
409 409
410 iommu->mapped_base = __ioremap(*base, 0x1000, _PAGE_NO_CACHE); 410 iommu->mapped_base = ioremap(*base, 0x1000);
411 iommu->mapped_mmio_base = __ioremap(*mmio_base, 0x1000, _PAGE_NO_CACHE); 411 iommu->mapped_mmio_base = ioremap(*mmio_base, 0x1000);
412 412
413 enable_mapping(iommu->mapped_base, 413 enable_mapping(iommu->mapped_base,
414 iommu->mapped_mmio_base); 414 iommu->mapped_mmio_base);
diff --git a/arch/powerpc/platforms/cell/pervasive.c b/arch/powerpc/platforms/cell/pervasive.c
index e0e051c675dd..58baeb52f6fc 100644
--- a/arch/powerpc/platforms/cell/pervasive.c
+++ b/arch/powerpc/platforms/cell/pervasive.c
@@ -203,7 +203,7 @@ found:
203 203
204 pr_debug("pervasive area for CPU %d at %lx, size %x\n", 204 pr_debug("pervasive area for CPU %d at %lx, size %x\n",
205 cpu, real_address, size); 205 cpu, real_address, size);
206 p->regs = __ioremap(real_address, size, _PAGE_NO_CACHE); 206 p->regs = ioremap(real_address, size);
207 p->thread = thread; 207 p->thread = thread;
208 return 0; 208 return 0;
209} 209}
diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c
index fec8e65b36ea..dac5d0365fde 100644
--- a/arch/powerpc/platforms/cell/setup.c
+++ b/arch/powerpc/platforms/cell/setup.c
@@ -195,9 +195,13 @@ static void __init cell_init_early(void)
195} 195}
196 196
197 197
198static int __init cell_probe(int platform) 198static int __init cell_probe(void)
199{ 199{
200 if (platform != PLATFORM_CELL) 200 /* XXX This is temporary, the Cell maintainer will come up with
201 * more appropriate detection logic
202 */
203 unsigned long root = of_get_flat_dt_root();
204 if (!of_flat_dt_is_compatible(root, "IBM,CPBW-1.0"))
201 return 0; 205 return 0;
202 206
203 return 1; 207 return 1;
@@ -212,7 +216,8 @@ static int cell_check_legacy_ioport(unsigned int baseport)
212 return -ENODEV; 216 return -ENODEV;
213} 217}
214 218
215struct machdep_calls __initdata cell_md = { 219define_machine(cell) {
220 .name = "Cell",
216 .probe = cell_probe, 221 .probe = cell_probe,
217 .setup_arch = cell_setup_arch, 222 .setup_arch = cell_setup_arch,
218 .init_early = cell_init_early, 223 .init_early = cell_init_early,
diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c
index e74132188bdf..55cbdd77a62d 100644
--- a/arch/powerpc/platforms/cell/spider-pic.c
+++ b/arch/powerpc/platforms/cell/spider-pic.c
@@ -84,10 +84,11 @@ static void __iomem *spider_get_irq_config(int irq)
84 84
85static void spider_enable_irq(unsigned int irq) 85static void spider_enable_irq(unsigned int irq)
86{ 86{
87 int nodeid = (irq / IIC_NODE_STRIDE) * 0x10;
87 void __iomem *cfg = spider_get_irq_config(irq); 88 void __iomem *cfg = spider_get_irq_config(irq);
88 irq = spider_get_nr(irq); 89 irq = spider_get_nr(irq);
89 90
90 out_be32(cfg, in_be32(cfg) | 0x3107000eu); 91 out_be32(cfg, (in_be32(cfg) & ~0xf0)| 0x3107000eu | nodeid);
91 out_be32(cfg + 4, in_be32(cfg + 4) | 0x00020000u | irq); 92 out_be32(cfg + 4, in_be32(cfg + 4) | 0x00020000u | irq);
92} 93}
93 94
@@ -131,61 +132,108 @@ static struct hw_interrupt_type spider_pic = {
131 .end = spider_end_irq, 132 .end = spider_end_irq,
132}; 133};
133 134
134 135int spider_get_irq(int node)
135int spider_get_irq(unsigned long int_pending)
136{ 136{
137 void __iomem *regs = spider_get_pic(int_pending);
138 unsigned long cs; 137 unsigned long cs;
139 int irq; 138 void __iomem *regs = spider_pics[node];
140
141 cs = in_be32(regs + TIR_CS);
142 139
143 irq = cs >> 24; 140 cs = in_be32(regs + TIR_CS) >> 24;
144 if (irq != 63)
145 return irq;
146 141
147 return -1; 142 if (cs == 63)
143 return -1;
144 else
145 return cs;
148} 146}
149 147
150void spider_init_IRQ(void) 148/* hardcoded part to be compatible with older firmware */
149
150void spider_init_IRQ_hardcoded(void)
151{ 151{
152 int node; 152 int node;
153 struct device_node *dn;
154 unsigned int *property;
155 long spiderpic; 153 long spiderpic;
154 long pics[] = { 0x24000008000, 0x34000008000 };
156 int n; 155 int n;
157 156
158/* FIXME: detect multiple PICs as soon as the device tree has them */ 157 pr_debug("%s(%d): Using hardcoded defaults\n", __FUNCTION__, __LINE__);
159 for (node = 0; node < 1; node++) {
160 dn = of_find_node_by_path("/");
161 n = prom_n_addr_cells(dn);
162 property = (unsigned int *) get_property(dn,
163 "platform-spider-pic", NULL);
164 158
165 if (!property) 159 for (node = 0; node < num_present_cpus()/2; node++) {
166 continue; 160 spiderpic = pics[node];
167 for (spiderpic = 0; n > 0; --n)
168 spiderpic = (spiderpic << 32) + *property++;
169 printk(KERN_DEBUG "SPIDER addr: %lx\n", spiderpic); 161 printk(KERN_DEBUG "SPIDER addr: %lx\n", spiderpic);
170 spider_pics[node] = __ioremap(spiderpic, 0x800, _PAGE_NO_CACHE); 162 spider_pics[node] = ioremap(spiderpic, 0x800);
171 for (n = 0; n < IIC_NUM_EXT; n++) { 163 for (n = 0; n < IIC_NUM_EXT; n++) {
172 int irq = n + IIC_EXT_OFFSET + node * IIC_NODE_STRIDE; 164 int irq = n + IIC_EXT_OFFSET + node * IIC_NODE_STRIDE;
173 get_irq_desc(irq)->handler = &spider_pic; 165 get_irq_desc(irq)->handler = &spider_pic;
166 }
174 167
175 /* do not mask any interrupts because of level */ 168 /* do not mask any interrupts because of level */
176 out_be32(spider_pics[node] + TIR_MSK, 0x0); 169 out_be32(spider_pics[node] + TIR_MSK, 0x0);
177 170
178 /* disable edge detection clear */ 171 /* disable edge detection clear */
179 /* out_be32(spider_pics[node] + TIR_EDC, 0x0); */ 172 /* out_be32(spider_pics[node] + TIR_EDC, 0x0); */
180 173
181 /* enable interrupt packets to be output */ 174 /* enable interrupt packets to be output */
182 out_be32(spider_pics[node] + TIR_PIEN, 175 out_be32(spider_pics[node] + TIR_PIEN,
183 in_be32(spider_pics[node] + TIR_PIEN) | 0x1); 176 in_be32(spider_pics[node] + TIR_PIEN) | 0x1);
184 177
185 /* Enable the interrupt detection enable bit. Do this last! */ 178 /* Enable the interrupt detection enable bit. Do this last! */
186 out_be32(spider_pics[node] + TIR_DEN, 179 out_be32(spider_pics[node] + TIR_DEN,
187 in_be32(spider_pics[node] +TIR_DEN) | 0x1); 180 in_be32(spider_pics[node] + TIR_DEN) | 0x1);
181 }
182}
183
184void spider_init_IRQ(void)
185{
186 long spider_reg;
187 struct device_node *dn;
188 char *compatible;
189 int n, node = 0;
190
191 for (dn = NULL; (dn = of_find_node_by_name(dn, "interrupt-controller"));) {
192 compatible = (char *)get_property(dn, "compatible", NULL);
188 193
194 if (!compatible)
195 continue;
196
197 if (strstr(compatible, "CBEA,platform-spider-pic"))
198 spider_reg = *(long *)get_property(dn,"reg", NULL);
199 else if (strstr(compatible, "sti,platform-spider-pic")) {
200 spider_init_IRQ_hardcoded();
201 return;
202 } else
203 continue;
204
205 if (!spider_reg)
206 printk("interrupt controller does not have reg property !\n");
207
208 n = prom_n_addr_cells(dn);
209
210 if ( n != 2)
211 printk("reg property with invalid number of elements \n");
212
213 spider_pics[node] = ioremap(spider_reg, 0x800);
214
215 printk("SPIDER addr: %lx with %i addr_cells mapped to %p\n",
216 spider_reg, n, spider_pics[node]);
217
218 for (n = 0; n < IIC_NUM_EXT; n++) {
219 int irq = n + IIC_EXT_OFFSET + node * IIC_NODE_STRIDE;
220 get_irq_desc(irq)->handler = &spider_pic;
189 } 221 }
222
223 /* do not mask any interrupts because of level */
224 out_be32(spider_pics[node] + TIR_MSK, 0x0);
225
226 /* disable edge detection clear */
227 /* out_be32(spider_pics[node] + TIR_EDC, 0x0); */
228
229 /* enable interrupt packets to be output */
230 out_be32(spider_pics[node] + TIR_PIEN,
231 in_be32(spider_pics[node] + TIR_PIEN) | 0x1);
232
233 /* Enable the interrupt detection enable bit. Do this last! */
234 out_be32(spider_pics[node] + TIR_DEN,
235 in_be32(spider_pics[node] + TIR_DEN) | 0x1);
236
237 node++;
190 } 238 }
191} 239}
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c
index a8fa1eeeb174..269dda4fd0b4 100644
--- a/arch/powerpc/platforms/cell/spu_base.c
+++ b/arch/powerpc/platforms/cell/spu_base.c
@@ -111,7 +111,7 @@ static int __spu_trap_data_seg(struct spu *spu, unsigned long ea)
111extern int hash_page(unsigned long ea, unsigned long access, unsigned long trap); //XXX 111extern int hash_page(unsigned long ea, unsigned long access, unsigned long trap); //XXX
112static int __spu_trap_data_map(struct spu *spu, unsigned long ea, u64 dsisr) 112static int __spu_trap_data_map(struct spu *spu, unsigned long ea, u64 dsisr)
113{ 113{
114 pr_debug("%s\n", __FUNCTION__); 114 pr_debug("%s, %lx, %lx\n", __FUNCTION__, dsisr, ea);
115 115
116 /* Handle kernel space hash faults immediately. 116 /* Handle kernel space hash faults immediately.
117 User hash faults need to be deferred to process context. */ 117 User hash faults need to be deferred to process context. */
@@ -168,7 +168,7 @@ static int __spu_trap_halt(struct spu *spu)
168static int __spu_trap_tag_group(struct spu *spu) 168static int __spu_trap_tag_group(struct spu *spu)
169{ 169{
170 pr_debug("%s\n", __FUNCTION__); 170 pr_debug("%s\n", __FUNCTION__);
171 /* wake_up(&spu->dma_wq); */ 171 spu->mfc_callback(spu);
172 return 0; 172 return 0;
173} 173}
174 174
@@ -242,6 +242,8 @@ spu_irq_class_1(int irq, void *data, struct pt_regs *regs)
242 spu_mfc_dsisr_set(spu, 0ul); 242 spu_mfc_dsisr_set(spu, 0ul);
243 spu_int_stat_clear(spu, 1, stat); 243 spu_int_stat_clear(spu, 1, stat);
244 spin_unlock(&spu->register_lock); 244 spin_unlock(&spu->register_lock);
245 pr_debug("%s: %lx %lx %lx %lx\n", __FUNCTION__, mask, stat,
246 dar, dsisr);
245 247
246 if (stat & 1) /* segment fault */ 248 if (stat & 1) /* segment fault */
247 __spu_trap_data_seg(spu, dar); 249 __spu_trap_data_seg(spu, dar);
@@ -484,14 +486,13 @@ int spu_irq_class_1_bottom(struct spu *spu)
484 486
485 ea = spu->dar; 487 ea = spu->dar;
486 dsisr = spu->dsisr; 488 dsisr = spu->dsisr;
487 if (dsisr & MFC_DSISR_PTE_NOT_FOUND) { 489 if (dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED)) {
488 access = (_PAGE_PRESENT | _PAGE_USER); 490 access = (_PAGE_PRESENT | _PAGE_USER);
489 access |= (dsisr & MFC_DSISR_ACCESS_PUT) ? _PAGE_RW : 0UL; 491 access |= (dsisr & MFC_DSISR_ACCESS_PUT) ? _PAGE_RW : 0UL;
490 if (hash_page(ea, access, 0x300) != 0) 492 if (hash_page(ea, access, 0x300) != 0)
491 error |= CLASS1_ENABLE_STORAGE_FAULT_INTR; 493 error |= CLASS1_ENABLE_STORAGE_FAULT_INTR;
492 } 494 }
493 if ((error & CLASS1_ENABLE_STORAGE_FAULT_INTR) || 495 if (error & CLASS1_ENABLE_STORAGE_FAULT_INTR) {
494 (dsisr & MFC_DSISR_ACCESS_DENIED)) {
495 if ((ret = spu_handle_mm_fault(spu)) != 0) 496 if ((ret = spu_handle_mm_fault(spu)) != 0)
496 error |= CLASS1_ENABLE_STORAGE_FAULT_INTR; 497 error |= CLASS1_ENABLE_STORAGE_FAULT_INTR;
497 else 498 else
@@ -568,6 +569,11 @@ static int __init spu_map_device(struct spu *spu, struct device_node *spe)
568 if (!spu->local_store) 569 if (!spu->local_store)
569 goto out; 570 goto out;
570 571
572 prop = get_property(spe, "problem", NULL);
573 if (!prop)
574 goto out_unmap;
575 spu->problem_phys = *(unsigned long *)prop;
576
571 spu->problem= map_spe_prop(spe, "problem"); 577 spu->problem= map_spe_prop(spe, "problem");
572 if (!spu->problem) 578 if (!spu->problem)
573 goto out_unmap; 579 goto out_unmap;
@@ -632,6 +638,7 @@ static int __init create_spu(struct device_node *spe)
632 spu->ibox_callback = NULL; 638 spu->ibox_callback = NULL;
633 spu->wbox_callback = NULL; 639 spu->wbox_callback = NULL;
634 spu->stop_callback = NULL; 640 spu->stop_callback = NULL;
641 spu->mfc_callback = NULL;
635 642
636 mutex_lock(&spu_mutex); 643 mutex_lock(&spu_mutex);
637 spu->number = number++; 644 spu->number = number++;
diff --git a/arch/powerpc/platforms/cell/spu_callbacks.c b/arch/powerpc/platforms/cell/spu_callbacks.c
new file mode 100644
index 000000000000..3a4245c926ad
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spu_callbacks.c
@@ -0,0 +1,345 @@
1/*
2 * System call callback functions for SPUs
3 */
4
5#define DEBUG
6
7#include <linux/kallsyms.h>
8#include <linux/module.h>
9#include <linux/syscalls.h>
10
11#include <asm/spu.h>
12#include <asm/syscalls.h>
13#include <asm/unistd.h>
14
15/*
16 * This table defines the system calls that an SPU can call.
17 * It is currently a subset of the 64 bit powerpc system calls,
18 * with the exact semantics.
19 *
20 * The reasons for disabling some of the system calls are:
21 * 1. They interact with the way SPU syscalls are handled
22 * and we can't let them execute ever:
23 * restart_syscall, exit, for, execve, ptrace, ...
24 * 2. They are deprecated and replaced by other means:
25 * uselib, pciconfig_*, sysfs, ...
26 * 3. They are somewhat interacting with the system in a way
27 * we don't want an SPU to:
28 * reboot, init_module, mount, kexec_load
29 * 4. They are optional and we can't rely on them being
30 * linked into the kernel. Unfortunately, the cond_syscall
31 * helper does not work here as it does not add the necessary
32 * opd symbols:
33 * mbind, mq_open, ipc, ...
34 */
35
36void *spu_syscall_table[] = {
37 [__NR_restart_syscall] sys_ni_syscall, /* sys_restart_syscall */
38 [__NR_exit] sys_ni_syscall, /* sys_exit */
39 [__NR_fork] sys_ni_syscall, /* ppc_fork */
40 [__NR_read] sys_read,
41 [__NR_write] sys_write,
42 [__NR_open] sys_open,
43 [__NR_close] sys_close,
44 [__NR_waitpid] sys_waitpid,
45 [__NR_creat] sys_creat,
46 [__NR_link] sys_link,
47 [__NR_unlink] sys_unlink,
48 [__NR_execve] sys_ni_syscall, /* sys_execve */
49 [__NR_chdir] sys_chdir,
50 [__NR_time] sys_time,
51 [__NR_mknod] sys_mknod,
52 [__NR_chmod] sys_chmod,
53 [__NR_lchown] sys_lchown,
54 [__NR_break] sys_ni_syscall,
55 [__NR_oldstat] sys_ni_syscall,
56 [__NR_lseek] sys_lseek,
57 [__NR_getpid] sys_getpid,
58 [__NR_mount] sys_ni_syscall, /* sys_mount */
59 [__NR_umount] sys_ni_syscall,
60 [__NR_setuid] sys_setuid,
61 [__NR_getuid] sys_getuid,
62 [__NR_stime] sys_stime,
63 [__NR_ptrace] sys_ni_syscall, /* sys_ptrace */
64 [__NR_alarm] sys_alarm,
65 [__NR_oldfstat] sys_ni_syscall,
66 [__NR_pause] sys_ni_syscall, /* sys_pause */
67 [__NR_utime] sys_ni_syscall, /* sys_utime */
68 [__NR_stty] sys_ni_syscall,
69 [__NR_gtty] sys_ni_syscall,
70 [__NR_access] sys_access,
71 [__NR_nice] sys_nice,
72 [__NR_ftime] sys_ni_syscall,
73 [__NR_sync] sys_sync,
74 [__NR_kill] sys_kill,
75 [__NR_rename] sys_rename,
76 [__NR_mkdir] sys_mkdir,
77 [__NR_rmdir] sys_rmdir,
78 [__NR_dup] sys_dup,
79 [__NR_pipe] sys_pipe,
80 [__NR_times] sys_times,
81 [__NR_prof] sys_ni_syscall,
82 [__NR_brk] sys_brk,
83 [__NR_setgid] sys_setgid,
84 [__NR_getgid] sys_getgid,
85 [__NR_signal] sys_ni_syscall, /* sys_signal */
86 [__NR_geteuid] sys_geteuid,
87 [__NR_getegid] sys_getegid,
88 [__NR_acct] sys_ni_syscall, /* sys_acct */
89 [__NR_umount2] sys_ni_syscall, /* sys_umount */
90 [__NR_lock] sys_ni_syscall,
91 [__NR_ioctl] sys_ioctl,
92 [__NR_fcntl] sys_fcntl,
93 [__NR_mpx] sys_ni_syscall,
94 [__NR_setpgid] sys_setpgid,
95 [__NR_ulimit] sys_ni_syscall,
96 [__NR_oldolduname] sys_ni_syscall,
97 [__NR_umask] sys_umask,
98 [__NR_chroot] sys_chroot,
99 [__NR_ustat] sys_ni_syscall, /* sys_ustat */
100 [__NR_dup2] sys_dup2,
101 [__NR_getppid] sys_getppid,
102 [__NR_getpgrp] sys_getpgrp,
103 [__NR_setsid] sys_setsid,
104 [__NR_sigaction] sys_ni_syscall,
105 [__NR_sgetmask] sys_sgetmask,
106 [__NR_ssetmask] sys_ssetmask,
107 [__NR_setreuid] sys_setreuid,
108 [__NR_setregid] sys_setregid,
109 [__NR_sigsuspend] sys_ni_syscall,
110 [__NR_sigpending] sys_ni_syscall,
111 [__NR_sethostname] sys_sethostname,
112 [__NR_setrlimit] sys_setrlimit,
113 [__NR_getrlimit] sys_ni_syscall,
114 [__NR_getrusage] sys_getrusage,
115 [__NR_gettimeofday] sys_gettimeofday,
116 [__NR_settimeofday] sys_settimeofday,
117 [__NR_getgroups] sys_getgroups,
118 [__NR_setgroups] sys_setgroups,
119 [__NR_select] sys_ni_syscall,
120 [__NR_symlink] sys_symlink,
121 [__NR_oldlstat] sys_ni_syscall,
122 [__NR_readlink] sys_readlink,
123 [__NR_uselib] sys_ni_syscall, /* sys_uselib */
124 [__NR_swapon] sys_ni_syscall, /* sys_swapon */
125 [__NR_reboot] sys_ni_syscall, /* sys_reboot */
126 [__NR_readdir] sys_ni_syscall,
127 [__NR_mmap] sys_mmap,
128 [__NR_munmap] sys_munmap,
129 [__NR_truncate] sys_truncate,
130 [__NR_ftruncate] sys_ftruncate,
131 [__NR_fchmod] sys_fchmod,
132 [__NR_fchown] sys_fchown,
133 [__NR_getpriority] sys_getpriority,
134 [__NR_setpriority] sys_setpriority,
135 [__NR_profil] sys_ni_syscall,
136 [__NR_statfs] sys_ni_syscall, /* sys_statfs */
137 [__NR_fstatfs] sys_ni_syscall, /* sys_fstatfs */
138 [__NR_ioperm] sys_ni_syscall,
139 [__NR_socketcall] sys_socketcall,
140 [__NR_syslog] sys_syslog,
141 [__NR_setitimer] sys_setitimer,
142 [__NR_getitimer] sys_getitimer,
143 [__NR_stat] sys_newstat,
144 [__NR_lstat] sys_newlstat,
145 [__NR_fstat] sys_newfstat,
146 [__NR_olduname] sys_ni_syscall,
147 [__NR_iopl] sys_ni_syscall,
148 [__NR_vhangup] sys_vhangup,
149 [__NR_idle] sys_ni_syscall,
150 [__NR_vm86] sys_ni_syscall,
151 [__NR_wait4] sys_wait4,
152 [__NR_swapoff] sys_ni_syscall, /* sys_swapoff */
153 [__NR_sysinfo] sys_sysinfo,
154 [__NR_ipc] sys_ni_syscall, /* sys_ipc */
155 [__NR_fsync] sys_fsync,
156 [__NR_sigreturn] sys_ni_syscall,
157 [__NR_clone] sys_ni_syscall, /* ppc_clone */
158 [__NR_setdomainname] sys_setdomainname,
159 [__NR_uname] ppc_newuname,
160 [__NR_modify_ldt] sys_ni_syscall,
161 [__NR_adjtimex] sys_adjtimex,
162 [__NR_mprotect] sys_mprotect,
163 [__NR_sigprocmask] sys_ni_syscall,
164 [__NR_create_module] sys_ni_syscall,
165 [__NR_init_module] sys_ni_syscall, /* sys_init_module */
166 [__NR_delete_module] sys_ni_syscall, /* sys_delete_module */
167 [__NR_get_kernel_syms] sys_ni_syscall,
168 [__NR_quotactl] sys_ni_syscall, /* sys_quotactl */
169 [__NR_getpgid] sys_getpgid,
170 [__NR_fchdir] sys_fchdir,
171 [__NR_bdflush] sys_bdflush,
172 [__NR_sysfs] sys_ni_syscall, /* sys_sysfs */
173 [__NR_personality] ppc64_personality,
174 [__NR_afs_syscall] sys_ni_syscall,
175 [__NR_setfsuid] sys_setfsuid,
176 [__NR_setfsgid] sys_setfsgid,
177 [__NR__llseek] sys_llseek,
178 [__NR_getdents] sys_getdents,
179 [__NR__newselect] sys_select,
180 [__NR_flock] sys_flock,
181 [__NR_msync] sys_msync,
182 [__NR_readv] sys_readv,
183 [__NR_writev] sys_writev,
184 [__NR_getsid] sys_getsid,
185 [__NR_fdatasync] sys_fdatasync,
186 [__NR__sysctl] sys_ni_syscall, /* sys_sysctl */
187 [__NR_mlock] sys_mlock,
188 [__NR_munlock] sys_munlock,
189 [__NR_mlockall] sys_mlockall,
190 [__NR_munlockall] sys_munlockall,
191 [__NR_sched_setparam] sys_sched_setparam,
192 [__NR_sched_getparam] sys_sched_getparam,
193 [__NR_sched_setscheduler] sys_sched_setscheduler,
194 [__NR_sched_getscheduler] sys_sched_getscheduler,
195 [__NR_sched_yield] sys_sched_yield,
196 [__NR_sched_get_priority_max] sys_sched_get_priority_max,
197 [__NR_sched_get_priority_min] sys_sched_get_priority_min,
198 [__NR_sched_rr_get_interval] sys_sched_rr_get_interval,
199 [__NR_nanosleep] sys_nanosleep,
200 [__NR_mremap] sys_mremap,
201 [__NR_setresuid] sys_setresuid,
202 [__NR_getresuid] sys_getresuid,
203 [__NR_query_module] sys_ni_syscall,
204 [__NR_poll] sys_poll,
205 [__NR_nfsservctl] sys_ni_syscall, /* sys_nfsservctl */
206 [__NR_setresgid] sys_setresgid,
207 [__NR_getresgid] sys_getresgid,
208 [__NR_prctl] sys_prctl,
209 [__NR_rt_sigreturn] sys_ni_syscall, /* ppc64_rt_sigreturn */
210 [__NR_rt_sigaction] sys_ni_syscall, /* sys_rt_sigaction */
211 [__NR_rt_sigprocmask] sys_ni_syscall, /* sys_rt_sigprocmask */
212 [__NR_rt_sigpending] sys_ni_syscall, /* sys_rt_sigpending */
213 [__NR_rt_sigtimedwait] sys_ni_syscall, /* sys_rt_sigtimedwait */
214 [__NR_rt_sigqueueinfo] sys_ni_syscall, /* sys_rt_sigqueueinfo */
215 [__NR_rt_sigsuspend] sys_ni_syscall, /* sys_rt_sigsuspend */
216 [__NR_pread64] sys_pread64,
217 [__NR_pwrite64] sys_pwrite64,
218 [__NR_chown] sys_chown,
219 [__NR_getcwd] sys_getcwd,
220 [__NR_capget] sys_capget,
221 [__NR_capset] sys_capset,
222 [__NR_sigaltstack] sys_ni_syscall, /* sys_sigaltstack */
223 [__NR_sendfile] sys_sendfile64,
224 [__NR_getpmsg] sys_ni_syscall,
225 [__NR_putpmsg] sys_ni_syscall,
226 [__NR_vfork] sys_ni_syscall, /* ppc_vfork */
227 [__NR_ugetrlimit] sys_getrlimit,
228 [__NR_readahead] sys_readahead,
229 [192] sys_ni_syscall,
230 [193] sys_ni_syscall,
231 [194] sys_ni_syscall,
232 [195] sys_ni_syscall,
233 [196] sys_ni_syscall,
234 [197] sys_ni_syscall,
235 [__NR_pciconfig_read] sys_ni_syscall, /* sys_pciconfig_read */
236 [__NR_pciconfig_write] sys_ni_syscall, /* sys_pciconfig_write */
237 [__NR_pciconfig_iobase] sys_ni_syscall, /* sys_pciconfig_iobase */
238 [__NR_multiplexer] sys_ni_syscall,
239 [__NR_getdents64] sys_getdents64,
240 [__NR_pivot_root] sys_pivot_root,
241 [204] sys_ni_syscall,
242 [__NR_madvise] sys_madvise,
243 [__NR_mincore] sys_mincore,
244 [__NR_gettid] sys_gettid,
245 [__NR_tkill] sys_tkill,
246 [__NR_setxattr] sys_setxattr,
247 [__NR_lsetxattr] sys_lsetxattr,
248 [__NR_fsetxattr] sys_fsetxattr,
249 [__NR_getxattr] sys_getxattr,
250 [__NR_lgetxattr] sys_lgetxattr,
251 [__NR_fgetxattr] sys_fgetxattr,
252 [__NR_listxattr] sys_listxattr,
253 [__NR_llistxattr] sys_llistxattr,
254 [__NR_flistxattr] sys_flistxattr,
255 [__NR_removexattr] sys_removexattr,
256 [__NR_lremovexattr] sys_lremovexattr,
257 [__NR_fremovexattr] sys_fremovexattr,
258 [__NR_futex] sys_futex,
259 [__NR_sched_setaffinity] sys_sched_setaffinity,
260 [__NR_sched_getaffinity] sys_sched_getaffinity,
261 [__NR_tuxcall] sys_ni_syscall,
262 [226] sys_ni_syscall,
263 [__NR_io_setup] sys_io_setup,
264 [__NR_io_destroy] sys_io_destroy,
265 [__NR_io_getevents] sys_io_getevents,
266 [__NR_io_submit] sys_io_submit,
267 [__NR_io_cancel] sys_io_cancel,
268 [__NR_set_tid_address] sys_ni_syscall, /* sys_set_tid_address */
269 [__NR_fadvise64] sys_fadvise64,
270 [__NR_exit_group] sys_ni_syscall, /* sys_exit_group */
271 [__NR_lookup_dcookie] sys_ni_syscall, /* sys_lookup_dcookie */
272 [__NR_epoll_create] sys_epoll_create,
273 [__NR_epoll_ctl] sys_epoll_ctl,
274 [__NR_epoll_wait] sys_epoll_wait,
275 [__NR_remap_file_pages] sys_remap_file_pages,
276 [__NR_timer_create] sys_timer_create,
277 [__NR_timer_settime] sys_timer_settime,
278 [__NR_timer_gettime] sys_timer_gettime,
279 [__NR_timer_getoverrun] sys_timer_getoverrun,
280 [__NR_timer_delete] sys_timer_delete,
281 [__NR_clock_settime] sys_clock_settime,
282 [__NR_clock_gettime] sys_clock_gettime,
283 [__NR_clock_getres] sys_clock_getres,
284 [__NR_clock_nanosleep] sys_clock_nanosleep,
285 [__NR_swapcontext] sys_ni_syscall, /* ppc64_swapcontext */
286 [__NR_tgkill] sys_tgkill,
287 [__NR_utimes] sys_utimes,
288 [__NR_statfs64] sys_statfs64,
289 [__NR_fstatfs64] sys_fstatfs64,
290 [254] sys_ni_syscall,
291 [__NR_rtas] ppc_rtas,
292 [256] sys_ni_syscall,
293 [257] sys_ni_syscall,
294 [258] sys_ni_syscall,
295 [__NR_mbind] sys_ni_syscall, /* sys_mbind */
296 [__NR_get_mempolicy] sys_ni_syscall, /* sys_get_mempolicy */
297 [__NR_set_mempolicy] sys_ni_syscall, /* sys_set_mempolicy */
298 [__NR_mq_open] sys_ni_syscall, /* sys_mq_open */
299 [__NR_mq_unlink] sys_ni_syscall, /* sys_mq_unlink */
300 [__NR_mq_timedsend] sys_ni_syscall, /* sys_mq_timedsend */
301 [__NR_mq_timedreceive] sys_ni_syscall, /* sys_mq_timedreceive */
302 [__NR_mq_notify] sys_ni_syscall, /* sys_mq_notify */
303 [__NR_mq_getsetattr] sys_ni_syscall, /* sys_mq_getsetattr */
304 [__NR_kexec_load] sys_ni_syscall, /* sys_kexec_load */
305 [__NR_add_key] sys_ni_syscall, /* sys_add_key */
306 [__NR_request_key] sys_ni_syscall, /* sys_request_key */
307 [__NR_keyctl] sys_ni_syscall, /* sys_keyctl */
308 [__NR_waitid] sys_ni_syscall, /* sys_waitid */
309 [__NR_ioprio_set] sys_ni_syscall, /* sys_ioprio_set */
310 [__NR_ioprio_get] sys_ni_syscall, /* sys_ioprio_get */
311 [__NR_inotify_init] sys_ni_syscall, /* sys_inotify_init */
312 [__NR_inotify_add_watch] sys_ni_syscall, /* sys_inotify_add_watch */
313 [__NR_inotify_rm_watch] sys_ni_syscall, /* sys_inotify_rm_watch */
314 [__NR_spu_run] sys_ni_syscall, /* sys_spu_run */
315 [__NR_spu_create] sys_ni_syscall, /* sys_spu_create */
316 [__NR_pselect6] sys_ni_syscall, /* sys_pselect */
317 [__NR_ppoll] sys_ni_syscall, /* sys_ppoll */
318 [__NR_unshare] sys_unshare,
319};
320
321long spu_sys_callback(struct spu_syscall_block *s)
322{
323 long (*syscall)(u64 a1, u64 a2, u64 a3, u64 a4, u64 a5, u64 a6);
324
325 BUILD_BUG_ON(ARRAY_SIZE(spu_syscall_table) != __NR_syscalls);
326
327 syscall = spu_syscall_table[s->nr_ret];
328
329 if (s->nr_ret >= __NR_syscalls) {
330 pr_debug("%s: invalid syscall #%ld", __FUNCTION__, s->nr_ret);
331 return -ENOSYS;
332 }
333
334#ifdef DEBUG
335 print_symbol(KERN_DEBUG "SPU-syscall %s:", (unsigned long)syscall);
336 printk("syscall%ld(%lx, %lx, %lx, %lx, %lx, %lx)\n",
337 s->nr_ret,
338 s->parm[0], s->parm[1], s->parm[2],
339 s->parm[3], s->parm[4], s->parm[5]);
340#endif
341
342 return syscall(s->parm[0], s->parm[1], s->parm[2],
343 s->parm[3], s->parm[4], s->parm[5]);
344}
345EXPORT_SYMBOL_GPL(spu_sys_callback);
diff --git a/arch/powerpc/platforms/cell/spufs/backing_ops.c b/arch/powerpc/platforms/cell/spufs/backing_ops.c
index a5c489a53c61..f1d35ddc9df3 100644
--- a/arch/powerpc/platforms/cell/spufs/backing_ops.c
+++ b/arch/powerpc/platforms/cell/spufs/backing_ops.c
@@ -285,6 +285,49 @@ static void spu_backing_runcntl_stop(struct spu_context *ctx)
285 spu_backing_runcntl_write(ctx, SPU_RUNCNTL_STOP); 285 spu_backing_runcntl_write(ctx, SPU_RUNCNTL_STOP);
286} 286}
287 287
288static int spu_backing_set_mfc_query(struct spu_context * ctx, u32 mask,
289 u32 mode)
290{
291 struct spu_problem_collapsed *prob = &ctx->csa.prob;
292 int ret;
293
294 spin_lock(&ctx->csa.register_lock);
295 ret = -EAGAIN;
296 if (prob->dma_querytype_RW)
297 goto out;
298 ret = 0;
299 /* FIXME: what are the side-effects of this? */
300 prob->dma_querymask_RW = mask;
301 prob->dma_querytype_RW = mode;
302out:
303 spin_unlock(&ctx->csa.register_lock);
304
305 return ret;
306}
307
308static u32 spu_backing_read_mfc_tagstatus(struct spu_context * ctx)
309{
310 return ctx->csa.prob.dma_tagstatus_R;
311}
312
313static u32 spu_backing_get_mfc_free_elements(struct spu_context *ctx)
314{
315 return ctx->csa.prob.dma_qstatus_R;
316}
317
318static int spu_backing_send_mfc_command(struct spu_context *ctx,
319 struct mfc_dma_command *cmd)
320{
321 int ret;
322
323 spin_lock(&ctx->csa.register_lock);
324 ret = -EAGAIN;
325 /* FIXME: set up priv2->puq */
326 spin_unlock(&ctx->csa.register_lock);
327
328 return ret;
329}
330
288struct spu_context_ops spu_backing_ops = { 331struct spu_context_ops spu_backing_ops = {
289 .mbox_read = spu_backing_mbox_read, 332 .mbox_read = spu_backing_mbox_read,
290 .mbox_stat_read = spu_backing_mbox_stat_read, 333 .mbox_stat_read = spu_backing_mbox_stat_read,
@@ -305,4 +348,8 @@ struct spu_context_ops spu_backing_ops = {
305 .get_ls = spu_backing_get_ls, 348 .get_ls = spu_backing_get_ls,
306 .runcntl_write = spu_backing_runcntl_write, 349 .runcntl_write = spu_backing_runcntl_write,
307 .runcntl_stop = spu_backing_runcntl_stop, 350 .runcntl_stop = spu_backing_runcntl_stop,
351 .set_mfc_query = spu_backing_set_mfc_query,
352 .read_mfc_tagstatus = spu_backing_read_mfc_tagstatus,
353 .get_mfc_free_elements = spu_backing_get_mfc_free_elements,
354 .send_mfc_command = spu_backing_send_mfc_command,
308}; 355};
diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c
index 336f238102fd..8bb33abfad17 100644
--- a/arch/powerpc/platforms/cell/spufs/context.c
+++ b/arch/powerpc/platforms/cell/spufs/context.c
@@ -27,7 +27,7 @@
27#include <asm/spu_csa.h> 27#include <asm/spu_csa.h>
28#include "spufs.h" 28#include "spufs.h"
29 29
30struct spu_context *alloc_spu_context(struct address_space *local_store) 30struct spu_context *alloc_spu_context(void)
31{ 31{
32 struct spu_context *ctx; 32 struct spu_context *ctx;
33 ctx = kmalloc(sizeof *ctx, GFP_KERNEL); 33 ctx = kmalloc(sizeof *ctx, GFP_KERNEL);
@@ -47,10 +47,17 @@ struct spu_context *alloc_spu_context(struct address_space *local_store)
47 init_waitqueue_head(&ctx->ibox_wq); 47 init_waitqueue_head(&ctx->ibox_wq);
48 init_waitqueue_head(&ctx->wbox_wq); 48 init_waitqueue_head(&ctx->wbox_wq);
49 init_waitqueue_head(&ctx->stop_wq); 49 init_waitqueue_head(&ctx->stop_wq);
50 init_waitqueue_head(&ctx->mfc_wq);
50 ctx->ibox_fasync = NULL; 51 ctx->ibox_fasync = NULL;
51 ctx->wbox_fasync = NULL; 52 ctx->wbox_fasync = NULL;
53 ctx->mfc_fasync = NULL;
54 ctx->mfc = NULL;
55 ctx->tagwait = 0;
52 ctx->state = SPU_STATE_SAVED; 56 ctx->state = SPU_STATE_SAVED;
53 ctx->local_store = local_store; 57 ctx->local_store = NULL;
58 ctx->cntl = NULL;
59 ctx->signal1 = NULL;
60 ctx->signal2 = NULL;
54 ctx->spu = NULL; 61 ctx->spu = NULL;
55 ctx->ops = &spu_backing_ops; 62 ctx->ops = &spu_backing_ops;
56 ctx->owner = get_task_mm(current); 63 ctx->owner = get_task_mm(current);
@@ -68,8 +75,6 @@ void destroy_spu_context(struct kref *kref)
68 ctx = container_of(kref, struct spu_context, kref); 75 ctx = container_of(kref, struct spu_context, kref);
69 down_write(&ctx->state_sema); 76 down_write(&ctx->state_sema);
70 spu_deactivate(ctx); 77 spu_deactivate(ctx);
71 ctx->ibox_fasync = NULL;
72 ctx->wbox_fasync = NULL;
73 up_write(&ctx->state_sema); 78 up_write(&ctx->state_sema);
74 spu_fini_csa(&ctx->csa); 79 spu_fini_csa(&ctx->csa);
75 kfree(ctx); 80 kfree(ctx);
@@ -109,7 +114,16 @@ void spu_release(struct spu_context *ctx)
109 114
110void spu_unmap_mappings(struct spu_context *ctx) 115void spu_unmap_mappings(struct spu_context *ctx)
111{ 116{
112 unmap_mapping_range(ctx->local_store, 0, LS_SIZE, 1); 117 if (ctx->local_store)
118 unmap_mapping_range(ctx->local_store, 0, LS_SIZE, 1);
119 if (ctx->mfc)
120 unmap_mapping_range(ctx->mfc, 0, 0x4000, 1);
121 if (ctx->cntl)
122 unmap_mapping_range(ctx->cntl, 0, 0x4000, 1);
123 if (ctx->signal1)
124 unmap_mapping_range(ctx->signal1, 0, 0x4000, 1);
125 if (ctx->signal2)
126 unmap_mapping_range(ctx->signal2, 0, 0x4000, 1);
113} 127}
114 128
115int spu_acquire_runnable(struct spu_context *ctx) 129int spu_acquire_runnable(struct spu_context *ctx)
diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c
index dfa649c9b956..366185e92667 100644
--- a/arch/powerpc/platforms/cell/spufs/file.c
+++ b/arch/powerpc/platforms/cell/spufs/file.c
@@ -20,6 +20,8 @@
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */ 21 */
22 22
23#undef DEBUG
24
23#include <linux/fs.h> 25#include <linux/fs.h>
24#include <linux/ioctl.h> 26#include <linux/ioctl.h>
25#include <linux/module.h> 27#include <linux/module.h>
@@ -39,8 +41,10 @@ static int
39spufs_mem_open(struct inode *inode, struct file *file) 41spufs_mem_open(struct inode *inode, struct file *file)
40{ 42{
41 struct spufs_inode_info *i = SPUFS_I(inode); 43 struct spufs_inode_info *i = SPUFS_I(inode);
42 file->private_data = i->i_ctx; 44 struct spu_context *ctx = i->i_ctx;
43 file->f_mapping = i->i_ctx->local_store; 45 file->private_data = ctx;
46 file->f_mapping = inode->i_mapping;
47 ctx->local_store = inode->i_mapping;
44 return 0; 48 return 0;
45} 49}
46 50
@@ -84,7 +88,7 @@ spufs_mem_write(struct file *file, const char __user *buffer,
84 return ret; 88 return ret;
85} 89}
86 90
87#ifdef CONFIG_SPARSEMEM 91#ifdef CONFIG_SPUFS_MMAP
88static struct page * 92static struct page *
89spufs_mem_mmap_nopage(struct vm_area_struct *vma, 93spufs_mem_mmap_nopage(struct vm_area_struct *vma,
90 unsigned long address, int *type) 94 unsigned long address, int *type)
@@ -136,11 +140,113 @@ static struct file_operations spufs_mem_fops = {
136 .read = spufs_mem_read, 140 .read = spufs_mem_read,
137 .write = spufs_mem_write, 141 .write = spufs_mem_write,
138 .llseek = generic_file_llseek, 142 .llseek = generic_file_llseek,
139#ifdef CONFIG_SPARSEMEM 143#ifdef CONFIG_SPUFS_MMAP
140 .mmap = spufs_mem_mmap, 144 .mmap = spufs_mem_mmap,
141#endif 145#endif
142}; 146};
143 147
148#ifdef CONFIG_SPUFS_MMAP
149static struct page *spufs_ps_nopage(struct vm_area_struct *vma,
150 unsigned long address,
151 int *type, unsigned long ps_offs)
152{
153 struct page *page = NOPAGE_SIGBUS;
154 int fault_type = VM_FAULT_SIGBUS;
155 struct spu_context *ctx = vma->vm_file->private_data;
156 unsigned long offset = address - vma->vm_start;
157 unsigned long area;
158 int ret;
159
160 offset += vma->vm_pgoff << PAGE_SHIFT;
161 if (offset >= 0x4000)
162 goto out;
163
164 ret = spu_acquire_runnable(ctx);
165 if (ret)
166 goto out;
167
168 area = ctx->spu->problem_phys + ps_offs;
169 page = pfn_to_page((area + offset) >> PAGE_SHIFT);
170 fault_type = VM_FAULT_MINOR;
171 page_cache_get(page);
172
173 spu_release(ctx);
174
175 out:
176 if (type)
177 *type = fault_type;
178
179 return page;
180}
181
182static struct page *spufs_cntl_mmap_nopage(struct vm_area_struct *vma,
183 unsigned long address, int *type)
184{
185 return spufs_ps_nopage(vma, address, type, 0x4000);
186}
187
188static struct vm_operations_struct spufs_cntl_mmap_vmops = {
189 .nopage = spufs_cntl_mmap_nopage,
190};
191
192/*
193 * mmap support for problem state control area [0x4000 - 0x4fff].
194 * Mapping this area requires that the application have CAP_SYS_RAWIO,
195 * as these registers require special care when read/writing.
196 */
197static int spufs_cntl_mmap(struct file *file, struct vm_area_struct *vma)
198{
199 if (!(vma->vm_flags & VM_SHARED))
200 return -EINVAL;
201
202 if (!capable(CAP_SYS_RAWIO))
203 return -EPERM;
204
205 vma->vm_flags |= VM_RESERVED;
206 vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
207 | _PAGE_NO_CACHE);
208
209 vma->vm_ops = &spufs_cntl_mmap_vmops;
210 return 0;
211}
212#endif
213
214static int spufs_cntl_open(struct inode *inode, struct file *file)
215{
216 struct spufs_inode_info *i = SPUFS_I(inode);
217 struct spu_context *ctx = i->i_ctx;
218
219 file->private_data = ctx;
220 file->f_mapping = inode->i_mapping;
221 ctx->cntl = inode->i_mapping;
222 return 0;
223}
224
225static ssize_t
226spufs_cntl_read(struct file *file, char __user *buffer,
227 size_t size, loff_t *pos)
228{
229 /* FIXME: read from spu status */
230 return -EINVAL;
231}
232
233static ssize_t
234spufs_cntl_write(struct file *file, const char __user *buffer,
235 size_t size, loff_t *pos)
236{
237 /* FIXME: write to runctl bit */
238 return -EINVAL;
239}
240
241static struct file_operations spufs_cntl_fops = {
242 .open = spufs_cntl_open,
243 .read = spufs_cntl_read,
244 .write = spufs_cntl_write,
245#ifdef CONFIG_SPUFS_MMAP
246 .mmap = spufs_cntl_mmap,
247#endif
248};
249
144static int 250static int
145spufs_regs_open(struct inode *inode, struct file *file) 251spufs_regs_open(struct inode *inode, struct file *file)
146{ 252{
@@ -501,6 +607,16 @@ static struct file_operations spufs_wbox_stat_fops = {
501 .read = spufs_wbox_stat_read, 607 .read = spufs_wbox_stat_read,
502}; 608};
503 609
610static int spufs_signal1_open(struct inode *inode, struct file *file)
611{
612 struct spufs_inode_info *i = SPUFS_I(inode);
613 struct spu_context *ctx = i->i_ctx;
614 file->private_data = ctx;
615 file->f_mapping = inode->i_mapping;
616 ctx->signal1 = inode->i_mapping;
617 return nonseekable_open(inode, file);
618}
619
504static ssize_t spufs_signal1_read(struct file *file, char __user *buf, 620static ssize_t spufs_signal1_read(struct file *file, char __user *buf,
505 size_t len, loff_t *pos) 621 size_t len, loff_t *pos)
506{ 622{
@@ -541,12 +657,50 @@ static ssize_t spufs_signal1_write(struct file *file, const char __user *buf,
541 return 4; 657 return 4;
542} 658}
543 659
660#ifdef CONFIG_SPUFS_MMAP
661static struct page *spufs_signal1_mmap_nopage(struct vm_area_struct *vma,
662 unsigned long address, int *type)
663{
664 return spufs_ps_nopage(vma, address, type, 0x14000);
665}
666
667static struct vm_operations_struct spufs_signal1_mmap_vmops = {
668 .nopage = spufs_signal1_mmap_nopage,
669};
670
671static int spufs_signal1_mmap(struct file *file, struct vm_area_struct *vma)
672{
673 if (!(vma->vm_flags & VM_SHARED))
674 return -EINVAL;
675
676 vma->vm_flags |= VM_RESERVED;
677 vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
678 | _PAGE_NO_CACHE);
679
680 vma->vm_ops = &spufs_signal1_mmap_vmops;
681 return 0;
682}
683#endif
684
544static struct file_operations spufs_signal1_fops = { 685static struct file_operations spufs_signal1_fops = {
545 .open = spufs_pipe_open, 686 .open = spufs_signal1_open,
546 .read = spufs_signal1_read, 687 .read = spufs_signal1_read,
547 .write = spufs_signal1_write, 688 .write = spufs_signal1_write,
689#ifdef CONFIG_SPUFS_MMAP
690 .mmap = spufs_signal1_mmap,
691#endif
548}; 692};
549 693
694static int spufs_signal2_open(struct inode *inode, struct file *file)
695{
696 struct spufs_inode_info *i = SPUFS_I(inode);
697 struct spu_context *ctx = i->i_ctx;
698 file->private_data = ctx;
699 file->f_mapping = inode->i_mapping;
700 ctx->signal2 = inode->i_mapping;
701 return nonseekable_open(inode, file);
702}
703
550static ssize_t spufs_signal2_read(struct file *file, char __user *buf, 704static ssize_t spufs_signal2_read(struct file *file, char __user *buf,
551 size_t len, loff_t *pos) 705 size_t len, loff_t *pos)
552{ 706{
@@ -589,10 +743,39 @@ static ssize_t spufs_signal2_write(struct file *file, const char __user *buf,
589 return 4; 743 return 4;
590} 744}
591 745
746#ifdef CONFIG_SPUFS_MMAP
747static struct page *spufs_signal2_mmap_nopage(struct vm_area_struct *vma,
748 unsigned long address, int *type)
749{
750 return spufs_ps_nopage(vma, address, type, 0x1c000);
751}
752
753static struct vm_operations_struct spufs_signal2_mmap_vmops = {
754 .nopage = spufs_signal2_mmap_nopage,
755};
756
757static int spufs_signal2_mmap(struct file *file, struct vm_area_struct *vma)
758{
759 if (!(vma->vm_flags & VM_SHARED))
760 return -EINVAL;
761
762 /* FIXME: */
763 vma->vm_flags |= VM_RESERVED;
764 vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
765 | _PAGE_NO_CACHE);
766
767 vma->vm_ops = &spufs_signal2_mmap_vmops;
768 return 0;
769}
770#endif
771
592static struct file_operations spufs_signal2_fops = { 772static struct file_operations spufs_signal2_fops = {
593 .open = spufs_pipe_open, 773 .open = spufs_signal2_open,
594 .read = spufs_signal2_read, 774 .read = spufs_signal2_read,
595 .write = spufs_signal2_write, 775 .write = spufs_signal2_write,
776#ifdef CONFIG_SPUFS_MMAP
777 .mmap = spufs_signal2_mmap,
778#endif
596}; 779};
597 780
598static void spufs_signal1_type_set(void *data, u64 val) 781static void spufs_signal1_type_set(void *data, u64 val)
@@ -641,6 +824,332 @@ static u64 spufs_signal2_type_get(void *data)
641DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get, 824DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get,
642 spufs_signal2_type_set, "%llu"); 825 spufs_signal2_type_set, "%llu");
643 826
827#ifdef CONFIG_SPUFS_MMAP
828static struct page *spufs_mfc_mmap_nopage(struct vm_area_struct *vma,
829 unsigned long address, int *type)
830{
831 return spufs_ps_nopage(vma, address, type, 0x3000);
832}
833
834static struct vm_operations_struct spufs_mfc_mmap_vmops = {
835 .nopage = spufs_mfc_mmap_nopage,
836};
837
838/*
839 * mmap support for problem state MFC DMA area [0x0000 - 0x0fff].
840 * Mapping this area requires that the application have CAP_SYS_RAWIO,
841 * as these registers require special care when read/writing.
842 */
843static int spufs_mfc_mmap(struct file *file, struct vm_area_struct *vma)
844{
845 if (!(vma->vm_flags & VM_SHARED))
846 return -EINVAL;
847
848 if (!capable(CAP_SYS_RAWIO))
849 return -EPERM;
850
851 vma->vm_flags |= VM_RESERVED;
852 vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
853 | _PAGE_NO_CACHE);
854
855 vma->vm_ops = &spufs_mfc_mmap_vmops;
856 return 0;
857}
858#endif
859
860static int spufs_mfc_open(struct inode *inode, struct file *file)
861{
862 struct spufs_inode_info *i = SPUFS_I(inode);
863 struct spu_context *ctx = i->i_ctx;
864
865 /* we don't want to deal with DMA into other processes */
866 if (ctx->owner != current->mm)
867 return -EINVAL;
868
869 if (atomic_read(&inode->i_count) != 1)
870 return -EBUSY;
871
872 file->private_data = ctx;
873 return nonseekable_open(inode, file);
874}
875
876/* interrupt-level mfc callback function. */
877void spufs_mfc_callback(struct spu *spu)
878{
879 struct spu_context *ctx = spu->ctx;
880
881 wake_up_all(&ctx->mfc_wq);
882
883 pr_debug("%s %s\n", __FUNCTION__, spu->name);
884 if (ctx->mfc_fasync) {
885 u32 free_elements, tagstatus;
886 unsigned int mask;
887
888 /* no need for spu_acquire in interrupt context */
889 free_elements = ctx->ops->get_mfc_free_elements(ctx);
890 tagstatus = ctx->ops->read_mfc_tagstatus(ctx);
891
892 mask = 0;
893 if (free_elements & 0xffff)
894 mask |= POLLOUT;
895 if (tagstatus & ctx->tagwait)
896 mask |= POLLIN;
897
898 kill_fasync(&ctx->mfc_fasync, SIGIO, mask);
899 }
900}
901
902static int spufs_read_mfc_tagstatus(struct spu_context *ctx, u32 *status)
903{
904 /* See if there is one tag group is complete */
905 /* FIXME we need locking around tagwait */
906 *status = ctx->ops->read_mfc_tagstatus(ctx) & ctx->tagwait;
907 ctx->tagwait &= ~*status;
908 if (*status)
909 return 1;
910
911 /* enable interrupt waiting for any tag group,
912 may silently fail if interrupts are already enabled */
913 ctx->ops->set_mfc_query(ctx, ctx->tagwait, 1);
914 return 0;
915}
916
917static ssize_t spufs_mfc_read(struct file *file, char __user *buffer,
918 size_t size, loff_t *pos)
919{
920 struct spu_context *ctx = file->private_data;
921 int ret = -EINVAL;
922 u32 status;
923
924 if (size != 4)
925 goto out;
926
927 spu_acquire(ctx);
928 if (file->f_flags & O_NONBLOCK) {
929 status = ctx->ops->read_mfc_tagstatus(ctx);
930 if (!(status & ctx->tagwait))
931 ret = -EAGAIN;
932 else
933 ctx->tagwait &= ~status;
934 } else {
935 ret = spufs_wait(ctx->mfc_wq,
936 spufs_read_mfc_tagstatus(ctx, &status));
937 }
938 spu_release(ctx);
939
940 if (ret)
941 goto out;
942
943 ret = 4;
944 if (copy_to_user(buffer, &status, 4))
945 ret = -EFAULT;
946
947out:
948 return ret;
949}
950
951static int spufs_check_valid_dma(struct mfc_dma_command *cmd)
952{
953 pr_debug("queueing DMA %x %lx %x %x %x\n", cmd->lsa,
954 cmd->ea, cmd->size, cmd->tag, cmd->cmd);
955
956 switch (cmd->cmd) {
957 case MFC_PUT_CMD:
958 case MFC_PUTF_CMD:
959 case MFC_PUTB_CMD:
960 case MFC_GET_CMD:
961 case MFC_GETF_CMD:
962 case MFC_GETB_CMD:
963 break;
964 default:
965 pr_debug("invalid DMA opcode %x\n", cmd->cmd);
966 return -EIO;
967 }
968
969 if ((cmd->lsa & 0xf) != (cmd->ea &0xf)) {
970 pr_debug("invalid DMA alignment, ea %lx lsa %x\n",
971 cmd->ea, cmd->lsa);
972 return -EIO;
973 }
974
975 switch (cmd->size & 0xf) {
976 case 1:
977 break;
978 case 2:
979 if (cmd->lsa & 1)
980 goto error;
981 break;
982 case 4:
983 if (cmd->lsa & 3)
984 goto error;
985 break;
986 case 8:
987 if (cmd->lsa & 7)
988 goto error;
989 break;
990 case 0:
991 if (cmd->lsa & 15)
992 goto error;
993 break;
994 error:
995 default:
996 pr_debug("invalid DMA alignment %x for size %x\n",
997 cmd->lsa & 0xf, cmd->size);
998 return -EIO;
999 }
1000
1001 if (cmd->size > 16 * 1024) {
1002 pr_debug("invalid DMA size %x\n", cmd->size);
1003 return -EIO;
1004 }
1005
1006 if (cmd->tag & 0xfff0) {
1007 /* we reserve the higher tag numbers for kernel use */
1008 pr_debug("invalid DMA tag\n");
1009 return -EIO;
1010 }
1011
1012 if (cmd->class) {
1013 /* not supported in this version */
1014 pr_debug("invalid DMA class\n");
1015 return -EIO;
1016 }
1017
1018 return 0;
1019}
1020
1021static int spu_send_mfc_command(struct spu_context *ctx,
1022 struct mfc_dma_command cmd,
1023 int *error)
1024{
1025 *error = ctx->ops->send_mfc_command(ctx, &cmd);
1026 if (*error == -EAGAIN) {
1027 /* wait for any tag group to complete
1028 so we have space for the new command */
1029 ctx->ops->set_mfc_query(ctx, ctx->tagwait, 1);
1030 /* try again, because the queue might be
1031 empty again */
1032 *error = ctx->ops->send_mfc_command(ctx, &cmd);
1033 if (*error == -EAGAIN)
1034 return 0;
1035 }
1036 return 1;
1037}
1038
1039static ssize_t spufs_mfc_write(struct file *file, const char __user *buffer,
1040 size_t size, loff_t *pos)
1041{
1042 struct spu_context *ctx = file->private_data;
1043 struct mfc_dma_command cmd;
1044 int ret = -EINVAL;
1045
1046 if (size != sizeof cmd)
1047 goto out;
1048
1049 ret = -EFAULT;
1050 if (copy_from_user(&cmd, buffer, sizeof cmd))
1051 goto out;
1052
1053 ret = spufs_check_valid_dma(&cmd);
1054 if (ret)
1055 goto out;
1056
1057 spu_acquire_runnable(ctx);
1058 if (file->f_flags & O_NONBLOCK) {
1059 ret = ctx->ops->send_mfc_command(ctx, &cmd);
1060 } else {
1061 int status;
1062 ret = spufs_wait(ctx->mfc_wq,
1063 spu_send_mfc_command(ctx, cmd, &status));
1064 if (status)
1065 ret = status;
1066 }
1067 spu_release(ctx);
1068
1069 if (ret)
1070 goto out;
1071
1072 ctx->tagwait |= 1 << cmd.tag;
1073
1074out:
1075 return ret;
1076}
1077
1078static unsigned int spufs_mfc_poll(struct file *file,poll_table *wait)
1079{
1080 struct spu_context *ctx = file->private_data;
1081 u32 free_elements, tagstatus;
1082 unsigned int mask;
1083
1084 spu_acquire(ctx);
1085 ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2);
1086 free_elements = ctx->ops->get_mfc_free_elements(ctx);
1087 tagstatus = ctx->ops->read_mfc_tagstatus(ctx);
1088 spu_release(ctx);
1089
1090 poll_wait(file, &ctx->mfc_wq, wait);
1091
1092 mask = 0;
1093 if (free_elements & 0xffff)
1094 mask |= POLLOUT | POLLWRNORM;
1095 if (tagstatus & ctx->tagwait)
1096 mask |= POLLIN | POLLRDNORM;
1097
1098 pr_debug("%s: free %d tagstatus %d tagwait %d\n", __FUNCTION__,
1099 free_elements, tagstatus, ctx->tagwait);
1100
1101 return mask;
1102}
1103
1104static int spufs_mfc_flush(struct file *file)
1105{
1106 struct spu_context *ctx = file->private_data;
1107 int ret;
1108
1109 spu_acquire(ctx);
1110#if 0
1111/* this currently hangs */
1112 ret = spufs_wait(ctx->mfc_wq,
1113 ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2));
1114 if (ret)
1115 goto out;
1116 ret = spufs_wait(ctx->mfc_wq,
1117 ctx->ops->read_mfc_tagstatus(ctx) == ctx->tagwait);
1118out:
1119#else
1120 ret = 0;
1121#endif
1122 spu_release(ctx);
1123
1124 return ret;
1125}
1126
1127static int spufs_mfc_fsync(struct file *file, struct dentry *dentry,
1128 int datasync)
1129{
1130 return spufs_mfc_flush(file);
1131}
1132
1133static int spufs_mfc_fasync(int fd, struct file *file, int on)
1134{
1135 struct spu_context *ctx = file->private_data;
1136
1137 return fasync_helper(fd, file, on, &ctx->mfc_fasync);
1138}
1139
1140static struct file_operations spufs_mfc_fops = {
1141 .open = spufs_mfc_open,
1142 .read = spufs_mfc_read,
1143 .write = spufs_mfc_write,
1144 .poll = spufs_mfc_poll,
1145 .flush = spufs_mfc_flush,
1146 .fsync = spufs_mfc_fsync,
1147 .fasync = spufs_mfc_fasync,
1148#ifdef CONFIG_SPUFS_MMAP
1149 .mmap = spufs_mfc_mmap,
1150#endif
1151};
1152
644static void spufs_npc_set(void *data, u64 val) 1153static void spufs_npc_set(void *data, u64 val)
645{ 1154{
646 struct spu_context *ctx = data; 1155 struct spu_context *ctx = data;
@@ -783,6 +1292,8 @@ struct tree_descr spufs_dir_contents[] = {
783 { "signal2", &spufs_signal2_fops, 0666, }, 1292 { "signal2", &spufs_signal2_fops, 0666, },
784 { "signal1_type", &spufs_signal1_type, 0666, }, 1293 { "signal1_type", &spufs_signal1_type, 0666, },
785 { "signal2_type", &spufs_signal2_type, 0666, }, 1294 { "signal2_type", &spufs_signal2_type, 0666, },
1295 { "mfc", &spufs_mfc_fops, 0666, },
1296 { "cntl", &spufs_cntl_fops, 0666, },
786 { "npc", &spufs_npc_ops, 0666, }, 1297 { "npc", &spufs_npc_ops, 0666, },
787 { "fpcr", &spufs_fpcr_fops, 0666, }, 1298 { "fpcr", &spufs_fpcr_fops, 0666, },
788 { "decr", &spufs_decr_ops, 0666, }, 1299 { "decr", &spufs_decr_ops, 0666, },
diff --git a/arch/powerpc/platforms/cell/spufs/hw_ops.c b/arch/powerpc/platforms/cell/spufs/hw_ops.c
index 5445719bff79..a13a8b5a014d 100644
--- a/arch/powerpc/platforms/cell/spufs/hw_ops.c
+++ b/arch/powerpc/platforms/cell/spufs/hw_ops.c
@@ -232,6 +232,59 @@ static void spu_hw_runcntl_stop(struct spu_context *ctx)
232 spin_unlock_irq(&ctx->spu->register_lock); 232 spin_unlock_irq(&ctx->spu->register_lock);
233} 233}
234 234
235static int spu_hw_set_mfc_query(struct spu_context * ctx, u32 mask, u32 mode)
236{
237 struct spu_problem *prob = ctx->spu->problem;
238 int ret;
239
240 spin_lock_irq(&ctx->spu->register_lock);
241 ret = -EAGAIN;
242 if (in_be32(&prob->dma_querytype_RW))
243 goto out;
244 ret = 0;
245 out_be32(&prob->dma_querymask_RW, mask);
246 out_be32(&prob->dma_querytype_RW, mode);
247out:
248 spin_unlock_irq(&ctx->spu->register_lock);
249 return ret;
250}
251
252static u32 spu_hw_read_mfc_tagstatus(struct spu_context * ctx)
253{
254 return in_be32(&ctx->spu->problem->dma_tagstatus_R);
255}
256
257static u32 spu_hw_get_mfc_free_elements(struct spu_context *ctx)
258{
259 return in_be32(&ctx->spu->problem->dma_qstatus_R);
260}
261
262static int spu_hw_send_mfc_command(struct spu_context *ctx,
263 struct mfc_dma_command *cmd)
264{
265 u32 status;
266 struct spu_problem *prob = ctx->spu->problem;
267
268 spin_lock_irq(&ctx->spu->register_lock);
269 out_be32(&prob->mfc_lsa_W, cmd->lsa);
270 out_be64(&prob->mfc_ea_W, cmd->ea);
271 out_be32(&prob->mfc_union_W.by32.mfc_size_tag32,
272 cmd->size << 16 | cmd->tag);
273 out_be32(&prob->mfc_union_W.by32.mfc_class_cmd32,
274 cmd->class << 16 | cmd->cmd);
275 status = in_be32(&prob->mfc_union_W.by32.mfc_class_cmd32);
276 spin_unlock_irq(&ctx->spu->register_lock);
277
278 switch (status & 0xffff) {
279 case 0:
280 return 0;
281 case 2:
282 return -EAGAIN;
283 default:
284 return -EINVAL;
285 }
286}
287
235struct spu_context_ops spu_hw_ops = { 288struct spu_context_ops spu_hw_ops = {
236 .mbox_read = spu_hw_mbox_read, 289 .mbox_read = spu_hw_mbox_read,
237 .mbox_stat_read = spu_hw_mbox_stat_read, 290 .mbox_stat_read = spu_hw_mbox_stat_read,
@@ -252,4 +305,8 @@ struct spu_context_ops spu_hw_ops = {
252 .get_ls = spu_hw_get_ls, 305 .get_ls = spu_hw_get_ls,
253 .runcntl_write = spu_hw_runcntl_write, 306 .runcntl_write = spu_hw_runcntl_write,
254 .runcntl_stop = spu_hw_runcntl_stop, 307 .runcntl_stop = spu_hw_runcntl_stop,
308 .set_mfc_query = spu_hw_set_mfc_query,
309 .read_mfc_tagstatus = spu_hw_read_mfc_tagstatus,
310 .get_mfc_free_elements = spu_hw_get_mfc_free_elements,
311 .send_mfc_command = spu_hw_send_mfc_command,
255}; 312};
diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c
index 5be40aa483fd..d9554199afa7 100644
--- a/arch/powerpc/platforms/cell/spufs/inode.c
+++ b/arch/powerpc/platforms/cell/spufs/inode.c
@@ -241,7 +241,7 @@ spufs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
241 inode->i_gid = dir->i_gid; 241 inode->i_gid = dir->i_gid;
242 inode->i_mode &= S_ISGID; 242 inode->i_mode &= S_ISGID;
243 } 243 }
244 ctx = alloc_spu_context(inode->i_mapping); 244 ctx = alloc_spu_context();
245 SPUFS_I(inode)->i_ctx = ctx; 245 SPUFS_I(inode)->i_ctx = ctx;
246 if (!ctx) 246 if (!ctx)
247 goto out_iput; 247 goto out_iput;
@@ -442,7 +442,7 @@ static struct file_system_type spufs_type = {
442 .kill_sb = kill_litter_super, 442 .kill_sb = kill_litter_super,
443}; 443};
444 444
445static int spufs_init(void) 445static int __init spufs_init(void)
446{ 446{
447 int ret; 447 int ret;
448 ret = -ENOMEM; 448 ret = -ENOMEM;
@@ -472,7 +472,7 @@ out:
472} 472}
473module_init(spufs_init); 473module_init(spufs_init);
474 474
475static void spufs_exit(void) 475static void __exit spufs_exit(void)
476{ 476{
477 spu_sched_exit(); 477 spu_sched_exit();
478 unregister_spu_syscalls(&spufs_calls); 478 unregister_spu_syscalls(&spufs_calls);
diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c
index 18ea8866c61a..c04e078c0fe5 100644
--- a/arch/powerpc/platforms/cell/spufs/run.c
+++ b/arch/powerpc/platforms/cell/spufs/run.c
@@ -76,6 +76,90 @@ static inline int spu_reacquire_runnable(struct spu_context *ctx, u32 *npc,
76 return 0; 76 return 0;
77} 77}
78 78
79/*
80 * SPU syscall restarting is tricky because we violate the basic
81 * assumption that the signal handler is running on the interrupted
82 * thread. Here instead, the handler runs on PowerPC user space code,
83 * while the syscall was called from the SPU.
84 * This means we can only do a very rough approximation of POSIX
85 * signal semantics.
86 */
87int spu_handle_restartsys(struct spu_context *ctx, long *spu_ret,
88 unsigned int *npc)
89{
90 int ret;
91
92 switch (*spu_ret) {
93 case -ERESTARTSYS:
94 case -ERESTARTNOINTR:
95 /*
96 * Enter the regular syscall restarting for
97 * sys_spu_run, then restart the SPU syscall
98 * callback.
99 */
100 *npc -= 8;
101 ret = -ERESTARTSYS;
102 break;
103 case -ERESTARTNOHAND:
104 case -ERESTART_RESTARTBLOCK:
105 /*
106 * Restart block is too hard for now, just return -EINTR
107 * to the SPU.
108 * ERESTARTNOHAND comes from sys_pause, we also return
109 * -EINTR from there.
110 * Assume that we need to be restarted ourselves though.
111 */
112 *spu_ret = -EINTR;
113 ret = -ERESTARTSYS;
114 break;
115 default:
116 printk(KERN_WARNING "%s: unexpected return code %ld\n",
117 __FUNCTION__, *spu_ret);
118 ret = 0;
119 }
120 return ret;
121}
122
123int spu_process_callback(struct spu_context *ctx)
124{
125 struct spu_syscall_block s;
126 u32 ls_pointer, npc;
127 char *ls;
128 long spu_ret;
129 int ret;
130
131 /* get syscall block from local store */
132 npc = ctx->ops->npc_read(ctx);
133 ls = ctx->ops->get_ls(ctx);
134 ls_pointer = *(u32*)(ls + npc);
135 if (ls_pointer > (LS_SIZE - sizeof(s)))
136 return -EFAULT;
137 memcpy(&s, ls + ls_pointer, sizeof (s));
138
139 /* do actual syscall without pinning the spu */
140 ret = 0;
141 spu_ret = -ENOSYS;
142 npc += 4;
143
144 if (s.nr_ret < __NR_syscalls) {
145 spu_release(ctx);
146 /* do actual system call from here */
147 spu_ret = spu_sys_callback(&s);
148 if (spu_ret <= -ERESTARTSYS) {
149 ret = spu_handle_restartsys(ctx, &spu_ret, &npc);
150 }
151 spu_acquire(ctx);
152 if (ret == -ERESTARTSYS)
153 return ret;
154 }
155
156 /* write result, jump over indirect pointer */
157 memcpy(ls + ls_pointer, &spu_ret, sizeof (spu_ret));
158 ctx->ops->npc_write(ctx, npc);
159 ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE);
160 return ret;
161}
162
79static inline int spu_process_events(struct spu_context *ctx) 163static inline int spu_process_events(struct spu_context *ctx)
80{ 164{
81 struct spu *spu = ctx->spu; 165 struct spu *spu = ctx->spu;
@@ -107,6 +191,13 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx,
107 ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, status)); 191 ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, status));
108 if (unlikely(ret)) 192 if (unlikely(ret))
109 break; 193 break;
194 if ((*status & SPU_STATUS_STOPPED_BY_STOP) &&
195 (*status >> SPU_STOP_STATUS_SHIFT == 0x2104)) {
196 ret = spu_process_callback(ctx);
197 if (ret)
198 break;
199 *status &= ~SPU_STATUS_STOPPED_BY_STOP;
200 }
110 if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) { 201 if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) {
111 ret = spu_reacquire_runnable(ctx, npc, status); 202 ret = spu_reacquire_runnable(ctx, npc, status);
112 if (ret) 203 if (ret)
diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c
index 963182fbd1aa..bf652cd77000 100644
--- a/arch/powerpc/platforms/cell/spufs/sched.c
+++ b/arch/powerpc/platforms/cell/spufs/sched.c
@@ -180,6 +180,7 @@ static inline void bind_context(struct spu *spu, struct spu_context *ctx)
180 spu->ibox_callback = spufs_ibox_callback; 180 spu->ibox_callback = spufs_ibox_callback;
181 spu->wbox_callback = spufs_wbox_callback; 181 spu->wbox_callback = spufs_wbox_callback;
182 spu->stop_callback = spufs_stop_callback; 182 spu->stop_callback = spufs_stop_callback;
183 spu->mfc_callback = spufs_mfc_callback;
183 mb(); 184 mb();
184 spu_unmap_mappings(ctx); 185 spu_unmap_mappings(ctx);
185 spu_restore(&ctx->csa, spu); 186 spu_restore(&ctx->csa, spu);
@@ -197,6 +198,7 @@ static inline void unbind_context(struct spu *spu, struct spu_context *ctx)
197 spu->ibox_callback = NULL; 198 spu->ibox_callback = NULL;
198 spu->wbox_callback = NULL; 199 spu->wbox_callback = NULL;
199 spu->stop_callback = NULL; 200 spu->stop_callback = NULL;
201 spu->mfc_callback = NULL;
200 spu->mm = NULL; 202 spu->mm = NULL;
201 spu->pid = 0; 203 spu->pid = 0;
202 spu->prio = MAX_PRIO; 204 spu->prio = MAX_PRIO;
diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h
index db2601f0abd5..4485738e2102 100644
--- a/arch/powerpc/platforms/cell/spufs/spufs.h
+++ b/arch/powerpc/platforms/cell/spufs/spufs.h
@@ -43,7 +43,11 @@ struct spu_context {
43 struct spu *spu; /* pointer to a physical SPU */ 43 struct spu *spu; /* pointer to a physical SPU */
44 struct spu_state csa; /* SPU context save area. */ 44 struct spu_state csa; /* SPU context save area. */
45 spinlock_t mmio_lock; /* protects mmio access */ 45 spinlock_t mmio_lock; /* protects mmio access */
46 struct address_space *local_store;/* local store backing store */ 46 struct address_space *local_store; /* local store mapping. */
47 struct address_space *mfc; /* 'mfc' area mappings. */
48 struct address_space *cntl; /* 'control' area mappings. */
49 struct address_space *signal1; /* 'signal1' area mappings. */
50 struct address_space *signal2; /* 'signal2' area mappings. */
47 51
48 enum { SPU_STATE_RUNNABLE, SPU_STATE_SAVED } state; 52 enum { SPU_STATE_RUNNABLE, SPU_STATE_SAVED } state;
49 struct rw_semaphore state_sema; 53 struct rw_semaphore state_sema;
@@ -55,13 +59,27 @@ struct spu_context {
55 wait_queue_head_t ibox_wq; 59 wait_queue_head_t ibox_wq;
56 wait_queue_head_t wbox_wq; 60 wait_queue_head_t wbox_wq;
57 wait_queue_head_t stop_wq; 61 wait_queue_head_t stop_wq;
62 wait_queue_head_t mfc_wq;
58 struct fasync_struct *ibox_fasync; 63 struct fasync_struct *ibox_fasync;
59 struct fasync_struct *wbox_fasync; 64 struct fasync_struct *wbox_fasync;
65 struct fasync_struct *mfc_fasync;
66 u32 tagwait;
60 struct spu_context_ops *ops; 67 struct spu_context_ops *ops;
61 struct work_struct reap_work; 68 struct work_struct reap_work;
62 u64 flags; 69 u64 flags;
63}; 70};
64 71
72struct mfc_dma_command {
73 int32_t pad; /* reserved */
74 uint32_t lsa; /* local storage address */
75 uint64_t ea; /* effective address */
76 uint16_t size; /* transfer size */
77 uint16_t tag; /* command tag */
78 uint16_t class; /* class ID */
79 uint16_t cmd; /* command opcode */
80};
81
82
65/* SPU context query/set operations. */ 83/* SPU context query/set operations. */
66struct spu_context_ops { 84struct spu_context_ops {
67 int (*mbox_read) (struct spu_context * ctx, u32 * data); 85 int (*mbox_read) (struct spu_context * ctx, u32 * data);
@@ -84,6 +102,11 @@ struct spu_context_ops {
84 char*(*get_ls) (struct spu_context * ctx); 102 char*(*get_ls) (struct spu_context * ctx);
85 void (*runcntl_write) (struct spu_context * ctx, u32 data); 103 void (*runcntl_write) (struct spu_context * ctx, u32 data);
86 void (*runcntl_stop) (struct spu_context * ctx); 104 void (*runcntl_stop) (struct spu_context * ctx);
105 int (*set_mfc_query)(struct spu_context * ctx, u32 mask, u32 mode);
106 u32 (*read_mfc_tagstatus)(struct spu_context * ctx);
107 u32 (*get_mfc_free_elements)(struct spu_context *ctx);
108 int (*send_mfc_command)(struct spu_context *ctx,
109 struct mfc_dma_command *cmd);
87}; 110};
88 111
89extern struct spu_context_ops spu_hw_ops; 112extern struct spu_context_ops spu_hw_ops;
@@ -106,7 +129,7 @@ long spufs_create_thread(struct nameidata *nd,
106extern struct file_operations spufs_context_fops; 129extern struct file_operations spufs_context_fops;
107 130
108/* context management */ 131/* context management */
109struct spu_context * alloc_spu_context(struct address_space *local_store); 132struct spu_context * alloc_spu_context(void);
110void destroy_spu_context(struct kref *kref); 133void destroy_spu_context(struct kref *kref);
111struct spu_context * get_spu_context(struct spu_context *ctx); 134struct spu_context * get_spu_context(struct spu_context *ctx);
112int put_spu_context(struct spu_context *ctx); 135int put_spu_context(struct spu_context *ctx);
@@ -159,5 +182,6 @@ size_t spu_ibox_read(struct spu_context *ctx, u32 *data);
159void spufs_ibox_callback(struct spu *spu); 182void spufs_ibox_callback(struct spu *spu);
160void spufs_wbox_callback(struct spu *spu); 183void spufs_wbox_callback(struct spu *spu);
161void spufs_stop_callback(struct spu *spu); 184void spufs_stop_callback(struct spu *spu);
185void spufs_mfc_callback(struct spu *spu);
162 186
163#endif 187#endif
diff --git a/arch/powerpc/platforms/cell/spufs/switch.c b/arch/powerpc/platforms/cell/spufs/switch.c
index 212db28531fa..97898d5d34e5 100644
--- a/arch/powerpc/platforms/cell/spufs/switch.c
+++ b/arch/powerpc/platforms/cell/spufs/switch.c
@@ -2145,7 +2145,8 @@ static void init_priv1(struct spu_state *csa)
2145 csa->priv1.int_mask_class1_RW = CLASS1_ENABLE_SEGMENT_FAULT_INTR | 2145 csa->priv1.int_mask_class1_RW = CLASS1_ENABLE_SEGMENT_FAULT_INTR |
2146 CLASS1_ENABLE_STORAGE_FAULT_INTR; 2146 CLASS1_ENABLE_STORAGE_FAULT_INTR;
2147 csa->priv1.int_mask_class2_RW = CLASS2_ENABLE_SPU_STOP_INTR | 2147 csa->priv1.int_mask_class2_RW = CLASS2_ENABLE_SPU_STOP_INTR |
2148 CLASS2_ENABLE_SPU_HALT_INTR; 2148 CLASS2_ENABLE_SPU_HALT_INTR |
2149 CLASS2_ENABLE_SPU_DMA_TAG_GROUP_COMPLETE_INTR;
2149} 2150}
2150 2151
2151static void init_priv2(struct spu_state *csa) 2152static void init_priv2(struct spu_state *csa)
diff --git a/arch/powerpc/platforms/chrp/chrp.h b/arch/powerpc/platforms/chrp/chrp.h
index 814f54742e0f..63f0aee4c158 100644
--- a/arch/powerpc/platforms/chrp/chrp.h
+++ b/arch/powerpc/platforms/chrp/chrp.h
@@ -8,4 +8,4 @@ extern int chrp_set_rtc_time(struct rtc_time *);
8extern long chrp_time_init(void); 8extern long chrp_time_init(void);
9 9
10extern void chrp_find_bridges(void); 10extern void chrp_find_bridges(void);
11extern void chrp_event_scan(void); 11extern void chrp_event_scan(unsigned long);
diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c
index 8bf4307e323d..23a201718704 100644
--- a/arch/powerpc/platforms/chrp/setup.c
+++ b/arch/powerpc/platforms/chrp/setup.c
@@ -35,6 +35,7 @@
35#include <linux/root_dev.h> 35#include <linux/root_dev.h>
36#include <linux/initrd.h> 36#include <linux/initrd.h>
37#include <linux/module.h> 37#include <linux/module.h>
38#include <linux/timer.h>
38 39
39#include <asm/io.h> 40#include <asm/io.h>
40#include <asm/pgtable.h> 41#include <asm/pgtable.h>
@@ -61,6 +62,10 @@ EXPORT_SYMBOL(_chrp_type);
61 62
62struct mpic *chrp_mpic; 63struct mpic *chrp_mpic;
63 64
65/* Used for doing CHRP event-scans */
66DEFINE_PER_CPU(struct timer_list, heartbeat_timer);
67unsigned long event_scan_interval;
68
64/* 69/*
65 * XXX this should be in xmon.h, but putting it there means xmon.h 70 * XXX this should be in xmon.h, but putting it there means xmon.h
66 * has to include <linux/interrupt.h> (to get irqreturn_t), which 71 * has to include <linux/interrupt.h> (to get irqreturn_t), which
@@ -229,8 +234,6 @@ void __init chrp_setup_arch(void)
229{ 234{
230 struct device_node *root = find_path_device ("/"); 235 struct device_node *root = find_path_device ("/");
231 char *machine = NULL; 236 char *machine = NULL;
232 struct device_node *device;
233 unsigned int *p = NULL;
234 237
235 /* init to some ~sane value until calibrate_delay() runs */ 238 /* init to some ~sane value until calibrate_delay() runs */
236 loops_per_jiffy = 50000000/HZ; 239 loops_per_jiffy = 50000000/HZ;
@@ -287,23 +290,12 @@ void __init chrp_setup_arch(void)
287 */ 290 */
288 sio_init(); 291 sio_init();
289 292
290 /* Get the event scan rate for the rtas so we know how
291 * often it expects a heartbeat. -- Cort
292 */
293 device = find_devices("rtas");
294 if (device)
295 p = (unsigned int *) get_property
296 (device, "rtas-event-scan-rate", NULL);
297 if (p && *p) {
298 ppc_md.heartbeat = chrp_event_scan;
299 ppc_md.heartbeat_reset = HZ / (*p * 30) - 1;
300 ppc_md.heartbeat_count = 1;
301 printk("RTAS Event Scan Rate: %u (%lu jiffies)\n",
302 *p, ppc_md.heartbeat_reset);
303 }
304
305 pci_create_OF_bus_map(); 293 pci_create_OF_bus_map();
306 294
295#ifdef CONFIG_SMP
296 smp_ops = &chrp_smp_ops;
297#endif /* CONFIG_SMP */
298
307 /* 299 /*
308 * Print the banner, then scroll down so boot progress 300 * Print the banner, then scroll down so boot progress
309 * can be printed. -- Cort 301 * can be printed. -- Cort
@@ -312,7 +304,7 @@ void __init chrp_setup_arch(void)
312} 304}
313 305
314void 306void
315chrp_event_scan(void) 307chrp_event_scan(unsigned long unused)
316{ 308{
317 unsigned char log[1024]; 309 unsigned char log[1024];
318 int ret = 0; 310 int ret = 0;
@@ -320,7 +312,8 @@ chrp_event_scan(void)
320 /* XXX: we should loop until the hardware says no more error logs -- Cort */ 312 /* XXX: we should loop until the hardware says no more error logs -- Cort */
321 rtas_call(rtas_token("event-scan"), 4, 1, &ret, 0xffffffff, 0, 313 rtas_call(rtas_token("event-scan"), 4, 1, &ret, 0xffffffff, 0,
322 __pa(log), 1024); 314 __pa(log), 1024);
323 ppc_md.heartbeat_count = ppc_md.heartbeat_reset; 315 mod_timer(&__get_cpu_var(heartbeat_timer),
316 jiffies + event_scan_interval);
324} 317}
325 318
326/* 319/*
@@ -465,6 +458,9 @@ void __init chrp_init_IRQ(void)
465void __init 458void __init
466chrp_init2(void) 459chrp_init2(void)
467{ 460{
461 struct device_node *device;
462 unsigned int *p = NULL;
463
468#ifdef CONFIG_NVRAM 464#ifdef CONFIG_NVRAM
469 chrp_nvram_init(); 465 chrp_nvram_init();
470#endif 466#endif
@@ -476,12 +472,53 @@ chrp_init2(void)
476 request_region(0x80,0x10,"dma page reg"); 472 request_region(0x80,0x10,"dma page reg");
477 request_region(0xc0,0x20,"dma2"); 473 request_region(0xc0,0x20,"dma2");
478 474
475 /* Get the event scan rate for the rtas so we know how
476 * often it expects a heartbeat. -- Cort
477 */
478 device = find_devices("rtas");
479 if (device)
480 p = (unsigned int *) get_property
481 (device, "rtas-event-scan-rate", NULL);
482 if (p && *p) {
483 /*
484 * Arrange to call chrp_event_scan at least *p times
485 * per minute. We use 59 rather than 60 here so that
486 * the rate will be slightly higher than the minimum.
487 * This all assumes we don't do hotplug CPU on any
488 * machine that needs the event scans done.
489 */
490 unsigned long interval, offset;
491 int cpu, ncpus;
492 struct timer_list *timer;
493
494 interval = HZ * 59 / *p;
495 offset = HZ;
496 ncpus = num_online_cpus();
497 event_scan_interval = ncpus * interval;
498 for (cpu = 0; cpu < ncpus; ++cpu) {
499 timer = &per_cpu(heartbeat_timer, cpu);
500 setup_timer(timer, chrp_event_scan, 0);
501 timer->expires = jiffies + offset;
502 add_timer_on(timer, cpu);
503 offset += interval;
504 }
505 printk("RTAS Event Scan Rate: %u (%lu jiffies)\n",
506 *p, interval);
507 }
508
479 if (ppc_md.progress) 509 if (ppc_md.progress)
480 ppc_md.progress(" Have fun! ", 0x7777); 510 ppc_md.progress(" Have fun! ", 0x7777);
481} 511}
482 512
483void __init chrp_init(void) 513static int __init chrp_probe(void)
484{ 514{
515 char *dtype = of_get_flat_dt_prop(of_get_flat_dt_root(),
516 "device_type", NULL);
517 if (dtype == NULL)
518 return 0;
519 if (strcmp(dtype, "chrp"))
520 return 0;
521
485 ISA_DMA_THRESHOLD = ~0L; 522 ISA_DMA_THRESHOLD = ~0L;
486 DMA_MODE_READ = 0x44; 523 DMA_MODE_READ = 0x44;
487 DMA_MODE_WRITE = 0x48; 524 DMA_MODE_WRITE = 0x48;
diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c
index fa4550611c11..6ce8a404ba6b 100644
--- a/arch/powerpc/platforms/iseries/setup.c
+++ b/arch/powerpc/platforms/iseries/setup.c
@@ -675,18 +675,20 @@ static void iseries_dedicated_idle(void)
675void __init iSeries_init_IRQ(void) { } 675void __init iSeries_init_IRQ(void) { }
676#endif 676#endif
677 677
678static int __init iseries_probe(int platform) 678static int __init iseries_probe(void)
679{ 679{
680 if (PLATFORM_ISERIES_LPAR != platform) 680 unsigned long root = of_get_flat_dt_root();
681 if (!of_flat_dt_is_compatible(root, "IBM,iSeries"))
681 return 0; 682 return 0;
682 683
683 ppc64_firmware_features |= FW_FEATURE_ISERIES; 684 powerpc_firmware_features |= FW_FEATURE_ISERIES;
684 ppc64_firmware_features |= FW_FEATURE_LPAR; 685 powerpc_firmware_features |= FW_FEATURE_LPAR;
685 686
686 return 1; 687 return 1;
687} 688}
688 689
689struct machdep_calls __initdata iseries_md = { 690define_machine(iseries) {
691 .name = "iSeries",
690 .setup_arch = iSeries_setup_arch, 692 .setup_arch = iSeries_setup_arch,
691 .show_cpuinfo = iSeries_show_cpuinfo, 693 .show_cpuinfo = iSeries_show_cpuinfo,
692 .init_IRQ = iSeries_init_IRQ, 694 .init_IRQ = iSeries_init_IRQ,
@@ -930,7 +932,6 @@ void build_flat_dt(struct iseries_flat_dt *dt, unsigned long phys_mem_size)
930 932
931 /* /chosen */ 933 /* /chosen */
932 dt_start_node(dt, "chosen"); 934 dt_start_node(dt, "chosen");
933 dt_prop_u32(dt, "linux,platform", PLATFORM_ISERIES_LPAR);
934 dt_prop_str(dt, "bootargs", cmd_line); 935 dt_prop_str(dt, "bootargs", cmd_line);
935 if (cmd_mem_limit) 936 if (cmd_mem_limit)
936 dt_prop_u64(dt, "linux,memory-limit", cmd_mem_limit); 937 dt_prop_u64(dt, "linux,memory-limit", cmd_mem_limit);
diff --git a/arch/powerpc/platforms/maple/setup.c b/arch/powerpc/platforms/maple/setup.c
index ec5c1e10c407..24c0aef4ea39 100644
--- a/arch/powerpc/platforms/maple/setup.c
+++ b/arch/powerpc/platforms/maple/setup.c
@@ -259,9 +259,10 @@ static void __init maple_progress(char *s, unsigned short hex)
259/* 259/*
260 * Called very early, MMU is off, device-tree isn't unflattened 260 * Called very early, MMU is off, device-tree isn't unflattened
261 */ 261 */
262static int __init maple_probe(int platform) 262static int __init maple_probe(void)
263{ 263{
264 if (platform != PLATFORM_MAPLE) 264 unsigned long root = of_get_flat_dt_root();
265 if (!of_flat_dt_is_compatible(root, "Momentum,Maple"))
265 return 0; 266 return 0;
266 /* 267 /*
267 * On U3, the DART (iommu) must be allocated now since it 268 * On U3, the DART (iommu) must be allocated now since it
@@ -274,7 +275,8 @@ static int __init maple_probe(int platform)
274 return 1; 275 return 1;
275} 276}
276 277
277struct machdep_calls __initdata maple_md = { 278define_machine(maple_md) {
279 .name = "Maple",
278 .probe = maple_probe, 280 .probe = maple_probe,
279 .setup_arch = maple_setup_arch, 281 .setup_arch = maple_setup_arch,
280 .init_early = maple_init_early, 282 .init_early = maple_init_early,
@@ -290,7 +292,7 @@ struct machdep_calls __initdata maple_md = {
290 .get_rtc_time = maple_get_rtc_time, 292 .get_rtc_time = maple_get_rtc_time,
291 .calibrate_decr = generic_calibrate_decr, 293 .calibrate_decr = generic_calibrate_decr,
292 .progress = maple_progress, 294 .progress = maple_progress,
293 .idle_loop = native_idle, 295 .power_save = power4_idle,
294#ifdef CONFIG_KEXEC 296#ifdef CONFIG_KEXEC
295 .machine_kexec = default_machine_kexec, 297 .machine_kexec = default_machine_kexec,
296 .machine_kexec_prepare = default_machine_kexec_prepare, 298 .machine_kexec_prepare = default_machine_kexec_prepare,
diff --git a/arch/powerpc/platforms/powermac/bootx_init.c b/arch/powerpc/platforms/powermac/bootx_init.c
index fa8b4d7b5ded..eacbfd9beabc 100644
--- a/arch/powerpc/platforms/powermac/bootx_init.c
+++ b/arch/powerpc/platforms/powermac/bootx_init.c
@@ -161,9 +161,7 @@ static void __init bootx_dt_add_prop(char *name, void *data, int size,
161static void __init bootx_add_chosen_props(unsigned long base, 161static void __init bootx_add_chosen_props(unsigned long base,
162 unsigned long *mem_end) 162 unsigned long *mem_end)
163{ 163{
164 u32 val = _MACH_Pmac; 164 u32 val;
165
166 bootx_dt_add_prop("linux,platform", &val, 4, mem_end);
167 165
168 if (bootx_info->kernelParamsOffset) { 166 if (bootx_info->kernelParamsOffset) {
169 char *args = (char *)((unsigned long)bootx_info) + 167 char *args = (char *)((unsigned long)bootx_info) +
@@ -493,7 +491,7 @@ void __init bootx_init(unsigned long r3, unsigned long r4)
493 && (strcmp(model, "iMac,1") == 0 491 && (strcmp(model, "iMac,1") == 0
494 || strcmp(model, "PowerMac1,1") == 0)) { 492 || strcmp(model, "PowerMac1,1") == 0)) {
495 bootx_printf("iMac,1 detected, shutting down USB \n"); 493 bootx_printf("iMac,1 detected, shutting down USB \n");
496 out_le32((unsigned *)0x80880008, 1); /* XXX */ 494 out_le32((unsigned __iomem *)0x80880008, 1); /* XXX */
497 } 495 }
498 } 496 }
499 497
diff --git a/arch/powerpc/platforms/powermac/feature.c b/arch/powerpc/platforms/powermac/feature.c
index e49eddd5042d..a5063cd675c5 100644
--- a/arch/powerpc/platforms/powermac/feature.c
+++ b/arch/powerpc/platforms/powermac/feature.c
@@ -2951,7 +2951,7 @@ static void *pmac_early_vresume_data;
2951 2951
2952void pmac_set_early_video_resume(void (*proc)(void *data), void *data) 2952void pmac_set_early_video_resume(void (*proc)(void *data), void *data)
2953{ 2953{
2954 if (_machine != _MACH_Pmac) 2954 if (!machine_is(powermac))
2955 return; 2955 return;
2956 preempt_disable(); 2956 preempt_disable();
2957 pmac_early_vresume_proc = proc; 2957 pmac_early_vresume_proc = proc;
diff --git a/arch/powerpc/platforms/powermac/low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c
index 87eb6bb7f0e7..e14f9ac55cf4 100644
--- a/arch/powerpc/platforms/powermac/low_i2c.c
+++ b/arch/powerpc/platforms/powermac/low_i2c.c
@@ -1457,6 +1457,9 @@ int __init pmac_i2c_init(void)
1457 return 0; 1457 return 0;
1458 i2c_inited = 1; 1458 i2c_inited = 1;
1459 1459
1460 if (!machine_is(powermac))
1461 return 0;
1462
1460 /* Probe keywest-i2c busses */ 1463 /* Probe keywest-i2c busses */
1461 kw_i2c_probe(); 1464 kw_i2c_probe();
1462 1465
diff --git a/arch/powerpc/platforms/powermac/nvram.c b/arch/powerpc/platforms/powermac/nvram.c
index 5fd28995c74c..262f967b880a 100644
--- a/arch/powerpc/platforms/powermac/nvram.c
+++ b/arch/powerpc/platforms/powermac/nvram.c
@@ -74,7 +74,7 @@ struct core99_header {
74 * Read and write the non-volatile RAM on PowerMacs and CHRP machines. 74 * Read and write the non-volatile RAM on PowerMacs and CHRP machines.
75 */ 75 */
76static int nvram_naddrs; 76static int nvram_naddrs;
77static volatile unsigned char *nvram_data; 77static volatile unsigned char __iomem *nvram_data;
78static int is_core_99; 78static int is_core_99;
79static int core99_bank = 0; 79static int core99_bank = 0;
80static int nvram_partitions[3]; 80static int nvram_partitions[3];
@@ -148,7 +148,7 @@ static ssize_t core99_nvram_size(void)
148} 148}
149 149
150#ifdef CONFIG_PPC32 150#ifdef CONFIG_PPC32
151static volatile unsigned char *nvram_addr; 151static volatile unsigned char __iomem *nvram_addr;
152static int nvram_mult; 152static int nvram_mult;
153 153
154static unsigned char direct_nvram_read_byte(int addr) 154static unsigned char direct_nvram_read_byte(int addr)
@@ -285,7 +285,7 @@ static int sm_erase_bank(int bank)
285 int stat, i; 285 int stat, i;
286 unsigned long timeout; 286 unsigned long timeout;
287 287
288 u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE; 288 u8 __iomem *base = (u8 __iomem *)nvram_data + core99_bank*NVRAM_SIZE;
289 289
290 DBG("nvram: Sharp/Micron Erasing bank %d...\n", bank); 290 DBG("nvram: Sharp/Micron Erasing bank %d...\n", bank);
291 291
@@ -317,7 +317,7 @@ static int sm_write_bank(int bank, u8* datas)
317 int i, stat = 0; 317 int i, stat = 0;
318 unsigned long timeout; 318 unsigned long timeout;
319 319
320 u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE; 320 u8 __iomem *base = (u8 __iomem *)nvram_data + core99_bank*NVRAM_SIZE;
321 321
322 DBG("nvram: Sharp/Micron Writing bank %d...\n", bank); 322 DBG("nvram: Sharp/Micron Writing bank %d...\n", bank);
323 323
@@ -352,7 +352,7 @@ static int amd_erase_bank(int bank)
352 int i, stat = 0; 352 int i, stat = 0;
353 unsigned long timeout; 353 unsigned long timeout;
354 354
355 u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE; 355 u8 __iomem *base = (u8 __iomem *)nvram_data + core99_bank*NVRAM_SIZE;
356 356
357 DBG("nvram: AMD Erasing bank %d...\n", bank); 357 DBG("nvram: AMD Erasing bank %d...\n", bank);
358 358
@@ -399,7 +399,7 @@ static int amd_write_bank(int bank, u8* datas)
399 int i, stat = 0; 399 int i, stat = 0;
400 unsigned long timeout; 400 unsigned long timeout;
401 401
402 u8* base = (u8 *)nvram_data + core99_bank*NVRAM_SIZE; 402 u8 __iomem *base = (u8 __iomem *)nvram_data + core99_bank*NVRAM_SIZE;
403 403
404 DBG("nvram: AMD Writing bank %d...\n", bank); 404 DBG("nvram: AMD Writing bank %d...\n", bank);
405 405
@@ -597,7 +597,7 @@ int __init pmac_nvram_init(void)
597 } 597 }
598 598
599#ifdef CONFIG_PPC32 599#ifdef CONFIG_PPC32
600 if (_machine == _MACH_chrp && nvram_naddrs == 1) { 600 if (machine_is(chrp) && nvram_naddrs == 1) {
601 nvram_data = ioremap(r1.start, s1); 601 nvram_data = ioremap(r1.start, s1);
602 nvram_mult = 1; 602 nvram_mult = 1;
603 ppc_md.nvram_read_val = direct_nvram_read_byte; 603 ppc_md.nvram_read_val = direct_nvram_read_byte;
diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c
index de3f30e6b333..f5d8d15d74fa 100644
--- a/arch/powerpc/platforms/powermac/pci.c
+++ b/arch/powerpc/platforms/powermac/pci.c
@@ -1201,7 +1201,7 @@ void __init pmac_pcibios_after_init(void)
1201#ifdef CONFIG_PPC32 1201#ifdef CONFIG_PPC32
1202void pmac_pci_fixup_cardbus(struct pci_dev* dev) 1202void pmac_pci_fixup_cardbus(struct pci_dev* dev)
1203{ 1203{
1204 if (_machine != _MACH_Pmac) 1204 if (!machine_is(powermac))
1205 return; 1205 return;
1206 /* 1206 /*
1207 * Fix the interrupt routing on the various cardbus bridges 1207 * Fix the interrupt routing on the various cardbus bridges
@@ -1244,8 +1244,9 @@ void pmac_pci_fixup_pciata(struct pci_dev* dev)
1244 * On PowerMacs, we try to switch any PCI ATA controller to 1244 * On PowerMacs, we try to switch any PCI ATA controller to
1245 * fully native mode 1245 * fully native mode
1246 */ 1246 */
1247 if (_machine != _MACH_Pmac) 1247 if (!machine_is(powermac))
1248 return; 1248 return;
1249
1249 /* Some controllers don't have the class IDE */ 1250 /* Some controllers don't have the class IDE */
1250 if (dev->vendor == PCI_VENDOR_ID_PROMISE) 1251 if (dev->vendor == PCI_VENDOR_ID_PROMISE)
1251 switch(dev->device) { 1252 switch(dev->device) {
diff --git a/arch/powerpc/platforms/powermac/pfunc_base.c b/arch/powerpc/platforms/powermac/pfunc_base.c
index 9b7150f10414..a3bd3e728fa3 100644
--- a/arch/powerpc/platforms/powermac/pfunc_base.c
+++ b/arch/powerpc/platforms/powermac/pfunc_base.c
@@ -336,6 +336,8 @@ int __init pmac_pfunc_base_install(void)
336 return 0; 336 return 0;
337 pfbase_inited = 1; 337 pfbase_inited = 1;
338 338
339 if (!machine_is(powermac))
340 return 0;
339 341
340 DBG("Installing base platform functions...\n"); 342 DBG("Installing base platform functions...\n");
341 343
diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c
index 385aab90c4d2..4d15e396655c 100644
--- a/arch/powerpc/platforms/powermac/setup.c
+++ b/arch/powerpc/platforms/powermac/setup.c
@@ -350,6 +350,13 @@ static void __init pmac_setup_arch(void)
350 smp_ops = &psurge_smp_ops; 350 smp_ops = &psurge_smp_ops;
351#endif 351#endif
352#endif /* CONFIG_SMP */ 352#endif /* CONFIG_SMP */
353
354#ifdef CONFIG_ADB
355 if (strstr(cmd_line, "adb_sync")) {
356 extern int __adb_probe_sync;
357 __adb_probe_sync = 1;
358 }
359#endif /* CONFIG_ADB */
353} 360}
354 361
355char *bootpath; 362char *bootpath;
@@ -576,30 +583,6 @@ pmac_halt(void)
576 pmac_power_off(); 583 pmac_power_off();
577} 584}
578 585
579#ifdef CONFIG_PPC32
580void __init pmac_init(void)
581{
582 /* isa_io_base gets set in pmac_pci_init */
583 isa_mem_base = PMAC_ISA_MEM_BASE;
584 pci_dram_offset = PMAC_PCI_DRAM_OFFSET;
585 ISA_DMA_THRESHOLD = ~0L;
586 DMA_MODE_READ = 1;
587 DMA_MODE_WRITE = 2;
588
589 ppc_md = pmac_md;
590
591#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
592#ifdef CONFIG_BLK_DEV_IDE_PMAC
593 ppc_ide_md.ide_init_hwif = pmac_ide_init_hwif_ports;
594 ppc_ide_md.default_io_base = pmac_ide_get_base;
595#endif /* CONFIG_BLK_DEV_IDE_PMAC */
596#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */
597
598 if (ppc_md.progress) ppc_md.progress("pmac_init(): exit", 0);
599
600}
601#endif
602
603/* 586/*
604 * Early initialization. 587 * Early initialization.
605 */ 588 */
@@ -646,6 +629,12 @@ static int __init pmac_declare_of_platform_devices(void)
646{ 629{
647 struct device_node *np; 630 struct device_node *np;
648 631
632 if (machine_is(chrp))
633 return -1;
634
635 if (!machine_is(powermac))
636 return 0;
637
649 np = of_find_node_by_name(NULL, "valkyrie"); 638 np = of_find_node_by_name(NULL, "valkyrie");
650 if (np) 639 if (np)
651 of_platform_device_create(np, "valkyrie", NULL); 640 of_platform_device_create(np, "valkyrie", NULL);
@@ -666,12 +655,15 @@ device_initcall(pmac_declare_of_platform_devices);
666/* 655/*
667 * Called very early, MMU is off, device-tree isn't unflattened 656 * Called very early, MMU is off, device-tree isn't unflattened
668 */ 657 */
669static int __init pmac_probe(int platform) 658static int __init pmac_probe(void)
670{ 659{
671#ifdef CONFIG_PPC64 660 unsigned long root = of_get_flat_dt_root();
672 if (platform != PLATFORM_POWERMAC) 661
662 if (!of_flat_dt_is_compatible(root, "Power Macintosh") &&
663 !of_flat_dt_is_compatible(root, "MacRISC"))
673 return 0; 664 return 0;
674 665
666#ifdef CONFIG_PPC64
675 /* 667 /*
676 * On U3, the DART (iommu) must be allocated now since it 668 * On U3, the DART (iommu) must be allocated now since it
677 * has an impact on htab_initialize (due to the large page it 669 * has an impact on htab_initialize (due to the large page it
@@ -681,6 +673,23 @@ static int __init pmac_probe(int platform)
681 alloc_dart_table(); 673 alloc_dart_table();
682#endif 674#endif
683 675
676#ifdef CONFIG_PPC32
677 /* isa_io_base gets set in pmac_pci_init */
678 isa_mem_base = PMAC_ISA_MEM_BASE;
679 pci_dram_offset = PMAC_PCI_DRAM_OFFSET;
680 ISA_DMA_THRESHOLD = ~0L;
681 DMA_MODE_READ = 1;
682 DMA_MODE_WRITE = 2;
683
684#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
685#ifdef CONFIG_BLK_DEV_IDE_PMAC
686 ppc_ide_md.ide_init_hwif = pmac_ide_init_hwif_ports;
687 ppc_ide_md.default_io_base = pmac_ide_get_base;
688#endif /* CONFIG_BLK_DEV_IDE_PMAC */
689#endif /* defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE) */
690
691#endif /* CONFIG_PPC32 */
692
684#ifdef CONFIG_PMAC_SMU 693#ifdef CONFIG_PMAC_SMU
685 /* 694 /*
686 * SMU based G5s need some memory below 2Gb, at least the current 695 * SMU based G5s need some memory below 2Gb, at least the current
@@ -709,10 +718,8 @@ static int pmac_pci_probe_mode(struct pci_bus *bus)
709} 718}
710#endif 719#endif
711 720
712struct machdep_calls __initdata pmac_md = { 721define_machine(powermac) {
713#if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PPC64) 722 .name = "PowerMac",
714 .cpu_die = generic_mach_cpu_die,
715#endif
716 .probe = pmac_probe, 723 .probe = pmac_probe,
717 .setup_arch = pmac_setup_arch, 724 .setup_arch = pmac_setup_arch,
718 .init_early = pmac_init_early, 725 .init_early = pmac_init_early,
@@ -733,7 +740,7 @@ struct machdep_calls __initdata pmac_md = {
733 .progress = udbg_progress, 740 .progress = udbg_progress,
734#ifdef CONFIG_PPC64 741#ifdef CONFIG_PPC64
735 .pci_probe_mode = pmac_pci_probe_mode, 742 .pci_probe_mode = pmac_pci_probe_mode,
736 .idle_loop = native_idle, 743 .power_save = power4_idle,
737 .enable_pmcs = power4_enable_pmcs, 744 .enable_pmcs = power4_enable_pmcs,
738#ifdef CONFIG_KEXEC 745#ifdef CONFIG_KEXEC
739 .machine_kexec = default_machine_kexec, 746 .machine_kexec = default_machine_kexec,
@@ -746,4 +753,7 @@ struct machdep_calls __initdata pmac_md = {
746 .pcibios_after_init = pmac_pcibios_after_init, 753 .pcibios_after_init = pmac_pcibios_after_init,
747 .phys_mem_access_prot = pci_phys_mem_access_prot, 754 .phys_mem_access_prot = pci_phys_mem_access_prot,
748#endif 755#endif
756#if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PPC64)
757 .cpu_die = generic_mach_cpu_die,
758#endif
749}; 759};
diff --git a/arch/powerpc/platforms/powermac/time.c b/arch/powerpc/platforms/powermac/time.c
index 5d9afa1fa02d..890758aa9667 100644
--- a/arch/powerpc/platforms/powermac/time.c
+++ b/arch/powerpc/platforms/powermac/time.c
@@ -336,10 +336,10 @@ static struct pmu_sleep_notifier time_sleep_notifier = {
336 */ 336 */
337void __init pmac_calibrate_decr(void) 337void __init pmac_calibrate_decr(void)
338{ 338{
339#ifdef CONFIG_PM 339#if defined(CONFIG_PM) && defined(CONFIG_ADB_PMU)
340 /* XXX why here? */ 340 /* XXX why here? */
341 pmu_register_sleep_notifier(&time_sleep_notifier); 341 pmu_register_sleep_notifier(&time_sleep_notifier);
342#endif /* CONFIG_PM */ 342#endif
343 343
344 generic_calibrate_decr(); 344 generic_calibrate_decr();
345 345
diff --git a/arch/powerpc/platforms/powermac/udbg_scc.c b/arch/powerpc/platforms/powermac/udbg_scc.c
index c4352a8db644..b4fa9f03b461 100644
--- a/arch/powerpc/platforms/powermac/udbg_scc.c
+++ b/arch/powerpc/platforms/powermac/udbg_scc.c
@@ -116,7 +116,7 @@ void udbg_scc_init(int force_scc)
116 /* Setup for 57600 8N1 */ 116 /* Setup for 57600 8N1 */
117 if (ch == ch_a) 117 if (ch == ch_a)
118 addr += 0x20; 118 addr += 0x20;
119 sccc = (volatile u8 * __iomem) ioremap(addr & PAGE_MASK, PAGE_SIZE) ; 119 sccc = ioremap(addr & PAGE_MASK, PAGE_SIZE) ;
120 sccc += addr & ~PAGE_MASK; 120 sccc += addr & ~PAGE_MASK;
121 sccd = sccc + 0x10; 121 sccd = sccc + 0x10;
122 122
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
index 2ab9dcdfb415..9b2b1cb117b3 100644
--- a/arch/powerpc/platforms/pseries/eeh.c
+++ b/arch/powerpc/platforms/pseries/eeh.c
@@ -1018,7 +1018,7 @@ static int __init eeh_init_proc(void)
1018{ 1018{
1019 struct proc_dir_entry *e; 1019 struct proc_dir_entry *e;
1020 1020
1021 if (platform_is_pseries()) { 1021 if (machine_is(pseries)) {
1022 e = create_proc_entry("ppc64/eeh", 0, NULL); 1022 e = create_proc_entry("ppc64/eeh", 0, NULL);
1023 if (e) 1023 if (e)
1024 e->proc_fops = &proc_eeh_operations; 1024 e->proc_fops = &proc_eeh_operations;
diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c
index b811d5ff92fe..cc2495a0cdd5 100644
--- a/arch/powerpc/platforms/pseries/eeh_driver.c
+++ b/arch/powerpc/platforms/pseries/eeh_driver.c
@@ -257,6 +257,7 @@ void handle_eeh_events (struct eeh_event *event)
257 struct pci_bus *frozen_bus; 257 struct pci_bus *frozen_bus;
258 int rc = 0; 258 int rc = 0;
259 enum pci_ers_result result = PCI_ERS_RESULT_NONE; 259 enum pci_ers_result result = PCI_ERS_RESULT_NONE;
260 const char *pci_str, *drv_str;
260 261
261 frozen_dn = find_device_pe(event->dn); 262 frozen_dn = find_device_pe(event->dn);
262 frozen_bus = pcibios_find_pci_bus(frozen_dn); 263 frozen_bus = pcibios_find_pci_bus(frozen_dn);
@@ -291,6 +292,13 @@ void handle_eeh_events (struct eeh_event *event)
291 292
292 frozen_pdn = PCI_DN(frozen_dn); 293 frozen_pdn = PCI_DN(frozen_dn);
293 frozen_pdn->eeh_freeze_count++; 294 frozen_pdn->eeh_freeze_count++;
295
296 pci_str = pci_name (frozen_pdn->pcidev);
297 drv_str = pcid_name (frozen_pdn->pcidev);
298 if (!pci_str) {
299 pci_str = pci_name (event->dev);
300 drv_str = pcid_name (event->dev);
301 }
294 302
295 if (frozen_pdn->eeh_freeze_count > EEH_MAX_ALLOWED_FREEZES) 303 if (frozen_pdn->eeh_freeze_count > EEH_MAX_ALLOWED_FREEZES)
296 goto hard_fail; 304 goto hard_fail;
@@ -306,9 +314,7 @@ void handle_eeh_events (struct eeh_event *event)
306 eeh_slot_error_detail(frozen_pdn, 1 /* Temporary Error */); 314 eeh_slot_error_detail(frozen_pdn, 1 /* Temporary Error */);
307 printk(KERN_WARNING 315 printk(KERN_WARNING
308 "EEH: This PCI device has failed %d times since last reboot: %s - %s\n", 316 "EEH: This PCI device has failed %d times since last reboot: %s - %s\n",
309 frozen_pdn->eeh_freeze_count, 317 frozen_pdn->eeh_freeze_count, drv_str, pci_str);
310 pci_name (frozen_pdn->pcidev),
311 pcid_name(frozen_pdn->pcidev));
312 318
313 /* Walk the various device drivers attached to this slot through 319 /* Walk the various device drivers attached to this slot through
314 * a reset sequence, giving each an opportunity to do what it needs 320 * a reset sequence, giving each an opportunity to do what it needs
@@ -360,9 +366,7 @@ hard_fail:
360 "EEH: PCI device %s - %s has failed %d times \n" 366 "EEH: PCI device %s - %s has failed %d times \n"
361 "and has been permanently disabled. Please try reseating\n" 367 "and has been permanently disabled. Please try reseating\n"
362 "this device or replacing it.\n", 368 "this device or replacing it.\n",
363 pci_name (frozen_pdn->pcidev), 369 drv_str, pci_str, frozen_pdn->eeh_freeze_count);
364 pcid_name(frozen_pdn->pcidev),
365 frozen_pdn->eeh_freeze_count);
366 370
367 eeh_slot_error_detail(frozen_pdn, 2 /* Permanent Error */); 371 eeh_slot_error_detail(frozen_pdn, 2 /* Permanent Error */);
368 372
diff --git a/arch/powerpc/platforms/pseries/firmware.c b/arch/powerpc/platforms/pseries/firmware.c
index 989f4bc136cb..c01d8f0cbe6d 100644
--- a/arch/powerpc/platforms/pseries/firmware.c
+++ b/arch/powerpc/platforms/pseries/firmware.c
@@ -91,7 +91,7 @@ void __init fw_feature_init(void)
91 continue; 91 continue;
92 92
93 /* we have a match */ 93 /* we have a match */
94 ppc64_firmware_features |= 94 powerpc_firmware_features |=
95 firmware_features_table[i].val; 95 firmware_features_table[i].val;
96 break; 96 break;
97 } 97 }
diff --git a/arch/powerpc/platforms/pseries/hvconsole.c b/arch/powerpc/platforms/pseries/hvconsole.c
index 138e128a3886..ba6befd96636 100644
--- a/arch/powerpc/platforms/pseries/hvconsole.c
+++ b/arch/powerpc/platforms/pseries/hvconsole.c
@@ -62,6 +62,11 @@ int hvc_put_chars(uint32_t vtermno, const char *buf, int count)
62 unsigned long *lbuf = (unsigned long *) buf; 62 unsigned long *lbuf = (unsigned long *) buf;
63 long ret; 63 long ret;
64 64
65
66 /* hcall will ret H_PARAMETER if 'count' exceeds firmware max.*/
67 if (count > MAX_VIO_PUT_CHARS)
68 count = MAX_VIO_PUT_CHARS;
69
65 ret = plpar_hcall_norets(H_PUT_TERM_CHAR, vtermno, count, lbuf[0], 70 ret = plpar_hcall_norets(H_PUT_TERM_CHAR, vtermno, count, lbuf[0],
66 lbuf[1]); 71 lbuf[1]);
67 if (ret == H_Success) 72 if (ret == H_Success)
diff --git a/arch/powerpc/platforms/pseries/pci.c b/arch/powerpc/platforms/pseries/pci.c
index 946ad59e3352..e97e67f5e079 100644
--- a/arch/powerpc/platforms/pseries/pci.c
+++ b/arch/powerpc/platforms/pseries/pci.c
@@ -120,7 +120,7 @@ static void fixup_winbond_82c105(struct pci_dev* dev)
120 int i; 120 int i;
121 unsigned int reg; 121 unsigned int reg;
122 122
123 if (!platform_is_pseries()) 123 if (!machine_is(pseries))
124 return; 124 return;
125 125
126 printk("Using INTC for W82c105 IDE controller.\n"); 126 printk("Using INTC for W82c105 IDE controller.\n");
diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c
index 44abdeb9ca03..6bfacc217085 100644
--- a/arch/powerpc/platforms/pseries/pci_dlpar.c
+++ b/arch/powerpc/platforms/pseries/pci_dlpar.c
@@ -28,6 +28,7 @@
28#include <linux/pci.h> 28#include <linux/pci.h>
29#include <asm/pci-bridge.h> 29#include <asm/pci-bridge.h>
30#include <asm/ppc-pci.h> 30#include <asm/ppc-pci.h>
31#include <asm/firmware.h>
31 32
32static struct pci_bus * 33static struct pci_bus *
33find_bus_among_children(struct pci_bus *bus, 34find_bus_among_children(struct pci_bus *bus,
@@ -152,20 +153,24 @@ pcibios_pci_config_bridge(struct pci_dev *dev)
152void 153void
153pcibios_add_pci_devices(struct pci_bus * bus) 154pcibios_add_pci_devices(struct pci_bus * bus)
154{ 155{
155 int slotno, num; 156 int slotno, num, mode;
156 struct pci_dev *dev; 157 struct pci_dev *dev;
157 struct device_node *dn = pci_bus_to_OF_node(bus); 158 struct device_node *dn = pci_bus_to_OF_node(bus);
158 159
159 eeh_add_device_tree_early(dn); 160 eeh_add_device_tree_early(dn);
160 161
161 if (_machine == PLATFORM_PSERIES_LPAR) { 162 mode = PCI_PROBE_NORMAL;
163 if (ppc_md.pci_probe_mode)
164 mode = ppc_md.pci_probe_mode(bus);
165
166 if (mode == PCI_PROBE_DEVTREE) {
162 /* use ofdt-based probe */ 167 /* use ofdt-based probe */
163 of_scan_bus(dn, bus); 168 of_scan_bus(dn, bus);
164 if (!list_empty(&bus->devices)) { 169 if (!list_empty(&bus->devices)) {
165 pcibios_fixup_new_pci_devices(bus, 0); 170 pcibios_fixup_new_pci_devices(bus, 0);
166 pci_bus_add_devices(bus); 171 pci_bus_add_devices(bus);
167 } 172 }
168 } else { 173 } else if (mode == PCI_PROBE_NORMAL) {
169 /* use legacy probe */ 174 /* use legacy probe */
170 slotno = PCI_SLOT(PCI_DN(dn->child)->devfn); 175 slotno = PCI_SLOT(PCI_DN(dn->child)->devfn);
171 num = pci_scan_slot(bus, PCI_DEVFN(slotno, 0)); 176 num = pci_scan_slot(bus, PCI_DEVFN(slotno, 0));
diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c
index b046bcf7443d..9639c66b453d 100644
--- a/arch/powerpc/platforms/pseries/ras.c
+++ b/arch/powerpc/platforms/pseries/ras.c
@@ -132,7 +132,7 @@ static int __init init_ras_IRQ(void)
132 of_node_put(np); 132 of_node_put(np);
133 } 133 }
134 134
135 return 1; 135 return 0;
136} 136}
137__initcall(init_ras_IRQ); 137__initcall(init_ras_IRQ);
138 138
diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c
index 5ad90676567a..1773103354be 100644
--- a/arch/powerpc/platforms/pseries/reconfig.c
+++ b/arch/powerpc/platforms/pseries/reconfig.c
@@ -17,8 +17,9 @@
17#include <linux/proc_fs.h> 17#include <linux/proc_fs.h>
18 18
19#include <asm/prom.h> 19#include <asm/prom.h>
20#include <asm/pSeries_reconfig.h> 20#include <asm/machdep.h>
21#include <asm/uaccess.h> 21#include <asm/uaccess.h>
22#include <asm/pSeries_reconfig.h>
22 23
23 24
24 25
@@ -508,7 +509,7 @@ static int proc_ppc64_create_ofdt(void)
508{ 509{
509 struct proc_dir_entry *ent; 510 struct proc_dir_entry *ent;
510 511
511 if (!platform_is_pseries()) 512 if (!machine_is(pseries))
512 return 0; 513 return 0;
513 514
514 ent = create_proc_entry("ppc64/ofdt", S_IWUSR, NULL); 515 ent = create_proc_entry("ppc64/ofdt", S_IWUSR, NULL);
diff --git a/arch/powerpc/platforms/pseries/rtasd.c b/arch/powerpc/platforms/pseries/rtasd.c
index a6f628d4c9dc..fcc4d561a236 100644
--- a/arch/powerpc/platforms/pseries/rtasd.c
+++ b/arch/powerpc/platforms/pseries/rtasd.c
@@ -27,6 +27,7 @@
27#include <asm/prom.h> 27#include <asm/prom.h>
28#include <asm/nvram.h> 28#include <asm/nvram.h>
29#include <asm/atomic.h> 29#include <asm/atomic.h>
30#include <asm/machdep.h>
30 31
31#if 0 32#if 0
32#define DEBUG(A...) printk(KERN_ERR A) 33#define DEBUG(A...) printk(KERN_ERR A)
@@ -481,7 +482,7 @@ static int __init rtas_init(void)
481{ 482{
482 struct proc_dir_entry *entry; 483 struct proc_dir_entry *entry;
483 484
484 if (!platform_is_pseries()) 485 if (!machine_is(pseries))
485 return 0; 486 return 0;
486 487
487 /* No RTAS */ 488 /* No RTAS */
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index 44d5c7fdcd97..b2fbf8ba8fbb 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -81,8 +81,8 @@ extern void find_udbg_vterm(void);
81 81
82int fwnmi_active; /* TRUE if an FWNMI handler is present */ 82int fwnmi_active; /* TRUE if an FWNMI handler is present */
83 83
84static void pseries_shared_idle(void); 84static void pseries_shared_idle_sleep(void);
85static void pseries_dedicated_idle(void); 85static void pseries_dedicated_idle_sleep(void);
86 86
87struct mpic *pSeries_mpic; 87struct mpic *pSeries_mpic;
88 88
@@ -236,14 +236,13 @@ static void __init pSeries_setup_arch(void)
236 vpa_init(boot_cpuid); 236 vpa_init(boot_cpuid);
237 if (get_lppaca()->shared_proc) { 237 if (get_lppaca()->shared_proc) {
238 printk(KERN_INFO "Using shared processor idle loop\n"); 238 printk(KERN_INFO "Using shared processor idle loop\n");
239 ppc_md.idle_loop = pseries_shared_idle; 239 ppc_md.power_save = pseries_shared_idle_sleep;
240 } else { 240 } else {
241 printk(KERN_INFO "Using dedicated idle loop\n"); 241 printk(KERN_INFO "Using dedicated idle loop\n");
242 ppc_md.idle_loop = pseries_dedicated_idle; 242 ppc_md.power_save = pseries_dedicated_idle_sleep;
243 } 243 }
244 } else { 244 } else {
245 printk(KERN_INFO "Using default idle loop\n"); 245 printk(KERN_INFO "Using default idle loop\n");
246 ppc_md.idle_loop = default_idle;
247 } 246 }
248 247
249 if (firmware_has_feature(FW_FEATURE_LPAR)) 248 if (firmware_has_feature(FW_FEATURE_LPAR))
@@ -373,156 +372,123 @@ static int pSeries_check_legacy_ioport(unsigned int baseport)
373/* 372/*
374 * Called very early, MMU is off, device-tree isn't unflattened 373 * Called very early, MMU is off, device-tree isn't unflattened
375 */ 374 */
376extern struct machdep_calls pSeries_md;
377 375
378static int __init pSeries_probe(int platform) 376static int __init pSeries_probe_hypertas(unsigned long node,
377 const char *uname, int depth,
378 void *data)
379{ 379{
380 if (platform != PLATFORM_PSERIES && 380 if (depth != 1 ||
381 platform != PLATFORM_PSERIES_LPAR) 381 (strcmp(uname, "rtas") != 0 && strcmp(uname, "rtas@0") != 0))
382 return 0; 382 return 0;
383
384 /* if we have some ppc_md fixups for LPAR to do, do
385 * it here ...
386 */
387 383
388 if (platform == PLATFORM_PSERIES_LPAR) 384 if (of_get_flat_dt_prop(node, "ibm,hypertas-functions", NULL) != NULL)
389 ppc64_firmware_features |= FW_FEATURE_LPAR; 385 powerpc_firmware_features |= FW_FEATURE_LPAR;
390 386
391 return 1; 387 return 1;
392} 388}
393 389
394DECLARE_PER_CPU(unsigned long, smt_snooze_delay); 390static int __init pSeries_probe(void)
395
396static inline void dedicated_idle_sleep(unsigned int cpu)
397{ 391{
398 struct lppaca *plppaca = &lppaca[cpu ^ 1]; 392 char *dtype = of_get_flat_dt_prop(of_get_flat_dt_root(),
393 "device_type", NULL);
394 if (dtype == NULL)
395 return 0;
396 if (strcmp(dtype, "chrp"))
397 return 0;
399 398
400 /* Only sleep if the other thread is not idle */ 399 DBG("pSeries detected, looking for LPAR capability...\n");
401 if (!(plppaca->idle)) {
402 local_irq_disable();
403 400
404 /* 401 /* Now try to figure out if we are running on LPAR */
405 * We are about to sleep the thread and so wont be polling any 402 of_scan_flat_dt(pSeries_probe_hypertas, NULL);
406 * more. 403
407 */ 404 DBG("Machine is%s LPAR !\n",
408 clear_thread_flag(TIF_POLLING_NRFLAG); 405 (powerpc_firmware_features & FW_FEATURE_LPAR) ? "" : " not");
409 smp_mb__after_clear_bit(); 406
410 407 return 1;
411 /*
412 * SMT dynamic mode. Cede will result in this thread going
413 * dormant, if the partner thread is still doing work. Thread
414 * wakes up if partner goes idle, an interrupt is presented, or
415 * a prod occurs. Returning from the cede enables external
416 * interrupts.
417 */
418 if (!need_resched())
419 cede_processor();
420 else
421 local_irq_enable();
422 set_thread_flag(TIF_POLLING_NRFLAG);
423 } else {
424 /*
425 * Give the HV an opportunity at the processor, since we are
426 * not doing any work.
427 */
428 poll_pending();
429 }
430} 408}
431 409
432static void pseries_dedicated_idle(void) 410
411DECLARE_PER_CPU(unsigned long, smt_snooze_delay);
412
413static void pseries_dedicated_idle_sleep(void)
433{ 414{
434 unsigned int cpu = smp_processor_id(); 415 unsigned int cpu = smp_processor_id();
435 unsigned long start_snooze; 416 unsigned long start_snooze;
436 unsigned long *smt_snooze_delay = &__get_cpu_var(smt_snooze_delay); 417 unsigned long *smt_snooze_delay = &__get_cpu_var(smt_snooze_delay);
437 set_thread_flag(TIF_POLLING_NRFLAG);
438
439 while (1) {
440 /*
441 * Indicate to the HV that we are idle. Now would be
442 * a good time to find other work to dispatch.
443 */
444 get_lppaca()->idle = 1;
445
446 if (!need_resched()) {
447 start_snooze = get_tb() +
448 *smt_snooze_delay * tb_ticks_per_usec;
449
450 while (!need_resched() && !cpu_is_offline(cpu)) {
451 ppc64_runlatch_off();
452
453 /*
454 * Go into low thread priority and possibly
455 * low power mode.
456 */
457 HMT_low();
458 HMT_very_low();
459
460 if (*smt_snooze_delay != 0 &&
461 get_tb() > start_snooze) {
462 HMT_medium();
463 dedicated_idle_sleep(cpu);
464 }
465
466 }
467
468 HMT_medium();
469 }
470
471 get_lppaca()->idle = 0;
472 ppc64_runlatch_on();
473 418
474 preempt_enable_no_resched(); 419 /*
475 schedule(); 420 * Indicate to the HV that we are idle. Now would be
476 preempt_disable(); 421 * a good time to find other work to dispatch.
422 */
423 get_lppaca()->idle = 1;
477 424
478 if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING) 425 /*
479 cpu_die(); 426 * We come in with interrupts disabled, and need_resched()
480 } 427 * has been checked recently. If we should poll for a little
481} 428 * while, do so.
429 */
430 if (*smt_snooze_delay) {
431 start_snooze = get_tb() +
432 *smt_snooze_delay * tb_ticks_per_usec;
433 local_irq_enable();
434 set_thread_flag(TIF_POLLING_NRFLAG);
482 435
483static void pseries_shared_idle(void) 436 while (get_tb() < start_snooze) {
484{ 437 if (need_resched() || cpu_is_offline(cpu))
485 unsigned int cpu = smp_processor_id(); 438 goto out;
439 ppc64_runlatch_off();
440 HMT_low();
441 HMT_very_low();
442 }
486 443
487 while (1) { 444 HMT_medium();
488 /* 445 clear_thread_flag(TIF_POLLING_NRFLAG);
489 * Indicate to the HV that we are idle. Now would be 446 smp_mb();
490 * a good time to find other work to dispatch. 447 local_irq_disable();
491 */ 448 if (need_resched() || cpu_is_offline(cpu))
492 get_lppaca()->idle = 1; 449 goto out;
450 }
493 451
494 while (!need_resched() && !cpu_is_offline(cpu)) { 452 /*
495 local_irq_disable(); 453 * Cede if the other thread is not idle, so that it can
496 ppc64_runlatch_off(); 454 * go single-threaded. If the other thread is idle,
455 * we ask the hypervisor if it has pending work it
456 * wants to do and cede if it does. Otherwise we keep
457 * polling in order to reduce interrupt latency.
458 *
459 * Doing the cede when the other thread is active will
460 * result in this thread going dormant, meaning the other
461 * thread gets to run in single-threaded (ST) mode, which
462 * is slightly faster than SMT mode with this thread at
463 * very low priority. The cede enables interrupts, which
464 * doesn't matter here.
465 */
466 if (!lppaca[cpu ^ 1].idle || poll_pending() == H_Pending)
467 cede_processor();
497 468
498 /* 469out:
499 * Yield the processor to the hypervisor. We return if 470 HMT_medium();
500 * an external interrupt occurs (which are driven prior 471 get_lppaca()->idle = 0;
501 * to returning here) or if a prod occurs from another 472}
502 * processor. When returning here, external interrupts
503 * are enabled.
504 *
505 * Check need_resched() again with interrupts disabled
506 * to avoid a race.
507 */
508 if (!need_resched())
509 cede_processor();
510 else
511 local_irq_enable();
512
513 HMT_medium();
514 }
515 473
516 get_lppaca()->idle = 0; 474static void pseries_shared_idle_sleep(void)
517 ppc64_runlatch_on(); 475{
476 /*
477 * Indicate to the HV that we are idle. Now would be
478 * a good time to find other work to dispatch.
479 */
480 get_lppaca()->idle = 1;
518 481
519 preempt_enable_no_resched(); 482 /*
520 schedule(); 483 * Yield the processor to the hypervisor. We return if
521 preempt_disable(); 484 * an external interrupt occurs (which are driven prior
485 * to returning here) or if a prod occurs from another
486 * processor. When returning here, external interrupts
487 * are enabled.
488 */
489 cede_processor();
522 490
523 if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING) 491 get_lppaca()->idle = 0;
524 cpu_die();
525 }
526} 492}
527 493
528static int pSeries_pci_probe_mode(struct pci_bus *bus) 494static int pSeries_pci_probe_mode(struct pci_bus *bus)
@@ -553,7 +519,8 @@ static void pseries_kexec_cpu_down(int crash_shutdown, int secondary)
553} 519}
554#endif 520#endif
555 521
556struct machdep_calls __initdata pSeries_md = { 522define_machine(pseries) {
523 .name = "pSeries",
557 .probe = pSeries_probe, 524 .probe = pSeries_probe,
558 .setup_arch = pSeries_setup_arch, 525 .setup_arch = pSeries_setup_arch,
559 .init_early = pSeries_init_early, 526 .init_early = pSeries_init_early,
diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c
index eb86cdb9b802..c60d3ff25a2f 100644
--- a/arch/powerpc/platforms/pseries/xics.c
+++ b/arch/powerpc/platforms/pseries/xics.c
@@ -500,7 +500,7 @@ nextnode:
500 np; 500 np;
501 np = of_find_node_by_type(np, "cpu")) { 501 np = of_find_node_by_type(np, "cpu")) {
502 ireg = (uint *)get_property(np, "reg", &ilen); 502 ireg = (uint *)get_property(np, "reg", &ilen);
503 if (ireg && ireg[0] == boot_cpuid_phys) { 503 if (ireg && ireg[0] == get_hard_smp_processor_id(boot_cpuid)) {
504 ireg = (uint *)get_property(np, "ibm,ppc-interrupt-gserver#s", 504 ireg = (uint *)get_property(np, "ibm,ppc-interrupt-gserver#s",
505 &ilen); 505 &ilen);
506 i = ilen / sizeof(int); 506 i = ilen / sizeof(int);