diff options
54 files changed, 907 insertions, 290 deletions
diff --git a/Documentation/powerpc/00-INDEX b/Documentation/powerpc/00-INDEX index 3be84aa38dfe..29d839ce7327 100644 --- a/Documentation/powerpc/00-INDEX +++ b/Documentation/powerpc/00-INDEX | |||
| @@ -20,8 +20,6 @@ mpc52xx-device-tree-bindings.txt | |||
| 20 | - MPC5200 Device Tree Bindings | 20 | - MPC5200 Device Tree Bindings |
| 21 | ppc_htab.txt | 21 | ppc_htab.txt |
| 22 | - info about the Linux/PPC /proc/ppc_htab entry | 22 | - info about the Linux/PPC /proc/ppc_htab entry |
| 23 | SBC8260_memory_mapping.txt | ||
| 24 | - EST SBC8260 board info | ||
| 25 | smp.txt | 23 | smp.txt |
| 26 | - use and state info about Linux/PPC on MP machines | 24 | - use and state info about Linux/PPC on MP machines |
| 27 | sound.txt | 25 | sound.txt |
diff --git a/Documentation/powerpc/SBC8260_memory_mapping.txt b/Documentation/powerpc/SBC8260_memory_mapping.txt deleted file mode 100644 index e6e9ee0506c3..000000000000 --- a/Documentation/powerpc/SBC8260_memory_mapping.txt +++ /dev/null | |||
| @@ -1,197 +0,0 @@ | |||
| 1 | Please mail me (Jon Diekema, diekema_jon@si.com or diekema@cideas.com) | ||
| 2 | if you have questions, comments or corrections. | ||
| 3 | |||
| 4 | * EST SBC8260 Linux memory mapping rules | ||
| 5 | |||
| 6 | http://www.estc.com/ | ||
| 7 | http://www.estc.com/products/boards/SBC8260-8240_ds.html | ||
| 8 | |||
| 9 | Initial conditions: | ||
| 10 | ------------------- | ||
| 11 | |||
| 12 | Tasks that need to be perform by the boot ROM before control is | ||
| 13 | transferred to zImage (compressed Linux kernel): | ||
| 14 | |||
| 15 | - Define the IMMR to 0xf0000000 | ||
| 16 | |||
| 17 | - Initialize the memory controller so that RAM is available at | ||
| 18 | physical address 0x00000000. On the SBC8260 is this 16M (64M) | ||
| 19 | SDRAM. | ||
| 20 | |||
| 21 | - The boot ROM should only clear the RAM that it is using. | ||
| 22 | |||
| 23 | The reason for doing this is to enhances the chances of a | ||
| 24 | successful post mortem on a Linux panic. One of the first | ||
| 25 | items to examine is the 16k (LOG_BUF_LEN) circular console | ||
| 26 | buffer called log_buf which is defined in kernel/printk.c. | ||
| 27 | |||
| 28 | - To enhance boot ROM performance, the I-cache can be enabled. | ||
| 29 | |||
| 30 | Date: Mon, 22 May 2000 14:21:10 -0700 | ||
| 31 | From: Neil Russell <caret@c-side.com> | ||
| 32 | |||
| 33 | LiMon (LInux MONitor) runs with and starts Linux with MMU | ||
| 34 | off, I-cache enabled, D-cache disabled. The I-cache doesn't | ||
| 35 | need hints from the MMU to work correctly as the D-cache | ||
| 36 | does. No D-cache means no special code to handle devices in | ||
| 37 | the presence of cache (no snooping, etc). The use of the | ||
| 38 | I-cache means that the monitor can run acceptably fast | ||
| 39 | directly from ROM, rather than having to copy it to RAM. | ||
| 40 | |||
| 41 | - Build the board information structure (see | ||
| 42 | include/asm-ppc/est8260.h for its definition) | ||
| 43 | |||
| 44 | - The compressed Linux kernel (zImage) contains a bootstrap loader | ||
| 45 | that is position independent; you can load it into any RAM, | ||
| 46 | ROM or FLASH memory address >= 0x00500000 (above 5 MB), or | ||
| 47 | at its link address of 0x00400000 (4 MB). | ||
| 48 | |||
| 49 | Note: If zImage is loaded at its link address of 0x00400000 (4 MB), | ||
| 50 | then zImage will skip the step of moving itself to | ||
| 51 | its link address. | ||
| 52 | |||
| 53 | - Load R3 with the address of the board information structure | ||
| 54 | |||
| 55 | - Transfer control to zImage | ||
| 56 | |||
| 57 | - The Linux console port is SMC1, and the baud rate is controlled | ||
| 58 | from the bi_baudrate field of the board information structure. | ||
| 59 | On thing to keep in mind when picking the baud rate, is that | ||
| 60 | there is no flow control on the SMC ports. I would stick | ||
| 61 | with something safe and standard like 19200. | ||
| 62 | |||
| 63 | On the EST SBC8260, the SMC1 port is on the COM1 connector of | ||
| 64 | the board. | ||
| 65 | |||
| 66 | |||
| 67 | EST SBC8260 defaults: | ||
| 68 | --------------------- | ||
| 69 | |||
| 70 | Chip | ||
| 71 | Memory Sel Bus Use | ||
| 72 | --------------------- --- --- ---------------------------------- | ||
| 73 | 0x00000000-0x03FFFFFF CS2 60x (16M or 64M)/64M SDRAM | ||
| 74 | 0x04000000-0x04FFFFFF CS4 local 4M/16M SDRAM (soldered to the board) | ||
| 75 | 0x21000000-0x21000000 CS7 60x 1B/64K Flash present detect (from the flash SIMM) | ||
| 76 | 0x21000001-0x21000001 CS7 60x 1B/64K Switches (read) and LEDs (write) | ||
| 77 | 0x22000000-0x2200FFFF CS5 60x 8K/64K EEPROM | ||
| 78 | 0xFC000000-0xFCFFFFFF CS6 60x 2M/16M flash (8 bits wide, soldered to the board) | ||
| 79 | 0xFE000000-0xFFFFFFFF CS0 60x 4M/16M flash (SIMM) | ||
| 80 | |||
| 81 | Notes: | ||
| 82 | ------ | ||
| 83 | |||
| 84 | - The chip selects can map 32K blocks and up (powers of 2) | ||
| 85 | |||
| 86 | - The SDRAM machine can handled up to 128Mbytes per chip select | ||
| 87 | |||
| 88 | - Linux uses the 60x bus memory (the SDRAM DIMM) for the | ||
| 89 | communications buffers. | ||
| 90 | |||
| 91 | - BATs can map 128K-256Mbytes each. There are four data BATs and | ||
| 92 | four instruction BATs. Generally the data and instruction BATs | ||
| 93 | are mapped the same. | ||
| 94 | |||
| 95 | - The IMMR must be set above the kernel virtual memory addresses, | ||
| 96 | which start at 0xC0000000. Otherwise, the kernel may crash as | ||
| 97 | soon as you start any threads or processes due to VM collisions | ||
| 98 | in the kernel or user process space. | ||
| 99 | |||
| 100 | |||
| 101 | Details from Dan Malek <dan_malek@mvista.com> on 10/29/1999: | ||
| 102 | |||
| 103 | The user application virtual space consumes the first 2 Gbytes | ||
| 104 | (0x00000000 to 0x7FFFFFFF). The kernel virtual text starts at | ||
| 105 | 0xC0000000, with data following. There is a "protection hole" | ||
| 106 | between the end of kernel data and the start of the kernel | ||
| 107 | dynamically allocated space, but this space is still within | ||
| 108 | 0xCxxxxxxx. | ||
| 109 | |||
| 110 | Obviously the kernel can't map any physical addresses 1:1 in | ||
| 111 | these ranges. | ||
| 112 | |||
| 113 | |||
| 114 | Details from Dan Malek <dan_malek@mvista.com> on 5/19/2000: | ||
| 115 | |||
| 116 | During the early kernel initialization, the kernel virtual | ||
| 117 | memory allocator is not operational. Prior to this KVM | ||
| 118 | initialization, we choose to map virtual to physical addresses | ||
| 119 | 1:1. That is, the kernel virtual address exactly matches the | ||
| 120 | physical address on the bus. These mappings are typically done | ||
| 121 | in arch/ppc/kernel/head.S, or arch/ppc/mm/init.c. Only | ||
| 122 | absolutely necessary mappings should be done at this time, for | ||
| 123 | example board control registers or a serial uart. Normal device | ||
| 124 | driver initialization should map resources later when necessary. | ||
| 125 | |||
| 126 | Although platform dependent, and certainly the case for embedded | ||
| 127 | 8xx, traditionally memory is mapped at physical address zero, | ||
| 128 | and I/O devices above physical address 0x80000000. The lowest | ||
| 129 | and highest (above 0xf0000000) I/O addresses are traditionally | ||
| 130 | used for devices or registers we need to map during kernel | ||
| 131 | initialization and prior to KVM operation. For this reason, | ||
| 132 | and since it followed prior PowerPC platform examples, I chose | ||
| 133 | to map the embedded 8xx kernel to the 0xc0000000 virtual address. | ||
| 134 | This way, we can enable the MMU to map the kernel for proper | ||
| 135 | operation, and still map a few windows before the KVM is operational. | ||
| 136 | |||
| 137 | On some systems, you could possibly run the kernel at the | ||
| 138 | 0x80000000 or any other virtual address. It just depends upon | ||
| 139 | mapping that must be done prior to KVM operational. You can never | ||
| 140 | map devices or kernel spaces that overlap with the user virtual | ||
| 141 | space. This is why default IMMR mapping used by most BDM tools | ||
| 142 | won't work. They put the IMMR at something like 0x10000000 or | ||
| 143 | 0x02000000 for example. You simply can't map these addresses early | ||
| 144 | in the kernel, and continue proper system operation. | ||
| 145 | |||
| 146 | The embedded 8xx/82xx kernel is mature enough that all you should | ||
| 147 | need to do is map the IMMR someplace at or above 0xf0000000 and it | ||
| 148 | should boot far enough to get serial console messages and KGDB | ||
| 149 | connected on any platform. There are lots of other subtle memory | ||
| 150 | management design features that you simply don't need to worry | ||
| 151 | about. If you are changing functions related to MMU initialization, | ||
| 152 | you are likely breaking things that are known to work and are | ||
| 153 | heading down a path of disaster and frustration. Your changes | ||
| 154 | should be to make the flexibility of the processor fit Linux, | ||
| 155 | not force arbitrary and non-workable memory mappings into Linux. | ||
| 156 | |||
| 157 | - You don't want to change KERNELLOAD or KERNELBASE, otherwise the | ||
| 158 | virtual memory and MMU code will get confused. | ||
| 159 | |||
| 160 | arch/ppc/Makefile:KERNELLOAD = 0xc0000000 | ||
| 161 | |||
| 162 | include/asm-ppc/page.h:#define PAGE_OFFSET 0xc0000000 | ||
| 163 | include/asm-ppc/page.h:#define KERNELBASE PAGE_OFFSET | ||
| 164 | |||
| 165 | - RAM is at physical address 0x00000000, and gets mapped to | ||
| 166 | virtual address 0xC0000000 for the kernel. | ||
| 167 | |||
| 168 | |||
| 169 | Physical addresses used by the Linux kernel: | ||
| 170 | -------------------------------------------- | ||
| 171 | |||
| 172 | 0x00000000-0x3FFFFFFF 1GB reserved for RAM | ||
| 173 | 0xF0000000-0xF001FFFF 128K IMMR 64K used for dual port memory, | ||
| 174 | 64K for 8260 registers | ||
| 175 | |||
| 176 | |||
| 177 | Logical addresses used by the Linux kernel: | ||
| 178 | ------------------------------------------- | ||
| 179 | |||
| 180 | 0xF0000000-0xFFFFFFFF 256M BAT0 (IMMR: dual port RAM, registers) | ||
| 181 | 0xE0000000-0xEFFFFFFF 256M BAT1 (I/O space for custom boards) | ||
| 182 | 0xC0000000-0xCFFFFFFF 256M BAT2 (RAM) | ||
| 183 | 0xD0000000-0xDFFFFFFF 256M BAT3 (if RAM > 256MByte) | ||
| 184 | |||
| 185 | |||
| 186 | EST SBC8260 Linux mapping: | ||
| 187 | -------------------------- | ||
| 188 | |||
| 189 | DBAT0, IBAT0, cache inhibited: | ||
| 190 | |||
| 191 | Chip | ||
| 192 | Memory Sel Use | ||
| 193 | --------------------- --- --------------------------------- | ||
| 194 | 0xF0000000-0xF001FFFF n/a IMMR: dual port RAM, registers | ||
| 195 | |||
| 196 | DBAT1, IBAT1, cache inhibited: | ||
| 197 | |||
diff --git a/Documentation/powerpc/dts-bindings/fsl/cpm_qe/serial.txt b/Documentation/powerpc/dts-bindings/fsl/cpm_qe/serial.txt index b35f3482e3e4..2ea76d9d137c 100644 --- a/Documentation/powerpc/dts-bindings/fsl/cpm_qe/serial.txt +++ b/Documentation/powerpc/dts-bindings/fsl/cpm_qe/serial.txt | |||
| @@ -7,6 +7,15 @@ Currently defined compatibles: | |||
| 7 | - fsl,cpm2-scc-uart | 7 | - fsl,cpm2-scc-uart |
| 8 | - fsl,qe-uart | 8 | - fsl,qe-uart |
| 9 | 9 | ||
| 10 | Modem control lines connected to GPIO controllers are listed in the gpios | ||
| 11 | property as described in booting-without-of.txt, section IX.1 in the following | ||
| 12 | order: | ||
| 13 | |||
| 14 | CTS, RTS, DCD, DSR, DTR, and RI. | ||
| 15 | |||
| 16 | The gpios property is optional and can be left out when control lines are | ||
| 17 | not used. | ||
| 18 | |||
| 10 | Example: | 19 | Example: |
| 11 | 20 | ||
| 12 | serial@11a00 { | 21 | serial@11a00 { |
| @@ -18,4 +27,6 @@ Example: | |||
| 18 | interrupt-parent = <&PIC>; | 27 | interrupt-parent = <&PIC>; |
| 19 | fsl,cpm-brg = <1>; | 28 | fsl,cpm-brg = <1>; |
| 20 | fsl,cpm-command = <00800000>; | 29 | fsl,cpm-command = <00800000>; |
| 30 | gpios = <&gpio_c 15 0 | ||
| 31 | &gpio_d 29 0>; | ||
| 21 | }; | 32 | }; |
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 587da5e0990f..63c9cafda9c4 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig | |||
| @@ -42,6 +42,9 @@ config GENERIC_HARDIRQS | |||
| 42 | bool | 42 | bool |
| 43 | default y | 43 | default y |
| 44 | 44 | ||
| 45 | config HAVE_GET_USER_PAGES_FAST | ||
| 46 | def_bool PPC64 | ||
| 47 | |||
| 45 | config HAVE_SETUP_PER_CPU_AREA | 48 | config HAVE_SETUP_PER_CPU_AREA |
| 46 | def_bool PPC64 | 49 | def_bool PPC64 |
| 47 | 50 | ||
diff --git a/arch/powerpc/boot/dts/mpc832x_mds.dts b/arch/powerpc/boot/dts/mpc832x_mds.dts index 7345743d3d96..fbc930410ff6 100644 --- a/arch/powerpc/boot/dts/mpc832x_mds.dts +++ b/arch/powerpc/boot/dts/mpc832x_mds.dts | |||
| @@ -68,6 +68,7 @@ | |||
| 68 | #address-cells = <1>; | 68 | #address-cells = <1>; |
| 69 | #size-cells = <1>; | 69 | #size-cells = <1>; |
| 70 | device_type = "soc"; | 70 | device_type = "soc"; |
| 71 | compatible = "simple-bus"; | ||
| 71 | ranges = <0x0 0xe0000000 0x00100000>; | 72 | ranges = <0x0 0xe0000000 0x00100000>; |
| 72 | reg = <0xe0000000 0x00000200>; | 73 | reg = <0xe0000000 0x00000200>; |
| 73 | bus-frequency = <132000000>; | 74 | bus-frequency = <132000000>; |
diff --git a/arch/powerpc/boot/dts/mpc832x_rdb.dts b/arch/powerpc/boot/dts/mpc832x_rdb.dts index e74c045a0f8c..b157d1885a28 100644 --- a/arch/powerpc/boot/dts/mpc832x_rdb.dts +++ b/arch/powerpc/boot/dts/mpc832x_rdb.dts | |||
| @@ -51,6 +51,7 @@ | |||
| 51 | #address-cells = <1>; | 51 | #address-cells = <1>; |
| 52 | #size-cells = <1>; | 52 | #size-cells = <1>; |
| 53 | device_type = "soc"; | 53 | device_type = "soc"; |
| 54 | compatible = "simple-bus"; | ||
| 54 | ranges = <0x0 0xe0000000 0x00100000>; | 55 | ranges = <0x0 0xe0000000 0x00100000>; |
| 55 | reg = <0xe0000000 0x00000200>; | 56 | reg = <0xe0000000 0x00000200>; |
| 56 | bus-frequency = <0>; | 57 | bus-frequency = <0>; |
diff --git a/arch/powerpc/boot/dts/mpc8349emitx.dts b/arch/powerpc/boot/dts/mpc8349emitx.dts index 8dfab5662585..700e076ef3f5 100644 --- a/arch/powerpc/boot/dts/mpc8349emitx.dts +++ b/arch/powerpc/boot/dts/mpc8349emitx.dts | |||
| @@ -52,6 +52,7 @@ | |||
| 52 | #address-cells = <1>; | 52 | #address-cells = <1>; |
| 53 | #size-cells = <1>; | 53 | #size-cells = <1>; |
| 54 | device_type = "soc"; | 54 | device_type = "soc"; |
| 55 | compatible = "simple-bus"; | ||
| 55 | ranges = <0x0 0xe0000000 0x00100000>; | 56 | ranges = <0x0 0xe0000000 0x00100000>; |
| 56 | reg = <0xe0000000 0x00000200>; | 57 | reg = <0xe0000000 0x00000200>; |
| 57 | bus-frequency = <0>; // from bootloader | 58 | bus-frequency = <0>; // from bootloader |
diff --git a/arch/powerpc/boot/dts/mpc8349emitxgp.dts b/arch/powerpc/boot/dts/mpc8349emitxgp.dts index 49ca3497eefb..cdd3063258ea 100644 --- a/arch/powerpc/boot/dts/mpc8349emitxgp.dts +++ b/arch/powerpc/boot/dts/mpc8349emitxgp.dts | |||
| @@ -50,6 +50,7 @@ | |||
| 50 | #address-cells = <1>; | 50 | #address-cells = <1>; |
| 51 | #size-cells = <1>; | 51 | #size-cells = <1>; |
| 52 | device_type = "soc"; | 52 | device_type = "soc"; |
| 53 | compatible = "simple-bus"; | ||
| 53 | ranges = <0x0 0xe0000000 0x00100000>; | 54 | ranges = <0x0 0xe0000000 0x00100000>; |
| 54 | reg = <0xe0000000 0x00000200>; | 55 | reg = <0xe0000000 0x00000200>; |
| 55 | bus-frequency = <0>; // from bootloader | 56 | bus-frequency = <0>; // from bootloader |
diff --git a/arch/powerpc/boot/dts/mpc834x_mds.dts b/arch/powerpc/boot/dts/mpc834x_mds.dts index ba586cb7afbb..783241c00240 100644 --- a/arch/powerpc/boot/dts/mpc834x_mds.dts +++ b/arch/powerpc/boot/dts/mpc834x_mds.dts | |||
| @@ -57,6 +57,7 @@ | |||
| 57 | #address-cells = <1>; | 57 | #address-cells = <1>; |
| 58 | #size-cells = <1>; | 58 | #size-cells = <1>; |
| 59 | device_type = "soc"; | 59 | device_type = "soc"; |
| 60 | compatible = "simple-bus"; | ||
| 60 | ranges = <0x0 0xe0000000 0x00100000>; | 61 | ranges = <0x0 0xe0000000 0x00100000>; |
| 61 | reg = <0xe0000000 0x00000200>; | 62 | reg = <0xe0000000 0x00000200>; |
| 62 | bus-frequency = <0>; | 63 | bus-frequency = <0>; |
diff --git a/arch/powerpc/boot/dts/mpc836x_mds.dts b/arch/powerpc/boot/dts/mpc836x_mds.dts index 3701dae1ee02..a3b76a709951 100644 --- a/arch/powerpc/boot/dts/mpc836x_mds.dts +++ b/arch/powerpc/boot/dts/mpc836x_mds.dts | |||
| @@ -61,6 +61,7 @@ | |||
| 61 | #address-cells = <1>; | 61 | #address-cells = <1>; |
| 62 | #size-cells = <1>; | 62 | #size-cells = <1>; |
| 63 | device_type = "soc"; | 63 | device_type = "soc"; |
| 64 | compatible = "simple-bus"; | ||
| 64 | ranges = <0x0 0xe0000000 0x00100000>; | 65 | ranges = <0x0 0xe0000000 0x00100000>; |
| 65 | reg = <0xe0000000 0x00000200>; | 66 | reg = <0xe0000000 0x00000200>; |
| 66 | bus-frequency = <264000000>; | 67 | bus-frequency = <264000000>; |
diff --git a/arch/powerpc/boot/dts/mpc836x_rdk.dts b/arch/powerpc/boot/dts/mpc836x_rdk.dts index 8acd1d6577f2..89c9202f8bd7 100644 --- a/arch/powerpc/boot/dts/mpc836x_rdk.dts +++ b/arch/powerpc/boot/dts/mpc836x_rdk.dts | |||
| @@ -149,18 +149,14 @@ | |||
| 149 | }; | 149 | }; |
| 150 | 150 | ||
| 151 | crypto@30000 { | 151 | crypto@30000 { |
| 152 | compatible = "fsl,sec2-crypto"; | 152 | compatible = "fsl,sec2.0"; |
| 153 | reg = <0x30000 0x10000>; | 153 | reg = <0x30000 0x10000>; |
| 154 | interrupts = <11 8>; | 154 | interrupts = <11 0x8>; |
| 155 | interrupt-parent = <&ipic>; | 155 | interrupt-parent = <&ipic>; |
| 156 | num-channels = <4>; | 156 | fsl,num-channels = <4>; |
| 157 | channel-fifo-len = <24>; | 157 | fsl,channel-fifo-len = <24>; |
| 158 | exec-units-mask = <0x7e>; | 158 | fsl,exec-units-mask = <0x7e>; |
| 159 | /* | 159 | fsl,descriptor-types-mask = <0x01010ebf>; |
| 160 | * desc mask is for rev1.x, we need runtime fixup | ||
| 161 | * for >=2.x | ||
| 162 | */ | ||
| 163 | descriptor-types-mask = <0x1010ebf>; | ||
| 164 | }; | 160 | }; |
| 165 | 161 | ||
| 166 | ipic: interrupt-controller@700 { | 162 | ipic: interrupt-controller@700 { |
diff --git a/arch/powerpc/boot/dts/mpc8377_mds.dts b/arch/powerpc/boot/dts/mpc8377_mds.dts index 0a700cb5f611..432782b6d20a 100644 --- a/arch/powerpc/boot/dts/mpc8377_mds.dts +++ b/arch/powerpc/boot/dts/mpc8377_mds.dts | |||
| @@ -117,6 +117,7 @@ | |||
| 117 | #address-cells = <1>; | 117 | #address-cells = <1>; |
| 118 | #size-cells = <1>; | 118 | #size-cells = <1>; |
| 119 | device_type = "soc"; | 119 | device_type = "soc"; |
| 120 | compatible = "simple-bus"; | ||
| 120 | ranges = <0x0 0xe0000000 0x00100000>; | 121 | ranges = <0x0 0xe0000000 0x00100000>; |
| 121 | reg = <0xe0000000 0x00000200>; | 122 | reg = <0xe0000000 0x00000200>; |
| 122 | bus-frequency = <0>; | 123 | bus-frequency = <0>; |
diff --git a/arch/powerpc/boot/dts/mpc8378_mds.dts b/arch/powerpc/boot/dts/mpc8378_mds.dts index 29c8c76a58f7..ed32c8ddafe3 100644 --- a/arch/powerpc/boot/dts/mpc8378_mds.dts +++ b/arch/powerpc/boot/dts/mpc8378_mds.dts | |||
| @@ -117,6 +117,7 @@ | |||
| 117 | #address-cells = <1>; | 117 | #address-cells = <1>; |
| 118 | #size-cells = <1>; | 118 | #size-cells = <1>; |
| 119 | device_type = "soc"; | 119 | device_type = "soc"; |
| 120 | compatible = "simple-bus"; | ||
| 120 | ranges = <0x0 0xe0000000 0x00100000>; | 121 | ranges = <0x0 0xe0000000 0x00100000>; |
| 121 | reg = <0xe0000000 0x00000200>; | 122 | reg = <0xe0000000 0x00000200>; |
| 122 | bus-frequency = <0>; | 123 | bus-frequency = <0>; |
diff --git a/arch/powerpc/boot/dts/mpc8379_mds.dts b/arch/powerpc/boot/dts/mpc8379_mds.dts index d641a8985ea3..f4db9ed4a301 100644 --- a/arch/powerpc/boot/dts/mpc8379_mds.dts +++ b/arch/powerpc/boot/dts/mpc8379_mds.dts | |||
| @@ -117,6 +117,7 @@ | |||
| 117 | #address-cells = <1>; | 117 | #address-cells = <1>; |
| 118 | #size-cells = <1>; | 118 | #size-cells = <1>; |
| 119 | device_type = "soc"; | 119 | device_type = "soc"; |
| 120 | compatible = "simple-bus"; | ||
| 120 | ranges = <0x0 0xe0000000 0x00100000>; | 121 | ranges = <0x0 0xe0000000 0x00100000>; |
| 121 | reg = <0xe0000000 0x00000200>; | 122 | reg = <0xe0000000 0x00000200>; |
| 122 | bus-frequency = <0>; | 123 | bus-frequency = <0>; |
diff --git a/arch/powerpc/boot/dts/mpc8536ds.dts b/arch/powerpc/boot/dts/mpc8536ds.dts index 02cfa24a1695..1505d6855eff 100644 --- a/arch/powerpc/boot/dts/mpc8536ds.dts +++ b/arch/powerpc/boot/dts/mpc8536ds.dts | |||
| @@ -49,6 +49,7 @@ | |||
| 49 | #address-cells = <1>; | 49 | #address-cells = <1>; |
| 50 | #size-cells = <1>; | 50 | #size-cells = <1>; |
| 51 | device_type = "soc"; | 51 | device_type = "soc"; |
| 52 | compatible = "simple-bus"; | ||
| 52 | ranges = <0x0 0xffe00000 0x100000>; | 53 | ranges = <0x0 0xffe00000 0x100000>; |
| 53 | reg = <0xffe00000 0x1000>; | 54 | reg = <0xffe00000 0x1000>; |
| 54 | bus-frequency = <0>; // Filled out by uboot. | 55 | bus-frequency = <0>; // Filled out by uboot. |
diff --git a/arch/powerpc/boot/dts/mpc8540ads.dts b/arch/powerpc/boot/dts/mpc8540ads.dts index f2273a872b11..9568bfaff8f7 100644 --- a/arch/powerpc/boot/dts/mpc8540ads.dts +++ b/arch/powerpc/boot/dts/mpc8540ads.dts | |||
| @@ -53,6 +53,7 @@ | |||
| 53 | #address-cells = <1>; | 53 | #address-cells = <1>; |
| 54 | #size-cells = <1>; | 54 | #size-cells = <1>; |
| 55 | device_type = "soc"; | 55 | device_type = "soc"; |
| 56 | compatible = "simple-bus"; | ||
| 56 | ranges = <0x0 0xe0000000 0x100000>; | 57 | ranges = <0x0 0xe0000000 0x100000>; |
| 57 | reg = <0xe0000000 0x100000>; // CCSRBAR 1M | 58 | reg = <0xe0000000 0x100000>; // CCSRBAR 1M |
| 58 | bus-frequency = <0>; | 59 | bus-frequency = <0>; |
diff --git a/arch/powerpc/boot/dts/mpc8541cds.dts b/arch/powerpc/boot/dts/mpc8541cds.dts index c4469f19ff82..6480f4fd96e0 100644 --- a/arch/powerpc/boot/dts/mpc8541cds.dts +++ b/arch/powerpc/boot/dts/mpc8541cds.dts | |||
| @@ -53,6 +53,7 @@ | |||
| 53 | #address-cells = <1>; | 53 | #address-cells = <1>; |
| 54 | #size-cells = <1>; | 54 | #size-cells = <1>; |
| 55 | device_type = "soc"; | 55 | device_type = "soc"; |
| 56 | compatible = "simple-bus"; | ||
| 56 | ranges = <0x0 0xe0000000 0x100000>; | 57 | ranges = <0x0 0xe0000000 0x100000>; |
| 57 | reg = <0xe0000000 0x1000>; // CCSRBAR 1M | 58 | reg = <0xe0000000 0x1000>; // CCSRBAR 1M |
| 58 | bus-frequency = <0>; | 59 | bus-frequency = <0>; |
diff --git a/arch/powerpc/boot/dts/mpc8544ds.dts b/arch/powerpc/boot/dts/mpc8544ds.dts index 7d3829d3495e..f1fb20737e3e 100644 --- a/arch/powerpc/boot/dts/mpc8544ds.dts +++ b/arch/powerpc/boot/dts/mpc8544ds.dts | |||
| @@ -54,6 +54,7 @@ | |||
| 54 | #address-cells = <1>; | 54 | #address-cells = <1>; |
| 55 | #size-cells = <1>; | 55 | #size-cells = <1>; |
| 56 | device_type = "soc"; | 56 | device_type = "soc"; |
| 57 | compatible = "simple-bus"; | ||
| 57 | 58 | ||
| 58 | ranges = <0x0 0xe0000000 0x100000>; | 59 | ranges = <0x0 0xe0000000 0x100000>; |
| 59 | reg = <0xe0000000 0x1000>; // CCSRBAR 1M | 60 | reg = <0xe0000000 0x1000>; // CCSRBAR 1M |
diff --git a/arch/powerpc/boot/dts/mpc8548cds.dts b/arch/powerpc/boot/dts/mpc8548cds.dts index d84466bb7eca..431b496270dc 100644 --- a/arch/powerpc/boot/dts/mpc8548cds.dts +++ b/arch/powerpc/boot/dts/mpc8548cds.dts | |||
| @@ -58,6 +58,7 @@ | |||
| 58 | #address-cells = <1>; | 58 | #address-cells = <1>; |
| 59 | #size-cells = <1>; | 59 | #size-cells = <1>; |
| 60 | device_type = "soc"; | 60 | device_type = "soc"; |
| 61 | compatible = "simple-bus"; | ||
| 61 | ranges = <0x0 0xe0000000 0x100000>; | 62 | ranges = <0x0 0xe0000000 0x100000>; |
| 62 | reg = <0xe0000000 0x1000>; // CCSRBAR | 63 | reg = <0xe0000000 0x1000>; // CCSRBAR |
| 63 | bus-frequency = <0>; | 64 | bus-frequency = <0>; |
diff --git a/arch/powerpc/boot/dts/mpc8555cds.dts b/arch/powerpc/boot/dts/mpc8555cds.dts index e03a78006283..d833a5c4f476 100644 --- a/arch/powerpc/boot/dts/mpc8555cds.dts +++ b/arch/powerpc/boot/dts/mpc8555cds.dts | |||
| @@ -53,6 +53,7 @@ | |||
| 53 | #address-cells = <1>; | 53 | #address-cells = <1>; |
| 54 | #size-cells = <1>; | 54 | #size-cells = <1>; |
| 55 | device_type = "soc"; | 55 | device_type = "soc"; |
| 56 | compatible = "simple-bus"; | ||
| 56 | ranges = <0x0 0xe0000000 0x100000>; | 57 | ranges = <0x0 0xe0000000 0x100000>; |
| 57 | reg = <0xe0000000 0x1000>; // CCSRBAR 1M | 58 | reg = <0xe0000000 0x1000>; // CCSRBAR 1M |
| 58 | bus-frequency = <0>; | 59 | bus-frequency = <0>; |
diff --git a/arch/powerpc/boot/dts/mpc8560ads.dts b/arch/powerpc/boot/dts/mpc8560ads.dts index ba8159de040b..4d1f2f284094 100644 --- a/arch/powerpc/boot/dts/mpc8560ads.dts +++ b/arch/powerpc/boot/dts/mpc8560ads.dts | |||
| @@ -53,6 +53,7 @@ | |||
| 53 | #address-cells = <1>; | 53 | #address-cells = <1>; |
| 54 | #size-cells = <1>; | 54 | #size-cells = <1>; |
| 55 | device_type = "soc"; | 55 | device_type = "soc"; |
| 56 | compatible = "simple-bus"; | ||
| 56 | ranges = <0x0 0xe0000000 0x100000>; | 57 | ranges = <0x0 0xe0000000 0x100000>; |
| 57 | reg = <0xe0000000 0x200>; | 58 | reg = <0xe0000000 0x200>; |
| 58 | bus-frequency = <330000000>; | 59 | bus-frequency = <330000000>; |
diff --git a/arch/powerpc/boot/dts/mpc8568mds.dts b/arch/powerpc/boot/dts/mpc8568mds.dts index 9c30a34821dc..a15f10343f53 100644 --- a/arch/powerpc/boot/dts/mpc8568mds.dts +++ b/arch/powerpc/boot/dts/mpc8568mds.dts | |||
| @@ -60,6 +60,7 @@ | |||
| 60 | #address-cells = <1>; | 60 | #address-cells = <1>; |
| 61 | #size-cells = <1>; | 61 | #size-cells = <1>; |
| 62 | device_type = "soc"; | 62 | device_type = "soc"; |
| 63 | compatible = "simple-bus"; | ||
| 63 | ranges = <0x0 0xe0000000 0x100000>; | 64 | ranges = <0x0 0xe0000000 0x100000>; |
| 64 | reg = <0xe0000000 0x1000>; | 65 | reg = <0xe0000000 0x1000>; |
| 65 | bus-frequency = <0>; | 66 | bus-frequency = <0>; |
diff --git a/arch/powerpc/boot/dts/mpc8572ds.dts b/arch/powerpc/boot/dts/mpc8572ds.dts index 08c61e3daecc..e124dd18fb5a 100644 --- a/arch/powerpc/boot/dts/mpc8572ds.dts +++ b/arch/powerpc/boot/dts/mpc8572ds.dts | |||
| @@ -68,6 +68,7 @@ | |||
| 68 | #address-cells = <1>; | 68 | #address-cells = <1>; |
| 69 | #size-cells = <1>; | 69 | #size-cells = <1>; |
| 70 | device_type = "soc"; | 70 | device_type = "soc"; |
| 71 | compatible = "simple-bus"; | ||
| 71 | ranges = <0x0 0xffe00000 0x100000>; | 72 | ranges = <0x0 0xffe00000 0x100000>; |
| 72 | reg = <0xffe00000 0x1000>; // CCSRBAR & soc regs, remove once parse code for immrbase fixed | 73 | reg = <0xffe00000 0x1000>; // CCSRBAR & soc regs, remove once parse code for immrbase fixed |
| 73 | bus-frequency = <0>; // Filled out by uboot. | 74 | bus-frequency = <0>; // Filled out by uboot. |
diff --git a/arch/powerpc/kernel/lparcfg.c b/arch/powerpc/kernel/lparcfg.c index 9f856a0c3e38..1a09719c7628 100644 --- a/arch/powerpc/kernel/lparcfg.c +++ b/arch/powerpc/kernel/lparcfg.c | |||
| @@ -636,10 +636,6 @@ static ssize_t lparcfg_write(struct file *file, const char __user * buf, | |||
| 636 | retval = -EIO; | 636 | retval = -EIO; |
| 637 | } else if (retval == H_PARAMETER) { | 637 | } else if (retval == H_PARAMETER) { |
| 638 | retval = -EINVAL; | 638 | retval = -EINVAL; |
| 639 | } else { | ||
| 640 | printk(KERN_WARNING "%s: received unknown hv return code %ld", | ||
| 641 | __func__, retval); | ||
| 642 | retval = -EIO; | ||
| 643 | } | 639 | } |
| 644 | 640 | ||
| 645 | return retval; | 641 | return retval; |
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 6b66cd85b433..3635be61f899 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c | |||
| @@ -375,7 +375,7 @@ static int vsr_get(struct task_struct *target, const struct user_regset *regset, | |||
| 375 | flush_vsx_to_thread(target); | 375 | flush_vsx_to_thread(target); |
| 376 | 376 | ||
| 377 | for (i = 0; i < 32 ; i++) | 377 | for (i = 0; i < 32 ; i++) |
| 378 | buf[i] = current->thread.fpr[i][TS_VSRLOWOFFSET]; | 378 | buf[i] = target->thread.fpr[i][TS_VSRLOWOFFSET]; |
| 379 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, | 379 | ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, |
| 380 | buf, 0, 32 * sizeof(double)); | 380 | buf, 0, 32 * sizeof(double)); |
| 381 | 381 | ||
| @@ -394,7 +394,7 @@ static int vsr_set(struct task_struct *target, const struct user_regset *regset, | |||
| 394 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, | 394 | ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, |
| 395 | buf, 0, 32 * sizeof(double)); | 395 | buf, 0, 32 * sizeof(double)); |
| 396 | for (i = 0; i < 32 ; i++) | 396 | for (i = 0; i < 32 ; i++) |
| 397 | current->thread.fpr[i][TS_VSRLOWOFFSET] = buf[i]; | 397 | target->thread.fpr[i][TS_VSRLOWOFFSET] = buf[i]; |
| 398 | 398 | ||
| 399 | 399 | ||
| 400 | return ret; | 400 | return ret; |
| @@ -975,15 +975,13 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) | |||
| 975 | case PTRACE_GETVSRREGS: | 975 | case PTRACE_GETVSRREGS: |
| 976 | return copy_regset_to_user(child, &user_ppc_native_view, | 976 | return copy_regset_to_user(child, &user_ppc_native_view, |
| 977 | REGSET_VSX, | 977 | REGSET_VSX, |
| 978 | 0, (32 * sizeof(vector128) + | 978 | 0, 32 * sizeof(double), |
| 979 | sizeof(u32)), | ||
| 980 | (void __user *) data); | 979 | (void __user *) data); |
| 981 | 980 | ||
| 982 | case PTRACE_SETVSRREGS: | 981 | case PTRACE_SETVSRREGS: |
| 983 | return copy_regset_from_user(child, &user_ppc_native_view, | 982 | return copy_regset_from_user(child, &user_ppc_native_view, |
| 984 | REGSET_VSX, | 983 | REGSET_VSX, |
| 985 | 0, (32 * sizeof(vector128) + | 984 | 0, 32 * sizeof(double), |
| 986 | sizeof(u32)), | ||
| 987 | (const void __user *) data); | 985 | (const void __user *) data); |
| 988 | #endif | 986 | #endif |
| 989 | #ifdef CONFIG_SPE | 987 | #ifdef CONFIG_SPE |
diff --git a/arch/powerpc/kernel/ptrace32.c b/arch/powerpc/kernel/ptrace32.c index 67bf1a1e7e14..197d49c790ad 100644 --- a/arch/powerpc/kernel/ptrace32.c +++ b/arch/powerpc/kernel/ptrace32.c | |||
| @@ -294,6 +294,8 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, | |||
| 294 | case PTRACE_SETFPREGS: | 294 | case PTRACE_SETFPREGS: |
| 295 | case PTRACE_GETVRREGS: | 295 | case PTRACE_GETVRREGS: |
| 296 | case PTRACE_SETVRREGS: | 296 | case PTRACE_SETVRREGS: |
| 297 | case PTRACE_GETVSRREGS: | ||
| 298 | case PTRACE_SETVSRREGS: | ||
| 297 | case PTRACE_GETREGS64: | 299 | case PTRACE_GETREGS64: |
| 298 | case PTRACE_SETREGS64: | 300 | case PTRACE_SETREGS64: |
| 299 | case PPC_PTRACE_GETFPREGS: | 301 | case PPC_PTRACE_GETFPREGS: |
diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile index 1c00e0196f6c..e7392b45a5ef 100644 --- a/arch/powerpc/mm/Makefile +++ b/arch/powerpc/mm/Makefile | |||
| @@ -12,7 +12,8 @@ obj-y := fault.o mem.o \ | |||
| 12 | mmu_context_$(CONFIG_WORD_SIZE).o | 12 | mmu_context_$(CONFIG_WORD_SIZE).o |
| 13 | hash-$(CONFIG_PPC_NATIVE) := hash_native_64.o | 13 | hash-$(CONFIG_PPC_NATIVE) := hash_native_64.o |
| 14 | obj-$(CONFIG_PPC64) += hash_utils_64.o \ | 14 | obj-$(CONFIG_PPC64) += hash_utils_64.o \ |
| 15 | slb_low.o slb.o stab.o mmap.o $(hash-y) | 15 | slb_low.o slb.o stab.o \ |
| 16 | gup.o mmap.o $(hash-y) | ||
| 16 | obj-$(CONFIG_PPC_STD_MMU_32) += ppc_mmu_32.o | 17 | obj-$(CONFIG_PPC_STD_MMU_32) += ppc_mmu_32.o |
| 17 | obj-$(CONFIG_PPC_STD_MMU) += hash_low_$(CONFIG_WORD_SIZE).o \ | 18 | obj-$(CONFIG_PPC_STD_MMU) += hash_low_$(CONFIG_WORD_SIZE).o \ |
| 18 | tlb_$(CONFIG_WORD_SIZE).o | 19 | tlb_$(CONFIG_WORD_SIZE).o |
diff --git a/arch/powerpc/mm/gup.c b/arch/powerpc/mm/gup.c new file mode 100644 index 000000000000..9fdf4d6335e4 --- /dev/null +++ b/arch/powerpc/mm/gup.c | |||
| @@ -0,0 +1,280 @@ | |||
| 1 | /* | ||
| 2 | * Lockless get_user_pages_fast for powerpc | ||
| 3 | * | ||
| 4 | * Copyright (C) 2008 Nick Piggin | ||
| 5 | * Copyright (C) 2008 Novell Inc. | ||
| 6 | */ | ||
| 7 | #undef DEBUG | ||
| 8 | |||
| 9 | #include <linux/sched.h> | ||
| 10 | #include <linux/mm.h> | ||
| 11 | #include <linux/hugetlb.h> | ||
| 12 | #include <linux/vmstat.h> | ||
| 13 | #include <linux/pagemap.h> | ||
| 14 | #include <linux/rwsem.h> | ||
| 15 | #include <asm/pgtable.h> | ||
| 16 | |||
| 17 | /* | ||
| 18 | * The performance critical leaf functions are made noinline otherwise gcc | ||
| 19 | * inlines everything into a single function which results in too much | ||
| 20 | * register pressure. | ||
| 21 | */ | ||
| 22 | static noinline int gup_pte_range(pmd_t pmd, unsigned long addr, | ||
| 23 | unsigned long end, int write, struct page **pages, int *nr) | ||
| 24 | { | ||
| 25 | unsigned long mask, result; | ||
| 26 | pte_t *ptep; | ||
| 27 | |||
| 28 | result = _PAGE_PRESENT|_PAGE_USER; | ||
| 29 | if (write) | ||
| 30 | result |= _PAGE_RW; | ||
| 31 | mask = result | _PAGE_SPECIAL; | ||
| 32 | |||
| 33 | ptep = pte_offset_kernel(&pmd, addr); | ||
| 34 | do { | ||
| 35 | pte_t pte = *ptep; | ||
| 36 | struct page *page; | ||
| 37 | |||
| 38 | if ((pte_val(pte) & mask) != result) | ||
| 39 | return 0; | ||
| 40 | VM_BUG_ON(!pfn_valid(pte_pfn(pte))); | ||
| 41 | page = pte_page(pte); | ||
| 42 | if (!page_cache_get_speculative(page)) | ||
| 43 | return 0; | ||
| 44 | if (unlikely(pte != *ptep)) { | ||
| 45 | put_page(page); | ||
| 46 | return 0; | ||
| 47 | } | ||
| 48 | pages[*nr] = page; | ||
| 49 | (*nr)++; | ||
| 50 | |||
| 51 | } while (ptep++, addr += PAGE_SIZE, addr != end); | ||
| 52 | |||
| 53 | return 1; | ||
| 54 | } | ||
| 55 | |||
| 56 | #ifdef CONFIG_HUGETLB_PAGE | ||
| 57 | static noinline int gup_huge_pte(pte_t *ptep, struct hstate *hstate, | ||
| 58 | unsigned long *addr, unsigned long end, | ||
| 59 | int write, struct page **pages, int *nr) | ||
| 60 | { | ||
| 61 | unsigned long mask; | ||
| 62 | unsigned long pte_end; | ||
| 63 | struct page *head, *page; | ||
| 64 | pte_t pte; | ||
| 65 | int refs; | ||
| 66 | |||
| 67 | pte_end = (*addr + huge_page_size(hstate)) & huge_page_mask(hstate); | ||
| 68 | if (pte_end < end) | ||
| 69 | end = pte_end; | ||
| 70 | |||
| 71 | pte = *ptep; | ||
| 72 | mask = _PAGE_PRESENT|_PAGE_USER; | ||
| 73 | if (write) | ||
| 74 | mask |= _PAGE_RW; | ||
| 75 | if ((pte_val(pte) & mask) != mask) | ||
| 76 | return 0; | ||
| 77 | /* hugepages are never "special" */ | ||
| 78 | VM_BUG_ON(!pfn_valid(pte_pfn(pte))); | ||
| 79 | |||
| 80 | refs = 0; | ||
| 81 | head = pte_page(pte); | ||
| 82 | page = head + ((*addr & ~huge_page_mask(hstate)) >> PAGE_SHIFT); | ||
| 83 | do { | ||
| 84 | VM_BUG_ON(compound_head(page) != head); | ||
| 85 | pages[*nr] = page; | ||
| 86 | (*nr)++; | ||
| 87 | page++; | ||
| 88 | refs++; | ||
| 89 | } while (*addr += PAGE_SIZE, *addr != end); | ||
| 90 | |||
| 91 | if (!page_cache_add_speculative(head, refs)) { | ||
| 92 | *nr -= refs; | ||
| 93 | return 0; | ||
| 94 | } | ||
| 95 | if (unlikely(pte != *ptep)) { | ||
| 96 | /* Could be optimized better */ | ||
| 97 | while (*nr) { | ||
| 98 | put_page(page); | ||
| 99 | (*nr)--; | ||
| 100 | } | ||
| 101 | } | ||
| 102 | |||
| 103 | return 1; | ||
| 104 | } | ||
| 105 | #endif /* CONFIG_HUGETLB_PAGE */ | ||
| 106 | |||
| 107 | static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end, | ||
| 108 | int write, struct page **pages, int *nr) | ||
| 109 | { | ||
| 110 | unsigned long next; | ||
| 111 | pmd_t *pmdp; | ||
| 112 | |||
| 113 | pmdp = pmd_offset(&pud, addr); | ||
| 114 | do { | ||
| 115 | pmd_t pmd = *pmdp; | ||
| 116 | |||
| 117 | next = pmd_addr_end(addr, end); | ||
| 118 | if (pmd_none(pmd)) | ||
| 119 | return 0; | ||
| 120 | if (!gup_pte_range(pmd, addr, next, write, pages, nr)) | ||
| 121 | return 0; | ||
| 122 | } while (pmdp++, addr = next, addr != end); | ||
| 123 | |||
| 124 | return 1; | ||
| 125 | } | ||
| 126 | |||
| 127 | static int gup_pud_range(pgd_t pgd, unsigned long addr, unsigned long end, | ||
| 128 | int write, struct page **pages, int *nr) | ||
| 129 | { | ||
| 130 | unsigned long next; | ||
| 131 | pud_t *pudp; | ||
| 132 | |||
| 133 | pudp = pud_offset(&pgd, addr); | ||
| 134 | do { | ||
| 135 | pud_t pud = *pudp; | ||
| 136 | |||
| 137 | next = pud_addr_end(addr, end); | ||
| 138 | if (pud_none(pud)) | ||
| 139 | return 0; | ||
| 140 | if (!gup_pmd_range(pud, addr, next, write, pages, nr)) | ||
| 141 | return 0; | ||
| 142 | } while (pudp++, addr = next, addr != end); | ||
| 143 | |||
| 144 | return 1; | ||
| 145 | } | ||
| 146 | |||
| 147 | int get_user_pages_fast(unsigned long start, int nr_pages, int write, | ||
| 148 | struct page **pages) | ||
| 149 | { | ||
| 150 | struct mm_struct *mm = current->mm; | ||
| 151 | unsigned long addr, len, end; | ||
| 152 | unsigned long next; | ||
| 153 | pgd_t *pgdp; | ||
| 154 | int psize, nr = 0; | ||
| 155 | unsigned int shift; | ||
| 156 | |||
| 157 | pr_debug("%s(%lx,%x,%s)\n", __func__, start, nr_pages, write ? "write" : "read"); | ||
| 158 | |||
| 159 | start &= PAGE_MASK; | ||
| 160 | addr = start; | ||
| 161 | len = (unsigned long) nr_pages << PAGE_SHIFT; | ||
| 162 | end = start + len; | ||
| 163 | |||
| 164 | if (unlikely(!access_ok(write ? VERIFY_WRITE : VERIFY_READ, | ||
| 165 | start, len))) | ||
| 166 | goto slow_irqon; | ||
| 167 | |||
| 168 | pr_debug(" aligned: %lx .. %lx\n", start, end); | ||
| 169 | |||
| 170 | #ifdef CONFIG_HUGETLB_PAGE | ||
| 171 | /* We bail out on slice boundary crossing when hugetlb is | ||
| 172 | * enabled in order to not have to deal with two different | ||
| 173 | * page table formats | ||
| 174 | */ | ||
| 175 | if (addr < SLICE_LOW_TOP) { | ||
| 176 | if (end > SLICE_LOW_TOP) | ||
| 177 | goto slow_irqon; | ||
| 178 | |||
| 179 | if (unlikely(GET_LOW_SLICE_INDEX(addr) != | ||
| 180 | GET_LOW_SLICE_INDEX(end - 1))) | ||
| 181 | goto slow_irqon; | ||
| 182 | } else { | ||
| 183 | if (unlikely(GET_HIGH_SLICE_INDEX(addr) != | ||
| 184 | GET_HIGH_SLICE_INDEX(end - 1))) | ||
| 185 | goto slow_irqon; | ||
| 186 | } | ||
| 187 | #endif /* CONFIG_HUGETLB_PAGE */ | ||
| 188 | |||
| 189 | /* | ||
| 190 | * XXX: batch / limit 'nr', to avoid large irq off latency | ||
| 191 | * needs some instrumenting to determine the common sizes used by | ||
| 192 | * important workloads (eg. DB2), and whether limiting the batch size | ||
| 193 | * will decrease performance. | ||
| 194 | * | ||
| 195 | * It seems like we're in the clear for the moment. Direct-IO is | ||
| 196 | * the main guy that batches up lots of get_user_pages, and even | ||
| 197 | * they are limited to 64-at-a-time which is not so many. | ||
| 198 | */ | ||
| 199 | /* | ||
| 200 | * This doesn't prevent pagetable teardown, but does prevent | ||
| 201 | * the pagetables from being freed on powerpc. | ||
| 202 | * | ||
| 203 | * So long as we atomically load page table pointers versus teardown, | ||
| 204 | * we can follow the address down to the the page and take a ref on it. | ||
| 205 | */ | ||
| 206 | local_irq_disable(); | ||
| 207 | |||
| 208 | psize = get_slice_psize(mm, addr); | ||
| 209 | shift = mmu_psize_defs[psize].shift; | ||
| 210 | |||
| 211 | #ifdef CONFIG_HUGETLB_PAGE | ||
| 212 | if (unlikely(mmu_huge_psizes[psize])) { | ||
| 213 | pte_t *ptep; | ||
| 214 | unsigned long a = addr; | ||
| 215 | unsigned long sz = ((1UL) << shift); | ||
| 216 | struct hstate *hstate = size_to_hstate(sz); | ||
| 217 | |||
| 218 | BUG_ON(!hstate); | ||
| 219 | /* | ||
| 220 | * XXX: could be optimized to avoid hstate | ||
| 221 | * lookup entirely (just use shift) | ||
| 222 | */ | ||
| 223 | |||
| 224 | do { | ||
| 225 | VM_BUG_ON(shift != mmu_psize_defs[get_slice_psize(mm, a)].shift); | ||
| 226 | ptep = huge_pte_offset(mm, a); | ||
| 227 | pr_debug(" %016lx: huge ptep %p\n", a, ptep); | ||
| 228 | if (!ptep || !gup_huge_pte(ptep, hstate, &a, end, write, pages, | ||
| 229 | &nr)) | ||
| 230 | goto slow; | ||
| 231 | } while (a != end); | ||
| 232 | } else | ||
| 233 | #endif /* CONFIG_HUGETLB_PAGE */ | ||
| 234 | { | ||
| 235 | pgdp = pgd_offset(mm, addr); | ||
| 236 | do { | ||
| 237 | pgd_t pgd = *pgdp; | ||
| 238 | |||
| 239 | VM_BUG_ON(shift != mmu_psize_defs[get_slice_psize(mm, addr)].shift); | ||
| 240 | pr_debug(" %016lx: normal pgd %p\n", addr, (void *)pgd); | ||
| 241 | next = pgd_addr_end(addr, end); | ||
| 242 | if (pgd_none(pgd)) | ||
| 243 | goto slow; | ||
| 244 | if (!gup_pud_range(pgd, addr, next, write, pages, &nr)) | ||
| 245 | goto slow; | ||
| 246 | } while (pgdp++, addr = next, addr != end); | ||
| 247 | } | ||
| 248 | local_irq_enable(); | ||
| 249 | |||
| 250 | VM_BUG_ON(nr != (end - start) >> PAGE_SHIFT); | ||
| 251 | return nr; | ||
| 252 | |||
| 253 | { | ||
| 254 | int ret; | ||
| 255 | |||
| 256 | slow: | ||
| 257 | local_irq_enable(); | ||
| 258 | slow_irqon: | ||
| 259 | pr_debug(" slow path ! nr = %d\n", nr); | ||
| 260 | |||
| 261 | /* Try to get the remaining pages with get_user_pages */ | ||
| 262 | start += nr << PAGE_SHIFT; | ||
| 263 | pages += nr; | ||
| 264 | |||
| 265 | down_read(&mm->mmap_sem); | ||
| 266 | ret = get_user_pages(current, mm, start, | ||
| 267 | (end - start) >> PAGE_SHIFT, write, 0, pages, NULL); | ||
| 268 | up_read(&mm->mmap_sem); | ||
| 269 | |||
| 270 | /* Have to be a bit careful with return values */ | ||
| 271 | if (nr > 0) { | ||
| 272 | if (ret < 0) | ||
| 273 | ret = nr; | ||
| 274 | else | ||
| 275 | ret += nr; | ||
| 276 | } | ||
| 277 | |||
| 278 | return ret; | ||
| 279 | } | ||
| 280 | } | ||
diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.c b/arch/powerpc/platforms/83xx/mpc832x_mds.c index dd4be4aee314..ec43477caa63 100644 --- a/arch/powerpc/platforms/83xx/mpc832x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc832x_mds.c | |||
| @@ -105,6 +105,7 @@ static void __init mpc832x_sys_setup_arch(void) | |||
| 105 | static struct of_device_id mpc832x_ids[] = { | 105 | static struct of_device_id mpc832x_ids[] = { |
| 106 | { .type = "soc", }, | 106 | { .type = "soc", }, |
| 107 | { .compatible = "soc", }, | 107 | { .compatible = "soc", }, |
| 108 | { .compatible = "simple-bus", }, | ||
| 108 | { .type = "qe", }, | 109 | { .type = "qe", }, |
| 109 | { .compatible = "fsl,qe", }, | 110 | { .compatible = "fsl,qe", }, |
| 110 | {}, | 111 | {}, |
diff --git a/arch/powerpc/platforms/83xx/mpc832x_rdb.c b/arch/powerpc/platforms/83xx/mpc832x_rdb.c index f049d692d4c8..0300268ce5b8 100644 --- a/arch/powerpc/platforms/83xx/mpc832x_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc832x_rdb.c | |||
| @@ -115,6 +115,7 @@ static void __init mpc832x_rdb_setup_arch(void) | |||
| 115 | static struct of_device_id mpc832x_ids[] = { | 115 | static struct of_device_id mpc832x_ids[] = { |
| 116 | { .type = "soc", }, | 116 | { .type = "soc", }, |
| 117 | { .compatible = "soc", }, | 117 | { .compatible = "soc", }, |
| 118 | { .compatible = "simple-bus", }, | ||
| 118 | { .type = "qe", }, | 119 | { .type = "qe", }, |
| 119 | { .compatible = "fsl,qe", }, | 120 | { .compatible = "fsl,qe", }, |
| 120 | {}, | 121 | {}, |
diff --git a/arch/powerpc/platforms/83xx/mpc834x_itx.c b/arch/powerpc/platforms/83xx/mpc834x_itx.c index 7301d77a08ee..76092d37c7d9 100644 --- a/arch/powerpc/platforms/83xx/mpc834x_itx.c +++ b/arch/powerpc/platforms/83xx/mpc834x_itx.c | |||
| @@ -41,6 +41,7 @@ | |||
| 41 | 41 | ||
| 42 | static struct of_device_id __initdata mpc834x_itx_ids[] = { | 42 | static struct of_device_id __initdata mpc834x_itx_ids[] = { |
| 43 | { .compatible = "fsl,pq2pro-localbus", }, | 43 | { .compatible = "fsl,pq2pro-localbus", }, |
| 44 | { .compatible = "simple-bus", }, | ||
| 44 | {}, | 45 | {}, |
| 45 | }; | 46 | }; |
| 46 | 47 | ||
diff --git a/arch/powerpc/platforms/83xx/mpc834x_mds.c b/arch/powerpc/platforms/83xx/mpc834x_mds.c index 30d509aa9f08..fc3f2ed1f3e9 100644 --- a/arch/powerpc/platforms/83xx/mpc834x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc834x_mds.c | |||
| @@ -111,6 +111,7 @@ static void __init mpc834x_mds_init_IRQ(void) | |||
| 111 | static struct of_device_id mpc834x_ids[] = { | 111 | static struct of_device_id mpc834x_ids[] = { |
| 112 | { .type = "soc", }, | 112 | { .type = "soc", }, |
| 113 | { .compatible = "soc", }, | 113 | { .compatible = "soc", }, |
| 114 | { .compatible = "simple-bus", }, | ||
| 114 | {}, | 115 | {}, |
| 115 | }; | 116 | }; |
| 116 | 117 | ||
diff --git a/arch/powerpc/platforms/83xx/mpc836x_mds.c b/arch/powerpc/platforms/83xx/mpc836x_mds.c index 75b80e836576..9d46e5bdd101 100644 --- a/arch/powerpc/platforms/83xx/mpc836x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc836x_mds.c | |||
| @@ -136,6 +136,7 @@ static void __init mpc836x_mds_setup_arch(void) | |||
| 136 | static struct of_device_id mpc836x_ids[] = { | 136 | static struct of_device_id mpc836x_ids[] = { |
| 137 | { .type = "soc", }, | 137 | { .type = "soc", }, |
| 138 | { .compatible = "soc", }, | 138 | { .compatible = "soc", }, |
| 139 | { .compatible = "simple-bus", }, | ||
| 139 | { .type = "qe", }, | 140 | { .type = "qe", }, |
| 140 | { .compatible = "fsl,qe", }, | 141 | { .compatible = "fsl,qe", }, |
| 141 | {}, | 142 | {}, |
diff --git a/arch/powerpc/platforms/83xx/sbc834x.c b/arch/powerpc/platforms/83xx/sbc834x.c index fc21f5c15bab..156c4e218009 100644 --- a/arch/powerpc/platforms/83xx/sbc834x.c +++ b/arch/powerpc/platforms/83xx/sbc834x.c | |||
| @@ -83,6 +83,7 @@ static void __init sbc834x_init_IRQ(void) | |||
| 83 | static struct __initdata of_device_id sbc834x_ids[] = { | 83 | static struct __initdata of_device_id sbc834x_ids[] = { |
| 84 | { .type = "soc", }, | 84 | { .type = "soc", }, |
| 85 | { .compatible = "soc", }, | 85 | { .compatible = "soc", }, |
| 86 | { .compatible = "simple-bus", }, | ||
| 86 | {}, | 87 | {}, |
| 87 | }; | 88 | }; |
| 88 | 89 | ||
diff --git a/arch/powerpc/platforms/85xx/ksi8560.c b/arch/powerpc/platforms/85xx/ksi8560.c index 2145adeb220c..8a3b117b6ce2 100644 --- a/arch/powerpc/platforms/85xx/ksi8560.c +++ b/arch/powerpc/platforms/85xx/ksi8560.c | |||
| @@ -222,6 +222,7 @@ static void ksi8560_show_cpuinfo(struct seq_file *m) | |||
| 222 | 222 | ||
| 223 | static struct of_device_id __initdata of_bus_ids[] = { | 223 | static struct of_device_id __initdata of_bus_ids[] = { |
| 224 | { .type = "soc", }, | 224 | { .type = "soc", }, |
| 225 | { .type = "simple-bus", }, | ||
| 225 | { .name = "cpm", }, | 226 | { .name = "cpm", }, |
| 226 | { .name = "localbus", }, | 227 | { .name = "localbus", }, |
| 227 | {}, | 228 | {}, |
diff --git a/arch/powerpc/platforms/85xx/mpc8536_ds.c b/arch/powerpc/platforms/85xx/mpc8536_ds.c index 6b846aa1ced9..1bf5aefdfeb1 100644 --- a/arch/powerpc/platforms/85xx/mpc8536_ds.c +++ b/arch/powerpc/platforms/85xx/mpc8536_ds.c | |||
| @@ -91,6 +91,7 @@ static void __init mpc8536_ds_setup_arch(void) | |||
| 91 | static struct of_device_id __initdata mpc8536_ds_ids[] = { | 91 | static struct of_device_id __initdata mpc8536_ds_ids[] = { |
| 92 | { .type = "soc", }, | 92 | { .type = "soc", }, |
| 93 | { .compatible = "soc", }, | 93 | { .compatible = "soc", }, |
| 94 | { .compatible = "simple-bus", }, | ||
| 94 | {}, | 95 | {}, |
| 95 | }; | 96 | }; |
| 96 | 97 | ||
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c index ba498d6f2d02..d17807a6b89a 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c | |||
| @@ -230,6 +230,7 @@ static struct of_device_id __initdata of_bus_ids[] = { | |||
| 230 | { .type = "soc", }, | 230 | { .type = "soc", }, |
| 231 | { .name = "cpm", }, | 231 | { .name = "cpm", }, |
| 232 | { .name = "localbus", }, | 232 | { .name = "localbus", }, |
| 233 | { .compatible = "simple-bus", }, | ||
| 233 | {}, | 234 | {}, |
| 234 | }; | 235 | }; |
| 235 | 236 | ||
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ds.c b/arch/powerpc/platforms/85xx/mpc85xx_ds.c index 00c535806647..483b65cbabae 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ds.c | |||
| @@ -186,6 +186,7 @@ static int __init mpc8544_ds_probe(void) | |||
| 186 | static struct of_device_id __initdata mpc85xxds_ids[] = { | 186 | static struct of_device_id __initdata mpc85xxds_ids[] = { |
| 187 | { .type = "soc", }, | 187 | { .type = "soc", }, |
| 188 | { .compatible = "soc", }, | 188 | { .compatible = "soc", }, |
| 189 | { .compatible = "simple-bus", }, | ||
| 189 | {}, | 190 | {}, |
| 190 | }; | 191 | }; |
| 191 | 192 | ||
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c index 43a459f63e31..2494c5155919 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c | |||
| @@ -260,6 +260,7 @@ machine_arch_initcall(mpc85xx_mds, board_fixups); | |||
| 260 | static struct of_device_id mpc85xx_ids[] = { | 260 | static struct of_device_id mpc85xx_ids[] = { |
| 261 | { .type = "soc", }, | 261 | { .type = "soc", }, |
| 262 | { .compatible = "soc", }, | 262 | { .compatible = "soc", }, |
| 263 | { .compatible = "simple-bus", }, | ||
| 263 | { .type = "qe", }, | 264 | { .type = "qe", }, |
| 264 | { .compatible = "fsl,qe", }, | 265 | { .compatible = "fsl,qe", }, |
| 265 | {}, | 266 | {}, |
diff --git a/arch/powerpc/platforms/85xx/sbc8560.c b/arch/powerpc/platforms/85xx/sbc8560.c index 2c580cd24e4f..6509ade71668 100644 --- a/arch/powerpc/platforms/85xx/sbc8560.c +++ b/arch/powerpc/platforms/85xx/sbc8560.c | |||
| @@ -217,6 +217,7 @@ static struct of_device_id __initdata of_bus_ids[] = { | |||
| 217 | { .type = "soc", }, | 217 | { .type = "soc", }, |
| 218 | { .name = "cpm", }, | 218 | { .name = "cpm", }, |
| 219 | { .name = "localbus", }, | 219 | { .name = "localbus", }, |
| 220 | { .compatible = "simple-bus", }, | ||
| 220 | {}, | 221 | {}, |
| 221 | }; | 222 | }; |
| 222 | 223 | ||
diff --git a/arch/powerpc/platforms/8xx/Kconfig b/arch/powerpc/platforms/8xx/Kconfig index 6fc849e51e48..71d7562e190b 100644 --- a/arch/powerpc/platforms/8xx/Kconfig +++ b/arch/powerpc/platforms/8xx/Kconfig | |||
| @@ -105,6 +105,16 @@ config 8xx_COPYBACK | |||
| 105 | 105 | ||
| 106 | If in doubt, say Y here. | 106 | If in doubt, say Y here. |
| 107 | 107 | ||
| 108 | config 8xx_GPIO | ||
| 109 | bool "GPIO API Support" | ||
| 110 | select GENERIC_GPIO | ||
| 111 | select ARCH_REQUIRE_GPIOLIB | ||
| 112 | help | ||
| 113 | Saying Y here will cause the ports on an MPC8xx processor to be used | ||
| 114 | with the GPIO API. If you say N here, the kernel needs less memory. | ||
| 115 | |||
| 116 | If in doubt, say Y here. | ||
| 117 | |||
| 108 | config 8xx_CPU6 | 118 | config 8xx_CPU6 |
| 109 | bool "CPU6 Silicon Errata (860 Pre Rev. C)" | 119 | bool "CPU6 Silicon Errata (860 Pre Rev. C)" |
| 110 | help | 120 | help |
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index 1d0968775c0a..4c900efa164e 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig | |||
| @@ -254,6 +254,8 @@ config CPM2 | |||
| 254 | select CPM | 254 | select CPM |
| 255 | select PPC_LIB_RHEAP | 255 | select PPC_LIB_RHEAP |
| 256 | select PPC_PCI_CHOICE | 256 | select PPC_PCI_CHOICE |
| 257 | select ARCH_REQUIRE_GPIOLIB | ||
| 258 | select GENERIC_GPIO | ||
| 257 | help | 259 | help |
| 258 | The CPM2 (Communications Processor Module) is a coprocessor on | 260 | The CPM2 (Communications Processor Module) is a coprocessor on |
| 259 | embedded CPUs made by Freescale. Selecting this option means that | 261 | embedded CPUs made by Freescale. Selecting this option means that |
| @@ -281,6 +283,7 @@ config FSL_ULI1575 | |||
| 281 | 283 | ||
| 282 | config CPM | 284 | config CPM |
| 283 | bool | 285 | bool |
| 286 | select PPC_CLOCK | ||
| 284 | 287 | ||
| 285 | config OF_RTC | 288 | config OF_RTC |
| 286 | bool | 289 | bool |
diff --git a/arch/powerpc/sysdev/cpm1.c b/arch/powerpc/sysdev/cpm1.c index 661df42830b9..4a04823e8423 100644 --- a/arch/powerpc/sysdev/cpm1.c +++ b/arch/powerpc/sysdev/cpm1.c | |||
| @@ -30,6 +30,7 @@ | |||
| 30 | #include <linux/interrupt.h> | 30 | #include <linux/interrupt.h> |
| 31 | #include <linux/irq.h> | 31 | #include <linux/irq.h> |
| 32 | #include <linux/module.h> | 32 | #include <linux/module.h> |
| 33 | #include <linux/spinlock.h> | ||
| 33 | #include <asm/page.h> | 34 | #include <asm/page.h> |
| 34 | #include <asm/pgtable.h> | 35 | #include <asm/pgtable.h> |
| 35 | #include <asm/8xx_immap.h> | 36 | #include <asm/8xx_immap.h> |
| @@ -42,6 +43,10 @@ | |||
| 42 | 43 | ||
| 43 | #include <asm/fs_pd.h> | 44 | #include <asm/fs_pd.h> |
| 44 | 45 | ||
| 46 | #ifdef CONFIG_8xx_GPIO | ||
| 47 | #include <linux/of_gpio.h> | ||
| 48 | #endif | ||
| 49 | |||
| 45 | #define CPM_MAP_SIZE (0x4000) | 50 | #define CPM_MAP_SIZE (0x4000) |
| 46 | 51 | ||
| 47 | cpm8xx_t __iomem *cpmp; /* Pointer to comm processor space */ | 52 | cpm8xx_t __iomem *cpmp; /* Pointer to comm processor space */ |
| @@ -290,20 +295,24 @@ struct cpm_ioport16 { | |||
| 290 | __be16 res[3]; | 295 | __be16 res[3]; |
| 291 | }; | 296 | }; |
| 292 | 297 | ||
| 293 | struct cpm_ioport32 { | 298 | struct cpm_ioport32b { |
| 294 | __be32 dir, par, sor; | 299 | __be32 dir, par, odr, dat; |
| 300 | }; | ||
| 301 | |||
| 302 | struct cpm_ioport32e { | ||
| 303 | __be32 dir, par, sor, odr, dat; | ||
| 295 | }; | 304 | }; |
| 296 | 305 | ||
| 297 | static void cpm1_set_pin32(int port, int pin, int flags) | 306 | static void cpm1_set_pin32(int port, int pin, int flags) |
| 298 | { | 307 | { |
| 299 | struct cpm_ioport32 __iomem *iop; | 308 | struct cpm_ioport32e __iomem *iop; |
| 300 | pin = 1 << (31 - pin); | 309 | pin = 1 << (31 - pin); |
| 301 | 310 | ||
| 302 | if (port == CPM_PORTB) | 311 | if (port == CPM_PORTB) |
| 303 | iop = (struct cpm_ioport32 __iomem *) | 312 | iop = (struct cpm_ioport32e __iomem *) |
| 304 | &mpc8xx_immr->im_cpm.cp_pbdir; | 313 | &mpc8xx_immr->im_cpm.cp_pbdir; |
| 305 | else | 314 | else |
| 306 | iop = (struct cpm_ioport32 __iomem *) | 315 | iop = (struct cpm_ioport32e __iomem *) |
| 307 | &mpc8xx_immr->im_cpm.cp_pedir; | 316 | &mpc8xx_immr->im_cpm.cp_pedir; |
| 308 | 317 | ||
| 309 | if (flags & CPM_PIN_OUTPUT) | 318 | if (flags & CPM_PIN_OUTPUT) |
| @@ -498,3 +507,251 @@ int cpm1_clk_setup(enum cpm_clk_target target, int clock, int mode) | |||
| 498 | 507 | ||
| 499 | return 0; | 508 | return 0; |
| 500 | } | 509 | } |
| 510 | |||
| 511 | /* | ||
| 512 | * GPIO LIB API implementation | ||
| 513 | */ | ||
| 514 | #ifdef CONFIG_8xx_GPIO | ||
| 515 | |||
| 516 | struct cpm1_gpio16_chip { | ||
| 517 | struct of_mm_gpio_chip mm_gc; | ||
| 518 | spinlock_t lock; | ||
| 519 | |||
| 520 | /* shadowed data register to clear/set bits safely */ | ||
| 521 | u16 cpdata; | ||
| 522 | }; | ||
| 523 | |||
| 524 | static inline struct cpm1_gpio16_chip * | ||
| 525 | to_cpm1_gpio16_chip(struct of_mm_gpio_chip *mm_gc) | ||
| 526 | { | ||
| 527 | return container_of(mm_gc, struct cpm1_gpio16_chip, mm_gc); | ||
| 528 | } | ||
| 529 | |||
| 530 | static void cpm1_gpio16_save_regs(struct of_mm_gpio_chip *mm_gc) | ||
| 531 | { | ||
| 532 | struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc); | ||
| 533 | struct cpm_ioport16 __iomem *iop = mm_gc->regs; | ||
| 534 | |||
| 535 | cpm1_gc->cpdata = in_be16(&iop->dat); | ||
| 536 | } | ||
| 537 | |||
| 538 | static int cpm1_gpio16_get(struct gpio_chip *gc, unsigned int gpio) | ||
| 539 | { | ||
| 540 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | ||
| 541 | struct cpm_ioport16 __iomem *iop = mm_gc->regs; | ||
| 542 | u16 pin_mask; | ||
| 543 | |||
| 544 | pin_mask = 1 << (15 - gpio); | ||
| 545 | |||
| 546 | return !!(in_be16(&iop->dat) & pin_mask); | ||
| 547 | } | ||
| 548 | |||
| 549 | static void cpm1_gpio16_set(struct gpio_chip *gc, unsigned int gpio, int value) | ||
| 550 | { | ||
| 551 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | ||
| 552 | struct cpm1_gpio16_chip *cpm1_gc = to_cpm1_gpio16_chip(mm_gc); | ||
| 553 | struct cpm_ioport16 __iomem *iop = mm_gc->regs; | ||
| 554 | unsigned long flags; | ||
| 555 | u16 pin_mask = 1 << (15 - gpio); | ||
| 556 | |||
| 557 | spin_lock_irqsave(&cpm1_gc->lock, flags); | ||
| 558 | |||
| 559 | if (value) | ||
| 560 | cpm1_gc->cpdata |= pin_mask; | ||
| 561 | else | ||
| 562 | cpm1_gc->cpdata &= ~pin_mask; | ||
| 563 | |||
| 564 | out_be16(&iop->dat, cpm1_gc->cpdata); | ||
| 565 | |||
| 566 | spin_unlock_irqrestore(&cpm1_gc->lock, flags); | ||
| 567 | } | ||
| 568 | |||
| 569 | static int cpm1_gpio16_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) | ||
| 570 | { | ||
| 571 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | ||
| 572 | struct cpm_ioport16 __iomem *iop = mm_gc->regs; | ||
| 573 | u16 pin_mask; | ||
| 574 | |||
| 575 | pin_mask = 1 << (15 - gpio); | ||
| 576 | |||
| 577 | setbits16(&iop->dir, pin_mask); | ||
| 578 | |||
| 579 | cpm1_gpio16_set(gc, gpio, val); | ||
| 580 | |||
| 581 | return 0; | ||
| 582 | } | ||
| 583 | |||
| 584 | static int cpm1_gpio16_dir_in(struct gpio_chip *gc, unsigned int gpio) | ||
| 585 | { | ||
| 586 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | ||
| 587 | struct cpm_ioport16 __iomem *iop = mm_gc->regs; | ||
| 588 | u16 pin_mask; | ||
| 589 | |||
| 590 | pin_mask = 1 << (15 - gpio); | ||
| 591 | |||
| 592 | clrbits16(&iop->dir, pin_mask); | ||
| 593 | |||
| 594 | return 0; | ||
| 595 | } | ||
| 596 | |||
| 597 | int cpm1_gpiochip_add16(struct device_node *np) | ||
| 598 | { | ||
| 599 | struct cpm1_gpio16_chip *cpm1_gc; | ||
| 600 | struct of_mm_gpio_chip *mm_gc; | ||
| 601 | struct of_gpio_chip *of_gc; | ||
| 602 | struct gpio_chip *gc; | ||
| 603 | |||
| 604 | cpm1_gc = kzalloc(sizeof(*cpm1_gc), GFP_KERNEL); | ||
| 605 | if (!cpm1_gc) | ||
| 606 | return -ENOMEM; | ||
| 607 | |||
| 608 | spin_lock_init(&cpm1_gc->lock); | ||
| 609 | |||
| 610 | mm_gc = &cpm1_gc->mm_gc; | ||
| 611 | of_gc = &mm_gc->of_gc; | ||
| 612 | gc = &of_gc->gc; | ||
| 613 | |||
| 614 | mm_gc->save_regs = cpm1_gpio16_save_regs; | ||
| 615 | of_gc->gpio_cells = 2; | ||
| 616 | gc->ngpio = 16; | ||
| 617 | gc->direction_input = cpm1_gpio16_dir_in; | ||
| 618 | gc->direction_output = cpm1_gpio16_dir_out; | ||
| 619 | gc->get = cpm1_gpio16_get; | ||
| 620 | gc->set = cpm1_gpio16_set; | ||
| 621 | |||
| 622 | return of_mm_gpiochip_add(np, mm_gc); | ||
| 623 | } | ||
| 624 | |||
| 625 | struct cpm1_gpio32_chip { | ||
| 626 | struct of_mm_gpio_chip mm_gc; | ||
| 627 | spinlock_t lock; | ||
| 628 | |||
| 629 | /* shadowed data register to clear/set bits safely */ | ||
| 630 | u32 cpdata; | ||
| 631 | }; | ||
| 632 | |||
| 633 | static inline struct cpm1_gpio32_chip * | ||
| 634 | to_cpm1_gpio32_chip(struct of_mm_gpio_chip *mm_gc) | ||
| 635 | { | ||
| 636 | return container_of(mm_gc, struct cpm1_gpio32_chip, mm_gc); | ||
| 637 | } | ||
| 638 | |||
| 639 | static void cpm1_gpio32_save_regs(struct of_mm_gpio_chip *mm_gc) | ||
| 640 | { | ||
| 641 | struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc); | ||
| 642 | struct cpm_ioport32b __iomem *iop = mm_gc->regs; | ||
| 643 | |||
| 644 | cpm1_gc->cpdata = in_be32(&iop->dat); | ||
| 645 | } | ||
| 646 | |||
| 647 | static int cpm1_gpio32_get(struct gpio_chip *gc, unsigned int gpio) | ||
| 648 | { | ||
| 649 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | ||
| 650 | struct cpm_ioport32b __iomem *iop = mm_gc->regs; | ||
| 651 | u32 pin_mask; | ||
| 652 | |||
| 653 | pin_mask = 1 << (31 - gpio); | ||
| 654 | |||
| 655 | return !!(in_be32(&iop->dat) & pin_mask); | ||
| 656 | } | ||
| 657 | |||
| 658 | static void cpm1_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value) | ||
| 659 | { | ||
| 660 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | ||
| 661 | struct cpm1_gpio32_chip *cpm1_gc = to_cpm1_gpio32_chip(mm_gc); | ||
| 662 | struct cpm_ioport32b __iomem *iop = mm_gc->regs; | ||
| 663 | unsigned long flags; | ||
| 664 | u32 pin_mask = 1 << (31 - gpio); | ||
| 665 | |||
| 666 | spin_lock_irqsave(&cpm1_gc->lock, flags); | ||
| 667 | |||
| 668 | if (value) | ||
| 669 | cpm1_gc->cpdata |= pin_mask; | ||
| 670 | else | ||
| 671 | cpm1_gc->cpdata &= ~pin_mask; | ||
| 672 | |||
| 673 | out_be32(&iop->dat, cpm1_gc->cpdata); | ||
| 674 | |||
| 675 | spin_unlock_irqrestore(&cpm1_gc->lock, flags); | ||
| 676 | } | ||
| 677 | |||
| 678 | static int cpm1_gpio32_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) | ||
| 679 | { | ||
| 680 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | ||
| 681 | struct cpm_ioport32b __iomem *iop = mm_gc->regs; | ||
| 682 | u32 pin_mask; | ||
| 683 | |||
| 684 | pin_mask = 1 << (31 - gpio); | ||
| 685 | |||
| 686 | setbits32(&iop->dir, pin_mask); | ||
| 687 | |||
| 688 | cpm1_gpio32_set(gc, gpio, val); | ||
| 689 | |||
| 690 | return 0; | ||
| 691 | } | ||
| 692 | |||
| 693 | static int cpm1_gpio32_dir_in(struct gpio_chip *gc, unsigned int gpio) | ||
| 694 | { | ||
| 695 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | ||
| 696 | struct cpm_ioport32b __iomem *iop = mm_gc->regs; | ||
| 697 | u32 pin_mask; | ||
| 698 | |||
| 699 | pin_mask = 1 << (31 - gpio); | ||
| 700 | |||
| 701 | clrbits32(&iop->dir, pin_mask); | ||
| 702 | |||
| 703 | return 0; | ||
| 704 | } | ||
| 705 | |||
| 706 | int cpm1_gpiochip_add32(struct device_node *np) | ||
| 707 | { | ||
| 708 | struct cpm1_gpio32_chip *cpm1_gc; | ||
| 709 | struct of_mm_gpio_chip *mm_gc; | ||
| 710 | struct of_gpio_chip *of_gc; | ||
| 711 | struct gpio_chip *gc; | ||
| 712 | |||
| 713 | cpm1_gc = kzalloc(sizeof(*cpm1_gc), GFP_KERNEL); | ||
| 714 | if (!cpm1_gc) | ||
| 715 | return -ENOMEM; | ||
| 716 | |||
| 717 | spin_lock_init(&cpm1_gc->lock); | ||
| 718 | |||
| 719 | mm_gc = &cpm1_gc->mm_gc; | ||
| 720 | of_gc = &mm_gc->of_gc; | ||
| 721 | gc = &of_gc->gc; | ||
| 722 | |||
| 723 | mm_gc->save_regs = cpm1_gpio32_save_regs; | ||
| 724 | of_gc->gpio_cells = 2; | ||
| 725 | gc->ngpio = 32; | ||
| 726 | gc->direction_input = cpm1_gpio32_dir_in; | ||
| 727 | gc->direction_output = cpm1_gpio32_dir_out; | ||
| 728 | gc->get = cpm1_gpio32_get; | ||
| 729 | gc->set = cpm1_gpio32_set; | ||
| 730 | |||
| 731 | return of_mm_gpiochip_add(np, mm_gc); | ||
| 732 | } | ||
| 733 | |||
| 734 | static int cpm_init_par_io(void) | ||
| 735 | { | ||
| 736 | struct device_node *np; | ||
| 737 | |||
| 738 | for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-a") | ||
| 739 | cpm1_gpiochip_add16(np); | ||
| 740 | |||
| 741 | for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-b") | ||
| 742 | cpm1_gpiochip_add32(np); | ||
| 743 | |||
| 744 | for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-c") | ||
| 745 | cpm1_gpiochip_add16(np); | ||
| 746 | |||
| 747 | for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-d") | ||
| 748 | cpm1_gpiochip_add16(np); | ||
| 749 | |||
| 750 | /* Port E uses CPM2 layout */ | ||
| 751 | for_each_compatible_node(np, NULL, "fsl,cpm1-pario-bank-e") | ||
| 752 | cpm2_gpiochip_add32(np); | ||
| 753 | return 0; | ||
| 754 | } | ||
| 755 | arch_initcall(cpm_init_par_io); | ||
| 756 | |||
| 757 | #endif /* CONFIG_8xx_GPIO */ | ||
diff --git a/arch/powerpc/sysdev/cpm2.c b/arch/powerpc/sysdev/cpm2.c index 5a6c5dfc53ef..f1c3395633b9 100644 --- a/arch/powerpc/sysdev/cpm2.c +++ b/arch/powerpc/sysdev/cpm2.c | |||
| @@ -115,16 +115,10 @@ EXPORT_SYMBOL(cpm_command); | |||
| 115 | * Baud rate clocks are zero-based in the driver code (as that maps | 115 | * Baud rate clocks are zero-based in the driver code (as that maps |
| 116 | * to port numbers). Documentation uses 1-based numbering. | 116 | * to port numbers). Documentation uses 1-based numbering. |
| 117 | */ | 117 | */ |
| 118 | #define BRG_INT_CLK (get_brgfreq()) | 118 | void __cpm2_setbrg(uint brg, uint rate, uint clk, int div16, int src) |
| 119 | #define BRG_UART_CLK (BRG_INT_CLK/16) | ||
| 120 | |||
| 121 | /* This function is used by UARTS, or anything else that uses a 16x | ||
| 122 | * oversampled clock. | ||
| 123 | */ | ||
| 124 | void | ||
| 125 | cpm_setbrg(uint brg, uint rate) | ||
| 126 | { | 119 | { |
| 127 | u32 __iomem *bp; | 120 | u32 __iomem *bp; |
| 121 | u32 val; | ||
| 128 | 122 | ||
| 129 | /* This is good enough to get SMCs running..... | 123 | /* This is good enough to get SMCs running..... |
| 130 | */ | 124 | */ |
| @@ -135,34 +129,14 @@ cpm_setbrg(uint brg, uint rate) | |||
| 135 | brg -= 4; | 129 | brg -= 4; |
| 136 | } | 130 | } |
| 137 | bp += brg; | 131 | bp += brg; |
| 138 | out_be32(bp, (((BRG_UART_CLK / rate) - 1) << 1) | CPM_BRG_EN); | 132 | val = (((clk / rate) - 1) << 1) | CPM_BRG_EN | src; |
| 139 | |||
| 140 | cpm2_unmap(bp); | ||
| 141 | } | ||
| 142 | |||
| 143 | /* This function is used to set high speed synchronous baud rate | ||
| 144 | * clocks. | ||
| 145 | */ | ||
| 146 | void | ||
| 147 | cpm2_fastbrg(uint brg, uint rate, int div16) | ||
| 148 | { | ||
| 149 | u32 __iomem *bp; | ||
| 150 | u32 val; | ||
| 151 | |||
| 152 | if (brg < 4) { | ||
| 153 | bp = cpm2_map_size(im_brgc1, 16); | ||
| 154 | } else { | ||
| 155 | bp = cpm2_map_size(im_brgc5, 16); | ||
| 156 | brg -= 4; | ||
| 157 | } | ||
| 158 | bp += brg; | ||
| 159 | val = ((BRG_INT_CLK / rate) << 1) | CPM_BRG_EN; | ||
| 160 | if (div16) | 133 | if (div16) |
| 161 | val |= CPM_BRG_DIV16; | 134 | val |= CPM_BRG_DIV16; |
| 162 | 135 | ||
| 163 | out_be32(bp, val); | 136 | out_be32(bp, val); |
| 164 | cpm2_unmap(bp); | 137 | cpm2_unmap(bp); |
| 165 | } | 138 | } |
| 139 | EXPORT_SYMBOL(__cpm2_setbrg); | ||
| 166 | 140 | ||
| 167 | int cpm2_clk_setup(enum cpm_clk_target target, int clock, int mode) | 141 | int cpm2_clk_setup(enum cpm_clk_target target, int clock, int mode) |
| 168 | { | 142 | { |
| @@ -377,3 +351,14 @@ void cpm2_set_pin(int port, int pin, int flags) | |||
| 377 | else | 351 | else |
| 378 | clrbits32(&iop[port].odr, pin); | 352 | clrbits32(&iop[port].odr, pin); |
| 379 | } | 353 | } |
| 354 | |||
| 355 | static int cpm_init_par_io(void) | ||
| 356 | { | ||
| 357 | struct device_node *np; | ||
| 358 | |||
| 359 | for_each_compatible_node(np, NULL, "fsl,cpm2-pario-bank") | ||
| 360 | cpm2_gpiochip_add32(np); | ||
| 361 | return 0; | ||
| 362 | } | ||
| 363 | arch_initcall(cpm_init_par_io); | ||
| 364 | |||
diff --git a/arch/powerpc/sysdev/cpm_common.c b/arch/powerpc/sysdev/cpm_common.c index e4b7296acb2c..53da8a079f96 100644 --- a/arch/powerpc/sysdev/cpm_common.c +++ b/arch/powerpc/sysdev/cpm_common.c | |||
| @@ -19,6 +19,8 @@ | |||
| 19 | 19 | ||
| 20 | #include <linux/init.h> | 20 | #include <linux/init.h> |
| 21 | #include <linux/of_device.h> | 21 | #include <linux/of_device.h> |
| 22 | #include <linux/spinlock.h> | ||
| 23 | #include <linux/of.h> | ||
| 22 | 24 | ||
| 23 | #include <asm/udbg.h> | 25 | #include <asm/udbg.h> |
| 24 | #include <asm/io.h> | 26 | #include <asm/io.h> |
| @@ -28,6 +30,10 @@ | |||
| 28 | 30 | ||
| 29 | #include <mm/mmu_decl.h> | 31 | #include <mm/mmu_decl.h> |
| 30 | 32 | ||
| 33 | #if defined(CONFIG_CPM2) || defined(CONFIG_8xx_GPIO) | ||
| 34 | #include <linux/of_gpio.h> | ||
| 35 | #endif | ||
| 36 | |||
| 31 | #ifdef CONFIG_PPC_EARLY_DEBUG_CPM | 37 | #ifdef CONFIG_PPC_EARLY_DEBUG_CPM |
| 32 | static u32 __iomem *cpm_udbg_txdesc = | 38 | static u32 __iomem *cpm_udbg_txdesc = |
| 33 | (u32 __iomem __force *)CONFIG_PPC_EARLY_DEBUG_CPM_ADDR; | 39 | (u32 __iomem __force *)CONFIG_PPC_EARLY_DEBUG_CPM_ADDR; |
| @@ -207,3 +213,120 @@ dma_addr_t cpm_muram_dma(void __iomem *addr) | |||
| 207 | return muram_pbase + ((u8 __iomem *)addr - muram_vbase); | 213 | return muram_pbase + ((u8 __iomem *)addr - muram_vbase); |
| 208 | } | 214 | } |
| 209 | EXPORT_SYMBOL(cpm_muram_dma); | 215 | EXPORT_SYMBOL(cpm_muram_dma); |
| 216 | |||
| 217 | #if defined(CONFIG_CPM2) || defined(CONFIG_8xx_GPIO) | ||
| 218 | |||
| 219 | struct cpm2_ioports { | ||
| 220 | u32 dir, par, sor, odr, dat; | ||
| 221 | u32 res[3]; | ||
| 222 | }; | ||
| 223 | |||
| 224 | struct cpm2_gpio32_chip { | ||
| 225 | struct of_mm_gpio_chip mm_gc; | ||
| 226 | spinlock_t lock; | ||
| 227 | |||
| 228 | /* shadowed data register to clear/set bits safely */ | ||
| 229 | u32 cpdata; | ||
| 230 | }; | ||
| 231 | |||
| 232 | static inline struct cpm2_gpio32_chip * | ||
| 233 | to_cpm2_gpio32_chip(struct of_mm_gpio_chip *mm_gc) | ||
| 234 | { | ||
| 235 | return container_of(mm_gc, struct cpm2_gpio32_chip, mm_gc); | ||
| 236 | } | ||
| 237 | |||
| 238 | static void cpm2_gpio32_save_regs(struct of_mm_gpio_chip *mm_gc) | ||
| 239 | { | ||
| 240 | struct cpm2_gpio32_chip *cpm2_gc = to_cpm2_gpio32_chip(mm_gc); | ||
| 241 | struct cpm2_ioports __iomem *iop = mm_gc->regs; | ||
| 242 | |||
| 243 | cpm2_gc->cpdata = in_be32(&iop->dat); | ||
| 244 | } | ||
| 245 | |||
| 246 | static int cpm2_gpio32_get(struct gpio_chip *gc, unsigned int gpio) | ||
| 247 | { | ||
| 248 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | ||
| 249 | struct cpm2_ioports __iomem *iop = mm_gc->regs; | ||
| 250 | u32 pin_mask; | ||
| 251 | |||
| 252 | pin_mask = 1 << (31 - gpio); | ||
| 253 | |||
| 254 | return !!(in_be32(&iop->dat) & pin_mask); | ||
| 255 | } | ||
| 256 | |||
| 257 | static void cpm2_gpio32_set(struct gpio_chip *gc, unsigned int gpio, int value) | ||
| 258 | { | ||
| 259 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | ||
| 260 | struct cpm2_gpio32_chip *cpm2_gc = to_cpm2_gpio32_chip(mm_gc); | ||
| 261 | struct cpm2_ioports __iomem *iop = mm_gc->regs; | ||
| 262 | unsigned long flags; | ||
| 263 | u32 pin_mask = 1 << (31 - gpio); | ||
| 264 | |||
| 265 | spin_lock_irqsave(&cpm2_gc->lock, flags); | ||
| 266 | |||
| 267 | if (value) | ||
| 268 | cpm2_gc->cpdata |= pin_mask; | ||
| 269 | else | ||
| 270 | cpm2_gc->cpdata &= ~pin_mask; | ||
| 271 | |||
| 272 | out_be32(&iop->dat, cpm2_gc->cpdata); | ||
| 273 | |||
| 274 | spin_unlock_irqrestore(&cpm2_gc->lock, flags); | ||
| 275 | } | ||
| 276 | |||
| 277 | static int cpm2_gpio32_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) | ||
| 278 | { | ||
| 279 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | ||
| 280 | struct cpm2_ioports __iomem *iop = mm_gc->regs; | ||
| 281 | u32 pin_mask; | ||
| 282 | |||
| 283 | pin_mask = 1 << (31 - gpio); | ||
| 284 | |||
| 285 | setbits32(&iop->dir, pin_mask); | ||
| 286 | |||
| 287 | cpm2_gpio32_set(gc, gpio, val); | ||
| 288 | |||
| 289 | return 0; | ||
| 290 | } | ||
| 291 | |||
| 292 | static int cpm2_gpio32_dir_in(struct gpio_chip *gc, unsigned int gpio) | ||
| 293 | { | ||
| 294 | struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc); | ||
| 295 | struct cpm2_ioports __iomem *iop = mm_gc->regs; | ||
| 296 | u32 pin_mask; | ||
| 297 | |||
| 298 | pin_mask = 1 << (31 - gpio); | ||
| 299 | |||
| 300 | clrbits32(&iop->dir, pin_mask); | ||
| 301 | |||
| 302 | return 0; | ||
| 303 | } | ||
| 304 | |||
| 305 | int cpm2_gpiochip_add32(struct device_node *np) | ||
| 306 | { | ||
| 307 | struct cpm2_gpio32_chip *cpm2_gc; | ||
| 308 | struct of_mm_gpio_chip *mm_gc; | ||
| 309 | struct of_gpio_chip *of_gc; | ||
| 310 | struct gpio_chip *gc; | ||
| 311 | |||
| 312 | cpm2_gc = kzalloc(sizeof(*cpm2_gc), GFP_KERNEL); | ||
| 313 | if (!cpm2_gc) | ||
| 314 | return -ENOMEM; | ||
| 315 | |||
| 316 | spin_lock_init(&cpm2_gc->lock); | ||
| 317 | |||
| 318 | mm_gc = &cpm2_gc->mm_gc; | ||
| 319 | of_gc = &mm_gc->of_gc; | ||
| 320 | gc = &of_gc->gc; | ||
| 321 | |||
| 322 | mm_gc->save_regs = cpm2_gpio32_save_regs; | ||
| 323 | of_gc->gpio_cells = 2; | ||
| 324 | gc->ngpio = 32; | ||
| 325 | gc->direction_input = cpm2_gpio32_dir_in; | ||
| 326 | gc->direction_output = cpm2_gpio32_dir_out; | ||
| 327 | gc->get = cpm2_gpio32_get; | ||
| 328 | gc->set = cpm2_gpio32_set; | ||
| 329 | |||
| 330 | return of_mm_gpiochip_add(np, mm_gc); | ||
| 331 | } | ||
| 332 | #endif /* CONFIG_CPM2 || CONFIG_8xx_GPIO */ | ||
diff --git a/arch/powerpc/sysdev/rtc_cmos_setup.c b/arch/powerpc/sysdev/rtc_cmos_setup.c index c09ddc0dbeb3..c1879ebfd4f4 100644 --- a/arch/powerpc/sysdev/rtc_cmos_setup.c +++ b/arch/powerpc/sysdev/rtc_cmos_setup.c | |||
| @@ -21,6 +21,7 @@ static int __init add_rtc(void) | |||
| 21 | struct device_node *np; | 21 | struct device_node *np; |
| 22 | struct platform_device *pd; | 22 | struct platform_device *pd; |
| 23 | struct resource res[2]; | 23 | struct resource res[2]; |
| 24 | unsigned int num_res = 1; | ||
| 24 | int ret; | 25 | int ret; |
| 25 | 26 | ||
| 26 | memset(&res, 0, sizeof(res)); | 27 | memset(&res, 0, sizeof(res)); |
| @@ -41,14 +42,24 @@ static int __init add_rtc(void) | |||
| 41 | if (res[0].start != RTC_PORT(0)) | 42 | if (res[0].start != RTC_PORT(0)) |
| 42 | return -EINVAL; | 43 | return -EINVAL; |
| 43 | 44 | ||
| 44 | /* Use a fixed interrupt value of 8 since on PPC if we are using this | 45 | np = of_find_compatible_node(NULL, NULL, "chrp,iic"); |
| 45 | * its off an i8259 which we ensure has interrupt numbers 0..15. */ | 46 | if (!np) |
| 46 | res[1].start = 8; | 47 | np = of_find_compatible_node(NULL, NULL, "pnpPNP,000"); |
| 47 | res[1].end = 8; | 48 | if (np) { |
| 48 | res[1].flags = IORESOURCE_IRQ; | 49 | of_node_put(np); |
| 50 | /* | ||
| 51 | * Use a fixed interrupt value of 8 since on PPC if we are | ||
| 52 | * using this its off an i8259 which we ensure has interrupt | ||
| 53 | * numbers 0..15. | ||
| 54 | */ | ||
| 55 | res[1].start = 8; | ||
| 56 | res[1].end = 8; | ||
| 57 | res[1].flags = IORESOURCE_IRQ; | ||
| 58 | num_res++; | ||
| 59 | } | ||
| 49 | 60 | ||
| 50 | pd = platform_device_register_simple("rtc_cmos", -1, | 61 | pd = platform_device_register_simple("rtc_cmos", -1, |
| 51 | &res[0], 2); | 62 | &res[0], num_res); |
| 52 | 63 | ||
| 53 | if (IS_ERR(pd)) | 64 | if (IS_ERR(pd)) |
| 54 | return PTR_ERR(pd); | 65 | return PTR_ERR(pd); |
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 192688344ed2..f52931e1c16e 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c | |||
| @@ -66,8 +66,8 @@ | |||
| 66 | #include <linux/ctype.h> | 66 | #include <linux/ctype.h> |
| 67 | 67 | ||
| 68 | #ifdef CONFIG_PPC_OF | 68 | #ifdef CONFIG_PPC_OF |
| 69 | #include <asm/of_device.h> | 69 | #include <linux/of_device.h> |
| 70 | #include <asm/of_platform.h> | 70 | #include <linux/of_platform.h> |
| 71 | #endif | 71 | #endif |
| 72 | 72 | ||
| 73 | #define PFX "ipmi_si: " | 73 | #define PFX "ipmi_si: " |
diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c index c521bf6e1bf2..fa2be26272d5 100644 --- a/drivers/ide/ppc/pmac.c +++ b/drivers/ide/ppc/pmac.c | |||
| @@ -1086,6 +1086,11 @@ static int __devinit pmac_ide_setup_device(pmac_ide_hwif_t *pmif, hw_regs_t *hw) | |||
| 1086 | /* Make sure we have sane timings */ | 1086 | /* Make sure we have sane timings */ |
| 1087 | sanitize_timings(pmif); | 1087 | sanitize_timings(pmif); |
| 1088 | 1088 | ||
| 1089 | host = ide_host_alloc(&d, hws); | ||
| 1090 | if (host == NULL) | ||
| 1091 | return -ENOMEM; | ||
| 1092 | hwif = host->ports[0]; | ||
| 1093 | |||
| 1089 | #ifndef CONFIG_PPC64 | 1094 | #ifndef CONFIG_PPC64 |
| 1090 | /* XXX FIXME: Media bay stuff need re-organizing */ | 1095 | /* XXX FIXME: Media bay stuff need re-organizing */ |
| 1091 | if (np->parent && np->parent->name | 1096 | if (np->parent && np->parent->name |
| @@ -1119,11 +1124,11 @@ static int __devinit pmac_ide_setup_device(pmac_ide_hwif_t *pmif, hw_regs_t *hw) | |||
| 1119 | pmif->mdev ? "macio" : "PCI", pmif->aapl_bus_id, | 1124 | pmif->mdev ? "macio" : "PCI", pmif->aapl_bus_id, |
| 1120 | pmif->mediabay ? " (mediabay)" : "", hw->irq); | 1125 | pmif->mediabay ? " (mediabay)" : "", hw->irq); |
| 1121 | 1126 | ||
| 1122 | rc = ide_host_add(&d, hws, &host); | 1127 | rc = ide_host_register(host, &d, hws); |
| 1123 | if (rc) | 1128 | if (rc) { |
| 1129 | ide_host_free(host); | ||
| 1124 | return rc; | 1130 | return rc; |
| 1125 | 1131 | } | |
| 1126 | hwif = host->ports[0]; | ||
| 1127 | 1132 | ||
| 1128 | return 0; | 1133 | return 0; |
| 1129 | } | 1134 | } |
diff --git a/drivers/serial/cpm_uart/cpm_uart.h b/drivers/serial/cpm_uart/cpm_uart.h index 5c76e0ae0582..7274b527a3c1 100644 --- a/drivers/serial/cpm_uart/cpm_uart.h +++ b/drivers/serial/cpm_uart/cpm_uart.h | |||
| @@ -50,6 +50,15 @@ | |||
| 50 | 50 | ||
| 51 | #define SCC_WAIT_CLOSING 100 | 51 | #define SCC_WAIT_CLOSING 100 |
| 52 | 52 | ||
| 53 | #define GPIO_CTS 0 | ||
| 54 | #define GPIO_RTS 1 | ||
| 55 | #define GPIO_DCD 2 | ||
| 56 | #define GPIO_DSR 3 | ||
| 57 | #define GPIO_DTR 4 | ||
| 58 | #define GPIO_RI 5 | ||
| 59 | |||
| 60 | #define NUM_GPIOS (GPIO_RI+1) | ||
| 61 | |||
| 53 | struct uart_cpm_port { | 62 | struct uart_cpm_port { |
| 54 | struct uart_port port; | 63 | struct uart_port port; |
| 55 | u16 rx_nrfifos; | 64 | u16 rx_nrfifos; |
| @@ -68,6 +77,7 @@ struct uart_cpm_port { | |||
| 68 | unsigned char *rx_buf; | 77 | unsigned char *rx_buf; |
| 69 | u32 flags; | 78 | u32 flags; |
| 70 | void (*set_lineif)(struct uart_cpm_port *); | 79 | void (*set_lineif)(struct uart_cpm_port *); |
| 80 | struct clk *clk; | ||
| 71 | u8 brg; | 81 | u8 brg; |
| 72 | uint dp_addr; | 82 | uint dp_addr; |
| 73 | void *mem_addr; | 83 | void *mem_addr; |
| @@ -82,6 +92,7 @@ struct uart_cpm_port { | |||
| 82 | int wait_closing; | 92 | int wait_closing; |
| 83 | /* value to combine with opcode to form cpm command */ | 93 | /* value to combine with opcode to form cpm command */ |
| 84 | u32 command; | 94 | u32 command; |
| 95 | int gpios[NUM_GPIOS]; | ||
| 85 | }; | 96 | }; |
| 86 | 97 | ||
| 87 | extern int cpm_uart_nr; | 98 | extern int cpm_uart_nr; |
diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c index a4f86927a74b..25efca5a7a1f 100644 --- a/drivers/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/serial/cpm_uart/cpm_uart_core.c | |||
| @@ -43,6 +43,9 @@ | |||
| 43 | #include <linux/dma-mapping.h> | 43 | #include <linux/dma-mapping.h> |
| 44 | #include <linux/fs_uart_pd.h> | 44 | #include <linux/fs_uart_pd.h> |
| 45 | #include <linux/of_platform.h> | 45 | #include <linux/of_platform.h> |
| 46 | #include <linux/gpio.h> | ||
| 47 | #include <linux/of_gpio.h> | ||
| 48 | #include <linux/clk.h> | ||
| 46 | 49 | ||
| 47 | #include <asm/io.h> | 50 | #include <asm/io.h> |
| 48 | #include <asm/irq.h> | 51 | #include <asm/irq.h> |
| @@ -96,13 +99,41 @@ static unsigned int cpm_uart_tx_empty(struct uart_port *port) | |||
| 96 | 99 | ||
| 97 | static void cpm_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) | 100 | static void cpm_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) |
| 98 | { | 101 | { |
| 99 | /* Whee. Do nothing. */ | 102 | struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; |
| 103 | |||
| 104 | if (pinfo->gpios[GPIO_RTS] >= 0) | ||
| 105 | gpio_set_value(pinfo->gpios[GPIO_RTS], !(mctrl & TIOCM_RTS)); | ||
| 106 | |||
| 107 | if (pinfo->gpios[GPIO_DTR] >= 0) | ||
| 108 | gpio_set_value(pinfo->gpios[GPIO_DTR], !(mctrl & TIOCM_DTR)); | ||
| 100 | } | 109 | } |
| 101 | 110 | ||
| 102 | static unsigned int cpm_uart_get_mctrl(struct uart_port *port) | 111 | static unsigned int cpm_uart_get_mctrl(struct uart_port *port) |
| 103 | { | 112 | { |
| 104 | /* Whee. Do nothing. */ | 113 | struct uart_cpm_port *pinfo = (struct uart_cpm_port *)port; |
| 105 | return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; | 114 | unsigned int mctrl = TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; |
| 115 | |||
| 116 | if (pinfo->gpios[GPIO_CTS] >= 0) { | ||
| 117 | if (gpio_get_value(pinfo->gpios[GPIO_CTS])) | ||
| 118 | mctrl &= ~TIOCM_CTS; | ||
| 119 | } | ||
| 120 | |||
| 121 | if (pinfo->gpios[GPIO_DSR] >= 0) { | ||
| 122 | if (gpio_get_value(pinfo->gpios[GPIO_DSR])) | ||
| 123 | mctrl &= ~TIOCM_DSR; | ||
| 124 | } | ||
| 125 | |||
| 126 | if (pinfo->gpios[GPIO_DCD] >= 0) { | ||
| 127 | if (gpio_get_value(pinfo->gpios[GPIO_DCD])) | ||
| 128 | mctrl &= ~TIOCM_CAR; | ||
| 129 | } | ||
| 130 | |||
| 131 | if (pinfo->gpios[GPIO_RI] >= 0) { | ||
| 132 | if (!gpio_get_value(pinfo->gpios[GPIO_RI])) | ||
| 133 | mctrl |= TIOCM_RNG; | ||
| 134 | } | ||
| 135 | |||
| 136 | return mctrl; | ||
| 106 | } | 137 | } |
| 107 | 138 | ||
| 108 | /* | 139 | /* |
| @@ -566,7 +597,10 @@ static void cpm_uart_set_termios(struct uart_port *port, | |||
| 566 | out_be16(&sccp->scc_psmr, (sbits << 12) | scval); | 597 | out_be16(&sccp->scc_psmr, (sbits << 12) | scval); |
| 567 | } | 598 | } |
| 568 | 599 | ||
| 569 | cpm_set_brg(pinfo->brg - 1, baud); | 600 | if (pinfo->clk) |
| 601 | clk_set_rate(pinfo->clk, baud); | ||
| 602 | else | ||
| 603 | cpm_set_brg(pinfo->brg - 1, baud); | ||
| 570 | spin_unlock_irqrestore(&port->lock, flags); | 604 | spin_unlock_irqrestore(&port->lock, flags); |
| 571 | } | 605 | } |
| 572 | 606 | ||
| @@ -991,14 +1025,23 @@ static int cpm_uart_init_port(struct device_node *np, | |||
| 991 | void __iomem *mem, *pram; | 1025 | void __iomem *mem, *pram; |
| 992 | int len; | 1026 | int len; |
| 993 | int ret; | 1027 | int ret; |
| 1028 | int i; | ||
| 994 | 1029 | ||
| 995 | data = of_get_property(np, "fsl,cpm-brg", &len); | 1030 | data = of_get_property(np, "clock", NULL); |
| 996 | if (!data || len != 4) { | 1031 | if (data) { |
| 997 | printk(KERN_ERR "CPM UART %s has no/invalid " | 1032 | struct clk *clk = clk_get(NULL, (const char*)data); |
| 998 | "fsl,cpm-brg property.\n", np->name); | 1033 | if (!IS_ERR(clk)) |
| 999 | return -EINVAL; | 1034 | pinfo->clk = clk; |
| 1035 | } | ||
| 1036 | if (!pinfo->clk) { | ||
| 1037 | data = of_get_property(np, "fsl,cpm-brg", &len); | ||
| 1038 | if (!data || len != 4) { | ||
| 1039 | printk(KERN_ERR "CPM UART %s has no/invalid " | ||
| 1040 | "fsl,cpm-brg property.\n", np->name); | ||
| 1041 | return -EINVAL; | ||
| 1042 | } | ||
| 1043 | pinfo->brg = *data; | ||
| 1000 | } | 1044 | } |
| 1001 | pinfo->brg = *data; | ||
| 1002 | 1045 | ||
| 1003 | data = of_get_property(np, "fsl,cpm-command", &len); | 1046 | data = of_get_property(np, "fsl,cpm-command", &len); |
| 1004 | if (!data || len != 4) { | 1047 | if (!data || len != 4) { |
| @@ -1050,6 +1093,9 @@ static int cpm_uart_init_port(struct device_node *np, | |||
| 1050 | goto out_pram; | 1093 | goto out_pram; |
| 1051 | } | 1094 | } |
| 1052 | 1095 | ||
| 1096 | for (i = 0; i < NUM_GPIOS; i++) | ||
| 1097 | pinfo->gpios[i] = of_get_gpio(np, i); | ||
| 1098 | |||
| 1053 | return cpm_uart_request_port(&pinfo->port); | 1099 | return cpm_uart_request_port(&pinfo->port); |
| 1054 | 1100 | ||
| 1055 | out_pram: | 1101 | out_pram: |
diff --git a/include/asm-powerpc/cpm.h b/include/asm-powerpc/cpm.h index 63a55337c2de..24d79e3abd8e 100644 --- a/include/asm-powerpc/cpm.h +++ b/include/asm-powerpc/cpm.h | |||
| @@ -3,6 +3,7 @@ | |||
| 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/of.h> | ||
| 6 | 7 | ||
| 7 | /* Opcodes common to CPM1 and CPM2 | 8 | /* Opcodes common to CPM1 and CPM2 |
| 8 | */ | 9 | */ |
| @@ -100,4 +101,6 @@ unsigned long cpm_muram_offset(void __iomem *addr); | |||
| 100 | dma_addr_t cpm_muram_dma(void __iomem *addr); | 101 | dma_addr_t cpm_muram_dma(void __iomem *addr); |
| 101 | int cpm_command(u32 command, u8 opcode); | 102 | int cpm_command(u32 command, u8 opcode); |
| 102 | 103 | ||
| 104 | int cpm2_gpiochip_add32(struct device_node *np); | ||
| 105 | |||
| 103 | #endif | 106 | #endif |
diff --git a/include/asm-powerpc/cpm2.h b/include/asm-powerpc/cpm2.h index 2c7fd9cee291..2a6fa0183ac9 100644 --- a/include/asm-powerpc/cpm2.h +++ b/include/asm-powerpc/cpm2.h | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | 12 | ||
| 13 | #include <asm/immap_cpm2.h> | 13 | #include <asm/immap_cpm2.h> |
| 14 | #include <asm/cpm.h> | 14 | #include <asm/cpm.h> |
| 15 | #include <sysdev/fsl_soc.h> | ||
| 15 | 16 | ||
| 16 | #ifdef CONFIG_PPC_85xx | 17 | #ifdef CONFIG_PPC_85xx |
| 17 | #define CPM_MAP_ADDR (get_immrbase() + 0x80000) | 18 | #define CPM_MAP_ADDR (get_immrbase() + 0x80000) |
| @@ -93,10 +94,40 @@ extern cpm_cpm2_t __iomem *cpmp; /* Pointer to comm processor */ | |||
| 93 | #define cpm_dpfree cpm_muram_free | 94 | #define cpm_dpfree cpm_muram_free |
| 94 | #define cpm_dpram_addr cpm_muram_addr | 95 | #define cpm_dpram_addr cpm_muram_addr |
| 95 | 96 | ||
| 96 | extern void cpm_setbrg(uint brg, uint rate); | ||
| 97 | extern void cpm2_fastbrg(uint brg, uint rate, int div16); | ||
| 98 | extern void cpm2_reset(void); | 97 | extern void cpm2_reset(void); |
| 99 | 98 | ||
| 99 | /* Baud rate generators. | ||
| 100 | */ | ||
| 101 | #define CPM_BRG_RST ((uint)0x00020000) | ||
| 102 | #define CPM_BRG_EN ((uint)0x00010000) | ||
| 103 | #define CPM_BRG_EXTC_INT ((uint)0x00000000) | ||
| 104 | #define CPM_BRG_EXTC_CLK3_9 ((uint)0x00004000) | ||
| 105 | #define CPM_BRG_EXTC_CLK5_15 ((uint)0x00008000) | ||
| 106 | #define CPM_BRG_ATB ((uint)0x00002000) | ||
| 107 | #define CPM_BRG_CD_MASK ((uint)0x00001ffe) | ||
| 108 | #define CPM_BRG_DIV16 ((uint)0x00000001) | ||
| 109 | |||
| 110 | #define CPM2_BRG_INT_CLK (get_brgfreq()) | ||
| 111 | #define CPM2_BRG_UART_CLK (CPM2_BRG_INT_CLK/16) | ||
| 112 | |||
| 113 | extern void __cpm2_setbrg(uint brg, uint rate, uint clk, int div16, int src); | ||
| 114 | |||
| 115 | /* This function is used by UARTS, or anything else that uses a 16x | ||
| 116 | * oversampled clock. | ||
| 117 | */ | ||
| 118 | static inline void cpm_setbrg(uint brg, uint rate) | ||
| 119 | { | ||
| 120 | __cpm2_setbrg(brg, rate, CPM2_BRG_UART_CLK, 0, CPM_BRG_EXTC_INT); | ||
| 121 | } | ||
| 122 | |||
| 123 | /* This function is used to set high speed synchronous baud rate | ||
| 124 | * clocks. | ||
| 125 | */ | ||
| 126 | static inline void cpm2_fastbrg(uint brg, uint rate, int div16) | ||
| 127 | { | ||
| 128 | __cpm2_setbrg(brg, rate, CPM2_BRG_INT_CLK, div16, CPM_BRG_EXTC_INT); | ||
| 129 | } | ||
| 130 | |||
| 100 | /* Function code bits, usually generic to devices. | 131 | /* Function code bits, usually generic to devices. |
| 101 | */ | 132 | */ |
| 102 | #define CPMFCR_GBL ((u_char)0x20) /* Set memory snooping */ | 133 | #define CPMFCR_GBL ((u_char)0x20) /* Set memory snooping */ |
| @@ -195,17 +226,6 @@ typedef struct smc_uart { | |||
| 195 | #define SMCM_TX ((unsigned char)0x02) | 226 | #define SMCM_TX ((unsigned char)0x02) |
| 196 | #define SMCM_RX ((unsigned char)0x01) | 227 | #define SMCM_RX ((unsigned char)0x01) |
| 197 | 228 | ||
| 198 | /* Baud rate generators. | ||
| 199 | */ | ||
| 200 | #define CPM_BRG_RST ((uint)0x00020000) | ||
| 201 | #define CPM_BRG_EN ((uint)0x00010000) | ||
| 202 | #define CPM_BRG_EXTC_INT ((uint)0x00000000) | ||
| 203 | #define CPM_BRG_EXTC_CLK3_9 ((uint)0x00004000) | ||
| 204 | #define CPM_BRG_EXTC_CLK5_15 ((uint)0x00008000) | ||
| 205 | #define CPM_BRG_ATB ((uint)0x00002000) | ||
| 206 | #define CPM_BRG_CD_MASK ((uint)0x00001ffe) | ||
| 207 | #define CPM_BRG_DIV16 ((uint)0x00000001) | ||
| 208 | |||
| 209 | /* SCCs. | 229 | /* SCCs. |
| 210 | */ | 230 | */ |
| 211 | #define SCC_GSMRH_IRP ((uint)0x00040000) | 231 | #define SCC_GSMRH_IRP ((uint)0x00040000) |
diff --git a/include/asm-powerpc/pgtable-ppc64.h b/include/asm-powerpc/pgtable-ppc64.h index 5fc78c0be302..74c6f380b805 100644 --- a/include/asm-powerpc/pgtable-ppc64.h +++ b/include/asm-powerpc/pgtable-ppc64.h | |||
| @@ -461,6 +461,8 @@ void pgtable_cache_init(void); | |||
| 461 | return pt; | 461 | return pt; |
| 462 | } | 462 | } |
| 463 | 463 | ||
| 464 | pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long address); | ||
| 465 | |||
| 464 | #endif /* __ASSEMBLY__ */ | 466 | #endif /* __ASSEMBLY__ */ |
| 465 | 467 | ||
| 466 | #endif /* _ASM_POWERPC_PGTABLE_PPC64_H_ */ | 468 | #endif /* _ASM_POWERPC_PGTABLE_PPC64_H_ */ |
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h index a39b38ccdc97..69ed3cb1197a 100644 --- a/include/linux/pagemap.h +++ b/include/linux/pagemap.h | |||
| @@ -143,6 +143,29 @@ static inline int page_cache_get_speculative(struct page *page) | |||
| 143 | return 1; | 143 | return 1; |
| 144 | } | 144 | } |
| 145 | 145 | ||
| 146 | /* | ||
| 147 | * Same as above, but add instead of inc (could just be merged) | ||
| 148 | */ | ||
| 149 | static inline int page_cache_add_speculative(struct page *page, int count) | ||
| 150 | { | ||
| 151 | VM_BUG_ON(in_interrupt()); | ||
| 152 | |||
| 153 | #if !defined(CONFIG_SMP) && defined(CONFIG_CLASSIC_RCU) | ||
| 154 | # ifdef CONFIG_PREEMPT | ||
| 155 | VM_BUG_ON(!in_atomic()); | ||
| 156 | # endif | ||
| 157 | VM_BUG_ON(page_count(page) == 0); | ||
| 158 | atomic_add(count, &page->_count); | ||
| 159 | |||
| 160 | #else | ||
| 161 | if (unlikely(!atomic_add_unless(&page->_count, count, 0))) | ||
| 162 | return 0; | ||
| 163 | #endif | ||
| 164 | VM_BUG_ON(PageCompound(page) && page != compound_head(page)); | ||
| 165 | |||
| 166 | return 1; | ||
| 167 | } | ||
| 168 | |||
| 146 | static inline int page_freeze_refs(struct page *page, int count) | 169 | static inline int page_freeze_refs(struct page *page, int count) |
| 147 | { | 170 | { |
| 148 | return likely(atomic_cmpxchg(&page->_count, count, 0) == count); | 171 | return likely(atomic_cmpxchg(&page->_count, count, 0) == count); |
