diff options
Diffstat (limited to 'arch')
192 files changed, 9748 insertions, 1821 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 36707dec94d7..e9af16cc7c0c 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/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 | ||
