aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@g5.osdl.org>2005-11-07 23:23:46 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2005-11-07 23:23:46 -0500
commitf093182d313edde9b1f86dbdaf40ba4da2dbd0e7 (patch)
treeecfc614d514bd5b43a98cf4c62fdd2f47d86e33c
parentd27ba47e7e8c466c18983a1779d611f82d6a354f (diff)
parent76c8e25b905f99be5ddbe999597ba7c2c33ec64b (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc-merge
-rw-r--r--arch/powerpc/Kconfig9
-rw-r--r--arch/powerpc/configs/g5_defconfig261
-rw-r--r--arch/powerpc/kernel/misc_64.S70
-rw-r--r--arch/powerpc/kernel/process.c4
-rw-r--r--arch/powerpc/kernel/prom.c21
-rw-r--r--arch/powerpc/kernel/prom_init.c11
-rw-r--r--arch/powerpc/kernel/rtas.c5
-rw-r--r--arch/powerpc/kernel/setup-common.c40
-rw-r--r--arch/powerpc/kernel/setup_32.c1
-rw-r--r--arch/powerpc/kernel/setup_64.c46
-rw-r--r--arch/powerpc/kernel/signal_32.c1
-rw-r--r--arch/powerpc/kernel/signal_64.c1
-rw-r--r--arch/powerpc/kernel/smp.c1
-rw-r--r--arch/powerpc/kernel/time.c5
-rw-r--r--arch/powerpc/kernel/traps.c11
-rw-r--r--arch/powerpc/lib/locks.c1
-rw-r--r--arch/powerpc/mm/fault.c17
-rw-r--r--arch/powerpc/mm/hash_utils_64.c10
-rw-r--r--arch/powerpc/mm/init_64.c1
-rw-r--r--arch/powerpc/mm/mem.c2
-rw-r--r--arch/powerpc/mm/numa.c1
-rw-r--r--arch/powerpc/mm/pgtable_64.c1
-rw-r--r--arch/powerpc/oprofile/op_model_power4.c24
-rw-r--r--arch/powerpc/platforms/iseries/irq.c5
-rw-r--r--arch/powerpc/platforms/iseries/pci.c37
-rw-r--r--arch/powerpc/platforms/iseries/setup.c4
-rw-r--r--arch/powerpc/platforms/iseries/smp.c1
-rw-r--r--arch/powerpc/platforms/powermac/Makefile3
-rw-r--r--arch/powerpc/platforms/powermac/cpufreq_32.c (renamed from arch/powerpc/platforms/powermac/cpufreq.c)15
-rw-r--r--arch/powerpc/platforms/powermac/cpufreq_64.c323
-rw-r--r--arch/powerpc/platforms/powermac/setup.c13
-rw-r--r--arch/powerpc/platforms/pseries/iommu.c2
-rw-r--r--arch/powerpc/platforms/pseries/lpar.c3
-rw-r--r--arch/powerpc/platforms/pseries/plpar_wrappers.h10
-rw-r--r--arch/powerpc/platforms/pseries/ras.c2
-rw-r--r--arch/powerpc/platforms/pseries/setup.c18
-rw-r--r--arch/powerpc/sysdev/i8259.c5
-rw-r--r--arch/powerpc/sysdev/u3_iommu.c1
-rw-r--r--arch/ppc/kernel/misc.S145
-rw-r--r--arch/ppc/kernel/traps.c12
-rw-r--r--arch/ppc/syslib/m8xx_wdt.c13
-rw-r--r--arch/ppc/syslib/prom.c4
-rw-r--r--arch/ppc/xmon/xmon.c5
-rw-r--r--arch/ppc64/Kconfig11
-rw-r--r--arch/ppc64/Kconfig.debug4
-rw-r--r--arch/ppc64/kernel/idle.c1
-rw-r--r--arch/ppc64/kernel/machine_kexec.c1
-rw-r--r--arch/ppc64/kernel/misc.S72
-rw-r--r--arch/ppc64/kernel/pci.c17
-rw-r--r--arch/ppc64/kernel/prom.c25
-rw-r--r--arch/ppc64/kernel/prom_init.c3
-rw-r--r--arch/ppc64/kernel/rtas_pci.c6
-rw-r--r--arch/ppc64/kernel/udbg.c55
-rw-r--r--drivers/block/swim3.c20
-rw-r--r--drivers/ide/ppc/pmac.c9
-rw-r--r--drivers/macintosh/Kconfig19
-rw-r--r--drivers/macintosh/Makefile9
-rw-r--r--drivers/macintosh/smu.c174
-rw-r--r--drivers/macintosh/via-pmu.c10
-rw-r--r--drivers/macintosh/windfarm.h131
-rw-r--r--drivers/macintosh/windfarm_core.c426
-rw-r--r--drivers/macintosh/windfarm_cpufreq_clamp.c105
-rw-r--r--drivers/macintosh/windfarm_lm75_sensor.c263
-rw-r--r--drivers/macintosh/windfarm_pid.c145
-rw-r--r--drivers/macintosh/windfarm_pid.h84
-rw-r--r--drivers/macintosh/windfarm_pm81.c879
-rw-r--r--drivers/macintosh/windfarm_pm91.c814
-rw-r--r--drivers/macintosh/windfarm_smu_controls.c282
-rw-r--r--drivers/macintosh/windfarm_smu_sensors.c479
-rw-r--r--fs/proc/proc_devtree.c57
-rw-r--r--include/asm-powerpc/ide.h (renamed from include/asm-ppc/ide.h)29
-rw-r--r--include/asm-powerpc/machdep.h4
-rw-r--r--include/asm-powerpc/ppc-pci.h1
-rw-r--r--include/asm-powerpc/prom.h2
-rw-r--r--include/asm-powerpc/reg.h9
-rw-r--r--include/asm-powerpc/smp.h4
-rw-r--r--include/asm-powerpc/smu.h199
-rw-r--r--include/asm-powerpc/xmon.h1
-rw-r--r--include/asm-ppc/btext.h22
-rw-r--r--include/asm-ppc/io.h12
-rw-r--r--include/asm-ppc/kgdb.h2
-rw-r--r--include/asm-ppc/prom.h2
-rw-r--r--include/asm-ppc64/ide.h30
-rw-r--r--include/asm-ppc64/pci.h8
-rw-r--r--include/asm-ppc64/ppcdebug.h108
-rw-r--r--include/asm-ppc64/prom.h2
-rw-r--r--include/asm-ppc64/udbg.h3
-rw-r--r--include/linux/proc_fs.h9
88 files changed, 5134 insertions, 579 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 6ffae2d2b3fa..1493c7896fe3 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -404,6 +404,14 @@ config CPU_FREQ_PMAC
404 this currently includes some models of iBook & Titanium 404 this currently includes some models of iBook & Titanium
405 PowerBook. 405 PowerBook.
406 406
407config CPU_FREQ_PMAC64
408 bool "Support for some Apple G5s"
409 depends on CPU_FREQ && PMAC_SMU && PPC64
410 select CPU_FREQ_TABLE
411 help
412 This adds support for frequency switching on Apple iMac G5,
413 and some of the more recent desktop G5 machines as well.
414
407config PPC601_SYNC_FIX 415config PPC601_SYNC_FIX
408 bool "Workarounds for PPC601 bugs" 416 bool "Workarounds for PPC601 bugs"
409 depends on 6xx && (PPC_PREP || PPC_PMAC) 417 depends on 6xx && (PPC_PREP || PPC_PMAC)
@@ -484,6 +492,7 @@ source "fs/Kconfig.binfmt"
484config FORCE_MAX_ZONEORDER 492config FORCE_MAX_ZONEORDER
485 int 493 int
486 depends on PPC64 494 depends on PPC64
495 default "9" if PPC_64K_PAGES
487 default "13" 496 default "13"
488 497
489config MATH_EMULATION 498config MATH_EMULATION
diff --git a/arch/powerpc/configs/g5_defconfig b/arch/powerpc/configs/g5_defconfig
index 6323065fbf2c..e76854f8c121 100644
--- a/arch/powerpc/configs/g5_defconfig
+++ b/arch/powerpc/configs/g5_defconfig
@@ -1,18 +1,32 @@
1# 1#
2# Automatically generated make config: don't edit 2# Automatically generated make config: don't edit
3# Linux kernel version: 2.6.14-rc4 3# Linux kernel version: 2.6.14
4# Thu Oct 20 08:30:23 2005 4# Mon Nov 7 13:37:59 2005
5# 5#
6CONFIG_PPC64=y
6CONFIG_64BIT=y 7CONFIG_64BIT=y
8CONFIG_PPC_MERGE=y
7CONFIG_MMU=y 9CONFIG_MMU=y
10CONFIG_GENERIC_HARDIRQS=y
8CONFIG_RWSEM_XCHGADD_ALGORITHM=y 11CONFIG_RWSEM_XCHGADD_ALGORITHM=y
9CONFIG_GENERIC_CALIBRATE_DELAY=y 12CONFIG_GENERIC_CALIBRATE_DELAY=y
10CONFIG_GENERIC_ISA_DMA=y 13CONFIG_PPC=y
11CONFIG_EARLY_PRINTK=y 14CONFIG_EARLY_PRINTK=y
12CONFIG_COMPAT=y 15CONFIG_COMPAT=y
16CONFIG_SYSVIPC_COMPAT=y
13CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y 17CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
14CONFIG_ARCH_MAY_HAVE_PC_FDC=y 18CONFIG_ARCH_MAY_HAVE_PC_FDC=y
15CONFIG_FORCE_MAX_ZONEORDER=13 19
20#
21# Processor support
22#
23CONFIG_POWER4_ONLY=y
24CONFIG_POWER4=y
25CONFIG_PPC_FPU=y
26CONFIG_ALTIVEC=y
27CONFIG_PPC_STD_MMU=y
28CONFIG_SMP=y
29CONFIG_NR_CPUS=2
16 30
17# 31#
18# Code maturity level options 32# Code maturity level options
@@ -67,30 +81,60 @@ CONFIG_MODVERSIONS=y
67CONFIG_MODULE_SRCVERSION_ALL=y 81CONFIG_MODULE_SRCVERSION_ALL=y
68CONFIG_KMOD=y 82CONFIG_KMOD=y
69CONFIG_STOP_MACHINE=y 83CONFIG_STOP_MACHINE=y
70CONFIG_SYSVIPC_COMPAT=y
71 84
72# 85#
73# Platform support 86# Platform support
74# 87#
75# CONFIG_PPC_ISERIES is not set
76CONFIG_PPC_MULTIPLATFORM=y 88CONFIG_PPC_MULTIPLATFORM=y
89# CONFIG_PPC_ISERIES is not set
90# CONFIG_EMBEDDED6xx is not set
91# CONFIG_APUS is not set
77# CONFIG_PPC_PSERIES is not set 92# CONFIG_PPC_PSERIES is not set
78# CONFIG_PPC_BPA is not set
79CONFIG_PPC_PMAC=y 93CONFIG_PPC_PMAC=y
94CONFIG_PPC_PMAC64=y
80# CONFIG_PPC_MAPLE is not set 95# CONFIG_PPC_MAPLE is not set
81CONFIG_PPC=y 96# CONFIG_PPC_CELL is not set
82CONFIG_PPC64=y
83CONFIG_PPC_OF=y 97CONFIG_PPC_OF=y
84CONFIG_MPIC=y
85CONFIG_ALTIVEC=y
86CONFIG_KEXEC=y
87CONFIG_U3_DART=y 98CONFIG_U3_DART=y
88CONFIG_PPC_PMAC64=y 99CONFIG_MPIC=y
89CONFIG_BOOTX_TEXT=y 100# CONFIG_PPC_RTAS is not set
90CONFIG_POWER4_ONLY=y 101# CONFIG_MMIO_NVRAM is not set
102# CONFIG_PPC_MPC106 is not set
103CONFIG_GENERIC_TBSYNC=y
104CONFIG_CPU_FREQ=y
105CONFIG_CPU_FREQ_TABLE=y
106# CONFIG_CPU_FREQ_DEBUG is not set
107CONFIG_CPU_FREQ_STAT=y
108# CONFIG_CPU_FREQ_STAT_DETAILS is not set
109CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
110# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
111CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
112CONFIG_CPU_FREQ_GOV_POWERSAVE=y
113CONFIG_CPU_FREQ_GOV_USERSPACE=y
114# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
115# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
116CONFIG_CPU_FREQ_PMAC64=y
117# CONFIG_WANT_EARLY_SERIAL is not set
118
119#
120# Kernel options
121#
122# CONFIG_HZ_100 is not set
123CONFIG_HZ_250=y
124# CONFIG_HZ_1000 is not set
125CONFIG_HZ=250
126CONFIG_PREEMPT_NONE=y
127# CONFIG_PREEMPT_VOLUNTARY is not set
128# CONFIG_PREEMPT is not set
129# CONFIG_PREEMPT_BKL is not set
130CONFIG_BINFMT_ELF=y
131# CONFIG_BINFMT_MISC is not set
132CONFIG_FORCE_MAX_ZONEORDER=13
91CONFIG_IOMMU_VMERGE=y 133CONFIG_IOMMU_VMERGE=y
92CONFIG_SMP=y 134# CONFIG_HOTPLUG_CPU is not set
93CONFIG_NR_CPUS=2 135CONFIG_KEXEC=y
136CONFIG_IRQ_ALL_CPUS=y
137# CONFIG_NUMA is not set
94CONFIG_ARCH_SELECT_MEMORY_MODEL=y 138CONFIG_ARCH_SELECT_MEMORY_MODEL=y
95CONFIG_ARCH_FLATMEM_ENABLE=y 139CONFIG_ARCH_FLATMEM_ENABLE=y
96CONFIG_SELECT_MEMORY_MODEL=y 140CONFIG_SELECT_MEMORY_MODEL=y
@@ -100,28 +144,21 @@ CONFIG_FLATMEM_MANUAL=y
100CONFIG_FLATMEM=y 144CONFIG_FLATMEM=y
101CONFIG_FLAT_NODE_MEM_MAP=y 145CONFIG_FLAT_NODE_MEM_MAP=y
102# CONFIG_SPARSEMEM_STATIC is not set 146# CONFIG_SPARSEMEM_STATIC is not set
103# CONFIG_NUMA is not set 147CONFIG_SPLIT_PTLOCK_CPUS=4
148# CONFIG_PPC_64K_PAGES is not set
104# CONFIG_SCHED_SMT is not set 149# CONFIG_SCHED_SMT is not set
105CONFIG_PREEMPT_NONE=y
106# CONFIG_PREEMPT_VOLUNTARY is not set
107# CONFIG_PREEMPT is not set
108# CONFIG_PREEMPT_BKL is not set
109# CONFIG_HZ_100 is not set
110CONFIG_HZ_250=y
111# CONFIG_HZ_1000 is not set
112CONFIG_HZ=250
113CONFIG_GENERIC_HARDIRQS=y
114CONFIG_SECCOMP=y
115CONFIG_BINFMT_ELF=y
116# CONFIG_BINFMT_MISC is not set
117# CONFIG_HOTPLUG_CPU is not set
118CONFIG_PROC_DEVICETREE=y 150CONFIG_PROC_DEVICETREE=y
119# CONFIG_CMDLINE_BOOL is not set 151# CONFIG_CMDLINE_BOOL is not set
152# CONFIG_PM is not set
153CONFIG_SECCOMP=y
120CONFIG_ISA_DMA_API=y 154CONFIG_ISA_DMA_API=y
121 155
122# 156#
123# Bus Options 157# Bus options
124# 158#
159CONFIG_GENERIC_ISA_DMA=y
160# CONFIG_PPC_I8259 is not set
161# CONFIG_PPC_INDIRECT_PCI is not set
125CONFIG_PCI=y 162CONFIG_PCI=y
126CONFIG_PCI_DOMAINS=y 163CONFIG_PCI_DOMAINS=y
127CONFIG_PCI_LEGACY_PROC=y 164CONFIG_PCI_LEGACY_PROC=y
@@ -136,6 +173,7 @@ CONFIG_PCI_LEGACY_PROC=y
136# PCI Hotplug Support 173# PCI Hotplug Support
137# 174#
138# CONFIG_HOTPLUG_PCI is not set 175# CONFIG_HOTPLUG_PCI is not set
176CONFIG_KERNEL_START=0xc000000000000000
139 177
140# 178#
141# Networking 179# Networking
@@ -276,6 +314,10 @@ CONFIG_LLC=y
276# CONFIG_NET_DIVERT is not set 314# CONFIG_NET_DIVERT is not set
277# CONFIG_ECONET is not set 315# CONFIG_ECONET is not set
278# CONFIG_WAN_ROUTER is not set 316# CONFIG_WAN_ROUTER is not set
317
318#
319# QoS and/or fair queueing
320#
279# CONFIG_NET_SCHED is not set 321# CONFIG_NET_SCHED is not set
280CONFIG_NET_CLS_ROUTE=y 322CONFIG_NET_CLS_ROUTE=y
281 323
@@ -348,6 +390,11 @@ CONFIG_IOSCHED_NOOP=y
348CONFIG_IOSCHED_AS=y 390CONFIG_IOSCHED_AS=y
349CONFIG_IOSCHED_DEADLINE=y 391CONFIG_IOSCHED_DEADLINE=y
350CONFIG_IOSCHED_CFQ=y 392CONFIG_IOSCHED_CFQ=y
393CONFIG_DEFAULT_AS=y
394# CONFIG_DEFAULT_DEADLINE is not set
395# CONFIG_DEFAULT_CFQ is not set
396# CONFIG_DEFAULT_NOOP is not set
397CONFIG_DEFAULT_IOSCHED="anticipatory"
351# CONFIG_ATA_OVER_ETH is not set 398# CONFIG_ATA_OVER_ETH is not set
352 399
353# 400#
@@ -449,6 +496,7 @@ CONFIG_SCSI_SPI_ATTRS=y
449# 496#
450# SCSI low-level drivers 497# SCSI low-level drivers
451# 498#
499# CONFIG_ISCSI_TCP is not set
452# CONFIG_BLK_DEV_3W_XXXX_RAID is not set 500# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
453# CONFIG_SCSI_3W_9XXX is not set 501# CONFIG_SCSI_3W_9XXX is not set
454# CONFIG_SCSI_ACARD is not set 502# CONFIG_SCSI_ACARD is not set
@@ -465,10 +513,12 @@ CONFIG_SCSI_SATA_SVW=y
465# CONFIG_SCSI_ATA_PIIX is not set 513# CONFIG_SCSI_ATA_PIIX is not set
466# CONFIG_SCSI_SATA_MV is not set 514# CONFIG_SCSI_SATA_MV is not set
467# CONFIG_SCSI_SATA_NV is not set 515# CONFIG_SCSI_SATA_NV is not set
468# CONFIG_SCSI_SATA_PROMISE is not set 516# CONFIG_SCSI_PDC_ADMA is not set
469# CONFIG_SCSI_SATA_QSTOR is not set 517# CONFIG_SCSI_SATA_QSTOR is not set
518# CONFIG_SCSI_SATA_PROMISE is not set
470# CONFIG_SCSI_SATA_SX4 is not set 519# CONFIG_SCSI_SATA_SX4 is not set
471# CONFIG_SCSI_SATA_SIL is not set 520# CONFIG_SCSI_SATA_SIL is not set
521# CONFIG_SCSI_SATA_SIL24 is not set
472# CONFIG_SCSI_SATA_SIS is not set 522# CONFIG_SCSI_SATA_SIS is not set
473# CONFIG_SCSI_SATA_ULI is not set 523# CONFIG_SCSI_SATA_ULI is not set
474# CONFIG_SCSI_SATA_VIA is not set 524# CONFIG_SCSI_SATA_VIA is not set
@@ -567,6 +617,9 @@ CONFIG_IEEE1394_RAWIO=y
567CONFIG_ADB_PMU=y 617CONFIG_ADB_PMU=y
568CONFIG_PMAC_SMU=y 618CONFIG_PMAC_SMU=y
569CONFIG_THERM_PM72=y 619CONFIG_THERM_PM72=y
620CONFIG_WINDFARM=y
621CONFIG_WINDFARM_PM81=y
622CONFIG_WINDFARM_PM91=y
570 623
571# 624#
572# Network device support 625# Network device support
@@ -603,6 +656,7 @@ CONFIG_SUNGEM=y
603# CONFIG_NET_TULIP is not set 656# CONFIG_NET_TULIP is not set
604# CONFIG_HP100 is not set 657# CONFIG_HP100 is not set
605# CONFIG_NET_PCI is not set 658# CONFIG_NET_PCI is not set
659# CONFIG_FEC_8XX is not set
606 660
607# 661#
608# Ethernet (1000 Mbit) 662# Ethernet (1000 Mbit)
@@ -768,6 +822,7 @@ CONFIG_MAX_RAW_DEVS=256
768# TPM devices 822# TPM devices
769# 823#
770# CONFIG_TCG_TPM is not set 824# CONFIG_TCG_TPM is not set
825# CONFIG_TELCLOCK is not set
771 826
772# 827#
773# I2C support 828# I2C support
@@ -820,6 +875,7 @@ CONFIG_I2C_PMAC_SMU=y
820# CONFIG_SENSORS_PCF8591 is not set 875# CONFIG_SENSORS_PCF8591 is not set
821# CONFIG_SENSORS_RTC8564 is not set 876# CONFIG_SENSORS_RTC8564 is not set
822# CONFIG_SENSORS_MAX6875 is not set 877# CONFIG_SENSORS_MAX6875 is not set
878# CONFIG_RTC_X1205_I2C is not set
823# CONFIG_I2C_DEBUG_CORE is not set 879# CONFIG_I2C_DEBUG_CORE is not set
824# CONFIG_I2C_DEBUG_ALGO is not set 880# CONFIG_I2C_DEBUG_ALGO is not set
825# CONFIG_I2C_DEBUG_BUS is not set 881# CONFIG_I2C_DEBUG_BUS is not set
@@ -876,10 +932,9 @@ CONFIG_FB_OF=y
876# CONFIG_FB_ASILIANT is not set 932# CONFIG_FB_ASILIANT is not set
877# CONFIG_FB_IMSTT is not set 933# CONFIG_FB_IMSTT is not set
878# CONFIG_FB_VGA16 is not set 934# CONFIG_FB_VGA16 is not set
879# CONFIG_FB_NVIDIA is not set 935CONFIG_FB_NVIDIA=y
880CONFIG_FB_RIVA=y 936CONFIG_FB_NVIDIA_I2C=y
881# CONFIG_FB_RIVA_I2C is not set 937# CONFIG_FB_RIVA is not set
882# CONFIG_FB_RIVA_DEBUG is not set
883# CONFIG_FB_MATROX is not set 938# CONFIG_FB_MATROX is not set
884# CONFIG_FB_RADEON_OLD is not set 939# CONFIG_FB_RADEON_OLD is not set
885CONFIG_FB_RADEON=y 940CONFIG_FB_RADEON=y
@@ -924,7 +979,96 @@ CONFIG_LCD_DEVICE=y
924# 979#
925# Sound 980# Sound
926# 981#
927# CONFIG_SOUND is not set 982CONFIG_SOUND=m
983
984#
985# Advanced Linux Sound Architecture
986#
987CONFIG_SND=m
988CONFIG_SND_TIMER=m
989CONFIG_SND_PCM=m
990CONFIG_SND_HWDEP=m
991CONFIG_SND_RAWMIDI=m
992CONFIG_SND_SEQUENCER=m
993# CONFIG_SND_SEQ_DUMMY is not set
994CONFIG_SND_OSSEMUL=y
995CONFIG_SND_MIXER_OSS=m
996CONFIG_SND_PCM_OSS=m
997CONFIG_SND_SEQUENCER_OSS=y
998# CONFIG_SND_VERBOSE_PRINTK is not set
999# CONFIG_SND_DEBUG is not set
1000CONFIG_SND_GENERIC_DRIVER=y
1001
1002#
1003# Generic devices
1004#
1005# CONFIG_SND_DUMMY is not set
1006# CONFIG_SND_VIRMIDI is not set
1007# CONFIG_SND_MTPAV is not set
1008# CONFIG_SND_SERIAL_U16550 is not set
1009# CONFIG_SND_MPU401 is not set
1010
1011#
1012# PCI devices
1013#
1014# CONFIG_SND_ALI5451 is not set
1015# CONFIG_SND_ATIIXP is not set
1016# CONFIG_SND_ATIIXP_MODEM is not set
1017# CONFIG_SND_AU8810 is not set
1018# CONFIG_SND_AU8820 is not set
1019# CONFIG_SND_AU8830 is not set
1020# CONFIG_SND_AZT3328 is not set
1021# CONFIG_SND_BT87X is not set
1022# CONFIG_SND_CS46XX is not set
1023# CONFIG_SND_CS4281 is not set
1024# CONFIG_SND_EMU10K1 is not set
1025# CONFIG_SND_EMU10K1X is not set
1026# CONFIG_SND_CA0106 is not set
1027# CONFIG_SND_KORG1212 is not set
1028# CONFIG_SND_MIXART is not set
1029# CONFIG_SND_NM256 is not set
1030# CONFIG_SND_RME32 is not set
1031# CONFIG_SND_RME96 is not set
1032# CONFIG_SND_RME9652 is not set
1033# CONFIG_SND_HDSP is not set
1034# CONFIG_SND_HDSPM is not set
1035# CONFIG_SND_TRIDENT is not set
1036# CONFIG_SND_YMFPCI is not set
1037# CONFIG_SND_AD1889 is not set
1038# CONFIG_SND_ALS4000 is not set
1039# CONFIG_SND_CMIPCI is not set
1040# CONFIG_SND_ENS1370 is not set
1041# CONFIG_SND_ENS1371 is not set
1042# CONFIG_SND_ES1938 is not set
1043# CONFIG_SND_ES1968 is not set
1044# CONFIG_SND_MAESTRO3 is not set
1045# CONFIG_SND_FM801 is not set
1046# CONFIG_SND_ICE1712 is not set
1047# CONFIG_SND_ICE1724 is not set
1048# CONFIG_SND_INTEL8X0 is not set
1049# CONFIG_SND_INTEL8X0M is not set
1050# CONFIG_SND_SONICVIBES is not set
1051# CONFIG_SND_VIA82XX is not set
1052# CONFIG_SND_VIA82XX_MODEM is not set
1053# CONFIG_SND_VX222 is not set
1054# CONFIG_SND_HDA_INTEL is not set
1055
1056#
1057# ALSA PowerMac devices
1058#
1059CONFIG_SND_POWERMAC=m
1060CONFIG_SND_POWERMAC_AUTO_DRC=y
1061
1062#
1063# USB devices
1064#
1065CONFIG_SND_USB_AUDIO=m
1066# CONFIG_SND_USB_USX2Y is not set
1067
1068#
1069# Open Sound System
1070#
1071# CONFIG_SOUND_PRIME is not set
928 1072
929# 1073#
930# USB support 1074# USB support
@@ -958,12 +1102,16 @@ CONFIG_USB_OHCI_LITTLE_ENDIAN=y
958# 1102#
959# USB Device Class drivers 1103# USB Device Class drivers
960# 1104#
961# CONFIG_USB_BLUETOOTH_TTY is not set 1105# CONFIG_OBSOLETE_OSS_USB_DRIVER is not set
962CONFIG_USB_ACM=m 1106CONFIG_USB_ACM=m
963CONFIG_USB_PRINTER=y 1107CONFIG_USB_PRINTER=y
964 1108
965# 1109#
966# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information 1110# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
1111#
1112
1113#
1114# may also be needed; see USB_STORAGE Help for more information
967# 1115#
968CONFIG_USB_STORAGE=y 1116CONFIG_USB_STORAGE=y
969# CONFIG_USB_STORAGE_DEBUG is not set 1117# CONFIG_USB_STORAGE_DEBUG is not set
@@ -1074,6 +1222,7 @@ CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y
1074CONFIG_USB_SERIAL_KLSI=m 1222CONFIG_USB_SERIAL_KLSI=m
1075CONFIG_USB_SERIAL_KOBIL_SCT=m 1223CONFIG_USB_SERIAL_KOBIL_SCT=m
1076CONFIG_USB_SERIAL_MCT_U232=m 1224CONFIG_USB_SERIAL_MCT_U232=m
1225# CONFIG_USB_SERIAL_NOKIA_DKU2 is not set
1077CONFIG_USB_SERIAL_PL2303=m 1226CONFIG_USB_SERIAL_PL2303=m
1078# CONFIG_USB_SERIAL_HP4X is not set 1227# CONFIG_USB_SERIAL_HP4X is not set
1079CONFIG_USB_SERIAL_SAFE=m 1228CONFIG_USB_SERIAL_SAFE=m
@@ -1311,6 +1460,20 @@ CONFIG_NLS_ISO8859_15=y
1311CONFIG_NLS_UTF8=y 1460CONFIG_NLS_UTF8=y
1312 1461
1313# 1462#
1463# Library routines
1464#
1465CONFIG_CRC_CCITT=m
1466# CONFIG_CRC16 is not set
1467CONFIG_CRC32=y
1468CONFIG_LIBCRC32C=m
1469CONFIG_ZLIB_INFLATE=y
1470CONFIG_ZLIB_DEFLATE=m
1471CONFIG_TEXTSEARCH=y
1472CONFIG_TEXTSEARCH_KMP=m
1473CONFIG_TEXTSEARCH_BM=m
1474CONFIG_TEXTSEARCH_FSM=m
1475
1476#
1314# Profiling support 1477# Profiling support
1315# 1478#
1316CONFIG_PROFILING=y 1479CONFIG_PROFILING=y
@@ -1331,12 +1494,14 @@ CONFIG_DETECT_SOFTLOCKUP=y
1331# CONFIG_DEBUG_KOBJECT is not set 1494# CONFIG_DEBUG_KOBJECT is not set
1332# CONFIG_DEBUG_INFO is not set 1495# CONFIG_DEBUG_INFO is not set
1333CONFIG_DEBUG_FS=y 1496CONFIG_DEBUG_FS=y
1497# CONFIG_DEBUG_VM is not set
1498# CONFIG_RCU_TORTURE_TEST is not set
1334# CONFIG_DEBUG_STACKOVERFLOW is not set 1499# CONFIG_DEBUG_STACKOVERFLOW is not set
1335# CONFIG_KPROBES is not set 1500# CONFIG_KPROBES is not set
1336# CONFIG_DEBUG_STACK_USAGE is not set 1501# CONFIG_DEBUG_STACK_USAGE is not set
1337# CONFIG_DEBUGGER is not set 1502# CONFIG_DEBUGGER is not set
1338# CONFIG_PPCDBG is not set
1339CONFIG_IRQSTACKS=y 1503CONFIG_IRQSTACKS=y
1504CONFIG_BOOTX_TEXT=y
1340 1505
1341# 1506#
1342# Security options 1507# Security options
@@ -1376,17 +1541,3 @@ CONFIG_CRYPTO_TEST=m
1376# 1541#
1377# Hardware crypto devices 1542# Hardware crypto devices
1378# 1543#
1379
1380#
1381# Library routines
1382#
1383CONFIG_CRC_CCITT=m
1384# CONFIG_CRC16 is not set
1385CONFIG_CRC32=y
1386CONFIG_LIBCRC32C=m
1387CONFIG_ZLIB_INFLATE=y
1388CONFIG_ZLIB_DEFLATE=m
1389CONFIG_TEXTSEARCH=y
1390CONFIG_TEXTSEARCH_KMP=m
1391CONFIG_TEXTSEARCH_BM=m
1392CONFIG_TEXTSEARCH_FSM=m
diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S
index b3e95ff0dba0..ae1433da09b2 100644
--- a/arch/powerpc/kernel/misc_64.S
+++ b/arch/powerpc/kernel/misc_64.S
@@ -604,6 +604,76 @@ _GLOBAL(real_writeb)
604#endif /* defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE) */ 604#endif /* defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE) */
605 605
606/* 606/*
607 * SCOM access functions for 970 (FX only for now)
608 *
609 * unsigned long scom970_read(unsigned int address);
610 * void scom970_write(unsigned int address, unsigned long value);
611 *
612 * The address passed in is the 24 bits register address. This code
613 * is 970 specific and will not check the status bits, so you should
614 * know what you are doing.
615 */
616_GLOBAL(scom970_read)
617 /* interrupts off */
618 mfmsr r4
619 ori r0,r4,MSR_EE
620 xori r0,r0,MSR_EE
621 mtmsrd r0,1
622
623 /* rotate 24 bits SCOM address 8 bits left and mask out it's low 8 bits
624 * (including parity). On current CPUs they must be 0'd,
625 * and finally or in RW bit
626 */
627 rlwinm r3,r3,8,0,15
628 ori r3,r3,0x8000
629
630 /* do the actual scom read */
631 sync
632 mtspr SPRN_SCOMC,r3
633 isync
634 mfspr r3,SPRN_SCOMD
635 isync
636 mfspr r0,SPRN_SCOMC
637 isync
638
639 /* XXX: fixup result on some buggy 970's (ouch ! we lost a bit, bah
640 * that's the best we can do). Not implemented yet as we don't use
641 * the scom on any of the bogus CPUs yet, but may have to be done
642 * ultimately
643 */
644
645 /* restore interrupts */
646 mtmsrd r4,1
647 blr
648
649
650_GLOBAL(scom970_write)
651 /* interrupts off */
652 mfmsr r5
653 ori r0,r5,MSR_EE
654 xori r0,r0,MSR_EE
655 mtmsrd r0,1
656
657 /* rotate 24 bits SCOM address 8 bits left and mask out it's low 8 bits
658 * (including parity). On current CPUs they must be 0'd.
659 */
660
661 rlwinm r3,r3,8,0,15
662
663 sync
664 mtspr SPRN_SCOMD,r4 /* write data */
665 isync
666 mtspr SPRN_SCOMC,r3 /* write command */
667 isync
668 mfspr 3,SPRN_SCOMC
669 isync
670
671 /* restore interrupts */
672 mtmsrd r5,1
673 blr
674
675
676/*
607 * Create a kernel thread 677 * Create a kernel thread
608 * kernel_thread(fn, arg, flags) 678 * kernel_thread(fn, arg, flags)
609 */ 679 */
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 7f64f0464d44..de69fb37c731 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -46,10 +46,10 @@
46#include <asm/processor.h> 46#include <asm/processor.h>
47#include <asm/mmu.h> 47#include <asm/mmu.h>
48#include <asm/prom.h> 48#include <asm/prom.h>
49#include <asm/machdep.h>
49#ifdef CONFIG_PPC64 50#ifdef CONFIG_PPC64
50#include <asm/firmware.h> 51#include <asm/firmware.h>
51#include <asm/time.h> 52#include <asm/time.h>
52#include <asm/machdep.h>
53#endif 53#endif
54 54
55extern unsigned long _get_SP(void); 55extern unsigned long _get_SP(void);
@@ -203,10 +203,8 @@ int dump_spe(struct pt_regs *regs, elf_vrregset_t *evrregs)
203 203
204int set_dabr(unsigned long dabr) 204int set_dabr(unsigned long dabr)
205{ 205{
206#ifdef CONFIG_PPC64
207 if (ppc_md.set_dabr) 206 if (ppc_md.set_dabr)
208 return ppc_md.set_dabr(dabr); 207 return ppc_md.set_dabr(dabr);
209#endif
210 208
211 mtspr(SPRN_DABR, dabr); 209 mtspr(SPRN_DABR, dabr);
212 return 0; 210 return 0;
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index 3675ef4bac90..f645adb57534 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -1974,14 +1974,29 @@ EXPORT_SYMBOL(get_property);
1974/* 1974/*
1975 * Add a property to a node 1975 * Add a property to a node
1976 */ 1976 */
1977void prom_add_property(struct device_node* np, struct property* prop) 1977int prom_add_property(struct device_node* np, struct property* prop)
1978{ 1978{
1979 struct property **next = &np->properties; 1979 struct property **next;
1980 1980
1981 prop->next = NULL; 1981 prop->next = NULL;
1982 while (*next) 1982 write_lock(&devtree_lock);
1983 next = &np->properties;
1984 while (*next) {
1985 if (strcmp(prop->name, (*next)->name) == 0) {
1986 /* duplicate ! don't insert it */
1987 write_unlock(&devtree_lock);
1988 return -1;
1989 }
1983 next = &(*next)->next; 1990 next = &(*next)->next;
1991 }
1984 *next = prop; 1992 *next = prop;
1993 write_unlock(&devtree_lock);
1994
1995 /* try to add to proc as well if it was initialized */
1996 if (np->pde)
1997 proc_device_tree_add_prop(np->pde, prop);
1998
1999 return 0;
1985} 2000}
1986 2001
1987/* I quickly hacked that one, check against spec ! */ 2002/* I quickly hacked that one, check against spec ! */
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c
index c758b6624d7b..6dc33d19fc2a 100644
--- a/arch/powerpc/kernel/prom_init.c
+++ b/arch/powerpc/kernel/prom_init.c
@@ -403,19 +403,19 @@ static int __init prom_next_node(phandle *nodep)
403 } 403 }
404} 404}
405 405
406static int __init prom_getprop(phandle node, const char *pname, 406static int inline prom_getprop(phandle node, const char *pname,
407 void *value, size_t valuelen) 407 void *value, size_t valuelen)
408{ 408{
409 return call_prom("getprop", 4, 1, node, ADDR(pname), 409 return call_prom("getprop", 4, 1, node, ADDR(pname),
410 (u32)(unsigned long) value, (u32) valuelen); 410 (u32)(unsigned long) value, (u32) valuelen);
411} 411}
412 412
413static int __init prom_getproplen(phandle node, const char *pname) 413static int inline prom_getproplen(phandle node, const char *pname)
414{ 414{
415 return call_prom("getproplen", 2, 1, node, ADDR(pname)); 415 return call_prom("getproplen", 2, 1, node, ADDR(pname));
416} 416}
417 417
418static int __init prom_setprop(phandle node, const char *pname, 418static int inline prom_setprop(phandle node, const char *pname,
419 void *value, size_t valuelen) 419 void *value, size_t valuelen)
420{ 420{
421 return call_prom("setprop", 4, 1, node, ADDR(pname), 421 return call_prom("setprop", 4, 1, node, ADDR(pname),
@@ -1408,8 +1408,9 @@ static int __init prom_find_machine_type(void)
1408 struct prom_t *_prom = &RELOC(prom); 1408 struct prom_t *_prom = &RELOC(prom);
1409 char compat[256]; 1409 char compat[256];
1410 int len, i = 0; 1410 int len, i = 0;
1411#ifdef CONFIG_PPC64
1411 phandle rtas; 1412 phandle rtas;
1412 1413#endif
1413 len = prom_getprop(_prom->root, "compatible", 1414 len = prom_getprop(_prom->root, "compatible",
1414 compat, sizeof(compat)-1); 1415 compat, sizeof(compat)-1);
1415 if (len > 0) { 1416 if (len > 0) {
@@ -1872,7 +1873,7 @@ static void __init fixup_device_tree(void)
1872 if (prom_getprop(u3, "device-rev", &u3_rev, sizeof(u3_rev)) 1873 if (prom_getprop(u3, "device-rev", &u3_rev, sizeof(u3_rev))
1873 == PROM_ERROR) 1874 == PROM_ERROR)
1874 return; 1875 return;
1875 if (u3_rev != 0x35 && u3_rev != 0x37) 1876 if (u3_rev < 0x35 || u3_rev > 0x39)
1876 return; 1877 return;
1877 /* does it need fixup ? */ 1878 /* does it need fixup ? */
1878 if (prom_getproplen(i2c, "interrupts") > 0) 1879 if (prom_getproplen(i2c, "interrupts") > 0)
diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c
index b7fc2d884950..9d4e07f6f1ec 100644
--- a/arch/powerpc/kernel/rtas.c
+++ b/arch/powerpc/kernel/rtas.c
@@ -17,6 +17,7 @@
17#include <linux/spinlock.h> 17#include <linux/spinlock.h>
18#include <linux/module.h> 18#include <linux/module.h>
19#include <linux/init.h> 19#include <linux/init.h>
20#include <linux/delay.h>
20 21
21#include <asm/prom.h> 22#include <asm/prom.h>
22#include <asm/rtas.h> 23#include <asm/rtas.h>
@@ -83,7 +84,7 @@ void call_rtas_display_status_delay(unsigned char c)
83 while (width-- > 0) 84 while (width-- > 0)
84 call_rtas_display_status(' '); 85 call_rtas_display_status(' ');
85 width = 16; 86 width = 16;
86 udelay(500000); 87 mdelay(500);
87 pending_newline = 1; 88 pending_newline = 1;
88 } else { 89 } else {
89 if (pending_newline) { 90 if (pending_newline) {
@@ -608,7 +609,6 @@ asmlinkage int ppc_rtas(struct rtas_args __user *uargs)
608 return 0; 609 return 0;
609} 610}
610 611
611#ifdef CONFIG_SMP
612/* This version can't take the spinlock, because it never returns */ 612/* This version can't take the spinlock, because it never returns */
613 613
614struct rtas_args rtas_stop_self_args = { 614struct rtas_args rtas_stop_self_args = {
@@ -633,7 +633,6 @@ void rtas_stop_self(void)
633 633
634 panic("Alas, I survived.\n"); 634 panic("Alas, I survived.\n");
635} 635}
636#endif
637 636
638/* 637/*
639 * Call early during boot, before mem init or bootmem, to retreive the RTAS 638 * Call early during boot, before mem init or bootmem, to retreive the RTAS
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c
index d43fa8c0e5ac..e22856ecb5a0 100644
--- a/arch/powerpc/kernel/setup-common.c
+++ b/arch/powerpc/kernel/setup-common.c
@@ -405,6 +405,46 @@ static int __init set_preferred_console(void)
405console_initcall(set_preferred_console); 405console_initcall(set_preferred_console);
406#endif /* CONFIG_PPC_MULTIPLATFORM */ 406#endif /* CONFIG_PPC_MULTIPLATFORM */
407 407
408void __init check_for_initrd(void)
409{
410#ifdef CONFIG_BLK_DEV_INITRD
411 unsigned long *prop;
412
413 DBG(" -> check_for_initrd()\n");
414
415 if (of_chosen) {
416 prop = (unsigned long *)get_property(of_chosen,
417 "linux,initrd-start", NULL);
418 if (prop != NULL) {
419 initrd_start = (unsigned long)__va(*prop);
420 prop = (unsigned long *)get_property(of_chosen,
421 "linux,initrd-end", NULL);
422 if (prop != NULL) {
423 initrd_end = (unsigned long)__va(*prop);
424 initrd_below_start_ok = 1;
425 } else
426 initrd_start = 0;
427 }
428 }
429
430 /* If we were passed an initrd, set the ROOT_DEV properly if the values
431 * look sensible. If not, clear initrd reference.
432 */
433 if (initrd_start >= KERNELBASE && initrd_end >= KERNELBASE &&
434 initrd_end > initrd_start)
435 ROOT_DEV = Root_RAM0;
436 else {
437 printk("Bogus initrd %08lx %08lx\n", initrd_start, initrd_end);
438 initrd_start = initrd_end = 0;
439 }
440
441 if (initrd_start)
442 printk("Found initrd at 0x%lx:0x%lx\n", initrd_start, initrd_end);
443
444 DBG(" <- check_for_initrd()\n");
445#endif /* CONFIG_BLK_DEV_INITRD */
446}
447
408#ifdef CONFIG_SMP 448#ifdef CONFIG_SMP
409 449
410/** 450/**
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index b45eedbb4b3a..3af2631e3fab 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -286,6 +286,7 @@ void __init setup_arch(char **cmdline_p)
286 loops_per_jiffy = 500000000 / HZ; 286 loops_per_jiffy = 500000000 / HZ;
287 287
288 unflatten_device_tree(); 288 unflatten_device_tree();
289 check_for_initrd();
289 finish_device_tree(); 290 finish_device_tree();
290 291
291 smp_setup_cpu_maps(); 292 smp_setup_cpu_maps();
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index b0994050024f..0471e843b6c5 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -41,7 +41,6 @@
41#include <asm/elf.h> 41#include <asm/elf.h>
42#include <asm/machdep.h> 42#include <asm/machdep.h>
43#include <asm/paca.h> 43#include <asm/paca.h>
44#include <asm/ppcdebug.h>
45#include <asm/time.h> 44#include <asm/time.h>
46#include <asm/cputable.h> 45#include <asm/cputable.h>
47#include <asm/sections.h> 46#include <asm/sections.h>
@@ -60,6 +59,7 @@
60#include <asm/firmware.h> 59#include <asm/firmware.h>
61#include <asm/systemcfg.h> 60#include <asm/systemcfg.h>
62#include <asm/xmon.h> 61#include <asm/xmon.h>
62#include <asm/udbg.h>
63 63
64#ifdef DEBUG 64#ifdef DEBUG
65#define DBG(fmt...) udbg_printf(fmt) 65#define DBG(fmt...) udbg_printf(fmt)
@@ -244,12 +244,6 @@ void __init early_setup(unsigned long dt_ptr)
244 DBG(" -> early_setup()\n"); 244 DBG(" -> early_setup()\n");
245 245
246 /* 246 /*
247 * Fill the default DBG level (do we want to keep
248 * that old mecanism around forever ?)
249 */
250 ppcdbg_initialize();
251
252 /*
253 * Do early initializations using the flattened device 247 * Do early initializations using the flattened device
254 * tree, like retreiving the physical memory map or 248 * tree, like retreiving the physical memory map or
255 * calculating/retreiving the hash table size 249 * calculating/retreiving the hash table size
@@ -401,43 +395,6 @@ static void __init initialize_cache_info(void)
401 DBG(" <- initialize_cache_info()\n"); 395 DBG(" <- initialize_cache_info()\n");
402} 396}
403 397
404static void __init check_for_initrd(void)
405{
406#ifdef CONFIG_BLK_DEV_INITRD
407 u64 *prop;
408
409 DBG(" -> check_for_initrd()\n");
410
411 if (of_chosen) {
412 prop = (u64 *)get_property(of_chosen,
413 "linux,initrd-start", NULL);
414 if (prop != NULL) {
415 initrd_start = (unsigned long)__va(*prop);
416 prop = (u64 *)get_property(of_chosen,
417 "linux,initrd-end", NULL);
418 if (prop != NULL) {
419 initrd_end = (unsigned long)__va(*prop);
420 initrd_below_start_ok = 1;
421 } else
422 initrd_start = 0;
423 }
424 }
425
426 /* If we were passed an initrd, set the ROOT_DEV properly if the values
427 * look sensible. If not, clear initrd reference.
428 */
429 if (initrd_start >= KERNELBASE && initrd_end >= KERNELBASE &&
430 initrd_end > initrd_start)
431 ROOT_DEV = Root_RAM0;
432 else
433 initrd_start = initrd_end = 0;
434
435 if (initrd_start)
436 printk("Found initrd at 0x%lx:0x%lx\n", initrd_start, initrd_end);
437
438 DBG(" <- check_for_initrd()\n");
439#endif /* CONFIG_BLK_DEV_INITRD */
440}
441 398
442/* 399/*
443 * Do some initial setup of the system. The parameters are those which 400 * Do some initial setup of the system. The parameters are those which
@@ -521,7 +478,6 @@ void __init setup_system(void)
521 478
522 printk("-----------------------------------------------------\n"); 479 printk("-----------------------------------------------------\n");
523 printk("ppc64_pft_size = 0x%lx\n", ppc64_pft_size); 480 printk("ppc64_pft_size = 0x%lx\n", ppc64_pft_size);
524 printk("ppc64_debug_switch = 0x%lx\n", ppc64_debug_switch);
525 printk("ppc64_interrupt_controller = 0x%ld\n", ppc64_interrupt_controller); 481 printk("ppc64_interrupt_controller = 0x%ld\n", ppc64_interrupt_controller);
526 printk("systemcfg = 0x%p\n", systemcfg); 482 printk("systemcfg = 0x%p\n", systemcfg);
527 printk("systemcfg->platform = 0x%x\n", systemcfg->platform); 483 printk("systemcfg->platform = 0x%x\n", systemcfg->platform);
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c
index 876c57c11365..081d931eae48 100644
--- a/arch/powerpc/kernel/signal_32.c
+++ b/arch/powerpc/kernel/signal_32.c
@@ -44,7 +44,6 @@
44#include <asm/cacheflush.h> 44#include <asm/cacheflush.h>
45#ifdef CONFIG_PPC64 45#ifdef CONFIG_PPC64
46#include "ppc32.h" 46#include "ppc32.h"
47#include <asm/ppcdebug.h>
48#include <asm/unistd.h> 47#include <asm/unistd.h>
49#include <asm/vdso.h> 48#include <asm/vdso.h>
50#else 49#else
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c
index ec9d0984b6a0..58194e150711 100644
--- a/arch/powerpc/kernel/signal_64.c
+++ b/arch/powerpc/kernel/signal_64.c
@@ -33,7 +33,6 @@
33#include <asm/ucontext.h> 33#include <asm/ucontext.h>
34#include <asm/uaccess.h> 34#include <asm/uaccess.h>
35#include <asm/pgtable.h> 35#include <asm/pgtable.h>
36#include <asm/ppcdebug.h>
37#include <asm/unistd.h> 36#include <asm/unistd.h>
38#include <asm/cacheflush.h> 37#include <asm/cacheflush.h>
39#include <asm/vdso.h> 38#include <asm/vdso.h>
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index 1794a694a928..5c330c3366e4 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -40,7 +40,6 @@
40#include <asm/prom.h> 40#include <asm/prom.h>
41#include <asm/smp.h> 41#include <asm/smp.h>
42#include <asm/time.h> 42#include <asm/time.h>
43#include <asm/xmon.h>
44#include <asm/machdep.h> 43#include <asm/machdep.h>
45#include <asm/cputable.h> 44#include <asm/cputable.h>
46#include <asm/system.h> 45#include <asm/system.h>
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index b1c89bc4bf90..a6282b625b44 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -61,6 +61,7 @@
61#include <asm/prom.h> 61#include <asm/prom.h>
62#include <asm/irq.h> 62#include <asm/irq.h>
63#include <asm/div64.h> 63#include <asm/div64.h>
64#include <asm/smp.h>
64#ifdef CONFIG_PPC64 65#ifdef CONFIG_PPC64
65#include <asm/systemcfg.h> 66#include <asm/systemcfg.h>
66#include <asm/firmware.h> 67#include <asm/firmware.h>
@@ -119,10 +120,6 @@ static unsigned adjusting_time = 0;
119unsigned long ppc_proc_freq; 120unsigned long ppc_proc_freq;
120unsigned long ppc_tb_freq; 121unsigned long ppc_tb_freq;
121 122
122#ifdef CONFIG_PPC32 /* XXX for now */
123#define boot_cpuid 0
124#endif
125
126u64 tb_last_jiffy __cacheline_aligned_in_smp; 123u64 tb_last_jiffy __cacheline_aligned_in_smp;
127unsigned long tb_last_stamp; 124unsigned long tb_last_stamp;
128 125
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 07e5ee40b870..32f215825e8d 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -39,7 +39,6 @@
39#include <asm/io.h> 39#include <asm/io.h>
40#include <asm/machdep.h> 40#include <asm/machdep.h>
41#include <asm/rtas.h> 41#include <asm/rtas.h>
42#include <asm/xmon.h>
43#include <asm/pmc.h> 42#include <asm/pmc.h>
44#ifdef CONFIG_PPC32 43#ifdef CONFIG_PPC32
45#include <asm/reg.h> 44#include <asm/reg.h>
@@ -748,22 +747,12 @@ static int check_bug_trap(struct pt_regs *regs)
748 return 0; 747 return 0;
749 if (bug->line & BUG_WARNING_TRAP) { 748 if (bug->line & BUG_WARNING_TRAP) {
750 /* this is a WARN_ON rather than BUG/BUG_ON */ 749 /* this is a WARN_ON rather than BUG/BUG_ON */
751#ifdef CONFIG_XMON
752 xmon_printf(KERN_ERR "Badness in %s at %s:%ld\n",
753 bug->function, bug->file,
754 bug->line & ~BUG_WARNING_TRAP);
755#endif /* CONFIG_XMON */
756 printk(KERN_ERR "Badness in %s at %s:%ld\n", 750 printk(KERN_ERR "Badness in %s at %s:%ld\n",
757 bug->function, bug->file, 751 bug->function, bug->file,
758 bug->line & ~BUG_WARNING_TRAP); 752 bug->line & ~BUG_WARNING_TRAP);
759 dump_stack(); 753 dump_stack();
760 return 1; 754 return 1;
761 } 755 }
762#ifdef CONFIG_XMON
763 xmon_printf(KERN_CRIT "kernel BUG in %s at %s:%ld!\n",
764 bug->function, bug->file, bug->line);
765 xmon(regs);
766#endif /* CONFIG_XMON */
767 printk(KERN_CRIT "kernel BUG in %s at %s:%ld!\n", 756 printk(KERN_CRIT "kernel BUG in %s at %s:%ld!\n",
768 bug->function, bug->file, bug->line); 757 bug->function, bug->file, bug->line);
769 758
diff --git a/arch/powerpc/lib/locks.c b/arch/powerpc/lib/locks.c
index 2a912f411eb4..35bd03c41dd1 100644
--- a/arch/powerpc/lib/locks.c
+++ b/arch/powerpc/lib/locks.c
@@ -23,6 +23,7 @@
23#if defined(CONFIG_PPC_SPLPAR) || defined(CONFIG_PPC_ISERIES) 23#if defined(CONFIG_PPC_SPLPAR) || defined(CONFIG_PPC_ISERIES)
24#include <asm/hvcall.h> 24#include <asm/hvcall.h>
25#include <asm/iseries/hv_call.h> 25#include <asm/iseries/hv_call.h>
26#include <asm/smp.h>
26 27
27void __spin_yield(raw_spinlock_t *lock) 28void __spin_yield(raw_spinlock_t *lock)
28{ 29{
diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c
index 841d8b6323a8..93d4fbfdb724 100644
--- a/arch/powerpc/mm/fault.c
+++ b/arch/powerpc/mm/fault.c
@@ -389,5 +389,22 @@ void bad_page_fault(struct pt_regs *regs, unsigned long address, int sig)
389 } 389 }
390 390
391 /* kernel has accessed a bad area */ 391 /* kernel has accessed a bad area */
392
393 printk(KERN_ALERT "Unable to handle kernel paging request for ");
394 switch (regs->trap) {
395 case 0x300:
396 case 0x380:
397 printk("data at address 0x%08lx\n", regs->dar);
398 break;
399 case 0x400:
400 case 0x480:
401 printk("instruction fetch\n");
402 break;
403 default:
404 printk("unknown fault\n");
405 }
406 printk(KERN_ALERT "Faulting instruction address: 0x%08lx\n",
407 regs->nip);
408
392 die("Kernel access of bad area", regs, sig); 409 die("Kernel access of bad area", regs, sig);
393} 410}
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index f15dfb92dec0..22e474876133 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -33,7 +33,6 @@
33#include <linux/init.h> 33#include <linux/init.h>
34#include <linux/signal.h> 34#include <linux/signal.h>
35 35
36#include <asm/ppcdebug.h>
37#include <asm/processor.h> 36#include <asm/processor.h>
38#include <asm/pgtable.h> 37#include <asm/pgtable.h>
39#include <asm/mmu.h> 38#include <asm/mmu.h>
@@ -409,12 +408,6 @@ void __init htab_initialize(void)
409 htab_size_bytes = htab_get_table_size(); 408 htab_size_bytes = htab_get_table_size();
410 pteg_count = htab_size_bytes >> 7; 409 pteg_count = htab_size_bytes >> 7;
411 410
412 /* For debug, make the HTAB 1/8 as big as it normally would be. */
413 ifppcdebug(PPCDBG_HTABSIZE) {
414 pteg_count >>= 3;
415 htab_size_bytes = pteg_count << 7;
416 }
417
418 htab_hash_mask = pteg_count - 1; 411 htab_hash_mask = pteg_count - 1;
419 412
420 if (systemcfg->platform & PLATFORM_LPAR) { 413 if (systemcfg->platform & PLATFORM_LPAR) {
@@ -514,6 +507,9 @@ unsigned int hash_page_do_lazy_icache(unsigned int pp, pte_t pte, int trap)
514{ 507{
515 struct page *page; 508 struct page *page;
516 509
510 if (!pfn_valid(pte_pfn(pte)))
511 return pp;
512
517 page = pte_page(pte); 513 page = pte_page(pte);
518 514
519 /* page is dirty */ 515 /* page is dirty */
diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c
index dfe7fa37b41a..ce974c83d88a 100644
--- a/arch/powerpc/mm/init_64.c
+++ b/arch/powerpc/mm/init_64.c
@@ -57,7 +57,6 @@
57#include <asm/processor.h> 57#include <asm/processor.h>
58#include <asm/mmzone.h> 58#include <asm/mmzone.h>
59#include <asm/cputable.h> 59#include <asm/cputable.h>
60#include <asm/ppcdebug.h>
61#include <asm/sections.h> 60#include <asm/sections.h>
62#include <asm/system.h> 61#include <asm/system.h>
63#include <asm/iommu.h> 62#include <asm/iommu.h>
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index 7faa46b71f21..6f55efd9be95 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -358,7 +358,7 @@ void __init mem_init(void)
358 } 358 }
359 359
360 codesize = (unsigned long)&_sdata - (unsigned long)&_stext; 360 codesize = (unsigned long)&_sdata - (unsigned long)&_stext;
361 datasize = (unsigned long)&__init_begin - (unsigned long)&_sdata; 361 datasize = (unsigned long)&_edata - (unsigned long)&_sdata;
362 initsize = (unsigned long)&__init_end - (unsigned long)&__init_begin; 362 initsize = (unsigned long)&__init_end - (unsigned long)&__init_begin;
363 bsssize = (unsigned long)&__bss_stop - (unsigned long)&__bss_start; 363 bsssize = (unsigned long)&__bss_stop - (unsigned long)&__bss_start;
364 364
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
index 4035cad8d7f1..da09ba03c424 100644
--- a/arch/powerpc/mm/numa.c
+++ b/arch/powerpc/mm/numa.c
@@ -21,6 +21,7 @@
21#include <asm/machdep.h> 21#include <asm/machdep.h>
22#include <asm/abs_addr.h> 22#include <asm/abs_addr.h>
23#include <asm/system.h> 23#include <asm/system.h>
24#include <asm/smp.h>
24 25
25static int numa_enabled = 1; 26static int numa_enabled = 1;
26 27
diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c
index 51b786940971..900842451bd3 100644
--- a/arch/powerpc/mm/pgtable_64.c
+++ b/arch/powerpc/mm/pgtable_64.c
@@ -59,7 +59,6 @@
59#include <asm/processor.h> 59#include <asm/processor.h>
60#include <asm/mmzone.h> 60#include <asm/mmzone.h>
61#include <asm/cputable.h> 61#include <asm/cputable.h>
62#include <asm/ppcdebug.h>
63#include <asm/sections.h> 62#include <asm/sections.h>
64#include <asm/system.h> 63#include <asm/system.h>
65#include <asm/iommu.h> 64#include <asm/iommu.h>
diff --git a/arch/powerpc/oprofile/op_model_power4.c b/arch/powerpc/oprofile/op_model_power4.c
index 886449315847..c4ee5478427b 100644
--- a/arch/powerpc/oprofile/op_model_power4.c
+++ b/arch/powerpc/oprofile/op_model_power4.c
@@ -17,6 +17,7 @@
17#include <asm/systemcfg.h> 17#include <asm/systemcfg.h>
18#include <asm/rtas.h> 18#include <asm/rtas.h>
19#include <asm/oprofile_impl.h> 19#include <asm/oprofile_impl.h>
20#include <asm/reg.h>
20 21
21#define dbg(args...) 22#define dbg(args...)
22 23
@@ -81,6 +82,26 @@ static void power4_reg_setup(struct op_counter_config *ctr,
81 82
82extern void ppc64_enable_pmcs(void); 83extern void ppc64_enable_pmcs(void);
83 84
85/*
86 * Older CPUs require the MMCRA sample bit to be always set, but newer
87 * CPUs only want it set for some groups. Eventually we will remove all
88 * knowledge of this bit in the kernel, oprofile userspace should be
89 * setting it when required.
90 *
91 * In order to keep current installations working we force the bit for
92 * those older CPUs. Once everyone has updated their oprofile userspace we
93 * can remove this hack.
94 */
95static inline int mmcra_must_set_sample(void)
96{
97 if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p) ||
98 __is_processor(PV_970) || __is_processor(PV_970FX) ||
99 __is_processor(PV_970MP))
100 return 1;
101
102 return 0;
103}
104
84static void power4_cpu_setup(void *unused) 105static void power4_cpu_setup(void *unused)
85{ 106{
86 unsigned int mmcr0 = mmcr0_val; 107 unsigned int mmcr0 = mmcr0_val;
@@ -98,7 +119,8 @@ static void power4_cpu_setup(void *unused)
98 119
99 mtspr(SPRN_MMCR1, mmcr1_val); 120 mtspr(SPRN_MMCR1, mmcr1_val);
100 121
101 mmcra |= MMCRA_SAMPLE_ENABLE; 122 if (mmcra_must_set_sample())
123 mmcra |= MMCRA_SAMPLE_ENABLE;
102 mtspr(SPRN_MMCRA, mmcra); 124 mtspr(SPRN_MMCRA, mmcra);
103 125
104 dbg("setup on cpu %d, mmcr0 %lx\n", smp_processor_id(), 126 dbg("setup on cpu %d, mmcr0 %lx\n", smp_processor_id(),
diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c
index c1135912cc05..a06603d84a45 100644
--- a/arch/powerpc/platforms/iseries/irq.c
+++ b/arch/powerpc/platforms/iseries/irq.c
@@ -35,7 +35,6 @@
35#include <linux/irq.h> 35#include <linux/irq.h>
36#include <linux/spinlock.h> 36#include <linux/spinlock.h>
37 37
38#include <asm/ppcdebug.h>
39#include <asm/iseries/hv_types.h> 38#include <asm/iseries/hv_types.h>
40#include <asm/iseries/hv_lp_event.h> 39#include <asm/iseries/hv_lp_event.h>
41#include <asm/iseries/hv_call_xm.h> 40#include <asm/iseries/hv_call_xm.h>
@@ -227,8 +226,6 @@ static void iSeries_enable_IRQ(unsigned int irq)
227 /* Unmask secondary INTA */ 226 /* Unmask secondary INTA */
228 mask = 0x80000000; 227 mask = 0x80000000;
229 HvCallPci_unmaskInterrupts(bus, subBus, deviceId, mask); 228 HvCallPci_unmaskInterrupts(bus, subBus, deviceId, mask);
230 PPCDBG(PPCDBG_BUSWALK, "iSeries_enable_IRQ 0x%02X.%02X.%02X 0x%04X\n",
231 bus, subBus, deviceId, irq);
232} 229}
233 230
234/* This is called by iSeries_activate_IRQs */ 231/* This is called by iSeries_activate_IRQs */
@@ -310,8 +307,6 @@ static void iSeries_disable_IRQ(unsigned int irq)
310 /* Mask secondary INTA */ 307 /* Mask secondary INTA */
311 mask = 0x80000000; 308 mask = 0x80000000;
312 HvCallPci_maskInterrupts(bus, subBus, deviceId, mask); 309 HvCallPci_maskInterrupts(bus, subBus, deviceId, mask);
313 PPCDBG(PPCDBG_BUSWALK, "iSeries_disable_IRQ 0x%02X.%02X.%02X 0x%04X\n",
314 bus, subBus, deviceId, irq);
315} 310}
316 311
317/* 312/*
diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c
index 7d7d5884343f..4b75131773a6 100644
--- a/arch/powerpc/platforms/iseries/pci.c
+++ b/arch/powerpc/platforms/iseries/pci.c
@@ -32,7 +32,6 @@
32#include <asm/prom.h> 32#include <asm/prom.h>
33#include <asm/machdep.h> 33#include <asm/machdep.h>
34#include <asm/pci-bridge.h> 34#include <asm/pci-bridge.h>
35#include <asm/ppcdebug.h>
36#include <asm/iommu.h> 35#include <asm/iommu.h>
37#include <asm/abs_addr.h> 36#include <asm/abs_addr.h>
38 37
@@ -207,10 +206,6 @@ static struct device_node *build_device_node(HvBusNumber Bus,
207 struct device_node *node; 206 struct device_node *node;
208 struct pci_dn *pdn; 207 struct pci_dn *pdn;
209 208
210 PPCDBG(PPCDBG_BUSWALK,
211 "-build_device_node 0x%02X.%02X.%02X Function: %02X\n",
212 Bus, SubBus, AgentId, Function);
213
214 node = kmalloc(sizeof(struct device_node), GFP_KERNEL); 209 node = kmalloc(sizeof(struct device_node), GFP_KERNEL);
215 if (node == NULL) 210 if (node == NULL)
216 return NULL; 211 return NULL;
@@ -243,8 +238,6 @@ unsigned long __init find_and_init_phbs(void)
243 struct pci_controller *phb; 238 struct pci_controller *phb;
244 HvBusNumber bus; 239 HvBusNumber bus;
245 240
246 PPCDBG(PPCDBG_BUSWALK, "find_and_init_phbs Entry\n");
247
248 /* Check all possible buses. */ 241 /* Check all possible buses. */
249 for (bus = 0; bus < 256; bus++) { 242 for (bus = 0; bus < 256; bus++) {
250 int ret = HvCallXm_testBus(bus); 243 int ret = HvCallXm_testBus(bus);
@@ -261,9 +254,6 @@ unsigned long __init find_and_init_phbs(void)
261 phb->last_busno = bus; 254 phb->last_busno = bus;
262 phb->ops = &iSeries_pci_ops; 255 phb->ops = &iSeries_pci_ops;
263 256
264 PPCDBG(PPCDBG_BUSWALK, "PCI:Create iSeries pci_controller(%p), Bus: %04X\n",
265 phb, bus);
266
267 /* Find and connect the devices. */ 257 /* Find and connect the devices. */
268 scan_PHB_slots(phb); 258 scan_PHB_slots(phb);
269 } 259 }
@@ -285,11 +275,9 @@ unsigned long __init find_and_init_phbs(void)
285 */ 275 */
286void iSeries_pcibios_init(void) 276void iSeries_pcibios_init(void)
287{ 277{
288 PPCDBG(PPCDBG_BUSWALK, "iSeries_pcibios_init Entry.\n");
289 iomm_table_initialize(); 278 iomm_table_initialize();
290 find_and_init_phbs(); 279 find_and_init_phbs();
291 io_page_mask = -1; 280 io_page_mask = -1;
292 PPCDBG(PPCDBG_BUSWALK, "iSeries_pcibios_init Exit.\n");
293} 281}
294 282
295/* 283/*
@@ -301,8 +289,6 @@ void __init iSeries_pci_final_fixup(void)
301 struct device_node *node; 289 struct device_node *node;
302 int DeviceCount = 0; 290 int DeviceCount = 0;
303 291
304 PPCDBG(PPCDBG_BUSWALK, "iSeries_pcibios_fixup Entry.\n");
305
306 /* Fix up at the device node and pci_dev relationship */ 292 /* Fix up at the device node and pci_dev relationship */
307 mf_display_src(0xC9000100); 293 mf_display_src(0xC9000100);
308 294
@@ -316,9 +302,6 @@ void __init iSeries_pci_final_fixup(void)
316 ++DeviceCount; 302 ++DeviceCount;
317 pdev->sysdata = (void *)node; 303 pdev->sysdata = (void *)node;
318 PCI_DN(node)->pcidev = pdev; 304 PCI_DN(node)->pcidev = pdev;
319 PPCDBG(PPCDBG_BUSWALK,
320 "pdev 0x%p <==> DevNode 0x%p\n",
321 pdev, node);
322 allocate_device_bars(pdev); 305 allocate_device_bars(pdev);
323 iSeries_Device_Information(pdev, DeviceCount); 306 iSeries_Device_Information(pdev, DeviceCount);
324 iommu_devnode_init_iSeries(node); 307 iommu_devnode_init_iSeries(node);
@@ -333,13 +316,10 @@ void __init iSeries_pci_final_fixup(void)
333 316
334void pcibios_fixup_bus(struct pci_bus *PciBus) 317void pcibios_fixup_bus(struct pci_bus *PciBus)
335{ 318{
336 PPCDBG(PPCDBG_BUSWALK, "iSeries_pcibios_fixup_bus(0x%04X) Entry.\n",
337 PciBus->number);
338} 319}
339 320
340void pcibios_fixup_resources(struct pci_dev *pdev) 321void pcibios_fixup_resources(struct pci_dev *pdev)
341{ 322{
342 PPCDBG(PPCDBG_BUSWALK, "fixup_resources pdev %p\n", pdev);
343} 323}
344 324
345/* 325/*
@@ -401,9 +381,6 @@ static void scan_EADS_bridge(HvBusNumber bus, HvSubBusNumber SubBus,
401 printk("found device at bus %d idsel %d func %d (AgentId %x)\n", 381 printk("found device at bus %d idsel %d func %d (AgentId %x)\n",
402 bus, IdSel, Function, AgentId); 382 bus, IdSel, Function, AgentId);
403 /* Connect EADs: 0x18.00.12 = 0x00 */ 383 /* Connect EADs: 0x18.00.12 = 0x00 */
404 PPCDBG(PPCDBG_BUSWALK,
405 "PCI:Connect EADs: 0x%02X.%02X.%02X\n",
406 bus, SubBus, AgentId);
407 HvRc = HvCallPci_getBusUnitInfo(bus, SubBus, AgentId, 384 HvRc = HvCallPci_getBusUnitInfo(bus, SubBus, AgentId,
408 iseries_hv_addr(BridgeInfo), 385 iseries_hv_addr(BridgeInfo),
409 sizeof(struct HvCallPci_BridgeInfo)); 386 sizeof(struct HvCallPci_BridgeInfo));
@@ -414,14 +391,6 @@ static void scan_EADS_bridge(HvBusNumber bus, HvSubBusNumber SubBus,
414 BridgeInfo->maxAgents, 391 BridgeInfo->maxAgents,
415 BridgeInfo->maxSubBusNumber, 392 BridgeInfo->maxSubBusNumber,
416 BridgeInfo->logicalSlotNumber); 393 BridgeInfo->logicalSlotNumber);
417 PPCDBG(PPCDBG_BUSWALK,
418 "PCI: BridgeInfo, Type:0x%02X, SubBus:0x%02X, MaxAgents:0x%02X, MaxSubBus: 0x%02X, LSlot: 0x%02X\n",
419 BridgeInfo->busUnitInfo.deviceType,
420 BridgeInfo->subBusNumber,
421 BridgeInfo->maxAgents,
422 BridgeInfo->maxSubBusNumber,
423 BridgeInfo->logicalSlotNumber);
424
425 if (BridgeInfo->busUnitInfo.deviceType == 394 if (BridgeInfo->busUnitInfo.deviceType ==
426 HvCallPci_BridgeDevice) { 395 HvCallPci_BridgeDevice) {
427 /* Scan_Bridge_Slot...: 0x18.00.12 */ 396 /* Scan_Bridge_Slot...: 0x18.00.12 */
@@ -454,9 +423,6 @@ static int scan_bridge_slot(HvBusNumber Bus,
454 423
455 /* iSeries_allocate_IRQ.: 0x18.00.12(0xA3) */ 424 /* iSeries_allocate_IRQ.: 0x18.00.12(0xA3) */
456 Irq = iSeries_allocate_IRQ(Bus, 0, EADsIdSel); 425 Irq = iSeries_allocate_IRQ(Bus, 0, EADsIdSel);
457 PPCDBG(PPCDBG_BUSWALK,
458 "PCI:- allocate and assign IRQ 0x%02X.%02X.%02X = 0x%02X\n",
459 Bus, 0, EADsIdSel, Irq);
460 426
461 /* 427 /*
462 * Connect all functions of any device found. 428 * Connect all functions of any device found.
@@ -482,9 +448,6 @@ static int scan_bridge_slot(HvBusNumber Bus,
482 printk("read vendor ID: %x\n", VendorId); 448 printk("read vendor ID: %x\n", VendorId);
483 449
484 /* FoundDevice: 0x18.28.10 = 0x12AE */ 450 /* FoundDevice: 0x18.28.10 = 0x12AE */
485 PPCDBG(PPCDBG_BUSWALK,
486 "PCI:- FoundDevice: 0x%02X.%02X.%02X = 0x%04X, irq %d\n",
487 Bus, SubBus, AgentId, VendorId, Irq);
488 HvRc = HvCallPci_configStore8(Bus, SubBus, AgentId, 451 HvRc = HvCallPci_configStore8(Bus, SubBus, AgentId,
489 PCI_INTERRUPT_LINE, Irq); 452 PCI_INTERRUPT_LINE, Irq);
490 if (HvRc != 0) 453 if (HvRc != 0)
diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c
index c5207064977d..d3e4bf756c83 100644
--- a/arch/powerpc/platforms/iseries/setup.c
+++ b/arch/powerpc/platforms/iseries/setup.c
@@ -71,8 +71,6 @@ extern void hvlog(char *fmt, ...);
71#endif 71#endif
72 72
73/* Function Prototypes */ 73/* Function Prototypes */
74extern void ppcdbg_initialize(void);
75
76static void build_iSeries_Memory_Map(void); 74static void build_iSeries_Memory_Map(void);
77static void iseries_shared_idle(void); 75static void iseries_shared_idle(void);
78static void iseries_dedicated_idle(void); 76static void iseries_dedicated_idle(void);
@@ -309,8 +307,6 @@ static void __init iSeries_init_early(void)
309 307
310 ppc64_firmware_features = FW_FEATURE_ISERIES; 308 ppc64_firmware_features = FW_FEATURE_ISERIES;
311 309
312 ppcdbg_initialize();
313
314 ppc64_interrupt_controller = IC_ISERIES; 310 ppc64_interrupt_controller = IC_ISERIES;
315 311
316#if defined(CONFIG_BLK_DEV_INITRD) 312#if defined(CONFIG_BLK_DEV_INITRD)
diff --git a/arch/powerpc/platforms/iseries/smp.c b/arch/powerpc/platforms/iseries/smp.c
index 3336bad67724..fcb094ec6aec 100644
--- a/arch/powerpc/platforms/iseries/smp.c
+++ b/arch/powerpc/platforms/iseries/smp.c
@@ -40,7 +40,6 @@
40#include <asm/paca.h> 40#include <asm/paca.h>
41#include <asm/iseries/hv_call.h> 41#include <asm/iseries/hv_call.h>
42#include <asm/time.h> 42#include <asm/time.h>
43#include <asm/ppcdebug.h>
44#include <asm/machdep.h> 43#include <asm/machdep.h>
45#include <asm/cputable.h> 44#include <asm/cputable.h>
46#include <asm/system.h> 45#include <asm/system.h>
diff --git a/arch/powerpc/platforms/powermac/Makefile b/arch/powerpc/platforms/powermac/Makefile
index 4369676f1d54..c9df44fcf571 100644
--- a/arch/powerpc/platforms/powermac/Makefile
+++ b/arch/powerpc/platforms/powermac/Makefile
@@ -1,7 +1,8 @@
1obj-y += pic.o setup.o time.o feature.o pci.o \ 1obj-y += pic.o setup.o time.o feature.o pci.o \
2 sleep.o low_i2c.o cache.o 2 sleep.o low_i2c.o cache.o
3obj-$(CONFIG_PMAC_BACKLIGHT) += backlight.o 3obj-$(CONFIG_PMAC_BACKLIGHT) += backlight.o
4obj-$(CONFIG_CPU_FREQ_PMAC) += cpufreq.o 4obj-$(CONFIG_CPU_FREQ_PMAC) += cpufreq_32.o
5obj-$(CONFIG_CPU_FREQ_PMAC64) += cpufreq_64.o
5obj-$(CONFIG_NVRAM) += nvram.o 6obj-$(CONFIG_NVRAM) += nvram.o
6# ppc64 pmac doesn't define CONFIG_NVRAM but needs nvram stuff 7# ppc64 pmac doesn't define CONFIG_NVRAM but needs nvram stuff
7obj-$(CONFIG_PPC64) += nvram.o 8obj-$(CONFIG_PPC64) += nvram.o
diff --git a/arch/powerpc/platforms/powermac/cpufreq.c b/arch/powerpc/platforms/powermac/cpufreq_32.c
index c47f8b69725c..56fd4e05fede 100644
--- a/arch/powerpc/platforms/powermac/cpufreq.c
+++ b/arch/powerpc/platforms/powermac/cpufreq_32.c
@@ -397,18 +397,16 @@ static int pmac_cpufreq_target( struct cpufreq_policy *policy,
397 unsigned int relation) 397 unsigned int relation)
398{ 398{
399 unsigned int newstate = 0; 399 unsigned int newstate = 0;
400 int rc;
400 401
401 if (cpufreq_frequency_table_target(policy, pmac_cpu_freqs, 402 if (cpufreq_frequency_table_target(policy, pmac_cpu_freqs,
402 target_freq, relation, &newstate)) 403 target_freq, relation, &newstate))
403 return -EINVAL; 404 return -EINVAL;
404 405
405 return do_set_cpu_speed(newstate, 1); 406 rc = do_set_cpu_speed(newstate, 1);
406}
407 407
408unsigned int pmac_get_one_cpufreq(int i) 408 ppc_proc_freq = cur_freq * 1000ul;
409{ 409 return rc;
410 /* Supports only one CPU for now */
411 return (i == 0) ? cur_freq : 0;
412} 410}
413 411
414static int pmac_cpufreq_cpu_init(struct cpufreq_policy *policy) 412static int pmac_cpufreq_cpu_init(struct cpufreq_policy *policy)
@@ -474,6 +472,8 @@ static int pmac_cpufreq_resume(struct cpufreq_policy *policy)
474 do_set_cpu_speed(sleep_freq == low_freq ? 472 do_set_cpu_speed(sleep_freq == low_freq ?
475 CPUFREQ_LOW : CPUFREQ_HIGH, 0); 473 CPUFREQ_LOW : CPUFREQ_HIGH, 0);
476 474
475 ppc_proc_freq = cur_freq * 1000ul;
476
477 no_schedule = 0; 477 no_schedule = 0;
478 return 0; 478 return 0;
479} 479}
@@ -547,7 +547,7 @@ static int pmac_cpufreq_init_MacRISC3(struct device_node *cpunode)
547 */ 547 */
548 if (low_freq < 98000000) 548 if (low_freq < 98000000)
549 low_freq = 101000000; 549 low_freq = 101000000;
550 550
551 /* Convert those to CPU core clocks */ 551 /* Convert those to CPU core clocks */
552 low_freq = (low_freq * (*ratio)) / 2000; 552 low_freq = (low_freq * (*ratio)) / 2000;
553 hi_freq = (hi_freq * (*ratio)) / 2000; 553 hi_freq = (hi_freq * (*ratio)) / 2000;
@@ -714,6 +714,7 @@ out:
714 714
715 pmac_cpu_freqs[CPUFREQ_LOW].frequency = low_freq; 715 pmac_cpu_freqs[CPUFREQ_LOW].frequency = low_freq;
716 pmac_cpu_freqs[CPUFREQ_HIGH].frequency = hi_freq; 716 pmac_cpu_freqs[CPUFREQ_HIGH].frequency = hi_freq;
717 ppc_proc_freq = cur_freq * 1000ul;
717 718
718 printk(KERN_INFO "Registering PowerMac CPU frequency driver\n"); 719 printk(KERN_INFO "Registering PowerMac CPU frequency driver\n");
719 printk(KERN_INFO "Low: %d Mhz, High: %d Mhz, Boot: %d Mhz\n", 720 printk(KERN_INFO "Low: %d Mhz, High: %d Mhz, Boot: %d Mhz\n",
diff --git a/arch/powerpc/platforms/powermac/cpufreq_64.c b/arch/powerpc/platforms/powermac/cpufreq_64.c
new file mode 100644
index 000000000000..39150342c6f1
--- /dev/null
+++ b/arch/powerpc/platforms/powermac/cpufreq_64.c
@@ -0,0 +1,323 @@
1/*
2 * Copyright (C) 2002 - 2005 Benjamin Herrenschmidt <benh@kernel.crashing.org>
3 * and Markus Demleitner <msdemlei@cl.uni-heidelberg.de>
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 version 2 as
7 * published by the Free Software Foundation.
8 *
9 * This driver adds basic cpufreq support for SMU & 970FX based G5 Macs,
10 * that is iMac G5 and latest single CPU desktop.
11 */
12
13#include <linux/config.h>
14#include <linux/module.h>
15#include <linux/types.h>
16#include <linux/errno.h>
17#include <linux/kernel.h>
18#include <linux/delay.h>
19#include <linux/sched.h>
20#include <linux/slab.h>
21#include <linux/cpufreq.h>
22#include <linux/init.h>
23#include <linux/completion.h>
24#include <asm/prom.h>
25#include <asm/machdep.h>
26#include <asm/irq.h>
27#include <asm/sections.h>
28#include <asm/cputable.h>
29#include <asm/time.h>
30#include <asm/smu.h>
31
32#undef DEBUG
33
34#ifdef DEBUG
35#define DBG(fmt...) printk(fmt)
36#else
37#define DBG(fmt...)
38#endif
39
40/* see 970FX user manual */
41
42#define SCOM_PCR 0x0aa001 /* PCR scom addr */
43
44#define PCR_HILO_SELECT 0x80000000U /* 1 = PCR, 0 = PCRH */
45#define PCR_SPEED_FULL 0x00000000U /* 1:1 speed value */
46#define PCR_SPEED_HALF 0x00020000U /* 1:2 speed value */
47#define PCR_SPEED_QUARTER 0x00040000U /* 1:4 speed value */
48#define PCR_SPEED_MASK 0x000e0000U /* speed mask */
49#define PCR_SPEED_SHIFT 17
50#define PCR_FREQ_REQ_VALID 0x00010000U /* freq request valid */
51#define PCR_VOLT_REQ_VALID 0x00008000U /* volt request valid */
52#define PCR_TARGET_TIME_MASK 0x00006000U /* target time */
53#define PCR_STATLAT_MASK 0x00001f00U /* STATLAT value */
54#define PCR_SNOOPLAT_MASK 0x000000f0U /* SNOOPLAT value */
55#define PCR_SNOOPACC_MASK 0x0000000fU /* SNOOPACC value */
56
57#define SCOM_PSR 0x408001 /* PSR scom addr */
58/* warning: PSR is a 64 bits register */
59#define PSR_CMD_RECEIVED 0x2000000000000000U /* command received */
60#define PSR_CMD_COMPLETED 0x1000000000000000U /* command completed */
61#define PSR_CUR_SPEED_MASK 0x0300000000000000U /* current speed */
62#define PSR_CUR_SPEED_SHIFT (56)
63
64/*
65 * The G5 only supports two frequencies (Quarter speed is not supported)
66 */
67#define CPUFREQ_HIGH 0
68#define CPUFREQ_LOW 1
69
70static struct cpufreq_frequency_table g5_cpu_freqs[] = {
71 {CPUFREQ_HIGH, 0},
72 {CPUFREQ_LOW, 0},
73 {0, CPUFREQ_TABLE_END},
74};
75
76static struct freq_attr* g5_cpu_freqs_attr[] = {
77 &cpufreq_freq_attr_scaling_available_freqs,
78 NULL,
79};
80
81/* Power mode data is an array of the 32 bits PCR values to use for
82 * the various frequencies, retreived from the device-tree
83 */
84static u32 *g5_pmode_data;
85static int g5_pmode_max;
86static int g5_pmode_cur;
87
88static DECLARE_MUTEX(g5_switch_mutex);
89
90
91static struct smu_sdbp_fvt *g5_fvt_table; /* table of op. points */
92static int g5_fvt_count; /* number of op. points */
93static int g5_fvt_cur; /* current op. point */
94
95/* ----------------- real hardware interface */
96
97static void g5_switch_volt(int speed_mode)
98{
99 struct smu_simple_cmd cmd;
100
101 DECLARE_COMPLETION(comp);
102 smu_queue_simple(&cmd, SMU_CMD_POWER_COMMAND, 8, smu_done_complete,
103 &comp, 'V', 'S', 'L', 'E', 'W',
104 0xff, g5_fvt_cur+1, speed_mode);
105 wait_for_completion(&comp);
106}
107
108static int g5_switch_freq(int speed_mode)
109{
110 struct cpufreq_freqs freqs;
111 int to;
112
113 if (g5_pmode_cur == speed_mode)
114 return 0;
115
116 down(&g5_switch_mutex);
117
118 freqs.old = g5_cpu_freqs[g5_pmode_cur].frequency;
119 freqs.new = g5_cpu_freqs[speed_mode].frequency;
120 freqs.cpu = 0;
121
122 cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
123
124 /* If frequency is going up, first ramp up the voltage */
125 if (speed_mode < g5_pmode_cur)
126 g5_switch_volt(speed_mode);
127
128 /* Clear PCR high */
129 scom970_write(SCOM_PCR, 0);
130 /* Clear PCR low */
131 scom970_write(SCOM_PCR, PCR_HILO_SELECT | 0);
132 /* Set PCR low */
133 scom970_write(SCOM_PCR, PCR_HILO_SELECT |
134 g5_pmode_data[speed_mode]);
135
136 /* Wait for completion */
137 for (to = 0; to < 10; to++) {
138 unsigned long psr = scom970_read(SCOM_PSR);
139
140 if ((psr & PSR_CMD_RECEIVED) == 0 &&
141 (((psr >> PSR_CUR_SPEED_SHIFT) ^
142 (g5_pmode_data[speed_mode] >> PCR_SPEED_SHIFT)) & 0x3)
143 == 0)
144 break;
145 if (psr & PSR_CMD_COMPLETED)
146 break;
147 udelay(100);
148 }
149
150 /* If frequency is going down, last ramp the voltage */
151 if (speed_mode > g5_pmode_cur)
152 g5_switch_volt(speed_mode);
153
154 g5_pmode_cur = speed_mode;
155 ppc_proc_freq = g5_cpu_freqs[speed_mode].frequency * 1000ul;
156
157 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
158
159 up(&g5_switch_mutex);
160
161 return 0;
162}
163
164static int g5_query_freq(void)
165{
166 unsigned long psr = scom970_read(SCOM_PSR);
167 int i;
168
169 for (i = 0; i <= g5_pmode_max; i++)
170 if ((((psr >> PSR_CUR_SPEED_SHIFT) ^
171 (g5_pmode_data[i] >> PCR_SPEED_SHIFT)) & 0x3) == 0)
172 break;
173 return i;
174}
175
176/* ----------------- cpufreq bookkeeping */
177
178static int g5_cpufreq_verify(struct cpufreq_policy *policy)
179{
180 return cpufreq_frequency_table_verify(policy, g5_cpu_freqs);
181}
182
183static int g5_cpufreq_target(struct cpufreq_policy *policy,
184 unsigned int target_freq, unsigned int relation)
185{
186 unsigned int newstate = 0;
187
188 if (cpufreq_frequency_table_target(policy, g5_cpu_freqs,
189 target_freq, relation, &newstate))
190 return -EINVAL;
191
192 return g5_switch_freq(newstate);
193}
194
195static unsigned int g5_cpufreq_get_speed(unsigned int cpu)
196{
197 return g5_cpu_freqs[g5_pmode_cur].frequency;
198}
199
200static int g5_cpufreq_cpu_init(struct cpufreq_policy *policy)
201{
202 if (policy->cpu != 0)
203 return -ENODEV;
204
205 policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
206 policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
207 policy->cur = g5_cpu_freqs[g5_query_freq()].frequency;
208 cpufreq_frequency_table_get_attr(g5_cpu_freqs, policy->cpu);
209
210 return cpufreq_frequency_table_cpuinfo(policy,
211 g5_cpu_freqs);
212}
213
214
215static struct cpufreq_driver g5_cpufreq_driver = {
216 .name = "powermac",
217 .owner = THIS_MODULE,
218 .flags = CPUFREQ_CONST_LOOPS,
219 .init = g5_cpufreq_cpu_init,
220 .verify = g5_cpufreq_verify,
221 .target = g5_cpufreq_target,
222 .get = g5_cpufreq_get_speed,
223 .attr = g5_cpu_freqs_attr,
224};
225
226
227static int __init g5_cpufreq_init(void)
228{
229 struct device_node *cpunode;
230 unsigned int psize, ssize;
231 struct smu_sdbp_header *shdr;
232 unsigned long max_freq;
233 u32 *valp;
234 int rc = -ENODEV;
235
236 /* Look for CPU and SMU nodes */
237 cpunode = of_find_node_by_type(NULL, "cpu");
238 if (!cpunode) {
239 DBG("No CPU node !\n");
240 return -ENODEV;
241 }
242
243 /* Check 970FX for now */
244 valp = (u32 *)get_property(cpunode, "cpu-version", NULL);
245 if (!valp) {
246 DBG("No cpu-version property !\n");
247 goto bail_noprops;
248 }
249 if (((*valp) >> 16) != 0x3c) {
250 DBG("Wrong CPU version: %08x\n", *valp);
251 goto bail_noprops;
252 }
253
254 /* Look for the powertune data in the device-tree */
255 g5_pmode_data = (u32 *)get_property(cpunode, "power-mode-data",&psize);
256 if (!g5_pmode_data) {
257 DBG("No power-mode-data !\n");
258 goto bail_noprops;
259 }
260 g5_pmode_max = psize / sizeof(u32) - 1;
261
262 /* Look for the FVT table */
263 shdr = smu_get_sdb_partition(SMU_SDB_FVT_ID, NULL);
264 if (!shdr)
265 goto bail_noprops;
266 g5_fvt_table = (struct smu_sdbp_fvt *)&shdr[1];
267 ssize = (shdr->len * sizeof(u32)) - sizeof(struct smu_sdbp_header);
268 g5_fvt_count = ssize / sizeof(struct smu_sdbp_fvt);
269 g5_fvt_cur = 0;
270
271 /* Sanity checking */
272 if (g5_fvt_count < 1 || g5_pmode_max < 1)
273 goto bail_noprops;
274
275 /*
276 * From what I see, clock-frequency is always the maximal frequency.
277 * The current driver can not slew sysclk yet, so we really only deal
278 * with powertune steps for now. We also only implement full freq and
279 * half freq in this version. So far, I haven't yet seen a machine
280 * supporting anything else.
281 */
282 valp = (u32 *)get_property(cpunode, "clock-frequency", NULL);
283 if (!valp)
284 return -ENODEV;
285 max_freq = (*valp)/1000;
286 g5_cpu_freqs[0].frequency = max_freq;
287 g5_cpu_freqs[1].frequency = max_freq/2;
288
289 /* Check current frequency */
290 g5_pmode_cur = g5_query_freq();
291 if (g5_pmode_cur > 1)
292 /* We don't support anything but 1:1 and 1:2, fixup ... */
293 g5_pmode_cur = 1;
294
295 /* Force apply current frequency to make sure everything is in
296 * sync (voltage is right for example). Firmware may leave us with
297 * a strange setting ...
298 */
299 g5_switch_freq(g5_pmode_cur);
300
301 printk(KERN_INFO "Registering G5 CPU frequency driver\n");
302 printk(KERN_INFO "Low: %d Mhz, High: %d Mhz, Cur: %d MHz\n",
303 g5_cpu_freqs[1].frequency/1000,
304 g5_cpu_freqs[0].frequency/1000,
305 g5_cpu_freqs[g5_pmode_cur].frequency/1000);
306
307 rc = cpufreq_register_driver(&g5_cpufreq_driver);
308
309 /* We keep the CPU node on hold... hopefully, Apple G5 don't have
310 * hotplug CPU with a dynamic device-tree ...
311 */
312 return rc;
313
314 bail_noprops:
315 of_node_put(cpunode);
316
317 return rc;
318}
319
320module_init(g5_cpufreq_init);
321
322
323MODULE_LICENSE("GPL");
diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c
index 80b58c1ec412..7acb0546671f 100644
--- a/arch/powerpc/platforms/powermac/setup.c
+++ b/arch/powerpc/platforms/powermac/setup.c
@@ -193,18 +193,6 @@ static void pmac_show_cpuinfo(struct seq_file *m)
193 pmac_newworld ? "NewWorld" : "OldWorld"); 193 pmac_newworld ? "NewWorld" : "OldWorld");
194} 194}
195 195
196static void pmac_show_percpuinfo(struct seq_file *m, int i)
197{
198#ifdef CONFIG_CPU_FREQ_PMAC
199 extern unsigned int pmac_get_one_cpufreq(int i);
200 unsigned int freq = pmac_get_one_cpufreq(i);
201 if (freq != 0) {
202 seq_printf(m, "clock\t\t: %dMHz\n", freq/1000);
203 return;
204 }
205#endif /* CONFIG_CPU_FREQ_PMAC */
206}
207
208#ifndef CONFIG_ADB_CUDA 196#ifndef CONFIG_ADB_CUDA
209int find_via_cuda(void) 197int find_via_cuda(void)
210{ 198{
@@ -767,7 +755,6 @@ struct machdep_calls __initdata pmac_md = {
767 .setup_arch = pmac_setup_arch, 755 .setup_arch = pmac_setup_arch,
768 .init_early = pmac_init_early, 756 .init_early = pmac_init_early,
769 .show_cpuinfo = pmac_show_cpuinfo, 757 .show_cpuinfo = pmac_show_cpuinfo,
770 .show_percpuinfo = pmac_show_percpuinfo,
771 .init_IRQ = pmac_pic_init, 758 .init_IRQ = pmac_pic_init,
772 .get_irq = mpic_get_irq, /* changed later */ 759 .get_irq = mpic_get_irq, /* changed later */
773 .pcibios_fixup = pmac_pcibios_fixup, 760 .pcibios_fixup = pmac_pcibios_fixup,
diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c
index 513e27231493..fcc50bfd43fd 100644
--- a/arch/powerpc/platforms/pseries/iommu.c
+++ b/arch/powerpc/platforms/pseries/iommu.c
@@ -37,7 +37,6 @@
37#include <asm/io.h> 37#include <asm/io.h>
38#include <asm/prom.h> 38#include <asm/prom.h>
39#include <asm/rtas.h> 39#include <asm/rtas.h>
40#include <asm/ppcdebug.h>
41#include <asm/iommu.h> 40#include <asm/iommu.h>
42#include <asm/pci-bridge.h> 41#include <asm/pci-bridge.h>
43#include <asm/machdep.h> 42#include <asm/machdep.h>
@@ -47,6 +46,7 @@
47#include <asm/firmware.h> 46#include <asm/firmware.h>
48#include <asm/tce.h> 47#include <asm/tce.h>
49#include <asm/ppc-pci.h> 48#include <asm/ppc-pci.h>
49#include <asm/udbg.h>
50 50
51#include "plpar_wrappers.h" 51#include "plpar_wrappers.h"
52 52
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c
index ab0c6dd6ec94..a50e5f3f396d 100644
--- a/arch/powerpc/platforms/pseries/lpar.c
+++ b/arch/powerpc/platforms/pseries/lpar.c
@@ -31,13 +31,14 @@
31#include <asm/machdep.h> 31#include <asm/machdep.h>
32#include <asm/abs_addr.h> 32#include <asm/abs_addr.h>
33#include <asm/mmu_context.h> 33#include <asm/mmu_context.h>
34#include <asm/ppcdebug.h>
35#include <asm/iommu.h> 34#include <asm/iommu.h>
36#include <asm/tlbflush.h> 35#include <asm/tlbflush.h>
37#include <asm/tlb.h> 36#include <asm/tlb.h>
38#include <asm/prom.h> 37#include <asm/prom.h>
39#include <asm/abs_addr.h> 38#include <asm/abs_addr.h>
40#include <asm/cputable.h> 39#include <asm/cputable.h>
40#include <asm/udbg.h>
41#include <asm/smp.h>
41 42
42#include "plpar_wrappers.h" 43#include "plpar_wrappers.h"
43 44
diff --git a/arch/powerpc/platforms/pseries/plpar_wrappers.h b/arch/powerpc/platforms/pseries/plpar_wrappers.h
index 382f8c5b0e7c..3bd1b3e06003 100644
--- a/arch/powerpc/platforms/pseries/plpar_wrappers.h
+++ b/arch/powerpc/platforms/pseries/plpar_wrappers.h
@@ -107,14 +107,4 @@ static inline long plpar_put_term_char(unsigned long termno, unsigned long len,
107 lbuf[1]); 107 lbuf[1]);
108} 108}
109 109
110static inline long plpar_set_xdabr(unsigned long address, unsigned long flags)
111{
112 return plpar_hcall_norets(H_SET_XDABR, address, flags);
113}
114
115static inline long plpar_set_dabr(unsigned long val)
116{
117 return plpar_hcall_norets(H_SET_DABR, val);
118}
119
120#endif /* _PSERIES_PLPAR_WRAPPERS_H */ 110#endif /* _PSERIES_PLPAR_WRAPPERS_H */
diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c
index 6562ff4b0a82..fbd214d68b07 100644
--- a/arch/powerpc/platforms/pseries/ras.c
+++ b/arch/powerpc/platforms/pseries/ras.c
@@ -48,7 +48,7 @@
48#include <asm/ptrace.h> 48#include <asm/ptrace.h>
49#include <asm/machdep.h> 49#include <asm/machdep.h>
50#include <asm/rtas.h> 50#include <asm/rtas.h>
51#include <asm/ppcdebug.h> 51#include <asm/udbg.h>
52 52
53static unsigned char ras_log_buf[RTAS_ERROR_LOG_MAX]; 53static unsigned char ras_log_buf[RTAS_ERROR_LOG_MAX];
54static DEFINE_SPINLOCK(ras_log_buf_lock); 54static DEFINE_SPINLOCK(ras_log_buf_lock);
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index 65bee939eecc..e78c39368841 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -65,6 +65,7 @@
65#include <asm/ppc-pci.h> 65#include <asm/ppc-pci.h>
66#include <asm/i8259.h> 66#include <asm/i8259.h>
67#include <asm/udbg.h> 67#include <asm/udbg.h>
68#include <asm/smp.h>
68 69
69#include "plpar_wrappers.h" 70#include "plpar_wrappers.h"
70 71
@@ -353,14 +354,15 @@ static void pSeries_mach_cpu_die(void)
353 354
354static int pseries_set_dabr(unsigned long dabr) 355static int pseries_set_dabr(unsigned long dabr)
355{ 356{
356 if (firmware_has_feature(FW_FEATURE_XDABR)) { 357 return plpar_hcall_norets(H_SET_DABR, dabr);
357 /* We want to catch accesses from kernel and userspace */
358 return plpar_set_xdabr(dabr, H_DABRX_KERNEL | H_DABRX_USER);
359 }
360
361 return plpar_set_dabr(dabr);
362} 358}
363 359
360static int pseries_set_xdabr(unsigned long dabr)
361{
362 /* We want to catch accesses from kernel and userspace */
363 return plpar_hcall_norets(H_SET_XDABR, dabr,
364 H_DABRX_KERNEL | H_DABRX_USER);
365}
364 366
365/* 367/*
366 * Early initialization. Relocation is on but do not reference unbolted pages 368 * Early initialization. Relocation is on but do not reference unbolted pages
@@ -396,8 +398,10 @@ static void __init pSeries_init_early(void)
396 DBG("Hello World !\n"); 398 DBG("Hello World !\n");
397 } 399 }
398 400
399 if (firmware_has_feature(FW_FEATURE_XDABR | FW_FEATURE_DABR)) 401 if (firmware_has_feature(FW_FEATURE_DABR))
400 ppc_md.set_dabr = pseries_set_dabr; 402 ppc_md.set_dabr = pseries_set_dabr;
403 else if (firmware_has_feature(FW_FEATURE_XDABR))
404 ppc_md.set_dabr = pseries_set_xdabr;
401 405
402 iommu_init_early_pSeries(); 406 iommu_init_early_pSeries();
403 407
diff --git a/arch/powerpc/sysdev/i8259.c b/arch/powerpc/sysdev/i8259.c
index 90bce6e0c191..b7ac32fdd776 100644
--- a/arch/powerpc/sysdev/i8259.c
+++ b/arch/powerpc/sysdev/i8259.c
@@ -207,6 +207,9 @@ void __init i8259_init(unsigned long intack_addr, int offset)
207 207
208 spin_unlock_irqrestore(&i8259_lock, flags); 208 spin_unlock_irqrestore(&i8259_lock, flags);
209 209
210 for (i = 0; i < NUM_ISA_INTERRUPTS; ++i)
211 irq_desc[offset + i].handler = &i8259_pic;
212
210 /* reserve our resources */ 213 /* reserve our resources */
211 setup_irq(offset + 2, &i8259_irqaction); 214 setup_irq(offset + 2, &i8259_irqaction);
212 request_resource(&ioport_resource, &pic1_iores); 215 request_resource(&ioport_resource, &pic1_iores);
@@ -216,6 +219,4 @@ void __init i8259_init(unsigned long intack_addr, int offset)
216 if (intack_addr != 0) 219 if (intack_addr != 0)
217 pci_intack = ioremap(intack_addr, 1); 220 pci_intack = ioremap(intack_addr, 1);
218 221
219 for (i = 0; i < NUM_ISA_INTERRUPTS; ++i)
220 irq_desc[offset + i].handler = &i8259_pic;
221} 222}
diff --git a/arch/powerpc/sysdev/u3_iommu.c b/arch/powerpc/sysdev/u3_iommu.c
index 607722178c1a..543d65909812 100644
--- a/arch/powerpc/sysdev/u3_iommu.c
+++ b/arch/powerpc/sysdev/u3_iommu.c
@@ -37,7 +37,6 @@
37#include <linux/vmalloc.h> 37#include <linux/vmalloc.h>
38#include <asm/io.h> 38#include <asm/io.h>
39#include <asm/prom.h> 39#include <asm/prom.h>
40#include <asm/ppcdebug.h>
41#include <asm/iommu.h> 40#include <asm/iommu.h>
42#include <asm/pci-bridge.h> 41#include <asm/pci-bridge.h>
43#include <asm/machdep.h> 42#include <asm/machdep.h>
diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
index 3056ede2424d..ae6af29938a1 100644
--- a/arch/ppc/kernel/misc.S
+++ b/arch/ppc/kernel/misc.S
@@ -25,6 +25,11 @@
25#include <asm/thread_info.h> 25#include <asm/thread_info.h>
26#include <asm/asm-offsets.h> 26#include <asm/asm-offsets.h>
27 27
28#ifdef CONFIG_8xx
29#define ISYNC_8xx isync
30#else
31#define ISYNC_8xx
32#endif
28 .text 33 .text
29 34
30 .align 5 35 .align 5
@@ -800,8 +805,18 @@ _GLOBAL(_insb)
800 subi r4,r4,1 805 subi r4,r4,1
801 blelr- 806 blelr-
80200: lbz r5,0(r3) 80700: lbz r5,0(r3)
803 eieio 80801: eieio
804 stbu r5,1(r4) 80902: stbu r5,1(r4)
810 ISYNC_8xx
811 .section .fixup,"ax"
81203: blr
813 .text
814 .section __ex_table, "a"
815 .align 2
816 .long 00b, 03b
817 .long 01b, 03b
818 .long 02b, 03b
819 .text
805 bdnz 00b 820 bdnz 00b
806 blr 821 blr
807 822
@@ -811,8 +826,18 @@ _GLOBAL(_outsb)
811 subi r4,r4,1 826 subi r4,r4,1
812 blelr- 827 blelr-
81300: lbzu r5,1(r4) 82800: lbzu r5,1(r4)
814 stb r5,0(r3) 82901: stb r5,0(r3)
815 eieio 83002: eieio
831 ISYNC_8xx
832 .section .fixup,"ax"
83303: blr
834 .text
835 .section __ex_table, "a"
836 .align 2
837 .long 00b, 03b
838 .long 01b, 03b
839 .long 02b, 03b
840 .text
816 bdnz 00b 841 bdnz 00b
817 blr 842 blr
818 843
@@ -822,8 +847,18 @@ _GLOBAL(_insw)
822 subi r4,r4,2 847 subi r4,r4,2
823 blelr- 848 blelr-
82400: lhbrx r5,0,r3 84900: lhbrx r5,0,r3
825 eieio 85001: eieio
826 sthu r5,2(r4) 85102: sthu r5,2(r4)
852 ISYNC_8xx
853 .section .fixup,"ax"
85403: blr
855 .text
856 .section __ex_table, "a"
857 .align 2
858 .long 00b, 03b
859 .long 01b, 03b
860 .long 02b, 03b
861 .text
827 bdnz 00b 862 bdnz 00b
828 blr 863 blr
829 864
@@ -833,8 +868,18 @@ _GLOBAL(_outsw)
833 subi r4,r4,2 868 subi r4,r4,2
834 blelr- 869 blelr-
83500: lhzu r5,2(r4) 87000: lhzu r5,2(r4)
836 eieio 87101: eieio
837 sthbrx r5,0,r3 87202: sthbrx r5,0,r3
873 ISYNC_8xx
874 .section .fixup,"ax"
87503: blr
876 .text
877 .section __ex_table, "a"
878 .align 2
879 .long 00b, 03b
880 .long 01b, 03b
881 .long 02b, 03b
882 .text
838 bdnz 00b 883 bdnz 00b
839 blr 884 blr
840 885
@@ -844,8 +889,18 @@ _GLOBAL(_insl)
844 subi r4,r4,4 889 subi r4,r4,4
845 blelr- 890 blelr-
84600: lwbrx r5,0,r3 89100: lwbrx r5,0,r3
847 eieio 89201: eieio
848 stwu r5,4(r4) 89302: stwu r5,4(r4)
894 ISYNC_8xx
895 .section .fixup,"ax"
89603: blr
897 .text
898 .section __ex_table, "a"
899 .align 2
900 .long 00b, 03b
901 .long 01b, 03b
902 .long 02b, 03b
903 .text
849 bdnz 00b 904 bdnz 00b
850 blr 905 blr
851 906
@@ -855,8 +910,18 @@ _GLOBAL(_outsl)
855 subi r4,r4,4 910 subi r4,r4,4
856 blelr- 911 blelr-
85700: lwzu r5,4(r4) 91200: lwzu r5,4(r4)
858 stwbrx r5,0,r3 91301: stwbrx r5,0,r3
859 eieio 91402: eieio
915 ISYNC_8xx
916 .section .fixup,"ax"
91703: blr
918 .text
919 .section __ex_table, "a"
920 .align 2
921 .long 00b, 03b
922 .long 01b, 03b
923 .long 02b, 03b
924 .text
860 bdnz 00b 925 bdnz 00b
861 blr 926 blr
862 927
@@ -867,8 +932,18 @@ _GLOBAL(_insw_ns)
867 subi r4,r4,2 932 subi r4,r4,2
868 blelr- 933 blelr-
86900: lhz r5,0(r3) 93400: lhz r5,0(r3)
870 eieio 93501: eieio
871 sthu r5,2(r4) 93602: sthu r5,2(r4)
937 ISYNC_8xx
938 .section .fixup,"ax"
93903: blr
940 .text
941 .section __ex_table, "a"
942 .align 2
943 .long 00b, 03b
944 .long 01b, 03b
945 .long 02b, 03b
946 .text
872 bdnz 00b 947 bdnz 00b
873 blr 948 blr
874 949
@@ -879,8 +954,18 @@ _GLOBAL(_outsw_ns)
879 subi r4,r4,2 954 subi r4,r4,2
880 blelr- 955 blelr-
88100: lhzu r5,2(r4) 95600: lhzu r5,2(r4)
882 sth r5,0(r3) 95701: sth r5,0(r3)
883 eieio 95802: eieio
959 ISYNC_8xx
960 .section .fixup,"ax"
96103: blr
962 .text
963 .section __ex_table, "a"
964 .align 2
965 .long 00b, 03b
966 .long 01b, 03b
967 .long 02b, 03b
968 .text
884 bdnz 00b 969 bdnz 00b
885 blr 970 blr
886 971
@@ -891,8 +976,18 @@ _GLOBAL(_insl_ns)
891 subi r4,r4,4 976 subi r4,r4,4
892 blelr- 977 blelr-
89300: lwz r5,0(r3) 97800: lwz r5,0(r3)
894 eieio 97901: eieio
895 stwu r5,4(r4) 98002: stwu r5,4(r4)
981 ISYNC_8xx
982 .section .fixup,"ax"
98303: blr
984 .text
985 .section __ex_table, "a"
986 .align 2
987 .long 00b, 03b
988 .long 01b, 03b
989 .long 02b, 03b
990 .text
896 bdnz 00b 991 bdnz 00b
897 blr 992 blr
898 993
@@ -903,8 +998,18 @@ _GLOBAL(_outsl_ns)
903 subi r4,r4,4 998 subi r4,r4,4
904 blelr- 999 blelr-
90500: lwzu r5,4(r4) 100000: lwzu r5,4(r4)
906 stw r5,0(r3) 100101: stw r5,0(r3)
907 eieio 100202: eieio
1003 ISYNC_8xx
1004 .section .fixup,"ax"
100503: blr
1006 .text
1007 .section __ex_table, "a"
1008 .align 2
1009 .long 00b, 03b
1010 .long 01b, 03b
1011 .long 02b, 03b
1012 .text
908 bdnz 00b 1013 bdnz 00b
909 blr 1014 blr
910 1015
diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c
index 16adde6b429d..9dbc4d28fa28 100644
--- a/arch/ppc/kernel/traps.c
+++ b/arch/ppc/kernel/traps.c
@@ -49,7 +49,7 @@ extern int xmon_sstep(struct pt_regs *regs);
49extern int xmon_iabr_match(struct pt_regs *regs); 49extern int xmon_iabr_match(struct pt_regs *regs);
50extern int xmon_dabr_match(struct pt_regs *regs); 50extern int xmon_dabr_match(struct pt_regs *regs);
51 51
52void (*debugger)(struct pt_regs *regs) = xmon; 52int (*debugger)(struct pt_regs *regs) = xmon;
53int (*debugger_bpt)(struct pt_regs *regs) = xmon_bpt; 53int (*debugger_bpt)(struct pt_regs *regs) = xmon_bpt;
54int (*debugger_sstep)(struct pt_regs *regs) = xmon_sstep; 54int (*debugger_sstep)(struct pt_regs *regs) = xmon_sstep;
55int (*debugger_iabr_match)(struct pt_regs *regs) = xmon_iabr_match; 55int (*debugger_iabr_match)(struct pt_regs *regs) = xmon_iabr_match;
@@ -57,7 +57,7 @@ int (*debugger_dabr_match)(struct pt_regs *regs) = xmon_dabr_match;
57void (*debugger_fault_handler)(struct pt_regs *regs); 57void (*debugger_fault_handler)(struct pt_regs *regs);
58#else 58#else
59#ifdef CONFIG_KGDB 59#ifdef CONFIG_KGDB
60void (*debugger)(struct pt_regs *regs); 60int (*debugger)(struct pt_regs *regs);
61int (*debugger_bpt)(struct pt_regs *regs); 61int (*debugger_bpt)(struct pt_regs *regs);
62int (*debugger_sstep)(struct pt_regs *regs); 62int (*debugger_sstep)(struct pt_regs *regs);
63int (*debugger_iabr_match)(struct pt_regs *regs); 63int (*debugger_iabr_match)(struct pt_regs *regs);
@@ -159,7 +159,7 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
159 */ 159 */
160static inline int check_io_access(struct pt_regs *regs) 160static inline int check_io_access(struct pt_regs *regs)
161{ 161{
162#ifdef CONFIG_PPC_PMAC 162#if defined CONFIG_PPC_PMAC || defined CONFIG_8xx
163 unsigned long msr = regs->msr; 163 unsigned long msr = regs->msr;
164 const struct exception_table_entry *entry; 164 const struct exception_table_entry *entry;
165 unsigned int *nip = (unsigned int *)regs->nip; 165 unsigned int *nip = (unsigned int *)regs->nip;
@@ -178,7 +178,11 @@ static inline int check_io_access(struct pt_regs *regs)
178 nip -= 2; 178 nip -= 2;
179 else if (*nip == 0x4c00012c) /* isync */ 179 else if (*nip == 0x4c00012c) /* isync */
180 --nip; 180 --nip;
181 if (*nip == 0x7c0004ac || (*nip >> 26) == 3) { 181 /* eieio from I/O string functions */
182 else if ((*nip) == 0x7c0006ac || *(nip+1) == 0x7c0006ac)
183 nip += 2;
184 if (*nip == 0x7c0004ac || (*nip >> 26) == 3 ||
185 (*(nip+1) >> 26) == 3) {
182 /* sync or twi */ 186 /* sync or twi */
183 unsigned int rb; 187 unsigned int rb;
184 188
diff --git a/arch/ppc/syslib/m8xx_wdt.c b/arch/ppc/syslib/m8xx_wdt.c
index c5ac5ce5d7d2..a21632d37e5a 100644
--- a/arch/ppc/syslib/m8xx_wdt.c
+++ b/arch/ppc/syslib/m8xx_wdt.c
@@ -14,6 +14,7 @@
14#include <linux/irq.h> 14#include <linux/irq.h>
15#include <linux/kernel.h> 15#include <linux/kernel.h>
16#include <linux/sched.h> 16#include <linux/sched.h>
17#include <asm/io.h>
17#include <asm/8xx_immap.h> 18#include <asm/8xx_immap.h>
18#include <syslib/m8xx_wdt.h> 19#include <syslib/m8xx_wdt.h>
19 20
@@ -29,8 +30,8 @@ void m8xx_wdt_reset(void)
29{ 30{
30 volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR; 31 volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR;
31 32
32 out_be16(imap->im_siu_conf.sc_swsr, 0x556c); /* write magic1 */ 33 out_be16(&imap->im_siu_conf.sc_swsr, 0x556c); /* write magic1 */
33 out_be16(imap->im_siu_conf.sc_swsr, 0xaa39); /* write magic2 */ 34 out_be16(&imap->im_siu_conf.sc_swsr, 0xaa39); /* write magic2 */
34} 35}
35 36
36static irqreturn_t m8xx_wdt_interrupt(int irq, void *dev, struct pt_regs *regs) 37static irqreturn_t m8xx_wdt_interrupt(int irq, void *dev, struct pt_regs *regs)
@@ -39,7 +40,7 @@ static irqreturn_t m8xx_wdt_interrupt(int irq, void *dev, struct pt_regs *regs)
39 40
40 m8xx_wdt_reset(); 41 m8xx_wdt_reset();
41 42
42 out_be16(imap->im_sit.sit_piscr, in_be16(imap->im_sit.sit_piscr | PISCR_PS)); /* clear irq */ 43 out_be16(&imap->im_sit.sit_piscr, in_be16(&imap->im_sit.sit_piscr) | PISCR_PS); /* clear irq */
43 44
44 return IRQ_HANDLED; 45 return IRQ_HANDLED;
45} 46}
@@ -51,7 +52,7 @@ void __init m8xx_wdt_handler_install(bd_t * binfo)
51 u32 sypcr; 52 u32 sypcr;
52 u32 pitrtclk; 53 u32 pitrtclk;
53 54
54 sypcr = in_be32(imap->im_siu_conf.sc_sypcr); 55 sypcr = in_be32(&imap->im_siu_conf.sc_sypcr);
55 56
56 if (!(sypcr & 0x04)) { 57 if (!(sypcr & 0x04)) {
57 printk(KERN_NOTICE "m8xx_wdt: wdt disabled (SYPCR: 0x%08X)\n", 58 printk(KERN_NOTICE "m8xx_wdt: wdt disabled (SYPCR: 0x%08X)\n",
@@ -87,9 +88,9 @@ void __init m8xx_wdt_handler_install(bd_t * binfo)
87 else 88 else
88 pitc = pitrtclk * wdt_timeout / binfo->bi_intfreq / 2; 89 pitc = pitrtclk * wdt_timeout / binfo->bi_intfreq / 2;
89 90
90 out_be32(imap->im_sit.sit_pitc, pitc << 16); 91 out_be32(&imap->im_sit.sit_pitc, pitc << 16);
91 92
92 out_be16(imap->im_sit.sit_piscr, (mk_int_int_mask(PIT_INTERRUPT) << 8) | PISCR_PIE | PISCR_PTE); 93 out_be16(&imap->im_sit.sit_piscr, (mk_int_int_mask(PIT_INTERRUPT) << 8) | PISCR_PIE | PISCR_PTE);
93 94
94 if (setup_irq(PIT_INTERRUPT, &m8xx_wdt_irqaction)) 95 if (setup_irq(PIT_INTERRUPT, &m8xx_wdt_irqaction))
95 panic("m8xx_wdt: error setting up the watchdog irq!"); 96 panic("m8xx_wdt: error setting up the watchdog irq!");
diff --git a/arch/ppc/syslib/prom.c b/arch/ppc/syslib/prom.c
index 1b9aa0d6a924..03b1fc9b9501 100644
--- a/arch/ppc/syslib/prom.c
+++ b/arch/ppc/syslib/prom.c
@@ -1165,7 +1165,7 @@ get_property(struct device_node *np, const char *name, int *lenp)
1165/* 1165/*
1166 * Add a property to a node 1166 * Add a property to a node
1167 */ 1167 */
1168void 1168int
1169prom_add_property(struct device_node* np, struct property* prop) 1169prom_add_property(struct device_node* np, struct property* prop)
1170{ 1170{
1171 struct property **next = &np->properties; 1171 struct property **next = &np->properties;
@@ -1174,6 +1174,8 @@ prom_add_property(struct device_node* np, struct property* prop)
1174 while (*next) 1174 while (*next)
1175 next = &(*next)->next; 1175 next = &(*next)->next;
1176 *next = prop; 1176 *next = prop;
1177
1178 return 0;
1177} 1179}
1178 1180
1179/* I quickly hacked that one, check against spec ! */ 1181/* I quickly hacked that one, check against spec ! */
diff --git a/arch/ppc/xmon/xmon.c b/arch/ppc/xmon/xmon.c
index 66bfaa3211a2..2b483b4f1602 100644
--- a/arch/ppc/xmon/xmon.c
+++ b/arch/ppc/xmon/xmon.c
@@ -220,8 +220,7 @@ static void get_tb(unsigned *p)
220 p[1] = lo; 220 p[1] = lo;
221} 221}
222 222
223void 223int xmon(struct pt_regs *excp)
224xmon(struct pt_regs *excp)
225{ 224{
226 struct pt_regs regs; 225 struct pt_regs regs;
227 int msr, cmd; 226 int msr, cmd;
@@ -290,6 +289,8 @@ xmon(struct pt_regs *excp)
290#endif /* CONFIG_SMP */ 289#endif /* CONFIG_SMP */
291 set_msr(msr); /* restore interrupt enable */ 290 set_msr(msr); /* restore interrupt enable */
292 get_tb(start_tb[smp_processor_id()]); 291 get_tb(start_tb[smp_processor_id()]);
292
293 return cmd != 'X';
293} 294}
294 295
295irqreturn_t 296irqreturn_t
diff --git a/arch/ppc64/Kconfig b/arch/ppc64/Kconfig
index 2130cc315957..29552348e581 100644
--- a/arch/ppc64/Kconfig
+++ b/arch/ppc64/Kconfig
@@ -56,6 +56,7 @@ config PPC_STD_MMU
56# max order + 1 56# max order + 1
57config FORCE_MAX_ZONEORDER 57config FORCE_MAX_ZONEORDER
58 int 58 int
59 default "9" if PPC_64K_PAGES
59 default "13" 60 default "13"
60 61
61source "init/Kconfig" 62source "init/Kconfig"
@@ -173,6 +174,16 @@ config KEXEC
173 support. As of this writing the exact hardware interface is 174 support. As of this writing the exact hardware interface is
174 strongly in flux, so no good recommendation can be made. 175 strongly in flux, so no good recommendation can be made.
175 176
177source "drivers/cpufreq/Kconfig"
178
179config CPU_FREQ_PMAC64
180 bool "Support for some Apple G5s"
181 depends on CPU_FREQ && PMAC_SMU && PPC64
182 select CPU_FREQ_TABLE
183 help
184 This adds support for frequency switching on Apple iMac G5,
185 and some of the more recent desktop G5 machines as well.
186
176config IBMVIO 187config IBMVIO
177 depends on PPC_PSERIES || PPC_ISERIES 188 depends on PPC_PSERIES || PPC_ISERIES
178 bool 189 bool
diff --git a/arch/ppc64/Kconfig.debug b/arch/ppc64/Kconfig.debug
index f16a5030527b..b258c9314a1b 100644
--- a/arch/ppc64/Kconfig.debug
+++ b/arch/ppc64/Kconfig.debug
@@ -55,10 +55,6 @@ config XMON_DEFAULT
55 xmon is normally disabled unless booted with 'xmon=on'. 55 xmon is normally disabled unless booted with 'xmon=on'.
56 Use 'xmon=off' to disable xmon init during runtime. 56 Use 'xmon=off' to disable xmon init during runtime.
57 57
58config PPCDBG
59 bool "Include PPCDBG realtime debugging"
60 depends on DEBUG_KERNEL
61
62config IRQSTACKS 58config IRQSTACKS
63 bool "Use separate kernel stacks when processing interrupts" 59 bool "Use separate kernel stacks when processing interrupts"
64 help 60 help
diff --git a/arch/ppc64/kernel/idle.c b/arch/ppc64/kernel/idle.c
index 8abd2ad92832..8fec27469802 100644
--- a/arch/ppc64/kernel/idle.c
+++ b/arch/ppc64/kernel/idle.c
@@ -28,6 +28,7 @@
28#include <asm/time.h> 28#include <asm/time.h>
29#include <asm/systemcfg.h> 29#include <asm/systemcfg.h>
30#include <asm/machdep.h> 30#include <asm/machdep.h>
31#include <asm/smp.h>
31 32
32extern void power4_idle(void); 33extern void power4_idle(void);
33 34
diff --git a/arch/ppc64/kernel/machine_kexec.c b/arch/ppc64/kernel/machine_kexec.c
index ff8679f260f3..07ea03598c00 100644
--- a/arch/ppc64/kernel/machine_kexec.c
+++ b/arch/ppc64/kernel/machine_kexec.c
@@ -24,6 +24,7 @@
24#include <asm/mmu.h> 24#include <asm/mmu.h>
25#include <asm/sections.h> /* _end */ 25#include <asm/sections.h> /* _end */
26#include <asm/prom.h> 26#include <asm/prom.h>
27#include <asm/smp.h>
27 28
28#define HASH_GROUP_SIZE 0x80 /* size of each hash group, asm/mmu.h */ 29#define HASH_GROUP_SIZE 0x80 /* size of each hash group, asm/mmu.h */
29 30
diff --git a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S
index 077507ffbab8..914632ec587d 100644
--- a/arch/ppc64/kernel/misc.S
+++ b/arch/ppc64/kernel/misc.S
@@ -560,7 +560,7 @@ _GLOBAL(real_readb)
560 isync 560 isync
561 blr 561 blr
562 562
563 /* 563/*
564 * Do an IO access in real mode 564 * Do an IO access in real mode
565 */ 565 */
566_GLOBAL(real_writeb) 566_GLOBAL(real_writeb)
@@ -593,6 +593,76 @@ _GLOBAL(real_writeb)
593#endif /* defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE) */ 593#endif /* defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE) */
594 594
595/* 595/*
596 * SCOM access functions for 970 (FX only for now)
597 *
598 * unsigned long scom970_read(unsigned int address);
599 * void scom970_write(unsigned int address, unsigned long value);
600 *
601 * The address passed in is the 24 bits register address. This code
602 * is 970 specific and will not check the status bits, so you should
603 * know what you are doing.
604 */
605_GLOBAL(scom970_read)
606 /* interrupts off */
607 mfmsr r4
608 ori r0,r4,MSR_EE
609 xori r0,r0,MSR_EE
610 mtmsrd r0,1
611
612 /* rotate 24 bits SCOM address 8 bits left and mask out it's low 8 bits
613 * (including parity). On current CPUs they must be 0'd,
614 * and finally or in RW bit
615 */
616 rlwinm r3,r3,8,0,15
617 ori r3,r3,0x8000
618
619 /* do the actual scom read */
620 sync
621 mtspr SPRN_SCOMC,r3
622 isync
623 mfspr r3,SPRN_SCOMD
624 isync
625 mfspr r0,SPRN_SCOMC
626 isync
627
628 /* XXX: fixup result on some buggy 970's (ouch ! we lost a bit, bah
629 * that's the best we can do). Not implemented yet as we don't use
630 * the scom on any of the bogus CPUs yet, but may have to be done
631 * ultimately
632 */
633
634 /* restore interrupts */
635 mtmsrd r4,1
636 blr
637
638
639_GLOBAL(scom970_write)
640 /* interrupts off */
641 mfmsr r5
642 ori r0,r5,MSR_EE
643 xori r0,r0,MSR_EE
644 mtmsrd r0,1
645
646 /* rotate 24 bits SCOM address 8 bits left and mask out it's low 8 bits
647 * (including parity). On current CPUs they must be 0'd.
648 */
649
650 rlwinm r3,r3,8,0,15
651
652 sync
653 mtspr SPRN_SCOMD,r4 /* write data */
654 isync
655 mtspr SPRN_SCOMC,r3 /* write command */
656 isync
657 mfspr 3,SPRN_SCOMC
658 isync
659
660 /* restore interrupts */
661 mtmsrd r5,1
662 blr
663
664
665/*
596 * Create a kernel thread 666 * Create a kernel thread
597 * kernel_thread(fn, arg, flags) 667 * kernel_thread(fn, arg, flags)
598 */ 668 */
diff --git a/arch/ppc64/kernel/pci.c b/arch/ppc64/kernel/pci.c
index 3d2106b022a1..30247ff74972 100644
--- a/arch/ppc64/kernel/pci.c
+++ b/arch/ppc64/kernel/pci.c
@@ -295,8 +295,8 @@ static void pci_parse_of_addrs(struct device_node *node, struct pci_dev *dev)
295 } 295 }
296} 296}
297 297
298static struct pci_dev *of_create_pci_dev(struct device_node *node, 298struct pci_dev *of_create_pci_dev(struct device_node *node,
299 struct pci_bus *bus, int devfn) 299 struct pci_bus *bus, int devfn)
300{ 300{
301 struct pci_dev *dev; 301 struct pci_dev *dev;
302 const char *type; 302 const char *type;
@@ -354,10 +354,9 @@ static struct pci_dev *of_create_pci_dev(struct device_node *node,
354 354
355 return dev; 355 return dev;
356} 356}
357EXPORT_SYMBOL(of_create_pci_dev);
357 358
358static void of_scan_pci_bridge(struct device_node *node, struct pci_dev *dev); 359void __devinit of_scan_bus(struct device_node *node,
359
360static void __devinit of_scan_bus(struct device_node *node,
361 struct pci_bus *bus) 360 struct pci_bus *bus)
362{ 361{
363 struct device_node *child = NULL; 362 struct device_node *child = NULL;
@@ -381,9 +380,10 @@ static void __devinit of_scan_bus(struct device_node *node,
381 380
382 do_bus_setup(bus); 381 do_bus_setup(bus);
383} 382}
383EXPORT_SYMBOL(of_scan_bus);
384 384
385static void __devinit of_scan_pci_bridge(struct device_node *node, 385void __devinit of_scan_pci_bridge(struct device_node *node,
386 struct pci_dev *dev) 386 struct pci_dev *dev)
387{ 387{
388 struct pci_bus *bus; 388 struct pci_bus *bus;
389 u32 *busrange, *ranges; 389 u32 *busrange, *ranges;
@@ -464,9 +464,10 @@ static void __devinit of_scan_pci_bridge(struct device_node *node,
464 else if (mode == PCI_PROBE_NORMAL) 464 else if (mode == PCI_PROBE_NORMAL)
465 pci_scan_child_bus(bus); 465 pci_scan_child_bus(bus);
466} 466}
467EXPORT_SYMBOL(of_scan_pci_bridge);
467#endif /* CONFIG_PPC_MULTIPLATFORM */ 468#endif /* CONFIG_PPC_MULTIPLATFORM */
468 469
469static void __devinit scan_phb(struct pci_controller *hose) 470void __devinit scan_phb(struct pci_controller *hose)
470{ 471{
471 struct pci_bus *bus; 472 struct pci_bus *bus;
472 struct device_node *node = hose->arch_data; 473 struct device_node *node = hose->arch_data;
diff --git a/arch/ppc64/kernel/prom.c b/arch/ppc64/kernel/prom.c
index dece31e58bc4..3402fbee62c7 100644
--- a/arch/ppc64/kernel/prom.c
+++ b/arch/ppc64/kernel/prom.c
@@ -31,6 +31,7 @@
31#include <linux/initrd.h> 31#include <linux/initrd.h>
32#include <linux/bitops.h> 32#include <linux/bitops.h>
33#include <linux/module.h> 33#include <linux/module.h>
34#include <linux/module.h>
34 35
35#include <asm/prom.h> 36#include <asm/prom.h>
36#include <asm/rtas.h> 37#include <asm/rtas.h>
@@ -46,7 +47,6 @@
46#include <asm/pgtable.h> 47#include <asm/pgtable.h>
47#include <asm/pci.h> 48#include <asm/pci.h>
48#include <asm/iommu.h> 49#include <asm/iommu.h>
49#include <asm/ppcdebug.h>
50#include <asm/btext.h> 50#include <asm/btext.h>
51#include <asm/sections.h> 51#include <asm/sections.h>
52#include <asm/machdep.h> 52#include <asm/machdep.h>
@@ -1866,17 +1866,32 @@ get_property(struct device_node *np, const char *name, int *lenp)
1866EXPORT_SYMBOL(get_property); 1866EXPORT_SYMBOL(get_property);
1867 1867
1868/* 1868/*
1869 * Add a property to a node 1869 * Add a property to a node.
1870 */ 1870 */
1871void 1871int
1872prom_add_property(struct device_node* np, struct property* prop) 1872prom_add_property(struct device_node* np, struct property* prop)
1873{ 1873{
1874 struct property **next = &np->properties; 1874 struct property **next;
1875 1875
1876 prop->next = NULL; 1876 prop->next = NULL;
1877 while (*next) 1877 write_lock(&devtree_lock);
1878 next = &np->properties;
1879 while (*next) {
1880 if (strcmp(prop->name, (*next)->name) == 0) {
1881 /* duplicate ! don't insert it */
1882 write_unlock(&devtree_lock);
1883 return -1;
1884 }
1878 next = &(*next)->next; 1885 next = &(*next)->next;
1886 }
1879 *next = prop; 1887 *next = prop;
1888 write_unlock(&devtree_lock);
1889
1890 /* try to add to proc as well if it was initialized */
1891 if (np->pde)
1892 proc_device_tree_add_prop(np->pde, prop);
1893
1894 return 0;
1880} 1895}
1881 1896
1882#if 0 1897#if 0
diff --git a/arch/ppc64/kernel/prom_init.c b/arch/ppc64/kernel/prom_init.c
index a4bbca6dbb8b..e4c880dab997 100644
--- a/arch/ppc64/kernel/prom_init.c
+++ b/arch/ppc64/kernel/prom_init.c
@@ -44,7 +44,6 @@
44#include <asm/pgtable.h> 44#include <asm/pgtable.h>
45#include <asm/pci.h> 45#include <asm/pci.h>
46#include <asm/iommu.h> 46#include <asm/iommu.h>
47#include <asm/ppcdebug.h>
48#include <asm/btext.h> 47#include <asm/btext.h>
49#include <asm/sections.h> 48#include <asm/sections.h>
50#include <asm/machdep.h> 49#include <asm/machdep.h>
@@ -1825,7 +1824,7 @@ static void __init fixup_device_tree(void)
1825 if (prom_getprop(u3, "device-rev", &u3_rev, sizeof(u3_rev)) 1824 if (prom_getprop(u3, "device-rev", &u3_rev, sizeof(u3_rev))
1826 == PROM_ERROR) 1825 == PROM_ERROR)
1827 return; 1826 return;
1828 if (u3_rev != 0x35 && u3_rev != 0x37) 1827 if (u3_rev < 0x35 || u3_rev > 0x39)
1829 return; 1828 return;
1830 /* does it need fixup ? */ 1829 /* does it need fixup ? */
1831 if (prom_getproplen(i2c, "interrupts") > 0) 1830 if (prom_getproplen(i2c, "interrupts") > 0)
diff --git a/arch/ppc64/kernel/rtas_pci.c b/arch/ppc64/kernel/rtas_pci.c
index 3ad15c90fbbd..3c3f19192fcc 100644
--- a/arch/ppc64/kernel/rtas_pci.c
+++ b/arch/ppc64/kernel/rtas_pci.c
@@ -440,7 +440,6 @@ struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn)
440 struct device_node *root = of_find_node_by_path("/"); 440 struct device_node *root = of_find_node_by_path("/");
441 unsigned int root_size_cells = 0; 441 unsigned int root_size_cells = 0;
442 struct pci_controller *phb; 442 struct pci_controller *phb;
443 struct pci_bus *bus;
444 int primary; 443 int primary;
445 444
446 root_size_cells = prom_n_size_cells(root); 445 root_size_cells = prom_n_size_cells(root);
@@ -456,10 +455,7 @@ struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn)
456 of_node_put(root); 455 of_node_put(root);
457 456
458 pci_devs_phb_init_dynamic(phb); 457 pci_devs_phb_init_dynamic(phb);
459 phb->last_busno = 0xff; 458 scan_phb(phb);
460 bus = pci_scan_bus(phb->first_busno, phb->ops, phb->arch_data);
461 phb->bus = bus;
462 phb->last_busno = bus->subordinate;
463 459
464 return phb; 460 return phb;
465} 461}
diff --git a/arch/ppc64/kernel/udbg.c b/arch/ppc64/kernel/udbg.c
index d49c3613c8ec..0d878e72fc44 100644
--- a/arch/ppc64/kernel/udbg.c
+++ b/arch/ppc64/kernel/udbg.c
@@ -10,12 +10,10 @@
10 */ 10 */
11 11
12#include <stdarg.h> 12#include <stdarg.h>
13#define WANT_PPCDBG_TAB /* Only defined here */
14#include <linux/config.h> 13#include <linux/config.h>
15#include <linux/types.h> 14#include <linux/types.h>
16#include <linux/sched.h> 15#include <linux/sched.h>
17#include <linux/console.h> 16#include <linux/console.h>
18#include <asm/ppcdebug.h>
19#include <asm/processor.h> 17#include <asm/processor.h>
20 18
21void (*udbg_putc)(unsigned char c); 19void (*udbg_putc)(unsigned char c);
@@ -89,59 +87,6 @@ void udbg_printf(const char *fmt, ...)
89 va_end(args); 87 va_end(args);
90} 88}
91 89
92/* PPCDBG stuff */
93
94u64 ppc64_debug_switch;
95
96/* Special print used by PPCDBG() macro */
97void udbg_ppcdbg(unsigned long debug_flags, const char *fmt, ...)
98{
99 unsigned long active_debugs = debug_flags & ppc64_debug_switch;
100
101 if (active_debugs) {
102 va_list ap;
103 unsigned char buf[UDBG_BUFSIZE];
104 unsigned long i, len = 0;
105
106 for (i=0; i < PPCDBG_NUM_FLAGS; i++) {
107 if (((1U << i) & active_debugs) &&
108 trace_names[i]) {
109 len += strlen(trace_names[i]);
110 udbg_puts(trace_names[i]);
111 break;
112 }
113 }
114
115 snprintf(buf, UDBG_BUFSIZE, " [%s]: ", current->comm);
116 len += strlen(buf);
117 udbg_puts(buf);
118
119 while (len < 18) {
120 udbg_puts(" ");
121 len++;
122 }
123
124 va_start(ap, fmt);
125 vsnprintf(buf, UDBG_BUFSIZE, fmt, ap);
126 udbg_puts(buf);
127 va_end(ap);
128 }
129}
130
131unsigned long udbg_ifdebug(unsigned long flags)
132{
133 return (flags & ppc64_debug_switch);
134}
135
136/*
137 * Initialize the PPCDBG state. Called before relocation has been enabled.
138 */
139void __init ppcdbg_initialize(void)
140{
141 ppc64_debug_switch = PPC_DEBUG_DEFAULT; /* | PPCDBG_BUSWALK | */
142 /* PPCDBG_PHBINIT | PPCDBG_MM | PPCDBG_MMINIT | PPCDBG_TCEINIT | PPCDBG_TCE */;
143}
144
145/* 90/*
146 * Early boot console based on udbg 91 * Early boot console based on udbg
147 */ 92 */
diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c
index e425ad3eebba..af7cb2bfd670 100644
--- a/drivers/block/swim3.c
+++ b/drivers/block/swim3.c
@@ -28,6 +28,7 @@
28#include <linux/devfs_fs_kernel.h> 28#include <linux/devfs_fs_kernel.h>
29#include <linux/interrupt.h> 29#include <linux/interrupt.h>
30#include <linux/module.h> 30#include <linux/module.h>
31#include <linux/spinlock.h>
31#include <asm/io.h> 32#include <asm/io.h>
32#include <asm/dbdma.h> 33#include <asm/dbdma.h>
33#include <asm/prom.h> 34#include <asm/prom.h>
@@ -176,6 +177,7 @@ struct swim3 {
176 177
177struct floppy_state { 178struct floppy_state {
178 enum swim_state state; 179 enum swim_state state;
180 spinlock_t lock;
179 struct swim3 __iomem *swim3; /* hardware registers */ 181 struct swim3 __iomem *swim3; /* hardware registers */
180 struct dbdma_regs __iomem *dma; /* DMA controller registers */ 182 struct dbdma_regs __iomem *dma; /* DMA controller registers */
181 int swim3_intr; /* interrupt number for SWIM3 */ 183 int swim3_intr; /* interrupt number for SWIM3 */
@@ -304,7 +306,6 @@ static void do_fd_request(request_queue_t * q)
304#endif /* CONFIG_PMAC_MEDIABAY */ 306#endif /* CONFIG_PMAC_MEDIABAY */
305 start_request(&floppy_states[i]); 307 start_request(&floppy_states[i]);
306 } 308 }
307 sti();
308} 309}
309 310
310static void start_request(struct floppy_state *fs) 311static void start_request(struct floppy_state *fs)
@@ -370,7 +371,7 @@ static void set_timeout(struct floppy_state *fs, int nticks,
370{ 371{
371 unsigned long flags; 372 unsigned long flags;
372 373
373 save_flags(flags); cli(); 374 spin_lock_irqsave(&fs->lock, flags);
374 if (fs->timeout_pending) 375 if (fs->timeout_pending)
375 del_timer(&fs->timeout); 376 del_timer(&fs->timeout);
376 fs->timeout.expires = jiffies + nticks; 377 fs->timeout.expires = jiffies + nticks;
@@ -378,7 +379,7 @@ static void set_timeout(struct floppy_state *fs, int nticks,
378 fs->timeout.data = (unsigned long) fs; 379 fs->timeout.data = (unsigned long) fs;
379 add_timer(&fs->timeout); 380 add_timer(&fs->timeout);
380 fs->timeout_pending = 1; 381 fs->timeout_pending = 1;
381 restore_flags(flags); 382 spin_unlock_irqrestore(&fs->lock, flags);
382} 383}
383 384
384static inline void scan_track(struct floppy_state *fs) 385static inline void scan_track(struct floppy_state *fs)
@@ -790,14 +791,13 @@ static int grab_drive(struct floppy_state *fs, enum swim_state state,
790{ 791{
791 unsigned long flags; 792 unsigned long flags;
792 793
793 save_flags(flags); 794 spin_lock_irqsave(&fs->lock, flags);
794 cli();
795 if (fs->state != idle) { 795 if (fs->state != idle) {
796 ++fs->wanted; 796 ++fs->wanted;
797 while (fs->state != available) { 797 while (fs->state != available) {
798 if (interruptible && signal_pending(current)) { 798 if (interruptible && signal_pending(current)) {
799 --fs->wanted; 799 --fs->wanted;
800 restore_flags(flags); 800 spin_unlock_irqrestore(&fs->lock, flags);
801 return -EINTR; 801 return -EINTR;
802 } 802 }
803 interruptible_sleep_on(&fs->wait); 803 interruptible_sleep_on(&fs->wait);
@@ -805,7 +805,7 @@ static int grab_drive(struct floppy_state *fs, enum swim_state state,
805 --fs->wanted; 805 --fs->wanted;
806 } 806 }
807 fs->state = state; 807 fs->state = state;
808 restore_flags(flags); 808 spin_unlock_irqrestore(&fs->lock, flags);
809 return 0; 809 return 0;
810} 810}
811 811
@@ -813,11 +813,10 @@ static void release_drive(struct floppy_state *fs)
813{ 813{
814 unsigned long flags; 814 unsigned long flags;
815 815
816 save_flags(flags); 816 spin_lock_irqsave(&fs->lock, flags);
817 cli();
818 fs->state = idle; 817 fs->state = idle;
819 start_request(fs); 818 start_request(fs);
820 restore_flags(flags); 819 spin_unlock_irqrestore(&fs->lock, flags);
821} 820}
822 821
823static int fd_eject(struct floppy_state *fs) 822static int fd_eject(struct floppy_state *fs)
@@ -1109,6 +1108,7 @@ static int swim3_add_device(struct device_node *swim)
1109 pmac_call_feature(PMAC_FTR_SWIM3_ENABLE, swim, 0, 1); 1108 pmac_call_feature(PMAC_FTR_SWIM3_ENABLE, swim, 0, 1);
1110 1109
1111 memset(fs, 0, sizeof(*fs)); 1110 memset(fs, 0, sizeof(*fs));
1111 spin_lock_init(&fs->lock);
1112 fs->state = idle; 1112 fs->state = idle;
1113 fs->swim3 = (struct swim3 __iomem *) 1113 fs->swim3 = (struct swim3 __iomem *)
1114 ioremap(swim->addrs[0].address, 0x200); 1114 ioremap(swim->addrs[0].address, 0x200);
diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c
index d8c3d8ebad30..b3e65a65d202 100644
--- a/drivers/ide/ppc/pmac.c
+++ b/drivers/ide/ppc/pmac.c
@@ -497,16 +497,19 @@ pmu_hd_blink_init(void)
497 if (pmu_get_model() != PMU_KEYLARGO_BASED) 497 if (pmu_get_model() != PMU_KEYLARGO_BASED)
498 return 0; 498 return 0;
499 499
500 dt = find_devices("device-tree"); 500 dt = of_find_node_by_path("/");
501 if (dt == NULL) 501 if (dt == NULL)
502 return 0; 502 return 0;
503 model = (const char *)get_property(dt, "model", NULL); 503 model = (const char *)get_property(dt, "model", NULL);
504 if (model == NULL) 504 if (model == NULL)
505 return 0; 505 return 0;
506 if (strncmp(model, "PowerBook", strlen("PowerBook")) != 0 && 506 if (strncmp(model, "PowerBook", strlen("PowerBook")) != 0 &&
507 strncmp(model, "iBook", strlen("iBook")) != 0) 507 strncmp(model, "iBook", strlen("iBook")) != 0) {
508 of_node_put(dt);
508 return 0; 509 return 0;
509 510 }
511 of_node_put(dt);
512
510 pmu_blink_on.complete = 1; 513 pmu_blink_on.complete = 1;
511 pmu_blink_off.complete = 1; 514 pmu_blink_off.complete = 1;
512 spin_lock_init(&pmu_blink_lock); 515 spin_lock_init(&pmu_blink_lock);
diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig
index bc3e096d84f7..a0ea44c3e8b1 100644
--- a/drivers/macintosh/Kconfig
+++ b/drivers/macintosh/Kconfig
@@ -169,6 +169,25 @@ config THERM_PM72
169 This driver provides thermostat and fan control for the desktop 169 This driver provides thermostat and fan control for the desktop
170 G5 machines. 170 G5 machines.
171 171
172config WINDFARM
173 tristate "New PowerMac thermal control infrastructure"
174
175config WINDFARM_PM81
176 tristate "Support for thermal management on iMac G5"
177 depends on WINDFARM && I2C && CPU_FREQ_PMAC64 && PMAC_SMU
178 select I2C_PMAC_SMU
179 help
180 This driver provides thermal control for the iMacG5
181
182config WINDFARM_PM91
183 tristate "Support for thermal management on PowerMac9,1"
184 depends on WINDFARM && I2C && CPU_FREQ_PMAC64 && PMAC_SMU
185 select I2C_PMAC_SMU
186 help
187 This driver provides thermal control for the PowerMac9,1
188 which is the recent (SMU based) single CPU desktop G5
189
190
172config ANSLCD 191config ANSLCD
173 tristate "Support for ANS LCD display" 192 tristate "Support for ANS LCD display"
174 depends on ADB_CUDA && PPC_PMAC 193 depends on ADB_CUDA && PPC_PMAC
diff --git a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile
index 236291bd48a4..f4657aa81fb0 100644
--- a/drivers/macintosh/Makefile
+++ b/drivers/macintosh/Makefile
@@ -26,3 +26,12 @@ obj-$(CONFIG_ADB_MACIO) += macio-adb.o
26obj-$(CONFIG_THERM_PM72) += therm_pm72.o 26obj-$(CONFIG_THERM_PM72) += therm_pm72.o
27obj-$(CONFIG_THERM_WINDTUNNEL) += therm_windtunnel.o 27obj-$(CONFIG_THERM_WINDTUNNEL) += therm_windtunnel.o
28obj-$(CONFIG_THERM_ADT746X) += therm_adt746x.o 28obj-$(CONFIG_THERM_ADT746X) += therm_adt746x.o
29obj-$(CONFIG_WINDFARM) += windfarm_core.o
30obj-$(CONFIG_WINDFARM_PM81) += windfarm_smu_controls.o \
31 windfarm_smu_sensors.o \
32 windfarm_lm75_sensor.o windfarm_pid.o \
33 windfarm_cpufreq_clamp.o windfarm_pm81.o
34obj-$(CONFIG_WINDFARM_PM91) += windfarm_smu_controls.o \
35 windfarm_smu_sensors.o \
36 windfarm_lm75_sensor.o windfarm_pid.o \
37 windfarm_cpufreq_clamp.o windfarm_pm91.o
diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c
index 34f3c7e2d832..e8378274d710 100644
--- a/drivers/macintosh/smu.c
+++ b/drivers/macintosh/smu.c
@@ -47,13 +47,13 @@
47#include <asm/uaccess.h> 47#include <asm/uaccess.h>
48#include <asm/of_device.h> 48#include <asm/of_device.h>
49 49
50#define VERSION "0.6" 50#define VERSION "0.7"
51#define AUTHOR "(c) 2005 Benjamin Herrenschmidt, IBM Corp." 51#define AUTHOR "(c) 2005 Benjamin Herrenschmidt, IBM Corp."
52 52
53#undef DEBUG_SMU 53#undef DEBUG_SMU
54 54
55#ifdef DEBUG_SMU 55#ifdef DEBUG_SMU
56#define DPRINTK(fmt, args...) do { printk(KERN_DEBUG fmt , ##args); } while (0) 56#define DPRINTK(fmt, args...) do { udbg_printf(KERN_DEBUG fmt , ##args); } while (0)
57#else 57#else
58#define DPRINTK(fmt, args...) do { } while (0) 58#define DPRINTK(fmt, args...) do { } while (0)
59#endif 59#endif
@@ -92,7 +92,7 @@ struct smu_device {
92 * for now, just hard code that 92 * for now, just hard code that
93 */ 93 */
94static struct smu_device *smu; 94static struct smu_device *smu;
95 95static DECLARE_MUTEX(smu_part_access);
96 96
97/* 97/*
98 * SMU driver low level stuff 98 * SMU driver low level stuff
@@ -113,9 +113,11 @@ static void smu_start_cmd(void)
113 113
114 DPRINTK("SMU: starting cmd %x, %d bytes data\n", cmd->cmd, 114 DPRINTK("SMU: starting cmd %x, %d bytes data\n", cmd->cmd,
115 cmd->data_len); 115 cmd->data_len);
116 DPRINTK("SMU: data buffer: %02x %02x %02x %02x ...\n", 116 DPRINTK("SMU: data buffer: %02x %02x %02x %02x %02x %02x %02x %02x\n",
117 ((u8 *)cmd->data_buf)[0], ((u8 *)cmd->data_buf)[1], 117 ((u8 *)cmd->data_buf)[0], ((u8 *)cmd->data_buf)[1],
118 ((u8 *)cmd->data_buf)[2], ((u8 *)cmd->data_buf)[3]); 118 ((u8 *)cmd->data_buf)[2], ((u8 *)cmd->data_buf)[3],
119 ((u8 *)cmd->data_buf)[4], ((u8 *)cmd->data_buf)[5],
120 ((u8 *)cmd->data_buf)[6], ((u8 *)cmd->data_buf)[7]);
119 121
120 /* Fill the SMU command buffer */ 122 /* Fill the SMU command buffer */
121 smu->cmd_buf->cmd = cmd->cmd; 123 smu->cmd_buf->cmd = cmd->cmd;
@@ -440,7 +442,7 @@ int smu_present(void)
440EXPORT_SYMBOL(smu_present); 442EXPORT_SYMBOL(smu_present);
441 443
442 444
443int smu_init (void) 445int __init smu_init (void)
444{ 446{
445 struct device_node *np; 447 struct device_node *np;
446 u32 *data; 448 u32 *data;
@@ -588,6 +590,8 @@ static void smu_expose_childs(void *unused)
588 sprintf(name, "smu-i2c-%02x", *reg); 590 sprintf(name, "smu-i2c-%02x", *reg);
589 of_platform_device_create(np, name, &smu->of_dev->dev); 591 of_platform_device_create(np, name, &smu->of_dev->dev);
590 } 592 }
593 if (device_is_compatible(np, "smu-sensors"))
594 of_platform_device_create(np, "smu-sensors", &smu->of_dev->dev);
591 } 595 }
592 596
593} 597}
@@ -845,6 +849,156 @@ int smu_queue_i2c(struct smu_i2c_cmd *cmd)
845 return 0; 849 return 0;
846} 850}
847 851
852/*
853 * Handling of "partitions"
854 */
855
856static int smu_read_datablock(u8 *dest, unsigned int addr, unsigned int len)
857{
858 DECLARE_COMPLETION(comp);
859 unsigned int chunk;
860 struct smu_cmd cmd;
861 int rc;
862 u8 params[8];
863
864 /* We currently use a chunk size of 0xe. We could check the
865 * SMU firmware version and use bigger sizes though
866 */
867 chunk = 0xe;
868
869 while (len) {
870 unsigned int clen = min(len, chunk);
871
872 cmd.cmd = SMU_CMD_MISC_ee_COMMAND;
873 cmd.data_len = 7;
874 cmd.data_buf = params;
875 cmd.reply_len = chunk;
876 cmd.reply_buf = dest;
877 cmd.done = smu_done_complete;
878 cmd.misc = &comp;
879 params[0] = SMU_CMD_MISC_ee_GET_DATABLOCK_REC;
880 params[1] = 0x4;
881 *((u32 *)&params[2]) = addr;
882 params[6] = clen;
883
884 rc = smu_queue_cmd(&cmd);
885 if (rc)
886 return rc;
887 wait_for_completion(&comp);
888 if (cmd.status != 0)
889 return rc;
890 if (cmd.reply_len != clen) {
891 printk(KERN_DEBUG "SMU: short read in "
892 "smu_read_datablock, got: %d, want: %d\n",
893 cmd.reply_len, clen);
894 return -EIO;
895 }
896 len -= clen;
897 addr += clen;
898 dest += clen;
899 }
900 return 0;
901}
902
903static struct smu_sdbp_header *smu_create_sdb_partition(int id)
904{
905 DECLARE_COMPLETION(comp);
906 struct smu_simple_cmd cmd;
907 unsigned int addr, len, tlen;
908 struct smu_sdbp_header *hdr;
909 struct property *prop;
910
911 /* First query the partition info */
912 smu_queue_simple(&cmd, SMU_CMD_PARTITION_COMMAND, 2,
913 smu_done_complete, &comp,
914 SMU_CMD_PARTITION_LATEST, id);
915 wait_for_completion(&comp);
916
917 /* Partition doesn't exist (or other error) */
918 if (cmd.cmd.status != 0 || cmd.cmd.reply_len != 6)
919 return NULL;
920
921 /* Fetch address and length from reply */
922 addr = *((u16 *)cmd.buffer);
923 len = cmd.buffer[3] << 2;
924 /* Calucluate total length to allocate, including the 17 bytes
925 * for "sdb-partition-XX" that we append at the end of the buffer
926 */
927 tlen = sizeof(struct property) + len + 18;
928
929 prop = kcalloc(tlen, 1, GFP_KERNEL);
930 if (prop == NULL)
931 return NULL;
932 hdr = (struct smu_sdbp_header *)(prop + 1);
933 prop->name = ((char *)prop) + tlen - 18;
934 sprintf(prop->name, "sdb-partition-%02x", id);
935 prop->length = len;
936 prop->value = (unsigned char *)hdr;
937 prop->next = NULL;
938
939 /* Read the datablock */
940 if (smu_read_datablock((u8 *)hdr, addr, len)) {
941 printk(KERN_DEBUG "SMU: datablock read failed while reading "
942 "partition %02x !\n", id);
943 goto failure;
944 }
945
946 /* Got it, check a few things and create the property */
947 if (hdr->id != id) {
948 printk(KERN_DEBUG "SMU: Reading partition %02x and got "
949 "%02x !\n", id, hdr->id);
950 goto failure;
951 }
952 if (prom_add_property(smu->of_node, prop)) {
953 printk(KERN_DEBUG "SMU: Failed creating sdb-partition-%02x "
954 "property !\n", id);
955 goto failure;
956 }
957
958 return hdr;
959 failure:
960 kfree(prop);
961 return NULL;
962}
963
964/* Note: Only allowed to return error code in pointers (using ERR_PTR)
965 * when interruptible is 1
966 */
967struct smu_sdbp_header *__smu_get_sdb_partition(int id, unsigned int *size,
968 int interruptible)
969{
970 char pname[32];
971 struct smu_sdbp_header *part;
972
973 if (!smu)
974 return NULL;
975
976 sprintf(pname, "sdb-partition-%02x", id);
977
978 if (interruptible) {
979 int rc;
980 rc = down_interruptible(&smu_part_access);
981 if (rc)
982 return ERR_PTR(rc);
983 } else
984 down(&smu_part_access);
985
986 part = (struct smu_sdbp_header *)get_property(smu->of_node,
987 pname, size);
988 if (part == NULL) {
989 part = smu_create_sdb_partition(id);
990 if (part != NULL && size)
991 *size = part->len << 2;
992 }
993 up(&smu_part_access);
994 return part;
995}
996
997struct smu_sdbp_header *smu_get_sdb_partition(int id, unsigned int *size)
998{
999 return __smu_get_sdb_partition(id, size, 0);
1000}
1001EXPORT_SYMBOL(smu_get_sdb_partition);
848 1002
849 1003
850/* 1004/*
@@ -918,6 +1072,14 @@ static ssize_t smu_write(struct file *file, const char __user *buf,
918 else if (hdr.cmdtype == SMU_CMDTYPE_WANTS_EVENTS) { 1072 else if (hdr.cmdtype == SMU_CMDTYPE_WANTS_EVENTS) {
919 pp->mode = smu_file_events; 1073 pp->mode = smu_file_events;
920 return 0; 1074 return 0;
1075 } else if (hdr.cmdtype == SMU_CMDTYPE_GET_PARTITION) {
1076 struct smu_sdbp_header *part;
1077 part = __smu_get_sdb_partition(hdr.cmd, NULL, 1);
1078 if (part == NULL)
1079 return -EINVAL;
1080 else if (IS_ERR(part))
1081 return PTR_ERR(part);
1082 return 0;
921 } else if (hdr.cmdtype != SMU_CMDTYPE_SMU) 1083 } else if (hdr.cmdtype != SMU_CMDTYPE_SMU)
922 return -EINVAL; 1084 return -EINVAL;
923 else if (pp->mode != smu_file_commands) 1085 else if (pp->mode != smu_file_commands)
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index 9bc6cc6e3845..564043508569 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -2053,6 +2053,7 @@ pmu_register_sleep_notifier(struct pmu_sleep_notifier *n)
2053 __list_add(&n->list, list->prev, list); 2053 __list_add(&n->list, list->prev, list);
2054 return 0; 2054 return 0;
2055} 2055}
2056EXPORT_SYMBOL(pmu_register_sleep_notifier);
2056 2057
2057int 2058int
2058pmu_unregister_sleep_notifier(struct pmu_sleep_notifier* n) 2059pmu_unregister_sleep_notifier(struct pmu_sleep_notifier* n)
@@ -2063,6 +2064,7 @@ pmu_unregister_sleep_notifier(struct pmu_sleep_notifier* n)
2063 n->list.next = NULL; 2064 n->list.next = NULL;
2064 return 0; 2065 return 0;
2065} 2066}
2067EXPORT_SYMBOL(pmu_unregister_sleep_notifier);
2066#endif /* CONFIG_PM */ 2068#endif /* CONFIG_PM */
2067 2069
2068#if defined(CONFIG_PM) && defined(CONFIG_PPC32) 2070#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
@@ -2667,10 +2669,10 @@ powerbook_sleep_3400(void)
2667 asleep = 1; 2669 asleep = 1;
2668 2670
2669 /* Put the CPU into sleep mode */ 2671 /* Put the CPU into sleep mode */
2670 asm volatile("mfspr %0,1008" : "=r" (hid0) :); 2672 hid0 = mfspr(SPRN_HID0);
2671 hid0 = (hid0 & ~(HID0_NAP | HID0_DOZE)) | HID0_SLEEP; 2673 hid0 = (hid0 & ~(HID0_NAP | HID0_DOZE)) | HID0_SLEEP;
2672 asm volatile("mtspr 1008,%0" : : "r" (hid0)); 2674 mtspr(SPRN_HID0, hid0);
2673 _nmask_and_or_msr(0, MSR_POW | MSR_EE); 2675 mtmsr(mfmsr() | MSR_POW | MSR_EE);
2674 udelay(10); 2676 udelay(10);
2675 2677
2676 /* OK, we're awake again, start restoring things */ 2678 /* OK, we're awake again, start restoring things */
@@ -3139,8 +3141,6 @@ EXPORT_SYMBOL(pmu_i2c_stdsub_write);
3139EXPORT_SYMBOL(pmu_i2c_simple_read); 3141EXPORT_SYMBOL(pmu_i2c_simple_read);
3140EXPORT_SYMBOL(pmu_i2c_simple_write); 3142EXPORT_SYMBOL(pmu_i2c_simple_write);
3141#if defined(CONFIG_PM) && defined(CONFIG_PPC32) 3143#if defined(CONFIG_PM) && defined(CONFIG_PPC32)
3142EXPORT_SYMBOL(pmu_register_sleep_notifier);
3143EXPORT_SYMBOL(pmu_unregister_sleep_notifier);
3144EXPORT_SYMBOL(pmu_enable_irled); 3144EXPORT_SYMBOL(pmu_enable_irled);
3145EXPORT_SYMBOL(pmu_battery_count); 3145EXPORT_SYMBOL(pmu_battery_count);
3146EXPORT_SYMBOL(pmu_batteries); 3146EXPORT_SYMBOL(pmu_batteries);
diff --git a/drivers/macintosh/windfarm.h b/drivers/macintosh/windfarm.h
new file mode 100644
index 000000000000..3f0cb0312ea3
--- /dev/null
+++ b/drivers/macintosh/windfarm.h
@@ -0,0 +1,131 @@
1/*
2 * Windfarm PowerMac thermal control.
3 *
4 * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp.
5 * <benh@kernel.crashing.org>
6 *
7 * Released under the term of the GNU GPL v2.
8 */
9
10#ifndef __WINDFARM_H__
11#define __WINDFARM_H__
12
13#include <linux/kref.h>
14#include <linux/list.h>
15#include <linux/module.h>
16#include <linux/notifier.h>
17
18/* Display a 16.16 fixed point value */
19#define FIX32TOPRINT(f) ((f) >> 16),((((f) & 0xffff) * 1000) >> 16)
20
21/*
22 * Control objects
23 */
24
25struct wf_control;
26
27struct wf_control_ops {
28 int (*set_value)(struct wf_control *ct, s32 val);
29 int (*get_value)(struct wf_control *ct, s32 *val);
30 s32 (*get_min)(struct wf_control *ct);
31 s32 (*get_max)(struct wf_control *ct);
32 void (*release)(struct wf_control *ct);
33 struct module *owner;
34};
35
36struct wf_control {
37 struct list_head link;
38 struct wf_control_ops *ops;
39 char *name;
40 int type;
41 struct kref ref;
42};
43
44#define WF_CONTROL_TYPE_GENERIC 0
45#define WF_CONTROL_RPM_FAN 1
46#define WF_CONTROL_PWM_FAN 2
47
48
49/* Note about lifetime rules: wf_register_control() will initialize
50 * the kref and wf_unregister_control will decrement it, thus the
51 * object creating/disposing a given control shouldn't assume it
52 * still exists after wf_unregister_control has been called.
53 * wf_find_control will inc the refcount for you
54 */
55extern int wf_register_control(struct wf_control *ct);
56extern void wf_unregister_control(struct wf_control *ct);
57extern struct wf_control * wf_find_control(const char *name);
58extern int wf_get_control(struct wf_control *ct);
59extern void wf_put_control(struct wf_control *ct);
60
61static inline int wf_control_set_max(struct wf_control *ct)
62{
63 s32 vmax = ct->ops->get_max(ct);
64 return ct->ops->set_value(ct, vmax);
65}
66
67static inline int wf_control_set_min(struct wf_control *ct)
68{
69 s32 vmin = ct->ops->get_min(ct);
70 return ct->ops->set_value(ct, vmin);
71}
72
73/*
74 * Sensor objects
75 */
76
77struct wf_sensor;
78
79struct wf_sensor_ops {
80 int (*get_value)(struct wf_sensor *sr, s32 *val);
81 void (*release)(struct wf_sensor *sr);
82 struct module *owner;
83};
84
85struct wf_sensor {
86 struct list_head link;
87 struct wf_sensor_ops *ops;
88 char *name;
89 struct kref ref;
90};
91
92/* Same lifetime rules as controls */
93extern int wf_register_sensor(struct wf_sensor *sr);
94extern void wf_unregister_sensor(struct wf_sensor *sr);
95extern struct wf_sensor * wf_find_sensor(const char *name);
96extern int wf_get_sensor(struct wf_sensor *sr);
97extern void wf_put_sensor(struct wf_sensor *sr);
98
99/* For use by clients. Note that we are a bit racy here since
100 * notifier_block doesn't have a module owner field. I may fix
101 * it one day ...
102 *
103 * LOCKING NOTE !
104 *
105 * All "events" except WF_EVENT_TICK are called with an internal mutex
106 * held which will deadlock if you call basically any core routine.
107 * So don't ! Just take note of the event and do your actual operations
108 * from the ticker.
109 *
110 */
111extern int wf_register_client(struct notifier_block *nb);
112extern int wf_unregister_client(struct notifier_block *nb);
113
114/* Overtemp conditions. Those are refcounted */
115extern void wf_set_overtemp(void);
116extern void wf_clear_overtemp(void);
117extern int wf_is_overtemp(void);
118
119#define WF_EVENT_NEW_CONTROL 0 /* param is wf_control * */
120#define WF_EVENT_NEW_SENSOR 1 /* param is wf_sensor * */
121#define WF_EVENT_OVERTEMP 2 /* no param */
122#define WF_EVENT_NORMALTEMP 3 /* overtemp condition cleared */
123#define WF_EVENT_TICK 4 /* 1 second tick */
124
125/* Note: If that driver gets more broad use, we could replace the
126 * simplistic overtemp bits with "environmental conditions". That
127 * could then be used to also notify of things like fan failure,
128 * case open, battery conditions, ...
129 */
130
131#endif /* __WINDFARM_H__ */
diff --git a/drivers/macintosh/windfarm_core.c b/drivers/macintosh/windfarm_core.c
new file mode 100644
index 000000000000..6c2a471ea6c0
--- /dev/null
+++ b/drivers/macintosh/windfarm_core.c
@@ -0,0 +1,426 @@
1/*
2 * Windfarm PowerMac thermal control. Core
3 *
4 * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp.
5 * <benh@kernel.crashing.org>
6 *
7 * Released under the term of the GNU GPL v2.
8 *
9 * This core code tracks the list of sensors & controls, register
10 * clients, and holds the kernel thread used for control.
11 *
12 * TODO:
13 *
14 * Add some information about sensor/control type and data format to
15 * sensors/controls, and have the sysfs attribute stuff be moved
16 * generically here instead of hard coded in the platform specific
17 * driver as it us currently
18 *
19 * This however requires solving some annoying lifetime issues with
20 * sysfs which doesn't seem to have lifetime rules for struct attribute,
21 * I may have to create full features kobjects for every sensor/control
22 * instead which is a bit of an overkill imho
23 */
24
25#include <linux/types.h>
26#include <linux/errno.h>
27#include <linux/kernel.h>
28#include <linux/init.h>
29#include <linux/spinlock.h>
30#include <linux/smp_lock.h>
31#include <linux/kthread.h>
32#include <linux/jiffies.h>
33#include <linux/reboot.h>
34#include <linux/device.h>
35#include <linux/platform_device.h>
36
37#include "windfarm.h"
38
39#define VERSION "0.2"
40
41#undef DEBUG
42
43#ifdef DEBUG
44#define DBG(args...) printk(args)
45#else
46#define DBG(args...) do { } while(0)
47#endif
48
49static LIST_HEAD(wf_controls);
50static LIST_HEAD(wf_sensors);
51static DECLARE_MUTEX(wf_lock);
52static struct notifier_block *wf_client_list;
53static int wf_client_count;
54static unsigned int wf_overtemp;
55static unsigned int wf_overtemp_counter;
56struct task_struct *wf_thread;
57
58/*
59 * Utilities & tick thread
60 */
61
62static inline void wf_notify(int event, void *param)
63{
64 notifier_call_chain(&wf_client_list, event, param);
65}
66
67int wf_critical_overtemp(void)
68{
69 static char * critical_overtemp_path = "/sbin/critical_overtemp";
70 char *argv[] = { critical_overtemp_path, NULL };
71 static char *envp[] = { "HOME=/",
72 "TERM=linux",
73 "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
74 NULL };
75
76 return call_usermodehelper(critical_overtemp_path, argv, envp, 0);
77}
78EXPORT_SYMBOL_GPL(wf_critical_overtemp);
79
80static int wf_thread_func(void *data)
81{
82 unsigned long next, delay;
83
84 next = jiffies;
85
86 DBG("wf: thread started\n");
87
88 while(!kthread_should_stop()) {
89 try_to_freeze();
90
91 if (time_after_eq(jiffies, next)) {
92 wf_notify(WF_EVENT_TICK, NULL);
93 if (wf_overtemp) {
94 wf_overtemp_counter++;
95 /* 10 seconds overtemp, notify userland */
96 if (wf_overtemp_counter > 10)
97 wf_critical_overtemp();
98 /* 30 seconds, shutdown */
99 if (wf_overtemp_counter > 30) {
100 printk(KERN_ERR "windfarm: Overtemp "
101 "for more than 30"
102 " seconds, shutting down\n");
103 machine_power_off();
104 }
105 }
106 next += HZ;
107 }
108
109 delay = next - jiffies;
110 if (delay <= HZ)
111 schedule_timeout_interruptible(delay);
112
113 /* there should be no signal, but oh well */
114 if (signal_pending(current)) {
115 printk(KERN_WARNING "windfarm: thread got sigl !\n");
116 break;
117 }
118 }
119
120 DBG("wf: thread stopped\n");
121
122 return 0;
123}
124
125static void wf_start_thread(void)
126{
127 wf_thread = kthread_run(wf_thread_func, NULL, "kwindfarm");
128 if (IS_ERR(wf_thread)) {
129 printk(KERN_ERR "windfarm: failed to create thread,err %ld\n",
130 PTR_ERR(wf_thread));
131 wf_thread = NULL;
132 }
133}
134
135
136static void wf_stop_thread(void)
137{
138 if (wf_thread)
139 kthread_stop(wf_thread);
140 wf_thread = NULL;
141}
142
143/*
144 * Controls
145 */
146
147static void wf_control_release(struct kref *kref)
148{
149 struct wf_control *ct = container_of(kref, struct wf_control, ref);
150
151 DBG("wf: Deleting control %s\n", ct->name);
152
153 if (ct->ops && ct->ops->release)
154 ct->ops->release(ct);
155 else
156 kfree(ct);
157}
158
159int wf_register_control(struct wf_control *new_ct)
160{
161 struct wf_control *ct;
162
163 down(&wf_lock);
164 list_for_each_entry(ct, &wf_controls, link) {
165 if (!strcmp(ct->name, new_ct->name)) {
166 printk(KERN_WARNING "windfarm: trying to register"
167 " duplicate control %s\n", ct->name);
168 up(&wf_lock);
169 return -EEXIST;
170 }
171 }
172 kref_init(&new_ct->ref);
173 list_add(&new_ct->link, &wf_controls);
174
175 DBG("wf: Registered control %s\n", new_ct->name);
176
177 wf_notify(WF_EVENT_NEW_CONTROL, new_ct);
178 up(&wf_lock);
179
180 return 0;
181}
182EXPORT_SYMBOL_GPL(wf_register_control);
183
184void wf_unregister_control(struct wf_control *ct)
185{
186 down(&wf_lock);
187 list_del(&ct->link);
188 up(&wf_lock);
189
190 DBG("wf: Unregistered control %s\n", ct->name);
191
192 kref_put(&ct->ref, wf_control_release);
193}
194EXPORT_SYMBOL_GPL(wf_unregister_control);
195
196struct wf_control * wf_find_control(const char *name)
197{
198 struct wf_control *ct;
199
200 down(&wf_lock);
201 list_for_each_entry(ct, &wf_controls, link) {
202 if (!strcmp(ct->name, name)) {
203 if (wf_get_control(ct))
204 ct = NULL;
205 up(&wf_lock);
206 return ct;
207 }
208 }
209 up(&wf_lock);
210 return NULL;
211}
212EXPORT_SYMBOL_GPL(wf_find_control);
213
214int wf_get_control(struct wf_control *ct)
215{
216 if (!try_module_get(ct->ops->owner))
217 return -ENODEV;
218 kref_get(&ct->ref);
219 return 0;
220}
221EXPORT_SYMBOL_GPL(wf_get_control);
222
223void wf_put_control(struct wf_control *ct)
224{
225 struct module *mod = ct->ops->owner;
226 kref_put(&ct->ref, wf_control_release);
227 module_put(mod);
228}
229EXPORT_SYMBOL_GPL(wf_put_control);
230
231
232/*
233 * Sensors
234 */
235
236
237static void wf_sensor_release(struct kref *kref)
238{
239 struct wf_sensor *sr = container_of(kref, struct wf_sensor, ref);
240
241 DBG("wf: Deleting sensor %s\n", sr->name);
242
243 if (sr->ops && sr->ops->release)
244 sr->ops->release(sr);
245 else
246 kfree(sr);
247}
248
249int wf_register_sensor(struct wf_sensor *new_sr)
250{
251 struct wf_sensor *sr;
252
253 down(&wf_lock);
254 list_for_each_entry(sr, &wf_sensors, link) {
255 if (!strcmp(sr->name, new_sr->name)) {
256 printk(KERN_WARNING "windfarm: trying to register"
257 " duplicate sensor %s\n", sr->name);
258 up(&wf_lock);
259 return -EEXIST;
260 }
261 }
262 kref_init(&new_sr->ref);
263 list_add(&new_sr->link, &wf_sensors);
264
265 DBG("wf: Registered sensor %s\n", new_sr->name);
266
267 wf_notify(WF_EVENT_NEW_SENSOR, new_sr);
268 up(&wf_lock);
269
270 return 0;
271}
272EXPORT_SYMBOL_GPL(wf_register_sensor);
273
274void wf_unregister_sensor(struct wf_sensor *sr)
275{
276 down(&wf_lock);
277 list_del(&sr->link);
278 up(&wf_lock);
279
280 DBG("wf: Unregistered sensor %s\n", sr->name);
281
282 wf_put_sensor(sr);
283}
284EXPORT_SYMBOL_GPL(wf_unregister_sensor);
285
286struct wf_sensor * wf_find_sensor(const char *name)
287{
288 struct wf_sensor *sr;
289
290 down(&wf_lock);
291 list_for_each_entry(sr, &wf_sensors, link) {
292 if (!strcmp(sr->name, name)) {
293 if (wf_get_sensor(sr))
294 sr = NULL;
295 up(&wf_lock);
296 return sr;
297 }
298 }
299 up(&wf_lock);
300 return NULL;
301}
302EXPORT_SYMBOL_GPL(wf_find_sensor);
303
304int wf_get_sensor(struct wf_sensor *sr)
305{
306 if (!try_module_get(sr->ops->owner))
307 return -ENODEV;
308 kref_get(&sr->ref);
309 return 0;
310}
311EXPORT_SYMBOL_GPL(wf_get_sensor);
312
313void wf_put_sensor(struct wf_sensor *sr)
314{
315 struct module *mod = sr->ops->owner;
316 kref_put(&sr->ref, wf_sensor_release);
317 module_put(mod);
318}
319EXPORT_SYMBOL_GPL(wf_put_sensor);
320
321
322/*
323 * Client & notification
324 */
325
326int wf_register_client(struct notifier_block *nb)
327{
328 int rc;
329 struct wf_control *ct;
330 struct wf_sensor *sr;
331
332 down(&wf_lock);
333 rc = notifier_chain_register(&wf_client_list, nb);
334 if (rc != 0)
335 goto bail;
336 wf_client_count++;
337 list_for_each_entry(ct, &wf_controls, link)
338 wf_notify(WF_EVENT_NEW_CONTROL, ct);
339 list_for_each_entry(sr, &wf_sensors, link)
340 wf_notify(WF_EVENT_NEW_SENSOR, sr);
341 if (wf_client_count == 1)
342 wf_start_thread();
343 bail:
344 up(&wf_lock);
345 return rc;
346}
347EXPORT_SYMBOL_GPL(wf_register_client);
348
349int wf_unregister_client(struct notifier_block *nb)
350{
351 down(&wf_lock);
352 notifier_chain_unregister(&wf_client_list, nb);
353 wf_client_count++;
354 if (wf_client_count == 0)
355 wf_stop_thread();
356 up(&wf_lock);
357
358 return 0;
359}
360EXPORT_SYMBOL_GPL(wf_unregister_client);
361
362void wf_set_overtemp(void)
363{
364 down(&wf_lock);
365 wf_overtemp++;
366 if (wf_overtemp == 1) {
367 printk(KERN_WARNING "windfarm: Overtemp condition detected !\n");
368 wf_overtemp_counter = 0;
369 wf_notify(WF_EVENT_OVERTEMP, NULL);
370 }
371 up(&wf_lock);
372}
373EXPORT_SYMBOL_GPL(wf_set_overtemp);
374
375void wf_clear_overtemp(void)
376{
377 down(&wf_lock);
378 WARN_ON(wf_overtemp == 0);
379 if (wf_overtemp == 0) {
380 up(&wf_lock);
381 return;
382 }
383 wf_overtemp--;
384 if (wf_overtemp == 0) {
385 printk(KERN_WARNING "windfarm: Overtemp condition cleared !\n");
386 wf_notify(WF_EVENT_NORMALTEMP, NULL);
387 }
388 up(&wf_lock);
389}
390EXPORT_SYMBOL_GPL(wf_clear_overtemp);
391
392int wf_is_overtemp(void)
393{
394 return (wf_overtemp != 0);
395}
396EXPORT_SYMBOL_GPL(wf_is_overtemp);
397
398static struct platform_device wf_platform_device = {
399 .name = "windfarm",
400};
401
402static int __init windfarm_core_init(void)
403{
404 DBG("wf: core loaded\n");
405
406 platform_device_register(&wf_platform_device);
407 return 0;
408}
409
410static void __exit windfarm_core_exit(void)
411{
412 BUG_ON(wf_client_count != 0);
413
414 DBG("wf: core unloaded\n");
415
416 platform_device_unregister(&wf_platform_device);
417}
418
419
420module_init(windfarm_core_init);
421module_exit(windfarm_core_exit);
422
423MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
424MODULE_DESCRIPTION("Core component of PowerMac thermal control");
425MODULE_LICENSE("GPL");
426
diff --git a/drivers/macintosh/windfarm_cpufreq_clamp.c b/drivers/macintosh/windfarm_cpufreq_clamp.c
new file mode 100644
index 000000000000..607dbaca69c9
--- /dev/null
+++ b/drivers/macintosh/windfarm_cpufreq_clamp.c
@@ -0,0 +1,105 @@
1#include <linux/config.h>
2#include <linux/types.h>
3#include <linux/errno.h>
4#include <linux/kernel.h>
5#include <linux/delay.h>
6#include <linux/slab.h>
7#include <linux/init.h>
8#include <linux/wait.h>
9#include <linux/cpufreq.h>
10
11#include "windfarm.h"
12
13#define VERSION "0.3"
14
15static int clamped;
16static struct wf_control *clamp_control;
17
18static int clamp_notifier_call(struct notifier_block *self,
19 unsigned long event, void *data)
20{
21 struct cpufreq_policy *p = data;
22 unsigned long max_freq;
23
24 if (event != CPUFREQ_ADJUST)
25 return 0;
26
27 max_freq = clamped ? (p->cpuinfo.min_freq) : (p->cpuinfo.max_freq);
28 cpufreq_verify_within_limits(p, 0, max_freq);
29
30 return 0;
31}
32
33static struct notifier_block clamp_notifier = {
34 .notifier_call = clamp_notifier_call,
35};
36
37static int clamp_set(struct wf_control *ct, s32 value)
38{
39 if (value)
40 printk(KERN_INFO "windfarm: Clamping CPU frequency to "
41 "minimum !\n");
42 else
43 printk(KERN_INFO "windfarm: CPU frequency unclamped !\n");
44 clamped = value;
45 cpufreq_update_policy(0);
46 return 0;
47}
48
49static int clamp_get(struct wf_control *ct, s32 *value)
50{
51 *value = clamped;
52 return 0;
53}
54
55static s32 clamp_min(struct wf_control *ct)
56{
57 return 0;
58}
59
60static s32 clamp_max(struct wf_control *ct)
61{
62 return 1;
63}
64
65static struct wf_control_ops clamp_ops = {
66 .set_value = clamp_set,
67 .get_value = clamp_get,
68 .get_min = clamp_min,
69 .get_max = clamp_max,
70 .owner = THIS_MODULE,
71};
72
73static int __init wf_cpufreq_clamp_init(void)
74{
75 struct wf_control *clamp;
76
77 clamp = kmalloc(sizeof(struct wf_control), GFP_KERNEL);
78 if (clamp == NULL)
79 return -ENOMEM;
80 cpufreq_register_notifier(&clamp_notifier, CPUFREQ_POLICY_NOTIFIER);
81 clamp->ops = &clamp_ops;
82 clamp->name = "cpufreq-clamp";
83 if (wf_register_control(clamp))
84 goto fail;
85 clamp_control = clamp;
86 return 0;
87 fail:
88 kfree(clamp);
89 return -ENODEV;
90}
91
92static void __exit wf_cpufreq_clamp_exit(void)
93{
94 if (clamp_control)
95 wf_unregister_control(clamp_control);
96}
97
98
99module_init(wf_cpufreq_clamp_init);
100module_exit(wf_cpufreq_clamp_exit);
101
102MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
103MODULE_DESCRIPTION("CPU frequency clamp for PowerMacs thermal control");
104MODULE_LICENSE("GPL");
105
diff --git a/drivers/macintosh/windfarm_lm75_sensor.c b/drivers/macintosh/windfarm_lm75_sensor.c
new file mode 100644
index 000000000000..a0a41ad0f2b5
--- /dev/null
+++ b/drivers/macintosh/windfarm_lm75_sensor.c
@@ -0,0 +1,263 @@
1/*
2 * Windfarm PowerMac thermal control. LM75 sensor
3 *
4 * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp.
5 * <benh@kernel.crashing.org>
6 *
7 * Released under the term of the GNU GPL v2.
8 */
9
10#include <linux/types.h>
11#include <linux/errno.h>
12#include <linux/kernel.h>
13#include <linux/delay.h>
14#include <linux/slab.h>
15#include <linux/init.h>
16#include <linux/wait.h>
17#include <linux/i2c.h>
18#include <linux/i2c-dev.h>
19#include <asm/prom.h>
20#include <asm/machdep.h>
21#include <asm/io.h>
22#include <asm/system.h>
23#include <asm/sections.h>
24
25#include "windfarm.h"
26
27#define VERSION "0.1"
28
29#undef DEBUG
30
31#ifdef DEBUG
32#define DBG(args...) printk(args)
33#else
34#define DBG(args...) do { } while(0)
35#endif
36
37struct wf_lm75_sensor {
38 int ds1775 : 1;
39 int inited : 1;
40 struct i2c_client i2c;
41 struct wf_sensor sens;
42};
43#define wf_to_lm75(c) container_of(c, struct wf_lm75_sensor, sens)
44#define i2c_to_lm75(c) container_of(c, struct wf_lm75_sensor, i2c)
45
46static int wf_lm75_attach(struct i2c_adapter *adapter);
47static int wf_lm75_detach(struct i2c_client *client);
48
49static struct i2c_driver wf_lm75_driver = {
50 .owner = THIS_MODULE,
51 .name = "wf_lm75",
52 .flags = I2C_DF_NOTIFY,
53 .attach_adapter = wf_lm75_attach,
54 .detach_client = wf_lm75_detach,
55};
56
57static int wf_lm75_get(struct wf_sensor *sr, s32 *value)
58{
59 struct wf_lm75_sensor *lm = wf_to_lm75(sr);
60 s32 data;
61
62 if (lm->i2c.adapter == NULL)
63 return -ENODEV;
64
65 /* Init chip if necessary */
66 if (!lm->inited) {
67 u8 cfg_new, cfg = (u8)i2c_smbus_read_byte_data(&lm->i2c, 1);
68
69 DBG("wf_lm75: Initializing %s, cfg was: %02x\n",
70 sr->name, cfg);
71
72 /* clear shutdown bit, keep other settings as left by
73 * the firmware for now
74 */
75 cfg_new = cfg & ~0x01;
76 i2c_smbus_write_byte_data(&lm->i2c, 1, cfg_new);
77 lm->inited = 1;
78
79 /* If we just powered it up, let's wait 200 ms */
80 msleep(200);
81 }
82
83 /* Read temperature register */
84 data = (s32)le16_to_cpu(i2c_smbus_read_word_data(&lm->i2c, 0));
85 data <<= 8;
86 *value = data;
87
88 return 0;
89}
90
91static void wf_lm75_release(struct wf_sensor *sr)
92{
93 struct wf_lm75_sensor *lm = wf_to_lm75(sr);
94
95 /* check if client is registered and detach from i2c */
96 if (lm->i2c.adapter) {
97 i2c_detach_client(&lm->i2c);
98 lm->i2c.adapter = NULL;
99 }
100
101 kfree(lm);
102}
103
104static struct wf_sensor_ops wf_lm75_ops = {
105 .get_value = wf_lm75_get,
106 .release = wf_lm75_release,
107 .owner = THIS_MODULE,
108};
109
110static struct wf_lm75_sensor *wf_lm75_create(struct i2c_adapter *adapter,
111 u8 addr, int ds1775,
112 const char *loc)
113{
114 struct wf_lm75_sensor *lm;
115
116 DBG("wf_lm75: creating %s device at address 0x%02x\n",
117 ds1775 ? "ds1775" : "lm75", addr);
118
119 lm = kmalloc(sizeof(struct wf_lm75_sensor), GFP_KERNEL);
120 if (lm == NULL)
121 return NULL;
122 memset(lm, 0, sizeof(struct wf_lm75_sensor));
123
124 /* Usual rant about sensor names not beeing very consistent in
125 * the device-tree, oh well ...
126 * Add more entries below as you deal with more setups
127 */
128 if (!strcmp(loc, "Hard drive") || !strcmp(loc, "DRIVE BAY"))
129 lm->sens.name = "hd-temp";
130 else
131 goto fail;
132
133 lm->inited = 0;
134 lm->sens.ops = &wf_lm75_ops;
135 lm->ds1775 = ds1775;
136 lm->i2c.addr = (addr >> 1) & 0x7f;
137 lm->i2c.adapter = adapter;
138 lm->i2c.driver = &wf_lm75_driver;
139 strncpy(lm->i2c.name, lm->sens.name, I2C_NAME_SIZE-1);
140
141 if (i2c_attach_client(&lm->i2c)) {
142 printk(KERN_ERR "windfarm: failed to attach %s %s to i2c\n",
143 ds1775 ? "ds1775" : "lm75", lm->i2c.name);
144 goto fail;
145 }
146
147 if (wf_register_sensor(&lm->sens)) {
148 i2c_detach_client(&lm->i2c);
149 goto fail;
150 }
151
152 return lm;
153 fail:
154 kfree(lm);
155 return NULL;
156}
157
158static int wf_lm75_attach(struct i2c_adapter *adapter)
159{
160 u8 bus_id;
161 struct device_node *smu, *bus, *dev;
162
163 /* We currently only deal with LM75's hanging off the SMU
164 * i2c busses. If we extend that driver to other/older
165 * machines, we should split this function into SMU-i2c,
166 * keywest-i2c, PMU-i2c, ...
167 */
168
169 DBG("wf_lm75: adapter %s detected\n", adapter->name);
170
171 if (strncmp(adapter->name, "smu-i2c-", 8) != 0)
172 return 0;
173 smu = of_find_node_by_type(NULL, "smu");
174 if (smu == NULL)
175 return 0;
176
177 /* Look for the bus in the device-tree */
178 bus_id = (u8)simple_strtoul(adapter->name + 8, NULL, 16);
179
180 DBG("wf_lm75: bus ID is %x\n", bus_id);
181
182 /* Look for sensors subdir */
183 for (bus = NULL;
184 (bus = of_get_next_child(smu, bus)) != NULL;) {
185 u32 *reg;
186
187 if (strcmp(bus->name, "i2c"))
188 continue;
189 reg = (u32 *)get_property(bus, "reg", NULL);
190 if (reg == NULL)
191 continue;
192 if (bus_id == *reg)
193 break;
194 }
195 of_node_put(smu);
196 if (bus == NULL) {
197 printk(KERN_WARNING "windfarm: SMU i2c bus 0x%x not found"
198 " in device-tree !\n", bus_id);
199 return 0;
200 }
201
202 DBG("wf_lm75: bus found, looking for device...\n");
203
204 /* Now look for lm75(s) in there */
205 for (dev = NULL;
206 (dev = of_get_next_child(bus, dev)) != NULL;) {
207 const char *loc =
208 get_property(dev, "hwsensor-location", NULL);
209 u32 *reg = (u32 *)get_property(dev, "reg", NULL);
210 DBG(" dev: %s... (loc: %p, reg: %p)\n", dev->name, loc, reg);
211 if (loc == NULL || reg == NULL)
212 continue;
213 /* real lm75 */
214 if (device_is_compatible(dev, "lm75"))
215 wf_lm75_create(adapter, *reg, 0, loc);
216 /* ds1775 (compatible, better resolution */
217 else if (device_is_compatible(dev, "ds1775"))
218 wf_lm75_create(adapter, *reg, 1, loc);
219 }
220
221 of_node_put(bus);
222
223 return 0;
224}
225
226static int wf_lm75_detach(struct i2c_client *client)
227{
228 struct wf_lm75_sensor *lm = i2c_to_lm75(client);
229
230 DBG("wf_lm75: i2c detatch called for %s\n", lm->sens.name);
231
232 /* Mark client detached */
233 lm->i2c.adapter = NULL;
234
235 /* release sensor */
236 wf_unregister_sensor(&lm->sens);
237
238 return 0;
239}
240
241static int __init wf_lm75_sensor_init(void)
242{
243 int rc;
244
245 rc = i2c_add_driver(&wf_lm75_driver);
246 if (rc < 0)
247 return rc;
248 return 0;
249}
250
251static void __exit wf_lm75_sensor_exit(void)
252{
253 i2c_del_driver(&wf_lm75_driver);
254}
255
256
257module_init(wf_lm75_sensor_init);
258module_exit(wf_lm75_sensor_exit);
259
260MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
261MODULE_DESCRIPTION("LM75 sensor objects for PowerMacs thermal control");
262MODULE_LICENSE("GPL");
263
diff --git a/drivers/macintosh/windfarm_pid.c b/drivers/macintosh/windfarm_pid.c
new file mode 100644
index 000000000000..2e803b368757
--- /dev/null
+++ b/drivers/macintosh/windfarm_pid.c
@@ -0,0 +1,145 @@
1/*
2 * Windfarm PowerMac thermal control. Generic PID helpers
3 *
4 * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp.
5 * <benh@kernel.crashing.org>
6 *
7 * Released under the term of the GNU GPL v2.
8 */
9
10#include <linux/types.h>
11#include <linux/errno.h>
12#include <linux/kernel.h>
13#include <linux/string.h>
14#include <linux/module.h>
15
16#include "windfarm_pid.h"
17
18#undef DEBUG
19
20#ifdef DEBUG
21#define DBG(args...) printk(args)
22#else
23#define DBG(args...) do { } while(0)
24#endif
25
26void wf_pid_init(struct wf_pid_state *st, struct wf_pid_param *param)
27{
28 memset(st, 0, sizeof(struct wf_pid_state));
29 st->param = *param;
30 st->first = 1;
31}
32EXPORT_SYMBOL_GPL(wf_pid_init);
33
34s32 wf_pid_run(struct wf_pid_state *st, s32 new_sample)
35{
36 s64 error, integ, deriv;
37 s32 target;
38 int i, hlen = st->param.history_len;
39
40 /* Calculate error term */
41 error = new_sample - st->param.itarget;
42
43 /* Get samples into our history buffer */
44 if (st->first) {
45 for (i = 0; i < hlen; i++) {
46 st->samples[i] = new_sample;
47 st->errors[i] = error;
48 }
49 st->first = 0;
50 st->index = 0;
51 } else {
52 st->index = (st->index + 1) % hlen;
53 st->samples[st->index] = new_sample;
54 st->errors[st->index] = error;
55 }
56
57 /* Calculate integral term */
58 for (i = 0, integ = 0; i < hlen; i++)
59 integ += st->errors[(st->index + hlen - i) % hlen];
60 integ *= st->param.interval;
61
62 /* Calculate derivative term */
63 deriv = st->errors[st->index] -
64 st->errors[(st->index + hlen - 1) % hlen];
65 deriv /= st->param.interval;
66
67 /* Calculate target */
68 target = (s32)((integ * (s64)st->param.gr + deriv * (s64)st->param.gd +
69 error * (s64)st->param.gp) >> 36);
70 if (st->param.additive)
71 target += st->target;
72 target = max(target, st->param.min);
73 target = min(target, st->param.max);
74 st->target = target;
75
76 return st->target;
77}
78EXPORT_SYMBOL_GPL(wf_pid_run);
79
80void wf_cpu_pid_init(struct wf_cpu_pid_state *st,
81 struct wf_cpu_pid_param *param)
82{
83 memset(st, 0, sizeof(struct wf_cpu_pid_state));
84 st->param = *param;
85 st->first = 1;
86}
87EXPORT_SYMBOL_GPL(wf_cpu_pid_init);
88
89s32 wf_cpu_pid_run(struct wf_cpu_pid_state *st, s32 new_power, s32 new_temp)
90{
91 s64 error, integ, deriv, prop;
92 s32 target, sval, adj;
93 int i, hlen = st->param.history_len;
94
95 /* Calculate error term */
96 error = st->param.pmaxadj - new_power;
97
98 /* Get samples into our history buffer */
99 if (st->first) {
100 for (i = 0; i < hlen; i++) {
101 st->powers[i] = new_power;
102 st->errors[i] = error;
103 }
104 st->temps[0] = st->temps[1] = new_temp;
105 st->first = 0;
106 st->index = st->tindex = 0;
107 } else {
108 st->index = (st->index + 1) % hlen;
109 st->powers[st->index] = new_power;
110 st->errors[st->index] = error;
111 st->tindex = (st->tindex + 1) % 2;
112 st->temps[st->tindex] = new_temp;
113 }
114
115 /* Calculate integral term */
116 for (i = 0, integ = 0; i < hlen; i++)
117 integ += st->errors[(st->index + hlen - i) % hlen];
118 integ *= st->param.interval;
119 integ *= st->param.gr;
120 sval = st->param.tmax - ((integ >> 20) & 0xffffffff);
121 adj = min(st->param.ttarget, sval);
122
123 DBG("integ: %lx, sval: %lx, adj: %lx\n", integ, sval, adj);
124
125 /* Calculate derivative term */
126 deriv = st->temps[st->tindex] -
127 st->temps[(st->tindex + 2 - 1) % 2];
128 deriv /= st->param.interval;
129 deriv *= st->param.gd;
130
131 /* Calculate proportional term */
132 prop = (new_temp - adj);
133 prop *= st->param.gp;
134
135 DBG("deriv: %lx, prop: %lx\n", deriv, prop);
136
137 /* Calculate target */
138 target = st->target + (s32)((deriv + prop) >> 36);
139 target = max(target, st->param.min);
140 target = min(target, st->param.max);
141 st->target = target;
142
143 return st->target;
144}
145EXPORT_SYMBOL_GPL(wf_cpu_pid_run);
diff --git a/drivers/macintosh/windfarm_pid.h b/drivers/macintosh/windfarm_pid.h
new file mode 100644
index 000000000000..a364c2a2499c
--- /dev/null
+++ b/drivers/macintosh/windfarm_pid.h
@@ -0,0 +1,84 @@
1/*
2 * Windfarm PowerMac thermal control. Generic PID helpers
3 *
4 * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp.
5 * <benh@kernel.crashing.org>
6 *
7 * Released under the term of the GNU GPL v2.
8 *
9 * This is a pair of generic PID helpers that can be used by
10 * control loops. One is the basic PID implementation, the
11 * other one is more specifically tailored to the loops used
12 * for CPU control with 2 input sample types (temp and power)
13 */
14
15/*
16 * *** Simple PID ***
17 */
18
19#define WF_PID_MAX_HISTORY 32
20
21/* This parameter array is passed to the PID algorithm. Currently,
22 * we don't support changing parameters on the fly as it's not needed
23 * but could be implemented (with necessary adjustment of the history
24 * buffer
25 */
26struct wf_pid_param {
27 int interval; /* Interval between samples in seconds */
28 int history_len; /* Size of history buffer */
29 int additive; /* 1: target relative to previous value */
30 s32 gd, gp, gr; /* PID gains */
31 s32 itarget; /* PID input target */
32 s32 min,max; /* min and max target values */
33};
34
35struct wf_pid_state {
36 int first; /* first run of the loop */
37 int index; /* index of current sample */
38 s32 target; /* current target value */
39 s32 samples[WF_PID_MAX_HISTORY]; /* samples history buffer */
40 s32 errors[WF_PID_MAX_HISTORY]; /* error history buffer */
41
42 struct wf_pid_param param;
43};
44
45extern void wf_pid_init(struct wf_pid_state *st, struct wf_pid_param *param);
46extern s32 wf_pid_run(struct wf_pid_state *st, s32 sample);
47
48
49/*
50 * *** CPU PID ***
51 */
52
53#define WF_CPU_PID_MAX_HISTORY 32
54
55/* This parameter array is passed to the CPU PID algorithm. Currently,
56 * we don't support changing parameters on the fly as it's not needed
57 * but could be implemented (with necessary adjustment of the history
58 * buffer
59 */
60struct wf_cpu_pid_param {
61 int interval; /* Interval between samples in seconds */
62 int history_len; /* Size of history buffer */
63 s32 gd, gp, gr; /* PID gains */
64 s32 pmaxadj; /* PID max power adjust */
65 s32 ttarget; /* PID input target */
66 s32 tmax; /* PID input max */
67 s32 min,max; /* min and max target values */
68};
69
70struct wf_cpu_pid_state {
71 int first; /* first run of the loop */
72 int index; /* index of current power */
73 int tindex; /* index of current temp */
74 s32 target; /* current target value */
75 s32 powers[WF_PID_MAX_HISTORY]; /* power history buffer */
76 s32 errors[WF_PID_MAX_HISTORY]; /* error history buffer */
77 s32 temps[2]; /* temp. history buffer */
78
79 struct wf_cpu_pid_param param;
80};
81
82extern void wf_cpu_pid_init(struct wf_cpu_pid_state *st,
83 struct wf_cpu_pid_param *param);
84extern s32 wf_cpu_pid_run(struct wf_cpu_pid_state *st, s32 power, s32 temp);
diff --git a/drivers/macintosh/windfarm_pm81.c b/drivers/macintosh/windfarm_pm81.c
new file mode 100644
index 000000000000..322c74b2687f
--- /dev/null
+++ b/drivers/macintosh/windfarm_pm81.c
@@ -0,0 +1,879 @@
1/*
2 * Windfarm PowerMac thermal control. iMac G5
3 *
4 * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp.
5 * <benh@kernel.crashing.org>
6 *
7 * Released under the term of the GNU GPL v2.
8 *
9 * The algorithm used is the PID control algorithm, used the same
10 * way the published Darwin code does, using the same values that
11 * are present in the Darwin 8.2 snapshot property lists (note however
12 * that none of the code has been re-used, it's a complete re-implementation
13 *
14 * The various control loops found in Darwin config file are:
15 *
16 * PowerMac8,1 and PowerMac8,2
17 * ===========================
18 *
19 * System Fans control loop. Different based on models. In addition to the
20 * usual PID algorithm, the control loop gets 2 additional pairs of linear
21 * scaling factors (scale/offsets) expressed as 4.12 fixed point values
22 * signed offset, unsigned scale)
23 *
24 * The targets are modified such as:
25 * - the linked control (second control) gets the target value as-is
26 * (typically the drive fan)
27 * - the main control (first control) gets the target value scaled with
28 * the first pair of factors, and is then modified as below
29 * - the value of the target of the CPU Fan control loop is retreived,
30 * scaled with the second pair of factors, and the max of that and
31 * the scaled target is applied to the main control.
32 *
33 * # model_id: 2
34 * controls : system-fan, drive-bay-fan
35 * sensors : hd-temp
36 * PID params : G_d = 0x15400000
37 * G_p = 0x00200000
38 * G_r = 0x000002fd
39 * History = 2 entries
40 * Input target = 0x3a0000
41 * Interval = 5s
42 * linear-factors : offset = 0xff38 scale = 0x0ccd
43 * offset = 0x0208 scale = 0x07ae
44 *
45 * # model_id: 3
46 * controls : system-fan, drive-bay-fan
47 * sensors : hd-temp
48 * PID params : G_d = 0x08e00000
49 * G_p = 0x00566666
50 * G_r = 0x0000072b
51 * History = 2 entries
52 * Input target = 0x350000
53 * Interval = 5s
54 * linear-factors : offset = 0xff38 scale = 0x0ccd
55 * offset = 0x0000 scale = 0x0000
56 *
57 * # model_id: 5
58 * controls : system-fan
59 * sensors : hd-temp
60 * PID params : G_d = 0x15400000
61 * G_p = 0x00233333
62 * G_r = 0x000002fd
63 * History = 2 entries
64 * Input target = 0x3a0000
65 * Interval = 5s
66 * linear-factors : offset = 0x0000 scale = 0x1000
67 * offset = 0x0091 scale = 0x0bae
68 *
69 * CPU Fan control loop. The loop is identical for all models. it
70 * has an additional pair of scaling factor. This is used to scale the
71 * systems fan control loop target result (the one before it gets scaled
72 * by the System Fans control loop itself). Then, the max value of the
73 * calculated target value and system fan value is sent to the fans
74 *
75 * controls : cpu-fan
76 * sensors : cpu-temp cpu-power
77 * PID params : From SMU sdb partition
78 * linear-factors : offset = 0xfb50 scale = 0x1000
79 *
80 * CPU Slew control loop. Not implemented. The cpufreq driver in linux is
81 * completely separate for now, though we could find a way to link it, either
82 * as a client reacting to overtemp notifications, or directling monitoring
83 * the CPU temperature
84 *
85 * WARNING ! The CPU control loop requires the CPU tmax for the current
86 * operating point. However, we currently are completely separated from
87 * the cpufreq driver and thus do not know what the current operating
88 * point is. Fortunately, we also do not have any hardware supporting anything
89 * but operating point 0 at the moment, thus we just peek that value directly
90 * from the SDB partition. If we ever end up with actually slewing the system
91 * clock and thus changing operating points, we'll have to find a way to
92 * communicate with the CPU freq driver;
93 *
94 */
95
96#include <linux/types.h>
97#include <linux/errno.h>
98#include <linux/kernel.h>
99#include <linux/delay.h>
100#include <linux/slab.h>
101#include <linux/init.h>
102#include <linux/spinlock.h>
103#include <linux/wait.h>
104#include <linux/kmod.h>
105#include <linux/device.h>
106#include <linux/platform_device.h>
107#include <asm/prom.h>
108#include <asm/machdep.h>
109#include <asm/io.h>
110#include <asm/system.h>
111#include <asm/sections.h>
112#include <asm/smu.h>
113
114#include "windfarm.h"
115#include "windfarm_pid.h"
116
117#define VERSION "0.4"
118
119#undef DEBUG
120
121#ifdef DEBUG
122#define DBG(args...) printk(args)
123#else
124#define DBG(args...) do { } while(0)
125#endif
126
127/* define this to force CPU overtemp to 74 degree, useful for testing
128 * the overtemp code
129 */
130#undef HACKED_OVERTEMP
131
132static int wf_smu_mach_model; /* machine model id */
133
134static struct device *wf_smu_dev;
135
136/* Controls & sensors */
137static struct wf_sensor *sensor_cpu_power;
138static struct wf_sensor *sensor_cpu_temp;
139static struct wf_sensor *sensor_hd_temp;
140static struct wf_control *fan_cpu_main;
141static struct wf_control *fan_hd;
142static struct wf_control *fan_system;
143static struct wf_control *cpufreq_clamp;
144
145/* Set to kick the control loop into life */
146static int wf_smu_all_controls_ok, wf_smu_all_sensors_ok, wf_smu_started;
147
148/* Failure handling.. could be nicer */
149#define FAILURE_FAN 0x01
150#define FAILURE_SENSOR 0x02
151#define FAILURE_OVERTEMP 0x04
152
153static unsigned int wf_smu_failure_state;
154static int wf_smu_readjust, wf_smu_skipping;
155
156/*
157 * ****** System Fans Control Loop ******
158 *
159 */
160
161/* Parameters for the System Fans control loop. Parameters
162 * not in this table such as interval, history size, ...
163 * are common to all versions and thus hard coded for now.
164 */
165struct wf_smu_sys_fans_param {
166 int model_id;
167 s32 itarget;
168 s32 gd, gp, gr;
169
170 s16 offset0;
171 u16 scale0;
172 s16 offset1;
173 u16 scale1;
174};
175
176#define WF_SMU_SYS_FANS_INTERVAL 5
177#define WF_SMU_SYS_FANS_HISTORY_SIZE 2
178
179/* State data used by the system fans control loop
180 */
181struct wf_smu_sys_fans_state {
182 int ticks;
183 s32 sys_setpoint;
184 s32 hd_setpoint;
185 s16 offset0;
186 u16 scale0;
187 s16 offset1;
188 u16 scale1;
189 struct wf_pid_state pid;
190};
191
192/*
193 * Configs for SMU Sytem Fan control loop
194 */
195static struct wf_smu_sys_fans_param wf_smu_sys_all_params[] = {
196 /* Model ID 2 */
197 {
198 .model_id = 2,
199 .itarget = 0x3a0000,
200 .gd = 0x15400000,
201 .gp = 0x00200000,
202 .gr = 0x000002fd,
203 .offset0 = 0xff38,
204 .scale0 = 0x0ccd,
205 .offset1 = 0x0208,
206 .scale1 = 0x07ae,
207 },
208 /* Model ID 3 */
209 {
210 .model_id = 2,
211 .itarget = 0x350000,
212 .gd = 0x08e00000,
213 .gp = 0x00566666,
214 .gr = 0x0000072b,
215 .offset0 = 0xff38,
216 .scale0 = 0x0ccd,
217 .offset1 = 0x0000,
218 .scale1 = 0x0000,
219 },
220 /* Model ID 5 */
221 {
222 .model_id = 2,
223 .itarget = 0x3a0000,
224 .gd = 0x15400000,
225 .gp = 0x00233333,
226 .gr = 0x000002fd,
227 .offset0 = 0x0000,
228 .scale0 = 0x1000,
229 .offset1 = 0x0091,
230 .scale1 = 0x0bae,
231 },
232};
233#define WF_SMU_SYS_FANS_NUM_CONFIGS ARRAY_SIZE(wf_smu_sys_all_params)
234
235static struct wf_smu_sys_fans_state *wf_smu_sys_fans;
236
237/*
238 * ****** CPU Fans Control Loop ******
239 *
240 */
241
242
243#define WF_SMU_CPU_FANS_INTERVAL 1
244#define WF_SMU_CPU_FANS_MAX_HISTORY 16
245#define WF_SMU_CPU_FANS_SIBLING_SCALE 0x00001000
246#define WF_SMU_CPU_FANS_SIBLING_OFFSET 0xfffffb50
247
248/* State data used by the cpu fans control loop
249 */
250struct wf_smu_cpu_fans_state {
251 int ticks;
252 s32 cpu_setpoint;
253 s32 scale;
254 s32 offset;
255 struct wf_cpu_pid_state pid;
256};
257
258static struct wf_smu_cpu_fans_state *wf_smu_cpu_fans;
259
260
261
262/*
263 * ***** Implementation *****
264 *
265 */
266
267static void wf_smu_create_sys_fans(void)
268{
269 struct wf_smu_sys_fans_param *param = NULL;
270 struct wf_pid_param pid_param;
271 int i;
272
273 /* First, locate the params for this model */
274 for (i = 0; i < WF_SMU_SYS_FANS_NUM_CONFIGS; i++)
275 if (wf_smu_sys_all_params[i].model_id == wf_smu_mach_model) {
276 param = &wf_smu_sys_all_params[i];
277 break;
278 }
279
280 /* No params found, put fans to max */
281 if (param == NULL) {
282 printk(KERN_WARNING "windfarm: System fan config not found "
283 "for this machine model, max fan speed\n");
284 goto fail;
285 }
286
287 /* Alloc & initialize state */
288 wf_smu_sys_fans = kmalloc(sizeof(struct wf_smu_sys_fans_state),
289 GFP_KERNEL);
290 if (wf_smu_sys_fans == NULL) {
291 printk(KERN_WARNING "windfarm: Memory allocation error"
292 " max fan speed\n");
293 goto fail;
294 }
295 wf_smu_sys_fans->ticks = 1;
296 wf_smu_sys_fans->scale0 = param->scale0;
297 wf_smu_sys_fans->offset0 = param->offset0;
298 wf_smu_sys_fans->scale1 = param->scale1;
299 wf_smu_sys_fans->offset1 = param->offset1;
300
301 /* Fill PID params */
302 pid_param.gd = param->gd;
303 pid_param.gp = param->gp;
304 pid_param.gr = param->gr;
305 pid_param.interval = WF_SMU_SYS_FANS_INTERVAL;
306 pid_param.history_len = WF_SMU_SYS_FANS_HISTORY_SIZE;
307 pid_param.itarget = param->itarget;
308 pid_param.min = fan_system->ops->get_min(fan_system);
309 pid_param.max = fan_system->ops->get_max(fan_system);
310 if (fan_hd) {
311 pid_param.min =
312 max(pid_param.min,fan_hd->ops->get_min(fan_hd));
313 pid_param.max =
314 min(pid_param.max,fan_hd->ops->get_max(fan_hd));
315 }
316 wf_pid_init(&wf_smu_sys_fans->pid, &pid_param);
317
318 DBG("wf: System Fan control initialized.\n");
319 DBG(" itarged=%d.%03d, min=%d RPM, max=%d RPM\n",
320 FIX32TOPRINT(pid_param.itarget), pid_param.min, pid_param.max);
321 return;
322
323 fail:
324
325 if (fan_system)
326 wf_control_set_max(fan_system);
327 if (fan_hd)
328 wf_control_set_max(fan_hd);
329}
330
331static void wf_smu_sys_fans_tick(struct wf_smu_sys_fans_state *st)
332{
333 s32 new_setpoint, temp, scaled, cputarget;
334 int rc;
335
336 if (--st->ticks != 0) {
337 if (wf_smu_readjust)
338 goto readjust;
339 return;
340 }
341 st->ticks = WF_SMU_SYS_FANS_INTERVAL;
342
343 rc = sensor_hd_temp->ops->get_value(sensor_hd_temp, &temp);
344 if (rc) {
345 printk(KERN_WARNING "windfarm: HD temp sensor error %d\n",
346 rc);
347 wf_smu_failure_state |= FAILURE_SENSOR;
348 return;
349 }
350
351 DBG("wf_smu: System Fans tick ! HD temp: %d.%03d\n",
352 FIX32TOPRINT(temp));
353
354 if (temp > (st->pid.param.itarget + 0x50000))
355 wf_smu_failure_state |= FAILURE_OVERTEMP;
356
357 new_setpoint = wf_pid_run(&st->pid, temp);
358
359 DBG("wf_smu: new_setpoint: %d RPM\n", (int)new_setpoint);
360
361 scaled = ((((s64)new_setpoint) * (s64)st->scale0) >> 12) + st->offset0;
362
363 DBG("wf_smu: scaled setpoint: %d RPM\n", (int)scaled);
364
365 cputarget = wf_smu_cpu_fans ? wf_smu_cpu_fans->pid.target : 0;
366 cputarget = ((((s64)cputarget) * (s64)st->scale1) >> 12) + st->offset1;
367 scaled = max(scaled, cputarget);
368 scaled = max(scaled, st->pid.param.min);
369 scaled = min(scaled, st->pid.param.max);
370
371 DBG("wf_smu: adjusted setpoint: %d RPM\n", (int)scaled);
372
373 if (st->sys_setpoint == scaled && new_setpoint == st->hd_setpoint)
374 return;
375 st->sys_setpoint = scaled;
376 st->hd_setpoint = new_setpoint;
377 readjust:
378 if (fan_system && wf_smu_failure_state == 0) {
379 rc = fan_system->ops->set_value(fan_system, st->sys_setpoint);
380 if (rc) {
381 printk(KERN_WARNING "windfarm: Sys fan error %d\n",
382 rc);
383 wf_smu_failure_state |= FAILURE_FAN;
384 }
385 }
386 if (fan_hd && wf_smu_failure_state == 0) {
387 rc = fan_hd->ops->set_value(fan_hd, st->hd_setpoint);
388 if (rc) {
389 printk(KERN_WARNING "windfarm: HD fan error %d\n",
390 rc);
391 wf_smu_failure_state |= FAILURE_FAN;
392 }
393 }
394}
395
396static void wf_smu_create_cpu_fans(void)
397{
398 struct wf_cpu_pid_param pid_param;
399 struct smu_sdbp_header *hdr;
400 struct smu_sdbp_cpupiddata *piddata;
401 struct smu_sdbp_fvt *fvt;
402 s32 tmax, tdelta, maxpow, powadj;
403
404 /* First, locate the PID params in SMU SBD */
405 hdr = smu_get_sdb_partition(SMU_SDB_CPUPIDDATA_ID, NULL);
406 if (hdr == 0) {
407 printk(KERN_WARNING "windfarm: CPU PID fan config not found "
408 "max fan speed\n");
409 goto fail;
410 }
411 piddata = (struct smu_sdbp_cpupiddata *)&hdr[1];
412
413 /* Get the FVT params for operating point 0 (the only supported one
414 * for now) in order to get tmax
415 */
416 hdr = smu_get_sdb_partition(SMU_SDB_FVT_ID, NULL);
417 if (hdr) {
418 fvt = (struct smu_sdbp_fvt *)&hdr[1];
419 tmax = ((s32)fvt->maxtemp) << 16;
420 } else
421 tmax = 0x5e0000; /* 94 degree default */
422
423 /* Alloc & initialize state */
424 wf_smu_cpu_fans = kmalloc(sizeof(struct wf_smu_cpu_fans_state),
425 GFP_KERNEL);
426 if (wf_smu_cpu_fans == NULL)
427 goto fail;
428 wf_smu_cpu_fans->ticks = 1;
429
430 wf_smu_cpu_fans->scale = WF_SMU_CPU_FANS_SIBLING_SCALE;
431 wf_smu_cpu_fans->offset = WF_SMU_CPU_FANS_SIBLING_OFFSET;
432
433 /* Fill PID params */
434 pid_param.interval = WF_SMU_CPU_FANS_INTERVAL;
435 pid_param.history_len = piddata->history_len;
436 if (pid_param.history_len > WF_CPU_PID_MAX_HISTORY) {
437 printk(KERN_WARNING "windfarm: History size overflow on "
438 "CPU control loop (%d)\n", piddata->history_len);
439 pid_param.history_len = WF_CPU_PID_MAX_HISTORY;
440 }
441 pid_param.gd = piddata->gd;
442 pid_param.gp = piddata->gp;
443 pid_param.gr = piddata->gr / pid_param.history_len;
444
445 tdelta = ((s32)piddata->target_temp_delta) << 16;
446 maxpow = ((s32)piddata->max_power) << 16;
447 powadj = ((s32)piddata->power_adj) << 16;
448
449 pid_param.tmax = tmax;
450 pid_param.ttarget = tmax - tdelta;
451 pid_param.pmaxadj = maxpow - powadj;
452
453 pid_param.min = fan_cpu_main->ops->get_min(fan_cpu_main);
454 pid_param.max = fan_cpu_main->ops->get_max(fan_cpu_main);
455
456 wf_cpu_pid_init(&wf_smu_cpu_fans->pid, &pid_param);
457
458 DBG("wf: CPU Fan control initialized.\n");
459 DBG(" ttarged=%d.%03d, tmax=%d.%03d, min=%d RPM, max=%d RPM\n",
460 FIX32TOPRINT(pid_param.ttarget), FIX32TOPRINT(pid_param.tmax),
461 pid_param.min, pid_param.max);
462
463 return;
464
465 fail:
466 printk(KERN_WARNING "windfarm: CPU fan config not found\n"
467 "for this machine model, max fan speed\n");
468
469 if (cpufreq_clamp)
470 wf_control_set_max(cpufreq_clamp);
471 if (fan_cpu_main)
472 wf_control_set_max(fan_cpu_main);
473}
474
475static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st)
476{
477 s32 new_setpoint, temp, power, systarget;
478 int rc;
479
480 if (--st->ticks != 0) {
481 if (wf_smu_readjust)
482 goto readjust;
483 return;
484 }
485 st->ticks = WF_SMU_CPU_FANS_INTERVAL;
486
487 rc = sensor_cpu_temp->ops->get_value(sensor_cpu_temp, &temp);
488 if (rc) {
489 printk(KERN_WARNING "windfarm: CPU temp sensor error %d\n",
490 rc);
491 wf_smu_failure_state |= FAILURE_SENSOR;
492 return;
493 }
494
495 rc = sensor_cpu_power->ops->get_value(sensor_cpu_power, &power);
496 if (rc) {
497 printk(KERN_WARNING "windfarm: CPU power sensor error %d\n",
498 rc);
499 wf_smu_failure_state |= FAILURE_SENSOR;
500 return;
501 }
502
503 DBG("wf_smu: CPU Fans tick ! CPU temp: %d.%03d, power: %d.%03d\n",
504 FIX32TOPRINT(temp), FIX32TOPRINT(power));
505
506#ifdef HACKED_OVERTEMP
507 if (temp > 0x4a0000)
508 wf_smu_failure_state |= FAILURE_OVERTEMP;
509#else
510 if (temp > st->pid.param.tmax)
511 wf_smu_failure_state |= FAILURE_OVERTEMP;
512#endif
513 new_setpoint = wf_cpu_pid_run(&st->pid, power, temp);
514
515 DBG("wf_smu: new_setpoint: %d RPM\n", (int)new_setpoint);
516
517 systarget = wf_smu_sys_fans ? wf_smu_sys_fans->pid.target : 0;
518 systarget = ((((s64)systarget) * (s64)st->scale) >> 12)
519 + st->offset;
520 new_setpoint = max(new_setpoint, systarget);
521 new_setpoint = max(new_setpoint, st->pid.param.min);
522 new_setpoint = min(new_setpoint, st->pid.param.max);
523
524 DBG("wf_smu: adjusted setpoint: %d RPM\n", (int)new_setpoint);
525
526 if (st->cpu_setpoint == new_setpoint)
527 return;
528 st->cpu_setpoint = new_setpoint;
529 readjust:
530 if (fan_cpu_main && wf_smu_failure_state == 0) {
531 rc = fan_cpu_main->ops->set_value(fan_cpu_main,
532 st->cpu_setpoint);
533 if (rc) {
534 printk(KERN_WARNING "windfarm: CPU main fan"
535 " error %d\n", rc);
536 wf_smu_failure_state |= FAILURE_FAN;
537 }
538 }
539}
540
541
542/*
543 * ****** Attributes ******
544 *
545 */
546
547#define BUILD_SHOW_FUNC_FIX(name, data) \
548static ssize_t show_##name(struct device *dev, \
549 struct device_attribute *attr, \
550 char *buf) \
551{ \
552 ssize_t r; \
553 s32 val = 0; \
554 data->ops->get_value(data, &val); \
555 r = sprintf(buf, "%d.%03d", FIX32TOPRINT(val)); \
556 return r; \
557} \
558static DEVICE_ATTR(name,S_IRUGO,show_##name, NULL);
559
560
561#define BUILD_SHOW_FUNC_INT(name, data) \
562static ssize_t show_##name(struct device *dev, \
563 struct device_attribute *attr, \
564 char *buf) \
565{ \
566 s32 val = 0; \
567 data->ops->get_value(data, &val); \
568 return sprintf(buf, "%d", val); \
569} \
570static DEVICE_ATTR(name,S_IRUGO,show_##name, NULL);
571
572BUILD_SHOW_FUNC_INT(cpu_fan, fan_cpu_main);
573BUILD_SHOW_FUNC_INT(sys_fan, fan_system);
574BUILD_SHOW_FUNC_INT(hd_fan, fan_hd);
575
576BUILD_SHOW_FUNC_FIX(cpu_temp, sensor_cpu_temp);
577BUILD_SHOW_FUNC_FIX(cpu_power, sensor_cpu_power);
578BUILD_SHOW_FUNC_FIX(hd_temp, sensor_hd_temp);
579
580/*
581 * ****** Setup / Init / Misc ... ******
582 *
583 */
584
585static void wf_smu_tick(void)
586{
587 unsigned int last_failure = wf_smu_failure_state;
588 unsigned int new_failure;
589
590 if (!wf_smu_started) {
591 DBG("wf: creating control loops !\n");
592 wf_smu_create_sys_fans();
593 wf_smu_create_cpu_fans();
594 wf_smu_started = 1;
595 }
596
597 /* Skipping ticks */
598 if (wf_smu_skipping && --wf_smu_skipping)
599 return;
600
601 wf_smu_failure_state = 0;
602 if (wf_smu_sys_fans)
603 wf_smu_sys_fans_tick(wf_smu_sys_fans);
604 if (wf_smu_cpu_fans)
605 wf_smu_cpu_fans_tick(wf_smu_cpu_fans);
606
607 wf_smu_readjust = 0;
608 new_failure = wf_smu_failure_state & ~last_failure;
609
610 /* If entering failure mode, clamp cpufreq and ramp all
611 * fans to full speed.
612 */
613 if (wf_smu_failure_state && !last_failure) {
614 if (cpufreq_clamp)
615 wf_control_set_max(cpufreq_clamp);
616 if (fan_system)
617 wf_control_set_max(fan_system);
618 if (fan_cpu_main)
619 wf_control_set_max(fan_cpu_main);
620 if (fan_hd)
621 wf_control_set_max(fan_hd);
622 }
623
624 /* If leaving failure mode, unclamp cpufreq and readjust
625 * all fans on next iteration
626 */
627 if (!wf_smu_failure_state && last_failure) {
628 if (cpufreq_clamp)
629 wf_control_set_min(cpufreq_clamp);
630 wf_smu_readjust = 1;
631 }
632
633 /* Overtemp condition detected, notify and start skipping a couple
634 * ticks to let the temperature go down
635 */
636 if (new_failure & FAILURE_OVERTEMP) {
637 wf_set_overtemp();
638 wf_smu_skipping = 2;
639 }
640
641 /* We only clear the overtemp condition if overtemp is cleared
642 * _and_ no other failure is present. Since a sensor error will
643 * clear the overtemp condition (can't measure temperature) at
644 * the control loop levels, but we don't want to keep it clear
645 * here in this case
646 */
647 if (new_failure == 0 && last_failure & FAILURE_OVERTEMP)
648 wf_clear_overtemp();
649}
650
651static void wf_smu_new_control(struct wf_control *ct)
652{
653 if (wf_smu_all_controls_ok)
654 return;
655
656 if (fan_cpu_main == NULL && !strcmp(ct->name, "cpu-fan")) {
657 if (wf_get_control(ct) == 0) {
658 fan_cpu_main = ct;
659 device_create_file(wf_smu_dev, &dev_attr_cpu_fan);
660 }
661 }
662
663 if (fan_system == NULL && !strcmp(ct->name, "system-fan")) {
664 if (wf_get_control(ct) == 0) {
665 fan_system = ct;
666 device_create_file(wf_smu_dev, &dev_attr_sys_fan);
667 }
668 }
669
670 if (cpufreq_clamp == NULL && !strcmp(ct->name, "cpufreq-clamp")) {
671 if (wf_get_control(ct) == 0)
672 cpufreq_clamp = ct;
673 }
674
675 /* Darwin property list says the HD fan is only for model ID
676 * 0, 1, 2 and 3
677 */
678
679 if (wf_smu_mach_model > 3) {
680 if (fan_system && fan_cpu_main && cpufreq_clamp)
681 wf_smu_all_controls_ok = 1;
682 return;
683 }
684
685 if (fan_hd == NULL && !strcmp(ct->name, "drive-bay-fan")) {
686 if (wf_get_control(ct) == 0) {
687 fan_hd = ct;
688 device_create_file(wf_smu_dev, &dev_attr_hd_fan);
689 }
690 }
691
692 if (fan_system && fan_hd && fan_cpu_main && cpufreq_clamp)
693 wf_smu_all_controls_ok = 1;
694}
695
696static void wf_smu_new_sensor(struct wf_sensor *sr)
697{
698 if (wf_smu_all_sensors_ok)
699 return;
700
701 if (sensor_cpu_power == NULL && !strcmp(sr->name, "cpu-power")) {
702 if (wf_get_sensor(sr) == 0) {
703 sensor_cpu_power = sr;
704 device_create_file(wf_smu_dev, &dev_attr_cpu_power);
705 }
706 }
707
708 if (sensor_cpu_temp == NULL && !strcmp(sr->name, "cpu-temp")) {
709 if (wf_get_sensor(sr) == 0) {
710 sensor_cpu_temp = sr;
711 device_create_file(wf_smu_dev, &dev_attr_cpu_temp);
712 }
713 }
714
715 if (sensor_hd_temp == NULL && !strcmp(sr->name, "hd-temp")) {
716 if (wf_get_sensor(sr) == 0) {
717 sensor_hd_temp = sr;
718 device_create_file(wf_smu_dev, &dev_attr_hd_temp);
719 }
720 }
721
722 if (sensor_cpu_power && sensor_cpu_temp && sensor_hd_temp)
723 wf_smu_all_sensors_ok = 1;
724}
725
726
727static int wf_smu_notify(struct notifier_block *self,
728 unsigned long event, void *data)
729{
730 switch(event) {
731 case WF_EVENT_NEW_CONTROL:
732 DBG("wf: new control %s detected\n",
733 ((struct wf_control *)data)->name);
734 wf_smu_new_control(data);
735 wf_smu_readjust = 1;
736 break;
737 case WF_EVENT_NEW_SENSOR:
738 DBG("wf: new sensor %s detected\n",
739 ((struct wf_sensor *)data)->name);
740 wf_smu_new_sensor(data);
741 break;
742 case WF_EVENT_TICK:
743 if (wf_smu_all_controls_ok && wf_smu_all_sensors_ok)
744 wf_smu_tick();
745 }
746
747 return 0;
748}
749
750static struct notifier_block wf_smu_events = {
751 .notifier_call = wf_smu_notify,
752};
753
754static int wf_init_pm(void)
755{
756 struct smu_sdbp_header *hdr;
757
758 hdr = smu_get_sdb_partition(SMU_SDB_SENSORTREE_ID, NULL);
759 if (hdr != 0) {
760 struct smu_sdbp_sensortree *st =
761 (struct smu_sdbp_sensortree *)&hdr[1];
762 wf_smu_mach_model = st->model_id;
763 }
764
765 printk(KERN_INFO "windfarm: Initializing for iMacG5 model ID %d\n",
766 wf_smu_mach_model);
767
768 return 0;
769}
770
771static int wf_smu_probe(struct device *ddev)
772{
773 wf_smu_dev = ddev;
774
775 wf_register_client(&wf_smu_events);
776
777 return 0;
778}
779
780static int wf_smu_remove(struct device *ddev)
781{
782 wf_unregister_client(&wf_smu_events);
783
784 /* XXX We don't have yet a guarantee that our callback isn't
785 * in progress when returning from wf_unregister_client, so
786 * we add an arbitrary delay. I'll have to fix that in the core
787 */
788 msleep(1000);
789
790 /* Release all sensors */
791 /* One more crappy race: I don't think we have any guarantee here
792 * that the attribute callback won't race with the sensor beeing
793 * disposed of, and I'm not 100% certain what best way to deal
794 * with that except by adding locks all over... I'll do that
795 * eventually but heh, who ever rmmod this module anyway ?
796 */
797 if (sensor_cpu_power) {
798 device_remove_file(wf_smu_dev, &dev_attr_cpu_power);
799 wf_put_sensor(sensor_cpu_power);
800 }
801 if (sensor_cpu_temp) {
802 device_remove_file(wf_smu_dev, &dev_attr_cpu_temp);
803 wf_put_sensor(sensor_cpu_temp);
804 }
805 if (sensor_hd_temp) {
806 device_remove_file(wf_smu_dev, &dev_attr_hd_temp);
807 wf_put_sensor(sensor_hd_temp);
808 }
809
810 /* Release all controls */
811 if (fan_cpu_main) {
812 device_remove_file(wf_smu_dev, &dev_attr_cpu_fan);
813 wf_put_control(fan_cpu_main);
814 }
815 if (fan_hd) {
816 device_remove_file(wf_smu_dev, &dev_attr_hd_fan);
817 wf_put_control(fan_hd);
818 }
819 if (fan_system) {
820 device_remove_file(wf_smu_dev, &dev_attr_sys_fan);
821 wf_put_control(fan_system);
822 }
823 if (cpufreq_clamp)
824 wf_put_control(cpufreq_clamp);
825
826 /* Destroy control loops state structures */
827 if (wf_smu_sys_fans)
828 kfree(wf_smu_sys_fans);
829 if (wf_smu_cpu_fans)
830 kfree(wf_smu_cpu_fans);
831
832 wf_smu_dev = NULL;
833
834 return 0;
835}
836
837static struct device_driver wf_smu_driver = {
838 .name = "windfarm",
839 .bus = &platform_bus_type,
840 .probe = wf_smu_probe,
841 .remove = wf_smu_remove,
842};
843
844
845static int __init wf_smu_init(void)
846{
847 int rc = -ENODEV;
848
849 if (machine_is_compatible("PowerMac8,1") ||
850 machine_is_compatible("PowerMac8,2"))
851 rc = wf_init_pm();
852
853 if (rc == 0) {
854#ifdef MODULE
855 request_module("windfarm_smu_controls");
856 request_module("windfarm_smu_sensors");
857 request_module("windfarm_lm75_sensor");
858
859#endif /* MODULE */
860 driver_register(&wf_smu_driver);
861 }
862
863 return rc;
864}
865
866static void __exit wf_smu_exit(void)
867{
868
869 driver_unregister(&wf_smu_driver);
870}
871
872
873module_init(wf_smu_init);
874module_exit(wf_smu_exit);
875
876MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
877MODULE_DESCRIPTION("Thermal control logic for iMac G5");
878MODULE_LICENSE("GPL");
879
diff --git a/drivers/macintosh/windfarm_pm91.c b/drivers/macintosh/windfarm_pm91.c
new file mode 100644
index 000000000000..43243cf7410b
--- /dev/null
+++ b/drivers/macintosh/windfarm_pm91.c
@@ -0,0 +1,814 @@
1/*
2 * Windfarm PowerMac thermal control. SMU based 1 CPU desktop control loops
3 *
4 * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp.
5 * <benh@kernel.crashing.org>
6 *
7 * Released under the term of the GNU GPL v2.
8 *
9 * The algorithm used is the PID control algorithm, used the same
10 * way the published Darwin code does, using the same values that
11 * are present in the Darwin 8.2 snapshot property lists (note however
12 * that none of the code has been re-used, it's a complete re-implementation
13 *
14 * The various control loops found in Darwin config file are:
15 *
16 * PowerMac9,1
17 * ===========
18 *
19 * Has 3 control loops: CPU fans is similar to PowerMac8,1 (though it doesn't
20 * try to play with other control loops fans). Drive bay is rather basic PID
21 * with one sensor and one fan. Slots area is a bit different as the Darwin
22 * driver is supposed to be capable of working in a special "AGP" mode which
23 * involves the presence of an AGP sensor and an AGP fan (possibly on the
24 * AGP card itself). I can't deal with that special mode as I don't have
25 * access to those additional sensor/fans for now (though ultimately, it would
26 * be possible to add sensor objects for them) so I'm only implementing the
27 * basic PCI slot control loop
28 */
29
30#include <linux/types.h>
31#include <linux/errno.h>
32#include <linux/kernel.h>
33#include <linux/delay.h>
34#include <linux/slab.h>
35#include <linux/init.h>
36#include <linux/spinlock.h>
37#include <linux/wait.h>
38#include <linux/kmod.h>
39#include <linux/device.h>
40#include <linux/platform_device.h>
41#include <asm/prom.h>
42#include <asm/machdep.h>
43#include <asm/io.h>
44#include <asm/system.h>
45#include <asm/sections.h>
46#include <asm/smu.h>
47
48#include "windfarm.h"
49#include "windfarm_pid.h"
50
51#define VERSION "0.4"
52
53#undef DEBUG
54
55#ifdef DEBUG
56#define DBG(args...) printk(args)
57#else
58#define DBG(args...) do { } while(0)
59#endif
60
61/* define this to force CPU overtemp to 74 degree, useful for testing
62 * the overtemp code
63 */
64#undef HACKED_OVERTEMP
65
66static struct device *wf_smu_dev;
67
68/* Controls & sensors */
69static struct wf_sensor *sensor_cpu_power;
70static struct wf_sensor *sensor_cpu_temp;
71static struct wf_sensor *sensor_hd_temp;
72static struct wf_sensor *sensor_slots_power;
73static struct wf_control *fan_cpu_main;
74static struct wf_control *fan_cpu_second;
75static struct wf_control *fan_cpu_third;
76static struct wf_control *fan_hd;
77static struct wf_control *fan_slots;
78static struct wf_control *cpufreq_clamp;
79
80/* Set to kick the control loop into life */
81static int wf_smu_all_controls_ok, wf_smu_all_sensors_ok, wf_smu_started;
82
83/* Failure handling.. could be nicer */
84#define FAILURE_FAN 0x01
85#define FAILURE_SENSOR 0x02
86#define FAILURE_OVERTEMP 0x04
87
88static unsigned int wf_smu_failure_state;
89static int wf_smu_readjust, wf_smu_skipping;
90
91/*
92 * ****** CPU Fans Control Loop ******
93 *
94 */
95
96
97#define WF_SMU_CPU_FANS_INTERVAL 1
98#define WF_SMU_CPU_FANS_MAX_HISTORY 16
99
100/* State data used by the cpu fans control loop
101 */
102struct wf_smu_cpu_fans_state {
103 int ticks;
104 s32 cpu_setpoint;
105 struct wf_cpu_pid_state pid;
106};
107
108static struct wf_smu_cpu_fans_state *wf_smu_cpu_fans;
109
110
111
112/*
113 * ****** Drive Fan Control Loop ******
114 *
115 */
116
117struct wf_smu_drive_fans_state {
118 int ticks;
119 s32 setpoint;
120 struct wf_pid_state pid;
121};
122
123static struct wf_smu_drive_fans_state *wf_smu_drive_fans;
124
125/*
126 * ****** Slots Fan Control Loop ******
127 *
128 */
129
130struct wf_smu_slots_fans_state {
131 int ticks;
132 s32 setpoint;
133 struct wf_pid_state pid;
134};
135
136static struct wf_smu_slots_fans_state *wf_smu_slots_fans;
137
138/*
139 * ***** Implementation *****
140 *
141 */
142
143
144static void wf_smu_create_cpu_fans(void)
145{
146 struct wf_cpu_pid_param pid_param;
147 struct smu_sdbp_header *hdr;
148 struct smu_sdbp_cpupiddata *piddata;
149 struct smu_sdbp_fvt *fvt;
150 s32 tmax, tdelta, maxpow, powadj;
151
152 /* First, locate the PID params in SMU SBD */
153 hdr = smu_get_sdb_partition(SMU_SDB_CPUPIDDATA_ID, NULL);
154 if (hdr == 0) {
155 printk(KERN_WARNING "windfarm: CPU PID fan config not found "
156 "max fan speed\n");
157 goto fail;
158 }
159 piddata = (struct smu_sdbp_cpupiddata *)&hdr[1];
160
161 /* Get the FVT params for operating point 0 (the only supported one
162 * for now) in order to get tmax
163 */
164 hdr = smu_get_sdb_partition(SMU_SDB_FVT_ID, NULL);
165 if (hdr) {
166 fvt = (struct smu_sdbp_fvt *)&hdr[1];
167 tmax = ((s32)fvt->maxtemp) << 16;
168 } else
169 tmax = 0x5e0000; /* 94 degree default */
170
171 /* Alloc & initialize state */
172 wf_smu_cpu_fans = kmalloc(sizeof(struct wf_smu_cpu_fans_state),
173 GFP_KERNEL);
174 if (wf_smu_cpu_fans == NULL)
175 goto fail;
176 wf_smu_cpu_fans->ticks = 1;
177
178 /* Fill PID params */
179 pid_param.interval = WF_SMU_CPU_FANS_INTERVAL;
180 pid_param.history_len = piddata->history_len;
181 if (pid_param.history_len > WF_CPU_PID_MAX_HISTORY) {
182 printk(KERN_WARNING "windfarm: History size overflow on "
183 "CPU control loop (%d)\n", piddata->history_len);
184 pid_param.history_len = WF_CPU_PID_MAX_HISTORY;
185 }
186 pid_param.gd = piddata->gd;
187 pid_param.gp = piddata->gp;
188 pid_param.gr = piddata->gr / pid_param.history_len;
189
190 tdelta = ((s32)piddata->target_temp_delta) << 16;
191 maxpow = ((s32)piddata->max_power) << 16;
192 powadj = ((s32)piddata->power_adj) << 16;
193
194 pid_param.tmax = tmax;
195 pid_param.ttarget = tmax - tdelta;
196 pid_param.pmaxadj = maxpow - powadj;
197
198 pid_param.min = fan_cpu_main->ops->get_min(fan_cpu_main);
199 pid_param.max = fan_cpu_main->ops->get_max(fan_cpu_main);
200
201 wf_cpu_pid_init(&wf_smu_cpu_fans->pid, &pid_param);
202
203 DBG("wf: CPU Fan control initialized.\n");
204 DBG(" ttarged=%d.%03d, tmax=%d.%03d, min=%d RPM, max=%d RPM\n",
205 FIX32TOPRINT(pid_param.ttarget), FIX32TOPRINT(pid_param.tmax),
206 pid_param.min, pid_param.max);
207
208 return;
209
210 fail:
211 printk(KERN_WARNING "windfarm: CPU fan config not found\n"
212 "for this machine model, max fan speed\n");
213
214 if (cpufreq_clamp)
215 wf_control_set_max(cpufreq_clamp);
216 if (fan_cpu_main)
217 wf_control_set_max(fan_cpu_main);
218}
219
220static void wf_smu_cpu_fans_tick(struct wf_smu_cpu_fans_state *st)
221{
222 s32 new_setpoint, temp, power;
223 int rc;
224
225 if (--st->ticks != 0) {
226 if (wf_smu_readjust)
227 goto readjust;
228 return;
229 }
230 st->ticks = WF_SMU_CPU_FANS_INTERVAL;
231
232 rc = sensor_cpu_temp->ops->get_value(sensor_cpu_temp, &temp);
233 if (rc) {
234 printk(KERN_WARNING "windfarm: CPU temp sensor error %d\n",
235 rc);
236 wf_smu_failure_state |= FAILURE_SENSOR;
237 return;
238 }
239
240 rc = sensor_cpu_power->ops->get_value(sensor_cpu_power, &power);
241 if (rc) {
242 printk(KERN_WARNING "windfarm: CPU power sensor error %d\n",
243 rc);
244 wf_smu_failure_state |= FAILURE_SENSOR;
245 return;
246 }
247
248 DBG("wf_smu: CPU Fans tick ! CPU temp: %d.%03d, power: %d.%03d\n",
249 FIX32TOPRINT(temp), FIX32TOPRINT(power));
250
251#ifdef HACKED_OVERTEMP
252 if (temp > 0x4a0000)
253 wf_smu_failure_state |= FAILURE_OVERTEMP;
254#else
255 if (temp > st->pid.param.tmax)
256 wf_smu_failure_state |= FAILURE_OVERTEMP;
257#endif
258 new_setpoint = wf_cpu_pid_run(&st->pid, power, temp);
259
260 DBG("wf_smu: new_setpoint: %d RPM\n", (int)new_setpoint);
261
262 if (st->cpu_setpoint == new_setpoint)
263 return;
264 st->cpu_setpoint = new_setpoint;
265 readjust:
266 if (fan_cpu_main && wf_smu_failure_state == 0) {
267 rc = fan_cpu_main->ops->set_value(fan_cpu_main,
268 st->cpu_setpoint);
269 if (rc) {
270 printk(KERN_WARNING "windfarm: CPU main fan"
271 " error %d\n", rc);
272 wf_smu_failure_state |= FAILURE_FAN;
273 }
274 }
275 if (fan_cpu_second && wf_smu_failure_state == 0) {
276 rc = fan_cpu_second->ops->set_value(fan_cpu_second,
277 st->cpu_setpoint);
278 if (rc) {
279 printk(KERN_WARNING "windfarm: CPU second fan"
280 " error %d\n", rc);
281 wf_smu_failure_state |= FAILURE_FAN;
282 }
283 }
284 if (fan_cpu_third && wf_smu_failure_state == 0) {
285 rc = fan_cpu_main->ops->set_value(fan_cpu_third,
286 st->cpu_setpoint);
287 if (rc) {
288 printk(KERN_WARNING "windfarm: CPU third fan"
289 " error %d\n", rc);
290 wf_smu_failure_state |= FAILURE_FAN;
291 }
292 }
293}
294
295static void wf_smu_create_drive_fans(void)
296{
297 struct wf_pid_param param = {
298 .interval = 5,
299 .history_len = 2,
300 .gd = 0x01e00000,
301 .gp = 0x00500000,
302 .gr = 0x00000000,
303 .itarget = 0x00200000,
304 };
305
306 /* Alloc & initialize state */
307 wf_smu_drive_fans = kmalloc(sizeof(struct wf_smu_drive_fans_state),
308 GFP_KERNEL);
309 if (wf_smu_drive_fans == NULL) {
310 printk(KERN_WARNING "windfarm: Memory allocation error"
311 " max fan speed\n");
312 goto fail;
313 }
314 wf_smu_drive_fans->ticks = 1;
315
316 /* Fill PID params */
317 param.additive = (fan_hd->type == WF_CONTROL_RPM_FAN);
318 param.min = fan_hd->ops->get_min(fan_hd);
319 param.max = fan_hd->ops->get_max(fan_hd);
320 wf_pid_init(&wf_smu_drive_fans->pid, &param);
321
322 DBG("wf: Drive Fan control initialized.\n");
323 DBG(" itarged=%d.%03d, min=%d RPM, max=%d RPM\n",
324 FIX32TOPRINT(param.itarget), param.min, param.max);
325 return;
326
327 fail:
328 if (fan_hd)
329 wf_control_set_max(fan_hd);
330}
331
332static void wf_smu_drive_fans_tick(struct wf_smu_drive_fans_state *st)
333{
334 s32 new_setpoint, temp;
335 int rc;
336
337 if (--st->ticks != 0) {
338 if (wf_smu_readjust)
339 goto readjust;
340 return;
341 }
342 st->ticks = st->pid.param.interval;
343
344 rc = sensor_hd_temp->ops->get_value(sensor_hd_temp, &temp);
345 if (rc) {
346 printk(KERN_WARNING "windfarm: HD temp sensor error %d\n",
347 rc);
348 wf_smu_failure_state |= FAILURE_SENSOR;
349 return;
350 }
351
352 DBG("wf_smu: Drive Fans tick ! HD temp: %d.%03d\n",
353 FIX32TOPRINT(temp));
354
355 if (temp > (st->pid.param.itarget + 0x50000))
356 wf_smu_failure_state |= FAILURE_OVERTEMP;
357
358 new_setpoint = wf_pid_run(&st->pid, temp);
359
360 DBG("wf_smu: new_setpoint: %d\n", (int)new_setpoint);
361
362 if (st->setpoint == new_setpoint)
363 return;
364 st->setpoint = new_setpoint;
365 readjust:
366 if (fan_hd && wf_smu_failure_state == 0) {
367 rc = fan_hd->ops->set_value(fan_hd, st->setpoint);
368 if (rc) {
369 printk(KERN_WARNING "windfarm: HD fan error %d\n",
370 rc);
371 wf_smu_failure_state |= FAILURE_FAN;
372 }
373 }
374}
375
376static void wf_smu_create_slots_fans(void)
377{
378 struct wf_pid_param param = {
379 .interval = 1,
380 .history_len = 8,
381 .gd = 0x00000000,
382 .gp = 0x00000000,
383 .gr = 0x00020000,
384 .itarget = 0x00000000
385 };
386
387 /* Alloc & initialize state */
388 wf_smu_slots_fans = kmalloc(sizeof(struct wf_smu_slots_fans_state),
389 GFP_KERNEL);
390 if (wf_smu_slots_fans == NULL) {
391 printk(KERN_WARNING "windfarm: Memory allocation error"
392 " max fan speed\n");
393 goto fail;
394 }
395 wf_smu_slots_fans->ticks = 1;
396
397 /* Fill PID params */
398 param.additive = (fan_slots->type == WF_CONTROL_RPM_FAN);
399 param.min = fan_slots->ops->get_min(fan_slots);
400 param.max = fan_slots->ops->get_max(fan_slots);
401 wf_pid_init(&wf_smu_slots_fans->pid, &param);
402
403 DBG("wf: Slots Fan control initialized.\n");
404 DBG(" itarged=%d.%03d, min=%d RPM, max=%d RPM\n",
405 FIX32TOPRINT(param.itarget), param.min, param.max);
406 return;
407
408 fail:
409 if (fan_slots)
410 wf_control_set_max(fan_slots);
411}
412
413static void wf_smu_slots_fans_tick(struct wf_smu_slots_fans_state *st)
414{
415 s32 new_setpoint, power;
416 int rc;
417
418 if (--st->ticks != 0) {
419 if (wf_smu_readjust)
420 goto readjust;
421 return;
422 }
423 st->ticks = st->pid.param.interval;
424
425 rc = sensor_slots_power->ops->get_value(sensor_slots_power, &power);
426 if (rc) {
427 printk(KERN_WARNING "windfarm: Slots power sensor error %d\n",
428 rc);
429 wf_smu_failure_state |= FAILURE_SENSOR;
430 return;
431 }
432
433 DBG("wf_smu: Slots Fans tick ! Slots power: %d.%03d\n",
434 FIX32TOPRINT(power));
435
436#if 0 /* Check what makes a good overtemp condition */
437 if (power > (st->pid.param.itarget + 0x50000))
438 wf_smu_failure_state |= FAILURE_OVERTEMP;
439#endif
440
441 new_setpoint = wf_pid_run(&st->pid, power);
442
443 DBG("wf_smu: new_setpoint: %d\n", (int)new_setpoint);
444
445 if (st->setpoint == new_setpoint)
446 return;
447 st->setpoint = new_setpoint;
448 readjust:
449 if (fan_slots && wf_smu_failure_state == 0) {
450 rc = fan_slots->ops->set_value(fan_slots, st->setpoint);
451 if (rc) {
452 printk(KERN_WARNING "windfarm: Slots fan error %d\n",
453 rc);
454 wf_smu_failure_state |= FAILURE_FAN;
455 }
456 }
457}
458
459
460/*
461 * ****** Attributes ******
462 *
463 */
464
465#define BUILD_SHOW_FUNC_FIX(name, data) \
466static ssize_t show_##name(struct device *dev, \
467 struct device_attribute *attr, \
468 char *buf) \
469{ \
470 ssize_t r; \
471 s32 val = 0; \
472 data->ops->get_value(data, &val); \
473 r = sprintf(buf, "%d.%03d", FIX32TOPRINT(val)); \
474 return r; \
475} \
476static DEVICE_ATTR(name,S_IRUGO,show_##name, NULL);
477
478
479#define BUILD_SHOW_FUNC_INT(name, data) \
480static ssize_t show_##name(struct device *dev, \
481 struct device_attribute *attr, \
482 char *buf) \
483{ \
484 s32 val = 0; \
485 data->ops->get_value(data, &val); \
486 return sprintf(buf, "%d", val); \
487} \
488static DEVICE_ATTR(name,S_IRUGO,show_##name, NULL);
489
490BUILD_SHOW_FUNC_INT(cpu_fan, fan_cpu_main);
491BUILD_SHOW_FUNC_INT(hd_fan, fan_hd);
492BUILD_SHOW_FUNC_INT(slots_fan, fan_slots);
493
494BUILD_SHOW_FUNC_FIX(cpu_temp, sensor_cpu_temp);
495BUILD_SHOW_FUNC_FIX(cpu_power, sensor_cpu_power);
496BUILD_SHOW_FUNC_FIX(hd_temp, sensor_hd_temp);
497BUILD_SHOW_FUNC_FIX(slots_power, sensor_slots_power);
498
499/*
500 * ****** Setup / Init / Misc ... ******
501 *
502 */
503
504static void wf_smu_tick(void)
505{
506 unsigned int last_failure = wf_smu_failure_state;
507 unsigned int new_failure;
508
509 if (!wf_smu_started) {
510 DBG("wf: creating control loops !\n");
511 wf_smu_create_drive_fans();
512 wf_smu_create_slots_fans();
513 wf_smu_create_cpu_fans();
514 wf_smu_started = 1;
515 }
516
517 /* Skipping ticks */
518 if (wf_smu_skipping && --wf_smu_skipping)
519 return;
520
521 wf_smu_failure_state = 0;
522 if (wf_smu_drive_fans)
523 wf_smu_drive_fans_tick(wf_smu_drive_fans);
524 if (wf_smu_slots_fans)
525 wf_smu_slots_fans_tick(wf_smu_slots_fans);
526 if (wf_smu_cpu_fans)
527 wf_smu_cpu_fans_tick(wf_smu_cpu_fans);
528
529 wf_smu_readjust = 0;
530 new_failure = wf_smu_failure_state & ~last_failure;
531
532 /* If entering failure mode, clamp cpufreq and ramp all
533 * fans to full speed.
534 */
535 if (wf_smu_failure_state && !last_failure) {
536 if (cpufreq_clamp)
537 wf_control_set_max(cpufreq_clamp);
538 if (fan_cpu_main)
539 wf_control_set_max(fan_cpu_main);
540 if (fan_cpu_second)
541 wf_control_set_max(fan_cpu_second);
542 if (fan_cpu_third)
543 wf_control_set_max(fan_cpu_third);
544 if (fan_hd)
545 wf_control_set_max(fan_hd);
546 if (fan_slots)
547 wf_control_set_max(fan_slots);
548 }
549
550 /* If leaving failure mode, unclamp cpufreq and readjust
551 * all fans on next iteration
552 */
553 if (!wf_smu_failure_state && last_failure) {
554 if (cpufreq_clamp)
555 wf_control_set_min(cpufreq_clamp);
556 wf_smu_readjust = 1;
557 }
558
559 /* Overtemp condition detected, notify and start skipping a couple
560 * ticks to let the temperature go down
561 */
562 if (new_failure & FAILURE_OVERTEMP) {
563 wf_set_overtemp();
564 wf_smu_skipping = 2;
565 }
566
567 /* We only clear the overtemp condition if overtemp is cleared
568 * _and_ no other failure is present. Since a sensor error will
569 * clear the overtemp condition (can't measure temperature) at
570 * the control loop levels, but we don't want to keep it clear
571 * here in this case
572 */
573 if (new_failure == 0 && last_failure & FAILURE_OVERTEMP)
574 wf_clear_overtemp();
575}
576
577
578static void wf_smu_new_control(struct wf_control *ct)
579{
580 if (wf_smu_all_controls_ok)
581 return;
582
583 if (fan_cpu_main == NULL && !strcmp(ct->name, "cpu-rear-fan-0")) {
584 if (wf_get_control(ct) == 0) {
585 fan_cpu_main = ct;
586 device_create_file(wf_smu_dev, &dev_attr_cpu_fan);
587 }
588 }
589
590 if (fan_cpu_second == NULL && !strcmp(ct->name, "cpu-rear-fan-1")) {
591 if (wf_get_control(ct) == 0)
592 fan_cpu_second = ct;
593 }
594
595 if (fan_cpu_third == NULL && !strcmp(ct->name, "cpu-front-fan-0")) {
596 if (wf_get_control(ct) == 0)
597 fan_cpu_third = ct;
598 }
599
600 if (cpufreq_clamp == NULL && !strcmp(ct->name, "cpufreq-clamp")) {
601 if (wf_get_control(ct) == 0)
602 cpufreq_clamp = ct;
603 }
604
605 if (fan_hd == NULL && !strcmp(ct->name, "drive-bay-fan")) {
606 if (wf_get_control(ct) == 0) {
607 fan_hd = ct;
608 device_create_file(wf_smu_dev, &dev_attr_hd_fan);
609 }
610 }
611
612 if (fan_slots == NULL && !strcmp(ct->name, "slots-fan")) {
613 if (wf_get_control(ct) == 0) {
614 fan_slots = ct;
615 device_create_file(wf_smu_dev, &dev_attr_slots_fan);
616 }
617 }
618
619 if (fan_cpu_main && (fan_cpu_second || fan_cpu_third) && fan_hd &&
620 fan_slots && cpufreq_clamp)
621 wf_smu_all_controls_ok = 1;
622}
623
624static void wf_smu_new_sensor(struct wf_sensor *sr)
625{
626 if (wf_smu_all_sensors_ok)
627 return;
628
629 if (sensor_cpu_power == NULL && !strcmp(sr->name, "cpu-power")) {
630 if (wf_get_sensor(sr) == 0) {
631 sensor_cpu_power = sr;
632 device_create_file(wf_smu_dev, &dev_attr_cpu_power);
633 }
634 }
635
636 if (sensor_cpu_temp == NULL && !strcmp(sr->name, "cpu-temp")) {
637 if (wf_get_sensor(sr) == 0) {
638 sensor_cpu_temp = sr;
639 device_create_file(wf_smu_dev, &dev_attr_cpu_temp);
640 }
641 }
642
643 if (sensor_hd_temp == NULL && !strcmp(sr->name, "hd-temp")) {
644 if (wf_get_sensor(sr) == 0) {
645 sensor_hd_temp = sr;
646 device_create_file(wf_smu_dev, &dev_attr_hd_temp);
647 }
648 }
649
650 if (sensor_slots_power == NULL && !strcmp(sr->name, "slots-power")) {
651 if (wf_get_sensor(sr) == 0) {
652 sensor_slots_power = sr;
653 device_create_file(wf_smu_dev, &dev_attr_slots_power);
654 }
655 }
656
657 if (sensor_cpu_power && sensor_cpu_temp &&
658 sensor_hd_temp && sensor_slots_power)
659 wf_smu_all_sensors_ok = 1;
660}
661
662
663static int wf_smu_notify(struct notifier_block *self,
664 unsigned long event, void *data)
665{
666 switch(event) {
667 case WF_EVENT_NEW_CONTROL:
668 DBG("wf: new control %s detected\n",
669 ((struct wf_control *)data)->name);
670 wf_smu_new_control(data);
671 wf_smu_readjust = 1;
672 break;
673 case WF_EVENT_NEW_SENSOR:
674 DBG("wf: new sensor %s detected\n",
675 ((struct wf_sensor *)data)->name);
676 wf_smu_new_sensor(data);
677 break;
678 case WF_EVENT_TICK:
679 if (wf_smu_all_controls_ok && wf_smu_all_sensors_ok)
680 wf_smu_tick();
681 }
682
683 return 0;
684}
685
686static struct notifier_block wf_smu_events = {
687 .notifier_call = wf_smu_notify,
688};
689
690static int wf_init_pm(void)
691{
692 printk(KERN_INFO "windfarm: Initializing for Desktop G5 model\n");
693
694 return 0;
695}
696
697static int wf_smu_probe(struct device *ddev)
698{
699 wf_smu_dev = ddev;
700
701 wf_register_client(&wf_smu_events);
702
703 return 0;
704}
705
706static int wf_smu_remove(struct device *ddev)
707{
708 wf_unregister_client(&wf_smu_events);
709
710 /* XXX We don't have yet a guarantee that our callback isn't
711 * in progress when returning from wf_unregister_client, so
712 * we add an arbitrary delay. I'll have to fix that in the core
713 */
714 msleep(1000);
715
716 /* Release all sensors */
717 /* One more crappy race: I don't think we have any guarantee here
718 * that the attribute callback won't race with the sensor beeing
719 * disposed of, and I'm not 100% certain what best way to deal
720 * with that except by adding locks all over... I'll do that
721 * eventually but heh, who ever rmmod this module anyway ?
722 */
723 if (sensor_cpu_power) {
724 device_remove_file(wf_smu_dev, &dev_attr_cpu_power);
725 wf_put_sensor(sensor_cpu_power);
726 }
727 if (sensor_cpu_temp) {
728 device_remove_file(wf_smu_dev, &dev_attr_cpu_temp);
729 wf_put_sensor(sensor_cpu_temp);
730 }
731 if (sensor_hd_temp) {
732 device_remove_file(wf_smu_dev, &dev_attr_hd_temp);
733 wf_put_sensor(sensor_hd_temp);
734 }
735 if (sensor_slots_power) {
736 device_remove_file(wf_smu_dev, &dev_attr_slots_power);
737 wf_put_sensor(sensor_slots_power);
738 }
739
740 /* Release all controls */
741 if (fan_cpu_main) {
742 device_remove_file(wf_smu_dev, &dev_attr_cpu_fan);
743 wf_put_control(fan_cpu_main);
744 }
745 if (fan_cpu_second)
746 wf_put_control(fan_cpu_second);
747 if (fan_cpu_third)
748 wf_put_control(fan_cpu_third);
749 if (fan_hd) {
750 device_remove_file(wf_smu_dev, &dev_attr_hd_fan);
751 wf_put_control(fan_hd);
752 }
753 if (fan_slots) {
754 device_remove_file(wf_smu_dev, &dev_attr_slots_fan);
755 wf_put_control(fan_slots);
756 }
757 if (cpufreq_clamp)
758 wf_put_control(cpufreq_clamp);
759
760 /* Destroy control loops state structures */
761 if (wf_smu_slots_fans)
762 kfree(wf_smu_cpu_fans);
763 if (wf_smu_drive_fans)
764 kfree(wf_smu_cpu_fans);
765 if (wf_smu_cpu_fans)
766 kfree(wf_smu_cpu_fans);
767
768 wf_smu_dev = NULL;
769
770 return 0;
771}
772
773static struct device_driver wf_smu_driver = {
774 .name = "windfarm",
775 .bus = &platform_bus_type,
776 .probe = wf_smu_probe,
777 .remove = wf_smu_remove,
778};
779
780
781static int __init wf_smu_init(void)
782{
783 int rc = -ENODEV;
784
785 if (machine_is_compatible("PowerMac9,1"))
786 rc = wf_init_pm();
787
788 if (rc == 0) {
789#ifdef MODULE
790 request_module("windfarm_smu_controls");
791 request_module("windfarm_smu_sensors");
792 request_module("windfarm_lm75_sensor");
793
794#endif /* MODULE */
795 driver_register(&wf_smu_driver);
796 }
797
798 return rc;
799}
800
801static void __exit wf_smu_exit(void)
802{
803
804 driver_unregister(&wf_smu_driver);
805}
806
807
808module_init(wf_smu_init);
809module_exit(wf_smu_exit);
810
811MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
812MODULE_DESCRIPTION("Thermal control logic for PowerMac9,1");
813MODULE_LICENSE("GPL");
814
diff --git a/drivers/macintosh/windfarm_smu_controls.c b/drivers/macintosh/windfarm_smu_controls.c
new file mode 100644
index 000000000000..2c3158c81ff2
--- /dev/null
+++ b/drivers/macintosh/windfarm_smu_controls.c
@@ -0,0 +1,282 @@
1/*
2 * Windfarm PowerMac thermal control. SMU based controls
3 *
4 * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp.
5 * <benh@kernel.crashing.org>
6 *
7 * Released under the term of the GNU GPL v2.
8 */
9
10#include <linux/types.h>
11#include <linux/errno.h>
12#include <linux/kernel.h>
13#include <linux/delay.h>
14#include <linux/slab.h>
15#include <linux/init.h>
16#include <linux/wait.h>
17#include <asm/prom.h>
18#include <asm/machdep.h>
19#include <asm/io.h>
20#include <asm/system.h>
21#include <asm/sections.h>
22#include <asm/smu.h>
23
24#include "windfarm.h"
25
26#define VERSION "0.3"
27
28#undef DEBUG
29
30#ifdef DEBUG
31#define DBG(args...) printk(args)
32#else
33#define DBG(args...) do { } while(0)
34#endif
35
36/*
37 * SMU fans control object
38 */
39
40static LIST_HEAD(smu_fans);
41
42struct smu_fan_control {
43 struct list_head link;
44 int fan_type; /* 0 = rpm, 1 = pwm */
45 u32 reg; /* index in SMU */
46 s32 value; /* current value */
47 s32 min, max; /* min/max values */
48 struct wf_control ctrl;
49};
50#define to_smu_fan(c) container_of(c, struct smu_fan_control, ctrl)
51
52static int smu_set_fan(int pwm, u8 id, u16 value)
53{
54 struct smu_cmd cmd;
55 u8 buffer[16];
56 DECLARE_COMPLETION(comp);
57 int rc;
58
59 /* Fill SMU command structure */
60 cmd.cmd = SMU_CMD_FAN_COMMAND;
61 cmd.data_len = 14;
62 cmd.reply_len = 16;
63 cmd.data_buf = cmd.reply_buf = buffer;
64 cmd.status = 0;
65 cmd.done = smu_done_complete;
66 cmd.misc = &comp;
67
68 /* Fill argument buffer */
69 memset(buffer, 0, 16);
70 buffer[0] = pwm ? 0x10 : 0x00;
71 buffer[1] = 0x01 << id;
72 *((u16 *)&buffer[2 + id * 2]) = value;
73
74 rc = smu_queue_cmd(&cmd);
75 if (rc)
76 return rc;
77 wait_for_completion(&comp);
78 return cmd.status;
79}
80
81static void smu_fan_release(struct wf_control *ct)
82{
83 struct smu_fan_control *fct = to_smu_fan(ct);
84
85 kfree(fct);
86}
87
88static int smu_fan_set(struct wf_control *ct, s32 value)
89{
90 struct smu_fan_control *fct = to_smu_fan(ct);
91
92 if (value < fct->min)
93 value = fct->min;
94 if (value > fct->max)
95 value = fct->max;
96 fct->value = value;
97
98 return smu_set_fan(fct->fan_type, fct->reg, value);
99}
100
101static int smu_fan_get(struct wf_control *ct, s32 *value)
102{
103 struct smu_fan_control *fct = to_smu_fan(ct);
104 *value = fct->value; /* todo: read from SMU */
105 return 0;
106}
107
108static s32 smu_fan_min(struct wf_control *ct)
109{
110 struct smu_fan_control *fct = to_smu_fan(ct);
111 return fct->min;
112}
113
114static s32 smu_fan_max(struct wf_control *ct)
115{
116 struct smu_fan_control *fct = to_smu_fan(ct);
117 return fct->max;
118}
119
120static struct wf_control_ops smu_fan_ops = {
121 .set_value = smu_fan_set,
122 .get_value = smu_fan_get,
123 .get_min = smu_fan_min,
124 .get_max = smu_fan_max,
125 .release = smu_fan_release,
126 .owner = THIS_MODULE,
127};
128
129static struct smu_fan_control *smu_fan_create(struct device_node *node,
130 int pwm_fan)
131{
132 struct smu_fan_control *fct;
133 s32 *v; u32 *reg;
134 char *l;
135
136 fct = kmalloc(sizeof(struct smu_fan_control), GFP_KERNEL);
137 if (fct == NULL)
138 return NULL;
139 fct->ctrl.ops = &smu_fan_ops;
140 l = (char *)get_property(node, "location", NULL);
141 if (l == NULL)
142 goto fail;
143
144 fct->fan_type = pwm_fan;
145 fct->ctrl.type = pwm_fan ? WF_CONTROL_PWM_FAN : WF_CONTROL_RPM_FAN;
146
147 /* We use the name & location here the same way we do for SMU sensors,
148 * see the comment in windfarm_smu_sensors.c. The locations are a bit
149 * less consistent here between the iMac and the desktop models, but
150 * that is good enough for our needs for now at least.
151 *
152 * One problem though is that Apple seem to be inconsistent with case
153 * and the kernel doesn't have strcasecmp =P
154 */
155
156 fct->ctrl.name = NULL;
157
158 /* Names used on desktop models */
159 if (!strcmp(l, "Rear Fan 0") || !strcmp(l, "Rear Fan") ||
160 !strcmp(l, "Rear fan 0") || !strcmp(l, "Rear fan"))
161 fct->ctrl.name = "cpu-rear-fan-0";
162 else if (!strcmp(l, "Rear Fan 1") || !strcmp(l, "Rear fan 1"))
163 fct->ctrl.name = "cpu-rear-fan-1";
164 else if (!strcmp(l, "Front Fan 0") || !strcmp(l, "Front Fan") ||
165 !strcmp(l, "Front fan 0") || !strcmp(l, "Front fan"))
166 fct->ctrl.name = "cpu-front-fan-0";
167 else if (!strcmp(l, "Front Fan 1") || !strcmp(l, "Front fan 1"))
168 fct->ctrl.name = "cpu-front-fan-1";
169 else if (!strcmp(l, "Slots Fan") || !strcmp(l, "Slots fan"))
170 fct->ctrl.name = "slots-fan";
171 else if (!strcmp(l, "Drive Bay") || !strcmp(l, "Drive bay"))
172 fct->ctrl.name = "drive-bay-fan";
173
174 /* Names used on iMac models */
175 if (!strcmp(l, "System Fan") || !strcmp(l, "System fan"))
176 fct->ctrl.name = "system-fan";
177 else if (!strcmp(l, "CPU Fan") || !strcmp(l, "CPU fan"))
178 fct->ctrl.name = "cpu-fan";
179 else if (!strcmp(l, "Hard Drive") || !strcmp(l, "Hard drive"))
180 fct->ctrl.name = "drive-bay-fan";
181
182 /* Unrecognized fan, bail out */
183 if (fct->ctrl.name == NULL)
184 goto fail;
185
186 /* Get min & max values*/
187 v = (s32 *)get_property(node, "min-value", NULL);
188 if (v == NULL)
189 goto fail;
190 fct->min = *v;
191 v = (s32 *)get_property(node, "max-value", NULL);
192 if (v == NULL)
193 goto fail;
194 fct->max = *v;
195
196 /* Get "reg" value */
197 reg = (u32 *)get_property(node, "reg", NULL);
198 if (reg == NULL)
199 goto fail;
200 fct->reg = *reg;
201
202 if (wf_register_control(&fct->ctrl))
203 goto fail;
204
205 return fct;
206 fail:
207 kfree(fct);
208 return NULL;
209}
210
211
212static int __init smu_controls_init(void)
213{
214 struct device_node *smu, *fans, *fan;
215
216 if (!smu_present())
217 return -ENODEV;
218
219 smu = of_find_node_by_type(NULL, "smu");
220 if (smu == NULL)
221 return -ENODEV;
222
223 /* Look for RPM fans */
224 for (fans = NULL; (fans = of_get_next_child(smu, fans)) != NULL;)
225 if (!strcmp(fans->name, "rpm-fans"))
226 break;
227 for (fan = NULL;
228 fans && (fan = of_get_next_child(fans, fan)) != NULL;) {
229 struct smu_fan_control *fct;
230
231 fct = smu_fan_create(fan, 0);
232 if (fct == NULL) {
233 printk(KERN_WARNING "windfarm: Failed to create SMU "
234 "RPM fan %s\n", fan->name);
235 continue;
236 }
237 list_add(&fct->link, &smu_fans);
238 }
239 of_node_put(fans);
240
241
242 /* Look for PWM fans */
243 for (fans = NULL; (fans = of_get_next_child(smu, fans)) != NULL;)
244 if (!strcmp(fans->name, "pwm-fans"))
245 break;
246 for (fan = NULL;
247 fans && (fan = of_get_next_child(fans, fan)) != NULL;) {
248 struct smu_fan_control *fct;
249
250 fct = smu_fan_create(fan, 1);
251 if (fct == NULL) {
252 printk(KERN_WARNING "windfarm: Failed to create SMU "
253 "PWM fan %s\n", fan->name);
254 continue;
255 }
256 list_add(&fct->link, &smu_fans);
257 }
258 of_node_put(fans);
259 of_node_put(smu);
260
261 return 0;
262}
263
264static void __exit smu_controls_exit(void)
265{
266 struct smu_fan_control *fct;
267
268 while (!list_empty(&smu_fans)) {
269 fct = list_entry(smu_fans.next, struct smu_fan_control, link);
270 list_del(&fct->link);
271 wf_unregister_control(&fct->ctrl);
272 }
273}
274
275
276module_init(smu_controls_init);
277module_exit(smu_controls_exit);
278
279MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
280MODULE_DESCRIPTION("SMU control objects for PowerMacs thermal control");
281MODULE_LICENSE("GPL");
282
diff --git a/drivers/macintosh/windfarm_smu_sensors.c b/drivers/macintosh/windfarm_smu_sensors.c
new file mode 100644
index 000000000000..b558cc209d49
--- /dev/null
+++ b/drivers/macintosh/windfarm_smu_sensors.c
@@ -0,0 +1,479 @@
1/*
2 * Windfarm PowerMac thermal control. SMU based sensors
3 *
4 * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp.
5 * <benh@kernel.crashing.org>
6 *
7 * Released under the term of the GNU GPL v2.
8 */
9
10#include <linux/types.h>
11#include <linux/errno.h>
12#include <linux/kernel.h>
13#include <linux/delay.h>
14#include <linux/slab.h>
15#include <linux/init.h>
16#include <linux/wait.h>
17#include <asm/prom.h>
18#include <asm/machdep.h>
19#include <asm/io.h>
20#include <asm/system.h>
21#include <asm/sections.h>
22#include <asm/smu.h>
23
24#include "windfarm.h"
25
26#define VERSION "0.2"
27
28#undef DEBUG
29
30#ifdef DEBUG
31#define DBG(args...) printk(args)
32#else
33#define DBG(args...) do { } while(0)
34#endif
35
36/*
37 * Various SMU "partitions" calibration objects for which we
38 * keep pointers here for use by bits & pieces of the driver
39 */
40static struct smu_sdbp_cpuvcp *cpuvcp;
41static int cpuvcp_version;
42static struct smu_sdbp_cpudiode *cpudiode;
43static struct smu_sdbp_slotspow *slotspow;
44static u8 *debugswitches;
45
46/*
47 * SMU basic sensors objects
48 */
49
50static LIST_HEAD(smu_ads);
51
52struct smu_ad_sensor {
53 struct list_head link;
54 u32 reg; /* index in SMU */
55 struct wf_sensor sens;
56};
57#define to_smu_ads(c) container_of(c, struct smu_ad_sensor, sens)
58
59static void smu_ads_release(struct wf_sensor *sr)
60{
61 struct smu_ad_sensor *ads = to_smu_ads(sr);
62
63 kfree(ads);
64}
65
66static int smu_read_adc(u8 id, s32 *value)
67{
68 struct smu_simple_cmd cmd;
69 DECLARE_COMPLETION(comp);
70 int rc;
71
72 rc = smu_queue_simple(&cmd, SMU_CMD_READ_ADC, 1,
73 smu_done_complete, &comp, id);
74 if (rc)
75 return rc;
76 wait_for_completion(&comp);
77 if (cmd.cmd.status != 0)
78 return cmd.cmd.status;
79 if (cmd.cmd.reply_len != 2) {
80 printk(KERN_ERR "winfarm: read ADC 0x%x returned %d bytes !\n",
81 id, cmd.cmd.reply_len);
82 return -EIO;
83 }
84 *value = *((u16 *)cmd.buffer);
85 return 0;
86}
87
88static int smu_cputemp_get(struct wf_sensor *sr, s32 *value)
89{
90 struct smu_ad_sensor *ads = to_smu_ads(sr);
91 int rc;
92 s32 val;
93 s64 scaled;
94
95 rc = smu_read_adc(ads->reg, &val);
96 if (rc) {
97 printk(KERN_ERR "windfarm: read CPU temp failed, err %d\n",
98 rc);
99 return rc;
100 }
101
102 /* Ok, we have to scale & adjust, taking units into account */
103 scaled = (s64)(((u64)val) * (u64)cpudiode->m_value);
104 scaled >>= 3;
105 scaled += ((s64)cpudiode->b_value) << 9;
106 *value = (s32)(scaled << 1);
107
108 return 0;
109}
110
111static int smu_cpuamp_get(struct wf_sensor *sr, s32 *value)
112{
113 struct smu_ad_sensor *ads = to_smu_ads(sr);
114 s32 val, scaled;
115 int rc;
116
117 rc = smu_read_adc(ads->reg, &val);
118 if (rc) {
119 printk(KERN_ERR "windfarm: read CPU current failed, err %d\n",
120 rc);
121 return rc;
122 }
123
124 /* Ok, we have to scale & adjust, taking units into account */
125 scaled = (s32)(val * (u32)cpuvcp->curr_scale);
126 scaled += (s32)cpuvcp->curr_offset;
127 *value = scaled << 4;
128
129 return 0;
130}
131
132static int smu_cpuvolt_get(struct wf_sensor *sr, s32 *value)
133{
134 struct smu_ad_sensor *ads = to_smu_ads(sr);
135 s32 val, scaled;
136 int rc;
137
138 rc = smu_read_adc(ads->reg, &val);
139 if (rc) {
140 printk(KERN_ERR "windfarm: read CPU voltage failed, err %d\n",
141 rc);
142 return rc;
143 }
144
145 /* Ok, we have to scale & adjust, taking units into account */
146 scaled = (s32)(val * (u32)cpuvcp->volt_scale);
147 scaled += (s32)cpuvcp->volt_offset;
148 *value = scaled << 4;
149
150 return 0;
151}
152
153static int smu_slotspow_get(struct wf_sensor *sr, s32 *value)
154{
155 struct smu_ad_sensor *ads = to_smu_ads(sr);
156 s32 val, scaled;
157 int rc;
158
159 rc = smu_read_adc(ads->reg, &val);
160 if (rc) {
161 printk(KERN_ERR "windfarm: read slots power failed, err %d\n",
162 rc);
163 return rc;
164 }
165
166 /* Ok, we have to scale & adjust, taking units into account */
167 scaled = (s32)(val * (u32)slotspow->pow_scale);
168 scaled += (s32)slotspow->pow_offset;
169 *value = scaled << 4;
170
171 return 0;
172}
173
174
175static struct wf_sensor_ops smu_cputemp_ops = {
176 .get_value = smu_cputemp_get,
177 .release = smu_ads_release,
178 .owner = THIS_MODULE,
179};
180static struct wf_sensor_ops smu_cpuamp_ops = {
181 .get_value = smu_cpuamp_get,
182 .release = smu_ads_release,
183 .owner = THIS_MODULE,
184};
185static struct wf_sensor_ops smu_cpuvolt_ops = {
186 .get_value = smu_cpuvolt_get,
187 .release = smu_ads_release,
188 .owner = THIS_MODULE,
189};
190static struct wf_sensor_ops smu_slotspow_ops = {
191 .get_value = smu_slotspow_get,
192 .release = smu_ads_release,
193 .owner = THIS_MODULE,
194};
195
196
197static struct smu_ad_sensor *smu_ads_create(struct device_node *node)
198{
199 struct smu_ad_sensor *ads;
200 char *c, *l;
201 u32 *v;
202
203 ads = kmalloc(sizeof(struct smu_ad_sensor), GFP_KERNEL);
204 if (ads == NULL)
205 return NULL;
206 c = (char *)get_property(node, "device_type", NULL);
207 l = (char *)get_property(node, "location", NULL);
208 if (c == NULL || l == NULL)
209 goto fail;
210
211 /* We currently pick the sensors based on the OF name and location
212 * properties, while Darwin uses the sensor-id's.
213 * The problem with the IDs is that they are model specific while it
214 * looks like apple has been doing a reasonably good job at keeping
215 * the names and locations consistents so I'll stick with the names
216 * and locations for now.
217 */
218 if (!strcmp(c, "temp-sensor") &&
219 !strcmp(l, "CPU T-Diode")) {
220 ads->sens.ops = &smu_cputemp_ops;
221 ads->sens.name = "cpu-temp";
222 } else if (!strcmp(c, "current-sensor") &&
223 !strcmp(l, "CPU Current")) {
224 ads->sens.ops = &smu_cpuamp_ops;
225 ads->sens.name = "cpu-current";
226 } else if (!strcmp(c, "voltage-sensor") &&
227 !strcmp(l, "CPU Voltage")) {
228 ads->sens.ops = &smu_cpuvolt_ops;
229 ads->sens.name = "cpu-voltage";
230 } else if (!strcmp(c, "power-sensor") &&
231 !strcmp(l, "Slots Power")) {
232 ads->sens.ops = &smu_slotspow_ops;
233 ads->sens.name = "slots-power";
234 if (slotspow == NULL) {
235 DBG("wf: slotspow partition (%02x) not found\n",
236 SMU_SDB_SLOTSPOW_ID);
237 goto fail;
238 }
239 } else
240 goto fail;
241
242 v = (u32 *)get_property(node, "reg", NULL);
243 if (v == NULL)
244 goto fail;
245 ads->reg = *v;
246
247 if (wf_register_sensor(&ads->sens))
248 goto fail;
249 return ads;
250 fail:
251 kfree(ads);
252 return NULL;
253}
254
255/*
256 * SMU Power combo sensor object
257 */
258
259struct smu_cpu_power_sensor {
260 struct list_head link;
261 struct wf_sensor *volts;
262 struct wf_sensor *amps;
263 int fake_volts : 1;
264 int quadratic : 1;
265 struct wf_sensor sens;
266};
267#define to_smu_cpu_power(c) container_of(c, struct smu_cpu_power_sensor, sens)
268
269static struct smu_cpu_power_sensor *smu_cpu_power;
270
271static void smu_cpu_power_release(struct wf_sensor *sr)
272{
273 struct smu_cpu_power_sensor *pow = to_smu_cpu_power(sr);
274
275 if (pow->volts)
276 wf_put_sensor(pow->volts);
277 if (pow->amps)
278 wf_put_sensor(pow->amps);
279 kfree(pow);
280}
281
282static int smu_cpu_power_get(struct wf_sensor *sr, s32 *value)
283{
284 struct smu_cpu_power_sensor *pow = to_smu_cpu_power(sr);
285 s32 volts, amps, power;
286 u64 tmps, tmpa, tmpb;
287 int rc;
288
289 rc = pow->amps->ops->get_value(pow->amps, &amps);
290 if (rc)
291 return rc;
292
293 if (pow->fake_volts) {
294 *value = amps * 12 - 0x30000;
295 return 0;
296 }
297
298 rc = pow->volts->ops->get_value(pow->volts, &volts);
299 if (rc)
300 return rc;
301
302 power = (s32)((((u64)volts) * ((u64)amps)) >> 16);
303 if (!pow->quadratic) {
304 *value = power;
305 return 0;
306 }
307 tmps = (((u64)power) * ((u64)power)) >> 16;
308 tmpa = ((u64)cpuvcp->power_quads[0]) * tmps;
309 tmpb = ((u64)cpuvcp->power_quads[1]) * ((u64)power);
310 *value = (tmpa >> 28) + (tmpb >> 28) + (cpuvcp->power_quads[2] >> 12);
311
312 return 0;
313}
314
315static struct wf_sensor_ops smu_cpu_power_ops = {
316 .get_value = smu_cpu_power_get,
317 .release = smu_cpu_power_release,
318 .owner = THIS_MODULE,
319};
320
321
322static struct smu_cpu_power_sensor *
323smu_cpu_power_create(struct wf_sensor *volts, struct wf_sensor *amps)
324{
325 struct smu_cpu_power_sensor *pow;
326
327 pow = kmalloc(sizeof(struct smu_cpu_power_sensor), GFP_KERNEL);
328 if (pow == NULL)
329 return NULL;
330 pow->sens.ops = &smu_cpu_power_ops;
331 pow->sens.name = "cpu-power";
332
333 wf_get_sensor(volts);
334 pow->volts = volts;
335 wf_get_sensor(amps);
336 pow->amps = amps;
337
338 /* Some early machines need a faked voltage */
339 if (debugswitches && ((*debugswitches) & 0x80)) {
340 printk(KERN_INFO "windfarm: CPU Power sensor using faked"
341 " voltage !\n");
342 pow->fake_volts = 1;
343 } else
344 pow->fake_volts = 0;
345
346 /* Try to use quadratic transforms on PowerMac8,1 and 9,1 for now,
347 * I yet have to figure out what's up with 8,2 and will have to
348 * adjust for later, unless we can 100% trust the SDB partition...
349 */
350 if ((machine_is_compatible("PowerMac8,1") ||
351 machine_is_compatible("PowerMac8,2") ||
352 machine_is_compatible("PowerMac9,1")) &&
353 cpuvcp_version >= 2) {
354 pow->quadratic = 1;
355 DBG("windfarm: CPU Power using quadratic transform\n");
356 } else
357 pow->quadratic = 0;
358
359 if (wf_register_sensor(&pow->sens))
360 goto fail;
361 return pow;
362 fail:
363 kfree(pow);
364 return NULL;
365}
366
367static int smu_fetch_param_partitions(void)
368{
369 struct smu_sdbp_header *hdr;
370
371 /* Get CPU voltage/current/power calibration data */
372 hdr = smu_get_sdb_partition(SMU_SDB_CPUVCP_ID, NULL);
373 if (hdr == NULL) {
374 DBG("wf: cpuvcp partition (%02x) not found\n",
375 SMU_SDB_CPUVCP_ID);
376 return -ENODEV;
377 }
378 cpuvcp = (struct smu_sdbp_cpuvcp *)&hdr[1];
379 /* Keep version around */
380 cpuvcp_version = hdr->version;
381
382 /* Get CPU diode calibration data */
383 hdr = smu_get_sdb_partition(SMU_SDB_CPUDIODE_ID, NULL);
384 if (hdr == NULL) {
385 DBG("wf: cpudiode partition (%02x) not found\n",
386 SMU_SDB_CPUDIODE_ID);
387 return -ENODEV;
388 }
389 cpudiode = (struct smu_sdbp_cpudiode *)&hdr[1];
390
391 /* Get slots power calibration data if any */
392 hdr = smu_get_sdb_partition(SMU_SDB_SLOTSPOW_ID, NULL);
393 if (hdr != NULL)
394 slotspow = (struct smu_sdbp_slotspow *)&hdr[1];
395
396 /* Get debug switches if any */
397 hdr = smu_get_sdb_partition(SMU_SDB_DEBUG_SWITCHES_ID, NULL);
398 if (hdr != NULL)
399 debugswitches = (u8 *)&hdr[1];
400
401 return 0;
402}
403
404static int __init smu_sensors_init(void)
405{
406 struct device_node *smu, *sensors, *s;
407 struct smu_ad_sensor *volt_sensor = NULL, *curr_sensor = NULL;
408 int rc;
409
410 if (!smu_present())
411 return -ENODEV;
412
413 /* Get parameters partitions */
414 rc = smu_fetch_param_partitions();
415 if (rc)
416 return rc;
417
418 smu = of_find_node_by_type(NULL, "smu");
419 if (smu == NULL)
420 return -ENODEV;
421
422 /* Look for sensors subdir */
423 for (sensors = NULL;
424 (sensors = of_get_next_child(smu, sensors)) != NULL;)
425 if (!strcmp(sensors->name, "sensors"))
426 break;
427
428 of_node_put(smu);
429
430 /* Create basic sensors */
431 for (s = NULL;
432 sensors && (s = of_get_next_child(sensors, s)) != NULL;) {
433 struct smu_ad_sensor *ads;
434
435 ads = smu_ads_create(s);
436 if (ads == NULL)
437 continue;
438 list_add(&ads->link, &smu_ads);
439 /* keep track of cpu voltage & current */
440 if (!strcmp(ads->sens.name, "cpu-voltage"))
441 volt_sensor = ads;
442 else if (!strcmp(ads->sens.name, "cpu-current"))
443 curr_sensor = ads;
444 }
445
446 of_node_put(sensors);
447
448 /* Create CPU power sensor if possible */
449 if (volt_sensor && curr_sensor)
450 smu_cpu_power = smu_cpu_power_create(&volt_sensor->sens,
451 &curr_sensor->sens);
452
453 return 0;
454}
455
456static void __exit smu_sensors_exit(void)
457{
458 struct smu_ad_sensor *ads;
459
460 /* dispose of power sensor */
461 if (smu_cpu_power)
462 wf_unregister_sensor(&smu_cpu_power->sens);
463
464 /* dispose of basic sensors */
465 while (!list_empty(&smu_ads)) {
466 ads = list_entry(smu_ads.next, struct smu_ad_sensor, link);
467 list_del(&ads->link);
468 wf_unregister_sensor(&ads->sens);
469 }
470}
471
472
473module_init(smu_sensors_init);
474module_exit(smu_sensors_exit);
475
476MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
477MODULE_DESCRIPTION("SMU sensor objects for PowerMacs thermal control");
478MODULE_LICENSE("GPL");
479
diff --git a/fs/proc/proc_devtree.c b/fs/proc/proc_devtree.c
index 6fd57f154197..fb117b74809e 100644
--- a/fs/proc/proc_devtree.c
+++ b/fs/proc/proc_devtree.c
@@ -49,6 +49,39 @@ static int property_read_proc(char *page, char **start, off_t off,
49 */ 49 */
50 50
51/* 51/*
52 * Add a property to a node
53 */
54static struct proc_dir_entry *
55__proc_device_tree_add_prop(struct proc_dir_entry *de, struct property *pp)
56{
57 struct proc_dir_entry *ent;
58
59 /*
60 * Unfortunately proc_register puts each new entry
61 * at the beginning of the list. So we rearrange them.
62 */
63 ent = create_proc_read_entry(pp->name,
64 strncmp(pp->name, "security-", 9)
65 ? S_IRUGO : S_IRUSR, de,
66 property_read_proc, pp);
67 if (ent == NULL)
68 return NULL;
69
70 if (!strncmp(pp->name, "security-", 9))
71 ent->size = 0; /* don't leak number of password chars */
72 else
73 ent->size = pp->length;
74
75 return ent;
76}
77
78
79void proc_device_tree_add_prop(struct proc_dir_entry *pde, struct property *prop)
80{
81 __proc_device_tree_add_prop(pde, prop);
82}
83
84/*
52 * Process a node, adding entries for its children and its properties. 85 * Process a node, adding entries for its children and its properties.
53 */ 86 */
54void proc_device_tree_add_node(struct device_node *np, 87void proc_device_tree_add_node(struct device_node *np,
@@ -57,11 +90,9 @@ void proc_device_tree_add_node(struct device_node *np,
57 struct property *pp; 90 struct property *pp;
58 struct proc_dir_entry *ent; 91 struct proc_dir_entry *ent;
59 struct device_node *child; 92 struct device_node *child;
60 struct proc_dir_entry *list = NULL, **lastp;
61 const char *p; 93 const char *p;
62 94
63 set_node_proc_entry(np, de); 95 set_node_proc_entry(np, de);
64 lastp = &list;
65 for (child = NULL; (child = of_get_next_child(np, child));) { 96 for (child = NULL; (child = of_get_next_child(np, child));) {
66 p = strrchr(child->full_name, '/'); 97 p = strrchr(child->full_name, '/');
67 if (!p) 98 if (!p)
@@ -71,9 +102,6 @@ void proc_device_tree_add_node(struct device_node *np,
71 ent = proc_mkdir(p, de); 102 ent = proc_mkdir(p, de);
72 if (ent == 0) 103 if (ent == 0)
73 break; 104 break;
74 *lastp = ent;
75 ent->next = NULL;
76 lastp = &ent->next;
77 proc_device_tree_add_node(child, ent); 105 proc_device_tree_add_node(child, ent);
78 } 106 }
79 of_node_put(child); 107 of_node_put(child);
@@ -84,7 +112,7 @@ void proc_device_tree_add_node(struct device_node *np,
84 * properties are quite unimportant for us though, thus we 112 * properties are quite unimportant for us though, thus we
85 * simply "skip" them here, but we do have to check. 113 * simply "skip" them here, but we do have to check.
86 */ 114 */
87 for (ent = list; ent != NULL; ent = ent->next) 115 for (ent = de->subdir; ent != NULL; ent = ent->next)
88 if (!strcmp(ent->name, pp->name)) 116 if (!strcmp(ent->name, pp->name))
89 break; 117 break;
90 if (ent != NULL) { 118 if (ent != NULL) {
@@ -94,25 +122,10 @@ void proc_device_tree_add_node(struct device_node *np,
94 continue; 122 continue;
95 } 123 }
96 124
97 /* 125 ent = __proc_device_tree_add_prop(de, pp);
98 * Unfortunately proc_register puts each new entry
99 * at the beginning of the list. So we rearrange them.
100 */
101 ent = create_proc_read_entry(pp->name,
102 strncmp(pp->name, "security-", 9)
103 ? S_IRUGO : S_IRUSR, de,
104 property_read_proc, pp);
105 if (ent == 0) 126 if (ent == 0)
106 break; 127 break;
107 if (!strncmp(pp->name, "security-", 9))
108 ent->size = 0; /* don't leak number of password chars */
109 else
110 ent->size = pp->length;
111 ent->next = NULL;
112 *lastp = ent;
113 lastp = &ent->next;
114 } 128 }
115 de->subdir = list;
116} 129}
117 130
118/* 131/*
diff --git a/include/asm-ppc/ide.h b/include/asm-powerpc/ide.h
index 7d6e6599fac4..da5f640480cf 100644
--- a/include/asm-ppc/ide.h
+++ b/include/asm-powerpc/ide.h
@@ -1,24 +1,27 @@
1/* 1/*
2 * linux/include/asm-ppc/ide.h 2 * Copyright (C) 1994-1996 Linus Torvalds & authors
3 * 3 *
4 * Copyright (C) 1994-1996 Linus Torvalds & authors */ 4 * This file contains the powerpc architecture specific IDE code.
5
6/*
7 * This file contains the ppc architecture specific IDE code.
8 */ 5 */
9 6#ifndef _ASM_POWERPC_IDE_H
10#ifndef __ASMPPC_IDE_H 7#define _ASM_POWERPC_IDE_H
11#define __ASMPPC_IDE_H
12 8
13#ifdef __KERNEL__ 9#ifdef __KERNEL__
14 10
11#ifndef __powerpc64__
15#include <linux/sched.h> 12#include <linux/sched.h>
16#include <asm/mpc8xx.h> 13#include <asm/mpc8xx.h>
14#endif
17 15
18#ifndef MAX_HWIFS 16#ifndef MAX_HWIFS
17#ifdef __powerpc64__
18#define MAX_HWIFS 10
19#else
19#define MAX_HWIFS 8 20#define MAX_HWIFS 8
20#endif 21#endif
22#endif
21 23
24#ifndef __powerpc64__
22#include <linux/config.h> 25#include <linux/config.h>
23#include <linux/hdreg.h> 26#include <linux/hdreg.h>
24#include <linux/ioport.h> 27#include <linux/ioport.h>
@@ -59,9 +62,6 @@ static __inline__ unsigned long ide_default_io_base(int index)
59 return 0; 62 return 0;
60} 63}
61 64
62#define IDE_ARCH_OBSOLETE_INIT
63#define ide_default_io_ctl(base) ((base) + 0x206) /* obsolete */
64
65#ifdef CONFIG_PCI 65#ifdef CONFIG_PCI
66#define ide_init_default_irq(base) (0) 66#define ide_init_default_irq(base) (0)
67#else 67#else
@@ -73,6 +73,11 @@ static __inline__ unsigned long ide_default_io_base(int index)
73#define ide_ack_intr(hwif) (hwif->hw.ack_intr ? hwif->hw.ack_intr(hwif) : 1) 73#define ide_ack_intr(hwif) (hwif->hw.ack_intr ? hwif->hw.ack_intr(hwif) : 1)
74#endif 74#endif
75 75
76#endif /* __powerpc64__ */
77
78#define IDE_ARCH_OBSOLETE_INIT
79#define ide_default_io_ctl(base) ((base) + 0x206) /* obsolete */
80
76#endif /* __KERNEL__ */ 81#endif /* __KERNEL__ */
77 82
78#endif /* __ASMPPC_IDE_H */ 83#endif /* _ASM_POWERPC_IDE_H */
diff --git a/include/asm-powerpc/machdep.h b/include/asm-powerpc/machdep.h
index fa03864d06eb..5670f0cd6143 100644
--- a/include/asm-powerpc/machdep.h
+++ b/include/asm-powerpc/machdep.h
@@ -82,7 +82,6 @@ struct machdep_calls {
82 void (*iommu_dev_setup)(struct pci_dev *dev); 82 void (*iommu_dev_setup)(struct pci_dev *dev);
83 void (*iommu_bus_setup)(struct pci_bus *bus); 83 void (*iommu_bus_setup)(struct pci_bus *bus);
84 void (*irq_bus_setup)(struct pci_bus *bus); 84 void (*irq_bus_setup)(struct pci_bus *bus);
85 int (*set_dabr)(unsigned long dabr);
86#endif 85#endif
87 86
88 int (*probe)(int platform); 87 int (*probe)(int platform);
@@ -158,6 +157,9 @@ struct machdep_calls {
158 platform, called once per cpu. */ 157 platform, called once per cpu. */
159 void (*enable_pmcs)(void); 158 void (*enable_pmcs)(void);
160 159
160 /* Set DABR for this platform, leave empty for default implemenation */
161 int (*set_dabr)(unsigned long dabr);
162
161#ifdef CONFIG_PPC32 /* XXX for now */ 163#ifdef CONFIG_PPC32 /* XXX for now */
162 /* A general init function, called by ppc_init in init/main.c. 164 /* A general init function, called by ppc_init in init/main.c.
163 May be NULL. */ 165 May be NULL. */
diff --git a/include/asm-powerpc/ppc-pci.h b/include/asm-powerpc/ppc-pci.h
index a88728fba8f6..13aacff755f3 100644
--- a/include/asm-powerpc/ppc-pci.h
+++ b/include/asm-powerpc/ppc-pci.h
@@ -34,6 +34,7 @@ void *traverse_pci_devices(struct device_node *start, traverse_func pre,
34 34
35void pci_devs_phb_init(void); 35void pci_devs_phb_init(void);
36void pci_devs_phb_init_dynamic(struct pci_controller *phb); 36void pci_devs_phb_init_dynamic(struct pci_controller *phb);
37void __devinit scan_phb(struct pci_controller *hose);
37 38
38/* PCI address cache management routines */ 39/* PCI address cache management routines */
39void pci_addr_cache_insert_device(struct pci_dev *dev); 40void pci_addr_cache_insert_device(struct pci_dev *dev);
diff --git a/include/asm-powerpc/prom.h b/include/asm-powerpc/prom.h
index 7587bf5f38c6..f999df1c5c90 100644
--- a/include/asm-powerpc/prom.h
+++ b/include/asm-powerpc/prom.h
@@ -203,7 +203,7 @@ extern int prom_n_addr_cells(struct device_node* np);
203extern int prom_n_size_cells(struct device_node* np); 203extern int prom_n_size_cells(struct device_node* np);
204extern int prom_n_intr_cells(struct device_node* np); 204extern int prom_n_intr_cells(struct device_node* np);
205extern void prom_get_irq_senses(unsigned char *senses, int off, int max); 205extern void prom_get_irq_senses(unsigned char *senses, int off, int max);
206extern void prom_add_property(struct device_node* np, struct property* prop); 206extern int prom_add_property(struct device_node* np, struct property* prop);
207 207
208#ifdef CONFIG_PPC32 208#ifdef CONFIG_PPC32
209/* 209/*
diff --git a/include/asm-powerpc/reg.h b/include/asm-powerpc/reg.h
index da848412f11b..489cf4c99c21 100644
--- a/include/asm-powerpc/reg.h
+++ b/include/asm-powerpc/reg.h
@@ -396,6 +396,9 @@
396#define SPRN_VRSAVE 0x100 /* Vector Register Save Register */ 396#define SPRN_VRSAVE 0x100 /* Vector Register Save Register */
397#define SPRN_XER 0x001 /* Fixed Point Exception Register */ 397#define SPRN_XER 0x001 /* Fixed Point Exception Register */
398 398
399#define SPRN_SCOMC 0x114 /* SCOM Access Control */
400#define SPRN_SCOMD 0x115 /* SCOM Access DATA */
401
399/* Performance monitor SPRs */ 402/* Performance monitor SPRs */
400#ifdef CONFIG_PPC64 403#ifdef CONFIG_PPC64
401#define SPRN_MMCR0 795 404#define SPRN_MMCR0 795
@@ -594,7 +597,11 @@ static inline void ppc64_runlatch_off(void)
594 mtspr(SPRN_CTRLT, ctrl); 597 mtspr(SPRN_CTRLT, ctrl);
595 } 598 }
596} 599}
597#endif 600
601extern unsigned long scom970_read(unsigned int address);
602extern void scom970_write(unsigned int address, unsigned long value);
603
604#endif /* CONFIG_PPC64 */
598 605
599#define __get_SP() ({unsigned long sp; \ 606#define __get_SP() ({unsigned long sp; \
600 asm volatile("mr %0,1": "=r" (sp)); sp;}) 607 asm volatile("mr %0,1": "=r" (sp)); sp;})
diff --git a/include/asm-powerpc/smp.h b/include/asm-powerpc/smp.h
index 8bcdd0faefea..98581e5a8279 100644
--- a/include/asm-powerpc/smp.h
+++ b/include/asm-powerpc/smp.h
@@ -86,7 +86,6 @@ extern void __cpu_die(unsigned int cpu);
86#else 86#else
87/* for UP */ 87/* for UP */
88#define smp_setup_cpu_maps() 88#define smp_setup_cpu_maps()
89#define smp_release_cpus()
90 89
91#endif /* CONFIG_SMP */ 90#endif /* CONFIG_SMP */
92 91
@@ -94,6 +93,9 @@ extern void __cpu_die(unsigned int cpu);
94#define get_hard_smp_processor_id(CPU) (paca[(CPU)].hw_cpu_id) 93#define get_hard_smp_processor_id(CPU) (paca[(CPU)].hw_cpu_id)
95#define set_hard_smp_processor_id(CPU, VAL) \ 94#define set_hard_smp_processor_id(CPU, VAL) \
96 do { (paca[(CPU)].hw_cpu_id = (VAL)); } while (0) 95 do { (paca[(CPU)].hw_cpu_id = (VAL)); } while (0)
96
97extern void smp_release_cpus(void);
98
97#else 99#else
98/* 32-bit */ 100/* 32-bit */
99#ifndef CONFIG_SMP 101#ifndef CONFIG_SMP
diff --git a/include/asm-powerpc/smu.h b/include/asm-powerpc/smu.h
index dee8eefe47bc..76c29a9784dd 100644
--- a/include/asm-powerpc/smu.h
+++ b/include/asm-powerpc/smu.h
@@ -20,16 +20,52 @@
20/* 20/*
21 * Partition info commands 21 * Partition info commands
22 * 22 *
23 * I do not know what those are for at this point 23 * These commands are used to retreive the sdb-partition-XX datas from
24 * the SMU. The lenght is always 2. First byte is the subcommand code
25 * and second byte is the partition ID.
26 *
27 * The reply is 6 bytes:
28 *
29 * - 0..1 : partition address
30 * - 2 : a byte containing the partition ID
31 * - 3 : length (maybe other bits are rest of header ?)
32 *
33 * The data must then be obtained with calls to another command:
34 * SMU_CMD_MISC_ee_GET_DATABLOCK_REC (described below).
24 */ 35 */
25#define SMU_CMD_PARTITION_COMMAND 0x3e 36#define SMU_CMD_PARTITION_COMMAND 0x3e
37#define SMU_CMD_PARTITION_LATEST 0x01
38#define SMU_CMD_PARTITION_BASE 0x02
39#define SMU_CMD_PARTITION_UPDATE 0x03
26 40
27 41
28/* 42/*
29 * Fan control 43 * Fan control
30 * 44 *
31 * This is a "mux" for fan control commands, first byte is the 45 * This is a "mux" for fan control commands. The command seem to
32 * "sub" command. 46 * act differently based on the number of arguments. With 1 byte
47 * of argument, this seem to be queries for fans status, setpoint,
48 * etc..., while with 0xe arguments, we will set the fans speeds.
49 *
50 * Queries (1 byte arg):
51 * ---------------------
52 *
53 * arg=0x01: read RPM fans status
54 * arg=0x02: read RPM fans setpoint
55 * arg=0x11: read PWM fans status
56 * arg=0x12: read PWM fans setpoint
57 *
58 * the "status" queries return the current speed while the "setpoint" ones
59 * return the programmed/target speed. It _seems_ that the result is a bit
60 * mask in the first byte of active/available fans, followed by 6 words (16
61 * bits) containing the requested speed.
62 *
63 * Setpoint (14 bytes arg):
64 * ------------------------
65 *
66 * first arg byte is 0 for RPM fans and 0x10 for PWM. Second arg byte is the
67 * mask of fans affected by the command. Followed by 6 words containing the
68 * setpoint value for selected fans in the mask (or 0 if mask value is 0)
33 */ 69 */
34#define SMU_CMD_FAN_COMMAND 0x4a 70#define SMU_CMD_FAN_COMMAND 0x4a
35 71
@@ -144,7 +180,11 @@
144 * - lenght 8 ("VSLEWxyz") has 3 additional bytes appended, and is 180 * - lenght 8 ("VSLEWxyz") has 3 additional bytes appended, and is
145 * used to set the voltage slewing point. The SMU replies with "DONE" 181 * used to set the voltage slewing point. The SMU replies with "DONE"
146 * I yet have to figure out their exact meaning of those 3 bytes in 182 * I yet have to figure out their exact meaning of those 3 bytes in
147 * both cases. 183 * both cases. They seem to be:
184 * x = processor mask
185 * y = op. point index
186 * z = processor freq. step index
187 * I haven't yet decyphered result codes
148 * 188 *
149 */ 189 */
150#define SMU_CMD_POWER_COMMAND 0xaa 190#define SMU_CMD_POWER_COMMAND 0xaa
@@ -152,6 +192,14 @@
152#define SMU_CMD_POWER_SHUTDOWN "SHUTDOWN" 192#define SMU_CMD_POWER_SHUTDOWN "SHUTDOWN"
153#define SMU_CMD_POWER_VOLTAGE_SLEW "VSLEW" 193#define SMU_CMD_POWER_VOLTAGE_SLEW "VSLEW"
154 194
195/*
196 * Read ADC sensors
197 *
198 * This command takes one byte of parameter: the sensor ID (or "reg"
199 * value in the device-tree) and returns a 16 bits value
200 */
201#define SMU_CMD_READ_ADC 0xd8
202
155/* Misc commands 203/* Misc commands
156 * 204 *
157 * This command seem to be a grab bag of various things 205 * This command seem to be a grab bag of various things
@@ -172,6 +220,25 @@
172 * Misc commands 220 * Misc commands
173 * 221 *
174 * This command seem to be a grab bag of various things 222 * This command seem to be a grab bag of various things
223 *
224 * SMU_CMD_MISC_ee_GET_DATABLOCK_REC is used, among others, to
225 * transfer blocks of data from the SMU. So far, I've decrypted it's
226 * usage to retreive partition data. In order to do that, you have to
227 * break your transfer in "chunks" since that command cannot transfer
228 * more than a chunk at a time. The chunk size used by OF is 0xe bytes,
229 * but it seems that the darwin driver will let you do 0x1e bytes if
230 * your "PMU" version is >= 0x30. You can get the "PMU" version apparently
231 * either in the last 16 bits of property "smu-version-pmu" or as the 16
232 * bytes at offset 1 of "smu-version-info"
233 *
234 * For each chunk, the command takes 7 bytes of arguments:
235 * byte 0: subcommand code (0x02)
236 * byte 1: 0x04 (always, I don't know what it means, maybe the address
237 * space to use or some other nicety. It's hard coded in OF)
238 * byte 2..5: SMU address of the chunk (big endian 32 bits)
239 * byte 6: size to transfer (up to max chunk size)
240 *
241 * The data is returned directly
175 */ 242 */
176#define SMU_CMD_MISC_ee_COMMAND 0xee 243#define SMU_CMD_MISC_ee_COMMAND 0xee
177#define SMU_CMD_MISC_ee_GET_DATABLOCK_REC 0x02 244#define SMU_CMD_MISC_ee_GET_DATABLOCK_REC 0x02
@@ -333,6 +400,128 @@ extern int smu_queue_i2c(struct smu_i2c_cmd *cmd);
333 400
334#endif /* __KERNEL__ */ 401#endif /* __KERNEL__ */
335 402
403
404/*
405 * - SMU "sdb" partitions informations -
406 */
407
408
409/*
410 * Partition header format
411 */
412struct smu_sdbp_header {
413 __u8 id;
414 __u8 len;
415 __u8 version;
416 __u8 flags;
417};
418
419
420 /*
421 * demangle 16 and 32 bits integer in some SMU partitions
422 * (currently, afaik, this concerns only the FVT partition
423 * (0x12)
424 */
425#define SMU_U16_MIX(x) le16_to_cpu(x);
426#define SMU_U32_MIX(x) ((((x) & 0xff00ff00u) >> 8)|(((x) & 0x00ff00ffu) << 8))
427
428
429/* This is the definition of the SMU sdb-partition-0x12 table (called
430 * CPU F/V/T operating points in Darwin). The definition for all those
431 * SMU tables should be moved to some separate file
432 */
433#define SMU_SDB_FVT_ID 0x12
434
435struct smu_sdbp_fvt {
436 __u32 sysclk; /* Base SysClk frequency in Hz for
437 * this operating point. Value need to
438 * be unmixed with SMU_U32_MIX()
439 */
440 __u8 pad;
441 __u8 maxtemp; /* Max temp. supported by this
442 * operating point
443 */
444
445 __u16 volts[3]; /* CPU core voltage for the 3
446 * PowerTune modes, a mode with
447 * 0V = not supported. Value need
448 * to be unmixed with SMU_U16_MIX()
449 */
450};
451
452/* This partition contains voltage & current sensor calibration
453 * informations
454 */
455#define SMU_SDB_CPUVCP_ID 0x21
456
457struct smu_sdbp_cpuvcp {
458 __u16 volt_scale; /* u4.12 fixed point */
459 __s16 volt_offset; /* s4.12 fixed point */
460 __u16 curr_scale; /* u4.12 fixed point */
461 __s16 curr_offset; /* s4.12 fixed point */
462 __s32 power_quads[3]; /* s4.28 fixed point */
463};
464
465/* This partition contains CPU thermal diode calibration
466 */
467#define SMU_SDB_CPUDIODE_ID 0x18
468
469struct smu_sdbp_cpudiode {
470 __u16 m_value; /* u1.15 fixed point */
471 __s16 b_value; /* s10.6 fixed point */
472
473};
474
475/* This partition contains Slots power calibration
476 */
477#define SMU_SDB_SLOTSPOW_ID 0x78
478
479struct smu_sdbp_slotspow {
480 __u16 pow_scale; /* u4.12 fixed point */
481 __s16 pow_offset; /* s4.12 fixed point */
482};
483
484/* This partition contains machine specific version information about
485 * the sensor/control layout
486 */
487#define SMU_SDB_SENSORTREE_ID 0x25
488
489struct smu_sdbp_sensortree {
490 u8 model_id;
491 u8 unknown[3];
492};
493
494/* This partition contains CPU thermal control PID informations. So far
495 * only single CPU machines have been seen with an SMU, so we assume this
496 * carries only informations for those
497 */
498#define SMU_SDB_CPUPIDDATA_ID 0x17
499
500struct smu_sdbp_cpupiddata {
501 u8 unknown1;
502 u8 target_temp_delta;
503 u8 unknown2;
504 u8 history_len;
505 s16 power_adj;
506 u16 max_power;
507 s32 gp,gr,gd;
508};
509
510
511/* Other partitions without known structures */
512#define SMU_SDB_DEBUG_SWITCHES_ID 0x05
513
514#ifdef __KERNEL__
515/*
516 * This returns the pointer to an SMU "sdb" partition data or NULL
517 * if not found. The data format is described below
518 */
519extern struct smu_sdbp_header *smu_get_sdb_partition(int id,
520 unsigned int *size);
521
522#endif /* __KERNEL__ */
523
524
336/* 525/*
337 * - Userland interface - 526 * - Userland interface -
338 */ 527 */
@@ -365,8 +554,10 @@ struct smu_user_cmd_hdr
365 __u32 cmdtype; 554 __u32 cmdtype;
366#define SMU_CMDTYPE_SMU 0 /* SMU command */ 555#define SMU_CMDTYPE_SMU 0 /* SMU command */
367#define SMU_CMDTYPE_WANTS_EVENTS 1 /* switch fd to events mode */ 556#define SMU_CMDTYPE_WANTS_EVENTS 1 /* switch fd to events mode */
557#define SMU_CMDTYPE_GET_PARTITION 2 /* retreive an sdb partition */
368 558
369 __u8 cmd; /* SMU command byte */ 559 __u8 cmd; /* SMU command byte */
560 __u8 pad[3]; /* padding */
370 __u32 data_len; /* Lenght of data following */ 561 __u32 data_len; /* Lenght of data following */
371}; 562};
372 563
diff --git a/include/asm-powerpc/xmon.h b/include/asm-powerpc/xmon.h
index 43f7129984c7..ace2072d4a83 100644
--- a/include/asm-powerpc/xmon.h
+++ b/include/asm-powerpc/xmon.h
@@ -7,6 +7,7 @@ struct pt_regs;
7extern int xmon(struct pt_regs *excp); 7extern int xmon(struct pt_regs *excp);
8extern void xmon_printf(const char *fmt, ...); 8extern void xmon_printf(const char *fmt, ...);
9extern void xmon_init(int); 9extern void xmon_init(int);
10extern void xmon_map_scc(void);
10 11
11#endif 12#endif
12#endif 13#endif
diff --git a/include/asm-ppc/btext.h b/include/asm-ppc/btext.h
index 36c7640d00f2..ccaefabe0bf5 100644
--- a/include/asm-ppc/btext.h
+++ b/include/asm-ppc/btext.h
@@ -17,18 +17,18 @@ extern unsigned long disp_BAT[2];
17extern boot_infos_t disp_bi; 17extern boot_infos_t disp_bi;
18extern int boot_text_mapped; 18extern int boot_text_mapped;
19 19
20void btext_init(boot_infos_t *bi); 20extern void init_boot_display(void);
21void btext_welcome(void); 21extern void btext_welcome(void);
22void btext_prepare_BAT(void); 22extern void btext_prepare_BAT(void);
23void btext_setup_display(int width, int height, int depth, int pitch, 23extern void btext_setup_display(int width, int height, int depth, int pitch,
24 unsigned long address); 24 unsigned long address);
25void map_boot_text(void); 25extern void map_boot_text(void);
26void btext_update_display(unsigned long phys, int width, int height, 26extern void btext_update_display(unsigned long phys, int width, int height,
27 int depth, int pitch); 27 int depth, int pitch);
28 28
29void btext_drawchar(char c); 29extern void btext_drawchar(char c);
30void btext_drawstring(const char *str); 30extern void btext_drawstring(const char *str);
31void btext_drawhex(unsigned long v); 31extern void btext_drawhex(unsigned long v);
32 32
33#endif /* __KERNEL__ */ 33#endif /* __KERNEL__ */
34#endif /* __PPC_BTEXT_H */ 34#endif /* __PPC_BTEXT_H */
diff --git a/include/asm-ppc/io.h b/include/asm-ppc/io.h
index f7f614dfc648..2bfdf9c98459 100644
--- a/include/asm-ppc/io.h
+++ b/include/asm-ppc/io.h
@@ -237,9 +237,9 @@ static inline void __raw_writel(__u32 b, volatile void __iomem *addr)
237#define outsl(port, buf, nl) _outsl_ns((port)+___IO_BASE, (buf), (nl)) 237#define outsl(port, buf, nl) _outsl_ns((port)+___IO_BASE, (buf), (nl))
238 238
239/* 239/*
240 * On powermacs, we will get a machine check exception if we 240 * On powermacs and 8xx we will get a machine check exception
241 * try to read data from a non-existent I/O port. Because the 241 * if we try to read data from a non-existent I/O port. Because
242 * machine check is an asynchronous exception, it isn't 242 * the machine check is an asynchronous exception, it isn't
243 * well-defined which instruction SRR0 will point to when the 243 * well-defined which instruction SRR0 will point to when the
244 * exception occurs. 244 * exception occurs.
245 * With the sequence below (twi; isync; nop), we have found that 245 * With the sequence below (twi; isync; nop), we have found that
@@ -258,7 +258,7 @@ extern __inline__ unsigned int name(unsigned int port) \
258{ \ 258{ \
259 unsigned int x; \ 259 unsigned int x; \
260 __asm__ __volatile__( \ 260 __asm__ __volatile__( \
261 op " %0,0,%1\n" \ 261 "0:" op " %0,0,%1\n" \
262 "1: twi 0,%0,0\n" \ 262 "1: twi 0,%0,0\n" \
263 "2: isync\n" \ 263 "2: isync\n" \
264 "3: nop\n" \ 264 "3: nop\n" \
@@ -269,6 +269,7 @@ extern __inline__ unsigned int name(unsigned int port) \
269 ".previous\n" \ 269 ".previous\n" \
270 ".section __ex_table,\"a\"\n" \ 270 ".section __ex_table,\"a\"\n" \
271 " .align 2\n" \ 271 " .align 2\n" \
272 " .long 0b,5b\n" \
272 " .long 1b,5b\n" \ 273 " .long 1b,5b\n" \
273 " .long 2b,5b\n" \ 274 " .long 2b,5b\n" \
274 " .long 3b,5b\n" \ 275 " .long 3b,5b\n" \
@@ -282,11 +283,12 @@ extern __inline__ unsigned int name(unsigned int port) \
282extern __inline__ void name(unsigned int val, unsigned int port) \ 283extern __inline__ void name(unsigned int val, unsigned int port) \
283{ \ 284{ \
284 __asm__ __volatile__( \ 285 __asm__ __volatile__( \
285 op " %0,0,%1\n" \ 286 "0:" op " %0,0,%1\n" \
286 "1: sync\n" \ 287 "1: sync\n" \
287 "2:\n" \ 288 "2:\n" \
288 ".section __ex_table,\"a\"\n" \ 289 ".section __ex_table,\"a\"\n" \
289 " .align 2\n" \ 290 " .align 2\n" \
291 " .long 0b,2b\n" \
290 " .long 1b,2b\n" \ 292 " .long 1b,2b\n" \
291 ".previous" \ 293 ".previous" \
292 : : "r" (val), "r" (port + ___IO_BASE)); \ 294 : : "r" (val), "r" (port + ___IO_BASE)); \
diff --git a/include/asm-ppc/kgdb.h b/include/asm-ppc/kgdb.h
index 1d3c927ce626..b617dac82969 100644
--- a/include/asm-ppc/kgdb.h
+++ b/include/asm-ppc/kgdb.h
@@ -31,7 +31,7 @@ extern void breakpoint(void);
31/* For taking exceptions 31/* For taking exceptions
32 * these are defined in traps.c 32 * these are defined in traps.c
33 */ 33 */
34extern void (*debugger)(struct pt_regs *regs); 34extern int (*debugger)(struct pt_regs *regs);
35extern int (*debugger_bpt)(struct pt_regs *regs); 35extern int (*debugger_bpt)(struct pt_regs *regs);
36extern int (*debugger_sstep)(struct pt_regs *regs); 36extern int (*debugger_sstep)(struct pt_regs *regs);
37extern int (*debugger_iabr_match)(struct pt_regs *regs); 37extern int (*debugger_iabr_match)(struct pt_regs *regs);
diff --git a/include/asm-ppc/prom.h b/include/asm-ppc/prom.h
index 75c0637acdc8..3e39827ed566 100644
--- a/include/asm-ppc/prom.h
+++ b/include/asm-ppc/prom.h
@@ -93,7 +93,7 @@ extern int device_is_compatible(struct device_node *device, const char *);
93extern int machine_is_compatible(const char *compat); 93extern int machine_is_compatible(const char *compat);
94extern unsigned char *get_property(struct device_node *node, const char *name, 94extern unsigned char *get_property(struct device_node *node, const char *name,
95 int *lenp); 95 int *lenp);
96extern void prom_add_property(struct device_node* np, struct property* prop); 96extern int prom_add_property(struct device_node* np, struct property* prop);
97extern void prom_get_irq_senses(unsigned char *, int, int); 97extern void prom_get_irq_senses(unsigned char *, int, int);
98extern int prom_n_addr_cells(struct device_node* np); 98extern int prom_n_addr_cells(struct device_node* np);
99extern int prom_n_size_cells(struct device_node* np); 99extern int prom_n_size_cells(struct device_node* np);
diff --git a/include/asm-ppc64/ide.h b/include/asm-ppc64/ide.h
deleted file mode 100644
index 0aae1c590c0e..000000000000
--- a/include/asm-ppc64/ide.h
+++ /dev/null
@@ -1,30 +0,0 @@
1/*
2 * linux/include/asm-ppc/ide.h
3 *
4 * Copyright (C) 1994-1996 Linus Torvalds & authors
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11
12/*
13 * This file contains the ppc64 architecture specific IDE code.
14 */
15
16#ifndef __ASMPPC64_IDE_H
17#define __ASMPPC64_IDE_H
18
19#ifdef __KERNEL__
20
21#ifndef MAX_HWIFS
22# define MAX_HWIFS 10
23#endif
24
25#define IDE_ARCH_OBSOLETE_INIT
26#define ide_default_io_ctl(base) ((base) + 0x206) /* obsolete */
27
28#endif /* __KERNEL__ */
29
30#endif /* __ASMPPC64_IDE_H */
diff --git a/include/asm-ppc64/pci.h b/include/asm-ppc64/pci.h
index 342e2d755550..fafdf885a3cc 100644
--- a/include/asm-ppc64/pci.h
+++ b/include/asm-ppc64/pci.h
@@ -162,6 +162,14 @@ pcibios_fixup_device_resources(struct pci_dev *dev, struct pci_bus *bus);
162 162
163extern struct pci_controller *init_phb_dynamic(struct device_node *dn); 163extern struct pci_controller *init_phb_dynamic(struct device_node *dn);
164 164
165extern struct pci_dev *of_create_pci_dev(struct device_node *node,
166 struct pci_bus *bus, int devfn);
167
168extern void of_scan_pci_bridge(struct device_node *node,
169 struct pci_dev *dev);
170
171extern void of_scan_bus(struct device_node *node, struct pci_bus *bus);
172
165extern int pci_read_irq_line(struct pci_dev *dev); 173extern int pci_read_irq_line(struct pci_dev *dev);
166 174
167extern void pcibios_add_platform_entries(struct pci_dev *dev); 175extern void pcibios_add_platform_entries(struct pci_dev *dev);
diff --git a/include/asm-ppc64/ppcdebug.h b/include/asm-ppc64/ppcdebug.h
deleted file mode 100644
index fd7f696065c4..000000000000
--- a/include/asm-ppc64/ppcdebug.h
+++ /dev/null
@@ -1,108 +0,0 @@
1#ifndef __PPCDEBUG_H
2#define __PPCDEBUG_H
3/********************************************************************
4 * Author: Adam Litke, IBM Corp
5 * (c) 2001
6 *
7 * This file contains definitions and macros for a runtime debugging
8 * system for ppc64 (This should also work on 32 bit with a few
9 * adjustments.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version
14 * 2 of the License, or (at your option) any later version.
15 *
16 ********************************************************************/
17
18#include <linux/config.h>
19#include <linux/types.h>
20#include <asm/udbg.h>
21#include <stdarg.h>
22
23#define PPCDBG_BITVAL(X) ((1UL)<<((unsigned long)(X)))
24
25/* Defined below are the bit positions of various debug flags in the
26 * ppc64_debug_switch variable.
27 * -- When adding new values, please enter them into trace names below --
28 *
29 * Values 62 & 63 can be used to stress the hardware page table management
30 * code. They must be set statically, any attempt to change them dynamically
31 * would be a very bad idea.
32 */
33#define PPCDBG_MMINIT PPCDBG_BITVAL(0)
34#define PPCDBG_MM PPCDBG_BITVAL(1)
35#define PPCDBG_SYS32 PPCDBG_BITVAL(2)
36#define PPCDBG_SYS32NI PPCDBG_BITVAL(3)
37#define PPCDBG_SYS32X PPCDBG_BITVAL(4)
38#define PPCDBG_SYS32M PPCDBG_BITVAL(5)
39#define PPCDBG_SYS64 PPCDBG_BITVAL(6)
40#define PPCDBG_SYS64NI PPCDBG_BITVAL(7)
41#define PPCDBG_SYS64X PPCDBG_BITVAL(8)
42#define PPCDBG_SIGNAL PPCDBG_BITVAL(9)
43#define PPCDBG_SIGNALXMON PPCDBG_BITVAL(10)
44#define PPCDBG_BINFMT32 PPCDBG_BITVAL(11)
45#define PPCDBG_BINFMT64 PPCDBG_BITVAL(12)
46#define PPCDBG_BINFMTXMON PPCDBG_BITVAL(13)
47#define PPCDBG_BINFMT_32ADDR PPCDBG_BITVAL(14)
48#define PPCDBG_ALIGNFIXUP PPCDBG_BITVAL(15)
49#define PPCDBG_TCEINIT PPCDBG_BITVAL(16)
50#define PPCDBG_TCE PPCDBG_BITVAL(17)
51#define PPCDBG_PHBINIT PPCDBG_BITVAL(18)
52#define PPCDBG_SMP PPCDBG_BITVAL(19)
53#define PPCDBG_BOOT PPCDBG_BITVAL(20)
54#define PPCDBG_BUSWALK PPCDBG_BITVAL(21)
55#define PPCDBG_PROM PPCDBG_BITVAL(22)
56#define PPCDBG_RTAS PPCDBG_BITVAL(23)
57#define PPCDBG_HTABSTRESS PPCDBG_BITVAL(62)
58#define PPCDBG_HTABSIZE PPCDBG_BITVAL(63)
59#define PPCDBG_NONE (0UL)
60#define PPCDBG_ALL (0xffffffffUL)
61
62/* The default initial value for the debug switch */
63#define PPC_DEBUG_DEFAULT 0
64/* #define PPC_DEBUG_DEFAULT PPCDBG_ALL */
65
66#define PPCDBG_NUM_FLAGS 64
67
68extern u64 ppc64_debug_switch;
69
70#ifdef WANT_PPCDBG_TAB
71/* A table of debug switch names to allow name lookup in xmon
72 * (and whoever else wants it.
73 */
74char *trace_names[PPCDBG_NUM_FLAGS] = {
75 /* Known debug names */
76 "mminit", "mm",
77 "syscall32", "syscall32_ni", "syscall32x", "syscall32m",
78 "syscall64", "syscall64_ni", "syscall64x",
79 "signal", "signal_xmon",
80 "binfmt32", "binfmt64", "binfmt_xmon", "binfmt_32addr",
81 "alignfixup", "tceinit", "tce", "phb_init",
82 "smp", "boot", "buswalk", "prom",
83 "rtas"
84};
85#else
86extern char *trace_names[64];
87#endif /* WANT_PPCDBG_TAB */
88
89#ifdef CONFIG_PPCDBG
90/* Macro to conditionally print debug based on debug_switch */
91#define PPCDBG(...) udbg_ppcdbg(__VA_ARGS__)
92
93/* Macro to conditionally call a debug routine based on debug_switch */
94#define PPCDBGCALL(FLAGS,FUNCTION) ifppcdebug(FLAGS) FUNCTION
95
96/* Macros to test for debug states */
97#define ifppcdebug(FLAGS) if (udbg_ifdebug(FLAGS))
98#define ppcdebugset(FLAGS) (udbg_ifdebug(FLAGS))
99#define PPCDBG_BINFMT (test_thread_flag(TIF_32BIT) ? PPCDBG_BINFMT32 : PPCDBG_BINFMT64)
100
101#else
102#define PPCDBG(...) do {;} while (0)
103#define PPCDBGCALL(FLAGS,FUNCTION) do {;} while (0)
104#define ifppcdebug(...) if (0)
105#define ppcdebugset(FLAGS) (0)
106#endif /* CONFIG_PPCDBG */
107
108#endif /*__PPCDEBUG_H */
diff --git a/include/asm-ppc64/prom.h b/include/asm-ppc64/prom.h
index bdb47174ff0e..76bb0266d67c 100644
--- a/include/asm-ppc64/prom.h
+++ b/include/asm-ppc64/prom.h
@@ -213,6 +213,6 @@ extern int prom_n_addr_cells(struct device_node* np);
213extern int prom_n_size_cells(struct device_node* np); 213extern int prom_n_size_cells(struct device_node* np);
214extern int prom_n_intr_cells(struct device_node* np); 214extern int prom_n_intr_cells(struct device_node* np);
215extern void prom_get_irq_senses(unsigned char *senses, int off, int max); 215extern void prom_get_irq_senses(unsigned char *senses, int off, int max);
216extern void prom_add_property(struct device_node* np, struct property* prop); 216extern int prom_add_property(struct device_node* np, struct property* prop);
217 217
218#endif /* _PPC64_PROM_H */ 218#endif /* _PPC64_PROM_H */
diff --git a/include/asm-ppc64/udbg.h b/include/asm-ppc64/udbg.h
index 8192fb8541cc..e3b927991851 100644
--- a/include/asm-ppc64/udbg.h
+++ b/include/asm-ppc64/udbg.h
@@ -23,9 +23,6 @@ extern int udbg_read(char *buf, int buflen);
23 23
24extern void register_early_udbg_console(void); 24extern void register_early_udbg_console(void);
25extern void udbg_printf(const char *fmt, ...); 25extern void udbg_printf(const char *fmt, ...);
26extern void udbg_ppcdbg(unsigned long flags, const char *fmt, ...);
27extern unsigned long udbg_ifdebug(unsigned long flags);
28extern void __init ppcdbg_initialize(void);
29 26
30extern void udbg_init_uart(void __iomem *comport, unsigned int speed); 27extern void udbg_init_uart(void __iomem *comport, unsigned int speed);
31 28
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index 0563581e3a02..65ceeaa30652 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -139,15 +139,12 @@ extern void proc_tty_unregister_driver(struct tty_driver *driver);
139/* 139/*
140 * proc_devtree.c 140 * proc_devtree.c
141 */ 141 */
142#ifdef CONFIG_PROC_DEVICETREE
142struct device_node; 143struct device_node;
144struct property;
143extern void proc_device_tree_init(void); 145extern void proc_device_tree_init(void);
144#ifdef CONFIG_PROC_DEVICETREE
145extern void proc_device_tree_add_node(struct device_node *, struct proc_dir_entry *); 146extern void proc_device_tree_add_node(struct device_node *, struct proc_dir_entry *);
146#else /* !CONFIG_PROC_DEVICETREE */ 147extern void proc_device_tree_add_prop(struct proc_dir_entry *pde, struct property *prop);
147static inline void proc_device_tree_add_node(struct device_node *np, struct proc_dir_entry *pde)
148{
149 return;
150}
151#endif /* CONFIG_PROC_DEVICETREE */ 148#endif /* CONFIG_PROC_DEVICETREE */
152 149
153extern struct proc_dir_entry *proc_symlink(const char *, 150extern struct proc_dir_entry *proc_symlink(const char *,