diff options
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 | ||
407 | config 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 | |||
407 | config PPC601_SYNC_FIX | 415 | config 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" | |||
484 | config FORCE_MAX_ZONEORDER | 492 | config 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 | ||
489 | config MATH_EMULATION | 498 | config 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 | # |
6 | CONFIG_PPC64=y | ||
6 | CONFIG_64BIT=y | 7 | CONFIG_64BIT=y |
8 | CONFIG_PPC_MERGE=y | ||
7 | CONFIG_MMU=y | 9 | CONFIG_MMU=y |
10 | CONFIG_GENERIC_HARDIRQS=y | ||
8 | CONFIG_RWSEM_XCHGADD_ALGORITHM=y | 11 | CONFIG_RWSEM_XCHGADD_ALGORITHM=y |
9 | CONFIG_GENERIC_CALIBRATE_DELAY=y | 12 | CONFIG_GENERIC_CALIBRATE_DELAY=y |
10 | CONFIG_GENERIC_ISA_DMA=y | 13 | CONFIG_PPC=y |
11 | CONFIG_EARLY_PRINTK=y | 14 | CONFIG_EARLY_PRINTK=y |
12 | CONFIG_COMPAT=y | 15 | CONFIG_COMPAT=y |
16 | CONFIG_SYSVIPC_COMPAT=y | ||
13 | CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y | 17 | CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y |
14 | CONFIG_ARCH_MAY_HAVE_PC_FDC=y | 18 | CONFIG_ARCH_MAY_HAVE_PC_FDC=y |
15 | CONFIG_FORCE_MAX_ZONEORDER=13 | 19 | |
20 | # | ||
21 | # Processor support | ||
22 | # | ||
23 | CONFIG_POWER4_ONLY=y | ||
24 | CONFIG_POWER4=y | ||
25 | CONFIG_PPC_FPU=y | ||
26 | CONFIG_ALTIVEC=y | ||
27 | CONFIG_PPC_STD_MMU=y | ||
28 | CONFIG_SMP=y | ||
29 | CONFIG_NR_CPUS=2 | ||
16 | 30 | ||
17 | # | 31 | # |
18 | # Code maturity level options | 32 | # Code maturity level options |
@@ -67,30 +81,60 @@ CONFIG_MODVERSIONS=y | |||
67 | CONFIG_MODULE_SRCVERSION_ALL=y | 81 | CONFIG_MODULE_SRCVERSION_ALL=y |
68 | CONFIG_KMOD=y | 82 | CONFIG_KMOD=y |
69 | CONFIG_STOP_MACHINE=y | 83 | CONFIG_STOP_MACHINE=y |
70 | CONFIG_SYSVIPC_COMPAT=y | ||
71 | 84 | ||
72 | # | 85 | # |
73 | # Platform support | 86 | # Platform support |
74 | # | 87 | # |
75 | # CONFIG_PPC_ISERIES is not set | ||
76 | CONFIG_PPC_MULTIPLATFORM=y | 88 | CONFIG_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 | ||
79 | CONFIG_PPC_PMAC=y | 93 | CONFIG_PPC_PMAC=y |
94 | CONFIG_PPC_PMAC64=y | ||
80 | # CONFIG_PPC_MAPLE is not set | 95 | # CONFIG_PPC_MAPLE is not set |
81 | CONFIG_PPC=y | 96 | # CONFIG_PPC_CELL is not set |
82 | CONFIG_PPC64=y | ||
83 | CONFIG_PPC_OF=y | 97 | CONFIG_PPC_OF=y |
84 | CONFIG_MPIC=y | ||
85 | CONFIG_ALTIVEC=y | ||
86 | CONFIG_KEXEC=y | ||
87 | CONFIG_U3_DART=y | 98 | CONFIG_U3_DART=y |
88 | CONFIG_PPC_PMAC64=y | 99 | CONFIG_MPIC=y |
89 | CONFIG_BOOTX_TEXT=y | 100 | # CONFIG_PPC_RTAS is not set |
90 | CONFIG_POWER4_ONLY=y | 101 | # CONFIG_MMIO_NVRAM is not set |
102 | # CONFIG_PPC_MPC106 is not set | ||
103 | CONFIG_GENERIC_TBSYNC=y | ||
104 | CONFIG_CPU_FREQ=y | ||
105 | CONFIG_CPU_FREQ_TABLE=y | ||
106 | # CONFIG_CPU_FREQ_DEBUG is not set | ||
107 | CONFIG_CPU_FREQ_STAT=y | ||
108 | # CONFIG_CPU_FREQ_STAT_DETAILS is not set | ||
109 | CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y | ||
110 | # CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set | ||
111 | CONFIG_CPU_FREQ_GOV_PERFORMANCE=y | ||
112 | CONFIG_CPU_FREQ_GOV_POWERSAVE=y | ||
113 | CONFIG_CPU_FREQ_GOV_USERSPACE=y | ||
114 | # CONFIG_CPU_FREQ_GOV_ONDEMAND is not set | ||
115 | # CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set | ||
116 | CONFIG_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 | ||
123 | CONFIG_HZ_250=y | ||
124 | # CONFIG_HZ_1000 is not set | ||
125 | CONFIG_HZ=250 | ||
126 | CONFIG_PREEMPT_NONE=y | ||
127 | # CONFIG_PREEMPT_VOLUNTARY is not set | ||
128 | # CONFIG_PREEMPT is not set | ||
129 | # CONFIG_PREEMPT_BKL is not set | ||
130 | CONFIG_BINFMT_ELF=y | ||
131 | # CONFIG_BINFMT_MISC is not set | ||
132 | CONFIG_FORCE_MAX_ZONEORDER=13 | ||
91 | CONFIG_IOMMU_VMERGE=y | 133 | CONFIG_IOMMU_VMERGE=y |
92 | CONFIG_SMP=y | 134 | # CONFIG_HOTPLUG_CPU is not set |
93 | CONFIG_NR_CPUS=2 | 135 | CONFIG_KEXEC=y |
136 | CONFIG_IRQ_ALL_CPUS=y | ||
137 | # CONFIG_NUMA is not set | ||
94 | CONFIG_ARCH_SELECT_MEMORY_MODEL=y | 138 | CONFIG_ARCH_SELECT_MEMORY_MODEL=y |
95 | CONFIG_ARCH_FLATMEM_ENABLE=y | 139 | CONFIG_ARCH_FLATMEM_ENABLE=y |
96 | CONFIG_SELECT_MEMORY_MODEL=y | 140 | CONFIG_SELECT_MEMORY_MODEL=y |
@@ -100,28 +144,21 @@ CONFIG_FLATMEM_MANUAL=y | |||
100 | CONFIG_FLATMEM=y | 144 | CONFIG_FLATMEM=y |
101 | CONFIG_FLAT_NODE_MEM_MAP=y | 145 | CONFIG_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 | 147 | CONFIG_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 |
105 | CONFIG_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 | ||
110 | CONFIG_HZ_250=y | ||
111 | # CONFIG_HZ_1000 is not set | ||
112 | CONFIG_HZ=250 | ||
113 | CONFIG_GENERIC_HARDIRQS=y | ||
114 | CONFIG_SECCOMP=y | ||
115 | CONFIG_BINFMT_ELF=y | ||
116 | # CONFIG_BINFMT_MISC is not set | ||
117 | # CONFIG_HOTPLUG_CPU is not set | ||
118 | CONFIG_PROC_DEVICETREE=y | 150 | CONFIG_PROC_DEVICETREE=y |
119 | # CONFIG_CMDLINE_BOOL is not set | 151 | # CONFIG_CMDLINE_BOOL is not set |
152 | # CONFIG_PM is not set | ||
153 | CONFIG_SECCOMP=y | ||
120 | CONFIG_ISA_DMA_API=y | 154 | CONFIG_ISA_DMA_API=y |
121 | 155 | ||
122 | # | 156 | # |
123 | # Bus Options | 157 | # Bus options |
124 | # | 158 | # |
159 | CONFIG_GENERIC_ISA_DMA=y | ||
160 | # CONFIG_PPC_I8259 is not set | ||
161 | # CONFIG_PPC_INDIRECT_PCI is not set | ||
125 | CONFIG_PCI=y | 162 | CONFIG_PCI=y |
126 | CONFIG_PCI_DOMAINS=y | 163 | CONFIG_PCI_DOMAINS=y |
127 | CONFIG_PCI_LEGACY_PROC=y | 164 | CONFIG_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 |
176 | CONFIG_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 |
280 | CONFIG_NET_CLS_ROUTE=y | 322 | CONFIG_NET_CLS_ROUTE=y |
281 | 323 | ||
@@ -348,6 +390,11 @@ CONFIG_IOSCHED_NOOP=y | |||
348 | CONFIG_IOSCHED_AS=y | 390 | CONFIG_IOSCHED_AS=y |
349 | CONFIG_IOSCHED_DEADLINE=y | 391 | CONFIG_IOSCHED_DEADLINE=y |
350 | CONFIG_IOSCHED_CFQ=y | 392 | CONFIG_IOSCHED_CFQ=y |
393 | CONFIG_DEFAULT_AS=y | ||
394 | # CONFIG_DEFAULT_DEADLINE is not set | ||
395 | # CONFIG_DEFAULT_CFQ is not set | ||
396 | # CONFIG_DEFAULT_NOOP is not set | ||
397 | CONFIG_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 | |||
567 | CONFIG_ADB_PMU=y | 617 | CONFIG_ADB_PMU=y |
568 | CONFIG_PMAC_SMU=y | 618 | CONFIG_PMAC_SMU=y |
569 | CONFIG_THERM_PM72=y | 619 | CONFIG_THERM_PM72=y |
620 | CONFIG_WINDFARM=y | ||
621 | CONFIG_WINDFARM_PM81=y | ||
622 | CONFIG_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 | 935 | CONFIG_FB_NVIDIA=y |
880 | CONFIG_FB_RIVA=y | 936 | CONFIG_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 |
885 | CONFIG_FB_RADEON=y | 940 | CONFIG_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 | 982 | CONFIG_SOUND=m |
983 | |||
984 | # | ||
985 | # Advanced Linux Sound Architecture | ||
986 | # | ||
987 | CONFIG_SND=m | ||
988 | CONFIG_SND_TIMER=m | ||
989 | CONFIG_SND_PCM=m | ||
990 | CONFIG_SND_HWDEP=m | ||
991 | CONFIG_SND_RAWMIDI=m | ||
992 | CONFIG_SND_SEQUENCER=m | ||
993 | # CONFIG_SND_SEQ_DUMMY is not set | ||
994 | CONFIG_SND_OSSEMUL=y | ||
995 | CONFIG_SND_MIXER_OSS=m | ||
996 | CONFIG_SND_PCM_OSS=m | ||
997 | CONFIG_SND_SEQUENCER_OSS=y | ||
998 | # CONFIG_SND_VERBOSE_PRINTK is not set | ||
999 | # CONFIG_SND_DEBUG is not set | ||
1000 | CONFIG_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 | # | ||
1059 | CONFIG_SND_POWERMAC=m | ||
1060 | CONFIG_SND_POWERMAC_AUTO_DRC=y | ||
1061 | |||
1062 | # | ||
1063 | # USB devices | ||
1064 | # | ||
1065 | CONFIG_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 |
962 | CONFIG_USB_ACM=m | 1106 | CONFIG_USB_ACM=m |
963 | CONFIG_USB_PRINTER=y | 1107 | CONFIG_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 | # |
968 | CONFIG_USB_STORAGE=y | 1116 | CONFIG_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 | |||
1074 | CONFIG_USB_SERIAL_KLSI=m | 1222 | CONFIG_USB_SERIAL_KLSI=m |
1075 | CONFIG_USB_SERIAL_KOBIL_SCT=m | 1223 | CONFIG_USB_SERIAL_KOBIL_SCT=m |
1076 | CONFIG_USB_SERIAL_MCT_U232=m | 1224 | CONFIG_USB_SERIAL_MCT_U232=m |
1225 | # CONFIG_USB_SERIAL_NOKIA_DKU2 is not set | ||
1077 | CONFIG_USB_SERIAL_PL2303=m | 1226 | CONFIG_USB_SERIAL_PL2303=m |
1078 | # CONFIG_USB_SERIAL_HP4X is not set | 1227 | # CONFIG_USB_SERIAL_HP4X is not set |
1079 | CONFIG_USB_SERIAL_SAFE=m | 1228 | CONFIG_USB_SERIAL_SAFE=m |
@@ -1311,6 +1460,20 @@ CONFIG_NLS_ISO8859_15=y | |||
1311 | CONFIG_NLS_UTF8=y | 1460 | CONFIG_NLS_UTF8=y |
1312 | 1461 | ||
1313 | # | 1462 | # |
1463 | # Library routines | ||
1464 | # | ||
1465 | CONFIG_CRC_CCITT=m | ||
1466 | # CONFIG_CRC16 is not set | ||
1467 | CONFIG_CRC32=y | ||
1468 | CONFIG_LIBCRC32C=m | ||
1469 | CONFIG_ZLIB_INFLATE=y | ||
1470 | CONFIG_ZLIB_DEFLATE=m | ||
1471 | CONFIG_TEXTSEARCH=y | ||
1472 | CONFIG_TEXTSEARCH_KMP=m | ||
1473 | CONFIG_TEXTSEARCH_BM=m | ||
1474 | CONFIG_TEXTSEARCH_FSM=m | ||
1475 | |||
1476 | # | ||
1314 | # Profiling support | 1477 | # Profiling support |
1315 | # | 1478 | # |
1316 | CONFIG_PROFILING=y | 1479 | CONFIG_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 |
1333 | CONFIG_DEBUG_FS=y | 1496 | CONFIG_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 | ||
1339 | CONFIG_IRQSTACKS=y | 1503 | CONFIG_IRQSTACKS=y |
1504 | CONFIG_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 | # | ||
1383 | CONFIG_CRC_CCITT=m | ||
1384 | # CONFIG_CRC16 is not set | ||
1385 | CONFIG_CRC32=y | ||
1386 | CONFIG_LIBCRC32C=m | ||
1387 | CONFIG_ZLIB_INFLATE=y | ||
1388 | CONFIG_ZLIB_DEFLATE=m | ||
1389 | CONFIG_TEXTSEARCH=y | ||
1390 | CONFIG_TEXTSEARCH_KMP=m | ||
1391 | CONFIG_TEXTSEARCH_BM=m | ||
1392 | CONFIG_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 | ||
55 | extern unsigned long _get_SP(void); | 55 | extern unsigned long _get_SP(void); |
@@ -203,10 +203,8 @@ int dump_spe(struct pt_regs *regs, elf_vrregset_t *evrregs) | |||
203 | 203 | ||
204 | int set_dabr(unsigned long dabr) | 204 | int 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 | */ |
1977 | void prom_add_property(struct device_node* np, struct property* prop) | 1977 | int 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 | ||
406 | static int __init prom_getprop(phandle node, const char *pname, | 406 | static 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 | ||
413 | static int __init prom_getproplen(phandle node, const char *pname) | 413 | static 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 | ||
418 | static int __init prom_setprop(phandle node, const char *pname, | 418 | static 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 | ||
614 | struct rtas_args rtas_stop_self_args = { | 614 | struct 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) | |||
405 | console_initcall(set_preferred_console); | 405 | console_initcall(set_preferred_console); |
406 | #endif /* CONFIG_PPC_MULTIPLATFORM */ | 406 | #endif /* CONFIG_PPC_MULTIPLATFORM */ |
407 | 407 | ||
408 | void __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 | ||
404 | static 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; | |||
119 | unsigned long ppc_proc_freq; | 120 | unsigned long ppc_proc_freq; |
120 | unsigned long ppc_tb_freq; | 121 | unsigned long ppc_tb_freq; |
121 | 122 | ||
122 | #ifdef CONFIG_PPC32 /* XXX for now */ | ||
123 | #define boot_cpuid 0 | ||
124 | #endif | ||
125 | |||
126 | u64 tb_last_jiffy __cacheline_aligned_in_smp; | 123 | u64 tb_last_jiffy __cacheline_aligned_in_smp; |
127 | unsigned long tb_last_stamp; | 124 | unsigned 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 | ||
27 | void __spin_yield(raw_spinlock_t *lock) | 28 | void __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 | ||
25 | static int numa_enabled = 1; | 26 | static 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 | ||
82 | extern void ppc64_enable_pmcs(void); | 83 | extern 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 | */ | ||
95 | static 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 | |||
84 | static void power4_cpu_setup(void *unused) | 105 | static 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 | */ |
286 | void iSeries_pcibios_init(void) | 276 | void 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 | ||
334 | void pcibios_fixup_bus(struct pci_bus *PciBus) | 317 | void 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 | ||
340 | void pcibios_fixup_resources(struct pci_dev *pdev) | 321 | void 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 */ |
74 | extern void ppcdbg_initialize(void); | ||
75 | |||
76 | static void build_iSeries_Memory_Map(void); | 74 | static void build_iSeries_Memory_Map(void); |
77 | static void iseries_shared_idle(void); | 75 | static void iseries_shared_idle(void); |
78 | static void iseries_dedicated_idle(void); | 76 | static 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 @@ | |||
1 | obj-y += pic.o setup.o time.o feature.o pci.o \ | 1 | obj-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 |
3 | obj-$(CONFIG_PMAC_BACKLIGHT) += backlight.o | 3 | obj-$(CONFIG_PMAC_BACKLIGHT) += backlight.o |
4 | obj-$(CONFIG_CPU_FREQ_PMAC) += cpufreq.o | 4 | obj-$(CONFIG_CPU_FREQ_PMAC) += cpufreq_32.o |
5 | obj-$(CONFIG_CPU_FREQ_PMAC64) += cpufreq_64.o | ||
5 | obj-$(CONFIG_NVRAM) += nvram.o | 6 | obj-$(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 |
7 | obj-$(CONFIG_PPC64) += nvram.o | 8 | obj-$(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 | ||
408 | unsigned 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 | ||
414 | static int pmac_cpufreq_cpu_init(struct cpufreq_policy *policy) | 412 | static 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 | |||
70 | static struct cpufreq_frequency_table g5_cpu_freqs[] = { | ||
71 | {CPUFREQ_HIGH, 0}, | ||
72 | {CPUFREQ_LOW, 0}, | ||
73 | {0, CPUFREQ_TABLE_END}, | ||
74 | }; | ||
75 | |||
76 | static 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 | */ | ||
84 | static u32 *g5_pmode_data; | ||
85 | static int g5_pmode_max; | ||
86 | static int g5_pmode_cur; | ||
87 | |||
88 | static DECLARE_MUTEX(g5_switch_mutex); | ||
89 | |||
90 | |||
91 | static struct smu_sdbp_fvt *g5_fvt_table; /* table of op. points */ | ||
92 | static int g5_fvt_count; /* number of op. points */ | ||
93 | static int g5_fvt_cur; /* current op. point */ | ||
94 | |||
95 | /* ----------------- real hardware interface */ | ||
96 | |||
97 | static 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 | |||
108 | static 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 | |||
164 | static 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 | |||
178 | static int g5_cpufreq_verify(struct cpufreq_policy *policy) | ||
179 | { | ||
180 | return cpufreq_frequency_table_verify(policy, g5_cpu_freqs); | ||
181 | } | ||
182 | |||
183 | static 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 | |||
195 | static unsigned int g5_cpufreq_get_speed(unsigned int cpu) | ||
196 | { | ||
197 | return g5_cpu_freqs[g5_pmode_cur].frequency; | ||
198 | } | ||
199 | |||
200 | static 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 | |||
215 | static 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 | |||
227 | static 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 | |||
320 | module_init(g5_cpufreq_init); | ||
321 | |||
322 | |||
323 | MODULE_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 | ||
196 | static 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 |
209 | int find_via_cuda(void) | 197 | int 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 | ||
110 | static inline long plpar_set_xdabr(unsigned long address, unsigned long flags) | ||
111 | { | ||
112 | return plpar_hcall_norets(H_SET_XDABR, address, flags); | ||
113 | } | ||
114 | |||
115 | static 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 | ||
53 | static unsigned char ras_log_buf[RTAS_ERROR_LOG_MAX]; | 53 | static unsigned char ras_log_buf[RTAS_ERROR_LOG_MAX]; |
54 | static DEFINE_SPINLOCK(ras_log_buf_lock); | 54 | static 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 | ||
354 | static int pseries_set_dabr(unsigned long dabr) | 355 | static 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 | ||
360 | static 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- |
802 | 00: lbz r5,0(r3) | 807 | 00: lbz r5,0(r3) |
803 | eieio | 808 | 01: eieio |
804 | stbu r5,1(r4) | 809 | 02: stbu r5,1(r4) |
810 | ISYNC_8xx | ||
811 | .section .fixup,"ax" | ||
812 | 03: 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- |
813 | 00: lbzu r5,1(r4) | 828 | 00: lbzu r5,1(r4) |
814 | stb r5,0(r3) | 829 | 01: stb r5,0(r3) |
815 | eieio | 830 | 02: eieio |
831 | ISYNC_8xx | ||
832 | .section .fixup,"ax" | ||
833 | 03: 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- |
824 | 00: lhbrx r5,0,r3 | 849 | 00: lhbrx r5,0,r3 |
825 | eieio | 850 | 01: eieio |
826 | sthu r5,2(r4) | 851 | 02: sthu r5,2(r4) |
852 | ISYNC_8xx | ||
853 | .section .fixup,"ax" | ||
854 | 03: 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- |
835 | 00: lhzu r5,2(r4) | 870 | 00: lhzu r5,2(r4) |
836 | eieio | 871 | 01: eieio |
837 | sthbrx r5,0,r3 | 872 | 02: sthbrx r5,0,r3 |
873 | ISYNC_8xx | ||
874 | .section .fixup,"ax" | ||
875 | 03: 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- |
846 | 00: lwbrx r5,0,r3 | 891 | 00: lwbrx r5,0,r3 |
847 | eieio | 892 | 01: eieio |
848 | stwu r5,4(r4) | 893 | 02: stwu r5,4(r4) |
894 | ISYNC_8xx | ||
895 | .section .fixup,"ax" | ||
896 | 03: 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- |
857 | 00: lwzu r5,4(r4) | 912 | 00: lwzu r5,4(r4) |
858 | stwbrx r5,0,r3 | 913 | 01: stwbrx r5,0,r3 |
859 | eieio | 914 | 02: eieio |
915 | ISYNC_8xx | ||
916 | .section .fixup,"ax" | ||
917 | 03: 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- |
869 | 00: lhz r5,0(r3) | 934 | 00: lhz r5,0(r3) |
870 | eieio | 935 | 01: eieio |
871 | sthu r5,2(r4) | 936 | 02: sthu r5,2(r4) |
937 | ISYNC_8xx | ||
938 | .section .fixup,"ax" | ||
939 | 03: 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- |
881 | 00: lhzu r5,2(r4) | 956 | 00: lhzu r5,2(r4) |
882 | sth r5,0(r3) | 957 | 01: sth r5,0(r3) |
883 | eieio | 958 | 02: eieio |
959 | ISYNC_8xx | ||
960 | .section .fixup,"ax" | ||
961 | 03: 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- |
893 | 00: lwz r5,0(r3) | 978 | 00: lwz r5,0(r3) |
894 | eieio | 979 | 01: eieio |
895 | stwu r5,4(r4) | 980 | 02: stwu r5,4(r4) |
981 | ISYNC_8xx | ||
982 | .section .fixup,"ax" | ||
983 | 03: 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- |
905 | 00: lwzu r5,4(r4) | 1000 | 00: lwzu r5,4(r4) |
906 | stw r5,0(r3) | 1001 | 01: stw r5,0(r3) |
907 | eieio | 1002 | 02: eieio |
1003 | ISYNC_8xx | ||
1004 | .section .fixup,"ax" | ||
1005 | 03: 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); | |||
49 | extern int xmon_iabr_match(struct pt_regs *regs); | 49 | extern int xmon_iabr_match(struct pt_regs *regs); |
50 | extern int xmon_dabr_match(struct pt_regs *regs); | 50 | extern int xmon_dabr_match(struct pt_regs *regs); |
51 | 51 | ||
52 | void (*debugger)(struct pt_regs *regs) = xmon; | 52 | int (*debugger)(struct pt_regs *regs) = xmon; |
53 | int (*debugger_bpt)(struct pt_regs *regs) = xmon_bpt; | 53 | int (*debugger_bpt)(struct pt_regs *regs) = xmon_bpt; |
54 | int (*debugger_sstep)(struct pt_regs *regs) = xmon_sstep; | 54 | int (*debugger_sstep)(struct pt_regs *regs) = xmon_sstep; |
55 | int (*debugger_iabr_match)(struct pt_regs *regs) = xmon_iabr_match; | 55 | int (*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; | |||
57 | void (*debugger_fault_handler)(struct pt_regs *regs); | 57 | void (*debugger_fault_handler)(struct pt_regs *regs); |
58 | #else | 58 | #else |
59 | #ifdef CONFIG_KGDB | 59 | #ifdef CONFIG_KGDB |
60 | void (*debugger)(struct pt_regs *regs); | 60 | int (*debugger)(struct pt_regs *regs); |
61 | int (*debugger_bpt)(struct pt_regs *regs); | 61 | int (*debugger_bpt)(struct pt_regs *regs); |
62 | int (*debugger_sstep)(struct pt_regs *regs); | 62 | int (*debugger_sstep)(struct pt_regs *regs); |
63 | int (*debugger_iabr_match)(struct pt_regs *regs); | 63 | int (*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 | */ |
160 | static inline int check_io_access(struct pt_regs *regs) | 160 | static 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 | ||
36 | static irqreturn_t m8xx_wdt_interrupt(int irq, void *dev, struct pt_regs *regs) | 37 | static 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 | */ |
1168 | void | 1168 | int |
1169 | prom_add_property(struct device_node* np, struct property* prop) | 1169 | prom_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 | ||
223 | void | 223 | int xmon(struct pt_regs *excp) |
224 | xmon(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 | ||
295 | irqreturn_t | 296 | irqreturn_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 |
57 | config FORCE_MAX_ZONEORDER | 57 | config FORCE_MAX_ZONEORDER |
58 | int | 58 | int |
59 | default "9" if PPC_64K_PAGES | ||
59 | default "13" | 60 | default "13" |
60 | 61 | ||
61 | source "init/Kconfig" | 62 | source "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 | ||
177 | source "drivers/cpufreq/Kconfig" | ||
178 | |||
179 | config 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 | |||
176 | config IBMVIO | 187 | config 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 | ||
58 | config PPCDBG | ||
59 | bool "Include PPCDBG realtime debugging" | ||
60 | depends on DEBUG_KERNEL | ||
61 | |||
62 | config IRQSTACKS | 58 | config 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 | ||
32 | extern void power4_idle(void); | 33 | extern 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 | ||
298 | static struct pci_dev *of_create_pci_dev(struct device_node *node, | 298 | struct 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 | } |
357 | EXPORT_SYMBOL(of_create_pci_dev); | ||
357 | 358 | ||
358 | static void of_scan_pci_bridge(struct device_node *node, struct pci_dev *dev); | 359 | void __devinit of_scan_bus(struct device_node *node, |
359 | |||
360 | static 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 | } |
383 | EXPORT_SYMBOL(of_scan_bus); | ||
384 | 384 | ||
385 | static void __devinit of_scan_pci_bridge(struct device_node *node, | 385 | void __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 | } |
467 | EXPORT_SYMBOL(of_scan_pci_bridge); | ||
467 | #endif /* CONFIG_PPC_MULTIPLATFORM */ | 468 | #endif /* CONFIG_PPC_MULTIPLATFORM */ |
468 | 469 | ||
469 | static void __devinit scan_phb(struct pci_controller *hose) | 470 | void __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) | |||
1866 | EXPORT_SYMBOL(get_property); | 1866 | EXPORT_SYMBOL(get_property); |
1867 | 1867 | ||
1868 | /* | 1868 | /* |
1869 | * Add a property to a node | 1869 | * Add a property to a node. |
1870 | */ | 1870 | */ |
1871 | void | 1871 | int |
1872 | prom_add_property(struct device_node* np, struct property* prop) | 1872 | prom_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 | ||
21 | void (*udbg_putc)(unsigned char c); | 19 | void (*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 | |||
94 | u64 ppc64_debug_switch; | ||
95 | |||
96 | /* Special print used by PPCDBG() macro */ | ||
97 | void 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 | |||
131 | unsigned 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 | */ | ||
139 | void __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 | ||
177 | struct floppy_state { | 178 | struct 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 | ||
310 | static void start_request(struct floppy_state *fs) | 311 | static 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 | ||
384 | static inline void scan_track(struct floppy_state *fs) | 385 | static 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 | ||
823 | static int fd_eject(struct floppy_state *fs) | 822 | static 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 | ||
172 | config WINDFARM | ||
173 | tristate "New PowerMac thermal control infrastructure" | ||
174 | |||
175 | config 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 | |||
182 | config 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 | |||
172 | config ANSLCD | 191 | config 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 | |||
26 | obj-$(CONFIG_THERM_PM72) += therm_pm72.o | 26 | obj-$(CONFIG_THERM_PM72) += therm_pm72.o |
27 | obj-$(CONFIG_THERM_WINDTUNNEL) += therm_windtunnel.o | 27 | obj-$(CONFIG_THERM_WINDTUNNEL) += therm_windtunnel.o |
28 | obj-$(CONFIG_THERM_ADT746X) += therm_adt746x.o | 28 | obj-$(CONFIG_THERM_ADT746X) += therm_adt746x.o |
29 | obj-$(CONFIG_WINDFARM) += windfarm_core.o | ||
30 | obj-$(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 | ||
34 | obj-$(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 | */ |
94 | static struct smu_device *smu; | 94 | static struct smu_device *smu; |
95 | 95 | static 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) | |||
440 | EXPORT_SYMBOL(smu_present); | 442 | EXPORT_SYMBOL(smu_present); |
441 | 443 | ||
442 | 444 | ||
443 | int smu_init (void) | 445 | int __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 | |||
856 | static 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 = ∁ | ||
879 | params[0] = SMU_CMD_MISC_ee_GET_DATABLOCK_REC; | ||
880 | params[1] = 0x4; | ||
881 | *((u32 *)¶ms[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 | |||
903 | static 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 | */ | ||
967 | struct 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 | |||
997 | struct smu_sdbp_header *smu_get_sdb_partition(int id, unsigned int *size) | ||
998 | { | ||
999 | return __smu_get_sdb_partition(id, size, 0); | ||
1000 | } | ||
1001 | EXPORT_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 | } |
2056 | EXPORT_SYMBOL(pmu_register_sleep_notifier); | ||
2056 | 2057 | ||
2057 | int | 2058 | int |
2058 | pmu_unregister_sleep_notifier(struct pmu_sleep_notifier* n) | 2059 | pmu_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 | } |
2067 | EXPORT_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); | |||
3139 | EXPORT_SYMBOL(pmu_i2c_simple_read); | 3141 | EXPORT_SYMBOL(pmu_i2c_simple_read); |
3140 | EXPORT_SYMBOL(pmu_i2c_simple_write); | 3142 | EXPORT_SYMBOL(pmu_i2c_simple_write); |
3141 | #if defined(CONFIG_PM) && defined(CONFIG_PPC32) | 3143 | #if defined(CONFIG_PM) && defined(CONFIG_PPC32) |
3142 | EXPORT_SYMBOL(pmu_register_sleep_notifier); | ||
3143 | EXPORT_SYMBOL(pmu_unregister_sleep_notifier); | ||
3144 | EXPORT_SYMBOL(pmu_enable_irled); | 3144 | EXPORT_SYMBOL(pmu_enable_irled); |
3145 | EXPORT_SYMBOL(pmu_battery_count); | 3145 | EXPORT_SYMBOL(pmu_battery_count); |
3146 | EXPORT_SYMBOL(pmu_batteries); | 3146 | EXPORT_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 | |||
25 | struct wf_control; | ||
26 | |||
27 | struct 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 | |||
36 | struct 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 | */ | ||
55 | extern int wf_register_control(struct wf_control *ct); | ||
56 | extern void wf_unregister_control(struct wf_control *ct); | ||
57 | extern struct wf_control * wf_find_control(const char *name); | ||
58 | extern int wf_get_control(struct wf_control *ct); | ||
59 | extern void wf_put_control(struct wf_control *ct); | ||
60 | |||
61 | static 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 | |||
67 | static 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 | |||
77 | struct wf_sensor; | ||
78 | |||
79 | struct 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 | |||
85 | struct 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 */ | ||
93 | extern int wf_register_sensor(struct wf_sensor *sr); | ||
94 | extern void wf_unregister_sensor(struct wf_sensor *sr); | ||
95 | extern struct wf_sensor * wf_find_sensor(const char *name); | ||
96 | extern int wf_get_sensor(struct wf_sensor *sr); | ||
97 | extern 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 | */ | ||
111 | extern int wf_register_client(struct notifier_block *nb); | ||
112 | extern int wf_unregister_client(struct notifier_block *nb); | ||
113 | |||
114 | /* Overtemp conditions. Those are refcounted */ | ||
115 | extern void wf_set_overtemp(void); | ||
116 | extern void wf_clear_overtemp(void); | ||
117 | extern 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 | |||
49 | static LIST_HEAD(wf_controls); | ||
50 | static LIST_HEAD(wf_sensors); | ||
51 | static DECLARE_MUTEX(wf_lock); | ||
52 | static struct notifier_block *wf_client_list; | ||
53 | static int wf_client_count; | ||
54 | static unsigned int wf_overtemp; | ||
55 | static unsigned int wf_overtemp_counter; | ||
56 | struct task_struct *wf_thread; | ||
57 | |||
58 | /* | ||
59 | * Utilities & tick thread | ||
60 | */ | ||
61 | |||
62 | static inline void wf_notify(int event, void *param) | ||
63 | { | ||
64 | notifier_call_chain(&wf_client_list, event, param); | ||
65 | } | ||
66 | |||
67 | int 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 | } | ||
78 | EXPORT_SYMBOL_GPL(wf_critical_overtemp); | ||
79 | |||
80 | static 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 | |||
125 | static 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 | |||
136 | static 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 | |||
147 | static 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 | |||
159 | int 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 | } | ||
182 | EXPORT_SYMBOL_GPL(wf_register_control); | ||
183 | |||
184 | void 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 | } | ||
194 | EXPORT_SYMBOL_GPL(wf_unregister_control); | ||
195 | |||
196 | struct 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 | } | ||
212 | EXPORT_SYMBOL_GPL(wf_find_control); | ||
213 | |||
214 | int 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 | } | ||
221 | EXPORT_SYMBOL_GPL(wf_get_control); | ||
222 | |||
223 | void 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 | } | ||
229 | EXPORT_SYMBOL_GPL(wf_put_control); | ||
230 | |||
231 | |||
232 | /* | ||
233 | * Sensors | ||
234 | */ | ||
235 | |||
236 | |||
237 | static 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 | |||
249 | int 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 | } | ||
272 | EXPORT_SYMBOL_GPL(wf_register_sensor); | ||
273 | |||
274 | void 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 | } | ||
284 | EXPORT_SYMBOL_GPL(wf_unregister_sensor); | ||
285 | |||
286 | struct 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 | } | ||
302 | EXPORT_SYMBOL_GPL(wf_find_sensor); | ||
303 | |||
304 | int 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 | } | ||
311 | EXPORT_SYMBOL_GPL(wf_get_sensor); | ||
312 | |||
313 | void 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 | } | ||
319 | EXPORT_SYMBOL_GPL(wf_put_sensor); | ||
320 | |||
321 | |||
322 | /* | ||
323 | * Client & notification | ||
324 | */ | ||
325 | |||
326 | int 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 | } | ||
347 | EXPORT_SYMBOL_GPL(wf_register_client); | ||
348 | |||
349 | int 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 | } | ||
360 | EXPORT_SYMBOL_GPL(wf_unregister_client); | ||
361 | |||
362 | void 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 | } | ||
373 | EXPORT_SYMBOL_GPL(wf_set_overtemp); | ||
374 | |||
375 | void 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 | } | ||
390 | EXPORT_SYMBOL_GPL(wf_clear_overtemp); | ||
391 | |||
392 | int wf_is_overtemp(void) | ||
393 | { | ||
394 | return (wf_overtemp != 0); | ||
395 | } | ||
396 | EXPORT_SYMBOL_GPL(wf_is_overtemp); | ||
397 | |||
398 | static struct platform_device wf_platform_device = { | ||
399 | .name = "windfarm", | ||
400 | }; | ||
401 | |||
402 | static 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 | |||
410 | static 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 | |||
420 | module_init(windfarm_core_init); | ||
421 | module_exit(windfarm_core_exit); | ||
422 | |||
423 | MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>"); | ||
424 | MODULE_DESCRIPTION("Core component of PowerMac thermal control"); | ||
425 | MODULE_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 | |||
15 | static int clamped; | ||
16 | static struct wf_control *clamp_control; | ||
17 | |||
18 | static 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 | |||
33 | static struct notifier_block clamp_notifier = { | ||
34 | .notifier_call = clamp_notifier_call, | ||
35 | }; | ||
36 | |||
37 | static 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 | |||
49 | static int clamp_get(struct wf_control *ct, s32 *value) | ||
50 | { | ||
51 | *value = clamped; | ||
52 | return 0; | ||
53 | } | ||
54 | |||
55 | static s32 clamp_min(struct wf_control *ct) | ||
56 | { | ||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | static s32 clamp_max(struct wf_control *ct) | ||
61 | { | ||
62 | return 1; | ||
63 | } | ||
64 | |||
65 | static 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 | |||
73 | static 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 | |||
92 | static void __exit wf_cpufreq_clamp_exit(void) | ||
93 | { | ||
94 | if (clamp_control) | ||
95 | wf_unregister_control(clamp_control); | ||
96 | } | ||
97 | |||
98 | |||
99 | module_init(wf_cpufreq_clamp_init); | ||
100 | module_exit(wf_cpufreq_clamp_exit); | ||
101 | |||
102 | MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>"); | ||
103 | MODULE_DESCRIPTION("CPU frequency clamp for PowerMacs thermal control"); | ||
104 | MODULE_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 | |||
37 | struct 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 | |||
46 | static int wf_lm75_attach(struct i2c_adapter *adapter); | ||
47 | static int wf_lm75_detach(struct i2c_client *client); | ||
48 | |||
49 | static 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 | |||
57 | static 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 | |||
91 | static 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 | |||
104 | static struct wf_sensor_ops wf_lm75_ops = { | ||
105 | .get_value = wf_lm75_get, | ||
106 | .release = wf_lm75_release, | ||
107 | .owner = THIS_MODULE, | ||
108 | }; | ||
109 | |||
110 | static 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 | |||
158 | static 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 | |||
226 | static 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 | |||
241 | static 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 | |||
251 | static void __exit wf_lm75_sensor_exit(void) | ||
252 | { | ||
253 | i2c_del_driver(&wf_lm75_driver); | ||
254 | } | ||
255 | |||
256 | |||
257 | module_init(wf_lm75_sensor_init); | ||
258 | module_exit(wf_lm75_sensor_exit); | ||
259 | |||
260 | MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>"); | ||
261 | MODULE_DESCRIPTION("LM75 sensor objects for PowerMacs thermal control"); | ||
262 | MODULE_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 | |||
26 | void 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 | } | ||
32 | EXPORT_SYMBOL_GPL(wf_pid_init); | ||
33 | |||
34 | s32 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 | } | ||
78 | EXPORT_SYMBOL_GPL(wf_pid_run); | ||
79 | |||
80 | void 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 | } | ||
87 | EXPORT_SYMBOL_GPL(wf_cpu_pid_init); | ||
88 | |||
89 | s32 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 | } | ||
145 | EXPORT_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 | */ | ||
26 | struct 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 | |||
35 | struct 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 | |||
45 | extern void wf_pid_init(struct wf_pid_state *st, struct wf_pid_param *param); | ||
46 | extern 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 | */ | ||
60 | struct 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 | |||
70 | struct 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 | |||
82 | extern void wf_cpu_pid_init(struct wf_cpu_pid_state *st, | ||
83 | struct wf_cpu_pid_param *param); | ||
84 | extern 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 | |||
132 | static int wf_smu_mach_model; /* machine model id */ | ||
133 | |||
134 | static struct device *wf_smu_dev; | ||
135 | |||
136 | /* Controls & sensors */ | ||
137 | static struct wf_sensor *sensor_cpu_power; | ||
138 | static struct wf_sensor *sensor_cpu_temp; | ||
139 | static struct wf_sensor *sensor_hd_temp; | ||
140 | static struct wf_control *fan_cpu_main; | ||
141 | static struct wf_control *fan_hd; | ||
142 | static struct wf_control *fan_system; | ||
143 | static struct wf_control *cpufreq_clamp; | ||
144 | |||
145 | /* Set to kick the control loop into life */ | ||
146 | static 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 | |||
153 | static unsigned int wf_smu_failure_state; | ||
154 | static 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 | */ | ||
165 | struct 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 | */ | ||
181 | struct 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 | */ | ||
195 | static 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 | |||
235 | static 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 | */ | ||
250 | struct 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 | |||
258 | static struct wf_smu_cpu_fans_state *wf_smu_cpu_fans; | ||
259 | |||
260 | |||
261 | |||
262 | /* | ||
263 | * ***** Implementation ***** | ||
264 | * | ||
265 | */ | ||
266 | |||
267 | static 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 | |||
331 | static 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 | |||
396 | static 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 | |||
475 | static 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) \ | ||
548 | static 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 | } \ | ||
558 | static DEVICE_ATTR(name,S_IRUGO,show_##name, NULL); | ||
559 | |||
560 | |||
561 | #define BUILD_SHOW_FUNC_INT(name, data) \ | ||
562 | static 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 | } \ | ||
570 | static DEVICE_ATTR(name,S_IRUGO,show_##name, NULL); | ||
571 | |||
572 | BUILD_SHOW_FUNC_INT(cpu_fan, fan_cpu_main); | ||
573 | BUILD_SHOW_FUNC_INT(sys_fan, fan_system); | ||
574 | BUILD_SHOW_FUNC_INT(hd_fan, fan_hd); | ||
575 | |||
576 | BUILD_SHOW_FUNC_FIX(cpu_temp, sensor_cpu_temp); | ||
577 | BUILD_SHOW_FUNC_FIX(cpu_power, sensor_cpu_power); | ||
578 | BUILD_SHOW_FUNC_FIX(hd_temp, sensor_hd_temp); | ||
579 | |||
580 | /* | ||
581 | * ****** Setup / Init / Misc ... ****** | ||
582 | * | ||
583 | */ | ||
584 | |||
585 | static 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 | |||
651 | static 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 | |||
696 | static 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 | |||
727 | static 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 | |||
750 | static struct notifier_block wf_smu_events = { | ||
751 | .notifier_call = wf_smu_notify, | ||
752 | }; | ||
753 | |||
754 | static 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 | |||
771 | static 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 | |||
780 | static 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 | |||
837 | static 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 | |||
845 | static 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 | |||
866 | static void __exit wf_smu_exit(void) | ||
867 | { | ||
868 | |||
869 | driver_unregister(&wf_smu_driver); | ||
870 | } | ||
871 | |||
872 | |||
873 | module_init(wf_smu_init); | ||
874 | module_exit(wf_smu_exit); | ||
875 | |||
876 | MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>"); | ||
877 | MODULE_DESCRIPTION("Thermal control logic for iMac G5"); | ||
878 | MODULE_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 | |||
66 | static struct device *wf_smu_dev; | ||
67 | |||
68 | /* Controls & sensors */ | ||
69 | static struct wf_sensor *sensor_cpu_power; | ||
70 | static struct wf_sensor *sensor_cpu_temp; | ||
71 | static struct wf_sensor *sensor_hd_temp; | ||
72 | static struct wf_sensor *sensor_slots_power; | ||
73 | static struct wf_control *fan_cpu_main; | ||
74 | static struct wf_control *fan_cpu_second; | ||
75 | static struct wf_control *fan_cpu_third; | ||
76 | static struct wf_control *fan_hd; | ||
77 | static struct wf_control *fan_slots; | ||
78 | static struct wf_control *cpufreq_clamp; | ||
79 | |||
80 | /* Set to kick the control loop into life */ | ||
81 | static 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 | |||
88 | static unsigned int wf_smu_failure_state; | ||
89 | static 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 | */ | ||
102 | struct wf_smu_cpu_fans_state { | ||
103 | int ticks; | ||
104 | s32 cpu_setpoint; | ||
105 | struct wf_cpu_pid_state pid; | ||
106 | }; | ||
107 | |||
108 | static struct wf_smu_cpu_fans_state *wf_smu_cpu_fans; | ||
109 | |||
110 | |||
111 | |||
112 | /* | ||
113 | * ****** Drive Fan Control Loop ****** | ||
114 | * | ||
115 | */ | ||
116 | |||
117 | struct wf_smu_drive_fans_state { | ||
118 | int ticks; | ||
119 | s32 setpoint; | ||
120 | struct wf_pid_state pid; | ||
121 | }; | ||
122 | |||
123 | static struct wf_smu_drive_fans_state *wf_smu_drive_fans; | ||
124 | |||
125 | /* | ||
126 | * ****** Slots Fan Control Loop ****** | ||
127 | * | ||
128 | */ | ||
129 | |||
130 | struct wf_smu_slots_fans_state { | ||
131 | int ticks; | ||
132 | s32 setpoint; | ||
133 | struct wf_pid_state pid; | ||
134 | }; | ||
135 | |||
136 | static struct wf_smu_slots_fans_state *wf_smu_slots_fans; | ||
137 | |||
138 | /* | ||
139 | * ***** Implementation ***** | ||
140 | * | ||
141 | */ | ||
142 | |||
143 | |||
144 | static 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 | |||
220 | static 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 | |||
295 | static 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, ¶m); | ||
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 | |||
332 | static 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 | |||
376 | static 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, ¶m); | ||
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 | |||
413 | static 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) \ | ||
466 | static 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 | } \ | ||
476 | static DEVICE_ATTR(name,S_IRUGO,show_##name, NULL); | ||
477 | |||
478 | |||
479 | #define BUILD_SHOW_FUNC_INT(name, data) \ | ||
480 | static 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 | } \ | ||
488 | static DEVICE_ATTR(name,S_IRUGO,show_##name, NULL); | ||
489 | |||
490 | BUILD_SHOW_FUNC_INT(cpu_fan, fan_cpu_main); | ||
491 | BUILD_SHOW_FUNC_INT(hd_fan, fan_hd); | ||
492 | BUILD_SHOW_FUNC_INT(slots_fan, fan_slots); | ||
493 | |||
494 | BUILD_SHOW_FUNC_FIX(cpu_temp, sensor_cpu_temp); | ||
495 | BUILD_SHOW_FUNC_FIX(cpu_power, sensor_cpu_power); | ||
496 | BUILD_SHOW_FUNC_FIX(hd_temp, sensor_hd_temp); | ||
497 | BUILD_SHOW_FUNC_FIX(slots_power, sensor_slots_power); | ||
498 | |||
499 | /* | ||
500 | * ****** Setup / Init / Misc ... ****** | ||
501 | * | ||
502 | */ | ||
503 | |||
504 | static 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 | |||
578 | static 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 | |||
624 | static 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 | |||
663 | static 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 | |||
686 | static struct notifier_block wf_smu_events = { | ||
687 | .notifier_call = wf_smu_notify, | ||
688 | }; | ||
689 | |||
690 | static int wf_init_pm(void) | ||
691 | { | ||
692 | printk(KERN_INFO "windfarm: Initializing for Desktop G5 model\n"); | ||
693 | |||
694 | return 0; | ||
695 | } | ||
696 | |||
697 | static 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 | |||
706 | static 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 | |||
773 | static 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 | |||
781 | static 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 | |||
801 | static void __exit wf_smu_exit(void) | ||
802 | { | ||
803 | |||
804 | driver_unregister(&wf_smu_driver); | ||
805 | } | ||
806 | |||
807 | |||
808 | module_init(wf_smu_init); | ||
809 | module_exit(wf_smu_exit); | ||
810 | |||
811 | MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>"); | ||
812 | MODULE_DESCRIPTION("Thermal control logic for PowerMac9,1"); | ||
813 | MODULE_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 | |||
40 | static LIST_HEAD(smu_fans); | ||
41 | |||
42 | struct 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 | |||
52 | static 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 = ∁ | ||
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 | |||
81 | static 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 | |||
88 | static 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 | |||
101 | static 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 | |||
108 | static 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 | |||
114 | static 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 | |||
120 | static 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 | |||
129 | static 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 | |||
212 | static 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 | |||
264 | static 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 | |||
276 | module_init(smu_controls_init); | ||
277 | module_exit(smu_controls_exit); | ||
278 | |||
279 | MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>"); | ||
280 | MODULE_DESCRIPTION("SMU control objects for PowerMacs thermal control"); | ||
281 | MODULE_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 | */ | ||
40 | static struct smu_sdbp_cpuvcp *cpuvcp; | ||
41 | static int cpuvcp_version; | ||
42 | static struct smu_sdbp_cpudiode *cpudiode; | ||
43 | static struct smu_sdbp_slotspow *slotspow; | ||
44 | static u8 *debugswitches; | ||
45 | |||
46 | /* | ||
47 | * SMU basic sensors objects | ||
48 | */ | ||
49 | |||
50 | static LIST_HEAD(smu_ads); | ||
51 | |||
52 | struct 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 | |||
59 | static 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 | |||
66 | static 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 | |||
88 | static 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 | |||
111 | static 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 | |||
132 | static 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 | |||
153 | static 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 | |||
175 | static struct wf_sensor_ops smu_cputemp_ops = { | ||
176 | .get_value = smu_cputemp_get, | ||
177 | .release = smu_ads_release, | ||
178 | .owner = THIS_MODULE, | ||
179 | }; | ||
180 | static struct wf_sensor_ops smu_cpuamp_ops = { | ||
181 | .get_value = smu_cpuamp_get, | ||
182 | .release = smu_ads_release, | ||
183 | .owner = THIS_MODULE, | ||
184 | }; | ||
185 | static struct wf_sensor_ops smu_cpuvolt_ops = { | ||
186 | .get_value = smu_cpuvolt_get, | ||
187 | .release = smu_ads_release, | ||
188 | .owner = THIS_MODULE, | ||
189 | }; | ||
190 | static 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 | |||
197 | static 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 | |||
259 | struct 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 | |||
269 | static struct smu_cpu_power_sensor *smu_cpu_power; | ||
270 | |||
271 | static 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 | |||
282 | static 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, &s); | ||
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 | |||
315 | static 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 | |||
322 | static struct smu_cpu_power_sensor * | ||
323 | smu_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 | |||
367 | static 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 | |||
404 | static 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 | |||
456 | static 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 | |||
473 | module_init(smu_sensors_init); | ||
474 | module_exit(smu_sensors_exit); | ||
475 | |||
476 | MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>"); | ||
477 | MODULE_DESCRIPTION("SMU sensor objects for PowerMacs thermal control"); | ||
478 | MODULE_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 | */ | ||
54 | static 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 | |||
79 | void 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 | */ |
54 | void proc_device_tree_add_node(struct device_node *np, | 87 | void 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 | ||
35 | void pci_devs_phb_init(void); | 35 | void pci_devs_phb_init(void); |
36 | void pci_devs_phb_init_dynamic(struct pci_controller *phb); | 36 | void pci_devs_phb_init_dynamic(struct pci_controller *phb); |
37 | void __devinit scan_phb(struct pci_controller *hose); | ||
37 | 38 | ||
38 | /* PCI address cache management routines */ | 39 | /* PCI address cache management routines */ |
39 | void pci_addr_cache_insert_device(struct pci_dev *dev); | 40 | void 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); | |||
203 | extern int prom_n_size_cells(struct device_node* np); | 203 | extern int prom_n_size_cells(struct device_node* np); |
204 | extern int prom_n_intr_cells(struct device_node* np); | 204 | extern int prom_n_intr_cells(struct device_node* np); |
205 | extern void prom_get_irq_senses(unsigned char *senses, int off, int max); | 205 | extern void prom_get_irq_senses(unsigned char *senses, int off, int max); |
206 | extern void prom_add_property(struct device_node* np, struct property* prop); | 206 | extern 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 | |
601 | extern unsigned long scom970_read(unsigned int address); | ||
602 | extern 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 | |||
97 | extern 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 | */ | ||
412 | struct 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 | |||
435 | struct 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 | |||
457 | struct 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 | |||
469 | struct 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 | |||
479 | struct 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 | |||
489 | struct 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 | |||
500 | struct 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 | */ | ||
519 | extern 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; | |||
7 | extern int xmon(struct pt_regs *excp); | 7 | extern int xmon(struct pt_regs *excp); |
8 | extern void xmon_printf(const char *fmt, ...); | 8 | extern void xmon_printf(const char *fmt, ...); |
9 | extern void xmon_init(int); | 9 | extern void xmon_init(int); |
10 | extern 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]; | |||
17 | extern boot_infos_t disp_bi; | 17 | extern boot_infos_t disp_bi; |
18 | extern int boot_text_mapped; | 18 | extern int boot_text_mapped; |
19 | 19 | ||
20 | void btext_init(boot_infos_t *bi); | 20 | extern void init_boot_display(void); |
21 | void btext_welcome(void); | 21 | extern void btext_welcome(void); |
22 | void btext_prepare_BAT(void); | 22 | extern void btext_prepare_BAT(void); |
23 | void btext_setup_display(int width, int height, int depth, int pitch, | 23 | extern void btext_setup_display(int width, int height, int depth, int pitch, |
24 | unsigned long address); | 24 | unsigned long address); |
25 | void map_boot_text(void); | 25 | extern void map_boot_text(void); |
26 | void btext_update_display(unsigned long phys, int width, int height, | 26 | extern void btext_update_display(unsigned long phys, int width, int height, |
27 | int depth, int pitch); | 27 | int depth, int pitch); |
28 | 28 | ||
29 | void btext_drawchar(char c); | 29 | extern void btext_drawchar(char c); |
30 | void btext_drawstring(const char *str); | 30 | extern void btext_drawstring(const char *str); |
31 | void btext_drawhex(unsigned long v); | 31 | extern 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) \ | |||
282 | extern __inline__ void name(unsigned int val, unsigned int port) \ | 283 | extern __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 | */ |
34 | extern void (*debugger)(struct pt_regs *regs); | 34 | extern int (*debugger)(struct pt_regs *regs); |
35 | extern int (*debugger_bpt)(struct pt_regs *regs); | 35 | extern int (*debugger_bpt)(struct pt_regs *regs); |
36 | extern int (*debugger_sstep)(struct pt_regs *regs); | 36 | extern int (*debugger_sstep)(struct pt_regs *regs); |
37 | extern int (*debugger_iabr_match)(struct pt_regs *regs); | 37 | extern 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 *); | |||
93 | extern int machine_is_compatible(const char *compat); | 93 | extern int machine_is_compatible(const char *compat); |
94 | extern unsigned char *get_property(struct device_node *node, const char *name, | 94 | extern unsigned char *get_property(struct device_node *node, const char *name, |
95 | int *lenp); | 95 | int *lenp); |
96 | extern void prom_add_property(struct device_node* np, struct property* prop); | 96 | extern int prom_add_property(struct device_node* np, struct property* prop); |
97 | extern void prom_get_irq_senses(unsigned char *, int, int); | 97 | extern void prom_get_irq_senses(unsigned char *, int, int); |
98 | extern int prom_n_addr_cells(struct device_node* np); | 98 | extern int prom_n_addr_cells(struct device_node* np); |
99 | extern int prom_n_size_cells(struct device_node* np); | 99 | extern 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 | ||
163 | extern struct pci_controller *init_phb_dynamic(struct device_node *dn); | 163 | extern struct pci_controller *init_phb_dynamic(struct device_node *dn); |
164 | 164 | ||
165 | extern struct pci_dev *of_create_pci_dev(struct device_node *node, | ||
166 | struct pci_bus *bus, int devfn); | ||
167 | |||
168 | extern void of_scan_pci_bridge(struct device_node *node, | ||
169 | struct pci_dev *dev); | ||
170 | |||
171 | extern void of_scan_bus(struct device_node *node, struct pci_bus *bus); | ||
172 | |||
165 | extern int pci_read_irq_line(struct pci_dev *dev); | 173 | extern int pci_read_irq_line(struct pci_dev *dev); |
166 | 174 | ||
167 | extern void pcibios_add_platform_entries(struct pci_dev *dev); | 175 | extern 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 | |||
68 | extern 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 | */ | ||
74 | char *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 | ||
86 | extern 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); | |||
213 | extern int prom_n_size_cells(struct device_node* np); | 213 | extern int prom_n_size_cells(struct device_node* np); |
214 | extern int prom_n_intr_cells(struct device_node* np); | 214 | extern int prom_n_intr_cells(struct device_node* np); |
215 | extern void prom_get_irq_senses(unsigned char *senses, int off, int max); | 215 | extern void prom_get_irq_senses(unsigned char *senses, int off, int max); |
216 | extern void prom_add_property(struct device_node* np, struct property* prop); | 216 | extern 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 | ||
24 | extern void register_early_udbg_console(void); | 24 | extern void register_early_udbg_console(void); |
25 | extern void udbg_printf(const char *fmt, ...); | 25 | extern void udbg_printf(const char *fmt, ...); |
26 | extern void udbg_ppcdbg(unsigned long flags, const char *fmt, ...); | ||
27 | extern unsigned long udbg_ifdebug(unsigned long flags); | ||
28 | extern void __init ppcdbg_initialize(void); | ||
29 | 26 | ||
30 | extern void udbg_init_uart(void __iomem *comport, unsigned int speed); | 27 | extern 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 | ||
142 | struct device_node; | 143 | struct device_node; |
144 | struct property; | ||
143 | extern void proc_device_tree_init(void); | 145 | extern void proc_device_tree_init(void); |
144 | #ifdef CONFIG_PROC_DEVICETREE | ||
145 | extern void proc_device_tree_add_node(struct device_node *, struct proc_dir_entry *); | 146 | extern void proc_device_tree_add_node(struct device_node *, struct proc_dir_entry *); |
146 | #else /* !CONFIG_PROC_DEVICETREE */ | 147 | extern void proc_device_tree_add_prop(struct proc_dir_entry *pde, struct property *prop); |
147 | static 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 | ||
153 | extern struct proc_dir_entry *proc_symlink(const char *, | 150 | extern struct proc_dir_entry *proc_symlink(const char *, |