diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-12 17:27:24 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-12 17:27:24 -0500 |
commit | 09cea96caa59fabab3030c53bd698b9b568d959a (patch) | |
tree | a991cdc0c887fdcda37f4b751ee98d3db9559f4e /arch/powerpc | |
parent | 6eb7365db6f3a4a9d8d9922bb0b800f9cbaad641 (diff) | |
parent | e090aa80321b64c3b793f3b047e31ecf1af9538d (diff) |
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc
* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc: (151 commits)
powerpc: Fix usage of 64-bit instruction in 32-bit altivec code
MAINTAINERS: Add PowerPC patterns
powerpc/pseries: Track previous CPPR values to correctly EOI interrupts
powerpc/pseries: Correct pseries/dlpar.c build break without CONFIG_SMP
powerpc: Make "intspec" pointers in irq_host->xlate() const
powerpc/8xx: DTLB Miss cleanup
powerpc/8xx: Remove DIRTY pte handling in DTLB Error.
powerpc/8xx: Start using dcbX instructions in various copy routines
powerpc/8xx: Restore _PAGE_WRITETHRU
powerpc/8xx: Add missing Guarded setting in DTLB Error.
powerpc/8xx: Fixup DAR from buggy dcbX instructions.
powerpc/8xx: Tag DAR with 0x00f0 to catch buggy instructions.
powerpc/8xx: Update TLB asm so it behaves as linux mm expects.
powerpc/8xx: Invalidate non present TLBs
powerpc/pseries: Serialize cpu hotplug operations during deactivate Vs deallocate
pseries/pseries: Add code to online/offline CPUs of a DLPAR node
powerpc: stop_this_cpu: remove the cpu from the online map.
powerpc/pseries: Add kernel based CPU DLPAR handling
sysfs/cpu: Add probe/release files
powerpc/pseries: Kernel DLPAR Infrastructure
...
Diffstat (limited to 'arch/powerpc')
193 files changed, 9749 insertions, 1822 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 2ba14e77296c..0df57466e783 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig | |||
@@ -56,6 +56,16 @@ config IRQ_PER_CPU | |||
56 | bool | 56 | bool |
57 | default y | 57 | default y |
58 | 58 | ||
59 | config NR_IRQS | ||
60 | int "Number of virtual interrupt numbers" | ||
61 | range 32 512 | ||
62 | default "512" | ||
63 | help | ||
64 | This defines the number of virtual interrupt numbers the kernel | ||
65 | can manage. Virtual interrupt numbers are what you see in | ||
66 | /proc/interrupts. If you configure your system to have too few, | ||
67 | drivers will fail to load or worse - handle with care. | ||
68 | |||
59 | config STACKTRACE_SUPPORT | 69 | config STACKTRACE_SUPPORT |
60 | bool | 70 | bool |
61 | default y | 71 | default y |
@@ -199,24 +209,14 @@ config DEFAULT_UIMAGE | |||
199 | config REDBOOT | 209 | config REDBOOT |
200 | bool | 210 | bool |
201 | 211 | ||
202 | config HIBERNATE_32 | ||
203 | bool | ||
204 | depends on (PPC_PMAC && !SMP) || BROKEN | ||
205 | default y | ||
206 | |||
207 | config HIBERNATE_64 | ||
208 | bool | ||
209 | depends on BROKEN || (PPC_PMAC64 && EXPERIMENTAL) | ||
210 | default y | ||
211 | |||
212 | config ARCH_HIBERNATION_POSSIBLE | 212 | config ARCH_HIBERNATION_POSSIBLE |
213 | bool | 213 | bool |
214 | depends on (PPC64 && HIBERNATE_64) || (PPC32 && HIBERNATE_32) | ||
215 | default y | 214 | default y |
216 | 215 | ||
217 | config ARCH_SUSPEND_POSSIBLE | 216 | config ARCH_SUSPEND_POSSIBLE |
218 | def_bool y | 217 | def_bool y |
219 | depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200 || PPC_83xx | 218 | depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200 || PPC_83xx || \ |
219 | PPC_85xx || PPC_86xx | ||
220 | 220 | ||
221 | config PPC_DCR_NATIVE | 221 | config PPC_DCR_NATIVE |
222 | bool | 222 | bool |
@@ -320,6 +320,10 @@ config HOTPLUG_CPU | |||
320 | 320 | ||
321 | Say N if you are unsure. | 321 | Say N if you are unsure. |
322 | 322 | ||
323 | config ARCH_CPU_PROBE_RELEASE | ||
324 | def_bool y | ||
325 | depends on HOTPLUG_CPU | ||
326 | |||
323 | config ARCH_ENABLE_MEMORY_HOTPLUG | 327 | config ARCH_ENABLE_MEMORY_HOTPLUG |
324 | def_bool y | 328 | def_bool y |
325 | 329 | ||
@@ -378,6 +382,19 @@ config IRQ_ALL_CPUS | |||
378 | CPU. Generally saying Y is safe, although some problems have been | 382 | CPU. Generally saying Y is safe, although some problems have been |
379 | reported with SMP Power Macintoshes with this option enabled. | 383 | reported with SMP Power Macintoshes with this option enabled. |
380 | 384 | ||
385 | config SPARSE_IRQ | ||
386 | bool "Support sparse irq numbering" | ||
387 | default y | ||
388 | help | ||
389 | This enables support for sparse irqs. This is useful for distro | ||
390 | kernels that want to define a high CONFIG_NR_CPUS value but still | ||
391 | want to have low kernel memory footprint on smaller machines. | ||
392 | |||
393 | ( Sparse IRQs can also be beneficial on NUMA boxes, as they spread | ||
394 | out the irq_desc[] array in a more NUMA-friendly way. ) | ||
395 | |||
396 | If you don't know what to do here, say Y. | ||
397 | |||
381 | config NUMA | 398 | config NUMA |
382 | bool "NUMA support" | 399 | bool "NUMA support" |
383 | depends on PPC64 | 400 | depends on PPC64 |
@@ -652,6 +669,14 @@ config FSL_PCI | |||
652 | select PPC_INDIRECT_PCI | 669 | select PPC_INDIRECT_PCI |
653 | select PCI_QUIRKS | 670 | select PCI_QUIRKS |
654 | 671 | ||
672 | config FSL_PMC | ||
673 | bool | ||
674 | default y | ||
675 | depends on SUSPEND && (PPC_85xx || PPC_86xx) | ||
676 | help | ||
677 | Freescale MPC85xx/MPC86xx power management controller support | ||
678 | (suspend/resume). For MPC83xx see platforms/83xx/suspend.c | ||
679 | |||
655 | config 4xx_SOC | 680 | config 4xx_SOC |
656 | bool | 681 | bool |
657 | 682 | ||
diff --git a/arch/powerpc/boot/dts/canyonlands.dts b/arch/powerpc/boot/dts/canyonlands.dts index c920170b7dfe..cd56bb5b347b 100644 --- a/arch/powerpc/boot/dts/canyonlands.dts +++ b/arch/powerpc/boot/dts/canyonlands.dts | |||
@@ -352,6 +352,7 @@ | |||
352 | max-frame-size = <9000>; | 352 | max-frame-size = <9000>; |
353 | rx-fifo-size = <4096>; | 353 | rx-fifo-size = <4096>; |
354 | tx-fifo-size = <2048>; | 354 | tx-fifo-size = <2048>; |
355 | rx-fifo-size-gige = <16384>; | ||
355 | phy-mode = "rgmii"; | 356 | phy-mode = "rgmii"; |
356 | phy-map = <0x00000000>; | 357 | phy-map = <0x00000000>; |
357 | rgmii-device = <&RGMII0>; | 358 | rgmii-device = <&RGMII0>; |
@@ -381,6 +382,7 @@ | |||
381 | max-frame-size = <9000>; | 382 | max-frame-size = <9000>; |
382 | rx-fifo-size = <4096>; | 383 | rx-fifo-size = <4096>; |
383 | tx-fifo-size = <2048>; | 384 | tx-fifo-size = <2048>; |
385 | rx-fifo-size-gige = <16384>; | ||
384 | phy-mode = "rgmii"; | 386 | phy-mode = "rgmii"; |
385 | phy-map = <0x00000000>; | 387 | phy-map = <0x00000000>; |
386 | rgmii-device = <&RGMII0>; | 388 | rgmii-device = <&RGMII0>; |
diff --git a/arch/powerpc/boot/dts/eiger.dts b/arch/powerpc/boot/dts/eiger.dts index c4a934f2e886..48bcf7187924 100644 --- a/arch/powerpc/boot/dts/eiger.dts +++ b/arch/powerpc/boot/dts/eiger.dts | |||
@@ -316,6 +316,7 @@ | |||
316 | max-frame-size = <9000>; | 316 | max-frame-size = <9000>; |
317 | rx-fifo-size = <4096>; | 317 | rx-fifo-size = <4096>; |
318 | tx-fifo-size = <2048>; | 318 | tx-fifo-size = <2048>; |
319 | rx-fifo-size-gige = <16384>; | ||
319 | phy-mode = "rgmii"; | 320 | phy-mode = "rgmii"; |
320 | phy-map = <0x00000000>; | 321 | phy-map = <0x00000000>; |
321 | rgmii-device = <&RGMII0>; | 322 | rgmii-device = <&RGMII0>; |
@@ -345,6 +346,7 @@ | |||
345 | max-frame-size = <9000>; | 346 | max-frame-size = <9000>; |
346 | rx-fifo-size = <4096>; | 347 | rx-fifo-size = <4096>; |
347 | tx-fifo-size = <2048>; | 348 | tx-fifo-size = <2048>; |
349 | rx-fifo-size-gige = <16384>; | ||
348 | phy-mode = "rgmii"; | 350 | phy-mode = "rgmii"; |
349 | phy-map = <0x00000000>; | 351 | phy-map = <0x00000000>; |
350 | rgmii-device = <&RGMII0>; | 352 | rgmii-device = <&RGMII0>; |
@@ -375,6 +377,8 @@ | |||
375 | max-frame-size = <9000>; | 377 | max-frame-size = <9000>; |
376 | rx-fifo-size = <4096>; | 378 | rx-fifo-size = <4096>; |
377 | tx-fifo-size = <2048>; | 379 | tx-fifo-size = <2048>; |
380 | rx-fifo-size-gige = <16384>; | ||
381 | tx-fifo-size-gige = <16384>; /* emac2&3 only */ | ||
378 | phy-mode = "rgmii"; | 382 | phy-mode = "rgmii"; |
379 | phy-map = <0x00000000>; | 383 | phy-map = <0x00000000>; |
380 | rgmii-device = <&RGMII1>; | 384 | rgmii-device = <&RGMII1>; |
@@ -403,6 +407,8 @@ | |||
403 | max-frame-size = <9000>; | 407 | max-frame-size = <9000>; |
404 | rx-fifo-size = <4096>; | 408 | rx-fifo-size = <4096>; |
405 | tx-fifo-size = <2048>; | 409 | tx-fifo-size = <2048>; |
410 | rx-fifo-size-gige = <16384>; | ||
411 | tx-fifo-size-gige = <16384>; /* emac2&3 only */ | ||
406 | phy-mode = "rgmii"; | 412 | phy-mode = "rgmii"; |
407 | phy-map = <0x00000000>; | 413 | phy-map = <0x00000000>; |
408 | rgmii-device = <&RGMII1>; | 414 | rgmii-device = <&RGMII1>; |
diff --git a/arch/powerpc/boot/dts/gef_ppc9a.dts b/arch/powerpc/boot/dts/gef_ppc9a.dts index 910944edd886..c86114e93f1e 100644 --- a/arch/powerpc/boot/dts/gef_ppc9a.dts +++ b/arch/powerpc/boot/dts/gef_ppc9a.dts | |||
@@ -118,6 +118,12 @@ | |||
118 | }; | 118 | }; |
119 | }; | 119 | }; |
120 | 120 | ||
121 | nvram@3,0 { | ||
122 | device_type = "nvram"; | ||
123 | compatible = "simtek,stk14ca8"; | ||
124 | reg = <0x3 0x0 0x20000>; | ||
125 | }; | ||
126 | |||
121 | fpga@4,0 { | 127 | fpga@4,0 { |
122 | compatible = "gef,ppc9a-fpga-regs"; | 128 | compatible = "gef,ppc9a-fpga-regs"; |
123 | reg = <0x4 0x0 0x40>; | 129 | reg = <0x4 0x0 0x40>; |
diff --git a/arch/powerpc/boot/dts/gef_sbc310.dts b/arch/powerpc/boot/dts/gef_sbc310.dts index 2107d3c7cfe1..820c2b355ab1 100644 --- a/arch/powerpc/boot/dts/gef_sbc310.dts +++ b/arch/powerpc/boot/dts/gef_sbc310.dts | |||
@@ -115,6 +115,12 @@ | |||
115 | }; | 115 | }; |
116 | }; | 116 | }; |
117 | 117 | ||
118 | nvram@3,0 { | ||
119 | device_type = "nvram"; | ||
120 | compatible = "simtek,stk14ca8"; | ||
121 | reg = <0x3 0x0 0x20000>; | ||
122 | }; | ||
123 | |||
118 | fpga@4,0 { | 124 | fpga@4,0 { |
119 | compatible = "gef,fpga-regs"; | 125 | compatible = "gef,fpga-regs"; |
120 | reg = <0x4 0x0 0x40>; | 126 | reg = <0x4 0x0 0x40>; |
diff --git a/arch/powerpc/boot/dts/gef_sbc610.dts b/arch/powerpc/boot/dts/gef_sbc610.dts index 35a63183eecc..30911adefc8e 100644 --- a/arch/powerpc/boot/dts/gef_sbc610.dts +++ b/arch/powerpc/boot/dts/gef_sbc610.dts | |||
@@ -84,6 +84,12 @@ | |||
84 | 6 0 0xfd000000 0x00800000 // IO FPGA (8-bit) | 84 | 6 0 0xfd000000 0x00800000 // IO FPGA (8-bit) |
85 | 7 0 0xfd800000 0x00800000>; // IO FPGA (32-bit) | 85 | 7 0 0xfd800000 0x00800000>; // IO FPGA (32-bit) |
86 | 86 | ||
87 | nvram@3,0 { | ||
88 | device_type = "nvram"; | ||
89 | compatible = "simtek,stk14ca8"; | ||
90 | reg = <0x3 0x0 0x20000>; | ||
91 | }; | ||
92 | |||
87 | fpga@4,0 { | 93 | fpga@4,0 { |
88 | compatible = "gef,fpga-regs"; | 94 | compatible = "gef,fpga-regs"; |
89 | reg = <0x4 0x0 0x40>; | 95 | reg = <0x4 0x0 0x40>; |
diff --git a/arch/powerpc/boot/dts/glacier.dts b/arch/powerpc/boot/dts/glacier.dts index f3787a27f634..f6f618939293 100644 --- a/arch/powerpc/boot/dts/glacier.dts +++ b/arch/powerpc/boot/dts/glacier.dts | |||
@@ -292,6 +292,7 @@ | |||
292 | max-frame-size = <9000>; | 292 | max-frame-size = <9000>; |
293 | rx-fifo-size = <4096>; | 293 | rx-fifo-size = <4096>; |
294 | tx-fifo-size = <2048>; | 294 | tx-fifo-size = <2048>; |
295 | rx-fifo-size-gige = <16384>; | ||
295 | phy-mode = "rgmii"; | 296 | phy-mode = "rgmii"; |
296 | phy-map = <0x00000000>; | 297 | phy-map = <0x00000000>; |
297 | rgmii-device = <&RGMII0>; | 298 | rgmii-device = <&RGMII0>; |
@@ -321,6 +322,7 @@ | |||
321 | max-frame-size = <9000>; | 322 | max-frame-size = <9000>; |
322 | rx-fifo-size = <4096>; | 323 | rx-fifo-size = <4096>; |
323 | tx-fifo-size = <2048>; | 324 | tx-fifo-size = <2048>; |
325 | rx-fifo-size-gige = <16384>; | ||
324 | phy-mode = "rgmii"; | 326 | phy-mode = "rgmii"; |
325 | phy-map = <0x00000000>; | 327 | phy-map = <0x00000000>; |
326 | rgmii-device = <&RGMII0>; | 328 | rgmii-device = <&RGMII0>; |
@@ -351,6 +353,8 @@ | |||
351 | max-frame-size = <9000>; | 353 | max-frame-size = <9000>; |
352 | rx-fifo-size = <4096>; | 354 | rx-fifo-size = <4096>; |
353 | tx-fifo-size = <2048>; | 355 | tx-fifo-size = <2048>; |
356 | rx-fifo-size-gige = <16384>; | ||
357 | tx-fifo-size-gige = <16384>; /* emac2&3 only */ | ||
354 | phy-mode = "rgmii"; | 358 | phy-mode = "rgmii"; |
355 | phy-map = <0x00000000>; | 359 | phy-map = <0x00000000>; |
356 | rgmii-device = <&RGMII1>; | 360 | rgmii-device = <&RGMII1>; |
@@ -379,6 +383,8 @@ | |||
379 | max-frame-size = <9000>; | 383 | max-frame-size = <9000>; |
380 | rx-fifo-size = <4096>; | 384 | rx-fifo-size = <4096>; |
381 | tx-fifo-size = <2048>; | 385 | tx-fifo-size = <2048>; |
386 | rx-fifo-size-gige = <16384>; | ||
387 | tx-fifo-size-gige = <16384>; /* emac2&3 only */ | ||
382 | phy-mode = "rgmii"; | 388 | phy-mode = "rgmii"; |
383 | phy-map = <0x00000000>; | 389 | phy-map = <0x00000000>; |
384 | rgmii-device = <&RGMII1>; | 390 | rgmii-device = <&RGMII1>; |
diff --git a/arch/powerpc/boot/dts/haleakala.dts b/arch/powerpc/boot/dts/haleakala.dts index 5b2a4947bf82..2b256694eca6 100644 --- a/arch/powerpc/boot/dts/haleakala.dts +++ b/arch/powerpc/boot/dts/haleakala.dts | |||
@@ -226,6 +226,8 @@ | |||
226 | max-frame-size = <9000>; | 226 | max-frame-size = <9000>; |
227 | rx-fifo-size = <4096>; | 227 | rx-fifo-size = <4096>; |
228 | tx-fifo-size = <2048>; | 228 | tx-fifo-size = <2048>; |
229 | rx-fifo-size-gige = <16384>; | ||
230 | tx-fifo-size-gige = <16384>; | ||
229 | phy-mode = "rgmii"; | 231 | phy-mode = "rgmii"; |
230 | phy-map = <0x00000000>; | 232 | phy-map = <0x00000000>; |
231 | rgmii-device = <&RGMII0>; | 233 | rgmii-device = <&RGMII0>; |
diff --git a/arch/powerpc/boot/dts/katmai.dts b/arch/powerpc/boot/dts/katmai.dts index 077819bc3cbd..51eb6ed5da2d 100644 --- a/arch/powerpc/boot/dts/katmai.dts +++ b/arch/powerpc/boot/dts/katmai.dts | |||
@@ -16,7 +16,7 @@ | |||
16 | 16 | ||
17 | / { | 17 | / { |
18 | #address-cells = <2>; | 18 | #address-cells = <2>; |
19 | #size-cells = <1>; | 19 | #size-cells = <2>; |
20 | model = "amcc,katmai"; | 20 | model = "amcc,katmai"; |
21 | compatible = "amcc,katmai"; | 21 | compatible = "amcc,katmai"; |
22 | dcr-parent = <&{/cpus/cpu@0}>; | 22 | dcr-parent = <&{/cpus/cpu@0}>; |
@@ -49,7 +49,7 @@ | |||
49 | 49 | ||
50 | memory { | 50 | memory { |
51 | device_type = "memory"; | 51 | device_type = "memory"; |
52 | reg = <0x00000000 0x00000000 0x00000000>; /* Filled in by zImage */ | 52 | reg = <0x0 0x00000000 0x0 0x00000000>; /* Filled in by U-Boot */ |
53 | }; | 53 | }; |
54 | 54 | ||
55 | UIC0: interrupt-controller0 { | 55 | UIC0: interrupt-controller0 { |
@@ -112,7 +112,15 @@ | |||
112 | compatible = "ibm,plb-440spe", "ibm,plb-440gp", "ibm,plb4"; | 112 | compatible = "ibm,plb-440spe", "ibm,plb-440gp", "ibm,plb4"; |
113 | #address-cells = <2>; | 113 | #address-cells = <2>; |
114 | #size-cells = <1>; | 114 | #size-cells = <1>; |
115 | ranges; | 115 | /* addr-child addr-parent size */ |
116 | ranges = <0x4 0xe0000000 0x4 0xe0000000 0x20000000 | ||
117 | 0xc 0x00000000 0xc 0x00000000 0x20000000 | ||
118 | 0xd 0x00000000 0xd 0x00000000 0x80000000 | ||
119 | 0xd 0x80000000 0xd 0x80000000 0x80000000 | ||
120 | 0xe 0x00000000 0xe 0x00000000 0x80000000 | ||
121 | 0xe 0x80000000 0xe 0x80000000 0x80000000 | ||
122 | 0xf 0x00000000 0xf 0x00000000 0x80000000 | ||
123 | 0xf 0x80000000 0xf 0x80000000 0x80000000>; | ||
116 | clock-frequency = <0>; /* Filled in by zImage */ | 124 | clock-frequency = <0>; /* Filled in by zImage */ |
117 | 125 | ||
118 | SDRAM0: sdram { | 126 | SDRAM0: sdram { |
@@ -245,8 +253,8 @@ | |||
245 | ranges = <0x02000000 0x00000000 0x80000000 0x0000000d 0x80000000 0x00000000 0x80000000 | 253 | ranges = <0x02000000 0x00000000 0x80000000 0x0000000d 0x80000000 0x00000000 0x80000000 |
246 | 0x01000000 0x00000000 0x00000000 0x0000000c 0x08000000 0x00000000 0x00010000>; | 254 | 0x01000000 0x00000000 0x00000000 0x0000000c 0x08000000 0x00000000 0x00010000>; |
247 | 255 | ||
248 | /* Inbound 2GB range starting at 0 */ | 256 | /* Inbound 4GB range starting at 0 */ |
249 | dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x80000000>; | 257 | dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x1 0x00000000>; |
250 | 258 | ||
251 | /* This drives busses 0 to 0xf */ | 259 | /* This drives busses 0 to 0xf */ |
252 | bus-range = <0x0 0xf>; | 260 | bus-range = <0x0 0xf>; |
@@ -289,10 +297,10 @@ | |||
289 | ranges = <0x02000000 0x00000000 0x80000000 0x0000000e 0x00000000 0x00000000 0x80000000 | 297 | ranges = <0x02000000 0x00000000 0x80000000 0x0000000e 0x00000000 0x00000000 0x80000000 |
290 | 0x01000000 0x00000000 0x00000000 0x0000000f 0x80000000 0x00000000 0x00010000>; | 298 | 0x01000000 0x00000000 0x00000000 0x0000000f 0x80000000 0x00000000 0x00010000>; |
291 | 299 | ||
292 | /* Inbound 2GB range starting at 0 */ | 300 | /* Inbound 4GB range starting at 0 */ |
293 | dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x80000000>; | 301 | dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x1 0x00000000>; |
294 | 302 | ||
295 | /* This drives busses 10 to 0x1f */ | 303 | /* This drives busses 0x10 to 0x1f */ |
296 | bus-range = <0x10 0x1f>; | 304 | bus-range = <0x10 0x1f>; |
297 | 305 | ||
298 | /* Legacy interrupts (note the weird polarity, the bridge seems | 306 | /* Legacy interrupts (note the weird polarity, the bridge seems |
@@ -330,10 +338,10 @@ | |||
330 | ranges = <0x02000000 0x00000000 0x80000000 0x0000000e 0x80000000 0x00000000 0x80000000 | 338 | ranges = <0x02000000 0x00000000 0x80000000 0x0000000e 0x80000000 0x00000000 0x80000000 |
331 | 0x01000000 0x00000000 0x00000000 0x0000000f 0x80010000 0x00000000 0x00010000>; | 339 | 0x01000000 0x00000000 0x00000000 0x0000000f 0x80010000 0x00000000 0x00010000>; |
332 | 340 | ||
333 | /* Inbound 2GB range starting at 0 */ | 341 | /* Inbound 4GB range starting at 0 */ |
334 | dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x80000000>; | 342 | dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x1 0x00000000>; |
335 | 343 | ||
336 | /* This drives busses 10 to 0x1f */ | 344 | /* This drives busses 0x20 to 0x2f */ |
337 | bus-range = <0x20 0x2f>; | 345 | bus-range = <0x20 0x2f>; |
338 | 346 | ||
339 | /* Legacy interrupts (note the weird polarity, the bridge seems | 347 | /* Legacy interrupts (note the weird polarity, the bridge seems |
@@ -371,10 +379,10 @@ | |||
371 | ranges = <0x02000000 0x00000000 0x80000000 0x0000000f 0x00000000 0x00000000 0x80000000 | 379 | ranges = <0x02000000 0x00000000 0x80000000 0x0000000f 0x00000000 0x00000000 0x80000000 |
372 | 0x01000000 0x00000000 0x00000000 0x0000000f 0x80020000 0x00000000 0x00010000>; | 380 | 0x01000000 0x00000000 0x00000000 0x0000000f 0x80020000 0x00000000 0x00010000>; |
373 | 381 | ||
374 | /* Inbound 2GB range starting at 0 */ | 382 | /* Inbound 4GB range starting at 0 */ |
375 | dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x80000000>; | 383 | dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x1 0x00000000>; |
376 | 384 | ||
377 | /* This drives busses 10 to 0x1f */ | 385 | /* This drives busses 0x30 to 0x3f */ |
378 | bus-range = <0x30 0x3f>; | 386 | bus-range = <0x30 0x3f>; |
379 | 387 | ||
380 | /* Legacy interrupts (note the weird polarity, the bridge seems | 388 | /* Legacy interrupts (note the weird polarity, the bridge seems |
diff --git a/arch/powerpc/boot/dts/kilauea.dts b/arch/powerpc/boot/dts/kilauea.dts index c46561456ede..083e68eeaca4 100644 --- a/arch/powerpc/boot/dts/kilauea.dts +++ b/arch/powerpc/boot/dts/kilauea.dts | |||
@@ -272,6 +272,8 @@ | |||
272 | max-frame-size = <9000>; | 272 | max-frame-size = <9000>; |
273 | rx-fifo-size = <4096>; | 273 | rx-fifo-size = <4096>; |
274 | tx-fifo-size = <2048>; | 274 | tx-fifo-size = <2048>; |
275 | rx-fifo-size-gige = <16384>; | ||
276 | tx-fifo-size-gige = <16384>; | ||
275 | phy-mode = "rgmii"; | 277 | phy-mode = "rgmii"; |
276 | phy-map = <0x00000000>; | 278 | phy-map = <0x00000000>; |
277 | rgmii-device = <&RGMII0>; | 279 | rgmii-device = <&RGMII0>; |
@@ -300,6 +302,8 @@ | |||
300 | max-frame-size = <9000>; | 302 | max-frame-size = <9000>; |
301 | rx-fifo-size = <4096>; | 303 | rx-fifo-size = <4096>; |
302 | tx-fifo-size = <2048>; | 304 | tx-fifo-size = <2048>; |
305 | rx-fifo-size-gige = <16384>; | ||
306 | tx-fifo-size-gige = <16384>; | ||
303 | phy-mode = "rgmii"; | 307 | phy-mode = "rgmii"; |
304 | phy-map = <0x00000000>; | 308 | phy-map = <0x00000000>; |
305 | rgmii-device = <&RGMII0>; | 309 | rgmii-device = <&RGMII0>; |
diff --git a/arch/powerpc/boot/dts/kmeter1.dts b/arch/powerpc/boot/dts/kmeter1.dts index 167044f7de1d..65b8b4f27efe 100644 --- a/arch/powerpc/boot/dts/kmeter1.dts +++ b/arch/powerpc/boot/dts/kmeter1.dts | |||
@@ -59,6 +59,13 @@ | |||
59 | reg = <0xe0000000 0x00000200>; | 59 | reg = <0xe0000000 0x00000200>; |
60 | bus-frequency = <0>; /* Filled in by U-Boot */ | 60 | bus-frequency = <0>; /* Filled in by U-Boot */ |
61 | 61 | ||
62 | pmc: power@b00 { | ||
63 | compatible = "fsl,mpc8360-pmc", "fsl,mpc8349-pmc"; | ||
64 | reg = <0xb00 0x100 0xa00 0x100>; | ||
65 | interrupts = <80 0x8>; | ||
66 | interrupt-parent = <&ipic>; | ||
67 | }; | ||
68 | |||
62 | i2c@3000 { | 69 | i2c@3000 { |
63 | #address-cells = <1>; | 70 | #address-cells = <1>; |
64 | #size-cells = <0>; | 71 | #size-cells = <0>; |
diff --git a/arch/powerpc/boot/dts/makalu.dts b/arch/powerpc/boot/dts/makalu.dts index ffc246e72670..63d48b632c84 100644 --- a/arch/powerpc/boot/dts/makalu.dts +++ b/arch/powerpc/boot/dts/makalu.dts | |||
@@ -227,6 +227,8 @@ | |||
227 | max-frame-size = <9000>; | 227 | max-frame-size = <9000>; |
228 | rx-fifo-size = <4096>; | 228 | rx-fifo-size = <4096>; |
229 | tx-fifo-size = <2048>; | 229 | tx-fifo-size = <2048>; |
230 | rx-fifo-size-gige = <16384>; | ||
231 | tx-fifo-size-gige = <16384>; | ||
230 | phy-mode = "rgmii"; | 232 | phy-mode = "rgmii"; |
231 | phy-map = <0x0000003f>; /* Start at 6 */ | 233 | phy-map = <0x0000003f>; /* Start at 6 */ |
232 | rgmii-device = <&RGMII0>; | 234 | rgmii-device = <&RGMII0>; |
@@ -255,6 +257,8 @@ | |||
255 | max-frame-size = <9000>; | 257 | max-frame-size = <9000>; |
256 | rx-fifo-size = <4096>; | 258 | rx-fifo-size = <4096>; |
257 | tx-fifo-size = <2048>; | 259 | tx-fifo-size = <2048>; |
260 | rx-fifo-size-gige = <16384>; | ||
261 | tx-fifo-size-gige = <16384>; | ||
258 | phy-mode = "rgmii"; | 262 | phy-mode = "rgmii"; |
259 | phy-map = <0x00000000>; | 263 | phy-map = <0x00000000>; |
260 | rgmii-device = <&RGMII0>; | 264 | rgmii-device = <&RGMII0>; |
diff --git a/arch/powerpc/boot/dts/mpc832x_mds.dts b/arch/powerpc/boot/dts/mpc832x_mds.dts index 436c9c671dd9..05ad8c98e527 100644 --- a/arch/powerpc/boot/dts/mpc832x_mds.dts +++ b/arch/powerpc/boot/dts/mpc832x_mds.dts | |||
@@ -79,6 +79,13 @@ | |||
79 | reg = <0x200 0x100>; | 79 | reg = <0x200 0x100>; |
80 | }; | 80 | }; |
81 | 81 | ||
82 | pmc: power@b00 { | ||
83 | compatible = "fsl,mpc8323-pmc", "fsl,mpc8349-pmc"; | ||
84 | reg = <0xb00 0x100 0xa00 0x100>; | ||
85 | interrupts = <80 0x8>; | ||
86 | interrupt-parent = <&ipic>; | ||
87 | }; | ||
88 | |||
82 | i2c@3000 { | 89 | i2c@3000 { |
83 | #address-cells = <1>; | 90 | #address-cells = <1>; |
84 | #size-cells = <0>; | 91 | #size-cells = <0>; |
@@ -163,6 +170,7 @@ | |||
163 | fsl,channel-fifo-len = <24>; | 170 | fsl,channel-fifo-len = <24>; |
164 | fsl,exec-units-mask = <0x4c>; | 171 | fsl,exec-units-mask = <0x4c>; |
165 | fsl,descriptor-types-mask = <0x0122003f>; | 172 | fsl,descriptor-types-mask = <0x0122003f>; |
173 | sleep = <&pmc 0x03000000>; | ||
166 | }; | 174 | }; |
167 | 175 | ||
168 | ipic: pic@700 { | 176 | ipic: pic@700 { |
@@ -428,5 +436,6 @@ | |||
428 | 0xe0008300 0x8>; /* config space access registers */ | 436 | 0xe0008300 0x8>; /* config space access registers */ |
429 | compatible = "fsl,mpc8349-pci"; | 437 | compatible = "fsl,mpc8349-pci"; |
430 | device_type = "pci"; | 438 | device_type = "pci"; |
439 | sleep = <&pmc 0x00010000>; | ||
431 | }; | 440 | }; |
432 | }; | 441 | }; |
diff --git a/arch/powerpc/boot/dts/mpc832x_rdb.dts b/arch/powerpc/boot/dts/mpc832x_rdb.dts index 9a0952f74b81..f4fadb23ad6f 100644 --- a/arch/powerpc/boot/dts/mpc832x_rdb.dts +++ b/arch/powerpc/boot/dts/mpc832x_rdb.dts | |||
@@ -62,6 +62,13 @@ | |||
62 | reg = <0x200 0x100>; | 62 | reg = <0x200 0x100>; |
63 | }; | 63 | }; |
64 | 64 | ||
65 | pmc: power@b00 { | ||
66 | compatible = "fsl,mpc8323-pmc", "fsl,mpc8349-pmc"; | ||
67 | reg = <0xb00 0x100 0xa00 0x100>; | ||
68 | interrupts = <80 0x8>; | ||
69 | interrupt-parent = <&ipic>; | ||
70 | }; | ||
71 | |||
65 | i2c@3000 { | 72 | i2c@3000 { |
66 | #address-cells = <1>; | 73 | #address-cells = <1>; |
67 | #size-cells = <0>; | 74 | #size-cells = <0>; |
@@ -141,6 +148,7 @@ | |||
141 | fsl,channel-fifo-len = <24>; | 148 | fsl,channel-fifo-len = <24>; |
142 | fsl,exec-units-mask = <0x4c>; | 149 | fsl,exec-units-mask = <0x4c>; |
143 | fsl,descriptor-types-mask = <0x0122003f>; | 150 | fsl,descriptor-types-mask = <0x0122003f>; |
151 | sleep = <&pmc 0x03000000>; | ||
144 | }; | 152 | }; |
145 | 153 | ||
146 | ipic:pic@700 { | 154 | ipic:pic@700 { |
@@ -360,5 +368,6 @@ | |||
360 | 0xe0008300 0x8>; /* config space access registers */ | 368 | 0xe0008300 0x8>; /* config space access registers */ |
361 | compatible = "fsl,mpc8349-pci"; | 369 | compatible = "fsl,mpc8349-pci"; |
362 | device_type = "pci"; | 370 | device_type = "pci"; |
371 | sleep = <&pmc 0x00010000>; | ||
363 | }; | 372 | }; |
364 | }; | 373 | }; |
diff --git a/arch/powerpc/boot/dts/mpc836x_mds.dts b/arch/powerpc/boot/dts/mpc836x_mds.dts index 39ff4c829caf..45cfa1c50a2a 100644 --- a/arch/powerpc/boot/dts/mpc836x_mds.dts +++ b/arch/powerpc/boot/dts/mpc836x_mds.dts | |||
@@ -99,6 +99,13 @@ | |||
99 | reg = <0x200 0x100>; | 99 | reg = <0x200 0x100>; |
100 | }; | 100 | }; |
101 | 101 | ||
102 | pmc: power@b00 { | ||
103 | compatible = "fsl,mpc8360-pmc", "fsl,mpc8349-pmc"; | ||
104 | reg = <0xb00 0x100 0xa00 0x100>; | ||
105 | interrupts = <80 0x8>; | ||
106 | interrupt-parent = <&ipic>; | ||
107 | }; | ||
108 | |||
102 | i2c@3000 { | 109 | i2c@3000 { |
103 | #address-cells = <1>; | 110 | #address-cells = <1>; |
104 | #size-cells = <0>; | 111 | #size-cells = <0>; |
@@ -194,6 +201,7 @@ | |||
194 | fsl,channel-fifo-len = <24>; | 201 | fsl,channel-fifo-len = <24>; |
195 | fsl,exec-units-mask = <0x7e>; | 202 | fsl,exec-units-mask = <0x7e>; |
196 | fsl,descriptor-types-mask = <0x01010ebf>; | 203 | fsl,descriptor-types-mask = <0x01010ebf>; |
204 | sleep = <&pmc 0x03000000>; | ||
197 | }; | 205 | }; |
198 | 206 | ||
199 | ipic: pic@700 { | 207 | ipic: pic@700 { |
@@ -470,5 +478,6 @@ | |||
470 | 0xe0008300 0x8>; /* config space access registers */ | 478 | 0xe0008300 0x8>; /* config space access registers */ |
471 | compatible = "fsl,mpc8349-pci"; | 479 | compatible = "fsl,mpc8349-pci"; |
472 | device_type = "pci"; | 480 | device_type = "pci"; |
481 | sleep = <&pmc 0x00010000>; | ||
473 | }; | 482 | }; |
474 | }; | 483 | }; |
diff --git a/arch/powerpc/boot/dts/mpc836x_rdk.dts b/arch/powerpc/boot/dts/mpc836x_rdk.dts index 6315d6fcc58a..bdf4459677b1 100644 --- a/arch/powerpc/boot/dts/mpc836x_rdk.dts +++ b/arch/powerpc/boot/dts/mpc836x_rdk.dts | |||
@@ -71,6 +71,13 @@ | |||
71 | reg = <0x200 0x100>; | 71 | reg = <0x200 0x100>; |
72 | }; | 72 | }; |
73 | 73 | ||
74 | pmc: power@b00 { | ||
75 | compatible = "fsl,mpc8360-pmc", "fsl,mpc8349-pmc"; | ||
76 | reg = <0xb00 0x100 0xa00 0x100>; | ||
77 | interrupts = <80 0x8>; | ||
78 | interrupt-parent = <&ipic>; | ||
79 | }; | ||
80 | |||
74 | i2c@3000 { | 81 | i2c@3000 { |
75 | #address-cells = <1>; | 82 | #address-cells = <1>; |
76 | #size-cells = <0>; | 83 | #size-cells = <0>; |
@@ -161,6 +168,7 @@ | |||
161 | fsl,channel-fifo-len = <24>; | 168 | fsl,channel-fifo-len = <24>; |
162 | fsl,exec-units-mask = <0x7e>; | 169 | fsl,exec-units-mask = <0x7e>; |
163 | fsl,descriptor-types-mask = <0x01010ebf>; | 170 | fsl,descriptor-types-mask = <0x01010ebf>; |
171 | sleep = <&pmc 0x03000000>; | ||
164 | }; | 172 | }; |
165 | 173 | ||
166 | ipic: interrupt-controller@700 { | 174 | ipic: interrupt-controller@700 { |
@@ -455,6 +463,7 @@ | |||
455 | 0xa800 0 0 2 &ipic 20 8 | 463 | 0xa800 0 0 2 &ipic 20 8 |
456 | 0xa800 0 0 3 &ipic 21 8 | 464 | 0xa800 0 0 3 &ipic 21 8 |
457 | 0xa800 0 0 4 &ipic 18 8>; | 465 | 0xa800 0 0 4 &ipic 18 8>; |
466 | sleep = <&pmc 0x00010000>; | ||
458 | /* filled by u-boot */ | 467 | /* filled by u-boot */ |
459 | bus-range = <0 0>; | 468 | bus-range = <0 0>; |
460 | clock-frequency = <0>; | 469 | clock-frequency = <0>; |
diff --git a/arch/powerpc/boot/dts/mpc8568mds.dts b/arch/powerpc/boot/dts/mpc8568mds.dts index 00c2bbda7013..6d892ba74e55 100644 --- a/arch/powerpc/boot/dts/mpc8568mds.dts +++ b/arch/powerpc/boot/dts/mpc8568mds.dts | |||
@@ -40,6 +40,8 @@ | |||
40 | i-cache-line-size = <32>; // 32 bytes | 40 | i-cache-line-size = <32>; // 32 bytes |
41 | d-cache-size = <0x8000>; // L1, 32K | 41 | d-cache-size = <0x8000>; // L1, 32K |
42 | i-cache-size = <0x8000>; // L1, 32K | 42 | i-cache-size = <0x8000>; // L1, 32K |
43 | sleep = <&pmc 0x00008000 // core | ||
44 | &pmc 0x00004000>; // timebase | ||
43 | timebase-frequency = <0>; | 45 | timebase-frequency = <0>; |
44 | bus-frequency = <0>; | 46 | bus-frequency = <0>; |
45 | clock-frequency = <0>; | 47 | clock-frequency = <0>; |
@@ -94,31 +96,41 @@ | |||
94 | interrupts = <16 2>; | 96 | interrupts = <16 2>; |
95 | }; | 97 | }; |
96 | 98 | ||
97 | i2c@3000 { | 99 | i2c-sleep-nexus { |
98 | #address-cells = <1>; | 100 | #address-cells = <1>; |
99 | #size-cells = <0>; | 101 | #size-cells = <1>; |
100 | cell-index = <0>; | 102 | compatible = "simple-bus"; |
101 | compatible = "fsl-i2c"; | 103 | sleep = <&pmc 0x00000004>; |
102 | reg = <0x3000 0x100>; | 104 | ranges; |
103 | interrupts = <43 2>; | ||
104 | interrupt-parent = <&mpic>; | ||
105 | dfsrr; | ||
106 | 105 | ||
107 | rtc@68 { | 106 | i2c@3000 { |
108 | compatible = "dallas,ds1374"; | 107 | #address-cells = <1>; |
109 | reg = <0x68>; | 108 | #size-cells = <0>; |
109 | cell-index = <0>; | ||
110 | compatible = "fsl-i2c"; | ||
111 | reg = <0x3000 0x100>; | ||
112 | interrupts = <43 2>; | ||
113 | interrupt-parent = <&mpic>; | ||
114 | dfsrr; | ||
115 | |||
116 | rtc@68 { | ||
117 | compatible = "dallas,ds1374"; | ||
118 | reg = <0x68>; | ||
119 | interrupts = <3 1>; | ||
120 | interrupt-parent = <&mpic>; | ||
121 | }; | ||
110 | }; | 122 | }; |
111 | }; | ||
112 | 123 | ||
113 | i2c@3100 { | 124 | i2c@3100 { |
114 | #address-cells = <1>; | 125 | #address-cells = <1>; |
115 | #size-cells = <0>; | 126 | #size-cells = <0>; |
116 | cell-index = <1>; | 127 | cell-index = <1>; |
117 | compatible = "fsl-i2c"; | 128 | compatible = "fsl-i2c"; |
118 | reg = <0x3100 0x100>; | 129 | reg = <0x3100 0x100>; |
119 | interrupts = <43 2>; | 130 | interrupts = <43 2>; |
120 | interrupt-parent = <&mpic>; | 131 | interrupt-parent = <&mpic>; |
121 | dfsrr; | 132 | dfsrr; |
133 | }; | ||
122 | }; | 134 | }; |
123 | 135 | ||
124 | dma@21300 { | 136 | dma@21300 { |
@@ -128,6 +140,8 @@ | |||
128 | reg = <0x21300 0x4>; | 140 | reg = <0x21300 0x4>; |
129 | ranges = <0x0 0x21100 0x200>; | 141 | ranges = <0x0 0x21100 0x200>; |
130 | cell-index = <0>; | 142 | cell-index = <0>; |
143 | sleep = <&pmc 0x00000400>; | ||
144 | |||
131 | dma-channel@0 { | 145 | dma-channel@0 { |
132 | compatible = "fsl,mpc8568-dma-channel", | 146 | compatible = "fsl,mpc8568-dma-channel", |
133 | "fsl,eloplus-dma-channel"; | 147 | "fsl,eloplus-dma-channel"; |
@@ -176,6 +190,7 @@ | |||
176 | interrupt-parent = <&mpic>; | 190 | interrupt-parent = <&mpic>; |
177 | tbi-handle = <&tbi0>; | 191 | tbi-handle = <&tbi0>; |
178 | phy-handle = <&phy2>; | 192 | phy-handle = <&phy2>; |
193 | sleep = <&pmc 0x00000080>; | ||
179 | 194 | ||
180 | mdio@520 { | 195 | mdio@520 { |
181 | #address-cells = <1>; | 196 | #address-cells = <1>; |
@@ -228,6 +243,7 @@ | |||
228 | interrupt-parent = <&mpic>; | 243 | interrupt-parent = <&mpic>; |
229 | tbi-handle = <&tbi1>; | 244 | tbi-handle = <&tbi1>; |
230 | phy-handle = <&phy3>; | 245 | phy-handle = <&phy3>; |
246 | sleep = <&pmc 0x00000040>; | ||
231 | 247 | ||
232 | mdio@520 { | 248 | mdio@520 { |
233 | #address-cells = <1>; | 249 | #address-cells = <1>; |
@@ -242,30 +258,47 @@ | |||
242 | }; | 258 | }; |
243 | }; | 259 | }; |
244 | 260 | ||
245 | serial0: serial@4500 { | 261 | duart-sleep-nexus { |
246 | cell-index = <0>; | 262 | #address-cells = <1>; |
247 | device_type = "serial"; | 263 | #size-cells = <1>; |
248 | compatible = "ns16550"; | 264 | compatible = "simple-bus"; |
249 | reg = <0x4500 0x100>; | 265 | sleep = <&pmc 0x00000002>; |
250 | clock-frequency = <0>; | 266 | ranges; |
251 | interrupts = <42 2>; | 267 | |
252 | interrupt-parent = <&mpic>; | 268 | serial0: serial@4500 { |
269 | cell-index = <0>; | ||
270 | device_type = "serial"; | ||
271 | compatible = "ns16550"; | ||
272 | reg = <0x4500 0x100>; | ||
273 | clock-frequency = <0>; | ||
274 | interrupts = <42 2>; | ||
275 | interrupt-parent = <&mpic>; | ||
276 | }; | ||
277 | |||
278 | serial1: serial@4600 { | ||
279 | cell-index = <1>; | ||
280 | device_type = "serial"; | ||
281 | compatible = "ns16550"; | ||
282 | reg = <0x4600 0x100>; | ||
283 | clock-frequency = <0>; | ||
284 | interrupts = <42 2>; | ||
285 | interrupt-parent = <&mpic>; | ||
286 | }; | ||
253 | }; | 287 | }; |
254 | 288 | ||
255 | global-utilities@e0000 { //global utilities block | 289 | global-utilities@e0000 { |
256 | compatible = "fsl,mpc8548-guts"; | 290 | #address-cells = <1>; |
291 | #size-cells = <1>; | ||
292 | compatible = "fsl,mpc8568-guts", "fsl,mpc8548-guts"; | ||
257 | reg = <0xe0000 0x1000>; | 293 | reg = <0xe0000 0x1000>; |
294 | ranges = <0 0xe0000 0x1000>; | ||
258 | fsl,has-rstcr; | 295 | fsl,has-rstcr; |
259 | }; | ||
260 | 296 | ||
261 | serial1: serial@4600 { | 297 | pmc: power@70 { |
262 | cell-index = <1>; | 298 | compatible = "fsl,mpc8568-pmc", |
263 | device_type = "serial"; | 299 | "fsl,mpc8548-pmc"; |
264 | compatible = "ns16550"; | 300 | reg = <0x70 0x20>; |
265 | reg = <0x4600 0x100>; | 301 | }; |
266 | clock-frequency = <0>; | ||
267 | interrupts = <42 2>; | ||
268 | interrupt-parent = <&mpic>; | ||
269 | }; | 302 | }; |
270 | 303 | ||
271 | crypto@30000 { | 304 | crypto@30000 { |
@@ -277,6 +310,7 @@ | |||
277 | fsl,channel-fifo-len = <24>; | 310 | fsl,channel-fifo-len = <24>; |
278 | fsl,exec-units-mask = <0xfe>; | 311 | fsl,exec-units-mask = <0xfe>; |
279 | fsl,descriptor-types-mask = <0x12b0ebf>; | 312 | fsl,descriptor-types-mask = <0x12b0ebf>; |
313 | sleep = <&pmc 0x01000000>; | ||
280 | }; | 314 | }; |
281 | 315 | ||
282 | mpic: pic@40000 { | 316 | mpic: pic@40000 { |
@@ -376,6 +410,7 @@ | |||
376 | compatible = "fsl,qe"; | 410 | compatible = "fsl,qe"; |
377 | ranges = <0x0 0xe0080000 0x40000>; | 411 | ranges = <0x0 0xe0080000 0x40000>; |
378 | reg = <0xe0080000 0x480>; | 412 | reg = <0xe0080000 0x480>; |
413 | sleep = <&pmc 0x00000800>; | ||
379 | brg-frequency = <0>; | 414 | brg-frequency = <0>; |
380 | bus-frequency = <396000000>; | 415 | bus-frequency = <396000000>; |
381 | fsl,qe-num-riscs = <2>; | 416 | fsl,qe-num-riscs = <2>; |
@@ -509,6 +544,7 @@ | |||
509 | bus-range = <0 255>; | 544 | bus-range = <0 255>; |
510 | ranges = <0x2000000 0x0 0x80000000 0x80000000 0x0 0x20000000 | 545 | ranges = <0x2000000 0x0 0x80000000 0x80000000 0x0 0x20000000 |
511 | 0x1000000 0x0 0x0 0xe2000000 0x0 0x800000>; | 546 | 0x1000000 0x0 0x0 0xe2000000 0x0 0x800000>; |
547 | sleep = <&pmc 0x80000000>; | ||
512 | clock-frequency = <66666666>; | 548 | clock-frequency = <66666666>; |
513 | #interrupt-cells = <1>; | 549 | #interrupt-cells = <1>; |
514 | #size-cells = <2>; | 550 | #size-cells = <2>; |
@@ -534,6 +570,7 @@ | |||
534 | bus-range = <0 255>; | 570 | bus-range = <0 255>; |
535 | ranges = <0x2000000 0x0 0xa0000000 0xa0000000 0x0 0x10000000 | 571 | ranges = <0x2000000 0x0 0xa0000000 0xa0000000 0x0 0x10000000 |
536 | 0x1000000 0x0 0x0 0xe2800000 0x0 0x800000>; | 572 | 0x1000000 0x0 0x0 0xe2800000 0x0 0x800000>; |
573 | sleep = <&pmc 0x20000000>; | ||
537 | clock-frequency = <33333333>; | 574 | clock-frequency = <33333333>; |
538 | #interrupt-cells = <1>; | 575 | #interrupt-cells = <1>; |
539 | #size-cells = <2>; | 576 | #size-cells = <2>; |
@@ -570,5 +607,7 @@ | |||
570 | 55 2 /* msg2_tx */ | 607 | 55 2 /* msg2_tx */ |
571 | 56 2 /* msg2_rx */>; | 608 | 56 2 /* msg2_rx */>; |
572 | interrupt-parent = <&mpic>; | 609 | interrupt-parent = <&mpic>; |
610 | sleep = <&pmc 0x00080000 /* controller */ | ||
611 | &pmc 0x00040000>; /* message unit */ | ||
573 | }; | 612 | }; |
574 | }; | 613 | }; |
diff --git a/arch/powerpc/boot/dts/mpc8569mds.dts b/arch/powerpc/boot/dts/mpc8569mds.dts index 1e3ec8f059bf..795eb362fcf9 100644 --- a/arch/powerpc/boot/dts/mpc8569mds.dts +++ b/arch/powerpc/boot/dts/mpc8569mds.dts | |||
@@ -41,6 +41,8 @@ | |||
41 | i-cache-line-size = <32>; // 32 bytes | 41 | i-cache-line-size = <32>; // 32 bytes |
42 | d-cache-size = <0x8000>; // L1, 32K | 42 | d-cache-size = <0x8000>; // L1, 32K |
43 | i-cache-size = <0x8000>; // L1, 32K | 43 | i-cache-size = <0x8000>; // L1, 32K |
44 | sleep = <&pmc 0x00008000 // core | ||
45 | &pmc 0x00004000>; // timebase | ||
44 | timebase-frequency = <0>; | 46 | timebase-frequency = <0>; |
45 | bus-frequency = <0>; | 47 | bus-frequency = <0>; |
46 | clock-frequency = <0>; | 48 | clock-frequency = <0>; |
@@ -59,6 +61,7 @@ | |||
59 | reg = <0xe0005000 0x1000>; | 61 | reg = <0xe0005000 0x1000>; |
60 | interrupts = <19 2>; | 62 | interrupts = <19 2>; |
61 | interrupt-parent = <&mpic>; | 63 | interrupt-parent = <&mpic>; |
64 | sleep = <&pmc 0x08000000>; | ||
62 | 65 | ||
63 | ranges = <0x0 0x0 0xfe000000 0x02000000 | 66 | ranges = <0x0 0x0 0xfe000000 0x02000000 |
64 | 0x1 0x0 0xf8000000 0x00008000 | 67 | 0x1 0x0 0xf8000000 0x00008000 |
@@ -158,51 +161,69 @@ | |||
158 | interrupts = <18 2>; | 161 | interrupts = <18 2>; |
159 | }; | 162 | }; |
160 | 163 | ||
161 | i2c@3000 { | 164 | i2c-sleep-nexus { |
162 | #address-cells = <1>; | 165 | #address-cells = <1>; |
163 | #size-cells = <0>; | 166 | #size-cells = <1>; |
164 | cell-index = <0>; | 167 | compatible = "simple-bus"; |
165 | compatible = "fsl-i2c"; | 168 | sleep = <&pmc 0x00000004>; |
166 | reg = <0x3000 0x100>; | 169 | ranges; |
167 | interrupts = <43 2>; | 170 | |
168 | interrupt-parent = <&mpic>; | 171 | i2c@3000 { |
169 | dfsrr; | 172 | #address-cells = <1>; |
173 | #size-cells = <0>; | ||
174 | cell-index = <0>; | ||
175 | compatible = "fsl-i2c"; | ||
176 | reg = <0x3000 0x100>; | ||
177 | interrupts = <43 2>; | ||
178 | interrupt-parent = <&mpic>; | ||
179 | dfsrr; | ||
180 | |||
181 | rtc@68 { | ||
182 | compatible = "dallas,ds1374"; | ||
183 | reg = <0x68>; | ||
184 | interrupts = <3 1>; | ||
185 | interrupt-parent = <&mpic>; | ||
186 | }; | ||
187 | }; | ||
170 | 188 | ||
171 | rtc@68 { | 189 | i2c@3100 { |
172 | compatible = "dallas,ds1374"; | 190 | #address-cells = <1>; |
173 | reg = <0x68>; | 191 | #size-cells = <0>; |
192 | cell-index = <1>; | ||
193 | compatible = "fsl-i2c"; | ||
194 | reg = <0x3100 0x100>; | ||
195 | interrupts = <43 2>; | ||
196 | interrupt-parent = <&mpic>; | ||
197 | dfsrr; | ||
174 | }; | 198 | }; |
175 | }; | 199 | }; |
176 | 200 | ||
177 | i2c@3100 { | 201 | duart-sleep-nexus { |
178 | #address-cells = <1>; | 202 | #address-cells = <1>; |
179 | #size-cells = <0>; | 203 | #size-cells = <1>; |
180 | cell-index = <1>; | 204 | compatible = "simple-bus"; |
181 | compatible = "fsl-i2c"; | 205 | sleep = <&pmc 0x00000002>; |
182 | reg = <0x3100 0x100>; | 206 | ranges; |
183 | interrupts = <43 2>; | ||
184 | interrupt-parent = <&mpic>; | ||
185 | dfsrr; | ||
186 | }; | ||
187 | 207 | ||
188 | serial0: serial@4500 { | 208 | serial0: serial@4500 { |
189 | cell-index = <0>; | 209 | cell-index = <0>; |
190 | device_type = "serial"; | 210 | device_type = "serial"; |
191 | compatible = "ns16550"; | 211 | compatible = "ns16550"; |
192 | reg = <0x4500 0x100>; | 212 | reg = <0x4500 0x100>; |
193 | clock-frequency = <0>; | 213 | clock-frequency = <0>; |
194 | interrupts = <42 2>; | 214 | interrupts = <42 2>; |
195 | interrupt-parent = <&mpic>; | 215 | interrupt-parent = <&mpic>; |
196 | }; | 216 | }; |
197 | 217 | ||
198 | serial1: serial@4600 { | 218 | serial1: serial@4600 { |
199 | cell-index = <1>; | 219 | cell-index = <1>; |
200 | device_type = "serial"; | 220 | device_type = "serial"; |
201 | compatible = "ns16550"; | 221 | compatible = "ns16550"; |
202 | reg = <0x4600 0x100>; | 222 | reg = <0x4600 0x100>; |
203 | clock-frequency = <0>; | 223 | clock-frequency = <0>; |
204 | interrupts = <42 2>; | 224 | interrupts = <42 2>; |
205 | interrupt-parent = <&mpic>; | 225 | interrupt-parent = <&mpic>; |
226 | }; | ||
206 | }; | 227 | }; |
207 | 228 | ||
208 | L2: l2-cache-controller@20000 { | 229 | L2: l2-cache-controller@20000 { |
@@ -260,6 +281,7 @@ | |||
260 | reg = <0x2e000 0x1000>; | 281 | reg = <0x2e000 0x1000>; |
261 | interrupts = <72 0x8>; | 282 | interrupts = <72 0x8>; |
262 | interrupt-parent = <&mpic>; | 283 | interrupt-parent = <&mpic>; |
284 | sleep = <&pmc 0x00200000>; | ||
263 | /* Filled in by U-Boot */ | 285 | /* Filled in by U-Boot */ |
264 | clock-frequency = <0>; | 286 | clock-frequency = <0>; |
265 | status = "disabled"; | 287 | status = "disabled"; |
@@ -276,6 +298,7 @@ | |||
276 | fsl,channel-fifo-len = <24>; | 298 | fsl,channel-fifo-len = <24>; |
277 | fsl,exec-units-mask = <0xbfe>; | 299 | fsl,exec-units-mask = <0xbfe>; |
278 | fsl,descriptor-types-mask = <0x3ab0ebf>; | 300 | fsl,descriptor-types-mask = <0x3ab0ebf>; |
301 | sleep = <&pmc 0x01000000>; | ||
279 | }; | 302 | }; |
280 | 303 | ||
281 | mpic: pic@40000 { | 304 | mpic: pic@40000 { |
@@ -304,9 +327,18 @@ | |||
304 | }; | 327 | }; |
305 | 328 | ||
306 | global-utilities@e0000 { | 329 | global-utilities@e0000 { |
307 | compatible = "fsl,mpc8569-guts"; | 330 | #address-cells = <1>; |
331 | #size-cells = <1>; | ||
332 | compatible = "fsl,mpc8569-guts", "fsl,mpc8548-guts"; | ||
308 | reg = <0xe0000 0x1000>; | 333 | reg = <0xe0000 0x1000>; |
334 | ranges = <0 0xe0000 0x1000>; | ||
309 | fsl,has-rstcr; | 335 | fsl,has-rstcr; |
336 | |||
337 | pmc: power@70 { | ||
338 | compatible = "fsl,mpc8569-pmc", | ||
339 | "fsl,mpc8548-pmc"; | ||
340 | reg = <0x70 0x20>; | ||
341 | }; | ||
310 | }; | 342 | }; |
311 | 343 | ||
312 | par_io@e0100 { | 344 | par_io@e0100 { |
@@ -422,6 +454,7 @@ | |||
422 | compatible = "fsl,qe"; | 454 | compatible = "fsl,qe"; |
423 | ranges = <0x0 0xe0080000 0x40000>; | 455 | ranges = <0x0 0xe0080000 0x40000>; |
424 | reg = <0xe0080000 0x480>; | 456 | reg = <0xe0080000 0x480>; |
457 | sleep = <&pmc 0x00000800>; | ||
425 | brg-frequency = <0>; | 458 | brg-frequency = <0>; |
426 | bus-frequency = <0>; | 459 | bus-frequency = <0>; |
427 | fsl,qe-num-riscs = <4>; | 460 | fsl,qe-num-riscs = <4>; |
@@ -684,6 +717,7 @@ | |||
684 | bus-range = <0 255>; | 717 | bus-range = <0 255>; |
685 | ranges = <0x2000000 0x0 0xa0000000 0xa0000000 0x0 0x10000000 | 718 | ranges = <0x2000000 0x0 0xa0000000 0xa0000000 0x0 0x10000000 |
686 | 0x1000000 0x0 0x00000000 0xe2800000 0x0 0x00800000>; | 719 | 0x1000000 0x0 0x00000000 0xe2800000 0x0 0x00800000>; |
720 | sleep = <&pmc 0x20000000>; | ||
687 | clock-frequency = <33333333>; | 721 | clock-frequency = <33333333>; |
688 | pcie@0 { | 722 | pcie@0 { |
689 | reg = <0x0 0x0 0x0 0x0 0x0>; | 723 | reg = <0x0 0x0 0x0 0x0 0x0>; |
@@ -714,5 +748,6 @@ | |||
714 | 55 2 /* msg2_tx */ | 748 | 55 2 /* msg2_tx */ |
715 | 56 2 /* msg2_rx */>; | 749 | 56 2 /* msg2_rx */>; |
716 | interrupt-parent = <&mpic>; | 750 | interrupt-parent = <&mpic>; |
751 | sleep = <&pmc 0x00080000>; | ||
717 | }; | 752 | }; |
718 | }; | 753 | }; |
diff --git a/arch/powerpc/boot/dts/mpc8610_hpcd.dts b/arch/powerpc/boot/dts/mpc8610_hpcd.dts index f468d215f716..9535ce68caae 100644 --- a/arch/powerpc/boot/dts/mpc8610_hpcd.dts +++ b/arch/powerpc/boot/dts/mpc8610_hpcd.dts | |||
@@ -35,6 +35,8 @@ | |||
35 | i-cache-line-size = <32>; | 35 | i-cache-line-size = <32>; |
36 | d-cache-size = <32768>; // L1 | 36 | d-cache-size = <32768>; // L1 |
37 | i-cache-size = <32768>; // L1 | 37 | i-cache-size = <32768>; // L1 |
38 | sleep = <&pmc 0x00008000 0 // core | ||
39 | &pmc 0x00004000 0>; // timebase | ||
38 | timebase-frequency = <0>; // From uboot | 40 | timebase-frequency = <0>; // From uboot |
39 | bus-frequency = <0>; // From uboot | 41 | bus-frequency = <0>; // From uboot |
40 | clock-frequency = <0>; // From uboot | 42 | clock-frequency = <0>; // From uboot |
@@ -60,6 +62,7 @@ | |||
60 | 5 0 0xe8480000 0x00008000 | 62 | 5 0 0xe8480000 0x00008000 |
61 | 6 0 0xe84c0000 0x00008000 | 63 | 6 0 0xe84c0000 0x00008000 |
62 | 3 0 0xe8000000 0x00000020>; | 64 | 3 0 0xe8000000 0x00000020>; |
65 | sleep = <&pmc 0x08000000 0>; | ||
63 | 66 | ||
64 | flash@0,0 { | 67 | flash@0,0 { |
65 | compatible = "cfi-flash"; | 68 | compatible = "cfi-flash"; |
@@ -105,6 +108,8 @@ | |||
105 | compatible = "fsl,fpga-pixis"; | 108 | compatible = "fsl,fpga-pixis"; |
106 | reg = <3 0 0x20>; | 109 | reg = <3 0 0x20>; |
107 | ranges = <0 3 0 0x20>; | 110 | ranges = <0 3 0 0x20>; |
111 | interrupt-parent = <&mpic>; | ||
112 | interrupts = <8 8>; | ||
108 | 113 | ||
109 | sdcsr_pio: gpio-controller@a { | 114 | sdcsr_pio: gpio-controller@a { |
110 | #gpio-cells = <2>; | 115 | #gpio-cells = <2>; |
@@ -163,6 +168,7 @@ | |||
163 | reg = <0x3100 0x100>; | 168 | reg = <0x3100 0x100>; |
164 | interrupts = <43 2>; | 169 | interrupts = <43 2>; |
165 | interrupt-parent = <&mpic>; | 170 | interrupt-parent = <&mpic>; |
171 | sleep = <&pmc 0x00000004 0>; | ||
166 | dfsrr; | 172 | dfsrr; |
167 | }; | 173 | }; |
168 | 174 | ||
@@ -174,6 +180,7 @@ | |||
174 | clock-frequency = <0>; | 180 | clock-frequency = <0>; |
175 | interrupts = <42 2>; | 181 | interrupts = <42 2>; |
176 | interrupt-parent = <&mpic>; | 182 | interrupt-parent = <&mpic>; |
183 | sleep = <&pmc 0x00000002 0>; | ||
177 | }; | 184 | }; |
178 | 185 | ||
179 | serial1: serial@4600 { | 186 | serial1: serial@4600 { |
@@ -184,6 +191,7 @@ | |||
184 | clock-frequency = <0>; | 191 | clock-frequency = <0>; |
185 | interrupts = <42 2>; | 192 | interrupts = <42 2>; |
186 | interrupt-parent = <&mpic>; | 193 | interrupt-parent = <&mpic>; |
194 | sleep = <&pmc 0x00000008 0>; | ||
187 | }; | 195 | }; |
188 | 196 | ||
189 | spi@7000 { | 197 | spi@7000 { |
@@ -196,6 +204,7 @@ | |||
196 | interrupt-parent = <&mpic>; | 204 | interrupt-parent = <&mpic>; |
197 | mode = "cpu"; | 205 | mode = "cpu"; |
198 | gpios = <&sdcsr_pio 7 0>; | 206 | gpios = <&sdcsr_pio 7 0>; |
207 | sleep = <&pmc 0x00000800 0>; | ||
199 | 208 | ||
200 | mmc-slot@0 { | 209 | mmc-slot@0 { |
201 | compatible = "fsl,mpc8610hpcd-mmc-slot", | 210 | compatible = "fsl,mpc8610hpcd-mmc-slot", |
@@ -213,6 +222,7 @@ | |||
213 | reg = <0x2c000 100>; | 222 | reg = <0x2c000 100>; |
214 | interrupts = <72 2>; | 223 | interrupts = <72 2>; |
215 | interrupt-parent = <&mpic>; | 224 | interrupt-parent = <&mpic>; |
225 | sleep = <&pmc 0x04000000 0>; | ||
216 | }; | 226 | }; |
217 | 227 | ||
218 | mpic: interrupt-controller@40000 { | 228 | mpic: interrupt-controller@40000 { |
@@ -241,9 +251,18 @@ | |||
241 | }; | 251 | }; |
242 | 252 | ||
243 | global-utilities@e0000 { | 253 | global-utilities@e0000 { |
254 | #address-cells = <1>; | ||
255 | #size-cells = <1>; | ||
244 | compatible = "fsl,mpc8610-guts"; | 256 | compatible = "fsl,mpc8610-guts"; |
245 | reg = <0xe0000 0x1000>; | 257 | reg = <0xe0000 0x1000>; |
258 | ranges = <0 0xe0000 0x1000>; | ||
246 | fsl,has-rstcr; | 259 | fsl,has-rstcr; |
260 | |||
261 | pmc: power@70 { | ||
262 | compatible = "fsl,mpc8610-pmc", | ||
263 | "fsl,mpc8641d-pmc"; | ||
264 | reg = <0x70 0x20>; | ||
265 | }; | ||
247 | }; | 266 | }; |
248 | 267 | ||
249 | wdt@e4000 { | 268 | wdt@e4000 { |
@@ -262,6 +281,7 @@ | |||
262 | fsl,playback-dma = <&dma00>; | 281 | fsl,playback-dma = <&dma00>; |
263 | fsl,capture-dma = <&dma01>; | 282 | fsl,capture-dma = <&dma01>; |
264 | fsl,fifo-depth = <8>; | 283 | fsl,fifo-depth = <8>; |
284 | sleep = <&pmc 0 0x08000000>; | ||
265 | }; | 285 | }; |
266 | 286 | ||
267 | ssi@16100 { | 287 | ssi@16100 { |
@@ -271,6 +291,7 @@ | |||
271 | interrupt-parent = <&mpic>; | 291 | interrupt-parent = <&mpic>; |
272 | interrupts = <63 2>; | 292 | interrupts = <63 2>; |
273 | fsl,fifo-depth = <8>; | 293 | fsl,fifo-depth = <8>; |
294 | sleep = <&pmc 0 0x04000000>; | ||
274 | }; | 295 | }; |
275 | 296 | ||
276 | dma@21300 { | 297 | dma@21300 { |
@@ -280,6 +301,7 @@ | |||
280 | cell-index = <0>; | 301 | cell-index = <0>; |
281 | reg = <0x21300 0x4>; /* DMA general status register */ | 302 | reg = <0x21300 0x4>; /* DMA general status register */ |
282 | ranges = <0x0 0x21100 0x200>; | 303 | ranges = <0x0 0x21100 0x200>; |
304 | sleep = <&pmc 0x00000400 0>; | ||
283 | 305 | ||
284 | dma00: dma-channel@0 { | 306 | dma00: dma-channel@0 { |
285 | compatible = "fsl,mpc8610-dma-channel", | 307 | compatible = "fsl,mpc8610-dma-channel", |
@@ -322,6 +344,7 @@ | |||
322 | cell-index = <1>; | 344 | cell-index = <1>; |
323 | reg = <0xc300 0x4>; /* DMA general status register */ | 345 | reg = <0xc300 0x4>; /* DMA general status register */ |
324 | ranges = <0x0 0xc100 0x200>; | 346 | ranges = <0x0 0xc100 0x200>; |
347 | sleep = <&pmc 0x00000200 0>; | ||
325 | 348 | ||
326 | dma-channel@0 { | 349 | dma-channel@0 { |
327 | compatible = "fsl,mpc8610-dma-channel", | 350 | compatible = "fsl,mpc8610-dma-channel", |
@@ -369,6 +392,7 @@ | |||
369 | bus-range = <0 0>; | 392 | bus-range = <0 0>; |
370 | ranges = <0x02000000 0x0 0x80000000 0x80000000 0x0 0x10000000 | 393 | ranges = <0x02000000 0x0 0x80000000 0x80000000 0x0 0x10000000 |
371 | 0x01000000 0x0 0x00000000 0xe1000000 0x0 0x00100000>; | 394 | 0x01000000 0x0 0x00000000 0xe1000000 0x0 0x00100000>; |
395 | sleep = <&pmc 0x80000000 0>; | ||
372 | clock-frequency = <33333333>; | 396 | clock-frequency = <33333333>; |
373 | interrupt-parent = <&mpic>; | 397 | interrupt-parent = <&mpic>; |
374 | interrupts = <24 2>; | 398 | interrupts = <24 2>; |
@@ -398,6 +422,7 @@ | |||
398 | bus-range = <1 3>; | 422 | bus-range = <1 3>; |
399 | ranges = <0x02000000 0x0 0xa0000000 0xa0000000 0x0 0x10000000 | 423 | ranges = <0x02000000 0x0 0xa0000000 0xa0000000 0x0 0x10000000 |
400 | 0x01000000 0x0 0x00000000 0xe3000000 0x0 0x00100000>; | 424 | 0x01000000 0x0 0x00000000 0xe3000000 0x0 0x00100000>; |
425 | sleep = <&pmc 0x40000000 0>; | ||
401 | clock-frequency = <33333333>; | 426 | clock-frequency = <33333333>; |
402 | interrupt-parent = <&mpic>; | 427 | interrupt-parent = <&mpic>; |
403 | interrupts = <26 2>; | 428 | interrupts = <26 2>; |
@@ -474,6 +499,7 @@ | |||
474 | 0x0000 0 0 4 &mpic 7 1>; | 499 | 0x0000 0 0 4 &mpic 7 1>; |
475 | interrupt-parent = <&mpic>; | 500 | interrupt-parent = <&mpic>; |
476 | interrupts = <25 2>; | 501 | interrupts = <25 2>; |
502 | sleep = <&pmc 0x20000000 0>; | ||
477 | clock-frequency = <33333333>; | 503 | clock-frequency = <33333333>; |
478 | }; | 504 | }; |
479 | }; | 505 | }; |
diff --git a/arch/powerpc/boot/dts/p1020rdb.dts b/arch/powerpc/boot/dts/p1020rdb.dts new file mode 100644 index 000000000000..df5269093af8 --- /dev/null +++ b/arch/powerpc/boot/dts/p1020rdb.dts | |||
@@ -0,0 +1,477 @@ | |||
1 | /* | ||
2 | * P1020 RDB Device Tree Source | ||
3 | * | ||
4 | * Copyright 2009 Freescale Semiconductor Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License as published by the | ||
8 | * Free Software Foundation; either version 2 of the License, or (at your | ||
9 | * option) any later version. | ||
10 | */ | ||
11 | |||
12 | /dts-v1/; | ||
13 | / { | ||
14 | model = "fsl,P1020"; | ||
15 | compatible = "fsl,P1020RDB"; | ||
16 | #address-cells = <2>; | ||
17 | #size-cells = <2>; | ||
18 | |||
19 | aliases { | ||
20 | serial0 = &serial0; | ||
21 | serial1 = &serial1; | ||
22 | pci0 = &pci0; | ||
23 | pci1 = &pci1; | ||
24 | }; | ||
25 | |||
26 | cpus { | ||
27 | #address-cells = <1>; | ||
28 | #size-cells = <0>; | ||
29 | |||
30 | PowerPC,P1020@0 { | ||
31 | device_type = "cpu"; | ||
32 | reg = <0x0>; | ||
33 | next-level-cache = <&L2>; | ||
34 | }; | ||
35 | |||
36 | PowerPC,P1020@1 { | ||
37 | device_type = "cpu"; | ||
38 | reg = <0x1>; | ||
39 | next-level-cache = <&L2>; | ||
40 | }; | ||
41 | }; | ||
42 | |||
43 | memory { | ||
44 | device_type = "memory"; | ||
45 | }; | ||
46 | |||
47 | localbus@ffe05000 { | ||
48 | #address-cells = <2>; | ||
49 | #size-cells = <1>; | ||
50 | compatible = "fsl,p1020-elbc", "fsl,elbc", "simple-bus"; | ||
51 | reg = <0 0xffe05000 0 0x1000>; | ||
52 | interrupts = <19 2>; | ||
53 | interrupt-parent = <&mpic>; | ||
54 | |||
55 | /* NOR, NAND Flashes and Vitesse 5 port L2 switch */ | ||
56 | ranges = <0x0 0x0 0x0 0xef000000 0x01000000 | ||
57 | 0x1 0x0 0x0 0xffa00000 0x00040000 | ||
58 | 0x2 0x0 0x0 0xffb00000 0x00020000>; | ||
59 | |||
60 | nor@0,0 { | ||
61 | #address-cells = <1>; | ||
62 | #size-cells = <1>; | ||
63 | compatible = "cfi-flash"; | ||
64 | reg = <0x0 0x0 0x1000000>; | ||
65 | bank-width = <2>; | ||
66 | device-width = <1>; | ||
67 | |||
68 | partition@0 { | ||
69 | /* This location must not be altered */ | ||
70 | /* 256KB for Vitesse 7385 Switch firmware */ | ||
71 | reg = <0x0 0x00040000>; | ||
72 | label = "NOR (RO) Vitesse-7385 Firmware"; | ||
73 | read-only; | ||
74 | }; | ||
75 | |||
76 | partition@40000 { | ||
77 | /* 256KB for DTB Image */ | ||
78 | reg = <0x00040000 0x00040000>; | ||
79 | label = "NOR (RO) DTB Image"; | ||
80 | read-only; | ||
81 | }; | ||
82 | |||
83 | partition@80000 { | ||
84 | /* 3.5 MB for Linux Kernel Image */ | ||
85 | reg = <0x00080000 0x00380000>; | ||
86 | label = "NOR (RO) Linux Kernel Image"; | ||
87 | read-only; | ||
88 | }; | ||
89 | |||
90 | partition@400000 { | ||
91 | /* 11MB for JFFS2 based Root file System */ | ||
92 | reg = <0x00400000 0x00b00000>; | ||
93 | label = "NOR (RW) JFFS2 Root File System"; | ||
94 | }; | ||
95 | |||
96 | partition@f00000 { | ||
97 | /* This location must not be altered */ | ||
98 | /* 512KB for u-boot Bootloader Image */ | ||
99 | /* 512KB for u-boot Environment Variables */ | ||
100 | reg = <0x00f00000 0x00100000>; | ||
101 | label = "NOR (RO) U-Boot Image"; | ||
102 | read-only; | ||
103 | }; | ||
104 | }; | ||
105 | |||
106 | nand@1,0 { | ||
107 | #address-cells = <1>; | ||
108 | #size-cells = <1>; | ||
109 | compatible = "fsl,p1020-fcm-nand", | ||
110 | "fsl,elbc-fcm-nand"; | ||
111 | reg = <0x1 0x0 0x40000>; | ||
112 | |||
113 | partition@0 { | ||
114 | /* This location must not be altered */ | ||
115 | /* 1MB for u-boot Bootloader Image */ | ||
116 | reg = <0x0 0x00100000>; | ||
117 | label = "NAND (RO) U-Boot Image"; | ||
118 | read-only; | ||
119 | }; | ||
120 | |||
121 | partition@100000 { | ||
122 | /* 1MB for DTB Image */ | ||
123 | reg = <0x00100000 0x00100000>; | ||
124 | label = "NAND (RO) DTB Image"; | ||
125 | read-only; | ||
126 | }; | ||
127 | |||
128 | partition@200000 { | ||
129 | /* 4MB for Linux Kernel Image */ | ||
130 | reg = <0x00200000 0x00400000>; | ||
131 | label = "NAND (RO) Linux Kernel Image"; | ||
132 | read-only; | ||
133 | }; | ||
134 | |||
135 | partition@600000 { | ||
136 | /* 4MB for Compressed Root file System Image */ | ||
137 | reg = <0x00600000 0x00400000>; | ||
138 | label = "NAND (RO) Compressed RFS Image"; | ||
139 | read-only; | ||
140 | }; | ||
141 | |||
142 | partition@a00000 { | ||
143 | /* 7MB for JFFS2 based Root file System */ | ||
144 | reg = <0x00a00000 0x00700000>; | ||
145 | label = "NAND (RW) JFFS2 Root File System"; | ||
146 | }; | ||
147 | |||
148 | partition@1100000 { | ||
149 | /* 15MB for JFFS2 based Root file System */ | ||
150 | reg = <0x01100000 0x00f00000>; | ||
151 | label = "NAND (RW) Writable User area"; | ||
152 | }; | ||
153 | }; | ||
154 | |||
155 | L2switch@2,0 { | ||
156 | #address-cells = <1>; | ||
157 | #size-cells = <1>; | ||
158 | compatible = "vitesse-7385"; | ||
159 | reg = <0x2 0x0 0x20000>; | ||
160 | }; | ||
161 | |||
162 | }; | ||
163 | |||
164 | soc@ffe00000 { | ||
165 | #address-cells = <1>; | ||
166 | #size-cells = <1>; | ||
167 | device_type = "soc"; | ||
168 | compatible = "fsl,p1020-immr", "simple-bus"; | ||
169 | ranges = <0x0 0x0 0xffe00000 0x100000>; | ||
170 | bus-frequency = <0>; // Filled out by uboot. | ||
171 | |||
172 | ecm-law@0 { | ||
173 | compatible = "fsl,ecm-law"; | ||
174 | reg = <0x0 0x1000>; | ||
175 | fsl,num-laws = <12>; | ||
176 | }; | ||
177 | |||
178 | ecm@1000 { | ||
179 | compatible = "fsl,p1020-ecm", "fsl,ecm"; | ||
180 | reg = <0x1000 0x1000>; | ||
181 | interrupts = <16 2>; | ||
182 | interrupt-parent = <&mpic>; | ||
183 | }; | ||
184 | |||
185 | memory-controller@2000 { | ||
186 | compatible = "fsl,p1020-memory-controller"; | ||
187 | reg = <0x2000 0x1000>; | ||
188 | interrupt-parent = <&mpic>; | ||
189 | interrupts = <16 2>; | ||
190 | }; | ||
191 | |||
192 | i2c@3000 { | ||
193 | #address-cells = <1>; | ||
194 | #size-cells = <0>; | ||
195 | cell-index = <0>; | ||
196 | compatible = "fsl-i2c"; | ||
197 | reg = <0x3000 0x100>; | ||
198 | interrupts = <43 2>; | ||
199 | interrupt-parent = <&mpic>; | ||
200 | dfsrr; | ||
201 | rtc@68 { | ||
202 | compatible = "dallas,ds1339"; | ||
203 | reg = <0x68>; | ||
204 | }; | ||
205 | }; | ||
206 | |||
207 | i2c@3100 { | ||
208 | #address-cells = <1>; | ||
209 | #size-cells = <0>; | ||
210 | cell-index = <1>; | ||
211 | compatible = "fsl-i2c"; | ||
212 | reg = <0x3100 0x100>; | ||
213 | interrupts = <43 2>; | ||
214 | interrupt-parent = <&mpic>; | ||
215 | dfsrr; | ||
216 | }; | ||
217 | |||
218 | serial0: serial@4500 { | ||
219 | cell-index = <0>; | ||
220 | device_type = "serial"; | ||
221 | compatible = "ns16550"; | ||
222 | reg = <0x4500 0x100>; | ||
223 | clock-frequency = <0>; | ||
224 | interrupts = <42 2>; | ||
225 | interrupt-parent = <&mpic>; | ||
226 | }; | ||
227 | |||
228 | serial1: serial@4600 { | ||
229 | cell-index = <1>; | ||
230 | device_type = "serial"; | ||
231 | compatible = "ns16550"; | ||
232 | reg = <0x4600 0x100>; | ||
233 | clock-frequency = <0>; | ||
234 | interrupts = <42 2>; | ||
235 | interrupt-parent = <&mpic>; | ||
236 | }; | ||
237 | |||
238 | spi@7000 { | ||
239 | cell-index = <0>; | ||
240 | #address-cells = <1>; | ||
241 | #size-cells = <0>; | ||
242 | compatible = "fsl,espi"; | ||
243 | reg = <0x7000 0x1000>; | ||
244 | interrupts = <59 0x2>; | ||
245 | interrupt-parent = <&mpic>; | ||
246 | mode = "cpu"; | ||
247 | |||
248 | fsl_m25p80@0 { | ||
249 | #address-cells = <1>; | ||
250 | #size-cells = <1>; | ||
251 | compatible = "fsl,espi-flash"; | ||
252 | reg = <0>; | ||
253 | linux,modalias = "fsl_m25p80"; | ||
254 | modal = "s25sl128b"; | ||
255 | spi-max-frequency = <50000000>; | ||
256 | mode = <0>; | ||
257 | |||
258 | partition@0 { | ||
259 | /* 512KB for u-boot Bootloader Image */ | ||
260 | reg = <0x0 0x00080000>; | ||
261 | label = "SPI (RO) U-Boot Image"; | ||
262 | read-only; | ||
263 | }; | ||
264 | |||
265 | partition@80000 { | ||
266 | /* 512KB for DTB Image */ | ||
267 | reg = <0x00080000 0x00080000>; | ||
268 | label = "SPI (RO) DTB Image"; | ||
269 | read-only; | ||
270 | }; | ||
271 | |||
272 | partition@100000 { | ||
273 | /* 4MB for Linux Kernel Image */ | ||
274 | reg = <0x00100000 0x00400000>; | ||
275 | label = "SPI (RO) Linux Kernel Image"; | ||
276 | read-only; | ||
277 | }; | ||
278 | |||
279 | partition@500000 { | ||
280 | /* 4MB for Compressed RFS Image */ | ||
281 | reg = <0x00500000 0x00400000>; | ||
282 | label = "SPI (RO) Compressed RFS Image"; | ||
283 | read-only; | ||
284 | }; | ||
285 | |||
286 | partition@900000 { | ||
287 | /* 7MB for JFFS2 based RFS */ | ||
288 | reg = <0x00900000 0x00700000>; | ||
289 | label = "SPI (RW) JFFS2 RFS"; | ||
290 | }; | ||
291 | }; | ||
292 | }; | ||
293 | |||
294 | gpio: gpio-controller@f000 { | ||
295 | #gpio-cells = <2>; | ||
296 | compatible = "fsl,mpc8572-gpio"; | ||
297 | reg = <0xf000 0x100>; | ||
298 | interrupts = <47 0x2>; | ||
299 | interrupt-parent = <&mpic>; | ||
300 | gpio-controller; | ||
301 | }; | ||
302 | |||
303 | L2: l2-cache-controller@20000 { | ||
304 | compatible = "fsl,p1020-l2-cache-controller"; | ||
305 | reg = <0x20000 0x1000>; | ||
306 | cache-line-size = <32>; // 32 bytes | ||
307 | cache-size = <0x40000>; // L2,256K | ||
308 | interrupt-parent = <&mpic>; | ||
309 | interrupts = <16 2>; | ||
310 | }; | ||
311 | |||
312 | dma@21300 { | ||
313 | #address-cells = <1>; | ||
314 | #size-cells = <1>; | ||
315 | compatible = "fsl,eloplus-dma"; | ||
316 | reg = <0x21300 0x4>; | ||
317 | ranges = <0x0 0x21100 0x200>; | ||
318 | cell-index = <0>; | ||
319 | dma-channel@0 { | ||
320 | compatible = "fsl,eloplus-dma-channel"; | ||
321 | reg = <0x0 0x80>; | ||
322 | cell-index = <0>; | ||
323 | interrupt-parent = <&mpic>; | ||
324 | interrupts = <20 2>; | ||
325 | }; | ||
326 | dma-channel@80 { | ||
327 | compatible = "fsl,eloplus-dma-channel"; | ||
328 | reg = <0x80 0x80>; | ||
329 | cell-index = <1>; | ||
330 | interrupt-parent = <&mpic>; | ||
331 | interrupts = <21 2>; | ||
332 | }; | ||
333 | dma-channel@100 { | ||
334 | compatible = "fsl,eloplus-dma-channel"; | ||
335 | reg = <0x100 0x80>; | ||
336 | cell-index = <2>; | ||
337 | interrupt-parent = <&mpic>; | ||
338 | interrupts = <22 2>; | ||
339 | }; | ||
340 | dma-channel@180 { | ||
341 | compatible = "fsl,eloplus-dma-channel"; | ||
342 | reg = <0x180 0x80>; | ||
343 | cell-index = <3>; | ||
344 | interrupt-parent = <&mpic>; | ||
345 | interrupts = <23 2>; | ||
346 | }; | ||
347 | }; | ||
348 | |||
349 | usb@22000 { | ||
350 | #address-cells = <1>; | ||
351 | #size-cells = <0>; | ||
352 | compatible = "fsl-usb2-dr"; | ||
353 | reg = <0x22000 0x1000>; | ||
354 | interrupt-parent = <&mpic>; | ||
355 | interrupts = <28 0x2>; | ||
356 | phy_type = "ulpi"; | ||
357 | }; | ||
358 | |||
359 | usb@23000 { | ||
360 | #address-cells = <1>; | ||
361 | #size-cells = <0>; | ||
362 | compatible = "fsl-usb2-dr"; | ||
363 | reg = <0x23000 0x1000>; | ||
364 | interrupt-parent = <&mpic>; | ||
365 | interrupts = <46 0x2>; | ||
366 | phy_type = "ulpi"; | ||
367 | }; | ||
368 | |||
369 | sdhci@2e000 { | ||
370 | compatible = "fsl,p1020-esdhc", "fsl,esdhc"; | ||
371 | reg = <0x2e000 0x1000>; | ||
372 | interrupts = <72 0x2>; | ||
373 | interrupt-parent = <&mpic>; | ||
374 | /* Filled in by U-Boot */ | ||
375 | clock-frequency = <0>; | ||
376 | }; | ||
377 | |||
378 | crypto@30000 { | ||
379 | compatible = "fsl,sec3.1", "fsl,sec3.0", "fsl,sec2.4", | ||
380 | "fsl,sec2.2", "fsl,sec2.1", "fsl,sec2.0"; | ||
381 | reg = <0x30000 0x10000>; | ||
382 | interrupts = <45 2 58 2>; | ||
383 | interrupt-parent = <&mpic>; | ||
384 | fsl,num-channels = <4>; | ||
385 | fsl,channel-fifo-len = <24>; | ||
386 | fsl,exec-units-mask = <0xbfe>; | ||
387 | fsl,descriptor-types-mask = <0x3ab0ebf>; | ||
388 | }; | ||
389 | |||
390 | mpic: pic@40000 { | ||
391 | interrupt-controller; | ||
392 | #address-cells = <0>; | ||
393 | #interrupt-cells = <2>; | ||
394 | reg = <0x40000 0x40000>; | ||
395 | compatible = "chrp,open-pic"; | ||
396 | device_type = "open-pic"; | ||
397 | }; | ||
398 | |||
399 | msi@41600 { | ||
400 | compatible = "fsl,p1020-msi", "fsl,mpic-msi"; | ||
401 | reg = <0x41600 0x80>; | ||
402 | msi-available-ranges = <0 0x100>; | ||
403 | interrupts = < | ||
404 | 0xe0 0 | ||
405 | 0xe1 0 | ||
406 | 0xe2 0 | ||
407 | 0xe3 0 | ||
408 | 0xe4 0 | ||
409 | 0xe5 0 | ||
410 | 0xe6 0 | ||
411 | 0xe7 0>; | ||
412 | interrupt-parent = <&mpic>; | ||
413 | }; | ||
414 | |||
415 | global-utilities@e0000 { //global utilities block | ||
416 | compatible = "fsl,p1020-guts"; | ||
417 | reg = <0xe0000 0x1000>; | ||
418 | fsl,has-rstcr; | ||
419 | }; | ||
420 | }; | ||
421 | |||
422 | pci0: pcie@ffe09000 { | ||
423 | compatible = "fsl,mpc8548-pcie"; | ||
424 | device_type = "pci"; | ||
425 | #interrupt-cells = <1>; | ||
426 | #size-cells = <2>; | ||
427 | #address-cells = <3>; | ||
428 | reg = <0 0xffe09000 0 0x1000>; | ||
429 | bus-range = <0 255>; | ||
430 | ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000 | ||
431 | 0x1000000 0x0 0x00000000 0 0xffc30000 0x0 0x10000>; | ||
432 | clock-frequency = <33333333>; | ||
433 | interrupt-parent = <&mpic>; | ||
434 | interrupts = <16 2>; | ||
435 | pcie@0 { | ||
436 | reg = <0x0 0x0 0x0 0x0 0x0>; | ||
437 | #size-cells = <2>; | ||
438 | #address-cells = <3>; | ||
439 | device_type = "pci"; | ||
440 | ranges = <0x2000000 0x0 0xa0000000 | ||
441 | 0x2000000 0x0 0xa0000000 | ||
442 | 0x0 0x20000000 | ||
443 | |||
444 | 0x1000000 0x0 0x0 | ||
445 | 0x1000000 0x0 0x0 | ||
446 | 0x0 0x100000>; | ||
447 | }; | ||
448 | }; | ||
449 | |||
450 | pci1: pcie@ffe0a000 { | ||
451 | compatible = "fsl,mpc8548-pcie"; | ||
452 | device_type = "pci"; | ||
453 | #interrupt-cells = <1>; | ||
454 | #size-cells = <2>; | ||
455 | #address-cells = <3>; | ||
456 | reg = <0 0xffe0a000 0 0x1000>; | ||
457 | bus-range = <0 255>; | ||
458 | ranges = <0x2000000 0x0 0xc0000000 0 0xc0000000 0x0 0x20000000 | ||
459 | 0x1000000 0x0 0x00000000 0 0xffc20000 0x0 0x10000>; | ||
460 | clock-frequency = <33333333>; | ||
461 | interrupt-parent = <&mpic>; | ||
462 | interrupts = <16 2>; | ||
463 | pcie@0 { | ||
464 | reg = <0x0 0x0 0x0 0x0 0x0>; | ||
465 | #size-cells = <2>; | ||
466 | #address-cells = <3>; | ||
467 | device_type = "pci"; | ||
468 | ranges = <0x2000000 0x0 0xc0000000 | ||
469 | 0x2000000 0x0 0xc0000000 | ||
470 | 0x0 0x20000000 | ||
471 | |||
472 | 0x1000000 0x0 0x0 | ||
473 | 0x1000000 0x0 0x0 | ||
474 | 0x0 0x100000>; | ||
475 | }; | ||
476 | }; | ||
477 | }; | ||
diff --git a/arch/powerpc/boot/dts/p2020rdb_camp_core0.dts b/arch/powerpc/boot/dts/p2020rdb_camp_core0.dts new file mode 100644 index 000000000000..0fe93d0c8b2e --- /dev/null +++ b/arch/powerpc/boot/dts/p2020rdb_camp_core0.dts | |||
@@ -0,0 +1,363 @@ | |||
1 | /* | ||
2 | * P2020 RDB Core0 Device Tree Source in CAMP mode. | ||
3 | * | ||
4 | * In CAMP mode, each core needs to have its own dts. Only mpic and L2 cache | ||
5 | * can be shared, all the other devices must be assigned to one core only. | ||
6 | * This dts file allows core0 to have memory, l2, i2c, spi, gpio, dma1, usb, | ||
7 | * eth1, eth2, sdhc, crypto, global-util, pci0. | ||
8 | * | ||
9 | * Copyright 2009 Freescale Semiconductor Inc. | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify it | ||
12 | * under the terms of the GNU General Public License as published by the | ||
13 | * Free Software Foundation; either version 2 of the License, or (at your | ||
14 | * option) any later version. | ||
15 | */ | ||
16 | |||
17 | /dts-v1/; | ||
18 | / { | ||
19 | model = "fsl,P2020"; | ||
20 | compatible = "fsl,P2020RDB", "fsl,MPC85XXRDB-CAMP"; | ||
21 | #address-cells = <2>; | ||
22 | #size-cells = <2>; | ||
23 | |||
24 | aliases { | ||
25 | ethernet1 = &enet1; | ||
26 | ethernet2 = &enet2; | ||
27 | serial0 = &serial0; | ||
28 | pci0 = &pci0; | ||
29 | }; | ||
30 | |||
31 | cpus { | ||
32 | #address-cells = <1>; | ||
33 | #size-cells = <0>; | ||
34 | |||
35 | PowerPC,P2020@0 { | ||
36 | device_type = "cpu"; | ||
37 | reg = <0x0>; | ||
38 | next-level-cache = <&L2>; | ||
39 | }; | ||
40 | }; | ||
41 | |||
42 | memory { | ||
43 | device_type = "memory"; | ||
44 | }; | ||
45 | |||
46 | soc@ffe00000 { | ||
47 | #address-cells = <1>; | ||
48 | #size-cells = <1>; | ||
49 | device_type = "soc"; | ||
50 | compatible = "fsl,p2020-immr", "simple-bus"; | ||
51 | ranges = <0x0 0x0 0xffe00000 0x100000>; | ||
52 | bus-frequency = <0>; // Filled out by uboot. | ||
53 | |||
54 | ecm-law@0 { | ||
55 | compatible = "fsl,ecm-law"; | ||
56 | reg = <0x0 0x1000>; | ||
57 | fsl,num-laws = <12>; | ||
58 | }; | ||
59 | |||
60 | ecm@1000 { | ||
61 | compatible = "fsl,p2020-ecm", "fsl,ecm"; | ||
62 | reg = <0x1000 0x1000>; | ||
63 | interrupts = <17 2>; | ||
64 | interrupt-parent = <&mpic>; | ||
65 | }; | ||
66 | |||
67 | memory-controller@2000 { | ||
68 | compatible = "fsl,p2020-memory-controller"; | ||
69 | reg = <0x2000 0x1000>; | ||
70 | interrupt-parent = <&mpic>; | ||
71 | interrupts = <18 2>; | ||
72 | }; | ||
73 | |||
74 | i2c@3000 { | ||
75 | #address-cells = <1>; | ||
76 | #size-cells = <0>; | ||
77 | cell-index = <0>; | ||
78 | compatible = "fsl-i2c"; | ||
79 | reg = <0x3000 0x100>; | ||
80 | interrupts = <43 2>; | ||
81 | interrupt-parent = <&mpic>; | ||
82 | dfsrr; | ||
83 | rtc@68 { | ||
84 | compatible = "dallas,ds1339"; | ||
85 | reg = <0x68>; | ||
86 | }; | ||
87 | }; | ||
88 | |||
89 | i2c@3100 { | ||
90 | #address-cells = <1>; | ||
91 | #size-cells = <0>; | ||
92 | cell-index = <1>; | ||
93 | compatible = "fsl-i2c"; | ||
94 | reg = <0x3100 0x100>; | ||
95 | interrupts = <43 2>; | ||
96 | interrupt-parent = <&mpic>; | ||
97 | dfsrr; | ||
98 | }; | ||
99 | |||
100 | serial0: serial@4500 { | ||
101 | cell-index = <0>; | ||
102 | device_type = "serial"; | ||
103 | compatible = "ns16550"; | ||
104 | reg = <0x4500 0x100>; | ||
105 | clock-frequency = <0>; | ||
106 | }; | ||
107 | |||
108 | spi@7000 { | ||
109 | cell-index = <0>; | ||
110 | #address-cells = <1>; | ||
111 | #size-cells = <0>; | ||
112 | compatible = "fsl,espi"; | ||
113 | reg = <0x7000 0x1000>; | ||
114 | interrupts = <59 0x2>; | ||
115 | interrupt-parent = <&mpic>; | ||
116 | mode = "cpu"; | ||
117 | |||
118 | fsl_m25p80@0 { | ||
119 | #address-cells = <1>; | ||
120 | #size-cells = <1>; | ||
121 | compatible = "fsl,espi-flash"; | ||
122 | reg = <0>; | ||
123 | linux,modalias = "fsl_m25p80"; | ||
124 | modal = "s25sl128b"; | ||
125 | spi-max-frequency = <50000000>; | ||
126 | mode = <0>; | ||
127 | |||
128 | partition@0 { | ||
129 | /* 512KB for u-boot Bootloader Image */ | ||
130 | reg = <0x0 0x00080000>; | ||
131 | label = "SPI (RO) U-Boot Image"; | ||
132 | read-only; | ||
133 | }; | ||
134 | |||
135 | partition@80000 { | ||
136 | /* 512KB for DTB Image */ | ||
137 | reg = <0x00080000 0x00080000>; | ||
138 | label = "SPI (RO) DTB Image"; | ||
139 | read-only; | ||
140 | }; | ||
141 | |||
142 | partition@100000 { | ||
143 | /* 4MB for Linux Kernel Image */ | ||
144 | reg = <0x00100000 0x00400000>; | ||
145 | label = "SPI (RO) Linux Kernel Image"; | ||
146 | read-only; | ||
147 | }; | ||
148 | |||
149 | partition@500000 { | ||
150 | /* 4MB for Compressed RFS Image */ | ||
151 | reg = <0x00500000 0x00400000>; | ||
152 | label = "SPI (RO) Compressed RFS Image"; | ||
153 | read-only; | ||
154 | }; | ||
155 | |||
156 | partition@900000 { | ||
157 | /* 7MB for JFFS2 based RFS */ | ||
158 | reg = <0x00900000 0x00700000>; | ||
159 | label = "SPI (RW) JFFS2 RFS"; | ||
160 | }; | ||
161 | }; | ||
162 | }; | ||
163 | |||
164 | gpio: gpio-controller@f000 { | ||
165 | #gpio-cells = <2>; | ||
166 | compatible = "fsl,mpc8572-gpio"; | ||
167 | reg = <0xf000 0x100>; | ||
168 | interrupts = <47 0x2>; | ||
169 | interrupt-parent = <&mpic>; | ||
170 | gpio-controller; | ||
171 | }; | ||
172 | |||
173 | L2: l2-cache-controller@20000 { | ||
174 | compatible = "fsl,p2020-l2-cache-controller"; | ||
175 | reg = <0x20000 0x1000>; | ||
176 | cache-line-size = <32>; // 32 bytes | ||
177 | cache-size = <0x80000>; // L2,512K | ||
178 | interrupt-parent = <&mpic>; | ||
179 | interrupts = <16 2>; | ||
180 | }; | ||
181 | |||
182 | dma@21300 { | ||
183 | #address-cells = <1>; | ||
184 | #size-cells = <1>; | ||
185 | compatible = "fsl,eloplus-dma"; | ||
186 | reg = <0x21300 0x4>; | ||
187 | ranges = <0x0 0x21100 0x200>; | ||
188 | cell-index = <0>; | ||
189 | dma-channel@0 { | ||
190 | compatible = "fsl,eloplus-dma-channel"; | ||
191 | reg = <0x0 0x80>; | ||
192 | cell-index = <0>; | ||
193 | interrupt-parent = <&mpic>; | ||
194 | interrupts = <20 2>; | ||
195 | }; | ||
196 | dma-channel@80 { | ||
197 | compatible = "fsl,eloplus-dma-channel"; | ||
198 | reg = <0x80 0x80>; | ||
199 | cell-index = <1>; | ||
200 | interrupt-parent = <&mpic>; | ||
201 | interrupts = <21 2>; | ||
202 | }; | ||
203 | dma-channel@100 { | ||
204 | compatible = "fsl,eloplus-dma-channel"; | ||
205 | reg = <0x100 0x80>; | ||
206 | cell-index = <2>; | ||
207 | interrupt-parent = <&mpic>; | ||
208 | interrupts = <22 2>; | ||
209 | }; | ||
210 | dma-channel@180 { | ||
211 | compatible = "fsl,eloplus-dma-channel"; | ||
212 | reg = <0x180 0x80>; | ||
213 | cell-index = <3>; | ||
214 | interrupt-parent = <&mpic>; | ||
215 | interrupts = <23 2>; | ||
216 | }; | ||
217 | }; | ||
218 | |||
219 | usb@22000 { | ||
220 | #address-cells = <1>; | ||
221 | #size-cells = <0>; | ||
222 | compatible = "fsl-usb2-dr"; | ||
223 | reg = <0x22000 0x1000>; | ||
224 | interrupt-parent = <&mpic>; | ||
225 | interrupts = <28 0x2>; | ||
226 | phy_type = "ulpi"; | ||
227 | }; | ||
228 | |||
229 | mdio@24520 { | ||
230 | #address-cells = <1>; | ||
231 | #size-cells = <0>; | ||
232 | compatible = "fsl,gianfar-mdio"; | ||
233 | reg = <0x24520 0x20>; | ||
234 | |||
235 | phy0: ethernet-phy@0 { | ||
236 | interrupt-parent = <&mpic>; | ||
237 | interrupts = <3 1>; | ||
238 | reg = <0x0>; | ||
239 | }; | ||
240 | phy1: ethernet-phy@1 { | ||
241 | interrupt-parent = <&mpic>; | ||
242 | interrupts = <3 1>; | ||
243 | reg = <0x1>; | ||
244 | }; | ||
245 | }; | ||
246 | |||
247 | mdio@25520 { | ||
248 | #address-cells = <1>; | ||
249 | #size-cells = <0>; | ||
250 | compatible = "fsl,gianfar-tbi"; | ||
251 | reg = <0x26520 0x20>; | ||
252 | |||
253 | tbi0: tbi-phy@11 { | ||
254 | reg = <0x11>; | ||
255 | device_type = "tbi-phy"; | ||
256 | }; | ||
257 | }; | ||
258 | |||
259 | enet1: ethernet@25000 { | ||
260 | #address-cells = <1>; | ||
261 | #size-cells = <1>; | ||
262 | cell-index = <1>; | ||
263 | device_type = "network"; | ||
264 | model = "eTSEC"; | ||
265 | compatible = "gianfar"; | ||
266 | reg = <0x25000 0x1000>; | ||
267 | ranges = <0x0 0x25000 0x1000>; | ||
268 | local-mac-address = [ 00 00 00 00 00 00 ]; | ||
269 | interrupts = <35 2 36 2 40 2>; | ||
270 | interrupt-parent = <&mpic>; | ||
271 | tbi-handle = <&tbi0>; | ||
272 | phy-handle = <&phy0>; | ||
273 | phy-connection-type = "sgmii"; | ||
274 | |||
275 | }; | ||
276 | |||
277 | enet2: ethernet@26000 { | ||
278 | #address-cells = <1>; | ||
279 | #size-cells = <1>; | ||
280 | cell-index = <2>; | ||
281 | device_type = "network"; | ||
282 | model = "eTSEC"; | ||
283 | compatible = "gianfar"; | ||
284 | reg = <0x26000 0x1000>; | ||
285 | ranges = <0x0 0x26000 0x1000>; | ||
286 | local-mac-address = [ 00 00 00 00 00 00 ]; | ||
287 | interrupts = <31 2 32 2 33 2>; | ||
288 | interrupt-parent = <&mpic>; | ||
289 | phy-handle = <&phy1>; | ||
290 | phy-connection-type = "rgmii-id"; | ||
291 | }; | ||
292 | |||
293 | sdhci@2e000 { | ||
294 | compatible = "fsl,p2020-esdhc", "fsl,esdhc"; | ||
295 | reg = <0x2e000 0x1000>; | ||
296 | interrupts = <72 0x2>; | ||
297 | interrupt-parent = <&mpic>; | ||
298 | /* Filled in by U-Boot */ | ||
299 | clock-frequency = <0>; | ||
300 | }; | ||
301 | |||
302 | crypto@30000 { | ||
303 | compatible = "fsl,sec3.1", "fsl,sec3.0", "fsl,sec2.4", | ||
304 | "fsl,sec2.2", "fsl,sec2.1", "fsl,sec2.0"; | ||
305 | reg = <0x30000 0x10000>; | ||
306 | interrupts = <45 2 58 2>; | ||
307 | interrupt-parent = <&mpic>; | ||
308 | fsl,num-channels = <4>; | ||
309 | fsl,channel-fifo-len = <24>; | ||
310 | fsl,exec-units-mask = <0xbfe>; | ||
311 | fsl,descriptor-types-mask = <0x3ab0ebf>; | ||
312 | }; | ||
313 | |||
314 | mpic: pic@40000 { | ||
315 | interrupt-controller; | ||
316 | #address-cells = <0>; | ||
317 | #interrupt-cells = <2>; | ||
318 | reg = <0x40000 0x40000>; | ||
319 | compatible = "chrp,open-pic"; | ||
320 | device_type = "open-pic"; | ||
321 | protected-sources = < | ||
322 | 42 76 77 78 79 /* serial1 , dma2 */ | ||
323 | 29 30 34 26 /* enet0, pci1 */ | ||
324 | 0xe0 0xe1 0xe2 0xe3 /* msi */ | ||
325 | 0xe4 0xe5 0xe6 0xe7 | ||
326 | >; | ||
327 | }; | ||
328 | |||
329 | global-utilities@e0000 { | ||
330 | compatible = "fsl,p2020-guts"; | ||
331 | reg = <0xe0000 0x1000>; | ||
332 | fsl,has-rstcr; | ||
333 | }; | ||
334 | }; | ||
335 | |||
336 | pci0: pcie@ffe09000 { | ||
337 | compatible = "fsl,mpc8548-pcie"; | ||
338 | device_type = "pci"; | ||
339 | #interrupt-cells = <1>; | ||
340 | #size-cells = <2>; | ||
341 | #address-cells = <3>; | ||
342 | reg = <0 0xffe09000 0 0x1000>; | ||
343 | bus-range = <0 255>; | ||
344 | ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000 | ||
345 | 0x1000000 0x0 0x00000000 0 0xffc30000 0x0 0x10000>; | ||
346 | clock-frequency = <33333333>; | ||
347 | interrupt-parent = <&mpic>; | ||
348 | interrupts = <25 2>; | ||
349 | pcie@0 { | ||
350 | reg = <0x0 0x0 0x0 0x0 0x0>; | ||
351 | #size-cells = <2>; | ||
352 | #address-cells = <3>; | ||
353 | device_type = "pci"; | ||
354 | ranges = <0x2000000 0x0 0xa0000000 | ||
355 | 0x2000000 0x0 0xa0000000 | ||
356 | 0x0 0x20000000 | ||
357 | |||
358 | 0x1000000 0x0 0x0 | ||
359 | 0x1000000 0x0 0x0 | ||
360 | 0x0 0x100000>; | ||
361 | }; | ||
362 | }; | ||
363 | }; | ||
diff --git a/arch/powerpc/boot/dts/p2020rdb_camp_core1.dts b/arch/powerpc/boot/dts/p2020rdb_camp_core1.dts new file mode 100644 index 000000000000..e95a51285328 --- /dev/null +++ b/arch/powerpc/boot/dts/p2020rdb_camp_core1.dts | |||
@@ -0,0 +1,184 @@ | |||
1 | /* | ||
2 | * P2020 RDB Core1 Device Tree Source in CAMP mode. | ||
3 | * | ||
4 | * In CAMP mode, each core needs to have its own dts. Only mpic and L2 cache | ||
5 | * can be shared, all the other devices must be assigned to one core only. | ||
6 | * This dts allows core1 to have l2, dma2, eth0, pci1, msi. | ||
7 | * | ||
8 | * Please note to add "-b 1" for core1's dts compiling. | ||
9 | * | ||
10 | * Copyright 2009 Freescale Semiconductor Inc. | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify it | ||
13 | * under the terms of the GNU General Public License as published by the | ||
14 | * Free Software Foundation; either version 2 of the License, or (at your | ||
15 | * option) any later version. | ||
16 | */ | ||
17 | |||
18 | /dts-v1/; | ||
19 | / { | ||
20 | model = "fsl,P2020"; | ||
21 | compatible = "fsl,P2020RDB", "fsl,MPC85XXRDB-CAMP"; | ||
22 | #address-cells = <2>; | ||
23 | #size-cells = <2>; | ||
24 | |||
25 | aliases { | ||
26 | ethernet0 = &enet0; | ||
27 | serial0 = &serial0; | ||
28 | pci1 = &pci1; | ||
29 | }; | ||
30 | |||
31 | cpus { | ||
32 | #address-cells = <1>; | ||
33 | #size-cells = <0>; | ||
34 | |||
35 | PowerPC,P2020@1 { | ||
36 | device_type = "cpu"; | ||
37 | reg = <0x1>; | ||
38 | next-level-cache = <&L2>; | ||
39 | }; | ||
40 | }; | ||
41 | |||
42 | memory { | ||
43 | device_type = "memory"; | ||
44 | }; | ||
45 | |||
46 | soc@ffe00000 { | ||
47 | #address-cells = <1>; | ||
48 | #size-cells = <1>; | ||
49 | device_type = "soc"; | ||
50 | compatible = "fsl,p2020-immr", "simple-bus"; | ||
51 | ranges = <0x0 0x0 0xffe00000 0x100000>; | ||
52 | bus-frequency = <0>; // Filled out by uboot. | ||
53 | |||
54 | serial0: serial@4600 { | ||
55 | cell-index = <1>; | ||
56 | device_type = "serial"; | ||
57 | compatible = "ns16550"; | ||
58 | reg = <0x4600 0x100>; | ||
59 | clock-frequency = <0>; | ||
60 | }; | ||
61 | |||
62 | dma@c300 { | ||
63 | #address-cells = <1>; | ||
64 | #size-cells = <1>; | ||
65 | compatible = "fsl,eloplus-dma"; | ||
66 | reg = <0xc300 0x4>; | ||
67 | ranges = <0x0 0xc100 0x200>; | ||
68 | cell-index = <1>; | ||
69 | dma-channel@0 { | ||
70 | compatible = "fsl,eloplus-dma-channel"; | ||
71 | reg = <0x0 0x80>; | ||
72 | cell-index = <0>; | ||
73 | interrupt-parent = <&mpic>; | ||
74 | interrupts = <76 2>; | ||
75 | }; | ||
76 | dma-channel@80 { | ||
77 | compatible = "fsl,eloplus-dma-channel"; | ||
78 | reg = <0x80 0x80>; | ||
79 | cell-index = <1>; | ||
80 | interrupt-parent = <&mpic>; | ||
81 | interrupts = <77 2>; | ||
82 | }; | ||
83 | dma-channel@100 { | ||
84 | compatible = "fsl,eloplus-dma-channel"; | ||
85 | reg = <0x100 0x80>; | ||
86 | cell-index = <2>; | ||
87 | interrupt-parent = <&mpic>; | ||
88 | interrupts = <78 2>; | ||
89 | }; | ||
90 | dma-channel@180 { | ||
91 | compatible = "fsl,eloplus-dma-channel"; | ||
92 | reg = <0x180 0x80>; | ||
93 | cell-index = <3>; | ||
94 | interrupt-parent = <&mpic>; | ||
95 | interrupts = <79 2>; | ||
96 | }; | ||
97 | }; | ||
98 | |||
99 | L2: l2-cache-controller@20000 { | ||
100 | compatible = "fsl,p2020-l2-cache-controller"; | ||
101 | reg = <0x20000 0x1000>; | ||
102 | cache-line-size = <32>; // 32 bytes | ||
103 | cache-size = <0x80000>; // L2,512K | ||
104 | interrupt-parent = <&mpic>; | ||
105 | }; | ||
106 | |||
107 | |||
108 | enet0: ethernet@24000 { | ||
109 | #address-cells = <1>; | ||
110 | #size-cells = <1>; | ||
111 | cell-index = <0>; | ||
112 | device_type = "network"; | ||
113 | model = "eTSEC"; | ||
114 | compatible = "gianfar"; | ||
115 | reg = <0x24000 0x1000>; | ||
116 | ranges = <0x0 0x24000 0x1000>; | ||
117 | local-mac-address = [ 00 00 00 00 00 00 ]; | ||
118 | interrupts = <29 2 30 2 34 2>; | ||
119 | interrupt-parent = <&mpic>; | ||
120 | fixed-link = <1 1 1000 0 0>; | ||
121 | phy-connection-type = "rgmii-id"; | ||
122 | |||
123 | }; | ||
124 | |||
125 | mpic: pic@40000 { | ||
126 | interrupt-controller; | ||
127 | #address-cells = <0>; | ||
128 | #interrupt-cells = <2>; | ||
129 | reg = <0x40000 0x40000>; | ||
130 | compatible = "chrp,open-pic"; | ||
131 | device_type = "open-pic"; | ||
132 | protected-sources = < | ||
133 | 17 18 43 42 59 47 /*ecm, mem, i2c, serial0, spi,gpio */ | ||
134 | 16 20 21 22 23 28 /* L2, dma1, USB */ | ||
135 | 03 35 36 40 31 32 33 /* mdio, enet1, enet2 */ | ||
136 | 72 45 58 25 /* sdhci, crypto , pci */ | ||
137 | >; | ||
138 | }; | ||
139 | |||
140 | msi@41600 { | ||
141 | compatible = "fsl,p2020-msi", "fsl,mpic-msi"; | ||
142 | reg = <0x41600 0x80>; | ||
143 | msi-available-ranges = <0 0x100>; | ||
144 | interrupts = < | ||
145 | 0xe0 0 | ||
146 | 0xe1 0 | ||
147 | 0xe2 0 | ||
148 | 0xe3 0 | ||
149 | 0xe4 0 | ||
150 | 0xe5 0 | ||
151 | 0xe6 0 | ||
152 | 0xe7 0>; | ||
153 | interrupt-parent = <&mpic>; | ||
154 | }; | ||
155 | }; | ||
156 | |||
157 | pci1: pcie@ffe0a000 { | ||
158 | compatible = "fsl,mpc8548-pcie"; | ||
159 | device_type = "pci"; | ||
160 | #interrupt-cells = <1>; | ||
161 | #size-cells = <2>; | ||
162 | #address-cells = <3>; | ||
163 | reg = <0 0xffe0a000 0 0x1000>; | ||
164 | bus-range = <0 255>; | ||
165 | ranges = <0x2000000 0x0 0xc0000000 0 0xc0000000 0x0 0x20000000 | ||
166 | 0x1000000 0x0 0x00000000 0 0xffc20000 0x0 0x10000>; | ||
167 | clock-frequency = <33333333>; | ||
168 | interrupt-parent = <&mpic>; | ||
169 | interrupts = <26 2>; | ||
170 | pcie@0 { | ||
171 | reg = <0x0 0x0 0x0 0x0 0x0>; | ||
172 | #size-cells = <2>; | ||
173 | #address-cells = <3>; | ||
174 | device_type = "pci"; | ||
175 | ranges = <0x2000000 0x0 0xc0000000 | ||
176 | 0x2000000 0x0 0xc0000000 | ||
177 | 0x0 0x20000000 | ||
178 | |||
179 | 0x1000000 0x0 0x0 | ||
180 | 0x1000000 0x0 0x0 | ||
181 | 0x0 0x100000>; | ||
182 | }; | ||
183 | }; | ||
184 | }; | ||
diff --git a/arch/powerpc/boot/dts/p4080ds.dts b/arch/powerpc/boot/dts/p4080ds.dts new file mode 100644 index 000000000000..6b29eab05362 --- /dev/null +++ b/arch/powerpc/boot/dts/p4080ds.dts | |||
@@ -0,0 +1,554 @@ | |||
1 | /* | ||
2 | * P4080DS Device Tree Source | ||
3 | * | ||
4 | * Copyright 2009 Freescale Semiconductor Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License as published by the | ||
8 | * Free Software Foundation; either version 2 of the License, or (at your | ||
9 | * option) any later version. | ||
10 | */ | ||
11 | |||
12 | /dts-v1/; | ||
13 | |||
14 | / { | ||
15 | model = "fsl,P4080DS"; | ||
16 | compatible = "fsl,P4080DS"; | ||
17 | #address-cells = <2>; | ||
18 | #size-cells = <2>; | ||
19 | |||
20 | aliases { | ||
21 | ccsr = &soc; | ||
22 | |||
23 | serial0 = &serial0; | ||
24 | serial1 = &serial1; | ||
25 | serial2 = &serial2; | ||
26 | serial3 = &serial3; | ||
27 | pci0 = &pci0; | ||
28 | pci1 = &pci1; | ||
29 | pci2 = &pci2; | ||
30 | usb0 = &usb0; | ||
31 | usb1 = &usb1; | ||
32 | dma0 = &dma0; | ||
33 | dma1 = &dma1; | ||
34 | sdhc = &sdhc; | ||
35 | |||
36 | rio0 = &rapidio0; | ||
37 | }; | ||
38 | |||
39 | cpus { | ||
40 | #address-cells = <1>; | ||
41 | #size-cells = <0>; | ||
42 | |||
43 | cpu0: PowerPC,4080@0 { | ||
44 | device_type = "cpu"; | ||
45 | reg = <0>; | ||
46 | next-level-cache = <&L2_0>; | ||
47 | L2_0: l2-cache { | ||
48 | }; | ||
49 | }; | ||
50 | cpu1: PowerPC,4080@1 { | ||
51 | device_type = "cpu"; | ||
52 | reg = <1>; | ||
53 | next-level-cache = <&L2_1>; | ||
54 | L2_1: l2-cache { | ||
55 | }; | ||
56 | }; | ||
57 | cpu2: PowerPC,4080@2 { | ||
58 | device_type = "cpu"; | ||
59 | reg = <2>; | ||
60 | next-level-cache = <&L2_2>; | ||
61 | L2_2: l2-cache { | ||
62 | }; | ||
63 | }; | ||
64 | cpu3: PowerPC,4080@3 { | ||
65 | device_type = "cpu"; | ||
66 | reg = <3>; | ||
67 | next-level-cache = <&L2_3>; | ||
68 | L2_3: l2-cache { | ||
69 | }; | ||
70 | }; | ||
71 | cpu4: PowerPC,4080@4 { | ||
72 | device_type = "cpu"; | ||
73 | reg = <4>; | ||
74 | next-level-cache = <&L2_4>; | ||
75 | L2_4: l2-cache { | ||
76 | }; | ||
77 | }; | ||
78 | cpu5: PowerPC,4080@5 { | ||
79 | device_type = "cpu"; | ||
80 | reg = <5>; | ||
81 | next-level-cache = <&L2_5>; | ||
82 | L2_5: l2-cache { | ||
83 | }; | ||
84 | }; | ||
85 | cpu6: PowerPC,4080@6 { | ||
86 | device_type = "cpu"; | ||
87 | reg = <6>; | ||
88 | next-level-cache = <&L2_6>; | ||
89 | L2_6: l2-cache { | ||
90 | }; | ||
91 | }; | ||
92 | cpu7: PowerPC,4080@7 { | ||
93 | device_type = "cpu"; | ||
94 | reg = <7>; | ||
95 | next-level-cache = <&L2_7>; | ||
96 | L2_7: l2-cache { | ||
97 | }; | ||
98 | }; | ||
99 | }; | ||
100 | |||
101 | memory { | ||
102 | device_type = "memory"; | ||
103 | }; | ||
104 | |||
105 | soc: soc@ffe000000 { | ||
106 | #address-cells = <1>; | ||
107 | #size-cells = <1>; | ||
108 | device_type = "soc"; | ||
109 | compatible = "simple-bus"; | ||
110 | ranges = <0x00000000 0xf 0xfe000000 0x1000000>; | ||
111 | reg = <0xf 0xfe000000 0 0x00001000>; | ||
112 | |||
113 | corenet-law@0 { | ||
114 | compatible = "fsl,corenet-law"; | ||
115 | reg = <0x0 0x1000>; | ||
116 | fsl,num-laws = <32>; | ||
117 | }; | ||
118 | |||
119 | memory-controller@8000 { | ||
120 | compatible = "fsl,p4080-memory-controller"; | ||
121 | reg = <0x8000 0x1000>; | ||
122 | interrupt-parent = <&mpic>; | ||
123 | interrupts = <0x12 2>; | ||
124 | }; | ||
125 | |||
126 | memory-controller@9000 { | ||
127 | compatible = "fsl,p4080-memory-controller"; | ||
128 | reg = <0x9000 0x1000>; | ||
129 | interrupt-parent = <&mpic>; | ||
130 | interrupts = <0x12 2>; | ||
131 | }; | ||
132 | |||
133 | corenet-cf@18000 { | ||
134 | compatible = "fsl,corenet-cf"; | ||
135 | reg = <0x18000 0x1000>; | ||
136 | fsl,ccf-num-csdids = <32>; | ||
137 | fsl,ccf-num-snoopids = <32>; | ||
138 | }; | ||
139 | |||
140 | iommu@20000 { | ||
141 | compatible = "fsl,p4080-pamu"; | ||
142 | reg = <0x20000 0x10000>; | ||
143 | interrupts = <24 2>; | ||
144 | interrupt-parent = <&mpic>; | ||
145 | }; | ||
146 | |||
147 | mpic: pic@40000 { | ||
148 | interrupt-controller; | ||
149 | #address-cells = <0>; | ||
150 | #interrupt-cells = <2>; | ||
151 | reg = <0x40000 0x40000>; | ||
152 | compatible = "chrp,open-pic"; | ||
153 | device_type = "open-pic"; | ||
154 | }; | ||
155 | |||
156 | dma0: dma@100300 { | ||
157 | #address-cells = <1>; | ||
158 | #size-cells = <1>; | ||
159 | compatible = "fsl,p4080-dma", "fsl,eloplus-dma"; | ||
160 | reg = <0x100300 0x4>; | ||
161 | ranges = <0x0 0x100100 0x200>; | ||
162 | cell-index = <0>; | ||
163 | dma-channel@0 { | ||
164 | compatible = "fsl,p4080-dma-channel", | ||
165 | "fsl,eloplus-dma-channel"; | ||
166 | reg = <0x0 0x80>; | ||
167 | cell-index = <0>; | ||
168 | interrupt-parent = <&mpic>; | ||
169 | interrupts = <28 2>; | ||
170 | }; | ||
171 | dma-channel@80 { | ||
172 | compatible = "fsl,p4080-dma-channel", | ||
173 | "fsl,eloplus-dma-channel"; | ||
174 | reg = <0x80 0x80>; | ||
175 | cell-index = <1>; | ||
176 | interrupt-parent = <&mpic>; | ||
177 | interrupts = <29 2>; | ||
178 | }; | ||
179 | dma-channel@100 { | ||
180 | compatible = "fsl,p4080-dma-channel", | ||
181 | "fsl,eloplus-dma-channel"; | ||
182 | reg = <0x100 0x80>; | ||
183 | cell-index = <2>; | ||
184 | interrupt-parent = <&mpic>; | ||
185 | interrupts = <30 2>; | ||
186 | }; | ||
187 | dma-channel@180 { | ||
188 | compatible = "fsl,p4080-dma-channel", | ||
189 | "fsl,eloplus-dma-channel"; | ||
190 | reg = <0x180 0x80>; | ||
191 | cell-index = <3>; | ||
192 | interrupt-parent = <&mpic>; | ||
193 | interrupts = <31 2>; | ||
194 | }; | ||
195 | }; | ||
196 | |||
197 | dma1: dma@101300 { | ||
198 | #address-cells = <1>; | ||
199 | #size-cells = <1>; | ||
200 | compatible = "fsl,p4080-dma", "fsl,eloplus-dma"; | ||
201 | reg = <0x101300 0x4>; | ||
202 | ranges = <0x0 0x101100 0x200>; | ||
203 | cell-index = <1>; | ||
204 | dma-channel@0 { | ||
205 | compatible = "fsl,p4080-dma-channel", | ||
206 | "fsl,eloplus-dma-channel"; | ||
207 | reg = <0x0 0x80>; | ||
208 | cell-index = <0>; | ||
209 | interrupt-parent = <&mpic>; | ||
210 | interrupts = <32 2>; | ||
211 | }; | ||
212 | dma-channel@80 { | ||
213 | compatible = "fsl,p4080-dma-channel", | ||
214 | "fsl,eloplus-dma-channel"; | ||
215 | reg = <0x80 0x80>; | ||
216 | cell-index = <1>; | ||
217 | interrupt-parent = <&mpic>; | ||
218 | interrupts = <33 2>; | ||
219 | }; | ||
220 | dma-channel@100 { | ||
221 | compatible = "fsl,p4080-dma-channel", | ||
222 | "fsl,eloplus-dma-channel"; | ||
223 | reg = <0x100 0x80>; | ||
224 | cell-index = <2>; | ||
225 | interrupt-parent = <&mpic>; | ||
226 | interrupts = <34 2>; | ||
227 | }; | ||
228 | dma-channel@180 { | ||
229 | compatible = "fsl,p4080-dma-channel", | ||
230 | "fsl,eloplus-dma-channel"; | ||
231 | reg = <0x180 0x80>; | ||
232 | cell-index = <3>; | ||
233 | interrupt-parent = <&mpic>; | ||
234 | interrupts = <35 2>; | ||
235 | }; | ||
236 | }; | ||
237 | |||
238 | spi@110000 { | ||
239 | cell-index = <0>; | ||
240 | #address-cells = <1>; | ||
241 | #size-cells = <0>; | ||
242 | compatible = "fsl,espi"; | ||
243 | reg = <0x110000 0x1000>; | ||
244 | interrupts = <53 0x2>; | ||
245 | interrupt-parent = <&mpic>; | ||
246 | espi,num-ss-bits = <4>; | ||
247 | mode = "cpu"; | ||
248 | |||
249 | fsl_m25p80@0 { | ||
250 | #address-cells = <1>; | ||
251 | #size-cells = <1>; | ||
252 | compatible = "fsl,espi-flash"; | ||
253 | reg = <0>; | ||
254 | linux,modalias = "fsl_m25p80"; | ||
255 | spi-max-frequency = <40000000>; /* input clock */ | ||
256 | partition@u-boot { | ||
257 | label = "u-boot"; | ||
258 | reg = <0x00000000 0x00100000>; | ||
259 | read-only; | ||
260 | }; | ||
261 | partition@kernel { | ||
262 | label = "kernel"; | ||
263 | reg = <0x00100000 0x00500000>; | ||
264 | read-only; | ||
265 | }; | ||
266 | partition@dtb { | ||
267 | label = "dtb"; | ||
268 | reg = <0x00600000 0x00100000>; | ||
269 | read-only; | ||
270 | }; | ||
271 | partition@fs { | ||
272 | label = "file system"; | ||
273 | reg = <0x00700000 0x00900000>; | ||
274 | }; | ||
275 | }; | ||
276 | }; | ||
277 | |||
278 | sdhc: sdhc@114000 { | ||
279 | compatible = "fsl,p4080-esdhc", "fsl,esdhc"; | ||
280 | reg = <0x114000 0x1000>; | ||
281 | interrupts = <48 2>; | ||
282 | interrupt-parent = <&mpic>; | ||
283 | }; | ||
284 | |||
285 | i2c@118000 { | ||
286 | #address-cells = <1>; | ||
287 | #size-cells = <0>; | ||
288 | cell-index = <0>; | ||
289 | compatible = "fsl-i2c"; | ||
290 | reg = <0x118000 0x100>; | ||
291 | interrupts = <38 2>; | ||
292 | interrupt-parent = <&mpic>; | ||
293 | dfsrr; | ||
294 | }; | ||
295 | |||
296 | i2c@118100 { | ||
297 | #address-cells = <1>; | ||
298 | #size-cells = <0>; | ||
299 | cell-index = <1>; | ||
300 | compatible = "fsl-i2c"; | ||
301 | reg = <0x118100 0x100>; | ||
302 | interrupts = <38 2>; | ||
303 | interrupt-parent = <&mpic>; | ||
304 | dfsrr; | ||
305 | eeprom@51 { | ||
306 | compatible = "at24,24c256"; | ||
307 | reg = <0x51>; | ||
308 | }; | ||
309 | eeprom@52 { | ||
310 | compatible = "at24,24c256"; | ||
311 | reg = <0x52>; | ||
312 | }; | ||
313 | rtc@68 { | ||
314 | compatible = "dallas,ds3232"; | ||
315 | reg = <0x68>; | ||
316 | interrupts = <0 0x1>; | ||
317 | interrupt-parent = <&mpic>; | ||
318 | }; | ||
319 | }; | ||
320 | |||
321 | i2c@119000 { | ||
322 | #address-cells = <1>; | ||
323 | #size-cells = <0>; | ||
324 | cell-index = <2>; | ||
325 | compatible = "fsl-i2c"; | ||
326 | reg = <0x119000 0x100>; | ||
327 | interrupts = <39 2>; | ||
328 | interrupt-parent = <&mpic>; | ||
329 | dfsrr; | ||
330 | }; | ||
331 | |||
332 | i2c@119100 { | ||
333 | #address-cells = <1>; | ||
334 | #size-cells = <0>; | ||
335 | cell-index = <3>; | ||
336 | compatible = "fsl-i2c"; | ||
337 | reg = <0x119100 0x100>; | ||
338 | interrupts = <39 2>; | ||
339 | interrupt-parent = <&mpic>; | ||
340 | dfsrr; | ||
341 | }; | ||
342 | |||
343 | serial0: serial@11c500 { | ||
344 | cell-index = <0>; | ||
345 | device_type = "serial"; | ||
346 | compatible = "ns16550"; | ||
347 | reg = <0x11c500 0x100>; | ||
348 | clock-frequency = <0>; | ||
349 | interrupts = <36 2>; | ||
350 | interrupt-parent = <&mpic>; | ||
351 | }; | ||
352 | |||
353 | serial1: serial@11c600 { | ||
354 | cell-index = <1>; | ||
355 | device_type = "serial"; | ||
356 | compatible = "ns16550"; | ||
357 | reg = <0x11c600 0x100>; | ||
358 | clock-frequency = <0>; | ||
359 | interrupts = <36 2>; | ||
360 | interrupt-parent = <&mpic>; | ||
361 | }; | ||
362 | |||
363 | serial2: serial@11d500 { | ||
364 | cell-index = <2>; | ||
365 | device_type = "serial"; | ||
366 | compatible = "ns16550"; | ||
367 | reg = <0x11d500 0x100>; | ||
368 | clock-frequency = <0>; | ||
369 | interrupts = <37 2>; | ||
370 | interrupt-parent = <&mpic>; | ||
371 | }; | ||
372 | |||
373 | serial3: serial@11d600 { | ||
374 | cell-index = <3>; | ||
375 | device_type = "serial"; | ||
376 | compatible = "ns16550"; | ||
377 | reg = <0x11d600 0x100>; | ||
378 | clock-frequency = <0>; | ||
379 | interrupts = <37 2>; | ||
380 | interrupt-parent = <&mpic>; | ||
381 | }; | ||
382 | |||
383 | gpio0: gpio@130000 { | ||
384 | compatible = "fsl,p4080-gpio"; | ||
385 | reg = <0x130000 0x1000>; | ||
386 | interrupts = <55 2>; | ||
387 | interrupt-parent = <&mpic>; | ||
388 | #gpio-cells = <2>; | ||
389 | gpio-controller; | ||
390 | }; | ||
391 | |||
392 | usb0: usb@210000 { | ||
393 | compatible = "fsl,p4080-usb2-mph", | ||
394 | "fsl,mpc85xx-usb2-mph", "fsl-usb2-mph"; | ||
395 | reg = <0x210000 0x1000>; | ||
396 | #address-cells = <1>; | ||
397 | #size-cells = <0>; | ||
398 | interrupt-parent = <&mpic>; | ||
399 | interrupts = <44 0x2>; | ||
400 | phy_type = "ulpi"; | ||
401 | }; | ||
402 | |||
403 | usb1: usb@211000 { | ||
404 | compatible = "fsl,p4080-usb2-dr", | ||
405 | "fsl,mpc85xx-usb2-dr", "fsl-usb2-dr"; | ||
406 | reg = <0x211000 0x1000>; | ||
407 | #address-cells = <1>; | ||
408 | #size-cells = <0>; | ||
409 | interrupt-parent = <&mpic>; | ||
410 | interrupts = <45 0x2>; | ||
411 | dr_mode = "host"; | ||
412 | phy_type = "ulpi"; | ||
413 | }; | ||
414 | }; | ||
415 | |||
416 | rapidio0: rapidio@ffe0c0000 { | ||
417 | #address-cells = <2>; | ||
418 | #size-cells = <2>; | ||
419 | compatible = "fsl,rapidio-delta"; | ||
420 | reg = <0xf 0xfe0c0000 0 0x20000>; | ||
421 | ranges = <0 0 0xf 0xf5000000 0 0x01000000>; | ||
422 | interrupt-parent = <&mpic>; | ||
423 | /* err_irq bell_outb_irq bell_inb_irq | ||
424 | msg1_tx_irq msg1_rx_irq msg2_tx_irq msg2_rx_irq */ | ||
425 | interrupts = <16 2 56 2 57 2 60 2 61 2 62 2 63 2>; | ||
426 | }; | ||
427 | |||
428 | localbus@ffe124000 { | ||
429 | compatible = "fsl,p4080-elbc", "fsl,elbc", "simple-bus"; | ||
430 | reg = <0xf 0xfe124000 0 0x1000>; | ||
431 | interrupts = <25 2>; | ||
432 | #address-cells = <2>; | ||
433 | #size-cells = <1>; | ||
434 | |||
435 | ranges = <0 0 0xf 0xe8000000 0x08000000>; | ||
436 | |||
437 | flash@0,0 { | ||
438 | compatible = "cfi-flash"; | ||
439 | reg = <0 0 0x08000000>; | ||
440 | bank-width = <2>; | ||
441 | device-width = <2>; | ||
442 | }; | ||
443 | }; | ||
444 | |||
445 | pci0: pcie@ffe200000 { | ||
446 | compatible = "fsl,p4080-pcie"; | ||
447 | device_type = "pci"; | ||
448 | #interrupt-cells = <1>; | ||
449 | #size-cells = <2>; | ||
450 | #address-cells = <3>; | ||
451 | reg = <0xf 0xfe200000 0 0x1000>; | ||
452 | bus-range = <0x0 0xff>; | ||
453 | ranges = <0x02000000 0 0xe0000000 0xc 0x00000000 0x0 0x20000000 | ||
454 | 0x01000000 0 0x00000000 0xf 0xf8000000 0x0 0x00010000>; | ||
455 | clock-frequency = <0x1fca055>; | ||
456 | interrupt-parent = <&mpic>; | ||
457 | interrupts = <16 2>; | ||
458 | |||
459 | interrupt-map-mask = <0xf800 0 0 7>; | ||
460 | interrupt-map = < | ||
461 | /* IDSEL 0x0 */ | ||
462 | 0000 0 0 1 &mpic 40 1 | ||
463 | 0000 0 0 2 &mpic 1 1 | ||
464 | 0000 0 0 3 &mpic 2 1 | ||
465 | 0000 0 0 4 &mpic 3 1 | ||
466 | >; | ||
467 | pcie@0 { | ||
468 | reg = <0 0 0 0 0>; | ||
469 | #size-cells = <2>; | ||
470 | #address-cells = <3>; | ||
471 | device_type = "pci"; | ||
472 | ranges = <0x02000000 0 0xe0000000 | ||
473 | 0x02000000 0 0xe0000000 | ||
474 | 0 0x20000000 | ||
475 | |||
476 | 0x01000000 0 0x00000000 | ||
477 | 0x01000000 0 0x00000000 | ||
478 | 0 0x00010000>; | ||
479 | }; | ||
480 | }; | ||
481 | |||
482 | pci1: pcie@ffe201000 { | ||
483 | compatible = "fsl,p4080-pcie"; | ||
484 | device_type = "pci"; | ||
485 | #interrupt-cells = <1>; | ||
486 | #size-cells = <2>; | ||
487 | #address-cells = <3>; | ||
488 | reg = <0xf 0xfe201000 0 0x1000>; | ||
489 | bus-range = <0 0xff>; | ||
490 | ranges = <0x02000000 0x0 0xe0000000 0xc 0x20000000 0x0 0x20000000 | ||
491 | 0x01000000 0x0 0x00000000 0xf 0xf8010000 0x0 0x00010000>; | ||
492 | clock-frequency = <0x1fca055>; | ||
493 | interrupt-parent = <&mpic>; | ||
494 | interrupts = <16 2>; | ||
495 | interrupt-map-mask = <0xf800 0 0 7>; | ||
496 | interrupt-map = < | ||
497 | /* IDSEL 0x0 */ | ||
498 | 0000 0 0 1 &mpic 41 1 | ||
499 | 0000 0 0 2 &mpic 5 1 | ||
500 | 0000 0 0 3 &mpic 6 1 | ||
501 | 0000 0 0 4 &mpic 7 1 | ||
502 | >; | ||
503 | pcie@0 { | ||
504 | reg = <0 0 0 0 0>; | ||
505 | #size-cells = <2>; | ||
506 | #address-cells = <3>; | ||
507 | device_type = "pci"; | ||
508 | ranges = <0x02000000 0 0xe0000000 | ||
509 | 0x02000000 0 0xe0000000 | ||
510 | 0 0x20000000 | ||
511 | |||
512 | 0x01000000 0 0x00000000 | ||
513 | 0x01000000 0 0x00000000 | ||
514 | 0 0x00010000>; | ||
515 | }; | ||
516 | }; | ||
517 | |||
518 | pci2: pcie@ffe202000 { | ||
519 | compatible = "fsl,p4080-pcie"; | ||
520 | device_type = "pci"; | ||
521 | #interrupt-cells = <1>; | ||
522 | #size-cells = <2>; | ||
523 | #address-cells = <3>; | ||
524 | reg = <0xf 0xfe202000 0 0x1000>; | ||
525 | bus-range = <0x0 0xff>; | ||
526 | ranges = <0x02000000 0 0xe0000000 0xc 0x40000000 0 0x20000000 | ||
527 | 0x01000000 0 0x00000000 0xf 0xf8020000 0 0x00010000>; | ||
528 | clock-frequency = <0x1fca055>; | ||
529 | interrupt-parent = <&mpic>; | ||
530 | interrupts = <16 2>; | ||
531 | interrupt-map-mask = <0xf800 0 0 7>; | ||
532 | interrupt-map = < | ||
533 | /* IDSEL 0x0 */ | ||
534 | 0000 0 0 1 &mpic 42 1 | ||
535 | 0000 0 0 2 &mpic 9 1 | ||
536 | 0000 0 0 3 &mpic 10 1 | ||
537 | 0000 0 0 4 &mpic 11 1 | ||
538 | >; | ||
539 | pcie@0 { | ||
540 | reg = <0 0 0 0 0>; | ||
541 | #size-cells = <2>; | ||
542 | #address-cells = <3>; | ||
543 | device_type = "pci"; | ||
544 | ranges = <0x02000000 0 0xe0000000 | ||
545 | 0x02000000 0 0xe0000000 | ||
546 | 0 0x20000000 | ||
547 | |||
548 | 0x01000000 0 0x00000000 | ||
549 | 0x01000000 0 0x00000000 | ||
550 | 0 0x00010000>; | ||
551 | }; | ||
552 | }; | ||
553 | |||
554 | }; | ||
diff --git a/arch/powerpc/boot/dts/redwood.dts b/arch/powerpc/boot/dts/redwood.dts index ad402c488741..d2af32e2bf7a 100644 --- a/arch/powerpc/boot/dts/redwood.dts +++ b/arch/powerpc/boot/dts/redwood.dts | |||
@@ -226,6 +226,7 @@ | |||
226 | max-frame-size = <9000>; | 226 | max-frame-size = <9000>; |
227 | rx-fifo-size = <4096>; | 227 | rx-fifo-size = <4096>; |
228 | tx-fifo-size = <2048>; | 228 | tx-fifo-size = <2048>; |
229 | rx-fifo-size-gige = <16384>; | ||
229 | phy-mode = "rgmii"; | 230 | phy-mode = "rgmii"; |
230 | phy-map = <0x00000000>; | 231 | phy-map = <0x00000000>; |
231 | rgmii-device = <&RGMII0>; | 232 | rgmii-device = <&RGMII0>; |
diff --git a/arch/powerpc/boot/dts/yosemite.dts b/arch/powerpc/boot/dts/yosemite.dts index 1fa3cb4c4ebb..64923245f0e5 100644 --- a/arch/powerpc/boot/dts/yosemite.dts +++ b/arch/powerpc/boot/dts/yosemite.dts | |||
@@ -282,20 +282,10 @@ | |||
282 | /* Inbound 2GB range starting at 0 */ | 282 | /* Inbound 2GB range starting at 0 */ |
283 | dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x80000000>; | 283 | dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x80000000>; |
284 | 284 | ||
285 | /* Bamboo has all 4 IRQ pins tied together per slot */ | ||
286 | interrupt-map-mask = <0xf800 0x0 0x0 0x0>; | 285 | interrupt-map-mask = <0xf800 0x0 0x0 0x0>; |
287 | interrupt-map = < | 286 | interrupt-map = < |
288 | /* IDSEL 1 */ | 287 | /* IDSEL 12 */ |
289 | 0x800 0x0 0x0 0x0 &UIC0 0x1c 0x8 | 288 | 0x6000 0x0 0x0 0x0 &UIC0 0x19 0x8 |
290 | |||
291 | /* IDSEL 2 */ | ||
292 | 0x1000 0x0 0x0 0x0 &UIC0 0x1b 0x8 | ||
293 | |||
294 | /* IDSEL 3 */ | ||
295 | 0x1800 0x0 0x0 0x0 &UIC0 0x1a 0x8 | ||
296 | |||
297 | /* IDSEL 4 */ | ||
298 | 0x2000 0x0 0x0 0x0 &UIC0 0x19 0x8 | ||
299 | >; | 289 | >; |
300 | }; | 290 | }; |
301 | }; | 291 | }; |
diff --git a/arch/powerpc/configs/86xx/gef_ppc9a_defconfig b/arch/powerpc/configs/86xx/gef_ppc9a_defconfig index 28980738776c..6cd2cd65c2cd 100644 --- a/arch/powerpc/configs/86xx/gef_ppc9a_defconfig +++ b/arch/powerpc/configs/86xx/gef_ppc9a_defconfig | |||
@@ -218,7 +218,7 @@ CONFIG_MPIC=y | |||
218 | # CONFIG_MPIC_WEIRD is not set | 218 | # CONFIG_MPIC_WEIRD is not set |
219 | # CONFIG_PPC_I8259 is not set | 219 | # CONFIG_PPC_I8259 is not set |
220 | # CONFIG_PPC_RTAS is not set | 220 | # CONFIG_PPC_RTAS is not set |
221 | # CONFIG_MMIO_NVRAM is not set | 221 | CONFIG_MMIO_NVRAM=y |
222 | # CONFIG_PPC_MPC106 is not set | 222 | # CONFIG_PPC_MPC106 is not set |
223 | # CONFIG_PPC_970_NAP is not set | 223 | # CONFIG_PPC_970_NAP is not set |
224 | # CONFIG_PPC_INDIRECT_IO is not set | 224 | # CONFIG_PPC_INDIRECT_IO is not set |
diff --git a/arch/powerpc/configs/86xx/gef_sbc310_defconfig b/arch/powerpc/configs/86xx/gef_sbc310_defconfig index e199d1cacbaf..a6a3768f7304 100644 --- a/arch/powerpc/configs/86xx/gef_sbc310_defconfig +++ b/arch/powerpc/configs/86xx/gef_sbc310_defconfig | |||
@@ -218,7 +218,7 @@ CONFIG_MPIC=y | |||
218 | # CONFIG_MPIC_WEIRD is not set | 218 | # CONFIG_MPIC_WEIRD is not set |
219 | # CONFIG_PPC_I8259 is not set | 219 | # CONFIG_PPC_I8259 is not set |
220 | # CONFIG_PPC_RTAS is not set | 220 | # CONFIG_PPC_RTAS is not set |
221 | # CONFIG_MMIO_NVRAM is not set | 221 | CONFIG_MMIO_NVRAM=y |
222 | # CONFIG_PPC_MPC106 is not set | 222 | # CONFIG_PPC_MPC106 is not set |
223 | # CONFIG_PPC_970_NAP is not set | 223 | # CONFIG_PPC_970_NAP is not set |
224 | # CONFIG_PPC_INDIRECT_IO is not set | 224 | # CONFIG_PPC_INDIRECT_IO is not set |
diff --git a/arch/powerpc/configs/86xx/gef_sbc610_defconfig b/arch/powerpc/configs/86xx/gef_sbc610_defconfig index 3b0fbfb28efd..1975d41e0763 100644 --- a/arch/powerpc/configs/86xx/gef_sbc610_defconfig +++ b/arch/powerpc/configs/86xx/gef_sbc610_defconfig | |||
@@ -219,7 +219,7 @@ CONFIG_MPIC=y | |||
219 | # CONFIG_MPIC_WEIRD is not set | 219 | # CONFIG_MPIC_WEIRD is not set |
220 | # CONFIG_PPC_I8259 is not set | 220 | # CONFIG_PPC_I8259 is not set |
221 | # CONFIG_PPC_RTAS is not set | 221 | # CONFIG_PPC_RTAS is not set |
222 | # CONFIG_MMIO_NVRAM is not set | 222 | CONFIG_MMIO_NVRAM=y |
223 | # CONFIG_PPC_MPC106 is not set | 223 | # CONFIG_PPC_MPC106 is not set |
224 | # CONFIG_PPC_970_NAP is not set | 224 | # CONFIG_PPC_970_NAP is not set |
225 | # CONFIG_PPC_INDIRECT_IO is not set | 225 | # CONFIG_PPC_INDIRECT_IO is not set |
@@ -1124,7 +1124,7 @@ CONFIG_UNIX98_PTYS=y | |||
1124 | # CONFIG_IPMI_HANDLER is not set | 1124 | # CONFIG_IPMI_HANDLER is not set |
1125 | CONFIG_HW_RANDOM=y | 1125 | CONFIG_HW_RANDOM=y |
1126 | # CONFIG_HW_RANDOM_TIMERIOMEM is not set | 1126 | # CONFIG_HW_RANDOM_TIMERIOMEM is not set |
1127 | # CONFIG_NVRAM is not set | 1127 | CONFIG_NVRAM=y |
1128 | # CONFIG_R3964 is not set | 1128 | # CONFIG_R3964 is not set |
1129 | # CONFIG_APPLICOM is not set | 1129 | # CONFIG_APPLICOM is not set |
1130 | # CONFIG_RAW_DRIVER is not set | 1130 | # CONFIG_RAW_DRIVER is not set |
diff --git a/arch/powerpc/include/asm/cpm.h b/arch/powerpc/include/asm/cpm.h index 24d79e3abd8e..0835eb977ba9 100644 --- a/arch/powerpc/include/asm/cpm.h +++ b/arch/powerpc/include/asm/cpm.h | |||
@@ -3,8 +3,47 @@ | |||
3 | 3 | ||
4 | #include <linux/compiler.h> | 4 | #include <linux/compiler.h> |
5 | #include <linux/types.h> | 5 | #include <linux/types.h> |
6 | #include <linux/errno.h> | ||
6 | #include <linux/of.h> | 7 | #include <linux/of.h> |
7 | 8 | ||
9 | /* | ||
10 | * USB Controller pram common to QE and CPM. | ||
11 | */ | ||
12 | struct usb_ctlr { | ||
13 | u8 usb_usmod; | ||
14 | u8 usb_usadr; | ||
15 | u8 usb_uscom; | ||
16 | u8 res1[1]; | ||
17 | __be16 usb_usep[4]; | ||
18 | u8 res2[4]; | ||
19 | __be16 usb_usber; | ||
20 | u8 res3[2]; | ||
21 | __be16 usb_usbmr; | ||
22 | u8 res4[1]; | ||
23 | u8 usb_usbs; | ||
24 | /* Fields down below are QE-only */ | ||
25 | __be16 usb_ussft; | ||
26 | u8 res5[2]; | ||
27 | __be16 usb_usfrn; | ||
28 | u8 res6[0x22]; | ||
29 | } __attribute__ ((packed)); | ||
30 | |||
31 | /* | ||
32 | * Function code bits, usually generic to devices. | ||
33 | */ | ||
34 | #ifdef CONFIG_CPM1 | ||
35 | #define CPMFCR_GBL ((u_char)0x00) /* Flag doesn't exist in CPM1 */ | ||
36 | #define CPMFCR_TC2 ((u_char)0x00) /* Flag doesn't exist in CPM1 */ | ||
37 | #define CPMFCR_DTB ((u_char)0x00) /* Flag doesn't exist in CPM1 */ | ||
38 | #define CPMFCR_BDB ((u_char)0x00) /* Flag doesn't exist in CPM1 */ | ||
39 | #else | ||
40 | #define CPMFCR_GBL ((u_char)0x20) /* Set memory snooping */ | ||
41 | #define CPMFCR_TC2 ((u_char)0x04) /* Transfer code 2 value */ | ||
42 | #define CPMFCR_DTB ((u_char)0x02) /* Use local bus for data when set */ | ||
43 | #define CPMFCR_BDB ((u_char)0x01) /* Use local bus for BD when set */ | ||
44 | #endif | ||
45 | #define CPMFCR_EB ((u_char)0x10) /* Set big endian byte order */ | ||
46 | |||
8 | /* Opcodes common to CPM1 and CPM2 | 47 | /* Opcodes common to CPM1 and CPM2 |
9 | */ | 48 | */ |
10 | #define CPM_CR_INIT_TRX ((ushort)0x0000) | 49 | #define CPM_CR_INIT_TRX ((ushort)0x0000) |
@@ -93,13 +132,56 @@ typedef struct cpm_buf_desc { | |||
93 | #define BD_I2C_START (0x0400) | 132 | #define BD_I2C_START (0x0400) |
94 | 133 | ||
95 | int cpm_muram_init(void); | 134 | int cpm_muram_init(void); |
135 | |||
136 | #if defined(CONFIG_CPM) || defined(CONFIG_QUICC_ENGINE) | ||
96 | unsigned long cpm_muram_alloc(unsigned long size, unsigned long align); | 137 | unsigned long cpm_muram_alloc(unsigned long size, unsigned long align); |
97 | int cpm_muram_free(unsigned long offset); | 138 | int cpm_muram_free(unsigned long offset); |
98 | unsigned long cpm_muram_alloc_fixed(unsigned long offset, unsigned long size); | 139 | unsigned long cpm_muram_alloc_fixed(unsigned long offset, unsigned long size); |
99 | void __iomem *cpm_muram_addr(unsigned long offset); | 140 | void __iomem *cpm_muram_addr(unsigned long offset); |
100 | unsigned long cpm_muram_offset(void __iomem *addr); | 141 | unsigned long cpm_muram_offset(void __iomem *addr); |
101 | dma_addr_t cpm_muram_dma(void __iomem *addr); | 142 | dma_addr_t cpm_muram_dma(void __iomem *addr); |
143 | #else | ||
144 | static inline unsigned long cpm_muram_alloc(unsigned long size, | ||
145 | unsigned long align) | ||
146 | { | ||
147 | return -ENOSYS; | ||
148 | } | ||
149 | |||
150 | static inline int cpm_muram_free(unsigned long offset) | ||
151 | { | ||
152 | return -ENOSYS; | ||
153 | } | ||
154 | |||
155 | static inline unsigned long cpm_muram_alloc_fixed(unsigned long offset, | ||
156 | unsigned long size) | ||
157 | { | ||
158 | return -ENOSYS; | ||
159 | } | ||
160 | |||
161 | static inline void __iomem *cpm_muram_addr(unsigned long offset) | ||
162 | { | ||
163 | return NULL; | ||
164 | } | ||
165 | |||
166 | static inline unsigned long cpm_muram_offset(void __iomem *addr) | ||
167 | { | ||
168 | return -ENOSYS; | ||
169 | } | ||
170 | |||
171 | static inline dma_addr_t cpm_muram_dma(void __iomem *addr) | ||
172 | { | ||
173 | return 0; | ||
174 | } | ||
175 | #endif /* defined(CONFIG_CPM) || defined(CONFIG_QUICC_ENGINE) */ | ||
176 | |||
177 | #ifdef CONFIG_CPM | ||
102 | int cpm_command(u32 command, u8 opcode); | 178 | int cpm_command(u32 command, u8 opcode); |
179 | #else | ||
180 | static inline int cpm_command(u32 command, u8 opcode) | ||
181 | { | ||
182 | return -ENOSYS; | ||
183 | } | ||
184 | #endif /* CONFIG_CPM */ | ||
103 | 185 | ||
104 | int cpm2_gpiochip_add32(struct device_node *np); | 186 | int cpm2_gpiochip_add32(struct device_node *np); |
105 | 187 | ||
diff --git a/arch/powerpc/include/asm/cpm1.h b/arch/powerpc/include/asm/cpm1.h index 7685ffde8821..81b01192f440 100644 --- a/arch/powerpc/include/asm/cpm1.h +++ b/arch/powerpc/include/asm/cpm1.h | |||
@@ -478,51 +478,6 @@ typedef struct iic { | |||
478 | char res2[2]; /* Reserved */ | 478 | char res2[2]; /* Reserved */ |
479 | } iic_t; | 479 | } iic_t; |
480 | 480 | ||
481 | /* SPI parameter RAM. | ||
482 | */ | ||
483 | typedef struct spi { | ||
484 | ushort spi_rbase; /* Rx Buffer descriptor base address */ | ||
485 | ushort spi_tbase; /* Tx Buffer descriptor base address */ | ||
486 | u_char spi_rfcr; /* Rx function code */ | ||
487 | u_char spi_tfcr; /* Tx function code */ | ||
488 | ushort spi_mrblr; /* Max receive buffer length */ | ||
489 | uint spi_rstate; /* Internal */ | ||
490 | uint spi_rdp; /* Internal */ | ||
491 | ushort spi_rbptr; /* Internal */ | ||
492 | ushort spi_rbc; /* Internal */ | ||
493 | uint spi_rxtmp; /* Internal */ | ||
494 | uint spi_tstate; /* Internal */ | ||
495 | uint spi_tdp; /* Internal */ | ||
496 | ushort spi_tbptr; /* Internal */ | ||
497 | ushort spi_tbc; /* Internal */ | ||
498 | uint spi_txtmp; /* Internal */ | ||
499 | uint spi_res; | ||
500 | ushort spi_rpbase; /* Relocation pointer */ | ||
501 | ushort spi_res2; | ||
502 | } spi_t; | ||
503 | |||
504 | /* SPI Mode register. | ||
505 | */ | ||
506 | #define SPMODE_LOOP ((ushort)0x4000) /* Loopback */ | ||
507 | #define SPMODE_CI ((ushort)0x2000) /* Clock Invert */ | ||
508 | #define SPMODE_CP ((ushort)0x1000) /* Clock Phase */ | ||
509 | #define SPMODE_DIV16 ((ushort)0x0800) /* BRG/16 mode */ | ||
510 | #define SPMODE_REV ((ushort)0x0400) /* Reversed Data */ | ||
511 | #define SPMODE_MSTR ((ushort)0x0200) /* SPI Master */ | ||
512 | #define SPMODE_EN ((ushort)0x0100) /* Enable */ | ||
513 | #define SPMODE_LENMSK ((ushort)0x00f0) /* character length */ | ||
514 | #define SPMODE_LEN4 ((ushort)0x0030) /* 4 bits per char */ | ||
515 | #define SPMODE_LEN8 ((ushort)0x0070) /* 8 bits per char */ | ||
516 | #define SPMODE_LEN16 ((ushort)0x00f0) /* 16 bits per char */ | ||
517 | #define SPMODE_PMMSK ((ushort)0x000f) /* prescale modulus */ | ||
518 | |||
519 | /* SPIE fields */ | ||
520 | #define SPIE_MME 0x20 | ||
521 | #define SPIE_TXE 0x10 | ||
522 | #define SPIE_BSY 0x04 | ||
523 | #define SPIE_TXB 0x02 | ||
524 | #define SPIE_RXB 0x01 | ||
525 | |||
526 | /* | 481 | /* |
527 | * RISC Controller Configuration Register definitons | 482 | * RISC Controller Configuration Register definitons |
528 | */ | 483 | */ |
diff --git a/arch/powerpc/include/asm/cpm2.h b/arch/powerpc/include/asm/cpm2.h index 990ff191da8b..f42e9baf3a4e 100644 --- a/arch/powerpc/include/asm/cpm2.h +++ b/arch/powerpc/include/asm/cpm2.h | |||
@@ -124,14 +124,6 @@ static inline void cpm2_fastbrg(uint brg, uint rate, int div16) | |||
124 | __cpm2_setbrg(brg, rate, CPM2_BRG_INT_CLK, div16, CPM_BRG_EXTC_INT); | 124 | __cpm2_setbrg(brg, rate, CPM2_BRG_INT_CLK, div16, CPM_BRG_EXTC_INT); |
125 | } | 125 | } |
126 | 126 | ||
127 | /* Function code bits, usually generic to devices. | ||
128 | */ | ||
129 | #define CPMFCR_GBL ((u_char)0x20) /* Set memory snooping */ | ||
130 | #define CPMFCR_EB ((u_char)0x10) /* Set big endian byte order */ | ||
131 | #define CPMFCR_TC2 ((u_char)0x04) /* Transfer code 2 value */ | ||
132 | #define CPMFCR_DTB ((u_char)0x02) /* Use local bus for data when set */ | ||
133 | #define CPMFCR_BDB ((u_char)0x01) /* Use local bus for BD when set */ | ||
134 | |||
135 | /* Parameter RAM offsets from the base. | 127 | /* Parameter RAM offsets from the base. |
136 | */ | 128 | */ |
137 | #define PROFF_SCC1 ((uint)0x8000) | 129 | #define PROFF_SCC1 ((uint)0x8000) |
@@ -654,45 +646,6 @@ typedef struct iic { | |||
654 | uint iic_txtmp; /* Internal */ | 646 | uint iic_txtmp; /* Internal */ |
655 | } iic_t; | 647 | } iic_t; |
656 | 648 | ||
657 | /* SPI parameter RAM. | ||
658 | */ | ||
659 | typedef struct spi { | ||
660 | ushort spi_rbase; /* Rx Buffer descriptor base address */ | ||
661 | ushort spi_tbase; /* Tx Buffer descriptor base address */ | ||
662 | u_char spi_rfcr; /* Rx function code */ | ||
663 | u_char spi_tfcr; /* Tx function code */ | ||
664 | ushort spi_mrblr; /* Max receive buffer length */ | ||
665 | uint spi_rstate; /* Internal */ | ||
666 | uint spi_rdp; /* Internal */ | ||
667 | ushort spi_rbptr; /* Internal */ | ||
668 | ushort spi_rbc; /* Internal */ | ||
669 | uint spi_rxtmp; /* Internal */ | ||
670 | uint spi_tstate; /* Internal */ | ||
671 | uint spi_tdp; /* Internal */ | ||
672 | ushort spi_tbptr; /* Internal */ | ||
673 | ushort spi_tbc; /* Internal */ | ||
674 | uint spi_txtmp; /* Internal */ | ||
675 | uint spi_res; /* Tx temp. */ | ||
676 | uint spi_res1[4]; /* SDMA temp. */ | ||
677 | } spi_t; | ||
678 | |||
679 | /* SPI Mode register. | ||
680 | */ | ||
681 | #define SPMODE_LOOP ((ushort)0x4000) /* Loopback */ | ||
682 | #define SPMODE_CI ((ushort)0x2000) /* Clock Invert */ | ||
683 | #define SPMODE_CP ((ushort)0x1000) /* Clock Phase */ | ||
684 | #define SPMODE_DIV16 ((ushort)0x0800) /* BRG/16 mode */ | ||
685 | #define SPMODE_REV ((ushort)0x0400) /* Reversed Data */ | ||
686 | #define SPMODE_MSTR ((ushort)0x0200) /* SPI Master */ | ||
687 | #define SPMODE_EN ((ushort)0x0100) /* Enable */ | ||
688 | #define SPMODE_LENMSK ((ushort)0x00f0) /* character length */ | ||
689 | #define SPMODE_PMMSK ((ushort)0x000f) /* prescale modulus */ | ||
690 | |||
691 | #define SPMODE_LEN(x) ((((x)-1)&0xF)<<4) | ||
692 | #define SPMODE_PM(x) ((x) &0xF) | ||
693 | |||
694 | #define SPI_EB ((u_char)0x10) /* big endian byte order */ | ||
695 | |||
696 | /* IDMA parameter RAM | 649 | /* IDMA parameter RAM |
697 | */ | 650 | */ |
698 | typedef struct idma { | 651 | typedef struct idma { |
diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h index a98653b26231..57c400071995 100644 --- a/arch/powerpc/include/asm/exception-64s.h +++ b/arch/powerpc/include/asm/exception-64s.h | |||
@@ -147,6 +147,7 @@ | |||
147 | .globl label##_pSeries; \ | 147 | .globl label##_pSeries; \ |
148 | label##_pSeries: \ | 148 | label##_pSeries: \ |
149 | HMT_MEDIUM; \ | 149 | HMT_MEDIUM; \ |
150 | DO_KVM n; \ | ||
150 | mtspr SPRN_SPRG_SCRATCH0,r13; /* save r13 */ \ | 151 | mtspr SPRN_SPRG_SCRATCH0,r13; /* save r13 */ \ |
151 | EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common) | 152 | EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common) |
152 | 153 | ||
@@ -170,6 +171,7 @@ label##_pSeries: \ | |||
170 | .globl label##_pSeries; \ | 171 | .globl label##_pSeries; \ |
171 | label##_pSeries: \ | 172 | label##_pSeries: \ |
172 | HMT_MEDIUM; \ | 173 | HMT_MEDIUM; \ |
174 | DO_KVM n; \ | ||
173 | mtspr SPRN_SPRG_SCRATCH0,r13; /* save r13 */ \ | 175 | mtspr SPRN_SPRG_SCRATCH0,r13; /* save r13 */ \ |
174 | mfspr r13,SPRN_SPRG_PACA; /* get paca address into r13 */ \ | 176 | mfspr r13,SPRN_SPRG_PACA; /* get paca address into r13 */ \ |
175 | std r9,PACA_EXGEN+EX_R9(r13); /* save r9, r10 */ \ | 177 | std r9,PACA_EXGEN+EX_R9(r13); /* save r9, r10 */ \ |
diff --git a/arch/powerpc/include/asm/hugetlb.h b/arch/powerpc/include/asm/hugetlb.h index b1dafb6a9743..5856a66ab404 100644 --- a/arch/powerpc/include/asm/hugetlb.h +++ b/arch/powerpc/include/asm/hugetlb.h | |||
@@ -3,6 +3,10 @@ | |||
3 | 3 | ||
4 | #include <asm/page.h> | 4 | #include <asm/page.h> |
5 | 5 | ||
6 | pte_t *huge_pte_offset_and_shift(struct mm_struct *mm, | ||
7 | unsigned long addr, unsigned *shift); | ||
8 | |||
9 | void flush_dcache_icache_hugepage(struct page *page); | ||
6 | 10 | ||
7 | int is_hugepage_only_range(struct mm_struct *mm, unsigned long addr, | 11 | int is_hugepage_only_range(struct mm_struct *mm, unsigned long addr, |
8 | unsigned long len); | 12 | unsigned long len); |
@@ -11,12 +15,6 @@ void hugetlb_free_pgd_range(struct mmu_gather *tlb, unsigned long addr, | |||
11 | unsigned long end, unsigned long floor, | 15 | unsigned long end, unsigned long floor, |
12 | unsigned long ceiling); | 16 | unsigned long ceiling); |
13 | 17 | ||
14 | void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, | ||
15 | pte_t *ptep, pte_t pte); | ||
16 | |||
17 | pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, | ||
18 | pte_t *ptep); | ||
19 | |||
20 | /* | 18 | /* |
21 | * The version of vma_mmu_pagesize() in arch/powerpc/mm/hugetlbpage.c needs | 19 | * The version of vma_mmu_pagesize() in arch/powerpc/mm/hugetlbpage.c needs |
22 | * to override the version in mm/hugetlb.c | 20 | * to override the version in mm/hugetlb.c |
@@ -42,9 +40,26 @@ static inline void hugetlb_prefault_arch_hook(struct mm_struct *mm) | |||
42 | { | 40 | { |
43 | } | 41 | } |
44 | 42 | ||
43 | |||
44 | static inline void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, | ||
45 | pte_t *ptep, pte_t pte) | ||
46 | { | ||
47 | set_pte_at(mm, addr, ptep, pte); | ||
48 | } | ||
49 | |||
50 | static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm, | ||
51 | unsigned long addr, pte_t *ptep) | ||
52 | { | ||
53 | unsigned long old = pte_update(mm, addr, ptep, ~0UL, 1); | ||
54 | return __pte(old); | ||
55 | } | ||
56 | |||
45 | static inline void huge_ptep_clear_flush(struct vm_area_struct *vma, | 57 | static inline void huge_ptep_clear_flush(struct vm_area_struct *vma, |
46 | unsigned long addr, pte_t *ptep) | 58 | unsigned long addr, pte_t *ptep) |
47 | { | 59 | { |
60 | pte_t pte; | ||
61 | pte = huge_ptep_get_and_clear(vma->vm_mm, addr, ptep); | ||
62 | flush_tlb_page(vma, addr); | ||
48 | } | 63 | } |
49 | 64 | ||
50 | static inline int huge_pte_none(pte_t pte) | 65 | static inline int huge_pte_none(pte_t pte) |
diff --git a/arch/powerpc/include/asm/hvcall.h b/arch/powerpc/include/asm/hvcall.h index c27caac47ad1..f0275818b95c 100644 --- a/arch/powerpc/include/asm/hvcall.h +++ b/arch/powerpc/include/asm/hvcall.h | |||
@@ -212,6 +212,19 @@ | |||
212 | #define H_QUERY_INT_STATE 0x1E4 | 212 | #define H_QUERY_INT_STATE 0x1E4 |
213 | #define H_POLL_PENDING 0x1D8 | 213 | #define H_POLL_PENDING 0x1D8 |
214 | #define H_ILLAN_ATTRIBUTES 0x244 | 214 | #define H_ILLAN_ATTRIBUTES 0x244 |
215 | #define H_MODIFY_HEA_QP 0x250 | ||
216 | #define H_QUERY_HEA_QP 0x254 | ||
217 | #define H_QUERY_HEA 0x258 | ||
218 | #define H_QUERY_HEA_PORT 0x25C | ||
219 | #define H_MODIFY_HEA_PORT 0x260 | ||
220 | #define H_REG_BCMC 0x264 | ||
221 | #define H_DEREG_BCMC 0x268 | ||
222 | #define H_REGISTER_HEA_RPAGES 0x26C | ||
223 | #define H_DISABLE_AND_GET_HEA 0x270 | ||
224 | #define H_GET_HEA_INFO 0x274 | ||
225 | #define H_ALLOC_HEA_RESOURCE 0x278 | ||
226 | #define H_ADD_CONN 0x284 | ||
227 | #define H_DEL_CONN 0x288 | ||
215 | #define H_JOIN 0x298 | 228 | #define H_JOIN 0x298 |
216 | #define H_VASI_STATE 0x2A4 | 229 | #define H_VASI_STATE 0x2A4 |
217 | #define H_ENABLE_CRQ 0x2B0 | 230 | #define H_ENABLE_CRQ 0x2B0 |
diff --git a/arch/powerpc/include/asm/hw_irq.h b/arch/powerpc/include/asm/hw_irq.h index abbc2aaaced5..9f4c9d4f5803 100644 --- a/arch/powerpc/include/asm/hw_irq.h +++ b/arch/powerpc/include/asm/hw_irq.h | |||
@@ -64,11 +64,6 @@ extern void iseries_handle_interrupts(void); | |||
64 | get_paca()->hard_enabled = 0; \ | 64 | get_paca()->hard_enabled = 0; \ |
65 | } while(0) | 65 | } while(0) |
66 | 66 | ||
67 | static inline int irqs_disabled_flags(unsigned long flags) | ||
68 | { | ||
69 | return flags == 0; | ||
70 | } | ||
71 | |||
72 | #else | 67 | #else |
73 | 68 | ||
74 | #if defined(CONFIG_BOOKE) | 69 | #if defined(CONFIG_BOOKE) |
diff --git a/arch/powerpc/include/asm/immap_cpm2.h b/arch/powerpc/include/asm/immap_cpm2.h index d4f069bf0e57..7c64fda5357b 100644 --- a/arch/powerpc/include/asm/immap_cpm2.h +++ b/arch/powerpc/include/asm/immap_cpm2.h | |||
@@ -549,7 +549,7 @@ typedef struct comm_proc { | |||
549 | 549 | ||
550 | /* USB Controller. | 550 | /* USB Controller. |
551 | */ | 551 | */ |
552 | typedef struct usb_ctlr { | 552 | typedef struct cpm_usb_ctlr { |
553 | u8 usb_usmod; | 553 | u8 usb_usmod; |
554 | u8 usb_usadr; | 554 | u8 usb_usadr; |
555 | u8 usb_uscom; | 555 | u8 usb_uscom; |
diff --git a/arch/powerpc/include/asm/immap_qe.h b/arch/powerpc/include/asm/immap_qe.h index c346d0bcd230..4e10f508570a 100644 --- a/arch/powerpc/include/asm/immap_qe.h +++ b/arch/powerpc/include/asm/immap_qe.h | |||
@@ -210,7 +210,7 @@ struct sir { | |||
210 | } __attribute__ ((packed)); | 210 | } __attribute__ ((packed)); |
211 | 211 | ||
212 | /* USB Controller */ | 212 | /* USB Controller */ |
213 | struct usb_ctlr { | 213 | struct qe_usb_ctlr { |
214 | u8 usb_usmod; | 214 | u8 usb_usmod; |
215 | u8 usb_usadr; | 215 | u8 usb_usadr; |
216 | u8 usb_uscom; | 216 | u8 usb_uscom; |
@@ -229,7 +229,7 @@ struct usb_ctlr { | |||
229 | } __attribute__ ((packed)); | 229 | } __attribute__ ((packed)); |
230 | 230 | ||
231 | /* MCC */ | 231 | /* MCC */ |
232 | struct mcc { | 232 | struct qe_mcc { |
233 | __be32 mcce; /* MCC event register */ | 233 | __be32 mcce; /* MCC event register */ |
234 | __be32 mccm; /* MCC mask register */ | 234 | __be32 mccm; /* MCC mask register */ |
235 | __be32 mccf; /* MCC configuration register */ | 235 | __be32 mccf; /* MCC configuration register */ |
@@ -431,9 +431,9 @@ struct qe_immap { | |||
431 | struct qe_mux qmx; /* QE Multiplexer */ | 431 | struct qe_mux qmx; /* QE Multiplexer */ |
432 | struct qe_timers qet; /* QE Timers */ | 432 | struct qe_timers qet; /* QE Timers */ |
433 | struct spi spi[0x2]; /* spi */ | 433 | struct spi spi[0x2]; /* spi */ |
434 | struct mcc mcc; /* mcc */ | 434 | struct qe_mcc mcc; /* mcc */ |
435 | struct qe_brg brg; /* brg */ | 435 | struct qe_brg brg; /* brg */ |
436 | struct usb_ctlr usb; /* USB */ | 436 | struct qe_usb_ctlr usb; /* USB */ |
437 | struct si1 si1; /* SI */ | 437 | struct si1 si1; /* SI */ |
438 | u8 res11[0x800]; | 438 | u8 res11[0x800]; |
439 | struct sir sir; /* SI Routing Tables */ | 439 | struct sir sir; /* SI Routing Tables */ |
diff --git a/arch/powerpc/include/asm/irq.h b/arch/powerpc/include/asm/irq.h index bbcd1aaf3dfd..e054baef1845 100644 --- a/arch/powerpc/include/asm/irq.h +++ b/arch/powerpc/include/asm/irq.h | |||
@@ -17,8 +17,6 @@ | |||
17 | #include <asm/atomic.h> | 17 | #include <asm/atomic.h> |
18 | 18 | ||
19 | 19 | ||
20 | #define get_irq_desc(irq) (&irq_desc[(irq)]) | ||
21 | |||
22 | /* Define a way to iterate across irqs. */ | 20 | /* Define a way to iterate across irqs. */ |
23 | #define for_each_irq(i) \ | 21 | #define for_each_irq(i) \ |
24 | for ((i) = 0; (i) < NR_IRQS; ++(i)) | 22 | for ((i) = 0; (i) < NR_IRQS; ++(i)) |
@@ -34,12 +32,15 @@ extern atomic_t ppc_n_lost_interrupts; | |||
34 | */ | 32 | */ |
35 | #define NO_IRQ_IGNORE ((unsigned int)-1) | 33 | #define NO_IRQ_IGNORE ((unsigned int)-1) |
36 | 34 | ||
37 | /* Total number of virq in the platform (make it a CONFIG_* option ? */ | 35 | /* Total number of virq in the platform */ |
38 | #define NR_IRQS 512 | 36 | #define NR_IRQS CONFIG_NR_IRQS |
39 | 37 | ||
40 | /* Number of irqs reserved for the legacy controller */ | 38 | /* Number of irqs reserved for the legacy controller */ |
41 | #define NUM_ISA_INTERRUPTS 16 | 39 | #define NUM_ISA_INTERRUPTS 16 |
42 | 40 | ||
41 | /* Same thing, used by the generic IRQ code */ | ||
42 | #define NR_IRQS_LEGACY NUM_ISA_INTERRUPTS | ||
43 | |||
43 | /* This type is the placeholder for a hardware interrupt number. It has to | 44 | /* This type is the placeholder for a hardware interrupt number. It has to |
44 | * be big enough to enclose whatever representation is used by a given | 45 | * be big enough to enclose whatever representation is used by a given |
45 | * platform. | 46 | * platform. |
@@ -99,7 +100,7 @@ struct irq_host_ops { | |||
99 | * interrupt controller has for that line) | 100 | * interrupt controller has for that line) |
100 | */ | 101 | */ |
101 | int (*xlate)(struct irq_host *h, struct device_node *ctrler, | 102 | int (*xlate)(struct irq_host *h, struct device_node *ctrler, |
102 | u32 *intspec, unsigned int intsize, | 103 | const u32 *intspec, unsigned int intsize, |
103 | irq_hw_number_t *out_hwirq, unsigned int *out_type); | 104 | irq_hw_number_t *out_hwirq, unsigned int *out_type); |
104 | }; | 105 | }; |
105 | 106 | ||
@@ -313,7 +314,7 @@ extern void irq_free_virt(unsigned int virq, unsigned int count); | |||
313 | * of the of_irq_map_*() functions. | 314 | * of the of_irq_map_*() functions. |
314 | */ | 315 | */ |
315 | extern unsigned int irq_create_of_mapping(struct device_node *controller, | 316 | extern unsigned int irq_create_of_mapping(struct device_node *controller, |
316 | u32 *intspec, unsigned int intsize); | 317 | const u32 *intspec, unsigned int intsize); |
317 | 318 | ||
318 | /** | 319 | /** |
319 | * irq_of_parse_and_map - Parse and Map an interrupt into linux virq space | 320 | * irq_of_parse_and_map - Parse and Map an interrupt into linux virq space |
diff --git a/arch/powerpc/include/asm/kvm.h b/arch/powerpc/include/asm/kvm.h index bb2de6aa5ce0..81f3b0b5601e 100644 --- a/arch/powerpc/include/asm/kvm.h +++ b/arch/powerpc/include/asm/kvm.h | |||
@@ -46,6 +46,24 @@ struct kvm_regs { | |||
46 | }; | 46 | }; |
47 | 47 | ||
48 | struct kvm_sregs { | 48 | struct kvm_sregs { |
49 | __u32 pvr; | ||
50 | union { | ||
51 | struct { | ||
52 | __u64 sdr1; | ||
53 | struct { | ||
54 | struct { | ||
55 | __u64 slbe; | ||
56 | __u64 slbv; | ||
57 | } slb[64]; | ||
58 | } ppc64; | ||
59 | struct { | ||
60 | __u32 sr[16]; | ||
61 | __u64 ibat[8]; | ||
62 | __u64 dbat[8]; | ||
63 | } ppc32; | ||
64 | } s; | ||
65 | __u8 pad[1020]; | ||
66 | } u; | ||
49 | }; | 67 | }; |
50 | 68 | ||
51 | struct kvm_fpu { | 69 | struct kvm_fpu { |
diff --git a/arch/powerpc/include/asm/kvm_asm.h b/arch/powerpc/include/asm/kvm_asm.h index 56bfae59837f..af2abe74f544 100644 --- a/arch/powerpc/include/asm/kvm_asm.h +++ b/arch/powerpc/include/asm/kvm_asm.h | |||
@@ -49,6 +49,46 @@ | |||
49 | #define BOOKE_INTERRUPT_SPE_FP_ROUND 34 | 49 | #define BOOKE_INTERRUPT_SPE_FP_ROUND 34 |
50 | #define BOOKE_INTERRUPT_PERFORMANCE_MONITOR 35 | 50 | #define BOOKE_INTERRUPT_PERFORMANCE_MONITOR 35 |
51 | 51 | ||
52 | /* book3s */ | ||
53 | |||
54 | #define BOOK3S_INTERRUPT_SYSTEM_RESET 0x100 | ||
55 | #define BOOK3S_INTERRUPT_MACHINE_CHECK 0x200 | ||
56 | #define BOOK3S_INTERRUPT_DATA_STORAGE 0x300 | ||
57 | #define BOOK3S_INTERRUPT_DATA_SEGMENT 0x380 | ||
58 | #define BOOK3S_INTERRUPT_INST_STORAGE 0x400 | ||
59 | #define BOOK3S_INTERRUPT_INST_SEGMENT 0x480 | ||
60 | #define BOOK3S_INTERRUPT_EXTERNAL 0x500 | ||
61 | #define BOOK3S_INTERRUPT_ALIGNMENT 0x600 | ||
62 | #define BOOK3S_INTERRUPT_PROGRAM 0x700 | ||
63 | #define BOOK3S_INTERRUPT_FP_UNAVAIL 0x800 | ||
64 | #define BOOK3S_INTERRUPT_DECREMENTER 0x900 | ||
65 | #define BOOK3S_INTERRUPT_SYSCALL 0xc00 | ||
66 | #define BOOK3S_INTERRUPT_TRACE 0xd00 | ||
67 | #define BOOK3S_INTERRUPT_PERFMON 0xf00 | ||
68 | #define BOOK3S_INTERRUPT_ALTIVEC 0xf20 | ||
69 | #define BOOK3S_INTERRUPT_VSX 0xf40 | ||
70 | |||
71 | #define BOOK3S_IRQPRIO_SYSTEM_RESET 0 | ||
72 | #define BOOK3S_IRQPRIO_DATA_SEGMENT 1 | ||
73 | #define BOOK3S_IRQPRIO_INST_SEGMENT 2 | ||
74 | #define BOOK3S_IRQPRIO_DATA_STORAGE 3 | ||
75 | #define BOOK3S_IRQPRIO_INST_STORAGE 4 | ||
76 | #define BOOK3S_IRQPRIO_ALIGNMENT 5 | ||
77 | #define BOOK3S_IRQPRIO_PROGRAM 6 | ||
78 | #define BOOK3S_IRQPRIO_FP_UNAVAIL 7 | ||
79 | #define BOOK3S_IRQPRIO_ALTIVEC 8 | ||
80 | #define BOOK3S_IRQPRIO_VSX 9 | ||
81 | #define BOOK3S_IRQPRIO_SYSCALL 10 | ||
82 | #define BOOK3S_IRQPRIO_MACHINE_CHECK 11 | ||
83 | #define BOOK3S_IRQPRIO_DEBUG 12 | ||
84 | #define BOOK3S_IRQPRIO_EXTERNAL 13 | ||
85 | #define BOOK3S_IRQPRIO_DECREMENTER 14 | ||
86 | #define BOOK3S_IRQPRIO_PERFORMANCE_MONITOR 15 | ||
87 | #define BOOK3S_IRQPRIO_MAX 16 | ||
88 | |||
89 | #define BOOK3S_HFLAG_DCBZ32 0x1 | ||
90 | #define BOOK3S_HFLAG_SLB 0x2 | ||
91 | |||
52 | #define RESUME_FLAG_NV (1<<0) /* Reload guest nonvolatile state? */ | 92 | #define RESUME_FLAG_NV (1<<0) /* Reload guest nonvolatile state? */ |
53 | #define RESUME_FLAG_HOST (1<<1) /* Resume host? */ | 93 | #define RESUME_FLAG_HOST (1<<1) /* Resume host? */ |
54 | 94 | ||
diff --git a/arch/powerpc/include/asm/kvm_book3s.h b/arch/powerpc/include/asm/kvm_book3s.h new file mode 100644 index 000000000000..74b7369770d0 --- /dev/null +++ b/arch/powerpc/include/asm/kvm_book3s.h | |||
@@ -0,0 +1,139 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License, version 2, as | ||
4 | * published by the Free Software Foundation. | ||
5 | * | ||
6 | * This program is distributed in the hope that it will be useful, | ||
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
9 | * GNU General Public License for more details. | ||
10 | * | ||
11 | * You should have received a copy of the GNU General Public License | ||
12 | * along with this program; if not, write to the Free Software | ||
13 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
14 | * | ||
15 | * Copyright SUSE Linux Products GmbH 2009 | ||
16 | * | ||
17 | * Authors: Alexander Graf <agraf@suse.de> | ||
18 | */ | ||
19 | |||
20 | #ifndef __ASM_KVM_BOOK3S_H__ | ||
21 | #define __ASM_KVM_BOOK3S_H__ | ||
22 | |||
23 | #include <linux/types.h> | ||
24 | #include <linux/kvm_host.h> | ||
25 | #include <asm/kvm_ppc.h> | ||
26 | |||
27 | struct kvmppc_slb { | ||
28 | u64 esid; | ||
29 | u64 vsid; | ||
30 | u64 orige; | ||
31 | u64 origv; | ||
32 | bool valid; | ||
33 | bool Ks; | ||
34 | bool Kp; | ||
35 | bool nx; | ||
36 | bool large; | ||
37 | bool class; | ||
38 | }; | ||
39 | |||
40 | struct kvmppc_sr { | ||
41 | u32 raw; | ||
42 | u32 vsid; | ||
43 | bool Ks; | ||
44 | bool Kp; | ||
45 | bool nx; | ||
46 | }; | ||
47 | |||
48 | struct kvmppc_bat { | ||
49 | u64 raw; | ||
50 | u32 bepi; | ||
51 | u32 bepi_mask; | ||
52 | bool vs; | ||
53 | bool vp; | ||
54 | u32 brpn; | ||
55 | u8 wimg; | ||
56 | u8 pp; | ||
57 | }; | ||
58 | |||
59 | struct kvmppc_sid_map { | ||
60 | u64 guest_vsid; | ||
61 | u64 guest_esid; | ||
62 | u64 host_vsid; | ||
63 | bool valid; | ||
64 | }; | ||
65 | |||
66 | #define SID_MAP_BITS 9 | ||
67 | #define SID_MAP_NUM (1 << SID_MAP_BITS) | ||
68 | #define SID_MAP_MASK (SID_MAP_NUM - 1) | ||
69 | |||
70 | struct kvmppc_vcpu_book3s { | ||
71 | struct kvm_vcpu vcpu; | ||
72 | struct kvmppc_sid_map sid_map[SID_MAP_NUM]; | ||
73 | struct kvmppc_slb slb[64]; | ||
74 | struct { | ||
75 | u64 esid; | ||
76 | u64 vsid; | ||
77 | } slb_shadow[64]; | ||
78 | u8 slb_shadow_max; | ||
79 | struct kvmppc_sr sr[16]; | ||
80 | struct kvmppc_bat ibat[8]; | ||
81 | struct kvmppc_bat dbat[8]; | ||
82 | u64 hid[6]; | ||
83 | int slb_nr; | ||
84 | u64 sdr1; | ||
85 | u64 dsisr; | ||
86 | u64 hior; | ||
87 | u64 msr_mask; | ||
88 | u64 vsid_first; | ||
89 | u64 vsid_next; | ||
90 | u64 vsid_max; | ||
91 | int context_id; | ||
92 | }; | ||
93 | |||
94 | #define CONTEXT_HOST 0 | ||
95 | #define CONTEXT_GUEST 1 | ||
96 | #define CONTEXT_GUEST_END 2 | ||
97 | |||
98 | #define VSID_REAL 0xfffffffffff00000 | ||
99 | #define VSID_REAL_DR 0xffffffffffe00000 | ||
100 | #define VSID_REAL_IR 0xffffffffffd00000 | ||
101 | #define VSID_BAT 0xffffffffffc00000 | ||
102 | #define VSID_PR 0x8000000000000000 | ||
103 | |||
104 | extern void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, u64 ea, u64 ea_mask); | ||
105 | extern void kvmppc_mmu_pte_vflush(struct kvm_vcpu *vcpu, u64 vp, u64 vp_mask); | ||
106 | extern void kvmppc_mmu_pte_pflush(struct kvm_vcpu *vcpu, u64 pa_start, u64 pa_end); | ||
107 | extern void kvmppc_set_msr(struct kvm_vcpu *vcpu, u64 new_msr); | ||
108 | extern void kvmppc_mmu_book3s_64_init(struct kvm_vcpu *vcpu); | ||
109 | extern void kvmppc_mmu_book3s_32_init(struct kvm_vcpu *vcpu); | ||
110 | extern int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte); | ||
111 | extern int kvmppc_mmu_map_segment(struct kvm_vcpu *vcpu, ulong eaddr); | ||
112 | extern void kvmppc_mmu_flush_segments(struct kvm_vcpu *vcpu); | ||
113 | extern struct kvmppc_pte *kvmppc_mmu_find_pte(struct kvm_vcpu *vcpu, u64 ea, bool data); | ||
114 | extern int kvmppc_ld(struct kvm_vcpu *vcpu, ulong eaddr, int size, void *ptr, bool data); | ||
115 | extern int kvmppc_st(struct kvm_vcpu *vcpu, ulong eaddr, int size, void *ptr); | ||
116 | extern void kvmppc_book3s_queue_irqprio(struct kvm_vcpu *vcpu, unsigned int vec); | ||
117 | extern void kvmppc_set_bat(struct kvm_vcpu *vcpu, struct kvmppc_bat *bat, | ||
118 | bool upper, u32 val); | ||
119 | |||
120 | extern u32 kvmppc_trampoline_lowmem; | ||
121 | extern u32 kvmppc_trampoline_enter; | ||
122 | |||
123 | static inline struct kvmppc_vcpu_book3s *to_book3s(struct kvm_vcpu *vcpu) | ||
124 | { | ||
125 | return container_of(vcpu, struct kvmppc_vcpu_book3s, vcpu); | ||
126 | } | ||
127 | |||
128 | static inline ulong dsisr(void) | ||
129 | { | ||
130 | ulong r; | ||
131 | asm ( "mfdsisr %0 " : "=r" (r) ); | ||
132 | return r; | ||
133 | } | ||
134 | |||
135 | extern void kvm_return_point(void); | ||
136 | |||
137 | #define INS_DCBZ 0x7c0007ec | ||
138 | |||
139 | #endif /* __ASM_KVM_BOOK3S_H__ */ | ||
diff --git a/arch/powerpc/include/asm/kvm_book3s_64_asm.h b/arch/powerpc/include/asm/kvm_book3s_64_asm.h new file mode 100644 index 000000000000..2e06ee8184ef --- /dev/null +++ b/arch/powerpc/include/asm/kvm_book3s_64_asm.h | |||
@@ -0,0 +1,58 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License, version 2, as | ||
4 | * published by the Free Software Foundation. | ||
5 | * | ||
6 | * This program is distributed in the hope that it will be useful, | ||
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
9 | * GNU General Public License for more details. | ||
10 | * | ||
11 | * You should have received a copy of the GNU General Public License | ||
12 | * along with this program; if not, write to the Free Software | ||
13 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
14 | * | ||
15 | * Copyright SUSE Linux Products GmbH 2009 | ||
16 | * | ||
17 | * Authors: Alexander Graf <agraf@suse.de> | ||
18 | */ | ||
19 | |||
20 | #ifndef __ASM_KVM_BOOK3S_ASM_H__ | ||
21 | #define __ASM_KVM_BOOK3S_ASM_H__ | ||
22 | |||
23 | #ifdef CONFIG_KVM_BOOK3S_64_HANDLER | ||
24 | |||
25 | #include <asm/kvm_asm.h> | ||
26 | |||
27 | .macro DO_KVM intno | ||
28 | .if (\intno == BOOK3S_INTERRUPT_SYSTEM_RESET) || \ | ||
29 | (\intno == BOOK3S_INTERRUPT_MACHINE_CHECK) || \ | ||
30 | (\intno == BOOK3S_INTERRUPT_DATA_STORAGE) || \ | ||
31 | (\intno == BOOK3S_INTERRUPT_INST_STORAGE) || \ | ||
32 | (\intno == BOOK3S_INTERRUPT_DATA_SEGMENT) || \ | ||
33 | (\intno == BOOK3S_INTERRUPT_INST_SEGMENT) || \ | ||
34 | (\intno == BOOK3S_INTERRUPT_EXTERNAL) || \ | ||
35 | (\intno == BOOK3S_INTERRUPT_ALIGNMENT) || \ | ||
36 | (\intno == BOOK3S_INTERRUPT_PROGRAM) || \ | ||
37 | (\intno == BOOK3S_INTERRUPT_FP_UNAVAIL) || \ | ||
38 | (\intno == BOOK3S_INTERRUPT_DECREMENTER) || \ | ||
39 | (\intno == BOOK3S_INTERRUPT_SYSCALL) || \ | ||
40 | (\intno == BOOK3S_INTERRUPT_TRACE) || \ | ||
41 | (\intno == BOOK3S_INTERRUPT_PERFMON) || \ | ||
42 | (\intno == BOOK3S_INTERRUPT_ALTIVEC) || \ | ||
43 | (\intno == BOOK3S_INTERRUPT_VSX) | ||
44 | |||
45 | b kvmppc_trampoline_\intno | ||
46 | kvmppc_resume_\intno: | ||
47 | |||
48 | .endif | ||
49 | .endm | ||
50 | |||
51 | #else | ||
52 | |||
53 | .macro DO_KVM intno | ||
54 | .endm | ||
55 | |||
56 | #endif /* CONFIG_KVM_BOOK3S_64_HANDLER */ | ||
57 | |||
58 | #endif /* __ASM_KVM_BOOK3S_ASM_H__ */ | ||
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h index c9c930ed11d7..1201f62d0d73 100644 --- a/arch/powerpc/include/asm/kvm_host.h +++ b/arch/powerpc/include/asm/kvm_host.h | |||
@@ -21,7 +21,8 @@ | |||
21 | #define __POWERPC_KVM_HOST_H__ | 21 | #define __POWERPC_KVM_HOST_H__ |
22 | 22 | ||
23 | #include <linux/mutex.h> | 23 | #include <linux/mutex.h> |
24 | #include <linux/timer.h> | 24 | #include <linux/hrtimer.h> |
25 | #include <linux/interrupt.h> | ||
25 | #include <linux/types.h> | 26 | #include <linux/types.h> |
26 | #include <linux/kvm_types.h> | 27 | #include <linux/kvm_types.h> |
27 | #include <asm/kvm_asm.h> | 28 | #include <asm/kvm_asm.h> |
@@ -37,6 +38,8 @@ | |||
37 | #define KVM_NR_PAGE_SIZES 1 | 38 | #define KVM_NR_PAGE_SIZES 1 |
38 | #define KVM_PAGES_PER_HPAGE(x) (1UL<<31) | 39 | #define KVM_PAGES_PER_HPAGE(x) (1UL<<31) |
39 | 40 | ||
41 | #define HPTEG_CACHE_NUM 1024 | ||
42 | |||
40 | struct kvm; | 43 | struct kvm; |
41 | struct kvm_run; | 44 | struct kvm_run; |
42 | struct kvm_vcpu; | 45 | struct kvm_vcpu; |
@@ -63,6 +66,17 @@ struct kvm_vcpu_stat { | |||
63 | u32 dec_exits; | 66 | u32 dec_exits; |
64 | u32 ext_intr_exits; | 67 | u32 ext_intr_exits; |
65 | u32 halt_wakeup; | 68 | u32 halt_wakeup; |
69 | #ifdef CONFIG_PPC64 | ||
70 | u32 pf_storage; | ||
71 | u32 pf_instruc; | ||
72 | u32 sp_storage; | ||
73 | u32 sp_instruc; | ||
74 | u32 queue_intr; | ||
75 | u32 ld; | ||
76 | u32 ld_slow; | ||
77 | u32 st; | ||
78 | u32 st_slow; | ||
79 | #endif | ||
66 | }; | 80 | }; |
67 | 81 | ||
68 | enum kvm_exit_types { | 82 | enum kvm_exit_types { |
@@ -109,9 +123,53 @@ struct kvmppc_exit_timing { | |||
109 | struct kvm_arch { | 123 | struct kvm_arch { |
110 | }; | 124 | }; |
111 | 125 | ||
126 | struct kvmppc_pte { | ||
127 | u64 eaddr; | ||
128 | u64 vpage; | ||
129 | u64 raddr; | ||
130 | bool may_read; | ||
131 | bool may_write; | ||
132 | bool may_execute; | ||
133 | }; | ||
134 | |||
135 | struct kvmppc_mmu { | ||
136 | /* book3s_64 only */ | ||
137 | void (*slbmte)(struct kvm_vcpu *vcpu, u64 rb, u64 rs); | ||
138 | u64 (*slbmfee)(struct kvm_vcpu *vcpu, u64 slb_nr); | ||
139 | u64 (*slbmfev)(struct kvm_vcpu *vcpu, u64 slb_nr); | ||
140 | void (*slbie)(struct kvm_vcpu *vcpu, u64 slb_nr); | ||
141 | void (*slbia)(struct kvm_vcpu *vcpu); | ||
142 | /* book3s */ | ||
143 | void (*mtsrin)(struct kvm_vcpu *vcpu, u32 srnum, ulong value); | ||
144 | u32 (*mfsrin)(struct kvm_vcpu *vcpu, u32 srnum); | ||
145 | int (*xlate)(struct kvm_vcpu *vcpu, gva_t eaddr, struct kvmppc_pte *pte, bool data); | ||
146 | void (*reset_msr)(struct kvm_vcpu *vcpu); | ||
147 | void (*tlbie)(struct kvm_vcpu *vcpu, ulong addr, bool large); | ||
148 | int (*esid_to_vsid)(struct kvm_vcpu *vcpu, u64 esid, u64 *vsid); | ||
149 | u64 (*ea_to_vp)(struct kvm_vcpu *vcpu, gva_t eaddr, bool data); | ||
150 | bool (*is_dcbz32)(struct kvm_vcpu *vcpu); | ||
151 | }; | ||
152 | |||
153 | struct hpte_cache { | ||
154 | u64 host_va; | ||
155 | u64 pfn; | ||
156 | ulong slot; | ||
157 | struct kvmppc_pte pte; | ||
158 | }; | ||
159 | |||
112 | struct kvm_vcpu_arch { | 160 | struct kvm_vcpu_arch { |
113 | u32 host_stack; | 161 | ulong host_stack; |
114 | u32 host_pid; | 162 | u32 host_pid; |
163 | #ifdef CONFIG_PPC64 | ||
164 | ulong host_msr; | ||
165 | ulong host_r2; | ||
166 | void *host_retip; | ||
167 | ulong trampoline_lowmem; | ||
168 | ulong trampoline_enter; | ||
169 | ulong highmem_handler; | ||
170 | ulong host_paca_phys; | ||
171 | struct kvmppc_mmu mmu; | ||
172 | #endif | ||
115 | 173 | ||
116 | u64 fpr[32]; | 174 | u64 fpr[32]; |
117 | ulong gpr[32]; | 175 | ulong gpr[32]; |
@@ -123,6 +181,10 @@ struct kvm_vcpu_arch { | |||
123 | ulong xer; | 181 | ulong xer; |
124 | 182 | ||
125 | ulong msr; | 183 | ulong msr; |
184 | #ifdef CONFIG_PPC64 | ||
185 | ulong shadow_msr; | ||
186 | ulong hflags; | ||
187 | #endif | ||
126 | u32 mmucr; | 188 | u32 mmucr; |
127 | ulong sprg0; | 189 | ulong sprg0; |
128 | ulong sprg1; | 190 | ulong sprg1; |
@@ -149,6 +211,7 @@ struct kvm_vcpu_arch { | |||
149 | u32 ivor[64]; | 211 | u32 ivor[64]; |
150 | ulong ivpr; | 212 | ulong ivpr; |
151 | u32 pir; | 213 | u32 pir; |
214 | u32 pvr; | ||
152 | 215 | ||
153 | u32 shadow_pid; | 216 | u32 shadow_pid; |
154 | u32 pid; | 217 | u32 pid; |
@@ -174,6 +237,9 @@ struct kvm_vcpu_arch { | |||
174 | #endif | 237 | #endif |
175 | 238 | ||
176 | u32 last_inst; | 239 | u32 last_inst; |
240 | #ifdef CONFIG_PPC64 | ||
241 | ulong fault_dsisr; | ||
242 | #endif | ||
177 | ulong fault_dear; | 243 | ulong fault_dear; |
178 | ulong fault_esr; | 244 | ulong fault_esr; |
179 | gpa_t paddr_accessed; | 245 | gpa_t paddr_accessed; |
@@ -185,8 +251,15 @@ struct kvm_vcpu_arch { | |||
185 | 251 | ||
186 | u32 cpr0_cfgaddr; /* holds the last set cpr0_cfgaddr */ | 252 | u32 cpr0_cfgaddr; /* holds the last set cpr0_cfgaddr */ |
187 | 253 | ||
188 | struct timer_list dec_timer; | 254 | struct hrtimer dec_timer; |
255 | struct tasklet_struct tasklet; | ||
256 | u64 dec_jiffies; | ||
189 | unsigned long pending_exceptions; | 257 | unsigned long pending_exceptions; |
258 | |||
259 | #ifdef CONFIG_PPC64 | ||
260 | struct hpte_cache hpte_cache[HPTEG_CACHE_NUM]; | ||
261 | int hpte_cache_offset; | ||
262 | #endif | ||
190 | }; | 263 | }; |
191 | 264 | ||
192 | #endif /* __POWERPC_KVM_HOST_H__ */ | 265 | #endif /* __POWERPC_KVM_HOST_H__ */ |
diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h index 2c6ee349df5e..269ee46ab028 100644 --- a/arch/powerpc/include/asm/kvm_ppc.h +++ b/arch/powerpc/include/asm/kvm_ppc.h | |||
@@ -39,6 +39,7 @@ enum emulation_result { | |||
39 | extern int __kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu); | 39 | extern int __kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu); |
40 | extern char kvmppc_handlers_start[]; | 40 | extern char kvmppc_handlers_start[]; |
41 | extern unsigned long kvmppc_handler_len; | 41 | extern unsigned long kvmppc_handler_len; |
42 | extern void kvmppc_handler_highmem(void); | ||
42 | 43 | ||
43 | extern void kvmppc_dump_vcpu(struct kvm_vcpu *vcpu); | 44 | extern void kvmppc_dump_vcpu(struct kvm_vcpu *vcpu); |
44 | extern int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu, | 45 | extern int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu, |
diff --git a/arch/powerpc/include/asm/lppaca.h b/arch/powerpc/include/asm/lppaca.h index f78f65c38f05..14b592dfb4e8 100644 --- a/arch/powerpc/include/asm/lppaca.h +++ b/arch/powerpc/include/asm/lppaca.h | |||
@@ -100,7 +100,14 @@ struct lppaca { | |||
100 | // Used to pass parms from the OS to PLIC for SetAsrAndRfid | 100 | // Used to pass parms from the OS to PLIC for SetAsrAndRfid |
101 | u64 saved_gpr3; // Saved GPR3 x20-x27 | 101 | u64 saved_gpr3; // Saved GPR3 x20-x27 |
102 | u64 saved_gpr4; // Saved GPR4 x28-x2F | 102 | u64 saved_gpr4; // Saved GPR4 x28-x2F |
103 | u64 saved_gpr5; // Saved GPR5 x30-x37 | 103 | union { |
104 | u64 saved_gpr5; /* Saved GPR5 x30-x37 */ | ||
105 | struct { | ||
106 | u8 cede_latency_hint; /* x30 */ | ||
107 | u8 reserved[7]; /* x31-x36 */ | ||
108 | } fields; | ||
109 | } gpr5_dword; | ||
110 | |||
104 | 111 | ||
105 | u8 dtl_enable_mask; // Dispatch Trace Log mask x38-x38 | 112 | u8 dtl_enable_mask; // Dispatch Trace Log mask x38-x38 |
106 | u8 donate_dedicated_cpu; // Donate dedicated CPU cycles x39-x39 | 113 | u8 donate_dedicated_cpu; // Donate dedicated CPU cycles x39-x39 |
diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h index 9efa2be78331..9f0fc9e6ce0d 100644 --- a/arch/powerpc/include/asm/machdep.h +++ b/arch/powerpc/include/asm/machdep.h | |||
@@ -266,6 +266,11 @@ struct machdep_calls { | |||
266 | void (*suspend_disable_irqs)(void); | 266 | void (*suspend_disable_irqs)(void); |
267 | void (*suspend_enable_irqs)(void); | 267 | void (*suspend_enable_irqs)(void); |
268 | #endif | 268 | #endif |
269 | |||
270 | #ifdef CONFIG_ARCH_CPU_PROBE_RELEASE | ||
271 | ssize_t (*cpu_probe)(const char *, size_t); | ||
272 | ssize_t (*cpu_release)(const char *, size_t); | ||
273 | #endif | ||
269 | }; | 274 | }; |
270 | 275 | ||
271 | extern void e500_idle(void); | 276 | extern void e500_idle(void); |
diff --git a/arch/powerpc/include/asm/macio.h b/arch/powerpc/include/asm/macio.h index 079c06eae446..a062c57696d0 100644 --- a/arch/powerpc/include/asm/macio.h +++ b/arch/powerpc/include/asm/macio.h | |||
@@ -39,6 +39,7 @@ struct macio_dev | |||
39 | struct macio_bus *bus; /* macio bus this device is on */ | 39 | struct macio_bus *bus; /* macio bus this device is on */ |
40 | struct macio_dev *media_bay; /* Device is part of a media bay */ | 40 | struct macio_dev *media_bay; /* Device is part of a media bay */ |
41 | struct of_device ofdev; | 41 | struct of_device ofdev; |
42 | struct device_dma_parameters dma_parms; /* ide needs that */ | ||
42 | int n_resources; | 43 | int n_resources; |
43 | struct resource resource[MACIO_DEV_COUNT_RESOURCES]; | 44 | struct resource resource[MACIO_DEV_COUNT_RESOURCES]; |
44 | int n_interrupts; | 45 | int n_interrupts; |
@@ -78,6 +79,8 @@ static inline unsigned long macio_resource_len(struct macio_dev *dev, int resour | |||
78 | return res->end - res->start + 1; | 79 | return res->end - res->start + 1; |
79 | } | 80 | } |
80 | 81 | ||
82 | extern int macio_enable_devres(struct macio_dev *dev); | ||
83 | |||
81 | extern int macio_request_resource(struct macio_dev *dev, int resource_no, const char *name); | 84 | extern int macio_request_resource(struct macio_dev *dev, int resource_no, const char *name); |
82 | extern void macio_release_resource(struct macio_dev *dev, int resource_no); | 85 | extern void macio_release_resource(struct macio_dev *dev, int resource_no); |
83 | extern int macio_request_resources(struct macio_dev *dev, const char *name); | 86 | extern int macio_request_resources(struct macio_dev *dev, const char *name); |
@@ -131,6 +134,9 @@ struct macio_driver | |||
131 | int (*resume)(struct macio_dev* dev); | 134 | int (*resume)(struct macio_dev* dev); |
132 | int (*shutdown)(struct macio_dev* dev); | 135 | int (*shutdown)(struct macio_dev* dev); |
133 | 136 | ||
137 | #ifdef CONFIG_PMAC_MEDIABAY | ||
138 | void (*mediabay_event)(struct macio_dev* dev, int mb_state); | ||
139 | #endif | ||
134 | struct device_driver driver; | 140 | struct device_driver driver; |
135 | }; | 141 | }; |
136 | #define to_macio_driver(drv) container_of(drv,struct macio_driver, driver) | 142 | #define to_macio_driver(drv) container_of(drv,struct macio_driver, driver) |
diff --git a/arch/powerpc/include/asm/mediabay.h b/arch/powerpc/include/asm/mediabay.h index b2efb3325808..11037a4133ee 100644 --- a/arch/powerpc/include/asm/mediabay.h +++ b/arch/powerpc/include/asm/mediabay.h | |||
@@ -17,26 +17,31 @@ | |||
17 | #define MB_POWER 6 /* media bay contains a Power device (???) */ | 17 | #define MB_POWER 6 /* media bay contains a Power device (???) */ |
18 | #define MB_NO 7 /* media bay contains nothing */ | 18 | #define MB_NO 7 /* media bay contains nothing */ |
19 | 19 | ||
20 | /* Number of bays in the machine or 0 */ | 20 | struct macio_dev; |
21 | extern int media_bay_count; | ||
22 | 21 | ||
23 | #ifdef CONFIG_BLK_DEV_IDE_PMAC | 22 | #ifdef CONFIG_PMAC_MEDIABAY |
24 | #include <linux/ide.h> | ||
25 | 23 | ||
26 | int check_media_bay_by_base(unsigned long base, int what); | 24 | /* Check the content type of the bay, returns MB_NO if the bay is still |
27 | /* called by IDE PMAC host driver to register IDE controller for media bay */ | 25 | * transitionning |
28 | int media_bay_set_ide_infos(struct device_node *which_bay, unsigned long base, | 26 | */ |
29 | int irq, ide_hwif_t *hwif); | 27 | extern int check_media_bay(struct macio_dev *bay); |
30 | 28 | ||
31 | int check_media_bay(struct device_node *which_bay, int what); | 29 | /* The ATA driver uses the calls below to temporarily hold on the |
30 | * media bay callbacks while initializing the interface | ||
31 | */ | ||
32 | extern void lock_media_bay(struct macio_dev *bay); | ||
33 | extern void unlock_media_bay(struct macio_dev *bay); | ||
32 | 34 | ||
33 | #else | 35 | #else |
34 | 36 | ||
35 | static inline int check_media_bay(struct device_node *which_bay, int what) | 37 | static inline int check_media_bay(struct macio_dev *bay) |
36 | { | 38 | { |
37 | return -ENODEV; | 39 | return MB_NO; |
38 | } | 40 | } |
39 | 41 | ||
42 | static inline void lock_media_bay(struct macio_dev *bay) { } | ||
43 | static inline void unlock_media_bay(struct macio_dev *bay) { } | ||
44 | |||
40 | #endif | 45 | #endif |
41 | 46 | ||
42 | #endif /* __KERNEL__ */ | 47 | #endif /* __KERNEL__ */ |
diff --git a/arch/powerpc/include/asm/mmu-hash64.h b/arch/powerpc/include/asm/mmu-hash64.h index bebe31c2e907..2102b214a87c 100644 --- a/arch/powerpc/include/asm/mmu-hash64.h +++ b/arch/powerpc/include/asm/mmu-hash64.h | |||
@@ -173,14 +173,6 @@ extern unsigned long tce_alloc_start, tce_alloc_end; | |||
173 | */ | 173 | */ |
174 | extern int mmu_ci_restrictions; | 174 | extern int mmu_ci_restrictions; |
175 | 175 | ||
176 | #ifdef CONFIG_HUGETLB_PAGE | ||
177 | /* | ||
178 | * The page size indexes of the huge pages for use by hugetlbfs | ||
179 | */ | ||
180 | extern unsigned int mmu_huge_psizes[MMU_PAGE_COUNT]; | ||
181 | |||
182 | #endif /* CONFIG_HUGETLB_PAGE */ | ||
183 | |||
184 | /* | 176 | /* |
185 | * This function sets the AVPN and L fields of the HPTE appropriately | 177 | * This function sets the AVPN and L fields of the HPTE appropriately |
186 | * for the page size | 178 | * for the page size |
@@ -253,10 +245,11 @@ extern int __hash_page_64K(unsigned long ea, unsigned long access, | |||
253 | unsigned long vsid, pte_t *ptep, unsigned long trap, | 245 | unsigned long vsid, pte_t *ptep, unsigned long trap, |
254 | unsigned int local, int ssize); | 246 | unsigned int local, int ssize); |
255 | struct mm_struct; | 247 | struct mm_struct; |
248 | unsigned int hash_page_do_lazy_icache(unsigned int pp, pte_t pte, int trap); | ||
256 | extern int hash_page(unsigned long ea, unsigned long access, unsigned long trap); | 249 | extern int hash_page(unsigned long ea, unsigned long access, unsigned long trap); |
257 | extern int hash_huge_page(struct mm_struct *mm, unsigned long access, | 250 | int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid, |
258 | unsigned long ea, unsigned long vsid, int local, | 251 | pte_t *ptep, unsigned long trap, int local, int ssize, |
259 | unsigned long trap); | 252 | unsigned int shift, unsigned int mmu_psize); |
260 | 253 | ||
261 | extern int htab_bolt_mapping(unsigned long vstart, unsigned long vend, | 254 | extern int htab_bolt_mapping(unsigned long vstart, unsigned long vend, |
262 | unsigned long pstart, unsigned long prot, | 255 | unsigned long pstart, unsigned long prot, |
@@ -380,6 +373,38 @@ extern void slb_set_size(u16 size); | |||
380 | 373 | ||
381 | #ifndef __ASSEMBLY__ | 374 | #ifndef __ASSEMBLY__ |
382 | 375 | ||
376 | #ifdef CONFIG_PPC_SUBPAGE_PROT | ||
377 | /* | ||
378 | * For the sub-page protection option, we extend the PGD with one of | ||
379 | * these. Basically we have a 3-level tree, with the top level being | ||
380 | * the protptrs array. To optimize speed and memory consumption when | ||
381 | * only addresses < 4GB are being protected, pointers to the first | ||
382 | * four pages of sub-page protection words are stored in the low_prot | ||
383 | * array. | ||
384 | * Each page of sub-page protection words protects 1GB (4 bytes | ||
385 | * protects 64k). For the 3-level tree, each page of pointers then | ||
386 | * protects 8TB. | ||
387 | */ | ||
388 | struct subpage_prot_table { | ||
389 | unsigned long maxaddr; /* only addresses < this are protected */ | ||
390 | unsigned int **protptrs[2]; | ||
391 | unsigned int *low_prot[4]; | ||
392 | }; | ||
393 | |||
394 | #define SBP_L1_BITS (PAGE_SHIFT - 2) | ||
395 | #define SBP_L2_BITS (PAGE_SHIFT - 3) | ||
396 | #define SBP_L1_COUNT (1 << SBP_L1_BITS) | ||
397 | #define SBP_L2_COUNT (1 << SBP_L2_BITS) | ||
398 | #define SBP_L2_SHIFT (PAGE_SHIFT + SBP_L1_BITS) | ||
399 | #define SBP_L3_SHIFT (SBP_L2_SHIFT + SBP_L2_BITS) | ||
400 | |||
401 | extern void subpage_prot_free(struct mm_struct *mm); | ||
402 | extern void subpage_prot_init_new_context(struct mm_struct *mm); | ||
403 | #else | ||
404 | static inline void subpage_prot_free(struct mm_struct *mm) {} | ||
405 | static inline void subpage_prot_init_new_context(struct mm_struct *mm) { } | ||
406 | #endif /* CONFIG_PPC_SUBPAGE_PROT */ | ||
407 | |||
383 | typedef unsigned long mm_context_id_t; | 408 | typedef unsigned long mm_context_id_t; |
384 | 409 | ||
385 | typedef struct { | 410 | typedef struct { |
@@ -393,6 +418,9 @@ typedef struct { | |||
393 | u16 sllp; /* SLB page size encoding */ | 418 | u16 sllp; /* SLB page size encoding */ |
394 | #endif | 419 | #endif |
395 | unsigned long vdso_base; | 420 | unsigned long vdso_base; |
421 | #ifdef CONFIG_PPC_SUBPAGE_PROT | ||
422 | struct subpage_prot_table spt; | ||
423 | #endif /* CONFIG_PPC_SUBPAGE_PROT */ | ||
396 | } mm_context_t; | 424 | } mm_context_t; |
397 | 425 | ||
398 | 426 | ||
diff --git a/arch/powerpc/include/asm/mmu_context.h b/arch/powerpc/include/asm/mmu_context.h index b34e94d94435..26383e0778aa 100644 --- a/arch/powerpc/include/asm/mmu_context.h +++ b/arch/powerpc/include/asm/mmu_context.h | |||
@@ -23,6 +23,8 @@ extern void switch_slb(struct task_struct *tsk, struct mm_struct *mm); | |||
23 | extern void set_context(unsigned long id, pgd_t *pgd); | 23 | extern void set_context(unsigned long id, pgd_t *pgd); |
24 | 24 | ||
25 | #ifdef CONFIG_PPC_BOOK3S_64 | 25 | #ifdef CONFIG_PPC_BOOK3S_64 |
26 | extern int __init_new_context(void); | ||
27 | extern void __destroy_context(int context_id); | ||
26 | static inline void mmu_context_init(void) { } | 28 | static inline void mmu_context_init(void) { } |
27 | #else | 29 | #else |
28 | extern void mmu_context_init(void); | 30 | extern void mmu_context_init(void); |
diff --git a/arch/powerpc/include/asm/mpc52xx.h b/arch/powerpc/include/asm/mpc52xx.h index 1b4f697abbdd..b664ce79a172 100644 --- a/arch/powerpc/include/asm/mpc52xx.h +++ b/arch/powerpc/include/asm/mpc52xx.h | |||
@@ -276,6 +276,53 @@ extern int mpc52xx_set_psc_clkdiv(int psc_id, int clkdiv); | |||
276 | extern unsigned int mpc52xx_get_xtal_freq(struct device_node *node); | 276 | extern unsigned int mpc52xx_get_xtal_freq(struct device_node *node); |
277 | extern void mpc52xx_restart(char *cmd); | 277 | extern void mpc52xx_restart(char *cmd); |
278 | 278 | ||
279 | /* mpc52xx_gpt.c */ | ||
280 | struct mpc52xx_gpt_priv; | ||
281 | extern struct mpc52xx_gpt_priv *mpc52xx_gpt_from_irq(int irq); | ||
282 | extern int mpc52xx_gpt_start_timer(struct mpc52xx_gpt_priv *gpt, u64 period, | ||
283 | int continuous); | ||
284 | extern u64 mpc52xx_gpt_timer_period(struct mpc52xx_gpt_priv *gpt); | ||
285 | extern int mpc52xx_gpt_stop_timer(struct mpc52xx_gpt_priv *gpt); | ||
286 | |||
287 | /* mpc52xx_lpbfifo.c */ | ||
288 | #define MPC52XX_LPBFIFO_FLAG_READ (0) | ||
289 | #define MPC52XX_LPBFIFO_FLAG_WRITE (1<<0) | ||
290 | #define MPC52XX_LPBFIFO_FLAG_NO_INCREMENT (1<<1) | ||
291 | #define MPC52XX_LPBFIFO_FLAG_NO_DMA (1<<2) | ||
292 | #define MPC52XX_LPBFIFO_FLAG_POLL_DMA (1<<3) | ||
293 | |||
294 | struct mpc52xx_lpbfifo_request { | ||
295 | struct list_head list; | ||
296 | |||
297 | /* localplus bus address */ | ||
298 | unsigned int cs; | ||
299 | size_t offset; | ||
300 | |||
301 | /* Memory address */ | ||
302 | void *data; | ||
303 | phys_addr_t data_phys; | ||
304 | |||
305 | /* Details of transfer */ | ||
306 | size_t size; | ||
307 | size_t pos; /* current position of transfer */ | ||
308 | int flags; | ||
309 | |||
310 | /* What to do when finished */ | ||
311 | void (*callback)(struct mpc52xx_lpbfifo_request *); | ||
312 | |||
313 | void *priv; /* Driver private data */ | ||
314 | |||
315 | /* statistics */ | ||
316 | int irq_count; | ||
317 | int irq_ticks; | ||
318 | u8 last_byte; | ||
319 | int buffer_not_done_cnt; | ||
320 | }; | ||
321 | |||
322 | extern int mpc52xx_lpbfifo_submit(struct mpc52xx_lpbfifo_request *req); | ||
323 | extern void mpc52xx_lpbfifo_abort(struct mpc52xx_lpbfifo_request *req); | ||
324 | extern void mpc52xx_lpbfifo_poll(void); | ||
325 | |||
279 | /* mpc52xx_pic.c */ | 326 | /* mpc52xx_pic.c */ |
280 | extern void mpc52xx_init_irq(void); | 327 | extern void mpc52xx_init_irq(void); |
281 | extern unsigned int mpc52xx_get_irq(void); | 328 | extern unsigned int mpc52xx_get_irq(void); |
diff --git a/arch/powerpc/include/asm/nvram.h b/arch/powerpc/include/asm/nvram.h index 6c587eddee59..850b72f27445 100644 --- a/arch/powerpc/include/asm/nvram.h +++ b/arch/powerpc/include/asm/nvram.h | |||
@@ -73,7 +73,6 @@ extern int nvram_write_error_log(char * buff, int length, | |||
73 | extern int nvram_read_error_log(char * buff, int length, | 73 | extern int nvram_read_error_log(char * buff, int length, |
74 | unsigned int * err_type, unsigned int *err_seq); | 74 | unsigned int * err_type, unsigned int *err_seq); |
75 | extern int nvram_clear_error_log(void); | 75 | extern int nvram_clear_error_log(void); |
76 | extern struct nvram_partition *nvram_find_partition(int sig, const char *name); | ||
77 | 76 | ||
78 | extern int pSeries_nvram_init(void); | 77 | extern int pSeries_nvram_init(void); |
79 | 78 | ||
diff --git a/arch/powerpc/include/asm/pSeries_reconfig.h b/arch/powerpc/include/asm/pSeries_reconfig.h index e482e5352e69..d4b4bfa26fb3 100644 --- a/arch/powerpc/include/asm/pSeries_reconfig.h +++ b/arch/powerpc/include/asm/pSeries_reconfig.h | |||
@@ -17,6 +17,7 @@ | |||
17 | #ifdef CONFIG_PPC_PSERIES | 17 | #ifdef CONFIG_PPC_PSERIES |
18 | extern int pSeries_reconfig_notifier_register(struct notifier_block *); | 18 | extern int pSeries_reconfig_notifier_register(struct notifier_block *); |
19 | extern void pSeries_reconfig_notifier_unregister(struct notifier_block *); | 19 | extern void pSeries_reconfig_notifier_unregister(struct notifier_block *); |
20 | extern struct blocking_notifier_head pSeries_reconfig_chain; | ||
20 | #else /* !CONFIG_PPC_PSERIES */ | 21 | #else /* !CONFIG_PPC_PSERIES */ |
21 | static inline int pSeries_reconfig_notifier_register(struct notifier_block *nb) | 22 | static inline int pSeries_reconfig_notifier_register(struct notifier_block *nb) |
22 | { | 23 | { |
diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h index 7d8514ceceae..5e9b4ef71415 100644 --- a/arch/powerpc/include/asm/paca.h +++ b/arch/powerpc/include/asm/paca.h | |||
@@ -129,6 +129,15 @@ struct paca_struct { | |||
129 | u64 system_time; /* accumulated system TB ticks */ | 129 | u64 system_time; /* accumulated system TB ticks */ |
130 | u64 startpurr; /* PURR/TB value snapshot */ | 130 | u64 startpurr; /* PURR/TB value snapshot */ |
131 | u64 startspurr; /* SPURR value snapshot */ | 131 | u64 startspurr; /* SPURR value snapshot */ |
132 | |||
133 | #ifdef CONFIG_KVM_BOOK3S_64_HANDLER | ||
134 | struct { | ||
135 | u64 esid; | ||
136 | u64 vsid; | ||
137 | } kvm_slb[64]; /* guest SLB */ | ||
138 | u8 kvm_slb_max; /* highest used guest slb entry */ | ||
139 | u8 kvm_in_guest; /* are we inside the guest? */ | ||
140 | #endif | ||
132 | }; | 141 | }; |
133 | 142 | ||
134 | extern struct paca_struct paca[]; | 143 | extern struct paca_struct paca[]; |
diff --git a/arch/powerpc/include/asm/page.h b/arch/powerpc/include/asm/page.h index ff24254990e1..e96d52a516ba 100644 --- a/arch/powerpc/include/asm/page.h +++ b/arch/powerpc/include/asm/page.h | |||
@@ -229,6 +229,20 @@ typedef unsigned long pgprot_t; | |||
229 | 229 | ||
230 | #endif | 230 | #endif |
231 | 231 | ||
232 | typedef struct { signed long pd; } hugepd_t; | ||
233 | #define HUGEPD_SHIFT_MASK 0x3f | ||
234 | |||
235 | #ifdef CONFIG_HUGETLB_PAGE | ||
236 | static inline int hugepd_ok(hugepd_t hpd) | ||
237 | { | ||
238 | return (hpd.pd > 0); | ||
239 | } | ||
240 | |||
241 | #define is_hugepd(pdep) (hugepd_ok(*((hugepd_t *)(pdep)))) | ||
242 | #else /* CONFIG_HUGETLB_PAGE */ | ||
243 | #define is_hugepd(pdep) 0 | ||
244 | #endif /* CONFIG_HUGETLB_PAGE */ | ||
245 | |||
232 | struct page; | 246 | struct page; |
233 | extern void clear_user_page(void *page, unsigned long vaddr, struct page *pg); | 247 | extern void clear_user_page(void *page, unsigned long vaddr, struct page *pg); |
234 | extern void copy_user_page(void *to, void *from, unsigned long vaddr, | 248 | extern void copy_user_page(void *to, void *from, unsigned long vaddr, |
diff --git a/arch/powerpc/include/asm/page_64.h b/arch/powerpc/include/asm/page_64.h index 3f17b83f55a1..bfc4e027e2ad 100644 --- a/arch/powerpc/include/asm/page_64.h +++ b/arch/powerpc/include/asm/page_64.h | |||
@@ -90,7 +90,7 @@ extern unsigned int HPAGE_SHIFT; | |||
90 | #define HPAGE_SIZE ((1UL) << HPAGE_SHIFT) | 90 | #define HPAGE_SIZE ((1UL) << HPAGE_SHIFT) |
91 | #define HPAGE_MASK (~(HPAGE_SIZE - 1)) | 91 | #define HPAGE_MASK (~(HPAGE_SIZE - 1)) |
92 | #define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT) | 92 | #define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT) |
93 | #define HUGE_MAX_HSTATE 3 | 93 | #define HUGE_MAX_HSTATE (MMU_PAGE_COUNT-1) |
94 | 94 | ||
95 | #endif /* __ASSEMBLY__ */ | 95 | #endif /* __ASSEMBLY__ */ |
96 | 96 | ||
diff --git a/arch/powerpc/include/asm/pgalloc-32.h b/arch/powerpc/include/asm/pgalloc-32.h index c9500d666a1d..580cf73b96e8 100644 --- a/arch/powerpc/include/asm/pgalloc-32.h +++ b/arch/powerpc/include/asm/pgalloc-32.h | |||
@@ -3,7 +3,8 @@ | |||
3 | 3 | ||
4 | #include <linux/threads.h> | 4 | #include <linux/threads.h> |
5 | 5 | ||
6 | #define PTE_NONCACHE_NUM 0 /* dummy for now to share code w/ppc64 */ | 6 | /* For 32-bit, all levels of page tables are just drawn from get_free_page() */ |
7 | #define MAX_PGTABLE_INDEX_SIZE 0 | ||
7 | 8 | ||
8 | extern void __bad_pte(pmd_t *pmd); | 9 | extern void __bad_pte(pmd_t *pmd); |
9 | 10 | ||
@@ -36,11 +37,10 @@ extern void pgd_free(struct mm_struct *mm, pgd_t *pgd); | |||
36 | extern pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr); | 37 | extern pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr); |
37 | extern pgtable_t pte_alloc_one(struct mm_struct *mm, unsigned long addr); | 38 | extern pgtable_t pte_alloc_one(struct mm_struct *mm, unsigned long addr); |
38 | 39 | ||
39 | static inline void pgtable_free(pgtable_free_t pgf) | 40 | static inline void pgtable_free(void *table, unsigned index_size) |
40 | { | 41 | { |
41 | void *p = (void *)(pgf.val & ~PGF_CACHENUM_MASK); | 42 | BUG_ON(index_size); /* 32-bit doesn't use this */ |
42 | 43 | free_page((unsigned long)table); | |
43 | free_page((unsigned long)p); | ||
44 | } | 44 | } |
45 | 45 | ||
46 | #define check_pgt_cache() do { } while (0) | 46 | #define check_pgt_cache() do { } while (0) |
diff --git a/arch/powerpc/include/asm/pgalloc-64.h b/arch/powerpc/include/asm/pgalloc-64.h index e6f069c4f713..605f5c5398d1 100644 --- a/arch/powerpc/include/asm/pgalloc-64.h +++ b/arch/powerpc/include/asm/pgalloc-64.h | |||
@@ -11,27 +11,34 @@ | |||
11 | #include <linux/cpumask.h> | 11 | #include <linux/cpumask.h> |
12 | #include <linux/percpu.h> | 12 | #include <linux/percpu.h> |
13 | 13 | ||
14 | #ifndef CONFIG_PPC_SUBPAGE_PROT | 14 | /* |
15 | static inline void subpage_prot_free(pgd_t *pgd) {} | 15 | * Functions that deal with pagetables that could be at any level of |
16 | #endif | 16 | * the table need to be passed an "index_size" so they know how to |
17 | * handle allocation. For PTE pages (which are linked to a struct | ||
18 | * page for now, and drawn from the main get_free_pages() pool), the | ||
19 | * allocation size will be (2^index_size * sizeof(pointer)) and | ||
20 | * allocations are drawn from the kmem_cache in PGT_CACHE(index_size). | ||
21 | * | ||
22 | * The maximum index size needs to be big enough to allow any | ||
23 | * pagetable sizes we need, but small enough to fit in the low bits of | ||
24 | * any page table pointer. In other words all pagetables, even tiny | ||
25 | * ones, must be aligned to allow at least enough low 0 bits to | ||
26 | * contain this value. This value is also used as a mask, so it must | ||
27 | * be one less than a power of two. | ||
28 | */ | ||
29 | #define MAX_PGTABLE_INDEX_SIZE 0xf | ||
17 | 30 | ||
18 | extern struct kmem_cache *pgtable_cache[]; | 31 | extern struct kmem_cache *pgtable_cache[]; |
19 | 32 | #define PGT_CACHE(shift) (pgtable_cache[(shift)-1]) | |
20 | #define PGD_CACHE_NUM 0 | ||
21 | #define PUD_CACHE_NUM 1 | ||
22 | #define PMD_CACHE_NUM 1 | ||
23 | #define HUGEPTE_CACHE_NUM 2 | ||
24 | #define PTE_NONCACHE_NUM 7 /* from GFP rather than kmem_cache */ | ||
25 | 33 | ||
26 | static inline pgd_t *pgd_alloc(struct mm_struct *mm) | 34 | static inline pgd_t *pgd_alloc(struct mm_struct *mm) |
27 | { | 35 | { |
28 | return kmem_cache_alloc(pgtable_cache[PGD_CACHE_NUM], GFP_KERNEL); | 36 | return kmem_cache_alloc(PGT_CACHE(PGD_INDEX_SIZE), GFP_KERNEL); |
29 | } | 37 | } |
30 | 38 | ||
31 | static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd) | 39 | static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd) |
32 | { | 40 | { |
33 | subpage_prot_free(pgd); | 41 | kmem_cache_free(PGT_CACHE(PGD_INDEX_SIZE), pgd); |
34 | kmem_cache_free(pgtable_cache[PGD_CACHE_NUM], pgd); | ||
35 | } | 42 | } |
36 | 43 | ||
37 | #ifndef CONFIG_PPC_64K_PAGES | 44 | #ifndef CONFIG_PPC_64K_PAGES |
@@ -40,13 +47,13 @@ static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd) | |||
40 | 47 | ||
41 | static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr) | 48 | static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr) |
42 | { | 49 | { |
43 | return kmem_cache_alloc(pgtable_cache[PUD_CACHE_NUM], | 50 | return kmem_cache_alloc(PGT_CACHE(PUD_INDEX_SIZE), |
44 | GFP_KERNEL|__GFP_REPEAT); | 51 | GFP_KERNEL|__GFP_REPEAT); |
45 | } | 52 | } |
46 | 53 | ||
47 | static inline void pud_free(struct mm_struct *mm, pud_t *pud) | 54 | static inline void pud_free(struct mm_struct *mm, pud_t *pud) |
48 | { | 55 | { |
49 | kmem_cache_free(pgtable_cache[PUD_CACHE_NUM], pud); | 56 | kmem_cache_free(PGT_CACHE(PUD_INDEX_SIZE), pud); |
50 | } | 57 | } |
51 | 58 | ||
52 | static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) | 59 | static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd) |
@@ -78,13 +85,13 @@ static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, | |||
78 | 85 | ||
79 | static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr) | 86 | static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr) |
80 | { | 87 | { |
81 | return kmem_cache_alloc(pgtable_cache[PMD_CACHE_NUM], | 88 | return kmem_cache_alloc(PGT_CACHE(PMD_INDEX_SIZE), |
82 | GFP_KERNEL|__GFP_REPEAT); | 89 | GFP_KERNEL|__GFP_REPEAT); |
83 | } | 90 | } |
84 | 91 | ||
85 | static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd) | 92 | static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd) |
86 | { | 93 | { |
87 | kmem_cache_free(pgtable_cache[PMD_CACHE_NUM], pmd); | 94 | kmem_cache_free(PGT_CACHE(PMD_INDEX_SIZE), pmd); |
88 | } | 95 | } |
89 | 96 | ||
90 | static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, | 97 | static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, |
@@ -107,24 +114,22 @@ static inline pgtable_t pte_alloc_one(struct mm_struct *mm, | |||
107 | return page; | 114 | return page; |
108 | } | 115 | } |
109 | 116 | ||
110 | static inline void pgtable_free(pgtable_free_t pgf) | 117 | static inline void pgtable_free(void *table, unsigned index_size) |
111 | { | 118 | { |
112 | void *p = (void *)(pgf.val & ~PGF_CACHENUM_MASK); | 119 | if (!index_size) |
113 | int cachenum = pgf.val & PGF_CACHENUM_MASK; | 120 | free_page((unsigned long)table); |
114 | 121 | else { | |
115 | if (cachenum == PTE_NONCACHE_NUM) | 122 | BUG_ON(index_size > MAX_PGTABLE_INDEX_SIZE); |
116 | free_page((unsigned long)p); | 123 | kmem_cache_free(PGT_CACHE(index_size), table); |
117 | else | 124 | } |
118 | kmem_cache_free(pgtable_cache[cachenum], p); | ||
119 | } | 125 | } |
120 | 126 | ||
121 | #define __pmd_free_tlb(tlb, pmd,addr) \ | 127 | #define __pmd_free_tlb(tlb, pmd, addr) \ |
122 | pgtable_free_tlb(tlb, pgtable_free_cache(pmd, \ | 128 | pgtable_free_tlb(tlb, pmd, PMD_INDEX_SIZE) |
123 | PMD_CACHE_NUM, PMD_TABLE_SIZE-1)) | ||
124 | #ifndef CONFIG_PPC_64K_PAGES | 129 | #ifndef CONFIG_PPC_64K_PAGES |
125 | #define __pud_free_tlb(tlb, pud, addr) \ | 130 | #define __pud_free_tlb(tlb, pud, addr) \ |
126 | pgtable_free_tlb(tlb, pgtable_free_cache(pud, \ | 131 | pgtable_free_tlb(tlb, pud, PUD_INDEX_SIZE) |
127 | PUD_CACHE_NUM, PUD_TABLE_SIZE-1)) | 132 | |
128 | #endif /* CONFIG_PPC_64K_PAGES */ | 133 | #endif /* CONFIG_PPC_64K_PAGES */ |
129 | 134 | ||
130 | #define check_pgt_cache() do { } while (0) | 135 | #define check_pgt_cache() do { } while (0) |
diff --git a/arch/powerpc/include/asm/pgalloc.h b/arch/powerpc/include/asm/pgalloc.h index f2e812de7c3c..abe8532bd14e 100644 --- a/arch/powerpc/include/asm/pgalloc.h +++ b/arch/powerpc/include/asm/pgalloc.h | |||
@@ -24,25 +24,6 @@ static inline void pte_free(struct mm_struct *mm, pgtable_t ptepage) | |||
24 | __free_page(ptepage); | 24 | __free_page(ptepage); |
25 | } | 25 | } |
26 | 26 | ||
27 | typedef struct pgtable_free { | ||
28 | unsigned long val; | ||
29 | } pgtable_free_t; | ||
30 | |||
31 | /* This needs to be big enough to allow for MMU_PAGE_COUNT + 2 to be stored | ||
32 | * and small enough to fit in the low bits of any naturally aligned page | ||
33 | * table cache entry. Arbitrarily set to 0x1f, that should give us some | ||
34 | * room to grow | ||
35 | */ | ||
36 | #define PGF_CACHENUM_MASK 0x1f | ||
37 | |||
38 | static inline pgtable_free_t pgtable_free_cache(void *p, int cachenum, | ||
39 | unsigned long mask) | ||
40 | { | ||
41 | BUG_ON(cachenum > PGF_CACHENUM_MASK); | ||
42 | |||
43 | return (pgtable_free_t){.val = ((unsigned long) p & ~mask) | cachenum}; | ||
44 | } | ||
45 | |||
46 | #ifdef CONFIG_PPC64 | 27 | #ifdef CONFIG_PPC64 |
47 | #include <asm/pgalloc-64.h> | 28 | #include <asm/pgalloc-64.h> |
48 | #else | 29 | #else |
@@ -50,12 +31,12 @@ static inline pgtable_free_t pgtable_free_cache(void *p, int cachenum, | |||
50 | #endif | 31 | #endif |
51 | 32 | ||
52 | #ifdef CONFIG_SMP | 33 | #ifdef CONFIG_SMP |
53 | extern void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf); | 34 | extern void pgtable_free_tlb(struct mmu_gather *tlb, void *table, unsigned shift); |
54 | extern void pte_free_finish(void); | 35 | extern void pte_free_finish(void); |
55 | #else /* CONFIG_SMP */ | 36 | #else /* CONFIG_SMP */ |
56 | static inline void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf) | 37 | static inline void pgtable_free_tlb(struct mmu_gather *tlb, void *table, unsigned shift) |
57 | { | 38 | { |
58 | pgtable_free(pgf); | 39 | pgtable_free(table, shift); |
59 | } | 40 | } |
60 | static inline void pte_free_finish(void) { } | 41 | static inline void pte_free_finish(void) { } |
61 | #endif /* !CONFIG_SMP */ | 42 | #endif /* !CONFIG_SMP */ |
@@ -63,12 +44,9 @@ static inline void pte_free_finish(void) { } | |||
63 | static inline void __pte_free_tlb(struct mmu_gather *tlb, struct page *ptepage, | 44 | static inline void __pte_free_tlb(struct mmu_gather *tlb, struct page *ptepage, |
64 | unsigned long address) | 45 | unsigned long address) |
65 | { | 46 | { |
66 | pgtable_free_t pgf = pgtable_free_cache(page_address(ptepage), | ||
67 | PTE_NONCACHE_NUM, | ||
68 | PTE_TABLE_SIZE-1); | ||
69 | tlb_flush_pgtable(tlb, address); | 47 | tlb_flush_pgtable(tlb, address); |
70 | pgtable_page_dtor(ptepage); | 48 | pgtable_page_dtor(ptepage); |
71 | pgtable_free_tlb(tlb, pgf); | 49 | pgtable_free_tlb(tlb, page_address(ptepage), 0); |
72 | } | 50 | } |
73 | 51 | ||
74 | #endif /* __KERNEL__ */ | 52 | #endif /* __KERNEL__ */ |
diff --git a/arch/powerpc/include/asm/pgtable-ppc64.h b/arch/powerpc/include/asm/pgtable-ppc64.h index 806abe7a3fa5..49865045d56f 100644 --- a/arch/powerpc/include/asm/pgtable-ppc64.h +++ b/arch/powerpc/include/asm/pgtable-ppc64.h | |||
@@ -354,6 +354,7 @@ static inline void __ptep_set_access_flags(pte_t *ptep, pte_t entry) | |||
354 | #define pgoff_to_pte(off) ((pte_t) {((off) << PTE_RPN_SHIFT)|_PAGE_FILE}) | 354 | #define pgoff_to_pte(off) ((pte_t) {((off) << PTE_RPN_SHIFT)|_PAGE_FILE}) |
355 | #define PTE_FILE_MAX_BITS (BITS_PER_LONG - PTE_RPN_SHIFT) | 355 | #define PTE_FILE_MAX_BITS (BITS_PER_LONG - PTE_RPN_SHIFT) |
356 | 356 | ||
357 | void pgtable_cache_add(unsigned shift, void (*ctor)(void *)); | ||
357 | void pgtable_cache_init(void); | 358 | void pgtable_cache_init(void); |
358 | 359 | ||
359 | /* | 360 | /* |
@@ -378,7 +379,18 @@ void pgtable_cache_init(void); | |||
378 | return pt; | 379 | return pt; |
379 | } | 380 | } |
380 | 381 | ||
381 | pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long address); | 382 | #ifdef CONFIG_HUGETLB_PAGE |
383 | pte_t *find_linux_pte_or_hugepte(pgd_t *pgdir, unsigned long ea, | ||
384 | unsigned *shift); | ||
385 | #else | ||
386 | static inline pte_t *find_linux_pte_or_hugepte(pgd_t *pgdir, unsigned long ea, | ||
387 | unsigned *shift) | ||
388 | { | ||
389 | if (shift) | ||
390 | *shift = 0; | ||
391 | return find_linux_pte(pgdir, ea); | ||
392 | } | ||
393 | #endif /* !CONFIG_HUGETLB_PAGE */ | ||
382 | 394 | ||
383 | #endif /* __ASSEMBLY__ */ | 395 | #endif /* __ASSEMBLY__ */ |
384 | 396 | ||
diff --git a/arch/powerpc/include/asm/pgtable.h b/arch/powerpc/include/asm/pgtable.h index 2a5da069714e..21207e54825b 100644 --- a/arch/powerpc/include/asm/pgtable.h +++ b/arch/powerpc/include/asm/pgtable.h | |||
@@ -211,6 +211,9 @@ extern void paging_init(void); | |||
211 | */ | 211 | */ |
212 | extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t); | 212 | extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t); |
213 | 213 | ||
214 | extern int gup_hugepd(hugepd_t *hugepd, unsigned pdshift, unsigned long addr, | ||
215 | unsigned long end, int write, struct page **pages, int *nr); | ||
216 | |||
214 | #endif /* __ASSEMBLY__ */ | 217 | #endif /* __ASSEMBLY__ */ |
215 | 218 | ||
216 | #endif /* __KERNEL__ */ | 219 | #endif /* __KERNEL__ */ |
diff --git a/arch/powerpc/include/asm/pte-8xx.h b/arch/powerpc/include/asm/pte-8xx.h index dd5ea95fe61e..d44826e4ff97 100644 --- a/arch/powerpc/include/asm/pte-8xx.h +++ b/arch/powerpc/include/asm/pte-8xx.h | |||
@@ -33,21 +33,21 @@ | |||
33 | #define _PAGE_NO_CACHE 0x0002 /* I: cache inhibit */ | 33 | #define _PAGE_NO_CACHE 0x0002 /* I: cache inhibit */ |
34 | #define _PAGE_SHARED 0x0004 /* No ASID (context) compare */ | 34 | #define _PAGE_SHARED 0x0004 /* No ASID (context) compare */ |
35 | #define _PAGE_SPECIAL 0x0008 /* SW entry, forced to 0 by the TLB miss */ | 35 | #define _PAGE_SPECIAL 0x0008 /* SW entry, forced to 0 by the TLB miss */ |
36 | #define _PAGE_DIRTY 0x0100 /* C: page changed */ | ||
36 | 37 | ||
37 | /* These five software bits must be masked out when the entry is loaded | 38 | /* These 4 software bits must be masked out when the entry is loaded |
38 | * into the TLB. | 39 | * into the TLB, 1 SW bit left(0x0080). |
39 | */ | 40 | */ |
40 | #define _PAGE_GUARDED 0x0010 /* software: guarded access */ | 41 | #define _PAGE_GUARDED 0x0010 /* software: guarded access */ |
41 | #define _PAGE_DIRTY 0x0020 /* software: page changed */ | 42 | #define _PAGE_ACCESSED 0x0020 /* software: page referenced */ |
42 | #define _PAGE_RW 0x0040 /* software: user write access allowed */ | 43 | #define _PAGE_WRITETHRU 0x0040 /* software: caching is write through */ |
43 | #define _PAGE_ACCESSED 0x0080 /* software: page referenced */ | ||
44 | 44 | ||
45 | /* Setting any bits in the nibble with the follow two controls will | 45 | /* Setting any bits in the nibble with the follow two controls will |
46 | * require a TLB exception handler change. It is assumed unused bits | 46 | * require a TLB exception handler change. It is assumed unused bits |
47 | * are always zero. | 47 | * are always zero. |
48 | */ | 48 | */ |
49 | #define _PAGE_HWWRITE 0x0100 /* h/w write enable: never set in Linux PTE */ | 49 | #define _PAGE_RW 0x0400 /* lsb PP bits, inverted in HW */ |
50 | #define _PAGE_USER 0x0800 /* One of the PP bits, the other is USER&~RW */ | 50 | #define _PAGE_USER 0x0800 /* msb PP bits */ |
51 | 51 | ||
52 | #define _PMD_PRESENT 0x0001 | 52 | #define _PMD_PRESENT 0x0001 |
53 | #define _PMD_BAD 0x0ff0 | 53 | #define _PMD_BAD 0x0ff0 |
diff --git a/arch/powerpc/include/asm/pte-hash64-64k.h b/arch/powerpc/include/asm/pte-hash64-64k.h index 82b72207c51c..c4490f9c67c4 100644 --- a/arch/powerpc/include/asm/pte-hash64-64k.h +++ b/arch/powerpc/include/asm/pte-hash64-64k.h | |||
@@ -76,41 +76,4 @@ | |||
76 | remap_pfn_range((vma), (addr), (pfn), PAGE_SIZE, \ | 76 | remap_pfn_range((vma), (addr), (pfn), PAGE_SIZE, \ |
77 | __pgprot(pgprot_val((prot)) | _PAGE_4K_PFN)) | 77 | __pgprot(pgprot_val((prot)) | _PAGE_4K_PFN)) |
78 | 78 | ||
79 | |||
80 | #ifdef CONFIG_PPC_SUBPAGE_PROT | ||
81 | /* | ||
82 | * For the sub-page protection option, we extend the PGD with one of | ||
83 | * these. Basically we have a 3-level tree, with the top level being | ||
84 | * the protptrs array. To optimize speed and memory consumption when | ||
85 | * only addresses < 4GB are being protected, pointers to the first | ||
86 | * four pages of sub-page protection words are stored in the low_prot | ||
87 | * array. | ||
88 | * Each page of sub-page protection words protects 1GB (4 bytes | ||
89 | * protects 64k). For the 3-level tree, each page of pointers then | ||
90 | * protects 8TB. | ||
91 | */ | ||
92 | struct subpage_prot_table { | ||
93 | unsigned long maxaddr; /* only addresses < this are protected */ | ||
94 | unsigned int **protptrs[2]; | ||
95 | unsigned int *low_prot[4]; | ||
96 | }; | ||
97 | |||
98 | #undef PGD_TABLE_SIZE | ||
99 | #define PGD_TABLE_SIZE ((sizeof(pgd_t) << PGD_INDEX_SIZE) + \ | ||
100 | sizeof(struct subpage_prot_table)) | ||
101 | |||
102 | #define SBP_L1_BITS (PAGE_SHIFT - 2) | ||
103 | #define SBP_L2_BITS (PAGE_SHIFT - 3) | ||
104 | #define SBP_L1_COUNT (1 << SBP_L1_BITS) | ||
105 | #define SBP_L2_COUNT (1 << SBP_L2_BITS) | ||
106 | #define SBP_L2_SHIFT (PAGE_SHIFT + SBP_L1_BITS) | ||
107 | #define SBP_L3_SHIFT (SBP_L2_SHIFT + SBP_L2_BITS) | ||
108 | |||
109 | extern void subpage_prot_free(pgd_t *pgd); | ||
110 | |||
111 | static inline struct subpage_prot_table *pgd_subpage_prot(pgd_t *pgd) | ||
112 | { | ||
113 | return (struct subpage_prot_table *)(pgd + PTRS_PER_PGD); | ||
114 | } | ||
115 | #endif /* CONFIG_PPC_SUBPAGE_PROT */ | ||
116 | #endif /* __ASSEMBLY__ */ | 79 | #endif /* __ASSEMBLY__ */ |
diff --git a/arch/powerpc/include/asm/qe.h b/arch/powerpc/include/asm/qe.h index f388f0ab193f..0947b36e534c 100644 --- a/arch/powerpc/include/asm/qe.h +++ b/arch/powerpc/include/asm/qe.h | |||
@@ -87,7 +87,7 @@ extern spinlock_t cmxgcr_lock; | |||
87 | 87 | ||
88 | /* Export QE common operations */ | 88 | /* Export QE common operations */ |
89 | #ifdef CONFIG_QUICC_ENGINE | 89 | #ifdef CONFIG_QUICC_ENGINE |
90 | extern void __init qe_reset(void); | 90 | extern void qe_reset(void); |
91 | #else | 91 | #else |
92 | static inline void qe_reset(void) {} | 92 | static inline void qe_reset(void) {} |
93 | #endif | 93 | #endif |
@@ -145,8 +145,17 @@ static inline void qe_pin_set_gpio(struct qe_pin *qe_pin) {} | |||
145 | static inline void qe_pin_set_dedicated(struct qe_pin *pin) {} | 145 | static inline void qe_pin_set_dedicated(struct qe_pin *pin) {} |
146 | #endif /* CONFIG_QE_GPIO */ | 146 | #endif /* CONFIG_QE_GPIO */ |
147 | 147 | ||
148 | /* QE internal API */ | 148 | #ifdef CONFIG_QUICC_ENGINE |
149 | int qe_issue_cmd(u32 cmd, u32 device, u8 mcn_protocol, u32 cmd_input); | 149 | int qe_issue_cmd(u32 cmd, u32 device, u8 mcn_protocol, u32 cmd_input); |
150 | #else | ||
151 | static inline int qe_issue_cmd(u32 cmd, u32 device, u8 mcn_protocol, | ||
152 | u32 cmd_input) | ||
153 | { | ||
154 | return -ENOSYS; | ||
155 | } | ||
156 | #endif /* CONFIG_QUICC_ENGINE */ | ||
157 | |||
158 | /* QE internal API */ | ||
150 | enum qe_clock qe_clock_source(const char *source); | 159 | enum qe_clock qe_clock_source(const char *source); |
151 | unsigned int qe_get_brg_clk(void); | 160 | unsigned int qe_get_brg_clk(void); |
152 | int qe_setbrg(enum qe_clock brg, unsigned int rate, unsigned int multiplier); | 161 | int qe_setbrg(enum qe_clock brg, unsigned int rate, unsigned int multiplier); |
@@ -154,7 +163,28 @@ int qe_get_snum(void); | |||
154 | void qe_put_snum(u8 snum); | 163 | void qe_put_snum(u8 snum); |
155 | unsigned int qe_get_num_of_risc(void); | 164 | unsigned int qe_get_num_of_risc(void); |
156 | unsigned int qe_get_num_of_snums(void); | 165 | unsigned int qe_get_num_of_snums(void); |
157 | int qe_alive_during_sleep(void); | 166 | |
167 | static inline int qe_alive_during_sleep(void) | ||
168 | { | ||
169 | /* | ||
170 | * MPC8568E reference manual says: | ||
171 | * | ||
172 | * "...power down sequence waits for all I/O interfaces to become idle. | ||
173 | * In some applications this may happen eventually without actively | ||
174 | * shutting down interfaces, but most likely, software will have to | ||
175 | * take steps to shut down the eTSEC, QUICC Engine Block, and PCI | ||
176 | * interfaces before issuing the command (either the write to the core | ||
177 | * MSR[WE] as described above or writing to POWMGTCSR) to put the | ||
178 | * device into sleep state." | ||
179 | * | ||
180 | * MPC8569E reference manual has a similar paragraph. | ||
181 | */ | ||
182 | #ifdef CONFIG_PPC_85xx | ||
183 | return 0; | ||
184 | #else | ||
185 | return 1; | ||
186 | #endif | ||
187 | } | ||
158 | 188 | ||
159 | /* we actually use cpm_muram implementation, define this for convenience */ | 189 | /* we actually use cpm_muram implementation, define this for convenience */ |
160 | #define qe_muram_init cpm_muram_init | 190 | #define qe_muram_init cpm_muram_init |
@@ -210,8 +240,15 @@ struct qe_firmware_info { | |||
210 | u64 extended_modes; /* Extended modes */ | 240 | u64 extended_modes; /* Extended modes */ |
211 | }; | 241 | }; |
212 | 242 | ||
243 | #ifdef CONFIG_QUICC_ENGINE | ||
213 | /* Upload a firmware to the QE */ | 244 | /* Upload a firmware to the QE */ |
214 | int qe_upload_firmware(const struct qe_firmware *firmware); | 245 | int qe_upload_firmware(const struct qe_firmware *firmware); |
246 | #else | ||
247 | static inline int qe_upload_firmware(const struct qe_firmware *firmware) | ||
248 | { | ||
249 | return -ENOSYS; | ||
250 | } | ||
251 | #endif /* CONFIG_QUICC_ENGINE */ | ||
215 | 252 | ||
216 | /* Obtain information on the uploaded firmware */ | 253 | /* Obtain information on the uploaded firmware */ |
217 | struct qe_firmware_info *qe_get_firmware_info(void); | 254 | struct qe_firmware_info *qe_get_firmware_info(void); |
diff --git a/arch/powerpc/include/asm/systbl.h b/arch/powerpc/include/asm/systbl.h index c7d671a7d9a1..07d2d19ab5e9 100644 --- a/arch/powerpc/include/asm/systbl.h +++ b/arch/powerpc/include/asm/systbl.h | |||
@@ -145,7 +145,7 @@ SYSCALL_SPU(setfsuid) | |||
145 | SYSCALL_SPU(setfsgid) | 145 | SYSCALL_SPU(setfsgid) |
146 | SYSCALL_SPU(llseek) | 146 | SYSCALL_SPU(llseek) |
147 | COMPAT_SYS_SPU(getdents) | 147 | COMPAT_SYS_SPU(getdents) |
148 | SYSX_SPU(sys_select,ppc32_select,ppc_select) | 148 | SYSX_SPU(sys_select,ppc32_select,sys_select) |
149 | SYSCALL_SPU(flock) | 149 | SYSCALL_SPU(flock) |
150 | SYSCALL_SPU(msync) | 150 | SYSCALL_SPU(msync) |
151 | COMPAT_SYS_SPU(readv) | 151 | COMPAT_SYS_SPU(readv) |
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index b23664a0b86c..c002b0410219 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile | |||
@@ -42,10 +42,11 @@ obj-$(CONFIG_ALTIVEC) += vecemu.o | |||
42 | obj-$(CONFIG_PPC_970_NAP) += idle_power4.o | 42 | obj-$(CONFIG_PPC_970_NAP) += idle_power4.o |
43 | obj-$(CONFIG_PPC_OF) += of_device.o of_platform.o prom_parse.o | 43 | obj-$(CONFIG_PPC_OF) += of_device.o of_platform.o prom_parse.o |
44 | obj-$(CONFIG_PPC_CLOCK) += clock.o | 44 | obj-$(CONFIG_PPC_CLOCK) += clock.o |
45 | procfs-$(CONFIG_PPC64) := proc_ppc64.o | 45 | procfs-y := proc_powerpc.o |
46 | obj-$(CONFIG_PROC_FS) += $(procfs-y) | 46 | obj-$(CONFIG_PROC_FS) += $(procfs-y) |
47 | rtaspci-$(CONFIG_PPC64)-$(CONFIG_PCI) := rtas_pci.o | 47 | rtaspci-$(CONFIG_PPC64)-$(CONFIG_PCI) := rtas_pci.o |
48 | obj-$(CONFIG_PPC_RTAS) += rtas.o rtas-rtc.o $(rtaspci-y-y) | 48 | obj-$(CONFIG_PPC_RTAS) += rtas.o rtas-rtc.o $(rtaspci-y-y) |
49 | obj-$(CONFIG_PPC_RTAS_DAEMON) += rtasd.o | ||
49 | obj-$(CONFIG_RTAS_FLASH) += rtas_flash.o | 50 | obj-$(CONFIG_RTAS_FLASH) += rtas_flash.o |
50 | obj-$(CONFIG_RTAS_PROC) += rtas-proc.o | 51 | obj-$(CONFIG_RTAS_PROC) += rtas-proc.o |
51 | obj-$(CONFIG_LPARCFG) += lparcfg.o | 52 | obj-$(CONFIG_LPARCFG) += lparcfg.o |
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 0812b0f414bb..a6c2b63227b3 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c | |||
@@ -190,6 +190,11 @@ int main(void) | |||
190 | DEFINE(PACA_SYSTEM_TIME, offsetof(struct paca_struct, system_time)); | 190 | DEFINE(PACA_SYSTEM_TIME, offsetof(struct paca_struct, system_time)); |
191 | DEFINE(PACA_DATA_OFFSET, offsetof(struct paca_struct, data_offset)); | 191 | DEFINE(PACA_DATA_OFFSET, offsetof(struct paca_struct, data_offset)); |
192 | DEFINE(PACA_TRAP_SAVE, offsetof(struct paca_struct, trap_save)); | 192 | DEFINE(PACA_TRAP_SAVE, offsetof(struct paca_struct, trap_save)); |
193 | #ifdef CONFIG_KVM_BOOK3S_64_HANDLER | ||
194 | DEFINE(PACA_KVM_IN_GUEST, offsetof(struct paca_struct, kvm_in_guest)); | ||
195 | DEFINE(PACA_KVM_SLB, offsetof(struct paca_struct, kvm_slb)); | ||
196 | DEFINE(PACA_KVM_SLB_MAX, offsetof(struct paca_struct, kvm_slb_max)); | ||
197 | #endif | ||
193 | #endif /* CONFIG_PPC64 */ | 198 | #endif /* CONFIG_PPC64 */ |
194 | 199 | ||
195 | /* RTAS */ | 200 | /* RTAS */ |
@@ -398,14 +403,24 @@ int main(void) | |||
398 | DEFINE(VCPU_LAST_INST, offsetof(struct kvm_vcpu, arch.last_inst)); | 403 | DEFINE(VCPU_LAST_INST, offsetof(struct kvm_vcpu, arch.last_inst)); |
399 | DEFINE(VCPU_FAULT_DEAR, offsetof(struct kvm_vcpu, arch.fault_dear)); | 404 | DEFINE(VCPU_FAULT_DEAR, offsetof(struct kvm_vcpu, arch.fault_dear)); |
400 | DEFINE(VCPU_FAULT_ESR, offsetof(struct kvm_vcpu, arch.fault_esr)); | 405 | DEFINE(VCPU_FAULT_ESR, offsetof(struct kvm_vcpu, arch.fault_esr)); |
406 | |||
407 | /* book3s_64 */ | ||
408 | #ifdef CONFIG_PPC64 | ||
409 | DEFINE(VCPU_FAULT_DSISR, offsetof(struct kvm_vcpu, arch.fault_dsisr)); | ||
410 | DEFINE(VCPU_HOST_RETIP, offsetof(struct kvm_vcpu, arch.host_retip)); | ||
411 | DEFINE(VCPU_HOST_R2, offsetof(struct kvm_vcpu, arch.host_r2)); | ||
412 | DEFINE(VCPU_HOST_MSR, offsetof(struct kvm_vcpu, arch.host_msr)); | ||
413 | DEFINE(VCPU_SHADOW_MSR, offsetof(struct kvm_vcpu, arch.shadow_msr)); | ||
414 | DEFINE(VCPU_TRAMPOLINE_LOWMEM, offsetof(struct kvm_vcpu, arch.trampoline_lowmem)); | ||
415 | DEFINE(VCPU_TRAMPOLINE_ENTER, offsetof(struct kvm_vcpu, arch.trampoline_enter)); | ||
416 | DEFINE(VCPU_HIGHMEM_HANDLER, offsetof(struct kvm_vcpu, arch.highmem_handler)); | ||
417 | DEFINE(VCPU_HFLAGS, offsetof(struct kvm_vcpu, arch.hflags)); | ||
418 | #endif | ||
401 | #endif | 419 | #endif |
402 | #ifdef CONFIG_44x | 420 | #ifdef CONFIG_44x |
403 | DEFINE(PGD_T_LOG2, PGD_T_LOG2); | 421 | DEFINE(PGD_T_LOG2, PGD_T_LOG2); |
404 | DEFINE(PTE_T_LOG2, PTE_T_LOG2); | 422 | DEFINE(PTE_T_LOG2, PTE_T_LOG2); |
405 | #endif | 423 | #endif |
406 | #ifdef CONFIG_FSL_BOOKE | ||
407 | DEFINE(TLBCAM_SIZE, sizeof(struct tlbcam)); | ||
408 | #endif | ||
409 | 424 | ||
410 | #ifdef CONFIG_KVM_EXIT_TIMING | 425 | #ifdef CONFIG_KVM_EXIT_TIMING |
411 | DEFINE(VCPU_TIMING_EXIT_TBU, offsetof(struct kvm_vcpu, | 426 | DEFINE(VCPU_TIMING_EXIT_TBU, offsetof(struct kvm_vcpu, |
diff --git a/arch/powerpc/kernel/crash.c b/arch/powerpc/kernel/crash.c index 0a8439aafdd1..6f4613dd05ef 100644 --- a/arch/powerpc/kernel/crash.c +++ b/arch/powerpc/kernel/crash.c | |||
@@ -373,7 +373,7 @@ void default_machine_crash_shutdown(struct pt_regs *regs) | |||
373 | hard_irq_disable(); | 373 | hard_irq_disable(); |
374 | 374 | ||
375 | for_each_irq(i) { | 375 | for_each_irq(i) { |
376 | struct irq_desc *desc = irq_desc + i; | 376 | struct irq_desc *desc = irq_to_desc(i); |
377 | 377 | ||
378 | if (desc->status & IRQ_INPROGRESS) | 378 | if (desc->status & IRQ_INPROGRESS) |
379 | desc->chip->eoi(i); | 379 | desc->chip->eoi(i); |
diff --git a/arch/powerpc/kernel/dma-swiotlb.c b/arch/powerpc/kernel/dma-swiotlb.c index e96cbbd9b449..59c928564a03 100644 --- a/arch/powerpc/kernel/dma-swiotlb.c +++ b/arch/powerpc/kernel/dma-swiotlb.c | |||
@@ -21,7 +21,6 @@ | |||
21 | #include <asm/dma.h> | 21 | #include <asm/dma.h> |
22 | #include <asm/abs_addr.h> | 22 | #include <asm/abs_addr.h> |
23 | 23 | ||
24 | int swiotlb __read_mostly; | ||
25 | unsigned int ppc_swiotlb_enable; | 24 | unsigned int ppc_swiotlb_enable; |
26 | 25 | ||
27 | /* | 26 | /* |
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index c7eb4e0eb86c..e3be98ffe2a7 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S | |||
@@ -41,6 +41,7 @@ __start_interrupts: | |||
41 | . = 0x200 | 41 | . = 0x200 |
42 | _machine_check_pSeries: | 42 | _machine_check_pSeries: |
43 | HMT_MEDIUM | 43 | HMT_MEDIUM |
44 | DO_KVM 0x200 | ||
44 | mtspr SPRN_SPRG_SCRATCH0,r13 /* save r13 */ | 45 | mtspr SPRN_SPRG_SCRATCH0,r13 /* save r13 */ |
45 | EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common) | 46 | EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common) |
46 | 47 | ||
@@ -48,6 +49,7 @@ _machine_check_pSeries: | |||
48 | .globl data_access_pSeries | 49 | .globl data_access_pSeries |
49 | data_access_pSeries: | 50 | data_access_pSeries: |
50 | HMT_MEDIUM | 51 | HMT_MEDIUM |
52 | DO_KVM 0x300 | ||
51 | mtspr SPRN_SPRG_SCRATCH0,r13 | 53 | mtspr SPRN_SPRG_SCRATCH0,r13 |
52 | BEGIN_FTR_SECTION | 54 | BEGIN_FTR_SECTION |
53 | mfspr r13,SPRN_SPRG_PACA | 55 | mfspr r13,SPRN_SPRG_PACA |
@@ -77,6 +79,7 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_SLB) | |||
77 | .globl data_access_slb_pSeries | 79 | .globl data_access_slb_pSeries |
78 | data_access_slb_pSeries: | 80 | data_access_slb_pSeries: |
79 | HMT_MEDIUM | 81 | HMT_MEDIUM |
82 | DO_KVM 0x380 | ||
80 | mtspr SPRN_SPRG_SCRATCH0,r13 | 83 | mtspr SPRN_SPRG_SCRATCH0,r13 |
81 | mfspr r13,SPRN_SPRG_PACA /* get paca address into r13 */ | 84 | mfspr r13,SPRN_SPRG_PACA /* get paca address into r13 */ |
82 | std r3,PACA_EXSLB+EX_R3(r13) | 85 | std r3,PACA_EXSLB+EX_R3(r13) |
@@ -115,6 +118,7 @@ data_access_slb_pSeries: | |||
115 | .globl instruction_access_slb_pSeries | 118 | .globl instruction_access_slb_pSeries |
116 | instruction_access_slb_pSeries: | 119 | instruction_access_slb_pSeries: |
117 | HMT_MEDIUM | 120 | HMT_MEDIUM |
121 | DO_KVM 0x480 | ||
118 | mtspr SPRN_SPRG_SCRATCH0,r13 | 122 | mtspr SPRN_SPRG_SCRATCH0,r13 |
119 | mfspr r13,SPRN_SPRG_PACA /* get paca address into r13 */ | 123 | mfspr r13,SPRN_SPRG_PACA /* get paca address into r13 */ |
120 | std r3,PACA_EXSLB+EX_R3(r13) | 124 | std r3,PACA_EXSLB+EX_R3(r13) |
@@ -154,6 +158,7 @@ instruction_access_slb_pSeries: | |||
154 | .globl system_call_pSeries | 158 | .globl system_call_pSeries |
155 | system_call_pSeries: | 159 | system_call_pSeries: |
156 | HMT_MEDIUM | 160 | HMT_MEDIUM |
161 | DO_KVM 0xc00 | ||
157 | BEGIN_FTR_SECTION | 162 | BEGIN_FTR_SECTION |
158 | cmpdi r0,0x1ebe | 163 | cmpdi r0,0x1ebe |
159 | beq- 1f | 164 | beq- 1f |
@@ -187,14 +192,17 @@ END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE) | |||
187 | */ | 192 | */ |
188 | performance_monitor_pSeries_1: | 193 | performance_monitor_pSeries_1: |
189 | . = 0xf00 | 194 | . = 0xf00 |
195 | DO_KVM 0xf00 | ||
190 | b performance_monitor_pSeries | 196 | b performance_monitor_pSeries |
191 | 197 | ||
192 | altivec_unavailable_pSeries_1: | 198 | altivec_unavailable_pSeries_1: |
193 | . = 0xf20 | 199 | . = 0xf20 |
200 | DO_KVM 0xf20 | ||
194 | b altivec_unavailable_pSeries | 201 | b altivec_unavailable_pSeries |
195 | 202 | ||
196 | vsx_unavailable_pSeries_1: | 203 | vsx_unavailable_pSeries_1: |
197 | . = 0xf40 | 204 | . = 0xf40 |
205 | DO_KVM 0xf40 | ||
198 | b vsx_unavailable_pSeries | 206 | b vsx_unavailable_pSeries |
199 | 207 | ||
200 | #ifdef CONFIG_CBE_RAS | 208 | #ifdef CONFIG_CBE_RAS |
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index c38afdb45d7b..925807488022 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <asm/firmware.h> | 37 | #include <asm/firmware.h> |
38 | #include <asm/page_64.h> | 38 | #include <asm/page_64.h> |
39 | #include <asm/irqflags.h> | 39 | #include <asm/irqflags.h> |
40 | #include <asm/kvm_book3s_64_asm.h> | ||
40 | 41 | ||
41 | /* The physical memory is layed out such that the secondary processor | 42 | /* The physical memory is layed out such that the secondary processor |
42 | * spin code sits at 0x0000...0x00ff. On server, the vectors follow | 43 | * spin code sits at 0x0000...0x00ff. On server, the vectors follow |
@@ -165,6 +166,12 @@ exception_marker: | |||
165 | #include "exceptions-64s.S" | 166 | #include "exceptions-64s.S" |
166 | #endif | 167 | #endif |
167 | 168 | ||
169 | /* KVM trampoline code needs to be close to the interrupt handlers */ | ||
170 | |||
171 | #ifdef CONFIG_KVM_BOOK3S_64_HANDLER | ||
172 | #include "../kvm/book3s_64_rmhandlers.S" | ||
173 | #endif | ||
174 | |||
168 | _GLOBAL(generic_secondary_thread_init) | 175 | _GLOBAL(generic_secondary_thread_init) |
169 | mr r24,r3 | 176 | mr r24,r3 |
170 | 177 | ||
diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S index 6ded19d01891..678f98cd5e64 100644 --- a/arch/powerpc/kernel/head_8xx.S +++ b/arch/powerpc/kernel/head_8xx.S | |||
@@ -206,6 +206,8 @@ MachineCheck: | |||
206 | EXCEPTION_PROLOG | 206 | EXCEPTION_PROLOG |
207 | mfspr r4,SPRN_DAR | 207 | mfspr r4,SPRN_DAR |
208 | stw r4,_DAR(r11) | 208 | stw r4,_DAR(r11) |
209 | li r5,0x00f0 | ||
210 | mtspr SPRN_DAR,r5 /* Tag DAR, to be used in DTLB Error */ | ||
209 | mfspr r5,SPRN_DSISR | 211 | mfspr r5,SPRN_DSISR |
210 | stw r5,_DSISR(r11) | 212 | stw r5,_DSISR(r11) |
211 | addi r3,r1,STACK_FRAME_OVERHEAD | 213 | addi r3,r1,STACK_FRAME_OVERHEAD |
@@ -222,6 +224,8 @@ DataAccess: | |||
222 | stw r10,_DSISR(r11) | 224 | stw r10,_DSISR(r11) |
223 | mr r5,r10 | 225 | mr r5,r10 |
224 | mfspr r4,SPRN_DAR | 226 | mfspr r4,SPRN_DAR |
227 | li r10,0x00f0 | ||
228 | mtspr SPRN_DAR,r10 /* Tag DAR, to be used in DTLB Error */ | ||
225 | EXC_XFER_EE_LITE(0x300, handle_page_fault) | 229 | EXC_XFER_EE_LITE(0x300, handle_page_fault) |
226 | 230 | ||
227 | /* Instruction access exception. | 231 | /* Instruction access exception. |
@@ -244,6 +248,8 @@ Alignment: | |||
244 | EXCEPTION_PROLOG | 248 | EXCEPTION_PROLOG |
245 | mfspr r4,SPRN_DAR | 249 | mfspr r4,SPRN_DAR |
246 | stw r4,_DAR(r11) | 250 | stw r4,_DAR(r11) |
251 | li r5,0x00f0 | ||
252 | mtspr SPRN_DAR,r5 /* Tag DAR, to be used in DTLB Error */ | ||
247 | mfspr r5,SPRN_DSISR | 253 | mfspr r5,SPRN_DSISR |
248 | stw r5,_DSISR(r11) | 254 | stw r5,_DSISR(r11) |
249 | addi r3,r1,STACK_FRAME_OVERHEAD | 255 | addi r3,r1,STACK_FRAME_OVERHEAD |
@@ -333,26 +339,20 @@ InstructionTLBMiss: | |||
333 | mfspr r11, SPRN_MD_TWC /* ....and get the pte address */ | 339 | mfspr r11, SPRN_MD_TWC /* ....and get the pte address */ |
334 | lwz r10, 0(r11) /* Get the pte */ | 340 | lwz r10, 0(r11) /* Get the pte */ |
335 | 341 | ||
336 | #ifdef CONFIG_SWAP | 342 | andi. r11, r10, _PAGE_ACCESSED | _PAGE_PRESENT |
337 | /* do not set the _PAGE_ACCESSED bit of a non-present page */ | 343 | cmpwi cr0, r11, _PAGE_ACCESSED | _PAGE_PRESENT |
338 | andi. r11, r10, _PAGE_PRESENT | 344 | bne- cr0, 2f |
339 | beq 4f | 345 | |
340 | ori r10, r10, _PAGE_ACCESSED | 346 | /* Clear PP lsb, 0x400 */ |
341 | mfspr r11, SPRN_MD_TWC /* get the pte address again */ | 347 | rlwinm r10, r10, 0, 22, 20 |
342 | stw r10, 0(r11) | ||
343 | 4: | ||
344 | #else | ||
345 | ori r10, r10, _PAGE_ACCESSED | ||
346 | stw r10, 0(r11) | ||
347 | #endif | ||
348 | 348 | ||
349 | /* The Linux PTE won't go exactly into the MMU TLB. | 349 | /* The Linux PTE won't go exactly into the MMU TLB. |
350 | * Software indicator bits 21, 22 and 28 must be clear. | 350 | * Software indicator bits 22 and 28 must be clear. |
351 | * Software indicator bits 24, 25, 26, and 27 must be | 351 | * Software indicator bits 24, 25, 26, and 27 must be |
352 | * set. All other Linux PTE bits control the behavior | 352 | * set. All other Linux PTE bits control the behavior |
353 | * of the MMU. | 353 | * of the MMU. |
354 | */ | 354 | */ |
355 | 2: li r11, 0x00f0 | 355 | li r11, 0x00f0 |
356 | rlwimi r10, r11, 0, 24, 28 /* Set 24-27, clear 28 */ | 356 | rlwimi r10, r11, 0, 24, 28 /* Set 24-27, clear 28 */ |
357 | DO_8xx_CPU6(0x2d80, r3) | 357 | DO_8xx_CPU6(0x2d80, r3) |
358 | mtspr SPRN_MI_RPN, r10 /* Update TLB entry */ | 358 | mtspr SPRN_MI_RPN, r10 /* Update TLB entry */ |
@@ -365,6 +365,22 @@ InstructionTLBMiss: | |||
365 | lwz r3, 8(r0) | 365 | lwz r3, 8(r0) |
366 | #endif | 366 | #endif |
367 | rfi | 367 | rfi |
368 | 2: | ||
369 | mfspr r11, SPRN_SRR1 | ||
370 | /* clear all error bits as TLB Miss | ||
371 | * sets a few unconditionally | ||
372 | */ | ||
373 | rlwinm r11, r11, 0, 0xffff | ||
374 | mtspr SPRN_SRR1, r11 | ||
375 | |||
376 | mfspr r10, SPRN_M_TW /* Restore registers */ | ||
377 | lwz r11, 0(r0) | ||
378 | mtcr r11 | ||
379 | lwz r11, 4(r0) | ||
380 | #ifdef CONFIG_8xx_CPU6 | ||
381 | lwz r3, 8(r0) | ||
382 | #endif | ||
383 | b InstructionAccess | ||
368 | 384 | ||
369 | . = 0x1200 | 385 | . = 0x1200 |
370 | DataStoreTLBMiss: | 386 | DataStoreTLBMiss: |
@@ -406,29 +422,45 @@ DataStoreTLBMiss: | |||
406 | * above. | 422 | * above. |
407 | */ | 423 | */ |
408 | rlwimi r11, r10, 0, 27, 27 | 424 | rlwimi r11, r10, 0, 27, 27 |
425 | /* Insert the WriteThru flag into the TWC from the Linux PTE. | ||
426 | * It is bit 25 in the Linux PTE and bit 30 in the TWC | ||
427 | */ | ||
428 | rlwimi r11, r10, 32-5, 30, 30 | ||
409 | DO_8xx_CPU6(0x3b80, r3) | 429 | DO_8xx_CPU6(0x3b80, r3) |
410 | mtspr SPRN_MD_TWC, r11 | 430 | mtspr SPRN_MD_TWC, r11 |
411 | 431 | ||
412 | #ifdef CONFIG_SWAP | 432 | /* Both _PAGE_ACCESSED and _PAGE_PRESENT has to be set. |
413 | /* do not set the _PAGE_ACCESSED bit of a non-present page */ | 433 | * We also need to know if the insn is a load/store, so: |
414 | andi. r11, r10, _PAGE_PRESENT | 434 | * Clear _PAGE_PRESENT and load that which will |
415 | beq 4f | 435 | * trap into DTLB Error with store bit set accordinly. |
416 | ori r10, r10, _PAGE_ACCESSED | 436 | */ |
417 | 4: | 437 | /* PRESENT=0x1, ACCESSED=0x20 |
418 | /* and update pte in table */ | 438 | * r11 = ((r10 & PRESENT) & ((r10 & ACCESSED) >> 5)); |
419 | #else | 439 | * r10 = (r10 & ~PRESENT) | r11; |
420 | ori r10, r10, _PAGE_ACCESSED | 440 | */ |
421 | #endif | 441 | rlwinm r11, r10, 32-5, _PAGE_PRESENT |
422 | mfspr r11, SPRN_MD_TWC /* get the pte address again */ | 442 | and r11, r11, r10 |
423 | stw r10, 0(r11) | 443 | rlwimi r10, r11, 0, _PAGE_PRESENT |
444 | |||
445 | /* Honour kernel RO, User NA */ | ||
446 | /* 0x200 == Extended encoding, bit 22 */ | ||
447 | /* r11 = (r10 & _PAGE_USER) >> 2 */ | ||
448 | rlwinm r11, r10, 32-2, 0x200 | ||
449 | or r10, r11, r10 | ||
450 | /* r11 = (r10 & _PAGE_RW) >> 1 */ | ||
451 | rlwinm r11, r10, 32-1, 0x200 | ||
452 | or r10, r11, r10 | ||
453 | /* invert RW and 0x200 bits */ | ||
454 | xori r10, r10, _PAGE_RW | 0x200 | ||
424 | 455 | ||
425 | /* The Linux PTE won't go exactly into the MMU TLB. | 456 | /* The Linux PTE won't go exactly into the MMU TLB. |
426 | * Software indicator bits 21, 22 and 28 must be clear. | 457 | * Software indicator bits 22 and 28 must be clear. |
427 | * Software indicator bits 24, 25, 26, and 27 must be | 458 | * Software indicator bits 24, 25, 26, and 27 must be |
428 | * set. All other Linux PTE bits control the behavior | 459 | * set. All other Linux PTE bits control the behavior |
429 | * of the MMU. | 460 | * of the MMU. |
430 | */ | 461 | */ |
431 | 2: li r11, 0x00f0 | 462 | 2: li r11, 0x00f0 |
463 | mtspr SPRN_DAR,r11 /* Tag DAR */ | ||
432 | rlwimi r10, r11, 0, 24, 28 /* Set 24-27, clear 28 */ | 464 | rlwimi r10, r11, 0, 24, 28 /* Set 24-27, clear 28 */ |
433 | DO_8xx_CPU6(0x3d80, r3) | 465 | DO_8xx_CPU6(0x3d80, r3) |
434 | mtspr SPRN_MD_RPN, r10 /* Update TLB entry */ | 466 | mtspr SPRN_MD_RPN, r10 /* Update TLB entry */ |
@@ -469,97 +501,10 @@ DataTLBError: | |||
469 | stw r10, 0(r0) | 501 | stw r10, 0(r0) |
470 | stw r11, 4(r0) | 502 | stw r11, 4(r0) |
471 | 503 | ||
472 | /* First, make sure this was a store operation. | ||
473 | */ | ||
474 | mfspr r10, SPRN_DSISR | ||
475 | andis. r11, r10, 0x0200 /* If set, indicates store op */ | ||
476 | beq 2f | ||
477 | |||
478 | /* The EA of a data TLB miss is automatically stored in the MD_EPN | ||
479 | * register. The EA of a data TLB error is automatically stored in | ||
480 | * the DAR, but not the MD_EPN register. We must copy the 20 most | ||
481 | * significant bits of the EA from the DAR to MD_EPN before we | ||
482 | * start walking the page tables. We also need to copy the CASID | ||
483 | * value from the M_CASID register. | ||
484 | * Addendum: The EA of a data TLB error is _supposed_ to be stored | ||
485 | * in DAR, but it seems that this doesn't happen in some cases, such | ||
486 | * as when the error is due to a dcbi instruction to a page with a | ||
487 | * TLB that doesn't have the changed bit set. In such cases, there | ||
488 | * does not appear to be any way to recover the EA of the error | ||
489 | * since it is neither in DAR nor MD_EPN. As a workaround, the | ||
490 | * _PAGE_HWWRITE bit is set for all kernel data pages when the PTEs | ||
491 | * are initialized in mapin_ram(). This will avoid the problem, | ||
492 | * assuming we only use the dcbi instruction on kernel addresses. | ||
493 | */ | ||
494 | mfspr r10, SPRN_DAR | 504 | mfspr r10, SPRN_DAR |
495 | rlwinm r11, r10, 0, 0, 19 | 505 | cmpwi cr0, r10, 0x00f0 |
496 | ori r11, r11, MD_EVALID | 506 | beq- FixupDAR /* must be a buggy dcbX, icbi insn. */ |
497 | mfspr r10, SPRN_M_CASID | 507 | DARFixed:/* Return from dcbx instruction bug workaround, r10 holds value of DAR */ |
498 | rlwimi r11, r10, 0, 28, 31 | ||
499 | DO_8xx_CPU6(0x3780, r3) | ||
500 | mtspr SPRN_MD_EPN, r11 | ||
501 | |||
502 | mfspr r10, SPRN_M_TWB /* Get level 1 table entry address */ | ||
503 | |||
504 | /* If we are faulting a kernel address, we have to use the | ||
505 | * kernel page tables. | ||
506 | */ | ||
507 | andi. r11, r10, 0x0800 | ||
508 | beq 3f | ||
509 | lis r11, swapper_pg_dir@h | ||
510 | ori r11, r11, swapper_pg_dir@l | ||
511 | rlwimi r10, r11, 0, 2, 19 | ||
512 | 3: | ||
513 | lwz r11, 0(r10) /* Get the level 1 entry */ | ||
514 | rlwinm. r10, r11,0,0,19 /* Extract page descriptor page address */ | ||
515 | beq 2f /* If zero, bail */ | ||
516 | |||
517 | /* We have a pte table, so fetch the pte from the table. | ||
518 | */ | ||
519 | ori r11, r11, 1 /* Set valid bit in physical L2 page */ | ||
520 | DO_8xx_CPU6(0x3b80, r3) | ||
521 | mtspr SPRN_MD_TWC, r11 /* Load pte table base address */ | ||
522 | mfspr r11, SPRN_MD_TWC /* ....and get the pte address */ | ||
523 | lwz r10, 0(r11) /* Get the pte */ | ||
524 | |||
525 | andi. r11, r10, _PAGE_RW /* Is it writeable? */ | ||
526 | beq 2f /* Bail out if not */ | ||
527 | |||
528 | /* Update 'changed', among others. | ||
529 | */ | ||
530 | #ifdef CONFIG_SWAP | ||
531 | ori r10, r10, _PAGE_DIRTY|_PAGE_HWWRITE | ||
532 | /* do not set the _PAGE_ACCESSED bit of a non-present page */ | ||
533 | andi. r11, r10, _PAGE_PRESENT | ||
534 | beq 4f | ||
535 | ori r10, r10, _PAGE_ACCESSED | ||
536 | 4: | ||
537 | #else | ||
538 | ori r10, r10, _PAGE_DIRTY|_PAGE_ACCESSED|_PAGE_HWWRITE | ||
539 | #endif | ||
540 | mfspr r11, SPRN_MD_TWC /* Get pte address again */ | ||
541 | stw r10, 0(r11) /* and update pte in table */ | ||
542 | |||
543 | /* The Linux PTE won't go exactly into the MMU TLB. | ||
544 | * Software indicator bits 21, 22 and 28 must be clear. | ||
545 | * Software indicator bits 24, 25, 26, and 27 must be | ||
546 | * set. All other Linux PTE bits control the behavior | ||
547 | * of the MMU. | ||
548 | */ | ||
549 | li r11, 0x00f0 | ||
550 | rlwimi r10, r11, 0, 24, 28 /* Set 24-27, clear 28 */ | ||
551 | DO_8xx_CPU6(0x3d80, r3) | ||
552 | mtspr SPRN_MD_RPN, r10 /* Update TLB entry */ | ||
553 | |||
554 | mfspr r10, SPRN_M_TW /* Restore registers */ | ||
555 | lwz r11, 0(r0) | ||
556 | mtcr r11 | ||
557 | lwz r11, 4(r0) | ||
558 | #ifdef CONFIG_8xx_CPU6 | ||
559 | lwz r3, 8(r0) | ||
560 | #endif | ||
561 | rfi | ||
562 | 2: | ||
563 | mfspr r10, SPRN_M_TW /* Restore registers */ | 508 | mfspr r10, SPRN_M_TW /* Restore registers */ |
564 | lwz r11, 0(r0) | 509 | lwz r11, 0(r0) |
565 | mtcr r11 | 510 | mtcr r11 |
@@ -588,6 +533,140 @@ DataTLBError: | |||
588 | 533 | ||
589 | . = 0x2000 | 534 | . = 0x2000 |
590 | 535 | ||
536 | /* This is the procedure to calculate the data EA for buggy dcbx,dcbi instructions | ||
537 | * by decoding the registers used by the dcbx instruction and adding them. | ||
538 | * DAR is set to the calculated address and r10 also holds the EA on exit. | ||
539 | */ | ||
540 | /* define if you don't want to use self modifying code */ | ||
541 | #define NO_SELF_MODIFYING_CODE | ||
542 | FixupDAR:/* Entry point for dcbx workaround. */ | ||
543 | /* fetch instruction from memory. */ | ||
544 | mfspr r10, SPRN_SRR0 | ||
545 | DO_8xx_CPU6(0x3780, r3) | ||
546 | mtspr SPRN_MD_EPN, r10 | ||
547 | mfspr r11, SPRN_M_TWB /* Get level 1 table entry address */ | ||
548 | cmplwi cr0, r11, 0x0800 | ||
549 | blt- 3f /* Branch if user space */ | ||
550 | lis r11, (swapper_pg_dir-PAGE_OFFSET)@h | ||
551 | ori r11, r11, (swapper_pg_dir-PAGE_OFFSET)@l | ||
552 | rlwimi r11, r10, 32-20, 0xffc /* r11 = r11&~0xffc|(r10>>20)&0xffc */ | ||
553 | 3: lwz r11, 0(r11) /* Get the level 1 entry */ | ||
554 | DO_8xx_CPU6(0x3b80, r3) | ||
555 | mtspr SPRN_MD_TWC, r11 /* Load pte table base address */ | ||
556 | mfspr r11, SPRN_MD_TWC /* ....and get the pte address */ | ||
557 | lwz r11, 0(r11) /* Get the pte */ | ||
558 | /* concat physical page address(r11) and page offset(r10) */ | ||
559 | rlwimi r11, r10, 0, 20, 31 | ||
560 | lwz r11,0(r11) | ||
561 | /* Check if it really is a dcbx instruction. */ | ||
562 | /* dcbt and dcbtst does not generate DTLB Misses/Errors, | ||
563 | * no need to include them here */ | ||
564 | srwi r10, r11, 26 /* check if major OP code is 31 */ | ||
565 | cmpwi cr0, r10, 31 | ||
566 | bne- 141f | ||
567 | rlwinm r10, r11, 0, 21, 30 | ||
568 | cmpwi cr0, r10, 2028 /* Is dcbz? */ | ||
569 | beq+ 142f | ||
570 | cmpwi cr0, r10, 940 /* Is dcbi? */ | ||
571 | beq+ 142f | ||
572 | cmpwi cr0, r10, 108 /* Is dcbst? */ | ||
573 | beq+ 144f /* Fix up store bit! */ | ||
574 | cmpwi cr0, r10, 172 /* Is dcbf? */ | ||
575 | beq+ 142f | ||
576 | cmpwi cr0, r10, 1964 /* Is icbi? */ | ||
577 | beq+ 142f | ||
578 | 141: mfspr r10, SPRN_DAR /* r10 must hold DAR at exit */ | ||
579 | b DARFixed /* Nope, go back to normal TLB processing */ | ||
580 | |||
581 | 144: mfspr r10, SPRN_DSISR | ||
582 | rlwinm r10, r10,0,7,5 /* Clear store bit for buggy dcbst insn */ | ||
583 | mtspr SPRN_DSISR, r10 | ||
584 | 142: /* continue, it was a dcbx, dcbi instruction. */ | ||
585 | #ifdef CONFIG_8xx_CPU6 | ||
586 | lwz r3, 8(r0) /* restore r3 from memory */ | ||
587 | #endif | ||
588 | #ifndef NO_SELF_MODIFYING_CODE | ||
589 | andis. r10,r11,0x1f /* test if reg RA is r0 */ | ||
590 | li r10,modified_instr@l | ||
591 | dcbtst r0,r10 /* touch for store */ | ||
592 | rlwinm r11,r11,0,0,20 /* Zero lower 10 bits */ | ||
593 | oris r11,r11,640 /* Transform instr. to a "add r10,RA,RB" */ | ||
594 | ori r11,r11,532 | ||
595 | stw r11,0(r10) /* store add/and instruction */ | ||
596 | dcbf 0,r10 /* flush new instr. to memory. */ | ||
597 | icbi 0,r10 /* invalidate instr. cache line */ | ||
598 | lwz r11, 4(r0) /* restore r11 from memory */ | ||
599 | mfspr r10, SPRN_M_TW /* restore r10 from M_TW */ | ||
600 | isync /* Wait until new instr is loaded from memory */ | ||
601 | modified_instr: | ||
602 | .space 4 /* this is where the add instr. is stored */ | ||
603 | bne+ 143f | ||
604 | subf r10,r0,r10 /* r10=r10-r0, only if reg RA is r0 */ | ||
605 | 143: mtdar r10 /* store faulting EA in DAR */ | ||
606 | b DARFixed /* Go back to normal TLB handling */ | ||
607 | #else | ||
608 | mfctr r10 | ||
609 | mtdar r10 /* save ctr reg in DAR */ | ||
610 | rlwinm r10, r11, 24, 24, 28 /* offset into jump table for reg RB */ | ||
611 | addi r10, r10, 150f@l /* add start of table */ | ||
612 | mtctr r10 /* load ctr with jump address */ | ||
613 | xor r10, r10, r10 /* sum starts at zero */ | ||
614 | bctr /* jump into table */ | ||
615 | 150: | ||
616 | add r10, r10, r0 ;b 151f | ||
617 | add r10, r10, r1 ;b 151f | ||
618 | add r10, r10, r2 ;b 151f | ||
619 | add r10, r10, r3 ;b 151f | ||
620 | add r10, r10, r4 ;b 151f | ||
621 | add r10, r10, r5 ;b 151f | ||
622 | add r10, r10, r6 ;b 151f | ||
623 | add r10, r10, r7 ;b 151f | ||
624 | add r10, r10, r8 ;b 151f | ||
625 | add r10, r10, r9 ;b 151f | ||
626 | mtctr r11 ;b 154f /* r10 needs special handling */ | ||
627 | mtctr r11 ;b 153f /* r11 needs special handling */ | ||
628 | add r10, r10, r12 ;b 151f | ||
629 | add r10, r10, r13 ;b 151f | ||
630 | add r10, r10, r14 ;b 151f | ||
631 | add r10, r10, r15 ;b 151f | ||
632 | add r10, r10, r16 ;b 151f | ||
633 | add r10, r10, r17 ;b 151f | ||
634 | add r10, r10, r18 ;b 151f | ||
635 | add r10, r10, r19 ;b 151f | ||
636 | add r10, r10, r20 ;b 151f | ||
637 | add r10, r10, r21 ;b 151f | ||
638 | add r10, r10, r22 ;b 151f | ||
639 | add r10, r10, r23 ;b 151f | ||
640 | add r10, r10, r24 ;b 151f | ||
641 | add r10, r10, r25 ;b 151f | ||
642 | add r10, r10, r26 ;b 151f | ||
643 | add r10, r10, r27 ;b 151f | ||
644 | add r10, r10, r28 ;b 151f | ||
645 | add r10, r10, r29 ;b 151f | ||
646 | add r10, r10, r30 ;b 151f | ||
647 | add r10, r10, r31 | ||
648 | 151: | ||
649 | rlwinm. r11,r11,19,24,28 /* offset into jump table for reg RA */ | ||
650 | beq 152f /* if reg RA is zero, don't add it */ | ||
651 | addi r11, r11, 150b@l /* add start of table */ | ||
652 | mtctr r11 /* load ctr with jump address */ | ||
653 | rlwinm r11,r11,0,16,10 /* make sure we don't execute this more than once */ | ||
654 | bctr /* jump into table */ | ||
655 | 152: | ||
656 | mfdar r11 | ||
657 | mtctr r11 /* restore ctr reg from DAR */ | ||
658 | mtdar r10 /* save fault EA to DAR */ | ||
659 | b DARFixed /* Go back to normal TLB handling */ | ||
660 | |||
661 | /* special handling for r10,r11 since these are modified already */ | ||
662 | 153: lwz r11, 4(r0) /* load r11 from memory */ | ||
663 | b 155f | ||
664 | 154: mfspr r11, SPRN_M_TW /* load r10 from M_TW */ | ||
665 | 155: add r10, r10, r11 /* add it */ | ||
666 | mfctr r11 /* restore r11 */ | ||
667 | b 151b | ||
668 | #endif | ||
669 | |||
591 | .globl giveup_fpu | 670 | .globl giveup_fpu |
592 | giveup_fpu: | 671 | giveup_fpu: |
593 | blr | 672 | blr |
diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S index 975788ca05d2..7f4bd7f3b6af 100644 --- a/arch/powerpc/kernel/head_fsl_booke.S +++ b/arch/powerpc/kernel/head_fsl_booke.S | |||
@@ -944,28 +944,6 @@ _GLOBAL(__setup_e500mc_ivors) | |||
944 | blr | 944 | blr |
945 | 945 | ||
946 | /* | 946 | /* |
947 | * extern void loadcam_entry(unsigned int index) | ||
948 | * | ||
949 | * Load TLBCAM[index] entry in to the L2 CAM MMU | ||
950 | */ | ||
951 | _GLOBAL(loadcam_entry) | ||
952 | lis r4,TLBCAM@ha | ||
953 | addi r4,r4,TLBCAM@l | ||
954 | mulli r5,r3,TLBCAM_SIZE | ||
955 | add r3,r5,r4 | ||
956 | lwz r4,0(r3) | ||
957 | mtspr SPRN_MAS0,r4 | ||
958 | lwz r4,4(r3) | ||
959 | mtspr SPRN_MAS1,r4 | ||
960 | lwz r4,8(r3) | ||
961 | mtspr SPRN_MAS2,r4 | ||
962 | lwz r4,12(r3) | ||
963 | mtspr SPRN_MAS3,r4 | ||
964 | tlbwe | ||
965 | isync | ||
966 | blr | ||
967 | |||
968 | /* | ||
969 | * extern void giveup_altivec(struct task_struct *prev) | 947 | * extern void giveup_altivec(struct task_struct *prev) |
970 | * | 948 | * |
971 | * The e500 core does not have an AltiVec unit. | 949 | * The e500 core does not have an AltiVec unit. |
diff --git a/arch/powerpc/kernel/io.c b/arch/powerpc/kernel/io.c index 1882bf419fa6..8dc7547c2377 100644 --- a/arch/powerpc/kernel/io.c +++ b/arch/powerpc/kernel/io.c | |||
@@ -161,7 +161,7 @@ void _memcpy_fromio(void *dest, const volatile void __iomem *src, | |||
161 | dest++; | 161 | dest++; |
162 | n--; | 162 | n--; |
163 | } | 163 | } |
164 | while(n > 4) { | 164 | while(n >= 4) { |
165 | *((u32 *)dest) = *((volatile u32 *)vsrc); | 165 | *((u32 *)dest) = *((volatile u32 *)vsrc); |
166 | eieio(); | 166 | eieio(); |
167 | vsrc += 4; | 167 | vsrc += 4; |
@@ -190,7 +190,7 @@ void _memcpy_toio(volatile void __iomem *dest, const void *src, unsigned long n) | |||
190 | vdest++; | 190 | vdest++; |
191 | n--; | 191 | n--; |
192 | } | 192 | } |
193 | while(n > 4) { | 193 | while(n >= 4) { |
194 | *((volatile u32 *)vdest) = *((volatile u32 *)src); | 194 | *((volatile u32 *)vdest) = *((volatile u32 *)src); |
195 | src += 4; | 195 | src += 4; |
196 | vdest += 4; | 196 | vdest += 4; |
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 02a334662cc0..f6dca4f4b295 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c | |||
@@ -87,7 +87,10 @@ extern int tau_interrupts(int); | |||
87 | #endif /* CONFIG_PPC32 */ | 87 | #endif /* CONFIG_PPC32 */ |
88 | 88 | ||
89 | #ifdef CONFIG_PPC64 | 89 | #ifdef CONFIG_PPC64 |
90 | |||
91 | #ifndef CONFIG_SPARSE_IRQ | ||
90 | EXPORT_SYMBOL(irq_desc); | 92 | EXPORT_SYMBOL(irq_desc); |
93 | #endif | ||
91 | 94 | ||
92 | int distribute_irqs = 1; | 95 | int distribute_irqs = 1; |
93 | 96 | ||
@@ -189,33 +192,7 @@ int show_interrupts(struct seq_file *p, void *v) | |||
189 | for_each_online_cpu(j) | 192 | for_each_online_cpu(j) |
190 | seq_printf(p, "CPU%d ", j); | 193 | seq_printf(p, "CPU%d ", j); |
191 | seq_putc(p, '\n'); | 194 | seq_putc(p, '\n'); |
192 | } | 195 | } else if (i == nr_irqs) { |
193 | |||
194 | if (i < NR_IRQS) { | ||
195 | desc = get_irq_desc(i); | ||
196 | spin_lock_irqsave(&desc->lock, flags); | ||
197 | action = desc->action; | ||
198 | if (!action || !action->handler) | ||
199 | goto skip; | ||
200 | seq_printf(p, "%3d: ", i); | ||
201 | #ifdef CONFIG_SMP | ||
202 | for_each_online_cpu(j) | ||
203 | seq_printf(p, "%10u ", kstat_irqs_cpu(i, j)); | ||
204 | #else | ||
205 | seq_printf(p, "%10u ", kstat_irqs(i)); | ||
206 | #endif /* CONFIG_SMP */ | ||
207 | if (desc->chip) | ||
208 | seq_printf(p, " %s ", desc->chip->typename); | ||
209 | else | ||
210 | seq_puts(p, " None "); | ||
211 | seq_printf(p, "%s", (desc->status & IRQ_LEVEL) ? "Level " : "Edge "); | ||
212 | seq_printf(p, " %s", action->name); | ||
213 | for (action = action->next; action; action = action->next) | ||
214 | seq_printf(p, ", %s", action->name); | ||
215 | seq_putc(p, '\n'); | ||
216 | skip: | ||
217 | spin_unlock_irqrestore(&desc->lock, flags); | ||
218 | } else if (i == NR_IRQS) { | ||
219 | #if defined(CONFIG_PPC32) && defined(CONFIG_TAU_INT) | 196 | #if defined(CONFIG_PPC32) && defined(CONFIG_TAU_INT) |
220 | if (tau_initialized){ | 197 | if (tau_initialized){ |
221 | seq_puts(p, "TAU: "); | 198 | seq_puts(p, "TAU: "); |
@@ -225,30 +202,68 @@ skip: | |||
225 | } | 202 | } |
226 | #endif /* CONFIG_PPC32 && CONFIG_TAU_INT*/ | 203 | #endif /* CONFIG_PPC32 && CONFIG_TAU_INT*/ |
227 | seq_printf(p, "BAD: %10u\n", ppc_spurious_interrupts); | 204 | seq_printf(p, "BAD: %10u\n", ppc_spurious_interrupts); |
205 | |||
206 | return 0; | ||
228 | } | 207 | } |
208 | |||
209 | desc = irq_to_desc(i); | ||
210 | if (!desc) | ||
211 | return 0; | ||
212 | |||
213 | spin_lock_irqsave(&desc->lock, flags); | ||
214 | |||
215 | action = desc->action; | ||
216 | if (!action || !action->handler) | ||
217 | goto skip; | ||
218 | |||
219 | seq_printf(p, "%3d: ", i); | ||
220 | #ifdef CONFIG_SMP | ||
221 | for_each_online_cpu(j) | ||
222 | seq_printf(p, "%10u ", kstat_irqs_cpu(i, j)); | ||
223 | #else | ||
224 | seq_printf(p, "%10u ", kstat_irqs(i)); | ||
225 | #endif /* CONFIG_SMP */ | ||
226 | |||
227 | if (desc->chip) | ||
228 | seq_printf(p, " %s ", desc->chip->name); | ||
229 | else | ||
230 | seq_puts(p, " None "); | ||
231 | |||
232 | seq_printf(p, "%s", (desc->status & IRQ_LEVEL) ? "Level " : "Edge "); | ||
233 | seq_printf(p, " %s", action->name); | ||
234 | |||
235 | for (action = action->next; action; action = action->next) | ||
236 | seq_printf(p, ", %s", action->name); | ||
237 | seq_putc(p, '\n'); | ||
238 | |||
239 | skip: | ||
240 | spin_unlock_irqrestore(&desc->lock, flags); | ||
241 | |||
229 | return 0; | 242 | return 0; |
230 | } | 243 | } |
231 | 244 | ||
232 | #ifdef CONFIG_HOTPLUG_CPU | 245 | #ifdef CONFIG_HOTPLUG_CPU |
233 | void fixup_irqs(cpumask_t map) | 246 | void fixup_irqs(cpumask_t map) |
234 | { | 247 | { |
248 | struct irq_desc *desc; | ||
235 | unsigned int irq; | 249 | unsigned int irq; |
236 | static int warned; | 250 | static int warned; |
237 | 251 | ||
238 | for_each_irq(irq) { | 252 | for_each_irq(irq) { |
239 | cpumask_t mask; | 253 | cpumask_t mask; |
240 | 254 | ||
241 | if (irq_desc[irq].status & IRQ_PER_CPU) | 255 | desc = irq_to_desc(irq); |
256 | if (desc && desc->status & IRQ_PER_CPU) | ||
242 | continue; | 257 | continue; |
243 | 258 | ||
244 | cpumask_and(&mask, irq_desc[irq].affinity, &map); | 259 | cpumask_and(&mask, desc->affinity, &map); |
245 | if (any_online_cpu(mask) == NR_CPUS) { | 260 | if (any_online_cpu(mask) == NR_CPUS) { |
246 | printk("Breaking affinity for irq %i\n", irq); | 261 | printk("Breaking affinity for irq %i\n", irq); |
247 | mask = map; | 262 | mask = map; |
248 | } | 263 | } |
249 | if (irq_desc[irq].chip->set_affinity) | 264 | if (desc->chip->set_affinity) |
250 | irq_desc[irq].chip->set_affinity(irq, &mask); | 265 | desc->chip->set_affinity(irq, &mask); |
251 | else if (irq_desc[irq].action && !(warned++)) | 266 | else if (desc->action && !(warned++)) |
252 | printk("Cannot set affinity for irq %i\n", irq); | 267 | printk("Cannot set affinity for irq %i\n", irq); |
253 | } | 268 | } |
254 | 269 | ||
@@ -275,7 +290,7 @@ static inline void handle_one_irq(unsigned int irq) | |||
275 | return; | 290 | return; |
276 | } | 291 | } |
277 | 292 | ||
278 | desc = irq_desc + irq; | 293 | desc = irq_to_desc(irq); |
279 | saved_sp_limit = current->thread.ksp_limit; | 294 | saved_sp_limit = current->thread.ksp_limit; |
280 | 295 | ||
281 | irqtp->task = curtp->task; | 296 | irqtp->task = curtp->task; |
@@ -541,7 +556,7 @@ struct irq_host *irq_alloc_host(struct device_node *of_node, | |||
541 | smp_wmb(); | 556 | smp_wmb(); |
542 | 557 | ||
543 | /* Clear norequest flags */ | 558 | /* Clear norequest flags */ |
544 | get_irq_desc(i)->status &= ~IRQ_NOREQUEST; | 559 | irq_to_desc(i)->status &= ~IRQ_NOREQUEST; |
545 | 560 | ||
546 | /* Legacy flags are left to default at this point, | 561 | /* Legacy flags are left to default at this point, |
547 | * one can then use irq_create_mapping() to | 562 | * one can then use irq_create_mapping() to |
@@ -607,8 +622,16 @@ void irq_set_virq_count(unsigned int count) | |||
607 | static int irq_setup_virq(struct irq_host *host, unsigned int virq, | 622 | static int irq_setup_virq(struct irq_host *host, unsigned int virq, |
608 | irq_hw_number_t hwirq) | 623 | irq_hw_number_t hwirq) |
609 | { | 624 | { |
625 | struct irq_desc *desc; | ||
626 | |||
627 | desc = irq_to_desc_alloc_node(virq, 0); | ||
628 | if (!desc) { | ||
629 | pr_debug("irq: -> allocating desc failed\n"); | ||
630 | goto error; | ||
631 | } | ||
632 | |||
610 | /* Clear IRQ_NOREQUEST flag */ | 633 | /* Clear IRQ_NOREQUEST flag */ |
611 | get_irq_desc(virq)->status &= ~IRQ_NOREQUEST; | 634 | desc->status &= ~IRQ_NOREQUEST; |
612 | 635 | ||
613 | /* map it */ | 636 | /* map it */ |
614 | smp_wmb(); | 637 | smp_wmb(); |
@@ -617,11 +640,14 @@ static int irq_setup_virq(struct irq_host *host, unsigned int virq, | |||
617 | 640 | ||
618 | if (host->ops->map(host, virq, hwirq)) { | 641 | if (host->ops->map(host, virq, hwirq)) { |
619 | pr_debug("irq: -> mapping failed, freeing\n"); | 642 | pr_debug("irq: -> mapping failed, freeing\n"); |
620 | irq_free_virt(virq, 1); | 643 | goto error; |
621 | return -1; | ||
622 | } | 644 | } |
623 | 645 | ||
624 | return 0; | 646 | return 0; |
647 | |||
648 | error: | ||
649 | irq_free_virt(virq, 1); | ||
650 | return -1; | ||
625 | } | 651 | } |
626 | 652 | ||
627 | unsigned int irq_create_direct_mapping(struct irq_host *host) | 653 | unsigned int irq_create_direct_mapping(struct irq_host *host) |
@@ -705,7 +731,7 @@ unsigned int irq_create_mapping(struct irq_host *host, | |||
705 | EXPORT_SYMBOL_GPL(irq_create_mapping); | 731 | EXPORT_SYMBOL_GPL(irq_create_mapping); |
706 | 732 | ||
707 | unsigned int irq_create_of_mapping(struct device_node *controller, | 733 | unsigned int irq_create_of_mapping(struct device_node *controller, |
708 | u32 *intspec, unsigned int intsize) | 734 | const u32 *intspec, unsigned int intsize) |
709 | { | 735 | { |
710 | struct irq_host *host; | 736 | struct irq_host *host; |
711 | irq_hw_number_t hwirq; | 737 | irq_hw_number_t hwirq; |
@@ -738,7 +764,7 @@ unsigned int irq_create_of_mapping(struct device_node *controller, | |||
738 | 764 | ||
739 | /* Set type if specified and different than the current one */ | 765 | /* Set type if specified and different than the current one */ |
740 | if (type != IRQ_TYPE_NONE && | 766 | if (type != IRQ_TYPE_NONE && |
741 | type != (get_irq_desc(virq)->status & IRQF_TRIGGER_MASK)) | 767 | type != (irq_to_desc(virq)->status & IRQF_TRIGGER_MASK)) |
742 | set_irq_type(virq, type); | 768 | set_irq_type(virq, type); |
743 | return virq; | 769 | return virq; |
744 | } | 770 | } |
@@ -810,7 +836,7 @@ void irq_dispose_mapping(unsigned int virq) | |||
810 | irq_map[virq].hwirq = host->inval_irq; | 836 | irq_map[virq].hwirq = host->inval_irq; |
811 | 837 | ||
812 | /* Set some flags */ | 838 | /* Set some flags */ |
813 | get_irq_desc(virq)->status |= IRQ_NOREQUEST; | 839 | irq_to_desc(virq)->status |= IRQ_NOREQUEST; |
814 | 840 | ||
815 | /* Free it */ | 841 | /* Free it */ |
816 | irq_free_virt(virq, 1); | 842 | irq_free_virt(virq, 1); |
@@ -1002,12 +1028,24 @@ void irq_free_virt(unsigned int virq, unsigned int count) | |||
1002 | spin_unlock_irqrestore(&irq_big_lock, flags); | 1028 | spin_unlock_irqrestore(&irq_big_lock, flags); |
1003 | } | 1029 | } |
1004 | 1030 | ||
1005 | void irq_early_init(void) | 1031 | int arch_early_irq_init(void) |
1006 | { | 1032 | { |
1007 | unsigned int i; | 1033 | struct irq_desc *desc; |
1034 | int i; | ||
1035 | |||
1036 | for (i = 0; i < NR_IRQS; i++) { | ||
1037 | desc = irq_to_desc(i); | ||
1038 | if (desc) | ||
1039 | desc->status |= IRQ_NOREQUEST; | ||
1040 | } | ||
1008 | 1041 | ||
1009 | for (i = 0; i < NR_IRQS; i++) | 1042 | return 0; |
1010 | get_irq_desc(i)->status |= IRQ_NOREQUEST; | 1043 | } |
1044 | |||
1045 | int arch_init_chip_data(struct irq_desc *desc, int node) | ||
1046 | { | ||
1047 | desc->status |= IRQ_NOREQUEST; | ||
1048 | return 0; | ||
1011 | } | 1049 | } |
1012 | 1050 | ||
1013 | /* We need to create the radix trees late */ | 1051 | /* We need to create the radix trees late */ |
@@ -1069,16 +1107,19 @@ static int virq_debug_show(struct seq_file *m, void *private) | |||
1069 | seq_printf(m, "%-5s %-7s %-15s %s\n", "virq", "hwirq", | 1107 | seq_printf(m, "%-5s %-7s %-15s %s\n", "virq", "hwirq", |
1070 | "chip name", "host name"); | 1108 | "chip name", "host name"); |
1071 | 1109 | ||
1072 | for (i = 1; i < NR_IRQS; i++) { | 1110 | for (i = 1; i < nr_irqs; i++) { |
1073 | desc = get_irq_desc(i); | 1111 | desc = irq_to_desc(i); |
1112 | if (!desc) | ||
1113 | continue; | ||
1114 | |||
1074 | spin_lock_irqsave(&desc->lock, flags); | 1115 | spin_lock_irqsave(&desc->lock, flags); |
1075 | 1116 | ||
1076 | if (desc->action && desc->action->handler) { | 1117 | if (desc->action && desc->action->handler) { |
1077 | seq_printf(m, "%5d ", i); | 1118 | seq_printf(m, "%5d ", i); |
1078 | seq_printf(m, "0x%05lx ", virq_to_hw(i)); | 1119 | seq_printf(m, "0x%05lx ", virq_to_hw(i)); |
1079 | 1120 | ||
1080 | if (desc->chip && desc->chip->typename) | 1121 | if (desc->chip && desc->chip->name) |
1081 | p = desc->chip->typename; | 1122 | p = desc->chip->name; |
1082 | else | 1123 | else |
1083 | p = none; | 1124 | p = none; |
1084 | seq_printf(m, "%-15s ", p); | 1125 | seq_printf(m, "%-15s ", p); |
diff --git a/arch/powerpc/kernel/lparcfg.c b/arch/powerpc/kernel/lparcfg.c index ed0ac4e4b8d8..79a00bb9c64c 100644 --- a/arch/powerpc/kernel/lparcfg.c +++ b/arch/powerpc/kernel/lparcfg.c | |||
@@ -781,9 +781,9 @@ static int __init lparcfg_init(void) | |||
781 | !firmware_has_feature(FW_FEATURE_ISERIES)) | 781 | !firmware_has_feature(FW_FEATURE_ISERIES)) |
782 | mode |= S_IWUSR; | 782 | mode |= S_IWUSR; |
783 | 783 | ||
784 | ent = proc_create("ppc64/lparcfg", mode, NULL, &lparcfg_fops); | 784 | ent = proc_create("powerpc/lparcfg", mode, NULL, &lparcfg_fops); |
785 | if (!ent) { | 785 | if (!ent) { |
786 | printk(KERN_ERR "Failed to create ppc64/lparcfg\n"); | 786 | printk(KERN_ERR "Failed to create powerpc/lparcfg\n"); |
787 | return -EIO; | 787 | return -EIO; |
788 | } | 788 | } |
789 | 789 | ||
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S index da9c0c4c10f3..8649f536f8df 100644 --- a/arch/powerpc/kernel/misc_32.S +++ b/arch/powerpc/kernel/misc_32.S | |||
@@ -502,15 +502,7 @@ _GLOBAL(clear_pages) | |||
502 | li r0,PAGE_SIZE/L1_CACHE_BYTES | 502 | li r0,PAGE_SIZE/L1_CACHE_BYTES |
503 | slw r0,r0,r4 | 503 | slw r0,r0,r4 |
504 | mtctr r0 | 504 | mtctr r0 |
505 | #ifdef CONFIG_8xx | ||
506 | li r4, 0 | ||
507 | 1: stw r4, 0(r3) | ||
508 | stw r4, 4(r3) | ||
509 | stw r4, 8(r3) | ||
510 | stw r4, 12(r3) | ||
511 | #else | ||
512 | 1: dcbz 0,r3 | 505 | 1: dcbz 0,r3 |
513 | #endif | ||
514 | addi r3,r3,L1_CACHE_BYTES | 506 | addi r3,r3,L1_CACHE_BYTES |
515 | bdnz 1b | 507 | bdnz 1b |
516 | blr | 508 | blr |
@@ -535,15 +527,6 @@ _GLOBAL(copy_page) | |||
535 | addi r3,r3,-4 | 527 | addi r3,r3,-4 |
536 | addi r4,r4,-4 | 528 | addi r4,r4,-4 |
537 | 529 | ||
538 | #ifdef CONFIG_8xx | ||
539 | /* don't use prefetch on 8xx */ | ||
540 | li r0,4096/L1_CACHE_BYTES | ||
541 | mtctr r0 | ||
542 | 1: COPY_16_BYTES | ||
543 | bdnz 1b | ||
544 | blr | ||
545 | |||
546 | #else /* not 8xx, we can prefetch */ | ||
547 | li r5,4 | 530 | li r5,4 |
548 | 531 | ||
549 | #if MAX_COPY_PREFETCH > 1 | 532 | #if MAX_COPY_PREFETCH > 1 |
@@ -584,7 +567,6 @@ _GLOBAL(copy_page) | |||
584 | li r0,MAX_COPY_PREFETCH | 567 | li r0,MAX_COPY_PREFETCH |
585 | li r11,4 | 568 | li r11,4 |
586 | b 2b | 569 | b 2b |
587 | #endif /* CONFIG_8xx */ | ||
588 | 570 | ||
589 | /* | 571 | /* |
590 | * void atomic_clear_mask(atomic_t mask, atomic_t *addr) | 572 | * void atomic_clear_mask(atomic_t mask, atomic_t *addr) |
diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c index 0ed31f220482..ad461e735aec 100644 --- a/arch/powerpc/kernel/nvram_64.c +++ b/arch/powerpc/kernel/nvram_64.c | |||
@@ -139,8 +139,8 @@ out: | |||
139 | 139 | ||
140 | } | 140 | } |
141 | 141 | ||
142 | static int dev_nvram_ioctl(struct inode *inode, struct file *file, | 142 | static long dev_nvram_ioctl(struct file *file, unsigned int cmd, |
143 | unsigned int cmd, unsigned long arg) | 143 | unsigned long arg) |
144 | { | 144 | { |
145 | switch(cmd) { | 145 | switch(cmd) { |
146 | #ifdef CONFIG_PPC_PMAC | 146 | #ifdef CONFIG_PPC_PMAC |
@@ -169,11 +169,11 @@ static int dev_nvram_ioctl(struct inode *inode, struct file *file, | |||
169 | } | 169 | } |
170 | 170 | ||
171 | const struct file_operations nvram_fops = { | 171 | const struct file_operations nvram_fops = { |
172 | .owner = THIS_MODULE, | 172 | .owner = THIS_MODULE, |
173 | .llseek = dev_nvram_llseek, | 173 | .llseek = dev_nvram_llseek, |
174 | .read = dev_nvram_read, | 174 | .read = dev_nvram_read, |
175 | .write = dev_nvram_write, | 175 | .write = dev_nvram_write, |
176 | .ioctl = dev_nvram_ioctl, | 176 | .unlocked_ioctl = dev_nvram_ioctl, |
177 | }; | 177 | }; |
178 | 178 | ||
179 | static struct miscdevice nvram_dev = { | 179 | static struct miscdevice nvram_dev = { |
@@ -184,7 +184,7 @@ static struct miscdevice nvram_dev = { | |||
184 | 184 | ||
185 | 185 | ||
186 | #ifdef DEBUG_NVRAM | 186 | #ifdef DEBUG_NVRAM |
187 | static void nvram_print_partitions(char * label) | 187 | static void __init nvram_print_partitions(char * label) |
188 | { | 188 | { |
189 | struct list_head * p; | 189 | struct list_head * p; |
190 | struct nvram_partition * tmp_part; | 190 | struct nvram_partition * tmp_part; |
@@ -202,7 +202,7 @@ static void nvram_print_partitions(char * label) | |||
202 | #endif | 202 | #endif |
203 | 203 | ||
204 | 204 | ||
205 | static int nvram_write_header(struct nvram_partition * part) | 205 | static int __init nvram_write_header(struct nvram_partition * part) |
206 | { | 206 | { |
207 | loff_t tmp_index; | 207 | loff_t tmp_index; |
208 | int rc; | 208 | int rc; |
@@ -214,7 +214,7 @@ static int nvram_write_header(struct nvram_partition * part) | |||
214 | } | 214 | } |
215 | 215 | ||
216 | 216 | ||
217 | static unsigned char nvram_checksum(struct nvram_header *p) | 217 | static unsigned char __init nvram_checksum(struct nvram_header *p) |
218 | { | 218 | { |
219 | unsigned int c_sum, c_sum2; | 219 | unsigned int c_sum, c_sum2; |
220 | unsigned short *sp = (unsigned short *)p->name; /* assume 6 shorts */ | 220 | unsigned short *sp = (unsigned short *)p->name; /* assume 6 shorts */ |
@@ -228,32 +228,7 @@ static unsigned char nvram_checksum(struct nvram_header *p) | |||
228 | return c_sum; | 228 | return c_sum; |
229 | } | 229 | } |
230 | 230 | ||
231 | 231 | static int __init nvram_remove_os_partition(void) | |
232 | /* | ||
233 | * Find an nvram partition, sig can be 0 for any | ||
234 | * partition or name can be NULL for any name, else | ||
235 | * tries to match both | ||
236 | */ | ||
237 | struct nvram_partition *nvram_find_partition(int sig, const char *name) | ||
238 | { | ||
239 | struct nvram_partition * part; | ||
240 | struct list_head * p; | ||
241 | |||
242 | list_for_each(p, &nvram_part->partition) { | ||
243 | part = list_entry(p, struct nvram_partition, partition); | ||
244 | |||
245 | if (sig && part->header.signature != sig) | ||
246 | continue; | ||
247 | if (name && 0 != strncmp(name, part->header.name, 12)) | ||
248 | continue; | ||
249 | return part; | ||
250 | } | ||
251 | return NULL; | ||
252 | } | ||
253 | EXPORT_SYMBOL(nvram_find_partition); | ||
254 | |||
255 | |||
256 | static int nvram_remove_os_partition(void) | ||
257 | { | 232 | { |
258 | struct list_head *i; | 233 | struct list_head *i; |
259 | struct list_head *j; | 234 | struct list_head *j; |
@@ -319,7 +294,7 @@ static int nvram_remove_os_partition(void) | |||
319 | * Will create a partition starting at the first free | 294 | * Will create a partition starting at the first free |
320 | * space found if space has enough room. | 295 | * space found if space has enough room. |
321 | */ | 296 | */ |
322 | static int nvram_create_os_partition(void) | 297 | static int __init nvram_create_os_partition(void) |
323 | { | 298 | { |
324 | struct nvram_partition *part; | 299 | struct nvram_partition *part; |
325 | struct nvram_partition *new_part; | 300 | struct nvram_partition *new_part; |
@@ -422,7 +397,7 @@ static int nvram_create_os_partition(void) | |||
422 | * 5.) If the max chunk cannot be allocated then try finding a chunk | 397 | * 5.) If the max chunk cannot be allocated then try finding a chunk |
423 | * that will satisfy the minum needed (NVRAM_MIN_REQ). | 398 | * that will satisfy the minum needed (NVRAM_MIN_REQ). |
424 | */ | 399 | */ |
425 | static int nvram_setup_partition(void) | 400 | static int __init nvram_setup_partition(void) |
426 | { | 401 | { |
427 | struct list_head * p; | 402 | struct list_head * p; |
428 | struct nvram_partition * part; | 403 | struct nvram_partition * part; |
@@ -480,7 +455,7 @@ static int nvram_setup_partition(void) | |||
480 | } | 455 | } |
481 | 456 | ||
482 | 457 | ||
483 | static int nvram_scan_partitions(void) | 458 | static int __init nvram_scan_partitions(void) |
484 | { | 459 | { |
485 | loff_t cur_index = 0; | 460 | loff_t cur_index = 0; |
486 | struct nvram_header phead; | 461 | struct nvram_header phead; |
@@ -706,6 +681,9 @@ int nvram_clear_error_log(void) | |||
706 | int clear_word = ERR_FLAG_ALREADY_LOGGED; | 681 | int clear_word = ERR_FLAG_ALREADY_LOGGED; |
707 | int rc; | 682 | int rc; |
708 | 683 | ||
684 | if (nvram_error_log_index == -1) | ||
685 | return -1; | ||
686 | |||
709 | tmp_index = nvram_error_log_index; | 687 | tmp_index = nvram_error_log_index; |
710 | 688 | ||
711 | rc = ppc_md.nvram_write((char *)&clear_word, sizeof(int), &tmp_index); | 689 | rc = ppc_md.nvram_write((char *)&clear_word, sizeof(int), &tmp_index); |
diff --git a/arch/powerpc/kernel/perf_callchain.c b/arch/powerpc/kernel/perf_callchain.c index 0a03cf70d247..936f04dbfc6f 100644 --- a/arch/powerpc/kernel/perf_callchain.c +++ b/arch/powerpc/kernel/perf_callchain.c | |||
@@ -119,13 +119,6 @@ static void perf_callchain_kernel(struct pt_regs *regs, | |||
119 | } | 119 | } |
120 | 120 | ||
121 | #ifdef CONFIG_PPC64 | 121 | #ifdef CONFIG_PPC64 |
122 | |||
123 | #ifdef CONFIG_HUGETLB_PAGE | ||
124 | #define is_huge_psize(pagesize) (HPAGE_SHIFT && mmu_huge_psizes[pagesize]) | ||
125 | #else | ||
126 | #define is_huge_psize(pagesize) 0 | ||
127 | #endif | ||
128 | |||
129 | /* | 122 | /* |
130 | * On 64-bit we don't want to invoke hash_page on user addresses from | 123 | * On 64-bit we don't want to invoke hash_page on user addresses from |
131 | * interrupt context, so if the access faults, we read the page tables | 124 | * interrupt context, so if the access faults, we read the page tables |
@@ -135,7 +128,7 @@ static int read_user_stack_slow(void __user *ptr, void *ret, int nb) | |||
135 | { | 128 | { |
136 | pgd_t *pgdir; | 129 | pgd_t *pgdir; |
137 | pte_t *ptep, pte; | 130 | pte_t *ptep, pte; |
138 | int pagesize; | 131 | unsigned shift; |
139 | unsigned long addr = (unsigned long) ptr; | 132 | unsigned long addr = (unsigned long) ptr; |
140 | unsigned long offset; | 133 | unsigned long offset; |
141 | unsigned long pfn; | 134 | unsigned long pfn; |
@@ -145,17 +138,14 @@ static int read_user_stack_slow(void __user *ptr, void *ret, int nb) | |||
145 | if (!pgdir) | 138 | if (!pgdir) |
146 | return -EFAULT; | 139 | return -EFAULT; |
147 | 140 | ||
148 | pagesize = get_slice_psize(current->mm, addr); | 141 | ptep = find_linux_pte_or_hugepte(pgdir, addr, &shift); |
142 | if (!shift) | ||
143 | shift = PAGE_SHIFT; | ||
149 | 144 | ||
150 | /* align address to page boundary */ | 145 | /* align address to page boundary */ |
151 | offset = addr & ((1ul << mmu_psize_defs[pagesize].shift) - 1); | 146 | offset = addr & ((1UL << shift) - 1); |
152 | addr -= offset; | 147 | addr -= offset; |
153 | 148 | ||
154 | if (is_huge_psize(pagesize)) | ||
155 | ptep = huge_pte_offset(current->mm, addr); | ||
156 | else | ||
157 | ptep = find_linux_pte(pgdir, addr); | ||
158 | |||
159 | if (ptep == NULL) | 149 | if (ptep == NULL) |
160 | return -EFAULT; | 150 | return -EFAULT; |
161 | pte = *ptep; | 151 | pte = *ptep; |
diff --git a/arch/powerpc/kernel/ppc_ksyms.c b/arch/powerpc/kernel/ppc_ksyms.c index c8b27bb4dbde..425451453e96 100644 --- a/arch/powerpc/kernel/ppc_ksyms.c +++ b/arch/powerpc/kernel/ppc_ksyms.c | |||
@@ -96,8 +96,6 @@ EXPORT_SYMBOL(copy_4K_page); | |||
96 | EXPORT_SYMBOL(isa_io_base); | 96 | EXPORT_SYMBOL(isa_io_base); |
97 | EXPORT_SYMBOL(isa_mem_base); | 97 | EXPORT_SYMBOL(isa_mem_base); |
98 | EXPORT_SYMBOL(pci_dram_offset); | 98 | EXPORT_SYMBOL(pci_dram_offset); |
99 | EXPORT_SYMBOL(pci_alloc_consistent); | ||
100 | EXPORT_SYMBOL(pci_free_consistent); | ||
101 | #endif /* CONFIG_PCI */ | 99 | #endif /* CONFIG_PCI */ |
102 | 100 | ||
103 | EXPORT_SYMBOL(start_thread); | 101 | EXPORT_SYMBOL(start_thread); |
@@ -162,7 +160,6 @@ EXPORT_SYMBOL(screen_info); | |||
162 | 160 | ||
163 | #ifdef CONFIG_PPC32 | 161 | #ifdef CONFIG_PPC32 |
164 | EXPORT_SYMBOL(timer_interrupt); | 162 | EXPORT_SYMBOL(timer_interrupt); |
165 | EXPORT_SYMBOL(irq_desc); | ||
166 | EXPORT_SYMBOL(tb_ticks_per_jiffy); | 163 | EXPORT_SYMBOL(tb_ticks_per_jiffy); |
167 | EXPORT_SYMBOL(cacheable_memcpy); | 164 | EXPORT_SYMBOL(cacheable_memcpy); |
168 | EXPORT_SYMBOL(cacheable_memzero); | 165 | EXPORT_SYMBOL(cacheable_memzero); |
diff --git a/arch/powerpc/kernel/proc_ppc64.c b/arch/powerpc/kernel/proc_powerpc.c index c647ddef40dc..1ed3b8d7981e 100644 --- a/arch/powerpc/kernel/proc_ppc64.c +++ b/arch/powerpc/kernel/proc_powerpc.c | |||
@@ -28,55 +28,7 @@ | |||
28 | #include <asm/uaccess.h> | 28 | #include <asm/uaccess.h> |
29 | #include <asm/prom.h> | 29 | #include <asm/prom.h> |
30 | 30 | ||
31 | static loff_t page_map_seek( struct file *file, loff_t off, int whence); | 31 | #ifdef CONFIG_PPC64 |
32 | static ssize_t page_map_read( struct file *file, char __user *buf, size_t nbytes, | ||
33 | loff_t *ppos); | ||
34 | static int page_map_mmap( struct file *file, struct vm_area_struct *vma ); | ||
35 | |||
36 | static const struct file_operations page_map_fops = { | ||
37 | .llseek = page_map_seek, | ||
38 | .read = page_map_read, | ||
39 | .mmap = page_map_mmap | ||
40 | }; | ||
41 | |||
42 | /* | ||
43 | * Create the ppc64 and ppc64/rtas directories early. This allows us to | ||
44 | * assume that they have been previously created in drivers. | ||
45 | */ | ||
46 | static int __init proc_ppc64_create(void) | ||
47 | { | ||
48 | struct proc_dir_entry *root; | ||
49 | |||
50 | root = proc_mkdir("ppc64", NULL); | ||
51 | if (!root) | ||
52 | return 1; | ||
53 | |||
54 | if (!of_find_node_by_path("/rtas")) | ||
55 | return 0; | ||
56 | |||
57 | if (!proc_mkdir("rtas", root)) | ||
58 | return 1; | ||
59 | |||
60 | if (!proc_symlink("rtas", NULL, "ppc64/rtas")) | ||
61 | return 1; | ||
62 | |||
63 | return 0; | ||
64 | } | ||
65 | core_initcall(proc_ppc64_create); | ||
66 | |||
67 | static int __init proc_ppc64_init(void) | ||
68 | { | ||
69 | struct proc_dir_entry *pde; | ||
70 | |||
71 | pde = proc_create_data("ppc64/systemcfg", S_IFREG|S_IRUGO, NULL, | ||
72 | &page_map_fops, vdso_data); | ||
73 | if (!pde) | ||
74 | return 1; | ||
75 | pde->size = PAGE_SIZE; | ||
76 | |||
77 | return 0; | ||
78 | } | ||
79 | __initcall(proc_ppc64_init); | ||
80 | 32 | ||
81 | static loff_t page_map_seek( struct file *file, loff_t off, int whence) | 33 | static loff_t page_map_seek( struct file *file, loff_t off, int whence) |
82 | { | 34 | { |
@@ -120,3 +72,55 @@ static int page_map_mmap( struct file *file, struct vm_area_struct *vma ) | |||
120 | return 0; | 72 | return 0; |
121 | } | 73 | } |
122 | 74 | ||
75 | static const struct file_operations page_map_fops = { | ||
76 | .llseek = page_map_seek, | ||
77 | .read = page_map_read, | ||
78 | .mmap = page_map_mmap | ||
79 | }; | ||
80 | |||
81 | |||
82 | static int __init proc_ppc64_init(void) | ||
83 | { | ||
84 | struct proc_dir_entry *pde; | ||
85 | |||
86 | pde = proc_create_data("powerpc/systemcfg", S_IFREG|S_IRUGO, NULL, | ||
87 | &page_map_fops, vdso_data); | ||
88 | if (!pde) | ||
89 | return 1; | ||
90 | pde->size = PAGE_SIZE; | ||
91 | |||
92 | return 0; | ||
93 | } | ||
94 | __initcall(proc_ppc64_init); | ||
95 | |||
96 | #endif /* CONFIG_PPC64 */ | ||
97 | |||
98 | /* | ||
99 | * Create the ppc64 and ppc64/rtas directories early. This allows us to | ||
100 | * assume that they have been previously created in drivers. | ||
101 | */ | ||
102 | static int __init proc_ppc64_create(void) | ||
103 | { | ||
104 | struct proc_dir_entry *root; | ||
105 | |||
106 | root = proc_mkdir("powerpc", NULL); | ||
107 | if (!root) | ||
108 | return 1; | ||
109 | |||
110 | #ifdef CONFIG_PPC64 | ||
111 | if (!proc_symlink("ppc64", NULL, "powerpc")) | ||
112 | pr_err("Failed to create link /proc/ppc64 -> /proc/powerpc\n"); | ||
113 | #endif | ||
114 | |||
115 | if (!of_find_node_by_path("/rtas")) | ||
116 | return 0; | ||
117 | |||
118 | if (!proc_mkdir("rtas", root)) | ||
119 | return 1; | ||
120 | |||
121 | if (!proc_symlink("rtas", NULL, "powerpc/rtas")) | ||
122 | return 1; | ||
123 | |||
124 | return 0; | ||
125 | } | ||
126 | core_initcall(proc_ppc64_create); | ||
diff --git a/arch/powerpc/kernel/rtas_flash.c b/arch/powerpc/kernel/rtas_flash.c index 13011a96a977..a85117d5c9a4 100644 --- a/arch/powerpc/kernel/rtas_flash.c +++ b/arch/powerpc/kernel/rtas_flash.c | |||
@@ -6,7 +6,7 @@ | |||
6 | * as published by the Free Software Foundation; either version | 6 | * as published by the Free Software Foundation; either version |
7 | * 2 of the License, or (at your option) any later version. | 7 | * 2 of the License, or (at your option) any later version. |
8 | * | 8 | * |
9 | * /proc/ppc64/rtas/firmware_flash interface | 9 | * /proc/powerpc/rtas/firmware_flash interface |
10 | * | 10 | * |
11 | * This file implements a firmware_flash interface to pump a firmware | 11 | * This file implements a firmware_flash interface to pump a firmware |
12 | * image into the kernel. At reboot time rtas_restart() will see the | 12 | * image into the kernel. At reboot time rtas_restart() will see the |
@@ -740,7 +740,7 @@ static int __init rtas_flash_init(void) | |||
740 | return 1; | 740 | return 1; |
741 | } | 741 | } |
742 | 742 | ||
743 | firmware_flash_pde = create_flash_pde("ppc64/rtas/" | 743 | firmware_flash_pde = create_flash_pde("powerpc/rtas/" |
744 | FIRMWARE_FLASH_NAME, | 744 | FIRMWARE_FLASH_NAME, |
745 | &rtas_flash_operations); | 745 | &rtas_flash_operations); |
746 | if (firmware_flash_pde == NULL) { | 746 | if (firmware_flash_pde == NULL) { |
@@ -754,7 +754,7 @@ static int __init rtas_flash_init(void) | |||
754 | if (rc != 0) | 754 | if (rc != 0) |
755 | goto cleanup; | 755 | goto cleanup; |
756 | 756 | ||
757 | firmware_update_pde = create_flash_pde("ppc64/rtas/" | 757 | firmware_update_pde = create_flash_pde("powerpc/rtas/" |
758 | FIRMWARE_UPDATE_NAME, | 758 | FIRMWARE_UPDATE_NAME, |
759 | &rtas_flash_operations); | 759 | &rtas_flash_operations); |
760 | if (firmware_update_pde == NULL) { | 760 | if (firmware_update_pde == NULL) { |
@@ -768,7 +768,7 @@ static int __init rtas_flash_init(void) | |||
768 | if (rc != 0) | 768 | if (rc != 0) |
769 | goto cleanup; | 769 | goto cleanup; |
770 | 770 | ||
771 | validate_pde = create_flash_pde("ppc64/rtas/" VALIDATE_FLASH_NAME, | 771 | validate_pde = create_flash_pde("powerpc/rtas/" VALIDATE_FLASH_NAME, |
772 | &validate_flash_operations); | 772 | &validate_flash_operations); |
773 | if (validate_pde == NULL) { | 773 | if (validate_pde == NULL) { |
774 | rc = -ENOMEM; | 774 | rc = -ENOMEM; |
@@ -781,7 +781,7 @@ static int __init rtas_flash_init(void) | |||
781 | if (rc != 0) | 781 | if (rc != 0) |
782 | goto cleanup; | 782 | goto cleanup; |
783 | 783 | ||
784 | manage_pde = create_flash_pde("ppc64/rtas/" MANAGE_FLASH_NAME, | 784 | manage_pde = create_flash_pde("powerpc/rtas/" MANAGE_FLASH_NAME, |
785 | &manage_flash_operations); | 785 | &manage_flash_operations); |
786 | if (manage_pde == NULL) { | 786 | if (manage_pde == NULL) { |
787 | rc = -ENOMEM; | 787 | rc = -ENOMEM; |
diff --git a/arch/powerpc/platforms/pseries/rtasd.c b/arch/powerpc/kernel/rtasd.c index b3cbac855924..2e4832ab2108 100644 --- a/arch/powerpc/platforms/pseries/rtasd.c +++ b/arch/powerpc/kernel/rtasd.c | |||
@@ -39,6 +39,7 @@ static unsigned long rtas_log_start; | |||
39 | static unsigned long rtas_log_size; | 39 | static unsigned long rtas_log_size; |
40 | 40 | ||
41 | static int surveillance_timeout = -1; | 41 | static int surveillance_timeout = -1; |
42 | |||
42 | static unsigned int rtas_error_log_max; | 43 | static unsigned int rtas_error_log_max; |
43 | static unsigned int rtas_error_log_buffer_max; | 44 | static unsigned int rtas_error_log_buffer_max; |
44 | 45 | ||
@@ -213,9 +214,11 @@ void pSeries_log_error(char *buf, unsigned int err_type, int fatal) | |||
213 | return; | 214 | return; |
214 | } | 215 | } |
215 | 216 | ||
217 | #ifdef CONFIG_PPC64 | ||
216 | /* Write error to NVRAM */ | 218 | /* Write error to NVRAM */ |
217 | if (logging_enabled && !(err_type & ERR_FLAG_BOOT)) | 219 | if (logging_enabled && !(err_type & ERR_FLAG_BOOT)) |
218 | nvram_write_error_log(buf, len, err_type, error_log_cnt); | 220 | nvram_write_error_log(buf, len, err_type, error_log_cnt); |
221 | #endif /* CONFIG_PPC64 */ | ||
219 | 222 | ||
220 | /* | 223 | /* |
221 | * rtas errors can occur during boot, and we do want to capture | 224 | * rtas errors can occur during boot, and we do want to capture |
@@ -264,7 +267,6 @@ void pSeries_log_error(char *buf, unsigned int err_type, int fatal) | |||
264 | 267 | ||
265 | } | 268 | } |
266 | 269 | ||
267 | |||
268 | static int rtas_log_open(struct inode * inode, struct file * file) | 270 | static int rtas_log_open(struct inode * inode, struct file * file) |
269 | { | 271 | { |
270 | return 0; | 272 | return 0; |
@@ -300,6 +302,7 @@ static ssize_t rtas_log_read(struct file * file, char __user * buf, | |||
300 | return -ENOMEM; | 302 | return -ENOMEM; |
301 | 303 | ||
302 | spin_lock_irqsave(&rtasd_log_lock, s); | 304 | spin_lock_irqsave(&rtasd_log_lock, s); |
305 | |||
303 | /* if it's 0, then we know we got the last one (the one in NVRAM) */ | 306 | /* if it's 0, then we know we got the last one (the one in NVRAM) */ |
304 | while (rtas_log_size == 0) { | 307 | while (rtas_log_size == 0) { |
305 | if (file->f_flags & O_NONBLOCK) { | 308 | if (file->f_flags & O_NONBLOCK) { |
@@ -313,7 +316,9 @@ static ssize_t rtas_log_read(struct file * file, char __user * buf, | |||
313 | error = -ENODATA; | 316 | error = -ENODATA; |
314 | goto out; | 317 | goto out; |
315 | } | 318 | } |
319 | #ifdef CONFIG_PPC64 | ||
316 | nvram_clear_error_log(); | 320 | nvram_clear_error_log(); |
321 | #endif /* CONFIG_PPC64 */ | ||
317 | 322 | ||
318 | spin_unlock_irqrestore(&rtasd_log_lock, s); | 323 | spin_unlock_irqrestore(&rtasd_log_lock, s); |
319 | error = wait_event_interruptible(rtas_log_wait, rtas_log_size); | 324 | error = wait_event_interruptible(rtas_log_wait, rtas_log_size); |
@@ -427,14 +432,11 @@ static void rtas_event_scan(struct work_struct *w) | |||
427 | put_online_cpus(); | 432 | put_online_cpus(); |
428 | } | 433 | } |
429 | 434 | ||
430 | static void start_event_scan(void) | 435 | #ifdef CONFIG_PPC64 |
436 | static void retreive_nvram_error_log(void) | ||
431 | { | 437 | { |
432 | unsigned int err_type; | 438 | unsigned int err_type ; |
433 | int rc; | 439 | int rc ; |
434 | |||
435 | printk(KERN_DEBUG "RTAS daemon started\n"); | ||
436 | pr_debug("rtasd: will sleep for %d milliseconds\n", | ||
437 | (30000 / rtas_event_scan_rate)); | ||
438 | 440 | ||
439 | /* See if we have any error stored in NVRAM */ | 441 | /* See if we have any error stored in NVRAM */ |
440 | memset(logdata, 0, rtas_error_log_max); | 442 | memset(logdata, 0, rtas_error_log_max); |
@@ -442,12 +444,26 @@ static void start_event_scan(void) | |||
442 | &err_type, &error_log_cnt); | 444 | &err_type, &error_log_cnt); |
443 | /* We can use rtas_log_buf now */ | 445 | /* We can use rtas_log_buf now */ |
444 | logging_enabled = 1; | 446 | logging_enabled = 1; |
445 | |||
446 | if (!rc) { | 447 | if (!rc) { |
447 | if (err_type != ERR_FLAG_ALREADY_LOGGED) { | 448 | if (err_type != ERR_FLAG_ALREADY_LOGGED) { |
448 | pSeries_log_error(logdata, err_type | ERR_FLAG_BOOT, 0); | 449 | pSeries_log_error(logdata, err_type | ERR_FLAG_BOOT, 0); |
449 | } | 450 | } |
450 | } | 451 | } |
452 | } | ||
453 | #else /* CONFIG_PPC64 */ | ||
454 | static void retreive_nvram_error_log(void) | ||
455 | { | ||
456 | } | ||
457 | #endif /* CONFIG_PPC64 */ | ||
458 | |||
459 | static void start_event_scan(void) | ||
460 | { | ||
461 | printk(KERN_DEBUG "RTAS daemon started\n"); | ||
462 | pr_debug("rtasd: will sleep for %d milliseconds\n", | ||
463 | (30000 / rtas_event_scan_rate)); | ||
464 | |||
465 | /* Retreive errors from nvram if any */ | ||
466 | retreive_nvram_error_log(); | ||
451 | 467 | ||
452 | schedule_delayed_work_on(first_cpu(cpu_online_map), &event_scan_work, | 468 | schedule_delayed_work_on(first_cpu(cpu_online_map), &event_scan_work, |
453 | event_scan_delay); | 469 | event_scan_delay); |
@@ -457,13 +473,13 @@ static int __init rtas_init(void) | |||
457 | { | 473 | { |
458 | struct proc_dir_entry *entry; | 474 | struct proc_dir_entry *entry; |
459 | 475 | ||
460 | if (!machine_is(pseries)) | 476 | if (!machine_is(pseries) && !machine_is(chrp)) |
461 | return 0; | 477 | return 0; |
462 | 478 | ||
463 | /* No RTAS */ | 479 | /* No RTAS */ |
464 | event_scan = rtas_token("event-scan"); | 480 | event_scan = rtas_token("event-scan"); |
465 | if (event_scan == RTAS_UNKNOWN_SERVICE) { | 481 | if (event_scan == RTAS_UNKNOWN_SERVICE) { |
466 | printk(KERN_DEBUG "rtasd: no event-scan on system\n"); | 482 | printk(KERN_INFO "rtasd: No event-scan on system\n"); |
467 | return -ENODEV; | 483 | return -ENODEV; |
468 | } | 484 | } |
469 | 485 | ||
@@ -483,7 +499,7 @@ static int __init rtas_init(void) | |||
483 | return -ENOMEM; | 499 | return -ENOMEM; |
484 | } | 500 | } |
485 | 501 | ||
486 | entry = proc_create("ppc64/rtas/error_log", S_IRUSR, NULL, | 502 | entry = proc_create("powerpc/rtas/error_log", S_IRUSR, NULL, |
487 | &proc_rtas_log_operations); | 503 | &proc_rtas_log_operations); |
488 | if (!entry) | 504 | if (!entry) |
489 | printk(KERN_ERR "Failed to create error_log proc entry\n"); | 505 | printk(KERN_ERR "Failed to create error_log proc entry\n"); |
@@ -492,11 +508,16 @@ static int __init rtas_init(void) | |||
492 | 508 | ||
493 | return 0; | 509 | return 0; |
494 | } | 510 | } |
511 | __initcall(rtas_init); | ||
495 | 512 | ||
496 | static int __init surveillance_setup(char *str) | 513 | static int __init surveillance_setup(char *str) |
497 | { | 514 | { |
498 | int i; | 515 | int i; |
499 | 516 | ||
517 | /* We only do surveillance on pseries */ | ||
518 | if (!machine_is(pseries)) | ||
519 | return 0; | ||
520 | |||
500 | if (get_option(&str,&i)) { | 521 | if (get_option(&str,&i)) { |
501 | if (i >= 0 && i <= 255) | 522 | if (i >= 0 && i <= 255) |
502 | surveillance_timeout = i; | 523 | surveillance_timeout = i; |
@@ -504,6 +525,7 @@ static int __init surveillance_setup(char *str) | |||
504 | 525 | ||
505 | return 1; | 526 | return 1; |
506 | } | 527 | } |
528 | __setup("surveillance=", surveillance_setup); | ||
507 | 529 | ||
508 | static int __init rtasmsgs_setup(char *str) | 530 | static int __init rtasmsgs_setup(char *str) |
509 | { | 531 | { |
@@ -514,6 +536,4 @@ static int __init rtasmsgs_setup(char *str) | |||
514 | 536 | ||
515 | return 1; | 537 | return 1; |
516 | } | 538 | } |
517 | __initcall(rtas_init); | ||
518 | __setup("surveillance=", surveillance_setup); | ||
519 | __setup("rtasmsgs=", rtasmsgs_setup); | 539 | __setup("rtasmsgs=", rtasmsgs_setup); |
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c index df2c9e932b37..6568406b2a30 100644 --- a/arch/powerpc/kernel/setup_64.c +++ b/arch/powerpc/kernel/setup_64.c | |||
@@ -356,11 +356,6 @@ void __init setup_system(void) | |||
356 | */ | 356 | */ |
357 | initialize_cache_info(); | 357 | initialize_cache_info(); |
358 | 358 | ||
359 | /* | ||
360 | * Initialize irq remapping subsystem | ||
361 | */ | ||
362 | irq_early_init(); | ||
363 | |||
364 | #ifdef CONFIG_PPC_RTAS | 359 | #ifdef CONFIG_PPC_RTAS |
365 | /* | 360 | /* |
366 | * Initialize RTAS if available | 361 | * Initialize RTAS if available |
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c index 9b86a74d2815..97196eefef3e 100644 --- a/arch/powerpc/kernel/smp.c +++ b/arch/powerpc/kernel/smp.c | |||
@@ -218,6 +218,9 @@ void crash_send_ipi(void (*crash_ipi_callback)(struct pt_regs *)) | |||
218 | 218 | ||
219 | static void stop_this_cpu(void *dummy) | 219 | static void stop_this_cpu(void *dummy) |
220 | { | 220 | { |
221 | /* Remove this CPU */ | ||
222 | set_cpu_online(smp_processor_id(), false); | ||
223 | |||
221 | local_irq_disable(); | 224 | local_irq_disable(); |
222 | while (1) | 225 | while (1) |
223 | ; | 226 | ; |
diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c index 956ab33fd73f..e235e52dc4fe 100644 --- a/arch/powerpc/kernel/sysfs.c +++ b/arch/powerpc/kernel/sysfs.c | |||
@@ -461,6 +461,25 @@ static void unregister_cpu_online(unsigned int cpu) | |||
461 | 461 | ||
462 | cacheinfo_cpu_offline(cpu); | 462 | cacheinfo_cpu_offline(cpu); |
463 | } | 463 | } |
464 | |||
465 | #ifdef CONFIG_ARCH_CPU_PROBE_RELEASE | ||
466 | ssize_t arch_cpu_probe(const char *buf, size_t count) | ||
467 | { | ||
468 | if (ppc_md.cpu_probe) | ||
469 | return ppc_md.cpu_probe(buf, count); | ||
470 | |||
471 | return -EINVAL; | ||
472 | } | ||
473 | |||
474 | ssize_t arch_cpu_release(const char *buf, size_t count) | ||
475 | { | ||
476 | if (ppc_md.cpu_release) | ||
477 | return ppc_md.cpu_release(buf, count); | ||
478 | |||
479 | return -EINVAL; | ||
480 | } | ||
481 | #endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */ | ||
482 | |||
464 | #endif /* CONFIG_HOTPLUG_CPU */ | 483 | #endif /* CONFIG_HOTPLUG_CPU */ |
465 | 484 | ||
466 | static int __cpuinit sysfs_cpu_notify(struct notifier_block *self, | 485 | static int __cpuinit sysfs_cpu_notify(struct notifier_block *self, |
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 674800b242d6..9ba2cc88591d 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c | |||
@@ -269,6 +269,7 @@ void account_system_vtime(struct task_struct *tsk) | |||
269 | per_cpu(cputime_scaled_last_delta, smp_processor_id()) = deltascaled; | 269 | per_cpu(cputime_scaled_last_delta, smp_processor_id()) = deltascaled; |
270 | local_irq_restore(flags); | 270 | local_irq_restore(flags); |
271 | } | 271 | } |
272 | EXPORT_SYMBOL_GPL(account_system_vtime); | ||
272 | 273 | ||
273 | /* | 274 | /* |
274 | * Transfer the user and system times accumulated in the paca | 275 | * Transfer the user and system times accumulated in the paca |
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 9d1f9354d6ca..804f0f30f227 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c | |||
@@ -198,28 +198,6 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) | |||
198 | info.si_code = code; | 198 | info.si_code = code; |
199 | info.si_addr = (void __user *) addr; | 199 | info.si_addr = (void __user *) addr; |
200 | force_sig_info(signr, &info, current); | 200 | force_sig_info(signr, &info, current); |
201 | |||
202 | /* | ||
203 | * Init gets no signals that it doesn't have a handler for. | ||
204 | * That's all very well, but if it has caused a synchronous | ||
205 | * exception and we ignore the resulting signal, it will just | ||
206 | * generate the same exception over and over again and we get | ||
207 | * nowhere. Better to kill it and let the kernel panic. | ||
208 | */ | ||
209 | if (is_global_init(current)) { | ||
210 | __sighandler_t handler; | ||
211 | |||
212 | spin_lock_irq(¤t->sighand->siglock); | ||
213 | handler = current->sighand->action[signr-1].sa.sa_handler; | ||
214 | spin_unlock_irq(¤t->sighand->siglock); | ||
215 | if (handler == SIG_DFL) { | ||
216 | /* init has generated a synchronous exception | ||
217 | and it doesn't have a handler for the signal */ | ||
218 | printk(KERN_CRIT "init has generated signal %d " | ||
219 | "but has no handler for it\n", signr); | ||
220 | do_exit(signr); | ||
221 | } | ||
222 | } | ||
223 | } | 201 | } |
224 | 202 | ||
225 | #ifdef CONFIG_PPC64 | 203 | #ifdef CONFIG_PPC64 |
diff --git a/arch/powerpc/kernel/vector.S b/arch/powerpc/kernel/vector.S index 67b6916f0e94..fe460482fa68 100644 --- a/arch/powerpc/kernel/vector.S +++ b/arch/powerpc/kernel/vector.S | |||
@@ -58,7 +58,7 @@ _GLOBAL(load_up_altivec) | |||
58 | * all 1's | 58 | * all 1's |
59 | */ | 59 | */ |
60 | mfspr r4,SPRN_VRSAVE | 60 | mfspr r4,SPRN_VRSAVE |
61 | cmpdi 0,r4,0 | 61 | cmpwi 0,r4,0 |
62 | bne+ 1f | 62 | bne+ 1f |
63 | li r4,-1 | 63 | li r4,-1 |
64 | mtspr SPRN_VRSAVE,r4 | 64 | mtspr SPRN_VRSAVE,r4 |
diff --git a/arch/powerpc/kvm/Kconfig b/arch/powerpc/kvm/Kconfig index c29926846613..07703f72330e 100644 --- a/arch/powerpc/kvm/Kconfig +++ b/arch/powerpc/kvm/Kconfig | |||
@@ -21,6 +21,23 @@ config KVM | |||
21 | select PREEMPT_NOTIFIERS | 21 | select PREEMPT_NOTIFIERS |
22 | select ANON_INODES | 22 | select ANON_INODES |
23 | 23 | ||
24 | config KVM_BOOK3S_64_HANDLER | ||
25 | bool | ||
26 | |||
27 | config KVM_BOOK3S_64 | ||
28 | tristate "KVM support for PowerPC book3s_64 processors" | ||
29 | depends on EXPERIMENTAL && PPC64 | ||
30 | select KVM | ||
31 | select KVM_BOOK3S_64_HANDLER | ||
32 | ---help--- | ||
33 | Support running unmodified book3s_64 and book3s_32 guest kernels | ||
34 | in virtual machines on book3s_64 host processors. | ||
35 | |||
36 | This module provides access to the hardware capabilities through | ||
37 | a character device node named /dev/kvm. | ||
38 | |||
39 | If unsure, say N. | ||
40 | |||
24 | config KVM_440 | 41 | config KVM_440 |
25 | bool "KVM support for PowerPC 440 processors" | 42 | bool "KVM support for PowerPC 440 processors" |
26 | depends on EXPERIMENTAL && 44x | 43 | depends on EXPERIMENTAL && 44x |
diff --git a/arch/powerpc/kvm/Makefile b/arch/powerpc/kvm/Makefile index 37655fe19f2f..56484d652377 100644 --- a/arch/powerpc/kvm/Makefile +++ b/arch/powerpc/kvm/Makefile | |||
@@ -12,26 +12,45 @@ CFLAGS_44x_tlb.o := -I. | |||
12 | CFLAGS_e500_tlb.o := -I. | 12 | CFLAGS_e500_tlb.o := -I. |
13 | CFLAGS_emulate.o := -I. | 13 | CFLAGS_emulate.o := -I. |
14 | 14 | ||
15 | kvm-objs := $(common-objs-y) powerpc.o emulate.o | 15 | common-objs-y += powerpc.o emulate.o |
16 | obj-$(CONFIG_KVM_EXIT_TIMING) += timing.o | 16 | obj-$(CONFIG_KVM_EXIT_TIMING) += timing.o |
17 | obj-$(CONFIG_KVM) += kvm.o | 17 | obj-$(CONFIG_KVM_BOOK3S_64_HANDLER) += book3s_64_exports.o |
18 | 18 | ||
19 | AFLAGS_booke_interrupts.o := -I$(obj) | 19 | AFLAGS_booke_interrupts.o := -I$(obj) |
20 | 20 | ||
21 | kvm-440-objs := \ | 21 | kvm-440-objs := \ |
22 | $(common-objs-y) \ | ||
22 | booke.o \ | 23 | booke.o \ |
23 | booke_emulate.o \ | 24 | booke_emulate.o \ |
24 | booke_interrupts.o \ | 25 | booke_interrupts.o \ |
25 | 44x.o \ | 26 | 44x.o \ |
26 | 44x_tlb.o \ | 27 | 44x_tlb.o \ |
27 | 44x_emulate.o | 28 | 44x_emulate.o |
28 | obj-$(CONFIG_KVM_440) += kvm-440.o | 29 | kvm-objs-$(CONFIG_KVM_440) := $(kvm-440-objs) |
29 | 30 | ||
30 | kvm-e500-objs := \ | 31 | kvm-e500-objs := \ |
32 | $(common-objs-y) \ | ||
31 | booke.o \ | 33 | booke.o \ |
32 | booke_emulate.o \ | 34 | booke_emulate.o \ |
33 | booke_interrupts.o \ | 35 | booke_interrupts.o \ |
34 | e500.o \ | 36 | e500.o \ |
35 | e500_tlb.o \ | 37 | e500_tlb.o \ |
36 | e500_emulate.o | 38 | e500_emulate.o |
37 | obj-$(CONFIG_KVM_E500) += kvm-e500.o | 39 | kvm-objs-$(CONFIG_KVM_E500) := $(kvm-e500-objs) |
40 | |||
41 | kvm-book3s_64-objs := \ | ||
42 | $(common-objs-y) \ | ||
43 | book3s.o \ | ||
44 | book3s_64_emulate.o \ | ||
45 | book3s_64_interrupts.o \ | ||
46 | book3s_64_mmu_host.o \ | ||
47 | book3s_64_mmu.o \ | ||
48 | book3s_32_mmu.o | ||
49 | kvm-objs-$(CONFIG_KVM_BOOK3S_64) := $(kvm-book3s_64-objs) | ||
50 | |||
51 | kvm-objs := $(kvm-objs-m) $(kvm-objs-y) | ||
52 | |||
53 | obj-$(CONFIG_KVM_440) += kvm.o | ||
54 | obj-$(CONFIG_KVM_E500) += kvm.o | ||
55 | obj-$(CONFIG_KVM_BOOK3S_64) += kvm.o | ||
56 | |||
diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c new file mode 100644 index 000000000000..3e294bd9b8c6 --- /dev/null +++ b/arch/powerpc/kvm/book3s.c | |||
@@ -0,0 +1,974 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009. SUSE Linux Products GmbH. All rights reserved. | ||
3 | * | ||
4 | * Authors: | ||
5 | * Alexander Graf <agraf@suse.de> | ||
6 | * Kevin Wolf <mail@kevin-wolf.de> | ||
7 | * | ||
8 | * Description: | ||
9 | * This file is derived from arch/powerpc/kvm/44x.c, | ||
10 | * by Hollis Blanchard <hollisb@us.ibm.com>. | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License, version 2, as | ||
14 | * published by the Free Software Foundation. | ||
15 | */ | ||
16 | |||
17 | #include <linux/kvm_host.h> | ||
18 | #include <linux/err.h> | ||
19 | |||
20 | #include <asm/reg.h> | ||
21 | #include <asm/cputable.h> | ||
22 | #include <asm/cacheflush.h> | ||
23 | #include <asm/tlbflush.h> | ||
24 | #include <asm/uaccess.h> | ||
25 | #include <asm/io.h> | ||
26 | #include <asm/kvm_ppc.h> | ||
27 | #include <asm/kvm_book3s.h> | ||
28 | #include <asm/mmu_context.h> | ||
29 | #include <linux/sched.h> | ||
30 | #include <linux/vmalloc.h> | ||
31 | |||
32 | #define VCPU_STAT(x) offsetof(struct kvm_vcpu, stat.x), KVM_STAT_VCPU | ||
33 | |||
34 | /* #define EXIT_DEBUG */ | ||
35 | /* #define EXIT_DEBUG_SIMPLE */ | ||
36 | |||
37 | /* Without AGGRESSIVE_DEC we only fire off a DEC interrupt when DEC turns 0. | ||
38 | * When set, we retrigger a DEC interrupt after that if DEC <= 0. | ||
39 | * PPC32 Linux runs faster without AGGRESSIVE_DEC, PPC64 Linux requires it. */ | ||
40 | |||
41 | /* #define AGGRESSIVE_DEC */ | ||
42 | |||
43 | struct kvm_stats_debugfs_item debugfs_entries[] = { | ||
44 | { "exits", VCPU_STAT(sum_exits) }, | ||
45 | { "mmio", VCPU_STAT(mmio_exits) }, | ||
46 | { "sig", VCPU_STAT(signal_exits) }, | ||
47 | { "sysc", VCPU_STAT(syscall_exits) }, | ||
48 | { "inst_emu", VCPU_STAT(emulated_inst_exits) }, | ||
49 | { "dec", VCPU_STAT(dec_exits) }, | ||
50 | { "ext_intr", VCPU_STAT(ext_intr_exits) }, | ||
51 | { "queue_intr", VCPU_STAT(queue_intr) }, | ||
52 | { "halt_wakeup", VCPU_STAT(halt_wakeup) }, | ||
53 | { "pf_storage", VCPU_STAT(pf_storage) }, | ||
54 | { "sp_storage", VCPU_STAT(sp_storage) }, | ||
55 | { "pf_instruc", VCPU_STAT(pf_instruc) }, | ||
56 | { "sp_instruc", VCPU_STAT(sp_instruc) }, | ||
57 | { "ld", VCPU_STAT(ld) }, | ||
58 | { "ld_slow", VCPU_STAT(ld_slow) }, | ||
59 | { "st", VCPU_STAT(st) }, | ||
60 | { "st_slow", VCPU_STAT(st_slow) }, | ||
61 | { NULL } | ||
62 | }; | ||
63 | |||
64 | void kvmppc_core_load_host_debugstate(struct kvm_vcpu *vcpu) | ||
65 | { | ||
66 | } | ||
67 | |||
68 | void kvmppc_core_load_guest_debugstate(struct kvm_vcpu *vcpu) | ||
69 | { | ||
70 | } | ||
71 | |||
72 | void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu) | ||
73 | { | ||
74 | memcpy(get_paca()->kvm_slb, to_book3s(vcpu)->slb_shadow, sizeof(get_paca()->kvm_slb)); | ||
75 | get_paca()->kvm_slb_max = to_book3s(vcpu)->slb_shadow_max; | ||
76 | } | ||
77 | |||
78 | void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu) | ||
79 | { | ||
80 | memcpy(to_book3s(vcpu)->slb_shadow, get_paca()->kvm_slb, sizeof(get_paca()->kvm_slb)); | ||
81 | to_book3s(vcpu)->slb_shadow_max = get_paca()->kvm_slb_max; | ||
82 | } | ||
83 | |||
84 | #if defined(AGGRESSIVE_DEC) || defined(EXIT_DEBUG) | ||
85 | static u32 kvmppc_get_dec(struct kvm_vcpu *vcpu) | ||
86 | { | ||
87 | u64 jd = mftb() - vcpu->arch.dec_jiffies; | ||
88 | return vcpu->arch.dec - jd; | ||
89 | } | ||
90 | #endif | ||
91 | |||
92 | void kvmppc_set_msr(struct kvm_vcpu *vcpu, u64 msr) | ||
93 | { | ||
94 | ulong old_msr = vcpu->arch.msr; | ||
95 | |||
96 | #ifdef EXIT_DEBUG | ||
97 | printk(KERN_INFO "KVM: Set MSR to 0x%llx\n", msr); | ||
98 | #endif | ||
99 | msr &= to_book3s(vcpu)->msr_mask; | ||
100 | vcpu->arch.msr = msr; | ||
101 | vcpu->arch.shadow_msr = msr | MSR_USER32; | ||
102 | vcpu->arch.shadow_msr &= ( MSR_VEC | MSR_VSX | MSR_FP | MSR_FE0 | | ||
103 | MSR_USER64 | MSR_SE | MSR_BE | MSR_DE | | ||
104 | MSR_FE1); | ||
105 | |||
106 | if (msr & (MSR_WE|MSR_POW)) { | ||
107 | if (!vcpu->arch.pending_exceptions) { | ||
108 | kvm_vcpu_block(vcpu); | ||
109 | vcpu->stat.halt_wakeup++; | ||
110 | } | ||
111 | } | ||
112 | |||
113 | if (((vcpu->arch.msr & (MSR_IR|MSR_DR)) != (old_msr & (MSR_IR|MSR_DR))) || | ||
114 | (vcpu->arch.msr & MSR_PR) != (old_msr & MSR_PR)) { | ||
115 | kvmppc_mmu_flush_segments(vcpu); | ||
116 | kvmppc_mmu_map_segment(vcpu, vcpu->arch.pc); | ||
117 | } | ||
118 | } | ||
119 | |||
120 | void kvmppc_inject_interrupt(struct kvm_vcpu *vcpu, int vec, u64 flags) | ||
121 | { | ||
122 | vcpu->arch.srr0 = vcpu->arch.pc; | ||
123 | vcpu->arch.srr1 = vcpu->arch.msr | flags; | ||
124 | vcpu->arch.pc = to_book3s(vcpu)->hior + vec; | ||
125 | vcpu->arch.mmu.reset_msr(vcpu); | ||
126 | } | ||
127 | |||
128 | void kvmppc_book3s_queue_irqprio(struct kvm_vcpu *vcpu, unsigned int vec) | ||
129 | { | ||
130 | unsigned int prio; | ||
131 | |||
132 | vcpu->stat.queue_intr++; | ||
133 | switch (vec) { | ||
134 | case 0x100: prio = BOOK3S_IRQPRIO_SYSTEM_RESET; break; | ||
135 | case 0x200: prio = BOOK3S_IRQPRIO_MACHINE_CHECK; break; | ||
136 | case 0x300: prio = BOOK3S_IRQPRIO_DATA_STORAGE; break; | ||
137 | case 0x380: prio = BOOK3S_IRQPRIO_DATA_SEGMENT; break; | ||
138 | case 0x400: prio = BOOK3S_IRQPRIO_INST_STORAGE; break; | ||
139 | case 0x480: prio = BOOK3S_IRQPRIO_INST_SEGMENT; break; | ||
140 | case 0x500: prio = BOOK3S_IRQPRIO_EXTERNAL; break; | ||
141 | case 0x600: prio = BOOK3S_IRQPRIO_ALIGNMENT; break; | ||
142 | case 0x700: prio = BOOK3S_IRQPRIO_PROGRAM; break; | ||
143 | case 0x800: prio = BOOK3S_IRQPRIO_FP_UNAVAIL; break; | ||
144 | case 0x900: prio = BOOK3S_IRQPRIO_DECREMENTER; break; | ||
145 | case 0xc00: prio = BOOK3S_IRQPRIO_SYSCALL; break; | ||
146 | case 0xd00: prio = BOOK3S_IRQPRIO_DEBUG; break; | ||
147 | case 0xf20: prio = BOOK3S_IRQPRIO_ALTIVEC; break; | ||
148 | case 0xf40: prio = BOOK3S_IRQPRIO_VSX; break; | ||
149 | default: prio = BOOK3S_IRQPRIO_MAX; break; | ||
150 | } | ||
151 | |||
152 | set_bit(prio, &vcpu->arch.pending_exceptions); | ||
153 | #ifdef EXIT_DEBUG | ||
154 | printk(KERN_INFO "Queueing interrupt %x\n", vec); | ||
155 | #endif | ||
156 | } | ||
157 | |||
158 | |||
159 | void kvmppc_core_queue_program(struct kvm_vcpu *vcpu) | ||
160 | { | ||
161 | kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_PROGRAM); | ||
162 | } | ||
163 | |||
164 | void kvmppc_core_queue_dec(struct kvm_vcpu *vcpu) | ||
165 | { | ||
166 | kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_DECREMENTER); | ||
167 | } | ||
168 | |||
169 | int kvmppc_core_pending_dec(struct kvm_vcpu *vcpu) | ||
170 | { | ||
171 | return test_bit(BOOK3S_INTERRUPT_DECREMENTER >> 7, &vcpu->arch.pending_exceptions); | ||
172 | } | ||
173 | |||
174 | void kvmppc_core_queue_external(struct kvm_vcpu *vcpu, | ||
175 | struct kvm_interrupt *irq) | ||
176 | { | ||
177 | kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_EXTERNAL); | ||
178 | } | ||
179 | |||
180 | int kvmppc_book3s_irqprio_deliver(struct kvm_vcpu *vcpu, unsigned int priority) | ||
181 | { | ||
182 | int deliver = 1; | ||
183 | int vec = 0; | ||
184 | |||
185 | switch (priority) { | ||
186 | case BOOK3S_IRQPRIO_DECREMENTER: | ||
187 | deliver = vcpu->arch.msr & MSR_EE; | ||
188 | vec = BOOK3S_INTERRUPT_DECREMENTER; | ||
189 | break; | ||
190 | case BOOK3S_IRQPRIO_EXTERNAL: | ||
191 | deliver = vcpu->arch.msr & MSR_EE; | ||
192 | vec = BOOK3S_INTERRUPT_EXTERNAL; | ||
193 | break; | ||
194 | case BOOK3S_IRQPRIO_SYSTEM_RESET: | ||
195 | vec = BOOK3S_INTERRUPT_SYSTEM_RESET; | ||
196 | break; | ||
197 | case BOOK3S_IRQPRIO_MACHINE_CHECK: | ||
198 | vec = BOOK3S_INTERRUPT_MACHINE_CHECK; | ||
199 | break; | ||
200 | case BOOK3S_IRQPRIO_DATA_STORAGE: | ||
201 | vec = BOOK3S_INTERRUPT_DATA_STORAGE; | ||
202 | break; | ||
203 | case BOOK3S_IRQPRIO_INST_STORAGE: | ||
204 | vec = BOOK3S_INTERRUPT_INST_STORAGE; | ||
205 | break; | ||
206 | case BOOK3S_IRQPRIO_DATA_SEGMENT: | ||
207 | vec = BOOK3S_INTERRUPT_DATA_SEGMENT; | ||
208 | break; | ||
209 | case BOOK3S_IRQPRIO_INST_SEGMENT: | ||
210 | vec = BOOK3S_INTERRUPT_INST_SEGMENT; | ||
211 | break; | ||
212 | case BOOK3S_IRQPRIO_ALIGNMENT: | ||
213 | vec = BOOK3S_INTERRUPT_ALIGNMENT; | ||
214 | break; | ||
215 | case BOOK3S_IRQPRIO_PROGRAM: | ||
216 | vec = BOOK3S_INTERRUPT_PROGRAM; | ||
217 | break; | ||
218 | case BOOK3S_IRQPRIO_VSX: | ||
219 | vec = BOOK3S_INTERRUPT_VSX; | ||
220 | break; | ||
221 | case BOOK3S_IRQPRIO_ALTIVEC: | ||
222 | vec = BOOK3S_INTERRUPT_ALTIVEC; | ||
223 | break; | ||
224 | case BOOK3S_IRQPRIO_FP_UNAVAIL: | ||
225 | vec = BOOK3S_INTERRUPT_FP_UNAVAIL; | ||
226 | break; | ||
227 | case BOOK3S_IRQPRIO_SYSCALL: | ||
228 | vec = BOOK3S_INTERRUPT_SYSCALL; | ||
229 | break; | ||
230 | case BOOK3S_IRQPRIO_DEBUG: | ||
231 | vec = BOOK3S_INTERRUPT_TRACE; | ||
232 | break; | ||
233 | case BOOK3S_IRQPRIO_PERFORMANCE_MONITOR: | ||
234 | vec = BOOK3S_INTERRUPT_PERFMON; | ||
235 | break; | ||
236 | default: | ||
237 | deliver = 0; | ||
238 | printk(KERN_ERR "KVM: Unknown interrupt: 0x%x\n", priority); | ||
239 | break; | ||
240 | } | ||
241 | |||
242 | #if 0 | ||
243 | printk(KERN_INFO "Deliver interrupt 0x%x? %x\n", vec, deliver); | ||
244 | #endif | ||
245 | |||
246 | if (deliver) | ||
247 | kvmppc_inject_interrupt(vcpu, vec, 0ULL); | ||
248 | |||
249 | return deliver; | ||
250 | } | ||
251 | |||
252 | void kvmppc_core_deliver_interrupts(struct kvm_vcpu *vcpu) | ||
253 | { | ||
254 | unsigned long *pending = &vcpu->arch.pending_exceptions; | ||
255 | unsigned int priority; | ||
256 | |||
257 | /* XXX be more clever here - no need to mftb() on every entry */ | ||
258 | /* Issue DEC again if it's still active */ | ||
259 | #ifdef AGGRESSIVE_DEC | ||
260 | if (vcpu->arch.msr & MSR_EE) | ||
261 | if (kvmppc_get_dec(vcpu) & 0x80000000) | ||
262 | kvmppc_core_queue_dec(vcpu); | ||
263 | #endif | ||
264 | |||
265 | #ifdef EXIT_DEBUG | ||
266 | if (vcpu->arch.pending_exceptions) | ||
267 | printk(KERN_EMERG "KVM: Check pending: %lx\n", vcpu->arch.pending_exceptions); | ||
268 | #endif | ||
269 | priority = __ffs(*pending); | ||
270 | while (priority <= (sizeof(unsigned int) * 8)) { | ||
271 | if (kvmppc_book3s_irqprio_deliver(vcpu, priority)) { | ||
272 | clear_bit(priority, &vcpu->arch.pending_exceptions); | ||
273 | break; | ||
274 | } | ||
275 | |||
276 | priority = find_next_bit(pending, | ||
277 | BITS_PER_BYTE * sizeof(*pending), | ||
278 | priority + 1); | ||
279 | } | ||
280 | } | ||
281 | |||
282 | void kvmppc_set_pvr(struct kvm_vcpu *vcpu, u32 pvr) | ||
283 | { | ||
284 | vcpu->arch.hflags &= ~BOOK3S_HFLAG_SLB; | ||
285 | vcpu->arch.pvr = pvr; | ||
286 | if ((pvr >= 0x330000) && (pvr < 0x70330000)) { | ||
287 | kvmppc_mmu_book3s_64_init(vcpu); | ||
288 | to_book3s(vcpu)->hior = 0xfff00000; | ||
289 | to_book3s(vcpu)->msr_mask = 0xffffffffffffffffULL; | ||
290 | } else { | ||
291 | kvmppc_mmu_book3s_32_init(vcpu); | ||
292 | to_book3s(vcpu)->hior = 0; | ||
293 | to_book3s(vcpu)->msr_mask = 0xffffffffULL; | ||
294 | } | ||
295 | |||
296 | /* If we are in hypervisor level on 970, we can tell the CPU to | ||
297 | * treat DCBZ as 32 bytes store */ | ||
298 | vcpu->arch.hflags &= ~BOOK3S_HFLAG_DCBZ32; | ||
299 | if (vcpu->arch.mmu.is_dcbz32(vcpu) && (mfmsr() & MSR_HV) && | ||
300 | !strcmp(cur_cpu_spec->platform, "ppc970")) | ||
301 | vcpu->arch.hflags |= BOOK3S_HFLAG_DCBZ32; | ||
302 | |||
303 | } | ||
304 | |||
305 | /* Book3s_32 CPUs always have 32 bytes cache line size, which Linux assumes. To | ||
306 | * make Book3s_32 Linux work on Book3s_64, we have to make sure we trap dcbz to | ||
307 | * emulate 32 bytes dcbz length. | ||
308 | * | ||
309 | * The Book3s_64 inventors also realized this case and implemented a special bit | ||
310 | * in the HID5 register, which is a hypervisor ressource. Thus we can't use it. | ||
311 | * | ||
312 | * My approach here is to patch the dcbz instruction on executing pages. | ||
313 | */ | ||
314 | static void kvmppc_patch_dcbz(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte) | ||
315 | { | ||
316 | bool touched = false; | ||
317 | hva_t hpage; | ||
318 | u32 *page; | ||
319 | int i; | ||
320 | |||
321 | hpage = gfn_to_hva(vcpu->kvm, pte->raddr >> PAGE_SHIFT); | ||
322 | if (kvm_is_error_hva(hpage)) | ||
323 | return; | ||
324 | |||
325 | hpage |= pte->raddr & ~PAGE_MASK; | ||
326 | hpage &= ~0xFFFULL; | ||
327 | |||
328 | page = vmalloc(HW_PAGE_SIZE); | ||
329 | |||
330 | if (copy_from_user(page, (void __user *)hpage, HW_PAGE_SIZE)) | ||
331 | goto out; | ||
332 | |||
333 | for (i=0; i < HW_PAGE_SIZE / 4; i++) | ||
334 | if ((page[i] & 0xff0007ff) == INS_DCBZ) { | ||
335 | page[i] &= 0xfffffff7; // reserved instruction, so we trap | ||
336 | touched = true; | ||
337 | } | ||
338 | |||
339 | if (touched) | ||
340 | copy_to_user((void __user *)hpage, page, HW_PAGE_SIZE); | ||
341 | |||
342 | out: | ||
343 | vfree(page); | ||
344 | } | ||
345 | |||
346 | static int kvmppc_xlate(struct kvm_vcpu *vcpu, ulong eaddr, bool data, | ||
347 | struct kvmppc_pte *pte) | ||
348 | { | ||
349 | int relocated = (vcpu->arch.msr & (data ? MSR_DR : MSR_IR)); | ||
350 | int r; | ||
351 | |||
352 | if (relocated) { | ||
353 | r = vcpu->arch.mmu.xlate(vcpu, eaddr, pte, data); | ||
354 | } else { | ||
355 | pte->eaddr = eaddr; | ||
356 | pte->raddr = eaddr & 0xffffffff; | ||
357 | pte->vpage = eaddr >> 12; | ||
358 | switch (vcpu->arch.msr & (MSR_DR|MSR_IR)) { | ||
359 | case 0: | ||
360 | pte->vpage |= VSID_REAL; | ||
361 | case MSR_DR: | ||
362 | pte->vpage |= VSID_REAL_DR; | ||
363 | case MSR_IR: | ||
364 | pte->vpage |= VSID_REAL_IR; | ||
365 | } | ||
366 | pte->may_read = true; | ||
367 | pte->may_write = true; | ||
368 | pte->may_execute = true; | ||
369 | r = 0; | ||
370 | } | ||
371 | |||
372 | return r; | ||
373 | } | ||
374 | |||
375 | static hva_t kvmppc_bad_hva(void) | ||
376 | { | ||
377 | return PAGE_OFFSET; | ||
378 | } | ||
379 | |||
380 | static hva_t kvmppc_pte_to_hva(struct kvm_vcpu *vcpu, struct kvmppc_pte *pte, | ||
381 | bool read) | ||
382 | { | ||
383 | hva_t hpage; | ||
384 | |||
385 | if (read && !pte->may_read) | ||
386 | goto err; | ||
387 | |||
388 | if (!read && !pte->may_write) | ||
389 | goto err; | ||
390 | |||
391 | hpage = gfn_to_hva(vcpu->kvm, pte->raddr >> PAGE_SHIFT); | ||
392 | if (kvm_is_error_hva(hpage)) | ||
393 | goto err; | ||
394 | |||
395 | return hpage | (pte->raddr & ~PAGE_MASK); | ||
396 | err: | ||
397 | return kvmppc_bad_hva(); | ||
398 | } | ||
399 | |||
400 | int kvmppc_st(struct kvm_vcpu *vcpu, ulong eaddr, int size, void *ptr) | ||
401 | { | ||
402 | struct kvmppc_pte pte; | ||
403 | hva_t hva = eaddr; | ||
404 | |||
405 | vcpu->stat.st++; | ||
406 | |||
407 | if (kvmppc_xlate(vcpu, eaddr, false, &pte)) | ||
408 | goto err; | ||
409 | |||
410 | hva = kvmppc_pte_to_hva(vcpu, &pte, false); | ||
411 | if (kvm_is_error_hva(hva)) | ||
412 | goto err; | ||
413 | |||
414 | if (copy_to_user((void __user *)hva, ptr, size)) { | ||
415 | printk(KERN_INFO "kvmppc_st at 0x%lx failed\n", hva); | ||
416 | goto err; | ||
417 | } | ||
418 | |||
419 | return 0; | ||
420 | |||
421 | err: | ||
422 | return -ENOENT; | ||
423 | } | ||
424 | |||
425 | int kvmppc_ld(struct kvm_vcpu *vcpu, ulong eaddr, int size, void *ptr, | ||
426 | bool data) | ||
427 | { | ||
428 | struct kvmppc_pte pte; | ||
429 | hva_t hva = eaddr; | ||
430 | |||
431 | vcpu->stat.ld++; | ||
432 | |||
433 | if (kvmppc_xlate(vcpu, eaddr, data, &pte)) | ||
434 | goto err; | ||
435 | |||
436 | hva = kvmppc_pte_to_hva(vcpu, &pte, true); | ||
437 | if (kvm_is_error_hva(hva)) | ||
438 | goto err; | ||
439 | |||
440 | if (copy_from_user(ptr, (void __user *)hva, size)) { | ||
441 | printk(KERN_INFO "kvmppc_ld at 0x%lx failed\n", hva); | ||
442 | goto err; | ||
443 | } | ||
444 | |||
445 | return 0; | ||
446 | |||
447 | err: | ||
448 | return -ENOENT; | ||
449 | } | ||
450 | |||
451 | static int kvmppc_visible_gfn(struct kvm_vcpu *vcpu, gfn_t gfn) | ||
452 | { | ||
453 | return kvm_is_visible_gfn(vcpu->kvm, gfn); | ||
454 | } | ||
455 | |||
456 | int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu, | ||
457 | ulong eaddr, int vec) | ||
458 | { | ||
459 | bool data = (vec == BOOK3S_INTERRUPT_DATA_STORAGE); | ||
460 | int r = RESUME_GUEST; | ||
461 | int relocated; | ||
462 | int page_found = 0; | ||
463 | struct kvmppc_pte pte; | ||
464 | bool is_mmio = false; | ||
465 | |||
466 | if ( vec == BOOK3S_INTERRUPT_DATA_STORAGE ) { | ||
467 | relocated = (vcpu->arch.msr & MSR_DR); | ||
468 | } else { | ||
469 | relocated = (vcpu->arch.msr & MSR_IR); | ||
470 | } | ||
471 | |||
472 | /* Resolve real address if translation turned on */ | ||
473 | if (relocated) { | ||
474 | page_found = vcpu->arch.mmu.xlate(vcpu, eaddr, &pte, data); | ||
475 | } else { | ||
476 | pte.may_execute = true; | ||
477 | pte.may_read = true; | ||
478 | pte.may_write = true; | ||
479 | pte.raddr = eaddr & 0xffffffff; | ||
480 | pte.eaddr = eaddr; | ||
481 | pte.vpage = eaddr >> 12; | ||
482 | switch (vcpu->arch.msr & (MSR_DR|MSR_IR)) { | ||
483 | case 0: | ||
484 | pte.vpage |= VSID_REAL; | ||
485 | case MSR_DR: | ||
486 | pte.vpage |= VSID_REAL_DR; | ||
487 | case MSR_IR: | ||
488 | pte.vpage |= VSID_REAL_IR; | ||
489 | } | ||
490 | } | ||
491 | |||
492 | if (vcpu->arch.mmu.is_dcbz32(vcpu) && | ||
493 | (!(vcpu->arch.hflags & BOOK3S_HFLAG_DCBZ32))) { | ||
494 | /* | ||
495 | * If we do the dcbz hack, we have to NX on every execution, | ||
496 | * so we can patch the executing code. This renders our guest | ||
497 | * NX-less. | ||
498 | */ | ||
499 | pte.may_execute = !data; | ||
500 | } | ||
501 | |||
502 | if (page_found == -ENOENT) { | ||
503 | /* Page not found in guest PTE entries */ | ||
504 | vcpu->arch.dear = vcpu->arch.fault_dear; | ||
505 | to_book3s(vcpu)->dsisr = vcpu->arch.fault_dsisr; | ||
506 | vcpu->arch.msr |= (vcpu->arch.shadow_msr & 0x00000000f8000000ULL); | ||
507 | kvmppc_book3s_queue_irqprio(vcpu, vec); | ||
508 | } else if (page_found == -EPERM) { | ||
509 | /* Storage protection */ | ||
510 | vcpu->arch.dear = vcpu->arch.fault_dear; | ||
511 | to_book3s(vcpu)->dsisr = vcpu->arch.fault_dsisr & ~DSISR_NOHPTE; | ||
512 | to_book3s(vcpu)->dsisr |= DSISR_PROTFAULT; | ||
513 | vcpu->arch.msr |= (vcpu->arch.shadow_msr & 0x00000000f8000000ULL); | ||
514 | kvmppc_book3s_queue_irqprio(vcpu, vec); | ||
515 | } else if (page_found == -EINVAL) { | ||
516 | /* Page not found in guest SLB */ | ||
517 | vcpu->arch.dear = vcpu->arch.fault_dear; | ||
518 | kvmppc_book3s_queue_irqprio(vcpu, vec + 0x80); | ||
519 | } else if (!is_mmio && | ||
520 | kvmppc_visible_gfn(vcpu, pte.raddr >> PAGE_SHIFT)) { | ||
521 | /* The guest's PTE is not mapped yet. Map on the host */ | ||
522 | kvmppc_mmu_map_page(vcpu, &pte); | ||
523 | if (data) | ||
524 | vcpu->stat.sp_storage++; | ||
525 | else if (vcpu->arch.mmu.is_dcbz32(vcpu) && | ||
526 | (!(vcpu->arch.hflags & BOOK3S_HFLAG_DCBZ32))) | ||
527 | kvmppc_patch_dcbz(vcpu, &pte); | ||
528 | } else { | ||
529 | /* MMIO */ | ||
530 | vcpu->stat.mmio_exits++; | ||
531 | vcpu->arch.paddr_accessed = pte.raddr; | ||
532 | r = kvmppc_emulate_mmio(run, vcpu); | ||
533 | if ( r == RESUME_HOST_NV ) | ||
534 | r = RESUME_HOST; | ||
535 | if ( r == RESUME_GUEST_NV ) | ||
536 | r = RESUME_GUEST; | ||
537 | } | ||
538 | |||
539 | return r; | ||
540 | } | ||
541 | |||
542 | int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, | ||
543 | unsigned int exit_nr) | ||
544 | { | ||
545 | int r = RESUME_HOST; | ||
546 | |||
547 | vcpu->stat.sum_exits++; | ||
548 | |||
549 | run->exit_reason = KVM_EXIT_UNKNOWN; | ||
550 | run->ready_for_interrupt_injection = 1; | ||
551 | #ifdef EXIT_DEBUG | ||
552 | printk(KERN_EMERG "exit_nr=0x%x | pc=0x%lx | dar=0x%lx | dec=0x%x | msr=0x%lx\n", | ||
553 | exit_nr, vcpu->arch.pc, vcpu->arch.fault_dear, | ||
554 | kvmppc_get_dec(vcpu), vcpu->arch.msr); | ||
555 | #elif defined (EXIT_DEBUG_SIMPLE) | ||
556 | if ((exit_nr != 0x900) && (exit_nr != 0x500)) | ||
557 | printk(KERN_EMERG "exit_nr=0x%x | pc=0x%lx | dar=0x%lx | msr=0x%lx\n", | ||
558 | exit_nr, vcpu->arch.pc, vcpu->arch.fault_dear, | ||
559 | vcpu->arch.msr); | ||
560 | #endif | ||
561 | kvm_resched(vcpu); | ||
562 | switch (exit_nr) { | ||
563 | case BOOK3S_INTERRUPT_INST_STORAGE: | ||
564 | vcpu->stat.pf_instruc++; | ||
565 | /* only care about PTEG not found errors, but leave NX alone */ | ||
566 | if (vcpu->arch.shadow_msr & 0x40000000) { | ||
567 | r = kvmppc_handle_pagefault(run, vcpu, vcpu->arch.pc, exit_nr); | ||
568 | vcpu->stat.sp_instruc++; | ||
569 | } else if (vcpu->arch.mmu.is_dcbz32(vcpu) && | ||
570 | (!(vcpu->arch.hflags & BOOK3S_HFLAG_DCBZ32))) { | ||
571 | /* | ||
572 | * XXX If we do the dcbz hack we use the NX bit to flush&patch the page, | ||
573 | * so we can't use the NX bit inside the guest. Let's cross our fingers, | ||
574 | * that no guest that needs the dcbz hack does NX. | ||
575 | */ | ||
576 | kvmppc_mmu_pte_flush(vcpu, vcpu->arch.pc, ~0xFFFULL); | ||
577 | } else { | ||
578 | vcpu->arch.msr |= (vcpu->arch.shadow_msr & 0x58000000); | ||
579 | kvmppc_book3s_queue_irqprio(vcpu, exit_nr); | ||
580 | kvmppc_mmu_pte_flush(vcpu, vcpu->arch.pc, ~0xFFFULL); | ||
581 | r = RESUME_GUEST; | ||
582 | } | ||
583 | break; | ||
584 | case BOOK3S_INTERRUPT_DATA_STORAGE: | ||
585 | vcpu->stat.pf_storage++; | ||
586 | /* The only case we need to handle is missing shadow PTEs */ | ||
587 | if (vcpu->arch.fault_dsisr & DSISR_NOHPTE) { | ||
588 | r = kvmppc_handle_pagefault(run, vcpu, vcpu->arch.fault_dear, exit_nr); | ||
589 | } else { | ||
590 | vcpu->arch.dear = vcpu->arch.fault_dear; | ||
591 | to_book3s(vcpu)->dsisr = vcpu->arch.fault_dsisr; | ||
592 | kvmppc_book3s_queue_irqprio(vcpu, exit_nr); | ||
593 | kvmppc_mmu_pte_flush(vcpu, vcpu->arch.dear, ~0xFFFULL); | ||
594 | r = RESUME_GUEST; | ||
595 | } | ||
596 | break; | ||
597 | case BOOK3S_INTERRUPT_DATA_SEGMENT: | ||
598 | if (kvmppc_mmu_map_segment(vcpu, vcpu->arch.fault_dear) < 0) { | ||
599 | vcpu->arch.dear = vcpu->arch.fault_dear; | ||
600 | kvmppc_book3s_queue_irqprio(vcpu, | ||
601 | BOOK3S_INTERRUPT_DATA_SEGMENT); | ||
602 | } | ||
603 | r = RESUME_GUEST; | ||
604 | break; | ||
605 | case BOOK3S_INTERRUPT_INST_SEGMENT: | ||
606 | if (kvmppc_mmu_map_segment(vcpu, vcpu->arch.pc) < 0) { | ||
607 | kvmppc_book3s_queue_irqprio(vcpu, | ||
608 | BOOK3S_INTERRUPT_INST_SEGMENT); | ||
609 | } | ||
610 | r = RESUME_GUEST; | ||
611 | break; | ||
612 | /* We're good on these - the host merely wanted to get our attention */ | ||
613 | case BOOK3S_INTERRUPT_DECREMENTER: | ||
614 | vcpu->stat.dec_exits++; | ||
615 | r = RESUME_GUEST; | ||
616 | break; | ||
617 | case BOOK3S_INTERRUPT_EXTERNAL: | ||
618 | vcpu->stat.ext_intr_exits++; | ||
619 | r = RESUME_GUEST; | ||
620 | break; | ||
621 | case BOOK3S_INTERRUPT_PROGRAM: | ||
622 | { | ||
623 | enum emulation_result er; | ||
624 | |||
625 | if (vcpu->arch.msr & MSR_PR) { | ||
626 | #ifdef EXIT_DEBUG | ||
627 | printk(KERN_INFO "Userspace triggered 0x700 exception at 0x%lx (0x%x)\n", vcpu->arch.pc, vcpu->arch.last_inst); | ||
628 | #endif | ||
629 | if ((vcpu->arch.last_inst & 0xff0007ff) != | ||
630 | (INS_DCBZ & 0xfffffff7)) { | ||
631 | kvmppc_book3s_queue_irqprio(vcpu, exit_nr); | ||
632 | r = RESUME_GUEST; | ||
633 | break; | ||
634 | } | ||
635 | } | ||
636 | |||
637 | vcpu->stat.emulated_inst_exits++; | ||
638 | er = kvmppc_emulate_instruction(run, vcpu); | ||
639 | switch (er) { | ||
640 | case EMULATE_DONE: | ||
641 | r = RESUME_GUEST; | ||
642 | break; | ||
643 | case EMULATE_FAIL: | ||
644 | printk(KERN_CRIT "%s: emulation at %lx failed (%08x)\n", | ||
645 | __func__, vcpu->arch.pc, vcpu->arch.last_inst); | ||
646 | kvmppc_book3s_queue_irqprio(vcpu, exit_nr); | ||
647 | r = RESUME_GUEST; | ||
648 | break; | ||
649 | default: | ||
650 | BUG(); | ||
651 | } | ||
652 | break; | ||
653 | } | ||
654 | case BOOK3S_INTERRUPT_SYSCALL: | ||
655 | #ifdef EXIT_DEBUG | ||
656 | printk(KERN_INFO "Syscall Nr %d\n", (int)vcpu->arch.gpr[0]); | ||
657 | #endif | ||
658 | vcpu->stat.syscall_exits++; | ||
659 | kvmppc_book3s_queue_irqprio(vcpu, exit_nr); | ||
660 | r = RESUME_GUEST; | ||
661 | break; | ||
662 | case BOOK3S_INTERRUPT_MACHINE_CHECK: | ||
663 | case BOOK3S_INTERRUPT_FP_UNAVAIL: | ||
664 | case BOOK3S_INTERRUPT_TRACE: | ||
665 | case BOOK3S_INTERRUPT_ALTIVEC: | ||
666 | case BOOK3S_INTERRUPT_VSX: | ||
667 | kvmppc_book3s_queue_irqprio(vcpu, exit_nr); | ||
668 | r = RESUME_GUEST; | ||
669 | break; | ||
670 | default: | ||
671 | /* Ugh - bork here! What did we get? */ | ||
672 | printk(KERN_EMERG "exit_nr=0x%x | pc=0x%lx | msr=0x%lx\n", exit_nr, vcpu->arch.pc, vcpu->arch.shadow_msr); | ||
673 | r = RESUME_HOST; | ||
674 | BUG(); | ||
675 | break; | ||
676 | } | ||
677 | |||
678 | |||
679 | if (!(r & RESUME_HOST)) { | ||
680 | /* To avoid clobbering exit_reason, only check for signals if | ||
681 | * we aren't already exiting to userspace for some other | ||
682 | * reason. */ | ||
683 | if (signal_pending(current)) { | ||
684 | #ifdef EXIT_DEBUG | ||
685 | printk(KERN_EMERG "KVM: Going back to host\n"); | ||
686 | #endif | ||
687 | vcpu->stat.signal_exits++; | ||
688 | run->exit_reason = KVM_EXIT_INTR; | ||
689 | r = -EINTR; | ||
690 | } else { | ||
691 | /* In case an interrupt came in that was triggered | ||
692 | * from userspace (like DEC), we need to check what | ||
693 | * to inject now! */ | ||
694 | kvmppc_core_deliver_interrupts(vcpu); | ||
695 | } | ||
696 | } | ||
697 | |||
698 | #ifdef EXIT_DEBUG | ||
699 | printk(KERN_EMERG "KVM exit: vcpu=0x%p pc=0x%lx r=0x%x\n", vcpu, vcpu->arch.pc, r); | ||
700 | #endif | ||
701 | |||
702 | return r; | ||
703 | } | ||
704 | |||
705 | int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu) | ||
706 | { | ||
707 | return 0; | ||
708 | } | ||
709 | |||
710 | int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) | ||
711 | { | ||
712 | int i; | ||
713 | |||
714 | regs->pc = vcpu->arch.pc; | ||
715 | regs->cr = vcpu->arch.cr; | ||
716 | regs->ctr = vcpu->arch.ctr; | ||
717 | regs->lr = vcpu->arch.lr; | ||
718 | regs->xer = vcpu->arch.xer; | ||
719 | regs->msr = vcpu->arch.msr; | ||
720 | regs->srr0 = vcpu->arch.srr0; | ||
721 | regs->srr1 = vcpu->arch.srr1; | ||
722 | regs->pid = vcpu->arch.pid; | ||
723 | regs->sprg0 = vcpu->arch.sprg0; | ||
724 | regs->sprg1 = vcpu->arch.sprg1; | ||
725 | regs->sprg2 = vcpu->arch.sprg2; | ||
726 | regs->sprg3 = vcpu->arch.sprg3; | ||
727 | regs->sprg5 = vcpu->arch.sprg4; | ||
728 | regs->sprg6 = vcpu->arch.sprg5; | ||
729 | regs->sprg7 = vcpu->arch.sprg6; | ||
730 | |||
731 | for (i = 0; i < ARRAY_SIZE(regs->gpr); i++) | ||
732 | regs->gpr[i] = vcpu->arch.gpr[i]; | ||
733 | |||
734 | return 0; | ||
735 | } | ||
736 | |||
737 | int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) | ||
738 | { | ||
739 | int i; | ||
740 | |||
741 | vcpu->arch.pc = regs->pc; | ||
742 | vcpu->arch.cr = regs->cr; | ||
743 | vcpu->arch.ctr = regs->ctr; | ||
744 | vcpu->arch.lr = regs->lr; | ||
745 | vcpu->arch.xer = regs->xer; | ||
746 | kvmppc_set_msr(vcpu, regs->msr); | ||
747 | vcpu->arch.srr0 = regs->srr0; | ||
748 | vcpu->arch.srr1 = regs->srr1; | ||
749 | vcpu->arch.sprg0 = regs->sprg0; | ||
750 | vcpu->arch.sprg1 = regs->sprg1; | ||
751 | vcpu->arch.sprg2 = regs->sprg2; | ||
752 | vcpu->arch.sprg3 = regs->sprg3; | ||
753 | vcpu->arch.sprg5 = regs->sprg4; | ||
754 | vcpu->arch.sprg6 = regs->sprg5; | ||
755 | vcpu->arch.sprg7 = regs->sprg6; | ||
756 | |||
757 | for (i = 0; i < ARRAY_SIZE(vcpu->arch.gpr); i++) | ||
758 | vcpu->arch.gpr[i] = regs->gpr[i]; | ||
759 | |||
760 | return 0; | ||
761 | } | ||
762 | |||
763 | int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, | ||
764 | struct kvm_sregs *sregs) | ||
765 | { | ||
766 | struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu); | ||
767 | int i; | ||
768 | |||
769 | sregs->pvr = vcpu->arch.pvr; | ||
770 | |||
771 | sregs->u.s.sdr1 = to_book3s(vcpu)->sdr1; | ||
772 | if (vcpu->arch.hflags & BOOK3S_HFLAG_SLB) { | ||
773 | for (i = 0; i < 64; i++) { | ||
774 | sregs->u.s.ppc64.slb[i].slbe = vcpu3s->slb[i].orige | i; | ||
775 | sregs->u.s.ppc64.slb[i].slbv = vcpu3s->slb[i].origv; | ||
776 | } | ||
777 | } else { | ||
778 | for (i = 0; i < 16; i++) { | ||
779 | sregs->u.s.ppc32.sr[i] = vcpu3s->sr[i].raw; | ||
780 | sregs->u.s.ppc32.sr[i] = vcpu3s->sr[i].raw; | ||
781 | } | ||
782 | for (i = 0; i < 8; i++) { | ||
783 | sregs->u.s.ppc32.ibat[i] = vcpu3s->ibat[i].raw; | ||
784 | sregs->u.s.ppc32.dbat[i] = vcpu3s->dbat[i].raw; | ||
785 | } | ||
786 | } | ||
787 | return 0; | ||
788 | } | ||
789 | |||
790 | int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, | ||
791 | struct kvm_sregs *sregs) | ||
792 | { | ||
793 | struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu); | ||
794 | int i; | ||
795 | |||
796 | kvmppc_set_pvr(vcpu, sregs->pvr); | ||
797 | |||
798 | vcpu3s->sdr1 = sregs->u.s.sdr1; | ||
799 | if (vcpu->arch.hflags & BOOK3S_HFLAG_SLB) { | ||
800 | for (i = 0; i < 64; i++) { | ||
801 | vcpu->arch.mmu.slbmte(vcpu, sregs->u.s.ppc64.slb[i].slbv, | ||
802 | sregs->u.s.ppc64.slb[i].slbe); | ||
803 | } | ||
804 | } else { | ||
805 | for (i = 0; i < 16; i++) { | ||
806 | vcpu->arch.mmu.mtsrin(vcpu, i, sregs->u.s.ppc32.sr[i]); | ||
807 | } | ||
808 | for (i = 0; i < 8; i++) { | ||
809 | kvmppc_set_bat(vcpu, &(vcpu3s->ibat[i]), false, | ||
810 | (u32)sregs->u.s.ppc32.ibat[i]); | ||
811 | kvmppc_set_bat(vcpu, &(vcpu3s->ibat[i]), true, | ||
812 | (u32)(sregs->u.s.ppc32.ibat[i] >> 32)); | ||
813 | kvmppc_set_bat(vcpu, &(vcpu3s->dbat[i]), false, | ||
814 | (u32)sregs->u.s.ppc32.dbat[i]); | ||
815 | kvmppc_set_bat(vcpu, &(vcpu3s->dbat[i]), true, | ||
816 | (u32)(sregs->u.s.ppc32.dbat[i] >> 32)); | ||
817 | } | ||
818 | } | ||
819 | |||
820 | /* Flush the MMU after messing with the segments */ | ||
821 | kvmppc_mmu_pte_flush(vcpu, 0, 0); | ||
822 | return 0; | ||
823 | } | ||
824 | |||
825 | int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) | ||
826 | { | ||
827 | return -ENOTSUPP; | ||
828 | } | ||
829 | |||
830 | int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) | ||
831 | { | ||
832 | return -ENOTSUPP; | ||
833 | } | ||
834 | |||
835 | int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu, | ||
836 | struct kvm_translation *tr) | ||
837 | { | ||
838 | return 0; | ||
839 | } | ||
840 | |||
841 | /* | ||
842 | * Get (and clear) the dirty memory log for a memory slot. | ||
843 | */ | ||
844 | int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, | ||
845 | struct kvm_dirty_log *log) | ||
846 | { | ||
847 | struct kvm_memory_slot *memslot; | ||
848 | struct kvm_vcpu *vcpu; | ||
849 | ulong ga, ga_end; | ||
850 | int is_dirty = 0; | ||
851 | int r, n; | ||
852 | |||
853 | down_write(&kvm->slots_lock); | ||
854 | |||
855 | r = kvm_get_dirty_log(kvm, log, &is_dirty); | ||
856 | if (r) | ||
857 | goto out; | ||
858 | |||
859 | /* If nothing is dirty, don't bother messing with page tables. */ | ||
860 | if (is_dirty) { | ||
861 | memslot = &kvm->memslots[log->slot]; | ||
862 | |||
863 | ga = memslot->base_gfn << PAGE_SHIFT; | ||
864 | ga_end = ga + (memslot->npages << PAGE_SHIFT); | ||
865 | |||
866 | kvm_for_each_vcpu(n, vcpu, kvm) | ||
867 | kvmppc_mmu_pte_pflush(vcpu, ga, ga_end); | ||
868 | |||
869 | n = ALIGN(memslot->npages, BITS_PER_LONG) / 8; | ||
870 | memset(memslot->dirty_bitmap, 0, n); | ||
871 | } | ||
872 | |||
873 | r = 0; | ||
874 | out: | ||
875 | up_write(&kvm->slots_lock); | ||
876 | return r; | ||
877 | } | ||
878 | |||
879 | int kvmppc_core_check_processor_compat(void) | ||
880 | { | ||
881 | return 0; | ||
882 | } | ||
883 | |||
884 | struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id) | ||
885 | { | ||
886 | struct kvmppc_vcpu_book3s *vcpu_book3s; | ||
887 | struct kvm_vcpu *vcpu; | ||
888 | int err; | ||
889 | |||
890 | vcpu_book3s = (struct kvmppc_vcpu_book3s *)__get_free_pages( GFP_KERNEL | __GFP_ZERO, | ||
891 | get_order(sizeof(struct kvmppc_vcpu_book3s))); | ||
892 | if (!vcpu_book3s) { | ||
893 | err = -ENOMEM; | ||
894 | goto out; | ||
895 | } | ||
896 | |||
897 | vcpu = &vcpu_book3s->vcpu; | ||
898 | err = kvm_vcpu_init(vcpu, kvm, id); | ||
899 | if (err) | ||
900 | goto free_vcpu; | ||
901 | |||
902 | vcpu->arch.host_retip = kvm_return_point; | ||
903 | vcpu->arch.host_msr = mfmsr(); | ||
904 | /* default to book3s_64 (970fx) */ | ||
905 | vcpu->arch.pvr = 0x3C0301; | ||
906 | kvmppc_set_pvr(vcpu, vcpu->arch.pvr); | ||
907 | vcpu_book3s->slb_nr = 64; | ||
908 | |||
909 | /* remember where some real-mode handlers are */ | ||
910 | vcpu->arch.trampoline_lowmem = kvmppc_trampoline_lowmem; | ||
911 | vcpu->arch.trampoline_enter = kvmppc_trampoline_enter; | ||
912 | vcpu->arch.highmem_handler = (ulong)kvmppc_handler_highmem; | ||
913 | |||
914 | vcpu->arch.shadow_msr = MSR_USER64; | ||
915 | |||
916 | err = __init_new_context(); | ||
917 | if (err < 0) | ||
918 | goto free_vcpu; | ||
919 | vcpu_book3s->context_id = err; | ||
920 | |||
921 | vcpu_book3s->vsid_max = ((vcpu_book3s->context_id + 1) << USER_ESID_BITS) - 1; | ||
922 | vcpu_book3s->vsid_first = vcpu_book3s->context_id << USER_ESID_BITS; | ||
923 | vcpu_book3s->vsid_next = vcpu_book3s->vsid_first; | ||
924 | |||
925 | return vcpu; | ||
926 | |||
927 | free_vcpu: | ||
928 | free_pages((long)vcpu_book3s, get_order(sizeof(struct kvmppc_vcpu_book3s))); | ||
929 | out: | ||
930 | return ERR_PTR(err); | ||
931 | } | ||
932 | |||
933 | void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu) | ||
934 | { | ||
935 | struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu); | ||
936 | |||
937 | __destroy_context(vcpu_book3s->context_id); | ||
938 | kvm_vcpu_uninit(vcpu); | ||
939 | free_pages((long)vcpu_book3s, get_order(sizeof(struct kvmppc_vcpu_book3s))); | ||
940 | } | ||
941 | |||
942 | extern int __kvmppc_vcpu_entry(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu); | ||
943 | int __kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) | ||
944 | { | ||
945 | int ret; | ||
946 | |||
947 | /* No need to go into the guest when all we do is going out */ | ||
948 | if (signal_pending(current)) { | ||
949 | kvm_run->exit_reason = KVM_EXIT_INTR; | ||
950 | return -EINTR; | ||
951 | } | ||
952 | |||
953 | /* XXX we get called with irq disabled - change that! */ | ||
954 | local_irq_enable(); | ||
955 | |||
956 | ret = __kvmppc_vcpu_entry(kvm_run, vcpu); | ||
957 | |||
958 | local_irq_disable(); | ||
959 | |||
960 | return ret; | ||
961 | } | ||
962 | |||
963 | static int kvmppc_book3s_init(void) | ||
964 | { | ||
965 | return kvm_init(NULL, sizeof(struct kvmppc_vcpu_book3s), THIS_MODULE); | ||
966 | } | ||
967 | |||
968 | static void kvmppc_book3s_exit(void) | ||
969 | { | ||
970 | kvm_exit(); | ||
971 | } | ||
972 | |||
973 | module_init(kvmppc_book3s_init); | ||
974 | module_exit(kvmppc_book3s_exit); | ||
diff --git a/arch/powerpc/kvm/book3s_32_mmu.c b/arch/powerpc/kvm/book3s_32_mmu.c new file mode 100644 index 000000000000..faf99f20d993 --- /dev/null +++ b/arch/powerpc/kvm/book3s_32_mmu.c | |||
@@ -0,0 +1,372 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License, version 2, as | ||
4 | * published by the Free Software Foundation. | ||
5 | * | ||
6 | * This program is distributed in the hope that it will be useful, | ||
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
9 | * GNU General Public License for more details. | ||
10 | * | ||
11 | * You should have received a copy of the GNU General Public License | ||
12 | * along with this program; if not, write to the Free Software | ||
13 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
14 | * | ||
15 | * Copyright SUSE Linux Products GmbH 2009 | ||
16 | * | ||
17 | * Authors: Alexander Graf <agraf@suse.de> | ||
18 | */ | ||
19 | |||
20 | #include <linux/types.h> | ||
21 | #include <linux/string.h> | ||
22 | #include <linux/kvm.h> | ||
23 | #include <linux/kvm_host.h> | ||
24 | #include <linux/highmem.h> | ||
25 | |||
26 | #include <asm/tlbflush.h> | ||
27 | #include <asm/kvm_ppc.h> | ||
28 | #include <asm/kvm_book3s.h> | ||
29 | |||
30 | /* #define DEBUG_MMU */ | ||
31 | /* #define DEBUG_MMU_PTE */ | ||
32 | /* #define DEBUG_MMU_PTE_IP 0xfff14c40 */ | ||
33 | |||
34 | #ifdef DEBUG_MMU | ||
35 | #define dprintk(X...) printk(KERN_INFO X) | ||
36 | #else | ||
37 | #define dprintk(X...) do { } while(0) | ||
38 | #endif | ||
39 | |||
40 | #ifdef DEBUG_PTE | ||
41 | #define dprintk_pte(X...) printk(KERN_INFO X) | ||
42 | #else | ||
43 | #define dprintk_pte(X...) do { } while(0) | ||
44 | #endif | ||
45 | |||
46 | #define PTEG_FLAG_ACCESSED 0x00000100 | ||
47 | #define PTEG_FLAG_DIRTY 0x00000080 | ||
48 | |||
49 | static inline bool check_debug_ip(struct kvm_vcpu *vcpu) | ||
50 | { | ||
51 | #ifdef DEBUG_MMU_PTE_IP | ||
52 | return vcpu->arch.pc == DEBUG_MMU_PTE_IP; | ||
53 | #else | ||
54 | return true; | ||
55 | #endif | ||
56 | } | ||
57 | |||
58 | static int kvmppc_mmu_book3s_32_xlate_bat(struct kvm_vcpu *vcpu, gva_t eaddr, | ||
59 | struct kvmppc_pte *pte, bool data); | ||
60 | |||
61 | static struct kvmppc_sr *find_sr(struct kvmppc_vcpu_book3s *vcpu_book3s, gva_t eaddr) | ||
62 | { | ||
63 | return &vcpu_book3s->sr[(eaddr >> 28) & 0xf]; | ||
64 | } | ||
65 | |||
66 | static u64 kvmppc_mmu_book3s_32_ea_to_vp(struct kvm_vcpu *vcpu, gva_t eaddr, | ||
67 | bool data) | ||
68 | { | ||
69 | struct kvmppc_sr *sre = find_sr(to_book3s(vcpu), eaddr); | ||
70 | struct kvmppc_pte pte; | ||
71 | |||
72 | if (!kvmppc_mmu_book3s_32_xlate_bat(vcpu, eaddr, &pte, data)) | ||
73 | return pte.vpage; | ||
74 | |||
75 | return (((u64)eaddr >> 12) & 0xffff) | (((u64)sre->vsid) << 16); | ||
76 | } | ||
77 | |||
78 | static void kvmppc_mmu_book3s_32_reset_msr(struct kvm_vcpu *vcpu) | ||
79 | { | ||
80 | kvmppc_set_msr(vcpu, 0); | ||
81 | } | ||
82 | |||
83 | static hva_t kvmppc_mmu_book3s_32_get_pteg(struct kvmppc_vcpu_book3s *vcpu_book3s, | ||
84 | struct kvmppc_sr *sre, gva_t eaddr, | ||
85 | bool primary) | ||
86 | { | ||
87 | u32 page, hash, pteg, htabmask; | ||
88 | hva_t r; | ||
89 | |||
90 | page = (eaddr & 0x0FFFFFFF) >> 12; | ||
91 | htabmask = ((vcpu_book3s->sdr1 & 0x1FF) << 16) | 0xFFC0; | ||
92 | |||
93 | hash = ((sre->vsid ^ page) << 6); | ||
94 | if (!primary) | ||
95 | hash = ~hash; | ||
96 | hash &= htabmask; | ||
97 | |||
98 | pteg = (vcpu_book3s->sdr1 & 0xffff0000) | hash; | ||
99 | |||
100 | dprintk("MMU: pc=0x%lx eaddr=0x%lx sdr1=0x%llx pteg=0x%x vsid=0x%x\n", | ||
101 | vcpu_book3s->vcpu.arch.pc, eaddr, vcpu_book3s->sdr1, pteg, | ||
102 | sre->vsid); | ||
103 | |||
104 | r = gfn_to_hva(vcpu_book3s->vcpu.kvm, pteg >> PAGE_SHIFT); | ||
105 | if (kvm_is_error_hva(r)) | ||
106 | return r; | ||
107 | return r | (pteg & ~PAGE_MASK); | ||
108 | } | ||
109 | |||
110 | static u32 kvmppc_mmu_book3s_32_get_ptem(struct kvmppc_sr *sre, gva_t eaddr, | ||
111 | bool primary) | ||
112 | { | ||
113 | return ((eaddr & 0x0fffffff) >> 22) | (sre->vsid << 7) | | ||
114 | (primary ? 0 : 0x40) | 0x80000000; | ||
115 | } | ||
116 | |||
117 | static int kvmppc_mmu_book3s_32_xlate_bat(struct kvm_vcpu *vcpu, gva_t eaddr, | ||
118 | struct kvmppc_pte *pte, bool data) | ||
119 | { | ||
120 | struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu); | ||
121 | struct kvmppc_bat *bat; | ||
122 | int i; | ||
123 | |||
124 | for (i = 0; i < 8; i++) { | ||
125 | if (data) | ||
126 | bat = &vcpu_book3s->dbat[i]; | ||
127 | else | ||
128 | bat = &vcpu_book3s->ibat[i]; | ||
129 | |||
130 | if (vcpu->arch.msr & MSR_PR) { | ||
131 | if (!bat->vp) | ||
132 | continue; | ||
133 | } else { | ||
134 | if (!bat->vs) | ||
135 | continue; | ||
136 | } | ||
137 | |||
138 | if (check_debug_ip(vcpu)) | ||
139 | { | ||
140 | dprintk_pte("%cBAT %02d: 0x%lx - 0x%x (0x%x)\n", | ||
141 | data ? 'd' : 'i', i, eaddr, bat->bepi, | ||
142 | bat->bepi_mask); | ||
143 | } | ||
144 | if ((eaddr & bat->bepi_mask) == bat->bepi) { | ||
145 | pte->raddr = bat->brpn | (eaddr & ~bat->bepi_mask); | ||
146 | pte->vpage = (eaddr >> 12) | VSID_BAT; | ||
147 | pte->may_read = bat->pp; | ||
148 | pte->may_write = bat->pp > 1; | ||
149 | pte->may_execute = true; | ||
150 | if (!pte->may_read) { | ||
151 | printk(KERN_INFO "BAT is not readable!\n"); | ||
152 | continue; | ||
153 | } | ||
154 | if (!pte->may_write) { | ||
155 | /* let's treat r/o BATs as not-readable for now */ | ||
156 | dprintk_pte("BAT is read-only!\n"); | ||
157 | continue; | ||
158 | } | ||
159 | |||
160 | return 0; | ||
161 | } | ||
162 | } | ||
163 | |||
164 | return -ENOENT; | ||
165 | } | ||
166 | |||
167 | static int kvmppc_mmu_book3s_32_xlate_pte(struct kvm_vcpu *vcpu, gva_t eaddr, | ||
168 | struct kvmppc_pte *pte, bool data, | ||
169 | bool primary) | ||
170 | { | ||
171 | struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu); | ||
172 | struct kvmppc_sr *sre; | ||
173 | hva_t ptegp; | ||
174 | u32 pteg[16]; | ||
175 | u64 ptem = 0; | ||
176 | int i; | ||
177 | int found = 0; | ||
178 | |||
179 | sre = find_sr(vcpu_book3s, eaddr); | ||
180 | |||
181 | dprintk_pte("SR 0x%lx: vsid=0x%x, raw=0x%x\n", eaddr >> 28, | ||
182 | sre->vsid, sre->raw); | ||
183 | |||
184 | pte->vpage = kvmppc_mmu_book3s_32_ea_to_vp(vcpu, eaddr, data); | ||
185 | |||
186 | ptegp = kvmppc_mmu_book3s_32_get_pteg(vcpu_book3s, sre, eaddr, primary); | ||
187 | if (kvm_is_error_hva(ptegp)) { | ||
188 | printk(KERN_INFO "KVM: Invalid PTEG!\n"); | ||
189 | goto no_page_found; | ||
190 | } | ||
191 | |||
192 | ptem = kvmppc_mmu_book3s_32_get_ptem(sre, eaddr, primary); | ||
193 | |||
194 | if(copy_from_user(pteg, (void __user *)ptegp, sizeof(pteg))) { | ||
195 | printk(KERN_ERR "KVM: Can't copy data from 0x%lx!\n", ptegp); | ||
196 | goto no_page_found; | ||
197 | } | ||
198 | |||
199 | for (i=0; i<16; i+=2) { | ||
200 | if (ptem == pteg[i]) { | ||
201 | u8 pp; | ||
202 | |||
203 | pte->raddr = (pteg[i+1] & ~(0xFFFULL)) | (eaddr & 0xFFF); | ||
204 | pp = pteg[i+1] & 3; | ||
205 | |||
206 | if ((sre->Kp && (vcpu->arch.msr & MSR_PR)) || | ||
207 | (sre->Ks && !(vcpu->arch.msr & MSR_PR))) | ||
208 | pp |= 4; | ||
209 | |||
210 | pte->may_write = false; | ||
211 | pte->may_read = false; | ||
212 | pte->may_execute = true; | ||
213 | switch (pp) { | ||
214 | case 0: | ||
215 | case 1: | ||
216 | case 2: | ||
217 | case 6: | ||
218 | pte->may_write = true; | ||
219 | case 3: | ||
220 | case 5: | ||
221 | case 7: | ||
222 | pte->may_read = true; | ||
223 | break; | ||
224 | } | ||
225 | |||
226 | if ( !pte->may_read ) | ||
227 | continue; | ||
228 | |||
229 | dprintk_pte("MMU: Found PTE -> %x %x - %x\n", | ||
230 | pteg[i], pteg[i+1], pp); | ||
231 | found = 1; | ||
232 | break; | ||
233 | } | ||
234 | } | ||
235 | |||
236 | /* Update PTE C and A bits, so the guest's swapper knows we used the | ||
237 | page */ | ||
238 | if (found) { | ||
239 | u32 oldpte = pteg[i+1]; | ||
240 | |||
241 | if (pte->may_read) | ||
242 | pteg[i+1] |= PTEG_FLAG_ACCESSED; | ||
243 | if (pte->may_write) | ||
244 | pteg[i+1] |= PTEG_FLAG_DIRTY; | ||
245 | else | ||
246 | dprintk_pte("KVM: Mapping read-only page!\n"); | ||
247 | |||
248 | /* Write back into the PTEG */ | ||
249 | if (pteg[i+1] != oldpte) | ||
250 | copy_to_user((void __user *)ptegp, pteg, sizeof(pteg)); | ||
251 | |||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | no_page_found: | ||
256 | |||
257 | if (check_debug_ip(vcpu)) { | ||
258 | dprintk_pte("KVM MMU: No PTE found (sdr1=0x%llx ptegp=0x%lx)\n", | ||
259 | to_book3s(vcpu)->sdr1, ptegp); | ||
260 | for (i=0; i<16; i+=2) { | ||
261 | dprintk_pte(" %02d: 0x%x - 0x%x (0x%llx)\n", | ||
262 | i, pteg[i], pteg[i+1], ptem); | ||
263 | } | ||
264 | } | ||
265 | |||
266 | return -ENOENT; | ||
267 | } | ||
268 | |||
269 | static int kvmppc_mmu_book3s_32_xlate(struct kvm_vcpu *vcpu, gva_t eaddr, | ||
270 | struct kvmppc_pte *pte, bool data) | ||
271 | { | ||
272 | int r; | ||
273 | |||
274 | pte->eaddr = eaddr; | ||
275 | r = kvmppc_mmu_book3s_32_xlate_bat(vcpu, eaddr, pte, data); | ||
276 | if (r < 0) | ||
277 | r = kvmppc_mmu_book3s_32_xlate_pte(vcpu, eaddr, pte, data, true); | ||
278 | if (r < 0) | ||
279 | r = kvmppc_mmu_book3s_32_xlate_pte(vcpu, eaddr, pte, data, false); | ||
280 | |||
281 | return r; | ||
282 | } | ||
283 | |||
284 | |||
285 | static u32 kvmppc_mmu_book3s_32_mfsrin(struct kvm_vcpu *vcpu, u32 srnum) | ||
286 | { | ||
287 | return to_book3s(vcpu)->sr[srnum].raw; | ||
288 | } | ||
289 | |||
290 | static void kvmppc_mmu_book3s_32_mtsrin(struct kvm_vcpu *vcpu, u32 srnum, | ||
291 | ulong value) | ||
292 | { | ||
293 | struct kvmppc_sr *sre; | ||
294 | |||
295 | sre = &to_book3s(vcpu)->sr[srnum]; | ||
296 | |||
297 | /* Flush any left-over shadows from the previous SR */ | ||
298 | |||
299 | /* XXX Not necessary? */ | ||
300 | /* kvmppc_mmu_pte_flush(vcpu, ((u64)sre->vsid) << 28, 0xf0000000ULL); */ | ||
301 | |||
302 | /* And then put in the new SR */ | ||
303 | sre->raw = value; | ||
304 | sre->vsid = (value & 0x0fffffff); | ||
305 | sre->Ks = (value & 0x40000000) ? true : false; | ||
306 | sre->Kp = (value & 0x20000000) ? true : false; | ||
307 | sre->nx = (value & 0x10000000) ? true : false; | ||
308 | |||
309 | /* Map the new segment */ | ||
310 | kvmppc_mmu_map_segment(vcpu, srnum << SID_SHIFT); | ||
311 | } | ||
312 | |||
313 | static void kvmppc_mmu_book3s_32_tlbie(struct kvm_vcpu *vcpu, ulong ea, bool large) | ||
314 | { | ||
315 | kvmppc_mmu_pte_flush(vcpu, ea, ~0xFFFULL); | ||
316 | } | ||
317 | |||
318 | static int kvmppc_mmu_book3s_32_esid_to_vsid(struct kvm_vcpu *vcpu, u64 esid, | ||
319 | u64 *vsid) | ||
320 | { | ||
321 | /* In case we only have one of MSR_IR or MSR_DR set, let's put | ||
322 | that in the real-mode context (and hope RM doesn't access | ||
323 | high memory) */ | ||
324 | switch (vcpu->arch.msr & (MSR_DR|MSR_IR)) { | ||
325 | case 0: | ||
326 | *vsid = (VSID_REAL >> 16) | esid; | ||
327 | break; | ||
328 | case MSR_IR: | ||
329 | *vsid = (VSID_REAL_IR >> 16) | esid; | ||
330 | break; | ||
331 | case MSR_DR: | ||
332 | *vsid = (VSID_REAL_DR >> 16) | esid; | ||
333 | break; | ||
334 | case MSR_DR|MSR_IR: | ||
335 | { | ||
336 | ulong ea; | ||
337 | ea = esid << SID_SHIFT; | ||
338 | *vsid = find_sr(to_book3s(vcpu), ea)->vsid; | ||
339 | break; | ||
340 | } | ||
341 | default: | ||
342 | BUG(); | ||
343 | } | ||
344 | |||
345 | return 0; | ||
346 | } | ||
347 | |||
348 | static bool kvmppc_mmu_book3s_32_is_dcbz32(struct kvm_vcpu *vcpu) | ||
349 | { | ||
350 | return true; | ||
351 | } | ||
352 | |||
353 | |||
354 | void kvmppc_mmu_book3s_32_init(struct kvm_vcpu *vcpu) | ||
355 | { | ||
356 | struct kvmppc_mmu *mmu = &vcpu->arch.mmu; | ||
357 | |||
358 | mmu->mtsrin = kvmppc_mmu_book3s_32_mtsrin; | ||
359 | mmu->mfsrin = kvmppc_mmu_book3s_32_mfsrin; | ||
360 | mmu->xlate = kvmppc_mmu_book3s_32_xlate; | ||
361 | mmu->reset_msr = kvmppc_mmu_book3s_32_reset_msr; | ||
362 | mmu->tlbie = kvmppc_mmu_book3s_32_tlbie; | ||
363 | mmu->esid_to_vsid = kvmppc_mmu_book3s_32_esid_to_vsid; | ||
364 | mmu->ea_to_vp = kvmppc_mmu_book3s_32_ea_to_vp; | ||
365 | mmu->is_dcbz32 = kvmppc_mmu_book3s_32_is_dcbz32; | ||
366 | |||
367 | mmu->slbmte = NULL; | ||
368 | mmu->slbmfee = NULL; | ||
369 | mmu->slbmfev = NULL; | ||
370 | mmu->slbie = NULL; | ||
371 | mmu->slbia = NULL; | ||
372 | } | ||
diff --git a/arch/powerpc/kvm/book3s_64_emulate.c b/arch/powerpc/kvm/book3s_64_emulate.c new file mode 100644 index 000000000000..1027eac6d474 --- /dev/null +++ b/arch/powerpc/kvm/book3s_64_emulate.c | |||
@@ -0,0 +1,345 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License, version 2, as | ||
4 | * published by the Free Software Foundation. | ||
5 | * | ||
6 | * This program is distributed in the hope that it will be useful, | ||
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
9 | * GNU General Public License for more details. | ||
10 | * | ||
11 | * You should have received a copy of the GNU General Public License | ||
12 | * along with this program; if not, write to the Free Software | ||
13 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
14 | * | ||
15 | * Copyright SUSE Linux Products GmbH 2009 | ||
16 | * | ||
17 | * Authors: Alexander Graf <agraf@suse.de> | ||
18 | */ | ||
19 | |||
20 | #include <asm/kvm_ppc.h> | ||
21 | #include <asm/disassemble.h> | ||
22 | #include <asm/kvm_book3s.h> | ||
23 | #include <asm/reg.h> | ||
24 | |||
25 | #define OP_19_XOP_RFID 18 | ||
26 | #define OP_19_XOP_RFI 50 | ||
27 | |||
28 | #define OP_31_XOP_MFMSR 83 | ||
29 | #define OP_31_XOP_MTMSR 146 | ||
30 | #define OP_31_XOP_MTMSRD 178 | ||
31 | #define OP_31_XOP_MTSRIN 242 | ||
32 | #define OP_31_XOP_TLBIEL 274 | ||
33 | #define OP_31_XOP_TLBIE 306 | ||
34 | #define OP_31_XOP_SLBMTE 402 | ||
35 | #define OP_31_XOP_SLBIE 434 | ||
36 | #define OP_31_XOP_SLBIA 498 | ||
37 | #define OP_31_XOP_MFSRIN 659 | ||
38 | #define OP_31_XOP_SLBMFEV 851 | ||
39 | #define OP_31_XOP_EIOIO 854 | ||
40 | #define OP_31_XOP_SLBMFEE 915 | ||
41 | |||
42 | /* DCBZ is actually 1014, but we patch it to 1010 so we get a trap */ | ||
43 | #define OP_31_XOP_DCBZ 1010 | ||
44 | |||
45 | int kvmppc_core_emulate_op(struct kvm_run *run, struct kvm_vcpu *vcpu, | ||
46 | unsigned int inst, int *advance) | ||
47 | { | ||
48 | int emulated = EMULATE_DONE; | ||
49 | |||
50 | switch (get_op(inst)) { | ||
51 | case 19: | ||
52 | switch (get_xop(inst)) { | ||
53 | case OP_19_XOP_RFID: | ||
54 | case OP_19_XOP_RFI: | ||
55 | vcpu->arch.pc = vcpu->arch.srr0; | ||
56 | kvmppc_set_msr(vcpu, vcpu->arch.srr1); | ||
57 | *advance = 0; | ||
58 | break; | ||
59 | |||
60 | default: | ||
61 | emulated = EMULATE_FAIL; | ||
62 | break; | ||
63 | } | ||
64 | break; | ||
65 | case 31: | ||
66 | switch (get_xop(inst)) { | ||
67 | case OP_31_XOP_MFMSR: | ||
68 | vcpu->arch.gpr[get_rt(inst)] = vcpu->arch.msr; | ||
69 | break; | ||
70 | case OP_31_XOP_MTMSRD: | ||
71 | { | ||
72 | ulong rs = vcpu->arch.gpr[get_rs(inst)]; | ||
73 | if (inst & 0x10000) { | ||
74 | vcpu->arch.msr &= ~(MSR_RI | MSR_EE); | ||
75 | vcpu->arch.msr |= rs & (MSR_RI | MSR_EE); | ||
76 | } else | ||
77 | kvmppc_set_msr(vcpu, rs); | ||
78 | break; | ||
79 | } | ||
80 | case OP_31_XOP_MTMSR: | ||
81 | kvmppc_set_msr(vcpu, vcpu->arch.gpr[get_rs(inst)]); | ||
82 | break; | ||
83 | case OP_31_XOP_MFSRIN: | ||
84 | { | ||
85 | int srnum; | ||
86 | |||
87 | srnum = (vcpu->arch.gpr[get_rb(inst)] >> 28) & 0xf; | ||
88 | if (vcpu->arch.mmu.mfsrin) { | ||
89 | u32 sr; | ||
90 | sr = vcpu->arch.mmu.mfsrin(vcpu, srnum); | ||
91 | vcpu->arch.gpr[get_rt(inst)] = sr; | ||
92 | } | ||
93 | break; | ||
94 | } | ||
95 | case OP_31_XOP_MTSRIN: | ||
96 | vcpu->arch.mmu.mtsrin(vcpu, | ||
97 | (vcpu->arch.gpr[get_rb(inst)] >> 28) & 0xf, | ||
98 | vcpu->arch.gpr[get_rs(inst)]); | ||
99 | break; | ||
100 | case OP_31_XOP_TLBIE: | ||
101 | case OP_31_XOP_TLBIEL: | ||
102 | { | ||
103 | bool large = (inst & 0x00200000) ? true : false; | ||
104 | ulong addr = vcpu->arch.gpr[get_rb(inst)]; | ||
105 | vcpu->arch.mmu.tlbie(vcpu, addr, large); | ||
106 | break; | ||
107 | } | ||
108 | case OP_31_XOP_EIOIO: | ||
109 | break; | ||
110 | case OP_31_XOP_SLBMTE: | ||
111 | if (!vcpu->arch.mmu.slbmte) | ||
112 | return EMULATE_FAIL; | ||
113 | |||
114 | vcpu->arch.mmu.slbmte(vcpu, vcpu->arch.gpr[get_rs(inst)], | ||
115 | vcpu->arch.gpr[get_rb(inst)]); | ||
116 | break; | ||
117 | case OP_31_XOP_SLBIE: | ||
118 | if (!vcpu->arch.mmu.slbie) | ||
119 | return EMULATE_FAIL; | ||
120 | |||
121 | vcpu->arch.mmu.slbie(vcpu, vcpu->arch.gpr[get_rb(inst)]); | ||
122 | break; | ||
123 | case OP_31_XOP_SLBIA: | ||
124 | if (!vcpu->arch.mmu.slbia) | ||
125 | return EMULATE_FAIL; | ||
126 | |||
127 | vcpu->arch.mmu.slbia(vcpu); | ||
128 | break; | ||
129 | case OP_31_XOP_SLBMFEE: | ||
130 | if (!vcpu->arch.mmu.slbmfee) { | ||
131 | emulated = EMULATE_FAIL; | ||
132 | } else { | ||
133 | ulong t, rb; | ||
134 | |||
135 | rb = vcpu->arch.gpr[get_rb(inst)]; | ||
136 | t = vcpu->arch.mmu.slbmfee(vcpu, rb); | ||
137 | vcpu->arch.gpr[get_rt(inst)] = t; | ||
138 | } | ||
139 | break; | ||
140 | case OP_31_XOP_SLBMFEV: | ||
141 | if (!vcpu->arch.mmu.slbmfev) { | ||
142 | emulated = EMULATE_FAIL; | ||
143 | } else { | ||
144 | ulong t, rb; | ||
145 | |||
146 | rb = vcpu->arch.gpr[get_rb(inst)]; | ||
147 | t = vcpu->arch.mmu.slbmfev(vcpu, rb); | ||
148 | vcpu->arch.gpr[get_rt(inst)] = t; | ||
149 | } | ||
150 | break; | ||
151 | case OP_31_XOP_DCBZ: | ||
152 | { | ||
153 | ulong rb = vcpu->arch.gpr[get_rb(inst)]; | ||
154 | ulong ra = 0; | ||
155 | ulong addr; | ||
156 | u32 zeros[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; | ||
157 | |||
158 | if (get_ra(inst)) | ||
159 | ra = vcpu->arch.gpr[get_ra(inst)]; | ||
160 | |||
161 | addr = (ra + rb) & ~31ULL; | ||
162 | if (!(vcpu->arch.msr & MSR_SF)) | ||
163 | addr &= 0xffffffff; | ||
164 | |||
165 | if (kvmppc_st(vcpu, addr, 32, zeros)) { | ||
166 | vcpu->arch.dear = addr; | ||
167 | vcpu->arch.fault_dear = addr; | ||
168 | to_book3s(vcpu)->dsisr = DSISR_PROTFAULT | | ||
169 | DSISR_ISSTORE; | ||
170 | kvmppc_book3s_queue_irqprio(vcpu, | ||
171 | BOOK3S_INTERRUPT_DATA_STORAGE); | ||
172 | kvmppc_mmu_pte_flush(vcpu, addr, ~0xFFFULL); | ||
173 | } | ||
174 | |||
175 | break; | ||
176 | } | ||
177 | default: | ||
178 | emulated = EMULATE_FAIL; | ||
179 | } | ||
180 | break; | ||
181 | default: | ||
182 | emulated = EMULATE_FAIL; | ||
183 | } | ||
184 | |||
185 | return emulated; | ||
186 | } | ||
187 | |||
188 | void kvmppc_set_bat(struct kvm_vcpu *vcpu, struct kvmppc_bat *bat, bool upper, | ||
189 | u32 val) | ||
190 | { | ||
191 | if (upper) { | ||
192 | /* Upper BAT */ | ||
193 | u32 bl = (val >> 2) & 0x7ff; | ||
194 | bat->bepi_mask = (~bl << 17); | ||
195 | bat->bepi = val & 0xfffe0000; | ||
196 | bat->vs = (val & 2) ? 1 : 0; | ||
197 | bat->vp = (val & 1) ? 1 : 0; | ||
198 | bat->raw = (bat->raw & 0xffffffff00000000ULL) | val; | ||
199 | } else { | ||
200 | /* Lower BAT */ | ||
201 | bat->brpn = val & 0xfffe0000; | ||
202 | bat->wimg = (val >> 3) & 0xf; | ||
203 | bat->pp = val & 3; | ||
204 | bat->raw = (bat->raw & 0x00000000ffffffffULL) | ((u64)val << 32); | ||
205 | } | ||
206 | } | ||
207 | |||
208 | static void kvmppc_write_bat(struct kvm_vcpu *vcpu, int sprn, u32 val) | ||
209 | { | ||
210 | struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu); | ||
211 | struct kvmppc_bat *bat; | ||
212 | |||
213 | switch (sprn) { | ||
214 | case SPRN_IBAT0U ... SPRN_IBAT3L: | ||
215 | bat = &vcpu_book3s->ibat[(sprn - SPRN_IBAT0U) / 2]; | ||
216 | break; | ||
217 | case SPRN_IBAT4U ... SPRN_IBAT7L: | ||
218 | bat = &vcpu_book3s->ibat[(sprn - SPRN_IBAT4U) / 2]; | ||
219 | break; | ||
220 | case SPRN_DBAT0U ... SPRN_DBAT3L: | ||
221 | bat = &vcpu_book3s->dbat[(sprn - SPRN_DBAT0U) / 2]; | ||
222 | break; | ||
223 | case SPRN_DBAT4U ... SPRN_DBAT7L: | ||
224 | bat = &vcpu_book3s->dbat[(sprn - SPRN_DBAT4U) / 2]; | ||
225 | break; | ||
226 | default: | ||
227 | BUG(); | ||
228 | } | ||
229 | |||
230 | kvmppc_set_bat(vcpu, bat, !(sprn % 2), val); | ||
231 | } | ||
232 | |||
233 | int kvmppc_core_emulate_mtspr(struct kvm_vcpu *vcpu, int sprn, int rs) | ||
234 | { | ||
235 | int emulated = EMULATE_DONE; | ||
236 | |||
237 | switch (sprn) { | ||
238 | case SPRN_SDR1: | ||
239 | to_book3s(vcpu)->sdr1 = vcpu->arch.gpr[rs]; | ||
240 | break; | ||
241 | case SPRN_DSISR: | ||
242 | to_book3s(vcpu)->dsisr = vcpu->arch.gpr[rs]; | ||
243 | break; | ||
244 | case SPRN_DAR: | ||
245 | vcpu->arch.dear = vcpu->arch.gpr[rs]; | ||
246 | break; | ||
247 | case SPRN_HIOR: | ||
248 | to_book3s(vcpu)->hior = vcpu->arch.gpr[rs]; | ||
249 | break; | ||
250 | case SPRN_IBAT0U ... SPRN_IBAT3L: | ||
251 | case SPRN_IBAT4U ... SPRN_IBAT7L: | ||
252 | case SPRN_DBAT0U ... SPRN_DBAT3L: | ||
253 | case SPRN_DBAT4U ... SPRN_DBAT7L: | ||
254 | kvmppc_write_bat(vcpu, sprn, (u32)vcpu->arch.gpr[rs]); | ||
255 | /* BAT writes happen so rarely that we're ok to flush | ||
256 | * everything here */ | ||
257 | kvmppc_mmu_pte_flush(vcpu, 0, 0); | ||
258 | break; | ||
259 | case SPRN_HID0: | ||
260 | to_book3s(vcpu)->hid[0] = vcpu->arch.gpr[rs]; | ||
261 | break; | ||
262 | case SPRN_HID1: | ||
263 | to_book3s(vcpu)->hid[1] = vcpu->arch.gpr[rs]; | ||
264 | break; | ||
265 | case SPRN_HID2: | ||
266 | to_book3s(vcpu)->hid[2] = vcpu->arch.gpr[rs]; | ||
267 | break; | ||
268 | case SPRN_HID4: | ||
269 | to_book3s(vcpu)->hid[4] = vcpu->arch.gpr[rs]; | ||
270 | break; | ||
271 | case SPRN_HID5: | ||
272 | to_book3s(vcpu)->hid[5] = vcpu->arch.gpr[rs]; | ||
273 | /* guest HID5 set can change is_dcbz32 */ | ||
274 | if (vcpu->arch.mmu.is_dcbz32(vcpu) && | ||
275 | (mfmsr() & MSR_HV)) | ||
276 | vcpu->arch.hflags |= BOOK3S_HFLAG_DCBZ32; | ||
277 | break; | ||
278 | case SPRN_ICTC: | ||
279 | case SPRN_THRM1: | ||
280 | case SPRN_THRM2: | ||
281 | case SPRN_THRM3: | ||
282 | case SPRN_CTRLF: | ||
283 | case SPRN_CTRLT: | ||
284 | break; | ||
285 | default: | ||
286 | printk(KERN_INFO "KVM: invalid SPR write: %d\n", sprn); | ||
287 | #ifndef DEBUG_SPR | ||
288 | emulated = EMULATE_FAIL; | ||
289 | #endif | ||
290 | break; | ||
291 | } | ||
292 | |||
293 | return emulated; | ||
294 | } | ||
295 | |||
296 | int kvmppc_core_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt) | ||
297 | { | ||
298 | int emulated = EMULATE_DONE; | ||
299 | |||
300 | switch (sprn) { | ||
301 | case SPRN_SDR1: | ||
302 | vcpu->arch.gpr[rt] = to_book3s(vcpu)->sdr1; | ||
303 | break; | ||
304 | case SPRN_DSISR: | ||
305 | vcpu->arch.gpr[rt] = to_book3s(vcpu)->dsisr; | ||
306 | break; | ||
307 | case SPRN_DAR: | ||
308 | vcpu->arch.gpr[rt] = vcpu->arch.dear; | ||
309 | break; | ||
310 | case SPRN_HIOR: | ||
311 | vcpu->arch.gpr[rt] = to_book3s(vcpu)->hior; | ||
312 | break; | ||
313 | case SPRN_HID0: | ||
314 | vcpu->arch.gpr[rt] = to_book3s(vcpu)->hid[0]; | ||
315 | break; | ||
316 | case SPRN_HID1: | ||
317 | vcpu->arch.gpr[rt] = to_book3s(vcpu)->hid[1]; | ||
318 | break; | ||
319 | case SPRN_HID2: | ||
320 | vcpu->arch.gpr[rt] = to_book3s(vcpu)->hid[2]; | ||
321 | break; | ||
322 | case SPRN_HID4: | ||
323 | vcpu->arch.gpr[rt] = to_book3s(vcpu)->hid[4]; | ||
324 | break; | ||
325 | case SPRN_HID5: | ||
326 | vcpu->arch.gpr[rt] = to_book3s(vcpu)->hid[5]; | ||
327 | break; | ||
328 | case SPRN_THRM1: | ||
329 | case SPRN_THRM2: | ||
330 | case SPRN_THRM3: | ||
331 | case SPRN_CTRLF: | ||
332 | case SPRN_CTRLT: | ||
333 | vcpu->arch.gpr[rt] = 0; | ||
334 | break; | ||
335 | default: | ||
336 | printk(KERN_INFO "KVM: invalid SPR read: %d\n", sprn); | ||
337 | #ifndef DEBUG_SPR | ||
338 | emulated = EMULATE_FAIL; | ||
339 | #endif | ||
340 | break; | ||
341 | } | ||
342 | |||
343 | return emulated; | ||
344 | } | ||
345 | |||
diff --git a/arch/powerpc/kvm/book3s_64_exports.c b/arch/powerpc/kvm/book3s_64_exports.c new file mode 100644 index 000000000000..5b2db38ed86c --- /dev/null +++ b/arch/powerpc/kvm/book3s_64_exports.c | |||
@@ -0,0 +1,24 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License, version 2, as | ||
4 | * published by the Free Software Foundation. | ||
5 | * | ||
6 | * This program is distributed in the hope that it will be useful, | ||
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
9 | * GNU General Public License for more details. | ||
10 | * | ||
11 | * You should have received a copy of the GNU General Public License | ||
12 | * along with this program; if not, write to the Free Software | ||
13 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
14 | * | ||
15 | * Copyright SUSE Linux Products GmbH 2009 | ||
16 | * | ||
17 | * Authors: Alexander Graf <agraf@suse.de> | ||
18 | */ | ||
19 | |||
20 | #include <linux/module.h> | ||
21 | #include <asm/kvm_book3s.h> | ||
22 | |||
23 | EXPORT_SYMBOL_GPL(kvmppc_trampoline_enter); | ||
24 | EXPORT_SYMBOL_GPL(kvmppc_trampoline_lowmem); | ||
diff --git a/arch/powerpc/kvm/book3s_64_interrupts.S b/arch/powerpc/kvm/book3s_64_interrupts.S new file mode 100644 index 000000000000..7b55d8094c8b --- /dev/null +++ b/arch/powerpc/kvm/book3s_64_interrupts.S | |||
@@ -0,0 +1,392 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License, version 2, as | ||
4 | * published by the Free Software Foundation. | ||
5 | * | ||
6 | * This program is distributed in the hope that it will be useful, | ||
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
9 | * GNU General Public License for more details. | ||
10 | * | ||
11 | * You should have received a copy of the GNU General Public License | ||
12 | * along with this program; if not, write to the Free Software | ||
13 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
14 | * | ||
15 | * Copyright SUSE Linux Products GmbH 2009 | ||
16 | * | ||
17 | * Authors: Alexander Graf <agraf@suse.de> | ||
18 | */ | ||
19 | |||
20 | #include <asm/ppc_asm.h> | ||
21 | #include <asm/kvm_asm.h> | ||
22 | #include <asm/reg.h> | ||
23 | #include <asm/page.h> | ||
24 | #include <asm/asm-offsets.h> | ||
25 | #include <asm/exception-64s.h> | ||
26 | |||
27 | #define KVMPPC_HANDLE_EXIT .kvmppc_handle_exit | ||
28 | #define ULONG_SIZE 8 | ||
29 | #define VCPU_GPR(n) (VCPU_GPRS + (n * ULONG_SIZE)) | ||
30 | |||
31 | .macro mfpaca tmp_reg, src_reg, offset, vcpu_reg | ||
32 | ld \tmp_reg, (PACA_EXMC+\offset)(r13) | ||
33 | std \tmp_reg, VCPU_GPR(\src_reg)(\vcpu_reg) | ||
34 | .endm | ||
35 | |||
36 | .macro DISABLE_INTERRUPTS | ||
37 | mfmsr r0 | ||
38 | rldicl r0,r0,48,1 | ||
39 | rotldi r0,r0,16 | ||
40 | mtmsrd r0,1 | ||
41 | .endm | ||
42 | |||
43 | /***************************************************************************** | ||
44 | * * | ||
45 | * Guest entry / exit code that is in kernel module memory (highmem) * | ||
46 | * * | ||
47 | ****************************************************************************/ | ||
48 | |||
49 | /* Registers: | ||
50 | * r3: kvm_run pointer | ||
51 | * r4: vcpu pointer | ||
52 | */ | ||
53 | _GLOBAL(__kvmppc_vcpu_entry) | ||
54 | |||
55 | kvm_start_entry: | ||
56 | /* Write correct stack frame */ | ||
57 | mflr r0 | ||
58 | std r0,16(r1) | ||
59 | |||
60 | /* Save host state to the stack */ | ||
61 | stdu r1, -SWITCH_FRAME_SIZE(r1) | ||
62 | |||
63 | /* Save r3 (kvm_run) and r4 (vcpu) */ | ||
64 | SAVE_2GPRS(3, r1) | ||
65 | |||
66 | /* Save non-volatile registers (r14 - r31) */ | ||
67 | SAVE_NVGPRS(r1) | ||
68 | |||
69 | /* Save LR */ | ||
70 | mflr r14 | ||
71 | std r14, _LINK(r1) | ||
72 | |||
73 | /* XXX optimize non-volatile loading away */ | ||
74 | kvm_start_lightweight: | ||
75 | |||
76 | DISABLE_INTERRUPTS | ||
77 | |||
78 | /* Save R1/R2 in the PACA */ | ||
79 | std r1, PACAR1(r13) | ||
80 | std r2, (PACA_EXMC+EX_SRR0)(r13) | ||
81 | ld r3, VCPU_HIGHMEM_HANDLER(r4) | ||
82 | std r3, PACASAVEDMSR(r13) | ||
83 | |||
84 | /* Load non-volatile guest state from the vcpu */ | ||
85 | ld r14, VCPU_GPR(r14)(r4) | ||
86 | ld r15, VCPU_GPR(r15)(r4) | ||
87 | ld r16, VCPU_GPR(r16)(r4) | ||
88 | ld r17, VCPU_GPR(r17)(r4) | ||
89 | ld r18, VCPU_GPR(r18)(r4) | ||
90 | ld r19, VCPU_GPR(r19)(r4) | ||
91 | ld r20, VCPU_GPR(r20)(r4) | ||
92 | ld r21, VCPU_GPR(r21)(r4) | ||
93 | ld r22, VCPU_GPR(r22)(r4) | ||
94 | ld r23, VCPU_GPR(r23)(r4) | ||
95 | ld r24, VCPU_GPR(r24)(r4) | ||
96 | ld r25, VCPU_GPR(r25)(r4) | ||
97 | ld r26, VCPU_GPR(r26)(r4) | ||
98 | ld r27, VCPU_GPR(r27)(r4) | ||
99 | ld r28, VCPU_GPR(r28)(r4) | ||
100 | ld r29, VCPU_GPR(r29)(r4) | ||
101 | ld r30, VCPU_GPR(r30)(r4) | ||
102 | ld r31, VCPU_GPR(r31)(r4) | ||
103 | |||
104 | ld r9, VCPU_PC(r4) /* r9 = vcpu->arch.pc */ | ||
105 | ld r10, VCPU_SHADOW_MSR(r4) /* r10 = vcpu->arch.shadow_msr */ | ||
106 | |||
107 | ld r3, VCPU_TRAMPOLINE_ENTER(r4) | ||
108 | mtsrr0 r3 | ||
109 | |||
110 | LOAD_REG_IMMEDIATE(r3, MSR_KERNEL & ~(MSR_IR | MSR_DR)) | ||
111 | mtsrr1 r3 | ||
112 | |||
113 | /* Load guest state in the respective registers */ | ||
114 | lwz r3, VCPU_CR(r4) /* r3 = vcpu->arch.cr */ | ||
115 | stw r3, (PACA_EXMC + EX_CCR)(r13) | ||
116 | |||
117 | ld r3, VCPU_CTR(r4) /* r3 = vcpu->arch.ctr */ | ||
118 | mtctr r3 /* CTR = r3 */ | ||
119 | |||
120 | ld r3, VCPU_LR(r4) /* r3 = vcpu->arch.lr */ | ||
121 | mtlr r3 /* LR = r3 */ | ||
122 | |||
123 | ld r3, VCPU_XER(r4) /* r3 = vcpu->arch.xer */ | ||
124 | std r3, (PACA_EXMC + EX_R3)(r13) | ||
125 | |||
126 | /* Some guests may need to have dcbz set to 32 byte length. | ||
127 | * | ||
128 | * Usually we ensure that by patching the guest's instructions | ||
129 | * to trap on dcbz and emulate it in the hypervisor. | ||
130 | * | ||
131 | * If we can, we should tell the CPU to use 32 byte dcbz though, | ||
132 | * because that's a lot faster. | ||
133 | */ | ||
134 | |||
135 | ld r3, VCPU_HFLAGS(r4) | ||
136 | rldicl. r3, r3, 0, 63 /* CR = ((r3 & 1) == 0) */ | ||
137 | beq no_dcbz32_on | ||
138 | |||
139 | mfspr r3,SPRN_HID5 | ||
140 | ori r3, r3, 0x80 /* XXX HID5_dcbz32 = 0x80 */ | ||
141 | mtspr SPRN_HID5,r3 | ||
142 | |||
143 | no_dcbz32_on: | ||
144 | /* Load guest GPRs */ | ||
145 | |||
146 | ld r3, VCPU_GPR(r9)(r4) | ||
147 | std r3, (PACA_EXMC + EX_R9)(r13) | ||
148 | ld r3, VCPU_GPR(r10)(r4) | ||
149 | std r3, (PACA_EXMC + EX_R10)(r13) | ||
150 | ld r3, VCPU_GPR(r11)(r4) | ||
151 | std r3, (PACA_EXMC + EX_R11)(r13) | ||
152 | ld r3, VCPU_GPR(r12)(r4) | ||
153 | std r3, (PACA_EXMC + EX_R12)(r13) | ||
154 | ld r3, VCPU_GPR(r13)(r4) | ||
155 | std r3, (PACA_EXMC + EX_R13)(r13) | ||
156 | |||
157 | ld r0, VCPU_GPR(r0)(r4) | ||
158 | ld r1, VCPU_GPR(r1)(r4) | ||
159 | ld r2, VCPU_GPR(r2)(r4) | ||
160 | ld r3, VCPU_GPR(r3)(r4) | ||
161 | ld r5, VCPU_GPR(r5)(r4) | ||
162 | ld r6, VCPU_GPR(r6)(r4) | ||
163 | ld r7, VCPU_GPR(r7)(r4) | ||
164 | ld r8, VCPU_GPR(r8)(r4) | ||
165 | ld r4, VCPU_GPR(r4)(r4) | ||
166 | |||
167 | /* This sets the Magic value for the trampoline */ | ||
168 | |||
169 | li r11, 1 | ||
170 | stb r11, PACA_KVM_IN_GUEST(r13) | ||
171 | |||
172 | /* Jump to SLB patching handlder and into our guest */ | ||
173 | RFI | ||
174 | |||
175 | /* | ||
176 | * This is the handler in module memory. It gets jumped at from the | ||
177 | * lowmem trampoline code, so it's basically the guest exit code. | ||
178 | * | ||
179 | */ | ||
180 | |||
181 | .global kvmppc_handler_highmem | ||
182 | kvmppc_handler_highmem: | ||
183 | |||
184 | /* | ||
185 | * Register usage at this point: | ||
186 | * | ||
187 | * R00 = guest R13 | ||
188 | * R01 = host R1 | ||
189 | * R02 = host R2 | ||
190 | * R10 = guest PC | ||
191 | * R11 = guest MSR | ||
192 | * R12 = exit handler id | ||
193 | * R13 = PACA | ||
194 | * PACA.exmc.R9 = guest R1 | ||
195 | * PACA.exmc.R10 = guest R10 | ||
196 | * PACA.exmc.R11 = guest R11 | ||
197 | * PACA.exmc.R12 = guest R12 | ||
198 | * PACA.exmc.R13 = guest R2 | ||
199 | * PACA.exmc.DAR = guest DAR | ||
200 | * PACA.exmc.DSISR = guest DSISR | ||
201 | * PACA.exmc.LR = guest instruction | ||
202 | * PACA.exmc.CCR = guest CR | ||
203 | * PACA.exmc.SRR0 = guest R0 | ||
204 | * | ||
205 | */ | ||
206 | |||
207 | std r3, (PACA_EXMC+EX_R3)(r13) | ||
208 | |||
209 | /* save the exit id in R3 */ | ||
210 | mr r3, r12 | ||
211 | |||
212 | /* R12 = vcpu */ | ||
213 | ld r12, GPR4(r1) | ||
214 | |||
215 | /* Now save the guest state */ | ||
216 | |||
217 | std r0, VCPU_GPR(r13)(r12) | ||
218 | std r4, VCPU_GPR(r4)(r12) | ||
219 | std r5, VCPU_GPR(r5)(r12) | ||
220 | std r6, VCPU_GPR(r6)(r12) | ||
221 | std r7, VCPU_GPR(r7)(r12) | ||
222 | std r8, VCPU_GPR(r8)(r12) | ||
223 | std r9, VCPU_GPR(r9)(r12) | ||
224 | |||
225 | /* get registers from PACA */ | ||
226 | mfpaca r5, r0, EX_SRR0, r12 | ||
227 | mfpaca r5, r3, EX_R3, r12 | ||
228 | mfpaca r5, r1, EX_R9, r12 | ||
229 | mfpaca r5, r10, EX_R10, r12 | ||
230 | mfpaca r5, r11, EX_R11, r12 | ||
231 | mfpaca r5, r12, EX_R12, r12 | ||
232 | mfpaca r5, r2, EX_R13, r12 | ||
233 | |||
234 | lwz r5, (PACA_EXMC+EX_LR)(r13) | ||
235 | stw r5, VCPU_LAST_INST(r12) | ||
236 | |||
237 | lwz r5, (PACA_EXMC+EX_CCR)(r13) | ||
238 | stw r5, VCPU_CR(r12) | ||
239 | |||
240 | ld r5, VCPU_HFLAGS(r12) | ||
241 | rldicl. r5, r5, 0, 63 /* CR = ((r5 & 1) == 0) */ | ||
242 | beq no_dcbz32_off | ||
243 | |||
244 | mfspr r5,SPRN_HID5 | ||
245 | rldimi r5,r5,6,56 | ||
246 | mtspr SPRN_HID5,r5 | ||
247 | |||
248 | no_dcbz32_off: | ||
249 | |||
250 | /* XXX maybe skip on lightweight? */ | ||
251 | std r14, VCPU_GPR(r14)(r12) | ||
252 | std r15, VCPU_GPR(r15)(r12) | ||
253 | std r16, VCPU_GPR(r16)(r12) | ||
254 | std r17, VCPU_GPR(r17)(r12) | ||
255 | std r18, VCPU_GPR(r18)(r12) | ||
256 | std r19, VCPU_GPR(r19)(r12) | ||
257 | std r20, VCPU_GPR(r20)(r12) | ||
258 | std r21, VCPU_GPR(r21)(r12) | ||
259 | std r22, VCPU_GPR(r22)(r12) | ||
260 | std r23, VCPU_GPR(r23)(r12) | ||
261 | std r24, VCPU_GPR(r24)(r12) | ||
262 | std r25, VCPU_GPR(r25)(r12) | ||
263 | std r26, VCPU_GPR(r26)(r12) | ||
264 | std r27, VCPU_GPR(r27)(r12) | ||
265 | std r28, VCPU_GPR(r28)(r12) | ||
266 | std r29, VCPU_GPR(r29)(r12) | ||
267 | std r30, VCPU_GPR(r30)(r12) | ||
268 | std r31, VCPU_GPR(r31)(r12) | ||
269 | |||
270 | /* Restore non-volatile host registers (r14 - r31) */ | ||
271 | REST_NVGPRS(r1) | ||
272 | |||
273 | /* Save guest PC (R10) */ | ||
274 | std r10, VCPU_PC(r12) | ||
275 | |||
276 | /* Save guest msr (R11) */ | ||
277 | std r11, VCPU_SHADOW_MSR(r12) | ||
278 | |||
279 | /* Save guest CTR (in R12) */ | ||
280 | mfctr r5 | ||
281 | std r5, VCPU_CTR(r12) | ||
282 | |||
283 | /* Save guest LR */ | ||
284 | mflr r5 | ||
285 | std r5, VCPU_LR(r12) | ||
286 | |||
287 | /* Save guest XER */ | ||
288 | mfxer r5 | ||
289 | std r5, VCPU_XER(r12) | ||
290 | |||
291 | /* Save guest DAR */ | ||
292 | ld r5, (PACA_EXMC+EX_DAR)(r13) | ||
293 | std r5, VCPU_FAULT_DEAR(r12) | ||
294 | |||
295 | /* Save guest DSISR */ | ||
296 | lwz r5, (PACA_EXMC+EX_DSISR)(r13) | ||
297 | std r5, VCPU_FAULT_DSISR(r12) | ||
298 | |||
299 | /* Restore host msr -> SRR1 */ | ||
300 | ld r7, VCPU_HOST_MSR(r12) | ||
301 | mtsrr1 r7 | ||
302 | |||
303 | /* Restore host IP -> SRR0 */ | ||
304 | ld r6, VCPU_HOST_RETIP(r12) | ||
305 | mtsrr0 r6 | ||
306 | |||
307 | /* | ||
308 | * For some interrupts, we need to call the real Linux | ||
309 | * handler, so it can do work for us. This has to happen | ||
310 | * as if the interrupt arrived from the kernel though, | ||
311 | * so let's fake it here where most state is restored. | ||
312 | * | ||
313 | * Call Linux for hardware interrupts/decrementer | ||
314 | * r3 = address of interrupt handler (exit reason) | ||
315 | */ | ||
316 | |||
317 | cmpwi r3, BOOK3S_INTERRUPT_EXTERNAL | ||
318 | beq call_linux_handler | ||
319 | cmpwi r3, BOOK3S_INTERRUPT_DECREMENTER | ||
320 | beq call_linux_handler | ||
321 | |||
322 | /* Back to Interruptable Mode! (goto kvm_return_point) */ | ||
323 | RFI | ||
324 | |||
325 | call_linux_handler: | ||
326 | |||
327 | /* | ||
328 | * If we land here we need to jump back to the handler we | ||
329 | * came from. | ||
330 | * | ||
331 | * We have a page that we can access from real mode, so let's | ||
332 | * jump back to that and use it as a trampoline to get back into the | ||
333 | * interrupt handler! | ||
334 | * | ||
335 | * R3 still contains the exit code, | ||
336 | * R6 VCPU_HOST_RETIP and | ||
337 | * R7 VCPU_HOST_MSR | ||
338 | */ | ||
339 | |||
340 | mtlr r3 | ||
341 | |||
342 | ld r5, VCPU_TRAMPOLINE_LOWMEM(r12) | ||
343 | mtsrr0 r5 | ||
344 | LOAD_REG_IMMEDIATE(r5, MSR_KERNEL & ~(MSR_IR | MSR_DR)) | ||
345 | mtsrr1 r5 | ||
346 | |||
347 | RFI | ||
348 | |||
349 | .global kvm_return_point | ||
350 | kvm_return_point: | ||
351 | |||
352 | /* Jump back to lightweight entry if we're supposed to */ | ||
353 | /* go back into the guest */ | ||
354 | mr r5, r3 | ||
355 | /* Restore r3 (kvm_run) and r4 (vcpu) */ | ||
356 | REST_2GPRS(3, r1) | ||
357 | bl KVMPPC_HANDLE_EXIT | ||
358 | |||
359 | #if 0 /* XXX get lightweight exits back */ | ||
360 | cmpwi r3, RESUME_GUEST | ||
361 | bne kvm_exit_heavyweight | ||
362 | |||
363 | /* put VCPU and KVM_RUN back into place and roll again! */ | ||
364 | REST_2GPRS(3, r1) | ||
365 | b kvm_start_lightweight | ||
366 | |||
367 | kvm_exit_heavyweight: | ||
368 | /* Restore non-volatile host registers */ | ||
369 | ld r14, _LINK(r1) | ||
370 | mtlr r14 | ||
371 | REST_NVGPRS(r1) | ||
372 | |||
373 | addi r1, r1, SWITCH_FRAME_SIZE | ||
374 | #else | ||
375 | ld r4, _LINK(r1) | ||
376 | mtlr r4 | ||
377 | |||
378 | cmpwi r3, RESUME_GUEST | ||
379 | bne kvm_exit_heavyweight | ||
380 | |||
381 | REST_2GPRS(3, r1) | ||
382 | |||
383 | addi r1, r1, SWITCH_FRAME_SIZE | ||
384 | |||
385 | b kvm_start_entry | ||
386 | |||
387 | kvm_exit_heavyweight: | ||
388 | |||
389 | addi r1, r1, SWITCH_FRAME_SIZE | ||
390 | #endif | ||
391 | |||
392 | blr | ||
diff --git a/arch/powerpc/kvm/book3s_64_mmu.c b/arch/powerpc/kvm/book3s_64_mmu.c new file mode 100644 index 000000000000..5598f88f142e --- /dev/null +++ b/arch/powerpc/kvm/book3s_64_mmu.c | |||
@@ -0,0 +1,478 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License, version 2, as | ||
4 | * published by the Free Software Foundation. | ||
5 | * | ||
6 | * This program is distributed in the hope that it will be useful, | ||
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
9 | * GNU General Public License for more details. | ||
10 | * | ||
11 | * You should have received a copy of the GNU General Public License | ||
12 | * along with this program; if not, write to the Free Software | ||
13 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
14 | * | ||
15 | * Copyright SUSE Linux Products GmbH 2009 | ||
16 | * | ||
17 | * Authors: Alexander Graf <agraf@suse.de> | ||
18 | */ | ||
19 | |||
20 | #include <linux/types.h> | ||
21 | #include <linux/string.h> | ||
22 | #include <linux/kvm.h> | ||
23 | #include <linux/kvm_host.h> | ||
24 | #include <linux/highmem.h> | ||
25 | |||
26 | #include <asm/tlbflush.h> | ||
27 | #include <asm/kvm_ppc.h> | ||
28 | #include <asm/kvm_book3s.h> | ||
29 | |||
30 | /* #define DEBUG_MMU */ | ||
31 | |||
32 | #ifdef DEBUG_MMU | ||
33 | #define dprintk(X...) printk(KERN_INFO X) | ||
34 | #else | ||
35 | #define dprintk(X...) do { } while(0) | ||
36 | #endif | ||
37 | |||
38 | static void kvmppc_mmu_book3s_64_reset_msr(struct kvm_vcpu *vcpu) | ||
39 | { | ||
40 | kvmppc_set_msr(vcpu, MSR_SF); | ||
41 | } | ||
42 | |||
43 | static struct kvmppc_slb *kvmppc_mmu_book3s_64_find_slbe( | ||
44 | struct kvmppc_vcpu_book3s *vcpu_book3s, | ||
45 | gva_t eaddr) | ||
46 | { | ||
47 | int i; | ||
48 | u64 esid = GET_ESID(eaddr); | ||
49 | u64 esid_1t = GET_ESID_1T(eaddr); | ||
50 | |||
51 | for (i = 0; i < vcpu_book3s->slb_nr; i++) { | ||
52 | u64 cmp_esid = esid; | ||
53 | |||
54 | if (!vcpu_book3s->slb[i].valid) | ||
55 | continue; | ||
56 | |||
57 | if (vcpu_book3s->slb[i].large) | ||
58 | cmp_esid = esid_1t; | ||
59 | |||
60 | if (vcpu_book3s->slb[i].esid == cmp_esid) | ||
61 | return &vcpu_book3s->slb[i]; | ||
62 | } | ||
63 | |||
64 | dprintk("KVM: No SLB entry found for 0x%lx [%llx | %llx]\n", | ||
65 | eaddr, esid, esid_1t); | ||
66 | for (i = 0; i < vcpu_book3s->slb_nr; i++) { | ||
67 | if (vcpu_book3s->slb[i].vsid) | ||
68 | dprintk(" %d: %c%c %llx %llx\n", i, | ||
69 | vcpu_book3s->slb[i].valid ? 'v' : ' ', | ||
70 | vcpu_book3s->slb[i].large ? 'l' : ' ', | ||
71 | vcpu_book3s->slb[i].esid, | ||
72 | vcpu_book3s->slb[i].vsid); | ||
73 | } | ||
74 | |||
75 | return NULL; | ||
76 | } | ||
77 | |||
78 | static u64 kvmppc_mmu_book3s_64_ea_to_vp(struct kvm_vcpu *vcpu, gva_t eaddr, | ||
79 | bool data) | ||
80 | { | ||
81 | struct kvmppc_slb *slb; | ||
82 | |||
83 | slb = kvmppc_mmu_book3s_64_find_slbe(to_book3s(vcpu), eaddr); | ||
84 | if (!slb) | ||
85 | return 0; | ||
86 | |||
87 | if (slb->large) | ||
88 | return (((u64)eaddr >> 12) & 0xfffffff) | | ||
89 | (((u64)slb->vsid) << 28); | ||
90 | |||
91 | return (((u64)eaddr >> 12) & 0xffff) | (((u64)slb->vsid) << 16); | ||
92 | } | ||
93 | |||
94 | static int kvmppc_mmu_book3s_64_get_pagesize(struct kvmppc_slb *slbe) | ||
95 | { | ||
96 | return slbe->large ? 24 : 12; | ||
97 | } | ||
98 | |||
99 | static u32 kvmppc_mmu_book3s_64_get_page(struct kvmppc_slb *slbe, gva_t eaddr) | ||
100 | { | ||
101 | int p = kvmppc_mmu_book3s_64_get_pagesize(slbe); | ||
102 | return ((eaddr & 0xfffffff) >> p); | ||
103 | } | ||
104 | |||
105 | static hva_t kvmppc_mmu_book3s_64_get_pteg( | ||
106 | struct kvmppc_vcpu_book3s *vcpu_book3s, | ||
107 | struct kvmppc_slb *slbe, gva_t eaddr, | ||
108 | bool second) | ||
109 | { | ||
110 | u64 hash, pteg, htabsize; | ||
111 | u32 page; | ||
112 | hva_t r; | ||
113 | |||
114 | page = kvmppc_mmu_book3s_64_get_page(slbe, eaddr); | ||
115 | htabsize = ((1 << ((vcpu_book3s->sdr1 & 0x1f) + 11)) - 1); | ||
116 | |||
117 | hash = slbe->vsid ^ page; | ||
118 | if (second) | ||
119 | hash = ~hash; | ||
120 | hash &= ((1ULL << 39ULL) - 1ULL); | ||
121 | hash &= htabsize; | ||
122 | hash <<= 7ULL; | ||
123 | |||
124 | pteg = vcpu_book3s->sdr1 & 0xfffffffffffc0000ULL; | ||
125 | pteg |= hash; | ||
126 | |||
127 | dprintk("MMU: page=0x%x sdr1=0x%llx pteg=0x%llx vsid=0x%llx\n", | ||
128 | page, vcpu_book3s->sdr1, pteg, slbe->vsid); | ||
129 | |||
130 | r = gfn_to_hva(vcpu_book3s->vcpu.kvm, pteg >> PAGE_SHIFT); | ||
131 | if (kvm_is_error_hva(r)) | ||
132 | return r; | ||
133 | return r | (pteg & ~PAGE_MASK); | ||
134 | } | ||
135 | |||
136 | static u64 kvmppc_mmu_book3s_64_get_avpn(struct kvmppc_slb *slbe, gva_t eaddr) | ||
137 | { | ||
138 | int p = kvmppc_mmu_book3s_64_get_pagesize(slbe); | ||
139 | u64 avpn; | ||
140 | |||
141 | avpn = kvmppc_mmu_book3s_64_get_page(slbe, eaddr); | ||
142 | avpn |= slbe->vsid << (28 - p); | ||
143 | |||
144 | if (p < 24) | ||
145 | avpn >>= ((80 - p) - 56) - 8; | ||
146 | else | ||
147 | avpn <<= 8; | ||
148 | |||
149 | return avpn; | ||
150 | } | ||
151 | |||
152 | static int kvmppc_mmu_book3s_64_xlate(struct kvm_vcpu *vcpu, gva_t eaddr, | ||
153 | struct kvmppc_pte *gpte, bool data) | ||
154 | { | ||
155 | struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu); | ||
156 | struct kvmppc_slb *slbe; | ||
157 | hva_t ptegp; | ||
158 | u64 pteg[16]; | ||
159 | u64 avpn = 0; | ||
160 | int i; | ||
161 | u8 key = 0; | ||
162 | bool found = false; | ||
163 | bool perm_err = false; | ||
164 | int second = 0; | ||
165 | |||
166 | slbe = kvmppc_mmu_book3s_64_find_slbe(vcpu_book3s, eaddr); | ||
167 | if (!slbe) | ||
168 | goto no_seg_found; | ||
169 | |||
170 | do_second: | ||
171 | ptegp = kvmppc_mmu_book3s_64_get_pteg(vcpu_book3s, slbe, eaddr, second); | ||
172 | if (kvm_is_error_hva(ptegp)) | ||
173 | goto no_page_found; | ||
174 | |||
175 | avpn = kvmppc_mmu_book3s_64_get_avpn(slbe, eaddr); | ||
176 | |||
177 | if(copy_from_user(pteg, (void __user *)ptegp, sizeof(pteg))) { | ||
178 | printk(KERN_ERR "KVM can't copy data from 0x%lx!\n", ptegp); | ||
179 | goto no_page_found; | ||
180 | } | ||
181 | |||
182 | if ((vcpu->arch.msr & MSR_PR) && slbe->Kp) | ||
183 | key = 4; | ||
184 | else if (!(vcpu->arch.msr & MSR_PR) && slbe->Ks) | ||
185 | key = 4; | ||
186 | |||
187 | for (i=0; i<16; i+=2) { | ||
188 | u64 v = pteg[i]; | ||
189 | u64 r = pteg[i+1]; | ||
190 | |||
191 | /* Valid check */ | ||
192 | if (!(v & HPTE_V_VALID)) | ||
193 | continue; | ||
194 | /* Hash check */ | ||
195 | if ((v & HPTE_V_SECONDARY) != second) | ||
196 | continue; | ||
197 | |||
198 | /* AVPN compare */ | ||
199 | if (HPTE_V_AVPN_VAL(avpn) == HPTE_V_AVPN_VAL(v)) { | ||
200 | u8 pp = (r & HPTE_R_PP) | key; | ||
201 | int eaddr_mask = 0xFFF; | ||
202 | |||
203 | gpte->eaddr = eaddr; | ||
204 | gpte->vpage = kvmppc_mmu_book3s_64_ea_to_vp(vcpu, | ||
205 | eaddr, | ||
206 | data); | ||
207 | if (slbe->large) | ||
208 | eaddr_mask = 0xFFFFFF; | ||
209 | gpte->raddr = (r & HPTE_R_RPN) | (eaddr & eaddr_mask); | ||
210 | gpte->may_execute = ((r & HPTE_R_N) ? false : true); | ||
211 | gpte->may_read = false; | ||
212 | gpte->may_write = false; | ||
213 | |||
214 | switch (pp) { | ||
215 | case 0: | ||
216 | case 1: | ||
217 | case 2: | ||
218 | case 6: | ||
219 | gpte->may_write = true; | ||
220 | /* fall through */ | ||
221 | case 3: | ||
222 | case 5: | ||
223 | case 7: | ||
224 | gpte->may_read = true; | ||
225 | break; | ||
226 | } | ||
227 | |||
228 | if (!gpte->may_read) { | ||
229 | perm_err = true; | ||
230 | continue; | ||
231 | } | ||
232 | |||
233 | dprintk("KVM MMU: Translated 0x%lx [0x%llx] -> 0x%llx " | ||
234 | "-> 0x%llx\n", | ||
235 | eaddr, avpn, gpte->vpage, gpte->raddr); | ||
236 | found = true; | ||
237 | break; | ||
238 | } | ||
239 | } | ||
240 | |||
241 | /* Update PTE R and C bits, so the guest's swapper knows we used the | ||
242 | * page */ | ||
243 | if (found) { | ||
244 | u32 oldr = pteg[i+1]; | ||
245 | |||
246 | if (gpte->may_read) { | ||
247 | /* Set the accessed flag */ | ||
248 | pteg[i+1] |= HPTE_R_R; | ||
249 | } | ||
250 | if (gpte->may_write) { | ||
251 | /* Set the dirty flag */ | ||
252 | pteg[i+1] |= HPTE_R_C; | ||
253 | } else { | ||
254 | dprintk("KVM: Mapping read-only page!\n"); | ||
255 | } | ||
256 | |||
257 | /* Write back into the PTEG */ | ||
258 | if (pteg[i+1] != oldr) | ||
259 | copy_to_user((void __user *)ptegp, pteg, sizeof(pteg)); | ||
260 | |||
261 | return 0; | ||
262 | } else { | ||
263 | dprintk("KVM MMU: No PTE found (ea=0x%lx sdr1=0x%llx " | ||
264 | "ptegp=0x%lx)\n", | ||
265 | eaddr, to_book3s(vcpu)->sdr1, ptegp); | ||
266 | for (i = 0; i < 16; i += 2) | ||
267 | dprintk(" %02d: 0x%llx - 0x%llx (0x%llx)\n", | ||
268 | i, pteg[i], pteg[i+1], avpn); | ||
269 | |||
270 | if (!second) { | ||
271 | second = HPTE_V_SECONDARY; | ||
272 | goto do_second; | ||
273 | } | ||
274 | } | ||
275 | |||
276 | |||
277 | no_page_found: | ||
278 | |||
279 | |||
280 | if (perm_err) | ||
281 | return -EPERM; | ||
282 | |||
283 | return -ENOENT; | ||
284 | |||
285 | no_seg_found: | ||
286 | |||
287 | dprintk("KVM MMU: Trigger segment fault\n"); | ||
288 | return -EINVAL; | ||
289 | } | ||
290 | |||
291 | static void kvmppc_mmu_book3s_64_slbmte(struct kvm_vcpu *vcpu, u64 rs, u64 rb) | ||
292 | { | ||
293 | struct kvmppc_vcpu_book3s *vcpu_book3s; | ||
294 | u64 esid, esid_1t; | ||
295 | int slb_nr; | ||
296 | struct kvmppc_slb *slbe; | ||
297 | |||
298 | dprintk("KVM MMU: slbmte(0x%llx, 0x%llx)\n", rs, rb); | ||
299 | |||
300 | vcpu_book3s = to_book3s(vcpu); | ||
301 | |||
302 | esid = GET_ESID(rb); | ||
303 | esid_1t = GET_ESID_1T(rb); | ||
304 | slb_nr = rb & 0xfff; | ||
305 | |||
306 | if (slb_nr > vcpu_book3s->slb_nr) | ||
307 | return; | ||
308 | |||
309 | slbe = &vcpu_book3s->slb[slb_nr]; | ||
310 | |||
311 | slbe->large = (rs & SLB_VSID_L) ? 1 : 0; | ||
312 | slbe->esid = slbe->large ? esid_1t : esid; | ||
313 | slbe->vsid = rs >> 12; | ||
314 | slbe->valid = (rb & SLB_ESID_V) ? 1 : 0; | ||
315 | slbe->Ks = (rs & SLB_VSID_KS) ? 1 : 0; | ||
316 | slbe->Kp = (rs & SLB_VSID_KP) ? 1 : 0; | ||
317 | slbe->nx = (rs & SLB_VSID_N) ? 1 : 0; | ||
318 | slbe->class = (rs & SLB_VSID_C) ? 1 : 0; | ||
319 | |||
320 | slbe->orige = rb & (ESID_MASK | SLB_ESID_V); | ||
321 | slbe->origv = rs; | ||
322 | |||
323 | /* Map the new segment */ | ||
324 | kvmppc_mmu_map_segment(vcpu, esid << SID_SHIFT); | ||
325 | } | ||
326 | |||
327 | static u64 kvmppc_mmu_book3s_64_slbmfee(struct kvm_vcpu *vcpu, u64 slb_nr) | ||
328 | { | ||
329 | struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu); | ||
330 | struct kvmppc_slb *slbe; | ||
331 | |||
332 | if (slb_nr > vcpu_book3s->slb_nr) | ||
333 | return 0; | ||
334 | |||
335 | slbe = &vcpu_book3s->slb[slb_nr]; | ||
336 | |||
337 | return slbe->orige; | ||
338 | } | ||
339 | |||
340 | static u64 kvmppc_mmu_book3s_64_slbmfev(struct kvm_vcpu *vcpu, u64 slb_nr) | ||
341 | { | ||
342 | struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu); | ||
343 | struct kvmppc_slb *slbe; | ||
344 | |||
345 | if (slb_nr > vcpu_book3s->slb_nr) | ||
346 | return 0; | ||
347 | |||
348 | slbe = &vcpu_book3s->slb[slb_nr]; | ||
349 | |||
350 | return slbe->origv; | ||
351 | } | ||
352 | |||
353 | static void kvmppc_mmu_book3s_64_slbie(struct kvm_vcpu *vcpu, u64 ea) | ||
354 | { | ||
355 | struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu); | ||
356 | struct kvmppc_slb *slbe; | ||
357 | |||
358 | dprintk("KVM MMU: slbie(0x%llx)\n", ea); | ||
359 | |||
360 | slbe = kvmppc_mmu_book3s_64_find_slbe(vcpu_book3s, ea); | ||
361 | |||
362 | if (!slbe) | ||
363 | return; | ||
364 | |||
365 | dprintk("KVM MMU: slbie(0x%llx, 0x%llx)\n", ea, slbe->esid); | ||
366 | |||
367 | slbe->valid = false; | ||
368 | |||
369 | kvmppc_mmu_map_segment(vcpu, ea); | ||
370 | } | ||
371 | |||
372 | static void kvmppc_mmu_book3s_64_slbia(struct kvm_vcpu *vcpu) | ||
373 | { | ||
374 | struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu); | ||
375 | int i; | ||
376 | |||
377 | dprintk("KVM MMU: slbia()\n"); | ||
378 | |||
379 | for (i = 1; i < vcpu_book3s->slb_nr; i++) | ||
380 | vcpu_book3s->slb[i].valid = false; | ||
381 | |||
382 | if (vcpu->arch.msr & MSR_IR) { | ||
383 | kvmppc_mmu_flush_segments(vcpu); | ||
384 | kvmppc_mmu_map_segment(vcpu, vcpu->arch.pc); | ||
385 | } | ||
386 | } | ||
387 | |||
388 | static void kvmppc_mmu_book3s_64_mtsrin(struct kvm_vcpu *vcpu, u32 srnum, | ||
389 | ulong value) | ||
390 | { | ||
391 | u64 rb = 0, rs = 0; | ||
392 | |||
393 | /* ESID = srnum */ | ||
394 | rb |= (srnum & 0xf) << 28; | ||
395 | /* Set the valid bit */ | ||
396 | rb |= 1 << 27; | ||
397 | /* Index = ESID */ | ||
398 | rb |= srnum; | ||
399 | |||
400 | /* VSID = VSID */ | ||
401 | rs |= (value & 0xfffffff) << 12; | ||
402 | /* flags = flags */ | ||
403 | rs |= ((value >> 27) & 0xf) << 9; | ||
404 | |||
405 | kvmppc_mmu_book3s_64_slbmte(vcpu, rs, rb); | ||
406 | } | ||
407 | |||
408 | static void kvmppc_mmu_book3s_64_tlbie(struct kvm_vcpu *vcpu, ulong va, | ||
409 | bool large) | ||
410 | { | ||
411 | u64 mask = 0xFFFFFFFFFULL; | ||
412 | |||
413 | dprintk("KVM MMU: tlbie(0x%lx)\n", va); | ||
414 | |||
415 | if (large) | ||
416 | mask = 0xFFFFFF000ULL; | ||
417 | kvmppc_mmu_pte_vflush(vcpu, va >> 12, mask); | ||
418 | } | ||
419 | |||
420 | static int kvmppc_mmu_book3s_64_esid_to_vsid(struct kvm_vcpu *vcpu, u64 esid, | ||
421 | u64 *vsid) | ||
422 | { | ||
423 | switch (vcpu->arch.msr & (MSR_DR|MSR_IR)) { | ||
424 | case 0: | ||
425 | *vsid = (VSID_REAL >> 16) | esid; | ||
426 | break; | ||
427 | case MSR_IR: | ||
428 | *vsid = (VSID_REAL_IR >> 16) | esid; | ||
429 | break; | ||
430 | case MSR_DR: | ||
431 | *vsid = (VSID_REAL_DR >> 16) | esid; | ||
432 | break; | ||
433 | case MSR_DR|MSR_IR: | ||
434 | { | ||
435 | ulong ea; | ||
436 | struct kvmppc_slb *slb; | ||
437 | ea = esid << SID_SHIFT; | ||
438 | slb = kvmppc_mmu_book3s_64_find_slbe(to_book3s(vcpu), ea); | ||
439 | if (slb) | ||
440 | *vsid = slb->vsid; | ||
441 | else | ||
442 | return -ENOENT; | ||
443 | |||
444 | break; | ||
445 | } | ||
446 | default: | ||
447 | BUG(); | ||
448 | break; | ||
449 | } | ||
450 | |||
451 | return 0; | ||
452 | } | ||
453 | |||
454 | static bool kvmppc_mmu_book3s_64_is_dcbz32(struct kvm_vcpu *vcpu) | ||
455 | { | ||
456 | return (to_book3s(vcpu)->hid[5] & 0x80); | ||
457 | } | ||
458 | |||
459 | void kvmppc_mmu_book3s_64_init(struct kvm_vcpu *vcpu) | ||
460 | { | ||
461 | struct kvmppc_mmu *mmu = &vcpu->arch.mmu; | ||
462 | |||
463 | mmu->mfsrin = NULL; | ||
464 | mmu->mtsrin = kvmppc_mmu_book3s_64_mtsrin; | ||
465 | mmu->slbmte = kvmppc_mmu_book3s_64_slbmte; | ||
466 | mmu->slbmfee = kvmppc_mmu_book3s_64_slbmfee; | ||
467 | mmu->slbmfev = kvmppc_mmu_book3s_64_slbmfev; | ||
468 | mmu->slbie = kvmppc_mmu_book3s_64_slbie; | ||
469 | mmu->slbia = kvmppc_mmu_book3s_64_slbia; | ||
470 | mmu->xlate = kvmppc_mmu_book3s_64_xlate; | ||
471 | mmu->reset_msr = kvmppc_mmu_book3s_64_reset_msr; | ||
472 | mmu->tlbie = kvmppc_mmu_book3s_64_tlbie; | ||
473 | mmu->esid_to_vsid = kvmppc_mmu_book3s_64_esid_to_vsid; | ||
474 | mmu->ea_to_vp = kvmppc_mmu_book3s_64_ea_to_vp; | ||
475 | mmu->is_dcbz32 = kvmppc_mmu_book3s_64_is_dcbz32; | ||
476 | |||
477 | vcpu->arch.hflags |= BOOK3S_HFLAG_SLB; | ||
478 | } | ||
diff --git a/arch/powerpc/kvm/book3s_64_mmu_host.c b/arch/powerpc/kvm/book3s_64_mmu_host.c new file mode 100644 index 000000000000..f2899b297ffd --- /dev/null +++ b/arch/powerpc/kvm/book3s_64_mmu_host.c | |||
@@ -0,0 +1,408 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009 SUSE Linux Products GmbH. All rights reserved. | ||
3 | * | ||
4 | * Authors: | ||
5 | * Alexander Graf <agraf@suse.de> | ||
6 | * Kevin Wolf <mail@kevin-wolf.de> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License, version 2, as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/kvm_host.h> | ||
23 | |||
24 | #include <asm/kvm_ppc.h> | ||
25 | #include <asm/kvm_book3s.h> | ||
26 | #include <asm/mmu-hash64.h> | ||
27 | #include <asm/machdep.h> | ||
28 | #include <asm/mmu_context.h> | ||
29 | #include <asm/hw_irq.h> | ||
30 | |||
31 | #define PTE_SIZE 12 | ||
32 | #define VSID_ALL 0 | ||
33 | |||
34 | /* #define DEBUG_MMU */ | ||
35 | /* #define DEBUG_SLB */ | ||
36 | |||
37 | #ifdef DEBUG_MMU | ||
38 | #define dprintk_mmu(a, ...) printk(KERN_INFO a, __VA_ARGS__) | ||
39 | #else | ||
40 | #define dprintk_mmu(a, ...) do { } while(0) | ||
41 | #endif | ||
42 | |||
43 | #ifdef DEBUG_SLB | ||
44 | #define dprintk_slb(a, ...) printk(KERN_INFO a, __VA_ARGS__) | ||
45 | #else | ||
46 | #define dprintk_slb(a, ...) do { } while(0) | ||
47 | #endif | ||
48 | |||
49 | static void invalidate_pte(struct hpte_cache *pte) | ||
50 | { | ||
51 | dprintk_mmu("KVM: Flushing SPT %d: 0x%llx (0x%llx) -> 0x%llx\n", | ||
52 | i, pte->pte.eaddr, pte->pte.vpage, pte->host_va); | ||
53 | |||
54 | ppc_md.hpte_invalidate(pte->slot, pte->host_va, | ||
55 | MMU_PAGE_4K, MMU_SEGSIZE_256M, | ||
56 | false); | ||
57 | pte->host_va = 0; | ||
58 | kvm_release_pfn_dirty(pte->pfn); | ||
59 | } | ||
60 | |||
61 | void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, u64 guest_ea, u64 ea_mask) | ||
62 | { | ||
63 | int i; | ||
64 | |||
65 | dprintk_mmu("KVM: Flushing %d Shadow PTEs: 0x%llx & 0x%llx\n", | ||
66 | vcpu->arch.hpte_cache_offset, guest_ea, ea_mask); | ||
67 | BUG_ON(vcpu->arch.hpte_cache_offset > HPTEG_CACHE_NUM); | ||
68 | |||
69 | guest_ea &= ea_mask; | ||
70 | for (i = 0; i < vcpu->arch.hpte_cache_offset; i++) { | ||
71 | struct hpte_cache *pte; | ||
72 | |||
73 | pte = &vcpu->arch.hpte_cache[i]; | ||
74 | if (!pte->host_va) | ||
75 | continue; | ||
76 | |||
77 | if ((pte->pte.eaddr & ea_mask) == guest_ea) { | ||
78 | invalidate_pte(pte); | ||
79 | } | ||
80 | } | ||
81 | |||
82 | /* Doing a complete flush -> start from scratch */ | ||
83 | if (!ea_mask) | ||
84 | vcpu->arch.hpte_cache_offset = 0; | ||
85 | } | ||
86 | |||
87 | void kvmppc_mmu_pte_vflush(struct kvm_vcpu *vcpu, u64 guest_vp, u64 vp_mask) | ||
88 | { | ||
89 | int i; | ||
90 | |||
91 | dprintk_mmu("KVM: Flushing %d Shadow vPTEs: 0x%llx & 0x%llx\n", | ||
92 | vcpu->arch.hpte_cache_offset, guest_vp, vp_mask); | ||
93 | BUG_ON(vcpu->arch.hpte_cache_offset > HPTEG_CACHE_NUM); | ||
94 | |||
95 | guest_vp &= vp_mask; | ||
96 | for (i = 0; i < vcpu->arch.hpte_cache_offset; i++) { | ||
97 | struct hpte_cache *pte; | ||
98 | |||
99 | pte = &vcpu->arch.hpte_cache[i]; | ||
100 | if (!pte->host_va) | ||
101 | continue; | ||
102 | |||
103 | if ((pte->pte.vpage & vp_mask) == guest_vp) { | ||
104 | invalidate_pte(pte); | ||
105 | } | ||
106 | } | ||
107 | } | ||
108 | |||
109 | void kvmppc_mmu_pte_pflush(struct kvm_vcpu *vcpu, u64 pa_start, u64 pa_end) | ||
110 | { | ||
111 | int i; | ||
112 | |||
113 | dprintk_mmu("KVM: Flushing %d Shadow pPTEs: 0x%llx & 0x%llx\n", | ||
114 | vcpu->arch.hpte_cache_offset, guest_pa, pa_mask); | ||
115 | BUG_ON(vcpu->arch.hpte_cache_offset > HPTEG_CACHE_NUM); | ||
116 | |||
117 | for (i = 0; i < vcpu->arch.hpte_cache_offset; i++) { | ||
118 | struct hpte_cache *pte; | ||
119 | |||
120 | pte = &vcpu->arch.hpte_cache[i]; | ||
121 | if (!pte->host_va) | ||
122 | continue; | ||
123 | |||
124 | if ((pte->pte.raddr >= pa_start) && | ||
125 | (pte->pte.raddr < pa_end)) { | ||
126 | invalidate_pte(pte); | ||
127 | } | ||
128 | } | ||
129 | } | ||
130 | |||
131 | struct kvmppc_pte *kvmppc_mmu_find_pte(struct kvm_vcpu *vcpu, u64 ea, bool data) | ||
132 | { | ||
133 | int i; | ||
134 | u64 guest_vp; | ||
135 | |||
136 | guest_vp = vcpu->arch.mmu.ea_to_vp(vcpu, ea, false); | ||
137 | for (i=0; i<vcpu->arch.hpte_cache_offset; i++) { | ||
138 | struct hpte_cache *pte; | ||
139 | |||
140 | pte = &vcpu->arch.hpte_cache[i]; | ||
141 | if (!pte->host_va) | ||
142 | continue; | ||
143 | |||
144 | if (pte->pte.vpage == guest_vp) | ||
145 | return &pte->pte; | ||
146 | } | ||
147 | |||
148 | return NULL; | ||
149 | } | ||
150 | |||
151 | static int kvmppc_mmu_hpte_cache_next(struct kvm_vcpu *vcpu) | ||
152 | { | ||
153 | if (vcpu->arch.hpte_cache_offset == HPTEG_CACHE_NUM) | ||
154 | kvmppc_mmu_pte_flush(vcpu, 0, 0); | ||
155 | |||
156 | return vcpu->arch.hpte_cache_offset++; | ||
157 | } | ||
158 | |||
159 | /* We keep 512 gvsid->hvsid entries, mapping the guest ones to the array using | ||
160 | * a hash, so we don't waste cycles on looping */ | ||
161 | static u16 kvmppc_sid_hash(struct kvm_vcpu *vcpu, u64 gvsid) | ||
162 | { | ||
163 | return (u16)(((gvsid >> (SID_MAP_BITS * 7)) & SID_MAP_MASK) ^ | ||
164 | ((gvsid >> (SID_MAP_BITS * 6)) & SID_MAP_MASK) ^ | ||
165 | ((gvsid >> (SID_MAP_BITS * 5)) & SID_MAP_MASK) ^ | ||
166 | ((gvsid >> (SID_MAP_BITS * 4)) & SID_MAP_MASK) ^ | ||
167 | ((gvsid >> (SID_MAP_BITS * 3)) & SID_MAP_MASK) ^ | ||
168 | ((gvsid >> (SID_MAP_BITS * 2)) & SID_MAP_MASK) ^ | ||
169 | ((gvsid >> (SID_MAP_BITS * 1)) & SID_MAP_MASK) ^ | ||
170 | ((gvsid >> (SID_MAP_BITS * 0)) & SID_MAP_MASK)); | ||
171 | } | ||
172 | |||
173 | |||
174 | static struct kvmppc_sid_map *find_sid_vsid(struct kvm_vcpu *vcpu, u64 gvsid) | ||
175 | { | ||
176 | struct kvmppc_sid_map *map; | ||
177 | u16 sid_map_mask; | ||
178 | |||
179 | if (vcpu->arch.msr & MSR_PR) | ||
180 | gvsid |= VSID_PR; | ||
181 | |||
182 | sid_map_mask = kvmppc_sid_hash(vcpu, gvsid); | ||
183 | map = &to_book3s(vcpu)->sid_map[sid_map_mask]; | ||
184 | if (map->guest_vsid == gvsid) { | ||
185 | dprintk_slb("SLB: Searching 0x%llx -> 0x%llx\n", | ||
186 | gvsid, map->host_vsid); | ||
187 | return map; | ||
188 | } | ||
189 | |||
190 | map = &to_book3s(vcpu)->sid_map[SID_MAP_MASK - sid_map_mask]; | ||
191 | if (map->guest_vsid == gvsid) { | ||
192 | dprintk_slb("SLB: Searching 0x%llx -> 0x%llx\n", | ||
193 | gvsid, map->host_vsid); | ||
194 | return map; | ||
195 | } | ||
196 | |||
197 | dprintk_slb("SLB: Searching 0x%llx -> not found\n", gvsid); | ||
198 | return NULL; | ||
199 | } | ||
200 | |||
201 | int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte) | ||
202 | { | ||
203 | pfn_t hpaddr; | ||
204 | ulong hash, hpteg, va; | ||
205 | u64 vsid; | ||
206 | int ret; | ||
207 | int rflags = 0x192; | ||
208 | int vflags = 0; | ||
209 | int attempt = 0; | ||
210 | struct kvmppc_sid_map *map; | ||
211 | |||
212 | /* Get host physical address for gpa */ | ||
213 | hpaddr = gfn_to_pfn(vcpu->kvm, orig_pte->raddr >> PAGE_SHIFT); | ||
214 | if (kvm_is_error_hva(hpaddr)) { | ||
215 | printk(KERN_INFO "Couldn't get guest page for gfn %llx!\n", orig_pte->eaddr); | ||
216 | return -EINVAL; | ||
217 | } | ||
218 | hpaddr <<= PAGE_SHIFT; | ||
219 | #if PAGE_SHIFT == 12 | ||
220 | #elif PAGE_SHIFT == 16 | ||
221 | hpaddr |= orig_pte->raddr & 0xf000; | ||
222 | #else | ||
223 | #error Unknown page size | ||
224 | #endif | ||
225 | |||
226 | /* and write the mapping ea -> hpa into the pt */ | ||
227 | vcpu->arch.mmu.esid_to_vsid(vcpu, orig_pte->eaddr >> SID_SHIFT, &vsid); | ||
228 | map = find_sid_vsid(vcpu, vsid); | ||
229 | if (!map) { | ||
230 | kvmppc_mmu_map_segment(vcpu, orig_pte->eaddr); | ||
231 | map = find_sid_vsid(vcpu, vsid); | ||
232 | } | ||
233 | BUG_ON(!map); | ||
234 | |||
235 | vsid = map->host_vsid; | ||
236 | va = hpt_va(orig_pte->eaddr, vsid, MMU_SEGSIZE_256M); | ||
237 | |||
238 | if (!orig_pte->may_write) | ||
239 | rflags |= HPTE_R_PP; | ||
240 | else | ||
241 | mark_page_dirty(vcpu->kvm, orig_pte->raddr >> PAGE_SHIFT); | ||
242 | |||
243 | if (!orig_pte->may_execute) | ||
244 | rflags |= HPTE_R_N; | ||
245 | |||
246 | hash = hpt_hash(va, PTE_SIZE, MMU_SEGSIZE_256M); | ||
247 | |||
248 | map_again: | ||
249 | hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP); | ||
250 | |||
251 | /* In case we tried normal mapping already, let's nuke old entries */ | ||
252 | if (attempt > 1) | ||
253 | if (ppc_md.hpte_remove(hpteg) < 0) | ||
254 | return -1; | ||
255 | |||
256 | ret = ppc_md.hpte_insert(hpteg, va, hpaddr, rflags, vflags, MMU_PAGE_4K, MMU_SEGSIZE_256M); | ||
257 | |||
258 | if (ret < 0) { | ||
259 | /* If we couldn't map a primary PTE, try a secondary */ | ||
260 | #ifdef USE_SECONDARY | ||
261 | hash = ~hash; | ||
262 | attempt++; | ||
263 | if (attempt % 2) | ||
264 | vflags = HPTE_V_SECONDARY; | ||
265 | else | ||
266 | vflags = 0; | ||
267 | #else | ||
268 | attempt = 2; | ||
269 | #endif | ||
270 | goto map_again; | ||
271 | } else { | ||
272 | int hpte_id = kvmppc_mmu_hpte_cache_next(vcpu); | ||
273 | struct hpte_cache *pte = &vcpu->arch.hpte_cache[hpte_id]; | ||
274 | |||
275 | dprintk_mmu("KVM: %c%c Map 0x%llx: [%lx] 0x%lx (0x%llx) -> %lx\n", | ||
276 | ((rflags & HPTE_R_PP) == 3) ? '-' : 'w', | ||
277 | (rflags & HPTE_R_N) ? '-' : 'x', | ||
278 | orig_pte->eaddr, hpteg, va, orig_pte->vpage, hpaddr); | ||
279 | |||
280 | pte->slot = hpteg + (ret & 7); | ||
281 | pte->host_va = va; | ||
282 | pte->pte = *orig_pte; | ||
283 | pte->pfn = hpaddr >> PAGE_SHIFT; | ||
284 | } | ||
285 | |||
286 | return 0; | ||
287 | } | ||
288 | |||
289 | static struct kvmppc_sid_map *create_sid_map(struct kvm_vcpu *vcpu, u64 gvsid) | ||
290 | { | ||
291 | struct kvmppc_sid_map *map; | ||
292 | struct kvmppc_vcpu_book3s *vcpu_book3s = to_book3s(vcpu); | ||
293 | u16 sid_map_mask; | ||
294 | static int backwards_map = 0; | ||
295 | |||
296 | if (vcpu->arch.msr & MSR_PR) | ||
297 | gvsid |= VSID_PR; | ||
298 | |||
299 | /* We might get collisions that trap in preceding order, so let's | ||
300 | map them differently */ | ||
301 | |||
302 | sid_map_mask = kvmppc_sid_hash(vcpu, gvsid); | ||
303 | if (backwards_map) | ||
304 | sid_map_mask = SID_MAP_MASK - sid_map_mask; | ||
305 | |||
306 | map = &to_book3s(vcpu)->sid_map[sid_map_mask]; | ||
307 | |||
308 | /* Make sure we're taking the other map next time */ | ||
309 | backwards_map = !backwards_map; | ||
310 | |||
311 | /* Uh-oh ... out of mappings. Let's flush! */ | ||
312 | if (vcpu_book3s->vsid_next == vcpu_book3s->vsid_max) { | ||
313 | vcpu_book3s->vsid_next = vcpu_book3s->vsid_first; | ||
314 | memset(vcpu_book3s->sid_map, 0, | ||
315 | sizeof(struct kvmppc_sid_map) * SID_MAP_NUM); | ||
316 | kvmppc_mmu_pte_flush(vcpu, 0, 0); | ||
317 | kvmppc_mmu_flush_segments(vcpu); | ||
318 | } | ||
319 | map->host_vsid = vcpu_book3s->vsid_next++; | ||
320 | |||
321 | map->guest_vsid = gvsid; | ||
322 | map->valid = true; | ||
323 | |||
324 | return map; | ||
325 | } | ||
326 | |||
327 | static int kvmppc_mmu_next_segment(struct kvm_vcpu *vcpu, ulong esid) | ||
328 | { | ||
329 | int i; | ||
330 | int max_slb_size = 64; | ||
331 | int found_inval = -1; | ||
332 | int r; | ||
333 | |||
334 | if (!get_paca()->kvm_slb_max) | ||
335 | get_paca()->kvm_slb_max = 1; | ||
336 | |||
337 | /* Are we overwriting? */ | ||
338 | for (i = 1; i < get_paca()->kvm_slb_max; i++) { | ||
339 | if (!(get_paca()->kvm_slb[i].esid & SLB_ESID_V)) | ||
340 | found_inval = i; | ||
341 | else if ((get_paca()->kvm_slb[i].esid & ESID_MASK) == esid) | ||
342 | return i; | ||
343 | } | ||
344 | |||
345 | /* Found a spare entry that was invalidated before */ | ||
346 | if (found_inval > 0) | ||
347 | return found_inval; | ||
348 | |||
349 | /* No spare invalid entry, so create one */ | ||
350 | |||
351 | if (mmu_slb_size < 64) | ||
352 | max_slb_size = mmu_slb_size; | ||
353 | |||
354 | /* Overflowing -> purge */ | ||
355 | if ((get_paca()->kvm_slb_max) == max_slb_size) | ||
356 | kvmppc_mmu_flush_segments(vcpu); | ||
357 | |||
358 | r = get_paca()->kvm_slb_max; | ||
359 | get_paca()->kvm_slb_max++; | ||
360 | |||
361 | return r; | ||
362 | } | ||
363 | |||
364 | int kvmppc_mmu_map_segment(struct kvm_vcpu *vcpu, ulong eaddr) | ||
365 | { | ||
366 | u64 esid = eaddr >> SID_SHIFT; | ||
367 | u64 slb_esid = (eaddr & ESID_MASK) | SLB_ESID_V; | ||
368 | u64 slb_vsid = SLB_VSID_USER; | ||
369 | u64 gvsid; | ||
370 | int slb_index; | ||
371 | struct kvmppc_sid_map *map; | ||
372 | |||
373 | slb_index = kvmppc_mmu_next_segment(vcpu, eaddr & ESID_MASK); | ||
374 | |||
375 | if (vcpu->arch.mmu.esid_to_vsid(vcpu, esid, &gvsid)) { | ||
376 | /* Invalidate an entry */ | ||
377 | get_paca()->kvm_slb[slb_index].esid = 0; | ||
378 | return -ENOENT; | ||
379 | } | ||
380 | |||
381 | map = find_sid_vsid(vcpu, gvsid); | ||
382 | if (!map) | ||
383 | map = create_sid_map(vcpu, gvsid); | ||
384 | |||
385 | map->guest_esid = esid; | ||
386 | |||
387 | slb_vsid |= (map->host_vsid << 12); | ||
388 | slb_vsid &= ~SLB_VSID_KP; | ||
389 | slb_esid |= slb_index; | ||
390 | |||
391 | get_paca()->kvm_slb[slb_index].esid = slb_esid; | ||
392 | get_paca()->kvm_slb[slb_index].vsid = slb_vsid; | ||
393 | |||
394 | dprintk_slb("slbmte %#llx, %#llx\n", slb_vsid, slb_esid); | ||
395 | |||
396 | return 0; | ||
397 | } | ||
398 | |||
399 | void kvmppc_mmu_flush_segments(struct kvm_vcpu *vcpu) | ||
400 | { | ||
401 | get_paca()->kvm_slb_max = 1; | ||
402 | get_paca()->kvm_slb[0].esid = 0; | ||
403 | } | ||
404 | |||
405 | void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu) | ||
406 | { | ||
407 | kvmppc_mmu_pte_flush(vcpu, 0, 0); | ||
408 | } | ||
diff --git a/arch/powerpc/kvm/book3s_64_rmhandlers.S b/arch/powerpc/kvm/book3s_64_rmhandlers.S new file mode 100644 index 000000000000..fb7dd2e9ac88 --- /dev/null +++ b/arch/powerpc/kvm/book3s_64_rmhandlers.S | |||
@@ -0,0 +1,131 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License, version 2, as | ||
4 | * published by the Free Software Foundation. | ||
5 | * | ||
6 | * This program is distributed in the hope that it will be useful, | ||
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
9 | * GNU General Public License for more details. | ||
10 | * | ||
11 | * You should have received a copy of the GNU General Public License | ||
12 | * along with this program; if not, write to the Free Software | ||
13 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
14 | * | ||
15 | * Copyright SUSE Linux Products GmbH 2009 | ||
16 | * | ||
17 | * Authors: Alexander Graf <agraf@suse.de> | ||
18 | */ | ||
19 | |||
20 | #include <asm/ppc_asm.h> | ||
21 | #include <asm/kvm_asm.h> | ||
22 | #include <asm/reg.h> | ||
23 | #include <asm/page.h> | ||
24 | #include <asm/asm-offsets.h> | ||
25 | #include <asm/exception-64s.h> | ||
26 | |||
27 | /***************************************************************************** | ||
28 | * * | ||
29 | * Real Mode handlers that need to be in low physical memory * | ||
30 | * * | ||
31 | ****************************************************************************/ | ||
32 | |||
33 | |||
34 | .macro INTERRUPT_TRAMPOLINE intno | ||
35 | |||
36 | .global kvmppc_trampoline_\intno | ||
37 | kvmppc_trampoline_\intno: | ||
38 | |||
39 | mtspr SPRN_SPRG_SCRATCH0, r13 /* Save r13 */ | ||
40 | |||
41 | /* | ||
42 | * First thing to do is to find out if we're coming | ||
43 | * from a KVM guest or a Linux process. | ||
44 | * | ||
45 | * To distinguish, we check a magic byte in the PACA | ||
46 | */ | ||
47 | mfspr r13, SPRN_SPRG_PACA /* r13 = PACA */ | ||
48 | std r12, (PACA_EXMC + EX_R12)(r13) | ||
49 | mfcr r12 | ||
50 | stw r12, (PACA_EXMC + EX_CCR)(r13) | ||
51 | lbz r12, PACA_KVM_IN_GUEST(r13) | ||
52 | cmpwi r12, 0 | ||
53 | bne ..kvmppc_handler_hasmagic_\intno | ||
54 | /* No KVM guest? Then jump back to the Linux handler! */ | ||
55 | lwz r12, (PACA_EXMC + EX_CCR)(r13) | ||
56 | mtcr r12 | ||
57 | ld r12, (PACA_EXMC + EX_R12)(r13) | ||
58 | mfspr r13, SPRN_SPRG_SCRATCH0 /* r13 = original r13 */ | ||
59 | b kvmppc_resume_\intno /* Get back original handler */ | ||
60 | |||
61 | /* Now we know we're handling a KVM guest */ | ||
62 | ..kvmppc_handler_hasmagic_\intno: | ||
63 | /* Unset guest state */ | ||
64 | li r12, 0 | ||
65 | stb r12, PACA_KVM_IN_GUEST(r13) | ||
66 | |||
67 | std r1, (PACA_EXMC+EX_R9)(r13) | ||
68 | std r10, (PACA_EXMC+EX_R10)(r13) | ||
69 | std r11, (PACA_EXMC+EX_R11)(r13) | ||
70 | std r2, (PACA_EXMC+EX_R13)(r13) | ||
71 | |||
72 | mfsrr0 r10 | ||
73 | mfsrr1 r11 | ||
74 | |||
75 | /* Restore R1/R2 so we can handle faults */ | ||
76 | ld r1, PACAR1(r13) | ||
77 | ld r2, (PACA_EXMC+EX_SRR0)(r13) | ||
78 | |||
79 | /* Let's store which interrupt we're handling */ | ||
80 | li r12, \intno | ||
81 | |||
82 | /* Jump into the SLB exit code that goes to the highmem handler */ | ||
83 | b kvmppc_handler_trampoline_exit | ||
84 | |||
85 | .endm | ||
86 | |||
87 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_SYSTEM_RESET | ||
88 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_MACHINE_CHECK | ||
89 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_DATA_STORAGE | ||
90 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_DATA_SEGMENT | ||
91 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_INST_STORAGE | ||
92 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_INST_SEGMENT | ||
93 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_EXTERNAL | ||
94 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_ALIGNMENT | ||
95 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_PROGRAM | ||
96 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_FP_UNAVAIL | ||
97 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_DECREMENTER | ||
98 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_SYSCALL | ||
99 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_TRACE | ||
100 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_PERFMON | ||
101 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_ALTIVEC | ||
102 | INTERRUPT_TRAMPOLINE BOOK3S_INTERRUPT_VSX | ||
103 | |||
104 | /* | ||
105 | * This trampoline brings us back to a real mode handler | ||
106 | * | ||
107 | * Input Registers: | ||
108 | * | ||
109 | * R6 = SRR0 | ||
110 | * R7 = SRR1 | ||
111 | * LR = real-mode IP | ||
112 | * | ||
113 | */ | ||
114 | .global kvmppc_handler_lowmem_trampoline | ||
115 | kvmppc_handler_lowmem_trampoline: | ||
116 | |||
117 | mtsrr0 r6 | ||
118 | mtsrr1 r7 | ||
119 | blr | ||
120 | kvmppc_handler_lowmem_trampoline_end: | ||
121 | |||
122 | .global kvmppc_trampoline_lowmem | ||
123 | kvmppc_trampoline_lowmem: | ||
124 | .long kvmppc_handler_lowmem_trampoline - _stext | ||
125 | |||
126 | .global kvmppc_trampoline_enter | ||
127 | kvmppc_trampoline_enter: | ||
128 | .long kvmppc_handler_trampoline_enter - _stext | ||
129 | |||
130 | #include "book3s_64_slb.S" | ||
131 | |||
diff --git a/arch/powerpc/kvm/book3s_64_slb.S b/arch/powerpc/kvm/book3s_64_slb.S new file mode 100644 index 000000000000..ecd237a03fd0 --- /dev/null +++ b/arch/powerpc/kvm/book3s_64_slb.S | |||
@@ -0,0 +1,262 @@ | |||
1 | /* | ||
2 | * This program is free software; you can redistribute it and/or modify | ||
3 | * it under the terms of the GNU General Public License, version 2, as | ||
4 | * published by the Free Software Foundation. | ||
5 | * | ||
6 | * This program is distributed in the hope that it will be useful, | ||
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
9 | * GNU General Public License for more details. | ||
10 | * | ||
11 | * You should have received a copy of the GNU General Public License | ||
12 | * along with this program; if not, write to the Free Software | ||
13 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
14 | * | ||
15 | * Copyright SUSE Linux Products GmbH 2009 | ||
16 | * | ||
17 | * Authors: Alexander Graf <agraf@suse.de> | ||
18 | */ | ||
19 | |||
20 | #define SHADOW_SLB_ESID(num) (SLBSHADOW_SAVEAREA + (num * 0x10)) | ||
21 | #define SHADOW_SLB_VSID(num) (SLBSHADOW_SAVEAREA + (num * 0x10) + 0x8) | ||
22 | #define UNBOLT_SLB_ENTRY(num) \ | ||
23 | ld r9, SHADOW_SLB_ESID(num)(r12); \ | ||
24 | /* Invalid? Skip. */; \ | ||
25 | rldicl. r0, r9, 37, 63; \ | ||
26 | beq slb_entry_skip_ ## num; \ | ||
27 | xoris r9, r9, SLB_ESID_V@h; \ | ||
28 | std r9, SHADOW_SLB_ESID(num)(r12); \ | ||
29 | slb_entry_skip_ ## num: | ||
30 | |||
31 | #define REBOLT_SLB_ENTRY(num) \ | ||
32 | ld r10, SHADOW_SLB_ESID(num)(r11); \ | ||
33 | cmpdi r10, 0; \ | ||
34 | beq slb_exit_skip_1; \ | ||
35 | oris r10, r10, SLB_ESID_V@h; \ | ||
36 | ld r9, SHADOW_SLB_VSID(num)(r11); \ | ||
37 | slbmte r9, r10; \ | ||
38 | std r10, SHADOW_SLB_ESID(num)(r11); \ | ||
39 | slb_exit_skip_ ## num: | ||
40 | |||
41 | /****************************************************************************** | ||
42 | * * | ||
43 | * Entry code * | ||
44 | * * | ||
45 | *****************************************************************************/ | ||
46 | |||
47 | .global kvmppc_handler_trampoline_enter | ||
48 | kvmppc_handler_trampoline_enter: | ||
49 | |||
50 | /* Required state: | ||
51 | * | ||
52 | * MSR = ~IR|DR | ||
53 | * R13 = PACA | ||
54 | * R9 = guest IP | ||
55 | * R10 = guest MSR | ||
56 | * R11 = free | ||
57 | * R12 = free | ||
58 | * PACA[PACA_EXMC + EX_R9] = guest R9 | ||
59 | * PACA[PACA_EXMC + EX_R10] = guest R10 | ||
60 | * PACA[PACA_EXMC + EX_R11] = guest R11 | ||
61 | * PACA[PACA_EXMC + EX_R12] = guest R12 | ||
62 | * PACA[PACA_EXMC + EX_R13] = guest R13 | ||
63 | * PACA[PACA_EXMC + EX_CCR] = guest CR | ||
64 | * PACA[PACA_EXMC + EX_R3] = guest XER | ||
65 | */ | ||
66 | |||
67 | mtsrr0 r9 | ||
68 | mtsrr1 r10 | ||
69 | |||
70 | mtspr SPRN_SPRG_SCRATCH0, r0 | ||
71 | |||
72 | /* Remove LPAR shadow entries */ | ||
73 | |||
74 | #if SLB_NUM_BOLTED == 3 | ||
75 | |||
76 | ld r12, PACA_SLBSHADOWPTR(r13) | ||
77 | |||
78 | /* Save off the first entry so we can slbie it later */ | ||
79 | ld r10, SHADOW_SLB_ESID(0)(r12) | ||
80 | ld r11, SHADOW_SLB_VSID(0)(r12) | ||
81 | |||
82 | /* Remove bolted entries */ | ||
83 | UNBOLT_SLB_ENTRY(0) | ||
84 | UNBOLT_SLB_ENTRY(1) | ||
85 | UNBOLT_SLB_ENTRY(2) | ||
86 | |||
87 | #else | ||
88 | #error unknown number of bolted entries | ||
89 | #endif | ||
90 | |||
91 | /* Flush SLB */ | ||
92 | |||
93 | slbia | ||
94 | |||
95 | /* r0 = esid & ESID_MASK */ | ||
96 | rldicr r10, r10, 0, 35 | ||
97 | /* r0 |= CLASS_BIT(VSID) */ | ||
98 | rldic r12, r11, 56 - 36, 36 | ||
99 | or r10, r10, r12 | ||
100 | slbie r10 | ||
101 | |||
102 | isync | ||
103 | |||
104 | /* Fill SLB with our shadow */ | ||
105 | |||
106 | lbz r12, PACA_KVM_SLB_MAX(r13) | ||
107 | mulli r12, r12, 16 | ||
108 | addi r12, r12, PACA_KVM_SLB | ||
109 | add r12, r12, r13 | ||
110 | |||
111 | /* for (r11 = kvm_slb; r11 < kvm_slb + kvm_slb_size; r11+=slb_entry) */ | ||
112 | li r11, PACA_KVM_SLB | ||
113 | add r11, r11, r13 | ||
114 | |||
115 | slb_loop_enter: | ||
116 | |||
117 | ld r10, 0(r11) | ||
118 | |||
119 | rldicl. r0, r10, 37, 63 | ||
120 | beq slb_loop_enter_skip | ||
121 | |||
122 | ld r9, 8(r11) | ||
123 | slbmte r9, r10 | ||
124 | |||
125 | slb_loop_enter_skip: | ||
126 | addi r11, r11, 16 | ||
127 | cmpd cr0, r11, r12 | ||
128 | blt slb_loop_enter | ||
129 | |||
130 | slb_do_enter: | ||
131 | |||
132 | /* Enter guest */ | ||
133 | |||
134 | mfspr r0, SPRN_SPRG_SCRATCH0 | ||
135 | |||
136 | ld r9, (PACA_EXMC+EX_R9)(r13) | ||
137 | ld r10, (PACA_EXMC+EX_R10)(r13) | ||
138 | ld r12, (PACA_EXMC+EX_R12)(r13) | ||
139 | |||
140 | lwz r11, (PACA_EXMC+EX_CCR)(r13) | ||
141 | mtcr r11 | ||
142 | |||
143 | ld r11, (PACA_EXMC+EX_R3)(r13) | ||
144 | mtxer r11 | ||
145 | |||
146 | ld r11, (PACA_EXMC+EX_R11)(r13) | ||
147 | ld r13, (PACA_EXMC+EX_R13)(r13) | ||
148 | |||
149 | RFI | ||
150 | kvmppc_handler_trampoline_enter_end: | ||
151 | |||
152 | |||
153 | |||
154 | /****************************************************************************** | ||
155 | * * | ||
156 | * Exit code * | ||
157 | * * | ||
158 | *****************************************************************************/ | ||
159 | |||
160 | .global kvmppc_handler_trampoline_exit | ||
161 | kvmppc_handler_trampoline_exit: | ||
162 | |||
163 | /* Register usage at this point: | ||
164 | * | ||
165 | * SPRG_SCRATCH0 = guest R13 | ||
166 | * R01 = host R1 | ||
167 | * R02 = host R2 | ||
168 | * R10 = guest PC | ||
169 | * R11 = guest MSR | ||
170 | * R12 = exit handler id | ||
171 | * R13 = PACA | ||
172 | * PACA.exmc.CCR = guest CR | ||
173 | * PACA.exmc.R9 = guest R1 | ||
174 | * PACA.exmc.R10 = guest R10 | ||
175 | * PACA.exmc.R11 = guest R11 | ||
176 | * PACA.exmc.R12 = guest R12 | ||
177 | * PACA.exmc.R13 = guest R2 | ||
178 | * | ||
179 | */ | ||
180 | |||
181 | /* Save registers */ | ||
182 | |||
183 | std r0, (PACA_EXMC+EX_SRR0)(r13) | ||
184 | std r9, (PACA_EXMC+EX_R3)(r13) | ||
185 | std r10, (PACA_EXMC+EX_LR)(r13) | ||
186 | std r11, (PACA_EXMC+EX_DAR)(r13) | ||
187 | |||
188 | /* | ||
189 | * In order for us to easily get the last instruction, | ||
190 | * we got the #vmexit at, we exploit the fact that the | ||
191 | * virtual layout is still the same here, so we can just | ||
192 | * ld from the guest's PC address | ||
193 | */ | ||
194 | |||
195 | /* We only load the last instruction when it's safe */ | ||
196 | cmpwi r12, BOOK3S_INTERRUPT_DATA_STORAGE | ||
197 | beq ld_last_inst | ||
198 | cmpwi r12, BOOK3S_INTERRUPT_PROGRAM | ||
199 | beq ld_last_inst | ||
200 | |||
201 | b no_ld_last_inst | ||
202 | |||
203 | ld_last_inst: | ||
204 | /* Save off the guest instruction we're at */ | ||
205 | /* 1) enable paging for data */ | ||
206 | mfmsr r9 | ||
207 | ori r11, r9, MSR_DR /* Enable paging for data */ | ||
208 | mtmsr r11 | ||
209 | /* 2) fetch the instruction */ | ||
210 | lwz r0, 0(r10) | ||
211 | /* 3) disable paging again */ | ||
212 | mtmsr r9 | ||
213 | |||
214 | no_ld_last_inst: | ||
215 | |||
216 | /* Restore bolted entries from the shadow and fix it along the way */ | ||
217 | |||
218 | /* We don't store anything in entry 0, so we don't need to take care of it */ | ||
219 | slbia | ||
220 | isync | ||
221 | |||
222 | #if SLB_NUM_BOLTED == 3 | ||
223 | |||
224 | ld r11, PACA_SLBSHADOWPTR(r13) | ||
225 | |||
226 | REBOLT_SLB_ENTRY(0) | ||
227 | REBOLT_SLB_ENTRY(1) | ||
228 | REBOLT_SLB_ENTRY(2) | ||
229 | |||
230 | #else | ||
231 | #error unknown number of bolted entries | ||
232 | #endif | ||
233 | |||
234 | slb_do_exit: | ||
235 | |||
236 | /* Restore registers */ | ||
237 | |||
238 | ld r11, (PACA_EXMC+EX_DAR)(r13) | ||
239 | ld r10, (PACA_EXMC+EX_LR)(r13) | ||
240 | ld r9, (PACA_EXMC+EX_R3)(r13) | ||
241 | |||
242 | /* Save last inst */ | ||
243 | stw r0, (PACA_EXMC+EX_LR)(r13) | ||
244 | |||
245 | /* Save DAR and DSISR before going to paged mode */ | ||
246 | mfdar r0 | ||
247 | std r0, (PACA_EXMC+EX_DAR)(r13) | ||
248 | mfdsisr r0 | ||
249 | stw r0, (PACA_EXMC+EX_DSISR)(r13) | ||
250 | |||
251 | /* RFI into the highmem handler */ | ||
252 | mfmsr r0 | ||
253 | ori r0, r0, MSR_IR|MSR_DR|MSR_RI /* Enable paging */ | ||
254 | mtsrr1 r0 | ||
255 | ld r0, PACASAVEDMSR(r13) /* Highmem handler address */ | ||
256 | mtsrr0 r0 | ||
257 | |||
258 | mfspr r0, SPRN_SPRG_SCRATCH0 | ||
259 | |||
260 | RFI | ||
261 | kvmppc_handler_trampoline_exit_end: | ||
262 | |||
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c index e7bf4d029484..06f5a9ecc42c 100644 --- a/arch/powerpc/kvm/booke.c +++ b/arch/powerpc/kvm/booke.c | |||
@@ -520,6 +520,11 @@ int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu, | |||
520 | return kvmppc_core_vcpu_translate(vcpu, tr); | 520 | return kvmppc_core_vcpu_translate(vcpu, tr); |
521 | } | 521 | } |
522 | 522 | ||
523 | int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log) | ||
524 | { | ||
525 | return -ENOTSUPP; | ||
526 | } | ||
527 | |||
523 | int __init kvmppc_booke_init(void) | 528 | int __init kvmppc_booke_init(void) |
524 | { | 529 | { |
525 | unsigned long ivor[16]; | 530 | unsigned long ivor[16]; |
diff --git a/arch/powerpc/kvm/emulate.c b/arch/powerpc/kvm/emulate.c index 7737146af3fb..4a9ac6640fad 100644 --- a/arch/powerpc/kvm/emulate.c +++ b/arch/powerpc/kvm/emulate.c | |||
@@ -18,7 +18,7 @@ | |||
18 | */ | 18 | */ |
19 | 19 | ||
20 | #include <linux/jiffies.h> | 20 | #include <linux/jiffies.h> |
21 | #include <linux/timer.h> | 21 | #include <linux/hrtimer.h> |
22 | #include <linux/types.h> | 22 | #include <linux/types.h> |
23 | #include <linux/string.h> | 23 | #include <linux/string.h> |
24 | #include <linux/kvm_host.h> | 24 | #include <linux/kvm_host.h> |
@@ -32,6 +32,7 @@ | |||
32 | #include "trace.h" | 32 | #include "trace.h" |
33 | 33 | ||
34 | #define OP_TRAP 3 | 34 | #define OP_TRAP 3 |
35 | #define OP_TRAP_64 2 | ||
35 | 36 | ||
36 | #define OP_31_XOP_LWZX 23 | 37 | #define OP_31_XOP_LWZX 23 |
37 | #define OP_31_XOP_LBZX 87 | 38 | #define OP_31_XOP_LBZX 87 |
@@ -64,19 +65,45 @@ | |||
64 | #define OP_STH 44 | 65 | #define OP_STH 44 |
65 | #define OP_STHU 45 | 66 | #define OP_STHU 45 |
66 | 67 | ||
68 | #ifdef CONFIG_PPC64 | ||
69 | static int kvmppc_dec_enabled(struct kvm_vcpu *vcpu) | ||
70 | { | ||
71 | return 1; | ||
72 | } | ||
73 | #else | ||
74 | static int kvmppc_dec_enabled(struct kvm_vcpu *vcpu) | ||
75 | { | ||
76 | return vcpu->arch.tcr & TCR_DIE; | ||
77 | } | ||
78 | #endif | ||
79 | |||
67 | void kvmppc_emulate_dec(struct kvm_vcpu *vcpu) | 80 | void kvmppc_emulate_dec(struct kvm_vcpu *vcpu) |
68 | { | 81 | { |
69 | if (vcpu->arch.tcr & TCR_DIE) { | 82 | unsigned long dec_nsec; |
83 | |||
84 | pr_debug("mtDEC: %x\n", vcpu->arch.dec); | ||
85 | #ifdef CONFIG_PPC64 | ||
86 | /* POWER4+ triggers a dec interrupt if the value is < 0 */ | ||
87 | if (vcpu->arch.dec & 0x80000000) { | ||
88 | hrtimer_try_to_cancel(&vcpu->arch.dec_timer); | ||
89 | kvmppc_core_queue_dec(vcpu); | ||
90 | return; | ||
91 | } | ||
92 | #endif | ||
93 | if (kvmppc_dec_enabled(vcpu)) { | ||
70 | /* The decrementer ticks at the same rate as the timebase, so | 94 | /* The decrementer ticks at the same rate as the timebase, so |
71 | * that's how we convert the guest DEC value to the number of | 95 | * that's how we convert the guest DEC value to the number of |
72 | * host ticks. */ | 96 | * host ticks. */ |
73 | unsigned long nr_jiffies; | ||
74 | 97 | ||
75 | nr_jiffies = vcpu->arch.dec / tb_ticks_per_jiffy; | 98 | hrtimer_try_to_cancel(&vcpu->arch.dec_timer); |
76 | mod_timer(&vcpu->arch.dec_timer, | 99 | dec_nsec = vcpu->arch.dec; |
77 | get_jiffies_64() + nr_jiffies); | 100 | dec_nsec *= 1000; |
101 | dec_nsec /= tb_ticks_per_usec; | ||
102 | hrtimer_start(&vcpu->arch.dec_timer, ktime_set(0, dec_nsec), | ||
103 | HRTIMER_MODE_REL); | ||
104 | vcpu->arch.dec_jiffies = get_tb(); | ||
78 | } else { | 105 | } else { |
79 | del_timer(&vcpu->arch.dec_timer); | 106 | hrtimer_try_to_cancel(&vcpu->arch.dec_timer); |
80 | } | 107 | } |
81 | } | 108 | } |
82 | 109 | ||
@@ -111,9 +138,15 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu) | |||
111 | /* this default type might be overwritten by subcategories */ | 138 | /* this default type might be overwritten by subcategories */ |
112 | kvmppc_set_exit_type(vcpu, EMULATED_INST_EXITS); | 139 | kvmppc_set_exit_type(vcpu, EMULATED_INST_EXITS); |
113 | 140 | ||
141 | pr_debug(KERN_INFO "Emulating opcode %d / %d\n", get_op(inst), get_xop(inst)); | ||
142 | |||
114 | switch (get_op(inst)) { | 143 | switch (get_op(inst)) { |
115 | case OP_TRAP: | 144 | case OP_TRAP: |
145 | #ifdef CONFIG_PPC64 | ||
146 | case OP_TRAP_64: | ||
147 | #else | ||
116 | vcpu->arch.esr |= ESR_PTR; | 148 | vcpu->arch.esr |= ESR_PTR; |
149 | #endif | ||
117 | kvmppc_core_queue_program(vcpu); | 150 | kvmppc_core_queue_program(vcpu); |
118 | advance = 0; | 151 | advance = 0; |
119 | break; | 152 | break; |
@@ -188,17 +221,19 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu) | |||
188 | case SPRN_SRR1: | 221 | case SPRN_SRR1: |
189 | vcpu->arch.gpr[rt] = vcpu->arch.srr1; break; | 222 | vcpu->arch.gpr[rt] = vcpu->arch.srr1; break; |
190 | case SPRN_PVR: | 223 | case SPRN_PVR: |
191 | vcpu->arch.gpr[rt] = mfspr(SPRN_PVR); break; | 224 | vcpu->arch.gpr[rt] = vcpu->arch.pvr; break; |
192 | case SPRN_PIR: | 225 | case SPRN_PIR: |
193 | vcpu->arch.gpr[rt] = mfspr(SPRN_PIR); break; | 226 | vcpu->arch.gpr[rt] = vcpu->vcpu_id; break; |
227 | case SPRN_MSSSR0: | ||
228 | vcpu->arch.gpr[rt] = 0; break; | ||
194 | 229 | ||
195 | /* Note: mftb and TBRL/TBWL are user-accessible, so | 230 | /* Note: mftb and TBRL/TBWL are user-accessible, so |
196 | * the guest can always access the real TB anyways. | 231 | * the guest can always access the real TB anyways. |
197 | * In fact, we probably will never see these traps. */ | 232 | * In fact, we probably will never see these traps. */ |
198 | case SPRN_TBWL: | 233 | case SPRN_TBWL: |
199 | vcpu->arch.gpr[rt] = mftbl(); break; | 234 | vcpu->arch.gpr[rt] = get_tb() >> 32; break; |
200 | case SPRN_TBWU: | 235 | case SPRN_TBWU: |
201 | vcpu->arch.gpr[rt] = mftbu(); break; | 236 | vcpu->arch.gpr[rt] = get_tb(); break; |
202 | 237 | ||
203 | case SPRN_SPRG0: | 238 | case SPRN_SPRG0: |
204 | vcpu->arch.gpr[rt] = vcpu->arch.sprg0; break; | 239 | vcpu->arch.gpr[rt] = vcpu->arch.sprg0; break; |
@@ -211,6 +246,13 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu) | |||
211 | /* Note: SPRG4-7 are user-readable, so we don't get | 246 | /* Note: SPRG4-7 are user-readable, so we don't get |
212 | * a trap. */ | 247 | * a trap. */ |
213 | 248 | ||
249 | case SPRN_DEC: | ||
250 | { | ||
251 | u64 jd = get_tb() - vcpu->arch.dec_jiffies; | ||
252 | vcpu->arch.gpr[rt] = vcpu->arch.dec - jd; | ||
253 | pr_debug(KERN_INFO "mfDEC: %x - %llx = %lx\n", vcpu->arch.dec, jd, vcpu->arch.gpr[rt]); | ||
254 | break; | ||
255 | } | ||
214 | default: | 256 | default: |
215 | emulated = kvmppc_core_emulate_mfspr(vcpu, sprn, rt); | 257 | emulated = kvmppc_core_emulate_mfspr(vcpu, sprn, rt); |
216 | if (emulated == EMULATE_FAIL) { | 258 | if (emulated == EMULATE_FAIL) { |
@@ -260,6 +302,8 @@ int kvmppc_emulate_instruction(struct kvm_run *run, struct kvm_vcpu *vcpu) | |||
260 | case SPRN_TBWL: break; | 302 | case SPRN_TBWL: break; |
261 | case SPRN_TBWU: break; | 303 | case SPRN_TBWU: break; |
262 | 304 | ||
305 | case SPRN_MSSSR0: break; | ||
306 | |||
263 | case SPRN_DEC: | 307 | case SPRN_DEC: |
264 | vcpu->arch.dec = vcpu->arch.gpr[rs]; | 308 | vcpu->arch.dec = vcpu->arch.gpr[rs]; |
265 | kvmppc_emulate_dec(vcpu); | 309 | kvmppc_emulate_dec(vcpu); |
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index 5902bbc2411e..f06cf93b178e 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/kvm_host.h> | 23 | #include <linux/kvm_host.h> |
24 | #include <linux/module.h> | 24 | #include <linux/module.h> |
25 | #include <linux/vmalloc.h> | 25 | #include <linux/vmalloc.h> |
26 | #include <linux/hrtimer.h> | ||
26 | #include <linux/fs.h> | 27 | #include <linux/fs.h> |
27 | #include <asm/cputable.h> | 28 | #include <asm/cputable.h> |
28 | #include <asm/uaccess.h> | 29 | #include <asm/uaccess.h> |
@@ -144,6 +145,9 @@ int kvm_dev_ioctl_check_extension(long ext) | |||
144 | int r; | 145 | int r; |
145 | 146 | ||
146 | switch (ext) { | 147 | switch (ext) { |
148 | case KVM_CAP_PPC_SEGSTATE: | ||
149 | r = 1; | ||
150 | break; | ||
147 | case KVM_CAP_COALESCED_MMIO: | 151 | case KVM_CAP_COALESCED_MMIO: |
148 | r = KVM_COALESCED_MMIO_PAGE_OFFSET; | 152 | r = KVM_COALESCED_MMIO_PAGE_OFFSET; |
149 | break; | 153 | break; |
@@ -209,10 +213,25 @@ static void kvmppc_decrementer_func(unsigned long data) | |||
209 | } | 213 | } |
210 | } | 214 | } |
211 | 215 | ||
216 | /* | ||
217 | * low level hrtimer wake routine. Because this runs in hardirq context | ||
218 | * we schedule a tasklet to do the real work. | ||
219 | */ | ||
220 | enum hrtimer_restart kvmppc_decrementer_wakeup(struct hrtimer *timer) | ||
221 | { | ||
222 | struct kvm_vcpu *vcpu; | ||
223 | |||
224 | vcpu = container_of(timer, struct kvm_vcpu, arch.dec_timer); | ||
225 | tasklet_schedule(&vcpu->arch.tasklet); | ||
226 | |||
227 | return HRTIMER_NORESTART; | ||
228 | } | ||
229 | |||
212 | int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) | 230 | int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) |
213 | { | 231 | { |
214 | setup_timer(&vcpu->arch.dec_timer, kvmppc_decrementer_func, | 232 | hrtimer_init(&vcpu->arch.dec_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS); |
215 | (unsigned long)vcpu); | 233 | tasklet_init(&vcpu->arch.tasklet, kvmppc_decrementer_func, (ulong)vcpu); |
234 | vcpu->arch.dec_timer.function = kvmppc_decrementer_wakeup; | ||
216 | 235 | ||
217 | return 0; | 236 | return 0; |
218 | } | 237 | } |
@@ -410,11 +429,6 @@ out: | |||
410 | return r; | 429 | return r; |
411 | } | 430 | } |
412 | 431 | ||
413 | int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log) | ||
414 | { | ||
415 | return -ENOTSUPP; | ||
416 | } | ||
417 | |||
418 | long kvm_arch_vm_ioctl(struct file *filp, | 432 | long kvm_arch_vm_ioctl(struct file *filp, |
419 | unsigned int ioctl, unsigned long arg) | 433 | unsigned int ioctl, unsigned long arg) |
420 | { | 434 | { |
diff --git a/arch/powerpc/kvm/timing.c b/arch/powerpc/kvm/timing.c index 2aa371e30079..70378551c0cc 100644 --- a/arch/powerpc/kvm/timing.c +++ b/arch/powerpc/kvm/timing.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/seq_file.h> | 23 | #include <linux/seq_file.h> |
24 | #include <linux/debugfs.h> | 24 | #include <linux/debugfs.h> |
25 | #include <linux/uaccess.h> | 25 | #include <linux/uaccess.h> |
26 | #include <linux/module.h> | ||
26 | 27 | ||
27 | #include <asm/time.h> | 28 | #include <asm/time.h> |
28 | #include <asm-generic/div64.h> | 29 | #include <asm-generic/div64.h> |
diff --git a/arch/powerpc/kvm/trace.h b/arch/powerpc/kvm/trace.h index 67f219de0455..a8e840018052 100644 --- a/arch/powerpc/kvm/trace.h +++ b/arch/powerpc/kvm/trace.h | |||
@@ -12,8 +12,8 @@ | |||
12 | * Tracepoint for guest mode entry. | 12 | * Tracepoint for guest mode entry. |
13 | */ | 13 | */ |
14 | TRACE_EVENT(kvm_ppc_instr, | 14 | TRACE_EVENT(kvm_ppc_instr, |
15 | TP_PROTO(unsigned int inst, unsigned long pc, unsigned int emulate), | 15 | TP_PROTO(unsigned int inst, unsigned long _pc, unsigned int emulate), |
16 | TP_ARGS(inst, pc, emulate), | 16 | TP_ARGS(inst, _pc, emulate), |
17 | 17 | ||
18 | TP_STRUCT__entry( | 18 | TP_STRUCT__entry( |
19 | __field( unsigned int, inst ) | 19 | __field( unsigned int, inst ) |
@@ -23,7 +23,7 @@ TRACE_EVENT(kvm_ppc_instr, | |||
23 | 23 | ||
24 | TP_fast_assign( | 24 | TP_fast_assign( |
25 | __entry->inst = inst; | 25 | __entry->inst = inst; |
26 | __entry->pc = pc; | 26 | __entry->pc = _pc; |
27 | __entry->emulate = emulate; | 27 | __entry->emulate = emulate; |
28 | ), | 28 | ), |
29 | 29 | ||
diff --git a/arch/powerpc/lib/copy_32.S b/arch/powerpc/lib/copy_32.S index c657de59abca..74a7f4130b4c 100644 --- a/arch/powerpc/lib/copy_32.S +++ b/arch/powerpc/lib/copy_32.S | |||
@@ -98,20 +98,7 @@ _GLOBAL(cacheable_memzero) | |||
98 | bdnz 4b | 98 | bdnz 4b |
99 | 3: mtctr r9 | 99 | 3: mtctr r9 |
100 | li r7,4 | 100 | li r7,4 |
101 | #if !defined(CONFIG_8xx) | ||
102 | 10: dcbz r7,r6 | 101 | 10: dcbz r7,r6 |
103 | #else | ||
104 | 10: stw r4, 4(r6) | ||
105 | stw r4, 8(r6) | ||
106 | stw r4, 12(r6) | ||
107 | stw r4, 16(r6) | ||
108 | #if CACHE_LINE_SIZE >= 32 | ||
109 | stw r4, 20(r6) | ||
110 | stw r4, 24(r6) | ||
111 | stw r4, 28(r6) | ||
112 | stw r4, 32(r6) | ||
113 | #endif /* CACHE_LINE_SIZE */ | ||
114 | #endif | ||
115 | addi r6,r6,CACHELINE_BYTES | 102 | addi r6,r6,CACHELINE_BYTES |
116 | bdnz 10b | 103 | bdnz 10b |
117 | clrlwi r5,r8,32-LG_CACHELINE_BYTES | 104 | clrlwi r5,r8,32-LG_CACHELINE_BYTES |
@@ -200,9 +187,7 @@ _GLOBAL(cacheable_memcpy) | |||
200 | mtctr r0 | 187 | mtctr r0 |
201 | beq 63f | 188 | beq 63f |
202 | 53: | 189 | 53: |
203 | #if !defined(CONFIG_8xx) | ||
204 | dcbz r11,r6 | 190 | dcbz r11,r6 |
205 | #endif | ||
206 | COPY_16_BYTES | 191 | COPY_16_BYTES |
207 | #if L1_CACHE_BYTES >= 32 | 192 | #if L1_CACHE_BYTES >= 32 |
208 | COPY_16_BYTES | 193 | COPY_16_BYTES |
@@ -356,14 +341,6 @@ _GLOBAL(__copy_tofrom_user) | |||
356 | li r11,4 | 341 | li r11,4 |
357 | beq 63f | 342 | beq 63f |
358 | 343 | ||
359 | #ifdef CONFIG_8xx | ||
360 | /* Don't use prefetch on 8xx */ | ||
361 | mtctr r0 | ||
362 | li r0,0 | ||
363 | 53: COPY_16_BYTES_WITHEX(0) | ||
364 | bdnz 53b | ||
365 | |||
366 | #else /* not CONFIG_8xx */ | ||
367 | /* Here we decide how far ahead to prefetch the source */ | 344 | /* Here we decide how far ahead to prefetch the source */ |
368 | li r3,4 | 345 | li r3,4 |
369 | cmpwi r0,1 | 346 | cmpwi r0,1 |
@@ -416,7 +393,6 @@ _GLOBAL(__copy_tofrom_user) | |||
416 | li r3,4 | 393 | li r3,4 |
417 | li r7,0 | 394 | li r7,0 |
418 | bne 114b | 395 | bne 114b |
419 | #endif /* CONFIG_8xx */ | ||
420 | 396 | ||
421 | 63: srwi. r0,r5,2 | 397 | 63: srwi. r0,r5,2 |
422 | mtctr r0 | 398 | mtctr r0 |
diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile index 6fb8fc8d2fea..ce68708bbad5 100644 --- a/arch/powerpc/mm/Makefile +++ b/arch/powerpc/mm/Makefile | |||
@@ -28,7 +28,10 @@ obj-$(CONFIG_44x) += 44x_mmu.o | |||
28 | obj-$(CONFIG_FSL_BOOKE) += fsl_booke_mmu.o | 28 | obj-$(CONFIG_FSL_BOOKE) += fsl_booke_mmu.o |
29 | obj-$(CONFIG_NEED_MULTIPLE_NODES) += numa.o | 29 | obj-$(CONFIG_NEED_MULTIPLE_NODES) += numa.o |
30 | obj-$(CONFIG_PPC_MM_SLICES) += slice.o | 30 | obj-$(CONFIG_PPC_MM_SLICES) += slice.o |
31 | obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o | 31 | ifeq ($(CONFIG_HUGETLB_PAGE),y) |
32 | obj-y += hugetlbpage.o | ||
33 | obj-$(CONFIG_PPC_STD_MMU_64) += hugetlbpage-hash64.o | ||
34 | endif | ||
32 | obj-$(CONFIG_PPC_SUBPAGE_PROT) += subpage-prot.o | 35 | obj-$(CONFIG_PPC_SUBPAGE_PROT) += subpage-prot.o |
33 | obj-$(CONFIG_NOT_COHERENT_CACHE) += dma-noncoherent.o | 36 | obj-$(CONFIG_NOT_COHERENT_CACHE) += dma-noncoherent.o |
34 | obj-$(CONFIG_HIGHMEM) += highmem.o | 37 | obj-$(CONFIG_HIGHMEM) += highmem.o |
diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c index e7dae82c1285..26fb6b990b0a 100644 --- a/arch/powerpc/mm/fault.c +++ b/arch/powerpc/mm/fault.c | |||
@@ -40,7 +40,7 @@ | |||
40 | #include <asm/uaccess.h> | 40 | #include <asm/uaccess.h> |
41 | #include <asm/tlbflush.h> | 41 | #include <asm/tlbflush.h> |
42 | #include <asm/siginfo.h> | 42 | #include <asm/siginfo.h> |
43 | 43 | #include <mm/mmu_decl.h> | |
44 | 44 | ||
45 | #ifdef CONFIG_KPROBES | 45 | #ifdef CONFIG_KPROBES |
46 | static inline int notify_page_fault(struct pt_regs *regs) | 46 | static inline int notify_page_fault(struct pt_regs *regs) |
@@ -246,6 +246,12 @@ good_area: | |||
246 | goto bad_area; | 246 | goto bad_area; |
247 | #endif /* CONFIG_6xx */ | 247 | #endif /* CONFIG_6xx */ |
248 | #if defined(CONFIG_8xx) | 248 | #if defined(CONFIG_8xx) |
249 | /* 8xx sometimes need to load a invalid/non-present TLBs. | ||
250 | * These must be invalidated separately as linux mm don't. | ||
251 | */ | ||
252 | if (error_code & 0x40000000) /* no translation? */ | ||
253 | _tlbil_va(address, 0, 0, 0); | ||
254 | |||
249 | /* The MPC8xx seems to always set 0x80000000, which is | 255 | /* The MPC8xx seems to always set 0x80000000, which is |
250 | * "undefined". Of those that can be set, this is the only | 256 | * "undefined". Of those that can be set, this is the only |
251 | * one which seems bad. | 257 | * one which seems bad. |
diff --git a/arch/powerpc/mm/fsl_booke_mmu.c b/arch/powerpc/mm/fsl_booke_mmu.c index dc93e95b256e..fcfcb6e976c7 100644 --- a/arch/powerpc/mm/fsl_booke_mmu.c +++ b/arch/powerpc/mm/fsl_booke_mmu.c | |||
@@ -54,26 +54,35 @@ | |||
54 | 54 | ||
55 | #include "mmu_decl.h" | 55 | #include "mmu_decl.h" |
56 | 56 | ||
57 | extern void loadcam_entry(unsigned int index); | ||
58 | unsigned int tlbcam_index; | 57 | unsigned int tlbcam_index; |
59 | static unsigned long cam[CONFIG_LOWMEM_CAM_NUM]; | ||
60 | 58 | ||
61 | #define NUM_TLBCAMS (16) | 59 | #define NUM_TLBCAMS (64) |
62 | 60 | ||
63 | #if defined(CONFIG_LOWMEM_CAM_NUM_BOOL) && (CONFIG_LOWMEM_CAM_NUM >= NUM_TLBCAMS) | 61 | #if defined(CONFIG_LOWMEM_CAM_NUM_BOOL) && (CONFIG_LOWMEM_CAM_NUM >= NUM_TLBCAMS) |
64 | #error "LOWMEM_CAM_NUM must be less than NUM_TLBCAMS" | 62 | #error "LOWMEM_CAM_NUM must be less than NUM_TLBCAMS" |
65 | #endif | 63 | #endif |
66 | 64 | ||
67 | struct tlbcam TLBCAM[NUM_TLBCAMS]; | 65 | struct tlbcam { |
66 | u32 MAS0; | ||
67 | u32 MAS1; | ||
68 | unsigned long MAS2; | ||
69 | u32 MAS3; | ||
70 | u32 MAS7; | ||
71 | } TLBCAM[NUM_TLBCAMS]; | ||
68 | 72 | ||
69 | struct tlbcamrange { | 73 | struct tlbcamrange { |
70 | unsigned long start; | 74 | unsigned long start; |
71 | unsigned long limit; | 75 | unsigned long limit; |
72 | phys_addr_t phys; | 76 | phys_addr_t phys; |
73 | } tlbcam_addrs[NUM_TLBCAMS]; | 77 | } tlbcam_addrs[NUM_TLBCAMS]; |
74 | 78 | ||
75 | extern unsigned int tlbcam_index; | 79 | extern unsigned int tlbcam_index; |
76 | 80 | ||
81 | unsigned long tlbcam_sz(int idx) | ||
82 | { | ||
83 | return tlbcam_addrs[idx].limit - tlbcam_addrs[idx].start + 1; | ||
84 | } | ||
85 | |||
77 | /* | 86 | /* |
78 | * Return PA for this VA if it is mapped by a CAM, or 0 | 87 | * Return PA for this VA if it is mapped by a CAM, or 0 |
79 | */ | 88 | */ |
@@ -94,23 +103,36 @@ unsigned long p_mapped_by_tlbcam(phys_addr_t pa) | |||
94 | int b; | 103 | int b; |
95 | for (b = 0; b < tlbcam_index; ++b) | 104 | for (b = 0; b < tlbcam_index; ++b) |
96 | if (pa >= tlbcam_addrs[b].phys | 105 | if (pa >= tlbcam_addrs[b].phys |
97 | && pa < (tlbcam_addrs[b].limit-tlbcam_addrs[b].start) | 106 | && pa < (tlbcam_addrs[b].limit-tlbcam_addrs[b].start) |
98 | +tlbcam_addrs[b].phys) | 107 | +tlbcam_addrs[b].phys) |
99 | return tlbcam_addrs[b].start+(pa-tlbcam_addrs[b].phys); | 108 | return tlbcam_addrs[b].start+(pa-tlbcam_addrs[b].phys); |
100 | return 0; | 109 | return 0; |
101 | } | 110 | } |
102 | 111 | ||
112 | void loadcam_entry(int idx) | ||
113 | { | ||
114 | mtspr(SPRN_MAS0, TLBCAM[idx].MAS0); | ||
115 | mtspr(SPRN_MAS1, TLBCAM[idx].MAS1); | ||
116 | mtspr(SPRN_MAS2, TLBCAM[idx].MAS2); | ||
117 | mtspr(SPRN_MAS3, TLBCAM[idx].MAS3); | ||
118 | |||
119 | if (cur_cpu_spec->cpu_features & MMU_FTR_BIG_PHYS) | ||
120 | mtspr(SPRN_MAS7, TLBCAM[idx].MAS7); | ||
121 | |||
122 | asm volatile("isync;tlbwe;isync" : : : "memory"); | ||
123 | } | ||
124 | |||
103 | /* | 125 | /* |
104 | * Set up one of the I/D BAT (block address translation) register pairs. | 126 | * Set up one of the I/D BAT (block address translation) register pairs. |
105 | * The parameters are not checked; in particular size must be a power | 127 | * The parameters are not checked; in particular size must be a power |
106 | * of 4 between 4k and 256M. | 128 | * of 4 between 4k and 256M. |
107 | */ | 129 | */ |
108 | void settlbcam(int index, unsigned long virt, phys_addr_t phys, | 130 | static void settlbcam(int index, unsigned long virt, phys_addr_t phys, |
109 | unsigned int size, int flags, unsigned int pid) | 131 | unsigned long size, unsigned long flags, unsigned int pid) |
110 | { | 132 | { |
111 | unsigned int tsize, lz; | 133 | unsigned int tsize, lz; |
112 | 134 | ||
113 | asm ("cntlzw %0,%1" : "=r" (lz) : "r" (size)); | 135 | asm (PPC_CNTLZL "%0,%1" : "=r" (lz) : "r" (size)); |
114 | tsize = 21 - lz; | 136 | tsize = 21 - lz; |
115 | 137 | ||
116 | #ifdef CONFIG_SMP | 138 | #ifdef CONFIG_SMP |
@@ -128,8 +150,10 @@ void settlbcam(int index, unsigned long virt, phys_addr_t phys, | |||
128 | TLBCAM[index].MAS2 |= (flags & _PAGE_GUARDED) ? MAS2_G : 0; | 150 | TLBCAM[index].MAS2 |= (flags & _PAGE_GUARDED) ? MAS2_G : 0; |
129 | TLBCAM[index].MAS2 |= (flags & _PAGE_ENDIAN) ? MAS2_E : 0; | 151 | TLBCAM[index].MAS2 |= (flags & _PAGE_ENDIAN) ? MAS2_E : 0; |
130 | 152 | ||
131 | TLBCAM[index].MAS3 = (phys & PAGE_MASK) | MAS3_SX | MAS3_SR; | 153 | TLBCAM[index].MAS3 = (phys & MAS3_RPN) | MAS3_SX | MAS3_SR; |
132 | TLBCAM[index].MAS3 |= ((flags & _PAGE_RW) ? MAS3_SW : 0); | 154 | TLBCAM[index].MAS3 |= ((flags & _PAGE_RW) ? MAS3_SW : 0); |
155 | if (cur_cpu_spec->cpu_features & MMU_FTR_BIG_PHYS) | ||
156 | TLBCAM[index].MAS7 = (u64)phys >> 32; | ||
133 | 157 | ||
134 | #ifndef CONFIG_KGDB /* want user access for breakpoints */ | 158 | #ifndef CONFIG_KGDB /* want user access for breakpoints */ |
135 | if (flags & _PAGE_USER) { | 159 | if (flags & _PAGE_USER) { |
@@ -148,27 +172,44 @@ void settlbcam(int index, unsigned long virt, phys_addr_t phys, | |||
148 | loadcam_entry(index); | 172 | loadcam_entry(index); |
149 | } | 173 | } |
150 | 174 | ||
151 | void invalidate_tlbcam_entry(int index) | 175 | unsigned long map_mem_in_cams(unsigned long ram, int max_cam_idx) |
152 | { | ||
153 | TLBCAM[index].MAS0 = MAS0_TLBSEL(1) | MAS0_ESEL(index); | ||
154 | TLBCAM[index].MAS1 = ~MAS1_VALID; | ||
155 | |||
156 | loadcam_entry(index); | ||
157 | } | ||
158 | |||
159 | unsigned long __init mmu_mapin_ram(void) | ||
160 | { | 176 | { |
177 | int i; | ||
161 | unsigned long virt = PAGE_OFFSET; | 178 | unsigned long virt = PAGE_OFFSET; |
162 | phys_addr_t phys = memstart_addr; | 179 | phys_addr_t phys = memstart_addr; |
180 | unsigned long amount_mapped = 0; | ||
181 | unsigned long max_cam = (mfspr(SPRN_TLB1CFG) >> 16) & 0xf; | ||
182 | |||
183 | /* Convert (4^max) kB to (2^max) bytes */ | ||
184 | max_cam = max_cam * 2 + 10; | ||
163 | 185 | ||
164 | while (tlbcam_index < ARRAY_SIZE(cam) && cam[tlbcam_index]) { | 186 | /* Calculate CAM values */ |
165 | settlbcam(tlbcam_index, virt, phys, cam[tlbcam_index], PAGE_KERNEL_X, 0); | 187 | for (i = 0; ram && i < max_cam_idx; i++) { |
166 | virt += cam[tlbcam_index]; | 188 | unsigned int camsize = __ilog2(ram) & ~1U; |
167 | phys += cam[tlbcam_index]; | 189 | unsigned int align = __ffs(virt | phys) & ~1U; |
168 | tlbcam_index++; | 190 | unsigned long cam_sz; |
191 | |||
192 | if (camsize > align) | ||
193 | camsize = align; | ||
194 | if (camsize > max_cam) | ||
195 | camsize = max_cam; | ||
196 | |||
197 | cam_sz = 1UL << camsize; | ||
198 | settlbcam(i, virt, phys, cam_sz, PAGE_KERNEL_X, 0); | ||
199 | |||
200 | ram -= cam_sz; | ||
201 | amount_mapped += cam_sz; | ||
202 | virt += cam_sz; | ||
203 | phys += cam_sz; | ||
169 | } | 204 | } |
205 | tlbcam_index = i; | ||
206 | |||
207 | return amount_mapped; | ||
208 | } | ||
170 | 209 | ||
171 | return virt - PAGE_OFFSET; | 210 | unsigned long __init mmu_mapin_ram(void) |
211 | { | ||
212 | return tlbcam_addrs[tlbcam_index - 1].limit - PAGE_OFFSET + 1; | ||
172 | } | 213 | } |
173 | 214 | ||
174 | /* | 215 | /* |
@@ -179,46 +220,21 @@ void __init MMU_init_hw(void) | |||
179 | flush_instruction_cache(); | 220 | flush_instruction_cache(); |
180 | } | 221 | } |
181 | 222 | ||
182 | void __init | 223 | void __init adjust_total_lowmem(void) |
183 | adjust_total_lowmem(void) | ||
184 | { | 224 | { |
185 | phys_addr_t ram; | 225 | unsigned long ram; |
186 | unsigned int max_cam = (mfspr(SPRN_TLB1CFG) >> 16) & 0xff; | ||
187 | char buf[ARRAY_SIZE(cam) * 5 + 1], *p = buf; | ||
188 | int i; | 226 | int i; |
189 | unsigned long virt = PAGE_OFFSET & 0xffffffffUL; | ||
190 | unsigned long phys = memstart_addr & 0xffffffffUL; | ||
191 | |||
192 | /* Convert (4^max) kB to (2^max) bytes */ | ||
193 | max_cam = max_cam * 2 + 10; | ||
194 | 227 | ||
195 | /* adjust lowmem size to __max_low_memory */ | 228 | /* adjust lowmem size to __max_low_memory */ |
196 | ram = min((phys_addr_t)__max_low_memory, (phys_addr_t)total_lowmem); | 229 | ram = min((phys_addr_t)__max_low_memory, (phys_addr_t)total_lowmem); |
197 | 230 | ||
198 | /* Calculate CAM values */ | 231 | __max_low_memory = map_mem_in_cams(ram, CONFIG_LOWMEM_CAM_NUM); |
199 | __max_low_memory = 0; | ||
200 | for (i = 0; ram && i < ARRAY_SIZE(cam); i++) { | ||
201 | unsigned int camsize = __ilog2(ram) & ~1U; | ||
202 | unsigned int align = __ffs(virt | phys) & ~1U; | ||
203 | 232 | ||
204 | if (camsize > align) | 233 | pr_info("Memory CAM mapping: "); |
205 | camsize = align; | 234 | for (i = 0; i < tlbcam_index - 1; i++) |
206 | if (camsize > max_cam) | 235 | pr_cont("%lu/", tlbcam_sz(i) >> 20); |
207 | camsize = max_cam; | 236 | pr_cont("%lu Mb, residual: %dMb\n", tlbcam_sz(tlbcam_index - 1) >> 20, |
208 | |||
209 | cam[i] = 1UL << camsize; | ||
210 | ram -= cam[i]; | ||
211 | __max_low_memory += cam[i]; | ||
212 | virt += cam[i]; | ||
213 | phys += cam[i]; | ||
214 | |||
215 | p += sprintf(p, "%lu/", cam[i] >> 20); | ||
216 | } | ||
217 | for (; i < ARRAY_SIZE(cam); i++) | ||
218 | p += sprintf(p, "0/"); | ||
219 | p[-1] = '\0'; | ||
220 | |||
221 | pr_info("Memory CAM mapping: %s Mb, residual: %dMb\n", buf, | ||
222 | (unsigned int)((total_lowmem - __max_low_memory) >> 20)); | 237 | (unsigned int)((total_lowmem - __max_low_memory) >> 20)); |
238 | |||
223 | __initial_memory_limit_addr = memstart_addr + __max_low_memory; | 239 | __initial_memory_limit_addr = memstart_addr + __max_low_memory; |
224 | } | 240 | } |
diff --git a/arch/powerpc/mm/gup.c b/arch/powerpc/mm/gup.c index bc122a120bf0..d7efdbf640c7 100644 --- a/arch/powerpc/mm/gup.c +++ b/arch/powerpc/mm/gup.c | |||
@@ -55,57 +55,6 @@ static noinline int gup_pte_range(pmd_t pmd, unsigned long addr, | |||
55 | return 1; | 55 | return 1; |
56 | } | 56 | } |
57 | 57 | ||
58 | #ifdef CONFIG_HUGETLB_PAGE | ||
59 | static noinline int gup_huge_pte(pte_t *ptep, struct hstate *hstate, | ||
60 | unsigned long *addr, unsigned long end, | ||
61 | int write, struct page **pages, int *nr) | ||
62 | { | ||
63 | unsigned long mask; | ||
64 | unsigned long pte_end; | ||
65 | struct page *head, *page; | ||
66 | pte_t pte; | ||
67 | int refs; | ||
68 | |||
69 | pte_end = (*addr + huge_page_size(hstate)) & huge_page_mask(hstate); | ||
70 | if (pte_end < end) | ||
71 | end = pte_end; | ||
72 | |||
73 | pte = *ptep; | ||
74 | mask = _PAGE_PRESENT|_PAGE_USER; | ||
75 | if (write) | ||
76 | mask |= _PAGE_RW; | ||
77 | if ((pte_val(pte) & mask) != mask) | ||
78 | return 0; | ||
79 | /* hugepages are never "special" */ | ||
80 | VM_BUG_ON(!pfn_valid(pte_pfn(pte))); | ||
81 | |||
82 | refs = 0; | ||
83 | head = pte_page(pte); | ||
84 | page = head + ((*addr & ~huge_page_mask(hstate)) >> PAGE_SHIFT); | ||
85 | do { | ||
86 | VM_BUG_ON(compound_head(page) != head); | ||
87 | pages[*nr] = page; | ||
88 | (*nr)++; | ||
89 | page++; | ||
90 | refs++; | ||
91 | } while (*addr += PAGE_SIZE, *addr != end); | ||
92 | |||
93 | if (!page_cache_add_speculative(head, refs)) { | ||
94 | *nr -= refs; | ||
95 | return 0; | ||
96 | } | ||
97 | if (unlikely(pte_val(pte) != pte_val(*ptep))) { | ||
98 | /* Could be optimized better */ | ||
99 | while (*nr) { | ||
100 | put_page(page); | ||
101 | (*nr)--; | ||
102 | } | ||
103 | } | ||
104 | |||
105 | return 1; | ||
106 | } | ||
107 | #endif /* CONFIG_HUGETLB_PAGE */ | ||
108 | |||
109 | static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end, | 58 | static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end, |
110 | int write, struct page **pages, int *nr) | 59 | int write, struct page **pages, int *nr) |
111 | { | 60 | { |
@@ -119,7 +68,11 @@ static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end, | |||
119 | next = pmd_addr_end(addr, end); | 68 | next = pmd_addr_end(addr, end); |
120 | if (pmd_none(pmd)) | 69 | if (pmd_none(pmd)) |
121 | return 0; | 70 | return 0; |
122 | if (!gup_pte_range(pmd, addr, next, write, pages, nr)) | 71 | if (is_hugepd(pmdp)) { |
72 | if (!gup_hugepd((hugepd_t *)pmdp, PMD_SHIFT, | ||
73 | addr, next, write, pages, nr)) | ||
74 | return 0; | ||
75 | } else if (!gup_pte_range(pmd, addr, next, write, pages, nr)) | ||
123 | return 0; | 76 | return 0; |
124 | } while (pmdp++, addr = next, addr != end); | 77 | } while (pmdp++, addr = next, addr != end); |
125 | 78 | ||
@@ -139,7 +92,11 @@ static int gup_pud_range(pgd_t pgd, unsigned long addr, unsigned long end, | |||
139 | next = pud_addr_end(addr, end); | 92 | next = pud_addr_end(addr, end); |
140 | if (pud_none(pud)) | 93 | if (pud_none(pud)) |
141 | return 0; | 94 | return 0; |
142 | if (!gup_pmd_range(pud, addr, next, write, pages, nr)) | 95 | if (is_hugepd(pudp)) { |
96 | if (!gup_hugepd((hugepd_t *)pudp, PUD_SHIFT, | ||
97 | addr, next, write, pages, nr)) | ||
98 | return 0; | ||
99 | } else if (!gup_pmd_range(pud, addr, next, write, pages, nr)) | ||
143 | return 0; | 100 | return 0; |
144 | } while (pudp++, addr = next, addr != end); | 101 | } while (pudp++, addr = next, addr != end); |
145 | 102 | ||
@@ -154,10 +111,6 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write, | |||
154 | unsigned long next; | 111 | unsigned long next; |
155 | pgd_t *pgdp; | 112 | pgd_t *pgdp; |
156 | int nr = 0; | 113 | int nr = 0; |
157 | #ifdef CONFIG_PPC64 | ||
158 | unsigned int shift; | ||
159 | int psize; | ||
160 | #endif | ||
161 | 114 | ||
162 | pr_devel("%s(%lx,%x,%s)\n", __func__, start, nr_pages, write ? "write" : "read"); | 115 | pr_devel("%s(%lx,%x,%s)\n", __func__, start, nr_pages, write ? "write" : "read"); |
163 | 116 | ||
@@ -172,25 +125,6 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write, | |||
172 | 125 | ||
173 | pr_devel(" aligned: %lx .. %lx\n", start, end); | 126 | pr_devel(" aligned: %lx .. %lx\n", start, end); |
174 | 127 | ||
175 | #ifdef CONFIG_HUGETLB_PAGE | ||
176 | /* We bail out on slice boundary crossing when hugetlb is | ||
177 | * enabled in order to not have to deal with two different | ||
178 | * page table formats | ||
179 | */ | ||
180 | if (addr < SLICE_LOW_TOP) { | ||
181 | if (end > SLICE_LOW_TOP) | ||
182 | goto slow_irqon; | ||
183 | |||
184 | if (unlikely(GET_LOW_SLICE_INDEX(addr) != | ||
185 | GET_LOW_SLICE_INDEX(end - 1))) | ||
186 | goto slow_irqon; | ||
187 | } else { | ||
188 | if (unlikely(GET_HIGH_SLICE_INDEX(addr) != | ||
189 | GET_HIGH_SLICE_INDEX(end - 1))) | ||
190 | goto slow_irqon; | ||
191 | } | ||
192 | #endif /* CONFIG_HUGETLB_PAGE */ | ||
193 | |||
194 | /* | 128 | /* |
195 | * XXX: batch / limit 'nr', to avoid large irq off latency | 129 | * XXX: batch / limit 'nr', to avoid large irq off latency |
196 | * needs some instrumenting to determine the common sizes used by | 130 | * needs some instrumenting to determine the common sizes used by |
@@ -210,54 +144,23 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write, | |||
210 | */ | 144 | */ |
211 | local_irq_disable(); | 145 | local_irq_disable(); |
212 | 146 | ||
213 | #ifdef CONFIG_PPC64 | 147 | pgdp = pgd_offset(mm, addr); |
214 | /* Those bits are related to hugetlbfs implementation and only exist | 148 | do { |
215 | * on 64-bit for now | 149 | pgd_t pgd = *pgdp; |
216 | */ | 150 | |
217 | psize = get_slice_psize(mm, addr); | 151 | pr_devel(" %016lx: normal pgd %p\n", addr, |
218 | shift = mmu_psize_defs[psize].shift; | 152 | (void *)pgd_val(pgd)); |
219 | #endif /* CONFIG_PPC64 */ | 153 | next = pgd_addr_end(addr, end); |
220 | 154 | if (pgd_none(pgd)) | |
221 | #ifdef CONFIG_HUGETLB_PAGE | 155 | goto slow; |
222 | if (unlikely(mmu_huge_psizes[psize])) { | 156 | if (is_hugepd(pgdp)) { |
223 | pte_t *ptep; | 157 | if (!gup_hugepd((hugepd_t *)pgdp, PGDIR_SHIFT, |
224 | unsigned long a = addr; | 158 | addr, next, write, pages, &nr)) |
225 | unsigned long sz = ((1UL) << shift); | ||
226 | struct hstate *hstate = size_to_hstate(sz); | ||
227 | |||
228 | BUG_ON(!hstate); | ||
229 | /* | ||
230 | * XXX: could be optimized to avoid hstate | ||
231 | * lookup entirely (just use shift) | ||
232 | */ | ||
233 | |||
234 | do { | ||
235 | VM_BUG_ON(shift != mmu_psize_defs[get_slice_psize(mm, a)].shift); | ||
236 | ptep = huge_pte_offset(mm, a); | ||
237 | pr_devel(" %016lx: huge ptep %p\n", a, ptep); | ||
238 | if (!ptep || !gup_huge_pte(ptep, hstate, &a, end, write, pages, | ||
239 | &nr)) | ||
240 | goto slow; | ||
241 | } while (a != end); | ||
242 | } else | ||
243 | #endif /* CONFIG_HUGETLB_PAGE */ | ||
244 | { | ||
245 | pgdp = pgd_offset(mm, addr); | ||
246 | do { | ||
247 | pgd_t pgd = *pgdp; | ||
248 | |||
249 | #ifdef CONFIG_PPC64 | ||
250 | VM_BUG_ON(shift != mmu_psize_defs[get_slice_psize(mm, addr)].shift); | ||
251 | #endif | ||
252 | pr_devel(" %016lx: normal pgd %p\n", addr, | ||
253 | (void *)pgd_val(pgd)); | ||
254 | next = pgd_addr_end(addr, end); | ||
255 | if (pgd_none(pgd)) | ||
256 | goto slow; | ||
257 | if (!gup_pud_range(pgd, addr, next, write, pages, &nr)) | ||
258 | goto slow; | 159 | goto slow; |
259 | } while (pgdp++, addr = next, addr != end); | 160 | } else if (!gup_pud_range(pgd, addr, next, write, pages, &nr)) |
260 | } | 161 | goto slow; |
162 | } while (pgdp++, addr = next, addr != end); | ||
163 | |||
261 | local_irq_enable(); | 164 | local_irq_enable(); |
262 | 165 | ||
263 | VM_BUG_ON(nr != (end - start) >> PAGE_SHIFT); | 166 | VM_BUG_ON(nr != (end - start) >> PAGE_SHIFT); |
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index 1ade7eb6ae00..50f867d657df 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c | |||
@@ -92,6 +92,7 @@ struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT]; | |||
92 | struct hash_pte *htab_address; | 92 | struct hash_pte *htab_address; |
93 | unsigned long htab_size_bytes; | 93 | unsigned long htab_size_bytes; |
94 | unsigned long htab_hash_mask; | 94 | unsigned long htab_hash_mask; |
95 | EXPORT_SYMBOL_GPL(htab_hash_mask); | ||
95 | int mmu_linear_psize = MMU_PAGE_4K; | 96 | int mmu_linear_psize = MMU_PAGE_4K; |
96 | int mmu_virtual_psize = MMU_PAGE_4K; | 97 | int mmu_virtual_psize = MMU_PAGE_4K; |
97 | int mmu_vmalloc_psize = MMU_PAGE_4K; | 98 | int mmu_vmalloc_psize = MMU_PAGE_4K; |
@@ -102,6 +103,7 @@ int mmu_io_psize = MMU_PAGE_4K; | |||
102 | int mmu_kernel_ssize = MMU_SEGSIZE_256M; | 103 | int mmu_kernel_ssize = MMU_SEGSIZE_256M; |
103 | int mmu_highuser_ssize = MMU_SEGSIZE_256M; | 104 | int mmu_highuser_ssize = MMU_SEGSIZE_256M; |
104 | u16 mmu_slb_size = 64; | 105 | u16 mmu_slb_size = 64; |
106 | EXPORT_SYMBOL_GPL(mmu_slb_size); | ||
105 | #ifdef CONFIG_HUGETLB_PAGE | 107 | #ifdef CONFIG_HUGETLB_PAGE |
106 | unsigned int HPAGE_SHIFT; | 108 | unsigned int HPAGE_SHIFT; |
107 | #endif | 109 | #endif |
@@ -481,16 +483,6 @@ static void __init htab_init_page_sizes(void) | |||
481 | #ifdef CONFIG_HUGETLB_PAGE | 483 | #ifdef CONFIG_HUGETLB_PAGE |
482 | /* Reserve 16G huge page memory sections for huge pages */ | 484 | /* Reserve 16G huge page memory sections for huge pages */ |
483 | of_scan_flat_dt(htab_dt_scan_hugepage_blocks, NULL); | 485 | of_scan_flat_dt(htab_dt_scan_hugepage_blocks, NULL); |
484 | |||
485 | /* Set default large page size. Currently, we pick 16M or 1M depending | ||
486 | * on what is available | ||
487 | */ | ||
488 | if (mmu_psize_defs[MMU_PAGE_16M].shift) | ||
489 | HPAGE_SHIFT = mmu_psize_defs[MMU_PAGE_16M].shift; | ||
490 | /* With 4k/4level pagetables, we can't (for now) cope with a | ||
491 | * huge page size < PMD_SIZE */ | ||
492 | else if (mmu_psize_defs[MMU_PAGE_1M].shift) | ||
493 | HPAGE_SHIFT = mmu_psize_defs[MMU_PAGE_1M].shift; | ||
494 | #endif /* CONFIG_HUGETLB_PAGE */ | 486 | #endif /* CONFIG_HUGETLB_PAGE */ |
495 | } | 487 | } |
496 | 488 | ||
@@ -785,7 +777,7 @@ unsigned int hash_page_do_lazy_icache(unsigned int pp, pte_t pte, int trap) | |||
785 | /* page is dirty */ | 777 | /* page is dirty */ |
786 | if (!test_bit(PG_arch_1, &page->flags) && !PageReserved(page)) { | 778 | if (!test_bit(PG_arch_1, &page->flags) && !PageReserved(page)) { |
787 | if (trap == 0x400) { | 779 | if (trap == 0x400) { |
788 | __flush_dcache_icache(page_address(page)); | 780 | flush_dcache_icache_page(page); |
789 | set_bit(PG_arch_1, &page->flags); | 781 | set_bit(PG_arch_1, &page->flags); |
790 | } else | 782 | } else |
791 | pp |= HPTE_R_N; | 783 | pp |= HPTE_R_N; |
@@ -843,9 +835,9 @@ void demote_segment_4k(struct mm_struct *mm, unsigned long addr) | |||
843 | * Result is 0: full permissions, _PAGE_RW: read-only, | 835 | * Result is 0: full permissions, _PAGE_RW: read-only, |
844 | * _PAGE_USER or _PAGE_USER|_PAGE_RW: no access. | 836 | * _PAGE_USER or _PAGE_USER|_PAGE_RW: no access. |
845 | */ | 837 | */ |
846 | static int subpage_protection(pgd_t *pgdir, unsigned long ea) | 838 | static int subpage_protection(struct mm_struct *mm, unsigned long ea) |
847 | { | 839 | { |
848 | struct subpage_prot_table *spt = pgd_subpage_prot(pgdir); | 840 | struct subpage_prot_table *spt = &mm->context.spt; |
849 | u32 spp = 0; | 841 | u32 spp = 0; |
850 | u32 **sbpm, *sbpp; | 842 | u32 **sbpm, *sbpp; |
851 | 843 | ||
@@ -873,7 +865,7 @@ static int subpage_protection(pgd_t *pgdir, unsigned long ea) | |||
873 | } | 865 | } |
874 | 866 | ||
875 | #else /* CONFIG_PPC_SUBPAGE_PROT */ | 867 | #else /* CONFIG_PPC_SUBPAGE_PROT */ |
876 | static inline int subpage_protection(pgd_t *pgdir, unsigned long ea) | 868 | static inline int subpage_protection(struct mm_struct *mm, unsigned long ea) |
877 | { | 869 | { |
878 | return 0; | 870 | return 0; |
879 | } | 871 | } |
@@ -891,6 +883,7 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap) | |||
891 | unsigned long vsid; | 883 | unsigned long vsid; |
892 | struct mm_struct *mm; | 884 | struct mm_struct *mm; |
893 | pte_t *ptep; | 885 | pte_t *ptep; |
886 | unsigned hugeshift; | ||
894 | const struct cpumask *tmp; | 887 | const struct cpumask *tmp; |
895 | int rc, user_region = 0, local = 0; | 888 | int rc, user_region = 0, local = 0; |
896 | int psize, ssize; | 889 | int psize, ssize; |
@@ -943,30 +936,31 @@ int hash_page(unsigned long ea, unsigned long access, unsigned long trap) | |||
943 | if (user_region && cpumask_equal(mm_cpumask(mm), tmp)) | 936 | if (user_region && cpumask_equal(mm_cpumask(mm), tmp)) |
944 | local = 1; | 937 | local = 1; |
945 | 938 | ||
946 | #ifdef CONFIG_HUGETLB_PAGE | ||
947 | /* Handle hugepage regions */ | ||
948 | if (HPAGE_SHIFT && mmu_huge_psizes[psize]) { | ||
949 | DBG_LOW(" -> huge page !\n"); | ||
950 | return hash_huge_page(mm, access, ea, vsid, local, trap); | ||
951 | } | ||
952 | #endif /* CONFIG_HUGETLB_PAGE */ | ||
953 | |||
954 | #ifndef CONFIG_PPC_64K_PAGES | 939 | #ifndef CONFIG_PPC_64K_PAGES |
955 | /* If we use 4K pages and our psize is not 4K, then we are hitting | 940 | /* If we use 4K pages and our psize is not 4K, then we might |
956 | * a special driver mapping, we need to align the address before | 941 | * be hitting a special driver mapping, and need to align the |
957 | * we fetch the PTE | 942 | * address before we fetch the PTE. |
943 | * | ||
944 | * It could also be a hugepage mapping, in which case this is | ||
945 | * not necessary, but it's not harmful, either. | ||
958 | */ | 946 | */ |
959 | if (psize != MMU_PAGE_4K) | 947 | if (psize != MMU_PAGE_4K) |
960 | ea &= ~((1ul << mmu_psize_defs[psize].shift) - 1); | 948 | ea &= ~((1ul << mmu_psize_defs[psize].shift) - 1); |
961 | #endif /* CONFIG_PPC_64K_PAGES */ | 949 | #endif /* CONFIG_PPC_64K_PAGES */ |
962 | 950 | ||
963 | /* Get PTE and page size from page tables */ | 951 | /* Get PTE and page size from page tables */ |
964 | ptep = find_linux_pte(pgdir, ea); | 952 | ptep = find_linux_pte_or_hugepte(pgdir, ea, &hugeshift); |
965 | if (ptep == NULL || !pte_present(*ptep)) { | 953 | if (ptep == NULL || !pte_present(*ptep)) { |
966 | DBG_LOW(" no PTE !\n"); | 954 | DBG_LOW(" no PTE !\n"); |
967 | return 1; | 955 | return 1; |
968 | } | 956 | } |
969 | 957 | ||
958 | #ifdef CONFIG_HUGETLB_PAGE | ||
959 | if (hugeshift) | ||
960 | return __hash_page_huge(ea, access, vsid, ptep, trap, local, | ||
961 | ssize, hugeshift, psize); | ||
962 | #endif /* CONFIG_HUGETLB_PAGE */ | ||
963 | |||
970 | #ifndef CONFIG_PPC_64K_PAGES | 964 | #ifndef CONFIG_PPC_64K_PAGES |
971 | DBG_LOW(" i-pte: %016lx\n", pte_val(*ptep)); | 965 | DBG_LOW(" i-pte: %016lx\n", pte_val(*ptep)); |
972 | #else | 966 | #else |
diff --git a/arch/powerpc/mm/hugetlbpage-hash64.c b/arch/powerpc/mm/hugetlbpage-hash64.c new file mode 100644 index 000000000000..199539882f92 --- /dev/null +++ b/arch/powerpc/mm/hugetlbpage-hash64.c | |||
@@ -0,0 +1,139 @@ | |||
1 | /* | ||
2 | * PPC64 Huge TLB Page Support for hash based MMUs (POWER4 and later) | ||
3 | * | ||
4 | * Copyright (C) 2003 David Gibson, IBM Corporation. | ||
5 | * | ||
6 | * Based on the IA-32 version: | ||
7 | * Copyright (C) 2002, Rohit Seth <rohit.seth@intel.com> | ||
8 | */ | ||
9 | |||
10 | #include <linux/mm.h> | ||
11 | #include <linux/hugetlb.h> | ||
12 | #include <asm/pgtable.h> | ||
13 | #include <asm/pgalloc.h> | ||
14 | #include <asm/cacheflush.h> | ||
15 | #include <asm/machdep.h> | ||
16 | |||
17 | int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid, | ||
18 | pte_t *ptep, unsigned long trap, int local, int ssize, | ||
19 | unsigned int shift, unsigned int mmu_psize) | ||
20 | { | ||
21 | unsigned long old_pte, new_pte; | ||
22 | unsigned long va, rflags, pa, sz; | ||
23 | long slot; | ||
24 | int err = 1; | ||
25 | |||
26 | BUG_ON(shift != mmu_psize_defs[mmu_psize].shift); | ||
27 | |||
28 | /* Search the Linux page table for a match with va */ | ||
29 | va = hpt_va(ea, vsid, ssize); | ||
30 | |||
31 | /* | ||
32 | * Check the user's access rights to the page. If access should be | ||
33 | * prevented then send the problem up to do_page_fault. | ||
34 | */ | ||
35 | if (unlikely(access & ~pte_val(*ptep))) | ||
36 | goto out; | ||
37 | /* | ||
38 | * At this point, we have a pte (old_pte) which can be used to build | ||
39 | * or update an HPTE. There are 2 cases: | ||
40 | * | ||
41 | * 1. There is a valid (present) pte with no associated HPTE (this is | ||
42 | * the most common case) | ||
43 | * 2. There is a valid (present) pte with an associated HPTE. The | ||
44 | * current values of the pp bits in the HPTE prevent access | ||
45 | * because we are doing software DIRTY bit management and the | ||
46 | * page is currently not DIRTY. | ||
47 | */ | ||
48 | |||
49 | |||
50 | do { | ||
51 | old_pte = pte_val(*ptep); | ||
52 | if (old_pte & _PAGE_BUSY) | ||
53 | goto out; | ||
54 | new_pte = old_pte | _PAGE_BUSY | _PAGE_ACCESSED; | ||
55 | } while(old_pte != __cmpxchg_u64((unsigned long *)ptep, | ||
56 | old_pte, new_pte)); | ||
57 | |||
58 | rflags = 0x2 | (!(new_pte & _PAGE_RW)); | ||
59 | /* _PAGE_EXEC -> HW_NO_EXEC since it's inverted */ | ||
60 | rflags |= ((new_pte & _PAGE_EXEC) ? 0 : HPTE_R_N); | ||
61 | sz = ((1UL) << shift); | ||
62 | if (!cpu_has_feature(CPU_FTR_COHERENT_ICACHE)) | ||
63 | /* No CPU has hugepages but lacks no execute, so we | ||
64 | * don't need to worry about that case */ | ||
65 | rflags = hash_page_do_lazy_icache(rflags, __pte(old_pte), trap); | ||
66 | |||
67 | /* Check if pte already has an hpte (case 2) */ | ||
68 | if (unlikely(old_pte & _PAGE_HASHPTE)) { | ||
69 | /* There MIGHT be an HPTE for this pte */ | ||
70 | unsigned long hash, slot; | ||
71 | |||
72 | hash = hpt_hash(va, shift, ssize); | ||
73 | if (old_pte & _PAGE_F_SECOND) | ||
74 | hash = ~hash; | ||
75 | slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; | ||
76 | slot += (old_pte & _PAGE_F_GIX) >> 12; | ||
77 | |||
78 | if (ppc_md.hpte_updatepp(slot, rflags, va, mmu_psize, | ||
79 | ssize, local) == -1) | ||
80 | old_pte &= ~_PAGE_HPTEFLAGS; | ||
81 | } | ||
82 | |||
83 | if (likely(!(old_pte & _PAGE_HASHPTE))) { | ||
84 | unsigned long hash = hpt_hash(va, shift, ssize); | ||
85 | unsigned long hpte_group; | ||
86 | |||
87 | pa = pte_pfn(__pte(old_pte)) << PAGE_SHIFT; | ||
88 | |||
89 | repeat: | ||
90 | hpte_group = ((hash & htab_hash_mask) * | ||
91 | HPTES_PER_GROUP) & ~0x7UL; | ||
92 | |||
93 | /* clear HPTE slot informations in new PTE */ | ||
94 | #ifdef CONFIG_PPC_64K_PAGES | ||
95 | new_pte = (new_pte & ~_PAGE_HPTEFLAGS) | _PAGE_HPTE_SUB0; | ||
96 | #else | ||
97 | new_pte = (new_pte & ~_PAGE_HPTEFLAGS) | _PAGE_HASHPTE; | ||
98 | #endif | ||
99 | /* Add in WIMG bits */ | ||
100 | rflags |= (new_pte & (_PAGE_WRITETHRU | _PAGE_NO_CACHE | | ||
101 | _PAGE_COHERENT | _PAGE_GUARDED)); | ||
102 | |||
103 | /* Insert into the hash table, primary slot */ | ||
104 | slot = ppc_md.hpte_insert(hpte_group, va, pa, rflags, 0, | ||
105 | mmu_psize, ssize); | ||
106 | |||
107 | /* Primary is full, try the secondary */ | ||
108 | if (unlikely(slot == -1)) { | ||
109 | hpte_group = ((~hash & htab_hash_mask) * | ||
110 | HPTES_PER_GROUP) & ~0x7UL; | ||
111 | slot = ppc_md.hpte_insert(hpte_group, va, pa, rflags, | ||
112 | HPTE_V_SECONDARY, | ||
113 | mmu_psize, ssize); | ||
114 | if (slot == -1) { | ||
115 | if (mftb() & 0x1) | ||
116 | hpte_group = ((hash & htab_hash_mask) * | ||
117 | HPTES_PER_GROUP)&~0x7UL; | ||
118 | |||
119 | ppc_md.hpte_remove(hpte_group); | ||
120 | goto repeat; | ||
121 | } | ||
122 | } | ||
123 | |||
124 | if (unlikely(slot == -2)) | ||
125 | panic("hash_huge_page: pte_insert failed\n"); | ||
126 | |||
127 | new_pte |= (slot << 12) & (_PAGE_F_SECOND | _PAGE_F_GIX); | ||
128 | } | ||
129 | |||
130 | /* | ||
131 | * No need to use ldarx/stdcx here | ||
132 | */ | ||
133 | *ptep = __pte(new_pte & ~_PAGE_BUSY); | ||
134 | |||
135 | err = 0; | ||
136 | |||
137 | out: | ||
138 | return err; | ||
139 | } | ||
diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c index 90df6ffe3a43..123f7070238a 100644 --- a/arch/powerpc/mm/hugetlbpage.c +++ b/arch/powerpc/mm/hugetlbpage.c | |||
@@ -7,29 +7,17 @@ | |||
7 | * Copyright (C) 2002, Rohit Seth <rohit.seth@intel.com> | 7 | * Copyright (C) 2002, Rohit Seth <rohit.seth@intel.com> |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/fs.h> | ||
12 | #include <linux/mm.h> | 10 | #include <linux/mm.h> |
11 | #include <linux/io.h> | ||
13 | #include <linux/hugetlb.h> | 12 | #include <linux/hugetlb.h> |
14 | #include <linux/pagemap.h> | 13 | #include <asm/pgtable.h> |
15 | #include <linux/slab.h> | ||
16 | #include <linux/err.h> | ||
17 | #include <linux/sysctl.h> | ||
18 | #include <asm/mman.h> | ||
19 | #include <asm/pgalloc.h> | 14 | #include <asm/pgalloc.h> |
20 | #include <asm/tlb.h> | 15 | #include <asm/tlb.h> |
21 | #include <asm/tlbflush.h> | ||
22 | #include <asm/mmu_context.h> | ||
23 | #include <asm/machdep.h> | ||
24 | #include <asm/cputable.h> | ||
25 | #include <asm/spu.h> | ||
26 | 16 | ||
27 | #define PAGE_SHIFT_64K 16 | 17 | #define PAGE_SHIFT_64K 16 |
28 | #define PAGE_SHIFT_16M 24 | 18 | #define PAGE_SHIFT_16M 24 |
29 | #define PAGE_SHIFT_16G 34 | 19 | #define PAGE_SHIFT_16G 34 |
30 | 20 | ||
31 | #define NUM_LOW_AREAS (0x100000000UL >> SID_SHIFT) | ||
32 | #define NUM_HIGH_AREAS (PGTABLE_RANGE >> HTLB_AREA_SHIFT) | ||
33 | #define MAX_NUMBER_GPAGES 1024 | 21 | #define MAX_NUMBER_GPAGES 1024 |
34 | 22 | ||
35 | /* Tracks the 16G pages after the device tree is scanned and before the | 23 | /* Tracks the 16G pages after the device tree is scanned and before the |
@@ -37,53 +25,17 @@ | |||
37 | static unsigned long gpage_freearray[MAX_NUMBER_GPAGES]; | 25 | static unsigned long gpage_freearray[MAX_NUMBER_GPAGES]; |
38 | static unsigned nr_gpages; | 26 | static unsigned nr_gpages; |
39 | 27 | ||
40 | /* Array of valid huge page sizes - non-zero value(hugepte_shift) is | ||
41 | * stored for the huge page sizes that are valid. | ||
42 | */ | ||
43 | unsigned int mmu_huge_psizes[MMU_PAGE_COUNT] = { }; /* initialize all to 0 */ | ||
44 | |||
45 | #define hugepte_shift mmu_huge_psizes | ||
46 | #define PTRS_PER_HUGEPTE(psize) (1 << hugepte_shift[psize]) | ||
47 | #define HUGEPTE_TABLE_SIZE(psize) (sizeof(pte_t) << hugepte_shift[psize]) | ||
48 | |||
49 | #define HUGEPD_SHIFT(psize) (mmu_psize_to_shift(psize) \ | ||
50 | + hugepte_shift[psize]) | ||
51 | #define HUGEPD_SIZE(psize) (1UL << HUGEPD_SHIFT(psize)) | ||
52 | #define HUGEPD_MASK(psize) (~(HUGEPD_SIZE(psize)-1)) | ||
53 | |||
54 | /* Subtract one from array size because we don't need a cache for 4K since | ||
55 | * is not a huge page size */ | ||
56 | #define HUGE_PGTABLE_INDEX(psize) (HUGEPTE_CACHE_NUM + psize - 1) | ||
57 | #define HUGEPTE_CACHE_NAME(psize) (huge_pgtable_cache_name[psize]) | ||
58 | |||
59 | static const char *huge_pgtable_cache_name[MMU_PAGE_COUNT] = { | ||
60 | [MMU_PAGE_64K] = "hugepte_cache_64K", | ||
61 | [MMU_PAGE_1M] = "hugepte_cache_1M", | ||
62 | [MMU_PAGE_16M] = "hugepte_cache_16M", | ||
63 | [MMU_PAGE_16G] = "hugepte_cache_16G", | ||
64 | }; | ||
65 | |||
66 | /* Flag to mark huge PD pointers. This means pmd_bad() and pud_bad() | 28 | /* Flag to mark huge PD pointers. This means pmd_bad() and pud_bad() |
67 | * will choke on pointers to hugepte tables, which is handy for | 29 | * will choke on pointers to hugepte tables, which is handy for |
68 | * catching screwups early. */ | 30 | * catching screwups early. */ |
69 | #define HUGEPD_OK 0x1 | ||
70 | |||
71 | typedef struct { unsigned long pd; } hugepd_t; | ||
72 | |||
73 | #define hugepd_none(hpd) ((hpd).pd == 0) | ||
74 | 31 | ||
75 | static inline int shift_to_mmu_psize(unsigned int shift) | 32 | static inline int shift_to_mmu_psize(unsigned int shift) |
76 | { | 33 | { |
77 | switch (shift) { | 34 | int psize; |
78 | #ifndef CONFIG_PPC_64K_PAGES | 35 | |
79 | case PAGE_SHIFT_64K: | 36 | for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) |
80 | return MMU_PAGE_64K; | 37 | if (mmu_psize_defs[psize].shift == shift) |
81 | #endif | 38 | return psize; |
82 | case PAGE_SHIFT_16M: | ||
83 | return MMU_PAGE_16M; | ||
84 | case PAGE_SHIFT_16G: | ||
85 | return MMU_PAGE_16G; | ||
86 | } | ||
87 | return -1; | 39 | return -1; |
88 | } | 40 | } |
89 | 41 | ||
@@ -94,71 +46,126 @@ static inline unsigned int mmu_psize_to_shift(unsigned int mmu_psize) | |||
94 | BUG(); | 46 | BUG(); |
95 | } | 47 | } |
96 | 48 | ||
49 | #define hugepd_none(hpd) ((hpd).pd == 0) | ||
50 | |||
97 | static inline pte_t *hugepd_page(hugepd_t hpd) | 51 | static inline pte_t *hugepd_page(hugepd_t hpd) |
98 | { | 52 | { |
99 | BUG_ON(!(hpd.pd & HUGEPD_OK)); | 53 | BUG_ON(!hugepd_ok(hpd)); |
100 | return (pte_t *)(hpd.pd & ~HUGEPD_OK); | 54 | return (pte_t *)((hpd.pd & ~HUGEPD_SHIFT_MASK) | 0xc000000000000000); |
55 | } | ||
56 | |||
57 | static inline unsigned int hugepd_shift(hugepd_t hpd) | ||
58 | { | ||
59 | return hpd.pd & HUGEPD_SHIFT_MASK; | ||
101 | } | 60 | } |
102 | 61 | ||
103 | static inline pte_t *hugepte_offset(hugepd_t *hpdp, unsigned long addr, | 62 | static inline pte_t *hugepte_offset(hugepd_t *hpdp, unsigned long addr, unsigned pdshift) |
104 | struct hstate *hstate) | ||
105 | { | 63 | { |
106 | unsigned int shift = huge_page_shift(hstate); | 64 | unsigned long idx = (addr & ((1UL << pdshift) - 1)) >> hugepd_shift(*hpdp); |
107 | int psize = shift_to_mmu_psize(shift); | ||
108 | unsigned long idx = ((addr >> shift) & (PTRS_PER_HUGEPTE(psize)-1)); | ||
109 | pte_t *dir = hugepd_page(*hpdp); | 65 | pte_t *dir = hugepd_page(*hpdp); |
110 | 66 | ||
111 | return dir + idx; | 67 | return dir + idx; |
112 | } | 68 | } |
113 | 69 | ||
70 | pte_t *find_linux_pte_or_hugepte(pgd_t *pgdir, unsigned long ea, unsigned *shift) | ||
71 | { | ||
72 | pgd_t *pg; | ||
73 | pud_t *pu; | ||
74 | pmd_t *pm; | ||
75 | hugepd_t *hpdp = NULL; | ||
76 | unsigned pdshift = PGDIR_SHIFT; | ||
77 | |||
78 | if (shift) | ||
79 | *shift = 0; | ||
80 | |||
81 | pg = pgdir + pgd_index(ea); | ||
82 | if (is_hugepd(pg)) { | ||
83 | hpdp = (hugepd_t *)pg; | ||
84 | } else if (!pgd_none(*pg)) { | ||
85 | pdshift = PUD_SHIFT; | ||
86 | pu = pud_offset(pg, ea); | ||
87 | if (is_hugepd(pu)) | ||
88 | hpdp = (hugepd_t *)pu; | ||
89 | else if (!pud_none(*pu)) { | ||
90 | pdshift = PMD_SHIFT; | ||
91 | pm = pmd_offset(pu, ea); | ||
92 | if (is_hugepd(pm)) | ||
93 | hpdp = (hugepd_t *)pm; | ||
94 | else if (!pmd_none(*pm)) { | ||
95 | return pte_offset_map(pm, ea); | ||
96 | } | ||
97 | } | ||
98 | } | ||
99 | |||
100 | if (!hpdp) | ||
101 | return NULL; | ||
102 | |||
103 | if (shift) | ||
104 | *shift = hugepd_shift(*hpdp); | ||
105 | return hugepte_offset(hpdp, ea, pdshift); | ||
106 | } | ||
107 | |||
108 | pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) | ||
109 | { | ||
110 | return find_linux_pte_or_hugepte(mm->pgd, addr, NULL); | ||
111 | } | ||
112 | |||
114 | static int __hugepte_alloc(struct mm_struct *mm, hugepd_t *hpdp, | 113 | static int __hugepte_alloc(struct mm_struct *mm, hugepd_t *hpdp, |
115 | unsigned long address, unsigned int psize) | 114 | unsigned long address, unsigned pdshift, unsigned pshift) |
116 | { | 115 | { |
117 | pte_t *new = kmem_cache_zalloc(pgtable_cache[HUGE_PGTABLE_INDEX(psize)], | 116 | pte_t *new = kmem_cache_zalloc(PGT_CACHE(pdshift - pshift), |
118 | GFP_KERNEL|__GFP_REPEAT); | 117 | GFP_KERNEL|__GFP_REPEAT); |
118 | |||
119 | BUG_ON(pshift > HUGEPD_SHIFT_MASK); | ||
120 | BUG_ON((unsigned long)new & HUGEPD_SHIFT_MASK); | ||
119 | 121 | ||
120 | if (! new) | 122 | if (! new) |
121 | return -ENOMEM; | 123 | return -ENOMEM; |
122 | 124 | ||
123 | spin_lock(&mm->page_table_lock); | 125 | spin_lock(&mm->page_table_lock); |
124 | if (!hugepd_none(*hpdp)) | 126 | if (!hugepd_none(*hpdp)) |
125 | kmem_cache_free(pgtable_cache[HUGE_PGTABLE_INDEX(psize)], new); | 127 | kmem_cache_free(PGT_CACHE(pdshift - pshift), new); |
126 | else | 128 | else |
127 | hpdp->pd = (unsigned long)new | HUGEPD_OK; | 129 | hpdp->pd = ((unsigned long)new & ~0x8000000000000000) | pshift; |
128 | spin_unlock(&mm->page_table_lock); | 130 | spin_unlock(&mm->page_table_lock); |
129 | return 0; | 131 | return 0; |
130 | } | 132 | } |
131 | 133 | ||
132 | 134 | pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr, unsigned long sz) | |
133 | static pud_t *hpud_offset(pgd_t *pgd, unsigned long addr, struct hstate *hstate) | ||
134 | { | ||
135 | if (huge_page_shift(hstate) < PUD_SHIFT) | ||
136 | return pud_offset(pgd, addr); | ||
137 | else | ||
138 | return (pud_t *) pgd; | ||
139 | } | ||
140 | static pud_t *hpud_alloc(struct mm_struct *mm, pgd_t *pgd, unsigned long addr, | ||
141 | struct hstate *hstate) | ||
142 | { | 135 | { |
143 | if (huge_page_shift(hstate) < PUD_SHIFT) | 136 | pgd_t *pg; |
144 | return pud_alloc(mm, pgd, addr); | 137 | pud_t *pu; |
145 | else | 138 | pmd_t *pm; |
146 | return (pud_t *) pgd; | 139 | hugepd_t *hpdp = NULL; |
147 | } | 140 | unsigned pshift = __ffs(sz); |
148 | static pmd_t *hpmd_offset(pud_t *pud, unsigned long addr, struct hstate *hstate) | 141 | unsigned pdshift = PGDIR_SHIFT; |
149 | { | 142 | |
150 | if (huge_page_shift(hstate) < PMD_SHIFT) | 143 | addr &= ~(sz-1); |
151 | return pmd_offset(pud, addr); | 144 | |
152 | else | 145 | pg = pgd_offset(mm, addr); |
153 | return (pmd_t *) pud; | 146 | if (pshift >= PUD_SHIFT) { |
154 | } | 147 | hpdp = (hugepd_t *)pg; |
155 | static pmd_t *hpmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long addr, | 148 | } else { |
156 | struct hstate *hstate) | 149 | pdshift = PUD_SHIFT; |
157 | { | 150 | pu = pud_alloc(mm, pg, addr); |
158 | if (huge_page_shift(hstate) < PMD_SHIFT) | 151 | if (pshift >= PMD_SHIFT) { |
159 | return pmd_alloc(mm, pud, addr); | 152 | hpdp = (hugepd_t *)pu; |
160 | else | 153 | } else { |
161 | return (pmd_t *) pud; | 154 | pdshift = PMD_SHIFT; |
155 | pm = pmd_alloc(mm, pu, addr); | ||
156 | hpdp = (hugepd_t *)pm; | ||
157 | } | ||
158 | } | ||
159 | |||
160 | if (!hpdp) | ||
161 | return NULL; | ||
162 | |||
163 | BUG_ON(!hugepd_none(*hpdp) && !hugepd_ok(*hpdp)); | ||
164 | |||
165 | if (hugepd_none(*hpdp) && __hugepte_alloc(mm, hpdp, addr, pdshift, pshift)) | ||
166 | return NULL; | ||
167 | |||
168 | return hugepte_offset(hpdp, addr, pdshift); | ||
162 | } | 169 | } |
163 | 170 | ||
164 | /* Build list of addresses of gigantic pages. This function is used in early | 171 | /* Build list of addresses of gigantic pages. This function is used in early |
@@ -192,94 +199,38 @@ int alloc_bootmem_huge_page(struct hstate *hstate) | |||
192 | return 1; | 199 | return 1; |
193 | } | 200 | } |
194 | 201 | ||
195 | |||
196 | /* Modelled after find_linux_pte() */ | ||
197 | pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) | ||
198 | { | ||
199 | pgd_t *pg; | ||
200 | pud_t *pu; | ||
201 | pmd_t *pm; | ||
202 | |||
203 | unsigned int psize; | ||
204 | unsigned int shift; | ||
205 | unsigned long sz; | ||
206 | struct hstate *hstate; | ||
207 | psize = get_slice_psize(mm, addr); | ||
208 | shift = mmu_psize_to_shift(psize); | ||
209 | sz = ((1UL) << shift); | ||
210 | hstate = size_to_hstate(sz); | ||
211 | |||
212 | addr &= hstate->mask; | ||
213 | |||
214 | pg = pgd_offset(mm, addr); | ||
215 | if (!pgd_none(*pg)) { | ||
216 | pu = hpud_offset(pg, addr, hstate); | ||
217 | if (!pud_none(*pu)) { | ||
218 | pm = hpmd_offset(pu, addr, hstate); | ||
219 | if (!pmd_none(*pm)) | ||
220 | return hugepte_offset((hugepd_t *)pm, addr, | ||
221 | hstate); | ||
222 | } | ||
223 | } | ||
224 | |||
225 | return NULL; | ||
226 | } | ||
227 | |||
228 | pte_t *huge_pte_alloc(struct mm_struct *mm, | ||
229 | unsigned long addr, unsigned long sz) | ||
230 | { | ||
231 | pgd_t *pg; | ||
232 | pud_t *pu; | ||
233 | pmd_t *pm; | ||
234 | hugepd_t *hpdp = NULL; | ||
235 | struct hstate *hstate; | ||
236 | unsigned int psize; | ||
237 | hstate = size_to_hstate(sz); | ||
238 | |||
239 | psize = get_slice_psize(mm, addr); | ||
240 | BUG_ON(!mmu_huge_psizes[psize]); | ||
241 | |||
242 | addr &= hstate->mask; | ||
243 | |||
244 | pg = pgd_offset(mm, addr); | ||
245 | pu = hpud_alloc(mm, pg, addr, hstate); | ||
246 | |||
247 | if (pu) { | ||
248 | pm = hpmd_alloc(mm, pu, addr, hstate); | ||
249 | if (pm) | ||
250 | hpdp = (hugepd_t *)pm; | ||
251 | } | ||
252 | |||
253 | if (! hpdp) | ||
254 | return NULL; | ||
255 | |||
256 | if (hugepd_none(*hpdp) && __hugepte_alloc(mm, hpdp, addr, psize)) | ||
257 | return NULL; | ||
258 | |||
259 | return hugepte_offset(hpdp, addr, hstate); | ||
260 | } | ||
261 | |||
262 | int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep) | 202 | int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep) |
263 | { | 203 | { |
264 | return 0; | 204 | return 0; |
265 | } | 205 | } |
266 | 206 | ||
267 | static void free_hugepte_range(struct mmu_gather *tlb, hugepd_t *hpdp, | 207 | static void free_hugepd_range(struct mmu_gather *tlb, hugepd_t *hpdp, int pdshift, |
268 | unsigned int psize) | 208 | unsigned long start, unsigned long end, |
209 | unsigned long floor, unsigned long ceiling) | ||
269 | { | 210 | { |
270 | pte_t *hugepte = hugepd_page(*hpdp); | 211 | pte_t *hugepte = hugepd_page(*hpdp); |
212 | unsigned shift = hugepd_shift(*hpdp); | ||
213 | unsigned long pdmask = ~((1UL << pdshift) - 1); | ||
214 | |||
215 | start &= pdmask; | ||
216 | if (start < floor) | ||
217 | return; | ||
218 | if (ceiling) { | ||
219 | ceiling &= pdmask; | ||
220 | if (! ceiling) | ||
221 | return; | ||
222 | } | ||
223 | if (end - 1 > ceiling - 1) | ||
224 | return; | ||
271 | 225 | ||
272 | hpdp->pd = 0; | 226 | hpdp->pd = 0; |
273 | tlb->need_flush = 1; | 227 | tlb->need_flush = 1; |
274 | pgtable_free_tlb(tlb, pgtable_free_cache(hugepte, | 228 | pgtable_free_tlb(tlb, hugepte, pdshift - shift); |
275 | HUGEPTE_CACHE_NUM+psize-1, | ||
276 | PGF_CACHENUM_MASK)); | ||
277 | } | 229 | } |
278 | 230 | ||
279 | static void hugetlb_free_pmd_range(struct mmu_gather *tlb, pud_t *pud, | 231 | static void hugetlb_free_pmd_range(struct mmu_gather *tlb, pud_t *pud, |
280 | unsigned long addr, unsigned long end, | 232 | unsigned long addr, unsigned long end, |
281 | unsigned long floor, unsigned long ceiling, | 233 | unsigned long floor, unsigned long ceiling) |
282 | unsigned int psize) | ||
283 | { | 234 | { |
284 | pmd_t *pmd; | 235 | pmd_t *pmd; |
285 | unsigned long next; | 236 | unsigned long next; |
@@ -291,7 +242,8 @@ static void hugetlb_free_pmd_range(struct mmu_gather *tlb, pud_t *pud, | |||
291 | next = pmd_addr_end(addr, end); | 242 | next = pmd_addr_end(addr, end); |
292 | if (pmd_none(*pmd)) | 243 | if (pmd_none(*pmd)) |
293 | continue; | 244 | continue; |
294 | free_hugepte_range(tlb, (hugepd_t *)pmd, psize); | 245 | free_hugepd_range(tlb, (hugepd_t *)pmd, PMD_SHIFT, |
246 | addr, next, floor, ceiling); | ||
295 | } while (pmd++, addr = next, addr != end); | 247 | } while (pmd++, addr = next, addr != end); |
296 | 248 | ||
297 | start &= PUD_MASK; | 249 | start &= PUD_MASK; |
@@ -317,23 +269,19 @@ static void hugetlb_free_pud_range(struct mmu_gather *tlb, pgd_t *pgd, | |||
317 | pud_t *pud; | 269 | pud_t *pud; |
318 | unsigned long next; | 270 | unsigned long next; |
319 | unsigned long start; | 271 | unsigned long start; |
320 | unsigned int shift; | ||
321 | unsigned int psize = get_slice_psize(tlb->mm, addr); | ||
322 | shift = mmu_psize_to_shift(psize); | ||
323 | 272 | ||
324 | start = addr; | 273 | start = addr; |
325 | pud = pud_offset(pgd, addr); | 274 | pud = pud_offset(pgd, addr); |
326 | do { | 275 | do { |
327 | next = pud_addr_end(addr, end); | 276 | next = pud_addr_end(addr, end); |
328 | if (shift < PMD_SHIFT) { | 277 | if (!is_hugepd(pud)) { |
329 | if (pud_none_or_clear_bad(pud)) | 278 | if (pud_none_or_clear_bad(pud)) |
330 | continue; | 279 | continue; |
331 | hugetlb_free_pmd_range(tlb, pud, addr, next, floor, | 280 | hugetlb_free_pmd_range(tlb, pud, addr, next, floor, |
332 | ceiling, psize); | 281 | ceiling); |
333 | } else { | 282 | } else { |
334 | if (pud_none(*pud)) | 283 | free_hugepd_range(tlb, (hugepd_t *)pud, PUD_SHIFT, |
335 | continue; | 284 | addr, next, floor, ceiling); |
336 | free_hugepte_range(tlb, (hugepd_t *)pud, psize); | ||
337 | } | 285 | } |
338 | } while (pud++, addr = next, addr != end); | 286 | } while (pud++, addr = next, addr != end); |
339 | 287 | ||
@@ -364,121 +312,56 @@ void hugetlb_free_pgd_range(struct mmu_gather *tlb, | |||
364 | { | 312 | { |
365 | pgd_t *pgd; | 313 | pgd_t *pgd; |
366 | unsigned long next; | 314 | unsigned long next; |
367 | unsigned long start; | ||
368 | 315 | ||
369 | /* | 316 | /* |
370 | * Comments below take from the normal free_pgd_range(). They | 317 | * Because there are a number of different possible pagetable |
371 | * apply here too. The tests against HUGEPD_MASK below are | 318 | * layouts for hugepage ranges, we limit knowledge of how |
372 | * essential, because we *don't* test for this at the bottom | 319 | * things should be laid out to the allocation path |
373 | * level. Without them we'll attempt to free a hugepte table | 320 | * (huge_pte_alloc(), above). Everything else works out the |
374 | * when we unmap just part of it, even if there are other | 321 | * structure as it goes from information in the hugepd |
375 | * active mappings using it. | 322 | * pointers. That means that we can't here use the |
376 | * | 323 | * optimization used in the normal page free_pgd_range(), of |
377 | * The next few lines have given us lots of grief... | 324 | * checking whether we're actually covering a large enough |
378 | * | 325 | * range to have to do anything at the top level of the walk |
379 | * Why are we testing HUGEPD* at this top level? Because | 326 | * instead of at the bottom. |
380 | * often there will be no work to do at all, and we'd prefer | ||
381 | * not to go all the way down to the bottom just to discover | ||
382 | * that. | ||
383 | * | ||
384 | * Why all these "- 1"s? Because 0 represents both the bottom | ||
385 | * of the address space and the top of it (using -1 for the | ||
386 | * top wouldn't help much: the masks would do the wrong thing). | ||
387 | * The rule is that addr 0 and floor 0 refer to the bottom of | ||
388 | * the address space, but end 0 and ceiling 0 refer to the top | ||
389 | * Comparisons need to use "end - 1" and "ceiling - 1" (though | ||
390 | * that end 0 case should be mythical). | ||
391 | * | 327 | * |
392 | * Wherever addr is brought up or ceiling brought down, we | 328 | * To make sense of this, you should probably go read the big |
393 | * must be careful to reject "the opposite 0" before it | 329 | * block comment at the top of the normal free_pgd_range(), |
394 | * confuses the subsequent tests. But what about where end is | 330 | * too. |
395 | * brought down by HUGEPD_SIZE below? no, end can't go down to | ||
396 | * 0 there. | ||
397 | * | ||
398 | * Whereas we round start (addr) and ceiling down, by different | ||
399 | * masks at different levels, in order to test whether a table | ||
400 | * now has no other vmas using it, so can be freed, we don't | ||
401 | * bother to round floor or end up - the tests don't need that. | ||
402 | */ | 331 | */ |
403 | unsigned int psize = get_slice_psize(tlb->mm, addr); | ||
404 | |||
405 | addr &= HUGEPD_MASK(psize); | ||
406 | if (addr < floor) { | ||
407 | addr += HUGEPD_SIZE(psize); | ||
408 | if (!addr) | ||
409 | return; | ||
410 | } | ||
411 | if (ceiling) { | ||
412 | ceiling &= HUGEPD_MASK(psize); | ||
413 | if (!ceiling) | ||
414 | return; | ||
415 | } | ||
416 | if (end - 1 > ceiling - 1) | ||
417 | end -= HUGEPD_SIZE(psize); | ||
418 | if (addr > end - 1) | ||
419 | return; | ||
420 | 332 | ||
421 | start = addr; | ||
422 | pgd = pgd_offset(tlb->mm, addr); | 333 | pgd = pgd_offset(tlb->mm, addr); |
423 | do { | 334 | do { |
424 | psize = get_slice_psize(tlb->mm, addr); | ||
425 | BUG_ON(!mmu_huge_psizes[psize]); | ||
426 | next = pgd_addr_end(addr, end); | 335 | next = pgd_addr_end(addr, end); |
427 | if (mmu_psize_to_shift(psize) < PUD_SHIFT) { | 336 | if (!is_hugepd(pgd)) { |
428 | if (pgd_none_or_clear_bad(pgd)) | 337 | if (pgd_none_or_clear_bad(pgd)) |
429 | continue; | 338 | continue; |
430 | hugetlb_free_pud_range(tlb, pgd, addr, next, floor, ceiling); | 339 | hugetlb_free_pud_range(tlb, pgd, addr, next, floor, ceiling); |
431 | } else { | 340 | } else { |
432 | if (pgd_none(*pgd)) | 341 | free_hugepd_range(tlb, (hugepd_t *)pgd, PGDIR_SHIFT, |
433 | continue; | 342 | addr, next, floor, ceiling); |
434 | free_hugepte_range(tlb, (hugepd_t *)pgd, psize); | ||
435 | } | 343 | } |
436 | } while (pgd++, addr = next, addr != end); | 344 | } while (pgd++, addr = next, addr != end); |
437 | } | 345 | } |
438 | 346 | ||
439 | void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, | ||
440 | pte_t *ptep, pte_t pte) | ||
441 | { | ||
442 | if (pte_present(*ptep)) { | ||
443 | /* We open-code pte_clear because we need to pass the right | ||
444 | * argument to hpte_need_flush (huge / !huge). Might not be | ||
445 | * necessary anymore if we make hpte_need_flush() get the | ||
446 | * page size from the slices | ||
447 | */ | ||
448 | unsigned int psize = get_slice_psize(mm, addr); | ||
449 | unsigned int shift = mmu_psize_to_shift(psize); | ||
450 | unsigned long sz = ((1UL) << shift); | ||
451 | struct hstate *hstate = size_to_hstate(sz); | ||
452 | pte_update(mm, addr & hstate->mask, ptep, ~0UL, 1); | ||
453 | } | ||
454 | *ptep = __pte(pte_val(pte) & ~_PAGE_HPTEFLAGS); | ||
455 | } | ||
456 | |||
457 | pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, | ||
458 | pte_t *ptep) | ||
459 | { | ||
460 | unsigned long old = pte_update(mm, addr, ptep, ~0UL, 1); | ||
461 | return __pte(old); | ||
462 | } | ||
463 | |||
464 | struct page * | 347 | struct page * |
465 | follow_huge_addr(struct mm_struct *mm, unsigned long address, int write) | 348 | follow_huge_addr(struct mm_struct *mm, unsigned long address, int write) |
466 | { | 349 | { |
467 | pte_t *ptep; | 350 | pte_t *ptep; |
468 | struct page *page; | 351 | struct page *page; |
469 | unsigned int mmu_psize = get_slice_psize(mm, address); | 352 | unsigned shift; |
353 | unsigned long mask; | ||
354 | |||
355 | ptep = find_linux_pte_or_hugepte(mm->pgd, address, &shift); | ||
470 | 356 | ||
471 | /* Verify it is a huge page else bail. */ | 357 | /* Verify it is a huge page else bail. */ |
472 | if (!mmu_huge_psizes[mmu_psize]) | 358 | if (!ptep || !shift) |
473 | return ERR_PTR(-EINVAL); | 359 | return ERR_PTR(-EINVAL); |
474 | 360 | ||
475 | ptep = huge_pte_offset(mm, address); | 361 | mask = (1UL << shift) - 1; |
476 | page = pte_page(*ptep); | 362 | page = pte_page(*ptep); |
477 | if (page) { | 363 | if (page) |
478 | unsigned int shift = mmu_psize_to_shift(mmu_psize); | 364 | page += (address & mask) / PAGE_SIZE; |
479 | unsigned long sz = ((1UL) << shift); | ||
480 | page += (address % sz) / PAGE_SIZE; | ||
481 | } | ||
482 | 365 | ||
483 | return page; | 366 | return page; |
484 | } | 367 | } |
@@ -501,6 +384,82 @@ follow_huge_pmd(struct mm_struct *mm, unsigned long address, | |||
501 | return NULL; | 384 | return NULL; |
502 | } | 385 | } |
503 | 386 | ||
387 | static noinline int gup_hugepte(pte_t *ptep, unsigned long sz, unsigned long addr, | ||
388 | unsigned long end, int write, struct page **pages, int *nr) | ||
389 | { | ||
390 | unsigned long mask; | ||
391 | unsigned long pte_end; | ||
392 | struct page *head, *page; | ||
393 | pte_t pte; | ||
394 | int refs; | ||
395 | |||
396 | pte_end = (addr + sz) & ~(sz-1); | ||
397 | if (pte_end < end) | ||
398 | end = pte_end; | ||
399 | |||
400 | pte = *ptep; | ||
401 | mask = _PAGE_PRESENT | _PAGE_USER; | ||
402 | if (write) | ||
403 | mask |= _PAGE_RW; | ||
404 | |||
405 | if ((pte_val(pte) & mask) != mask) | ||
406 | return 0; | ||
407 | |||
408 | /* hugepages are never "special" */ | ||
409 | VM_BUG_ON(!pfn_valid(pte_pfn(pte))); | ||
410 | |||
411 | refs = 0; | ||
412 | head = pte_page(pte); | ||
413 | |||
414 | page = head + ((addr & (sz-1)) >> PAGE_SHIFT); | ||
415 | do { | ||
416 | VM_BUG_ON(compound_head(page) != head); | ||
417 | pages[*nr] = page; | ||
418 | (*nr)++; | ||
419 | page++; | ||
420 | refs++; | ||
421 | } while (addr += PAGE_SIZE, addr != end); | ||
422 | |||
423 | if (!page_cache_add_speculative(head, refs)) { | ||
424 | *nr -= refs; | ||
425 | return 0; | ||
426 | } | ||
427 | |||
428 | if (unlikely(pte_val(pte) != pte_val(*ptep))) { | ||
429 | /* Could be optimized better */ | ||
430 | while (*nr) { | ||
431 | put_page(page); | ||
432 | (*nr)--; | ||
433 | } | ||
434 | } | ||
435 | |||
436 | return 1; | ||
437 | } | ||
438 | |||
439 | static unsigned long hugepte_addr_end(unsigned long addr, unsigned long end, | ||
440 | unsigned long sz) | ||
441 | { | ||
442 | unsigned long __boundary = (addr + sz) & ~(sz-1); | ||
443 | return (__boundary - 1 < end - 1) ? __boundary : end; | ||
444 | } | ||
445 | |||
446 | int gup_hugepd(hugepd_t *hugepd, unsigned pdshift, | ||
447 | unsigned long addr, unsigned long end, | ||
448 | int write, struct page **pages, int *nr) | ||
449 | { | ||
450 | pte_t *ptep; | ||
451 | unsigned long sz = 1UL << hugepd_shift(*hugepd); | ||
452 | unsigned long next; | ||
453 | |||
454 | ptep = hugepte_offset(hugepd, addr, pdshift); | ||
455 | do { | ||
456 | next = hugepte_addr_end(addr, end, sz); | ||
457 | if (!gup_hugepte(ptep, sz, addr, end, write, pages, nr)) | ||
458 | return 0; | ||
459 | } while (ptep++, addr = next, addr != end); | ||
460 | |||
461 | return 1; | ||
462 | } | ||
504 | 463 | ||
505 | unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, | 464 | unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, |
506 | unsigned long len, unsigned long pgoff, | 465 | unsigned long len, unsigned long pgoff, |
@@ -509,8 +468,6 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, | |||
509 | struct hstate *hstate = hstate_file(file); | 468 | struct hstate *hstate = hstate_file(file); |
510 | int mmu_psize = shift_to_mmu_psize(huge_page_shift(hstate)); | 469 | int mmu_psize = shift_to_mmu_psize(huge_page_shift(hstate)); |
511 | 470 | ||
512 | if (!mmu_huge_psizes[mmu_psize]) | ||
513 | return -EINVAL; | ||
514 | return slice_get_unmapped_area(addr, len, flags, mmu_psize, 1, 0); | 471 | return slice_get_unmapped_area(addr, len, flags, mmu_psize, 1, 0); |
515 | } | 472 | } |
516 | 473 | ||
@@ -521,229 +478,46 @@ unsigned long vma_mmu_pagesize(struct vm_area_struct *vma) | |||
521 | return 1UL << mmu_psize_to_shift(psize); | 478 | return 1UL << mmu_psize_to_shift(psize); |
522 | } | 479 | } |
523 | 480 | ||
524 | /* | 481 | static int __init add_huge_page_size(unsigned long long size) |
525 | * Called by asm hashtable.S for doing lazy icache flush | ||
526 | */ | ||
527 | static unsigned int hash_huge_page_do_lazy_icache(unsigned long rflags, | ||
528 | pte_t pte, int trap, unsigned long sz) | ||
529 | { | 482 | { |
530 | struct page *page; | 483 | int shift = __ffs(size); |
531 | int i; | 484 | int mmu_psize; |
532 | |||
533 | if (!pfn_valid(pte_pfn(pte))) | ||
534 | return rflags; | ||
535 | |||
536 | page = pte_page(pte); | ||
537 | |||
538 | /* page is dirty */ | ||
539 | if (!test_bit(PG_arch_1, &page->flags) && !PageReserved(page)) { | ||
540 | if (trap == 0x400) { | ||
541 | for (i = 0; i < (sz / PAGE_SIZE); i++) | ||
542 | __flush_dcache_icache(page_address(page+i)); | ||
543 | set_bit(PG_arch_1, &page->flags); | ||
544 | } else { | ||
545 | rflags |= HPTE_R_N; | ||
546 | } | ||
547 | } | ||
548 | return rflags; | ||
549 | } | ||
550 | 485 | ||
551 | int hash_huge_page(struct mm_struct *mm, unsigned long access, | 486 | /* Check that it is a page size supported by the hardware and |
552 | unsigned long ea, unsigned long vsid, int local, | 487 | * that it fits within pagetable and slice limits. */ |
553 | unsigned long trap) | 488 | if (!is_power_of_2(size) |
554 | { | 489 | || (shift > SLICE_HIGH_SHIFT) || (shift <= PAGE_SHIFT)) |
555 | pte_t *ptep; | 490 | return -EINVAL; |
556 | unsigned long old_pte, new_pte; | ||
557 | unsigned long va, rflags, pa, sz; | ||
558 | long slot; | ||
559 | int err = 1; | ||
560 | int ssize = user_segment_size(ea); | ||
561 | unsigned int mmu_psize; | ||
562 | int shift; | ||
563 | mmu_psize = get_slice_psize(mm, ea); | ||
564 | |||
565 | if (!mmu_huge_psizes[mmu_psize]) | ||
566 | goto out; | ||
567 | ptep = huge_pte_offset(mm, ea); | ||
568 | |||
569 | /* Search the Linux page table for a match with va */ | ||
570 | va = hpt_va(ea, vsid, ssize); | ||
571 | 491 | ||
572 | /* | 492 | if ((mmu_psize = shift_to_mmu_psize(shift)) < 0) |
573 | * If no pte found or not present, send the problem up to | 493 | return -EINVAL; |
574 | * do_page_fault | ||
575 | */ | ||
576 | if (unlikely(!ptep || pte_none(*ptep))) | ||
577 | goto out; | ||
578 | 494 | ||
579 | /* | 495 | #ifdef CONFIG_SPU_FS_64K_LS |
580 | * Check the user's access rights to the page. If access should be | 496 | /* Disable support for 64K huge pages when 64K SPU local store |
581 | * prevented then send the problem up to do_page_fault. | 497 | * support is enabled as the current implementation conflicts. |
582 | */ | 498 | */ |
583 | if (unlikely(access & ~pte_val(*ptep))) | 499 | if (shift == PAGE_SHIFT_64K) |
584 | goto out; | 500 | return -EINVAL; |
585 | /* | 501 | #endif /* CONFIG_SPU_FS_64K_LS */ |
586 | * At this point, we have a pte (old_pte) which can be used to build | ||
587 | * or update an HPTE. There are 2 cases: | ||
588 | * | ||
589 | * 1. There is a valid (present) pte with no associated HPTE (this is | ||
590 | * the most common case) | ||
591 | * 2. There is a valid (present) pte with an associated HPTE. The | ||
592 | * current values of the pp bits in the HPTE prevent access | ||
593 | * because we are doing software DIRTY bit management and the | ||
594 | * page is currently not DIRTY. | ||
595 | */ | ||
596 | |||
597 | |||
598 | do { | ||
599 | old_pte = pte_val(*ptep); | ||
600 | if (old_pte & _PAGE_BUSY) | ||
601 | goto out; | ||
602 | new_pte = old_pte | _PAGE_BUSY | _PAGE_ACCESSED; | ||
603 | } while(old_pte != __cmpxchg_u64((unsigned long *)ptep, | ||
604 | old_pte, new_pte)); | ||
605 | |||
606 | rflags = 0x2 | (!(new_pte & _PAGE_RW)); | ||
607 | /* _PAGE_EXEC -> HW_NO_EXEC since it's inverted */ | ||
608 | rflags |= ((new_pte & _PAGE_EXEC) ? 0 : HPTE_R_N); | ||
609 | shift = mmu_psize_to_shift(mmu_psize); | ||
610 | sz = ((1UL) << shift); | ||
611 | if (!cpu_has_feature(CPU_FTR_COHERENT_ICACHE)) | ||
612 | /* No CPU has hugepages but lacks no execute, so we | ||
613 | * don't need to worry about that case */ | ||
614 | rflags = hash_huge_page_do_lazy_icache(rflags, __pte(old_pte), | ||
615 | trap, sz); | ||
616 | |||
617 | /* Check if pte already has an hpte (case 2) */ | ||
618 | if (unlikely(old_pte & _PAGE_HASHPTE)) { | ||
619 | /* There MIGHT be an HPTE for this pte */ | ||
620 | unsigned long hash, slot; | ||
621 | |||
622 | hash = hpt_hash(va, shift, ssize); | ||
623 | if (old_pte & _PAGE_F_SECOND) | ||
624 | hash = ~hash; | ||
625 | slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; | ||
626 | slot += (old_pte & _PAGE_F_GIX) >> 12; | ||
627 | |||
628 | if (ppc_md.hpte_updatepp(slot, rflags, va, mmu_psize, | ||
629 | ssize, local) == -1) | ||
630 | old_pte &= ~_PAGE_HPTEFLAGS; | ||
631 | } | ||
632 | |||
633 | if (likely(!(old_pte & _PAGE_HASHPTE))) { | ||
634 | unsigned long hash = hpt_hash(va, shift, ssize); | ||
635 | unsigned long hpte_group; | ||
636 | |||
637 | pa = pte_pfn(__pte(old_pte)) << PAGE_SHIFT; | ||
638 | |||
639 | repeat: | ||
640 | hpte_group = ((hash & htab_hash_mask) * | ||
641 | HPTES_PER_GROUP) & ~0x7UL; | ||
642 | |||
643 | /* clear HPTE slot informations in new PTE */ | ||
644 | #ifdef CONFIG_PPC_64K_PAGES | ||
645 | new_pte = (new_pte & ~_PAGE_HPTEFLAGS) | _PAGE_HPTE_SUB0; | ||
646 | #else | ||
647 | new_pte = (new_pte & ~_PAGE_HPTEFLAGS) | _PAGE_HASHPTE; | ||
648 | #endif | ||
649 | /* Add in WIMG bits */ | ||
650 | rflags |= (new_pte & (_PAGE_WRITETHRU | _PAGE_NO_CACHE | | ||
651 | _PAGE_COHERENT | _PAGE_GUARDED)); | ||
652 | |||
653 | /* Insert into the hash table, primary slot */ | ||
654 | slot = ppc_md.hpte_insert(hpte_group, va, pa, rflags, 0, | ||
655 | mmu_psize, ssize); | ||
656 | |||
657 | /* Primary is full, try the secondary */ | ||
658 | if (unlikely(slot == -1)) { | ||
659 | hpte_group = ((~hash & htab_hash_mask) * | ||
660 | HPTES_PER_GROUP) & ~0x7UL; | ||
661 | slot = ppc_md.hpte_insert(hpte_group, va, pa, rflags, | ||
662 | HPTE_V_SECONDARY, | ||
663 | mmu_psize, ssize); | ||
664 | if (slot == -1) { | ||
665 | if (mftb() & 0x1) | ||
666 | hpte_group = ((hash & htab_hash_mask) * | ||
667 | HPTES_PER_GROUP)&~0x7UL; | ||
668 | |||
669 | ppc_md.hpte_remove(hpte_group); | ||
670 | goto repeat; | ||
671 | } | ||
672 | } | ||
673 | |||
674 | if (unlikely(slot == -2)) | ||
675 | panic("hash_huge_page: pte_insert failed\n"); | ||
676 | |||
677 | new_pte |= (slot << 12) & (_PAGE_F_SECOND | _PAGE_F_GIX); | ||
678 | } | ||
679 | 502 | ||
680 | /* | 503 | BUG_ON(mmu_psize_defs[mmu_psize].shift != shift); |
681 | * No need to use ldarx/stdcx here | ||
682 | */ | ||
683 | *ptep = __pte(new_pte & ~_PAGE_BUSY); | ||
684 | 504 | ||
685 | err = 0; | 505 | /* Return if huge page size has already been setup */ |
506 | if (size_to_hstate(size)) | ||
507 | return 0; | ||
686 | 508 | ||
687 | out: | 509 | hugetlb_add_hstate(shift - PAGE_SHIFT); |
688 | return err; | ||
689 | } | ||
690 | 510 | ||
691 | static void __init set_huge_psize(int psize) | 511 | return 0; |
692 | { | ||
693 | /* Check that it is a page size supported by the hardware and | ||
694 | * that it fits within pagetable limits. */ | ||
695 | if (mmu_psize_defs[psize].shift && | ||
696 | mmu_psize_defs[psize].shift < SID_SHIFT_1T && | ||
697 | (mmu_psize_defs[psize].shift > MIN_HUGEPTE_SHIFT || | ||
698 | mmu_psize_defs[psize].shift == PAGE_SHIFT_64K || | ||
699 | mmu_psize_defs[psize].shift == PAGE_SHIFT_16G)) { | ||
700 | /* Return if huge page size has already been setup or is the | ||
701 | * same as the base page size. */ | ||
702 | if (mmu_huge_psizes[psize] || | ||
703 | mmu_psize_defs[psize].shift == PAGE_SHIFT) | ||
704 | return; | ||
705 | if (WARN_ON(HUGEPTE_CACHE_NAME(psize) == NULL)) | ||
706 | return; | ||
707 | hugetlb_add_hstate(mmu_psize_defs[psize].shift - PAGE_SHIFT); | ||
708 | |||
709 | switch (mmu_psize_defs[psize].shift) { | ||
710 | case PAGE_SHIFT_64K: | ||
711 | /* We only allow 64k hpages with 4k base page, | ||
712 | * which was checked above, and always put them | ||
713 | * at the PMD */ | ||
714 | hugepte_shift[psize] = PMD_SHIFT; | ||
715 | break; | ||
716 | case PAGE_SHIFT_16M: | ||
717 | /* 16M pages can be at two different levels | ||
718 | * of pagestables based on base page size */ | ||
719 | if (PAGE_SHIFT == PAGE_SHIFT_64K) | ||
720 | hugepte_shift[psize] = PMD_SHIFT; | ||
721 | else /* 4k base page */ | ||
722 | hugepte_shift[psize] = PUD_SHIFT; | ||
723 | break; | ||
724 | case PAGE_SHIFT_16G: | ||
725 | /* 16G pages are always at PGD level */ | ||
726 | hugepte_shift[psize] = PGDIR_SHIFT; | ||
727 | break; | ||
728 | } | ||
729 | hugepte_shift[psize] -= mmu_psize_defs[psize].shift; | ||
730 | } else | ||
731 | hugepte_shift[psize] = 0; | ||
732 | } | 512 | } |
733 | 513 | ||
734 | static int __init hugepage_setup_sz(char *str) | 514 | static int __init hugepage_setup_sz(char *str) |
735 | { | 515 | { |
736 | unsigned long long size; | 516 | unsigned long long size; |
737 | int mmu_psize; | ||
738 | int shift; | ||
739 | 517 | ||
740 | size = memparse(str, &str); | 518 | size = memparse(str, &str); |
741 | 519 | ||
742 | shift = __ffs(size); | 520 | if (add_huge_page_size(size) != 0) |
743 | mmu_psize = shift_to_mmu_psize(shift); | ||
744 | if (mmu_psize >= 0 && mmu_psize_defs[mmu_psize].shift) | ||
745 | set_huge_psize(mmu_psize); | ||
746 | else | ||
747 | printk(KERN_WARNING "Invalid huge page size specified(%llu)\n", size); | 521 | printk(KERN_WARNING "Invalid huge page size specified(%llu)\n", size); |
748 | 522 | ||
749 | return 1; | 523 | return 1; |
@@ -752,41 +526,55 @@ __setup("hugepagesz=", hugepage_setup_sz); | |||
752 | 526 | ||
753 | static int __init hugetlbpage_init(void) | 527 | static int __init hugetlbpage_init(void) |
754 | { | 528 | { |
755 | unsigned int psize; | 529 | int psize; |
756 | 530 | ||
757 | if (!cpu_has_feature(CPU_FTR_16M_PAGE)) | 531 | if (!cpu_has_feature(CPU_FTR_16M_PAGE)) |
758 | return -ENODEV; | 532 | return -ENODEV; |
759 | 533 | ||
760 | /* Add supported huge page sizes. Need to change HUGE_MAX_HSTATE | 534 | for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) { |
761 | * and adjust PTE_NONCACHE_NUM if the number of supported huge page | 535 | unsigned shift; |
762 | * sizes changes. | 536 | unsigned pdshift; |
763 | */ | ||
764 | set_huge_psize(MMU_PAGE_16M); | ||
765 | set_huge_psize(MMU_PAGE_16G); | ||
766 | 537 | ||
767 | /* Temporarily disable support for 64K huge pages when 64K SPU local | 538 | if (!mmu_psize_defs[psize].shift) |
768 | * store support is enabled as the current implementation conflicts. | 539 | continue; |
769 | */ | ||
770 | #ifndef CONFIG_SPU_FS_64K_LS | ||
771 | set_huge_psize(MMU_PAGE_64K); | ||
772 | #endif | ||
773 | 540 | ||
774 | for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) { | 541 | shift = mmu_psize_to_shift(psize); |
775 | if (mmu_huge_psizes[psize]) { | 542 | |
776 | pgtable_cache[HUGE_PGTABLE_INDEX(psize)] = | 543 | if (add_huge_page_size(1ULL << shift) < 0) |
777 | kmem_cache_create( | 544 | continue; |
778 | HUGEPTE_CACHE_NAME(psize), | 545 | |
779 | HUGEPTE_TABLE_SIZE(psize), | 546 | if (shift < PMD_SHIFT) |
780 | HUGEPTE_TABLE_SIZE(psize), | 547 | pdshift = PMD_SHIFT; |
781 | 0, | 548 | else if (shift < PUD_SHIFT) |
782 | NULL); | 549 | pdshift = PUD_SHIFT; |
783 | if (!pgtable_cache[HUGE_PGTABLE_INDEX(psize)]) | 550 | else |
784 | panic("hugetlbpage_init(): could not create %s"\ | 551 | pdshift = PGDIR_SHIFT; |
785 | "\n", HUGEPTE_CACHE_NAME(psize)); | 552 | |
786 | } | 553 | pgtable_cache_add(pdshift - shift, NULL); |
554 | if (!PGT_CACHE(pdshift - shift)) | ||
555 | panic("hugetlbpage_init(): could not create " | ||
556 | "pgtable cache for %d bit pagesize\n", shift); | ||
787 | } | 557 | } |
788 | 558 | ||
559 | /* Set default large page size. Currently, we pick 16M or 1M | ||
560 | * depending on what is available | ||
561 | */ | ||
562 | if (mmu_psize_defs[MMU_PAGE_16M].shift) | ||
563 | HPAGE_SHIFT = mmu_psize_defs[MMU_PAGE_16M].shift; | ||
564 | else if (mmu_psize_defs[MMU_PAGE_1M].shift) | ||
565 | HPAGE_SHIFT = mmu_psize_defs[MMU_PAGE_1M].shift; | ||
566 | |||
789 | return 0; | 567 | return 0; |
790 | } | 568 | } |
791 | 569 | ||
792 | module_init(hugetlbpage_init); | 570 | module_init(hugetlbpage_init); |
571 | |||
572 | void flush_dcache_icache_hugepage(struct page *page) | ||
573 | { | ||
574 | int i; | ||
575 | |||
576 | BUG_ON(!PageCompound(page)); | ||
577 | |||
578 | for (i = 0; i < (1UL << compound_order(page)); i++) | ||
579 | __flush_dcache_icache(page_address(page+i)); | ||
580 | } | ||
diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c index 335c578b9cc3..776f28d02b6b 100644 --- a/arch/powerpc/mm/init_64.c +++ b/arch/powerpc/mm/init_64.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include <linux/module.h> | 41 | #include <linux/module.h> |
42 | #include <linux/poison.h> | 42 | #include <linux/poison.h> |
43 | #include <linux/lmb.h> | 43 | #include <linux/lmb.h> |
44 | #include <linux/hugetlb.h> | ||
44 | 45 | ||
45 | #include <asm/pgalloc.h> | 46 | #include <asm/pgalloc.h> |
46 | #include <asm/page.h> | 47 | #include <asm/page.h> |
@@ -119,30 +120,63 @@ static void pmd_ctor(void *addr) | |||
119 | memset(addr, 0, PMD_TABLE_SIZE); | 120 | memset(addr, 0, PMD_TABLE_SIZE); |
120 | } | 121 | } |
121 | 122 | ||
122 | static const unsigned int pgtable_cache_size[2] = { | 123 | struct kmem_cache *pgtable_cache[MAX_PGTABLE_INDEX_SIZE]; |
123 | PGD_TABLE_SIZE, PMD_TABLE_SIZE | 124 | |
124 | }; | 125 | /* |
125 | static const char *pgtable_cache_name[ARRAY_SIZE(pgtable_cache_size)] = { | 126 | * Create a kmem_cache() for pagetables. This is not used for PTE |
126 | #ifdef CONFIG_PPC_64K_PAGES | 127 | * pages - they're linked to struct page, come from the normal free |
127 | "pgd_cache", "pmd_cache", | 128 | * pages pool and have a different entry size (see real_pte_t) to |
128 | #else | 129 | * everything else. Caches created by this function are used for all |
129 | "pgd_cache", "pud_pmd_cache", | 130 | * the higher level pagetables, and for hugepage pagetables. |
130 | #endif /* CONFIG_PPC_64K_PAGES */ | 131 | */ |
131 | }; | 132 | void pgtable_cache_add(unsigned shift, void (*ctor)(void *)) |
132 | 133 | { | |
133 | #ifdef CONFIG_HUGETLB_PAGE | 134 | char *name; |
134 | /* Hugepages need an extra cache per hugepagesize, initialized in | 135 | unsigned long table_size = sizeof(void *) << shift; |
135 | * hugetlbpage.c. We can't put into the tables above, because HPAGE_SHIFT | 136 | unsigned long align = table_size; |
136 | * is not compile time constant. */ | 137 | |
137 | struct kmem_cache *pgtable_cache[ARRAY_SIZE(pgtable_cache_size)+MMU_PAGE_COUNT]; | 138 | /* When batching pgtable pointers for RCU freeing, we store |
138 | #else | 139 | * the index size in the low bits. Table alignment must be |
139 | struct kmem_cache *pgtable_cache[ARRAY_SIZE(pgtable_cache_size)]; | 140 | * big enough to fit it. |
140 | #endif | 141 | * |
142 | * Likewise, hugeapge pagetable pointers contain a (different) | ||
143 | * shift value in the low bits. All tables must be aligned so | ||
144 | * as to leave enough 0 bits in the address to contain it. */ | ||
145 | unsigned long minalign = max(MAX_PGTABLE_INDEX_SIZE + 1, | ||
146 | HUGEPD_SHIFT_MASK + 1); | ||
147 | struct kmem_cache *new; | ||
148 | |||
149 | /* It would be nice if this was a BUILD_BUG_ON(), but at the | ||
150 | * moment, gcc doesn't seem to recognize is_power_of_2 as a | ||
151 | * constant expression, so so much for that. */ | ||
152 | BUG_ON(!is_power_of_2(minalign)); | ||
153 | BUG_ON((shift < 1) || (shift > MAX_PGTABLE_INDEX_SIZE)); | ||
154 | |||
155 | if (PGT_CACHE(shift)) | ||
156 | return; /* Already have a cache of this size */ | ||
157 | |||
158 | align = max_t(unsigned long, align, minalign); | ||
159 | name = kasprintf(GFP_KERNEL, "pgtable-2^%d", shift); | ||
160 | new = kmem_cache_create(name, table_size, align, 0, ctor); | ||
161 | PGT_CACHE(shift) = new; | ||
162 | |||
163 | pr_debug("Allocated pgtable cache for order %d\n", shift); | ||
164 | } | ||
165 | |||
141 | 166 | ||
142 | void pgtable_cache_init(void) | 167 | void pgtable_cache_init(void) |
143 | { | 168 | { |
144 | pgtable_cache[0] = kmem_cache_create(pgtable_cache_name[0], PGD_TABLE_SIZE, PGD_TABLE_SIZE, SLAB_PANIC, pgd_ctor); | 169 | pgtable_cache_add(PGD_INDEX_SIZE, pgd_ctor); |
145 | pgtable_cache[1] = kmem_cache_create(pgtable_cache_name[1], PMD_TABLE_SIZE, PMD_TABLE_SIZE, SLAB_PANIC, pmd_ctor); | 170 | pgtable_cache_add(PMD_INDEX_SIZE, pmd_ctor); |
171 | if (!PGT_CACHE(PGD_INDEX_SIZE) || !PGT_CACHE(PMD_INDEX_SIZE)) | ||
172 | panic("Couldn't allocate pgtable caches"); | ||
173 | |||
174 | /* In all current configs, when the PUD index exists it's the | ||
175 | * same size as either the pgd or pmd index. Verify that the | ||
176 | * initialization above has also created a PUD cache. This | ||
177 | * will need re-examiniation if we add new possibilities for | ||
178 | * the pagetable layout. */ | ||
179 | BUG_ON(PUD_INDEX_SIZE && !PGT_CACHE(PUD_INDEX_SIZE)); | ||
146 | } | 180 | } |
147 | 181 | ||
148 | #ifdef CONFIG_SPARSEMEM_VMEMMAP | 182 | #ifdef CONFIG_SPARSEMEM_VMEMMAP |
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index 59736317bf0e..b9b152558f9c 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/pagemap.h> | 32 | #include <linux/pagemap.h> |
33 | #include <linux/suspend.h> | 33 | #include <linux/suspend.h> |
34 | #include <linux/lmb.h> | 34 | #include <linux/lmb.h> |
35 | #include <linux/hugetlb.h> | ||
35 | 36 | ||
36 | #include <asm/pgalloc.h> | 37 | #include <asm/pgalloc.h> |
37 | #include <asm/prom.h> | 38 | #include <asm/prom.h> |
@@ -417,18 +418,26 @@ EXPORT_SYMBOL(flush_dcache_page); | |||
417 | 418 | ||
418 | void flush_dcache_icache_page(struct page *page) | 419 | void flush_dcache_icache_page(struct page *page) |
419 | { | 420 | { |
421 | #ifdef CONFIG_HUGETLB_PAGE | ||
422 | if (PageCompound(page)) { | ||
423 | flush_dcache_icache_hugepage(page); | ||
424 | return; | ||
425 | } | ||
426 | #endif | ||
420 | #ifdef CONFIG_BOOKE | 427 | #ifdef CONFIG_BOOKE |
421 | void *start = kmap_atomic(page, KM_PPC_SYNC_ICACHE); | 428 | { |
422 | __flush_dcache_icache(start); | 429 | void *start = kmap_atomic(page, KM_PPC_SYNC_ICACHE); |
423 | kunmap_atomic(start, KM_PPC_SYNC_ICACHE); | 430 | __flush_dcache_icache(start); |
431 | kunmap_atomic(start, KM_PPC_SYNC_ICACHE); | ||
432 | } | ||
424 | #elif defined(CONFIG_8xx) || defined(CONFIG_PPC64) | 433 | #elif defined(CONFIG_8xx) || defined(CONFIG_PPC64) |
425 | /* On 8xx there is no need to kmap since highmem is not supported */ | 434 | /* On 8xx there is no need to kmap since highmem is not supported */ |
426 | __flush_dcache_icache(page_address(page)); | 435 | __flush_dcache_icache(page_address(page)); |
427 | #else | 436 | #else |
428 | __flush_dcache_icache_phys(page_to_pfn(page) << PAGE_SHIFT); | 437 | __flush_dcache_icache_phys(page_to_pfn(page) << PAGE_SHIFT); |
429 | #endif | 438 | #endif |
430 | |||
431 | } | 439 | } |
440 | |||
432 | void clear_user_page(void *page, unsigned long vaddr, struct page *pg) | 441 | void clear_user_page(void *page, unsigned long vaddr, struct page *pg) |
433 | { | 442 | { |
434 | clear_page(page); | 443 | clear_page(page); |
diff --git a/arch/powerpc/mm/mmu_context_hash64.c b/arch/powerpc/mm/mmu_context_hash64.c index dbeb86ac90cd..b910d37aea1a 100644 --- a/arch/powerpc/mm/mmu_context_hash64.c +++ b/arch/powerpc/mm/mmu_context_hash64.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/mm.h> | 18 | #include <linux/mm.h> |
19 | #include <linux/spinlock.h> | 19 | #include <linux/spinlock.h> |
20 | #include <linux/idr.h> | 20 | #include <linux/idr.h> |
21 | #include <linux/module.h> | ||
21 | 22 | ||
22 | #include <asm/mmu_context.h> | 23 | #include <asm/mmu_context.h> |
23 | 24 | ||
@@ -32,7 +33,7 @@ static DEFINE_IDR(mmu_context_idr); | |||
32 | #define NO_CONTEXT 0 | 33 | #define NO_CONTEXT 0 |
33 | #define MAX_CONTEXT ((1UL << 19) - 1) | 34 | #define MAX_CONTEXT ((1UL << 19) - 1) |
34 | 35 | ||
35 | int init_new_context(struct task_struct *tsk, struct mm_struct *mm) | 36 | int __init_new_context(void) |
36 | { | 37 | { |
37 | int index; | 38 | int index; |
38 | int err; | 39 | int err; |
@@ -57,22 +58,41 @@ again: | |||
57 | return -ENOMEM; | 58 | return -ENOMEM; |
58 | } | 59 | } |
59 | 60 | ||
61 | return index; | ||
62 | } | ||
63 | EXPORT_SYMBOL_GPL(__init_new_context); | ||
64 | |||
65 | int init_new_context(struct task_struct *tsk, struct mm_struct *mm) | ||
66 | { | ||
67 | int index; | ||
68 | |||
69 | index = __init_new_context(); | ||
70 | if (index < 0) | ||
71 | return index; | ||
72 | |||
60 | /* The old code would re-promote on fork, we don't do that | 73 | /* The old code would re-promote on fork, we don't do that |
61 | * when using slices as it could cause problem promoting slices | 74 | * when using slices as it could cause problem promoting slices |
62 | * that have been forced down to 4K | 75 | * that have been forced down to 4K |
63 | */ | 76 | */ |
64 | if (slice_mm_new_context(mm)) | 77 | if (slice_mm_new_context(mm)) |
65 | slice_set_user_psize(mm, mmu_virtual_psize); | 78 | slice_set_user_psize(mm, mmu_virtual_psize); |
79 | subpage_prot_init_new_context(mm); | ||
66 | mm->context.id = index; | 80 | mm->context.id = index; |
67 | 81 | ||
68 | return 0; | 82 | return 0; |
69 | } | 83 | } |
70 | 84 | ||
71 | void destroy_context(struct mm_struct *mm) | 85 | void __destroy_context(int context_id) |
72 | { | 86 | { |
73 | spin_lock(&mmu_context_lock); | 87 | spin_lock(&mmu_context_lock); |
74 | idr_remove(&mmu_context_idr, mm->context.id); | 88 | idr_remove(&mmu_context_idr, context_id); |
75 | spin_unlock(&mmu_context_lock); | 89 | spin_unlock(&mmu_context_lock); |
90 | } | ||
91 | EXPORT_SYMBOL_GPL(__destroy_context); | ||
76 | 92 | ||
93 | void destroy_context(struct mm_struct *mm) | ||
94 | { | ||
95 | __destroy_context(mm->context.id); | ||
96 | subpage_prot_free(mm); | ||
77 | mm->context.id = NO_CONTEXT; | 97 | mm->context.id = NO_CONTEXT; |
78 | } | 98 | } |
diff --git a/arch/powerpc/mm/mmu_decl.h b/arch/powerpc/mm/mmu_decl.h index d2e5321d5ea6..e27a990af42d 100644 --- a/arch/powerpc/mm/mmu_decl.h +++ b/arch/powerpc/mm/mmu_decl.h | |||
@@ -98,21 +98,10 @@ extern void _tlbia(void); | |||
98 | 98 | ||
99 | #ifdef CONFIG_PPC32 | 99 | #ifdef CONFIG_PPC32 |
100 | 100 | ||
101 | struct tlbcam { | ||
102 | u32 MAS0; | ||
103 | u32 MAS1; | ||
104 | u32 MAS2; | ||
105 | u32 MAS3; | ||
106 | u32 MAS7; | ||
107 | }; | ||
108 | |||
109 | extern void mapin_ram(void); | 101 | extern void mapin_ram(void); |
110 | extern int map_page(unsigned long va, phys_addr_t pa, int flags); | 102 | extern int map_page(unsigned long va, phys_addr_t pa, int flags); |
111 | extern void setbat(int index, unsigned long virt, phys_addr_t phys, | 103 | extern void setbat(int index, unsigned long virt, phys_addr_t phys, |
112 | unsigned int size, int flags); | 104 | unsigned int size, int flags); |
113 | extern void settlbcam(int index, unsigned long virt, phys_addr_t phys, | ||
114 | unsigned int size, int flags, unsigned int pid); | ||
115 | extern void invalidate_tlbcam_entry(int index); | ||
116 | 105 | ||
117 | extern int __map_without_bats; | 106 | extern int __map_without_bats; |
118 | extern unsigned long ioremap_base; | 107 | extern unsigned long ioremap_base; |
diff --git a/arch/powerpc/mm/pgtable.c b/arch/powerpc/mm/pgtable.c index 53040931de32..99df697c601a 100644 --- a/arch/powerpc/mm/pgtable.c +++ b/arch/powerpc/mm/pgtable.c | |||
@@ -49,12 +49,12 @@ struct pte_freelist_batch | |||
49 | { | 49 | { |
50 | struct rcu_head rcu; | 50 | struct rcu_head rcu; |
51 | unsigned int index; | 51 | unsigned int index; |
52 | pgtable_free_t tables[0]; | 52 | unsigned long tables[0]; |
53 | }; | 53 | }; |
54 | 54 | ||
55 | #define PTE_FREELIST_SIZE \ | 55 | #define PTE_FREELIST_SIZE \ |
56 | ((PAGE_SIZE - sizeof(struct pte_freelist_batch)) \ | 56 | ((PAGE_SIZE - sizeof(struct pte_freelist_batch)) \ |
57 | / sizeof(pgtable_free_t)) | 57 | / sizeof(unsigned long)) |
58 | 58 | ||
59 | static void pte_free_smp_sync(void *arg) | 59 | static void pte_free_smp_sync(void *arg) |
60 | { | 60 | { |
@@ -64,13 +64,13 @@ static void pte_free_smp_sync(void *arg) | |||
64 | /* This is only called when we are critically out of memory | 64 | /* This is only called when we are critically out of memory |
65 | * (and fail to get a page in pte_free_tlb). | 65 | * (and fail to get a page in pte_free_tlb). |
66 | */ | 66 | */ |
67 | static void pgtable_free_now(pgtable_free_t pgf) | 67 | static void pgtable_free_now(void *table, unsigned shift) |
68 | { | 68 | { |
69 | pte_freelist_forced_free++; | 69 | pte_freelist_forced_free++; |
70 | 70 | ||
71 | smp_call_function(pte_free_smp_sync, NULL, 1); | 71 | smp_call_function(pte_free_smp_sync, NULL, 1); |
72 | 72 | ||
73 | pgtable_free(pgf); | 73 | pgtable_free(table, shift); |
74 | } | 74 | } |
75 | 75 | ||
76 | static void pte_free_rcu_callback(struct rcu_head *head) | 76 | static void pte_free_rcu_callback(struct rcu_head *head) |
@@ -79,8 +79,12 @@ static void pte_free_rcu_callback(struct rcu_head *head) | |||
79 | container_of(head, struct pte_freelist_batch, rcu); | 79 | container_of(head, struct pte_freelist_batch, rcu); |
80 | unsigned int i; | 80 | unsigned int i; |
81 | 81 | ||
82 | for (i = 0; i < batch->index; i++) | 82 | for (i = 0; i < batch->index; i++) { |
83 | pgtable_free(batch->tables[i]); | 83 | void *table = (void *)(batch->tables[i] & ~MAX_PGTABLE_INDEX_SIZE); |
84 | unsigned shift = batch->tables[i] & MAX_PGTABLE_INDEX_SIZE; | ||
85 | |||
86 | pgtable_free(table, shift); | ||
87 | } | ||
84 | 88 | ||
85 | free_page((unsigned long)batch); | 89 | free_page((unsigned long)batch); |
86 | } | 90 | } |
@@ -91,25 +95,28 @@ static void pte_free_submit(struct pte_freelist_batch *batch) | |||
91 | call_rcu(&batch->rcu, pte_free_rcu_callback); | 95 | call_rcu(&batch->rcu, pte_free_rcu_callback); |
92 | } | 96 | } |
93 | 97 | ||
94 | void pgtable_free_tlb(struct mmu_gather *tlb, pgtable_free_t pgf) | 98 | void pgtable_free_tlb(struct mmu_gather *tlb, void *table, unsigned shift) |
95 | { | 99 | { |
96 | /* This is safe since tlb_gather_mmu has disabled preemption */ | 100 | /* This is safe since tlb_gather_mmu has disabled preemption */ |
97 | struct pte_freelist_batch **batchp = &__get_cpu_var(pte_freelist_cur); | 101 | struct pte_freelist_batch **batchp = &__get_cpu_var(pte_freelist_cur); |
102 | unsigned long pgf; | ||
98 | 103 | ||
99 | if (atomic_read(&tlb->mm->mm_users) < 2 || | 104 | if (atomic_read(&tlb->mm->mm_users) < 2 || |
100 | cpumask_equal(mm_cpumask(tlb->mm), cpumask_of(smp_processor_id()))){ | 105 | cpumask_equal(mm_cpumask(tlb->mm), cpumask_of(smp_processor_id()))){ |
101 | pgtable_free(pgf); | 106 | pgtable_free(table, shift); |
102 | return; | 107 | return; |
103 | } | 108 | } |
104 | 109 | ||
105 | if (*batchp == NULL) { | 110 | if (*batchp == NULL) { |
106 | *batchp = (struct pte_freelist_batch *)__get_free_page(GFP_ATOMIC); | 111 | *batchp = (struct pte_freelist_batch *)__get_free_page(GFP_ATOMIC); |
107 | if (*batchp == NULL) { | 112 | if (*batchp == NULL) { |
108 | pgtable_free_now(pgf); | 113 | pgtable_free_now(table, shift); |
109 | return; | 114 | return; |
110 | } | 115 | } |
111 | (*batchp)->index = 0; | 116 | (*batchp)->index = 0; |
112 | } | 117 | } |
118 | BUG_ON(shift > MAX_PGTABLE_INDEX_SIZE); | ||
119 | pgf = (unsigned long)table | shift; | ||
113 | (*batchp)->tables[(*batchp)->index++] = pgf; | 120 | (*batchp)->tables[(*batchp)->index++] = pgf; |
114 | if ((*batchp)->index == PTE_FREELIST_SIZE) { | 121 | if ((*batchp)->index == PTE_FREELIST_SIZE) { |
115 | pte_free_submit(*batchp); | 122 | pte_free_submit(*batchp); |
diff --git a/arch/powerpc/mm/subpage-prot.c b/arch/powerpc/mm/subpage-prot.c index 4cafc0c33d0a..a040b81e93bd 100644 --- a/arch/powerpc/mm/subpage-prot.c +++ b/arch/powerpc/mm/subpage-prot.c | |||
@@ -24,9 +24,9 @@ | |||
24 | * Also makes sure that the subpage_prot_table structure is | 24 | * Also makes sure that the subpage_prot_table structure is |
25 | * reinitialized for the next user. | 25 | * reinitialized for the next user. |
26 | */ | 26 | */ |
27 | void subpage_prot_free(pgd_t *pgd) | 27 | void subpage_prot_free(struct mm_struct *mm) |
28 | { | 28 | { |
29 | struct subpage_prot_table *spt = pgd_subpage_prot(pgd); | 29 | struct subpage_prot_table *spt = &mm->context.spt; |
30 | unsigned long i, j, addr; | 30 | unsigned long i, j, addr; |
31 | u32 **p; | 31 | u32 **p; |
32 | 32 | ||
@@ -51,6 +51,13 @@ void subpage_prot_free(pgd_t *pgd) | |||
51 | spt->maxaddr = 0; | 51 | spt->maxaddr = 0; |
52 | } | 52 | } |
53 | 53 | ||
54 | void subpage_prot_init_new_context(struct mm_struct *mm) | ||
55 | { | ||
56 | struct subpage_prot_table *spt = &mm->context.spt; | ||
57 | |||
58 | memset(spt, 0, sizeof(*spt)); | ||
59 | } | ||
60 | |||
54 | static void hpte_flush_range(struct mm_struct *mm, unsigned long addr, | 61 | static void hpte_flush_range(struct mm_struct *mm, unsigned long addr, |
55 | int npages) | 62 | int npages) |
56 | { | 63 | { |
@@ -87,7 +94,7 @@ static void hpte_flush_range(struct mm_struct *mm, unsigned long addr, | |||
87 | static void subpage_prot_clear(unsigned long addr, unsigned long len) | 94 | static void subpage_prot_clear(unsigned long addr, unsigned long len) |
88 | { | 95 | { |
89 | struct mm_struct *mm = current->mm; | 96 | struct mm_struct *mm = current->mm; |
90 | struct subpage_prot_table *spt = pgd_subpage_prot(mm->pgd); | 97 | struct subpage_prot_table *spt = &mm->context.spt; |
91 | u32 **spm, *spp; | 98 | u32 **spm, *spp; |
92 | int i, nw; | 99 | int i, nw; |
93 | unsigned long next, limit; | 100 | unsigned long next, limit; |
@@ -136,7 +143,7 @@ static void subpage_prot_clear(unsigned long addr, unsigned long len) | |||
136 | long sys_subpage_prot(unsigned long addr, unsigned long len, u32 __user *map) | 143 | long sys_subpage_prot(unsigned long addr, unsigned long len, u32 __user *map) |
137 | { | 144 | { |
138 | struct mm_struct *mm = current->mm; | 145 | struct mm_struct *mm = current->mm; |
139 | struct subpage_prot_table *spt = pgd_subpage_prot(mm->pgd); | 146 | struct subpage_prot_table *spt = &mm->context.spt; |
140 | u32 **spm, *spp; | 147 | u32 **spm, *spp; |
141 | int i, nw; | 148 | int i, nw; |
142 | unsigned long next, limit; | 149 | unsigned long next, limit; |
diff --git a/arch/powerpc/mm/tlb_hash64.c b/arch/powerpc/mm/tlb_hash64.c index 2b2f35f6985e..282d9306361f 100644 --- a/arch/powerpc/mm/tlb_hash64.c +++ b/arch/powerpc/mm/tlb_hash64.c | |||
@@ -53,11 +53,6 @@ void hpte_need_flush(struct mm_struct *mm, unsigned long addr, | |||
53 | 53 | ||
54 | i = batch->index; | 54 | i = batch->index; |
55 | 55 | ||
56 | /* We mask the address for the base page size. Huge pages will | ||
57 | * have applied their own masking already | ||
58 | */ | ||
59 | addr &= PAGE_MASK; | ||
60 | |||
61 | /* Get page size (maybe move back to caller). | 56 | /* Get page size (maybe move back to caller). |
62 | * | 57 | * |
63 | * NOTE: when using special 64K mappings in 4K environment like | 58 | * NOTE: when using special 64K mappings in 4K environment like |
@@ -75,6 +70,9 @@ void hpte_need_flush(struct mm_struct *mm, unsigned long addr, | |||
75 | } else | 70 | } else |
76 | psize = pte_pagesize_index(mm, addr, pte); | 71 | psize = pte_pagesize_index(mm, addr, pte); |
77 | 72 | ||
73 | /* Mask the address for the correct page size */ | ||
74 | addr &= ~((1UL << mmu_psize_defs[psize].shift) - 1); | ||
75 | |||
78 | /* Build full vaddr */ | 76 | /* Build full vaddr */ |
79 | if (!is_kernel_addr(addr)) { | 77 | if (!is_kernel_addr(addr)) { |
80 | ssize = user_segment_size(addr); | 78 | ssize = user_segment_size(addr); |
diff --git a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c index a6ce80566625..da9b20a63769 100644 --- a/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c +++ b/arch/powerpc/platforms/512x/mpc5121_ads_cpld.c | |||
@@ -79,7 +79,7 @@ cpld_unmask_irq(unsigned int irq) | |||
79 | } | 79 | } |
80 | 80 | ||
81 | static struct irq_chip cpld_pic = { | 81 | static struct irq_chip cpld_pic = { |
82 | .typename = " CPLD PIC ", | 82 | .name = " CPLD PIC ", |
83 | .mask = cpld_mask_irq, | 83 | .mask = cpld_mask_irq, |
84 | .ack = cpld_mask_irq, | 84 | .ack = cpld_mask_irq, |
85 | .unmask = cpld_unmask_irq, | 85 | .unmask = cpld_unmask_irq, |
@@ -132,7 +132,7 @@ static int | |||
132 | cpld_pic_host_map(struct irq_host *h, unsigned int virq, | 132 | cpld_pic_host_map(struct irq_host *h, unsigned int virq, |
133 | irq_hw_number_t hw) | 133 | irq_hw_number_t hw) |
134 | { | 134 | { |
135 | get_irq_desc(virq)->status |= IRQ_LEVEL; | 135 | irq_to_desc(virq)->status |= IRQ_LEVEL; |
136 | set_irq_chip_and_handler(virq, &cpld_pic, handle_level_irq); | 136 | set_irq_chip_and_handler(virq, &cpld_pic, handle_level_irq); |
137 | return 0; | 137 | return 0; |
138 | } | 138 | } |
diff --git a/arch/powerpc/platforms/52xx/Kconfig b/arch/powerpc/platforms/52xx/Kconfig index 8b8e9560a315..47ea1be1481b 100644 --- a/arch/powerpc/platforms/52xx/Kconfig +++ b/arch/powerpc/platforms/52xx/Kconfig | |||
@@ -62,3 +62,8 @@ config PPC_MPC5200_GPIO | |||
62 | select GENERIC_GPIO | 62 | select GENERIC_GPIO |
63 | help | 63 | help |
64 | Enable gpiolib support for mpc5200 based boards | 64 | Enable gpiolib support for mpc5200 based boards |
65 | |||
66 | config PPC_MPC5200_LPBFIFO | ||
67 | tristate "MPC5200 LocalPlus bus FIFO driver" | ||
68 | depends on PPC_MPC52xx | ||
69 | select PPC_BESTCOMM_GEN_BD | ||
diff --git a/arch/powerpc/platforms/52xx/Makefile b/arch/powerpc/platforms/52xx/Makefile index bfd4f52cf3dd..2bc8cd0c5cfc 100644 --- a/arch/powerpc/platforms/52xx/Makefile +++ b/arch/powerpc/platforms/52xx/Makefile | |||
@@ -15,3 +15,4 @@ ifeq ($(CONFIG_PPC_LITE5200),y) | |||
15 | endif | 15 | endif |
16 | 16 | ||
17 | obj-$(CONFIG_PPC_MPC5200_GPIO) += mpc52xx_gpio.o | 17 | obj-$(CONFIG_PPC_MPC5200_GPIO) += mpc52xx_gpio.o |
18 | obj-$(CONFIG_PPC_MPC5200_LPBFIFO) += mpc52xx_lpbfifo.o | ||
diff --git a/arch/powerpc/platforms/52xx/media5200.c b/arch/powerpc/platforms/52xx/media5200.c index 68e4f1696d14..cc0c854291d7 100644 --- a/arch/powerpc/platforms/52xx/media5200.c +++ b/arch/powerpc/platforms/52xx/media5200.c | |||
@@ -74,7 +74,7 @@ static void media5200_irq_mask(unsigned int virq) | |||
74 | } | 74 | } |
75 | 75 | ||
76 | static struct irq_chip media5200_irq_chip = { | 76 | static struct irq_chip media5200_irq_chip = { |
77 | .typename = "Media5200 FPGA", | 77 | .name = "Media5200 FPGA", |
78 | .unmask = media5200_irq_unmask, | 78 | .unmask = media5200_irq_unmask, |
79 | .mask = media5200_irq_mask, | 79 | .mask = media5200_irq_mask, |
80 | .mask_ack = media5200_irq_mask, | 80 | .mask_ack = media5200_irq_mask, |
@@ -114,7 +114,7 @@ void media5200_irq_cascade(unsigned int virq, struct irq_desc *desc) | |||
114 | static int media5200_irq_map(struct irq_host *h, unsigned int virq, | 114 | static int media5200_irq_map(struct irq_host *h, unsigned int virq, |
115 | irq_hw_number_t hw) | 115 | irq_hw_number_t hw) |
116 | { | 116 | { |
117 | struct irq_desc *desc = get_irq_desc(virq); | 117 | struct irq_desc *desc = irq_to_desc(virq); |
118 | 118 | ||
119 | pr_debug("%s: h=%p, virq=%i, hwirq=%i\n", __func__, h, virq, (int)hw); | 119 | pr_debug("%s: h=%p, virq=%i, hwirq=%i\n", __func__, h, virq, (int)hw); |
120 | set_irq_chip_data(virq, &media5200_irq); | 120 | set_irq_chip_data(virq, &media5200_irq); |
@@ -127,7 +127,7 @@ static int media5200_irq_map(struct irq_host *h, unsigned int virq, | |||
127 | } | 127 | } |
128 | 128 | ||
129 | static int media5200_irq_xlate(struct irq_host *h, struct device_node *ct, | 129 | static int media5200_irq_xlate(struct irq_host *h, struct device_node *ct, |
130 | u32 *intspec, unsigned int intsize, | 130 | const u32 *intspec, unsigned int intsize, |
131 | irq_hw_number_t *out_hwirq, | 131 | irq_hw_number_t *out_hwirq, |
132 | unsigned int *out_flags) | 132 | unsigned int *out_flags) |
133 | { | 133 | { |
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c index bfbcd418e690..6f8ebe1085b3 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_gpt.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_gpt.c | |||
@@ -16,8 +16,14 @@ | |||
16 | * output signals or measure input signals. | 16 | * output signals or measure input signals. |
17 | * | 17 | * |
18 | * This driver supports the GPIO and IRQ controller functions of the GPT | 18 | * This driver supports the GPIO and IRQ controller functions of the GPT |
19 | * device. Timer functions are not yet supported, nor is the watchdog | 19 | * device. Timer functions are not yet supported. |
20 | * timer. | 20 | * |
21 | * The timer gpt0 can be used as watchdog (wdt). If the wdt mode is used, | ||
22 | * this prevents the use of any gpt0 gpt function (i.e. they will fail with | ||
23 | * -EBUSY). Thus, the safety wdt function always has precedence over the gpt | ||
24 | * function. If the kernel has been compiled with CONFIG_WATCHDOG_NOWAYOUT, | ||
25 | * this means that gpt0 is locked in wdt mode until the next reboot - this | ||
26 | * may be a requirement in safety applications. | ||
21 | * | 27 | * |
22 | * To use the GPIO function, the following two properties must be added | 28 | * To use the GPIO function, the following two properties must be added |
23 | * to the device tree node for the gpt device (typically in the .dts file | 29 | * to the device tree node for the gpt device (typically in the .dts file |
@@ -46,17 +52,24 @@ | |||
46 | * the output mode. This driver does not change the output mode setting. | 52 | * the output mode. This driver does not change the output mode setting. |
47 | */ | 53 | */ |
48 | 54 | ||
55 | #include <linux/device.h> | ||
49 | #include <linux/irq.h> | 56 | #include <linux/irq.h> |
50 | #include <linux/interrupt.h> | 57 | #include <linux/interrupt.h> |
51 | #include <linux/io.h> | 58 | #include <linux/io.h> |
59 | #include <linux/list.h> | ||
60 | #include <linux/mutex.h> | ||
52 | #include <linux/of.h> | 61 | #include <linux/of.h> |
53 | #include <linux/of_platform.h> | 62 | #include <linux/of_platform.h> |
54 | #include <linux/of_gpio.h> | 63 | #include <linux/of_gpio.h> |
55 | #include <linux/kernel.h> | 64 | #include <linux/kernel.h> |
65 | #include <linux/watchdog.h> | ||
66 | #include <linux/miscdevice.h> | ||
67 | #include <linux/uaccess.h> | ||
68 | #include <asm/div64.h> | ||
56 | #include <asm/mpc52xx.h> | 69 | #include <asm/mpc52xx.h> |
57 | 70 | ||
58 | MODULE_DESCRIPTION("Freescale MPC52xx gpt driver"); | 71 | MODULE_DESCRIPTION("Freescale MPC52xx gpt driver"); |
59 | MODULE_AUTHOR("Sascha Hauer, Grant Likely"); | 72 | MODULE_AUTHOR("Sascha Hauer, Grant Likely, Albrecht Dreß"); |
60 | MODULE_LICENSE("GPL"); | 73 | MODULE_LICENSE("GPL"); |
61 | 74 | ||
62 | /** | 75 | /** |
@@ -66,18 +79,27 @@ MODULE_LICENSE("GPL"); | |||
66 | * @lock: spinlock to coordinate between different functions. | 79 | * @lock: spinlock to coordinate between different functions. |
67 | * @of_gc: of_gpio_chip instance structure; used when GPIO is enabled | 80 | * @of_gc: of_gpio_chip instance structure; used when GPIO is enabled |
68 | * @irqhost: Pointer to irq_host instance; used when IRQ mode is supported | 81 | * @irqhost: Pointer to irq_host instance; used when IRQ mode is supported |
82 | * @wdt_mode: only relevant for gpt0: bit 0 (MPC52xx_GPT_CAN_WDT) indicates | ||
83 | * if the gpt may be used as wdt, bit 1 (MPC52xx_GPT_IS_WDT) indicates | ||
84 | * if the timer is actively used as wdt which blocks gpt functions | ||
69 | */ | 85 | */ |
70 | struct mpc52xx_gpt_priv { | 86 | struct mpc52xx_gpt_priv { |
87 | struct list_head list; /* List of all GPT devices */ | ||
71 | struct device *dev; | 88 | struct device *dev; |
72 | struct mpc52xx_gpt __iomem *regs; | 89 | struct mpc52xx_gpt __iomem *regs; |
73 | spinlock_t lock; | 90 | spinlock_t lock; |
74 | struct irq_host *irqhost; | 91 | struct irq_host *irqhost; |
92 | u32 ipb_freq; | ||
93 | u8 wdt_mode; | ||
75 | 94 | ||
76 | #if defined(CONFIG_GPIOLIB) | 95 | #if defined(CONFIG_GPIOLIB) |
77 | struct of_gpio_chip of_gc; | 96 | struct of_gpio_chip of_gc; |
78 | #endif | 97 | #endif |
79 | }; | 98 | }; |
80 | 99 | ||
100 | LIST_HEAD(mpc52xx_gpt_list); | ||
101 | DEFINE_MUTEX(mpc52xx_gpt_list_mutex); | ||
102 | |||
81 | #define MPC52xx_GPT_MODE_MS_MASK (0x07) | 103 | #define MPC52xx_GPT_MODE_MS_MASK (0x07) |
82 | #define MPC52xx_GPT_MODE_MS_IC (0x01) | 104 | #define MPC52xx_GPT_MODE_MS_IC (0x01) |
83 | #define MPC52xx_GPT_MODE_MS_OC (0x02) | 105 | #define MPC52xx_GPT_MODE_MS_OC (0x02) |
@@ -88,15 +110,25 @@ struct mpc52xx_gpt_priv { | |||
88 | #define MPC52xx_GPT_MODE_GPIO_OUT_LOW (0x20) | 110 | #define MPC52xx_GPT_MODE_GPIO_OUT_LOW (0x20) |
89 | #define MPC52xx_GPT_MODE_GPIO_OUT_HIGH (0x30) | 111 | #define MPC52xx_GPT_MODE_GPIO_OUT_HIGH (0x30) |
90 | 112 | ||
113 | #define MPC52xx_GPT_MODE_COUNTER_ENABLE (0x1000) | ||
114 | #define MPC52xx_GPT_MODE_CONTINUOUS (0x0400) | ||
115 | #define MPC52xx_GPT_MODE_OPEN_DRAIN (0x0200) | ||
91 | #define MPC52xx_GPT_MODE_IRQ_EN (0x0100) | 116 | #define MPC52xx_GPT_MODE_IRQ_EN (0x0100) |
117 | #define MPC52xx_GPT_MODE_WDT_EN (0x8000) | ||
92 | 118 | ||
93 | #define MPC52xx_GPT_MODE_ICT_MASK (0x030000) | 119 | #define MPC52xx_GPT_MODE_ICT_MASK (0x030000) |
94 | #define MPC52xx_GPT_MODE_ICT_RISING (0x010000) | 120 | #define MPC52xx_GPT_MODE_ICT_RISING (0x010000) |
95 | #define MPC52xx_GPT_MODE_ICT_FALLING (0x020000) | 121 | #define MPC52xx_GPT_MODE_ICT_FALLING (0x020000) |
96 | #define MPC52xx_GPT_MODE_ICT_TOGGLE (0x030000) | 122 | #define MPC52xx_GPT_MODE_ICT_TOGGLE (0x030000) |
97 | 123 | ||
124 | #define MPC52xx_GPT_MODE_WDT_PING (0xa5) | ||
125 | |||
98 | #define MPC52xx_GPT_STATUS_IRQMASK (0x000f) | 126 | #define MPC52xx_GPT_STATUS_IRQMASK (0x000f) |
99 | 127 | ||
128 | #define MPC52xx_GPT_CAN_WDT (1 << 0) | ||
129 | #define MPC52xx_GPT_IS_WDT (1 << 1) | ||
130 | |||
131 | |||
100 | /* --------------------------------------------------------------------- | 132 | /* --------------------------------------------------------------------- |
101 | * Cascaded interrupt controller hooks | 133 | * Cascaded interrupt controller hooks |
102 | */ | 134 | */ |
@@ -149,7 +181,7 @@ static int mpc52xx_gpt_irq_set_type(unsigned int virq, unsigned int flow_type) | |||
149 | } | 181 | } |
150 | 182 | ||
151 | static struct irq_chip mpc52xx_gpt_irq_chip = { | 183 | static struct irq_chip mpc52xx_gpt_irq_chip = { |
152 | .typename = "MPC52xx GPT", | 184 | .name = "MPC52xx GPT", |
153 | .unmask = mpc52xx_gpt_irq_unmask, | 185 | .unmask = mpc52xx_gpt_irq_unmask, |
154 | .mask = mpc52xx_gpt_irq_mask, | 186 | .mask = mpc52xx_gpt_irq_mask, |
155 | .ack = mpc52xx_gpt_irq_ack, | 187 | .ack = mpc52xx_gpt_irq_ack, |
@@ -182,7 +214,7 @@ static int mpc52xx_gpt_irq_map(struct irq_host *h, unsigned int virq, | |||
182 | } | 214 | } |
183 | 215 | ||
184 | static int mpc52xx_gpt_irq_xlate(struct irq_host *h, struct device_node *ct, | 216 | static int mpc52xx_gpt_irq_xlate(struct irq_host *h, struct device_node *ct, |
185 | u32 *intspec, unsigned int intsize, | 217 | const u32 *intspec, unsigned int intsize, |
186 | irq_hw_number_t *out_hwirq, | 218 | irq_hw_number_t *out_hwirq, |
187 | unsigned int *out_flags) | 219 | unsigned int *out_flags) |
188 | { | 220 | { |
@@ -190,7 +222,7 @@ static int mpc52xx_gpt_irq_xlate(struct irq_host *h, struct device_node *ct, | |||
190 | 222 | ||
191 | dev_dbg(gpt->dev, "%s: flags=%i\n", __func__, intspec[0]); | 223 | dev_dbg(gpt->dev, "%s: flags=%i\n", __func__, intspec[0]); |
192 | 224 | ||
193 | if ((intsize < 1) || (intspec[0] < 1) || (intspec[0] > 3)) { | 225 | if ((intsize < 1) || (intspec[0] > 3)) { |
194 | dev_err(gpt->dev, "bad irq specifier in %s\n", ct->full_name); | 226 | dev_err(gpt->dev, "bad irq specifier in %s\n", ct->full_name); |
195 | return -EINVAL; | 227 | return -EINVAL; |
196 | } | 228 | } |
@@ -211,13 +243,11 @@ mpc52xx_gpt_irq_setup(struct mpc52xx_gpt_priv *gpt, struct device_node *node) | |||
211 | { | 243 | { |
212 | int cascade_virq; | 244 | int cascade_virq; |
213 | unsigned long flags; | 245 | unsigned long flags; |
214 | 246 | u32 mode; | |
215 | /* Only setup cascaded IRQ if device tree claims the GPT is | ||
216 | * an interrupt controller */ | ||
217 | if (!of_find_property(node, "interrupt-controller", NULL)) | ||
218 | return; | ||
219 | 247 | ||
220 | cascade_virq = irq_of_parse_and_map(node, 0); | 248 | cascade_virq = irq_of_parse_and_map(node, 0); |
249 | if (!cascade_virq) | ||
250 | return; | ||
221 | 251 | ||
222 | gpt->irqhost = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR, 1, | 252 | gpt->irqhost = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR, 1, |
223 | &mpc52xx_gpt_irq_ops, -1); | 253 | &mpc52xx_gpt_irq_ops, -1); |
@@ -227,14 +257,16 @@ mpc52xx_gpt_irq_setup(struct mpc52xx_gpt_priv *gpt, struct device_node *node) | |||
227 | } | 257 | } |
228 | 258 | ||
229 | gpt->irqhost->host_data = gpt; | 259 | gpt->irqhost->host_data = gpt; |
230 | |||
231 | set_irq_data(cascade_virq, gpt); | 260 | set_irq_data(cascade_virq, gpt); |
232 | set_irq_chained_handler(cascade_virq, mpc52xx_gpt_irq_cascade); | 261 | set_irq_chained_handler(cascade_virq, mpc52xx_gpt_irq_cascade); |
233 | 262 | ||
234 | /* Set to Input Capture mode */ | 263 | /* If the GPT is currently disabled, then change it to be in Input |
264 | * Capture mode. If the mode is non-zero, then the pin could be | ||
265 | * already in use for something. */ | ||
235 | spin_lock_irqsave(&gpt->lock, flags); | 266 | spin_lock_irqsave(&gpt->lock, flags); |
236 | clrsetbits_be32(&gpt->regs->mode, MPC52xx_GPT_MODE_MS_MASK, | 267 | mode = in_be32(&gpt->regs->mode); |
237 | MPC52xx_GPT_MODE_MS_IC); | 268 | if ((mode & MPC52xx_GPT_MODE_MS_MASK) == 0) |
269 | out_be32(&gpt->regs->mode, mode | MPC52xx_GPT_MODE_MS_IC); | ||
238 | spin_unlock_irqrestore(&gpt->lock, flags); | 270 | spin_unlock_irqrestore(&gpt->lock, flags); |
239 | 271 | ||
240 | dev_dbg(gpt->dev, "%s() complete. virq=%i\n", __func__, cascade_virq); | 272 | dev_dbg(gpt->dev, "%s() complete. virq=%i\n", __func__, cascade_virq); |
@@ -335,6 +367,354 @@ static void | |||
335 | mpc52xx_gpt_gpio_setup(struct mpc52xx_gpt_priv *p, struct device_node *np) { } | 367 | mpc52xx_gpt_gpio_setup(struct mpc52xx_gpt_priv *p, struct device_node *np) { } |
336 | #endif /* defined(CONFIG_GPIOLIB) */ | 368 | #endif /* defined(CONFIG_GPIOLIB) */ |
337 | 369 | ||
370 | /*********************************************************************** | ||
371 | * Timer API | ||
372 | */ | ||
373 | |||
374 | /** | ||
375 | * mpc52xx_gpt_from_irq - Return the GPT device associated with an IRQ number | ||
376 | * @irq: irq of timer. | ||
377 | */ | ||
378 | struct mpc52xx_gpt_priv *mpc52xx_gpt_from_irq(int irq) | ||
379 | { | ||
380 | struct mpc52xx_gpt_priv *gpt; | ||
381 | struct list_head *pos; | ||
382 | |||
383 | /* Iterate over the list of timers looking for a matching device */ | ||
384 | mutex_lock(&mpc52xx_gpt_list_mutex); | ||
385 | list_for_each(pos, &mpc52xx_gpt_list) { | ||
386 | gpt = container_of(pos, struct mpc52xx_gpt_priv, list); | ||
387 | if (gpt->irqhost && irq == irq_linear_revmap(gpt->irqhost, 0)) { | ||
388 | mutex_unlock(&mpc52xx_gpt_list_mutex); | ||
389 | return gpt; | ||
390 | } | ||
391 | } | ||
392 | mutex_unlock(&mpc52xx_gpt_list_mutex); | ||
393 | |||
394 | return NULL; | ||
395 | } | ||
396 | EXPORT_SYMBOL(mpc52xx_gpt_from_irq); | ||
397 | |||
398 | static int mpc52xx_gpt_do_start(struct mpc52xx_gpt_priv *gpt, u64 period, | ||
399 | int continuous, int as_wdt) | ||
400 | { | ||
401 | u32 clear, set; | ||
402 | u64 clocks; | ||
403 | u32 prescale; | ||
404 | unsigned long flags; | ||
405 | |||
406 | clear = MPC52xx_GPT_MODE_MS_MASK | MPC52xx_GPT_MODE_CONTINUOUS; | ||
407 | set = MPC52xx_GPT_MODE_MS_GPIO | MPC52xx_GPT_MODE_COUNTER_ENABLE; | ||
408 | if (as_wdt) { | ||
409 | clear |= MPC52xx_GPT_MODE_IRQ_EN; | ||
410 | set |= MPC52xx_GPT_MODE_WDT_EN; | ||
411 | } else if (continuous) | ||
412 | set |= MPC52xx_GPT_MODE_CONTINUOUS; | ||
413 | |||
414 | /* Determine the number of clocks in the requested period. 64 bit | ||
415 | * arithmatic is done here to preserve the precision until the value | ||
416 | * is scaled back down into the u32 range. Period is in 'ns', bus | ||
417 | * frequency is in Hz. */ | ||
418 | clocks = period * (u64)gpt->ipb_freq; | ||
419 | do_div(clocks, 1000000000); /* Scale it down to ns range */ | ||
420 | |||
421 | /* This device cannot handle a clock count greater than 32 bits */ | ||
422 | if (clocks > 0xffffffff) | ||
423 | return -EINVAL; | ||
424 | |||
425 | /* Calculate the prescaler and count values from the clocks value. | ||
426 | * 'clocks' is the number of clock ticks in the period. The timer | ||
427 | * has 16 bit precision and a 16 bit prescaler. Prescaler is | ||
428 | * calculated by integer dividing the clocks by 0x10000 (shifting | ||
429 | * down 16 bits) to obtain the smallest possible divisor for clocks | ||
430 | * to get a 16 bit count value. | ||
431 | * | ||
432 | * Note: the prescale register is '1' based, not '0' based. ie. a | ||
433 | * value of '1' means divide the clock by one. 0xffff divides the | ||
434 | * clock by 0xffff. '0x0000' does not divide by zero, but wraps | ||
435 | * around and divides by 0x10000. That is why prescale must be | ||
436 | * a u32 variable, not a u16, for this calculation. */ | ||
437 | prescale = (clocks >> 16) + 1; | ||
438 | do_div(clocks, prescale); | ||
439 | if (clocks > 0xffff) { | ||
440 | pr_err("calculation error; prescale:%x clocks:%llx\n", | ||
441 | prescale, clocks); | ||
442 | return -EINVAL; | ||
443 | } | ||
444 | |||
445 | /* Set and enable the timer, reject an attempt to use a wdt as gpt */ | ||
446 | spin_lock_irqsave(&gpt->lock, flags); | ||
447 | if (as_wdt) | ||
448 | gpt->wdt_mode |= MPC52xx_GPT_IS_WDT; | ||
449 | else if ((gpt->wdt_mode & MPC52xx_GPT_IS_WDT) != 0) { | ||
450 | spin_unlock_irqrestore(&gpt->lock, flags); | ||
451 | return -EBUSY; | ||
452 | } | ||
453 | out_be32(&gpt->regs->count, prescale << 16 | clocks); | ||
454 | clrsetbits_be32(&gpt->regs->mode, clear, set); | ||
455 | spin_unlock_irqrestore(&gpt->lock, flags); | ||
456 | |||
457 | return 0; | ||
458 | } | ||
459 | |||
460 | /** | ||
461 | * mpc52xx_gpt_start_timer - Set and enable the GPT timer | ||
462 | * @gpt: Pointer to gpt private data structure | ||
463 | * @period: period of timer in ns; max. ~130s @ 33MHz IPB clock | ||
464 | * @continuous: set to 1 to make timer continuous free running | ||
465 | * | ||
466 | * An interrupt will be generated every time the timer fires | ||
467 | */ | ||
468 | int mpc52xx_gpt_start_timer(struct mpc52xx_gpt_priv *gpt, u64 period, | ||
469 | int continuous) | ||
470 | { | ||
471 | return mpc52xx_gpt_do_start(gpt, period, continuous, 0); | ||
472 | } | ||
473 | EXPORT_SYMBOL(mpc52xx_gpt_start_timer); | ||
474 | |||
475 | /** | ||
476 | * mpc52xx_gpt_stop_timer - Stop a gpt | ||
477 | * @gpt: Pointer to gpt private data structure | ||
478 | * | ||
479 | * Returns an error if attempting to stop a wdt | ||
480 | */ | ||
481 | int mpc52xx_gpt_stop_timer(struct mpc52xx_gpt_priv *gpt) | ||
482 | { | ||
483 | unsigned long flags; | ||
484 | |||
485 | /* reject the operation if the timer is used as watchdog (gpt 0 only) */ | ||
486 | spin_lock_irqsave(&gpt->lock, flags); | ||
487 | if ((gpt->wdt_mode & MPC52xx_GPT_IS_WDT) != 0) { | ||
488 | spin_unlock_irqrestore(&gpt->lock, flags); | ||
489 | return -EBUSY; | ||
490 | } | ||
491 | |||
492 | clrbits32(&gpt->regs->mode, MPC52xx_GPT_MODE_COUNTER_ENABLE); | ||
493 | spin_unlock_irqrestore(&gpt->lock, flags); | ||
494 | return 0; | ||
495 | } | ||
496 | EXPORT_SYMBOL(mpc52xx_gpt_stop_timer); | ||
497 | |||
498 | /** | ||
499 | * mpc52xx_gpt_timer_period - Read the timer period | ||
500 | * @gpt: Pointer to gpt private data structure | ||
501 | * | ||
502 | * Returns the timer period in ns | ||
503 | */ | ||
504 | u64 mpc52xx_gpt_timer_period(struct mpc52xx_gpt_priv *gpt) | ||
505 | { | ||
506 | u64 period; | ||
507 | u64 prescale; | ||
508 | unsigned long flags; | ||
509 | |||
510 | spin_lock_irqsave(&gpt->lock, flags); | ||
511 | period = in_be32(&gpt->regs->count); | ||
512 | spin_unlock_irqrestore(&gpt->lock, flags); | ||
513 | |||
514 | prescale = period >> 16; | ||
515 | period &= 0xffff; | ||
516 | if (prescale == 0) | ||
517 | prescale = 0x10000; | ||
518 | period = period * prescale * 1000000000ULL; | ||
519 | do_div(period, (u64)gpt->ipb_freq); | ||
520 | return period; | ||
521 | } | ||
522 | EXPORT_SYMBOL(mpc52xx_gpt_timer_period); | ||
523 | |||
524 | #if defined(CONFIG_MPC5200_WDT) | ||
525 | /*********************************************************************** | ||
526 | * Watchdog API for gpt0 | ||
527 | */ | ||
528 | |||
529 | #define WDT_IDENTITY "mpc52xx watchdog on GPT0" | ||
530 | |||
531 | /* wdt_is_active stores wether or not the /dev/watchdog device is opened */ | ||
532 | static unsigned long wdt_is_active; | ||
533 | |||
534 | /* wdt-capable gpt */ | ||
535 | static struct mpc52xx_gpt_priv *mpc52xx_gpt_wdt; | ||
536 | |||
537 | /* low-level wdt functions */ | ||
538 | static inline void mpc52xx_gpt_wdt_ping(struct mpc52xx_gpt_priv *gpt_wdt) | ||
539 | { | ||
540 | unsigned long flags; | ||
541 | |||
542 | spin_lock_irqsave(&gpt_wdt->lock, flags); | ||
543 | out_8((u8 *) &gpt_wdt->regs->mode, MPC52xx_GPT_MODE_WDT_PING); | ||
544 | spin_unlock_irqrestore(&gpt_wdt->lock, flags); | ||
545 | } | ||
546 | |||
547 | /* wdt misc device api */ | ||
548 | static ssize_t mpc52xx_wdt_write(struct file *file, const char __user *data, | ||
549 | size_t len, loff_t *ppos) | ||
550 | { | ||
551 | struct mpc52xx_gpt_priv *gpt_wdt = file->private_data; | ||
552 | mpc52xx_gpt_wdt_ping(gpt_wdt); | ||
553 | return 0; | ||
554 | } | ||
555 | |||
556 | static struct watchdog_info mpc5200_wdt_info = { | ||
557 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, | ||
558 | .identity = WDT_IDENTITY, | ||
559 | }; | ||
560 | |||
561 | static long mpc52xx_wdt_ioctl(struct file *file, unsigned int cmd, | ||
562 | unsigned long arg) | ||
563 | { | ||
564 | struct mpc52xx_gpt_priv *gpt_wdt = file->private_data; | ||
565 | int __user *data = (int __user *)arg; | ||
566 | int timeout; | ||
567 | u64 real_timeout; | ||
568 | int ret = 0; | ||
569 | |||
570 | switch (cmd) { | ||
571 | case WDIOC_GETSUPPORT: | ||
572 | ret = copy_to_user(data, &mpc5200_wdt_info, | ||
573 | sizeof(mpc5200_wdt_info)); | ||
574 | if (ret) | ||
575 | ret = -EFAULT; | ||
576 | break; | ||
577 | |||
578 | case WDIOC_GETSTATUS: | ||
579 | case WDIOC_GETBOOTSTATUS: | ||
580 | ret = put_user(0, data); | ||
581 | break; | ||
582 | |||
583 | case WDIOC_KEEPALIVE: | ||
584 | mpc52xx_gpt_wdt_ping(gpt_wdt); | ||
585 | break; | ||
586 | |||
587 | case WDIOC_SETTIMEOUT: | ||
588 | ret = get_user(timeout, data); | ||
589 | if (ret) | ||
590 | break; | ||
591 | real_timeout = (u64) timeout * 1000000000ULL; | ||
592 | ret = mpc52xx_gpt_do_start(gpt_wdt, real_timeout, 0, 1); | ||
593 | if (ret) | ||
594 | break; | ||
595 | /* fall through and return the timeout */ | ||
596 | |||
597 | case WDIOC_GETTIMEOUT: | ||
598 | /* we need to round here as to avoid e.g. the following | ||
599 | * situation: | ||
600 | * - timeout requested is 1 second; | ||
601 | * - real timeout @33MHz is 999997090ns | ||
602 | * - the int divide by 10^9 will return 0. | ||
603 | */ | ||
604 | real_timeout = | ||
605 | mpc52xx_gpt_timer_period(gpt_wdt) + 500000000ULL; | ||
606 | do_div(real_timeout, 1000000000ULL); | ||
607 | timeout = (int) real_timeout; | ||
608 | ret = put_user(timeout, data); | ||
609 | break; | ||
610 | |||
611 | default: | ||
612 | ret = -ENOTTY; | ||
613 | } | ||
614 | return ret; | ||
615 | } | ||
616 | |||
617 | static int mpc52xx_wdt_open(struct inode *inode, struct file *file) | ||
618 | { | ||
619 | int ret; | ||
620 | |||
621 | /* sanity check */ | ||
622 | if (!mpc52xx_gpt_wdt) | ||
623 | return -ENODEV; | ||
624 | |||
625 | /* /dev/watchdog can only be opened once */ | ||
626 | if (test_and_set_bit(0, &wdt_is_active)) | ||
627 | return -EBUSY; | ||
628 | |||
629 | /* Set and activate the watchdog with 30 seconds timeout */ | ||
630 | ret = mpc52xx_gpt_do_start(mpc52xx_gpt_wdt, 30ULL * 1000000000ULL, | ||
631 | 0, 1); | ||
632 | if (ret) { | ||
633 | clear_bit(0, &wdt_is_active); | ||
634 | return ret; | ||
635 | } | ||
636 | |||
637 | file->private_data = mpc52xx_gpt_wdt; | ||
638 | return nonseekable_open(inode, file); | ||
639 | } | ||
640 | |||
641 | static int mpc52xx_wdt_release(struct inode *inode, struct file *file) | ||
642 | { | ||
643 | /* note: releasing the wdt in NOWAYOUT-mode does not stop it */ | ||
644 | #if !defined(CONFIG_WATCHDOG_NOWAYOUT) | ||
645 | struct mpc52xx_gpt_priv *gpt_wdt = file->private_data; | ||
646 | unsigned long flags; | ||
647 | |||
648 | spin_lock_irqsave(&gpt_wdt->lock, flags); | ||
649 | clrbits32(&gpt_wdt->regs->mode, | ||
650 | MPC52xx_GPT_MODE_COUNTER_ENABLE | MPC52xx_GPT_MODE_WDT_EN); | ||
651 | gpt_wdt->wdt_mode &= ~MPC52xx_GPT_IS_WDT; | ||
652 | spin_unlock_irqrestore(&gpt_wdt->lock, flags); | ||
653 | #endif | ||
654 | clear_bit(0, &wdt_is_active); | ||
655 | return 0; | ||
656 | } | ||
657 | |||
658 | |||
659 | static const struct file_operations mpc52xx_wdt_fops = { | ||
660 | .owner = THIS_MODULE, | ||
661 | .llseek = no_llseek, | ||
662 | .write = mpc52xx_wdt_write, | ||
663 | .unlocked_ioctl = mpc52xx_wdt_ioctl, | ||
664 | .open = mpc52xx_wdt_open, | ||
665 | .release = mpc52xx_wdt_release, | ||
666 | }; | ||
667 | |||
668 | static struct miscdevice mpc52xx_wdt_miscdev = { | ||
669 | .minor = WATCHDOG_MINOR, | ||
670 | .name = "watchdog", | ||
671 | .fops = &mpc52xx_wdt_fops, | ||
672 | }; | ||
673 | |||
674 | static int __devinit mpc52xx_gpt_wdt_init(void) | ||
675 | { | ||
676 | int err; | ||
677 | |||
678 | /* try to register the watchdog misc device */ | ||
679 | err = misc_register(&mpc52xx_wdt_miscdev); | ||
680 | if (err) | ||
681 | pr_err("%s: cannot register watchdog device\n", WDT_IDENTITY); | ||
682 | else | ||
683 | pr_info("%s: watchdog device registered\n", WDT_IDENTITY); | ||
684 | return err; | ||
685 | } | ||
686 | |||
687 | static int mpc52xx_gpt_wdt_setup(struct mpc52xx_gpt_priv *gpt, | ||
688 | const u32 *period) | ||
689 | { | ||
690 | u64 real_timeout; | ||
691 | |||
692 | /* remember the gpt for the wdt operation */ | ||
693 | mpc52xx_gpt_wdt = gpt; | ||
694 | |||
695 | /* configure the wdt if the device tree contained a timeout */ | ||
696 | if (!period || *period == 0) | ||
697 | return 0; | ||
698 | |||
699 | real_timeout = (u64) *period * 1000000000ULL; | ||
700 | if (mpc52xx_gpt_do_start(gpt, real_timeout, 0, 1)) | ||
701 | dev_warn(gpt->dev, "starting as wdt failed\n"); | ||
702 | else | ||
703 | dev_info(gpt->dev, "watchdog set to %us timeout\n", *period); | ||
704 | return 0; | ||
705 | } | ||
706 | |||
707 | #else | ||
708 | |||
709 | static int __devinit mpc52xx_gpt_wdt_init(void) | ||
710 | { | ||
711 | return 0; | ||
712 | } | ||
713 | |||
714 | #define mpc52xx_gpt_wdt_setup(x, y) (0) | ||
715 | |||
716 | #endif /* CONFIG_MPC5200_WDT */ | ||
717 | |||
338 | /* --------------------------------------------------------------------- | 718 | /* --------------------------------------------------------------------- |
339 | * of_platform bus binding code | 719 | * of_platform bus binding code |
340 | */ | 720 | */ |
@@ -349,6 +729,7 @@ static int __devinit mpc52xx_gpt_probe(struct of_device *ofdev, | |||
349 | 729 | ||
350 | spin_lock_init(&gpt->lock); | 730 | spin_lock_init(&gpt->lock); |
351 | gpt->dev = &ofdev->dev; | 731 | gpt->dev = &ofdev->dev; |
732 | gpt->ipb_freq = mpc5xxx_get_bus_frequency(ofdev->node); | ||
352 | gpt->regs = of_iomap(ofdev->node, 0); | 733 | gpt->regs = of_iomap(ofdev->node, 0); |
353 | if (!gpt->regs) { | 734 | if (!gpt->regs) { |
354 | kfree(gpt); | 735 | kfree(gpt); |
@@ -360,6 +741,26 @@ static int __devinit mpc52xx_gpt_probe(struct of_device *ofdev, | |||
360 | mpc52xx_gpt_gpio_setup(gpt, ofdev->node); | 741 | mpc52xx_gpt_gpio_setup(gpt, ofdev->node); |
361 | mpc52xx_gpt_irq_setup(gpt, ofdev->node); | 742 | mpc52xx_gpt_irq_setup(gpt, ofdev->node); |
362 | 743 | ||
744 | mutex_lock(&mpc52xx_gpt_list_mutex); | ||
745 | list_add(&gpt->list, &mpc52xx_gpt_list); | ||
746 | mutex_unlock(&mpc52xx_gpt_list_mutex); | ||
747 | |||
748 | /* check if this device could be a watchdog */ | ||
749 | if (of_get_property(ofdev->node, "fsl,has-wdt", NULL) || | ||
750 | of_get_property(ofdev->node, "has-wdt", NULL)) { | ||
751 | const u32 *on_boot_wdt; | ||
752 | |||
753 | gpt->wdt_mode = MPC52xx_GPT_CAN_WDT; | ||
754 | on_boot_wdt = of_get_property(ofdev->node, "fsl,wdt-on-boot", | ||
755 | NULL); | ||
756 | if (on_boot_wdt) { | ||
757 | dev_info(gpt->dev, "used as watchdog\n"); | ||
758 | gpt->wdt_mode |= MPC52xx_GPT_IS_WDT; | ||
759 | } else | ||
760 | dev_info(gpt->dev, "can function as watchdog\n"); | ||
761 | mpc52xx_gpt_wdt_setup(gpt, on_boot_wdt); | ||
762 | } | ||
763 | |||
363 | return 0; | 764 | return 0; |
364 | } | 765 | } |
365 | 766 | ||
@@ -394,3 +795,4 @@ static int __init mpc52xx_gpt_init(void) | |||
394 | 795 | ||
395 | /* Make sure GPIOs and IRQs get set up before anyone tries to use them */ | 796 | /* Make sure GPIOs and IRQs get set up before anyone tries to use them */ |
396 | subsys_initcall(mpc52xx_gpt_init); | 797 | subsys_initcall(mpc52xx_gpt_init); |
798 | device_initcall(mpc52xx_gpt_wdt_init); | ||
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c b/arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c new file mode 100644 index 000000000000..929d017535a3 --- /dev/null +++ b/arch/powerpc/platforms/52xx/mpc52xx_lpbfifo.c | |||
@@ -0,0 +1,560 @@ | |||
1 | /* | ||
2 | * LocalPlus Bus FIFO driver for the Freescale MPC52xx. | ||
3 | * | ||
4 | * Copyright (C) 2009 Secret Lab Technologies Ltd. | ||
5 | * | ||
6 | * This file is released under the GPLv2 | ||
7 | * | ||
8 | * Todo: | ||
9 | * - Add support for multiple requests to be queued. | ||
10 | */ | ||
11 | |||
12 | #include <linux/interrupt.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/of.h> | ||
15 | #include <linux/of_platform.h> | ||
16 | #include <linux/spinlock.h> | ||
17 | #include <asm/io.h> | ||
18 | #include <asm/prom.h> | ||
19 | #include <asm/mpc52xx.h> | ||
20 | #include <asm/time.h> | ||
21 | |||
22 | #include <sysdev/bestcomm/bestcomm.h> | ||
23 | #include <sysdev/bestcomm/bestcomm_priv.h> | ||
24 | #include <sysdev/bestcomm/gen_bd.h> | ||
25 | |||
26 | MODULE_AUTHOR("Grant Likely <grant.likely@secretlab.ca>"); | ||
27 | MODULE_DESCRIPTION("MPC5200 LocalPlus FIFO device driver"); | ||
28 | MODULE_LICENSE("GPL"); | ||
29 | |||
30 | #define LPBFIFO_REG_PACKET_SIZE (0x00) | ||
31 | #define LPBFIFO_REG_START_ADDRESS (0x04) | ||
32 | #define LPBFIFO_REG_CONTROL (0x08) | ||
33 | #define LPBFIFO_REG_ENABLE (0x0C) | ||
34 | #define LPBFIFO_REG_BYTES_DONE_STATUS (0x14) | ||
35 | #define LPBFIFO_REG_FIFO_DATA (0x40) | ||
36 | #define LPBFIFO_REG_FIFO_STATUS (0x44) | ||
37 | #define LPBFIFO_REG_FIFO_CONTROL (0x48) | ||
38 | #define LPBFIFO_REG_FIFO_ALARM (0x4C) | ||
39 | |||
40 | struct mpc52xx_lpbfifo { | ||
41 | struct device *dev; | ||
42 | phys_addr_t regs_phys; | ||
43 | void __iomem *regs; | ||
44 | int irq; | ||
45 | spinlock_t lock; | ||
46 | |||
47 | struct bcom_task *bcom_tx_task; | ||
48 | struct bcom_task *bcom_rx_task; | ||
49 | struct bcom_task *bcom_cur_task; | ||
50 | |||
51 | /* Current state data */ | ||
52 | struct mpc52xx_lpbfifo_request *req; | ||
53 | int dma_irqs_enabled; | ||
54 | }; | ||
55 | |||
56 | /* The MPC5200 has only one fifo, so only need one instance structure */ | ||
57 | static struct mpc52xx_lpbfifo lpbfifo; | ||
58 | |||
59 | /** | ||
60 | * mpc52xx_lpbfifo_kick - Trigger the next block of data to be transfered | ||
61 | */ | ||
62 | static void mpc52xx_lpbfifo_kick(struct mpc52xx_lpbfifo_request *req) | ||
63 | { | ||
64 | size_t transfer_size = req->size - req->pos; | ||
65 | struct bcom_bd *bd; | ||
66 | void __iomem *reg; | ||
67 | u32 *data; | ||
68 | int i; | ||
69 | int bit_fields; | ||
70 | int dma = !(req->flags & MPC52XX_LPBFIFO_FLAG_NO_DMA); | ||
71 | int write = req->flags & MPC52XX_LPBFIFO_FLAG_WRITE; | ||
72 | int poll_dma = req->flags & MPC52XX_LPBFIFO_FLAG_POLL_DMA; | ||
73 | |||
74 | /* Set and clear the reset bits; is good practice in User Manual */ | ||
75 | out_be32(lpbfifo.regs + LPBFIFO_REG_ENABLE, 0x01010000); | ||
76 | |||
77 | /* set master enable bit */ | ||
78 | out_be32(lpbfifo.regs + LPBFIFO_REG_ENABLE, 0x00000001); | ||
79 | if (!dma) { | ||
80 | /* While the FIFO can be setup for transfer sizes as large as | ||
81 | * 16M-1, the FIFO itself is only 512 bytes deep and it does | ||
82 | * not generate interrupts for FIFO full events (only transfer | ||
83 | * complete will raise an IRQ). Therefore when not using | ||
84 | * Bestcomm to drive the FIFO it needs to either be polled, or | ||
85 | * transfers need to constrained to the size of the fifo. | ||
86 | * | ||
87 | * This driver restricts the size of the transfer | ||
88 | */ | ||
89 | if (transfer_size > 512) | ||
90 | transfer_size = 512; | ||
91 | |||
92 | /* Load the FIFO with data */ | ||
93 | if (write) { | ||
94 | reg = lpbfifo.regs + LPBFIFO_REG_FIFO_DATA; | ||
95 | data = req->data + req->pos; | ||
96 | for (i = 0; i < transfer_size; i += 4) | ||
97 | out_be32(reg, *data++); | ||
98 | } | ||
99 | |||
100 | /* Unmask both error and completion irqs */ | ||
101 | out_be32(lpbfifo.regs + LPBFIFO_REG_ENABLE, 0x00000301); | ||
102 | } else { | ||
103 | /* Choose the correct direction | ||
104 | * | ||
105 | * Configure the watermarks so DMA will always complete correctly. | ||
106 | * It may be worth experimenting with the ALARM value to see if | ||
107 | * there is a performance impacit. However, if it is wrong there | ||
108 | * is a risk of DMA not transferring the last chunk of data | ||
109 | */ | ||
110 | if (write) { | ||
111 | out_be32(lpbfifo.regs + LPBFIFO_REG_FIFO_ALARM, 0x1e4); | ||
112 | out_8(lpbfifo.regs + LPBFIFO_REG_FIFO_CONTROL, 7); | ||
113 | lpbfifo.bcom_cur_task = lpbfifo.bcom_tx_task; | ||
114 | } else { | ||
115 | out_be32(lpbfifo.regs + LPBFIFO_REG_FIFO_ALARM, 0x1ff); | ||
116 | out_8(lpbfifo.regs + LPBFIFO_REG_FIFO_CONTROL, 0); | ||
117 | lpbfifo.bcom_cur_task = lpbfifo.bcom_rx_task; | ||
118 | |||
119 | if (poll_dma) { | ||
120 | if (lpbfifo.dma_irqs_enabled) { | ||
121 | disable_irq(bcom_get_task_irq(lpbfifo.bcom_rx_task)); | ||
122 | lpbfifo.dma_irqs_enabled = 0; | ||
123 | } | ||
124 | } else { | ||
125 | if (!lpbfifo.dma_irqs_enabled) { | ||
126 | enable_irq(bcom_get_task_irq(lpbfifo.bcom_rx_task)); | ||
127 | lpbfifo.dma_irqs_enabled = 1; | ||
128 | } | ||
129 | } | ||
130 | } | ||
131 | |||
132 | bd = bcom_prepare_next_buffer(lpbfifo.bcom_cur_task); | ||
133 | bd->status = transfer_size; | ||
134 | if (!write) { | ||
135 | /* | ||
136 | * In the DMA read case, the DMA doesn't complete, | ||
137 | * possibly due to incorrect watermarks in the ALARM | ||
138 | * and CONTROL regs. For now instead of trying to | ||
139 | * determine the right watermarks that will make this | ||
140 | * work, just increase the number of bytes the FIFO is | ||
141 | * expecting. | ||
142 | * | ||
143 | * When submitting another operation, the FIFO will get | ||
144 | * reset, so the condition of the FIFO waiting for a | ||
145 | * non-existent 4 bytes will get cleared. | ||
146 | */ | ||
147 | transfer_size += 4; /* BLECH! */ | ||
148 | } | ||
149 | bd->data[0] = req->data_phys + req->pos; | ||
150 | bcom_submit_next_buffer(lpbfifo.bcom_cur_task, NULL); | ||
151 | |||
152 | /* error irq & master enabled bit */ | ||
153 | bit_fields = 0x00000201; | ||
154 | |||
155 | /* Unmask irqs */ | ||
156 | if (write && (!poll_dma)) | ||
157 | bit_fields |= 0x00000100; /* completion irq too */ | ||
158 | out_be32(lpbfifo.regs + LPBFIFO_REG_ENABLE, bit_fields); | ||
159 | } | ||
160 | |||
161 | /* Set transfer size, width, chip select and READ mode */ | ||
162 | out_be32(lpbfifo.regs + LPBFIFO_REG_START_ADDRESS, | ||
163 | req->offset + req->pos); | ||
164 | out_be32(lpbfifo.regs + LPBFIFO_REG_PACKET_SIZE, transfer_size); | ||
165 | |||
166 | bit_fields = req->cs << 24 | 0x000008; | ||
167 | if (!write) | ||
168 | bit_fields |= 0x010000; /* read mode */ | ||
169 | out_be32(lpbfifo.regs + LPBFIFO_REG_CONTROL, bit_fields); | ||
170 | |||
171 | /* Kick it off */ | ||
172 | out_8(lpbfifo.regs + LPBFIFO_REG_PACKET_SIZE, 0x01); | ||
173 | if (dma) | ||
174 | bcom_enable(lpbfifo.bcom_cur_task); | ||
175 | } | ||
176 | |||
177 | /** | ||
178 | * mpc52xx_lpbfifo_irq - IRQ handler for LPB FIFO | ||
179 | * | ||
180 | * On transmit, the dma completion irq triggers before the fifo completion | ||
181 | * triggers. Handle the dma completion here instead of the LPB FIFO Bestcomm | ||
182 | * task completion irq becuase everyting is not really done until the LPB FIFO | ||
183 | * completion irq triggers. | ||
184 | * | ||
185 | * In other words: | ||
186 | * For DMA, on receive, the "Fat Lady" is the bestcom completion irq. on | ||
187 | * transmit, the fifo completion irq is the "Fat Lady". The opera (or in this | ||
188 | * case the DMA/FIFO operation) is not finished until the "Fat Lady" sings. | ||
189 | * | ||
190 | * Reasons for entering this routine: | ||
191 | * 1) PIO mode rx and tx completion irq | ||
192 | * 2) DMA interrupt mode tx completion irq | ||
193 | * 3) DMA polled mode tx | ||
194 | * | ||
195 | * Exit conditions: | ||
196 | * 1) Transfer aborted | ||
197 | * 2) FIFO complete without DMA; more data to do | ||
198 | * 3) FIFO complete without DMA; all data transfered | ||
199 | * 4) FIFO complete using DMA | ||
200 | * | ||
201 | * Condition 1 can occur regardless of whether or not DMA is used. | ||
202 | * It requires executing the callback to report the error and exiting | ||
203 | * immediately. | ||
204 | * | ||
205 | * Condition 2 requires programming the FIFO with the next block of data | ||
206 | * | ||
207 | * Condition 3 requires executing the callback to report completion | ||
208 | * | ||
209 | * Condition 4 means the same as 3, except that we also retrieve the bcom | ||
210 | * buffer so DMA doesn't get clogged up. | ||
211 | * | ||
212 | * To make things trickier, the spinlock must be dropped before | ||
213 | * executing the callback, otherwise we could end up with a deadlock | ||
214 | * or nested spinlock condition. The out path is non-trivial, so | ||
215 | * extra fiddling is done to make sure all paths lead to the same | ||
216 | * outbound code. | ||
217 | */ | ||
218 | static irqreturn_t mpc52xx_lpbfifo_irq(int irq, void *dev_id) | ||
219 | { | ||
220 | struct mpc52xx_lpbfifo_request *req; | ||
221 | u32 status = in_8(lpbfifo.regs + LPBFIFO_REG_BYTES_DONE_STATUS); | ||
222 | void __iomem *reg; | ||
223 | u32 *data; | ||
224 | int count, i; | ||
225 | int do_callback = 0; | ||
226 | u32 ts; | ||
227 | unsigned long flags; | ||
228 | int dma, write, poll_dma; | ||
229 | |||
230 | spin_lock_irqsave(&lpbfifo.lock, flags); | ||
231 | ts = get_tbl(); | ||
232 | |||
233 | req = lpbfifo.req; | ||
234 | if (!req) { | ||
235 | spin_unlock_irqrestore(&lpbfifo.lock, flags); | ||
236 | pr_err("bogus LPBFIFO IRQ\n"); | ||
237 | return IRQ_HANDLED; | ||
238 | } | ||
239 | |||
240 | dma = !(req->flags & MPC52XX_LPBFIFO_FLAG_NO_DMA); | ||
241 | write = req->flags & MPC52XX_LPBFIFO_FLAG_WRITE; | ||
242 | poll_dma = req->flags & MPC52XX_LPBFIFO_FLAG_POLL_DMA; | ||
243 | |||
244 | if (dma && !write) { | ||
245 | spin_unlock_irqrestore(&lpbfifo.lock, flags); | ||
246 | pr_err("bogus LPBFIFO IRQ (dma and not writting)\n"); | ||
247 | return IRQ_HANDLED; | ||
248 | } | ||
249 | |||
250 | if ((status & 0x01) == 0) { | ||
251 | goto out; | ||
252 | } | ||
253 | |||
254 | /* check abort bit */ | ||
255 | if (status & 0x10) { | ||
256 | out_be32(lpbfifo.regs + LPBFIFO_REG_ENABLE, 0x01010000); | ||
257 | do_callback = 1; | ||
258 | goto out; | ||
259 | } | ||
260 | |||
261 | /* Read result from hardware */ | ||
262 | count = in_be32(lpbfifo.regs + LPBFIFO_REG_BYTES_DONE_STATUS); | ||
263 | count &= 0x00ffffff; | ||
264 | |||
265 | if (!dma && !write) { | ||
266 | /* copy the data out of the FIFO */ | ||
267 | reg = lpbfifo.regs + LPBFIFO_REG_FIFO_DATA; | ||
268 | data = req->data + req->pos; | ||
269 | for (i = 0; i < count; i += 4) | ||
270 | *data++ = in_be32(reg); | ||
271 | } | ||
272 | |||
273 | /* Update transfer position and count */ | ||
274 | req->pos += count; | ||
275 | |||
276 | /* Decide what to do next */ | ||
277 | if (req->size - req->pos) | ||
278 | mpc52xx_lpbfifo_kick(req); /* more work to do */ | ||
279 | else | ||
280 | do_callback = 1; | ||
281 | |||
282 | out: | ||
283 | /* Clear the IRQ */ | ||
284 | out_8(lpbfifo.regs + LPBFIFO_REG_BYTES_DONE_STATUS, 0x01); | ||
285 | |||
286 | if (dma && (status & 0x11)) { | ||
287 | /* | ||
288 | * Count the DMA as complete only when the FIFO completion | ||
289 | * status or abort bits are set. | ||
290 | * | ||
291 | * (status & 0x01) should always be the case except sometimes | ||
292 | * when using polled DMA. | ||
293 | * | ||
294 | * (status & 0x10) {transfer aborted}: This case needs more | ||
295 | * testing. | ||
296 | */ | ||
297 | bcom_retrieve_buffer(lpbfifo.bcom_cur_task, &status, NULL); | ||
298 | } | ||
299 | req->last_byte = ((u8 *)req->data)[req->size - 1]; | ||
300 | |||
301 | /* When the do_callback flag is set; it means the transfer is finished | ||
302 | * so set the FIFO as idle */ | ||
303 | if (do_callback) | ||
304 | lpbfifo.req = NULL; | ||
305 | |||
306 | if (irq != 0) /* don't increment on polled case */ | ||
307 | req->irq_count++; | ||
308 | |||
309 | req->irq_ticks += get_tbl() - ts; | ||
310 | spin_unlock_irqrestore(&lpbfifo.lock, flags); | ||
311 | |||
312 | /* Spinlock is released; it is now safe to call the callback */ | ||
313 | if (do_callback && req->callback) | ||
314 | req->callback(req); | ||
315 | |||
316 | return IRQ_HANDLED; | ||
317 | } | ||
318 | |||
319 | /** | ||
320 | * mpc52xx_lpbfifo_bcom_irq - IRQ handler for LPB FIFO Bestcomm task | ||
321 | * | ||
322 | * Only used when receiving data. | ||
323 | */ | ||
324 | static irqreturn_t mpc52xx_lpbfifo_bcom_irq(int irq, void *dev_id) | ||
325 | { | ||
326 | struct mpc52xx_lpbfifo_request *req; | ||
327 | unsigned long flags; | ||
328 | u32 status; | ||
329 | u32 ts; | ||
330 | |||
331 | spin_lock_irqsave(&lpbfifo.lock, flags); | ||
332 | ts = get_tbl(); | ||
333 | |||
334 | req = lpbfifo.req; | ||
335 | if (!req || (req->flags & MPC52XX_LPBFIFO_FLAG_NO_DMA)) { | ||
336 | spin_unlock_irqrestore(&lpbfifo.lock, flags); | ||
337 | return IRQ_HANDLED; | ||
338 | } | ||
339 | |||
340 | if (irq != 0) /* don't increment on polled case */ | ||
341 | req->irq_count++; | ||
342 | |||
343 | if (!bcom_buffer_done(lpbfifo.bcom_cur_task)) { | ||
344 | spin_unlock_irqrestore(&lpbfifo.lock, flags); | ||
345 | |||
346 | req->buffer_not_done_cnt++; | ||
347 | if ((req->buffer_not_done_cnt % 1000) == 0) | ||
348 | pr_err("transfer stalled\n"); | ||
349 | |||
350 | return IRQ_HANDLED; | ||
351 | } | ||
352 | |||
353 | bcom_retrieve_buffer(lpbfifo.bcom_cur_task, &status, NULL); | ||
354 | |||
355 | req->last_byte = ((u8 *)req->data)[req->size - 1]; | ||
356 | |||
357 | req->pos = status & 0x00ffffff; | ||
358 | |||
359 | /* Mark the FIFO as idle */ | ||
360 | lpbfifo.req = NULL; | ||
361 | |||
362 | /* Release the lock before calling out to the callback. */ | ||
363 | req->irq_ticks += get_tbl() - ts; | ||
364 | spin_unlock_irqrestore(&lpbfifo.lock, flags); | ||
365 | |||
366 | if (req->callback) | ||
367 | req->callback(req); | ||
368 | |||
369 | return IRQ_HANDLED; | ||
370 | } | ||
371 | |||
372 | /** | ||
373 | * mpc52xx_lpbfifo_bcom_poll - Poll for DMA completion | ||
374 | */ | ||
375 | void mpc52xx_lpbfifo_poll(void) | ||
376 | { | ||
377 | struct mpc52xx_lpbfifo_request *req = lpbfifo.req; | ||
378 | int dma = !(req->flags & MPC52XX_LPBFIFO_FLAG_NO_DMA); | ||
379 | int write = req->flags & MPC52XX_LPBFIFO_FLAG_WRITE; | ||
380 | |||
381 | /* | ||
382 | * For more information, see comments on the "Fat Lady" | ||
383 | */ | ||
384 | if (dma && write) | ||
385 | mpc52xx_lpbfifo_irq(0, NULL); | ||
386 | else | ||
387 | mpc52xx_lpbfifo_bcom_irq(0, NULL); | ||
388 | } | ||
389 | EXPORT_SYMBOL(mpc52xx_lpbfifo_poll); | ||
390 | |||
391 | /** | ||
392 | * mpc52xx_lpbfifo_submit - Submit an LPB FIFO transfer request. | ||
393 | * @req: Pointer to request structure | ||
394 | */ | ||
395 | int mpc52xx_lpbfifo_submit(struct mpc52xx_lpbfifo_request *req) | ||
396 | { | ||
397 | unsigned long flags; | ||
398 | |||
399 | if (!lpbfifo.regs) | ||
400 | return -ENODEV; | ||
401 | |||
402 | spin_lock_irqsave(&lpbfifo.lock, flags); | ||
403 | |||
404 | /* If the req pointer is already set, then a transfer is in progress */ | ||
405 | if (lpbfifo.req) { | ||
406 | spin_unlock_irqrestore(&lpbfifo.lock, flags); | ||
407 | return -EBUSY; | ||
408 | } | ||
409 | |||
410 | /* Setup the transfer */ | ||
411 | lpbfifo.req = req; | ||
412 | req->irq_count = 0; | ||
413 | req->irq_ticks = 0; | ||
414 | req->buffer_not_done_cnt = 0; | ||
415 | req->pos = 0; | ||
416 | |||
417 | mpc52xx_lpbfifo_kick(req); | ||
418 | spin_unlock_irqrestore(&lpbfifo.lock, flags); | ||
419 | return 0; | ||
420 | } | ||
421 | EXPORT_SYMBOL(mpc52xx_lpbfifo_submit); | ||
422 | |||
423 | void mpc52xx_lpbfifo_abort(struct mpc52xx_lpbfifo_request *req) | ||
424 | { | ||
425 | unsigned long flags; | ||
426 | |||
427 | spin_lock_irqsave(&lpbfifo.lock, flags); | ||
428 | if (lpbfifo.req == req) { | ||
429 | /* Put it into reset and clear the state */ | ||
430 | bcom_gen_bd_rx_reset(lpbfifo.bcom_rx_task); | ||
431 | bcom_gen_bd_tx_reset(lpbfifo.bcom_tx_task); | ||
432 | out_be32(lpbfifo.regs + LPBFIFO_REG_ENABLE, 0x01010000); | ||
433 | lpbfifo.req = NULL; | ||
434 | } | ||
435 | spin_unlock_irqrestore(&lpbfifo.lock, flags); | ||
436 | } | ||
437 | EXPORT_SYMBOL(mpc52xx_lpbfifo_abort); | ||
438 | |||
439 | static int __devinit | ||
440 | mpc52xx_lpbfifo_probe(struct of_device *op, const struct of_device_id *match) | ||
441 | { | ||
442 | struct resource res; | ||
443 | int rc = -ENOMEM; | ||
444 | |||
445 | if (lpbfifo.dev != NULL) | ||
446 | return -ENOSPC; | ||
447 | |||
448 | lpbfifo.irq = irq_of_parse_and_map(op->node, 0); | ||
449 | if (!lpbfifo.irq) | ||
450 | return -ENODEV; | ||
451 | |||
452 | if (of_address_to_resource(op->node, 0, &res)) | ||
453 | return -ENODEV; | ||
454 | lpbfifo.regs_phys = res.start; | ||
455 | lpbfifo.regs = of_iomap(op->node, 0); | ||
456 | if (!lpbfifo.regs) | ||
457 | return -ENOMEM; | ||
458 | |||
459 | spin_lock_init(&lpbfifo.lock); | ||
460 | |||
461 | /* Put FIFO into reset */ | ||
462 | out_be32(lpbfifo.regs + LPBFIFO_REG_ENABLE, 0x01010000); | ||
463 | |||
464 | /* Register the interrupt handler */ | ||
465 | rc = request_irq(lpbfifo.irq, mpc52xx_lpbfifo_irq, 0, | ||
466 | "mpc52xx-lpbfifo", &lpbfifo); | ||
467 | if (rc) | ||
468 | goto err_irq; | ||
469 | |||
470 | /* Request the Bestcomm receive (fifo --> memory) task and IRQ */ | ||
471 | lpbfifo.bcom_rx_task = | ||
472 | bcom_gen_bd_rx_init(2, res.start + LPBFIFO_REG_FIFO_DATA, | ||
473 | BCOM_INITIATOR_SCLPC, BCOM_IPR_SCLPC, | ||
474 | 16*1024*1024); | ||
475 | if (!lpbfifo.bcom_rx_task) | ||
476 | goto err_bcom_rx; | ||
477 | |||
478 | rc = request_irq(bcom_get_task_irq(lpbfifo.bcom_rx_task), | ||
479 | mpc52xx_lpbfifo_bcom_irq, 0, | ||
480 | "mpc52xx-lpbfifo-rx", &lpbfifo); | ||
481 | if (rc) | ||
482 | goto err_bcom_rx_irq; | ||
483 | |||
484 | /* Request the Bestcomm transmit (memory --> fifo) task and IRQ */ | ||
485 | lpbfifo.bcom_tx_task = | ||
486 | bcom_gen_bd_tx_init(2, res.start + LPBFIFO_REG_FIFO_DATA, | ||
487 | BCOM_INITIATOR_SCLPC, BCOM_IPR_SCLPC); | ||
488 | if (!lpbfifo.bcom_tx_task) | ||
489 | goto err_bcom_tx; | ||
490 | |||
491 | lpbfifo.dev = &op->dev; | ||
492 | return 0; | ||
493 | |||
494 | err_bcom_tx: | ||
495 | free_irq(bcom_get_task_irq(lpbfifo.bcom_rx_task), &lpbfifo); | ||
496 | err_bcom_rx_irq: | ||
497 | bcom_gen_bd_rx_release(lpbfifo.bcom_rx_task); | ||
498 | err_bcom_rx: | ||
499 | err_irq: | ||
500 | iounmap(lpbfifo.regs); | ||
501 | lpbfifo.regs = NULL; | ||
502 | |||
503 | dev_err(&op->dev, "mpc52xx_lpbfifo_probe() failed\n"); | ||
504 | return -ENODEV; | ||
505 | } | ||
506 | |||
507 | |||
508 | static int __devexit mpc52xx_lpbfifo_remove(struct of_device *op) | ||
509 | { | ||
510 | if (lpbfifo.dev != &op->dev) | ||
511 | return 0; | ||
512 | |||
513 | /* Put FIFO in reset */ | ||
514 | out_be32(lpbfifo.regs + LPBFIFO_REG_ENABLE, 0x01010000); | ||
515 | |||
516 | /* Release the bestcomm transmit task */ | ||
517 | free_irq(bcom_get_task_irq(lpbfifo.bcom_tx_task), &lpbfifo); | ||
518 | bcom_gen_bd_tx_release(lpbfifo.bcom_tx_task); | ||
519 | |||
520 | /* Release the bestcomm receive task */ | ||
521 | free_irq(bcom_get_task_irq(lpbfifo.bcom_rx_task), &lpbfifo); | ||
522 | bcom_gen_bd_rx_release(lpbfifo.bcom_rx_task); | ||
523 | |||
524 | free_irq(lpbfifo.irq, &lpbfifo); | ||
525 | iounmap(lpbfifo.regs); | ||
526 | lpbfifo.regs = NULL; | ||
527 | lpbfifo.dev = NULL; | ||
528 | |||
529 | return 0; | ||
530 | } | ||
531 | |||
532 | static struct of_device_id mpc52xx_lpbfifo_match[] __devinitconst = { | ||
533 | { .compatible = "fsl,mpc5200-lpbfifo", }, | ||
534 | {}, | ||
535 | }; | ||
536 | |||
537 | static struct of_platform_driver mpc52xx_lpbfifo_driver = { | ||
538 | .owner = THIS_MODULE, | ||
539 | .name = "mpc52xx-lpbfifo", | ||
540 | .match_table = mpc52xx_lpbfifo_match, | ||
541 | .probe = mpc52xx_lpbfifo_probe, | ||
542 | .remove = __devexit_p(mpc52xx_lpbfifo_remove), | ||
543 | }; | ||
544 | |||
545 | /*********************************************************************** | ||
546 | * Module init/exit | ||
547 | */ | ||
548 | static int __init mpc52xx_lpbfifo_init(void) | ||
549 | { | ||
550 | pr_debug("Registering LocalPlus bus FIFO driver\n"); | ||
551 | return of_register_platform_driver(&mpc52xx_lpbfifo_driver); | ||
552 | } | ||
553 | module_init(mpc52xx_lpbfifo_init); | ||
554 | |||
555 | static void __exit mpc52xx_lpbfifo_exit(void) | ||
556 | { | ||
557 | pr_debug("Unregistering LocalPlus bus FIFO driver\n"); | ||
558 | of_unregister_platform_driver(&mpc52xx_lpbfifo_driver); | ||
559 | } | ||
560 | module_exit(mpc52xx_lpbfifo_exit); | ||
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pic.c b/arch/powerpc/platforms/52xx/mpc52xx_pic.c index 480f806fd0a9..4bf4bf7b063e 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pic.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pic.c | |||
@@ -220,7 +220,7 @@ static int mpc52xx_extirq_set_type(unsigned int virq, unsigned int flow_type) | |||
220 | } | 220 | } |
221 | 221 | ||
222 | static struct irq_chip mpc52xx_extirq_irqchip = { | 222 | static struct irq_chip mpc52xx_extirq_irqchip = { |
223 | .typename = "MPC52xx External", | 223 | .name = "MPC52xx External", |
224 | .mask = mpc52xx_extirq_mask, | 224 | .mask = mpc52xx_extirq_mask, |
225 | .unmask = mpc52xx_extirq_unmask, | 225 | .unmask = mpc52xx_extirq_unmask, |
226 | .ack = mpc52xx_extirq_ack, | 226 | .ack = mpc52xx_extirq_ack, |
@@ -258,7 +258,7 @@ static void mpc52xx_main_unmask(unsigned int virq) | |||
258 | } | 258 | } |
259 | 259 | ||
260 | static struct irq_chip mpc52xx_main_irqchip = { | 260 | static struct irq_chip mpc52xx_main_irqchip = { |
261 | .typename = "MPC52xx Main", | 261 | .name = "MPC52xx Main", |
262 | .mask = mpc52xx_main_mask, | 262 | .mask = mpc52xx_main_mask, |
263 | .mask_ack = mpc52xx_main_mask, | 263 | .mask_ack = mpc52xx_main_mask, |
264 | .unmask = mpc52xx_main_unmask, | 264 | .unmask = mpc52xx_main_unmask, |
@@ -291,7 +291,7 @@ static void mpc52xx_periph_unmask(unsigned int virq) | |||
291 | } | 291 | } |
292 | 292 | ||
293 | static struct irq_chip mpc52xx_periph_irqchip = { | 293 | static struct irq_chip mpc52xx_periph_irqchip = { |
294 | .typename = "MPC52xx Peripherals", | 294 | .name = "MPC52xx Peripherals", |
295 | .mask = mpc52xx_periph_mask, | 295 | .mask = mpc52xx_periph_mask, |
296 | .mask_ack = mpc52xx_periph_mask, | 296 | .mask_ack = mpc52xx_periph_mask, |
297 | .unmask = mpc52xx_periph_unmask, | 297 | .unmask = mpc52xx_periph_unmask, |
@@ -335,7 +335,7 @@ static void mpc52xx_sdma_ack(unsigned int virq) | |||
335 | } | 335 | } |
336 | 336 | ||
337 | static struct irq_chip mpc52xx_sdma_irqchip = { | 337 | static struct irq_chip mpc52xx_sdma_irqchip = { |
338 | .typename = "MPC52xx SDMA", | 338 | .name = "MPC52xx SDMA", |
339 | .mask = mpc52xx_sdma_mask, | 339 | .mask = mpc52xx_sdma_mask, |
340 | .unmask = mpc52xx_sdma_unmask, | 340 | .unmask = mpc52xx_sdma_unmask, |
341 | .ack = mpc52xx_sdma_ack, | 341 | .ack = mpc52xx_sdma_ack, |
@@ -355,7 +355,7 @@ static int mpc52xx_is_extirq(int l1, int l2) | |||
355 | * mpc52xx_irqhost_xlate - translate virq# from device tree interrupts property | 355 | * mpc52xx_irqhost_xlate - translate virq# from device tree interrupts property |
356 | */ | 356 | */ |
357 | static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct, | 357 | static int mpc52xx_irqhost_xlate(struct irq_host *h, struct device_node *ct, |
358 | u32 *intspec, unsigned int intsize, | 358 | const u32 *intspec, unsigned int intsize, |
359 | irq_hw_number_t *out_hwirq, | 359 | irq_hw_number_t *out_hwirq, |
360 | unsigned int *out_flags) | 360 | unsigned int *out_flags) |
361 | { | 361 | { |
diff --git a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c index 7ee979f323d1..9d962d7c72c1 100644 --- a/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c +++ b/arch/powerpc/platforms/82xx/pq2ads-pci-pic.c | |||
@@ -69,7 +69,6 @@ static void pq2ads_pci_unmask_irq(unsigned int virq) | |||
69 | } | 69 | } |
70 | 70 | ||
71 | static struct irq_chip pq2ads_pci_ic = { | 71 | static struct irq_chip pq2ads_pci_ic = { |
72 | .typename = "PQ2 ADS PCI", | ||
73 | .name = "PQ2 ADS PCI", | 72 | .name = "PQ2 ADS PCI", |
74 | .end = pq2ads_pci_unmask_irq, | 73 | .end = pq2ads_pci_unmask_irq, |
75 | .mask = pq2ads_pci_mask_irq, | 74 | .mask = pq2ads_pci_mask_irq, |
@@ -107,7 +106,7 @@ static void pq2ads_pci_irq_demux(unsigned int irq, struct irq_desc *desc) | |||
107 | static int pci_pic_host_map(struct irq_host *h, unsigned int virq, | 106 | static int pci_pic_host_map(struct irq_host *h, unsigned int virq, |
108 | irq_hw_number_t hw) | 107 | irq_hw_number_t hw) |
109 | { | 108 | { |
110 | get_irq_desc(virq)->status |= IRQ_LEVEL; | 109 | irq_to_desc(virq)->status |= IRQ_LEVEL; |
111 | set_irq_chip_data(virq, h->host_data); | 110 | set_irq_chip_data(virq, h->host_data); |
112 | set_irq_chip_and_handler(virq, &pq2ads_pci_ic, handle_level_irq); | 111 | set_irq_chip_and_handler(virq, &pq2ads_pci_ic, handle_level_irq); |
113 | return 0; | 112 | return 0; |
diff --git a/arch/powerpc/platforms/83xx/mpc832x_rdb.c b/arch/powerpc/platforms/83xx/mpc832x_rdb.c index 567ded7c3b9b..17f99745f0e4 100644 --- a/arch/powerpc/platforms/83xx/mpc832x_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc832x_rdb.c | |||
@@ -74,7 +74,7 @@ static int __init of_fsl_spi_probe(char *type, char *compatible, u32 sysclk, | |||
74 | 74 | ||
75 | prop = of_get_property(np, "mode", NULL); | 75 | prop = of_get_property(np, "mode", NULL); |
76 | if (prop && !strcmp(prop, "cpu-qe")) | 76 | if (prop && !strcmp(prop, "cpu-qe")) |
77 | pdata.qe_mode = 1; | 77 | pdata.flags = SPI_QE_CPU_MODE; |
78 | 78 | ||
79 | for (j = 0; j < num_board_infos; j++) { | 79 | for (j = 0; j < num_board_infos; j++) { |
80 | if (board_infos[j].bus_num == pdata.bus_num) | 80 | if (board_infos[j].bus_num == pdata.bus_num) |
diff --git a/arch/powerpc/platforms/83xx/suspend.c b/arch/powerpc/platforms/83xx/suspend.c index 08e65fc8b98c..d306f07b9aa1 100644 --- a/arch/powerpc/platforms/83xx/suspend.c +++ b/arch/powerpc/platforms/83xx/suspend.c | |||
@@ -96,6 +96,7 @@ int fsl_deep_sleep(void) | |||
96 | { | 96 | { |
97 | return deep_sleeping; | 97 | return deep_sleeping; |
98 | } | 98 | } |
99 | EXPORT_SYMBOL(fsl_deep_sleep); | ||
99 | 100 | ||
100 | static int mpc83xx_change_state(void) | 101 | static int mpc83xx_change_state(void) |
101 | { | 102 | { |
diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig index d3a975e8fd3e..d95121894eb7 100644 --- a/arch/powerpc/platforms/85xx/Kconfig +++ b/arch/powerpc/platforms/85xx/Kconfig | |||
@@ -1,6 +1,7 @@ | |||
1 | menuconfig MPC85xx | 1 | menuconfig FSL_SOC_BOOKE |
2 | bool "Machine Type" | 2 | bool "Freescale Book-E Machine Type" |
3 | depends on PPC_85xx | 3 | depends on PPC_85xx || PPC_BOOK3E |
4 | select FSL_SOC | ||
4 | select PPC_UDBG_16550 | 5 | select PPC_UDBG_16550 |
5 | select MPIC | 6 | select MPIC |
6 | select PPC_PCI_CHOICE | 7 | select PPC_PCI_CHOICE |
@@ -8,7 +9,7 @@ menuconfig MPC85xx | |||
8 | select SERIAL_8250_SHARE_IRQ if SERIAL_8250 | 9 | select SERIAL_8250_SHARE_IRQ if SERIAL_8250 |
9 | default y | 10 | default y |
10 | 11 | ||
11 | if MPC85xx | 12 | if FSL_SOC_BOOKE |
12 | 13 | ||
13 | config MPC8540_ADS | 14 | config MPC8540_ADS |
14 | bool "Freescale MPC8540 ADS" | 15 | bool "Freescale MPC8540 ADS" |
@@ -144,7 +145,19 @@ config SBC8560 | |||
144 | help | 145 | help |
145 | This option enables support for the Wind River SBC8560 board | 146 | This option enables support for the Wind River SBC8560 board |
146 | 147 | ||
147 | endif # MPC85xx | 148 | config P4080_DS |
149 | bool "Freescale P4080 DS" | ||
150 | select DEFAULT_UIMAGE | ||
151 | select PPC_FSL_BOOK3E | ||
152 | select PPC_E500MC | ||
153 | select PHYS_64BIT | ||
154 | select SWIOTLB | ||
155 | select MPC8xxx_GPIO | ||
156 | select HAS_RAPIDIO | ||
157 | help | ||
158 | This option enables support for the P4080 DS board | ||
159 | |||
160 | endif # FSL_SOC_BOOKE | ||
148 | 161 | ||
149 | config TQM85xx | 162 | config TQM85xx |
150 | bool | 163 | bool |
diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile index 9098aea0cf32..387c128f2c8c 100644 --- a/arch/powerpc/platforms/85xx/Makefile +++ b/arch/powerpc/platforms/85xx/Makefile | |||
@@ -10,6 +10,7 @@ obj-$(CONFIG_MPC8536_DS) += mpc8536_ds.o | |||
10 | obj-$(CONFIG_MPC85xx_DS) += mpc85xx_ds.o | 10 | obj-$(CONFIG_MPC85xx_DS) += mpc85xx_ds.o |
11 | obj-$(CONFIG_MPC85xx_MDS) += mpc85xx_mds.o | 11 | obj-$(CONFIG_MPC85xx_MDS) += mpc85xx_mds.o |
12 | obj-$(CONFIG_MPC85xx_RDB) += mpc85xx_rdb.o | 12 | obj-$(CONFIG_MPC85xx_RDB) += mpc85xx_rdb.o |
13 | obj-$(CONFIG_P4080_DS) += p4080_ds.o corenet_ds.o | ||
13 | obj-$(CONFIG_STX_GP3) += stx_gp3.o | 14 | obj-$(CONFIG_STX_GP3) += stx_gp3.o |
14 | obj-$(CONFIG_TQM85xx) += tqm85xx.o | 15 | obj-$(CONFIG_TQM85xx) += tqm85xx.o |
15 | obj-$(CONFIG_SBC8560) += sbc8560.o | 16 | obj-$(CONFIG_SBC8560) += sbc8560.o |
diff --git a/arch/powerpc/platforms/85xx/corenet_ds.c b/arch/powerpc/platforms/85xx/corenet_ds.c new file mode 100644 index 000000000000..534c2ecc89d9 --- /dev/null +++ b/arch/powerpc/platforms/85xx/corenet_ds.c | |||
@@ -0,0 +1,125 @@ | |||
1 | /* | ||
2 | * Corenet based SoC DS Setup | ||
3 | * | ||
4 | * Maintained by Kumar Gala (see MAINTAINERS for contact information) | ||
5 | * | ||
6 | * Copyright 2009 Freescale Semiconductor Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/pci.h> | ||
16 | #include <linux/kdev_t.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/lmb.h> | ||
20 | |||
21 | #include <asm/system.h> | ||
22 | #include <asm/time.h> | ||
23 | #include <asm/machdep.h> | ||
24 | #include <asm/pci-bridge.h> | ||
25 | #include <mm/mmu_decl.h> | ||
26 | #include <asm/prom.h> | ||
27 | #include <asm/udbg.h> | ||
28 | #include <asm/mpic.h> | ||
29 | |||
30 | #include <linux/of_platform.h> | ||
31 | #include <sysdev/fsl_soc.h> | ||
32 | #include <sysdev/fsl_pci.h> | ||
33 | |||
34 | void __init corenet_ds_pic_init(void) | ||
35 | { | ||
36 | struct mpic *mpic; | ||
37 | struct resource r; | ||
38 | struct device_node *np = NULL; | ||
39 | unsigned int flags = MPIC_PRIMARY | MPIC_BIG_ENDIAN | | ||
40 | MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU; | ||
41 | |||
42 | np = of_find_node_by_type(np, "open-pic"); | ||
43 | |||
44 | if (np == NULL) { | ||
45 | printk(KERN_ERR "Could not find open-pic node\n"); | ||
46 | return; | ||
47 | } | ||
48 | |||
49 | if (of_address_to_resource(np, 0, &r)) { | ||
50 | printk(KERN_ERR "Failed to map mpic register space\n"); | ||
51 | of_node_put(np); | ||
52 | return; | ||
53 | } | ||
54 | |||
55 | if (ppc_md.get_irq == mpic_get_coreint_irq) | ||
56 | flags |= MPIC_ENABLE_COREINT; | ||
57 | |||
58 | mpic = mpic_alloc(np, r.start, flags, 0, 256, " OpenPIC "); | ||
59 | BUG_ON(mpic == NULL); | ||
60 | |||
61 | mpic_init(mpic); | ||
62 | } | ||
63 | |||
64 | #ifdef CONFIG_PCI | ||
65 | static int primary_phb_addr; | ||
66 | #endif | ||
67 | |||
68 | /* | ||
69 | * Setup the architecture | ||
70 | */ | ||
71 | #ifdef CONFIG_SMP | ||
72 | void __init mpc85xx_smp_init(void); | ||
73 | #endif | ||
74 | |||
75 | void __init corenet_ds_setup_arch(void) | ||
76 | { | ||
77 | #ifdef CONFIG_PCI | ||
78 | struct device_node *np; | ||
79 | struct pci_controller *hose; | ||
80 | #endif | ||
81 | dma_addr_t max = 0xffffffff; | ||
82 | |||
83 | #ifdef CONFIG_SMP | ||
84 | mpc85xx_smp_init(); | ||
85 | #endif | ||
86 | |||
87 | #ifdef CONFIG_PCI | ||
88 | for_each_compatible_node(np, "pci", "fsl,p4080-pcie") { | ||
89 | struct resource rsrc; | ||
90 | of_address_to_resource(np, 0, &rsrc); | ||
91 | if ((rsrc.start & 0xfffff) == primary_phb_addr) | ||
92 | fsl_add_bridge(np, 1); | ||
93 | else | ||
94 | fsl_add_bridge(np, 0); | ||
95 | |||
96 | hose = pci_find_hose_for_OF_device(np); | ||
97 | max = min(max, hose->dma_window_base_cur + | ||
98 | hose->dma_window_size); | ||
99 | } | ||
100 | #endif | ||
101 | |||
102 | #ifdef CONFIG_SWIOTLB | ||
103 | if (lmb_end_of_DRAM() > max) { | ||
104 | ppc_swiotlb_enable = 1; | ||
105 | set_pci_dma_ops(&swiotlb_dma_ops); | ||
106 | ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_swiotlb; | ||
107 | } | ||
108 | #endif | ||
109 | pr_info("%s board from Freescale Semiconductor\n", ppc_md.name); | ||
110 | } | ||
111 | |||
112 | static const struct of_device_id of_device_ids[] __devinitconst = { | ||
113 | { | ||
114 | .compatible = "simple-bus" | ||
115 | }, | ||
116 | { | ||
117 | .compatible = "fsl,rapidio-delta", | ||
118 | }, | ||
119 | {} | ||
120 | }; | ||
121 | |||
122 | int __init corenet_ds_publish_devices(void) | ||
123 | { | ||
124 | return of_platform_bus_probe(NULL, of_device_ids, NULL); | ||
125 | } | ||
diff --git a/arch/powerpc/platforms/85xx/corenet_ds.h b/arch/powerpc/platforms/85xx/corenet_ds.h new file mode 100644 index 000000000000..ddd700b23031 --- /dev/null +++ b/arch/powerpc/platforms/85xx/corenet_ds.h | |||
@@ -0,0 +1,19 @@ | |||
1 | /* | ||
2 | * Corenet based SoC DS Setup | ||
3 | * | ||
4 | * Copyright 2009 Freescale Semiconductor Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #ifndef CORENET_DS_H | ||
13 | #define CORENET_DS_H | ||
14 | |||
15 | extern void __init corenet_ds_pic_init(void); | ||
16 | extern void __init corenet_ds_setup_arch(void); | ||
17 | extern int __init corenet_ds_publish_devices(void); | ||
18 | |||
19 | #endif | ||
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c index 3909d57b86e3..c5028a2e5a58 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c | |||
@@ -301,6 +301,7 @@ static struct of_device_id mpc85xx_ids[] = { | |||
301 | { .compatible = "fsl,qe", }, | 301 | { .compatible = "fsl,qe", }, |
302 | { .compatible = "gianfar", }, | 302 | { .compatible = "gianfar", }, |
303 | { .compatible = "fsl,rapidio-delta", }, | 303 | { .compatible = "fsl,rapidio-delta", }, |
304 | { .compatible = "fsl,mpc8548-guts", }, | ||
304 | {}, | 305 | {}, |
305 | }; | 306 | }; |
306 | 307 | ||
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c index c8468de4acf6..088f30b0c088 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c | |||
@@ -44,6 +44,7 @@ void __init mpc85xx_rdb_pic_init(void) | |||
44 | struct mpic *mpic; | 44 | struct mpic *mpic; |
45 | struct resource r; | 45 | struct resource r; |
46 | struct device_node *np; | 46 | struct device_node *np; |
47 | unsigned long root = of_get_flat_dt_root(); | ||
47 | 48 | ||
48 | np = of_find_node_by_type(NULL, "open-pic"); | 49 | np = of_find_node_by_type(NULL, "open-pic"); |
49 | if (np == NULL) { | 50 | if (np == NULL) { |
@@ -57,11 +58,18 @@ void __init mpc85xx_rdb_pic_init(void) | |||
57 | return; | 58 | return; |
58 | } | 59 | } |
59 | 60 | ||
60 | mpic = mpic_alloc(np, r.start, | 61 | if (of_flat_dt_is_compatible(root, "fsl,85XXRDB-CAMP")) { |
62 | mpic = mpic_alloc(np, r.start, | ||
63 | MPIC_PRIMARY | | ||
64 | MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS, | ||
65 | 0, 256, " OpenPIC "); | ||
66 | } else { | ||
67 | mpic = mpic_alloc(np, r.start, | ||
61 | MPIC_PRIMARY | MPIC_WANTS_RESET | | 68 | MPIC_PRIMARY | MPIC_WANTS_RESET | |
62 | MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS | | 69 | MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS | |
63 | MPIC_SINGLE_DEST_CPU, | 70 | MPIC_SINGLE_DEST_CPU, |
64 | 0, 256, " OpenPIC "); | 71 | 0, 256, " OpenPIC "); |
72 | } | ||
65 | 73 | ||
66 | BUG_ON(mpic == NULL); | 74 | BUG_ON(mpic == NULL); |
67 | of_node_put(np); | 75 | of_node_put(np); |
@@ -113,6 +121,7 @@ static int __init mpc85xxrdb_publish_devices(void) | |||
113 | return of_platform_bus_probe(NULL, mpc85xxrdb_ids, NULL); | 121 | return of_platform_bus_probe(NULL, mpc85xxrdb_ids, NULL); |
114 | } | 122 | } |
115 | machine_device_initcall(p2020_rdb, mpc85xxrdb_publish_devices); | 123 | machine_device_initcall(p2020_rdb, mpc85xxrdb_publish_devices); |
124 | machine_device_initcall(p1020_rdb, mpc85xxrdb_publish_devices); | ||
116 | 125 | ||
117 | /* | 126 | /* |
118 | * Called very early, device-tree isn't unflattened | 127 | * Called very early, device-tree isn't unflattened |
@@ -126,6 +135,15 @@ static int __init p2020_rdb_probe(void) | |||
126 | return 0; | 135 | return 0; |
127 | } | 136 | } |
128 | 137 | ||
138 | static int __init p1020_rdb_probe(void) | ||
139 | { | ||
140 | unsigned long root = of_get_flat_dt_root(); | ||
141 | |||
142 | if (of_flat_dt_is_compatible(root, "fsl,P1020RDB")) | ||
143 | return 1; | ||
144 | return 0; | ||
145 | } | ||
146 | |||
129 | define_machine(p2020_rdb) { | 147 | define_machine(p2020_rdb) { |
130 | .name = "P2020 RDB", | 148 | .name = "P2020 RDB", |
131 | .probe = p2020_rdb_probe, | 149 | .probe = p2020_rdb_probe, |
@@ -139,3 +157,17 @@ define_machine(p2020_rdb) { | |||
139 | .calibrate_decr = generic_calibrate_decr, | 157 | .calibrate_decr = generic_calibrate_decr, |
140 | .progress = udbg_progress, | 158 | .progress = udbg_progress, |
141 | }; | 159 | }; |
160 | |||
161 | define_machine(p1020_rdb) { | ||
162 | .name = "P1020 RDB", | ||
163 | .probe = p1020_rdb_probe, | ||
164 | .setup_arch = mpc85xx_rdb_setup_arch, | ||
165 | .init_IRQ = mpc85xx_rdb_pic_init, | ||
166 | #ifdef CONFIG_PCI | ||
167 | .pcibios_fixup_bus = fsl_pcibios_fixup_bus, | ||
168 | #endif | ||
169 | .get_irq = mpic_get_irq, | ||
170 | .restart = fsl_rstcr_restart, | ||
171 | .calibrate_decr = generic_calibrate_decr, | ||
172 | .progress = udbg_progress, | ||
173 | }; | ||
diff --git a/arch/powerpc/platforms/85xx/p4080_ds.c b/arch/powerpc/platforms/85xx/p4080_ds.c new file mode 100644 index 000000000000..84170460497b --- /dev/null +++ b/arch/powerpc/platforms/85xx/p4080_ds.c | |||
@@ -0,0 +1,74 @@ | |||
1 | /* | ||
2 | * P4080 DS Setup | ||
3 | * | ||
4 | * Maintained by Kumar Gala (see MAINTAINERS for contact information) | ||
5 | * | ||
6 | * Copyright 2009 Freescale Semiconductor Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/pci.h> | ||
16 | #include <linux/kdev_t.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | |||
20 | #include <asm/system.h> | ||
21 | #include <asm/time.h> | ||
22 | #include <asm/machdep.h> | ||
23 | #include <asm/pci-bridge.h> | ||
24 | #include <mm/mmu_decl.h> | ||
25 | #include <asm/prom.h> | ||
26 | #include <asm/udbg.h> | ||
27 | #include <asm/mpic.h> | ||
28 | |||
29 | #include <linux/of_platform.h> | ||
30 | #include <sysdev/fsl_soc.h> | ||
31 | #include <sysdev/fsl_pci.h> | ||
32 | |||
33 | #include "corenet_ds.h" | ||
34 | |||
35 | #ifdef CONFIG_PCI | ||
36 | static int primary_phb_addr; | ||
37 | #endif | ||
38 | |||
39 | /* | ||
40 | * Called very early, device-tree isn't unflattened | ||
41 | */ | ||
42 | static int __init p4080_ds_probe(void) | ||
43 | { | ||
44 | unsigned long root = of_get_flat_dt_root(); | ||
45 | |||
46 | if (of_flat_dt_is_compatible(root, "fsl,P4080DS")) { | ||
47 | #ifdef CONFIG_PCI | ||
48 | /* treat PCIe1 as primary, | ||
49 | * shouldn't matter as we have no ISA on the board | ||
50 | */ | ||
51 | primary_phb_addr = 0x0000; | ||
52 | #endif | ||
53 | return 1; | ||
54 | } else { | ||
55 | return 0; | ||
56 | } | ||
57 | } | ||
58 | |||
59 | define_machine(p4080_ds) { | ||
60 | .name = "P4080 DS", | ||
61 | .probe = p4080_ds_probe, | ||
62 | .setup_arch = corenet_ds_setup_arch, | ||
63 | .init_IRQ = corenet_ds_pic_init, | ||
64 | #ifdef CONFIG_PCI | ||
65 | .pcibios_fixup_bus = fsl_pcibios_fixup_bus, | ||
66 | #endif | ||
67 | .get_irq = mpic_get_coreint_irq, | ||
68 | .restart = fsl_rstcr_restart, | ||
69 | .calibrate_decr = generic_calibrate_decr, | ||
70 | .progress = udbg_progress, | ||
71 | }; | ||
72 | |||
73 | machine_device_initcall(p4080_ds, corenet_ds_publish_devices); | ||
74 | machine_arch_initcall(p4080_ds, swiotlb_setup_bus_notifier); | ||
diff --git a/arch/powerpc/platforms/85xx/socrates_fpga_pic.c b/arch/powerpc/platforms/85xx/socrates_fpga_pic.c index 60edf63d0157..e5da5f62b24a 100644 --- a/arch/powerpc/platforms/85xx/socrates_fpga_pic.c +++ b/arch/powerpc/platforms/85xx/socrates_fpga_pic.c | |||
@@ -232,7 +232,7 @@ static int socrates_fpga_pic_set_type(unsigned int virq, | |||
232 | } | 232 | } |
233 | 233 | ||
234 | static struct irq_chip socrates_fpga_pic_chip = { | 234 | static struct irq_chip socrates_fpga_pic_chip = { |
235 | .typename = " FPGA-PIC ", | 235 | .name = " FPGA-PIC ", |
236 | .ack = socrates_fpga_pic_ack, | 236 | .ack = socrates_fpga_pic_ack, |
237 | .mask = socrates_fpga_pic_mask, | 237 | .mask = socrates_fpga_pic_mask, |
238 | .mask_ack = socrates_fpga_pic_mask_ack, | 238 | .mask_ack = socrates_fpga_pic_mask_ack, |
@@ -245,7 +245,7 @@ static int socrates_fpga_pic_host_map(struct irq_host *h, unsigned int virq, | |||
245 | irq_hw_number_t hwirq) | 245 | irq_hw_number_t hwirq) |
246 | { | 246 | { |
247 | /* All interrupts are LEVEL sensitive */ | 247 | /* All interrupts are LEVEL sensitive */ |
248 | get_irq_desc(virq)->status |= IRQ_LEVEL; | 248 | irq_to_desc(virq)->status |= IRQ_LEVEL; |
249 | set_irq_chip_and_handler(virq, &socrates_fpga_pic_chip, | 249 | set_irq_chip_and_handler(virq, &socrates_fpga_pic_chip, |
250 | handle_fasteoi_irq); | 250 | handle_fasteoi_irq); |
251 | 251 | ||
@@ -253,7 +253,7 @@ static int socrates_fpga_pic_host_map(struct irq_host *h, unsigned int virq, | |||
253 | } | 253 | } |
254 | 254 | ||
255 | static int socrates_fpga_pic_host_xlate(struct irq_host *h, | 255 | static int socrates_fpga_pic_host_xlate(struct irq_host *h, |
256 | struct device_node *ct, u32 *intspec, unsigned int intsize, | 256 | struct device_node *ct, const u32 *intspec, unsigned int intsize, |
257 | irq_hw_number_t *out_hwirq, unsigned int *out_flags) | 257 | irq_hw_number_t *out_hwirq, unsigned int *out_flags) |
258 | { | 258 | { |
259 | struct socrates_fpga_irq_info *fpga_irq = &fpga_irqs[intspec[0]]; | 259 | struct socrates_fpga_irq_info *fpga_irq = &fpga_irqs[intspec[0]]; |
diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig index 9c7b64a3402b..2bbfd530d6d8 100644 --- a/arch/powerpc/platforms/86xx/Kconfig +++ b/arch/powerpc/platforms/86xx/Kconfig | |||
@@ -35,6 +35,7 @@ config MPC8610_HPCD | |||
35 | config GEF_PPC9A | 35 | config GEF_PPC9A |
36 | bool "GE Fanuc PPC9A" | 36 | bool "GE Fanuc PPC9A" |
37 | select DEFAULT_UIMAGE | 37 | select DEFAULT_UIMAGE |
38 | select MMIO_NVRAM | ||
38 | select GENERIC_GPIO | 39 | select GENERIC_GPIO |
39 | select ARCH_REQUIRE_GPIOLIB | 40 | select ARCH_REQUIRE_GPIOLIB |
40 | help | 41 | help |
@@ -43,6 +44,7 @@ config GEF_PPC9A | |||
43 | config GEF_SBC310 | 44 | config GEF_SBC310 |
44 | bool "GE Fanuc SBC310" | 45 | bool "GE Fanuc SBC310" |
45 | select DEFAULT_UIMAGE | 46 | select DEFAULT_UIMAGE |
47 | select MMIO_NVRAM | ||
46 | select GENERIC_GPIO | 48 | select GENERIC_GPIO |
47 | select ARCH_REQUIRE_GPIOLIB | 49 | select ARCH_REQUIRE_GPIOLIB |
48 | help | 50 | help |
@@ -51,6 +53,7 @@ config GEF_SBC310 | |||
51 | config GEF_SBC610 | 53 | config GEF_SBC610 |
52 | bool "GE Fanuc SBC610" | 54 | bool "GE Fanuc SBC610" |
53 | select DEFAULT_UIMAGE | 55 | select DEFAULT_UIMAGE |
56 | select MMIO_NVRAM | ||
54 | select GENERIC_GPIO | 57 | select GENERIC_GPIO |
55 | select ARCH_REQUIRE_GPIOLIB | 58 | select ARCH_REQUIRE_GPIOLIB |
56 | select HAS_RAPIDIO | 59 | select HAS_RAPIDIO |
diff --git a/arch/powerpc/platforms/86xx/gef_pic.c b/arch/powerpc/platforms/86xx/gef_pic.c index 50d0a2b63809..0110a8736d33 100644 --- a/arch/powerpc/platforms/86xx/gef_pic.c +++ b/arch/powerpc/platforms/86xx/gef_pic.c | |||
@@ -149,7 +149,7 @@ static void gef_pic_unmask(unsigned int virq) | |||
149 | } | 149 | } |
150 | 150 | ||
151 | static struct irq_chip gef_pic_chip = { | 151 | static struct irq_chip gef_pic_chip = { |
152 | .typename = "gefp", | 152 | .name = "gefp", |
153 | .mask = gef_pic_mask, | 153 | .mask = gef_pic_mask, |
154 | .mask_ack = gef_pic_mask_ack, | 154 | .mask_ack = gef_pic_mask_ack, |
155 | .unmask = gef_pic_unmask, | 155 | .unmask = gef_pic_unmask, |
@@ -163,14 +163,14 @@ static int gef_pic_host_map(struct irq_host *h, unsigned int virq, | |||
163 | irq_hw_number_t hwirq) | 163 | irq_hw_number_t hwirq) |
164 | { | 164 | { |
165 | /* All interrupts are LEVEL sensitive */ | 165 | /* All interrupts are LEVEL sensitive */ |
166 | get_irq_desc(virq)->status |= IRQ_LEVEL; | 166 | irq_to_desc(virq)->status |= IRQ_LEVEL; |
167 | set_irq_chip_and_handler(virq, &gef_pic_chip, handle_level_irq); | 167 | set_irq_chip_and_handler(virq, &gef_pic_chip, handle_level_irq); |
168 | 168 | ||
169 | return 0; | 169 | return 0; |
170 | } | 170 | } |
171 | 171 | ||
172 | static int gef_pic_host_xlate(struct irq_host *h, struct device_node *ct, | 172 | static int gef_pic_host_xlate(struct irq_host *h, struct device_node *ct, |
173 | u32 *intspec, unsigned int intsize, | 173 | const u32 *intspec, unsigned int intsize, |
174 | irq_hw_number_t *out_hwirq, unsigned int *out_flags) | 174 | irq_hw_number_t *out_hwirq, unsigned int *out_flags) |
175 | { | 175 | { |
176 | 176 | ||
diff --git a/arch/powerpc/platforms/86xx/gef_ppc9a.c b/arch/powerpc/platforms/86xx/gef_ppc9a.c index 287f7bd17dd9..a792e5d85813 100644 --- a/arch/powerpc/platforms/86xx/gef_ppc9a.c +++ b/arch/powerpc/platforms/86xx/gef_ppc9a.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <asm/udbg.h> | 33 | #include <asm/udbg.h> |
34 | 34 | ||
35 | #include <asm/mpic.h> | 35 | #include <asm/mpic.h> |
36 | #include <asm/nvram.h> | ||
36 | 37 | ||
37 | #include <sysdev/fsl_pci.h> | 38 | #include <sysdev/fsl_pci.h> |
38 | #include <sysdev/fsl_soc.h> | 39 | #include <sysdev/fsl_soc.h> |
@@ -95,6 +96,10 @@ static void __init gef_ppc9a_setup_arch(void) | |||
95 | printk(KERN_WARNING "Unable to map board registers\n"); | 96 | printk(KERN_WARNING "Unable to map board registers\n"); |
96 | of_node_put(regs); | 97 | of_node_put(regs); |
97 | } | 98 | } |
99 | |||
100 | #if defined(CONFIG_MMIO_NVRAM) | ||
101 | mmio_nvram_init(); | ||
102 | #endif | ||
98 | } | 103 | } |
99 | 104 | ||
100 | /* Return the PCB revision */ | 105 | /* Return the PCB revision */ |
diff --git a/arch/powerpc/platforms/86xx/gef_sbc310.c b/arch/powerpc/platforms/86xx/gef_sbc310.c index 90754e752bd8..6a1a613836c2 100644 --- a/arch/powerpc/platforms/86xx/gef_sbc310.c +++ b/arch/powerpc/platforms/86xx/gef_sbc310.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <asm/udbg.h> | 33 | #include <asm/udbg.h> |
34 | 34 | ||
35 | #include <asm/mpic.h> | 35 | #include <asm/mpic.h> |
36 | #include <asm/nvram.h> | ||
36 | 37 | ||
37 | #include <sysdev/fsl_pci.h> | 38 | #include <sysdev/fsl_pci.h> |
38 | #include <sysdev/fsl_soc.h> | 39 | #include <sysdev/fsl_soc.h> |
@@ -95,6 +96,10 @@ static void __init gef_sbc310_setup_arch(void) | |||
95 | printk(KERN_WARNING "Unable to map board registers\n"); | 96 | printk(KERN_WARNING "Unable to map board registers\n"); |
96 | of_node_put(regs); | 97 | of_node_put(regs); |
97 | } | 98 | } |
99 | |||
100 | #if defined(CONFIG_MMIO_NVRAM) | ||
101 | mmio_nvram_init(); | ||
102 | #endif | ||
98 | } | 103 | } |
99 | 104 | ||
100 | /* Return the PCB revision */ | 105 | /* Return the PCB revision */ |
diff --git a/arch/powerpc/platforms/86xx/gef_sbc610.c b/arch/powerpc/platforms/86xx/gef_sbc610.c index 72b31a6010a0..e10688a0fc4e 100644 --- a/arch/powerpc/platforms/86xx/gef_sbc610.c +++ b/arch/powerpc/platforms/86xx/gef_sbc610.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <asm/udbg.h> | 33 | #include <asm/udbg.h> |
34 | 34 | ||
35 | #include <asm/mpic.h> | 35 | #include <asm/mpic.h> |
36 | #include <asm/nvram.h> | ||
36 | 37 | ||
37 | #include <sysdev/fsl_pci.h> | 38 | #include <sysdev/fsl_pci.h> |
38 | #include <sysdev/fsl_soc.h> | 39 | #include <sysdev/fsl_soc.h> |
@@ -95,6 +96,10 @@ static void __init gef_sbc610_setup_arch(void) | |||
95 | printk(KERN_WARNING "Unable to map board registers\n"); | 96 | printk(KERN_WARNING "Unable to map board registers\n"); |
96 | of_node_put(regs); | 97 | of_node_put(regs); |
97 | } | 98 | } |
99 | |||
100 | #if defined(CONFIG_MMIO_NVRAM) | ||
101 | mmio_nvram_init(); | ||
102 | #endif | ||
98 | } | 103 | } |
99 | 104 | ||
100 | /* Return the PCB revision */ | 105 | /* Return the PCB revision */ |
diff --git a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c index 627908a4cd77..5abe137f6309 100644 --- a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c +++ b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/stddef.h> | 19 | #include <linux/stddef.h> |
20 | #include <linux/kernel.h> | 20 | #include <linux/kernel.h> |
21 | #include <linux/pci.h> | 21 | #include <linux/pci.h> |
22 | #include <linux/interrupt.h> | ||
22 | #include <linux/kdev_t.h> | 23 | #include <linux/kdev_t.h> |
23 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
24 | #include <linux/seq_file.h> | 25 | #include <linux/seq_file.h> |
@@ -41,10 +42,46 @@ | |||
41 | 42 | ||
42 | #include "mpc86xx.h" | 43 | #include "mpc86xx.h" |
43 | 44 | ||
45 | static struct device_node *pixis_node; | ||
44 | static unsigned char *pixis_bdcfg0, *pixis_arch; | 46 | static unsigned char *pixis_bdcfg0, *pixis_arch; |
45 | 47 | ||
48 | #ifdef CONFIG_SUSPEND | ||
49 | static irqreturn_t mpc8610_sw9_irq(int irq, void *data) | ||
50 | { | ||
51 | pr_debug("%s: PIXIS' event (sw9/wakeup) IRQ handled\n", __func__); | ||
52 | return IRQ_HANDLED; | ||
53 | } | ||
54 | |||
55 | static void __init mpc8610_suspend_init(void) | ||
56 | { | ||
57 | int irq; | ||
58 | int ret; | ||
59 | |||
60 | if (!pixis_node) | ||
61 | return; | ||
62 | |||
63 | irq = irq_of_parse_and_map(pixis_node, 0); | ||
64 | if (!irq) { | ||
65 | pr_err("%s: can't map pixis event IRQ.\n", __func__); | ||
66 | return; | ||
67 | } | ||
68 | |||
69 | ret = request_irq(irq, mpc8610_sw9_irq, 0, "sw9/wakeup", NULL); | ||
70 | if (ret) { | ||
71 | pr_err("%s: can't request pixis event IRQ: %d\n", | ||
72 | __func__, ret); | ||
73 | irq_dispose_mapping(irq); | ||
74 | } | ||
75 | |||
76 | enable_irq_wake(irq); | ||
77 | } | ||
78 | #else | ||
79 | static inline void mpc8610_suspend_init(void) { } | ||
80 | #endif /* CONFIG_SUSPEND */ | ||
81 | |||
46 | static struct of_device_id __initdata mpc8610_ids[] = { | 82 | static struct of_device_id __initdata mpc8610_ids[] = { |
47 | { .compatible = "fsl,mpc8610-immr", }, | 83 | { .compatible = "fsl,mpc8610-immr", }, |
84 | { .compatible = "fsl,mpc8610-guts", }, | ||
48 | { .compatible = "simple-bus", }, | 85 | { .compatible = "simple-bus", }, |
49 | { .compatible = "gianfar", }, | 86 | { .compatible = "gianfar", }, |
50 | {} | 87 | {} |
@@ -55,6 +92,9 @@ static int __init mpc8610_declare_of_platform_devices(void) | |||
55 | /* Firstly, register PIXIS GPIOs. */ | 92 | /* Firstly, register PIXIS GPIOs. */ |
56 | simple_gpiochip_init("fsl,fpga-pixis-gpio-bank"); | 93 | simple_gpiochip_init("fsl,fpga-pixis-gpio-bank"); |
57 | 94 | ||
95 | /* Enable wakeup on PIXIS' event IRQ. */ | ||
96 | mpc8610_suspend_init(); | ||
97 | |||
58 | /* Without this call, the SSI device driver won't get probed. */ | 98 | /* Without this call, the SSI device driver won't get probed. */ |
59 | of_platform_bus_probe(NULL, mpc8610_ids, NULL); | 99 | of_platform_bus_probe(NULL, mpc8610_ids, NULL); |
60 | 100 | ||
@@ -250,10 +290,10 @@ static void __init mpc86xx_hpcd_setup_arch(void) | |||
250 | diu_ops.set_sysfs_monitor_port = mpc8610hpcd_set_sysfs_monitor_port; | 290 | diu_ops.set_sysfs_monitor_port = mpc8610hpcd_set_sysfs_monitor_port; |
251 | #endif | 291 | #endif |
252 | 292 | ||
253 | np = of_find_compatible_node(NULL, NULL, "fsl,fpga-pixis"); | 293 | pixis_node = of_find_compatible_node(NULL, NULL, "fsl,fpga-pixis"); |
254 | if (np) { | 294 | if (pixis_node) { |
255 | of_address_to_resource(np, 0, &r); | 295 | of_address_to_resource(pixis_node, 0, &r); |
256 | of_node_put(np); | 296 | of_node_put(pixis_node); |
257 | pixis = ioremap(r.start, 32); | 297 | pixis = ioremap(r.start, 32); |
258 | if (!pixis) { | 298 | if (!pixis) { |
259 | printk(KERN_ERR "Err: can't map FPGA cfg register!\n"); | 299 | printk(KERN_ERR "Err: can't map FPGA cfg register!\n"); |
diff --git a/arch/powerpc/platforms/8xx/m8xx_setup.c b/arch/powerpc/platforms/8xx/m8xx_setup.c index 385acfc48397..242954c4293f 100644 --- a/arch/powerpc/platforms/8xx/m8xx_setup.c +++ b/arch/powerpc/platforms/8xx/m8xx_setup.c | |||
@@ -222,7 +222,7 @@ static void cpm_cascade(unsigned int irq, struct irq_desc *desc) | |||
222 | int cascade_irq; | 222 | int cascade_irq; |
223 | 223 | ||
224 | if ((cascade_irq = cpm_get_irq()) >= 0) { | 224 | if ((cascade_irq = cpm_get_irq()) >= 0) { |
225 | struct irq_desc *cdesc = irq_desc + cascade_irq; | 225 | struct irq_desc *cdesc = irq_to_desc(cascade_irq); |
226 | 226 | ||
227 | generic_handle_irq(cascade_irq); | 227 | generic_handle_irq(cascade_irq); |
228 | cdesc->chip->eoi(cascade_irq); | 228 | cdesc->chip->eoi(cascade_irq); |
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index 04a8061045c4..d1663db7810f 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig | |||
@@ -86,6 +86,11 @@ config RTAS_ERROR_LOGGING | |||
86 | depends on PPC_RTAS | 86 | depends on PPC_RTAS |
87 | default n | 87 | default n |
88 | 88 | ||
89 | config PPC_RTAS_DAEMON | ||
90 | bool | ||
91 | depends on PPC_RTAS | ||
92 | default n | ||
93 | |||
89 | config RTAS_PROC | 94 | config RTAS_PROC |
90 | bool "Proc interface to RTAS" | 95 | bool "Proc interface to RTAS" |
91 | depends on PPC_RTAS | 96 | depends on PPC_RTAS |
@@ -255,7 +260,7 @@ config QE_GPIO | |||
255 | 260 | ||
256 | config CPM2 | 261 | config CPM2 |
257 | bool "Enable support for the CPM2 (Communications Processor Module)" | 262 | bool "Enable support for the CPM2 (Communications Processor Module)" |
258 | depends on MPC85xx || 8260 | 263 | depends on (FSL_SOC_BOOKE && PPC32) || 8260 |
259 | select CPM | 264 | select CPM |
260 | select PPC_LIB_RHEAP | 265 | select PPC_LIB_RHEAP |
261 | select PPC_PCI_CHOICE | 266 | select PPC_PCI_CHOICE |
@@ -300,7 +305,7 @@ source "arch/powerpc/sysdev/bestcomm/Kconfig" | |||
300 | 305 | ||
301 | config MPC8xxx_GPIO | 306 | config MPC8xxx_GPIO |
302 | bool "MPC8xxx GPIO support" | 307 | bool "MPC8xxx GPIO support" |
303 | depends on PPC_MPC831x || PPC_MPC834x || PPC_MPC837x || PPC_85xx || PPC_86xx | 308 | depends on PPC_MPC831x || PPC_MPC834x || PPC_MPC837x || FSL_SOC_BOOKE || PPC_86xx |
304 | select GENERIC_GPIO | 309 | select GENERIC_GPIO |
305 | select ARCH_REQUIRE_GPIOLIB | 310 | select ARCH_REQUIRE_GPIOLIB |
306 | help | 311 | help |
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype index e382cae678b8..2eab27a94cc9 100644 --- a/arch/powerpc/platforms/Kconfig.cputype +++ b/arch/powerpc/platforms/Kconfig.cputype | |||
@@ -28,8 +28,6 @@ config PPC_BOOK3S_32 | |||
28 | config PPC_85xx | 28 | config PPC_85xx |
29 | bool "Freescale 85xx" | 29 | bool "Freescale 85xx" |
30 | select E500 | 30 | select E500 |
31 | select FSL_SOC | ||
32 | select MPC85xx | ||
33 | 31 | ||
34 | config PPC_8xx | 32 | config PPC_8xx |
35 | bool "Freescale 8xx" | 33 | bool "Freescale 8xx" |
@@ -138,6 +136,14 @@ config PPC_FPU | |||
138 | bool | 136 | bool |
139 | default y if PPC64 | 137 | default y if PPC64 |
140 | 138 | ||
139 | config FSL_EMB_PERFMON | ||
140 | bool "Freescale Embedded Perfmon" | ||
141 | depends on E500 || PPC_83xx | ||
142 | help | ||
143 | This is the Performance Monitor support found on the e500 core | ||
144 | and some e300 cores (c3 and c4). Select this only if your | ||
145 | core supports the Embedded Performance Monitor APU | ||
146 | |||
141 | config 4xx | 147 | config 4xx |
142 | bool | 148 | bool |
143 | depends on 40x || 44x | 149 | depends on 40x || 44x |
@@ -153,13 +159,6 @@ config FSL_BOOKE | |||
153 | depends on E200 || E500 | 159 | depends on E200 || E500 |
154 | default y | 160 | default y |
155 | 161 | ||
156 | config FSL_EMB_PERFMON | ||
157 | bool "Freescale Embedded Perfmon" | ||
158 | depends on E500 || PPC_83xx | ||
159 | help | ||
160 | This is the Performance Monitor support found on the e500 core | ||
161 | and some e300 cores (c3 and c4). Select this only if your | ||
162 | core supports the Embedded Performance Monitor APU | ||
163 | 162 | ||
164 | config PTE_64BIT | 163 | config PTE_64BIT |
165 | bool | 164 | bool |
diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile index a6812ee00100..fdb9f0b0d7a8 100644 --- a/arch/powerpc/platforms/Makefile +++ b/arch/powerpc/platforms/Makefile | |||
@@ -12,7 +12,7 @@ obj-$(CONFIG_PPC_MPC52xx) += 52xx/ | |||
12 | obj-$(CONFIG_PPC_8xx) += 8xx/ | 12 | obj-$(CONFIG_PPC_8xx) += 8xx/ |
13 | obj-$(CONFIG_PPC_82xx) += 82xx/ | 13 | obj-$(CONFIG_PPC_82xx) += 82xx/ |
14 | obj-$(CONFIG_PPC_83xx) += 83xx/ | 14 | obj-$(CONFIG_PPC_83xx) += 83xx/ |
15 | obj-$(CONFIG_PPC_85xx) += 85xx/ | 15 | obj-$(CONFIG_FSL_SOC_BOOKE) += 85xx/ |
16 | obj-$(CONFIG_PPC_86xx) += 86xx/ | 16 | obj-$(CONFIG_PPC_86xx) += 86xx/ |
17 | obj-$(CONFIG_PPC_PSERIES) += pseries/ | 17 | obj-$(CONFIG_PPC_PSERIES) += pseries/ |
18 | obj-$(CONFIG_PPC_ISERIES) += iseries/ | 18 | obj-$(CONFIG_PPC_ISERIES) += iseries/ |
diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c index a86c34b3bb84..96fe896f6df3 100644 --- a/arch/powerpc/platforms/cell/axon_msi.c +++ b/arch/powerpc/platforms/cell/axon_msi.c | |||
@@ -312,7 +312,7 @@ static struct irq_chip msic_irq_chip = { | |||
312 | .mask = mask_msi_irq, | 312 | .mask = mask_msi_irq, |
313 | .unmask = unmask_msi_irq, | 313 | .unmask = unmask_msi_irq, |
314 | .shutdown = unmask_msi_irq, | 314 | .shutdown = unmask_msi_irq, |
315 | .typename = "AXON-MSI", | 315 | .name = "AXON-MSI", |
316 | }; | 316 | }; |
317 | 317 | ||
318 | static int msic_host_map(struct irq_host *h, unsigned int virq, | 318 | static int msic_host_map(struct irq_host *h, unsigned int virq, |
diff --git a/arch/powerpc/platforms/cell/beat_interrupt.c b/arch/powerpc/platforms/cell/beat_interrupt.c index 72254848a228..36052a9ebcda 100644 --- a/arch/powerpc/platforms/cell/beat_interrupt.c +++ b/arch/powerpc/platforms/cell/beat_interrupt.c | |||
@@ -110,7 +110,7 @@ static void beatic_end_irq(unsigned int irq_plug) | |||
110 | } | 110 | } |
111 | 111 | ||
112 | static struct irq_chip beatic_pic = { | 112 | static struct irq_chip beatic_pic = { |
113 | .typename = " CELL-BEAT ", | 113 | .name = " CELL-BEAT ", |
114 | .unmask = beatic_unmask_irq, | 114 | .unmask = beatic_unmask_irq, |
115 | .mask = beatic_mask_irq, | 115 | .mask = beatic_mask_irq, |
116 | .eoi = beatic_end_irq, | 116 | .eoi = beatic_end_irq, |
@@ -136,7 +136,7 @@ static void beatic_pic_host_unmap(struct irq_host *h, unsigned int virq) | |||
136 | static int beatic_pic_host_map(struct irq_host *h, unsigned int virq, | 136 | static int beatic_pic_host_map(struct irq_host *h, unsigned int virq, |
137 | irq_hw_number_t hw) | 137 | irq_hw_number_t hw) |
138 | { | 138 | { |
139 | struct irq_desc *desc = get_irq_desc(virq); | 139 | struct irq_desc *desc = irq_to_desc(virq); |
140 | int64_t err; | 140 | int64_t err; |
141 | 141 | ||
142 | err = beat_construct_and_connect_irq_plug(virq, hw); | 142 | err = beat_construct_and_connect_irq_plug(virq, hw); |
@@ -166,11 +166,11 @@ static void beatic_pic_host_remap(struct irq_host *h, unsigned int virq, | |||
166 | * Note: We have only 1 entry to translate. | 166 | * Note: We have only 1 entry to translate. |
167 | */ | 167 | */ |
168 | static int beatic_pic_host_xlate(struct irq_host *h, struct device_node *ct, | 168 | static int beatic_pic_host_xlate(struct irq_host *h, struct device_node *ct, |
169 | u32 *intspec, unsigned int intsize, | 169 | const u32 *intspec, unsigned int intsize, |
170 | irq_hw_number_t *out_hwirq, | 170 | irq_hw_number_t *out_hwirq, |
171 | unsigned int *out_flags) | 171 | unsigned int *out_flags) |
172 | { | 172 | { |
173 | u64 *intspec2 = (u64 *)intspec; | 173 | const u64 *intspec2 = (const u64 *)intspec; |
174 | 174 | ||
175 | *out_hwirq = *intspec2; | 175 | *out_hwirq = *intspec2; |
176 | *out_flags |= IRQ_TYPE_LEVEL_LOW; | 176 | *out_flags |= IRQ_TYPE_LEVEL_LOW; |
diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c index 882e47080e74..f9dbf76a763f 100644 --- a/arch/powerpc/platforms/cell/interrupt.c +++ b/arch/powerpc/platforms/cell/interrupt.c | |||
@@ -88,7 +88,7 @@ static void iic_eoi(unsigned int irq) | |||
88 | } | 88 | } |
89 | 89 | ||
90 | static struct irq_chip iic_chip = { | 90 | static struct irq_chip iic_chip = { |
91 | .typename = " CELL-IIC ", | 91 | .name = " CELL-IIC ", |
92 | .mask = iic_mask, | 92 | .mask = iic_mask, |
93 | .unmask = iic_unmask, | 93 | .unmask = iic_unmask, |
94 | .eoi = iic_eoi, | 94 | .eoi = iic_eoi, |
@@ -133,7 +133,7 @@ static void iic_ioexc_cascade(unsigned int irq, struct irq_desc *desc) | |||
133 | 133 | ||
134 | 134 | ||
135 | static struct irq_chip iic_ioexc_chip = { | 135 | static struct irq_chip iic_ioexc_chip = { |
136 | .typename = " CELL-IOEX", | 136 | .name = " CELL-IOEX", |
137 | .mask = iic_mask, | 137 | .mask = iic_mask, |
138 | .unmask = iic_unmask, | 138 | .unmask = iic_unmask, |
139 | .eoi = iic_ioexc_eoi, | 139 | .eoi = iic_ioexc_eoi, |
@@ -297,7 +297,7 @@ static int iic_host_map(struct irq_host *h, unsigned int virq, | |||
297 | } | 297 | } |
298 | 298 | ||
299 | static int iic_host_xlate(struct irq_host *h, struct device_node *ct, | 299 | static int iic_host_xlate(struct irq_host *h, struct device_node *ct, |
300 | u32 *intspec, unsigned int intsize, | 300 | const u32 *intspec, unsigned int intsize, |
301 | irq_hw_number_t *out_hwirq, unsigned int *out_flags) | 301 | irq_hw_number_t *out_hwirq, unsigned int *out_flags) |
302 | 302 | ||
303 | { | 303 | { |
diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c index 4e5655624ae8..01244f254a11 100644 --- a/arch/powerpc/platforms/cell/spider-pic.c +++ b/arch/powerpc/platforms/cell/spider-pic.c | |||
@@ -102,7 +102,7 @@ static void spider_ack_irq(unsigned int virq) | |||
102 | 102 | ||
103 | /* Reset edge detection logic if necessary | 103 | /* Reset edge detection logic if necessary |
104 | */ | 104 | */ |
105 | if (get_irq_desc(virq)->status & IRQ_LEVEL) | 105 | if (irq_to_desc(virq)->status & IRQ_LEVEL) |
106 | return; | 106 | return; |
107 | 107 | ||
108 | /* Only interrupts 47 to 50 can be set to edge */ | 108 | /* Only interrupts 47 to 50 can be set to edge */ |
@@ -119,7 +119,7 @@ static int spider_set_irq_type(unsigned int virq, unsigned int type) | |||
119 | struct spider_pic *pic = spider_virq_to_pic(virq); | 119 | struct spider_pic *pic = spider_virq_to_pic(virq); |
120 | unsigned int hw = irq_map[virq].hwirq; | 120 | unsigned int hw = irq_map[virq].hwirq; |
121 | void __iomem *cfg = spider_get_irq_config(pic, hw); | 121 | void __iomem *cfg = spider_get_irq_config(pic, hw); |
122 | struct irq_desc *desc = get_irq_desc(virq); | 122 | struct irq_desc *desc = irq_to_desc(virq); |
123 | u32 old_mask; | 123 | u32 old_mask; |
124 | u32 ic; | 124 | u32 ic; |
125 | 125 | ||
@@ -168,7 +168,7 @@ static int spider_set_irq_type(unsigned int virq, unsigned int type) | |||
168 | } | 168 | } |
169 | 169 | ||
170 | static struct irq_chip spider_pic = { | 170 | static struct irq_chip spider_pic = { |
171 | .typename = " SPIDER ", | 171 | .name = " SPIDER ", |
172 | .unmask = spider_unmask_irq, | 172 | .unmask = spider_unmask_irq, |
173 | .mask = spider_mask_irq, | 173 | .mask = spider_mask_irq, |
174 | .ack = spider_ack_irq, | 174 | .ack = spider_ack_irq, |
@@ -187,7 +187,7 @@ static int spider_host_map(struct irq_host *h, unsigned int virq, | |||
187 | } | 187 | } |
188 | 188 | ||
189 | static int spider_host_xlate(struct irq_host *h, struct device_node *ct, | 189 | static int spider_host_xlate(struct irq_host *h, struct device_node *ct, |
190 | u32 *intspec, unsigned int intsize, | 190 | const u32 *intspec, unsigned int intsize, |
191 | irq_hw_number_t *out_hwirq, unsigned int *out_flags) | 191 | irq_hw_number_t *out_hwirq, unsigned int *out_flags) |
192 | 192 | ||
193 | { | 193 | { |
diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index 884e8bcec499..64a4c2d85f7c 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c | |||
@@ -2494,7 +2494,7 @@ static ssize_t spufs_switch_log_read(struct file *file, char __user *buf, | |||
2494 | struct spu_context *ctx = SPUFS_I(inode)->i_ctx; | 2494 | struct spu_context *ctx = SPUFS_I(inode)->i_ctx; |
2495 | int error = 0, cnt = 0; | 2495 | int error = 0, cnt = 0; |
2496 | 2496 | ||
2497 | if (!buf || len < 0) | 2497 | if (!buf) |
2498 | return -EINVAL; | 2498 | return -EINVAL; |
2499 | 2499 | ||
2500 | error = spu_acquire(ctx); | 2500 | error = spu_acquire(ctx); |
diff --git a/arch/powerpc/platforms/chrp/Kconfig b/arch/powerpc/platforms/chrp/Kconfig index 37d438bd5b7a..bc0b0efdc5fe 100644 --- a/arch/powerpc/platforms/chrp/Kconfig +++ b/arch/powerpc/platforms/chrp/Kconfig | |||
@@ -5,6 +5,8 @@ config PPC_CHRP | |||
5 | select PPC_I8259 | 5 | select PPC_I8259 |
6 | select PPC_INDIRECT_PCI | 6 | select PPC_INDIRECT_PCI |
7 | select PPC_RTAS | 7 | select PPC_RTAS |
8 | select PPC_RTAS_DAEMON | ||
9 | select RTAS_ERROR_LOGGING | ||
8 | select PPC_MPC106 | 10 | select PPC_MPC106 |
9 | select PPC_UDBG_16550 | 11 | select PPC_UDBG_16550 |
10 | select PPC_NATIVE | 12 | select PPC_NATIVE |
diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c index cd4ad9aea760..52f3df3b4ca0 100644 --- a/arch/powerpc/platforms/chrp/setup.c +++ b/arch/powerpc/platforms/chrp/setup.c | |||
@@ -364,19 +364,6 @@ void __init chrp_setup_arch(void) | |||
364 | if (ppc_md.progress) ppc_md.progress("Linux/PPC "UTS_RELEASE"\n", 0x0); | 364 | if (ppc_md.progress) ppc_md.progress("Linux/PPC "UTS_RELEASE"\n", 0x0); |
365 | } | 365 | } |
366 | 366 | ||
367 | void | ||
368 | chrp_event_scan(unsigned long unused) | ||
369 | { | ||
370 | unsigned char log[1024]; | ||
371 | int ret = 0; | ||
372 | |||
373 | /* XXX: we should loop until the hardware says no more error logs -- Cort */ | ||
374 | rtas_call(rtas_token("event-scan"), 4, 1, &ret, 0xffffffff, 0, | ||
375 | __pa(log), 1024); | ||
376 | mod_timer(&__get_cpu_var(heartbeat_timer), | ||
377 | jiffies + event_scan_interval); | ||
378 | } | ||
379 | |||
380 | static void chrp_8259_cascade(unsigned int irq, struct irq_desc *desc) | 367 | static void chrp_8259_cascade(unsigned int irq, struct irq_desc *desc) |
381 | { | 368 | { |
382 | unsigned int cascade_irq = i8259_irq(); | 369 | unsigned int cascade_irq = i8259_irq(); |
@@ -568,9 +555,6 @@ void __init chrp_init_IRQ(void) | |||
568 | void __init | 555 | void __init |
569 | chrp_init2(void) | 556 | chrp_init2(void) |
570 | { | 557 | { |
571 | struct device_node *device; | ||
572 | const unsigned int *p = NULL; | ||
573 | |||
574 | #ifdef CONFIG_NVRAM | 558 | #ifdef CONFIG_NVRAM |
575 | chrp_nvram_init(); | 559 | chrp_nvram_init(); |
576 | #endif | 560 | #endif |
@@ -582,40 +566,6 @@ chrp_init2(void) | |||
582 | request_region(0x80,0x10,"dma page reg"); | 566 | request_region(0x80,0x10,"dma page reg"); |
583 | request_region(0xc0,0x20,"dma2"); | 567 | request_region(0xc0,0x20,"dma2"); |
584 | 568 | ||
585 | /* Get the event scan rate for the rtas so we know how | ||
586 | * often it expects a heartbeat. -- Cort | ||
587 | */ | ||
588 | device = of_find_node_by_name(NULL, "rtas"); | ||
589 | if (device) | ||
590 | p = of_get_property(device, "rtas-event-scan-rate", NULL); | ||
591 | if (p && *p) { | ||
592 | /* | ||
593 | * Arrange to call chrp_event_scan at least *p times | ||
594 | * per minute. We use 59 rather than 60 here so that | ||
595 | * the rate will be slightly higher than the minimum. | ||
596 | * This all assumes we don't do hotplug CPU on any | ||
597 | * machine that needs the event scans done. | ||
598 | */ | ||
599 | unsigned long interval, offset; | ||
600 | int cpu, ncpus; | ||
601 | struct timer_list *timer; | ||
602 | |||
603 | interval = HZ * 59 / *p; | ||
604 | offset = HZ; | ||
605 | ncpus = num_online_cpus(); | ||
606 | event_scan_interval = ncpus * interval; | ||
607 | for (cpu = 0; cpu < ncpus; ++cpu) { | ||
608 | timer = &per_cpu(heartbeat_timer, cpu); | ||
609 | setup_timer(timer, chrp_event_scan, 0); | ||
610 | timer->expires = jiffies + offset; | ||
611 | add_timer_on(timer, cpu); | ||
612 | offset += interval; | ||
613 | } | ||
614 | printk("RTAS Event Scan Rate: %u (%lu jiffies)\n", | ||
615 | *p, interval); | ||
616 | } | ||
617 | of_node_put(device); | ||
618 | |||
619 | if (ppc_md.progress) | 569 | if (ppc_md.progress) |
620 | ppc_md.progress(" Have fun! ", 0x7777); | 570 | ppc_md.progress(" Have fun! ", 0x7777); |
621 | } | 571 | } |
diff --git a/arch/powerpc/platforms/iseries/htab.c b/arch/powerpc/platforms/iseries/htab.c index f99c6c4b6985..3ae66ab9d5e7 100644 --- a/arch/powerpc/platforms/iseries/htab.c +++ b/arch/powerpc/platforms/iseries/htab.c | |||
@@ -19,8 +19,7 @@ | |||
19 | 19 | ||
20 | #include "call_hpt.h" | 20 | #include "call_hpt.h" |
21 | 21 | ||
22 | static spinlock_t iSeries_hlocks[64] __cacheline_aligned_in_smp = | 22 | static spinlock_t iSeries_hlocks[64] __cacheline_aligned_in_smp; |
23 | { [0 ... 63] = SPIN_LOCK_UNLOCKED}; | ||
24 | 23 | ||
25 | /* | 24 | /* |
26 | * Very primitive algorithm for picking up a lock | 25 | * Very primitive algorithm for picking up a lock |
@@ -245,6 +244,11 @@ static void iSeries_hpte_invalidate(unsigned long slot, unsigned long va, | |||
245 | 244 | ||
246 | void __init hpte_init_iSeries(void) | 245 | void __init hpte_init_iSeries(void) |
247 | { | 246 | { |
247 | int i; | ||
248 | |||
249 | for (i = 0; i < ARRAY_SIZE(iSeries_hlocks); i++) | ||
250 | spin_lock_init(&iSeries_hlocks[i]); | ||
251 | |||
248 | ppc_md.hpte_invalidate = iSeries_hpte_invalidate; | 252 | ppc_md.hpte_invalidate = iSeries_hpte_invalidate; |
249 | ppc_md.hpte_updatepp = iSeries_hpte_updatepp; | 253 | ppc_md.hpte_updatepp = iSeries_hpte_updatepp; |
250 | ppc_md.hpte_updateboltedpp = iSeries_hpte_updateboltedpp; | 254 | ppc_md.hpte_updateboltedpp = iSeries_hpte_updateboltedpp; |
diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c index 94f444758836..07762259c60a 100644 --- a/arch/powerpc/platforms/iseries/irq.c +++ b/arch/powerpc/platforms/iseries/irq.c | |||
@@ -214,7 +214,7 @@ void __init iSeries_activate_IRQs() | |||
214 | unsigned long flags; | 214 | unsigned long flags; |
215 | 215 | ||
216 | for_each_irq (irq) { | 216 | for_each_irq (irq) { |
217 | struct irq_desc *desc = get_irq_desc(irq); | 217 | struct irq_desc *desc = irq_to_desc(irq); |
218 | 218 | ||
219 | if (desc && desc->chip && desc->chip->startup) { | 219 | if (desc && desc->chip && desc->chip->startup) { |
220 | spin_lock_irqsave(&desc->lock, flags); | 220 | spin_lock_irqsave(&desc->lock, flags); |
@@ -273,7 +273,7 @@ static void iseries_end_IRQ(unsigned int irq) | |||
273 | } | 273 | } |
274 | 274 | ||
275 | static struct irq_chip iseries_pic = { | 275 | static struct irq_chip iseries_pic = { |
276 | .typename = "iSeries irq controller", | 276 | .name = "iSeries irq controller", |
277 | .startup = iseries_startup_IRQ, | 277 | .startup = iseries_startup_IRQ, |
278 | .shutdown = iseries_shutdown_IRQ, | 278 | .shutdown = iseries_shutdown_IRQ, |
279 | .unmask = iseries_enable_IRQ, | 279 | .unmask = iseries_enable_IRQ, |
diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c index d212006a5b3c..09e827296276 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c | |||
@@ -152,12 +152,12 @@ static unsigned int pmac_startup_irq(unsigned int virq) | |||
152 | unsigned long bit = 1UL << (src & 0x1f); | 152 | unsigned long bit = 1UL << (src & 0x1f); |
153 | int i = src >> 5; | 153 | int i = src >> 5; |
154 | 154 | ||
155 | spin_lock_irqsave(&pmac_pic_lock, flags); | 155 | spin_lock_irqsave(&pmac_pic_lock, flags); |
156 | if ((irq_desc[virq].status & IRQ_LEVEL) == 0) | 156 | if ((irq_to_desc(virq)->status & IRQ_LEVEL) == 0) |
157 | out_le32(&pmac_irq_hw[i]->ack, bit); | 157 | out_le32(&pmac_irq_hw[i]->ack, bit); |
158 | __set_bit(src, ppc_cached_irq_mask); | 158 | __set_bit(src, ppc_cached_irq_mask); |
159 | __pmac_set_irq_mask(src, 0); | 159 | __pmac_set_irq_mask(src, 0); |
160 | spin_unlock_irqrestore(&pmac_pic_lock, flags); | 160 | spin_unlock_irqrestore(&pmac_pic_lock, flags); |
161 | 161 | ||
162 | return 0; | 162 | return 0; |
163 | } | 163 | } |
@@ -195,7 +195,7 @@ static int pmac_retrigger(unsigned int virq) | |||
195 | } | 195 | } |
196 | 196 | ||
197 | static struct irq_chip pmac_pic = { | 197 | static struct irq_chip pmac_pic = { |
198 | .typename = " PMAC-PIC ", | 198 | .name = " PMAC-PIC ", |
199 | .startup = pmac_startup_irq, | 199 | .startup = pmac_startup_irq, |
200 | .mask = pmac_mask_irq, | 200 | .mask = pmac_mask_irq, |
201 | .ack = pmac_ack_irq, | 201 | .ack = pmac_ack_irq, |
@@ -285,7 +285,7 @@ static int pmac_pic_host_match(struct irq_host *h, struct device_node *node) | |||
285 | static int pmac_pic_host_map(struct irq_host *h, unsigned int virq, | 285 | static int pmac_pic_host_map(struct irq_host *h, unsigned int virq, |
286 | irq_hw_number_t hw) | 286 | irq_hw_number_t hw) |
287 | { | 287 | { |
288 | struct irq_desc *desc = get_irq_desc(virq); | 288 | struct irq_desc *desc = irq_to_desc(virq); |
289 | int level; | 289 | int level; |
290 | 290 | ||
291 | if (hw >= max_irqs) | 291 | if (hw >= max_irqs) |
@@ -303,7 +303,7 @@ static int pmac_pic_host_map(struct irq_host *h, unsigned int virq, | |||
303 | } | 303 | } |
304 | 304 | ||
305 | static int pmac_pic_host_xlate(struct irq_host *h, struct device_node *ct, | 305 | static int pmac_pic_host_xlate(struct irq_host *h, struct device_node *ct, |
306 | u32 *intspec, unsigned int intsize, | 306 | const u32 *intspec, unsigned int intsize, |
307 | irq_hw_number_t *out_hwirq, | 307 | irq_hw_number_t *out_hwirq, |
308 | unsigned int *out_flags) | 308 | unsigned int *out_flags) |
309 | 309 | ||
diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c index 8ec5ccf76b19..59d9712d7364 100644 --- a/arch/powerpc/platforms/ps3/interrupt.c +++ b/arch/powerpc/platforms/ps3/interrupt.c | |||
@@ -152,7 +152,7 @@ static void ps3_chip_eoi(unsigned int virq) | |||
152 | */ | 152 | */ |
153 | 153 | ||
154 | static struct irq_chip ps3_irq_chip = { | 154 | static struct irq_chip ps3_irq_chip = { |
155 | .typename = "ps3", | 155 | .name = "ps3", |
156 | .mask = ps3_chip_mask, | 156 | .mask = ps3_chip_mask, |
157 | .unmask = ps3_chip_unmask, | 157 | .unmask = ps3_chip_unmask, |
158 | .eoi = ps3_chip_eoi, | 158 | .eoi = ps3_chip_eoi, |
diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c index 189a25b80735..e81b028a2a48 100644 --- a/arch/powerpc/platforms/ps3/mm.c +++ b/arch/powerpc/platforms/ps3/mm.c | |||
@@ -34,7 +34,7 @@ | |||
34 | #if defined(DEBUG) | 34 | #if defined(DEBUG) |
35 | #define DBG udbg_printf | 35 | #define DBG udbg_printf |
36 | #else | 36 | #else |
37 | #define DBG pr_debug | 37 | #define DBG pr_devel |
38 | #endif | 38 | #endif |
39 | 39 | ||
40 | enum { | 40 | enum { |
diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig index f0e6f28427bd..27554c807fd5 100644 --- a/arch/powerpc/platforms/pseries/Kconfig +++ b/arch/powerpc/platforms/pseries/Kconfig | |||
@@ -4,6 +4,7 @@ config PPC_PSERIES | |||
4 | select MPIC | 4 | select MPIC |
5 | select PPC_I8259 | 5 | select PPC_I8259 |
6 | select PPC_RTAS | 6 | select PPC_RTAS |
7 | select PPC_RTAS_DAEMON | ||
7 | select RTAS_ERROR_LOGGING | 8 | select RTAS_ERROR_LOGGING |
8 | select PPC_UDBG_16550 | 9 | select PPC_UDBG_16550 |
9 | select PPC_NATIVE | 10 | select PPC_NATIVE |
@@ -59,7 +60,7 @@ config PPC_SMLPAR | |||
59 | 60 | ||
60 | config CMM | 61 | config CMM |
61 | tristate "Collaborative memory management" | 62 | tristate "Collaborative memory management" |
62 | depends on PPC_SMLPAR && !CRASH_DUMP | 63 | depends on PPC_SMLPAR |
63 | default y | 64 | default y |
64 | help | 65 | help |
65 | Select this option, if you want to enable the kernel interface | 66 | Select this option, if you want to enable the kernel interface |
diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile index 790c0b872d4f..0ff5174ae4f5 100644 --- a/arch/powerpc/platforms/pseries/Makefile +++ b/arch/powerpc/platforms/pseries/Makefile | |||
@@ -7,8 +7,8 @@ EXTRA_CFLAGS += -DDEBUG | |||
7 | endif | 7 | endif |
8 | 8 | ||
9 | obj-y := lpar.o hvCall.o nvram.o reconfig.o \ | 9 | obj-y := lpar.o hvCall.o nvram.o reconfig.o \ |
10 | setup.o iommu.o ras.o rtasd.o \ | 10 | setup.o iommu.o ras.o \ |
11 | firmware.o power.o | 11 | firmware.o power.o dlpar.o |
12 | obj-$(CONFIG_SMP) += smp.o | 12 | obj-$(CONFIG_SMP) += smp.o |
13 | obj-$(CONFIG_XICS) += xics.o | 13 | obj-$(CONFIG_XICS) += xics.o |
14 | obj-$(CONFIG_SCANLOG) += scanlog.o | 14 | obj-$(CONFIG_SCANLOG) += scanlog.o |
diff --git a/arch/powerpc/platforms/pseries/cmm.c b/arch/powerpc/platforms/pseries/cmm.c index 6567439fe78d..bcdcf0ccc8d7 100644 --- a/arch/powerpc/platforms/pseries/cmm.c +++ b/arch/powerpc/platforms/pseries/cmm.c | |||
@@ -229,8 +229,9 @@ static void cmm_get_mpp(void) | |||
229 | { | 229 | { |
230 | int rc; | 230 | int rc; |
231 | struct hvcall_mpp_data mpp_data; | 231 | struct hvcall_mpp_data mpp_data; |
232 | unsigned long active_pages_target; | 232 | signed long active_pages_target, page_loan_request, target; |
233 | signed long page_loan_request; | 233 | signed long total_pages = totalram_pages + loaned_pages; |
234 | signed long min_mem_pages = (min_mem_mb * 1024 * 1024) / PAGE_SIZE; | ||
234 | 235 | ||
235 | rc = h_get_mpp(&mpp_data); | 236 | rc = h_get_mpp(&mpp_data); |
236 | 237 | ||
@@ -238,17 +239,25 @@ static void cmm_get_mpp(void) | |||
238 | return; | 239 | return; |
239 | 240 | ||
240 | page_loan_request = div_s64((s64)mpp_data.loan_request, PAGE_SIZE); | 241 | page_loan_request = div_s64((s64)mpp_data.loan_request, PAGE_SIZE); |
241 | loaned_pages_target = page_loan_request + loaned_pages; | 242 | target = page_loan_request + (signed long)loaned_pages; |
242 | if (loaned_pages_target > oom_freed_pages) | 243 | |
243 | loaned_pages_target -= oom_freed_pages; | 244 | if (target < 0 || total_pages < min_mem_pages) |
245 | target = 0; | ||
246 | |||
247 | if (target > oom_freed_pages) | ||
248 | target -= oom_freed_pages; | ||
244 | else | 249 | else |
245 | loaned_pages_target = 0; | 250 | target = 0; |
251 | |||
252 | active_pages_target = total_pages - target; | ||
253 | |||
254 | if (min_mem_pages > active_pages_target) | ||
255 | target = total_pages - min_mem_pages; | ||
246 | 256 | ||
247 | active_pages_target = totalram_pages + loaned_pages - loaned_pages_target; | 257 | if (target < 0) |
258 | target = 0; | ||
248 | 259 | ||
249 | if ((min_mem_mb * 1024 * 1024) > (active_pages_target * PAGE_SIZE)) | 260 | loaned_pages_target = target; |
250 | loaned_pages_target = totalram_pages + loaned_pages - | ||
251 | ((min_mem_mb * 1024 * 1024) / PAGE_SIZE); | ||
252 | 261 | ||
253 | cmm_dbg("delta = %ld, loaned = %lu, target = %lu, oom = %lu, totalram = %lu\n", | 262 | cmm_dbg("delta = %ld, loaned = %lu, target = %lu, oom = %lu, totalram = %lu\n", |
254 | page_loan_request, loaned_pages, loaned_pages_target, | 263 | page_loan_request, loaned_pages, loaned_pages_target, |
diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c new file mode 100644 index 000000000000..12df9e8812a9 --- /dev/null +++ b/arch/powerpc/platforms/pseries/dlpar.c | |||
@@ -0,0 +1,558 @@ | |||
1 | /* | ||
2 | * Support for dynamic reconfiguration for PCI, Memory, and CPU | ||
3 | * Hotplug and Dynamic Logical Partitioning on RPA platforms. | ||
4 | * | ||
5 | * Copyright (C) 2009 Nathan Fontenot | ||
6 | * Copyright (C) 2009 IBM Corporation | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License version | ||
10 | * 2 as published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/kref.h> | ||
15 | #include <linux/notifier.h> | ||
16 | #include <linux/proc_fs.h> | ||
17 | #include <linux/spinlock.h> | ||
18 | #include <linux/cpu.h> | ||
19 | #include "offline_states.h" | ||
20 | |||
21 | #include <asm/prom.h> | ||
22 | #include <asm/machdep.h> | ||
23 | #include <asm/uaccess.h> | ||
24 | #include <asm/rtas.h> | ||
25 | #include <asm/pSeries_reconfig.h> | ||
26 | |||
27 | struct cc_workarea { | ||
28 | u32 drc_index; | ||
29 | u32 zero; | ||
30 | u32 name_offset; | ||
31 | u32 prop_length; | ||
32 | u32 prop_offset; | ||
33 | }; | ||
34 | |||
35 | static void dlpar_free_cc_property(struct property *prop) | ||
36 | { | ||
37 | kfree(prop->name); | ||
38 | kfree(prop->value); | ||
39 | kfree(prop); | ||
40 | } | ||
41 | |||
42 | static struct property *dlpar_parse_cc_property(struct cc_workarea *ccwa) | ||
43 | { | ||
44 | struct property *prop; | ||
45 | char *name; | ||
46 | char *value; | ||
47 | |||
48 | prop = kzalloc(sizeof(*prop), GFP_KERNEL); | ||
49 | if (!prop) | ||
50 | return NULL; | ||
51 | |||
52 | name = (char *)ccwa + ccwa->name_offset; | ||
53 | prop->name = kstrdup(name, GFP_KERNEL); | ||
54 | |||
55 | prop->length = ccwa->prop_length; | ||
56 | value = (char *)ccwa + ccwa->prop_offset; | ||
57 | prop->value = kzalloc(prop->length, GFP_KERNEL); | ||
58 | if (!prop->value) { | ||
59 | dlpar_free_cc_property(prop); | ||
60 | return NULL; | ||
61 | } | ||
62 | |||
63 | memcpy(prop->value, value, prop->length); | ||
64 | return prop; | ||
65 | } | ||
66 | |||
67 | static struct device_node *dlpar_parse_cc_node(struct cc_workarea *ccwa) | ||
68 | { | ||
69 | struct device_node *dn; | ||
70 | char *name; | ||
71 | |||
72 | dn = kzalloc(sizeof(*dn), GFP_KERNEL); | ||
73 | if (!dn) | ||
74 | return NULL; | ||
75 | |||
76 | /* The configure connector reported name does not contain a | ||
77 | * preceeding '/', so we allocate a buffer large enough to | ||
78 | * prepend this to the full_name. | ||
79 | */ | ||
80 | name = (char *)ccwa + ccwa->name_offset; | ||
81 | dn->full_name = kmalloc(strlen(name) + 2, GFP_KERNEL); | ||
82 | if (!dn->full_name) { | ||
83 | kfree(dn); | ||
84 | return NULL; | ||
85 | } | ||
86 | |||
87 | sprintf(dn->full_name, "/%s", name); | ||
88 | return dn; | ||
89 | } | ||
90 | |||
91 | static void dlpar_free_one_cc_node(struct device_node *dn) | ||
92 | { | ||
93 | struct property *prop; | ||
94 | |||
95 | while (dn->properties) { | ||
96 | prop = dn->properties; | ||
97 | dn->properties = prop->next; | ||
98 | dlpar_free_cc_property(prop); | ||
99 | } | ||
100 | |||
101 | kfree(dn->full_name); | ||
102 | kfree(dn); | ||
103 | } | ||
104 | |||
105 | static void dlpar_free_cc_nodes(struct device_node *dn) | ||
106 | { | ||
107 | if (dn->child) | ||
108 | dlpar_free_cc_nodes(dn->child); | ||
109 | |||
110 | if (dn->sibling) | ||
111 | dlpar_free_cc_nodes(dn->sibling); | ||
112 | |||
113 | dlpar_free_one_cc_node(dn); | ||
114 | } | ||
115 | |||
116 | #define NEXT_SIBLING 1 | ||
117 | #define NEXT_CHILD 2 | ||
118 | #define NEXT_PROPERTY 3 | ||
119 | #define PREV_PARENT 4 | ||
120 | #define MORE_MEMORY 5 | ||
121 | #define CALL_AGAIN -2 | ||
122 | #define ERR_CFG_USE -9003 | ||
123 | |||
124 | struct device_node *dlpar_configure_connector(u32 drc_index) | ||
125 | { | ||
126 | struct device_node *dn; | ||
127 | struct device_node *first_dn = NULL; | ||
128 | struct device_node *last_dn = NULL; | ||
129 | struct property *property; | ||
130 | struct property *last_property = NULL; | ||
131 | struct cc_workarea *ccwa; | ||
132 | int cc_token; | ||
133 | int rc; | ||
134 | |||
135 | cc_token = rtas_token("ibm,configure-connector"); | ||
136 | if (cc_token == RTAS_UNKNOWN_SERVICE) | ||
137 | return NULL; | ||
138 | |||
139 | spin_lock(&rtas_data_buf_lock); | ||
140 | ccwa = (struct cc_workarea *)&rtas_data_buf[0]; | ||
141 | ccwa->drc_index = drc_index; | ||
142 | ccwa->zero = 0; | ||
143 | |||
144 | rc = rtas_call(cc_token, 2, 1, NULL, rtas_data_buf, NULL); | ||
145 | while (rc) { | ||
146 | switch (rc) { | ||
147 | case NEXT_SIBLING: | ||
148 | dn = dlpar_parse_cc_node(ccwa); | ||
149 | if (!dn) | ||
150 | goto cc_error; | ||
151 | |||
152 | dn->parent = last_dn->parent; | ||
153 | last_dn->sibling = dn; | ||
154 | last_dn = dn; | ||
155 | break; | ||
156 | |||
157 | case NEXT_CHILD: | ||
158 | dn = dlpar_parse_cc_node(ccwa); | ||
159 | if (!dn) | ||
160 | goto cc_error; | ||
161 | |||
162 | if (!first_dn) | ||
163 | first_dn = dn; | ||
164 | else { | ||
165 | dn->parent = last_dn; | ||
166 | if (last_dn) | ||
167 | last_dn->child = dn; | ||
168 | } | ||
169 | |||
170 | last_dn = dn; | ||
171 | break; | ||
172 | |||
173 | case NEXT_PROPERTY: | ||
174 | property = dlpar_parse_cc_property(ccwa); | ||
175 | if (!property) | ||
176 | goto cc_error; | ||
177 | |||
178 | if (!last_dn->properties) | ||
179 | last_dn->properties = property; | ||
180 | else | ||
181 | last_property->next = property; | ||
182 | |||
183 | last_property = property; | ||
184 | break; | ||
185 | |||
186 | case PREV_PARENT: | ||
187 | last_dn = last_dn->parent; | ||
188 | break; | ||
189 | |||
190 | case CALL_AGAIN: | ||
191 | break; | ||
192 | |||
193 | case MORE_MEMORY: | ||
194 | case ERR_CFG_USE: | ||
195 | default: | ||
196 | printk(KERN_ERR "Unexpected Error (%d) " | ||
197 | "returned from configure-connector\n", rc); | ||
198 | goto cc_error; | ||
199 | } | ||
200 | |||
201 | rc = rtas_call(cc_token, 2, 1, NULL, rtas_data_buf, NULL); | ||
202 | } | ||
203 | |||
204 | spin_unlock(&rtas_data_buf_lock); | ||
205 | return first_dn; | ||
206 | |||
207 | cc_error: | ||
208 | if (first_dn) | ||
209 | dlpar_free_cc_nodes(first_dn); | ||
210 | spin_unlock(&rtas_data_buf_lock); | ||
211 | return NULL; | ||
212 | } | ||
213 | |||
214 | static struct device_node *derive_parent(const char *path) | ||
215 | { | ||
216 | struct device_node *parent; | ||
217 | char *last_slash; | ||
218 | |||
219 | last_slash = strrchr(path, '/'); | ||
220 | if (last_slash == path) { | ||
221 | parent = of_find_node_by_path("/"); | ||
222 | } else { | ||
223 | char *parent_path; | ||
224 | int parent_path_len = last_slash - path + 1; | ||
225 | parent_path = kmalloc(parent_path_len, GFP_KERNEL); | ||
226 | if (!parent_path) | ||
227 | return NULL; | ||
228 | |||
229 | strlcpy(parent_path, path, parent_path_len); | ||
230 | parent = of_find_node_by_path(parent_path); | ||
231 | kfree(parent_path); | ||
232 | } | ||
233 | |||
234 | return parent; | ||
235 | } | ||
236 | |||
237 | int dlpar_attach_node(struct device_node *dn) | ||
238 | { | ||
239 | struct proc_dir_entry *ent; | ||
240 | int rc; | ||
241 | |||
242 | of_node_set_flag(dn, OF_DYNAMIC); | ||
243 | kref_init(&dn->kref); | ||
244 | dn->parent = derive_parent(dn->full_name); | ||
245 | if (!dn->parent) | ||
246 | return -ENOMEM; | ||
247 | |||
248 | rc = blocking_notifier_call_chain(&pSeries_reconfig_chain, | ||
249 | PSERIES_RECONFIG_ADD, dn); | ||
250 | if (rc == NOTIFY_BAD) { | ||
251 | printk(KERN_ERR "Failed to add device node %s\n", | ||
252 | dn->full_name); | ||
253 | return -ENOMEM; /* For now, safe to assume kmalloc failure */ | ||
254 | } | ||
255 | |||
256 | of_attach_node(dn); | ||
257 | |||
258 | #ifdef CONFIG_PROC_DEVICETREE | ||
259 | ent = proc_mkdir(strrchr(dn->full_name, '/') + 1, dn->parent->pde); | ||
260 | if (ent) | ||
261 | proc_device_tree_add_node(dn, ent); | ||
262 | #endif | ||
263 | |||
264 | of_node_put(dn->parent); | ||
265 | return 0; | ||
266 | } | ||
267 | |||
268 | int dlpar_detach_node(struct device_node *dn) | ||
269 | { | ||
270 | struct device_node *parent = dn->parent; | ||
271 | struct property *prop = dn->properties; | ||
272 | |||
273 | #ifdef CONFIG_PROC_DEVICETREE | ||
274 | while (prop) { | ||
275 | remove_proc_entry(prop->name, dn->pde); | ||
276 | prop = prop->next; | ||
277 | } | ||
278 | |||
279 | if (dn->pde) | ||
280 | remove_proc_entry(dn->pde->name, parent->pde); | ||
281 | #endif | ||
282 | |||
283 | blocking_notifier_call_chain(&pSeries_reconfig_chain, | ||
284 | PSERIES_RECONFIG_REMOVE, dn); | ||
285 | of_detach_node(dn); | ||
286 | of_node_put(dn); /* Must decrement the refcount */ | ||
287 | |||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | #define DR_ENTITY_SENSE 9003 | ||
292 | #define DR_ENTITY_PRESENT 1 | ||
293 | #define DR_ENTITY_UNUSABLE 2 | ||
294 | #define ALLOCATION_STATE 9003 | ||
295 | #define ALLOC_UNUSABLE 0 | ||
296 | #define ALLOC_USABLE 1 | ||
297 | #define ISOLATION_STATE 9001 | ||
298 | #define ISOLATE 0 | ||
299 | #define UNISOLATE 1 | ||
300 | |||
301 | int dlpar_acquire_drc(u32 drc_index) | ||
302 | { | ||
303 | int dr_status, rc; | ||
304 | |||
305 | rc = rtas_call(rtas_token("get-sensor-state"), 2, 2, &dr_status, | ||
306 | DR_ENTITY_SENSE, drc_index); | ||
307 | if (rc || dr_status != DR_ENTITY_UNUSABLE) | ||
308 | return -1; | ||
309 | |||
310 | rc = rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_USABLE); | ||
311 | if (rc) | ||
312 | return rc; | ||
313 | |||
314 | rc = rtas_set_indicator(ISOLATION_STATE, drc_index, UNISOLATE); | ||
315 | if (rc) { | ||
316 | rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_UNUSABLE); | ||
317 | return rc; | ||
318 | } | ||
319 | |||
320 | return 0; | ||
321 | } | ||
322 | |||
323 | int dlpar_release_drc(u32 drc_index) | ||
324 | { | ||
325 | int dr_status, rc; | ||
326 | |||
327 | rc = rtas_call(rtas_token("get-sensor-state"), 2, 2, &dr_status, | ||
328 | DR_ENTITY_SENSE, drc_index); | ||
329 | if (rc || dr_status != DR_ENTITY_PRESENT) | ||
330 | return -1; | ||
331 | |||
332 | rc = rtas_set_indicator(ISOLATION_STATE, drc_index, ISOLATE); | ||
333 | if (rc) | ||
334 | return rc; | ||
335 | |||
336 | rc = rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_UNUSABLE); | ||
337 | if (rc) { | ||
338 | rtas_set_indicator(ISOLATION_STATE, drc_index, UNISOLATE); | ||
339 | return rc; | ||
340 | } | ||
341 | |||
342 | return 0; | ||
343 | } | ||
344 | |||
345 | #ifdef CONFIG_ARCH_CPU_PROBE_RELEASE | ||
346 | |||
347 | static DEFINE_MUTEX(pseries_cpu_hotplug_mutex); | ||
348 | |||
349 | void cpu_hotplug_driver_lock() | ||
350 | { | ||
351 | mutex_lock(&pseries_cpu_hotplug_mutex); | ||
352 | } | ||
353 | |||
354 | void cpu_hotplug_driver_unlock() | ||
355 | { | ||
356 | mutex_unlock(&pseries_cpu_hotplug_mutex); | ||
357 | } | ||
358 | |||
359 | static int dlpar_online_cpu(struct device_node *dn) | ||
360 | { | ||
361 | int rc = 0; | ||
362 | unsigned int cpu; | ||
363 | int len, nthreads, i; | ||
364 | const u32 *intserv; | ||
365 | |||
366 | intserv = of_get_property(dn, "ibm,ppc-interrupt-server#s", &len); | ||
367 | if (!intserv) | ||
368 | return -EINVAL; | ||
369 | |||
370 | nthreads = len / sizeof(u32); | ||
371 | |||
372 | cpu_maps_update_begin(); | ||
373 | for (i = 0; i < nthreads; i++) { | ||
374 | for_each_present_cpu(cpu) { | ||
375 | if (get_hard_smp_processor_id(cpu) != intserv[i]) | ||
376 | continue; | ||
377 | BUG_ON(get_cpu_current_state(cpu) | ||
378 | != CPU_STATE_OFFLINE); | ||
379 | cpu_maps_update_done(); | ||
380 | rc = cpu_up(cpu); | ||
381 | if (rc) | ||
382 | goto out; | ||
383 | cpu_maps_update_begin(); | ||
384 | |||
385 | break; | ||
386 | } | ||
387 | if (cpu == num_possible_cpus()) | ||
388 | printk(KERN_WARNING "Could not find cpu to online " | ||
389 | "with physical id 0x%x\n", intserv[i]); | ||
390 | } | ||
391 | cpu_maps_update_done(); | ||
392 | |||
393 | out: | ||
394 | return rc; | ||
395 | |||
396 | } | ||
397 | |||
398 | static ssize_t dlpar_cpu_probe(const char *buf, size_t count) | ||
399 | { | ||
400 | struct device_node *dn; | ||
401 | unsigned long drc_index; | ||
402 | char *cpu_name; | ||
403 | int rc; | ||
404 | |||
405 | cpu_hotplug_driver_lock(); | ||
406 | rc = strict_strtoul(buf, 0, &drc_index); | ||
407 | if (rc) { | ||
408 | rc = -EINVAL; | ||
409 | goto out; | ||
410 | } | ||
411 | |||
412 | dn = dlpar_configure_connector(drc_index); | ||
413 | if (!dn) { | ||
414 | rc = -EINVAL; | ||
415 | goto out; | ||
416 | } | ||
417 | |||
418 | /* configure-connector reports cpus as living in the base | ||
419 | * directory of the device tree. CPUs actually live in the | ||
420 | * cpus directory so we need to fixup the full_name. | ||
421 | */ | ||
422 | cpu_name = kzalloc(strlen(dn->full_name) + strlen("/cpus") + 1, | ||
423 | GFP_KERNEL); | ||
424 | if (!cpu_name) { | ||
425 | dlpar_free_cc_nodes(dn); | ||
426 | rc = -ENOMEM; | ||
427 | goto out; | ||
428 | } | ||
429 | |||
430 | sprintf(cpu_name, "/cpus%s", dn->full_name); | ||
431 | kfree(dn->full_name); | ||
432 | dn->full_name = cpu_name; | ||
433 | |||
434 | rc = dlpar_acquire_drc(drc_index); | ||
435 | if (rc) { | ||
436 | dlpar_free_cc_nodes(dn); | ||
437 | rc = -EINVAL; | ||
438 | goto out; | ||
439 | } | ||
440 | |||
441 | rc = dlpar_attach_node(dn); | ||
442 | if (rc) { | ||
443 | dlpar_release_drc(drc_index); | ||
444 | dlpar_free_cc_nodes(dn); | ||
445 | } | ||
446 | |||
447 | rc = dlpar_online_cpu(dn); | ||
448 | out: | ||
449 | cpu_hotplug_driver_unlock(); | ||
450 | |||
451 | return rc ? rc : count; | ||
452 | } | ||
453 | |||
454 | static int dlpar_offline_cpu(struct device_node *dn) | ||
455 | { | ||
456 | int rc = 0; | ||
457 | unsigned int cpu; | ||
458 | int len, nthreads, i; | ||
459 | const u32 *intserv; | ||
460 | |||
461 | intserv = of_get_property(dn, "ibm,ppc-interrupt-server#s", &len); | ||
462 | if (!intserv) | ||
463 | return -EINVAL; | ||
464 | |||
465 | nthreads = len / sizeof(u32); | ||
466 | |||
467 | cpu_maps_update_begin(); | ||
468 | for (i = 0; i < nthreads; i++) { | ||
469 | for_each_present_cpu(cpu) { | ||
470 | if (get_hard_smp_processor_id(cpu) != intserv[i]) | ||
471 | continue; | ||
472 | |||
473 | if (get_cpu_current_state(cpu) == CPU_STATE_OFFLINE) | ||
474 | break; | ||
475 | |||
476 | if (get_cpu_current_state(cpu) == CPU_STATE_ONLINE) { | ||
477 | cpu_maps_update_done(); | ||
478 | rc = cpu_down(cpu); | ||
479 | if (rc) | ||
480 | goto out; | ||
481 | cpu_maps_update_begin(); | ||
482 | break; | ||
483 | |||
484 | } | ||
485 | |||
486 | /* | ||
487 | * The cpu is in CPU_STATE_INACTIVE. | ||
488 | * Upgrade it's state to CPU_STATE_OFFLINE. | ||
489 | */ | ||
490 | set_preferred_offline_state(cpu, CPU_STATE_OFFLINE); | ||
491 | BUG_ON(plpar_hcall_norets(H_PROD, intserv[i]) | ||
492 | != H_SUCCESS); | ||
493 | __cpu_die(cpu); | ||
494 | break; | ||
495 | } | ||
496 | if (cpu == num_possible_cpus()) | ||
497 | printk(KERN_WARNING "Could not find cpu to offline " | ||
498 | "with physical id 0x%x\n", intserv[i]); | ||
499 | } | ||
500 | cpu_maps_update_done(); | ||
501 | |||
502 | out: | ||
503 | return rc; | ||
504 | |||
505 | } | ||
506 | |||
507 | static ssize_t dlpar_cpu_release(const char *buf, size_t count) | ||
508 | { | ||
509 | struct device_node *dn; | ||
510 | const u32 *drc_index; | ||
511 | int rc; | ||
512 | |||
513 | dn = of_find_node_by_path(buf); | ||
514 | if (!dn) | ||
515 | return -EINVAL; | ||
516 | |||
517 | drc_index = of_get_property(dn, "ibm,my-drc-index", NULL); | ||
518 | if (!drc_index) { | ||
519 | of_node_put(dn); | ||
520 | return -EINVAL; | ||
521 | } | ||
522 | |||
523 | cpu_hotplug_driver_lock(); | ||
524 | rc = dlpar_offline_cpu(dn); | ||
525 | if (rc) { | ||
526 | of_node_put(dn); | ||
527 | rc = -EINVAL; | ||
528 | goto out; | ||
529 | } | ||
530 | |||
531 | rc = dlpar_release_drc(*drc_index); | ||
532 | if (rc) { | ||
533 | of_node_put(dn); | ||
534 | goto out; | ||
535 | } | ||
536 | |||
537 | rc = dlpar_detach_node(dn); | ||
538 | if (rc) { | ||
539 | dlpar_acquire_drc(*drc_index); | ||
540 | goto out; | ||
541 | } | ||
542 | |||
543 | of_node_put(dn); | ||
544 | out: | ||
545 | cpu_hotplug_driver_unlock(); | ||
546 | return rc ? rc : count; | ||
547 | } | ||
548 | |||
549 | static int __init pseries_dlpar_init(void) | ||
550 | { | ||
551 | ppc_md.cpu_probe = dlpar_cpu_probe; | ||
552 | ppc_md.cpu_release = dlpar_cpu_release; | ||
553 | |||
554 | return 0; | ||
555 | } | ||
556 | machine_device_initcall(pseries, pseries_dlpar_init); | ||
557 | |||
558 | #endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */ | ||
diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c index 0e8db6771252..ef8e45448480 100644 --- a/arch/powerpc/platforms/pseries/eeh_driver.c +++ b/arch/powerpc/platforms/pseries/eeh_driver.c | |||
@@ -63,22 +63,6 @@ static void print_device_node_tree(struct pci_dn *pdn, int dent) | |||
63 | } | 63 | } |
64 | #endif | 64 | #endif |
65 | 65 | ||
66 | /** | ||
67 | * irq_in_use - return true if this irq is being used | ||
68 | */ | ||
69 | static int irq_in_use(unsigned int irq) | ||
70 | { | ||
71 | int rc = 0; | ||
72 | unsigned long flags; | ||
73 | struct irq_desc *desc = irq_desc + irq; | ||
74 | |||
75 | spin_lock_irqsave(&desc->lock, flags); | ||
76 | if (desc->action) | ||
77 | rc = 1; | ||
78 | spin_unlock_irqrestore(&desc->lock, flags); | ||
79 | return rc; | ||
80 | } | ||
81 | |||
82 | /** | 66 | /** |
83 | * eeh_disable_irq - disable interrupt for the recovering device | 67 | * eeh_disable_irq - disable interrupt for the recovering device |
84 | */ | 68 | */ |
@@ -93,7 +77,7 @@ static void eeh_disable_irq(struct pci_dev *dev) | |||
93 | if (dev->msi_enabled || dev->msix_enabled) | 77 | if (dev->msi_enabled || dev->msix_enabled) |
94 | return; | 78 | return; |
95 | 79 | ||
96 | if (!irq_in_use(dev->irq)) | 80 | if (!irq_has_action(dev->irq)) |
97 | return; | 81 | return; |
98 | 82 | ||
99 | PCI_DN(dn)->eeh_mode |= EEH_MODE_IRQ_DISABLED; | 83 | PCI_DN(dn)->eeh_mode |= EEH_MODE_IRQ_DISABLED; |
diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c index ebff6d9a4e39..6ea4698d9176 100644 --- a/arch/powerpc/platforms/pseries/hotplug-cpu.c +++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <asm/pSeries_reconfig.h> | 30 | #include <asm/pSeries_reconfig.h> |
31 | #include "xics.h" | 31 | #include "xics.h" |
32 | #include "plpar_wrappers.h" | 32 | #include "plpar_wrappers.h" |
33 | #include "offline_states.h" | ||
33 | 34 | ||
34 | /* This version can't take the spinlock, because it never returns */ | 35 | /* This version can't take the spinlock, because it never returns */ |
35 | static struct rtas_args rtas_stop_self_args = { | 36 | static struct rtas_args rtas_stop_self_args = { |
@@ -39,6 +40,55 @@ static struct rtas_args rtas_stop_self_args = { | |||
39 | .rets = &rtas_stop_self_args.args[0], | 40 | .rets = &rtas_stop_self_args.args[0], |
40 | }; | 41 | }; |
41 | 42 | ||
43 | static DEFINE_PER_CPU(enum cpu_state_vals, preferred_offline_state) = | ||
44 | CPU_STATE_OFFLINE; | ||
45 | static DEFINE_PER_CPU(enum cpu_state_vals, current_state) = CPU_STATE_OFFLINE; | ||
46 | |||
47 | static enum cpu_state_vals default_offline_state = CPU_STATE_OFFLINE; | ||
48 | |||
49 | static int cede_offline_enabled __read_mostly = 1; | ||
50 | |||
51 | /* | ||
52 | * Enable/disable cede_offline when available. | ||
53 | */ | ||
54 | static int __init setup_cede_offline(char *str) | ||
55 | { | ||
56 | if (!strcmp(str, "off")) | ||
57 | cede_offline_enabled = 0; | ||
58 | else if (!strcmp(str, "on")) | ||
59 | cede_offline_enabled = 1; | ||
60 | else | ||
61 | return 0; | ||
62 | return 1; | ||
63 | } | ||
64 | |||
65 | __setup("cede_offline=", setup_cede_offline); | ||
66 | |||
67 | enum cpu_state_vals get_cpu_current_state(int cpu) | ||
68 | { | ||
69 | return per_cpu(current_state, cpu); | ||
70 | } | ||
71 | |||
72 | void set_cpu_current_state(int cpu, enum cpu_state_vals state) | ||
73 | { | ||
74 | per_cpu(current_state, cpu) = state; | ||
75 | } | ||
76 | |||
77 | enum cpu_state_vals get_preferred_offline_state(int cpu) | ||
78 | { | ||
79 | return per_cpu(preferred_offline_state, cpu); | ||
80 | } | ||
81 | |||
82 | void set_preferred_offline_state(int cpu, enum cpu_state_vals state) | ||
83 | { | ||
84 | per_cpu(preferred_offline_state, cpu) = state; | ||
85 | } | ||
86 | |||
87 | void set_default_offline_state(int cpu) | ||
88 | { | ||
89 | per_cpu(preferred_offline_state, cpu) = default_offline_state; | ||
90 | } | ||
91 | |||
42 | static void rtas_stop_self(void) | 92 | static void rtas_stop_self(void) |
43 | { | 93 | { |
44 | struct rtas_args *args = &rtas_stop_self_args; | 94 | struct rtas_args *args = &rtas_stop_self_args; |
@@ -56,11 +106,61 @@ static void rtas_stop_self(void) | |||
56 | 106 | ||
57 | static void pseries_mach_cpu_die(void) | 107 | static void pseries_mach_cpu_die(void) |
58 | { | 108 | { |
109 | unsigned int cpu = smp_processor_id(); | ||
110 | unsigned int hwcpu = hard_smp_processor_id(); | ||
111 | u8 cede_latency_hint = 0; | ||
112 | |||
59 | local_irq_disable(); | 113 | local_irq_disable(); |
60 | idle_task_exit(); | 114 | idle_task_exit(); |
61 | xics_teardown_cpu(); | 115 | xics_teardown_cpu(); |
62 | unregister_slb_shadow(hard_smp_processor_id(), __pa(get_slb_shadow())); | 116 | |
63 | rtas_stop_self(); | 117 | if (get_preferred_offline_state(cpu) == CPU_STATE_INACTIVE) { |
118 | set_cpu_current_state(cpu, CPU_STATE_INACTIVE); | ||
119 | cede_latency_hint = 2; | ||
120 | |||
121 | get_lppaca()->idle = 1; | ||
122 | if (!get_lppaca()->shared_proc) | ||
123 | get_lppaca()->donate_dedicated_cpu = 1; | ||
124 | |||
125 | printk(KERN_INFO | ||
126 | "cpu %u (hwid %u) ceding for offline with hint %d\n", | ||
127 | cpu, hwcpu, cede_latency_hint); | ||
128 | while (get_preferred_offline_state(cpu) == CPU_STATE_INACTIVE) { | ||
129 | extended_cede_processor(cede_latency_hint); | ||
130 | printk(KERN_INFO "cpu %u (hwid %u) returned from cede.\n", | ||
131 | cpu, hwcpu); | ||
132 | printk(KERN_INFO | ||
133 | "Decrementer value = %x Timebase value = %llx\n", | ||
134 | get_dec(), get_tb()); | ||
135 | } | ||
136 | |||
137 | printk(KERN_INFO "cpu %u (hwid %u) got prodded to go online\n", | ||
138 | cpu, hwcpu); | ||
139 | |||
140 | if (!get_lppaca()->shared_proc) | ||
141 | get_lppaca()->donate_dedicated_cpu = 0; | ||
142 | get_lppaca()->idle = 0; | ||
143 | } | ||
144 | |||
145 | if (get_preferred_offline_state(cpu) == CPU_STATE_ONLINE) { | ||
146 | unregister_slb_shadow(hwcpu, __pa(get_slb_shadow())); | ||
147 | |||
148 | /* | ||
149 | * NOTE: Calling start_secondary() here for now to | ||
150 | * start new context. | ||
151 | * However, need to do it cleanly by resetting the | ||
152 | * stack pointer. | ||
153 | */ | ||
154 | start_secondary(); | ||
155 | |||
156 | } else if (get_preferred_offline_state(cpu) == CPU_STATE_OFFLINE) { | ||
157 | |||
158 | set_cpu_current_state(cpu, CPU_STATE_OFFLINE); | ||
159 | unregister_slb_shadow(hard_smp_processor_id(), | ||
160 | __pa(get_slb_shadow())); | ||
161 | rtas_stop_self(); | ||
162 | } | ||
163 | |||
64 | /* Should never get here... */ | 164 | /* Should never get here... */ |
65 | BUG(); | 165 | BUG(); |
66 | for(;;); | 166 | for(;;); |
@@ -106,18 +206,43 @@ static int pseries_cpu_disable(void) | |||
106 | return 0; | 206 | return 0; |
107 | } | 207 | } |
108 | 208 | ||
209 | /* | ||
210 | * pseries_cpu_die: Wait for the cpu to die. | ||
211 | * @cpu: logical processor id of the CPU whose death we're awaiting. | ||
212 | * | ||
213 | * This function is called from the context of the thread which is performing | ||
214 | * the cpu-offline. Here we wait for long enough to allow the cpu in question | ||
215 | * to self-destroy so that the cpu-offline thread can send the CPU_DEAD | ||
216 | * notifications. | ||
217 | * | ||
218 | * OTOH, pseries_mach_cpu_die() is called by the @cpu when it wants to | ||
219 | * self-destruct. | ||
220 | */ | ||
109 | static void pseries_cpu_die(unsigned int cpu) | 221 | static void pseries_cpu_die(unsigned int cpu) |
110 | { | 222 | { |
111 | int tries; | 223 | int tries; |
112 | int cpu_status; | 224 | int cpu_status = 1; |
113 | unsigned int pcpu = get_hard_smp_processor_id(cpu); | 225 | unsigned int pcpu = get_hard_smp_processor_id(cpu); |
114 | 226 | ||
115 | for (tries = 0; tries < 25; tries++) { | 227 | if (get_preferred_offline_state(cpu) == CPU_STATE_INACTIVE) { |
116 | cpu_status = query_cpu_stopped(pcpu); | 228 | cpu_status = 1; |
117 | if (cpu_status == 0 || cpu_status == -1) | 229 | for (tries = 0; tries < 1000; tries++) { |
118 | break; | 230 | if (get_cpu_current_state(cpu) == CPU_STATE_INACTIVE) { |
119 | cpu_relax(); | 231 | cpu_status = 0; |
232 | break; | ||
233 | } | ||
234 | cpu_relax(); | ||
235 | } | ||
236 | } else if (get_preferred_offline_state(cpu) == CPU_STATE_OFFLINE) { | ||
237 | |||
238 | for (tries = 0; tries < 25; tries++) { | ||
239 | cpu_status = query_cpu_stopped(pcpu); | ||
240 | if (cpu_status == 0 || cpu_status == -1) | ||
241 | break; | ||
242 | cpu_relax(); | ||
243 | } | ||
120 | } | 244 | } |
245 | |||
121 | if (cpu_status != 0) { | 246 | if (cpu_status != 0) { |
122 | printk("Querying DEAD? cpu %i (%i) shows %i\n", | 247 | printk("Querying DEAD? cpu %i (%i) shows %i\n", |
123 | cpu, pcpu, cpu_status); | 248 | cpu, pcpu, cpu_status); |
@@ -252,10 +377,41 @@ static struct notifier_block pseries_smp_nb = { | |||
252 | .notifier_call = pseries_smp_notifier, | 377 | .notifier_call = pseries_smp_notifier, |
253 | }; | 378 | }; |
254 | 379 | ||
380 | #define MAX_CEDE_LATENCY_LEVELS 4 | ||
381 | #define CEDE_LATENCY_PARAM_LENGTH 10 | ||
382 | #define CEDE_LATENCY_PARAM_MAX_LENGTH \ | ||
383 | (MAX_CEDE_LATENCY_LEVELS * CEDE_LATENCY_PARAM_LENGTH * sizeof(char)) | ||
384 | #define CEDE_LATENCY_TOKEN 45 | ||
385 | |||
386 | static char cede_parameters[CEDE_LATENCY_PARAM_MAX_LENGTH]; | ||
387 | |||
388 | static int parse_cede_parameters(void) | ||
389 | { | ||
390 | int call_status; | ||
391 | |||
392 | memset(cede_parameters, 0, CEDE_LATENCY_PARAM_MAX_LENGTH); | ||
393 | call_status = rtas_call(rtas_token("ibm,get-system-parameter"), 3, 1, | ||
394 | NULL, | ||
395 | CEDE_LATENCY_TOKEN, | ||
396 | __pa(cede_parameters), | ||
397 | CEDE_LATENCY_PARAM_MAX_LENGTH); | ||
398 | |||
399 | if (call_status != 0) | ||
400 | printk(KERN_INFO "CEDE_LATENCY: \ | ||
401 | %s %s Error calling get-system-parameter(0x%x)\n", | ||
402 | __FILE__, __func__, call_status); | ||
403 | else | ||
404 | printk(KERN_INFO "CEDE_LATENCY: \ | ||
405 | get-system-parameter successful.\n"); | ||
406 | |||
407 | return call_status; | ||
408 | } | ||
409 | |||
255 | static int __init pseries_cpu_hotplug_init(void) | 410 | static int __init pseries_cpu_hotplug_init(void) |
256 | { | 411 | { |
257 | struct device_node *np; | 412 | struct device_node *np; |
258 | const char *typep; | 413 | const char *typep; |
414 | int cpu; | ||
259 | 415 | ||
260 | for_each_node_by_name(np, "interrupt-controller") { | 416 | for_each_node_by_name(np, "interrupt-controller") { |
261 | typep = of_get_property(np, "compatible", NULL); | 417 | typep = of_get_property(np, "compatible", NULL); |
@@ -283,8 +439,16 @@ static int __init pseries_cpu_hotplug_init(void) | |||
283 | smp_ops->cpu_die = pseries_cpu_die; | 439 | smp_ops->cpu_die = pseries_cpu_die; |
284 | 440 | ||
285 | /* Processors can be added/removed only on LPAR */ | 441 | /* Processors can be added/removed only on LPAR */ |
286 | if (firmware_has_feature(FW_FEATURE_LPAR)) | 442 | if (firmware_has_feature(FW_FEATURE_LPAR)) { |
287 | pSeries_reconfig_notifier_register(&pseries_smp_nb); | 443 | pSeries_reconfig_notifier_register(&pseries_smp_nb); |
444 | cpu_maps_update_begin(); | ||
445 | if (cede_offline_enabled && parse_cede_parameters() == 0) { | ||
446 | default_offline_state = CPU_STATE_INACTIVE; | ||
447 | for_each_online_cpu(cpu) | ||
448 | set_default_offline_state(cpu); | ||
449 | } | ||
450 | cpu_maps_update_done(); | ||
451 | } | ||
288 | 452 | ||
289 | return 0; | 453 | return 0; |
290 | } | 454 | } |
diff --git a/arch/powerpc/platforms/pseries/offline_states.h b/arch/powerpc/platforms/pseries/offline_states.h new file mode 100644 index 000000000000..22574e0d9d91 --- /dev/null +++ b/arch/powerpc/platforms/pseries/offline_states.h | |||
@@ -0,0 +1,18 @@ | |||
1 | #ifndef _OFFLINE_STATES_H_ | ||
2 | #define _OFFLINE_STATES_H_ | ||
3 | |||
4 | /* Cpu offline states go here */ | ||
5 | enum cpu_state_vals { | ||
6 | CPU_STATE_OFFLINE, | ||
7 | CPU_STATE_INACTIVE, | ||
8 | CPU_STATE_ONLINE, | ||
9 | CPU_MAX_OFFLINE_STATES | ||
10 | }; | ||
11 | |||
12 | extern enum cpu_state_vals get_cpu_current_state(int cpu); | ||
13 | extern void set_cpu_current_state(int cpu, enum cpu_state_vals state); | ||
14 | extern enum cpu_state_vals get_preferred_offline_state(int cpu); | ||
15 | extern void set_preferred_offline_state(int cpu, enum cpu_state_vals state); | ||
16 | extern void set_default_offline_state(int cpu); | ||
17 | extern int start_secondary(void); | ||
18 | #endif | ||
diff --git a/arch/powerpc/platforms/pseries/plpar_wrappers.h b/arch/powerpc/platforms/pseries/plpar_wrappers.h index a24a6b2333b2..0603c91538ae 100644 --- a/arch/powerpc/platforms/pseries/plpar_wrappers.h +++ b/arch/powerpc/platforms/pseries/plpar_wrappers.h | |||
@@ -9,11 +9,33 @@ static inline long poll_pending(void) | |||
9 | return plpar_hcall_norets(H_POLL_PENDING); | 9 | return plpar_hcall_norets(H_POLL_PENDING); |
10 | } | 10 | } |
11 | 11 | ||
12 | static inline u8 get_cede_latency_hint(void) | ||
13 | { | ||
14 | return get_lppaca()->gpr5_dword.fields.cede_latency_hint; | ||
15 | } | ||
16 | |||
17 | static inline void set_cede_latency_hint(u8 latency_hint) | ||
18 | { | ||
19 | get_lppaca()->gpr5_dword.fields.cede_latency_hint = latency_hint; | ||
20 | } | ||
21 | |||
12 | static inline long cede_processor(void) | 22 | static inline long cede_processor(void) |
13 | { | 23 | { |
14 | return plpar_hcall_norets(H_CEDE); | 24 | return plpar_hcall_norets(H_CEDE); |
15 | } | 25 | } |
16 | 26 | ||
27 | static inline long extended_cede_processor(unsigned long latency_hint) | ||
28 | { | ||
29 | long rc; | ||
30 | u8 old_latency_hint = get_cede_latency_hint(); | ||
31 | |||
32 | set_cede_latency_hint(latency_hint); | ||
33 | rc = cede_processor(); | ||
34 | set_cede_latency_hint(old_latency_hint); | ||
35 | |||
36 | return rc; | ||
37 | } | ||
38 | |||
17 | static inline long vpa_call(unsigned long flags, unsigned long cpu, | 39 | static inline long vpa_call(unsigned long flags, unsigned long cpu, |
18 | unsigned long vpa) | 40 | unsigned long vpa) |
19 | { | 41 | { |
diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c index 2e2bbe120b90..a2305d29bbbd 100644 --- a/arch/powerpc/platforms/pseries/reconfig.c +++ b/arch/powerpc/platforms/pseries/reconfig.c | |||
@@ -96,7 +96,7 @@ static struct device_node *derive_parent(const char *path) | |||
96 | return parent; | 96 | return parent; |
97 | } | 97 | } |
98 | 98 | ||
99 | static BLOCKING_NOTIFIER_HEAD(pSeries_reconfig_chain); | 99 | BLOCKING_NOTIFIER_HEAD(pSeries_reconfig_chain); |
100 | 100 | ||
101 | int pSeries_reconfig_notifier_register(struct notifier_block *nb) | 101 | int pSeries_reconfig_notifier_register(struct notifier_block *nb) |
102 | { | 102 | { |
@@ -184,7 +184,7 @@ static int pSeries_reconfig_remove_node(struct device_node *np) | |||
184 | } | 184 | } |
185 | 185 | ||
186 | /* | 186 | /* |
187 | * /proc/ppc64/ofdt - yucky binary interface for adding and removing | 187 | * /proc/powerpc/ofdt - yucky binary interface for adding and removing |
188 | * OF device nodes. Should be deprecated as soon as we get an | 188 | * OF device nodes. Should be deprecated as soon as we get an |
189 | * in-kernel wrapper for the RTAS ibm,configure-connector call. | 189 | * in-kernel wrapper for the RTAS ibm,configure-connector call. |
190 | */ | 190 | */ |
@@ -543,7 +543,7 @@ static const struct file_operations ofdt_fops = { | |||
543 | .write = ofdt_write | 543 | .write = ofdt_write |
544 | }; | 544 | }; |
545 | 545 | ||
546 | /* create /proc/ppc64/ofdt write-only by root */ | 546 | /* create /proc/powerpc/ofdt write-only by root */ |
547 | static int proc_ppc64_create_ofdt(void) | 547 | static int proc_ppc64_create_ofdt(void) |
548 | { | 548 | { |
549 | struct proc_dir_entry *ent; | 549 | struct proc_dir_entry *ent; |
@@ -551,7 +551,7 @@ static int proc_ppc64_create_ofdt(void) | |||
551 | if (!machine_is(pseries)) | 551 | if (!machine_is(pseries)) |
552 | return 0; | 552 | return 0; |
553 | 553 | ||
554 | ent = proc_create("ppc64/ofdt", S_IWUSR, NULL, &ofdt_fops); | 554 | ent = proc_create("powerpc/ofdt", S_IWUSR, NULL, &ofdt_fops); |
555 | if (ent) | 555 | if (ent) |
556 | ent->size = 0; | 556 | ent->size = 0; |
557 | 557 | ||
diff --git a/arch/powerpc/platforms/pseries/scanlog.c b/arch/powerpc/platforms/pseries/scanlog.c index 417eca79df69..1b45c458f952 100644 --- a/arch/powerpc/platforms/pseries/scanlog.c +++ b/arch/powerpc/platforms/pseries/scanlog.c | |||
@@ -13,7 +13,7 @@ | |||
13 | * of this data using this driver. A dump exists if the device-tree | 13 | * of this data using this driver. A dump exists if the device-tree |
14 | * /chosen/ibm,scan-log-data property exists. | 14 | * /chosen/ibm,scan-log-data property exists. |
15 | * | 15 | * |
16 | * This driver exports /proc/ppc64/scan-log-dump which can be read. | 16 | * This driver exports /proc/powerpc/scan-log-dump which can be read. |
17 | * The driver supports only sequential reads. | 17 | * The driver supports only sequential reads. |
18 | * | 18 | * |
19 | * The driver looks at a write to the driver for the single word "reset". | 19 | * The driver looks at a write to the driver for the single word "reset". |
@@ -186,7 +186,7 @@ static int __init scanlog_init(void) | |||
186 | if (!data) | 186 | if (!data) |
187 | goto err; | 187 | goto err; |
188 | 188 | ||
189 | ent = proc_create_data("ppc64/rtas/scan-log-dump", S_IRUSR, NULL, | 189 | ent = proc_create_data("powerpc/rtas/scan-log-dump", S_IRUSR, NULL, |
190 | &scanlog_fops, data); | 190 | &scanlog_fops, data); |
191 | if (!ent) | 191 | if (!ent) |
192 | goto err; | 192 | goto err; |
diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c index 440000cc7130..8868c012268a 100644 --- a/arch/powerpc/platforms/pseries/smp.c +++ b/arch/powerpc/platforms/pseries/smp.c | |||
@@ -48,6 +48,7 @@ | |||
48 | #include "plpar_wrappers.h" | 48 | #include "plpar_wrappers.h" |
49 | #include "pseries.h" | 49 | #include "pseries.h" |
50 | #include "xics.h" | 50 | #include "xics.h" |
51 | #include "offline_states.h" | ||
51 | 52 | ||
52 | 53 | ||
53 | /* | 54 | /* |
@@ -84,6 +85,9 @@ static inline int __devinit smp_startup_cpu(unsigned int lcpu) | |||
84 | /* Fixup atomic count: it exited inside IRQ handler. */ | 85 | /* Fixup atomic count: it exited inside IRQ handler. */ |
85 | task_thread_info(paca[lcpu].__current)->preempt_count = 0; | 86 | task_thread_info(paca[lcpu].__current)->preempt_count = 0; |
86 | 87 | ||
88 | if (get_cpu_current_state(lcpu) == CPU_STATE_INACTIVE) | ||
89 | goto out; | ||
90 | |||
87 | /* | 91 | /* |
88 | * If the RTAS start-cpu token does not exist then presume the | 92 | * If the RTAS start-cpu token does not exist then presume the |
89 | * cpu is already spinning. | 93 | * cpu is already spinning. |
@@ -98,6 +102,7 @@ static inline int __devinit smp_startup_cpu(unsigned int lcpu) | |||
98 | return 0; | 102 | return 0; |
99 | } | 103 | } |
100 | 104 | ||
105 | out: | ||
101 | return 1; | 106 | return 1; |
102 | } | 107 | } |
103 | 108 | ||
@@ -111,12 +116,16 @@ static void __devinit smp_xics_setup_cpu(int cpu) | |||
111 | vpa_init(cpu); | 116 | vpa_init(cpu); |
112 | 117 | ||
113 | cpu_clear(cpu, of_spin_map); | 118 | cpu_clear(cpu, of_spin_map); |
119 | set_cpu_current_state(cpu, CPU_STATE_ONLINE); | ||
120 | set_default_offline_state(cpu); | ||
114 | 121 | ||
115 | } | 122 | } |
116 | #endif /* CONFIG_XICS */ | 123 | #endif /* CONFIG_XICS */ |
117 | 124 | ||
118 | static void __devinit smp_pSeries_kick_cpu(int nr) | 125 | static void __devinit smp_pSeries_kick_cpu(int nr) |
119 | { | 126 | { |
127 | long rc; | ||
128 | unsigned long hcpuid; | ||
120 | BUG_ON(nr < 0 || nr >= NR_CPUS); | 129 | BUG_ON(nr < 0 || nr >= NR_CPUS); |
121 | 130 | ||
122 | if (!smp_startup_cpu(nr)) | 131 | if (!smp_startup_cpu(nr)) |
@@ -128,6 +137,16 @@ static void __devinit smp_pSeries_kick_cpu(int nr) | |||
128 | * the processor will continue on to secondary_start | 137 | * the processor will continue on to secondary_start |
129 | */ | 138 | */ |
130 | paca[nr].cpu_start = 1; | 139 | paca[nr].cpu_start = 1; |
140 | |||
141 | set_preferred_offline_state(nr, CPU_STATE_ONLINE); | ||
142 | |||
143 | if (get_cpu_current_state(nr) == CPU_STATE_INACTIVE) { | ||
144 | hcpuid = get_hard_smp_processor_id(nr); | ||
145 | rc = plpar_hcall_norets(H_PROD, hcpuid); | ||
146 | if (rc != H_SUCCESS) | ||
147 | panic("Error: Prod to wake up processor %d Ret= %ld\n", | ||
148 | nr, rc); | ||
149 | } | ||
131 | } | 150 | } |
132 | 151 | ||
133 | static int smp_pSeries_cpu_bootable(unsigned int nr) | 152 | static int smp_pSeries_cpu_bootable(unsigned int nr) |
diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c index b9bf0eedccf2..7d01b58f3989 100644 --- a/arch/powerpc/platforms/pseries/xics.c +++ b/arch/powerpc/platforms/pseries/xics.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/cpu.h> | 20 | #include <linux/cpu.h> |
21 | #include <linux/msi.h> | 21 | #include <linux/msi.h> |
22 | #include <linux/of.h> | 22 | #include <linux/of.h> |
23 | #include <linux/percpu.h> | ||
23 | 24 | ||
24 | #include <asm/firmware.h> | 25 | #include <asm/firmware.h> |
25 | #include <asm/io.h> | 26 | #include <asm/io.h> |
@@ -46,6 +47,12 @@ static struct irq_host *xics_host; | |||
46 | */ | 47 | */ |
47 | #define IPI_PRIORITY 4 | 48 | #define IPI_PRIORITY 4 |
48 | 49 | ||
50 | /* The least favored priority */ | ||
51 | #define LOWEST_PRIORITY 0xFF | ||
52 | |||
53 | /* The number of priorities defined above */ | ||
54 | #define MAX_NUM_PRIORITIES 3 | ||
55 | |||
49 | static unsigned int default_server = 0xFF; | 56 | static unsigned int default_server = 0xFF; |
50 | static unsigned int default_distrib_server = 0; | 57 | static unsigned int default_distrib_server = 0; |
51 | static unsigned int interrupt_server_size = 8; | 58 | static unsigned int interrupt_server_size = 8; |
@@ -56,6 +63,12 @@ static int ibm_set_xive; | |||
56 | static int ibm_int_on; | 63 | static int ibm_int_on; |
57 | static int ibm_int_off; | 64 | static int ibm_int_off; |
58 | 65 | ||
66 | struct xics_cppr { | ||
67 | unsigned char stack[MAX_NUM_PRIORITIES]; | ||
68 | int index; | ||
69 | }; | ||
70 | |||
71 | static DEFINE_PER_CPU(struct xics_cppr, xics_cppr); | ||
59 | 72 | ||
60 | /* Direct hardware low level accessors */ | 73 | /* Direct hardware low level accessors */ |
61 | 74 | ||
@@ -157,7 +170,7 @@ static int get_irq_server(unsigned int virq, unsigned int strict_check) | |||
157 | cpumask_t cpumask; | 170 | cpumask_t cpumask; |
158 | cpumask_t tmp = CPU_MASK_NONE; | 171 | cpumask_t tmp = CPU_MASK_NONE; |
159 | 172 | ||
160 | cpumask_copy(&cpumask, irq_desc[virq].affinity); | 173 | cpumask_copy(&cpumask, irq_to_desc(virq)->affinity); |
161 | if (!distribute_irqs) | 174 | if (!distribute_irqs) |
162 | return default_server; | 175 | return default_server; |
163 | 176 | ||
@@ -284,6 +297,19 @@ static inline unsigned int xics_xirr_vector(unsigned int xirr) | |||
284 | return xirr & 0x00ffffff; | 297 | return xirr & 0x00ffffff; |
285 | } | 298 | } |
286 | 299 | ||
300 | static void push_cppr(unsigned int vec) | ||
301 | { | ||
302 | struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr); | ||
303 | |||
304 | if (WARN_ON(os_cppr->index >= MAX_NUM_PRIORITIES - 1)) | ||
305 | return; | ||
306 | |||
307 | if (vec == XICS_IPI) | ||
308 | os_cppr->stack[++os_cppr->index] = IPI_PRIORITY; | ||
309 | else | ||
310 | os_cppr->stack[++os_cppr->index] = DEFAULT_PRIORITY; | ||
311 | } | ||
312 | |||
287 | static unsigned int xics_get_irq_direct(void) | 313 | static unsigned int xics_get_irq_direct(void) |
288 | { | 314 | { |
289 | unsigned int xirr = direct_xirr_info_get(); | 315 | unsigned int xirr = direct_xirr_info_get(); |
@@ -294,8 +320,10 @@ static unsigned int xics_get_irq_direct(void) | |||
294 | return NO_IRQ; | 320 | return NO_IRQ; |
295 | 321 | ||
296 | irq = irq_radix_revmap_lookup(xics_host, vec); | 322 | irq = irq_radix_revmap_lookup(xics_host, vec); |
297 | if (likely(irq != NO_IRQ)) | 323 | if (likely(irq != NO_IRQ)) { |
324 | push_cppr(vec); | ||
298 | return irq; | 325 | return irq; |
326 | } | ||
299 | 327 | ||
300 | /* We don't have a linux mapping, so have rtas mask it. */ | 328 | /* We don't have a linux mapping, so have rtas mask it. */ |
301 | xics_mask_unknown_vec(vec); | 329 | xics_mask_unknown_vec(vec); |
@@ -315,8 +343,10 @@ static unsigned int xics_get_irq_lpar(void) | |||
315 | return NO_IRQ; | 343 | return NO_IRQ; |
316 | 344 | ||
317 | irq = irq_radix_revmap_lookup(xics_host, vec); | 345 | irq = irq_radix_revmap_lookup(xics_host, vec); |
318 | if (likely(irq != NO_IRQ)) | 346 | if (likely(irq != NO_IRQ)) { |
347 | push_cppr(vec); | ||
319 | return irq; | 348 | return irq; |
349 | } | ||
320 | 350 | ||
321 | /* We don't have a linux mapping, so have RTAS mask it. */ | 351 | /* We don't have a linux mapping, so have RTAS mask it. */ |
322 | xics_mask_unknown_vec(vec); | 352 | xics_mask_unknown_vec(vec); |
@@ -326,12 +356,22 @@ static unsigned int xics_get_irq_lpar(void) | |||
326 | return NO_IRQ; | 356 | return NO_IRQ; |
327 | } | 357 | } |
328 | 358 | ||
359 | static unsigned char pop_cppr(void) | ||
360 | { | ||
361 | struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr); | ||
362 | |||
363 | if (WARN_ON(os_cppr->index < 1)) | ||
364 | return LOWEST_PRIORITY; | ||
365 | |||
366 | return os_cppr->stack[--os_cppr->index]; | ||
367 | } | ||
368 | |||
329 | static void xics_eoi_direct(unsigned int virq) | 369 | static void xics_eoi_direct(unsigned int virq) |
330 | { | 370 | { |
331 | unsigned int irq = (unsigned int)irq_map[virq].hwirq; | 371 | unsigned int irq = (unsigned int)irq_map[virq].hwirq; |
332 | 372 | ||
333 | iosync(); | 373 | iosync(); |
334 | direct_xirr_info_set((0xff << 24) | irq); | 374 | direct_xirr_info_set((pop_cppr() << 24) | irq); |
335 | } | 375 | } |
336 | 376 | ||
337 | static void xics_eoi_lpar(unsigned int virq) | 377 | static void xics_eoi_lpar(unsigned int virq) |
@@ -339,7 +379,7 @@ static void xics_eoi_lpar(unsigned int virq) | |||
339 | unsigned int irq = (unsigned int)irq_map[virq].hwirq; | 379 | unsigned int irq = (unsigned int)irq_map[virq].hwirq; |
340 | 380 | ||
341 | iosync(); | 381 | iosync(); |
342 | lpar_xirr_info_set((0xff << 24) | irq); | 382 | lpar_xirr_info_set((pop_cppr() << 24) | irq); |
343 | } | 383 | } |
344 | 384 | ||
345 | static int xics_set_affinity(unsigned int virq, const struct cpumask *cpumask) | 385 | static int xics_set_affinity(unsigned int virq, const struct cpumask *cpumask) |
@@ -388,7 +428,7 @@ static int xics_set_affinity(unsigned int virq, const struct cpumask *cpumask) | |||
388 | } | 428 | } |
389 | 429 | ||
390 | static struct irq_chip xics_pic_direct = { | 430 | static struct irq_chip xics_pic_direct = { |
391 | .typename = " XICS ", | 431 | .name = " XICS ", |
392 | .startup = xics_startup, | 432 | .startup = xics_startup, |
393 | .mask = xics_mask_irq, | 433 | .mask = xics_mask_irq, |
394 | .unmask = xics_unmask_irq, | 434 | .unmask = xics_unmask_irq, |
@@ -397,7 +437,7 @@ static struct irq_chip xics_pic_direct = { | |||
397 | }; | 437 | }; |
398 | 438 | ||
399 | static struct irq_chip xics_pic_lpar = { | 439 | static struct irq_chip xics_pic_lpar = { |
400 | .typename = " XICS ", | 440 | .name = " XICS ", |
401 | .startup = xics_startup, | 441 | .startup = xics_startup, |
402 | .mask = xics_mask_irq, | 442 | .mask = xics_mask_irq, |
403 | .unmask = xics_unmask_irq, | 443 | .unmask = xics_unmask_irq, |
@@ -428,13 +468,13 @@ static int xics_host_map(struct irq_host *h, unsigned int virq, | |||
428 | /* Insert the interrupt mapping into the radix tree for fast lookup */ | 468 | /* Insert the interrupt mapping into the radix tree for fast lookup */ |
429 | irq_radix_revmap_insert(xics_host, virq, hw); | 469 | irq_radix_revmap_insert(xics_host, virq, hw); |
430 | 470 | ||
431 | get_irq_desc(virq)->status |= IRQ_LEVEL; | 471 | irq_to_desc(virq)->status |= IRQ_LEVEL; |
432 | set_irq_chip_and_handler(virq, xics_irq_chip, handle_fasteoi_irq); | 472 | set_irq_chip_and_handler(virq, xics_irq_chip, handle_fasteoi_irq); |
433 | return 0; | 473 | return 0; |
434 | } | 474 | } |
435 | 475 | ||
436 | static int xics_host_xlate(struct irq_host *h, struct device_node *ct, | 476 | static int xics_host_xlate(struct irq_host *h, struct device_node *ct, |
437 | u32 *intspec, unsigned int intsize, | 477 | const u32 *intspec, unsigned int intsize, |
438 | irq_hw_number_t *out_hwirq, unsigned int *out_flags) | 478 | irq_hw_number_t *out_hwirq, unsigned int *out_flags) |
439 | 479 | ||
440 | { | 480 | { |
@@ -746,6 +786,12 @@ void __init xics_init_IRQ(void) | |||
746 | 786 | ||
747 | static void xics_set_cpu_priority(unsigned char cppr) | 787 | static void xics_set_cpu_priority(unsigned char cppr) |
748 | { | 788 | { |
789 | struct xics_cppr *os_cppr = &__get_cpu_var(xics_cppr); | ||
790 | |||
791 | BUG_ON(os_cppr->index != 0); | ||
792 | |||
793 | os_cppr->stack[os_cppr->index] = cppr; | ||
794 | |||
749 | if (firmware_has_feature(FW_FEATURE_LPAR)) | 795 | if (firmware_has_feature(FW_FEATURE_LPAR)) |
750 | lpar_cppr_info(cppr); | 796 | lpar_cppr_info(cppr); |
751 | else | 797 | else |
@@ -772,7 +818,7 @@ static void xics_set_cpu_giq(unsigned int gserver, unsigned int join) | |||
772 | 818 | ||
773 | void xics_setup_cpu(void) | 819 | void xics_setup_cpu(void) |
774 | { | 820 | { |
775 | xics_set_cpu_priority(0xff); | 821 | xics_set_cpu_priority(LOWEST_PRIORITY); |
776 | 822 | ||
777 | xics_set_cpu_giq(default_distrib_server, 1); | 823 | xics_set_cpu_giq(default_distrib_server, 1); |
778 | } | 824 | } |
@@ -852,7 +898,7 @@ void xics_migrate_irqs_away(void) | |||
852 | /* We need to get IPIs still. */ | 898 | /* We need to get IPIs still. */ |
853 | if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS) | 899 | if (irq == XICS_IPI || irq == XICS_IRQ_SPURIOUS) |
854 | continue; | 900 | continue; |
855 | desc = get_irq_desc(virq); | 901 | desc = irq_to_desc(virq); |
856 | 902 | ||
857 | /* We only need to migrate enabled IRQS */ | 903 | /* We only need to migrate enabled IRQS */ |
858 | if (desc == NULL || desc->chip == NULL | 904 | if (desc == NULL || desc->chip == NULL |
@@ -881,7 +927,7 @@ void xics_migrate_irqs_away(void) | |||
881 | virq, cpu); | 927 | virq, cpu); |
882 | 928 | ||
883 | /* Reset affinity to all cpus */ | 929 | /* Reset affinity to all cpus */ |
884 | cpumask_setall(irq_desc[virq].affinity); | 930 | cpumask_setall(irq_to_desc(virq)->affinity); |
885 | desc->chip->set_affinity(virq, cpu_all_mask); | 931 | desc->chip->set_affinity(virq, cpu_all_mask); |
886 | unlock: | 932 | unlock: |
887 | spin_unlock_irqrestore(&desc->lock, flags); | 933 | spin_unlock_irqrestore(&desc->lock, flags); |
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index 9d4b17462f13..5642924fb9fb 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile | |||
@@ -16,6 +16,7 @@ obj-$(CONFIG_U3_DART) += dart_iommu.o | |||
16 | obj-$(CONFIG_MMIO_NVRAM) += mmio_nvram.o | 16 | obj-$(CONFIG_MMIO_NVRAM) += mmio_nvram.o |
17 | obj-$(CONFIG_FSL_SOC) += fsl_soc.o | 17 | obj-$(CONFIG_FSL_SOC) += fsl_soc.o |
18 | obj-$(CONFIG_FSL_PCI) += fsl_pci.o $(fsl-msi-obj-y) | 18 | obj-$(CONFIG_FSL_PCI) += fsl_pci.o $(fsl-msi-obj-y) |
19 | obj-$(CONFIG_FSL_PMC) += fsl_pmc.o | ||
19 | obj-$(CONFIG_FSL_LBC) += fsl_lbc.o | 20 | obj-$(CONFIG_FSL_LBC) += fsl_lbc.o |
20 | obj-$(CONFIG_FSL_GTM) += fsl_gtm.o | 21 | obj-$(CONFIG_FSL_GTM) += fsl_gtm.o |
21 | obj-$(CONFIG_MPC8xxx_GPIO) += mpc8xxx_gpio.o | 22 | obj-$(CONFIG_MPC8xxx_GPIO) += mpc8xxx_gpio.o |
diff --git a/arch/powerpc/sysdev/cpm1.c b/arch/powerpc/sysdev/cpm1.c index 82424cd7e128..a4b41dbde128 100644 --- a/arch/powerpc/sysdev/cpm1.c +++ b/arch/powerpc/sysdev/cpm1.c | |||
@@ -77,7 +77,7 @@ static void cpm_end_irq(unsigned int irq) | |||
77 | } | 77 | } |
78 | 78 | ||
79 | static struct irq_chip cpm_pic = { | 79 | static struct irq_chip cpm_pic = { |
80 | .typename = " CPM PIC ", | 80 | .name = " CPM PIC ", |
81 | .mask = cpm_mask_irq, | 81 | .mask = cpm_mask_irq, |
82 | .unmask = cpm_unmask_irq, | 82 | .unmask = cpm_unmask_irq, |
83 | .eoi = cpm_end_irq, | 83 | .eoi = cpm_end_irq, |
@@ -102,7 +102,7 @@ static int cpm_pic_host_map(struct irq_host *h, unsigned int virq, | |||
102 | { | 102 | { |
103 | pr_debug("cpm_pic_host_map(%d, 0x%lx)\n", virq, hw); | 103 | pr_debug("cpm_pic_host_map(%d, 0x%lx)\n", virq, hw); |
104 | 104 | ||
105 | get_irq_desc(virq)->status |= IRQ_LEVEL; | 105 | irq_to_desc(virq)->status |= IRQ_LEVEL; |
106 | set_irq_chip_and_handler(virq, &cpm_pic, handle_fasteoi_irq); | 106 | set_irq_chip_and_handler(virq, &cpm_pic, handle_fasteoi_irq); |
107 | return 0; | 107 | return 0; |
108 | } | 108 | } |
diff --git a/arch/powerpc/sysdev/cpm2_pic.c b/arch/powerpc/sysdev/cpm2_pic.c index 78f1f7cca0a0..971483f0dfac 100644 --- a/arch/powerpc/sysdev/cpm2_pic.c +++ b/arch/powerpc/sysdev/cpm2_pic.c | |||
@@ -115,11 +115,13 @@ static void cpm2_ack(unsigned int virq) | |||
115 | 115 | ||
116 | static void cpm2_end_irq(unsigned int virq) | 116 | static void cpm2_end_irq(unsigned int virq) |
117 | { | 117 | { |
118 | struct irq_desc *desc; | ||
118 | int bit, word; | 119 | int bit, word; |
119 | unsigned int irq_nr = virq_to_hw(virq); | 120 | unsigned int irq_nr = virq_to_hw(virq); |
120 | 121 | ||
121 | if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS)) | 122 | desc = irq_to_desc(irq_nr); |
122 | && irq_desc[irq_nr].action) { | 123 | if (!(desc->status & (IRQ_DISABLED|IRQ_INPROGRESS)) |
124 | && desc->action) { | ||
123 | 125 | ||
124 | bit = irq_to_siubit[irq_nr]; | 126 | bit = irq_to_siubit[irq_nr]; |
125 | word = irq_to_siureg[irq_nr]; | 127 | word = irq_to_siureg[irq_nr]; |
@@ -138,7 +140,7 @@ static void cpm2_end_irq(unsigned int virq) | |||
138 | static int cpm2_set_irq_type(unsigned int virq, unsigned int flow_type) | 140 | static int cpm2_set_irq_type(unsigned int virq, unsigned int flow_type) |
139 | { | 141 | { |
140 | unsigned int src = virq_to_hw(virq); | 142 | unsigned int src = virq_to_hw(virq); |
141 | struct irq_desc *desc = get_irq_desc(virq); | 143 | struct irq_desc *desc = irq_to_desc(virq); |
142 | unsigned int vold, vnew, edibit; | 144 | unsigned int vold, vnew, edibit; |
143 | 145 | ||
144 | if (flow_type == IRQ_TYPE_NONE) | 146 | if (flow_type == IRQ_TYPE_NONE) |
@@ -182,7 +184,7 @@ static int cpm2_set_irq_type(unsigned int virq, unsigned int flow_type) | |||
182 | } | 184 | } |
183 | 185 | ||
184 | static struct irq_chip cpm2_pic = { | 186 | static struct irq_chip cpm2_pic = { |
185 | .typename = " CPM2 SIU ", | 187 | .name = " CPM2 SIU ", |
186 | .mask = cpm2_mask_irq, | 188 | .mask = cpm2_mask_irq, |
187 | .unmask = cpm2_unmask_irq, | 189 | .unmask = cpm2_unmask_irq, |
188 | .ack = cpm2_ack, | 190 | .ack = cpm2_ack, |
@@ -210,13 +212,13 @@ static int cpm2_pic_host_map(struct irq_host *h, unsigned int virq, | |||
210 | { | 212 | { |
211 | pr_debug("cpm2_pic_host_map(%d, 0x%lx)\n", virq, hw); | 213 | pr_debug("cpm2_pic_host_map(%d, 0x%lx)\n", virq, hw); |
212 | 214 | ||
213 | get_irq_desc(virq)->status |= IRQ_LEVEL; | 215 | irq_to_desc(virq)->status |= IRQ_LEVEL; |
214 | set_irq_chip_and_handler(virq, &cpm2_pic, handle_level_irq); | 216 | set_irq_chip_and_handler(virq, &cpm2_pic, handle_level_irq); |
215 | return 0; | 217 | return 0; |
216 | } | 218 | } |
217 | 219 | ||
218 | static int cpm2_pic_host_xlate(struct irq_host *h, struct device_node *ct, | 220 | static int cpm2_pic_host_xlate(struct irq_host *h, struct device_node *ct, |
219 | u32 *intspec, unsigned int intsize, | 221 | const u32 *intspec, unsigned int intsize, |
220 | irq_hw_number_t *out_hwirq, unsigned int *out_flags) | 222 | irq_hw_number_t *out_hwirq, unsigned int *out_flags) |
221 | { | 223 | { |
222 | *out_hwirq = intspec[0]; | 224 | *out_hwirq = intspec[0]; |
diff --git a/arch/powerpc/sysdev/cpm_common.c b/arch/powerpc/sysdev/cpm_common.c index e4b6d66d93de..9de72c96e6d1 100644 --- a/arch/powerpc/sysdev/cpm_common.c +++ b/arch/powerpc/sysdev/cpm_common.c | |||
@@ -72,7 +72,7 @@ static phys_addr_t muram_pbase; | |||
72 | /* Max address size we deal with */ | 72 | /* Max address size we deal with */ |
73 | #define OF_MAX_ADDR_CELLS 4 | 73 | #define OF_MAX_ADDR_CELLS 4 |
74 | 74 | ||
75 | int __init cpm_muram_init(void) | 75 | int cpm_muram_init(void) |
76 | { | 76 | { |
77 | struct device_node *np; | 77 | struct device_node *np; |
78 | struct resource r; | 78 | struct resource r; |
@@ -81,6 +81,9 @@ int __init cpm_muram_init(void) | |||
81 | int i = 0; | 81 | int i = 0; |
82 | int ret = 0; | 82 | int ret = 0; |
83 | 83 | ||
84 | if (muram_pbase) | ||
85 | return 0; | ||
86 | |||
84 | spin_lock_init(&cpm_muram_lock); | 87 | spin_lock_init(&cpm_muram_lock); |
85 | /* initialize the info header */ | 88 | /* initialize the info header */ |
86 | rh_init(&cpm_muram_info, 1, | 89 | rh_init(&cpm_muram_info, 1, |
diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index da38a1ff97bb..62e50258cdef 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c | |||
@@ -47,7 +47,7 @@ static struct irq_chip fsl_msi_chip = { | |||
47 | .mask = mask_msi_irq, | 47 | .mask = mask_msi_irq, |
48 | .unmask = unmask_msi_irq, | 48 | .unmask = unmask_msi_irq, |
49 | .ack = fsl_msi_end_irq, | 49 | .ack = fsl_msi_end_irq, |
50 | .typename = " FSL-MSI ", | 50 | .name = " FSL-MSI ", |
51 | }; | 51 | }; |
52 | 52 | ||
53 | static int fsl_msi_host_map(struct irq_host *h, unsigned int virq, | 53 | static int fsl_msi_host_map(struct irq_host *h, unsigned int virq, |
@@ -55,7 +55,7 @@ static int fsl_msi_host_map(struct irq_host *h, unsigned int virq, | |||
55 | { | 55 | { |
56 | struct irq_chip *chip = &fsl_msi_chip; | 56 | struct irq_chip *chip = &fsl_msi_chip; |
57 | 57 | ||
58 | get_irq_desc(virq)->status |= IRQ_TYPE_EDGE_FALLING; | 58 | irq_to_desc(virq)->status |= IRQ_TYPE_EDGE_FALLING; |
59 | 59 | ||
60 | set_irq_chip_and_handler(virq, chip, handle_edge_irq); | 60 | set_irq_chip_and_handler(virq, chip, handle_edge_irq); |
61 | 61 | ||
diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c index ae88b1448018..4e3a3e345ab3 100644 --- a/arch/powerpc/sysdev/fsl_pci.c +++ b/arch/powerpc/sysdev/fsl_pci.c | |||
@@ -56,7 +56,7 @@ static int __init fsl_pcie_check_link(struct pci_controller *hose) | |||
56 | return 0; | 56 | return 0; |
57 | } | 57 | } |
58 | 58 | ||
59 | #if defined(CONFIG_PPC_85xx) || defined(CONFIG_PPC_86xx) | 59 | #if defined(CONFIG_FSL_SOC_BOOKE) || defined(CONFIG_PPC_86xx) |
60 | static int __init setup_one_atmu(struct ccsr_pci __iomem *pci, | 60 | static int __init setup_one_atmu(struct ccsr_pci __iomem *pci, |
61 | unsigned int index, const struct resource *res, | 61 | unsigned int index, const struct resource *res, |
62 | resource_size_t offset) | 62 | resource_size_t offset) |
@@ -392,9 +392,23 @@ DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8536, quirk_fsl_pcie_header); | |||
392 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8641, quirk_fsl_pcie_header); | 392 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8641, quirk_fsl_pcie_header); |
393 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8641D, quirk_fsl_pcie_header); | 393 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8641D, quirk_fsl_pcie_header); |
394 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8610, quirk_fsl_pcie_header); | 394 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8610, quirk_fsl_pcie_header); |
395 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P1011E, quirk_fsl_pcie_header); | ||
396 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P1011, quirk_fsl_pcie_header); | ||
397 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P1013E, quirk_fsl_pcie_header); | ||
398 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P1013, quirk_fsl_pcie_header); | ||
399 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P1020E, quirk_fsl_pcie_header); | ||
400 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P1020, quirk_fsl_pcie_header); | ||
401 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P1022E, quirk_fsl_pcie_header); | ||
402 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P1022, quirk_fsl_pcie_header); | ||
403 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P2010E, quirk_fsl_pcie_header); | ||
404 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P2010, quirk_fsl_pcie_header); | ||
395 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P2020E, quirk_fsl_pcie_header); | 405 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P2020E, quirk_fsl_pcie_header); |
396 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P2020, quirk_fsl_pcie_header); | 406 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P2020, quirk_fsl_pcie_header); |
397 | #endif /* CONFIG_PPC_85xx || CONFIG_PPC_86xx */ | 407 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P4040E, quirk_fsl_pcie_header); |
408 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P4040, quirk_fsl_pcie_header); | ||
409 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P4080E, quirk_fsl_pcie_header); | ||
410 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P4080, quirk_fsl_pcie_header); | ||
411 | #endif /* CONFIG_FSL_SOC_BOOKE || CONFIG_PPC_86xx */ | ||
398 | 412 | ||
399 | #if defined(CONFIG_PPC_83xx) || defined(CONFIG_PPC_MPC512x) | 413 | #if defined(CONFIG_PPC_83xx) || defined(CONFIG_PPC_MPC512x) |
400 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8314E, quirk_fsl_pcie_header); | 414 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8314E, quirk_fsl_pcie_header); |
diff --git a/arch/powerpc/sysdev/fsl_pmc.c b/arch/powerpc/sysdev/fsl_pmc.c new file mode 100644 index 000000000000..a7635a993dca --- /dev/null +++ b/arch/powerpc/sysdev/fsl_pmc.c | |||
@@ -0,0 +1,88 @@ | |||
1 | /* | ||
2 | * Suspend/resume support | ||
3 | * | ||
4 | * Copyright 2009 MontaVista Software, Inc. | ||
5 | * | ||
6 | * Author: Anton Vorontsov <avorontsov@ru.mvista.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/init.h> | ||
15 | #include <linux/types.h> | ||
16 | #include <linux/errno.h> | ||
17 | #include <linux/suspend.h> | ||
18 | #include <linux/delay.h> | ||
19 | #include <linux/device.h> | ||
20 | #include <linux/of_platform.h> | ||
21 | |||
22 | struct pmc_regs { | ||
23 | __be32 devdisr; | ||
24 | __be32 devdisr2; | ||
25 | __be32 :32; | ||
26 | __be32 :32; | ||
27 | __be32 pmcsr; | ||
28 | #define PMCSR_SLP (1 << 17) | ||
29 | }; | ||
30 | |||
31 | static struct device *pmc_dev; | ||
32 | static struct pmc_regs __iomem *pmc_regs; | ||
33 | |||
34 | static int pmc_suspend_enter(suspend_state_t state) | ||
35 | { | ||
36 | int ret; | ||
37 | |||
38 | setbits32(&pmc_regs->pmcsr, PMCSR_SLP); | ||
39 | /* At this point, the CPU is asleep. */ | ||
40 | |||
41 | /* Upon resume, wait for SLP bit to be clear. */ | ||
42 | ret = spin_event_timeout((in_be32(&pmc_regs->pmcsr) & PMCSR_SLP) == 0, | ||
43 | 10000, 10) ? 0 : -ETIMEDOUT; | ||
44 | if (ret) | ||
45 | dev_err(pmc_dev, "tired waiting for SLP bit to clear\n"); | ||
46 | return ret; | ||
47 | } | ||
48 | |||
49 | static int pmc_suspend_valid(suspend_state_t state) | ||
50 | { | ||
51 | if (state != PM_SUSPEND_STANDBY) | ||
52 | return 0; | ||
53 | return 1; | ||
54 | } | ||
55 | |||
56 | static struct platform_suspend_ops pmc_suspend_ops = { | ||
57 | .valid = pmc_suspend_valid, | ||
58 | .enter = pmc_suspend_enter, | ||
59 | }; | ||
60 | |||
61 | static int pmc_probe(struct of_device *ofdev, const struct of_device_id *id) | ||
62 | { | ||
63 | pmc_regs = of_iomap(ofdev->node, 0); | ||
64 | if (!pmc_regs) | ||
65 | return -ENOMEM; | ||
66 | |||
67 | pmc_dev = &ofdev->dev; | ||
68 | suspend_set_ops(&pmc_suspend_ops); | ||
69 | return 0; | ||
70 | } | ||
71 | |||
72 | static const struct of_device_id pmc_ids[] = { | ||
73 | { .compatible = "fsl,mpc8548-pmc", }, | ||
74 | { .compatible = "fsl,mpc8641d-pmc", }, | ||
75 | { }, | ||
76 | }; | ||
77 | |||
78 | static struct of_platform_driver pmc_driver = { | ||
79 | .driver.name = "fsl-pmc", | ||
80 | .match_table = pmc_ids, | ||
81 | .probe = pmc_probe, | ||
82 | }; | ||
83 | |||
84 | static int __init pmc_init(void) | ||
85 | { | ||
86 | return of_register_platform_driver(&pmc_driver); | ||
87 | } | ||
88 | device_initcall(pmc_init); | ||
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c index adca4affcf1f..b91f7acdda6f 100644 --- a/arch/powerpc/sysdev/fsl_soc.c +++ b/arch/powerpc/sysdev/fsl_soc.c | |||
@@ -372,7 +372,7 @@ err: | |||
372 | 372 | ||
373 | arch_initcall(fsl_usb_of_init); | 373 | arch_initcall(fsl_usb_of_init); |
374 | 374 | ||
375 | #if defined(CONFIG_PPC_85xx) || defined(CONFIG_PPC_86xx) | 375 | #if defined(CONFIG_FSL_SOC_BOOKE) || defined(CONFIG_PPC_86xx) |
376 | static __be32 __iomem *rstcr; | 376 | static __be32 __iomem *rstcr; |
377 | 377 | ||
378 | static int __init setup_rstcr(void) | 378 | static int __init setup_rstcr(void) |
diff --git a/arch/powerpc/sysdev/i8259.c b/arch/powerpc/sysdev/i8259.c index a96584ab33dd..0a55db8a5a29 100644 --- a/arch/powerpc/sysdev/i8259.c +++ b/arch/powerpc/sysdev/i8259.c | |||
@@ -135,7 +135,7 @@ static void i8259_unmask_irq(unsigned int irq_nr) | |||
135 | } | 135 | } |
136 | 136 | ||
137 | static struct irq_chip i8259_pic = { | 137 | static struct irq_chip i8259_pic = { |
138 | .typename = " i8259 ", | 138 | .name = " i8259 ", |
139 | .mask = i8259_mask_irq, | 139 | .mask = i8259_mask_irq, |
140 | .disable = i8259_mask_irq, | 140 | .disable = i8259_mask_irq, |
141 | .unmask = i8259_unmask_irq, | 141 | .unmask = i8259_unmask_irq, |
@@ -175,12 +175,12 @@ static int i8259_host_map(struct irq_host *h, unsigned int virq, | |||
175 | 175 | ||
176 | /* We block the internal cascade */ | 176 | /* We block the internal cascade */ |
177 | if (hw == 2) | 177 | if (hw == 2) |
178 | get_irq_desc(virq)->status |= IRQ_NOREQUEST; | 178 | irq_to_desc(virq)->status |= IRQ_NOREQUEST; |
179 | 179 | ||
180 | /* We use the level handler only for now, we might want to | 180 | /* We use the level handler only for now, we might want to |
181 | * be more cautious here but that works for now | 181 | * be more cautious here but that works for now |
182 | */ | 182 | */ |
183 | get_irq_desc(virq)->status |= IRQ_LEVEL; | 183 | irq_to_desc(virq)->status |= IRQ_LEVEL; |
184 | set_irq_chip_and_handler(virq, &i8259_pic, handle_level_irq); | 184 | set_irq_chip_and_handler(virq, &i8259_pic, handle_level_irq); |
185 | return 0; | 185 | return 0; |
186 | } | 186 | } |
@@ -198,7 +198,7 @@ static void i8259_host_unmap(struct irq_host *h, unsigned int virq) | |||
198 | } | 198 | } |
199 | 199 | ||
200 | static int i8259_host_xlate(struct irq_host *h, struct device_node *ct, | 200 | static int i8259_host_xlate(struct irq_host *h, struct device_node *ct, |
201 | u32 *intspec, unsigned int intsize, | 201 | const u32 *intspec, unsigned int intsize, |
202 | irq_hw_number_t *out_hwirq, unsigned int *out_flags) | 202 | irq_hw_number_t *out_hwirq, unsigned int *out_flags) |
203 | { | 203 | { |
204 | static unsigned char map_isa_senses[4] = { | 204 | static unsigned char map_isa_senses[4] = { |
diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c index cb7689c4bfbd..28cdddd2f89e 100644 --- a/arch/powerpc/sysdev/ipic.c +++ b/arch/powerpc/sysdev/ipic.c | |||
@@ -605,7 +605,7 @@ static int ipic_set_irq_type(unsigned int virq, unsigned int flow_type) | |||
605 | { | 605 | { |
606 | struct ipic *ipic = ipic_from_irq(virq); | 606 | struct ipic *ipic = ipic_from_irq(virq); |
607 | unsigned int src = ipic_irq_to_hw(virq); | 607 | unsigned int src = ipic_irq_to_hw(virq); |
608 | struct irq_desc *desc = get_irq_desc(virq); | 608 | struct irq_desc *desc = irq_to_desc(virq); |
609 | unsigned int vold, vnew, edibit; | 609 | unsigned int vold, vnew, edibit; |
610 | 610 | ||
611 | if (flow_type == IRQ_TYPE_NONE) | 611 | if (flow_type == IRQ_TYPE_NONE) |
@@ -660,7 +660,7 @@ static int ipic_set_irq_type(unsigned int virq, unsigned int flow_type) | |||
660 | 660 | ||
661 | /* level interrupts and edge interrupts have different ack operations */ | 661 | /* level interrupts and edge interrupts have different ack operations */ |
662 | static struct irq_chip ipic_level_irq_chip = { | 662 | static struct irq_chip ipic_level_irq_chip = { |
663 | .typename = " IPIC ", | 663 | .name = " IPIC ", |
664 | .unmask = ipic_unmask_irq, | 664 | .unmask = ipic_unmask_irq, |
665 | .mask = ipic_mask_irq, | 665 | .mask = ipic_mask_irq, |
666 | .mask_ack = ipic_mask_irq, | 666 | .mask_ack = ipic_mask_irq, |
@@ -668,7 +668,7 @@ static struct irq_chip ipic_level_irq_chip = { | |||
668 | }; | 668 | }; |
669 | 669 | ||
670 | static struct irq_chip ipic_edge_irq_chip = { | 670 | static struct irq_chip ipic_edge_irq_chip = { |
671 | .typename = " IPIC ", | 671 | .name = " IPIC ", |
672 | .unmask = ipic_unmask_irq, | 672 | .unmask = ipic_unmask_irq, |
673 | .mask = ipic_mask_irq, | 673 | .mask = ipic_mask_irq, |
674 | .mask_ack = ipic_mask_irq_and_ack, | 674 | .mask_ack = ipic_mask_irq_and_ack, |
@@ -697,7 +697,7 @@ static int ipic_host_map(struct irq_host *h, unsigned int virq, | |||
697 | } | 697 | } |
698 | 698 | ||
699 | static int ipic_host_xlate(struct irq_host *h, struct device_node *ct, | 699 | static int ipic_host_xlate(struct irq_host *h, struct device_node *ct, |
700 | u32 *intspec, unsigned int intsize, | 700 | const u32 *intspec, unsigned int intsize, |
701 | irq_hw_number_t *out_hwirq, unsigned int *out_flags) | 701 | irq_hw_number_t *out_hwirq, unsigned int *out_flags) |
702 | 702 | ||
703 | { | 703 | { |
diff --git a/arch/powerpc/sysdev/mpc8xx_pic.c b/arch/powerpc/sysdev/mpc8xx_pic.c index 5d2d5522ef41..69bd6f4dff83 100644 --- a/arch/powerpc/sysdev/mpc8xx_pic.c +++ b/arch/powerpc/sysdev/mpc8xx_pic.c | |||
@@ -72,7 +72,7 @@ static void mpc8xx_end_irq(unsigned int virq) | |||
72 | 72 | ||
73 | static int mpc8xx_set_irq_type(unsigned int virq, unsigned int flow_type) | 73 | static int mpc8xx_set_irq_type(unsigned int virq, unsigned int flow_type) |
74 | { | 74 | { |
75 | struct irq_desc *desc = get_irq_desc(virq); | 75 | struct irq_desc *desc = irq_to_desc(virq); |
76 | 76 | ||
77 | desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL); | 77 | desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL); |
78 | desc->status |= flow_type & IRQ_TYPE_SENSE_MASK; | 78 | desc->status |= flow_type & IRQ_TYPE_SENSE_MASK; |
@@ -94,7 +94,7 @@ static int mpc8xx_set_irq_type(unsigned int virq, unsigned int flow_type) | |||
94 | } | 94 | } |
95 | 95 | ||
96 | static struct irq_chip mpc8xx_pic = { | 96 | static struct irq_chip mpc8xx_pic = { |
97 | .typename = " MPC8XX SIU ", | 97 | .name = " MPC8XX SIU ", |
98 | .unmask = mpc8xx_unmask_irq, | 98 | .unmask = mpc8xx_unmask_irq, |
99 | .mask = mpc8xx_mask_irq, | 99 | .mask = mpc8xx_mask_irq, |
100 | .ack = mpc8xx_ack, | 100 | .ack = mpc8xx_ack, |
@@ -130,7 +130,7 @@ static int mpc8xx_pic_host_map(struct irq_host *h, unsigned int virq, | |||
130 | 130 | ||
131 | 131 | ||
132 | static int mpc8xx_pic_host_xlate(struct irq_host *h, struct device_node *ct, | 132 | static int mpc8xx_pic_host_xlate(struct irq_host *h, struct device_node *ct, |
133 | u32 *intspec, unsigned int intsize, | 133 | const u32 *intspec, unsigned int intsize, |
134 | irq_hw_number_t *out_hwirq, unsigned int *out_flags) | 134 | irq_hw_number_t *out_hwirq, unsigned int *out_flags) |
135 | { | 135 | { |
136 | static unsigned char map_pic_senses[4] = { | 136 | static unsigned char map_pic_senses[4] = { |
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 30c44e6b0413..aa9d06e5925b 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c | |||
@@ -572,7 +572,7 @@ static int irq_choose_cpu(unsigned int virt_irq) | |||
572 | cpumask_t mask; | 572 | cpumask_t mask; |
573 | int cpuid; | 573 | int cpuid; |
574 | 574 | ||
575 | cpumask_copy(&mask, irq_desc[virt_irq].affinity); | 575 | cpumask_copy(&mask, irq_to_desc(virt_irq)->affinity); |
576 | if (cpus_equal(mask, CPU_MASK_ALL)) { | 576 | if (cpus_equal(mask, CPU_MASK_ALL)) { |
577 | static int irq_rover; | 577 | static int irq_rover; |
578 | static DEFINE_SPINLOCK(irq_rover_lock); | 578 | static DEFINE_SPINLOCK(irq_rover_lock); |
@@ -621,7 +621,7 @@ static struct mpic *mpic_find(unsigned int irq) | |||
621 | if (irq < NUM_ISA_INTERRUPTS) | 621 | if (irq < NUM_ISA_INTERRUPTS) |
622 | return NULL; | 622 | return NULL; |
623 | 623 | ||
624 | return irq_desc[irq].chip_data; | 624 | return irq_to_desc(irq)->chip_data; |
625 | } | 625 | } |
626 | 626 | ||
627 | /* Determine if the linux irq is an IPI */ | 627 | /* Determine if the linux irq is an IPI */ |
@@ -648,14 +648,14 @@ static inline u32 mpic_physmask(u32 cpumask) | |||
648 | /* Get the mpic structure from the IPI number */ | 648 | /* Get the mpic structure from the IPI number */ |
649 | static inline struct mpic * mpic_from_ipi(unsigned int ipi) | 649 | static inline struct mpic * mpic_from_ipi(unsigned int ipi) |
650 | { | 650 | { |
651 | return irq_desc[ipi].chip_data; | 651 | return irq_to_desc(ipi)->chip_data; |
652 | } | 652 | } |
653 | #endif | 653 | #endif |
654 | 654 | ||
655 | /* Get the mpic structure from the irq number */ | 655 | /* Get the mpic structure from the irq number */ |
656 | static inline struct mpic * mpic_from_irq(unsigned int irq) | 656 | static inline struct mpic * mpic_from_irq(unsigned int irq) |
657 | { | 657 | { |
658 | return irq_desc[irq].chip_data; | 658 | return irq_to_desc(irq)->chip_data; |
659 | } | 659 | } |
660 | 660 | ||
661 | /* Send an EOI */ | 661 | /* Send an EOI */ |
@@ -735,7 +735,7 @@ static void mpic_unmask_ht_irq(unsigned int irq) | |||
735 | 735 | ||
736 | mpic_unmask_irq(irq); | 736 | mpic_unmask_irq(irq); |
737 | 737 | ||
738 | if (irq_desc[irq].status & IRQ_LEVEL) | 738 | if (irq_to_desc(irq)->status & IRQ_LEVEL) |
739 | mpic_ht_end_irq(mpic, src); | 739 | mpic_ht_end_irq(mpic, src); |
740 | } | 740 | } |
741 | 741 | ||
@@ -745,7 +745,7 @@ static unsigned int mpic_startup_ht_irq(unsigned int irq) | |||
745 | unsigned int src = mpic_irq_to_hw(irq); | 745 | unsigned int src = mpic_irq_to_hw(irq); |
746 | 746 | ||
747 | mpic_unmask_irq(irq); | 747 | mpic_unmask_irq(irq); |
748 | mpic_startup_ht_interrupt(mpic, src, irq_desc[irq].status); | 748 | mpic_startup_ht_interrupt(mpic, src, irq_to_desc(irq)->status); |
749 | 749 | ||
750 | return 0; | 750 | return 0; |
751 | } | 751 | } |
@@ -755,7 +755,7 @@ static void mpic_shutdown_ht_irq(unsigned int irq) | |||
755 | struct mpic *mpic = mpic_from_irq(irq); | 755 | struct mpic *mpic = mpic_from_irq(irq); |
756 | unsigned int src = mpic_irq_to_hw(irq); | 756 | unsigned int src = mpic_irq_to_hw(irq); |
757 | 757 | ||
758 | mpic_shutdown_ht_interrupt(mpic, src, irq_desc[irq].status); | 758 | mpic_shutdown_ht_interrupt(mpic, src, irq_to_desc(irq)->status); |
759 | mpic_mask_irq(irq); | 759 | mpic_mask_irq(irq); |
760 | } | 760 | } |
761 | 761 | ||
@@ -772,7 +772,7 @@ static void mpic_end_ht_irq(unsigned int irq) | |||
772 | * latched another edge interrupt coming in anyway | 772 | * latched another edge interrupt coming in anyway |
773 | */ | 773 | */ |
774 | 774 | ||
775 | if (irq_desc[irq].status & IRQ_LEVEL) | 775 | if (irq_to_desc(irq)->status & IRQ_LEVEL) |
776 | mpic_ht_end_irq(mpic, src); | 776 | mpic_ht_end_irq(mpic, src); |
777 | mpic_eoi(mpic); | 777 | mpic_eoi(mpic); |
778 | } | 778 | } |
@@ -856,7 +856,7 @@ int mpic_set_irq_type(unsigned int virq, unsigned int flow_type) | |||
856 | { | 856 | { |
857 | struct mpic *mpic = mpic_from_irq(virq); | 857 | struct mpic *mpic = mpic_from_irq(virq); |
858 | unsigned int src = mpic_irq_to_hw(virq); | 858 | unsigned int src = mpic_irq_to_hw(virq); |
859 | struct irq_desc *desc = get_irq_desc(virq); | 859 | struct irq_desc *desc = irq_to_desc(virq); |
860 | unsigned int vecpri, vold, vnew; | 860 | unsigned int vecpri, vold, vnew; |
861 | 861 | ||
862 | DBG("mpic: set_irq_type(mpic:@%p,virq:%d,src:0x%x,type:0x%x)\n", | 862 | DBG("mpic: set_irq_type(mpic:@%p,virq:%d,src:0x%x,type:0x%x)\n", |
@@ -994,7 +994,7 @@ static int mpic_host_map(struct irq_host *h, unsigned int virq, | |||
994 | } | 994 | } |
995 | 995 | ||
996 | static int mpic_host_xlate(struct irq_host *h, struct device_node *ct, | 996 | static int mpic_host_xlate(struct irq_host *h, struct device_node *ct, |
997 | u32 *intspec, unsigned int intsize, | 997 | const u32 *intspec, unsigned int intsize, |
998 | irq_hw_number_t *out_hwirq, unsigned int *out_flags) | 998 | irq_hw_number_t *out_hwirq, unsigned int *out_flags) |
999 | 999 | ||
1000 | { | 1000 | { |
@@ -1062,19 +1062,19 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
1062 | mpic->name = name; | 1062 | mpic->name = name; |
1063 | 1063 | ||
1064 | mpic->hc_irq = mpic_irq_chip; | 1064 | mpic->hc_irq = mpic_irq_chip; |
1065 | mpic->hc_irq.typename = name; | 1065 | mpic->hc_irq.name = name; |
1066 | if (flags & MPIC_PRIMARY) | 1066 | if (flags & MPIC_PRIMARY) |
1067 | mpic->hc_irq.set_affinity = mpic_set_affinity; | 1067 | mpic->hc_irq.set_affinity = mpic_set_affinity; |
1068 | #ifdef CONFIG_MPIC_U3_HT_IRQS | 1068 | #ifdef CONFIG_MPIC_U3_HT_IRQS |
1069 | mpic->hc_ht_irq = mpic_irq_ht_chip; | 1069 | mpic->hc_ht_irq = mpic_irq_ht_chip; |
1070 | mpic->hc_ht_irq.typename = name; | 1070 | mpic->hc_ht_irq.name = name; |
1071 | if (flags & MPIC_PRIMARY) | 1071 | if (flags & MPIC_PRIMARY) |
1072 | mpic->hc_ht_irq.set_affinity = mpic_set_affinity; | 1072 | mpic->hc_ht_irq.set_affinity = mpic_set_affinity; |
1073 | #endif /* CONFIG_MPIC_U3_HT_IRQS */ | 1073 | #endif /* CONFIG_MPIC_U3_HT_IRQS */ |
1074 | 1074 | ||
1075 | #ifdef CONFIG_SMP | 1075 | #ifdef CONFIG_SMP |
1076 | mpic->hc_ipi = mpic_ipi_chip; | 1076 | mpic->hc_ipi = mpic_ipi_chip; |
1077 | mpic->hc_ipi.typename = name; | 1077 | mpic->hc_ipi.name = name; |
1078 | #endif /* CONFIG_SMP */ | 1078 | #endif /* CONFIG_SMP */ |
1079 | 1079 | ||
1080 | mpic->flags = flags; | 1080 | mpic->flags = flags; |
diff --git a/arch/powerpc/sysdev/mpic_pasemi_msi.c b/arch/powerpc/sysdev/mpic_pasemi_msi.c index 656cb772b691..0f6ab06f8474 100644 --- a/arch/powerpc/sysdev/mpic_pasemi_msi.c +++ b/arch/powerpc/sysdev/mpic_pasemi_msi.c | |||
@@ -60,7 +60,7 @@ static struct irq_chip mpic_pasemi_msi_chip = { | |||
60 | .eoi = mpic_end_irq, | 60 | .eoi = mpic_end_irq, |
61 | .set_type = mpic_set_irq_type, | 61 | .set_type = mpic_set_irq_type, |
62 | .set_affinity = mpic_set_affinity, | 62 | .set_affinity = mpic_set_affinity, |
63 | .typename = "PASEMI-MSI ", | 63 | .name = "PASEMI-MSI ", |
64 | }; | 64 | }; |
65 | 65 | ||
66 | static int pasemi_msi_check_device(struct pci_dev *pdev, int nvec, int type) | 66 | static int pasemi_msi_check_device(struct pci_dev *pdev, int nvec, int type) |
diff --git a/arch/powerpc/sysdev/mpic_u3msi.c b/arch/powerpc/sysdev/mpic_u3msi.c index 0a8f5a9e87c9..d3caf23e6312 100644 --- a/arch/powerpc/sysdev/mpic_u3msi.c +++ b/arch/powerpc/sysdev/mpic_u3msi.c | |||
@@ -42,7 +42,7 @@ static struct irq_chip mpic_u3msi_chip = { | |||
42 | .eoi = mpic_end_irq, | 42 | .eoi = mpic_end_irq, |
43 | .set_type = mpic_set_irq_type, | 43 | .set_type = mpic_set_irq_type, |
44 | .set_affinity = mpic_set_affinity, | 44 | .set_affinity = mpic_set_affinity, |
45 | .typename = "MPIC-U3MSI", | 45 | .name = "MPIC-U3MSI", |
46 | }; | 46 | }; |
47 | 47 | ||
48 | static u64 read_ht_magic_addr(struct pci_dev *pdev, unsigned int pos) | 48 | static u64 read_ht_magic_addr(struct pci_dev *pdev, unsigned int pos) |
diff --git a/arch/powerpc/sysdev/mv64x60_pic.c b/arch/powerpc/sysdev/mv64x60_pic.c index 2aa4ed066db1..485b92477d7c 100644 --- a/arch/powerpc/sysdev/mv64x60_pic.c +++ b/arch/powerpc/sysdev/mv64x60_pic.c | |||
@@ -213,7 +213,7 @@ static int mv64x60_host_map(struct irq_host *h, unsigned int virq, | |||
213 | { | 213 | { |
214 | int level1; | 214 | int level1; |
215 | 215 | ||
216 | get_irq_desc(virq)->status |= IRQ_LEVEL; | 216 | irq_to_desc(virq)->status |= IRQ_LEVEL; |
217 | 217 | ||
218 | level1 = (hwirq & MV64x60_LEVEL1_MASK) >> MV64x60_LEVEL1_OFFSET; | 218 | level1 = (hwirq & MV64x60_LEVEL1_MASK) >> MV64x60_LEVEL1_OFFSET; |
219 | BUG_ON(level1 > MV64x60_LEVEL1_GPP); | 219 | BUG_ON(level1 > MV64x60_LEVEL1_GPP); |
diff --git a/arch/powerpc/sysdev/qe_lib/qe.c b/arch/powerpc/sysdev/qe_lib/qe.c index 464271bea6c9..149393c02c3f 100644 --- a/arch/powerpc/sysdev/qe_lib/qe.c +++ b/arch/powerpc/sysdev/qe_lib/qe.c | |||
@@ -27,6 +27,8 @@ | |||
27 | #include <linux/delay.h> | 27 | #include <linux/delay.h> |
28 | #include <linux/ioport.h> | 28 | #include <linux/ioport.h> |
29 | #include <linux/crc32.h> | 29 | #include <linux/crc32.h> |
30 | #include <linux/mod_devicetable.h> | ||
31 | #include <linux/of_platform.h> | ||
30 | #include <asm/irq.h> | 32 | #include <asm/irq.h> |
31 | #include <asm/page.h> | 33 | #include <asm/page.h> |
32 | #include <asm/pgtable.h> | 34 | #include <asm/pgtable.h> |
@@ -65,19 +67,6 @@ static unsigned int qe_num_of_snum; | |||
65 | 67 | ||
66 | static phys_addr_t qebase = -1; | 68 | static phys_addr_t qebase = -1; |
67 | 69 | ||
68 | int qe_alive_during_sleep(void) | ||
69 | { | ||
70 | static int ret = -1; | ||
71 | |||
72 | if (ret != -1) | ||
73 | return ret; | ||
74 | |||
75 | ret = !of_find_compatible_node(NULL, NULL, "fsl,mpc8569-pmc"); | ||
76 | |||
77 | return ret; | ||
78 | } | ||
79 | EXPORT_SYMBOL(qe_alive_during_sleep); | ||
80 | |||
81 | phys_addr_t get_qe_base(void) | 70 | phys_addr_t get_qe_base(void) |
82 | { | 71 | { |
83 | struct device_node *qe; | 72 | struct device_node *qe; |
@@ -104,7 +93,7 @@ phys_addr_t get_qe_base(void) | |||
104 | 93 | ||
105 | EXPORT_SYMBOL(get_qe_base); | 94 | EXPORT_SYMBOL(get_qe_base); |
106 | 95 | ||
107 | void __init qe_reset(void) | 96 | void qe_reset(void) |
108 | { | 97 | { |
109 | if (qe_immr == NULL) | 98 | if (qe_immr == NULL) |
110 | qe_immr = ioremap(get_qe_base(), QE_IMMAP_SIZE); | 99 | qe_immr = ioremap(get_qe_base(), QE_IMMAP_SIZE); |
@@ -330,16 +319,18 @@ EXPORT_SYMBOL(qe_put_snum); | |||
330 | static int qe_sdma_init(void) | 319 | static int qe_sdma_init(void) |
331 | { | 320 | { |
332 | struct sdma __iomem *sdma = &qe_immr->sdma; | 321 | struct sdma __iomem *sdma = &qe_immr->sdma; |
333 | unsigned long sdma_buf_offset; | 322 | static unsigned long sdma_buf_offset = (unsigned long)-ENOMEM; |
334 | 323 | ||
335 | if (!sdma) | 324 | if (!sdma) |
336 | return -ENODEV; | 325 | return -ENODEV; |
337 | 326 | ||
338 | /* allocate 2 internal temporary buffers (512 bytes size each) for | 327 | /* allocate 2 internal temporary buffers (512 bytes size each) for |
339 | * the SDMA */ | 328 | * the SDMA */ |
340 | sdma_buf_offset = qe_muram_alloc(512 * 2, 4096); | 329 | if (IS_ERR_VALUE(sdma_buf_offset)) { |
341 | if (IS_ERR_VALUE(sdma_buf_offset)) | 330 | sdma_buf_offset = qe_muram_alloc(512 * 2, 4096); |
342 | return -ENOMEM; | 331 | if (IS_ERR_VALUE(sdma_buf_offset)) |
332 | return -ENOMEM; | ||
333 | } | ||
343 | 334 | ||
344 | out_be32(&sdma->sdebcr, (u32) sdma_buf_offset & QE_SDEBCR_BA_MASK); | 335 | out_be32(&sdma->sdebcr, (u32) sdma_buf_offset & QE_SDEBCR_BA_MASK); |
345 | out_be32(&sdma->sdmr, (QE_SDMR_GLB_1_MSK | | 336 | out_be32(&sdma->sdmr, (QE_SDMR_GLB_1_MSK | |
@@ -349,7 +340,7 @@ static int qe_sdma_init(void) | |||
349 | } | 340 | } |
350 | 341 | ||
351 | /* The maximum number of RISCs we support */ | 342 | /* The maximum number of RISCs we support */ |
352 | #define MAX_QE_RISC 2 | 343 | #define MAX_QE_RISC 4 |
353 | 344 | ||
354 | /* Firmware information stored here for qe_get_firmware_info() */ | 345 | /* Firmware information stored here for qe_get_firmware_info() */ |
355 | static struct qe_firmware_info qe_firmware_info; | 346 | static struct qe_firmware_info qe_firmware_info; |
@@ -658,3 +649,35 @@ unsigned int qe_get_num_of_snums(void) | |||
658 | return num_of_snums; | 649 | return num_of_snums; |
659 | } | 650 | } |
660 | EXPORT_SYMBOL(qe_get_num_of_snums); | 651 | EXPORT_SYMBOL(qe_get_num_of_snums); |
652 | |||
653 | #if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC_85xx) | ||
654 | static int qe_resume(struct of_device *ofdev) | ||
655 | { | ||
656 | if (!qe_alive_during_sleep()) | ||
657 | qe_reset(); | ||
658 | return 0; | ||
659 | } | ||
660 | |||
661 | static int qe_probe(struct of_device *ofdev, const struct of_device_id *id) | ||
662 | { | ||
663 | return 0; | ||
664 | } | ||
665 | |||
666 | static const struct of_device_id qe_ids[] = { | ||
667 | { .compatible = "fsl,qe", }, | ||
668 | { }, | ||
669 | }; | ||
670 | |||
671 | static struct of_platform_driver qe_driver = { | ||
672 | .driver.name = "fsl-qe", | ||
673 | .match_table = qe_ids, | ||
674 | .probe = qe_probe, | ||
675 | .resume = qe_resume, | ||
676 | }; | ||
677 | |||
678 | static int __init qe_drv_init(void) | ||
679 | { | ||
680 | return of_register_platform_driver(&qe_driver); | ||
681 | } | ||
682 | device_initcall(qe_drv_init); | ||
683 | #endif /* defined(CONFIG_SUSPEND) && defined(CONFIG_PPC_85xx) */ | ||
diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/arch/powerpc/sysdev/qe_lib/qe_ic.c index 3faa42e03a85..2acc928d1920 100644 --- a/arch/powerpc/sysdev/qe_lib/qe_ic.c +++ b/arch/powerpc/sysdev/qe_lib/qe_ic.c | |||
@@ -189,7 +189,7 @@ static inline void qe_ic_write(volatile __be32 __iomem * base, unsigned int reg | |||
189 | 189 | ||
190 | static inline struct qe_ic *qe_ic_from_irq(unsigned int virq) | 190 | static inline struct qe_ic *qe_ic_from_irq(unsigned int virq) |
191 | { | 191 | { |
192 | return irq_desc[virq].chip_data; | 192 | return irq_to_desc(virq)->chip_data; |
193 | } | 193 | } |
194 | 194 | ||
195 | #define virq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq) | 195 | #define virq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq) |
@@ -237,7 +237,7 @@ static void qe_ic_mask_irq(unsigned int virq) | |||
237 | } | 237 | } |
238 | 238 | ||
239 | static struct irq_chip qe_ic_irq_chip = { | 239 | static struct irq_chip qe_ic_irq_chip = { |
240 | .typename = " QEIC ", | 240 | .name = " QEIC ", |
241 | .unmask = qe_ic_unmask_irq, | 241 | .unmask = qe_ic_unmask_irq, |
242 | .mask = qe_ic_mask_irq, | 242 | .mask = qe_ic_mask_irq, |
243 | .mask_ack = qe_ic_mask_irq, | 243 | .mask_ack = qe_ic_mask_irq, |
@@ -263,7 +263,7 @@ static int qe_ic_host_map(struct irq_host *h, unsigned int virq, | |||
263 | chip = &qe_ic->hc_irq; | 263 | chip = &qe_ic->hc_irq; |
264 | 264 | ||
265 | set_irq_chip_data(virq, qe_ic); | 265 | set_irq_chip_data(virq, qe_ic); |
266 | get_irq_desc(virq)->status |= IRQ_LEVEL; | 266 | irq_to_desc(virq)->status |= IRQ_LEVEL; |
267 | 267 | ||
268 | set_irq_chip_and_handler(virq, chip, handle_level_irq); | 268 | set_irq_chip_and_handler(virq, chip, handle_level_irq); |
269 | 269 | ||
@@ -271,7 +271,7 @@ static int qe_ic_host_map(struct irq_host *h, unsigned int virq, | |||
271 | } | 271 | } |
272 | 272 | ||
273 | static int qe_ic_host_xlate(struct irq_host *h, struct device_node *ct, | 273 | static int qe_ic_host_xlate(struct irq_host *h, struct device_node *ct, |
274 | u32 * intspec, unsigned int intsize, | 274 | const u32 * intspec, unsigned int intsize, |
275 | irq_hw_number_t * out_hwirq, | 275 | irq_hw_number_t * out_hwirq, |
276 | unsigned int *out_flags) | 276 | unsigned int *out_flags) |
277 | { | 277 | { |
diff --git a/arch/powerpc/sysdev/tsi108_pci.c b/arch/powerpc/sysdev/tsi108_pci.c index cf244a419e96..595034cfb85a 100644 --- a/arch/powerpc/sysdev/tsi108_pci.c +++ b/arch/powerpc/sysdev/tsi108_pci.c | |||
@@ -376,7 +376,7 @@ static void tsi108_pci_irq_end(u_int irq) | |||
376 | */ | 376 | */ |
377 | 377 | ||
378 | static struct irq_chip tsi108_pci_irq = { | 378 | static struct irq_chip tsi108_pci_irq = { |
379 | .typename = "tsi108_PCI_int", | 379 | .name = "tsi108_PCI_int", |
380 | .mask = tsi108_pci_irq_disable, | 380 | .mask = tsi108_pci_irq_disable, |
381 | .ack = tsi108_pci_irq_ack, | 381 | .ack = tsi108_pci_irq_ack, |
382 | .end = tsi108_pci_irq_end, | 382 | .end = tsi108_pci_irq_end, |
@@ -384,7 +384,7 @@ static struct irq_chip tsi108_pci_irq = { | |||
384 | }; | 384 | }; |
385 | 385 | ||
386 | static int pci_irq_host_xlate(struct irq_host *h, struct device_node *ct, | 386 | static int pci_irq_host_xlate(struct irq_host *h, struct device_node *ct, |
387 | u32 *intspec, unsigned int intsize, | 387 | const u32 *intspec, unsigned int intsize, |
388 | irq_hw_number_t *out_hwirq, unsigned int *out_flags) | 388 | irq_hw_number_t *out_hwirq, unsigned int *out_flags) |
389 | { | 389 | { |
390 | *out_hwirq = intspec[0]; | 390 | *out_hwirq = intspec[0]; |
@@ -398,7 +398,7 @@ static int pci_irq_host_map(struct irq_host *h, unsigned int virq, | |||
398 | DBG("%s(%d, 0x%lx)\n", __func__, virq, hw); | 398 | DBG("%s(%d, 0x%lx)\n", __func__, virq, hw); |
399 | if ((virq >= 1) && (virq <= 4)){ | 399 | if ((virq >= 1) && (virq <= 4)){ |
400 | irq = virq + IRQ_PCI_INTAD_BASE - 1; | 400 | irq = virq + IRQ_PCI_INTAD_BASE - 1; |
401 | get_irq_desc(irq)->status |= IRQ_LEVEL; | 401 | irq_to_desc(irq)->status |= IRQ_LEVEL; |
402 | set_irq_chip(irq, &tsi108_pci_irq); | 402 | set_irq_chip(irq, &tsi108_pci_irq); |
403 | } | 403 | } |
404 | return 0; | 404 | return 0; |
diff --git a/arch/powerpc/sysdev/uic.c b/arch/powerpc/sysdev/uic.c index 466ce9ace127..7d10074b3304 100644 --- a/arch/powerpc/sysdev/uic.c +++ b/arch/powerpc/sysdev/uic.c | |||
@@ -57,7 +57,7 @@ struct uic { | |||
57 | 57 | ||
58 | static void uic_unmask_irq(unsigned int virq) | 58 | static void uic_unmask_irq(unsigned int virq) |
59 | { | 59 | { |
60 | struct irq_desc *desc = get_irq_desc(virq); | 60 | struct irq_desc *desc = irq_to_desc(virq); |
61 | struct uic *uic = get_irq_chip_data(virq); | 61 | struct uic *uic = get_irq_chip_data(virq); |
62 | unsigned int src = uic_irq_to_hw(virq); | 62 | unsigned int src = uic_irq_to_hw(virq); |
63 | unsigned long flags; | 63 | unsigned long flags; |
@@ -101,7 +101,7 @@ static void uic_ack_irq(unsigned int virq) | |||
101 | 101 | ||
102 | static void uic_mask_ack_irq(unsigned int virq) | 102 | static void uic_mask_ack_irq(unsigned int virq) |
103 | { | 103 | { |
104 | struct irq_desc *desc = get_irq_desc(virq); | 104 | struct irq_desc *desc = irq_to_desc(virq); |
105 | struct uic *uic = get_irq_chip_data(virq); | 105 | struct uic *uic = get_irq_chip_data(virq); |
106 | unsigned int src = uic_irq_to_hw(virq); | 106 | unsigned int src = uic_irq_to_hw(virq); |
107 | unsigned long flags; | 107 | unsigned long flags; |
@@ -129,7 +129,7 @@ static int uic_set_irq_type(unsigned int virq, unsigned int flow_type) | |||
129 | { | 129 | { |
130 | struct uic *uic = get_irq_chip_data(virq); | 130 | struct uic *uic = get_irq_chip_data(virq); |
131 | unsigned int src = uic_irq_to_hw(virq); | 131 | unsigned int src = uic_irq_to_hw(virq); |
132 | struct irq_desc *desc = get_irq_desc(virq); | 132 | struct irq_desc *desc = irq_to_desc(virq); |
133 | unsigned long flags; | 133 | unsigned long flags; |
134 | int trigger, polarity; | 134 | int trigger, polarity; |
135 | u32 tr, pr, mask; | 135 | u32 tr, pr, mask; |
@@ -177,7 +177,7 @@ static int uic_set_irq_type(unsigned int virq, unsigned int flow_type) | |||
177 | } | 177 | } |
178 | 178 | ||
179 | static struct irq_chip uic_irq_chip = { | 179 | static struct irq_chip uic_irq_chip = { |
180 | .typename = " UIC ", | 180 | .name = " UIC ", |
181 | .unmask = uic_unmask_irq, | 181 | .unmask = uic_unmask_irq, |
182 | .mask = uic_mask_irq, | 182 | .mask = uic_mask_irq, |
183 | .mask_ack = uic_mask_ack_irq, | 183 | .mask_ack = uic_mask_ack_irq, |
@@ -202,7 +202,7 @@ static int uic_host_map(struct irq_host *h, unsigned int virq, | |||
202 | } | 202 | } |
203 | 203 | ||
204 | static int uic_host_xlate(struct irq_host *h, struct device_node *ct, | 204 | static int uic_host_xlate(struct irq_host *h, struct device_node *ct, |
205 | u32 *intspec, unsigned int intsize, | 205 | const u32 *intspec, unsigned int intsize, |
206 | irq_hw_number_t *out_hwirq, unsigned int *out_type) | 206 | irq_hw_number_t *out_hwirq, unsigned int *out_type) |
207 | 207 | ||
208 | { | 208 | { |
diff --git a/arch/powerpc/sysdev/xilinx_intc.c b/arch/powerpc/sysdev/xilinx_intc.c index 40edad520770..1e0ccfaf403e 100644 --- a/arch/powerpc/sysdev/xilinx_intc.c +++ b/arch/powerpc/sysdev/xilinx_intc.c | |||
@@ -79,7 +79,7 @@ static void xilinx_intc_mask(unsigned int virq) | |||
79 | 79 | ||
80 | static int xilinx_intc_set_type(unsigned int virq, unsigned int flow_type) | 80 | static int xilinx_intc_set_type(unsigned int virq, unsigned int flow_type) |
81 | { | 81 | { |
82 | struct irq_desc *desc = get_irq_desc(virq); | 82 | struct irq_desc *desc = irq_to_desc(virq); |
83 | 83 | ||
84 | desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL); | 84 | desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL); |
85 | desc->status |= flow_type & IRQ_TYPE_SENSE_MASK; | 85 | desc->status |= flow_type & IRQ_TYPE_SENSE_MASK; |
@@ -106,7 +106,7 @@ static void xilinx_intc_level_unmask(unsigned int virq) | |||
106 | } | 106 | } |
107 | 107 | ||
108 | static struct irq_chip xilinx_intc_level_irqchip = { | 108 | static struct irq_chip xilinx_intc_level_irqchip = { |
109 | .typename = "Xilinx Level INTC", | 109 | .name = "Xilinx Level INTC", |
110 | .mask = xilinx_intc_mask, | 110 | .mask = xilinx_intc_mask, |
111 | .mask_ack = xilinx_intc_mask, | 111 | .mask_ack = xilinx_intc_mask, |
112 | .unmask = xilinx_intc_level_unmask, | 112 | .unmask = xilinx_intc_level_unmask, |
@@ -133,7 +133,7 @@ static void xilinx_intc_edge_ack(unsigned int virq) | |||
133 | } | 133 | } |
134 | 134 | ||
135 | static struct irq_chip xilinx_intc_edge_irqchip = { | 135 | static struct irq_chip xilinx_intc_edge_irqchip = { |
136 | .typename = "Xilinx Edge INTC", | 136 | .name = "Xilinx Edge INTC", |
137 | .mask = xilinx_intc_mask, | 137 | .mask = xilinx_intc_mask, |
138 | .unmask = xilinx_intc_edge_unmask, | 138 | .unmask = xilinx_intc_edge_unmask, |
139 | .ack = xilinx_intc_edge_ack, | 139 | .ack = xilinx_intc_edge_ack, |
@@ -148,7 +148,7 @@ static struct irq_chip xilinx_intc_edge_irqchip = { | |||
148 | * xilinx_intc_xlate - translate virq# from device tree interrupts property | 148 | * xilinx_intc_xlate - translate virq# from device tree interrupts property |
149 | */ | 149 | */ |
150 | static int xilinx_intc_xlate(struct irq_host *h, struct device_node *ct, | 150 | static int xilinx_intc_xlate(struct irq_host *h, struct device_node *ct, |
151 | u32 *intspec, unsigned int intsize, | 151 | const u32 *intspec, unsigned int intsize, |
152 | irq_hw_number_t *out_hwirq, | 152 | irq_hw_number_t *out_hwirq, |
153 | unsigned int *out_flags) | 153 | unsigned int *out_flags) |
154 | { | 154 | { |
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index bdbe96c8a7e4..4e6152c13764 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c | |||
@@ -1641,7 +1641,8 @@ static void super_regs(void) | |||
1641 | ptrLpPaca->saved_srr0, ptrLpPaca->saved_srr1); | 1641 | ptrLpPaca->saved_srr0, ptrLpPaca->saved_srr1); |
1642 | printf(" Saved Gpr3=%.16lx Saved Gpr4=%.16lx \n", | 1642 | printf(" Saved Gpr3=%.16lx Saved Gpr4=%.16lx \n", |
1643 | ptrLpPaca->saved_gpr3, ptrLpPaca->saved_gpr4); | 1643 | ptrLpPaca->saved_gpr3, ptrLpPaca->saved_gpr4); |
1644 | printf(" Saved Gpr5=%.16lx \n", ptrLpPaca->saved_gpr5); | 1644 | printf(" Saved Gpr5=%.16lx \n", |
1645 | ptrLpPaca->gpr5_dword.saved_gpr5); | ||
1645 | } | 1646 | } |
1646 | #endif | 1647 | #endif |
1647 | 1648 | ||