diff options
317 files changed, 11233 insertions, 17284 deletions
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/mpic-msgr.txt b/Documentation/devicetree/bindings/powerpc/fsl/mpic-msgr.txt new file mode 100644 index 000000000000..bc8ded641ab6 --- /dev/null +++ b/Documentation/devicetree/bindings/powerpc/fsl/mpic-msgr.txt | |||
@@ -0,0 +1,63 @@ | |||
1 | * FSL MPIC Message Registers | ||
2 | |||
3 | This binding specifies what properties must be available in the device tree | ||
4 | representation of the message register blocks found in some FSL MPIC | ||
5 | implementations. | ||
6 | |||
7 | Required properties: | ||
8 | |||
9 | - compatible: Specifies the compatibility list for the message register | ||
10 | block. The type shall be <string-list> and the value shall be of the form | ||
11 | "fsl,mpic-v<version>-msgr", where <version> is the version number of | ||
12 | the MPIC containing the message registers. | ||
13 | |||
14 | - reg: Specifies the base physical address(s) and size(s) of the | ||
15 | message register block's addressable register space. The type shall be | ||
16 | <prop-encoded-array>. | ||
17 | |||
18 | - interrupts: Specifies a list of interrupt-specifiers which are available | ||
19 | for receiving interrupts. Interrupt-specifier consists of two cells: first | ||
20 | cell is interrupt-number and second cell is level-sense. The type shall be | ||
21 | <prop-encoded-array>. | ||
22 | |||
23 | Optional properties: | ||
24 | |||
25 | - mpic-msgr-receive-mask: Specifies what registers in the containing block | ||
26 | are allowed to receive interrupts. The value is a bit mask where a set | ||
27 | bit at bit 'n' indicates that message register 'n' can receive interrupts. | ||
28 | Note that "bit 'n'" is numbered from LSB for PPC hardware. The type shall | ||
29 | be <u32>. If not present, then all of the message registers in the block | ||
30 | are available. | ||
31 | |||
32 | Aliases: | ||
33 | |||
34 | An alias should be created for every message register block. They are not | ||
35 | required, though. However, a particular implementation of this binding | ||
36 | may require aliases to be present. Aliases are of the form | ||
37 | 'mpic-msgr-block<n>', where <n> is an integer specifying the block's number. | ||
38 | Numbers shall start at 0. | ||
39 | |||
40 | Example: | ||
41 | |||
42 | aliases { | ||
43 | mpic-msgr-block0 = &mpic_msgr_block0; | ||
44 | mpic-msgr-block1 = &mpic_msgr_block1; | ||
45 | }; | ||
46 | |||
47 | mpic_msgr_block0: mpic-msgr-block@41400 { | ||
48 | compatible = "fsl,mpic-v3.1-msgr"; | ||
49 | reg = <0x41400 0x200>; | ||
50 | // Message registers 0 and 2 in this block can receive interrupts on | ||
51 | // sources 0xb0 and 0xb2, respectively. | ||
52 | interrupts = <0xb0 2 0xb2 2>; | ||
53 | mpic-msgr-receive-mask = <0x5>; | ||
54 | }; | ||
55 | |||
56 | mpic_msgr_block1: mpic-msgr-block@42400 { | ||
57 | compatible = "fsl,mpic-v3.1-msgr"; | ||
58 | reg = <0x42400 0x200>; | ||
59 | // Message registers 0 and 2 in this block can receive interrupts on | ||
60 | // sources 0xb4 and 0xb6, respectively. | ||
61 | interrupts = <0xb4 2 0xb6 2>; | ||
62 | mpic-msgr-receive-mask = <0x5>; | ||
63 | }; | ||
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/mpic.txt b/Documentation/devicetree/bindings/powerpc/fsl/mpic.txt index 2cf38bd841fd..dc5744636a57 100644 --- a/Documentation/devicetree/bindings/powerpc/fsl/mpic.txt +++ b/Documentation/devicetree/bindings/powerpc/fsl/mpic.txt | |||
@@ -56,7 +56,27 @@ PROPERTIES | |||
56 | to the client. The presence of this property also mandates | 56 | to the client. The presence of this property also mandates |
57 | that any initialization related to interrupt sources shall | 57 | that any initialization related to interrupt sources shall |
58 | be limited to sources explicitly referenced in the device tree. | 58 | be limited to sources explicitly referenced in the device tree. |
59 | 59 | ||
60 | - big-endian | ||
61 | Usage: optional | ||
62 | Value type: <empty> | ||
63 | If present the MPIC will be assumed to be big-endian. Some | ||
64 | device-trees omit this property on MPIC nodes even when the MPIC is | ||
65 | in fact big-endian, so certain boards override this property. | ||
66 | |||
67 | - single-cpu-affinity | ||
68 | Usage: optional | ||
69 | Value type: <empty> | ||
70 | If present the MPIC will be assumed to only be able to route | ||
71 | non-IPI interrupts to a single CPU at a time (EG: Freescale MPIC). | ||
72 | |||
73 | - last-interrupt-source | ||
74 | Usage: optional | ||
75 | Value type: <u32> | ||
76 | Some MPICs do not correctly report the number of hardware sources | ||
77 | in the global feature registers. If specified, this field will | ||
78 | override the value read from MPIC_GREG_FEATURE_LAST_SRC. | ||
79 | |||
60 | INTERRUPT SPECIFIER DEFINITION | 80 | INTERRUPT SPECIFIER DEFINITION |
61 | 81 | ||
62 | Interrupt specifiers consists of 4 cells encoded as | 82 | Interrupt specifiers consists of 4 cells encoded as |
diff --git a/Documentation/devicetree/bindings/powerpc/fsl/msi-pic.txt b/Documentation/devicetree/bindings/powerpc/fsl/msi-pic.txt index 5d586e1ccaf5..5693877ab377 100644 --- a/Documentation/devicetree/bindings/powerpc/fsl/msi-pic.txt +++ b/Documentation/devicetree/bindings/powerpc/fsl/msi-pic.txt | |||
@@ -6,8 +6,10 @@ Required properties: | |||
6 | etc.) and the second is "fsl,mpic-msi" or "fsl,ipic-msi" depending on | 6 | etc.) and the second is "fsl,mpic-msi" or "fsl,ipic-msi" depending on |
7 | the parent type. | 7 | the parent type. |
8 | 8 | ||
9 | - reg : should contain the address and the length of the shared message | 9 | - reg : It may contain one or two regions. The first region should contain |
10 | interrupt register set. | 10 | the address and the length of the shared message interrupt register set. |
11 | The second region should contain the address of aliased MSIIR register for | ||
12 | platforms that have such an alias. | ||
11 | 13 | ||
12 | - msi-available-ranges: use <start count> style section to define which | 14 | - msi-available-ranges: use <start count> style section to define which |
13 | msi interrupt can be used in the 256 msi interrupts. This property is | 15 | msi interrupt can be used in the 256 msi interrupts. This property is |
diff --git a/Documentation/powerpc/firmware-assisted-dump.txt b/Documentation/powerpc/firmware-assisted-dump.txt new file mode 100644 index 000000000000..3007bc98af28 --- /dev/null +++ b/Documentation/powerpc/firmware-assisted-dump.txt | |||
@@ -0,0 +1,270 @@ | |||
1 | |||
2 | Firmware-Assisted Dump | ||
3 | ------------------------ | ||
4 | July 2011 | ||
5 | |||
6 | The goal of firmware-assisted dump is to enable the dump of | ||
7 | a crashed system, and to do so from a fully-reset system, and | ||
8 | to minimize the total elapsed time until the system is back | ||
9 | in production use. | ||
10 | |||
11 | - Firmware assisted dump (fadump) infrastructure is intended to replace | ||
12 | the existing phyp assisted dump. | ||
13 | - Fadump uses the same firmware interfaces and memory reservation model | ||
14 | as phyp assisted dump. | ||
15 | - Unlike phyp dump, fadump exports the memory dump through /proc/vmcore | ||
16 | in the ELF format in the same way as kdump. This helps us reuse the | ||
17 | kdump infrastructure for dump capture and filtering. | ||
18 | - Unlike phyp dump, userspace tool does not need to refer any sysfs | ||
19 | interface while reading /proc/vmcore. | ||
20 | - Unlike phyp dump, fadump allows user to release all the memory reserved | ||
21 | for dump, with a single operation of echo 1 > /sys/kernel/fadump_release_mem. | ||
22 | - Once enabled through kernel boot parameter, fadump can be | ||
23 | started/stopped through /sys/kernel/fadump_registered interface (see | ||
24 | sysfs files section below) and can be easily integrated with kdump | ||
25 | service start/stop init scripts. | ||
26 | |||
27 | Comparing with kdump or other strategies, firmware-assisted | ||
28 | dump offers several strong, practical advantages: | ||
29 | |||
30 | -- Unlike kdump, the system has been reset, and loaded | ||
31 | with a fresh copy of the kernel. In particular, | ||
32 | PCI and I/O devices have been reinitialized and are | ||
33 | in a clean, consistent state. | ||
34 | -- Once the dump is copied out, the memory that held the dump | ||
35 | is immediately available to the running kernel. And therefore, | ||
36 | unlike kdump, fadump doesn't need a 2nd reboot to get back | ||
37 | the system to the production configuration. | ||
38 | |||
39 | The above can only be accomplished by coordination with, | ||
40 | and assistance from the Power firmware. The procedure is | ||
41 | as follows: | ||
42 | |||
43 | -- The first kernel registers the sections of memory with the | ||
44 | Power firmware for dump preservation during OS initialization. | ||
45 | These registered sections of memory are reserved by the first | ||
46 | kernel during early boot. | ||
47 | |||
48 | -- When a system crashes, the Power firmware will save | ||
49 | the low memory (boot memory of size larger of 5% of system RAM | ||
50 | or 256MB) of RAM to the previous registered region. It will | ||
51 | also save system registers, and hardware PTE's. | ||
52 | |||
53 | NOTE: The term 'boot memory' means size of the low memory chunk | ||
54 | that is required for a kernel to boot successfully when | ||
55 | booted with restricted memory. By default, the boot memory | ||
56 | size will be the larger of 5% of system RAM or 256MB. | ||
57 | Alternatively, user can also specify boot memory size | ||
58 | through boot parameter 'fadump_reserve_mem=' which will | ||
59 | override the default calculated size. Use this option | ||
60 | if default boot memory size is not sufficient for second | ||
61 | kernel to boot successfully. | ||
62 | |||
63 | -- After the low memory (boot memory) area has been saved, the | ||
64 | firmware will reset PCI and other hardware state. It will | ||
65 | *not* clear the RAM. It will then launch the bootloader, as | ||
66 | normal. | ||
67 | |||
68 | -- The freshly booted kernel will notice that there is a new | ||
69 | node (ibm,dump-kernel) in the device tree, indicating that | ||
70 | there is crash data available from a previous boot. During | ||
71 | the early boot OS will reserve rest of the memory above | ||
72 | boot memory size effectively booting with restricted memory | ||
73 | size. This will make sure that the second kernel will not | ||
74 | touch any of the dump memory area. | ||
75 | |||
76 | -- User-space tools will read /proc/vmcore to obtain the contents | ||
77 | of memory, which holds the previous crashed kernel dump in ELF | ||
78 | format. The userspace tools may copy this info to disk, or | ||
79 | network, nas, san, iscsi, etc. as desired. | ||
80 | |||
81 | -- Once the userspace tool is done saving dump, it will echo | ||
82 | '1' to /sys/kernel/fadump_release_mem to release the reserved | ||
83 | memory back to general use, except the memory required for | ||
84 | next firmware-assisted dump registration. | ||
85 | |||
86 | e.g. | ||
87 | # echo 1 > /sys/kernel/fadump_release_mem | ||
88 | |||
89 | Please note that the firmware-assisted dump feature | ||
90 | is only available on Power6 and above systems with recent | ||
91 | firmware versions. | ||
92 | |||
93 | Implementation details: | ||
94 | ---------------------- | ||
95 | |||
96 | During boot, a check is made to see if firmware supports | ||
97 | this feature on that particular machine. If it does, then | ||
98 | we check to see if an active dump is waiting for us. If yes | ||
99 | then everything but boot memory size of RAM is reserved during | ||
100 | early boot (See Fig. 2). This area is released once we finish | ||
101 | collecting the dump from user land scripts (e.g. kdump scripts) | ||
102 | that are run. If there is dump data, then the | ||
103 | /sys/kernel/fadump_release_mem file is created, and the reserved | ||
104 | memory is held. | ||
105 | |||
106 | If there is no waiting dump data, then only the memory required | ||
107 | to hold CPU state, HPTE region, boot memory dump and elfcore | ||
108 | header, is reserved at the top of memory (see Fig. 1). This area | ||
109 | is *not* released: this region will be kept permanently reserved, | ||
110 | so that it can act as a receptacle for a copy of the boot memory | ||
111 | content in addition to CPU state and HPTE region, in the case a | ||
112 | crash does occur. | ||
113 | |||
114 | o Memory Reservation during first kernel | ||
115 | |||
116 | Low memory Top of memory | ||
117 | 0 boot memory size | | ||
118 | | | |<--Reserved dump area -->| | ||
119 | V V | Permanent Reservation V | ||
120 | +-----------+----------/ /----------+---+----+-----------+----+ | ||
121 | | | |CPU|HPTE| DUMP |ELF | | ||
122 | +-----------+----------/ /----------+---+----+-----------+----+ | ||
123 | | ^ | ||
124 | | | | ||
125 | \ / | ||
126 | ------------------------------------------- | ||
127 | Boot memory content gets transferred to | ||
128 | reserved area by firmware at the time of | ||
129 | crash | ||
130 | Fig. 1 | ||
131 | |||
132 | o Memory Reservation during second kernel after crash | ||
133 | |||
134 | Low memory Top of memory | ||
135 | 0 boot memory size | | ||
136 | | |<------------- Reserved dump area ----------- -->| | ||
137 | V V V | ||
138 | +-----------+----------/ /----------+---+----+-----------+----+ | ||
139 | | | |CPU|HPTE| DUMP |ELF | | ||
140 | +-----------+----------/ /----------+---+----+-----------+----+ | ||
141 | | | | ||
142 | V V | ||
143 | Used by second /proc/vmcore | ||
144 | kernel to boot | ||
145 | Fig. 2 | ||
146 | |||
147 | Currently the dump will be copied from /proc/vmcore to a | ||
148 | a new file upon user intervention. The dump data available through | ||
149 | /proc/vmcore will be in ELF format. Hence the existing kdump | ||
150 | infrastructure (kdump scripts) to save the dump works fine with | ||
151 | minor modifications. | ||
152 | |||
153 | The tools to examine the dump will be same as the ones | ||
154 | used for kdump. | ||
155 | |||
156 | How to enable firmware-assisted dump (fadump): | ||
157 | ------------------------------------- | ||
158 | |||
159 | 1. Set config option CONFIG_FA_DUMP=y and build kernel. | ||
160 | 2. Boot into linux kernel with 'fadump=on' kernel cmdline option. | ||
161 | 3. Optionally, user can also set 'fadump_reserve_mem=' kernel cmdline | ||
162 | to specify size of the memory to reserve for boot memory dump | ||
163 | preservation. | ||
164 | |||
165 | NOTE: If firmware-assisted dump fails to reserve memory then it will | ||
166 | fallback to existing kdump mechanism if 'crashkernel=' option | ||
167 | is set at kernel cmdline. | ||
168 | |||
169 | Sysfs/debugfs files: | ||
170 | ------------ | ||
171 | |||
172 | Firmware-assisted dump feature uses sysfs file system to hold | ||
173 | the control files and debugfs file to display memory reserved region. | ||
174 | |||
175 | Here is the list of files under kernel sysfs: | ||
176 | |||
177 | /sys/kernel/fadump_enabled | ||
178 | |||
179 | This is used to display the fadump status. | ||
180 | 0 = fadump is disabled | ||
181 | 1 = fadump is enabled | ||
182 | |||
183 | This interface can be used by kdump init scripts to identify if | ||
184 | fadump is enabled in the kernel and act accordingly. | ||
185 | |||
186 | /sys/kernel/fadump_registered | ||
187 | |||
188 | This is used to display the fadump registration status as well | ||
189 | as to control (start/stop) the fadump registration. | ||
190 | 0 = fadump is not registered. | ||
191 | 1 = fadump is registered and ready to handle system crash. | ||
192 | |||
193 | To register fadump echo 1 > /sys/kernel/fadump_registered and | ||
194 | echo 0 > /sys/kernel/fadump_registered for un-register and stop the | ||
195 | fadump. Once the fadump is un-registered, the system crash will not | ||
196 | be handled and vmcore will not be captured. This interface can be | ||
197 | easily integrated with kdump service start/stop. | ||
198 | |||
199 | /sys/kernel/fadump_release_mem | ||
200 | |||
201 | This file is available only when fadump is active during | ||
202 | second kernel. This is used to release the reserved memory | ||
203 | region that are held for saving crash dump. To release the | ||
204 | reserved memory echo 1 to it: | ||
205 | |||
206 | echo 1 > /sys/kernel/fadump_release_mem | ||
207 | |||
208 | After echo 1, the content of the /sys/kernel/debug/powerpc/fadump_region | ||
209 | file will change to reflect the new memory reservations. | ||
210 | |||
211 | The existing userspace tools (kdump infrastructure) can be easily | ||
212 | enhanced to use this interface to release the memory reserved for | ||
213 | dump and continue without 2nd reboot. | ||
214 | |||
215 | Here is the list of files under powerpc debugfs: | ||
216 | (Assuming debugfs is mounted on /sys/kernel/debug directory.) | ||
217 | |||
218 | /sys/kernel/debug/powerpc/fadump_region | ||
219 | |||
220 | This file shows the reserved memory regions if fadump is | ||
221 | enabled otherwise this file is empty. The output format | ||
222 | is: | ||
223 | <region>: [<start>-<end>] <reserved-size> bytes, Dumped: <dump-size> | ||
224 | |||
225 | e.g. | ||
226 | Contents when fadump is registered during first kernel | ||
227 | |||
228 | # cat /sys/kernel/debug/powerpc/fadump_region | ||
229 | CPU : [0x0000006ffb0000-0x0000006fff001f] 0x40020 bytes, Dumped: 0x0 | ||
230 | HPTE: [0x0000006fff0020-0x0000006fff101f] 0x1000 bytes, Dumped: 0x0 | ||
231 | DUMP: [0x0000006fff1020-0x0000007fff101f] 0x10000000 bytes, Dumped: 0x0 | ||
232 | |||
233 | Contents when fadump is active during second kernel | ||
234 | |||
235 | # cat /sys/kernel/debug/powerpc/fadump_region | ||
236 | CPU : [0x0000006ffb0000-0x0000006fff001f] 0x40020 bytes, Dumped: 0x40020 | ||
237 | HPTE: [0x0000006fff0020-0x0000006fff101f] 0x1000 bytes, Dumped: 0x1000 | ||
238 | DUMP: [0x0000006fff1020-0x0000007fff101f] 0x10000000 bytes, Dumped: 0x10000000 | ||
239 | : [0x00000010000000-0x0000006ffaffff] 0x5ffb0000 bytes, Dumped: 0x5ffb0000 | ||
240 | |||
241 | NOTE: Please refer to Documentation/filesystems/debugfs.txt on | ||
242 | how to mount the debugfs filesystem. | ||
243 | |||
244 | |||
245 | TODO: | ||
246 | ----- | ||
247 | o Need to come up with the better approach to find out more | ||
248 | accurate boot memory size that is required for a kernel to | ||
249 | boot successfully when booted with restricted memory. | ||
250 | o The fadump implementation introduces a fadump crash info structure | ||
251 | in the scratch area before the ELF core header. The idea of introducing | ||
252 | this structure is to pass some important crash info data to the second | ||
253 | kernel which will help second kernel to populate ELF core header with | ||
254 | correct data before it gets exported through /proc/vmcore. The current | ||
255 | design implementation does not address a possibility of introducing | ||
256 | additional fields (in future) to this structure without affecting | ||
257 | compatibility. Need to come up with the better approach to address this. | ||
258 | The possible approaches are: | ||
259 | 1. Introduce version field for version tracking, bump up the version | ||
260 | whenever a new field is added to the structure in future. The version | ||
261 | field can be used to find out what fields are valid for the current | ||
262 | version of the structure. | ||
263 | 2. Reserve the area of predefined size (say PAGE_SIZE) for this | ||
264 | structure and have unused area as reserved (initialized to zero) | ||
265 | for future field additions. | ||
266 | The advantage of approach 1 over 2 is we don't need to reserve extra space. | ||
267 | --- | ||
268 | Author: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com> | ||
269 | This document is based on the original documentation written for phyp | ||
270 | assisted dump by Linas Vepstas and Manish Ahuja. | ||
diff --git a/Documentation/powerpc/mpc52xx.txt b/Documentation/powerpc/mpc52xx.txt index 10dd4ab93b85..0d540a31ea1a 100644 --- a/Documentation/powerpc/mpc52xx.txt +++ b/Documentation/powerpc/mpc52xx.txt | |||
@@ -2,7 +2,7 @@ Linux 2.6.x on MPC52xx family | |||
2 | ----------------------------- | 2 | ----------------------------- |
3 | 3 | ||
4 | For the latest info, go to http://www.246tNt.com/mpc52xx/ | 4 | For the latest info, go to http://www.246tNt.com/mpc52xx/ |
5 | 5 | ||
6 | To compile/use : | 6 | To compile/use : |
7 | 7 | ||
8 | - U-Boot: | 8 | - U-Boot: |
@@ -10,23 +10,23 @@ To compile/use : | |||
10 | if you wish to ). | 10 | if you wish to ). |
11 | # make lite5200_defconfig | 11 | # make lite5200_defconfig |
12 | # make uImage | 12 | # make uImage |
13 | 13 | ||
14 | then, on U-boot: | 14 | then, on U-boot: |
15 | => tftpboot 200000 uImage | 15 | => tftpboot 200000 uImage |
16 | => tftpboot 400000 pRamdisk | 16 | => tftpboot 400000 pRamdisk |
17 | => bootm 200000 400000 | 17 | => bootm 200000 400000 |
18 | 18 | ||
19 | - DBug: | 19 | - DBug: |
20 | # <edit Makefile to set ARCH=ppc & CROSS_COMPILE=... ( also EXTRAVERSION | 20 | # <edit Makefile to set ARCH=ppc & CROSS_COMPILE=... ( also EXTRAVERSION |
21 | if you wish to ). | 21 | if you wish to ). |
22 | # make lite5200_defconfig | 22 | # make lite5200_defconfig |
23 | # cp your_initrd.gz arch/ppc/boot/images/ramdisk.image.gz | 23 | # cp your_initrd.gz arch/ppc/boot/images/ramdisk.image.gz |
24 | # make zImage.initrd | 24 | # make zImage.initrd |
25 | # make | 25 | # make |
26 | 26 | ||
27 | then in DBug: | 27 | then in DBug: |
28 | DBug> dn -i zImage.initrd.lite5200 | 28 | DBug> dn -i zImage.initrd.lite5200 |
29 | 29 | ||
30 | 30 | ||
31 | Some remarks : | 31 | Some remarks : |
32 | - The port is named mpc52xxx, and config options are PPC_MPC52xx. The MGT5100 | 32 | - The port is named mpc52xxx, and config options are PPC_MPC52xx. The MGT5100 |
diff --git a/Documentation/powerpc/phyp-assisted-dump.txt b/Documentation/powerpc/phyp-assisted-dump.txt deleted file mode 100644 index ad340205d96a..000000000000 --- a/Documentation/powerpc/phyp-assisted-dump.txt +++ /dev/null | |||
@@ -1,127 +0,0 @@ | |||
1 | |||
2 | Hypervisor-Assisted Dump | ||
3 | ------------------------ | ||
4 | November 2007 | ||
5 | |||
6 | The goal of hypervisor-assisted dump is to enable the dump of | ||
7 | a crashed system, and to do so from a fully-reset system, and | ||
8 | to minimize the total elapsed time until the system is back | ||
9 | in production use. | ||
10 | |||
11 | As compared to kdump or other strategies, hypervisor-assisted | ||
12 | dump offers several strong, practical advantages: | ||
13 | |||
14 | -- Unlike kdump, the system has been reset, and loaded | ||
15 | with a fresh copy of the kernel. In particular, | ||
16 | PCI and I/O devices have been reinitialized and are | ||
17 | in a clean, consistent state. | ||
18 | -- As the dump is performed, the dumped memory becomes | ||
19 | immediately available to the system for normal use. | ||
20 | -- After the dump is completed, no further reboots are | ||
21 | required; the system will be fully usable, and running | ||
22 | in its normal, production mode on its normal kernel. | ||
23 | |||
24 | The above can only be accomplished by coordination with, | ||
25 | and assistance from the hypervisor. The procedure is | ||
26 | as follows: | ||
27 | |||
28 | -- When a system crashes, the hypervisor will save | ||
29 | the low 256MB of RAM to a previously registered | ||
30 | save region. It will also save system state, system | ||
31 | registers, and hardware PTE's. | ||
32 | |||
33 | -- After the low 256MB area has been saved, the | ||
34 | hypervisor will reset PCI and other hardware state. | ||
35 | It will *not* clear RAM. It will then launch the | ||
36 | bootloader, as normal. | ||
37 | |||
38 | -- The freshly booted kernel will notice that there | ||
39 | is a new node (ibm,dump-kernel) in the device tree, | ||
40 | indicating that there is crash data available from | ||
41 | a previous boot. It will boot into only 256MB of RAM, | ||
42 | reserving the rest of system memory. | ||
43 | |||
44 | -- Userspace tools will parse /sys/kernel/release_region | ||
45 | and read /proc/vmcore to obtain the contents of memory, | ||
46 | which holds the previous crashed kernel. The userspace | ||
47 | tools may copy this info to disk, or network, nas, san, | ||
48 | iscsi, etc. as desired. | ||
49 | |||
50 | For Example: the values in /sys/kernel/release-region | ||
51 | would look something like this (address-range pairs). | ||
52 | CPU:0x177fee000-0x10000: HPTE:0x177ffe020-0x1000: / | ||
53 | DUMP:0x177fff020-0x10000000, 0x10000000-0x16F1D370A | ||
54 | |||
55 | -- As the userspace tools complete saving a portion of | ||
56 | dump, they echo an offset and size to | ||
57 | /sys/kernel/release_region to release the reserved | ||
58 | memory back to general use. | ||
59 | |||
60 | An example of this is: | ||
61 | "echo 0x40000000 0x10000000 > /sys/kernel/release_region" | ||
62 | which will release 256MB at the 1GB boundary. | ||
63 | |||
64 | Please note that the hypervisor-assisted dump feature | ||
65 | is only available on Power6-based systems with recent | ||
66 | firmware versions. | ||
67 | |||
68 | Implementation details: | ||
69 | ---------------------- | ||
70 | |||
71 | During boot, a check is made to see if firmware supports | ||
72 | this feature on this particular machine. If it does, then | ||
73 | we check to see if a active dump is waiting for us. If yes | ||
74 | then everything but 256 MB of RAM is reserved during early | ||
75 | boot. This area is released once we collect a dump from user | ||
76 | land scripts that are run. If there is dump data, then | ||
77 | the /sys/kernel/release_region file is created, and | ||
78 | the reserved memory is held. | ||
79 | |||
80 | If there is no waiting dump data, then only the highest | ||
81 | 256MB of the ram is reserved as a scratch area. This area | ||
82 | is *not* released: this region will be kept permanently | ||
83 | reserved, so that it can act as a receptacle for a copy | ||
84 | of the low 256MB in the case a crash does occur. See, | ||
85 | however, "open issues" below, as to whether | ||
86 | such a reserved region is really needed. | ||
87 | |||
88 | Currently the dump will be copied from /proc/vmcore to a | ||
89 | a new file upon user intervention. The starting address | ||
90 | to be read and the range for each data point in provided | ||
91 | in /sys/kernel/release_region. | ||
92 | |||
93 | The tools to examine the dump will be same as the ones | ||
94 | used for kdump. | ||
95 | |||
96 | General notes: | ||
97 | -------------- | ||
98 | Security: please note that there are potential security issues | ||
99 | with any sort of dump mechanism. In particular, plaintext | ||
100 | (unencrypted) data, and possibly passwords, may be present in | ||
101 | the dump data. Userspace tools must take adequate precautions to | ||
102 | preserve security. | ||
103 | |||
104 | Open issues/ToDo: | ||
105 | ------------ | ||
106 | o The various code paths that tell the hypervisor that a crash | ||
107 | occurred, vs. it simply being a normal reboot, should be | ||
108 | reviewed, and possibly clarified/fixed. | ||
109 | |||
110 | o Instead of using /sys/kernel, should there be a /sys/dump | ||
111 | instead? There is a dump_subsys being created by the s390 code, | ||
112 | perhaps the pseries code should use a similar layout as well. | ||
113 | |||
114 | o Is reserving a 256MB region really required? The goal of | ||
115 | reserving a 256MB scratch area is to make sure that no | ||
116 | important crash data is clobbered when the hypervisor | ||
117 | save low mem to the scratch area. But, if one could assure | ||
118 | that nothing important is located in some 256MB area, then | ||
119 | it would not need to be reserved. Something that can be | ||
120 | improved in subsequent versions. | ||
121 | |||
122 | o Still working the kdump team to integrate this with kdump, | ||
123 | some work remains but this would not affect the current | ||
124 | patches. | ||
125 | |||
126 | o Still need to write a shell script, to copy the dump away. | ||
127 | Currently I am parsing it manually. | ||
diff --git a/MAINTAINERS b/MAINTAINERS index 92f9924c4335..58f60356f071 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -4071,7 +4071,7 @@ M: Josh Boyer <jwboyer@gmail.com> | |||
4071 | M: Matt Porter <mporter@kernel.crashing.org> | 4071 | M: Matt Porter <mporter@kernel.crashing.org> |
4072 | W: http://www.penguinppc.org/ | 4072 | W: http://www.penguinppc.org/ |
4073 | L: linuxppc-dev@lists.ozlabs.org | 4073 | L: linuxppc-dev@lists.ozlabs.org |
4074 | T: git git://git.infradead.org/users/jwboyer/powerpc-4xx.git | 4074 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/jwboyer/powerpc-4xx.git |
4075 | S: Maintained | 4075 | S: Maintained |
4076 | F: arch/powerpc/platforms/40x/ | 4076 | F: arch/powerpc/platforms/40x/ |
4077 | F: arch/powerpc/platforms/44x/ | 4077 | F: arch/powerpc/platforms/44x/ |
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 303703d716fe..d219ebecabf0 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig | |||
@@ -134,6 +134,7 @@ config PPC | |||
134 | select HAVE_HW_BREAKPOINT if PERF_EVENTS && PPC_BOOK3S_64 | 134 | select HAVE_HW_BREAKPOINT if PERF_EVENTS && PPC_BOOK3S_64 |
135 | select HAVE_GENERIC_HARDIRQS | 135 | select HAVE_GENERIC_HARDIRQS |
136 | select HAVE_SPARSE_IRQ | 136 | select HAVE_SPARSE_IRQ |
137 | select SPARSE_IRQ | ||
137 | select IRQ_PER_CPU | 138 | select IRQ_PER_CPU |
138 | select IRQ_DOMAIN | 139 | select IRQ_DOMAIN |
139 | select GENERIC_IRQ_SHOW | 140 | select GENERIC_IRQ_SHOW |
@@ -377,13 +378,16 @@ config CRASH_DUMP | |||
377 | The same kernel binary can be used as production kernel and dump | 378 | The same kernel binary can be used as production kernel and dump |
378 | capture kernel. | 379 | capture kernel. |
379 | 380 | ||
380 | config PHYP_DUMP | 381 | config FA_DUMP |
381 | bool "Hypervisor-assisted dump (EXPERIMENTAL)" | 382 | bool "Firmware-assisted dump" |
382 | depends on PPC_PSERIES && EXPERIMENTAL | 383 | depends on PPC64 && PPC_RTAS && CRASH_DUMP |
383 | help | 384 | help |
384 | Hypervisor-assisted dump is meant to be a kdump replacement | 385 | A robust mechanism to get reliable kernel crash dump with |
385 | offering robustness and speed not possible without system | 386 | assistance from firmware. This approach does not use kexec, |
386 | hypervisor assistance. | 387 | instead firmware assists in booting the kdump kernel |
388 | while preserving memory contents. Firmware-assisted dump | ||
389 | is meant to be a kdump replacement offering robustness and | ||
390 | speed not possible without system firmware assistance. | ||
387 | 391 | ||
388 | If unsure, say "N" | 392 | If unsure, say "N" |
389 | 393 | ||
@@ -612,7 +616,7 @@ endmenu | |||
612 | 616 | ||
613 | config ISA_DMA_API | 617 | config ISA_DMA_API |
614 | bool | 618 | bool |
615 | default !PPC_ISERIES || PCI | 619 | default PCI |
616 | 620 | ||
617 | menu "Bus options" | 621 | menu "Bus options" |
618 | 622 | ||
diff --git a/arch/powerpc/Kconfig.debug b/arch/powerpc/Kconfig.debug index 4ccb2a009f74..72d55dbc6119 100644 --- a/arch/powerpc/Kconfig.debug +++ b/arch/powerpc/Kconfig.debug | |||
@@ -196,13 +196,6 @@ config PPC_EARLY_DEBUG_MAPLE | |||
196 | help | 196 | help |
197 | Select this to enable early debugging for Maple. | 197 | Select this to enable early debugging for Maple. |
198 | 198 | ||
199 | config PPC_EARLY_DEBUG_ISERIES | ||
200 | bool "iSeries HV Console" | ||
201 | depends on PPC_ISERIES | ||
202 | help | ||
203 | Select this to enable early debugging for legacy iSeries. You need | ||
204 | to hit "Ctrl-x Ctrl-x" to see the messages on the console. | ||
205 | |||
206 | config PPC_EARLY_DEBUG_PAS_REALMODE | 199 | config PPC_EARLY_DEBUG_PAS_REALMODE |
207 | bool "PA Semi real mode" | 200 | bool "PA Semi real mode" |
208 | depends on PPC_PASEMI | 201 | depends on PPC_PASEMI |
diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index b8b105c01c64..6524c6e21896 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile | |||
@@ -157,6 +157,7 @@ core-y += arch/powerpc/kernel/ \ | |||
157 | arch/powerpc/net/ | 157 | arch/powerpc/net/ |
158 | core-$(CONFIG_XMON) += arch/powerpc/xmon/ | 158 | core-$(CONFIG_XMON) += arch/powerpc/xmon/ |
159 | core-$(CONFIG_KVM) += arch/powerpc/kvm/ | 159 | core-$(CONFIG_KVM) += arch/powerpc/kvm/ |
160 | core-$(CONFIG_PERF_EVENTS) += arch/powerpc/perf/ | ||
160 | 161 | ||
161 | drivers-$(CONFIG_OPROFILE) += arch/powerpc/oprofile/ | 162 | drivers-$(CONFIG_OPROFILE) += arch/powerpc/oprofile/ |
162 | 163 | ||
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile index 8844a17ce8ed..e8461cb18d04 100644 --- a/arch/powerpc/boot/Makefile +++ b/arch/powerpc/boot/Makefile | |||
@@ -184,7 +184,6 @@ image-$(CONFIG_PPC_EFIKA) += zImage.chrp | |||
184 | image-$(CONFIG_PPC_PMAC) += zImage.pmac | 184 | image-$(CONFIG_PPC_PMAC) += zImage.pmac |
185 | image-$(CONFIG_PPC_HOLLY) += dtbImage.holly | 185 | image-$(CONFIG_PPC_HOLLY) += dtbImage.holly |
186 | image-$(CONFIG_PPC_PRPMC2800) += dtbImage.prpmc2800 | 186 | image-$(CONFIG_PPC_PRPMC2800) += dtbImage.prpmc2800 |
187 | image-$(CONFIG_PPC_ISERIES) += zImage.iseries | ||
188 | image-$(CONFIG_DEFAULT_UIMAGE) += uImage | 187 | image-$(CONFIG_DEFAULT_UIMAGE) += uImage |
189 | image-$(CONFIG_EPAPR_BOOT) += zImage.epapr | 188 | image-$(CONFIG_EPAPR_BOOT) += zImage.epapr |
190 | 189 | ||
@@ -247,7 +246,7 @@ image-$(CONFIG_ASP834x) += dtbImage.asp834x-redboot | |||
247 | image-$(CONFIG_MPC8540_ADS) += cuImage.mpc8540ads | 246 | image-$(CONFIG_MPC8540_ADS) += cuImage.mpc8540ads |
248 | image-$(CONFIG_MPC8560_ADS) += cuImage.mpc8560ads | 247 | image-$(CONFIG_MPC8560_ADS) += cuImage.mpc8560ads |
249 | image-$(CONFIG_MPC85xx_CDS) += cuImage.mpc8541cds \ | 248 | image-$(CONFIG_MPC85xx_CDS) += cuImage.mpc8541cds \ |
250 | cuImage.mpc8548cds \ | 249 | cuImage.mpc8548cds_32b \ |
251 | cuImage.mpc8555cds | 250 | cuImage.mpc8555cds |
252 | image-$(CONFIG_MPC85xx_MDS) += cuImage.mpc8568mds | 251 | image-$(CONFIG_MPC85xx_MDS) += cuImage.mpc8568mds |
253 | image-$(CONFIG_MPC85xx_DS) += cuImage.mpc8544ds \ | 252 | image-$(CONFIG_MPC85xx_DS) += cuImage.mpc8544ds \ |
@@ -311,12 +310,6 @@ $(obj)/dtbImage.%: vmlinux $(wrapperbits) $(obj)/%.dtb | |||
311 | $(obj)/vmlinux.strip: vmlinux | 310 | $(obj)/vmlinux.strip: vmlinux |
312 | $(STRIP) -s -R .comment $< -o $@ | 311 | $(STRIP) -s -R .comment $< -o $@ |
313 | 312 | ||
314 | # The iseries hypervisor won't take an ET_DYN executable, so this | ||
315 | # changes the type (byte 17) in the file to ET_EXEC (2). | ||
316 | $(obj)/zImage.iseries: vmlinux | ||
317 | $(STRIP) -s -R .comment $< -o $@ | ||
318 | printf "\x02" | dd of=$@ conv=notrunc bs=1 seek=17 | ||
319 | |||
320 | $(obj)/uImage: vmlinux $(wrapperbits) | 313 | $(obj)/uImage: vmlinux $(wrapperbits) |
321 | $(call if_changed,wrap,uboot) | 314 | $(call if_changed,wrap,uboot) |
322 | 315 | ||
@@ -364,7 +357,7 @@ install: $(CONFIGURE) $(addprefix $(obj)/, $(image-y)) | |||
364 | # anything not in $(targets) | 357 | # anything not in $(targets) |
365 | clean-files += $(image-) $(initrd-) cuImage.* dtbImage.* treeImage.* \ | 358 | clean-files += $(image-) $(initrd-) cuImage.* dtbImage.* treeImage.* \ |
366 | zImage zImage.initrd zImage.chrp zImage.coff zImage.holly \ | 359 | zImage zImage.initrd zImage.chrp zImage.coff zImage.holly \ |
367 | zImage.iseries zImage.miboot zImage.pmac zImage.pseries \ | 360 | zImage.miboot zImage.pmac zImage.pseries \ |
368 | zImage.maple simpleImage.* otheros.bld *.dtb | 361 | zImage.maple simpleImage.* otheros.bld *.dtb |
369 | 362 | ||
370 | # clean up files cached by wrapper | 363 | # clean up files cached by wrapper |
diff --git a/arch/powerpc/boot/dts/a4m072.dts b/arch/powerpc/boot/dts/a4m072.dts new file mode 100644 index 000000000000..fabe7b7d5f13 --- /dev/null +++ b/arch/powerpc/boot/dts/a4m072.dts | |||
@@ -0,0 +1,168 @@ | |||
1 | /* | ||
2 | * a4m072 board Device Tree Source | ||
3 | * | ||
4 | * Copyright (C) 2011 DENX Software Engineering GmbH | ||
5 | * Heiko Schocher <hs@denx.de> | ||
6 | * | ||
7 | * Copyright (C) 2007 Semihalf | ||
8 | * Marian Balakowicz <m8@semihalf.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License as published by the | ||
12 | * Free Software Foundation; either version 2 of the License, or (at your | ||
13 | * option) any later version. | ||
14 | */ | ||
15 | |||
16 | /include/ "mpc5200b.dtsi" | ||
17 | |||
18 | / { | ||
19 | model = "anonymous,a4m072"; | ||
20 | compatible = "anonymous,a4m072"; | ||
21 | |||
22 | soc5200@f0000000 { | ||
23 | #address-cells = <1>; | ||
24 | #size-cells = <1>; | ||
25 | compatible = "fsl,mpc5200b-immr"; | ||
26 | ranges = <0 0xf0000000 0x0000c000>; | ||
27 | reg = <0xf0000000 0x00000100>; | ||
28 | bus-frequency = <0>; /* From boot loader */ | ||
29 | system-frequency = <0>; /* From boot loader */ | ||
30 | |||
31 | cdm@200 { | ||
32 | fsl,init-ext-48mhz-en = <0x0>; | ||
33 | fsl,init-fd-enable = <0x01>; | ||
34 | fsl,init-fd-counters = <0x3333>; | ||
35 | }; | ||
36 | |||
37 | timer@600 { | ||
38 | fsl,has-wdt; | ||
39 | }; | ||
40 | |||
41 | gpt3: timer@630 { /* General Purpose Timer in GPIO mode */ | ||
42 | compatible = "fsl,mpc5200b-gpt-gpio","fsl,mpc5200-gpt-gpio"; | ||
43 | gpio-controller; | ||
44 | #gpio-cells = <2>; | ||
45 | }; | ||
46 | |||
47 | gpt4: timer@640 { /* General Purpose Timer in GPIO mode */ | ||
48 | compatible = "fsl,mpc5200b-gpt-gpio","fsl,mpc5200-gpt-gpio"; | ||
49 | gpio-controller; | ||
50 | #gpio-cells = <2>; | ||
51 | }; | ||
52 | |||
53 | gpt5: timer@650 { /* General Purpose Timer in GPIO mode */ | ||
54 | compatible = "fsl,mpc5200b-gpt-gpio","fsl,mpc5200-gpt-gpio"; | ||
55 | gpio-controller; | ||
56 | #gpio-cells = <2>; | ||
57 | }; | ||
58 | |||
59 | spi@f00 { | ||
60 | status = "disabled"; | ||
61 | }; | ||
62 | |||
63 | psc@2000 { | ||
64 | compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart"; | ||
65 | reg = <0x2000 0x100>; | ||
66 | interrupts = <2 1 0>; | ||
67 | }; | ||
68 | |||
69 | psc@2200 { | ||
70 | compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart"; | ||
71 | reg = <0x2200 0x100>; | ||
72 | interrupts = <2 2 0>; | ||
73 | }; | ||
74 | |||
75 | psc@2400 { | ||
76 | compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart"; | ||
77 | reg = <0x2400 0x100>; | ||
78 | interrupts = <2 3 0>; | ||
79 | }; | ||
80 | |||
81 | psc@2600 { | ||
82 | status = "disabled"; | ||
83 | }; | ||
84 | |||
85 | psc@2800 { | ||
86 | status = "disabled"; | ||
87 | }; | ||
88 | |||
89 | psc@2c00 { | ||
90 | compatible = "fsl,mpc5200b-psc-uart","fsl,mpc5200-psc-uart"; | ||
91 | reg = <0x2c00 0x100>; | ||
92 | interrupts = <2 4 0>; | ||
93 | }; | ||
94 | |||
95 | ethernet@3000 { | ||
96 | phy-handle = <&phy0>; | ||
97 | }; | ||
98 | |||
99 | mdio@3000 { | ||
100 | phy0: ethernet-phy@1f { | ||
101 | reg = <0x1f>; | ||
102 | interrupts = <1 2 0>; /* IRQ 2 active low */ | ||
103 | }; | ||
104 | }; | ||
105 | |||
106 | i2c@3d00 { | ||
107 | status = "disabled"; | ||
108 | }; | ||
109 | |||
110 | i2c@3d40 { | ||
111 | hwmon@2e { | ||
112 | compatible = "nsc,lm87"; | ||
113 | reg = <0x2e>; | ||
114 | }; | ||
115 | rtc@51 { | ||
116 | compatible = "nxp,rtc8564"; | ||
117 | reg = <0x51>; | ||
118 | }; | ||
119 | }; | ||
120 | }; | ||
121 | |||
122 | localbus { | ||
123 | compatible = "fsl,mpc5200b-lpb","simple-bus"; | ||
124 | #address-cells = <2>; | ||
125 | #size-cells = <1>; | ||
126 | ranges = <0 0 0xfe000000 0x02000000 | ||
127 | 1 0 0x62000000 0x00400000 | ||
128 | 2 0 0x64000000 0x00200000 | ||
129 | 3 0 0x66000000 0x01000000 | ||
130 | 6 0 0x68000000 0x01000000 | ||
131 | 7 0 0x6a000000 0x00000004>; | ||
132 | |||
133 | flash@0,0 { | ||
134 | compatible = "cfi-flash"; | ||
135 | reg = <0 0 0x02000000>; | ||
136 | bank-width = <2>; | ||
137 | #size-cells = <1>; | ||
138 | #address-cells = <1>; | ||
139 | }; | ||
140 | sram0@1,0 { | ||
141 | compatible = "mtd-ram"; | ||
142 | reg = <1 0x00000 0x00400000>; | ||
143 | bank-width = <2>; | ||
144 | }; | ||
145 | }; | ||
146 | |||
147 | pci@f0000d00 { | ||
148 | #interrupt-cells = <1>; | ||
149 | #size-cells = <2>; | ||
150 | #address-cells = <3>; | ||
151 | device_type = "pci"; | ||
152 | compatible = "fsl,mpc5200-pci"; | ||
153 | reg = <0xf0000d00 0x100>; | ||
154 | interrupt-map-mask = <0xf800 0 0 7>; | ||
155 | interrupt-map = < | ||
156 | /* IDSEL 0x16 */ | ||
157 | 0xc000 0 0 1 &mpc5200_pic 1 3 3 | ||
158 | 0xc000 0 0 2 &mpc5200_pic 1 3 3 | ||
159 | 0xc000 0 0 3 &mpc5200_pic 1 3 3 | ||
160 | 0xc000 0 0 4 &mpc5200_pic 1 3 3>; | ||
161 | clock-frequency = <0>; /* From boot loader */ | ||
162 | interrupts = <2 8 0 2 9 0 2 10 0>; | ||
163 | bus-range = <0 0>; | ||
164 | ranges = <0x42000000 0 0x80000000 0x80000000 0 0x10000000 | ||
165 | 0x02000000 0 0x90000000 0x90000000 0 0x10000000 | ||
166 | 0x01000000 0 0x00000000 0xa0000000 0 0x01000000>; | ||
167 | }; | ||
168 | }; | ||
diff --git a/arch/powerpc/boot/dts/bluestone.dts b/arch/powerpc/boot/dts/bluestone.dts index 74876f737407..7bda373f10ef 100644 --- a/arch/powerpc/boot/dts/bluestone.dts +++ b/arch/powerpc/boot/dts/bluestone.dts | |||
@@ -33,7 +33,7 @@ | |||
33 | aliases { | 33 | aliases { |
34 | ethernet0 = &EMAC0; | 34 | ethernet0 = &EMAC0; |
35 | serial0 = &UART0; | 35 | serial0 = &UART0; |
36 | //serial1 = &UART1; --gcl missing UART1 label | 36 | serial1 = &UART1; |
37 | }; | 37 | }; |
38 | 38 | ||
39 | cpus { | 39 | cpus { |
@@ -52,7 +52,7 @@ | |||
52 | d-cache-size = <32768>; | 52 | d-cache-size = <32768>; |
53 | dcr-controller; | 53 | dcr-controller; |
54 | dcr-access-method = "native"; | 54 | dcr-access-method = "native"; |
55 | //next-level-cache = <&L2C0>; --gcl missing L2C0 label | 55 | next-level-cache = <&L2C0>; |
56 | }; | 56 | }; |
57 | }; | 57 | }; |
58 | 58 | ||
@@ -117,6 +117,16 @@ | |||
117 | dcr-reg = <0x00c 0x002>; | 117 | dcr-reg = <0x00c 0x002>; |
118 | }; | 118 | }; |
119 | 119 | ||
120 | L2C0: l2c { | ||
121 | compatible = "ibm,l2-cache-apm82181", "ibm,l2-cache"; | ||
122 | dcr-reg = <0x020 0x008 | ||
123 | 0x030 0x008>; | ||
124 | cache-line-size = <32>; | ||
125 | cache-size = <262144>; | ||
126 | interrupt-parent = <&UIC1>; | ||
127 | interrupts = <11 1>; | ||
128 | }; | ||
129 | |||
120 | plb { | 130 | plb { |
121 | compatible = "ibm,plb4"; | 131 | compatible = "ibm,plb4"; |
122 | #address-cells = <2>; | 132 | #address-cells = <2>; |
@@ -182,6 +192,53 @@ | |||
182 | reg = <0x001a0000 0x00060000>; | 192 | reg = <0x001a0000 0x00060000>; |
183 | }; | 193 | }; |
184 | }; | 194 | }; |
195 | |||
196 | ndfc@1,0 { | ||
197 | compatible = "ibm,ndfc"; | ||
198 | reg = <0x00000003 0x00000000 0x00002000>; | ||
199 | ccr = <0x00001000>; | ||
200 | bank-settings = <0x80002222>; | ||
201 | #address-cells = <1>; | ||
202 | #size-cells = <1>; | ||
203 | /* 2Gb Nand Flash */ | ||
204 | nand { | ||
205 | #address-cells = <1>; | ||
206 | #size-cells = <1>; | ||
207 | |||
208 | partition@0 { | ||
209 | label = "firmware"; | ||
210 | reg = <0x00000000 0x00C00000>; | ||
211 | }; | ||
212 | partition@c00000 { | ||
213 | label = "environment"; | ||
214 | reg = <0x00C00000 0x00B00000>; | ||
215 | }; | ||
216 | partition@1700000 { | ||
217 | label = "kernel"; | ||
218 | reg = <0x01700000 0x00E00000>; | ||
219 | }; | ||
220 | partition@2500000 { | ||
221 | label = "root"; | ||
222 | reg = <0x02500000 0x08200000>; | ||
223 | }; | ||
224 | partition@a700000 { | ||
225 | label = "device-tree"; | ||
226 | reg = <0x0A700000 0x00B00000>; | ||
227 | }; | ||
228 | partition@b200000 { | ||
229 | label = "config"; | ||
230 | reg = <0x0B200000 0x00D00000>; | ||
231 | }; | ||
232 | partition@bf00000 { | ||
233 | label = "diag"; | ||
234 | reg = <0x0BF00000 0x00C00000>; | ||
235 | }; | ||
236 | partition@cb00000 { | ||
237 | label = "vendor"; | ||
238 | reg = <0x0CB00000 0x3500000>; | ||
239 | }; | ||
240 | }; | ||
241 | }; | ||
185 | }; | 242 | }; |
186 | 243 | ||
187 | UART0: serial@ef600300 { | 244 | UART0: serial@ef600300 { |
@@ -195,11 +252,36 @@ | |||
195 | interrupts = <0x1 0x4>; | 252 | interrupts = <0x1 0x4>; |
196 | }; | 253 | }; |
197 | 254 | ||
255 | UART1: serial@ef600400 { | ||
256 | device_type = "serial"; | ||
257 | compatible = "ns16550"; | ||
258 | reg = <0xef600400 0x00000008>; | ||
259 | virtual-reg = <0xef600400>; | ||
260 | clock-frequency = <0>; /* Filled in by U-Boot */ | ||
261 | current-speed = <0>; /* Filled in by U-Boot */ | ||
262 | interrupt-parent = <&UIC0>; | ||
263 | interrupts = <0x1 0x4>; | ||
264 | }; | ||
265 | |||
198 | IIC0: i2c@ef600700 { | 266 | IIC0: i2c@ef600700 { |
199 | compatible = "ibm,iic"; | 267 | compatible = "ibm,iic"; |
200 | reg = <0xef600700 0x00000014>; | 268 | reg = <0xef600700 0x00000014>; |
201 | interrupt-parent = <&UIC0>; | 269 | interrupt-parent = <&UIC0>; |
202 | interrupts = <0x2 0x4>; | 270 | interrupts = <0x2 0x4>; |
271 | #address-cells = <1>; | ||
272 | #size-cells = <0>; | ||
273 | rtc@68 { | ||
274 | compatible = "stm,m41t80"; | ||
275 | reg = <0x68>; | ||
276 | interrupt-parent = <&UIC0>; | ||
277 | interrupts = <0x9 0x8>; | ||
278 | }; | ||
279 | sttm@4C { | ||
280 | compatible = "adm,adm1032"; | ||
281 | reg = <0x4C>; | ||
282 | interrupt-parent = <&UIC1>; | ||
283 | interrupts = <0x1E 0x8>; /* CPU_THERNAL_L */ | ||
284 | }; | ||
203 | }; | 285 | }; |
204 | 286 | ||
205 | IIC1: i2c@ef600800 { | 287 | IIC1: i2c@ef600800 { |
@@ -250,5 +332,46 @@ | |||
250 | }; | 332 | }; |
251 | }; | 333 | }; |
252 | 334 | ||
335 | PCIE0: pciex@d00000000 { | ||
336 | device_type = "pci"; | ||
337 | #interrupt-cells = <1>; | ||
338 | #size-cells = <2>; | ||
339 | #address-cells = <3>; | ||
340 | compatible = "ibm,plb-pciex-apm821xx", "ibm,plb-pciex"; | ||
341 | primary; | ||
342 | port = <0x0>; /* port number */ | ||
343 | reg = <0x0000000d 0x00000000 0x20000000 /* Config space access */ | ||
344 | 0x0000000c 0x08010000 0x00001000>; /* Registers */ | ||
345 | dcr-reg = <0x100 0x020>; | ||
346 | sdr-base = <0x300>; | ||
347 | |||
348 | /* Outbound ranges, one memory and one IO, | ||
349 | * later cannot be changed | ||
350 | */ | ||
351 | ranges = <0x02000000 0x00000000 0x80000000 0x0000000e 0x00000000 0x00000000 0x80000000 | ||
352 | 0x02000000 0x00000000 0x00000000 0x0000000f 0x00000000 0x00000000 0x00100000 | ||
353 | 0x01000000 0x00000000 0x00000000 0x0000000f 0x80000000 0x00000000 0x00010000>; | ||
354 | |||
355 | /* Inbound 2GB range starting at 0 */ | ||
356 | dma-ranges = <0x42000000 0x0 0x0 0x0 0x0 0x0 0x80000000>; | ||
357 | |||
358 | /* This drives busses 40 to 0x7f */ | ||
359 | bus-range = <0x40 0x7f>; | ||
360 | |||
361 | /* Legacy interrupts (note the weird polarity, the bridge seems | ||
362 | * to invert PCIe legacy interrupts). | ||
363 | * We are de-swizzling here because the numbers are actually for | ||
364 | * port of the root complex virtual P2P bridge. But I want | ||
365 | * to avoid putting a node for it in the tree, so the numbers | ||
366 | * below are basically de-swizzled numbers. | ||
367 | * The real slot is on idsel 0, so the swizzling is 1:1 | ||
368 | */ | ||
369 | interrupt-map-mask = <0x0 0x0 0x0 0x7>; | ||
370 | interrupt-map = < | ||
371 | 0x0 0x0 0x0 0x1 &UIC3 0xc 0x4 /* swizzled int A */ | ||
372 | 0x0 0x0 0x0 0x2 &UIC3 0xd 0x4 /* swizzled int B */ | ||
373 | 0x0 0x0 0x0 0x3 &UIC3 0xe 0x4 /* swizzled int C */ | ||
374 | 0x0 0x0 0x0 0x4 &UIC3 0xf 0x4 /* swizzled int D */>; | ||
375 | }; | ||
253 | }; | 376 | }; |
254 | }; | 377 | }; |
diff --git a/arch/powerpc/boot/dts/fsl/mpc8536si-post.dtsi b/arch/powerpc/boot/dts/fsl/mpc8536si-post.dtsi index b37da56018b6..c8b2daa40ac8 100644 --- a/arch/powerpc/boot/dts/fsl/mpc8536si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/mpc8536si-post.dtsi | |||
@@ -202,7 +202,7 @@ | |||
202 | /include/ "pq3-etsec1-timer-0.dtsi" | 202 | /include/ "pq3-etsec1-timer-0.dtsi" |
203 | 203 | ||
204 | usb@22000 { | 204 | usb@22000 { |
205 | compatible = "fsl,mpc8536-usb2-mph", "fsl-usb2-mph"; | 205 | compatible = "fsl-usb2-mph-v1.2", "fsl,mpc8536-usb2-mph", "fsl-usb2-mph"; |
206 | reg = <0x22000 0x1000>; | 206 | reg = <0x22000 0x1000>; |
207 | #address-cells = <1>; | 207 | #address-cells = <1>; |
208 | #size-cells = <0>; | 208 | #size-cells = <0>; |
@@ -210,7 +210,7 @@ | |||
210 | }; | 210 | }; |
211 | 211 | ||
212 | usb@23000 { | 212 | usb@23000 { |
213 | compatible = "fsl,mpc8536-usb2-mph", "fsl-usb2-mph"; | 213 | compatible = "fsl-usb2-mph-v1.2", "fsl,mpc8536-usb2-mph", "fsl-usb2-mph"; |
214 | reg = <0x23000 0x1000>; | 214 | reg = <0x23000 0x1000>; |
215 | #address-cells = <1>; | 215 | #address-cells = <1>; |
216 | #size-cells = <0>; | 216 | #size-cells = <0>; |
diff --git a/arch/powerpc/boot/dts/fsl/mpc8548si-post.dtsi b/arch/powerpc/boot/dts/fsl/mpc8548si-post.dtsi index 9d8023a69d7d..579d76cb8e32 100644 --- a/arch/powerpc/boot/dts/fsl/mpc8548si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/mpc8548si-post.dtsi | |||
@@ -89,6 +89,21 @@ | |||
89 | }; | 89 | }; |
90 | }; | 90 | }; |
91 | 91 | ||
92 | &rio { | ||
93 | compatible = "fsl,srio"; | ||
94 | interrupts = <48 2 0 0>; | ||
95 | #address-cells = <2>; | ||
96 | #size-cells = <2>; | ||
97 | fsl,srio-rmu-handle = <&rmu>; | ||
98 | ranges; | ||
99 | |||
100 | port1 { | ||
101 | #address-cells = <2>; | ||
102 | #size-cells = <2>; | ||
103 | cell-index = <1>; | ||
104 | }; | ||
105 | }; | ||
106 | |||
92 | &soc { | 107 | &soc { |
93 | #address-cells = <1>; | 108 | #address-cells = <1>; |
94 | #size-cells = <1>; | 109 | #size-cells = <1>; |
@@ -134,6 +149,7 @@ | |||
134 | 149 | ||
135 | /include/ "pq3-sec2.1-0.dtsi" | 150 | /include/ "pq3-sec2.1-0.dtsi" |
136 | /include/ "pq3-mpic.dtsi" | 151 | /include/ "pq3-mpic.dtsi" |
152 | /include/ "pq3-rmu-0.dtsi" | ||
137 | 153 | ||
138 | global-utilities@e0000 { | 154 | global-utilities@e0000 { |
139 | compatible = "fsl,mpc8548-guts"; | 155 | compatible = "fsl,mpc8548-guts"; |
diff --git a/arch/powerpc/boot/dts/fsl/mpc8548si-pre.dtsi b/arch/powerpc/boot/dts/fsl/mpc8548si-pre.dtsi index 289f1218d755..720422d83529 100644 --- a/arch/powerpc/boot/dts/fsl/mpc8548si-pre.dtsi +++ b/arch/powerpc/boot/dts/fsl/mpc8548si-pre.dtsi | |||
@@ -43,7 +43,9 @@ | |||
43 | serial0 = &serial0; | 43 | serial0 = &serial0; |
44 | serial1 = &serial1; | 44 | serial1 = &serial1; |
45 | ethernet0 = &enet0; | 45 | ethernet0 = &enet0; |
46 | ethernet1 = &enet2; | 46 | ethernet1 = &enet1; |
47 | ethernet2 = &enet2; | ||
48 | ethernet3 = &enet3; | ||
47 | pci0 = &pci0; | 49 | pci0 = &pci0; |
48 | pci1 = &pci1; | 50 | pci1 = &pci1; |
49 | pci2 = &pci2; | 51 | pci2 = &pci2; |
diff --git a/arch/powerpc/boot/dts/fsl/p1010si-post.dtsi b/arch/powerpc/boot/dts/fsl/p1010si-post.dtsi index a97d1263372c..0bde9ee8afaf 100644 --- a/arch/powerpc/boot/dts/fsl/p1010si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/p1010si-post.dtsi | |||
@@ -156,6 +156,9 @@ | |||
156 | 156 | ||
157 | /include/ "pq3-dma-0.dtsi" | 157 | /include/ "pq3-dma-0.dtsi" |
158 | /include/ "pq3-usb2-dr-0.dtsi" | 158 | /include/ "pq3-usb2-dr-0.dtsi" |
159 | usb@22000 { | ||
160 | compatible = "fsl-usb2-dr-v1.6", "fsl-usb2-dr"; | ||
161 | }; | ||
159 | /include/ "pq3-esdhc-0.dtsi" | 162 | /include/ "pq3-esdhc-0.dtsi" |
160 | sdhc@2e000 { | 163 | sdhc@2e000 { |
161 | compatible = "fsl,p1010-esdhc", "fsl,esdhc"; | 164 | compatible = "fsl,p1010-esdhc", "fsl,esdhc"; |
diff --git a/arch/powerpc/boot/dts/fsl/p1020si-post.dtsi b/arch/powerpc/boot/dts/fsl/p1020si-post.dtsi index 5de5fc351314..68cc5e7f6477 100644 --- a/arch/powerpc/boot/dts/fsl/p1020si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/p1020si-post.dtsi | |||
@@ -142,7 +142,13 @@ | |||
142 | 142 | ||
143 | /include/ "pq3-dma-0.dtsi" | 143 | /include/ "pq3-dma-0.dtsi" |
144 | /include/ "pq3-usb2-dr-0.dtsi" | 144 | /include/ "pq3-usb2-dr-0.dtsi" |
145 | usb@22000 { | ||
146 | compatible = "fsl-usb2-dr-v1.6", "fsl-usb2-dr"; | ||
147 | }; | ||
145 | /include/ "pq3-usb2-dr-1.dtsi" | 148 | /include/ "pq3-usb2-dr-1.dtsi" |
149 | usb@23000 { | ||
150 | compatible = "fsl-usb2-dr-v1.6", "fsl-usb2-dr"; | ||
151 | }; | ||
146 | 152 | ||
147 | /include/ "pq3-esdhc-0.dtsi" | 153 | /include/ "pq3-esdhc-0.dtsi" |
148 | sdhc@2e000 { | 154 | sdhc@2e000 { |
diff --git a/arch/powerpc/boot/dts/fsl/p1021si-post.dtsi b/arch/powerpc/boot/dts/fsl/p1021si-post.dtsi index 38ba54d1e32e..4252ef85fb7a 100644 --- a/arch/powerpc/boot/dts/fsl/p1021si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/p1021si-post.dtsi | |||
@@ -142,8 +142,15 @@ | |||
142 | 142 | ||
143 | /include/ "pq3-dma-0.dtsi" | 143 | /include/ "pq3-dma-0.dtsi" |
144 | /include/ "pq3-usb2-dr-0.dtsi" | 144 | /include/ "pq3-usb2-dr-0.dtsi" |
145 | usb@22000 { | ||
146 | compatible = "fsl-usb2-dr-v1.6", "fsl-usb2-dr"; | ||
147 | }; | ||
145 | 148 | ||
146 | /include/ "pq3-esdhc-0.dtsi" | 149 | /include/ "pq3-esdhc-0.dtsi" |
150 | sdhc@2e000 { | ||
151 | sdhci,auto-cmd12; | ||
152 | }; | ||
153 | |||
147 | /include/ "pq3-sec3.3-0.dtsi" | 154 | /include/ "pq3-sec3.3-0.dtsi" |
148 | 155 | ||
149 | /include/ "pq3-mpic.dtsi" | 156 | /include/ "pq3-mpic.dtsi" |
diff --git a/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi b/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi index ff9ed1d87929..06216b8c0af5 100644 --- a/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/p1022si-post.dtsi | |||
@@ -35,7 +35,11 @@ | |||
35 | &lbc { | 35 | &lbc { |
36 | #address-cells = <2>; | 36 | #address-cells = <2>; |
37 | #size-cells = <1>; | 37 | #size-cells = <1>; |
38 | compatible = "fsl,p1022-elbc", "fsl,elbc", "simple-bus"; | 38 | /* |
39 | * The localbus on the P1022 is not a simple-bus because of the eLBC | ||
40 | * pin muxing when the DIU is enabled. | ||
41 | */ | ||
42 | compatible = "fsl,p1022-elbc", "fsl,elbc"; | ||
39 | interrupts = <19 2 0 0>; | 43 | interrupts = <19 2 0 0>; |
40 | }; | 44 | }; |
41 | 45 | ||
@@ -199,7 +203,13 @@ | |||
199 | 203 | ||
200 | /include/ "pq3-dma-0.dtsi" | 204 | /include/ "pq3-dma-0.dtsi" |
201 | /include/ "pq3-usb2-dr-0.dtsi" | 205 | /include/ "pq3-usb2-dr-0.dtsi" |
206 | usb@22000 { | ||
207 | compatible = "fsl-usb2-dr-v1.6", "fsl-usb2-dr"; | ||
208 | }; | ||
202 | /include/ "pq3-usb2-dr-1.dtsi" | 209 | /include/ "pq3-usb2-dr-1.dtsi" |
210 | usb@23000 { | ||
211 | compatible = "fsl-usb2-dr-v1.6", "fsl-usb2-dr"; | ||
212 | }; | ||
203 | 213 | ||
204 | /include/ "pq3-esdhc-0.dtsi" | 214 | /include/ "pq3-esdhc-0.dtsi" |
205 | sdhc@2e000 { | 215 | sdhc@2e000 { |
diff --git a/arch/powerpc/boot/dts/fsl/p1023si-post.dtsi b/arch/powerpc/boot/dts/fsl/p1023si-post.dtsi index b06bb4cc1fe8..941fa159cefb 100644 --- a/arch/powerpc/boot/dts/fsl/p1023si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/p1023si-post.dtsi | |||
@@ -142,6 +142,9 @@ | |||
142 | 142 | ||
143 | /include/ "pq3-dma-0.dtsi" | 143 | /include/ "pq3-dma-0.dtsi" |
144 | /include/ "pq3-usb2-dr-0.dtsi" | 144 | /include/ "pq3-usb2-dr-0.dtsi" |
145 | usb@22000 { | ||
146 | compatible = "fsl-usb2-dr-v1.6", "fsl-usb2-dr"; | ||
147 | }; | ||
145 | 148 | ||
146 | crypto: crypto@300000 { | 149 | crypto: crypto@300000 { |
147 | compatible = "fsl,sec-v4.2", "fsl,sec-v4.0"; | 150 | compatible = "fsl,sec-v4.2", "fsl,sec-v4.0"; |
diff --git a/arch/powerpc/boot/dts/fsl/p2020si-post.dtsi b/arch/powerpc/boot/dts/fsl/p2020si-post.dtsi index 332e9e75e6c2..884e01bcb243 100644 --- a/arch/powerpc/boot/dts/fsl/p2020si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/p2020si-post.dtsi | |||
@@ -171,6 +171,9 @@ | |||
171 | 171 | ||
172 | /include/ "pq3-dma-0.dtsi" | 172 | /include/ "pq3-dma-0.dtsi" |
173 | /include/ "pq3-usb2-dr-0.dtsi" | 173 | /include/ "pq3-usb2-dr-0.dtsi" |
174 | usb@22000 { | ||
175 | compatible = "fsl-usb2-dr-v1.6", "fsl-usb2-dr"; | ||
176 | }; | ||
174 | /include/ "pq3-etsec1-0.dtsi" | 177 | /include/ "pq3-etsec1-0.dtsi" |
175 | /include/ "pq3-etsec1-timer-0.dtsi" | 178 | /include/ "pq3-etsec1-timer-0.dtsi" |
176 | 179 | ||
diff --git a/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi b/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi index 234a399ddeb2..531eab82c6c9 100644 --- a/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/p2041si-post.dtsi | |||
@@ -309,12 +309,14 @@ | |||
309 | /include/ "qoriq-gpio-0.dtsi" | 309 | /include/ "qoriq-gpio-0.dtsi" |
310 | /include/ "qoriq-usb2-mph-0.dtsi" | 310 | /include/ "qoriq-usb2-mph-0.dtsi" |
311 | usb0: usb@210000 { | 311 | usb0: usb@210000 { |
312 | compatible = "fsl-usb2-mph-v1.6", "fsl,mpc85xx-usb2-mph", "fsl-usb2-mph"; | ||
312 | phy_type = "utmi"; | 313 | phy_type = "utmi"; |
313 | port0; | 314 | port0; |
314 | }; | 315 | }; |
315 | 316 | ||
316 | /include/ "qoriq-usb2-dr-0.dtsi" | 317 | /include/ "qoriq-usb2-dr-0.dtsi" |
317 | usb1: usb@211000 { | 318 | usb1: usb@211000 { |
319 | compatible = "fsl-usb2-dr-v1.6", "fsl,mpc85xx-usb2-dr", "fsl-usb2-dr"; | ||
318 | dr_mode = "host"; | 320 | dr_mode = "host"; |
319 | phy_type = "utmi"; | 321 | phy_type = "utmi"; |
320 | }; | 322 | }; |
diff --git a/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi b/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi index d41d08de7f7e..af4ebc8009e3 100644 --- a/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/p3041si-post.dtsi | |||
@@ -336,12 +336,14 @@ | |||
336 | /include/ "qoriq-gpio-0.dtsi" | 336 | /include/ "qoriq-gpio-0.dtsi" |
337 | /include/ "qoriq-usb2-mph-0.dtsi" | 337 | /include/ "qoriq-usb2-mph-0.dtsi" |
338 | usb0: usb@210000 { | 338 | usb0: usb@210000 { |
339 | compatible = "fsl-usb2-mph-v1.6", "fsl-usb2-mph"; | ||
339 | phy_type = "utmi"; | 340 | phy_type = "utmi"; |
340 | port0; | 341 | port0; |
341 | }; | 342 | }; |
342 | 343 | ||
343 | /include/ "qoriq-usb2-dr-0.dtsi" | 344 | /include/ "qoriq-usb2-dr-0.dtsi" |
344 | usb1: usb@211000 { | 345 | usb1: usb@211000 { |
346 | compatible = "fsl-usb2-dr-v1.6", "fsl,mpc85xx-usb2-dr", "fsl-usb2-dr"; | ||
345 | dr_mode = "host"; | 347 | dr_mode = "host"; |
346 | phy_type = "utmi"; | 348 | phy_type = "utmi"; |
347 | }; | 349 | }; |
diff --git a/arch/powerpc/boot/dts/fsl/p3060si-post.dtsi b/arch/powerpc/boot/dts/fsl/p3060si-post.dtsi index a63edd195ae5..b3e56929eee2 100644 --- a/arch/powerpc/boot/dts/fsl/p3060si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/p3060si-post.dtsi | |||
@@ -291,6 +291,12 @@ | |||
291 | /include/ "qoriq-duart-1.dtsi" | 291 | /include/ "qoriq-duart-1.dtsi" |
292 | /include/ "qoriq-gpio-0.dtsi" | 292 | /include/ "qoriq-gpio-0.dtsi" |
293 | /include/ "qoriq-usb2-mph-0.dtsi" | 293 | /include/ "qoriq-usb2-mph-0.dtsi" |
294 | usb@210000 { | ||
295 | compatible = "fsl-usb2-mph-v2.2", "fsl,mpc85xx-usb2-mph", "fsl-usb2-mph"; | ||
296 | }; | ||
294 | /include/ "qoriq-usb2-dr-0.dtsi" | 297 | /include/ "qoriq-usb2-dr-0.dtsi" |
298 | usb@211000 { | ||
299 | compatible = "fsl-usb2-dr-v2.2", "fsl,mpc85xx-usb2-dr", "fsl-usb2-dr"; | ||
300 | }; | ||
295 | /include/ "qoriq-sec4.1-0.dtsi" | 301 | /include/ "qoriq-sec4.1-0.dtsi" |
296 | }; | 302 | }; |
diff --git a/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi b/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi index 914074b91a85..64b6abea8464 100644 --- a/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi +++ b/arch/powerpc/boot/dts/fsl/p5020si-post.dtsi | |||
@@ -339,12 +339,14 @@ | |||
339 | /include/ "qoriq-gpio-0.dtsi" | 339 | /include/ "qoriq-gpio-0.dtsi" |
340 | /include/ "qoriq-usb2-mph-0.dtsi" | 340 | /include/ "qoriq-usb2-mph-0.dtsi" |
341 | usb0: usb@210000 { | 341 | usb0: usb@210000 { |
342 | compatible = "fsl-usb2-mph-v1.6", "fsl,mpc85xx-usb2-mph", "fsl-usb2-mph"; | ||
342 | phy_type = "utmi"; | 343 | phy_type = "utmi"; |
343 | port0; | 344 | port0; |
344 | }; | 345 | }; |
345 | 346 | ||
346 | /include/ "qoriq-usb2-dr-0.dtsi" | 347 | /include/ "qoriq-usb2-dr-0.dtsi" |
347 | usb1: usb@211000 { | 348 | usb1: usb@211000 { |
349 | compatible = "fsl-usb2-dr-v1.6", "fsl,mpc85xx-usb2-dr", "fsl-usb2-dr"; | ||
348 | dr_mode = "host"; | 350 | dr_mode = "host"; |
349 | phy_type = "utmi"; | 351 | phy_type = "utmi"; |
350 | }; | 352 | }; |
diff --git a/arch/powerpc/boot/dts/fsl/pq3-etsec1-0.dtsi b/arch/powerpc/boot/dts/fsl/pq3-etsec1-0.dtsi index a1979ae334a7..3b0650a98478 100644 --- a/arch/powerpc/boot/dts/fsl/pq3-etsec1-0.dtsi +++ b/arch/powerpc/boot/dts/fsl/pq3-etsec1-0.dtsi | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * PQ3 eTSEC device tree stub [ @ offsets 0x24000 ] | 2 | * PQ3 eTSEC device tree stub [ @ offsets 0x24000 ] |
3 | * | 3 | * |
4 | * Copyright 2011 Freescale Semiconductor Inc. | 4 | * Copyright 2011-2012 Freescale Semiconductor Inc. |
5 | * | 5 | * |
6 | * Redistribution and use in source and binary forms, with or without | 6 | * Redistribution and use in source and binary forms, with or without |
7 | * modification, are permitted provided that the following conditions are met: | 7 | * modification, are permitted provided that the following conditions are met: |
@@ -41,6 +41,7 @@ ethernet@24000 { | |||
41 | compatible = "gianfar"; | 41 | compatible = "gianfar"; |
42 | reg = <0x24000 0x1000>; | 42 | reg = <0x24000 0x1000>; |
43 | ranges = <0x0 0x24000 0x1000>; | 43 | ranges = <0x0 0x24000 0x1000>; |
44 | fsl,magic-packet; | ||
44 | local-mac-address = [ 00 00 00 00 00 00 ]; | 45 | local-mac-address = [ 00 00 00 00 00 00 ]; |
45 | interrupts = <29 2 0 0 30 2 0 0 34 2 0 0>; | 46 | interrupts = <29 2 0 0 30 2 0 0 34 2 0 0>; |
46 | }; | 47 | }; |
diff --git a/arch/powerpc/boot/dts/fsl/pq3-etsec1-1.dtsi b/arch/powerpc/boot/dts/fsl/pq3-etsec1-1.dtsi index 4c4fdde1ec2a..96693b41f0f1 100644 --- a/arch/powerpc/boot/dts/fsl/pq3-etsec1-1.dtsi +++ b/arch/powerpc/boot/dts/fsl/pq3-etsec1-1.dtsi | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * PQ3 eTSEC device tree stub [ @ offsets 0x25000 ] | 2 | * PQ3 eTSEC device tree stub [ @ offsets 0x25000 ] |
3 | * | 3 | * |
4 | * Copyright 2011 Freescale Semiconductor Inc. | 4 | * Copyright 2011-2012 Freescale Semiconductor Inc. |
5 | * | 5 | * |
6 | * Redistribution and use in source and binary forms, with or without | 6 | * Redistribution and use in source and binary forms, with or without |
7 | * modification, are permitted provided that the following conditions are met: | 7 | * modification, are permitted provided that the following conditions are met: |
@@ -41,6 +41,7 @@ ethernet@25000 { | |||
41 | compatible = "gianfar"; | 41 | compatible = "gianfar"; |
42 | reg = <0x25000 0x1000>; | 42 | reg = <0x25000 0x1000>; |
43 | ranges = <0x0 0x25000 0x1000>; | 43 | ranges = <0x0 0x25000 0x1000>; |
44 | fsl,magic-packet; | ||
44 | local-mac-address = [ 00 00 00 00 00 00 ]; | 45 | local-mac-address = [ 00 00 00 00 00 00 ]; |
45 | interrupts = <35 2 0 0 36 2 0 0 40 2 0 0>; | 46 | interrupts = <35 2 0 0 36 2 0 0 40 2 0 0>; |
46 | }; | 47 | }; |
diff --git a/arch/powerpc/boot/dts/fsl/pq3-etsec1-2.dtsi b/arch/powerpc/boot/dts/fsl/pq3-etsec1-2.dtsi index 4b8ab438668a..6b3fab19da1f 100644 --- a/arch/powerpc/boot/dts/fsl/pq3-etsec1-2.dtsi +++ b/arch/powerpc/boot/dts/fsl/pq3-etsec1-2.dtsi | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * PQ3 eTSEC device tree stub [ @ offsets 0x26000 ] | 2 | * PQ3 eTSEC device tree stub [ @ offsets 0x26000 ] |
3 | * | 3 | * |
4 | * Copyright 2011 Freescale Semiconductor Inc. | 4 | * Copyright 2011-2012 Freescale Semiconductor Inc. |
5 | * | 5 | * |
6 | * Redistribution and use in source and binary forms, with or without | 6 | * Redistribution and use in source and binary forms, with or without |
7 | * modification, are permitted provided that the following conditions are met: | 7 | * modification, are permitted provided that the following conditions are met: |
@@ -41,6 +41,7 @@ ethernet@26000 { | |||
41 | compatible = "gianfar"; | 41 | compatible = "gianfar"; |
42 | reg = <0x26000 0x1000>; | 42 | reg = <0x26000 0x1000>; |
43 | ranges = <0x0 0x26000 0x1000>; | 43 | ranges = <0x0 0x26000 0x1000>; |
44 | fsl,magic-packet; | ||
44 | local-mac-address = [ 00 00 00 00 00 00 ]; | 45 | local-mac-address = [ 00 00 00 00 00 00 ]; |
45 | interrupts = <31 2 0 0 32 2 0 0 33 2 0 0>; | 46 | interrupts = <31 2 0 0 32 2 0 0 33 2 0 0>; |
46 | }; | 47 | }; |
diff --git a/arch/powerpc/boot/dts/fsl/pq3-etsec1-3.dtsi b/arch/powerpc/boot/dts/fsl/pq3-etsec1-3.dtsi index 40c9137729ae..0da592d93ddd 100644 --- a/arch/powerpc/boot/dts/fsl/pq3-etsec1-3.dtsi +++ b/arch/powerpc/boot/dts/fsl/pq3-etsec1-3.dtsi | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * PQ3 eTSEC device tree stub [ @ offsets 0x27000 ] | 2 | * PQ3 eTSEC device tree stub [ @ offsets 0x27000 ] |
3 | * | 3 | * |
4 | * Copyright 2011 Freescale Semiconductor Inc. | 4 | * Copyright 2011-2012 Freescale Semiconductor Inc. |
5 | * | 5 | * |
6 | * Redistribution and use in source and binary forms, with or without | 6 | * Redistribution and use in source and binary forms, with or without |
7 | * modification, are permitted provided that the following conditions are met: | 7 | * modification, are permitted provided that the following conditions are met: |
@@ -41,6 +41,7 @@ ethernet@27000 { | |||
41 | compatible = "gianfar"; | 41 | compatible = "gianfar"; |
42 | reg = <0x27000 0x1000>; | 42 | reg = <0x27000 0x1000>; |
43 | ranges = <0x0 0x27000 0x1000>; | 43 | ranges = <0x0 0x27000 0x1000>; |
44 | fsl,magic-packet; | ||
44 | local-mac-address = [ 00 00 00 00 00 00 ]; | 45 | local-mac-address = [ 00 00 00 00 00 00 ]; |
45 | interrupts = <37 2 0 0 38 2 0 0 39 2 0 0>; | 46 | interrupts = <37 2 0 0 38 2 0 0 39 2 0 0>; |
46 | }; | 47 | }; |
diff --git a/arch/powerpc/boot/dts/fsl/pq3-mpic.dtsi b/arch/powerpc/boot/dts/fsl/pq3-mpic.dtsi index 5c8046065844..fdedf7b1fe0f 100644 --- a/arch/powerpc/boot/dts/fsl/pq3-mpic.dtsi +++ b/arch/powerpc/boot/dts/fsl/pq3-mpic.dtsi | |||
@@ -39,6 +39,9 @@ mpic: pic@40000 { | |||
39 | reg = <0x40000 0x40000>; | 39 | reg = <0x40000 0x40000>; |
40 | compatible = "fsl,mpic"; | 40 | compatible = "fsl,mpic"; |
41 | device_type = "open-pic"; | 41 | device_type = "open-pic"; |
42 | big-endian; | ||
43 | single-cpu-affinity; | ||
44 | last-interrupt-source = <255>; | ||
42 | }; | 45 | }; |
43 | 46 | ||
44 | timer@41100 { | 47 | timer@41100 { |
diff --git a/arch/powerpc/boot/dts/fsl/pq3-sec4.4-0.dtsi b/arch/powerpc/boot/dts/fsl/pq3-sec4.4-0.dtsi index bf957a7fca2a..d4c9d5daab21 100644 --- a/arch/powerpc/boot/dts/fsl/pq3-sec4.4-0.dtsi +++ b/arch/powerpc/boot/dts/fsl/pq3-sec4.4-0.dtsi | |||
@@ -33,32 +33,32 @@ | |||
33 | */ | 33 | */ |
34 | 34 | ||
35 | crypto@30000 { | 35 | crypto@30000 { |
36 | compatible = "fsl,sec4.4", "fsl,sec4.0"; | 36 | compatible = "fsl,sec-v4.4", "fsl,sec-v4.0"; |
37 | #address-cells = <1>; | 37 | #address-cells = <1>; |
38 | #size-cells = <1>; | 38 | #size-cells = <1>; |
39 | reg = <0x30000 0x10000>; | 39 | reg = <0x30000 0x10000>; |
40 | interrupts = <58 2 0 0>; | 40 | interrupts = <58 2 0 0>; |
41 | 41 | ||
42 | sec_jr0: jr@1000 { | 42 | sec_jr0: jr@1000 { |
43 | compatible = "fsl,sec4.4-job-ring", "fsl,sec4.0-job-ring"; | 43 | compatible = "fsl,sec-v4.4-job-ring", "fsl,sec-v4.0-job-ring"; |
44 | reg = <0x1000 0x1000>; | 44 | reg = <0x1000 0x1000>; |
45 | interrupts = <45 2 0 0>; | 45 | interrupts = <45 2 0 0>; |
46 | }; | 46 | }; |
47 | 47 | ||
48 | sec_jr1: jr@2000 { | 48 | sec_jr1: jr@2000 { |
49 | compatible = "fsl,sec4.4-job-ring", "fsl,sec4.0-job-ring"; | 49 | compatible = "fsl,sec-v4.4-job-ring", "fsl,sec-v4.0-job-ring"; |
50 | reg = <0x2000 0x1000>; | 50 | reg = <0x2000 0x1000>; |
51 | interrupts = <45 2 0 0>; | 51 | interrupts = <45 2 0 0>; |
52 | }; | 52 | }; |
53 | 53 | ||
54 | sec_jr2: jr@3000 { | 54 | sec_jr2: jr@3000 { |
55 | compatible = "fsl,sec4.4-job-ring", "fsl,sec4.0-job-ring"; | 55 | compatible = "fsl,sec-v4.4-job-ring", "fsl,sec-v4.0-job-ring"; |
56 | reg = <0x3000 0x1000>; | 56 | reg = <0x3000 0x1000>; |
57 | interrupts = <45 2 0 0>; | 57 | interrupts = <45 2 0 0>; |
58 | }; | 58 | }; |
59 | 59 | ||
60 | sec_jr3: jr@4000 { | 60 | sec_jr3: jr@4000 { |
61 | compatible = "fsl,sec4.4-job-ring", "fsl,sec4.0-job-ring"; | 61 | compatible = "fsl,sec-v4.4-job-ring", "fsl,sec-v4.0-job-ring"; |
62 | reg = <0x4000 0x1000>; | 62 | reg = <0x4000 0x1000>; |
63 | interrupts = <45 2 0 0>; | 63 | interrupts = <45 2 0 0>; |
64 | }; | 64 | }; |
diff --git a/arch/powerpc/boot/dts/fsl/qoriq-mpic.dtsi b/arch/powerpc/boot/dts/fsl/qoriq-mpic.dtsi index b9bada6a87dc..08f42271f86a 100644 --- a/arch/powerpc/boot/dts/fsl/qoriq-mpic.dtsi +++ b/arch/powerpc/boot/dts/fsl/qoriq-mpic.dtsi | |||
@@ -53,7 +53,7 @@ timer@41100 { | |||
53 | 53 | ||
54 | msi0: msi@41600 { | 54 | msi0: msi@41600 { |
55 | compatible = "fsl,mpic-msi"; | 55 | compatible = "fsl,mpic-msi"; |
56 | reg = <0x41600 0x200>; | 56 | reg = <0x41600 0x200 0x44140 4>; |
57 | msi-available-ranges = <0 0x100>; | 57 | msi-available-ranges = <0 0x100>; |
58 | interrupts = < | 58 | interrupts = < |
59 | 0xe0 0 0 0 | 59 | 0xe0 0 0 0 |
@@ -68,7 +68,7 @@ msi0: msi@41600 { | |||
68 | 68 | ||
69 | msi1: msi@41800 { | 69 | msi1: msi@41800 { |
70 | compatible = "fsl,mpic-msi"; | 70 | compatible = "fsl,mpic-msi"; |
71 | reg = <0x41800 0x200>; | 71 | reg = <0x41800 0x200 0x45140 4>; |
72 | msi-available-ranges = <0 0x100>; | 72 | msi-available-ranges = <0 0x100>; |
73 | interrupts = < | 73 | interrupts = < |
74 | 0xe8 0 0 0 | 74 | 0xe8 0 0 0 |
@@ -83,7 +83,7 @@ msi1: msi@41800 { | |||
83 | 83 | ||
84 | msi2: msi@41a00 { | 84 | msi2: msi@41a00 { |
85 | compatible = "fsl,mpic-msi"; | 85 | compatible = "fsl,mpic-msi"; |
86 | reg = <0x41a00 0x200>; | 86 | reg = <0x41a00 0x200 0x46140 4>; |
87 | msi-available-ranges = <0 0x100>; | 87 | msi-available-ranges = <0 0x100>; |
88 | interrupts = < | 88 | interrupts = < |
89 | 0xf0 0 0 0 | 89 | 0xf0 0 0 0 |
diff --git a/arch/powerpc/boot/dts/ge_imp3a.dts b/arch/powerpc/boot/dts/ge_imp3a.dts new file mode 100644 index 000000000000..fefae416a097 --- /dev/null +++ b/arch/powerpc/boot/dts/ge_imp3a.dts | |||
@@ -0,0 +1,255 @@ | |||
1 | /* | ||
2 | * GE IMP3A Device Tree Source | ||
3 | * | ||
4 | * Copyright 2010-2011 GE Intelligent Platforms Embedded Systems, 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 | * Based on: P2020 DS Device Tree Source | ||
12 | * Copyright 2009 Freescale Semiconductor Inc. | ||
13 | */ | ||
14 | |||
15 | /include/ "fsl/p2020si-pre.dtsi" | ||
16 | |||
17 | / { | ||
18 | model = "GE_IMP3A"; | ||
19 | compatible = "ge,imp3a"; | ||
20 | |||
21 | memory { | ||
22 | device_type = "memory"; | ||
23 | }; | ||
24 | |||
25 | lbc: localbus@fef05000 { | ||
26 | reg = <0 0xfef05000 0 0x1000>; | ||
27 | |||
28 | ranges = <0x0 0x0 0x0 0xff000000 0x01000000 | ||
29 | 0x1 0x0 0x0 0xe0000000 0x08000000 | ||
30 | 0x2 0x0 0x0 0xe8000000 0x08000000 | ||
31 | 0x3 0x0 0x0 0xfc100000 0x00020000 | ||
32 | 0x4 0x0 0x0 0xfc000000 0x00008000 | ||
33 | 0x5 0x0 0x0 0xfc008000 0x00008000 | ||
34 | 0x6 0x0 0x0 0xfee00000 0x00040000 | ||
35 | 0x7 0x0 0x0 0xfee80000 0x00040000>; | ||
36 | |||
37 | /* nor@0,0 is a mirror of part of the memory in nor@1,0 | ||
38 | nor@0,0 { | ||
39 | #address-cells = <1>; | ||
40 | #size-cells = <1>; | ||
41 | compatible = "ge,imp3a-firmware-mirror", "cfi-flash"; | ||
42 | reg = <0x0 0x0 0x1000000>; | ||
43 | bank-width = <2>; | ||
44 | device-width = <1>; | ||
45 | |||
46 | partition@0 { | ||
47 | label = "firmware"; | ||
48 | reg = <0x0 0x1000000>; | ||
49 | read-only; | ||
50 | }; | ||
51 | }; | ||
52 | */ | ||
53 | |||
54 | nor@1,0 { | ||
55 | #address-cells = <1>; | ||
56 | #size-cells = <1>; | ||
57 | compatible = "ge,imp3a-paged-flash", "cfi-flash"; | ||
58 | reg = <0x1 0x0 0x8000000>; | ||
59 | bank-width = <2>; | ||
60 | device-width = <1>; | ||
61 | |||
62 | partition@0 { | ||
63 | label = "user"; | ||
64 | reg = <0x0 0x7800000>; | ||
65 | }; | ||
66 | |||
67 | partition@7800000 { | ||
68 | label = "firmware"; | ||
69 | reg = <0x7800000 0x800000>; | ||
70 | read-only; | ||
71 | }; | ||
72 | }; | ||
73 | |||
74 | nvram@3,0 { | ||
75 | device_type = "nvram"; | ||
76 | compatible = "simtek,stk14ca8"; | ||
77 | reg = <0x3 0x0 0x20000>; | ||
78 | }; | ||
79 | |||
80 | fpga@4,0 { | ||
81 | compatible = "ge,imp3a-fpga-regs"; | ||
82 | reg = <0x4 0x0 0x20>; | ||
83 | }; | ||
84 | |||
85 | gef_pic: pic@4,20 { | ||
86 | #interrupt-cells = <1>; | ||
87 | interrupt-controller; | ||
88 | device_type = "interrupt-controller"; | ||
89 | compatible = "ge,imp3a-fpga-pic", "gef,fpga-pic-1.00"; | ||
90 | reg = <0x4 0x20 0x20>; | ||
91 | interrupts = <6 7 0 0>; | ||
92 | }; | ||
93 | |||
94 | gef_gpio: gpio@4,400 { | ||
95 | #gpio-cells = <2>; | ||
96 | compatible = "ge,imp3a-gpio"; | ||
97 | reg = <0x4 0x400 0x24>; | ||
98 | gpio-controller; | ||
99 | }; | ||
100 | |||
101 | wdt@4,800 { | ||
102 | compatible = "ge,imp3a-fpga-wdt", "gef,fpga-wdt-1.00", | ||
103 | "gef,fpga-wdt"; | ||
104 | reg = <0x4 0x800 0x8>; | ||
105 | interrupts = <10 4>; | ||
106 | interrupt-parent = <&gef_pic>; | ||
107 | }; | ||
108 | |||
109 | /* Second watchdog available, driver currently supports one. | ||
110 | wdt@4,808 { | ||
111 | compatible = "gef,imp3a-fpga-wdt", "gef,fpga-wdt-1.00", | ||
112 | "gef,fpga-wdt"; | ||
113 | reg = <0x4 0x808 0x8>; | ||
114 | interrupts = <9 4>; | ||
115 | interrupt-parent = <&gef_pic>; | ||
116 | }; | ||
117 | */ | ||
118 | |||
119 | nand@6,0 { | ||
120 | compatible = "fsl,elbc-fcm-nand"; | ||
121 | reg = <0x6 0x0 0x40000>; | ||
122 | }; | ||
123 | |||
124 | nand@7,0 { | ||
125 | compatible = "fsl,elbc-fcm-nand"; | ||
126 | reg = <0x7 0x0 0x40000>; | ||
127 | }; | ||
128 | }; | ||
129 | |||
130 | soc: soc@fef00000 { | ||
131 | ranges = <0x0 0 0xfef00000 0x100000>; | ||
132 | |||
133 | i2c@3000 { | ||
134 | hwmon@48 { | ||
135 | compatible = "national,lm92"; | ||
136 | reg = <0x48>; | ||
137 | }; | ||
138 | |||
139 | hwmon@4c { | ||
140 | compatible = "adi,adt7461"; | ||
141 | reg = <0x4c>; | ||
142 | }; | ||
143 | |||
144 | rtc@51 { | ||
145 | compatible = "epson,rx8581"; | ||
146 | reg = <0x51>; | ||
147 | }; | ||
148 | |||
149 | eti@6b { | ||
150 | compatible = "dallas,ds1682"; | ||
151 | reg = <0x6b>; | ||
152 | }; | ||
153 | }; | ||
154 | |||
155 | usb@22000 { | ||
156 | phy_type = "ulpi"; | ||
157 | dr_mode = "host"; | ||
158 | }; | ||
159 | |||
160 | mdio@24520 { | ||
161 | phy0: ethernet-phy@0 { | ||
162 | interrupt-parent = <&gef_pic>; | ||
163 | interrupts = <0xc 0x4>; | ||
164 | reg = <0x1>; | ||
165 | }; | ||
166 | phy1: ethernet-phy@1 { | ||
167 | interrupt-parent = <&gef_pic>; | ||
168 | interrupts = <0xb 0x4>; | ||
169 | reg = <0x2>; | ||
170 | }; | ||
171 | tbi0: tbi-phy@11 { | ||
172 | reg = <0x11>; | ||
173 | device_type = "tbi-phy"; | ||
174 | }; | ||
175 | }; | ||
176 | |||
177 | mdio@25520 { | ||
178 | tbi1: tbi-phy@11 { | ||
179 | reg = <0x11>; | ||
180 | device_type = "tbi-phy"; | ||
181 | }; | ||
182 | }; | ||
183 | |||
184 | mdio@26520 { | ||
185 | status = "disabled"; | ||
186 | }; | ||
187 | |||
188 | enet0: ethernet@24000 { | ||
189 | tbi-handle = <&tbi0>; | ||
190 | phy-handle = <&phy0>; | ||
191 | phy-connection-type = "gmii"; | ||
192 | }; | ||
193 | |||
194 | enet1: ethernet@25000 { | ||
195 | tbi-handle = <&tbi1>; | ||
196 | phy-handle = <&phy1>; | ||
197 | phy-connection-type = "gmii"; | ||
198 | }; | ||
199 | |||
200 | enet2: ethernet@26000 { | ||
201 | status = "disabled"; | ||
202 | }; | ||
203 | }; | ||
204 | |||
205 | pci0: pcie@fef08000 { | ||
206 | ranges = <0x2000000 0x0 0xc0000000 0 0xc0000000 0x0 0x20000000 | ||
207 | 0x1000000 0x0 0x00000000 0 0xfe020000 0x0 0x10000>; | ||
208 | reg = <0 0xfef08000 0 0x1000>; | ||
209 | |||
210 | pcie@0 { | ||
211 | ranges = <0x2000000 0x0 0xc0000000 | ||
212 | 0x2000000 0x0 0xc0000000 | ||
213 | 0x0 0x20000000 | ||
214 | |||
215 | 0x1000000 0x0 0x0 | ||
216 | 0x1000000 0x0 0x0 | ||
217 | 0x0 0x10000>; | ||
218 | }; | ||
219 | }; | ||
220 | |||
221 | pci1: pcie@fef09000 { | ||
222 | reg = <0 0xfef09000 0 0x1000>; | ||
223 | ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000 | ||
224 | 0x1000000 0x0 0x00000000 0 0xfe010000 0x0 0x10000>; | ||
225 | |||
226 | pcie@0 { | ||
227 | ranges = <0x2000000 0x0 0xa0000000 | ||
228 | 0x2000000 0x0 0xa0000000 | ||
229 | 0x0 0x20000000 | ||
230 | |||
231 | 0x1000000 0x0 0x0 | ||
232 | 0x1000000 0x0 0x0 | ||
233 | 0x0 0x10000>; | ||
234 | }; | ||
235 | |||
236 | }; | ||
237 | |||
238 | pci2: pcie@fef0a000 { | ||
239 | reg = <0 0xfef0a000 0 0x1000>; | ||
240 | ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000 | ||
241 | 0x1000000 0x0 0x00000000 0 0xfe000000 0x0 0x10000>; | ||
242 | |||
243 | pcie@0 { | ||
244 | ranges = <0x2000000 0x0 0x80000000 | ||
245 | 0x2000000 0x0 0x80000000 | ||
246 | 0x0 0x20000000 | ||
247 | |||
248 | 0x1000000 0x0 0x0 | ||
249 | 0x1000000 0x0 0x0 | ||
250 | 0x0 0x10000>; | ||
251 | }; | ||
252 | }; | ||
253 | }; | ||
254 | |||
255 | /include/ "fsl/p2020si-post.dtsi" | ||
diff --git a/arch/powerpc/boot/dts/mpc836x_mds.dts b/arch/powerpc/boot/dts/mpc836x_mds.dts index c0e450a551bf..81dd513d6308 100644 --- a/arch/powerpc/boot/dts/mpc836x_mds.dts +++ b/arch/powerpc/boot/dts/mpc836x_mds.dts | |||
@@ -405,6 +405,10 @@ | |||
405 | reg = <0x1>; | 405 | reg = <0x1>; |
406 | device_type = "ethernet-phy"; | 406 | device_type = "ethernet-phy"; |
407 | }; | 407 | }; |
408 | tbi-phy@2 { | ||
409 | device_type = "tbi-phy"; | ||
410 | reg = <0x2>; | ||
411 | }; | ||
408 | }; | 412 | }; |
409 | 413 | ||
410 | qeic: interrupt-controller@80 { | 414 | qeic: interrupt-controller@80 { |
diff --git a/arch/powerpc/boot/dts/mpc8536ds.dts b/arch/powerpc/boot/dts/mpc8536ds.dts index c15881574fdc..19736222a0b9 100644 --- a/arch/powerpc/boot/dts/mpc8536ds.dts +++ b/arch/powerpc/boot/dts/mpc8536ds.dts | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * MPC8536 DS Device Tree Source | 2 | * MPC8536 DS Device Tree Source |
3 | * | 3 | * |
4 | * Copyright 2008 Freescale Semiconductor, Inc. | 4 | * Copyright 2008, 2011 Freescale Semiconductor, Inc. |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify it | 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 | 7 | * under the terms of the GNU General Public License as published by the |
@@ -34,6 +34,10 @@ | |||
34 | 34 | ||
35 | lbc: localbus@ffe05000 { | 35 | lbc: localbus@ffe05000 { |
36 | reg = <0 0xffe05000 0 0x1000>; | 36 | reg = <0 0xffe05000 0 0x1000>; |
37 | |||
38 | ranges = <0x0 0x0 0x0 0xe8000000 0x08000000 | ||
39 | 0x2 0x0 0x0 0xffa00000 0x00040000 | ||
40 | 0x3 0x0 0x0 0xffdf0000 0x00008000>; | ||
37 | }; | 41 | }; |
38 | 42 | ||
39 | board_soc: soc: soc@ffe00000 { | 43 | board_soc: soc: soc@ffe00000 { |
diff --git a/arch/powerpc/boot/dts/mpc8536ds.dtsi b/arch/powerpc/boot/dts/mpc8536ds.dtsi index 1462e4cf49d7..cc46dbd9746d 100644 --- a/arch/powerpc/boot/dts/mpc8536ds.dtsi +++ b/arch/powerpc/boot/dts/mpc8536ds.dtsi | |||
@@ -32,6 +32,99 @@ | |||
32 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 32 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
33 | */ | 33 | */ |
34 | 34 | ||
35 | &lbc { | ||
36 | nor@0,0 { | ||
37 | #address-cells = <1>; | ||
38 | #size-cells = <1>; | ||
39 | compatible = "cfi-flash"; | ||
40 | reg = <0x0 0x0 0x8000000>; | ||
41 | bank-width = <2>; | ||
42 | device-width = <1>; | ||
43 | |||
44 | partition@0 { | ||
45 | reg = <0x0 0x03000000>; | ||
46 | label = "ramdisk-nor"; | ||
47 | }; | ||
48 | |||
49 | partition@3000000 { | ||
50 | reg = <0x03000000 0x00e00000>; | ||
51 | label = "diagnostic-nor"; | ||
52 | read-only; | ||
53 | }; | ||
54 | |||
55 | partition@3e00000 { | ||
56 | reg = <0x03e00000 0x00200000>; | ||
57 | label = "dink-nor"; | ||
58 | read-only; | ||
59 | }; | ||
60 | |||
61 | partition@4000000 { | ||
62 | reg = <0x04000000 0x00400000>; | ||
63 | label = "kernel-nor"; | ||
64 | }; | ||
65 | |||
66 | partition@4400000 { | ||
67 | reg = <0x04400000 0x03b00000>; | ||
68 | label = "fs-nor"; | ||
69 | }; | ||
70 | |||
71 | partition@7f00000 { | ||
72 | reg = <0x07f00000 0x00080000>; | ||
73 | label = "dtb-nor"; | ||
74 | }; | ||
75 | |||
76 | partition@7f80000 { | ||
77 | reg = <0x07f80000 0x00080000>; | ||
78 | label = "u-boot-nor"; | ||
79 | read-only; | ||
80 | }; | ||
81 | }; | ||
82 | |||
83 | nand@2,0 { | ||
84 | #address-cells = <1>; | ||
85 | #size-cells = <1>; | ||
86 | compatible = "fsl,mpc8536-fcm-nand", | ||
87 | "fsl,elbc-fcm-nand"; | ||
88 | reg = <0x2 0x0 0x40000>; | ||
89 | |||
90 | partition@0 { | ||
91 | reg = <0x0 0x02000000>; | ||
92 | label = "u-boot-nand"; | ||
93 | read-only; | ||
94 | }; | ||
95 | |||
96 | partition@2000000 { | ||
97 | reg = <0x02000000 0x10000000>; | ||
98 | label = "fs-nand"; | ||
99 | }; | ||
100 | |||
101 | partition@12000000 { | ||
102 | reg = <0x12000000 0x08000000>; | ||
103 | label = "ramdisk-nand"; | ||
104 | }; | ||
105 | |||
106 | partition@1a000000 { | ||
107 | reg = <0x1a000000 0x04000000>; | ||
108 | label = "kernel-nand"; | ||
109 | }; | ||
110 | |||
111 | partition@1e000000 { | ||
112 | reg = <0x1e000000 0x01000000>; | ||
113 | label = "dtb-nand"; | ||
114 | }; | ||
115 | |||
116 | partition@1f000000 { | ||
117 | reg = <0x1f000000 0x21000000>; | ||
118 | label = "empty-nand"; | ||
119 | }; | ||
120 | }; | ||
121 | |||
122 | board-control@3,0 { | ||
123 | compatible = "fsl,mpc8536ds-fpga-pixis"; | ||
124 | reg = <0x3 0x0 0x8000>; | ||
125 | }; | ||
126 | }; | ||
127 | |||
35 | &board_soc { | 128 | &board_soc { |
36 | i2c@3100 { | 129 | i2c@3100 { |
37 | rtc@68 { | 130 | rtc@68 { |
diff --git a/arch/powerpc/boot/dts/mpc8536ds_36b.dts b/arch/powerpc/boot/dts/mpc8536ds_36b.dts index 8f4b929b1d1d..f8a3b3413176 100644 --- a/arch/powerpc/boot/dts/mpc8536ds_36b.dts +++ b/arch/powerpc/boot/dts/mpc8536ds_36b.dts | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * MPC8536DS Device Tree Source (36-bit address map) | 2 | * MPC8536DS Device Tree Source (36-bit address map) |
3 | * | 3 | * |
4 | * Copyright 2008-2009 Freescale Semiconductor, Inc. | 4 | * Copyright 2008-2009, 2011 Freescale Semiconductor, Inc. |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify it | 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 | 7 | * under the terms of the GNU General Public License as published by the |
@@ -33,7 +33,11 @@ | |||
33 | }; | 33 | }; |
34 | 34 | ||
35 | lbc: localbus@ffe05000 { | 35 | lbc: localbus@ffe05000 { |
36 | reg = <0 0xffe05000 0 0x1000>; | 36 | reg = <0xf 0xffe05000 0 0x1000>; |
37 | |||
38 | ranges = <0x0 0x0 0xf 0xe8000000 0x08000000 | ||
39 | 0x2 0x0 0xf 0xffa00000 0x00040000 | ||
40 | 0x3 0x0 0xf 0xffdf0000 0x00008000>; | ||
37 | }; | 41 | }; |
38 | 42 | ||
39 | board_soc: soc: soc@fffe00000 { | 43 | board_soc: soc: soc@fffe00000 { |
diff --git a/arch/powerpc/boot/dts/mpc8548cds.dts b/arch/powerpc/boot/dts/mpc8548cds.dts deleted file mode 100644 index 07b8dae0f46e..000000000000 --- a/arch/powerpc/boot/dts/mpc8548cds.dts +++ /dev/null | |||
@@ -1,306 +0,0 @@ | |||
1 | /* | ||
2 | * MPC8548 CDS Device Tree Source | ||
3 | * | ||
4 | * Copyright 2006, 2008 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 | /include/ "fsl/mpc8548si-pre.dtsi" | ||
13 | |||
14 | / { | ||
15 | model = "MPC8548CDS"; | ||
16 | compatible = "MPC8548CDS", "MPC85xxCDS"; | ||
17 | |||
18 | aliases { | ||
19 | ethernet0 = &enet0; | ||
20 | ethernet1 = &enet1; | ||
21 | ethernet2 = &enet2; | ||
22 | ethernet3 = &enet3; | ||
23 | serial0 = &serial0; | ||
24 | serial1 = &serial1; | ||
25 | pci0 = &pci0; | ||
26 | pci1 = &pci1; | ||
27 | pci2 = &pci2; | ||
28 | }; | ||
29 | |||
30 | memory { | ||
31 | device_type = "memory"; | ||
32 | reg = <0 0 0x0 0x8000000>; // 128M at 0x0 | ||
33 | }; | ||
34 | |||
35 | lbc: localbus@e0005000 { | ||
36 | reg = <0 0xe0005000 0 0x1000>; | ||
37 | }; | ||
38 | |||
39 | soc: soc8548@e0000000 { | ||
40 | ranges = <0 0x0 0xe0000000 0x100000>; | ||
41 | |||
42 | i2c@3000 { | ||
43 | eeprom@50 { | ||
44 | compatible = "atmel,24c64"; | ||
45 | reg = <0x50>; | ||
46 | }; | ||
47 | |||
48 | eeprom@56 { | ||
49 | compatible = "atmel,24c64"; | ||
50 | reg = <0x56>; | ||
51 | }; | ||
52 | |||
53 | eeprom@57 { | ||
54 | compatible = "atmel,24c64"; | ||
55 | reg = <0x57>; | ||
56 | }; | ||
57 | }; | ||
58 | |||
59 | i2c@3100 { | ||
60 | eeprom@50 { | ||
61 | compatible = "atmel,24c64"; | ||
62 | reg = <0x50>; | ||
63 | }; | ||
64 | }; | ||
65 | |||
66 | enet0: ethernet@24000 { | ||
67 | tbi-handle = <&tbi0>; | ||
68 | phy-handle = <&phy0>; | ||
69 | }; | ||
70 | |||
71 | mdio@24520 { | ||
72 | phy0: ethernet-phy@0 { | ||
73 | interrupts = <5 1 0 0>; | ||
74 | reg = <0x0>; | ||
75 | device_type = "ethernet-phy"; | ||
76 | }; | ||
77 | phy1: ethernet-phy@1 { | ||
78 | interrupts = <5 1 0 0>; | ||
79 | reg = <0x1>; | ||
80 | device_type = "ethernet-phy"; | ||
81 | }; | ||
82 | phy2: ethernet-phy@2 { | ||
83 | interrupts = <5 1 0 0>; | ||
84 | reg = <0x2>; | ||
85 | device_type = "ethernet-phy"; | ||
86 | }; | ||
87 | phy3: ethernet-phy@3 { | ||
88 | interrupts = <5 1 0 0>; | ||
89 | reg = <0x3>; | ||
90 | device_type = "ethernet-phy"; | ||
91 | }; | ||
92 | tbi0: tbi-phy@11 { | ||
93 | reg = <0x11>; | ||
94 | device_type = "tbi-phy"; | ||
95 | }; | ||
96 | }; | ||
97 | |||
98 | enet1: ethernet@25000 { | ||
99 | tbi-handle = <&tbi1>; | ||
100 | phy-handle = <&phy1>; | ||
101 | }; | ||
102 | |||
103 | mdio@25520 { | ||
104 | tbi1: tbi-phy@11 { | ||
105 | reg = <0x11>; | ||
106 | device_type = "tbi-phy"; | ||
107 | }; | ||
108 | }; | ||
109 | |||
110 | enet2: ethernet@26000 { | ||
111 | tbi-handle = <&tbi2>; | ||
112 | phy-handle = <&phy2>; | ||
113 | }; | ||
114 | |||
115 | mdio@26520 { | ||
116 | tbi2: tbi-phy@11 { | ||
117 | reg = <0x11>; | ||
118 | device_type = "tbi-phy"; | ||
119 | }; | ||
120 | }; | ||
121 | |||
122 | enet3: ethernet@27000 { | ||
123 | tbi-handle = <&tbi3>; | ||
124 | phy-handle = <&phy3>; | ||
125 | }; | ||
126 | |||
127 | mdio@27520 { | ||
128 | tbi3: tbi-phy@11 { | ||
129 | reg = <0x11>; | ||
130 | device_type = "tbi-phy"; | ||
131 | }; | ||
132 | }; | ||
133 | }; | ||
134 | |||
135 | pci0: pci@e0008000 { | ||
136 | reg = <0 0xe0008000 0 0x1000>; | ||
137 | ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x10000000 | ||
138 | 0x1000000 0x0 0x00000000 0 0xe2000000 0x0 0x800000>; | ||
139 | clock-frequency = <66666666>; | ||
140 | interrupt-map-mask = <0xf800 0x0 0x0 0x7>; | ||
141 | interrupt-map = < | ||
142 | /* IDSEL 0x4 (PCIX Slot 2) */ | ||
143 | 0x2000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 | ||
144 | 0x2000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 | ||
145 | 0x2000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 | ||
146 | 0x2000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0 | ||
147 | |||
148 | /* IDSEL 0x5 (PCIX Slot 3) */ | ||
149 | 0x2800 0x0 0x0 0x1 &mpic 0x1 0x1 0 0 | ||
150 | 0x2800 0x0 0x0 0x2 &mpic 0x2 0x1 0 0 | ||
151 | 0x2800 0x0 0x0 0x3 &mpic 0x3 0x1 0 0 | ||
152 | 0x2800 0x0 0x0 0x4 &mpic 0x0 0x1 0 0 | ||
153 | |||
154 | /* IDSEL 0x6 (PCIX Slot 4) */ | ||
155 | 0x3000 0x0 0x0 0x1 &mpic 0x2 0x1 0 0 | ||
156 | 0x3000 0x0 0x0 0x2 &mpic 0x3 0x1 0 0 | ||
157 | 0x3000 0x0 0x0 0x3 &mpic 0x0 0x1 0 0 | ||
158 | 0x3000 0x0 0x0 0x4 &mpic 0x1 0x1 0 0 | ||
159 | |||
160 | /* IDSEL 0x8 (PCIX Slot 5) */ | ||
161 | 0x4000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 | ||
162 | 0x4000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 | ||
163 | 0x4000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 | ||
164 | 0x4000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0 | ||
165 | |||
166 | /* IDSEL 0xC (Tsi310 bridge) */ | ||
167 | 0x6000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 | ||
168 | 0x6000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 | ||
169 | 0x6000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 | ||
170 | 0x6000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0 | ||
171 | |||
172 | /* IDSEL 0x14 (Slot 2) */ | ||
173 | 0xa000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 | ||
174 | 0xa000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 | ||
175 | 0xa000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 | ||
176 | 0xa000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0 | ||
177 | |||
178 | /* IDSEL 0x15 (Slot 3) */ | ||
179 | 0xa800 0x0 0x0 0x1 &mpic 0x1 0x1 0 0 | ||
180 | 0xa800 0x0 0x0 0x2 &mpic 0x2 0x1 0 0 | ||
181 | 0xa800 0x0 0x0 0x3 &mpic 0x3 0x1 0 0 | ||
182 | 0xa800 0x0 0x0 0x4 &mpic 0x0 0x1 0 0 | ||
183 | |||
184 | /* IDSEL 0x16 (Slot 4) */ | ||
185 | 0xb000 0x0 0x0 0x1 &mpic 0x2 0x1 0 0 | ||
186 | 0xb000 0x0 0x0 0x2 &mpic 0x3 0x1 0 0 | ||
187 | 0xb000 0x0 0x0 0x3 &mpic 0x0 0x1 0 0 | ||
188 | 0xb000 0x0 0x0 0x4 &mpic 0x1 0x1 0 0 | ||
189 | |||
190 | /* IDSEL 0x18 (Slot 5) */ | ||
191 | 0xc000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 | ||
192 | 0xc000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 | ||
193 | 0xc000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 | ||
194 | 0xc000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0 | ||
195 | |||
196 | /* IDSEL 0x1C (Tsi310 bridge PCI primary) */ | ||
197 | 0xe000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 | ||
198 | 0xe000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 | ||
199 | 0xe000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 | ||
200 | 0xe000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0>; | ||
201 | |||
202 | pci_bridge@1c { | ||
203 | interrupt-map-mask = <0xf800 0x0 0x0 0x7>; | ||
204 | interrupt-map = < | ||
205 | |||
206 | /* IDSEL 0x00 (PrPMC Site) */ | ||
207 | 0000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 | ||
208 | 0000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 | ||
209 | 0000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 | ||
210 | 0000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0 | ||
211 | |||
212 | /* IDSEL 0x04 (VIA chip) */ | ||
213 | 0x2000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 | ||
214 | 0x2000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 | ||
215 | 0x2000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 | ||
216 | 0x2000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0 | ||
217 | |||
218 | /* IDSEL 0x05 (8139) */ | ||
219 | 0x2800 0x0 0x0 0x1 &mpic 0x1 0x1 0 0 | ||
220 | |||
221 | /* IDSEL 0x06 (Slot 6) */ | ||
222 | 0x3000 0x0 0x0 0x1 &mpic 0x2 0x1 0 0 | ||
223 | 0x3000 0x0 0x0 0x2 &mpic 0x3 0x1 0 0 | ||
224 | 0x3000 0x0 0x0 0x3 &mpic 0x0 0x1 0 0 | ||
225 | 0x3000 0x0 0x0 0x4 &mpic 0x1 0x1 0 0 | ||
226 | |||
227 | /* IDESL 0x07 (Slot 7) */ | ||
228 | 0x3800 0x0 0x0 0x1 &mpic 0x3 0x1 0 0 | ||
229 | 0x3800 0x0 0x0 0x2 &mpic 0x0 0x1 0 0 | ||
230 | 0x3800 0x0 0x0 0x3 &mpic 0x1 0x1 0 0 | ||
231 | 0x3800 0x0 0x0 0x4 &mpic 0x2 0x1 0 0>; | ||
232 | |||
233 | reg = <0xe000 0x0 0x0 0x0 0x0>; | ||
234 | #interrupt-cells = <1>; | ||
235 | #size-cells = <2>; | ||
236 | #address-cells = <3>; | ||
237 | ranges = <0x2000000 0x0 0x80000000 | ||
238 | 0x2000000 0x0 0x80000000 | ||
239 | 0x0 0x20000000 | ||
240 | 0x1000000 0x0 0x0 | ||
241 | 0x1000000 0x0 0x0 | ||
242 | 0x0 0x80000>; | ||
243 | clock-frequency = <33333333>; | ||
244 | |||
245 | isa@4 { | ||
246 | device_type = "isa"; | ||
247 | #interrupt-cells = <2>; | ||
248 | #size-cells = <1>; | ||
249 | #address-cells = <2>; | ||
250 | reg = <0x2000 0x0 0x0 0x0 0x0>; | ||
251 | ranges = <0x1 0x0 0x1000000 0x0 0x0 0x1000>; | ||
252 | interrupt-parent = <&i8259>; | ||
253 | |||
254 | i8259: interrupt-controller@20 { | ||
255 | interrupt-controller; | ||
256 | device_type = "interrupt-controller"; | ||
257 | reg = <0x1 0x20 0x2 | ||
258 | 0x1 0xa0 0x2 | ||
259 | 0x1 0x4d0 0x2>; | ||
260 | #address-cells = <0>; | ||
261 | #interrupt-cells = <2>; | ||
262 | compatible = "chrp,iic"; | ||
263 | interrupts = <0 1 0 0>; | ||
264 | interrupt-parent = <&mpic>; | ||
265 | }; | ||
266 | |||
267 | rtc@70 { | ||
268 | compatible = "pnpPNP,b00"; | ||
269 | reg = <0x1 0x70 0x2>; | ||
270 | }; | ||
271 | }; | ||
272 | }; | ||
273 | }; | ||
274 | |||
275 | pci1: pci@e0009000 { | ||
276 | reg = <0 0xe0009000 0 0x1000>; | ||
277 | ranges = <0x2000000 0x0 0x90000000 0 0x90000000 0x0 0x10000000 | ||
278 | 0x1000000 0x0 0x00000000 0 0xe2800000 0x0 0x800000>; | ||
279 | clock-frequency = <66666666>; | ||
280 | interrupt-map-mask = <0xf800 0x0 0x0 0x7>; | ||
281 | interrupt-map = < | ||
282 | |||
283 | /* IDSEL 0x15 */ | ||
284 | 0xa800 0x0 0x0 0x1 &mpic 0xb 0x1 0 0 | ||
285 | 0xa800 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 | ||
286 | 0xa800 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 | ||
287 | 0xa800 0x0 0x0 0x4 &mpic 0x3 0x1 0 0>; | ||
288 | }; | ||
289 | |||
290 | pci2: pcie@e000a000 { | ||
291 | reg = <0 0xe000a000 0 0x1000>; | ||
292 | ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000 | ||
293 | 0x1000000 0x0 0x00000000 0 0xe3000000 0x0 0x100000>; | ||
294 | pcie@0 { | ||
295 | ranges = <0x2000000 0x0 0xa0000000 | ||
296 | 0x2000000 0x0 0xa0000000 | ||
297 | 0x0 0x20000000 | ||
298 | |||
299 | 0x1000000 0x0 0x0 | ||
300 | 0x1000000 0x0 0x0 | ||
301 | 0x0 0x100000>; | ||
302 | }; | ||
303 | }; | ||
304 | }; | ||
305 | |||
306 | /include/ "fsl/mpc8548si-post.dtsi" | ||
diff --git a/arch/powerpc/boot/dts/mpc8548cds.dtsi b/arch/powerpc/boot/dts/mpc8548cds.dtsi new file mode 100644 index 000000000000..c61f525e4740 --- /dev/null +++ b/arch/powerpc/boot/dts/mpc8548cds.dtsi | |||
@@ -0,0 +1,306 @@ | |||
1 | /* | ||
2 | * MPC8548CDS Device Tree Source stub (no addresses or top-level ranges) | ||
3 | * | ||
4 | * Copyright 2012 Freescale Semiconductor Inc. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions are met: | ||
8 | * * Redistributions of source code must retain the above copyright | ||
9 | * notice, this list of conditions and the following disclaimer. | ||
10 | * * Redistributions in binary form must reproduce the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer in the | ||
12 | * documentation and/or other materials provided with the distribution. | ||
13 | * * Neither the name of Freescale Semiconductor nor the | ||
14 | * names of its contributors may be used to endorse or promote products | ||
15 | * derived from this software without specific prior written permission. | ||
16 | * | ||
17 | * | ||
18 | * ALTERNATIVELY, this software may be distributed under the terms of the | ||
19 | * GNU General Public License ("GPL") as published by the Free Software | ||
20 | * Foundation, either version 2 of that License or (at your option) any | ||
21 | * later version. | ||
22 | * | ||
23 | * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY | ||
24 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
26 | * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY | ||
27 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
28 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
29 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
30 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
32 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | &board_lbc { | ||
36 | nor@0,0 { | ||
37 | #address-cells = <1>; | ||
38 | #size-cells = <1>; | ||
39 | compatible = "cfi-flash"; | ||
40 | reg = <0x0 0x0 0x01000000>; | ||
41 | bank-width = <2>; | ||
42 | device-width = <2>; | ||
43 | |||
44 | partition@0 { | ||
45 | reg = <0x0 0x0b00000>; | ||
46 | label = "ramdisk-nor"; | ||
47 | }; | ||
48 | |||
49 | partition@300000 { | ||
50 | reg = <0x0b00000 0x0400000>; | ||
51 | label = "kernel-nor"; | ||
52 | }; | ||
53 | |||
54 | partition@700000 { | ||
55 | reg = <0x0f00000 0x060000>; | ||
56 | label = "dtb-nor"; | ||
57 | }; | ||
58 | |||
59 | partition@760000 { | ||
60 | reg = <0x0f60000 0x020000>; | ||
61 | label = "env-nor"; | ||
62 | read-only; | ||
63 | }; | ||
64 | |||
65 | partition@780000 { | ||
66 | reg = <0x0f80000 0x080000>; | ||
67 | label = "u-boot-nor"; | ||
68 | read-only; | ||
69 | }; | ||
70 | }; | ||
71 | |||
72 | board-control@1,0 { | ||
73 | compatible = "fsl,mpc8548cds-fpga"; | ||
74 | reg = <0x1 0x0 0x1000>; | ||
75 | }; | ||
76 | }; | ||
77 | |||
78 | &board_soc { | ||
79 | i2c@3000 { | ||
80 | eeprom@50 { | ||
81 | compatible = "atmel,24c64"; | ||
82 | reg = <0x50>; | ||
83 | }; | ||
84 | |||
85 | eeprom@56 { | ||
86 | compatible = "atmel,24c64"; | ||
87 | reg = <0x56>; | ||
88 | }; | ||
89 | |||
90 | eeprom@57 { | ||
91 | compatible = "atmel,24c64"; | ||
92 | reg = <0x57>; | ||
93 | }; | ||
94 | }; | ||
95 | |||
96 | i2c@3100 { | ||
97 | eeprom@50 { | ||
98 | compatible = "atmel,24c64"; | ||
99 | reg = <0x50>; | ||
100 | }; | ||
101 | }; | ||
102 | |||
103 | enet0: ethernet@24000 { | ||
104 | tbi-handle = <&tbi0>; | ||
105 | phy-handle = <&phy0>; | ||
106 | }; | ||
107 | |||
108 | mdio@24520 { | ||
109 | phy0: ethernet-phy@0 { | ||
110 | interrupts = <5 1 0 0>; | ||
111 | reg = <0x0>; | ||
112 | device_type = "ethernet-phy"; | ||
113 | }; | ||
114 | phy1: ethernet-phy@1 { | ||
115 | interrupts = <5 1 0 0>; | ||
116 | reg = <0x1>; | ||
117 | device_type = "ethernet-phy"; | ||
118 | }; | ||
119 | phy2: ethernet-phy@2 { | ||
120 | interrupts = <5 1 0 0>; | ||
121 | reg = <0x2>; | ||
122 | device_type = "ethernet-phy"; | ||
123 | }; | ||
124 | phy3: ethernet-phy@3 { | ||
125 | interrupts = <5 1 0 0>; | ||
126 | reg = <0x3>; | ||
127 | device_type = "ethernet-phy"; | ||
128 | }; | ||
129 | tbi0: tbi-phy@11 { | ||
130 | reg = <0x11>; | ||
131 | device_type = "tbi-phy"; | ||
132 | }; | ||
133 | }; | ||
134 | |||
135 | enet1: ethernet@25000 { | ||
136 | tbi-handle = <&tbi1>; | ||
137 | phy-handle = <&phy1>; | ||
138 | }; | ||
139 | |||
140 | mdio@25520 { | ||
141 | tbi1: tbi-phy@11 { | ||
142 | reg = <0x11>; | ||
143 | device_type = "tbi-phy"; | ||
144 | }; | ||
145 | }; | ||
146 | |||
147 | enet2: ethernet@26000 { | ||
148 | tbi-handle = <&tbi2>; | ||
149 | phy-handle = <&phy2>; | ||
150 | }; | ||
151 | |||
152 | mdio@26520 { | ||
153 | tbi2: tbi-phy@11 { | ||
154 | reg = <0x11>; | ||
155 | device_type = "tbi-phy"; | ||
156 | }; | ||
157 | }; | ||
158 | |||
159 | enet3: ethernet@27000 { | ||
160 | tbi-handle = <&tbi3>; | ||
161 | phy-handle = <&phy3>; | ||
162 | }; | ||
163 | |||
164 | mdio@27520 { | ||
165 | tbi3: tbi-phy@11 { | ||
166 | reg = <0x11>; | ||
167 | device_type = "tbi-phy"; | ||
168 | }; | ||
169 | }; | ||
170 | }; | ||
171 | |||
172 | &board_pci0 { | ||
173 | interrupt-map-mask = <0xf800 0x0 0x0 0x7>; | ||
174 | interrupt-map = < | ||
175 | /* IDSEL 0x4 (PCIX Slot 2) */ | ||
176 | 0x2000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 | ||
177 | 0x2000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 | ||
178 | 0x2000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 | ||
179 | 0x2000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0 | ||
180 | |||
181 | /* IDSEL 0x5 (PCIX Slot 3) */ | ||
182 | 0x2800 0x0 0x0 0x1 &mpic 0x1 0x1 0 0 | ||
183 | 0x2800 0x0 0x0 0x2 &mpic 0x2 0x1 0 0 | ||
184 | 0x2800 0x0 0x0 0x3 &mpic 0x3 0x1 0 0 | ||
185 | 0x2800 0x0 0x0 0x4 &mpic 0x0 0x1 0 0 | ||
186 | |||
187 | /* IDSEL 0x6 (PCIX Slot 4) */ | ||
188 | 0x3000 0x0 0x0 0x1 &mpic 0x2 0x1 0 0 | ||
189 | 0x3000 0x0 0x0 0x2 &mpic 0x3 0x1 0 0 | ||
190 | 0x3000 0x0 0x0 0x3 &mpic 0x0 0x1 0 0 | ||
191 | 0x3000 0x0 0x0 0x4 &mpic 0x1 0x1 0 0 | ||
192 | |||
193 | /* IDSEL 0x8 (PCIX Slot 5) */ | ||
194 | 0x4000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 | ||
195 | 0x4000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 | ||
196 | 0x4000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 | ||
197 | 0x4000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0 | ||
198 | |||
199 | /* IDSEL 0xC (Tsi310 bridge) */ | ||
200 | 0x6000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 | ||
201 | 0x6000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 | ||
202 | 0x6000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 | ||
203 | 0x6000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0 | ||
204 | |||
205 | /* IDSEL 0x14 (Slot 2) */ | ||
206 | 0xa000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 | ||
207 | 0xa000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 | ||
208 | 0xa000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 | ||
209 | 0xa000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0 | ||
210 | |||
211 | /* IDSEL 0x15 (Slot 3) */ | ||
212 | 0xa800 0x0 0x0 0x1 &mpic 0x1 0x1 0 0 | ||
213 | 0xa800 0x0 0x0 0x2 &mpic 0x2 0x1 0 0 | ||
214 | 0xa800 0x0 0x0 0x3 &mpic 0x3 0x1 0 0 | ||
215 | 0xa800 0x0 0x0 0x4 &mpic 0x0 0x1 0 0 | ||
216 | |||
217 | /* IDSEL 0x16 (Slot 4) */ | ||
218 | 0xb000 0x0 0x0 0x1 &mpic 0x2 0x1 0 0 | ||
219 | 0xb000 0x0 0x0 0x2 &mpic 0x3 0x1 0 0 | ||
220 | 0xb000 0x0 0x0 0x3 &mpic 0x0 0x1 0 0 | ||
221 | 0xb000 0x0 0x0 0x4 &mpic 0x1 0x1 0 0 | ||
222 | |||
223 | /* IDSEL 0x18 (Slot 5) */ | ||
224 | 0xc000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 | ||
225 | 0xc000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 | ||
226 | 0xc000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 | ||
227 | 0xc000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0 | ||
228 | |||
229 | /* IDSEL 0x1C (Tsi310 bridge PCI primary) */ | ||
230 | 0xe000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 | ||
231 | 0xe000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 | ||
232 | 0xe000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 | ||
233 | 0xe000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0>; | ||
234 | |||
235 | pci_bridge@1c { | ||
236 | interrupt-map-mask = <0xf800 0x0 0x0 0x7>; | ||
237 | interrupt-map = < | ||
238 | |||
239 | /* IDSEL 0x00 (PrPMC Site) */ | ||
240 | 0000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 | ||
241 | 0000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 | ||
242 | 0000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 | ||
243 | 0000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0 | ||
244 | |||
245 | /* IDSEL 0x04 (VIA chip) */ | ||
246 | 0x2000 0x0 0x0 0x1 &mpic 0x0 0x1 0 0 | ||
247 | 0x2000 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 | ||
248 | 0x2000 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 | ||
249 | 0x2000 0x0 0x0 0x4 &mpic 0x3 0x1 0 0 | ||
250 | |||
251 | /* IDSEL 0x05 (8139) */ | ||
252 | 0x2800 0x0 0x0 0x1 &mpic 0x1 0x1 0 0 | ||
253 | |||
254 | /* IDSEL 0x06 (Slot 6) */ | ||
255 | 0x3000 0x0 0x0 0x1 &mpic 0x2 0x1 0 0 | ||
256 | 0x3000 0x0 0x0 0x2 &mpic 0x3 0x1 0 0 | ||
257 | 0x3000 0x0 0x0 0x3 &mpic 0x0 0x1 0 0 | ||
258 | 0x3000 0x0 0x0 0x4 &mpic 0x1 0x1 0 0 | ||
259 | |||
260 | /* IDESL 0x07 (Slot 7) */ | ||
261 | 0x3800 0x0 0x0 0x1 &mpic 0x3 0x1 0 0 | ||
262 | 0x3800 0x0 0x0 0x2 &mpic 0x0 0x1 0 0 | ||
263 | 0x3800 0x0 0x0 0x3 &mpic 0x1 0x1 0 0 | ||
264 | 0x3800 0x0 0x0 0x4 &mpic 0x2 0x1 0 0>; | ||
265 | |||
266 | reg = <0xe000 0x0 0x0 0x0 0x0>; | ||
267 | #interrupt-cells = <1>; | ||
268 | #size-cells = <2>; | ||
269 | #address-cells = <3>; | ||
270 | ranges = <0x2000000 0x0 0x80000000 | ||
271 | 0x2000000 0x0 0x80000000 | ||
272 | 0x0 0x20000000 | ||
273 | 0x1000000 0x0 0x0 | ||
274 | 0x1000000 0x0 0x0 | ||
275 | 0x0 0x80000>; | ||
276 | clock-frequency = <33333333>; | ||
277 | |||
278 | isa@4 { | ||
279 | device_type = "isa"; | ||
280 | #interrupt-cells = <2>; | ||
281 | #size-cells = <1>; | ||
282 | #address-cells = <2>; | ||
283 | reg = <0x2000 0x0 0x0 0x0 0x0>; | ||
284 | ranges = <0x1 0x0 0x1000000 0x0 0x0 0x1000>; | ||
285 | interrupt-parent = <&i8259>; | ||
286 | |||
287 | i8259: interrupt-controller@20 { | ||
288 | interrupt-controller; | ||
289 | device_type = "interrupt-controller"; | ||
290 | reg = <0x1 0x20 0x2 | ||
291 | 0x1 0xa0 0x2 | ||
292 | 0x1 0x4d0 0x2>; | ||
293 | #address-cells = <0>; | ||
294 | #interrupt-cells = <2>; | ||
295 | compatible = "chrp,iic"; | ||
296 | interrupts = <0 1 0 0>; | ||
297 | interrupt-parent = <&mpic>; | ||
298 | }; | ||
299 | |||
300 | rtc@70 { | ||
301 | compatible = "pnpPNP,b00"; | ||
302 | reg = <0x1 0x70 0x2>; | ||
303 | }; | ||
304 | }; | ||
305 | }; | ||
306 | }; | ||
diff --git a/arch/powerpc/boot/dts/mpc8548cds_32b.dts b/arch/powerpc/boot/dts/mpc8548cds_32b.dts new file mode 100644 index 000000000000..6fd63163fc6b --- /dev/null +++ b/arch/powerpc/boot/dts/mpc8548cds_32b.dts | |||
@@ -0,0 +1,86 @@ | |||
1 | /* | ||
2 | * MPC8548 CDS Device Tree Source (32-bit address map) | ||
3 | * | ||
4 | * Copyright 2006, 2008, 2011-2012 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 | /include/ "fsl/mpc8548si-pre.dtsi" | ||
13 | |||
14 | / { | ||
15 | model = "MPC8548CDS"; | ||
16 | compatible = "MPC8548CDS", "MPC85xxCDS"; | ||
17 | |||
18 | memory { | ||
19 | device_type = "memory"; | ||
20 | reg = <0 0 0x0 0x8000000>; // 128M at 0x0 | ||
21 | }; | ||
22 | |||
23 | board_lbc: lbc: localbus@e0005000 { | ||
24 | reg = <0 0xe0005000 0 0x1000>; | ||
25 | |||
26 | ranges = <0x0 0x0 0x0 0xff000000 0x01000000 | ||
27 | 0x1 0x0 0x0 0xf8004000 0x00001000>; | ||
28 | |||
29 | }; | ||
30 | |||
31 | board_soc: soc: soc8548@e0000000 { | ||
32 | ranges = <0 0x0 0xe0000000 0x100000>; | ||
33 | }; | ||
34 | |||
35 | board_pci0: pci0: pci@e0008000 { | ||
36 | reg = <0 0xe0008000 0 0x1000>; | ||
37 | ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x10000000 | ||
38 | 0x1000000 0x0 0x00000000 0 0xe2000000 0x0 0x800000>; | ||
39 | clock-frequency = <66666666>; | ||
40 | }; | ||
41 | |||
42 | pci1: pci@e0009000 { | ||
43 | reg = <0 0xe0009000 0 0x1000>; | ||
44 | ranges = <0x2000000 0x0 0x90000000 0 0x90000000 0x0 0x10000000 | ||
45 | 0x1000000 0x0 0x00000000 0 0xe2800000 0x0 0x800000>; | ||
46 | clock-frequency = <66666666>; | ||
47 | interrupt-map-mask = <0xf800 0x0 0x0 0x7>; | ||
48 | interrupt-map = < | ||
49 | |||
50 | /* IDSEL 0x15 */ | ||
51 | 0xa800 0x0 0x0 0x1 &mpic 0xb 0x1 0 0 | ||
52 | 0xa800 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 | ||
53 | 0xa800 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 | ||
54 | 0xa800 0x0 0x0 0x4 &mpic 0x3 0x1 0 0>; | ||
55 | }; | ||
56 | |||
57 | pci2: pcie@e000a000 { | ||
58 | reg = <0 0xe000a000 0 0x1000>; | ||
59 | ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000 | ||
60 | 0x1000000 0x0 0x00000000 0 0xe3000000 0x0 0x100000>; | ||
61 | pcie@0 { | ||
62 | ranges = <0x2000000 0x0 0xa0000000 | ||
63 | 0x2000000 0x0 0xa0000000 | ||
64 | 0x0 0x20000000 | ||
65 | |||
66 | 0x1000000 0x0 0x0 | ||
67 | 0x1000000 0x0 0x0 | ||
68 | 0x0 0x100000>; | ||
69 | }; | ||
70 | }; | ||
71 | |||
72 | rio: rapidio@e00c0000 { | ||
73 | reg = <0x0 0xe00c0000 0x0 0x20000>; | ||
74 | port1 { | ||
75 | ranges = <0x0 0x0 0x0 0xc0000000 0x0 0x20000000>; | ||
76 | }; | ||
77 | }; | ||
78 | }; | ||
79 | |||
80 | /* | ||
81 | * mpc8548cds.dtsi must be last to ensure board_pci0 overrides pci0 settings | ||
82 | * for interrupt-map & interrupt-map-mask. | ||
83 | */ | ||
84 | |||
85 | /include/ "fsl/mpc8548si-post.dtsi" | ||
86 | /include/ "mpc8548cds.dtsi" | ||
diff --git a/arch/powerpc/boot/dts/mpc8548cds_36b.dts b/arch/powerpc/boot/dts/mpc8548cds_36b.dts new file mode 100644 index 000000000000..10e551b11bd6 --- /dev/null +++ b/arch/powerpc/boot/dts/mpc8548cds_36b.dts | |||
@@ -0,0 +1,86 @@ | |||
1 | /* | ||
2 | * MPC8548 CDS Device Tree Source (36-bit address map) | ||
3 | * | ||
4 | * Copyright 2012 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 | /include/ "fsl/mpc8548si-pre.dtsi" | ||
13 | |||
14 | / { | ||
15 | model = "MPC8548CDS"; | ||
16 | compatible = "MPC8548CDS", "MPC85xxCDS"; | ||
17 | |||
18 | memory { | ||
19 | device_type = "memory"; | ||
20 | reg = <0 0 0x0 0x8000000>; // 128M at 0x0 | ||
21 | }; | ||
22 | |||
23 | board_lbc: lbc: localbus@fe0005000 { | ||
24 | reg = <0xf 0xe0005000 0 0x1000>; | ||
25 | |||
26 | ranges = <0x0 0x0 0xf 0xff000000 0x01000000 | ||
27 | 0x1 0x0 0xf 0xf8004000 0x00001000>; | ||
28 | |||
29 | }; | ||
30 | |||
31 | board_soc: soc: soc8548@fe0000000 { | ||
32 | ranges = <0 0xf 0xe0000000 0x100000>; | ||
33 | }; | ||
34 | |||
35 | board_pci0: pci0: pci@fe0008000 { | ||
36 | reg = <0xf 0xe0008000 0 0x1000>; | ||
37 | ranges = <0x2000000 0x0 0xe0000000 0xc 0x00000000 0x0 0x10000000 | ||
38 | 0x1000000 0x0 0x00000000 0xf 0xe2000000 0x0 0x800000>; | ||
39 | clock-frequency = <66666666>; | ||
40 | }; | ||
41 | |||
42 | pci1: pci@fe0009000 { | ||
43 | reg = <0xf 0xe0009000 0 0x1000>; | ||
44 | ranges = <0x2000000 0x0 0xe0000000 0xc 0x10000000 0x0 0x10000000 | ||
45 | 0x1000000 0x0 0x00000000 0xf 0xe2800000 0x0 0x800000>; | ||
46 | clock-frequency = <66666666>; | ||
47 | interrupt-map-mask = <0xf800 0x0 0x0 0x7>; | ||
48 | interrupt-map = < | ||
49 | |||
50 | /* IDSEL 0x15 */ | ||
51 | 0xa800 0x0 0x0 0x1 &mpic 0xb 0x1 0 0 | ||
52 | 0xa800 0x0 0x0 0x2 &mpic 0x1 0x1 0 0 | ||
53 | 0xa800 0x0 0x0 0x3 &mpic 0x2 0x1 0 0 | ||
54 | 0xa800 0x0 0x0 0x4 &mpic 0x3 0x1 0 0>; | ||
55 | }; | ||
56 | |||
57 | pci2: pcie@fe000a000 { | ||
58 | reg = <0xf 0xe000a000 0 0x1000>; | ||
59 | ranges = <0x2000000 0x0 0xe0000000 0xc 0x20000000 0x0 0x20000000 | ||
60 | 0x1000000 0x0 0x00000000 0xf 0xe3000000 0x0 0x100000>; | ||
61 | pcie@0 { | ||
62 | ranges = <0x2000000 0x0 0xa0000000 | ||
63 | 0x2000000 0x0 0xa0000000 | ||
64 | 0x0 0x20000000 | ||
65 | |||
66 | 0x1000000 0x0 0x0 | ||
67 | 0x1000000 0x0 0x0 | ||
68 | 0x0 0x100000>; | ||
69 | }; | ||
70 | }; | ||
71 | |||
72 | rio: rapidio@fe00c0000 { | ||
73 | reg = <0xf 0xe00c0000 0x0 0x20000>; | ||
74 | port1 { | ||
75 | ranges = <0x0 0x0 0xc 0x40000000 0x0 0x20000000>; | ||
76 | }; | ||
77 | }; | ||
78 | }; | ||
79 | |||
80 | /* | ||
81 | * mpc8548cds.dtsi must be last to ensure board_pci0 overrides pci0 settings | ||
82 | * for interrupt-map & interrupt-map-mask. | ||
83 | */ | ||
84 | |||
85 | /include/ "fsl/mpc8548si-post.dtsi" | ||
86 | /include/ "mpc8548cds.dtsi" | ||
diff --git a/arch/powerpc/boot/dts/mpc8572ds.dtsi b/arch/powerpc/boot/dts/mpc8572ds.dtsi index c3d4fac0532a..14178944e220 100644 --- a/arch/powerpc/boot/dts/mpc8572ds.dtsi +++ b/arch/powerpc/boot/dts/mpc8572ds.dtsi | |||
@@ -41,37 +41,47 @@ | |||
41 | bank-width = <2>; | 41 | bank-width = <2>; |
42 | device-width = <1>; | 42 | device-width = <1>; |
43 | 43 | ||
44 | ramdisk@0 { | 44 | partition@0 { |
45 | reg = <0x0 0x03000000>; | 45 | reg = <0x0 0x03000000>; |
46 | read-only; | 46 | label = "ramdisk-nor"; |
47 | }; | 47 | }; |
48 | 48 | ||
49 | diagnostic@3000000 { | 49 | partition@3000000 { |
50 | reg = <0x03000000 0x00e00000>; | 50 | reg = <0x03000000 0x00e00000>; |
51 | label = "diagnostic-nor"; | ||
51 | read-only; | 52 | read-only; |
52 | }; | 53 | }; |
53 | 54 | ||
54 | dink@3e00000 { | 55 | partition@3e00000 { |
55 | reg = <0x03e00000 0x00200000>; | 56 | reg = <0x03e00000 0x00200000>; |
57 | label = "dink-nor"; | ||
56 | read-only; | 58 | read-only; |
57 | }; | 59 | }; |
58 | 60 | ||
59 | kernel@4000000 { | 61 | partition@4000000 { |
60 | reg = <0x04000000 0x00400000>; | 62 | reg = <0x04000000 0x00400000>; |
61 | read-only; | 63 | label = "kernel-nor"; |
62 | }; | 64 | }; |
63 | 65 | ||
64 | jffs2@4400000 { | 66 | partition@4400000 { |
65 | reg = <0x04400000 0x03b00000>; | 67 | reg = <0x04400000 0x03b00000>; |
68 | label = "fs-nor"; | ||
69 | }; | ||
70 | |||
71 | partition@7f00000 { | ||
72 | reg = <0x07f00000 0x00060000>; | ||
73 | label = "dtb-nor"; | ||
66 | }; | 74 | }; |
67 | 75 | ||
68 | dtb@7f00000 { | 76 | partition@7f60000 { |
69 | reg = <0x07f00000 0x00080000>; | 77 | reg = <0x07f60000 0x00020000>; |
78 | label = "env-nor"; | ||
70 | read-only; | 79 | read-only; |
71 | }; | 80 | }; |
72 | 81 | ||
73 | u-boot@7f80000 { | 82 | partition@7f80000 { |
74 | reg = <0x07f80000 0x00080000>; | 83 | reg = <0x07f80000 0x00080000>; |
84 | label = "u-boot-nor"; | ||
75 | read-only; | 85 | read-only; |
76 | }; | 86 | }; |
77 | }; | 87 | }; |
@@ -83,31 +93,35 @@ | |||
83 | "fsl,elbc-fcm-nand"; | 93 | "fsl,elbc-fcm-nand"; |
84 | reg = <0x2 0x0 0x40000>; | 94 | reg = <0x2 0x0 0x40000>; |
85 | 95 | ||
86 | u-boot@0 { | 96 | partition@0 { |
87 | reg = <0x0 0x02000000>; | 97 | reg = <0x0 0x02000000>; |
98 | label = "u-boot-nand"; | ||
88 | read-only; | 99 | read-only; |
89 | }; | 100 | }; |
90 | 101 | ||
91 | jffs2@2000000 { | 102 | partition@2000000 { |
92 | reg = <0x02000000 0x10000000>; | 103 | reg = <0x02000000 0x10000000>; |
104 | label = "fs-nand"; | ||
93 | }; | 105 | }; |
94 | 106 | ||
95 | ramdisk@12000000 { | 107 | partition@12000000 { |
96 | reg = <0x12000000 0x08000000>; | 108 | reg = <0x12000000 0x08000000>; |
97 | read-only; | 109 | label = "ramdisk-nand"; |
98 | }; | 110 | }; |
99 | 111 | ||
100 | kernel@1a000000 { | 112 | partition@1a000000 { |
101 | reg = <0x1a000000 0x04000000>; | 113 | reg = <0x1a000000 0x04000000>; |
114 | label = "kernel-nand"; | ||
102 | }; | 115 | }; |
103 | 116 | ||
104 | dtb@1e000000 { | 117 | partition@1e000000 { |
105 | reg = <0x1e000000 0x01000000>; | 118 | reg = <0x1e000000 0x01000000>; |
106 | read-only; | 119 | label = "dtb-nand"; |
107 | }; | 120 | }; |
108 | 121 | ||
109 | empty@1f000000 { | 122 | partition@1f000000 { |
110 | reg = <0x1f000000 0x21000000>; | 123 | reg = <0x1f000000 0x21000000>; |
124 | label = "empty-nand"; | ||
111 | }; | 125 | }; |
112 | }; | 126 | }; |
113 | 127 | ||
diff --git a/arch/powerpc/boot/dts/p1010rdb.dtsi b/arch/powerpc/boot/dts/p1010rdb.dtsi index d4c4a7730285..49776143a1b8 100644 --- a/arch/powerpc/boot/dts/p1010rdb.dtsi +++ b/arch/powerpc/boot/dts/p1010rdb.dtsi | |||
@@ -138,7 +138,7 @@ | |||
138 | #size-cells = <1>; | 138 | #size-cells = <1>; |
139 | compatible = "spansion,s25sl12801"; | 139 | compatible = "spansion,s25sl12801"; |
140 | reg = <0>; | 140 | reg = <0>; |
141 | spi-max-frequency = <50000000>; | 141 | spi-max-frequency = <40000000>; |
142 | 142 | ||
143 | partition@0 { | 143 | partition@0 { |
144 | /* 1MB for u-boot Bootloader Image */ | 144 | /* 1MB for u-boot Bootloader Image */ |
@@ -196,7 +196,7 @@ | |||
196 | }; | 196 | }; |
197 | 197 | ||
198 | tbi-phy@3 { | 198 | tbi-phy@3 { |
199 | device-type = "tbi-phy"; | 199 | device_type = "tbi-phy"; |
200 | reg = <0x3>; | 200 | reg = <0x3>; |
201 | }; | 201 | }; |
202 | }; | 202 | }; |
diff --git a/arch/powerpc/boot/dts/p1020rdb-pc.dtsi b/arch/powerpc/boot/dts/p1020rdb-pc.dtsi new file mode 100644 index 000000000000..c952cd37cf6d --- /dev/null +++ b/arch/powerpc/boot/dts/p1020rdb-pc.dtsi | |||
@@ -0,0 +1,247 @@ | |||
1 | /* | ||
2 | * P1020 RDB-PC Device Tree Source stub (no addresses or top-level ranges) | ||
3 | * | ||
4 | * Copyright 2012 Freescale Semiconductor Inc. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions are met: | ||
8 | * * Redistributions of source code must retain the above copyright | ||
9 | * notice, this list of conditions and the following disclaimer. | ||
10 | * * Redistributions in binary form must reproduce the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer in the | ||
12 | * documentation and/or other materials provided with the distribution. | ||
13 | * * Neither the name of Freescale Semiconductor nor the | ||
14 | * names of its contributors may be used to endorse or promote products | ||
15 | * derived from this software without specific prior written permission. | ||
16 | * | ||
17 | * | ||
18 | * ALTERNATIVELY, this software may be distributed under the terms of the | ||
19 | * GNU General Public License ("GPL") as published by the Free Software | ||
20 | * Foundation, either version 2 of that License or (at your option) any | ||
21 | * later version. | ||
22 | * | ||
23 | * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY | ||
24 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
26 | * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY | ||
27 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
28 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
29 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
30 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
32 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | &lbc { | ||
36 | nor@0,0 { | ||
37 | #address-cells = <1>; | ||
38 | #size-cells = <1>; | ||
39 | compatible = "cfi-flash"; | ||
40 | reg = <0x0 0x0 0x1000000>; | ||
41 | bank-width = <2>; | ||
42 | device-width = <1>; | ||
43 | |||
44 | partition@0 { | ||
45 | /* This location must not be altered */ | ||
46 | /* 256KB for Vitesse 7385 Switch firmware */ | ||
47 | reg = <0x0 0x00040000>; | ||
48 | label = "NOR Vitesse-7385 Firmware"; | ||
49 | read-only; | ||
50 | }; | ||
51 | |||
52 | partition@40000 { | ||
53 | /* 256KB for DTB Image */ | ||
54 | reg = <0x00040000 0x00040000>; | ||
55 | label = "NOR DTB Image"; | ||
56 | }; | ||
57 | |||
58 | partition@80000 { | ||
59 | /* 3.5 MB for Linux Kernel Image */ | ||
60 | reg = <0x00080000 0x00380000>; | ||
61 | label = "NOR Linux Kernel Image"; | ||
62 | }; | ||
63 | |||
64 | partition@400000 { | ||
65 | /* 11MB for JFFS2 based Root file System */ | ||
66 | reg = <0x00400000 0x00b00000>; | ||
67 | label = "NOR JFFS2 Root File System"; | ||
68 | }; | ||
69 | |||
70 | partition@f00000 { | ||
71 | /* This location must not be altered */ | ||
72 | /* 512KB for u-boot Bootloader Image */ | ||
73 | /* 512KB for u-boot Environment Variables */ | ||
74 | reg = <0x00f00000 0x00100000>; | ||
75 | label = "NOR U-Boot Image"; | ||
76 | read-only; | ||
77 | }; | ||
78 | }; | ||
79 | |||
80 | nand@1,0 { | ||
81 | #address-cells = <1>; | ||
82 | #size-cells = <1>; | ||
83 | compatible = "fsl,p1020-fcm-nand", | ||
84 | "fsl,elbc-fcm-nand"; | ||
85 | reg = <0x1 0x0 0x40000>; | ||
86 | |||
87 | partition@0 { | ||
88 | /* This location must not be altered */ | ||
89 | /* 1MB for u-boot Bootloader Image */ | ||
90 | reg = <0x0 0x00100000>; | ||
91 | label = "NAND U-Boot Image"; | ||
92 | read-only; | ||
93 | }; | ||
94 | |||
95 | partition@100000 { | ||
96 | /* 1MB for DTB Image */ | ||
97 | reg = <0x00100000 0x00100000>; | ||
98 | label = "NAND DTB Image"; | ||
99 | }; | ||
100 | |||
101 | partition@200000 { | ||
102 | /* 4MB for Linux Kernel Image */ | ||
103 | reg = <0x00200000 0x00400000>; | ||
104 | label = "NAND Linux Kernel Image"; | ||
105 | }; | ||
106 | |||
107 | partition@600000 { | ||
108 | /* 4MB for Compressed Root file System Image */ | ||
109 | reg = <0x00600000 0x00400000>; | ||
110 | label = "NAND Compressed RFS Image"; | ||
111 | }; | ||
112 | |||
113 | partition@a00000 { | ||
114 | /* 7MB for JFFS2 based Root file System */ | ||
115 | reg = <0x00a00000 0x00700000>; | ||
116 | label = "NAND JFFS2 Root File System"; | ||
117 | }; | ||
118 | |||
119 | partition@1100000 { | ||
120 | /* 15MB for JFFS2 based Root file System */ | ||
121 | reg = <0x01100000 0x00f00000>; | ||
122 | label = "NAND Writable User area"; | ||
123 | }; | ||
124 | }; | ||
125 | |||
126 | L2switch@2,0 { | ||
127 | #address-cells = <1>; | ||
128 | #size-cells = <1>; | ||
129 | compatible = "vitesse-7385"; | ||
130 | reg = <0x2 0x0 0x20000>; | ||
131 | }; | ||
132 | |||
133 | cpld@3,0 { | ||
134 | #address-cells = <1>; | ||
135 | #size-cells = <1>; | ||
136 | compatible = "cpld"; | ||
137 | reg = <0x3 0x0 0x20000>; | ||
138 | read-only; | ||
139 | }; | ||
140 | }; | ||
141 | |||
142 | &soc { | ||
143 | i2c@3000 { | ||
144 | rtc@68 { | ||
145 | compatible = "pericom,pt7c4338"; | ||
146 | reg = <0x68>; | ||
147 | }; | ||
148 | }; | ||
149 | |||
150 | spi@7000 { | ||
151 | flash@0 { | ||
152 | #address-cells = <1>; | ||
153 | #size-cells = <1>; | ||
154 | compatible = "spansion,s25sl12801"; | ||
155 | reg = <0>; | ||
156 | spi-max-frequency = <40000000>; /* input clock */ | ||
157 | |||
158 | partition@u-boot { | ||
159 | /* 512KB for u-boot Bootloader Image */ | ||
160 | reg = <0x0 0x00080000>; | ||
161 | label = "u-boot"; | ||
162 | read-only; | ||
163 | }; | ||
164 | |||
165 | partition@dtb { | ||
166 | /* 512KB for DTB Image*/ | ||
167 | reg = <0x00080000 0x00080000>; | ||
168 | label = "dtb"; | ||
169 | }; | ||
170 | |||
171 | partition@kernel { | ||
172 | /* 4MB for Linux Kernel Image */ | ||
173 | reg = <0x00100000 0x00400000>; | ||
174 | label = "kernel"; | ||
175 | }; | ||
176 | |||
177 | partition@fs { | ||
178 | /* 4MB for Compressed RFS Image */ | ||
179 | reg = <0x00500000 0x00400000>; | ||
180 | label = "file system"; | ||
181 | }; | ||
182 | |||
183 | partition@jffs-fs { | ||
184 | /* 7MB for JFFS2 based RFS */ | ||
185 | reg = <0x00900000 0x00700000>; | ||
186 | label = "file system jffs2"; | ||
187 | }; | ||
188 | }; | ||
189 | }; | ||
190 | |||
191 | usb@22000 { | ||
192 | phy_type = "ulpi"; | ||
193 | }; | ||
194 | |||
195 | /* USB2 is shared with localbus, so it must be disabled | ||
196 | by default. We can't put 'status = "disabled";' here | ||
197 | since U-Boot doesn't clear the status property when | ||
198 | it enables USB2. OTOH, U-Boot does create a new node | ||
199 | when there isn't any. So, just comment it out. | ||
200 | usb@23000 { | ||
201 | phy_type = "ulpi"; | ||
202 | }; | ||
203 | */ | ||
204 | |||
205 | mdio@24000 { | ||
206 | phy0: ethernet-phy@0 { | ||
207 | interrupt-parent = <&mpic>; | ||
208 | interrupts = <3 1>; | ||
209 | reg = <0x0>; | ||
210 | }; | ||
211 | |||
212 | phy1: ethernet-phy@1 { | ||
213 | interrupt-parent = <&mpic>; | ||
214 | interrupts = <2 1>; | ||
215 | reg = <0x1>; | ||
216 | }; | ||
217 | |||
218 | tbi0: tbi-phy@11 { | ||
219 | device_type = "tbi-phy"; | ||
220 | reg = <0x11>; | ||
221 | }; | ||
222 | }; | ||
223 | |||
224 | mdio@25000 { | ||
225 | tbi1: tbi-phy@11 { | ||
226 | reg = <0x11>; | ||
227 | device_type = "tbi-phy"; | ||
228 | }; | ||
229 | }; | ||
230 | |||
231 | enet0: ethernet@b0000 { | ||
232 | fixed-link = <1 1 1000 0 0>; | ||
233 | phy-connection-type = "rgmii-id"; | ||
234 | |||
235 | }; | ||
236 | |||
237 | enet1: ethernet@b1000 { | ||
238 | phy-handle = <&phy0>; | ||
239 | tbi-handle = <&tbi1>; | ||
240 | phy-connection-type = "sgmii"; | ||
241 | }; | ||
242 | |||
243 | enet2: ethernet@b2000 { | ||
244 | phy-handle = <&phy1>; | ||
245 | phy-connection-type = "rgmii-id"; | ||
246 | }; | ||
247 | }; | ||
diff --git a/arch/powerpc/boot/dts/p1020rdb-pc_32b.dts b/arch/powerpc/boot/dts/p1020rdb-pc_32b.dts new file mode 100644 index 000000000000..4de69b726dc5 --- /dev/null +++ b/arch/powerpc/boot/dts/p1020rdb-pc_32b.dts | |||
@@ -0,0 +1,90 @@ | |||
1 | /* | ||
2 | * P1020 RDB-PC Device Tree Source (32-bit address map) | ||
3 | * | ||
4 | * Copyright 2012 Freescale Semiconductor Inc. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions are met: | ||
8 | * * Redistributions of source code must retain the above copyright | ||
9 | * notice, this list of conditions and the following disclaimer. | ||
10 | * * Redistributions in binary form must reproduce the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer in the | ||
12 | * documentation and/or other materials provided with the distribution. | ||
13 | * * Neither the name of Freescale Semiconductor nor the | ||
14 | * names of its contributors may be used to endorse or promote products | ||
15 | * derived from this software without specific prior written permission. | ||
16 | * | ||
17 | * | ||
18 | * ALTERNATIVELY, this software may be distributed under the terms of the | ||
19 | * GNU General Public License ("GPL") as published by the Free Software | ||
20 | * Foundation, either version 2 of that License or (at your option) any | ||
21 | * later version. | ||
22 | * | ||
23 | * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY | ||
24 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
26 | * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY | ||
27 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
28 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
29 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
30 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
32 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | /include/ "fsl/p1020si-pre.dtsi" | ||
36 | / { | ||
37 | model = "fsl,P1020RDB-PC"; | ||
38 | compatible = "fsl,P1020RDB-PC"; | ||
39 | |||
40 | memory { | ||
41 | device_type = "memory"; | ||
42 | }; | ||
43 | |||
44 | lbc: localbus@ffe05000 { | ||
45 | reg = <0 0xffe05000 0 0x1000>; | ||
46 | |||
47 | /* NOR, NAND Flashes and Vitesse 5 port L2 switch */ | ||
48 | ranges = <0x0 0x0 0x0 0xef000000 0x01000000 | ||
49 | 0x1 0x0 0x0 0xff800000 0x00040000 | ||
50 | 0x2 0x0 0x0 0xffb00000 0x00020000 | ||
51 | 0x3 0x0 0x0 0xffa00000 0x00020000>; | ||
52 | }; | ||
53 | |||
54 | soc: soc@ffe00000 { | ||
55 | ranges = <0x0 0x0 0xffe00000 0x100000>; | ||
56 | }; | ||
57 | |||
58 | pci0: pcie@ffe09000 { | ||
59 | ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000 | ||
60 | 0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>; | ||
61 | reg = <0 0xffe09000 0 0x1000>; | ||
62 | pcie@0 { | ||
63 | ranges = <0x2000000 0x0 0xa0000000 | ||
64 | 0x2000000 0x0 0xa0000000 | ||
65 | 0x0 0x20000000 | ||
66 | |||
67 | 0x1000000 0x0 0x0 | ||
68 | 0x1000000 0x0 0x0 | ||
69 | 0x0 0x100000>; | ||
70 | }; | ||
71 | }; | ||
72 | |||
73 | pci1: pcie@ffe0a000 { | ||
74 | reg = <0 0xffe0a000 0 0x1000>; | ||
75 | ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000 | ||
76 | 0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>; | ||
77 | pcie@0 { | ||
78 | ranges = <0x2000000 0x0 0x80000000 | ||
79 | 0x2000000 0x0 0x80000000 | ||
80 | 0x0 0x20000000 | ||
81 | |||
82 | 0x1000000 0x0 0x0 | ||
83 | 0x1000000 0x0 0x0 | ||
84 | 0x0 0x100000>; | ||
85 | }; | ||
86 | }; | ||
87 | }; | ||
88 | |||
89 | /include/ "p1020rdb-pc.dtsi" | ||
90 | /include/ "fsl/p1020si-post.dtsi" | ||
diff --git a/arch/powerpc/boot/dts/p1020rdb-pc_36b.dts b/arch/powerpc/boot/dts/p1020rdb-pc_36b.dts new file mode 100644 index 000000000000..5237da7441bc --- /dev/null +++ b/arch/powerpc/boot/dts/p1020rdb-pc_36b.dts | |||
@@ -0,0 +1,90 @@ | |||
1 | /* | ||
2 | * P1020 RDB-PC Device Tree Source (36-bit address map) | ||
3 | * | ||
4 | * Copyright 2012 Freescale Semiconductor Inc. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions are met: | ||
8 | * * Redistributions of source code must retain the above copyright | ||
9 | * notice, this list of conditions and the following disclaimer. | ||
10 | * * Redistributions in binary form must reproduce the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer in the | ||
12 | * documentation and/or other materials provided with the distribution. | ||
13 | * * Neither the name of Freescale Semiconductor nor the | ||
14 | * names of its contributors may be used to endorse or promote products | ||
15 | * derived from this software without specific prior written permission. | ||
16 | * | ||
17 | * | ||
18 | * ALTERNATIVELY, this software may be distributed under the terms of the | ||
19 | * GNU General Public License ("GPL") as published by the Free Software | ||
20 | * Foundation, either version 2 of that License or (at your option) any | ||
21 | * later version. | ||
22 | * | ||
23 | * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY | ||
24 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
26 | * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY | ||
27 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
28 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
29 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
30 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
32 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | /include/ "fsl/p1020si-pre.dtsi" | ||
36 | / { | ||
37 | model = "fsl,P1020RDB-PC"; | ||
38 | compatible = "fsl,P1020RDB-PC"; | ||
39 | |||
40 | memory { | ||
41 | device_type = "memory"; | ||
42 | }; | ||
43 | |||
44 | lbc: localbus@fffe05000 { | ||
45 | reg = <0xf 0xffe05000 0 0x1000>; | ||
46 | |||
47 | /* NOR, NAND Flashes and Vitesse 5 port L2 switch */ | ||
48 | ranges = <0x0 0x0 0xf 0xef000000 0x01000000 | ||
49 | 0x1 0x0 0xf 0xff800000 0x00040000 | ||
50 | 0x2 0x0 0xf 0xffb00000 0x00040000 | ||
51 | 0x3 0x0 0xf 0xffa00000 0x00020000>; | ||
52 | }; | ||
53 | |||
54 | soc: soc@fffe00000 { | ||
55 | ranges = <0x0 0xf 0xffe00000 0x100000>; | ||
56 | }; | ||
57 | |||
58 | pci0: pcie@fffe09000 { | ||
59 | reg = <0xf 0xffe09000 0 0x1000>; | ||
60 | ranges = <0x2000000 0x0 0xc0000000 0xc 0x20000000 0x0 0x20000000 | ||
61 | 0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>; | ||
62 | pcie@0 { | ||
63 | ranges = <0x2000000 0x0 0xc0000000 | ||
64 | 0x2000000 0x0 0xc0000000 | ||
65 | 0x0 0x20000000 | ||
66 | |||
67 | 0x1000000 0x0 0x0 | ||
68 | 0x1000000 0x0 0x0 | ||
69 | 0x0 0x100000>; | ||
70 | }; | ||
71 | }; | ||
72 | |||
73 | pci1: pcie@fffe0a000 { | ||
74 | reg = <0xf 0xffe0a000 0 0x1000>; | ||
75 | ranges = <0x2000000 0x0 0x80000000 0xc 0x00000000 0x0 0x20000000 | ||
76 | 0x1000000 0x0 0x00000000 0xf 0xffc00000 0x0 0x10000>; | ||
77 | pcie@0 { | ||
78 | ranges = <0x2000000 0x0 0x80000000 | ||
79 | 0x2000000 0x0 0x80000000 | ||
80 | 0x0 0x20000000 | ||
81 | |||
82 | 0x1000000 0x0 0x0 | ||
83 | 0x1000000 0x0 0x0 | ||
84 | 0x0 0x100000>; | ||
85 | }; | ||
86 | }; | ||
87 | }; | ||
88 | |||
89 | /include/ "p1020rdb-pc.dtsi" | ||
90 | /include/ "fsl/p1020si-post.dtsi" | ||
diff --git a/arch/powerpc/boot/dts/p1020rdb-pc_camp_core0.dts b/arch/powerpc/boot/dts/p1020rdb-pc_camp_core0.dts new file mode 100644 index 000000000000..f411515937ec --- /dev/null +++ b/arch/powerpc/boot/dts/p1020rdb-pc_camp_core0.dts | |||
@@ -0,0 +1,64 @@ | |||
1 | /* | ||
2 | * P1020 RDB-PC 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, tdm, dma, usb, | ||
7 | * eth1, eth2, sdhc, crypto, global-util, message, pci0, pci1, msi. | ||
8 | * | ||
9 | * Please note to add "-b 0" for core0's dts compiling. | ||
10 | * | ||
11 | * Copyright 2012 Freescale Semiconductor Inc. | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify it | ||
14 | * under the terms of the GNU General Public License as published by the | ||
15 | * Free Software Foundation; either version 2 of the License, or (at your | ||
16 | * option) any later version. | ||
17 | */ | ||
18 | |||
19 | /include/ "p1020rdb-pc_32b.dts" | ||
20 | |||
21 | / { | ||
22 | model = "fsl,P1020RDB-PC"; | ||
23 | compatible = "fsl,P1020RDB-PC"; | ||
24 | |||
25 | aliases { | ||
26 | ethernet1 = &enet1; | ||
27 | ethernet2 = &enet2; | ||
28 | serial0 = &serial0; | ||
29 | pci0 = &pci0; | ||
30 | pci1 = &pci1; | ||
31 | }; | ||
32 | |||
33 | cpus { | ||
34 | PowerPC,P1020@1 { | ||
35 | status = "disabled"; | ||
36 | }; | ||
37 | }; | ||
38 | |||
39 | memory { | ||
40 | device_type = "memory"; | ||
41 | }; | ||
42 | |||
43 | localbus@ffe05000 { | ||
44 | status = "disabled"; | ||
45 | }; | ||
46 | |||
47 | soc@ffe00000 { | ||
48 | serial1: serial@4600 { | ||
49 | status = "disabled"; | ||
50 | }; | ||
51 | |||
52 | enet0: ethernet@b0000 { | ||
53 | status = "disabled"; | ||
54 | }; | ||
55 | |||
56 | mpic: pic@40000 { | ||
57 | protected-sources = < | ||
58 | 42 29 30 34 /* serial1, enet0-queue-group0 */ | ||
59 | 17 18 24 45 /* enet0-queue-group1, crypto */ | ||
60 | >; | ||
61 | pic-no-reset; | ||
62 | }; | ||
63 | }; | ||
64 | }; | ||
diff --git a/arch/powerpc/boot/dts/p1020rdb-pc_camp_core1.dts b/arch/powerpc/boot/dts/p1020rdb-pc_camp_core1.dts new file mode 100644 index 000000000000..a91335ad82c2 --- /dev/null +++ b/arch/powerpc/boot/dts/p1020rdb-pc_camp_core1.dts | |||
@@ -0,0 +1,142 @@ | |||
1 | /* | ||
2 | * P1020 RDB-PC 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, eth0, crypto. | ||
7 | * | ||
8 | * Please note to add "-b 1" for core1's dts compiling. | ||
9 | * | ||
10 | * Copyright 2012 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 | /include/ "p1020rdb-pc_32b.dts" | ||
19 | |||
20 | / { | ||
21 | model = "fsl,P1020RDB-PC"; | ||
22 | compatible = "fsl,P1020RDB-PC"; | ||
23 | |||
24 | aliases { | ||
25 | ethernet0 = &enet0; | ||
26 | serial0 = &serial1; | ||
27 | }; | ||
28 | |||
29 | cpus { | ||
30 | PowerPC,P1020@0 { | ||
31 | status = "disabled"; | ||
32 | }; | ||
33 | }; | ||
34 | |||
35 | memory { | ||
36 | device_type = "memory"; | ||
37 | }; | ||
38 | |||
39 | localbus@ffe05000 { | ||
40 | status = "disabled"; | ||
41 | }; | ||
42 | |||
43 | soc@ffe00000 { | ||
44 | ecm-law@0 { | ||
45 | status = "disabled"; | ||
46 | }; | ||
47 | |||
48 | ecm@1000 { | ||
49 | status = "disabled"; | ||
50 | }; | ||
51 | |||
52 | memory-controller@2000 { | ||
53 | status = "disabled"; | ||
54 | }; | ||
55 | |||
56 | i2c@3000 { | ||
57 | status = "disabled"; | ||
58 | }; | ||
59 | |||
60 | i2c@3100 { | ||
61 | status = "disabled"; | ||
62 | }; | ||
63 | |||
64 | serial0: serial@4500 { | ||
65 | status = "disabled"; | ||
66 | }; | ||
67 | |||
68 | spi@7000 { | ||
69 | status = "disabled"; | ||
70 | }; | ||
71 | |||
72 | gpio: gpio-controller@f000 { | ||
73 | status = "disabled"; | ||
74 | }; | ||
75 | |||
76 | dma@21300 { | ||
77 | status = "disabled"; | ||
78 | }; | ||
79 | |||
80 | mdio@24000 { | ||
81 | status = "disabled"; | ||
82 | }; | ||
83 | |||
84 | mdio@25000 { | ||
85 | status = "disabled"; | ||
86 | }; | ||
87 | |||
88 | enet1: ethernet@b1000 { | ||
89 | status = "disabled"; | ||
90 | }; | ||
91 | |||
92 | enet2: ethernet@b2000 { | ||
93 | status = "disabled"; | ||
94 | }; | ||
95 | |||
96 | usb@22000 { | ||
97 | status = "disabled"; | ||
98 | }; | ||
99 | |||
100 | sdhci@2e000 { | ||
101 | status = "disabled"; | ||
102 | }; | ||
103 | |||
104 | mpic: pic@40000 { | ||
105 | protected-sources = < | ||
106 | 16 /* ecm, mem, L2, pci0, pci1 */ | ||
107 | 43 42 59 /* i2c, serial0, spi */ | ||
108 | 47 63 62 /* gpio, tdm */ | ||
109 | 20 21 22 23 /* dma */ | ||
110 | 03 02 /* mdio */ | ||
111 | 35 36 40 /* enet1-queue-group0 */ | ||
112 | 51 52 67 /* enet1-queue-group1 */ | ||
113 | 31 32 33 /* enet2-queue-group0 */ | ||
114 | 25 26 27 /* enet2-queue-group1 */ | ||
115 | 28 72 58 /* usb, sdhci, crypto */ | ||
116 | 0xb0 0xb1 0xb2 /* message */ | ||
117 | 0xb3 0xb4 0xb5 | ||
118 | 0xb6 0xb7 | ||
119 | 0xe0 0xe1 0xe2 /* msi */ | ||
120 | 0xe3 0xe4 0xe5 | ||
121 | 0xe6 0xe7 /* sdhci, crypto , pci */ | ||
122 | >; | ||
123 | pic-no-reset; | ||
124 | }; | ||
125 | |||
126 | msi@41600 { | ||
127 | status = "disabled"; | ||
128 | }; | ||
129 | |||
130 | global-utilities@e0000 { //global utilities block | ||
131 | status = "disabled"; | ||
132 | }; | ||
133 | }; | ||
134 | |||
135 | pci0: pcie@ffe09000 { | ||
136 | status = "disabled"; | ||
137 | }; | ||
138 | |||
139 | pci1: pcie@ffe0a000 { | ||
140 | status = "disabled"; | ||
141 | }; | ||
142 | }; | ||
diff --git a/arch/powerpc/boot/dts/p1021rdb.dts b/arch/powerpc/boot/dts/p1021rdb.dts new file mode 100644 index 000000000000..90b6b4caa273 --- /dev/null +++ b/arch/powerpc/boot/dts/p1021rdb.dts | |||
@@ -0,0 +1,96 @@ | |||
1 | /* | ||
2 | * P1021 RDB Device Tree Source | ||
3 | * | ||
4 | * Copyright 2011 Freescale Semiconductor Inc. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions are met: | ||
8 | * * Redistributions of source code must retain the above copyright | ||
9 | * notice, this list of conditions and the following disclaimer. | ||
10 | * * Redistributions in binary form must reproduce the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer in the | ||
12 | * documentation and/or other materials provided with the distribution. | ||
13 | * * Neither the name of Freescale Semiconductor nor the | ||
14 | * names of its contributors may be used to endorse or promote products | ||
15 | * derived from this software without specific prior written permission. | ||
16 | * | ||
17 | * | ||
18 | * ALTERNATIVELY, this software may be distributed under the terms of the | ||
19 | * GNU General Public License ("GPL") as published by the Free Software | ||
20 | * Foundation, either version 2 of that License or (at your option) any | ||
21 | * later version. | ||
22 | * | ||
23 | * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor "AS IS" AND ANY | ||
24 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
26 | * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY | ||
27 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
28 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
29 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
30 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
32 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | /include/ "fsl/p1021si-pre.dtsi" | ||
36 | / { | ||
37 | model = "fsl,P1021RDB"; | ||
38 | compatible = "fsl,P1021RDB-PC"; | ||
39 | |||
40 | memory { | ||
41 | device_type = "memory"; | ||
42 | }; | ||
43 | |||
44 | lbc: localbus@ffe05000 { | ||
45 | reg = <0 0xffe05000 0 0x1000>; | ||
46 | |||
47 | /* NOR, NAND Flashes and Vitesse 5 port L2 switch */ | ||
48 | ranges = <0x0 0x0 0x0 0xef000000 0x01000000 | ||
49 | 0x1 0x0 0x0 0xff800000 0x00040000 | ||
50 | 0x2 0x0 0x0 0xffb00000 0x00020000>; | ||
51 | }; | ||
52 | |||
53 | soc: soc@ffe00000 { | ||
54 | ranges = <0x0 0x0 0xffe00000 0x100000>; | ||
55 | }; | ||
56 | |||
57 | pci0: pcie@ffe09000 { | ||
58 | ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000 | ||
59 | 0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>; | ||
60 | reg = <0 0xffe09000 0 0x1000>; | ||
61 | pcie@0 { | ||
62 | ranges = <0x2000000 0x0 0xa0000000 | ||
63 | 0x2000000 0x0 0xa0000000 | ||
64 | 0x0 0x20000000 | ||
65 | |||
66 | 0x1000000 0x0 0x0 | ||
67 | 0x1000000 0x0 0x0 | ||
68 | 0x0 0x100000>; | ||
69 | }; | ||
70 | }; | ||
71 | |||
72 | pci1: pcie@ffe0a000 { | ||
73 | reg = <0 0xffe0a000 0 0x1000>; | ||
74 | ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000 | ||
75 | 0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>; | ||
76 | pcie@0 { | ||
77 | ranges = <0x2000000 0x0 0x80000000 | ||
78 | 0x2000000 0x0 0x80000000 | ||
79 | 0x0 0x20000000 | ||
80 | |||
81 | 0x1000000 0x0 0x0 | ||
82 | 0x1000000 0x0 0x0 | ||
83 | 0x0 0x100000>; | ||
84 | }; | ||
85 | }; | ||
86 | |||
87 | qe: qe@ffe80000 { | ||
88 | ranges = <0x0 0x0 0xffe80000 0x40000>; | ||
89 | reg = <0 0xffe80000 0 0x480>; | ||
90 | brg-frequency = <0>; | ||
91 | bus-frequency = <0>; | ||
92 | }; | ||
93 | }; | ||
94 | |||
95 | /include/ "p1021rdb.dtsi" | ||
96 | /include/ "fsl/p1021si-post.dtsi" | ||
diff --git a/arch/powerpc/boot/dts/p1021rdb.dtsi b/arch/powerpc/boot/dts/p1021rdb.dtsi new file mode 100644 index 000000000000..b973461ab751 --- /dev/null +++ b/arch/powerpc/boot/dts/p1021rdb.dtsi | |||
@@ -0,0 +1,236 @@ | |||
1 | /* | ||
2 | * P1021 RDB Device Tree Source stub (no addresses or top-level ranges) | ||
3 | * | ||
4 | * Copyright 2011 Freescale Semiconductor Inc. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions are met: | ||
8 | * * Redistributions of source code must retain the above copyright | ||
9 | * notice, this list of conditions and the following disclaimer. | ||
10 | * * Redistributions in binary form must reproduce the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer in the | ||
12 | * documentation and/or other materials provided with the distribution. | ||
13 | * * Neither the name of Freescale Semiconductor nor the | ||
14 | * names of its contributors may be used to endorse or promote products | ||
15 | * derived from this software without specific prior written permission. | ||
16 | * | ||
17 | * | ||
18 | * ALTERNATIVELY, this software may be distributed under the terms of the | ||
19 | * GNU General Public License ("GPL") as published by the Free Software | ||
20 | * Foundation, either version 2 of that License or (at your option) any | ||
21 | * later version. | ||
22 | * | ||
23 | * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY | ||
24 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
26 | * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY | ||
27 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
28 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
29 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
30 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
32 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | &lbc { | ||
36 | nor@0,0 { | ||
37 | #address-cells = <1>; | ||
38 | #size-cells = <1>; | ||
39 | compatible = "cfi-flash"; | ||
40 | reg = <0x0 0x0 0x1000000>; | ||
41 | bank-width = <2>; | ||
42 | device-width = <1>; | ||
43 | |||
44 | partition@0 { | ||
45 | /* This location must not be altered */ | ||
46 | /* 256KB for Vitesse 7385 Switch firmware */ | ||
47 | reg = <0x0 0x00040000>; | ||
48 | label = "NOR Vitesse-7385 Firmware"; | ||
49 | read-only; | ||
50 | }; | ||
51 | |||
52 | partition@40000 { | ||
53 | /* 256KB for DTB Image */ | ||
54 | reg = <0x00040000 0x00040000>; | ||
55 | label = "NOR DTB Image"; | ||
56 | }; | ||
57 | |||
58 | partition@80000 { | ||
59 | /* 3.5 MB for Linux Kernel Image */ | ||
60 | reg = <0x00080000 0x00380000>; | ||
61 | label = "NOR Linux Kernel Image"; | ||
62 | }; | ||
63 | |||
64 | partition@400000 { | ||
65 | /* 11MB for JFFS2 based Root file System */ | ||
66 | reg = <0x00400000 0x00b00000>; | ||
67 | label = "NOR JFFS2 Root File System"; | ||
68 | }; | ||
69 | |||
70 | partition@f00000 { | ||
71 | /* This location must not be altered */ | ||
72 | /* 512KB for u-boot Bootloader Image */ | ||
73 | /* 512KB for u-boot Environment Variables */ | ||
74 | reg = <0x00f00000 0x00100000>; | ||
75 | label = "NOR U-Boot Image"; | ||
76 | }; | ||
77 | }; | ||
78 | |||
79 | nand@1,0 { | ||
80 | #address-cells = <1>; | ||
81 | #size-cells = <1>; | ||
82 | compatible = "fsl,p1021-fcm-nand", | ||
83 | "fsl,elbc-fcm-nand"; | ||
84 | reg = <0x1 0x0 0x40000>; | ||
85 | |||
86 | partition@0 { | ||
87 | /* This location must not be altered */ | ||
88 | /* 1MB for u-boot Bootloader Image */ | ||
89 | reg = <0x0 0x00100000>; | ||
90 | label = "NAND U-Boot Image"; | ||
91 | read-only; | ||
92 | }; | ||
93 | |||
94 | partition@100000 { | ||
95 | /* 1MB for DTB Image */ | ||
96 | reg = <0x00100000 0x00100000>; | ||
97 | label = "NAND DTB Image"; | ||
98 | }; | ||
99 | |||
100 | partition@200000 { | ||
101 | /* 4MB for Linux Kernel Image */ | ||
102 | reg = <0x00200000 0x00400000>; | ||
103 | label = "NAND Linux Kernel Image"; | ||
104 | }; | ||
105 | |||
106 | partition@600000 { | ||
107 | /* 4MB for Compressed Root file System Image */ | ||
108 | reg = <0x00600000 0x00400000>; | ||
109 | label = "NAND Compressed RFS Image"; | ||
110 | }; | ||
111 | |||
112 | partition@a00000 { | ||
113 | /* 7MB for JFFS2 based Root file System */ | ||
114 | reg = <0x00a00000 0x00700000>; | ||
115 | label = "NAND JFFS2 Root File System"; | ||
116 | }; | ||
117 | |||
118 | partition@1100000 { | ||
119 | /* 15MB for User Writable Area */ | ||
120 | reg = <0x01100000 0x00f00000>; | ||
121 | label = "NAND Writable User area"; | ||
122 | }; | ||
123 | }; | ||
124 | |||
125 | L2switch@2,0 { | ||
126 | #address-cells = <1>; | ||
127 | #size-cells = <1>; | ||
128 | compatible = "vitesse-7385"; | ||
129 | reg = <0x2 0x0 0x20000>; | ||
130 | }; | ||
131 | }; | ||
132 | |||
133 | &soc { | ||
134 | i2c@3000 { | ||
135 | rtc@68 { | ||
136 | compatible = "pericom,pt7c4338"; | ||
137 | reg = <0x68>; | ||
138 | }; | ||
139 | }; | ||
140 | |||
141 | spi@7000 { | ||
142 | flash@0 { | ||
143 | #address-cells = <1>; | ||
144 | #size-cells = <1>; | ||
145 | compatible = "spansion,s25sl12801"; | ||
146 | reg = <0>; | ||
147 | spi-max-frequency = <40000000>; /* input clock */ | ||
148 | |||
149 | partition@u-boot { | ||
150 | /* 512KB for u-boot Bootloader Image */ | ||
151 | reg = <0x0 0x00080000>; | ||
152 | label = "SPI Flash U-Boot Image"; | ||
153 | read-only; | ||
154 | }; | ||
155 | |||
156 | partition@dtb { | ||
157 | /* 512KB for DTB Image */ | ||
158 | reg = <0x00080000 0x00080000>; | ||
159 | label = "SPI Flash DTB Image"; | ||
160 | }; | ||
161 | |||
162 | partition@kernel { | ||
163 | /* 4MB for Linux Kernel Image */ | ||
164 | reg = <0x00100000 0x00400000>; | ||
165 | label = "SPI Flash Linux Kernel Image"; | ||
166 | }; | ||
167 | |||
168 | partition@fs { | ||
169 | /* 4MB for Compressed RFS Image */ | ||
170 | reg = <0x00500000 0x00400000>; | ||
171 | label = "SPI Flash Compressed RFSImage"; | ||
172 | }; | ||
173 | |||
174 | partition@jffs-fs { | ||
175 | /* 7MB for JFFS2 based RFS */ | ||
176 | reg = <0x00900000 0x00700000>; | ||
177 | label = "SPI Flash JFFS2 RFS"; | ||
178 | }; | ||
179 | }; | ||
180 | }; | ||
181 | |||
182 | usb@22000 { | ||
183 | phy_type = "ulpi"; | ||
184 | }; | ||
185 | |||
186 | mdio@24000 { | ||
187 | phy0: ethernet-phy@0 { | ||
188 | interrupt-parent = <&mpic>; | ||
189 | interrupts = <3 1 0 0>; | ||
190 | reg = <0x0>; | ||
191 | }; | ||
192 | |||
193 | phy1: ethernet-phy@1 { | ||
194 | interrupt-parent = <&mpic>; | ||
195 | interrupts = <2 1 0 0>; | ||
196 | reg = <0x1>; | ||
197 | }; | ||
198 | |||
199 | tbi0: tbi-phy@11 { | ||
200 | reg = <0x11>; | ||
201 | device_type = "tbi-phy"; | ||
202 | }; | ||
203 | }; | ||
204 | |||
205 | mdio@25000 { | ||
206 | tbi1: tbi-phy@11 { | ||
207 | reg = <0x11>; | ||
208 | device_type = "tbi-phy"; | ||
209 | }; | ||
210 | }; | ||
211 | |||
212 | mdio@26000 { | ||
213 | tbi2: tbi-phy@11 { | ||
214 | reg = <0x11>; | ||
215 | device_type = "tbi-phy"; | ||
216 | }; | ||
217 | }; | ||
218 | |||
219 | enet0: ethernet@b0000 { | ||
220 | fixed-link = <1 1 1000 0 0>; | ||
221 | phy-connection-type = "rgmii-id"; | ||
222 | |||
223 | }; | ||
224 | |||
225 | enet1: ethernet@b1000 { | ||
226 | phy-handle = <&phy0>; | ||
227 | tbi-handle = <&tbi1>; | ||
228 | phy-connection-type = "sgmii"; | ||
229 | }; | ||
230 | |||
231 | enet2: ethernet@b2000 { | ||
232 | phy-handle = <&phy1>; | ||
233 | tbi-handle = <&tbi2>; | ||
234 | phy-connection-type = "rgmii-id"; | ||
235 | }; | ||
236 | }; | ||
diff --git a/arch/powerpc/boot/dts/p1021rdb_36b.dts b/arch/powerpc/boot/dts/p1021rdb_36b.dts new file mode 100644 index 000000000000..ea6d8b5fa10b --- /dev/null +++ b/arch/powerpc/boot/dts/p1021rdb_36b.dts | |||
@@ -0,0 +1,96 @@ | |||
1 | /* | ||
2 | * P1021 RDB Device Tree Source (36-bit address map) | ||
3 | * | ||
4 | * Copyright 2011 Freescale Semiconductor Inc. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions are met: | ||
8 | * * Redistributions of source code must retain the above copyright | ||
9 | * notice, this list of conditions and the following disclaimer. | ||
10 | * * Redistributions in binary form must reproduce the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer in the | ||
12 | * documentation and/or other materials provided with the distribution. | ||
13 | * * Neither the name of Freescale Semiconductor nor the | ||
14 | * names of its contributors may be used to endorse or promote products | ||
15 | * derived from this software without specific prior written permission. | ||
16 | * | ||
17 | * | ||
18 | * ALTERNATIVELY, this software may be distributed under the terms of the | ||
19 | * GNU General Public License ("GPL") as published by the Free Software | ||
20 | * Foundation, either version 2 of that License or (at your option) any | ||
21 | * later version. | ||
22 | * | ||
23 | * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor "AS IS" AND ANY | ||
24 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
26 | * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY | ||
27 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
28 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
29 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
30 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
32 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | /include/ "fsl/p1021si-pre.dtsi" | ||
36 | / { | ||
37 | model = "fsl,P1021RDB"; | ||
38 | compatible = "fsl,P1021RDB-PC"; | ||
39 | |||
40 | memory { | ||
41 | device_type = "memory"; | ||
42 | }; | ||
43 | |||
44 | lbc: localbus@fffe05000 { | ||
45 | reg = <0xf 0xffe05000 0 0x1000>; | ||
46 | |||
47 | /* NOR, NAND Flashes and Vitesse 5 port L2 switch */ | ||
48 | ranges = <0x0 0x0 0xf 0xef000000 0x01000000 | ||
49 | 0x1 0x0 0xf 0xff800000 0x00040000 | ||
50 | 0x2 0x0 0xf 0xffb00000 0x00020000>; | ||
51 | }; | ||
52 | |||
53 | soc: soc@fffe00000 { | ||
54 | ranges = <0x0 0xf 0xffe00000 0x100000>; | ||
55 | }; | ||
56 | |||
57 | pci0: pcie@fffe09000 { | ||
58 | ranges = <0x2000000 0x0 0xc0000000 0xc 0x20000000 0x0 0x20000000 | ||
59 | 0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>; | ||
60 | reg = <0xf 0xffe09000 0 0x1000>; | ||
61 | pcie@0 { | ||
62 | ranges = <0x2000000 0x0 0xa0000000 | ||
63 | 0x2000000 0x0 0xa0000000 | ||
64 | 0x0 0x20000000 | ||
65 | |||
66 | 0x1000000 0x0 0x0 | ||
67 | 0x1000000 0x0 0x0 | ||
68 | 0x0 0x100000>; | ||
69 | }; | ||
70 | }; | ||
71 | |||
72 | pci1: pcie@fffe0a000 { | ||
73 | reg = <0xf 0xffe0a000 0 0x1000>; | ||
74 | ranges = <0x2000000 0x0 0x80000000 0xc 0x00000000 0x0 0x20000000 | ||
75 | 0x1000000 0x0 0x00000000 0xf 0xffc00000 0x0 0x10000>; | ||
76 | pcie@0 { | ||
77 | ranges = <0x2000000 0x0 0xc0000000 | ||
78 | 0x2000000 0x0 0xc0000000 | ||
79 | 0x0 0x20000000 | ||
80 | |||
81 | 0x1000000 0x0 0x0 | ||
82 | 0x1000000 0x0 0x0 | ||
83 | 0x0 0x100000>; | ||
84 | }; | ||
85 | }; | ||
86 | |||
87 | qe: qe@fffe80000 { | ||
88 | ranges = <0x0 0xf 0xffe80000 0x40000>; | ||
89 | reg = <0xf 0xffe80000 0 0x480>; | ||
90 | brg-frequency = <0>; | ||
91 | bus-frequency = <0>; | ||
92 | }; | ||
93 | }; | ||
94 | |||
95 | /include/ "p1021rdb.dtsi" | ||
96 | /include/ "fsl/p1021si-post.dtsi" | ||
diff --git a/arch/powerpc/boot/dts/p1022ds.dts b/arch/powerpc/boot/dts/p1022ds.dts deleted file mode 100644 index ef95717db4bc..000000000000 --- a/arch/powerpc/boot/dts/p1022ds.dts +++ /dev/null | |||
@@ -1,274 +0,0 @@ | |||
1 | /* | ||
2 | * P1022 DS 36Bit Physical Address Map Device Tree Source | ||
3 | * | ||
4 | * Copyright 2010 Freescale Semiconductor, Inc. | ||
5 | * | ||
6 | * This file is licensed under the terms of the GNU General Public License | ||
7 | * version 2. This program is licensed "as is" without any warranty of any | ||
8 | * kind, whether express or implied. | ||
9 | */ | ||
10 | |||
11 | /include/ "fsl/p1022si-pre.dtsi" | ||
12 | / { | ||
13 | model = "fsl,P1022DS"; | ||
14 | compatible = "fsl,P1022DS"; | ||
15 | |||
16 | memory { | ||
17 | device_type = "memory"; | ||
18 | }; | ||
19 | |||
20 | lbc: localbus@fffe05000 { | ||
21 | reg = <0xf 0xffe05000 0 0x1000>; | ||
22 | ranges = <0x0 0x0 0xf 0xe8000000 0x08000000 | ||
23 | 0x1 0x0 0xf 0xe0000000 0x08000000 | ||
24 | 0x2 0x0 0xf 0xff800000 0x00040000 | ||
25 | 0x3 0x0 0xf 0xffdf0000 0x00008000>; | ||
26 | |||
27 | /* | ||
28 | * This node is used to access the pixis via "indirect" mode, | ||
29 | * which is done by writing the pixis register index to chip | ||
30 | * select 0 and the value to/from chip select 1. Indirect | ||
31 | * mode is the only way to access the pixis when DIU video | ||
32 | * is enabled. Note that this assumes that the first column | ||
33 | * of the 'ranges' property above is the chip select number. | ||
34 | */ | ||
35 | board-control@0,0 { | ||
36 | compatible = "fsl,p1022ds-indirect-pixis"; | ||
37 | reg = <0x0 0x0 1 /* CS0 */ | ||
38 | 0x1 0x0 1>; /* CS1 */ | ||
39 | }; | ||
40 | |||
41 | nor@0,0 { | ||
42 | #address-cells = <1>; | ||
43 | #size-cells = <1>; | ||
44 | compatible = "cfi-flash"; | ||
45 | reg = <0x0 0x0 0x8000000>; | ||
46 | bank-width = <2>; | ||
47 | device-width = <1>; | ||
48 | |||
49 | partition@0 { | ||
50 | reg = <0x0 0x03000000>; | ||
51 | label = "ramdisk-nor"; | ||
52 | read-only; | ||
53 | }; | ||
54 | |||
55 | partition@3000000 { | ||
56 | reg = <0x03000000 0x00e00000>; | ||
57 | label = "diagnostic-nor"; | ||
58 | read-only; | ||
59 | }; | ||
60 | |||
61 | partition@3e00000 { | ||
62 | reg = <0x03e00000 0x00200000>; | ||
63 | label = "dink-nor"; | ||
64 | read-only; | ||
65 | }; | ||
66 | |||
67 | partition@4000000 { | ||
68 | reg = <0x04000000 0x00400000>; | ||
69 | label = "kernel-nor"; | ||
70 | read-only; | ||
71 | }; | ||
72 | |||
73 | partition@4400000 { | ||
74 | reg = <0x04400000 0x03b00000>; | ||
75 | label = "jffs2-nor"; | ||
76 | }; | ||
77 | |||
78 | partition@7f00000 { | ||
79 | reg = <0x07f00000 0x00080000>; | ||
80 | label = "dtb-nor"; | ||
81 | read-only; | ||
82 | }; | ||
83 | |||
84 | partition@7f80000 { | ||
85 | reg = <0x07f80000 0x00080000>; | ||
86 | label = "u-boot-nor"; | ||
87 | read-only; | ||
88 | }; | ||
89 | }; | ||
90 | |||
91 | nand@2,0 { | ||
92 | #address-cells = <1>; | ||
93 | #size-cells = <1>; | ||
94 | compatible = "fsl,elbc-fcm-nand"; | ||
95 | reg = <0x2 0x0 0x40000>; | ||
96 | |||
97 | partition@0 { | ||
98 | reg = <0x0 0x02000000>; | ||
99 | label = "u-boot-nand"; | ||
100 | read-only; | ||
101 | }; | ||
102 | |||
103 | partition@2000000 { | ||
104 | reg = <0x02000000 0x10000000>; | ||
105 | label = "jffs2-nand"; | ||
106 | }; | ||
107 | |||
108 | partition@12000000 { | ||
109 | reg = <0x12000000 0x10000000>; | ||
110 | label = "ramdisk-nand"; | ||
111 | read-only; | ||
112 | }; | ||
113 | |||
114 | partition@22000000 { | ||
115 | reg = <0x22000000 0x04000000>; | ||
116 | label = "kernel-nand"; | ||
117 | }; | ||
118 | |||
119 | partition@26000000 { | ||
120 | reg = <0x26000000 0x01000000>; | ||
121 | label = "dtb-nand"; | ||
122 | read-only; | ||
123 | }; | ||
124 | |||
125 | partition@27000000 { | ||
126 | reg = <0x27000000 0x19000000>; | ||
127 | label = "reserved-nand"; | ||
128 | }; | ||
129 | }; | ||
130 | |||
131 | board-control@3,0 { | ||
132 | compatible = "fsl,p1022ds-fpga", "fsl,fpga-ngpixis"; | ||
133 | reg = <3 0 0x30>; | ||
134 | interrupt-parent = <&mpic>; | ||
135 | /* | ||
136 | * IRQ8 is generated if the "EVENT" switch is pressed | ||
137 | * and PX_CTL[EVESEL] is set to 00. | ||
138 | */ | ||
139 | interrupts = <8 8 0 0>; | ||
140 | }; | ||
141 | }; | ||
142 | |||
143 | soc: soc@fffe00000 { | ||
144 | ranges = <0x0 0xf 0xffe00000 0x100000>; | ||
145 | |||
146 | i2c@3100 { | ||
147 | wm8776:codec@1a { | ||
148 | compatible = "wlf,wm8776"; | ||
149 | reg = <0x1a>; | ||
150 | /* | ||
151 | * clock-frequency will be set by U-Boot if | ||
152 | * the clock is enabled. | ||
153 | */ | ||
154 | }; | ||
155 | }; | ||
156 | |||
157 | spi@7000 { | ||
158 | flash@0 { | ||
159 | #address-cells = <1>; | ||
160 | #size-cells = <1>; | ||
161 | compatible = "spansion,s25sl12801"; | ||
162 | reg = <0>; | ||
163 | spi-max-frequency = <40000000>; /* input clock */ | ||
164 | |||
165 | partition@0 { | ||
166 | label = "u-boot-spi"; | ||
167 | reg = <0x00000000 0x00100000>; | ||
168 | read-only; | ||
169 | }; | ||
170 | partition@100000 { | ||
171 | label = "kernel-spi"; | ||
172 | reg = <0x00100000 0x00500000>; | ||
173 | read-only; | ||
174 | }; | ||
175 | partition@600000 { | ||
176 | label = "dtb-spi"; | ||
177 | reg = <0x00600000 0x00100000>; | ||
178 | read-only; | ||
179 | }; | ||
180 | partition@700000 { | ||
181 | label = "file system-spi"; | ||
182 | reg = <0x00700000 0x00900000>; | ||
183 | }; | ||
184 | }; | ||
185 | }; | ||
186 | |||
187 | ssi@15000 { | ||
188 | fsl,mode = "i2s-slave"; | ||
189 | codec-handle = <&wm8776>; | ||
190 | fsl,ssi-asynchronous; | ||
191 | }; | ||
192 | |||
193 | usb@22000 { | ||
194 | phy_type = "ulpi"; | ||
195 | }; | ||
196 | |||
197 | usb@23000 { | ||
198 | status = "disabled"; | ||
199 | }; | ||
200 | |||
201 | mdio@24000 { | ||
202 | phy0: ethernet-phy@0 { | ||
203 | interrupts = <3 1 0 0>; | ||
204 | reg = <0x1>; | ||
205 | }; | ||
206 | phy1: ethernet-phy@1 { | ||
207 | interrupts = <9 1 0 0>; | ||
208 | reg = <0x2>; | ||
209 | }; | ||
210 | tbi-phy@2 { | ||
211 | device_type = "tbi-phy"; | ||
212 | reg = <0x2>; | ||
213 | }; | ||
214 | }; | ||
215 | |||
216 | ethernet@b0000 { | ||
217 | phy-handle = <&phy0>; | ||
218 | phy-connection-type = "rgmii-id"; | ||
219 | }; | ||
220 | |||
221 | ethernet@b1000 { | ||
222 | phy-handle = <&phy1>; | ||
223 | phy-connection-type = "rgmii-id"; | ||
224 | }; | ||
225 | }; | ||
226 | |||
227 | pci0: pcie@fffe09000 { | ||
228 | reg = <0xf 0xffe09000 0 0x1000>; | ||
229 | ranges = <0x2000000 0x0 0xe0000000 0xc 0x20000000 0x0 0x20000000 | ||
230 | 0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>; | ||
231 | pcie@0 { | ||
232 | ranges = <0x2000000 0x0 0xe0000000 | ||
233 | 0x2000000 0x0 0xe0000000 | ||
234 | 0x0 0x20000000 | ||
235 | |||
236 | 0x1000000 0x0 0x0 | ||
237 | 0x1000000 0x0 0x0 | ||
238 | 0x0 0x100000>; | ||
239 | }; | ||
240 | }; | ||
241 | |||
242 | pci1: pcie@fffe0a000 { | ||
243 | reg = <0xf 0xffe0a000 0 0x1000>; | ||
244 | ranges = <0x2000000 0x0 0xe0000000 0xc 0x40000000 0x0 0x20000000 | ||
245 | 0x1000000 0x0 0x00000000 0xf 0xffc20000 0x0 0x10000>; | ||
246 | pcie@0 { | ||
247 | reg = <0x0 0x0 0x0 0x0 0x0>; | ||
248 | ranges = <0x2000000 0x0 0xe0000000 | ||
249 | 0x2000000 0x0 0xe0000000 | ||
250 | 0x0 0x20000000 | ||
251 | |||
252 | 0x1000000 0x0 0x0 | ||
253 | 0x1000000 0x0 0x0 | ||
254 | 0x0 0x100000>; | ||
255 | }; | ||
256 | }; | ||
257 | |||
258 | pci2: pcie@fffe0b000 { | ||
259 | reg = <0xf 0xffe0b000 0 0x1000>; | ||
260 | ranges = <0x2000000 0x0 0xe0000000 0xc 0x00000000 0x0 0x20000000 | ||
261 | 0x1000000 0x0 0x00000000 0xf 0xffc00000 0x0 0x10000>; | ||
262 | pcie@0 { | ||
263 | ranges = <0x2000000 0x0 0xe0000000 | ||
264 | 0x2000000 0x0 0xe0000000 | ||
265 | 0x0 0x20000000 | ||
266 | |||
267 | 0x1000000 0x0 0x0 | ||
268 | 0x1000000 0x0 0x0 | ||
269 | 0x0 0x100000>; | ||
270 | }; | ||
271 | }; | ||
272 | }; | ||
273 | |||
274 | /include/ "fsl/p1022si-post.dtsi" | ||
diff --git a/arch/powerpc/boot/dts/p1022ds.dtsi b/arch/powerpc/boot/dts/p1022ds.dtsi new file mode 100644 index 000000000000..7cdb505036bb --- /dev/null +++ b/arch/powerpc/boot/dts/p1022ds.dtsi | |||
@@ -0,0 +1,234 @@ | |||
1 | /* | ||
2 | * P1022 DS Device Tree Source stub (no addresses or top-level ranges) | ||
3 | * | ||
4 | * Copyright 2012 Freescale Semiconductor Inc. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions are met: | ||
8 | * * Redistributions of source code must retain the above copyright | ||
9 | * notice, this list of conditions and the following disclaimer. | ||
10 | * * Redistributions in binary form must reproduce the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer in the | ||
12 | * documentation and/or other materials provided with the distribution. | ||
13 | * * Neither the name of Freescale Semiconductor nor the | ||
14 | * names of its contributors may be used to endorse or promote products | ||
15 | * derived from this software without specific prior written permission. | ||
16 | * | ||
17 | * | ||
18 | * ALTERNATIVELY, this software may be distributed under the terms of the | ||
19 | * GNU General Public License ("GPL") as published by the Free Software | ||
20 | * Foundation, either version 2 of that License or (at your option) any | ||
21 | * later version. | ||
22 | * | ||
23 | * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor "AS IS" AND ANY | ||
24 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
26 | * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY | ||
27 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
28 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
29 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
30 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
32 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | &board_lbc { | ||
36 | /* | ||
37 | * This node is used to access the pixis via "indirect" mode, | ||
38 | * which is done by writing the pixis register index to chip | ||
39 | * select 0 and the value to/from chip select 1. Indirect | ||
40 | * mode is the only way to access the pixis when DIU video | ||
41 | * is enabled. Note that this assumes that the first column | ||
42 | * of the 'ranges' property above is the chip select number. | ||
43 | */ | ||
44 | board-control@0,0 { | ||
45 | compatible = "fsl,p1022ds-indirect-pixis"; | ||
46 | reg = <0x0 0x0 1 /* CS0 */ | ||
47 | 0x1 0x0 1>; /* CS1 */ | ||
48 | interrupt-parent = <&mpic>; | ||
49 | interrupts = <8 0 0 0>; | ||
50 | }; | ||
51 | |||
52 | nor@0,0 { | ||
53 | #address-cells = <1>; | ||
54 | #size-cells = <1>; | ||
55 | compatible = "cfi-flash"; | ||
56 | reg = <0x0 0x0 0x8000000>; | ||
57 | bank-width = <2>; | ||
58 | device-width = <1>; | ||
59 | |||
60 | partition@0 { | ||
61 | reg = <0x0 0x03000000>; | ||
62 | label = "ramdisk-nor"; | ||
63 | read-only; | ||
64 | }; | ||
65 | |||
66 | partition@3000000 { | ||
67 | reg = <0x03000000 0x00e00000>; | ||
68 | label = "diagnostic-nor"; | ||
69 | read-only; | ||
70 | }; | ||
71 | |||
72 | partition@3e00000 { | ||
73 | reg = <0x03e00000 0x00200000>; | ||
74 | label = "dink-nor"; | ||
75 | read-only; | ||
76 | }; | ||
77 | |||
78 | partition@4000000 { | ||
79 | reg = <0x04000000 0x00400000>; | ||
80 | label = "kernel-nor"; | ||
81 | read-only; | ||
82 | }; | ||
83 | |||
84 | partition@4400000 { | ||
85 | reg = <0x04400000 0x03b00000>; | ||
86 | label = "jffs2-nor"; | ||
87 | }; | ||
88 | |||
89 | partition@7f00000 { | ||
90 | reg = <0x07f00000 0x00080000>; | ||
91 | label = "dtb-nor"; | ||
92 | read-only; | ||
93 | }; | ||
94 | |||
95 | partition@7f80000 { | ||
96 | reg = <0x07f80000 0x00080000>; | ||
97 | label = "u-boot-nor"; | ||
98 | read-only; | ||
99 | }; | ||
100 | }; | ||
101 | |||
102 | nand@2,0 { | ||
103 | #address-cells = <1>; | ||
104 | #size-cells = <1>; | ||
105 | compatible = "fsl,elbc-fcm-nand"; | ||
106 | reg = <0x2 0x0 0x40000>; | ||
107 | |||
108 | partition@0 { | ||
109 | reg = <0x0 0x02000000>; | ||
110 | label = "u-boot-nand"; | ||
111 | read-only; | ||
112 | }; | ||
113 | |||
114 | partition@2000000 { | ||
115 | reg = <0x02000000 0x10000000>; | ||
116 | label = "jffs2-nand"; | ||
117 | }; | ||
118 | |||
119 | partition@12000000 { | ||
120 | reg = <0x12000000 0x10000000>; | ||
121 | label = "ramdisk-nand"; | ||
122 | read-only; | ||
123 | }; | ||
124 | |||
125 | partition@22000000 { | ||
126 | reg = <0x22000000 0x04000000>; | ||
127 | label = "kernel-nand"; | ||
128 | }; | ||
129 | |||
130 | partition@26000000 { | ||
131 | reg = <0x26000000 0x01000000>; | ||
132 | label = "dtb-nand"; | ||
133 | read-only; | ||
134 | }; | ||
135 | |||
136 | partition@27000000 { | ||
137 | reg = <0x27000000 0x19000000>; | ||
138 | label = "reserved-nand"; | ||
139 | }; | ||
140 | }; | ||
141 | |||
142 | board-control@3,0 { | ||
143 | compatible = "fsl,p1022ds-fpga", "fsl,fpga-ngpixis"; | ||
144 | reg = <3 0 0x30>; | ||
145 | interrupt-parent = <&mpic>; | ||
146 | /* | ||
147 | * IRQ8 is generated if the "EVENT" switch is pressed | ||
148 | * and PX_CTL[EVESEL] is set to 00. | ||
149 | */ | ||
150 | interrupts = <8 0 0 0>; | ||
151 | }; | ||
152 | }; | ||
153 | |||
154 | &board_soc { | ||
155 | i2c@3100 { | ||
156 | wm8776:codec@1a { | ||
157 | compatible = "wlf,wm8776"; | ||
158 | reg = <0x1a>; | ||
159 | /* | ||
160 | * clock-frequency will be set by U-Boot if | ||
161 | * the clock is enabled. | ||
162 | */ | ||
163 | }; | ||
164 | }; | ||
165 | |||
166 | spi@7000 { | ||
167 | flash@0 { | ||
168 | #address-cells = <1>; | ||
169 | #size-cells = <1>; | ||
170 | compatible = "spansion,s25sl12801"; | ||
171 | reg = <0>; | ||
172 | spi-max-frequency = <40000000>; /* input clock */ | ||
173 | |||
174 | partition@0 { | ||
175 | label = "u-boot-spi"; | ||
176 | reg = <0x00000000 0x00100000>; | ||
177 | read-only; | ||
178 | }; | ||
179 | partition@100000 { | ||
180 | label = "kernel-spi"; | ||
181 | reg = <0x00100000 0x00500000>; | ||
182 | read-only; | ||
183 | }; | ||
184 | partition@600000 { | ||
185 | label = "dtb-spi"; | ||
186 | reg = <0x00600000 0x00100000>; | ||
187 | read-only; | ||
188 | }; | ||
189 | partition@700000 { | ||
190 | label = "file system-spi"; | ||
191 | reg = <0x00700000 0x00900000>; | ||
192 | }; | ||
193 | }; | ||
194 | }; | ||
195 | |||
196 | ssi@15000 { | ||
197 | fsl,mode = "i2s-slave"; | ||
198 | codec-handle = <&wm8776>; | ||
199 | fsl,ssi-asynchronous; | ||
200 | }; | ||
201 | |||
202 | usb@22000 { | ||
203 | phy_type = "ulpi"; | ||
204 | }; | ||
205 | |||
206 | usb@23000 { | ||
207 | status = "disabled"; | ||
208 | }; | ||
209 | |||
210 | mdio@24000 { | ||
211 | phy0: ethernet-phy@0 { | ||
212 | interrupts = <3 1 0 0>; | ||
213 | reg = <0x1>; | ||
214 | }; | ||
215 | phy1: ethernet-phy@1 { | ||
216 | interrupts = <9 1 0 0>; | ||
217 | reg = <0x2>; | ||
218 | }; | ||
219 | tbi-phy@2 { | ||
220 | device_type = "tbi-phy"; | ||
221 | reg = <0x2>; | ||
222 | }; | ||
223 | }; | ||
224 | |||
225 | ethernet@b0000 { | ||
226 | phy-handle = <&phy0>; | ||
227 | phy-connection-type = "rgmii-id"; | ||
228 | }; | ||
229 | |||
230 | ethernet@b1000 { | ||
231 | phy-handle = <&phy1>; | ||
232 | phy-connection-type = "rgmii-id"; | ||
233 | }; | ||
234 | }; | ||
diff --git a/arch/powerpc/boot/dts/p1022ds_32b.dts b/arch/powerpc/boot/dts/p1022ds_32b.dts new file mode 100644 index 000000000000..d96cae00a9e3 --- /dev/null +++ b/arch/powerpc/boot/dts/p1022ds_32b.dts | |||
@@ -0,0 +1,103 @@ | |||
1 | /* | ||
2 | * P1022 DS 32-bit Physical Address Map Device Tree Source | ||
3 | * | ||
4 | * Copyright 2012 Freescale Semiconductor Inc. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions are met: | ||
8 | * * Redistributions of source code must retain the above copyright | ||
9 | * notice, this list of conditions and the following disclaimer. | ||
10 | * * Redistributions in binary form must reproduce the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer in the | ||
12 | * documentation and/or other materials provided with the distribution. | ||
13 | * * Neither the name of Freescale Semiconductor nor the | ||
14 | * names of its contributors may be used to endorse or promote products | ||
15 | * derived from this software without specific prior written permission. | ||
16 | * | ||
17 | * | ||
18 | * ALTERNATIVELY, this software may be distributed under the terms of the | ||
19 | * GNU General Public License ("GPL") as published by the Free Software | ||
20 | * Foundation, either version 2 of that License or (at your option) any | ||
21 | * later version. | ||
22 | * | ||
23 | * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor "AS IS" AND ANY | ||
24 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
26 | * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY | ||
27 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
28 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
29 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
30 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
32 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | /include/ "fsl/p1022si-pre.dtsi" | ||
36 | / { | ||
37 | model = "fsl,P1022DS"; | ||
38 | compatible = "fsl,P1022DS"; | ||
39 | |||
40 | memory { | ||
41 | device_type = "memory"; | ||
42 | }; | ||
43 | |||
44 | board_lbc: lbc: localbus@ffe05000 { | ||
45 | ranges = <0x0 0x0 0x0 0xe8000000 0x08000000 | ||
46 | 0x1 0x0 0x0 0xe0000000 0x08000000 | ||
47 | 0x2 0x0 0x0 0xff800000 0x00040000 | ||
48 | 0x3 0x0 0x0 0xffdf0000 0x00008000>; | ||
49 | reg = <0x0 0xffe05000 0 0x1000>; | ||
50 | }; | ||
51 | |||
52 | board_soc: soc: soc@ffe00000 { | ||
53 | ranges = <0x0 0x0 0xffe00000 0x100000>; | ||
54 | }; | ||
55 | |||
56 | pci0: pcie@ffe09000 { | ||
57 | ranges = <0x2000000 0x0 0xe0000000 0 0xa0000000 0x0 0x20000000 | ||
58 | 0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>; | ||
59 | reg = <0x0 0xffe09000 0 0x1000>; | ||
60 | pcie@0 { | ||
61 | ranges = <0x2000000 0x0 0xe0000000 | ||
62 | 0x2000000 0x0 0xe0000000 | ||
63 | 0x0 0x20000000 | ||
64 | |||
65 | 0x1000000 0x0 0x0 | ||
66 | 0x1000000 0x0 0x0 | ||
67 | 0x0 0x100000>; | ||
68 | }; | ||
69 | }; | ||
70 | |||
71 | pci1: pcie@ffe0a000 { | ||
72 | ranges = <0x2000000 0x0 0xe0000000 0 0xc0000000 0x0 0x20000000 | ||
73 | 0x1000000 0x0 0x00000000 0 0xffc20000 0x0 0x10000>; | ||
74 | reg = <0 0xffe0a000 0 0x1000>; | ||
75 | pcie@0 { | ||
76 | ranges = <0x2000000 0x0 0xe0000000 | ||
77 | 0x2000000 0x0 0xe0000000 | ||
78 | 0x0 0x20000000 | ||
79 | |||
80 | 0x1000000 0x0 0x0 | ||
81 | 0x1000000 0x0 0x0 | ||
82 | 0x0 0x100000>; | ||
83 | }; | ||
84 | }; | ||
85 | |||
86 | pci2: pcie@ffe0b000 { | ||
87 | ranges = <0x2000000 0x0 0xe0000000 0 0x80000000 0x0 0x20000000 | ||
88 | 0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>; | ||
89 | reg = <0 0xffe0b000 0 0x1000>; | ||
90 | pcie@0 { | ||
91 | ranges = <0x2000000 0x0 0xe0000000 | ||
92 | 0x2000000 0x0 0xe0000000 | ||
93 | 0x0 0x20000000 | ||
94 | |||
95 | 0x1000000 0x0 0x0 | ||
96 | 0x1000000 0x0 0x0 | ||
97 | 0x0 0x100000>; | ||
98 | }; | ||
99 | }; | ||
100 | }; | ||
101 | |||
102 | /include/ "fsl/p1022si-post.dtsi" | ||
103 | /include/ "p1022ds.dtsi" | ||
diff --git a/arch/powerpc/boot/dts/p1022ds_36b.dts b/arch/powerpc/boot/dts/p1022ds_36b.dts new file mode 100644 index 000000000000..f7aacce40bf6 --- /dev/null +++ b/arch/powerpc/boot/dts/p1022ds_36b.dts | |||
@@ -0,0 +1,103 @@ | |||
1 | /* | ||
2 | * P1022 DS 36-bit Physical Address Map Device Tree Source | ||
3 | * | ||
4 | * Copyright 2012 Freescale Semiconductor Inc. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions are met: | ||
8 | * * Redistributions of source code must retain the above copyright | ||
9 | * notice, this list of conditions and the following disclaimer. | ||
10 | * * Redistributions in binary form must reproduce the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer in the | ||
12 | * documentation and/or other materials provided with the distribution. | ||
13 | * * Neither the name of Freescale Semiconductor nor the | ||
14 | * names of its contributors may be used to endorse or promote products | ||
15 | * derived from this software without specific prior written permission. | ||
16 | * | ||
17 | * | ||
18 | * ALTERNATIVELY, this software may be distributed under the terms of the | ||
19 | * GNU General Public License ("GPL") as published by the Free Software | ||
20 | * Foundation, either version 2 of that License or (at your option) any | ||
21 | * later version. | ||
22 | * | ||
23 | * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor "AS IS" AND ANY | ||
24 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
26 | * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY | ||
27 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
28 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
29 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
30 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
32 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | /include/ "fsl/p1022si-pre.dtsi" | ||
36 | / { | ||
37 | model = "fsl,P1022DS"; | ||
38 | compatible = "fsl,P1022DS"; | ||
39 | |||
40 | memory { | ||
41 | device_type = "memory"; | ||
42 | }; | ||
43 | |||
44 | board_lbc: lbc: localbus@fffe05000 { | ||
45 | ranges = <0x0 0x0 0xf 0xe8000000 0x08000000 | ||
46 | 0x1 0x0 0xf 0xe0000000 0x08000000 | ||
47 | 0x2 0x0 0xf 0xff800000 0x00040000 | ||
48 | 0x3 0x0 0xf 0xffdf0000 0x00008000>; | ||
49 | reg = <0xf 0xffe05000 0 0x1000>; | ||
50 | }; | ||
51 | |||
52 | board_soc: soc: soc@fffe00000 { | ||
53 | ranges = <0x0 0xf 0xffe00000 0x100000>; | ||
54 | }; | ||
55 | |||
56 | pci0: pcie@fffe09000 { | ||
57 | ranges = <0x2000000 0x0 0xe0000000 0xc 0x20000000 0x0 0x20000000 | ||
58 | 0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>; | ||
59 | reg = <0xf 0xffe09000 0 0x1000>; | ||
60 | pcie@0 { | ||
61 | ranges = <0x2000000 0x0 0xe0000000 | ||
62 | 0x2000000 0x0 0xe0000000 | ||
63 | 0x0 0x20000000 | ||
64 | |||
65 | 0x1000000 0x0 0x0 | ||
66 | 0x1000000 0x0 0x0 | ||
67 | 0x0 0x100000>; | ||
68 | }; | ||
69 | }; | ||
70 | |||
71 | pci1: pcie@fffe0a000 { | ||
72 | ranges = <0x2000000 0x0 0xe0000000 0xc 0x40000000 0x0 0x20000000 | ||
73 | 0x1000000 0x0 0x00000000 0xf 0xffc20000 0x0 0x10000>; | ||
74 | reg = <0xf 0xffe0a000 0 0x1000>; | ||
75 | pcie@0 { | ||
76 | ranges = <0x2000000 0x0 0xe0000000 | ||
77 | 0x2000000 0x0 0xe0000000 | ||
78 | 0x0 0x20000000 | ||
79 | |||
80 | 0x1000000 0x0 0x0 | ||
81 | 0x1000000 0x0 0x0 | ||
82 | 0x0 0x100000>; | ||
83 | }; | ||
84 | }; | ||
85 | |||
86 | pci2: pcie@fffe0b000 { | ||
87 | ranges = <0x2000000 0x0 0xe0000000 0xc 0x00000000 0x0 0x20000000 | ||
88 | 0x1000000 0x0 0x00000000 0xf 0xffc00000 0x0 0x10000>; | ||
89 | reg = <0xf 0xffe0b000 0 0x1000>; | ||
90 | pcie@0 { | ||
91 | ranges = <0x2000000 0x0 0xe0000000 | ||
92 | 0x2000000 0x0 0xe0000000 | ||
93 | 0x0 0x20000000 | ||
94 | |||
95 | 0x1000000 0x0 0x0 | ||
96 | 0x1000000 0x0 0x0 | ||
97 | 0x0 0x100000>; | ||
98 | }; | ||
99 | }; | ||
100 | }; | ||
101 | |||
102 | /include/ "fsl/p1022si-post.dtsi" | ||
103 | /include/ "p1022ds.dtsi" | ||
diff --git a/arch/powerpc/boot/dts/p1025rdb.dtsi b/arch/powerpc/boot/dts/p1025rdb.dtsi new file mode 100644 index 000000000000..cf3676fc714b --- /dev/null +++ b/arch/powerpc/boot/dts/p1025rdb.dtsi | |||
@@ -0,0 +1,286 @@ | |||
1 | /* | ||
2 | * P1025 RDB Device Tree Source stub (no addresses or top-level ranges) | ||
3 | * | ||
4 | * Copyright 2011 Freescale Semiconductor Inc. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions are met: | ||
8 | * * Redistributions of source code must retain the above copyright | ||
9 | * notice, this list of conditions and the following disclaimer. | ||
10 | * * Redistributions in binary form must reproduce the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer in the | ||
12 | * documentation and/or other materials provided with the distribution. | ||
13 | * * Neither the name of Freescale Semiconductor nor the | ||
14 | * names of its contributors may be used to endorse or promote products | ||
15 | * derived from this software without specific prior written permission. | ||
16 | * | ||
17 | * | ||
18 | * ALTERNATIVELY, this software may be distributed under the terms of the | ||
19 | * GNU General Public License ("GPL") as published by the Free Software | ||
20 | * Foundation, either version 2 of that License or (at your option) any | ||
21 | * later version. | ||
22 | * | ||
23 | * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY | ||
24 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
26 | * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY | ||
27 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
28 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
29 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
30 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
32 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | &lbc { | ||
36 | nor@0,0 { | ||
37 | #address-cells = <1>; | ||
38 | #size-cells = <1>; | ||
39 | compatible = "cfi-flash"; | ||
40 | reg = <0x0 0x0 0x1000000>; | ||
41 | bank-width = <2>; | ||
42 | device-width = <1>; | ||
43 | |||
44 | partition@0 { | ||
45 | /* This location must not be altered */ | ||
46 | /* 256KB for Vitesse 7385 Switch firmware */ | ||
47 | reg = <0x0 0x00040000>; | ||
48 | label = "NOR Vitesse-7385 Firmware"; | ||
49 | read-only; | ||
50 | }; | ||
51 | |||
52 | partition@40000 { | ||
53 | /* 256KB for DTB Image */ | ||
54 | reg = <0x00040000 0x00040000>; | ||
55 | label = "NOR DTB Image"; | ||
56 | }; | ||
57 | |||
58 | partition@80000 { | ||
59 | /* 3.5 MB for Linux Kernel Image */ | ||
60 | reg = <0x00080000 0x00380000>; | ||
61 | label = "NOR Linux Kernel Image"; | ||
62 | }; | ||
63 | |||
64 | partition@400000 { | ||
65 | /* 11MB for JFFS2 based Root file System */ | ||
66 | reg = <0x00400000 0x00b00000>; | ||
67 | label = "NOR JFFS2 Root File System"; | ||
68 | }; | ||
69 | |||
70 | partition@f00000 { | ||
71 | /* This location must not be altered */ | ||
72 | /* 512KB for u-boot Bootloader Image */ | ||
73 | /* 512KB for u-boot Environment Variables */ | ||
74 | reg = <0x00f00000 0x00100000>; | ||
75 | label = "NOR U-Boot Image"; | ||
76 | read-only; | ||
77 | }; | ||
78 | }; | ||
79 | |||
80 | nand@1,0 { | ||
81 | #address-cells = <1>; | ||
82 | #size-cells = <1>; | ||
83 | compatible = "fsl,p1025-fcm-nand", | ||
84 | "fsl,elbc-fcm-nand"; | ||
85 | reg = <0x1 0x0 0x40000>; | ||
86 | |||
87 | partition@0 { | ||
88 | /* This location must not be altered */ | ||
89 | /* 1MB for u-boot Bootloader Image */ | ||
90 | reg = <0x0 0x00100000>; | ||
91 | label = "NAND U-Boot Image"; | ||
92 | read-only; | ||
93 | }; | ||
94 | |||
95 | partition@100000 { | ||
96 | /* 1MB for DTB Image */ | ||
97 | reg = <0x00100000 0x00100000>; | ||
98 | label = "NAND DTB Image"; | ||
99 | }; | ||
100 | |||
101 | partition@200000 { | ||
102 | /* 4MB for Linux Kernel Image */ | ||
103 | reg = <0x00200000 0x00400000>; | ||
104 | label = "NAND Linux Kernel Image"; | ||
105 | }; | ||
106 | |||
107 | partition@600000 { | ||
108 | /* 4MB for Compressed Root file System Image */ | ||
109 | reg = <0x00600000 0x00400000>; | ||
110 | label = "NAND Compressed RFS Image"; | ||
111 | }; | ||
112 | |||
113 | partition@a00000 { | ||
114 | /* 7MB for JFFS2 based Root file System */ | ||
115 | reg = <0x00a00000 0x00700000>; | ||
116 | label = "NAND JFFS2 Root File System"; | ||
117 | }; | ||
118 | |||
119 | partition@1100000 { | ||
120 | /* 15MB for JFFS2 based Root file System */ | ||
121 | reg = <0x01100000 0x00f00000>; | ||
122 | label = "NAND Writable User area"; | ||
123 | }; | ||
124 | }; | ||
125 | |||
126 | }; | ||
127 | |||
128 | &soc { | ||
129 | i2c@3000 { | ||
130 | rtc@68 { | ||
131 | compatible = "dallas,ds1339"; | ||
132 | reg = <0x68>; | ||
133 | }; | ||
134 | }; | ||
135 | |||
136 | spi@7000 { | ||
137 | flash@0 { | ||
138 | #address-cells = <1>; | ||
139 | #size-cells = <1>; | ||
140 | compatible = "spansion,s25sl12801"; | ||
141 | reg = <0>; | ||
142 | spi-max-frequency = <40000000>; /* input clock */ | ||
143 | |||
144 | partition@u-boot { | ||
145 | /* 512KB for u-boot Bootloader Image */ | ||
146 | reg = <0x0 0x00080000>; | ||
147 | label = "u-boot"; | ||
148 | read-only; | ||
149 | }; | ||
150 | |||
151 | partition@dtb { | ||
152 | /* 512KB for DTB Image */ | ||
153 | reg = <0x00080000 0x00080000>; | ||
154 | label = "dtb"; | ||
155 | }; | ||
156 | |||
157 | partition@kernel { | ||
158 | /* 4MB for Linux Kernel Image */ | ||
159 | reg = <0x00100000 0x00400000>; | ||
160 | label = "kernel"; | ||
161 | }; | ||
162 | |||
163 | partition@fs { | ||
164 | /* 4MB for Compressed RFS Image */ | ||
165 | reg = <0x00500000 0x00400000>; | ||
166 | label = "file system"; | ||
167 | }; | ||
168 | |||
169 | partition@jffs-fs { | ||
170 | /* 7MB for JFFS2 based RFS */ | ||
171 | reg = <0x00900000 0x00700000>; | ||
172 | label = "file system jffs2"; | ||
173 | }; | ||
174 | }; | ||
175 | }; | ||
176 | |||
177 | usb@22000 { | ||
178 | phy_type = "ulpi"; | ||
179 | }; | ||
180 | |||
181 | /* USB2 is shared with localbus, so it must be disabled | ||
182 | by default. We can't put 'status = "disabled";' here | ||
183 | since U-Boot doesn't clear the status property when | ||
184 | it enables USB2. OTOH, U-Boot does create a new node | ||
185 | when there isn't any. So, just comment it out. | ||
186 | usb@23000 { | ||
187 | phy_type = "ulpi"; | ||
188 | }; | ||
189 | */ | ||
190 | |||
191 | mdio@24000 { | ||
192 | phy0: ethernet-phy@0 { | ||
193 | interrupt-parent = <&mpic>; | ||
194 | interrupts = <3 1>; | ||
195 | reg = <0x0>; | ||
196 | }; | ||
197 | |||
198 | phy1: ethernet-phy@1 { | ||
199 | interrupt-parent = <&mpic>; | ||
200 | interrupts = <2 1>; | ||
201 | reg = <0x1>; | ||
202 | }; | ||
203 | |||
204 | tbi0: tbi-phy@11 { | ||
205 | reg = <0x11>; | ||
206 | device_type = "tbi-phy"; | ||
207 | }; | ||
208 | }; | ||
209 | |||
210 | mdio@25000 { | ||
211 | tbi1: tbi-phy@11 { | ||
212 | reg = <0x11>; | ||
213 | device_type = "tbi-phy"; | ||
214 | }; | ||
215 | }; | ||
216 | |||
217 | mdio@26000 { | ||
218 | tbi2: tbi-phy@11 { | ||
219 | reg = <0x11>; | ||
220 | device_type = "tbi-phy"; | ||
221 | }; | ||
222 | }; | ||
223 | |||
224 | enet0: ethernet@b0000 { | ||
225 | fixed-link = <1 1 1000 0 0>; | ||
226 | phy-connection-type = "rgmii-id"; | ||
227 | |||
228 | }; | ||
229 | |||
230 | enet1: ethernet@b1000 { | ||
231 | phy-handle = <&phy0>; | ||
232 | tbi-handle = <&tbi1>; | ||
233 | phy-connection-type = "sgmii"; | ||
234 | }; | ||
235 | |||
236 | enet2: ethernet@b2000 { | ||
237 | phy-handle = <&phy1>; | ||
238 | phy-connection-type = "rgmii-id"; | ||
239 | }; | ||
240 | |||
241 | par_io@e0100 { | ||
242 | #address-cells = <1>; | ||
243 | #size-cells = <1>; | ||
244 | reg = <0xe0100 0x60>; | ||
245 | ranges = <0x0 0xe0100 0x60>; | ||
246 | device_type = "par_io"; | ||
247 | num-ports = <3>; | ||
248 | pio1: ucc_pin@01 { | ||
249 | pio-map = < | ||
250 | /* port pin dir open_drain assignment has_irq */ | ||
251 | 0x1 0x13 0x1 0x0 0x1 0x0 /* QE_MUX_MDC */ | ||
252 | 0x1 0x14 0x3 0x0 0x1 0x0 /* QE_MUX_MDIO */ | ||
253 | 0x0 0x17 0x2 0x0 0x2 0x0 /* CLK12 */ | ||
254 | 0x0 0x18 0x2 0x0 0x1 0x0 /* CLK9 */ | ||
255 | 0x0 0x7 0x1 0x0 0x2 0x0 /* ENET1_TXD0_SER1_TXD0 */ | ||
256 | 0x0 0x9 0x1 0x0 0x2 0x0 /* ENET1_TXD1_SER1_TXD1 */ | ||
257 | 0x0 0xb 0x1 0x0 0x2 0x0 /* ENET1_TXD2_SER1_TXD2 */ | ||
258 | 0x0 0xc 0x1 0x0 0x2 0x0 /* ENET1_TXD3_SER1_TXD3 */ | ||
259 | 0x0 0x6 0x2 0x0 0x2 0x0 /* ENET1_RXD0_SER1_RXD0 */ | ||
260 | 0x0 0xa 0x2 0x0 0x2 0x0 /* ENET1_RXD1_SER1_RXD1 */ | ||
261 | 0x0 0xe 0x2 0x0 0x2 0x0 /* ENET1_RXD2_SER1_RXD2 */ | ||
262 | 0x0 0xf 0x2 0x0 0x2 0x0 /* ENET1_RXD3_SER1_RXD3 */ | ||
263 | 0x0 0x5 0x1 0x0 0x2 0x0 /* ENET1_TX_EN_SER1_RTS_B */ | ||
264 | 0x0 0xd 0x1 0x0 0x2 0x0 /* ENET1_TX_ER */ | ||
265 | 0x0 0x4 0x2 0x0 0x2 0x0 /* ENET1_RX_DV_SER1_CTS_B */ | ||
266 | 0x0 0x8 0x2 0x0 0x2 0x0 /* ENET1_RX_ER_SER1_CD_B */ | ||
267 | 0x0 0x11 0x2 0x0 0x2 0x0 /* ENET1_CRS */ | ||
268 | 0x0 0x10 0x2 0x0 0x2 0x0>; /* ENET1_COL */ | ||
269 | }; | ||
270 | |||
271 | pio2: ucc_pin@02 { | ||
272 | pio-map = < | ||
273 | /* port pin dir open_drain assignment has_irq */ | ||
274 | 0x1 0x13 0x1 0x0 0x1 0x0 /* QE_MUX_MDC */ | ||
275 | 0x1 0x14 0x3 0x0 0x1 0x0 /* QE_MUX_MDIO */ | ||
276 | 0x1 0xb 0x2 0x0 0x1 0x0 /* CLK13 */ | ||
277 | 0x1 0x7 0x1 0x0 0x2 0x0 /* ENET5_TXD0_SER5_TXD0 */ | ||
278 | 0x1 0xa 0x1 0x0 0x2 0x0 /* ENET5_TXD1_SER5_TXD1 */ | ||
279 | 0x1 0x6 0x2 0x0 0x2 0x0 /* ENET5_RXD0_SER5_RXD0 */ | ||
280 | 0x1 0x9 0x2 0x0 0x2 0x0 /* ENET5_RXD1_SER5_RXD1 */ | ||
281 | 0x1 0x5 0x1 0x0 0x2 0x0 /* ENET5_TX_EN_SER5_RTS_B */ | ||
282 | 0x1 0x4 0x2 0x0 0x2 0x0 /* ENET5_RX_DV_SER5_CTS_B */ | ||
283 | 0x1 0x8 0x2 0x0 0x2 0x0>; /* ENET5_RX_ER_SER5_CD_B */ | ||
284 | }; | ||
285 | }; | ||
286 | }; | ||
diff --git a/arch/powerpc/boot/dts/p1025rdb_32b.dts b/arch/powerpc/boot/dts/p1025rdb_32b.dts new file mode 100644 index 000000000000..ac5729c14eda --- /dev/null +++ b/arch/powerpc/boot/dts/p1025rdb_32b.dts | |||
@@ -0,0 +1,135 @@ | |||
1 | /* | ||
2 | * P1025 RDB Device Tree Source (32-bit address map) | ||
3 | * | ||
4 | * Copyright 2011 Freescale Semiconductor Inc. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions are met: | ||
8 | * * Redistributions of source code must retain the above copyright | ||
9 | * notice, this list of conditions and the following disclaimer. | ||
10 | * * Redistributions in binary form must reproduce the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer in the | ||
12 | * documentation and/or other materials provided with the distribution. | ||
13 | * * Neither the name of Freescale Semiconductor nor the | ||
14 | * names of its contributors may be used to endorse or promote products | ||
15 | * derived from this software without specific prior written permission. | ||
16 | * | ||
17 | * | ||
18 | * ALTERNATIVELY, this software may be distributed under the terms of the | ||
19 | * GNU General Public License ("GPL") as published by the Free Software | ||
20 | * Foundation, either version 2 of that License or (at your option) any | ||
21 | * later version. | ||
22 | * | ||
23 | * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY | ||
24 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
26 | * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY | ||
27 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
28 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
29 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
30 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
32 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | /include/ "fsl/p1021si-pre.dtsi" | ||
36 | / { | ||
37 | model = "fsl,P1025RDB"; | ||
38 | compatible = "fsl,P1025RDB"; | ||
39 | |||
40 | memory { | ||
41 | device_type = "memory"; | ||
42 | }; | ||
43 | |||
44 | lbc: localbus@ffe05000 { | ||
45 | reg = <0 0xffe05000 0 0x1000>; | ||
46 | |||
47 | /* NOR, NAND Flashes */ | ||
48 | ranges = <0x0 0x0 0x0 0xef000000 0x01000000 | ||
49 | 0x1 0x0 0x0 0xff800000 0x00040000>; | ||
50 | }; | ||
51 | |||
52 | soc: soc@ffe00000 { | ||
53 | ranges = <0x0 0x0 0xffe00000 0x100000>; | ||
54 | }; | ||
55 | |||
56 | pci0: pcie@ffe09000 { | ||
57 | ranges = <0x2000000 0x0 0xe0000000 0 0xe0000000 0x0 0x20000000 | ||
58 | 0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>; | ||
59 | reg = <0 0xffe09000 0 0x1000>; | ||
60 | pcie@0 { | ||
61 | ranges = <0x2000000 0x0 0xe0000000 | ||
62 | 0x2000000 0x0 0xe0000000 | ||
63 | 0x0 0x20000000 | ||
64 | |||
65 | 0x1000000 0x0 0x0 | ||
66 | 0x1000000 0x0 0x0 | ||
67 | 0x0 0x100000>; | ||
68 | }; | ||
69 | }; | ||
70 | |||
71 | pci1: pcie@ffe0a000 { | ||
72 | reg = <0 0xffe0a000 0 0x1000>; | ||
73 | ranges = <0x2000000 0x0 0xe0000000 0 0xe0000000 0x0 0x20000000 | ||
74 | 0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>; | ||
75 | pcie@0 { | ||
76 | ranges = <0x2000000 0x0 0xe0000000 | ||
77 | 0x2000000 0x0 0xe0000000 | ||
78 | 0x0 0x20000000 | ||
79 | |||
80 | 0x1000000 0x0 0x0 | ||
81 | 0x1000000 0x0 0x0 | ||
82 | 0x0 0x100000>; | ||
83 | }; | ||
84 | }; | ||
85 | |||
86 | qe: qe@ffe80000 { | ||
87 | ranges = <0x0 0x0 0xffe80000 0x40000>; | ||
88 | reg = <0 0xffe80000 0 0x480>; | ||
89 | brg-frequency = <0>; | ||
90 | bus-frequency = <0>; | ||
91 | status = "disabled"; /* no firmware loaded */ | ||
92 | |||
93 | enet3: ucc@2000 { | ||
94 | device_type = "network"; | ||
95 | compatible = "ucc_geth"; | ||
96 | rx-clock-name = "clk12"; | ||
97 | tx-clock-name = "clk9"; | ||
98 | pio-handle = <&pio1>; | ||
99 | phy-handle = <&qe_phy0>; | ||
100 | phy-connection-type = "mii"; | ||
101 | }; | ||
102 | |||
103 | mdio@2120 { | ||
104 | qe_phy0: ethernet-phy@0 { | ||
105 | interrupt-parent = <&mpic>; | ||
106 | interrupts = <4 1 0 0>; | ||
107 | reg = <0x6>; | ||
108 | device_type = "ethernet-phy"; | ||
109 | }; | ||
110 | qe_phy1: ethernet-phy@03 { | ||
111 | interrupt-parent = <&mpic>; | ||
112 | interrupts = <5 1 0 0>; | ||
113 | reg = <0x3>; | ||
114 | device_type = "ethernet-phy"; | ||
115 | }; | ||
116 | tbi-phy@11 { | ||
117 | reg = <0x11>; | ||
118 | device_type = "tbi-phy"; | ||
119 | }; | ||
120 | }; | ||
121 | |||
122 | enet4: ucc@2400 { | ||
123 | device_type = "network"; | ||
124 | compatible = "ucc_geth"; | ||
125 | rx-clock-name = "none"; | ||
126 | tx-clock-name = "clk13"; | ||
127 | pio-handle = <&pio2>; | ||
128 | phy-handle = <&qe_phy1>; | ||
129 | phy-connection-type = "rmii"; | ||
130 | }; | ||
131 | }; | ||
132 | }; | ||
133 | |||
134 | /include/ "p1025rdb.dtsi" | ||
135 | /include/ "fsl/p1021si-post.dtsi" | ||
diff --git a/arch/powerpc/boot/dts/p1025rdb_36b.dts b/arch/powerpc/boot/dts/p1025rdb_36b.dts new file mode 100644 index 000000000000..4ce4bfa0eda4 --- /dev/null +++ b/arch/powerpc/boot/dts/p1025rdb_36b.dts | |||
@@ -0,0 +1,88 @@ | |||
1 | /* | ||
2 | * P1025 RDB Device Tree Source (36-bit address map) | ||
3 | * | ||
4 | * Copyright 2011 Freescale Semiconductor Inc. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions are met: | ||
8 | * * Redistributions of source code must retain the above copyright | ||
9 | * notice, this list of conditions and the following disclaimer. | ||
10 | * * Redistributions in binary form must reproduce the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer in the | ||
12 | * documentation and/or other materials provided with the distribution. | ||
13 | * * Neither the name of Freescale Semiconductor nor the | ||
14 | * names of its contributors may be used to endorse or promote products | ||
15 | * derived from this software without specific prior written permission. | ||
16 | * | ||
17 | * | ||
18 | * ALTERNATIVELY, this software may be distributed under the terms of the | ||
19 | * GNU General Public License ("GPL") as published by the Free Software | ||
20 | * Foundation, either version 2 of that License or (at your option) any | ||
21 | * later version. | ||
22 | * | ||
23 | * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY | ||
24 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
26 | * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY | ||
27 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
28 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
29 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
30 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
32 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | /include/ "fsl/p1021si-pre.dtsi" | ||
36 | / { | ||
37 | model = "fsl,P1025RDB"; | ||
38 | compatible = "fsl,P1025RDB"; | ||
39 | |||
40 | memory { | ||
41 | device_type = "memory"; | ||
42 | }; | ||
43 | |||
44 | lbc: localbus@fffe05000 { | ||
45 | reg = <0xf 0xffe05000 0 0x1000>; | ||
46 | |||
47 | /* NOR, NAND Flashes */ | ||
48 | ranges = <0x0 0x0 0xf 0xef000000 0x01000000 | ||
49 | 0x1 0x0 0xf 0xff800000 0x00040000>; | ||
50 | }; | ||
51 | |||
52 | soc: soc@fffe00000 { | ||
53 | ranges = <0x0 0xf 0xffe00000 0x100000>; | ||
54 | }; | ||
55 | |||
56 | pci0: pcie@fffe09000 { | ||
57 | reg = <0xf 0xffe09000 0 0x1000>; | ||
58 | ranges = <0x2000000 0x0 0xe0000000 0xe 0x20000000 0x0 0x20000000 | ||
59 | 0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>; | ||
60 | pcie@0 { | ||
61 | ranges = <0x2000000 0x0 0xe0000000 | ||
62 | 0x2000000 0x0 0xe0000000 | ||
63 | 0x0 0x20000000 | ||
64 | |||
65 | 0x1000000 0x0 0x0 | ||
66 | 0x1000000 0x0 0x0 | ||
67 | 0x0 0x100000>; | ||
68 | }; | ||
69 | }; | ||
70 | |||
71 | pci1: pcie@fffe0a000 { | ||
72 | reg = <0xf 0xffe0a000 0 0x1000>; | ||
73 | ranges = <0x2000000 0x0 0xe0000000 0xc 0x00000000 0x0 0x20000000 | ||
74 | 0x1000000 0x0 0x00000000 0xf 0xffc00000 0x0 0x10000>; | ||
75 | pcie@0 { | ||
76 | ranges = <0x2000000 0x0 0xe0000000 | ||
77 | 0x2000000 0x0 0xe0000000 | ||
78 | 0x0 0x20000000 | ||
79 | |||
80 | 0x1000000 0x0 0x0 | ||
81 | 0x1000000 0x0 0x0 | ||
82 | 0x0 0x100000>; | ||
83 | }; | ||
84 | }; | ||
85 | }; | ||
86 | |||
87 | /include/ "p1025rdb.dtsi" | ||
88 | /include/ "fsl/p1021si-post.dtsi" | ||
diff --git a/arch/powerpc/boot/dts/p2020rdb-pc.dtsi b/arch/powerpc/boot/dts/p2020rdb-pc.dtsi new file mode 100644 index 000000000000..c21d1c7d16cd --- /dev/null +++ b/arch/powerpc/boot/dts/p2020rdb-pc.dtsi | |||
@@ -0,0 +1,241 @@ | |||
1 | /* | ||
2 | * P2020 RDB-PC Device Tree Source stub (no addresses or top-level ranges) | ||
3 | * | ||
4 | * Copyright 2011 Freescale Semiconductor Inc. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions are met: | ||
8 | * * Redistributions of source code must retain the above copyright | ||
9 | * notice, this list of conditions and the following disclaimer. | ||
10 | * * Redistributions in binary form must reproduce the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer in the | ||
12 | * documentation and/or other materials provided with the distribution. | ||
13 | * * Neither the name of Freescale Semiconductor nor the | ||
14 | * names of its contributors may be used to endorse or promote products | ||
15 | * derived from this software without specific prior written permission. | ||
16 | * | ||
17 | * | ||
18 | * ALTERNATIVELY, this software may be distributed under the terms of the | ||
19 | * GNU General Public License ("GPL") as published by the Free Software | ||
20 | * Foundation, either version 2 of that License or (at your option) any | ||
21 | * later version. | ||
22 | * | ||
23 | * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY | ||
24 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
26 | * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY | ||
27 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
28 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
29 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
30 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
32 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | &lbc { | ||
36 | nor@0,0 { | ||
37 | #address-cells = <1>; | ||
38 | #size-cells = <1>; | ||
39 | compatible = "cfi-flash"; | ||
40 | reg = <0x0 0x0 0x1000000>; | ||
41 | bank-width = <2>; | ||
42 | device-width = <1>; | ||
43 | |||
44 | partition@0 { | ||
45 | /* This location must not be altered */ | ||
46 | /* 256KB for Vitesse 7385 Switch firmware */ | ||
47 | reg = <0x0 0x00040000>; | ||
48 | label = "NOR Vitesse-7385 Firmware"; | ||
49 | read-only; | ||
50 | }; | ||
51 | |||
52 | partition@40000 { | ||
53 | /* 256KB for DTB Image */ | ||
54 | reg = <0x00040000 0x00040000>; | ||
55 | label = "NOR DTB Image"; | ||
56 | }; | ||
57 | |||
58 | partition@80000 { | ||
59 | /* 3.5 MB for Linux Kernel Image */ | ||
60 | reg = <0x00080000 0x00380000>; | ||
61 | label = "NOR Linux Kernel Image"; | ||
62 | }; | ||
63 | |||
64 | partition@400000 { | ||
65 | /* 11MB for JFFS2 based Root file System */ | ||
66 | reg = <0x00400000 0x00b00000>; | ||
67 | label = "NOR JFFS2 Root File System"; | ||
68 | }; | ||
69 | |||
70 | partition@f00000 { | ||
71 | /* This location must not be altered */ | ||
72 | /* 512KB for u-boot Bootloader Image */ | ||
73 | /* 512KB for u-boot Environment Variables */ | ||
74 | reg = <0x00f00000 0x00100000>; | ||
75 | label = "NOR U-Boot Image"; | ||
76 | read-only; | ||
77 | }; | ||
78 | }; | ||
79 | |||
80 | nand@1,0 { | ||
81 | #address-cells = <1>; | ||
82 | #size-cells = <1>; | ||
83 | compatible = "fsl,p2020-fcm-nand", | ||
84 | "fsl,elbc-fcm-nand"; | ||
85 | reg = <0x1 0x0 0x40000>; | ||
86 | |||
87 | partition@0 { | ||
88 | /* This location must not be altered */ | ||
89 | /* 1MB for u-boot Bootloader Image */ | ||
90 | reg = <0x0 0x00100000>; | ||
91 | label = "NAND U-Boot Image"; | ||
92 | read-only; | ||
93 | }; | ||
94 | |||
95 | partition@100000 { | ||
96 | /* 1MB for DTB Image */ | ||
97 | reg = <0x00100000 0x00100000>; | ||
98 | label = "NAND DTB Image"; | ||
99 | }; | ||
100 | |||
101 | partition@200000 { | ||
102 | /* 4MB for Linux Kernel Image */ | ||
103 | reg = <0x00200000 0x00400000>; | ||
104 | label = "NAND Linux Kernel Image"; | ||
105 | }; | ||
106 | |||
107 | partition@600000 { | ||
108 | /* 4MB for Compressed Root file System Image */ | ||
109 | reg = <0x00600000 0x00400000>; | ||
110 | label = "NAND Compressed RFS Image"; | ||
111 | }; | ||
112 | |||
113 | partition@a00000 { | ||
114 | /* 7MB for JFFS2 based Root file System */ | ||
115 | reg = <0x00a00000 0x00700000>; | ||
116 | label = "NAND JFFS2 Root File System"; | ||
117 | }; | ||
118 | |||
119 | partition@1100000 { | ||
120 | /* 15MB for JFFS2 based Root file System */ | ||
121 | reg = <0x01100000 0x00f00000>; | ||
122 | label = "NAND Writable User area"; | ||
123 | }; | ||
124 | }; | ||
125 | |||
126 | L2switch@2,0 { | ||
127 | #address-cells = <1>; | ||
128 | #size-cells = <1>; | ||
129 | compatible = "vitesse-7385"; | ||
130 | reg = <0x2 0x0 0x20000>; | ||
131 | }; | ||
132 | |||
133 | cpld@3,0 { | ||
134 | #address-cells = <1>; | ||
135 | #size-cells = <1>; | ||
136 | compatible = "cpld"; | ||
137 | reg = <0x3 0x0 0x20000>; | ||
138 | read-only; | ||
139 | }; | ||
140 | }; | ||
141 | |||
142 | &soc { | ||
143 | i2c@3000 { | ||
144 | rtc@68 { | ||
145 | compatible = "pericom,pt7c4338"; | ||
146 | reg = <0x68>; | ||
147 | }; | ||
148 | }; | ||
149 | |||
150 | spi@7000 { | ||
151 | flash@0 { | ||
152 | #address-cells = <1>; | ||
153 | #size-cells = <1>; | ||
154 | compatible = "spansion,m25p80"; | ||
155 | reg = <0>; | ||
156 | spi-max-frequency = <40000000>; | ||
157 | |||
158 | partition@0 { | ||
159 | /* 512KB for u-boot Bootloader Image */ | ||
160 | reg = <0x0 0x00080000>; | ||
161 | label = "SPI U-Boot Image"; | ||
162 | read-only; | ||
163 | }; | ||
164 | |||
165 | partition@80000 { | ||
166 | /* 512KB for DTB Image */ | ||
167 | reg = <0x00080000 0x00080000>; | ||
168 | label = "SPI DTB Image"; | ||
169 | }; | ||
170 | |||
171 | partition@100000 { | ||
172 | /* 4MB for Linux Kernel Image */ | ||
173 | reg = <0x00100000 0x00400000>; | ||
174 | label = "SPI Linux Kernel Image"; | ||
175 | }; | ||
176 | |||
177 | partition@500000 { | ||
178 | /* 4MB for Compressed RFS Image */ | ||
179 | reg = <0x00500000 0x00400000>; | ||
180 | label = "SPI Compressed RFS Image"; | ||
181 | }; | ||
182 | |||
183 | partition@900000 { | ||
184 | /* 7MB for JFFS2 based RFS */ | ||
185 | reg = <0x00900000 0x00700000>; | ||
186 | label = "SPI JFFS2 RFS"; | ||
187 | }; | ||
188 | }; | ||
189 | }; | ||
190 | |||
191 | usb@22000 { | ||
192 | phy_type = "ulpi"; | ||
193 | }; | ||
194 | |||
195 | mdio@24520 { | ||
196 | phy0: ethernet-phy@0 { | ||
197 | interrupts = <3 1 0 0>; | ||
198 | reg = <0x0>; | ||
199 | }; | ||
200 | phy1: ethernet-phy@1 { | ||
201 | interrupts = <2 1 0 0>; | ||
202 | reg = <0x1>; | ||
203 | }; | ||
204 | }; | ||
205 | |||
206 | mdio@25520 { | ||
207 | tbi0: tbi-phy@11 { | ||
208 | reg = <0x11>; | ||
209 | device_type = "tbi-phy"; | ||
210 | }; | ||
211 | }; | ||
212 | |||
213 | mdio@26520 { | ||
214 | status = "disabled"; | ||
215 | }; | ||
216 | |||
217 | ptp_clock@24e00 { | ||
218 | fsl,tclk-period = <5>; | ||
219 | fsl,tmr-prsc = <200>; | ||
220 | fsl,tmr-add = <0xCCCCCCCD>; | ||
221 | fsl,tmr-fiper1 = <0x3B9AC9FB>; | ||
222 | fsl,tmr-fiper2 = <0x0001869B>; | ||
223 | fsl,max-adj = <249999999>; | ||
224 | }; | ||
225 | |||
226 | enet0: ethernet@24000 { | ||
227 | fixed-link = <1 1 1000 0 0>; | ||
228 | phy-connection-type = "rgmii-id"; | ||
229 | }; | ||
230 | |||
231 | enet1: ethernet@25000 { | ||
232 | tbi-handle = <&tbi0>; | ||
233 | phy-handle = <&phy0>; | ||
234 | phy-connection-type = "sgmii"; | ||
235 | }; | ||
236 | |||
237 | enet2: ethernet@26000 { | ||
238 | phy-handle = <&phy1>; | ||
239 | phy-connection-type = "rgmii-id"; | ||
240 | }; | ||
241 | }; | ||
diff --git a/arch/powerpc/boot/dts/p2020rdb-pc_32b.dts b/arch/powerpc/boot/dts/p2020rdb-pc_32b.dts new file mode 100644 index 000000000000..852e5b27485d --- /dev/null +++ b/arch/powerpc/boot/dts/p2020rdb-pc_32b.dts | |||
@@ -0,0 +1,96 @@ | |||
1 | /* | ||
2 | * P2020 RDB-PC 32Bit Physical Address Map Device Tree Source | ||
3 | * | ||
4 | * Copyright 2011 Freescale Semiconductor Inc. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions are met: | ||
8 | * * Redistributions of source code must retain the above copyright | ||
9 | * notice, this list of conditions and the following disclaimer. | ||
10 | * * Redistributions in binary form must reproduce the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer in the | ||
12 | * documentation and/or other materials provided with the distribution. | ||
13 | * * Neither the name of Freescale Semiconductor nor the | ||
14 | * names of its contributors may be used to endorse or promote products | ||
15 | * derived from this software without specific prior written permission. | ||
16 | * | ||
17 | * | ||
18 | * ALTERNATIVELY, this software may be distributed under the terms of the | ||
19 | * GNU General Public License ("GPL") as published by the Free Software | ||
20 | * Foundation, either version 2 of that License or (at your option) any | ||
21 | * later version. | ||
22 | * | ||
23 | * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY | ||
24 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
26 | * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY | ||
27 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
28 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
29 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
30 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
32 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | /include/ "fsl/p2020si-pre.dtsi" | ||
36 | |||
37 | / { | ||
38 | model = "fsl,P2020RDB"; | ||
39 | compatible = "fsl,P2020RDB-PC"; | ||
40 | |||
41 | memory { | ||
42 | device_type = "memory"; | ||
43 | }; | ||
44 | |||
45 | lbc: localbus@ffe05000 { | ||
46 | reg = <0 0xffe05000 0 0x1000>; | ||
47 | |||
48 | /* NOR and NAND Flashes */ | ||
49 | ranges = <0x0 0x0 0x0 0xef000000 0x01000000 | ||
50 | 0x1 0x0 0x0 0xff800000 0x00040000 | ||
51 | 0x2 0x0 0x0 0xffb00000 0x00020000 | ||
52 | 0x3 0x0 0x0 0xffa00000 0x00020000>; | ||
53 | }; | ||
54 | |||
55 | soc: soc@ffe00000 { | ||
56 | ranges = <0x0 0x0 0xffe00000 0x100000>; | ||
57 | }; | ||
58 | |||
59 | pci0: pcie@ffe08000 { | ||
60 | reg = <0 0xffe08000 0 0x1000>; | ||
61 | status = "disabled"; | ||
62 | }; | ||
63 | |||
64 | pci1: pcie@ffe09000 { | ||
65 | reg = <0 0xffe09000 0 0x1000>; | ||
66 | ranges = <0x2000000 0x0 0xe0000000 0 0xa0000000 0x0 0x20000000 | ||
67 | 0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>; | ||
68 | pcie@0 { | ||
69 | ranges = <0x2000000 0x0 0xe0000000 | ||
70 | 0x2000000 0x0 0xe0000000 | ||
71 | 0x0 0x20000000 | ||
72 | |||
73 | 0x1000000 0x0 0x0 | ||
74 | 0x1000000 0x0 0x0 | ||
75 | 0x0 0x100000>; | ||
76 | }; | ||
77 | }; | ||
78 | |||
79 | pci2: pcie@ffe0a000 { | ||
80 | reg = <0 0xffe0a000 0 0x1000>; | ||
81 | ranges = <0x2000000 0x0 0xe0000000 0 0x80000000 0x0 0x20000000 | ||
82 | 0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>; | ||
83 | pcie@0 { | ||
84 | ranges = <0x2000000 0x0 0xe0000000 | ||
85 | 0x2000000 0x0 0xe0000000 | ||
86 | 0x0 0x20000000 | ||
87 | |||
88 | 0x1000000 0x0 0x0 | ||
89 | 0x1000000 0x0 0x0 | ||
90 | 0x0 0x100000>; | ||
91 | }; | ||
92 | }; | ||
93 | }; | ||
94 | |||
95 | /include/ "p2020rdb-pc.dtsi" | ||
96 | /include/ "fsl/p2020si-post.dtsi" | ||
diff --git a/arch/powerpc/boot/dts/p2020rdb-pc_36b.dts b/arch/powerpc/boot/dts/p2020rdb-pc_36b.dts new file mode 100644 index 000000000000..b5a56ca51cf7 --- /dev/null +++ b/arch/powerpc/boot/dts/p2020rdb-pc_36b.dts | |||
@@ -0,0 +1,96 @@ | |||
1 | /* | ||
2 | * P2020 RDB-PC 36Bit Physical Address Map Device Tree Source | ||
3 | * | ||
4 | * Copyright 2011 Freescale Semiconductor Inc. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions are met: | ||
8 | * * Redistributions of source code must retain the above copyright | ||
9 | * notice, this list of conditions and the following disclaimer. | ||
10 | * * Redistributions in binary form must reproduce the above copyright | ||
11 | * notice, this list of conditions and the following disclaimer in the | ||
12 | * documentation and/or other materials provided with the distribution. | ||
13 | * * Neither the name of Freescale Semiconductor nor the | ||
14 | * names of its contributors may be used to endorse or promote products | ||
15 | * derived from this software without specific prior written permission. | ||
16 | * | ||
17 | * | ||
18 | * ALTERNATIVELY, this software may be distributed under the terms of the | ||
19 | * GNU General Public License ("GPL") as published by the Free Software | ||
20 | * Foundation, either version 2 of that License or (at your option) any | ||
21 | * later version. | ||
22 | * | ||
23 | * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY | ||
24 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
25 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
26 | * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY | ||
27 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
28 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
29 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
30 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
31 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
32 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | /include/ "fsl/p2020si-pre.dtsi" | ||
36 | |||
37 | / { | ||
38 | model = "fsl,P2020RDB"; | ||
39 | compatible = "fsl,P2020RDB-PC"; | ||
40 | |||
41 | memory { | ||
42 | device_type = "memory"; | ||
43 | }; | ||
44 | |||
45 | lbc: localbus@fffe05000 { | ||
46 | reg = <0xf 0xffe05000 0 0x1000>; | ||
47 | |||
48 | /* NOR and NAND Flashes */ | ||
49 | ranges = <0x0 0x0 0xf 0xef000000 0x01000000 | ||
50 | 0x1 0x0 0xf 0xff800000 0x00040000 | ||
51 | 0x2 0x0 0xf 0xffb00000 0x00020000 | ||
52 | 0x3 0x0 0xf 0xffa00000 0x00020000>; | ||
53 | }; | ||
54 | |||
55 | soc: soc@fffe00000 { | ||
56 | ranges = <0x0 0xf 0xffe00000 0x100000>; | ||
57 | }; | ||
58 | |||
59 | pci0: pcie@fffe08000 { | ||
60 | reg = <0xf 0xffe08000 0 0x1000>; | ||
61 | status = "disabled"; | ||
62 | }; | ||
63 | |||
64 | pci1: pcie@fffe09000 { | ||
65 | reg = <0xf 0xffe09000 0 0x1000>; | ||
66 | ranges = <0x2000000 0x0 0xe0000000 0xc 0x20000000 0x0 0x20000000 | ||
67 | 0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>; | ||
68 | pcie@0 { | ||
69 | ranges = <0x2000000 0x0 0xe0000000 | ||
70 | 0x2000000 0x0 0xe0000000 | ||
71 | 0x0 0x20000000 | ||
72 | |||
73 | 0x1000000 0x0 0x0 | ||
74 | 0x1000000 0x0 0x0 | ||
75 | 0x0 0x100000>; | ||
76 | }; | ||
77 | }; | ||
78 | |||
79 | pci2: pcie@fffe0a000 { | ||
80 | reg = <0xf 0xffe0a000 0 0x1000>; | ||
81 | ranges = <0x2000000 0x0 0xe0000000 0xc 0x00000000 0x0 0x20000000 | ||
82 | 0x1000000 0x0 0x00000000 0xf 0xffc00000 0x0 0x10000>; | ||
83 | pcie@0 { | ||
84 | ranges = <0x2000000 0x0 0xe0000000 | ||
85 | 0x2000000 0x0 0xe0000000 | ||
86 | 0x0 0x20000000 | ||
87 | |||
88 | 0x1000000 0x0 0x0 | ||
89 | 0x1000000 0x0 0x0 | ||
90 | 0x0 0x100000>; | ||
91 | }; | ||
92 | }; | ||
93 | }; | ||
94 | |||
95 | /include/ "p2020rdb-pc.dtsi" | ||
96 | /include/ "fsl/p2020si-post.dtsi" | ||
diff --git a/arch/powerpc/boot/dts/p2020rdb.dts b/arch/powerpc/boot/dts/p2020rdb.dts index eb8a6aa2bda5..153bc76bb48e 100644 --- a/arch/powerpc/boot/dts/p2020rdb.dts +++ b/arch/powerpc/boot/dts/p2020rdb.dts | |||
@@ -34,7 +34,7 @@ | |||
34 | 34 | ||
35 | /* NOR and NAND Flashes */ | 35 | /* NOR and NAND Flashes */ |
36 | ranges = <0x0 0x0 0x0 0xef000000 0x01000000 | 36 | ranges = <0x0 0x0 0x0 0xef000000 0x01000000 |
37 | 0x1 0x0 0x0 0xffa00000 0x00040000 | 37 | 0x1 0x0 0x0 0xff800000 0x00040000 |
38 | 0x2 0x0 0x0 0xffb00000 0x00020000>; | 38 | 0x2 0x0 0x0 0xffb00000 0x00020000>; |
39 | 39 | ||
40 | nor@0,0 { | 40 | nor@0,0 { |
@@ -157,7 +157,7 @@ | |||
157 | #size-cells = <1>; | 157 | #size-cells = <1>; |
158 | compatible = "spansion,s25sl12801"; | 158 | compatible = "spansion,s25sl12801"; |
159 | reg = <0>; | 159 | reg = <0>; |
160 | spi-max-frequency = <50000000>; | 160 | spi-max-frequency = <40000000>; |
161 | 161 | ||
162 | partition@0 { | 162 | partition@0 { |
163 | /* 512KB for u-boot Bootloader Image */ | 163 | /* 512KB for u-boot Bootloader Image */ |
diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper index f090e6d2907e..6761c746048d 100755 --- a/arch/powerpc/boot/wrapper +++ b/arch/powerpc/boot/wrapper | |||
@@ -144,6 +144,7 @@ tmp=$tmpdir/zImage.$$.o | |||
144 | ksection=.kernel:vmlinux.strip | 144 | ksection=.kernel:vmlinux.strip |
145 | isection=.kernel:initrd | 145 | isection=.kernel:initrd |
146 | link_address='0x400000' | 146 | link_address='0x400000' |
147 | make_space=y | ||
147 | 148 | ||
148 | case "$platform" in | 149 | case "$platform" in |
149 | pseries) | 150 | pseries) |
@@ -210,6 +211,7 @@ ps3) | |||
210 | ksection=.kernel:vmlinux.bin | 211 | ksection=.kernel:vmlinux.bin |
211 | isection=.kernel:initrd | 212 | isection=.kernel:initrd |
212 | link_address='' | 213 | link_address='' |
214 | make_space=n | ||
213 | pie= | 215 | pie= |
214 | ;; | 216 | ;; |
215 | ep88xc|ep405|ep8248e) | 217 | ep88xc|ep405|ep8248e) |
@@ -278,17 +280,19 @@ else | |||
278 | rm -f $vmz.$$ | 280 | rm -f $vmz.$$ |
279 | fi | 281 | fi |
280 | 282 | ||
281 | # Round the size to next higher MB limit | 283 | if [ "$make_space" = "y" ]; then |
282 | round_size=$(((strip_size + 0xfffff) & 0xfff00000)) | 284 | # Round the size to next higher MB limit |
285 | round_size=$(((strip_size + 0xfffff) & 0xfff00000)) | ||
283 | 286 | ||
284 | round_size=0x$(printf "%x" $round_size) | 287 | round_size=0x$(printf "%x" $round_size) |
285 | link_addr=$(printf "%d" $link_address) | 288 | link_addr=$(printf "%d" $link_address) |
286 | 289 | ||
287 | if [ $link_addr -lt $strip_size ]; then | 290 | if [ $link_addr -lt $strip_size ]; then |
288 | echo "INFO: Uncompressed kernel (size 0x$(printf "%x\n" $strip_size))" \ | 291 | echo "INFO: Uncompressed kernel (size 0x$(printf "%x\n" $strip_size))" \ |
289 | "overlaps the address of the wrapper($link_address)" | 292 | "overlaps the address of the wrapper($link_address)" |
290 | echo "INFO: Fixing the link_address of wrapper to ($round_size)" | 293 | echo "INFO: Fixing the link_address of wrapper to ($round_size)" |
291 | link_address=$round_size | 294 | link_address=$round_size |
295 | fi | ||
292 | fi | 296 | fi |
293 | 297 | ||
294 | vmz="$vmz$gzip" | 298 | vmz="$vmz$gzip" |
diff --git a/arch/powerpc/configs/85xx/ge_imp3a_defconfig b/arch/powerpc/configs/85xx/ge_imp3a_defconfig new file mode 100644 index 000000000000..f8c51a4ab995 --- /dev/null +++ b/arch/powerpc/configs/85xx/ge_imp3a_defconfig | |||
@@ -0,0 +1,257 @@ | |||
1 | CONFIG_PPC_85xx=y | ||
2 | CONFIG_SMP=y | ||
3 | CONFIG_NR_CPUS=2 | ||
4 | CONFIG_EXPERIMENTAL=y | ||
5 | CONFIG_SYSVIPC=y | ||
6 | CONFIG_POSIX_MQUEUE=y | ||
7 | CONFIG_BSD_PROCESS_ACCT=y | ||
8 | CONFIG_BSD_PROCESS_ACCT_V3=y | ||
9 | CONFIG_SPARSE_IRQ=y | ||
10 | CONFIG_IKCONFIG=y | ||
11 | CONFIG_IKCONFIG_PROC=y | ||
12 | # CONFIG_UTS_NS is not set | ||
13 | # CONFIG_IPC_NS is not set | ||
14 | # CONFIG_USER_NS is not set | ||
15 | # CONFIG_PID_NS is not set | ||
16 | # CONFIG_NET_NS is not set | ||
17 | CONFIG_SYSFS_DEPRECATED=y | ||
18 | CONFIG_SYSFS_DEPRECATED_V2=y | ||
19 | CONFIG_RELAY=y | ||
20 | CONFIG_BLK_DEV_INITRD=y | ||
21 | CONFIG_PERF_EVENTS=y | ||
22 | CONFIG_SLAB=y | ||
23 | CONFIG_MODULES=y | ||
24 | CONFIG_MODULE_UNLOAD=y | ||
25 | # CONFIG_BLK_DEV_BSG is not set | ||
26 | CONFIG_GE_IMP3A=y | ||
27 | CONFIG_QUICC_ENGINE=y | ||
28 | CONFIG_QE_GPIO=y | ||
29 | CONFIG_CPM2=y | ||
30 | CONFIG_HIGHMEM=y | ||
31 | CONFIG_HIGH_RES_TIMERS=y | ||
32 | CONFIG_HZ_1000=y | ||
33 | CONFIG_PREEMPT=y | ||
34 | # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set | ||
35 | CONFIG_BINFMT_MISC=m | ||
36 | CONFIG_MATH_EMULATION=y | ||
37 | CONFIG_IRQ_ALL_CPUS=y | ||
38 | CONFIG_FORCE_MAX_ZONEORDER=17 | ||
39 | CONFIG_PCI=y | ||
40 | CONFIG_PCIEPORTBUS=y | ||
41 | CONFIG_PCI_MSI=y | ||
42 | CONFIG_PCCARD=y | ||
43 | # CONFIG_PCMCIA_LOAD_CIS is not set | ||
44 | CONFIG_YENTA=y | ||
45 | CONFIG_NET=y | ||
46 | CONFIG_PACKET=y | ||
47 | CONFIG_UNIX=y | ||
48 | CONFIG_XFRM_USER=m | ||
49 | CONFIG_NET_KEY=y | ||
50 | CONFIG_INET=y | ||
51 | CONFIG_IP_MULTICAST=y | ||
52 | CONFIG_IP_ADVANCED_ROUTER=y | ||
53 | CONFIG_IP_MULTIPLE_TABLES=y | ||
54 | CONFIG_IP_ROUTE_MULTIPATH=y | ||
55 | CONFIG_IP_ROUTE_VERBOSE=y | ||
56 | CONFIG_IP_PNP=y | ||
57 | CONFIG_IP_PNP_DHCP=y | ||
58 | CONFIG_IP_PNP_BOOTP=y | ||
59 | CONFIG_IP_PNP_RARP=y | ||
60 | CONFIG_NET_IPIP=m | ||
61 | CONFIG_IP_MROUTE=y | ||
62 | CONFIG_IP_PIMSM_V1=y | ||
63 | CONFIG_IP_PIMSM_V2=y | ||
64 | CONFIG_SYN_COOKIES=y | ||
65 | CONFIG_INET_AH=m | ||
66 | CONFIG_INET_ESP=m | ||
67 | CONFIG_INET_IPCOMP=m | ||
68 | # CONFIG_INET_XFRM_MODE_BEET is not set | ||
69 | CONFIG_INET6_AH=m | ||
70 | CONFIG_INET6_IPCOMP=m | ||
71 | CONFIG_IPV6_TUNNEL=m | ||
72 | CONFIG_NET_PKTGEN=m | ||
73 | CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" | ||
74 | CONFIG_MTD=y | ||
75 | CONFIG_MTD_OF_PARTS=y | ||
76 | CONFIG_MTD_CHAR=y | ||
77 | CONFIG_MTD_BLOCK=y | ||
78 | CONFIG_MTD_CFI=y | ||
79 | CONFIG_MTD_JEDECPROBE=y | ||
80 | CONFIG_MTD_CFI_INTELEXT=y | ||
81 | CONFIG_MTD_CFI_AMDSTD=y | ||
82 | CONFIG_MTD_PHYSMAP_OF=y | ||
83 | CONFIG_MTD_NAND=y | ||
84 | CONFIG_MTD_NAND_FSL_ELBC=y | ||
85 | CONFIG_PROC_DEVICETREE=y | ||
86 | CONFIG_BLK_DEV_LOOP=m | ||
87 | CONFIG_BLK_DEV_CRYPTOLOOP=m | ||
88 | CONFIG_BLK_DEV_NBD=m | ||
89 | CONFIG_BLK_DEV_RAM=y | ||
90 | CONFIG_BLK_DEV_RAM_SIZE=131072 | ||
91 | CONFIG_MISC_DEVICES=y | ||
92 | CONFIG_DS1682=y | ||
93 | CONFIG_BLK_DEV_SD=y | ||
94 | CONFIG_CHR_DEV_ST=y | ||
95 | CONFIG_BLK_DEV_SR=y | ||
96 | CONFIG_ATA=y | ||
97 | CONFIG_SATA_AHCI=y | ||
98 | CONFIG_SATA_SIL24=y | ||
99 | # CONFIG_ATA_SFF is not set | ||
100 | CONFIG_NETDEVICES=y | ||
101 | CONFIG_BONDING=m | ||
102 | CONFIG_DUMMY=m | ||
103 | CONFIG_NETCONSOLE=y | ||
104 | CONFIG_NETPOLL_TRAP=y | ||
105 | CONFIG_TUN=m | ||
106 | # CONFIG_NET_VENDOR_3COM is not set | ||
107 | CONFIG_FS_ENET=y | ||
108 | CONFIG_UCC_GETH=y | ||
109 | CONFIG_GIANFAR=y | ||
110 | CONFIG_PPP=m | ||
111 | CONFIG_PPP_BSDCOMP=m | ||
112 | CONFIG_PPP_DEFLATE=m | ||
113 | CONFIG_PPP_FILTER=y | ||
114 | CONFIG_PPP_MULTILINK=y | ||
115 | CONFIG_PPPOE=m | ||
116 | CONFIG_PPP_ASYNC=m | ||
117 | CONFIG_PPP_SYNC_TTY=m | ||
118 | CONFIG_SLIP=m | ||
119 | CONFIG_SLIP_COMPRESSED=y | ||
120 | CONFIG_SLIP_SMART=y | ||
121 | CONFIG_SLIP_MODE_SLIP6=y | ||
122 | # CONFIG_INPUT_KEYBOARD is not set | ||
123 | # CONFIG_INPUT_MOUSE is not set | ||
124 | # CONFIG_SERIO is not set | ||
125 | # CONFIG_LEGACY_PTYS is not set | ||
126 | CONFIG_SERIAL_8250=y | ||
127 | CONFIG_SERIAL_8250_CONSOLE=y | ||
128 | CONFIG_SERIAL_8250_NR_UARTS=2 | ||
129 | CONFIG_SERIAL_8250_RUNTIME_UARTS=2 | ||
130 | CONFIG_SERIAL_8250_EXTENDED=y | ||
131 | CONFIG_SERIAL_8250_MANY_PORTS=y | ||
132 | CONFIG_SERIAL_8250_DETECT_IRQ=y | ||
133 | CONFIG_SERIAL_8250_RSA=y | ||
134 | CONFIG_SERIAL_QE=m | ||
135 | CONFIG_NVRAM=y | ||
136 | CONFIG_I2C=y | ||
137 | CONFIG_I2C_CHARDEV=y | ||
138 | CONFIG_I2C_CPM=m | ||
139 | CONFIG_I2C_MPC=y | ||
140 | CONFIG_GPIO_SYSFS=y | ||
141 | CONFIG_GPIO_GE_FPGA=y | ||
142 | CONFIG_SENSORS_LM90=y | ||
143 | CONFIG_SENSORS_LM92=y | ||
144 | CONFIG_WATCHDOG=y | ||
145 | CONFIG_GEF_WDT=y | ||
146 | CONFIG_VIDEO_OUTPUT_CONTROL=m | ||
147 | CONFIG_HID_DRAGONRISE=y | ||
148 | CONFIG_HID_GYRATION=y | ||
149 | CONFIG_HID_TWINHAN=y | ||
150 | CONFIG_HID_ORTEK=y | ||
151 | CONFIG_HID_PANTHERLORD=y | ||
152 | CONFIG_HID_PETALYNX=y | ||
153 | CONFIG_HID_SAMSUNG=y | ||
154 | CONFIG_HID_SONY=y | ||
155 | CONFIG_HID_SUNPLUS=y | ||
156 | CONFIG_HID_GREENASIA=y | ||
157 | CONFIG_HID_SMARTJOYPLUS=y | ||
158 | CONFIG_HID_TOPSEED=y | ||
159 | CONFIG_HID_THRUSTMASTER=y | ||
160 | CONFIG_HID_ZEROPLUS=y | ||
161 | CONFIG_USB=y | ||
162 | CONFIG_USB_DEVICEFS=y | ||
163 | CONFIG_USB_EHCI_HCD=y | ||
164 | # CONFIG_USB_EHCI_TT_NEWSCHED is not set | ||
165 | CONFIG_USB_EHCI_FSL=y | ||
166 | CONFIG_USB_OHCI_HCD=y | ||
167 | CONFIG_USB_OHCI_HCD_PPC_OF_BE=y | ||
168 | CONFIG_USB_OHCI_HCD_PPC_OF_LE=y | ||
169 | CONFIG_USB_STORAGE=y | ||
170 | CONFIG_EDAC=y | ||
171 | CONFIG_EDAC_MM_EDAC=y | ||
172 | CONFIG_EDAC_MPC85XX=y | ||
173 | CONFIG_RTC_CLASS=y | ||
174 | # CONFIG_RTC_INTF_PROC is not set | ||
175 | CONFIG_RTC_DRV_RX8581=y | ||
176 | CONFIG_DMADEVICES=y | ||
177 | CONFIG_FSL_DMA=y | ||
178 | # CONFIG_NET_DMA is not set | ||
179 | CONFIG_EXT2_FS=y | ||
180 | CONFIG_EXT2_FS_XATTR=y | ||
181 | CONFIG_EXT2_FS_POSIX_ACL=y | ||
182 | CONFIG_EXT3_FS=y | ||
183 | # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set | ||
184 | CONFIG_EXT3_FS_POSIX_ACL=y | ||
185 | CONFIG_EXT4_FS=y | ||
186 | CONFIG_FUSE_FS=y | ||
187 | CONFIG_ISO9660_FS=y | ||
188 | CONFIG_JOLIET=y | ||
189 | CONFIG_ZISOFS=y | ||
190 | CONFIG_UDF_FS=y | ||
191 | CONFIG_MSDOS_FS=y | ||
192 | CONFIG_VFAT_FS=y | ||
193 | CONFIG_FAT_DEFAULT_CODEPAGE=850 | ||
194 | CONFIG_FAT_DEFAULT_IOCHARSET="ascii" | ||
195 | CONFIG_NTFS_FS=y | ||
196 | CONFIG_PROC_KCORE=y | ||
197 | CONFIG_TMPFS=y | ||
198 | CONFIG_JFFS2_FS=y | ||
199 | CONFIG_NFS_FS=y | ||
200 | CONFIG_NFS_V3=y | ||
201 | CONFIG_NFS_V4=y | ||
202 | CONFIG_ROOT_NFS=y | ||
203 | CONFIG_NFSD=y | ||
204 | CONFIG_NFSD_V4=y | ||
205 | CONFIG_CIFS=m | ||
206 | CONFIG_CIFS_XATTR=y | ||
207 | CONFIG_CIFS_POSIX=y | ||
208 | CONFIG_NLS_CODEPAGE_437=y | ||
209 | CONFIG_NLS_CODEPAGE_737=m | ||
210 | CONFIG_NLS_CODEPAGE_775=m | ||
211 | CONFIG_NLS_CODEPAGE_850=y | ||
212 | CONFIG_NLS_CODEPAGE_852=m | ||
213 | CONFIG_NLS_CODEPAGE_855=m | ||
214 | CONFIG_NLS_CODEPAGE_857=m | ||
215 | CONFIG_NLS_CODEPAGE_860=m | ||
216 | CONFIG_NLS_CODEPAGE_861=m | ||
217 | CONFIG_NLS_CODEPAGE_862=m | ||
218 | CONFIG_NLS_CODEPAGE_863=m | ||
219 | CONFIG_NLS_CODEPAGE_864=m | ||
220 | CONFIG_NLS_CODEPAGE_865=m | ||
221 | CONFIG_NLS_CODEPAGE_866=m | ||
222 | CONFIG_NLS_CODEPAGE_869=m | ||
223 | CONFIG_NLS_CODEPAGE_936=m | ||
224 | CONFIG_NLS_CODEPAGE_950=m | ||
225 | CONFIG_NLS_CODEPAGE_932=m | ||
226 | CONFIG_NLS_CODEPAGE_949=m | ||
227 | CONFIG_NLS_CODEPAGE_874=m | ||
228 | CONFIG_NLS_ISO8859_8=m | ||
229 | CONFIG_NLS_CODEPAGE_1250=m | ||
230 | CONFIG_NLS_CODEPAGE_1251=m | ||
231 | CONFIG_NLS_ASCII=y | ||
232 | CONFIG_NLS_ISO8859_1=y | ||
233 | CONFIG_NLS_ISO8859_2=m | ||
234 | CONFIG_NLS_ISO8859_3=m | ||
235 | CONFIG_NLS_ISO8859_4=m | ||
236 | CONFIG_NLS_ISO8859_5=m | ||
237 | CONFIG_NLS_ISO8859_6=m | ||
238 | CONFIG_NLS_ISO8859_7=m | ||
239 | CONFIG_NLS_ISO8859_9=m | ||
240 | CONFIG_NLS_ISO8859_13=m | ||
241 | CONFIG_NLS_ISO8859_14=m | ||
242 | CONFIG_NLS_ISO8859_15=y | ||
243 | CONFIG_NLS_KOI8_R=m | ||
244 | CONFIG_NLS_KOI8_U=m | ||
245 | CONFIG_NLS_UTF8=y | ||
246 | CONFIG_CRC_CCITT=y | ||
247 | CONFIG_CRC_T10DIF=y | ||
248 | CONFIG_LIBCRC32C=y | ||
249 | CONFIG_MAGIC_SYSRQ=y | ||
250 | CONFIG_SYSCTL_SYSCALL_CHECK=y | ||
251 | CONFIG_CRYPTO_CBC=y | ||
252 | CONFIG_CRYPTO_MD5=y | ||
253 | CONFIG_CRYPTO_SHA256=m | ||
254 | CONFIG_CRYPTO_SHA512=m | ||
255 | CONFIG_CRYPTO_DES=y | ||
256 | # CONFIG_CRYPTO_ANSI_CPRNG is not set | ||
257 | CONFIG_CRYPTO_DEV_TALITOS=y | ||
diff --git a/arch/powerpc/configs/86xx/gef_ppc9a_defconfig b/arch/powerpc/configs/86xx/gef_ppc9a_defconfig index d41857a5152d..da731c2fe984 100644 --- a/arch/powerpc/configs/86xx/gef_ppc9a_defconfig +++ b/arch/powerpc/configs/86xx/gef_ppc9a_defconfig | |||
@@ -131,6 +131,7 @@ CONFIG_I2C=y | |||
131 | CONFIG_I2C_CHARDEV=y | 131 | CONFIG_I2C_CHARDEV=y |
132 | CONFIG_I2C_MPC=y | 132 | CONFIG_I2C_MPC=y |
133 | CONFIG_GPIO_SYSFS=y | 133 | CONFIG_GPIO_SYSFS=y |
134 | CONFIG_GPIO_GE_FPGA=y | ||
134 | CONFIG_SENSORS_LM90=y | 135 | CONFIG_SENSORS_LM90=y |
135 | CONFIG_SENSORS_LM92=y | 136 | CONFIG_SENSORS_LM92=y |
136 | CONFIG_WATCHDOG=y | 137 | CONFIG_WATCHDOG=y |
diff --git a/arch/powerpc/configs/86xx/gef_sbc310_defconfig b/arch/powerpc/configs/86xx/gef_sbc310_defconfig index 38303ec11bcd..2149360a1e62 100644 --- a/arch/powerpc/configs/86xx/gef_sbc310_defconfig +++ b/arch/powerpc/configs/86xx/gef_sbc310_defconfig | |||
@@ -132,6 +132,7 @@ CONFIG_I2C=y | |||
132 | CONFIG_I2C_CHARDEV=y | 132 | CONFIG_I2C_CHARDEV=y |
133 | CONFIG_I2C_MPC=y | 133 | CONFIG_I2C_MPC=y |
134 | CONFIG_GPIO_SYSFS=y | 134 | CONFIG_GPIO_SYSFS=y |
135 | CONFIG_GPIO_GE_FPGA=y | ||
135 | CONFIG_SENSORS_LM90=y | 136 | CONFIG_SENSORS_LM90=y |
136 | CONFIG_SENSORS_LM92=y | 137 | CONFIG_SENSORS_LM92=y |
137 | CONFIG_WATCHDOG=y | 138 | CONFIG_WATCHDOG=y |
diff --git a/arch/powerpc/configs/86xx/gef_sbc610_defconfig b/arch/powerpc/configs/86xx/gef_sbc610_defconfig index 98533973d20f..af2e8e1edba6 100644 --- a/arch/powerpc/configs/86xx/gef_sbc610_defconfig +++ b/arch/powerpc/configs/86xx/gef_sbc610_defconfig | |||
@@ -183,6 +183,8 @@ CONFIG_NVRAM=y | |||
183 | CONFIG_I2C=y | 183 | CONFIG_I2C=y |
184 | CONFIG_I2C_CHARDEV=y | 184 | CONFIG_I2C_CHARDEV=y |
185 | CONFIG_I2C_MPC=y | 185 | CONFIG_I2C_MPC=y |
186 | CONFIG_GPIO_SYSFS=y | ||
187 | CONFIG_GPIO_GE_FPGA=y | ||
186 | CONFIG_SENSORS_LM90=y | 188 | CONFIG_SENSORS_LM90=y |
187 | CONFIG_SENSORS_LM92=y | 189 | CONFIG_SENSORS_LM92=y |
188 | CONFIG_WATCHDOG=y | 190 | CONFIG_WATCHDOG=y |
diff --git a/arch/powerpc/configs/iseries_defconfig b/arch/powerpc/configs/iseries_defconfig deleted file mode 100644 index 27c46d679968..000000000000 --- a/arch/powerpc/configs/iseries_defconfig +++ /dev/null | |||
@@ -1,236 +0,0 @@ | |||
1 | CONFIG_PPC64=y | ||
2 | CONFIG_SMP=y | ||
3 | CONFIG_EXPERIMENTAL=y | ||
4 | CONFIG_SYSVIPC=y | ||
5 | CONFIG_POSIX_MQUEUE=y | ||
6 | CONFIG_AUDIT=y | ||
7 | CONFIG_AUDITSYSCALL=y | ||
8 | CONFIG_IKCONFIG=y | ||
9 | CONFIG_IKCONFIG_PROC=y | ||
10 | CONFIG_BLK_DEV_INITRD=y | ||
11 | # CONFIG_COMPAT_BRK is not set | ||
12 | CONFIG_MODULES=y | ||
13 | CONFIG_MODULE_UNLOAD=y | ||
14 | CONFIG_MODVERSIONS=y | ||
15 | CONFIG_MODULE_SRCVERSION_ALL=y | ||
16 | # CONFIG_PPC_PSERIES is not set | ||
17 | CONFIG_LPARCFG=y | ||
18 | CONFIG_PPC_ISERIES=y | ||
19 | CONFIG_VIODASD=y | ||
20 | CONFIG_VIOCD=m | ||
21 | CONFIG_VIOTAPE=m | ||
22 | # CONFIG_PPC_PMAC is not set | ||
23 | CONFIG_NO_HZ=y | ||
24 | CONFIG_HIGH_RES_TIMERS=y | ||
25 | CONFIG_IRQ_ALL_CPUS=y | ||
26 | # CONFIG_MIGRATION is not set | ||
27 | CONFIG_PACKET=y | ||
28 | CONFIG_UNIX=y | ||
29 | CONFIG_XFRM_USER=m | ||
30 | CONFIG_XFRM_SUB_POLICY=y | ||
31 | CONFIG_NET_KEY=m | ||
32 | CONFIG_INET=y | ||
33 | CONFIG_IP_MULTICAST=y | ||
34 | CONFIG_NET_IPIP=y | ||
35 | CONFIG_SYN_COOKIES=y | ||
36 | CONFIG_INET_AH=m | ||
37 | CONFIG_INET_ESP=m | ||
38 | CONFIG_INET_IPCOMP=m | ||
39 | CONFIG_INET_XFRM_MODE_BEET=m | ||
40 | # CONFIG_INET_LRO is not set | ||
41 | # CONFIG_IPV6 is not set | ||
42 | CONFIG_NETFILTER=y | ||
43 | CONFIG_NETFILTER_NETLINK_QUEUE=m | ||
44 | CONFIG_NETFILTER_NETLINK_LOG=m | ||
45 | CONFIG_NF_CONNTRACK=m | ||
46 | CONFIG_NF_CONNTRACK_EVENTS=y | ||
47 | # CONFIG_NF_CT_PROTO_SCTP is not set | ||
48 | CONFIG_NF_CONNTRACK_FTP=m | ||
49 | CONFIG_NF_CONNTRACK_IRC=m | ||
50 | CONFIG_NF_CONNTRACK_TFTP=m | ||
51 | CONFIG_NF_CT_NETLINK=m | ||
52 | CONFIG_NETFILTER_TPROXY=m | ||
53 | CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m | ||
54 | CONFIG_NETFILTER_XT_TARGET_CONNMARK=m | ||
55 | CONFIG_NETFILTER_XT_TARGET_DSCP=m | ||
56 | CONFIG_NETFILTER_XT_TARGET_MARK=m | ||
57 | CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m | ||
58 | CONFIG_NETFILTER_XT_TARGET_TPROXY=m | ||
59 | CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m | ||
60 | CONFIG_NETFILTER_XT_MATCH_COMMENT=m | ||
61 | CONFIG_NETFILTER_XT_MATCH_CONNMARK=m | ||
62 | CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m | ||
63 | CONFIG_NETFILTER_XT_MATCH_DSCP=m | ||
64 | CONFIG_NETFILTER_XT_MATCH_IPRANGE=m | ||
65 | CONFIG_NETFILTER_XT_MATCH_LENGTH=m | ||
66 | CONFIG_NETFILTER_XT_MATCH_LIMIT=m | ||
67 | CONFIG_NETFILTER_XT_MATCH_MAC=m | ||
68 | CONFIG_NETFILTER_XT_MATCH_MARK=m | ||
69 | CONFIG_NETFILTER_XT_MATCH_OWNER=m | ||
70 | CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m | ||
71 | CONFIG_NETFILTER_XT_MATCH_RATEEST=m | ||
72 | CONFIG_NETFILTER_XT_MATCH_REALM=m | ||
73 | CONFIG_NETFILTER_XT_MATCH_RECENT=m | ||
74 | CONFIG_NETFILTER_XT_MATCH_STRING=m | ||
75 | CONFIG_NETFILTER_XT_MATCH_TCPMSS=m | ||
76 | CONFIG_NETFILTER_XT_MATCH_TIME=m | ||
77 | CONFIG_NF_CONNTRACK_IPV4=m | ||
78 | CONFIG_IP_NF_QUEUE=m | ||
79 | CONFIG_IP_NF_IPTABLES=m | ||
80 | CONFIG_IP_NF_MATCH_ADDRTYPE=m | ||
81 | CONFIG_IP_NF_MATCH_ECN=m | ||
82 | CONFIG_IP_NF_MATCH_TTL=m | ||
83 | CONFIG_IP_NF_FILTER=m | ||
84 | CONFIG_IP_NF_TARGET_REJECT=m | ||
85 | CONFIG_IP_NF_TARGET_LOG=m | ||
86 | CONFIG_IP_NF_TARGET_ULOG=m | ||
87 | CONFIG_NF_NAT=m | ||
88 | CONFIG_IP_NF_TARGET_MASQUERADE=m | ||
89 | CONFIG_IP_NF_TARGET_NETMAP=m | ||
90 | CONFIG_IP_NF_TARGET_REDIRECT=m | ||
91 | CONFIG_IP_NF_MANGLE=m | ||
92 | CONFIG_IP_NF_TARGET_CLUSTERIP=m | ||
93 | CONFIG_IP_NF_TARGET_ECN=m | ||
94 | CONFIG_IP_NF_TARGET_TTL=m | ||
95 | CONFIG_IP_NF_RAW=m | ||
96 | CONFIG_IP_NF_ARPTABLES=m | ||
97 | CONFIG_IP_NF_ARPFILTER=m | ||
98 | CONFIG_IP_NF_ARP_MANGLE=m | ||
99 | CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" | ||
100 | CONFIG_PROC_DEVICETREE=y | ||
101 | CONFIG_BLK_DEV_LOOP=y | ||
102 | CONFIG_BLK_DEV_NBD=m | ||
103 | CONFIG_BLK_DEV_RAM=y | ||
104 | CONFIG_BLK_DEV_RAM_SIZE=65536 | ||
105 | CONFIG_SCSI=y | ||
106 | CONFIG_BLK_DEV_SD=y | ||
107 | CONFIG_CHR_DEV_ST=y | ||
108 | CONFIG_BLK_DEV_SR=y | ||
109 | CONFIG_BLK_DEV_SR_VENDOR=y | ||
110 | CONFIG_CHR_DEV_SG=y | ||
111 | CONFIG_SCSI_MULTI_LUN=y | ||
112 | CONFIG_SCSI_CONSTANTS=y | ||
113 | CONFIG_SCSI_SPI_ATTRS=y | ||
114 | CONFIG_SCSI_FC_ATTRS=y | ||
115 | CONFIG_SCSI_SAS_LIBSAS=m | ||
116 | CONFIG_SCSI_IBMVSCSI=m | ||
117 | CONFIG_MD=y | ||
118 | CONFIG_BLK_DEV_MD=y | ||
119 | CONFIG_MD_LINEAR=y | ||
120 | CONFIG_MD_RAID0=y | ||
121 | CONFIG_MD_RAID1=y | ||
122 | CONFIG_MD_RAID10=m | ||
123 | CONFIG_MD_MULTIPATH=m | ||
124 | CONFIG_MD_FAULTY=m | ||
125 | CONFIG_BLK_DEV_DM=y | ||
126 | CONFIG_DM_CRYPT=m | ||
127 | CONFIG_DM_SNAPSHOT=m | ||
128 | CONFIG_DM_MIRROR=m | ||
129 | CONFIG_DM_ZERO=m | ||
130 | CONFIG_NETDEVICES=y | ||
131 | CONFIG_DUMMY=m | ||
132 | CONFIG_BONDING=m | ||
133 | CONFIG_TUN=m | ||
134 | CONFIG_NET_ETHERNET=y | ||
135 | CONFIG_NET_PCI=y | ||
136 | CONFIG_PCNET32=y | ||
137 | CONFIG_E100=y | ||
138 | CONFIG_ACENIC=m | ||
139 | CONFIG_E1000=m | ||
140 | CONFIG_ISERIES_VETH=y | ||
141 | CONFIG_PPP=m | ||
142 | CONFIG_PPP_ASYNC=m | ||
143 | CONFIG_PPP_SYNC_TTY=m | ||
144 | CONFIG_PPP_DEFLATE=m | ||
145 | CONFIG_PPP_BSDCOMP=m | ||
146 | CONFIG_PPPOE=m | ||
147 | CONFIG_NETCONSOLE=y | ||
148 | CONFIG_NETPOLL_TRAP=y | ||
149 | # CONFIG_INPUT_MOUSEDEV_PSAUX is not set | ||
150 | # CONFIG_INPUT_KEYBOARD is not set | ||
151 | # CONFIG_INPUT_MOUSE is not set | ||
152 | # CONFIG_SERIO is not set | ||
153 | CONFIG_SERIAL_ICOM=m | ||
154 | # CONFIG_HW_RANDOM is not set | ||
155 | CONFIG_GEN_RTC=y | ||
156 | CONFIG_RAW_DRIVER=y | ||
157 | # CONFIG_HWMON is not set | ||
158 | # CONFIG_HID_SUPPORT is not set | ||
159 | # CONFIG_USB_SUPPORT is not set | ||
160 | CONFIG_EXT2_FS=y | ||
161 | CONFIG_EXT2_FS_XATTR=y | ||
162 | CONFIG_EXT2_FS_POSIX_ACL=y | ||
163 | CONFIG_EXT2_FS_SECURITY=y | ||
164 | CONFIG_EXT2_FS_XIP=y | ||
165 | CONFIG_EXT3_FS=y | ||
166 | CONFIG_EXT3_FS_POSIX_ACL=y | ||
167 | CONFIG_EXT3_FS_SECURITY=y | ||
168 | CONFIG_EXT4_FS=y | ||
169 | CONFIG_REISERFS_FS=y | ||
170 | CONFIG_REISERFS_FS_XATTR=y | ||
171 | CONFIG_REISERFS_FS_POSIX_ACL=y | ||
172 | CONFIG_REISERFS_FS_SECURITY=y | ||
173 | CONFIG_JFS_FS=m | ||
174 | CONFIG_JFS_POSIX_ACL=y | ||
175 | CONFIG_JFS_SECURITY=y | ||
176 | CONFIG_XFS_FS=m | ||
177 | CONFIG_XFS_POSIX_ACL=y | ||
178 | CONFIG_GFS2_FS=m | ||
179 | CONFIG_AUTOFS_FS=m | ||
180 | CONFIG_ISO9660_FS=y | ||
181 | CONFIG_JOLIET=y | ||
182 | CONFIG_ZISOFS=y | ||
183 | CONFIG_UDF_FS=m | ||
184 | CONFIG_MSDOS_FS=y | ||
185 | CONFIG_VFAT_FS=y | ||
186 | CONFIG_PROC_KCORE=y | ||
187 | CONFIG_TMPFS=y | ||
188 | CONFIG_TMPFS_POSIX_ACL=y | ||
189 | CONFIG_CRAMFS=y | ||
190 | CONFIG_NFS_FS=y | ||
191 | CONFIG_NFS_V3=y | ||
192 | CONFIG_NFS_V3_ACL=y | ||
193 | CONFIG_NFS_V4=y | ||
194 | CONFIG_NFSD=m | ||
195 | CONFIG_NFSD_V3_ACL=y | ||
196 | CONFIG_NFSD_V4=y | ||
197 | CONFIG_RPCSEC_GSS_SPKM3=m | ||
198 | CONFIG_CIFS=m | ||
199 | CONFIG_CIFS_XATTR=y | ||
200 | CONFIG_CIFS_POSIX=y | ||
201 | CONFIG_NLS_CODEPAGE_437=y | ||
202 | CONFIG_NLS_ASCII=y | ||
203 | CONFIG_NLS_ISO8859_1=y | ||
204 | CONFIG_DLM=m | ||
205 | CONFIG_CRC_T10DIF=y | ||
206 | CONFIG_MAGIC_SYSRQ=y | ||
207 | CONFIG_DEBUG_FS=y | ||
208 | CONFIG_DEBUG_KERNEL=y | ||
209 | # CONFIG_RCU_CPU_STALL_DETECTOR is not set | ||
210 | CONFIG_LATENCYTOP=y | ||
211 | CONFIG_SYSCTL_SYSCALL_CHECK=y | ||
212 | CONFIG_DEBUG_STACKOVERFLOW=y | ||
213 | CONFIG_DEBUG_STACK_USAGE=y | ||
214 | CONFIG_CRYPTO_NULL=m | ||
215 | CONFIG_CRYPTO_TEST=m | ||
216 | CONFIG_CRYPTO_ECB=m | ||
217 | CONFIG_CRYPTO_PCBC=m | ||
218 | CONFIG_CRYPTO_HMAC=y | ||
219 | CONFIG_CRYPTO_MD4=m | ||
220 | CONFIG_CRYPTO_MICHAEL_MIC=m | ||
221 | CONFIG_CRYPTO_SHA256=m | ||
222 | CONFIG_CRYPTO_SHA512=m | ||
223 | CONFIG_CRYPTO_TGR192=m | ||
224 | CONFIG_CRYPTO_WP512=m | ||
225 | CONFIG_CRYPTO_AES=m | ||
226 | CONFIG_CRYPTO_ANUBIS=m | ||
227 | CONFIG_CRYPTO_ARC4=m | ||
228 | CONFIG_CRYPTO_BLOWFISH=m | ||
229 | CONFIG_CRYPTO_CAST6=m | ||
230 | CONFIG_CRYPTO_KHAZAD=m | ||
231 | CONFIG_CRYPTO_SEED=m | ||
232 | CONFIG_CRYPTO_SERPENT=m | ||
233 | CONFIG_CRYPTO_TEA=m | ||
234 | CONFIG_CRYPTO_TWOFISH=m | ||
235 | # CONFIG_CRYPTO_ANSI_CPRNG is not set | ||
236 | # CONFIG_CRYPTO_HW is not set | ||
diff --git a/arch/powerpc/configs/mpc5200_defconfig b/arch/powerpc/configs/mpc5200_defconfig index 2a1320fb2723..6640a35bebb7 100644 --- a/arch/powerpc/configs/mpc5200_defconfig +++ b/arch/powerpc/configs/mpc5200_defconfig | |||
@@ -1,8 +1,8 @@ | |||
1 | CONFIG_EXPERIMENTAL=y | 1 | CONFIG_EXPERIMENTAL=y |
2 | CONFIG_SYSVIPC=y | 2 | CONFIG_SYSVIPC=y |
3 | CONFIG_SPARSE_IRQ=y | ||
3 | CONFIG_LOG_BUF_SHIFT=14 | 4 | CONFIG_LOG_BUF_SHIFT=14 |
4 | CONFIG_BLK_DEV_INITRD=y | 5 | CONFIG_BLK_DEV_INITRD=y |
5 | # CONFIG_CC_OPTIMIZE_FOR_SIZE is not set | ||
6 | CONFIG_MODULES=y | 6 | CONFIG_MODULES=y |
7 | CONFIG_MODULE_UNLOAD=y | 7 | CONFIG_MODULE_UNLOAD=y |
8 | # CONFIG_BLK_DEV_BSG is not set | 8 | # CONFIG_BLK_DEV_BSG is not set |
@@ -13,15 +13,12 @@ CONFIG_PPC_EFIKA=y | |||
13 | CONFIG_PPC_LITE5200=y | 13 | CONFIG_PPC_LITE5200=y |
14 | CONFIG_PPC_MEDIA5200=y | 14 | CONFIG_PPC_MEDIA5200=y |
15 | CONFIG_PPC_MPC5200_BUGFIX=y | 15 | CONFIG_PPC_MPC5200_BUGFIX=y |
16 | CONFIG_PPC_MPC5200_GPIO=y | ||
17 | CONFIG_PPC_MPC5200_LPBFIFO=m | 16 | CONFIG_PPC_MPC5200_LPBFIFO=m |
18 | # CONFIG_PPC_PMAC is not set | 17 | # CONFIG_PPC_PMAC is not set |
19 | CONFIG_PPC_BESTCOMM=y | 18 | CONFIG_PPC_BESTCOMM=y |
20 | CONFIG_SIMPLE_GPIO=y | 19 | CONFIG_SIMPLE_GPIO=y |
21 | CONFIG_NO_HZ=y | 20 | CONFIG_NO_HZ=y |
22 | CONFIG_HIGH_RES_TIMERS=y | 21 | CONFIG_HIGH_RES_TIMERS=y |
23 | CONFIG_SPARSE_IRQ=y | ||
24 | CONFIG_PM=y | ||
25 | CONFIG_NET=y | 22 | CONFIG_NET=y |
26 | CONFIG_PACKET=y | 23 | CONFIG_PACKET=y |
27 | CONFIG_UNIX=y | 24 | CONFIG_UNIX=y |
@@ -36,23 +33,20 @@ CONFIG_SYN_COOKIES=y | |||
36 | # CONFIG_IPV6 is not set | 33 | # CONFIG_IPV6 is not set |
37 | CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" | 34 | CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" |
38 | CONFIG_MTD=y | 35 | CONFIG_MTD=y |
39 | CONFIG_MTD_CONCAT=y | ||
40 | CONFIG_MTD_PARTITIONS=y | ||
41 | CONFIG_MTD_CMDLINE_PARTS=y | 36 | CONFIG_MTD_CMDLINE_PARTS=y |
42 | CONFIG_MTD_OF_PARTS=y | 37 | CONFIG_MTD_OF_PARTS=y |
43 | CONFIG_MTD_CHAR=y | 38 | CONFIG_MTD_CHAR=y |
44 | CONFIG_MTD_BLOCK=y | 39 | CONFIG_MTD_BLOCK=y |
45 | CONFIG_MTD_CFI=y | 40 | CONFIG_MTD_CFI=y |
46 | CONFIG_MTD_CFI_AMDSTD=y | 41 | CONFIG_MTD_CFI_AMDSTD=y |
47 | CONFIG_MTD_RAM=y | ||
48 | CONFIG_MTD_ROM=y | 42 | CONFIG_MTD_ROM=y |
49 | CONFIG_MTD_PHYSMAP_OF=y | 43 | CONFIG_MTD_PHYSMAP_OF=y |
44 | CONFIG_MTD_PLATRAM=y | ||
50 | CONFIG_MTD_UBI=m | 45 | CONFIG_MTD_UBI=m |
51 | CONFIG_PROC_DEVICETREE=y | 46 | CONFIG_PROC_DEVICETREE=y |
52 | CONFIG_BLK_DEV_LOOP=y | 47 | CONFIG_BLK_DEV_LOOP=y |
53 | CONFIG_BLK_DEV_RAM=y | 48 | CONFIG_BLK_DEV_RAM=y |
54 | CONFIG_BLK_DEV_RAM_SIZE=32768 | 49 | CONFIG_BLK_DEV_RAM_SIZE=32768 |
55 | CONFIG_MISC_DEVICES=y | ||
56 | CONFIG_EEPROM_AT24=y | 50 | CONFIG_EEPROM_AT24=y |
57 | CONFIG_SCSI_TGT=y | 51 | CONFIG_SCSI_TGT=y |
58 | CONFIG_BLK_DEV_SD=y | 52 | CONFIG_BLK_DEV_SD=y |
@@ -61,11 +55,10 @@ CONFIG_ATA=y | |||
61 | CONFIG_PATA_MPC52xx=y | 55 | CONFIG_PATA_MPC52xx=y |
62 | CONFIG_PATA_PLATFORM=y | 56 | CONFIG_PATA_PLATFORM=y |
63 | CONFIG_NETDEVICES=y | 57 | CONFIG_NETDEVICES=y |
64 | CONFIG_LXT_PHY=y | ||
65 | CONFIG_NET_ETHERNET=y | ||
66 | CONFIG_FEC_MPC52xx=y | 58 | CONFIG_FEC_MPC52xx=y |
67 | # CONFIG_NETDEV_1000 is not set | 59 | CONFIG_AMD_PHY=y |
68 | # CONFIG_NETDEV_10000 is not set | 60 | CONFIG_LXT_PHY=y |
61 | CONFIG_FIXED_PHY=y | ||
69 | # CONFIG_INPUT_KEYBOARD is not set | 62 | # CONFIG_INPUT_KEYBOARD is not set |
70 | # CONFIG_INPUT_MOUSE is not set | 63 | # CONFIG_INPUT_MOUSE is not set |
71 | # CONFIG_SERIO is not set | 64 | # CONFIG_SERIO is not set |
@@ -80,11 +73,17 @@ CONFIG_SPI_GPIO=m | |||
80 | CONFIG_SPI_MPC52xx=m | 73 | CONFIG_SPI_MPC52xx=m |
81 | CONFIG_SPI_MPC52xx_PSC=m | 74 | CONFIG_SPI_MPC52xx_PSC=m |
82 | CONFIG_SPI_SPIDEV=m | 75 | CONFIG_SPI_SPIDEV=m |
76 | CONFIG_GPIO_SYSFS=y | ||
77 | CONFIG_SENSORS_LM80=y | ||
78 | CONFIG_SENSORS_LM87=m | ||
83 | CONFIG_WATCHDOG=y | 79 | CONFIG_WATCHDOG=y |
80 | CONFIG_MFD_SM501=m | ||
84 | CONFIG_DRM=y | 81 | CONFIG_DRM=y |
85 | CONFIG_VIDEO_OUTPUT_CONTROL=y | 82 | CONFIG_VIDEO_OUTPUT_CONTROL=y |
86 | CONFIG_FB=y | 83 | CONFIG_FB=y |
84 | CONFIG_FB_FOREIGN_ENDIAN=y | ||
87 | CONFIG_FB_RADEON=y | 85 | CONFIG_FB_RADEON=y |
86 | CONFIG_FB_SM501=m | ||
88 | # CONFIG_VGA_CONSOLE is not set | 87 | # CONFIG_VGA_CONSOLE is not set |
89 | CONFIG_FRAMEBUFFER_CONSOLE=y | 88 | CONFIG_FRAMEBUFFER_CONSOLE=y |
90 | CONFIG_LOGO=y | 89 | CONFIG_LOGO=y |
@@ -124,10 +123,11 @@ CONFIG_USB_STORAGE=y | |||
124 | CONFIG_NEW_LEDS=y | 123 | CONFIG_NEW_LEDS=y |
125 | CONFIG_RTC_CLASS=y | 124 | CONFIG_RTC_CLASS=y |
126 | CONFIG_RTC_DRV_DS1307=y | 125 | CONFIG_RTC_DRV_DS1307=y |
126 | CONFIG_RTC_DRV_DS1374=y | ||
127 | CONFIG_RTC_DRV_PCF8563=m | ||
127 | CONFIG_EXT2_FS=y | 128 | CONFIG_EXT2_FS=y |
128 | CONFIG_EXT3_FS=y | 129 | CONFIG_EXT3_FS=y |
129 | # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set | 130 | # CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set |
130 | CONFIG_INOTIFY=y | ||
131 | CONFIG_MSDOS_FS=y | 131 | CONFIG_MSDOS_FS=y |
132 | CONFIG_VFAT_FS=y | 132 | CONFIG_VFAT_FS=y |
133 | CONFIG_PROC_KCORE=y | 133 | CONFIG_PROC_KCORE=y |
@@ -145,5 +145,4 @@ CONFIG_PRINTK_TIME=y | |||
145 | CONFIG_DEBUG_KERNEL=y | 145 | CONFIG_DEBUG_KERNEL=y |
146 | CONFIG_DETECT_HUNG_TASK=y | 146 | CONFIG_DETECT_HUNG_TASK=y |
147 | CONFIG_DEBUG_INFO=y | 147 | CONFIG_DEBUG_INFO=y |
148 | # CONFIG_RCU_CPU_STALL_DETECTOR is not set | ||
149 | # CONFIG_CRYPTO_ANSI_CPRNG is not set | 148 | # CONFIG_CRYPTO_ANSI_CPRNG is not set |
diff --git a/arch/powerpc/configs/mpc85xx_defconfig b/arch/powerpc/configs/mpc85xx_defconfig index f37a2ab48881..5fb0c8a94811 100644 --- a/arch/powerpc/configs/mpc85xx_defconfig +++ b/arch/powerpc/configs/mpc85xx_defconfig | |||
@@ -1,4 +1,5 @@ | |||
1 | CONFIG_PPC_85xx=y | 1 | CONFIG_PPC_85xx=y |
2 | CONFIG_PHYS_64BIT=y | ||
2 | CONFIG_EXPERIMENTAL=y | 3 | CONFIG_EXPERIMENTAL=y |
3 | CONFIG_SYSVIPC=y | 4 | CONFIG_SYSVIPC=y |
4 | CONFIG_POSIX_MQUEUE=y | 5 | CONFIG_POSIX_MQUEUE=y |
diff --git a/arch/powerpc/configs/mpc85xx_smp_defconfig b/arch/powerpc/configs/mpc85xx_smp_defconfig index abdcd317cda7..fb51bc90edd2 100644 --- a/arch/powerpc/configs/mpc85xx_smp_defconfig +++ b/arch/powerpc/configs/mpc85xx_smp_defconfig | |||
@@ -1,4 +1,5 @@ | |||
1 | CONFIG_PPC_85xx=y | 1 | CONFIG_PPC_85xx=y |
2 | CONFIG_PHYS_64BIT=y | ||
2 | CONFIG_SMP=y | 3 | CONFIG_SMP=y |
3 | CONFIG_NR_CPUS=8 | 4 | CONFIG_NR_CPUS=8 |
4 | CONFIG_EXPERIMENTAL=y | 5 | CONFIG_EXPERIMENTAL=y |
diff --git a/arch/powerpc/include/asm/abs_addr.h b/arch/powerpc/include/asm/abs_addr.h index 5ab0b71531be..9d92ba04b033 100644 --- a/arch/powerpc/include/asm/abs_addr.h +++ b/arch/powerpc/include/asm/abs_addr.h | |||
@@ -17,7 +17,6 @@ | |||
17 | #include <asm/types.h> | 17 | #include <asm/types.h> |
18 | #include <asm/page.h> | 18 | #include <asm/page.h> |
19 | #include <asm/prom.h> | 19 | #include <asm/prom.h> |
20 | #include <asm/firmware.h> | ||
21 | 20 | ||
22 | struct mschunks_map { | 21 | struct mschunks_map { |
23 | unsigned long num_chunks; | 22 | unsigned long num_chunks; |
@@ -46,30 +45,12 @@ static inline unsigned long addr_to_chunk(unsigned long addr) | |||
46 | 45 | ||
47 | static inline unsigned long phys_to_abs(unsigned long pa) | 46 | static inline unsigned long phys_to_abs(unsigned long pa) |
48 | { | 47 | { |
49 | unsigned long chunk; | 48 | return pa; |
50 | |||
51 | /* This is a no-op on non-iSeries */ | ||
52 | if (!firmware_has_feature(FW_FEATURE_ISERIES)) | ||
53 | return pa; | ||
54 | |||
55 | chunk = addr_to_chunk(pa); | ||
56 | |||
57 | if (chunk < mschunks_map.num_chunks) | ||
58 | chunk = mschunks_map.mapping[chunk]; | ||
59 | |||
60 | return chunk_to_addr(chunk) + (pa & MSCHUNKS_OFFSET_MASK); | ||
61 | } | 49 | } |
62 | 50 | ||
63 | /* Convenience macros */ | 51 | /* Convenience macros */ |
64 | #define virt_to_abs(va) phys_to_abs(__pa(va)) | 52 | #define virt_to_abs(va) phys_to_abs(__pa(va)) |
65 | #define abs_to_virt(aa) __va(aa) | 53 | #define abs_to_virt(aa) __va(aa) |
66 | 54 | ||
67 | /* | ||
68 | * Converts Virtual Address to Real Address for | ||
69 | * Legacy iSeries Hypervisor calls | ||
70 | */ | ||
71 | #define iseries_hv_addr(virtaddr) \ | ||
72 | (0x8000000000000000UL | virt_to_abs(virtaddr)) | ||
73 | |||
74 | #endif /* __KERNEL__ */ | 55 | #endif /* __KERNEL__ */ |
75 | #endif /* _ASM_POWERPC_ABS_ADDR_H */ | 56 | #endif /* _ASM_POWERPC_ABS_ADDR_H */ |
diff --git a/arch/powerpc/include/asm/atomic.h b/arch/powerpc/include/asm/atomic.h index 02e41b53488d..14174e838ad9 100644 --- a/arch/powerpc/include/asm/atomic.h +++ b/arch/powerpc/include/asm/atomic.h | |||
@@ -212,6 +212,36 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u) | |||
212 | return t; | 212 | return t; |
213 | } | 213 | } |
214 | 214 | ||
215 | /** | ||
216 | * atomic_inc_not_zero - increment unless the number is zero | ||
217 | * @v: pointer of type atomic_t | ||
218 | * | ||
219 | * Atomically increments @v by 1, so long as @v is non-zero. | ||
220 | * Returns non-zero if @v was non-zero, and zero otherwise. | ||
221 | */ | ||
222 | static __inline__ int atomic_inc_not_zero(atomic_t *v) | ||
223 | { | ||
224 | int t1, t2; | ||
225 | |||
226 | __asm__ __volatile__ ( | ||
227 | PPC_ATOMIC_ENTRY_BARRIER | ||
228 | "1: lwarx %0,0,%2 # atomic_inc_not_zero\n\ | ||
229 | cmpwi 0,%0,0\n\ | ||
230 | beq- 2f\n\ | ||
231 | addic %1,%0,1\n" | ||
232 | PPC405_ERR77(0,%2) | ||
233 | " stwcx. %1,0,%2\n\ | ||
234 | bne- 1b\n" | ||
235 | PPC_ATOMIC_EXIT_BARRIER | ||
236 | "\n\ | ||
237 | 2:" | ||
238 | : "=&r" (t1), "=&r" (t2) | ||
239 | : "r" (&v->counter) | ||
240 | : "cc", "xer", "memory"); | ||
241 | |||
242 | return t1; | ||
243 | } | ||
244 | #define atomic_inc_not_zero(v) atomic_inc_not_zero((v)) | ||
215 | 245 | ||
216 | #define atomic_sub_and_test(a, v) (atomic_sub_return((a), (v)) == 0) | 246 | #define atomic_sub_and_test(a, v) (atomic_sub_return((a), (v)) == 0) |
217 | #define atomic_dec_and_test(v) (atomic_dec_return((v)) == 0) | 247 | #define atomic_dec_and_test(v) (atomic_dec_return((v)) == 0) |
@@ -467,7 +497,34 @@ static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u) | |||
467 | return t != u; | 497 | return t != u; |
468 | } | 498 | } |
469 | 499 | ||
470 | #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0) | 500 | /** |
501 | * atomic_inc64_not_zero - increment unless the number is zero | ||
502 | * @v: pointer of type atomic64_t | ||
503 | * | ||
504 | * Atomically increments @v by 1, so long as @v is non-zero. | ||
505 | * Returns non-zero if @v was non-zero, and zero otherwise. | ||
506 | */ | ||
507 | static __inline__ long atomic64_inc_not_zero(atomic64_t *v) | ||
508 | { | ||
509 | long t1, t2; | ||
510 | |||
511 | __asm__ __volatile__ ( | ||
512 | PPC_ATOMIC_ENTRY_BARRIER | ||
513 | "1: ldarx %0,0,%2 # atomic64_inc_not_zero\n\ | ||
514 | cmpdi 0,%0,0\n\ | ||
515 | beq- 2f\n\ | ||
516 | addic %1,%0,1\n\ | ||
517 | stdcx. %1,0,%2\n\ | ||
518 | bne- 1b\n" | ||
519 | PPC_ATOMIC_EXIT_BARRIER | ||
520 | "\n\ | ||
521 | 2:" | ||
522 | : "=&r" (t1), "=&r" (t2) | ||
523 | : "r" (&v->counter) | ||
524 | : "cc", "xer", "memory"); | ||
525 | |||
526 | return t1; | ||
527 | } | ||
471 | 528 | ||
472 | #endif /* __powerpc64__ */ | 529 | #endif /* __powerpc64__ */ |
473 | 530 | ||
diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h index ad55a1ccb9fb..b9219e99bd2a 100644 --- a/arch/powerpc/include/asm/cputable.h +++ b/arch/powerpc/include/asm/cputable.h | |||
@@ -390,6 +390,10 @@ extern const char *powerpc_base_platform; | |||
390 | CPU_FTR_L2CSR | CPU_FTR_LWSYNC | CPU_FTR_NOEXECUTE | \ | 390 | CPU_FTR_L2CSR | CPU_FTR_LWSYNC | CPU_FTR_NOEXECUTE | \ |
391 | CPU_FTR_DBELL | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \ | 391 | CPU_FTR_DBELL | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \ |
392 | CPU_FTR_DEBUG_LVL_EXC) | 392 | CPU_FTR_DEBUG_LVL_EXC) |
393 | #define CPU_FTRS_E6500 (CPU_FTR_USE_TB | CPU_FTR_NODSISRALIGN | \ | ||
394 | CPU_FTR_L2CSR | CPU_FTR_LWSYNC | CPU_FTR_NOEXECUTE | \ | ||
395 | CPU_FTR_DBELL | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \ | ||
396 | CPU_FTR_DEBUG_LVL_EXC) | ||
393 | #define CPU_FTRS_GENERIC_32 (CPU_FTR_COMMON | CPU_FTR_NODSISRALIGN) | 397 | #define CPU_FTRS_GENERIC_32 (CPU_FTR_COMMON | CPU_FTR_NODSISRALIGN) |
394 | 398 | ||
395 | /* 64-bit CPUs */ | 399 | /* 64-bit CPUs */ |
@@ -442,7 +446,7 @@ extern const char *powerpc_base_platform; | |||
442 | 446 | ||
443 | #ifdef __powerpc64__ | 447 | #ifdef __powerpc64__ |
444 | #ifdef CONFIG_PPC_BOOK3E | 448 | #ifdef CONFIG_PPC_BOOK3E |
445 | #define CPU_FTRS_POSSIBLE (CPU_FTRS_E5500 | CPU_FTRS_A2) | 449 | #define CPU_FTRS_POSSIBLE (CPU_FTRS_E6500 | CPU_FTRS_E5500 | CPU_FTRS_A2) |
446 | #else | 450 | #else |
447 | #define CPU_FTRS_POSSIBLE \ | 451 | #define CPU_FTRS_POSSIBLE \ |
448 | (CPU_FTRS_POWER3 | CPU_FTRS_RS64 | CPU_FTRS_POWER4 | \ | 452 | (CPU_FTRS_POWER3 | CPU_FTRS_RS64 | CPU_FTRS_POWER4 | \ |
@@ -483,7 +487,7 @@ enum { | |||
483 | #endif | 487 | #endif |
484 | #ifdef CONFIG_E500 | 488 | #ifdef CONFIG_E500 |
485 | CPU_FTRS_E500 | CPU_FTRS_E500_2 | CPU_FTRS_E500MC | | 489 | CPU_FTRS_E500 | CPU_FTRS_E500_2 | CPU_FTRS_E500MC | |
486 | CPU_FTRS_E5500 | | 490 | CPU_FTRS_E5500 | CPU_FTRS_E6500 | |
487 | #endif | 491 | #endif |
488 | 0, | 492 | 0, |
489 | }; | 493 | }; |
@@ -491,7 +495,7 @@ enum { | |||
491 | 495 | ||
492 | #ifdef __powerpc64__ | 496 | #ifdef __powerpc64__ |
493 | #ifdef CONFIG_PPC_BOOK3E | 497 | #ifdef CONFIG_PPC_BOOK3E |
494 | #define CPU_FTRS_ALWAYS (CPU_FTRS_E5500 & CPU_FTRS_A2) | 498 | #define CPU_FTRS_ALWAYS (CPU_FTRS_E6500 & CPU_FTRS_E5500 & CPU_FTRS_A2) |
495 | #else | 499 | #else |
496 | #define CPU_FTRS_ALWAYS \ | 500 | #define CPU_FTRS_ALWAYS \ |
497 | (CPU_FTRS_POWER3 & CPU_FTRS_RS64 & CPU_FTRS_POWER4 & \ | 501 | (CPU_FTRS_POWER3 & CPU_FTRS_RS64 & CPU_FTRS_POWER4 & \ |
@@ -528,7 +532,7 @@ enum { | |||
528 | #endif | 532 | #endif |
529 | #ifdef CONFIG_E500 | 533 | #ifdef CONFIG_E500 |
530 | CPU_FTRS_E500 & CPU_FTRS_E500_2 & CPU_FTRS_E500MC & | 534 | CPU_FTRS_E500 & CPU_FTRS_E500_2 & CPU_FTRS_E500MC & |
531 | CPU_FTRS_E5500 & | 535 | CPU_FTRS_E5500 & CPU_FTRS_E6500 & |
532 | #endif | 536 | #endif |
533 | CPU_FTRS_POSSIBLE, | 537 | CPU_FTRS_POSSIBLE, |
534 | }; | 538 | }; |
diff --git a/arch/powerpc/include/asm/device.h b/arch/powerpc/include/asm/device.h index d57c08acedfc..63d5ca49cece 100644 --- a/arch/powerpc/include/asm/device.h +++ b/arch/powerpc/include/asm/device.h | |||
@@ -31,6 +31,9 @@ struct dev_archdata { | |||
31 | #ifdef CONFIG_SWIOTLB | 31 | #ifdef CONFIG_SWIOTLB |
32 | dma_addr_t max_direct_dma_addr; | 32 | dma_addr_t max_direct_dma_addr; |
33 | #endif | 33 | #endif |
34 | #ifdef CONFIG_EEH | ||
35 | struct eeh_dev *edev; | ||
36 | #endif | ||
34 | }; | 37 | }; |
35 | 38 | ||
36 | struct pdev_archdata { | 39 | struct pdev_archdata { |
diff --git a/arch/powerpc/include/asm/dma.h b/arch/powerpc/include/asm/dma.h index a7e06e25c708..adadb9943610 100644 --- a/arch/powerpc/include/asm/dma.h +++ b/arch/powerpc/include/asm/dma.h | |||
@@ -34,8 +34,6 @@ | |||
34 | /* Doesn't really apply... */ | 34 | /* Doesn't really apply... */ |
35 | #define MAX_DMA_ADDRESS (~0UL) | 35 | #define MAX_DMA_ADDRESS (~0UL) |
36 | 36 | ||
37 | #if !defined(CONFIG_PPC_ISERIES) || defined(CONFIG_PCI) | ||
38 | |||
39 | #ifdef HAVE_REALLY_SLOW_DMA_CONTROLLER | 37 | #ifdef HAVE_REALLY_SLOW_DMA_CONTROLLER |
40 | #define dma_outb outb_p | 38 | #define dma_outb outb_p |
41 | #else | 39 | #else |
@@ -354,7 +352,5 @@ extern int isa_dma_bridge_buggy; | |||
354 | #define isa_dma_bridge_buggy (0) | 352 | #define isa_dma_bridge_buggy (0) |
355 | #endif | 353 | #endif |
356 | 354 | ||
357 | #endif /* !defined(CONFIG_PPC_ISERIES) || defined(CONFIG_PCI) */ | ||
358 | |||
359 | #endif /* __KERNEL__ */ | 355 | #endif /* __KERNEL__ */ |
360 | #endif /* _ASM_POWERPC_DMA_H */ | 356 | #endif /* _ASM_POWERPC_DMA_H */ |
diff --git a/arch/powerpc/include/asm/eeh.h b/arch/powerpc/include/asm/eeh.h index 66ea9b8b95c5..d60f99814ffb 100644 --- a/arch/powerpc/include/asm/eeh.h +++ b/arch/powerpc/include/asm/eeh.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * eeh.h | ||
3 | * Copyright (C) 2001 Dave Engebretsen & Todd Inglett IBM Corporation. | 2 | * Copyright (C) 2001 Dave Engebretsen & Todd Inglett IBM Corporation. |
3 | * Copyright 2001-2012 IBM Corporation. | ||
4 | * | 4 | * |
5 | * This program is free software; you can redistribute it and/or modify | 5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by | 6 | * it under the terms of the GNU General Public License as published by |
@@ -31,44 +31,105 @@ struct device_node; | |||
31 | 31 | ||
32 | #ifdef CONFIG_EEH | 32 | #ifdef CONFIG_EEH |
33 | 33 | ||
34 | extern int eeh_subsystem_enabled; | 34 | /* |
35 | * The struct is used to trace EEH state for the associated | ||
36 | * PCI device node or PCI device. In future, it might | ||
37 | * represent PE as well so that the EEH device to form | ||
38 | * another tree except the currently existing tree of PCI | ||
39 | * buses and PCI devices | ||
40 | */ | ||
41 | #define EEH_MODE_SUPPORTED (1<<0) /* EEH supported on the device */ | ||
42 | #define EEH_MODE_NOCHECK (1<<1) /* EEH check should be skipped */ | ||
43 | #define EEH_MODE_ISOLATED (1<<2) /* The device has been isolated */ | ||
44 | #define EEH_MODE_RECOVERING (1<<3) /* Recovering the device */ | ||
45 | #define EEH_MODE_IRQ_DISABLED (1<<4) /* Interrupt disabled */ | ||
46 | |||
47 | struct eeh_dev { | ||
48 | int mode; /* EEH mode */ | ||
49 | int class_code; /* Class code of the device */ | ||
50 | int config_addr; /* Config address */ | ||
51 | int pe_config_addr; /* PE config address */ | ||
52 | int check_count; /* Times of ignored error */ | ||
53 | int freeze_count; /* Times of froze up */ | ||
54 | int false_positives; /* Times of reported #ff's */ | ||
55 | u32 config_space[16]; /* Saved PCI config space */ | ||
56 | struct pci_controller *phb; /* Associated PHB */ | ||
57 | struct device_node *dn; /* Associated device node */ | ||
58 | struct pci_dev *pdev; /* Associated PCI device */ | ||
59 | }; | ||
60 | |||
61 | static inline struct device_node *eeh_dev_to_of_node(struct eeh_dev *edev) | ||
62 | { | ||
63 | return edev->dn; | ||
64 | } | ||
65 | |||
66 | static inline struct pci_dev *eeh_dev_to_pci_dev(struct eeh_dev *edev) | ||
67 | { | ||
68 | return edev->pdev; | ||
69 | } | ||
35 | 70 | ||
36 | /* Values for eeh_mode bits in device_node */ | 71 | /* |
37 | #define EEH_MODE_SUPPORTED (1<<0) | 72 | * The struct is used to trace the registered EEH operation |
38 | #define EEH_MODE_NOCHECK (1<<1) | 73 | * callback functions. Actually, those operation callback |
39 | #define EEH_MODE_ISOLATED (1<<2) | 74 | * functions are heavily platform dependent. That means the |
40 | #define EEH_MODE_RECOVERING (1<<3) | 75 | * platform should register its own EEH operation callback |
41 | #define EEH_MODE_IRQ_DISABLED (1<<4) | 76 | * functions before any EEH further operations. |
77 | */ | ||
78 | #define EEH_OPT_DISABLE 0 /* EEH disable */ | ||
79 | #define EEH_OPT_ENABLE 1 /* EEH enable */ | ||
80 | #define EEH_OPT_THAW_MMIO 2 /* MMIO enable */ | ||
81 | #define EEH_OPT_THAW_DMA 3 /* DMA enable */ | ||
82 | #define EEH_STATE_UNAVAILABLE (1 << 0) /* State unavailable */ | ||
83 | #define EEH_STATE_NOT_SUPPORT (1 << 1) /* EEH not supported */ | ||
84 | #define EEH_STATE_RESET_ACTIVE (1 << 2) /* Active reset */ | ||
85 | #define EEH_STATE_MMIO_ACTIVE (1 << 3) /* Active MMIO */ | ||
86 | #define EEH_STATE_DMA_ACTIVE (1 << 4) /* Active DMA */ | ||
87 | #define EEH_STATE_MMIO_ENABLED (1 << 5) /* MMIO enabled */ | ||
88 | #define EEH_STATE_DMA_ENABLED (1 << 6) /* DMA enabled */ | ||
89 | #define EEH_RESET_DEACTIVATE 0 /* Deactivate the PE reset */ | ||
90 | #define EEH_RESET_HOT 1 /* Hot reset */ | ||
91 | #define EEH_RESET_FUNDAMENTAL 3 /* Fundamental reset */ | ||
92 | #define EEH_LOG_TEMP 1 /* EEH temporary error log */ | ||
93 | #define EEH_LOG_PERM 2 /* EEH permanent error log */ | ||
94 | |||
95 | struct eeh_ops { | ||
96 | char *name; | ||
97 | int (*init)(void); | ||
98 | int (*set_option)(struct device_node *dn, int option); | ||
99 | int (*get_pe_addr)(struct device_node *dn); | ||
100 | int (*get_state)(struct device_node *dn, int *state); | ||
101 | int (*reset)(struct device_node *dn, int option); | ||
102 | int (*wait_state)(struct device_node *dn, int max_wait); | ||
103 | int (*get_log)(struct device_node *dn, int severity, char *drv_log, unsigned long len); | ||
104 | int (*configure_bridge)(struct device_node *dn); | ||
105 | int (*read_config)(struct device_node *dn, int where, int size, u32 *val); | ||
106 | int (*write_config)(struct device_node *dn, int where, int size, u32 val); | ||
107 | }; | ||
108 | |||
109 | extern struct eeh_ops *eeh_ops; | ||
110 | extern int eeh_subsystem_enabled; | ||
42 | 111 | ||
43 | /* Max number of EEH freezes allowed before we consider the device | 112 | /* |
44 | * to be permanently disabled. */ | 113 | * Max number of EEH freezes allowed before we consider the device |
114 | * to be permanently disabled. | ||
115 | */ | ||
45 | #define EEH_MAX_ALLOWED_FREEZES 5 | 116 | #define EEH_MAX_ALLOWED_FREEZES 5 |
46 | 117 | ||
118 | void * __devinit eeh_dev_init(struct device_node *dn, void *data); | ||
119 | void __devinit eeh_dev_phb_init_dynamic(struct pci_controller *phb); | ||
120 | void __init eeh_dev_phb_init(void); | ||
47 | void __init eeh_init(void); | 121 | void __init eeh_init(void); |
122 | #ifdef CONFIG_PPC_PSERIES | ||
123 | int __init eeh_pseries_init(void); | ||
124 | #endif | ||
125 | int __init eeh_ops_register(struct eeh_ops *ops); | ||
126 | int __exit eeh_ops_unregister(const char *name); | ||
48 | unsigned long eeh_check_failure(const volatile void __iomem *token, | 127 | unsigned long eeh_check_failure(const volatile void __iomem *token, |
49 | unsigned long val); | 128 | unsigned long val); |
50 | int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev); | 129 | int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev); |
51 | void __init pci_addr_cache_build(void); | 130 | void __init pci_addr_cache_build(void); |
52 | |||
53 | /** | ||
54 | * eeh_add_device_early | ||
55 | * eeh_add_device_late | ||
56 | * | ||
57 | * Perform eeh initialization for devices added after boot. | ||
58 | * Call eeh_add_device_early before doing any i/o to the | ||
59 | * device (including config space i/o). Call eeh_add_device_late | ||
60 | * to finish the eeh setup for this device. | ||
61 | */ | ||
62 | void eeh_add_device_tree_early(struct device_node *); | 131 | void eeh_add_device_tree_early(struct device_node *); |
63 | void eeh_add_device_tree_late(struct pci_bus *); | 132 | void eeh_add_device_tree_late(struct pci_bus *); |
64 | |||
65 | /** | ||
66 | * eeh_remove_device_recursive - undo EEH for device & children. | ||
67 | * @dev: pci device to be removed | ||
68 | * | ||
69 | * As above, this removes the device; it also removes child | ||
70 | * pci devices as well. | ||
71 | */ | ||
72 | void eeh_remove_bus_device(struct pci_dev *); | 133 | void eeh_remove_bus_device(struct pci_dev *); |
73 | 134 | ||
74 | /** | 135 | /** |
@@ -87,8 +148,25 @@ void eeh_remove_bus_device(struct pci_dev *); | |||
87 | #define EEH_IO_ERROR_VALUE(size) (~0U >> ((4 - (size)) * 8)) | 148 | #define EEH_IO_ERROR_VALUE(size) (~0U >> ((4 - (size)) * 8)) |
88 | 149 | ||
89 | #else /* !CONFIG_EEH */ | 150 | #else /* !CONFIG_EEH */ |
151 | |||
152 | static inline void *eeh_dev_init(struct device_node *dn, void *data) | ||
153 | { | ||
154 | return NULL; | ||
155 | } | ||
156 | |||
157 | static inline void eeh_dev_phb_init_dynamic(struct pci_controller *phb) { } | ||
158 | |||
159 | static inline void eeh_dev_phb_init(void) { } | ||
160 | |||
90 | static inline void eeh_init(void) { } | 161 | static inline void eeh_init(void) { } |
91 | 162 | ||
163 | #ifdef CONFIG_PPC_PSERIES | ||
164 | static inline int eeh_pseries_init(void) | ||
165 | { | ||
166 | return 0; | ||
167 | } | ||
168 | #endif /* CONFIG_PPC_PSERIES */ | ||
169 | |||
92 | static inline unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned long val) | 170 | static inline unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned long val) |
93 | { | 171 | { |
94 | return val; | 172 | return val; |
diff --git a/arch/powerpc/include/asm/eeh_event.h b/arch/powerpc/include/asm/eeh_event.h index cc3cb04539ac..c68b012b7797 100644 --- a/arch/powerpc/include/asm/eeh_event.h +++ b/arch/powerpc/include/asm/eeh_event.h | |||
@@ -1,6 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * eeh_event.h | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | 2 | * This program is free software; you can redistribute it and/or modify |
5 | * it under the terms of the GNU General Public License as published by | 3 | * it under the terms of the GNU General Public License as published by |
6 | * the Free Software Foundation; either version 2 of the License, or | 4 | * the Free Software Foundation; either version 2 of the License, or |
@@ -22,32 +20,19 @@ | |||
22 | #define ASM_POWERPC_EEH_EVENT_H | 20 | #define ASM_POWERPC_EEH_EVENT_H |
23 | #ifdef __KERNEL__ | 21 | #ifdef __KERNEL__ |
24 | 22 | ||
25 | /** EEH event -- structure holding pci controller data that describes | 23 | /* |
26 | * a change in the isolation status of a PCI slot. A pointer | 24 | * structure holding pci controller data that describes a |
27 | * to this struct is passed as the data pointer in a notify callback. | 25 | * change in the isolation status of a PCI slot. A pointer |
26 | * to this struct is passed as the data pointer in a notify | ||
27 | * callback. | ||
28 | */ | 28 | */ |
29 | struct eeh_event { | 29 | struct eeh_event { |
30 | struct list_head list; | 30 | struct list_head list; /* to form event queue */ |
31 | struct device_node *dn; /* struct device node */ | 31 | struct eeh_dev *edev; /* EEH device */ |
32 | struct pci_dev *dev; /* affected device */ | ||
33 | }; | 32 | }; |
34 | 33 | ||
35 | /** | 34 | int eeh_send_failure_event(struct eeh_dev *edev); |
36 | * eeh_send_failure_event - generate a PCI error event | 35 | struct eeh_dev *handle_eeh_events(struct eeh_event *); |
37 | * @dev pci device | ||
38 | * | ||
39 | * This routine builds a PCI error event which will be delivered | ||
40 | * to all listeners on the eeh_notifier_chain. | ||
41 | * | ||
42 | * This routine can be called within an interrupt context; | ||
43 | * the actual event will be delivered in a normal context | ||
44 | * (from a workqueue). | ||
45 | */ | ||
46 | int eeh_send_failure_event (struct device_node *dn, | ||
47 | struct pci_dev *dev); | ||
48 | |||
49 | /* Main recovery function */ | ||
50 | struct pci_dn * handle_eeh_events (struct eeh_event *); | ||
51 | 36 | ||
52 | #endif /* __KERNEL__ */ | 37 | #endif /* __KERNEL__ */ |
53 | #endif /* ASM_POWERPC_EEH_EVENT_H */ | 38 | #endif /* ASM_POWERPC_EEH_EVENT_H */ |
diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h index 8057f4f6980f..548da3aa0a30 100644 --- a/arch/powerpc/include/asm/exception-64s.h +++ b/arch/powerpc/include/asm/exception-64s.h | |||
@@ -232,23 +232,30 @@ label##_hv: \ | |||
232 | EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common, \ | 232 | EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common, \ |
233 | EXC_HV, KVMTEST, vec) | 233 | EXC_HV, KVMTEST, vec) |
234 | 234 | ||
235 | #define __SOFTEN_TEST(h) \ | 235 | /* This associate vector numbers with bits in paca->irq_happened */ |
236 | #define SOFTEN_VALUE_0x500 PACA_IRQ_EE | ||
237 | #define SOFTEN_VALUE_0x502 PACA_IRQ_EE | ||
238 | #define SOFTEN_VALUE_0x900 PACA_IRQ_DEC | ||
239 | #define SOFTEN_VALUE_0x982 PACA_IRQ_DEC | ||
240 | |||
241 | #define __SOFTEN_TEST(h, vec) \ | ||
236 | lbz r10,PACASOFTIRQEN(r13); \ | 242 | lbz r10,PACASOFTIRQEN(r13); \ |
237 | cmpwi r10,0; \ | 243 | cmpwi r10,0; \ |
244 | li r10,SOFTEN_VALUE_##vec; \ | ||
238 | beq masked_##h##interrupt | 245 | beq masked_##h##interrupt |
239 | #define _SOFTEN_TEST(h) __SOFTEN_TEST(h) | 246 | #define _SOFTEN_TEST(h, vec) __SOFTEN_TEST(h, vec) |
240 | 247 | ||
241 | #define SOFTEN_TEST_PR(vec) \ | 248 | #define SOFTEN_TEST_PR(vec) \ |
242 | KVMTEST_PR(vec); \ | 249 | KVMTEST_PR(vec); \ |
243 | _SOFTEN_TEST(EXC_STD) | 250 | _SOFTEN_TEST(EXC_STD, vec) |
244 | 251 | ||
245 | #define SOFTEN_TEST_HV(vec) \ | 252 | #define SOFTEN_TEST_HV(vec) \ |
246 | KVMTEST(vec); \ | 253 | KVMTEST(vec); \ |
247 | _SOFTEN_TEST(EXC_HV) | 254 | _SOFTEN_TEST(EXC_HV, vec) |
248 | 255 | ||
249 | #define SOFTEN_TEST_HV_201(vec) \ | 256 | #define SOFTEN_TEST_HV_201(vec) \ |
250 | KVMTEST(vec); \ | 257 | KVMTEST(vec); \ |
251 | _SOFTEN_TEST(EXC_STD) | 258 | _SOFTEN_TEST(EXC_STD, vec) |
252 | 259 | ||
253 | #define __MASKABLE_EXCEPTION_PSERIES(vec, label, h, extra) \ | 260 | #define __MASKABLE_EXCEPTION_PSERIES(vec, label, h, extra) \ |
254 | HMT_MEDIUM; \ | 261 | HMT_MEDIUM; \ |
@@ -272,73 +279,55 @@ label##_hv: \ | |||
272 | _MASKABLE_EXCEPTION_PSERIES(vec, label, \ | 279 | _MASKABLE_EXCEPTION_PSERIES(vec, label, \ |
273 | EXC_HV, SOFTEN_TEST_HV) | 280 | EXC_HV, SOFTEN_TEST_HV) |
274 | 281 | ||
275 | #ifdef CONFIG_PPC_ISERIES | 282 | /* |
276 | #define DISABLE_INTS \ | 283 | * Our exception common code can be passed various "additions" |
277 | li r11,0; \ | 284 | * to specify the behaviour of interrupts, whether to kick the |
278 | stb r11,PACASOFTIRQEN(r13); \ | 285 | * runlatch, etc... |
279 | BEGIN_FW_FTR_SECTION; \ | 286 | */ |
280 | stb r11,PACAHARDIRQEN(r13); \ | 287 | |
281 | END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES); \ | 288 | /* Exception addition: Hard disable interrupts */ |
282 | TRACE_DISABLE_INTS; \ | 289 | #define DISABLE_INTS SOFT_DISABLE_INTS(r10,r11) |
283 | BEGIN_FW_FTR_SECTION; \ | ||
284 | mfmsr r10; \ | ||
285 | ori r10,r10,MSR_EE; \ | ||
286 | mtmsrd r10,1; \ | ||
287 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) | ||
288 | #else | ||
289 | #define DISABLE_INTS \ | ||
290 | li r11,0; \ | ||
291 | stb r11,PACASOFTIRQEN(r13); \ | ||
292 | stb r11,PACAHARDIRQEN(r13); \ | ||
293 | TRACE_DISABLE_INTS | ||
294 | #endif /* CONFIG_PPC_ISERIES */ | ||
295 | 290 | ||
291 | /* Exception addition: Keep interrupt state */ | ||
296 | #define ENABLE_INTS \ | 292 | #define ENABLE_INTS \ |
293 | ld r11,PACAKMSR(r13); \ | ||
297 | ld r12,_MSR(r1); \ | 294 | ld r12,_MSR(r1); \ |
298 | mfmsr r11; \ | ||
299 | rlwimi r11,r12,0,MSR_EE; \ | 295 | rlwimi r11,r12,0,MSR_EE; \ |
300 | mtmsrd r11,1 | 296 | mtmsrd r11,1 |
301 | 297 | ||
302 | #define STD_EXCEPTION_COMMON(trap, label, hdlr) \ | 298 | #define ADD_NVGPRS \ |
303 | .align 7; \ | 299 | bl .save_nvgprs |
304 | .globl label##_common; \ | 300 | |
305 | label##_common: \ | 301 | #define RUNLATCH_ON \ |
306 | EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN); \ | 302 | BEGIN_FTR_SECTION \ |
307 | DISABLE_INTS; \ | 303 | clrrdi r3,r1,THREAD_SHIFT; \ |
308 | bl .save_nvgprs; \ | 304 | ld r4,TI_LOCAL_FLAGS(r3); \ |
309 | addi r3,r1,STACK_FRAME_OVERHEAD; \ | 305 | andi. r0,r4,_TLF_RUNLATCH; \ |
310 | bl hdlr; \ | 306 | beql ppc64_runlatch_on_trampoline; \ |
311 | b .ret_from_except | 307 | END_FTR_SECTION_IFSET(CPU_FTR_CTRL) |
308 | |||
309 | #define EXCEPTION_COMMON(trap, label, hdlr, ret, additions) \ | ||
310 | .align 7; \ | ||
311 | .globl label##_common; \ | ||
312 | label##_common: \ | ||
313 | EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN); \ | ||
314 | additions; \ | ||
315 | addi r3,r1,STACK_FRAME_OVERHEAD; \ | ||
316 | bl hdlr; \ | ||
317 | b ret | ||
318 | |||
319 | #define STD_EXCEPTION_COMMON(trap, label, hdlr) \ | ||
320 | EXCEPTION_COMMON(trap, label, hdlr, ret_from_except, \ | ||
321 | ADD_NVGPRS;DISABLE_INTS) | ||
312 | 322 | ||
313 | /* | 323 | /* |
314 | * Like STD_EXCEPTION_COMMON, but for exceptions that can occur | 324 | * Like STD_EXCEPTION_COMMON, but for exceptions that can occur |
315 | * in the idle task and therefore need the special idle handling. | 325 | * in the idle task and therefore need the special idle handling |
326 | * (finish nap and runlatch) | ||
316 | */ | 327 | */ |
317 | #define STD_EXCEPTION_COMMON_IDLE(trap, label, hdlr) \ | 328 | #define STD_EXCEPTION_COMMON_ASYNC(trap, label, hdlr) \ |
318 | .align 7; \ | 329 | EXCEPTION_COMMON(trap, label, hdlr, ret_from_except_lite, \ |
319 | .globl label##_common; \ | 330 | FINISH_NAP;RUNLATCH_ON;DISABLE_INTS) |
320 | label##_common: \ | ||
321 | EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN); \ | ||
322 | FINISH_NAP; \ | ||
323 | DISABLE_INTS; \ | ||
324 | bl .save_nvgprs; \ | ||
325 | addi r3,r1,STACK_FRAME_OVERHEAD; \ | ||
326 | bl hdlr; \ | ||
327 | b .ret_from_except | ||
328 | |||
329 | #define STD_EXCEPTION_COMMON_LITE(trap, label, hdlr) \ | ||
330 | .align 7; \ | ||
331 | .globl label##_common; \ | ||
332 | label##_common: \ | ||
333 | EXCEPTION_PROLOG_COMMON(trap, PACA_EXGEN); \ | ||
334 | FINISH_NAP; \ | ||
335 | DISABLE_INTS; \ | ||
336 | BEGIN_FTR_SECTION \ | ||
337 | bl .ppc64_runlatch_on; \ | ||
338 | END_FTR_SECTION_IFSET(CPU_FTR_CTRL) \ | ||
339 | addi r3,r1,STACK_FRAME_OVERHEAD; \ | ||
340 | bl hdlr; \ | ||
341 | b .ret_from_except_lite | ||
342 | 331 | ||
343 | /* | 332 | /* |
344 | * When the idle code in power4_idle puts the CPU into NAP mode, | 333 | * When the idle code in power4_idle puts the CPU into NAP mode, |
diff --git a/arch/powerpc/include/asm/fadump.h b/arch/powerpc/include/asm/fadump.h new file mode 100644 index 000000000000..88dbf9659185 --- /dev/null +++ b/arch/powerpc/include/asm/fadump.h | |||
@@ -0,0 +1,218 @@ | |||
1 | /* | ||
2 | * Firmware Assisted dump header file. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
17 | * | ||
18 | * Copyright 2011 IBM Corporation | ||
19 | * Author: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com> | ||
20 | */ | ||
21 | |||
22 | #ifndef __PPC64_FA_DUMP_H__ | ||
23 | #define __PPC64_FA_DUMP_H__ | ||
24 | |||
25 | #ifdef CONFIG_FA_DUMP | ||
26 | |||
27 | /* | ||
28 | * The RMA region will be saved for later dumping when kernel crashes. | ||
29 | * RMA is Real Mode Area, the first block of logical memory address owned | ||
30 | * by logical partition, containing the storage that may be accessed with | ||
31 | * translate off. | ||
32 | */ | ||
33 | #define RMA_START 0x0 | ||
34 | #define RMA_END (ppc64_rma_size) | ||
35 | |||
36 | /* | ||
37 | * On some Power systems where RMO is 128MB, it still requires minimum of | ||
38 | * 256MB for kernel to boot successfully. When kdump infrastructure is | ||
39 | * configured to save vmcore over network, we run into OOM issue while | ||
40 | * loading modules related to network setup. Hence we need aditional 64M | ||
41 | * of memory to avoid OOM issue. | ||
42 | */ | ||
43 | #define MIN_BOOT_MEM (((RMA_END < (0x1UL << 28)) ? (0x1UL << 28) : RMA_END) \ | ||
44 | + (0x1UL << 26)) | ||
45 | |||
46 | #define memblock_num_regions(memblock_type) (memblock.memblock_type.cnt) | ||
47 | |||
48 | #ifndef ELF_CORE_EFLAGS | ||
49 | #define ELF_CORE_EFLAGS 0 | ||
50 | #endif | ||
51 | |||
52 | /* Firmware provided dump sections */ | ||
53 | #define FADUMP_CPU_STATE_DATA 0x0001 | ||
54 | #define FADUMP_HPTE_REGION 0x0002 | ||
55 | #define FADUMP_REAL_MODE_REGION 0x0011 | ||
56 | |||
57 | /* Dump request flag */ | ||
58 | #define FADUMP_REQUEST_FLAG 0x00000001 | ||
59 | |||
60 | /* FAD commands */ | ||
61 | #define FADUMP_REGISTER 1 | ||
62 | #define FADUMP_UNREGISTER 2 | ||
63 | #define FADUMP_INVALIDATE 3 | ||
64 | |||
65 | /* Dump status flag */ | ||
66 | #define FADUMP_ERROR_FLAG 0x2000 | ||
67 | |||
68 | #define FADUMP_CPU_ID_MASK ((1UL << 32) - 1) | ||
69 | |||
70 | #define CPU_UNKNOWN (~((u32)0)) | ||
71 | |||
72 | /* Utility macros */ | ||
73 | #define SKIP_TO_NEXT_CPU(reg_entry) \ | ||
74 | ({ \ | ||
75 | while (reg_entry->reg_id != REG_ID("CPUEND")) \ | ||
76 | reg_entry++; \ | ||
77 | reg_entry++; \ | ||
78 | }) | ||
79 | |||
80 | /* Kernel Dump section info */ | ||
81 | struct fadump_section { | ||
82 | u32 request_flag; | ||
83 | u16 source_data_type; | ||
84 | u16 error_flags; | ||
85 | u64 source_address; | ||
86 | u64 source_len; | ||
87 | u64 bytes_dumped; | ||
88 | u64 destination_address; | ||
89 | }; | ||
90 | |||
91 | /* ibm,configure-kernel-dump header. */ | ||
92 | struct fadump_section_header { | ||
93 | u32 dump_format_version; | ||
94 | u16 dump_num_sections; | ||
95 | u16 dump_status_flag; | ||
96 | u32 offset_first_dump_section; | ||
97 | |||
98 | /* Fields for disk dump option. */ | ||
99 | u32 dd_block_size; | ||
100 | u64 dd_block_offset; | ||
101 | u64 dd_num_blocks; | ||
102 | u32 dd_offset_disk_path; | ||
103 | |||
104 | /* Maximum time allowed to prevent an automatic dump-reboot. */ | ||
105 | u32 max_time_auto; | ||
106 | }; | ||
107 | |||
108 | /* | ||
109 | * Firmware Assisted dump memory structure. This structure is required for | ||
110 | * registering future kernel dump with power firmware through rtas call. | ||
111 | * | ||
112 | * No disk dump option. Hence disk dump path string section is not included. | ||
113 | */ | ||
114 | struct fadump_mem_struct { | ||
115 | struct fadump_section_header header; | ||
116 | |||
117 | /* Kernel dump sections */ | ||
118 | struct fadump_section cpu_state_data; | ||
119 | struct fadump_section hpte_region; | ||
120 | struct fadump_section rmr_region; | ||
121 | }; | ||
122 | |||
123 | /* Firmware-assisted dump configuration details. */ | ||
124 | struct fw_dump { | ||
125 | unsigned long cpu_state_data_size; | ||
126 | unsigned long hpte_region_size; | ||
127 | unsigned long boot_memory_size; | ||
128 | unsigned long reserve_dump_area_start; | ||
129 | unsigned long reserve_dump_area_size; | ||
130 | /* cmd line option during boot */ | ||
131 | unsigned long reserve_bootvar; | ||
132 | |||
133 | unsigned long fadumphdr_addr; | ||
134 | unsigned long cpu_notes_buf; | ||
135 | unsigned long cpu_notes_buf_size; | ||
136 | |||
137 | int ibm_configure_kernel_dump; | ||
138 | |||
139 | unsigned long fadump_enabled:1; | ||
140 | unsigned long fadump_supported:1; | ||
141 | unsigned long dump_active:1; | ||
142 | unsigned long dump_registered:1; | ||
143 | }; | ||
144 | |||
145 | /* | ||
146 | * Copy the ascii values for first 8 characters from a string into u64 | ||
147 | * variable at their respective indexes. | ||
148 | * e.g. | ||
149 | * The string "FADMPINF" will be converted into 0x4641444d50494e46 | ||
150 | */ | ||
151 | static inline u64 str_to_u64(const char *str) | ||
152 | { | ||
153 | u64 val = 0; | ||
154 | int i; | ||
155 | |||
156 | for (i = 0; i < sizeof(val); i++) | ||
157 | val = (*str) ? (val << 8) | *str++ : val << 8; | ||
158 | return val; | ||
159 | } | ||
160 | #define STR_TO_HEX(x) str_to_u64(x) | ||
161 | #define REG_ID(x) str_to_u64(x) | ||
162 | |||
163 | #define FADUMP_CRASH_INFO_MAGIC STR_TO_HEX("FADMPINF") | ||
164 | #define REGSAVE_AREA_MAGIC STR_TO_HEX("REGSAVE") | ||
165 | |||
166 | /* The firmware-assisted dump format. | ||
167 | * | ||
168 | * The register save area is an area in the partition's memory used to preserve | ||
169 | * the register contents (CPU state data) for the active CPUs during a firmware | ||
170 | * assisted dump. The dump format contains register save area header followed | ||
171 | * by register entries. Each list of registers for a CPU starts with | ||
172 | * "CPUSTRT" and ends with "CPUEND". | ||
173 | */ | ||
174 | |||
175 | /* Register save area header. */ | ||
176 | struct fadump_reg_save_area_header { | ||
177 | u64 magic_number; | ||
178 | u32 version; | ||
179 | u32 num_cpu_offset; | ||
180 | }; | ||
181 | |||
182 | /* Register entry. */ | ||
183 | struct fadump_reg_entry { | ||
184 | u64 reg_id; | ||
185 | u64 reg_value; | ||
186 | }; | ||
187 | |||
188 | /* fadump crash info structure */ | ||
189 | struct fadump_crash_info_header { | ||
190 | u64 magic_number; | ||
191 | u64 elfcorehdr_addr; | ||
192 | u32 crashing_cpu; | ||
193 | struct pt_regs regs; | ||
194 | struct cpumask cpu_online_mask; | ||
195 | }; | ||
196 | |||
197 | /* Crash memory ranges */ | ||
198 | #define INIT_CRASHMEM_RANGES (INIT_MEMBLOCK_REGIONS + 2) | ||
199 | |||
200 | struct fad_crash_memory_ranges { | ||
201 | unsigned long long base; | ||
202 | unsigned long long size; | ||
203 | }; | ||
204 | |||
205 | extern int early_init_dt_scan_fw_dump(unsigned long node, | ||
206 | const char *uname, int depth, void *data); | ||
207 | extern int fadump_reserve_mem(void); | ||
208 | extern int setup_fadump(void); | ||
209 | extern int is_fadump_active(void); | ||
210 | extern void crash_fadump(struct pt_regs *, const char *); | ||
211 | extern void fadump_cleanup(void); | ||
212 | |||
213 | extern void vmcore_cleanup(void); | ||
214 | #else /* CONFIG_FA_DUMP */ | ||
215 | static inline int is_fadump_active(void) { return 0; } | ||
216 | static inline void crash_fadump(struct pt_regs *regs, const char *str) { } | ||
217 | #endif | ||
218 | #endif | ||
diff --git a/arch/powerpc/include/asm/firmware.h b/arch/powerpc/include/asm/firmware.h index 14db29b18d0e..ad0b751b0d78 100644 --- a/arch/powerpc/include/asm/firmware.h +++ b/arch/powerpc/include/asm/firmware.h | |||
@@ -41,7 +41,6 @@ | |||
41 | #define FW_FEATURE_XDABR ASM_CONST(0x0000000000040000) | 41 | #define FW_FEATURE_XDABR ASM_CONST(0x0000000000040000) |
42 | #define FW_FEATURE_MULTITCE ASM_CONST(0x0000000000080000) | 42 | #define FW_FEATURE_MULTITCE ASM_CONST(0x0000000000080000) |
43 | #define FW_FEATURE_SPLPAR ASM_CONST(0x0000000000100000) | 43 | #define FW_FEATURE_SPLPAR ASM_CONST(0x0000000000100000) |
44 | #define FW_FEATURE_ISERIES ASM_CONST(0x0000000000200000) | ||
45 | #define FW_FEATURE_LPAR ASM_CONST(0x0000000000400000) | 44 | #define FW_FEATURE_LPAR ASM_CONST(0x0000000000400000) |
46 | #define FW_FEATURE_PS3_LV1 ASM_CONST(0x0000000000800000) | 45 | #define FW_FEATURE_PS3_LV1 ASM_CONST(0x0000000000800000) |
47 | #define FW_FEATURE_BEAT ASM_CONST(0x0000000001000000) | 46 | #define FW_FEATURE_BEAT ASM_CONST(0x0000000001000000) |
@@ -65,8 +64,6 @@ enum { | |||
65 | FW_FEATURE_MULTITCE | FW_FEATURE_SPLPAR | FW_FEATURE_LPAR | | 64 | FW_FEATURE_MULTITCE | FW_FEATURE_SPLPAR | FW_FEATURE_LPAR | |
66 | FW_FEATURE_CMO | FW_FEATURE_VPHN | FW_FEATURE_XCMO, | 65 | FW_FEATURE_CMO | FW_FEATURE_VPHN | FW_FEATURE_XCMO, |
67 | FW_FEATURE_PSERIES_ALWAYS = 0, | 66 | FW_FEATURE_PSERIES_ALWAYS = 0, |
68 | FW_FEATURE_ISERIES_POSSIBLE = FW_FEATURE_ISERIES | FW_FEATURE_LPAR, | ||
69 | FW_FEATURE_ISERIES_ALWAYS = FW_FEATURE_ISERIES | FW_FEATURE_LPAR, | ||
70 | FW_FEATURE_POWERNV_POSSIBLE = FW_FEATURE_OPAL | FW_FEATURE_OPALv2, | 67 | FW_FEATURE_POWERNV_POSSIBLE = FW_FEATURE_OPAL | FW_FEATURE_OPALv2, |
71 | FW_FEATURE_POWERNV_ALWAYS = 0, | 68 | FW_FEATURE_POWERNV_ALWAYS = 0, |
72 | FW_FEATURE_PS3_POSSIBLE = FW_FEATURE_LPAR | FW_FEATURE_PS3_LV1, | 69 | FW_FEATURE_PS3_POSSIBLE = FW_FEATURE_LPAR | FW_FEATURE_PS3_LV1, |
@@ -79,9 +76,6 @@ enum { | |||
79 | #ifdef CONFIG_PPC_PSERIES | 76 | #ifdef CONFIG_PPC_PSERIES |
80 | FW_FEATURE_PSERIES_POSSIBLE | | 77 | FW_FEATURE_PSERIES_POSSIBLE | |
81 | #endif | 78 | #endif |
82 | #ifdef CONFIG_PPC_ISERIES | ||
83 | FW_FEATURE_ISERIES_POSSIBLE | | ||
84 | #endif | ||
85 | #ifdef CONFIG_PPC_POWERNV | 79 | #ifdef CONFIG_PPC_POWERNV |
86 | FW_FEATURE_POWERNV_POSSIBLE | | 80 | FW_FEATURE_POWERNV_POSSIBLE | |
87 | #endif | 81 | #endif |
@@ -99,9 +93,6 @@ enum { | |||
99 | #ifdef CONFIG_PPC_PSERIES | 93 | #ifdef CONFIG_PPC_PSERIES |
100 | FW_FEATURE_PSERIES_ALWAYS & | 94 | FW_FEATURE_PSERIES_ALWAYS & |
101 | #endif | 95 | #endif |
102 | #ifdef CONFIG_PPC_ISERIES | ||
103 | FW_FEATURE_ISERIES_ALWAYS & | ||
104 | #endif | ||
105 | #ifdef CONFIG_PPC_POWERNV | 96 | #ifdef CONFIG_PPC_POWERNV |
106 | FW_FEATURE_POWERNV_ALWAYS & | 97 | FW_FEATURE_POWERNV_ALWAYS & |
107 | #endif | 98 | #endif |
diff --git a/arch/powerpc/include/asm/fsl_guts.h b/arch/powerpc/include/asm/fsl_guts.h index bebd12463ec9..ce04530d2000 100644 --- a/arch/powerpc/include/asm/fsl_guts.h +++ b/arch/powerpc/include/asm/fsl_guts.h | |||
@@ -4,7 +4,7 @@ | |||
4 | * Authors: Jeff Brown | 4 | * Authors: Jeff Brown |
5 | * Timur Tabi <timur@freescale.com> | 5 | * Timur Tabi <timur@freescale.com> |
6 | * | 6 | * |
7 | * Copyright 2004,2007 Freescale Semiconductor, Inc | 7 | * Copyright 2004,2007,2012 Freescale Semiconductor, Inc |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or modify it | 9 | * This program is free software; you can redistribute it and/or modify it |
10 | * under the terms of the GNU General Public License as published by the | 10 | * under the terms of the GNU General Public License as published by the |
@@ -114,6 +114,10 @@ struct ccsr_guts_86xx { | |||
114 | __be32 srds2cr1; /* 0x.0f44 - SerDes2 Control Register 0 */ | 114 | __be32 srds2cr1; /* 0x.0f44 - SerDes2 Control Register 0 */ |
115 | } __attribute__ ((packed)); | 115 | } __attribute__ ((packed)); |
116 | 116 | ||
117 | |||
118 | /* Alternate function signal multiplex control */ | ||
119 | #define MPC85xx_PMUXCR_QE(x) (0x8000 >> (x)) | ||
120 | |||
117 | #ifdef CONFIG_PPC_86xx | 121 | #ifdef CONFIG_PPC_86xx |
118 | 122 | ||
119 | #define CCSR_GUTS_DMACR_DEV_SSI 0 /* DMA controller/channel set to SSI */ | 123 | #define CCSR_GUTS_DMACR_DEV_SSI 0 /* DMA controller/channel set to SSI */ |
diff --git a/arch/powerpc/include/asm/hw_irq.h b/arch/powerpc/include/asm/hw_irq.h index bb712c9488b3..51010bfc792e 100644 --- a/arch/powerpc/include/asm/hw_irq.h +++ b/arch/powerpc/include/asm/hw_irq.h | |||
@@ -11,6 +11,27 @@ | |||
11 | #include <asm/ptrace.h> | 11 | #include <asm/ptrace.h> |
12 | #include <asm/processor.h> | 12 | #include <asm/processor.h> |
13 | 13 | ||
14 | #ifdef CONFIG_PPC64 | ||
15 | |||
16 | /* | ||
17 | * PACA flags in paca->irq_happened. | ||
18 | * | ||
19 | * This bits are set when interrupts occur while soft-disabled | ||
20 | * and allow a proper replay. Additionally, PACA_IRQ_HARD_DIS | ||
21 | * is set whenever we manually hard disable. | ||
22 | */ | ||
23 | #define PACA_IRQ_HARD_DIS 0x01 | ||
24 | #define PACA_IRQ_DBELL 0x02 | ||
25 | #define PACA_IRQ_EE 0x04 | ||
26 | #define PACA_IRQ_DEC 0x08 /* Or FIT */ | ||
27 | #define PACA_IRQ_EE_EDGE 0x10 /* BookE only */ | ||
28 | |||
29 | #endif /* CONFIG_PPC64 */ | ||
30 | |||
31 | #ifndef __ASSEMBLY__ | ||
32 | |||
33 | extern void __replay_interrupt(unsigned int vector); | ||
34 | |||
14 | extern void timer_interrupt(struct pt_regs *); | 35 | extern void timer_interrupt(struct pt_regs *); |
15 | 36 | ||
16 | #ifdef CONFIG_PPC64 | 37 | #ifdef CONFIG_PPC64 |
@@ -42,7 +63,6 @@ static inline unsigned long arch_local_irq_disable(void) | |||
42 | } | 63 | } |
43 | 64 | ||
44 | extern void arch_local_irq_restore(unsigned long); | 65 | extern void arch_local_irq_restore(unsigned long); |
45 | extern void iseries_handle_interrupts(void); | ||
46 | 66 | ||
47 | static inline void arch_local_irq_enable(void) | 67 | static inline void arch_local_irq_enable(void) |
48 | { | 68 | { |
@@ -68,16 +88,33 @@ static inline bool arch_irqs_disabled(void) | |||
68 | #define __hard_irq_enable() asm volatile("wrteei 1" : : : "memory"); | 88 | #define __hard_irq_enable() asm volatile("wrteei 1" : : : "memory"); |
69 | #define __hard_irq_disable() asm volatile("wrteei 0" : : : "memory"); | 89 | #define __hard_irq_disable() asm volatile("wrteei 0" : : : "memory"); |
70 | #else | 90 | #else |
71 | #define __hard_irq_enable() __mtmsrd(mfmsr() | MSR_EE, 1) | 91 | #define __hard_irq_enable() __mtmsrd(local_paca->kernel_msr | MSR_EE, 1) |
72 | #define __hard_irq_disable() __mtmsrd(mfmsr() & ~MSR_EE, 1) | 92 | #define __hard_irq_disable() __mtmsrd(local_paca->kernel_msr, 1) |
73 | #endif | 93 | #endif |
74 | 94 | ||
75 | #define hard_irq_disable() \ | 95 | static inline void hard_irq_disable(void) |
76 | do { \ | 96 | { |
77 | __hard_irq_disable(); \ | 97 | __hard_irq_disable(); |
78 | get_paca()->soft_enabled = 0; \ | 98 | get_paca()->soft_enabled = 0; |
79 | get_paca()->hard_enabled = 0; \ | 99 | get_paca()->irq_happened |= PACA_IRQ_HARD_DIS; |
80 | } while(0) | 100 | } |
101 | |||
102 | /* | ||
103 | * This is called by asynchronous interrupts to conditionally | ||
104 | * re-enable hard interrupts when soft-disabled after having | ||
105 | * cleared the source of the interrupt | ||
106 | */ | ||
107 | static inline void may_hard_irq_enable(void) | ||
108 | { | ||
109 | get_paca()->irq_happened &= ~PACA_IRQ_HARD_DIS; | ||
110 | if (!(get_paca()->irq_happened & PACA_IRQ_EE)) | ||
111 | __hard_irq_enable(); | ||
112 | } | ||
113 | |||
114 | static inline bool arch_irq_disabled_regs(struct pt_regs *regs) | ||
115 | { | ||
116 | return !regs->softe; | ||
117 | } | ||
81 | 118 | ||
82 | #else /* CONFIG_PPC64 */ | 119 | #else /* CONFIG_PPC64 */ |
83 | 120 | ||
@@ -139,6 +176,13 @@ static inline bool arch_irqs_disabled(void) | |||
139 | 176 | ||
140 | #define hard_irq_disable() arch_local_irq_disable() | 177 | #define hard_irq_disable() arch_local_irq_disable() |
141 | 178 | ||
179 | static inline bool arch_irq_disabled_regs(struct pt_regs *regs) | ||
180 | { | ||
181 | return !(regs->msr & MSR_EE); | ||
182 | } | ||
183 | |||
184 | static inline void may_hard_irq_enable(void) { } | ||
185 | |||
142 | #endif /* CONFIG_PPC64 */ | 186 | #endif /* CONFIG_PPC64 */ |
143 | 187 | ||
144 | #define ARCH_IRQ_INIT_FLAGS IRQ_NOREQUEST | 188 | #define ARCH_IRQ_INIT_FLAGS IRQ_NOREQUEST |
@@ -149,5 +193,6 @@ static inline bool arch_irqs_disabled(void) | |||
149 | */ | 193 | */ |
150 | struct irq_chip; | 194 | struct irq_chip; |
151 | 195 | ||
196 | #endif /* __ASSEMBLY__ */ | ||
152 | #endif /* __KERNEL__ */ | 197 | #endif /* __KERNEL__ */ |
153 | #endif /* _ASM_POWERPC_HW_IRQ_H */ | 198 | #endif /* _ASM_POWERPC_HW_IRQ_H */ |
diff --git a/arch/powerpc/include/asm/irqflags.h b/arch/powerpc/include/asm/irqflags.h index b0b06d85788d..6f9b6e23dc5a 100644 --- a/arch/powerpc/include/asm/irqflags.h +++ b/arch/powerpc/include/asm/irqflags.h | |||
@@ -39,24 +39,31 @@ | |||
39 | #define TRACE_ENABLE_INTS TRACE_WITH_FRAME_BUFFER(.trace_hardirqs_on) | 39 | #define TRACE_ENABLE_INTS TRACE_WITH_FRAME_BUFFER(.trace_hardirqs_on) |
40 | #define TRACE_DISABLE_INTS TRACE_WITH_FRAME_BUFFER(.trace_hardirqs_off) | 40 | #define TRACE_DISABLE_INTS TRACE_WITH_FRAME_BUFFER(.trace_hardirqs_off) |
41 | 41 | ||
42 | #define TRACE_AND_RESTORE_IRQ_PARTIAL(en,skip) \ | 42 | /* |
43 | cmpdi en,0; \ | 43 | * This is used by assembly code to soft-disable interrupts |
44 | bne 95f; \ | 44 | */ |
45 | stb en,PACASOFTIRQEN(r13); \ | 45 | #define SOFT_DISABLE_INTS(__rA, __rB) \ |
46 | TRACE_WITH_FRAME_BUFFER(.trace_hardirqs_off) \ | 46 | lbz __rA,PACASOFTIRQEN(r13); \ |
47 | b skip; \ | 47 | lbz __rB,PACAIRQHAPPENED(r13); \ |
48 | 95: TRACE_WITH_FRAME_BUFFER(.trace_hardirqs_on) \ | 48 | cmpwi cr0,__rA,0; \ |
49 | li en,1; | 49 | li __rA,0; \ |
50 | #define TRACE_AND_RESTORE_IRQ(en) \ | 50 | ori __rB,__rB,PACA_IRQ_HARD_DIS; \ |
51 | TRACE_AND_RESTORE_IRQ_PARTIAL(en,96f); \ | 51 | stb __rB,PACAIRQHAPPENED(r13); \ |
52 | stb en,PACASOFTIRQEN(r13); \ | 52 | beq 44f; \ |
53 | 96: | 53 | stb __rA,PACASOFTIRQEN(r13); \ |
54 | TRACE_DISABLE_INTS; \ | ||
55 | 44: | ||
56 | |||
54 | #else | 57 | #else |
55 | #define TRACE_ENABLE_INTS | 58 | #define TRACE_ENABLE_INTS |
56 | #define TRACE_DISABLE_INTS | 59 | #define TRACE_DISABLE_INTS |
57 | #define TRACE_AND_RESTORE_IRQ_PARTIAL(en,skip) | 60 | |
58 | #define TRACE_AND_RESTORE_IRQ(en) \ | 61 | #define SOFT_DISABLE_INTS(__rA, __rB) \ |
59 | stb en,PACASOFTIRQEN(r13) | 62 | lbz __rA,PACAIRQHAPPENED(r13); \ |
63 | li __rB,0; \ | ||
64 | ori __rA,__rA,PACA_IRQ_HARD_DIS; \ | ||
65 | stb __rB,PACASOFTIRQEN(r13); \ | ||
66 | stb __rA,PACAIRQHAPPENED(r13) | ||
60 | #endif | 67 | #endif |
61 | #endif | 68 | #endif |
62 | 69 | ||
diff --git a/arch/powerpc/include/asm/iseries/alpaca.h b/arch/powerpc/include/asm/iseries/alpaca.h deleted file mode 100644 index c0cce6727a69..000000000000 --- a/arch/powerpc/include/asm/iseries/alpaca.h +++ /dev/null | |||
@@ -1,31 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright © 2008 Stephen Rothwell IBM Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | #ifndef _ASM_POWERPC_ISERIES_ALPACA_H | ||
19 | #define _ASM_POWERPC_ISERIES_ALPACA_H | ||
20 | |||
21 | /* | ||
22 | * This is the part of the paca that the iSeries hypervisor | ||
23 | * needs to be statically initialised. Immediately after boot | ||
24 | * we switch to the normal Linux paca. | ||
25 | */ | ||
26 | struct alpaca { | ||
27 | struct lppaca *lppaca_ptr; /* Pointer to LpPaca for PLIC */ | ||
28 | const void *reg_save_ptr; /* Pointer to LpRegSave for PLIC */ | ||
29 | }; | ||
30 | |||
31 | #endif /* _ASM_POWERPC_ISERIES_ALPACA_H */ | ||
diff --git a/arch/powerpc/include/asm/iseries/hv_call.h b/arch/powerpc/include/asm/iseries/hv_call.h deleted file mode 100644 index 162d653ad51f..000000000000 --- a/arch/powerpc/include/asm/iseries/hv_call.h +++ /dev/null | |||
@@ -1,111 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001 Mike Corrigan IBM Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | * | ||
18 | * This file contains the "hypervisor call" interface which is used to | ||
19 | * drive the hypervisor from the OS. | ||
20 | */ | ||
21 | #ifndef _ASM_POWERPC_ISERIES_HV_CALL_H | ||
22 | #define _ASM_POWERPC_ISERIES_HV_CALL_H | ||
23 | |||
24 | #include <asm/iseries/hv_call_sc.h> | ||
25 | #include <asm/iseries/hv_types.h> | ||
26 | #include <asm/paca.h> | ||
27 | |||
28 | /* Type of yield for HvCallBaseYieldProcessor */ | ||
29 | #define HvCall_YieldTimed 0 /* Yield until specified time (tb) */ | ||
30 | #define HvCall_YieldToActive 1 /* Yield until all active procs have run */ | ||
31 | #define HvCall_YieldToProc 2 /* Yield until the specified processor has run */ | ||
32 | |||
33 | /* interrupt masks for setEnabledInterrupts */ | ||
34 | #define HvCall_MaskIPI 0x00000001 | ||
35 | #define HvCall_MaskLpEvent 0x00000002 | ||
36 | #define HvCall_MaskLpProd 0x00000004 | ||
37 | #define HvCall_MaskTimeout 0x00000008 | ||
38 | |||
39 | /* Log buffer formats */ | ||
40 | #define HvCall_LogBuffer_ASCII 0 | ||
41 | #define HvCall_LogBuffer_EBCDIC 1 | ||
42 | |||
43 | #define HvCallBaseAckDeferredInts HvCallBase + 0 | ||
44 | #define HvCallBaseCpmPowerOff HvCallBase + 1 | ||
45 | #define HvCallBaseGetHwPatch HvCallBase + 2 | ||
46 | #define HvCallBaseReIplSpAttn HvCallBase + 3 | ||
47 | #define HvCallBaseSetASR HvCallBase + 4 | ||
48 | #define HvCallBaseSetASRAndRfi HvCallBase + 5 | ||
49 | #define HvCallBaseSetIMR HvCallBase + 6 | ||
50 | #define HvCallBaseSendIPI HvCallBase + 7 | ||
51 | #define HvCallBaseTerminateMachine HvCallBase + 8 | ||
52 | #define HvCallBaseTerminateMachineSrc HvCallBase + 9 | ||
53 | #define HvCallBaseProcessPlicInterrupts HvCallBase + 10 | ||
54 | #define HvCallBaseIsPrimaryCpmOrMsdIpl HvCallBase + 11 | ||
55 | #define HvCallBaseSetVirtualSIT HvCallBase + 12 | ||
56 | #define HvCallBaseVaryOffThisProcessor HvCallBase + 13 | ||
57 | #define HvCallBaseVaryOffMemoryChunk HvCallBase + 14 | ||
58 | #define HvCallBaseVaryOffInteractivePercentage HvCallBase + 15 | ||
59 | #define HvCallBaseSendLpProd HvCallBase + 16 | ||
60 | #define HvCallBaseSetEnabledInterrupts HvCallBase + 17 | ||
61 | #define HvCallBaseYieldProcessor HvCallBase + 18 | ||
62 | #define HvCallBaseVaryOffSharedProcUnits HvCallBase + 19 | ||
63 | #define HvCallBaseSetVirtualDecr HvCallBase + 20 | ||
64 | #define HvCallBaseClearLogBuffer HvCallBase + 21 | ||
65 | #define HvCallBaseGetLogBufferCodePage HvCallBase + 22 | ||
66 | #define HvCallBaseGetLogBufferFormat HvCallBase + 23 | ||
67 | #define HvCallBaseGetLogBufferLength HvCallBase + 24 | ||
68 | #define HvCallBaseReadLogBuffer HvCallBase + 25 | ||
69 | #define HvCallBaseSetLogBufferFormatAndCodePage HvCallBase + 26 | ||
70 | #define HvCallBaseWriteLogBuffer HvCallBase + 27 | ||
71 | #define HvCallBaseRouter28 HvCallBase + 28 | ||
72 | #define HvCallBaseRouter29 HvCallBase + 29 | ||
73 | #define HvCallBaseRouter30 HvCallBase + 30 | ||
74 | #define HvCallBaseSetDebugBus HvCallBase + 31 | ||
75 | |||
76 | #define HvCallCcSetDABR HvCallCc + 7 | ||
77 | |||
78 | static inline void HvCall_setVirtualDecr(void) | ||
79 | { | ||
80 | /* | ||
81 | * Ignore any error return codes - most likely means that the | ||
82 | * target value for the LP has been increased and this vary off | ||
83 | * would bring us below the new target. | ||
84 | */ | ||
85 | HvCall0(HvCallBaseSetVirtualDecr); | ||
86 | } | ||
87 | |||
88 | static inline void HvCall_yieldProcessor(unsigned typeOfYield, u64 yieldParm) | ||
89 | { | ||
90 | HvCall2(HvCallBaseYieldProcessor, typeOfYield, yieldParm); | ||
91 | } | ||
92 | |||
93 | static inline void HvCall_setEnabledInterrupts(u64 enabledInterrupts) | ||
94 | { | ||
95 | HvCall1(HvCallBaseSetEnabledInterrupts, enabledInterrupts); | ||
96 | } | ||
97 | |||
98 | static inline void HvCall_setLogBufferFormatAndCodepage(int format, | ||
99 | u32 codePage) | ||
100 | { | ||
101 | HvCall2(HvCallBaseSetLogBufferFormatAndCodePage, format, codePage); | ||
102 | } | ||
103 | |||
104 | extern void HvCall_writeLogBuffer(const void *buffer, u64 bufLen); | ||
105 | |||
106 | static inline void HvCall_sendIPI(struct paca_struct *targetPaca) | ||
107 | { | ||
108 | HvCall1(HvCallBaseSendIPI, targetPaca->paca_index); | ||
109 | } | ||
110 | |||
111 | #endif /* _ASM_POWERPC_ISERIES_HV_CALL_H */ | ||
diff --git a/arch/powerpc/include/asm/iseries/hv_call_event.h b/arch/powerpc/include/asm/iseries/hv_call_event.h deleted file mode 100644 index cc029d388e11..000000000000 --- a/arch/powerpc/include/asm/iseries/hv_call_event.h +++ /dev/null | |||
@@ -1,201 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001 Mike Corrigan IBM Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | * | ||
18 | * This file contains the "hypervisor call" interface which is used to | ||
19 | * drive the hypervisor from the OS. | ||
20 | */ | ||
21 | #ifndef _ASM_POWERPC_ISERIES_HV_CALL_EVENT_H | ||
22 | #define _ASM_POWERPC_ISERIES_HV_CALL_EVENT_H | ||
23 | |||
24 | #include <linux/types.h> | ||
25 | #include <linux/dma-mapping.h> | ||
26 | |||
27 | #include <asm/iseries/hv_call_sc.h> | ||
28 | #include <asm/iseries/hv_types.h> | ||
29 | #include <asm/abs_addr.h> | ||
30 | |||
31 | struct HvLpEvent; | ||
32 | |||
33 | typedef u8 HvLpEvent_Type; | ||
34 | typedef u8 HvLpEvent_AckInd; | ||
35 | typedef u8 HvLpEvent_AckType; | ||
36 | |||
37 | typedef u8 HvLpDma_Direction; | ||
38 | typedef u8 HvLpDma_AddressType; | ||
39 | |||
40 | typedef u64 HvLpEvent_Rc; | ||
41 | typedef u64 HvLpDma_Rc; | ||
42 | |||
43 | #define HvCallEventAckLpEvent HvCallEvent + 0 | ||
44 | #define HvCallEventCancelLpEvent HvCallEvent + 1 | ||
45 | #define HvCallEventCloseLpEventPath HvCallEvent + 2 | ||
46 | #define HvCallEventDmaBufList HvCallEvent + 3 | ||
47 | #define HvCallEventDmaSingle HvCallEvent + 4 | ||
48 | #define HvCallEventDmaToSp HvCallEvent + 5 | ||
49 | #define HvCallEventGetOverflowLpEvents HvCallEvent + 6 | ||
50 | #define HvCallEventGetSourceLpInstanceId HvCallEvent + 7 | ||
51 | #define HvCallEventGetTargetLpInstanceId HvCallEvent + 8 | ||
52 | #define HvCallEventOpenLpEventPath HvCallEvent + 9 | ||
53 | #define HvCallEventSetLpEventStack HvCallEvent + 10 | ||
54 | #define HvCallEventSignalLpEvent HvCallEvent + 11 | ||
55 | #define HvCallEventSignalLpEventParms HvCallEvent + 12 | ||
56 | #define HvCallEventSetInterLpQueueIndex HvCallEvent + 13 | ||
57 | #define HvCallEventSetLpEventQueueInterruptProc HvCallEvent + 14 | ||
58 | #define HvCallEventRouter15 HvCallEvent + 15 | ||
59 | |||
60 | static inline void HvCallEvent_getOverflowLpEvents(u8 queueIndex) | ||
61 | { | ||
62 | HvCall1(HvCallEventGetOverflowLpEvents, queueIndex); | ||
63 | } | ||
64 | |||
65 | static inline void HvCallEvent_setInterLpQueueIndex(u8 queueIndex) | ||
66 | { | ||
67 | HvCall1(HvCallEventSetInterLpQueueIndex, queueIndex); | ||
68 | } | ||
69 | |||
70 | static inline void HvCallEvent_setLpEventStack(u8 queueIndex, | ||
71 | char *eventStackAddr, u32 eventStackSize) | ||
72 | { | ||
73 | HvCall3(HvCallEventSetLpEventStack, queueIndex, | ||
74 | virt_to_abs(eventStackAddr), eventStackSize); | ||
75 | } | ||
76 | |||
77 | static inline void HvCallEvent_setLpEventQueueInterruptProc(u8 queueIndex, | ||
78 | u16 lpLogicalProcIndex) | ||
79 | { | ||
80 | HvCall2(HvCallEventSetLpEventQueueInterruptProc, queueIndex, | ||
81 | lpLogicalProcIndex); | ||
82 | } | ||
83 | |||
84 | static inline HvLpEvent_Rc HvCallEvent_signalLpEvent(struct HvLpEvent *event) | ||
85 | { | ||
86 | return HvCall1(HvCallEventSignalLpEvent, virt_to_abs(event)); | ||
87 | } | ||
88 | |||
89 | static inline HvLpEvent_Rc HvCallEvent_signalLpEventFast(HvLpIndex targetLp, | ||
90 | HvLpEvent_Type type, u16 subtype, HvLpEvent_AckInd ackInd, | ||
91 | HvLpEvent_AckType ackType, HvLpInstanceId sourceInstanceId, | ||
92 | HvLpInstanceId targetInstanceId, u64 correlationToken, | ||
93 | u64 eventData1, u64 eventData2, u64 eventData3, | ||
94 | u64 eventData4, u64 eventData5) | ||
95 | { | ||
96 | /* Pack the misc bits into a single Dword to pass to PLIC */ | ||
97 | union { | ||
98 | struct { | ||
99 | u8 ack_and_target; | ||
100 | u8 type; | ||
101 | u16 subtype; | ||
102 | HvLpInstanceId src_inst; | ||
103 | HvLpInstanceId target_inst; | ||
104 | } parms; | ||
105 | u64 dword; | ||
106 | } packed; | ||
107 | |||
108 | packed.parms.ack_and_target = (ackType << 7) | (ackInd << 6) | targetLp; | ||
109 | packed.parms.type = type; | ||
110 | packed.parms.subtype = subtype; | ||
111 | packed.parms.src_inst = sourceInstanceId; | ||
112 | packed.parms.target_inst = targetInstanceId; | ||
113 | |||
114 | return HvCall7(HvCallEventSignalLpEventParms, packed.dword, | ||
115 | correlationToken, eventData1, eventData2, | ||
116 | eventData3, eventData4, eventData5); | ||
117 | } | ||
118 | |||
119 | extern void *iseries_hv_alloc(size_t size, dma_addr_t *dma_handle, gfp_t flag); | ||
120 | extern void iseries_hv_free(size_t size, void *vaddr, dma_addr_t dma_handle); | ||
121 | extern dma_addr_t iseries_hv_map(void *vaddr, size_t size, | ||
122 | enum dma_data_direction direction); | ||
123 | extern void iseries_hv_unmap(dma_addr_t dma_handle, size_t size, | ||
124 | enum dma_data_direction direction); | ||
125 | |||
126 | static inline HvLpEvent_Rc HvCallEvent_ackLpEvent(struct HvLpEvent *event) | ||
127 | { | ||
128 | return HvCall1(HvCallEventAckLpEvent, virt_to_abs(event)); | ||
129 | } | ||
130 | |||
131 | static inline HvLpEvent_Rc HvCallEvent_cancelLpEvent(struct HvLpEvent *event) | ||
132 | { | ||
133 | return HvCall1(HvCallEventCancelLpEvent, virt_to_abs(event)); | ||
134 | } | ||
135 | |||
136 | static inline HvLpInstanceId HvCallEvent_getSourceLpInstanceId( | ||
137 | HvLpIndex targetLp, HvLpEvent_Type type) | ||
138 | { | ||
139 | return HvCall2(HvCallEventGetSourceLpInstanceId, targetLp, type); | ||
140 | } | ||
141 | |||
142 | static inline HvLpInstanceId HvCallEvent_getTargetLpInstanceId( | ||
143 | HvLpIndex targetLp, HvLpEvent_Type type) | ||
144 | { | ||
145 | return HvCall2(HvCallEventGetTargetLpInstanceId, targetLp, type); | ||
146 | } | ||
147 | |||
148 | static inline void HvCallEvent_openLpEventPath(HvLpIndex targetLp, | ||
149 | HvLpEvent_Type type) | ||
150 | { | ||
151 | HvCall2(HvCallEventOpenLpEventPath, targetLp, type); | ||
152 | } | ||
153 | |||
154 | static inline void HvCallEvent_closeLpEventPath(HvLpIndex targetLp, | ||
155 | HvLpEvent_Type type) | ||
156 | { | ||
157 | HvCall2(HvCallEventCloseLpEventPath, targetLp, type); | ||
158 | } | ||
159 | |||
160 | static inline HvLpDma_Rc HvCallEvent_dmaBufList(HvLpEvent_Type type, | ||
161 | HvLpIndex remoteLp, HvLpDma_Direction direction, | ||
162 | HvLpInstanceId localInstanceId, | ||
163 | HvLpInstanceId remoteInstanceId, | ||
164 | HvLpDma_AddressType localAddressType, | ||
165 | HvLpDma_AddressType remoteAddressType, | ||
166 | /* Do these need to be converted to absolute addresses? */ | ||
167 | u64 localBufList, u64 remoteBufList, u32 transferLength) | ||
168 | { | ||
169 | /* Pack the misc bits into a single Dword to pass to PLIC */ | ||
170 | union { | ||
171 | struct { | ||
172 | u8 flags; | ||
173 | HvLpIndex remote; | ||
174 | u8 type; | ||
175 | u8 reserved; | ||
176 | HvLpInstanceId local_inst; | ||
177 | HvLpInstanceId remote_inst; | ||
178 | } parms; | ||
179 | u64 dword; | ||
180 | } packed; | ||
181 | |||
182 | packed.parms.flags = (direction << 7) | | ||
183 | (localAddressType << 6) | (remoteAddressType << 5); | ||
184 | packed.parms.remote = remoteLp; | ||
185 | packed.parms.type = type; | ||
186 | packed.parms.reserved = 0; | ||
187 | packed.parms.local_inst = localInstanceId; | ||
188 | packed.parms.remote_inst = remoteInstanceId; | ||
189 | |||
190 | return HvCall4(HvCallEventDmaBufList, packed.dword, localBufList, | ||
191 | remoteBufList, transferLength); | ||
192 | } | ||
193 | |||
194 | static inline HvLpDma_Rc HvCallEvent_dmaToSp(void *local, u32 remote, | ||
195 | u32 length, HvLpDma_Direction dir) | ||
196 | { | ||
197 | return HvCall4(HvCallEventDmaToSp, virt_to_abs(local), remote, | ||
198 | length, dir); | ||
199 | } | ||
200 | |||
201 | #endif /* _ASM_POWERPC_ISERIES_HV_CALL_EVENT_H */ | ||
diff --git a/arch/powerpc/include/asm/iseries/hv_call_sc.h b/arch/powerpc/include/asm/iseries/hv_call_sc.h deleted file mode 100644 index f5d210959250..000000000000 --- a/arch/powerpc/include/asm/iseries/hv_call_sc.h +++ /dev/null | |||
@@ -1,50 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001 Mike Corrigan IBM Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | #ifndef _ASM_POWERPC_ISERIES_HV_CALL_SC_H | ||
19 | #define _ASM_POWERPC_ISERIES_HV_CALL_SC_H | ||
20 | |||
21 | #include <linux/types.h> | ||
22 | |||
23 | #define HvCallBase 0x8000000000000000ul | ||
24 | #define HvCallCc 0x8001000000000000ul | ||
25 | #define HvCallCfg 0x8002000000000000ul | ||
26 | #define HvCallEvent 0x8003000000000000ul | ||
27 | #define HvCallHpt 0x8004000000000000ul | ||
28 | #define HvCallPci 0x8005000000000000ul | ||
29 | #define HvCallSm 0x8007000000000000ul | ||
30 | #define HvCallXm 0x8009000000000000ul | ||
31 | |||
32 | extern u64 HvCall0(u64); | ||
33 | extern u64 HvCall1(u64, u64); | ||
34 | extern u64 HvCall2(u64, u64, u64); | ||
35 | extern u64 HvCall3(u64, u64, u64, u64); | ||
36 | extern u64 HvCall4(u64, u64, u64, u64, u64); | ||
37 | extern u64 HvCall5(u64, u64, u64, u64, u64, u64); | ||
38 | extern u64 HvCall6(u64, u64, u64, u64, u64, u64, u64); | ||
39 | extern u64 HvCall7(u64, u64, u64, u64, u64, u64, u64, u64); | ||
40 | |||
41 | extern u64 HvCall0Ret16(u64, void *); | ||
42 | extern u64 HvCall1Ret16(u64, void *, u64); | ||
43 | extern u64 HvCall2Ret16(u64, void *, u64, u64); | ||
44 | extern u64 HvCall3Ret16(u64, void *, u64, u64, u64); | ||
45 | extern u64 HvCall4Ret16(u64, void *, u64, u64, u64, u64); | ||
46 | extern u64 HvCall5Ret16(u64, void *, u64, u64, u64, u64, u64); | ||
47 | extern u64 HvCall6Ret16(u64, void *, u64, u64, u64, u64, u64, u64); | ||
48 | extern u64 HvCall7Ret16(u64, void *, u64, u64 ,u64 ,u64 ,u64 ,u64 ,u64); | ||
49 | |||
50 | #endif /* _ASM_POWERPC_ISERIES_HV_CALL_SC_H */ | ||
diff --git a/arch/powerpc/include/asm/iseries/hv_call_xm.h b/arch/powerpc/include/asm/iseries/hv_call_xm.h deleted file mode 100644 index 392ac3f54df0..000000000000 --- a/arch/powerpc/include/asm/iseries/hv_call_xm.h +++ /dev/null | |||
@@ -1,61 +0,0 @@ | |||
1 | /* | ||
2 | * This file contains the "hypervisor call" interface which is used to | ||
3 | * drive the hypervisor from SLIC. | ||
4 | */ | ||
5 | #ifndef _ASM_POWERPC_ISERIES_HV_CALL_XM_H | ||
6 | #define _ASM_POWERPC_ISERIES_HV_CALL_XM_H | ||
7 | |||
8 | #include <asm/iseries/hv_call_sc.h> | ||
9 | #include <asm/iseries/hv_types.h> | ||
10 | |||
11 | #define HvCallXmGetTceTableParms HvCallXm + 0 | ||
12 | #define HvCallXmTestBus HvCallXm + 1 | ||
13 | #define HvCallXmConnectBusUnit HvCallXm + 2 | ||
14 | #define HvCallXmLoadTod HvCallXm + 8 | ||
15 | #define HvCallXmTestBusUnit HvCallXm + 9 | ||
16 | #define HvCallXmSetTce HvCallXm + 11 | ||
17 | #define HvCallXmSetTces HvCallXm + 13 | ||
18 | |||
19 | static inline void HvCallXm_getTceTableParms(u64 cb) | ||
20 | { | ||
21 | HvCall1(HvCallXmGetTceTableParms, cb); | ||
22 | } | ||
23 | |||
24 | static inline u64 HvCallXm_setTce(u64 tceTableToken, u64 tceOffset, u64 tce) | ||
25 | { | ||
26 | return HvCall3(HvCallXmSetTce, tceTableToken, tceOffset, tce); | ||
27 | } | ||
28 | |||
29 | static inline u64 HvCallXm_setTces(u64 tceTableToken, u64 tceOffset, | ||
30 | u64 numTces, u64 tce1, u64 tce2, u64 tce3, u64 tce4) | ||
31 | { | ||
32 | return HvCall7(HvCallXmSetTces, tceTableToken, tceOffset, numTces, | ||
33 | tce1, tce2, tce3, tce4); | ||
34 | } | ||
35 | |||
36 | static inline u64 HvCallXm_testBus(u16 busNumber) | ||
37 | { | ||
38 | return HvCall1(HvCallXmTestBus, busNumber); | ||
39 | } | ||
40 | |||
41 | static inline u64 HvCallXm_testBusUnit(u16 busNumber, u8 subBusNumber, | ||
42 | u8 deviceId) | ||
43 | { | ||
44 | return HvCall2(HvCallXmTestBusUnit, busNumber, | ||
45 | (subBusNumber << 8) | deviceId); | ||
46 | } | ||
47 | |||
48 | static inline u64 HvCallXm_connectBusUnit(u16 busNumber, u8 subBusNumber, | ||
49 | u8 deviceId, u64 interruptToken) | ||
50 | { | ||
51 | return HvCall5(HvCallXmConnectBusUnit, busNumber, | ||
52 | (subBusNumber << 8) | deviceId, interruptToken, 0, | ||
53 | 0 /* HvLpConfig::mapDsaToQueueIndex(HvLpDSA(busNumber, xBoard, xCard)) */); | ||
54 | } | ||
55 | |||
56 | static inline u64 HvCallXm_loadTod(void) | ||
57 | { | ||
58 | return HvCall0(HvCallXmLoadTod); | ||
59 | } | ||
60 | |||
61 | #endif /* _ASM_POWERPC_ISERIES_HV_CALL_XM_H */ | ||
diff --git a/arch/powerpc/include/asm/iseries/hv_lp_config.h b/arch/powerpc/include/asm/iseries/hv_lp_config.h deleted file mode 100644 index a006fd1e4a2c..000000000000 --- a/arch/powerpc/include/asm/iseries/hv_lp_config.h +++ /dev/null | |||
@@ -1,128 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001 Mike Corrigan IBM Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | #ifndef _ASM_POWERPC_ISERIES_HV_LP_CONFIG_H | ||
19 | #define _ASM_POWERPC_ISERIES_HV_LP_CONFIG_H | ||
20 | |||
21 | /* | ||
22 | * This file contains the interface to the LPAR configuration data | ||
23 | * to determine which resources should be allocated to each partition. | ||
24 | */ | ||
25 | |||
26 | #include <asm/iseries/hv_call_sc.h> | ||
27 | #include <asm/iseries/hv_types.h> | ||
28 | |||
29 | enum { | ||
30 | HvCallCfg_Cur = 0, | ||
31 | HvCallCfg_Init = 1, | ||
32 | HvCallCfg_Max = 2, | ||
33 | HvCallCfg_Min = 3 | ||
34 | }; | ||
35 | |||
36 | #define HvCallCfgGetSystemPhysicalProcessors HvCallCfg + 6 | ||
37 | #define HvCallCfgGetPhysicalProcessors HvCallCfg + 7 | ||
38 | #define HvCallCfgGetMsChunks HvCallCfg + 9 | ||
39 | #define HvCallCfgGetSharedPoolIndex HvCallCfg + 20 | ||
40 | #define HvCallCfgGetSharedProcUnits HvCallCfg + 21 | ||
41 | #define HvCallCfgGetNumProcsInSharedPool HvCallCfg + 22 | ||
42 | #define HvCallCfgGetVirtualLanIndexMap HvCallCfg + 30 | ||
43 | #define HvCallCfgGetHostingLpIndex HvCallCfg + 32 | ||
44 | |||
45 | extern HvLpIndex HvLpConfig_getLpIndex_outline(void); | ||
46 | extern HvLpIndex HvLpConfig_getLpIndex(void); | ||
47 | extern HvLpIndex HvLpConfig_getPrimaryLpIndex(void); | ||
48 | |||
49 | static inline u64 HvLpConfig_getMsChunks(void) | ||
50 | { | ||
51 | return HvCall2(HvCallCfgGetMsChunks, HvLpConfig_getLpIndex(), | ||
52 | HvCallCfg_Cur); | ||
53 | } | ||
54 | |||
55 | static inline u64 HvLpConfig_getSystemPhysicalProcessors(void) | ||
56 | { | ||
57 | return HvCall0(HvCallCfgGetSystemPhysicalProcessors); | ||
58 | } | ||
59 | |||
60 | static inline u64 HvLpConfig_getNumProcsInSharedPool(HvLpSharedPoolIndex sPI) | ||
61 | { | ||
62 | return (u16)HvCall1(HvCallCfgGetNumProcsInSharedPool, sPI); | ||
63 | } | ||
64 | |||
65 | static inline u64 HvLpConfig_getPhysicalProcessors(void) | ||
66 | { | ||
67 | return HvCall2(HvCallCfgGetPhysicalProcessors, HvLpConfig_getLpIndex(), | ||
68 | HvCallCfg_Cur); | ||
69 | } | ||
70 | |||
71 | static inline HvLpSharedPoolIndex HvLpConfig_getSharedPoolIndex(void) | ||
72 | { | ||
73 | return HvCall1(HvCallCfgGetSharedPoolIndex, HvLpConfig_getLpIndex()); | ||
74 | } | ||
75 | |||
76 | static inline u64 HvLpConfig_getSharedProcUnits(void) | ||
77 | { | ||
78 | return HvCall2(HvCallCfgGetSharedProcUnits, HvLpConfig_getLpIndex(), | ||
79 | HvCallCfg_Cur); | ||
80 | } | ||
81 | |||
82 | static inline u64 HvLpConfig_getMaxSharedProcUnits(void) | ||
83 | { | ||
84 | return HvCall2(HvCallCfgGetSharedProcUnits, HvLpConfig_getLpIndex(), | ||
85 | HvCallCfg_Max); | ||
86 | } | ||
87 | |||
88 | static inline u64 HvLpConfig_getMaxPhysicalProcessors(void) | ||
89 | { | ||
90 | return HvCall2(HvCallCfgGetPhysicalProcessors, HvLpConfig_getLpIndex(), | ||
91 | HvCallCfg_Max); | ||
92 | } | ||
93 | |||
94 | static inline HvLpVirtualLanIndexMap HvLpConfig_getVirtualLanIndexMapForLp( | ||
95 | HvLpIndex lp) | ||
96 | { | ||
97 | /* | ||
98 | * This is a new function in V5R1 so calls to this on older | ||
99 | * hypervisors will return -1 | ||
100 | */ | ||
101 | u64 retVal = HvCall1(HvCallCfgGetVirtualLanIndexMap, lp); | ||
102 | if (retVal == -1) | ||
103 | retVal = 0; | ||
104 | return retVal; | ||
105 | } | ||
106 | |||
107 | static inline HvLpVirtualLanIndexMap HvLpConfig_getVirtualLanIndexMap(void) | ||
108 | { | ||
109 | return HvLpConfig_getVirtualLanIndexMapForLp( | ||
110 | HvLpConfig_getLpIndex_outline()); | ||
111 | } | ||
112 | |||
113 | static inline int HvLpConfig_doLpsCommunicateOnVirtualLan(HvLpIndex lp1, | ||
114 | HvLpIndex lp2) | ||
115 | { | ||
116 | HvLpVirtualLanIndexMap virtualLanIndexMap1 = | ||
117 | HvLpConfig_getVirtualLanIndexMapForLp(lp1); | ||
118 | HvLpVirtualLanIndexMap virtualLanIndexMap2 = | ||
119 | HvLpConfig_getVirtualLanIndexMapForLp(lp2); | ||
120 | return ((virtualLanIndexMap1 & virtualLanIndexMap2) != 0); | ||
121 | } | ||
122 | |||
123 | static inline HvLpIndex HvLpConfig_getHostingLpIndex(HvLpIndex lp) | ||
124 | { | ||
125 | return HvCall1(HvCallCfgGetHostingLpIndex, lp); | ||
126 | } | ||
127 | |||
128 | #endif /* _ASM_POWERPC_ISERIES_HV_LP_CONFIG_H */ | ||
diff --git a/arch/powerpc/include/asm/iseries/hv_lp_event.h b/arch/powerpc/include/asm/iseries/hv_lp_event.h deleted file mode 100644 index 8f5da7d77202..000000000000 --- a/arch/powerpc/include/asm/iseries/hv_lp_event.h +++ /dev/null | |||
@@ -1,162 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001 Mike Corrigan IBM Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | |||
19 | /* This file contains the class for HV events in the system. */ | ||
20 | |||
21 | #ifndef _ASM_POWERPC_ISERIES_HV_LP_EVENT_H | ||
22 | #define _ASM_POWERPC_ISERIES_HV_LP_EVENT_H | ||
23 | |||
24 | #include <asm/types.h> | ||
25 | #include <asm/ptrace.h> | ||
26 | #include <asm/iseries/hv_types.h> | ||
27 | #include <asm/iseries/hv_call_event.h> | ||
28 | |||
29 | /* | ||
30 | * HvLpEvent is the structure for Lp Event messages passed between | ||
31 | * partitions through PLIC. | ||
32 | */ | ||
33 | |||
34 | struct HvLpEvent { | ||
35 | u8 flags; /* Event flags x00-x00 */ | ||
36 | u8 xType; /* Type of message x01-x01 */ | ||
37 | u16 xSubtype; /* Subtype for event x02-x03 */ | ||
38 | u8 xSourceLp; /* Source LP x04-x04 */ | ||
39 | u8 xTargetLp; /* Target LP x05-x05 */ | ||
40 | u8 xSizeMinus1; /* Size of Derived class - 1 x06-x06 */ | ||
41 | u8 xRc; /* RC for Ack flows x07-x07 */ | ||
42 | u16 xSourceInstanceId; /* Source sides instance id x08-x09 */ | ||
43 | u16 xTargetInstanceId; /* Target sides instance id x0A-x0B */ | ||
44 | union { | ||
45 | u32 xSubtypeData; /* Data usable by the subtype x0C-x0F */ | ||
46 | u16 xSubtypeDataShort[2]; /* Data as 2 shorts */ | ||
47 | u8 xSubtypeDataChar[4]; /* Data as 4 chars */ | ||
48 | } x; | ||
49 | |||
50 | u64 xCorrelationToken; /* Unique value for source/type x10-x17 */ | ||
51 | }; | ||
52 | |||
53 | typedef void (*LpEventHandler)(struct HvLpEvent *); | ||
54 | |||
55 | /* Register a handler for an event type - returns 0 on success */ | ||
56 | extern int HvLpEvent_registerHandler(HvLpEvent_Type eventType, | ||
57 | LpEventHandler hdlr); | ||
58 | |||
59 | /* | ||
60 | * Unregister a handler for an event type | ||
61 | * | ||
62 | * This call will sleep until the handler being removed is guaranteed to | ||
63 | * be no longer executing on any CPU. Do not call with locks held. | ||
64 | * | ||
65 | * returns 0 on success | ||
66 | * Unregister will fail if there are any paths open for the type | ||
67 | */ | ||
68 | extern int HvLpEvent_unregisterHandler(HvLpEvent_Type eventType); | ||
69 | |||
70 | /* | ||
71 | * Open an Lp Event Path for an event type | ||
72 | * returns 0 on success | ||
73 | * openPath will fail if there is no handler registered for the event type. | ||
74 | * The lpIndex specified is the partition index for the target partition | ||
75 | * (for VirtualIo, VirtualLan and SessionMgr) other types specify zero) | ||
76 | */ | ||
77 | extern int HvLpEvent_openPath(HvLpEvent_Type eventType, HvLpIndex lpIndex); | ||
78 | |||
79 | /* | ||
80 | * Close an Lp Event Path for a type and partition | ||
81 | * returns 0 on success | ||
82 | */ | ||
83 | extern int HvLpEvent_closePath(HvLpEvent_Type eventType, HvLpIndex lpIndex); | ||
84 | |||
85 | #define HvLpEvent_Type_Hypervisor 0 | ||
86 | #define HvLpEvent_Type_MachineFac 1 | ||
87 | #define HvLpEvent_Type_SessionMgr 2 | ||
88 | #define HvLpEvent_Type_SpdIo 3 | ||
89 | #define HvLpEvent_Type_VirtualBus 4 | ||
90 | #define HvLpEvent_Type_PciIo 5 | ||
91 | #define HvLpEvent_Type_RioIo 6 | ||
92 | #define HvLpEvent_Type_VirtualLan 7 | ||
93 | #define HvLpEvent_Type_VirtualIo 8 | ||
94 | #define HvLpEvent_Type_NumTypes 9 | ||
95 | |||
96 | #define HvLpEvent_Rc_Good 0 | ||
97 | #define HvLpEvent_Rc_BufferNotAvailable 1 | ||
98 | #define HvLpEvent_Rc_Cancelled 2 | ||
99 | #define HvLpEvent_Rc_GenericError 3 | ||
100 | #define HvLpEvent_Rc_InvalidAddress 4 | ||
101 | #define HvLpEvent_Rc_InvalidPartition 5 | ||
102 | #define HvLpEvent_Rc_InvalidSize 6 | ||
103 | #define HvLpEvent_Rc_InvalidSubtype 7 | ||
104 | #define HvLpEvent_Rc_InvalidSubtypeData 8 | ||
105 | #define HvLpEvent_Rc_InvalidType 9 | ||
106 | #define HvLpEvent_Rc_PartitionDead 10 | ||
107 | #define HvLpEvent_Rc_PathClosed 11 | ||
108 | #define HvLpEvent_Rc_SubtypeError 12 | ||
109 | |||
110 | #define HvLpEvent_Function_Ack 0 | ||
111 | #define HvLpEvent_Function_Int 1 | ||
112 | |||
113 | #define HvLpEvent_AckInd_NoAck 0 | ||
114 | #define HvLpEvent_AckInd_DoAck 1 | ||
115 | |||
116 | #define HvLpEvent_AckType_ImmediateAck 0 | ||
117 | #define HvLpEvent_AckType_DeferredAck 1 | ||
118 | |||
119 | #define HV_LP_EVENT_INT 0x01 | ||
120 | #define HV_LP_EVENT_DO_ACK 0x02 | ||
121 | #define HV_LP_EVENT_DEFERRED_ACK 0x04 | ||
122 | #define HV_LP_EVENT_VALID 0x80 | ||
123 | |||
124 | #define HvLpDma_Direction_LocalToRemote 0 | ||
125 | #define HvLpDma_Direction_RemoteToLocal 1 | ||
126 | |||
127 | #define HvLpDma_AddressType_TceIndex 0 | ||
128 | #define HvLpDma_AddressType_RealAddress 1 | ||
129 | |||
130 | #define HvLpDma_Rc_Good 0 | ||
131 | #define HvLpDma_Rc_Error 1 | ||
132 | #define HvLpDma_Rc_PartitionDead 2 | ||
133 | #define HvLpDma_Rc_PathClosed 3 | ||
134 | #define HvLpDma_Rc_InvalidAddress 4 | ||
135 | #define HvLpDma_Rc_InvalidLength 5 | ||
136 | |||
137 | static inline int hvlpevent_is_valid(struct HvLpEvent *h) | ||
138 | { | ||
139 | return h->flags & HV_LP_EVENT_VALID; | ||
140 | } | ||
141 | |||
142 | static inline void hvlpevent_invalidate(struct HvLpEvent *h) | ||
143 | { | ||
144 | h->flags &= ~ HV_LP_EVENT_VALID; | ||
145 | } | ||
146 | |||
147 | static inline int hvlpevent_is_int(struct HvLpEvent *h) | ||
148 | { | ||
149 | return h->flags & HV_LP_EVENT_INT; | ||
150 | } | ||
151 | |||
152 | static inline int hvlpevent_is_ack(struct HvLpEvent *h) | ||
153 | { | ||
154 | return !hvlpevent_is_int(h); | ||
155 | } | ||
156 | |||
157 | static inline int hvlpevent_need_ack(struct HvLpEvent *h) | ||
158 | { | ||
159 | return h->flags & HV_LP_EVENT_DO_ACK; | ||
160 | } | ||
161 | |||
162 | #endif /* _ASM_POWERPC_ISERIES_HV_LP_EVENT_H */ | ||
diff --git a/arch/powerpc/include/asm/iseries/hv_types.h b/arch/powerpc/include/asm/iseries/hv_types.h deleted file mode 100644 index c3e6d2a1d1c3..000000000000 --- a/arch/powerpc/include/asm/iseries/hv_types.h +++ /dev/null | |||
@@ -1,112 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001 Mike Corrigan IBM Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | #ifndef _ASM_POWERPC_ISERIES_HV_TYPES_H | ||
19 | #define _ASM_POWERPC_ISERIES_HV_TYPES_H | ||
20 | |||
21 | /* | ||
22 | * General typedefs for the hypervisor. | ||
23 | */ | ||
24 | |||
25 | #include <asm/types.h> | ||
26 | |||
27 | typedef u8 HvLpIndex; | ||
28 | typedef u16 HvLpInstanceId; | ||
29 | typedef u64 HvLpTOD; | ||
30 | typedef u64 HvLpSystemSerialNum; | ||
31 | typedef u8 HvLpDeviceSerialNum[12]; | ||
32 | typedef u16 HvLpSanHwSet; | ||
33 | typedef u16 HvLpBus; | ||
34 | typedef u16 HvLpBoard; | ||
35 | typedef u16 HvLpCard; | ||
36 | typedef u8 HvLpDeviceType[4]; | ||
37 | typedef u8 HvLpDeviceModel[3]; | ||
38 | typedef u64 HvIoToken; | ||
39 | typedef u8 HvLpName[8]; | ||
40 | typedef u32 HvIoId; | ||
41 | typedef u64 HvRealMemoryIndex; | ||
42 | typedef u32 HvLpIndexMap; /* Must hold HVMAXARCHITECTEDLPS bits!!! */ | ||
43 | typedef u16 HvLpVrmIndex; | ||
44 | typedef u32 HvXmGenerationId; | ||
45 | typedef u8 HvLpBusPool; | ||
46 | typedef u8 HvLpSharedPoolIndex; | ||
47 | typedef u16 HvLpSharedProcUnitsX100; | ||
48 | typedef u8 HvLpVirtualLanIndex; | ||
49 | typedef u16 HvLpVirtualLanIndexMap; /* Must hold HVMAXARCHITECTEDVIRTUALLANS bits!!! */ | ||
50 | typedef u16 HvBusNumber; /* Hypervisor Bus Number */ | ||
51 | typedef u8 HvSubBusNumber; /* Hypervisor SubBus Number */ | ||
52 | typedef u8 HvAgentId; /* Hypervisor DevFn */ | ||
53 | |||
54 | |||
55 | #define HVMAXARCHITECTEDLPS 32 | ||
56 | #define HVMAXARCHITECTEDVIRTUALLANS 16 | ||
57 | #define HVMAXARCHITECTEDVIRTUALDISKS 32 | ||
58 | #define HVMAXARCHITECTEDVIRTUALCDROMS 8 | ||
59 | #define HVMAXARCHITECTEDVIRTUALTAPES 8 | ||
60 | #define HVCHUNKSIZE (256 * 1024) | ||
61 | #define HVPAGESIZE (4 * 1024) | ||
62 | #define HVLPMINMEGSPRIMARY 256 | ||
63 | #define HVLPMINMEGSSECONDARY 64 | ||
64 | #define HVCHUNKSPERMEG 4 | ||
65 | #define HVPAGESPERMEG 256 | ||
66 | #define HVPAGESPERCHUNK 64 | ||
67 | |||
68 | #define HvLpIndexInvalid ((HvLpIndex)0xff) | ||
69 | |||
70 | /* | ||
71 | * Enums for the sub-components under PLIC | ||
72 | * Used in HvCall and HvPrimaryCall | ||
73 | */ | ||
74 | enum { | ||
75 | HvCallCompId = 0, | ||
76 | HvCallCpuCtlsCompId = 1, | ||
77 | HvCallCfgCompId = 2, | ||
78 | HvCallEventCompId = 3, | ||
79 | HvCallHptCompId = 4, | ||
80 | HvCallPciCompId = 5, | ||
81 | HvCallSlmCompId = 6, | ||
82 | HvCallSmCompId = 7, | ||
83 | HvCallSpdCompId = 8, | ||
84 | HvCallXmCompId = 9, | ||
85 | HvCallRioCompId = 10, | ||
86 | HvCallRsvd3CompId = 11, | ||
87 | HvCallRsvd2CompId = 12, | ||
88 | HvCallRsvd1CompId = 13, | ||
89 | HvCallMaxCompId = 14, | ||
90 | HvPrimaryCallCompId = 0, | ||
91 | HvPrimaryCallCfgCompId = 1, | ||
92 | HvPrimaryCallPciCompId = 2, | ||
93 | HvPrimaryCallSmCompId = 3, | ||
94 | HvPrimaryCallSpdCompId = 4, | ||
95 | HvPrimaryCallXmCompId = 5, | ||
96 | HvPrimaryCallRioCompId = 6, | ||
97 | HvPrimaryCallRsvd7CompId = 7, | ||
98 | HvPrimaryCallRsvd6CompId = 8, | ||
99 | HvPrimaryCallRsvd5CompId = 9, | ||
100 | HvPrimaryCallRsvd4CompId = 10, | ||
101 | HvPrimaryCallRsvd3CompId = 11, | ||
102 | HvPrimaryCallRsvd2CompId = 12, | ||
103 | HvPrimaryCallRsvd1CompId = 13, | ||
104 | HvPrimaryCallMaxCompId = HvCallMaxCompId | ||
105 | }; | ||
106 | |||
107 | struct HvLpBufferList { | ||
108 | u64 addr; | ||
109 | u64 len; | ||
110 | }; | ||
111 | |||
112 | #endif /* _ASM_POWERPC_ISERIES_HV_TYPES_H */ | ||
diff --git a/arch/powerpc/include/asm/iseries/iommu.h b/arch/powerpc/include/asm/iseries/iommu.h deleted file mode 100644 index 1b9692c60899..000000000000 --- a/arch/powerpc/include/asm/iseries/iommu.h +++ /dev/null | |||
@@ -1,37 +0,0 @@ | |||
1 | #ifndef _ASM_POWERPC_ISERIES_IOMMU_H | ||
2 | #define _ASM_POWERPC_ISERIES_IOMMU_H | ||
3 | |||
4 | /* | ||
5 | * Copyright (C) 2005 Stephen Rothwell, IBM Corporation | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
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: | ||
19 | * Free Software Foundation, Inc., | ||
20 | * 59 Temple Place, Suite 330, | ||
21 | * Boston, MA 02111-1307 USA | ||
22 | */ | ||
23 | |||
24 | struct pci_dev; | ||
25 | struct vio_dev; | ||
26 | struct device_node; | ||
27 | struct iommu_table; | ||
28 | |||
29 | /* Get table parameters from HV */ | ||
30 | extern void iommu_table_getparms_iSeries(unsigned long busno, | ||
31 | unsigned char slotno, unsigned char virtbus, | ||
32 | struct iommu_table *tbl); | ||
33 | |||
34 | extern struct iommu_table *vio_build_iommu_table_iseries(struct vio_dev *dev); | ||
35 | extern void iommu_vio_init(void); | ||
36 | |||
37 | #endif /* _ASM_POWERPC_ISERIES_IOMMU_H */ | ||
diff --git a/arch/powerpc/include/asm/iseries/it_lp_queue.h b/arch/powerpc/include/asm/iseries/it_lp_queue.h deleted file mode 100644 index 428278838821..000000000000 --- a/arch/powerpc/include/asm/iseries/it_lp_queue.h +++ /dev/null | |||
@@ -1,78 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001 Mike Corrigan IBM Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | #ifndef _ASM_POWERPC_ISERIES_IT_LP_QUEUE_H | ||
19 | #define _ASM_POWERPC_ISERIES_IT_LP_QUEUE_H | ||
20 | |||
21 | /* | ||
22 | * This control block defines the simple LP queue structure that is | ||
23 | * shared between the hypervisor (PLIC) and the OS in order to send | ||
24 | * events to an LP. | ||
25 | */ | ||
26 | |||
27 | #include <asm/types.h> | ||
28 | #include <asm/ptrace.h> | ||
29 | |||
30 | #define IT_LP_MAX_QUEUES 8 | ||
31 | |||
32 | #define IT_LP_NOT_USED 0 /* Queue will not be used by PLIC */ | ||
33 | #define IT_LP_DEDICATED_IO 1 /* Queue dedicated to IO processor specified */ | ||
34 | #define IT_LP_DEDICATED_LP 2 /* Queue dedicated to LP specified */ | ||
35 | #define IT_LP_SHARED 3 /* Queue shared for both IO and LP */ | ||
36 | |||
37 | #define IT_LP_EVENT_STACK_SIZE 4096 | ||
38 | #define IT_LP_EVENT_MAX_SIZE 256 | ||
39 | #define IT_LP_EVENT_ALIGN 64 | ||
40 | |||
41 | struct hvlpevent_queue { | ||
42 | /* | ||
43 | * The hq_current_event is the pointer to the next event stack entry | ||
44 | * that will become valid. The OS must peek at this entry to determine | ||
45 | * if it is valid. PLIC will set the valid indicator as the very last | ||
46 | * store into that entry. | ||
47 | * | ||
48 | * When the OS has completed processing of the event then it will mark | ||
49 | * the event as invalid so that PLIC knows it can store into that event | ||
50 | * location again. | ||
51 | * | ||
52 | * If the event stack fills and there are overflow events, then PLIC | ||
53 | * will set the hq_overflow_pending flag in which case the OS will | ||
54 | * have to fetch the additional LP events once they have drained the | ||
55 | * event stack. | ||
56 | * | ||
57 | * The first 16-bytes are known by both the OS and PLIC. The remainder | ||
58 | * of the cache line is for use by the OS. | ||
59 | */ | ||
60 | u8 hq_overflow_pending; /* 0x00 Overflow events are pending */ | ||
61 | u8 hq_status; /* 0x01 DedicatedIo or DedicatedLp or NotUsed */ | ||
62 | u16 hq_proc_index; /* 0x02 Logical Proc Index for correlation */ | ||
63 | u8 hq_reserved1[12]; /* 0x04 */ | ||
64 | char *hq_current_event; /* 0x10 */ | ||
65 | char *hq_last_event; /* 0x18 */ | ||
66 | char *hq_event_stack; /* 0x20 */ | ||
67 | u8 hq_index; /* 0x28 unique sequential index. */ | ||
68 | u8 hq_reserved2[3]; /* 0x29-2b */ | ||
69 | spinlock_t hq_lock; | ||
70 | }; | ||
71 | |||
72 | extern struct hvlpevent_queue hvlpevent_queue; | ||
73 | |||
74 | extern int hvlpevent_is_pending(void); | ||
75 | extern void process_hvlpevents(void); | ||
76 | extern void setup_hvlpevent_queue(void); | ||
77 | |||
78 | #endif /* _ASM_POWERPC_ISERIES_IT_LP_QUEUE_H */ | ||
diff --git a/arch/powerpc/include/asm/iseries/lpar_map.h b/arch/powerpc/include/asm/iseries/lpar_map.h deleted file mode 100644 index 5e9f3e128ee2..000000000000 --- a/arch/powerpc/include/asm/iseries/lpar_map.h +++ /dev/null | |||
@@ -1,85 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001 Mike Corrigan IBM Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | #ifndef _ASM_POWERPC_ISERIES_LPAR_MAP_H | ||
19 | #define _ASM_POWERPC_ISERIES_LPAR_MAP_H | ||
20 | |||
21 | #ifndef __ASSEMBLY__ | ||
22 | |||
23 | #include <asm/types.h> | ||
24 | |||
25 | #endif | ||
26 | |||
27 | /* | ||
28 | * The iSeries hypervisor will set up mapping for one or more | ||
29 | * ESID/VSID pairs (in SLB/segment registers) and will set up | ||
30 | * mappings of one or more ranges of pages to VAs. | ||
31 | * We will have the hypervisor set up the ESID->VSID mapping | ||
32 | * for the four kernel segments (C-F). With shared processors, | ||
33 | * the hypervisor will clear all segment registers and reload | ||
34 | * these four whenever the processor is switched from one | ||
35 | * partition to another. | ||
36 | */ | ||
37 | |||
38 | /* The Vsid and Esid identified below will be used by the hypervisor | ||
39 | * to set up a memory mapping for part of the load area before giving | ||
40 | * control to the Linux kernel. The load area is 64 MB, but this must | ||
41 | * not attempt to map the whole load area. The Hashed Page Table may | ||
42 | * need to be located within the load area (if the total partition size | ||
43 | * is 64 MB), but cannot be mapped. Typically, this should specify | ||
44 | * to map half (32 MB) of the load area. | ||
45 | * | ||
46 | * The hypervisor will set up page table entries for the number of | ||
47 | * pages specified. | ||
48 | * | ||
49 | * In 32-bit mode, the hypervisor will load all four of the | ||
50 | * segment registers (identified by the low-order four bits of the | ||
51 | * Esid field. In 64-bit mode, the hypervisor will load one SLB | ||
52 | * entry to map the Esid to the Vsid. | ||
53 | */ | ||
54 | |||
55 | #define HvEsidsToMap 2 | ||
56 | #define HvRangesToMap 1 | ||
57 | |||
58 | /* Hypervisor initially maps 32MB of the load area */ | ||
59 | #define HvPagesToMap 8192 | ||
60 | |||
61 | #ifndef __ASSEMBLY__ | ||
62 | struct LparMap { | ||
63 | u64 xNumberEsids; // Number of ESID/VSID pairs | ||
64 | u64 xNumberRanges; // Number of VA ranges to map | ||
65 | u64 xSegmentTableOffs; // Page number within load area of seg table | ||
66 | u64 xRsvd[5]; | ||
67 | struct { | ||
68 | u64 xKernelEsid; // Esid used to map kernel load | ||
69 | u64 xKernelVsid; // Vsid used to map kernel load | ||
70 | } xEsids[HvEsidsToMap]; | ||
71 | struct { | ||
72 | u64 xPages; // Number of pages to be mapped | ||
73 | u64 xOffset; // Offset from start of load area | ||
74 | u64 xVPN; // Virtual Page Number | ||
75 | } xRanges[HvRangesToMap]; | ||
76 | }; | ||
77 | |||
78 | extern const struct LparMap xLparMap; | ||
79 | |||
80 | #endif /* __ASSEMBLY__ */ | ||
81 | |||
82 | /* the fixed address where the LparMap exists */ | ||
83 | #define LPARMAP_PHYS 0x7000 | ||
84 | |||
85 | #endif /* _ASM_POWERPC_ISERIES_LPAR_MAP_H */ | ||
diff --git a/arch/powerpc/include/asm/iseries/mf.h b/arch/powerpc/include/asm/iseries/mf.h deleted file mode 100644 index eb851a9c9e5c..000000000000 --- a/arch/powerpc/include/asm/iseries/mf.h +++ /dev/null | |||
@@ -1,51 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001 Troy D. Armstrong IBM Corporation | ||
3 | * Copyright (C) 2004 Stephen Rothwell IBM Corporation | ||
4 | * | ||
5 | * This modules exists as an interface between a Linux secondary partition | ||
6 | * running on an iSeries and the primary partition's Virtual Service | ||
7 | * Processor (VSP) object. The VSP has final authority over powering on/off | ||
8 | * all partitions in the iSeries. It also provides miscellaneous low-level | ||
9 | * machine facility type operations. | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | * GNU General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with this program; if not, write to the Free Software | ||
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
24 | */ | ||
25 | #ifndef _ASM_POWERPC_ISERIES_MF_H | ||
26 | #define _ASM_POWERPC_ISERIES_MF_H | ||
27 | |||
28 | #include <linux/types.h> | ||
29 | |||
30 | #include <asm/iseries/hv_types.h> | ||
31 | #include <asm/iseries/hv_call_event.h> | ||
32 | |||
33 | struct rtc_time; | ||
34 | |||
35 | typedef void (*MFCompleteHandler)(void *clientToken, int returnCode); | ||
36 | |||
37 | extern void mf_allocate_lp_events(HvLpIndex targetLp, HvLpEvent_Type type, | ||
38 | unsigned size, unsigned amount, MFCompleteHandler hdlr, | ||
39 | void *userToken); | ||
40 | extern void mf_deallocate_lp_events(HvLpIndex targetLp, HvLpEvent_Type type, | ||
41 | unsigned count, MFCompleteHandler hdlr, void *userToken); | ||
42 | |||
43 | extern void mf_power_off(void); | ||
44 | extern void mf_reboot(char *cmd); | ||
45 | |||
46 | extern void mf_display_src(u32 word); | ||
47 | extern void mf_display_progress(u16 value); | ||
48 | |||
49 | extern void mf_init(void); | ||
50 | |||
51 | #endif /* _ASM_POWERPC_ISERIES_MF_H */ | ||
diff --git a/arch/powerpc/include/asm/iseries/vio.h b/arch/powerpc/include/asm/iseries/vio.h deleted file mode 100644 index f9ac0d00b951..000000000000 --- a/arch/powerpc/include/asm/iseries/vio.h +++ /dev/null | |||
@@ -1,265 +0,0 @@ | |||
1 | /* -*- linux-c -*- | ||
2 | * | ||
3 | * iSeries Virtual I/O Message Path header | ||
4 | * | ||
5 | * Authors: Dave Boutcher <boutcher@us.ibm.com> | ||
6 | * Ryan Arnold <ryanarn@us.ibm.com> | ||
7 | * Colin Devilbiss <devilbis@us.ibm.com> | ||
8 | * | ||
9 | * (C) Copyright 2000 IBM Corporation | ||
10 | * | ||
11 | * This header file is used by the iSeries virtual I/O device | ||
12 | * drivers. It defines the interfaces to the common functions | ||
13 | * (implemented in drivers/char/viopath.h) as well as defining | ||
14 | * common functions and structures. Currently (at the time I | ||
15 | * wrote this comment) the iSeries virtual I/O device drivers | ||
16 | * that use this are | ||
17 | * drivers/block/viodasd.c | ||
18 | * drivers/char/viocons.c | ||
19 | * drivers/char/viotape.c | ||
20 | * drivers/cdrom/viocd.c | ||
21 | * | ||
22 | * The iSeries virtual ethernet support (veth.c) uses a whole | ||
23 | * different set of functions. | ||
24 | * | ||
25 | * This program is free software; you can redistribute it and/or | ||
26 | * modify it under the terms of the GNU General Public License as | ||
27 | * published by the Free Software Foundation; either version 2 of the | ||
28 | * License, or (at your option) anyu later version. | ||
29 | * | ||
30 | * This program is distributed in the hope that it will be useful, but | ||
31 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
32 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
33 | * General Public License for more details. | ||
34 | * | ||
35 | * You should have received a copy of the GNU General Public License | ||
36 | * along with this program; if not, write to the Free Software Foundation, | ||
37 | * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
38 | * | ||
39 | */ | ||
40 | #ifndef _ASM_POWERPC_ISERIES_VIO_H | ||
41 | #define _ASM_POWERPC_ISERIES_VIO_H | ||
42 | |||
43 | #include <asm/iseries/hv_types.h> | ||
44 | #include <asm/iseries/hv_lp_event.h> | ||
45 | |||
46 | /* | ||
47 | * iSeries virtual I/O events use the subtype field in | ||
48 | * HvLpEvent to figure out what kind of vio event is coming | ||
49 | * in. We use a table to route these, and this defines | ||
50 | * the maximum number of distinct subtypes | ||
51 | */ | ||
52 | #define VIO_MAX_SUBTYPES 8 | ||
53 | |||
54 | #define VIOMAXBLOCKDMA 12 | ||
55 | |||
56 | struct open_data { | ||
57 | u64 disk_size; | ||
58 | u16 max_disk; | ||
59 | u16 cylinders; | ||
60 | u16 tracks; | ||
61 | u16 sectors; | ||
62 | u16 bytes_per_sector; | ||
63 | }; | ||
64 | |||
65 | struct rw_data { | ||
66 | u64 offset; | ||
67 | struct { | ||
68 | u32 token; | ||
69 | u32 reserved; | ||
70 | u64 len; | ||
71 | } dma_info[VIOMAXBLOCKDMA]; | ||
72 | }; | ||
73 | |||
74 | struct vioblocklpevent { | ||
75 | struct HvLpEvent event; | ||
76 | u32 reserved; | ||
77 | u16 version; | ||
78 | u16 sub_result; | ||
79 | u16 disk; | ||
80 | u16 flags; | ||
81 | union { | ||
82 | struct open_data open_data; | ||
83 | struct rw_data rw_data; | ||
84 | u64 changed; | ||
85 | } u; | ||
86 | }; | ||
87 | |||
88 | #define vioblockflags_ro 0x0001 | ||
89 | |||
90 | enum vioblocksubtype { | ||
91 | vioblockopen = 0x0001, | ||
92 | vioblockclose = 0x0002, | ||
93 | vioblockread = 0x0003, | ||
94 | vioblockwrite = 0x0004, | ||
95 | vioblockflush = 0x0005, | ||
96 | vioblockcheck = 0x0007 | ||
97 | }; | ||
98 | |||
99 | struct viocdlpevent { | ||
100 | struct HvLpEvent event; | ||
101 | u32 reserved; | ||
102 | u16 version; | ||
103 | u16 sub_result; | ||
104 | u16 disk; | ||
105 | u16 flags; | ||
106 | u32 token; | ||
107 | u64 offset; /* On open, max number of disks */ | ||
108 | u64 len; /* On open, size of the disk */ | ||
109 | u32 block_size; /* Only set on open */ | ||
110 | u32 media_size; /* Only set on open */ | ||
111 | }; | ||
112 | |||
113 | enum viocdsubtype { | ||
114 | viocdopen = 0x0001, | ||
115 | viocdclose = 0x0002, | ||
116 | viocdread = 0x0003, | ||
117 | viocdwrite = 0x0004, | ||
118 | viocdlockdoor = 0x0005, | ||
119 | viocdgetinfo = 0x0006, | ||
120 | viocdcheck = 0x0007 | ||
121 | }; | ||
122 | |||
123 | struct viotapelpevent { | ||
124 | struct HvLpEvent event; | ||
125 | u32 reserved; | ||
126 | u16 version; | ||
127 | u16 sub_type_result; | ||
128 | u16 tape; | ||
129 | u16 flags; | ||
130 | u32 token; | ||
131 | u64 len; | ||
132 | union { | ||
133 | struct { | ||
134 | u32 tape_op; | ||
135 | u32 count; | ||
136 | } op; | ||
137 | struct { | ||
138 | u32 type; | ||
139 | u32 resid; | ||
140 | u32 dsreg; | ||
141 | u32 gstat; | ||
142 | u32 erreg; | ||
143 | u32 file_no; | ||
144 | u32 block_no; | ||
145 | } get_status; | ||
146 | struct { | ||
147 | u32 block_no; | ||
148 | } get_pos; | ||
149 | } u; | ||
150 | }; | ||
151 | |||
152 | enum viotapesubtype { | ||
153 | viotapeopen = 0x0001, | ||
154 | viotapeclose = 0x0002, | ||
155 | viotaperead = 0x0003, | ||
156 | viotapewrite = 0x0004, | ||
157 | viotapegetinfo = 0x0005, | ||
158 | viotapeop = 0x0006, | ||
159 | viotapegetpos = 0x0007, | ||
160 | viotapesetpos = 0x0008, | ||
161 | viotapegetstatus = 0x0009 | ||
162 | }; | ||
163 | |||
164 | /* | ||
165 | * Each subtype can register a handler to process their events. | ||
166 | * The handler must have this interface. | ||
167 | */ | ||
168 | typedef void (vio_event_handler_t) (struct HvLpEvent * event); | ||
169 | |||
170 | extern int viopath_open(HvLpIndex remoteLp, int subtype, int numReq); | ||
171 | extern int viopath_close(HvLpIndex remoteLp, int subtype, int numReq); | ||
172 | extern int vio_setHandler(int subtype, vio_event_handler_t * beh); | ||
173 | extern int vio_clearHandler(int subtype); | ||
174 | extern int viopath_isactive(HvLpIndex lp); | ||
175 | extern HvLpInstanceId viopath_sourceinst(HvLpIndex lp); | ||
176 | extern HvLpInstanceId viopath_targetinst(HvLpIndex lp); | ||
177 | extern void vio_set_hostlp(void); | ||
178 | extern void *vio_get_event_buffer(int subtype); | ||
179 | extern void vio_free_event_buffer(int subtype, void *buffer); | ||
180 | |||
181 | extern struct vio_dev *vio_create_viodasd(u32 unit); | ||
182 | |||
183 | extern HvLpIndex viopath_hostLp; | ||
184 | extern HvLpIndex viopath_ourLp; | ||
185 | |||
186 | #define VIOCHAR_MAX_DATA 200 | ||
187 | |||
188 | #define VIOMAJOR_SUBTYPE_MASK 0xff00 | ||
189 | #define VIOMINOR_SUBTYPE_MASK 0x00ff | ||
190 | #define VIOMAJOR_SUBTYPE_SHIFT 8 | ||
191 | |||
192 | #define VIOVERSION 0x0101 | ||
193 | |||
194 | /* | ||
195 | * This is the general structure for VIO errors; each module should have | ||
196 | * a table of them, and each table should be terminated by an entry of | ||
197 | * { 0, 0, NULL }. Then, to find a specific error message, a module | ||
198 | * should pass its local table and the return code. | ||
199 | */ | ||
200 | struct vio_error_entry { | ||
201 | u16 rc; | ||
202 | int errno; | ||
203 | const char *msg; | ||
204 | }; | ||
205 | extern const struct vio_error_entry *vio_lookup_rc( | ||
206 | const struct vio_error_entry *local_table, u16 rc); | ||
207 | |||
208 | enum viosubtypes { | ||
209 | viomajorsubtype_monitor = 0x0100, | ||
210 | viomajorsubtype_blockio = 0x0200, | ||
211 | viomajorsubtype_chario = 0x0300, | ||
212 | viomajorsubtype_config = 0x0400, | ||
213 | viomajorsubtype_cdio = 0x0500, | ||
214 | viomajorsubtype_tape = 0x0600, | ||
215 | viomajorsubtype_scsi = 0x0700 | ||
216 | }; | ||
217 | |||
218 | enum vioconfigsubtype { | ||
219 | vioconfigget = 0x0001, | ||
220 | }; | ||
221 | |||
222 | enum viorc { | ||
223 | viorc_good = 0x0000, | ||
224 | viorc_noConnection = 0x0001, | ||
225 | viorc_noReceiver = 0x0002, | ||
226 | viorc_noBufferAvailable = 0x0003, | ||
227 | viorc_invalidMessageType = 0x0004, | ||
228 | viorc_invalidRange = 0x0201, | ||
229 | viorc_invalidToken = 0x0202, | ||
230 | viorc_DMAError = 0x0203, | ||
231 | viorc_useError = 0x0204, | ||
232 | viorc_releaseError = 0x0205, | ||
233 | viorc_invalidDisk = 0x0206, | ||
234 | viorc_openRejected = 0x0301 | ||
235 | }; | ||
236 | |||
237 | /* | ||
238 | * The structure of the events that flow between us and OS/400 for chario | ||
239 | * events. You can't mess with this unless the OS/400 side changes too. | ||
240 | */ | ||
241 | struct viocharlpevent { | ||
242 | struct HvLpEvent event; | ||
243 | u32 reserved; | ||
244 | u16 version; | ||
245 | u16 subtype_result_code; | ||
246 | u8 virtual_device; | ||
247 | u8 len; | ||
248 | u8 data[VIOCHAR_MAX_DATA]; | ||
249 | }; | ||
250 | |||
251 | #define VIOCHAR_WINDOW 10 | ||
252 | |||
253 | enum viocharsubtype { | ||
254 | viocharopen = 0x0001, | ||
255 | viocharclose = 0x0002, | ||
256 | viochardata = 0x0003, | ||
257 | viocharack = 0x0004, | ||
258 | viocharconfig = 0x0005 | ||
259 | }; | ||
260 | |||
261 | enum viochar_rc { | ||
262 | viochar_rc_ebusy = 1 | ||
263 | }; | ||
264 | |||
265 | #endif /* _ASM_POWERPC_ISERIES_VIO_H */ | ||
diff --git a/arch/powerpc/include/asm/lppaca.h b/arch/powerpc/include/asm/lppaca.h index e0298d26ce5d..a76254af0aaa 100644 --- a/arch/powerpc/include/asm/lppaca.h +++ b/arch/powerpc/include/asm/lppaca.h | |||
@@ -41,15 +41,7 @@ | |||
41 | * We only have to have statically allocated lppaca structs on | 41 | * We only have to have statically allocated lppaca structs on |
42 | * legacy iSeries, which supports at most 64 cpus. | 42 | * legacy iSeries, which supports at most 64 cpus. |
43 | */ | 43 | */ |
44 | #ifdef CONFIG_PPC_ISERIES | ||
45 | #if NR_CPUS < 64 | ||
46 | #define NR_LPPACAS NR_CPUS | ||
47 | #else | ||
48 | #define NR_LPPACAS 64 | ||
49 | #endif | ||
50 | #else /* not iSeries */ | ||
51 | #define NR_LPPACAS 1 | 44 | #define NR_LPPACAS 1 |
52 | #endif | ||
53 | 45 | ||
54 | 46 | ||
55 | /* The Hypervisor barfs if the lppaca crosses a page boundary. A 1k | 47 | /* The Hypervisor barfs if the lppaca crosses a page boundary. A 1k |
diff --git a/arch/powerpc/include/asm/mpic.h b/arch/powerpc/include/asm/mpic.h index a5b7c56237f9..c65b9294376e 100644 --- a/arch/powerpc/include/asm/mpic.h +++ b/arch/powerpc/include/asm/mpic.h | |||
@@ -273,7 +273,6 @@ struct mpic | |||
273 | unsigned int isu_size; | 273 | unsigned int isu_size; |
274 | unsigned int isu_shift; | 274 | unsigned int isu_shift; |
275 | unsigned int isu_mask; | 275 | unsigned int isu_mask; |
276 | unsigned int irq_count; | ||
277 | /* Number of sources */ | 276 | /* Number of sources */ |
278 | unsigned int num_sources; | 277 | unsigned int num_sources; |
279 | /* default senses array */ | 278 | /* default senses array */ |
@@ -349,8 +348,6 @@ struct mpic | |||
349 | #define MPIC_U3_HT_IRQS 0x00000004 | 348 | #define MPIC_U3_HT_IRQS 0x00000004 |
350 | /* Broken IPI registers (autodetected) */ | 349 | /* Broken IPI registers (autodetected) */ |
351 | #define MPIC_BROKEN_IPI 0x00000008 | 350 | #define MPIC_BROKEN_IPI 0x00000008 |
352 | /* MPIC wants a reset */ | ||
353 | #define MPIC_WANTS_RESET 0x00000010 | ||
354 | /* Spurious vector requires EOI */ | 351 | /* Spurious vector requires EOI */ |
355 | #define MPIC_SPV_EOI 0x00000020 | 352 | #define MPIC_SPV_EOI 0x00000020 |
356 | /* No passthrough disable */ | 353 | /* No passthrough disable */ |
@@ -363,15 +360,11 @@ struct mpic | |||
363 | #define MPIC_ENABLE_MCK 0x00000200 | 360 | #define MPIC_ENABLE_MCK 0x00000200 |
364 | /* Disable bias among target selection, spread interrupts evenly */ | 361 | /* Disable bias among target selection, spread interrupts evenly */ |
365 | #define MPIC_NO_BIAS 0x00000400 | 362 | #define MPIC_NO_BIAS 0x00000400 |
366 | /* Ignore NIRQS as reported by FRR */ | ||
367 | #define MPIC_BROKEN_FRR_NIRQS 0x00000800 | ||
368 | /* Destination only supports a single CPU at a time */ | 363 | /* Destination only supports a single CPU at a time */ |
369 | #define MPIC_SINGLE_DEST_CPU 0x00001000 | 364 | #define MPIC_SINGLE_DEST_CPU 0x00001000 |
370 | /* Enable CoreInt delivery of interrupts */ | 365 | /* Enable CoreInt delivery of interrupts */ |
371 | #define MPIC_ENABLE_COREINT 0x00002000 | 366 | #define MPIC_ENABLE_COREINT 0x00002000 |
372 | /* Disable resetting of the MPIC. | 367 | /* Do not reset the MPIC during initialization */ |
373 | * NOTE: This flag trumps MPIC_WANTS_RESET. | ||
374 | */ | ||
375 | #define MPIC_NO_RESET 0x00004000 | 368 | #define MPIC_NO_RESET 0x00004000 |
376 | /* Freescale MPIC (compatible includes "fsl,mpic") */ | 369 | /* Freescale MPIC (compatible includes "fsl,mpic") */ |
377 | #define MPIC_FSL 0x00008000 | 370 | #define MPIC_FSL 0x00008000 |
diff --git a/arch/powerpc/include/asm/mpic_msgr.h b/arch/powerpc/include/asm/mpic_msgr.h new file mode 100644 index 000000000000..3ec37dc9003e --- /dev/null +++ b/arch/powerpc/include/asm/mpic_msgr.h | |||
@@ -0,0 +1,132 @@ | |||
1 | /* | ||
2 | * Copyright 2011-2012, Meador Inge, Mentor Graphics Corporation. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation; version 2 of the | ||
7 | * License. | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | #ifndef _ASM_MPIC_MSGR_H | ||
12 | #define _ASM_MPIC_MSGR_H | ||
13 | |||
14 | #include <linux/types.h> | ||
15 | #include <linux/spinlock.h> | ||
16 | |||
17 | struct mpic_msgr { | ||
18 | u32 __iomem *base; | ||
19 | u32 __iomem *mer; | ||
20 | int irq; | ||
21 | unsigned char in_use; | ||
22 | raw_spinlock_t lock; | ||
23 | int num; | ||
24 | }; | ||
25 | |||
26 | /* Get a message register | ||
27 | * | ||
28 | * @reg_num: the MPIC message register to get | ||
29 | * | ||
30 | * A pointer to the message register is returned. If | ||
31 | * the message register asked for is already in use, then | ||
32 | * EBUSY is returned. If the number given is not associated | ||
33 | * with an actual message register, then ENODEV is returned. | ||
34 | * Successfully getting the register marks it as in use. | ||
35 | */ | ||
36 | extern struct mpic_msgr *mpic_msgr_get(unsigned int reg_num); | ||
37 | |||
38 | /* Relinquish a message register | ||
39 | * | ||
40 | * @msgr: the message register to return | ||
41 | * | ||
42 | * Disables the given message register and marks it as free. | ||
43 | * After this call has completed successully the message | ||
44 | * register is available to be acquired by a call to | ||
45 | * mpic_msgr_get. | ||
46 | */ | ||
47 | extern void mpic_msgr_put(struct mpic_msgr *msgr); | ||
48 | |||
49 | /* Enable a message register | ||
50 | * | ||
51 | * @msgr: the message register to enable | ||
52 | * | ||
53 | * The given message register is enabled for sending | ||
54 | * messages. | ||
55 | */ | ||
56 | extern void mpic_msgr_enable(struct mpic_msgr *msgr); | ||
57 | |||
58 | /* Disable a message register | ||
59 | * | ||
60 | * @msgr: the message register to disable | ||
61 | * | ||
62 | * The given message register is disabled for sending | ||
63 | * messages. | ||
64 | */ | ||
65 | extern void mpic_msgr_disable(struct mpic_msgr *msgr); | ||
66 | |||
67 | /* Write a message to a message register | ||
68 | * | ||
69 | * @msgr: the message register to write to | ||
70 | * @message: the message to write | ||
71 | * | ||
72 | * The given 32-bit message is written to the given message | ||
73 | * register. Writing to an enabled message registers fires | ||
74 | * an interrupt. | ||
75 | */ | ||
76 | static inline void mpic_msgr_write(struct mpic_msgr *msgr, u32 message) | ||
77 | { | ||
78 | out_be32(msgr->base, message); | ||
79 | } | ||
80 | |||
81 | /* Read a message from a message register | ||
82 | * | ||
83 | * @msgr: the message register to read from | ||
84 | * | ||
85 | * Returns the 32-bit value currently in the given message register. | ||
86 | * Upon reading the register any interrupts for that register are | ||
87 | * cleared. | ||
88 | */ | ||
89 | static inline u32 mpic_msgr_read(struct mpic_msgr *msgr) | ||
90 | { | ||
91 | return in_be32(msgr->base); | ||
92 | } | ||
93 | |||
94 | /* Clear a message register | ||
95 | * | ||
96 | * @msgr: the message register to clear | ||
97 | * | ||
98 | * Clears any interrupts associated with the given message register. | ||
99 | */ | ||
100 | static inline void mpic_msgr_clear(struct mpic_msgr *msgr) | ||
101 | { | ||
102 | (void) mpic_msgr_read(msgr); | ||
103 | } | ||
104 | |||
105 | /* Set the destination CPU for the message register | ||
106 | * | ||
107 | * @msgr: the message register whose destination is to be set | ||
108 | * @cpu_num: the Linux CPU number to bind the message register to | ||
109 | * | ||
110 | * Note that the CPU number given is the CPU number used by the kernel | ||
111 | * and *not* the actual hardware CPU number. | ||
112 | */ | ||
113 | static inline void mpic_msgr_set_destination(struct mpic_msgr *msgr, | ||
114 | u32 cpu_num) | ||
115 | { | ||
116 | out_be32(msgr->base, 1 << get_hard_smp_processor_id(cpu_num)); | ||
117 | } | ||
118 | |||
119 | /* Get the IRQ number for the message register | ||
120 | * @msgr: the message register whose IRQ is to be returned | ||
121 | * | ||
122 | * Returns the IRQ number associated with the given message register. | ||
123 | * NO_IRQ is returned if this message register is not capable of | ||
124 | * receiving interrupts. What message register can and cannot receive | ||
125 | * interrupts is specified in the device tree for the system. | ||
126 | */ | ||
127 | static inline int mpic_msgr_get_irq(struct mpic_msgr *msgr) | ||
128 | { | ||
129 | return msgr->irq; | ||
130 | } | ||
131 | |||
132 | #endif | ||
diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h index 269c05a36d91..daf813fea91f 100644 --- a/arch/powerpc/include/asm/paca.h +++ b/arch/powerpc/include/asm/paca.h | |||
@@ -132,7 +132,7 @@ struct paca_struct { | |||
132 | u64 saved_msr; /* MSR saved here by enter_rtas */ | 132 | u64 saved_msr; /* MSR saved here by enter_rtas */ |
133 | u16 trap_save; /* Used when bad stack is encountered */ | 133 | u16 trap_save; /* Used when bad stack is encountered */ |
134 | u8 soft_enabled; /* irq soft-enable flag */ | 134 | u8 soft_enabled; /* irq soft-enable flag */ |
135 | u8 hard_enabled; /* set if irqs are enabled in MSR */ | 135 | u8 irq_happened; /* irq happened while soft-disabled */ |
136 | u8 io_sync; /* writel() needs spin_unlock sync */ | 136 | u8 io_sync; /* writel() needs spin_unlock sync */ |
137 | u8 irq_work_pending; /* IRQ_WORK interrupt while soft-disable */ | 137 | u8 irq_work_pending; /* IRQ_WORK interrupt while soft-disable */ |
138 | u8 nap_state_lost; /* NV GPR values lost in power7_idle */ | 138 | u8 nap_state_lost; /* NV GPR values lost in power7_idle */ |
diff --git a/arch/powerpc/include/asm/phyp_dump.h b/arch/powerpc/include/asm/phyp_dump.h deleted file mode 100644 index fa74c6c3e106..000000000000 --- a/arch/powerpc/include/asm/phyp_dump.h +++ /dev/null | |||
@@ -1,47 +0,0 @@ | |||
1 | /* | ||
2 | * Hypervisor-assisted dump | ||
3 | * | ||
4 | * Linas Vepstas, Manish Ahuja 2008 | ||
5 | * Copyright 2008 IBM Corp. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; either version | ||
10 | * 2 of the License, or (at your option) any later version. | ||
11 | */ | ||
12 | |||
13 | #ifndef _PPC64_PHYP_DUMP_H | ||
14 | #define _PPC64_PHYP_DUMP_H | ||
15 | |||
16 | #ifdef CONFIG_PHYP_DUMP | ||
17 | |||
18 | /* The RMR region will be saved for later dumping | ||
19 | * whenever the kernel crashes. Set this to 256MB. */ | ||
20 | #define PHYP_DUMP_RMR_START 0x0 | ||
21 | #define PHYP_DUMP_RMR_END (1UL<<28) | ||
22 | |||
23 | struct phyp_dump { | ||
24 | /* Memory that is reserved during very early boot. */ | ||
25 | unsigned long init_reserve_start; | ||
26 | unsigned long init_reserve_size; | ||
27 | /* cmd line options during boot */ | ||
28 | unsigned long reserve_bootvar; | ||
29 | unsigned long phyp_dump_at_boot; | ||
30 | /* Check status during boot if dump supported, active & present*/ | ||
31 | unsigned long phyp_dump_configured; | ||
32 | unsigned long phyp_dump_is_active; | ||
33 | /* store cpu & hpte size */ | ||
34 | unsigned long cpu_state_size; | ||
35 | unsigned long hpte_region_size; | ||
36 | /* previous scratch area values */ | ||
37 | unsigned long reserved_scratch_addr; | ||
38 | unsigned long reserved_scratch_size; | ||
39 | }; | ||
40 | |||
41 | extern struct phyp_dump *phyp_dump_info; | ||
42 | |||
43 | int early_init_dt_scan_phyp_dump(unsigned long node, | ||
44 | const char *uname, int depth, void *data); | ||
45 | |||
46 | #endif /* CONFIG_PHYP_DUMP */ | ||
47 | #endif /* _PPC64_PHYP_DUMP_H */ | ||
diff --git a/arch/powerpc/include/asm/ppc-pci.h b/arch/powerpc/include/asm/ppc-pci.h index 6d422979ebaf..e660b37aa7d0 100644 --- a/arch/powerpc/include/asm/ppc-pci.h +++ b/arch/powerpc/include/asm/ppc-pci.h | |||
@@ -47,92 +47,21 @@ extern int rtas_setup_phb(struct pci_controller *phb); | |||
47 | 47 | ||
48 | extern unsigned long pci_probe_only; | 48 | extern unsigned long pci_probe_only; |
49 | 49 | ||
50 | /* ---- EEH internal-use-only related routines ---- */ | ||
51 | #ifdef CONFIG_EEH | 50 | #ifdef CONFIG_EEH |
52 | 51 | ||
52 | void pci_addr_cache_build(void); | ||
53 | void pci_addr_cache_insert_device(struct pci_dev *dev); | 53 | void pci_addr_cache_insert_device(struct pci_dev *dev); |
54 | void pci_addr_cache_remove_device(struct pci_dev *dev); | 54 | void pci_addr_cache_remove_device(struct pci_dev *dev); |
55 | void pci_addr_cache_build(void); | 55 | struct pci_dev *pci_addr_cache_get_device(unsigned long addr); |
56 | struct pci_dev *pci_get_device_by_addr(unsigned long addr); | 56 | void eeh_slot_error_detail(struct eeh_dev *edev, int severity); |
57 | 57 | int eeh_pci_enable(struct eeh_dev *edev, int function); | |
58 | /** | 58 | int eeh_reset_pe(struct eeh_dev *); |
59 | * eeh_slot_error_detail -- record and EEH error condition to the log | 59 | void eeh_restore_bars(struct eeh_dev *); |
60 | * @pdn: pci device node | ||
61 | * @severity: EEH_LOG_TEMP_FAILURE or EEH_LOG_PERM_FAILURE | ||
62 | * | ||
63 | * Obtains the EEH error details from the RTAS subsystem, | ||
64 | * and then logs these details with the RTAS error log system. | ||
65 | */ | ||
66 | #define EEH_LOG_TEMP_FAILURE 1 | ||
67 | #define EEH_LOG_PERM_FAILURE 2 | ||
68 | void eeh_slot_error_detail (struct pci_dn *pdn, int severity); | ||
69 | |||
70 | /** | ||
71 | * rtas_pci_enable - enable IO transfers for this slot | ||
72 | * @pdn: pci device node | ||
73 | * @function: either EEH_THAW_MMIO or EEH_THAW_DMA | ||
74 | * | ||
75 | * Enable I/O transfers to this slot | ||
76 | */ | ||
77 | #define EEH_THAW_MMIO 2 | ||
78 | #define EEH_THAW_DMA 3 | ||
79 | int rtas_pci_enable(struct pci_dn *pdn, int function); | ||
80 | |||
81 | /** | ||
82 | * rtas_set_slot_reset -- unfreeze a frozen slot | ||
83 | * @pdn: pci device node | ||
84 | * | ||
85 | * Clear the EEH-frozen condition on a slot. This routine | ||
86 | * does this by asserting the PCI #RST line for 1/8th of | ||
87 | * a second; this routine will sleep while the adapter is | ||
88 | * being reset. | ||
89 | * | ||
90 | * Returns a non-zero value if the reset failed. | ||
91 | */ | ||
92 | int rtas_set_slot_reset (struct pci_dn *); | ||
93 | int eeh_wait_for_slot_status(struct pci_dn *pdn, int max_wait_msecs); | ||
94 | |||
95 | /** | ||
96 | * eeh_restore_bars - Restore device configuration info. | ||
97 | * @pdn: pci device node | ||
98 | * | ||
99 | * A reset of a PCI device will clear out its config space. | ||
100 | * This routines will restore the config space for this | ||
101 | * device, and is children, to values previously obtained | ||
102 | * from the firmware. | ||
103 | */ | ||
104 | void eeh_restore_bars(struct pci_dn *); | ||
105 | |||
106 | /** | ||
107 | * rtas_configure_bridge -- firmware initialization of pci bridge | ||
108 | * @pdn: pci device node | ||
109 | * | ||
110 | * Ask the firmware to configure all PCI bridges devices | ||
111 | * located behind the indicated node. Required after a | ||
112 | * pci device reset. Does essentially the same hing as | ||
113 | * eeh_restore_bars, but for brdges, and lets firmware | ||
114 | * do the work. | ||
115 | */ | ||
116 | void rtas_configure_bridge(struct pci_dn *); | ||
117 | |||
118 | int rtas_write_config(struct pci_dn *, int where, int size, u32 val); | 60 | int rtas_write_config(struct pci_dn *, int where, int size, u32 val); |
119 | int rtas_read_config(struct pci_dn *, int where, int size, u32 *val); | 61 | int rtas_read_config(struct pci_dn *, int where, int size, u32 *val); |
120 | 62 | void eeh_mark_slot(struct device_node *dn, int mode_flag); | |
121 | /** | 63 | void eeh_clear_slot(struct device_node *dn, int mode_flag); |
122 | * eeh_mark_slot -- set mode flags for pertition endpoint | 64 | struct device_node *eeh_find_device_pe(struct device_node *dn); |
123 | * @pdn: pci device node | ||
124 | * | ||
125 | * mark and clear slots: find "partition endpoint" PE and set or | ||
126 | * clear the flags for each subnode of the PE. | ||
127 | */ | ||
128 | void eeh_mark_slot (struct device_node *dn, int mode_flag); | ||
129 | void eeh_clear_slot (struct device_node *dn, int mode_flag); | ||
130 | |||
131 | /** | ||
132 | * find_device_pe -- Find the associated "Partiationable Endpoint" PE | ||
133 | * @pdn: pci device node | ||
134 | */ | ||
135 | struct device_node * find_device_pe(struct device_node *dn); | ||
136 | 65 | ||
137 | void eeh_sysfs_add_device(struct pci_dev *pdev); | 66 | void eeh_sysfs_add_device(struct pci_dev *pdev); |
138 | void eeh_sysfs_remove_device(struct pci_dev *pdev); | 67 | void eeh_sysfs_remove_device(struct pci_dev *pdev); |
diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h index 368f72f79808..50f73aa2ba21 100644 --- a/arch/powerpc/include/asm/ppc_asm.h +++ b/arch/powerpc/include/asm/ppc_asm.h | |||
@@ -60,6 +60,8 @@ BEGIN_FW_FTR_SECTION; \ | |||
60 | cmpd cr1,r11,r10; \ | 60 | cmpd cr1,r11,r10; \ |
61 | beq+ cr1,33f; \ | 61 | beq+ cr1,33f; \ |
62 | bl .accumulate_stolen_time; \ | 62 | bl .accumulate_stolen_time; \ |
63 | ld r12,_MSR(r1); \ | ||
64 | andi. r10,r12,MSR_PR; /* Restore cr0 (coming from user) */ \ | ||
63 | 33: \ | 65 | 33: \ |
64 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR) | 66 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR) |
65 | 67 | ||
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index 7fdc2c0b7fa0..b1a215eabef6 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h | |||
@@ -1079,30 +1079,12 @@ | |||
1079 | 1079 | ||
1080 | #define proc_trap() asm volatile("trap") | 1080 | #define proc_trap() asm volatile("trap") |
1081 | 1081 | ||
1082 | #ifdef CONFIG_PPC64 | 1082 | #define __get_SP() ({unsigned long sp; \ |
1083 | 1083 | asm volatile("mr %0,1": "=r" (sp)); sp;}) | |
1084 | extern void ppc64_runlatch_on(void); | ||
1085 | extern void __ppc64_runlatch_off(void); | ||
1086 | |||
1087 | #define ppc64_runlatch_off() \ | ||
1088 | do { \ | ||
1089 | if (cpu_has_feature(CPU_FTR_CTRL) && \ | ||
1090 | test_thread_flag(TIF_RUNLATCH)) \ | ||
1091 | __ppc64_runlatch_off(); \ | ||
1092 | } while (0) | ||
1093 | 1084 | ||
1094 | extern unsigned long scom970_read(unsigned int address); | 1085 | extern unsigned long scom970_read(unsigned int address); |
1095 | extern void scom970_write(unsigned int address, unsigned long value); | 1086 | extern void scom970_write(unsigned int address, unsigned long value); |
1096 | 1087 | ||
1097 | #else | ||
1098 | #define ppc64_runlatch_on() | ||
1099 | #define ppc64_runlatch_off() | ||
1100 | |||
1101 | #endif /* CONFIG_PPC64 */ | ||
1102 | |||
1103 | #define __get_SP() ({unsigned long sp; \ | ||
1104 | asm volatile("mr %0,1": "=r" (sp)); sp;}) | ||
1105 | |||
1106 | struct pt_regs; | 1088 | struct pt_regs; |
1107 | 1089 | ||
1108 | extern void ppc_save_regs(struct pt_regs *regs); | 1090 | extern void ppc_save_regs(struct pt_regs *regs); |
diff --git a/arch/powerpc/include/asm/reg_booke.h b/arch/powerpc/include/asm/reg_booke.h index 500fe1dc43e6..8a97aa7289d3 100644 --- a/arch/powerpc/include/asm/reg_booke.h +++ b/arch/powerpc/include/asm/reg_booke.h | |||
@@ -62,6 +62,7 @@ | |||
62 | #define SPRN_DVC2 0x13F /* Data Value Compare Register 2 */ | 62 | #define SPRN_DVC2 0x13F /* Data Value Compare Register 2 */ |
63 | #define SPRN_MAS8 0x155 /* MMU Assist Register 8 */ | 63 | #define SPRN_MAS8 0x155 /* MMU Assist Register 8 */ |
64 | #define SPRN_TLB0PS 0x158 /* TLB 0 Page Size Register */ | 64 | #define SPRN_TLB0PS 0x158 /* TLB 0 Page Size Register */ |
65 | #define SPRN_TLB1PS 0x159 /* TLB 1 Page Size Register */ | ||
65 | #define SPRN_MAS5_MAS6 0x15c /* MMU Assist Register 5 || 6 */ | 66 | #define SPRN_MAS5_MAS6 0x15c /* MMU Assist Register 5 || 6 */ |
66 | #define SPRN_MAS8_MAS1 0x15d /* MMU Assist Register 8 || 1 */ | 67 | #define SPRN_MAS8_MAS1 0x15d /* MMU Assist Register 8 || 1 */ |
67 | #define SPRN_EPTCFG 0x15e /* Embedded Page Table Config */ | 68 | #define SPRN_EPTCFG 0x15e /* Embedded Page Table Config */ |
diff --git a/arch/powerpc/include/asm/spinlock.h b/arch/powerpc/include/asm/spinlock.h index f9611bd69ed2..7124fc06ad47 100644 --- a/arch/powerpc/include/asm/spinlock.h +++ b/arch/powerpc/include/asm/spinlock.h | |||
@@ -23,7 +23,6 @@ | |||
23 | #ifdef CONFIG_PPC64 | 23 | #ifdef CONFIG_PPC64 |
24 | #include <asm/paca.h> | 24 | #include <asm/paca.h> |
25 | #include <asm/hvcall.h> | 25 | #include <asm/hvcall.h> |
26 | #include <asm/iseries/hv_call.h> | ||
27 | #endif | 26 | #endif |
28 | #include <asm/asm-compat.h> | 27 | #include <asm/asm-compat.h> |
29 | #include <asm/synch.h> | 28 | #include <asm/synch.h> |
@@ -95,12 +94,12 @@ static inline int arch_spin_trylock(arch_spinlock_t *lock) | |||
95 | * value. | 94 | * value. |
96 | */ | 95 | */ |
97 | 96 | ||
98 | #if defined(CONFIG_PPC_SPLPAR) || defined(CONFIG_PPC_ISERIES) | 97 | #if defined(CONFIG_PPC_SPLPAR) |
99 | /* We only yield to the hypervisor if we are in shared processor mode */ | 98 | /* We only yield to the hypervisor if we are in shared processor mode */ |
100 | #define SHARED_PROCESSOR (get_lppaca()->shared_proc) | 99 | #define SHARED_PROCESSOR (get_lppaca()->shared_proc) |
101 | extern void __spin_yield(arch_spinlock_t *lock); | 100 | extern void __spin_yield(arch_spinlock_t *lock); |
102 | extern void __rw_yield(arch_rwlock_t *lock); | 101 | extern void __rw_yield(arch_rwlock_t *lock); |
103 | #else /* SPLPAR || ISERIES */ | 102 | #else /* SPLPAR */ |
104 | #define __spin_yield(x) barrier() | 103 | #define __spin_yield(x) barrier() |
105 | #define __rw_yield(x) barrier() | 104 | #define __rw_yield(x) barrier() |
106 | #define SHARED_PROCESSOR 0 | 105 | #define SHARED_PROCESSOR 0 |
diff --git a/arch/powerpc/include/asm/system.h b/arch/powerpc/include/asm/system.h index c377457d1b89..a02883d5af43 100644 --- a/arch/powerpc/include/asm/system.h +++ b/arch/powerpc/include/asm/system.h | |||
@@ -550,5 +550,43 @@ extern void reloc_got2(unsigned long); | |||
550 | 550 | ||
551 | extern struct dentry *powerpc_debugfs_root; | 551 | extern struct dentry *powerpc_debugfs_root; |
552 | 552 | ||
553 | #ifdef CONFIG_PPC64 | ||
554 | |||
555 | extern void __ppc64_runlatch_on(void); | ||
556 | extern void __ppc64_runlatch_off(void); | ||
557 | |||
558 | /* | ||
559 | * We manually hard enable-disable, this is called | ||
560 | * in the idle loop and we don't want to mess up | ||
561 | * with soft-disable/enable & interrupt replay. | ||
562 | */ | ||
563 | #define ppc64_runlatch_off() \ | ||
564 | do { \ | ||
565 | if (cpu_has_feature(CPU_FTR_CTRL) && \ | ||
566 | test_thread_local_flags(_TLF_RUNLATCH)) { \ | ||
567 | unsigned long msr = mfmsr(); \ | ||
568 | __hard_irq_disable(); \ | ||
569 | __ppc64_runlatch_off(); \ | ||
570 | if (msr & MSR_EE) \ | ||
571 | __hard_irq_enable(); \ | ||
572 | } \ | ||
573 | } while (0) | ||
574 | |||
575 | #define ppc64_runlatch_on() \ | ||
576 | do { \ | ||
577 | if (cpu_has_feature(CPU_FTR_CTRL) && \ | ||
578 | !test_thread_local_flags(_TLF_RUNLATCH)) { \ | ||
579 | unsigned long msr = mfmsr(); \ | ||
580 | __hard_irq_disable(); \ | ||
581 | __ppc64_runlatch_on(); \ | ||
582 | if (msr & MSR_EE) \ | ||
583 | __hard_irq_enable(); \ | ||
584 | } \ | ||
585 | } while (0) | ||
586 | #else | ||
587 | #define ppc64_runlatch_on() | ||
588 | #define ppc64_runlatch_off() | ||
589 | #endif /* CONFIG_PPC64 */ | ||
590 | |||
553 | #endif /* __KERNEL__ */ | 591 | #endif /* __KERNEL__ */ |
554 | #endif /* _ASM_POWERPC_SYSTEM_H */ | 592 | #endif /* _ASM_POWERPC_SYSTEM_H */ |
diff --git a/arch/powerpc/include/asm/thread_info.h b/arch/powerpc/include/asm/thread_info.h index 964714940961..4a741c7efd02 100644 --- a/arch/powerpc/include/asm/thread_info.h +++ b/arch/powerpc/include/asm/thread_info.h | |||
@@ -110,7 +110,6 @@ static inline struct thread_info *current_thread_info(void) | |||
110 | #define TIF_NOERROR 12 /* Force successful syscall return */ | 110 | #define TIF_NOERROR 12 /* Force successful syscall return */ |
111 | #define TIF_NOTIFY_RESUME 13 /* callback before returning to user */ | 111 | #define TIF_NOTIFY_RESUME 13 /* callback before returning to user */ |
112 | #define TIF_SYSCALL_TRACEPOINT 15 /* syscall tracepoint instrumentation */ | 112 | #define TIF_SYSCALL_TRACEPOINT 15 /* syscall tracepoint instrumentation */ |
113 | #define TIF_RUNLATCH 16 /* Is the runlatch enabled? */ | ||
114 | 113 | ||
115 | /* as above, but as bit values */ | 114 | /* as above, but as bit values */ |
116 | #define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE) | 115 | #define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE) |
@@ -141,11 +140,13 @@ static inline struct thread_info *current_thread_info(void) | |||
141 | #define TLF_SLEEPING 1 /* suspend code enabled SLEEP mode */ | 140 | #define TLF_SLEEPING 1 /* suspend code enabled SLEEP mode */ |
142 | #define TLF_RESTORE_SIGMASK 2 /* Restore signal mask in do_signal */ | 141 | #define TLF_RESTORE_SIGMASK 2 /* Restore signal mask in do_signal */ |
143 | #define TLF_LAZY_MMU 3 /* tlb_batch is active */ | 142 | #define TLF_LAZY_MMU 3 /* tlb_batch is active */ |
143 | #define TLF_RUNLATCH 4 /* Is the runlatch enabled? */ | ||
144 | 144 | ||
145 | #define _TLF_NAPPING (1 << TLF_NAPPING) | 145 | #define _TLF_NAPPING (1 << TLF_NAPPING) |
146 | #define _TLF_SLEEPING (1 << TLF_SLEEPING) | 146 | #define _TLF_SLEEPING (1 << TLF_SLEEPING) |
147 | #define _TLF_RESTORE_SIGMASK (1 << TLF_RESTORE_SIGMASK) | 147 | #define _TLF_RESTORE_SIGMASK (1 << TLF_RESTORE_SIGMASK) |
148 | #define _TLF_LAZY_MMU (1 << TLF_LAZY_MMU) | 148 | #define _TLF_LAZY_MMU (1 << TLF_LAZY_MMU) |
149 | #define _TLF_RUNLATCH (1 << TLF_RUNLATCH) | ||
149 | 150 | ||
150 | #ifndef __ASSEMBLY__ | 151 | #ifndef __ASSEMBLY__ |
151 | #define HAVE_SET_RESTORE_SIGMASK 1 | 152 | #define HAVE_SET_RESTORE_SIGMASK 1 |
@@ -156,6 +157,12 @@ static inline void set_restore_sigmask(void) | |||
156 | set_bit(TIF_SIGPENDING, &ti->flags); | 157 | set_bit(TIF_SIGPENDING, &ti->flags); |
157 | } | 158 | } |
158 | 159 | ||
160 | static inline bool test_thread_local_flags(unsigned int flags) | ||
161 | { | ||
162 | struct thread_info *ti = current_thread_info(); | ||
163 | return (ti->local_flags & flags) != 0; | ||
164 | } | ||
165 | |||
159 | #ifdef CONFIG_PPC64 | 166 | #ifdef CONFIG_PPC64 |
160 | #define is_32bit_task() (test_thread_flag(TIF_32BIT)) | 167 | #define is_32bit_task() (test_thread_flag(TIF_32BIT)) |
161 | #else | 168 | #else |
diff --git a/arch/powerpc/include/asm/time.h b/arch/powerpc/include/asm/time.h index 7eb10fb96cd0..2136f58a54e8 100644 --- a/arch/powerpc/include/asm/time.h +++ b/arch/powerpc/include/asm/time.h | |||
@@ -18,11 +18,6 @@ | |||
18 | #include <linux/percpu.h> | 18 | #include <linux/percpu.h> |
19 | 19 | ||
20 | #include <asm/processor.h> | 20 | #include <asm/processor.h> |
21 | #ifdef CONFIG_PPC_ISERIES | ||
22 | #include <asm/paca.h> | ||
23 | #include <asm/firmware.h> | ||
24 | #include <asm/iseries/hv_call.h> | ||
25 | #endif | ||
26 | 21 | ||
27 | /* time.c */ | 22 | /* time.c */ |
28 | extern unsigned long tb_ticks_per_jiffy; | 23 | extern unsigned long tb_ticks_per_jiffy; |
@@ -167,15 +162,6 @@ static inline void set_dec(int val) | |||
167 | #ifndef CONFIG_BOOKE | 162 | #ifndef CONFIG_BOOKE |
168 | --val; | 163 | --val; |
169 | #endif | 164 | #endif |
170 | #ifdef CONFIG_PPC_ISERIES | ||
171 | if (firmware_has_feature(FW_FEATURE_ISERIES) && | ||
172 | get_lppaca()->shared_proc) { | ||
173 | get_lppaca()->virtual_decr = val; | ||
174 | if (get_dec() > val) | ||
175 | HvCall_setVirtualDecr(); | ||
176 | return; | ||
177 | } | ||
178 | #endif | ||
179 | mtspr(SPRN_DEC, val); | 165 | mtspr(SPRN_DEC, val); |
180 | #endif /* not 40x or 8xx_CPU6 */ | 166 | #endif /* not 40x or 8xx_CPU6 */ |
181 | } | 167 | } |
@@ -217,7 +203,6 @@ DECLARE_PER_CPU(struct cpu_usage, cpu_usage_array); | |||
217 | #endif | 203 | #endif |
218 | 204 | ||
219 | extern void secondary_cpu_time_init(void); | 205 | extern void secondary_cpu_time_init(void); |
220 | extern void iSeries_time_init_early(void); | ||
221 | 206 | ||
222 | DECLARE_PER_CPU(u64, decrementers_next_tb); | 207 | DECLARE_PER_CPU(u64, decrementers_next_tb); |
223 | 208 | ||
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index ee728e433aa2..f5808a35688c 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile | |||
@@ -60,6 +60,7 @@ obj-$(CONFIG_IBMVIO) += vio.o | |||
60 | obj-$(CONFIG_IBMEBUS) += ibmebus.o | 60 | obj-$(CONFIG_IBMEBUS) += ibmebus.o |
61 | obj-$(CONFIG_GENERIC_TBSYNC) += smp-tbsync.o | 61 | obj-$(CONFIG_GENERIC_TBSYNC) += smp-tbsync.o |
62 | obj-$(CONFIG_CRASH_DUMP) += crash_dump.o | 62 | obj-$(CONFIG_CRASH_DUMP) += crash_dump.o |
63 | obj-$(CONFIG_FA_DUMP) += fadump.o | ||
63 | ifeq ($(CONFIG_PPC32),y) | 64 | ifeq ($(CONFIG_PPC32),y) |
64 | obj-$(CONFIG_E500) += idle_e500.o | 65 | obj-$(CONFIG_E500) += idle_e500.o |
65 | endif | 66 | endif |
@@ -113,15 +114,6 @@ obj-$(CONFIG_PPC_IO_WORKAROUNDS) += io-workarounds.o | |||
113 | obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o | 114 | obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o |
114 | obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o | 115 | obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o |
115 | obj-$(CONFIG_FTRACE_SYSCALLS) += ftrace.o | 116 | obj-$(CONFIG_FTRACE_SYSCALLS) += ftrace.o |
116 | obj-$(CONFIG_PERF_EVENTS) += perf_callchain.o | ||
117 | |||
118 | obj-$(CONFIG_PPC_PERF_CTRS) += perf_event.o | ||
119 | obj64-$(CONFIG_PPC_PERF_CTRS) += power4-pmu.o ppc970-pmu.o power5-pmu.o \ | ||
120 | power5+-pmu.o power6-pmu.o power7-pmu.o | ||
121 | obj32-$(CONFIG_PPC_PERF_CTRS) += mpc7450-pmu.o | ||
122 | |||
123 | obj-$(CONFIG_FSL_EMB_PERF_EVENT) += perf_event_fsl_emb.o | ||
124 | obj-$(CONFIG_FSL_EMB_PERF_EVENT_E500) += e500-pmu.o | ||
125 | 117 | ||
126 | obj-$(CONFIG_8XX_MINIMAL_FPEMU) += softemu8xx.o | 118 | obj-$(CONFIG_8XX_MINIMAL_FPEMU) += softemu8xx.o |
127 | 119 | ||
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 04caee7d9bc1..cc492e48ddfa 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c | |||
@@ -46,9 +46,6 @@ | |||
46 | #include <asm/hvcall.h> | 46 | #include <asm/hvcall.h> |
47 | #include <asm/xics.h> | 47 | #include <asm/xics.h> |
48 | #endif | 48 | #endif |
49 | #ifdef CONFIG_PPC_ISERIES | ||
50 | #include <asm/iseries/alpaca.h> | ||
51 | #endif | ||
52 | #ifdef CONFIG_PPC_POWERNV | 49 | #ifdef CONFIG_PPC_POWERNV |
53 | #include <asm/opal.h> | 50 | #include <asm/opal.h> |
54 | #endif | 51 | #endif |
@@ -147,7 +144,7 @@ int main(void) | |||
147 | DEFINE(PACAKBASE, offsetof(struct paca_struct, kernelbase)); | 144 | DEFINE(PACAKBASE, offsetof(struct paca_struct, kernelbase)); |
148 | DEFINE(PACAKMSR, offsetof(struct paca_struct, kernel_msr)); | 145 | DEFINE(PACAKMSR, offsetof(struct paca_struct, kernel_msr)); |
149 | DEFINE(PACASOFTIRQEN, offsetof(struct paca_struct, soft_enabled)); | 146 | DEFINE(PACASOFTIRQEN, offsetof(struct paca_struct, soft_enabled)); |
150 | DEFINE(PACAHARDIRQEN, offsetof(struct paca_struct, hard_enabled)); | 147 | DEFINE(PACAIRQHAPPENED, offsetof(struct paca_struct, irq_happened)); |
151 | DEFINE(PACACONTEXTID, offsetof(struct paca_struct, context.id)); | 148 | DEFINE(PACACONTEXTID, offsetof(struct paca_struct, context.id)); |
152 | #ifdef CONFIG_PPC_MM_SLICES | 149 | #ifdef CONFIG_PPC_MM_SLICES |
153 | DEFINE(PACALOWSLICESPSIZE, offsetof(struct paca_struct, | 150 | DEFINE(PACALOWSLICESPSIZE, offsetof(struct paca_struct, |
@@ -384,17 +381,6 @@ int main(void) | |||
384 | DEFINE(BUG_ENTRY_SIZE, sizeof(struct bug_entry)); | 381 | DEFINE(BUG_ENTRY_SIZE, sizeof(struct bug_entry)); |
385 | #endif | 382 | #endif |
386 | 383 | ||
387 | #ifdef CONFIG_PPC_ISERIES | ||
388 | /* the assembler miscalculates the VSID values */ | ||
389 | DEFINE(PAGE_OFFSET_ESID, GET_ESID(PAGE_OFFSET)); | ||
390 | DEFINE(PAGE_OFFSET_VSID, KERNEL_VSID(PAGE_OFFSET)); | ||
391 | DEFINE(VMALLOC_START_ESID, GET_ESID(VMALLOC_START)); | ||
392 | DEFINE(VMALLOC_START_VSID, KERNEL_VSID(VMALLOC_START)); | ||
393 | |||
394 | /* alpaca */ | ||
395 | DEFINE(ALPACA_SIZE, sizeof(struct alpaca)); | ||
396 | #endif | ||
397 | |||
398 | DEFINE(PGD_TABLE_SIZE, PGD_TABLE_SIZE); | 384 | DEFINE(PGD_TABLE_SIZE, PGD_TABLE_SIZE); |
399 | DEFINE(PTE_SIZE, sizeof(pte_t)); | 385 | DEFINE(PTE_SIZE, sizeof(pte_t)); |
400 | 386 | ||
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c index 81db9e2a8a20..138ae183c440 100644 --- a/arch/powerpc/kernel/cputable.c +++ b/arch/powerpc/kernel/cputable.c | |||
@@ -1816,7 +1816,7 @@ static struct cpu_spec __initdata cpu_specs[] = { | |||
1816 | .platform = "ppc440", | 1816 | .platform = "ppc440", |
1817 | }, | 1817 | }, |
1818 | { /* 464 in APM821xx */ | 1818 | { /* 464 in APM821xx */ |
1819 | .pvr_mask = 0xffffff00, | 1819 | .pvr_mask = 0xfffffff0, |
1820 | .pvr_value = 0x12C41C80, | 1820 | .pvr_value = 0x12C41C80, |
1821 | .cpu_name = "APM821XX", | 1821 | .cpu_name = "APM821XX", |
1822 | .cpu_features = CPU_FTRS_44X, | 1822 | .cpu_features = CPU_FTRS_44X, |
@@ -2019,6 +2019,24 @@ static struct cpu_spec __initdata cpu_specs[] = { | |||
2019 | .machine_check = machine_check_e500mc, | 2019 | .machine_check = machine_check_e500mc, |
2020 | .platform = "ppce5500", | 2020 | .platform = "ppce5500", |
2021 | }, | 2021 | }, |
2022 | { /* e6500 */ | ||
2023 | .pvr_mask = 0xffff0000, | ||
2024 | .pvr_value = 0x80400000, | ||
2025 | .cpu_name = "e6500", | ||
2026 | .cpu_features = CPU_FTRS_E6500, | ||
2027 | .cpu_user_features = COMMON_USER_BOOKE | PPC_FEATURE_HAS_FPU, | ||
2028 | .mmu_features = MMU_FTR_TYPE_FSL_E | MMU_FTR_BIG_PHYS | | ||
2029 | MMU_FTR_USE_TLBILX, | ||
2030 | .icache_bsize = 64, | ||
2031 | .dcache_bsize = 64, | ||
2032 | .num_pmcs = 4, | ||
2033 | .oprofile_cpu_type = "ppc/e6500", | ||
2034 | .oprofile_type = PPC_OPROFILE_FSL_EMB, | ||
2035 | .cpu_setup = __setup_cpu_e5500, | ||
2036 | .cpu_restore = __restore_cpu_e5500, | ||
2037 | .machine_check = machine_check_e500mc, | ||
2038 | .platform = "ppce6500", | ||
2039 | }, | ||
2022 | #ifdef CONFIG_PPC32 | 2040 | #ifdef CONFIG_PPC32 |
2023 | { /* default match */ | 2041 | { /* default match */ |
2024 | .pvr_mask = 0x00000000, | 2042 | .pvr_mask = 0x00000000, |
diff --git a/arch/powerpc/kernel/dbell.c b/arch/powerpc/kernel/dbell.c index 2cc451aaaca7..5b25c8060fd6 100644 --- a/arch/powerpc/kernel/dbell.c +++ b/arch/powerpc/kernel/dbell.c | |||
@@ -37,6 +37,8 @@ void doorbell_exception(struct pt_regs *regs) | |||
37 | 37 | ||
38 | irq_enter(); | 38 | irq_enter(); |
39 | 39 | ||
40 | may_hard_irq_enable(); | ||
41 | |||
40 | smp_ipi_demux(); | 42 | smp_ipi_demux(); |
41 | 43 | ||
42 | irq_exit(); | 44 | irq_exit(); |
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index 866462cbe2d8..f8a7a1a1a9f4 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <asm/ptrace.h> | 32 | #include <asm/ptrace.h> |
33 | #include <asm/irqflags.h> | 33 | #include <asm/irqflags.h> |
34 | #include <asm/ftrace.h> | 34 | #include <asm/ftrace.h> |
35 | #include <asm/hw_irq.h> | ||
35 | 36 | ||
36 | /* | 37 | /* |
37 | * System calls. | 38 | * System calls. |
@@ -115,39 +116,33 @@ BEGIN_FW_FTR_SECTION | |||
115 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR) | 116 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR) |
116 | #endif /* CONFIG_VIRT_CPU_ACCOUNTING && CONFIG_PPC_SPLPAR */ | 117 | #endif /* CONFIG_VIRT_CPU_ACCOUNTING && CONFIG_PPC_SPLPAR */ |
117 | 118 | ||
118 | #ifdef CONFIG_TRACE_IRQFLAGS | 119 | /* |
119 | bl .trace_hardirqs_on | 120 | * A syscall should always be called with interrupts enabled |
120 | REST_GPR(0,r1) | 121 | * so we just unconditionally hard-enable here. When some kind |
121 | REST_4GPRS(3,r1) | 122 | * of irq tracing is used, we additionally check that condition |
122 | REST_2GPRS(7,r1) | 123 | * is correct |
123 | addi r9,r1,STACK_FRAME_OVERHEAD | 124 | */ |
124 | ld r12,_MSR(r1) | 125 | #if defined(CONFIG_TRACE_IRQFLAGS) && defined(CONFIG_BUG) |
125 | #endif /* CONFIG_TRACE_IRQFLAGS */ | 126 | lbz r10,PACASOFTIRQEN(r13) |
126 | li r10,1 | 127 | xori r10,r10,1 |
127 | stb r10,PACASOFTIRQEN(r13) | 128 | 1: tdnei r10,0 |
128 | stb r10,PACAHARDIRQEN(r13) | 129 | EMIT_BUG_ENTRY 1b,__FILE__,__LINE__,BUGFLAG_WARNING |
129 | std r10,SOFTE(r1) | 130 | #endif |
130 | #ifdef CONFIG_PPC_ISERIES | ||
131 | BEGIN_FW_FTR_SECTION | ||
132 | /* Hack for handling interrupts when soft-enabling on iSeries */ | ||
133 | cmpdi cr1,r0,0x5555 /* syscall 0x5555 */ | ||
134 | andi. r10,r12,MSR_PR /* from kernel */ | ||
135 | crand 4*cr0+eq,4*cr1+eq,4*cr0+eq | ||
136 | bne 2f | ||
137 | b hardware_interrupt_entry | ||
138 | 2: | ||
139 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) | ||
140 | #endif /* CONFIG_PPC_ISERIES */ | ||
141 | 131 | ||
142 | /* Hard enable interrupts */ | ||
143 | #ifdef CONFIG_PPC_BOOK3E | 132 | #ifdef CONFIG_PPC_BOOK3E |
144 | wrteei 1 | 133 | wrteei 1 |
145 | #else | 134 | #else |
146 | mfmsr r11 | 135 | ld r11,PACAKMSR(r13) |
147 | ori r11,r11,MSR_EE | 136 | ori r11,r11,MSR_EE |
148 | mtmsrd r11,1 | 137 | mtmsrd r11,1 |
149 | #endif /* CONFIG_PPC_BOOK3E */ | 138 | #endif /* CONFIG_PPC_BOOK3E */ |
150 | 139 | ||
140 | /* We do need to set SOFTE in the stack frame or the return | ||
141 | * from interrupt will be painful | ||
142 | */ | ||
143 | li r10,1 | ||
144 | std r10,SOFTE(r1) | ||
145 | |||
151 | #ifdef SHOW_SYSCALLS | 146 | #ifdef SHOW_SYSCALLS |
152 | bl .do_show_syscall | 147 | bl .do_show_syscall |
153 | REST_GPR(0,r1) | 148 | REST_GPR(0,r1) |
@@ -198,16 +193,14 @@ syscall_exit: | |||
198 | andi. r10,r8,MSR_RI | 193 | andi. r10,r8,MSR_RI |
199 | beq- unrecov_restore | 194 | beq- unrecov_restore |
200 | #endif | 195 | #endif |
201 | 196 | /* | |
202 | /* Disable interrupts so current_thread_info()->flags can't change, | 197 | * Disable interrupts so current_thread_info()->flags can't change, |
203 | * and so that we don't get interrupted after loading SRR0/1. | 198 | * and so that we don't get interrupted after loading SRR0/1. |
204 | */ | 199 | */ |
205 | #ifdef CONFIG_PPC_BOOK3E | 200 | #ifdef CONFIG_PPC_BOOK3E |
206 | wrteei 0 | 201 | wrteei 0 |
207 | #else | 202 | #else |
208 | mfmsr r10 | 203 | ld r10,PACAKMSR(r13) |
209 | rldicl r10,r10,48,1 | ||
210 | rotldi r10,r10,16 | ||
211 | mtmsrd r10,1 | 204 | mtmsrd r10,1 |
212 | #endif /* CONFIG_PPC_BOOK3E */ | 205 | #endif /* CONFIG_PPC_BOOK3E */ |
213 | 206 | ||
@@ -319,7 +312,7 @@ syscall_exit_work: | |||
319 | #ifdef CONFIG_PPC_BOOK3E | 312 | #ifdef CONFIG_PPC_BOOK3E |
320 | wrteei 1 | 313 | wrteei 1 |
321 | #else | 314 | #else |
322 | mfmsr r10 | 315 | ld r10,PACAKMSR(r13) |
323 | ori r10,r10,MSR_EE | 316 | ori r10,r10,MSR_EE |
324 | mtmsrd r10,1 | 317 | mtmsrd r10,1 |
325 | #endif /* CONFIG_PPC_BOOK3E */ | 318 | #endif /* CONFIG_PPC_BOOK3E */ |
@@ -565,10 +558,8 @@ _GLOBAL(ret_from_except_lite) | |||
565 | #ifdef CONFIG_PPC_BOOK3E | 558 | #ifdef CONFIG_PPC_BOOK3E |
566 | wrteei 0 | 559 | wrteei 0 |
567 | #else | 560 | #else |
568 | mfmsr r10 /* Get current interrupt state */ | 561 | ld r10,PACAKMSR(r13) /* Get kernel MSR without EE */ |
569 | rldicl r9,r10,48,1 /* clear MSR_EE */ | 562 | mtmsrd r10,1 /* Update machine state */ |
570 | rotldi r9,r9,16 | ||
571 | mtmsrd r9,1 /* Update machine state */ | ||
572 | #endif /* CONFIG_PPC_BOOK3E */ | 563 | #endif /* CONFIG_PPC_BOOK3E */ |
573 | 564 | ||
574 | #ifdef CONFIG_PREEMPT | 565 | #ifdef CONFIG_PREEMPT |
@@ -591,25 +582,74 @@ _GLOBAL(ret_from_except_lite) | |||
591 | ld r4,TI_FLAGS(r9) | 582 | ld r4,TI_FLAGS(r9) |
592 | andi. r0,r4,_TIF_USER_WORK_MASK | 583 | andi. r0,r4,_TIF_USER_WORK_MASK |
593 | bne do_work | 584 | bne do_work |
594 | #endif | 585 | #endif /* !CONFIG_PREEMPT */ |
595 | 586 | ||
587 | .globl fast_exc_return_irq | ||
588 | fast_exc_return_irq: | ||
596 | restore: | 589 | restore: |
597 | BEGIN_FW_FTR_SECTION | 590 | /* |
591 | * This is the main kernel exit path, we first check if we | ||
592 | * have to change our interrupt state. | ||
593 | */ | ||
598 | ld r5,SOFTE(r1) | 594 | ld r5,SOFTE(r1) |
599 | FW_FTR_SECTION_ELSE | 595 | lbz r6,PACASOFTIRQEN(r13) |
600 | b .Liseries_check_pending_irqs | 596 | cmpwi cr1,r5,0 |
601 | ALT_FW_FTR_SECTION_END_IFCLR(FW_FEATURE_ISERIES) | 597 | cmpw cr0,r5,r6 |
602 | 2: | 598 | beq cr0,4f |
603 | TRACE_AND_RESTORE_IRQ(r5); | 599 | |
600 | /* We do, handle disable first, which is easy */ | ||
601 | bne cr1,3f; | ||
602 | li r0,0 | ||
603 | stb r0,PACASOFTIRQEN(r13); | ||
604 | TRACE_DISABLE_INTS | ||
605 | b 4f | ||
604 | 606 | ||
605 | /* extract EE bit and use it to restore paca->hard_enabled */ | 607 | 3: /* |
606 | ld r3,_MSR(r1) | 608 | * We are about to soft-enable interrupts (we are hard disabled |
607 | rldicl r4,r3,49,63 /* r0 = (r3 >> 15) & 1 */ | 609 | * at this point). We check if there's anything that needs to |
608 | stb r4,PACAHARDIRQEN(r13) | 610 | * be replayed first. |
611 | */ | ||
612 | lbz r0,PACAIRQHAPPENED(r13) | ||
613 | cmpwi cr0,r0,0 | ||
614 | bne- restore_check_irq_replay | ||
609 | 615 | ||
616 | /* | ||
617 | * Get here when nothing happened while soft-disabled, just | ||
618 | * soft-enable and move-on. We will hard-enable as a side | ||
619 | * effect of rfi | ||
620 | */ | ||
621 | restore_no_replay: | ||
622 | TRACE_ENABLE_INTS | ||
623 | li r0,1 | ||
624 | stb r0,PACASOFTIRQEN(r13); | ||
625 | |||
626 | /* | ||
627 | * Final return path. BookE is handled in a different file | ||
628 | */ | ||
629 | 4: | ||
610 | #ifdef CONFIG_PPC_BOOK3E | 630 | #ifdef CONFIG_PPC_BOOK3E |
611 | b .exception_return_book3e | 631 | b .exception_return_book3e |
612 | #else | 632 | #else |
633 | /* | ||
634 | * Clear the reservation. If we know the CPU tracks the address of | ||
635 | * the reservation then we can potentially save some cycles and use | ||
636 | * a larx. On POWER6 and POWER7 this is significantly faster. | ||
637 | */ | ||
638 | BEGIN_FTR_SECTION | ||
639 | stdcx. r0,0,r1 /* to clear the reservation */ | ||
640 | FTR_SECTION_ELSE | ||
641 | ldarx r4,0,r1 | ||
642 | ALT_FTR_SECTION_END_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS) | ||
643 | |||
644 | /* | ||
645 | * Some code path such as load_up_fpu or altivec return directly | ||
646 | * here. They run entirely hard disabled and do not alter the | ||
647 | * interrupt state. They also don't use lwarx/stwcx. and thus | ||
648 | * are known not to leave dangling reservations. | ||
649 | */ | ||
650 | .globl fast_exception_return | ||
651 | fast_exception_return: | ||
652 | ld r3,_MSR(r1) | ||
613 | ld r4,_CTR(r1) | 653 | ld r4,_CTR(r1) |
614 | ld r0,_LINK(r1) | 654 | ld r0,_LINK(r1) |
615 | mtctr r4 | 655 | mtctr r4 |
@@ -623,28 +663,18 @@ ALT_FW_FTR_SECTION_END_IFCLR(FW_FEATURE_ISERIES) | |||
623 | beq- unrecov_restore | 663 | beq- unrecov_restore |
624 | 664 | ||
625 | /* | 665 | /* |
626 | * Clear the reservation. If we know the CPU tracks the address of | ||
627 | * the reservation then we can potentially save some cycles and use | ||
628 | * a larx. On POWER6 and POWER7 this is significantly faster. | ||
629 | */ | ||
630 | BEGIN_FTR_SECTION | ||
631 | stdcx. r0,0,r1 /* to clear the reservation */ | ||
632 | FTR_SECTION_ELSE | ||
633 | ldarx r4,0,r1 | ||
634 | ALT_FTR_SECTION_END_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS) | ||
635 | |||
636 | /* | ||
637 | * Clear RI before restoring r13. If we are returning to | 666 | * Clear RI before restoring r13. If we are returning to |
638 | * userspace and we take an exception after restoring r13, | 667 | * userspace and we take an exception after restoring r13, |
639 | * we end up corrupting the userspace r13 value. | 668 | * we end up corrupting the userspace r13 value. |
640 | */ | 669 | */ |
641 | mfmsr r4 | 670 | ld r4,PACAKMSR(r13) /* Get kernel MSR without EE */ |
642 | andc r4,r4,r0 /* r0 contains MSR_RI here */ | 671 | andc r4,r4,r0 /* r0 contains MSR_RI here */ |
643 | mtmsrd r4,1 | 672 | mtmsrd r4,1 |
644 | 673 | ||
645 | /* | 674 | /* |
646 | * r13 is our per cpu area, only restore it if we are returning to | 675 | * r13 is our per cpu area, only restore it if we are returning to |
647 | * userspace | 676 | * userspace the value stored in the stack frame may belong to |
677 | * another CPU. | ||
648 | */ | 678 | */ |
649 | andi. r0,r3,MSR_PR | 679 | andi. r0,r3,MSR_PR |
650 | beq 1f | 680 | beq 1f |
@@ -669,30 +699,55 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_STCX_CHECKS_ADDRESS) | |||
669 | 699 | ||
670 | #endif /* CONFIG_PPC_BOOK3E */ | 700 | #endif /* CONFIG_PPC_BOOK3E */ |
671 | 701 | ||
672 | .Liseries_check_pending_irqs: | 702 | /* |
673 | #ifdef CONFIG_PPC_ISERIES | 703 | * Something did happen, check if a re-emit is needed |
674 | ld r5,SOFTE(r1) | 704 | * (this also clears paca->irq_happened) |
675 | cmpdi 0,r5,0 | 705 | */ |
676 | beq 2b | 706 | restore_check_irq_replay: |
677 | /* Check for pending interrupts (iSeries) */ | 707 | /* XXX: We could implement a fast path here where we check |
678 | ld r3,PACALPPACAPTR(r13) | 708 | * for irq_happened being just 0x01, in which case we can |
679 | ld r3,LPPACAANYINT(r3) | 709 | * clear it and return. That means that we would potentially |
680 | cmpdi r3,0 | 710 | * miss a decrementer having wrapped all the way around. |
681 | beq+ 2b /* skip do_IRQ if no interrupts */ | 711 | * |
682 | 712 | * Still, this might be useful for things like hash_page | |
683 | li r3,0 | 713 | */ |
684 | stb r3,PACASOFTIRQEN(r13) /* ensure we are soft-disabled */ | 714 | bl .__check_irq_replay |
685 | #ifdef CONFIG_TRACE_IRQFLAGS | 715 | cmpwi cr0,r3,0 |
686 | bl .trace_hardirqs_off | 716 | beq restore_no_replay |
687 | mfmsr r10 | 717 | |
688 | #endif | 718 | /* |
689 | ori r10,r10,MSR_EE | 719 | * We need to re-emit an interrupt. We do so by re-using our |
690 | mtmsrd r10 /* hard-enable again */ | 720 | * existing exception frame. We first change the trap value, |
691 | addi r3,r1,STACK_FRAME_OVERHEAD | 721 | * but we need to ensure we preserve the low nibble of it |
692 | bl .do_IRQ | 722 | */ |
693 | b .ret_from_except_lite /* loop back and handle more */ | 723 | ld r4,_TRAP(r1) |
694 | #endif | 724 | clrldi r4,r4,60 |
725 | or r4,r4,r3 | ||
726 | std r4,_TRAP(r1) | ||
695 | 727 | ||
728 | /* | ||
729 | * Then find the right handler and call it. Interrupts are | ||
730 | * still soft-disabled and we keep them that way. | ||
731 | */ | ||
732 | cmpwi cr0,r3,0x500 | ||
733 | bne 1f | ||
734 | addi r3,r1,STACK_FRAME_OVERHEAD; | ||
735 | bl .do_IRQ | ||
736 | b .ret_from_except | ||
737 | 1: cmpwi cr0,r3,0x900 | ||
738 | bne 1f | ||
739 | addi r3,r1,STACK_FRAME_OVERHEAD; | ||
740 | bl .timer_interrupt | ||
741 | b .ret_from_except | ||
742 | #ifdef CONFIG_PPC_BOOK3E | ||
743 | 1: cmpwi cr0,r3,0x280 | ||
744 | bne 1f | ||
745 | addi r3,r1,STACK_FRAME_OVERHEAD; | ||
746 | bl .doorbell_exception | ||
747 | b .ret_from_except | ||
748 | #endif /* CONFIG_PPC_BOOK3E */ | ||
749 | 1: b .ret_from_except /* What else to do here ? */ | ||
750 | |||
696 | do_work: | 751 | do_work: |
697 | #ifdef CONFIG_PREEMPT | 752 | #ifdef CONFIG_PREEMPT |
698 | andi. r0,r3,MSR_PR /* Returning to user mode? */ | 753 | andi. r0,r3,MSR_PR /* Returning to user mode? */ |
@@ -705,31 +760,22 @@ do_work: | |||
705 | crandc eq,cr1*4+eq,eq | 760 | crandc eq,cr1*4+eq,eq |
706 | bne restore | 761 | bne restore |
707 | 762 | ||
708 | /* Here we are preempting the current task. | 763 | /* |
709 | * | 764 | * Here we are preempting the current task. We want to make |
710 | * Ensure interrupts are soft-disabled. We also properly mark | 765 | * sure we are soft-disabled first |
711 | * the PACA to reflect the fact that they are hard-disabled | ||
712 | * and trace the change | ||
713 | */ | 766 | */ |
714 | li r0,0 | 767 | SOFT_DISABLE_INTS(r3,r4) |
715 | stb r0,PACASOFTIRQEN(r13) | ||
716 | stb r0,PACAHARDIRQEN(r13) | ||
717 | TRACE_DISABLE_INTS | ||
718 | |||
719 | /* Call the scheduler with soft IRQs off */ | ||
720 | 1: bl .preempt_schedule_irq | 768 | 1: bl .preempt_schedule_irq |
721 | 769 | ||
722 | /* Hard-disable interrupts again (and update PACA) */ | 770 | /* Hard-disable interrupts again (and update PACA) */ |
723 | #ifdef CONFIG_PPC_BOOK3E | 771 | #ifdef CONFIG_PPC_BOOK3E |
724 | wrteei 0 | 772 | wrteei 0 |
725 | #else | 773 | #else |
726 | mfmsr r10 | 774 | ld r10,PACAKMSR(r13) /* Get kernel MSR without EE */ |
727 | rldicl r10,r10,48,1 | ||
728 | rotldi r10,r10,16 | ||
729 | mtmsrd r10,1 | 775 | mtmsrd r10,1 |
730 | #endif /* CONFIG_PPC_BOOK3E */ | 776 | #endif /* CONFIG_PPC_BOOK3E */ |
731 | li r0,0 | 777 | li r0,PACA_IRQ_HARD_DIS |
732 | stb r0,PACAHARDIRQEN(r13) | 778 | stb r0,PACAIRQHAPPENED(r13) |
733 | 779 | ||
734 | /* Re-test flags and eventually loop */ | 780 | /* Re-test flags and eventually loop */ |
735 | clrrdi r9,r1,THREAD_SHIFT | 781 | clrrdi r9,r1,THREAD_SHIFT |
@@ -751,14 +797,12 @@ user_work: | |||
751 | 797 | ||
752 | andi. r0,r4,_TIF_NEED_RESCHED | 798 | andi. r0,r4,_TIF_NEED_RESCHED |
753 | beq 1f | 799 | beq 1f |
754 | li r5,1 | 800 | bl .restore_interrupts |
755 | TRACE_AND_RESTORE_IRQ(r5); | ||
756 | bl .schedule | 801 | bl .schedule |
757 | b .ret_from_except_lite | 802 | b .ret_from_except_lite |
758 | 803 | ||
759 | 1: bl .save_nvgprs | 804 | 1: bl .save_nvgprs |
760 | li r5,1 | 805 | bl .restore_interrupts |
761 | TRACE_AND_RESTORE_IRQ(r5); | ||
762 | addi r3,r1,STACK_FRAME_OVERHEAD | 806 | addi r3,r1,STACK_FRAME_OVERHEAD |
763 | bl .do_notify_resume | 807 | bl .do_notify_resume |
764 | b .ret_from_except | 808 | b .ret_from_except |
diff --git a/arch/powerpc/kernel/exceptions-64e.S b/arch/powerpc/kernel/exceptions-64e.S index 429983c06f91..7215cc2495df 100644 --- a/arch/powerpc/kernel/exceptions-64e.S +++ b/arch/powerpc/kernel/exceptions-64e.S | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <asm/ptrace.h> | 24 | #include <asm/ptrace.h> |
25 | #include <asm/ppc-opcode.h> | 25 | #include <asm/ppc-opcode.h> |
26 | #include <asm/mmu.h> | 26 | #include <asm/mmu.h> |
27 | #include <asm/hw_irq.h> | ||
27 | 28 | ||
28 | /* XXX This will ultimately add space for a special exception save | 29 | /* XXX This will ultimately add space for a special exception save |
29 | * structure used to save things like SRR0/SRR1, SPRGs, MAS, etc... | 30 | * structure used to save things like SRR0/SRR1, SPRGs, MAS, etc... |
@@ -77,59 +78,55 @@ | |||
77 | #define SPRN_MC_SRR1 SPRN_MCSRR1 | 78 | #define SPRN_MC_SRR1 SPRN_MCSRR1 |
78 | 79 | ||
79 | #define NORMAL_EXCEPTION_PROLOG(n, addition) \ | 80 | #define NORMAL_EXCEPTION_PROLOG(n, addition) \ |
80 | EXCEPTION_PROLOG(n, GEN, addition##_GEN) | 81 | EXCEPTION_PROLOG(n, GEN, addition##_GEN(n)) |
81 | 82 | ||
82 | #define CRIT_EXCEPTION_PROLOG(n, addition) \ | 83 | #define CRIT_EXCEPTION_PROLOG(n, addition) \ |
83 | EXCEPTION_PROLOG(n, CRIT, addition##_CRIT) | 84 | EXCEPTION_PROLOG(n, CRIT, addition##_CRIT(n)) |
84 | 85 | ||
85 | #define DBG_EXCEPTION_PROLOG(n, addition) \ | 86 | #define DBG_EXCEPTION_PROLOG(n, addition) \ |
86 | EXCEPTION_PROLOG(n, DBG, addition##_DBG) | 87 | EXCEPTION_PROLOG(n, DBG, addition##_DBG(n)) |
87 | 88 | ||
88 | #define MC_EXCEPTION_PROLOG(n, addition) \ | 89 | #define MC_EXCEPTION_PROLOG(n, addition) \ |
89 | EXCEPTION_PROLOG(n, MC, addition##_MC) | 90 | EXCEPTION_PROLOG(n, MC, addition##_MC(n)) |
90 | 91 | ||
91 | 92 | ||
92 | /* Variants of the "addition" argument for the prolog | 93 | /* Variants of the "addition" argument for the prolog |
93 | */ | 94 | */ |
94 | #define PROLOG_ADDITION_NONE_GEN | 95 | #define PROLOG_ADDITION_NONE_GEN(n) |
95 | #define PROLOG_ADDITION_NONE_CRIT | 96 | #define PROLOG_ADDITION_NONE_CRIT(n) |
96 | #define PROLOG_ADDITION_NONE_DBG | 97 | #define PROLOG_ADDITION_NONE_DBG(n) |
97 | #define PROLOG_ADDITION_NONE_MC | 98 | #define PROLOG_ADDITION_NONE_MC(n) |
98 | 99 | ||
99 | #define PROLOG_ADDITION_MASKABLE_GEN \ | 100 | #define PROLOG_ADDITION_MASKABLE_GEN(n) \ |
100 | lbz r11,PACASOFTIRQEN(r13); /* are irqs soft-disabled ? */ \ | 101 | lbz r11,PACASOFTIRQEN(r13); /* are irqs soft-disabled ? */ \ |
101 | cmpwi cr0,r11,0; /* yes -> go out of line */ \ | 102 | cmpwi cr0,r11,0; /* yes -> go out of line */ \ |
102 | beq masked_interrupt_book3e; | 103 | beq masked_interrupt_book3e_##n |
103 | 104 | ||
104 | #define PROLOG_ADDITION_2REGS_GEN \ | 105 | #define PROLOG_ADDITION_2REGS_GEN(n) \ |
105 | std r14,PACA_EXGEN+EX_R14(r13); \ | 106 | std r14,PACA_EXGEN+EX_R14(r13); \ |
106 | std r15,PACA_EXGEN+EX_R15(r13) | 107 | std r15,PACA_EXGEN+EX_R15(r13) |
107 | 108 | ||
108 | #define PROLOG_ADDITION_1REG_GEN \ | 109 | #define PROLOG_ADDITION_1REG_GEN(n) \ |
109 | std r14,PACA_EXGEN+EX_R14(r13); | 110 | std r14,PACA_EXGEN+EX_R14(r13); |
110 | 111 | ||
111 | #define PROLOG_ADDITION_2REGS_CRIT \ | 112 | #define PROLOG_ADDITION_2REGS_CRIT(n) \ |
112 | std r14,PACA_EXCRIT+EX_R14(r13); \ | 113 | std r14,PACA_EXCRIT+EX_R14(r13); \ |
113 | std r15,PACA_EXCRIT+EX_R15(r13) | 114 | std r15,PACA_EXCRIT+EX_R15(r13) |
114 | 115 | ||
115 | #define PROLOG_ADDITION_2REGS_DBG \ | 116 | #define PROLOG_ADDITION_2REGS_DBG(n) \ |
116 | std r14,PACA_EXDBG+EX_R14(r13); \ | 117 | std r14,PACA_EXDBG+EX_R14(r13); \ |
117 | std r15,PACA_EXDBG+EX_R15(r13) | 118 | std r15,PACA_EXDBG+EX_R15(r13) |
118 | 119 | ||
119 | #define PROLOG_ADDITION_2REGS_MC \ | 120 | #define PROLOG_ADDITION_2REGS_MC(n) \ |
120 | std r14,PACA_EXMC+EX_R14(r13); \ | 121 | std r14,PACA_EXMC+EX_R14(r13); \ |
121 | std r15,PACA_EXMC+EX_R15(r13) | 122 | std r15,PACA_EXMC+EX_R15(r13) |
122 | 123 | ||
123 | #define PROLOG_ADDITION_DOORBELL_GEN \ | ||
124 | lbz r11,PACASOFTIRQEN(r13); /* are irqs soft-disabled ? */ \ | ||
125 | cmpwi cr0,r11,0; /* yes -> go out of line */ \ | ||
126 | beq masked_doorbell_book3e | ||
127 | |||
128 | 124 | ||
129 | /* Core exception code for all exceptions except TLB misses. | 125 | /* Core exception code for all exceptions except TLB misses. |
130 | * XXX: Needs to make SPRN_SPRG_GEN depend on exception type | 126 | * XXX: Needs to make SPRN_SPRG_GEN depend on exception type |
131 | */ | 127 | */ |
132 | #define EXCEPTION_COMMON(n, excf, ints) \ | 128 | #define EXCEPTION_COMMON(n, excf, ints) \ |
129 | exc_##n##_common: \ | ||
133 | std r0,GPR0(r1); /* save r0 in stackframe */ \ | 130 | std r0,GPR0(r1); /* save r0 in stackframe */ \ |
134 | std r2,GPR2(r1); /* save r2 in stackframe */ \ | 131 | std r2,GPR2(r1); /* save r2 in stackframe */ \ |
135 | SAVE_4GPRS(3, r1); /* save r3 - r6 in stackframe */ \ | 132 | SAVE_4GPRS(3, r1); /* save r3 - r6 in stackframe */ \ |
@@ -167,20 +164,21 @@ | |||
167 | std r0,RESULT(r1); /* clear regs->result */ \ | 164 | std r0,RESULT(r1); /* clear regs->result */ \ |
168 | ints; | 165 | ints; |
169 | 166 | ||
170 | /* Variants for the "ints" argument */ | 167 | /* Variants for the "ints" argument. This one does nothing when we want |
168 | * to keep interrupts in their original state | ||
169 | */ | ||
171 | #define INTS_KEEP | 170 | #define INTS_KEEP |
172 | #define INTS_DISABLE_SOFT \ | 171 | |
173 | stb r0,PACASOFTIRQEN(r13); /* mark interrupts soft-disabled */ \ | 172 | /* This second version is meant for exceptions that don't immediately |
174 | TRACE_DISABLE_INTS; | 173 | * hard-enable. We set a bit in paca->irq_happened to ensure that |
175 | #define INTS_DISABLE_HARD \ | 174 | * a subsequent call to arch_local_irq_restore() will properly |
176 | stb r0,PACAHARDIRQEN(r13); /* and hard disabled */ | 175 | * hard-enable and avoid the fast-path |
177 | #define INTS_DISABLE_ALL \ | 176 | */ |
178 | INTS_DISABLE_SOFT \ | 177 | #define INTS_DISABLE SOFT_DISABLE_INTS(r3,r4) |
179 | INTS_DISABLE_HARD | 178 | |
180 | 179 | /* This is called by exceptions that used INTS_KEEP (that did not touch | |
181 | /* This is called by exceptions that used INTS_KEEP (that is did not clear | 180 | * irq indicators in the PACA). This will restore MSR:EE to it's previous |
182 | * neither soft nor hard IRQ indicators in the PACA. This will restore MSR:EE | 181 | * value |
183 | * to it's previous value | ||
184 | * | 182 | * |
185 | * XXX In the long run, we may want to open-code it in order to separate the | 183 | * XXX In the long run, we may want to open-code it in order to separate the |
186 | * load from the wrtee, thus limiting the latency caused by the dependency | 184 | * load from the wrtee, thus limiting the latency caused by the dependency |
@@ -238,7 +236,7 @@ exc_##n##_bad_stack: \ | |||
238 | #define MASKABLE_EXCEPTION(trapnum, label, hdlr, ack) \ | 236 | #define MASKABLE_EXCEPTION(trapnum, label, hdlr, ack) \ |
239 | START_EXCEPTION(label); \ | 237 | START_EXCEPTION(label); \ |
240 | NORMAL_EXCEPTION_PROLOG(trapnum, PROLOG_ADDITION_MASKABLE) \ | 238 | NORMAL_EXCEPTION_PROLOG(trapnum, PROLOG_ADDITION_MASKABLE) \ |
241 | EXCEPTION_COMMON(trapnum, PACA_EXGEN, INTS_DISABLE_ALL) \ | 239 | EXCEPTION_COMMON(trapnum, PACA_EXGEN, INTS_DISABLE) \ |
242 | ack(r8); \ | 240 | ack(r8); \ |
243 | CHECK_NAPPING(); \ | 241 | CHECK_NAPPING(); \ |
244 | addi r3,r1,STACK_FRAME_OVERHEAD; \ | 242 | addi r3,r1,STACK_FRAME_OVERHEAD; \ |
@@ -289,7 +287,7 @@ interrupt_end_book3e: | |||
289 | /* Critical Input Interrupt */ | 287 | /* Critical Input Interrupt */ |
290 | START_EXCEPTION(critical_input); | 288 | START_EXCEPTION(critical_input); |
291 | CRIT_EXCEPTION_PROLOG(0x100, PROLOG_ADDITION_NONE) | 289 | CRIT_EXCEPTION_PROLOG(0x100, PROLOG_ADDITION_NONE) |
292 | // EXCEPTION_COMMON(0x100, PACA_EXCRIT, INTS_DISABLE_ALL) | 290 | // EXCEPTION_COMMON(0x100, PACA_EXCRIT, INTS_DISABLE) |
293 | // bl special_reg_save_crit | 291 | // bl special_reg_save_crit |
294 | // CHECK_NAPPING(); | 292 | // CHECK_NAPPING(); |
295 | // addi r3,r1,STACK_FRAME_OVERHEAD | 293 | // addi r3,r1,STACK_FRAME_OVERHEAD |
@@ -300,7 +298,7 @@ interrupt_end_book3e: | |||
300 | /* Machine Check Interrupt */ | 298 | /* Machine Check Interrupt */ |
301 | START_EXCEPTION(machine_check); | 299 | START_EXCEPTION(machine_check); |
302 | CRIT_EXCEPTION_PROLOG(0x200, PROLOG_ADDITION_NONE) | 300 | CRIT_EXCEPTION_PROLOG(0x200, PROLOG_ADDITION_NONE) |
303 | // EXCEPTION_COMMON(0x200, PACA_EXMC, INTS_DISABLE_ALL) | 301 | // EXCEPTION_COMMON(0x200, PACA_EXMC, INTS_DISABLE) |
304 | // bl special_reg_save_mc | 302 | // bl special_reg_save_mc |
305 | // addi r3,r1,STACK_FRAME_OVERHEAD | 303 | // addi r3,r1,STACK_FRAME_OVERHEAD |
306 | // CHECK_NAPPING(); | 304 | // CHECK_NAPPING(); |
@@ -313,7 +311,7 @@ interrupt_end_book3e: | |||
313 | NORMAL_EXCEPTION_PROLOG(0x300, PROLOG_ADDITION_2REGS) | 311 | NORMAL_EXCEPTION_PROLOG(0x300, PROLOG_ADDITION_2REGS) |
314 | mfspr r14,SPRN_DEAR | 312 | mfspr r14,SPRN_DEAR |
315 | mfspr r15,SPRN_ESR | 313 | mfspr r15,SPRN_ESR |
316 | EXCEPTION_COMMON(0x300, PACA_EXGEN, INTS_KEEP) | 314 | EXCEPTION_COMMON(0x300, PACA_EXGEN, INTS_DISABLE) |
317 | b storage_fault_common | 315 | b storage_fault_common |
318 | 316 | ||
319 | /* Instruction Storage Interrupt */ | 317 | /* Instruction Storage Interrupt */ |
@@ -321,7 +319,7 @@ interrupt_end_book3e: | |||
321 | NORMAL_EXCEPTION_PROLOG(0x400, PROLOG_ADDITION_2REGS) | 319 | NORMAL_EXCEPTION_PROLOG(0x400, PROLOG_ADDITION_2REGS) |
322 | li r15,0 | 320 | li r15,0 |
323 | mr r14,r10 | 321 | mr r14,r10 |
324 | EXCEPTION_COMMON(0x400, PACA_EXGEN, INTS_KEEP) | 322 | EXCEPTION_COMMON(0x400, PACA_EXGEN, INTS_DISABLE) |
325 | b storage_fault_common | 323 | b storage_fault_common |
326 | 324 | ||
327 | /* External Input Interrupt */ | 325 | /* External Input Interrupt */ |
@@ -339,12 +337,11 @@ interrupt_end_book3e: | |||
339 | START_EXCEPTION(program); | 337 | START_EXCEPTION(program); |
340 | NORMAL_EXCEPTION_PROLOG(0x700, PROLOG_ADDITION_1REG) | 338 | NORMAL_EXCEPTION_PROLOG(0x700, PROLOG_ADDITION_1REG) |
341 | mfspr r14,SPRN_ESR | 339 | mfspr r14,SPRN_ESR |
342 | EXCEPTION_COMMON(0x700, PACA_EXGEN, INTS_DISABLE_SOFT) | 340 | EXCEPTION_COMMON(0x700, PACA_EXGEN, INTS_DISABLE) |
343 | std r14,_DSISR(r1) | 341 | std r14,_DSISR(r1) |
344 | addi r3,r1,STACK_FRAME_OVERHEAD | 342 | addi r3,r1,STACK_FRAME_OVERHEAD |
345 | ld r14,PACA_EXGEN+EX_R14(r13) | 343 | ld r14,PACA_EXGEN+EX_R14(r13) |
346 | bl .save_nvgprs | 344 | bl .save_nvgprs |
347 | INTS_RESTORE_HARD | ||
348 | bl .program_check_exception | 345 | bl .program_check_exception |
349 | b .ret_from_except | 346 | b .ret_from_except |
350 | 347 | ||
@@ -353,15 +350,16 @@ interrupt_end_book3e: | |||
353 | NORMAL_EXCEPTION_PROLOG(0x800, PROLOG_ADDITION_NONE) | 350 | NORMAL_EXCEPTION_PROLOG(0x800, PROLOG_ADDITION_NONE) |
354 | /* we can probably do a shorter exception entry for that one... */ | 351 | /* we can probably do a shorter exception entry for that one... */ |
355 | EXCEPTION_COMMON(0x800, PACA_EXGEN, INTS_KEEP) | 352 | EXCEPTION_COMMON(0x800, PACA_EXGEN, INTS_KEEP) |
356 | bne 1f /* if from user, just load it up */ | 353 | ld r12,_MSR(r1) |
354 | andi. r0,r12,MSR_PR; | ||
355 | beq- 1f | ||
356 | bl .load_up_fpu | ||
357 | b fast_exception_return | ||
358 | 1: INTS_DISABLE | ||
357 | bl .save_nvgprs | 359 | bl .save_nvgprs |
358 | addi r3,r1,STACK_FRAME_OVERHEAD | 360 | addi r3,r1,STACK_FRAME_OVERHEAD |
359 | INTS_RESTORE_HARD | ||
360 | bl .kernel_fp_unavailable_exception | 361 | bl .kernel_fp_unavailable_exception |
361 | BUG_OPCODE | 362 | b .ret_from_except |
362 | 1: ld r12,_MSR(r1) | ||
363 | bl .load_up_fpu | ||
364 | b fast_exception_return | ||
365 | 363 | ||
366 | /* Decrementer Interrupt */ | 364 | /* Decrementer Interrupt */ |
367 | MASKABLE_EXCEPTION(0x900, decrementer, .timer_interrupt, ACK_DEC) | 365 | MASKABLE_EXCEPTION(0x900, decrementer, .timer_interrupt, ACK_DEC) |
@@ -372,7 +370,7 @@ interrupt_end_book3e: | |||
372 | /* Watchdog Timer Interrupt */ | 370 | /* Watchdog Timer Interrupt */ |
373 | START_EXCEPTION(watchdog); | 371 | START_EXCEPTION(watchdog); |
374 | CRIT_EXCEPTION_PROLOG(0x9f0, PROLOG_ADDITION_NONE) | 372 | CRIT_EXCEPTION_PROLOG(0x9f0, PROLOG_ADDITION_NONE) |
375 | // EXCEPTION_COMMON(0x9f0, PACA_EXCRIT, INTS_DISABLE_ALL) | 373 | // EXCEPTION_COMMON(0x9f0, PACA_EXCRIT, INTS_DISABLE) |
376 | // bl special_reg_save_crit | 374 | // bl special_reg_save_crit |
377 | // CHECK_NAPPING(); | 375 | // CHECK_NAPPING(); |
378 | // addi r3,r1,STACK_FRAME_OVERHEAD | 376 | // addi r3,r1,STACK_FRAME_OVERHEAD |
@@ -391,10 +389,9 @@ interrupt_end_book3e: | |||
391 | /* Auxiliary Processor Unavailable Interrupt */ | 389 | /* Auxiliary Processor Unavailable Interrupt */ |
392 | START_EXCEPTION(ap_unavailable); | 390 | START_EXCEPTION(ap_unavailable); |
393 | NORMAL_EXCEPTION_PROLOG(0xf20, PROLOG_ADDITION_NONE) | 391 | NORMAL_EXCEPTION_PROLOG(0xf20, PROLOG_ADDITION_NONE) |
394 | EXCEPTION_COMMON(0xf20, PACA_EXGEN, INTS_KEEP) | 392 | EXCEPTION_COMMON(0xf20, PACA_EXGEN, INTS_DISABLE) |
395 | addi r3,r1,STACK_FRAME_OVERHEAD | ||
396 | bl .save_nvgprs | 393 | bl .save_nvgprs |
397 | INTS_RESTORE_HARD | 394 | addi r3,r1,STACK_FRAME_OVERHEAD |
398 | bl .unknown_exception | 395 | bl .unknown_exception |
399 | b .ret_from_except | 396 | b .ret_from_except |
400 | 397 | ||
@@ -450,7 +447,7 @@ interrupt_end_book3e: | |||
450 | mfspr r15,SPRN_SPRG_CRIT_SCRATCH | 447 | mfspr r15,SPRN_SPRG_CRIT_SCRATCH |
451 | mtspr SPRN_SPRG_GEN_SCRATCH,r15 | 448 | mtspr SPRN_SPRG_GEN_SCRATCH,r15 |
452 | mfspr r14,SPRN_DBSR | 449 | mfspr r14,SPRN_DBSR |
453 | EXCEPTION_COMMON(0xd00, PACA_EXCRIT, INTS_DISABLE_ALL) | 450 | EXCEPTION_COMMON(0xd00, PACA_EXCRIT, INTS_DISABLE) |
454 | std r14,_DSISR(r1) | 451 | std r14,_DSISR(r1) |
455 | addi r3,r1,STACK_FRAME_OVERHEAD | 452 | addi r3,r1,STACK_FRAME_OVERHEAD |
456 | mr r4,r14 | 453 | mr r4,r14 |
@@ -465,7 +462,7 @@ kernel_dbg_exc: | |||
465 | 462 | ||
466 | /* Debug exception as a debug interrupt*/ | 463 | /* Debug exception as a debug interrupt*/ |
467 | START_EXCEPTION(debug_debug); | 464 | START_EXCEPTION(debug_debug); |
468 | DBG_EXCEPTION_PROLOG(0xd00, PROLOG_ADDITION_2REGS) | 465 | DBG_EXCEPTION_PROLOG(0xd08, PROLOG_ADDITION_2REGS) |
469 | 466 | ||
470 | /* | 467 | /* |
471 | * If there is a single step or branch-taken exception in an | 468 | * If there is a single step or branch-taken exception in an |
@@ -515,7 +512,7 @@ kernel_dbg_exc: | |||
515 | mfspr r15,SPRN_SPRG_DBG_SCRATCH | 512 | mfspr r15,SPRN_SPRG_DBG_SCRATCH |
516 | mtspr SPRN_SPRG_GEN_SCRATCH,r15 | 513 | mtspr SPRN_SPRG_GEN_SCRATCH,r15 |
517 | mfspr r14,SPRN_DBSR | 514 | mfspr r14,SPRN_DBSR |
518 | EXCEPTION_COMMON(0xd00, PACA_EXDBG, INTS_DISABLE_ALL) | 515 | EXCEPTION_COMMON(0xd08, PACA_EXDBG, INTS_DISABLE) |
519 | std r14,_DSISR(r1) | 516 | std r14,_DSISR(r1) |
520 | addi r3,r1,STACK_FRAME_OVERHEAD | 517 | addi r3,r1,STACK_FRAME_OVERHEAD |
521 | mr r4,r14 | 518 | mr r4,r14 |
@@ -525,21 +522,20 @@ kernel_dbg_exc: | |||
525 | bl .DebugException | 522 | bl .DebugException |
526 | b .ret_from_except | 523 | b .ret_from_except |
527 | 524 | ||
528 | MASKABLE_EXCEPTION(0x260, perfmon, .performance_monitor_exception, ACK_NONE) | 525 | START_EXCEPTION(perfmon); |
529 | 526 | NORMAL_EXCEPTION_PROLOG(0x260, PROLOG_ADDITION_NONE) | |
530 | /* Doorbell interrupt */ | 527 | EXCEPTION_COMMON(0x260, PACA_EXGEN, INTS_DISABLE) |
531 | START_EXCEPTION(doorbell) | ||
532 | NORMAL_EXCEPTION_PROLOG(0x2070, PROLOG_ADDITION_DOORBELL) | ||
533 | EXCEPTION_COMMON(0x2070, PACA_EXGEN, INTS_DISABLE_ALL) | ||
534 | CHECK_NAPPING() | ||
535 | addi r3,r1,STACK_FRAME_OVERHEAD | 528 | addi r3,r1,STACK_FRAME_OVERHEAD |
536 | bl .doorbell_exception | 529 | bl .performance_monitor_exception |
537 | b .ret_from_except_lite | 530 | b .ret_from_except_lite |
538 | 531 | ||
532 | /* Doorbell interrupt */ | ||
533 | MASKABLE_EXCEPTION(0x280, doorbell, .doorbell_exception, ACK_NONE) | ||
534 | |||
539 | /* Doorbell critical Interrupt */ | 535 | /* Doorbell critical Interrupt */ |
540 | START_EXCEPTION(doorbell_crit); | 536 | START_EXCEPTION(doorbell_crit); |
541 | CRIT_EXCEPTION_PROLOG(0x2080, PROLOG_ADDITION_NONE) | 537 | CRIT_EXCEPTION_PROLOG(0x2a0, PROLOG_ADDITION_NONE) |
542 | // EXCEPTION_COMMON(0x2080, PACA_EXCRIT, INTS_DISABLE_ALL) | 538 | // EXCEPTION_COMMON(0x2a0, PACA_EXCRIT, INTS_DISABLE) |
543 | // bl special_reg_save_crit | 539 | // bl special_reg_save_crit |
544 | // CHECK_NAPPING(); | 540 | // CHECK_NAPPING(); |
545 | // addi r3,r1,STACK_FRAME_OVERHEAD | 541 | // addi r3,r1,STACK_FRAME_OVERHEAD |
@@ -547,36 +543,114 @@ kernel_dbg_exc: | |||
547 | // b ret_from_crit_except | 543 | // b ret_from_crit_except |
548 | b . | 544 | b . |
549 | 545 | ||
546 | /* Guest Doorbell */ | ||
550 | MASKABLE_EXCEPTION(0x2c0, guest_doorbell, .unknown_exception, ACK_NONE) | 547 | MASKABLE_EXCEPTION(0x2c0, guest_doorbell, .unknown_exception, ACK_NONE) |
551 | MASKABLE_EXCEPTION(0x2e0, guest_doorbell_crit, .unknown_exception, ACK_NONE) | ||
552 | MASKABLE_EXCEPTION(0x310, hypercall, .unknown_exception, ACK_NONE) | ||
553 | MASKABLE_EXCEPTION(0x320, ehpriv, .unknown_exception, ACK_NONE) | ||
554 | 548 | ||
549 | /* Guest Doorbell critical Interrupt */ | ||
550 | START_EXCEPTION(guest_doorbell_crit); | ||
551 | CRIT_EXCEPTION_PROLOG(0x2e0, PROLOG_ADDITION_NONE) | ||
552 | // EXCEPTION_COMMON(0x2e0, PACA_EXCRIT, INTS_DISABLE) | ||
553 | // bl special_reg_save_crit | ||
554 | // CHECK_NAPPING(); | ||
555 | // addi r3,r1,STACK_FRAME_OVERHEAD | ||
556 | // bl .guest_doorbell_critical_exception | ||
557 | // b ret_from_crit_except | ||
558 | b . | ||
559 | |||
560 | /* Hypervisor call */ | ||
561 | START_EXCEPTION(hypercall); | ||
562 | NORMAL_EXCEPTION_PROLOG(0x310, PROLOG_ADDITION_NONE) | ||
563 | EXCEPTION_COMMON(0x310, PACA_EXGEN, INTS_KEEP) | ||
564 | addi r3,r1,STACK_FRAME_OVERHEAD | ||
565 | bl .save_nvgprs | ||
566 | INTS_RESTORE_HARD | ||
567 | bl .unknown_exception | ||
568 | b .ret_from_except | ||
569 | |||
570 | /* Embedded Hypervisor priviledged */ | ||
571 | START_EXCEPTION(ehpriv); | ||
572 | NORMAL_EXCEPTION_PROLOG(0x320, PROLOG_ADDITION_NONE) | ||
573 | EXCEPTION_COMMON(0x320, PACA_EXGEN, INTS_KEEP) | ||
574 | addi r3,r1,STACK_FRAME_OVERHEAD | ||
575 | bl .save_nvgprs | ||
576 | INTS_RESTORE_HARD | ||
577 | bl .unknown_exception | ||
578 | b .ret_from_except | ||
555 | 579 | ||
556 | /* | 580 | /* |
557 | * An interrupt came in while soft-disabled; clear EE in SRR1, | 581 | * An interrupt came in while soft-disabled; We mark paca->irq_happened |
558 | * clear paca->hard_enabled and return. | 582 | * accordingly and if the interrupt is level sensitive, we hard disable |
559 | */ | 583 | */ |
560 | masked_doorbell_book3e: | ||
561 | mtcr r10 | ||
562 | /* Resend the doorbell to fire again when ints enabled */ | ||
563 | mfspr r10,SPRN_PIR | ||
564 | PPC_MSGSND(r10) | ||
565 | b masked_interrupt_book3e_common | ||
566 | 584 | ||
567 | masked_interrupt_book3e: | 585 | masked_interrupt_book3e_0x500: |
586 | /* XXX When adding support for EPR, use PACA_IRQ_EE_EDGE */ | ||
587 | li r11,PACA_IRQ_EE | ||
588 | b masked_interrupt_book3e_full_mask | ||
589 | |||
590 | masked_interrupt_book3e_0x900: | ||
591 | ACK_DEC(r11); | ||
592 | li r11,PACA_IRQ_DEC | ||
593 | b masked_interrupt_book3e_no_mask | ||
594 | masked_interrupt_book3e_0x980: | ||
595 | ACK_FIT(r11); | ||
596 | li r11,PACA_IRQ_DEC | ||
597 | b masked_interrupt_book3e_no_mask | ||
598 | masked_interrupt_book3e_0x280: | ||
599 | masked_interrupt_book3e_0x2c0: | ||
600 | li r11,PACA_IRQ_DBELL | ||
601 | b masked_interrupt_book3e_no_mask | ||
602 | |||
603 | masked_interrupt_book3e_no_mask: | ||
604 | mtcr r10 | ||
605 | lbz r10,PACAIRQHAPPENED(r13) | ||
606 | or r10,r10,r11 | ||
607 | stb r10,PACAIRQHAPPENED(r13) | ||
608 | b 1f | ||
609 | masked_interrupt_book3e_full_mask: | ||
568 | mtcr r10 | 610 | mtcr r10 |
569 | masked_interrupt_book3e_common: | 611 | lbz r10,PACAIRQHAPPENED(r13) |
570 | stb r11,PACAHARDIRQEN(r13) | 612 | or r10,r10,r11 |
613 | stb r10,PACAIRQHAPPENED(r13) | ||
571 | mfspr r10,SPRN_SRR1 | 614 | mfspr r10,SPRN_SRR1 |
572 | rldicl r11,r10,48,1 /* clear MSR_EE */ | 615 | rldicl r11,r10,48,1 /* clear MSR_EE */ |
573 | rotldi r10,r11,16 | 616 | rotldi r10,r11,16 |
574 | mtspr SPRN_SRR1,r10 | 617 | mtspr SPRN_SRR1,r10 |
575 | ld r10,PACA_EXGEN+EX_R10(r13); /* restore registers */ | 618 | 1: ld r10,PACA_EXGEN+EX_R10(r13); |
576 | ld r11,PACA_EXGEN+EX_R11(r13); | 619 | ld r11,PACA_EXGEN+EX_R11(r13); |
577 | mfspr r13,SPRN_SPRG_GEN_SCRATCH; | 620 | mfspr r13,SPRN_SPRG_GEN_SCRATCH; |
578 | rfi | 621 | rfi |
579 | b . | 622 | b . |
623 | /* | ||
624 | * Called from arch_local_irq_enable when an interrupt needs | ||
625 | * to be resent. r3 contains either 0x500,0x900,0x260 or 0x280 | ||
626 | * to indicate the kind of interrupt. MSR:EE is already off. | ||
627 | * We generate a stackframe like if a real interrupt had happened. | ||
628 | * | ||
629 | * Note: While MSR:EE is off, we need to make sure that _MSR | ||
630 | * in the generated frame has EE set to 1 or the exception | ||
631 | * handler will not properly re-enable them. | ||
632 | */ | ||
633 | _GLOBAL(__replay_interrupt) | ||
634 | /* We are going to jump to the exception common code which | ||
635 | * will retrieve various register values from the PACA which | ||
636 | * we don't give a damn about. | ||
637 | */ | ||
638 | mflr r10 | ||
639 | mfmsr r11 | ||
640 | mfcr r4 | ||
641 | mtspr SPRN_SPRG_GEN_SCRATCH,r13; | ||
642 | std r1,PACA_EXGEN+EX_R1(r13); | ||
643 | stw r4,PACA_EXGEN+EX_CR(r13); | ||
644 | ori r11,r11,MSR_EE | ||
645 | subi r1,r1,INT_FRAME_SIZE; | ||
646 | cmpwi cr0,r3,0x500 | ||
647 | beq exc_0x500_common | ||
648 | cmpwi cr0,r3,0x900 | ||
649 | beq exc_0x900_common | ||
650 | cmpwi cr0,r3,0x280 | ||
651 | beq exc_0x280_common | ||
652 | blr | ||
653 | |||
580 | 654 | ||
581 | /* | 655 | /* |
582 | * This is called from 0x300 and 0x400 handlers after the prologs with | 656 | * This is called from 0x300 and 0x400 handlers after the prologs with |
@@ -591,7 +665,6 @@ storage_fault_common: | |||
591 | mr r5,r15 | 665 | mr r5,r15 |
592 | ld r14,PACA_EXGEN+EX_R14(r13) | 666 | ld r14,PACA_EXGEN+EX_R14(r13) |
593 | ld r15,PACA_EXGEN+EX_R15(r13) | 667 | ld r15,PACA_EXGEN+EX_R15(r13) |
594 | INTS_RESTORE_HARD | ||
595 | bl .do_page_fault | 668 | bl .do_page_fault |
596 | cmpdi r3,0 | 669 | cmpdi r3,0 |
597 | bne- 1f | 670 | bne- 1f |
@@ -680,6 +753,8 @@ BAD_STACK_TRAMPOLINE(0x000) | |||
680 | BAD_STACK_TRAMPOLINE(0x100) | 753 | BAD_STACK_TRAMPOLINE(0x100) |
681 | BAD_STACK_TRAMPOLINE(0x200) | 754 | BAD_STACK_TRAMPOLINE(0x200) |
682 | BAD_STACK_TRAMPOLINE(0x260) | 755 | BAD_STACK_TRAMPOLINE(0x260) |
756 | BAD_STACK_TRAMPOLINE(0x280) | ||
757 | BAD_STACK_TRAMPOLINE(0x2a0) | ||
683 | BAD_STACK_TRAMPOLINE(0x2c0) | 758 | BAD_STACK_TRAMPOLINE(0x2c0) |
684 | BAD_STACK_TRAMPOLINE(0x2e0) | 759 | BAD_STACK_TRAMPOLINE(0x2e0) |
685 | BAD_STACK_TRAMPOLINE(0x300) | 760 | BAD_STACK_TRAMPOLINE(0x300) |
@@ -697,11 +772,10 @@ BAD_STACK_TRAMPOLINE(0xa00) | |||
697 | BAD_STACK_TRAMPOLINE(0xb00) | 772 | BAD_STACK_TRAMPOLINE(0xb00) |
698 | BAD_STACK_TRAMPOLINE(0xc00) | 773 | BAD_STACK_TRAMPOLINE(0xc00) |
699 | BAD_STACK_TRAMPOLINE(0xd00) | 774 | BAD_STACK_TRAMPOLINE(0xd00) |
775 | BAD_STACK_TRAMPOLINE(0xd08) | ||
700 | BAD_STACK_TRAMPOLINE(0xe00) | 776 | BAD_STACK_TRAMPOLINE(0xe00) |
701 | BAD_STACK_TRAMPOLINE(0xf00) | 777 | BAD_STACK_TRAMPOLINE(0xf00) |
702 | BAD_STACK_TRAMPOLINE(0xf20) | 778 | BAD_STACK_TRAMPOLINE(0xf20) |
703 | BAD_STACK_TRAMPOLINE(0x2070) | ||
704 | BAD_STACK_TRAMPOLINE(0x2080) | ||
705 | 779 | ||
706 | .globl bad_stack_book3e | 780 | .globl bad_stack_book3e |
707 | bad_stack_book3e: | 781 | bad_stack_book3e: |
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 15c5a4f6de01..2d0868a4e2f0 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S | |||
@@ -12,6 +12,7 @@ | |||
12 | * | 12 | * |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <asm/hw_irq.h> | ||
15 | #include <asm/exception-64s.h> | 16 | #include <asm/exception-64s.h> |
16 | #include <asm/ptrace.h> | 17 | #include <asm/ptrace.h> |
17 | 18 | ||
@@ -19,7 +20,7 @@ | |||
19 | * We layout physical memory as follows: | 20 | * We layout physical memory as follows: |
20 | * 0x0000 - 0x00ff : Secondary processor spin code | 21 | * 0x0000 - 0x00ff : Secondary processor spin code |
21 | * 0x0100 - 0x2fff : pSeries Interrupt prologs | 22 | * 0x0100 - 0x2fff : pSeries Interrupt prologs |
22 | * 0x3000 - 0x5fff : interrupt support, iSeries and common interrupt prologs | 23 | * 0x3000 - 0x5fff : interrupt support common interrupt prologs |
23 | * 0x6000 - 0x6fff : Initial (CPU0) segment table | 24 | * 0x6000 - 0x6fff : Initial (CPU0) segment table |
24 | * 0x7000 - 0x7fff : FWNMI data area | 25 | * 0x7000 - 0x7fff : FWNMI data area |
25 | * 0x8000 - : Early init and support code | 26 | * 0x8000 - : Early init and support code |
@@ -356,34 +357,60 @@ do_stab_bolted_pSeries: | |||
356 | KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0xf40) | 357 | KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0xf40) |
357 | 358 | ||
358 | /* | 359 | /* |
359 | * An interrupt came in while soft-disabled; clear EE in SRR1, | 360 | * An interrupt came in while soft-disabled. We set paca->irq_happened, |
360 | * clear paca->hard_enabled and return. | 361 | * then, if it was a decrementer interrupt, we bump the dec to max and |
362 | * and return, else we hard disable and return. This is called with | ||
363 | * r10 containing the value to OR to the paca field. | ||
361 | */ | 364 | */ |
362 | masked_interrupt: | 365 | #define MASKED_INTERRUPT(_H) \ |
363 | stb r10,PACAHARDIRQEN(r13) | 366 | masked_##_H##interrupt: \ |
364 | mtcrf 0x80,r9 | 367 | std r11,PACA_EXGEN+EX_R11(r13); \ |
365 | ld r9,PACA_EXGEN+EX_R9(r13) | 368 | lbz r11,PACAIRQHAPPENED(r13); \ |
366 | mfspr r10,SPRN_SRR1 | 369 | or r11,r11,r10; \ |
367 | rldicl r10,r10,48,1 /* clear MSR_EE */ | 370 | stb r11,PACAIRQHAPPENED(r13); \ |
368 | rotldi r10,r10,16 | 371 | andi. r10,r10,PACA_IRQ_DEC; \ |
369 | mtspr SPRN_SRR1,r10 | 372 | beq 1f; \ |
370 | ld r10,PACA_EXGEN+EX_R10(r13) | 373 | lis r10,0x7fff; \ |
371 | GET_SCRATCH0(r13) | 374 | ori r10,r10,0xffff; \ |
372 | rfid | 375 | mtspr SPRN_DEC,r10; \ |
376 | b 2f; \ | ||
377 | 1: mfspr r10,SPRN_##_H##SRR1; \ | ||
378 | rldicl r10,r10,48,1; /* clear MSR_EE */ \ | ||
379 | rotldi r10,r10,16; \ | ||
380 | mtspr SPRN_##_H##SRR1,r10; \ | ||
381 | 2: mtcrf 0x80,r9; \ | ||
382 | ld r9,PACA_EXGEN+EX_R9(r13); \ | ||
383 | ld r10,PACA_EXGEN+EX_R10(r13); \ | ||
384 | ld r11,PACA_EXGEN+EX_R11(r13); \ | ||
385 | GET_SCRATCH0(r13); \ | ||
386 | ##_H##rfid; \ | ||
373 | b . | 387 | b . |
388 | |||
389 | MASKED_INTERRUPT() | ||
390 | MASKED_INTERRUPT(H) | ||
374 | 391 | ||
375 | masked_Hinterrupt: | 392 | /* |
376 | stb r10,PACAHARDIRQEN(r13) | 393 | * Called from arch_local_irq_enable when an interrupt needs |
377 | mtcrf 0x80,r9 | 394 | * to be resent. r3 contains 0x500 or 0x900 to indicate which |
378 | ld r9,PACA_EXGEN+EX_R9(r13) | 395 | * kind of interrupt. MSR:EE is already off. We generate a |
379 | mfspr r10,SPRN_HSRR1 | 396 | * stackframe like if a real interrupt had happened. |
380 | rldicl r10,r10,48,1 /* clear MSR_EE */ | 397 | * |
381 | rotldi r10,r10,16 | 398 | * Note: While MSR:EE is off, we need to make sure that _MSR |
382 | mtspr SPRN_HSRR1,r10 | 399 | * in the generated frame has EE set to 1 or the exception |
383 | ld r10,PACA_EXGEN+EX_R10(r13) | 400 | * handler will not properly re-enable them. |
384 | GET_SCRATCH0(r13) | 401 | */ |
385 | hrfid | 402 | _GLOBAL(__replay_interrupt) |
386 | b . | 403 | /* We are going to jump to the exception common code which |
404 | * will retrieve various register values from the PACA which | ||
405 | * we don't give a damn about, so we don't bother storing them. | ||
406 | */ | ||
407 | mfmsr r12 | ||
408 | mflr r11 | ||
409 | mfcr r9 | ||
410 | ori r12,r12,MSR_EE | ||
411 | andi. r3,r3,0x0800 | ||
412 | bne decrementer_common | ||
413 | b hardware_interrupt_common | ||
387 | 414 | ||
388 | #ifdef CONFIG_PPC_PSERIES | 415 | #ifdef CONFIG_PPC_PSERIES |
389 | /* | 416 | /* |
@@ -458,14 +485,15 @@ machine_check_common: | |||
458 | bl .machine_check_exception | 485 | bl .machine_check_exception |
459 | b .ret_from_except | 486 | b .ret_from_except |
460 | 487 | ||
461 | STD_EXCEPTION_COMMON_LITE(0x900, decrementer, .timer_interrupt) | 488 | STD_EXCEPTION_COMMON_ASYNC(0x500, hardware_interrupt, do_IRQ) |
489 | STD_EXCEPTION_COMMON_ASYNC(0x900, decrementer, .timer_interrupt) | ||
462 | STD_EXCEPTION_COMMON(0xa00, trap_0a, .unknown_exception) | 490 | STD_EXCEPTION_COMMON(0xa00, trap_0a, .unknown_exception) |
463 | STD_EXCEPTION_COMMON(0xb00, trap_0b, .unknown_exception) | 491 | STD_EXCEPTION_COMMON(0xb00, trap_0b, .unknown_exception) |
464 | STD_EXCEPTION_COMMON(0xd00, single_step, .single_step_exception) | 492 | STD_EXCEPTION_COMMON(0xd00, single_step, .single_step_exception) |
465 | STD_EXCEPTION_COMMON(0xe00, trap_0e, .unknown_exception) | 493 | STD_EXCEPTION_COMMON(0xe00, trap_0e, .unknown_exception) |
466 | STD_EXCEPTION_COMMON(0xe40, emulation_assist, .program_check_exception) | 494 | STD_EXCEPTION_COMMON(0xe40, emulation_assist, .program_check_exception) |
467 | STD_EXCEPTION_COMMON(0xe60, hmi_exception, .unknown_exception) | 495 | STD_EXCEPTION_COMMON(0xe60, hmi_exception, .unknown_exception) |
468 | STD_EXCEPTION_COMMON_IDLE(0xf00, performance_monitor, .performance_monitor_exception) | 496 | STD_EXCEPTION_COMMON_ASYNC(0xf00, performance_monitor, .performance_monitor_exception) |
469 | STD_EXCEPTION_COMMON(0x1300, instruction_breakpoint, .instruction_breakpoint_exception) | 497 | STD_EXCEPTION_COMMON(0x1300, instruction_breakpoint, .instruction_breakpoint_exception) |
470 | #ifdef CONFIG_ALTIVEC | 498 | #ifdef CONFIG_ALTIVEC |
471 | STD_EXCEPTION_COMMON(0x1700, altivec_assist, .altivec_assist_exception) | 499 | STD_EXCEPTION_COMMON(0x1700, altivec_assist, .altivec_assist_exception) |
@@ -482,6 +510,9 @@ machine_check_common: | |||
482 | system_call_entry: | 510 | system_call_entry: |
483 | b system_call_common | 511 | b system_call_common |
484 | 512 | ||
513 | ppc64_runlatch_on_trampoline: | ||
514 | b .__ppc64_runlatch_on | ||
515 | |||
485 | /* | 516 | /* |
486 | * Here we have detected that the kernel stack pointer is bad. | 517 | * Here we have detected that the kernel stack pointer is bad. |
487 | * R9 contains the saved CR, r13 points to the paca, | 518 | * R9 contains the saved CR, r13 points to the paca, |
@@ -555,6 +586,8 @@ data_access_common: | |||
555 | mfspr r10,SPRN_DSISR | 586 | mfspr r10,SPRN_DSISR |
556 | stw r10,PACA_EXGEN+EX_DSISR(r13) | 587 | stw r10,PACA_EXGEN+EX_DSISR(r13) |
557 | EXCEPTION_PROLOG_COMMON(0x300, PACA_EXGEN) | 588 | EXCEPTION_PROLOG_COMMON(0x300, PACA_EXGEN) |
589 | DISABLE_INTS | ||
590 | ld r12,_MSR(r1) | ||
558 | ld r3,PACA_EXGEN+EX_DAR(r13) | 591 | ld r3,PACA_EXGEN+EX_DAR(r13) |
559 | lwz r4,PACA_EXGEN+EX_DSISR(r13) | 592 | lwz r4,PACA_EXGEN+EX_DSISR(r13) |
560 | li r5,0x300 | 593 | li r5,0x300 |
@@ -569,6 +602,7 @@ h_data_storage_common: | |||
569 | stw r10,PACA_EXGEN+EX_DSISR(r13) | 602 | stw r10,PACA_EXGEN+EX_DSISR(r13) |
570 | EXCEPTION_PROLOG_COMMON(0xe00, PACA_EXGEN) | 603 | EXCEPTION_PROLOG_COMMON(0xe00, PACA_EXGEN) |
571 | bl .save_nvgprs | 604 | bl .save_nvgprs |
605 | DISABLE_INTS | ||
572 | addi r3,r1,STACK_FRAME_OVERHEAD | 606 | addi r3,r1,STACK_FRAME_OVERHEAD |
573 | bl .unknown_exception | 607 | bl .unknown_exception |
574 | b .ret_from_except | 608 | b .ret_from_except |
@@ -577,6 +611,8 @@ h_data_storage_common: | |||
577 | .globl instruction_access_common | 611 | .globl instruction_access_common |
578 | instruction_access_common: | 612 | instruction_access_common: |
579 | EXCEPTION_PROLOG_COMMON(0x400, PACA_EXGEN) | 613 | EXCEPTION_PROLOG_COMMON(0x400, PACA_EXGEN) |
614 | DISABLE_INTS | ||
615 | ld r12,_MSR(r1) | ||
580 | ld r3,_NIP(r1) | 616 | ld r3,_NIP(r1) |
581 | andis. r4,r12,0x5820 | 617 | andis. r4,r12,0x5820 |
582 | li r5,0x400 | 618 | li r5,0x400 |
@@ -672,12 +708,6 @@ _GLOBAL(slb_miss_realmode) | |||
672 | ld r10,PACA_EXSLB+EX_LR(r13) | 708 | ld r10,PACA_EXSLB+EX_LR(r13) |
673 | ld r3,PACA_EXSLB+EX_R3(r13) | 709 | ld r3,PACA_EXSLB+EX_R3(r13) |
674 | lwz r9,PACA_EXSLB+EX_CCR(r13) /* get saved CR */ | 710 | lwz r9,PACA_EXSLB+EX_CCR(r13) /* get saved CR */ |
675 | #ifdef CONFIG_PPC_ISERIES | ||
676 | BEGIN_FW_FTR_SECTION | ||
677 | ld r11,PACALPPACAPTR(r13) | ||
678 | ld r11,LPPACASRR0(r11) /* get SRR0 value */ | ||
679 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) | ||
680 | #endif /* CONFIG_PPC_ISERIES */ | ||
681 | 711 | ||
682 | mtlr r10 | 712 | mtlr r10 |
683 | 713 | ||
@@ -690,12 +720,6 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) | |||
690 | mtcrf 0x01,r9 /* slb_allocate uses cr0 and cr7 */ | 720 | mtcrf 0x01,r9 /* slb_allocate uses cr0 and cr7 */ |
691 | .machine pop | 721 | .machine pop |
692 | 722 | ||
693 | #ifdef CONFIG_PPC_ISERIES | ||
694 | BEGIN_FW_FTR_SECTION | ||
695 | mtspr SPRN_SRR0,r11 | ||
696 | mtspr SPRN_SRR1,r12 | ||
697 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) | ||
698 | #endif /* CONFIG_PPC_ISERIES */ | ||
699 | ld r9,PACA_EXSLB+EX_R9(r13) | 723 | ld r9,PACA_EXSLB+EX_R9(r13) |
700 | ld r10,PACA_EXSLB+EX_R10(r13) | 724 | ld r10,PACA_EXSLB+EX_R10(r13) |
701 | ld r11,PACA_EXSLB+EX_R11(r13) | 725 | ld r11,PACA_EXSLB+EX_R11(r13) |
@@ -704,13 +728,7 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) | |||
704 | rfid | 728 | rfid |
705 | b . /* prevent speculative execution */ | 729 | b . /* prevent speculative execution */ |
706 | 730 | ||
707 | 2: | 731 | 2: mfspr r11,SPRN_SRR0 |
708 | #ifdef CONFIG_PPC_ISERIES | ||
709 | BEGIN_FW_FTR_SECTION | ||
710 | b unrecov_slb | ||
711 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) | ||
712 | #endif /* CONFIG_PPC_ISERIES */ | ||
713 | mfspr r11,SPRN_SRR0 | ||
714 | ld r10,PACAKBASE(r13) | 732 | ld r10,PACAKBASE(r13) |
715 | LOAD_HANDLER(r10,unrecov_slb) | 733 | LOAD_HANDLER(r10,unrecov_slb) |
716 | mtspr SPRN_SRR0,r10 | 734 | mtspr SPRN_SRR0,r10 |
@@ -727,20 +745,6 @@ unrecov_slb: | |||
727 | bl .unrecoverable_exception | 745 | bl .unrecoverable_exception |
728 | b 1b | 746 | b 1b |
729 | 747 | ||
730 | .align 7 | ||
731 | .globl hardware_interrupt_common | ||
732 | .globl hardware_interrupt_entry | ||
733 | hardware_interrupt_common: | ||
734 | EXCEPTION_PROLOG_COMMON(0x500, PACA_EXGEN) | ||
735 | FINISH_NAP | ||
736 | hardware_interrupt_entry: | ||
737 | DISABLE_INTS | ||
738 | BEGIN_FTR_SECTION | ||
739 | bl .ppc64_runlatch_on | ||
740 | END_FTR_SECTION_IFSET(CPU_FTR_CTRL) | ||
741 | addi r3,r1,STACK_FRAME_OVERHEAD | ||
742 | bl .do_IRQ | ||
743 | b .ret_from_except_lite | ||
744 | 748 | ||
745 | #ifdef CONFIG_PPC_970_NAP | 749 | #ifdef CONFIG_PPC_970_NAP |
746 | power4_fixup_nap: | 750 | power4_fixup_nap: |
@@ -785,8 +789,8 @@ fp_unavailable_common: | |||
785 | EXCEPTION_PROLOG_COMMON(0x800, PACA_EXGEN) | 789 | EXCEPTION_PROLOG_COMMON(0x800, PACA_EXGEN) |
786 | bne 1f /* if from user, just load it up */ | 790 | bne 1f /* if from user, just load it up */ |
787 | bl .save_nvgprs | 791 | bl .save_nvgprs |
792 | DISABLE_INTS | ||
788 | addi r3,r1,STACK_FRAME_OVERHEAD | 793 | addi r3,r1,STACK_FRAME_OVERHEAD |
789 | ENABLE_INTS | ||
790 | bl .kernel_fp_unavailable_exception | 794 | bl .kernel_fp_unavailable_exception |
791 | BUG_OPCODE | 795 | BUG_OPCODE |
792 | 1: bl .load_up_fpu | 796 | 1: bl .load_up_fpu |
@@ -805,8 +809,8 @@ BEGIN_FTR_SECTION | |||
805 | END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) | 809 | END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) |
806 | #endif | 810 | #endif |
807 | bl .save_nvgprs | 811 | bl .save_nvgprs |
812 | DISABLE_INTS | ||
808 | addi r3,r1,STACK_FRAME_OVERHEAD | 813 | addi r3,r1,STACK_FRAME_OVERHEAD |
809 | ENABLE_INTS | ||
810 | bl .altivec_unavailable_exception | 814 | bl .altivec_unavailable_exception |
811 | b .ret_from_except | 815 | b .ret_from_except |
812 | 816 | ||
@@ -816,13 +820,14 @@ vsx_unavailable_common: | |||
816 | EXCEPTION_PROLOG_COMMON(0xf40, PACA_EXGEN) | 820 | EXCEPTION_PROLOG_COMMON(0xf40, PACA_EXGEN) |
817 | #ifdef CONFIG_VSX | 821 | #ifdef CONFIG_VSX |
818 | BEGIN_FTR_SECTION | 822 | BEGIN_FTR_SECTION |
819 | bne .load_up_vsx | 823 | beq 1f |
824 | b .load_up_vsx | ||
820 | 1: | 825 | 1: |
821 | END_FTR_SECTION_IFSET(CPU_FTR_VSX) | 826 | END_FTR_SECTION_IFSET(CPU_FTR_VSX) |
822 | #endif | 827 | #endif |
823 | bl .save_nvgprs | 828 | bl .save_nvgprs |
829 | DISABLE_INTS | ||
824 | addi r3,r1,STACK_FRAME_OVERHEAD | 830 | addi r3,r1,STACK_FRAME_OVERHEAD |
825 | ENABLE_INTS | ||
826 | bl .vsx_unavailable_exception | 831 | bl .vsx_unavailable_exception |
827 | b .ret_from_except | 832 | b .ret_from_except |
828 | 833 | ||
@@ -831,66 +836,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX) | |||
831 | __end_handlers: | 836 | __end_handlers: |
832 | 837 | ||
833 | /* | 838 | /* |
834 | * Return from an exception with minimal checks. | ||
835 | * The caller is assumed to have done EXCEPTION_PROLOG_COMMON. | ||
836 | * If interrupts have been enabled, or anything has been | ||
837 | * done that might have changed the scheduling status of | ||
838 | * any task or sent any task a signal, you should use | ||
839 | * ret_from_except or ret_from_except_lite instead of this. | ||
840 | */ | ||
841 | fast_exc_return_irq: /* restores irq state too */ | ||
842 | ld r3,SOFTE(r1) | ||
843 | TRACE_AND_RESTORE_IRQ(r3); | ||
844 | ld r12,_MSR(r1) | ||
845 | rldicl r4,r12,49,63 /* get MSR_EE to LSB */ | ||
846 | stb r4,PACAHARDIRQEN(r13) /* restore paca->hard_enabled */ | ||
847 | b 1f | ||
848 | |||
849 | .globl fast_exception_return | ||
850 | fast_exception_return: | ||
851 | ld r12,_MSR(r1) | ||
852 | 1: ld r11,_NIP(r1) | ||
853 | andi. r3,r12,MSR_RI /* check if RI is set */ | ||
854 | beq- unrecov_fer | ||
855 | |||
856 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | ||
857 | andi. r3,r12,MSR_PR | ||
858 | beq 2f | ||
859 | ACCOUNT_CPU_USER_EXIT(r3, r4) | ||
860 | 2: | ||
861 | #endif | ||
862 | |||
863 | ld r3,_CCR(r1) | ||
864 | ld r4,_LINK(r1) | ||
865 | ld r5,_CTR(r1) | ||
866 | ld r6,_XER(r1) | ||
867 | mtcr r3 | ||
868 | mtlr r4 | ||
869 | mtctr r5 | ||
870 | mtxer r6 | ||
871 | REST_GPR(0, r1) | ||
872 | REST_8GPRS(2, r1) | ||
873 | |||
874 | mfmsr r10 | ||
875 | rldicl r10,r10,48,1 /* clear EE */ | ||
876 | rldicr r10,r10,16,61 /* clear RI (LE is 0 already) */ | ||
877 | mtmsrd r10,1 | ||
878 | |||
879 | mtspr SPRN_SRR1,r12 | ||
880 | mtspr SPRN_SRR0,r11 | ||
881 | REST_4GPRS(10, r1) | ||
882 | ld r1,GPR1(r1) | ||
883 | rfid | ||
884 | b . /* prevent speculative execution */ | ||
885 | |||
886 | unrecov_fer: | ||
887 | bl .save_nvgprs | ||
888 | 1: addi r3,r1,STACK_FRAME_OVERHEAD | ||
889 | bl .unrecoverable_exception | ||
890 | b 1b | ||
891 | |||
892 | |||
893 | /* | ||
894 | * Hash table stuff | 839 | * Hash table stuff |
895 | */ | 840 | */ |
896 | .align 7 | 841 | .align 7 |
@@ -912,28 +857,6 @@ END_MMU_FTR_SECTION_IFCLR(MMU_FTR_SLB) | |||
912 | lwz r0,TI_PREEMPT(r11) /* If we're in an "NMI" */ | 857 | lwz r0,TI_PREEMPT(r11) /* If we're in an "NMI" */ |
913 | andis. r0,r0,NMI_MASK@h /* (i.e. an irq when soft-disabled) */ | 858 | andis. r0,r0,NMI_MASK@h /* (i.e. an irq when soft-disabled) */ |
914 | bne 77f /* then don't call hash_page now */ | 859 | bne 77f /* then don't call hash_page now */ |
915 | |||
916 | /* | ||
917 | * On iSeries, we soft-disable interrupts here, then | ||
918 | * hard-enable interrupts so that the hash_page code can spin on | ||
919 | * the hash_table_lock without problems on a shared processor. | ||
920 | */ | ||
921 | DISABLE_INTS | ||
922 | |||
923 | /* | ||
924 | * Currently, trace_hardirqs_off() will be called by DISABLE_INTS | ||
925 | * and will clobber volatile registers when irq tracing is enabled | ||
926 | * so we need to reload them. It may be possible to be smarter here | ||
927 | * and move the irq tracing elsewhere but let's keep it simple for | ||
928 | * now | ||
929 | */ | ||
930 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
931 | ld r3,_DAR(r1) | ||
932 | ld r4,_DSISR(r1) | ||
933 | ld r5,_TRAP(r1) | ||
934 | ld r12,_MSR(r1) | ||
935 | clrrdi r5,r5,4 | ||
936 | #endif /* CONFIG_TRACE_IRQFLAGS */ | ||
937 | /* | 860 | /* |
938 | * We need to set the _PAGE_USER bit if MSR_PR is set or if we are | 861 | * We need to set the _PAGE_USER bit if MSR_PR is set or if we are |
939 | * accessing a userspace segment (even from the kernel). We assume | 862 | * accessing a userspace segment (even from the kernel). We assume |
@@ -951,62 +874,25 @@ END_MMU_FTR_SECTION_IFCLR(MMU_FTR_SLB) | |||
951 | * r4 contains the required access permissions | 874 | * r4 contains the required access permissions |
952 | * r5 contains the trap number | 875 | * r5 contains the trap number |
953 | * | 876 | * |
954 | * at return r3 = 0 for success | 877 | * at return r3 = 0 for success, 1 for page fault, negative for error |
955 | */ | 878 | */ |
956 | bl .hash_page /* build HPTE if possible */ | 879 | bl .hash_page /* build HPTE if possible */ |
957 | cmpdi r3,0 /* see if hash_page succeeded */ | 880 | cmpdi r3,0 /* see if hash_page succeeded */ |
958 | 881 | ||
959 | BEGIN_FW_FTR_SECTION | 882 | /* Success */ |
960 | /* | ||
961 | * If we had interrupts soft-enabled at the point where the | ||
962 | * DSI/ISI occurred, and an interrupt came in during hash_page, | ||
963 | * handle it now. | ||
964 | * We jump to ret_from_except_lite rather than fast_exception_return | ||
965 | * because ret_from_except_lite will check for and handle pending | ||
966 | * interrupts if necessary. | ||
967 | */ | ||
968 | beq 13f | ||
969 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) | ||
970 | |||
971 | BEGIN_FW_FTR_SECTION | ||
972 | /* | ||
973 | * Here we have interrupts hard-disabled, so it is sufficient | ||
974 | * to restore paca->{soft,hard}_enable and get out. | ||
975 | */ | ||
976 | beq fast_exc_return_irq /* Return from exception on success */ | 883 | beq fast_exc_return_irq /* Return from exception on success */ |
977 | END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES) | ||
978 | |||
979 | /* For a hash failure, we don't bother re-enabling interrupts */ | ||
980 | ble- 12f | ||
981 | |||
982 | /* | ||
983 | * hash_page couldn't handle it, set soft interrupt enable back | ||
984 | * to what it was before the trap. Note that .arch_local_irq_restore | ||
985 | * handles any interrupts pending at this point. | ||
986 | */ | ||
987 | ld r3,SOFTE(r1) | ||
988 | TRACE_AND_RESTORE_IRQ_PARTIAL(r3, 11f) | ||
989 | bl .arch_local_irq_restore | ||
990 | b 11f | ||
991 | 884 | ||
992 | /* We have a data breakpoint exception - handle it */ | 885 | /* Error */ |
993 | handle_dabr_fault: | 886 | blt- 13f |
994 | bl .save_nvgprs | ||
995 | ld r4,_DAR(r1) | ||
996 | ld r5,_DSISR(r1) | ||
997 | addi r3,r1,STACK_FRAME_OVERHEAD | ||
998 | bl .do_dabr | ||
999 | b .ret_from_except_lite | ||
1000 | 887 | ||
1001 | /* Here we have a page fault that hash_page can't handle. */ | 888 | /* Here we have a page fault that hash_page can't handle. */ |
1002 | handle_page_fault: | 889 | handle_page_fault: |
1003 | ENABLE_INTS | ||
1004 | 11: ld r4,_DAR(r1) | 890 | 11: ld r4,_DAR(r1) |
1005 | ld r5,_DSISR(r1) | 891 | ld r5,_DSISR(r1) |
1006 | addi r3,r1,STACK_FRAME_OVERHEAD | 892 | addi r3,r1,STACK_FRAME_OVERHEAD |
1007 | bl .do_page_fault | 893 | bl .do_page_fault |
1008 | cmpdi r3,0 | 894 | cmpdi r3,0 |
1009 | beq+ 13f | 895 | beq+ 12f |
1010 | bl .save_nvgprs | 896 | bl .save_nvgprs |
1011 | mr r5,r3 | 897 | mr r5,r3 |
1012 | addi r3,r1,STACK_FRAME_OVERHEAD | 898 | addi r3,r1,STACK_FRAME_OVERHEAD |
@@ -1014,12 +900,20 @@ handle_page_fault: | |||
1014 | bl .bad_page_fault | 900 | bl .bad_page_fault |
1015 | b .ret_from_except | 901 | b .ret_from_except |
1016 | 902 | ||
1017 | 13: b .ret_from_except_lite | 903 | /* We have a data breakpoint exception - handle it */ |
904 | handle_dabr_fault: | ||
905 | bl .save_nvgprs | ||
906 | ld r4,_DAR(r1) | ||
907 | ld r5,_DSISR(r1) | ||
908 | addi r3,r1,STACK_FRAME_OVERHEAD | ||
909 | bl .do_dabr | ||
910 | 12: b .ret_from_except_lite | ||
911 | |||
1018 | 912 | ||
1019 | /* We have a page fault that hash_page could handle but HV refused | 913 | /* We have a page fault that hash_page could handle but HV refused |
1020 | * the PTE insertion | 914 | * the PTE insertion |
1021 | */ | 915 | */ |
1022 | 12: bl .save_nvgprs | 916 | 13: bl .save_nvgprs |
1023 | mr r5,r3 | 917 | mr r5,r3 |
1024 | addi r3,r1,STACK_FRAME_OVERHEAD | 918 | addi r3,r1,STACK_FRAME_OVERHEAD |
1025 | ld r4,_DAR(r1) | 919 | ld r4,_DAR(r1) |
@@ -1141,51 +1035,19 @@ _GLOBAL(do_stab_bolted) | |||
1141 | .= 0x7000 | 1035 | .= 0x7000 |
1142 | .globl fwnmi_data_area | 1036 | .globl fwnmi_data_area |
1143 | fwnmi_data_area: | 1037 | fwnmi_data_area: |
1144 | #endif /* defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV) */ | ||
1145 | 1038 | ||
1146 | /* iSeries does not use the FWNMI stuff, so it is safe to put | ||
1147 | * this here, even if we later allow kernels that will boot on | ||
1148 | * both pSeries and iSeries */ | ||
1149 | #ifdef CONFIG_PPC_ISERIES | ||
1150 | . = LPARMAP_PHYS | ||
1151 | .globl xLparMap | ||
1152 | xLparMap: | ||
1153 | .quad HvEsidsToMap /* xNumberEsids */ | ||
1154 | .quad HvRangesToMap /* xNumberRanges */ | ||
1155 | .quad STAB0_PAGE /* xSegmentTableOffs */ | ||
1156 | .zero 40 /* xRsvd */ | ||
1157 | /* xEsids (HvEsidsToMap entries of 2 quads) */ | ||
1158 | .quad PAGE_OFFSET_ESID /* xKernelEsid */ | ||
1159 | .quad PAGE_OFFSET_VSID /* xKernelVsid */ | ||
1160 | .quad VMALLOC_START_ESID /* xKernelEsid */ | ||
1161 | .quad VMALLOC_START_VSID /* xKernelVsid */ | ||
1162 | /* xRanges (HvRangesToMap entries of 3 quads) */ | ||
1163 | .quad HvPagesToMap /* xPages */ | ||
1164 | .quad 0 /* xOffset */ | ||
1165 | .quad PAGE_OFFSET_VSID << (SID_SHIFT - HW_PAGE_SHIFT) /* xVPN */ | ||
1166 | |||
1167 | #endif /* CONFIG_PPC_ISERIES */ | ||
1168 | |||
1169 | #if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV) | ||
1170 | /* pseries and powernv need to keep the whole page from | 1039 | /* pseries and powernv need to keep the whole page from |
1171 | * 0x7000 to 0x8000 free for use by the firmware | 1040 | * 0x7000 to 0x8000 free for use by the firmware |
1172 | */ | 1041 | */ |
1173 | . = 0x8000 | 1042 | . = 0x8000 |
1174 | #endif /* defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV) */ | 1043 | #endif /* defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV) */ |
1175 | 1044 | ||
1176 | /* | 1045 | /* Space for CPU0's segment table */ |
1177 | * Space for CPU0's segment table. | 1046 | .balign 4096 |
1178 | * | ||
1179 | * On iSeries, the hypervisor must fill in at least one entry before | ||
1180 | * we get control (with relocate on). The address is given to the hv | ||
1181 | * as a page number (see xLparMap above), so this must be at a | ||
1182 | * fixed address (the linker can't compute (u64)&initial_stab >> | ||
1183 | * PAGE_SHIFT). | ||
1184 | */ | ||
1185 | . = STAB0_OFFSET /* 0x8000 */ | ||
1186 | .globl initial_stab | 1047 | .globl initial_stab |
1187 | initial_stab: | 1048 | initial_stab: |
1188 | .space 4096 | 1049 | .space 4096 |
1050 | |||
1189 | #ifdef CONFIG_PPC_POWERNV | 1051 | #ifdef CONFIG_PPC_POWERNV |
1190 | _GLOBAL(opal_mc_secondary_handler) | 1052 | _GLOBAL(opal_mc_secondary_handler) |
1191 | HMT_MEDIUM | 1053 | HMT_MEDIUM |
diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c new file mode 100644 index 000000000000..cfe7a38708c3 --- /dev/null +++ b/arch/powerpc/kernel/fadump.c | |||
@@ -0,0 +1,1315 @@ | |||
1 | /* | ||
2 | * Firmware Assisted dump: A robust mechanism to get reliable kernel crash | ||
3 | * dump with assistance from firmware. This approach does not use kexec, | ||
4 | * instead firmware assists in booting the kdump kernel while preserving | ||
5 | * memory contents. The most of the code implementation has been adapted | ||
6 | * from phyp assisted dump implementation written by Linas Vepstas and | ||
7 | * Manish Ahuja | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
22 | * | ||
23 | * Copyright 2011 IBM Corporation | ||
24 | * Author: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com> | ||
25 | */ | ||
26 | |||
27 | #undef DEBUG | ||
28 | #define pr_fmt(fmt) "fadump: " fmt | ||
29 | |||
30 | #include <linux/string.h> | ||
31 | #include <linux/memblock.h> | ||
32 | #include <linux/delay.h> | ||
33 | #include <linux/debugfs.h> | ||
34 | #include <linux/seq_file.h> | ||
35 | #include <linux/crash_dump.h> | ||
36 | #include <linux/kobject.h> | ||
37 | #include <linux/sysfs.h> | ||
38 | |||
39 | #include <asm/page.h> | ||
40 | #include <asm/prom.h> | ||
41 | #include <asm/rtas.h> | ||
42 | #include <asm/fadump.h> | ||
43 | |||
44 | static struct fw_dump fw_dump; | ||
45 | static struct fadump_mem_struct fdm; | ||
46 | static const struct fadump_mem_struct *fdm_active; | ||
47 | |||
48 | static DEFINE_MUTEX(fadump_mutex); | ||
49 | struct fad_crash_memory_ranges crash_memory_ranges[INIT_CRASHMEM_RANGES]; | ||
50 | int crash_mem_ranges; | ||
51 | |||
52 | /* Scan the Firmware Assisted dump configuration details. */ | ||
53 | int __init early_init_dt_scan_fw_dump(unsigned long node, | ||
54 | const char *uname, int depth, void *data) | ||
55 | { | ||
56 | __be32 *sections; | ||
57 | int i, num_sections; | ||
58 | unsigned long size; | ||
59 | const int *token; | ||
60 | |||
61 | if (depth != 1 || strcmp(uname, "rtas") != 0) | ||
62 | return 0; | ||
63 | |||
64 | /* | ||
65 | * Check if Firmware Assisted dump is supported. if yes, check | ||
66 | * if dump has been initiated on last reboot. | ||
67 | */ | ||
68 | token = of_get_flat_dt_prop(node, "ibm,configure-kernel-dump", NULL); | ||
69 | if (!token) | ||
70 | return 0; | ||
71 | |||
72 | fw_dump.fadump_supported = 1; | ||
73 | fw_dump.ibm_configure_kernel_dump = *token; | ||
74 | |||
75 | /* | ||
76 | * The 'ibm,kernel-dump' rtas node is present only if there is | ||
77 | * dump data waiting for us. | ||
78 | */ | ||
79 | fdm_active = of_get_flat_dt_prop(node, "ibm,kernel-dump", NULL); | ||
80 | if (fdm_active) | ||
81 | fw_dump.dump_active = 1; | ||
82 | |||
83 | /* Get the sizes required to store dump data for the firmware provided | ||
84 | * dump sections. | ||
85 | * For each dump section type supported, a 32bit cell which defines | ||
86 | * the ID of a supported section followed by two 32 bit cells which | ||
87 | * gives teh size of the section in bytes. | ||
88 | */ | ||
89 | sections = of_get_flat_dt_prop(node, "ibm,configure-kernel-dump-sizes", | ||
90 | &size); | ||
91 | |||
92 | if (!sections) | ||
93 | return 0; | ||
94 | |||
95 | num_sections = size / (3 * sizeof(u32)); | ||
96 | |||
97 | for (i = 0; i < num_sections; i++, sections += 3) { | ||
98 | u32 type = (u32)of_read_number(sections, 1); | ||
99 | |||
100 | switch (type) { | ||
101 | case FADUMP_CPU_STATE_DATA: | ||
102 | fw_dump.cpu_state_data_size = | ||
103 | of_read_ulong(§ions[1], 2); | ||
104 | break; | ||
105 | case FADUMP_HPTE_REGION: | ||
106 | fw_dump.hpte_region_size = | ||
107 | of_read_ulong(§ions[1], 2); | ||
108 | break; | ||
109 | } | ||
110 | } | ||
111 | return 1; | ||
112 | } | ||
113 | |||
114 | int is_fadump_active(void) | ||
115 | { | ||
116 | return fw_dump.dump_active; | ||
117 | } | ||
118 | |||
119 | /* Print firmware assisted dump configurations for debugging purpose. */ | ||
120 | static void fadump_show_config(void) | ||
121 | { | ||
122 | pr_debug("Support for firmware-assisted dump (fadump): %s\n", | ||
123 | (fw_dump.fadump_supported ? "present" : "no support")); | ||
124 | |||
125 | if (!fw_dump.fadump_supported) | ||
126 | return; | ||
127 | |||
128 | pr_debug("Fadump enabled : %s\n", | ||
129 | (fw_dump.fadump_enabled ? "yes" : "no")); | ||
130 | pr_debug("Dump Active : %s\n", | ||
131 | (fw_dump.dump_active ? "yes" : "no")); | ||
132 | pr_debug("Dump section sizes:\n"); | ||
133 | pr_debug(" CPU state data size: %lx\n", fw_dump.cpu_state_data_size); | ||
134 | pr_debug(" HPTE region size : %lx\n", fw_dump.hpte_region_size); | ||
135 | pr_debug("Boot memory size : %lx\n", fw_dump.boot_memory_size); | ||
136 | } | ||
137 | |||
138 | static unsigned long init_fadump_mem_struct(struct fadump_mem_struct *fdm, | ||
139 | unsigned long addr) | ||
140 | { | ||
141 | if (!fdm) | ||
142 | return 0; | ||
143 | |||
144 | memset(fdm, 0, sizeof(struct fadump_mem_struct)); | ||
145 | addr = addr & PAGE_MASK; | ||
146 | |||
147 | fdm->header.dump_format_version = 0x00000001; | ||
148 | fdm->header.dump_num_sections = 3; | ||
149 | fdm->header.dump_status_flag = 0; | ||
150 | fdm->header.offset_first_dump_section = | ||
151 | (u32)offsetof(struct fadump_mem_struct, cpu_state_data); | ||
152 | |||
153 | /* | ||
154 | * Fields for disk dump option. | ||
155 | * We are not using disk dump option, hence set these fields to 0. | ||
156 | */ | ||
157 | fdm->header.dd_block_size = 0; | ||
158 | fdm->header.dd_block_offset = 0; | ||
159 | fdm->header.dd_num_blocks = 0; | ||
160 | fdm->header.dd_offset_disk_path = 0; | ||
161 | |||
162 | /* set 0 to disable an automatic dump-reboot. */ | ||
163 | fdm->header.max_time_auto = 0; | ||
164 | |||
165 | /* Kernel dump sections */ | ||
166 | /* cpu state data section. */ | ||
167 | fdm->cpu_state_data.request_flag = FADUMP_REQUEST_FLAG; | ||
168 | fdm->cpu_state_data.source_data_type = FADUMP_CPU_STATE_DATA; | ||
169 | fdm->cpu_state_data.source_address = 0; | ||
170 | fdm->cpu_state_data.source_len = fw_dump.cpu_state_data_size; | ||
171 | fdm->cpu_state_data.destination_address = addr; | ||
172 | addr += fw_dump.cpu_state_data_size; | ||
173 | |||
174 | /* hpte region section */ | ||
175 | fdm->hpte_region.request_flag = FADUMP_REQUEST_FLAG; | ||
176 | fdm->hpte_region.source_data_type = FADUMP_HPTE_REGION; | ||
177 | fdm->hpte_region.source_address = 0; | ||
178 | fdm->hpte_region.source_len = fw_dump.hpte_region_size; | ||
179 | fdm->hpte_region.destination_address = addr; | ||
180 | addr += fw_dump.hpte_region_size; | ||
181 | |||
182 | /* RMA region section */ | ||
183 | fdm->rmr_region.request_flag = FADUMP_REQUEST_FLAG; | ||
184 | fdm->rmr_region.source_data_type = FADUMP_REAL_MODE_REGION; | ||
185 | fdm->rmr_region.source_address = RMA_START; | ||
186 | fdm->rmr_region.source_len = fw_dump.boot_memory_size; | ||
187 | fdm->rmr_region.destination_address = addr; | ||
188 | addr += fw_dump.boot_memory_size; | ||
189 | |||
190 | return addr; | ||
191 | } | ||
192 | |||
193 | /** | ||
194 | * fadump_calculate_reserve_size(): reserve variable boot area 5% of System RAM | ||
195 | * | ||
196 | * Function to find the largest memory size we need to reserve during early | ||
197 | * boot process. This will be the size of the memory that is required for a | ||
198 | * kernel to boot successfully. | ||
199 | * | ||
200 | * This function has been taken from phyp-assisted dump feature implementation. | ||
201 | * | ||
202 | * returns larger of 256MB or 5% rounded down to multiples of 256MB. | ||
203 | * | ||
204 | * TODO: Come up with better approach to find out more accurate memory size | ||
205 | * that is required for a kernel to boot successfully. | ||
206 | * | ||
207 | */ | ||
208 | static inline unsigned long fadump_calculate_reserve_size(void) | ||
209 | { | ||
210 | unsigned long size; | ||
211 | |||
212 | /* | ||
213 | * Check if the size is specified through fadump_reserve_mem= cmdline | ||
214 | * option. If yes, then use that. | ||
215 | */ | ||
216 | if (fw_dump.reserve_bootvar) | ||
217 | return fw_dump.reserve_bootvar; | ||
218 | |||
219 | /* divide by 20 to get 5% of value */ | ||
220 | size = memblock_end_of_DRAM() / 20; | ||
221 | |||
222 | /* round it down in multiples of 256 */ | ||
223 | size = size & ~0x0FFFFFFFUL; | ||
224 | |||
225 | /* Truncate to memory_limit. We don't want to over reserve the memory.*/ | ||
226 | if (memory_limit && size > memory_limit) | ||
227 | size = memory_limit; | ||
228 | |||
229 | return (size > MIN_BOOT_MEM ? size : MIN_BOOT_MEM); | ||
230 | } | ||
231 | |||
232 | /* | ||
233 | * Calculate the total memory size required to be reserved for | ||
234 | * firmware-assisted dump registration. | ||
235 | */ | ||
236 | static unsigned long get_fadump_area_size(void) | ||
237 | { | ||
238 | unsigned long size = 0; | ||
239 | |||
240 | size += fw_dump.cpu_state_data_size; | ||
241 | size += fw_dump.hpte_region_size; | ||
242 | size += fw_dump.boot_memory_size; | ||
243 | size += sizeof(struct fadump_crash_info_header); | ||
244 | size += sizeof(struct elfhdr); /* ELF core header.*/ | ||
245 | size += sizeof(struct elf_phdr); /* place holder for cpu notes */ | ||
246 | /* Program headers for crash memory regions. */ | ||
247 | size += sizeof(struct elf_phdr) * (memblock_num_regions(memory) + 2); | ||
248 | |||
249 | size = PAGE_ALIGN(size); | ||
250 | return size; | ||
251 | } | ||
252 | |||
253 | int __init fadump_reserve_mem(void) | ||
254 | { | ||
255 | unsigned long base, size, memory_boundary; | ||
256 | |||
257 | if (!fw_dump.fadump_enabled) | ||
258 | return 0; | ||
259 | |||
260 | if (!fw_dump.fadump_supported) { | ||
261 | printk(KERN_INFO "Firmware-assisted dump is not supported on" | ||
262 | " this hardware\n"); | ||
263 | fw_dump.fadump_enabled = 0; | ||
264 | return 0; | ||
265 | } | ||
266 | /* | ||
267 | * Initialize boot memory size | ||
268 | * If dump is active then we have already calculated the size during | ||
269 | * first kernel. | ||
270 | */ | ||
271 | if (fdm_active) | ||
272 | fw_dump.boot_memory_size = fdm_active->rmr_region.source_len; | ||
273 | else | ||
274 | fw_dump.boot_memory_size = fadump_calculate_reserve_size(); | ||
275 | |||
276 | /* | ||
277 | * Calculate the memory boundary. | ||
278 | * If memory_limit is less than actual memory boundary then reserve | ||
279 | * the memory for fadump beyond the memory_limit and adjust the | ||
280 | * memory_limit accordingly, so that the running kernel can run with | ||
281 | * specified memory_limit. | ||
282 | */ | ||
283 | if (memory_limit && memory_limit < memblock_end_of_DRAM()) { | ||
284 | size = get_fadump_area_size(); | ||
285 | if ((memory_limit + size) < memblock_end_of_DRAM()) | ||
286 | memory_limit += size; | ||
287 | else | ||
288 | memory_limit = memblock_end_of_DRAM(); | ||
289 | printk(KERN_INFO "Adjusted memory_limit for firmware-assisted" | ||
290 | " dump, now %#016llx\n", | ||
291 | (unsigned long long)memory_limit); | ||
292 | } | ||
293 | if (memory_limit) | ||
294 | memory_boundary = memory_limit; | ||
295 | else | ||
296 | memory_boundary = memblock_end_of_DRAM(); | ||
297 | |||
298 | if (fw_dump.dump_active) { | ||
299 | printk(KERN_INFO "Firmware-assisted dump is active.\n"); | ||
300 | /* | ||
301 | * If last boot has crashed then reserve all the memory | ||
302 | * above boot_memory_size so that we don't touch it until | ||
303 | * dump is written to disk by userspace tool. This memory | ||
304 | * will be released for general use once the dump is saved. | ||
305 | */ | ||
306 | base = fw_dump.boot_memory_size; | ||
307 | size = memory_boundary - base; | ||
308 | memblock_reserve(base, size); | ||
309 | printk(KERN_INFO "Reserved %ldMB of memory at %ldMB " | ||
310 | "for saving crash dump\n", | ||
311 | (unsigned long)(size >> 20), | ||
312 | (unsigned long)(base >> 20)); | ||
313 | |||
314 | fw_dump.fadumphdr_addr = | ||
315 | fdm_active->rmr_region.destination_address + | ||
316 | fdm_active->rmr_region.source_len; | ||
317 | pr_debug("fadumphdr_addr = %p\n", | ||
318 | (void *) fw_dump.fadumphdr_addr); | ||
319 | } else { | ||
320 | /* Reserve the memory at the top of memory. */ | ||
321 | size = get_fadump_area_size(); | ||
322 | base = memory_boundary - size; | ||
323 | memblock_reserve(base, size); | ||
324 | printk(KERN_INFO "Reserved %ldMB of memory at %ldMB " | ||
325 | "for firmware-assisted dump\n", | ||
326 | (unsigned long)(size >> 20), | ||
327 | (unsigned long)(base >> 20)); | ||
328 | } | ||
329 | fw_dump.reserve_dump_area_start = base; | ||
330 | fw_dump.reserve_dump_area_size = size; | ||
331 | return 1; | ||
332 | } | ||
333 | |||
334 | /* Look for fadump= cmdline option. */ | ||
335 | static int __init early_fadump_param(char *p) | ||
336 | { | ||
337 | if (!p) | ||
338 | return 1; | ||
339 | |||
340 | if (strncmp(p, "on", 2) == 0) | ||
341 | fw_dump.fadump_enabled = 1; | ||
342 | else if (strncmp(p, "off", 3) == 0) | ||
343 | fw_dump.fadump_enabled = 0; | ||
344 | |||
345 | return 0; | ||
346 | } | ||
347 | early_param("fadump", early_fadump_param); | ||
348 | |||
349 | /* Look for fadump_reserve_mem= cmdline option */ | ||
350 | static int __init early_fadump_reserve_mem(char *p) | ||
351 | { | ||
352 | if (p) | ||
353 | fw_dump.reserve_bootvar = memparse(p, &p); | ||
354 | return 0; | ||
355 | } | ||
356 | early_param("fadump_reserve_mem", early_fadump_reserve_mem); | ||
357 | |||
358 | static void register_fw_dump(struct fadump_mem_struct *fdm) | ||
359 | { | ||
360 | int rc; | ||
361 | unsigned int wait_time; | ||
362 | |||
363 | pr_debug("Registering for firmware-assisted kernel dump...\n"); | ||
364 | |||
365 | /* TODO: Add upper time limit for the delay */ | ||
366 | do { | ||
367 | rc = rtas_call(fw_dump.ibm_configure_kernel_dump, 3, 1, NULL, | ||
368 | FADUMP_REGISTER, fdm, | ||
369 | sizeof(struct fadump_mem_struct)); | ||
370 | |||
371 | wait_time = rtas_busy_delay_time(rc); | ||
372 | if (wait_time) | ||
373 | mdelay(wait_time); | ||
374 | |||
375 | } while (wait_time); | ||
376 | |||
377 | switch (rc) { | ||
378 | case -1: | ||
379 | printk(KERN_ERR "Failed to register firmware-assisted kernel" | ||
380 | " dump. Hardware Error(%d).\n", rc); | ||
381 | break; | ||
382 | case -3: | ||
383 | printk(KERN_ERR "Failed to register firmware-assisted kernel" | ||
384 | " dump. Parameter Error(%d).\n", rc); | ||
385 | break; | ||
386 | case -9: | ||
387 | printk(KERN_ERR "firmware-assisted kernel dump is already " | ||
388 | " registered."); | ||
389 | fw_dump.dump_registered = 1; | ||
390 | break; | ||
391 | case 0: | ||
392 | printk(KERN_INFO "firmware-assisted kernel dump registration" | ||
393 | " is successful\n"); | ||
394 | fw_dump.dump_registered = 1; | ||
395 | break; | ||
396 | } | ||
397 | } | ||
398 | |||
399 | void crash_fadump(struct pt_regs *regs, const char *str) | ||
400 | { | ||
401 | struct fadump_crash_info_header *fdh = NULL; | ||
402 | |||
403 | if (!fw_dump.dump_registered || !fw_dump.fadumphdr_addr) | ||
404 | return; | ||
405 | |||
406 | fdh = __va(fw_dump.fadumphdr_addr); | ||
407 | crashing_cpu = smp_processor_id(); | ||
408 | fdh->crashing_cpu = crashing_cpu; | ||
409 | crash_save_vmcoreinfo(); | ||
410 | |||
411 | if (regs) | ||
412 | fdh->regs = *regs; | ||
413 | else | ||
414 | ppc_save_regs(&fdh->regs); | ||
415 | |||
416 | fdh->cpu_online_mask = *cpu_online_mask; | ||
417 | |||
418 | /* Call ibm,os-term rtas call to trigger firmware assisted dump */ | ||
419 | rtas_os_term((char *)str); | ||
420 | } | ||
421 | |||
422 | #define GPR_MASK 0xffffff0000000000 | ||
423 | static inline int fadump_gpr_index(u64 id) | ||
424 | { | ||
425 | int i = -1; | ||
426 | char str[3]; | ||
427 | |||
428 | if ((id & GPR_MASK) == REG_ID("GPR")) { | ||
429 | /* get the digits at the end */ | ||
430 | id &= ~GPR_MASK; | ||
431 | id >>= 24; | ||
432 | str[2] = '\0'; | ||
433 | str[1] = id & 0xff; | ||
434 | str[0] = (id >> 8) & 0xff; | ||
435 | sscanf(str, "%d", &i); | ||
436 | if (i > 31) | ||
437 | i = -1; | ||
438 | } | ||
439 | return i; | ||
440 | } | ||
441 | |||
442 | static inline void fadump_set_regval(struct pt_regs *regs, u64 reg_id, | ||
443 | u64 reg_val) | ||
444 | { | ||
445 | int i; | ||
446 | |||
447 | i = fadump_gpr_index(reg_id); | ||
448 | if (i >= 0) | ||
449 | regs->gpr[i] = (unsigned long)reg_val; | ||
450 | else if (reg_id == REG_ID("NIA")) | ||
451 | regs->nip = (unsigned long)reg_val; | ||
452 | else if (reg_id == REG_ID("MSR")) | ||
453 | regs->msr = (unsigned long)reg_val; | ||
454 | else if (reg_id == REG_ID("CTR")) | ||
455 | regs->ctr = (unsigned long)reg_val; | ||
456 | else if (reg_id == REG_ID("LR")) | ||
457 | regs->link = (unsigned long)reg_val; | ||
458 | else if (reg_id == REG_ID("XER")) | ||
459 | regs->xer = (unsigned long)reg_val; | ||
460 | else if (reg_id == REG_ID("CR")) | ||
461 | regs->ccr = (unsigned long)reg_val; | ||
462 | else if (reg_id == REG_ID("DAR")) | ||
463 | regs->dar = (unsigned long)reg_val; | ||
464 | else if (reg_id == REG_ID("DSISR")) | ||
465 | regs->dsisr = (unsigned long)reg_val; | ||
466 | } | ||
467 | |||
468 | static struct fadump_reg_entry* | ||
469 | fadump_read_registers(struct fadump_reg_entry *reg_entry, struct pt_regs *regs) | ||
470 | { | ||
471 | memset(regs, 0, sizeof(struct pt_regs)); | ||
472 | |||
473 | while (reg_entry->reg_id != REG_ID("CPUEND")) { | ||
474 | fadump_set_regval(regs, reg_entry->reg_id, | ||
475 | reg_entry->reg_value); | ||
476 | reg_entry++; | ||
477 | } | ||
478 | reg_entry++; | ||
479 | return reg_entry; | ||
480 | } | ||
481 | |||
482 | static u32 *fadump_append_elf_note(u32 *buf, char *name, unsigned type, | ||
483 | void *data, size_t data_len) | ||
484 | { | ||
485 | struct elf_note note; | ||
486 | |||
487 | note.n_namesz = strlen(name) + 1; | ||
488 | note.n_descsz = data_len; | ||
489 | note.n_type = type; | ||
490 | memcpy(buf, ¬e, sizeof(note)); | ||
491 | buf += (sizeof(note) + 3)/4; | ||
492 | memcpy(buf, name, note.n_namesz); | ||
493 | buf += (note.n_namesz + 3)/4; | ||
494 | memcpy(buf, data, note.n_descsz); | ||
495 | buf += (note.n_descsz + 3)/4; | ||
496 | |||
497 | return buf; | ||
498 | } | ||
499 | |||
500 | static void fadump_final_note(u32 *buf) | ||
501 | { | ||
502 | struct elf_note note; | ||
503 | |||
504 | note.n_namesz = 0; | ||
505 | note.n_descsz = 0; | ||
506 | note.n_type = 0; | ||
507 | memcpy(buf, ¬e, sizeof(note)); | ||
508 | } | ||
509 | |||
510 | static u32 *fadump_regs_to_elf_notes(u32 *buf, struct pt_regs *regs) | ||
511 | { | ||
512 | struct elf_prstatus prstatus; | ||
513 | |||
514 | memset(&prstatus, 0, sizeof(prstatus)); | ||
515 | /* | ||
516 | * FIXME: How do i get PID? Do I really need it? | ||
517 | * prstatus.pr_pid = ???? | ||
518 | */ | ||
519 | elf_core_copy_kernel_regs(&prstatus.pr_reg, regs); | ||
520 | buf = fadump_append_elf_note(buf, KEXEC_CORE_NOTE_NAME, NT_PRSTATUS, | ||
521 | &prstatus, sizeof(prstatus)); | ||
522 | return buf; | ||
523 | } | ||
524 | |||
525 | static void fadump_update_elfcore_header(char *bufp) | ||
526 | { | ||
527 | struct elfhdr *elf; | ||
528 | struct elf_phdr *phdr; | ||
529 | |||
530 | elf = (struct elfhdr *)bufp; | ||
531 | bufp += sizeof(struct elfhdr); | ||
532 | |||
533 | /* First note is a place holder for cpu notes info. */ | ||
534 | phdr = (struct elf_phdr *)bufp; | ||
535 | |||
536 | if (phdr->p_type == PT_NOTE) { | ||
537 | phdr->p_paddr = fw_dump.cpu_notes_buf; | ||
538 | phdr->p_offset = phdr->p_paddr; | ||
539 | phdr->p_filesz = fw_dump.cpu_notes_buf_size; | ||
540 | phdr->p_memsz = fw_dump.cpu_notes_buf_size; | ||
541 | } | ||
542 | return; | ||
543 | } | ||
544 | |||
545 | static void *fadump_cpu_notes_buf_alloc(unsigned long size) | ||
546 | { | ||
547 | void *vaddr; | ||
548 | struct page *page; | ||
549 | unsigned long order, count, i; | ||
550 | |||
551 | order = get_order(size); | ||
552 | vaddr = (void *)__get_free_pages(GFP_KERNEL|__GFP_ZERO, order); | ||
553 | if (!vaddr) | ||
554 | return NULL; | ||
555 | |||
556 | count = 1 << order; | ||
557 | page = virt_to_page(vaddr); | ||
558 | for (i = 0; i < count; i++) | ||
559 | SetPageReserved(page + i); | ||
560 | return vaddr; | ||
561 | } | ||
562 | |||
563 | static void fadump_cpu_notes_buf_free(unsigned long vaddr, unsigned long size) | ||
564 | { | ||
565 | struct page *page; | ||
566 | unsigned long order, count, i; | ||
567 | |||
568 | order = get_order(size); | ||
569 | count = 1 << order; | ||
570 | page = virt_to_page(vaddr); | ||
571 | for (i = 0; i < count; i++) | ||
572 | ClearPageReserved(page + i); | ||
573 | __free_pages(page, order); | ||
574 | } | ||
575 | |||
576 | /* | ||
577 | * Read CPU state dump data and convert it into ELF notes. | ||
578 | * The CPU dump starts with magic number "REGSAVE". NumCpusOffset should be | ||
579 | * used to access the data to allow for additional fields to be added without | ||
580 | * affecting compatibility. Each list of registers for a CPU starts with | ||
581 | * "CPUSTRT" and ends with "CPUEND". Each register entry is of 16 bytes, | ||
582 | * 8 Byte ASCII identifier and 8 Byte register value. The register entry | ||
583 | * with identifier "CPUSTRT" and "CPUEND" contains 4 byte cpu id as part | ||
584 | * of register value. For more details refer to PAPR document. | ||
585 | * | ||
586 | * Only for the crashing cpu we ignore the CPU dump data and get exact | ||
587 | * state from fadump crash info structure populated by first kernel at the | ||
588 | * time of crash. | ||
589 | */ | ||
590 | static int __init fadump_build_cpu_notes(const struct fadump_mem_struct *fdm) | ||
591 | { | ||
592 | struct fadump_reg_save_area_header *reg_header; | ||
593 | struct fadump_reg_entry *reg_entry; | ||
594 | struct fadump_crash_info_header *fdh = NULL; | ||
595 | void *vaddr; | ||
596 | unsigned long addr; | ||
597 | u32 num_cpus, *note_buf; | ||
598 | struct pt_regs regs; | ||
599 | int i, rc = 0, cpu = 0; | ||
600 | |||
601 | if (!fdm->cpu_state_data.bytes_dumped) | ||
602 | return -EINVAL; | ||
603 | |||
604 | addr = fdm->cpu_state_data.destination_address; | ||
605 | vaddr = __va(addr); | ||
606 | |||
607 | reg_header = vaddr; | ||
608 | if (reg_header->magic_number != REGSAVE_AREA_MAGIC) { | ||
609 | printk(KERN_ERR "Unable to read register save area.\n"); | ||
610 | return -ENOENT; | ||
611 | } | ||
612 | pr_debug("--------CPU State Data------------\n"); | ||
613 | pr_debug("Magic Number: %llx\n", reg_header->magic_number); | ||
614 | pr_debug("NumCpuOffset: %x\n", reg_header->num_cpu_offset); | ||
615 | |||
616 | vaddr += reg_header->num_cpu_offset; | ||
617 | num_cpus = *((u32 *)(vaddr)); | ||
618 | pr_debug("NumCpus : %u\n", num_cpus); | ||
619 | vaddr += sizeof(u32); | ||
620 | reg_entry = (struct fadump_reg_entry *)vaddr; | ||
621 | |||
622 | /* Allocate buffer to hold cpu crash notes. */ | ||
623 | fw_dump.cpu_notes_buf_size = num_cpus * sizeof(note_buf_t); | ||
624 | fw_dump.cpu_notes_buf_size = PAGE_ALIGN(fw_dump.cpu_notes_buf_size); | ||
625 | note_buf = fadump_cpu_notes_buf_alloc(fw_dump.cpu_notes_buf_size); | ||
626 | if (!note_buf) { | ||
627 | printk(KERN_ERR "Failed to allocate 0x%lx bytes for " | ||
628 | "cpu notes buffer\n", fw_dump.cpu_notes_buf_size); | ||
629 | return -ENOMEM; | ||
630 | } | ||
631 | fw_dump.cpu_notes_buf = __pa(note_buf); | ||
632 | |||
633 | pr_debug("Allocated buffer for cpu notes of size %ld at %p\n", | ||
634 | (num_cpus * sizeof(note_buf_t)), note_buf); | ||
635 | |||
636 | if (fw_dump.fadumphdr_addr) | ||
637 | fdh = __va(fw_dump.fadumphdr_addr); | ||
638 | |||
639 | for (i = 0; i < num_cpus; i++) { | ||
640 | if (reg_entry->reg_id != REG_ID("CPUSTRT")) { | ||
641 | printk(KERN_ERR "Unable to read CPU state data\n"); | ||
642 | rc = -ENOENT; | ||
643 | goto error_out; | ||
644 | } | ||
645 | /* Lower 4 bytes of reg_value contains logical cpu id */ | ||
646 | cpu = reg_entry->reg_value & FADUMP_CPU_ID_MASK; | ||
647 | if (!cpumask_test_cpu(cpu, &fdh->cpu_online_mask)) { | ||
648 | SKIP_TO_NEXT_CPU(reg_entry); | ||
649 | continue; | ||
650 | } | ||
651 | pr_debug("Reading register data for cpu %d...\n", cpu); | ||
652 | if (fdh && fdh->crashing_cpu == cpu) { | ||
653 | regs = fdh->regs; | ||
654 | note_buf = fadump_regs_to_elf_notes(note_buf, ®s); | ||
655 | SKIP_TO_NEXT_CPU(reg_entry); | ||
656 | } else { | ||
657 | reg_entry++; | ||
658 | reg_entry = fadump_read_registers(reg_entry, ®s); | ||
659 | note_buf = fadump_regs_to_elf_notes(note_buf, ®s); | ||
660 | } | ||
661 | } | ||
662 | fadump_final_note(note_buf); | ||
663 | |||
664 | pr_debug("Updating elfcore header (%llx) with cpu notes\n", | ||
665 | fdh->elfcorehdr_addr); | ||
666 | fadump_update_elfcore_header((char *)__va(fdh->elfcorehdr_addr)); | ||
667 | return 0; | ||
668 | |||
669 | error_out: | ||
670 | fadump_cpu_notes_buf_free((unsigned long)__va(fw_dump.cpu_notes_buf), | ||
671 | fw_dump.cpu_notes_buf_size); | ||
672 | fw_dump.cpu_notes_buf = 0; | ||
673 | fw_dump.cpu_notes_buf_size = 0; | ||
674 | return rc; | ||
675 | |||
676 | } | ||
677 | |||
678 | /* | ||
679 | * Validate and process the dump data stored by firmware before exporting | ||
680 | * it through '/proc/vmcore'. | ||
681 | */ | ||
682 | static int __init process_fadump(const struct fadump_mem_struct *fdm_active) | ||
683 | { | ||
684 | struct fadump_crash_info_header *fdh; | ||
685 | int rc = 0; | ||
686 | |||
687 | if (!fdm_active || !fw_dump.fadumphdr_addr) | ||
688 | return -EINVAL; | ||
689 | |||
690 | /* Check if the dump data is valid. */ | ||
691 | if ((fdm_active->header.dump_status_flag == FADUMP_ERROR_FLAG) || | ||
692 | (fdm_active->cpu_state_data.error_flags != 0) || | ||
693 | (fdm_active->rmr_region.error_flags != 0)) { | ||
694 | printk(KERN_ERR "Dump taken by platform is not valid\n"); | ||
695 | return -EINVAL; | ||
696 | } | ||
697 | if ((fdm_active->rmr_region.bytes_dumped != | ||
698 | fdm_active->rmr_region.source_len) || | ||
699 | !fdm_active->cpu_state_data.bytes_dumped) { | ||
700 | printk(KERN_ERR "Dump taken by platform is incomplete\n"); | ||
701 | return -EINVAL; | ||
702 | } | ||
703 | |||
704 | /* Validate the fadump crash info header */ | ||
705 | fdh = __va(fw_dump.fadumphdr_addr); | ||
706 | if (fdh->magic_number != FADUMP_CRASH_INFO_MAGIC) { | ||
707 | printk(KERN_ERR "Crash info header is not valid.\n"); | ||
708 | return -EINVAL; | ||
709 | } | ||
710 | |||
711 | rc = fadump_build_cpu_notes(fdm_active); | ||
712 | if (rc) | ||
713 | return rc; | ||
714 | |||
715 | /* | ||
716 | * We are done validating dump info and elfcore header is now ready | ||
717 | * to be exported. set elfcorehdr_addr so that vmcore module will | ||
718 | * export the elfcore header through '/proc/vmcore'. | ||
719 | */ | ||
720 | elfcorehdr_addr = fdh->elfcorehdr_addr; | ||
721 | |||
722 | return 0; | ||
723 | } | ||
724 | |||
725 | static inline void fadump_add_crash_memory(unsigned long long base, | ||
726 | unsigned long long end) | ||
727 | { | ||
728 | if (base == end) | ||
729 | return; | ||
730 | |||
731 | pr_debug("crash_memory_range[%d] [%#016llx-%#016llx], %#llx bytes\n", | ||
732 | crash_mem_ranges, base, end - 1, (end - base)); | ||
733 | crash_memory_ranges[crash_mem_ranges].base = base; | ||
734 | crash_memory_ranges[crash_mem_ranges].size = end - base; | ||
735 | crash_mem_ranges++; | ||
736 | } | ||
737 | |||
738 | static void fadump_exclude_reserved_area(unsigned long long start, | ||
739 | unsigned long long end) | ||
740 | { | ||
741 | unsigned long long ra_start, ra_end; | ||
742 | |||
743 | ra_start = fw_dump.reserve_dump_area_start; | ||
744 | ra_end = ra_start + fw_dump.reserve_dump_area_size; | ||
745 | |||
746 | if ((ra_start < end) && (ra_end > start)) { | ||
747 | if ((start < ra_start) && (end > ra_end)) { | ||
748 | fadump_add_crash_memory(start, ra_start); | ||
749 | fadump_add_crash_memory(ra_end, end); | ||
750 | } else if (start < ra_start) { | ||
751 | fadump_add_crash_memory(start, ra_start); | ||
752 | } else if (ra_end < end) { | ||
753 | fadump_add_crash_memory(ra_end, end); | ||
754 | } | ||
755 | } else | ||
756 | fadump_add_crash_memory(start, end); | ||
757 | } | ||
758 | |||
759 | static int fadump_init_elfcore_header(char *bufp) | ||
760 | { | ||
761 | struct elfhdr *elf; | ||
762 | |||
763 | elf = (struct elfhdr *) bufp; | ||
764 | bufp += sizeof(struct elfhdr); | ||
765 | memcpy(elf->e_ident, ELFMAG, SELFMAG); | ||
766 | elf->e_ident[EI_CLASS] = ELF_CLASS; | ||
767 | elf->e_ident[EI_DATA] = ELF_DATA; | ||
768 | elf->e_ident[EI_VERSION] = EV_CURRENT; | ||
769 | elf->e_ident[EI_OSABI] = ELF_OSABI; | ||
770 | memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD); | ||
771 | elf->e_type = ET_CORE; | ||
772 | elf->e_machine = ELF_ARCH; | ||
773 | elf->e_version = EV_CURRENT; | ||
774 | elf->e_entry = 0; | ||
775 | elf->e_phoff = sizeof(struct elfhdr); | ||
776 | elf->e_shoff = 0; | ||
777 | elf->e_flags = ELF_CORE_EFLAGS; | ||
778 | elf->e_ehsize = sizeof(struct elfhdr); | ||
779 | elf->e_phentsize = sizeof(struct elf_phdr); | ||
780 | elf->e_phnum = 0; | ||
781 | elf->e_shentsize = 0; | ||
782 | elf->e_shnum = 0; | ||
783 | elf->e_shstrndx = 0; | ||
784 | |||
785 | return 0; | ||
786 | } | ||
787 | |||
788 | /* | ||
789 | * Traverse through memblock structure and setup crash memory ranges. These | ||
790 | * ranges will be used create PT_LOAD program headers in elfcore header. | ||
791 | */ | ||
792 | static void fadump_setup_crash_memory_ranges(void) | ||
793 | { | ||
794 | struct memblock_region *reg; | ||
795 | unsigned long long start, end; | ||
796 | |||
797 | pr_debug("Setup crash memory ranges.\n"); | ||
798 | crash_mem_ranges = 0; | ||
799 | /* | ||
800 | * add the first memory chunk (RMA_START through boot_memory_size) as | ||
801 | * a separate memory chunk. The reason is, at the time crash firmware | ||
802 | * will move the content of this memory chunk to different location | ||
803 | * specified during fadump registration. We need to create a separate | ||
804 | * program header for this chunk with the correct offset. | ||
805 | */ | ||
806 | fadump_add_crash_memory(RMA_START, fw_dump.boot_memory_size); | ||
807 | |||
808 | for_each_memblock(memory, reg) { | ||
809 | start = (unsigned long long)reg->base; | ||
810 | end = start + (unsigned long long)reg->size; | ||
811 | if (start == RMA_START && end >= fw_dump.boot_memory_size) | ||
812 | start = fw_dump.boot_memory_size; | ||
813 | |||
814 | /* add this range excluding the reserved dump area. */ | ||
815 | fadump_exclude_reserved_area(start, end); | ||
816 | } | ||
817 | } | ||
818 | |||
819 | /* | ||
820 | * If the given physical address falls within the boot memory region then | ||
821 | * return the relocated address that points to the dump region reserved | ||
822 | * for saving initial boot memory contents. | ||
823 | */ | ||
824 | static inline unsigned long fadump_relocate(unsigned long paddr) | ||
825 | { | ||
826 | if (paddr > RMA_START && paddr < fw_dump.boot_memory_size) | ||
827 | return fdm.rmr_region.destination_address + paddr; | ||
828 | else | ||
829 | return paddr; | ||
830 | } | ||
831 | |||
832 | static int fadump_create_elfcore_headers(char *bufp) | ||
833 | { | ||
834 | struct elfhdr *elf; | ||
835 | struct elf_phdr *phdr; | ||
836 | int i; | ||
837 | |||
838 | fadump_init_elfcore_header(bufp); | ||
839 | elf = (struct elfhdr *)bufp; | ||
840 | bufp += sizeof(struct elfhdr); | ||
841 | |||
842 | /* | ||
843 | * setup ELF PT_NOTE, place holder for cpu notes info. The notes info | ||
844 | * will be populated during second kernel boot after crash. Hence | ||
845 | * this PT_NOTE will always be the first elf note. | ||
846 | * | ||
847 | * NOTE: Any new ELF note addition should be placed after this note. | ||
848 | */ | ||
849 | phdr = (struct elf_phdr *)bufp; | ||
850 | bufp += sizeof(struct elf_phdr); | ||
851 | phdr->p_type = PT_NOTE; | ||
852 | phdr->p_flags = 0; | ||
853 | phdr->p_vaddr = 0; | ||
854 | phdr->p_align = 0; | ||
855 | |||
856 | phdr->p_offset = 0; | ||
857 | phdr->p_paddr = 0; | ||
858 | phdr->p_filesz = 0; | ||
859 | phdr->p_memsz = 0; | ||
860 | |||
861 | (elf->e_phnum)++; | ||
862 | |||
863 | /* setup ELF PT_NOTE for vmcoreinfo */ | ||
864 | phdr = (struct elf_phdr *)bufp; | ||
865 | bufp += sizeof(struct elf_phdr); | ||
866 | phdr->p_type = PT_NOTE; | ||
867 | phdr->p_flags = 0; | ||
868 | phdr->p_vaddr = 0; | ||
869 | phdr->p_align = 0; | ||
870 | |||
871 | phdr->p_paddr = fadump_relocate(paddr_vmcoreinfo_note()); | ||
872 | phdr->p_offset = phdr->p_paddr; | ||
873 | phdr->p_memsz = vmcoreinfo_max_size; | ||
874 | phdr->p_filesz = vmcoreinfo_max_size; | ||
875 | |||
876 | /* Increment number of program headers. */ | ||
877 | (elf->e_phnum)++; | ||
878 | |||
879 | /* setup PT_LOAD sections. */ | ||
880 | |||
881 | for (i = 0; i < crash_mem_ranges; i++) { | ||
882 | unsigned long long mbase, msize; | ||
883 | mbase = crash_memory_ranges[i].base; | ||
884 | msize = crash_memory_ranges[i].size; | ||
885 | |||
886 | if (!msize) | ||
887 | continue; | ||
888 | |||
889 | phdr = (struct elf_phdr *)bufp; | ||
890 | bufp += sizeof(struct elf_phdr); | ||
891 | phdr->p_type = PT_LOAD; | ||
892 | phdr->p_flags = PF_R|PF_W|PF_X; | ||
893 | phdr->p_offset = mbase; | ||
894 | |||
895 | if (mbase == RMA_START) { | ||
896 | /* | ||
897 | * The entire RMA region will be moved by firmware | ||
898 | * to the specified destination_address. Hence set | ||
899 | * the correct offset. | ||
900 | */ | ||
901 | phdr->p_offset = fdm.rmr_region.destination_address; | ||
902 | } | ||
903 | |||
904 | phdr->p_paddr = mbase; | ||
905 | phdr->p_vaddr = (unsigned long)__va(mbase); | ||
906 | phdr->p_filesz = msize; | ||
907 | phdr->p_memsz = msize; | ||
908 | phdr->p_align = 0; | ||
909 | |||
910 | /* Increment number of program headers. */ | ||
911 | (elf->e_phnum)++; | ||
912 | } | ||
913 | return 0; | ||
914 | } | ||
915 | |||
916 | static unsigned long init_fadump_header(unsigned long addr) | ||
917 | { | ||
918 | struct fadump_crash_info_header *fdh; | ||
919 | |||
920 | if (!addr) | ||
921 | return 0; | ||
922 | |||
923 | fw_dump.fadumphdr_addr = addr; | ||
924 | fdh = __va(addr); | ||
925 | addr += sizeof(struct fadump_crash_info_header); | ||
926 | |||
927 | memset(fdh, 0, sizeof(struct fadump_crash_info_header)); | ||
928 | fdh->magic_number = FADUMP_CRASH_INFO_MAGIC; | ||
929 | fdh->elfcorehdr_addr = addr; | ||
930 | /* We will set the crashing cpu id in crash_fadump() during crash. */ | ||
931 | fdh->crashing_cpu = CPU_UNKNOWN; | ||
932 | |||
933 | return addr; | ||
934 | } | ||
935 | |||
936 | static void register_fadump(void) | ||
937 | { | ||
938 | unsigned long addr; | ||
939 | void *vaddr; | ||
940 | |||
941 | /* | ||
942 | * If no memory is reserved then we can not register for firmware- | ||
943 | * assisted dump. | ||
944 | */ | ||
945 | if (!fw_dump.reserve_dump_area_size) | ||
946 | return; | ||
947 | |||
948 | fadump_setup_crash_memory_ranges(); | ||
949 | |||
950 | addr = fdm.rmr_region.destination_address + fdm.rmr_region.source_len; | ||
951 | /* Initialize fadump crash info header. */ | ||
952 | addr = init_fadump_header(addr); | ||
953 | vaddr = __va(addr); | ||
954 | |||
955 | pr_debug("Creating ELF core headers at %#016lx\n", addr); | ||
956 | fadump_create_elfcore_headers(vaddr); | ||
957 | |||
958 | /* register the future kernel dump with firmware. */ | ||
959 | register_fw_dump(&fdm); | ||
960 | } | ||
961 | |||
962 | static int fadump_unregister_dump(struct fadump_mem_struct *fdm) | ||
963 | { | ||
964 | int rc = 0; | ||
965 | unsigned int wait_time; | ||
966 | |||
967 | pr_debug("Un-register firmware-assisted dump\n"); | ||
968 | |||
969 | /* TODO: Add upper time limit for the delay */ | ||
970 | do { | ||
971 | rc = rtas_call(fw_dump.ibm_configure_kernel_dump, 3, 1, NULL, | ||
972 | FADUMP_UNREGISTER, fdm, | ||
973 | sizeof(struct fadump_mem_struct)); | ||
974 | |||
975 | wait_time = rtas_busy_delay_time(rc); | ||
976 | if (wait_time) | ||
977 | mdelay(wait_time); | ||
978 | } while (wait_time); | ||
979 | |||
980 | if (rc) { | ||
981 | printk(KERN_ERR "Failed to un-register firmware-assisted dump." | ||
982 | " unexpected error(%d).\n", rc); | ||
983 | return rc; | ||
984 | } | ||
985 | fw_dump.dump_registered = 0; | ||
986 | return 0; | ||
987 | } | ||
988 | |||
989 | static int fadump_invalidate_dump(struct fadump_mem_struct *fdm) | ||
990 | { | ||
991 | int rc = 0; | ||
992 | unsigned int wait_time; | ||
993 | |||
994 | pr_debug("Invalidating firmware-assisted dump registration\n"); | ||
995 | |||
996 | /* TODO: Add upper time limit for the delay */ | ||
997 | do { | ||
998 | rc = rtas_call(fw_dump.ibm_configure_kernel_dump, 3, 1, NULL, | ||
999 | FADUMP_INVALIDATE, fdm, | ||
1000 | sizeof(struct fadump_mem_struct)); | ||
1001 | |||
1002 | wait_time = rtas_busy_delay_time(rc); | ||
1003 | if (wait_time) | ||
1004 | mdelay(wait_time); | ||
1005 | } while (wait_time); | ||
1006 | |||
1007 | if (rc) { | ||
1008 | printk(KERN_ERR "Failed to invalidate firmware-assisted dump " | ||
1009 | "rgistration. unexpected error(%d).\n", rc); | ||
1010 | return rc; | ||
1011 | } | ||
1012 | fw_dump.dump_active = 0; | ||
1013 | fdm_active = NULL; | ||
1014 | return 0; | ||
1015 | } | ||
1016 | |||
1017 | void fadump_cleanup(void) | ||
1018 | { | ||
1019 | /* Invalidate the registration only if dump is active. */ | ||
1020 | if (fw_dump.dump_active) { | ||
1021 | init_fadump_mem_struct(&fdm, | ||
1022 | fdm_active->cpu_state_data.destination_address); | ||
1023 | fadump_invalidate_dump(&fdm); | ||
1024 | } | ||
1025 | } | ||
1026 | |||
1027 | /* | ||
1028 | * Release the memory that was reserved in early boot to preserve the memory | ||
1029 | * contents. The released memory will be available for general use. | ||
1030 | */ | ||
1031 | static void fadump_release_memory(unsigned long begin, unsigned long end) | ||
1032 | { | ||
1033 | unsigned long addr; | ||
1034 | unsigned long ra_start, ra_end; | ||
1035 | |||
1036 | ra_start = fw_dump.reserve_dump_area_start; | ||
1037 | ra_end = ra_start + fw_dump.reserve_dump_area_size; | ||
1038 | |||
1039 | for (addr = begin; addr < end; addr += PAGE_SIZE) { | ||
1040 | /* | ||
1041 | * exclude the dump reserve area. Will reuse it for next | ||
1042 | * fadump registration. | ||
1043 | */ | ||
1044 | if (addr <= ra_end && ((addr + PAGE_SIZE) > ra_start)) | ||
1045 | continue; | ||
1046 | |||
1047 | ClearPageReserved(pfn_to_page(addr >> PAGE_SHIFT)); | ||
1048 | init_page_count(pfn_to_page(addr >> PAGE_SHIFT)); | ||
1049 | free_page((unsigned long)__va(addr)); | ||
1050 | totalram_pages++; | ||
1051 | } | ||
1052 | } | ||
1053 | |||
1054 | static void fadump_invalidate_release_mem(void) | ||
1055 | { | ||
1056 | unsigned long reserved_area_start, reserved_area_end; | ||
1057 | unsigned long destination_address; | ||
1058 | |||
1059 | mutex_lock(&fadump_mutex); | ||
1060 | if (!fw_dump.dump_active) { | ||
1061 | mutex_unlock(&fadump_mutex); | ||
1062 | return; | ||
1063 | } | ||
1064 | |||
1065 | destination_address = fdm_active->cpu_state_data.destination_address; | ||
1066 | fadump_cleanup(); | ||
1067 | mutex_unlock(&fadump_mutex); | ||
1068 | |||
1069 | /* | ||
1070 | * Save the current reserved memory bounds we will require them | ||
1071 | * later for releasing the memory for general use. | ||
1072 | */ | ||
1073 | reserved_area_start = fw_dump.reserve_dump_area_start; | ||
1074 | reserved_area_end = reserved_area_start + | ||
1075 | fw_dump.reserve_dump_area_size; | ||
1076 | /* | ||
1077 | * Setup reserve_dump_area_start and its size so that we can | ||
1078 | * reuse this reserved memory for Re-registration. | ||
1079 | */ | ||
1080 | fw_dump.reserve_dump_area_start = destination_address; | ||
1081 | fw_dump.reserve_dump_area_size = get_fadump_area_size(); | ||
1082 | |||
1083 | fadump_release_memory(reserved_area_start, reserved_area_end); | ||
1084 | if (fw_dump.cpu_notes_buf) { | ||
1085 | fadump_cpu_notes_buf_free( | ||
1086 | (unsigned long)__va(fw_dump.cpu_notes_buf), | ||
1087 | fw_dump.cpu_notes_buf_size); | ||
1088 | fw_dump.cpu_notes_buf = 0; | ||
1089 | fw_dump.cpu_notes_buf_size = 0; | ||
1090 | } | ||
1091 | /* Initialize the kernel dump memory structure for FAD registration. */ | ||
1092 | init_fadump_mem_struct(&fdm, fw_dump.reserve_dump_area_start); | ||
1093 | } | ||
1094 | |||
1095 | static ssize_t fadump_release_memory_store(struct kobject *kobj, | ||
1096 | struct kobj_attribute *attr, | ||
1097 | const char *buf, size_t count) | ||
1098 | { | ||
1099 | if (!fw_dump.dump_active) | ||
1100 | return -EPERM; | ||
1101 | |||
1102 | if (buf[0] == '1') { | ||
1103 | /* | ||
1104 | * Take away the '/proc/vmcore'. We are releasing the dump | ||
1105 | * memory, hence it will not be valid anymore. | ||
1106 | */ | ||
1107 | vmcore_cleanup(); | ||
1108 | fadump_invalidate_release_mem(); | ||
1109 | |||
1110 | } else | ||
1111 | return -EINVAL; | ||
1112 | return count; | ||
1113 | } | ||
1114 | |||
1115 | static ssize_t fadump_enabled_show(struct kobject *kobj, | ||
1116 | struct kobj_attribute *attr, | ||
1117 | char *buf) | ||
1118 | { | ||
1119 | return sprintf(buf, "%d\n", fw_dump.fadump_enabled); | ||
1120 | } | ||
1121 | |||
1122 | static ssize_t fadump_register_show(struct kobject *kobj, | ||
1123 | struct kobj_attribute *attr, | ||
1124 | char *buf) | ||
1125 | { | ||
1126 | return sprintf(buf, "%d\n", fw_dump.dump_registered); | ||
1127 | } | ||
1128 | |||
1129 | static ssize_t fadump_register_store(struct kobject *kobj, | ||
1130 | struct kobj_attribute *attr, | ||
1131 | const char *buf, size_t count) | ||
1132 | { | ||
1133 | int ret = 0; | ||
1134 | |||
1135 | if (!fw_dump.fadump_enabled || fdm_active) | ||
1136 | return -EPERM; | ||
1137 | |||
1138 | mutex_lock(&fadump_mutex); | ||
1139 | |||
1140 | switch (buf[0]) { | ||
1141 | case '0': | ||
1142 | if (fw_dump.dump_registered == 0) { | ||
1143 | ret = -EINVAL; | ||
1144 | goto unlock_out; | ||
1145 | } | ||
1146 | /* Un-register Firmware-assisted dump */ | ||
1147 | fadump_unregister_dump(&fdm); | ||
1148 | break; | ||
1149 | case '1': | ||
1150 | if (fw_dump.dump_registered == 1) { | ||
1151 | ret = -EINVAL; | ||
1152 | goto unlock_out; | ||
1153 | } | ||
1154 | /* Register Firmware-assisted dump */ | ||
1155 | register_fadump(); | ||
1156 | break; | ||
1157 | default: | ||
1158 | ret = -EINVAL; | ||
1159 | break; | ||
1160 | } | ||
1161 | |||
1162 | unlock_out: | ||
1163 | mutex_unlock(&fadump_mutex); | ||
1164 | return ret < 0 ? ret : count; | ||
1165 | } | ||
1166 | |||
1167 | static int fadump_region_show(struct seq_file *m, void *private) | ||
1168 | { | ||
1169 | const struct fadump_mem_struct *fdm_ptr; | ||
1170 | |||
1171 | if (!fw_dump.fadump_enabled) | ||
1172 | return 0; | ||
1173 | |||
1174 | mutex_lock(&fadump_mutex); | ||
1175 | if (fdm_active) | ||
1176 | fdm_ptr = fdm_active; | ||
1177 | else { | ||
1178 | mutex_unlock(&fadump_mutex); | ||
1179 | fdm_ptr = &fdm; | ||
1180 | } | ||
1181 | |||
1182 | seq_printf(m, | ||
1183 | "CPU : [%#016llx-%#016llx] %#llx bytes, " | ||
1184 | "Dumped: %#llx\n", | ||
1185 | fdm_ptr->cpu_state_data.destination_address, | ||
1186 | fdm_ptr->cpu_state_data.destination_address + | ||
1187 | fdm_ptr->cpu_state_data.source_len - 1, | ||
1188 | fdm_ptr->cpu_state_data.source_len, | ||
1189 | fdm_ptr->cpu_state_data.bytes_dumped); | ||
1190 | seq_printf(m, | ||
1191 | "HPTE: [%#016llx-%#016llx] %#llx bytes, " | ||
1192 | "Dumped: %#llx\n", | ||
1193 | fdm_ptr->hpte_region.destination_address, | ||
1194 | fdm_ptr->hpte_region.destination_address + | ||
1195 | fdm_ptr->hpte_region.source_len - 1, | ||
1196 | fdm_ptr->hpte_region.source_len, | ||
1197 | fdm_ptr->hpte_region.bytes_dumped); | ||
1198 | seq_printf(m, | ||
1199 | "DUMP: [%#016llx-%#016llx] %#llx bytes, " | ||
1200 | "Dumped: %#llx\n", | ||
1201 | fdm_ptr->rmr_region.destination_address, | ||
1202 | fdm_ptr->rmr_region.destination_address + | ||
1203 | fdm_ptr->rmr_region.source_len - 1, | ||
1204 | fdm_ptr->rmr_region.source_len, | ||
1205 | fdm_ptr->rmr_region.bytes_dumped); | ||
1206 | |||
1207 | if (!fdm_active || | ||
1208 | (fw_dump.reserve_dump_area_start == | ||
1209 | fdm_ptr->cpu_state_data.destination_address)) | ||
1210 | goto out; | ||
1211 | |||
1212 | /* Dump is active. Show reserved memory region. */ | ||
1213 | seq_printf(m, | ||
1214 | " : [%#016llx-%#016llx] %#llx bytes, " | ||
1215 | "Dumped: %#llx\n", | ||
1216 | (unsigned long long)fw_dump.reserve_dump_area_start, | ||
1217 | fdm_ptr->cpu_state_data.destination_address - 1, | ||
1218 | fdm_ptr->cpu_state_data.destination_address - | ||
1219 | fw_dump.reserve_dump_area_start, | ||
1220 | fdm_ptr->cpu_state_data.destination_address - | ||
1221 | fw_dump.reserve_dump_area_start); | ||
1222 | out: | ||
1223 | if (fdm_active) | ||
1224 | mutex_unlock(&fadump_mutex); | ||
1225 | return 0; | ||
1226 | } | ||
1227 | |||
1228 | static struct kobj_attribute fadump_release_attr = __ATTR(fadump_release_mem, | ||
1229 | 0200, NULL, | ||
1230 | fadump_release_memory_store); | ||
1231 | static struct kobj_attribute fadump_attr = __ATTR(fadump_enabled, | ||
1232 | 0444, fadump_enabled_show, | ||
1233 | NULL); | ||
1234 | static struct kobj_attribute fadump_register_attr = __ATTR(fadump_registered, | ||
1235 | 0644, fadump_register_show, | ||
1236 | fadump_register_store); | ||
1237 | |||
1238 | static int fadump_region_open(struct inode *inode, struct file *file) | ||
1239 | { | ||
1240 | return single_open(file, fadump_region_show, inode->i_private); | ||
1241 | } | ||
1242 | |||
1243 | static const struct file_operations fadump_region_fops = { | ||
1244 | .open = fadump_region_open, | ||
1245 | .read = seq_read, | ||
1246 | .llseek = seq_lseek, | ||
1247 | .release = single_release, | ||
1248 | }; | ||
1249 | |||
1250 | static void fadump_init_files(void) | ||
1251 | { | ||
1252 | struct dentry *debugfs_file; | ||
1253 | int rc = 0; | ||
1254 | |||
1255 | rc = sysfs_create_file(kernel_kobj, &fadump_attr.attr); | ||
1256 | if (rc) | ||
1257 | printk(KERN_ERR "fadump: unable to create sysfs file" | ||
1258 | " fadump_enabled (%d)\n", rc); | ||
1259 | |||
1260 | rc = sysfs_create_file(kernel_kobj, &fadump_register_attr.attr); | ||
1261 | if (rc) | ||
1262 | printk(KERN_ERR "fadump: unable to create sysfs file" | ||
1263 | " fadump_registered (%d)\n", rc); | ||
1264 | |||
1265 | debugfs_file = debugfs_create_file("fadump_region", 0444, | ||
1266 | powerpc_debugfs_root, NULL, | ||
1267 | &fadump_region_fops); | ||
1268 | if (!debugfs_file) | ||
1269 | printk(KERN_ERR "fadump: unable to create debugfs file" | ||
1270 | " fadump_region\n"); | ||
1271 | |||
1272 | if (fw_dump.dump_active) { | ||
1273 | rc = sysfs_create_file(kernel_kobj, &fadump_release_attr.attr); | ||
1274 | if (rc) | ||
1275 | printk(KERN_ERR "fadump: unable to create sysfs file" | ||
1276 | " fadump_release_mem (%d)\n", rc); | ||
1277 | } | ||
1278 | return; | ||
1279 | } | ||
1280 | |||
1281 | /* | ||
1282 | * Prepare for firmware-assisted dump. | ||
1283 | */ | ||
1284 | int __init setup_fadump(void) | ||
1285 | { | ||
1286 | if (!fw_dump.fadump_enabled) | ||
1287 | return 0; | ||
1288 | |||
1289 | if (!fw_dump.fadump_supported) { | ||
1290 | printk(KERN_ERR "Firmware-assisted dump is not supported on" | ||
1291 | " this hardware\n"); | ||
1292 | return 0; | ||
1293 | } | ||
1294 | |||
1295 | fadump_show_config(); | ||
1296 | /* | ||
1297 | * If dump data is available then see if it is valid and prepare for | ||
1298 | * saving it to the disk. | ||
1299 | */ | ||
1300 | if (fw_dump.dump_active) { | ||
1301 | /* | ||
1302 | * if dump process fails then invalidate the registration | ||
1303 | * and release memory before proceeding for re-registration. | ||
1304 | */ | ||
1305 | if (process_fadump(fdm_active) < 0) | ||
1306 | fadump_invalidate_release_mem(); | ||
1307 | } | ||
1308 | /* Initialize the kernel dump memory structure for FAD registration. */ | ||
1309 | else if (fw_dump.reserve_dump_area_size) | ||
1310 | init_fadump_mem_struct(&fdm, fw_dump.reserve_dump_area_start); | ||
1311 | fadump_init_files(); | ||
1312 | |||
1313 | return 1; | ||
1314 | } | ||
1315 | subsys_initcall(setup_fadump); | ||
diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S index 0654dba2c1f1..dc0488b6f6e1 100644 --- a/arch/powerpc/kernel/head_32.S +++ b/arch/powerpc/kernel/head_32.S | |||
@@ -395,7 +395,7 @@ DataAccess: | |||
395 | bl hash_page | 395 | bl hash_page |
396 | 1: lwz r5,_DSISR(r11) /* get DSISR value */ | 396 | 1: lwz r5,_DSISR(r11) /* get DSISR value */ |
397 | mfspr r4,SPRN_DAR | 397 | mfspr r4,SPRN_DAR |
398 | EXC_XFER_EE_LITE(0x300, handle_page_fault) | 398 | EXC_XFER_LITE(0x300, handle_page_fault) |
399 | 399 | ||
400 | 400 | ||
401 | /* Instruction access exception. */ | 401 | /* Instruction access exception. */ |
@@ -410,7 +410,7 @@ InstructionAccess: | |||
410 | bl hash_page | 410 | bl hash_page |
411 | 1: mr r4,r12 | 411 | 1: mr r4,r12 |
412 | mr r5,r9 | 412 | mr r5,r9 |
413 | EXC_XFER_EE_LITE(0x400, handle_page_fault) | 413 | EXC_XFER_LITE(0x400, handle_page_fault) |
414 | 414 | ||
415 | /* External interrupt */ | 415 | /* External interrupt */ |
416 | EXCEPTION(0x500, HardwareInterrupt, do_IRQ, EXC_XFER_LITE) | 416 | EXCEPTION(0x500, HardwareInterrupt, do_IRQ, EXC_XFER_LITE) |
diff --git a/arch/powerpc/kernel/head_40x.S b/arch/powerpc/kernel/head_40x.S index 872a6af83bad..4989661b710b 100644 --- a/arch/powerpc/kernel/head_40x.S +++ b/arch/powerpc/kernel/head_40x.S | |||
@@ -394,7 +394,7 @@ label: | |||
394 | NORMAL_EXCEPTION_PROLOG | 394 | NORMAL_EXCEPTION_PROLOG |
395 | mr r4,r12 /* Pass SRR0 as arg2 */ | 395 | mr r4,r12 /* Pass SRR0 as arg2 */ |
396 | li r5,0 /* Pass zero as arg3 */ | 396 | li r5,0 /* Pass zero as arg3 */ |
397 | EXC_XFER_EE_LITE(0x400, handle_page_fault) | 397 | EXC_XFER_LITE(0x400, handle_page_fault) |
398 | 398 | ||
399 | /* 0x0500 - External Interrupt Exception */ | 399 | /* 0x0500 - External Interrupt Exception */ |
400 | EXCEPTION(0x0500, HardwareInterrupt, do_IRQ, EXC_XFER_LITE) | 400 | EXCEPTION(0x0500, HardwareInterrupt, do_IRQ, EXC_XFER_LITE) |
@@ -747,7 +747,7 @@ DataAccess: | |||
747 | mfspr r5,SPRN_ESR /* Grab the ESR, save it, pass arg3 */ | 747 | mfspr r5,SPRN_ESR /* Grab the ESR, save it, pass arg3 */ |
748 | stw r5,_ESR(r11) | 748 | stw r5,_ESR(r11) |
749 | mfspr r4,SPRN_DEAR /* Grab the DEAR, save it, pass arg2 */ | 749 | mfspr r4,SPRN_DEAR /* Grab the DEAR, save it, pass arg2 */ |
750 | EXC_XFER_EE_LITE(0x300, handle_page_fault) | 750 | EXC_XFER_LITE(0x300, handle_page_fault) |
751 | 751 | ||
752 | /* Other PowerPC processors, namely those derived from the 6xx-series | 752 | /* Other PowerPC processors, namely those derived from the 6xx-series |
753 | * have vectors from 0x2100 through 0x2F00 defined, but marked as reserved. | 753 | * have vectors from 0x2100 through 0x2F00 defined, but marked as reserved. |
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S index 06c7251c1bf7..58bddee8e1e8 100644 --- a/arch/powerpc/kernel/head_64.S +++ b/arch/powerpc/kernel/head_64.S | |||
@@ -32,13 +32,13 @@ | |||
32 | #include <asm/cputable.h> | 32 | #include <asm/cputable.h> |
33 | #include <asm/setup.h> | 33 | #include <asm/setup.h> |
34 | #include <asm/hvcall.h> | 34 | #include <asm/hvcall.h> |
35 | #include <asm/iseries/lpar_map.h> | ||
36 | #include <asm/thread_info.h> | 35 | #include <asm/thread_info.h> |
37 | #include <asm/firmware.h> | 36 | #include <asm/firmware.h> |
38 | #include <asm/page_64.h> | 37 | #include <asm/page_64.h> |
39 | #include <asm/irqflags.h> | 38 | #include <asm/irqflags.h> |
40 | #include <asm/kvm_book3s_asm.h> | 39 | #include <asm/kvm_book3s_asm.h> |
41 | #include <asm/ptrace.h> | 40 | #include <asm/ptrace.h> |
41 | #include <asm/hw_irq.h> | ||
42 | 42 | ||
43 | /* The physical memory is laid out such that the secondary processor | 43 | /* The physical memory is laid out such that the secondary processor |
44 | * spin code sits at 0x0000...0x00ff. On server, the vectors follow | 44 | * spin code sits at 0x0000...0x00ff. On server, the vectors follow |
@@ -57,10 +57,6 @@ | |||
57 | * entry in r9 for debugging purposes | 57 | * entry in r9 for debugging purposes |
58 | * 2. Secondary processors enter at 0x60 with PIR in gpr3 | 58 | * 2. Secondary processors enter at 0x60 with PIR in gpr3 |
59 | * | 59 | * |
60 | * For iSeries: | ||
61 | * 1. The MMU is on (as it always is for iSeries) | ||
62 | * 2. The kernel is entered at system_reset_iSeries | ||
63 | * | ||
64 | * For Book3E processors: | 60 | * For Book3E processors: |
65 | * 1. The MMU is on running in AS0 in a state defined in ePAPR | 61 | * 1. The MMU is on running in AS0 in a state defined in ePAPR |
66 | * 2. The kernel is entered at __start | 62 | * 2. The kernel is entered at __start |
@@ -93,15 +89,6 @@ __secondary_hold_spinloop: | |||
93 | __secondary_hold_acknowledge: | 89 | __secondary_hold_acknowledge: |
94 | .llong 0x0 | 90 | .llong 0x0 |
95 | 91 | ||
96 | #ifdef CONFIG_PPC_ISERIES | ||
97 | /* | ||
98 | * At offset 0x20, there is a pointer to iSeries LPAR data. | ||
99 | * This is required by the hypervisor | ||
100 | */ | ||
101 | . = 0x20 | ||
102 | .llong hvReleaseData-KERNELBASE | ||
103 | #endif /* CONFIG_PPC_ISERIES */ | ||
104 | |||
105 | #ifdef CONFIG_RELOCATABLE | 92 | #ifdef CONFIG_RELOCATABLE |
106 | /* This flag is set to 1 by a loader if the kernel should run | 93 | /* This flag is set to 1 by a loader if the kernel should run |
107 | * at the loaded address instead of the linked address. This | 94 | * at the loaded address instead of the linked address. This |
@@ -564,7 +551,8 @@ _GLOBAL(pmac_secondary_start) | |||
564 | */ | 551 | */ |
565 | li r0,0 | 552 | li r0,0 |
566 | stb r0,PACASOFTIRQEN(r13) | 553 | stb r0,PACASOFTIRQEN(r13) |
567 | stb r0,PACAHARDIRQEN(r13) | 554 | li r0,PACA_IRQ_HARD_DIS |
555 | stb r0,PACAIRQHAPPENED(r13) | ||
568 | 556 | ||
569 | /* Create a temp kernel stack for use before relocation is on. */ | 557 | /* Create a temp kernel stack for use before relocation is on. */ |
570 | ld r1,PACAEMERGSP(r13) | 558 | ld r1,PACAEMERGSP(r13) |
@@ -582,7 +570,7 @@ _GLOBAL(pmac_secondary_start) | |||
582 | * 1. Processor number | 570 | * 1. Processor number |
583 | * 2. Segment table pointer (virtual address) | 571 | * 2. Segment table pointer (virtual address) |
584 | * On entry the following are set: | 572 | * On entry the following are set: |
585 | * r1 = stack pointer. vaddr for iSeries, raddr (temp stack) for pSeries | 573 | * r1 = stack pointer (real addr of temp stack) |
586 | * r24 = cpu# (in Linux terms) | 574 | * r24 = cpu# (in Linux terms) |
587 | * r13 = paca virtual address | 575 | * r13 = paca virtual address |
588 | * SPRG_PACA = paca virtual address | 576 | * SPRG_PACA = paca virtual address |
@@ -595,7 +583,7 @@ __secondary_start: | |||
595 | /* Set thread priority to MEDIUM */ | 583 | /* Set thread priority to MEDIUM */ |
596 | HMT_MEDIUM | 584 | HMT_MEDIUM |
597 | 585 | ||
598 | /* Initialize the kernel stack. Just a repeat for iSeries. */ | 586 | /* Initialize the kernel stack */ |
599 | LOAD_REG_ADDR(r3, current_set) | 587 | LOAD_REG_ADDR(r3, current_set) |
600 | sldi r28,r24,3 /* get current_set[cpu#] */ | 588 | sldi r28,r24,3 /* get current_set[cpu#] */ |
601 | ldx r14,r3,r28 | 589 | ldx r14,r3,r28 |
@@ -615,20 +603,16 @@ __secondary_start: | |||
615 | li r7,0 | 603 | li r7,0 |
616 | mtlr r7 | 604 | mtlr r7 |
617 | 605 | ||
606 | /* Mark interrupts soft and hard disabled (they might be enabled | ||
607 | * in the PACA when doing hotplug) | ||
608 | */ | ||
609 | stb r7,PACASOFTIRQEN(r13) | ||
610 | li r0,PACA_IRQ_HARD_DIS | ||
611 | stb r0,PACAIRQHAPPENED(r13) | ||
612 | |||
618 | /* enable MMU and jump to start_secondary */ | 613 | /* enable MMU and jump to start_secondary */ |
619 | LOAD_REG_ADDR(r3, .start_secondary_prolog) | 614 | LOAD_REG_ADDR(r3, .start_secondary_prolog) |
620 | LOAD_REG_IMMEDIATE(r4, MSR_KERNEL) | 615 | LOAD_REG_IMMEDIATE(r4, MSR_KERNEL) |
621 | #ifdef CONFIG_PPC_ISERIES | ||
622 | BEGIN_FW_FTR_SECTION | ||
623 | ori r4,r4,MSR_EE | ||
624 | li r8,1 | ||
625 | stb r8,PACAHARDIRQEN(r13) | ||
626 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) | ||
627 | #endif | ||
628 | BEGIN_FW_FTR_SECTION | ||
629 | stb r7,PACAHARDIRQEN(r13) | ||
630 | END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES) | ||
631 | stb r7,PACASOFTIRQEN(r13) | ||
632 | 616 | ||
633 | mtspr SPRN_SRR0,r3 | 617 | mtspr SPRN_SRR0,r3 |
634 | mtspr SPRN_SRR1,r4 | 618 | mtspr SPRN_SRR1,r4 |
@@ -771,22 +755,18 @@ _INIT_GLOBAL(start_here_common) | |||
771 | /* Load the TOC (virtual address) */ | 755 | /* Load the TOC (virtual address) */ |
772 | ld r2,PACATOC(r13) | 756 | ld r2,PACATOC(r13) |
773 | 757 | ||
758 | /* Do more system initializations in virtual mode */ | ||
774 | bl .setup_system | 759 | bl .setup_system |
775 | 760 | ||
776 | /* Load up the kernel context */ | 761 | /* Mark interrupts soft and hard disabled (they might be enabled |
777 | 5: | 762 | * in the PACA when doing hotplug) |
778 | li r5,0 | 763 | */ |
779 | stb r5,PACASOFTIRQEN(r13) /* Soft Disabled */ | 764 | li r0,0 |
780 | #ifdef CONFIG_PPC_ISERIES | 765 | stb r0,PACASOFTIRQEN(r13) |
781 | BEGIN_FW_FTR_SECTION | 766 | li r0,PACA_IRQ_HARD_DIS |
782 | mfmsr r5 | 767 | stb r0,PACAIRQHAPPENED(r13) |
783 | ori r5,r5,MSR_EE /* Hard Enabled on iSeries*/ | ||
784 | mtmsrd r5 | ||
785 | li r5,1 | ||
786 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) | ||
787 | #endif | ||
788 | stb r5,PACAHARDIRQEN(r13) /* Hard Disabled on others */ | ||
789 | 768 | ||
769 | /* Generic kernel entry */ | ||
790 | bl .start_kernel | 770 | bl .start_kernel |
791 | 771 | ||
792 | /* Not reached */ | 772 | /* Not reached */ |
diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S index b68cb173ba2c..b2a5860accfb 100644 --- a/arch/powerpc/kernel/head_8xx.S +++ b/arch/powerpc/kernel/head_8xx.S | |||
@@ -220,7 +220,7 @@ DataAccess: | |||
220 | mfspr r4,SPRN_DAR | 220 | mfspr r4,SPRN_DAR |
221 | li r10,0x00f0 | 221 | li r10,0x00f0 |
222 | mtspr SPRN_DAR,r10 /* Tag DAR, to be used in DTLB Error */ | 222 | mtspr SPRN_DAR,r10 /* Tag DAR, to be used in DTLB Error */ |
223 | EXC_XFER_EE_LITE(0x300, handle_page_fault) | 223 | EXC_XFER_LITE(0x300, handle_page_fault) |
224 | 224 | ||
225 | /* Instruction access exception. | 225 | /* Instruction access exception. |
226 | * This is "never generated" by the MPC8xx. We jump to it for other | 226 | * This is "never generated" by the MPC8xx. We jump to it for other |
@@ -231,7 +231,7 @@ InstructionAccess: | |||
231 | EXCEPTION_PROLOG | 231 | EXCEPTION_PROLOG |
232 | mr r4,r12 | 232 | mr r4,r12 |
233 | mr r5,r9 | 233 | mr r5,r9 |
234 | EXC_XFER_EE_LITE(0x400, handle_page_fault) | 234 | EXC_XFER_LITE(0x400, handle_page_fault) |
235 | 235 | ||
236 | /* External interrupt */ | 236 | /* External interrupt */ |
237 | EXCEPTION(0x500, HardwareInterrupt, do_IRQ, EXC_XFER_LITE) | 237 | EXCEPTION(0x500, HardwareInterrupt, do_IRQ, EXC_XFER_LITE) |
diff --git a/arch/powerpc/kernel/head_booke.h b/arch/powerpc/kernel/head_booke.h index fc921bf62e15..0e4175388f47 100644 --- a/arch/powerpc/kernel/head_booke.h +++ b/arch/powerpc/kernel/head_booke.h | |||
@@ -359,7 +359,7 @@ label: | |||
359 | mfspr r5,SPRN_ESR; /* Grab the ESR and save it */ \ | 359 | mfspr r5,SPRN_ESR; /* Grab the ESR and save it */ \ |
360 | stw r5,_ESR(r11); \ | 360 | stw r5,_ESR(r11); \ |
361 | mfspr r4,SPRN_DEAR; /* Grab the DEAR */ \ | 361 | mfspr r4,SPRN_DEAR; /* Grab the DEAR */ \ |
362 | EXC_XFER_EE_LITE(0x0300, handle_page_fault) | 362 | EXC_XFER_LITE(0x0300, handle_page_fault) |
363 | 363 | ||
364 | #define INSTRUCTION_STORAGE_EXCEPTION \ | 364 | #define INSTRUCTION_STORAGE_EXCEPTION \ |
365 | START_EXCEPTION(InstructionStorage) \ | 365 | START_EXCEPTION(InstructionStorage) \ |
@@ -368,7 +368,7 @@ label: | |||
368 | stw r5,_ESR(r11); \ | 368 | stw r5,_ESR(r11); \ |
369 | mr r4,r12; /* Pass SRR0 as arg2 */ \ | 369 | mr r4,r12; /* Pass SRR0 as arg2 */ \ |
370 | li r5,0; /* Pass zero as arg3 */ \ | 370 | li r5,0; /* Pass zero as arg3 */ \ |
371 | EXC_XFER_EE_LITE(0x0400, handle_page_fault) | 371 | EXC_XFER_LITE(0x0400, handle_page_fault) |
372 | 372 | ||
373 | #define ALIGNMENT_EXCEPTION \ | 373 | #define ALIGNMENT_EXCEPTION \ |
374 | START_EXCEPTION(Alignment) \ | 374 | START_EXCEPTION(Alignment) \ |
diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S index d5d78c4ceef6..28e62598d0e8 100644 --- a/arch/powerpc/kernel/head_fsl_booke.S +++ b/arch/powerpc/kernel/head_fsl_booke.S | |||
@@ -319,7 +319,7 @@ interrupt_base: | |||
319 | mfspr r4,SPRN_DEAR /* Grab the DEAR, save it, pass arg2 */ | 319 | mfspr r4,SPRN_DEAR /* Grab the DEAR, save it, pass arg2 */ |
320 | andis. r10,r5,(ESR_ILK|ESR_DLK)@h | 320 | andis. r10,r5,(ESR_ILK|ESR_DLK)@h |
321 | bne 1f | 321 | bne 1f |
322 | EXC_XFER_EE_LITE(0x0300, handle_page_fault) | 322 | EXC_XFER_LITE(0x0300, handle_page_fault) |
323 | 1: | 323 | 1: |
324 | addi r3,r1,STACK_FRAME_OVERHEAD | 324 | addi r3,r1,STACK_FRAME_OVERHEAD |
325 | EXC_XFER_EE_LITE(0x0300, CacheLockingException) | 325 | EXC_XFER_EE_LITE(0x0300, CacheLockingException) |
diff --git a/arch/powerpc/kernel/idle.c b/arch/powerpc/kernel/idle.c index c97fc60c790c..e8e821146f38 100644 --- a/arch/powerpc/kernel/idle.c +++ b/arch/powerpc/kernel/idle.c | |||
@@ -84,7 +84,11 @@ void cpu_idle(void) | |||
84 | 84 | ||
85 | start_critical_timings(); | 85 | start_critical_timings(); |
86 | 86 | ||
87 | local_irq_enable(); | 87 | /* Some power_save functions return with |
88 | * interrupts enabled, some don't. | ||
89 | */ | ||
90 | if (irqs_disabled()) | ||
91 | local_irq_enable(); | ||
88 | set_thread_flag(TIF_POLLING_NRFLAG); | 92 | set_thread_flag(TIF_POLLING_NRFLAG); |
89 | 93 | ||
90 | } else { | 94 | } else { |
diff --git a/arch/powerpc/kernel/idle_book3e.S b/arch/powerpc/kernel/idle_book3e.S index 16c002d6bdf1..ff007b59448d 100644 --- a/arch/powerpc/kernel/idle_book3e.S +++ b/arch/powerpc/kernel/idle_book3e.S | |||
@@ -29,43 +29,30 @@ _GLOBAL(book3e_idle) | |||
29 | wrteei 0 | 29 | wrteei 0 |
30 | 30 | ||
31 | /* Now check if an interrupt came in while we were soft disabled | 31 | /* Now check if an interrupt came in while we were soft disabled |
32 | * since we may otherwise lose it (doorbells etc...). We know | 32 | * since we may otherwise lose it (doorbells etc...). |
33 | * that since PACAHARDIRQEN will have been cleared in that case. | ||
34 | */ | 33 | */ |
35 | lbz r3,PACAHARDIRQEN(r13) | 34 | lbz r3,PACAIRQHAPPENED(r13) |
36 | cmpwi cr0,r3,0 | 35 | cmpwi cr0,r3,0 |
37 | beqlr | 36 | bnelr |
38 | 37 | ||
39 | /* Now we are going to mark ourselves as soft and hard enables in | 38 | /* Now we are going to mark ourselves as soft and hard enabled in |
40 | * order to be able to take interrupts while asleep. We inform lockdep | 39 | * order to be able to take interrupts while asleep. We inform lockdep |
41 | * of that. We don't actually turn interrupts on just yet tho. | 40 | * of that. We don't actually turn interrupts on just yet tho. |
42 | */ | 41 | */ |
43 | #ifdef CONFIG_TRACE_IRQFLAGS | 42 | #ifdef CONFIG_TRACE_IRQFLAGS |
44 | stdu r1,-128(r1) | 43 | stdu r1,-128(r1) |
45 | bl .trace_hardirqs_on | 44 | bl .trace_hardirqs_on |
45 | addi r1,r1,128 | ||
46 | #endif | 46 | #endif |
47 | li r0,1 | 47 | li r0,1 |
48 | stb r0,PACASOFTIRQEN(r13) | 48 | stb r0,PACASOFTIRQEN(r13) |
49 | stb r0,PACAHARDIRQEN(r13) | ||
50 | 49 | ||
51 | /* Interrupts will make use return to LR, so get something we want | 50 | /* Interrupts will make use return to LR, so get something we want |
52 | * in there | 51 | * in there |
53 | */ | 52 | */ |
54 | bl 1f | 53 | bl 1f |
55 | 54 | ||
56 | /* Hard disable interrupts again */ | 55 | /* And return (interrupts are on) */ |
57 | wrteei 0 | ||
58 | |||
59 | /* Mark them off again in the PACA as well */ | ||
60 | li r0,0 | ||
61 | stb r0,PACASOFTIRQEN(r13) | ||
62 | stb r0,PACAHARDIRQEN(r13) | ||
63 | |||
64 | /* Tell lockdep about it */ | ||
65 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
66 | bl .trace_hardirqs_off | ||
67 | addi r1,r1,128 | ||
68 | #endif | ||
69 | ld r0,16(r1) | 56 | ld r0,16(r1) |
70 | mtlr r0 | 57 | mtlr r0 |
71 | blr | 58 | blr |
diff --git a/arch/powerpc/kernel/idle_power4.S b/arch/powerpc/kernel/idle_power4.S index ba3195478600..2c71b0fc9f91 100644 --- a/arch/powerpc/kernel/idle_power4.S +++ b/arch/powerpc/kernel/idle_power4.S | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <asm/thread_info.h> | 14 | #include <asm/thread_info.h> |
15 | #include <asm/ppc_asm.h> | 15 | #include <asm/ppc_asm.h> |
16 | #include <asm/asm-offsets.h> | 16 | #include <asm/asm-offsets.h> |
17 | #include <asm/irqflags.h> | ||
17 | 18 | ||
18 | #undef DEBUG | 19 | #undef DEBUG |
19 | 20 | ||
@@ -29,14 +30,31 @@ END_FTR_SECTION_IFCLR(CPU_FTR_CAN_NAP) | |||
29 | cmpwi 0,r4,0 | 30 | cmpwi 0,r4,0 |
30 | beqlr | 31 | beqlr |
31 | 32 | ||
32 | /* Go to NAP now */ | 33 | /* Hard disable interrupts */ |
33 | mfmsr r7 | 34 | mfmsr r7 |
34 | rldicl r0,r7,48,1 | 35 | rldicl r0,r7,48,1 |
35 | rotldi r0,r0,16 | 36 | rotldi r0,r0,16 |
36 | mtmsrd r0,1 /* hard-disable interrupts */ | 37 | mtmsrd r0,1 |
38 | |||
39 | /* Check if something happened while soft-disabled */ | ||
40 | lbz r0,PACAIRQHAPPENED(r13) | ||
41 | cmpwi cr0,r0,0 | ||
42 | bnelr | ||
43 | |||
44 | /* Soft-enable interrupts */ | ||
45 | #ifdef CONFIG_TRACE_IRQFLAGS | ||
46 | mflr r0 | ||
47 | std r0,16(r1) | ||
48 | stdu r1,-128(r1) | ||
49 | bl .trace_hardirqs_on | ||
50 | addi r1,r1,128 | ||
51 | ld r0,16(r1) | ||
52 | mtlr r0 | ||
53 | mfmsr r7 | ||
54 | #endif /* CONFIG_TRACE_IRQFLAGS */ | ||
55 | |||
37 | li r0,1 | 56 | li r0,1 |
38 | stb r0,PACASOFTIRQEN(r13) /* we'll hard-enable shortly */ | 57 | stb r0,PACASOFTIRQEN(r13) /* we'll hard-enable shortly */ |
39 | stb r0,PACAHARDIRQEN(r13) | ||
40 | BEGIN_FTR_SECTION | 58 | BEGIN_FTR_SECTION |
41 | DSSALL | 59 | DSSALL |
42 | sync | 60 | sync |
diff --git a/arch/powerpc/kernel/idle_power7.S b/arch/powerpc/kernel/idle_power7.S index fcdff198da4b..0cdc9a392839 100644 --- a/arch/powerpc/kernel/idle_power7.S +++ b/arch/powerpc/kernel/idle_power7.S | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * This file contains the power_save function for 970-family CPUs. | 2 | * This file contains the power_save function for Power7 CPUs. |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or | 4 | * This program is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU General Public License | 5 | * modify it under the terms of the GNU General Public License |
@@ -15,6 +15,7 @@ | |||
15 | #include <asm/ppc_asm.h> | 15 | #include <asm/ppc_asm.h> |
16 | #include <asm/asm-offsets.h> | 16 | #include <asm/asm-offsets.h> |
17 | #include <asm/ppc-opcode.h> | 17 | #include <asm/ppc-opcode.h> |
18 | #include <asm/hw_irq.h> | ||
18 | 19 | ||
19 | #undef DEBUG | 20 | #undef DEBUG |
20 | 21 | ||
@@ -51,9 +52,25 @@ _GLOBAL(power7_idle) | |||
51 | rldicl r9,r9,48,1 | 52 | rldicl r9,r9,48,1 |
52 | rotldi r9,r9,16 | 53 | rotldi r9,r9,16 |
53 | mtmsrd r9,1 /* hard-disable interrupts */ | 54 | mtmsrd r9,1 /* hard-disable interrupts */ |
55 | |||
56 | /* Check if something happened while soft-disabled */ | ||
57 | lbz r0,PACAIRQHAPPENED(r13) | ||
58 | cmpwi cr0,r0,0 | ||
59 | beq 1f | ||
60 | addi r1,r1,INT_FRAME_SIZE | ||
61 | ld r0,16(r1) | ||
62 | mtlr r0 | ||
63 | blr | ||
64 | |||
65 | 1: /* We mark irqs hard disabled as this is the state we'll | ||
66 | * be in when returning and we need to tell arch_local_irq_restore() | ||
67 | * about it | ||
68 | */ | ||
69 | li r0,PACA_IRQ_HARD_DIS | ||
70 | stb r0,PACAIRQHAPPENED(r13) | ||
71 | |||
72 | /* We haven't lost state ... yet */ | ||
54 | li r0,0 | 73 | li r0,0 |
55 | stb r0,PACASOFTIRQEN(r13) /* we'll hard-enable shortly */ | ||
56 | stb r0,PACAHARDIRQEN(r13) | ||
57 | stb r0,PACA_NAPSTATELOST(r13) | 74 | stb r0,PACA_NAPSTATELOST(r13) |
58 | 75 | ||
59 | /* Continue saving state */ | 76 | /* Continue saving state */ |
diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c index 0cfcf98aafca..359f078571c7 100644 --- a/arch/powerpc/kernel/iommu.c +++ b/arch/powerpc/kernel/iommu.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <asm/pci-bridge.h> | 39 | #include <asm/pci-bridge.h> |
40 | #include <asm/machdep.h> | 40 | #include <asm/machdep.h> |
41 | #include <asm/kdump.h> | 41 | #include <asm/kdump.h> |
42 | #include <asm/fadump.h> | ||
42 | 43 | ||
43 | #define DBG(...) | 44 | #define DBG(...) |
44 | 45 | ||
@@ -445,7 +446,12 @@ void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist, | |||
445 | 446 | ||
446 | static void iommu_table_clear(struct iommu_table *tbl) | 447 | static void iommu_table_clear(struct iommu_table *tbl) |
447 | { | 448 | { |
448 | if (!is_kdump_kernel()) { | 449 | /* |
450 | * In case of firmware assisted dump system goes through clean | ||
451 | * reboot process at the time of system crash. Hence it's safe to | ||
452 | * clear the TCE entries if firmware assisted dump is active. | ||
453 | */ | ||
454 | if (!is_kdump_kernel() || is_fadump_active()) { | ||
449 | /* Clear the table in case firmware left allocations in it */ | 455 | /* Clear the table in case firmware left allocations in it */ |
450 | ppc_md.tce_free(tbl, tbl->it_offset, tbl->it_size); | 456 | ppc_md.tce_free(tbl, tbl->it_offset, tbl->it_size); |
451 | return; | 457 | return; |
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index bdfb3eee3e6f..a3d128e94cff 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c | |||
@@ -93,20 +93,16 @@ extern int tau_interrupts(int); | |||
93 | 93 | ||
94 | #ifdef CONFIG_PPC64 | 94 | #ifdef CONFIG_PPC64 |
95 | 95 | ||
96 | #ifndef CONFIG_SPARSE_IRQ | ||
97 | EXPORT_SYMBOL(irq_desc); | ||
98 | #endif | ||
99 | |||
100 | int distribute_irqs = 1; | 96 | int distribute_irqs = 1; |
101 | 97 | ||
102 | static inline notrace unsigned long get_hard_enabled(void) | 98 | static inline notrace unsigned long get_irq_happened(void) |
103 | { | 99 | { |
104 | unsigned long enabled; | 100 | unsigned long happened; |
105 | 101 | ||
106 | __asm__ __volatile__("lbz %0,%1(13)" | 102 | __asm__ __volatile__("lbz %0,%1(13)" |
107 | : "=r" (enabled) : "i" (offsetof(struct paca_struct, hard_enabled))); | 103 | : "=r" (happened) : "i" (offsetof(struct paca_struct, irq_happened))); |
108 | 104 | ||
109 | return enabled; | 105 | return happened; |
110 | } | 106 | } |
111 | 107 | ||
112 | static inline notrace void set_soft_enabled(unsigned long enable) | 108 | static inline notrace void set_soft_enabled(unsigned long enable) |
@@ -115,88 +111,162 @@ static inline notrace void set_soft_enabled(unsigned long enable) | |||
115 | : : "r" (enable), "i" (offsetof(struct paca_struct, soft_enabled))); | 111 | : : "r" (enable), "i" (offsetof(struct paca_struct, soft_enabled))); |
116 | } | 112 | } |
117 | 113 | ||
118 | static inline notrace void decrementer_check_overflow(void) | 114 | static inline notrace int decrementer_check_overflow(void) |
119 | { | 115 | { |
120 | u64 now = get_tb_or_rtc(); | 116 | u64 now = get_tb_or_rtc(); |
121 | u64 *next_tb; | 117 | u64 *next_tb = &__get_cpu_var(decrementers_next_tb); |
122 | 118 | ||
123 | preempt_disable(); | ||
124 | next_tb = &__get_cpu_var(decrementers_next_tb); | ||
125 | |||
126 | if (now >= *next_tb) | 119 | if (now >= *next_tb) |
127 | set_dec(1); | 120 | set_dec(1); |
128 | preempt_enable(); | 121 | return now >= *next_tb; |
129 | } | 122 | } |
130 | 123 | ||
131 | notrace void arch_local_irq_restore(unsigned long en) | 124 | /* This is called whenever we are re-enabling interrupts |
125 | * and returns either 0 (nothing to do) or 500/900 if there's | ||
126 | * either an EE or a DEC to generate. | ||
127 | * | ||
128 | * This is called in two contexts: From arch_local_irq_restore() | ||
129 | * before soft-enabling interrupts, and from the exception exit | ||
130 | * path when returning from an interrupt from a soft-disabled to | ||
131 | * a soft enabled context. In both case we have interrupts hard | ||
132 | * disabled. | ||
133 | * | ||
134 | * We take care of only clearing the bits we handled in the | ||
135 | * PACA irq_happened field since we can only re-emit one at a | ||
136 | * time and we don't want to "lose" one. | ||
137 | */ | ||
138 | notrace unsigned int __check_irq_replay(void) | ||
132 | { | 139 | { |
133 | /* | 140 | /* |
134 | * get_paca()->soft_enabled = en; | 141 | * We use local_paca rather than get_paca() to avoid all |
135 | * Is it ever valid to use local_irq_restore(0) when soft_enabled is 1? | 142 | * the debug_smp_processor_id() business in this low level |
136 | * That was allowed before, and in such a case we do need to take care | 143 | * function |
137 | * that gcc will set soft_enabled directly via r13, not choose to use | ||
138 | * an intermediate register, lest we're preempted to a different cpu. | ||
139 | */ | 144 | */ |
140 | set_soft_enabled(en); | 145 | unsigned char happened = local_paca->irq_happened; |
141 | if (!en) | ||
142 | return; | ||
143 | 146 | ||
144 | #ifdef CONFIG_PPC_STD_MMU_64 | 147 | /* Clear bit 0 which we wouldn't clear otherwise */ |
145 | if (firmware_has_feature(FW_FEATURE_ISERIES)) { | 148 | local_paca->irq_happened &= ~PACA_IRQ_HARD_DIS; |
146 | /* | 149 | |
147 | * Do we need to disable preemption here? Not really: in the | 150 | /* |
148 | * unlikely event that we're preempted to a different cpu in | 151 | * Force the delivery of pending soft-disabled interrupts on PS3. |
149 | * between getting r13, loading its lppaca_ptr, and loading | 152 | * Any HV call will have this side effect. |
150 | * its any_int, we might call iseries_handle_interrupts without | 153 | */ |
151 | * an interrupt pending on the new cpu, but that's no disaster, | 154 | if (firmware_has_feature(FW_FEATURE_PS3_LV1)) { |
152 | * is it? And the business of preempting us off the old cpu | 155 | u64 tmp, tmp2; |
153 | * would itself involve a local_irq_restore which handles the | 156 | lv1_get_version_info(&tmp, &tmp2); |
154 | * interrupt to that cpu. | ||
155 | * | ||
156 | * But use "local_paca->lppaca_ptr" instead of "get_lppaca()" | ||
157 | * to avoid any preemption checking added into get_paca(). | ||
158 | */ | ||
159 | if (local_paca->lppaca_ptr->int_dword.any_int) | ||
160 | iseries_handle_interrupts(); | ||
161 | } | 157 | } |
162 | #endif /* CONFIG_PPC_STD_MMU_64 */ | ||
163 | 158 | ||
164 | /* | 159 | /* |
165 | * if (get_paca()->hard_enabled) return; | 160 | * We may have missed a decrementer interrupt. We check the |
166 | * But again we need to take care that gcc gets hard_enabled directly | 161 | * decrementer itself rather than the paca irq_happened field |
167 | * via r13, not choose to use an intermediate register, lest we're | 162 | * in case we also had a rollover while hard disabled |
168 | * preempted to a different cpu in between the two instructions. | 163 | */ |
164 | local_paca->irq_happened &= ~PACA_IRQ_DEC; | ||
165 | if (decrementer_check_overflow()) | ||
166 | return 0x900; | ||
167 | |||
168 | /* Finally check if an external interrupt happened */ | ||
169 | local_paca->irq_happened &= ~PACA_IRQ_EE; | ||
170 | if (happened & PACA_IRQ_EE) | ||
171 | return 0x500; | ||
172 | |||
173 | #ifdef CONFIG_PPC_BOOK3E | ||
174 | /* Finally check if an EPR external interrupt happened | ||
175 | * this bit is typically set if we need to handle another | ||
176 | * "edge" interrupt from within the MPIC "EPR" handler | ||
169 | */ | 177 | */ |
170 | if (get_hard_enabled()) | 178 | local_paca->irq_happened &= ~PACA_IRQ_EE_EDGE; |
179 | if (happened & PACA_IRQ_EE_EDGE) | ||
180 | return 0x500; | ||
181 | |||
182 | local_paca->irq_happened &= ~PACA_IRQ_DBELL; | ||
183 | if (happened & PACA_IRQ_DBELL) | ||
184 | return 0x280; | ||
185 | #endif /* CONFIG_PPC_BOOK3E */ | ||
186 | |||
187 | /* There should be nothing left ! */ | ||
188 | BUG_ON(local_paca->irq_happened != 0); | ||
189 | |||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | notrace void arch_local_irq_restore(unsigned long en) | ||
194 | { | ||
195 | unsigned char irq_happened; | ||
196 | unsigned int replay; | ||
197 | |||
198 | /* Write the new soft-enabled value */ | ||
199 | set_soft_enabled(en); | ||
200 | if (!en) | ||
201 | return; | ||
202 | /* | ||
203 | * From this point onward, we can take interrupts, preempt, | ||
204 | * etc... unless we got hard-disabled. We check if an event | ||
205 | * happened. If none happened, we know we can just return. | ||
206 | * | ||
207 | * We may have preempted before the check below, in which case | ||
208 | * we are checking the "new" CPU instead of the old one. This | ||
209 | * is only a problem if an event happened on the "old" CPU. | ||
210 | * | ||
211 | * External interrupt events on non-iseries will have caused | ||
212 | * interrupts to be hard-disabled, so there is no problem, we | ||
213 | * cannot have preempted. | ||
214 | */ | ||
215 | irq_happened = get_irq_happened(); | ||
216 | if (!irq_happened) | ||
171 | return; | 217 | return; |
172 | 218 | ||
173 | /* | 219 | /* |
174 | * Need to hard-enable interrupts here. Since currently disabled, | 220 | * We need to hard disable to get a trusted value from |
175 | * no need to take further asm precautions against preemption; but | 221 | * __check_irq_replay(). We also need to soft-disable |
176 | * use local_paca instead of get_paca() to avoid preemption checking. | 222 | * again to avoid warnings in there due to the use of |
223 | * per-cpu variables. | ||
224 | * | ||
225 | * We know that if the value in irq_happened is exactly 0x01 | ||
226 | * then we are already hard disabled (there are other less | ||
227 | * common cases that we'll ignore for now), so we skip the | ||
228 | * (expensive) mtmsrd. | ||
177 | */ | 229 | */ |
178 | local_paca->hard_enabled = en; | 230 | if (unlikely(irq_happened != PACA_IRQ_HARD_DIS)) |
231 | __hard_irq_disable(); | ||
232 | set_soft_enabled(0); | ||
179 | 233 | ||
180 | /* | 234 | /* |
181 | * Trigger the decrementer if we have a pending event. Some processors | 235 | * Check if anything needs to be re-emitted. We haven't |
182 | * only trigger on edge transitions of the sign bit. We might also | 236 | * soft-enabled yet to avoid warnings in decrementer_check_overflow |
183 | * have disabled interrupts long enough that the decrementer wrapped | 237 | * accessing per-cpu variables |
184 | * to positive. | ||
185 | */ | 238 | */ |
186 | decrementer_check_overflow(); | 239 | replay = __check_irq_replay(); |
240 | |||
241 | /* We can soft-enable now */ | ||
242 | set_soft_enabled(1); | ||
187 | 243 | ||
188 | /* | 244 | /* |
189 | * Force the delivery of pending soft-disabled interrupts on PS3. | 245 | * And replay if we have to. This will return with interrupts |
190 | * Any HV call will have this side effect. | 246 | * hard-enabled. |
191 | */ | 247 | */ |
192 | if (firmware_has_feature(FW_FEATURE_PS3_LV1)) { | 248 | if (replay) { |
193 | u64 tmp, tmp2; | 249 | __replay_interrupt(replay); |
194 | lv1_get_version_info(&tmp, &tmp2); | 250 | return; |
195 | } | 251 | } |
196 | 252 | ||
253 | /* Finally, let's ensure we are hard enabled */ | ||
197 | __hard_irq_enable(); | 254 | __hard_irq_enable(); |
198 | } | 255 | } |
199 | EXPORT_SYMBOL(arch_local_irq_restore); | 256 | EXPORT_SYMBOL(arch_local_irq_restore); |
257 | |||
258 | /* | ||
259 | * This is specifically called by assembly code to re-enable interrupts | ||
260 | * if they are currently disabled. This is typically called before | ||
261 | * schedule() or do_signal() when returning to userspace. We do it | ||
262 | * in C to avoid the burden of dealing with lockdep etc... | ||
263 | */ | ||
264 | void restore_interrupts(void) | ||
265 | { | ||
266 | if (irqs_disabled()) | ||
267 | local_irq_enable(); | ||
268 | } | ||
269 | |||
200 | #endif /* CONFIG_PPC64 */ | 270 | #endif /* CONFIG_PPC64 */ |
201 | 271 | ||
202 | int arch_show_interrupts(struct seq_file *p, int prec) | 272 | int arch_show_interrupts(struct seq_file *p, int prec) |
@@ -364,8 +434,17 @@ void do_IRQ(struct pt_regs *regs) | |||
364 | 434 | ||
365 | check_stack_overflow(); | 435 | check_stack_overflow(); |
366 | 436 | ||
437 | /* | ||
438 | * Query the platform PIC for the interrupt & ack it. | ||
439 | * | ||
440 | * This will typically lower the interrupt line to the CPU | ||
441 | */ | ||
367 | irq = ppc_md.get_irq(); | 442 | irq = ppc_md.get_irq(); |
368 | 443 | ||
444 | /* We can hard enable interrupts now */ | ||
445 | may_hard_irq_enable(); | ||
446 | |||
447 | /* And finally process it */ | ||
369 | if (irq != NO_IRQ && irq != NO_IRQ_IGNORE) | 448 | if (irq != NO_IRQ && irq != NO_IRQ_IGNORE) |
370 | handle_one_irq(irq); | 449 | handle_one_irq(irq); |
371 | else if (irq != NO_IRQ_IGNORE) | 450 | else if (irq != NO_IRQ_IGNORE) |
@@ -374,15 +453,6 @@ void do_IRQ(struct pt_regs *regs) | |||
374 | irq_exit(); | 453 | irq_exit(); |
375 | set_irq_regs(old_regs); | 454 | set_irq_regs(old_regs); |
376 | 455 | ||
377 | #ifdef CONFIG_PPC_ISERIES | ||
378 | if (firmware_has_feature(FW_FEATURE_ISERIES) && | ||
379 | get_lppaca()->int_dword.fields.decr_int) { | ||
380 | get_lppaca()->int_dword.fields.decr_int = 0; | ||
381 | /* Signal a fake decrementer interrupt */ | ||
382 | timer_interrupt(regs); | ||
383 | } | ||
384 | #endif | ||
385 | |||
386 | trace_irq_exit(regs); | 456 | trace_irq_exit(regs); |
387 | } | 457 | } |
388 | 458 | ||
diff --git a/arch/powerpc/kernel/isa-bridge.c b/arch/powerpc/kernel/isa-bridge.c index 479752901ec6..d45ec58703ce 100644 --- a/arch/powerpc/kernel/isa-bridge.c +++ b/arch/powerpc/kernel/isa-bridge.c | |||
@@ -29,7 +29,6 @@ | |||
29 | #include <asm/pci-bridge.h> | 29 | #include <asm/pci-bridge.h> |
30 | #include <asm/machdep.h> | 30 | #include <asm/machdep.h> |
31 | #include <asm/ppc-pci.h> | 31 | #include <asm/ppc-pci.h> |
32 | #include <asm/firmware.h> | ||
33 | 32 | ||
34 | unsigned long isa_io_base; /* NULL if no ISA bus */ | 33 | unsigned long isa_io_base; /* NULL if no ISA bus */ |
35 | EXPORT_SYMBOL(isa_io_base); | 34 | EXPORT_SYMBOL(isa_io_base); |
@@ -261,8 +260,6 @@ static struct notifier_block isa_bridge_notifier = { | |||
261 | */ | 260 | */ |
262 | static int __init isa_bridge_init(void) | 261 | static int __init isa_bridge_init(void) |
263 | { | 262 | { |
264 | if (firmware_has_feature(FW_FEATURE_ISERIES)) | ||
265 | return 0; | ||
266 | bus_register_notifier(&pci_bus_type, &isa_bridge_notifier); | 263 | bus_register_notifier(&pci_bus_type, &isa_bridge_notifier); |
267 | return 0; | 264 | return 0; |
268 | } | 265 | } |
diff --git a/arch/powerpc/kernel/lparcfg.c b/arch/powerpc/kernel/lparcfg.c index 578f35f18723..ac12bd80ad95 100644 --- a/arch/powerpc/kernel/lparcfg.c +++ b/arch/powerpc/kernel/lparcfg.c | |||
@@ -26,7 +26,6 @@ | |||
26 | #include <linux/seq_file.h> | 26 | #include <linux/seq_file.h> |
27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
28 | #include <asm/uaccess.h> | 28 | #include <asm/uaccess.h> |
29 | #include <asm/iseries/hv_lp_config.h> | ||
30 | #include <asm/lppaca.h> | 29 | #include <asm/lppaca.h> |
31 | #include <asm/hvcall.h> | 30 | #include <asm/hvcall.h> |
32 | #include <asm/firmware.h> | 31 | #include <asm/firmware.h> |
@@ -55,80 +54,14 @@ static unsigned long get_purr(void) | |||
55 | int cpu; | 54 | int cpu; |
56 | 55 | ||
57 | for_each_possible_cpu(cpu) { | 56 | for_each_possible_cpu(cpu) { |
58 | if (firmware_has_feature(FW_FEATURE_ISERIES)) | 57 | struct cpu_usage *cu; |
59 | sum_purr += lppaca_of(cpu).emulated_time_base; | ||
60 | else { | ||
61 | struct cpu_usage *cu; | ||
62 | 58 | ||
63 | cu = &per_cpu(cpu_usage_array, cpu); | 59 | cu = &per_cpu(cpu_usage_array, cpu); |
64 | sum_purr += cu->current_tb; | 60 | sum_purr += cu->current_tb; |
65 | } | ||
66 | } | 61 | } |
67 | return sum_purr; | 62 | return sum_purr; |
68 | } | 63 | } |
69 | 64 | ||
70 | #ifdef CONFIG_PPC_ISERIES | ||
71 | |||
72 | /* | ||
73 | * Methods used to fetch LPAR data when running on an iSeries platform. | ||
74 | */ | ||
75 | static int iseries_lparcfg_data(struct seq_file *m, void *v) | ||
76 | { | ||
77 | unsigned long pool_id; | ||
78 | int shared, entitled_capacity, max_entitled_capacity; | ||
79 | int processors, max_processors; | ||
80 | unsigned long purr = get_purr(); | ||
81 | |||
82 | shared = (int)(local_paca->lppaca_ptr->shared_proc); | ||
83 | |||
84 | seq_printf(m, "system_active_processors=%d\n", | ||
85 | (int)HvLpConfig_getSystemPhysicalProcessors()); | ||
86 | |||
87 | seq_printf(m, "system_potential_processors=%d\n", | ||
88 | (int)HvLpConfig_getSystemPhysicalProcessors()); | ||
89 | |||
90 | processors = (int)HvLpConfig_getPhysicalProcessors(); | ||
91 | seq_printf(m, "partition_active_processors=%d\n", processors); | ||
92 | |||
93 | max_processors = (int)HvLpConfig_getMaxPhysicalProcessors(); | ||
94 | seq_printf(m, "partition_potential_processors=%d\n", max_processors); | ||
95 | |||
96 | if (shared) { | ||
97 | entitled_capacity = HvLpConfig_getSharedProcUnits(); | ||
98 | max_entitled_capacity = HvLpConfig_getMaxSharedProcUnits(); | ||
99 | } else { | ||
100 | entitled_capacity = processors * 100; | ||
101 | max_entitled_capacity = max_processors * 100; | ||
102 | } | ||
103 | seq_printf(m, "partition_entitled_capacity=%d\n", entitled_capacity); | ||
104 | |||
105 | seq_printf(m, "partition_max_entitled_capacity=%d\n", | ||
106 | max_entitled_capacity); | ||
107 | |||
108 | if (shared) { | ||
109 | pool_id = HvLpConfig_getSharedPoolIndex(); | ||
110 | seq_printf(m, "pool=%d\n", (int)pool_id); | ||
111 | seq_printf(m, "pool_capacity=%d\n", | ||
112 | (int)(HvLpConfig_getNumProcsInSharedPool(pool_id) * | ||
113 | 100)); | ||
114 | seq_printf(m, "purr=%ld\n", purr); | ||
115 | } | ||
116 | |||
117 | seq_printf(m, "shared_processor_mode=%d\n", shared); | ||
118 | |||
119 | return 0; | ||
120 | } | ||
121 | |||
122 | #else /* CONFIG_PPC_ISERIES */ | ||
123 | |||
124 | static int iseries_lparcfg_data(struct seq_file *m, void *v) | ||
125 | { | ||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | #endif /* CONFIG_PPC_ISERIES */ | ||
130 | |||
131 | #ifdef CONFIG_PPC_PSERIES | ||
132 | /* | 65 | /* |
133 | * Methods used to fetch LPAR data when running on a pSeries platform. | 66 | * Methods used to fetch LPAR data when running on a pSeries platform. |
134 | */ | 67 | */ |
@@ -648,8 +581,7 @@ static ssize_t lparcfg_write(struct file *file, const char __user * buf, | |||
648 | u8 new_weight, *new_weight_ptr = &new_weight; | 581 | u8 new_weight, *new_weight_ptr = &new_weight; |
649 | ssize_t retval; | 582 | ssize_t retval; |
650 | 583 | ||
651 | if (!firmware_has_feature(FW_FEATURE_SPLPAR) || | 584 | if (!firmware_has_feature(FW_FEATURE_SPLPAR)) |
652 | firmware_has_feature(FW_FEATURE_ISERIES)) | ||
653 | return -EINVAL; | 585 | return -EINVAL; |
654 | 586 | ||
655 | if (count > kbuf_sz) | 587 | if (count > kbuf_sz) |
@@ -709,21 +641,6 @@ static ssize_t lparcfg_write(struct file *file, const char __user * buf, | |||
709 | return retval; | 641 | return retval; |
710 | } | 642 | } |
711 | 643 | ||
712 | #else /* CONFIG_PPC_PSERIES */ | ||
713 | |||
714 | static int pseries_lparcfg_data(struct seq_file *m, void *v) | ||
715 | { | ||
716 | return 0; | ||
717 | } | ||
718 | |||
719 | static ssize_t lparcfg_write(struct file *file, const char __user * buf, | ||
720 | size_t count, loff_t * off) | ||
721 | { | ||
722 | return -EINVAL; | ||
723 | } | ||
724 | |||
725 | #endif /* CONFIG_PPC_PSERIES */ | ||
726 | |||
727 | static int lparcfg_data(struct seq_file *m, void *v) | 644 | static int lparcfg_data(struct seq_file *m, void *v) |
728 | { | 645 | { |
729 | struct device_node *rootdn; | 646 | struct device_node *rootdn; |
@@ -738,19 +655,11 @@ static int lparcfg_data(struct seq_file *m, void *v) | |||
738 | rootdn = of_find_node_by_path("/"); | 655 | rootdn = of_find_node_by_path("/"); |
739 | if (rootdn) { | 656 | if (rootdn) { |
740 | tmp = of_get_property(rootdn, "model", NULL); | 657 | tmp = of_get_property(rootdn, "model", NULL); |
741 | if (tmp) { | 658 | if (tmp) |
742 | model = tmp; | 659 | model = tmp; |
743 | /* Skip "IBM," - see platforms/iseries/dt.c */ | ||
744 | if (firmware_has_feature(FW_FEATURE_ISERIES)) | ||
745 | model += 4; | ||
746 | } | ||
747 | tmp = of_get_property(rootdn, "system-id", NULL); | 660 | tmp = of_get_property(rootdn, "system-id", NULL); |
748 | if (tmp) { | 661 | if (tmp) |
749 | system_id = tmp; | 662 | system_id = tmp; |
750 | /* Skip "IBM," - see platforms/iseries/dt.c */ | ||
751 | if (firmware_has_feature(FW_FEATURE_ISERIES)) | ||
752 | system_id += 4; | ||
753 | } | ||
754 | lp_index_ptr = of_get_property(rootdn, "ibm,partition-no", | 663 | lp_index_ptr = of_get_property(rootdn, "ibm,partition-no", |
755 | NULL); | 664 | NULL); |
756 | if (lp_index_ptr) | 665 | if (lp_index_ptr) |
@@ -761,8 +670,6 @@ static int lparcfg_data(struct seq_file *m, void *v) | |||
761 | seq_printf(m, "system_type=%s\n", model); | 670 | seq_printf(m, "system_type=%s\n", model); |
762 | seq_printf(m, "partition_id=%d\n", (int)lp_index); | 671 | seq_printf(m, "partition_id=%d\n", (int)lp_index); |
763 | 672 | ||
764 | if (firmware_has_feature(FW_FEATURE_ISERIES)) | ||
765 | return iseries_lparcfg_data(m, v); | ||
766 | return pseries_lparcfg_data(m, v); | 673 | return pseries_lparcfg_data(m, v); |
767 | } | 674 | } |
768 | 675 | ||
@@ -786,8 +693,7 @@ static int __init lparcfg_init(void) | |||
786 | umode_t mode = S_IRUSR | S_IRGRP | S_IROTH; | 693 | umode_t mode = S_IRUSR | S_IRGRP | S_IROTH; |
787 | 694 | ||
788 | /* Allow writing if we have FW_FEATURE_SPLPAR */ | 695 | /* Allow writing if we have FW_FEATURE_SPLPAR */ |
789 | if (firmware_has_feature(FW_FEATURE_SPLPAR) && | 696 | if (firmware_has_feature(FW_FEATURE_SPLPAR)) |
790 | !firmware_has_feature(FW_FEATURE_ISERIES)) | ||
791 | mode |= S_IWUSR; | 697 | mode |= S_IWUSR; |
792 | 698 | ||
793 | ent = proc_create("powerpc/lparcfg", mode, NULL, &lparcfg_fops); | 699 | ent = proc_create("powerpc/lparcfg", mode, NULL, &lparcfg_fops); |
diff --git a/arch/powerpc/kernel/misc.S b/arch/powerpc/kernel/misc.S index b69463ec2010..ba16874fe294 100644 --- a/arch/powerpc/kernel/misc.S +++ b/arch/powerpc/kernel/misc.S | |||
@@ -5,7 +5,6 @@ | |||
5 | * Largely rewritten by Cort Dougan (cort@cs.nmt.edu) | 5 | * Largely rewritten by Cort Dougan (cort@cs.nmt.edu) |
6 | * and Paul Mackerras. | 6 | * and Paul Mackerras. |
7 | * | 7 | * |
8 | * Adapted for iSeries by Mike Corrigan (mikejc@us.ibm.com) | ||
9 | * PPC64 updates by Dave Engebretsen (engebret@us.ibm.com) | 8 | * PPC64 updates by Dave Engebretsen (engebret@us.ibm.com) |
10 | * | 9 | * |
11 | * setjmp/longjmp code by Paul Mackerras. | 10 | * setjmp/longjmp code by Paul Mackerras. |
diff --git a/arch/powerpc/kernel/of_platform.c b/arch/powerpc/kernel/of_platform.c index e1612dfb4a93..2049f2d00ffe 100644 --- a/arch/powerpc/kernel/of_platform.c +++ b/arch/powerpc/kernel/of_platform.c | |||
@@ -21,12 +21,13 @@ | |||
21 | #include <linux/of.h> | 21 | #include <linux/of.h> |
22 | #include <linux/of_device.h> | 22 | #include <linux/of_device.h> |
23 | #include <linux/of_platform.h> | 23 | #include <linux/of_platform.h> |
24 | #include <linux/atomic.h> | ||
24 | 25 | ||
25 | #include <asm/errno.h> | 26 | #include <asm/errno.h> |
26 | #include <asm/topology.h> | 27 | #include <asm/topology.h> |
27 | #include <asm/pci-bridge.h> | 28 | #include <asm/pci-bridge.h> |
28 | #include <asm/ppc-pci.h> | 29 | #include <asm/ppc-pci.h> |
29 | #include <linux/atomic.h> | 30 | #include <asm/eeh.h> |
30 | 31 | ||
31 | #ifdef CONFIG_PPC_OF_PLATFORM_PCI | 32 | #ifdef CONFIG_PPC_OF_PLATFORM_PCI |
32 | 33 | ||
@@ -66,6 +67,9 @@ static int __devinit of_pci_phb_probe(struct platform_device *dev) | |||
66 | /* Init pci_dn data structures */ | 67 | /* Init pci_dn data structures */ |
67 | pci_devs_phb_init_dynamic(phb); | 68 | pci_devs_phb_init_dynamic(phb); |
68 | 69 | ||
70 | /* Create EEH devices for the PHB */ | ||
71 | eeh_dev_phb_init_dynamic(phb); | ||
72 | |||
69 | /* Register devices with EEH */ | 73 | /* Register devices with EEH */ |
70 | #ifdef CONFIG_EEH | 74 | #ifdef CONFIG_EEH |
71 | if (dev->dev.of_node->child) | 75 | if (dev->dev.of_node->child) |
diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c index 41456ff55e14..0bb1f98613ba 100644 --- a/arch/powerpc/kernel/paca.c +++ b/arch/powerpc/kernel/paca.c | |||
@@ -11,13 +11,10 @@ | |||
11 | #include <linux/export.h> | 11 | #include <linux/export.h> |
12 | #include <linux/memblock.h> | 12 | #include <linux/memblock.h> |
13 | 13 | ||
14 | #include <asm/firmware.h> | ||
15 | #include <asm/lppaca.h> | 14 | #include <asm/lppaca.h> |
16 | #include <asm/paca.h> | 15 | #include <asm/paca.h> |
17 | #include <asm/sections.h> | 16 | #include <asm/sections.h> |
18 | #include <asm/pgtable.h> | 17 | #include <asm/pgtable.h> |
19 | #include <asm/iseries/lpar_map.h> | ||
20 | #include <asm/iseries/hv_types.h> | ||
21 | #include <asm/kexec.h> | 18 | #include <asm/kexec.h> |
22 | 19 | ||
23 | /* This symbol is provided by the linker - let it fill in the paca | 20 | /* This symbol is provided by the linker - let it fill in the paca |
@@ -30,8 +27,8 @@ extern unsigned long __toc_start; | |||
30 | * The structure which the hypervisor knows about - this structure | 27 | * The structure which the hypervisor knows about - this structure |
31 | * should not cross a page boundary. The vpa_init/register_vpa call | 28 | * should not cross a page boundary. The vpa_init/register_vpa call |
32 | * is now known to fail if the lppaca structure crosses a page | 29 | * is now known to fail if the lppaca structure crosses a page |
33 | * boundary. The lppaca is also used on legacy iSeries and POWER5 | 30 | * boundary. The lppaca is also used on POWER5 pSeries boxes. |
34 | * pSeries boxes. The lppaca is 640 bytes long, and cannot readily | 31 | * The lppaca is 640 bytes long, and cannot readily |
35 | * change since the hypervisor knows its layout, so a 1kB alignment | 32 | * change since the hypervisor knows its layout, so a 1kB alignment |
36 | * will suffice to ensure that it doesn't cross a page boundary. | 33 | * will suffice to ensure that it doesn't cross a page boundary. |
37 | */ | 34 | */ |
@@ -183,12 +180,9 @@ void __init allocate_pacas(void) | |||
183 | /* | 180 | /* |
184 | * We can't take SLB misses on the paca, and we want to access them | 181 | * We can't take SLB misses on the paca, and we want to access them |
185 | * in real mode, so allocate them within the RMA and also within | 182 | * in real mode, so allocate them within the RMA and also within |
186 | * the first segment. On iSeries they must be within the area mapped | 183 | * the first segment. |
187 | * by the HV, which is HvPagesToMap * HVPAGESIZE bytes. | ||
188 | */ | 184 | */ |
189 | limit = min(0x10000000ULL, ppc64_rma_size); | 185 | limit = min(0x10000000ULL, ppc64_rma_size); |
190 | if (firmware_has_feature(FW_FEATURE_ISERIES)) | ||
191 | limit = min(limit, HvPagesToMap * HVPAGESIZE); | ||
192 | 186 | ||
193 | paca_size = PAGE_ALIGN(sizeof(struct paca_struct) * nr_cpu_ids); | 187 | paca_size = PAGE_ALIGN(sizeof(struct paca_struct) * nr_cpu_ids); |
194 | 188 | ||
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index cce98d76e905..d0373bcb7c9d 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c | |||
@@ -38,7 +38,6 @@ | |||
38 | #include <asm/byteorder.h> | 38 | #include <asm/byteorder.h> |
39 | #include <asm/machdep.h> | 39 | #include <asm/machdep.h> |
40 | #include <asm/ppc-pci.h> | 40 | #include <asm/ppc-pci.h> |
41 | #include <asm/firmware.h> | ||
42 | #include <asm/eeh.h> | 41 | #include <asm/eeh.h> |
43 | 42 | ||
44 | static DEFINE_SPINLOCK(hose_spinlock); | 43 | static DEFINE_SPINLOCK(hose_spinlock); |
@@ -219,20 +218,6 @@ static int pci_read_irq_line(struct pci_dev *pci_dev) | |||
219 | struct of_irq oirq; | 218 | struct of_irq oirq; |
220 | unsigned int virq; | 219 | unsigned int virq; |
221 | 220 | ||
222 | /* The current device-tree that iSeries generates from the HV | ||
223 | * PCI informations doesn't contain proper interrupt routing, | ||
224 | * and all the fallback would do is print out crap, so we | ||
225 | * don't attempt to resolve the interrupts here at all, some | ||
226 | * iSeries specific fixup does it. | ||
227 | * | ||
228 | * In the long run, we will hopefully fix the generated device-tree | ||
229 | * instead. | ||
230 | */ | ||
231 | #ifdef CONFIG_PPC_ISERIES | ||
232 | if (firmware_has_feature(FW_FEATURE_ISERIES)) | ||
233 | return -1; | ||
234 | #endif | ||
235 | |||
236 | pr_debug("PCI: Try to map irq for %s...\n", pci_name(pci_dev)); | 221 | pr_debug("PCI: Try to map irq for %s...\n", pci_name(pci_dev)); |
237 | 222 | ||
238 | #ifdef DEBUG | 223 | #ifdef DEBUG |
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index d817ab018486..e40707032ac3 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c | |||
@@ -647,6 +647,9 @@ void show_regs(struct pt_regs * regs) | |||
647 | printk("MSR: "REG" ", regs->msr); | 647 | printk("MSR: "REG" ", regs->msr); |
648 | printbits(regs->msr, msr_bits); | 648 | printbits(regs->msr, msr_bits); |
649 | printk(" CR: %08lx XER: %08lx\n", regs->ccr, regs->xer); | 649 | printk(" CR: %08lx XER: %08lx\n", regs->ccr, regs->xer); |
650 | #ifdef CONFIG_PPC64 | ||
651 | printk("SOFTE: %ld\n", regs->softe); | ||
652 | #endif | ||
650 | trap = TRAP(regs); | 653 | trap = TRAP(regs); |
651 | if ((regs->trap != 0xc00) && cpu_has_feature(CPU_FTR_CFAR)) | 654 | if ((regs->trap != 0xc00) && cpu_has_feature(CPU_FTR_CFAR)) |
652 | printk("CFAR: "REG"\n", regs->orig_gpr3); | 655 | printk("CFAR: "REG"\n", regs->orig_gpr3); |
@@ -1220,34 +1223,32 @@ void dump_stack(void) | |||
1220 | EXPORT_SYMBOL(dump_stack); | 1223 | EXPORT_SYMBOL(dump_stack); |
1221 | 1224 | ||
1222 | #ifdef CONFIG_PPC64 | 1225 | #ifdef CONFIG_PPC64 |
1223 | void ppc64_runlatch_on(void) | 1226 | /* Called with hard IRQs off */ |
1227 | void __ppc64_runlatch_on(void) | ||
1224 | { | 1228 | { |
1229 | struct thread_info *ti = current_thread_info(); | ||
1225 | unsigned long ctrl; | 1230 | unsigned long ctrl; |
1226 | 1231 | ||
1227 | if (cpu_has_feature(CPU_FTR_CTRL) && !test_thread_flag(TIF_RUNLATCH)) { | 1232 | ctrl = mfspr(SPRN_CTRLF); |
1228 | HMT_medium(); | 1233 | ctrl |= CTRL_RUNLATCH; |
1229 | 1234 | mtspr(SPRN_CTRLT, ctrl); | |
1230 | ctrl = mfspr(SPRN_CTRLF); | ||
1231 | ctrl |= CTRL_RUNLATCH; | ||
1232 | mtspr(SPRN_CTRLT, ctrl); | ||
1233 | 1235 | ||
1234 | set_thread_flag(TIF_RUNLATCH); | 1236 | ti->local_flags |= TLF_RUNLATCH; |
1235 | } | ||
1236 | } | 1237 | } |
1237 | 1238 | ||
1239 | /* Called with hard IRQs off */ | ||
1238 | void __ppc64_runlatch_off(void) | 1240 | void __ppc64_runlatch_off(void) |
1239 | { | 1241 | { |
1242 | struct thread_info *ti = current_thread_info(); | ||
1240 | unsigned long ctrl; | 1243 | unsigned long ctrl; |
1241 | 1244 | ||
1242 | HMT_medium(); | 1245 | ti->local_flags &= ~TLF_RUNLATCH; |
1243 | |||
1244 | clear_thread_flag(TIF_RUNLATCH); | ||
1245 | 1246 | ||
1246 | ctrl = mfspr(SPRN_CTRLF); | 1247 | ctrl = mfspr(SPRN_CTRLF); |
1247 | ctrl &= ~CTRL_RUNLATCH; | 1248 | ctrl &= ~CTRL_RUNLATCH; |
1248 | mtspr(SPRN_CTRLT, ctrl); | 1249 | mtspr(SPRN_CTRLT, ctrl); |
1249 | } | 1250 | } |
1250 | #endif | 1251 | #endif /* CONFIG_PPC64 */ |
1251 | 1252 | ||
1252 | #if THREAD_SHIFT < PAGE_SHIFT | 1253 | #if THREAD_SHIFT < PAGE_SHIFT |
1253 | 1254 | ||
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index abe405dab34d..89e850af3dd6 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c | |||
@@ -52,9 +52,9 @@ | |||
52 | #include <asm/machdep.h> | 52 | #include <asm/machdep.h> |
53 | #include <asm/pSeries_reconfig.h> | 53 | #include <asm/pSeries_reconfig.h> |
54 | #include <asm/pci-bridge.h> | 54 | #include <asm/pci-bridge.h> |
55 | #include <asm/phyp_dump.h> | ||
56 | #include <asm/kexec.h> | 55 | #include <asm/kexec.h> |
57 | #include <asm/opal.h> | 56 | #include <asm/opal.h> |
57 | #include <asm/fadump.h> | ||
58 | 58 | ||
59 | #include <mm/mmu_decl.h> | 59 | #include <mm/mmu_decl.h> |
60 | 60 | ||
@@ -615,86 +615,6 @@ static void __init early_reserve_mem(void) | |||
615 | } | 615 | } |
616 | } | 616 | } |
617 | 617 | ||
618 | #ifdef CONFIG_PHYP_DUMP | ||
619 | /** | ||
620 | * phyp_dump_calculate_reserve_size() - reserve variable boot area 5% or arg | ||
621 | * | ||
622 | * Function to find the largest size we need to reserve | ||
623 | * during early boot process. | ||
624 | * | ||
625 | * It either looks for boot param and returns that OR | ||
626 | * returns larger of 256 or 5% rounded down to multiples of 256MB. | ||
627 | * | ||
628 | */ | ||
629 | static inline unsigned long phyp_dump_calculate_reserve_size(void) | ||
630 | { | ||
631 | unsigned long tmp; | ||
632 | |||
633 | if (phyp_dump_info->reserve_bootvar) | ||
634 | return phyp_dump_info->reserve_bootvar; | ||
635 | |||
636 | /* divide by 20 to get 5% of value */ | ||
637 | tmp = memblock_end_of_DRAM(); | ||
638 | do_div(tmp, 20); | ||
639 | |||
640 | /* round it down in multiples of 256 */ | ||
641 | tmp = tmp & ~0x0FFFFFFFUL; | ||
642 | |||
643 | return (tmp > PHYP_DUMP_RMR_END ? tmp : PHYP_DUMP_RMR_END); | ||
644 | } | ||
645 | |||
646 | /** | ||
647 | * phyp_dump_reserve_mem() - reserve all not-yet-dumped mmemory | ||
648 | * | ||
649 | * This routine may reserve memory regions in the kernel only | ||
650 | * if the system is supported and a dump was taken in last | ||
651 | * boot instance or if the hardware is supported and the | ||
652 | * scratch area needs to be setup. In other instances it returns | ||
653 | * without reserving anything. The memory in case of dump being | ||
654 | * active is freed when the dump is collected (by userland tools). | ||
655 | */ | ||
656 | static void __init phyp_dump_reserve_mem(void) | ||
657 | { | ||
658 | unsigned long base, size; | ||
659 | unsigned long variable_reserve_size; | ||
660 | |||
661 | if (!phyp_dump_info->phyp_dump_configured) { | ||
662 | printk(KERN_ERR "Phyp-dump not supported on this hardware\n"); | ||
663 | return; | ||
664 | } | ||
665 | |||
666 | if (!phyp_dump_info->phyp_dump_at_boot) { | ||
667 | printk(KERN_INFO "Phyp-dump disabled at boot time\n"); | ||
668 | return; | ||
669 | } | ||
670 | |||
671 | variable_reserve_size = phyp_dump_calculate_reserve_size(); | ||
672 | |||
673 | if (phyp_dump_info->phyp_dump_is_active) { | ||
674 | /* Reserve *everything* above RMR.Area freed by userland tools*/ | ||
675 | base = variable_reserve_size; | ||
676 | size = memblock_end_of_DRAM() - base; | ||
677 | |||
678 | /* XXX crashed_ram_end is wrong, since it may be beyond | ||
679 | * the memory_limit, it will need to be adjusted. */ | ||
680 | memblock_reserve(base, size); | ||
681 | |||
682 | phyp_dump_info->init_reserve_start = base; | ||
683 | phyp_dump_info->init_reserve_size = size; | ||
684 | } else { | ||
685 | size = phyp_dump_info->cpu_state_size + | ||
686 | phyp_dump_info->hpte_region_size + | ||
687 | variable_reserve_size; | ||
688 | base = memblock_end_of_DRAM() - size; | ||
689 | memblock_reserve(base, size); | ||
690 | phyp_dump_info->init_reserve_start = base; | ||
691 | phyp_dump_info->init_reserve_size = size; | ||
692 | } | ||
693 | } | ||
694 | #else | ||
695 | static inline void __init phyp_dump_reserve_mem(void) {} | ||
696 | #endif /* CONFIG_PHYP_DUMP && CONFIG_PPC_RTAS */ | ||
697 | |||
698 | void __init early_init_devtree(void *params) | 618 | void __init early_init_devtree(void *params) |
699 | { | 619 | { |
700 | phys_addr_t limit; | 620 | phys_addr_t limit; |
@@ -714,9 +634,9 @@ void __init early_init_devtree(void *params) | |||
714 | of_scan_flat_dt(early_init_dt_scan_opal, NULL); | 634 | of_scan_flat_dt(early_init_dt_scan_opal, NULL); |
715 | #endif | 635 | #endif |
716 | 636 | ||
717 | #ifdef CONFIG_PHYP_DUMP | 637 | #ifdef CONFIG_FA_DUMP |
718 | /* scan tree to see if dump occurred during last boot */ | 638 | /* scan tree to see if dump is active during last boot */ |
719 | of_scan_flat_dt(early_init_dt_scan_phyp_dump, NULL); | 639 | of_scan_flat_dt(early_init_dt_scan_fw_dump, NULL); |
720 | #endif | 640 | #endif |
721 | 641 | ||
722 | /* Pre-initialize the cmd_line with the content of boot_commmand_line, | 642 | /* Pre-initialize the cmd_line with the content of boot_commmand_line, |
@@ -750,9 +670,15 @@ void __init early_init_devtree(void *params) | |||
750 | if (PHYSICAL_START > MEMORY_START) | 670 | if (PHYSICAL_START > MEMORY_START) |
751 | memblock_reserve(MEMORY_START, 0x8000); | 671 | memblock_reserve(MEMORY_START, 0x8000); |
752 | reserve_kdump_trampoline(); | 672 | reserve_kdump_trampoline(); |
753 | reserve_crashkernel(); | 673 | #ifdef CONFIG_FA_DUMP |
674 | /* | ||
675 | * If we fail to reserve memory for firmware-assisted dump then | ||
676 | * fallback to kexec based kdump. | ||
677 | */ | ||
678 | if (fadump_reserve_mem() == 0) | ||
679 | #endif | ||
680 | reserve_crashkernel(); | ||
754 | early_reserve_mem(); | 681 | early_reserve_mem(); |
755 | phyp_dump_reserve_mem(); | ||
756 | 682 | ||
757 | /* | 683 | /* |
758 | * Ensure that total memory size is page-aligned, because otherwise | 684 | * Ensure that total memory size is page-aligned, because otherwise |
diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index eca626ea3f23..e2d599048142 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c | |||
@@ -48,14 +48,6 @@ | |||
48 | #include <linux/linux_logo.h> | 48 | #include <linux/linux_logo.h> |
49 | 49 | ||
50 | /* | 50 | /* |
51 | * Properties whose value is longer than this get excluded from our | ||
52 | * copy of the device tree. This value does need to be big enough to | ||
53 | * ensure that we don't lose things like the interrupt-map property | ||
54 | * on a PCI-PCI bridge. | ||
55 | */ | ||
56 | #define MAX_PROPERTY_LENGTH (1UL * 1024 * 1024) | ||
57 | |||
58 | /* | ||
59 | * Eventually bump that one up | 51 | * Eventually bump that one up |
60 | */ | 52 | */ |
61 | #define DEVTREE_CHUNK_SIZE 0x100000 | 53 | #define DEVTREE_CHUNK_SIZE 0x100000 |
@@ -2273,13 +2265,6 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, | |||
2273 | /* sanity checks */ | 2265 | /* sanity checks */ |
2274 | if (l == PROM_ERROR) | 2266 | if (l == PROM_ERROR) |
2275 | continue; | 2267 | continue; |
2276 | if (l > MAX_PROPERTY_LENGTH) { | ||
2277 | prom_printf("WARNING: ignoring large property "); | ||
2278 | /* It seems OF doesn't null-terminate the path :-( */ | ||
2279 | prom_printf("[%s] ", path); | ||
2280 | prom_printf("%s length 0x%x\n", RELOC(pname), l); | ||
2281 | continue; | ||
2282 | } | ||
2283 | 2268 | ||
2284 | /* push property head */ | 2269 | /* push property head */ |
2285 | dt_push_token(OF_DT_PROP, mem_start, mem_end); | 2270 | dt_push_token(OF_DT_PROP, mem_start, mem_end); |
diff --git a/arch/powerpc/kernel/rtas_pci.c b/arch/powerpc/kernel/rtas_pci.c index 6cd8f0196b6d..517bd86bc3f0 100644 --- a/arch/powerpc/kernel/rtas_pci.c +++ b/arch/powerpc/kernel/rtas_pci.c | |||
@@ -275,6 +275,9 @@ void __init find_and_init_phbs(void) | |||
275 | of_node_put(root); | 275 | of_node_put(root); |
276 | pci_devs_phb_init(); | 276 | pci_devs_phb_init(); |
277 | 277 | ||
278 | /* Create EEH devices for all PHBs */ | ||
279 | eeh_dev_phb_init(); | ||
280 | |||
278 | /* | 281 | /* |
279 | * pci_probe_only and pci_assign_all_buses can be set via properties | 282 | * pci_probe_only and pci_assign_all_buses can be set via properties |
280 | * in chosen. | 283 | * in chosen. |
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c index 77bb77da05c1..b0ebdeab9494 100644 --- a/arch/powerpc/kernel/setup-common.c +++ b/arch/powerpc/kernel/setup-common.c | |||
@@ -61,6 +61,7 @@ | |||
61 | #include <asm/xmon.h> | 61 | #include <asm/xmon.h> |
62 | #include <asm/cputhreads.h> | 62 | #include <asm/cputhreads.h> |
63 | #include <mm/mmu_decl.h> | 63 | #include <mm/mmu_decl.h> |
64 | #include <asm/fadump.h> | ||
64 | 65 | ||
65 | #include "setup.h" | 66 | #include "setup.h" |
66 | 67 | ||
@@ -109,6 +110,14 @@ EXPORT_SYMBOL(ppc_do_canonicalize_irqs); | |||
109 | /* also used by kexec */ | 110 | /* also used by kexec */ |
110 | void machine_shutdown(void) | 111 | void machine_shutdown(void) |
111 | { | 112 | { |
113 | #ifdef CONFIG_FA_DUMP | ||
114 | /* | ||
115 | * if fadump is active, cleanup the fadump registration before we | ||
116 | * shutdown. | ||
117 | */ | ||
118 | fadump_cleanup(); | ||
119 | #endif | ||
120 | |||
112 | if (ppc_md.machine_shutdown) | 121 | if (ppc_md.machine_shutdown) |
113 | ppc_md.machine_shutdown(); | 122 | ppc_md.machine_shutdown(); |
114 | } | 123 | } |
@@ -639,6 +648,11 @@ EXPORT_SYMBOL(check_legacy_ioport); | |||
639 | static int ppc_panic_event(struct notifier_block *this, | 648 | static int ppc_panic_event(struct notifier_block *this, |
640 | unsigned long event, void *ptr) | 649 | unsigned long event, void *ptr) |
641 | { | 650 | { |
651 | /* | ||
652 | * If firmware-assisted dump has been registered then trigger | ||
653 | * firmware-assisted dump and let firmware handle everything else. | ||
654 | */ | ||
655 | crash_fadump(NULL, ptr); | ||
642 | ppc_md.panic(ptr); /* May not return */ | 656 | ppc_md.panic(ptr); /* May not return */ |
643 | return NOTIFY_DONE; | 657 | return NOTIFY_DONE; |
644 | } | 658 | } |
diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c index ac6e437b1021..7006b7f4267a 100644 --- a/arch/powerpc/kernel/signal.c +++ b/arch/powerpc/kernel/signal.c | |||
@@ -57,10 +57,7 @@ void __user * get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, | |||
57 | void restore_sigmask(sigset_t *set) | 57 | void restore_sigmask(sigset_t *set) |
58 | { | 58 | { |
59 | sigdelsetmask(set, ~_BLOCKABLE); | 59 | sigdelsetmask(set, ~_BLOCKABLE); |
60 | spin_lock_irq(¤t->sighand->siglock); | 60 | set_current_blocked(set); |
61 | current->blocked = *set; | ||
62 | recalc_sigpending(); | ||
63 | spin_unlock_irq(¤t->sighand->siglock); | ||
64 | } | 61 | } |
65 | 62 | ||
66 | static void check_syscall_restart(struct pt_regs *regs, struct k_sigaction *ka, | 63 | static void check_syscall_restart(struct pt_regs *regs, struct k_sigaction *ka, |
@@ -169,13 +166,7 @@ static int do_signal(struct pt_regs *regs) | |||
169 | 166 | ||
170 | regs->trap = 0; | 167 | regs->trap = 0; |
171 | if (ret) { | 168 | if (ret) { |
172 | spin_lock_irq(¤t->sighand->siglock); | 169 | block_sigmask(&ka, signr); |
173 | sigorsets(¤t->blocked, ¤t->blocked, | ||
174 | &ka.sa.sa_mask); | ||
175 | if (!(ka.sa.sa_flags & SA_NODEFER)) | ||
176 | sigaddset(¤t->blocked, signr); | ||
177 | recalc_sigpending(); | ||
178 | spin_unlock_irq(¤t->sighand->siglock); | ||
179 | 170 | ||
180 | /* | 171 | /* |
181 | * A signal was successfully delivered; the saved sigmask is in | 172 | * A signal was successfully delivered; the saved sigmask is in |
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index 836a5a19eb2c..e061ef5dd449 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c | |||
@@ -242,12 +242,13 @@ static inline int restore_general_regs(struct pt_regs *regs, | |||
242 | */ | 242 | */ |
243 | long sys_sigsuspend(old_sigset_t mask) | 243 | long sys_sigsuspend(old_sigset_t mask) |
244 | { | 244 | { |
245 | mask &= _BLOCKABLE; | 245 | sigset_t blocked; |
246 | spin_lock_irq(¤t->sighand->siglock); | 246 | |
247 | current->saved_sigmask = current->blocked; | 247 | current->saved_sigmask = current->blocked; |
248 | siginitset(¤t->blocked, mask); | 248 | |
249 | recalc_sigpending(); | 249 | mask &= _BLOCKABLE; |
250 | spin_unlock_irq(¤t->sighand->siglock); | 250 | siginitset(&blocked, mask); |
251 | set_current_blocked(&blocked); | ||
251 | 252 | ||
252 | current->state = TASK_INTERRUPTIBLE; | 253 | current->state = TASK_INTERRUPTIBLE; |
253 | schedule(); | 254 | schedule(); |
diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c index 883e74c0d1b3..0c683d376b1c 100644 --- a/arch/powerpc/kernel/sysfs.c +++ b/arch/powerpc/kernel/sysfs.c | |||
@@ -12,7 +12,6 @@ | |||
12 | #include <asm/current.h> | 12 | #include <asm/current.h> |
13 | #include <asm/processor.h> | 13 | #include <asm/processor.h> |
14 | #include <asm/cputable.h> | 14 | #include <asm/cputable.h> |
15 | #include <asm/firmware.h> | ||
16 | #include <asm/hvcall.h> | 15 | #include <asm/hvcall.h> |
17 | #include <asm/prom.h> | 16 | #include <asm/prom.h> |
18 | #include <asm/machdep.h> | 17 | #include <asm/machdep.h> |
@@ -341,8 +340,7 @@ static void __cpuinit register_cpu_online(unsigned int cpu) | |||
341 | int i, nattrs; | 340 | int i, nattrs; |
342 | 341 | ||
343 | #ifdef CONFIG_PPC64 | 342 | #ifdef CONFIG_PPC64 |
344 | if (!firmware_has_feature(FW_FEATURE_ISERIES) && | 343 | if (cpu_has_feature(CPU_FTR_SMT)) |
345 | cpu_has_feature(CPU_FTR_SMT)) | ||
346 | device_create_file(s, &dev_attr_smt_snooze_delay); | 344 | device_create_file(s, &dev_attr_smt_snooze_delay); |
347 | #endif | 345 | #endif |
348 | 346 | ||
@@ -414,8 +412,7 @@ static void unregister_cpu_online(unsigned int cpu) | |||
414 | BUG_ON(!c->hotpluggable); | 412 | BUG_ON(!c->hotpluggable); |
415 | 413 | ||
416 | #ifdef CONFIG_PPC64 | 414 | #ifdef CONFIG_PPC64 |
417 | if (!firmware_has_feature(FW_FEATURE_ISERIES) && | 415 | if (cpu_has_feature(CPU_FTR_SMT)) |
418 | cpu_has_feature(CPU_FTR_SMT)) | ||
419 | device_remove_file(s, &dev_attr_smt_snooze_delay); | 416 | device_remove_file(s, &dev_attr_smt_snooze_delay); |
420 | #endif | 417 | #endif |
421 | 418 | ||
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 567dd7c3ac2a..2c42cd72d0f5 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c | |||
@@ -17,8 +17,7 @@ | |||
17 | * | 17 | * |
18 | * TODO (not necessarily in this file): | 18 | * TODO (not necessarily in this file): |
19 | * - improve precision and reproducibility of timebase frequency | 19 | * - improve precision and reproducibility of timebase frequency |
20 | * measurement at boot time. (for iSeries, we calibrate the timebase | 20 | * measurement at boot time. |
21 | * against the Titan chip's clock.) | ||
22 | * - for astronomical applications: add a new function to get | 21 | * - for astronomical applications: add a new function to get |
23 | * non ambiguous timestamps even around leap seconds. This needs | 22 | * non ambiguous timestamps even around leap seconds. This needs |
24 | * a new timestamp format and a good name. | 23 | * a new timestamp format and a good name. |
@@ -70,10 +69,6 @@ | |||
70 | #include <asm/vdso_datapage.h> | 69 | #include <asm/vdso_datapage.h> |
71 | #include <asm/firmware.h> | 70 | #include <asm/firmware.h> |
72 | #include <asm/cputime.h> | 71 | #include <asm/cputime.h> |
73 | #ifdef CONFIG_PPC_ISERIES | ||
74 | #include <asm/iseries/it_lp_queue.h> | ||
75 | #include <asm/iseries/hv_call_xm.h> | ||
76 | #endif | ||
77 | 72 | ||
78 | /* powerpc clocksource/clockevent code */ | 73 | /* powerpc clocksource/clockevent code */ |
79 | 74 | ||
@@ -117,14 +112,6 @@ static struct clock_event_device decrementer_clockevent = { | |||
117 | DEFINE_PER_CPU(u64, decrementers_next_tb); | 112 | DEFINE_PER_CPU(u64, decrementers_next_tb); |
118 | static DEFINE_PER_CPU(struct clock_event_device, decrementers); | 113 | static DEFINE_PER_CPU(struct clock_event_device, decrementers); |
119 | 114 | ||
120 | #ifdef CONFIG_PPC_ISERIES | ||
121 | static unsigned long __initdata iSeries_recal_titan; | ||
122 | static signed long __initdata iSeries_recal_tb; | ||
123 | |||
124 | /* Forward declaration is only needed for iSereis compiles */ | ||
125 | static void __init clocksource_init(void); | ||
126 | #endif | ||
127 | |||
128 | #define XSEC_PER_SEC (1024*1024) | 115 | #define XSEC_PER_SEC (1024*1024) |
129 | 116 | ||
130 | #ifdef CONFIG_PPC64 | 117 | #ifdef CONFIG_PPC64 |
@@ -259,7 +246,6 @@ void accumulate_stolen_time(void) | |||
259 | u64 sst, ust; | 246 | u64 sst, ust; |
260 | 247 | ||
261 | u8 save_soft_enabled = local_paca->soft_enabled; | 248 | u8 save_soft_enabled = local_paca->soft_enabled; |
262 | u8 save_hard_enabled = local_paca->hard_enabled; | ||
263 | 249 | ||
264 | /* We are called early in the exception entry, before | 250 | /* We are called early in the exception entry, before |
265 | * soft/hard_enabled are sync'ed to the expected state | 251 | * soft/hard_enabled are sync'ed to the expected state |
@@ -268,7 +254,6 @@ void accumulate_stolen_time(void) | |||
268 | * complain | 254 | * complain |
269 | */ | 255 | */ |
270 | local_paca->soft_enabled = 0; | 256 | local_paca->soft_enabled = 0; |
271 | local_paca->hard_enabled = 0; | ||
272 | 257 | ||
273 | sst = scan_dispatch_log(local_paca->starttime_user); | 258 | sst = scan_dispatch_log(local_paca->starttime_user); |
274 | ust = scan_dispatch_log(local_paca->starttime); | 259 | ust = scan_dispatch_log(local_paca->starttime); |
@@ -277,7 +262,6 @@ void accumulate_stolen_time(void) | |||
277 | local_paca->stolen_time += ust + sst; | 262 | local_paca->stolen_time += ust + sst; |
278 | 263 | ||
279 | local_paca->soft_enabled = save_soft_enabled; | 264 | local_paca->soft_enabled = save_soft_enabled; |
280 | local_paca->hard_enabled = save_hard_enabled; | ||
281 | } | 265 | } |
282 | 266 | ||
283 | static inline u64 calculate_stolen_time(u64 stop_tb) | 267 | static inline u64 calculate_stolen_time(u64 stop_tb) |
@@ -426,74 +410,6 @@ unsigned long profile_pc(struct pt_regs *regs) | |||
426 | EXPORT_SYMBOL(profile_pc); | 410 | EXPORT_SYMBOL(profile_pc); |
427 | #endif | 411 | #endif |
428 | 412 | ||
429 | #ifdef CONFIG_PPC_ISERIES | ||
430 | |||
431 | /* | ||
432 | * This function recalibrates the timebase based on the 49-bit time-of-day | ||
433 | * value in the Titan chip. The Titan is much more accurate than the value | ||
434 | * returned by the service processor for the timebase frequency. | ||
435 | */ | ||
436 | |||
437 | static int __init iSeries_tb_recal(void) | ||
438 | { | ||
439 | unsigned long titan, tb; | ||
440 | |||
441 | /* Make sure we only run on iSeries */ | ||
442 | if (!firmware_has_feature(FW_FEATURE_ISERIES)) | ||
443 | return -ENODEV; | ||
444 | |||
445 | tb = get_tb(); | ||
446 | titan = HvCallXm_loadTod(); | ||
447 | if ( iSeries_recal_titan ) { | ||
448 | unsigned long tb_ticks = tb - iSeries_recal_tb; | ||
449 | unsigned long titan_usec = (titan - iSeries_recal_titan) >> 12; | ||
450 | unsigned long new_tb_ticks_per_sec = (tb_ticks * USEC_PER_SEC)/titan_usec; | ||
451 | unsigned long new_tb_ticks_per_jiffy = | ||
452 | DIV_ROUND_CLOSEST(new_tb_ticks_per_sec, HZ); | ||
453 | long tick_diff = new_tb_ticks_per_jiffy - tb_ticks_per_jiffy; | ||
454 | char sign = '+'; | ||
455 | /* make sure tb_ticks_per_sec and tb_ticks_per_jiffy are consistent */ | ||
456 | new_tb_ticks_per_sec = new_tb_ticks_per_jiffy * HZ; | ||
457 | |||
458 | if ( tick_diff < 0 ) { | ||
459 | tick_diff = -tick_diff; | ||
460 | sign = '-'; | ||
461 | } | ||
462 | if ( tick_diff ) { | ||
463 | if ( tick_diff < tb_ticks_per_jiffy/25 ) { | ||
464 | printk( "Titan recalibrate: new tb_ticks_per_jiffy = %lu (%c%ld)\n", | ||
465 | new_tb_ticks_per_jiffy, sign, tick_diff ); | ||
466 | tb_ticks_per_jiffy = new_tb_ticks_per_jiffy; | ||
467 | tb_ticks_per_sec = new_tb_ticks_per_sec; | ||
468 | calc_cputime_factors(); | ||
469 | vdso_data->tb_ticks_per_sec = tb_ticks_per_sec; | ||
470 | setup_cputime_one_jiffy(); | ||
471 | } | ||
472 | else { | ||
473 | printk( "Titan recalibrate: FAILED (difference > 4 percent)\n" | ||
474 | " new tb_ticks_per_jiffy = %lu\n" | ||
475 | " old tb_ticks_per_jiffy = %lu\n", | ||
476 | new_tb_ticks_per_jiffy, tb_ticks_per_jiffy ); | ||
477 | } | ||
478 | } | ||
479 | } | ||
480 | iSeries_recal_titan = titan; | ||
481 | iSeries_recal_tb = tb; | ||
482 | |||
483 | /* Called here as now we know accurate values for the timebase */ | ||
484 | clocksource_init(); | ||
485 | return 0; | ||
486 | } | ||
487 | late_initcall(iSeries_tb_recal); | ||
488 | |||
489 | /* Called from platform early init */ | ||
490 | void __init iSeries_time_init_early(void) | ||
491 | { | ||
492 | iSeries_recal_tb = get_tb(); | ||
493 | iSeries_recal_titan = HvCallXm_loadTod(); | ||
494 | } | ||
495 | #endif /* CONFIG_PPC_ISERIES */ | ||
496 | |||
497 | #ifdef CONFIG_IRQ_WORK | 413 | #ifdef CONFIG_IRQ_WORK |
498 | 414 | ||
499 | /* | 415 | /* |
@@ -550,16 +466,6 @@ void arch_irq_work_raise(void) | |||
550 | #endif /* CONFIG_IRQ_WORK */ | 466 | #endif /* CONFIG_IRQ_WORK */ |
551 | 467 | ||
552 | /* | 468 | /* |
553 | * For iSeries shared processors, we have to let the hypervisor | ||
554 | * set the hardware decrementer. We set a virtual decrementer | ||
555 | * in the lppaca and call the hypervisor if the virtual | ||
556 | * decrementer is less than the current value in the hardware | ||
557 | * decrementer. (almost always the new decrementer value will | ||
558 | * be greater than the current hardware decementer so the hypervisor | ||
559 | * call will not be needed) | ||
560 | */ | ||
561 | |||
562 | /* | ||
563 | * timer_interrupt - gets called when the decrementer overflows, | 469 | * timer_interrupt - gets called when the decrementer overflows, |
564 | * with interrupts disabled. | 470 | * with interrupts disabled. |
565 | */ | 471 | */ |
@@ -580,6 +486,11 @@ void timer_interrupt(struct pt_regs * regs) | |||
580 | if (!cpu_online(smp_processor_id())) | 486 | if (!cpu_online(smp_processor_id())) |
581 | return; | 487 | return; |
582 | 488 | ||
489 | /* Conditionally hard-enable interrupts now that the DEC has been | ||
490 | * bumped to its maximum value | ||
491 | */ | ||
492 | may_hard_irq_enable(); | ||
493 | |||
583 | trace_timer_interrupt_entry(regs); | 494 | trace_timer_interrupt_entry(regs); |
584 | 495 | ||
585 | __get_cpu_var(irq_stat).timer_irqs++; | 496 | __get_cpu_var(irq_stat).timer_irqs++; |
@@ -597,20 +508,10 @@ void timer_interrupt(struct pt_regs * regs) | |||
597 | irq_work_run(); | 508 | irq_work_run(); |
598 | } | 509 | } |
599 | 510 | ||
600 | #ifdef CONFIG_PPC_ISERIES | ||
601 | if (firmware_has_feature(FW_FEATURE_ISERIES)) | ||
602 | get_lppaca()->int_dword.fields.decr_int = 0; | ||
603 | #endif | ||
604 | |||
605 | *next_tb = ~(u64)0; | 511 | *next_tb = ~(u64)0; |
606 | if (evt->event_handler) | 512 | if (evt->event_handler) |
607 | evt->event_handler(evt); | 513 | evt->event_handler(evt); |
608 | 514 | ||
609 | #ifdef CONFIG_PPC_ISERIES | ||
610 | if (firmware_has_feature(FW_FEATURE_ISERIES) && hvlpevent_is_pending()) | ||
611 | process_hvlpevents(); | ||
612 | #endif | ||
613 | |||
614 | #ifdef CONFIG_PPC64 | 515 | #ifdef CONFIG_PPC64 |
615 | /* collect purr register values often, for accurate calculations */ | 516 | /* collect purr register values often, for accurate calculations */ |
616 | if (firmware_has_feature(FW_FEATURE_SPLPAR)) { | 517 | if (firmware_has_feature(FW_FEATURE_SPLPAR)) { |
@@ -982,9 +883,8 @@ void __init time_init(void) | |||
982 | */ | 883 | */ |
983 | start_cpu_decrementer(); | 884 | start_cpu_decrementer(); |
984 | 885 | ||
985 | /* Register the clocksource, if we're not running on iSeries */ | 886 | /* Register the clocksource */ |
986 | if (!firmware_has_feature(FW_FEATURE_ISERIES)) | 887 | clocksource_init(); |
987 | clocksource_init(); | ||
988 | 888 | ||
989 | init_decrementer_clockevent(); | 889 | init_decrementer_clockevent(); |
990 | } | 890 | } |
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index c091527efd89..a750409ccc4e 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c | |||
@@ -57,6 +57,7 @@ | |||
57 | #include <asm/kexec.h> | 57 | #include <asm/kexec.h> |
58 | #include <asm/ppc-opcode.h> | 58 | #include <asm/ppc-opcode.h> |
59 | #include <asm/rio.h> | 59 | #include <asm/rio.h> |
60 | #include <asm/fadump.h> | ||
60 | 61 | ||
61 | #if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) | 62 | #if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) |
62 | int (*__debugger)(struct pt_regs *regs) __read_mostly; | 63 | int (*__debugger)(struct pt_regs *regs) __read_mostly; |
@@ -145,6 +146,8 @@ static void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, | |||
145 | arch_spin_unlock(&die_lock); | 146 | arch_spin_unlock(&die_lock); |
146 | raw_local_irq_restore(flags); | 147 | raw_local_irq_restore(flags); |
147 | 148 | ||
149 | crash_fadump(regs, "die oops"); | ||
150 | |||
148 | /* | 151 | /* |
149 | * A system reset (0x100) is a request to dump, so we always send | 152 | * A system reset (0x100) is a request to dump, so we always send |
150 | * it through the crashdump code. | 153 | * it through the crashdump code. |
@@ -244,6 +247,9 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) | |||
244 | addr, regs->nip, regs->link, code); | 247 | addr, regs->nip, regs->link, code); |
245 | } | 248 | } |
246 | 249 | ||
250 | if (!arch_irq_disabled_regs(regs)) | ||
251 | local_irq_enable(); | ||
252 | |||
247 | memset(&info, 0, sizeof(info)); | 253 | memset(&info, 0, sizeof(info)); |
248 | info.si_signo = signr; | 254 | info.si_signo = signr; |
249 | info.si_code = code; | 255 | info.si_code = code; |
diff --git a/arch/powerpc/kernel/vio.c b/arch/powerpc/kernel/vio.c index 8b086299ba25..bca3fc427b45 100644 --- a/arch/powerpc/kernel/vio.c +++ b/arch/powerpc/kernel/vio.c | |||
@@ -34,11 +34,6 @@ | |||
34 | #include <asm/abs_addr.h> | 34 | #include <asm/abs_addr.h> |
35 | #include <asm/page.h> | 35 | #include <asm/page.h> |
36 | #include <asm/hvcall.h> | 36 | #include <asm/hvcall.h> |
37 | #include <asm/iseries/vio.h> | ||
38 | #include <asm/iseries/hv_types.h> | ||
39 | #include <asm/iseries/hv_lp_config.h> | ||
40 | #include <asm/iseries/hv_call_xm.h> | ||
41 | #include <asm/iseries/iommu.h> | ||
42 | 37 | ||
43 | static struct bus_type vio_bus_type; | 38 | static struct bus_type vio_bus_type; |
44 | 39 | ||
@@ -1042,7 +1037,6 @@ static void vio_cmo_sysfs_init(void) | |||
1042 | vio_bus_type.bus_attrs = vio_cmo_bus_attrs; | 1037 | vio_bus_type.bus_attrs = vio_cmo_bus_attrs; |
1043 | } | 1038 | } |
1044 | #else /* CONFIG_PPC_SMLPAR */ | 1039 | #else /* CONFIG_PPC_SMLPAR */ |
1045 | /* Dummy functions for iSeries platform */ | ||
1046 | int vio_cmo_entitlement_update(size_t new_entitlement) { return 0; } | 1040 | int vio_cmo_entitlement_update(size_t new_entitlement) { return 0; } |
1047 | void vio_cmo_set_dev_desired(struct vio_dev *viodev, size_t desired) {} | 1041 | void vio_cmo_set_dev_desired(struct vio_dev *viodev, size_t desired) {} |
1048 | static int vio_cmo_bus_probe(struct vio_dev *viodev) { return 0; } | 1042 | static int vio_cmo_bus_probe(struct vio_dev *viodev) { return 0; } |
@@ -1060,9 +1054,6 @@ static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev) | |||
1060 | struct iommu_table *tbl; | 1054 | struct iommu_table *tbl; |
1061 | unsigned long offset, size; | 1055 | unsigned long offset, size; |
1062 | 1056 | ||
1063 | if (firmware_has_feature(FW_FEATURE_ISERIES)) | ||
1064 | return vio_build_iommu_table_iseries(dev); | ||
1065 | |||
1066 | dma_window = of_get_property(dev->dev.of_node, | 1057 | dma_window = of_get_property(dev->dev.of_node, |
1067 | "ibm,my-dma-window", NULL); | 1058 | "ibm,my-dma-window", NULL); |
1068 | if (!dma_window) | 1059 | if (!dma_window) |
@@ -1195,8 +1186,7 @@ static void __devinit vio_dev_release(struct device *dev) | |||
1195 | { | 1186 | { |
1196 | struct iommu_table *tbl = get_iommu_table_base(dev); | 1187 | struct iommu_table *tbl = get_iommu_table_base(dev); |
1197 | 1188 | ||
1198 | /* iSeries uses a common table for all vio devices */ | 1189 | if (tbl) |
1199 | if (!firmware_has_feature(FW_FEATURE_ISERIES) && tbl) | ||
1200 | iommu_free_table(tbl, dev->of_node ? | 1190 | iommu_free_table(tbl, dev->of_node ? |
1201 | dev->of_node->full_name : dev_name(dev)); | 1191 | dev->of_node->full_name : dev_name(dev)); |
1202 | of_node_put(dev->of_node); | 1192 | of_node_put(dev->of_node); |
@@ -1244,12 +1234,6 @@ struct vio_dev *vio_register_device_node(struct device_node *of_node) | |||
1244 | viodev->name = of_node->name; | 1234 | viodev->name = of_node->name; |
1245 | viodev->type = of_node->type; | 1235 | viodev->type = of_node->type; |
1246 | viodev->unit_address = *unit_address; | 1236 | viodev->unit_address = *unit_address; |
1247 | if (firmware_has_feature(FW_FEATURE_ISERIES)) { | ||
1248 | unit_address = of_get_property(of_node, | ||
1249 | "linux,unit_address", NULL); | ||
1250 | if (unit_address != NULL) | ||
1251 | viodev->unit_address = *unit_address; | ||
1252 | } | ||
1253 | viodev->dev.of_node = of_node_get(of_node); | 1237 | viodev->dev.of_node = of_node_get(of_node); |
1254 | 1238 | ||
1255 | if (firmware_has_feature(FW_FEATURE_CMO)) | 1239 | if (firmware_has_feature(FW_FEATURE_CMO)) |
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S index 710a54005dfb..65d1c08cf09e 100644 --- a/arch/powerpc/kernel/vmlinux.lds.S +++ b/arch/powerpc/kernel/vmlinux.lds.S | |||
@@ -109,11 +109,6 @@ SECTIONS | |||
109 | __ptov_table_begin = .; | 109 | __ptov_table_begin = .; |
110 | *(.ptov_fixup); | 110 | *(.ptov_fixup); |
111 | __ptov_table_end = .; | 111 | __ptov_table_end = .; |
112 | #ifdef CONFIG_PPC_ISERIES | ||
113 | __dt_strings_start = .; | ||
114 | *(.dt_strings); | ||
115 | __dt_strings_end = .; | ||
116 | #endif | ||
117 | } | 112 | } |
118 | 113 | ||
119 | .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) { | 114 | .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) { |
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index 336983da9e72..a7267167a550 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c | |||
@@ -46,7 +46,6 @@ | |||
46 | #include <asm/page.h> | 46 | #include <asm/page.h> |
47 | #include <asm/hvcall.h> | 47 | #include <asm/hvcall.h> |
48 | #include <linux/gfp.h> | 48 | #include <linux/gfp.h> |
49 | #include <linux/sched.h> | ||
50 | #include <linux/vmalloc.h> | 49 | #include <linux/vmalloc.h> |
51 | #include <linux/highmem.h> | 50 | #include <linux/highmem.h> |
52 | 51 | ||
diff --git a/arch/powerpc/lib/locks.c b/arch/powerpc/lib/locks.c index a6ebba56fdd4..bb7cfecf2788 100644 --- a/arch/powerpc/lib/locks.c +++ b/arch/powerpc/lib/locks.c | |||
@@ -19,11 +19,9 @@ | |||
19 | #include <linux/smp.h> | 19 | #include <linux/smp.h> |
20 | 20 | ||
21 | /* waiting for a spinlock... */ | 21 | /* waiting for a spinlock... */ |
22 | #if defined(CONFIG_PPC_SPLPAR) || defined(CONFIG_PPC_ISERIES) | 22 | #if defined(CONFIG_PPC_SPLPAR) |
23 | #include <asm/hvcall.h> | 23 | #include <asm/hvcall.h> |
24 | #include <asm/iseries/hv_call.h> | ||
25 | #include <asm/smp.h> | 24 | #include <asm/smp.h> |
26 | #include <asm/firmware.h> | ||
27 | 25 | ||
28 | void __spin_yield(arch_spinlock_t *lock) | 26 | void __spin_yield(arch_spinlock_t *lock) |
29 | { | 27 | { |
@@ -40,14 +38,8 @@ void __spin_yield(arch_spinlock_t *lock) | |||
40 | rmb(); | 38 | rmb(); |
41 | if (lock->slock != lock_value) | 39 | if (lock->slock != lock_value) |
42 | return; /* something has changed */ | 40 | return; /* something has changed */ |
43 | if (firmware_has_feature(FW_FEATURE_ISERIES)) | 41 | plpar_hcall_norets(H_CONFER, |
44 | HvCall2(HvCallBaseYieldProcessor, HvCall_YieldToProc, | 42 | get_hard_smp_processor_id(holder_cpu), yield_count); |
45 | ((u64)holder_cpu << 32) | yield_count); | ||
46 | #ifdef CONFIG_PPC_SPLPAR | ||
47 | else | ||
48 | plpar_hcall_norets(H_CONFER, | ||
49 | get_hard_smp_processor_id(holder_cpu), yield_count); | ||
50 | #endif | ||
51 | } | 43 | } |
52 | 44 | ||
53 | /* | 45 | /* |
@@ -71,14 +63,8 @@ void __rw_yield(arch_rwlock_t *rw) | |||
71 | rmb(); | 63 | rmb(); |
72 | if (rw->lock != lock_value) | 64 | if (rw->lock != lock_value) |
73 | return; /* something has changed */ | 65 | return; /* something has changed */ |
74 | if (firmware_has_feature(FW_FEATURE_ISERIES)) | 66 | plpar_hcall_norets(H_CONFER, |
75 | HvCall2(HvCallBaseYieldProcessor, HvCall_YieldToProc, | 67 | get_hard_smp_processor_id(holder_cpu), yield_count); |
76 | ((u64)holder_cpu << 32) | yield_count); | ||
77 | #ifdef CONFIG_PPC_SPLPAR | ||
78 | else | ||
79 | plpar_hcall_norets(H_CONFER, | ||
80 | get_hard_smp_processor_id(holder_cpu), yield_count); | ||
81 | #endif | ||
82 | } | 68 | } |
83 | #endif | 69 | #endif |
84 | 70 | ||
diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c index 2f0d1b032a89..19f2f9498b27 100644 --- a/arch/powerpc/mm/fault.c +++ b/arch/powerpc/mm/fault.c | |||
@@ -105,6 +105,82 @@ static int store_updates_sp(struct pt_regs *regs) | |||
105 | } | 105 | } |
106 | return 0; | 106 | return 0; |
107 | } | 107 | } |
108 | /* | ||
109 | * do_page_fault error handling helpers | ||
110 | */ | ||
111 | |||
112 | #define MM_FAULT_RETURN 0 | ||
113 | #define MM_FAULT_CONTINUE -1 | ||
114 | #define MM_FAULT_ERR(sig) (sig) | ||
115 | |||
116 | static int out_of_memory(struct pt_regs *regs) | ||
117 | { | ||
118 | /* | ||
119 | * We ran out of memory, or some other thing happened to us that made | ||
120 | * us unable to handle the page fault gracefully. | ||
121 | */ | ||
122 | up_read(¤t->mm->mmap_sem); | ||
123 | if (!user_mode(regs)) | ||
124 | return MM_FAULT_ERR(SIGKILL); | ||
125 | pagefault_out_of_memory(); | ||
126 | return MM_FAULT_RETURN; | ||
127 | } | ||
128 | |||
129 | static int do_sigbus(struct pt_regs *regs, unsigned long address) | ||
130 | { | ||
131 | siginfo_t info; | ||
132 | |||
133 | up_read(¤t->mm->mmap_sem); | ||
134 | |||
135 | if (user_mode(regs)) { | ||
136 | info.si_signo = SIGBUS; | ||
137 | info.si_errno = 0; | ||
138 | info.si_code = BUS_ADRERR; | ||
139 | info.si_addr = (void __user *)address; | ||
140 | force_sig_info(SIGBUS, &info, current); | ||
141 | return MM_FAULT_RETURN; | ||
142 | } | ||
143 | return MM_FAULT_ERR(SIGBUS); | ||
144 | } | ||
145 | |||
146 | static int mm_fault_error(struct pt_regs *regs, unsigned long addr, int fault) | ||
147 | { | ||
148 | /* | ||
149 | * Pagefault was interrupted by SIGKILL. We have no reason to | ||
150 | * continue the pagefault. | ||
151 | */ | ||
152 | if (fatal_signal_pending(current)) { | ||
153 | /* | ||
154 | * If we have retry set, the mmap semaphore will have | ||
155 | * alrady been released in __lock_page_or_retry(). Else | ||
156 | * we release it now. | ||
157 | */ | ||
158 | if (!(fault & VM_FAULT_RETRY)) | ||
159 | up_read(¤t->mm->mmap_sem); | ||
160 | /* Coming from kernel, we need to deal with uaccess fixups */ | ||
161 | if (user_mode(regs)) | ||
162 | return MM_FAULT_RETURN; | ||
163 | return MM_FAULT_ERR(SIGKILL); | ||
164 | } | ||
165 | |||
166 | /* No fault: be happy */ | ||
167 | if (!(fault & VM_FAULT_ERROR)) | ||
168 | return MM_FAULT_CONTINUE; | ||
169 | |||
170 | /* Out of memory */ | ||
171 | if (fault & VM_FAULT_OOM) | ||
172 | return out_of_memory(regs); | ||
173 | |||
174 | /* Bus error. x86 handles HWPOISON here, we'll add this if/when | ||
175 | * we support the feature in HW | ||
176 | */ | ||
177 | if (fault & VM_FAULT_SIGBUS) | ||
178 | return do_sigbus(regs, addr); | ||
179 | |||
180 | /* We don't understand the fault code, this is fatal */ | ||
181 | BUG(); | ||
182 | return MM_FAULT_CONTINUE; | ||
183 | } | ||
108 | 184 | ||
109 | /* | 185 | /* |
110 | * For 600- and 800-family processors, the error_code parameter is DSISR | 186 | * For 600- and 800-family processors, the error_code parameter is DSISR |
@@ -124,11 +200,12 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, | |||
124 | { | 200 | { |
125 | struct vm_area_struct * vma; | 201 | struct vm_area_struct * vma; |
126 | struct mm_struct *mm = current->mm; | 202 | struct mm_struct *mm = current->mm; |
127 | siginfo_t info; | 203 | unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE; |
128 | int code = SEGV_MAPERR; | 204 | int code = SEGV_MAPERR; |
129 | int is_write = 0, ret; | 205 | int is_write = 0; |
130 | int trap = TRAP(regs); | 206 | int trap = TRAP(regs); |
131 | int is_exec = trap == 0x400; | 207 | int is_exec = trap == 0x400; |
208 | int fault; | ||
132 | 209 | ||
133 | #if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE)) | 210 | #if !(defined(CONFIG_4xx) || defined(CONFIG_BOOKE)) |
134 | /* | 211 | /* |
@@ -145,6 +222,9 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, | |||
145 | is_write = error_code & ESR_DST; | 222 | is_write = error_code & ESR_DST; |
146 | #endif /* CONFIG_4xx || CONFIG_BOOKE */ | 223 | #endif /* CONFIG_4xx || CONFIG_BOOKE */ |
147 | 224 | ||
225 | if (is_write) | ||
226 | flags |= FAULT_FLAG_WRITE; | ||
227 | |||
148 | #ifdef CONFIG_PPC_ICSWX | 228 | #ifdef CONFIG_PPC_ICSWX |
149 | /* | 229 | /* |
150 | * we need to do this early because this "data storage | 230 | * we need to do this early because this "data storage |
@@ -152,13 +232,11 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, | |||
152 | * look at it | 232 | * look at it |
153 | */ | 233 | */ |
154 | if (error_code & ICSWX_DSI_UCT) { | 234 | if (error_code & ICSWX_DSI_UCT) { |
155 | int ret; | 235 | int rc = acop_handle_fault(regs, address, error_code); |
156 | 236 | if (rc) | |
157 | ret = acop_handle_fault(regs, address, error_code); | 237 | return rc; |
158 | if (ret) | ||
159 | return ret; | ||
160 | } | 238 | } |
161 | #endif | 239 | #endif /* CONFIG_PPC_ICSWX */ |
162 | 240 | ||
163 | if (notify_page_fault(regs)) | 241 | if (notify_page_fault(regs)) |
164 | return 0; | 242 | return 0; |
@@ -179,6 +257,10 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, | |||
179 | } | 257 | } |
180 | #endif | 258 | #endif |
181 | 259 | ||
260 | /* We restore the interrupt state now */ | ||
261 | if (!arch_irq_disabled_regs(regs)) | ||
262 | local_irq_enable(); | ||
263 | |||
182 | if (in_atomic() || mm == NULL) { | 264 | if (in_atomic() || mm == NULL) { |
183 | if (!user_mode(regs)) | 265 | if (!user_mode(regs)) |
184 | return SIGSEGV; | 266 | return SIGSEGV; |
@@ -212,7 +294,15 @@ int __kprobes do_page_fault(struct pt_regs *regs, unsigned long address, | |||
212 | if (!user_mode(regs) && !search_exception_tables(regs->nip)) | 294 | if (!user_mode(regs) && !search_exception_tables(regs->nip)) |
213 | goto bad_area_nosemaphore; | 295 | goto bad_area_nosemaphore; |
214 | 296 | ||
297 | retry: | ||
215 | down_read(&mm->mmap_sem); | 298 | down_read(&mm->mmap_sem); |
299 | } else { | ||
300 | /* | ||
301 | * The above down_read_trylock() might have succeeded in | ||
302 | * which case we'll have missed the might_sleep() from | ||
303 | * down_read(): | ||
304 | */ | ||
305 | might_sleep(); | ||
216 | } | 306 | } |
217 | 307 | ||
218 | vma = find_vma(mm, address); | 308 | vma = find_vma(mm, address); |
@@ -327,30 +417,43 @@ good_area: | |||
327 | * make sure we exit gracefully rather than endlessly redo | 417 | * make sure we exit gracefully rather than endlessly redo |
328 | * the fault. | 418 | * the fault. |
329 | */ | 419 | */ |
330 | ret = handle_mm_fault(mm, vma, address, is_write ? FAULT_FLAG_WRITE : 0); | 420 | fault = handle_mm_fault(mm, vma, address, flags); |
331 | if (unlikely(ret & VM_FAULT_ERROR)) { | 421 | if (unlikely(fault & (VM_FAULT_RETRY|VM_FAULT_ERROR))) { |
332 | if (ret & VM_FAULT_OOM) | 422 | int rc = mm_fault_error(regs, address, fault); |
333 | goto out_of_memory; | 423 | if (rc >= MM_FAULT_RETURN) |
334 | else if (ret & VM_FAULT_SIGBUS) | 424 | return rc; |
335 | goto do_sigbus; | ||
336 | BUG(); | ||
337 | } | 425 | } |
338 | if (ret & VM_FAULT_MAJOR) { | 426 | |
339 | current->maj_flt++; | 427 | /* |
340 | perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, | 428 | * Major/minor page fault accounting is only done on the |
341 | regs, address); | 429 | * initial attempt. If we go through a retry, it is extremely |
430 | * likely that the page will be found in page cache at that point. | ||
431 | */ | ||
432 | if (flags & FAULT_FLAG_ALLOW_RETRY) { | ||
433 | if (fault & VM_FAULT_MAJOR) { | ||
434 | current->maj_flt++; | ||
435 | perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MAJ, 1, | ||
436 | regs, address); | ||
342 | #ifdef CONFIG_PPC_SMLPAR | 437 | #ifdef CONFIG_PPC_SMLPAR |
343 | if (firmware_has_feature(FW_FEATURE_CMO)) { | 438 | if (firmware_has_feature(FW_FEATURE_CMO)) { |
344 | preempt_disable(); | 439 | preempt_disable(); |
345 | get_lppaca()->page_ins += (1 << PAGE_FACTOR); | 440 | get_lppaca()->page_ins += (1 << PAGE_FACTOR); |
346 | preempt_enable(); | 441 | preempt_enable(); |
442 | } | ||
443 | #endif /* CONFIG_PPC_SMLPAR */ | ||
444 | } else { | ||
445 | current->min_flt++; | ||
446 | perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, | ||
447 | regs, address); | ||
448 | } | ||
449 | if (fault & VM_FAULT_RETRY) { | ||
450 | /* Clear FAULT_FLAG_ALLOW_RETRY to avoid any risk | ||
451 | * of starvation. */ | ||
452 | flags &= ~FAULT_FLAG_ALLOW_RETRY; | ||
453 | goto retry; | ||
347 | } | 454 | } |
348 | #endif | ||
349 | } else { | ||
350 | current->min_flt++; | ||
351 | perf_sw_event(PERF_COUNT_SW_PAGE_FAULTS_MIN, 1, | ||
352 | regs, address); | ||
353 | } | 455 | } |
456 | |||
354 | up_read(&mm->mmap_sem); | 457 | up_read(&mm->mmap_sem); |
355 | return 0; | 458 | return 0; |
356 | 459 | ||
@@ -371,28 +474,6 @@ bad_area_nosemaphore: | |||
371 | 474 | ||
372 | return SIGSEGV; | 475 | return SIGSEGV; |
373 | 476 | ||
374 | /* | ||
375 | * We ran out of memory, or some other thing happened to us that made | ||
376 | * us unable to handle the page fault gracefully. | ||
377 | */ | ||
378 | out_of_memory: | ||
379 | up_read(&mm->mmap_sem); | ||
380 | if (!user_mode(regs)) | ||
381 | return SIGKILL; | ||
382 | pagefault_out_of_memory(); | ||
383 | return 0; | ||
384 | |||
385 | do_sigbus: | ||
386 | up_read(&mm->mmap_sem); | ||
387 | if (user_mode(regs)) { | ||
388 | info.si_signo = SIGBUS; | ||
389 | info.si_errno = 0; | ||
390 | info.si_code = BUS_ADRERR; | ||
391 | info.si_addr = (void __user *)address; | ||
392 | force_sig_info(SIGBUS, &info, current); | ||
393 | return 0; | ||
394 | } | ||
395 | return SIGBUS; | ||
396 | } | 477 | } |
397 | 478 | ||
398 | /* | 479 | /* |
diff --git a/arch/powerpc/mm/fsl_booke_mmu.c b/arch/powerpc/mm/fsl_booke_mmu.c index 66a6fd38e9cd..07ba45b0f07c 100644 --- a/arch/powerpc/mm/fsl_booke_mmu.c +++ b/arch/powerpc/mm/fsl_booke_mmu.c | |||
@@ -149,12 +149,19 @@ static void settlbcam(int index, unsigned long virt, phys_addr_t phys, | |||
149 | unsigned long calc_cam_sz(unsigned long ram, unsigned long virt, | 149 | unsigned long calc_cam_sz(unsigned long ram, unsigned long virt, |
150 | phys_addr_t phys) | 150 | phys_addr_t phys) |
151 | { | 151 | { |
152 | unsigned int camsize = __ilog2(ram) & ~1U; | 152 | unsigned int camsize = __ilog2(ram); |
153 | unsigned int align = __ffs(virt | phys) & ~1U; | 153 | unsigned int align = __ffs(virt | phys); |
154 | unsigned long max_cam = (mfspr(SPRN_TLB1CFG) >> 16) & 0xf; | 154 | unsigned long max_cam; |
155 | 155 | ||
156 | /* Convert (4^max) kB to (2^max) bytes */ | 156 | if ((mfspr(SPRN_MMUCFG) & MMUCFG_MAVN) == MMUCFG_MAVN_V1) { |
157 | max_cam = max_cam * 2 + 10; | 157 | /* Convert (4^max) kB to (2^max) bytes */ |
158 | max_cam = ((mfspr(SPRN_TLB1CFG) >> 16) & 0xf) * 2 + 10; | ||
159 | camsize &= ~1U; | ||
160 | align &= ~1U; | ||
161 | } else { | ||
162 | /* Convert (2^max) kB to (2^max) bytes */ | ||
163 | max_cam = __ilog2(mfspr(SPRN_TLB1PS)) + 10; | ||
164 | } | ||
158 | 165 | ||
159 | if (camsize > align) | 166 | if (camsize > align) |
160 | camsize = align; | 167 | camsize = align; |
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index 2d282186cb45..3e8c37a4e395 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c | |||
@@ -55,6 +55,8 @@ | |||
55 | #include <asm/spu.h> | 55 | #include <asm/spu.h> |
56 | #include <asm/udbg.h> | 56 | #include <asm/udbg.h> |
57 | #include <asm/code-patching.h> | 57 | #include <asm/code-patching.h> |
58 | #include <asm/fadump.h> | ||
59 | #include <asm/firmware.h> | ||
58 | 60 | ||
59 | #ifdef DEBUG | 61 | #ifdef DEBUG |
60 | #define DBG(fmt...) udbg_printf(fmt) | 62 | #define DBG(fmt...) udbg_printf(fmt) |
@@ -625,6 +627,16 @@ static void __init htab_initialize(void) | |||
625 | /* Using a hypervisor which owns the htab */ | 627 | /* Using a hypervisor which owns the htab */ |
626 | htab_address = NULL; | 628 | htab_address = NULL; |
627 | _SDR1 = 0; | 629 | _SDR1 = 0; |
630 | #ifdef CONFIG_FA_DUMP | ||
631 | /* | ||
632 | * If firmware assisted dump is active firmware preserves | ||
633 | * the contents of htab along with entire partition memory. | ||
634 | * Clear the htab if firmware assisted dump is active so | ||
635 | * that we dont end up using old mappings. | ||
636 | */ | ||
637 | if (is_fadump_active() && ppc_md.hpte_clear_all) | ||
638 | ppc_md.hpte_clear_all(); | ||
639 | #endif | ||
628 | } else { | 640 | } else { |
629 | /* Find storage for the HPT. Must be contiguous in | 641 | /* Find storage for the HPT. Must be contiguous in |
630 | * the absolute address space. On cell we want it to be | 642 | * the absolute address space. On cell we want it to be |
@@ -745,12 +757,9 @@ void __init early_init_mmu(void) | |||
745 | */ | 757 | */ |
746 | htab_initialize(); | 758 | htab_initialize(); |
747 | 759 | ||
748 | /* Initialize stab / SLB management except on iSeries | 760 | /* Initialize stab / SLB management */ |
749 | */ | ||
750 | if (mmu_has_feature(MMU_FTR_SLB)) | 761 | if (mmu_has_feature(MMU_FTR_SLB)) |
751 | slb_initialize(); | 762 | slb_initialize(); |
752 | else if (!firmware_has_feature(FW_FEATURE_ISERIES)) | ||
753 | stab_initialize(get_paca()->stab_real); | ||
754 | } | 763 | } |
755 | 764 | ||
756 | #ifdef CONFIG_SMP | 765 | #ifdef CONFIG_SMP |
@@ -761,8 +770,7 @@ void __cpuinit early_init_mmu_secondary(void) | |||
761 | mtspr(SPRN_SDR1, _SDR1); | 770 | mtspr(SPRN_SDR1, _SDR1); |
762 | 771 | ||
763 | /* Initialize STAB/SLB. We use a virtual address as it works | 772 | /* Initialize STAB/SLB. We use a virtual address as it works |
764 | * in real mode on pSeries and we want a virtual address on | 773 | * in real mode on pSeries. |
765 | * iSeries anyway | ||
766 | */ | 774 | */ |
767 | if (mmu_has_feature(MMU_FTR_SLB)) | 775 | if (mmu_has_feature(MMU_FTR_SLB)) |
768 | slb_initialize(); | 776 | slb_initialize(); |
diff --git a/arch/powerpc/mm/icswx.c b/arch/powerpc/mm/icswx.c index 5d9a59eaad93..8cdbd8634a58 100644 --- a/arch/powerpc/mm/icswx.c +++ b/arch/powerpc/mm/icswx.c | |||
@@ -163,7 +163,7 @@ EXPORT_SYMBOL_GPL(drop_cop); | |||
163 | 163 | ||
164 | static int acop_use_cop(int ct) | 164 | static int acop_use_cop(int ct) |
165 | { | 165 | { |
166 | /* todo */ | 166 | /* There is no alternate policy, yet */ |
167 | return -1; | 167 | return -1; |
168 | } | 168 | } |
169 | 169 | ||
@@ -227,11 +227,30 @@ int acop_handle_fault(struct pt_regs *regs, unsigned long address, | |||
227 | ct = (ccw >> 16) & 0x3f; | 227 | ct = (ccw >> 16) & 0x3f; |
228 | } | 228 | } |
229 | 229 | ||
230 | /* | ||
231 | * We could be here because another thread has enabled acop | ||
232 | * but the ACOP register has yet to be updated. | ||
233 | * | ||
234 | * This should have been taken care of by the IPI to sync all | ||
235 | * the threads (see smp_call_function(sync_cop, mm, 1)), but | ||
236 | * that could take forever if there are a significant amount | ||
237 | * of threads. | ||
238 | * | ||
239 | * Given the number of threads on some of these systems, | ||
240 | * perhaps this is the best way to sync ACOP rather than whack | ||
241 | * every thread with an IPI. | ||
242 | */ | ||
243 | if ((acop_copro_type_bit(ct) & current->active_mm->context.acop) != 0) { | ||
244 | sync_cop(current->active_mm); | ||
245 | return 0; | ||
246 | } | ||
247 | |||
248 | /* check for alternate policy */ | ||
230 | if (!acop_use_cop(ct)) | 249 | if (!acop_use_cop(ct)) |
231 | return 0; | 250 | return 0; |
232 | 251 | ||
233 | /* at this point the CT is unknown to the system */ | 252 | /* at this point the CT is unknown to the system */ |
234 | pr_warn("%s[%d]: Coprocessor %d is unavailable", | 253 | pr_warn("%s[%d]: Coprocessor %d is unavailable\n", |
235 | current->comm, current->pid, ct); | 254 | current->comm, current->pid, ct); |
236 | 255 | ||
237 | /* get inst if we don't already have it */ | 256 | /* get inst if we don't already have it */ |
diff --git a/arch/powerpc/mm/icswx.h b/arch/powerpc/mm/icswx.h index 42176bd0884c..6dedc08e62c8 100644 --- a/arch/powerpc/mm/icswx.h +++ b/arch/powerpc/mm/icswx.h | |||
@@ -59,4 +59,10 @@ extern void free_cop_pid(int free_pid); | |||
59 | 59 | ||
60 | extern int acop_handle_fault(struct pt_regs *regs, unsigned long address, | 60 | extern int acop_handle_fault(struct pt_regs *regs, unsigned long address, |
61 | unsigned long error_code); | 61 | unsigned long error_code); |
62 | |||
63 | static inline u64 acop_copro_type_bit(unsigned int type) | ||
64 | { | ||
65 | return 1ULL << (63 - type); | ||
66 | } | ||
67 | |||
62 | #endif /* !_ARCH_POWERPC_MM_ICSWX_H_ */ | 68 | #endif /* !_ARCH_POWERPC_MM_ICSWX_H_ */ |
diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c index 51f87956f8f8..0907f92ce309 100644 --- a/arch/powerpc/mm/pgtable_32.c +++ b/arch/powerpc/mm/pgtable_32.c | |||
@@ -207,7 +207,7 @@ __ioremap_caller(phys_addr_t addr, unsigned long size, unsigned long flags, | |||
207 | */ | 207 | */ |
208 | if (mem_init_done && (p < virt_to_phys(high_memory)) && | 208 | if (mem_init_done && (p < virt_to_phys(high_memory)) && |
209 | !(__allow_ioremap_reserved && memblock_is_region_reserved(p, size))) { | 209 | !(__allow_ioremap_reserved && memblock_is_region_reserved(p, size))) { |
210 | printk("__ioremap(): phys addr 0x%llx is RAM lr %p\n", | 210 | printk("__ioremap(): phys addr 0x%llx is RAM lr %pf\n", |
211 | (unsigned long long)p, __builtin_return_address(0)); | 211 | (unsigned long long)p, __builtin_return_address(0)); |
212 | return NULL; | 212 | return NULL; |
213 | } | 213 | } |
diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c index e22276cb67a4..a538c80db2df 100644 --- a/arch/powerpc/mm/slb.c +++ b/arch/powerpc/mm/slb.c | |||
@@ -21,7 +21,6 @@ | |||
21 | #include <asm/cputable.h> | 21 | #include <asm/cputable.h> |
22 | #include <asm/cacheflush.h> | 22 | #include <asm/cacheflush.h> |
23 | #include <asm/smp.h> | 23 | #include <asm/smp.h> |
24 | #include <asm/firmware.h> | ||
25 | #include <linux/compiler.h> | 24 | #include <linux/compiler.h> |
26 | #include <asm/udbg.h> | 25 | #include <asm/udbg.h> |
27 | #include <asm/code-patching.h> | 26 | #include <asm/code-patching.h> |
@@ -307,11 +306,6 @@ void slb_initialize(void) | |||
307 | 306 | ||
308 | get_paca()->stab_rr = SLB_NUM_BOLTED; | 307 | get_paca()->stab_rr = SLB_NUM_BOLTED; |
309 | 308 | ||
310 | /* On iSeries the bolted entries have already been set up by | ||
311 | * the hypervisor from the lparMap data in head.S */ | ||
312 | if (firmware_has_feature(FW_FEATURE_ISERIES)) | ||
313 | return; | ||
314 | |||
315 | lflags = SLB_VSID_KERNEL | linear_llp; | 309 | lflags = SLB_VSID_KERNEL | linear_llp; |
316 | vflags = SLB_VSID_KERNEL | vmalloc_llp; | 310 | vflags = SLB_VSID_KERNEL | vmalloc_llp; |
317 | 311 | ||
diff --git a/arch/powerpc/mm/slb_low.S b/arch/powerpc/mm/slb_low.S index ef653dc95b65..b9ee79ce2200 100644 --- a/arch/powerpc/mm/slb_low.S +++ b/arch/powerpc/mm/slb_low.S | |||
@@ -217,21 +217,6 @@ slb_finish_load: | |||
217 | * free slot first but that took too long. Unfortunately we | 217 | * free slot first but that took too long. Unfortunately we |
218 | * dont have any LRU information to help us choose a slot. | 218 | * dont have any LRU information to help us choose a slot. |
219 | */ | 219 | */ |
220 | #ifdef CONFIG_PPC_ISERIES | ||
221 | BEGIN_FW_FTR_SECTION | ||
222 | /* | ||
223 | * On iSeries, the "bolted" stack segment can be cast out on | ||
224 | * shared processor switch so we need to check for a miss on | ||
225 | * it and restore it to the right slot. | ||
226 | */ | ||
227 | ld r9,PACAKSAVE(r13) | ||
228 | clrrdi r9,r9,28 | ||
229 | clrrdi r3,r3,28 | ||
230 | li r10,SLB_NUM_BOLTED-1 /* Stack goes in last bolted slot */ | ||
231 | cmpld r9,r3 | ||
232 | beq 3f | ||
233 | END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES) | ||
234 | #endif /* CONFIG_PPC_ISERIES */ | ||
235 | 220 | ||
236 | 7: ld r10,PACASTABRR(r13) | 221 | 7: ld r10,PACASTABRR(r13) |
237 | addi r10,r10,1 | 222 | addi r10,r10,1 |
@@ -282,7 +267,6 @@ _GLOBAL(slb_compare_rr_to_size) | |||
282 | 267 | ||
283 | /* | 268 | /* |
284 | * Finish loading of a 1T SLB entry (for the kernel linear mapping) and return. | 269 | * Finish loading of a 1T SLB entry (for the kernel linear mapping) and return. |
285 | * We assume legacy iSeries will never have 1T segments. | ||
286 | * | 270 | * |
287 | * r3 = EA, r10 = proto-VSID, r11 = flags, clobbers r9 | 271 | * r3 = EA, r10 = proto-VSID, r11 = flags, clobbers r9 |
288 | */ | 272 | */ |
diff --git a/arch/powerpc/mm/stab.c b/arch/powerpc/mm/stab.c index 41e31642a86a..9106ebb118f5 100644 --- a/arch/powerpc/mm/stab.c +++ b/arch/powerpc/mm/stab.c | |||
@@ -21,8 +21,6 @@ | |||
21 | #include <asm/cputable.h> | 21 | #include <asm/cputable.h> |
22 | #include <asm/prom.h> | 22 | #include <asm/prom.h> |
23 | #include <asm/abs_addr.h> | 23 | #include <asm/abs_addr.h> |
24 | #include <asm/firmware.h> | ||
25 | #include <asm/iseries/hv_call.h> | ||
26 | 24 | ||
27 | struct stab_entry { | 25 | struct stab_entry { |
28 | unsigned long esid_data; | 26 | unsigned long esid_data; |
@@ -285,12 +283,5 @@ void stab_initialize(unsigned long stab) | |||
285 | /* Set ASR */ | 283 | /* Set ASR */ |
286 | stabreal = get_paca()->stab_real | 0x1ul; | 284 | stabreal = get_paca()->stab_real | 0x1ul; |
287 | 285 | ||
288 | #ifdef CONFIG_PPC_ISERIES | ||
289 | if (firmware_has_feature(FW_FEATURE_ISERIES)) { | ||
290 | HvCall1(HvCallBaseSetASR, stabreal); | ||
291 | return; | ||
292 | } | ||
293 | #endif /* CONFIG_PPC_ISERIES */ | ||
294 | |||
295 | mtspr(SPRN_ASR, stabreal); | 286 | mtspr(SPRN_ASR, stabreal); |
296 | } | 287 | } |
diff --git a/arch/powerpc/oprofile/common.c b/arch/powerpc/oprofile/common.c index d65e68f3cb25..6f01624f317f 100644 --- a/arch/powerpc/oprofile/common.c +++ b/arch/powerpc/oprofile/common.c | |||
@@ -195,9 +195,6 @@ int __init oprofile_arch_init(struct oprofile_operations *ops) | |||
195 | if (!cur_cpu_spec->oprofile_cpu_type) | 195 | if (!cur_cpu_spec->oprofile_cpu_type) |
196 | return -ENODEV; | 196 | return -ENODEV; |
197 | 197 | ||
198 | if (firmware_has_feature(FW_FEATURE_ISERIES)) | ||
199 | return -ENODEV; | ||
200 | |||
201 | switch (cur_cpu_spec->oprofile_type) { | 198 | switch (cur_cpu_spec->oprofile_type) { |
202 | #ifdef CONFIG_PPC_BOOK3S_64 | 199 | #ifdef CONFIG_PPC_BOOK3S_64 |
203 | #ifdef CONFIG_OPROFILE_CELL | 200 | #ifdef CONFIG_OPROFILE_CELL |
diff --git a/arch/powerpc/perf/Makefile b/arch/powerpc/perf/Makefile new file mode 100644 index 000000000000..af3fac23768c --- /dev/null +++ b/arch/powerpc/perf/Makefile | |||
@@ -0,0 +1,14 @@ | |||
1 | subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror | ||
2 | |||
3 | obj-$(CONFIG_PERF_EVENTS) += callchain.o | ||
4 | |||
5 | obj-$(CONFIG_PPC_PERF_CTRS) += core-book3s.o | ||
6 | obj64-$(CONFIG_PPC_PERF_CTRS) += power4-pmu.o ppc970-pmu.o power5-pmu.o \ | ||
7 | power5+-pmu.o power6-pmu.o power7-pmu.o | ||
8 | obj32-$(CONFIG_PPC_PERF_CTRS) += mpc7450-pmu.o | ||
9 | |||
10 | obj-$(CONFIG_FSL_EMB_PERF_EVENT) += core-fsl-emb.o | ||
11 | obj-$(CONFIG_FSL_EMB_PERF_EVENT_E500) += e500-pmu.o | ||
12 | |||
13 | obj-$(CONFIG_PPC64) += $(obj64-y) | ||
14 | obj-$(CONFIG_PPC32) += $(obj32-y) | ||
diff --git a/arch/powerpc/kernel/perf_callchain.c b/arch/powerpc/perf/callchain.c index 564c1d8bdb5c..e8a18d1cc7c9 100644 --- a/arch/powerpc/kernel/perf_callchain.c +++ b/arch/powerpc/perf/callchain.c | |||
@@ -20,7 +20,7 @@ | |||
20 | #include <asm/ucontext.h> | 20 | #include <asm/ucontext.h> |
21 | #include <asm/vdso.h> | 21 | #include <asm/vdso.h> |
22 | #ifdef CONFIG_PPC64 | 22 | #ifdef CONFIG_PPC64 |
23 | #include "ppc32.h" | 23 | #include "../kernel/ppc32.h" |
24 | #endif | 24 | #endif |
25 | 25 | ||
26 | 26 | ||
diff --git a/arch/powerpc/kernel/perf_event.c b/arch/powerpc/perf/core-book3s.c index c2e27ede07ec..c2e27ede07ec 100644 --- a/arch/powerpc/kernel/perf_event.c +++ b/arch/powerpc/perf/core-book3s.c | |||
diff --git a/arch/powerpc/kernel/perf_event_fsl_emb.c b/arch/powerpc/perf/core-fsl-emb.c index 0a6d2a9d569c..0a6d2a9d569c 100644 --- a/arch/powerpc/kernel/perf_event_fsl_emb.c +++ b/arch/powerpc/perf/core-fsl-emb.c | |||
diff --git a/arch/powerpc/kernel/e500-pmu.c b/arch/powerpc/perf/e500-pmu.c index cb2e2949c8d1..cb2e2949c8d1 100644 --- a/arch/powerpc/kernel/e500-pmu.c +++ b/arch/powerpc/perf/e500-pmu.c | |||
diff --git a/arch/powerpc/kernel/mpc7450-pmu.c b/arch/powerpc/perf/mpc7450-pmu.c index fe21b515ca44..fe21b515ca44 100644 --- a/arch/powerpc/kernel/mpc7450-pmu.c +++ b/arch/powerpc/perf/mpc7450-pmu.c | |||
diff --git a/arch/powerpc/kernel/power4-pmu.c b/arch/powerpc/perf/power4-pmu.c index b4f1dda4d089..b4f1dda4d089 100644 --- a/arch/powerpc/kernel/power4-pmu.c +++ b/arch/powerpc/perf/power4-pmu.c | |||
diff --git a/arch/powerpc/kernel/power5+-pmu.c b/arch/powerpc/perf/power5+-pmu.c index a8757baa28f3..a8757baa28f3 100644 --- a/arch/powerpc/kernel/power5+-pmu.c +++ b/arch/powerpc/perf/power5+-pmu.c | |||
diff --git a/arch/powerpc/kernel/power5-pmu.c b/arch/powerpc/perf/power5-pmu.c index e7f06eb7a861..e7f06eb7a861 100644 --- a/arch/powerpc/kernel/power5-pmu.c +++ b/arch/powerpc/perf/power5-pmu.c | |||
diff --git a/arch/powerpc/kernel/power6-pmu.c b/arch/powerpc/perf/power6-pmu.c index 0bbc901e7efc..31128e086fed 100644 --- a/arch/powerpc/kernel/power6-pmu.c +++ b/arch/powerpc/perf/power6-pmu.c | |||
@@ -131,7 +131,7 @@ static u32 marked_bus_events[16] = { | |||
131 | 0x00000022, /* BFP set 2: byte 0 bits 1, 5 */ | 131 | 0x00000022, /* BFP set 2: byte 0 bits 1, 5 */ |
132 | 0, 0 | 132 | 0, 0 |
133 | }; | 133 | }; |
134 | 134 | ||
135 | /* | 135 | /* |
136 | * Returns 1 if event counts things relating to marked instructions | 136 | * Returns 1 if event counts things relating to marked instructions |
137 | * and thus needs the MMCRA_SAMPLE_ENABLE bit set, or 0 if not. | 137 | * and thus needs the MMCRA_SAMPLE_ENABLE bit set, or 0 if not. |
diff --git a/arch/powerpc/kernel/power7-pmu.c b/arch/powerpc/perf/power7-pmu.c index 1251e4d7e262..1251e4d7e262 100644 --- a/arch/powerpc/kernel/power7-pmu.c +++ b/arch/powerpc/perf/power7-pmu.c | |||
diff --git a/arch/powerpc/kernel/ppc970-pmu.c b/arch/powerpc/perf/ppc970-pmu.c index 8c2190206964..111eb25bb0b6 100644 --- a/arch/powerpc/kernel/ppc970-pmu.c +++ b/arch/powerpc/perf/ppc970-pmu.c | |||
@@ -252,7 +252,7 @@ static int p970_get_alternatives(u64 event, unsigned int flags, u64 alt[]) | |||
252 | alt[1] = event ^ 0x1000; | 252 | alt[1] = event ^ 0x1000; |
253 | return 2; | 253 | return 2; |
254 | } | 254 | } |
255 | 255 | ||
256 | return 1; | 256 | return 1; |
257 | } | 257 | } |
258 | 258 | ||
diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig index fcf6bf2ceee9..2e4e64abfab4 100644 --- a/arch/powerpc/platforms/44x/Kconfig +++ b/arch/powerpc/platforms/44x/Kconfig | |||
@@ -23,6 +23,7 @@ config BLUESTONE | |||
23 | default n | 23 | default n |
24 | select PPC44x_SIMPLE | 24 | select PPC44x_SIMPLE |
25 | select APM821xx | 25 | select APM821xx |
26 | select PPC4xx_PCI_EXPRESS | ||
26 | select IBM_EMAC_RGMII | 27 | select IBM_EMAC_RGMII |
27 | help | 28 | help |
28 | This option enables support for the APM APM821xx Evaluation board. | 29 | This option enables support for the APM APM821xx Evaluation board. |
diff --git a/arch/powerpc/platforms/44x/currituck.c b/arch/powerpc/platforms/44x/currituck.c index 3f6229b5dee0..583e67fee37e 100644 --- a/arch/powerpc/platforms/44x/currituck.c +++ b/arch/powerpc/platforms/44x/currituck.c | |||
@@ -83,7 +83,7 @@ static void __init ppc47x_init_irq(void) | |||
83 | * device-tree, just pass 0 to all arguments | 83 | * device-tree, just pass 0 to all arguments |
84 | */ | 84 | */ |
85 | struct mpic *mpic = | 85 | struct mpic *mpic = |
86 | mpic_alloc(np, 0, 0, 0, 0, " MPIC "); | 86 | mpic_alloc(np, 0, MPIC_NO_RESET, 0, 0, " MPIC "); |
87 | BUG_ON(mpic == NULL); | 87 | BUG_ON(mpic == NULL); |
88 | mpic_init(mpic); | 88 | mpic_init(mpic); |
89 | ppc_md.get_irq = mpic_get_irq; | 89 | ppc_md.get_irq = mpic_get_irq; |
diff --git a/arch/powerpc/platforms/44x/iss4xx.c b/arch/powerpc/platforms/44x/iss4xx.c index 5b8cdbb82f80..a28a8629727e 100644 --- a/arch/powerpc/platforms/44x/iss4xx.c +++ b/arch/powerpc/platforms/44x/iss4xx.c | |||
@@ -71,8 +71,7 @@ static void __init iss4xx_init_irq(void) | |||
71 | /* The MPIC driver will get everything it needs from the | 71 | /* The MPIC driver will get everything it needs from the |
72 | * device-tree, just pass 0 to all arguments | 72 | * device-tree, just pass 0 to all arguments |
73 | */ | 73 | */ |
74 | struct mpic *mpic = mpic_alloc(np, 0, 0, 0, 0, | 74 | struct mpic *mpic = mpic_alloc(np, 0, MPIC_NO_RESET, 0, 0, " MPIC "); |
75 | " MPIC "); | ||
76 | BUG_ON(mpic == NULL); | 75 | BUG_ON(mpic == NULL); |
77 | mpic_init(mpic); | 76 | mpic_init(mpic); |
78 | ppc_md.get_irq = mpic_get_irq; | 77 | ppc_md.get_irq = mpic_get_irq; |
diff --git a/arch/powerpc/platforms/44x/ppc44x_simple.c b/arch/powerpc/platforms/44x/ppc44x_simple.c index 8d2202763415..3ffb915446e3 100644 --- a/arch/powerpc/platforms/44x/ppc44x_simple.c +++ b/arch/powerpc/platforms/44x/ppc44x_simple.c | |||
@@ -52,7 +52,7 @@ machine_device_initcall(ppc44x_simple, ppc44x_device_probe); | |||
52 | static char *board[] __initdata = { | 52 | static char *board[] __initdata = { |
53 | "amcc,arches", | 53 | "amcc,arches", |
54 | "amcc,bamboo", | 54 | "amcc,bamboo", |
55 | "amcc,bluestone", | 55 | "apm,bluestone", |
56 | "amcc,glacier", | 56 | "amcc,glacier", |
57 | "ibm,ebony", | 57 | "ibm,ebony", |
58 | "amcc,eiger", | 58 | "amcc,eiger", |
diff --git a/arch/powerpc/platforms/52xx/mpc5200_simple.c b/arch/powerpc/platforms/52xx/mpc5200_simple.c index 846b789fb195..c0aa04068d69 100644 --- a/arch/powerpc/platforms/52xx/mpc5200_simple.c +++ b/arch/powerpc/platforms/52xx/mpc5200_simple.c | |||
@@ -50,6 +50,7 @@ static void __init mpc5200_simple_setup_arch(void) | |||
50 | 50 | ||
51 | /* list of the supported boards */ | 51 | /* list of the supported boards */ |
52 | static const char *board[] __initdata = { | 52 | static const char *board[] __initdata = { |
53 | "anonymous,a4m072", | ||
53 | "anon,charon", | 54 | "anon,charon", |
54 | "intercontrol,digsy-mtc", | 55 | "intercontrol,digsy-mtc", |
55 | "manroland,mucmc52", | 56 | "manroland,mucmc52", |
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_common.c b/arch/powerpc/platforms/52xx/mpc52xx_common.c index 369fd5457a3f..d7e94f49532a 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_common.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_common.c | |||
@@ -98,13 +98,11 @@ struct mpc52xx_gpio_wkup __iomem *wkup_gpio; | |||
98 | * of the localplus bus to the of_platform | 98 | * of the localplus bus to the of_platform |
99 | * bus. | 99 | * bus. |
100 | */ | 100 | */ |
101 | void __init | 101 | void __init mpc52xx_declare_of_platform_devices(void) |
102 | mpc52xx_declare_of_platform_devices(void) | ||
103 | { | 102 | { |
104 | /* Find every child of the SOC node and add it to of_platform */ | 103 | /* Find all the 'platform' devices and register them. */ |
105 | if (of_platform_bus_probe(NULL, mpc52xx_bus_ids, NULL)) | 104 | if (of_platform_populate(NULL, mpc52xx_bus_ids, NULL, NULL)) |
106 | printk(KERN_ERR __FILE__ ": " | 105 | pr_err(__FILE__ ": Error while populating devices from DT\n"); |
107 | "Error while probing of_platform bus\n"); | ||
108 | } | 106 | } |
109 | 107 | ||
110 | /* | 108 | /* |
diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig index d7946be298b6..f000d81c4e31 100644 --- a/arch/powerpc/platforms/85xx/Kconfig +++ b/arch/powerpc/platforms/85xx/Kconfig | |||
@@ -6,6 +6,7 @@ menuconfig FSL_SOC_BOOKE | |||
6 | select MPIC | 6 | select MPIC |
7 | select PPC_PCI_CHOICE | 7 | select PPC_PCI_CHOICE |
8 | select FSL_PCI if PCI | 8 | select FSL_PCI if PCI |
9 | select SERIAL_8250_EXTENDED if SERIAL_8250 | ||
9 | select SERIAL_8250_SHARE_IRQ if SERIAL_8250 | 10 | select SERIAL_8250_SHARE_IRQ if SERIAL_8250 |
10 | default y | 11 | default y |
11 | 12 | ||
@@ -13,6 +14,15 @@ if FSL_SOC_BOOKE | |||
13 | 14 | ||
14 | if PPC32 | 15 | if PPC32 |
15 | 16 | ||
17 | config FSL_85XX_CACHE_SRAM | ||
18 | bool | ||
19 | select PPC_LIB_RHEAP | ||
20 | help | ||
21 | When selected, this option enables cache-sram support | ||
22 | for memory allocation on P1/P2 QorIQ platforms. | ||
23 | cache-sram-size and cache-sram-offset kernel boot | ||
24 | parameters should be passed when this option is enabled. | ||
25 | |||
16 | config MPC8540_ADS | 26 | config MPC8540_ADS |
17 | bool "Freescale MPC8540 ADS" | 27 | bool "Freescale MPC8540 ADS" |
18 | select DEFAULT_UIMAGE | 28 | select DEFAULT_UIMAGE |
@@ -30,6 +40,7 @@ config MPC85xx_CDS | |||
30 | bool "Freescale MPC85xx CDS" | 40 | bool "Freescale MPC85xx CDS" |
31 | select DEFAULT_UIMAGE | 41 | select DEFAULT_UIMAGE |
32 | select PPC_I8259 | 42 | select PPC_I8259 |
43 | select HAS_RAPIDIO | ||
33 | help | 44 | help |
34 | This option enables support for the MPC85xx CDS board | 45 | This option enables support for the MPC85xx CDS board |
35 | 46 | ||
@@ -80,7 +91,6 @@ config P1010_RDB | |||
80 | config P1022_DS | 91 | config P1022_DS |
81 | bool "Freescale P1022 DS" | 92 | bool "Freescale P1022 DS" |
82 | select DEFAULT_UIMAGE | 93 | select DEFAULT_UIMAGE |
83 | select PHYS_64BIT # The DTS has 36-bit addresses | ||
84 | select SWIOTLB | 94 | select SWIOTLB |
85 | help | 95 | help |
86 | This option enables support for the Freescale P1022DS reference board. | 96 | This option enables support for the Freescale P1022DS reference board. |
@@ -171,6 +181,21 @@ config SBC8560 | |||
171 | help | 181 | help |
172 | This option enables support for the Wind River SBC8560 board | 182 | This option enables support for the Wind River SBC8560 board |
173 | 183 | ||
184 | config GE_IMP3A | ||
185 | bool "GE Intelligent Platforms IMP3A" | ||
186 | select DEFAULT_UIMAGE | ||
187 | select SWIOTLB | ||
188 | select MMIO_NVRAM | ||
189 | select GENERIC_GPIO | ||
190 | select ARCH_REQUIRE_GPIOLIB | ||
191 | select GE_FPGA | ||
192 | help | ||
193 | This option enables support for the GE Intelligent Platforms IMP3A | ||
194 | board. | ||
195 | |||
196 | This board is a 3U CompactPCI Single Board Computer with a Freescale | ||
197 | P2020 processor. | ||
198 | |||
174 | config P2041_RDB | 199 | config P2041_RDB |
175 | bool "Freescale P2041 RDB" | 200 | bool "Freescale P2041 RDB" |
176 | select DEFAULT_UIMAGE | 201 | select DEFAULT_UIMAGE |
diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile index 9cb2d4320dcc..2125d4ca068a 100644 --- a/arch/powerpc/platforms/85xx/Makefile +++ b/arch/powerpc/platforms/85xx/Makefile | |||
@@ -27,3 +27,4 @@ obj-$(CONFIG_SBC8548) += sbc8548.o | |||
27 | obj-$(CONFIG_SOCRATES) += socrates.o socrates_fpga_pic.o | 27 | obj-$(CONFIG_SOCRATES) += socrates.o socrates_fpga_pic.o |
28 | obj-$(CONFIG_KSI8560) += ksi8560.o | 28 | obj-$(CONFIG_KSI8560) += ksi8560.o |
29 | obj-$(CONFIG_XES_MPC85xx) += xes_mpc85xx.o | 29 | obj-$(CONFIG_XES_MPC85xx) += xes_mpc85xx.o |
30 | obj-$(CONFIG_GE_IMP3A) += ge_imp3a.o | ||
diff --git a/arch/powerpc/platforms/85xx/corenet_ds.c b/arch/powerpc/platforms/85xx/corenet_ds.c index 07e3e6c47371..df69e99e511c 100644 --- a/arch/powerpc/platforms/85xx/corenet_ds.c +++ b/arch/powerpc/platforms/85xx/corenet_ds.c | |||
@@ -36,8 +36,8 @@ | |||
36 | void __init corenet_ds_pic_init(void) | 36 | void __init corenet_ds_pic_init(void) |
37 | { | 37 | { |
38 | struct mpic *mpic; | 38 | struct mpic *mpic; |
39 | unsigned int flags = MPIC_BIG_ENDIAN | | 39 | unsigned int flags = MPIC_BIG_ENDIAN | MPIC_SINGLE_DEST_CPU | |
40 | MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU; | 40 | MPIC_NO_RESET; |
41 | 41 | ||
42 | if (ppc_md.get_irq == mpic_get_coreint_irq) | 42 | if (ppc_md.get_irq == mpic_get_coreint_irq) |
43 | flags |= MPIC_ENABLE_COREINT; | 43 | flags |= MPIC_ENABLE_COREINT; |
diff --git a/arch/powerpc/platforms/85xx/ge_imp3a.c b/arch/powerpc/platforms/85xx/ge_imp3a.c new file mode 100644 index 000000000000..d50056f424f6 --- /dev/null +++ b/arch/powerpc/platforms/85xx/ge_imp3a.c | |||
@@ -0,0 +1,246 @@ | |||
1 | /* | ||
2 | * GE IMP3A Board Setup | ||
3 | * | ||
4 | * Author Martyn Welch <martyn.welch@ge.com> | ||
5 | * | ||
6 | * Copyright 2010 GE Intelligent Platforms Embedded Systems, 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 | * Based on: mpc85xx_ds.c (MPC85xx DS Board Setup) | ||
14 | * Copyright 2007 Freescale Semiconductor Inc. | ||
15 | */ | ||
16 | |||
17 | #include <linux/stddef.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/pci.h> | ||
20 | #include <linux/kdev_t.h> | ||
21 | #include <linux/delay.h> | ||
22 | #include <linux/seq_file.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/of_platform.h> | ||
25 | #include <linux/memblock.h> | ||
26 | |||
27 | #include <asm/system.h> | ||
28 | #include <asm/time.h> | ||
29 | #include <asm/machdep.h> | ||
30 | #include <asm/pci-bridge.h> | ||
31 | #include <mm/mmu_decl.h> | ||
32 | #include <asm/prom.h> | ||
33 | #include <asm/udbg.h> | ||
34 | #include <asm/mpic.h> | ||
35 | #include <asm/swiotlb.h> | ||
36 | #include <asm/nvram.h> | ||
37 | |||
38 | #include <sysdev/fsl_soc.h> | ||
39 | #include <sysdev/fsl_pci.h> | ||
40 | #include "smp.h" | ||
41 | |||
42 | #include "mpc85xx.h" | ||
43 | #include <sysdev/ge/ge_pic.h> | ||
44 | |||
45 | void __iomem *imp3a_regs; | ||
46 | |||
47 | void __init ge_imp3a_pic_init(void) | ||
48 | { | ||
49 | struct mpic *mpic; | ||
50 | struct device_node *np; | ||
51 | struct device_node *cascade_node = NULL; | ||
52 | unsigned long root = of_get_flat_dt_root(); | ||
53 | |||
54 | if (of_flat_dt_is_compatible(root, "fsl,MPC8572DS-CAMP")) { | ||
55 | mpic = mpic_alloc(NULL, 0, | ||
56 | MPIC_NO_RESET | | ||
57 | MPIC_BIG_ENDIAN | | ||
58 | MPIC_SINGLE_DEST_CPU, | ||
59 | 0, 256, " OpenPIC "); | ||
60 | } else { | ||
61 | mpic = mpic_alloc(NULL, 0, | ||
62 | MPIC_BIG_ENDIAN | | ||
63 | MPIC_SINGLE_DEST_CPU, | ||
64 | 0, 256, " OpenPIC "); | ||
65 | } | ||
66 | |||
67 | BUG_ON(mpic == NULL); | ||
68 | mpic_init(mpic); | ||
69 | /* | ||
70 | * There is a simple interrupt handler in the main FPGA, this needs | ||
71 | * to be cascaded into the MPIC | ||
72 | */ | ||
73 | for_each_node_by_type(np, "interrupt-controller") | ||
74 | if (of_device_is_compatible(np, "gef,fpga-pic-1.00")) { | ||
75 | cascade_node = np; | ||
76 | break; | ||
77 | } | ||
78 | |||
79 | if (cascade_node == NULL) { | ||
80 | printk(KERN_WARNING "IMP3A: No FPGA PIC\n"); | ||
81 | return; | ||
82 | } | ||
83 | |||
84 | gef_pic_init(cascade_node); | ||
85 | of_node_put(cascade_node); | ||
86 | } | ||
87 | |||
88 | #ifdef CONFIG_PCI | ||
89 | static int primary_phb_addr; | ||
90 | #endif /* CONFIG_PCI */ | ||
91 | |||
92 | /* | ||
93 | * Setup the architecture | ||
94 | */ | ||
95 | static void __init ge_imp3a_setup_arch(void) | ||
96 | { | ||
97 | struct device_node *regs; | ||
98 | #ifdef CONFIG_PCI | ||
99 | struct device_node *np; | ||
100 | struct pci_controller *hose; | ||
101 | #endif | ||
102 | dma_addr_t max = 0xffffffff; | ||
103 | |||
104 | if (ppc_md.progress) | ||
105 | ppc_md.progress("ge_imp3a_setup_arch()", 0); | ||
106 | |||
107 | #ifdef CONFIG_PCI | ||
108 | for_each_node_by_type(np, "pci") { | ||
109 | if (of_device_is_compatible(np, "fsl,mpc8540-pci") || | ||
110 | of_device_is_compatible(np, "fsl,mpc8548-pcie") || | ||
111 | of_device_is_compatible(np, "fsl,p2020-pcie")) { | ||
112 | struct resource rsrc; | ||
113 | of_address_to_resource(np, 0, &rsrc); | ||
114 | if ((rsrc.start & 0xfffff) == primary_phb_addr) | ||
115 | fsl_add_bridge(np, 1); | ||
116 | else | ||
117 | fsl_add_bridge(np, 0); | ||
118 | |||
119 | hose = pci_find_hose_for_OF_device(np); | ||
120 | max = min(max, hose->dma_window_base_cur + | ||
121 | hose->dma_window_size); | ||
122 | } | ||
123 | } | ||
124 | #endif | ||
125 | |||
126 | mpc85xx_smp_init(); | ||
127 | |||
128 | #ifdef CONFIG_SWIOTLB | ||
129 | if (memblock_end_of_DRAM() > max) { | ||
130 | ppc_swiotlb_enable = 1; | ||
131 | set_pci_dma_ops(&swiotlb_dma_ops); | ||
132 | ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_swiotlb; | ||
133 | } | ||
134 | #endif | ||
135 | |||
136 | /* Remap basic board registers */ | ||
137 | regs = of_find_compatible_node(NULL, NULL, "ge,imp3a-fpga-regs"); | ||
138 | if (regs) { | ||
139 | imp3a_regs = of_iomap(regs, 0); | ||
140 | if (imp3a_regs == NULL) | ||
141 | printk(KERN_WARNING "Unable to map board registers\n"); | ||
142 | of_node_put(regs); | ||
143 | } | ||
144 | |||
145 | #if defined(CONFIG_MMIO_NVRAM) | ||
146 | mmio_nvram_init(); | ||
147 | #endif | ||
148 | |||
149 | printk(KERN_INFO "GE Intelligent Platforms IMP3A 3U cPCI SBC\n"); | ||
150 | } | ||
151 | |||
152 | /* Return the PCB revision */ | ||
153 | static unsigned int ge_imp3a_get_pcb_rev(void) | ||
154 | { | ||
155 | unsigned int reg; | ||
156 | |||
157 | reg = ioread16(imp3a_regs); | ||
158 | return (reg >> 8) & 0xff; | ||
159 | } | ||
160 | |||
161 | /* Return the board (software) revision */ | ||
162 | static unsigned int ge_imp3a_get_board_rev(void) | ||
163 | { | ||
164 | unsigned int reg; | ||
165 | |||
166 | reg = ioread16(imp3a_regs + 0x2); | ||
167 | return reg & 0xff; | ||
168 | } | ||
169 | |||
170 | /* Return the FPGA revision */ | ||
171 | static unsigned int ge_imp3a_get_fpga_rev(void) | ||
172 | { | ||
173 | unsigned int reg; | ||
174 | |||
175 | reg = ioread16(imp3a_regs + 0x2); | ||
176 | return (reg >> 8) & 0xff; | ||
177 | } | ||
178 | |||
179 | /* Return compactPCI Geographical Address */ | ||
180 | static unsigned int ge_imp3a_get_cpci_geo_addr(void) | ||
181 | { | ||
182 | unsigned int reg; | ||
183 | |||
184 | reg = ioread16(imp3a_regs + 0x6); | ||
185 | return (reg & 0x0f00) >> 8; | ||
186 | } | ||
187 | |||
188 | /* Return compactPCI System Controller Status */ | ||
189 | static unsigned int ge_imp3a_get_cpci_is_syscon(void) | ||
190 | { | ||
191 | unsigned int reg; | ||
192 | |||
193 | reg = ioread16(imp3a_regs + 0x6); | ||
194 | return reg & (1 << 12); | ||
195 | } | ||
196 | |||
197 | static void ge_imp3a_show_cpuinfo(struct seq_file *m) | ||
198 | { | ||
199 | seq_printf(m, "Vendor\t\t: GE Intelligent Platforms\n"); | ||
200 | |||
201 | seq_printf(m, "Revision\t: %u%c\n", ge_imp3a_get_pcb_rev(), | ||
202 | ('A' + ge_imp3a_get_board_rev() - 1)); | ||
203 | |||
204 | seq_printf(m, "FPGA Revision\t: %u\n", ge_imp3a_get_fpga_rev()); | ||
205 | |||
206 | seq_printf(m, "cPCI geo. addr\t: %u\n", ge_imp3a_get_cpci_geo_addr()); | ||
207 | |||
208 | seq_printf(m, "cPCI syscon\t: %s\n", | ||
209 | ge_imp3a_get_cpci_is_syscon() ? "yes" : "no"); | ||
210 | } | ||
211 | |||
212 | /* | ||
213 | * Called very early, device-tree isn't unflattened | ||
214 | */ | ||
215 | static int __init ge_imp3a_probe(void) | ||
216 | { | ||
217 | unsigned long root = of_get_flat_dt_root(); | ||
218 | |||
219 | if (of_flat_dt_is_compatible(root, "ge,IMP3A")) { | ||
220 | #ifdef CONFIG_PCI | ||
221 | primary_phb_addr = 0x9000; | ||
222 | #endif | ||
223 | return 1; | ||
224 | } | ||
225 | |||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | machine_device_initcall(ge_imp3a, mpc85xx_common_publish_devices); | ||
230 | |||
231 | machine_arch_initcall(ge_imp3a, swiotlb_setup_bus_notifier); | ||
232 | |||
233 | define_machine(ge_imp3a) { | ||
234 | .name = "GE_IMP3A", | ||
235 | .probe = ge_imp3a_probe, | ||
236 | .setup_arch = ge_imp3a_setup_arch, | ||
237 | .init_IRQ = ge_imp3a_pic_init, | ||
238 | .show_cpuinfo = ge_imp3a_show_cpuinfo, | ||
239 | #ifdef CONFIG_PCI | ||
240 | .pcibios_fixup_bus = fsl_pcibios_fixup_bus, | ||
241 | #endif | ||
242 | .get_irq = mpic_get_irq, | ||
243 | .restart = fsl_rstcr_restart, | ||
244 | .calibrate_decr = generic_calibrate_decr, | ||
245 | .progress = udbg_progress, | ||
246 | }; | ||
diff --git a/arch/powerpc/platforms/85xx/ksi8560.c b/arch/powerpc/platforms/85xx/ksi8560.c index 20f75d7819c6..60120e55da41 100644 --- a/arch/powerpc/platforms/85xx/ksi8560.c +++ b/arch/powerpc/platforms/85xx/ksi8560.c | |||
@@ -57,8 +57,7 @@ static void machine_restart(char *cmd) | |||
57 | 57 | ||
58 | static void __init ksi8560_pic_init(void) | 58 | static void __init ksi8560_pic_init(void) |
59 | { | 59 | { |
60 | struct mpic *mpic = mpic_alloc(NULL, 0, | 60 | struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN, |
61 | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, | ||
62 | 0, 256, " OpenPIC "); | 61 | 0, 256, " OpenPIC "); |
63 | BUG_ON(mpic == NULL); | 62 | BUG_ON(mpic == NULL); |
64 | mpic_init(mpic); | 63 | mpic_init(mpic); |
diff --git a/arch/powerpc/platforms/85xx/mpc8536_ds.c b/arch/powerpc/platforms/85xx/mpc8536_ds.c index cf266826682e..f58872688d8f 100644 --- a/arch/powerpc/platforms/85xx/mpc8536_ds.c +++ b/arch/powerpc/platforms/85xx/mpc8536_ds.c | |||
@@ -36,9 +36,7 @@ | |||
36 | 36 | ||
37 | void __init mpc8536_ds_pic_init(void) | 37 | void __init mpc8536_ds_pic_init(void) |
38 | { | 38 | { |
39 | struct mpic *mpic = mpic_alloc(NULL, 0, | 39 | struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN, |
40 | MPIC_WANTS_RESET | | ||
41 | MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS, | ||
42 | 0, 256, " OpenPIC "); | 40 | 0, 256, " OpenPIC "); |
43 | BUG_ON(mpic == NULL); | 41 | BUG_ON(mpic == NULL); |
44 | mpic_init(mpic); | 42 | mpic_init(mpic); |
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c index 3bebb5173bfc..d19f675cb369 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c | |||
@@ -50,8 +50,7 @@ static int mpc85xx_exclude_device(struct pci_controller *hose, | |||
50 | 50 | ||
51 | static void __init mpc85xx_ads_pic_init(void) | 51 | static void __init mpc85xx_ads_pic_init(void) |
52 | { | 52 | { |
53 | struct mpic *mpic = mpic_alloc(NULL, 0, | 53 | struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN, |
54 | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, | ||
55 | 0, 256, " OpenPIC "); | 54 | 0, 256, " OpenPIC "); |
56 | BUG_ON(mpic == NULL); | 55 | BUG_ON(mpic == NULL); |
57 | mpic_init(mpic); | 56 | mpic_init(mpic); |
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c index 40f03da616a9..ab5f0bf19454 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Maintained by Kumar Gala (see MAINTAINERS for contact information) | 4 | * Maintained by Kumar Gala (see MAINTAINERS for contact information) |
5 | * | 5 | * |
6 | * Copyright 2005 Freescale Semiconductor Inc. | 6 | * Copyright 2005, 2011-2012 Freescale Semiconductor Inc. |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify it | 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 | 9 | * under the terms of the GNU General Public License as published by the |
@@ -48,17 +48,24 @@ | |||
48 | 48 | ||
49 | #include "mpc85xx.h" | 49 | #include "mpc85xx.h" |
50 | 50 | ||
51 | /* CADMUS info */ | 51 | /* |
52 | /* xxx - galak, move into device tree */ | 52 | * The CDS board contains an FPGA/CPLD called "Cadmus", which collects |
53 | #define CADMUS_BASE (0xf8004000) | 53 | * various logic and performs system control functions. |
54 | #define CADMUS_SIZE (256) | 54 | * Here is the FPGA/CPLD register map. |
55 | #define CM_VER (0) | 55 | */ |
56 | #define CM_CSR (1) | 56 | struct cadmus_reg { |
57 | #define CM_RST (2) | 57 | u8 cm_ver; /* Board version */ |
58 | 58 | u8 cm_csr; /* General control/status */ | |
59 | u8 cm_rst; /* Reset control */ | ||
60 | u8 cm_hsclk; /* High speed clock */ | ||
61 | u8 cm_hsxclk; /* High speed clock extended */ | ||
62 | u8 cm_led; /* LED data */ | ||
63 | u8 cm_pci; /* PCI control/status */ | ||
64 | u8 cm_dma; /* DMA control */ | ||
65 | u8 res[248]; /* Total 256 bytes */ | ||
66 | }; | ||
59 | 67 | ||
60 | static int cds_pci_slot = 2; | 68 | static struct cadmus_reg *cadmus; |
61 | static volatile u8 *cadmus; | ||
62 | 69 | ||
63 | #ifdef CONFIG_PCI | 70 | #ifdef CONFIG_PCI |
64 | 71 | ||
@@ -158,6 +165,33 @@ DECLARE_PCI_FIXUP_EARLY(0x1957, 0x3fff, skip_fake_bridge); | |||
158 | DECLARE_PCI_FIXUP_EARLY(0x3fff, 0x1957, skip_fake_bridge); | 165 | DECLARE_PCI_FIXUP_EARLY(0x3fff, 0x1957, skip_fake_bridge); |
159 | DECLARE_PCI_FIXUP_EARLY(0xff3f, 0x5719, skip_fake_bridge); | 166 | DECLARE_PCI_FIXUP_EARLY(0xff3f, 0x5719, skip_fake_bridge); |
160 | 167 | ||
168 | #define PCI_DEVICE_ID_IDT_TSI310 0x01a7 | ||
169 | |||
170 | /* | ||
171 | * Fix Tsi310 PCI-X bridge resource. | ||
172 | * Force the bridge to open a window from 0x0000-0x1fff in PCI I/O space. | ||
173 | * This allows legacy I/O(i8259, etc) on the VIA southbridge to be accessed. | ||
174 | */ | ||
175 | void mpc85xx_cds_fixup_bus(struct pci_bus *bus) | ||
176 | { | ||
177 | struct pci_dev *dev = bus->self; | ||
178 | struct resource *res = bus->resource[0]; | ||
179 | |||
180 | if (dev != NULL && | ||
181 | dev->vendor == PCI_VENDOR_ID_IBM && | ||
182 | dev->device == PCI_DEVICE_ID_IDT_TSI310) { | ||
183 | if (res) { | ||
184 | res->start = 0; | ||
185 | res->end = 0x1fff; | ||
186 | res->flags = IORESOURCE_IO; | ||
187 | pr_info("mpc85xx_cds: PCI bridge resource fixup applied\n"); | ||
188 | pr_info("mpc85xx_cds: %pR\n", res); | ||
189 | } | ||
190 | } | ||
191 | |||
192 | fsl_pcibios_fixup_bus(bus); | ||
193 | } | ||
194 | |||
161 | #ifdef CONFIG_PPC_I8259 | 195 | #ifdef CONFIG_PPC_I8259 |
162 | static void mpc85xx_8259_cascade_handler(unsigned int irq, | 196 | static void mpc85xx_8259_cascade_handler(unsigned int irq, |
163 | struct irq_desc *desc) | 197 | struct irq_desc *desc) |
@@ -188,8 +222,7 @@ static struct irqaction mpc85xxcds_8259_irqaction = { | |||
188 | static void __init mpc85xx_cds_pic_init(void) | 222 | static void __init mpc85xx_cds_pic_init(void) |
189 | { | 223 | { |
190 | struct mpic *mpic; | 224 | struct mpic *mpic; |
191 | mpic = mpic_alloc(NULL, 0, | 225 | mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN, |
192 | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, | ||
193 | 0, 256, " OpenPIC "); | 226 | 0, 256, " OpenPIC "); |
194 | BUG_ON(mpic == NULL); | 227 | BUG_ON(mpic == NULL); |
195 | mpic_init(mpic); | 228 | mpic_init(mpic); |
@@ -249,20 +282,30 @@ machine_device_initcall(mpc85xx_cds, mpc85xx_cds_8259_attach); | |||
249 | */ | 282 | */ |
250 | static void __init mpc85xx_cds_setup_arch(void) | 283 | static void __init mpc85xx_cds_setup_arch(void) |
251 | { | 284 | { |
252 | #ifdef CONFIG_PCI | ||
253 | struct device_node *np; | 285 | struct device_node *np; |
254 | #endif | 286 | int cds_pci_slot; |
255 | 287 | ||
256 | if (ppc_md.progress) | 288 | if (ppc_md.progress) |
257 | ppc_md.progress("mpc85xx_cds_setup_arch()", 0); | 289 | ppc_md.progress("mpc85xx_cds_setup_arch()", 0); |
258 | 290 | ||
259 | cadmus = ioremap(CADMUS_BASE, CADMUS_SIZE); | 291 | np = of_find_compatible_node(NULL, NULL, "fsl,mpc8548cds-fpga"); |
260 | cds_pci_slot = ((cadmus[CM_CSR] >> 6) & 0x3) + 1; | 292 | if (!np) { |
293 | pr_err("Could not find FPGA node.\n"); | ||
294 | return; | ||
295 | } | ||
296 | |||
297 | cadmus = of_iomap(np, 0); | ||
298 | of_node_put(np); | ||
299 | if (!cadmus) { | ||
300 | pr_err("Fail to map FPGA area.\n"); | ||
301 | return; | ||
302 | } | ||
261 | 303 | ||
262 | if (ppc_md.progress) { | 304 | if (ppc_md.progress) { |
263 | char buf[40]; | 305 | char buf[40]; |
306 | cds_pci_slot = ((in_8(&cadmus->cm_csr) >> 6) & 0x3) + 1; | ||
264 | snprintf(buf, 40, "CDS Version = 0x%x in slot %d\n", | 307 | snprintf(buf, 40, "CDS Version = 0x%x in slot %d\n", |
265 | cadmus[CM_VER], cds_pci_slot); | 308 | in_8(&cadmus->cm_ver), cds_pci_slot); |
266 | ppc_md.progress(buf, 0); | 309 | ppc_md.progress(buf, 0); |
267 | } | 310 | } |
268 | 311 | ||
@@ -292,7 +335,8 @@ static void mpc85xx_cds_show_cpuinfo(struct seq_file *m) | |||
292 | svid = mfspr(SPRN_SVR); | 335 | svid = mfspr(SPRN_SVR); |
293 | 336 | ||
294 | seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n"); | 337 | seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n"); |
295 | seq_printf(m, "Machine\t\t: MPC85xx CDS (0x%x)\n", cadmus[CM_VER]); | 338 | seq_printf(m, "Machine\t\t: MPC85xx CDS (0x%x)\n", |
339 | in_8(&cadmus->cm_ver)); | ||
296 | seq_printf(m, "PVR\t\t: 0x%x\n", pvid); | 340 | seq_printf(m, "PVR\t\t: 0x%x\n", pvid); |
297 | seq_printf(m, "SVR\t\t: 0x%x\n", svid); | 341 | seq_printf(m, "SVR\t\t: 0x%x\n", svid); |
298 | 342 | ||
@@ -323,7 +367,7 @@ define_machine(mpc85xx_cds) { | |||
323 | .get_irq = mpic_get_irq, | 367 | .get_irq = mpic_get_irq, |
324 | #ifdef CONFIG_PCI | 368 | #ifdef CONFIG_PCI |
325 | .restart = mpc85xx_cds_restart, | 369 | .restart = mpc85xx_cds_restart, |
326 | .pcibios_fixup_bus = fsl_pcibios_fixup_bus, | 370 | .pcibios_fixup_bus = mpc85xx_cds_fixup_bus, |
327 | #else | 371 | #else |
328 | .restart = fsl_rstcr_restart, | 372 | .restart = fsl_rstcr_restart, |
329 | #endif | 373 | #endif |
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ds.c b/arch/powerpc/platforms/85xx/mpc85xx_ds.c index eefbb91e1d61..6e23e3e34bd9 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ds.c | |||
@@ -72,13 +72,13 @@ void __init mpc85xx_ds_pic_init(void) | |||
72 | 72 | ||
73 | if (of_flat_dt_is_compatible(root, "fsl,MPC8572DS-CAMP")) { | 73 | if (of_flat_dt_is_compatible(root, "fsl,MPC8572DS-CAMP")) { |
74 | mpic = mpic_alloc(NULL, 0, | 74 | mpic = mpic_alloc(NULL, 0, |
75 | MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS | | 75 | MPIC_NO_RESET | |
76 | MPIC_BIG_ENDIAN | | ||
76 | MPIC_SINGLE_DEST_CPU, | 77 | MPIC_SINGLE_DEST_CPU, |
77 | 0, 256, " OpenPIC "); | 78 | 0, 256, " OpenPIC "); |
78 | } else { | 79 | } else { |
79 | mpic = mpic_alloc(NULL, 0, | 80 | mpic = mpic_alloc(NULL, 0, |
80 | MPIC_WANTS_RESET | | 81 | MPIC_BIG_ENDIAN | |
81 | MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS | | ||
82 | MPIC_SINGLE_DEST_CPU, | 82 | MPIC_SINGLE_DEST_CPU, |
83 | 0, 256, " OpenPIC "); | 83 | 0, 256, " OpenPIC "); |
84 | } | 84 | } |
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c index 1d15a0cd2c82..f33662b46b8d 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) Freescale Semicondutor, Inc. 2006-2010. All rights reserved. | 2 | * Copyright (C) 2006-2010, 2012 Freescale Semicondutor, Inc. |
3 | * All rights reserved. | ||
3 | * | 4 | * |
4 | * Author: Andy Fleming <afleming@freescale.com> | 5 | * Author: Andy Fleming <afleming@freescale.com> |
5 | * | 6 | * |
@@ -51,6 +52,7 @@ | |||
51 | #include <asm/qe_ic.h> | 52 | #include <asm/qe_ic.h> |
52 | #include <asm/mpic.h> | 53 | #include <asm/mpic.h> |
53 | #include <asm/swiotlb.h> | 54 | #include <asm/swiotlb.h> |
55 | #include <asm/fsl_guts.h> | ||
54 | #include "smp.h" | 56 | #include "smp.h" |
55 | 57 | ||
56 | #include "mpc85xx.h" | 58 | #include "mpc85xx.h" |
@@ -268,34 +270,27 @@ static void __init mpc85xx_mds_qe_init(void) | |||
268 | mpc85xx_mds_reset_ucc_phys(); | 270 | mpc85xx_mds_reset_ucc_phys(); |
269 | 271 | ||
270 | if (machine_is(p1021_mds)) { | 272 | if (machine_is(p1021_mds)) { |
271 | #define MPC85xx_PMUXCR_OFFSET 0x60 | ||
272 | #define MPC85xx_PMUXCR_QE0 0x00008000 | ||
273 | #define MPC85xx_PMUXCR_QE3 0x00001000 | ||
274 | #define MPC85xx_PMUXCR_QE9 0x00000040 | ||
275 | #define MPC85xx_PMUXCR_QE12 0x00000008 | ||
276 | static __be32 __iomem *pmuxcr; | ||
277 | 273 | ||
278 | np = of_find_node_by_name(NULL, "global-utilities"); | 274 | struct ccsr_guts_85xx __iomem *guts; |
279 | 275 | ||
276 | np = of_find_node_by_name(NULL, "global-utilities"); | ||
280 | if (np) { | 277 | if (np) { |
281 | pmuxcr = of_iomap(np, 0) + MPC85xx_PMUXCR_OFFSET; | 278 | guts = of_iomap(np, 0); |
282 | 279 | if (!guts) | |
283 | if (!pmuxcr) | 280 | pr_err("mpc85xx-rdb: could not map global utilities register\n"); |
284 | printk(KERN_EMERG "Error: Alternate function" | 281 | else{ |
285 | " signal multiplex control register not" | ||
286 | " mapped!\n"); | ||
287 | else | ||
288 | /* P1021 has pins muxed for QE and other functions. To | 282 | /* P1021 has pins muxed for QE and other functions. To |
289 | * enable QE UEC mode, we need to set bit QE0 for UCC1 | 283 | * enable QE UEC mode, we need to set bit QE0 for UCC1 |
290 | * in Eth mode, QE0 and QE3 for UCC5 in Eth mode, QE9 | 284 | * in Eth mode, QE0 and QE3 for UCC5 in Eth mode, QE9 |
291 | * and QE12 for QE MII management signals in PMUXCR | 285 | * and QE12 for QE MII management signals in PMUXCR |
292 | * register. | 286 | * register. |
293 | */ | 287 | */ |
294 | setbits32(pmuxcr, MPC85xx_PMUXCR_QE0 | | 288 | setbits32(&guts->pmuxcr, MPC85xx_PMUXCR_QE(0) | |
295 | MPC85xx_PMUXCR_QE3 | | 289 | MPC85xx_PMUXCR_QE(3) | |
296 | MPC85xx_PMUXCR_QE9 | | 290 | MPC85xx_PMUXCR_QE(9) | |
297 | MPC85xx_PMUXCR_QE12); | 291 | MPC85xx_PMUXCR_QE(12)); |
298 | 292 | iounmap(guts); | |
293 | } | ||
299 | of_node_put(np); | 294 | of_node_put(np); |
300 | } | 295 | } |
301 | 296 | ||
@@ -434,9 +429,8 @@ machine_arch_initcall(p1021_mds, swiotlb_setup_bus_notifier); | |||
434 | 429 | ||
435 | static void __init mpc85xx_mds_pic_init(void) | 430 | static void __init mpc85xx_mds_pic_init(void) |
436 | { | 431 | { |
437 | struct mpic *mpic = mpic_alloc(NULL, 0, | 432 | struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | |
438 | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN | | 433 | MPIC_SINGLE_DEST_CPU, |
439 | MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU, | ||
440 | 0, 256, " OpenPIC "); | 434 | 0, 256, " OpenPIC "); |
441 | BUG_ON(mpic == NULL); | 435 | BUG_ON(mpic == NULL); |
442 | 436 | ||
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c index ccf520e890be..db214cd4c822 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * MPC85xx RDB Board Setup | 2 | * MPC85xx RDB Board Setup |
3 | * | 3 | * |
4 | * Copyright 2009 Freescale Semiconductor Inc. | 4 | * Copyright 2009,2012 Freescale Semiconductor Inc. |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify it | 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 | 7 | * under the terms of the GNU General Public License as published by the |
@@ -26,6 +26,9 @@ | |||
26 | #include <asm/prom.h> | 26 | #include <asm/prom.h> |
27 | #include <asm/udbg.h> | 27 | #include <asm/udbg.h> |
28 | #include <asm/mpic.h> | 28 | #include <asm/mpic.h> |
29 | #include <asm/qe.h> | ||
30 | #include <asm/qe_ic.h> | ||
31 | #include <asm/fsl_guts.h> | ||
29 | 32 | ||
30 | #include <sysdev/fsl_soc.h> | 33 | #include <sysdev/fsl_soc.h> |
31 | #include <sysdev/fsl_pci.h> | 34 | #include <sysdev/fsl_pci.h> |
@@ -47,21 +50,36 @@ void __init mpc85xx_rdb_pic_init(void) | |||
47 | struct mpic *mpic; | 50 | struct mpic *mpic; |
48 | unsigned long root = of_get_flat_dt_root(); | 51 | unsigned long root = of_get_flat_dt_root(); |
49 | 52 | ||
53 | #ifdef CONFIG_QUICC_ENGINE | ||
54 | struct device_node *np; | ||
55 | #endif | ||
56 | |||
50 | if (of_flat_dt_is_compatible(root, "fsl,MPC85XXRDB-CAMP")) { | 57 | if (of_flat_dt_is_compatible(root, "fsl,MPC85XXRDB-CAMP")) { |
51 | mpic = mpic_alloc(NULL, 0, | 58 | mpic = mpic_alloc(NULL, 0, MPIC_NO_RESET | |
52 | MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS | | 59 | MPIC_BIG_ENDIAN | |
53 | MPIC_SINGLE_DEST_CPU, | 60 | MPIC_SINGLE_DEST_CPU, |
54 | 0, 256, " OpenPIC "); | 61 | 0, 256, " OpenPIC "); |
55 | } else { | 62 | } else { |
56 | mpic = mpic_alloc(NULL, 0, | 63 | mpic = mpic_alloc(NULL, 0, |
57 | MPIC_WANTS_RESET | | 64 | MPIC_BIG_ENDIAN | |
58 | MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS | | ||
59 | MPIC_SINGLE_DEST_CPU, | 65 | MPIC_SINGLE_DEST_CPU, |
60 | 0, 256, " OpenPIC "); | 66 | 0, 256, " OpenPIC "); |
61 | } | 67 | } |
62 | 68 | ||
63 | BUG_ON(mpic == NULL); | 69 | BUG_ON(mpic == NULL); |
64 | mpic_init(mpic); | 70 | mpic_init(mpic); |
71 | |||
72 | #ifdef CONFIG_QUICC_ENGINE | ||
73 | np = of_find_compatible_node(NULL, NULL, "fsl,qe-ic"); | ||
74 | if (np) { | ||
75 | qe_ic_init(np, 0, qe_ic_cascade_low_mpic, | ||
76 | qe_ic_cascade_high_mpic); | ||
77 | of_node_put(np); | ||
78 | |||
79 | } else | ||
80 | pr_err("%s: Could not find qe-ic node\n", __func__); | ||
81 | #endif | ||
82 | |||
65 | } | 83 | } |
66 | 84 | ||
67 | /* | 85 | /* |
@@ -69,7 +87,7 @@ void __init mpc85xx_rdb_pic_init(void) | |||
69 | */ | 87 | */ |
70 | static void __init mpc85xx_rdb_setup_arch(void) | 88 | static void __init mpc85xx_rdb_setup_arch(void) |
71 | { | 89 | { |
72 | #ifdef CONFIG_PCI | 90 | #if defined(CONFIG_PCI) || defined(CONFIG_QUICC_ENGINE) |
73 | struct device_node *np; | 91 | struct device_node *np; |
74 | #endif | 92 | #endif |
75 | 93 | ||
@@ -85,11 +103,73 @@ static void __init mpc85xx_rdb_setup_arch(void) | |||
85 | #endif | 103 | #endif |
86 | 104 | ||
87 | mpc85xx_smp_init(); | 105 | mpc85xx_smp_init(); |
106 | |||
107 | #ifdef CONFIG_QUICC_ENGINE | ||
108 | np = of_find_compatible_node(NULL, NULL, "fsl,qe"); | ||
109 | if (!np) { | ||
110 | pr_err("%s: Could not find Quicc Engine node\n", __func__); | ||
111 | goto qe_fail; | ||
112 | } | ||
113 | |||
114 | qe_reset(); | ||
115 | of_node_put(np); | ||
116 | |||
117 | np = of_find_node_by_name(NULL, "par_io"); | ||
118 | if (np) { | ||
119 | struct device_node *ucc; | ||
120 | |||
121 | par_io_init(np); | ||
122 | of_node_put(np); | ||
123 | |||
124 | for_each_node_by_name(ucc, "ucc") | ||
125 | par_io_of_config(ucc); | ||
126 | |||
127 | } | ||
128 | #if defined(CONFIG_UCC_GETH) || defined(CONFIG_SERIAL_QE) | ||
129 | if (machine_is(p1025_rdb)) { | ||
130 | |||
131 | struct ccsr_guts_85xx __iomem *guts; | ||
132 | |||
133 | np = of_find_node_by_name(NULL, "global-utilities"); | ||
134 | if (np) { | ||
135 | guts = of_iomap(np, 0); | ||
136 | if (!guts) { | ||
137 | |||
138 | pr_err("mpc85xx-rdb: could not map global utilities register\n"); | ||
139 | |||
140 | } else { | ||
141 | /* P1025 has pins muxed for QE and other functions. To | ||
142 | * enable QE UEC mode, we need to set bit QE0 for UCC1 | ||
143 | * in Eth mode, QE0 and QE3 for UCC5 in Eth mode, QE9 | ||
144 | * and QE12 for QE MII management singals in PMUXCR | ||
145 | * register. | ||
146 | */ | ||
147 | setbits32(&guts->pmuxcr, MPC85xx_PMUXCR_QE(0) | | ||
148 | MPC85xx_PMUXCR_QE(3) | | ||
149 | MPC85xx_PMUXCR_QE(9) | | ||
150 | MPC85xx_PMUXCR_QE(12)); | ||
151 | iounmap(guts); | ||
152 | } | ||
153 | of_node_put(np); | ||
154 | } | ||
155 | |||
156 | } | ||
157 | #endif | ||
158 | |||
159 | qe_fail: | ||
160 | #endif /* CONFIG_QUICC_ENGINE */ | ||
161 | |||
88 | printk(KERN_INFO "MPC85xx RDB board from Freescale Semiconductor\n"); | 162 | printk(KERN_INFO "MPC85xx RDB board from Freescale Semiconductor\n"); |
89 | } | 163 | } |
90 | 164 | ||
91 | machine_device_initcall(p2020_rdb, mpc85xx_common_publish_devices); | 165 | machine_device_initcall(p2020_rdb, mpc85xx_common_publish_devices); |
166 | machine_device_initcall(p2020_rdb_pc, mpc85xx_common_publish_devices); | ||
167 | machine_device_initcall(p1020_mbg_pc, mpc85xx_common_publish_devices); | ||
92 | machine_device_initcall(p1020_rdb, mpc85xx_common_publish_devices); | 168 | machine_device_initcall(p1020_rdb, mpc85xx_common_publish_devices); |
169 | machine_device_initcall(p1020_rdb_pc, mpc85xx_common_publish_devices); | ||
170 | machine_device_initcall(p1020_utm_pc, mpc85xx_common_publish_devices); | ||
171 | machine_device_initcall(p1021_rdb_pc, mpc85xx_common_publish_devices); | ||
172 | machine_device_initcall(p1025_rdb, mpc85xx_common_publish_devices); | ||
93 | 173 | ||
94 | /* | 174 | /* |
95 | * Called very early, device-tree isn't unflattened | 175 | * Called very early, device-tree isn't unflattened |
@@ -112,6 +192,52 @@ static int __init p1020_rdb_probe(void) | |||
112 | return 0; | 192 | return 0; |
113 | } | 193 | } |
114 | 194 | ||
195 | static int __init p1020_rdb_pc_probe(void) | ||
196 | { | ||
197 | unsigned long root = of_get_flat_dt_root(); | ||
198 | |||
199 | return of_flat_dt_is_compatible(root, "fsl,P1020RDB-PC"); | ||
200 | } | ||
201 | |||
202 | static int __init p1021_rdb_pc_probe(void) | ||
203 | { | ||
204 | unsigned long root = of_get_flat_dt_root(); | ||
205 | |||
206 | if (of_flat_dt_is_compatible(root, "fsl,P1021RDB-PC")) | ||
207 | return 1; | ||
208 | return 0; | ||
209 | } | ||
210 | |||
211 | static int __init p2020_rdb_pc_probe(void) | ||
212 | { | ||
213 | unsigned long root = of_get_flat_dt_root(); | ||
214 | |||
215 | if (of_flat_dt_is_compatible(root, "fsl,P2020RDB-PC")) | ||
216 | return 1; | ||
217 | return 0; | ||
218 | } | ||
219 | |||
220 | static int __init p1025_rdb_probe(void) | ||
221 | { | ||
222 | unsigned long root = of_get_flat_dt_root(); | ||
223 | |||
224 | return of_flat_dt_is_compatible(root, "fsl,P1025RDB"); | ||
225 | } | ||
226 | |||
227 | static int __init p1020_mbg_pc_probe(void) | ||
228 | { | ||
229 | unsigned long root = of_get_flat_dt_root(); | ||
230 | |||
231 | return of_flat_dt_is_compatible(root, "fsl,P1020MBG-PC"); | ||
232 | } | ||
233 | |||
234 | static int __init p1020_utm_pc_probe(void) | ||
235 | { | ||
236 | unsigned long root = of_get_flat_dt_root(); | ||
237 | |||
238 | return of_flat_dt_is_compatible(root, "fsl,P1020UTM-PC"); | ||
239 | } | ||
240 | |||
115 | define_machine(p2020_rdb) { | 241 | define_machine(p2020_rdb) { |
116 | .name = "P2020 RDB", | 242 | .name = "P2020 RDB", |
117 | .probe = p2020_rdb_probe, | 243 | .probe = p2020_rdb_probe, |
@@ -139,3 +265,87 @@ define_machine(p1020_rdb) { | |||
139 | .calibrate_decr = generic_calibrate_decr, | 265 | .calibrate_decr = generic_calibrate_decr, |
140 | .progress = udbg_progress, | 266 | .progress = udbg_progress, |
141 | }; | 267 | }; |
268 | |||
269 | define_machine(p1021_rdb_pc) { | ||
270 | .name = "P1021 RDB-PC", | ||
271 | .probe = p1021_rdb_pc_probe, | ||
272 | .setup_arch = mpc85xx_rdb_setup_arch, | ||
273 | .init_IRQ = mpc85xx_rdb_pic_init, | ||
274 | #ifdef CONFIG_PCI | ||
275 | .pcibios_fixup_bus = fsl_pcibios_fixup_bus, | ||
276 | #endif | ||
277 | .get_irq = mpic_get_irq, | ||
278 | .restart = fsl_rstcr_restart, | ||
279 | .calibrate_decr = generic_calibrate_decr, | ||
280 | .progress = udbg_progress, | ||
281 | }; | ||
282 | |||
283 | define_machine(p2020_rdb_pc) { | ||
284 | .name = "P2020RDB-PC", | ||
285 | .probe = p2020_rdb_pc_probe, | ||
286 | .setup_arch = mpc85xx_rdb_setup_arch, | ||
287 | .init_IRQ = mpc85xx_rdb_pic_init, | ||
288 | #ifdef CONFIG_PCI | ||
289 | .pcibios_fixup_bus = fsl_pcibios_fixup_bus, | ||
290 | #endif | ||
291 | .get_irq = mpic_get_irq, | ||
292 | .restart = fsl_rstcr_restart, | ||
293 | .calibrate_decr = generic_calibrate_decr, | ||
294 | .progress = udbg_progress, | ||
295 | }; | ||
296 | |||
297 | define_machine(p1025_rdb) { | ||
298 | .name = "P1025 RDB", | ||
299 | .probe = p1025_rdb_probe, | ||
300 | .setup_arch = mpc85xx_rdb_setup_arch, | ||
301 | .init_IRQ = mpc85xx_rdb_pic_init, | ||
302 | #ifdef CONFIG_PCI | ||
303 | .pcibios_fixup_bus = fsl_pcibios_fixup_bus, | ||
304 | #endif | ||
305 | .get_irq = mpic_get_irq, | ||
306 | .restart = fsl_rstcr_restart, | ||
307 | .calibrate_decr = generic_calibrate_decr, | ||
308 | .progress = udbg_progress, | ||
309 | }; | ||
310 | |||
311 | define_machine(p1020_mbg_pc) { | ||
312 | .name = "P1020 MBG-PC", | ||
313 | .probe = p1020_mbg_pc_probe, | ||
314 | .setup_arch = mpc85xx_rdb_setup_arch, | ||
315 | .init_IRQ = mpc85xx_rdb_pic_init, | ||
316 | #ifdef CONFIG_PCI | ||
317 | .pcibios_fixup_bus = fsl_pcibios_fixup_bus, | ||
318 | #endif | ||
319 | .get_irq = mpic_get_irq, | ||
320 | .restart = fsl_rstcr_restart, | ||
321 | .calibrate_decr = generic_calibrate_decr, | ||
322 | .progress = udbg_progress, | ||
323 | }; | ||
324 | |||
325 | define_machine(p1020_utm_pc) { | ||
326 | .name = "P1020 UTM-PC", | ||
327 | .probe = p1020_utm_pc_probe, | ||
328 | .setup_arch = mpc85xx_rdb_setup_arch, | ||
329 | .init_IRQ = mpc85xx_rdb_pic_init, | ||
330 | #ifdef CONFIG_PCI | ||
331 | .pcibios_fixup_bus = fsl_pcibios_fixup_bus, | ||
332 | #endif | ||
333 | .get_irq = mpic_get_irq, | ||
334 | .restart = fsl_rstcr_restart, | ||
335 | .calibrate_decr = generic_calibrate_decr, | ||
336 | .progress = udbg_progress, | ||
337 | }; | ||
338 | |||
339 | define_machine(p1020_rdb_pc) { | ||
340 | .name = "P1020RDB-PC", | ||
341 | .probe = p1020_rdb_pc_probe, | ||
342 | .setup_arch = mpc85xx_rdb_setup_arch, | ||
343 | .init_IRQ = mpc85xx_rdb_pic_init, | ||
344 | #ifdef CONFIG_PCI | ||
345 | .pcibios_fixup_bus = fsl_pcibios_fixup_bus, | ||
346 | #endif | ||
347 | .get_irq = mpic_get_irq, | ||
348 | .restart = fsl_rstcr_restart, | ||
349 | .calibrate_decr = generic_calibrate_decr, | ||
350 | .progress = udbg_progress, | ||
351 | }; | ||
diff --git a/arch/powerpc/platforms/85xx/p1010rdb.c b/arch/powerpc/platforms/85xx/p1010rdb.c index 538bc3f57e9d..d8bd6563d9ca 100644 --- a/arch/powerpc/platforms/85xx/p1010rdb.c +++ b/arch/powerpc/platforms/85xx/p1010rdb.c | |||
@@ -32,9 +32,8 @@ | |||
32 | 32 | ||
33 | void __init p1010_rdb_pic_init(void) | 33 | void __init p1010_rdb_pic_init(void) |
34 | { | 34 | { |
35 | struct mpic *mpic = mpic_alloc(NULL, 0, | 35 | struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | |
36 | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN | | 36 | MPIC_SINGLE_DEST_CPU, |
37 | MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU, | ||
38 | 0, 256, " OpenPIC "); | 37 | 0, 256, " OpenPIC "); |
39 | 38 | ||
40 | BUG_ON(mpic == NULL); | 39 | BUG_ON(mpic == NULL); |
diff --git a/arch/powerpc/platforms/85xx/p1022_ds.c b/arch/powerpc/platforms/85xx/p1022_ds.c index b0984ada3f83..0fe88e39945e 100644 --- a/arch/powerpc/platforms/85xx/p1022_ds.c +++ b/arch/powerpc/platforms/85xx/p1022_ds.c | |||
@@ -33,6 +33,10 @@ | |||
33 | 33 | ||
34 | #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) | 34 | #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) |
35 | 35 | ||
36 | #define PMUXCR_ELBCDIU_MASK 0xc0000000 | ||
37 | #define PMUXCR_ELBCDIU_NOR16 0x80000000 | ||
38 | #define PMUXCR_ELBCDIU_DIU 0x40000000 | ||
39 | |||
36 | /* | 40 | /* |
37 | * Board-specific initialization of the DIU. This code should probably be | 41 | * Board-specific initialization of the DIU. This code should probably be |
38 | * executed when the DIU is opened, rather than in arch code, but the DIU | 42 | * executed when the DIU is opened, rather than in arch code, but the DIU |
@@ -50,11 +54,22 @@ | |||
50 | #define CLKDVDR_PXCLK_MASK 0x00FF0000 | 54 | #define CLKDVDR_PXCLK_MASK 0x00FF0000 |
51 | 55 | ||
52 | /* Some ngPIXIS register definitions */ | 56 | /* Some ngPIXIS register definitions */ |
57 | #define PX_CTL 3 | ||
58 | #define PX_BRDCFG0 8 | ||
59 | #define PX_BRDCFG1 9 | ||
60 | |||
61 | #define PX_BRDCFG0_ELBC_SPI_MASK 0xc0 | ||
62 | #define PX_BRDCFG0_ELBC_SPI_ELBC 0x00 | ||
63 | #define PX_BRDCFG0_ELBC_SPI_NULL 0xc0 | ||
64 | #define PX_BRDCFG0_ELBC_DIU 0x02 | ||
65 | |||
53 | #define PX_BRDCFG1_DVIEN 0x80 | 66 | #define PX_BRDCFG1_DVIEN 0x80 |
54 | #define PX_BRDCFG1_DFPEN 0x40 | 67 | #define PX_BRDCFG1_DFPEN 0x40 |
55 | #define PX_BRDCFG1_BACKLIGHT 0x20 | 68 | #define PX_BRDCFG1_BACKLIGHT 0x20 |
56 | #define PX_BRDCFG1_DDCEN 0x10 | 69 | #define PX_BRDCFG1_DDCEN 0x10 |
57 | 70 | ||
71 | #define PX_CTL_ALTACC 0x80 | ||
72 | |||
58 | /* | 73 | /* |
59 | * DIU Area Descriptor | 74 | * DIU Area Descriptor |
60 | * | 75 | * |
@@ -133,44 +148,117 @@ static void p1022ds_set_gamma_table(enum fsl_diu_monitor_port port, | |||
133 | */ | 148 | */ |
134 | static void p1022ds_set_monitor_port(enum fsl_diu_monitor_port port) | 149 | static void p1022ds_set_monitor_port(enum fsl_diu_monitor_port port) |
135 | { | 150 | { |
136 | struct device_node *np; | 151 | struct device_node *guts_node; |
137 | void __iomem *pixis; | 152 | struct device_node *indirect_node = NULL; |
138 | u8 __iomem *brdcfg1; | 153 | struct ccsr_guts_85xx __iomem *guts; |
139 | 154 | u8 __iomem *lbc_lcs0_ba = NULL; | |
140 | np = of_find_compatible_node(NULL, NULL, "fsl,p1022ds-fpga"); | 155 | u8 __iomem *lbc_lcs1_ba = NULL; |
141 | if (!np) | 156 | u8 b; |
142 | /* older device trees used "fsl,p1022ds-pixis" */ | 157 | |
143 | np = of_find_compatible_node(NULL, NULL, "fsl,p1022ds-pixis"); | 158 | /* Map the global utilities registers. */ |
144 | if (!np) { | 159 | guts_node = of_find_compatible_node(NULL, NULL, "fsl,p1022-guts"); |
145 | pr_err("p1022ds: missing ngPIXIS node\n"); | 160 | if (!guts_node) { |
161 | pr_err("p1022ds: missing global utilties device node\n"); | ||
146 | return; | 162 | return; |
147 | } | 163 | } |
148 | 164 | ||
149 | pixis = of_iomap(np, 0); | 165 | guts = of_iomap(guts_node, 0); |
150 | if (!pixis) { | 166 | if (!guts) { |
151 | pr_err("p1022ds: could not map ngPIXIS registers\n"); | 167 | pr_err("p1022ds: could not map global utilties device\n"); |
152 | return; | 168 | goto exit; |
153 | } | 169 | } |
154 | brdcfg1 = pixis + 9; /* BRDCFG1 is at offset 9 in the ngPIXIS */ | 170 | |
171 | indirect_node = of_find_compatible_node(NULL, NULL, | ||
172 | "fsl,p1022ds-indirect-pixis"); | ||
173 | if (!indirect_node) { | ||
174 | pr_err("p1022ds: missing pixis indirect mode node\n"); | ||
175 | goto exit; | ||
176 | } | ||
177 | |||
178 | lbc_lcs0_ba = of_iomap(indirect_node, 0); | ||
179 | if (!lbc_lcs0_ba) { | ||
180 | pr_err("p1022ds: could not map localbus chip select 0\n"); | ||
181 | goto exit; | ||
182 | } | ||
183 | |||
184 | lbc_lcs1_ba = of_iomap(indirect_node, 1); | ||
185 | if (!lbc_lcs1_ba) { | ||
186 | pr_err("p1022ds: could not map localbus chip select 1\n"); | ||
187 | goto exit; | ||
188 | } | ||
189 | |||
190 | /* Make sure we're in indirect mode first. */ | ||
191 | if ((in_be32(&guts->pmuxcr) & PMUXCR_ELBCDIU_MASK) != | ||
192 | PMUXCR_ELBCDIU_DIU) { | ||
193 | struct device_node *pixis_node; | ||
194 | void __iomem *pixis; | ||
195 | |||
196 | pixis_node = | ||
197 | of_find_compatible_node(NULL, NULL, "fsl,p1022ds-fpga"); | ||
198 | if (!pixis_node) { | ||
199 | pr_err("p1022ds: missing pixis node\n"); | ||
200 | goto exit; | ||
201 | } | ||
202 | |||
203 | pixis = of_iomap(pixis_node, 0); | ||
204 | of_node_put(pixis_node); | ||
205 | if (!pixis) { | ||
206 | pr_err("p1022ds: could not map pixis registers\n"); | ||
207 | goto exit; | ||
208 | } | ||
209 | |||
210 | /* Enable indirect PIXIS mode. */ | ||
211 | setbits8(pixis + PX_CTL, PX_CTL_ALTACC); | ||
212 | iounmap(pixis); | ||
213 | |||
214 | /* Switch the board mux to the DIU */ | ||
215 | out_8(lbc_lcs0_ba, PX_BRDCFG0); /* BRDCFG0 */ | ||
216 | b = in_8(lbc_lcs1_ba); | ||
217 | b |= PX_BRDCFG0_ELBC_DIU; | ||
218 | out_8(lbc_lcs1_ba, b); | ||
219 | |||
220 | /* Set the chip mux to DIU mode. */ | ||
221 | clrsetbits_be32(&guts->pmuxcr, PMUXCR_ELBCDIU_MASK, | ||
222 | PMUXCR_ELBCDIU_DIU); | ||
223 | in_be32(&guts->pmuxcr); | ||
224 | } | ||
225 | |||
155 | 226 | ||
156 | switch (port) { | 227 | switch (port) { |
157 | case FSL_DIU_PORT_DVI: | 228 | case FSL_DIU_PORT_DVI: |
158 | printk(KERN_INFO "%s:%u\n", __func__, __LINE__); | ||
159 | /* Enable the DVI port, disable the DFP and the backlight */ | 229 | /* Enable the DVI port, disable the DFP and the backlight */ |
160 | clrsetbits_8(brdcfg1, PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT, | 230 | out_8(lbc_lcs0_ba, PX_BRDCFG1); |
161 | PX_BRDCFG1_DVIEN); | 231 | b = in_8(lbc_lcs1_ba); |
232 | b &= ~(PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT); | ||
233 | b |= PX_BRDCFG1_DVIEN; | ||
234 | out_8(lbc_lcs1_ba, b); | ||
162 | break; | 235 | break; |
163 | case FSL_DIU_PORT_LVDS: | 236 | case FSL_DIU_PORT_LVDS: |
164 | printk(KERN_INFO "%s:%u\n", __func__, __LINE__); | 237 | /* |
238 | * LVDS also needs backlight enabled, otherwise the display | ||
239 | * will be blank. | ||
240 | */ | ||
165 | /* Enable the DFP port, disable the DVI and the backlight */ | 241 | /* Enable the DFP port, disable the DVI and the backlight */ |
166 | clrsetbits_8(brdcfg1, PX_BRDCFG1_DVIEN | PX_BRDCFG1_BACKLIGHT, | 242 | out_8(lbc_lcs0_ba, PX_BRDCFG1); |
167 | PX_BRDCFG1_DFPEN); | 243 | b = in_8(lbc_lcs1_ba); |
244 | b &= ~PX_BRDCFG1_DVIEN; | ||
245 | b |= PX_BRDCFG1_DFPEN | PX_BRDCFG1_BACKLIGHT; | ||
246 | out_8(lbc_lcs1_ba, b); | ||
168 | break; | 247 | break; |
169 | default: | 248 | default: |
170 | pr_err("p1022ds: unsupported monitor port %i\n", port); | 249 | pr_err("p1022ds: unsupported monitor port %i\n", port); |
171 | } | 250 | } |
172 | 251 | ||
173 | iounmap(pixis); | 252 | exit: |
253 | if (lbc_lcs1_ba) | ||
254 | iounmap(lbc_lcs1_ba); | ||
255 | if (lbc_lcs0_ba) | ||
256 | iounmap(lbc_lcs0_ba); | ||
257 | if (guts) | ||
258 | iounmap(guts); | ||
259 | |||
260 | of_node_put(indirect_node); | ||
261 | of_node_put(guts_node); | ||
174 | } | 262 | } |
175 | 263 | ||
176 | /** | 264 | /** |
@@ -242,15 +330,56 @@ p1022ds_valid_monitor_port(enum fsl_diu_monitor_port port) | |||
242 | 330 | ||
243 | void __init p1022_ds_pic_init(void) | 331 | void __init p1022_ds_pic_init(void) |
244 | { | 332 | { |
245 | struct mpic *mpic = mpic_alloc(NULL, 0, | 333 | struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | |
246 | MPIC_WANTS_RESET | | ||
247 | MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS | | ||
248 | MPIC_SINGLE_DEST_CPU, | 334 | MPIC_SINGLE_DEST_CPU, |
249 | 0, 256, " OpenPIC "); | 335 | 0, 256, " OpenPIC "); |
250 | BUG_ON(mpic == NULL); | 336 | BUG_ON(mpic == NULL); |
251 | mpic_init(mpic); | 337 | mpic_init(mpic); |
252 | } | 338 | } |
253 | 339 | ||
340 | #if defined(CONFIG_FB_FSL_DIU) || defined(CONFIG_FB_FSL_DIU_MODULE) | ||
341 | |||
342 | /* | ||
343 | * Disables a node in the device tree. | ||
344 | * | ||
345 | * This function is called before kmalloc() is available, so the 'new' object | ||
346 | * should be allocated in the global area. The easiest way is to do that is | ||
347 | * to allocate one static local variable for each call to this function. | ||
348 | */ | ||
349 | static void __init disable_one_node(struct device_node *np, struct property *new) | ||
350 | { | ||
351 | struct property *old; | ||
352 | |||
353 | old = of_find_property(np, new->name, NULL); | ||
354 | if (old) | ||
355 | prom_update_property(np, new, old); | ||
356 | else | ||
357 | prom_add_property(np, new); | ||
358 | } | ||
359 | |||
360 | /* TRUE if there is a "video=fslfb" command-line parameter. */ | ||
361 | static bool fslfb; | ||
362 | |||
363 | /* | ||
364 | * Search for a "video=fslfb" command-line parameter, and set 'fslfb' to | ||
365 | * true if we find it. | ||
366 | * | ||
367 | * We need to use early_param() instead of __setup() because the normal | ||
368 | * __setup() gets called to late. However, early_param() gets called very | ||
369 | * early, before the device tree is unflattened, so all we can do now is set a | ||
370 | * global variable. Later on, p1022_ds_setup_arch() will use that variable | ||
371 | * to determine if we need to update the device tree. | ||
372 | */ | ||
373 | static int __init early_video_setup(char *options) | ||
374 | { | ||
375 | fslfb = (strncmp(options, "fslfb:", 6) == 0); | ||
376 | |||
377 | return 0; | ||
378 | } | ||
379 | early_param("video", early_video_setup); | ||
380 | |||
381 | #endif | ||
382 | |||
254 | /* | 383 | /* |
255 | * Setup the architecture | 384 | * Setup the architecture |
256 | */ | 385 | */ |
@@ -288,6 +417,34 @@ static void __init p1022_ds_setup_arch(void) | |||
288 | diu_ops.set_monitor_port = p1022ds_set_monitor_port; | 417 | diu_ops.set_monitor_port = p1022ds_set_monitor_port; |
289 | diu_ops.set_pixel_clock = p1022ds_set_pixel_clock; | 418 | diu_ops.set_pixel_clock = p1022ds_set_pixel_clock; |
290 | diu_ops.valid_monitor_port = p1022ds_valid_monitor_port; | 419 | diu_ops.valid_monitor_port = p1022ds_valid_monitor_port; |
420 | |||
421 | /* | ||
422 | * Disable the NOR flash node if there is video=fslfb... command-line | ||
423 | * parameter. When the DIU is active, NOR flash is unavailable, so we | ||
424 | * have to disable the node before the MTD driver loads. | ||
425 | */ | ||
426 | if (fslfb) { | ||
427 | struct device_node *np = | ||
428 | of_find_compatible_node(NULL, NULL, "fsl,p1022-elbc"); | ||
429 | |||
430 | if (np) { | ||
431 | np = of_find_compatible_node(np, NULL, "cfi-flash"); | ||
432 | if (np) { | ||
433 | static struct property nor_status = { | ||
434 | .name = "status", | ||
435 | .value = "disabled", | ||
436 | .length = sizeof("disabled"), | ||
437 | }; | ||
438 | |||
439 | pr_info("p1022ds: disabling %s node", | ||
440 | np->full_name); | ||
441 | disable_one_node(np, &nor_status); | ||
442 | of_node_put(np); | ||
443 | } | ||
444 | } | ||
445 | |||
446 | } | ||
447 | |||
291 | #endif | 448 | #endif |
292 | 449 | ||
293 | mpc85xx_smp_init(); | 450 | mpc85xx_smp_init(); |
diff --git a/arch/powerpc/platforms/85xx/p1023_rds.c b/arch/powerpc/platforms/85xx/p1023_rds.c index d951e7027bb6..6b07398e4369 100644 --- a/arch/powerpc/platforms/85xx/p1023_rds.c +++ b/arch/powerpc/platforms/85xx/p1023_rds.c | |||
@@ -93,9 +93,8 @@ machine_device_initcall(p1023_rds, mpc85xx_common_publish_devices); | |||
93 | 93 | ||
94 | static void __init mpc85xx_rds_pic_init(void) | 94 | static void __init mpc85xx_rds_pic_init(void) |
95 | { | 95 | { |
96 | struct mpic *mpic = mpic_alloc(NULL, 0, | 96 | struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | |
97 | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN | | 97 | MPIC_SINGLE_DEST_CPU, |
98 | MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU, | ||
99 | 0, 256, " OpenPIC "); | 98 | 0, 256, " OpenPIC "); |
100 | 99 | ||
101 | BUG_ON(mpic == NULL); | 100 | BUG_ON(mpic == NULL); |
diff --git a/arch/powerpc/platforms/85xx/sbc8548.c b/arch/powerpc/platforms/85xx/sbc8548.c index 184a50784617..1677b8a22677 100644 --- a/arch/powerpc/platforms/85xx/sbc8548.c +++ b/arch/powerpc/platforms/85xx/sbc8548.c | |||
@@ -54,8 +54,7 @@ static int sbc_rev; | |||
54 | 54 | ||
55 | static void __init sbc8548_pic_init(void) | 55 | static void __init sbc8548_pic_init(void) |
56 | { | 56 | { |
57 | struct mpic *mpic = mpic_alloc(NULL, 0, | 57 | struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN, |
58 | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, | ||
59 | 0, 256, " OpenPIC "); | 58 | 0, 256, " OpenPIC "); |
60 | BUG_ON(mpic == NULL); | 59 | BUG_ON(mpic == NULL); |
61 | mpic_init(mpic); | 60 | mpic_init(mpic); |
diff --git a/arch/powerpc/platforms/85xx/sbc8560.c b/arch/powerpc/platforms/85xx/sbc8560.c index 940752e93051..3c3bbcc27566 100644 --- a/arch/powerpc/platforms/85xx/sbc8560.c +++ b/arch/powerpc/platforms/85xx/sbc8560.c | |||
@@ -41,8 +41,7 @@ | |||
41 | 41 | ||
42 | static void __init sbc8560_pic_init(void) | 42 | static void __init sbc8560_pic_init(void) |
43 | { | 43 | { |
44 | struct mpic *mpic = mpic_alloc(NULL, 0, | 44 | struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN, |
45 | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, | ||
46 | 0, 256, " OpenPIC "); | 45 | 0, 256, " OpenPIC "); |
47 | BUG_ON(mpic == NULL); | 46 | BUG_ON(mpic == NULL); |
48 | mpic_init(mpic); | 47 | mpic_init(mpic); |
diff --git a/arch/powerpc/platforms/85xx/socrates.c b/arch/powerpc/platforms/85xx/socrates.c index 18f635906b27..b71919217756 100644 --- a/arch/powerpc/platforms/85xx/socrates.c +++ b/arch/powerpc/platforms/85xx/socrates.c | |||
@@ -48,8 +48,7 @@ static void __init socrates_pic_init(void) | |||
48 | { | 48 | { |
49 | struct device_node *np; | 49 | struct device_node *np; |
50 | 50 | ||
51 | struct mpic *mpic = mpic_alloc(NULL, 0, | 51 | struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN, |
52 | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, | ||
53 | 0, 256, " OpenPIC "); | 52 | 0, 256, " OpenPIC "); |
54 | BUG_ON(mpic == NULL); | 53 | BUG_ON(mpic == NULL); |
55 | mpic_init(mpic); | 54 | mpic_init(mpic); |
diff --git a/arch/powerpc/platforms/85xx/stx_gp3.c b/arch/powerpc/platforms/85xx/stx_gp3.c index e9e5234b4e76..27ca3a7b04ab 100644 --- a/arch/powerpc/platforms/85xx/stx_gp3.c +++ b/arch/powerpc/platforms/85xx/stx_gp3.c | |||
@@ -48,8 +48,7 @@ | |||
48 | 48 | ||
49 | static void __init stx_gp3_pic_init(void) | 49 | static void __init stx_gp3_pic_init(void) |
50 | { | 50 | { |
51 | struct mpic *mpic = mpic_alloc(NULL, 0, | 51 | struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN, |
52 | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, | ||
53 | 0, 256, " OpenPIC "); | 52 | 0, 256, " OpenPIC "); |
54 | BUG_ON(mpic == NULL); | 53 | BUG_ON(mpic == NULL); |
55 | mpic_init(mpic); | 54 | mpic_init(mpic); |
diff --git a/arch/powerpc/platforms/85xx/tqm85xx.c b/arch/powerpc/platforms/85xx/tqm85xx.c index bf7c89fb75bb..d7504cefe016 100644 --- a/arch/powerpc/platforms/85xx/tqm85xx.c +++ b/arch/powerpc/platforms/85xx/tqm85xx.c | |||
@@ -47,7 +47,7 @@ | |||
47 | static void __init tqm85xx_pic_init(void) | 47 | static void __init tqm85xx_pic_init(void) |
48 | { | 48 | { |
49 | struct mpic *mpic = mpic_alloc(NULL, 0, | 49 | struct mpic *mpic = mpic_alloc(NULL, 0, |
50 | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, | 50 | MPIC_BIG_ENDIAN, |
51 | 0, 256, " OpenPIC "); | 51 | 0, 256, " OpenPIC "); |
52 | BUG_ON(mpic == NULL); | 52 | BUG_ON(mpic == NULL); |
53 | mpic_init(mpic); | 53 | mpic_init(mpic); |
diff --git a/arch/powerpc/platforms/85xx/xes_mpc85xx.c b/arch/powerpc/platforms/85xx/xes_mpc85xx.c index 3a69f8b77de6..503c21596c63 100644 --- a/arch/powerpc/platforms/85xx/xes_mpc85xx.c +++ b/arch/powerpc/platforms/85xx/xes_mpc85xx.c | |||
@@ -43,9 +43,7 @@ | |||
43 | 43 | ||
44 | void __init xes_mpc85xx_pic_init(void) | 44 | void __init xes_mpc85xx_pic_init(void) |
45 | { | 45 | { |
46 | struct mpic *mpic = mpic_alloc(NULL, 0, | 46 | struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN, |
47 | MPIC_WANTS_RESET | | ||
48 | MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS, | ||
49 | 0, 256, " OpenPIC "); | 47 | 0, 256, " OpenPIC "); |
50 | BUG_ON(mpic == NULL); | 48 | BUG_ON(mpic == NULL); |
51 | mpic_init(mpic); | 49 | mpic_init(mpic); |
diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig index 8d6599d54ea6..7a6279e38213 100644 --- a/arch/powerpc/platforms/86xx/Kconfig +++ b/arch/powerpc/platforms/86xx/Kconfig | |||
@@ -39,6 +39,7 @@ config GEF_PPC9A | |||
39 | select MMIO_NVRAM | 39 | select MMIO_NVRAM |
40 | select GENERIC_GPIO | 40 | select GENERIC_GPIO |
41 | select ARCH_REQUIRE_GPIOLIB | 41 | select ARCH_REQUIRE_GPIOLIB |
42 | select GE_FPGA | ||
42 | help | 43 | help |
43 | This option enables support for the GE PPC9A. | 44 | This option enables support for the GE PPC9A. |
44 | 45 | ||
@@ -48,6 +49,7 @@ config GEF_SBC310 | |||
48 | select MMIO_NVRAM | 49 | select MMIO_NVRAM |
49 | select GENERIC_GPIO | 50 | select GENERIC_GPIO |
50 | select ARCH_REQUIRE_GPIOLIB | 51 | select ARCH_REQUIRE_GPIOLIB |
52 | select GE_FPGA | ||
51 | help | 53 | help |
52 | This option enables support for the GE SBC310. | 54 | This option enables support for the GE SBC310. |
53 | 55 | ||
@@ -57,6 +59,7 @@ config GEF_SBC610 | |||
57 | select MMIO_NVRAM | 59 | select MMIO_NVRAM |
58 | select GENERIC_GPIO | 60 | select GENERIC_GPIO |
59 | select ARCH_REQUIRE_GPIOLIB | 61 | select ARCH_REQUIRE_GPIOLIB |
62 | select GE_FPGA | ||
60 | select HAS_RAPIDIO | 63 | select HAS_RAPIDIO |
61 | help | 64 | help |
62 | This option enables support for the GE SBC610. | 65 | This option enables support for the GE SBC610. |
diff --git a/arch/powerpc/platforms/86xx/Makefile b/arch/powerpc/platforms/86xx/Makefile index 4b0d7b1aa005..ede815d6489d 100644 --- a/arch/powerpc/platforms/86xx/Makefile +++ b/arch/powerpc/platforms/86xx/Makefile | |||
@@ -7,7 +7,6 @@ obj-$(CONFIG_SMP) += mpc86xx_smp.o | |||
7 | obj-$(CONFIG_MPC8641_HPCN) += mpc86xx_hpcn.o | 7 | obj-$(CONFIG_MPC8641_HPCN) += mpc86xx_hpcn.o |
8 | obj-$(CONFIG_SBC8641D) += sbc8641d.o | 8 | obj-$(CONFIG_SBC8641D) += sbc8641d.o |
9 | obj-$(CONFIG_MPC8610_HPCD) += mpc8610_hpcd.o | 9 | obj-$(CONFIG_MPC8610_HPCD) += mpc8610_hpcd.o |
10 | gef-gpio-$(CONFIG_GPIOLIB) += gef_gpio.o | 10 | obj-$(CONFIG_GEF_SBC610) += gef_sbc610.o |
11 | obj-$(CONFIG_GEF_SBC610) += gef_sbc610.o gef_pic.o $(gef-gpio-y) | 11 | obj-$(CONFIG_GEF_SBC310) += gef_sbc310.o |
12 | obj-$(CONFIG_GEF_SBC310) += gef_sbc310.o gef_pic.o $(gef-gpio-y) | 12 | obj-$(CONFIG_GEF_PPC9A) += gef_ppc9a.o |
13 | obj-$(CONFIG_GEF_PPC9A) += gef_ppc9a.o gef_pic.o $(gef-gpio-y) | ||
diff --git a/arch/powerpc/platforms/86xx/gef_ppc9a.c b/arch/powerpc/platforms/86xx/gef_ppc9a.c index 60ce07e39100..ed58b6cfd60c 100644 --- a/arch/powerpc/platforms/86xx/gef_ppc9a.c +++ b/arch/powerpc/platforms/86xx/gef_ppc9a.c | |||
@@ -37,9 +37,9 @@ | |||
37 | 37 | ||
38 | #include <sysdev/fsl_pci.h> | 38 | #include <sysdev/fsl_pci.h> |
39 | #include <sysdev/fsl_soc.h> | 39 | #include <sysdev/fsl_soc.h> |
40 | #include <sysdev/ge/ge_pic.h> | ||
40 | 41 | ||
41 | #include "mpc86xx.h" | 42 | #include "mpc86xx.h" |
42 | #include "gef_pic.h" | ||
43 | 43 | ||
44 | #undef DEBUG | 44 | #undef DEBUG |
45 | 45 | ||
diff --git a/arch/powerpc/platforms/86xx/gef_sbc310.c b/arch/powerpc/platforms/86xx/gef_sbc310.c index 3ecee25bf3ed..710db69bd523 100644 --- a/arch/powerpc/platforms/86xx/gef_sbc310.c +++ b/arch/powerpc/platforms/86xx/gef_sbc310.c | |||
@@ -37,9 +37,9 @@ | |||
37 | 37 | ||
38 | #include <sysdev/fsl_pci.h> | 38 | #include <sysdev/fsl_pci.h> |
39 | #include <sysdev/fsl_soc.h> | 39 | #include <sysdev/fsl_soc.h> |
40 | #include <sysdev/ge/ge_pic.h> | ||
40 | 41 | ||
41 | #include "mpc86xx.h" | 42 | #include "mpc86xx.h" |
42 | #include "gef_pic.h" | ||
43 | 43 | ||
44 | #undef DEBUG | 44 | #undef DEBUG |
45 | 45 | ||
diff --git a/arch/powerpc/platforms/86xx/gef_sbc610.c b/arch/powerpc/platforms/86xx/gef_sbc610.c index 5090d608d9ee..4a13d2f4ac20 100644 --- a/arch/powerpc/platforms/86xx/gef_sbc610.c +++ b/arch/powerpc/platforms/86xx/gef_sbc610.c | |||
@@ -37,9 +37,9 @@ | |||
37 | 37 | ||
38 | #include <sysdev/fsl_pci.h> | 38 | #include <sysdev/fsl_pci.h> |
39 | #include <sysdev/fsl_soc.h> | 39 | #include <sysdev/fsl_soc.h> |
40 | #include <sysdev/ge/ge_pic.h> | ||
40 | 41 | ||
41 | #include "mpc86xx.h" | 42 | #include "mpc86xx.h" |
42 | #include "gef_pic.h" | ||
43 | 43 | ||
44 | #undef DEBUG | 44 | #undef DEBUG |
45 | 45 | ||
diff --git a/arch/powerpc/platforms/86xx/pic.c b/arch/powerpc/platforms/86xx/pic.c index 52bbfa031531..22cc3571ae19 100644 --- a/arch/powerpc/platforms/86xx/pic.c +++ b/arch/powerpc/platforms/86xx/pic.c | |||
@@ -37,9 +37,8 @@ void __init mpc86xx_init_irq(void) | |||
37 | int cascade_irq; | 37 | int cascade_irq; |
38 | #endif | 38 | #endif |
39 | 39 | ||
40 | struct mpic *mpic = mpic_alloc(NULL, 0, | 40 | struct mpic *mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | |
41 | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN | | 41 | MPIC_SINGLE_DEST_CPU, |
42 | MPIC_BROKEN_FRR_NIRQS | MPIC_SINGLE_DEST_CPU, | ||
43 | 0, 256, " MPIC "); | 42 | 0, 256, " MPIC "); |
44 | BUG_ON(mpic == NULL); | 43 | BUG_ON(mpic == NULL); |
45 | 44 | ||
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index 0cfb46d54b8c..a35ca44ade66 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig | |||
@@ -2,7 +2,6 @@ menu "Platform support" | |||
2 | 2 | ||
3 | source "arch/powerpc/platforms/powernv/Kconfig" | 3 | source "arch/powerpc/platforms/powernv/Kconfig" |
4 | source "arch/powerpc/platforms/pseries/Kconfig" | 4 | source "arch/powerpc/platforms/pseries/Kconfig" |
5 | source "arch/powerpc/platforms/iseries/Kconfig" | ||
6 | source "arch/powerpc/platforms/chrp/Kconfig" | 5 | source "arch/powerpc/platforms/chrp/Kconfig" |
7 | source "arch/powerpc/platforms/512x/Kconfig" | 6 | source "arch/powerpc/platforms/512x/Kconfig" |
8 | source "arch/powerpc/platforms/52xx/Kconfig" | 7 | source "arch/powerpc/platforms/52xx/Kconfig" |
@@ -87,6 +86,14 @@ config MPIC_WEIRD | |||
87 | bool | 86 | bool |
88 | default n | 87 | default n |
89 | 88 | ||
89 | config MPIC_MSGR | ||
90 | bool "MPIC message register support" | ||
91 | depends on MPIC | ||
92 | default n | ||
93 | help | ||
94 | Enables support for the MPIC message registers. These | ||
95 | registers are used for inter-processor communication. | ||
96 | |||
90 | config PPC_I8259 | 97 | config PPC_I8259 |
91 | bool | 98 | bool |
92 | default n | 99 | default n |
@@ -138,7 +145,7 @@ config MPIC_BROKEN_REGREAD | |||
138 | of the register contents in software. | 145 | of the register contents in software. |
139 | 146 | ||
140 | config IBMVIO | 147 | config IBMVIO |
141 | depends on PPC_PSERIES || PPC_ISERIES | 148 | depends on PPC_PSERIES |
142 | bool | 149 | bool |
143 | default y | 150 | default y |
144 | 151 | ||
diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile index 2635a22bade2..879b4a448498 100644 --- a/arch/powerpc/platforms/Makefile +++ b/arch/powerpc/platforms/Makefile | |||
@@ -16,7 +16,6 @@ obj-$(CONFIG_FSL_SOC_BOOKE) += 85xx/ | |||
16 | obj-$(CONFIG_PPC_86xx) += 86xx/ | 16 | obj-$(CONFIG_PPC_86xx) += 86xx/ |
17 | obj-$(CONFIG_PPC_POWERNV) += powernv/ | 17 | obj-$(CONFIG_PPC_POWERNV) += powernv/ |
18 | obj-$(CONFIG_PPC_PSERIES) += pseries/ | 18 | obj-$(CONFIG_PPC_PSERIES) += pseries/ |
19 | obj-$(CONFIG_PPC_ISERIES) += iseries/ | ||
20 | obj-$(CONFIG_PPC_MAPLE) += maple/ | 19 | obj-$(CONFIG_PPC_MAPLE) += maple/ |
21 | obj-$(CONFIG_PPC_PASEMI) += pasemi/ | 20 | obj-$(CONFIG_PPC_PASEMI) += pasemi/ |
22 | obj-$(CONFIG_PPC_CELL) += cell/ | 21 | obj-$(CONFIG_PPC_CELL) += cell/ |
diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c index 62002a7edfed..fa3e294fd343 100644 --- a/arch/powerpc/platforms/cell/setup.c +++ b/arch/powerpc/platforms/cell/setup.c | |||
@@ -197,7 +197,8 @@ static void __init mpic_init_IRQ(void) | |||
197 | /* The MPIC driver will get everything it needs from the | 197 | /* The MPIC driver will get everything it needs from the |
198 | * device-tree, just pass 0 to all arguments | 198 | * device-tree, just pass 0 to all arguments |
199 | */ | 199 | */ |
200 | mpic = mpic_alloc(dn, 0, MPIC_SECONDARY, 0, 0, " MPIC "); | 200 | mpic = mpic_alloc(dn, 0, MPIC_SECONDARY | MPIC_NO_RESET, |
201 | 0, 0, " MPIC "); | ||
201 | if (mpic == NULL) | 202 | if (mpic == NULL) |
202 | continue; | 203 | continue; |
203 | mpic_init(mpic); | 204 | mpic_init(mpic); |
diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index 4a3d90e0d426..1d75c92ea8fb 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c | |||
@@ -646,6 +646,7 @@ long spufs_create(struct path *path, struct dentry *dentry, | |||
646 | 646 | ||
647 | out: | 647 | out: |
648 | mutex_unlock(&path->dentry->d_inode->i_mutex); | 648 | mutex_unlock(&path->dentry->d_inode->i_mutex); |
649 | dput(dentry); | ||
649 | return ret; | 650 | return ret; |
650 | } | 651 | } |
651 | 652 | ||
diff --git a/arch/powerpc/platforms/cell/spufs/syscalls.c b/arch/powerpc/platforms/cell/spufs/syscalls.c index 8591bb62d7fc..5665dcc382c7 100644 --- a/arch/powerpc/platforms/cell/spufs/syscalls.c +++ b/arch/powerpc/platforms/cell/spufs/syscalls.c | |||
@@ -70,8 +70,6 @@ static long do_spu_create(const char __user *pathname, unsigned int flags, | |||
70 | ret = PTR_ERR(dentry); | 70 | ret = PTR_ERR(dentry); |
71 | if (!IS_ERR(dentry)) { | 71 | if (!IS_ERR(dentry)) { |
72 | ret = spufs_create(&path, dentry, flags, mode, neighbor); | 72 | ret = spufs_create(&path, dentry, flags, mode, neighbor); |
73 | mutex_unlock(&path.dentry->d_inode->i_mutex); | ||
74 | dput(dentry); | ||
75 | path_put(&path); | 73 | path_put(&path); |
76 | } | 74 | } |
77 | 75 | ||
diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c index f1f17bb2c33c..c665d7de6c99 100644 --- a/arch/powerpc/platforms/chrp/setup.c +++ b/arch/powerpc/platforms/chrp/setup.c | |||
@@ -435,7 +435,8 @@ static void __init chrp_find_openpic(void) | |||
435 | if (len > 1) | 435 | if (len > 1) |
436 | isu_size = iranges[3]; | 436 | isu_size = iranges[3]; |
437 | 437 | ||
438 | chrp_mpic = mpic_alloc(np, opaddr, 0, isu_size, 0, " MPIC "); | 438 | chrp_mpic = mpic_alloc(np, opaddr, MPIC_NO_RESET, |
439 | isu_size, 0, " MPIC "); | ||
439 | if (chrp_mpic == NULL) { | 440 | if (chrp_mpic == NULL) { |
440 | printk(KERN_ERR "Failed to allocate MPIC structure\n"); | 441 | printk(KERN_ERR "Failed to allocate MPIC structure\n"); |
441 | goto bail; | 442 | goto bail; |
diff --git a/arch/powerpc/platforms/embedded6xx/holly.c b/arch/powerpc/platforms/embedded6xx/holly.c index 9cfcf20c0560..ab51b21b4bd7 100644 --- a/arch/powerpc/platforms/embedded6xx/holly.c +++ b/arch/powerpc/platforms/embedded6xx/holly.c | |||
@@ -154,11 +154,9 @@ static void __init holly_init_IRQ(void) | |||
154 | struct device_node *cascade_node = NULL; | 154 | struct device_node *cascade_node = NULL; |
155 | #endif | 155 | #endif |
156 | 156 | ||
157 | mpic = mpic_alloc(NULL, 0, | 157 | mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | |
158 | MPIC_BIG_ENDIAN | MPIC_WANTS_RESET | | ||
159 | MPIC_SPV_EOI | MPIC_NO_PTHROU_DIS | MPIC_REGSET_TSI108, | 158 | MPIC_SPV_EOI | MPIC_NO_PTHROU_DIS | MPIC_REGSET_TSI108, |
160 | 24, | 159 | 24, 0, |
161 | NR_IRQS-4, /* num_sources used */ | ||
162 | "Tsi108_PIC"); | 160 | "Tsi108_PIC"); |
163 | 161 | ||
164 | BUG_ON(mpic == NULL); | 162 | BUG_ON(mpic == NULL); |
diff --git a/arch/powerpc/platforms/embedded6xx/linkstation.c b/arch/powerpc/platforms/embedded6xx/linkstation.c index bcfad92c9cec..455e7c087422 100644 --- a/arch/powerpc/platforms/embedded6xx/linkstation.c +++ b/arch/powerpc/platforms/embedded6xx/linkstation.c | |||
@@ -82,8 +82,7 @@ static void __init linkstation_init_IRQ(void) | |||
82 | { | 82 | { |
83 | struct mpic *mpic; | 83 | struct mpic *mpic; |
84 | 84 | ||
85 | mpic = mpic_alloc(NULL, 0, MPIC_WANTS_RESET, | 85 | mpic = mpic_alloc(NULL, 0, 0, 4, 0, " EPIC "); |
86 | 4, 32, " EPIC "); | ||
87 | BUG_ON(mpic == NULL); | 86 | BUG_ON(mpic == NULL); |
88 | 87 | ||
89 | /* PCI IRQs */ | 88 | /* PCI IRQs */ |
diff --git a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c index f3350d786f5b..74ccce36baed 100644 --- a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c +++ b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c | |||
@@ -108,11 +108,9 @@ static void __init mpc7448_hpc2_init_IRQ(void) | |||
108 | struct device_node *cascade_node = NULL; | 108 | struct device_node *cascade_node = NULL; |
109 | #endif | 109 | #endif |
110 | 110 | ||
111 | mpic = mpic_alloc(NULL, 0, | 111 | mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN | |
112 | MPIC_BIG_ENDIAN | MPIC_WANTS_RESET | | ||
113 | MPIC_SPV_EOI | MPIC_NO_PTHROU_DIS | MPIC_REGSET_TSI108, | 112 | MPIC_SPV_EOI | MPIC_NO_PTHROU_DIS | MPIC_REGSET_TSI108, |
114 | 24, | 113 | 24, 0, |
115 | NR_IRQS-4, /* num_sources used */ | ||
116 | "Tsi108_PIC"); | 114 | "Tsi108_PIC"); |
117 | 115 | ||
118 | BUG_ON(mpic == NULL); | 116 | BUG_ON(mpic == NULL); |
diff --git a/arch/powerpc/platforms/embedded6xx/storcenter.c b/arch/powerpc/platforms/embedded6xx/storcenter.c index afa638834965..e0ed3c71d69b 100644 --- a/arch/powerpc/platforms/embedded6xx/storcenter.c +++ b/arch/powerpc/platforms/embedded6xx/storcenter.c | |||
@@ -84,8 +84,7 @@ static void __init storcenter_init_IRQ(void) | |||
84 | { | 84 | { |
85 | struct mpic *mpic; | 85 | struct mpic *mpic; |
86 | 86 | ||
87 | mpic = mpic_alloc(NULL, 0, MPIC_WANTS_RESET, | 87 | mpic = mpic_alloc(NULL, 0, 0, 16, 0, " OpenPIC "); |
88 | 16, 32, " OpenPIC "); | ||
89 | BUG_ON(mpic == NULL); | 88 | BUG_ON(mpic == NULL); |
90 | 89 | ||
91 | /* | 90 | /* |
diff --git a/arch/powerpc/platforms/iseries/Kconfig b/arch/powerpc/platforms/iseries/Kconfig deleted file mode 100644 index 63835e09e5cc..000000000000 --- a/arch/powerpc/platforms/iseries/Kconfig +++ /dev/null | |||
@@ -1,39 +0,0 @@ | |||
1 | config PPC_ISERIES | ||
2 | bool "IBM Legacy iSeries" | ||
3 | depends on PPC64 && PPC_BOOK3S | ||
4 | select OF_DYNAMIC | ||
5 | select PPC_SMP_MUXED_IPI | ||
6 | select PPC_INDIRECT_PIO | ||
7 | select PPC_INDIRECT_MMIO | ||
8 | select PPC_PCI_CHOICE if EXPERT | ||
9 | |||
10 | menu "iSeries device drivers" | ||
11 | depends on PPC_ISERIES | ||
12 | |||
13 | config VIODASD | ||
14 | tristate "iSeries Virtual I/O disk support" | ||
15 | depends on BLOCK | ||
16 | select VIOPATH | ||
17 | help | ||
18 | If you are running on an iSeries system and you want to use | ||
19 | virtual disks created and managed by OS/400, say Y. | ||
20 | |||
21 | config VIOCD | ||
22 | tristate "iSeries Virtual I/O CD support" | ||
23 | depends on BLOCK | ||
24 | select VIOPATH | ||
25 | help | ||
26 | If you are running Linux on an IBM iSeries system and you want to | ||
27 | read a CD drive owned by OS/400, say Y here. | ||
28 | |||
29 | config VIOTAPE | ||
30 | tristate "iSeries Virtual Tape Support" | ||
31 | select VIOPATH | ||
32 | help | ||
33 | If you are running Linux on an iSeries system and you want Linux | ||
34 | to read and/or write a tape drive owned by OS/400, say Y here. | ||
35 | |||
36 | endmenu | ||
37 | |||
38 | config VIOPATH | ||
39 | bool | ||
diff --git a/arch/powerpc/platforms/iseries/Makefile b/arch/powerpc/platforms/iseries/Makefile deleted file mode 100644 index a7602b11ed9d..000000000000 --- a/arch/powerpc/platforms/iseries/Makefile +++ /dev/null | |||
@@ -1,9 +0,0 @@ | |||
1 | ccflags-y := -mno-minimal-toc | ||
2 | |||
3 | obj-y += exception.o | ||
4 | obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o dt.o mf.o lpevents.o \ | ||
5 | hvcall.o proc.o htab.o iommu.o misc.o irq.o | ||
6 | obj-$(CONFIG_PCI) += pci.o | ||
7 | obj-$(CONFIG_SMP) += smp.o | ||
8 | obj-$(CONFIG_VIOPATH) += viopath.o vio.o | ||
9 | obj-$(CONFIG_MODULES) += ksyms.o | ||
diff --git a/arch/powerpc/platforms/iseries/call_hpt.h b/arch/powerpc/platforms/iseries/call_hpt.h deleted file mode 100644 index 8d95fe4b554e..000000000000 --- a/arch/powerpc/platforms/iseries/call_hpt.h +++ /dev/null | |||
@@ -1,102 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001 Mike Corrigan IBM Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | #ifndef _PLATFORMS_ISERIES_CALL_HPT_H | ||
19 | #define _PLATFORMS_ISERIES_CALL_HPT_H | ||
20 | |||
21 | /* | ||
22 | * This file contains the "hypervisor call" interface which is used to | ||
23 | * drive the hypervisor from the OS. | ||
24 | */ | ||
25 | |||
26 | #include <asm/iseries/hv_call_sc.h> | ||
27 | #include <asm/iseries/hv_types.h> | ||
28 | #include <asm/mmu.h> | ||
29 | |||
30 | #define HvCallHptGetHptAddress HvCallHpt + 0 | ||
31 | #define HvCallHptGetHptPages HvCallHpt + 1 | ||
32 | #define HvCallHptSetPp HvCallHpt + 5 | ||
33 | #define HvCallHptSetSwBits HvCallHpt + 6 | ||
34 | #define HvCallHptUpdate HvCallHpt + 7 | ||
35 | #define HvCallHptInvalidateNoSyncICache HvCallHpt + 8 | ||
36 | #define HvCallHptGet HvCallHpt + 11 | ||
37 | #define HvCallHptFindNextValid HvCallHpt + 12 | ||
38 | #define HvCallHptFindValid HvCallHpt + 13 | ||
39 | #define HvCallHptAddValidate HvCallHpt + 16 | ||
40 | #define HvCallHptInvalidateSetSwBitsGet HvCallHpt + 18 | ||
41 | |||
42 | |||
43 | static inline u64 HvCallHpt_getHptAddress(void) | ||
44 | { | ||
45 | return HvCall0(HvCallHptGetHptAddress); | ||
46 | } | ||
47 | |||
48 | static inline u64 HvCallHpt_getHptPages(void) | ||
49 | { | ||
50 | return HvCall0(HvCallHptGetHptPages); | ||
51 | } | ||
52 | |||
53 | static inline void HvCallHpt_setPp(u32 hpteIndex, u8 value) | ||
54 | { | ||
55 | HvCall2(HvCallHptSetPp, hpteIndex, value); | ||
56 | } | ||
57 | |||
58 | static inline void HvCallHpt_setSwBits(u32 hpteIndex, u8 bitson, u8 bitsoff) | ||
59 | { | ||
60 | HvCall3(HvCallHptSetSwBits, hpteIndex, bitson, bitsoff); | ||
61 | } | ||
62 | |||
63 | static inline void HvCallHpt_invalidateNoSyncICache(u32 hpteIndex) | ||
64 | { | ||
65 | HvCall1(HvCallHptInvalidateNoSyncICache, hpteIndex); | ||
66 | } | ||
67 | |||
68 | static inline u64 HvCallHpt_invalidateSetSwBitsGet(u32 hpteIndex, u8 bitson, | ||
69 | u8 bitsoff) | ||
70 | { | ||
71 | u64 compressedStatus; | ||
72 | |||
73 | compressedStatus = HvCall4(HvCallHptInvalidateSetSwBitsGet, | ||
74 | hpteIndex, bitson, bitsoff, 1); | ||
75 | HvCall1(HvCallHptInvalidateNoSyncICache, hpteIndex); | ||
76 | return compressedStatus; | ||
77 | } | ||
78 | |||
79 | static inline u64 HvCallHpt_findValid(struct hash_pte *hpte, u64 vpn) | ||
80 | { | ||
81 | return HvCall3Ret16(HvCallHptFindValid, hpte, vpn, 0, 0); | ||
82 | } | ||
83 | |||
84 | static inline u64 HvCallHpt_findNextValid(struct hash_pte *hpte, u32 hpteIndex, | ||
85 | u8 bitson, u8 bitsoff) | ||
86 | { | ||
87 | return HvCall3Ret16(HvCallHptFindNextValid, hpte, hpteIndex, | ||
88 | bitson, bitsoff); | ||
89 | } | ||
90 | |||
91 | static inline void HvCallHpt_get(struct hash_pte *hpte, u32 hpteIndex) | ||
92 | { | ||
93 | HvCall2Ret16(HvCallHptGet, hpte, hpteIndex, 0); | ||
94 | } | ||
95 | |||
96 | static inline void HvCallHpt_addValidate(u32 hpteIndex, u32 hBit, | ||
97 | struct hash_pte *hpte) | ||
98 | { | ||
99 | HvCall4(HvCallHptAddValidate, hpteIndex, hBit, hpte->v, hpte->r); | ||
100 | } | ||
101 | |||
102 | #endif /* _PLATFORMS_ISERIES_CALL_HPT_H */ | ||
diff --git a/arch/powerpc/platforms/iseries/call_pci.h b/arch/powerpc/platforms/iseries/call_pci.h deleted file mode 100644 index dbdf69850ed9..000000000000 --- a/arch/powerpc/platforms/iseries/call_pci.h +++ /dev/null | |||
@@ -1,309 +0,0 @@ | |||
1 | /* | ||
2 | * Provides the Hypervisor PCI calls for iSeries Linux Parition. | ||
3 | * Copyright (C) 2001 <Wayne G Holm> <IBM Corporation> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the: | ||
17 | * Free Software Foundation, Inc., | ||
18 | * 59 Temple Place, Suite 330, | ||
19 | * Boston, MA 02111-1307 USA | ||
20 | * | ||
21 | * Change Activity: | ||
22 | * Created, Jan 9, 2001 | ||
23 | */ | ||
24 | |||
25 | #ifndef _PLATFORMS_ISERIES_CALL_PCI_H | ||
26 | #define _PLATFORMS_ISERIES_CALL_PCI_H | ||
27 | |||
28 | #include <asm/iseries/hv_call_sc.h> | ||
29 | #include <asm/iseries/hv_types.h> | ||
30 | |||
31 | /* | ||
32 | * DSA == Direct Select Address | ||
33 | * this struct must be 64 bits in total | ||
34 | */ | ||
35 | struct HvCallPci_DsaAddr { | ||
36 | u16 busNumber; /* PHB index? */ | ||
37 | u8 subBusNumber; /* PCI bus number? */ | ||
38 | u8 deviceId; /* device and function? */ | ||
39 | u8 barNumber; | ||
40 | u8 reserved[3]; | ||
41 | }; | ||
42 | |||
43 | union HvDsaMap { | ||
44 | u64 DsaAddr; | ||
45 | struct HvCallPci_DsaAddr Dsa; | ||
46 | }; | ||
47 | |||
48 | struct HvCallPci_LoadReturn { | ||
49 | u64 rc; | ||
50 | u64 value; | ||
51 | }; | ||
52 | |||
53 | enum HvCallPci_DeviceType { | ||
54 | HvCallPci_NodeDevice = 1, | ||
55 | HvCallPci_SpDevice = 2, | ||
56 | HvCallPci_IopDevice = 3, | ||
57 | HvCallPci_BridgeDevice = 4, | ||
58 | HvCallPci_MultiFunctionDevice = 5, | ||
59 | HvCallPci_IoaDevice = 6 | ||
60 | }; | ||
61 | |||
62 | |||
63 | struct HvCallPci_DeviceInfo { | ||
64 | u32 deviceType; /* See DeviceType enum for values */ | ||
65 | }; | ||
66 | |||
67 | struct HvCallPci_BusUnitInfo { | ||
68 | u32 sizeReturned; /* length of data returned */ | ||
69 | u32 deviceType; /* see DeviceType enum for values */ | ||
70 | }; | ||
71 | |||
72 | struct HvCallPci_BridgeInfo { | ||
73 | struct HvCallPci_BusUnitInfo busUnitInfo; /* Generic bus unit info */ | ||
74 | u8 subBusNumber; /* Bus number of secondary bus */ | ||
75 | u8 maxAgents; /* Max idsels on secondary bus */ | ||
76 | u8 maxSubBusNumber; /* Max Sub Bus */ | ||
77 | u8 logicalSlotNumber; /* Logical Slot Number for IOA */ | ||
78 | }; | ||
79 | |||
80 | |||
81 | /* | ||
82 | * Maximum BusUnitInfo buffer size. Provided for clients so | ||
83 | * they can allocate a buffer big enough for any type of bus | ||
84 | * unit. Increase as needed. | ||
85 | */ | ||
86 | enum {HvCallPci_MaxBusUnitInfoSize = 128}; | ||
87 | |||
88 | struct HvCallPci_BarParms { | ||
89 | u64 vaddr; | ||
90 | u64 raddr; | ||
91 | u64 size; | ||
92 | u64 protectStart; | ||
93 | u64 protectEnd; | ||
94 | u64 relocationOffset; | ||
95 | u64 pciAddress; | ||
96 | u64 reserved[3]; | ||
97 | }; | ||
98 | |||
99 | enum HvCallPci_VpdType { | ||
100 | HvCallPci_BusVpd = 1, | ||
101 | HvCallPci_BusAdapterVpd = 2 | ||
102 | }; | ||
103 | |||
104 | #define HvCallPciConfigLoad8 HvCallPci + 0 | ||
105 | #define HvCallPciConfigLoad16 HvCallPci + 1 | ||
106 | #define HvCallPciConfigLoad32 HvCallPci + 2 | ||
107 | #define HvCallPciConfigStore8 HvCallPci + 3 | ||
108 | #define HvCallPciConfigStore16 HvCallPci + 4 | ||
109 | #define HvCallPciConfigStore32 HvCallPci + 5 | ||
110 | #define HvCallPciEoi HvCallPci + 16 | ||
111 | #define HvCallPciGetBarParms HvCallPci + 18 | ||
112 | #define HvCallPciMaskFisr HvCallPci + 20 | ||
113 | #define HvCallPciUnmaskFisr HvCallPci + 21 | ||
114 | #define HvCallPciSetSlotReset HvCallPci + 25 | ||
115 | #define HvCallPciGetDeviceInfo HvCallPci + 27 | ||
116 | #define HvCallPciGetCardVpd HvCallPci + 28 | ||
117 | #define HvCallPciBarLoad8 HvCallPci + 40 | ||
118 | #define HvCallPciBarLoad16 HvCallPci + 41 | ||
119 | #define HvCallPciBarLoad32 HvCallPci + 42 | ||
120 | #define HvCallPciBarLoad64 HvCallPci + 43 | ||
121 | #define HvCallPciBarStore8 HvCallPci + 44 | ||
122 | #define HvCallPciBarStore16 HvCallPci + 45 | ||
123 | #define HvCallPciBarStore32 HvCallPci + 46 | ||
124 | #define HvCallPciBarStore64 HvCallPci + 47 | ||
125 | #define HvCallPciMaskInterrupts HvCallPci + 48 | ||
126 | #define HvCallPciUnmaskInterrupts HvCallPci + 49 | ||
127 | #define HvCallPciGetBusUnitInfo HvCallPci + 50 | ||
128 | |||
129 | static inline u64 HvCallPci_configLoad16(u16 busNumber, u8 subBusNumber, | ||
130 | u8 deviceId, u32 offset, u16 *value) | ||
131 | { | ||
132 | struct HvCallPci_DsaAddr dsa; | ||
133 | struct HvCallPci_LoadReturn retVal; | ||
134 | |||
135 | *((u64*)&dsa) = 0; | ||
136 | |||
137 | dsa.busNumber = busNumber; | ||
138 | dsa.subBusNumber = subBusNumber; | ||
139 | dsa.deviceId = deviceId; | ||
140 | |||
141 | HvCall3Ret16(HvCallPciConfigLoad16, &retVal, *(u64 *)&dsa, offset, 0); | ||
142 | |||
143 | *value = retVal.value; | ||
144 | |||
145 | return retVal.rc; | ||
146 | } | ||
147 | |||
148 | static inline u64 HvCallPci_configLoad32(u16 busNumber, u8 subBusNumber, | ||
149 | u8 deviceId, u32 offset, u32 *value) | ||
150 | { | ||
151 | struct HvCallPci_DsaAddr dsa; | ||
152 | struct HvCallPci_LoadReturn retVal; | ||
153 | |||
154 | *((u64*)&dsa) = 0; | ||
155 | |||
156 | dsa.busNumber = busNumber; | ||
157 | dsa.subBusNumber = subBusNumber; | ||
158 | dsa.deviceId = deviceId; | ||
159 | |||
160 | HvCall3Ret16(HvCallPciConfigLoad32, &retVal, *(u64 *)&dsa, offset, 0); | ||
161 | |||
162 | *value = retVal.value; | ||
163 | |||
164 | return retVal.rc; | ||
165 | } | ||
166 | |||
167 | static inline u64 HvCallPci_configStore8(u16 busNumber, u8 subBusNumber, | ||
168 | u8 deviceId, u32 offset, u8 value) | ||
169 | { | ||
170 | struct HvCallPci_DsaAddr dsa; | ||
171 | |||
172 | *((u64*)&dsa) = 0; | ||
173 | |||
174 | dsa.busNumber = busNumber; | ||
175 | dsa.subBusNumber = subBusNumber; | ||
176 | dsa.deviceId = deviceId; | ||
177 | |||
178 | return HvCall4(HvCallPciConfigStore8, *(u64 *)&dsa, offset, value, 0); | ||
179 | } | ||
180 | |||
181 | static inline u64 HvCallPci_eoi(u16 busNumberParm, u8 subBusParm, | ||
182 | u8 deviceIdParm) | ||
183 | { | ||
184 | struct HvCallPci_DsaAddr dsa; | ||
185 | struct HvCallPci_LoadReturn retVal; | ||
186 | |||
187 | *((u64*)&dsa) = 0; | ||
188 | |||
189 | dsa.busNumber = busNumberParm; | ||
190 | dsa.subBusNumber = subBusParm; | ||
191 | dsa.deviceId = deviceIdParm; | ||
192 | |||
193 | HvCall1Ret16(HvCallPciEoi, &retVal, *(u64*)&dsa); | ||
194 | |||
195 | return retVal.rc; | ||
196 | } | ||
197 | |||
198 | static inline u64 HvCallPci_getBarParms(u16 busNumberParm, u8 subBusParm, | ||
199 | u8 deviceIdParm, u8 barNumberParm, u64 parms, u32 sizeofParms) | ||
200 | { | ||
201 | struct HvCallPci_DsaAddr dsa; | ||
202 | |||
203 | *((u64*)&dsa) = 0; | ||
204 | |||
205 | dsa.busNumber = busNumberParm; | ||
206 | dsa.subBusNumber = subBusParm; | ||
207 | dsa.deviceId = deviceIdParm; | ||
208 | dsa.barNumber = barNumberParm; | ||
209 | |||
210 | return HvCall3(HvCallPciGetBarParms, *(u64*)&dsa, parms, sizeofParms); | ||
211 | } | ||
212 | |||
213 | static inline u64 HvCallPci_maskFisr(u16 busNumberParm, u8 subBusParm, | ||
214 | u8 deviceIdParm, u64 fisrMask) | ||
215 | { | ||
216 | struct HvCallPci_DsaAddr dsa; | ||
217 | |||
218 | *((u64*)&dsa) = 0; | ||
219 | |||
220 | dsa.busNumber = busNumberParm; | ||
221 | dsa.subBusNumber = subBusParm; | ||
222 | dsa.deviceId = deviceIdParm; | ||
223 | |||
224 | return HvCall2(HvCallPciMaskFisr, *(u64*)&dsa, fisrMask); | ||
225 | } | ||
226 | |||
227 | static inline u64 HvCallPci_unmaskFisr(u16 busNumberParm, u8 subBusParm, | ||
228 | u8 deviceIdParm, u64 fisrMask) | ||
229 | { | ||
230 | struct HvCallPci_DsaAddr dsa; | ||
231 | |||
232 | *((u64*)&dsa) = 0; | ||
233 | |||
234 | dsa.busNumber = busNumberParm; | ||
235 | dsa.subBusNumber = subBusParm; | ||
236 | dsa.deviceId = deviceIdParm; | ||
237 | |||
238 | return HvCall2(HvCallPciUnmaskFisr, *(u64*)&dsa, fisrMask); | ||
239 | } | ||
240 | |||
241 | static inline u64 HvCallPci_getDeviceInfo(u16 busNumberParm, u8 subBusParm, | ||
242 | u8 deviceNumberParm, u64 parms, u32 sizeofParms) | ||
243 | { | ||
244 | struct HvCallPci_DsaAddr dsa; | ||
245 | |||
246 | *((u64*)&dsa) = 0; | ||
247 | |||
248 | dsa.busNumber = busNumberParm; | ||
249 | dsa.subBusNumber = subBusParm; | ||
250 | dsa.deviceId = deviceNumberParm << 4; | ||
251 | |||
252 | return HvCall3(HvCallPciGetDeviceInfo, *(u64*)&dsa, parms, sizeofParms); | ||
253 | } | ||
254 | |||
255 | static inline u64 HvCallPci_maskInterrupts(u16 busNumberParm, u8 subBusParm, | ||
256 | u8 deviceIdParm, u64 interruptMask) | ||
257 | { | ||
258 | struct HvCallPci_DsaAddr dsa; | ||
259 | |||
260 | *((u64*)&dsa) = 0; | ||
261 | |||
262 | dsa.busNumber = busNumberParm; | ||
263 | dsa.subBusNumber = subBusParm; | ||
264 | dsa.deviceId = deviceIdParm; | ||
265 | |||
266 | return HvCall2(HvCallPciMaskInterrupts, *(u64*)&dsa, interruptMask); | ||
267 | } | ||
268 | |||
269 | static inline u64 HvCallPci_unmaskInterrupts(u16 busNumberParm, u8 subBusParm, | ||
270 | u8 deviceIdParm, u64 interruptMask) | ||
271 | { | ||
272 | struct HvCallPci_DsaAddr dsa; | ||
273 | |||
274 | *((u64*)&dsa) = 0; | ||
275 | |||
276 | dsa.busNumber = busNumberParm; | ||
277 | dsa.subBusNumber = subBusParm; | ||
278 | dsa.deviceId = deviceIdParm; | ||
279 | |||
280 | return HvCall2(HvCallPciUnmaskInterrupts, *(u64*)&dsa, interruptMask); | ||
281 | } | ||
282 | |||
283 | static inline u64 HvCallPci_getBusUnitInfo(u16 busNumberParm, u8 subBusParm, | ||
284 | u8 deviceIdParm, u64 parms, u32 sizeofParms) | ||
285 | { | ||
286 | struct HvCallPci_DsaAddr dsa; | ||
287 | |||
288 | *((u64*)&dsa) = 0; | ||
289 | |||
290 | dsa.busNumber = busNumberParm; | ||
291 | dsa.subBusNumber = subBusParm; | ||
292 | dsa.deviceId = deviceIdParm; | ||
293 | |||
294 | return HvCall3(HvCallPciGetBusUnitInfo, *(u64*)&dsa, parms, | ||
295 | sizeofParms); | ||
296 | } | ||
297 | |||
298 | static inline int HvCallPci_getBusVpd(u16 busNumParm, u64 destParm, | ||
299 | u16 sizeParm) | ||
300 | { | ||
301 | u64 xRc = HvCall4(HvCallPciGetCardVpd, busNumParm, destParm, | ||
302 | sizeParm, HvCallPci_BusVpd); | ||
303 | if (xRc == -1) | ||
304 | return -1; | ||
305 | else | ||
306 | return xRc & 0xFFFF; | ||
307 | } | ||
308 | |||
309 | #endif /* _PLATFORMS_ISERIES_CALL_PCI_H */ | ||
diff --git a/arch/powerpc/platforms/iseries/call_sm.h b/arch/powerpc/platforms/iseries/call_sm.h deleted file mode 100644 index c7e251619f48..000000000000 --- a/arch/powerpc/platforms/iseries/call_sm.h +++ /dev/null | |||
@@ -1,37 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001 Mike Corrigan IBM Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | #ifndef _ISERIES_CALL_SM_H | ||
19 | #define _ISERIES_CALL_SM_H | ||
20 | |||
21 | /* | ||
22 | * This file contains the "hypervisor call" interface which is used to | ||
23 | * drive the hypervisor from the OS. | ||
24 | */ | ||
25 | |||
26 | #include <asm/iseries/hv_call_sc.h> | ||
27 | #include <asm/iseries/hv_types.h> | ||
28 | |||
29 | #define HvCallSmGet64BitsOfAccessMap HvCallSm + 11 | ||
30 | |||
31 | static inline u64 HvCallSm_get64BitsOfAccessMap(HvLpIndex lpIndex, | ||
32 | u64 indexIntoBitMap) | ||
33 | { | ||
34 | return HvCall2(HvCallSmGet64BitsOfAccessMap, lpIndex, indexIntoBitMap); | ||
35 | } | ||
36 | |||
37 | #endif /* _ISERIES_CALL_SM_H */ | ||
diff --git a/arch/powerpc/platforms/iseries/dt.c b/arch/powerpc/platforms/iseries/dt.c deleted file mode 100644 index f0491cc28900..000000000000 --- a/arch/powerpc/platforms/iseries/dt.c +++ /dev/null | |||
@@ -1,643 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005-2006 Michael Ellerman, IBM Corporation | ||
3 | * Copyright (C) 2000-2004, IBM Corporation | ||
4 | * | ||
5 | * Description: | ||
6 | * This file contains all the routines to build a flattened device | ||
7 | * tree for a legacy iSeries machine. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * as published by the Free Software Foundation; either version | ||
12 | * 2 of the License, or (at your option) any later version. | ||
13 | */ | ||
14 | |||
15 | #undef DEBUG | ||
16 | |||
17 | #include <linux/types.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/pci.h> | ||
20 | #include <linux/pci_regs.h> | ||
21 | #include <linux/pci_ids.h> | ||
22 | #include <linux/threads.h> | ||
23 | #include <linux/bitops.h> | ||
24 | #include <linux/string.h> | ||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/if_ether.h> /* ETH_ALEN */ | ||
27 | |||
28 | #include <asm/machdep.h> | ||
29 | #include <asm/prom.h> | ||
30 | #include <asm/lppaca.h> | ||
31 | #include <asm/cputable.h> | ||
32 | #include <asm/abs_addr.h> | ||
33 | #include <asm/system.h> | ||
34 | #include <asm/iseries/hv_types.h> | ||
35 | #include <asm/iseries/hv_lp_config.h> | ||
36 | #include <asm/iseries/hv_call_xm.h> | ||
37 | #include <asm/udbg.h> | ||
38 | |||
39 | #include "processor_vpd.h" | ||
40 | #include "call_hpt.h" | ||
41 | #include "call_pci.h" | ||
42 | #include "pci.h" | ||
43 | #include "it_exp_vpd_panel.h" | ||
44 | #include "naca.h" | ||
45 | |||
46 | #ifdef DEBUG | ||
47 | #define DBG(fmt...) udbg_printf(fmt) | ||
48 | #else | ||
49 | #define DBG(fmt...) | ||
50 | #endif | ||
51 | |||
52 | /* | ||
53 | * These are created by the linker script at the start and end | ||
54 | * of the section containing all the strings marked with the DS macro. | ||
55 | */ | ||
56 | extern char __dt_strings_start[]; | ||
57 | extern char __dt_strings_end[]; | ||
58 | |||
59 | #define DS(s) ({ \ | ||
60 | static const char __s[] __attribute__((section(".dt_strings"))) = s; \ | ||
61 | __s; \ | ||
62 | }) | ||
63 | |||
64 | struct iseries_flat_dt { | ||
65 | struct boot_param_header header; | ||
66 | u64 reserve_map[2]; | ||
67 | }; | ||
68 | |||
69 | static void * __initdata dt_data; | ||
70 | |||
71 | /* | ||
72 | * Putting these strings here keeps them out of the .dt_strings section | ||
73 | * that we capture for the strings blob of the flattened device tree. | ||
74 | */ | ||
75 | static char __initdata device_type_cpu[] = "cpu"; | ||
76 | static char __initdata device_type_memory[] = "memory"; | ||
77 | static char __initdata device_type_serial[] = "serial"; | ||
78 | static char __initdata device_type_network[] = "network"; | ||
79 | static char __initdata device_type_pci[] = "pci"; | ||
80 | static char __initdata device_type_vdevice[] = "vdevice"; | ||
81 | static char __initdata device_type_vscsi[] = "vscsi"; | ||
82 | |||
83 | |||
84 | /* EBCDIC to ASCII conversion routines */ | ||
85 | |||
86 | static unsigned char __init e2a(unsigned char x) | ||
87 | { | ||
88 | switch (x) { | ||
89 | case 0x81 ... 0x89: | ||
90 | return x - 0x81 + 'a'; | ||
91 | case 0x91 ... 0x99: | ||
92 | return x - 0x91 + 'j'; | ||
93 | case 0xA2 ... 0xA9: | ||
94 | return x - 0xA2 + 's'; | ||
95 | case 0xC1 ... 0xC9: | ||
96 | return x - 0xC1 + 'A'; | ||
97 | case 0xD1 ... 0xD9: | ||
98 | return x - 0xD1 + 'J'; | ||
99 | case 0xE2 ... 0xE9: | ||
100 | return x - 0xE2 + 'S'; | ||
101 | case 0xF0 ... 0xF9: | ||
102 | return x - 0xF0 + '0'; | ||
103 | } | ||
104 | return ' '; | ||
105 | } | ||
106 | |||
107 | static unsigned char * __init strne2a(unsigned char *dest, | ||
108 | const unsigned char *src, size_t n) | ||
109 | { | ||
110 | int i; | ||
111 | |||
112 | n = strnlen(src, n); | ||
113 | |||
114 | for (i = 0; i < n; i++) | ||
115 | dest[i] = e2a(src[i]); | ||
116 | |||
117 | return dest; | ||
118 | } | ||
119 | |||
120 | static struct iseries_flat_dt * __init dt_init(void) | ||
121 | { | ||
122 | struct iseries_flat_dt *dt; | ||
123 | unsigned long str_len; | ||
124 | |||
125 | str_len = __dt_strings_end - __dt_strings_start; | ||
126 | dt = (struct iseries_flat_dt *)ALIGN(klimit, 8); | ||
127 | dt->header.off_mem_rsvmap = | ||
128 | offsetof(struct iseries_flat_dt, reserve_map); | ||
129 | dt->header.off_dt_strings = ALIGN(sizeof(*dt), 8); | ||
130 | dt->header.off_dt_struct = dt->header.off_dt_strings | ||
131 | + ALIGN(str_len, 8); | ||
132 | dt_data = (void *)((unsigned long)dt + dt->header.off_dt_struct); | ||
133 | dt->header.dt_strings_size = str_len; | ||
134 | |||
135 | /* There is no notion of hardware cpu id on iSeries */ | ||
136 | dt->header.boot_cpuid_phys = smp_processor_id(); | ||
137 | |||
138 | memcpy((char *)dt + dt->header.off_dt_strings, __dt_strings_start, | ||
139 | str_len); | ||
140 | |||
141 | dt->header.magic = OF_DT_HEADER; | ||
142 | dt->header.version = 0x10; | ||
143 | dt->header.last_comp_version = 0x10; | ||
144 | |||
145 | dt->reserve_map[0] = 0; | ||
146 | dt->reserve_map[1] = 0; | ||
147 | |||
148 | return dt; | ||
149 | } | ||
150 | |||
151 | static void __init dt_push_u32(struct iseries_flat_dt *dt, u32 value) | ||
152 | { | ||
153 | *((u32 *)dt_data) = value; | ||
154 | dt_data += sizeof(u32); | ||
155 | } | ||
156 | |||
157 | #ifdef notyet | ||
158 | static void __init dt_push_u64(struct iseries_flat_dt *dt, u64 value) | ||
159 | { | ||
160 | *((u64 *)dt_data) = value; | ||
161 | dt_data += sizeof(u64); | ||
162 | } | ||
163 | #endif | ||
164 | |||
165 | static void __init dt_push_bytes(struct iseries_flat_dt *dt, const char *data, | ||
166 | int len) | ||
167 | { | ||
168 | memcpy(dt_data, data, len); | ||
169 | dt_data += ALIGN(len, 4); | ||
170 | } | ||
171 | |||
172 | static void __init dt_start_node(struct iseries_flat_dt *dt, const char *name) | ||
173 | { | ||
174 | dt_push_u32(dt, OF_DT_BEGIN_NODE); | ||
175 | dt_push_bytes(dt, name, strlen(name) + 1); | ||
176 | } | ||
177 | |||
178 | #define dt_end_node(dt) dt_push_u32(dt, OF_DT_END_NODE) | ||
179 | |||
180 | static void __init __dt_prop(struct iseries_flat_dt *dt, const char *name, | ||
181 | const void *data, int len) | ||
182 | { | ||
183 | unsigned long offset; | ||
184 | |||
185 | dt_push_u32(dt, OF_DT_PROP); | ||
186 | |||
187 | /* Length of the data */ | ||
188 | dt_push_u32(dt, len); | ||
189 | |||
190 | offset = name - __dt_strings_start; | ||
191 | |||
192 | /* The offset of the properties name in the string blob. */ | ||
193 | dt_push_u32(dt, (u32)offset); | ||
194 | |||
195 | /* The actual data. */ | ||
196 | dt_push_bytes(dt, data, len); | ||
197 | } | ||
198 | #define dt_prop(dt, name, data, len) __dt_prop((dt), DS(name), (data), (len)) | ||
199 | |||
200 | #define dt_prop_str(dt, name, data) \ | ||
201 | dt_prop((dt), name, (data), strlen((data)) + 1); /* + 1 for NULL */ | ||
202 | |||
203 | static void __init __dt_prop_u32(struct iseries_flat_dt *dt, const char *name, | ||
204 | u32 data) | ||
205 | { | ||
206 | __dt_prop(dt, name, &data, sizeof(u32)); | ||
207 | } | ||
208 | #define dt_prop_u32(dt, name, data) __dt_prop_u32((dt), DS(name), (data)) | ||
209 | |||
210 | static void __init __maybe_unused __dt_prop_u64(struct iseries_flat_dt *dt, | ||
211 | const char *name, u64 data) | ||
212 | { | ||
213 | __dt_prop(dt, name, &data, sizeof(u64)); | ||
214 | } | ||
215 | #define dt_prop_u64(dt, name, data) __dt_prop_u64((dt), DS(name), (data)) | ||
216 | |||
217 | #define dt_prop_u64_list(dt, name, data, n) \ | ||
218 | dt_prop((dt), name, (data), sizeof(u64) * (n)) | ||
219 | |||
220 | #define dt_prop_u32_list(dt, name, data, n) \ | ||
221 | dt_prop((dt), name, (data), sizeof(u32) * (n)) | ||
222 | |||
223 | #define dt_prop_empty(dt, name) dt_prop((dt), name, NULL, 0) | ||
224 | |||
225 | static void __init dt_cpus(struct iseries_flat_dt *dt) | ||
226 | { | ||
227 | unsigned char buf[32]; | ||
228 | unsigned char *p; | ||
229 | unsigned int i, index; | ||
230 | struct IoHriProcessorVpd *d; | ||
231 | u32 pft_size[2]; | ||
232 | |||
233 | /* yuck */ | ||
234 | snprintf(buf, 32, "PowerPC,%s", cur_cpu_spec->cpu_name); | ||
235 | p = strchr(buf, ' '); | ||
236 | if (!p) p = buf + strlen(buf); | ||
237 | |||
238 | dt_start_node(dt, "cpus"); | ||
239 | dt_prop_u32(dt, "#address-cells", 1); | ||
240 | dt_prop_u32(dt, "#size-cells", 0); | ||
241 | |||
242 | pft_size[0] = 0; /* NUMA CEC cookie, 0 for non NUMA */ | ||
243 | pft_size[1] = __ilog2(HvCallHpt_getHptPages() * HW_PAGE_SIZE); | ||
244 | |||
245 | for (i = 0; i < NR_LPPACAS; i++) { | ||
246 | if (lppaca[i].dyn_proc_status >= 2) | ||
247 | continue; | ||
248 | |||
249 | snprintf(p, 32 - (p - buf), "@%d", i); | ||
250 | dt_start_node(dt, buf); | ||
251 | |||
252 | dt_prop_str(dt, "device_type", device_type_cpu); | ||
253 | |||
254 | index = lppaca[i].dyn_hv_phys_proc_index; | ||
255 | d = &xIoHriProcessorVpd[index]; | ||
256 | |||
257 | dt_prop_u32(dt, "i-cache-size", d->xInstCacheSize * 1024); | ||
258 | dt_prop_u32(dt, "i-cache-line-size", d->xInstCacheOperandSize); | ||
259 | |||
260 | dt_prop_u32(dt, "d-cache-size", d->xDataL1CacheSizeKB * 1024); | ||
261 | dt_prop_u32(dt, "d-cache-line-size", d->xDataCacheOperandSize); | ||
262 | |||
263 | /* magic conversions to Hz copied from old code */ | ||
264 | dt_prop_u32(dt, "clock-frequency", | ||
265 | ((1UL << 34) * 1000000) / d->xProcFreq); | ||
266 | dt_prop_u32(dt, "timebase-frequency", | ||
267 | ((1UL << 32) * 1000000) / d->xTimeBaseFreq); | ||
268 | |||
269 | dt_prop_u32(dt, "reg", i); | ||
270 | |||
271 | dt_prop_u32_list(dt, "ibm,pft-size", pft_size, 2); | ||
272 | |||
273 | dt_end_node(dt); | ||
274 | } | ||
275 | |||
276 | dt_end_node(dt); | ||
277 | } | ||
278 | |||
279 | static void __init dt_model(struct iseries_flat_dt *dt) | ||
280 | { | ||
281 | char buf[16] = "IBM,"; | ||
282 | |||
283 | /* N.B. lparcfg.c knows about the "IBM," prefixes ... */ | ||
284 | /* "IBM," + mfgId[2:3] + systemSerial[1:5] */ | ||
285 | strne2a(buf + 4, xItExtVpdPanel.mfgID + 2, 2); | ||
286 | strne2a(buf + 6, xItExtVpdPanel.systemSerial + 1, 5); | ||
287 | buf[11] = '\0'; | ||
288 | dt_prop_str(dt, "system-id", buf); | ||
289 | |||
290 | /* "IBM," + machineType[0:4] */ | ||
291 | strne2a(buf + 4, xItExtVpdPanel.machineType, 4); | ||
292 | buf[8] = '\0'; | ||
293 | dt_prop_str(dt, "model", buf); | ||
294 | |||
295 | dt_prop_str(dt, "compatible", "IBM,iSeries"); | ||
296 | dt_prop_u32(dt, "ibm,partition-no", HvLpConfig_getLpIndex()); | ||
297 | } | ||
298 | |||
299 | static void __init dt_initrd(struct iseries_flat_dt *dt) | ||
300 | { | ||
301 | #ifdef CONFIG_BLK_DEV_INITRD | ||
302 | if (naca.xRamDisk) { | ||
303 | dt_prop_u64(dt, "linux,initrd-start", (u64)naca.xRamDisk); | ||
304 | dt_prop_u64(dt, "linux,initrd-end", | ||
305 | (u64)naca.xRamDisk + naca.xRamDiskSize * HW_PAGE_SIZE); | ||
306 | } | ||
307 | #endif | ||
308 | } | ||
309 | |||
310 | static void __init dt_do_vdevice(struct iseries_flat_dt *dt, | ||
311 | const char *name, u32 reg, int unit, | ||
312 | const char *type, const char *compat, int end) | ||
313 | { | ||
314 | char buf[32]; | ||
315 | |||
316 | snprintf(buf, 32, "%s@%08x", name, reg + ((unit >= 0) ? unit : 0)); | ||
317 | dt_start_node(dt, buf); | ||
318 | dt_prop_str(dt, "device_type", type); | ||
319 | if (compat) | ||
320 | dt_prop_str(dt, "compatible", compat); | ||
321 | dt_prop_u32(dt, "reg", reg + ((unit >= 0) ? unit : 0)); | ||
322 | if (unit >= 0) | ||
323 | dt_prop_u32(dt, "linux,unit_address", unit); | ||
324 | if (end) | ||
325 | dt_end_node(dt); | ||
326 | } | ||
327 | |||
328 | static void __init dt_vdevices(struct iseries_flat_dt *dt) | ||
329 | { | ||
330 | u32 reg = 0; | ||
331 | HvLpIndexMap vlan_map; | ||
332 | int i; | ||
333 | |||
334 | dt_start_node(dt, "vdevice"); | ||
335 | dt_prop_str(dt, "device_type", device_type_vdevice); | ||
336 | dt_prop_str(dt, "compatible", "IBM,iSeries-vdevice"); | ||
337 | dt_prop_u32(dt, "#address-cells", 1); | ||
338 | dt_prop_u32(dt, "#size-cells", 0); | ||
339 | |||
340 | dt_do_vdevice(dt, "vty", reg, -1, device_type_serial, | ||
341 | "IBM,iSeries-vty", 1); | ||
342 | reg++; | ||
343 | |||
344 | dt_do_vdevice(dt, "v-scsi", reg, -1, device_type_vscsi, | ||
345 | "IBM,v-scsi", 1); | ||
346 | reg++; | ||
347 | |||
348 | vlan_map = HvLpConfig_getVirtualLanIndexMap(); | ||
349 | for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++) { | ||
350 | unsigned char mac_addr[ETH_ALEN]; | ||
351 | |||
352 | if ((vlan_map & (0x8000 >> i)) == 0) | ||
353 | continue; | ||
354 | dt_do_vdevice(dt, "l-lan", reg, i, device_type_network, | ||
355 | "IBM,iSeries-l-lan", 0); | ||
356 | mac_addr[0] = 0x02; | ||
357 | mac_addr[1] = 0x01; | ||
358 | mac_addr[2] = 0xff; | ||
359 | mac_addr[3] = i; | ||
360 | mac_addr[4] = 0xff; | ||
361 | mac_addr[5] = HvLpConfig_getLpIndex_outline(); | ||
362 | dt_prop(dt, "local-mac-address", (char *)mac_addr, ETH_ALEN); | ||
363 | dt_prop(dt, "mac-address", (char *)mac_addr, ETH_ALEN); | ||
364 | dt_prop_u32(dt, "max-frame-size", 9000); | ||
365 | dt_prop_u32(dt, "address-bits", 48); | ||
366 | |||
367 | dt_end_node(dt); | ||
368 | } | ||
369 | |||
370 | dt_end_node(dt); | ||
371 | } | ||
372 | |||
373 | struct pci_class_name { | ||
374 | u16 code; | ||
375 | const char *name; | ||
376 | const char *type; | ||
377 | }; | ||
378 | |||
379 | static struct pci_class_name __initdata pci_class_name[] = { | ||
380 | { PCI_CLASS_NETWORK_ETHERNET, "ethernet", device_type_network }, | ||
381 | }; | ||
382 | |||
383 | static struct pci_class_name * __init dt_find_pci_class_name(u16 class_code) | ||
384 | { | ||
385 | struct pci_class_name *cp; | ||
386 | |||
387 | for (cp = pci_class_name; | ||
388 | cp < &pci_class_name[ARRAY_SIZE(pci_class_name)]; cp++) | ||
389 | if (cp->code == class_code) | ||
390 | return cp; | ||
391 | return NULL; | ||
392 | } | ||
393 | |||
394 | /* | ||
395 | * This assumes that the node slot is always on the primary bus! | ||
396 | */ | ||
397 | static void __init scan_bridge_slot(struct iseries_flat_dt *dt, | ||
398 | HvBusNumber bus, struct HvCallPci_BridgeInfo *bridge_info) | ||
399 | { | ||
400 | HvSubBusNumber sub_bus = bridge_info->subBusNumber; | ||
401 | u16 vendor_id; | ||
402 | u16 device_id; | ||
403 | u32 class_id; | ||
404 | int err; | ||
405 | char buf[32]; | ||
406 | u32 reg[5]; | ||
407 | int id_sel = ISERIES_GET_DEVICE_FROM_SUBBUS(sub_bus); | ||
408 | int function = ISERIES_GET_FUNCTION_FROM_SUBBUS(sub_bus); | ||
409 | HvAgentId eads_id_sel = ISERIES_PCI_AGENTID(id_sel, function); | ||
410 | u8 devfn; | ||
411 | struct pci_class_name *cp; | ||
412 | |||
413 | /* | ||
414 | * Connect all functions of any device found. | ||
415 | */ | ||
416 | for (id_sel = 1; id_sel <= bridge_info->maxAgents; id_sel++) { | ||
417 | for (function = 0; function < 8; function++) { | ||
418 | HvAgentId agent_id = ISERIES_PCI_AGENTID(id_sel, | ||
419 | function); | ||
420 | err = HvCallXm_connectBusUnit(bus, sub_bus, | ||
421 | agent_id, 0); | ||
422 | if (err) { | ||
423 | if (err != 0x302) | ||
424 | DBG("connectBusUnit(%x, %x, %x) %x\n", | ||
425 | bus, sub_bus, agent_id, err); | ||
426 | continue; | ||
427 | } | ||
428 | |||
429 | err = HvCallPci_configLoad16(bus, sub_bus, agent_id, | ||
430 | PCI_VENDOR_ID, &vendor_id); | ||
431 | if (err) { | ||
432 | DBG("ReadVendor(%x, %x, %x) %x\n", | ||
433 | bus, sub_bus, agent_id, err); | ||
434 | continue; | ||
435 | } | ||
436 | err = HvCallPci_configLoad16(bus, sub_bus, agent_id, | ||
437 | PCI_DEVICE_ID, &device_id); | ||
438 | if (err) { | ||
439 | DBG("ReadDevice(%x, %x, %x) %x\n", | ||
440 | bus, sub_bus, agent_id, err); | ||
441 | continue; | ||
442 | } | ||
443 | err = HvCallPci_configLoad32(bus, sub_bus, agent_id, | ||
444 | PCI_CLASS_REVISION , &class_id); | ||
445 | if (err) { | ||
446 | DBG("ReadClass(%x, %x, %x) %x\n", | ||
447 | bus, sub_bus, agent_id, err); | ||
448 | continue; | ||
449 | } | ||
450 | |||
451 | devfn = PCI_DEVFN(ISERIES_ENCODE_DEVICE(eads_id_sel), | ||
452 | function); | ||
453 | cp = dt_find_pci_class_name(class_id >> 16); | ||
454 | if (cp && cp->name) | ||
455 | strncpy(buf, cp->name, sizeof(buf) - 1); | ||
456 | else | ||
457 | snprintf(buf, sizeof(buf), "pci%x,%x", | ||
458 | vendor_id, device_id); | ||
459 | buf[sizeof(buf) - 1] = '\0'; | ||
460 | snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), | ||
461 | "@%x", PCI_SLOT(devfn)); | ||
462 | buf[sizeof(buf) - 1] = '\0'; | ||
463 | if (function != 0) | ||
464 | snprintf(buf + strlen(buf), | ||
465 | sizeof(buf) - strlen(buf), | ||
466 | ",%x", function); | ||
467 | dt_start_node(dt, buf); | ||
468 | reg[0] = (bus << 16) | (devfn << 8); | ||
469 | reg[1] = 0; | ||
470 | reg[2] = 0; | ||
471 | reg[3] = 0; | ||
472 | reg[4] = 0; | ||
473 | dt_prop_u32_list(dt, "reg", reg, 5); | ||
474 | if (cp && (cp->type || cp->name)) | ||
475 | dt_prop_str(dt, "device_type", | ||
476 | cp->type ? cp->type : cp->name); | ||
477 | dt_prop_u32(dt, "vendor-id", vendor_id); | ||
478 | dt_prop_u32(dt, "device-id", device_id); | ||
479 | dt_prop_u32(dt, "class-code", class_id >> 8); | ||
480 | dt_prop_u32(dt, "revision-id", class_id & 0xff); | ||
481 | dt_prop_u32(dt, "linux,subbus", sub_bus); | ||
482 | dt_prop_u32(dt, "linux,agent-id", agent_id); | ||
483 | dt_prop_u32(dt, "linux,logical-slot-number", | ||
484 | bridge_info->logicalSlotNumber); | ||
485 | dt_end_node(dt); | ||
486 | |||
487 | } | ||
488 | } | ||
489 | } | ||
490 | |||
491 | static void __init scan_bridge(struct iseries_flat_dt *dt, HvBusNumber bus, | ||
492 | HvSubBusNumber sub_bus, int id_sel) | ||
493 | { | ||
494 | struct HvCallPci_BridgeInfo bridge_info; | ||
495 | HvAgentId agent_id; | ||
496 | int function; | ||
497 | int ret; | ||
498 | |||
499 | /* Note: hvSubBus and irq is always be 0 at this level! */ | ||
500 | for (function = 0; function < 8; ++function) { | ||
501 | agent_id = ISERIES_PCI_AGENTID(id_sel, function); | ||
502 | ret = HvCallXm_connectBusUnit(bus, sub_bus, agent_id, 0); | ||
503 | if (ret != 0) { | ||
504 | if (ret != 0xb) | ||
505 | DBG("connectBusUnit(%x, %x, %x) %x\n", | ||
506 | bus, sub_bus, agent_id, ret); | ||
507 | continue; | ||
508 | } | ||
509 | DBG("found device at bus %d idsel %d func %d (AgentId %x)\n", | ||
510 | bus, id_sel, function, agent_id); | ||
511 | ret = HvCallPci_getBusUnitInfo(bus, sub_bus, agent_id, | ||
512 | iseries_hv_addr(&bridge_info), | ||
513 | sizeof(struct HvCallPci_BridgeInfo)); | ||
514 | if (ret != 0) | ||
515 | continue; | ||
516 | DBG("bridge info: type %x subbus %x " | ||
517 | "maxAgents %x maxsubbus %x logslot %x\n", | ||
518 | bridge_info.busUnitInfo.deviceType, | ||
519 | bridge_info.subBusNumber, | ||
520 | bridge_info.maxAgents, | ||
521 | bridge_info.maxSubBusNumber, | ||
522 | bridge_info.logicalSlotNumber); | ||
523 | if (bridge_info.busUnitInfo.deviceType == | ||
524 | HvCallPci_BridgeDevice) | ||
525 | scan_bridge_slot(dt, bus, &bridge_info); | ||
526 | else | ||
527 | DBG("PCI: Invalid Bridge Configuration(0x%02X)", | ||
528 | bridge_info.busUnitInfo.deviceType); | ||
529 | } | ||
530 | } | ||
531 | |||
532 | static void __init scan_phb(struct iseries_flat_dt *dt, HvBusNumber bus) | ||
533 | { | ||
534 | struct HvCallPci_DeviceInfo dev_info; | ||
535 | const HvSubBusNumber sub_bus = 0; /* EADs is always 0. */ | ||
536 | int err; | ||
537 | int id_sel; | ||
538 | const int max_agents = 8; | ||
539 | |||
540 | /* | ||
541 | * Probe for EADs Bridges | ||
542 | */ | ||
543 | for (id_sel = 1; id_sel < max_agents; ++id_sel) { | ||
544 | err = HvCallPci_getDeviceInfo(bus, sub_bus, id_sel, | ||
545 | iseries_hv_addr(&dev_info), | ||
546 | sizeof(struct HvCallPci_DeviceInfo)); | ||
547 | if (err) { | ||
548 | if (err != 0x302) | ||
549 | DBG("getDeviceInfo(%x, %x, %x) %x\n", | ||
550 | bus, sub_bus, id_sel, err); | ||
551 | continue; | ||
552 | } | ||
553 | if (dev_info.deviceType != HvCallPci_NodeDevice) { | ||
554 | DBG("PCI: Invalid System Configuration" | ||
555 | "(0x%02X) for bus 0x%02x id 0x%02x.\n", | ||
556 | dev_info.deviceType, bus, id_sel); | ||
557 | continue; | ||
558 | } | ||
559 | scan_bridge(dt, bus, sub_bus, id_sel); | ||
560 | } | ||
561 | } | ||
562 | |||
563 | static void __init dt_pci_devices(struct iseries_flat_dt *dt) | ||
564 | { | ||
565 | HvBusNumber bus; | ||
566 | char buf[32]; | ||
567 | u32 buses[2]; | ||
568 | int phb_num = 0; | ||
569 | |||
570 | /* Check all possible buses. */ | ||
571 | for (bus = 0; bus < 256; bus++) { | ||
572 | int err = HvCallXm_testBus(bus); | ||
573 | |||
574 | if (err) { | ||
575 | /* | ||
576 | * Check for Unexpected Return code, a clue that | ||
577 | * something has gone wrong. | ||
578 | */ | ||
579 | if (err != 0x0301) | ||
580 | DBG("Unexpected Return on Probe(0x%02X) " | ||
581 | "0x%04X\n", bus, err); | ||
582 | continue; | ||
583 | } | ||
584 | DBG("bus %d appears to exist\n", bus); | ||
585 | snprintf(buf, 32, "pci@%d", phb_num); | ||
586 | dt_start_node(dt, buf); | ||
587 | dt_prop_str(dt, "device_type", device_type_pci); | ||
588 | dt_prop_str(dt, "compatible", "IBM,iSeries-Logical-PHB"); | ||
589 | dt_prop_u32(dt, "#address-cells", 3); | ||
590 | dt_prop_u32(dt, "#size-cells", 2); | ||
591 | buses[0] = buses[1] = bus; | ||
592 | dt_prop_u32_list(dt, "bus-range", buses, 2); | ||
593 | scan_phb(dt, bus); | ||
594 | dt_end_node(dt); | ||
595 | phb_num++; | ||
596 | } | ||
597 | } | ||
598 | |||
599 | static void dt_finish(struct iseries_flat_dt *dt) | ||
600 | { | ||
601 | dt_push_u32(dt, OF_DT_END); | ||
602 | dt->header.totalsize = (unsigned long)dt_data - (unsigned long)dt; | ||
603 | klimit = ALIGN((unsigned long)dt_data, 8); | ||
604 | } | ||
605 | |||
606 | void * __init build_flat_dt(unsigned long phys_mem_size) | ||
607 | { | ||
608 | struct iseries_flat_dt *iseries_dt; | ||
609 | u64 tmp[2]; | ||
610 | |||
611 | iseries_dt = dt_init(); | ||
612 | |||
613 | dt_start_node(iseries_dt, ""); | ||
614 | |||
615 | dt_prop_u32(iseries_dt, "#address-cells", 2); | ||
616 | dt_prop_u32(iseries_dt, "#size-cells", 2); | ||
617 | dt_model(iseries_dt); | ||
618 | |||
619 | /* /memory */ | ||
620 | dt_start_node(iseries_dt, "memory@0"); | ||
621 | dt_prop_str(iseries_dt, "device_type", device_type_memory); | ||
622 | tmp[0] = 0; | ||
623 | tmp[1] = phys_mem_size; | ||
624 | dt_prop_u64_list(iseries_dt, "reg", tmp, 2); | ||
625 | dt_end_node(iseries_dt); | ||
626 | |||
627 | /* /chosen */ | ||
628 | dt_start_node(iseries_dt, "chosen"); | ||
629 | dt_prop_str(iseries_dt, "bootargs", cmd_line); | ||
630 | dt_initrd(iseries_dt); | ||
631 | dt_end_node(iseries_dt); | ||
632 | |||
633 | dt_cpus(iseries_dt); | ||
634 | |||
635 | dt_vdevices(iseries_dt); | ||
636 | dt_pci_devices(iseries_dt); | ||
637 | |||
638 | dt_end_node(iseries_dt); | ||
639 | |||
640 | dt_finish(iseries_dt); | ||
641 | |||
642 | return iseries_dt; | ||
643 | } | ||
diff --git a/arch/powerpc/platforms/iseries/exception.S b/arch/powerpc/platforms/iseries/exception.S deleted file mode 100644 index f519ee17ff7d..000000000000 --- a/arch/powerpc/platforms/iseries/exception.S +++ /dev/null | |||
@@ -1,311 +0,0 @@ | |||
1 | /* | ||
2 | * Low level routines for legacy iSeries support. | ||
3 | * | ||
4 | * Extracted from head_64.S | ||
5 | * | ||
6 | * PowerPC version | ||
7 | * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) | ||
8 | * | ||
9 | * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP | ||
10 | * Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu> | ||
11 | * Adapted for Power Macintosh by Paul Mackerras. | ||
12 | * Low-level exception handlers and MMU support | ||
13 | * rewritten by Paul Mackerras. | ||
14 | * Copyright (C) 1996 Paul Mackerras. | ||
15 | * | ||
16 | * Adapted for 64bit PowerPC by Dave Engebretsen, Peter Bergner, and | ||
17 | * Mike Corrigan {engebret|bergner|mikejc}@us.ibm.com | ||
18 | * | ||
19 | * This file contains the low-level support and setup for the | ||
20 | * PowerPC-64 platform, including trap and interrupt dispatch. | ||
21 | * | ||
22 | * This program is free software; you can redistribute it and/or | ||
23 | * modify it under the terms of the GNU General Public License | ||
24 | * as published by the Free Software Foundation; either version | ||
25 | * 2 of the License, or (at your option) any later version. | ||
26 | */ | ||
27 | |||
28 | #include <asm/reg.h> | ||
29 | #include <asm/ppc_asm.h> | ||
30 | #include <asm/asm-offsets.h> | ||
31 | #include <asm/thread_info.h> | ||
32 | #include <asm/ptrace.h> | ||
33 | #include <asm/cputable.h> | ||
34 | #include <asm/mmu.h> | ||
35 | |||
36 | #include "exception.h" | ||
37 | |||
38 | .text | ||
39 | |||
40 | .globl system_reset_iSeries | ||
41 | system_reset_iSeries: | ||
42 | bl .relative_toc | ||
43 | mfspr r13,SPRN_SPRG3 /* Get alpaca address */ | ||
44 | LOAD_REG_ADDR(r23, alpaca) | ||
45 | li r0,ALPACA_SIZE | ||
46 | sub r23,r13,r23 | ||
47 | divdu r24,r23,r0 /* r24 has cpu number */ | ||
48 | cmpwi 0,r24,0 /* Are we processor 0? */ | ||
49 | bne 1f | ||
50 | LOAD_REG_ADDR(r13, boot_paca) | ||
51 | mtspr SPRN_SPRG_PACA,r13 /* Save it away for the future */ | ||
52 | mfmsr r23 | ||
53 | ori r23,r23,MSR_RI | ||
54 | mtmsrd r23 /* RI on */ | ||
55 | b .__start_initialization_iSeries /* Start up the first processor */ | ||
56 | 1: mfspr r4,SPRN_CTRLF | ||
57 | li r5,CTRL_RUNLATCH /* Turn off the run light */ | ||
58 | andc r4,r4,r5 | ||
59 | mtspr SPRN_CTRLT,r4 | ||
60 | |||
61 | /* Spin on __secondary_hold_spinloop until it is updated by the boot cpu. */ | ||
62 | /* In the UP case we'll yield() later, and we will not access the paca anyway */ | ||
63 | #ifdef CONFIG_SMP | ||
64 | iSeries_secondary_wait_paca: | ||
65 | HMT_LOW | ||
66 | LOAD_REG_ADDR(r23, __secondary_hold_spinloop) | ||
67 | ld r23,0(r23) | ||
68 | |||
69 | cmpdi 0,r23,0 | ||
70 | bne 2f /* go on when the master is ready */ | ||
71 | |||
72 | /* Keep poking the Hypervisor until we're released */ | ||
73 | /* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */ | ||
74 | lis r3,0x8002 | ||
75 | rldicr r3,r3,32,15 /* r0 = (r3 << 32) & 0xffff000000000000 */ | ||
76 | li r0,-1 /* r0=-1 indicates a Hypervisor call */ | ||
77 | sc /* Invoke the hypervisor via a system call */ | ||
78 | b iSeries_secondary_wait_paca | ||
79 | |||
80 | 2: | ||
81 | HMT_MEDIUM | ||
82 | sync | ||
83 | |||
84 | LOAD_REG_ADDR(r3, nr_cpu_ids) /* get number of pacas allocated */ | ||
85 | lwz r3,0(r3) /* nr_cpus= or NR_CPUS can limit */ | ||
86 | cmpld 0,r24,r3 /* is our cpu number allocated? */ | ||
87 | bge iSeries_secondary_yield /* no, yield forever */ | ||
88 | |||
89 | /* Load our paca now that it's been allocated */ | ||
90 | LOAD_REG_ADDR(r13, paca) | ||
91 | ld r13,0(r13) | ||
92 | mulli r0,r24,PACA_SIZE | ||
93 | add r13,r13,r0 | ||
94 | mtspr SPRN_SPRG_PACA,r13 /* Save it away for the future */ | ||
95 | mfmsr r23 | ||
96 | ori r23,r23,MSR_RI | ||
97 | mtmsrd r23 /* RI on */ | ||
98 | |||
99 | iSeries_secondary_smp_loop: | ||
100 | lbz r23,PACAPROCSTART(r13) /* Test if this processor | ||
101 | * should start */ | ||
102 | cmpwi 0,r23,0 | ||
103 | bne 3f /* go on when we are told */ | ||
104 | |||
105 | HMT_LOW | ||
106 | /* Let the Hypervisor know we are alive */ | ||
107 | /* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */ | ||
108 | lis r3,0x8002 | ||
109 | rldicr r3,r3,32,15 /* r0 = (r3 << 32) & 0xffff000000000000 */ | ||
110 | li r0,-1 /* r0=-1 indicates a Hypervisor call */ | ||
111 | sc /* Invoke the hypervisor via a system call */ | ||
112 | mfspr r13,SPRN_SPRG_PACA /* Put r13 back ???? */ | ||
113 | b iSeries_secondary_smp_loop /* wait for signal to start */ | ||
114 | |||
115 | 3: | ||
116 | HMT_MEDIUM | ||
117 | sync | ||
118 | LOAD_REG_ADDR(r3,current_set) | ||
119 | sldi r28,r24,3 /* get current_set[cpu#] */ | ||
120 | ldx r3,r3,r28 | ||
121 | addi r1,r3,THREAD_SIZE | ||
122 | subi r1,r1,STACK_FRAME_OVERHEAD | ||
123 | |||
124 | b __secondary_start /* Loop until told to go */ | ||
125 | #endif /* CONFIG_SMP */ | ||
126 | |||
127 | iSeries_secondary_yield: | ||
128 | /* Yield the processor. This is required for non-SMP kernels | ||
129 | which are running on multi-threaded machines. */ | ||
130 | HMT_LOW | ||
131 | lis r3,0x8000 | ||
132 | rldicr r3,r3,32,15 /* r3 = (r3 << 32) & 0xffff000000000000 */ | ||
133 | addi r3,r3,18 /* r3 = 0x8000000000000012 which is "yield" */ | ||
134 | li r4,0 /* "yield timed" */ | ||
135 | li r5,-1 /* "yield forever" */ | ||
136 | li r0,-1 /* r0=-1 indicates a Hypervisor call */ | ||
137 | sc /* Invoke the hypervisor via a system call */ | ||
138 | mfspr r13,SPRN_SPRG_PACA /* Put r13 back ???? */ | ||
139 | b iSeries_secondary_yield /* If SMP not configured, secondaries | ||
140 | * loop forever */ | ||
141 | |||
142 | /*** ISeries-LPAR interrupt handlers ***/ | ||
143 | |||
144 | STD_EXCEPTION_ISERIES(machine_check, PACA_EXMC) | ||
145 | |||
146 | .globl data_access_iSeries | ||
147 | data_access_iSeries: | ||
148 | mtspr SPRN_SPRG_SCRATCH0,r13 | ||
149 | BEGIN_FTR_SECTION | ||
150 | mfspr r13,SPRN_SPRG_PACA | ||
151 | std r9,PACA_EXSLB+EX_R9(r13) | ||
152 | std r10,PACA_EXSLB+EX_R10(r13) | ||
153 | mfspr r10,SPRN_DAR | ||
154 | mfspr r9,SPRN_DSISR | ||
155 | srdi r10,r10,60 | ||
156 | rlwimi r10,r9,16,0x20 | ||
157 | mfcr r9 | ||
158 | cmpwi r10,0x2c | ||
159 | beq .do_stab_bolted_iSeries | ||
160 | ld r10,PACA_EXSLB+EX_R10(r13) | ||
161 | std r11,PACA_EXGEN+EX_R11(r13) | ||
162 | ld r11,PACA_EXSLB+EX_R9(r13) | ||
163 | std r12,PACA_EXGEN+EX_R12(r13) | ||
164 | mfspr r12,SPRN_SPRG_SCRATCH0 | ||
165 | std r10,PACA_EXGEN+EX_R10(r13) | ||
166 | std r11,PACA_EXGEN+EX_R9(r13) | ||
167 | std r12,PACA_EXGEN+EX_R13(r13) | ||
168 | EXCEPTION_PROLOG_ISERIES_1 | ||
169 | FTR_SECTION_ELSE | ||
170 | EXCEPTION_PROLOG_1(PACA_EXGEN, NOTEST, 0) | ||
171 | EXCEPTION_PROLOG_ISERIES_1 | ||
172 | ALT_MMU_FTR_SECTION_END_IFCLR(MMU_FTR_SLB) | ||
173 | b data_access_common | ||
174 | |||
175 | .do_stab_bolted_iSeries: | ||
176 | std r11,PACA_EXSLB+EX_R11(r13) | ||
177 | std r12,PACA_EXSLB+EX_R12(r13) | ||
178 | mfspr r10,SPRN_SPRG_SCRATCH0 | ||
179 | std r10,PACA_EXSLB+EX_R13(r13) | ||
180 | EXCEPTION_PROLOG_ISERIES_1 | ||
181 | b .do_stab_bolted | ||
182 | |||
183 | .globl data_access_slb_iSeries | ||
184 | data_access_slb_iSeries: | ||
185 | mtspr SPRN_SPRG_SCRATCH0,r13 /* save r13 */ | ||
186 | mfspr r13,SPRN_SPRG_PACA /* get paca address into r13 */ | ||
187 | std r3,PACA_EXSLB+EX_R3(r13) | ||
188 | mfspr r3,SPRN_DAR | ||
189 | std r9,PACA_EXSLB+EX_R9(r13) | ||
190 | mfcr r9 | ||
191 | #ifdef __DISABLED__ | ||
192 | cmpdi r3,0 | ||
193 | bge slb_miss_user_iseries | ||
194 | #endif | ||
195 | std r10,PACA_EXSLB+EX_R10(r13) | ||
196 | std r11,PACA_EXSLB+EX_R11(r13) | ||
197 | std r12,PACA_EXSLB+EX_R12(r13) | ||
198 | mfspr r10,SPRN_SPRG_SCRATCH0 | ||
199 | std r10,PACA_EXSLB+EX_R13(r13) | ||
200 | ld r12,PACALPPACAPTR(r13) | ||
201 | ld r12,LPPACASRR1(r12) | ||
202 | b .slb_miss_realmode | ||
203 | |||
204 | STD_EXCEPTION_ISERIES(instruction_access, PACA_EXGEN) | ||
205 | |||
206 | .globl instruction_access_slb_iSeries | ||
207 | instruction_access_slb_iSeries: | ||
208 | mtspr SPRN_SPRG_SCRATCH0,r13 /* save r13 */ | ||
209 | mfspr r13,SPRN_SPRG_PACA /* get paca address into r13 */ | ||
210 | std r3,PACA_EXSLB+EX_R3(r13) | ||
211 | ld r3,PACALPPACAPTR(r13) | ||
212 | ld r3,LPPACASRR0(r3) /* get SRR0 value */ | ||
213 | std r9,PACA_EXSLB+EX_R9(r13) | ||
214 | mfcr r9 | ||
215 | #ifdef __DISABLED__ | ||
216 | cmpdi r3,0 | ||
217 | bge slb_miss_user_iseries | ||
218 | #endif | ||
219 | std r10,PACA_EXSLB+EX_R10(r13) | ||
220 | std r11,PACA_EXSLB+EX_R11(r13) | ||
221 | std r12,PACA_EXSLB+EX_R12(r13) | ||
222 | mfspr r10,SPRN_SPRG_SCRATCH0 | ||
223 | std r10,PACA_EXSLB+EX_R13(r13) | ||
224 | ld r12,PACALPPACAPTR(r13) | ||
225 | ld r12,LPPACASRR1(r12) | ||
226 | b .slb_miss_realmode | ||
227 | |||
228 | #ifdef __DISABLED__ | ||
229 | slb_miss_user_iseries: | ||
230 | std r10,PACA_EXGEN+EX_R10(r13) | ||
231 | std r11,PACA_EXGEN+EX_R11(r13) | ||
232 | std r12,PACA_EXGEN+EX_R12(r13) | ||
233 | mfspr r10,SPRG_SCRATCH0 | ||
234 | ld r11,PACA_EXSLB+EX_R9(r13) | ||
235 | ld r12,PACA_EXSLB+EX_R3(r13) | ||
236 | std r10,PACA_EXGEN+EX_R13(r13) | ||
237 | std r11,PACA_EXGEN+EX_R9(r13) | ||
238 | std r12,PACA_EXGEN+EX_R3(r13) | ||
239 | EXCEPTION_PROLOG_ISERIES_1 | ||
240 | b slb_miss_user_common | ||
241 | #endif | ||
242 | |||
243 | MASKABLE_EXCEPTION_ISERIES(hardware_interrupt) | ||
244 | STD_EXCEPTION_ISERIES(alignment, PACA_EXGEN) | ||
245 | STD_EXCEPTION_ISERIES(program_check, PACA_EXGEN) | ||
246 | STD_EXCEPTION_ISERIES(fp_unavailable, PACA_EXGEN) | ||
247 | MASKABLE_EXCEPTION_ISERIES(decrementer) | ||
248 | STD_EXCEPTION_ISERIES(trap_0a, PACA_EXGEN) | ||
249 | STD_EXCEPTION_ISERIES(trap_0b, PACA_EXGEN) | ||
250 | |||
251 | .globl system_call_iSeries | ||
252 | system_call_iSeries: | ||
253 | mr r9,r13 | ||
254 | mfspr r13,SPRN_SPRG_PACA | ||
255 | EXCEPTION_PROLOG_ISERIES_1 | ||
256 | b system_call_common | ||
257 | |||
258 | STD_EXCEPTION_ISERIES(single_step, PACA_EXGEN) | ||
259 | STD_EXCEPTION_ISERIES(trap_0e, PACA_EXGEN) | ||
260 | STD_EXCEPTION_ISERIES(performance_monitor, PACA_EXGEN) | ||
261 | |||
262 | decrementer_iSeries_masked: | ||
263 | /* We may not have a valid TOC pointer in here. */ | ||
264 | li r11,1 | ||
265 | ld r12,PACALPPACAPTR(r13) | ||
266 | stb r11,LPPACADECRINT(r12) | ||
267 | li r12,-1 | ||
268 | clrldi r12,r12,33 /* set DEC to 0x7fffffff */ | ||
269 | mtspr SPRN_DEC,r12 | ||
270 | /* fall through */ | ||
271 | |||
272 | hardware_interrupt_iSeries_masked: | ||
273 | mtcrf 0x80,r9 /* Restore regs */ | ||
274 | ld r12,PACALPPACAPTR(r13) | ||
275 | ld r11,LPPACASRR0(r12) | ||
276 | ld r12,LPPACASRR1(r12) | ||
277 | mtspr SPRN_SRR0,r11 | ||
278 | mtspr SPRN_SRR1,r12 | ||
279 | ld r9,PACA_EXGEN+EX_R9(r13) | ||
280 | ld r10,PACA_EXGEN+EX_R10(r13) | ||
281 | ld r11,PACA_EXGEN+EX_R11(r13) | ||
282 | ld r12,PACA_EXGEN+EX_R12(r13) | ||
283 | ld r13,PACA_EXGEN+EX_R13(r13) | ||
284 | rfid | ||
285 | b . /* prevent speculative execution */ | ||
286 | |||
287 | _INIT_STATIC(__start_initialization_iSeries) | ||
288 | /* Clear out the BSS */ | ||
289 | LOAD_REG_ADDR(r11,__bss_stop) | ||
290 | LOAD_REG_ADDR(r8,__bss_start) | ||
291 | sub r11,r11,r8 /* bss size */ | ||
292 | addi r11,r11,7 /* round up to an even double word */ | ||
293 | rldicl. r11,r11,61,3 /* shift right by 3 */ | ||
294 | beq 4f | ||
295 | addi r8,r8,-8 | ||
296 | li r0,0 | ||
297 | mtctr r11 /* zero this many doublewords */ | ||
298 | 3: stdu r0,8(r8) | ||
299 | bdnz 3b | ||
300 | 4: | ||
301 | LOAD_REG_ADDR(r1,init_thread_union) | ||
302 | addi r1,r1,THREAD_SIZE | ||
303 | li r0,0 | ||
304 | stdu r0,-STACK_FRAME_OVERHEAD(r1) | ||
305 | |||
306 | bl .iSeries_early_setup | ||
307 | bl .early_setup | ||
308 | |||
309 | /* relocation is on at this point */ | ||
310 | |||
311 | b .start_here_common | ||
diff --git a/arch/powerpc/platforms/iseries/exception.h b/arch/powerpc/platforms/iseries/exception.h deleted file mode 100644 index 50271b550a99..000000000000 --- a/arch/powerpc/platforms/iseries/exception.h +++ /dev/null | |||
@@ -1,58 +0,0 @@ | |||
1 | #ifndef _ASM_POWERPC_ISERIES_EXCEPTION_H | ||
2 | #define _ASM_POWERPC_ISERIES_EXCEPTION_H | ||
3 | /* | ||
4 | * Extracted from head_64.S | ||
5 | * | ||
6 | * PowerPC version | ||
7 | * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) | ||
8 | * | ||
9 | * Rewritten by Cort Dougan (cort@cs.nmt.edu) for PReP | ||
10 | * Copyright (C) 1996 Cort Dougan <cort@cs.nmt.edu> | ||
11 | * Adapted for Power Macintosh by Paul Mackerras. | ||
12 | * Low-level exception handlers and MMU support | ||
13 | * rewritten by Paul Mackerras. | ||
14 | * Copyright (C) 1996 Paul Mackerras. | ||
15 | * | ||
16 | * Adapted for 64bit PowerPC by Dave Engebretsen, Peter Bergner, and | ||
17 | * Mike Corrigan {engebret|bergner|mikejc}@us.ibm.com | ||
18 | * | ||
19 | * This file contains the low-level support and setup for the | ||
20 | * PowerPC-64 platform, including trap and interrupt dispatch. | ||
21 | * | ||
22 | * This program is free software; you can redistribute it and/or | ||
23 | * modify it under the terms of the GNU General Public License | ||
24 | * as published by the Free Software Foundation; either version | ||
25 | * 2 of the License, or (at your option) any later version. | ||
26 | */ | ||
27 | #include <asm/exception-64s.h> | ||
28 | |||
29 | #define EXCEPTION_PROLOG_ISERIES_1 \ | ||
30 | mfmsr r10; \ | ||
31 | ld r12,PACALPPACAPTR(r13); \ | ||
32 | ld r11,LPPACASRR0(r12); \ | ||
33 | ld r12,LPPACASRR1(r12); \ | ||
34 | ori r10,r10,MSR_RI; \ | ||
35 | mtmsrd r10,1 | ||
36 | |||
37 | #define STD_EXCEPTION_ISERIES(label, area) \ | ||
38 | .globl label##_iSeries; \ | ||
39 | label##_iSeries: \ | ||
40 | HMT_MEDIUM; \ | ||
41 | mtspr SPRN_SPRG_SCRATCH0,r13; /* save r13 */ \ | ||
42 | EXCEPTION_PROLOG_1(area, NOTEST, 0); \ | ||
43 | EXCEPTION_PROLOG_ISERIES_1; \ | ||
44 | b label##_common | ||
45 | |||
46 | #define MASKABLE_EXCEPTION_ISERIES(label) \ | ||
47 | .globl label##_iSeries; \ | ||
48 | label##_iSeries: \ | ||
49 | HMT_MEDIUM; \ | ||
50 | mtspr SPRN_SPRG_SCRATCH0,r13; /* save r13 */ \ | ||
51 | EXCEPTION_PROLOG_1(PACA_EXGEN, NOTEST, 0); \ | ||
52 | lbz r10,PACASOFTIRQEN(r13); \ | ||
53 | cmpwi 0,r10,0; \ | ||
54 | beq- label##_iSeries_masked; \ | ||
55 | EXCEPTION_PROLOG_ISERIES_1; \ | ||
56 | b label##_common; \ | ||
57 | |||
58 | #endif /* _ASM_POWERPC_ISERIES_EXCEPTION_H */ | ||
diff --git a/arch/powerpc/platforms/iseries/htab.c b/arch/powerpc/platforms/iseries/htab.c deleted file mode 100644 index 3ae66ab9d5e7..000000000000 --- a/arch/powerpc/platforms/iseries/htab.c +++ /dev/null | |||
@@ -1,257 +0,0 @@ | |||
1 | /* | ||
2 | * iSeries hashtable management. | ||
3 | * Derived from pSeries_htab.c | ||
4 | * | ||
5 | * SMP scalability work: | ||
6 | * Copyright (C) 2001 Anton Blanchard <anton@au.ibm.com>, IBM | ||
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 | ||
10 | * as published by the Free Software Foundation; either version | ||
11 | * 2 of the License, or (at your option) any later version. | ||
12 | */ | ||
13 | #include <asm/machdep.h> | ||
14 | #include <asm/pgtable.h> | ||
15 | #include <asm/mmu.h> | ||
16 | #include <asm/mmu_context.h> | ||
17 | #include <asm/abs_addr.h> | ||
18 | #include <linux/spinlock.h> | ||
19 | |||
20 | #include "call_hpt.h" | ||
21 | |||
22 | static spinlock_t iSeries_hlocks[64] __cacheline_aligned_in_smp; | ||
23 | |||
24 | /* | ||
25 | * Very primitive algorithm for picking up a lock | ||
26 | */ | ||
27 | static inline void iSeries_hlock(unsigned long slot) | ||
28 | { | ||
29 | if (slot & 0x8) | ||
30 | slot = ~slot; | ||
31 | spin_lock(&iSeries_hlocks[(slot >> 4) & 0x3f]); | ||
32 | } | ||
33 | |||
34 | static inline void iSeries_hunlock(unsigned long slot) | ||
35 | { | ||
36 | if (slot & 0x8) | ||
37 | slot = ~slot; | ||
38 | spin_unlock(&iSeries_hlocks[(slot >> 4) & 0x3f]); | ||
39 | } | ||
40 | |||
41 | static long iSeries_hpte_insert(unsigned long hpte_group, unsigned long va, | ||
42 | unsigned long pa, unsigned long rflags, | ||
43 | unsigned long vflags, int psize, int ssize) | ||
44 | { | ||
45 | long slot; | ||
46 | struct hash_pte lhpte; | ||
47 | int secondary = 0; | ||
48 | |||
49 | BUG_ON(psize != MMU_PAGE_4K); | ||
50 | |||
51 | /* | ||
52 | * The hypervisor tries both primary and secondary. | ||
53 | * If we are being called to insert in the secondary, | ||
54 | * it means we have already tried both primary and secondary, | ||
55 | * so we return failure immediately. | ||
56 | */ | ||
57 | if (vflags & HPTE_V_SECONDARY) | ||
58 | return -1; | ||
59 | |||
60 | iSeries_hlock(hpte_group); | ||
61 | |||
62 | slot = HvCallHpt_findValid(&lhpte, va >> HW_PAGE_SHIFT); | ||
63 | if (unlikely(lhpte.v & HPTE_V_VALID)) { | ||
64 | if (vflags & HPTE_V_BOLTED) { | ||
65 | HvCallHpt_setSwBits(slot, 0x10, 0); | ||
66 | HvCallHpt_setPp(slot, PP_RWXX); | ||
67 | iSeries_hunlock(hpte_group); | ||
68 | if (slot < 0) | ||
69 | return 0x8 | (slot & 7); | ||
70 | else | ||
71 | return slot & 7; | ||
72 | } | ||
73 | BUG(); | ||
74 | } | ||
75 | |||
76 | if (slot == -1) { /* No available entry found in either group */ | ||
77 | iSeries_hunlock(hpte_group); | ||
78 | return -1; | ||
79 | } | ||
80 | |||
81 | if (slot < 0) { /* MSB set means secondary group */ | ||
82 | vflags |= HPTE_V_SECONDARY; | ||
83 | secondary = 1; | ||
84 | slot &= 0x7fffffffffffffff; | ||
85 | } | ||
86 | |||
87 | |||
88 | lhpte.v = hpte_encode_v(va, MMU_PAGE_4K, MMU_SEGSIZE_256M) | | ||
89 | vflags | HPTE_V_VALID; | ||
90 | lhpte.r = hpte_encode_r(phys_to_abs(pa), MMU_PAGE_4K) | rflags; | ||
91 | |||
92 | /* Now fill in the actual HPTE */ | ||
93 | HvCallHpt_addValidate(slot, secondary, &lhpte); | ||
94 | |||
95 | iSeries_hunlock(hpte_group); | ||
96 | |||
97 | return (secondary << 3) | (slot & 7); | ||
98 | } | ||
99 | |||
100 | static unsigned long iSeries_hpte_getword0(unsigned long slot) | ||
101 | { | ||
102 | struct hash_pte hpte; | ||
103 | |||
104 | HvCallHpt_get(&hpte, slot); | ||
105 | return hpte.v; | ||
106 | } | ||
107 | |||
108 | static long iSeries_hpte_remove(unsigned long hpte_group) | ||
109 | { | ||
110 | unsigned long slot_offset; | ||
111 | int i; | ||
112 | unsigned long hpte_v; | ||
113 | |||
114 | /* Pick a random slot to start at */ | ||
115 | slot_offset = mftb() & 0x7; | ||
116 | |||
117 | iSeries_hlock(hpte_group); | ||
118 | |||
119 | for (i = 0; i < HPTES_PER_GROUP; i++) { | ||
120 | hpte_v = iSeries_hpte_getword0(hpte_group + slot_offset); | ||
121 | |||
122 | if (! (hpte_v & HPTE_V_BOLTED)) { | ||
123 | HvCallHpt_invalidateSetSwBitsGet(hpte_group + | ||
124 | slot_offset, 0, 0); | ||
125 | iSeries_hunlock(hpte_group); | ||
126 | return i; | ||
127 | } | ||
128 | |||
129 | slot_offset++; | ||
130 | slot_offset &= 0x7; | ||
131 | } | ||
132 | |||
133 | iSeries_hunlock(hpte_group); | ||
134 | |||
135 | return -1; | ||
136 | } | ||
137 | |||
138 | /* | ||
139 | * The HyperVisor expects the "flags" argument in this form: | ||
140 | * bits 0..59 : reserved | ||
141 | * bit 60 : N | ||
142 | * bits 61..63 : PP2,PP1,PP0 | ||
143 | */ | ||
144 | static long iSeries_hpte_updatepp(unsigned long slot, unsigned long newpp, | ||
145 | unsigned long va, int psize, int ssize, int local) | ||
146 | { | ||
147 | struct hash_pte hpte; | ||
148 | unsigned long want_v; | ||
149 | |||
150 | iSeries_hlock(slot); | ||
151 | |||
152 | HvCallHpt_get(&hpte, slot); | ||
153 | want_v = hpte_encode_v(va, MMU_PAGE_4K, MMU_SEGSIZE_256M); | ||
154 | |||
155 | if (HPTE_V_COMPARE(hpte.v, want_v) && (hpte.v & HPTE_V_VALID)) { | ||
156 | /* | ||
157 | * Hypervisor expects bits as NPPP, which is | ||
158 | * different from how they are mapped in our PP. | ||
159 | */ | ||
160 | HvCallHpt_setPp(slot, (newpp & 0x3) | ((newpp & 0x4) << 1)); | ||
161 | iSeries_hunlock(slot); | ||
162 | return 0; | ||
163 | } | ||
164 | iSeries_hunlock(slot); | ||
165 | |||
166 | return -1; | ||
167 | } | ||
168 | |||
169 | /* | ||
170 | * Functions used to find the PTE for a particular virtual address. | ||
171 | * Only used during boot when bolting pages. | ||
172 | * | ||
173 | * Input : vpn : virtual page number | ||
174 | * Output: PTE index within the page table of the entry | ||
175 | * -1 on failure | ||
176 | */ | ||
177 | static long iSeries_hpte_find(unsigned long vpn) | ||
178 | { | ||
179 | struct hash_pte hpte; | ||
180 | long slot; | ||
181 | |||
182 | /* | ||
183 | * The HvCallHpt_findValid interface is as follows: | ||
184 | * 0xffffffffffffffff : No entry found. | ||
185 | * 0x00000000xxxxxxxx : Entry found in primary group, slot x | ||
186 | * 0x80000000xxxxxxxx : Entry found in secondary group, slot x | ||
187 | */ | ||
188 | slot = HvCallHpt_findValid(&hpte, vpn); | ||
189 | if (hpte.v & HPTE_V_VALID) { | ||
190 | if (slot < 0) { | ||
191 | slot &= 0x7fffffffffffffff; | ||
192 | slot = -slot; | ||
193 | } | ||
194 | } else | ||
195 | slot = -1; | ||
196 | return slot; | ||
197 | } | ||
198 | |||
199 | /* | ||
200 | * Update the page protection bits. Intended to be used to create | ||
201 | * guard pages for kernel data structures on pages which are bolted | ||
202 | * in the HPT. Assumes pages being operated on will not be stolen. | ||
203 | * Does not work on large pages. | ||
204 | * | ||
205 | * No need to lock here because we should be the only user. | ||
206 | */ | ||
207 | static void iSeries_hpte_updateboltedpp(unsigned long newpp, unsigned long ea, | ||
208 | int psize, int ssize) | ||
209 | { | ||
210 | unsigned long vsid,va,vpn; | ||
211 | long slot; | ||
212 | |||
213 | BUG_ON(psize != MMU_PAGE_4K); | ||
214 | |||
215 | vsid = get_kernel_vsid(ea, MMU_SEGSIZE_256M); | ||
216 | va = (vsid << 28) | (ea & 0x0fffffff); | ||
217 | vpn = va >> HW_PAGE_SHIFT; | ||
218 | slot = iSeries_hpte_find(vpn); | ||
219 | if (slot == -1) | ||
220 | panic("updateboltedpp: Could not find page to bolt\n"); | ||
221 | HvCallHpt_setPp(slot, newpp); | ||
222 | } | ||
223 | |||
224 | static void iSeries_hpte_invalidate(unsigned long slot, unsigned long va, | ||
225 | int psize, int ssize, int local) | ||
226 | { | ||
227 | unsigned long hpte_v; | ||
228 | unsigned long avpn = va >> 23; | ||
229 | unsigned long flags; | ||
230 | |||
231 | local_irq_save(flags); | ||
232 | |||
233 | iSeries_hlock(slot); | ||
234 | |||
235 | hpte_v = iSeries_hpte_getword0(slot); | ||
236 | |||
237 | if ((HPTE_V_AVPN_VAL(hpte_v) == avpn) && (hpte_v & HPTE_V_VALID)) | ||
238 | HvCallHpt_invalidateSetSwBitsGet(slot, 0, 0); | ||
239 | |||
240 | iSeries_hunlock(slot); | ||
241 | |||
242 | local_irq_restore(flags); | ||
243 | } | ||
244 | |||
245 | void __init hpte_init_iSeries(void) | ||
246 | { | ||
247 | int i; | ||
248 | |||
249 | for (i = 0; i < ARRAY_SIZE(iSeries_hlocks); i++) | ||
250 | spin_lock_init(&iSeries_hlocks[i]); | ||
251 | |||
252 | ppc_md.hpte_invalidate = iSeries_hpte_invalidate; | ||
253 | ppc_md.hpte_updatepp = iSeries_hpte_updatepp; | ||
254 | ppc_md.hpte_updateboltedpp = iSeries_hpte_updateboltedpp; | ||
255 | ppc_md.hpte_insert = iSeries_hpte_insert; | ||
256 | ppc_md.hpte_remove = iSeries_hpte_remove; | ||
257 | } | ||
diff --git a/arch/powerpc/platforms/iseries/hvcall.S b/arch/powerpc/platforms/iseries/hvcall.S deleted file mode 100644 index 07ae6ad5f49f..000000000000 --- a/arch/powerpc/platforms/iseries/hvcall.S +++ /dev/null | |||
@@ -1,94 +0,0 @@ | |||
1 | /* | ||
2 | * This file contains the code to perform calls to the | ||
3 | * iSeries LPAR hypervisor | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public License | ||
7 | * as published by the Free Software Foundation; either version | ||
8 | * 2 of the License, or (at your option) any later version. | ||
9 | */ | ||
10 | |||
11 | #include <asm/ppc_asm.h> | ||
12 | #include <asm/processor.h> | ||
13 | #include <asm/ptrace.h> /* XXX for STACK_FRAME_OVERHEAD */ | ||
14 | |||
15 | .text | ||
16 | |||
17 | /* | ||
18 | * Hypervisor call | ||
19 | * | ||
20 | * Invoke the iSeries hypervisor via the System Call instruction | ||
21 | * Parameters are passed to this routine in registers r3 - r10 | ||
22 | * | ||
23 | * r3 contains the HV function to be called | ||
24 | * r4-r10 contain the operands to the hypervisor function | ||
25 | * | ||
26 | */ | ||
27 | |||
28 | _GLOBAL(HvCall) | ||
29 | _GLOBAL(HvCall0) | ||
30 | _GLOBAL(HvCall1) | ||
31 | _GLOBAL(HvCall2) | ||
32 | _GLOBAL(HvCall3) | ||
33 | _GLOBAL(HvCall4) | ||
34 | _GLOBAL(HvCall5) | ||
35 | _GLOBAL(HvCall6) | ||
36 | _GLOBAL(HvCall7) | ||
37 | |||
38 | |||
39 | mfcr r0 | ||
40 | std r0,-8(r1) | ||
41 | stdu r1,-(STACK_FRAME_OVERHEAD+16)(r1) | ||
42 | |||
43 | /* r0 = 0xffffffffffffffff indicates a hypervisor call */ | ||
44 | |||
45 | li r0,-1 | ||
46 | |||
47 | /* Invoke the hypervisor */ | ||
48 | |||
49 | sc | ||
50 | |||
51 | ld r1,0(r1) | ||
52 | ld r0,-8(r1) | ||
53 | mtcrf 0xff,r0 | ||
54 | |||
55 | /* return to caller, return value in r3 */ | ||
56 | |||
57 | blr | ||
58 | |||
59 | _GLOBAL(HvCall0Ret16) | ||
60 | _GLOBAL(HvCall1Ret16) | ||
61 | _GLOBAL(HvCall2Ret16) | ||
62 | _GLOBAL(HvCall3Ret16) | ||
63 | _GLOBAL(HvCall4Ret16) | ||
64 | _GLOBAL(HvCall5Ret16) | ||
65 | _GLOBAL(HvCall6Ret16) | ||
66 | _GLOBAL(HvCall7Ret16) | ||
67 | |||
68 | mfcr r0 | ||
69 | std r0,-8(r1) | ||
70 | std r31,-16(r1) | ||
71 | stdu r1,-(STACK_FRAME_OVERHEAD+32)(r1) | ||
72 | |||
73 | mr r31,r4 | ||
74 | li r0,-1 | ||
75 | mr r4,r5 | ||
76 | mr r5,r6 | ||
77 | mr r6,r7 | ||
78 | mr r7,r8 | ||
79 | mr r8,r9 | ||
80 | mr r9,r10 | ||
81 | |||
82 | sc | ||
83 | |||
84 | std r3,0(r31) | ||
85 | std r4,8(r31) | ||
86 | |||
87 | mr r3,r5 | ||
88 | |||
89 | ld r1,0(r1) | ||
90 | ld r0,-8(r1) | ||
91 | mtcrf 0xff,r0 | ||
92 | ld r31,-16(r1) | ||
93 | |||
94 | blr | ||
diff --git a/arch/powerpc/platforms/iseries/hvlog.c b/arch/powerpc/platforms/iseries/hvlog.c deleted file mode 100644 index f476d71194fa..000000000000 --- a/arch/powerpc/platforms/iseries/hvlog.c +++ /dev/null | |||
@@ -1,35 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001 Mike Corrigan IBM Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | */ | ||
9 | |||
10 | #include <asm/page.h> | ||
11 | #include <asm/abs_addr.h> | ||
12 | #include <asm/iseries/hv_call.h> | ||
13 | #include <asm/iseries/hv_call_sc.h> | ||
14 | #include <asm/iseries/hv_types.h> | ||
15 | |||
16 | |||
17 | void HvCall_writeLogBuffer(const void *buffer, u64 len) | ||
18 | { | ||
19 | struct HvLpBufferList hv_buf; | ||
20 | u64 left_this_page; | ||
21 | u64 cur = virt_to_abs(buffer); | ||
22 | |||
23 | while (len) { | ||
24 | hv_buf.addr = cur; | ||
25 | left_this_page = ((cur & HW_PAGE_MASK) + HW_PAGE_SIZE) - cur; | ||
26 | if (left_this_page > len) | ||
27 | left_this_page = len; | ||
28 | hv_buf.len = left_this_page; | ||
29 | len -= left_this_page; | ||
30 | HvCall2(HvCallBaseWriteLogBuffer, | ||
31 | virt_to_abs(&hv_buf), | ||
32 | left_this_page); | ||
33 | cur = (cur & HW_PAGE_MASK) + HW_PAGE_SIZE; | ||
34 | } | ||
35 | } | ||
diff --git a/arch/powerpc/platforms/iseries/hvlpconfig.c b/arch/powerpc/platforms/iseries/hvlpconfig.c deleted file mode 100644 index f62a0c5fa670..000000000000 --- a/arch/powerpc/platforms/iseries/hvlpconfig.c +++ /dev/null | |||
@@ -1,39 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001 Kyle A. Lucke, IBM Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | |||
19 | #include <linux/export.h> | ||
20 | #include <asm/iseries/hv_lp_config.h> | ||
21 | #include "it_lp_naca.h" | ||
22 | |||
23 | HvLpIndex HvLpConfig_getLpIndex_outline(void) | ||
24 | { | ||
25 | return HvLpConfig_getLpIndex(); | ||
26 | } | ||
27 | EXPORT_SYMBOL(HvLpConfig_getLpIndex_outline); | ||
28 | |||
29 | HvLpIndex HvLpConfig_getLpIndex(void) | ||
30 | { | ||
31 | return itLpNaca.xLpIndex; | ||
32 | } | ||
33 | EXPORT_SYMBOL(HvLpConfig_getLpIndex); | ||
34 | |||
35 | HvLpIndex HvLpConfig_getPrimaryLpIndex(void) | ||
36 | { | ||
37 | return itLpNaca.xPrimaryLpIndex; | ||
38 | } | ||
39 | EXPORT_SYMBOL_GPL(HvLpConfig_getPrimaryLpIndex); | ||
diff --git a/arch/powerpc/platforms/iseries/iommu.c b/arch/powerpc/platforms/iseries/iommu.c deleted file mode 100644 index 2f3d9110248c..000000000000 --- a/arch/powerpc/platforms/iseries/iommu.c +++ /dev/null | |||
@@ -1,260 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation | ||
3 | * | ||
4 | * Rewrite, cleanup: | ||
5 | * | ||
6 | * Copyright (C) 2004 Olof Johansson <olof@lixom.net>, IBM Corporation | ||
7 | * Copyright (C) 2006 Olof Johansson <olof@lixom.net> | ||
8 | * | ||
9 | * Dynamic DMA mapping support, iSeries-specific parts. | ||
10 | * | ||
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 as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
25 | */ | ||
26 | |||
27 | #include <linux/types.h> | ||
28 | #include <linux/dma-mapping.h> | ||
29 | #include <linux/list.h> | ||
30 | #include <linux/pci.h> | ||
31 | #include <linux/export.h> | ||
32 | #include <linux/slab.h> | ||
33 | |||
34 | #include <asm/iommu.h> | ||
35 | #include <asm/vio.h> | ||
36 | #include <asm/tce.h> | ||
37 | #include <asm/machdep.h> | ||
38 | #include <asm/abs_addr.h> | ||
39 | #include <asm/prom.h> | ||
40 | #include <asm/pci-bridge.h> | ||
41 | #include <asm/iseries/hv_call_xm.h> | ||
42 | #include <asm/iseries/hv_call_event.h> | ||
43 | #include <asm/iseries/iommu.h> | ||
44 | |||
45 | static int tce_build_iSeries(struct iommu_table *tbl, long index, long npages, | ||
46 | unsigned long uaddr, enum dma_data_direction direction, | ||
47 | struct dma_attrs *attrs) | ||
48 | { | ||
49 | u64 rc; | ||
50 | u64 tce, rpn; | ||
51 | |||
52 | while (npages--) { | ||
53 | rpn = virt_to_abs(uaddr) >> TCE_SHIFT; | ||
54 | tce = (rpn & TCE_RPN_MASK) << TCE_RPN_SHIFT; | ||
55 | |||
56 | if (tbl->it_type == TCE_VB) { | ||
57 | /* Virtual Bus */ | ||
58 | tce |= TCE_VALID|TCE_ALLIO; | ||
59 | if (direction != DMA_TO_DEVICE) | ||
60 | tce |= TCE_VB_WRITE; | ||
61 | } else { | ||
62 | /* PCI Bus */ | ||
63 | tce |= TCE_PCI_READ; /* Read allowed */ | ||
64 | if (direction != DMA_TO_DEVICE) | ||
65 | tce |= TCE_PCI_WRITE; | ||
66 | } | ||
67 | |||
68 | rc = HvCallXm_setTce((u64)tbl->it_index, (u64)index, tce); | ||
69 | if (rc) | ||
70 | panic("PCI_DMA: HvCallXm_setTce failed, Rc: 0x%llx\n", | ||
71 | rc); | ||
72 | index++; | ||
73 | uaddr += TCE_PAGE_SIZE; | ||
74 | } | ||
75 | return 0; | ||
76 | } | ||
77 | |||
78 | static void tce_free_iSeries(struct iommu_table *tbl, long index, long npages) | ||
79 | { | ||
80 | u64 rc; | ||
81 | |||
82 | while (npages--) { | ||
83 | rc = HvCallXm_setTce((u64)tbl->it_index, (u64)index, 0); | ||
84 | if (rc) | ||
85 | panic("PCI_DMA: HvCallXm_setTce failed, Rc: 0x%llx\n", | ||
86 | rc); | ||
87 | index++; | ||
88 | } | ||
89 | } | ||
90 | |||
91 | /* | ||
92 | * Structure passed to HvCallXm_getTceTableParms | ||
93 | */ | ||
94 | struct iommu_table_cb { | ||
95 | unsigned long itc_busno; /* Bus number for this tce table */ | ||
96 | unsigned long itc_start; /* Will be NULL for secondary */ | ||
97 | unsigned long itc_totalsize; /* Size (in pages) of whole table */ | ||
98 | unsigned long itc_offset; /* Index into real tce table of the | ||
99 | start of our section */ | ||
100 | unsigned long itc_size; /* Size (in pages) of our section */ | ||
101 | unsigned long itc_index; /* Index of this tce table */ | ||
102 | unsigned short itc_maxtables; /* Max num of tables for partition */ | ||
103 | unsigned char itc_virtbus; /* Flag to indicate virtual bus */ | ||
104 | unsigned char itc_slotno; /* IOA Tce Slot Index */ | ||
105 | unsigned char itc_rsvd[4]; | ||
106 | }; | ||
107 | |||
108 | /* | ||
109 | * Call Hv with the architected data structure to get TCE table info. | ||
110 | * info. Put the returned data into the Linux representation of the | ||
111 | * TCE table data. | ||
112 | * The Hardware Tce table comes in three flavors. | ||
113 | * 1. TCE table shared between Buses. | ||
114 | * 2. TCE table per Bus. | ||
115 | * 3. TCE Table per IOA. | ||
116 | */ | ||
117 | void iommu_table_getparms_iSeries(unsigned long busno, | ||
118 | unsigned char slotno, | ||
119 | unsigned char virtbus, | ||
120 | struct iommu_table* tbl) | ||
121 | { | ||
122 | struct iommu_table_cb *parms; | ||
123 | |||
124 | parms = kzalloc(sizeof(*parms), GFP_KERNEL); | ||
125 | if (parms == NULL) | ||
126 | panic("PCI_DMA: TCE Table Allocation failed."); | ||
127 | |||
128 | parms->itc_busno = busno; | ||
129 | parms->itc_slotno = slotno; | ||
130 | parms->itc_virtbus = virtbus; | ||
131 | |||
132 | HvCallXm_getTceTableParms(iseries_hv_addr(parms)); | ||
133 | |||
134 | if (parms->itc_size == 0) | ||
135 | panic("PCI_DMA: parms->size is zero, parms is 0x%p", parms); | ||
136 | |||
137 | /* itc_size is in pages worth of table, it_size is in # of entries */ | ||
138 | tbl->it_size = (parms->itc_size * TCE_PAGE_SIZE) / TCE_ENTRY_SIZE; | ||
139 | tbl->it_busno = parms->itc_busno; | ||
140 | tbl->it_offset = parms->itc_offset; | ||
141 | tbl->it_index = parms->itc_index; | ||
142 | tbl->it_blocksize = 1; | ||
143 | tbl->it_type = virtbus ? TCE_VB : TCE_PCI; | ||
144 | |||
145 | kfree(parms); | ||
146 | } | ||
147 | |||
148 | |||
149 | #ifdef CONFIG_PCI | ||
150 | /* | ||
151 | * This function compares the known tables to find an iommu_table | ||
152 | * that has already been built for hardware TCEs. | ||
153 | */ | ||
154 | static struct iommu_table *iommu_table_find(struct iommu_table * tbl) | ||
155 | { | ||
156 | struct device_node *node; | ||
157 | |||
158 | for (node = NULL; (node = of_find_all_nodes(node)); ) { | ||
159 | struct pci_dn *pdn = PCI_DN(node); | ||
160 | struct iommu_table *it; | ||
161 | |||
162 | if (pdn == NULL) | ||
163 | continue; | ||
164 | it = pdn->iommu_table; | ||
165 | if ((it != NULL) && | ||
166 | (it->it_type == TCE_PCI) && | ||
167 | (it->it_offset == tbl->it_offset) && | ||
168 | (it->it_index == tbl->it_index) && | ||
169 | (it->it_size == tbl->it_size)) { | ||
170 | of_node_put(node); | ||
171 | return it; | ||
172 | } | ||
173 | } | ||
174 | return NULL; | ||
175 | } | ||
176 | |||
177 | |||
178 | static void pci_dma_dev_setup_iseries(struct pci_dev *pdev) | ||
179 | { | ||
180 | struct iommu_table *tbl; | ||
181 | struct device_node *dn = pci_device_to_OF_node(pdev); | ||
182 | struct pci_dn *pdn = PCI_DN(dn); | ||
183 | const u32 *lsn = of_get_property(dn, "linux,logical-slot-number", NULL); | ||
184 | |||
185 | BUG_ON(lsn == NULL); | ||
186 | |||
187 | tbl = kzalloc(sizeof(struct iommu_table), GFP_KERNEL); | ||
188 | |||
189 | iommu_table_getparms_iSeries(pdn->busno, *lsn, 0, tbl); | ||
190 | |||
191 | /* Look for existing tce table */ | ||
192 | pdn->iommu_table = iommu_table_find(tbl); | ||
193 | if (pdn->iommu_table == NULL) | ||
194 | pdn->iommu_table = iommu_init_table(tbl, -1); | ||
195 | else | ||
196 | kfree(tbl); | ||
197 | set_iommu_table_base(&pdev->dev, pdn->iommu_table); | ||
198 | } | ||
199 | #else | ||
200 | #define pci_dma_dev_setup_iseries NULL | ||
201 | #endif | ||
202 | |||
203 | static struct iommu_table veth_iommu_table; | ||
204 | static struct iommu_table vio_iommu_table; | ||
205 | |||
206 | void *iseries_hv_alloc(size_t size, dma_addr_t *dma_handle, gfp_t flag) | ||
207 | { | ||
208 | return iommu_alloc_coherent(NULL, &vio_iommu_table, size, dma_handle, | ||
209 | DMA_BIT_MASK(32), flag, -1); | ||
210 | } | ||
211 | EXPORT_SYMBOL_GPL(iseries_hv_alloc); | ||
212 | |||
213 | void iseries_hv_free(size_t size, void *vaddr, dma_addr_t dma_handle) | ||
214 | { | ||
215 | iommu_free_coherent(&vio_iommu_table, size, vaddr, dma_handle); | ||
216 | } | ||
217 | EXPORT_SYMBOL_GPL(iseries_hv_free); | ||
218 | |||
219 | dma_addr_t iseries_hv_map(void *vaddr, size_t size, | ||
220 | enum dma_data_direction direction) | ||
221 | { | ||
222 | return iommu_map_page(NULL, &vio_iommu_table, virt_to_page(vaddr), | ||
223 | (unsigned long)vaddr % PAGE_SIZE, size, | ||
224 | DMA_BIT_MASK(32), direction, NULL); | ||
225 | } | ||
226 | |||
227 | void iseries_hv_unmap(dma_addr_t dma_handle, size_t size, | ||
228 | enum dma_data_direction direction) | ||
229 | { | ||
230 | iommu_unmap_page(&vio_iommu_table, dma_handle, size, direction, NULL); | ||
231 | } | ||
232 | |||
233 | void __init iommu_vio_init(void) | ||
234 | { | ||
235 | iommu_table_getparms_iSeries(255, 0, 0xff, &veth_iommu_table); | ||
236 | veth_iommu_table.it_size /= 2; | ||
237 | vio_iommu_table = veth_iommu_table; | ||
238 | vio_iommu_table.it_offset += veth_iommu_table.it_size; | ||
239 | |||
240 | if (!iommu_init_table(&veth_iommu_table, -1)) | ||
241 | printk("Virtual Bus VETH TCE table failed.\n"); | ||
242 | if (!iommu_init_table(&vio_iommu_table, -1)) | ||
243 | printk("Virtual Bus VIO TCE table failed.\n"); | ||
244 | } | ||
245 | |||
246 | struct iommu_table *vio_build_iommu_table_iseries(struct vio_dev *dev) | ||
247 | { | ||
248 | if (strcmp(dev->type, "network") == 0) | ||
249 | return &veth_iommu_table; | ||
250 | return &vio_iommu_table; | ||
251 | } | ||
252 | |||
253 | void iommu_init_early_iSeries(void) | ||
254 | { | ||
255 | ppc_md.tce_build = tce_build_iSeries; | ||
256 | ppc_md.tce_free = tce_free_iSeries; | ||
257 | |||
258 | ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_iseries; | ||
259 | set_pci_dma_ops(&dma_iommu_ops); | ||
260 | } | ||
diff --git a/arch/powerpc/platforms/iseries/ipl_parms.h b/arch/powerpc/platforms/iseries/ipl_parms.h deleted file mode 100644 index 83e4ca42fc57..000000000000 --- a/arch/powerpc/platforms/iseries/ipl_parms.h +++ /dev/null | |||
@@ -1,68 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001 Mike Corrigan IBM Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | #ifndef _ISERIES_IPL_PARMS_H | ||
19 | #define _ISERIES_IPL_PARMS_H | ||
20 | |||
21 | /* | ||
22 | * This struct maps the IPL Parameters DMA'd from the SP. | ||
23 | * | ||
24 | * Warning: | ||
25 | * This data must map in exactly 64 bytes and match the architecture for | ||
26 | * the IPL parms | ||
27 | */ | ||
28 | |||
29 | #include <asm/types.h> | ||
30 | |||
31 | struct ItIplParmsReal { | ||
32 | u8 xFormat; // Defines format of IplParms x00-x00 | ||
33 | u8 xRsvd01:6; // Reserved x01-x01 | ||
34 | u8 xAlternateSearch:1; // Alternate search indicator ... | ||
35 | u8 xUaSupplied:1; // UA Supplied on programmed IPL... | ||
36 | u8 xLsUaFormat; // Format byte for UA x02-x02 | ||
37 | u8 xRsvd02; // Reserved x03-x03 | ||
38 | u32 xLsUa; // LS UA x04-x07 | ||
39 | u32 xUnusedLsLid; // First OS LID to load x08-x0B | ||
40 | u16 xLsBusNumber; // LS Bus Number x0C-x0D | ||
41 | u8 xLsCardAdr; // LS Card Address x0E-x0E | ||
42 | u8 xLsBoardAdr; // LS Board Address x0F-x0F | ||
43 | u32 xRsvd03; // Reserved x10-x13 | ||
44 | u8 xSpcnPresent:1; // SPCN present x14-x14 | ||
45 | u8 xCpmPresent:1; // CPM present ... | ||
46 | u8 xRsvd04:6; // Reserved ... | ||
47 | u8 xRsvd05:4; // Reserved x15-x15 | ||
48 | u8 xKeyLock:4; // Keylock setting ... | ||
49 | u8 xRsvd06:6; // Reserved x16-x16 | ||
50 | u8 xIplMode:2; // Ipl mode (A|B|C|D) ... | ||
51 | u8 xHwIplType; // Fast v slow v slow EC HW IPL x17-x17 | ||
52 | u16 xCpmEnabledIpl:1; // CPM in effect when IPL initiatedx18-x19 | ||
53 | u16 xPowerOnResetIpl:1; // Indicate POR condition ... | ||
54 | u16 xMainStorePreserved:1; // Main Storage is preserved ... | ||
55 | u16 xRsvd07:13; // Reserved ... | ||
56 | u16 xIplSource:16; // Ipl source x1A-x1B | ||
57 | u8 xIplReason:8; // Reason for this IPL x1C-x1C | ||
58 | u8 xRsvd08; // Reserved x1D-x1D | ||
59 | u16 xRsvd09; // Reserved x1E-x1F | ||
60 | u16 xSysBoxType; // System Box Type x20-x21 | ||
61 | u16 xSysProcType; // System Processor Type x22-x23 | ||
62 | u32 xRsvd10; // Reserved x24-x27 | ||
63 | u64 xRsvd11; // Reserved x28-x2F | ||
64 | u64 xRsvd12; // Reserved x30-x37 | ||
65 | u64 xRsvd13; // Reserved x38-x3F | ||
66 | }; | ||
67 | |||
68 | #endif /* _ISERIES_IPL_PARMS_H */ | ||
diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c deleted file mode 100644 index 05ce5164cafc..000000000000 --- a/arch/powerpc/platforms/iseries/irq.c +++ /dev/null | |||
@@ -1,399 +0,0 @@ | |||
1 | /* | ||
2 | * This module supports the iSeries PCI bus interrupt handling | ||
3 | * Copyright (C) 20yy <Robert L Holtorf> <IBM Corp> | ||
4 | * Copyright (C) 2004-2005 IBM Corporation | ||
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 as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the: | ||
18 | * Free Software Foundation, Inc., | ||
19 | * 59 Temple Place, Suite 330, | ||
20 | * Boston, MA 02111-1307 USA | ||
21 | * | ||
22 | * Change Activity: | ||
23 | * Created, December 13, 2000 by Wayne Holm | ||
24 | * End Change Activity | ||
25 | */ | ||
26 | #include <linux/pci.h> | ||
27 | #include <linux/init.h> | ||
28 | #include <linux/threads.h> | ||
29 | #include <linux/smp.h> | ||
30 | #include <linux/param.h> | ||
31 | #include <linux/string.h> | ||
32 | #include <linux/bootmem.h> | ||
33 | #include <linux/irq.h> | ||
34 | #include <linux/spinlock.h> | ||
35 | |||
36 | #include <asm/paca.h> | ||
37 | #include <asm/iseries/hv_types.h> | ||
38 | #include <asm/iseries/hv_lp_event.h> | ||
39 | #include <asm/iseries/hv_call_xm.h> | ||
40 | #include <asm/iseries/it_lp_queue.h> | ||
41 | |||
42 | #include "irq.h" | ||
43 | #include "pci.h" | ||
44 | #include "call_pci.h" | ||
45 | |||
46 | #ifdef CONFIG_PCI | ||
47 | |||
48 | enum pci_event_type { | ||
49 | pe_bus_created = 0, /* PHB has been created */ | ||
50 | pe_bus_error = 1, /* PHB has failed */ | ||
51 | pe_bus_failed = 2, /* Msg to Secondary, Primary failed bus */ | ||
52 | pe_node_failed = 4, /* Multi-adapter bridge has failed */ | ||
53 | pe_node_recovered = 5, /* Multi-adapter bridge has recovered */ | ||
54 | pe_bus_recovered = 12, /* PHB has been recovered */ | ||
55 | pe_unquiese_bus = 18, /* Secondary bus unqiescing */ | ||
56 | pe_bridge_error = 21, /* Bridge Error */ | ||
57 | pe_slot_interrupt = 22 /* Slot interrupt */ | ||
58 | }; | ||
59 | |||
60 | struct pci_event { | ||
61 | struct HvLpEvent event; | ||
62 | union { | ||
63 | u64 __align; /* Align on an 8-byte boundary */ | ||
64 | struct { | ||
65 | u32 fisr; | ||
66 | HvBusNumber bus_number; | ||
67 | HvSubBusNumber sub_bus_number; | ||
68 | HvAgentId dev_id; | ||
69 | } slot; | ||
70 | struct { | ||
71 | HvBusNumber bus_number; | ||
72 | HvSubBusNumber sub_bus_number; | ||
73 | } bus; | ||
74 | struct { | ||
75 | HvBusNumber bus_number; | ||
76 | HvSubBusNumber sub_bus_number; | ||
77 | HvAgentId dev_id; | ||
78 | } node; | ||
79 | } data; | ||
80 | }; | ||
81 | |||
82 | static DEFINE_SPINLOCK(pending_irqs_lock); | ||
83 | static int num_pending_irqs; | ||
84 | static int pending_irqs[NR_IRQS]; | ||
85 | |||
86 | static void int_received(struct pci_event *event) | ||
87 | { | ||
88 | int irq; | ||
89 | |||
90 | switch (event->event.xSubtype) { | ||
91 | case pe_slot_interrupt: | ||
92 | irq = event->event.xCorrelationToken; | ||
93 | if (irq < NR_IRQS) { | ||
94 | spin_lock(&pending_irqs_lock); | ||
95 | pending_irqs[irq]++; | ||
96 | num_pending_irqs++; | ||
97 | spin_unlock(&pending_irqs_lock); | ||
98 | } else { | ||
99 | printk(KERN_WARNING "int_received: bad irq number %d\n", | ||
100 | irq); | ||
101 | HvCallPci_eoi(event->data.slot.bus_number, | ||
102 | event->data.slot.sub_bus_number, | ||
103 | event->data.slot.dev_id); | ||
104 | } | ||
105 | break; | ||
106 | /* Ignore error recovery events for now */ | ||
107 | case pe_bus_created: | ||
108 | printk(KERN_INFO "int_received: system bus %d created\n", | ||
109 | event->data.bus.bus_number); | ||
110 | break; | ||
111 | case pe_bus_error: | ||
112 | case pe_bus_failed: | ||
113 | printk(KERN_INFO "int_received: system bus %d failed\n", | ||
114 | event->data.bus.bus_number); | ||
115 | break; | ||
116 | case pe_bus_recovered: | ||
117 | case pe_unquiese_bus: | ||
118 | printk(KERN_INFO "int_received: system bus %d recovered\n", | ||
119 | event->data.bus.bus_number); | ||
120 | break; | ||
121 | case pe_node_failed: | ||
122 | case pe_bridge_error: | ||
123 | printk(KERN_INFO | ||
124 | "int_received: multi-adapter bridge %d/%d/%d failed\n", | ||
125 | event->data.node.bus_number, | ||
126 | event->data.node.sub_bus_number, | ||
127 | event->data.node.dev_id); | ||
128 | break; | ||
129 | case pe_node_recovered: | ||
130 | printk(KERN_INFO | ||
131 | "int_received: multi-adapter bridge %d/%d/%d recovered\n", | ||
132 | event->data.node.bus_number, | ||
133 | event->data.node.sub_bus_number, | ||
134 | event->data.node.dev_id); | ||
135 | break; | ||
136 | default: | ||
137 | printk(KERN_ERR | ||
138 | "int_received: unrecognized event subtype 0x%x\n", | ||
139 | event->event.xSubtype); | ||
140 | break; | ||
141 | } | ||
142 | } | ||
143 | |||
144 | static void pci_event_handler(struct HvLpEvent *event) | ||
145 | { | ||
146 | if (event && (event->xType == HvLpEvent_Type_PciIo)) { | ||
147 | if (hvlpevent_is_int(event)) | ||
148 | int_received((struct pci_event *)event); | ||
149 | else | ||
150 | printk(KERN_ERR | ||
151 | "pci_event_handler: unexpected ack received\n"); | ||
152 | } else if (event) | ||
153 | printk(KERN_ERR | ||
154 | "pci_event_handler: Unrecognized PCI event type 0x%x\n", | ||
155 | (int)event->xType); | ||
156 | else | ||
157 | printk(KERN_ERR "pci_event_handler: NULL event received\n"); | ||
158 | } | ||
159 | |||
160 | #define REAL_IRQ_TO_SUBBUS(irq) (((irq) >> 14) & 0xff) | ||
161 | #define REAL_IRQ_TO_BUS(irq) ((((irq) >> 6) & 0xff) + 1) | ||
162 | #define REAL_IRQ_TO_IDSEL(irq) ((((irq) >> 3) & 7) + 1) | ||
163 | #define REAL_IRQ_TO_FUNC(irq) ((irq) & 7) | ||
164 | |||
165 | /* | ||
166 | * This will be called by device drivers (via enable_IRQ) | ||
167 | * to enable INTA in the bridge interrupt status register. | ||
168 | */ | ||
169 | static void iseries_enable_IRQ(struct irq_data *d) | ||
170 | { | ||
171 | u32 bus, dev_id, function, mask; | ||
172 | const u32 sub_bus = 0; | ||
173 | unsigned int rirq = (unsigned int)irqd_to_hwirq(d); | ||
174 | |||
175 | /* The IRQ has already been locked by the caller */ | ||
176 | bus = REAL_IRQ_TO_BUS(rirq); | ||
177 | function = REAL_IRQ_TO_FUNC(rirq); | ||
178 | dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function; | ||
179 | |||
180 | /* Unmask secondary INTA */ | ||
181 | mask = 0x80000000; | ||
182 | HvCallPci_unmaskInterrupts(bus, sub_bus, dev_id, mask); | ||
183 | } | ||
184 | |||
185 | /* This is called by iseries_activate_IRQs */ | ||
186 | static unsigned int iseries_startup_IRQ(struct irq_data *d) | ||
187 | { | ||
188 | u32 bus, dev_id, function, mask; | ||
189 | const u32 sub_bus = 0; | ||
190 | unsigned int rirq = (unsigned int)irqd_to_hwirq(d); | ||
191 | |||
192 | bus = REAL_IRQ_TO_BUS(rirq); | ||
193 | function = REAL_IRQ_TO_FUNC(rirq); | ||
194 | dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function; | ||
195 | |||
196 | /* Link the IRQ number to the bridge */ | ||
197 | HvCallXm_connectBusUnit(bus, sub_bus, dev_id, d->irq); | ||
198 | |||
199 | /* Unmask bridge interrupts in the FISR */ | ||
200 | mask = 0x01010000 << function; | ||
201 | HvCallPci_unmaskFisr(bus, sub_bus, dev_id, mask); | ||
202 | iseries_enable_IRQ(d); | ||
203 | return 0; | ||
204 | } | ||
205 | |||
206 | /* | ||
207 | * This is called out of iSeries_fixup to activate interrupt | ||
208 | * generation for usable slots | ||
209 | */ | ||
210 | void __init iSeries_activate_IRQs() | ||
211 | { | ||
212 | int irq; | ||
213 | unsigned long flags; | ||
214 | |||
215 | for_each_irq (irq) { | ||
216 | struct irq_desc *desc = irq_to_desc(irq); | ||
217 | struct irq_chip *chip; | ||
218 | |||
219 | if (!desc) | ||
220 | continue; | ||
221 | |||
222 | chip = irq_desc_get_chip(desc); | ||
223 | if (chip && chip->irq_startup) { | ||
224 | raw_spin_lock_irqsave(&desc->lock, flags); | ||
225 | chip->irq_startup(&desc->irq_data); | ||
226 | raw_spin_unlock_irqrestore(&desc->lock, flags); | ||
227 | } | ||
228 | } | ||
229 | } | ||
230 | |||
231 | /* this is not called anywhere currently */ | ||
232 | static void iseries_shutdown_IRQ(struct irq_data *d) | ||
233 | { | ||
234 | u32 bus, dev_id, function, mask; | ||
235 | const u32 sub_bus = 0; | ||
236 | unsigned int rirq = (unsigned int)irqd_to_hwirq(d); | ||
237 | |||
238 | /* irq should be locked by the caller */ | ||
239 | bus = REAL_IRQ_TO_BUS(rirq); | ||
240 | function = REAL_IRQ_TO_FUNC(rirq); | ||
241 | dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function; | ||
242 | |||
243 | /* Invalidate the IRQ number in the bridge */ | ||
244 | HvCallXm_connectBusUnit(bus, sub_bus, dev_id, 0); | ||
245 | |||
246 | /* Mask bridge interrupts in the FISR */ | ||
247 | mask = 0x01010000 << function; | ||
248 | HvCallPci_maskFisr(bus, sub_bus, dev_id, mask); | ||
249 | } | ||
250 | |||
251 | /* | ||
252 | * This will be called by device drivers (via disable_IRQ) | ||
253 | * to disable INTA in the bridge interrupt status register. | ||
254 | */ | ||
255 | static void iseries_disable_IRQ(struct irq_data *d) | ||
256 | { | ||
257 | u32 bus, dev_id, function, mask; | ||
258 | const u32 sub_bus = 0; | ||
259 | unsigned int rirq = (unsigned int)irqd_to_hwirq(d); | ||
260 | |||
261 | /* The IRQ has already been locked by the caller */ | ||
262 | bus = REAL_IRQ_TO_BUS(rirq); | ||
263 | function = REAL_IRQ_TO_FUNC(rirq); | ||
264 | dev_id = (REAL_IRQ_TO_IDSEL(rirq) << 4) + function; | ||
265 | |||
266 | /* Mask secondary INTA */ | ||
267 | mask = 0x80000000; | ||
268 | HvCallPci_maskInterrupts(bus, sub_bus, dev_id, mask); | ||
269 | } | ||
270 | |||
271 | static void iseries_end_IRQ(struct irq_data *d) | ||
272 | { | ||
273 | unsigned int rirq = (unsigned int)irqd_to_hwirq(d); | ||
274 | |||
275 | HvCallPci_eoi(REAL_IRQ_TO_BUS(rirq), REAL_IRQ_TO_SUBBUS(rirq), | ||
276 | (REAL_IRQ_TO_IDSEL(rirq) << 4) + REAL_IRQ_TO_FUNC(rirq)); | ||
277 | } | ||
278 | |||
279 | static struct irq_chip iseries_pic = { | ||
280 | .name = "iSeries", | ||
281 | .irq_startup = iseries_startup_IRQ, | ||
282 | .irq_shutdown = iseries_shutdown_IRQ, | ||
283 | .irq_unmask = iseries_enable_IRQ, | ||
284 | .irq_mask = iseries_disable_IRQ, | ||
285 | .irq_eoi = iseries_end_IRQ | ||
286 | }; | ||
287 | |||
288 | /* | ||
289 | * This is called out of iSeries_scan_slot to allocate an IRQ for an EADS slot | ||
290 | * It calculates the irq value for the slot. | ||
291 | * Note that sub_bus is always 0 (at the moment at least). | ||
292 | */ | ||
293 | int __init iSeries_allocate_IRQ(HvBusNumber bus, | ||
294 | HvSubBusNumber sub_bus, u32 bsubbus) | ||
295 | { | ||
296 | unsigned int realirq; | ||
297 | u8 idsel = ISERIES_GET_DEVICE_FROM_SUBBUS(bsubbus); | ||
298 | u8 function = ISERIES_GET_FUNCTION_FROM_SUBBUS(bsubbus); | ||
299 | |||
300 | realirq = (((((sub_bus << 8) + (bus - 1)) << 3) + (idsel - 1)) << 3) | ||
301 | + function; | ||
302 | |||
303 | return irq_create_mapping(NULL, realirq); | ||
304 | } | ||
305 | |||
306 | #endif /* CONFIG_PCI */ | ||
307 | |||
308 | /* | ||
309 | * Get the next pending IRQ. | ||
310 | */ | ||
311 | unsigned int iSeries_get_irq(void) | ||
312 | { | ||
313 | int irq = NO_IRQ_IGNORE; | ||
314 | |||
315 | #ifdef CONFIG_SMP | ||
316 | if (get_lppaca()->int_dword.fields.ipi_cnt) { | ||
317 | get_lppaca()->int_dword.fields.ipi_cnt = 0; | ||
318 | smp_ipi_demux(); | ||
319 | } | ||
320 | #endif /* CONFIG_SMP */ | ||
321 | if (hvlpevent_is_pending()) | ||
322 | process_hvlpevents(); | ||
323 | |||
324 | #ifdef CONFIG_PCI | ||
325 | if (num_pending_irqs) { | ||
326 | spin_lock(&pending_irqs_lock); | ||
327 | for (irq = 0; irq < NR_IRQS; irq++) { | ||
328 | if (pending_irqs[irq]) { | ||
329 | pending_irqs[irq]--; | ||
330 | num_pending_irqs--; | ||
331 | break; | ||
332 | } | ||
333 | } | ||
334 | spin_unlock(&pending_irqs_lock); | ||
335 | if (irq >= NR_IRQS) | ||
336 | irq = NO_IRQ_IGNORE; | ||
337 | } | ||
338 | #endif | ||
339 | |||
340 | return irq; | ||
341 | } | ||
342 | |||
343 | #ifdef CONFIG_PCI | ||
344 | |||
345 | static int iseries_irq_host_map(struct irq_domain *h, unsigned int virq, | ||
346 | irq_hw_number_t hw) | ||
347 | { | ||
348 | irq_set_chip_and_handler(virq, &iseries_pic, handle_fasteoi_irq); | ||
349 | |||
350 | return 0; | ||
351 | } | ||
352 | |||
353 | static int iseries_irq_host_match(struct irq_domain *h, struct device_node *np) | ||
354 | { | ||
355 | /* Match all */ | ||
356 | return 1; | ||
357 | } | ||
358 | |||
359 | static const struct irq_domain_ops iseries_irq_domain_ops = { | ||
360 | .map = iseries_irq_host_map, | ||
361 | .match = iseries_irq_host_match, | ||
362 | }; | ||
363 | |||
364 | /* | ||
365 | * This is called by init_IRQ. set in ppc_md.init_IRQ by iSeries_setup.c | ||
366 | * It must be called before the bus walk. | ||
367 | */ | ||
368 | void __init iSeries_init_IRQ(void) | ||
369 | { | ||
370 | /* Register PCI event handler and open an event path */ | ||
371 | struct irq_domain *host; | ||
372 | int ret; | ||
373 | |||
374 | /* | ||
375 | * The Hypervisor only allows us up to 256 interrupt | ||
376 | * sources (the irq number is passed in a u8). | ||
377 | */ | ||
378 | irq_set_virq_count(256); | ||
379 | |||
380 | /* Create irq host. No need for a revmap since HV will give us | ||
381 | * back our virtual irq number | ||
382 | */ | ||
383 | host = irq_domain_add_nomap(NULL, &iseries_irq_domain_ops, NULL); | ||
384 | BUG_ON(host == NULL); | ||
385 | irq_set_default_host(host); | ||
386 | |||
387 | ret = HvLpEvent_registerHandler(HvLpEvent_Type_PciIo, | ||
388 | &pci_event_handler); | ||
389 | if (ret == 0) { | ||
390 | ret = HvLpEvent_openPath(HvLpEvent_Type_PciIo, 0); | ||
391 | if (ret != 0) | ||
392 | printk(KERN_ERR "iseries_init_IRQ: open event path " | ||
393 | "failed with rc 0x%x\n", ret); | ||
394 | } else | ||
395 | printk(KERN_ERR "iseries_init_IRQ: register handler " | ||
396 | "failed with rc 0x%x\n", ret); | ||
397 | } | ||
398 | |||
399 | #endif /* CONFIG_PCI */ | ||
diff --git a/arch/powerpc/platforms/iseries/irq.h b/arch/powerpc/platforms/iseries/irq.h deleted file mode 100644 index a1c236074034..000000000000 --- a/arch/powerpc/platforms/iseries/irq.h +++ /dev/null | |||
@@ -1,13 +0,0 @@ | |||
1 | #ifndef _ISERIES_IRQ_H | ||
2 | #define _ISERIES_IRQ_H | ||
3 | |||
4 | #ifdef CONFIG_PCI | ||
5 | extern void iSeries_init_IRQ(void); | ||
6 | extern int iSeries_allocate_IRQ(HvBusNumber, HvSubBusNumber, u32); | ||
7 | extern void iSeries_activate_IRQs(void); | ||
8 | #else | ||
9 | #define iSeries_init_IRQ NULL | ||
10 | #endif | ||
11 | extern unsigned int iSeries_get_irq(void); | ||
12 | |||
13 | #endif /* _ISERIES_IRQ_H */ | ||
diff --git a/arch/powerpc/platforms/iseries/it_exp_vpd_panel.h b/arch/powerpc/platforms/iseries/it_exp_vpd_panel.h deleted file mode 100644 index 6de9097b7f57..000000000000 --- a/arch/powerpc/platforms/iseries/it_exp_vpd_panel.h +++ /dev/null | |||
@@ -1,51 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2002 Dave Boutcher IBM Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | #ifndef _PLATFORMS_ISERIES_IT_EXT_VPD_PANEL_H | ||
19 | #define _PLATFORMS_ISERIES_IT_EXT_VPD_PANEL_H | ||
20 | |||
21 | /* | ||
22 | * This struct maps the panel information | ||
23 | * | ||
24 | * Warning: | ||
25 | * This data must match the architecture for the panel information | ||
26 | */ | ||
27 | |||
28 | #include <asm/types.h> | ||
29 | |||
30 | struct ItExtVpdPanel { | ||
31 | /* Definition of the Extended Vpd On Panel Data Area */ | ||
32 | char systemSerial[8]; | ||
33 | char mfgID[4]; | ||
34 | char reserved1[24]; | ||
35 | char machineType[4]; | ||
36 | char systemID[6]; | ||
37 | char somUniqueCnt[4]; | ||
38 | char serialNumberCount; | ||
39 | char reserved2[7]; | ||
40 | u16 bbu3; | ||
41 | u16 bbu2; | ||
42 | u16 bbu1; | ||
43 | char xLocationLabel[8]; | ||
44 | u8 xRsvd1[6]; | ||
45 | u16 xFrameId; | ||
46 | u8 xRsvd2[48]; | ||
47 | }; | ||
48 | |||
49 | extern struct ItExtVpdPanel xItExtVpdPanel; | ||
50 | |||
51 | #endif /* _PLATFORMS_ISERIES_IT_EXT_VPD_PANEL_H */ | ||
diff --git a/arch/powerpc/platforms/iseries/it_lp_naca.h b/arch/powerpc/platforms/iseries/it_lp_naca.h deleted file mode 100644 index cf6dcf6ef07b..000000000000 --- a/arch/powerpc/platforms/iseries/it_lp_naca.h +++ /dev/null | |||
@@ -1,80 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001 Mike Corrigan IBM Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | #ifndef _PLATFORMS_ISERIES_IT_LP_NACA_H | ||
19 | #define _PLATFORMS_ISERIES_IT_LP_NACA_H | ||
20 | |||
21 | #include <linux/types.h> | ||
22 | |||
23 | /* | ||
24 | * This control block contains the data that is shared between the | ||
25 | * hypervisor (PLIC) and the OS. | ||
26 | */ | ||
27 | |||
28 | struct ItLpNaca { | ||
29 | // CACHE_LINE_1 0x0000 - 0x007F Contains read-only data | ||
30 | u32 xDesc; // Eye catcher x00-x03 | ||
31 | u16 xSize; // Size of this class x04-x05 | ||
32 | u16 xIntHdlrOffset; // Offset to IntHdlr array x06-x07 | ||
33 | u8 xMaxIntHdlrEntries; // Number of entries in array x08-x08 | ||
34 | u8 xPrimaryLpIndex; // LP Index of Primary x09-x09 | ||
35 | u8 xServiceLpIndex; // LP Ind of Service Focal Pointx0A-x0A | ||
36 | u8 xLpIndex; // LP Index x0B-x0B | ||
37 | u16 xMaxLpQueues; // Number of allocated queues x0C-x0D | ||
38 | u16 xLpQueueOffset; // Offset to start of LP queues x0E-x0F | ||
39 | u8 xPirEnvironMode; // Piranha or hardware x10-x10 | ||
40 | u8 xPirConsoleMode; // Piranha console indicator x11-x11 | ||
41 | u8 xPirDasdMode; // Piranha dasd indicator x12-x12 | ||
42 | u8 xRsvd1_0[5]; // Reserved for Piranha related x13-x17 | ||
43 | u8 flags; // flags, see below x18-x1F | ||
44 | u8 xSpVpdFormat; // VPD areas are in CSP format ... | ||
45 | u8 xIntProcRatio; // Ratio of int procs to procs ... | ||
46 | u8 xRsvd1_2[5]; // Reserved ... | ||
47 | u16 xRsvd1_3; // Reserved x20-x21 | ||
48 | u16 xPlicVrmIndex; // VRM index of PLIC x22-x23 | ||
49 | u16 xMinSupportedSlicVrmInd;// Min supported OS VRM index x24-x25 | ||
50 | u16 xMinCompatableSlicVrmInd;// Min compatible OS VRM index x26-x27 | ||
51 | u64 xLoadAreaAddr; // ER address of load area x28-x2F | ||
52 | u32 xLoadAreaChunks; // Chunks for the load area x30-x33 | ||
53 | u32 xPaseSysCallCRMask; // Mask used to test CR before x34-x37 | ||
54 | // doing an ASR switch on PASE | ||
55 | // system call. | ||
56 | u64 xSlicSegmentTablePtr; // Pointer to Slic seg table. x38-x3f | ||
57 | u8 xRsvd1_4[64]; // x40-x7F | ||
58 | |||
59 | // CACHE_LINE_2 0x0080 - 0x00FF Contains local read-write data | ||
60 | u8 xRsvd2_0[128]; // Reserved x00-x7F | ||
61 | |||
62 | // CACHE_LINE_3-6 0x0100 - 0x02FF Contains LP Queue indicators | ||
63 | // NB: Padding required to keep xInterruptHdlr at x300 which is required | ||
64 | // for v4r4 PLIC. | ||
65 | u8 xOldLpQueue[128]; // LP Queue needed for v4r4 100-17F | ||
66 | u8 xRsvd3_0[384]; // Reserved 180-2FF | ||
67 | |||
68 | // CACHE_LINE_7-8 0x0300 - 0x03FF Contains the address of the OS interrupt | ||
69 | // handlers | ||
70 | u64 xInterruptHdlr[32]; // Interrupt handlers 300-x3FF | ||
71 | }; | ||
72 | |||
73 | extern struct ItLpNaca itLpNaca; | ||
74 | |||
75 | #define ITLPNACA_LPAR 0x80 /* Is LPAR installed on the system */ | ||
76 | #define ITLPNACA_PARTITIONED 0x40 /* Is the system partitioned */ | ||
77 | #define ITLPNACA_HWSYNCEDTBS 0x20 /* Hardware synced TBs */ | ||
78 | #define ITLPNACA_HMTINT 0x10 /* Utilize MHT for interrupts */ | ||
79 | |||
80 | #endif /* _PLATFORMS_ISERIES_IT_LP_NACA_H */ | ||
diff --git a/arch/powerpc/platforms/iseries/ksyms.c b/arch/powerpc/platforms/iseries/ksyms.c deleted file mode 100644 index 997e234fb8b7..000000000000 --- a/arch/powerpc/platforms/iseries/ksyms.c +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* | ||
2 | * (C) 2001-2005 PPC 64 Team, IBM Corp | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation; either version | ||
7 | * 2 of the License, or (at your option) any later version. | ||
8 | */ | ||
9 | #include <linux/export.h> | ||
10 | |||
11 | #include <asm/hw_irq.h> | ||
12 | #include <asm/iseries/hv_call_sc.h> | ||
13 | |||
14 | EXPORT_SYMBOL(HvCall0); | ||
15 | EXPORT_SYMBOL(HvCall1); | ||
16 | EXPORT_SYMBOL(HvCall2); | ||
17 | EXPORT_SYMBOL(HvCall3); | ||
18 | EXPORT_SYMBOL(HvCall4); | ||
19 | EXPORT_SYMBOL(HvCall5); | ||
20 | EXPORT_SYMBOL(HvCall6); | ||
21 | EXPORT_SYMBOL(HvCall7); | ||
diff --git a/arch/powerpc/platforms/iseries/lpardata.c b/arch/powerpc/platforms/iseries/lpardata.c deleted file mode 100644 index 00e0ec813a1c..000000000000 --- a/arch/powerpc/platforms/iseries/lpardata.c +++ /dev/null | |||
@@ -1,318 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright 2001 Mike Corrigan, IBM Corp | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation; either version | ||
7 | * 2 of the License, or (at your option) any later version. | ||
8 | */ | ||
9 | #include <linux/types.h> | ||
10 | #include <linux/threads.h> | ||
11 | #include <linux/bitops.h> | ||
12 | #include <asm/processor.h> | ||
13 | #include <asm/ptrace.h> | ||
14 | #include <asm/abs_addr.h> | ||
15 | #include <asm/lppaca.h> | ||
16 | #include <asm/paca.h> | ||
17 | #include <asm/iseries/lpar_map.h> | ||
18 | #include <asm/iseries/it_lp_queue.h> | ||
19 | #include <asm/iseries/alpaca.h> | ||
20 | |||
21 | #include "naca.h" | ||
22 | #include "vpd_areas.h" | ||
23 | #include "spcomm_area.h" | ||
24 | #include "ipl_parms.h" | ||
25 | #include "processor_vpd.h" | ||
26 | #include "release_data.h" | ||
27 | #include "it_exp_vpd_panel.h" | ||
28 | #include "it_lp_naca.h" | ||
29 | |||
30 | /* The HvReleaseData is the root of the information shared between | ||
31 | * the hypervisor and Linux. | ||
32 | */ | ||
33 | const struct HvReleaseData hvReleaseData = { | ||
34 | .xDesc = 0xc8a5d9c4, /* "HvRD" ebcdic */ | ||
35 | .xSize = sizeof(struct HvReleaseData), | ||
36 | .xVpdAreasPtrOffset = offsetof(struct naca_struct, xItVpdAreas), | ||
37 | .xSlicNacaAddr = &naca, /* 64-bit Naca address */ | ||
38 | .xMsNucDataOffset = LPARMAP_PHYS, | ||
39 | .xFlags = HVREL_TAGSINACTIVE /* tags inactive */ | ||
40 | /* 64 bit */ | ||
41 | /* shared processors */ | ||
42 | /* HMT allowed */ | ||
43 | | 6, /* TEMP: This allows non-GA driver */ | ||
44 | .xVrmIndex = 4, /* We are v5r2m0 */ | ||
45 | .xMinSupportedPlicVrmIndex = 3, /* v5r1m0 */ | ||
46 | .xMinCompatablePlicVrmIndex = 3, /* v5r1m0 */ | ||
47 | .xVrmName = { 0xd3, 0x89, 0x95, 0xa4, /* "Linux 2.4.64" ebcdic */ | ||
48 | 0xa7, 0x40, 0xf2, 0x4b, | ||
49 | 0xf4, 0x4b, 0xf6, 0xf4 }, | ||
50 | }; | ||
51 | |||
52 | /* | ||
53 | * The NACA. The first dword of the naca is required by the iSeries | ||
54 | * hypervisor to point to itVpdAreas. The hypervisor finds the NACA | ||
55 | * through the pointer in hvReleaseData. | ||
56 | */ | ||
57 | struct naca_struct naca = { | ||
58 | .xItVpdAreas = &itVpdAreas, | ||
59 | .xRamDisk = 0, | ||
60 | .xRamDiskSize = 0, | ||
61 | }; | ||
62 | |||
63 | struct ItLpRegSave { | ||
64 | u32 xDesc; // Eye catcher "LpRS" ebcdic 000-003 | ||
65 | u16 xSize; // Size of this class 004-005 | ||
66 | u8 xInUse; // Area is live 006-007 | ||
67 | u8 xRsvd1[9]; // Reserved 007-00F | ||
68 | |||
69 | u8 xFixedRegSave[352]; // Fixed Register Save Area 010-16F | ||
70 | u32 xCTRL; // Control Register 170-173 | ||
71 | u32 xDEC; // Decrementer 174-177 | ||
72 | u32 xFPSCR; // FP Status and Control Reg 178-17B | ||
73 | u32 xPVR; // Processor Version Number 17C-17F | ||
74 | |||
75 | u64 xMMCR0; // Monitor Mode Control Reg 0 180-187 | ||
76 | u32 xPMC1; // Perf Monitor Counter 1 188-18B | ||
77 | u32 xPMC2; // Perf Monitor Counter 2 18C-18F | ||
78 | u32 xPMC3; // Perf Monitor Counter 3 190-193 | ||
79 | u32 xPMC4; // Perf Monitor Counter 4 194-197 | ||
80 | u32 xPIR; // Processor ID Reg 198-19B | ||
81 | |||
82 | u32 xMMCR1; // Monitor Mode Control Reg 1 19C-19F | ||
83 | u32 xMMCRA; // Monitor Mode Control Reg A 1A0-1A3 | ||
84 | u32 xPMC5; // Perf Monitor Counter 5 1A4-1A7 | ||
85 | u32 xPMC6; // Perf Monitor Counter 6 1A8-1AB | ||
86 | u32 xPMC7; // Perf Monitor Counter 7 1AC-1AF | ||
87 | u32 xPMC8; // Perf Monitor Counter 8 1B0-1B3 | ||
88 | u32 xTSC; // Thread Switch Control 1B4-1B7 | ||
89 | u32 xTST; // Thread Switch Timeout 1B8-1BB | ||
90 | u32 xRsvd; // Reserved 1BC-1BF | ||
91 | |||
92 | u64 xACCR; // Address Compare Control Reg 1C0-1C7 | ||
93 | u64 xIMR; // Instruction Match Register 1C8-1CF | ||
94 | u64 xSDR1; // Storage Description Reg 1 1D0-1D7 | ||
95 | u64 xSPRG0; // Special Purpose Reg General0 1D8-1DF | ||
96 | u64 xSPRG1; // Special Purpose Reg General1 1E0-1E7 | ||
97 | u64 xSPRG2; // Special Purpose Reg General2 1E8-1EF | ||
98 | u64 xSPRG3; // Special Purpose Reg General3 1F0-1F7 | ||
99 | u64 xTB; // Time Base Register 1F8-1FF | ||
100 | |||
101 | u64 xFPR[32]; // Floating Point Registers 200-2FF | ||
102 | |||
103 | u64 xMSR; // Machine State Register 300-307 | ||
104 | u64 xNIA; // Next Instruction Address 308-30F | ||
105 | |||
106 | u64 xDABR; // Data Address Breakpoint Reg 310-317 | ||
107 | u64 xIABR; // Inst Address Breakpoint Reg 318-31F | ||
108 | |||
109 | u64 xHID0; // HW Implementation Dependent0 320-327 | ||
110 | |||
111 | u64 xHID4; // HW Implementation Dependent4 328-32F | ||
112 | u64 xSCOMd; // SCON Data Reg (SPRG4) 330-337 | ||
113 | u64 xSCOMc; // SCON Command Reg (SPRG5) 338-33F | ||
114 | u64 xSDAR; // Sample Data Address Register 340-347 | ||
115 | u64 xSIAR; // Sample Inst Address Register 348-34F | ||
116 | |||
117 | u8 xRsvd3[176]; // Reserved 350-3FF | ||
118 | }; | ||
119 | |||
120 | extern void system_reset_iSeries(void); | ||
121 | extern void machine_check_iSeries(void); | ||
122 | extern void data_access_iSeries(void); | ||
123 | extern void instruction_access_iSeries(void); | ||
124 | extern void hardware_interrupt_iSeries(void); | ||
125 | extern void alignment_iSeries(void); | ||
126 | extern void program_check_iSeries(void); | ||
127 | extern void fp_unavailable_iSeries(void); | ||
128 | extern void decrementer_iSeries(void); | ||
129 | extern void trap_0a_iSeries(void); | ||
130 | extern void trap_0b_iSeries(void); | ||
131 | extern void system_call_iSeries(void); | ||
132 | extern void single_step_iSeries(void); | ||
133 | extern void trap_0e_iSeries(void); | ||
134 | extern void performance_monitor_iSeries(void); | ||
135 | extern void data_access_slb_iSeries(void); | ||
136 | extern void instruction_access_slb_iSeries(void); | ||
137 | |||
138 | struct ItLpNaca itLpNaca = { | ||
139 | .xDesc = 0xd397d581, /* "LpNa" ebcdic */ | ||
140 | .xSize = 0x0400, /* size of ItLpNaca */ | ||
141 | .xIntHdlrOffset = 0x0300, /* offset to int array */ | ||
142 | .xMaxIntHdlrEntries = 19, /* # ents */ | ||
143 | .xPrimaryLpIndex = 0, /* Part # of primary */ | ||
144 | .xServiceLpIndex = 0, /* Part # of serv */ | ||
145 | .xLpIndex = 0, /* Part # of me */ | ||
146 | .xMaxLpQueues = 0, /* # of LP queues */ | ||
147 | .xLpQueueOffset = 0x100, /* offset of start of LP queues */ | ||
148 | .xPirEnvironMode = 0, /* Piranha stuff */ | ||
149 | .xPirConsoleMode = 0, | ||
150 | .xPirDasdMode = 0, | ||
151 | .flags = 0, | ||
152 | .xSpVpdFormat = 0, | ||
153 | .xIntProcRatio = 0, | ||
154 | .xPlicVrmIndex = 0, /* VRM index of PLIC */ | ||
155 | .xMinSupportedSlicVrmInd = 0, /* min supported SLIC */ | ||
156 | .xMinCompatableSlicVrmInd = 0, /* min compat SLIC */ | ||
157 | .xLoadAreaAddr = 0, /* 64-bit addr of load area */ | ||
158 | .xLoadAreaChunks = 0, /* chunks for load area */ | ||
159 | .xPaseSysCallCRMask = 0, /* PASE mask */ | ||
160 | .xSlicSegmentTablePtr = 0, /* seg table */ | ||
161 | .xOldLpQueue = { 0 }, /* Old LP Queue */ | ||
162 | .xInterruptHdlr = { | ||
163 | (u64)system_reset_iSeries, /* 0x100 System Reset */ | ||
164 | (u64)machine_check_iSeries, /* 0x200 Machine Check */ | ||
165 | (u64)data_access_iSeries, /* 0x300 Data Access */ | ||
166 | (u64)instruction_access_iSeries, /* 0x400 Instruction Access */ | ||
167 | (u64)hardware_interrupt_iSeries, /* 0x500 External */ | ||
168 | (u64)alignment_iSeries, /* 0x600 Alignment */ | ||
169 | (u64)program_check_iSeries, /* 0x700 Program Check */ | ||
170 | (u64)fp_unavailable_iSeries, /* 0x800 FP Unavailable */ | ||
171 | (u64)decrementer_iSeries, /* 0x900 Decrementer */ | ||
172 | (u64)trap_0a_iSeries, /* 0xa00 Trap 0A */ | ||
173 | (u64)trap_0b_iSeries, /* 0xb00 Trap 0B */ | ||
174 | (u64)system_call_iSeries, /* 0xc00 System Call */ | ||
175 | (u64)single_step_iSeries, /* 0xd00 Single Step */ | ||
176 | (u64)trap_0e_iSeries, /* 0xe00 Trap 0E */ | ||
177 | (u64)performance_monitor_iSeries,/* 0xf00 Performance Monitor */ | ||
178 | 0, /* int 0x1000 */ | ||
179 | 0, /* int 0x1010 */ | ||
180 | 0, /* int 0x1020 CPU ctls */ | ||
181 | (u64)hardware_interrupt_iSeries, /* SC Ret Hdlr */ | ||
182 | (u64)data_access_slb_iSeries, /* 0x380 D-SLB */ | ||
183 | (u64)instruction_access_slb_iSeries /* 0x480 I-SLB */ | ||
184 | } | ||
185 | }; | ||
186 | |||
187 | /* May be filled in by the hypervisor so cannot end up in the BSS */ | ||
188 | static struct ItIplParmsReal xItIplParmsReal __attribute__((__section__(".data"))); | ||
189 | |||
190 | /* May be filled in by the hypervisor so cannot end up in the BSS */ | ||
191 | struct ItExtVpdPanel xItExtVpdPanel __attribute__((__section__(".data"))); | ||
192 | |||
193 | #define maxPhysicalProcessors 32 | ||
194 | |||
195 | struct IoHriProcessorVpd xIoHriProcessorVpd[maxPhysicalProcessors] = { | ||
196 | { | ||
197 | .xInstCacheOperandSize = 32, | ||
198 | .xDataCacheOperandSize = 32, | ||
199 | .xProcFreq = 50000000, | ||
200 | .xTimeBaseFreq = 50000000, | ||
201 | .xPVR = 0x3600 | ||
202 | } | ||
203 | }; | ||
204 | |||
205 | /* Space for Main Store Vpd 27,200 bytes */ | ||
206 | /* May be filled in by the hypervisor so cannot end up in the BSS */ | ||
207 | u64 xMsVpd[3400] __attribute__((__section__(".data"))); | ||
208 | |||
209 | /* Space for Recovery Log Buffer */ | ||
210 | /* May be filled in by the hypervisor so cannot end up in the BSS */ | ||
211 | static u64 xRecoveryLogBuffer[32] __attribute__((__section__(".data"))); | ||
212 | |||
213 | static const struct SpCommArea xSpCommArea = { | ||
214 | .xDesc = 0xE2D7C3C2, | ||
215 | .xFormat = 1, | ||
216 | }; | ||
217 | |||
218 | static const struct ItLpRegSave iseries_reg_save[] = { | ||
219 | [0 ... (NR_CPUS-1)] = { | ||
220 | .xDesc = 0xd397d9e2, /* "LpRS" */ | ||
221 | .xSize = sizeof(struct ItLpRegSave), | ||
222 | }, | ||
223 | }; | ||
224 | |||
225 | #define ALPACA_INIT(number) \ | ||
226 | { \ | ||
227 | .lppaca_ptr = &lppaca[number], \ | ||
228 | .reg_save_ptr = &iseries_reg_save[number], \ | ||
229 | } | ||
230 | |||
231 | const struct alpaca alpaca[] = { | ||
232 | ALPACA_INIT( 0), | ||
233 | #if NR_CPUS > 1 | ||
234 | ALPACA_INIT( 1), ALPACA_INIT( 2), ALPACA_INIT( 3), | ||
235 | #if NR_CPUS > 4 | ||
236 | ALPACA_INIT( 4), ALPACA_INIT( 5), ALPACA_INIT( 6), ALPACA_INIT( 7), | ||
237 | #if NR_CPUS > 8 | ||
238 | ALPACA_INIT( 8), ALPACA_INIT( 9), ALPACA_INIT(10), ALPACA_INIT(11), | ||
239 | ALPACA_INIT(12), ALPACA_INIT(13), ALPACA_INIT(14), ALPACA_INIT(15), | ||
240 | ALPACA_INIT(16), ALPACA_INIT(17), ALPACA_INIT(18), ALPACA_INIT(19), | ||
241 | ALPACA_INIT(20), ALPACA_INIT(21), ALPACA_INIT(22), ALPACA_INIT(23), | ||
242 | ALPACA_INIT(24), ALPACA_INIT(25), ALPACA_INIT(26), ALPACA_INIT(27), | ||
243 | ALPACA_INIT(28), ALPACA_INIT(29), ALPACA_INIT(30), ALPACA_INIT(31), | ||
244 | #if NR_CPUS > 32 | ||
245 | ALPACA_INIT(32), ALPACA_INIT(33), ALPACA_INIT(34), ALPACA_INIT(35), | ||
246 | ALPACA_INIT(36), ALPACA_INIT(37), ALPACA_INIT(38), ALPACA_INIT(39), | ||
247 | ALPACA_INIT(40), ALPACA_INIT(41), ALPACA_INIT(42), ALPACA_INIT(43), | ||
248 | ALPACA_INIT(44), ALPACA_INIT(45), ALPACA_INIT(46), ALPACA_INIT(47), | ||
249 | ALPACA_INIT(48), ALPACA_INIT(49), ALPACA_INIT(50), ALPACA_INIT(51), | ||
250 | ALPACA_INIT(52), ALPACA_INIT(53), ALPACA_INIT(54), ALPACA_INIT(55), | ||
251 | ALPACA_INIT(56), ALPACA_INIT(57), ALPACA_INIT(58), ALPACA_INIT(59), | ||
252 | ALPACA_INIT(60), ALPACA_INIT(61), ALPACA_INIT(62), ALPACA_INIT(63), | ||
253 | #endif | ||
254 | #endif | ||
255 | #endif | ||
256 | #endif | ||
257 | }; | ||
258 | |||
259 | /* The LparMap data is now located at offset 0x6000 in head.S | ||
260 | * It was put there so that the HvReleaseData could address it | ||
261 | * with a 32-bit offset as required by the iSeries hypervisor | ||
262 | * | ||
263 | * The Naca has a pointer to the ItVpdAreas. The hypervisor finds | ||
264 | * the Naca via the HvReleaseData area. The HvReleaseData has the | ||
265 | * offset into the Naca of the pointer to the ItVpdAreas. | ||
266 | */ | ||
267 | const struct ItVpdAreas itVpdAreas = { | ||
268 | .xSlicDesc = 0xc9a3e5c1, /* "ItVA" */ | ||
269 | .xSlicSize = sizeof(struct ItVpdAreas), | ||
270 | .xSlicVpdEntries = ItVpdMaxEntries, /* # VPD array entries */ | ||
271 | .xSlicDmaEntries = ItDmaMaxEntries, /* # DMA array entries */ | ||
272 | .xSlicMaxLogicalProcs = NR_CPUS * 2, /* Max logical procs */ | ||
273 | .xSlicMaxPhysicalProcs = maxPhysicalProcessors, /* Max physical procs */ | ||
274 | .xSlicDmaToksOffset = offsetof(struct ItVpdAreas, xPlicDmaToks), | ||
275 | .xSlicVpdAdrsOffset = offsetof(struct ItVpdAreas, xSlicVpdAdrs), | ||
276 | .xSlicDmaLensOffset = offsetof(struct ItVpdAreas, xPlicDmaLens), | ||
277 | .xSlicVpdLensOffset = offsetof(struct ItVpdAreas, xSlicVpdLens), | ||
278 | .xSlicMaxSlotLabels = 0, /* max slot labels */ | ||
279 | .xSlicMaxLpQueues = 1, /* max LP queues */ | ||
280 | .xPlicDmaLens = { 0 }, /* DMA lengths */ | ||
281 | .xPlicDmaToks = { 0 }, /* DMA tokens */ | ||
282 | .xSlicVpdLens = { /* VPD lengths */ | ||
283 | 0,0,0, /* 0 - 2 */ | ||
284 | sizeof(xItExtVpdPanel), /* 3 Extended VPD */ | ||
285 | sizeof(struct alpaca), /* 4 length of (fake) Paca */ | ||
286 | 0, /* 5 */ | ||
287 | sizeof(struct ItIplParmsReal),/* 6 length of IPL parms */ | ||
288 | 26992, /* 7 length of MS VPD */ | ||
289 | 0, /* 8 */ | ||
290 | sizeof(struct ItLpNaca),/* 9 length of LP Naca */ | ||
291 | 0, /* 10 */ | ||
292 | 256, /* 11 length of Recovery Log Buf */ | ||
293 | sizeof(struct SpCommArea), /* 12 length of SP Comm Area */ | ||
294 | 0,0,0, /* 13 - 15 */ | ||
295 | sizeof(struct IoHriProcessorVpd),/* 16 length of Proc Vpd */ | ||
296 | 0,0,0,0,0,0, /* 17 - 22 */ | ||
297 | sizeof(struct hvlpevent_queue), /* 23 length of Lp Queue */ | ||
298 | 0,0 /* 24 - 25 */ | ||
299 | }, | ||
300 | .xSlicVpdAdrs = { /* VPD addresses */ | ||
301 | 0,0,0, /* 0 - 2 */ | ||
302 | &xItExtVpdPanel, /* 3 Extended VPD */ | ||
303 | &alpaca[0], /* 4 first (fake) Paca */ | ||
304 | 0, /* 5 */ | ||
305 | &xItIplParmsReal, /* 6 IPL parms */ | ||
306 | &xMsVpd, /* 7 MS Vpd */ | ||
307 | 0, /* 8 */ | ||
308 | &itLpNaca, /* 9 LpNaca */ | ||
309 | 0, /* 10 */ | ||
310 | &xRecoveryLogBuffer, /* 11 Recovery Log Buffer */ | ||
311 | &xSpCommArea, /* 12 SP Comm Area */ | ||
312 | 0,0,0, /* 13 - 15 */ | ||
313 | &xIoHriProcessorVpd, /* 16 Proc Vpd */ | ||
314 | 0,0,0,0,0,0, /* 17 - 22 */ | ||
315 | &hvlpevent_queue, /* 23 Lp Queue */ | ||
316 | 0,0 | ||
317 | } | ||
318 | }; | ||
diff --git a/arch/powerpc/platforms/iseries/lpevents.c b/arch/powerpc/platforms/iseries/lpevents.c deleted file mode 100644 index 202e22798d30..000000000000 --- a/arch/powerpc/platforms/iseries/lpevents.c +++ /dev/null | |||
@@ -1,341 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001 Mike Corrigan IBM Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | */ | ||
9 | |||
10 | #include <linux/stddef.h> | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/sched.h> | ||
13 | #include <linux/bootmem.h> | ||
14 | #include <linux/seq_file.h> | ||
15 | #include <linux/proc_fs.h> | ||
16 | #include <linux/export.h> | ||
17 | |||
18 | #include <asm/system.h> | ||
19 | #include <asm/paca.h> | ||
20 | #include <asm/firmware.h> | ||
21 | #include <asm/iseries/it_lp_queue.h> | ||
22 | #include <asm/iseries/hv_lp_event.h> | ||
23 | #include <asm/iseries/hv_call_event.h> | ||
24 | #include "it_lp_naca.h" | ||
25 | |||
26 | /* | ||
27 | * The LpQueue is used to pass event data from the hypervisor to | ||
28 | * the partition. This is where I/O interrupt events are communicated. | ||
29 | * | ||
30 | * It is written to by the hypervisor so cannot end up in the BSS. | ||
31 | */ | ||
32 | struct hvlpevent_queue hvlpevent_queue __attribute__((__section__(".data"))); | ||
33 | |||
34 | DEFINE_PER_CPU(unsigned long[HvLpEvent_Type_NumTypes], hvlpevent_counts); | ||
35 | |||
36 | static char *event_types[HvLpEvent_Type_NumTypes] = { | ||
37 | "Hypervisor", | ||
38 | "Machine Facilities", | ||
39 | "Session Manager", | ||
40 | "SPD I/O", | ||
41 | "Virtual Bus", | ||
42 | "PCI I/O", | ||
43 | "RIO I/O", | ||
44 | "Virtual Lan", | ||
45 | "Virtual I/O" | ||
46 | }; | ||
47 | |||
48 | /* Array of LpEvent handler functions */ | ||
49 | static LpEventHandler lpEventHandler[HvLpEvent_Type_NumTypes]; | ||
50 | static unsigned lpEventHandlerPaths[HvLpEvent_Type_NumTypes]; | ||
51 | |||
52 | static struct HvLpEvent * get_next_hvlpevent(void) | ||
53 | { | ||
54 | struct HvLpEvent * event; | ||
55 | event = (struct HvLpEvent *)hvlpevent_queue.hq_current_event; | ||
56 | |||
57 | if (hvlpevent_is_valid(event)) { | ||
58 | /* rmb() needed only for weakly consistent machines (regatta) */ | ||
59 | rmb(); | ||
60 | /* Set pointer to next potential event */ | ||
61 | hvlpevent_queue.hq_current_event += ((event->xSizeMinus1 + | ||
62 | IT_LP_EVENT_ALIGN) / IT_LP_EVENT_ALIGN) * | ||
63 | IT_LP_EVENT_ALIGN; | ||
64 | |||
65 | /* Wrap to beginning if no room at end */ | ||
66 | if (hvlpevent_queue.hq_current_event > | ||
67 | hvlpevent_queue.hq_last_event) { | ||
68 | hvlpevent_queue.hq_current_event = | ||
69 | hvlpevent_queue.hq_event_stack; | ||
70 | } | ||
71 | } else { | ||
72 | event = NULL; | ||
73 | } | ||
74 | |||
75 | return event; | ||
76 | } | ||
77 | |||
78 | static unsigned long spread_lpevents = NR_CPUS; | ||
79 | |||
80 | int hvlpevent_is_pending(void) | ||
81 | { | ||
82 | struct HvLpEvent *next_event; | ||
83 | |||
84 | if (smp_processor_id() >= spread_lpevents) | ||
85 | return 0; | ||
86 | |||
87 | next_event = (struct HvLpEvent *)hvlpevent_queue.hq_current_event; | ||
88 | |||
89 | return hvlpevent_is_valid(next_event) || | ||
90 | hvlpevent_queue.hq_overflow_pending; | ||
91 | } | ||
92 | |||
93 | static void hvlpevent_clear_valid(struct HvLpEvent * event) | ||
94 | { | ||
95 | /* Tell the Hypervisor that we're done with this event. | ||
96 | * Also clear bits within this event that might look like valid bits. | ||
97 | * ie. on 64-byte boundaries. | ||
98 | */ | ||
99 | struct HvLpEvent *tmp; | ||
100 | unsigned extra = ((event->xSizeMinus1 + IT_LP_EVENT_ALIGN) / | ||
101 | IT_LP_EVENT_ALIGN) - 1; | ||
102 | |||
103 | switch (extra) { | ||
104 | case 3: | ||
105 | tmp = (struct HvLpEvent*)((char*)event + 3 * IT_LP_EVENT_ALIGN); | ||
106 | hvlpevent_invalidate(tmp); | ||
107 | case 2: | ||
108 | tmp = (struct HvLpEvent*)((char*)event + 2 * IT_LP_EVENT_ALIGN); | ||
109 | hvlpevent_invalidate(tmp); | ||
110 | case 1: | ||
111 | tmp = (struct HvLpEvent*)((char*)event + 1 * IT_LP_EVENT_ALIGN); | ||
112 | hvlpevent_invalidate(tmp); | ||
113 | } | ||
114 | |||
115 | mb(); | ||
116 | |||
117 | hvlpevent_invalidate(event); | ||
118 | } | ||
119 | |||
120 | void process_hvlpevents(void) | ||
121 | { | ||
122 | struct HvLpEvent * event; | ||
123 | |||
124 | restart: | ||
125 | /* If we have recursed, just return */ | ||
126 | if (!spin_trylock(&hvlpevent_queue.hq_lock)) | ||
127 | return; | ||
128 | |||
129 | for (;;) { | ||
130 | event = get_next_hvlpevent(); | ||
131 | if (event) { | ||
132 | /* Call appropriate handler here, passing | ||
133 | * a pointer to the LpEvent. The handler | ||
134 | * must make a copy of the LpEvent if it | ||
135 | * needs it in a bottom half. (perhaps for | ||
136 | * an ACK) | ||
137 | * | ||
138 | * Handlers are responsible for ACK processing | ||
139 | * | ||
140 | * The Hypervisor guarantees that LpEvents will | ||
141 | * only be delivered with types that we have | ||
142 | * registered for, so no type check is necessary | ||
143 | * here! | ||
144 | */ | ||
145 | if (event->xType < HvLpEvent_Type_NumTypes) | ||
146 | __get_cpu_var(hvlpevent_counts)[event->xType]++; | ||
147 | if (event->xType < HvLpEvent_Type_NumTypes && | ||
148 | lpEventHandler[event->xType]) | ||
149 | lpEventHandler[event->xType](event); | ||
150 | else { | ||
151 | u8 type = event->xType; | ||
152 | |||
153 | /* | ||
154 | * Don't printk in the spinlock as printk | ||
155 | * may require ack events form the HV to send | ||
156 | * any characters there. | ||
157 | */ | ||
158 | hvlpevent_clear_valid(event); | ||
159 | spin_unlock(&hvlpevent_queue.hq_lock); | ||
160 | printk(KERN_INFO | ||
161 | "Unexpected Lp Event type=%d\n", type); | ||
162 | goto restart; | ||
163 | } | ||
164 | |||
165 | hvlpevent_clear_valid(event); | ||
166 | } else if (hvlpevent_queue.hq_overflow_pending) | ||
167 | /* | ||
168 | * No more valid events. If overflow events are | ||
169 | * pending process them | ||
170 | */ | ||
171 | HvCallEvent_getOverflowLpEvents(hvlpevent_queue.hq_index); | ||
172 | else | ||
173 | break; | ||
174 | } | ||
175 | |||
176 | spin_unlock(&hvlpevent_queue.hq_lock); | ||
177 | } | ||
178 | |||
179 | static int set_spread_lpevents(char *str) | ||
180 | { | ||
181 | unsigned long val = simple_strtoul(str, NULL, 0); | ||
182 | |||
183 | /* | ||
184 | * The parameter is the number of processors to share in processing | ||
185 | * lp events. | ||
186 | */ | ||
187 | if (( val > 0) && (val <= NR_CPUS)) { | ||
188 | spread_lpevents = val; | ||
189 | printk("lpevent processing spread over %ld processors\n", val); | ||
190 | } else { | ||
191 | printk("invalid spread_lpevents %ld\n", val); | ||
192 | } | ||
193 | |||
194 | return 1; | ||
195 | } | ||
196 | __setup("spread_lpevents=", set_spread_lpevents); | ||
197 | |||
198 | void __init setup_hvlpevent_queue(void) | ||
199 | { | ||
200 | void *eventStack; | ||
201 | |||
202 | spin_lock_init(&hvlpevent_queue.hq_lock); | ||
203 | |||
204 | /* Allocate a page for the Event Stack. */ | ||
205 | eventStack = alloc_bootmem_pages(IT_LP_EVENT_STACK_SIZE); | ||
206 | memset(eventStack, 0, IT_LP_EVENT_STACK_SIZE); | ||
207 | |||
208 | /* Invoke the hypervisor to initialize the event stack */ | ||
209 | HvCallEvent_setLpEventStack(0, eventStack, IT_LP_EVENT_STACK_SIZE); | ||
210 | |||
211 | hvlpevent_queue.hq_event_stack = eventStack; | ||
212 | hvlpevent_queue.hq_current_event = eventStack; | ||
213 | hvlpevent_queue.hq_last_event = (char *)eventStack + | ||
214 | (IT_LP_EVENT_STACK_SIZE - IT_LP_EVENT_MAX_SIZE); | ||
215 | hvlpevent_queue.hq_index = 0; | ||
216 | } | ||
217 | |||
218 | /* Register a handler for an LpEvent type */ | ||
219 | int HvLpEvent_registerHandler(HvLpEvent_Type eventType, LpEventHandler handler) | ||
220 | { | ||
221 | if (eventType < HvLpEvent_Type_NumTypes) { | ||
222 | lpEventHandler[eventType] = handler; | ||
223 | return 0; | ||
224 | } | ||
225 | return 1; | ||
226 | } | ||
227 | EXPORT_SYMBOL(HvLpEvent_registerHandler); | ||
228 | |||
229 | int HvLpEvent_unregisterHandler(HvLpEvent_Type eventType) | ||
230 | { | ||
231 | might_sleep(); | ||
232 | |||
233 | if (eventType < HvLpEvent_Type_NumTypes) { | ||
234 | if (!lpEventHandlerPaths[eventType]) { | ||
235 | lpEventHandler[eventType] = NULL; | ||
236 | /* | ||
237 | * We now sleep until all other CPUs have scheduled. | ||
238 | * This ensures that the deletion is seen by all | ||
239 | * other CPUs, and that the deleted handler isn't | ||
240 | * still running on another CPU when we return. | ||
241 | */ | ||
242 | synchronize_sched(); | ||
243 | return 0; | ||
244 | } | ||
245 | } | ||
246 | return 1; | ||
247 | } | ||
248 | EXPORT_SYMBOL(HvLpEvent_unregisterHandler); | ||
249 | |||
250 | /* | ||
251 | * lpIndex is the partition index of the target partition. | ||
252 | * needed only for VirtualIo, VirtualLan and SessionMgr. Zero | ||
253 | * indicates to use our partition index - for the other types. | ||
254 | */ | ||
255 | int HvLpEvent_openPath(HvLpEvent_Type eventType, HvLpIndex lpIndex) | ||
256 | { | ||
257 | if ((eventType < HvLpEvent_Type_NumTypes) && | ||
258 | lpEventHandler[eventType]) { | ||
259 | if (lpIndex == 0) | ||
260 | lpIndex = itLpNaca.xLpIndex; | ||
261 | HvCallEvent_openLpEventPath(lpIndex, eventType); | ||
262 | ++lpEventHandlerPaths[eventType]; | ||
263 | return 0; | ||
264 | } | ||
265 | return 1; | ||
266 | } | ||
267 | |||
268 | int HvLpEvent_closePath(HvLpEvent_Type eventType, HvLpIndex lpIndex) | ||
269 | { | ||
270 | if ((eventType < HvLpEvent_Type_NumTypes) && | ||
271 | lpEventHandler[eventType] && | ||
272 | lpEventHandlerPaths[eventType]) { | ||
273 | if (lpIndex == 0) | ||
274 | lpIndex = itLpNaca.xLpIndex; | ||
275 | HvCallEvent_closeLpEventPath(lpIndex, eventType); | ||
276 | --lpEventHandlerPaths[eventType]; | ||
277 | return 0; | ||
278 | } | ||
279 | return 1; | ||
280 | } | ||
281 | |||
282 | static int proc_lpevents_show(struct seq_file *m, void *v) | ||
283 | { | ||
284 | int cpu, i; | ||
285 | unsigned long sum; | ||
286 | static unsigned long cpu_totals[NR_CPUS]; | ||
287 | |||
288 | /* FIXME: do we care that there's no locking here? */ | ||
289 | sum = 0; | ||
290 | for_each_online_cpu(cpu) { | ||
291 | cpu_totals[cpu] = 0; | ||
292 | for (i = 0; i < HvLpEvent_Type_NumTypes; i++) { | ||
293 | cpu_totals[cpu] += per_cpu(hvlpevent_counts, cpu)[i]; | ||
294 | } | ||
295 | sum += cpu_totals[cpu]; | ||
296 | } | ||
297 | |||
298 | seq_printf(m, "LpEventQueue 0\n"); | ||
299 | seq_printf(m, " events processed:\t%lu\n", sum); | ||
300 | |||
301 | for (i = 0; i < HvLpEvent_Type_NumTypes; ++i) { | ||
302 | sum = 0; | ||
303 | for_each_online_cpu(cpu) { | ||
304 | sum += per_cpu(hvlpevent_counts, cpu)[i]; | ||
305 | } | ||
306 | |||
307 | seq_printf(m, " %-20s %10lu\n", event_types[i], sum); | ||
308 | } | ||
309 | |||
310 | seq_printf(m, "\n events processed by processor:\n"); | ||
311 | |||
312 | for_each_online_cpu(cpu) { | ||
313 | seq_printf(m, " CPU%02d %10lu\n", cpu, cpu_totals[cpu]); | ||
314 | } | ||
315 | |||
316 | return 0; | ||
317 | } | ||
318 | |||
319 | static int proc_lpevents_open(struct inode *inode, struct file *file) | ||
320 | { | ||
321 | return single_open(file, proc_lpevents_show, NULL); | ||
322 | } | ||
323 | |||
324 | static const struct file_operations proc_lpevents_operations = { | ||
325 | .open = proc_lpevents_open, | ||
326 | .read = seq_read, | ||
327 | .llseek = seq_lseek, | ||
328 | .release = single_release, | ||
329 | }; | ||
330 | |||
331 | static int __init proc_lpevents_init(void) | ||
332 | { | ||
333 | if (!firmware_has_feature(FW_FEATURE_ISERIES)) | ||
334 | return 0; | ||
335 | |||
336 | proc_create("iSeries/lpevents", S_IFREG|S_IRUGO, NULL, | ||
337 | &proc_lpevents_operations); | ||
338 | return 0; | ||
339 | } | ||
340 | __initcall(proc_lpevents_init); | ||
341 | |||
diff --git a/arch/powerpc/platforms/iseries/main_store.h b/arch/powerpc/platforms/iseries/main_store.h deleted file mode 100644 index 1a7a3f50e40b..000000000000 --- a/arch/powerpc/platforms/iseries/main_store.h +++ /dev/null | |||
@@ -1,165 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001 Mike Corrigan IBM Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | |||
19 | #ifndef _ISERIES_MAIN_STORE_H | ||
20 | #define _ISERIES_MAIN_STORE_H | ||
21 | |||
22 | /* Main Store Vpd for Condor,iStar,sStar */ | ||
23 | struct IoHriMainStoreSegment4 { | ||
24 | u8 msArea0Exists:1; | ||
25 | u8 msArea1Exists:1; | ||
26 | u8 msArea2Exists:1; | ||
27 | u8 msArea3Exists:1; | ||
28 | u8 reserved1:4; | ||
29 | u8 reserved2; | ||
30 | |||
31 | u8 msArea0Functional:1; | ||
32 | u8 msArea1Functional:1; | ||
33 | u8 msArea2Functional:1; | ||
34 | u8 msArea3Functional:1; | ||
35 | u8 reserved3:4; | ||
36 | u8 reserved4; | ||
37 | |||
38 | u32 totalMainStore; | ||
39 | |||
40 | u64 msArea0Ptr; | ||
41 | u64 msArea1Ptr; | ||
42 | u64 msArea2Ptr; | ||
43 | u64 msArea3Ptr; | ||
44 | |||
45 | u32 cardProductionLevel; | ||
46 | |||
47 | u32 msAdrHole; | ||
48 | |||
49 | u8 msArea0HasRiserVpd:1; | ||
50 | u8 msArea1HasRiserVpd:1; | ||
51 | u8 msArea2HasRiserVpd:1; | ||
52 | u8 msArea3HasRiserVpd:1; | ||
53 | u8 reserved5:4; | ||
54 | u8 reserved6; | ||
55 | u16 reserved7; | ||
56 | |||
57 | u8 reserved8[28]; | ||
58 | |||
59 | u64 nonInterleavedBlocksStartAdr; | ||
60 | u64 nonInterleavedBlocksEndAdr; | ||
61 | }; | ||
62 | |||
63 | /* Main Store VPD for Power4 */ | ||
64 | struct __attribute((packed)) IoHriMainStoreChipInfo1 { | ||
65 | u32 chipMfgID; | ||
66 | char chipECLevel[4]; | ||
67 | }; | ||
68 | |||
69 | struct IoHriMainStoreVpdIdData { | ||
70 | char typeNumber[4]; | ||
71 | char modelNumber[4]; | ||
72 | char partNumber[12]; | ||
73 | char serialNumber[12]; | ||
74 | }; | ||
75 | |||
76 | struct __attribute((packed)) IoHriMainStoreVpdFruData { | ||
77 | char fruLabel[8]; | ||
78 | u8 numberOfSlots; | ||
79 | u8 pluggingType; | ||
80 | u16 slotMapIndex; | ||
81 | }; | ||
82 | |||
83 | struct __attribute((packed)) IoHriMainStoreAdrRangeBlock { | ||
84 | void *blockStart; | ||
85 | void *blockEnd; | ||
86 | u32 blockProcChipId; | ||
87 | }; | ||
88 | |||
89 | #define MaxAreaAdrRangeBlocks 4 | ||
90 | |||
91 | struct __attribute((packed)) IoHriMainStoreArea4 { | ||
92 | u32 msVpdFormat; | ||
93 | u8 containedVpdType; | ||
94 | u8 reserved1; | ||
95 | u16 reserved2; | ||
96 | |||
97 | u64 msExists; | ||
98 | u64 msFunctional; | ||
99 | |||
100 | u32 memorySize; | ||
101 | u32 procNodeId; | ||
102 | |||
103 | u32 numAdrRangeBlocks; | ||
104 | struct IoHriMainStoreAdrRangeBlock xAdrRangeBlock[MaxAreaAdrRangeBlocks]; | ||
105 | |||
106 | struct IoHriMainStoreChipInfo1 chipInfo0; | ||
107 | struct IoHriMainStoreChipInfo1 chipInfo1; | ||
108 | struct IoHriMainStoreChipInfo1 chipInfo2; | ||
109 | struct IoHriMainStoreChipInfo1 chipInfo3; | ||
110 | struct IoHriMainStoreChipInfo1 chipInfo4; | ||
111 | struct IoHriMainStoreChipInfo1 chipInfo5; | ||
112 | struct IoHriMainStoreChipInfo1 chipInfo6; | ||
113 | struct IoHriMainStoreChipInfo1 chipInfo7; | ||
114 | |||
115 | void *msRamAreaArray; | ||
116 | u32 msRamAreaArrayNumEntries; | ||
117 | u32 msRamAreaArrayEntrySize; | ||
118 | |||
119 | u32 numaDimmExists; | ||
120 | u32 numaDimmFunctional; | ||
121 | void *numaDimmArray; | ||
122 | u32 numaDimmArrayNumEntries; | ||
123 | u32 numaDimmArrayEntrySize; | ||
124 | |||
125 | struct IoHriMainStoreVpdIdData idData; | ||
126 | |||
127 | u64 powerData; | ||
128 | u64 cardAssemblyPartNum; | ||
129 | u64 chipSerialNum; | ||
130 | |||
131 | u64 reserved3; | ||
132 | char reserved4[16]; | ||
133 | |||
134 | struct IoHriMainStoreVpdFruData fruData; | ||
135 | |||
136 | u8 vpdPortNum; | ||
137 | u8 reserved5; | ||
138 | u8 frameId; | ||
139 | u8 rackUnit; | ||
140 | char asciiKeywordVpd[256]; | ||
141 | u32 reserved6; | ||
142 | }; | ||
143 | |||
144 | |||
145 | struct IoHriMainStoreSegment5 { | ||
146 | u16 reserved1; | ||
147 | u8 reserved2; | ||
148 | u8 msVpdFormat; | ||
149 | |||
150 | u32 totalMainStore; | ||
151 | u64 maxConfiguredMsAdr; | ||
152 | |||
153 | struct IoHriMainStoreArea4 *msAreaArray; | ||
154 | u32 msAreaArrayNumEntries; | ||
155 | u32 msAreaArrayEntrySize; | ||
156 | |||
157 | u32 msAreaExists; | ||
158 | u32 msAreaFunctional; | ||
159 | |||
160 | u64 reserved3; | ||
161 | }; | ||
162 | |||
163 | extern u64 xMsVpd[]; | ||
164 | |||
165 | #endif /* _ISERIES_MAIN_STORE_H */ | ||
diff --git a/arch/powerpc/platforms/iseries/mf.c b/arch/powerpc/platforms/iseries/mf.c deleted file mode 100644 index 254c1fc3d8dd..000000000000 --- a/arch/powerpc/platforms/iseries/mf.c +++ /dev/null | |||
@@ -1,1275 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001 Troy D. Armstrong IBM Corporation | ||
3 | * Copyright (C) 2004-2005 Stephen Rothwell IBM Corporation | ||
4 | * | ||
5 | * This modules exists as an interface between a Linux secondary partition | ||
6 | * running on an iSeries and the primary partition's Virtual Service | ||
7 | * Processor (VSP) object. The VSP has final authority over powering on/off | ||
8 | * all partitions in the iSeries. It also provides miscellaneous low-level | ||
9 | * machine facility type operations. | ||
10 | * | ||
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 as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
25 | */ | ||
26 | |||
27 | #include <linux/types.h> | ||
28 | #include <linux/errno.h> | ||
29 | #include <linux/kernel.h> | ||
30 | #include <linux/init.h> | ||
31 | #include <linux/completion.h> | ||
32 | #include <linux/delay.h> | ||
33 | #include <linux/export.h> | ||
34 | #include <linux/proc_fs.h> | ||
35 | #include <linux/dma-mapping.h> | ||
36 | #include <linux/bcd.h> | ||
37 | #include <linux/rtc.h> | ||
38 | #include <linux/slab.h> | ||
39 | |||
40 | #include <asm/time.h> | ||
41 | #include <asm/uaccess.h> | ||
42 | #include <asm/paca.h> | ||
43 | #include <asm/abs_addr.h> | ||
44 | #include <asm/firmware.h> | ||
45 | #include <asm/iseries/mf.h> | ||
46 | #include <asm/iseries/hv_lp_config.h> | ||
47 | #include <asm/iseries/hv_lp_event.h> | ||
48 | #include <asm/iseries/it_lp_queue.h> | ||
49 | |||
50 | #include "setup.h" | ||
51 | |||
52 | static int mf_initialized; | ||
53 | |||
54 | /* | ||
55 | * This is the structure layout for the Machine Facilities LPAR event | ||
56 | * flows. | ||
57 | */ | ||
58 | struct vsp_cmd_data { | ||
59 | u64 token; | ||
60 | u16 cmd; | ||
61 | HvLpIndex lp_index; | ||
62 | u8 result_code; | ||
63 | u32 reserved; | ||
64 | union { | ||
65 | u64 state; /* GetStateOut */ | ||
66 | u64 ipl_type; /* GetIplTypeOut, Function02SelectIplTypeIn */ | ||
67 | u64 ipl_mode; /* GetIplModeOut, Function02SelectIplModeIn */ | ||
68 | u64 page[4]; /* GetSrcHistoryIn */ | ||
69 | u64 flag; /* GetAutoIplWhenPrimaryIplsOut, | ||
70 | SetAutoIplWhenPrimaryIplsIn, | ||
71 | WhiteButtonPowerOffIn, | ||
72 | Function08FastPowerOffIn, | ||
73 | IsSpcnRackPowerIncompleteOut */ | ||
74 | struct { | ||
75 | u64 token; | ||
76 | u64 address_type; | ||
77 | u64 side; | ||
78 | u32 length; | ||
79 | u32 offset; | ||
80 | } kern; /* SetKernelImageIn, GetKernelImageIn, | ||
81 | SetKernelCmdLineIn, GetKernelCmdLineIn */ | ||
82 | u32 length_out; /* GetKernelImageOut, GetKernelCmdLineOut */ | ||
83 | u8 reserved[80]; | ||
84 | } sub_data; | ||
85 | }; | ||
86 | |||
87 | struct vsp_rsp_data { | ||
88 | struct completion com; | ||
89 | struct vsp_cmd_data *response; | ||
90 | }; | ||
91 | |||
92 | struct alloc_data { | ||
93 | u16 size; | ||
94 | u16 type; | ||
95 | u32 count; | ||
96 | u16 reserved1; | ||
97 | u8 reserved2; | ||
98 | HvLpIndex target_lp; | ||
99 | }; | ||
100 | |||
101 | struct ce_msg_data; | ||
102 | |||
103 | typedef void (*ce_msg_comp_hdlr)(void *token, struct ce_msg_data *vsp_cmd_rsp); | ||
104 | |||
105 | struct ce_msg_comp_data { | ||
106 | ce_msg_comp_hdlr handler; | ||
107 | void *token; | ||
108 | }; | ||
109 | |||
110 | struct ce_msg_data { | ||
111 | u8 ce_msg[12]; | ||
112 | char reserved[4]; | ||
113 | struct ce_msg_comp_data *completion; | ||
114 | }; | ||
115 | |||
116 | struct io_mf_lp_event { | ||
117 | struct HvLpEvent hp_lp_event; | ||
118 | u16 subtype_result_code; | ||
119 | u16 reserved1; | ||
120 | u32 reserved2; | ||
121 | union { | ||
122 | struct alloc_data alloc; | ||
123 | struct ce_msg_data ce_msg; | ||
124 | struct vsp_cmd_data vsp_cmd; | ||
125 | } data; | ||
126 | }; | ||
127 | |||
128 | #define subtype_data(a, b, c, d) \ | ||
129 | (((a) << 24) + ((b) << 16) + ((c) << 8) + (d)) | ||
130 | |||
131 | /* | ||
132 | * All outgoing event traffic is kept on a FIFO queue. The first | ||
133 | * pointer points to the one that is outstanding, and all new | ||
134 | * requests get stuck on the end. Also, we keep a certain number of | ||
135 | * preallocated pending events so that we can operate very early in | ||
136 | * the boot up sequence (before kmalloc is ready). | ||
137 | */ | ||
138 | struct pending_event { | ||
139 | struct pending_event *next; | ||
140 | struct io_mf_lp_event event; | ||
141 | MFCompleteHandler hdlr; | ||
142 | char dma_data[72]; | ||
143 | unsigned dma_data_length; | ||
144 | unsigned remote_address; | ||
145 | }; | ||
146 | static spinlock_t pending_event_spinlock; | ||
147 | static struct pending_event *pending_event_head; | ||
148 | static struct pending_event *pending_event_tail; | ||
149 | static struct pending_event *pending_event_avail; | ||
150 | #define PENDING_EVENT_PREALLOC_LEN 16 | ||
151 | static struct pending_event pending_event_prealloc[PENDING_EVENT_PREALLOC_LEN]; | ||
152 | |||
153 | /* | ||
154 | * Put a pending event onto the available queue, so it can get reused. | ||
155 | * Attention! You must have the pending_event_spinlock before calling! | ||
156 | */ | ||
157 | static void free_pending_event(struct pending_event *ev) | ||
158 | { | ||
159 | if (ev != NULL) { | ||
160 | ev->next = pending_event_avail; | ||
161 | pending_event_avail = ev; | ||
162 | } | ||
163 | } | ||
164 | |||
165 | /* | ||
166 | * Enqueue the outbound event onto the stack. If the queue was | ||
167 | * empty to begin with, we must also issue it via the Hypervisor | ||
168 | * interface. There is a section of code below that will touch | ||
169 | * the first stack pointer without the protection of the pending_event_spinlock. | ||
170 | * This is OK, because we know that nobody else will be modifying | ||
171 | * the first pointer when we do this. | ||
172 | */ | ||
173 | static int signal_event(struct pending_event *ev) | ||
174 | { | ||
175 | int rc = 0; | ||
176 | unsigned long flags; | ||
177 | int go = 1; | ||
178 | struct pending_event *ev1; | ||
179 | HvLpEvent_Rc hv_rc; | ||
180 | |||
181 | /* enqueue the event */ | ||
182 | if (ev != NULL) { | ||
183 | ev->next = NULL; | ||
184 | spin_lock_irqsave(&pending_event_spinlock, flags); | ||
185 | if (pending_event_head == NULL) | ||
186 | pending_event_head = ev; | ||
187 | else { | ||
188 | go = 0; | ||
189 | pending_event_tail->next = ev; | ||
190 | } | ||
191 | pending_event_tail = ev; | ||
192 | spin_unlock_irqrestore(&pending_event_spinlock, flags); | ||
193 | } | ||
194 | |||
195 | /* send the event */ | ||
196 | while (go) { | ||
197 | go = 0; | ||
198 | |||
199 | /* any DMA data to send beforehand? */ | ||
200 | if (pending_event_head->dma_data_length > 0) | ||
201 | HvCallEvent_dmaToSp(pending_event_head->dma_data, | ||
202 | pending_event_head->remote_address, | ||
203 | pending_event_head->dma_data_length, | ||
204 | HvLpDma_Direction_LocalToRemote); | ||
205 | |||
206 | hv_rc = HvCallEvent_signalLpEvent( | ||
207 | &pending_event_head->event.hp_lp_event); | ||
208 | if (hv_rc != HvLpEvent_Rc_Good) { | ||
209 | printk(KERN_ERR "mf.c: HvCallEvent_signalLpEvent() " | ||
210 | "failed with %d\n", (int)hv_rc); | ||
211 | |||
212 | spin_lock_irqsave(&pending_event_spinlock, flags); | ||
213 | ev1 = pending_event_head; | ||
214 | pending_event_head = pending_event_head->next; | ||
215 | if (pending_event_head != NULL) | ||
216 | go = 1; | ||
217 | spin_unlock_irqrestore(&pending_event_spinlock, flags); | ||
218 | |||
219 | if (ev1 == ev) | ||
220 | rc = -EIO; | ||
221 | else if (ev1->hdlr != NULL) | ||
222 | (*ev1->hdlr)((void *)ev1->event.hp_lp_event.xCorrelationToken, -EIO); | ||
223 | |||
224 | spin_lock_irqsave(&pending_event_spinlock, flags); | ||
225 | free_pending_event(ev1); | ||
226 | spin_unlock_irqrestore(&pending_event_spinlock, flags); | ||
227 | } | ||
228 | } | ||
229 | |||
230 | return rc; | ||
231 | } | ||
232 | |||
233 | /* | ||
234 | * Allocate a new pending_event structure, and initialize it. | ||
235 | */ | ||
236 | static struct pending_event *new_pending_event(void) | ||
237 | { | ||
238 | struct pending_event *ev = NULL; | ||
239 | HvLpIndex primary_lp = HvLpConfig_getPrimaryLpIndex(); | ||
240 | unsigned long flags; | ||
241 | struct HvLpEvent *hev; | ||
242 | |||
243 | spin_lock_irqsave(&pending_event_spinlock, flags); | ||
244 | if (pending_event_avail != NULL) { | ||
245 | ev = pending_event_avail; | ||
246 | pending_event_avail = pending_event_avail->next; | ||
247 | } | ||
248 | spin_unlock_irqrestore(&pending_event_spinlock, flags); | ||
249 | if (ev == NULL) { | ||
250 | ev = kmalloc(sizeof(struct pending_event), GFP_ATOMIC); | ||
251 | if (ev == NULL) { | ||
252 | printk(KERN_ERR "mf.c: unable to kmalloc %ld bytes\n", | ||
253 | sizeof(struct pending_event)); | ||
254 | return NULL; | ||
255 | } | ||
256 | } | ||
257 | memset(ev, 0, sizeof(struct pending_event)); | ||
258 | hev = &ev->event.hp_lp_event; | ||
259 | hev->flags = HV_LP_EVENT_VALID | HV_LP_EVENT_DO_ACK | HV_LP_EVENT_INT; | ||
260 | hev->xType = HvLpEvent_Type_MachineFac; | ||
261 | hev->xSourceLp = HvLpConfig_getLpIndex(); | ||
262 | hev->xTargetLp = primary_lp; | ||
263 | hev->xSizeMinus1 = sizeof(ev->event) - 1; | ||
264 | hev->xRc = HvLpEvent_Rc_Good; | ||
265 | hev->xSourceInstanceId = HvCallEvent_getSourceLpInstanceId(primary_lp, | ||
266 | HvLpEvent_Type_MachineFac); | ||
267 | hev->xTargetInstanceId = HvCallEvent_getTargetLpInstanceId(primary_lp, | ||
268 | HvLpEvent_Type_MachineFac); | ||
269 | |||
270 | return ev; | ||
271 | } | ||
272 | |||
273 | static int __maybe_unused | ||
274 | signal_vsp_instruction(struct vsp_cmd_data *vsp_cmd) | ||
275 | { | ||
276 | struct pending_event *ev = new_pending_event(); | ||
277 | int rc; | ||
278 | struct vsp_rsp_data response; | ||
279 | |||
280 | if (ev == NULL) | ||
281 | return -ENOMEM; | ||
282 | |||
283 | init_completion(&response.com); | ||
284 | response.response = vsp_cmd; | ||
285 | ev->event.hp_lp_event.xSubtype = 6; | ||
286 | ev->event.hp_lp_event.x.xSubtypeData = | ||
287 | subtype_data('M', 'F', 'V', 'I'); | ||
288 | ev->event.data.vsp_cmd.token = (u64)&response; | ||
289 | ev->event.data.vsp_cmd.cmd = vsp_cmd->cmd; | ||
290 | ev->event.data.vsp_cmd.lp_index = HvLpConfig_getLpIndex(); | ||
291 | ev->event.data.vsp_cmd.result_code = 0xFF; | ||
292 | ev->event.data.vsp_cmd.reserved = 0; | ||
293 | memcpy(&(ev->event.data.vsp_cmd.sub_data), | ||
294 | &(vsp_cmd->sub_data), sizeof(vsp_cmd->sub_data)); | ||
295 | mb(); | ||
296 | |||
297 | rc = signal_event(ev); | ||
298 | if (rc == 0) | ||
299 | wait_for_completion(&response.com); | ||
300 | return rc; | ||
301 | } | ||
302 | |||
303 | |||
304 | /* | ||
305 | * Send a 12-byte CE message to the primary partition VSP object | ||
306 | */ | ||
307 | static int signal_ce_msg(char *ce_msg, struct ce_msg_comp_data *completion) | ||
308 | { | ||
309 | struct pending_event *ev = new_pending_event(); | ||
310 | |||
311 | if (ev == NULL) | ||
312 | return -ENOMEM; | ||
313 | |||
314 | ev->event.hp_lp_event.xSubtype = 0; | ||
315 | ev->event.hp_lp_event.x.xSubtypeData = | ||
316 | subtype_data('M', 'F', 'C', 'E'); | ||
317 | memcpy(ev->event.data.ce_msg.ce_msg, ce_msg, 12); | ||
318 | ev->event.data.ce_msg.completion = completion; | ||
319 | return signal_event(ev); | ||
320 | } | ||
321 | |||
322 | /* | ||
323 | * Send a 12-byte CE message (with no data) to the primary partition VSP object | ||
324 | */ | ||
325 | static int signal_ce_msg_simple(u8 ce_op, struct ce_msg_comp_data *completion) | ||
326 | { | ||
327 | u8 ce_msg[12]; | ||
328 | |||
329 | memset(ce_msg, 0, sizeof(ce_msg)); | ||
330 | ce_msg[3] = ce_op; | ||
331 | return signal_ce_msg(ce_msg, completion); | ||
332 | } | ||
333 | |||
334 | /* | ||
335 | * Send a 12-byte CE message and DMA data to the primary partition VSP object | ||
336 | */ | ||
337 | static int dma_and_signal_ce_msg(char *ce_msg, | ||
338 | struct ce_msg_comp_data *completion, void *dma_data, | ||
339 | unsigned dma_data_length, unsigned remote_address) | ||
340 | { | ||
341 | struct pending_event *ev = new_pending_event(); | ||
342 | |||
343 | if (ev == NULL) | ||
344 | return -ENOMEM; | ||
345 | |||
346 | ev->event.hp_lp_event.xSubtype = 0; | ||
347 | ev->event.hp_lp_event.x.xSubtypeData = | ||
348 | subtype_data('M', 'F', 'C', 'E'); | ||
349 | memcpy(ev->event.data.ce_msg.ce_msg, ce_msg, 12); | ||
350 | ev->event.data.ce_msg.completion = completion; | ||
351 | memcpy(ev->dma_data, dma_data, dma_data_length); | ||
352 | ev->dma_data_length = dma_data_length; | ||
353 | ev->remote_address = remote_address; | ||
354 | return signal_event(ev); | ||
355 | } | ||
356 | |||
357 | /* | ||
358 | * Initiate a nice (hopefully) shutdown of Linux. We simply are | ||
359 | * going to try and send the init process a SIGINT signal. If | ||
360 | * this fails (why?), we'll simply force it off in a not-so-nice | ||
361 | * manner. | ||
362 | */ | ||
363 | static int shutdown(void) | ||
364 | { | ||
365 | int rc = kill_cad_pid(SIGINT, 1); | ||
366 | |||
367 | if (rc) { | ||
368 | printk(KERN_ALERT "mf.c: SIGINT to init failed (%d), " | ||
369 | "hard shutdown commencing\n", rc); | ||
370 | mf_power_off(); | ||
371 | } else | ||
372 | printk(KERN_INFO "mf.c: init has been successfully notified " | ||
373 | "to proceed with shutdown\n"); | ||
374 | return rc; | ||
375 | } | ||
376 | |||
377 | /* | ||
378 | * The primary partition VSP object is sending us a new | ||
379 | * event flow. Handle it... | ||
380 | */ | ||
381 | static void handle_int(struct io_mf_lp_event *event) | ||
382 | { | ||
383 | struct ce_msg_data *ce_msg_data; | ||
384 | struct ce_msg_data *pce_msg_data; | ||
385 | unsigned long flags; | ||
386 | struct pending_event *pev; | ||
387 | |||
388 | /* ack the interrupt */ | ||
389 | event->hp_lp_event.xRc = HvLpEvent_Rc_Good; | ||
390 | HvCallEvent_ackLpEvent(&event->hp_lp_event); | ||
391 | |||
392 | /* process interrupt */ | ||
393 | switch (event->hp_lp_event.xSubtype) { | ||
394 | case 0: /* CE message */ | ||
395 | ce_msg_data = &event->data.ce_msg; | ||
396 | switch (ce_msg_data->ce_msg[3]) { | ||
397 | case 0x5B: /* power control notification */ | ||
398 | if ((ce_msg_data->ce_msg[5] & 0x20) != 0) { | ||
399 | printk(KERN_INFO "mf.c: Commencing partition shutdown\n"); | ||
400 | if (shutdown() == 0) | ||
401 | signal_ce_msg_simple(0xDB, NULL); | ||
402 | } | ||
403 | break; | ||
404 | case 0xC0: /* get time */ | ||
405 | spin_lock_irqsave(&pending_event_spinlock, flags); | ||
406 | pev = pending_event_head; | ||
407 | if (pev != NULL) | ||
408 | pending_event_head = pending_event_head->next; | ||
409 | spin_unlock_irqrestore(&pending_event_spinlock, flags); | ||
410 | if (pev == NULL) | ||
411 | break; | ||
412 | pce_msg_data = &pev->event.data.ce_msg; | ||
413 | if (pce_msg_data->ce_msg[3] != 0x40) | ||
414 | break; | ||
415 | if (pce_msg_data->completion != NULL) { | ||
416 | ce_msg_comp_hdlr handler = | ||
417 | pce_msg_data->completion->handler; | ||
418 | void *token = pce_msg_data->completion->token; | ||
419 | |||
420 | if (handler != NULL) | ||
421 | (*handler)(token, ce_msg_data); | ||
422 | } | ||
423 | spin_lock_irqsave(&pending_event_spinlock, flags); | ||
424 | free_pending_event(pev); | ||
425 | spin_unlock_irqrestore(&pending_event_spinlock, flags); | ||
426 | /* send next waiting event */ | ||
427 | if (pending_event_head != NULL) | ||
428 | signal_event(NULL); | ||
429 | break; | ||
430 | } | ||
431 | break; | ||
432 | case 1: /* IT sys shutdown */ | ||
433 | printk(KERN_INFO "mf.c: Commencing system shutdown\n"); | ||
434 | shutdown(); | ||
435 | break; | ||
436 | } | ||
437 | } | ||
438 | |||
439 | /* | ||
440 | * The primary partition VSP object is acknowledging the receipt | ||
441 | * of a flow we sent to them. If there are other flows queued | ||
442 | * up, we must send another one now... | ||
443 | */ | ||
444 | static void handle_ack(struct io_mf_lp_event *event) | ||
445 | { | ||
446 | unsigned long flags; | ||
447 | struct pending_event *two = NULL; | ||
448 | unsigned long free_it = 0; | ||
449 | struct ce_msg_data *ce_msg_data; | ||
450 | struct ce_msg_data *pce_msg_data; | ||
451 | struct vsp_rsp_data *rsp; | ||
452 | |||
453 | /* handle current event */ | ||
454 | if (pending_event_head == NULL) { | ||
455 | printk(KERN_ERR "mf.c: stack empty for receiving ack\n"); | ||
456 | return; | ||
457 | } | ||
458 | |||
459 | switch (event->hp_lp_event.xSubtype) { | ||
460 | case 0: /* CE msg */ | ||
461 | ce_msg_data = &event->data.ce_msg; | ||
462 | if (ce_msg_data->ce_msg[3] != 0x40) { | ||
463 | free_it = 1; | ||
464 | break; | ||
465 | } | ||
466 | if (ce_msg_data->ce_msg[2] == 0) | ||
467 | break; | ||
468 | free_it = 1; | ||
469 | pce_msg_data = &pending_event_head->event.data.ce_msg; | ||
470 | if (pce_msg_data->completion != NULL) { | ||
471 | ce_msg_comp_hdlr handler = | ||
472 | pce_msg_data->completion->handler; | ||
473 | void *token = pce_msg_data->completion->token; | ||
474 | |||
475 | if (handler != NULL) | ||
476 | (*handler)(token, ce_msg_data); | ||
477 | } | ||
478 | break; | ||
479 | case 4: /* allocate */ | ||
480 | case 5: /* deallocate */ | ||
481 | if (pending_event_head->hdlr != NULL) | ||
482 | (*pending_event_head->hdlr)((void *)event->hp_lp_event.xCorrelationToken, event->data.alloc.count); | ||
483 | free_it = 1; | ||
484 | break; | ||
485 | case 6: | ||
486 | free_it = 1; | ||
487 | rsp = (struct vsp_rsp_data *)event->data.vsp_cmd.token; | ||
488 | if (rsp == NULL) { | ||
489 | printk(KERN_ERR "mf.c: no rsp\n"); | ||
490 | break; | ||
491 | } | ||
492 | if (rsp->response != NULL) | ||
493 | memcpy(rsp->response, &event->data.vsp_cmd, | ||
494 | sizeof(event->data.vsp_cmd)); | ||
495 | complete(&rsp->com); | ||
496 | break; | ||
497 | } | ||
498 | |||
499 | /* remove from queue */ | ||
500 | spin_lock_irqsave(&pending_event_spinlock, flags); | ||
501 | if ((pending_event_head != NULL) && (free_it == 1)) { | ||
502 | struct pending_event *oldHead = pending_event_head; | ||
503 | |||
504 | pending_event_head = pending_event_head->next; | ||
505 | two = pending_event_head; | ||
506 | free_pending_event(oldHead); | ||
507 | } | ||
508 | spin_unlock_irqrestore(&pending_event_spinlock, flags); | ||
509 | |||
510 | /* send next waiting event */ | ||
511 | if (two != NULL) | ||
512 | signal_event(NULL); | ||
513 | } | ||
514 | |||
515 | /* | ||
516 | * This is the generic event handler we are registering with | ||
517 | * the Hypervisor. Ensure the flows are for us, and then | ||
518 | * parse it enough to know if it is an interrupt or an | ||
519 | * acknowledge. | ||
520 | */ | ||
521 | static void hv_handler(struct HvLpEvent *event) | ||
522 | { | ||
523 | if ((event != NULL) && (event->xType == HvLpEvent_Type_MachineFac)) { | ||
524 | if (hvlpevent_is_ack(event)) | ||
525 | handle_ack((struct io_mf_lp_event *)event); | ||
526 | else | ||
527 | handle_int((struct io_mf_lp_event *)event); | ||
528 | } else | ||
529 | printk(KERN_ERR "mf.c: alien event received\n"); | ||
530 | } | ||
531 | |||
532 | /* | ||
533 | * Global kernel interface to allocate and seed events into the | ||
534 | * Hypervisor. | ||
535 | */ | ||
536 | void mf_allocate_lp_events(HvLpIndex target_lp, HvLpEvent_Type type, | ||
537 | unsigned size, unsigned count, MFCompleteHandler hdlr, | ||
538 | void *user_token) | ||
539 | { | ||
540 | struct pending_event *ev = new_pending_event(); | ||
541 | int rc; | ||
542 | |||
543 | if (ev == NULL) { | ||
544 | rc = -ENOMEM; | ||
545 | } else { | ||
546 | ev->event.hp_lp_event.xSubtype = 4; | ||
547 | ev->event.hp_lp_event.xCorrelationToken = (u64)user_token; | ||
548 | ev->event.hp_lp_event.x.xSubtypeData = | ||
549 | subtype_data('M', 'F', 'M', 'A'); | ||
550 | ev->event.data.alloc.target_lp = target_lp; | ||
551 | ev->event.data.alloc.type = type; | ||
552 | ev->event.data.alloc.size = size; | ||
553 | ev->event.data.alloc.count = count; | ||
554 | ev->hdlr = hdlr; | ||
555 | rc = signal_event(ev); | ||
556 | } | ||
557 | if ((rc != 0) && (hdlr != NULL)) | ||
558 | (*hdlr)(user_token, rc); | ||
559 | } | ||
560 | EXPORT_SYMBOL(mf_allocate_lp_events); | ||
561 | |||
562 | /* | ||
563 | * Global kernel interface to unseed and deallocate events already in | ||
564 | * Hypervisor. | ||
565 | */ | ||
566 | void mf_deallocate_lp_events(HvLpIndex target_lp, HvLpEvent_Type type, | ||
567 | unsigned count, MFCompleteHandler hdlr, void *user_token) | ||
568 | { | ||
569 | struct pending_event *ev = new_pending_event(); | ||
570 | int rc; | ||
571 | |||
572 | if (ev == NULL) | ||
573 | rc = -ENOMEM; | ||
574 | else { | ||
575 | ev->event.hp_lp_event.xSubtype = 5; | ||
576 | ev->event.hp_lp_event.xCorrelationToken = (u64)user_token; | ||
577 | ev->event.hp_lp_event.x.xSubtypeData = | ||
578 | subtype_data('M', 'F', 'M', 'D'); | ||
579 | ev->event.data.alloc.target_lp = target_lp; | ||
580 | ev->event.data.alloc.type = type; | ||
581 | ev->event.data.alloc.count = count; | ||
582 | ev->hdlr = hdlr; | ||
583 | rc = signal_event(ev); | ||
584 | } | ||
585 | if ((rc != 0) && (hdlr != NULL)) | ||
586 | (*hdlr)(user_token, rc); | ||
587 | } | ||
588 | EXPORT_SYMBOL(mf_deallocate_lp_events); | ||
589 | |||
590 | /* | ||
591 | * Global kernel interface to tell the VSP object in the primary | ||
592 | * partition to power this partition off. | ||
593 | */ | ||
594 | void mf_power_off(void) | ||
595 | { | ||
596 | printk(KERN_INFO "mf.c: Down it goes...\n"); | ||
597 | signal_ce_msg_simple(0x4d, NULL); | ||
598 | for (;;) | ||
599 | ; | ||
600 | } | ||
601 | |||
602 | /* | ||
603 | * Global kernel interface to tell the VSP object in the primary | ||
604 | * partition to reboot this partition. | ||
605 | */ | ||
606 | void mf_reboot(char *cmd) | ||
607 | { | ||
608 | printk(KERN_INFO "mf.c: Preparing to bounce...\n"); | ||
609 | signal_ce_msg_simple(0x4e, NULL); | ||
610 | for (;;) | ||
611 | ; | ||
612 | } | ||
613 | |||
614 | /* | ||
615 | * Display a single word SRC onto the VSP control panel. | ||
616 | */ | ||
617 | void mf_display_src(u32 word) | ||
618 | { | ||
619 | u8 ce[12]; | ||
620 | |||
621 | memset(ce, 0, sizeof(ce)); | ||
622 | ce[3] = 0x4a; | ||
623 | ce[7] = 0x01; | ||
624 | ce[8] = word >> 24; | ||
625 | ce[9] = word >> 16; | ||
626 | ce[10] = word >> 8; | ||
627 | ce[11] = word; | ||
628 | signal_ce_msg(ce, NULL); | ||
629 | } | ||
630 | |||
631 | /* | ||
632 | * Display a single word SRC of the form "PROGXXXX" on the VSP control panel. | ||
633 | */ | ||
634 | static __init void mf_display_progress_src(u16 value) | ||
635 | { | ||
636 | u8 ce[12]; | ||
637 | u8 src[72]; | ||
638 | |||
639 | memcpy(ce, "\x00\x00\x04\x4A\x00\x00\x00\x48\x00\x00\x00\x00", 12); | ||
640 | memcpy(src, "\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00" | ||
641 | "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" | ||
642 | "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" | ||
643 | "\x00\x00\x00\x00PROGxxxx ", | ||
644 | 72); | ||
645 | src[6] = value >> 8; | ||
646 | src[7] = value & 255; | ||
647 | src[44] = "0123456789ABCDEF"[(value >> 12) & 15]; | ||
648 | src[45] = "0123456789ABCDEF"[(value >> 8) & 15]; | ||
649 | src[46] = "0123456789ABCDEF"[(value >> 4) & 15]; | ||
650 | src[47] = "0123456789ABCDEF"[value & 15]; | ||
651 | dma_and_signal_ce_msg(ce, NULL, src, sizeof(src), 9 * 64 * 1024); | ||
652 | } | ||
653 | |||
654 | /* | ||
655 | * Clear the VSP control panel. Used to "erase" an SRC that was | ||
656 | * previously displayed. | ||
657 | */ | ||
658 | static void mf_clear_src(void) | ||
659 | { | ||
660 | signal_ce_msg_simple(0x4b, NULL); | ||
661 | } | ||
662 | |||
663 | void __init mf_display_progress(u16 value) | ||
664 | { | ||
665 | if (!mf_initialized) | ||
666 | return; | ||
667 | |||
668 | if (0xFFFF == value) | ||
669 | mf_clear_src(); | ||
670 | else | ||
671 | mf_display_progress_src(value); | ||
672 | } | ||
673 | |||
674 | /* | ||
675 | * Initialization code here. | ||
676 | */ | ||
677 | void __init mf_init(void) | ||
678 | { | ||
679 | int i; | ||
680 | |||
681 | spin_lock_init(&pending_event_spinlock); | ||
682 | |||
683 | for (i = 0; i < PENDING_EVENT_PREALLOC_LEN; i++) | ||
684 | free_pending_event(&pending_event_prealloc[i]); | ||
685 | |||
686 | HvLpEvent_registerHandler(HvLpEvent_Type_MachineFac, &hv_handler); | ||
687 | |||
688 | /* virtual continue ack */ | ||
689 | signal_ce_msg_simple(0x57, NULL); | ||
690 | |||
691 | mf_initialized = 1; | ||
692 | mb(); | ||
693 | |||
694 | printk(KERN_NOTICE "mf.c: iSeries Linux LPAR Machine Facilities " | ||
695 | "initialized\n"); | ||
696 | } | ||
697 | |||
698 | struct rtc_time_data { | ||
699 | struct completion com; | ||
700 | struct ce_msg_data ce_msg; | ||
701 | int rc; | ||
702 | }; | ||
703 | |||
704 | static void get_rtc_time_complete(void *token, struct ce_msg_data *ce_msg) | ||
705 | { | ||
706 | struct rtc_time_data *rtc = token; | ||
707 | |||
708 | memcpy(&rtc->ce_msg, ce_msg, sizeof(rtc->ce_msg)); | ||
709 | rtc->rc = 0; | ||
710 | complete(&rtc->com); | ||
711 | } | ||
712 | |||
713 | static int mf_set_rtc(struct rtc_time *tm) | ||
714 | { | ||
715 | char ce_time[12]; | ||
716 | u8 day, mon, hour, min, sec, y1, y2; | ||
717 | unsigned year; | ||
718 | |||
719 | year = 1900 + tm->tm_year; | ||
720 | y1 = year / 100; | ||
721 | y2 = year % 100; | ||
722 | |||
723 | sec = tm->tm_sec; | ||
724 | min = tm->tm_min; | ||
725 | hour = tm->tm_hour; | ||
726 | day = tm->tm_mday; | ||
727 | mon = tm->tm_mon + 1; | ||
728 | |||
729 | sec = bin2bcd(sec); | ||
730 | min = bin2bcd(min); | ||
731 | hour = bin2bcd(hour); | ||
732 | mon = bin2bcd(mon); | ||
733 | day = bin2bcd(day); | ||
734 | y1 = bin2bcd(y1); | ||
735 | y2 = bin2bcd(y2); | ||
736 | |||
737 | memset(ce_time, 0, sizeof(ce_time)); | ||
738 | ce_time[3] = 0x41; | ||
739 | ce_time[4] = y1; | ||
740 | ce_time[5] = y2; | ||
741 | ce_time[6] = sec; | ||
742 | ce_time[7] = min; | ||
743 | ce_time[8] = hour; | ||
744 | ce_time[10] = day; | ||
745 | ce_time[11] = mon; | ||
746 | |||
747 | return signal_ce_msg(ce_time, NULL); | ||
748 | } | ||
749 | |||
750 | static int rtc_set_tm(int rc, u8 *ce_msg, struct rtc_time *tm) | ||
751 | { | ||
752 | tm->tm_wday = 0; | ||
753 | tm->tm_yday = 0; | ||
754 | tm->tm_isdst = 0; | ||
755 | if (rc) { | ||
756 | tm->tm_sec = 0; | ||
757 | tm->tm_min = 0; | ||
758 | tm->tm_hour = 0; | ||
759 | tm->tm_mday = 15; | ||
760 | tm->tm_mon = 5; | ||
761 | tm->tm_year = 52; | ||
762 | return rc; | ||
763 | } | ||
764 | |||
765 | if ((ce_msg[2] == 0xa9) || | ||
766 | (ce_msg[2] == 0xaf)) { | ||
767 | /* TOD clock is not set */ | ||
768 | tm->tm_sec = 1; | ||
769 | tm->tm_min = 1; | ||
770 | tm->tm_hour = 1; | ||
771 | tm->tm_mday = 10; | ||
772 | tm->tm_mon = 8; | ||
773 | tm->tm_year = 71; | ||
774 | mf_set_rtc(tm); | ||
775 | } | ||
776 | { | ||
777 | u8 year = ce_msg[5]; | ||
778 | u8 sec = ce_msg[6]; | ||
779 | u8 min = ce_msg[7]; | ||
780 | u8 hour = ce_msg[8]; | ||
781 | u8 day = ce_msg[10]; | ||
782 | u8 mon = ce_msg[11]; | ||
783 | |||
784 | sec = bcd2bin(sec); | ||
785 | min = bcd2bin(min); | ||
786 | hour = bcd2bin(hour); | ||
787 | day = bcd2bin(day); | ||
788 | mon = bcd2bin(mon); | ||
789 | year = bcd2bin(year); | ||
790 | |||
791 | if (year <= 69) | ||
792 | year += 100; | ||
793 | |||
794 | tm->tm_sec = sec; | ||
795 | tm->tm_min = min; | ||
796 | tm->tm_hour = hour; | ||
797 | tm->tm_mday = day; | ||
798 | tm->tm_mon = mon; | ||
799 | tm->tm_year = year; | ||
800 | } | ||
801 | |||
802 | return 0; | ||
803 | } | ||
804 | |||
805 | static int mf_get_rtc(struct rtc_time *tm) | ||
806 | { | ||
807 | struct ce_msg_comp_data ce_complete; | ||
808 | struct rtc_time_data rtc_data; | ||
809 | int rc; | ||
810 | |||
811 | memset(&ce_complete, 0, sizeof(ce_complete)); | ||
812 | memset(&rtc_data, 0, sizeof(rtc_data)); | ||
813 | init_completion(&rtc_data.com); | ||
814 | ce_complete.handler = &get_rtc_time_complete; | ||
815 | ce_complete.token = &rtc_data; | ||
816 | rc = signal_ce_msg_simple(0x40, &ce_complete); | ||
817 | if (rc) | ||
818 | return rc; | ||
819 | wait_for_completion(&rtc_data.com); | ||
820 | return rtc_set_tm(rtc_data.rc, rtc_data.ce_msg.ce_msg, tm); | ||
821 | } | ||
822 | |||
823 | struct boot_rtc_time_data { | ||
824 | int busy; | ||
825 | struct ce_msg_data ce_msg; | ||
826 | int rc; | ||
827 | }; | ||
828 | |||
829 | static void get_boot_rtc_time_complete(void *token, struct ce_msg_data *ce_msg) | ||
830 | { | ||
831 | struct boot_rtc_time_data *rtc = token; | ||
832 | |||
833 | memcpy(&rtc->ce_msg, ce_msg, sizeof(rtc->ce_msg)); | ||
834 | rtc->rc = 0; | ||
835 | rtc->busy = 0; | ||
836 | } | ||
837 | |||
838 | static int mf_get_boot_rtc(struct rtc_time *tm) | ||
839 | { | ||
840 | struct ce_msg_comp_data ce_complete; | ||
841 | struct boot_rtc_time_data rtc_data; | ||
842 | int rc; | ||
843 | |||
844 | memset(&ce_complete, 0, sizeof(ce_complete)); | ||
845 | memset(&rtc_data, 0, sizeof(rtc_data)); | ||
846 | rtc_data.busy = 1; | ||
847 | ce_complete.handler = &get_boot_rtc_time_complete; | ||
848 | ce_complete.token = &rtc_data; | ||
849 | rc = signal_ce_msg_simple(0x40, &ce_complete); | ||
850 | if (rc) | ||
851 | return rc; | ||
852 | /* We need to poll here as we are not yet taking interrupts */ | ||
853 | while (rtc_data.busy) { | ||
854 | if (hvlpevent_is_pending()) | ||
855 | process_hvlpevents(); | ||
856 | } | ||
857 | return rtc_set_tm(rtc_data.rc, rtc_data.ce_msg.ce_msg, tm); | ||
858 | } | ||
859 | |||
860 | #ifdef CONFIG_PROC_FS | ||
861 | static int mf_cmdline_proc_show(struct seq_file *m, void *v) | ||
862 | { | ||
863 | char *page, *p; | ||
864 | struct vsp_cmd_data vsp_cmd; | ||
865 | int rc; | ||
866 | dma_addr_t dma_addr; | ||
867 | |||
868 | /* The HV appears to return no more than 256 bytes of command line */ | ||
869 | page = kmalloc(256, GFP_KERNEL); | ||
870 | if (!page) | ||
871 | return -ENOMEM; | ||
872 | |||
873 | dma_addr = iseries_hv_map(page, 256, DMA_FROM_DEVICE); | ||
874 | if (dma_addr == DMA_ERROR_CODE) { | ||
875 | kfree(page); | ||
876 | return -ENOMEM; | ||
877 | } | ||
878 | memset(page, 0, 256); | ||
879 | memset(&vsp_cmd, 0, sizeof(vsp_cmd)); | ||
880 | vsp_cmd.cmd = 33; | ||
881 | vsp_cmd.sub_data.kern.token = dma_addr; | ||
882 | vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex; | ||
883 | vsp_cmd.sub_data.kern.side = (u64)m->private; | ||
884 | vsp_cmd.sub_data.kern.length = 256; | ||
885 | mb(); | ||
886 | rc = signal_vsp_instruction(&vsp_cmd); | ||
887 | iseries_hv_unmap(dma_addr, 256, DMA_FROM_DEVICE); | ||
888 | if (rc) { | ||
889 | kfree(page); | ||
890 | return rc; | ||
891 | } | ||
892 | if (vsp_cmd.result_code != 0) { | ||
893 | kfree(page); | ||
894 | return -ENOMEM; | ||
895 | } | ||
896 | p = page; | ||
897 | while (p - page < 256) { | ||
898 | if (*p == '\0' || *p == '\n') { | ||
899 | *p = '\n'; | ||
900 | break; | ||
901 | } | ||
902 | p++; | ||
903 | |||
904 | } | ||
905 | seq_write(m, page, p - page); | ||
906 | kfree(page); | ||
907 | return 0; | ||
908 | } | ||
909 | |||
910 | static int mf_cmdline_proc_open(struct inode *inode, struct file *file) | ||
911 | { | ||
912 | return single_open(file, mf_cmdline_proc_show, PDE(inode)->data); | ||
913 | } | ||
914 | |||
915 | #if 0 | ||
916 | static int mf_getVmlinuxChunk(char *buffer, int *size, int offset, u64 side) | ||
917 | { | ||
918 | struct vsp_cmd_data vsp_cmd; | ||
919 | int rc; | ||
920 | int len = *size; | ||
921 | dma_addr_t dma_addr; | ||
922 | |||
923 | dma_addr = iseries_hv_map(buffer, len, DMA_FROM_DEVICE); | ||
924 | memset(buffer, 0, len); | ||
925 | memset(&vsp_cmd, 0, sizeof(vsp_cmd)); | ||
926 | vsp_cmd.cmd = 32; | ||
927 | vsp_cmd.sub_data.kern.token = dma_addr; | ||
928 | vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex; | ||
929 | vsp_cmd.sub_data.kern.side = side; | ||
930 | vsp_cmd.sub_data.kern.offset = offset; | ||
931 | vsp_cmd.sub_data.kern.length = len; | ||
932 | mb(); | ||
933 | rc = signal_vsp_instruction(&vsp_cmd); | ||
934 | if (rc == 0) { | ||
935 | if (vsp_cmd.result_code == 0) | ||
936 | *size = vsp_cmd.sub_data.length_out; | ||
937 | else | ||
938 | rc = -ENOMEM; | ||
939 | } | ||
940 | |||
941 | iseries_hv_unmap(dma_addr, len, DMA_FROM_DEVICE); | ||
942 | |||
943 | return rc; | ||
944 | } | ||
945 | |||
946 | static int proc_mf_dump_vmlinux(char *page, char **start, off_t off, | ||
947 | int count, int *eof, void *data) | ||
948 | { | ||
949 | int sizeToGet = count; | ||
950 | |||
951 | if (!capable(CAP_SYS_ADMIN)) | ||
952 | return -EACCES; | ||
953 | |||
954 | if (mf_getVmlinuxChunk(page, &sizeToGet, off, (u64)data) == 0) { | ||
955 | if (sizeToGet != 0) { | ||
956 | *start = page + off; | ||
957 | return sizeToGet; | ||
958 | } | ||
959 | *eof = 1; | ||
960 | return 0; | ||
961 | } | ||
962 | *eof = 1; | ||
963 | return 0; | ||
964 | } | ||
965 | #endif | ||
966 | |||
967 | static int mf_side_proc_show(struct seq_file *m, void *v) | ||
968 | { | ||
969 | char mf_current_side = ' '; | ||
970 | struct vsp_cmd_data vsp_cmd; | ||
971 | |||
972 | memset(&vsp_cmd, 0, sizeof(vsp_cmd)); | ||
973 | vsp_cmd.cmd = 2; | ||
974 | vsp_cmd.sub_data.ipl_type = 0; | ||
975 | mb(); | ||
976 | |||
977 | if (signal_vsp_instruction(&vsp_cmd) == 0) { | ||
978 | if (vsp_cmd.result_code == 0) { | ||
979 | switch (vsp_cmd.sub_data.ipl_type) { | ||
980 | case 0: mf_current_side = 'A'; | ||
981 | break; | ||
982 | case 1: mf_current_side = 'B'; | ||
983 | break; | ||
984 | case 2: mf_current_side = 'C'; | ||
985 | break; | ||
986 | default: mf_current_side = 'D'; | ||
987 | break; | ||
988 | } | ||
989 | } | ||
990 | } | ||
991 | |||
992 | seq_printf(m, "%c\n", mf_current_side); | ||
993 | return 0; | ||
994 | } | ||
995 | |||
996 | static int mf_side_proc_open(struct inode *inode, struct file *file) | ||
997 | { | ||
998 | return single_open(file, mf_side_proc_show, NULL); | ||
999 | } | ||
1000 | |||
1001 | static ssize_t mf_side_proc_write(struct file *file, const char __user *buffer, | ||
1002 | size_t count, loff_t *pos) | ||
1003 | { | ||
1004 | char side; | ||
1005 | u64 newSide; | ||
1006 | struct vsp_cmd_data vsp_cmd; | ||
1007 | |||
1008 | if (!capable(CAP_SYS_ADMIN)) | ||
1009 | return -EACCES; | ||
1010 | |||
1011 | if (count == 0) | ||
1012 | return 0; | ||
1013 | |||
1014 | if (get_user(side, buffer)) | ||
1015 | return -EFAULT; | ||
1016 | |||
1017 | switch (side) { | ||
1018 | case 'A': newSide = 0; | ||
1019 | break; | ||
1020 | case 'B': newSide = 1; | ||
1021 | break; | ||
1022 | case 'C': newSide = 2; | ||
1023 | break; | ||
1024 | case 'D': newSide = 3; | ||
1025 | break; | ||
1026 | default: | ||
1027 | printk(KERN_ERR "mf_proc.c: proc_mf_change_side: invalid side\n"); | ||
1028 | return -EINVAL; | ||
1029 | } | ||
1030 | |||
1031 | memset(&vsp_cmd, 0, sizeof(vsp_cmd)); | ||
1032 | vsp_cmd.sub_data.ipl_type = newSide; | ||
1033 | vsp_cmd.cmd = 10; | ||
1034 | |||
1035 | (void)signal_vsp_instruction(&vsp_cmd); | ||
1036 | |||
1037 | return count; | ||
1038 | } | ||
1039 | |||
1040 | static const struct file_operations mf_side_proc_fops = { | ||
1041 | .owner = THIS_MODULE, | ||
1042 | .open = mf_side_proc_open, | ||
1043 | .read = seq_read, | ||
1044 | .llseek = seq_lseek, | ||
1045 | .release = single_release, | ||
1046 | .write = mf_side_proc_write, | ||
1047 | }; | ||
1048 | |||
1049 | static int mf_src_proc_show(struct seq_file *m, void *v) | ||
1050 | { | ||
1051 | return 0; | ||
1052 | } | ||
1053 | |||
1054 | static int mf_src_proc_open(struct inode *inode, struct file *file) | ||
1055 | { | ||
1056 | return single_open(file, mf_src_proc_show, NULL); | ||
1057 | } | ||
1058 | |||
1059 | static ssize_t mf_src_proc_write(struct file *file, const char __user *buffer, | ||
1060 | size_t count, loff_t *pos) | ||
1061 | { | ||
1062 | char stkbuf[10]; | ||
1063 | |||
1064 | if (!capable(CAP_SYS_ADMIN)) | ||
1065 | return -EACCES; | ||
1066 | |||
1067 | if ((count < 4) && (count != 1)) { | ||
1068 | printk(KERN_ERR "mf_proc: invalid src\n"); | ||
1069 | return -EINVAL; | ||
1070 | } | ||
1071 | |||
1072 | if (count > (sizeof(stkbuf) - 1)) | ||
1073 | count = sizeof(stkbuf) - 1; | ||
1074 | if (copy_from_user(stkbuf, buffer, count)) | ||
1075 | return -EFAULT; | ||
1076 | |||
1077 | if ((count == 1) && (*stkbuf == '\0')) | ||
1078 | mf_clear_src(); | ||
1079 | else | ||
1080 | mf_display_src(*(u32 *)stkbuf); | ||
1081 | |||
1082 | return count; | ||
1083 | } | ||
1084 | |||
1085 | static const struct file_operations mf_src_proc_fops = { | ||
1086 | .owner = THIS_MODULE, | ||
1087 | .open = mf_src_proc_open, | ||
1088 | .read = seq_read, | ||
1089 | .llseek = seq_lseek, | ||
1090 | .release = single_release, | ||
1091 | .write = mf_src_proc_write, | ||
1092 | }; | ||
1093 | |||
1094 | static ssize_t mf_cmdline_proc_write(struct file *file, const char __user *buffer, | ||
1095 | size_t count, loff_t *pos) | ||
1096 | { | ||
1097 | void *data = PDE(file->f_path.dentry->d_inode)->data; | ||
1098 | struct vsp_cmd_data vsp_cmd; | ||
1099 | dma_addr_t dma_addr; | ||
1100 | char *page; | ||
1101 | int ret = -EACCES; | ||
1102 | |||
1103 | if (!capable(CAP_SYS_ADMIN)) | ||
1104 | goto out; | ||
1105 | |||
1106 | dma_addr = 0; | ||
1107 | page = iseries_hv_alloc(count, &dma_addr, GFP_ATOMIC); | ||
1108 | ret = -ENOMEM; | ||
1109 | if (page == NULL) | ||
1110 | goto out; | ||
1111 | |||
1112 | ret = -EFAULT; | ||
1113 | if (copy_from_user(page, buffer, count)) | ||
1114 | goto out_free; | ||
1115 | |||
1116 | memset(&vsp_cmd, 0, sizeof(vsp_cmd)); | ||
1117 | vsp_cmd.cmd = 31; | ||
1118 | vsp_cmd.sub_data.kern.token = dma_addr; | ||
1119 | vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex; | ||
1120 | vsp_cmd.sub_data.kern.side = (u64)data; | ||
1121 | vsp_cmd.sub_data.kern.length = count; | ||
1122 | mb(); | ||
1123 | (void)signal_vsp_instruction(&vsp_cmd); | ||
1124 | ret = count; | ||
1125 | |||
1126 | out_free: | ||
1127 | iseries_hv_free(count, page, dma_addr); | ||
1128 | out: | ||
1129 | return ret; | ||
1130 | } | ||
1131 | |||
1132 | static const struct file_operations mf_cmdline_proc_fops = { | ||
1133 | .owner = THIS_MODULE, | ||
1134 | .open = mf_cmdline_proc_open, | ||
1135 | .read = seq_read, | ||
1136 | .llseek = seq_lseek, | ||
1137 | .release = single_release, | ||
1138 | .write = mf_cmdline_proc_write, | ||
1139 | }; | ||
1140 | |||
1141 | static ssize_t proc_mf_change_vmlinux(struct file *file, | ||
1142 | const char __user *buf, | ||
1143 | size_t count, loff_t *ppos) | ||
1144 | { | ||
1145 | struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode); | ||
1146 | ssize_t rc; | ||
1147 | dma_addr_t dma_addr; | ||
1148 | char *page; | ||
1149 | struct vsp_cmd_data vsp_cmd; | ||
1150 | |||
1151 | rc = -EACCES; | ||
1152 | if (!capable(CAP_SYS_ADMIN)) | ||
1153 | goto out; | ||
1154 | |||
1155 | dma_addr = 0; | ||
1156 | page = iseries_hv_alloc(count, &dma_addr, GFP_ATOMIC); | ||
1157 | rc = -ENOMEM; | ||
1158 | if (page == NULL) { | ||
1159 | printk(KERN_ERR "mf.c: couldn't allocate memory to set vmlinux chunk\n"); | ||
1160 | goto out; | ||
1161 | } | ||
1162 | rc = -EFAULT; | ||
1163 | if (copy_from_user(page, buf, count)) | ||
1164 | goto out_free; | ||
1165 | |||
1166 | memset(&vsp_cmd, 0, sizeof(vsp_cmd)); | ||
1167 | vsp_cmd.cmd = 30; | ||
1168 | vsp_cmd.sub_data.kern.token = dma_addr; | ||
1169 | vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex; | ||
1170 | vsp_cmd.sub_data.kern.side = (u64)dp->data; | ||
1171 | vsp_cmd.sub_data.kern.offset = *ppos; | ||
1172 | vsp_cmd.sub_data.kern.length = count; | ||
1173 | mb(); | ||
1174 | rc = signal_vsp_instruction(&vsp_cmd); | ||
1175 | if (rc) | ||
1176 | goto out_free; | ||
1177 | rc = -ENOMEM; | ||
1178 | if (vsp_cmd.result_code != 0) | ||
1179 | goto out_free; | ||
1180 | |||
1181 | *ppos += count; | ||
1182 | rc = count; | ||
1183 | out_free: | ||
1184 | iseries_hv_free(count, page, dma_addr); | ||
1185 | out: | ||
1186 | return rc; | ||
1187 | } | ||
1188 | |||
1189 | static const struct file_operations proc_vmlinux_operations = { | ||
1190 | .write = proc_mf_change_vmlinux, | ||
1191 | .llseek = default_llseek, | ||
1192 | }; | ||
1193 | |||
1194 | static int __init mf_proc_init(void) | ||
1195 | { | ||
1196 | struct proc_dir_entry *mf_proc_root; | ||
1197 | struct proc_dir_entry *ent; | ||
1198 | struct proc_dir_entry *mf; | ||
1199 | char name[2]; | ||
1200 | int i; | ||
1201 | |||
1202 | if (!firmware_has_feature(FW_FEATURE_ISERIES)) | ||
1203 | return 0; | ||
1204 | |||
1205 | mf_proc_root = proc_mkdir("iSeries/mf", NULL); | ||
1206 | if (!mf_proc_root) | ||
1207 | return 1; | ||
1208 | |||
1209 | name[1] = '\0'; | ||
1210 | for (i = 0; i < 4; i++) { | ||
1211 | name[0] = 'A' + i; | ||
1212 | mf = proc_mkdir(name, mf_proc_root); | ||
1213 | if (!mf) | ||
1214 | return 1; | ||
1215 | |||
1216 | ent = proc_create_data("cmdline", S_IRUSR|S_IWUSR, mf, | ||
1217 | &mf_cmdline_proc_fops, (void *)(long)i); | ||
1218 | if (!ent) | ||
1219 | return 1; | ||
1220 | |||
1221 | if (i == 3) /* no vmlinux entry for 'D' */ | ||
1222 | continue; | ||
1223 | |||
1224 | ent = proc_create_data("vmlinux", S_IFREG|S_IWUSR, mf, | ||
1225 | &proc_vmlinux_operations, | ||
1226 | (void *)(long)i); | ||
1227 | if (!ent) | ||
1228 | return 1; | ||
1229 | } | ||
1230 | |||
1231 | ent = proc_create("side", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root, | ||
1232 | &mf_side_proc_fops); | ||
1233 | if (!ent) | ||
1234 | return 1; | ||
1235 | |||
1236 | ent = proc_create("src", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root, | ||
1237 | &mf_src_proc_fops); | ||
1238 | if (!ent) | ||
1239 | return 1; | ||
1240 | |||
1241 | return 0; | ||
1242 | } | ||
1243 | |||
1244 | __initcall(mf_proc_init); | ||
1245 | |||
1246 | #endif /* CONFIG_PROC_FS */ | ||
1247 | |||
1248 | /* | ||
1249 | * Get the RTC from the virtual service processor | ||
1250 | * This requires flowing LpEvents to the primary partition | ||
1251 | */ | ||
1252 | void iSeries_get_rtc_time(struct rtc_time *rtc_tm) | ||
1253 | { | ||
1254 | mf_get_rtc(rtc_tm); | ||
1255 | rtc_tm->tm_mon--; | ||
1256 | } | ||
1257 | |||
1258 | /* | ||
1259 | * Set the RTC in the virtual service processor | ||
1260 | * This requires flowing LpEvents to the primary partition | ||
1261 | */ | ||
1262 | int iSeries_set_rtc_time(struct rtc_time *tm) | ||
1263 | { | ||
1264 | mf_set_rtc(tm); | ||
1265 | return 0; | ||
1266 | } | ||
1267 | |||
1268 | unsigned long iSeries_get_boot_time(void) | ||
1269 | { | ||
1270 | struct rtc_time tm; | ||
1271 | |||
1272 | mf_get_boot_rtc(&tm); | ||
1273 | return mktime(tm.tm_year + 1900, tm.tm_mon, tm.tm_mday, | ||
1274 | tm.tm_hour, tm.tm_min, tm.tm_sec); | ||
1275 | } | ||
diff --git a/arch/powerpc/platforms/iseries/misc.S b/arch/powerpc/platforms/iseries/misc.S deleted file mode 100644 index 2c6ff0fdac98..000000000000 --- a/arch/powerpc/platforms/iseries/misc.S +++ /dev/null | |||
@@ -1,26 +0,0 @@ | |||
1 | /* | ||
2 | * This file contains miscellaneous low-level functions. | ||
3 | * Copyright (C) 1995-2005 IBM Corp | ||
4 | * | ||
5 | * Largely rewritten by Cort Dougan (cort@cs.nmt.edu) | ||
6 | * and Paul Mackerras. | ||
7 | * Adapted for iSeries by Mike Corrigan (mikejc@us.ibm.com) | ||
8 | * PPC64 updates by Dave Engebretsen (engebret@us.ibm.com) | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or | ||
11 | * modify it under the terms of the GNU General Public License | ||
12 | * as published by the Free Software Foundation; either version | ||
13 | * 2 of the License, or (at your option) any later version. | ||
14 | */ | ||
15 | |||
16 | #include <asm/processor.h> | ||
17 | #include <asm/asm-offsets.h> | ||
18 | #include <asm/ppc_asm.h> | ||
19 | |||
20 | .text | ||
21 | |||
22 | /* Handle pending interrupts in interrupt context */ | ||
23 | _GLOBAL(iseries_handle_interrupts) | ||
24 | li r0,0x5555 | ||
25 | sc | ||
26 | blr | ||
diff --git a/arch/powerpc/platforms/iseries/naca.h b/arch/powerpc/platforms/iseries/naca.h deleted file mode 100644 index f01708e12862..000000000000 --- a/arch/powerpc/platforms/iseries/naca.h +++ /dev/null | |||
@@ -1,24 +0,0 @@ | |||
1 | #ifndef _PLATFORMS_ISERIES_NACA_H | ||
2 | #define _PLATFORMS_ISERIES_NACA_H | ||
3 | |||
4 | /* | ||
5 | * c 2001 PPC 64 Team, IBM Corp | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; either version | ||
10 | * 2 of the License, or (at your option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <asm/types.h> | ||
14 | |||
15 | struct naca_struct { | ||
16 | /* Kernel only data - undefined for user space */ | ||
17 | const void *xItVpdAreas; /* VPD Data 0x00 */ | ||
18 | void *xRamDisk; /* iSeries ramdisk 0x08 */ | ||
19 | u64 xRamDiskSize; /* In pages 0x10 */ | ||
20 | }; | ||
21 | |||
22 | extern struct naca_struct naca; | ||
23 | |||
24 | #endif /* _PLATFORMS_ISERIES_NACA_H */ | ||
diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c deleted file mode 100644 index c75412884625..000000000000 --- a/arch/powerpc/platforms/iseries/pci.c +++ /dev/null | |||
@@ -1,919 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001 Allan Trautman, IBM Corporation | ||
3 | * Copyright (C) 2005,2007 Stephen Rothwell, IBM Corp | ||
4 | * | ||
5 | * iSeries specific routines for PCI. | ||
6 | * | ||
7 | * Based on code from pci.c and iSeries_pci.c 32bit | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | */ | ||
23 | |||
24 | #undef DEBUG | ||
25 | |||
26 | #include <linux/jiffies.h> | ||
27 | #include <linux/kernel.h> | ||
28 | #include <linux/list.h> | ||
29 | #include <linux/string.h> | ||
30 | #include <linux/slab.h> | ||
31 | #include <linux/init.h> | ||
32 | #include <linux/pci.h> | ||
33 | #include <linux/of.h> | ||
34 | #include <linux/ratelimit.h> | ||
35 | |||
36 | #include <asm/types.h> | ||
37 | #include <asm/io.h> | ||
38 | #include <asm/irq.h> | ||
39 | #include <asm/prom.h> | ||
40 | #include <asm/machdep.h> | ||
41 | #include <asm/pci-bridge.h> | ||
42 | #include <asm/iommu.h> | ||
43 | #include <asm/abs_addr.h> | ||
44 | #include <asm/firmware.h> | ||
45 | |||
46 | #include <asm/iseries/hv_types.h> | ||
47 | #include <asm/iseries/hv_call_xm.h> | ||
48 | #include <asm/iseries/mf.h> | ||
49 | #include <asm/iseries/iommu.h> | ||
50 | |||
51 | #include <asm/ppc-pci.h> | ||
52 | |||
53 | #include "irq.h" | ||
54 | #include "pci.h" | ||
55 | #include "call_pci.h" | ||
56 | |||
57 | #define PCI_RETRY_MAX 3 | ||
58 | static int limit_pci_retries = 1; /* Set Retry Error on. */ | ||
59 | |||
60 | /* | ||
61 | * Table defines | ||
62 | * Each Entry size is 4 MB * 1024 Entries = 4GB I/O address space. | ||
63 | */ | ||
64 | #define IOMM_TABLE_MAX_ENTRIES 1024 | ||
65 | #define IOMM_TABLE_ENTRY_SIZE 0x0000000000400000UL | ||
66 | #define BASE_IO_MEMORY 0xE000000000000000UL | ||
67 | #define END_IO_MEMORY 0xEFFFFFFFFFFFFFFFUL | ||
68 | |||
69 | static unsigned long max_io_memory = BASE_IO_MEMORY; | ||
70 | static long current_iomm_table_entry; | ||
71 | |||
72 | /* | ||
73 | * Lookup Tables. | ||
74 | */ | ||
75 | static struct device_node *iomm_table[IOMM_TABLE_MAX_ENTRIES]; | ||
76 | static u64 ds_addr_table[IOMM_TABLE_MAX_ENTRIES]; | ||
77 | |||
78 | static DEFINE_SPINLOCK(iomm_table_lock); | ||
79 | |||
80 | /* | ||
81 | * Generate a Direct Select Address for the Hypervisor | ||
82 | */ | ||
83 | static inline u64 iseries_ds_addr(struct device_node *node) | ||
84 | { | ||
85 | struct pci_dn *pdn = PCI_DN(node); | ||
86 | const u32 *sbp = of_get_property(node, "linux,subbus", NULL); | ||
87 | |||
88 | return ((u64)pdn->busno << 48) + ((u64)(sbp ? *sbp : 0) << 40) | ||
89 | + ((u64)0x10 << 32); | ||
90 | } | ||
91 | |||
92 | /* | ||
93 | * Size of Bus VPD data | ||
94 | */ | ||
95 | #define BUS_VPDSIZE 1024 | ||
96 | |||
97 | /* | ||
98 | * Bus Vpd Tags | ||
99 | */ | ||
100 | #define VPD_END_OF_AREA 0x79 | ||
101 | #define VPD_ID_STRING 0x82 | ||
102 | #define VPD_VENDOR_AREA 0x84 | ||
103 | |||
104 | /* | ||
105 | * Mfg Area Tags | ||
106 | */ | ||
107 | #define VPD_FRU_FRAME_ID 0x4649 /* "FI" */ | ||
108 | #define VPD_SLOT_MAP_FORMAT 0x4D46 /* "MF" */ | ||
109 | #define VPD_SLOT_MAP 0x534D /* "SM" */ | ||
110 | |||
111 | /* | ||
112 | * Structures of the areas | ||
113 | */ | ||
114 | struct mfg_vpd_area { | ||
115 | u16 tag; | ||
116 | u8 length; | ||
117 | u8 data1; | ||
118 | u8 data2; | ||
119 | }; | ||
120 | #define MFG_ENTRY_SIZE 3 | ||
121 | |||
122 | struct slot_map { | ||
123 | u8 agent; | ||
124 | u8 secondary_agent; | ||
125 | u8 phb; | ||
126 | char card_location[3]; | ||
127 | char parms[8]; | ||
128 | char reserved[2]; | ||
129 | }; | ||
130 | #define SLOT_ENTRY_SIZE 16 | ||
131 | |||
132 | /* | ||
133 | * Parse the Slot Area | ||
134 | */ | ||
135 | static void __init iseries_parse_slot_area(struct slot_map *map, int len, | ||
136 | HvAgentId agent, u8 *phb, char card[4]) | ||
137 | { | ||
138 | /* | ||
139 | * Parse Slot label until we find the one requested | ||
140 | */ | ||
141 | while (len > 0) { | ||
142 | if (map->agent == agent) { | ||
143 | /* | ||
144 | * If Phb wasn't found, grab the entry first one found. | ||
145 | */ | ||
146 | if (*phb == 0xff) | ||
147 | *phb = map->phb; | ||
148 | /* Found it, extract the data. */ | ||
149 | if (map->phb == *phb) { | ||
150 | memcpy(card, &map->card_location, 3); | ||
151 | card[3] = 0; | ||
152 | break; | ||
153 | } | ||
154 | } | ||
155 | /* Point to the next Slot */ | ||
156 | map = (struct slot_map *)((char *)map + SLOT_ENTRY_SIZE); | ||
157 | len -= SLOT_ENTRY_SIZE; | ||
158 | } | ||
159 | } | ||
160 | |||
161 | /* | ||
162 | * Parse the Mfg Area | ||
163 | */ | ||
164 | static void __init iseries_parse_mfg_area(struct mfg_vpd_area *area, int len, | ||
165 | HvAgentId agent, u8 *phb, u8 *frame, char card[4]) | ||
166 | { | ||
167 | u16 slot_map_fmt = 0; | ||
168 | |||
169 | /* Parse Mfg Data */ | ||
170 | while (len > 0) { | ||
171 | int mfg_tag_len = area->length; | ||
172 | /* Frame ID (FI 4649020310 ) */ | ||
173 | if (area->tag == VPD_FRU_FRAME_ID) | ||
174 | *frame = area->data1; | ||
175 | /* Slot Map Format (MF 4D46020004 ) */ | ||
176 | else if (area->tag == VPD_SLOT_MAP_FORMAT) | ||
177 | slot_map_fmt = (area->data1 * 256) | ||
178 | + area->data2; | ||
179 | /* Slot Map (SM 534D90 */ | ||
180 | else if (area->tag == VPD_SLOT_MAP) { | ||
181 | struct slot_map *slot_map; | ||
182 | |||
183 | if (slot_map_fmt == 0x1004) | ||
184 | slot_map = (struct slot_map *)((char *)area | ||
185 | + MFG_ENTRY_SIZE + 1); | ||
186 | else | ||
187 | slot_map = (struct slot_map *)((char *)area | ||
188 | + MFG_ENTRY_SIZE); | ||
189 | iseries_parse_slot_area(slot_map, mfg_tag_len, | ||
190 | agent, phb, card); | ||
191 | } | ||
192 | /* | ||
193 | * Point to the next Mfg Area | ||
194 | * Use defined size, sizeof give wrong answer | ||
195 | */ | ||
196 | area = (struct mfg_vpd_area *)((char *)area + mfg_tag_len | ||
197 | + MFG_ENTRY_SIZE); | ||
198 | len -= (mfg_tag_len + MFG_ENTRY_SIZE); | ||
199 | } | ||
200 | } | ||
201 | |||
202 | /* | ||
203 | * Look for "BUS".. Data is not Null terminated. | ||
204 | * PHBID of 0xFF indicates PHB was not found in VPD Data. | ||
205 | */ | ||
206 | static u8 __init iseries_parse_phbid(u8 *area, int len) | ||
207 | { | ||
208 | while (len > 0) { | ||
209 | if ((*area == 'B') && (*(area + 1) == 'U') | ||
210 | && (*(area + 2) == 'S')) { | ||
211 | area += 3; | ||
212 | while (*area == ' ') | ||
213 | area++; | ||
214 | return *area & 0x0F; | ||
215 | } | ||
216 | area++; | ||
217 | len--; | ||
218 | } | ||
219 | return 0xff; | ||
220 | } | ||
221 | |||
222 | /* | ||
223 | * Parse out the VPD Areas | ||
224 | */ | ||
225 | static void __init iseries_parse_vpd(u8 *data, int data_len, | ||
226 | HvAgentId agent, u8 *frame, char card[4]) | ||
227 | { | ||
228 | u8 phb = 0xff; | ||
229 | |||
230 | while (data_len > 0) { | ||
231 | int len; | ||
232 | u8 tag = *data; | ||
233 | |||
234 | if (tag == VPD_END_OF_AREA) | ||
235 | break; | ||
236 | len = *(data + 1) + (*(data + 2) * 256); | ||
237 | data += 3; | ||
238 | data_len -= 3; | ||
239 | if (tag == VPD_ID_STRING) | ||
240 | phb = iseries_parse_phbid(data, len); | ||
241 | else if (tag == VPD_VENDOR_AREA) | ||
242 | iseries_parse_mfg_area((struct mfg_vpd_area *)data, len, | ||
243 | agent, &phb, frame, card); | ||
244 | /* Point to next Area. */ | ||
245 | data += len; | ||
246 | data_len -= len; | ||
247 | } | ||
248 | } | ||
249 | |||
250 | static int __init iseries_get_location_code(u16 bus, HvAgentId agent, | ||
251 | u8 *frame, char card[4]) | ||
252 | { | ||
253 | int status = 0; | ||
254 | int bus_vpd_len = 0; | ||
255 | u8 *bus_vpd = kmalloc(BUS_VPDSIZE, GFP_KERNEL); | ||
256 | |||
257 | if (bus_vpd == NULL) { | ||
258 | printk("PCI: Bus VPD Buffer allocation failure.\n"); | ||
259 | return 0; | ||
260 | } | ||
261 | bus_vpd_len = HvCallPci_getBusVpd(bus, iseries_hv_addr(bus_vpd), | ||
262 | BUS_VPDSIZE); | ||
263 | if (bus_vpd_len == 0) { | ||
264 | printk("PCI: Bus VPD Buffer zero length.\n"); | ||
265 | goto out_free; | ||
266 | } | ||
267 | /* printk("PCI: bus_vpd: %p, %d\n",bus_vpd, bus_vpd_len); */ | ||
268 | /* Make sure this is what I think it is */ | ||
269 | if (*bus_vpd != VPD_ID_STRING) { | ||
270 | printk("PCI: Bus VPD Buffer missing starting tag.\n"); | ||
271 | goto out_free; | ||
272 | } | ||
273 | iseries_parse_vpd(bus_vpd, bus_vpd_len, agent, frame, card); | ||
274 | status = 1; | ||
275 | out_free: | ||
276 | kfree(bus_vpd); | ||
277 | return status; | ||
278 | } | ||
279 | |||
280 | /* | ||
281 | * Prints the device information. | ||
282 | * - Pass in pci_dev* pointer to the device. | ||
283 | * - Pass in the device count | ||
284 | * | ||
285 | * Format: | ||
286 | * PCI: Bus 0, Device 26, Vendor 0x12AE Frame 1, Card C10 Ethernet | ||
287 | * controller | ||
288 | */ | ||
289 | static void __init iseries_device_information(struct pci_dev *pdev, | ||
290 | u16 bus, HvSubBusNumber subbus) | ||
291 | { | ||
292 | u8 frame = 0; | ||
293 | char card[4]; | ||
294 | HvAgentId agent; | ||
295 | |||
296 | agent = ISERIES_PCI_AGENTID(ISERIES_GET_DEVICE_FROM_SUBBUS(subbus), | ||
297 | ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus)); | ||
298 | |||
299 | if (iseries_get_location_code(bus, agent, &frame, card)) { | ||
300 | printk(KERN_INFO "PCI: %s, Vendor %04X Frame%3d, " | ||
301 | "Card %4s 0x%04X\n", pci_name(pdev), pdev->vendor, | ||
302 | frame, card, (int)(pdev->class >> 8)); | ||
303 | } | ||
304 | } | ||
305 | |||
306 | /* | ||
307 | * iomm_table_allocate_entry | ||
308 | * | ||
309 | * Adds pci_dev entry in address translation table | ||
310 | * | ||
311 | * - Allocates the number of entries required in table base on BAR | ||
312 | * size. | ||
313 | * - Allocates starting at BASE_IO_MEMORY and increases. | ||
314 | * - The size is round up to be a multiple of entry size. | ||
315 | * - CurrentIndex is incremented to keep track of the last entry. | ||
316 | * - Builds the resource entry for allocated BARs. | ||
317 | */ | ||
318 | static void __init iomm_table_allocate_entry(struct pci_dev *dev, int bar_num) | ||
319 | { | ||
320 | struct resource *bar_res = &dev->resource[bar_num]; | ||
321 | long bar_size = pci_resource_len(dev, bar_num); | ||
322 | struct device_node *dn = pci_device_to_OF_node(dev); | ||
323 | |||
324 | /* | ||
325 | * No space to allocate, quick exit, skip Allocation. | ||
326 | */ | ||
327 | if (bar_size == 0) | ||
328 | return; | ||
329 | /* | ||
330 | * Set Resource values. | ||
331 | */ | ||
332 | spin_lock(&iomm_table_lock); | ||
333 | bar_res->start = BASE_IO_MEMORY + | ||
334 | IOMM_TABLE_ENTRY_SIZE * current_iomm_table_entry; | ||
335 | bar_res->end = bar_res->start + bar_size - 1; | ||
336 | /* | ||
337 | * Allocate the number of table entries needed for BAR. | ||
338 | */ | ||
339 | while (bar_size > 0 ) { | ||
340 | iomm_table[current_iomm_table_entry] = dn; | ||
341 | ds_addr_table[current_iomm_table_entry] = | ||
342 | iseries_ds_addr(dn) | (bar_num << 24); | ||
343 | bar_size -= IOMM_TABLE_ENTRY_SIZE; | ||
344 | ++current_iomm_table_entry; | ||
345 | } | ||
346 | max_io_memory = BASE_IO_MEMORY + | ||
347 | IOMM_TABLE_ENTRY_SIZE * current_iomm_table_entry; | ||
348 | spin_unlock(&iomm_table_lock); | ||
349 | } | ||
350 | |||
351 | /* | ||
352 | * allocate_device_bars | ||
353 | * | ||
354 | * - Allocates ALL pci_dev BAR's and updates the resources with the | ||
355 | * BAR value. BARS with zero length will have the resources | ||
356 | * The HvCallPci_getBarParms is used to get the size of the BAR | ||
357 | * space. It calls iomm_table_allocate_entry to allocate | ||
358 | * each entry. | ||
359 | * - Loops through The Bar resources(0 - 5) including the ROM | ||
360 | * is resource(6). | ||
361 | */ | ||
362 | static void __init allocate_device_bars(struct pci_dev *dev) | ||
363 | { | ||
364 | int bar_num; | ||
365 | |||
366 | for (bar_num = 0; bar_num <= PCI_ROM_RESOURCE; ++bar_num) | ||
367 | iomm_table_allocate_entry(dev, bar_num); | ||
368 | } | ||
369 | |||
370 | /* | ||
371 | * Log error information to system console. | ||
372 | * Filter out the device not there errors. | ||
373 | * PCI: EADs Connect Failed 0x18.58.10 Rc: 0x00xx | ||
374 | * PCI: Read Vendor Failed 0x18.58.10 Rc: 0x00xx | ||
375 | * PCI: Connect Bus Unit Failed 0x18.58.10 Rc: 0x00xx | ||
376 | */ | ||
377 | static void pci_log_error(char *error, int bus, int subbus, | ||
378 | int agent, int hv_res) | ||
379 | { | ||
380 | if (hv_res == 0x0302) | ||
381 | return; | ||
382 | printk(KERN_ERR "PCI: %s Failed: 0x%02X.%02X.%02X Rc: 0x%04X", | ||
383 | error, bus, subbus, agent, hv_res); | ||
384 | } | ||
385 | |||
386 | /* | ||
387 | * Look down the chain to find the matching Device Device | ||
388 | */ | ||
389 | static struct device_node *find_device_node(int bus, int devfn) | ||
390 | { | ||
391 | struct device_node *node; | ||
392 | |||
393 | for (node = NULL; (node = of_find_all_nodes(node)); ) { | ||
394 | struct pci_dn *pdn = PCI_DN(node); | ||
395 | |||
396 | if (pdn && (bus == pdn->busno) && (devfn == pdn->devfn)) | ||
397 | return node; | ||
398 | } | ||
399 | return NULL; | ||
400 | } | ||
401 | |||
402 | /* | ||
403 | * iSeries_pcibios_fixup_resources | ||
404 | * | ||
405 | * Fixes up all resources for devices | ||
406 | */ | ||
407 | void __init iSeries_pcibios_fixup_resources(struct pci_dev *pdev) | ||
408 | { | ||
409 | const u32 *agent; | ||
410 | const u32 *sub_bus; | ||
411 | unsigned char bus = pdev->bus->number; | ||
412 | struct device_node *node; | ||
413 | int i; | ||
414 | |||
415 | node = pci_device_to_OF_node(pdev); | ||
416 | pr_debug("PCI: iSeries %s, pdev %p, node %p\n", | ||
417 | pci_name(pdev), pdev, node); | ||
418 | if (!node) { | ||
419 | printk("PCI: %s disabled, device tree entry not found !\n", | ||
420 | pci_name(pdev)); | ||
421 | for (i = 0; i <= PCI_ROM_RESOURCE; i++) | ||
422 | pdev->resource[i].flags = 0; | ||
423 | return; | ||
424 | } | ||
425 | sub_bus = of_get_property(node, "linux,subbus", NULL); | ||
426 | agent = of_get_property(node, "linux,agent-id", NULL); | ||
427 | if (agent && sub_bus) { | ||
428 | u8 irq = iSeries_allocate_IRQ(bus, 0, *sub_bus); | ||
429 | int err; | ||
430 | |||
431 | err = HvCallXm_connectBusUnit(bus, *sub_bus, *agent, irq); | ||
432 | if (err) | ||
433 | pci_log_error("Connect Bus Unit", | ||
434 | bus, *sub_bus, *agent, err); | ||
435 | else { | ||
436 | err = HvCallPci_configStore8(bus, *sub_bus, | ||
437 | *agent, PCI_INTERRUPT_LINE, irq); | ||
438 | if (err) | ||
439 | pci_log_error("PciCfgStore Irq Failed!", | ||
440 | bus, *sub_bus, *agent, err); | ||
441 | else | ||
442 | pdev->irq = irq; | ||
443 | } | ||
444 | } | ||
445 | |||
446 | allocate_device_bars(pdev); | ||
447 | if (likely(sub_bus)) | ||
448 | iseries_device_information(pdev, bus, *sub_bus); | ||
449 | else | ||
450 | printk(KERN_ERR "PCI: Device node %s has missing or invalid " | ||
451 | "linux,subbus property\n", node->full_name); | ||
452 | } | ||
453 | |||
454 | /* | ||
455 | * iSeries_pci_final_fixup(void) | ||
456 | */ | ||
457 | void __init iSeries_pci_final_fixup(void) | ||
458 | { | ||
459 | /* Fix up at the device node and pci_dev relationship */ | ||
460 | mf_display_src(0xC9000100); | ||
461 | iSeries_activate_IRQs(); | ||
462 | mf_display_src(0xC9000200); | ||
463 | } | ||
464 | |||
465 | /* | ||
466 | * Config space read and write functions. | ||
467 | * For now at least, we look for the device node for the bus and devfn | ||
468 | * that we are asked to access. It may be possible to translate the devfn | ||
469 | * to a subbus and deviceid more directly. | ||
470 | */ | ||
471 | static u64 hv_cfg_read_func[4] = { | ||
472 | HvCallPciConfigLoad8, HvCallPciConfigLoad16, | ||
473 | HvCallPciConfigLoad32, HvCallPciConfigLoad32 | ||
474 | }; | ||
475 | |||
476 | static u64 hv_cfg_write_func[4] = { | ||
477 | HvCallPciConfigStore8, HvCallPciConfigStore16, | ||
478 | HvCallPciConfigStore32, HvCallPciConfigStore32 | ||
479 | }; | ||
480 | |||
481 | /* | ||
482 | * Read PCI config space | ||
483 | */ | ||
484 | static int iSeries_pci_read_config(struct pci_bus *bus, unsigned int devfn, | ||
485 | int offset, int size, u32 *val) | ||
486 | { | ||
487 | struct device_node *node = find_device_node(bus->number, devfn); | ||
488 | u64 fn; | ||
489 | struct HvCallPci_LoadReturn ret; | ||
490 | |||
491 | if (node == NULL) | ||
492 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
493 | if (offset > 255) { | ||
494 | *val = ~0; | ||
495 | return PCIBIOS_BAD_REGISTER_NUMBER; | ||
496 | } | ||
497 | |||
498 | fn = hv_cfg_read_func[(size - 1) & 3]; | ||
499 | HvCall3Ret16(fn, &ret, iseries_ds_addr(node), offset, 0); | ||
500 | |||
501 | if (ret.rc != 0) { | ||
502 | *val = ~0; | ||
503 | return PCIBIOS_DEVICE_NOT_FOUND; /* or something */ | ||
504 | } | ||
505 | |||
506 | *val = ret.value; | ||
507 | return 0; | ||
508 | } | ||
509 | |||
510 | /* | ||
511 | * Write PCI config space | ||
512 | */ | ||
513 | |||
514 | static int iSeries_pci_write_config(struct pci_bus *bus, unsigned int devfn, | ||
515 | int offset, int size, u32 val) | ||
516 | { | ||
517 | struct device_node *node = find_device_node(bus->number, devfn); | ||
518 | u64 fn; | ||
519 | u64 ret; | ||
520 | |||
521 | if (node == NULL) | ||
522 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
523 | if (offset > 255) | ||
524 | return PCIBIOS_BAD_REGISTER_NUMBER; | ||
525 | |||
526 | fn = hv_cfg_write_func[(size - 1) & 3]; | ||
527 | ret = HvCall4(fn, iseries_ds_addr(node), offset, val, 0); | ||
528 | |||
529 | if (ret != 0) | ||
530 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
531 | |||
532 | return 0; | ||
533 | } | ||
534 | |||
535 | static struct pci_ops iSeries_pci_ops = { | ||
536 | .read = iSeries_pci_read_config, | ||
537 | .write = iSeries_pci_write_config | ||
538 | }; | ||
539 | |||
540 | /* | ||
541 | * Check Return Code | ||
542 | * -> On Failure, print and log information. | ||
543 | * Increment Retry Count, if exceeds max, panic partition. | ||
544 | * | ||
545 | * PCI: Device 23.90 ReadL I/O Error( 0): 0x1234 | ||
546 | * PCI: Device 23.90 ReadL Retry( 1) | ||
547 | * PCI: Device 23.90 ReadL Retry Successful(1) | ||
548 | */ | ||
549 | static int check_return_code(char *type, struct device_node *dn, | ||
550 | int *retry, u64 ret) | ||
551 | { | ||
552 | if (ret != 0) { | ||
553 | struct pci_dn *pdn = PCI_DN(dn); | ||
554 | |||
555 | (*retry)++; | ||
556 | printk("PCI: %s: Device 0x%04X:%02X I/O Error(%2d): 0x%04X\n", | ||
557 | type, pdn->busno, pdn->devfn, | ||
558 | *retry, (int)ret); | ||
559 | /* | ||
560 | * Bump the retry and check for retry count exceeded. | ||
561 | * If, Exceeded, panic the system. | ||
562 | */ | ||
563 | if (((*retry) > PCI_RETRY_MAX) && | ||
564 | (limit_pci_retries > 0)) { | ||
565 | mf_display_src(0xB6000103); | ||
566 | panic_timeout = 0; | ||
567 | panic("PCI: Hardware I/O Error, SRC B6000103, " | ||
568 | "Automatic Reboot Disabled.\n"); | ||
569 | } | ||
570 | return -1; /* Retry Try */ | ||
571 | } | ||
572 | return 0; | ||
573 | } | ||
574 | |||
575 | /* | ||
576 | * Translate the I/O Address into a device node, bar, and bar offset. | ||
577 | * Note: Make sure the passed variable end up on the stack to avoid | ||
578 | * the exposure of being device global. | ||
579 | */ | ||
580 | static inline struct device_node *xlate_iomm_address( | ||
581 | const volatile void __iomem *addr, | ||
582 | u64 *dsaptr, u64 *bar_offset, const char *func) | ||
583 | { | ||
584 | unsigned long orig_addr; | ||
585 | unsigned long base_addr; | ||
586 | unsigned long ind; | ||
587 | struct device_node *dn; | ||
588 | |||
589 | orig_addr = (unsigned long __force)addr; | ||
590 | if ((orig_addr < BASE_IO_MEMORY) || (orig_addr >= max_io_memory)) { | ||
591 | static DEFINE_RATELIMIT_STATE(ratelimit, 60 * HZ, 10); | ||
592 | |||
593 | if (__ratelimit(&ratelimit)) | ||
594 | printk(KERN_ERR | ||
595 | "iSeries_%s: invalid access at IO address %p\n", | ||
596 | func, addr); | ||
597 | return NULL; | ||
598 | } | ||
599 | base_addr = orig_addr - BASE_IO_MEMORY; | ||
600 | ind = base_addr / IOMM_TABLE_ENTRY_SIZE; | ||
601 | dn = iomm_table[ind]; | ||
602 | |||
603 | if (dn != NULL) { | ||
604 | *dsaptr = ds_addr_table[ind]; | ||
605 | *bar_offset = base_addr % IOMM_TABLE_ENTRY_SIZE; | ||
606 | } else | ||
607 | panic("PCI: Invalid PCI IO address detected!\n"); | ||
608 | return dn; | ||
609 | } | ||
610 | |||
611 | /* | ||
612 | * Read MM I/O Instructions for the iSeries | ||
613 | * On MM I/O error, all ones are returned and iSeries_pci_IoError is cal | ||
614 | * else, data is returned in Big Endian format. | ||
615 | */ | ||
616 | static u8 iseries_readb(const volatile void __iomem *addr) | ||
617 | { | ||
618 | u64 bar_offset; | ||
619 | u64 dsa; | ||
620 | int retry = 0; | ||
621 | struct HvCallPci_LoadReturn ret; | ||
622 | struct device_node *dn = | ||
623 | xlate_iomm_address(addr, &dsa, &bar_offset, "read_byte"); | ||
624 | |||
625 | if (dn == NULL) | ||
626 | return 0xff; | ||
627 | do { | ||
628 | HvCall3Ret16(HvCallPciBarLoad8, &ret, dsa, bar_offset, 0); | ||
629 | } while (check_return_code("RDB", dn, &retry, ret.rc) != 0); | ||
630 | |||
631 | return ret.value; | ||
632 | } | ||
633 | |||
634 | static u16 iseries_readw_be(const volatile void __iomem *addr) | ||
635 | { | ||
636 | u64 bar_offset; | ||
637 | u64 dsa; | ||
638 | int retry = 0; | ||
639 | struct HvCallPci_LoadReturn ret; | ||
640 | struct device_node *dn = | ||
641 | xlate_iomm_address(addr, &dsa, &bar_offset, "read_word"); | ||
642 | |||
643 | if (dn == NULL) | ||
644 | return 0xffff; | ||
645 | do { | ||
646 | HvCall3Ret16(HvCallPciBarLoad16, &ret, dsa, | ||
647 | bar_offset, 0); | ||
648 | } while (check_return_code("RDW", dn, &retry, ret.rc) != 0); | ||
649 | |||
650 | return ret.value; | ||
651 | } | ||
652 | |||
653 | static u32 iseries_readl_be(const volatile void __iomem *addr) | ||
654 | { | ||
655 | u64 bar_offset; | ||
656 | u64 dsa; | ||
657 | int retry = 0; | ||
658 | struct HvCallPci_LoadReturn ret; | ||
659 | struct device_node *dn = | ||
660 | xlate_iomm_address(addr, &dsa, &bar_offset, "read_long"); | ||
661 | |||
662 | if (dn == NULL) | ||
663 | return 0xffffffff; | ||
664 | do { | ||
665 | HvCall3Ret16(HvCallPciBarLoad32, &ret, dsa, | ||
666 | bar_offset, 0); | ||
667 | } while (check_return_code("RDL", dn, &retry, ret.rc) != 0); | ||
668 | |||
669 | return ret.value; | ||
670 | } | ||
671 | |||
672 | /* | ||
673 | * Write MM I/O Instructions for the iSeries | ||
674 | * | ||
675 | */ | ||
676 | static void iseries_writeb(u8 data, volatile void __iomem *addr) | ||
677 | { | ||
678 | u64 bar_offset; | ||
679 | u64 dsa; | ||
680 | int retry = 0; | ||
681 | u64 rc; | ||
682 | struct device_node *dn = | ||
683 | xlate_iomm_address(addr, &dsa, &bar_offset, "write_byte"); | ||
684 | |||
685 | if (dn == NULL) | ||
686 | return; | ||
687 | do { | ||
688 | rc = HvCall4(HvCallPciBarStore8, dsa, bar_offset, data, 0); | ||
689 | } while (check_return_code("WWB", dn, &retry, rc) != 0); | ||
690 | } | ||
691 | |||
692 | static void iseries_writew_be(u16 data, volatile void __iomem *addr) | ||
693 | { | ||
694 | u64 bar_offset; | ||
695 | u64 dsa; | ||
696 | int retry = 0; | ||
697 | u64 rc; | ||
698 | struct device_node *dn = | ||
699 | xlate_iomm_address(addr, &dsa, &bar_offset, "write_word"); | ||
700 | |||
701 | if (dn == NULL) | ||
702 | return; | ||
703 | do { | ||
704 | rc = HvCall4(HvCallPciBarStore16, dsa, bar_offset, data, 0); | ||
705 | } while (check_return_code("WWW", dn, &retry, rc) != 0); | ||
706 | } | ||
707 | |||
708 | static void iseries_writel_be(u32 data, volatile void __iomem *addr) | ||
709 | { | ||
710 | u64 bar_offset; | ||
711 | u64 dsa; | ||
712 | int retry = 0; | ||
713 | u64 rc; | ||
714 | struct device_node *dn = | ||
715 | xlate_iomm_address(addr, &dsa, &bar_offset, "write_long"); | ||
716 | |||
717 | if (dn == NULL) | ||
718 | return; | ||
719 | do { | ||
720 | rc = HvCall4(HvCallPciBarStore32, dsa, bar_offset, data, 0); | ||
721 | } while (check_return_code("WWL", dn, &retry, rc) != 0); | ||
722 | } | ||
723 | |||
724 | static u16 iseries_readw(const volatile void __iomem *addr) | ||
725 | { | ||
726 | return le16_to_cpu(iseries_readw_be(addr)); | ||
727 | } | ||
728 | |||
729 | static u32 iseries_readl(const volatile void __iomem *addr) | ||
730 | { | ||
731 | return le32_to_cpu(iseries_readl_be(addr)); | ||
732 | } | ||
733 | |||
734 | static void iseries_writew(u16 data, volatile void __iomem *addr) | ||
735 | { | ||
736 | iseries_writew_be(cpu_to_le16(data), addr); | ||
737 | } | ||
738 | |||
739 | static void iseries_writel(u32 data, volatile void __iomem *addr) | ||
740 | { | ||
741 | iseries_writel(cpu_to_le32(data), addr); | ||
742 | } | ||
743 | |||
744 | static void iseries_readsb(const volatile void __iomem *addr, void *buf, | ||
745 | unsigned long count) | ||
746 | { | ||
747 | u8 *dst = buf; | ||
748 | while(count-- > 0) | ||
749 | *(dst++) = iseries_readb(addr); | ||
750 | } | ||
751 | |||
752 | static void iseries_readsw(const volatile void __iomem *addr, void *buf, | ||
753 | unsigned long count) | ||
754 | { | ||
755 | u16 *dst = buf; | ||
756 | while(count-- > 0) | ||
757 | *(dst++) = iseries_readw_be(addr); | ||
758 | } | ||
759 | |||
760 | static void iseries_readsl(const volatile void __iomem *addr, void *buf, | ||
761 | unsigned long count) | ||
762 | { | ||
763 | u32 *dst = buf; | ||
764 | while(count-- > 0) | ||
765 | *(dst++) = iseries_readl_be(addr); | ||
766 | } | ||
767 | |||
768 | static void iseries_writesb(volatile void __iomem *addr, const void *buf, | ||
769 | unsigned long count) | ||
770 | { | ||
771 | const u8 *src = buf; | ||
772 | while(count-- > 0) | ||
773 | iseries_writeb(*(src++), addr); | ||
774 | } | ||
775 | |||
776 | static void iseries_writesw(volatile void __iomem *addr, const void *buf, | ||
777 | unsigned long count) | ||
778 | { | ||
779 | const u16 *src = buf; | ||
780 | while(count-- > 0) | ||
781 | iseries_writew_be(*(src++), addr); | ||
782 | } | ||
783 | |||
784 | static void iseries_writesl(volatile void __iomem *addr, const void *buf, | ||
785 | unsigned long count) | ||
786 | { | ||
787 | const u32 *src = buf; | ||
788 | while(count-- > 0) | ||
789 | iseries_writel_be(*(src++), addr); | ||
790 | } | ||
791 | |||
792 | static void iseries_memset_io(volatile void __iomem *addr, int c, | ||
793 | unsigned long n) | ||
794 | { | ||
795 | volatile char __iomem *d = addr; | ||
796 | |||
797 | while (n-- > 0) | ||
798 | iseries_writeb(c, d++); | ||
799 | } | ||
800 | |||
801 | static void iseries_memcpy_fromio(void *dest, const volatile void __iomem *src, | ||
802 | unsigned long n) | ||
803 | { | ||
804 | char *d = dest; | ||
805 | const volatile char __iomem *s = src; | ||
806 | |||
807 | while (n-- > 0) | ||
808 | *d++ = iseries_readb(s++); | ||
809 | } | ||
810 | |||
811 | static void iseries_memcpy_toio(volatile void __iomem *dest, const void *src, | ||
812 | unsigned long n) | ||
813 | { | ||
814 | const char *s = src; | ||
815 | volatile char __iomem *d = dest; | ||
816 | |||
817 | while (n-- > 0) | ||
818 | iseries_writeb(*s++, d++); | ||
819 | } | ||
820 | |||
821 | /* We only set MMIO ops. The default PIO ops will be default | ||
822 | * to the MMIO ops + pci_io_base which is 0 on iSeries as | ||
823 | * expected so both should work. | ||
824 | * | ||
825 | * Note that we don't implement the readq/writeq versions as | ||
826 | * I don't know of an HV call for doing so. Thus, the default | ||
827 | * operation will be used instead, which will fault a the value | ||
828 | * return by iSeries for MMIO addresses always hits a non mapped | ||
829 | * area. This is as good as the BUG() we used to have there. | ||
830 | */ | ||
831 | static struct ppc_pci_io __initdata iseries_pci_io = { | ||
832 | .readb = iseries_readb, | ||
833 | .readw = iseries_readw, | ||
834 | .readl = iseries_readl, | ||
835 | .readw_be = iseries_readw_be, | ||
836 | .readl_be = iseries_readl_be, | ||
837 | .writeb = iseries_writeb, | ||
838 | .writew = iseries_writew, | ||
839 | .writel = iseries_writel, | ||
840 | .writew_be = iseries_writew_be, | ||
841 | .writel_be = iseries_writel_be, | ||
842 | .readsb = iseries_readsb, | ||
843 | .readsw = iseries_readsw, | ||
844 | .readsl = iseries_readsl, | ||
845 | .writesb = iseries_writesb, | ||
846 | .writesw = iseries_writesw, | ||
847 | .writesl = iseries_writesl, | ||
848 | .memset_io = iseries_memset_io, | ||
849 | .memcpy_fromio = iseries_memcpy_fromio, | ||
850 | .memcpy_toio = iseries_memcpy_toio, | ||
851 | }; | ||
852 | |||
853 | /* | ||
854 | * iSeries_pcibios_init | ||
855 | * | ||
856 | * Description: | ||
857 | * This function checks for all possible system PCI host bridges that connect | ||
858 | * PCI buses. The system hypervisor is queried as to the guest partition | ||
859 | * ownership status. A pci_controller is built for any bus which is partially | ||
860 | * owned or fully owned by this guest partition. | ||
861 | */ | ||
862 | void __init iSeries_pcibios_init(void) | ||
863 | { | ||
864 | struct pci_controller *phb; | ||
865 | struct device_node *root = of_find_node_by_path("/"); | ||
866 | struct device_node *node = NULL; | ||
867 | |||
868 | /* Install IO hooks */ | ||
869 | ppc_pci_io = iseries_pci_io; | ||
870 | |||
871 | pci_probe_only = 1; | ||
872 | |||
873 | /* iSeries has no IO space in the common sense, it needs to set | ||
874 | * the IO base to 0 | ||
875 | */ | ||
876 | pci_io_base = 0; | ||
877 | |||
878 | if (root == NULL) { | ||
879 | printk(KERN_CRIT "iSeries_pcibios_init: can't find root " | ||
880 | "of device tree\n"); | ||
881 | return; | ||
882 | } | ||
883 | while ((node = of_get_next_child(root, node)) != NULL) { | ||
884 | HvBusNumber bus; | ||
885 | const u32 *busp; | ||
886 | |||
887 | if ((node->type == NULL) || (strcmp(node->type, "pci") != 0)) | ||
888 | continue; | ||
889 | |||
890 | busp = of_get_property(node, "bus-range", NULL); | ||
891 | if (busp == NULL) | ||
892 | continue; | ||
893 | bus = *busp; | ||
894 | printk("bus %d appears to exist\n", bus); | ||
895 | phb = pcibios_alloc_controller(node); | ||
896 | if (phb == NULL) | ||
897 | continue; | ||
898 | /* All legacy iSeries PHBs are in domain zero */ | ||
899 | phb->global_number = 0; | ||
900 | |||
901 | phb->first_busno = bus; | ||
902 | phb->last_busno = bus; | ||
903 | phb->ops = &iSeries_pci_ops; | ||
904 | phb->io_base_virt = (void __iomem *)_IO_BASE; | ||
905 | phb->io_resource.flags = IORESOURCE_IO; | ||
906 | phb->io_resource.start = BASE_IO_MEMORY; | ||
907 | phb->io_resource.end = END_IO_MEMORY; | ||
908 | phb->io_resource.name = "iSeries PCI IO"; | ||
909 | phb->mem_resources[0].flags = IORESOURCE_MEM; | ||
910 | phb->mem_resources[0].start = BASE_IO_MEMORY; | ||
911 | phb->mem_resources[0].end = END_IO_MEMORY; | ||
912 | phb->mem_resources[0].name = "Series PCI MEM"; | ||
913 | } | ||
914 | |||
915 | of_node_put(root); | ||
916 | |||
917 | pci_devs_phb_init(); | ||
918 | } | ||
919 | |||
diff --git a/arch/powerpc/platforms/iseries/pci.h b/arch/powerpc/platforms/iseries/pci.h deleted file mode 100644 index d9cf974c2718..000000000000 --- a/arch/powerpc/platforms/iseries/pci.h +++ /dev/null | |||
@@ -1,58 +0,0 @@ | |||
1 | #ifndef _PLATFORMS_ISERIES_PCI_H | ||
2 | #define _PLATFORMS_ISERIES_PCI_H | ||
3 | |||
4 | /* | ||
5 | * Created by Allan Trautman on Tue Feb 20, 2001. | ||
6 | * | ||
7 | * Define some useful macros for the iSeries pci routines. | ||
8 | * Copyright (C) 2001 Allan H Trautman, IBM Corporation | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the: | ||
22 | * Free Software Foundation, Inc., | ||
23 | * 59 Temple Place, Suite 330, | ||
24 | * Boston, MA 02111-1307 USA | ||
25 | * | ||
26 | * Change Activity: | ||
27 | * Created Feb 20, 2001 | ||
28 | * Added device reset, March 22, 2001 | ||
29 | * Ported to ppc64, May 25, 2001 | ||
30 | * End Change Activity | ||
31 | */ | ||
32 | |||
33 | /* | ||
34 | * Decodes Linux DevFn to iSeries DevFn, bridge device, or function. | ||
35 | * For Linux, see PCI_SLOT and PCI_FUNC in include/linux/pci.h | ||
36 | */ | ||
37 | |||
38 | #define ISERIES_PCI_AGENTID(idsel, func) \ | ||
39 | (((idsel & 0x0F) << 4) | (func & 0x07)) | ||
40 | #define ISERIES_ENCODE_DEVICE(agentid) \ | ||
41 | ((0x10) | ((agentid & 0x20) >> 2) | (agentid & 0x07)) | ||
42 | |||
43 | #define ISERIES_GET_DEVICE_FROM_SUBBUS(subbus) ((subbus >> 5) & 0x7) | ||
44 | #define ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus) ((subbus >> 2) & 0x7) | ||
45 | |||
46 | struct pci_dev; | ||
47 | |||
48 | #ifdef CONFIG_PCI | ||
49 | extern void iSeries_pcibios_init(void); | ||
50 | extern void iSeries_pci_final_fixup(void); | ||
51 | extern void iSeries_pcibios_fixup_resources(struct pci_dev *dev); | ||
52 | #else | ||
53 | static inline void iSeries_pcibios_init(void) { } | ||
54 | static inline void iSeries_pci_final_fixup(void) { } | ||
55 | static inline void iSeries_pcibios_fixup_resources(struct pci_dev *dev) {} | ||
56 | #endif | ||
57 | |||
58 | #endif /* _PLATFORMS_ISERIES_PCI_H */ | ||
diff --git a/arch/powerpc/platforms/iseries/proc.c b/arch/powerpc/platforms/iseries/proc.c deleted file mode 100644 index 06763682db47..000000000000 --- a/arch/powerpc/platforms/iseries/proc.c +++ /dev/null | |||
@@ -1,120 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001 Kyle A. Lucke IBM Corporation | ||
3 | * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen IBM Corporation | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/proc_fs.h> | ||
21 | #include <linux/seq_file.h> | ||
22 | #include <linux/param.h> /* for HZ */ | ||
23 | #include <asm/paca.h> | ||
24 | #include <asm/processor.h> | ||
25 | #include <asm/time.h> | ||
26 | #include <asm/lppaca.h> | ||
27 | #include <asm/firmware.h> | ||
28 | #include <asm/iseries/hv_call_xm.h> | ||
29 | |||
30 | #include "processor_vpd.h" | ||
31 | #include "main_store.h" | ||
32 | |||
33 | static int __init iseries_proc_create(void) | ||
34 | { | ||
35 | struct proc_dir_entry *e; | ||
36 | |||
37 | if (!firmware_has_feature(FW_FEATURE_ISERIES)) | ||
38 | return 0; | ||
39 | |||
40 | e = proc_mkdir("iSeries", 0); | ||
41 | if (!e) | ||
42 | return 1; | ||
43 | |||
44 | return 0; | ||
45 | } | ||
46 | core_initcall(iseries_proc_create); | ||
47 | |||
48 | static unsigned long startTitan = 0; | ||
49 | static unsigned long startTb = 0; | ||
50 | |||
51 | static int proc_titantod_show(struct seq_file *m, void *v) | ||
52 | { | ||
53 | unsigned long tb0, titan_tod; | ||
54 | |||
55 | tb0 = get_tb(); | ||
56 | titan_tod = HvCallXm_loadTod(); | ||
57 | |||
58 | seq_printf(m, "Titan\n" ); | ||
59 | seq_printf(m, " time base = %016lx\n", tb0); | ||
60 | seq_printf(m, " titan tod = %016lx\n", titan_tod); | ||
61 | seq_printf(m, " xProcFreq = %016x\n", | ||
62 | xIoHriProcessorVpd[0].xProcFreq); | ||
63 | seq_printf(m, " xTimeBaseFreq = %016x\n", | ||
64 | xIoHriProcessorVpd[0].xTimeBaseFreq); | ||
65 | seq_printf(m, " tb_ticks_per_jiffy = %lu\n", tb_ticks_per_jiffy); | ||
66 | seq_printf(m, " tb_ticks_per_usec = %lu\n", tb_ticks_per_usec); | ||
67 | |||
68 | if (!startTitan) { | ||
69 | startTitan = titan_tod; | ||
70 | startTb = tb0; | ||
71 | } else { | ||
72 | unsigned long titan_usec = (titan_tod - startTitan) >> 12; | ||
73 | unsigned long tb_ticks = (tb0 - startTb); | ||
74 | unsigned long titan_jiffies = titan_usec / (1000000/HZ); | ||
75 | unsigned long titan_jiff_usec = titan_jiffies * (1000000/HZ); | ||
76 | unsigned long titan_jiff_rem_usec = | ||
77 | titan_usec - titan_jiff_usec; | ||
78 | unsigned long tb_jiffies = tb_ticks / tb_ticks_per_jiffy; | ||
79 | unsigned long tb_jiff_ticks = tb_jiffies * tb_ticks_per_jiffy; | ||
80 | unsigned long tb_jiff_rem_ticks = tb_ticks - tb_jiff_ticks; | ||
81 | unsigned long tb_jiff_rem_usec = | ||
82 | tb_jiff_rem_ticks / tb_ticks_per_usec; | ||
83 | unsigned long new_tb_ticks_per_jiffy = | ||
84 | (tb_ticks * (1000000/HZ))/titan_usec; | ||
85 | |||
86 | seq_printf(m, " titan elapsed = %lu uSec\n", titan_usec); | ||
87 | seq_printf(m, " tb elapsed = %lu ticks\n", tb_ticks); | ||
88 | seq_printf(m, " titan jiffies = %lu.%04lu\n", titan_jiffies, | ||
89 | titan_jiff_rem_usec); | ||
90 | seq_printf(m, " tb jiffies = %lu.%04lu\n", tb_jiffies, | ||
91 | tb_jiff_rem_usec); | ||
92 | seq_printf(m, " new tb_ticks_per_jiffy = %lu\n", | ||
93 | new_tb_ticks_per_jiffy); | ||
94 | } | ||
95 | |||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | static int proc_titantod_open(struct inode *inode, struct file *file) | ||
100 | { | ||
101 | return single_open(file, proc_titantod_show, NULL); | ||
102 | } | ||
103 | |||
104 | static const struct file_operations proc_titantod_operations = { | ||
105 | .open = proc_titantod_open, | ||
106 | .read = seq_read, | ||
107 | .llseek = seq_lseek, | ||
108 | .release = single_release, | ||
109 | }; | ||
110 | |||
111 | static int __init iseries_proc_init(void) | ||
112 | { | ||
113 | if (!firmware_has_feature(FW_FEATURE_ISERIES)) | ||
114 | return 0; | ||
115 | |||
116 | proc_create("iSeries/titanTod", S_IFREG|S_IRUGO, NULL, | ||
117 | &proc_titantod_operations); | ||
118 | return 0; | ||
119 | } | ||
120 | __initcall(iseries_proc_init); | ||
diff --git a/arch/powerpc/platforms/iseries/processor_vpd.h b/arch/powerpc/platforms/iseries/processor_vpd.h deleted file mode 100644 index 7ac5d0d0dbfa..000000000000 --- a/arch/powerpc/platforms/iseries/processor_vpd.h +++ /dev/null | |||
@@ -1,85 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001 Mike Corrigan IBM Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | #ifndef _ISERIES_PROCESSOR_VPD_H | ||
19 | #define _ISERIES_PROCESSOR_VPD_H | ||
20 | |||
21 | #include <asm/types.h> | ||
22 | |||
23 | /* | ||
24 | * This struct maps Processor Vpd that is DMAd to SLIC by CSP | ||
25 | */ | ||
26 | struct IoHriProcessorVpd { | ||
27 | u8 xFormat; // VPD format indicator x00-x00 | ||
28 | u8 xProcStatus:8; // Processor State x01-x01 | ||
29 | u8 xSecondaryThreadCount; // Secondary thread cnt x02-x02 | ||
30 | u8 xSrcType:1; // Src Type x03-x03 | ||
31 | u8 xSrcSoft:1; // Src stay soft ... | ||
32 | u8 xSrcParable:1; // Src parable ... | ||
33 | u8 xRsvd1:5; // Reserved ... | ||
34 | u16 xHvPhysicalProcIndex; // Hypervisor physical proc index04-x05 | ||
35 | u16 xRsvd2; // Reserved x06-x07 | ||
36 | u32 xHwNodeId; // Hardware node id x08-x0B | ||
37 | u32 xHwProcId; // Hardware processor id x0C-x0F | ||
38 | |||
39 | u32 xTypeNum; // Card Type/CCIN number x10-x13 | ||
40 | u32 xModelNum; // Model/Feature number x14-x17 | ||
41 | u64 xSerialNum; // Serial number x18-x1F | ||
42 | char xPartNum[12]; // Book Part or FPU number x20-x2B | ||
43 | char xMfgID[4]; // Manufacturing ID x2C-x2F | ||
44 | |||
45 | u32 xProcFreq; // Processor Frequency x30-x33 | ||
46 | u32 xTimeBaseFreq; // Time Base Frequency x34-x37 | ||
47 | |||
48 | u32 xChipEcLevel; // Chip EC Levels x38-x3B | ||
49 | u32 xProcIdReg; // PIR SPR value x3C-x3F | ||
50 | u32 xPVR; // PVR value x40-x43 | ||
51 | u8 xRsvd3[12]; // Reserved x44-x4F | ||
52 | |||
53 | u32 xInstCacheSize; // Instruction cache size in KB x50-x53 | ||
54 | u32 xInstBlockSize; // Instruction cache block size x54-x57 | ||
55 | u32 xDataCacheOperandSize; // Data cache operand size x58-x5B | ||
56 | u32 xInstCacheOperandSize; // Inst cache operand size x5C-x5F | ||
57 | |||
58 | u32 xDataL1CacheSizeKB; // L1 data cache size in KB x60-x63 | ||
59 | u32 xDataL1CacheLineSize; // L1 data cache block size x64-x67 | ||
60 | u64 xRsvd4; // Reserved x68-x6F | ||
61 | |||
62 | u32 xDataL2CacheSizeKB; // L2 data cache size in KB x70-x73 | ||
63 | u32 xDataL2CacheLineSize; // L2 data cache block size x74-x77 | ||
64 | u64 xRsvd5; // Reserved x78-x7F | ||
65 | |||
66 | u32 xDataL3CacheSizeKB; // L3 data cache size in KB x80-x83 | ||
67 | u32 xDataL3CacheLineSize; // L3 data cache block size x84-x87 | ||
68 | u64 xRsvd6; // Reserved x88-x8F | ||
69 | |||
70 | u64 xFruLabel; // Card Location Label x90-x97 | ||
71 | u8 xSlotsOnCard; // Slots on card (0=no slots) x98-x98 | ||
72 | u8 xPartLocFlag; // Location flag (0-pluggable 1-imbedded) x99-x99 | ||
73 | u16 xSlotMapIndex; // Index in slot map table x9A-x9B | ||
74 | u8 xSmartCardPortNo; // Smart card port number x9C-x9C | ||
75 | u8 xRsvd7; // Reserved x9D-x9D | ||
76 | u16 xFrameIdAndRackUnit; // Frame ID and rack unit adr x9E-x9F | ||
77 | |||
78 | u8 xRsvd8[24]; // Reserved xA0-xB7 | ||
79 | |||
80 | char xProcSrc[72]; // CSP format SRC xB8-xFF | ||
81 | }; | ||
82 | |||
83 | extern struct IoHriProcessorVpd xIoHriProcessorVpd[]; | ||
84 | |||
85 | #endif /* _ISERIES_PROCESSOR_VPD_H */ | ||
diff --git a/arch/powerpc/platforms/iseries/release_data.h b/arch/powerpc/platforms/iseries/release_data.h deleted file mode 100644 index 6ad7d843e8fc..000000000000 --- a/arch/powerpc/platforms/iseries/release_data.h +++ /dev/null | |||
@@ -1,63 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001 Mike Corrigan IBM Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | #ifndef _ISERIES_RELEASE_DATA_H | ||
19 | #define _ISERIES_RELEASE_DATA_H | ||
20 | |||
21 | /* | ||
22 | * This control block contains the critical information about the | ||
23 | * release so that it can be changed in the future (ie, the virtual | ||
24 | * address of the OS's NACA). | ||
25 | */ | ||
26 | #include <asm/types.h> | ||
27 | #include "naca.h" | ||
28 | |||
29 | /* | ||
30 | * When we IPL a secondary partition, we will check if if the | ||
31 | * secondary xMinPlicVrmIndex > the primary xVrmIndex. | ||
32 | * If it is then this tells PLIC that this secondary is not | ||
33 | * supported running on this "old" of a level of PLIC. | ||
34 | * | ||
35 | * Likewise, we will compare the primary xMinSlicVrmIndex to | ||
36 | * the secondary xVrmIndex. | ||
37 | * If the primary xMinSlicVrmDelta > secondary xVrmDelta then we | ||
38 | * know that this PLIC does not support running an OS "that old". | ||
39 | */ | ||
40 | |||
41 | #define HVREL_TAGSINACTIVE 0x8000 | ||
42 | #define HVREL_32BIT 0x4000 | ||
43 | #define HVREL_NOSHAREDPROCS 0x2000 | ||
44 | #define HVREL_NOHMT 0x1000 | ||
45 | |||
46 | struct HvReleaseData { | ||
47 | u32 xDesc; /* Descriptor "HvRD" ebcdic x00-x03 */ | ||
48 | u16 xSize; /* Size of this control block x04-x05 */ | ||
49 | u16 xVpdAreasPtrOffset; /* Offset in NACA of ItVpdAreas x06-x07 */ | ||
50 | struct naca_struct *xSlicNacaAddr; /* Virt addr of SLIC NACA x08-x0F */ | ||
51 | u32 xMsNucDataOffset; /* Offset of Linux Mapping Data x10-x13 */ | ||
52 | u32 xRsvd1; /* Reserved x14-x17 */ | ||
53 | u16 xFlags; | ||
54 | u16 xVrmIndex; /* VRM Index of OS image x1A-x1B */ | ||
55 | u16 xMinSupportedPlicVrmIndex; /* Min PLIC level (soft) x1C-x1D */ | ||
56 | u16 xMinCompatablePlicVrmIndex; /* Min PLIC levelP (hard) x1E-x1F */ | ||
57 | char xVrmName[12]; /* Displayable name x20-x2B */ | ||
58 | char xRsvd3[20]; /* Reserved x2C-x3F */ | ||
59 | }; | ||
60 | |||
61 | extern const struct HvReleaseData hvReleaseData; | ||
62 | |||
63 | #endif /* _ISERIES_RELEASE_DATA_H */ | ||
diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c deleted file mode 100644 index a5fbf4cb6329..000000000000 --- a/arch/powerpc/platforms/iseries/setup.c +++ /dev/null | |||
@@ -1,718 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2000 Mike Corrigan <mikejc@us.ibm.com> | ||
3 | * Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu> | ||
4 | * | ||
5 | * Description: | ||
6 | * Architecture- / platform-specific boot-time initialization code for | ||
7 | * the IBM iSeries LPAR. Adapted from original code by Grant Erickson and | ||
8 | * code by Gary Thomas, Cort Dougan <cort@fsmlabs.com>, and Dan Malek | ||
9 | * <dan@net4x.com>. | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License | ||
13 | * as published by the Free Software Foundation; either version | ||
14 | * 2 of the License, or (at your option) any later version. | ||
15 | */ | ||
16 | |||
17 | #undef DEBUG | ||
18 | |||
19 | #include <linux/init.h> | ||
20 | #include <linux/threads.h> | ||
21 | #include <linux/smp.h> | ||
22 | #include <linux/param.h> | ||
23 | #include <linux/string.h> | ||
24 | #include <linux/export.h> | ||
25 | #include <linux/seq_file.h> | ||
26 | #include <linux/kdev_t.h> | ||
27 | #include <linux/kexec.h> | ||
28 | #include <linux/major.h> | ||
29 | #include <linux/root_dev.h> | ||
30 | #include <linux/kernel.h> | ||
31 | #include <linux/hrtimer.h> | ||
32 | #include <linux/tick.h> | ||
33 | |||
34 | #include <asm/processor.h> | ||
35 | #include <asm/machdep.h> | ||
36 | #include <asm/page.h> | ||
37 | #include <asm/mmu.h> | ||
38 | #include <asm/pgtable.h> | ||
39 | #include <asm/mmu_context.h> | ||
40 | #include <asm/cputable.h> | ||
41 | #include <asm/sections.h> | ||
42 | #include <asm/iommu.h> | ||
43 | #include <asm/firmware.h> | ||
44 | #include <asm/system.h> | ||
45 | #include <asm/time.h> | ||
46 | #include <asm/paca.h> | ||
47 | #include <asm/cache.h> | ||
48 | #include <asm/abs_addr.h> | ||
49 | #include <asm/iseries/hv_lp_config.h> | ||
50 | #include <asm/iseries/hv_call_event.h> | ||
51 | #include <asm/iseries/hv_call_xm.h> | ||
52 | #include <asm/iseries/it_lp_queue.h> | ||
53 | #include <asm/iseries/mf.h> | ||
54 | #include <asm/iseries/hv_lp_event.h> | ||
55 | #include <asm/iseries/lpar_map.h> | ||
56 | #include <asm/udbg.h> | ||
57 | #include <asm/irq.h> | ||
58 | |||
59 | #include "naca.h" | ||
60 | #include "setup.h" | ||
61 | #include "irq.h" | ||
62 | #include "vpd_areas.h" | ||
63 | #include "processor_vpd.h" | ||
64 | #include "it_lp_naca.h" | ||
65 | #include "main_store.h" | ||
66 | #include "call_sm.h" | ||
67 | #include "call_hpt.h" | ||
68 | #include "pci.h" | ||
69 | |||
70 | #ifdef DEBUG | ||
71 | #define DBG(fmt...) udbg_printf(fmt) | ||
72 | #else | ||
73 | #define DBG(fmt...) | ||
74 | #endif | ||
75 | |||
76 | /* Function Prototypes */ | ||
77 | static unsigned long build_iSeries_Memory_Map(void); | ||
78 | static void iseries_shared_idle(void); | ||
79 | static void iseries_dedicated_idle(void); | ||
80 | |||
81 | |||
82 | struct MemoryBlock { | ||
83 | unsigned long absStart; | ||
84 | unsigned long absEnd; | ||
85 | unsigned long logicalStart; | ||
86 | unsigned long logicalEnd; | ||
87 | }; | ||
88 | |||
89 | /* | ||
90 | * Process the main store vpd to determine where the holes in memory are | ||
91 | * and return the number of physical blocks and fill in the array of | ||
92 | * block data. | ||
93 | */ | ||
94 | static unsigned long iSeries_process_Condor_mainstore_vpd( | ||
95 | struct MemoryBlock *mb_array, unsigned long max_entries) | ||
96 | { | ||
97 | unsigned long holeFirstChunk, holeSizeChunks; | ||
98 | unsigned long numMemoryBlocks = 1; | ||
99 | struct IoHriMainStoreSegment4 *msVpd = | ||
100 | (struct IoHriMainStoreSegment4 *)xMsVpd; | ||
101 | unsigned long holeStart = msVpd->nonInterleavedBlocksStartAdr; | ||
102 | unsigned long holeEnd = msVpd->nonInterleavedBlocksEndAdr; | ||
103 | unsigned long holeSize = holeEnd - holeStart; | ||
104 | |||
105 | printk("Mainstore_VPD: Condor\n"); | ||
106 | /* | ||
107 | * Determine if absolute memory has any | ||
108 | * holes so that we can interpret the | ||
109 | * access map we get back from the hypervisor | ||
110 | * correctly. | ||
111 | */ | ||
112 | mb_array[0].logicalStart = 0; | ||
113 | mb_array[0].logicalEnd = 0x100000000UL; | ||
114 | mb_array[0].absStart = 0; | ||
115 | mb_array[0].absEnd = 0x100000000UL; | ||
116 | |||
117 | if (holeSize) { | ||
118 | numMemoryBlocks = 2; | ||
119 | holeStart = holeStart & 0x000fffffffffffffUL; | ||
120 | holeStart = addr_to_chunk(holeStart); | ||
121 | holeFirstChunk = holeStart; | ||
122 | holeSize = addr_to_chunk(holeSize); | ||
123 | holeSizeChunks = holeSize; | ||
124 | printk( "Main store hole: start chunk = %0lx, size = %0lx chunks\n", | ||
125 | holeFirstChunk, holeSizeChunks ); | ||
126 | mb_array[0].logicalEnd = holeFirstChunk; | ||
127 | mb_array[0].absEnd = holeFirstChunk; | ||
128 | mb_array[1].logicalStart = holeFirstChunk; | ||
129 | mb_array[1].logicalEnd = 0x100000000UL - holeSizeChunks; | ||
130 | mb_array[1].absStart = holeFirstChunk + holeSizeChunks; | ||
131 | mb_array[1].absEnd = 0x100000000UL; | ||
132 | } | ||
133 | return numMemoryBlocks; | ||
134 | } | ||
135 | |||
136 | #define MaxSegmentAreas 32 | ||
137 | #define MaxSegmentAdrRangeBlocks 128 | ||
138 | #define MaxAreaRangeBlocks 4 | ||
139 | |||
140 | static unsigned long iSeries_process_Regatta_mainstore_vpd( | ||
141 | struct MemoryBlock *mb_array, unsigned long max_entries) | ||
142 | { | ||
143 | struct IoHriMainStoreSegment5 *msVpdP = | ||
144 | (struct IoHriMainStoreSegment5 *)xMsVpd; | ||
145 | unsigned long numSegmentBlocks = 0; | ||
146 | u32 existsBits = msVpdP->msAreaExists; | ||
147 | unsigned long area_num; | ||
148 | |||
149 | printk("Mainstore_VPD: Regatta\n"); | ||
150 | |||
151 | for (area_num = 0; area_num < MaxSegmentAreas; ++area_num ) { | ||
152 | unsigned long numAreaBlocks; | ||
153 | struct IoHriMainStoreArea4 *currentArea; | ||
154 | |||
155 | if (existsBits & 0x80000000) { | ||
156 | unsigned long block_num; | ||
157 | |||
158 | currentArea = &msVpdP->msAreaArray[area_num]; | ||
159 | numAreaBlocks = currentArea->numAdrRangeBlocks; | ||
160 | printk("ms_vpd: processing area %2ld blocks=%ld", | ||
161 | area_num, numAreaBlocks); | ||
162 | for (block_num = 0; block_num < numAreaBlocks; | ||
163 | ++block_num ) { | ||
164 | /* Process an address range block */ | ||
165 | struct MemoryBlock tempBlock; | ||
166 | unsigned long i; | ||
167 | |||
168 | tempBlock.absStart = | ||
169 | (unsigned long)currentArea->xAdrRangeBlock[block_num].blockStart; | ||
170 | tempBlock.absEnd = | ||
171 | (unsigned long)currentArea->xAdrRangeBlock[block_num].blockEnd; | ||
172 | tempBlock.logicalStart = 0; | ||
173 | tempBlock.logicalEnd = 0; | ||
174 | printk("\n block %ld absStart=%016lx absEnd=%016lx", | ||
175 | block_num, tempBlock.absStart, | ||
176 | tempBlock.absEnd); | ||
177 | |||
178 | for (i = 0; i < numSegmentBlocks; ++i) { | ||
179 | if (mb_array[i].absStart == | ||
180 | tempBlock.absStart) | ||
181 | break; | ||
182 | } | ||
183 | if (i == numSegmentBlocks) { | ||
184 | if (numSegmentBlocks == max_entries) | ||
185 | panic("iSeries_process_mainstore_vpd: too many memory blocks"); | ||
186 | mb_array[numSegmentBlocks] = tempBlock; | ||
187 | ++numSegmentBlocks; | ||
188 | } else | ||
189 | printk(" (duplicate)"); | ||
190 | } | ||
191 | printk("\n"); | ||
192 | } | ||
193 | existsBits <<= 1; | ||
194 | } | ||
195 | /* Now sort the blocks found into ascending sequence */ | ||
196 | if (numSegmentBlocks > 1) { | ||
197 | unsigned long m, n; | ||
198 | |||
199 | for (m = 0; m < numSegmentBlocks - 1; ++m) { | ||
200 | for (n = numSegmentBlocks - 1; m < n; --n) { | ||
201 | if (mb_array[n].absStart < | ||
202 | mb_array[n-1].absStart) { | ||
203 | struct MemoryBlock tempBlock; | ||
204 | |||
205 | tempBlock = mb_array[n]; | ||
206 | mb_array[n] = mb_array[n-1]; | ||
207 | mb_array[n-1] = tempBlock; | ||
208 | } | ||
209 | } | ||
210 | } | ||
211 | } | ||
212 | /* | ||
213 | * Assign "logical" addresses to each block. These | ||
214 | * addresses correspond to the hypervisor "bitmap" space. | ||
215 | * Convert all addresses into units of 256K chunks. | ||
216 | */ | ||
217 | { | ||
218 | unsigned long i, nextBitmapAddress; | ||
219 | |||
220 | printk("ms_vpd: %ld sorted memory blocks\n", numSegmentBlocks); | ||
221 | nextBitmapAddress = 0; | ||
222 | for (i = 0; i < numSegmentBlocks; ++i) { | ||
223 | unsigned long length = mb_array[i].absEnd - | ||
224 | mb_array[i].absStart; | ||
225 | |||
226 | mb_array[i].logicalStart = nextBitmapAddress; | ||
227 | mb_array[i].logicalEnd = nextBitmapAddress + length; | ||
228 | nextBitmapAddress += length; | ||
229 | printk(" Bitmap range: %016lx - %016lx\n" | ||
230 | " Absolute range: %016lx - %016lx\n", | ||
231 | mb_array[i].logicalStart, | ||
232 | mb_array[i].logicalEnd, | ||
233 | mb_array[i].absStart, mb_array[i].absEnd); | ||
234 | mb_array[i].absStart = addr_to_chunk(mb_array[i].absStart & | ||
235 | 0x000fffffffffffffUL); | ||
236 | mb_array[i].absEnd = addr_to_chunk(mb_array[i].absEnd & | ||
237 | 0x000fffffffffffffUL); | ||
238 | mb_array[i].logicalStart = | ||
239 | addr_to_chunk(mb_array[i].logicalStart); | ||
240 | mb_array[i].logicalEnd = addr_to_chunk(mb_array[i].logicalEnd); | ||
241 | } | ||
242 | } | ||
243 | |||
244 | return numSegmentBlocks; | ||
245 | } | ||
246 | |||
247 | static unsigned long iSeries_process_mainstore_vpd(struct MemoryBlock *mb_array, | ||
248 | unsigned long max_entries) | ||
249 | { | ||
250 | unsigned long i; | ||
251 | unsigned long mem_blocks = 0; | ||
252 | |||
253 | if (mmu_has_feature(MMU_FTR_SLB)) | ||
254 | mem_blocks = iSeries_process_Regatta_mainstore_vpd(mb_array, | ||
255 | max_entries); | ||
256 | else | ||
257 | mem_blocks = iSeries_process_Condor_mainstore_vpd(mb_array, | ||
258 | max_entries); | ||
259 | |||
260 | printk("Mainstore_VPD: numMemoryBlocks = %ld\n", mem_blocks); | ||
261 | for (i = 0; i < mem_blocks; ++i) { | ||
262 | printk("Mainstore_VPD: block %3ld logical chunks %016lx - %016lx\n" | ||
263 | " abs chunks %016lx - %016lx\n", | ||
264 | i, mb_array[i].logicalStart, mb_array[i].logicalEnd, | ||
265 | mb_array[i].absStart, mb_array[i].absEnd); | ||
266 | } | ||
267 | return mem_blocks; | ||
268 | } | ||
269 | |||
270 | static void __init iSeries_get_cmdline(void) | ||
271 | { | ||
272 | char *p, *q; | ||
273 | |||
274 | /* copy the command line parameter from the primary VSP */ | ||
275 | HvCallEvent_dmaToSp(cmd_line, 2 * 64* 1024, 256, | ||
276 | HvLpDma_Direction_RemoteToLocal); | ||
277 | |||
278 | p = cmd_line; | ||
279 | q = cmd_line + 255; | ||
280 | while(p < q) { | ||
281 | if (!*p || *p == '\n') | ||
282 | break; | ||
283 | ++p; | ||
284 | } | ||
285 | *p = 0; | ||
286 | } | ||
287 | |||
288 | static void __init iSeries_init_early(void) | ||
289 | { | ||
290 | DBG(" -> iSeries_init_early()\n"); | ||
291 | |||
292 | /* Snapshot the timebase, for use in later recalibration */ | ||
293 | iSeries_time_init_early(); | ||
294 | |||
295 | /* | ||
296 | * Initialize the DMA/TCE management | ||
297 | */ | ||
298 | iommu_init_early_iSeries(); | ||
299 | |||
300 | /* Initialize machine-dependency vectors */ | ||
301 | #ifdef CONFIG_SMP | ||
302 | smp_init_iSeries(); | ||
303 | #endif | ||
304 | |||
305 | /* Associate Lp Event Queue 0 with processor 0 */ | ||
306 | HvCallEvent_setLpEventQueueInterruptProc(0, 0); | ||
307 | |||
308 | mf_init(); | ||
309 | |||
310 | DBG(" <- iSeries_init_early()\n"); | ||
311 | } | ||
312 | |||
313 | struct mschunks_map mschunks_map = { | ||
314 | /* XXX We don't use these, but Piranha might need them. */ | ||
315 | .chunk_size = MSCHUNKS_CHUNK_SIZE, | ||
316 | .chunk_shift = MSCHUNKS_CHUNK_SHIFT, | ||
317 | .chunk_mask = MSCHUNKS_OFFSET_MASK, | ||
318 | }; | ||
319 | EXPORT_SYMBOL(mschunks_map); | ||
320 | |||
321 | static void mschunks_alloc(unsigned long num_chunks) | ||
322 | { | ||
323 | klimit = _ALIGN(klimit, sizeof(u32)); | ||
324 | mschunks_map.mapping = (u32 *)klimit; | ||
325 | klimit += num_chunks * sizeof(u32); | ||
326 | mschunks_map.num_chunks = num_chunks; | ||
327 | } | ||
328 | |||
329 | /* | ||
330 | * The iSeries may have very large memories ( > 128 GB ) and a partition | ||
331 | * may get memory in "chunks" that may be anywhere in the 2**52 real | ||
332 | * address space. The chunks are 256K in size. To map this to the | ||
333 | * memory model Linux expects, the AS/400 specific code builds a | ||
334 | * translation table to translate what Linux thinks are "physical" | ||
335 | * addresses to the actual real addresses. This allows us to make | ||
336 | * it appear to Linux that we have contiguous memory starting at | ||
337 | * physical address zero while in fact this could be far from the truth. | ||
338 | * To avoid confusion, I'll let the words physical and/or real address | ||
339 | * apply to the Linux addresses while I'll use "absolute address" to | ||
340 | * refer to the actual hardware real address. | ||
341 | * | ||
342 | * build_iSeries_Memory_Map gets information from the Hypervisor and | ||
343 | * looks at the Main Store VPD to determine the absolute addresses | ||
344 | * of the memory that has been assigned to our partition and builds | ||
345 | * a table used to translate Linux's physical addresses to these | ||
346 | * absolute addresses. Absolute addresses are needed when | ||
347 | * communicating with the hypervisor (e.g. to build HPT entries) | ||
348 | * | ||
349 | * Returns the physical memory size | ||
350 | */ | ||
351 | |||
352 | static unsigned long __init build_iSeries_Memory_Map(void) | ||
353 | { | ||
354 | u32 loadAreaFirstChunk, loadAreaLastChunk, loadAreaSize; | ||
355 | u32 nextPhysChunk; | ||
356 | u32 hptFirstChunk, hptLastChunk, hptSizeChunks, hptSizePages; | ||
357 | u32 totalChunks,moreChunks; | ||
358 | u32 currChunk, thisChunk, absChunk; | ||
359 | u32 currDword; | ||
360 | u32 chunkBit; | ||
361 | u64 map; | ||
362 | struct MemoryBlock mb[32]; | ||
363 | unsigned long numMemoryBlocks, curBlock; | ||
364 | |||
365 | /* Chunk size on iSeries is 256K bytes */ | ||
366 | totalChunks = (u32)HvLpConfig_getMsChunks(); | ||
367 | mschunks_alloc(totalChunks); | ||
368 | |||
369 | /* | ||
370 | * Get absolute address of our load area | ||
371 | * and map it to physical address 0 | ||
372 | * This guarantees that the loadarea ends up at physical 0 | ||
373 | * otherwise, it might not be returned by PLIC as the first | ||
374 | * chunks | ||
375 | */ | ||
376 | |||
377 | loadAreaFirstChunk = (u32)addr_to_chunk(itLpNaca.xLoadAreaAddr); | ||
378 | loadAreaSize = itLpNaca.xLoadAreaChunks; | ||
379 | |||
380 | /* | ||
381 | * Only add the pages already mapped here. | ||
382 | * Otherwise we might add the hpt pages | ||
383 | * The rest of the pages of the load area | ||
384 | * aren't in the HPT yet and can still | ||
385 | * be assigned an arbitrary physical address | ||
386 | */ | ||
387 | if ((loadAreaSize * 64) > HvPagesToMap) | ||
388 | loadAreaSize = HvPagesToMap / 64; | ||
389 | |||
390 | loadAreaLastChunk = loadAreaFirstChunk + loadAreaSize - 1; | ||
391 | |||
392 | /* | ||
393 | * TODO Do we need to do something if the HPT is in the 64MB load area? | ||
394 | * This would be required if the itLpNaca.xLoadAreaChunks includes | ||
395 | * the HPT size | ||
396 | */ | ||
397 | |||
398 | printk("Mapping load area - physical addr = 0000000000000000\n" | ||
399 | " absolute addr = %016lx\n", | ||
400 | chunk_to_addr(loadAreaFirstChunk)); | ||
401 | printk("Load area size %dK\n", loadAreaSize * 256); | ||
402 | |||
403 | for (nextPhysChunk = 0; nextPhysChunk < loadAreaSize; ++nextPhysChunk) | ||
404 | mschunks_map.mapping[nextPhysChunk] = | ||
405 | loadAreaFirstChunk + nextPhysChunk; | ||
406 | |||
407 | /* | ||
408 | * Get absolute address of our HPT and remember it so | ||
409 | * we won't map it to any physical address | ||
410 | */ | ||
411 | hptFirstChunk = (u32)addr_to_chunk(HvCallHpt_getHptAddress()); | ||
412 | hptSizePages = (u32)HvCallHpt_getHptPages(); | ||
413 | hptSizeChunks = hptSizePages >> | ||
414 | (MSCHUNKS_CHUNK_SHIFT - HW_PAGE_SHIFT); | ||
415 | hptLastChunk = hptFirstChunk + hptSizeChunks - 1; | ||
416 | |||
417 | printk("HPT absolute addr = %016lx, size = %dK\n", | ||
418 | chunk_to_addr(hptFirstChunk), hptSizeChunks * 256); | ||
419 | |||
420 | /* | ||
421 | * Determine if absolute memory has any | ||
422 | * holes so that we can interpret the | ||
423 | * access map we get back from the hypervisor | ||
424 | * correctly. | ||
425 | */ | ||
426 | numMemoryBlocks = iSeries_process_mainstore_vpd(mb, 32); | ||
427 | |||
428 | /* | ||
429 | * Process the main store access map from the hypervisor | ||
430 | * to build up our physical -> absolute translation table | ||
431 | */ | ||
432 | curBlock = 0; | ||
433 | currChunk = 0; | ||
434 | currDword = 0; | ||
435 | moreChunks = totalChunks; | ||
436 | |||
437 | while (moreChunks) { | ||
438 | map = HvCallSm_get64BitsOfAccessMap(itLpNaca.xLpIndex, | ||
439 | currDword); | ||
440 | thisChunk = currChunk; | ||
441 | while (map) { | ||
442 | chunkBit = map >> 63; | ||
443 | map <<= 1; | ||
444 | if (chunkBit) { | ||
445 | --moreChunks; | ||
446 | while (thisChunk >= mb[curBlock].logicalEnd) { | ||
447 | ++curBlock; | ||
448 | if (curBlock >= numMemoryBlocks) | ||
449 | panic("out of memory blocks"); | ||
450 | } | ||
451 | if (thisChunk < mb[curBlock].logicalStart) | ||
452 | panic("memory block error"); | ||
453 | |||
454 | absChunk = mb[curBlock].absStart + | ||
455 | (thisChunk - mb[curBlock].logicalStart); | ||
456 | if (((absChunk < hptFirstChunk) || | ||
457 | (absChunk > hptLastChunk)) && | ||
458 | ((absChunk < loadAreaFirstChunk) || | ||
459 | (absChunk > loadAreaLastChunk))) { | ||
460 | mschunks_map.mapping[nextPhysChunk] = | ||
461 | absChunk; | ||
462 | ++nextPhysChunk; | ||
463 | } | ||
464 | } | ||
465 | ++thisChunk; | ||
466 | } | ||
467 | ++currDword; | ||
468 | currChunk += 64; | ||
469 | } | ||
470 | |||
471 | /* | ||
472 | * main store size (in chunks) is | ||
473 | * totalChunks - hptSizeChunks | ||
474 | * which should be equal to | ||
475 | * nextPhysChunk | ||
476 | */ | ||
477 | return chunk_to_addr(nextPhysChunk); | ||
478 | } | ||
479 | |||
480 | /* | ||
481 | * Document me. | ||
482 | */ | ||
483 | static void __init iSeries_setup_arch(void) | ||
484 | { | ||
485 | if (get_lppaca()->shared_proc) { | ||
486 | ppc_md.idle_loop = iseries_shared_idle; | ||
487 | printk(KERN_DEBUG "Using shared processor idle loop\n"); | ||
488 | } else { | ||
489 | ppc_md.idle_loop = iseries_dedicated_idle; | ||
490 | printk(KERN_DEBUG "Using dedicated idle loop\n"); | ||
491 | } | ||
492 | |||
493 | /* Setup the Lp Event Queue */ | ||
494 | setup_hvlpevent_queue(); | ||
495 | |||
496 | printk("Max logical processors = %d\n", | ||
497 | itVpdAreas.xSlicMaxLogicalProcs); | ||
498 | printk("Max physical processors = %d\n", | ||
499 | itVpdAreas.xSlicMaxPhysicalProcs); | ||
500 | |||
501 | iSeries_pcibios_init(); | ||
502 | } | ||
503 | |||
504 | static void iSeries_show_cpuinfo(struct seq_file *m) | ||
505 | { | ||
506 | seq_printf(m, "machine\t\t: 64-bit iSeries Logical Partition\n"); | ||
507 | } | ||
508 | |||
509 | static void __init iSeries_progress(char * st, unsigned short code) | ||
510 | { | ||
511 | printk("Progress: [%04x] - %s\n", (unsigned)code, st); | ||
512 | mf_display_progress(code); | ||
513 | } | ||
514 | |||
515 | static void __init iSeries_fixup_klimit(void) | ||
516 | { | ||
517 | /* | ||
518 | * Change klimit to take into account any ram disk | ||
519 | * that may be included | ||
520 | */ | ||
521 | if (naca.xRamDisk) | ||
522 | klimit = KERNELBASE + (u64)naca.xRamDisk + | ||
523 | (naca.xRamDiskSize * HW_PAGE_SIZE); | ||
524 | } | ||
525 | |||
526 | static int __init iSeries_src_init(void) | ||
527 | { | ||
528 | /* clear the progress line */ | ||
529 | if (firmware_has_feature(FW_FEATURE_ISERIES)) | ||
530 | ppc_md.progress(" ", 0xffff); | ||
531 | return 0; | ||
532 | } | ||
533 | |||
534 | late_initcall(iSeries_src_init); | ||
535 | |||
536 | static inline void process_iSeries_events(void) | ||
537 | { | ||
538 | asm volatile ("li 0,0x5555; sc" : : : "r0", "r3"); | ||
539 | } | ||
540 | |||
541 | static void yield_shared_processor(void) | ||
542 | { | ||
543 | unsigned long tb; | ||
544 | |||
545 | HvCall_setEnabledInterrupts(HvCall_MaskIPI | | ||
546 | HvCall_MaskLpEvent | | ||
547 | HvCall_MaskLpProd | | ||
548 | HvCall_MaskTimeout); | ||
549 | |||
550 | tb = get_tb(); | ||
551 | /* Compute future tb value when yield should expire */ | ||
552 | HvCall_yieldProcessor(HvCall_YieldTimed, tb+tb_ticks_per_jiffy); | ||
553 | |||
554 | /* | ||
555 | * The decrementer stops during the yield. Force a fake decrementer | ||
556 | * here and let the timer_interrupt code sort out the actual time. | ||
557 | */ | ||
558 | get_lppaca()->int_dword.fields.decr_int = 1; | ||
559 | ppc64_runlatch_on(); | ||
560 | process_iSeries_events(); | ||
561 | } | ||
562 | |||
563 | static void iseries_shared_idle(void) | ||
564 | { | ||
565 | while (1) { | ||
566 | tick_nohz_idle_enter(); | ||
567 | rcu_idle_enter(); | ||
568 | while (!need_resched() && !hvlpevent_is_pending()) { | ||
569 | local_irq_disable(); | ||
570 | ppc64_runlatch_off(); | ||
571 | |||
572 | /* Recheck with irqs off */ | ||
573 | if (!need_resched() && !hvlpevent_is_pending()) | ||
574 | yield_shared_processor(); | ||
575 | |||
576 | HMT_medium(); | ||
577 | local_irq_enable(); | ||
578 | } | ||
579 | |||
580 | ppc64_runlatch_on(); | ||
581 | rcu_idle_exit(); | ||
582 | tick_nohz_idle_exit(); | ||
583 | |||
584 | if (hvlpevent_is_pending()) | ||
585 | process_iSeries_events(); | ||
586 | |||
587 | schedule_preempt_disabled(); | ||
588 | } | ||
589 | } | ||
590 | |||
591 | static void iseries_dedicated_idle(void) | ||
592 | { | ||
593 | set_thread_flag(TIF_POLLING_NRFLAG); | ||
594 | |||
595 | while (1) { | ||
596 | tick_nohz_idle_enter(); | ||
597 | rcu_idle_enter(); | ||
598 | if (!need_resched()) { | ||
599 | while (!need_resched()) { | ||
600 | ppc64_runlatch_off(); | ||
601 | HMT_low(); | ||
602 | |||
603 | if (hvlpevent_is_pending()) { | ||
604 | HMT_medium(); | ||
605 | ppc64_runlatch_on(); | ||
606 | process_iSeries_events(); | ||
607 | } | ||
608 | } | ||
609 | |||
610 | HMT_medium(); | ||
611 | } | ||
612 | |||
613 | ppc64_runlatch_on(); | ||
614 | rcu_idle_exit(); | ||
615 | tick_nohz_idle_exit(); | ||
616 | schedule_preempt_disabled(); | ||
617 | } | ||
618 | } | ||
619 | |||
620 | static void __iomem *iseries_ioremap(phys_addr_t address, unsigned long size, | ||
621 | unsigned long flags, void *caller) | ||
622 | { | ||
623 | return (void __iomem *)address; | ||
624 | } | ||
625 | |||
626 | static void iseries_iounmap(volatile void __iomem *token) | ||
627 | { | ||
628 | } | ||
629 | |||
630 | static int __init iseries_probe(void) | ||
631 | { | ||
632 | unsigned long root = of_get_flat_dt_root(); | ||
633 | if (!of_flat_dt_is_compatible(root, "IBM,iSeries")) | ||
634 | return 0; | ||
635 | |||
636 | hpte_init_iSeries(); | ||
637 | /* iSeries does not support 16M pages */ | ||
638 | cur_cpu_spec->mmu_features &= ~MMU_FTR_16M_PAGE; | ||
639 | |||
640 | return 1; | ||
641 | } | ||
642 | |||
643 | #ifdef CONFIG_KEXEC | ||
644 | static int iseries_kexec_prepare(struct kimage *image) | ||
645 | { | ||
646 | return -ENOSYS; | ||
647 | } | ||
648 | #endif | ||
649 | |||
650 | define_machine(iseries) { | ||
651 | .name = "iSeries", | ||
652 | .setup_arch = iSeries_setup_arch, | ||
653 | .show_cpuinfo = iSeries_show_cpuinfo, | ||
654 | .init_IRQ = iSeries_init_IRQ, | ||
655 | .get_irq = iSeries_get_irq, | ||
656 | .init_early = iSeries_init_early, | ||
657 | .pcibios_fixup = iSeries_pci_final_fixup, | ||
658 | .pcibios_fixup_resources= iSeries_pcibios_fixup_resources, | ||
659 | .restart = mf_reboot, | ||
660 | .power_off = mf_power_off, | ||
661 | .halt = mf_power_off, | ||
662 | .get_boot_time = iSeries_get_boot_time, | ||
663 | .set_rtc_time = iSeries_set_rtc_time, | ||
664 | .get_rtc_time = iSeries_get_rtc_time, | ||
665 | .calibrate_decr = generic_calibrate_decr, | ||
666 | .progress = iSeries_progress, | ||
667 | .probe = iseries_probe, | ||
668 | .ioremap = iseries_ioremap, | ||
669 | .iounmap = iseries_iounmap, | ||
670 | #ifdef CONFIG_KEXEC | ||
671 | .machine_kexec_prepare = iseries_kexec_prepare, | ||
672 | #endif | ||
673 | /* XXX Implement enable_pmcs for iSeries */ | ||
674 | }; | ||
675 | |||
676 | void * __init iSeries_early_setup(void) | ||
677 | { | ||
678 | unsigned long phys_mem_size; | ||
679 | |||
680 | /* Identify CPU type. This is done again by the common code later | ||
681 | * on but calling this function multiple times is fine. | ||
682 | */ | ||
683 | identify_cpu(0, mfspr(SPRN_PVR)); | ||
684 | initialise_paca(&boot_paca, 0); | ||
685 | |||
686 | powerpc_firmware_features |= FW_FEATURE_ISERIES; | ||
687 | powerpc_firmware_features |= FW_FEATURE_LPAR; | ||
688 | |||
689 | #ifdef CONFIG_SMP | ||
690 | /* On iSeries we know we can never have more than 64 cpus */ | ||
691 | nr_cpu_ids = max(nr_cpu_ids, 64); | ||
692 | #endif | ||
693 | |||
694 | iSeries_fixup_klimit(); | ||
695 | |||
696 | /* | ||
697 | * Initialize the table which translate Linux physical addresses to | ||
698 | * AS/400 absolute addresses | ||
699 | */ | ||
700 | phys_mem_size = build_iSeries_Memory_Map(); | ||
701 | |||
702 | iSeries_get_cmdline(); | ||
703 | |||
704 | return (void *) __pa(build_flat_dt(phys_mem_size)); | ||
705 | } | ||
706 | |||
707 | static void hvputc(char c) | ||
708 | { | ||
709 | if (c == '\n') | ||
710 | hvputc('\r'); | ||
711 | |||
712 | HvCall_writeLogBuffer(&c, 1); | ||
713 | } | ||
714 | |||
715 | void __init udbg_init_iseries(void) | ||
716 | { | ||
717 | udbg_putc = hvputc; | ||
718 | } | ||
diff --git a/arch/powerpc/platforms/iseries/setup.h b/arch/powerpc/platforms/iseries/setup.h deleted file mode 100644 index 729754bbb018..000000000000 --- a/arch/powerpc/platforms/iseries/setup.h +++ /dev/null | |||
@@ -1,27 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2000 Mike Corrigan <mikejc@us.ibm.com> | ||
3 | * Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu> | ||
4 | * | ||
5 | * Description: | ||
6 | * Architecture- / platform-specific boot-time initialization code for | ||
7 | * the IBM AS/400 LPAR. Adapted from original code by Grant Erickson and | ||
8 | * code by Gary Thomas, Cort Dougan <cort@cs.nmt.edu>, and Dan Malek | ||
9 | * <dan@netx4.com>. | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License | ||
13 | * as published by the Free Software Foundation; either version | ||
14 | * 2 of the License, or (at your option) any later version. | ||
15 | */ | ||
16 | |||
17 | #ifndef __ISERIES_SETUP_H__ | ||
18 | #define __ISERIES_SETUP_H__ | ||
19 | |||
20 | extern void *iSeries_early_setup(void); | ||
21 | extern unsigned long iSeries_get_boot_time(void); | ||
22 | extern int iSeries_set_rtc_time(struct rtc_time *tm); | ||
23 | extern void iSeries_get_rtc_time(struct rtc_time *tm); | ||
24 | |||
25 | extern void *build_flat_dt(unsigned long phys_mem_size); | ||
26 | |||
27 | #endif /* __ISERIES_SETUP_H__ */ | ||
diff --git a/arch/powerpc/platforms/iseries/smp.c b/arch/powerpc/platforms/iseries/smp.c deleted file mode 100644 index 02df49fb59f0..000000000000 --- a/arch/powerpc/platforms/iseries/smp.c +++ /dev/null | |||
@@ -1,88 +0,0 @@ | |||
1 | /* | ||
2 | * SMP support for iSeries machines. | ||
3 | * | ||
4 | * Dave Engebretsen, Peter Bergner, and | ||
5 | * Mike Corrigan {engebret|bergner|mikec}@us.ibm.com | ||
6 | * | ||
7 | * Plus various changes from other IBM teams... | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * as published by the Free Software Foundation; either version | ||
12 | * 2 of the License, or (at your option) any later version. | ||
13 | */ | ||
14 | |||
15 | #undef DEBUG | ||
16 | |||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/sched.h> | ||
19 | #include <linux/smp.h> | ||
20 | #include <linux/interrupt.h> | ||
21 | #include <linux/kernel_stat.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/spinlock.h> | ||
25 | #include <linux/cache.h> | ||
26 | #include <linux/err.h> | ||
27 | #include <linux/device.h> | ||
28 | #include <linux/cpu.h> | ||
29 | |||
30 | #include <asm/ptrace.h> | ||
31 | #include <linux/atomic.h> | ||
32 | #include <asm/irq.h> | ||
33 | #include <asm/page.h> | ||
34 | #include <asm/pgtable.h> | ||
35 | #include <asm/io.h> | ||
36 | #include <asm/smp.h> | ||
37 | #include <asm/paca.h> | ||
38 | #include <asm/iseries/hv_call.h> | ||
39 | #include <asm/time.h> | ||
40 | #include <asm/machdep.h> | ||
41 | #include <asm/cputable.h> | ||
42 | #include <asm/system.h> | ||
43 | |||
44 | static void smp_iSeries_cause_ipi(int cpu, unsigned long data) | ||
45 | { | ||
46 | HvCall_sendIPI(&(paca[cpu])); | ||
47 | } | ||
48 | |||
49 | static int smp_iSeries_probe(void) | ||
50 | { | ||
51 | return cpumask_weight(cpu_possible_mask); | ||
52 | } | ||
53 | |||
54 | static int smp_iSeries_kick_cpu(int nr) | ||
55 | { | ||
56 | BUG_ON((nr < 0) || (nr >= NR_CPUS)); | ||
57 | |||
58 | /* Verify that our partition has a processor nr */ | ||
59 | if (lppaca_of(nr).dyn_proc_status >= 2) | ||
60 | return -ENOENT; | ||
61 | |||
62 | /* The processor is currently spinning, waiting | ||
63 | * for the cpu_start field to become non-zero | ||
64 | * After we set cpu_start, the processor will | ||
65 | * continue on to secondary_start in iSeries_head.S | ||
66 | */ | ||
67 | paca[nr].cpu_start = 1; | ||
68 | |||
69 | return 0; | ||
70 | } | ||
71 | |||
72 | static void __devinit smp_iSeries_setup_cpu(int nr) | ||
73 | { | ||
74 | } | ||
75 | |||
76 | static struct smp_ops_t iSeries_smp_ops = { | ||
77 | .message_pass = NULL, /* Use smp_muxed_ipi_message_pass */ | ||
78 | .cause_ipi = smp_iSeries_cause_ipi, | ||
79 | .probe = smp_iSeries_probe, | ||
80 | .kick_cpu = smp_iSeries_kick_cpu, | ||
81 | .setup_cpu = smp_iSeries_setup_cpu, | ||
82 | }; | ||
83 | |||
84 | /* This is called very early. */ | ||
85 | void __init smp_init_iSeries(void) | ||
86 | { | ||
87 | smp_ops = &iSeries_smp_ops; | ||
88 | } | ||
diff --git a/arch/powerpc/platforms/iseries/spcomm_area.h b/arch/powerpc/platforms/iseries/spcomm_area.h deleted file mode 100644 index 598b7c14573a..000000000000 --- a/arch/powerpc/platforms/iseries/spcomm_area.h +++ /dev/null | |||
@@ -1,34 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001 Mike Corrigan IBM Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | |||
19 | #ifndef _ISERIES_SPCOMM_AREA_H | ||
20 | #define _ISERIES_SPCOMM_AREA_H | ||
21 | |||
22 | |||
23 | struct SpCommArea { | ||
24 | u32 xDesc; // Descriptor (only in new formats) 000-003 | ||
25 | u8 xFormat; // Format (only in new formats) 004-004 | ||
26 | u8 xRsvd1[11]; // Reserved 005-00F | ||
27 | u64 xRawTbAtIplStart; // Raw HW TB value when IPL is started 010-017 | ||
28 | u64 xRawTodAtIplStart; // Raw HW TOD value when IPL is started 018-01F | ||
29 | u64 xBcdTimeAtIplStart; // BCD time when IPL is started 020-027 | ||
30 | u64 xBcdTimeAtOsStart; // BCD time when OS passed control 028-02F | ||
31 | u8 xRsvd2[80]; // Reserved 030-07F | ||
32 | }; | ||
33 | |||
34 | #endif /* _ISERIES_SPCOMM_AREA_H */ | ||
diff --git a/arch/powerpc/platforms/iseries/vio.c b/arch/powerpc/platforms/iseries/vio.c deleted file mode 100644 index 04be62d368a6..000000000000 --- a/arch/powerpc/platforms/iseries/vio.c +++ /dev/null | |||
@@ -1,556 +0,0 @@ | |||
1 | /* | ||
2 | * Legacy iSeries specific vio initialisation | ||
3 | * that needs to be built in (not a module). | ||
4 | * | ||
5 | * © Copyright 2007 IBM Corporation | ||
6 | * Author: Stephen Rothwell | ||
7 | * Some parts collected from various other files | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License as | ||
11 | * published by the Free Software Foundation; either version 2 of the | ||
12 | * License, or (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software Foundation, | ||
21 | * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | */ | ||
23 | #include <linux/of.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <linux/completion.h> | ||
27 | #include <linux/proc_fs.h> | ||
28 | #include <linux/export.h> | ||
29 | |||
30 | #include <asm/firmware.h> | ||
31 | #include <asm/vio.h> | ||
32 | #include <asm/iseries/vio.h> | ||
33 | #include <asm/iseries/iommu.h> | ||
34 | #include <asm/iseries/hv_types.h> | ||
35 | #include <asm/iseries/hv_lp_event.h> | ||
36 | |||
37 | #define FIRST_VTY 0 | ||
38 | #define NUM_VTYS 1 | ||
39 | #define FIRST_VSCSI (FIRST_VTY + NUM_VTYS) | ||
40 | #define NUM_VSCSIS 1 | ||
41 | #define FIRST_VLAN (FIRST_VSCSI + NUM_VSCSIS) | ||
42 | #define NUM_VLANS HVMAXARCHITECTEDVIRTUALLANS | ||
43 | #define FIRST_VIODASD (FIRST_VLAN + NUM_VLANS) | ||
44 | #define NUM_VIODASDS HVMAXARCHITECTEDVIRTUALDISKS | ||
45 | #define FIRST_VIOCD (FIRST_VIODASD + NUM_VIODASDS) | ||
46 | #define NUM_VIOCDS HVMAXARCHITECTEDVIRTUALCDROMS | ||
47 | #define FIRST_VIOTAPE (FIRST_VIOCD + NUM_VIOCDS) | ||
48 | #define NUM_VIOTAPES HVMAXARCHITECTEDVIRTUALTAPES | ||
49 | |||
50 | struct vio_waitevent { | ||
51 | struct completion com; | ||
52 | int rc; | ||
53 | u16 sub_result; | ||
54 | }; | ||
55 | |||
56 | struct vio_resource { | ||
57 | char rsrcname[10]; | ||
58 | char type[4]; | ||
59 | char model[3]; | ||
60 | }; | ||
61 | |||
62 | static struct property *new_property(const char *name, int length, | ||
63 | const void *value) | ||
64 | { | ||
65 | struct property *np = kzalloc(sizeof(*np) + strlen(name) + 1 + length, | ||
66 | GFP_KERNEL); | ||
67 | |||
68 | if (!np) | ||
69 | return NULL; | ||
70 | np->name = (char *)(np + 1); | ||
71 | np->value = np->name + strlen(name) + 1; | ||
72 | strcpy(np->name, name); | ||
73 | memcpy(np->value, value, length); | ||
74 | np->length = length; | ||
75 | return np; | ||
76 | } | ||
77 | |||
78 | static void free_property(struct property *np) | ||
79 | { | ||
80 | kfree(np); | ||
81 | } | ||
82 | |||
83 | static struct device_node *new_node(const char *path, | ||
84 | struct device_node *parent) | ||
85 | { | ||
86 | struct device_node *np = kzalloc(sizeof(*np), GFP_KERNEL); | ||
87 | |||
88 | if (!np) | ||
89 | return NULL; | ||
90 | np->full_name = kstrdup(path, GFP_KERNEL); | ||
91 | if (!np->full_name) { | ||
92 | kfree(np); | ||
93 | return NULL; | ||
94 | } | ||
95 | of_node_set_flag(np, OF_DYNAMIC); | ||
96 | kref_init(&np->kref); | ||
97 | np->parent = of_node_get(parent); | ||
98 | return np; | ||
99 | } | ||
100 | |||
101 | static void free_node(struct device_node *np) | ||
102 | { | ||
103 | struct property *next; | ||
104 | struct property *prop; | ||
105 | |||
106 | next = np->properties; | ||
107 | while (next) { | ||
108 | prop = next; | ||
109 | next = prop->next; | ||
110 | free_property(prop); | ||
111 | } | ||
112 | of_node_put(np->parent); | ||
113 | kfree(np->full_name); | ||
114 | kfree(np); | ||
115 | } | ||
116 | |||
117 | static int add_string_property(struct device_node *np, const char *name, | ||
118 | const char *value) | ||
119 | { | ||
120 | struct property *nprop = new_property(name, strlen(value) + 1, value); | ||
121 | |||
122 | if (!nprop) | ||
123 | return 0; | ||
124 | prom_add_property(np, nprop); | ||
125 | return 1; | ||
126 | } | ||
127 | |||
128 | static int add_raw_property(struct device_node *np, const char *name, | ||
129 | int length, const void *value) | ||
130 | { | ||
131 | struct property *nprop = new_property(name, length, value); | ||
132 | |||
133 | if (!nprop) | ||
134 | return 0; | ||
135 | prom_add_property(np, nprop); | ||
136 | return 1; | ||
137 | } | ||
138 | |||
139 | static struct device_node *do_device_node(struct device_node *parent, | ||
140 | const char *name, u32 reg, u32 unit, const char *type, | ||
141 | const char *compat, struct vio_resource *res) | ||
142 | { | ||
143 | struct device_node *np; | ||
144 | char path[32]; | ||
145 | |||
146 | snprintf(path, sizeof(path), "/vdevice/%s@%08x", name, reg); | ||
147 | np = new_node(path, parent); | ||
148 | if (!np) | ||
149 | return NULL; | ||
150 | if (!add_string_property(np, "name", name) || | ||
151 | !add_string_property(np, "device_type", type) || | ||
152 | !add_string_property(np, "compatible", compat) || | ||
153 | !add_raw_property(np, "reg", sizeof(reg), ®) || | ||
154 | !add_raw_property(np, "linux,unit_address", | ||
155 | sizeof(unit), &unit)) { | ||
156 | goto node_free; | ||
157 | } | ||
158 | if (res) { | ||
159 | if (!add_raw_property(np, "linux,vio_rsrcname", | ||
160 | sizeof(res->rsrcname), res->rsrcname) || | ||
161 | !add_raw_property(np, "linux,vio_type", | ||
162 | sizeof(res->type), res->type) || | ||
163 | !add_raw_property(np, "linux,vio_model", | ||
164 | sizeof(res->model), res->model)) | ||
165 | goto node_free; | ||
166 | } | ||
167 | np->name = of_get_property(np, "name", NULL); | ||
168 | np->type = of_get_property(np, "device_type", NULL); | ||
169 | of_attach_node(np); | ||
170 | #ifdef CONFIG_PROC_DEVICETREE | ||
171 | if (parent->pde) { | ||
172 | struct proc_dir_entry *ent; | ||
173 | |||
174 | ent = proc_mkdir(strrchr(np->full_name, '/') + 1, parent->pde); | ||
175 | if (ent) | ||
176 | proc_device_tree_add_node(np, ent); | ||
177 | } | ||
178 | #endif | ||
179 | return np; | ||
180 | |||
181 | node_free: | ||
182 | free_node(np); | ||
183 | return NULL; | ||
184 | } | ||
185 | |||
186 | /* | ||
187 | * This is here so that we can dynamically add viodasd | ||
188 | * devices without exposing all the above infrastructure. | ||
189 | */ | ||
190 | struct vio_dev *vio_create_viodasd(u32 unit) | ||
191 | { | ||
192 | struct device_node *vio_root; | ||
193 | struct device_node *np; | ||
194 | struct vio_dev *vdev = NULL; | ||
195 | |||
196 | vio_root = of_find_node_by_path("/vdevice"); | ||
197 | if (!vio_root) | ||
198 | return NULL; | ||
199 | np = do_device_node(vio_root, "viodasd", FIRST_VIODASD + unit, unit, | ||
200 | "block", "IBM,iSeries-viodasd", NULL); | ||
201 | of_node_put(vio_root); | ||
202 | if (np) { | ||
203 | vdev = vio_register_device_node(np); | ||
204 | if (!vdev) | ||
205 | free_node(np); | ||
206 | } | ||
207 | return vdev; | ||
208 | } | ||
209 | EXPORT_SYMBOL_GPL(vio_create_viodasd); | ||
210 | |||
211 | static void __init handle_block_event(struct HvLpEvent *event) | ||
212 | { | ||
213 | struct vioblocklpevent *bevent = (struct vioblocklpevent *)event; | ||
214 | struct vio_waitevent *pwe; | ||
215 | |||
216 | if (event == NULL) | ||
217 | /* Notification that a partition went away! */ | ||
218 | return; | ||
219 | /* First, we should NEVER get an int here...only acks */ | ||
220 | if (hvlpevent_is_int(event)) { | ||
221 | printk(KERN_WARNING "handle_viod_request: " | ||
222 | "Yikes! got an int in viodasd event handler!\n"); | ||
223 | if (hvlpevent_need_ack(event)) { | ||
224 | event->xRc = HvLpEvent_Rc_InvalidSubtype; | ||
225 | HvCallEvent_ackLpEvent(event); | ||
226 | } | ||
227 | return; | ||
228 | } | ||
229 | |||
230 | switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) { | ||
231 | case vioblockopen: | ||
232 | /* | ||
233 | * Handle a response to an open request. We get all the | ||
234 | * disk information in the response, so update it. The | ||
235 | * correlation token contains a pointer to a waitevent | ||
236 | * structure that has a completion in it. update the | ||
237 | * return code in the waitevent structure and post the | ||
238 | * completion to wake up the guy who sent the request | ||
239 | */ | ||
240 | pwe = (struct vio_waitevent *)event->xCorrelationToken; | ||
241 | pwe->rc = event->xRc; | ||
242 | pwe->sub_result = bevent->sub_result; | ||
243 | complete(&pwe->com); | ||
244 | break; | ||
245 | case vioblockclose: | ||
246 | break; | ||
247 | default: | ||
248 | printk(KERN_WARNING "handle_viod_request: unexpected subtype!"); | ||
249 | if (hvlpevent_need_ack(event)) { | ||
250 | event->xRc = HvLpEvent_Rc_InvalidSubtype; | ||
251 | HvCallEvent_ackLpEvent(event); | ||
252 | } | ||
253 | } | ||
254 | } | ||
255 | |||
256 | static void __init probe_disk(struct device_node *vio_root, u32 unit) | ||
257 | { | ||
258 | HvLpEvent_Rc hvrc; | ||
259 | struct vio_waitevent we; | ||
260 | u16 flags = 0; | ||
261 | |||
262 | retry: | ||
263 | init_completion(&we.com); | ||
264 | |||
265 | /* Send the open event to OS/400 */ | ||
266 | hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, | ||
267 | HvLpEvent_Type_VirtualIo, | ||
268 | viomajorsubtype_blockio | vioblockopen, | ||
269 | HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, | ||
270 | viopath_sourceinst(viopath_hostLp), | ||
271 | viopath_targetinst(viopath_hostLp), | ||
272 | (u64)(unsigned long)&we, VIOVERSION << 16, | ||
273 | ((u64)unit << 48) | ((u64)flags<< 32), | ||
274 | 0, 0, 0); | ||
275 | if (hvrc != 0) { | ||
276 | printk(KERN_WARNING "probe_disk: bad rc on HV open %d\n", | ||
277 | (int)hvrc); | ||
278 | return; | ||
279 | } | ||
280 | |||
281 | wait_for_completion(&we.com); | ||
282 | |||
283 | if (we.rc != 0) { | ||
284 | if (flags != 0) | ||
285 | return; | ||
286 | /* try again with read only flag set */ | ||
287 | flags = vioblockflags_ro; | ||
288 | goto retry; | ||
289 | } | ||
290 | |||
291 | /* Send the close event to OS/400. We DON'T expect a response */ | ||
292 | hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, | ||
293 | HvLpEvent_Type_VirtualIo, | ||
294 | viomajorsubtype_blockio | vioblockclose, | ||
295 | HvLpEvent_AckInd_NoAck, HvLpEvent_AckType_ImmediateAck, | ||
296 | viopath_sourceinst(viopath_hostLp), | ||
297 | viopath_targetinst(viopath_hostLp), | ||
298 | 0, VIOVERSION << 16, | ||
299 | ((u64)unit << 48) | ((u64)flags << 32), | ||
300 | 0, 0, 0); | ||
301 | if (hvrc != 0) { | ||
302 | printk(KERN_WARNING "probe_disk: " | ||
303 | "bad rc sending event to OS/400 %d\n", (int)hvrc); | ||
304 | return; | ||
305 | } | ||
306 | |||
307 | do_device_node(vio_root, "viodasd", FIRST_VIODASD + unit, unit, | ||
308 | "block", "IBM,iSeries-viodasd", NULL); | ||
309 | } | ||
310 | |||
311 | static void __init get_viodasd_info(struct device_node *vio_root) | ||
312 | { | ||
313 | int rc; | ||
314 | u32 unit; | ||
315 | |||
316 | rc = viopath_open(viopath_hostLp, viomajorsubtype_blockio, 2); | ||
317 | if (rc) { | ||
318 | printk(KERN_WARNING "get_viodasd_info: " | ||
319 | "error opening path to host partition %d\n", | ||
320 | viopath_hostLp); | ||
321 | return; | ||
322 | } | ||
323 | |||
324 | /* Initialize our request handler */ | ||
325 | vio_setHandler(viomajorsubtype_blockio, handle_block_event); | ||
326 | |||
327 | for (unit = 0; unit < HVMAXARCHITECTEDVIRTUALDISKS; unit++) | ||
328 | probe_disk(vio_root, unit); | ||
329 | |||
330 | vio_clearHandler(viomajorsubtype_blockio); | ||
331 | viopath_close(viopath_hostLp, viomajorsubtype_blockio, 2); | ||
332 | } | ||
333 | |||
334 | static void __init handle_cd_event(struct HvLpEvent *event) | ||
335 | { | ||
336 | struct viocdlpevent *bevent; | ||
337 | struct vio_waitevent *pwe; | ||
338 | |||
339 | if (!event) | ||
340 | /* Notification that a partition went away! */ | ||
341 | return; | ||
342 | |||
343 | /* First, we should NEVER get an int here...only acks */ | ||
344 | if (hvlpevent_is_int(event)) { | ||
345 | printk(KERN_WARNING "handle_cd_event: got an unexpected int\n"); | ||
346 | if (hvlpevent_need_ack(event)) { | ||
347 | event->xRc = HvLpEvent_Rc_InvalidSubtype; | ||
348 | HvCallEvent_ackLpEvent(event); | ||
349 | } | ||
350 | return; | ||
351 | } | ||
352 | |||
353 | bevent = (struct viocdlpevent *)event; | ||
354 | |||
355 | switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) { | ||
356 | case viocdgetinfo: | ||
357 | pwe = (struct vio_waitevent *)event->xCorrelationToken; | ||
358 | pwe->rc = event->xRc; | ||
359 | pwe->sub_result = bevent->sub_result; | ||
360 | complete(&pwe->com); | ||
361 | break; | ||
362 | |||
363 | default: | ||
364 | printk(KERN_WARNING "handle_cd_event: " | ||
365 | "message with unexpected subtype %0x04X!\n", | ||
366 | event->xSubtype & VIOMINOR_SUBTYPE_MASK); | ||
367 | if (hvlpevent_need_ack(event)) { | ||
368 | event->xRc = HvLpEvent_Rc_InvalidSubtype; | ||
369 | HvCallEvent_ackLpEvent(event); | ||
370 | } | ||
371 | } | ||
372 | } | ||
373 | |||
374 | static void __init get_viocd_info(struct device_node *vio_root) | ||
375 | { | ||
376 | HvLpEvent_Rc hvrc; | ||
377 | u32 unit; | ||
378 | struct vio_waitevent we; | ||
379 | struct vio_resource *unitinfo; | ||
380 | dma_addr_t unitinfo_dmaaddr; | ||
381 | int ret; | ||
382 | |||
383 | ret = viopath_open(viopath_hostLp, viomajorsubtype_cdio, 2); | ||
384 | if (ret) { | ||
385 | printk(KERN_WARNING | ||
386 | "get_viocd_info: error opening path to host partition %d\n", | ||
387 | viopath_hostLp); | ||
388 | return; | ||
389 | } | ||
390 | |||
391 | /* Initialize our request handler */ | ||
392 | vio_setHandler(viomajorsubtype_cdio, handle_cd_event); | ||
393 | |||
394 | unitinfo = iseries_hv_alloc( | ||
395 | sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS, | ||
396 | &unitinfo_dmaaddr, GFP_ATOMIC); | ||
397 | if (!unitinfo) { | ||
398 | printk(KERN_WARNING | ||
399 | "get_viocd_info: error allocating unitinfo\n"); | ||
400 | goto clear_handler; | ||
401 | } | ||
402 | |||
403 | memset(unitinfo, 0, sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS); | ||
404 | |||
405 | init_completion(&we.com); | ||
406 | |||
407 | hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, | ||
408 | HvLpEvent_Type_VirtualIo, | ||
409 | viomajorsubtype_cdio | viocdgetinfo, | ||
410 | HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, | ||
411 | viopath_sourceinst(viopath_hostLp), | ||
412 | viopath_targetinst(viopath_hostLp), | ||
413 | (u64)&we, VIOVERSION << 16, unitinfo_dmaaddr, 0, | ||
414 | sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS, 0); | ||
415 | if (hvrc != HvLpEvent_Rc_Good) { | ||
416 | printk(KERN_WARNING | ||
417 | "get_viocd_info: cdrom error sending event. rc %d\n", | ||
418 | (int)hvrc); | ||
419 | goto hv_free; | ||
420 | } | ||
421 | |||
422 | wait_for_completion(&we.com); | ||
423 | |||
424 | if (we.rc) { | ||
425 | printk(KERN_WARNING "get_viocd_info: bad rc %d:0x%04X\n", | ||
426 | we.rc, we.sub_result); | ||
427 | goto hv_free; | ||
428 | } | ||
429 | |||
430 | for (unit = 0; (unit < HVMAXARCHITECTEDVIRTUALCDROMS) && | ||
431 | unitinfo[unit].rsrcname[0]; unit++) { | ||
432 | if (!do_device_node(vio_root, "viocd", FIRST_VIOCD + unit, unit, | ||
433 | "block", "IBM,iSeries-viocd", &unitinfo[unit])) | ||
434 | break; | ||
435 | } | ||
436 | |||
437 | hv_free: | ||
438 | iseries_hv_free(sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALCDROMS, | ||
439 | unitinfo, unitinfo_dmaaddr); | ||
440 | clear_handler: | ||
441 | vio_clearHandler(viomajorsubtype_cdio); | ||
442 | viopath_close(viopath_hostLp, viomajorsubtype_cdio, 2); | ||
443 | } | ||
444 | |||
445 | /* Handle interrupt events for tape */ | ||
446 | static void __init handle_tape_event(struct HvLpEvent *event) | ||
447 | { | ||
448 | struct vio_waitevent *we; | ||
449 | struct viotapelpevent *tevent = (struct viotapelpevent *)event; | ||
450 | |||
451 | if (event == NULL) | ||
452 | /* Notification that a partition went away! */ | ||
453 | return; | ||
454 | |||
455 | we = (struct vio_waitevent *)event->xCorrelationToken; | ||
456 | switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) { | ||
457 | case viotapegetinfo: | ||
458 | we->rc = tevent->sub_type_result; | ||
459 | complete(&we->com); | ||
460 | break; | ||
461 | default: | ||
462 | printk(KERN_WARNING "handle_tape_event: weird ack\n"); | ||
463 | } | ||
464 | } | ||
465 | |||
466 | static void __init get_viotape_info(struct device_node *vio_root) | ||
467 | { | ||
468 | HvLpEvent_Rc hvrc; | ||
469 | u32 unit; | ||
470 | struct vio_resource *unitinfo; | ||
471 | dma_addr_t unitinfo_dmaaddr; | ||
472 | size_t len = sizeof(*unitinfo) * HVMAXARCHITECTEDVIRTUALTAPES; | ||
473 | struct vio_waitevent we; | ||
474 | int ret; | ||
475 | |||
476 | init_completion(&we.com); | ||
477 | |||
478 | ret = viopath_open(viopath_hostLp, viomajorsubtype_tape, 2); | ||
479 | if (ret) { | ||
480 | printk(KERN_WARNING "get_viotape_info: " | ||
481 | "error on viopath_open to hostlp %d\n", ret); | ||
482 | return; | ||
483 | } | ||
484 | |||
485 | vio_setHandler(viomajorsubtype_tape, handle_tape_event); | ||
486 | |||
487 | unitinfo = iseries_hv_alloc(len, &unitinfo_dmaaddr, GFP_ATOMIC); | ||
488 | if (!unitinfo) | ||
489 | goto clear_handler; | ||
490 | |||
491 | memset(unitinfo, 0, len); | ||
492 | |||
493 | hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, | ||
494 | HvLpEvent_Type_VirtualIo, | ||
495 | viomajorsubtype_tape | viotapegetinfo, | ||
496 | HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, | ||
497 | viopath_sourceinst(viopath_hostLp), | ||
498 | viopath_targetinst(viopath_hostLp), | ||
499 | (u64)(unsigned long)&we, VIOVERSION << 16, | ||
500 | unitinfo_dmaaddr, len, 0, 0); | ||
501 | if (hvrc != HvLpEvent_Rc_Good) { | ||
502 | printk(KERN_WARNING "get_viotape_info: hv error on op %d\n", | ||
503 | (int)hvrc); | ||
504 | goto hv_free; | ||
505 | } | ||
506 | |||
507 | wait_for_completion(&we.com); | ||
508 | |||
509 | for (unit = 0; (unit < HVMAXARCHITECTEDVIRTUALTAPES) && | ||
510 | unitinfo[unit].rsrcname[0]; unit++) { | ||
511 | if (!do_device_node(vio_root, "viotape", FIRST_VIOTAPE + unit, | ||
512 | unit, "byte", "IBM,iSeries-viotape", | ||
513 | &unitinfo[unit])) | ||
514 | break; | ||
515 | } | ||
516 | |||
517 | hv_free: | ||
518 | iseries_hv_free(len, unitinfo, unitinfo_dmaaddr); | ||
519 | clear_handler: | ||
520 | vio_clearHandler(viomajorsubtype_tape); | ||
521 | viopath_close(viopath_hostLp, viomajorsubtype_tape, 2); | ||
522 | } | ||
523 | |||
524 | static int __init iseries_vio_init(void) | ||
525 | { | ||
526 | struct device_node *vio_root; | ||
527 | int ret = -ENODEV; | ||
528 | |||
529 | if (!firmware_has_feature(FW_FEATURE_ISERIES)) | ||
530 | goto out; | ||
531 | |||
532 | iommu_vio_init(); | ||
533 | |||
534 | vio_root = of_find_node_by_path("/vdevice"); | ||
535 | if (!vio_root) | ||
536 | goto out; | ||
537 | |||
538 | if (viopath_hostLp == HvLpIndexInvalid) { | ||
539 | vio_set_hostlp(); | ||
540 | /* If we don't have a host, bail out */ | ||
541 | if (viopath_hostLp == HvLpIndexInvalid) | ||
542 | goto put_node; | ||
543 | } | ||
544 | |||
545 | get_viodasd_info(vio_root); | ||
546 | get_viocd_info(vio_root); | ||
547 | get_viotape_info(vio_root); | ||
548 | |||
549 | ret = 0; | ||
550 | |||
551 | put_node: | ||
552 | of_node_put(vio_root); | ||
553 | out: | ||
554 | return ret; | ||
555 | } | ||
556 | arch_initcall(iseries_vio_init); | ||
diff --git a/arch/powerpc/platforms/iseries/viopath.c b/arch/powerpc/platforms/iseries/viopath.c deleted file mode 100644 index 40dad0840eb3..000000000000 --- a/arch/powerpc/platforms/iseries/viopath.c +++ /dev/null | |||
@@ -1,677 +0,0 @@ | |||
1 | /* -*- linux-c -*- | ||
2 | * | ||
3 | * iSeries Virtual I/O Message Path code | ||
4 | * | ||
5 | * Authors: Dave Boutcher <boutcher@us.ibm.com> | ||
6 | * Ryan Arnold <ryanarn@us.ibm.com> | ||
7 | * Colin Devilbiss <devilbis@us.ibm.com> | ||
8 | * | ||
9 | * (C) Copyright 2000-2005 IBM Corporation | ||
10 | * | ||
11 | * This code is used by the iSeries virtual disk, cd, | ||
12 | * tape, and console to communicate with OS/400 in another | ||
13 | * partition. | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or | ||
16 | * modify it under the terms of the GNU General Public License as | ||
17 | * published by the Free Software Foundation; either version 2 of the | ||
18 | * License, or (at your option) anyu later version. | ||
19 | * | ||
20 | * This program is distributed in the hope that it will be useful, but | ||
21 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
23 | * General Public License for more details. | ||
24 | * | ||
25 | * You should have received a copy of the GNU General Public License | ||
26 | * along with this program; if not, write to the Free Software Foundation, | ||
27 | * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
28 | * | ||
29 | */ | ||
30 | #include <linux/export.h> | ||
31 | #include <linux/kernel.h> | ||
32 | #include <linux/slab.h> | ||
33 | #include <linux/errno.h> | ||
34 | #include <linux/vmalloc.h> | ||
35 | #include <linux/string.h> | ||
36 | #include <linux/proc_fs.h> | ||
37 | #include <linux/dma-mapping.h> | ||
38 | #include <linux/wait.h> | ||
39 | #include <linux/seq_file.h> | ||
40 | #include <linux/interrupt.h> | ||
41 | #include <linux/completion.h> | ||
42 | |||
43 | #include <asm/system.h> | ||
44 | #include <asm/uaccess.h> | ||
45 | #include <asm/prom.h> | ||
46 | #include <asm/firmware.h> | ||
47 | #include <asm/iseries/hv_types.h> | ||
48 | #include <asm/iseries/hv_lp_event.h> | ||
49 | #include <asm/iseries/hv_lp_config.h> | ||
50 | #include <asm/iseries/mf.h> | ||
51 | #include <asm/iseries/vio.h> | ||
52 | |||
53 | /* Status of the path to each other partition in the system. | ||
54 | * This is overkill, since we will only ever establish connections | ||
55 | * to our hosting partition and the primary partition on the system. | ||
56 | * But this allows for other support in the future. | ||
57 | */ | ||
58 | static struct viopathStatus { | ||
59 | int isOpen; /* Did we open the path? */ | ||
60 | int isActive; /* Do we have a mon msg outstanding */ | ||
61 | int users[VIO_MAX_SUBTYPES]; | ||
62 | HvLpInstanceId mSourceInst; | ||
63 | HvLpInstanceId mTargetInst; | ||
64 | int numberAllocated; | ||
65 | } viopathStatus[HVMAXARCHITECTEDLPS]; | ||
66 | |||
67 | static DEFINE_SPINLOCK(statuslock); | ||
68 | |||
69 | /* | ||
70 | * For each kind of event we allocate a buffer that is | ||
71 | * guaranteed not to cross a page boundary | ||
72 | */ | ||
73 | static unsigned char event_buffer[VIO_MAX_SUBTYPES * 256] | ||
74 | __attribute__((__aligned__(4096))); | ||
75 | static atomic_t event_buffer_available[VIO_MAX_SUBTYPES]; | ||
76 | static int event_buffer_initialised; | ||
77 | |||
78 | static void handleMonitorEvent(struct HvLpEvent *event); | ||
79 | |||
80 | /* | ||
81 | * We use this structure to handle asynchronous responses. The caller | ||
82 | * blocks on the semaphore and the handler posts the semaphore. However, | ||
83 | * if system_state is not SYSTEM_RUNNING, then wait_atomic is used ... | ||
84 | */ | ||
85 | struct alloc_parms { | ||
86 | struct completion done; | ||
87 | int number; | ||
88 | atomic_t wait_atomic; | ||
89 | int used_wait_atomic; | ||
90 | }; | ||
91 | |||
92 | /* Put a sequence number in each mon msg. The value is not | ||
93 | * important. Start at something other than 0 just for | ||
94 | * readability. wrapping this is ok. | ||
95 | */ | ||
96 | static u8 viomonseq = 22; | ||
97 | |||
98 | /* Our hosting logical partition. We get this at startup | ||
99 | * time, and different modules access this variable directly. | ||
100 | */ | ||
101 | HvLpIndex viopath_hostLp = HvLpIndexInvalid; | ||
102 | EXPORT_SYMBOL(viopath_hostLp); | ||
103 | HvLpIndex viopath_ourLp = HvLpIndexInvalid; | ||
104 | EXPORT_SYMBOL(viopath_ourLp); | ||
105 | |||
106 | /* For each kind of incoming event we set a pointer to a | ||
107 | * routine to call. | ||
108 | */ | ||
109 | static vio_event_handler_t *vio_handler[VIO_MAX_SUBTYPES]; | ||
110 | |||
111 | #define VIOPATH_KERN_WARN KERN_WARNING "viopath: " | ||
112 | #define VIOPATH_KERN_INFO KERN_INFO "viopath: " | ||
113 | |||
114 | static int proc_viopath_show(struct seq_file *m, void *v) | ||
115 | { | ||
116 | char *buf; | ||
117 | u16 vlanMap; | ||
118 | dma_addr_t handle; | ||
119 | HvLpEvent_Rc hvrc; | ||
120 | DECLARE_COMPLETION_ONSTACK(done); | ||
121 | struct device_node *node; | ||
122 | const char *sysid; | ||
123 | |||
124 | buf = kzalloc(HW_PAGE_SIZE, GFP_KERNEL); | ||
125 | if (!buf) | ||
126 | return 0; | ||
127 | |||
128 | handle = iseries_hv_map(buf, HW_PAGE_SIZE, DMA_FROM_DEVICE); | ||
129 | |||
130 | hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, | ||
131 | HvLpEvent_Type_VirtualIo, | ||
132 | viomajorsubtype_config | vioconfigget, | ||
133 | HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, | ||
134 | viopath_sourceinst(viopath_hostLp), | ||
135 | viopath_targetinst(viopath_hostLp), | ||
136 | (u64)(unsigned long)&done, VIOVERSION << 16, | ||
137 | ((u64)handle) << 32, HW_PAGE_SIZE, 0, 0); | ||
138 | |||
139 | if (hvrc != HvLpEvent_Rc_Good) | ||
140 | printk(VIOPATH_KERN_WARN "hv error on op %d\n", (int)hvrc); | ||
141 | |||
142 | wait_for_completion(&done); | ||
143 | |||
144 | vlanMap = HvLpConfig_getVirtualLanIndexMap(); | ||
145 | |||
146 | buf[HW_PAGE_SIZE-1] = '\0'; | ||
147 | seq_printf(m, "%s", buf); | ||
148 | |||
149 | iseries_hv_unmap(handle, HW_PAGE_SIZE, DMA_FROM_DEVICE); | ||
150 | kfree(buf); | ||
151 | |||
152 | seq_printf(m, "AVAILABLE_VETH=%x\n", vlanMap); | ||
153 | |||
154 | node = of_find_node_by_path("/"); | ||
155 | sysid = NULL; | ||
156 | if (node != NULL) | ||
157 | sysid = of_get_property(node, "system-id", NULL); | ||
158 | |||
159 | if (sysid == NULL) | ||
160 | seq_printf(m, "SRLNBR=<UNKNOWN>\n"); | ||
161 | else | ||
162 | /* Skip "IBM," on front of serial number, see dt.c */ | ||
163 | seq_printf(m, "SRLNBR=%s\n", sysid + 4); | ||
164 | |||
165 | of_node_put(node); | ||
166 | |||
167 | return 0; | ||
168 | } | ||
169 | |||
170 | static int proc_viopath_open(struct inode *inode, struct file *file) | ||
171 | { | ||
172 | return single_open(file, proc_viopath_show, NULL); | ||
173 | } | ||
174 | |||
175 | static const struct file_operations proc_viopath_operations = { | ||
176 | .open = proc_viopath_open, | ||
177 | .read = seq_read, | ||
178 | .llseek = seq_lseek, | ||
179 | .release = single_release, | ||
180 | }; | ||
181 | |||
182 | static int __init vio_proc_init(void) | ||
183 | { | ||
184 | if (!firmware_has_feature(FW_FEATURE_ISERIES)) | ||
185 | return 0; | ||
186 | |||
187 | proc_create("iSeries/config", 0, NULL, &proc_viopath_operations); | ||
188 | return 0; | ||
189 | } | ||
190 | __initcall(vio_proc_init); | ||
191 | |||
192 | /* See if a given LP is active. Allow for invalid lps to be passed in | ||
193 | * and just return invalid | ||
194 | */ | ||
195 | int viopath_isactive(HvLpIndex lp) | ||
196 | { | ||
197 | if (lp == HvLpIndexInvalid) | ||
198 | return 0; | ||
199 | if (lp < HVMAXARCHITECTEDLPS) | ||
200 | return viopathStatus[lp].isActive; | ||
201 | else | ||
202 | return 0; | ||
203 | } | ||
204 | EXPORT_SYMBOL(viopath_isactive); | ||
205 | |||
206 | /* | ||
207 | * We cache the source and target instance ids for each | ||
208 | * partition. | ||
209 | */ | ||
210 | HvLpInstanceId viopath_sourceinst(HvLpIndex lp) | ||
211 | { | ||
212 | return viopathStatus[lp].mSourceInst; | ||
213 | } | ||
214 | EXPORT_SYMBOL(viopath_sourceinst); | ||
215 | |||
216 | HvLpInstanceId viopath_targetinst(HvLpIndex lp) | ||
217 | { | ||
218 | return viopathStatus[lp].mTargetInst; | ||
219 | } | ||
220 | EXPORT_SYMBOL(viopath_targetinst); | ||
221 | |||
222 | /* | ||
223 | * Send a monitor message. This is a message with the acknowledge | ||
224 | * bit on that the other side will NOT explicitly acknowledge. When | ||
225 | * the other side goes down, the hypervisor will acknowledge any | ||
226 | * outstanding messages....so we will know when the other side dies. | ||
227 | */ | ||
228 | static void sendMonMsg(HvLpIndex remoteLp) | ||
229 | { | ||
230 | HvLpEvent_Rc hvrc; | ||
231 | |||
232 | viopathStatus[remoteLp].mSourceInst = | ||
233 | HvCallEvent_getSourceLpInstanceId(remoteLp, | ||
234 | HvLpEvent_Type_VirtualIo); | ||
235 | viopathStatus[remoteLp].mTargetInst = | ||
236 | HvCallEvent_getTargetLpInstanceId(remoteLp, | ||
237 | HvLpEvent_Type_VirtualIo); | ||
238 | |||
239 | /* | ||
240 | * Deliberately ignore the return code here. if we call this | ||
241 | * more than once, we don't care. | ||
242 | */ | ||
243 | vio_setHandler(viomajorsubtype_monitor, handleMonitorEvent); | ||
244 | |||
245 | hvrc = HvCallEvent_signalLpEventFast(remoteLp, HvLpEvent_Type_VirtualIo, | ||
246 | viomajorsubtype_monitor, HvLpEvent_AckInd_DoAck, | ||
247 | HvLpEvent_AckType_DeferredAck, | ||
248 | viopathStatus[remoteLp].mSourceInst, | ||
249 | viopathStatus[remoteLp].mTargetInst, | ||
250 | viomonseq++, 0, 0, 0, 0, 0); | ||
251 | |||
252 | if (hvrc == HvLpEvent_Rc_Good) | ||
253 | viopathStatus[remoteLp].isActive = 1; | ||
254 | else { | ||
255 | printk(VIOPATH_KERN_WARN "could not connect to partition %d\n", | ||
256 | remoteLp); | ||
257 | viopathStatus[remoteLp].isActive = 0; | ||
258 | } | ||
259 | } | ||
260 | |||
261 | static void handleMonitorEvent(struct HvLpEvent *event) | ||
262 | { | ||
263 | HvLpIndex remoteLp; | ||
264 | int i; | ||
265 | |||
266 | /* | ||
267 | * This handler is _also_ called as part of the loop | ||
268 | * at the end of this routine, so it must be able to | ||
269 | * ignore NULL events... | ||
270 | */ | ||
271 | if (!event) | ||
272 | return; | ||
273 | |||
274 | /* | ||
275 | * First see if this is just a normal monitor message from the | ||
276 | * other partition | ||
277 | */ | ||
278 | if (hvlpevent_is_int(event)) { | ||
279 | remoteLp = event->xSourceLp; | ||
280 | if (!viopathStatus[remoteLp].isActive) | ||
281 | sendMonMsg(remoteLp); | ||
282 | return; | ||
283 | } | ||
284 | |||
285 | /* | ||
286 | * This path is for an acknowledgement; the other partition | ||
287 | * died | ||
288 | */ | ||
289 | remoteLp = event->xTargetLp; | ||
290 | if ((event->xSourceInstanceId != viopathStatus[remoteLp].mSourceInst) || | ||
291 | (event->xTargetInstanceId != viopathStatus[remoteLp].mTargetInst)) { | ||
292 | printk(VIOPATH_KERN_WARN "ignoring ack....mismatched instances\n"); | ||
293 | return; | ||
294 | } | ||
295 | |||
296 | printk(VIOPATH_KERN_WARN "partition %d ended\n", remoteLp); | ||
297 | |||
298 | viopathStatus[remoteLp].isActive = 0; | ||
299 | |||
300 | /* | ||
301 | * For each active handler, pass them a NULL | ||
302 | * message to indicate that the other partition | ||
303 | * died | ||
304 | */ | ||
305 | for (i = 0; i < VIO_MAX_SUBTYPES; i++) { | ||
306 | if (vio_handler[i] != NULL) | ||
307 | (*vio_handler[i])(NULL); | ||
308 | } | ||
309 | } | ||
310 | |||
311 | int vio_setHandler(int subtype, vio_event_handler_t *beh) | ||
312 | { | ||
313 | subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT; | ||
314 | if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES)) | ||
315 | return -EINVAL; | ||
316 | if (vio_handler[subtype] != NULL) | ||
317 | return -EBUSY; | ||
318 | vio_handler[subtype] = beh; | ||
319 | return 0; | ||
320 | } | ||
321 | EXPORT_SYMBOL(vio_setHandler); | ||
322 | |||
323 | int vio_clearHandler(int subtype) | ||
324 | { | ||
325 | subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT; | ||
326 | if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES)) | ||
327 | return -EINVAL; | ||
328 | if (vio_handler[subtype] == NULL) | ||
329 | return -EAGAIN; | ||
330 | vio_handler[subtype] = NULL; | ||
331 | return 0; | ||
332 | } | ||
333 | EXPORT_SYMBOL(vio_clearHandler); | ||
334 | |||
335 | static void handleConfig(struct HvLpEvent *event) | ||
336 | { | ||
337 | if (!event) | ||
338 | return; | ||
339 | if (hvlpevent_is_int(event)) { | ||
340 | printk(VIOPATH_KERN_WARN | ||
341 | "unexpected config request from partition %d", | ||
342 | event->xSourceLp); | ||
343 | |||
344 | if (hvlpevent_need_ack(event)) { | ||
345 | event->xRc = HvLpEvent_Rc_InvalidSubtype; | ||
346 | HvCallEvent_ackLpEvent(event); | ||
347 | } | ||
348 | return; | ||
349 | } | ||
350 | |||
351 | complete((struct completion *)event->xCorrelationToken); | ||
352 | } | ||
353 | |||
354 | /* | ||
355 | * Initialization of the hosting partition | ||
356 | */ | ||
357 | void vio_set_hostlp(void) | ||
358 | { | ||
359 | /* | ||
360 | * If this has already been set then we DON'T want to either change | ||
361 | * it or re-register the proc file system | ||
362 | */ | ||
363 | if (viopath_hostLp != HvLpIndexInvalid) | ||
364 | return; | ||
365 | |||
366 | /* | ||
367 | * Figure out our hosting partition. This isn't allowed to change | ||
368 | * while we're active | ||
369 | */ | ||
370 | viopath_ourLp = HvLpConfig_getLpIndex(); | ||
371 | viopath_hostLp = HvLpConfig_getHostingLpIndex(viopath_ourLp); | ||
372 | |||
373 | if (viopath_hostLp != HvLpIndexInvalid) | ||
374 | vio_setHandler(viomajorsubtype_config, handleConfig); | ||
375 | } | ||
376 | EXPORT_SYMBOL(vio_set_hostlp); | ||
377 | |||
378 | static void vio_handleEvent(struct HvLpEvent *event) | ||
379 | { | ||
380 | HvLpIndex remoteLp; | ||
381 | int subtype = (event->xSubtype & VIOMAJOR_SUBTYPE_MASK) | ||
382 | >> VIOMAJOR_SUBTYPE_SHIFT; | ||
383 | |||
384 | if (hvlpevent_is_int(event)) { | ||
385 | remoteLp = event->xSourceLp; | ||
386 | /* | ||
387 | * The isActive is checked because if the hosting partition | ||
388 | * went down and came back up it would not be active but it | ||
389 | * would have different source and target instances, in which | ||
390 | * case we'd want to reset them. This case really protects | ||
391 | * against an unauthorized active partition sending interrupts | ||
392 | * or acks to this linux partition. | ||
393 | */ | ||
394 | if (viopathStatus[remoteLp].isActive | ||
395 | && (event->xSourceInstanceId != | ||
396 | viopathStatus[remoteLp].mTargetInst)) { | ||
397 | printk(VIOPATH_KERN_WARN | ||
398 | "message from invalid partition. " | ||
399 | "int msg rcvd, source inst (%d) doesn't match (%d)\n", | ||
400 | viopathStatus[remoteLp].mTargetInst, | ||
401 | event->xSourceInstanceId); | ||
402 | return; | ||
403 | } | ||
404 | |||
405 | if (viopathStatus[remoteLp].isActive | ||
406 | && (event->xTargetInstanceId != | ||
407 | viopathStatus[remoteLp].mSourceInst)) { | ||
408 | printk(VIOPATH_KERN_WARN | ||
409 | "message from invalid partition. " | ||
410 | "int msg rcvd, target inst (%d) doesn't match (%d)\n", | ||
411 | viopathStatus[remoteLp].mSourceInst, | ||
412 | event->xTargetInstanceId); | ||
413 | return; | ||
414 | } | ||
415 | } else { | ||
416 | remoteLp = event->xTargetLp; | ||
417 | if (event->xSourceInstanceId != | ||
418 | viopathStatus[remoteLp].mSourceInst) { | ||
419 | printk(VIOPATH_KERN_WARN | ||
420 | "message from invalid partition. " | ||
421 | "ack msg rcvd, source inst (%d) doesn't match (%d)\n", | ||
422 | viopathStatus[remoteLp].mSourceInst, | ||
423 | event->xSourceInstanceId); | ||
424 | return; | ||
425 | } | ||
426 | |||
427 | if (event->xTargetInstanceId != | ||
428 | viopathStatus[remoteLp].mTargetInst) { | ||
429 | printk(VIOPATH_KERN_WARN | ||
430 | "message from invalid partition. " | ||
431 | "viopath: ack msg rcvd, target inst (%d) doesn't match (%d)\n", | ||
432 | viopathStatus[remoteLp].mTargetInst, | ||
433 | event->xTargetInstanceId); | ||
434 | return; | ||
435 | } | ||
436 | } | ||
437 | |||
438 | if (vio_handler[subtype] == NULL) { | ||
439 | printk(VIOPATH_KERN_WARN | ||
440 | "unexpected virtual io event subtype %d from partition %d\n", | ||
441 | event->xSubtype, remoteLp); | ||
442 | /* No handler. Ack if necessary */ | ||
443 | if (hvlpevent_is_int(event) && hvlpevent_need_ack(event)) { | ||
444 | event->xRc = HvLpEvent_Rc_InvalidSubtype; | ||
445 | HvCallEvent_ackLpEvent(event); | ||
446 | } | ||
447 | return; | ||
448 | } | ||
449 | |||
450 | /* This innocuous little line is where all the real work happens */ | ||
451 | (*vio_handler[subtype])(event); | ||
452 | } | ||
453 | |||
454 | static void viopath_donealloc(void *parm, int number) | ||
455 | { | ||
456 | struct alloc_parms *parmsp = parm; | ||
457 | |||
458 | parmsp->number = number; | ||
459 | if (parmsp->used_wait_atomic) | ||
460 | atomic_set(&parmsp->wait_atomic, 0); | ||
461 | else | ||
462 | complete(&parmsp->done); | ||
463 | } | ||
464 | |||
465 | static int allocateEvents(HvLpIndex remoteLp, int numEvents) | ||
466 | { | ||
467 | struct alloc_parms parms; | ||
468 | |||
469 | if (system_state != SYSTEM_RUNNING) { | ||
470 | parms.used_wait_atomic = 1; | ||
471 | atomic_set(&parms.wait_atomic, 1); | ||
472 | } else { | ||
473 | parms.used_wait_atomic = 0; | ||
474 | init_completion(&parms.done); | ||
475 | } | ||
476 | mf_allocate_lp_events(remoteLp, HvLpEvent_Type_VirtualIo, 250, /* It would be nice to put a real number here! */ | ||
477 | numEvents, &viopath_donealloc, &parms); | ||
478 | if (system_state != SYSTEM_RUNNING) { | ||
479 | while (atomic_read(&parms.wait_atomic)) | ||
480 | mb(); | ||
481 | } else | ||
482 | wait_for_completion(&parms.done); | ||
483 | return parms.number; | ||
484 | } | ||
485 | |||
486 | int viopath_open(HvLpIndex remoteLp, int subtype, int numReq) | ||
487 | { | ||
488 | int i; | ||
489 | unsigned long flags; | ||
490 | int tempNumAllocated; | ||
491 | |||
492 | if ((remoteLp >= HVMAXARCHITECTEDLPS) || (remoteLp == HvLpIndexInvalid)) | ||
493 | return -EINVAL; | ||
494 | |||
495 | subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT; | ||
496 | if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES)) | ||
497 | return -EINVAL; | ||
498 | |||
499 | spin_lock_irqsave(&statuslock, flags); | ||
500 | |||
501 | if (!event_buffer_initialised) { | ||
502 | for (i = 0; i < VIO_MAX_SUBTYPES; i++) | ||
503 | atomic_set(&event_buffer_available[i], 1); | ||
504 | event_buffer_initialised = 1; | ||
505 | } | ||
506 | |||
507 | viopathStatus[remoteLp].users[subtype]++; | ||
508 | |||
509 | if (!viopathStatus[remoteLp].isOpen) { | ||
510 | viopathStatus[remoteLp].isOpen = 1; | ||
511 | HvCallEvent_openLpEventPath(remoteLp, HvLpEvent_Type_VirtualIo); | ||
512 | |||
513 | /* | ||
514 | * Don't hold the spinlock during an operation that | ||
515 | * can sleep. | ||
516 | */ | ||
517 | spin_unlock_irqrestore(&statuslock, flags); | ||
518 | tempNumAllocated = allocateEvents(remoteLp, 1); | ||
519 | spin_lock_irqsave(&statuslock, flags); | ||
520 | |||
521 | viopathStatus[remoteLp].numberAllocated += tempNumAllocated; | ||
522 | |||
523 | if (viopathStatus[remoteLp].numberAllocated == 0) { | ||
524 | HvCallEvent_closeLpEventPath(remoteLp, | ||
525 | HvLpEvent_Type_VirtualIo); | ||
526 | |||
527 | spin_unlock_irqrestore(&statuslock, flags); | ||
528 | return -ENOMEM; | ||
529 | } | ||
530 | |||
531 | viopathStatus[remoteLp].mSourceInst = | ||
532 | HvCallEvent_getSourceLpInstanceId(remoteLp, | ||
533 | HvLpEvent_Type_VirtualIo); | ||
534 | viopathStatus[remoteLp].mTargetInst = | ||
535 | HvCallEvent_getTargetLpInstanceId(remoteLp, | ||
536 | HvLpEvent_Type_VirtualIo); | ||
537 | HvLpEvent_registerHandler(HvLpEvent_Type_VirtualIo, | ||
538 | &vio_handleEvent); | ||
539 | sendMonMsg(remoteLp); | ||
540 | printk(VIOPATH_KERN_INFO "opening connection to partition %d, " | ||
541 | "setting sinst %d, tinst %d\n", | ||
542 | remoteLp, viopathStatus[remoteLp].mSourceInst, | ||
543 | viopathStatus[remoteLp].mTargetInst); | ||
544 | } | ||
545 | |||
546 | spin_unlock_irqrestore(&statuslock, flags); | ||
547 | tempNumAllocated = allocateEvents(remoteLp, numReq); | ||
548 | spin_lock_irqsave(&statuslock, flags); | ||
549 | viopathStatus[remoteLp].numberAllocated += tempNumAllocated; | ||
550 | spin_unlock_irqrestore(&statuslock, flags); | ||
551 | |||
552 | return 0; | ||
553 | } | ||
554 | EXPORT_SYMBOL(viopath_open); | ||
555 | |||
556 | int viopath_close(HvLpIndex remoteLp, int subtype, int numReq) | ||
557 | { | ||
558 | unsigned long flags; | ||
559 | int i; | ||
560 | int numOpen; | ||
561 | struct alloc_parms parms; | ||
562 | |||
563 | if ((remoteLp >= HVMAXARCHITECTEDLPS) || (remoteLp == HvLpIndexInvalid)) | ||
564 | return -EINVAL; | ||
565 | |||
566 | subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT; | ||
567 | if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES)) | ||
568 | return -EINVAL; | ||
569 | |||
570 | spin_lock_irqsave(&statuslock, flags); | ||
571 | /* | ||
572 | * If the viopath_close somehow gets called before a | ||
573 | * viopath_open it could decrement to -1 which is a non | ||
574 | * recoverable state so we'll prevent this from | ||
575 | * happening. | ||
576 | */ | ||
577 | if (viopathStatus[remoteLp].users[subtype] > 0) | ||
578 | viopathStatus[remoteLp].users[subtype]--; | ||
579 | |||
580 | spin_unlock_irqrestore(&statuslock, flags); | ||
581 | |||
582 | parms.used_wait_atomic = 0; | ||
583 | init_completion(&parms.done); | ||
584 | mf_deallocate_lp_events(remoteLp, HvLpEvent_Type_VirtualIo, | ||
585 | numReq, &viopath_donealloc, &parms); | ||
586 | wait_for_completion(&parms.done); | ||
587 | |||
588 | spin_lock_irqsave(&statuslock, flags); | ||
589 | for (i = 0, numOpen = 0; i < VIO_MAX_SUBTYPES; i++) | ||
590 | numOpen += viopathStatus[remoteLp].users[i]; | ||
591 | |||
592 | if ((viopathStatus[remoteLp].isOpen) && (numOpen == 0)) { | ||
593 | printk(VIOPATH_KERN_INFO "closing connection to partition %d\n", | ||
594 | remoteLp); | ||
595 | |||
596 | HvCallEvent_closeLpEventPath(remoteLp, | ||
597 | HvLpEvent_Type_VirtualIo); | ||
598 | viopathStatus[remoteLp].isOpen = 0; | ||
599 | viopathStatus[remoteLp].isActive = 0; | ||
600 | |||
601 | for (i = 0; i < VIO_MAX_SUBTYPES; i++) | ||
602 | atomic_set(&event_buffer_available[i], 0); | ||
603 | event_buffer_initialised = 0; | ||
604 | } | ||
605 | spin_unlock_irqrestore(&statuslock, flags); | ||
606 | return 0; | ||
607 | } | ||
608 | EXPORT_SYMBOL(viopath_close); | ||
609 | |||
610 | void *vio_get_event_buffer(int subtype) | ||
611 | { | ||
612 | subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT; | ||
613 | if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES)) | ||
614 | return NULL; | ||
615 | |||
616 | if (atomic_dec_if_positive(&event_buffer_available[subtype]) == 0) | ||
617 | return &event_buffer[subtype * 256]; | ||
618 | else | ||
619 | return NULL; | ||
620 | } | ||
621 | EXPORT_SYMBOL(vio_get_event_buffer); | ||
622 | |||
623 | void vio_free_event_buffer(int subtype, void *buffer) | ||
624 | { | ||
625 | subtype = subtype >> VIOMAJOR_SUBTYPE_SHIFT; | ||
626 | if ((subtype < 0) || (subtype >= VIO_MAX_SUBTYPES)) { | ||
627 | printk(VIOPATH_KERN_WARN | ||
628 | "unexpected subtype %d freeing event buffer\n", subtype); | ||
629 | return; | ||
630 | } | ||
631 | |||
632 | if (atomic_read(&event_buffer_available[subtype]) != 0) { | ||
633 | printk(VIOPATH_KERN_WARN | ||
634 | "freeing unallocated event buffer, subtype %d\n", | ||
635 | subtype); | ||
636 | return; | ||
637 | } | ||
638 | |||
639 | if (buffer != &event_buffer[subtype * 256]) { | ||
640 | printk(VIOPATH_KERN_WARN | ||
641 | "freeing invalid event buffer, subtype %d\n", subtype); | ||
642 | } | ||
643 | |||
644 | atomic_set(&event_buffer_available[subtype], 1); | ||
645 | } | ||
646 | EXPORT_SYMBOL(vio_free_event_buffer); | ||
647 | |||
648 | static const struct vio_error_entry vio_no_error = | ||
649 | { 0, 0, "Non-VIO Error" }; | ||
650 | static const struct vio_error_entry vio_unknown_error = | ||
651 | { 0, EIO, "Unknown Error" }; | ||
652 | |||
653 | static const struct vio_error_entry vio_default_errors[] = { | ||
654 | {0x0001, EIO, "No Connection"}, | ||
655 | {0x0002, EIO, "No Receiver"}, | ||
656 | {0x0003, EIO, "No Buffer Available"}, | ||
657 | {0x0004, EBADRQC, "Invalid Message Type"}, | ||
658 | {0x0000, 0, NULL}, | ||
659 | }; | ||
660 | |||
661 | const struct vio_error_entry *vio_lookup_rc( | ||
662 | const struct vio_error_entry *local_table, u16 rc) | ||
663 | { | ||
664 | const struct vio_error_entry *cur; | ||
665 | |||
666 | if (!rc) | ||
667 | return &vio_no_error; | ||
668 | if (local_table) | ||
669 | for (cur = local_table; cur->rc; ++cur) | ||
670 | if (cur->rc == rc) | ||
671 | return cur; | ||
672 | for (cur = vio_default_errors; cur->rc; ++cur) | ||
673 | if (cur->rc == rc) | ||
674 | return cur; | ||
675 | return &vio_unknown_error; | ||
676 | } | ||
677 | EXPORT_SYMBOL(vio_lookup_rc); | ||
diff --git a/arch/powerpc/platforms/iseries/vpd_areas.h b/arch/powerpc/platforms/iseries/vpd_areas.h deleted file mode 100644 index feb001f3a5fe..000000000000 --- a/arch/powerpc/platforms/iseries/vpd_areas.h +++ /dev/null | |||
@@ -1,88 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001 Mike Corrigan IBM Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | */ | ||
18 | #ifndef _ISERIES_VPD_AREAS_H | ||
19 | #define _ISERIES_VPD_AREAS_H | ||
20 | |||
21 | /* | ||
22 | * This file defines the address and length of all of the VPD area passed to | ||
23 | * the OS from PLIC (most of which start from the SP). | ||
24 | */ | ||
25 | |||
26 | #include <asm/types.h> | ||
27 | |||
28 | /* VPD Entry index is carved in stone - cannot be changed (easily). */ | ||
29 | #define ItVpdCecVpd 0 | ||
30 | #define ItVpdDynamicSpace 1 | ||
31 | #define ItVpdExtVpd 2 | ||
32 | #define ItVpdExtVpdOnPanel 3 | ||
33 | #define ItVpdFirstPaca 4 | ||
34 | #define ItVpdIoVpd 5 | ||
35 | #define ItVpdIplParms 6 | ||
36 | #define ItVpdMsVpd 7 | ||
37 | #define ItVpdPanelVpd 8 | ||
38 | #define ItVpdLpNaca 9 | ||
39 | #define ItVpdBackplaneAndMaybeClockCardVpd 10 | ||
40 | #define ItVpdRecoveryLogBuffer 11 | ||
41 | #define ItVpdSpCommArea 12 | ||
42 | #define ItVpdSpLogBuffer 13 | ||
43 | #define ItVpdSpLogBufferSave 14 | ||
44 | #define ItVpdSpCardVpd 15 | ||
45 | #define ItVpdFirstProcVpd 16 | ||
46 | #define ItVpdApModelVpd 17 | ||
47 | #define ItVpdClockCardVpd 18 | ||
48 | #define ItVpdBusExtCardVpd 19 | ||
49 | #define ItVpdProcCapacityVpd 20 | ||
50 | #define ItVpdInteractiveCapacityVpd 21 | ||
51 | #define ItVpdFirstSlotLabel 22 | ||
52 | #define ItVpdFirstLpQueue 23 | ||
53 | #define ItVpdFirstL3CacheVpd 24 | ||
54 | #define ItVpdFirstProcFruVpd 25 | ||
55 | |||
56 | #define ItVpdMaxEntries 26 | ||
57 | |||
58 | #define ItDmaMaxEntries 10 | ||
59 | |||
60 | #define ItVpdAreasMaxSlotLabels 192 | ||
61 | |||
62 | |||
63 | struct ItVpdAreas { | ||
64 | u32 xSlicDesc; // Descriptor 000-003 | ||
65 | u16 xSlicSize; // Size of this control block 004-005 | ||
66 | u16 xPlicAdjustVpdLens:1; // Flag to indicate new interface006-007 | ||
67 | u16 xRsvd1:15; // Reserved bits ... | ||
68 | u16 xSlicVpdEntries; // Number of VPD entries 008-009 | ||
69 | u16 xSlicDmaEntries; // Number of DMA entries 00A-00B | ||
70 | u16 xSlicMaxLogicalProcs; // Maximum logical processors 00C-00D | ||
71 | u16 xSlicMaxPhysicalProcs; // Maximum physical processors 00E-00F | ||
72 | u16 xSlicDmaToksOffset; // Offset into this of array 010-011 | ||
73 | u16 xSlicVpdAdrsOffset; // Offset into this of array 012-013 | ||
74 | u16 xSlicDmaLensOffset; // Offset into this of array 014-015 | ||
75 | u16 xSlicVpdLensOffset; // Offset into this of array 016-017 | ||
76 | u16 xSlicMaxSlotLabels; // Maximum number of slot labels018-019 | ||
77 | u16 xSlicMaxLpQueues; // Maximum number of LP Queues 01A-01B | ||
78 | u8 xRsvd2[4]; // Reserved 01C-01F | ||
79 | u64 xRsvd3[12]; // Reserved 020-07F | ||
80 | u32 xPlicDmaLens[ItDmaMaxEntries];// Array of DMA lengths 080-0A7 | ||
81 | u32 xPlicDmaToks[ItDmaMaxEntries];// Array of DMA tokens 0A8-0CF | ||
82 | u32 xSlicVpdLens[ItVpdMaxEntries];// Array of VPD lengths 0D0-12F | ||
83 | const void *xSlicVpdAdrs[ItVpdMaxEntries];// Array of VPD buffers 130-1EF | ||
84 | }; | ||
85 | |||
86 | extern const struct ItVpdAreas itVpdAreas; | ||
87 | |||
88 | #endif /* _ISERIES_VPD_AREAS_H */ | ||
diff --git a/arch/powerpc/platforms/maple/setup.c b/arch/powerpc/platforms/maple/setup.c index 0bcbfe7b2c55..3b7545a51aa9 100644 --- a/arch/powerpc/platforms/maple/setup.c +++ b/arch/powerpc/platforms/maple/setup.c | |||
@@ -262,7 +262,7 @@ static void __init maple_init_IRQ(void) | |||
262 | flags |= MPIC_BIG_ENDIAN; | 262 | flags |= MPIC_BIG_ENDIAN; |
263 | 263 | ||
264 | /* XXX Maple specific bits */ | 264 | /* XXX Maple specific bits */ |
265 | flags |= MPIC_U3_HT_IRQS | MPIC_WANTS_RESET; | 265 | flags |= MPIC_U3_HT_IRQS; |
266 | /* All U3/U4 are big-endian, older SLOF firmware doesn't encode this */ | 266 | /* All U3/U4 are big-endian, older SLOF firmware doesn't encode this */ |
267 | flags |= MPIC_BIG_ENDIAN; | 267 | flags |= MPIC_BIG_ENDIAN; |
268 | 268 | ||
diff --git a/arch/powerpc/platforms/pasemi/setup.c b/arch/powerpc/platforms/pasemi/setup.c index 98b7a7c13176..e777ad471a48 100644 --- a/arch/powerpc/platforms/pasemi/setup.c +++ b/arch/powerpc/platforms/pasemi/setup.c | |||
@@ -224,7 +224,7 @@ static __init void pas_init_IRQ(void) | |||
224 | openpic_addr = of_read_number(opprop, naddr); | 224 | openpic_addr = of_read_number(opprop, naddr); |
225 | printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic_addr); | 225 | printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic_addr); |
226 | 226 | ||
227 | mpic_flags = MPIC_LARGE_VECTORS | MPIC_NO_BIAS; | 227 | mpic_flags = MPIC_LARGE_VECTORS | MPIC_NO_BIAS | MPIC_NO_RESET; |
228 | 228 | ||
229 | nmiprop = of_get_property(mpic_node, "nmi-source", NULL); | 229 | nmiprop = of_get_property(mpic_node, "nmi-source", NULL); |
230 | if (nmiprop) | 230 | if (nmiprop) |
diff --git a/arch/powerpc/platforms/powermac/nvram.c b/arch/powerpc/platforms/powermac/nvram.c index 54d227127c9f..da18b26dcc6f 100644 --- a/arch/powerpc/platforms/powermac/nvram.c +++ b/arch/powerpc/platforms/powermac/nvram.c | |||
@@ -279,7 +279,7 @@ static u32 core99_check(u8* datas) | |||
279 | 279 | ||
280 | static int sm_erase_bank(int bank) | 280 | static int sm_erase_bank(int bank) |
281 | { | 281 | { |
282 | int stat, i; | 282 | int stat; |
283 | unsigned long timeout; | 283 | unsigned long timeout; |
284 | 284 | ||
285 | u8 __iomem *base = (u8 __iomem *)nvram_data + core99_bank*NVRAM_SIZE; | 285 | u8 __iomem *base = (u8 __iomem *)nvram_data + core99_bank*NVRAM_SIZE; |
@@ -301,11 +301,10 @@ static int sm_erase_bank(int bank) | |||
301 | out_8(base, SM_FLASH_CMD_CLEAR_STATUS); | 301 | out_8(base, SM_FLASH_CMD_CLEAR_STATUS); |
302 | out_8(base, SM_FLASH_CMD_RESET); | 302 | out_8(base, SM_FLASH_CMD_RESET); |
303 | 303 | ||
304 | for (i=0; i<NVRAM_SIZE; i++) | 304 | if (memchr_inv(base, 0xff, NVRAM_SIZE)) { |
305 | if (base[i] != 0xff) { | 305 | printk(KERN_ERR "nvram: Sharp/Micron flash erase failed !\n"); |
306 | printk(KERN_ERR "nvram: Sharp/Micron flash erase failed !\n"); | 306 | return -ENXIO; |
307 | return -ENXIO; | 307 | } |
308 | } | ||
309 | return 0; | 308 | return 0; |
310 | } | 309 | } |
311 | 310 | ||
@@ -336,17 +335,16 @@ static int sm_write_bank(int bank, u8* datas) | |||
336 | } | 335 | } |
337 | out_8(base, SM_FLASH_CMD_CLEAR_STATUS); | 336 | out_8(base, SM_FLASH_CMD_CLEAR_STATUS); |
338 | out_8(base, SM_FLASH_CMD_RESET); | 337 | out_8(base, SM_FLASH_CMD_RESET); |
339 | for (i=0; i<NVRAM_SIZE; i++) | 338 | if (memcmp(base, datas, NVRAM_SIZE)) { |
340 | if (base[i] != datas[i]) { | 339 | printk(KERN_ERR "nvram: Sharp/Micron flash write failed !\n"); |
341 | printk(KERN_ERR "nvram: Sharp/Micron flash write failed !\n"); | 340 | return -ENXIO; |
342 | return -ENXIO; | 341 | } |
343 | } | ||
344 | return 0; | 342 | return 0; |
345 | } | 343 | } |
346 | 344 | ||
347 | static int amd_erase_bank(int bank) | 345 | static int amd_erase_bank(int bank) |
348 | { | 346 | { |
349 | int i, stat = 0; | 347 | int stat = 0; |
350 | unsigned long timeout; | 348 | unsigned long timeout; |
351 | 349 | ||
352 | u8 __iomem *base = (u8 __iomem *)nvram_data + core99_bank*NVRAM_SIZE; | 350 | u8 __iomem *base = (u8 __iomem *)nvram_data + core99_bank*NVRAM_SIZE; |
@@ -382,12 +380,11 @@ static int amd_erase_bank(int bank) | |||
382 | /* Reset */ | 380 | /* Reset */ |
383 | out_8(base, 0xf0); | 381 | out_8(base, 0xf0); |
384 | udelay(1); | 382 | udelay(1); |
385 | 383 | ||
386 | for (i=0; i<NVRAM_SIZE; i++) | 384 | if (memchr_inv(base, 0xff, NVRAM_SIZE)) { |
387 | if (base[i] != 0xff) { | 385 | printk(KERN_ERR "nvram: AMD flash erase failed !\n"); |
388 | printk(KERN_ERR "nvram: AMD flash erase failed !\n"); | 386 | return -ENXIO; |
389 | return -ENXIO; | 387 | } |
390 | } | ||
391 | return 0; | 388 | return 0; |
392 | } | 389 | } |
393 | 390 | ||
@@ -429,11 +426,10 @@ static int amd_write_bank(int bank, u8* datas) | |||
429 | out_8(base, 0xf0); | 426 | out_8(base, 0xf0); |
430 | udelay(1); | 427 | udelay(1); |
431 | 428 | ||
432 | for (i=0; i<NVRAM_SIZE; i++) | 429 | if (memcmp(base, datas, NVRAM_SIZE)) { |
433 | if (base[i] != datas[i]) { | 430 | printk(KERN_ERR "nvram: AMD flash write failed !\n"); |
434 | printk(KERN_ERR "nvram: AMD flash write failed !\n"); | 431 | return -ENXIO; |
435 | return -ENXIO; | 432 | } |
436 | } | ||
437 | return 0; | 433 | return 0; |
438 | } | 434 | } |
439 | 435 | ||
diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c index 92afc382a49e..66ad93de1d55 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c | |||
@@ -457,7 +457,6 @@ static struct mpic * __init pmac_setup_one_mpic(struct device_node *np, | |||
457 | 457 | ||
458 | pmac_call_feature(PMAC_FTR_ENABLE_MPIC, np, 0, 0); | 458 | pmac_call_feature(PMAC_FTR_ENABLE_MPIC, np, 0, 0); |
459 | 459 | ||
460 | flags |= MPIC_WANTS_RESET; | ||
461 | if (of_get_property(np, "big-endian", NULL)) | 460 | if (of_get_property(np, "big-endian", NULL)) |
462 | flags |= MPIC_BIG_ENDIAN; | 461 | flags |= MPIC_BIG_ENDIAN; |
463 | 462 | ||
diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c index f92b9ef7340e..214478d781ae 100644 --- a/arch/powerpc/platforms/powernv/pci.c +++ b/arch/powerpc/platforms/powernv/pci.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <asm/iommu.h> | 31 | #include <asm/iommu.h> |
32 | #include <asm/tce.h> | 32 | #include <asm/tce.h> |
33 | #include <asm/abs_addr.h> | 33 | #include <asm/abs_addr.h> |
34 | #include <asm/firmware.h> | ||
34 | 35 | ||
35 | #include "powernv.h" | 36 | #include "powernv.h" |
36 | #include "pci.h" | 37 | #include "pci.h" |
diff --git a/arch/powerpc/platforms/powernv/setup.c b/arch/powerpc/platforms/powernv/setup.c index 467bd4ac6824..db1ad1c8f68f 100644 --- a/arch/powerpc/platforms/powernv/setup.c +++ b/arch/powerpc/platforms/powernv/setup.c | |||
@@ -31,7 +31,6 @@ | |||
31 | #include <asm/xics.h> | 31 | #include <asm/xics.h> |
32 | #include <asm/rtas.h> | 32 | #include <asm/rtas.h> |
33 | #include <asm/opal.h> | 33 | #include <asm/opal.h> |
34 | #include <asm/xics.h> | ||
35 | 34 | ||
36 | #include "powernv.h" | 35 | #include "powernv.h" |
37 | 36 | ||
diff --git a/arch/powerpc/platforms/pseries/Kconfig b/arch/powerpc/platforms/pseries/Kconfig index f2556257bbdc..aadbe4f6d537 100644 --- a/arch/powerpc/platforms/pseries/Kconfig +++ b/arch/powerpc/platforms/pseries/Kconfig | |||
@@ -73,7 +73,7 @@ config IO_EVENT_IRQ | |||
73 | 73 | ||
74 | config LPARCFG | 74 | config LPARCFG |
75 | bool "LPAR Configuration Data" | 75 | bool "LPAR Configuration Data" |
76 | depends on PPC_PSERIES || PPC_ISERIES | 76 | depends on PPC_PSERIES |
77 | help | 77 | help |
78 | Provide system capacity information via human readable | 78 | Provide system capacity information via human readable |
79 | <key word>=<value> pairs through a /proc/ppc64/lparcfg interface. | 79 | <key word>=<value> pairs through a /proc/ppc64/lparcfg interface. |
diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile index 236db46b4078..c222189f5bb2 100644 --- a/arch/powerpc/platforms/pseries/Makefile +++ b/arch/powerpc/platforms/pseries/Makefile | |||
@@ -6,7 +6,8 @@ obj-y := lpar.o hvCall.o nvram.o reconfig.o \ | |||
6 | firmware.o power.o dlpar.o mobility.o | 6 | firmware.o power.o dlpar.o mobility.o |
7 | obj-$(CONFIG_SMP) += smp.o | 7 | obj-$(CONFIG_SMP) += smp.o |
8 | obj-$(CONFIG_SCANLOG) += scanlog.o | 8 | obj-$(CONFIG_SCANLOG) += scanlog.o |
9 | obj-$(CONFIG_EEH) += eeh.o eeh_cache.o eeh_driver.o eeh_event.o eeh_sysfs.o | 9 | obj-$(CONFIG_EEH) += eeh.o eeh_dev.o eeh_cache.o eeh_driver.o \ |
10 | eeh_event.o eeh_sysfs.o eeh_pseries.o | ||
10 | obj-$(CONFIG_KEXEC) += kexec.o | 11 | obj-$(CONFIG_KEXEC) += kexec.o |
11 | obj-$(CONFIG_PCI) += pci.o pci_dlpar.o | 12 | obj-$(CONFIG_PCI) += pci.o pci_dlpar.o |
12 | obj-$(CONFIG_PSERIES_MSI) += msi.o | 13 | obj-$(CONFIG_PSERIES_MSI) += msi.o |
@@ -18,7 +19,6 @@ obj-$(CONFIG_MEMORY_HOTPLUG) += hotplug-memory.o | |||
18 | obj-$(CONFIG_HVC_CONSOLE) += hvconsole.o | 19 | obj-$(CONFIG_HVC_CONSOLE) += hvconsole.o |
19 | obj-$(CONFIG_HVCS) += hvcserver.o | 20 | obj-$(CONFIG_HVCS) += hvcserver.o |
20 | obj-$(CONFIG_HCALL_STATS) += hvCall_inst.o | 21 | obj-$(CONFIG_HCALL_STATS) += hvCall_inst.o |
21 | obj-$(CONFIG_PHYP_DUMP) += phyp_dump.o | ||
22 | obj-$(CONFIG_CMM) += cmm.o | 22 | obj-$(CONFIG_CMM) += cmm.o |
23 | obj-$(CONFIG_DTL) += dtl.o | 23 | obj-$(CONFIG_DTL) += dtl.o |
24 | obj-$(CONFIG_IO_EVENT_IRQ) += io_event_irq.o | 24 | obj-$(CONFIG_IO_EVENT_IRQ) += io_event_irq.o |
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index c0b40af4ce4f..8011088392d3 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c | |||
@@ -1,8 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * eeh.c | ||
3 | * Copyright IBM Corporation 2001, 2005, 2006 | 2 | * Copyright IBM Corporation 2001, 2005, 2006 |
4 | * Copyright Dave Engebretsen & Todd Inglett 2001 | 3 | * Copyright Dave Engebretsen & Todd Inglett 2001 |
5 | * Copyright Linas Vepstas 2005, 2006 | 4 | * Copyright Linas Vepstas 2005, 2006 |
5 | * Copyright 2001-2012 IBM Corporation. | ||
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by | 8 | * it under the terms of the GNU General Public License as published by |
@@ -22,7 +22,7 @@ | |||
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
25 | #include <linux/sched.h> /* for init_mm */ | 25 | #include <linux/sched.h> |
26 | #include <linux/init.h> | 26 | #include <linux/init.h> |
27 | #include <linux/list.h> | 27 | #include <linux/list.h> |
28 | #include <linux/pci.h> | 28 | #include <linux/pci.h> |
@@ -86,16 +86,8 @@ | |||
86 | /* Time to wait for a PCI slot to report status, in milliseconds */ | 86 | /* Time to wait for a PCI slot to report status, in milliseconds */ |
87 | #define PCI_BUS_RESET_WAIT_MSEC (60*1000) | 87 | #define PCI_BUS_RESET_WAIT_MSEC (60*1000) |
88 | 88 | ||
89 | /* RTAS tokens */ | 89 | /* Platform dependent EEH operations */ |
90 | static int ibm_set_eeh_option; | 90 | struct eeh_ops *eeh_ops = NULL; |
91 | static int ibm_set_slot_reset; | ||
92 | static int ibm_read_slot_reset_state; | ||
93 | static int ibm_read_slot_reset_state2; | ||
94 | static int ibm_slot_error_detail; | ||
95 | static int ibm_get_config_addr_info; | ||
96 | static int ibm_get_config_addr_info2; | ||
97 | static int ibm_configure_bridge; | ||
98 | static int ibm_configure_pe; | ||
99 | 91 | ||
100 | int eeh_subsystem_enabled; | 92 | int eeh_subsystem_enabled; |
101 | EXPORT_SYMBOL(eeh_subsystem_enabled); | 93 | EXPORT_SYMBOL(eeh_subsystem_enabled); |
@@ -103,14 +95,6 @@ EXPORT_SYMBOL(eeh_subsystem_enabled); | |||
103 | /* Lock to avoid races due to multiple reports of an error */ | 95 | /* Lock to avoid races due to multiple reports of an error */ |
104 | static DEFINE_RAW_SPINLOCK(confirm_error_lock); | 96 | static DEFINE_RAW_SPINLOCK(confirm_error_lock); |
105 | 97 | ||
106 | /* Buffer for reporting slot-error-detail rtas calls. Its here | ||
107 | * in BSS, and not dynamically alloced, so that it ends up in | ||
108 | * RMO where RTAS can access it. | ||
109 | */ | ||
110 | static unsigned char slot_errbuf[RTAS_ERROR_LOG_MAX]; | ||
111 | static DEFINE_SPINLOCK(slot_errbuf_lock); | ||
112 | static int eeh_error_buf_size; | ||
113 | |||
114 | /* Buffer for reporting pci register dumps. Its here in BSS, and | 98 | /* Buffer for reporting pci register dumps. Its here in BSS, and |
115 | * not dynamically alloced, so that it ends up in RMO where RTAS | 99 | * not dynamically alloced, so that it ends up in RMO where RTAS |
116 | * can access it. | 100 | * can access it. |
@@ -118,74 +102,50 @@ static int eeh_error_buf_size; | |||
118 | #define EEH_PCI_REGS_LOG_LEN 4096 | 102 | #define EEH_PCI_REGS_LOG_LEN 4096 |
119 | static unsigned char pci_regs_buf[EEH_PCI_REGS_LOG_LEN]; | 103 | static unsigned char pci_regs_buf[EEH_PCI_REGS_LOG_LEN]; |
120 | 104 | ||
121 | /* System monitoring statistics */ | 105 | /* |
122 | static unsigned long no_device; | 106 | * The struct is used to maintain the EEH global statistic |
123 | static unsigned long no_dn; | 107 | * information. Besides, the EEH global statistics will be |
124 | static unsigned long no_cfg_addr; | 108 | * exported to user space through procfs |
125 | static unsigned long ignored_check; | 109 | */ |
126 | static unsigned long total_mmio_ffs; | 110 | struct eeh_stats { |
127 | static unsigned long false_positives; | 111 | u64 no_device; /* PCI device not found */ |
128 | static unsigned long slot_resets; | 112 | u64 no_dn; /* OF node not found */ |
129 | 113 | u64 no_cfg_addr; /* Config address not found */ | |
130 | #define IS_BRIDGE(class_code) (((class_code)<<16) == PCI_BASE_CLASS_BRIDGE) | 114 | u64 ignored_check; /* EEH check skipped */ |
131 | 115 | u64 total_mmio_ffs; /* Total EEH checks */ | |
132 | /* --------------------------------------------------------------- */ | 116 | u64 false_positives; /* Unnecessary EEH checks */ |
133 | /* Below lies the EEH event infrastructure */ | 117 | u64 slot_resets; /* PE reset */ |
118 | }; | ||
134 | 119 | ||
135 | static void rtas_slot_error_detail(struct pci_dn *pdn, int severity, | 120 | static struct eeh_stats eeh_stats; |
136 | char *driver_log, size_t loglen) | ||
137 | { | ||
138 | int config_addr; | ||
139 | unsigned long flags; | ||
140 | int rc; | ||
141 | 121 | ||
142 | /* Log the error with the rtas logger */ | 122 | #define IS_BRIDGE(class_code) (((class_code)<<16) == PCI_BASE_CLASS_BRIDGE) |
143 | spin_lock_irqsave(&slot_errbuf_lock, flags); | ||
144 | memset(slot_errbuf, 0, eeh_error_buf_size); | ||
145 | |||
146 | /* Use PE configuration address, if present */ | ||
147 | config_addr = pdn->eeh_config_addr; | ||
148 | if (pdn->eeh_pe_config_addr) | ||
149 | config_addr = pdn->eeh_pe_config_addr; | ||
150 | |||
151 | rc = rtas_call(ibm_slot_error_detail, | ||
152 | 8, 1, NULL, config_addr, | ||
153 | BUID_HI(pdn->phb->buid), | ||
154 | BUID_LO(pdn->phb->buid), | ||
155 | virt_to_phys(driver_log), loglen, | ||
156 | virt_to_phys(slot_errbuf), | ||
157 | eeh_error_buf_size, | ||
158 | severity); | ||
159 | |||
160 | if (rc == 0) | ||
161 | log_error(slot_errbuf, ERR_TYPE_RTAS_LOG, 0); | ||
162 | spin_unlock_irqrestore(&slot_errbuf_lock, flags); | ||
163 | } | ||
164 | 123 | ||
165 | /** | 124 | /** |
166 | * gather_pci_data - copy assorted PCI config space registers to buff | 125 | * eeh_gather_pci_data - Copy assorted PCI config space registers to buff |
167 | * @pdn: device to report data for | 126 | * @edev: device to report data for |
168 | * @buf: point to buffer in which to log | 127 | * @buf: point to buffer in which to log |
169 | * @len: amount of room in buffer | 128 | * @len: amount of room in buffer |
170 | * | 129 | * |
171 | * This routine captures assorted PCI configuration space data, | 130 | * This routine captures assorted PCI configuration space data, |
172 | * and puts them into a buffer for RTAS error logging. | 131 | * and puts them into a buffer for RTAS error logging. |
173 | */ | 132 | */ |
174 | static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len) | 133 | static size_t eeh_gather_pci_data(struct eeh_dev *edev, char * buf, size_t len) |
175 | { | 134 | { |
176 | struct pci_dev *dev = pdn->pcidev; | 135 | struct device_node *dn = eeh_dev_to_of_node(edev); |
136 | struct pci_dev *dev = eeh_dev_to_pci_dev(edev); | ||
177 | u32 cfg; | 137 | u32 cfg; |
178 | int cap, i; | 138 | int cap, i; |
179 | int n = 0; | 139 | int n = 0; |
180 | 140 | ||
181 | n += scnprintf(buf+n, len-n, "%s\n", pdn->node->full_name); | 141 | n += scnprintf(buf+n, len-n, "%s\n", dn->full_name); |
182 | printk(KERN_WARNING "EEH: of node=%s\n", pdn->node->full_name); | 142 | printk(KERN_WARNING "EEH: of node=%s\n", dn->full_name); |
183 | 143 | ||
184 | rtas_read_config(pdn, PCI_VENDOR_ID, 4, &cfg); | 144 | eeh_ops->read_config(dn, PCI_VENDOR_ID, 4, &cfg); |
185 | n += scnprintf(buf+n, len-n, "dev/vend:%08x\n", cfg); | 145 | n += scnprintf(buf+n, len-n, "dev/vend:%08x\n", cfg); |
186 | printk(KERN_WARNING "EEH: PCI device/vendor: %08x\n", cfg); | 146 | printk(KERN_WARNING "EEH: PCI device/vendor: %08x\n", cfg); |
187 | 147 | ||
188 | rtas_read_config(pdn, PCI_COMMAND, 4, &cfg); | 148 | eeh_ops->read_config(dn, PCI_COMMAND, 4, &cfg); |
189 | n += scnprintf(buf+n, len-n, "cmd/stat:%x\n", cfg); | 149 | n += scnprintf(buf+n, len-n, "cmd/stat:%x\n", cfg); |
190 | printk(KERN_WARNING "EEH: PCI cmd/status register: %08x\n", cfg); | 150 | printk(KERN_WARNING "EEH: PCI cmd/status register: %08x\n", cfg); |
191 | 151 | ||
@@ -196,11 +156,11 @@ static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len) | |||
196 | 156 | ||
197 | /* Gather bridge-specific registers */ | 157 | /* Gather bridge-specific registers */ |
198 | if (dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) { | 158 | if (dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) { |
199 | rtas_read_config(pdn, PCI_SEC_STATUS, 2, &cfg); | 159 | eeh_ops->read_config(dn, PCI_SEC_STATUS, 2, &cfg); |
200 | n += scnprintf(buf+n, len-n, "sec stat:%x\n", cfg); | 160 | n += scnprintf(buf+n, len-n, "sec stat:%x\n", cfg); |
201 | printk(KERN_WARNING "EEH: Bridge secondary status: %04x\n", cfg); | 161 | printk(KERN_WARNING "EEH: Bridge secondary status: %04x\n", cfg); |
202 | 162 | ||
203 | rtas_read_config(pdn, PCI_BRIDGE_CONTROL, 2, &cfg); | 163 | eeh_ops->read_config(dn, PCI_BRIDGE_CONTROL, 2, &cfg); |
204 | n += scnprintf(buf+n, len-n, "brdg ctl:%x\n", cfg); | 164 | n += scnprintf(buf+n, len-n, "brdg ctl:%x\n", cfg); |
205 | printk(KERN_WARNING "EEH: Bridge control: %04x\n", cfg); | 165 | printk(KERN_WARNING "EEH: Bridge control: %04x\n", cfg); |
206 | } | 166 | } |
@@ -208,11 +168,11 @@ static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len) | |||
208 | /* Dump out the PCI-X command and status regs */ | 168 | /* Dump out the PCI-X command and status regs */ |
209 | cap = pci_find_capability(dev, PCI_CAP_ID_PCIX); | 169 | cap = pci_find_capability(dev, PCI_CAP_ID_PCIX); |
210 | if (cap) { | 170 | if (cap) { |
211 | rtas_read_config(pdn, cap, 4, &cfg); | 171 | eeh_ops->read_config(dn, cap, 4, &cfg); |
212 | n += scnprintf(buf+n, len-n, "pcix-cmd:%x\n", cfg); | 172 | n += scnprintf(buf+n, len-n, "pcix-cmd:%x\n", cfg); |
213 | printk(KERN_WARNING "EEH: PCI-X cmd: %08x\n", cfg); | 173 | printk(KERN_WARNING "EEH: PCI-X cmd: %08x\n", cfg); |
214 | 174 | ||
215 | rtas_read_config(pdn, cap+4, 4, &cfg); | 175 | eeh_ops->read_config(dn, cap+4, 4, &cfg); |
216 | n += scnprintf(buf+n, len-n, "pcix-stat:%x\n", cfg); | 176 | n += scnprintf(buf+n, len-n, "pcix-stat:%x\n", cfg); |
217 | printk(KERN_WARNING "EEH: PCI-X status: %08x\n", cfg); | 177 | printk(KERN_WARNING "EEH: PCI-X status: %08x\n", cfg); |
218 | } | 178 | } |
@@ -225,7 +185,7 @@ static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len) | |||
225 | "EEH: PCI-E capabilities and status follow:\n"); | 185 | "EEH: PCI-E capabilities and status follow:\n"); |
226 | 186 | ||
227 | for (i=0; i<=8; i++) { | 187 | for (i=0; i<=8; i++) { |
228 | rtas_read_config(pdn, cap+4*i, 4, &cfg); | 188 | eeh_ops->read_config(dn, cap+4*i, 4, &cfg); |
229 | n += scnprintf(buf+n, len-n, "%02x:%x\n", 4*i, cfg); | 189 | n += scnprintf(buf+n, len-n, "%02x:%x\n", 4*i, cfg); |
230 | printk(KERN_WARNING "EEH: PCI-E %02x: %08x\n", i, cfg); | 190 | printk(KERN_WARNING "EEH: PCI-E %02x: %08x\n", i, cfg); |
231 | } | 191 | } |
@@ -237,7 +197,7 @@ static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len) | |||
237 | "EEH: PCI-E AER capability register set follows:\n"); | 197 | "EEH: PCI-E AER capability register set follows:\n"); |
238 | 198 | ||
239 | for (i=0; i<14; i++) { | 199 | for (i=0; i<14; i++) { |
240 | rtas_read_config(pdn, cap+4*i, 4, &cfg); | 200 | eeh_ops->read_config(dn, cap+4*i, 4, &cfg); |
241 | n += scnprintf(buf+n, len-n, "%02x:%x\n", 4*i, cfg); | 201 | n += scnprintf(buf+n, len-n, "%02x:%x\n", 4*i, cfg); |
242 | printk(KERN_WARNING "EEH: PCI-E AER %02x: %08x\n", i, cfg); | 202 | printk(KERN_WARNING "EEH: PCI-E AER %02x: %08x\n", i, cfg); |
243 | } | 203 | } |
@@ -246,111 +206,46 @@ static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len) | |||
246 | 206 | ||
247 | /* Gather status on devices under the bridge */ | 207 | /* Gather status on devices under the bridge */ |
248 | if (dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) { | 208 | if (dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) { |
249 | struct device_node *dn; | 209 | struct device_node *child; |
250 | 210 | ||
251 | for_each_child_of_node(pdn->node, dn) { | 211 | for_each_child_of_node(dn, child) { |
252 | pdn = PCI_DN(dn); | 212 | if (of_node_to_eeh_dev(child)) |
253 | if (pdn) | 213 | n += eeh_gather_pci_data(of_node_to_eeh_dev(child), buf+n, len-n); |
254 | n += gather_pci_data(pdn, buf+n, len-n); | ||
255 | } | 214 | } |
256 | } | 215 | } |
257 | 216 | ||
258 | return n; | 217 | return n; |
259 | } | 218 | } |
260 | 219 | ||
261 | void eeh_slot_error_detail(struct pci_dn *pdn, int severity) | ||
262 | { | ||
263 | size_t loglen = 0; | ||
264 | pci_regs_buf[0] = 0; | ||
265 | |||
266 | rtas_pci_enable(pdn, EEH_THAW_MMIO); | ||
267 | rtas_configure_bridge(pdn); | ||
268 | eeh_restore_bars(pdn); | ||
269 | loglen = gather_pci_data(pdn, pci_regs_buf, EEH_PCI_REGS_LOG_LEN); | ||
270 | |||
271 | rtas_slot_error_detail(pdn, severity, pci_regs_buf, loglen); | ||
272 | } | ||
273 | |||
274 | /** | 220 | /** |
275 | * read_slot_reset_state - Read the reset state of a device node's slot | 221 | * eeh_slot_error_detail - Generate combined log including driver log and error log |
276 | * @dn: device node to read | 222 | * @edev: device to report error log for |
277 | * @rets: array to return results in | 223 | * @severity: temporary or permanent error log |
278 | */ | ||
279 | static int read_slot_reset_state(struct pci_dn *pdn, int rets[]) | ||
280 | { | ||
281 | int token, outputs; | ||
282 | int config_addr; | ||
283 | |||
284 | if (ibm_read_slot_reset_state2 != RTAS_UNKNOWN_SERVICE) { | ||
285 | token = ibm_read_slot_reset_state2; | ||
286 | outputs = 4; | ||
287 | } else { | ||
288 | token = ibm_read_slot_reset_state; | ||
289 | rets[2] = 0; /* fake PE Unavailable info */ | ||
290 | outputs = 3; | ||
291 | } | ||
292 | |||
293 | /* Use PE configuration address, if present */ | ||
294 | config_addr = pdn->eeh_config_addr; | ||
295 | if (pdn->eeh_pe_config_addr) | ||
296 | config_addr = pdn->eeh_pe_config_addr; | ||
297 | |||
298 | return rtas_call(token, 3, outputs, rets, config_addr, | ||
299 | BUID_HI(pdn->phb->buid), BUID_LO(pdn->phb->buid)); | ||
300 | } | ||
301 | |||
302 | /** | ||
303 | * eeh_wait_for_slot_status - returns error status of slot | ||
304 | * @pdn pci device node | ||
305 | * @max_wait_msecs maximum number to millisecs to wait | ||
306 | * | ||
307 | * Return negative value if a permanent error, else return | ||
308 | * Partition Endpoint (PE) status value. | ||
309 | * | 224 | * |
310 | * If @max_wait_msecs is positive, then this routine will | 225 | * This routine should be called to generate the combined log, which |
311 | * sleep until a valid status can be obtained, or until | 226 | * is comprised of driver log and error log. The driver log is figured |
312 | * the max allowed wait time is exceeded, in which case | 227 | * out from the config space of the corresponding PCI device, while |
313 | * a -2 is returned. | 228 | * the error log is fetched through platform dependent function call. |
314 | */ | 229 | */ |
315 | int | 230 | void eeh_slot_error_detail(struct eeh_dev *edev, int severity) |
316 | eeh_wait_for_slot_status(struct pci_dn *pdn, int max_wait_msecs) | ||
317 | { | 231 | { |
318 | int rc; | 232 | size_t loglen = 0; |
319 | int rets[3]; | 233 | pci_regs_buf[0] = 0; |
320 | int mwait; | ||
321 | |||
322 | while (1) { | ||
323 | rc = read_slot_reset_state(pdn, rets); | ||
324 | if (rc) return rc; | ||
325 | if (rets[1] == 0) return -1; /* EEH is not supported */ | ||
326 | |||
327 | if (rets[0] != 5) return rets[0]; /* return actual status */ | ||
328 | |||
329 | if (rets[2] == 0) return -1; /* permanently unavailable */ | ||
330 | 234 | ||
331 | if (max_wait_msecs <= 0) break; | 235 | eeh_pci_enable(edev, EEH_OPT_THAW_MMIO); |
236 | eeh_ops->configure_bridge(eeh_dev_to_of_node(edev)); | ||
237 | eeh_restore_bars(edev); | ||
238 | loglen = eeh_gather_pci_data(edev, pci_regs_buf, EEH_PCI_REGS_LOG_LEN); | ||
332 | 239 | ||
333 | mwait = rets[2]; | 240 | eeh_ops->get_log(eeh_dev_to_of_node(edev), severity, pci_regs_buf, loglen); |
334 | if (mwait <= 0) { | ||
335 | printk (KERN_WARNING | ||
336 | "EEH: Firmware returned bad wait value=%d\n", mwait); | ||
337 | mwait = 1000; | ||
338 | } else if (mwait > 300*1000) { | ||
339 | printk (KERN_WARNING | ||
340 | "EEH: Firmware is taking too long, time=%d\n", mwait); | ||
341 | mwait = 300*1000; | ||
342 | } | ||
343 | max_wait_msecs -= mwait; | ||
344 | msleep (mwait); | ||
345 | } | ||
346 | |||
347 | printk(KERN_WARNING "EEH: Timed out waiting for slot status\n"); | ||
348 | return -2; | ||
349 | } | 241 | } |
350 | 242 | ||
351 | /** | 243 | /** |
352 | * eeh_token_to_phys - convert EEH address token to phys address | 244 | * eeh_token_to_phys - Convert EEH address token to phys address |
353 | * @token i/o token, should be address in the form 0xA.... | 245 | * @token: I/O token, should be address in the form 0xA.... |
246 | * | ||
247 | * This routine should be called to convert virtual I/O address | ||
248 | * to physical one. | ||
354 | */ | 249 | */ |
355 | static inline unsigned long eeh_token_to_phys(unsigned long token) | 250 | static inline unsigned long eeh_token_to_phys(unsigned long token) |
356 | { | 251 | { |
@@ -365,36 +260,43 @@ static inline unsigned long eeh_token_to_phys(unsigned long token) | |||
365 | return pa | (token & (PAGE_SIZE-1)); | 260 | return pa | (token & (PAGE_SIZE-1)); |
366 | } | 261 | } |
367 | 262 | ||
368 | /** | 263 | /** |
369 | * Return the "partitionable endpoint" (pe) under which this device lies | 264 | * eeh_find_device_pe - Retrieve the PE for the given device |
265 | * @dn: device node | ||
266 | * | ||
267 | * Return the PE under which this device lies | ||
370 | */ | 268 | */ |
371 | struct device_node * find_device_pe(struct device_node *dn) | 269 | struct device_node *eeh_find_device_pe(struct device_node *dn) |
372 | { | 270 | { |
373 | while ((dn->parent) && PCI_DN(dn->parent) && | 271 | while (dn->parent && of_node_to_eeh_dev(dn->parent) && |
374 | (PCI_DN(dn->parent)->eeh_mode & EEH_MODE_SUPPORTED)) { | 272 | (of_node_to_eeh_dev(dn->parent)->mode & EEH_MODE_SUPPORTED)) { |
375 | dn = dn->parent; | 273 | dn = dn->parent; |
376 | } | 274 | } |
377 | return dn; | 275 | return dn; |
378 | } | 276 | } |
379 | 277 | ||
380 | /** Mark all devices that are children of this device as failed. | 278 | /** |
381 | * Mark the device driver too, so that it can see the failure | 279 | * __eeh_mark_slot - Mark all child devices as failed |
382 | * immediately; this is critical, since some drivers poll | 280 | * @parent: parent device |
383 | * status registers in interrupts ... If a driver is polling, | 281 | * @mode_flag: failure flag |
384 | * and the slot is frozen, then the driver can deadlock in | 282 | * |
385 | * an interrupt context, which is bad. | 283 | * Mark all devices that are children of this device as failed. |
284 | * Mark the device driver too, so that it can see the failure | ||
285 | * immediately; this is critical, since some drivers poll | ||
286 | * status registers in interrupts ... If a driver is polling, | ||
287 | * and the slot is frozen, then the driver can deadlock in | ||
288 | * an interrupt context, which is bad. | ||
386 | */ | 289 | */ |
387 | |||
388 | static void __eeh_mark_slot(struct device_node *parent, int mode_flag) | 290 | static void __eeh_mark_slot(struct device_node *parent, int mode_flag) |
389 | { | 291 | { |
390 | struct device_node *dn; | 292 | struct device_node *dn; |
391 | 293 | ||
392 | for_each_child_of_node(parent, dn) { | 294 | for_each_child_of_node(parent, dn) { |
393 | if (PCI_DN(dn)) { | 295 | if (of_node_to_eeh_dev(dn)) { |
394 | /* Mark the pci device driver too */ | 296 | /* Mark the pci device driver too */ |
395 | struct pci_dev *dev = PCI_DN(dn)->pcidev; | 297 | struct pci_dev *dev = of_node_to_eeh_dev(dn)->pdev; |
396 | 298 | ||
397 | PCI_DN(dn)->eeh_mode |= mode_flag; | 299 | of_node_to_eeh_dev(dn)->mode |= mode_flag; |
398 | 300 | ||
399 | if (dev && dev->driver) | 301 | if (dev && dev->driver) |
400 | dev->error_state = pci_channel_io_frozen; | 302 | dev->error_state = pci_channel_io_frozen; |
@@ -404,92 +306,81 @@ static void __eeh_mark_slot(struct device_node *parent, int mode_flag) | |||
404 | } | 306 | } |
405 | } | 307 | } |
406 | 308 | ||
407 | void eeh_mark_slot (struct device_node *dn, int mode_flag) | 309 | /** |
310 | * eeh_mark_slot - Mark the indicated device and its children as failed | ||
311 | * @dn: parent device | ||
312 | * @mode_flag: failure flag | ||
313 | * | ||
314 | * Mark the indicated device and its child devices as failed. | ||
315 | * The device drivers are marked as failed as well. | ||
316 | */ | ||
317 | void eeh_mark_slot(struct device_node *dn, int mode_flag) | ||
408 | { | 318 | { |
409 | struct pci_dev *dev; | 319 | struct pci_dev *dev; |
410 | dn = find_device_pe (dn); | 320 | dn = eeh_find_device_pe(dn); |
411 | 321 | ||
412 | /* Back up one, since config addrs might be shared */ | 322 | /* Back up one, since config addrs might be shared */ |
413 | if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent)) | 323 | if (!pcibios_find_pci_bus(dn) && of_node_to_eeh_dev(dn->parent)) |
414 | dn = dn->parent; | 324 | dn = dn->parent; |
415 | 325 | ||
416 | PCI_DN(dn)->eeh_mode |= mode_flag; | 326 | of_node_to_eeh_dev(dn)->mode |= mode_flag; |
417 | 327 | ||
418 | /* Mark the pci device too */ | 328 | /* Mark the pci device too */ |
419 | dev = PCI_DN(dn)->pcidev; | 329 | dev = of_node_to_eeh_dev(dn)->pdev; |
420 | if (dev) | 330 | if (dev) |
421 | dev->error_state = pci_channel_io_frozen; | 331 | dev->error_state = pci_channel_io_frozen; |
422 | 332 | ||
423 | __eeh_mark_slot(dn, mode_flag); | 333 | __eeh_mark_slot(dn, mode_flag); |
424 | } | 334 | } |
425 | 335 | ||
336 | /** | ||
337 | * __eeh_clear_slot - Clear failure flag for the child devices | ||
338 | * @parent: parent device | ||
339 | * @mode_flag: flag to be cleared | ||
340 | * | ||
341 | * Clear failure flag for the child devices. | ||
342 | */ | ||
426 | static void __eeh_clear_slot(struct device_node *parent, int mode_flag) | 343 | static void __eeh_clear_slot(struct device_node *parent, int mode_flag) |
427 | { | 344 | { |
428 | struct device_node *dn; | 345 | struct device_node *dn; |
429 | 346 | ||
430 | for_each_child_of_node(parent, dn) { | 347 | for_each_child_of_node(parent, dn) { |
431 | if (PCI_DN(dn)) { | 348 | if (of_node_to_eeh_dev(dn)) { |
432 | PCI_DN(dn)->eeh_mode &= ~mode_flag; | 349 | of_node_to_eeh_dev(dn)->mode &= ~mode_flag; |
433 | PCI_DN(dn)->eeh_check_count = 0; | 350 | of_node_to_eeh_dev(dn)->check_count = 0; |
434 | __eeh_clear_slot(dn, mode_flag); | 351 | __eeh_clear_slot(dn, mode_flag); |
435 | } | 352 | } |
436 | } | 353 | } |
437 | } | 354 | } |
438 | 355 | ||
439 | void eeh_clear_slot (struct device_node *dn, int mode_flag) | 356 | /** |
357 | * eeh_clear_slot - Clear failure flag for the indicated device and its children | ||
358 | * @dn: parent device | ||
359 | * @mode_flag: flag to be cleared | ||
360 | * | ||
361 | * Clear failure flag for the indicated device and its children. | ||
362 | */ | ||
363 | void eeh_clear_slot(struct device_node *dn, int mode_flag) | ||
440 | { | 364 | { |
441 | unsigned long flags; | 365 | unsigned long flags; |
442 | raw_spin_lock_irqsave(&confirm_error_lock, flags); | 366 | raw_spin_lock_irqsave(&confirm_error_lock, flags); |
443 | 367 | ||
444 | dn = find_device_pe (dn); | 368 | dn = eeh_find_device_pe(dn); |
445 | 369 | ||
446 | /* Back up one, since config addrs might be shared */ | 370 | /* Back up one, since config addrs might be shared */ |
447 | if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent)) | 371 | if (!pcibios_find_pci_bus(dn) && of_node_to_eeh_dev(dn->parent)) |
448 | dn = dn->parent; | 372 | dn = dn->parent; |
449 | 373 | ||
450 | PCI_DN(dn)->eeh_mode &= ~mode_flag; | 374 | of_node_to_eeh_dev(dn)->mode &= ~mode_flag; |
451 | PCI_DN(dn)->eeh_check_count = 0; | 375 | of_node_to_eeh_dev(dn)->check_count = 0; |
452 | __eeh_clear_slot(dn, mode_flag); | 376 | __eeh_clear_slot(dn, mode_flag); |
453 | raw_spin_unlock_irqrestore(&confirm_error_lock, flags); | 377 | raw_spin_unlock_irqrestore(&confirm_error_lock, flags); |
454 | } | 378 | } |
455 | 379 | ||
456 | void __eeh_set_pe_freset(struct device_node *parent, unsigned int *freset) | ||
457 | { | ||
458 | struct device_node *dn; | ||
459 | |||
460 | for_each_child_of_node(parent, dn) { | ||
461 | if (PCI_DN(dn)) { | ||
462 | |||
463 | struct pci_dev *dev = PCI_DN(dn)->pcidev; | ||
464 | |||
465 | if (dev && dev->driver) | ||
466 | *freset |= dev->needs_freset; | ||
467 | |||
468 | __eeh_set_pe_freset(dn, freset); | ||
469 | } | ||
470 | } | ||
471 | } | ||
472 | |||
473 | void eeh_set_pe_freset(struct device_node *dn, unsigned int *freset) | ||
474 | { | ||
475 | struct pci_dev *dev; | ||
476 | dn = find_device_pe(dn); | ||
477 | |||
478 | /* Back up one, since config addrs might be shared */ | ||
479 | if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent)) | ||
480 | dn = dn->parent; | ||
481 | |||
482 | dev = PCI_DN(dn)->pcidev; | ||
483 | if (dev) | ||
484 | *freset |= dev->needs_freset; | ||
485 | |||
486 | __eeh_set_pe_freset(dn, freset); | ||
487 | } | ||
488 | |||
489 | /** | 380 | /** |
490 | * eeh_dn_check_failure - check if all 1's data is due to EEH slot freeze | 381 | * eeh_dn_check_failure - Check if all 1's data is due to EEH slot freeze |
491 | * @dn device node | 382 | * @dn: device node |
492 | * @dev pci device, if known | 383 | * @dev: pci device, if known |
493 | * | 384 | * |
494 | * Check for an EEH failure for the given device node. Call this | 385 | * Check for an EEH failure for the given device node. Call this |
495 | * routine if the result of a read was all 0xff's and you want to | 386 | * routine if the result of a read was all 0xff's and you want to |
@@ -504,35 +395,34 @@ void eeh_set_pe_freset(struct device_node *dn, unsigned int *freset) | |||
504 | int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) | 395 | int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) |
505 | { | 396 | { |
506 | int ret; | 397 | int ret; |
507 | int rets[3]; | ||
508 | unsigned long flags; | 398 | unsigned long flags; |
509 | struct pci_dn *pdn; | 399 | struct eeh_dev *edev; |
510 | int rc = 0; | 400 | int rc = 0; |
511 | const char *location; | 401 | const char *location; |
512 | 402 | ||
513 | total_mmio_ffs++; | 403 | eeh_stats.total_mmio_ffs++; |
514 | 404 | ||
515 | if (!eeh_subsystem_enabled) | 405 | if (!eeh_subsystem_enabled) |
516 | return 0; | 406 | return 0; |
517 | 407 | ||
518 | if (!dn) { | 408 | if (!dn) { |
519 | no_dn++; | 409 | eeh_stats.no_dn++; |
520 | return 0; | 410 | return 0; |
521 | } | 411 | } |
522 | dn = find_device_pe(dn); | 412 | dn = eeh_find_device_pe(dn); |
523 | pdn = PCI_DN(dn); | 413 | edev = of_node_to_eeh_dev(dn); |
524 | 414 | ||
525 | /* Access to IO BARs might get this far and still not want checking. */ | 415 | /* Access to IO BARs might get this far and still not want checking. */ |
526 | if (!(pdn->eeh_mode & EEH_MODE_SUPPORTED) || | 416 | if (!(edev->mode & EEH_MODE_SUPPORTED) || |
527 | pdn->eeh_mode & EEH_MODE_NOCHECK) { | 417 | edev->mode & EEH_MODE_NOCHECK) { |
528 | ignored_check++; | 418 | eeh_stats.ignored_check++; |
529 | pr_debug("EEH: Ignored check (%x) for %s %s\n", | 419 | pr_debug("EEH: Ignored check (%x) for %s %s\n", |
530 | pdn->eeh_mode, eeh_pci_name(dev), dn->full_name); | 420 | edev->mode, eeh_pci_name(dev), dn->full_name); |
531 | return 0; | 421 | return 0; |
532 | } | 422 | } |
533 | 423 | ||
534 | if (!pdn->eeh_config_addr && !pdn->eeh_pe_config_addr) { | 424 | if (!edev->config_addr && !edev->pe_config_addr) { |
535 | no_cfg_addr++; | 425 | eeh_stats.no_cfg_addr++; |
536 | return 0; | 426 | return 0; |
537 | } | 427 | } |
538 | 428 | ||
@@ -544,15 +434,15 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) | |||
544 | */ | 434 | */ |
545 | raw_spin_lock_irqsave(&confirm_error_lock, flags); | 435 | raw_spin_lock_irqsave(&confirm_error_lock, flags); |
546 | rc = 1; | 436 | rc = 1; |
547 | if (pdn->eeh_mode & EEH_MODE_ISOLATED) { | 437 | if (edev->mode & EEH_MODE_ISOLATED) { |
548 | pdn->eeh_check_count ++; | 438 | edev->check_count++; |
549 | if (pdn->eeh_check_count % EEH_MAX_FAILS == 0) { | 439 | if (edev->check_count % EEH_MAX_FAILS == 0) { |
550 | location = of_get_property(dn, "ibm,loc-code", NULL); | 440 | location = of_get_property(dn, "ibm,loc-code", NULL); |
551 | printk (KERN_ERR "EEH: %d reads ignored for recovering device at " | 441 | printk(KERN_ERR "EEH: %d reads ignored for recovering device at " |
552 | "location=%s driver=%s pci addr=%s\n", | 442 | "location=%s driver=%s pci addr=%s\n", |
553 | pdn->eeh_check_count, location, | 443 | edev->check_count, location, |
554 | eeh_driver_name(dev), eeh_pci_name(dev)); | 444 | eeh_driver_name(dev), eeh_pci_name(dev)); |
555 | printk (KERN_ERR "EEH: Might be infinite loop in %s driver\n", | 445 | printk(KERN_ERR "EEH: Might be infinite loop in %s driver\n", |
556 | eeh_driver_name(dev)); | 446 | eeh_driver_name(dev)); |
557 | dump_stack(); | 447 | dump_stack(); |
558 | } | 448 | } |
@@ -566,58 +456,39 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) | |||
566 | * function zero of a multi-function device. | 456 | * function zero of a multi-function device. |
567 | * In any case they must share a common PHB. | 457 | * In any case they must share a common PHB. |
568 | */ | 458 | */ |
569 | ret = read_slot_reset_state(pdn, rets); | 459 | ret = eeh_ops->get_state(dn, NULL); |
570 | |||
571 | /* If the call to firmware failed, punt */ | ||
572 | if (ret != 0) { | ||
573 | printk(KERN_WARNING "EEH: read_slot_reset_state() failed; rc=%d dn=%s\n", | ||
574 | ret, dn->full_name); | ||
575 | false_positives++; | ||
576 | pdn->eeh_false_positives ++; | ||
577 | rc = 0; | ||
578 | goto dn_unlock; | ||
579 | } | ||
580 | 460 | ||
581 | /* Note that config-io to empty slots may fail; | 461 | /* Note that config-io to empty slots may fail; |
582 | * they are empty when they don't have children. */ | 462 | * they are empty when they don't have children. |
583 | if ((rets[0] == 5) && (rets[2] == 0) && (dn->child == NULL)) { | 463 | * We will punt with the following conditions: Failure to get |
584 | false_positives++; | 464 | * PE's state, EEH not support and Permanently unavailable |
585 | pdn->eeh_false_positives ++; | 465 | * state, PE is in good state. |
586 | rc = 0; | 466 | */ |
587 | goto dn_unlock; | 467 | if ((ret < 0) || |
588 | } | 468 | (ret == EEH_STATE_NOT_SUPPORT) || |
589 | 469 | (ret & (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) == | |
590 | /* If EEH is not supported on this device, punt. */ | 470 | (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) { |
591 | if (rets[1] != 1) { | 471 | eeh_stats.false_positives++; |
592 | printk(KERN_WARNING "EEH: event on unsupported device, rc=%d dn=%s\n", | 472 | edev->false_positives ++; |
593 | ret, dn->full_name); | ||
594 | false_positives++; | ||
595 | pdn->eeh_false_positives ++; | ||
596 | rc = 0; | ||
597 | goto dn_unlock; | ||
598 | } | ||
599 | |||
600 | /* If not the kind of error we know about, punt. */ | ||
601 | if (rets[0] != 1 && rets[0] != 2 && rets[0] != 4 && rets[0] != 5) { | ||
602 | false_positives++; | ||
603 | pdn->eeh_false_positives ++; | ||
604 | rc = 0; | 473 | rc = 0; |
605 | goto dn_unlock; | 474 | goto dn_unlock; |
606 | } | 475 | } |
607 | 476 | ||
608 | slot_resets++; | 477 | eeh_stats.slot_resets++; |
609 | 478 | ||
610 | /* Avoid repeated reports of this failure, including problems | 479 | /* Avoid repeated reports of this failure, including problems |
611 | * with other functions on this device, and functions under | 480 | * with other functions on this device, and functions under |
612 | * bridges. */ | 481 | * bridges. |
613 | eeh_mark_slot (dn, EEH_MODE_ISOLATED); | 482 | */ |
483 | eeh_mark_slot(dn, EEH_MODE_ISOLATED); | ||
614 | raw_spin_unlock_irqrestore(&confirm_error_lock, flags); | 484 | raw_spin_unlock_irqrestore(&confirm_error_lock, flags); |
615 | 485 | ||
616 | eeh_send_failure_event (dn, dev); | 486 | eeh_send_failure_event(edev); |
617 | 487 | ||
618 | /* Most EEH events are due to device driver bugs. Having | 488 | /* Most EEH events are due to device driver bugs. Having |
619 | * a stack trace will help the device-driver authors figure | 489 | * a stack trace will help the device-driver authors figure |
620 | * out what happened. So print that out. */ | 490 | * out what happened. So print that out. |
491 | */ | ||
621 | dump_stack(); | 492 | dump_stack(); |
622 | return 1; | 493 | return 1; |
623 | 494 | ||
@@ -629,9 +500,9 @@ dn_unlock: | |||
629 | EXPORT_SYMBOL_GPL(eeh_dn_check_failure); | 500 | EXPORT_SYMBOL_GPL(eeh_dn_check_failure); |
630 | 501 | ||
631 | /** | 502 | /** |
632 | * eeh_check_failure - check if all 1's data is due to EEH slot freeze | 503 | * eeh_check_failure - Check if all 1's data is due to EEH slot freeze |
633 | * @token i/o token, should be address in the form 0xA.... | 504 | * @token: I/O token, should be address in the form 0xA.... |
634 | * @val value, should be all 1's (XXX why do we need this arg??) | 505 | * @val: value, should be all 1's (XXX why do we need this arg??) |
635 | * | 506 | * |
636 | * Check for an EEH failure at the given token address. Call this | 507 | * Check for an EEH failure at the given token address. Call this |
637 | * routine if the result of a read was all 0xff's and you want to | 508 | * routine if the result of a read was all 0xff's and you want to |
@@ -648,14 +519,14 @@ unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned lon | |||
648 | 519 | ||
649 | /* Finding the phys addr + pci device; this is pretty quick. */ | 520 | /* Finding the phys addr + pci device; this is pretty quick. */ |
650 | addr = eeh_token_to_phys((unsigned long __force) token); | 521 | addr = eeh_token_to_phys((unsigned long __force) token); |
651 | dev = pci_get_device_by_addr(addr); | 522 | dev = pci_addr_cache_get_device(addr); |
652 | if (!dev) { | 523 | if (!dev) { |
653 | no_device++; | 524 | eeh_stats.no_device++; |
654 | return val; | 525 | return val; |
655 | } | 526 | } |
656 | 527 | ||
657 | dn = pci_device_to_OF_node(dev); | 528 | dn = pci_device_to_OF_node(dev); |
658 | eeh_dn_check_failure (dn, dev); | 529 | eeh_dn_check_failure(dn, dev); |
659 | 530 | ||
660 | pci_dev_put(dev); | 531 | pci_dev_put(dev); |
661 | return val; | 532 | return val; |
@@ -663,115 +534,54 @@ unsigned long eeh_check_failure(const volatile void __iomem *token, unsigned lon | |||
663 | 534 | ||
664 | EXPORT_SYMBOL(eeh_check_failure); | 535 | EXPORT_SYMBOL(eeh_check_failure); |
665 | 536 | ||
666 | /* ------------------------------------------------------------- */ | ||
667 | /* The code below deals with error recovery */ | ||
668 | 537 | ||
669 | /** | 538 | /** |
670 | * rtas_pci_enable - enable MMIO or DMA transfers for this slot | 539 | * eeh_pci_enable - Enable MMIO or DMA transfers for this slot |
671 | * @pdn pci device node | 540 | * @edev: pci device node |
541 | * | ||
542 | * This routine should be called to reenable frozen MMIO or DMA | ||
543 | * so that it would work correctly again. It's useful while doing | ||
544 | * recovery or log collection on the indicated device. | ||
672 | */ | 545 | */ |
673 | 546 | int eeh_pci_enable(struct eeh_dev *edev, int function) | |
674 | int | ||
675 | rtas_pci_enable(struct pci_dn *pdn, int function) | ||
676 | { | 547 | { |
677 | int config_addr; | ||
678 | int rc; | 548 | int rc; |
549 | struct device_node *dn = eeh_dev_to_of_node(edev); | ||
679 | 550 | ||
680 | /* Use PE configuration address, if present */ | 551 | rc = eeh_ops->set_option(dn, function); |
681 | config_addr = pdn->eeh_config_addr; | ||
682 | if (pdn->eeh_pe_config_addr) | ||
683 | config_addr = pdn->eeh_pe_config_addr; | ||
684 | |||
685 | rc = rtas_call(ibm_set_eeh_option, 4, 1, NULL, | ||
686 | config_addr, | ||
687 | BUID_HI(pdn->phb->buid), | ||
688 | BUID_LO(pdn->phb->buid), | ||
689 | function); | ||
690 | |||
691 | if (rc) | 552 | if (rc) |
692 | printk(KERN_WARNING "EEH: Unexpected state change %d, err=%d dn=%s\n", | 553 | printk(KERN_WARNING "EEH: Unexpected state change %d, err=%d dn=%s\n", |
693 | function, rc, pdn->node->full_name); | 554 | function, rc, dn->full_name); |
694 | 555 | ||
695 | rc = eeh_wait_for_slot_status (pdn, PCI_BUS_RESET_WAIT_MSEC); | 556 | rc = eeh_ops->wait_state(dn, PCI_BUS_RESET_WAIT_MSEC); |
696 | if ((rc == 4) && (function == EEH_THAW_MMIO)) | 557 | if (rc > 0 && (rc & EEH_STATE_MMIO_ENABLED) && |
558 | (function == EEH_OPT_THAW_MMIO)) | ||
697 | return 0; | 559 | return 0; |
698 | 560 | ||
699 | return rc; | 561 | return rc; |
700 | } | 562 | } |
701 | 563 | ||
702 | /** | 564 | /** |
703 | * rtas_pci_slot_reset - raises/lowers the pci #RST line | ||
704 | * @pdn pci device node | ||
705 | * @state: 1/0 to raise/lower the #RST | ||
706 | * | ||
707 | * Clear the EEH-frozen condition on a slot. This routine | ||
708 | * asserts the PCI #RST line if the 'state' argument is '1', | ||
709 | * and drops the #RST line if 'state is '0'. This routine is | ||
710 | * safe to call in an interrupt context. | ||
711 | * | ||
712 | */ | ||
713 | |||
714 | static void | ||
715 | rtas_pci_slot_reset(struct pci_dn *pdn, int state) | ||
716 | { | ||
717 | int config_addr; | ||
718 | int rc; | ||
719 | |||
720 | BUG_ON (pdn==NULL); | ||
721 | |||
722 | if (!pdn->phb) { | ||
723 | printk (KERN_WARNING "EEH: in slot reset, device node %s has no phb\n", | ||
724 | pdn->node->full_name); | ||
725 | return; | ||
726 | } | ||
727 | |||
728 | /* Use PE configuration address, if present */ | ||
729 | config_addr = pdn->eeh_config_addr; | ||
730 | if (pdn->eeh_pe_config_addr) | ||
731 | config_addr = pdn->eeh_pe_config_addr; | ||
732 | |||
733 | rc = rtas_call(ibm_set_slot_reset, 4, 1, NULL, | ||
734 | config_addr, | ||
735 | BUID_HI(pdn->phb->buid), | ||
736 | BUID_LO(pdn->phb->buid), | ||
737 | state); | ||
738 | |||
739 | /* Fundamental-reset not supported on this PE, try hot-reset */ | ||
740 | if (rc == -8 && state == 3) { | ||
741 | rc = rtas_call(ibm_set_slot_reset, 4, 1, NULL, | ||
742 | config_addr, | ||
743 | BUID_HI(pdn->phb->buid), | ||
744 | BUID_LO(pdn->phb->buid), 1); | ||
745 | if (rc) | ||
746 | printk(KERN_WARNING | ||
747 | "EEH: Unable to reset the failed slot," | ||
748 | " #RST=%d dn=%s\n", | ||
749 | rc, pdn->node->full_name); | ||
750 | } | ||
751 | } | ||
752 | |||
753 | /** | ||
754 | * pcibios_set_pcie_slot_reset - Set PCI-E reset state | 565 | * pcibios_set_pcie_slot_reset - Set PCI-E reset state |
755 | * @dev: pci device struct | 566 | * @dev: pci device struct |
756 | * @state: reset state to enter | 567 | * @state: reset state to enter |
757 | * | 568 | * |
758 | * Return value: | 569 | * Return value: |
759 | * 0 if success | 570 | * 0 if success |
760 | **/ | 571 | */ |
761 | int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state) | 572 | int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state) |
762 | { | 573 | { |
763 | struct device_node *dn = pci_device_to_OF_node(dev); | 574 | struct device_node *dn = pci_device_to_OF_node(dev); |
764 | struct pci_dn *pdn = PCI_DN(dn); | ||
765 | 575 | ||
766 | switch (state) { | 576 | switch (state) { |
767 | case pcie_deassert_reset: | 577 | case pcie_deassert_reset: |
768 | rtas_pci_slot_reset(pdn, 0); | 578 | eeh_ops->reset(dn, EEH_RESET_DEACTIVATE); |
769 | break; | 579 | break; |
770 | case pcie_hot_reset: | 580 | case pcie_hot_reset: |
771 | rtas_pci_slot_reset(pdn, 1); | 581 | eeh_ops->reset(dn, EEH_RESET_HOT); |
772 | break; | 582 | break; |
773 | case pcie_warm_reset: | 583 | case pcie_warm_reset: |
774 | rtas_pci_slot_reset(pdn, 3); | 584 | eeh_ops->reset(dn, EEH_RESET_FUNDAMENTAL); |
775 | break; | 585 | break; |
776 | default: | 586 | default: |
777 | return -EINVAL; | 587 | return -EINVAL; |
@@ -781,13 +591,66 @@ int pcibios_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state stat | |||
781 | } | 591 | } |
782 | 592 | ||
783 | /** | 593 | /** |
784 | * rtas_set_slot_reset -- assert the pci #RST line for 1/4 second | 594 | * __eeh_set_pe_freset - Check the required reset for child devices |
785 | * @pdn: pci device node to be reset. | 595 | * @parent: parent device |
596 | * @freset: return value | ||
597 | * | ||
598 | * Each device might have its preferred reset type: fundamental or | ||
599 | * hot reset. The routine is used to collect the information from | ||
600 | * the child devices so that they could be reset accordingly. | ||
601 | */ | ||
602 | void __eeh_set_pe_freset(struct device_node *parent, unsigned int *freset) | ||
603 | { | ||
604 | struct device_node *dn; | ||
605 | |||
606 | for_each_child_of_node(parent, dn) { | ||
607 | if (of_node_to_eeh_dev(dn)) { | ||
608 | struct pci_dev *dev = of_node_to_eeh_dev(dn)->pdev; | ||
609 | |||
610 | if (dev && dev->driver) | ||
611 | *freset |= dev->needs_freset; | ||
612 | |||
613 | __eeh_set_pe_freset(dn, freset); | ||
614 | } | ||
615 | } | ||
616 | } | ||
617 | |||
618 | /** | ||
619 | * eeh_set_pe_freset - Check the required reset for the indicated device and its children | ||
620 | * @dn: parent device | ||
621 | * @freset: return value | ||
622 | * | ||
623 | * Each device might have its preferred reset type: fundamental or | ||
624 | * hot reset. The routine is used to collected the information for | ||
625 | * the indicated device and its children so that the bunch of the | ||
626 | * devices could be reset properly. | ||
786 | */ | 627 | */ |
628 | void eeh_set_pe_freset(struct device_node *dn, unsigned int *freset) | ||
629 | { | ||
630 | struct pci_dev *dev; | ||
631 | dn = eeh_find_device_pe(dn); | ||
632 | |||
633 | /* Back up one, since config addrs might be shared */ | ||
634 | if (!pcibios_find_pci_bus(dn) && of_node_to_eeh_dev(dn->parent)) | ||
635 | dn = dn->parent; | ||
636 | |||
637 | dev = of_node_to_eeh_dev(dn)->pdev; | ||
638 | if (dev) | ||
639 | *freset |= dev->needs_freset; | ||
787 | 640 | ||
788 | static void __rtas_set_slot_reset(struct pci_dn *pdn) | 641 | __eeh_set_pe_freset(dn, freset); |
642 | } | ||
643 | |||
644 | /** | ||
645 | * eeh_reset_pe_once - Assert the pci #RST line for 1/4 second | ||
646 | * @edev: pci device node to be reset. | ||
647 | * | ||
648 | * Assert the PCI #RST line for 1/4 second. | ||
649 | */ | ||
650 | static void eeh_reset_pe_once(struct eeh_dev *edev) | ||
789 | { | 651 | { |
790 | unsigned int freset = 0; | 652 | unsigned int freset = 0; |
653 | struct device_node *dn = eeh_dev_to_of_node(edev); | ||
791 | 654 | ||
792 | /* Determine type of EEH reset required for | 655 | /* Determine type of EEH reset required for |
793 | * Partitionable Endpoint, a hot-reset (1) | 656 | * Partitionable Endpoint, a hot-reset (1) |
@@ -795,58 +658,68 @@ static void __rtas_set_slot_reset(struct pci_dn *pdn) | |||
795 | * A fundamental reset required by any device under | 658 | * A fundamental reset required by any device under |
796 | * Partitionable Endpoint trumps hot-reset. | 659 | * Partitionable Endpoint trumps hot-reset. |
797 | */ | 660 | */ |
798 | eeh_set_pe_freset(pdn->node, &freset); | 661 | eeh_set_pe_freset(dn, &freset); |
799 | 662 | ||
800 | if (freset) | 663 | if (freset) |
801 | rtas_pci_slot_reset(pdn, 3); | 664 | eeh_ops->reset(dn, EEH_RESET_FUNDAMENTAL); |
802 | else | 665 | else |
803 | rtas_pci_slot_reset(pdn, 1); | 666 | eeh_ops->reset(dn, EEH_RESET_HOT); |
804 | 667 | ||
805 | /* The PCI bus requires that the reset be held high for at least | 668 | /* The PCI bus requires that the reset be held high for at least |
806 | * a 100 milliseconds. We wait a bit longer 'just in case'. */ | 669 | * a 100 milliseconds. We wait a bit longer 'just in case'. |
807 | 670 | */ | |
808 | #define PCI_BUS_RST_HOLD_TIME_MSEC 250 | 671 | #define PCI_BUS_RST_HOLD_TIME_MSEC 250 |
809 | msleep (PCI_BUS_RST_HOLD_TIME_MSEC); | 672 | msleep(PCI_BUS_RST_HOLD_TIME_MSEC); |
810 | 673 | ||
811 | /* We might get hit with another EEH freeze as soon as the | 674 | /* We might get hit with another EEH freeze as soon as the |
812 | * pci slot reset line is dropped. Make sure we don't miss | 675 | * pci slot reset line is dropped. Make sure we don't miss |
813 | * these, and clear the flag now. */ | 676 | * these, and clear the flag now. |
814 | eeh_clear_slot (pdn->node, EEH_MODE_ISOLATED); | 677 | */ |
678 | eeh_clear_slot(dn, EEH_MODE_ISOLATED); | ||
815 | 679 | ||
816 | rtas_pci_slot_reset (pdn, 0); | 680 | eeh_ops->reset(dn, EEH_RESET_DEACTIVATE); |
817 | 681 | ||
818 | /* After a PCI slot has been reset, the PCI Express spec requires | 682 | /* After a PCI slot has been reset, the PCI Express spec requires |
819 | * a 1.5 second idle time for the bus to stabilize, before starting | 683 | * a 1.5 second idle time for the bus to stabilize, before starting |
820 | * up traffic. */ | 684 | * up traffic. |
685 | */ | ||
821 | #define PCI_BUS_SETTLE_TIME_MSEC 1800 | 686 | #define PCI_BUS_SETTLE_TIME_MSEC 1800 |
822 | msleep (PCI_BUS_SETTLE_TIME_MSEC); | 687 | msleep(PCI_BUS_SETTLE_TIME_MSEC); |
823 | } | 688 | } |
824 | 689 | ||
825 | int rtas_set_slot_reset(struct pci_dn *pdn) | 690 | /** |
691 | * eeh_reset_pe - Reset the indicated PE | ||
692 | * @edev: PCI device associated EEH device | ||
693 | * | ||
694 | * This routine should be called to reset indicated device, including | ||
695 | * PE. A PE might include multiple PCI devices and sometimes PCI bridges | ||
696 | * might be involved as well. | ||
697 | */ | ||
698 | int eeh_reset_pe(struct eeh_dev *edev) | ||
826 | { | 699 | { |
827 | int i, rc; | 700 | int i, rc; |
701 | struct device_node *dn = eeh_dev_to_of_node(edev); | ||
828 | 702 | ||
829 | /* Take three shots at resetting the bus */ | 703 | /* Take three shots at resetting the bus */ |
830 | for (i=0; i<3; i++) { | 704 | for (i=0; i<3; i++) { |
831 | __rtas_set_slot_reset(pdn); | 705 | eeh_reset_pe_once(edev); |
832 | 706 | ||
833 | rc = eeh_wait_for_slot_status(pdn, PCI_BUS_RESET_WAIT_MSEC); | 707 | rc = eeh_ops->wait_state(dn, PCI_BUS_RESET_WAIT_MSEC); |
834 | if (rc == 0) | 708 | if (rc == (EEH_STATE_MMIO_ACTIVE | EEH_STATE_DMA_ACTIVE)) |
835 | return 0; | 709 | return 0; |
836 | 710 | ||
837 | if (rc < 0) { | 711 | if (rc < 0) { |
838 | printk(KERN_ERR "EEH: unrecoverable slot failure %s\n", | 712 | printk(KERN_ERR "EEH: unrecoverable slot failure %s\n", |
839 | pdn->node->full_name); | 713 | dn->full_name); |
840 | return -1; | 714 | return -1; |
841 | } | 715 | } |
842 | printk(KERN_ERR "EEH: bus reset %d failed on slot %s, rc=%d\n", | 716 | printk(KERN_ERR "EEH: bus reset %d failed on slot %s, rc=%d\n", |
843 | i+1, pdn->node->full_name, rc); | 717 | i+1, dn->full_name, rc); |
844 | } | 718 | } |
845 | 719 | ||
846 | return -1; | 720 | return -1; |
847 | } | 721 | } |
848 | 722 | ||
849 | /* ------------------------------------------------------- */ | ||
850 | /** Save and restore of PCI BARs | 723 | /** Save and restore of PCI BARs |
851 | * | 724 | * |
852 | * Although firmware will set up BARs during boot, it doesn't | 725 | * Although firmware will set up BARs during boot, it doesn't |
@@ -856,181 +729,122 @@ int rtas_set_slot_reset(struct pci_dn *pdn) | |||
856 | */ | 729 | */ |
857 | 730 | ||
858 | /** | 731 | /** |
859 | * __restore_bars - Restore the Base Address Registers | 732 | * eeh_restore_one_device_bars - Restore the Base Address Registers for one device |
860 | * @pdn: pci device node | 733 | * @edev: PCI device associated EEH device |
861 | * | 734 | * |
862 | * Loads the PCI configuration space base address registers, | 735 | * Loads the PCI configuration space base address registers, |
863 | * the expansion ROM base address, the latency timer, and etc. | 736 | * the expansion ROM base address, the latency timer, and etc. |
864 | * from the saved values in the device node. | 737 | * from the saved values in the device node. |
865 | */ | 738 | */ |
866 | static inline void __restore_bars (struct pci_dn *pdn) | 739 | static inline void eeh_restore_one_device_bars(struct eeh_dev *edev) |
867 | { | 740 | { |
868 | int i; | 741 | int i; |
869 | u32 cmd; | 742 | u32 cmd; |
743 | struct device_node *dn = eeh_dev_to_of_node(edev); | ||
744 | |||
745 | if (!edev->phb) | ||
746 | return; | ||
870 | 747 | ||
871 | if (NULL==pdn->phb) return; | ||
872 | for (i=4; i<10; i++) { | 748 | for (i=4; i<10; i++) { |
873 | rtas_write_config(pdn, i*4, 4, pdn->config_space[i]); | 749 | eeh_ops->write_config(dn, i*4, 4, edev->config_space[i]); |
874 | } | 750 | } |
875 | 751 | ||
876 | /* 12 == Expansion ROM Address */ | 752 | /* 12 == Expansion ROM Address */ |
877 | rtas_write_config(pdn, 12*4, 4, pdn->config_space[12]); | 753 | eeh_ops->write_config(dn, 12*4, 4, edev->config_space[12]); |
878 | 754 | ||
879 | #define BYTE_SWAP(OFF) (8*((OFF)/4)+3-(OFF)) | 755 | #define BYTE_SWAP(OFF) (8*((OFF)/4)+3-(OFF)) |
880 | #define SAVED_BYTE(OFF) (((u8 *)(pdn->config_space))[BYTE_SWAP(OFF)]) | 756 | #define SAVED_BYTE(OFF) (((u8 *)(edev->config_space))[BYTE_SWAP(OFF)]) |
881 | 757 | ||
882 | rtas_write_config (pdn, PCI_CACHE_LINE_SIZE, 1, | 758 | eeh_ops->write_config(dn, PCI_CACHE_LINE_SIZE, 1, |
883 | SAVED_BYTE(PCI_CACHE_LINE_SIZE)); | 759 | SAVED_BYTE(PCI_CACHE_LINE_SIZE)); |
884 | 760 | ||
885 | rtas_write_config (pdn, PCI_LATENCY_TIMER, 1, | 761 | eeh_ops->write_config(dn, PCI_LATENCY_TIMER, 1, |
886 | SAVED_BYTE(PCI_LATENCY_TIMER)); | 762 | SAVED_BYTE(PCI_LATENCY_TIMER)); |
887 | 763 | ||
888 | /* max latency, min grant, interrupt pin and line */ | 764 | /* max latency, min grant, interrupt pin and line */ |
889 | rtas_write_config(pdn, 15*4, 4, pdn->config_space[15]); | 765 | eeh_ops->write_config(dn, 15*4, 4, edev->config_space[15]); |
890 | 766 | ||
891 | /* Restore PERR & SERR bits, some devices require it, | 767 | /* Restore PERR & SERR bits, some devices require it, |
892 | don't touch the other command bits */ | 768 | * don't touch the other command bits |
893 | rtas_read_config(pdn, PCI_COMMAND, 4, &cmd); | 769 | */ |
894 | if (pdn->config_space[1] & PCI_COMMAND_PARITY) | 770 | eeh_ops->read_config(dn, PCI_COMMAND, 4, &cmd); |
771 | if (edev->config_space[1] & PCI_COMMAND_PARITY) | ||
895 | cmd |= PCI_COMMAND_PARITY; | 772 | cmd |= PCI_COMMAND_PARITY; |
896 | else | 773 | else |
897 | cmd &= ~PCI_COMMAND_PARITY; | 774 | cmd &= ~PCI_COMMAND_PARITY; |
898 | if (pdn->config_space[1] & PCI_COMMAND_SERR) | 775 | if (edev->config_space[1] & PCI_COMMAND_SERR) |
899 | cmd |= PCI_COMMAND_SERR; | 776 | cmd |= PCI_COMMAND_SERR; |
900 | else | 777 | else |
901 | cmd &= ~PCI_COMMAND_SERR; | 778 | cmd &= ~PCI_COMMAND_SERR; |
902 | rtas_write_config(pdn, PCI_COMMAND, 4, cmd); | 779 | eeh_ops->write_config(dn, PCI_COMMAND, 4, cmd); |
903 | } | 780 | } |
904 | 781 | ||
905 | /** | 782 | /** |
906 | * eeh_restore_bars - restore the PCI config space info | 783 | * eeh_restore_bars - Restore the PCI config space info |
784 | * @edev: EEH device | ||
907 | * | 785 | * |
908 | * This routine performs a recursive walk to the children | 786 | * This routine performs a recursive walk to the children |
909 | * of this device as well. | 787 | * of this device as well. |
910 | */ | 788 | */ |
911 | void eeh_restore_bars(struct pci_dn *pdn) | 789 | void eeh_restore_bars(struct eeh_dev *edev) |
912 | { | 790 | { |
913 | struct device_node *dn; | 791 | struct device_node *dn; |
914 | if (!pdn) | 792 | if (!edev) |
915 | return; | 793 | return; |
916 | 794 | ||
917 | if ((pdn->eeh_mode & EEH_MODE_SUPPORTED) && !IS_BRIDGE(pdn->class_code)) | 795 | if ((edev->mode & EEH_MODE_SUPPORTED) && !IS_BRIDGE(edev->class_code)) |
918 | __restore_bars (pdn); | 796 | eeh_restore_one_device_bars(edev); |
919 | 797 | ||
920 | for_each_child_of_node(pdn->node, dn) | 798 | for_each_child_of_node(eeh_dev_to_of_node(edev), dn) |
921 | eeh_restore_bars (PCI_DN(dn)); | 799 | eeh_restore_bars(of_node_to_eeh_dev(dn)); |
922 | } | 800 | } |
923 | 801 | ||
924 | /** | 802 | /** |
925 | * eeh_save_bars - save device bars | 803 | * eeh_save_bars - Save device bars |
804 | * @edev: PCI device associated EEH device | ||
926 | * | 805 | * |
927 | * Save the values of the device bars. Unlike the restore | 806 | * Save the values of the device bars. Unlike the restore |
928 | * routine, this routine is *not* recursive. This is because | 807 | * routine, this routine is *not* recursive. This is because |
929 | * PCI devices are added individually; but, for the restore, | 808 | * PCI devices are added individually; but, for the restore, |
930 | * an entire slot is reset at a time. | 809 | * an entire slot is reset at a time. |
931 | */ | 810 | */ |
932 | static void eeh_save_bars(struct pci_dn *pdn) | 811 | static void eeh_save_bars(struct eeh_dev *edev) |
933 | { | 812 | { |
934 | int i; | 813 | int i; |
814 | struct device_node *dn; | ||
935 | 815 | ||
936 | if (!pdn ) | 816 | if (!edev) |
937 | return; | 817 | return; |
818 | dn = eeh_dev_to_of_node(edev); | ||
938 | 819 | ||
939 | for (i = 0; i < 16; i++) | 820 | for (i = 0; i < 16; i++) |
940 | rtas_read_config(pdn, i * 4, 4, &pdn->config_space[i]); | 821 | eeh_ops->read_config(dn, i * 4, 4, &edev->config_space[i]); |
941 | } | ||
942 | |||
943 | void | ||
944 | rtas_configure_bridge(struct pci_dn *pdn) | ||
945 | { | ||
946 | int config_addr; | ||
947 | int rc; | ||
948 | int token; | ||
949 | |||
950 | /* Use PE configuration address, if present */ | ||
951 | config_addr = pdn->eeh_config_addr; | ||
952 | if (pdn->eeh_pe_config_addr) | ||
953 | config_addr = pdn->eeh_pe_config_addr; | ||
954 | |||
955 | /* Use new configure-pe function, if supported */ | ||
956 | if (ibm_configure_pe != RTAS_UNKNOWN_SERVICE) | ||
957 | token = ibm_configure_pe; | ||
958 | else | ||
959 | token = ibm_configure_bridge; | ||
960 | |||
961 | rc = rtas_call(token, 3, 1, NULL, | ||
962 | config_addr, | ||
963 | BUID_HI(pdn->phb->buid), | ||
964 | BUID_LO(pdn->phb->buid)); | ||
965 | if (rc) { | ||
966 | printk (KERN_WARNING "EEH: Unable to configure device bridge (%d) for %s\n", | ||
967 | rc, pdn->node->full_name); | ||
968 | } | ||
969 | } | 822 | } |
970 | 823 | ||
971 | /* ------------------------------------------------------------- */ | 824 | /** |
972 | /* The code below deals with enabling EEH for devices during the | 825 | * eeh_early_enable - Early enable EEH on the indicated device |
973 | * early boot sequence. EEH must be enabled before any PCI probing | 826 | * @dn: device node |
974 | * can be done. | 827 | * @data: BUID |
828 | * | ||
829 | * Enable EEH functionality on the specified PCI device. The function | ||
830 | * is expected to be called before real PCI probing is done. However, | ||
831 | * the PHBs have been initialized at this point. | ||
975 | */ | 832 | */ |
976 | 833 | static void *eeh_early_enable(struct device_node *dn, void *data) | |
977 | #define EEH_ENABLE 1 | ||
978 | |||
979 | struct eeh_early_enable_info { | ||
980 | unsigned int buid_hi; | ||
981 | unsigned int buid_lo; | ||
982 | }; | ||
983 | |||
984 | static int get_pe_addr (int config_addr, | ||
985 | struct eeh_early_enable_info *info) | ||
986 | { | 834 | { |
987 | unsigned int rets[3]; | ||
988 | int ret; | ||
989 | |||
990 | /* Use latest config-addr token on power6 */ | ||
991 | if (ibm_get_config_addr_info2 != RTAS_UNKNOWN_SERVICE) { | ||
992 | /* Make sure we have a PE in hand */ | ||
993 | ret = rtas_call (ibm_get_config_addr_info2, 4, 2, rets, | ||
994 | config_addr, info->buid_hi, info->buid_lo, 1); | ||
995 | if (ret || (rets[0]==0)) | ||
996 | return 0; | ||
997 | |||
998 | ret = rtas_call (ibm_get_config_addr_info2, 4, 2, rets, | ||
999 | config_addr, info->buid_hi, info->buid_lo, 0); | ||
1000 | if (ret) | ||
1001 | return 0; | ||
1002 | return rets[0]; | ||
1003 | } | ||
1004 | |||
1005 | /* Use older config-addr token on power5 */ | ||
1006 | if (ibm_get_config_addr_info != RTAS_UNKNOWN_SERVICE) { | ||
1007 | ret = rtas_call (ibm_get_config_addr_info, 4, 2, rets, | ||
1008 | config_addr, info->buid_hi, info->buid_lo, 0); | ||
1009 | if (ret) | ||
1010 | return 0; | ||
1011 | return rets[0]; | ||
1012 | } | ||
1013 | return 0; | ||
1014 | } | ||
1015 | |||
1016 | /* Enable eeh for the given device node. */ | ||
1017 | static void *early_enable_eeh(struct device_node *dn, void *data) | ||
1018 | { | ||
1019 | unsigned int rets[3]; | ||
1020 | struct eeh_early_enable_info *info = data; | ||
1021 | int ret; | 835 | int ret; |
1022 | const u32 *class_code = of_get_property(dn, "class-code", NULL); | 836 | const u32 *class_code = of_get_property(dn, "class-code", NULL); |
1023 | const u32 *vendor_id = of_get_property(dn, "vendor-id", NULL); | 837 | const u32 *vendor_id = of_get_property(dn, "vendor-id", NULL); |
1024 | const u32 *device_id = of_get_property(dn, "device-id", NULL); | 838 | const u32 *device_id = of_get_property(dn, "device-id", NULL); |
1025 | const u32 *regs; | 839 | const u32 *regs; |
1026 | int enable; | 840 | int enable; |
1027 | struct pci_dn *pdn = PCI_DN(dn); | 841 | struct eeh_dev *edev = of_node_to_eeh_dev(dn); |
1028 | 842 | ||
1029 | pdn->class_code = 0; | 843 | edev->class_code = 0; |
1030 | pdn->eeh_mode = 0; | 844 | edev->mode = 0; |
1031 | pdn->eeh_check_count = 0; | 845 | edev->check_count = 0; |
1032 | pdn->eeh_freeze_count = 0; | 846 | edev->freeze_count = 0; |
1033 | pdn->eeh_false_positives = 0; | 847 | edev->false_positives = 0; |
1034 | 848 | ||
1035 | if (!of_device_is_available(dn)) | 849 | if (!of_device_is_available(dn)) |
1036 | return NULL; | 850 | return NULL; |
@@ -1041,54 +855,56 @@ static void *early_enable_eeh(struct device_node *dn, void *data) | |||
1041 | 855 | ||
1042 | /* There is nothing to check on PCI to ISA bridges */ | 856 | /* There is nothing to check on PCI to ISA bridges */ |
1043 | if (dn->type && !strcmp(dn->type, "isa")) { | 857 | if (dn->type && !strcmp(dn->type, "isa")) { |
1044 | pdn->eeh_mode |= EEH_MODE_NOCHECK; | 858 | edev->mode |= EEH_MODE_NOCHECK; |
1045 | return NULL; | 859 | return NULL; |
1046 | } | 860 | } |
1047 | pdn->class_code = *class_code; | 861 | edev->class_code = *class_code; |
1048 | 862 | ||
1049 | /* Ok... see if this device supports EEH. Some do, some don't, | 863 | /* Ok... see if this device supports EEH. Some do, some don't, |
1050 | * and the only way to find out is to check each and every one. */ | 864 | * and the only way to find out is to check each and every one. |
865 | */ | ||
1051 | regs = of_get_property(dn, "reg", NULL); | 866 | regs = of_get_property(dn, "reg", NULL); |
1052 | if (regs) { | 867 | if (regs) { |
1053 | /* First register entry is addr (00BBSS00) */ | 868 | /* First register entry is addr (00BBSS00) */ |
1054 | /* Try to enable eeh */ | 869 | /* Try to enable eeh */ |
1055 | ret = rtas_call(ibm_set_eeh_option, 4, 1, NULL, | 870 | ret = eeh_ops->set_option(dn, EEH_OPT_ENABLE); |
1056 | regs[0], info->buid_hi, info->buid_lo, | ||
1057 | EEH_ENABLE); | ||
1058 | 871 | ||
1059 | enable = 0; | 872 | enable = 0; |
1060 | if (ret == 0) { | 873 | if (ret == 0) { |
1061 | pdn->eeh_config_addr = regs[0]; | 874 | edev->config_addr = regs[0]; |
1062 | 875 | ||
1063 | /* If the newer, better, ibm,get-config-addr-info is supported, | 876 | /* If the newer, better, ibm,get-config-addr-info is supported, |
1064 | * then use that instead. */ | 877 | * then use that instead. |
1065 | pdn->eeh_pe_config_addr = get_pe_addr(pdn->eeh_config_addr, info); | 878 | */ |
879 | edev->pe_config_addr = eeh_ops->get_pe_addr(dn); | ||
1066 | 880 | ||
1067 | /* Some older systems (Power4) allow the | 881 | /* Some older systems (Power4) allow the |
1068 | * ibm,set-eeh-option call to succeed even on nodes | 882 | * ibm,set-eeh-option call to succeed even on nodes |
1069 | * where EEH is not supported. Verify support | 883 | * where EEH is not supported. Verify support |
1070 | * explicitly. */ | 884 | * explicitly. |
1071 | ret = read_slot_reset_state(pdn, rets); | 885 | */ |
1072 | if ((ret == 0) && (rets[1] == 1)) | 886 | ret = eeh_ops->get_state(dn, NULL); |
887 | if (ret > 0 && ret != EEH_STATE_NOT_SUPPORT) | ||
1073 | enable = 1; | 888 | enable = 1; |
1074 | } | 889 | } |
1075 | 890 | ||
1076 | if (enable) { | 891 | if (enable) { |
1077 | eeh_subsystem_enabled = 1; | 892 | eeh_subsystem_enabled = 1; |
1078 | pdn->eeh_mode |= EEH_MODE_SUPPORTED; | 893 | edev->mode |= EEH_MODE_SUPPORTED; |
1079 | 894 | ||
1080 | pr_debug("EEH: %s: eeh enabled, config=%x pe_config=%x\n", | 895 | pr_debug("EEH: %s: eeh enabled, config=%x pe_config=%x\n", |
1081 | dn->full_name, pdn->eeh_config_addr, | 896 | dn->full_name, edev->config_addr, |
1082 | pdn->eeh_pe_config_addr); | 897 | edev->pe_config_addr); |
1083 | } else { | 898 | } else { |
1084 | 899 | ||
1085 | /* This device doesn't support EEH, but it may have an | 900 | /* This device doesn't support EEH, but it may have an |
1086 | * EEH parent, in which case we mark it as supported. */ | 901 | * EEH parent, in which case we mark it as supported. |
1087 | if (dn->parent && PCI_DN(dn->parent) | 902 | */ |
1088 | && (PCI_DN(dn->parent)->eeh_mode & EEH_MODE_SUPPORTED)) { | 903 | if (dn->parent && of_node_to_eeh_dev(dn->parent) && |
904 | (of_node_to_eeh_dev(dn->parent)->mode & EEH_MODE_SUPPORTED)) { | ||
1089 | /* Parent supports EEH. */ | 905 | /* Parent supports EEH. */ |
1090 | pdn->eeh_mode |= EEH_MODE_SUPPORTED; | 906 | edev->mode |= EEH_MODE_SUPPORTED; |
1091 | pdn->eeh_config_addr = PCI_DN(dn->parent)->eeh_config_addr; | 907 | edev->config_addr = of_node_to_eeh_dev(dn->parent)->config_addr; |
1092 | return NULL; | 908 | return NULL; |
1093 | } | 909 | } |
1094 | } | 910 | } |
@@ -1097,11 +913,63 @@ static void *early_enable_eeh(struct device_node *dn, void *data) | |||
1097 | dn->full_name); | 913 | dn->full_name); |
1098 | } | 914 | } |
1099 | 915 | ||
1100 | eeh_save_bars(pdn); | 916 | eeh_save_bars(edev); |
1101 | return NULL; | 917 | return NULL; |
1102 | } | 918 | } |
1103 | 919 | ||
1104 | /* | 920 | /** |
921 | * eeh_ops_register - Register platform dependent EEH operations | ||
922 | * @ops: platform dependent EEH operations | ||
923 | * | ||
924 | * Register the platform dependent EEH operation callback | ||
925 | * functions. The platform should call this function before | ||
926 | * any other EEH operations. | ||
927 | */ | ||
928 | int __init eeh_ops_register(struct eeh_ops *ops) | ||
929 | { | ||
930 | if (!ops->name) { | ||
931 | pr_warning("%s: Invalid EEH ops name for %p\n", | ||
932 | __func__, ops); | ||
933 | return -EINVAL; | ||
934 | } | ||
935 | |||
936 | if (eeh_ops && eeh_ops != ops) { | ||
937 | pr_warning("%s: EEH ops of platform %s already existing (%s)\n", | ||
938 | __func__, eeh_ops->name, ops->name); | ||
939 | return -EEXIST; | ||
940 | } | ||
941 | |||
942 | eeh_ops = ops; | ||
943 | |||
944 | return 0; | ||
945 | } | ||
946 | |||
947 | /** | ||
948 | * eeh_ops_unregister - Unreigster platform dependent EEH operations | ||
949 | * @name: name of EEH platform operations | ||
950 | * | ||
951 | * Unregister the platform dependent EEH operation callback | ||
952 | * functions. | ||
953 | */ | ||
954 | int __exit eeh_ops_unregister(const char *name) | ||
955 | { | ||
956 | if (!name || !strlen(name)) { | ||
957 | pr_warning("%s: Invalid EEH ops name\n", | ||
958 | __func__); | ||
959 | return -EINVAL; | ||
960 | } | ||
961 | |||
962 | if (eeh_ops && !strcmp(eeh_ops->name, name)) { | ||
963 | eeh_ops = NULL; | ||
964 | return 0; | ||
965 | } | ||
966 | |||
967 | return -EEXIST; | ||
968 | } | ||
969 | |||
970 | /** | ||
971 | * eeh_init - EEH initialization | ||
972 | * | ||
1105 | * Initialize EEH by trying to enable it for all of the adapters in the system. | 973 | * Initialize EEH by trying to enable it for all of the adapters in the system. |
1106 | * As a side effect we can determine here if eeh is supported at all. | 974 | * As a side effect we can determine here if eeh is supported at all. |
1107 | * Note that we leave EEH on so failed config cycles won't cause a machine | 975 | * Note that we leave EEH on so failed config cycles won't cause a machine |
@@ -1117,50 +985,35 @@ static void *early_enable_eeh(struct device_node *dn, void *data) | |||
1117 | void __init eeh_init(void) | 985 | void __init eeh_init(void) |
1118 | { | 986 | { |
1119 | struct device_node *phb, *np; | 987 | struct device_node *phb, *np; |
1120 | struct eeh_early_enable_info info; | 988 | int ret; |
989 | |||
990 | /* call platform initialization function */ | ||
991 | if (!eeh_ops) { | ||
992 | pr_warning("%s: Platform EEH operation not found\n", | ||
993 | __func__); | ||
994 | return; | ||
995 | } else if ((ret = eeh_ops->init())) { | ||
996 | pr_warning("%s: Failed to call platform init function (%d)\n", | ||
997 | __func__, ret); | ||
998 | return; | ||
999 | } | ||
1121 | 1000 | ||
1122 | raw_spin_lock_init(&confirm_error_lock); | 1001 | raw_spin_lock_init(&confirm_error_lock); |
1123 | spin_lock_init(&slot_errbuf_lock); | ||
1124 | 1002 | ||
1125 | np = of_find_node_by_path("/rtas"); | 1003 | np = of_find_node_by_path("/rtas"); |
1126 | if (np == NULL) | 1004 | if (np == NULL) |
1127 | return; | 1005 | return; |
1128 | 1006 | ||
1129 | ibm_set_eeh_option = rtas_token("ibm,set-eeh-option"); | ||
1130 | ibm_set_slot_reset = rtas_token("ibm,set-slot-reset"); | ||
1131 | ibm_read_slot_reset_state2 = rtas_token("ibm,read-slot-reset-state2"); | ||
1132 | ibm_read_slot_reset_state = rtas_token("ibm,read-slot-reset-state"); | ||
1133 | ibm_slot_error_detail = rtas_token("ibm,slot-error-detail"); | ||
1134 | ibm_get_config_addr_info = rtas_token("ibm,get-config-addr-info"); | ||
1135 | ibm_get_config_addr_info2 = rtas_token("ibm,get-config-addr-info2"); | ||
1136 | ibm_configure_bridge = rtas_token ("ibm,configure-bridge"); | ||
1137 | ibm_configure_pe = rtas_token("ibm,configure-pe"); | ||
1138 | |||
1139 | if (ibm_set_eeh_option == RTAS_UNKNOWN_SERVICE) | ||
1140 | return; | ||
1141 | |||
1142 | eeh_error_buf_size = rtas_token("rtas-error-log-max"); | ||
1143 | if (eeh_error_buf_size == RTAS_UNKNOWN_SERVICE) { | ||
1144 | eeh_error_buf_size = 1024; | ||
1145 | } | ||
1146 | if (eeh_error_buf_size > RTAS_ERROR_LOG_MAX) { | ||
1147 | printk(KERN_WARNING "EEH: rtas-error-log-max is bigger than allocated " | ||
1148 | "buffer ! (%d vs %d)", eeh_error_buf_size, RTAS_ERROR_LOG_MAX); | ||
1149 | eeh_error_buf_size = RTAS_ERROR_LOG_MAX; | ||
1150 | } | ||
1151 | |||
1152 | /* Enable EEH for all adapters. Note that eeh requires buid's */ | 1007 | /* Enable EEH for all adapters. Note that eeh requires buid's */ |
1153 | for (phb = of_find_node_by_name(NULL, "pci"); phb; | 1008 | for (phb = of_find_node_by_name(NULL, "pci"); phb; |
1154 | phb = of_find_node_by_name(phb, "pci")) { | 1009 | phb = of_find_node_by_name(phb, "pci")) { |
1155 | unsigned long buid; | 1010 | unsigned long buid; |
1156 | 1011 | ||
1157 | buid = get_phb_buid(phb); | 1012 | buid = get_phb_buid(phb); |
1158 | if (buid == 0 || PCI_DN(phb) == NULL) | 1013 | if (buid == 0 || !of_node_to_eeh_dev(phb)) |
1159 | continue; | 1014 | continue; |
1160 | 1015 | ||
1161 | info.buid_lo = BUID_LO(buid); | 1016 | traverse_pci_devices(phb, eeh_early_enable, NULL); |
1162 | info.buid_hi = BUID_HI(buid); | ||
1163 | traverse_pci_devices(phb, early_enable_eeh, &info); | ||
1164 | } | 1017 | } |
1165 | 1018 | ||
1166 | if (eeh_subsystem_enabled) | 1019 | if (eeh_subsystem_enabled) |
@@ -1170,7 +1023,7 @@ void __init eeh_init(void) | |||
1170 | } | 1023 | } |
1171 | 1024 | ||
1172 | /** | 1025 | /** |
1173 | * eeh_add_device_early - enable EEH for the indicated device_node | 1026 | * eeh_add_device_early - Enable EEH for the indicated device_node |
1174 | * @dn: device node for which to set up EEH | 1027 | * @dn: device node for which to set up EEH |
1175 | * | 1028 | * |
1176 | * This routine must be used to perform EEH initialization for PCI | 1029 | * This routine must be used to perform EEH initialization for PCI |
@@ -1184,21 +1037,26 @@ void __init eeh_init(void) | |||
1184 | static void eeh_add_device_early(struct device_node *dn) | 1037 | static void eeh_add_device_early(struct device_node *dn) |
1185 | { | 1038 | { |
1186 | struct pci_controller *phb; | 1039 | struct pci_controller *phb; |
1187 | struct eeh_early_enable_info info; | ||
1188 | 1040 | ||
1189 | if (!dn || !PCI_DN(dn)) | 1041 | if (!dn || !of_node_to_eeh_dev(dn)) |
1190 | return; | 1042 | return; |
1191 | phb = PCI_DN(dn)->phb; | 1043 | phb = of_node_to_eeh_dev(dn)->phb; |
1192 | 1044 | ||
1193 | /* USB Bus children of PCI devices will not have BUID's */ | 1045 | /* USB Bus children of PCI devices will not have BUID's */ |
1194 | if (NULL == phb || 0 == phb->buid) | 1046 | if (NULL == phb || 0 == phb->buid) |
1195 | return; | 1047 | return; |
1196 | 1048 | ||
1197 | info.buid_hi = BUID_HI(phb->buid); | 1049 | eeh_early_enable(dn, NULL); |
1198 | info.buid_lo = BUID_LO(phb->buid); | ||
1199 | early_enable_eeh(dn, &info); | ||
1200 | } | 1050 | } |
1201 | 1051 | ||
1052 | /** | ||
1053 | * eeh_add_device_tree_early - Enable EEH for the indicated device | ||
1054 | * @dn: device node | ||
1055 | * | ||
1056 | * This routine must be used to perform EEH initialization for the | ||
1057 | * indicated PCI device that was added after system boot (e.g. | ||
1058 | * hotplug, dlpar). | ||
1059 | */ | ||
1202 | void eeh_add_device_tree_early(struct device_node *dn) | 1060 | void eeh_add_device_tree_early(struct device_node *dn) |
1203 | { | 1061 | { |
1204 | struct device_node *sib; | 1062 | struct device_node *sib; |
@@ -1210,7 +1068,7 @@ void eeh_add_device_tree_early(struct device_node *dn) | |||
1210 | EXPORT_SYMBOL_GPL(eeh_add_device_tree_early); | 1068 | EXPORT_SYMBOL_GPL(eeh_add_device_tree_early); |
1211 | 1069 | ||
1212 | /** | 1070 | /** |
1213 | * eeh_add_device_late - perform EEH initialization for the indicated pci device | 1071 | * eeh_add_device_late - Perform EEH initialization for the indicated pci device |
1214 | * @dev: pci device for which to set up EEH | 1072 | * @dev: pci device for which to set up EEH |
1215 | * | 1073 | * |
1216 | * This routine must be used to complete EEH initialization for PCI | 1074 | * This routine must be used to complete EEH initialization for PCI |
@@ -1219,7 +1077,7 @@ EXPORT_SYMBOL_GPL(eeh_add_device_tree_early); | |||
1219 | static void eeh_add_device_late(struct pci_dev *dev) | 1077 | static void eeh_add_device_late(struct pci_dev *dev) |
1220 | { | 1078 | { |
1221 | struct device_node *dn; | 1079 | struct device_node *dn; |
1222 | struct pci_dn *pdn; | 1080 | struct eeh_dev *edev; |
1223 | 1081 | ||
1224 | if (!dev || !eeh_subsystem_enabled) | 1082 | if (!dev || !eeh_subsystem_enabled) |
1225 | return; | 1083 | return; |
@@ -1227,20 +1085,29 @@ static void eeh_add_device_late(struct pci_dev *dev) | |||
1227 | pr_debug("EEH: Adding device %s\n", pci_name(dev)); | 1085 | pr_debug("EEH: Adding device %s\n", pci_name(dev)); |
1228 | 1086 | ||
1229 | dn = pci_device_to_OF_node(dev); | 1087 | dn = pci_device_to_OF_node(dev); |
1230 | pdn = PCI_DN(dn); | 1088 | edev = pci_dev_to_eeh_dev(dev); |
1231 | if (pdn->pcidev == dev) { | 1089 | if (edev->pdev == dev) { |
1232 | pr_debug("EEH: Already referenced !\n"); | 1090 | pr_debug("EEH: Already referenced !\n"); |
1233 | return; | 1091 | return; |
1234 | } | 1092 | } |
1235 | WARN_ON(pdn->pcidev); | 1093 | WARN_ON(edev->pdev); |
1236 | 1094 | ||
1237 | pci_dev_get (dev); | 1095 | pci_dev_get(dev); |
1238 | pdn->pcidev = dev; | 1096 | edev->pdev = dev; |
1097 | dev->dev.archdata.edev = edev; | ||
1239 | 1098 | ||
1240 | pci_addr_cache_insert_device(dev); | 1099 | pci_addr_cache_insert_device(dev); |
1241 | eeh_sysfs_add_device(dev); | 1100 | eeh_sysfs_add_device(dev); |
1242 | } | 1101 | } |
1243 | 1102 | ||
1103 | /** | ||
1104 | * eeh_add_device_tree_late - Perform EEH initialization for the indicated PCI bus | ||
1105 | * @bus: PCI bus | ||
1106 | * | ||
1107 | * This routine must be used to perform EEH initialization for PCI | ||
1108 | * devices which are attached to the indicated PCI bus. The PCI bus | ||
1109 | * is added after system boot through hotplug or dlpar. | ||
1110 | */ | ||
1244 | void eeh_add_device_tree_late(struct pci_bus *bus) | 1111 | void eeh_add_device_tree_late(struct pci_bus *bus) |
1245 | { | 1112 | { |
1246 | struct pci_dev *dev; | 1113 | struct pci_dev *dev; |
@@ -1257,7 +1124,7 @@ void eeh_add_device_tree_late(struct pci_bus *bus) | |||
1257 | EXPORT_SYMBOL_GPL(eeh_add_device_tree_late); | 1124 | EXPORT_SYMBOL_GPL(eeh_add_device_tree_late); |
1258 | 1125 | ||
1259 | /** | 1126 | /** |
1260 | * eeh_remove_device - undo EEH setup for the indicated pci device | 1127 | * eeh_remove_device - Undo EEH setup for the indicated pci device |
1261 | * @dev: pci device to be removed | 1128 | * @dev: pci device to be removed |
1262 | * | 1129 | * |
1263 | * This routine should be called when a device is removed from | 1130 | * This routine should be called when a device is removed from |
@@ -1268,25 +1135,35 @@ EXPORT_SYMBOL_GPL(eeh_add_device_tree_late); | |||
1268 | */ | 1135 | */ |
1269 | static void eeh_remove_device(struct pci_dev *dev) | 1136 | static void eeh_remove_device(struct pci_dev *dev) |
1270 | { | 1137 | { |
1271 | struct device_node *dn; | 1138 | struct eeh_dev *edev; |
1139 | |||
1272 | if (!dev || !eeh_subsystem_enabled) | 1140 | if (!dev || !eeh_subsystem_enabled) |
1273 | return; | 1141 | return; |
1142 | edev = pci_dev_to_eeh_dev(dev); | ||
1274 | 1143 | ||
1275 | /* Unregister the device with the EEH/PCI address search system */ | 1144 | /* Unregister the device with the EEH/PCI address search system */ |
1276 | pr_debug("EEH: Removing device %s\n", pci_name(dev)); | 1145 | pr_debug("EEH: Removing device %s\n", pci_name(dev)); |
1277 | 1146 | ||
1278 | dn = pci_device_to_OF_node(dev); | 1147 | if (!edev || !edev->pdev) { |
1279 | if (PCI_DN(dn)->pcidev == NULL) { | ||
1280 | pr_debug("EEH: Not referenced !\n"); | 1148 | pr_debug("EEH: Not referenced !\n"); |
1281 | return; | 1149 | return; |
1282 | } | 1150 | } |
1283 | PCI_DN(dn)->pcidev = NULL; | 1151 | edev->pdev = NULL; |
1284 | pci_dev_put (dev); | 1152 | dev->dev.archdata.edev = NULL; |
1153 | pci_dev_put(dev); | ||
1285 | 1154 | ||
1286 | pci_addr_cache_remove_device(dev); | 1155 | pci_addr_cache_remove_device(dev); |
1287 | eeh_sysfs_remove_device(dev); | 1156 | eeh_sysfs_remove_device(dev); |
1288 | } | 1157 | } |
1289 | 1158 | ||
1159 | /** | ||
1160 | * eeh_remove_bus_device - Undo EEH setup for the indicated PCI device | ||
1161 | * @dev: PCI device | ||
1162 | * | ||
1163 | * This routine must be called when a device is removed from the | ||
1164 | * running system through hotplug or dlpar. The corresponding | ||
1165 | * PCI address cache will be removed. | ||
1166 | */ | ||
1290 | void eeh_remove_bus_device(struct pci_dev *dev) | 1167 | void eeh_remove_bus_device(struct pci_dev *dev) |
1291 | { | 1168 | { |
1292 | struct pci_bus *bus = dev->subordinate; | 1169 | struct pci_bus *bus = dev->subordinate; |
@@ -1305,21 +1182,24 @@ static int proc_eeh_show(struct seq_file *m, void *v) | |||
1305 | { | 1182 | { |
1306 | if (0 == eeh_subsystem_enabled) { | 1183 | if (0 == eeh_subsystem_enabled) { |
1307 | seq_printf(m, "EEH Subsystem is globally disabled\n"); | 1184 | seq_printf(m, "EEH Subsystem is globally disabled\n"); |
1308 | seq_printf(m, "eeh_total_mmio_ffs=%ld\n", total_mmio_ffs); | 1185 | seq_printf(m, "eeh_total_mmio_ffs=%llu\n", eeh_stats.total_mmio_ffs); |
1309 | } else { | 1186 | } else { |
1310 | seq_printf(m, "EEH Subsystem is enabled\n"); | 1187 | seq_printf(m, "EEH Subsystem is enabled\n"); |
1311 | seq_printf(m, | 1188 | seq_printf(m, |
1312 | "no device=%ld\n" | 1189 | "no device=%llu\n" |
1313 | "no device node=%ld\n" | 1190 | "no device node=%llu\n" |
1314 | "no config address=%ld\n" | 1191 | "no config address=%llu\n" |
1315 | "check not wanted=%ld\n" | 1192 | "check not wanted=%llu\n" |
1316 | "eeh_total_mmio_ffs=%ld\n" | 1193 | "eeh_total_mmio_ffs=%llu\n" |
1317 | "eeh_false_positives=%ld\n" | 1194 | "eeh_false_positives=%llu\n" |
1318 | "eeh_slot_resets=%ld\n", | 1195 | "eeh_slot_resets=%llu\n", |
1319 | no_device, no_dn, no_cfg_addr, | 1196 | eeh_stats.no_device, |
1320 | ignored_check, total_mmio_ffs, | 1197 | eeh_stats.no_dn, |
1321 | false_positives, | 1198 | eeh_stats.no_cfg_addr, |
1322 | slot_resets); | 1199 | eeh_stats.ignored_check, |
1200 | eeh_stats.total_mmio_ffs, | ||
1201 | eeh_stats.false_positives, | ||
1202 | eeh_stats.slot_resets); | ||
1323 | } | 1203 | } |
1324 | 1204 | ||
1325 | return 0; | 1205 | return 0; |
diff --git a/arch/powerpc/platforms/pseries/eeh_cache.c b/arch/powerpc/platforms/pseries/eeh_cache.c index fc5ae767989e..e5ae1c687c66 100644 --- a/arch/powerpc/platforms/pseries/eeh_cache.c +++ b/arch/powerpc/platforms/pseries/eeh_cache.c | |||
@@ -1,5 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * eeh_cache.c | ||
3 | * PCI address cache; allows the lookup of PCI devices based on I/O address | 2 | * PCI address cache; allows the lookup of PCI devices based on I/O address |
4 | * | 3 | * |
5 | * Copyright IBM Corporation 2004 | 4 | * Copyright IBM Corporation 2004 |
@@ -47,8 +46,7 @@ | |||
47 | * than any hash algo I could think of for this problem, even | 46 | * than any hash algo I could think of for this problem, even |
48 | * with the penalty of slow pointer chases for d-cache misses). | 47 | * with the penalty of slow pointer chases for d-cache misses). |
49 | */ | 48 | */ |
50 | struct pci_io_addr_range | 49 | struct pci_io_addr_range { |
51 | { | ||
52 | struct rb_node rb_node; | 50 | struct rb_node rb_node; |
53 | unsigned long addr_lo; | 51 | unsigned long addr_lo; |
54 | unsigned long addr_hi; | 52 | unsigned long addr_hi; |
@@ -56,13 +54,12 @@ struct pci_io_addr_range | |||
56 | unsigned int flags; | 54 | unsigned int flags; |
57 | }; | 55 | }; |
58 | 56 | ||
59 | static struct pci_io_addr_cache | 57 | static struct pci_io_addr_cache { |
60 | { | ||
61 | struct rb_root rb_root; | 58 | struct rb_root rb_root; |
62 | spinlock_t piar_lock; | 59 | spinlock_t piar_lock; |
63 | } pci_io_addr_cache_root; | 60 | } pci_io_addr_cache_root; |
64 | 61 | ||
65 | static inline struct pci_dev *__pci_get_device_by_addr(unsigned long addr) | 62 | static inline struct pci_dev *__pci_addr_cache_get_device(unsigned long addr) |
66 | { | 63 | { |
67 | struct rb_node *n = pci_io_addr_cache_root.rb_root.rb_node; | 64 | struct rb_node *n = pci_io_addr_cache_root.rb_root.rb_node; |
68 | 65 | ||
@@ -86,7 +83,7 @@ static inline struct pci_dev *__pci_get_device_by_addr(unsigned long addr) | |||
86 | } | 83 | } |
87 | 84 | ||
88 | /** | 85 | /** |
89 | * pci_get_device_by_addr - Get device, given only address | 86 | * pci_addr_cache_get_device - Get device, given only address |
90 | * @addr: mmio (PIO) phys address or i/o port number | 87 | * @addr: mmio (PIO) phys address or i/o port number |
91 | * | 88 | * |
92 | * Given an mmio phys address, or a port number, find a pci device | 89 | * Given an mmio phys address, or a port number, find a pci device |
@@ -95,13 +92,13 @@ static inline struct pci_dev *__pci_get_device_by_addr(unsigned long addr) | |||
95 | * from zero (that is, they do *not* have pci_io_addr added in). | 92 | * from zero (that is, they do *not* have pci_io_addr added in). |
96 | * It is safe to call this function within an interrupt. | 93 | * It is safe to call this function within an interrupt. |
97 | */ | 94 | */ |
98 | struct pci_dev *pci_get_device_by_addr(unsigned long addr) | 95 | struct pci_dev *pci_addr_cache_get_device(unsigned long addr) |
99 | { | 96 | { |
100 | struct pci_dev *dev; | 97 | struct pci_dev *dev; |
101 | unsigned long flags; | 98 | unsigned long flags; |
102 | 99 | ||
103 | spin_lock_irqsave(&pci_io_addr_cache_root.piar_lock, flags); | 100 | spin_lock_irqsave(&pci_io_addr_cache_root.piar_lock, flags); |
104 | dev = __pci_get_device_by_addr(addr); | 101 | dev = __pci_addr_cache_get_device(addr); |
105 | spin_unlock_irqrestore(&pci_io_addr_cache_root.piar_lock, flags); | 102 | spin_unlock_irqrestore(&pci_io_addr_cache_root.piar_lock, flags); |
106 | return dev; | 103 | return dev; |
107 | } | 104 | } |
@@ -166,7 +163,7 @@ pci_addr_cache_insert(struct pci_dev *dev, unsigned long alo, | |||
166 | 163 | ||
167 | #ifdef DEBUG | 164 | #ifdef DEBUG |
168 | printk(KERN_DEBUG "PIAR: insert range=[%lx:%lx] dev=%s\n", | 165 | printk(KERN_DEBUG "PIAR: insert range=[%lx:%lx] dev=%s\n", |
169 | alo, ahi, pci_name (dev)); | 166 | alo, ahi, pci_name(dev)); |
170 | #endif | 167 | #endif |
171 | 168 | ||
172 | rb_link_node(&piar->rb_node, parent, p); | 169 | rb_link_node(&piar->rb_node, parent, p); |
@@ -178,7 +175,7 @@ pci_addr_cache_insert(struct pci_dev *dev, unsigned long alo, | |||
178 | static void __pci_addr_cache_insert_device(struct pci_dev *dev) | 175 | static void __pci_addr_cache_insert_device(struct pci_dev *dev) |
179 | { | 176 | { |
180 | struct device_node *dn; | 177 | struct device_node *dn; |
181 | struct pci_dn *pdn; | 178 | struct eeh_dev *edev; |
182 | int i; | 179 | int i; |
183 | 180 | ||
184 | dn = pci_device_to_OF_node(dev); | 181 | dn = pci_device_to_OF_node(dev); |
@@ -187,13 +184,19 @@ static void __pci_addr_cache_insert_device(struct pci_dev *dev) | |||
187 | return; | 184 | return; |
188 | } | 185 | } |
189 | 186 | ||
187 | edev = of_node_to_eeh_dev(dn); | ||
188 | if (!edev) { | ||
189 | pr_warning("PCI: no EEH dev found for dn=%s\n", | ||
190 | dn->full_name); | ||
191 | return; | ||
192 | } | ||
193 | |||
190 | /* Skip any devices for which EEH is not enabled. */ | 194 | /* Skip any devices for which EEH is not enabled. */ |
191 | pdn = PCI_DN(dn); | 195 | if (!(edev->mode & EEH_MODE_SUPPORTED) || |
192 | if (!(pdn->eeh_mode & EEH_MODE_SUPPORTED) || | 196 | edev->mode & EEH_MODE_NOCHECK) { |
193 | pdn->eeh_mode & EEH_MODE_NOCHECK) { | ||
194 | #ifdef DEBUG | 197 | #ifdef DEBUG |
195 | printk(KERN_INFO "PCI: skip building address cache for=%s - %s\n", | 198 | pr_info("PCI: skip building address cache for=%s - %s\n", |
196 | pci_name(dev), pdn->node->full_name); | 199 | pci_name(dev), dn->full_name); |
197 | #endif | 200 | #endif |
198 | return; | 201 | return; |
199 | } | 202 | } |
@@ -284,6 +287,7 @@ void pci_addr_cache_remove_device(struct pci_dev *dev) | |||
284 | void __init pci_addr_cache_build(void) | 287 | void __init pci_addr_cache_build(void) |
285 | { | 288 | { |
286 | struct device_node *dn; | 289 | struct device_node *dn; |
290 | struct eeh_dev *edev; | ||
287 | struct pci_dev *dev = NULL; | 291 | struct pci_dev *dev = NULL; |
288 | 292 | ||
289 | spin_lock_init(&pci_io_addr_cache_root.piar_lock); | 293 | spin_lock_init(&pci_io_addr_cache_root.piar_lock); |
@@ -294,8 +298,14 @@ void __init pci_addr_cache_build(void) | |||
294 | dn = pci_device_to_OF_node(dev); | 298 | dn = pci_device_to_OF_node(dev); |
295 | if (!dn) | 299 | if (!dn) |
296 | continue; | 300 | continue; |
301 | |||
302 | edev = of_node_to_eeh_dev(dn); | ||
303 | if (!edev) | ||
304 | continue; | ||
305 | |||
297 | pci_dev_get(dev); /* matching put is in eeh_remove_device() */ | 306 | pci_dev_get(dev); /* matching put is in eeh_remove_device() */ |
298 | PCI_DN(dn)->pcidev = dev; | 307 | dev->dev.archdata.edev = edev; |
308 | edev->pdev = dev; | ||
299 | 309 | ||
300 | eeh_sysfs_add_device(dev); | 310 | eeh_sysfs_add_device(dev); |
301 | } | 311 | } |
diff --git a/arch/powerpc/platforms/pseries/eeh_dev.c b/arch/powerpc/platforms/pseries/eeh_dev.c new file mode 100644 index 000000000000..f3aed7dcae95 --- /dev/null +++ b/arch/powerpc/platforms/pseries/eeh_dev.c | |||
@@ -0,0 +1,102 @@ | |||
1 | /* | ||
2 | * The file intends to implement dynamic creation of EEH device, which will | ||
3 | * be bound with OF node and PCI device simutaneously. The EEH devices would | ||
4 | * be foundamental information for EEH core components to work proerly. Besides, | ||
5 | * We have to support multiple situations where dynamic creation of EEH device | ||
6 | * is required: | ||
7 | * | ||
8 | * 1) Before PCI emunation starts, we need create EEH devices according to the | ||
9 | * PCI sensitive OF nodes. | ||
10 | * 2) When PCI emunation is done, we need do the binding between PCI device and | ||
11 | * the associated EEH device. | ||
12 | * 3) DR (Dynamic Reconfiguration) would create PCI sensitive OF node. EEH device | ||
13 | * will be created while PCI sensitive OF node is detected from DR. | ||
14 | * 4) PCI hotplug needs redoing the binding between PCI device and EEH device. If | ||
15 | * PHB is newly inserted, we also need create EEH devices accordingly. | ||
16 | * | ||
17 | * Copyright Benjamin Herrenschmidt & Gavin Shan, IBM Corporation 2012. | ||
18 | * | ||
19 | * This program is free software; you can redistribute it and/or modify | ||
20 | * it under the terms of the GNU General Public License as published by | ||
21 | * the Free Software Foundation; either version 2 of the License, or | ||
22 | * (at your option) any later version. | ||
23 | * | ||
24 | * This program is distributed in the hope that it will be useful, | ||
25 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
26 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
27 | * GNU General Public License for more details. | ||
28 | * | ||
29 | * You should have received a copy of the GNU General Public License | ||
30 | * along with this program; if not, write to the Free Software | ||
31 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
32 | */ | ||
33 | |||
34 | #include <linux/export.h> | ||
35 | #include <linux/gfp.h> | ||
36 | #include <linux/init.h> | ||
37 | #include <linux/kernel.h> | ||
38 | #include <linux/pci.h> | ||
39 | #include <linux/string.h> | ||
40 | |||
41 | #include <asm/pci-bridge.h> | ||
42 | #include <asm/ppc-pci.h> | ||
43 | |||
44 | /** | ||
45 | * eeh_dev_init - Create EEH device according to OF node | ||
46 | * @dn: device node | ||
47 | * @data: PHB | ||
48 | * | ||
49 | * It will create EEH device according to the given OF node. The function | ||
50 | * might be called by PCI emunation, DR, PHB hotplug. | ||
51 | */ | ||
52 | void * __devinit eeh_dev_init(struct device_node *dn, void *data) | ||
53 | { | ||
54 | struct pci_controller *phb = data; | ||
55 | struct eeh_dev *edev; | ||
56 | |||
57 | /* Allocate EEH device */ | ||
58 | edev = zalloc_maybe_bootmem(sizeof(*edev), GFP_KERNEL); | ||
59 | if (!edev) { | ||
60 | pr_warning("%s: out of memory\n", __func__); | ||
61 | return NULL; | ||
62 | } | ||
63 | |||
64 | /* Associate EEH device with OF node */ | ||
65 | dn->edev = edev; | ||
66 | edev->dn = dn; | ||
67 | edev->phb = phb; | ||
68 | |||
69 | return NULL; | ||
70 | } | ||
71 | |||
72 | /** | ||
73 | * eeh_dev_phb_init_dynamic - Create EEH devices for devices included in PHB | ||
74 | * @phb: PHB | ||
75 | * | ||
76 | * Scan the PHB OF node and its child association, then create the | ||
77 | * EEH devices accordingly | ||
78 | */ | ||
79 | void __devinit eeh_dev_phb_init_dynamic(struct pci_controller *phb) | ||
80 | { | ||
81 | struct device_node *dn = phb->dn; | ||
82 | |||
83 | /* EEH device for PHB */ | ||
84 | eeh_dev_init(dn, phb); | ||
85 | |||
86 | /* EEH devices for children OF nodes */ | ||
87 | traverse_pci_devices(dn, eeh_dev_init, phb); | ||
88 | } | ||
89 | |||
90 | /** | ||
91 | * eeh_dev_phb_init - Create EEH devices for devices included in existing PHBs | ||
92 | * | ||
93 | * Scan all the existing PHBs and create EEH devices for their OF | ||
94 | * nodes and their children OF nodes | ||
95 | */ | ||
96 | void __init eeh_dev_phb_init(void) | ||
97 | { | ||
98 | struct pci_controller *phb, *tmp; | ||
99 | |||
100 | list_for_each_entry_safe(phb, tmp, &hose_list, list_node) | ||
101 | eeh_dev_phb_init_dynamic(phb); | ||
102 | } | ||
diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c index 1b6cb10589e0..baf92cd9dfab 100644 --- a/arch/powerpc/platforms/pseries/eeh_driver.c +++ b/arch/powerpc/platforms/pseries/eeh_driver.c | |||
@@ -33,8 +33,14 @@ | |||
33 | #include <asm/prom.h> | 33 | #include <asm/prom.h> |
34 | #include <asm/rtas.h> | 34 | #include <asm/rtas.h> |
35 | 35 | ||
36 | 36 | /** | |
37 | static inline const char * pcid_name (struct pci_dev *pdev) | 37 | * eeh_pcid_name - Retrieve name of PCI device driver |
38 | * @pdev: PCI device | ||
39 | * | ||
40 | * This routine is used to retrieve the name of PCI device driver | ||
41 | * if that's valid. | ||
42 | */ | ||
43 | static inline const char *eeh_pcid_name(struct pci_dev *pdev) | ||
38 | { | 44 | { |
39 | if (pdev && pdev->dev.driver) | 45 | if (pdev && pdev->dev.driver) |
40 | return pdev->dev.driver->name; | 46 | return pdev->dev.driver->name; |
@@ -64,48 +70,59 @@ static void print_device_node_tree(struct pci_dn *pdn, int dent) | |||
64 | #endif | 70 | #endif |
65 | 71 | ||
66 | /** | 72 | /** |
67 | * eeh_disable_irq - disable interrupt for the recovering device | 73 | * eeh_disable_irq - Disable interrupt for the recovering device |
74 | * @dev: PCI device | ||
75 | * | ||
76 | * This routine must be called when reporting temporary or permanent | ||
77 | * error to the particular PCI device to disable interrupt of that | ||
78 | * device. If the device has enabled MSI or MSI-X interrupt, we needn't | ||
79 | * do real work because EEH should freeze DMA transfers for those PCI | ||
80 | * devices encountering EEH errors, which includes MSI or MSI-X. | ||
68 | */ | 81 | */ |
69 | static void eeh_disable_irq(struct pci_dev *dev) | 82 | static void eeh_disable_irq(struct pci_dev *dev) |
70 | { | 83 | { |
71 | struct device_node *dn = pci_device_to_OF_node(dev); | 84 | struct eeh_dev *edev = pci_dev_to_eeh_dev(dev); |
72 | 85 | ||
73 | /* Don't disable MSI and MSI-X interrupts. They are | 86 | /* Don't disable MSI and MSI-X interrupts. They are |
74 | * effectively disabled by the DMA Stopped state | 87 | * effectively disabled by the DMA Stopped state |
75 | * when an EEH error occurs. | 88 | * when an EEH error occurs. |
76 | */ | 89 | */ |
77 | if (dev->msi_enabled || dev->msix_enabled) | 90 | if (dev->msi_enabled || dev->msix_enabled) |
78 | return; | 91 | return; |
79 | 92 | ||
80 | if (!irq_has_action(dev->irq)) | 93 | if (!irq_has_action(dev->irq)) |
81 | return; | 94 | return; |
82 | 95 | ||
83 | PCI_DN(dn)->eeh_mode |= EEH_MODE_IRQ_DISABLED; | 96 | edev->mode |= EEH_MODE_IRQ_DISABLED; |
84 | disable_irq_nosync(dev->irq); | 97 | disable_irq_nosync(dev->irq); |
85 | } | 98 | } |
86 | 99 | ||
87 | /** | 100 | /** |
88 | * eeh_enable_irq - enable interrupt for the recovering device | 101 | * eeh_enable_irq - Enable interrupt for the recovering device |
102 | * @dev: PCI device | ||
103 | * | ||
104 | * This routine must be called to enable interrupt while failed | ||
105 | * device could be resumed. | ||
89 | */ | 106 | */ |
90 | static void eeh_enable_irq(struct pci_dev *dev) | 107 | static void eeh_enable_irq(struct pci_dev *dev) |
91 | { | 108 | { |
92 | struct device_node *dn = pci_device_to_OF_node(dev); | 109 | struct eeh_dev *edev = pci_dev_to_eeh_dev(dev); |
93 | 110 | ||
94 | if ((PCI_DN(dn)->eeh_mode) & EEH_MODE_IRQ_DISABLED) { | 111 | if ((edev->mode) & EEH_MODE_IRQ_DISABLED) { |
95 | PCI_DN(dn)->eeh_mode &= ~EEH_MODE_IRQ_DISABLED; | 112 | edev->mode &= ~EEH_MODE_IRQ_DISABLED; |
96 | enable_irq(dev->irq); | 113 | enable_irq(dev->irq); |
97 | } | 114 | } |
98 | } | 115 | } |
99 | 116 | ||
100 | /* ------------------------------------------------------- */ | ||
101 | /** | 117 | /** |
102 | * eeh_report_error - report pci error to each device driver | 118 | * eeh_report_error - Report pci error to each device driver |
119 | * @dev: PCI device | ||
120 | * @userdata: return value | ||
103 | * | 121 | * |
104 | * Report an EEH error to each device driver, collect up and | 122 | * Report an EEH error to each device driver, collect up and |
105 | * merge the device driver responses. Cumulative response | 123 | * merge the device driver responses. Cumulative response |
106 | * passed back in "userdata". | 124 | * passed back in "userdata". |
107 | */ | 125 | */ |
108 | |||
109 | static int eeh_report_error(struct pci_dev *dev, void *userdata) | 126 | static int eeh_report_error(struct pci_dev *dev, void *userdata) |
110 | { | 127 | { |
111 | enum pci_ers_result rc, *res = userdata; | 128 | enum pci_ers_result rc, *res = userdata; |
@@ -122,7 +139,7 @@ static int eeh_report_error(struct pci_dev *dev, void *userdata) | |||
122 | !driver->err_handler->error_detected) | 139 | !driver->err_handler->error_detected) |
123 | return 0; | 140 | return 0; |
124 | 141 | ||
125 | rc = driver->err_handler->error_detected (dev, pci_channel_io_frozen); | 142 | rc = driver->err_handler->error_detected(dev, pci_channel_io_frozen); |
126 | 143 | ||
127 | /* A driver that needs a reset trumps all others */ | 144 | /* A driver that needs a reset trumps all others */ |
128 | if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc; | 145 | if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc; |
@@ -132,13 +149,14 @@ static int eeh_report_error(struct pci_dev *dev, void *userdata) | |||
132 | } | 149 | } |
133 | 150 | ||
134 | /** | 151 | /** |
135 | * eeh_report_mmio_enabled - tell drivers that MMIO has been enabled | 152 | * eeh_report_mmio_enabled - Tell drivers that MMIO has been enabled |
153 | * @dev: PCI device | ||
154 | * @userdata: return value | ||
136 | * | 155 | * |
137 | * Tells each device driver that IO ports, MMIO and config space I/O | 156 | * Tells each device driver that IO ports, MMIO and config space I/O |
138 | * are now enabled. Collects up and merges the device driver responses. | 157 | * are now enabled. Collects up and merges the device driver responses. |
139 | * Cumulative response passed back in "userdata". | 158 | * Cumulative response passed back in "userdata". |
140 | */ | 159 | */ |
141 | |||
142 | static int eeh_report_mmio_enabled(struct pci_dev *dev, void *userdata) | 160 | static int eeh_report_mmio_enabled(struct pci_dev *dev, void *userdata) |
143 | { | 161 | { |
144 | enum pci_ers_result rc, *res = userdata; | 162 | enum pci_ers_result rc, *res = userdata; |
@@ -149,7 +167,7 @@ static int eeh_report_mmio_enabled(struct pci_dev *dev, void *userdata) | |||
149 | !driver->err_handler->mmio_enabled) | 167 | !driver->err_handler->mmio_enabled) |
150 | return 0; | 168 | return 0; |
151 | 169 | ||
152 | rc = driver->err_handler->mmio_enabled (dev); | 170 | rc = driver->err_handler->mmio_enabled(dev); |
153 | 171 | ||
154 | /* A driver that needs a reset trumps all others */ | 172 | /* A driver that needs a reset trumps all others */ |
155 | if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc; | 173 | if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc; |
@@ -159,9 +177,15 @@ static int eeh_report_mmio_enabled(struct pci_dev *dev, void *userdata) | |||
159 | } | 177 | } |
160 | 178 | ||
161 | /** | 179 | /** |
162 | * eeh_report_reset - tell device that slot has been reset | 180 | * eeh_report_reset - Tell device that slot has been reset |
181 | * @dev: PCI device | ||
182 | * @userdata: return value | ||
183 | * | ||
184 | * This routine must be called while EEH tries to reset particular | ||
185 | * PCI device so that the associated PCI device driver could take | ||
186 | * some actions, usually to save data the driver needs so that the | ||
187 | * driver can work again while the device is recovered. | ||
163 | */ | 188 | */ |
164 | |||
165 | static int eeh_report_reset(struct pci_dev *dev, void *userdata) | 189 | static int eeh_report_reset(struct pci_dev *dev, void *userdata) |
166 | { | 190 | { |
167 | enum pci_ers_result rc, *res = userdata; | 191 | enum pci_ers_result rc, *res = userdata; |
@@ -188,9 +212,14 @@ static int eeh_report_reset(struct pci_dev *dev, void *userdata) | |||
188 | } | 212 | } |
189 | 213 | ||
190 | /** | 214 | /** |
191 | * eeh_report_resume - tell device to resume normal operations | 215 | * eeh_report_resume - Tell device to resume normal operations |
216 | * @dev: PCI device | ||
217 | * @userdata: return value | ||
218 | * | ||
219 | * This routine must be called to notify the device driver that it | ||
220 | * could resume so that the device driver can do some initialization | ||
221 | * to make the recovered device work again. | ||
192 | */ | 222 | */ |
193 | |||
194 | static int eeh_report_resume(struct pci_dev *dev, void *userdata) | 223 | static int eeh_report_resume(struct pci_dev *dev, void *userdata) |
195 | { | 224 | { |
196 | struct pci_driver *driver = dev->driver; | 225 | struct pci_driver *driver = dev->driver; |
@@ -212,12 +241,13 @@ static int eeh_report_resume(struct pci_dev *dev, void *userdata) | |||
212 | } | 241 | } |
213 | 242 | ||
214 | /** | 243 | /** |
215 | * eeh_report_failure - tell device driver that device is dead. | 244 | * eeh_report_failure - Tell device driver that device is dead. |
245 | * @dev: PCI device | ||
246 | * @userdata: return value | ||
216 | * | 247 | * |
217 | * This informs the device driver that the device is permanently | 248 | * This informs the device driver that the device is permanently |
218 | * dead, and that no further recovery attempts will be made on it. | 249 | * dead, and that no further recovery attempts will be made on it. |
219 | */ | 250 | */ |
220 | |||
221 | static int eeh_report_failure(struct pci_dev *dev, void *userdata) | 251 | static int eeh_report_failure(struct pci_dev *dev, void *userdata) |
222 | { | 252 | { |
223 | struct pci_driver *driver = dev->driver; | 253 | struct pci_driver *driver = dev->driver; |
@@ -238,65 +268,46 @@ static int eeh_report_failure(struct pci_dev *dev, void *userdata) | |||
238 | return 0; | 268 | return 0; |
239 | } | 269 | } |
240 | 270 | ||
241 | /* ------------------------------------------------------- */ | ||
242 | /** | 271 | /** |
243 | * handle_eeh_events -- reset a PCI device after hard lockup. | 272 | * eeh_reset_device - Perform actual reset of a pci slot |
244 | * | 273 | * @edev: PE associated EEH device |
245 | * pSeries systems will isolate a PCI slot if the PCI-Host | 274 | * @bus: PCI bus corresponding to the isolcated slot |
246 | * bridge detects address or data parity errors, DMA's | ||
247 | * occurring to wild addresses (which usually happen due to | ||
248 | * bugs in device drivers or in PCI adapter firmware). | ||
249 | * Slot isolations also occur if #SERR, #PERR or other misc | ||
250 | * PCI-related errors are detected. | ||
251 | * | 275 | * |
252 | * Recovery process consists of unplugging the device driver | 276 | * This routine must be called to do reset on the indicated PE. |
253 | * (which generated hotplug events to userspace), then issuing | 277 | * During the reset, udev might be invoked because those affected |
254 | * a PCI #RST to the device, then reconfiguring the PCI config | 278 | * PCI devices will be removed and then added. |
255 | * space for all bridges & devices under this slot, and then | ||
256 | * finally restarting the device drivers (which cause a second | ||
257 | * set of hotplug events to go out to userspace). | ||
258 | */ | 279 | */ |
259 | 280 | static int eeh_reset_device(struct eeh_dev *edev, struct pci_bus *bus) | |
260 | /** | ||
261 | * eeh_reset_device() -- perform actual reset of a pci slot | ||
262 | * @bus: pointer to the pci bus structure corresponding | ||
263 | * to the isolated slot. A non-null value will | ||
264 | * cause all devices under the bus to be removed | ||
265 | * and then re-added. | ||
266 | * @pe_dn: pointer to a "Partionable Endpoint" device node. | ||
267 | * This is the top-level structure on which pci | ||
268 | * bus resets can be performed. | ||
269 | */ | ||
270 | |||
271 | static int eeh_reset_device (struct pci_dn *pe_dn, struct pci_bus *bus) | ||
272 | { | 281 | { |
273 | struct device_node *dn; | 282 | struct device_node *dn; |
274 | int cnt, rc; | 283 | int cnt, rc; |
275 | 284 | ||
276 | /* pcibios will clear the counter; save the value */ | 285 | /* pcibios will clear the counter; save the value */ |
277 | cnt = pe_dn->eeh_freeze_count; | 286 | cnt = edev->freeze_count; |
278 | 287 | ||
279 | if (bus) | 288 | if (bus) |
280 | pcibios_remove_pci_devices(bus); | 289 | pcibios_remove_pci_devices(bus); |
281 | 290 | ||
282 | /* Reset the pci controller. (Asserts RST#; resets config space). | 291 | /* Reset the pci controller. (Asserts RST#; resets config space). |
283 | * Reconfigure bridges and devices. Don't try to bring the system | 292 | * Reconfigure bridges and devices. Don't try to bring the system |
284 | * up if the reset failed for some reason. */ | 293 | * up if the reset failed for some reason. |
285 | rc = rtas_set_slot_reset(pe_dn); | 294 | */ |
295 | rc = eeh_reset_pe(edev); | ||
286 | if (rc) | 296 | if (rc) |
287 | return rc; | 297 | return rc; |
288 | 298 | ||
289 | /* Walk over all functions on this device. */ | 299 | /* Walk over all functions on this device. */ |
290 | dn = pe_dn->node; | 300 | dn = eeh_dev_to_of_node(edev); |
291 | if (!pcibios_find_pci_bus(dn) && PCI_DN(dn->parent)) | 301 | if (!pcibios_find_pci_bus(dn) && of_node_to_eeh_dev(dn->parent)) |
292 | dn = dn->parent->child; | 302 | dn = dn->parent->child; |
293 | 303 | ||
294 | while (dn) { | 304 | while (dn) { |
295 | struct pci_dn *ppe = PCI_DN(dn); | 305 | struct eeh_dev *pedev = of_node_to_eeh_dev(dn); |
306 | |||
296 | /* On Power4, always true because eeh_pe_config_addr=0 */ | 307 | /* On Power4, always true because eeh_pe_config_addr=0 */ |
297 | if (pe_dn->eeh_pe_config_addr == ppe->eeh_pe_config_addr) { | 308 | if (edev->pe_config_addr == pedev->pe_config_addr) { |
298 | rtas_configure_bridge(ppe); | 309 | eeh_ops->configure_bridge(dn); |
299 | eeh_restore_bars(ppe); | 310 | eeh_restore_bars(pedev); |
300 | } | 311 | } |
301 | dn = dn->sibling; | 312 | dn = dn->sibling; |
302 | } | 313 | } |
@@ -308,10 +319,10 @@ static int eeh_reset_device (struct pci_dn *pe_dn, struct pci_bus *bus) | |||
308 | * potentially weird things happen. | 319 | * potentially weird things happen. |
309 | */ | 320 | */ |
310 | if (bus) { | 321 | if (bus) { |
311 | ssleep (5); | 322 | ssleep(5); |
312 | pcibios_add_pci_devices(bus); | 323 | pcibios_add_pci_devices(bus); |
313 | } | 324 | } |
314 | pe_dn->eeh_freeze_count = cnt; | 325 | edev->freeze_count = cnt; |
315 | 326 | ||
316 | return 0; | 327 | return 0; |
317 | } | 328 | } |
@@ -321,23 +332,39 @@ static int eeh_reset_device (struct pci_dn *pe_dn, struct pci_bus *bus) | |||
321 | */ | 332 | */ |
322 | #define MAX_WAIT_FOR_RECOVERY 150 | 333 | #define MAX_WAIT_FOR_RECOVERY 150 |
323 | 334 | ||
324 | struct pci_dn * handle_eeh_events (struct eeh_event *event) | 335 | /** |
336 | * eeh_handle_event - Reset a PCI device after hard lockup. | ||
337 | * @event: EEH event | ||
338 | * | ||
339 | * While PHB detects address or data parity errors on particular PCI | ||
340 | * slot, the associated PE will be frozen. Besides, DMA's occurring | ||
341 | * to wild addresses (which usually happen due to bugs in device | ||
342 | * drivers or in PCI adapter firmware) can cause EEH error. #SERR, | ||
343 | * #PERR or other misc PCI-related errors also can trigger EEH errors. | ||
344 | * | ||
345 | * Recovery process consists of unplugging the device driver (which | ||
346 | * generated hotplug events to userspace), then issuing a PCI #RST to | ||
347 | * the device, then reconfiguring the PCI config space for all bridges | ||
348 | * & devices under this slot, and then finally restarting the device | ||
349 | * drivers (which cause a second set of hotplug events to go out to | ||
350 | * userspace). | ||
351 | */ | ||
352 | struct eeh_dev *handle_eeh_events(struct eeh_event *event) | ||
325 | { | 353 | { |
326 | struct device_node *frozen_dn; | 354 | struct device_node *frozen_dn; |
327 | struct pci_dn *frozen_pdn; | 355 | struct eeh_dev *frozen_edev; |
328 | struct pci_bus *frozen_bus; | 356 | struct pci_bus *frozen_bus; |
329 | int rc = 0; | 357 | int rc = 0; |
330 | enum pci_ers_result result = PCI_ERS_RESULT_NONE; | 358 | enum pci_ers_result result = PCI_ERS_RESULT_NONE; |
331 | const char *location, *pci_str, *drv_str, *bus_pci_str, *bus_drv_str; | 359 | const char *location, *pci_str, *drv_str, *bus_pci_str, *bus_drv_str; |
332 | 360 | ||
333 | frozen_dn = find_device_pe(event->dn); | 361 | frozen_dn = eeh_find_device_pe(eeh_dev_to_of_node(event->edev)); |
334 | if (!frozen_dn) { | 362 | if (!frozen_dn) { |
335 | 363 | location = of_get_property(eeh_dev_to_of_node(event->edev), "ibm,loc-code", NULL); | |
336 | location = of_get_property(event->dn, "ibm,loc-code", NULL); | ||
337 | location = location ? location : "unknown"; | 364 | location = location ? location : "unknown"; |
338 | printk(KERN_ERR "EEH: Error: Cannot find partition endpoint " | 365 | printk(KERN_ERR "EEH: Error: Cannot find partition endpoint " |
339 | "for location=%s pci addr=%s\n", | 366 | "for location=%s pci addr=%s\n", |
340 | location, eeh_pci_name(event->dev)); | 367 | location, eeh_pci_name(eeh_dev_to_pci_dev(event->edev))); |
341 | return NULL; | 368 | return NULL; |
342 | } | 369 | } |
343 | 370 | ||
@@ -350,9 +377,10 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event) | |||
350 | * which was always an EADS pci bridge. In the new style, | 377 | * which was always an EADS pci bridge. In the new style, |
351 | * there might not be any EADS bridges, and even when there are, | 378 | * there might not be any EADS bridges, and even when there are, |
352 | * the firmware marks them as "EEH incapable". So another | 379 | * the firmware marks them as "EEH incapable". So another |
353 | * two-step is needed to find the pci bus.. */ | 380 | * two-step is needed to find the pci bus.. |
381 | */ | ||
354 | if (!frozen_bus) | 382 | if (!frozen_bus) |
355 | frozen_bus = pcibios_find_pci_bus (frozen_dn->parent); | 383 | frozen_bus = pcibios_find_pci_bus(frozen_dn->parent); |
356 | 384 | ||
357 | if (!frozen_bus) { | 385 | if (!frozen_bus) { |
358 | printk(KERN_ERR "EEH: Cannot find PCI bus " | 386 | printk(KERN_ERR "EEH: Cannot find PCI bus " |
@@ -361,22 +389,21 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event) | |||
361 | return NULL; | 389 | return NULL; |
362 | } | 390 | } |
363 | 391 | ||
364 | frozen_pdn = PCI_DN(frozen_dn); | 392 | frozen_edev = of_node_to_eeh_dev(frozen_dn); |
365 | frozen_pdn->eeh_freeze_count++; | 393 | frozen_edev->freeze_count++; |
394 | pci_str = eeh_pci_name(eeh_dev_to_pci_dev(event->edev)); | ||
395 | drv_str = eeh_pcid_name(eeh_dev_to_pci_dev(event->edev)); | ||
366 | 396 | ||
367 | pci_str = eeh_pci_name(event->dev); | 397 | if (frozen_edev->freeze_count > EEH_MAX_ALLOWED_FREEZES) |
368 | drv_str = pcid_name(event->dev); | ||
369 | |||
370 | if (frozen_pdn->eeh_freeze_count > EEH_MAX_ALLOWED_FREEZES) | ||
371 | goto excess_failures; | 398 | goto excess_failures; |
372 | 399 | ||
373 | printk(KERN_WARNING | 400 | printk(KERN_WARNING |
374 | "EEH: This PCI device has failed %d times in the last hour:\n", | 401 | "EEH: This PCI device has failed %d times in the last hour:\n", |
375 | frozen_pdn->eeh_freeze_count); | 402 | frozen_edev->freeze_count); |
376 | 403 | ||
377 | if (frozen_pdn->pcidev) { | 404 | if (frozen_edev->pdev) { |
378 | bus_pci_str = pci_name(frozen_pdn->pcidev); | 405 | bus_pci_str = pci_name(frozen_edev->pdev); |
379 | bus_drv_str = pcid_name(frozen_pdn->pcidev); | 406 | bus_drv_str = eeh_pcid_name(frozen_edev->pdev); |
380 | printk(KERN_WARNING | 407 | printk(KERN_WARNING |
381 | "EEH: Bus location=%s driver=%s pci addr=%s\n", | 408 | "EEH: Bus location=%s driver=%s pci addr=%s\n", |
382 | location, bus_drv_str, bus_pci_str); | 409 | location, bus_drv_str, bus_pci_str); |
@@ -395,9 +422,10 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event) | |||
395 | pci_walk_bus(frozen_bus, eeh_report_error, &result); | 422 | pci_walk_bus(frozen_bus, eeh_report_error, &result); |
396 | 423 | ||
397 | /* Get the current PCI slot state. This can take a long time, | 424 | /* Get the current PCI slot state. This can take a long time, |
398 | * sometimes over 3 seconds for certain systems. */ | 425 | * sometimes over 3 seconds for certain systems. |
399 | rc = eeh_wait_for_slot_status (frozen_pdn, MAX_WAIT_FOR_RECOVERY*1000); | 426 | */ |
400 | if (rc < 0) { | 427 | rc = eeh_ops->wait_state(eeh_dev_to_of_node(frozen_edev), MAX_WAIT_FOR_RECOVERY*1000); |
428 | if (rc < 0 || rc == EEH_STATE_NOT_SUPPORT) { | ||
401 | printk(KERN_WARNING "EEH: Permanent failure\n"); | 429 | printk(KERN_WARNING "EEH: Permanent failure\n"); |
402 | goto hard_fail; | 430 | goto hard_fail; |
403 | } | 431 | } |
@@ -406,14 +434,14 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event) | |||
406 | * don't post the error log until after all dev drivers | 434 | * don't post the error log until after all dev drivers |
407 | * have been informed. | 435 | * have been informed. |
408 | */ | 436 | */ |
409 | eeh_slot_error_detail(frozen_pdn, EEH_LOG_TEMP_FAILURE); | 437 | eeh_slot_error_detail(frozen_edev, EEH_LOG_TEMP); |
410 | 438 | ||
411 | /* If all device drivers were EEH-unaware, then shut | 439 | /* If all device drivers were EEH-unaware, then shut |
412 | * down all of the device drivers, and hope they | 440 | * down all of the device drivers, and hope they |
413 | * go down willingly, without panicing the system. | 441 | * go down willingly, without panicing the system. |
414 | */ | 442 | */ |
415 | if (result == PCI_ERS_RESULT_NONE) { | 443 | if (result == PCI_ERS_RESULT_NONE) { |
416 | rc = eeh_reset_device(frozen_pdn, frozen_bus); | 444 | rc = eeh_reset_device(frozen_edev, frozen_bus); |
417 | if (rc) { | 445 | if (rc) { |
418 | printk(KERN_WARNING "EEH: Unable to reset, rc=%d\n", rc); | 446 | printk(KERN_WARNING "EEH: Unable to reset, rc=%d\n", rc); |
419 | goto hard_fail; | 447 | goto hard_fail; |
@@ -422,7 +450,7 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event) | |||
422 | 450 | ||
423 | /* If all devices reported they can proceed, then re-enable MMIO */ | 451 | /* If all devices reported they can proceed, then re-enable MMIO */ |
424 | if (result == PCI_ERS_RESULT_CAN_RECOVER) { | 452 | if (result == PCI_ERS_RESULT_CAN_RECOVER) { |
425 | rc = rtas_pci_enable(frozen_pdn, EEH_THAW_MMIO); | 453 | rc = eeh_pci_enable(frozen_edev, EEH_OPT_THAW_MMIO); |
426 | 454 | ||
427 | if (rc < 0) | 455 | if (rc < 0) |
428 | goto hard_fail; | 456 | goto hard_fail; |
@@ -436,7 +464,7 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event) | |||
436 | 464 | ||
437 | /* If all devices reported they can proceed, then re-enable DMA */ | 465 | /* If all devices reported they can proceed, then re-enable DMA */ |
438 | if (result == PCI_ERS_RESULT_CAN_RECOVER) { | 466 | if (result == PCI_ERS_RESULT_CAN_RECOVER) { |
439 | rc = rtas_pci_enable(frozen_pdn, EEH_THAW_DMA); | 467 | rc = eeh_pci_enable(frozen_edev, EEH_OPT_THAW_DMA); |
440 | 468 | ||
441 | if (rc < 0) | 469 | if (rc < 0) |
442 | goto hard_fail; | 470 | goto hard_fail; |
@@ -454,7 +482,7 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event) | |||
454 | 482 | ||
455 | /* If any device called out for a reset, then reset the slot */ | 483 | /* If any device called out for a reset, then reset the slot */ |
456 | if (result == PCI_ERS_RESULT_NEED_RESET) { | 484 | if (result == PCI_ERS_RESULT_NEED_RESET) { |
457 | rc = eeh_reset_device(frozen_pdn, NULL); | 485 | rc = eeh_reset_device(frozen_edev, NULL); |
458 | if (rc) { | 486 | if (rc) { |
459 | printk(KERN_WARNING "EEH: Cannot reset, rc=%d\n", rc); | 487 | printk(KERN_WARNING "EEH: Cannot reset, rc=%d\n", rc); |
460 | goto hard_fail; | 488 | goto hard_fail; |
@@ -473,7 +501,7 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event) | |||
473 | /* Tell all device drivers that they can resume operations */ | 501 | /* Tell all device drivers that they can resume operations */ |
474 | pci_walk_bus(frozen_bus, eeh_report_resume, NULL); | 502 | pci_walk_bus(frozen_bus, eeh_report_resume, NULL); |
475 | 503 | ||
476 | return frozen_pdn; | 504 | return frozen_edev; |
477 | 505 | ||
478 | excess_failures: | 506 | excess_failures: |
479 | /* | 507 | /* |
@@ -486,7 +514,7 @@ excess_failures: | |||
486 | "has failed %d times in the last hour " | 514 | "has failed %d times in the last hour " |
487 | "and has been permanently disabled.\n" | 515 | "and has been permanently disabled.\n" |
488 | "Please try reseating this device or replacing it.\n", | 516 | "Please try reseating this device or replacing it.\n", |
489 | location, drv_str, pci_str, frozen_pdn->eeh_freeze_count); | 517 | location, drv_str, pci_str, frozen_edev->freeze_count); |
490 | goto perm_error; | 518 | goto perm_error; |
491 | 519 | ||
492 | hard_fail: | 520 | hard_fail: |
@@ -497,7 +525,7 @@ hard_fail: | |||
497 | location, drv_str, pci_str); | 525 | location, drv_str, pci_str); |
498 | 526 | ||
499 | perm_error: | 527 | perm_error: |
500 | eeh_slot_error_detail(frozen_pdn, EEH_LOG_PERM_FAILURE); | 528 | eeh_slot_error_detail(frozen_edev, EEH_LOG_PERM); |
501 | 529 | ||
502 | /* Notify all devices that they're about to go down. */ | 530 | /* Notify all devices that they're about to go down. */ |
503 | pci_walk_bus(frozen_bus, eeh_report_failure, NULL); | 531 | pci_walk_bus(frozen_bus, eeh_report_failure, NULL); |
@@ -508,4 +536,3 @@ perm_error: | |||
508 | return NULL; | 536 | return NULL; |
509 | } | 537 | } |
510 | 538 | ||
511 | /* ---------- end of file ---------- */ | ||
diff --git a/arch/powerpc/platforms/pseries/eeh_event.c b/arch/powerpc/platforms/pseries/eeh_event.c index d2383cfb6dfd..4a4752565856 100644 --- a/arch/powerpc/platforms/pseries/eeh_event.c +++ b/arch/powerpc/platforms/pseries/eeh_event.c | |||
@@ -1,6 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * eeh_event.c | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | 2 | * This program is free software; you can redistribute it and/or modify |
5 | * it under the terms of the GNU General Public License as published by | 3 | * it under the terms of the GNU General Public License as published by |
6 | * the Free Software Foundation; either version 2 of the License, or | 4 | * the Free Software Foundation; either version 2 of the License, or |
@@ -46,7 +44,7 @@ DECLARE_WORK(eeh_event_wq, eeh_thread_launcher); | |||
46 | DEFINE_MUTEX(eeh_event_mutex); | 44 | DEFINE_MUTEX(eeh_event_mutex); |
47 | 45 | ||
48 | /** | 46 | /** |
49 | * eeh_event_handler - dispatch EEH events. | 47 | * eeh_event_handler - Dispatch EEH events. |
50 | * @dummy - unused | 48 | * @dummy - unused |
51 | * | 49 | * |
52 | * The detection of a frozen slot can occur inside an interrupt, | 50 | * The detection of a frozen slot can occur inside an interrupt, |
@@ -58,10 +56,10 @@ DEFINE_MUTEX(eeh_event_mutex); | |||
58 | static int eeh_event_handler(void * dummy) | 56 | static int eeh_event_handler(void * dummy) |
59 | { | 57 | { |
60 | unsigned long flags; | 58 | unsigned long flags; |
61 | struct eeh_event *event; | 59 | struct eeh_event *event; |
62 | struct pci_dn *pdn; | 60 | struct eeh_dev *edev; |
63 | 61 | ||
64 | daemonize ("eehd"); | 62 | daemonize("eehd"); |
65 | set_current_state(TASK_INTERRUPTIBLE); | 63 | set_current_state(TASK_INTERRUPTIBLE); |
66 | 64 | ||
67 | spin_lock_irqsave(&eeh_eventlist_lock, flags); | 65 | spin_lock_irqsave(&eeh_eventlist_lock, flags); |
@@ -79,31 +77,37 @@ static int eeh_event_handler(void * dummy) | |||
79 | 77 | ||
80 | /* Serialize processing of EEH events */ | 78 | /* Serialize processing of EEH events */ |
81 | mutex_lock(&eeh_event_mutex); | 79 | mutex_lock(&eeh_event_mutex); |
82 | eeh_mark_slot(event->dn, EEH_MODE_RECOVERING); | 80 | edev = event->edev; |
81 | eeh_mark_slot(eeh_dev_to_of_node(edev), EEH_MODE_RECOVERING); | ||
83 | 82 | ||
84 | printk(KERN_INFO "EEH: Detected PCI bus error on device %s\n", | 83 | printk(KERN_INFO "EEH: Detected PCI bus error on device %s\n", |
85 | eeh_pci_name(event->dev)); | 84 | eeh_pci_name(edev->pdev)); |
85 | |||
86 | edev = handle_eeh_events(event); | ||
86 | 87 | ||
87 | pdn = handle_eeh_events(event); | 88 | eeh_clear_slot(eeh_dev_to_of_node(edev), EEH_MODE_RECOVERING); |
89 | pci_dev_put(edev->pdev); | ||
88 | 90 | ||
89 | eeh_clear_slot(event->dn, EEH_MODE_RECOVERING); | ||
90 | pci_dev_put(event->dev); | ||
91 | kfree(event); | 91 | kfree(event); |
92 | mutex_unlock(&eeh_event_mutex); | 92 | mutex_unlock(&eeh_event_mutex); |
93 | 93 | ||
94 | /* If there are no new errors after an hour, clear the counter. */ | 94 | /* If there are no new errors after an hour, clear the counter. */ |
95 | if (pdn && pdn->eeh_freeze_count>0) { | 95 | if (edev && edev->freeze_count>0) { |
96 | msleep_interruptible (3600*1000); | 96 | msleep_interruptible(3600*1000); |
97 | if (pdn->eeh_freeze_count>0) | 97 | if (edev->freeze_count>0) |
98 | pdn->eeh_freeze_count--; | 98 | edev->freeze_count--; |
99 | |||
99 | } | 100 | } |
100 | 101 | ||
101 | return 0; | 102 | return 0; |
102 | } | 103 | } |
103 | 104 | ||
104 | /** | 105 | /** |
105 | * eeh_thread_launcher | 106 | * eeh_thread_launcher - Start kernel thread to handle EEH events |
106 | * @dummy - unused | 107 | * @dummy - unused |
108 | * | ||
109 | * This routine is called to start the kernel thread for processing | ||
110 | * EEH event. | ||
107 | */ | 111 | */ |
108 | static void eeh_thread_launcher(struct work_struct *dummy) | 112 | static void eeh_thread_launcher(struct work_struct *dummy) |
109 | { | 113 | { |
@@ -112,18 +116,18 @@ static void eeh_thread_launcher(struct work_struct *dummy) | |||
112 | } | 116 | } |
113 | 117 | ||
114 | /** | 118 | /** |
115 | * eeh_send_failure_event - generate a PCI error event | 119 | * eeh_send_failure_event - Generate a PCI error event |
116 | * @dev pci device | 120 | * @edev: EEH device |
117 | * | 121 | * |
118 | * This routine can be called within an interrupt context; | 122 | * This routine can be called within an interrupt context; |
119 | * the actual event will be delivered in a normal context | 123 | * the actual event will be delivered in a normal context |
120 | * (from a workqueue). | 124 | * (from a workqueue). |
121 | */ | 125 | */ |
122 | int eeh_send_failure_event (struct device_node *dn, | 126 | int eeh_send_failure_event(struct eeh_dev *edev) |
123 | struct pci_dev *dev) | ||
124 | { | 127 | { |
125 | unsigned long flags; | 128 | unsigned long flags; |
126 | struct eeh_event *event; | 129 | struct eeh_event *event; |
130 | struct device_node *dn = eeh_dev_to_of_node(edev); | ||
127 | const char *location; | 131 | const char *location; |
128 | 132 | ||
129 | if (!mem_init_done) { | 133 | if (!mem_init_done) { |
@@ -135,15 +139,14 @@ int eeh_send_failure_event (struct device_node *dn, | |||
135 | } | 139 | } |
136 | event = kmalloc(sizeof(*event), GFP_ATOMIC); | 140 | event = kmalloc(sizeof(*event), GFP_ATOMIC); |
137 | if (event == NULL) { | 141 | if (event == NULL) { |
138 | printk (KERN_ERR "EEH: out of memory, event not handled\n"); | 142 | printk(KERN_ERR "EEH: out of memory, event not handled\n"); |
139 | return 1; | 143 | return 1; |
140 | } | 144 | } |
141 | 145 | ||
142 | if (dev) | 146 | if (edev->pdev) |
143 | pci_dev_get(dev); | 147 | pci_dev_get(edev->pdev); |
144 | 148 | ||
145 | event->dn = dn; | 149 | event->edev = edev; |
146 | event->dev = dev; | ||
147 | 150 | ||
148 | /* We may or may not be called in an interrupt context */ | 151 | /* We may or may not be called in an interrupt context */ |
149 | spin_lock_irqsave(&eeh_eventlist_lock, flags); | 152 | spin_lock_irqsave(&eeh_eventlist_lock, flags); |
@@ -154,5 +157,3 @@ int eeh_send_failure_event (struct device_node *dn, | |||
154 | 157 | ||
155 | return 0; | 158 | return 0; |
156 | } | 159 | } |
157 | |||
158 | /********************** END OF FILE ******************************/ | ||
diff --git a/arch/powerpc/platforms/pseries/eeh_pseries.c b/arch/powerpc/platforms/pseries/eeh_pseries.c new file mode 100644 index 000000000000..8752f79a6af8 --- /dev/null +++ b/arch/powerpc/platforms/pseries/eeh_pseries.c | |||
@@ -0,0 +1,565 @@ | |||
1 | /* | ||
2 | * The file intends to implement the platform dependent EEH operations on pseries. | ||
3 | * Actually, the pseries platform is built based on RTAS heavily. That means the | ||
4 | * pseries platform dependent EEH operations will be built on RTAS calls. The functions | ||
5 | * are devired from arch/powerpc/platforms/pseries/eeh.c and necessary cleanup has | ||
6 | * been done. | ||
7 | * | ||
8 | * Copyright Benjamin Herrenschmidt & Gavin Shan, IBM Corporation 2011. | ||
9 | * Copyright IBM Corporation 2001, 2005, 2006 | ||
10 | * Copyright Dave Engebretsen & Todd Inglett 2001 | ||
11 | * Copyright Linas Vepstas 2005, 2006 | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation; either version 2 of the License, or | ||
16 | * (at your option) any later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, write to the Free Software | ||
25 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
26 | */ | ||
27 | |||
28 | #include <linux/atomic.h> | ||
29 | #include <linux/delay.h> | ||
30 | #include <linux/export.h> | ||
31 | #include <linux/init.h> | ||
32 | #include <linux/list.h> | ||
33 | #include <linux/of.h> | ||
34 | #include <linux/pci.h> | ||
35 | #include <linux/proc_fs.h> | ||
36 | #include <linux/rbtree.h> | ||
37 | #include <linux/sched.h> | ||
38 | #include <linux/seq_file.h> | ||
39 | #include <linux/spinlock.h> | ||
40 | |||
41 | #include <asm/eeh.h> | ||
42 | #include <asm/eeh_event.h> | ||
43 | #include <asm/io.h> | ||
44 | #include <asm/machdep.h> | ||
45 | #include <asm/ppc-pci.h> | ||
46 | #include <asm/rtas.h> | ||
47 | |||
48 | /* RTAS tokens */ | ||
49 | static int ibm_set_eeh_option; | ||
50 | static int ibm_set_slot_reset; | ||
51 | static int ibm_read_slot_reset_state; | ||
52 | static int ibm_read_slot_reset_state2; | ||
53 | static int ibm_slot_error_detail; | ||
54 | static int ibm_get_config_addr_info; | ||
55 | static int ibm_get_config_addr_info2; | ||
56 | static int ibm_configure_bridge; | ||
57 | static int ibm_configure_pe; | ||
58 | |||
59 | /* | ||
60 | * Buffer for reporting slot-error-detail rtas calls. Its here | ||
61 | * in BSS, and not dynamically alloced, so that it ends up in | ||
62 | * RMO where RTAS can access it. | ||
63 | */ | ||
64 | static unsigned char slot_errbuf[RTAS_ERROR_LOG_MAX]; | ||
65 | static DEFINE_SPINLOCK(slot_errbuf_lock); | ||
66 | static int eeh_error_buf_size; | ||
67 | |||
68 | /** | ||
69 | * pseries_eeh_init - EEH platform dependent initialization | ||
70 | * | ||
71 | * EEH platform dependent initialization on pseries. | ||
72 | */ | ||
73 | static int pseries_eeh_init(void) | ||
74 | { | ||
75 | /* figure out EEH RTAS function call tokens */ | ||
76 | ibm_set_eeh_option = rtas_token("ibm,set-eeh-option"); | ||
77 | ibm_set_slot_reset = rtas_token("ibm,set-slot-reset"); | ||
78 | ibm_read_slot_reset_state2 = rtas_token("ibm,read-slot-reset-state2"); | ||
79 | ibm_read_slot_reset_state = rtas_token("ibm,read-slot-reset-state"); | ||
80 | ibm_slot_error_detail = rtas_token("ibm,slot-error-detail"); | ||
81 | ibm_get_config_addr_info2 = rtas_token("ibm,get-config-addr-info2"); | ||
82 | ibm_get_config_addr_info = rtas_token("ibm,get-config-addr-info"); | ||
83 | ibm_configure_pe = rtas_token("ibm,configure-pe"); | ||
84 | ibm_configure_bridge = rtas_token ("ibm,configure-bridge"); | ||
85 | |||
86 | /* necessary sanity check */ | ||
87 | if (ibm_set_eeh_option == RTAS_UNKNOWN_SERVICE) { | ||
88 | pr_warning("%s: RTAS service <ibm,set-eeh-option> invalid\n", | ||
89 | __func__); | ||
90 | return -EINVAL; | ||
91 | } else if (ibm_set_slot_reset == RTAS_UNKNOWN_SERVICE) { | ||
92 | pr_warning("%s: RTAS service <ibm, set-slot-reset> invalid\n", | ||
93 | __func__); | ||
94 | return -EINVAL; | ||
95 | } else if (ibm_read_slot_reset_state2 == RTAS_UNKNOWN_SERVICE && | ||
96 | ibm_read_slot_reset_state == RTAS_UNKNOWN_SERVICE) { | ||
97 | pr_warning("%s: RTAS service <ibm,read-slot-reset-state2> and " | ||
98 | "<ibm,read-slot-reset-state> invalid\n", | ||
99 | __func__); | ||
100 | return -EINVAL; | ||
101 | } else if (ibm_slot_error_detail == RTAS_UNKNOWN_SERVICE) { | ||
102 | pr_warning("%s: RTAS service <ibm,slot-error-detail> invalid\n", | ||
103 | __func__); | ||
104 | return -EINVAL; | ||
105 | } else if (ibm_get_config_addr_info2 == RTAS_UNKNOWN_SERVICE && | ||
106 | ibm_get_config_addr_info == RTAS_UNKNOWN_SERVICE) { | ||
107 | pr_warning("%s: RTAS service <ibm,get-config-addr-info2> and " | ||
108 | "<ibm,get-config-addr-info> invalid\n", | ||
109 | __func__); | ||
110 | return -EINVAL; | ||
111 | } else if (ibm_configure_pe == RTAS_UNKNOWN_SERVICE && | ||
112 | ibm_configure_bridge == RTAS_UNKNOWN_SERVICE) { | ||
113 | pr_warning("%s: RTAS service <ibm,configure-pe> and " | ||
114 | "<ibm,configure-bridge> invalid\n", | ||
115 | __func__); | ||
116 | return -EINVAL; | ||
117 | } | ||
118 | |||
119 | /* Initialize error log lock and size */ | ||
120 | spin_lock_init(&slot_errbuf_lock); | ||
121 | eeh_error_buf_size = rtas_token("rtas-error-log-max"); | ||
122 | if (eeh_error_buf_size == RTAS_UNKNOWN_SERVICE) { | ||
123 | pr_warning("%s: unknown EEH error log size\n", | ||
124 | __func__); | ||
125 | eeh_error_buf_size = 1024; | ||
126 | } else if (eeh_error_buf_size > RTAS_ERROR_LOG_MAX) { | ||
127 | pr_warning("%s: EEH error log size %d exceeds the maximal %d\n", | ||
128 | __func__, eeh_error_buf_size, RTAS_ERROR_LOG_MAX); | ||
129 | eeh_error_buf_size = RTAS_ERROR_LOG_MAX; | ||
130 | } | ||
131 | |||
132 | return 0; | ||
133 | } | ||
134 | |||
135 | /** | ||
136 | * pseries_eeh_set_option - Initialize EEH or MMIO/DMA reenable | ||
137 | * @dn: device node | ||
138 | * @option: operation to be issued | ||
139 | * | ||
140 | * The function is used to control the EEH functionality globally. | ||
141 | * Currently, following options are support according to PAPR: | ||
142 | * Enable EEH, Disable EEH, Enable MMIO and Enable DMA | ||
143 | */ | ||
144 | static int pseries_eeh_set_option(struct device_node *dn, int option) | ||
145 | { | ||
146 | int ret = 0; | ||
147 | struct eeh_dev *edev; | ||
148 | const u32 *reg; | ||
149 | int config_addr; | ||
150 | |||
151 | edev = of_node_to_eeh_dev(dn); | ||
152 | |||
153 | /* | ||
154 | * When we're enabling or disabling EEH functioality on | ||
155 | * the particular PE, the PE config address is possibly | ||
156 | * unavailable. Therefore, we have to figure it out from | ||
157 | * the FDT node. | ||
158 | */ | ||
159 | switch (option) { | ||
160 | case EEH_OPT_DISABLE: | ||
161 | case EEH_OPT_ENABLE: | ||
162 | reg = of_get_property(dn, "reg", NULL); | ||
163 | config_addr = reg[0]; | ||
164 | break; | ||
165 | |||
166 | case EEH_OPT_THAW_MMIO: | ||
167 | case EEH_OPT_THAW_DMA: | ||
168 | config_addr = edev->config_addr; | ||
169 | if (edev->pe_config_addr) | ||
170 | config_addr = edev->pe_config_addr; | ||
171 | break; | ||
172 | |||
173 | default: | ||
174 | pr_err("%s: Invalid option %d\n", | ||
175 | __func__, option); | ||
176 | return -EINVAL; | ||
177 | } | ||
178 | |||
179 | ret = rtas_call(ibm_set_eeh_option, 4, 1, NULL, | ||
180 | config_addr, BUID_HI(edev->phb->buid), | ||
181 | BUID_LO(edev->phb->buid), option); | ||
182 | |||
183 | return ret; | ||
184 | } | ||
185 | |||
186 | /** | ||
187 | * pseries_eeh_get_pe_addr - Retrieve PE address | ||
188 | * @dn: device node | ||
189 | * | ||
190 | * Retrieve the assocated PE address. Actually, there're 2 RTAS | ||
191 | * function calls dedicated for the purpose. We need implement | ||
192 | * it through the new function and then the old one. Besides, | ||
193 | * you should make sure the config address is figured out from | ||
194 | * FDT node before calling the function. | ||
195 | * | ||
196 | * It's notable that zero'ed return value means invalid PE config | ||
197 | * address. | ||
198 | */ | ||
199 | static int pseries_eeh_get_pe_addr(struct device_node *dn) | ||
200 | { | ||
201 | struct eeh_dev *edev; | ||
202 | int ret = 0; | ||
203 | int rets[3]; | ||
204 | |||
205 | edev = of_node_to_eeh_dev(dn); | ||
206 | |||
207 | if (ibm_get_config_addr_info2 != RTAS_UNKNOWN_SERVICE) { | ||
208 | /* | ||
209 | * First of all, we need to make sure there has one PE | ||
210 | * associated with the device. Otherwise, PE address is | ||
211 | * meaningless. | ||
212 | */ | ||
213 | ret = rtas_call(ibm_get_config_addr_info2, 4, 2, rets, | ||
214 | edev->config_addr, BUID_HI(edev->phb->buid), | ||
215 | BUID_LO(edev->phb->buid), 1); | ||
216 | if (ret || (rets[0] == 0)) | ||
217 | return 0; | ||
218 | |||
219 | /* Retrieve the associated PE config address */ | ||
220 | ret = rtas_call(ibm_get_config_addr_info2, 4, 2, rets, | ||
221 | edev->config_addr, BUID_HI(edev->phb->buid), | ||
222 | BUID_LO(edev->phb->buid), 0); | ||
223 | if (ret) { | ||
224 | pr_warning("%s: Failed to get PE address for %s\n", | ||
225 | __func__, dn->full_name); | ||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | return rets[0]; | ||
230 | } | ||
231 | |||
232 | if (ibm_get_config_addr_info != RTAS_UNKNOWN_SERVICE) { | ||
233 | ret = rtas_call(ibm_get_config_addr_info, 4, 2, rets, | ||
234 | edev->config_addr, BUID_HI(edev->phb->buid), | ||
235 | BUID_LO(edev->phb->buid), 0); | ||
236 | if (ret) { | ||
237 | pr_warning("%s: Failed to get PE address for %s\n", | ||
238 | __func__, dn->full_name); | ||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | return rets[0]; | ||
243 | } | ||
244 | |||
245 | return ret; | ||
246 | } | ||
247 | |||
248 | /** | ||
249 | * pseries_eeh_get_state - Retrieve PE state | ||
250 | * @dn: PE associated device node | ||
251 | * @state: return value | ||
252 | * | ||
253 | * Retrieve the state of the specified PE. On RTAS compliant | ||
254 | * pseries platform, there already has one dedicated RTAS function | ||
255 | * for the purpose. It's notable that the associated PE config address | ||
256 | * might be ready when calling the function. Therefore, endeavour to | ||
257 | * use the PE config address if possible. Further more, there're 2 | ||
258 | * RTAS calls for the purpose, we need to try the new one and back | ||
259 | * to the old one if the new one couldn't work properly. | ||
260 | */ | ||
261 | static int pseries_eeh_get_state(struct device_node *dn, int *state) | ||
262 | { | ||
263 | struct eeh_dev *edev; | ||
264 | int config_addr; | ||
265 | int ret; | ||
266 | int rets[4]; | ||
267 | int result; | ||
268 | |||
269 | /* Figure out PE config address if possible */ | ||
270 | edev = of_node_to_eeh_dev(dn); | ||
271 | config_addr = edev->config_addr; | ||
272 | if (edev->pe_config_addr) | ||
273 | config_addr = edev->pe_config_addr; | ||
274 | |||
275 | if (ibm_read_slot_reset_state2 != RTAS_UNKNOWN_SERVICE) { | ||
276 | ret = rtas_call(ibm_read_slot_reset_state2, 3, 4, rets, | ||
277 | config_addr, BUID_HI(edev->phb->buid), | ||
278 | BUID_LO(edev->phb->buid)); | ||
279 | } else if (ibm_read_slot_reset_state != RTAS_UNKNOWN_SERVICE) { | ||
280 | /* Fake PE unavailable info */ | ||
281 | rets[2] = 0; | ||
282 | ret = rtas_call(ibm_read_slot_reset_state, 3, 3, rets, | ||
283 | config_addr, BUID_HI(edev->phb->buid), | ||
284 | BUID_LO(edev->phb->buid)); | ||
285 | } else { | ||
286 | return EEH_STATE_NOT_SUPPORT; | ||
287 | } | ||
288 | |||
289 | if (ret) | ||
290 | return ret; | ||
291 | |||
292 | /* Parse the result out */ | ||
293 | result = 0; | ||
294 | if (rets[1]) { | ||
295 | switch(rets[0]) { | ||
296 | case 0: | ||
297 | result &= ~EEH_STATE_RESET_ACTIVE; | ||
298 | result |= EEH_STATE_MMIO_ACTIVE; | ||
299 | result |= EEH_STATE_DMA_ACTIVE; | ||
300 | break; | ||
301 | case 1: | ||
302 | result |= EEH_STATE_RESET_ACTIVE; | ||
303 | result |= EEH_STATE_MMIO_ACTIVE; | ||
304 | result |= EEH_STATE_DMA_ACTIVE; | ||
305 | break; | ||
306 | case 2: | ||
307 | result &= ~EEH_STATE_RESET_ACTIVE; | ||
308 | result &= ~EEH_STATE_MMIO_ACTIVE; | ||
309 | result &= ~EEH_STATE_DMA_ACTIVE; | ||
310 | break; | ||
311 | case 4: | ||
312 | result &= ~EEH_STATE_RESET_ACTIVE; | ||
313 | result &= ~EEH_STATE_MMIO_ACTIVE; | ||
314 | result &= ~EEH_STATE_DMA_ACTIVE; | ||
315 | result |= EEH_STATE_MMIO_ENABLED; | ||
316 | break; | ||
317 | case 5: | ||
318 | if (rets[2]) { | ||
319 | if (state) *state = rets[2]; | ||
320 | result = EEH_STATE_UNAVAILABLE; | ||
321 | } else { | ||
322 | result = EEH_STATE_NOT_SUPPORT; | ||
323 | } | ||
324 | default: | ||
325 | result = EEH_STATE_NOT_SUPPORT; | ||
326 | } | ||
327 | } else { | ||
328 | result = EEH_STATE_NOT_SUPPORT; | ||
329 | } | ||
330 | |||
331 | return result; | ||
332 | } | ||
333 | |||
334 | /** | ||
335 | * pseries_eeh_reset - Reset the specified PE | ||
336 | * @dn: PE associated device node | ||
337 | * @option: reset option | ||
338 | * | ||
339 | * Reset the specified PE | ||
340 | */ | ||
341 | static int pseries_eeh_reset(struct device_node *dn, int option) | ||
342 | { | ||
343 | struct eeh_dev *edev; | ||
344 | int config_addr; | ||
345 | int ret; | ||
346 | |||
347 | /* Figure out PE address */ | ||
348 | edev = of_node_to_eeh_dev(dn); | ||
349 | config_addr = edev->config_addr; | ||
350 | if (edev->pe_config_addr) | ||
351 | config_addr = edev->pe_config_addr; | ||
352 | |||
353 | /* Reset PE through RTAS call */ | ||
354 | ret = rtas_call(ibm_set_slot_reset, 4, 1, NULL, | ||
355 | config_addr, BUID_HI(edev->phb->buid), | ||
356 | BUID_LO(edev->phb->buid), option); | ||
357 | |||
358 | /* If fundamental-reset not supported, try hot-reset */ | ||
359 | if (option == EEH_RESET_FUNDAMENTAL && | ||
360 | ret == -8) { | ||
361 | ret = rtas_call(ibm_set_slot_reset, 4, 1, NULL, | ||
362 | config_addr, BUID_HI(edev->phb->buid), | ||
363 | BUID_LO(edev->phb->buid), EEH_RESET_HOT); | ||
364 | } | ||
365 | |||
366 | return ret; | ||
367 | } | ||
368 | |||
369 | /** | ||
370 | * pseries_eeh_wait_state - Wait for PE state | ||
371 | * @dn: PE associated device node | ||
372 | * @max_wait: maximal period in microsecond | ||
373 | * | ||
374 | * Wait for the state of associated PE. It might take some time | ||
375 | * to retrieve the PE's state. | ||
376 | */ | ||
377 | static int pseries_eeh_wait_state(struct device_node *dn, int max_wait) | ||
378 | { | ||
379 | int ret; | ||
380 | int mwait; | ||
381 | |||
382 | /* | ||
383 | * According to PAPR, the state of PE might be temporarily | ||
384 | * unavailable. Under the circumstance, we have to wait | ||
385 | * for indicated time determined by firmware. The maximal | ||
386 | * wait time is 5 minutes, which is acquired from the original | ||
387 | * EEH implementation. Also, the original implementation | ||
388 | * also defined the minimal wait time as 1 second. | ||
389 | */ | ||
390 | #define EEH_STATE_MIN_WAIT_TIME (1000) | ||
391 | #define EEH_STATE_MAX_WAIT_TIME (300 * 1000) | ||
392 | |||
393 | while (1) { | ||
394 | ret = pseries_eeh_get_state(dn, &mwait); | ||
395 | |||
396 | /* | ||
397 | * If the PE's state is temporarily unavailable, | ||
398 | * we have to wait for the specified time. Otherwise, | ||
399 | * the PE's state will be returned immediately. | ||
400 | */ | ||
401 | if (ret != EEH_STATE_UNAVAILABLE) | ||
402 | return ret; | ||
403 | |||
404 | if (max_wait <= 0) { | ||
405 | pr_warning("%s: Timeout when getting PE's state (%d)\n", | ||
406 | __func__, max_wait); | ||
407 | return EEH_STATE_NOT_SUPPORT; | ||
408 | } | ||
409 | |||
410 | if (mwait <= 0) { | ||
411 | pr_warning("%s: Firmware returned bad wait value %d\n", | ||
412 | __func__, mwait); | ||
413 | mwait = EEH_STATE_MIN_WAIT_TIME; | ||
414 | } else if (mwait > EEH_STATE_MAX_WAIT_TIME) { | ||
415 | pr_warning("%s: Firmware returned too long wait value %d\n", | ||
416 | __func__, mwait); | ||
417 | mwait = EEH_STATE_MAX_WAIT_TIME; | ||
418 | } | ||
419 | |||
420 | max_wait -= mwait; | ||
421 | msleep(mwait); | ||
422 | } | ||
423 | |||
424 | return EEH_STATE_NOT_SUPPORT; | ||
425 | } | ||
426 | |||
427 | /** | ||
428 | * pseries_eeh_get_log - Retrieve error log | ||
429 | * @dn: device node | ||
430 | * @severity: temporary or permanent error log | ||
431 | * @drv_log: driver log to be combined with retrieved error log | ||
432 | * @len: length of driver log | ||
433 | * | ||
434 | * Retrieve the temporary or permanent error from the PE. | ||
435 | * Actually, the error will be retrieved through the dedicated | ||
436 | * RTAS call. | ||
437 | */ | ||
438 | static int pseries_eeh_get_log(struct device_node *dn, int severity, char *drv_log, unsigned long len) | ||
439 | { | ||
440 | struct eeh_dev *edev; | ||
441 | int config_addr; | ||
442 | unsigned long flags; | ||
443 | int ret; | ||
444 | |||
445 | edev = of_node_to_eeh_dev(dn); | ||
446 | spin_lock_irqsave(&slot_errbuf_lock, flags); | ||
447 | memset(slot_errbuf, 0, eeh_error_buf_size); | ||
448 | |||
449 | /* Figure out the PE address */ | ||
450 | config_addr = edev->config_addr; | ||
451 | if (edev->pe_config_addr) | ||
452 | config_addr = edev->pe_config_addr; | ||
453 | |||
454 | ret = rtas_call(ibm_slot_error_detail, 8, 1, NULL, config_addr, | ||
455 | BUID_HI(edev->phb->buid), BUID_LO(edev->phb->buid), | ||
456 | virt_to_phys(drv_log), len, | ||
457 | virt_to_phys(slot_errbuf), eeh_error_buf_size, | ||
458 | severity); | ||
459 | if (!ret) | ||
460 | log_error(slot_errbuf, ERR_TYPE_RTAS_LOG, 0); | ||
461 | spin_unlock_irqrestore(&slot_errbuf_lock, flags); | ||
462 | |||
463 | return ret; | ||
464 | } | ||
465 | |||
466 | /** | ||
467 | * pseries_eeh_configure_bridge - Configure PCI bridges in the indicated PE | ||
468 | * @dn: PE associated device node | ||
469 | * | ||
470 | * The function will be called to reconfigure the bridges included | ||
471 | * in the specified PE so that the mulfunctional PE would be recovered | ||
472 | * again. | ||
473 | */ | ||
474 | static int pseries_eeh_configure_bridge(struct device_node *dn) | ||
475 | { | ||
476 | struct eeh_dev *edev; | ||
477 | int config_addr; | ||
478 | int ret; | ||
479 | |||
480 | /* Figure out the PE address */ | ||
481 | edev = of_node_to_eeh_dev(dn); | ||
482 | config_addr = edev->config_addr; | ||
483 | if (edev->pe_config_addr) | ||
484 | config_addr = edev->pe_config_addr; | ||
485 | |||
486 | /* Use new configure-pe function, if supported */ | ||
487 | if (ibm_configure_pe != RTAS_UNKNOWN_SERVICE) { | ||
488 | ret = rtas_call(ibm_configure_pe, 3, 1, NULL, | ||
489 | config_addr, BUID_HI(edev->phb->buid), | ||
490 | BUID_LO(edev->phb->buid)); | ||
491 | } else if (ibm_configure_bridge != RTAS_UNKNOWN_SERVICE) { | ||
492 | ret = rtas_call(ibm_configure_bridge, 3, 1, NULL, | ||
493 | config_addr, BUID_HI(edev->phb->buid), | ||
494 | BUID_LO(edev->phb->buid)); | ||
495 | } else { | ||
496 | return -EFAULT; | ||
497 | } | ||
498 | |||
499 | if (ret) | ||
500 | pr_warning("%s: Unable to configure bridge %d for %s\n", | ||
501 | __func__, ret, dn->full_name); | ||
502 | |||
503 | return ret; | ||
504 | } | ||
505 | |||
506 | /** | ||
507 | * pseries_eeh_read_config - Read PCI config space | ||
508 | * @dn: device node | ||
509 | * @where: PCI address | ||
510 | * @size: size to read | ||
511 | * @val: return value | ||
512 | * | ||
513 | * Read config space from the speicifed device | ||
514 | */ | ||
515 | static int pseries_eeh_read_config(struct device_node *dn, int where, int size, u32 *val) | ||
516 | { | ||
517 | struct pci_dn *pdn; | ||
518 | |||
519 | pdn = PCI_DN(dn); | ||
520 | |||
521 | return rtas_read_config(pdn, where, size, val); | ||
522 | } | ||
523 | |||
524 | /** | ||
525 | * pseries_eeh_write_config - Write PCI config space | ||
526 | * @dn: device node | ||
527 | * @where: PCI address | ||
528 | * @size: size to write | ||
529 | * @val: value to be written | ||
530 | * | ||
531 | * Write config space to the specified device | ||
532 | */ | ||
533 | static int pseries_eeh_write_config(struct device_node *dn, int where, int size, u32 val) | ||
534 | { | ||
535 | struct pci_dn *pdn; | ||
536 | |||
537 | pdn = PCI_DN(dn); | ||
538 | |||
539 | return rtas_write_config(pdn, where, size, val); | ||
540 | } | ||
541 | |||
542 | static struct eeh_ops pseries_eeh_ops = { | ||
543 | .name = "pseries", | ||
544 | .init = pseries_eeh_init, | ||
545 | .set_option = pseries_eeh_set_option, | ||
546 | .get_pe_addr = pseries_eeh_get_pe_addr, | ||
547 | .get_state = pseries_eeh_get_state, | ||
548 | .reset = pseries_eeh_reset, | ||
549 | .wait_state = pseries_eeh_wait_state, | ||
550 | .get_log = pseries_eeh_get_log, | ||
551 | .configure_bridge = pseries_eeh_configure_bridge, | ||
552 | .read_config = pseries_eeh_read_config, | ||
553 | .write_config = pseries_eeh_write_config | ||
554 | }; | ||
555 | |||
556 | /** | ||
557 | * eeh_pseries_init - Register platform dependent EEH operations | ||
558 | * | ||
559 | * EEH initialization on pseries platform. This function should be | ||
560 | * called before any EEH related functions. | ||
561 | */ | ||
562 | int __init eeh_pseries_init(void) | ||
563 | { | ||
564 | return eeh_ops_register(&pseries_eeh_ops); | ||
565 | } | ||
diff --git a/arch/powerpc/platforms/pseries/eeh_sysfs.c b/arch/powerpc/platforms/pseries/eeh_sysfs.c index eb744ee234da..243b3510d70f 100644 --- a/arch/powerpc/platforms/pseries/eeh_sysfs.c +++ b/arch/powerpc/platforms/pseries/eeh_sysfs.c | |||
@@ -28,7 +28,7 @@ | |||
28 | #include <asm/pci-bridge.h> | 28 | #include <asm/pci-bridge.h> |
29 | 29 | ||
30 | /** | 30 | /** |
31 | * EEH_SHOW_ATTR -- create sysfs entry for eeh statistic | 31 | * EEH_SHOW_ATTR -- Create sysfs entry for eeh statistic |
32 | * @_name: name of file in sysfs directory | 32 | * @_name: name of file in sysfs directory |
33 | * @_memb: name of member in struct pci_dn to access | 33 | * @_memb: name of member in struct pci_dn to access |
34 | * @_format: printf format for display | 34 | * @_format: printf format for display |
@@ -41,24 +41,21 @@ static ssize_t eeh_show_##_name(struct device *dev, \ | |||
41 | struct device_attribute *attr, char *buf) \ | 41 | struct device_attribute *attr, char *buf) \ |
42 | { \ | 42 | { \ |
43 | struct pci_dev *pdev = to_pci_dev(dev); \ | 43 | struct pci_dev *pdev = to_pci_dev(dev); \ |
44 | struct device_node *dn = pci_device_to_OF_node(pdev); \ | 44 | struct eeh_dev *edev = pci_dev_to_eeh_dev(pdev); \ |
45 | struct pci_dn *pdn; \ | ||
46 | \ | 45 | \ |
47 | if (!dn || PCI_DN(dn) == NULL) \ | 46 | if (!edev) \ |
48 | return 0; \ | 47 | return 0; \ |
49 | \ | 48 | \ |
50 | pdn = PCI_DN(dn); \ | 49 | return sprintf(buf, _format "\n", edev->_memb); \ |
51 | return sprintf(buf, _format "\n", pdn->_memb); \ | ||
52 | } \ | 50 | } \ |
53 | static DEVICE_ATTR(_name, S_IRUGO, eeh_show_##_name, NULL); | 51 | static DEVICE_ATTR(_name, S_IRUGO, eeh_show_##_name, NULL); |
54 | 52 | ||
55 | 53 | EEH_SHOW_ATTR(eeh_mode, mode, "0x%x"); | |
56 | EEH_SHOW_ATTR(eeh_mode, eeh_mode, "0x%x"); | 54 | EEH_SHOW_ATTR(eeh_config_addr, config_addr, "0x%x"); |
57 | EEH_SHOW_ATTR(eeh_config_addr, eeh_config_addr, "0x%x"); | 55 | EEH_SHOW_ATTR(eeh_pe_config_addr, pe_config_addr, "0x%x"); |
58 | EEH_SHOW_ATTR(eeh_pe_config_addr, eeh_pe_config_addr, "0x%x"); | 56 | EEH_SHOW_ATTR(eeh_check_count, check_count, "%d" ); |
59 | EEH_SHOW_ATTR(eeh_check_count, eeh_check_count, "%d"); | 57 | EEH_SHOW_ATTR(eeh_freeze_count, freeze_count, "%d" ); |
60 | EEH_SHOW_ATTR(eeh_freeze_count, eeh_freeze_count, "%d"); | 58 | EEH_SHOW_ATTR(eeh_false_positives, false_positives, "%d" ); |
61 | EEH_SHOW_ATTR(eeh_false_positives, eeh_false_positives, "%d"); | ||
62 | 59 | ||
63 | void eeh_sysfs_add_device(struct pci_dev *pdev) | 60 | void eeh_sysfs_add_device(struct pci_dev *pdev) |
64 | { | 61 | { |
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index 7bc73af6c7b9..5f3ef876ded2 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include <asm/udbg.h> | 41 | #include <asm/udbg.h> |
42 | #include <asm/smp.h> | 42 | #include <asm/smp.h> |
43 | #include <asm/trace.h> | 43 | #include <asm/trace.h> |
44 | #include <asm/firmware.h> | ||
44 | 45 | ||
45 | #include "plpar_wrappers.h" | 46 | #include "plpar_wrappers.h" |
46 | #include "pseries.h" | 47 | #include "pseries.h" |
diff --git a/arch/powerpc/platforms/pseries/msi.c b/arch/powerpc/platforms/pseries/msi.c index 38d24e7e7bb1..109fdb75578d 100644 --- a/arch/powerpc/platforms/pseries/msi.c +++ b/arch/powerpc/platforms/pseries/msi.c | |||
@@ -217,7 +217,7 @@ static struct device_node *find_pe_dn(struct pci_dev *dev, int *total) | |||
217 | if (!dn) | 217 | if (!dn) |
218 | return NULL; | 218 | return NULL; |
219 | 219 | ||
220 | dn = find_device_pe(dn); | 220 | dn = eeh_find_device_pe(dn); |
221 | if (!dn) | 221 | if (!dn) |
222 | return NULL; | 222 | return NULL; |
223 | 223 | ||
diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c index 55d4ec1bd1ac..fbb21fc3080b 100644 --- a/arch/powerpc/platforms/pseries/pci_dlpar.c +++ b/arch/powerpc/platforms/pseries/pci_dlpar.c | |||
@@ -147,6 +147,9 @@ struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn) | |||
147 | 147 | ||
148 | pci_devs_phb_init_dynamic(phb); | 148 | pci_devs_phb_init_dynamic(phb); |
149 | 149 | ||
150 | /* Create EEH devices for the PHB */ | ||
151 | eeh_dev_phb_init_dynamic(phb); | ||
152 | |||
150 | if (dn->child) | 153 | if (dn->child) |
151 | eeh_add_device_tree_early(dn); | 154 | eeh_add_device_tree_early(dn); |
152 | 155 | ||
diff --git a/arch/powerpc/platforms/pseries/phyp_dump.c b/arch/powerpc/platforms/pseries/phyp_dump.c deleted file mode 100644 index 6e7742da0072..000000000000 --- a/arch/powerpc/platforms/pseries/phyp_dump.c +++ /dev/null | |||
@@ -1,513 +0,0 @@ | |||
1 | /* | ||
2 | * Hypervisor-assisted dump | ||
3 | * | ||
4 | * Linas Vepstas, Manish Ahuja 2008 | ||
5 | * Copyright 2008 IBM Corp. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; either version | ||
10 | * 2 of the License, or (at your option) any later version. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/gfp.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/kobject.h> | ||
17 | #include <linux/mm.h> | ||
18 | #include <linux/of.h> | ||
19 | #include <linux/pfn.h> | ||
20 | #include <linux/swap.h> | ||
21 | #include <linux/sysfs.h> | ||
22 | |||
23 | #include <asm/page.h> | ||
24 | #include <asm/phyp_dump.h> | ||
25 | #include <asm/machdep.h> | ||
26 | #include <asm/prom.h> | ||
27 | #include <asm/rtas.h> | ||
28 | |||
29 | /* Variables, used to communicate data between early boot and late boot */ | ||
30 | static struct phyp_dump phyp_dump_vars; | ||
31 | struct phyp_dump *phyp_dump_info = &phyp_dump_vars; | ||
32 | |||
33 | static int ibm_configure_kernel_dump; | ||
34 | /* ------------------------------------------------- */ | ||
35 | /* RTAS interfaces to declare the dump regions */ | ||
36 | |||
37 | struct dump_section { | ||
38 | u32 dump_flags; | ||
39 | u16 source_type; | ||
40 | u16 error_flags; | ||
41 | u64 source_address; | ||
42 | u64 source_length; | ||
43 | u64 length_copied; | ||
44 | u64 destination_address; | ||
45 | }; | ||
46 | |||
47 | struct phyp_dump_header { | ||
48 | u32 version; | ||
49 | u16 num_of_sections; | ||
50 | u16 status; | ||
51 | |||
52 | u32 first_offset_section; | ||
53 | u32 dump_disk_section; | ||
54 | u64 block_num_dd; | ||
55 | u64 num_of_blocks_dd; | ||
56 | u32 offset_dd; | ||
57 | u32 maxtime_to_auto; | ||
58 | /* No dump disk path string used */ | ||
59 | |||
60 | struct dump_section cpu_data; | ||
61 | struct dump_section hpte_data; | ||
62 | struct dump_section kernel_data; | ||
63 | }; | ||
64 | |||
65 | /* The dump header *must be* in low memory, so .bss it */ | ||
66 | static struct phyp_dump_header phdr; | ||
67 | |||
68 | #define NUM_DUMP_SECTIONS 3 | ||
69 | #define DUMP_HEADER_VERSION 0x1 | ||
70 | #define DUMP_REQUEST_FLAG 0x1 | ||
71 | #define DUMP_SOURCE_CPU 0x0001 | ||
72 | #define DUMP_SOURCE_HPTE 0x0002 | ||
73 | #define DUMP_SOURCE_RMO 0x0011 | ||
74 | #define DUMP_ERROR_FLAG 0x2000 | ||
75 | #define DUMP_TRIGGERED 0x4000 | ||
76 | #define DUMP_PERFORMED 0x8000 | ||
77 | |||
78 | |||
79 | /** | ||
80 | * init_dump_header() - initialize the header declaring a dump | ||
81 | * Returns: length of dump save area. | ||
82 | * | ||
83 | * When the hypervisor saves crashed state, it needs to put | ||
84 | * it somewhere. The dump header tells the hypervisor where | ||
85 | * the data can be saved. | ||
86 | */ | ||
87 | static unsigned long init_dump_header(struct phyp_dump_header *ph) | ||
88 | { | ||
89 | unsigned long addr_offset = 0; | ||
90 | |||
91 | /* Set up the dump header */ | ||
92 | ph->version = DUMP_HEADER_VERSION; | ||
93 | ph->num_of_sections = NUM_DUMP_SECTIONS; | ||
94 | ph->status = 0; | ||
95 | |||
96 | ph->first_offset_section = | ||
97 | (u32)offsetof(struct phyp_dump_header, cpu_data); | ||
98 | ph->dump_disk_section = 0; | ||
99 | ph->block_num_dd = 0; | ||
100 | ph->num_of_blocks_dd = 0; | ||
101 | ph->offset_dd = 0; | ||
102 | |||
103 | ph->maxtime_to_auto = 0; /* disabled */ | ||
104 | |||
105 | /* The first two sections are mandatory */ | ||
106 | ph->cpu_data.dump_flags = DUMP_REQUEST_FLAG; | ||
107 | ph->cpu_data.source_type = DUMP_SOURCE_CPU; | ||
108 | ph->cpu_data.source_address = 0; | ||
109 | ph->cpu_data.source_length = phyp_dump_info->cpu_state_size; | ||
110 | ph->cpu_data.destination_address = addr_offset; | ||
111 | addr_offset += phyp_dump_info->cpu_state_size; | ||
112 | |||
113 | ph->hpte_data.dump_flags = DUMP_REQUEST_FLAG; | ||
114 | ph->hpte_data.source_type = DUMP_SOURCE_HPTE; | ||
115 | ph->hpte_data.source_address = 0; | ||
116 | ph->hpte_data.source_length = phyp_dump_info->hpte_region_size; | ||
117 | ph->hpte_data.destination_address = addr_offset; | ||
118 | addr_offset += phyp_dump_info->hpte_region_size; | ||
119 | |||
120 | /* This section describes the low kernel region */ | ||
121 | ph->kernel_data.dump_flags = DUMP_REQUEST_FLAG; | ||
122 | ph->kernel_data.source_type = DUMP_SOURCE_RMO; | ||
123 | ph->kernel_data.source_address = PHYP_DUMP_RMR_START; | ||
124 | ph->kernel_data.source_length = PHYP_DUMP_RMR_END; | ||
125 | ph->kernel_data.destination_address = addr_offset; | ||
126 | addr_offset += ph->kernel_data.source_length; | ||
127 | |||
128 | return addr_offset; | ||
129 | } | ||
130 | |||
131 | static void print_dump_header(const struct phyp_dump_header *ph) | ||
132 | { | ||
133 | #ifdef DEBUG | ||
134 | if (ph == NULL) | ||
135 | return; | ||
136 | |||
137 | printk(KERN_INFO "dump header:\n"); | ||
138 | /* setup some ph->sections required */ | ||
139 | printk(KERN_INFO "version = %d\n", ph->version); | ||
140 | printk(KERN_INFO "Sections = %d\n", ph->num_of_sections); | ||
141 | printk(KERN_INFO "Status = 0x%x\n", ph->status); | ||
142 | |||
143 | /* No ph->disk, so all should be set to 0 */ | ||
144 | printk(KERN_INFO "Offset to first section 0x%x\n", | ||
145 | ph->first_offset_section); | ||
146 | printk(KERN_INFO "dump disk sections should be zero\n"); | ||
147 | printk(KERN_INFO "dump disk section = %d\n", ph->dump_disk_section); | ||
148 | printk(KERN_INFO "block num = %lld\n", ph->block_num_dd); | ||
149 | printk(KERN_INFO "number of blocks = %lld\n", ph->num_of_blocks_dd); | ||
150 | printk(KERN_INFO "dump disk offset = %d\n", ph->offset_dd); | ||
151 | printk(KERN_INFO "Max auto time= %d\n", ph->maxtime_to_auto); | ||
152 | |||
153 | /*set cpu state and hpte states as well scratch pad area */ | ||
154 | printk(KERN_INFO " CPU AREA\n"); | ||
155 | printk(KERN_INFO "cpu dump_flags =%d\n", ph->cpu_data.dump_flags); | ||
156 | printk(KERN_INFO "cpu source_type =%d\n", ph->cpu_data.source_type); | ||
157 | printk(KERN_INFO "cpu error_flags =%d\n", ph->cpu_data.error_flags); | ||
158 | printk(KERN_INFO "cpu source_address =%llx\n", | ||
159 | ph->cpu_data.source_address); | ||
160 | printk(KERN_INFO "cpu source_length =%llx\n", | ||
161 | ph->cpu_data.source_length); | ||
162 | printk(KERN_INFO "cpu length_copied =%llx\n", | ||
163 | ph->cpu_data.length_copied); | ||
164 | |||
165 | printk(KERN_INFO " HPTE AREA\n"); | ||
166 | printk(KERN_INFO "HPTE dump_flags =%d\n", ph->hpte_data.dump_flags); | ||
167 | printk(KERN_INFO "HPTE source_type =%d\n", ph->hpte_data.source_type); | ||
168 | printk(KERN_INFO "HPTE error_flags =%d\n", ph->hpte_data.error_flags); | ||
169 | printk(KERN_INFO "HPTE source_address =%llx\n", | ||
170 | ph->hpte_data.source_address); | ||
171 | printk(KERN_INFO "HPTE source_length =%llx\n", | ||
172 | ph->hpte_data.source_length); | ||
173 | printk(KERN_INFO "HPTE length_copied =%llx\n", | ||
174 | ph->hpte_data.length_copied); | ||
175 | |||
176 | printk(KERN_INFO " SRSD AREA\n"); | ||
177 | printk(KERN_INFO "SRSD dump_flags =%d\n", ph->kernel_data.dump_flags); | ||
178 | printk(KERN_INFO "SRSD source_type =%d\n", ph->kernel_data.source_type); | ||
179 | printk(KERN_INFO "SRSD error_flags =%d\n", ph->kernel_data.error_flags); | ||
180 | printk(KERN_INFO "SRSD source_address =%llx\n", | ||
181 | ph->kernel_data.source_address); | ||
182 | printk(KERN_INFO "SRSD source_length =%llx\n", | ||
183 | ph->kernel_data.source_length); | ||
184 | printk(KERN_INFO "SRSD length_copied =%llx\n", | ||
185 | ph->kernel_data.length_copied); | ||
186 | #endif | ||
187 | } | ||
188 | |||
189 | static ssize_t show_phyp_dump_active(struct kobject *kobj, | ||
190 | struct kobj_attribute *attr, char *buf) | ||
191 | { | ||
192 | |||
193 | /* create filesystem entry so kdump is phyp-dump aware */ | ||
194 | return sprintf(buf, "%lx\n", phyp_dump_info->phyp_dump_at_boot); | ||
195 | } | ||
196 | |||
197 | static struct kobj_attribute pdl = __ATTR(phyp_dump_active, 0600, | ||
198 | show_phyp_dump_active, | ||
199 | NULL); | ||
200 | |||
201 | static void register_dump_area(struct phyp_dump_header *ph, unsigned long addr) | ||
202 | { | ||
203 | int rc; | ||
204 | |||
205 | /* Add addr value if not initialized before */ | ||
206 | if (ph->cpu_data.destination_address == 0) { | ||
207 | ph->cpu_data.destination_address += addr; | ||
208 | ph->hpte_data.destination_address += addr; | ||
209 | ph->kernel_data.destination_address += addr; | ||
210 | } | ||
211 | |||
212 | /* ToDo Invalidate kdump and free memory range. */ | ||
213 | |||
214 | do { | ||
215 | rc = rtas_call(ibm_configure_kernel_dump, 3, 1, NULL, | ||
216 | 1, ph, sizeof(struct phyp_dump_header)); | ||
217 | } while (rtas_busy_delay(rc)); | ||
218 | |||
219 | if (rc) { | ||
220 | printk(KERN_ERR "phyp-dump: unexpected error (%d) on " | ||
221 | "register\n", rc); | ||
222 | print_dump_header(ph); | ||
223 | return; | ||
224 | } | ||
225 | |||
226 | rc = sysfs_create_file(kernel_kobj, &pdl.attr); | ||
227 | if (rc) | ||
228 | printk(KERN_ERR "phyp-dump: unable to create sysfs" | ||
229 | " file (%d)\n", rc); | ||
230 | } | ||
231 | |||
232 | static | ||
233 | void invalidate_last_dump(struct phyp_dump_header *ph, unsigned long addr) | ||
234 | { | ||
235 | int rc; | ||
236 | |||
237 | /* Add addr value if not initialized before */ | ||
238 | if (ph->cpu_data.destination_address == 0) { | ||
239 | ph->cpu_data.destination_address += addr; | ||
240 | ph->hpte_data.destination_address += addr; | ||
241 | ph->kernel_data.destination_address += addr; | ||
242 | } | ||
243 | |||
244 | do { | ||
245 | rc = rtas_call(ibm_configure_kernel_dump, 3, 1, NULL, | ||
246 | 2, ph, sizeof(struct phyp_dump_header)); | ||
247 | } while (rtas_busy_delay(rc)); | ||
248 | |||
249 | if (rc) { | ||
250 | printk(KERN_ERR "phyp-dump: unexpected error (%d) " | ||
251 | "on invalidate\n", rc); | ||
252 | print_dump_header(ph); | ||
253 | } | ||
254 | } | ||
255 | |||
256 | /* ------------------------------------------------- */ | ||
257 | /** | ||
258 | * release_memory_range -- release memory previously memblock_reserved | ||
259 | * @start_pfn: starting physical frame number | ||
260 | * @nr_pages: number of pages to free. | ||
261 | * | ||
262 | * This routine will release memory that had been previously | ||
263 | * memblock_reserved in early boot. The released memory becomes | ||
264 | * available for genreal use. | ||
265 | */ | ||
266 | static void release_memory_range(unsigned long start_pfn, | ||
267 | unsigned long nr_pages) | ||
268 | { | ||
269 | struct page *rpage; | ||
270 | unsigned long end_pfn; | ||
271 | long i; | ||
272 | |||
273 | end_pfn = start_pfn + nr_pages; | ||
274 | |||
275 | for (i = start_pfn; i <= end_pfn; i++) { | ||
276 | rpage = pfn_to_page(i); | ||
277 | if (PageReserved(rpage)) { | ||
278 | ClearPageReserved(rpage); | ||
279 | init_page_count(rpage); | ||
280 | __free_page(rpage); | ||
281 | totalram_pages++; | ||
282 | } | ||
283 | } | ||
284 | } | ||
285 | |||
286 | /** | ||
287 | * track_freed_range -- Counts the range being freed. | ||
288 | * Once the counter goes to zero, it re-registers dump for | ||
289 | * future use. | ||
290 | */ | ||
291 | static void | ||
292 | track_freed_range(unsigned long addr, unsigned long length) | ||
293 | { | ||
294 | static unsigned long scratch_area_size, reserved_area_size; | ||
295 | |||
296 | if (addr < phyp_dump_info->init_reserve_start) | ||
297 | return; | ||
298 | |||
299 | if ((addr >= phyp_dump_info->init_reserve_start) && | ||
300 | (addr <= phyp_dump_info->init_reserve_start + | ||
301 | phyp_dump_info->init_reserve_size)) | ||
302 | reserved_area_size += length; | ||
303 | |||
304 | if ((addr >= phyp_dump_info->reserved_scratch_addr) && | ||
305 | (addr <= phyp_dump_info->reserved_scratch_addr + | ||
306 | phyp_dump_info->reserved_scratch_size)) | ||
307 | scratch_area_size += length; | ||
308 | |||
309 | if ((reserved_area_size == phyp_dump_info->init_reserve_size) && | ||
310 | (scratch_area_size == phyp_dump_info->reserved_scratch_size)) { | ||
311 | |||
312 | invalidate_last_dump(&phdr, | ||
313 | phyp_dump_info->reserved_scratch_addr); | ||
314 | register_dump_area(&phdr, | ||
315 | phyp_dump_info->reserved_scratch_addr); | ||
316 | } | ||
317 | } | ||
318 | |||
319 | /* ------------------------------------------------- */ | ||
320 | /** | ||
321 | * sysfs_release_region -- sysfs interface to release memory range. | ||
322 | * | ||
323 | * Usage: | ||
324 | * "echo <start addr> <length> > /sys/kernel/release_region" | ||
325 | * | ||
326 | * Example: | ||
327 | * "echo 0x40000000 0x10000000 > /sys/kernel/release_region" | ||
328 | * | ||
329 | * will release 256MB starting at 1GB. | ||
330 | */ | ||
331 | static ssize_t store_release_region(struct kobject *kobj, | ||
332 | struct kobj_attribute *attr, | ||
333 | const char *buf, size_t count) | ||
334 | { | ||
335 | unsigned long start_addr, length, end_addr; | ||
336 | unsigned long start_pfn, nr_pages; | ||
337 | ssize_t ret; | ||
338 | |||
339 | ret = sscanf(buf, "%lx %lx", &start_addr, &length); | ||
340 | if (ret != 2) | ||
341 | return -EINVAL; | ||
342 | |||
343 | track_freed_range(start_addr, length); | ||
344 | |||
345 | /* Range-check - don't free any reserved memory that | ||
346 | * wasn't reserved for phyp-dump */ | ||
347 | if (start_addr < phyp_dump_info->init_reserve_start) | ||
348 | start_addr = phyp_dump_info->init_reserve_start; | ||
349 | |||
350 | end_addr = phyp_dump_info->init_reserve_start + | ||
351 | phyp_dump_info->init_reserve_size; | ||
352 | if (start_addr+length > end_addr) | ||
353 | length = end_addr - start_addr; | ||
354 | |||
355 | /* Release the region of memory assed in by user */ | ||
356 | start_pfn = PFN_DOWN(start_addr); | ||
357 | nr_pages = PFN_DOWN(length); | ||
358 | release_memory_range(start_pfn, nr_pages); | ||
359 | |||
360 | return count; | ||
361 | } | ||
362 | |||
363 | static ssize_t show_release_region(struct kobject *kobj, | ||
364 | struct kobj_attribute *attr, char *buf) | ||
365 | { | ||
366 | u64 second_addr_range; | ||
367 | |||
368 | /* total reserved size - start of scratch area */ | ||
369 | second_addr_range = phyp_dump_info->init_reserve_size - | ||
370 | phyp_dump_info->reserved_scratch_size; | ||
371 | return sprintf(buf, "CPU:0x%llx-0x%llx: HPTE:0x%llx-0x%llx:" | ||
372 | " DUMP:0x%llx-0x%llx, 0x%lx-0x%llx:\n", | ||
373 | phdr.cpu_data.destination_address, | ||
374 | phdr.cpu_data.length_copied, | ||
375 | phdr.hpte_data.destination_address, | ||
376 | phdr.hpte_data.length_copied, | ||
377 | phdr.kernel_data.destination_address, | ||
378 | phdr.kernel_data.length_copied, | ||
379 | phyp_dump_info->init_reserve_start, | ||
380 | second_addr_range); | ||
381 | } | ||
382 | |||
383 | static struct kobj_attribute rr = __ATTR(release_region, 0600, | ||
384 | show_release_region, | ||
385 | store_release_region); | ||
386 | |||
387 | static int __init phyp_dump_setup(void) | ||
388 | { | ||
389 | struct device_node *rtas; | ||
390 | const struct phyp_dump_header *dump_header = NULL; | ||
391 | unsigned long dump_area_start; | ||
392 | unsigned long dump_area_length; | ||
393 | int header_len = 0; | ||
394 | int rc; | ||
395 | |||
396 | /* If no memory was reserved in early boot, there is nothing to do */ | ||
397 | if (phyp_dump_info->init_reserve_size == 0) | ||
398 | return 0; | ||
399 | |||
400 | /* Return if phyp dump not supported */ | ||
401 | if (!phyp_dump_info->phyp_dump_configured) | ||
402 | return -ENOSYS; | ||
403 | |||
404 | /* Is there dump data waiting for us? If there isn't, | ||
405 | * then register a new dump area, and release all of | ||
406 | * the rest of the reserved ram. | ||
407 | * | ||
408 | * The /rtas/ibm,kernel-dump rtas node is present only | ||
409 | * if there is dump data waiting for us. | ||
410 | */ | ||
411 | rtas = of_find_node_by_path("/rtas"); | ||
412 | if (rtas) { | ||
413 | dump_header = of_get_property(rtas, "ibm,kernel-dump", | ||
414 | &header_len); | ||
415 | of_node_put(rtas); | ||
416 | } | ||
417 | |||
418 | ibm_configure_kernel_dump = rtas_token("ibm,configure-kernel-dump"); | ||
419 | |||
420 | print_dump_header(dump_header); | ||
421 | dump_area_length = init_dump_header(&phdr); | ||
422 | /* align down */ | ||
423 | dump_area_start = phyp_dump_info->init_reserve_start & PAGE_MASK; | ||
424 | |||
425 | if (dump_header == NULL) { | ||
426 | register_dump_area(&phdr, dump_area_start); | ||
427 | return 0; | ||
428 | } | ||
429 | |||
430 | /* re-register the dump area, if old dump was invalid */ | ||
431 | if ((dump_header) && (dump_header->status & DUMP_ERROR_FLAG)) { | ||
432 | invalidate_last_dump(&phdr, dump_area_start); | ||
433 | register_dump_area(&phdr, dump_area_start); | ||
434 | return 0; | ||
435 | } | ||
436 | |||
437 | if (dump_header) { | ||
438 | phyp_dump_info->reserved_scratch_addr = | ||
439 | dump_header->cpu_data.destination_address; | ||
440 | phyp_dump_info->reserved_scratch_size = | ||
441 | dump_header->cpu_data.source_length + | ||
442 | dump_header->hpte_data.source_length + | ||
443 | dump_header->kernel_data.source_length; | ||
444 | } | ||
445 | |||
446 | /* Should we create a dump_subsys, analogous to s390/ipl.c ? */ | ||
447 | rc = sysfs_create_file(kernel_kobj, &rr.attr); | ||
448 | if (rc) | ||
449 | printk(KERN_ERR "phyp-dump: unable to create sysfs file (%d)\n", | ||
450 | rc); | ||
451 | |||
452 | /* ToDo: re-register the dump area, for next time. */ | ||
453 | return 0; | ||
454 | } | ||
455 | machine_subsys_initcall(pseries, phyp_dump_setup); | ||
456 | |||
457 | int __init early_init_dt_scan_phyp_dump(unsigned long node, | ||
458 | const char *uname, int depth, void *data) | ||
459 | { | ||
460 | const unsigned int *sizes; | ||
461 | |||
462 | phyp_dump_info->phyp_dump_configured = 0; | ||
463 | phyp_dump_info->phyp_dump_is_active = 0; | ||
464 | |||
465 | if (depth != 1 || strcmp(uname, "rtas") != 0) | ||
466 | return 0; | ||
467 | |||
468 | if (of_get_flat_dt_prop(node, "ibm,configure-kernel-dump", NULL)) | ||
469 | phyp_dump_info->phyp_dump_configured++; | ||
470 | |||
471 | if (of_get_flat_dt_prop(node, "ibm,dump-kernel", NULL)) | ||
472 | phyp_dump_info->phyp_dump_is_active++; | ||
473 | |||
474 | sizes = of_get_flat_dt_prop(node, "ibm,configure-kernel-dump-sizes", | ||
475 | NULL); | ||
476 | if (!sizes) | ||
477 | return 0; | ||
478 | |||
479 | if (sizes[0] == 1) | ||
480 | phyp_dump_info->cpu_state_size = *((unsigned long *)&sizes[1]); | ||
481 | |||
482 | if (sizes[3] == 2) | ||
483 | phyp_dump_info->hpte_region_size = | ||
484 | *((unsigned long *)&sizes[4]); | ||
485 | return 1; | ||
486 | } | ||
487 | |||
488 | /* Look for phyp_dump= cmdline option */ | ||
489 | static int __init early_phyp_dump_enabled(char *p) | ||
490 | { | ||
491 | phyp_dump_info->phyp_dump_at_boot = 1; | ||
492 | |||
493 | if (!p) | ||
494 | return 0; | ||
495 | |||
496 | if (strncmp(p, "1", 1) == 0) | ||
497 | phyp_dump_info->phyp_dump_at_boot = 1; | ||
498 | else if (strncmp(p, "0", 1) == 0) | ||
499 | phyp_dump_info->phyp_dump_at_boot = 0; | ||
500 | |||
501 | return 0; | ||
502 | } | ||
503 | early_param("phyp_dump", early_phyp_dump_enabled); | ||
504 | |||
505 | /* Look for phyp_dump_reserve_size= cmdline option */ | ||
506 | static int __init early_phyp_dump_reserve_size(char *p) | ||
507 | { | ||
508 | if (p) | ||
509 | phyp_dump_info->reserve_bootvar = memparse(p, &p); | ||
510 | |||
511 | return 0; | ||
512 | } | ||
513 | early_param("phyp_dump_reserve_size", early_phyp_dump_reserve_size); | ||
diff --git a/arch/powerpc/platforms/pseries/processor_idle.c b/arch/powerpc/platforms/pseries/processor_idle.c index 085fd3f45ad2..a12e95af6933 100644 --- a/arch/powerpc/platforms/pseries/processor_idle.c +++ b/arch/powerpc/platforms/pseries/processor_idle.c | |||
@@ -96,6 +96,20 @@ out: | |||
96 | return index; | 96 | return index; |
97 | } | 97 | } |
98 | 98 | ||
99 | static void check_and_cede_processor(void) | ||
100 | { | ||
101 | /* | ||
102 | * Interrupts are soft-disabled at this point, | ||
103 | * but not hard disabled. So an interrupt might have | ||
104 | * occurred before entering NAP, and would be potentially | ||
105 | * lost (edge events, decrementer events, etc...) unless | ||
106 | * we first hard disable then check. | ||
107 | */ | ||
108 | hard_irq_disable(); | ||
109 | if (get_paca()->irq_happened == 0) | ||
110 | cede_processor(); | ||
111 | } | ||
112 | |||
99 | static int dedicated_cede_loop(struct cpuidle_device *dev, | 113 | static int dedicated_cede_loop(struct cpuidle_device *dev, |
100 | struct cpuidle_driver *drv, | 114 | struct cpuidle_driver *drv, |
101 | int index) | 115 | int index) |
@@ -108,7 +122,7 @@ static int dedicated_cede_loop(struct cpuidle_device *dev, | |||
108 | 122 | ||
109 | ppc64_runlatch_off(); | 123 | ppc64_runlatch_off(); |
110 | HMT_medium(); | 124 | HMT_medium(); |
111 | cede_processor(); | 125 | check_and_cede_processor(); |
112 | 126 | ||
113 | get_lppaca()->donate_dedicated_cpu = 0; | 127 | get_lppaca()->donate_dedicated_cpu = 0; |
114 | dev->last_residency = | 128 | dev->last_residency = |
@@ -132,7 +146,7 @@ static int shared_cede_loop(struct cpuidle_device *dev, | |||
132 | * processor. When returning here, external interrupts | 146 | * processor. When returning here, external interrupts |
133 | * are enabled. | 147 | * are enabled. |
134 | */ | 148 | */ |
135 | cede_processor(); | 149 | check_and_cede_processor(); |
136 | 150 | ||
137 | dev->last_residency = | 151 | dev->last_residency = |
138 | (int)idle_loop_epilog(in_purr, kt_before); | 152 | (int)idle_loop_epilog(in_purr, kt_before); |
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index f79f1278dfca..8f137af616af 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c | |||
@@ -190,9 +190,8 @@ static void __init pseries_mpic_init_IRQ(void) | |||
190 | BUG_ON(openpic_addr == 0); | 190 | BUG_ON(openpic_addr == 0); |
191 | 191 | ||
192 | /* Setup the openpic driver */ | 192 | /* Setup the openpic driver */ |
193 | mpic = mpic_alloc(pSeries_mpic_node, openpic_addr, 0, | 193 | mpic = mpic_alloc(pSeries_mpic_node, openpic_addr, |
194 | 16, 250, /* isu size, irq count */ | 194 | MPIC_NO_RESET, 16, 0, " MPIC "); |
195 | " MPIC "); | ||
196 | BUG_ON(mpic == NULL); | 195 | BUG_ON(mpic == NULL); |
197 | 196 | ||
198 | /* Add ISUs */ | 197 | /* Add ISUs */ |
@@ -261,8 +260,12 @@ static int pci_dn_reconfig_notifier(struct notifier_block *nb, unsigned long act | |||
261 | switch (action) { | 260 | switch (action) { |
262 | case PSERIES_RECONFIG_ADD: | 261 | case PSERIES_RECONFIG_ADD: |
263 | pci = np->parent->data; | 262 | pci = np->parent->data; |
264 | if (pci) | 263 | if (pci) { |
265 | update_dn_pci_info(np, pci->phb); | 264 | update_dn_pci_info(np, pci->phb); |
265 | |||
266 | /* Create EEH device for the OF node */ | ||
267 | eeh_dev_init(np, pci->phb); | ||
268 | } | ||
266 | break; | 269 | break; |
267 | default: | 270 | default: |
268 | err = NOTIFY_DONE; | 271 | err = NOTIFY_DONE; |
@@ -382,6 +385,7 @@ static void __init pSeries_setup_arch(void) | |||
382 | 385 | ||
383 | /* Find and initialize PCI host bridges */ | 386 | /* Find and initialize PCI host bridges */ |
384 | init_pci_config_tokens(); | 387 | init_pci_config_tokens(); |
388 | eeh_pseries_init(); | ||
385 | find_and_init_phbs(); | 389 | find_and_init_phbs(); |
386 | pSeries_reconfig_notifier_register(&pci_dn_reconfig_nb); | 390 | pSeries_reconfig_notifier_register(&pci_dn_reconfig_nb); |
387 | eeh_init(); | 391 | eeh_init(); |
diff --git a/arch/powerpc/sysdev/Kconfig b/arch/powerpc/sysdev/Kconfig index 7b4df37ac381..a84fecf63c4d 100644 --- a/arch/powerpc/sysdev/Kconfig +++ b/arch/powerpc/sysdev/Kconfig | |||
@@ -29,3 +29,7 @@ config SCOM_DEBUGFS | |||
29 | bool "Expose SCOM controllers via debugfs" | 29 | bool "Expose SCOM controllers via debugfs" |
30 | depends on PPC_SCOM | 30 | depends on PPC_SCOM |
31 | default n | 31 | default n |
32 | |||
33 | config GE_FPGA | ||
34 | bool | ||
35 | default n | ||
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index 5e37b4717864..1bd7ecb24620 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile | |||
@@ -4,6 +4,8 @@ ccflags-$(CONFIG_PPC64) := -mno-minimal-toc | |||
4 | 4 | ||
5 | mpic-msi-obj-$(CONFIG_PCI_MSI) += mpic_msi.o mpic_u3msi.o mpic_pasemi_msi.o | 5 | mpic-msi-obj-$(CONFIG_PCI_MSI) += mpic_msi.o mpic_u3msi.o mpic_pasemi_msi.o |
6 | obj-$(CONFIG_MPIC) += mpic.o $(mpic-msi-obj-y) | 6 | obj-$(CONFIG_MPIC) += mpic.o $(mpic-msi-obj-y) |
7 | mpic-msgr-obj-$(CONFIG_MPIC_MSGR) += mpic_msgr.o | ||
8 | obj-$(CONFIG_MPIC) += mpic.o $(mpic-msi-obj-y) $(mpic-msgr-obj-y) | ||
7 | obj-$(CONFIG_PPC_EPAPR_HV_PIC) += ehv_pic.o | 9 | obj-$(CONFIG_PPC_EPAPR_HV_PIC) += ehv_pic.o |
8 | fsl-msi-obj-$(CONFIG_PCI_MSI) += fsl_msi.o | 10 | fsl-msi-obj-$(CONFIG_PCI_MSI) += fsl_msi.o |
9 | obj-$(CONFIG_PPC_MSI_BITMAP) += msi_bitmap.o | 11 | obj-$(CONFIG_PPC_MSI_BITMAP) += msi_bitmap.o |
@@ -65,3 +67,5 @@ obj-$(CONFIG_PPC_SCOM) += scom.o | |||
65 | subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror | 67 | subdir-ccflags-$(CONFIG_PPC_WERROR) := -Werror |
66 | 68 | ||
67 | obj-$(CONFIG_PPC_XICS) += xics/ | 69 | obj-$(CONFIG_PPC_XICS) += xics/ |
70 | |||
71 | obj-$(CONFIG_GE_FPGA) += ge/ | ||
diff --git a/arch/powerpc/sysdev/fsl_85xx_cache_sram.c b/arch/powerpc/sysdev/fsl_85xx_cache_sram.c index 116415899176..37a69097e022 100644 --- a/arch/powerpc/sysdev/fsl_85xx_cache_sram.c +++ b/arch/powerpc/sysdev/fsl_85xx_cache_sram.c | |||
@@ -24,6 +24,7 @@ | |||
24 | */ | 24 | */ |
25 | 25 | ||
26 | #include <linux/kernel.h> | 26 | #include <linux/kernel.h> |
27 | #include <linux/export.h> | ||
27 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
28 | #include <linux/err.h> | 29 | #include <linux/err.h> |
29 | #include <linux/of_platform.h> | 30 | #include <linux/of_platform.h> |
diff --git a/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c b/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c index 5f88797dce73..cedabd0f4bfe 100644 --- a/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c +++ b/arch/powerpc/sysdev/fsl_85xx_l2ctlr.c | |||
@@ -21,6 +21,7 @@ | |||
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <linux/kernel.h> | 23 | #include <linux/kernel.h> |
24 | #include <linux/module.h> | ||
24 | #include <linux/of_platform.h> | 25 | #include <linux/of_platform.h> |
25 | #include <asm/io.h> | 26 | #include <asm/io.h> |
26 | 27 | ||
@@ -200,6 +201,9 @@ static struct of_device_id mpc85xx_l2ctlr_of_match[] = { | |||
200 | { | 201 | { |
201 | .compatible = "fsl,p1022-l2-cache-controller", | 202 | .compatible = "fsl,p1022-l2-cache-controller", |
202 | }, | 203 | }, |
204 | { | ||
205 | .compatible = "fsl,mpc8548-l2-cache-controller", | ||
206 | }, | ||
203 | {}, | 207 | {}, |
204 | }; | 208 | }; |
205 | 209 | ||
diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c index 0c01debe963b..6e097de00e09 100644 --- a/arch/powerpc/sysdev/fsl_msi.c +++ b/arch/powerpc/sysdev/fsl_msi.c | |||
@@ -410,6 +410,7 @@ static int __devinit fsl_of_msi_probe(struct platform_device *dev) | |||
410 | 410 | ||
411 | msi->msi_regs = ioremap(res.start, resource_size(&res)); | 411 | msi->msi_regs = ioremap(res.start, resource_size(&res)); |
412 | if (!msi->msi_regs) { | 412 | if (!msi->msi_regs) { |
413 | err = -ENOMEM; | ||
413 | dev_err(&dev->dev, "could not map node %s\n", | 414 | dev_err(&dev->dev, "could not map node %s\n", |
414 | dev->dev.of_node->full_name); | 415 | dev->dev.of_node->full_name); |
415 | goto error_out; | 416 | goto error_out; |
diff --git a/arch/powerpc/sysdev/fsl_rio.c b/arch/powerpc/sysdev/fsl_rio.c index a4c4f4a932d8..5b6f556094dd 100644 --- a/arch/powerpc/sysdev/fsl_rio.c +++ b/arch/powerpc/sysdev/fsl_rio.c | |||
@@ -66,8 +66,8 @@ | |||
66 | " li %0,%3\n" \ | 66 | " li %0,%3\n" \ |
67 | " b 2b\n" \ | 67 | " b 2b\n" \ |
68 | ".section __ex_table,\"a\"\n" \ | 68 | ".section __ex_table,\"a\"\n" \ |
69 | " .align 2\n" \ | 69 | PPC_LONG_ALIGN "\n" \ |
70 | " .long 1b,3b\n" \ | 70 | PPC_LONG "1b,3b\n" \ |
71 | ".text" \ | 71 | ".text" \ |
72 | : "=r" (err), "=r" (x) \ | 72 | : "=r" (err), "=r" (x) \ |
73 | : "b" (addr), "i" (-EFAULT), "0" (err)) | 73 | : "b" (addr), "i" (-EFAULT), "0" (err)) |
diff --git a/arch/powerpc/sysdev/fsl_rmu.c b/arch/powerpc/sysdev/fsl_rmu.c index 15485789e9db..14bd5221f28a 100644 --- a/arch/powerpc/sysdev/fsl_rmu.c +++ b/arch/powerpc/sysdev/fsl_rmu.c | |||
@@ -100,14 +100,8 @@ | |||
100 | #define DOORBELL_DSR_TE 0x00000080 | 100 | #define DOORBELL_DSR_TE 0x00000080 |
101 | #define DOORBELL_DSR_QFI 0x00000010 | 101 | #define DOORBELL_DSR_QFI 0x00000010 |
102 | #define DOORBELL_DSR_DIQI 0x00000001 | 102 | #define DOORBELL_DSR_DIQI 0x00000001 |
103 | #define DOORBELL_TID_OFFSET 0x02 | ||
104 | #define DOORBELL_SID_OFFSET 0x04 | ||
105 | #define DOORBELL_INFO_OFFSET 0x06 | ||
106 | 103 | ||
107 | #define DOORBELL_MESSAGE_SIZE 0x08 | 104 | #define DOORBELL_MESSAGE_SIZE 0x08 |
108 | #define DBELL_SID(x) (*(u16 *)(x + DOORBELL_SID_OFFSET)) | ||
109 | #define DBELL_TID(x) (*(u16 *)(x + DOORBELL_TID_OFFSET)) | ||
110 | #define DBELL_INF(x) (*(u16 *)(x + DOORBELL_INFO_OFFSET)) | ||
111 | 105 | ||
112 | struct rio_msg_regs { | 106 | struct rio_msg_regs { |
113 | u32 omr; | 107 | u32 omr; |
@@ -193,6 +187,13 @@ struct fsl_rmu { | |||
193 | int rxirq; | 187 | int rxirq; |
194 | }; | 188 | }; |
195 | 189 | ||
190 | struct rio_dbell_msg { | ||
191 | u16 pad1; | ||
192 | u16 tid; | ||
193 | u16 sid; | ||
194 | u16 info; | ||
195 | }; | ||
196 | |||
196 | /** | 197 | /** |
197 | * fsl_rio_tx_handler - MPC85xx outbound message interrupt handler | 198 | * fsl_rio_tx_handler - MPC85xx outbound message interrupt handler |
198 | * @irq: Linux interrupt number | 199 | * @irq: Linux interrupt number |
@@ -311,8 +312,8 @@ fsl_rio_dbell_handler(int irq, void *dev_instance) | |||
311 | 312 | ||
312 | /* XXX Need to check/dispatch until queue empty */ | 313 | /* XXX Need to check/dispatch until queue empty */ |
313 | if (dsr & DOORBELL_DSR_DIQI) { | 314 | if (dsr & DOORBELL_DSR_DIQI) { |
314 | u32 dmsg = | 315 | struct rio_dbell_msg *dmsg = |
315 | (u32) fsl_dbell->dbell_ring.virt + | 316 | fsl_dbell->dbell_ring.virt + |
316 | (in_be32(&fsl_dbell->dbell_regs->dqdpar) & 0xfff); | 317 | (in_be32(&fsl_dbell->dbell_regs->dqdpar) & 0xfff); |
317 | struct rio_dbell *dbell; | 318 | struct rio_dbell *dbell; |
318 | int found = 0; | 319 | int found = 0; |
@@ -320,25 +321,25 @@ fsl_rio_dbell_handler(int irq, void *dev_instance) | |||
320 | pr_debug | 321 | pr_debug |
321 | ("RIO: processing doorbell," | 322 | ("RIO: processing doorbell," |
322 | " sid %2.2x tid %2.2x info %4.4x\n", | 323 | " sid %2.2x tid %2.2x info %4.4x\n", |
323 | DBELL_SID(dmsg), DBELL_TID(dmsg), DBELL_INF(dmsg)); | 324 | dmsg->sid, dmsg->tid, dmsg->info); |
324 | 325 | ||
325 | for (i = 0; i < MAX_PORT_NUM; i++) { | 326 | for (i = 0; i < MAX_PORT_NUM; i++) { |
326 | if (fsl_dbell->mport[i]) { | 327 | if (fsl_dbell->mport[i]) { |
327 | list_for_each_entry(dbell, | 328 | list_for_each_entry(dbell, |
328 | &fsl_dbell->mport[i]->dbells, node) { | 329 | &fsl_dbell->mport[i]->dbells, node) { |
329 | if ((dbell->res->start | 330 | if ((dbell->res->start |
330 | <= DBELL_INF(dmsg)) | 331 | <= dmsg->info) |
331 | && (dbell->res->end | 332 | && (dbell->res->end |
332 | >= DBELL_INF(dmsg))) { | 333 | >= dmsg->info)) { |
333 | found = 1; | 334 | found = 1; |
334 | break; | 335 | break; |
335 | } | 336 | } |
336 | } | 337 | } |
337 | if (found && dbell->dinb) { | 338 | if (found && dbell->dinb) { |
338 | dbell->dinb(fsl_dbell->mport[i], | 339 | dbell->dinb(fsl_dbell->mport[i], |
339 | dbell->dev_id, DBELL_SID(dmsg), | 340 | dbell->dev_id, dmsg->sid, |
340 | DBELL_TID(dmsg), | 341 | dmsg->tid, |
341 | DBELL_INF(dmsg)); | 342 | dmsg->info); |
342 | break; | 343 | break; |
343 | } | 344 | } |
344 | } | 345 | } |
@@ -348,8 +349,8 @@ fsl_rio_dbell_handler(int irq, void *dev_instance) | |||
348 | pr_debug | 349 | pr_debug |
349 | ("RIO: spurious doorbell," | 350 | ("RIO: spurious doorbell," |
350 | " sid %2.2x tid %2.2x info %4.4x\n", | 351 | " sid %2.2x tid %2.2x info %4.4x\n", |
351 | DBELL_SID(dmsg), DBELL_TID(dmsg), | 352 | dmsg->sid, dmsg->tid, |
352 | DBELL_INF(dmsg)); | 353 | dmsg->info); |
353 | } | 354 | } |
354 | setbits32(&fsl_dbell->dbell_regs->dmr, DOORBELL_DMR_DI); | 355 | setbits32(&fsl_dbell->dbell_regs->dmr, DOORBELL_DMR_DI); |
355 | out_be32(&fsl_dbell->dbell_regs->dsr, DOORBELL_DSR_DIQI); | 356 | out_be32(&fsl_dbell->dbell_regs->dsr, DOORBELL_DSR_DIQI); |
@@ -657,7 +658,7 @@ fsl_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox, | |||
657 | int ret = 0; | 658 | int ret = 0; |
658 | 659 | ||
659 | pr_debug("RIO: fsl_add_outb_message(): destid %4.4x mbox %d buffer " \ | 660 | pr_debug("RIO: fsl_add_outb_message(): destid %4.4x mbox %d buffer " \ |
660 | "%8.8x len %8.8x\n", rdev->destid, mbox, (int)buffer, len); | 661 | "%p len %8.8zx\n", rdev->destid, mbox, buffer, len); |
661 | if ((len < 8) || (len > RIO_MAX_MSG_SIZE)) { | 662 | if ((len < 8) || (len > RIO_MAX_MSG_SIZE)) { |
662 | ret = -EINVAL; | 663 | ret = -EINVAL; |
663 | goto out; | 664 | goto out; |
@@ -972,7 +973,8 @@ out: | |||
972 | void *fsl_get_inb_message(struct rio_mport *mport, int mbox) | 973 | void *fsl_get_inb_message(struct rio_mport *mport, int mbox) |
973 | { | 974 | { |
974 | struct fsl_rmu *rmu = GET_RMM_HANDLE(mport); | 975 | struct fsl_rmu *rmu = GET_RMM_HANDLE(mport); |
975 | u32 phys_buf, virt_buf; | 976 | u32 phys_buf; |
977 | void *virt_buf; | ||
976 | void *buf = NULL; | 978 | void *buf = NULL; |
977 | int buf_idx; | 979 | int buf_idx; |
978 | 980 | ||
@@ -982,7 +984,7 @@ void *fsl_get_inb_message(struct rio_mport *mport, int mbox) | |||
982 | if (phys_buf == in_be32(&rmu->msg_regs->ifqepar)) | 984 | if (phys_buf == in_be32(&rmu->msg_regs->ifqepar)) |
983 | goto out2; | 985 | goto out2; |
984 | 986 | ||
985 | virt_buf = (u32) rmu->msg_rx_ring.virt + (phys_buf | 987 | virt_buf = rmu->msg_rx_ring.virt + (phys_buf |
986 | - rmu->msg_rx_ring.phys); | 988 | - rmu->msg_rx_ring.phys); |
987 | buf_idx = (phys_buf - rmu->msg_rx_ring.phys) / RIO_MAX_MSG_SIZE; | 989 | buf_idx = (phys_buf - rmu->msg_rx_ring.phys) / RIO_MAX_MSG_SIZE; |
988 | buf = rmu->msg_rx_ring.virt_buffer[buf_idx]; | 990 | buf = rmu->msg_rx_ring.virt_buffer[buf_idx]; |
@@ -994,7 +996,7 @@ void *fsl_get_inb_message(struct rio_mport *mport, int mbox) | |||
994 | } | 996 | } |
995 | 997 | ||
996 | /* Copy max message size, caller is expected to allocate that big */ | 998 | /* Copy max message size, caller is expected to allocate that big */ |
997 | memcpy(buf, (void *)virt_buf, RIO_MAX_MSG_SIZE); | 999 | memcpy(buf, virt_buf, RIO_MAX_MSG_SIZE); |
998 | 1000 | ||
999 | /* Clear the available buffer */ | 1001 | /* Clear the available buffer */ |
1000 | rmu->msg_rx_ring.virt_buffer[buf_idx] = NULL; | 1002 | rmu->msg_rx_ring.virt_buffer[buf_idx] = NULL; |
diff --git a/arch/powerpc/sysdev/ge/Makefile b/arch/powerpc/sysdev/ge/Makefile new file mode 100644 index 000000000000..8731ffcb79b9 --- /dev/null +++ b/arch/powerpc/sysdev/ge/Makefile | |||
@@ -0,0 +1 @@ | |||
obj-$(CONFIG_GE_FPGA) += ge_pic.o | |||
diff --git a/arch/powerpc/platforms/86xx/gef_pic.c b/arch/powerpc/sysdev/ge/ge_pic.c index af3fd697de82..2bcb78bb3a15 100644 --- a/arch/powerpc/platforms/86xx/gef_pic.c +++ b/arch/powerpc/sysdev/ge/ge_pic.c | |||
@@ -22,7 +22,7 @@ | |||
22 | #include <asm/prom.h> | 22 | #include <asm/prom.h> |
23 | #include <asm/irq.h> | 23 | #include <asm/irq.h> |
24 | 24 | ||
25 | #include "gef_pic.h" | 25 | #include "ge_pic.h" |
26 | 26 | ||
27 | #define DEBUG | 27 | #define DEBUG |
28 | #undef DEBUG | 28 | #undef DEBUG |
diff --git a/arch/powerpc/platforms/86xx/gef_pic.h b/arch/powerpc/sysdev/ge/ge_pic.h index 6149916da3f4..6149916da3f4 100644 --- a/arch/powerpc/platforms/86xx/gef_pic.h +++ b/arch/powerpc/sysdev/ge/ge_pic.h | |||
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index c83a512fa175..9ac71ebd2c40 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c | |||
@@ -873,7 +873,7 @@ int mpic_set_irq_type(struct irq_data *d, unsigned int flow_type) | |||
873 | DBG("mpic: set_irq_type(mpic:@%p,virq:%d,src:0x%x,type:0x%x)\n", | 873 | DBG("mpic: set_irq_type(mpic:@%p,virq:%d,src:0x%x,type:0x%x)\n", |
874 | mpic, d->irq, src, flow_type); | 874 | mpic, d->irq, src, flow_type); |
875 | 875 | ||
876 | if (src >= mpic->irq_count) | 876 | if (src >= mpic->num_sources) |
877 | return -EINVAL; | 877 | return -EINVAL; |
878 | 878 | ||
879 | if (flow_type == IRQ_TYPE_NONE) | 879 | if (flow_type == IRQ_TYPE_NONE) |
@@ -909,7 +909,7 @@ void mpic_set_vector(unsigned int virq, unsigned int vector) | |||
909 | DBG("mpic: set_vector(mpic:@%p,virq:%d,src:%d,vector:0x%x)\n", | 909 | DBG("mpic: set_vector(mpic:@%p,virq:%d,src:%d,vector:0x%x)\n", |
910 | mpic, virq, src, vector); | 910 | mpic, virq, src, vector); |
911 | 911 | ||
912 | if (src >= mpic->irq_count) | 912 | if (src >= mpic->num_sources) |
913 | return; | 913 | return; |
914 | 914 | ||
915 | vecpri = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)); | 915 | vecpri = mpic_irq_read(src, MPIC_INFO(IRQ_VECTOR_PRI)); |
@@ -926,7 +926,7 @@ void mpic_set_destination(unsigned int virq, unsigned int cpuid) | |||
926 | DBG("mpic: set_destination(mpic:@%p,virq:%d,src:%d,cpuid:0x%x)\n", | 926 | DBG("mpic: set_destination(mpic:@%p,virq:%d,src:%d,cpuid:0x%x)\n", |
927 | mpic, virq, src, cpuid); | 927 | mpic, virq, src, cpuid); |
928 | 928 | ||
929 | if (src >= mpic->irq_count) | 929 | if (src >= mpic->num_sources) |
930 | return; | 930 | return; |
931 | 931 | ||
932 | mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 1 << cpuid); | 932 | mpic_irq_write(src, MPIC_INFO(IRQ_DESTINATION), 1 << cpuid); |
@@ -1006,7 +1006,7 @@ static int mpic_host_map(struct irq_domain *h, unsigned int virq, | |||
1006 | return 0; | 1006 | return 0; |
1007 | } | 1007 | } |
1008 | 1008 | ||
1009 | if (hw >= mpic->irq_count) | 1009 | if (hw >= mpic->num_sources) |
1010 | return -EINVAL; | 1010 | return -EINVAL; |
1011 | 1011 | ||
1012 | mpic_msi_reserve_hwirq(mpic, hw); | 1012 | mpic_msi_reserve_hwirq(mpic, hw); |
@@ -1149,6 +1149,7 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
1149 | u32 greg_feature; | 1149 | u32 greg_feature; |
1150 | const char *vers; | 1150 | const char *vers; |
1151 | const u32 *psrc; | 1151 | const u32 *psrc; |
1152 | u32 last_irq; | ||
1152 | 1153 | ||
1153 | /* Default MPIC search parameters */ | 1154 | /* Default MPIC search parameters */ |
1154 | static const struct of_device_id __initconst mpic_device_id[] = { | 1155 | static const struct of_device_id __initconst mpic_device_id[] = { |
@@ -1182,6 +1183,16 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
1182 | } | 1183 | } |
1183 | } | 1184 | } |
1184 | 1185 | ||
1186 | /* Read extra device-tree properties into the flags variable */ | ||
1187 | if (of_get_property(node, "big-endian", NULL)) | ||
1188 | flags |= MPIC_BIG_ENDIAN; | ||
1189 | if (of_get_property(node, "pic-no-reset", NULL)) | ||
1190 | flags |= MPIC_NO_RESET; | ||
1191 | if (of_get_property(node, "single-cpu-affinity", NULL)) | ||
1192 | flags |= MPIC_SINGLE_DEST_CPU; | ||
1193 | if (of_device_is_compatible(node, "fsl,mpic")) | ||
1194 | flags |= MPIC_FSL; | ||
1195 | |||
1185 | mpic = kzalloc(sizeof(struct mpic), GFP_KERNEL); | 1196 | mpic = kzalloc(sizeof(struct mpic), GFP_KERNEL); |
1186 | if (mpic == NULL) | 1197 | if (mpic == NULL) |
1187 | goto err_of_node_put; | 1198 | goto err_of_node_put; |
@@ -1189,15 +1200,16 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
1189 | mpic->name = name; | 1200 | mpic->name = name; |
1190 | mpic->node = node; | 1201 | mpic->node = node; |
1191 | mpic->paddr = phys_addr; | 1202 | mpic->paddr = phys_addr; |
1203 | mpic->flags = flags; | ||
1192 | 1204 | ||
1193 | mpic->hc_irq = mpic_irq_chip; | 1205 | mpic->hc_irq = mpic_irq_chip; |
1194 | mpic->hc_irq.name = name; | 1206 | mpic->hc_irq.name = name; |
1195 | if (!(flags & MPIC_SECONDARY)) | 1207 | if (!(mpic->flags & MPIC_SECONDARY)) |
1196 | mpic->hc_irq.irq_set_affinity = mpic_set_affinity; | 1208 | mpic->hc_irq.irq_set_affinity = mpic_set_affinity; |
1197 | #ifdef CONFIG_MPIC_U3_HT_IRQS | 1209 | #ifdef CONFIG_MPIC_U3_HT_IRQS |
1198 | mpic->hc_ht_irq = mpic_irq_ht_chip; | 1210 | mpic->hc_ht_irq = mpic_irq_ht_chip; |
1199 | mpic->hc_ht_irq.name = name; | 1211 | mpic->hc_ht_irq.name = name; |
1200 | if (!(flags & MPIC_SECONDARY)) | 1212 | if (!(mpic->flags & MPIC_SECONDARY)) |
1201 | mpic->hc_ht_irq.irq_set_affinity = mpic_set_affinity; | 1213 | mpic->hc_ht_irq.irq_set_affinity = mpic_set_affinity; |
1202 | #endif /* CONFIG_MPIC_U3_HT_IRQS */ | 1214 | #endif /* CONFIG_MPIC_U3_HT_IRQS */ |
1203 | 1215 | ||
@@ -1209,12 +1221,9 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
1209 | mpic->hc_tm = mpic_tm_chip; | 1221 | mpic->hc_tm = mpic_tm_chip; |
1210 | mpic->hc_tm.name = name; | 1222 | mpic->hc_tm.name = name; |
1211 | 1223 | ||
1212 | mpic->flags = flags; | ||
1213 | mpic->isu_size = isu_size; | ||
1214 | mpic->irq_count = irq_count; | ||
1215 | mpic->num_sources = 0; /* so far */ | 1224 | mpic->num_sources = 0; /* so far */ |
1216 | 1225 | ||
1217 | if (flags & MPIC_LARGE_VECTORS) | 1226 | if (mpic->flags & MPIC_LARGE_VECTORS) |
1218 | intvec_top = 2047; | 1227 | intvec_top = 2047; |
1219 | else | 1228 | else |
1220 | intvec_top = 255; | 1229 | intvec_top = 255; |
@@ -1233,12 +1242,6 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
1233 | mpic->ipi_vecs[3] = intvec_top - 1; | 1242 | mpic->ipi_vecs[3] = intvec_top - 1; |
1234 | mpic->spurious_vec = intvec_top; | 1243 | mpic->spurious_vec = intvec_top; |
1235 | 1244 | ||
1236 | /* Check for "big-endian" in device-tree */ | ||
1237 | if (of_get_property(mpic->node, "big-endian", NULL) != NULL) | ||
1238 | mpic->flags |= MPIC_BIG_ENDIAN; | ||
1239 | if (of_device_is_compatible(mpic->node, "fsl,mpic")) | ||
1240 | mpic->flags |= MPIC_FSL; | ||
1241 | |||
1242 | /* Look for protected sources */ | 1245 | /* Look for protected sources */ |
1243 | psrc = of_get_property(mpic->node, "protected-sources", &psize); | 1246 | psrc = of_get_property(mpic->node, "protected-sources", &psize); |
1244 | if (psrc) { | 1247 | if (psrc) { |
@@ -1254,11 +1257,11 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
1254 | } | 1257 | } |
1255 | 1258 | ||
1256 | #ifdef CONFIG_MPIC_WEIRD | 1259 | #ifdef CONFIG_MPIC_WEIRD |
1257 | mpic->hw_set = mpic_infos[MPIC_GET_REGSET(flags)]; | 1260 | mpic->hw_set = mpic_infos[MPIC_GET_REGSET(mpic->flags)]; |
1258 | #endif | 1261 | #endif |
1259 | 1262 | ||
1260 | /* default register type */ | 1263 | /* default register type */ |
1261 | if (flags & MPIC_BIG_ENDIAN) | 1264 | if (mpic->flags & MPIC_BIG_ENDIAN) |
1262 | mpic->reg_type = mpic_access_mmio_be; | 1265 | mpic->reg_type = mpic_access_mmio_be; |
1263 | else | 1266 | else |
1264 | mpic->reg_type = mpic_access_mmio_le; | 1267 | mpic->reg_type = mpic_access_mmio_le; |
@@ -1268,10 +1271,10 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
1268 | * only if the kernel includes DCR support. | 1271 | * only if the kernel includes DCR support. |
1269 | */ | 1272 | */ |
1270 | #ifdef CONFIG_PPC_DCR | 1273 | #ifdef CONFIG_PPC_DCR |
1271 | if (flags & MPIC_USES_DCR) | 1274 | if (mpic->flags & MPIC_USES_DCR) |
1272 | mpic->reg_type = mpic_access_dcr; | 1275 | mpic->reg_type = mpic_access_dcr; |
1273 | #else | 1276 | #else |
1274 | BUG_ON(flags & MPIC_USES_DCR); | 1277 | BUG_ON(mpic->flags & MPIC_USES_DCR); |
1275 | #endif | 1278 | #endif |
1276 | 1279 | ||
1277 | /* Map the global registers */ | 1280 | /* Map the global registers */ |
@@ -1283,10 +1286,7 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
1283 | /* When using a device-node, reset requests are only honored if the MPIC | 1286 | /* When using a device-node, reset requests are only honored if the MPIC |
1284 | * is allowed to reset. | 1287 | * is allowed to reset. |
1285 | */ | 1288 | */ |
1286 | if (of_get_property(mpic->node, "pic-no-reset", NULL)) | 1289 | if (!(mpic->flags & MPIC_NO_RESET)) { |
1287 | mpic->flags |= MPIC_NO_RESET; | ||
1288 | |||
1289 | if ((flags & MPIC_WANTS_RESET) && !(mpic->flags & MPIC_NO_RESET)) { | ||
1290 | printk(KERN_DEBUG "mpic: Resetting\n"); | 1290 | printk(KERN_DEBUG "mpic: Resetting\n"); |
1291 | mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), | 1291 | mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), |
1292 | mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) | 1292 | mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) |
@@ -1297,31 +1297,17 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
1297 | } | 1297 | } |
1298 | 1298 | ||
1299 | /* CoreInt */ | 1299 | /* CoreInt */ |
1300 | if (flags & MPIC_ENABLE_COREINT) | 1300 | if (mpic->flags & MPIC_ENABLE_COREINT) |
1301 | mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), | 1301 | mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), |
1302 | mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) | 1302 | mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) |
1303 | | MPIC_GREG_GCONF_COREINT); | 1303 | | MPIC_GREG_GCONF_COREINT); |
1304 | 1304 | ||
1305 | if (flags & MPIC_ENABLE_MCK) | 1305 | if (mpic->flags & MPIC_ENABLE_MCK) |
1306 | mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), | 1306 | mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), |
1307 | mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) | 1307 | mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) |
1308 | | MPIC_GREG_GCONF_MCK); | 1308 | | MPIC_GREG_GCONF_MCK); |
1309 | 1309 | ||
1310 | /* | 1310 | /* |
1311 | * Read feature register. For non-ISU MPICs, num sources as well. On | ||
1312 | * ISU MPICs, sources are counted as ISUs are added | ||
1313 | */ | ||
1314 | greg_feature = mpic_read(mpic->gregs, MPIC_INFO(GREG_FEATURE_0)); | ||
1315 | if (isu_size == 0) { | ||
1316 | if (flags & MPIC_BROKEN_FRR_NIRQS) | ||
1317 | mpic->num_sources = mpic->irq_count; | ||
1318 | else | ||
1319 | mpic->num_sources = | ||
1320 | ((greg_feature & MPIC_GREG_FEATURE_LAST_SRC_MASK) | ||
1321 | >> MPIC_GREG_FEATURE_LAST_SRC_SHIFT) + 1; | ||
1322 | } | ||
1323 | |||
1324 | /* | ||
1325 | * The MPIC driver will crash if there are more cores than we | 1311 | * The MPIC driver will crash if there are more cores than we |
1326 | * can initialize, so we may as well catch that problem here. | 1312 | * can initialize, so we may as well catch that problem here. |
1327 | */ | 1313 | */ |
@@ -1336,17 +1322,41 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
1336 | 0x1000); | 1322 | 0x1000); |
1337 | } | 1323 | } |
1338 | 1324 | ||
1325 | /* | ||
1326 | * Read feature register. For non-ISU MPICs, num sources as well. On | ||
1327 | * ISU MPICs, sources are counted as ISUs are added | ||
1328 | */ | ||
1329 | greg_feature = mpic_read(mpic->gregs, MPIC_INFO(GREG_FEATURE_0)); | ||
1330 | |||
1331 | /* | ||
1332 | * By default, the last source number comes from the MPIC, but the | ||
1333 | * device-tree and board support code can override it on buggy hw. | ||
1334 | * If we get passed an isu_size (multi-isu MPIC) then we use that | ||
1335 | * as a default instead of the value read from the HW. | ||
1336 | */ | ||
1337 | last_irq = (greg_feature & MPIC_GREG_FEATURE_LAST_SRC_MASK) | ||
1338 | >> MPIC_GREG_FEATURE_LAST_SRC_SHIFT; | ||
1339 | if (isu_size) | ||
1340 | last_irq = isu_size * MPIC_MAX_ISU - 1; | ||
1341 | of_property_read_u32(mpic->node, "last-interrupt-source", &last_irq); | ||
1342 | if (irq_count) | ||
1343 | last_irq = irq_count - 1; | ||
1344 | |||
1339 | /* Initialize main ISU if none provided */ | 1345 | /* Initialize main ISU if none provided */ |
1340 | if (mpic->isu_size == 0) { | 1346 | if (!isu_size) { |
1341 | mpic->isu_size = mpic->num_sources; | 1347 | isu_size = last_irq + 1; |
1348 | mpic->num_sources = isu_size; | ||
1342 | mpic_map(mpic, mpic->paddr, &mpic->isus[0], | 1349 | mpic_map(mpic, mpic->paddr, &mpic->isus[0], |
1343 | MPIC_INFO(IRQ_BASE), MPIC_INFO(IRQ_STRIDE) * mpic->isu_size); | 1350 | MPIC_INFO(IRQ_BASE), |
1351 | MPIC_INFO(IRQ_STRIDE) * isu_size); | ||
1344 | } | 1352 | } |
1353 | |||
1354 | mpic->isu_size = isu_size; | ||
1345 | mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1); | 1355 | mpic->isu_shift = 1 + __ilog2(mpic->isu_size - 1); |
1346 | mpic->isu_mask = (1 << mpic->isu_shift) - 1; | 1356 | mpic->isu_mask = (1 << mpic->isu_shift) - 1; |
1347 | 1357 | ||
1348 | mpic->irqhost = irq_domain_add_linear(mpic->node, | 1358 | mpic->irqhost = irq_domain_add_linear(mpic->node, |
1349 | isu_size ? isu_size : mpic->num_sources, | 1359 | last_irq + 1, |
1350 | &mpic_host_ops, mpic); | 1360 | &mpic_host_ops, mpic); |
1351 | 1361 | ||
1352 | /* | 1362 | /* |
@@ -1380,7 +1390,7 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
1380 | mpic->next = mpics; | 1390 | mpic->next = mpics; |
1381 | mpics = mpic; | 1391 | mpics = mpic; |
1382 | 1392 | ||
1383 | if (!(flags & MPIC_SECONDARY)) { | 1393 | if (!(mpic->flags & MPIC_SECONDARY)) { |
1384 | mpic_primary = mpic; | 1394 | mpic_primary = mpic; |
1385 | irq_set_default_host(mpic->irqhost); | 1395 | irq_set_default_host(mpic->irqhost); |
1386 | } | 1396 | } |
@@ -1447,10 +1457,6 @@ void __init mpic_init(struct mpic *mpic) | |||
1447 | (mpic->ipi_vecs[0] + i)); | 1457 | (mpic->ipi_vecs[0] + i)); |
1448 | } | 1458 | } |
1449 | 1459 | ||
1450 | /* Initialize interrupt sources */ | ||
1451 | if (mpic->irq_count == 0) | ||
1452 | mpic->irq_count = mpic->num_sources; | ||
1453 | |||
1454 | /* Do the HT PIC fixups on U3 broken mpic */ | 1460 | /* Do the HT PIC fixups on U3 broken mpic */ |
1455 | DBG("MPIC flags: %x\n", mpic->flags); | 1461 | DBG("MPIC flags: %x\n", mpic->flags); |
1456 | if ((mpic->flags & MPIC_U3_HT_IRQS) && !(mpic->flags & MPIC_SECONDARY)) { | 1462 | if ((mpic->flags & MPIC_U3_HT_IRQS) && !(mpic->flags & MPIC_SECONDARY)) { |
diff --git a/arch/powerpc/sysdev/mpic_msgr.c b/arch/powerpc/sysdev/mpic_msgr.c new file mode 100644 index 000000000000..6e7fa386e76a --- /dev/null +++ b/arch/powerpc/sysdev/mpic_msgr.c | |||
@@ -0,0 +1,282 @@ | |||
1 | /* | ||
2 | * Copyright 2011-2012, Meador Inge, Mentor Graphics Corporation. | ||
3 | * | ||
4 | * Some ideas based on un-pushed work done by Vivek Mahajan, Jason Jin, and | ||
5 | * Mingkai Hu from Freescale Semiconductor, Inc. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * as published by the Free Software Foundation; version 2 of the | ||
10 | * License. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/list.h> | ||
15 | #include <linux/of_platform.h> | ||
16 | #include <linux/errno.h> | ||
17 | #include <asm/prom.h> | ||
18 | #include <asm/hw_irq.h> | ||
19 | #include <asm/ppc-pci.h> | ||
20 | #include <asm/mpic_msgr.h> | ||
21 | |||
22 | #define MPIC_MSGR_REGISTERS_PER_BLOCK 4 | ||
23 | #define MPIC_MSGR_STRIDE 0x10 | ||
24 | #define MPIC_MSGR_MER_OFFSET 0x100 | ||
25 | #define MSGR_INUSE 0 | ||
26 | #define MSGR_FREE 1 | ||
27 | |||
28 | static struct mpic_msgr **mpic_msgrs; | ||
29 | static unsigned int mpic_msgr_count; | ||
30 | |||
31 | static inline void _mpic_msgr_mer_write(struct mpic_msgr *msgr, u32 value) | ||
32 | { | ||
33 | out_be32(msgr->mer, value); | ||
34 | } | ||
35 | |||
36 | static inline u32 _mpic_msgr_mer_read(struct mpic_msgr *msgr) | ||
37 | { | ||
38 | return in_be32(msgr->mer); | ||
39 | } | ||
40 | |||
41 | static inline void _mpic_msgr_disable(struct mpic_msgr *msgr) | ||
42 | { | ||
43 | u32 mer = _mpic_msgr_mer_read(msgr); | ||
44 | |||
45 | _mpic_msgr_mer_write(msgr, mer & ~(1 << msgr->num)); | ||
46 | } | ||
47 | |||
48 | struct mpic_msgr *mpic_msgr_get(unsigned int reg_num) | ||
49 | { | ||
50 | unsigned long flags; | ||
51 | struct mpic_msgr *msgr; | ||
52 | |||
53 | /* Assume busy until proven otherwise. */ | ||
54 | msgr = ERR_PTR(-EBUSY); | ||
55 | |||
56 | if (reg_num >= mpic_msgr_count) | ||
57 | return ERR_PTR(-ENODEV); | ||
58 | |||
59 | raw_spin_lock_irqsave(&msgr->lock, flags); | ||
60 | if (mpic_msgrs[reg_num]->in_use == MSGR_FREE) { | ||
61 | msgr = mpic_msgrs[reg_num]; | ||
62 | msgr->in_use = MSGR_INUSE; | ||
63 | } | ||
64 | raw_spin_unlock_irqrestore(&msgr->lock, flags); | ||
65 | |||
66 | return msgr; | ||
67 | } | ||
68 | EXPORT_SYMBOL_GPL(mpic_msgr_get); | ||
69 | |||
70 | void mpic_msgr_put(struct mpic_msgr *msgr) | ||
71 | { | ||
72 | unsigned long flags; | ||
73 | |||
74 | raw_spin_lock_irqsave(&msgr->lock, flags); | ||
75 | msgr->in_use = MSGR_FREE; | ||
76 | _mpic_msgr_disable(msgr); | ||
77 | raw_spin_unlock_irqrestore(&msgr->lock, flags); | ||
78 | } | ||
79 | EXPORT_SYMBOL_GPL(mpic_msgr_put); | ||
80 | |||
81 | void mpic_msgr_enable(struct mpic_msgr *msgr) | ||
82 | { | ||
83 | unsigned long flags; | ||
84 | u32 mer; | ||
85 | |||
86 | raw_spin_lock_irqsave(&msgr->lock, flags); | ||
87 | mer = _mpic_msgr_mer_read(msgr); | ||
88 | _mpic_msgr_mer_write(msgr, mer | (1 << msgr->num)); | ||
89 | raw_spin_unlock_irqrestore(&msgr->lock, flags); | ||
90 | } | ||
91 | EXPORT_SYMBOL_GPL(mpic_msgr_enable); | ||
92 | |||
93 | void mpic_msgr_disable(struct mpic_msgr *msgr) | ||
94 | { | ||
95 | unsigned long flags; | ||
96 | |||
97 | raw_spin_lock_irqsave(&msgr->lock, flags); | ||
98 | _mpic_msgr_disable(msgr); | ||
99 | raw_spin_unlock_irqrestore(&msgr->lock, flags); | ||
100 | } | ||
101 | EXPORT_SYMBOL_GPL(mpic_msgr_disable); | ||
102 | |||
103 | /* The following three functions are used to compute the order and number of | ||
104 | * the message register blocks. They are clearly very inefficent. However, | ||
105 | * they are called *only* a few times during device initialization. | ||
106 | */ | ||
107 | static unsigned int mpic_msgr_number_of_blocks(void) | ||
108 | { | ||
109 | unsigned int count; | ||
110 | struct device_node *aliases; | ||
111 | |||
112 | count = 0; | ||
113 | aliases = of_find_node_by_name(NULL, "aliases"); | ||
114 | |||
115 | if (aliases) { | ||
116 | char buf[32]; | ||
117 | |||
118 | for (;;) { | ||
119 | snprintf(buf, sizeof(buf), "mpic-msgr-block%d", count); | ||
120 | if (!of_find_property(aliases, buf, NULL)) | ||
121 | break; | ||
122 | |||
123 | count += 1; | ||
124 | } | ||
125 | } | ||
126 | |||
127 | return count; | ||
128 | } | ||
129 | |||
130 | static unsigned int mpic_msgr_number_of_registers(void) | ||
131 | { | ||
132 | return mpic_msgr_number_of_blocks() * MPIC_MSGR_REGISTERS_PER_BLOCK; | ||
133 | } | ||
134 | |||
135 | static int mpic_msgr_block_number(struct device_node *node) | ||
136 | { | ||
137 | struct device_node *aliases; | ||
138 | unsigned int index, number_of_blocks; | ||
139 | char buf[64]; | ||
140 | |||
141 | number_of_blocks = mpic_msgr_number_of_blocks(); | ||
142 | aliases = of_find_node_by_name(NULL, "aliases"); | ||
143 | if (!aliases) | ||
144 | return -1; | ||
145 | |||
146 | for (index = 0; index < number_of_blocks; ++index) { | ||
147 | struct property *prop; | ||
148 | |||
149 | snprintf(buf, sizeof(buf), "mpic-msgr-block%d", index); | ||
150 | prop = of_find_property(aliases, buf, NULL); | ||
151 | if (node == of_find_node_by_path(prop->value)) | ||
152 | break; | ||
153 | } | ||
154 | |||
155 | return index == number_of_blocks ? -1 : index; | ||
156 | } | ||
157 | |||
158 | /* The probe function for a single message register block. | ||
159 | */ | ||
160 | static __devinit int mpic_msgr_probe(struct platform_device *dev) | ||
161 | { | ||
162 | void __iomem *msgr_block_addr; | ||
163 | int block_number; | ||
164 | struct resource rsrc; | ||
165 | unsigned int i; | ||
166 | unsigned int irq_index; | ||
167 | struct device_node *np = dev->dev.of_node; | ||
168 | unsigned int receive_mask; | ||
169 | const unsigned int *prop; | ||
170 | |||
171 | if (!np) { | ||
172 | dev_err(&dev->dev, "Device OF-Node is NULL"); | ||
173 | return -EFAULT; | ||
174 | } | ||
175 | |||
176 | /* Allocate the message register array upon the first device | ||
177 | * registered. | ||
178 | */ | ||
179 | if (!mpic_msgrs) { | ||
180 | mpic_msgr_count = mpic_msgr_number_of_registers(); | ||
181 | dev_info(&dev->dev, "Found %d message registers\n", | ||
182 | mpic_msgr_count); | ||
183 | |||
184 | mpic_msgrs = kzalloc(sizeof(struct mpic_msgr) * mpic_msgr_count, | ||
185 | GFP_KERNEL); | ||
186 | if (!mpic_msgrs) { | ||
187 | dev_err(&dev->dev, | ||
188 | "No memory for message register blocks\n"); | ||
189 | return -ENOMEM; | ||
190 | } | ||
191 | } | ||
192 | dev_info(&dev->dev, "Of-device full name %s\n", np->full_name); | ||
193 | |||
194 | /* IO map the message register block. */ | ||
195 | of_address_to_resource(np, 0, &rsrc); | ||
196 | msgr_block_addr = ioremap(rsrc.start, rsrc.end - rsrc.start); | ||
197 | if (!msgr_block_addr) { | ||
198 | dev_err(&dev->dev, "Failed to iomap MPIC message registers"); | ||
199 | return -EFAULT; | ||
200 | } | ||
201 | |||
202 | /* Ensure the block has a defined order. */ | ||
203 | block_number = mpic_msgr_block_number(np); | ||
204 | if (block_number < 0) { | ||
205 | dev_err(&dev->dev, | ||
206 | "Failed to find message register block alias\n"); | ||
207 | return -ENODEV; | ||
208 | } | ||
209 | dev_info(&dev->dev, "Setting up message register block %d\n", | ||
210 | block_number); | ||
211 | |||
212 | /* Grab the receive mask which specifies what registers can receive | ||
213 | * interrupts. | ||
214 | */ | ||
215 | prop = of_get_property(np, "mpic-msgr-receive-mask", NULL); | ||
216 | receive_mask = (prop) ? *prop : 0xF; | ||
217 | |||
218 | /* Build up the appropriate message register data structures. */ | ||
219 | for (i = 0, irq_index = 0; i < MPIC_MSGR_REGISTERS_PER_BLOCK; ++i) { | ||
220 | struct mpic_msgr *msgr; | ||
221 | unsigned int reg_number; | ||
222 | |||
223 | msgr = kzalloc(sizeof(struct mpic_msgr), GFP_KERNEL); | ||
224 | if (!msgr) { | ||
225 | dev_err(&dev->dev, "No memory for message register\n"); | ||
226 | return -ENOMEM; | ||
227 | } | ||
228 | |||
229 | reg_number = block_number * MPIC_MSGR_REGISTERS_PER_BLOCK + i; | ||
230 | msgr->base = msgr_block_addr + i * MPIC_MSGR_STRIDE; | ||
231 | msgr->mer = msgr->base + MPIC_MSGR_MER_OFFSET; | ||
232 | msgr->in_use = MSGR_FREE; | ||
233 | msgr->num = i; | ||
234 | raw_spin_lock_init(&msgr->lock); | ||
235 | |||
236 | if (receive_mask & (1 << i)) { | ||
237 | struct resource irq; | ||
238 | |||
239 | if (of_irq_to_resource(np, irq_index, &irq) == NO_IRQ) { | ||
240 | dev_err(&dev->dev, | ||
241 | "Missing interrupt specifier"); | ||
242 | kfree(msgr); | ||
243 | return -EFAULT; | ||
244 | } | ||
245 | msgr->irq = irq.start; | ||
246 | irq_index += 1; | ||
247 | } else { | ||
248 | msgr->irq = NO_IRQ; | ||
249 | } | ||
250 | |||
251 | mpic_msgrs[reg_number] = msgr; | ||
252 | mpic_msgr_disable(msgr); | ||
253 | dev_info(&dev->dev, "Register %d initialized: irq %d\n", | ||
254 | reg_number, msgr->irq); | ||
255 | |||
256 | } | ||
257 | |||
258 | return 0; | ||
259 | } | ||
260 | |||
261 | static const struct of_device_id mpic_msgr_ids[] = { | ||
262 | { | ||
263 | .compatible = "fsl,mpic-v3.1-msgr", | ||
264 | .data = NULL, | ||
265 | }, | ||
266 | {} | ||
267 | }; | ||
268 | |||
269 | static struct platform_driver mpic_msgr_driver = { | ||
270 | .driver = { | ||
271 | .name = "mpic-msgr", | ||
272 | .owner = THIS_MODULE, | ||
273 | .of_match_table = mpic_msgr_ids, | ||
274 | }, | ||
275 | .probe = mpic_msgr_probe, | ||
276 | }; | ||
277 | |||
278 | static __init int mpic_msgr_init(void) | ||
279 | { | ||
280 | return platform_driver_register(&mpic_msgr_driver); | ||
281 | } | ||
282 | subsys_initcall(mpic_msgr_init); | ||
diff --git a/arch/powerpc/sysdev/mpic_msi.c b/arch/powerpc/sysdev/mpic_msi.c index 0622aa91b18a..bbf342c88314 100644 --- a/arch/powerpc/sysdev/mpic_msi.c +++ b/arch/powerpc/sysdev/mpic_msi.c | |||
@@ -54,7 +54,7 @@ static int mpic_msi_reserve_u3_hwirqs(struct mpic *mpic) | |||
54 | for (i = 100; i < 105; i++) | 54 | for (i = 100; i < 105; i++) |
55 | msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, i); | 55 | msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, i); |
56 | 56 | ||
57 | for (i = 124; i < mpic->irq_count; i++) | 57 | for (i = 124; i < mpic->num_sources; i++) |
58 | msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, i); | 58 | msi_bitmap_reserve_hwirq(&mpic->msi_bitmap, i); |
59 | 59 | ||
60 | 60 | ||
@@ -83,7 +83,7 @@ int mpic_msi_init_allocator(struct mpic *mpic) | |||
83 | { | 83 | { |
84 | int rc; | 84 | int rc; |
85 | 85 | ||
86 | rc = msi_bitmap_alloc(&mpic->msi_bitmap, mpic->irq_count, | 86 | rc = msi_bitmap_alloc(&mpic->msi_bitmap, mpic->num_sources, |
87 | mpic->irqhost->of_node); | 87 | mpic->irqhost->of_node); |
88 | if (rc) | 88 | if (rc) |
89 | return rc; | 89 | return rc; |
diff --git a/arch/powerpc/sysdev/ppc4xx_pci.c b/arch/powerpc/sysdev/ppc4xx_pci.c index 4f05f7542346..56e8b3c3c890 100644 --- a/arch/powerpc/sysdev/ppc4xx_pci.c +++ b/arch/powerpc/sysdev/ppc4xx_pci.c | |||
@@ -1050,6 +1050,74 @@ static struct ppc4xx_pciex_hwops ppc460ex_pcie_hwops __initdata = | |||
1050 | .check_link = ppc4xx_pciex_check_link_sdr, | 1050 | .check_link = ppc4xx_pciex_check_link_sdr, |
1051 | }; | 1051 | }; |
1052 | 1052 | ||
1053 | static int __init apm821xx_pciex_core_init(struct device_node *np) | ||
1054 | { | ||
1055 | /* Return the number of pcie port */ | ||
1056 | return 1; | ||
1057 | } | ||
1058 | |||
1059 | static int apm821xx_pciex_init_port_hw(struct ppc4xx_pciex_port *port) | ||
1060 | { | ||
1061 | u32 val; | ||
1062 | |||
1063 | /* | ||
1064 | * Do a software reset on PCIe ports. | ||
1065 | * This code is to fix the issue that pci drivers doesn't re-assign | ||
1066 | * bus number for PCIE devices after Uboot | ||
1067 | * scanned and configured all the buses (eg. PCIE NIC IntelPro/1000 | ||
1068 | * PT quad port, SAS LSI 1064E) | ||
1069 | */ | ||
1070 | |||
1071 | mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST, 0x0); | ||
1072 | mdelay(10); | ||
1073 | |||
1074 | if (port->endpoint) | ||
1075 | val = PTYPE_LEGACY_ENDPOINT << 20; | ||
1076 | else | ||
1077 | val = PTYPE_ROOT_PORT << 20; | ||
1078 | |||
1079 | val |= LNKW_X1 << 12; | ||
1080 | |||
1081 | mtdcri(SDR0, port->sdr_base + PESDRn_DLPSET, val); | ||
1082 | mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET1, 0x00000000); | ||
1083 | mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET2, 0x01010000); | ||
1084 | |||
1085 | mtdcri(SDR0, PESDR0_460EX_L0CDRCTL, 0x00003230); | ||
1086 | mtdcri(SDR0, PESDR0_460EX_L0DRV, 0x00000130); | ||
1087 | mtdcri(SDR0, PESDR0_460EX_L0CLK, 0x00000006); | ||
1088 | |||
1089 | mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST, 0x10000000); | ||
1090 | mdelay(50); | ||
1091 | mtdcri(SDR0, PESDR0_460EX_PHY_CTL_RST, 0x30000000); | ||
1092 | |||
1093 | mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, | ||
1094 | mfdcri(SDR0, port->sdr_base + PESDRn_RCSSET) | | ||
1095 | (PESDRx_RCSSET_RSTGU | PESDRx_RCSSET_RSTPYN)); | ||
1096 | |||
1097 | /* Poll for PHY reset */ | ||
1098 | val = PESDR0_460EX_RSTSTA - port->sdr_base; | ||
1099 | if (ppc4xx_pciex_wait_on_sdr(port, val, 0x1, 1, 100)) { | ||
1100 | printk(KERN_WARNING "%s: PCIE: Can't reset PHY\n", __func__); | ||
1101 | return -EBUSY; | ||
1102 | } else { | ||
1103 | mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET, | ||
1104 | (mfdcri(SDR0, port->sdr_base + PESDRn_RCSSET) & | ||
1105 | ~(PESDRx_RCSSET_RSTGU | PESDRx_RCSSET_RSTDL)) | | ||
1106 | PESDRx_RCSSET_RSTPYN); | ||
1107 | |||
1108 | port->has_ibpre = 1; | ||
1109 | return 0; | ||
1110 | } | ||
1111 | } | ||
1112 | |||
1113 | static struct ppc4xx_pciex_hwops apm821xx_pcie_hwops __initdata = { | ||
1114 | .want_sdr = true, | ||
1115 | .core_init = apm821xx_pciex_core_init, | ||
1116 | .port_init_hw = apm821xx_pciex_init_port_hw, | ||
1117 | .setup_utl = ppc460ex_pciex_init_utl, | ||
1118 | .check_link = ppc4xx_pciex_check_link_sdr, | ||
1119 | }; | ||
1120 | |||
1053 | static int __init ppc460sx_pciex_core_init(struct device_node *np) | 1121 | static int __init ppc460sx_pciex_core_init(struct device_node *np) |
1054 | { | 1122 | { |
1055 | /* HSS drive amplitude */ | 1123 | /* HSS drive amplitude */ |
@@ -1362,6 +1430,8 @@ static int __init ppc4xx_pciex_check_core_init(struct device_node *np) | |||
1362 | ppc4xx_pciex_hwops = &ppc460ex_pcie_hwops; | 1430 | ppc4xx_pciex_hwops = &ppc460ex_pcie_hwops; |
1363 | if (of_device_is_compatible(np, "ibm,plb-pciex-460sx")) | 1431 | if (of_device_is_compatible(np, "ibm,plb-pciex-460sx")) |
1364 | ppc4xx_pciex_hwops = &ppc460sx_pcie_hwops; | 1432 | ppc4xx_pciex_hwops = &ppc460sx_pcie_hwops; |
1433 | if (of_device_is_compatible(np, "ibm,plb-pciex-apm821xx")) | ||
1434 | ppc4xx_pciex_hwops = &apm821xx_pcie_hwops; | ||
1365 | #endif /* CONFIG_44x */ | 1435 | #endif /* CONFIG_44x */ |
1366 | #ifdef CONFIG_40x | 1436 | #ifdef CONFIG_40x |
1367 | if (of_device_is_compatible(np, "ibm,plb-pciex-405ex")) | 1437 | if (of_device_is_compatible(np, "ibm,plb-pciex-405ex")) |
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index cb95eea74d3d..68a9cbbab450 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c | |||
@@ -39,7 +39,6 @@ | |||
39 | #include <asm/irq_regs.h> | 39 | #include <asm/irq_regs.h> |
40 | #include <asm/spu.h> | 40 | #include <asm/spu.h> |
41 | #include <asm/spu_priv1.h> | 41 | #include <asm/spu_priv1.h> |
42 | #include <asm/firmware.h> | ||
43 | #include <asm/setjmp.h> | 42 | #include <asm/setjmp.h> |
44 | #include <asm/reg.h> | 43 | #include <asm/reg.h> |
45 | 44 | ||
@@ -1437,7 +1436,8 @@ static void excprint(struct pt_regs *fp) | |||
1437 | 1436 | ||
1438 | printf(" current = 0x%lx\n", current); | 1437 | printf(" current = 0x%lx\n", current); |
1439 | #ifdef CONFIG_PPC64 | 1438 | #ifdef CONFIG_PPC64 |
1440 | printf(" paca = 0x%lx\n", get_paca()); | 1439 | printf(" paca = 0x%lx\t softe: %d\t irq_happened: 0x%02x\n", |
1440 | local_paca, local_paca->soft_enabled, local_paca->irq_happened); | ||
1441 | #endif | 1441 | #endif |
1442 | if (current) { | 1442 | if (current) { |
1443 | printf(" pid = %ld, comm = %s\n", | 1443 | printf(" pid = %ld, comm = %s\n", |
@@ -1634,25 +1634,6 @@ static void super_regs(void) | |||
1634 | mfspr(SPRN_DEC), mfspr(SPRN_SPRG2)); | 1634 | mfspr(SPRN_DEC), mfspr(SPRN_SPRG2)); |
1635 | printf("sp = "REG" sprg3= "REG"\n", sp, mfspr(SPRN_SPRG3)); | 1635 | printf("sp = "REG" sprg3= "REG"\n", sp, mfspr(SPRN_SPRG3)); |
1636 | printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR)); | 1636 | printf("toc = "REG" dar = "REG"\n", toc, mfspr(SPRN_DAR)); |
1637 | #ifdef CONFIG_PPC_ISERIES | ||
1638 | if (firmware_has_feature(FW_FEATURE_ISERIES)) { | ||
1639 | struct paca_struct *ptrPaca; | ||
1640 | struct lppaca *ptrLpPaca; | ||
1641 | |||
1642 | /* Dump out relevant Paca data areas. */ | ||
1643 | printf("Paca: \n"); | ||
1644 | ptrPaca = get_paca(); | ||
1645 | |||
1646 | printf(" Local Processor Control Area (LpPaca): \n"); | ||
1647 | ptrLpPaca = ptrPaca->lppaca_ptr; | ||
1648 | printf(" Saved Srr0=%.16lx Saved Srr1=%.16lx \n", | ||
1649 | ptrLpPaca->saved_srr0, ptrLpPaca->saved_srr1); | ||
1650 | printf(" Saved Gpr3=%.16lx Saved Gpr4=%.16lx \n", | ||
1651 | ptrLpPaca->saved_gpr3, ptrLpPaca->saved_gpr4); | ||
1652 | printf(" Saved Gpr5=%.16lx \n", | ||
1653 | ptrLpPaca->gpr5_dword.saved_gpr5); | ||
1654 | } | ||
1655 | #endif | ||
1656 | 1637 | ||
1657 | return; | 1638 | return; |
1658 | } | 1639 | } |
@@ -2644,7 +2625,7 @@ static void dump_slb(void) | |||
2644 | static void dump_stab(void) | 2625 | static void dump_stab(void) |
2645 | { | 2626 | { |
2646 | int i; | 2627 | int i; |
2647 | unsigned long *tmp = (unsigned long *)get_paca()->stab_addr; | 2628 | unsigned long *tmp = (unsigned long *)local_paca->stab_addr; |
2648 | 2629 | ||
2649 | printf("Segment table contents of cpu %x\n", smp_processor_id()); | 2630 | printf("Segment table contents of cpu %x\n", smp_processor_id()); |
2650 | 2631 | ||
@@ -2855,10 +2836,6 @@ static void dump_tlb_book3e(void) | |||
2855 | 2836 | ||
2856 | static void xmon_init(int enable) | 2837 | static void xmon_init(int enable) |
2857 | { | 2838 | { |
2858 | #ifdef CONFIG_PPC_ISERIES | ||
2859 | if (firmware_has_feature(FW_FEATURE_ISERIES)) | ||
2860 | return; | ||
2861 | #endif | ||
2862 | if (enable) { | 2839 | if (enable) { |
2863 | __debugger = xmon; | 2840 | __debugger = xmon; |
2864 | __debugger_ipi = xmon_ipi; | 2841 | __debugger_ipi = xmon_ipi; |
@@ -2895,10 +2872,6 @@ static struct sysrq_key_op sysrq_xmon_op = { | |||
2895 | 2872 | ||
2896 | static int __init setup_xmon_sysrq(void) | 2873 | static int __init setup_xmon_sysrq(void) |
2897 | { | 2874 | { |
2898 | #ifdef CONFIG_PPC_ISERIES | ||
2899 | if (firmware_has_feature(FW_FEATURE_ISERIES)) | ||
2900 | return 0; | ||
2901 | #endif | ||
2902 | register_sysrq_key('x', &sysrq_xmon_op); | 2875 | register_sysrq_key('x', &sysrq_xmon_op); |
2903 | return 0; | 2876 | return 0; |
2904 | } | 2877 | } |
diff --git a/drivers/base/driver.c b/drivers/base/driver.c index 60e4f77ca662..3ec3896c83a6 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c | |||
@@ -123,36 +123,6 @@ void driver_remove_file(struct device_driver *drv, | |||
123 | } | 123 | } |
124 | EXPORT_SYMBOL_GPL(driver_remove_file); | 124 | EXPORT_SYMBOL_GPL(driver_remove_file); |
125 | 125 | ||
126 | /** | ||
127 | * driver_add_kobj - add a kobject below the specified driver | ||
128 | * @drv: requesting device driver | ||
129 | * @kobj: kobject to add below this driver | ||
130 | * @fmt: format string that names the kobject | ||
131 | * | ||
132 | * You really don't want to do this, this is only here due to one looney | ||
133 | * iseries driver, go poke those developers if you are annoyed about | ||
134 | * this... | ||
135 | */ | ||
136 | int driver_add_kobj(struct device_driver *drv, struct kobject *kobj, | ||
137 | const char *fmt, ...) | ||
138 | { | ||
139 | va_list args; | ||
140 | char *name; | ||
141 | int ret; | ||
142 | |||
143 | va_start(args, fmt); | ||
144 | name = kvasprintf(GFP_KERNEL, fmt, args); | ||
145 | va_end(args); | ||
146 | |||
147 | if (!name) | ||
148 | return -ENOMEM; | ||
149 | |||
150 | ret = kobject_add(kobj, &drv->p->kobj, "%s", name); | ||
151 | kfree(name); | ||
152 | return ret; | ||
153 | } | ||
154 | EXPORT_SYMBOL_GPL(driver_add_kobj); | ||
155 | |||
156 | static int driver_add_groups(struct device_driver *drv, | 126 | static int driver_add_groups(struct device_driver *drv, |
157 | const struct attribute_group **groups) | 127 | const struct attribute_group **groups) |
158 | { | 128 | { |
diff --git a/drivers/block/viodasd.c b/drivers/block/viodasd.c deleted file mode 100644 index 9a5b2a2d616d..000000000000 --- a/drivers/block/viodasd.c +++ /dev/null | |||
@@ -1,809 +0,0 @@ | |||
1 | /* -*- linux-c -*- | ||
2 | * viodasd.c | ||
3 | * Authors: Dave Boutcher <boutcher@us.ibm.com> | ||
4 | * Ryan Arnold <ryanarn@us.ibm.com> | ||
5 | * Colin Devilbiss <devilbis@us.ibm.com> | ||
6 | * Stephen Rothwell | ||
7 | * | ||
8 | * (C) Copyright 2000-2004 IBM Corporation | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or | ||
11 | * modify it under the terms of the GNU General Public License as | ||
12 | * published by the Free Software Foundation; either version 2 of the | ||
13 | * License, or (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
23 | * | ||
24 | * This routine provides access to disk space (termed "DASD" in historical | ||
25 | * IBM terms) owned and managed by an OS/400 partition running on the | ||
26 | * same box as this Linux partition. | ||
27 | * | ||
28 | * All disk operations are performed by sending messages back and forth to | ||
29 | * the OS/400 partition. | ||
30 | */ | ||
31 | |||
32 | #define pr_fmt(fmt) "viod: " fmt | ||
33 | |||
34 | #include <linux/major.h> | ||
35 | #include <linux/fs.h> | ||
36 | #include <linux/module.h> | ||
37 | #include <linux/kernel.h> | ||
38 | #include <linux/blkdev.h> | ||
39 | #include <linux/genhd.h> | ||
40 | #include <linux/hdreg.h> | ||
41 | #include <linux/errno.h> | ||
42 | #include <linux/init.h> | ||
43 | #include <linux/string.h> | ||
44 | #include <linux/mutex.h> | ||
45 | #include <linux/dma-mapping.h> | ||
46 | #include <linux/completion.h> | ||
47 | #include <linux/device.h> | ||
48 | #include <linux/scatterlist.h> | ||
49 | |||
50 | #include <asm/uaccess.h> | ||
51 | #include <asm/vio.h> | ||
52 | #include <asm/iseries/hv_types.h> | ||
53 | #include <asm/iseries/hv_lp_event.h> | ||
54 | #include <asm/iseries/hv_lp_config.h> | ||
55 | #include <asm/iseries/vio.h> | ||
56 | #include <asm/firmware.h> | ||
57 | |||
58 | MODULE_DESCRIPTION("iSeries Virtual DASD"); | ||
59 | MODULE_AUTHOR("Dave Boutcher"); | ||
60 | MODULE_LICENSE("GPL"); | ||
61 | |||
62 | /* | ||
63 | * We only support 7 partitions per physical disk....so with minor | ||
64 | * numbers 0-255 we get a maximum of 32 disks. | ||
65 | */ | ||
66 | #define VIOD_GENHD_NAME "iseries/vd" | ||
67 | |||
68 | #define VIOD_VERS "1.64" | ||
69 | |||
70 | enum { | ||
71 | PARTITION_SHIFT = 3, | ||
72 | MAX_DISKNO = HVMAXARCHITECTEDVIRTUALDISKS, | ||
73 | MAX_DISK_NAME = FIELD_SIZEOF(struct gendisk, disk_name) | ||
74 | }; | ||
75 | |||
76 | static DEFINE_MUTEX(viodasd_mutex); | ||
77 | static DEFINE_SPINLOCK(viodasd_spinlock); | ||
78 | |||
79 | #define VIOMAXREQ 16 | ||
80 | |||
81 | #define DEVICE_NO(cell) ((struct viodasd_device *)(cell) - &viodasd_devices[0]) | ||
82 | |||
83 | struct viodasd_waitevent { | ||
84 | struct completion com; | ||
85 | int rc; | ||
86 | u16 sub_result; | ||
87 | int max_disk; /* open */ | ||
88 | }; | ||
89 | |||
90 | static const struct vio_error_entry viodasd_err_table[] = { | ||
91 | { 0x0201, EINVAL, "Invalid Range" }, | ||
92 | { 0x0202, EINVAL, "Invalid Token" }, | ||
93 | { 0x0203, EIO, "DMA Error" }, | ||
94 | { 0x0204, EIO, "Use Error" }, | ||
95 | { 0x0205, EIO, "Release Error" }, | ||
96 | { 0x0206, EINVAL, "Invalid Disk" }, | ||
97 | { 0x0207, EBUSY, "Can't Lock" }, | ||
98 | { 0x0208, EIO, "Already Locked" }, | ||
99 | { 0x0209, EIO, "Already Unlocked" }, | ||
100 | { 0x020A, EIO, "Invalid Arg" }, | ||
101 | { 0x020B, EIO, "Bad IFS File" }, | ||
102 | { 0x020C, EROFS, "Read Only Device" }, | ||
103 | { 0x02FF, EIO, "Internal Error" }, | ||
104 | { 0x0000, 0, NULL }, | ||
105 | }; | ||
106 | |||
107 | /* | ||
108 | * Figure out the biggest I/O request (in sectors) we can accept | ||
109 | */ | ||
110 | #define VIODASD_MAXSECTORS (4096 / 512 * VIOMAXBLOCKDMA) | ||
111 | |||
112 | /* | ||
113 | * Number of disk I/O requests we've sent to OS/400 | ||
114 | */ | ||
115 | static int num_req_outstanding; | ||
116 | |||
117 | /* | ||
118 | * This is our internal structure for keeping track of disk devices | ||
119 | */ | ||
120 | struct viodasd_device { | ||
121 | u16 cylinders; | ||
122 | u16 tracks; | ||
123 | u16 sectors; | ||
124 | u16 bytes_per_sector; | ||
125 | u64 size; | ||
126 | int read_only; | ||
127 | spinlock_t q_lock; | ||
128 | struct gendisk *disk; | ||
129 | struct device *dev; | ||
130 | } viodasd_devices[MAX_DISKNO]; | ||
131 | |||
132 | /* | ||
133 | * External open entry point. | ||
134 | */ | ||
135 | static int viodasd_open(struct block_device *bdev, fmode_t mode) | ||
136 | { | ||
137 | struct viodasd_device *d = bdev->bd_disk->private_data; | ||
138 | HvLpEvent_Rc hvrc; | ||
139 | struct viodasd_waitevent we; | ||
140 | u16 flags = 0; | ||
141 | |||
142 | if (d->read_only) { | ||
143 | if (mode & FMODE_WRITE) | ||
144 | return -EROFS; | ||
145 | flags = vioblockflags_ro; | ||
146 | } | ||
147 | |||
148 | init_completion(&we.com); | ||
149 | |||
150 | /* Send the open event to OS/400 */ | ||
151 | hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, | ||
152 | HvLpEvent_Type_VirtualIo, | ||
153 | viomajorsubtype_blockio | vioblockopen, | ||
154 | HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, | ||
155 | viopath_sourceinst(viopath_hostLp), | ||
156 | viopath_targetinst(viopath_hostLp), | ||
157 | (u64)(unsigned long)&we, VIOVERSION << 16, | ||
158 | ((u64)DEVICE_NO(d) << 48) | ((u64)flags << 32), | ||
159 | 0, 0, 0); | ||
160 | if (hvrc != 0) { | ||
161 | pr_warning("HV open failed %d\n", (int)hvrc); | ||
162 | return -EIO; | ||
163 | } | ||
164 | |||
165 | wait_for_completion(&we.com); | ||
166 | |||
167 | /* Check the return code */ | ||
168 | if (we.rc != 0) { | ||
169 | const struct vio_error_entry *err = | ||
170 | vio_lookup_rc(viodasd_err_table, we.sub_result); | ||
171 | |||
172 | pr_warning("bad rc opening disk: %d:0x%04x (%s)\n", | ||
173 | (int)we.rc, we.sub_result, err->msg); | ||
174 | return -EIO; | ||
175 | } | ||
176 | |||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | static int viodasd_unlocked_open(struct block_device *bdev, fmode_t mode) | ||
181 | { | ||
182 | int ret; | ||
183 | |||
184 | mutex_lock(&viodasd_mutex); | ||
185 | ret = viodasd_open(bdev, mode); | ||
186 | mutex_unlock(&viodasd_mutex); | ||
187 | |||
188 | return ret; | ||
189 | } | ||
190 | |||
191 | |||
192 | /* | ||
193 | * External release entry point. | ||
194 | */ | ||
195 | static int viodasd_release(struct gendisk *disk, fmode_t mode) | ||
196 | { | ||
197 | struct viodasd_device *d = disk->private_data; | ||
198 | HvLpEvent_Rc hvrc; | ||
199 | |||
200 | mutex_lock(&viodasd_mutex); | ||
201 | /* Send the event to OS/400. We DON'T expect a response */ | ||
202 | hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, | ||
203 | HvLpEvent_Type_VirtualIo, | ||
204 | viomajorsubtype_blockio | vioblockclose, | ||
205 | HvLpEvent_AckInd_NoAck, HvLpEvent_AckType_ImmediateAck, | ||
206 | viopath_sourceinst(viopath_hostLp), | ||
207 | viopath_targetinst(viopath_hostLp), | ||
208 | 0, VIOVERSION << 16, | ||
209 | ((u64)DEVICE_NO(d) << 48) /* | ((u64)flags << 32) */, | ||
210 | 0, 0, 0); | ||
211 | if (hvrc != 0) | ||
212 | pr_warning("HV close call failed %d\n", (int)hvrc); | ||
213 | |||
214 | mutex_unlock(&viodasd_mutex); | ||
215 | |||
216 | return 0; | ||
217 | } | ||
218 | |||
219 | |||
220 | /* External ioctl entry point. | ||
221 | */ | ||
222 | static int viodasd_getgeo(struct block_device *bdev, struct hd_geometry *geo) | ||
223 | { | ||
224 | struct gendisk *disk = bdev->bd_disk; | ||
225 | struct viodasd_device *d = disk->private_data; | ||
226 | |||
227 | geo->sectors = d->sectors ? d->sectors : 32; | ||
228 | geo->heads = d->tracks ? d->tracks : 64; | ||
229 | geo->cylinders = d->cylinders ? d->cylinders : | ||
230 | get_capacity(disk) / (geo->sectors * geo->heads); | ||
231 | |||
232 | return 0; | ||
233 | } | ||
234 | |||
235 | /* | ||
236 | * Our file operations table | ||
237 | */ | ||
238 | static const struct block_device_operations viodasd_fops = { | ||
239 | .owner = THIS_MODULE, | ||
240 | .open = viodasd_unlocked_open, | ||
241 | .release = viodasd_release, | ||
242 | .getgeo = viodasd_getgeo, | ||
243 | }; | ||
244 | |||
245 | /* | ||
246 | * End a request | ||
247 | */ | ||
248 | static void viodasd_end_request(struct request *req, int error, | ||
249 | int num_sectors) | ||
250 | { | ||
251 | __blk_end_request(req, error, num_sectors << 9); | ||
252 | } | ||
253 | |||
254 | /* | ||
255 | * Send an actual I/O request to OS/400 | ||
256 | */ | ||
257 | static int send_request(struct request *req) | ||
258 | { | ||
259 | u64 start; | ||
260 | int direction; | ||
261 | int nsg; | ||
262 | u16 viocmd; | ||
263 | HvLpEvent_Rc hvrc; | ||
264 | struct vioblocklpevent *bevent; | ||
265 | struct HvLpEvent *hev; | ||
266 | struct scatterlist sg[VIOMAXBLOCKDMA]; | ||
267 | int sgindex; | ||
268 | struct viodasd_device *d; | ||
269 | unsigned long flags; | ||
270 | |||
271 | start = (u64)blk_rq_pos(req) << 9; | ||
272 | |||
273 | if (rq_data_dir(req) == READ) { | ||
274 | direction = DMA_FROM_DEVICE; | ||
275 | viocmd = viomajorsubtype_blockio | vioblockread; | ||
276 | } else { | ||
277 | direction = DMA_TO_DEVICE; | ||
278 | viocmd = viomajorsubtype_blockio | vioblockwrite; | ||
279 | } | ||
280 | |||
281 | d = req->rq_disk->private_data; | ||
282 | |||
283 | /* Now build the scatter-gather list */ | ||
284 | sg_init_table(sg, VIOMAXBLOCKDMA); | ||
285 | nsg = blk_rq_map_sg(req->q, req, sg); | ||
286 | nsg = dma_map_sg(d->dev, sg, nsg, direction); | ||
287 | |||
288 | spin_lock_irqsave(&viodasd_spinlock, flags); | ||
289 | num_req_outstanding++; | ||
290 | |||
291 | /* This optimization handles a single DMA block */ | ||
292 | if (nsg == 1) | ||
293 | hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, | ||
294 | HvLpEvent_Type_VirtualIo, viocmd, | ||
295 | HvLpEvent_AckInd_DoAck, | ||
296 | HvLpEvent_AckType_ImmediateAck, | ||
297 | viopath_sourceinst(viopath_hostLp), | ||
298 | viopath_targetinst(viopath_hostLp), | ||
299 | (u64)(unsigned long)req, VIOVERSION << 16, | ||
300 | ((u64)DEVICE_NO(d) << 48), start, | ||
301 | ((u64)sg_dma_address(&sg[0])) << 32, | ||
302 | sg_dma_len(&sg[0])); | ||
303 | else { | ||
304 | bevent = (struct vioblocklpevent *) | ||
305 | vio_get_event_buffer(viomajorsubtype_blockio); | ||
306 | if (bevent == NULL) { | ||
307 | pr_warning("error allocating disk event buffer\n"); | ||
308 | goto error_ret; | ||
309 | } | ||
310 | |||
311 | /* | ||
312 | * Now build up the actual request. Note that we store | ||
313 | * the pointer to the request in the correlation | ||
314 | * token so we can match the response up later | ||
315 | */ | ||
316 | memset(bevent, 0, sizeof(struct vioblocklpevent)); | ||
317 | hev = &bevent->event; | ||
318 | hev->flags = HV_LP_EVENT_VALID | HV_LP_EVENT_DO_ACK | | ||
319 | HV_LP_EVENT_INT; | ||
320 | hev->xType = HvLpEvent_Type_VirtualIo; | ||
321 | hev->xSubtype = viocmd; | ||
322 | hev->xSourceLp = HvLpConfig_getLpIndex(); | ||
323 | hev->xTargetLp = viopath_hostLp; | ||
324 | hev->xSizeMinus1 = | ||
325 | offsetof(struct vioblocklpevent, u.rw_data.dma_info) + | ||
326 | (sizeof(bevent->u.rw_data.dma_info[0]) * nsg) - 1; | ||
327 | hev->xSourceInstanceId = viopath_sourceinst(viopath_hostLp); | ||
328 | hev->xTargetInstanceId = viopath_targetinst(viopath_hostLp); | ||
329 | hev->xCorrelationToken = (u64)req; | ||
330 | bevent->version = VIOVERSION; | ||
331 | bevent->disk = DEVICE_NO(d); | ||
332 | bevent->u.rw_data.offset = start; | ||
333 | |||
334 | /* | ||
335 | * Copy just the dma information from the sg list | ||
336 | * into the request | ||
337 | */ | ||
338 | for (sgindex = 0; sgindex < nsg; sgindex++) { | ||
339 | bevent->u.rw_data.dma_info[sgindex].token = | ||
340 | sg_dma_address(&sg[sgindex]); | ||
341 | bevent->u.rw_data.dma_info[sgindex].len = | ||
342 | sg_dma_len(&sg[sgindex]); | ||
343 | } | ||
344 | |||
345 | /* Send the request */ | ||
346 | hvrc = HvCallEvent_signalLpEvent(&bevent->event); | ||
347 | vio_free_event_buffer(viomajorsubtype_blockio, bevent); | ||
348 | } | ||
349 | |||
350 | if (hvrc != HvLpEvent_Rc_Good) { | ||
351 | pr_warning("error sending disk event to OS/400 (rc %d)\n", | ||
352 | (int)hvrc); | ||
353 | goto error_ret; | ||
354 | } | ||
355 | spin_unlock_irqrestore(&viodasd_spinlock, flags); | ||
356 | return 0; | ||
357 | |||
358 | error_ret: | ||
359 | num_req_outstanding--; | ||
360 | spin_unlock_irqrestore(&viodasd_spinlock, flags); | ||
361 | dma_unmap_sg(d->dev, sg, nsg, direction); | ||
362 | return -1; | ||
363 | } | ||
364 | |||
365 | /* | ||
366 | * This is the external request processing routine | ||
367 | */ | ||
368 | static void do_viodasd_request(struct request_queue *q) | ||
369 | { | ||
370 | struct request *req; | ||
371 | |||
372 | /* | ||
373 | * If we already have the maximum number of requests | ||
374 | * outstanding to OS/400 just bail out. We'll come | ||
375 | * back later. | ||
376 | */ | ||
377 | while (num_req_outstanding < VIOMAXREQ) { | ||
378 | req = blk_fetch_request(q); | ||
379 | if (req == NULL) | ||
380 | return; | ||
381 | /* check that request contains a valid command */ | ||
382 | if (req->cmd_type != REQ_TYPE_FS) { | ||
383 | viodasd_end_request(req, -EIO, blk_rq_sectors(req)); | ||
384 | continue; | ||
385 | } | ||
386 | /* Try sending the request */ | ||
387 | if (send_request(req) != 0) | ||
388 | viodasd_end_request(req, -EIO, blk_rq_sectors(req)); | ||
389 | } | ||
390 | } | ||
391 | |||
392 | /* | ||
393 | * Probe a single disk and fill in the viodasd_device structure | ||
394 | * for it. | ||
395 | */ | ||
396 | static int probe_disk(struct viodasd_device *d) | ||
397 | { | ||
398 | HvLpEvent_Rc hvrc; | ||
399 | struct viodasd_waitevent we; | ||
400 | int dev_no = DEVICE_NO(d); | ||
401 | struct gendisk *g; | ||
402 | struct request_queue *q; | ||
403 | u16 flags = 0; | ||
404 | |||
405 | retry: | ||
406 | init_completion(&we.com); | ||
407 | |||
408 | /* Send the open event to OS/400 */ | ||
409 | hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, | ||
410 | HvLpEvent_Type_VirtualIo, | ||
411 | viomajorsubtype_blockio | vioblockopen, | ||
412 | HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, | ||
413 | viopath_sourceinst(viopath_hostLp), | ||
414 | viopath_targetinst(viopath_hostLp), | ||
415 | (u64)(unsigned long)&we, VIOVERSION << 16, | ||
416 | ((u64)dev_no << 48) | ((u64)flags<< 32), | ||
417 | 0, 0, 0); | ||
418 | if (hvrc != 0) { | ||
419 | pr_warning("bad rc on HV open %d\n", (int)hvrc); | ||
420 | return 0; | ||
421 | } | ||
422 | |||
423 | wait_for_completion(&we.com); | ||
424 | |||
425 | if (we.rc != 0) { | ||
426 | if (flags != 0) | ||
427 | return 0; | ||
428 | /* try again with read only flag set */ | ||
429 | flags = vioblockflags_ro; | ||
430 | goto retry; | ||
431 | } | ||
432 | if (we.max_disk > (MAX_DISKNO - 1)) { | ||
433 | printk_once(KERN_INFO pr_fmt("Only examining the first %d of %d disks connected\n"), | ||
434 | MAX_DISKNO, we.max_disk + 1); | ||
435 | } | ||
436 | |||
437 | /* Send the close event to OS/400. We DON'T expect a response */ | ||
438 | hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, | ||
439 | HvLpEvent_Type_VirtualIo, | ||
440 | viomajorsubtype_blockio | vioblockclose, | ||
441 | HvLpEvent_AckInd_NoAck, HvLpEvent_AckType_ImmediateAck, | ||
442 | viopath_sourceinst(viopath_hostLp), | ||
443 | viopath_targetinst(viopath_hostLp), | ||
444 | 0, VIOVERSION << 16, | ||
445 | ((u64)dev_no << 48) | ((u64)flags << 32), | ||
446 | 0, 0, 0); | ||
447 | if (hvrc != 0) { | ||
448 | pr_warning("bad rc sending event to OS/400 %d\n", (int)hvrc); | ||
449 | return 0; | ||
450 | } | ||
451 | |||
452 | if (d->dev == NULL) { | ||
453 | /* this is when we reprobe for new disks */ | ||
454 | if (vio_create_viodasd(dev_no) == NULL) { | ||
455 | pr_warning("cannot allocate virtual device for disk %d\n", | ||
456 | dev_no); | ||
457 | return 0; | ||
458 | } | ||
459 | /* | ||
460 | * The vio_create_viodasd will have recursed into this | ||
461 | * routine with d->dev set to the new vio device and | ||
462 | * will finish the setup of the disk below. | ||
463 | */ | ||
464 | return 1; | ||
465 | } | ||
466 | |||
467 | /* create the request queue for the disk */ | ||
468 | spin_lock_init(&d->q_lock); | ||
469 | q = blk_init_queue(do_viodasd_request, &d->q_lock); | ||
470 | if (q == NULL) { | ||
471 | pr_warning("cannot allocate queue for disk %d\n", dev_no); | ||
472 | return 0; | ||
473 | } | ||
474 | g = alloc_disk(1 << PARTITION_SHIFT); | ||
475 | if (g == NULL) { | ||
476 | pr_warning("cannot allocate disk structure for disk %d\n", | ||
477 | dev_no); | ||
478 | blk_cleanup_queue(q); | ||
479 | return 0; | ||
480 | } | ||
481 | |||
482 | d->disk = g; | ||
483 | blk_queue_max_segments(q, VIOMAXBLOCKDMA); | ||
484 | blk_queue_max_hw_sectors(q, VIODASD_MAXSECTORS); | ||
485 | g->major = VIODASD_MAJOR; | ||
486 | g->first_minor = dev_no << PARTITION_SHIFT; | ||
487 | if (dev_no >= 26) | ||
488 | snprintf(g->disk_name, sizeof(g->disk_name), | ||
489 | VIOD_GENHD_NAME "%c%c", | ||
490 | 'a' + (dev_no / 26) - 1, 'a' + (dev_no % 26)); | ||
491 | else | ||
492 | snprintf(g->disk_name, sizeof(g->disk_name), | ||
493 | VIOD_GENHD_NAME "%c", 'a' + (dev_no % 26)); | ||
494 | g->fops = &viodasd_fops; | ||
495 | g->queue = q; | ||
496 | g->private_data = d; | ||
497 | g->driverfs_dev = d->dev; | ||
498 | set_capacity(g, d->size >> 9); | ||
499 | |||
500 | pr_info("disk %d: %lu sectors (%lu MB) CHS=%d/%d/%d sector size %d%s\n", | ||
501 | dev_no, (unsigned long)(d->size >> 9), | ||
502 | (unsigned long)(d->size >> 20), | ||
503 | (int)d->cylinders, (int)d->tracks, | ||
504 | (int)d->sectors, (int)d->bytes_per_sector, | ||
505 | d->read_only ? " (RO)" : ""); | ||
506 | |||
507 | /* register us in the global list */ | ||
508 | add_disk(g); | ||
509 | return 1; | ||
510 | } | ||
511 | |||
512 | /* returns the total number of scatterlist elements converted */ | ||
513 | static int block_event_to_scatterlist(const struct vioblocklpevent *bevent, | ||
514 | struct scatterlist *sg, int *total_len) | ||
515 | { | ||
516 | int i, numsg; | ||
517 | const struct rw_data *rw_data = &bevent->u.rw_data; | ||
518 | static const int offset = | ||
519 | offsetof(struct vioblocklpevent, u.rw_data.dma_info); | ||
520 | static const int element_size = sizeof(rw_data->dma_info[0]); | ||
521 | |||
522 | numsg = ((bevent->event.xSizeMinus1 + 1) - offset) / element_size; | ||
523 | if (numsg > VIOMAXBLOCKDMA) | ||
524 | numsg = VIOMAXBLOCKDMA; | ||
525 | |||
526 | *total_len = 0; | ||
527 | sg_init_table(sg, VIOMAXBLOCKDMA); | ||
528 | for (i = 0; (i < numsg) && (rw_data->dma_info[i].len > 0); ++i) { | ||
529 | sg_dma_address(&sg[i]) = rw_data->dma_info[i].token; | ||
530 | sg_dma_len(&sg[i]) = rw_data->dma_info[i].len; | ||
531 | *total_len += rw_data->dma_info[i].len; | ||
532 | } | ||
533 | return i; | ||
534 | } | ||
535 | |||
536 | /* | ||
537 | * Restart all queues, starting with the one _after_ the disk given, | ||
538 | * thus reducing the chance of starvation of higher numbered disks. | ||
539 | */ | ||
540 | static void viodasd_restart_all_queues_starting_from(int first_index) | ||
541 | { | ||
542 | int i; | ||
543 | |||
544 | for (i = first_index + 1; i < MAX_DISKNO; ++i) | ||
545 | if (viodasd_devices[i].disk) | ||
546 | blk_run_queue(viodasd_devices[i].disk->queue); | ||
547 | for (i = 0; i <= first_index; ++i) | ||
548 | if (viodasd_devices[i].disk) | ||
549 | blk_run_queue(viodasd_devices[i].disk->queue); | ||
550 | } | ||
551 | |||
552 | /* | ||
553 | * For read and write requests, decrement the number of outstanding requests, | ||
554 | * Free the DMA buffers we allocated. | ||
555 | */ | ||
556 | static int viodasd_handle_read_write(struct vioblocklpevent *bevent) | ||
557 | { | ||
558 | int num_sg, num_sect, pci_direction, total_len; | ||
559 | struct request *req; | ||
560 | struct scatterlist sg[VIOMAXBLOCKDMA]; | ||
561 | struct HvLpEvent *event = &bevent->event; | ||
562 | unsigned long irq_flags; | ||
563 | struct viodasd_device *d; | ||
564 | int error; | ||
565 | spinlock_t *qlock; | ||
566 | |||
567 | num_sg = block_event_to_scatterlist(bevent, sg, &total_len); | ||
568 | num_sect = total_len >> 9; | ||
569 | if (event->xSubtype == (viomajorsubtype_blockio | vioblockread)) | ||
570 | pci_direction = DMA_FROM_DEVICE; | ||
571 | else | ||
572 | pci_direction = DMA_TO_DEVICE; | ||
573 | req = (struct request *)bevent->event.xCorrelationToken; | ||
574 | d = req->rq_disk->private_data; | ||
575 | |||
576 | dma_unmap_sg(d->dev, sg, num_sg, pci_direction); | ||
577 | |||
578 | /* | ||
579 | * Since this is running in interrupt mode, we need to make sure | ||
580 | * we're not stepping on any global I/O operations | ||
581 | */ | ||
582 | spin_lock_irqsave(&viodasd_spinlock, irq_flags); | ||
583 | num_req_outstanding--; | ||
584 | spin_unlock_irqrestore(&viodasd_spinlock, irq_flags); | ||
585 | |||
586 | error = (event->xRc == HvLpEvent_Rc_Good) ? 0 : -EIO; | ||
587 | if (error) { | ||
588 | const struct vio_error_entry *err; | ||
589 | err = vio_lookup_rc(viodasd_err_table, bevent->sub_result); | ||
590 | pr_warning("read/write error %d:0x%04x (%s)\n", | ||
591 | event->xRc, bevent->sub_result, err->msg); | ||
592 | num_sect = blk_rq_sectors(req); | ||
593 | } | ||
594 | qlock = req->q->queue_lock; | ||
595 | spin_lock_irqsave(qlock, irq_flags); | ||
596 | viodasd_end_request(req, error, num_sect); | ||
597 | spin_unlock_irqrestore(qlock, irq_flags); | ||
598 | |||
599 | /* Finally, try to get more requests off of this device's queue */ | ||
600 | viodasd_restart_all_queues_starting_from(DEVICE_NO(d)); | ||
601 | |||
602 | return 0; | ||
603 | } | ||
604 | |||
605 | /* This routine handles incoming block LP events */ | ||
606 | static void handle_block_event(struct HvLpEvent *event) | ||
607 | { | ||
608 | struct vioblocklpevent *bevent = (struct vioblocklpevent *)event; | ||
609 | struct viodasd_waitevent *pwe; | ||
610 | |||
611 | if (event == NULL) | ||
612 | /* Notification that a partition went away! */ | ||
613 | return; | ||
614 | /* First, we should NEVER get an int here...only acks */ | ||
615 | if (hvlpevent_is_int(event)) { | ||
616 | pr_warning("Yikes! got an int in viodasd event handler!\n"); | ||
617 | if (hvlpevent_need_ack(event)) { | ||
618 | event->xRc = HvLpEvent_Rc_InvalidSubtype; | ||
619 | HvCallEvent_ackLpEvent(event); | ||
620 | } | ||
621 | } | ||
622 | |||
623 | switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) { | ||
624 | case vioblockopen: | ||
625 | /* | ||
626 | * Handle a response to an open request. We get all the | ||
627 | * disk information in the response, so update it. The | ||
628 | * correlation token contains a pointer to a waitevent | ||
629 | * structure that has a completion in it. update the | ||
630 | * return code in the waitevent structure and post the | ||
631 | * completion to wake up the guy who sent the request | ||
632 | */ | ||
633 | pwe = (struct viodasd_waitevent *)event->xCorrelationToken; | ||
634 | pwe->rc = event->xRc; | ||
635 | pwe->sub_result = bevent->sub_result; | ||
636 | if (event->xRc == HvLpEvent_Rc_Good) { | ||
637 | const struct open_data *data = &bevent->u.open_data; | ||
638 | struct viodasd_device *device = | ||
639 | &viodasd_devices[bevent->disk]; | ||
640 | device->read_only = | ||
641 | bevent->flags & vioblockflags_ro; | ||
642 | device->size = data->disk_size; | ||
643 | device->cylinders = data->cylinders; | ||
644 | device->tracks = data->tracks; | ||
645 | device->sectors = data->sectors; | ||
646 | device->bytes_per_sector = data->bytes_per_sector; | ||
647 | pwe->max_disk = data->max_disk; | ||
648 | } | ||
649 | complete(&pwe->com); | ||
650 | break; | ||
651 | case vioblockclose: | ||
652 | break; | ||
653 | case vioblockread: | ||
654 | case vioblockwrite: | ||
655 | viodasd_handle_read_write(bevent); | ||
656 | break; | ||
657 | |||
658 | default: | ||
659 | pr_warning("invalid subtype!"); | ||
660 | if (hvlpevent_need_ack(event)) { | ||
661 | event->xRc = HvLpEvent_Rc_InvalidSubtype; | ||
662 | HvCallEvent_ackLpEvent(event); | ||
663 | } | ||
664 | } | ||
665 | } | ||
666 | |||
667 | /* | ||
668 | * Get the driver to reprobe for more disks. | ||
669 | */ | ||
670 | static ssize_t probe_disks(struct device_driver *drv, const char *buf, | ||
671 | size_t count) | ||
672 | { | ||
673 | struct viodasd_device *d; | ||
674 | |||
675 | for (d = viodasd_devices; d < &viodasd_devices[MAX_DISKNO]; d++) { | ||
676 | if (d->disk == NULL) | ||
677 | probe_disk(d); | ||
678 | } | ||
679 | return count; | ||
680 | } | ||
681 | static DRIVER_ATTR(probe, S_IWUSR, NULL, probe_disks); | ||
682 | |||
683 | static int viodasd_probe(struct vio_dev *vdev, const struct vio_device_id *id) | ||
684 | { | ||
685 | struct viodasd_device *d = &viodasd_devices[vdev->unit_address]; | ||
686 | |||
687 | d->dev = &vdev->dev; | ||
688 | if (!probe_disk(d)) | ||
689 | return -ENODEV; | ||
690 | return 0; | ||
691 | } | ||
692 | |||
693 | static int viodasd_remove(struct vio_dev *vdev) | ||
694 | { | ||
695 | struct viodasd_device *d; | ||
696 | |||
697 | d = &viodasd_devices[vdev->unit_address]; | ||
698 | if (d->disk) { | ||
699 | del_gendisk(d->disk); | ||
700 | blk_cleanup_queue(d->disk->queue); | ||
701 | put_disk(d->disk); | ||
702 | d->disk = NULL; | ||
703 | } | ||
704 | d->dev = NULL; | ||
705 | return 0; | ||
706 | } | ||
707 | |||
708 | /** | ||
709 | * viodasd_device_table: Used by vio.c to match devices that we | ||
710 | * support. | ||
711 | */ | ||
712 | static struct vio_device_id viodasd_device_table[] __devinitdata = { | ||
713 | { "block", "IBM,iSeries-viodasd" }, | ||
714 | { "", "" } | ||
715 | }; | ||
716 | MODULE_DEVICE_TABLE(vio, viodasd_device_table); | ||
717 | |||
718 | static struct vio_driver viodasd_driver = { | ||
719 | .id_table = viodasd_device_table, | ||
720 | .probe = viodasd_probe, | ||
721 | .remove = viodasd_remove, | ||
722 | .driver = { | ||
723 | .name = "viodasd", | ||
724 | .owner = THIS_MODULE, | ||
725 | } | ||
726 | }; | ||
727 | |||
728 | static int need_delete_probe; | ||
729 | |||
730 | /* | ||
731 | * Initialize the whole device driver. Handle module and non-module | ||
732 | * versions | ||
733 | */ | ||
734 | static int __init viodasd_init(void) | ||
735 | { | ||
736 | int rc; | ||
737 | |||
738 | if (!firmware_has_feature(FW_FEATURE_ISERIES)) { | ||
739 | rc = -ENODEV; | ||
740 | goto early_fail; | ||
741 | } | ||
742 | |||
743 | /* Try to open to our host lp */ | ||
744 | if (viopath_hostLp == HvLpIndexInvalid) | ||
745 | vio_set_hostlp(); | ||
746 | |||
747 | if (viopath_hostLp == HvLpIndexInvalid) { | ||
748 | pr_warning("invalid hosting partition\n"); | ||
749 | rc = -EIO; | ||
750 | goto early_fail; | ||
751 | } | ||
752 | |||
753 | pr_info("vers " VIOD_VERS ", hosting partition %d\n", viopath_hostLp); | ||
754 | |||
755 | /* register the block device */ | ||
756 | rc = register_blkdev(VIODASD_MAJOR, VIOD_GENHD_NAME); | ||
757 | if (rc) { | ||
758 | pr_warning("Unable to get major number %d for %s\n", | ||
759 | VIODASD_MAJOR, VIOD_GENHD_NAME); | ||
760 | goto early_fail; | ||
761 | } | ||
762 | /* Actually open the path to the hosting partition */ | ||
763 | rc = viopath_open(viopath_hostLp, viomajorsubtype_blockio, | ||
764 | VIOMAXREQ + 2); | ||
765 | if (rc) { | ||
766 | pr_warning("error opening path to host partition %d\n", | ||
767 | viopath_hostLp); | ||
768 | goto unregister_blk; | ||
769 | } | ||
770 | |||
771 | /* Initialize our request handler */ | ||
772 | vio_setHandler(viomajorsubtype_blockio, handle_block_event); | ||
773 | |||
774 | rc = vio_register_driver(&viodasd_driver); | ||
775 | if (rc) { | ||
776 | pr_warning("vio_register_driver failed\n"); | ||
777 | goto unset_handler; | ||
778 | } | ||
779 | |||
780 | /* | ||
781 | * If this call fails, it just means that we cannot dynamically | ||
782 | * add virtual disks, but the driver will still work fine for | ||
783 | * all existing disk, so ignore the failure. | ||
784 | */ | ||
785 | if (!driver_create_file(&viodasd_driver.driver, &driver_attr_probe)) | ||
786 | need_delete_probe = 1; | ||
787 | |||
788 | return 0; | ||
789 | |||
790 | unset_handler: | ||
791 | vio_clearHandler(viomajorsubtype_blockio); | ||
792 | viopath_close(viopath_hostLp, viomajorsubtype_blockio, VIOMAXREQ + 2); | ||
793 | unregister_blk: | ||
794 | unregister_blkdev(VIODASD_MAJOR, VIOD_GENHD_NAME); | ||
795 | early_fail: | ||
796 | return rc; | ||
797 | } | ||
798 | module_init(viodasd_init); | ||
799 | |||
800 | void __exit viodasd_exit(void) | ||
801 | { | ||
802 | if (need_delete_probe) | ||
803 | driver_remove_file(&viodasd_driver.driver, &driver_attr_probe); | ||
804 | vio_unregister_driver(&viodasd_driver); | ||
805 | vio_clearHandler(viomajorsubtype_blockio); | ||
806 | viopath_close(viopath_hostLp, viomajorsubtype_blockio, VIOMAXREQ + 2); | ||
807 | unregister_blkdev(VIODASD_MAJOR, VIOD_GENHD_NAME); | ||
808 | } | ||
809 | module_exit(viodasd_exit); | ||
diff --git a/drivers/cdrom/viocd.c b/drivers/cdrom/viocd.c deleted file mode 100644 index 7878da89d29e..000000000000 --- a/drivers/cdrom/viocd.c +++ /dev/null | |||
@@ -1,739 +0,0 @@ | |||
1 | /* -*- linux-c -*- | ||
2 | * drivers/cdrom/viocd.c | ||
3 | * | ||
4 | * iSeries Virtual CD Rom | ||
5 | * | ||
6 | * Authors: Dave Boutcher <boutcher@us.ibm.com> | ||
7 | * Ryan Arnold <ryanarn@us.ibm.com> | ||
8 | * Colin Devilbiss <devilbis@us.ibm.com> | ||
9 | * Stephen Rothwell | ||
10 | * | ||
11 | * (C) Copyright 2000-2004 IBM Corporation | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License as | ||
15 | * published by the Free Software Foundation; either version 2 of the | ||
16 | * License, or (at your option) anyu later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, but | ||
19 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
21 | * General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, write to the Free Software Foundation, | ||
25 | * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
26 | * | ||
27 | * This routine provides access to CD ROM drives owned and managed by an | ||
28 | * OS/400 partition running on the same box as this Linux partition. | ||
29 | * | ||
30 | * All operations are performed by sending messages back and forth to | ||
31 | * the OS/400 partition. | ||
32 | */ | ||
33 | |||
34 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
35 | |||
36 | #include <linux/major.h> | ||
37 | #include <linux/blkdev.h> | ||
38 | #include <linux/cdrom.h> | ||
39 | #include <linux/errno.h> | ||
40 | #include <linux/init.h> | ||
41 | #include <linux/dma-mapping.h> | ||
42 | #include <linux/module.h> | ||
43 | #include <linux/completion.h> | ||
44 | #include <linux/proc_fs.h> | ||
45 | #include <linux/mutex.h> | ||
46 | #include <linux/seq_file.h> | ||
47 | #include <linux/scatterlist.h> | ||
48 | |||
49 | #include <asm/vio.h> | ||
50 | #include <asm/iseries/hv_types.h> | ||
51 | #include <asm/iseries/hv_lp_event.h> | ||
52 | #include <asm/iseries/vio.h> | ||
53 | #include <asm/firmware.h> | ||
54 | |||
55 | #define VIOCD_DEVICE "iseries/vcd" | ||
56 | |||
57 | #define VIOCD_VERS "1.06" | ||
58 | |||
59 | /* | ||
60 | * Should probably make this a module parameter....sigh | ||
61 | */ | ||
62 | #define VIOCD_MAX_CD HVMAXARCHITECTEDVIRTUALCDROMS | ||
63 | |||
64 | static DEFINE_MUTEX(viocd_mutex); | ||
65 | static const struct vio_error_entry viocd_err_table[] = { | ||
66 | {0x0201, EINVAL, "Invalid Range"}, | ||
67 | {0x0202, EINVAL, "Invalid Token"}, | ||
68 | {0x0203, EIO, "DMA Error"}, | ||
69 | {0x0204, EIO, "Use Error"}, | ||
70 | {0x0205, EIO, "Release Error"}, | ||
71 | {0x0206, EINVAL, "Invalid CD"}, | ||
72 | {0x020C, EROFS, "Read Only Device"}, | ||
73 | {0x020D, ENOMEDIUM, "Changed or Missing Volume (or Varied Off?)"}, | ||
74 | {0x020E, EIO, "Optical System Error (Varied Off?)"}, | ||
75 | {0x02FF, EIO, "Internal Error"}, | ||
76 | {0x3010, EIO, "Changed Volume"}, | ||
77 | {0xC100, EIO, "Optical System Error"}, | ||
78 | {0x0000, 0, NULL}, | ||
79 | }; | ||
80 | |||
81 | /* | ||
82 | * This is the structure we use to exchange info between driver and interrupt | ||
83 | * handler | ||
84 | */ | ||
85 | struct viocd_waitevent { | ||
86 | struct completion com; | ||
87 | int rc; | ||
88 | u16 sub_result; | ||
89 | int changed; | ||
90 | }; | ||
91 | |||
92 | /* this is a lookup table for the true capabilities of a device */ | ||
93 | struct capability_entry { | ||
94 | char *type; | ||
95 | int capability; | ||
96 | }; | ||
97 | |||
98 | static struct capability_entry capability_table[] __initdata = { | ||
99 | { "6330", CDC_LOCK | CDC_DVD_RAM | CDC_RAM }, | ||
100 | { "6331", CDC_LOCK | CDC_DVD_RAM | CDC_RAM }, | ||
101 | { "6333", CDC_LOCK | CDC_DVD_RAM | CDC_RAM }, | ||
102 | { "632A", CDC_LOCK | CDC_DVD_RAM | CDC_RAM }, | ||
103 | { "6321", CDC_LOCK }, | ||
104 | { "632B", 0 }, | ||
105 | { NULL , CDC_LOCK }, | ||
106 | }; | ||
107 | |||
108 | /* These are our internal structures for keeping track of devices */ | ||
109 | static int viocd_numdev; | ||
110 | |||
111 | struct disk_info { | ||
112 | struct gendisk *viocd_disk; | ||
113 | struct cdrom_device_info viocd_info; | ||
114 | struct device *dev; | ||
115 | const char *rsrcname; | ||
116 | const char *type; | ||
117 | const char *model; | ||
118 | }; | ||
119 | static struct disk_info viocd_diskinfo[VIOCD_MAX_CD]; | ||
120 | |||
121 | #define DEVICE_NR(di) ((di) - &viocd_diskinfo[0]) | ||
122 | |||
123 | static spinlock_t viocd_reqlock; | ||
124 | |||
125 | #define MAX_CD_REQ 1 | ||
126 | |||
127 | /* procfs support */ | ||
128 | static int proc_viocd_show(struct seq_file *m, void *v) | ||
129 | { | ||
130 | int i; | ||
131 | |||
132 | for (i = 0; i < viocd_numdev; i++) { | ||
133 | seq_printf(m, "viocd device %d is iSeries resource %10.10s" | ||
134 | "type %4.4s, model %3.3s\n", | ||
135 | i, viocd_diskinfo[i].rsrcname, | ||
136 | viocd_diskinfo[i].type, | ||
137 | viocd_diskinfo[i].model); | ||
138 | } | ||
139 | return 0; | ||
140 | } | ||
141 | |||
142 | static int proc_viocd_open(struct inode *inode, struct file *file) | ||
143 | { | ||
144 | return single_open(file, proc_viocd_show, NULL); | ||
145 | } | ||
146 | |||
147 | static const struct file_operations proc_viocd_operations = { | ||
148 | .owner = THIS_MODULE, | ||
149 | .open = proc_viocd_open, | ||
150 | .read = seq_read, | ||
151 | .llseek = seq_lseek, | ||
152 | .release = single_release, | ||
153 | }; | ||
154 | |||
155 | static int viocd_blk_open(struct block_device *bdev, fmode_t mode) | ||
156 | { | ||
157 | struct disk_info *di = bdev->bd_disk->private_data; | ||
158 | int ret; | ||
159 | |||
160 | mutex_lock(&viocd_mutex); | ||
161 | ret = cdrom_open(&di->viocd_info, bdev, mode); | ||
162 | mutex_unlock(&viocd_mutex); | ||
163 | |||
164 | return ret; | ||
165 | } | ||
166 | |||
167 | static int viocd_blk_release(struct gendisk *disk, fmode_t mode) | ||
168 | { | ||
169 | struct disk_info *di = disk->private_data; | ||
170 | mutex_lock(&viocd_mutex); | ||
171 | cdrom_release(&di->viocd_info, mode); | ||
172 | mutex_unlock(&viocd_mutex); | ||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | static int viocd_blk_ioctl(struct block_device *bdev, fmode_t mode, | ||
177 | unsigned cmd, unsigned long arg) | ||
178 | { | ||
179 | struct disk_info *di = bdev->bd_disk->private_data; | ||
180 | int ret; | ||
181 | |||
182 | mutex_lock(&viocd_mutex); | ||
183 | ret = cdrom_ioctl(&di->viocd_info, bdev, mode, cmd, arg); | ||
184 | mutex_unlock(&viocd_mutex); | ||
185 | |||
186 | return ret; | ||
187 | } | ||
188 | |||
189 | static unsigned int viocd_blk_check_events(struct gendisk *disk, | ||
190 | unsigned int clearing) | ||
191 | { | ||
192 | struct disk_info *di = disk->private_data; | ||
193 | return cdrom_check_events(&di->viocd_info, clearing); | ||
194 | } | ||
195 | |||
196 | static const struct block_device_operations viocd_fops = { | ||
197 | .owner = THIS_MODULE, | ||
198 | .open = viocd_blk_open, | ||
199 | .release = viocd_blk_release, | ||
200 | .ioctl = viocd_blk_ioctl, | ||
201 | .check_events = viocd_blk_check_events, | ||
202 | }; | ||
203 | |||
204 | static int viocd_open(struct cdrom_device_info *cdi, int purpose) | ||
205 | { | ||
206 | struct disk_info *diskinfo = cdi->handle; | ||
207 | int device_no = DEVICE_NR(diskinfo); | ||
208 | HvLpEvent_Rc hvrc; | ||
209 | struct viocd_waitevent we; | ||
210 | |||
211 | init_completion(&we.com); | ||
212 | hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, | ||
213 | HvLpEvent_Type_VirtualIo, | ||
214 | viomajorsubtype_cdio | viocdopen, | ||
215 | HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, | ||
216 | viopath_sourceinst(viopath_hostLp), | ||
217 | viopath_targetinst(viopath_hostLp), | ||
218 | (u64)&we, VIOVERSION << 16, ((u64)device_no << 48), | ||
219 | 0, 0, 0); | ||
220 | if (hvrc != 0) { | ||
221 | pr_warning("bad rc on HvCallEvent_signalLpEventFast %d\n", | ||
222 | (int)hvrc); | ||
223 | return -EIO; | ||
224 | } | ||
225 | |||
226 | wait_for_completion(&we.com); | ||
227 | |||
228 | if (we.rc) { | ||
229 | const struct vio_error_entry *err = | ||
230 | vio_lookup_rc(viocd_err_table, we.sub_result); | ||
231 | pr_warning("bad rc %d:0x%04X on open: %s\n", | ||
232 | we.rc, we.sub_result, err->msg); | ||
233 | return -err->errno; | ||
234 | } | ||
235 | |||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | static void viocd_release(struct cdrom_device_info *cdi) | ||
240 | { | ||
241 | int device_no = DEVICE_NR((struct disk_info *)cdi->handle); | ||
242 | HvLpEvent_Rc hvrc; | ||
243 | |||
244 | hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, | ||
245 | HvLpEvent_Type_VirtualIo, | ||
246 | viomajorsubtype_cdio | viocdclose, | ||
247 | HvLpEvent_AckInd_NoAck, HvLpEvent_AckType_ImmediateAck, | ||
248 | viopath_sourceinst(viopath_hostLp), | ||
249 | viopath_targetinst(viopath_hostLp), 0, | ||
250 | VIOVERSION << 16, ((u64)device_no << 48), 0, 0, 0); | ||
251 | if (hvrc != 0) | ||
252 | pr_warning("bad rc on HvCallEvent_signalLpEventFast %d\n", | ||
253 | (int)hvrc); | ||
254 | } | ||
255 | |||
256 | /* Send a read or write request to OS/400 */ | ||
257 | static int send_request(struct request *req) | ||
258 | { | ||
259 | HvLpEvent_Rc hvrc; | ||
260 | struct disk_info *diskinfo = req->rq_disk->private_data; | ||
261 | u64 len; | ||
262 | dma_addr_t dmaaddr; | ||
263 | int direction; | ||
264 | u16 cmd; | ||
265 | struct scatterlist sg; | ||
266 | |||
267 | BUG_ON(req->nr_phys_segments > 1); | ||
268 | |||
269 | if (rq_data_dir(req) == READ) { | ||
270 | direction = DMA_FROM_DEVICE; | ||
271 | cmd = viomajorsubtype_cdio | viocdread; | ||
272 | } else { | ||
273 | direction = DMA_TO_DEVICE; | ||
274 | cmd = viomajorsubtype_cdio | viocdwrite; | ||
275 | } | ||
276 | |||
277 | sg_init_table(&sg, 1); | ||
278 | if (blk_rq_map_sg(req->q, req, &sg) == 0) { | ||
279 | pr_warning("error setting up scatter/gather list\n"); | ||
280 | return -1; | ||
281 | } | ||
282 | |||
283 | if (dma_map_sg(diskinfo->dev, &sg, 1, direction) == 0) { | ||
284 | pr_warning("error allocating sg tce\n"); | ||
285 | return -1; | ||
286 | } | ||
287 | dmaaddr = sg_dma_address(&sg); | ||
288 | len = sg_dma_len(&sg); | ||
289 | |||
290 | hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, | ||
291 | HvLpEvent_Type_VirtualIo, cmd, | ||
292 | HvLpEvent_AckInd_DoAck, | ||
293 | HvLpEvent_AckType_ImmediateAck, | ||
294 | viopath_sourceinst(viopath_hostLp), | ||
295 | viopath_targetinst(viopath_hostLp), | ||
296 | (u64)req, VIOVERSION << 16, | ||
297 | ((u64)DEVICE_NR(diskinfo) << 48) | dmaaddr, | ||
298 | (u64)blk_rq_pos(req) * 512, len, 0); | ||
299 | if (hvrc != HvLpEvent_Rc_Good) { | ||
300 | pr_warning("hv error on op %d\n", (int)hvrc); | ||
301 | return -1; | ||
302 | } | ||
303 | |||
304 | return 0; | ||
305 | } | ||
306 | |||
307 | static int rwreq; | ||
308 | |||
309 | static void do_viocd_request(struct request_queue *q) | ||
310 | { | ||
311 | struct request *req; | ||
312 | |||
313 | while ((rwreq == 0) && ((req = blk_fetch_request(q)) != NULL)) { | ||
314 | if (req->cmd_type != REQ_TYPE_FS) | ||
315 | __blk_end_request_all(req, -EIO); | ||
316 | else if (send_request(req) < 0) { | ||
317 | pr_warning("unable to send message to OS/400!\n"); | ||
318 | __blk_end_request_all(req, -EIO); | ||
319 | } else | ||
320 | rwreq++; | ||
321 | } | ||
322 | } | ||
323 | |||
324 | static unsigned int viocd_check_events(struct cdrom_device_info *cdi, | ||
325 | unsigned int clearing, int disc_nr) | ||
326 | { | ||
327 | struct viocd_waitevent we; | ||
328 | HvLpEvent_Rc hvrc; | ||
329 | int device_no = DEVICE_NR((struct disk_info *)cdi->handle); | ||
330 | |||
331 | init_completion(&we.com); | ||
332 | |||
333 | /* Send the open event to OS/400 */ | ||
334 | hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, | ||
335 | HvLpEvent_Type_VirtualIo, | ||
336 | viomajorsubtype_cdio | viocdcheck, | ||
337 | HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, | ||
338 | viopath_sourceinst(viopath_hostLp), | ||
339 | viopath_targetinst(viopath_hostLp), | ||
340 | (u64)&we, VIOVERSION << 16, ((u64)device_no << 48), | ||
341 | 0, 0, 0); | ||
342 | if (hvrc != 0) { | ||
343 | pr_warning("bad rc on HvCallEvent_signalLpEventFast %d\n", | ||
344 | (int)hvrc); | ||
345 | return 0; | ||
346 | } | ||
347 | |||
348 | wait_for_completion(&we.com); | ||
349 | |||
350 | /* Check the return code. If bad, assume no change */ | ||
351 | if (we.rc) { | ||
352 | const struct vio_error_entry *err = | ||
353 | vio_lookup_rc(viocd_err_table, we.sub_result); | ||
354 | pr_warning("bad rc %d:0x%04X on check_change: %s; Assuming no change\n", | ||
355 | we.rc, we.sub_result, err->msg); | ||
356 | return 0; | ||
357 | } | ||
358 | |||
359 | return we.changed ? DISK_EVENT_MEDIA_CHANGE : 0; | ||
360 | } | ||
361 | |||
362 | static int viocd_lock_door(struct cdrom_device_info *cdi, int locking) | ||
363 | { | ||
364 | HvLpEvent_Rc hvrc; | ||
365 | u64 device_no = DEVICE_NR((struct disk_info *)cdi->handle); | ||
366 | /* NOTE: flags is 1 or 0 so it won't overwrite the device_no */ | ||
367 | u64 flags = !!locking; | ||
368 | struct viocd_waitevent we; | ||
369 | |||
370 | init_completion(&we.com); | ||
371 | |||
372 | /* Send the lockdoor event to OS/400 */ | ||
373 | hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, | ||
374 | HvLpEvent_Type_VirtualIo, | ||
375 | viomajorsubtype_cdio | viocdlockdoor, | ||
376 | HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, | ||
377 | viopath_sourceinst(viopath_hostLp), | ||
378 | viopath_targetinst(viopath_hostLp), | ||
379 | (u64)&we, VIOVERSION << 16, | ||
380 | (device_no << 48) | (flags << 32), 0, 0, 0); | ||
381 | if (hvrc != 0) { | ||
382 | pr_warning("bad rc on HvCallEvent_signalLpEventFast %d\n", | ||
383 | (int)hvrc); | ||
384 | return -EIO; | ||
385 | } | ||
386 | |||
387 | wait_for_completion(&we.com); | ||
388 | |||
389 | if (we.rc != 0) | ||
390 | return -EIO; | ||
391 | return 0; | ||
392 | } | ||
393 | |||
394 | static int viocd_packet(struct cdrom_device_info *cdi, | ||
395 | struct packet_command *cgc) | ||
396 | { | ||
397 | unsigned int buflen = cgc->buflen; | ||
398 | int ret = -EIO; | ||
399 | |||
400 | switch (cgc->cmd[0]) { | ||
401 | case GPCMD_READ_DISC_INFO: | ||
402 | { | ||
403 | disc_information *di = (disc_information *)cgc->buffer; | ||
404 | |||
405 | if (buflen >= 2) { | ||
406 | di->disc_information_length = cpu_to_be16(1); | ||
407 | ret = 0; | ||
408 | } | ||
409 | if (buflen >= 3) | ||
410 | di->erasable = | ||
411 | (cdi->ops->capability & ~cdi->mask | ||
412 | & (CDC_DVD_RAM | CDC_RAM)) != 0; | ||
413 | } | ||
414 | break; | ||
415 | case GPCMD_GET_CONFIGURATION: | ||
416 | if (cgc->cmd[3] == CDF_RWRT) { | ||
417 | struct rwrt_feature_desc *rfd = (struct rwrt_feature_desc *)(cgc->buffer + sizeof(struct feature_header)); | ||
418 | |||
419 | if ((buflen >= | ||
420 | (sizeof(struct feature_header) + sizeof(*rfd))) && | ||
421 | (cdi->ops->capability & ~cdi->mask | ||
422 | & (CDC_DVD_RAM | CDC_RAM))) { | ||
423 | rfd->feature_code = cpu_to_be16(CDF_RWRT); | ||
424 | rfd->curr = 1; | ||
425 | ret = 0; | ||
426 | } | ||
427 | } | ||
428 | break; | ||
429 | default: | ||
430 | if (cgc->sense) { | ||
431 | /* indicate Unknown code */ | ||
432 | cgc->sense->sense_key = 0x05; | ||
433 | cgc->sense->asc = 0x20; | ||
434 | cgc->sense->ascq = 0x00; | ||
435 | } | ||
436 | break; | ||
437 | } | ||
438 | |||
439 | cgc->stat = ret; | ||
440 | return ret; | ||
441 | } | ||
442 | |||
443 | static void restart_all_queues(int first_index) | ||
444 | { | ||
445 | int i; | ||
446 | |||
447 | for (i = first_index + 1; i < viocd_numdev; i++) | ||
448 | if (viocd_diskinfo[i].viocd_disk) | ||
449 | blk_run_queue(viocd_diskinfo[i].viocd_disk->queue); | ||
450 | for (i = 0; i <= first_index; i++) | ||
451 | if (viocd_diskinfo[i].viocd_disk) | ||
452 | blk_run_queue(viocd_diskinfo[i].viocd_disk->queue); | ||
453 | } | ||
454 | |||
455 | /* This routine handles incoming CD LP events */ | ||
456 | static void vio_handle_cd_event(struct HvLpEvent *event) | ||
457 | { | ||
458 | struct viocdlpevent *bevent; | ||
459 | struct viocd_waitevent *pwe; | ||
460 | struct disk_info *di; | ||
461 | unsigned long flags; | ||
462 | struct request *req; | ||
463 | |||
464 | |||
465 | if (event == NULL) | ||
466 | /* Notification that a partition went away! */ | ||
467 | return; | ||
468 | /* First, we should NEVER get an int here...only acks */ | ||
469 | if (hvlpevent_is_int(event)) { | ||
470 | pr_warning("Yikes! got an int in viocd event handler!\n"); | ||
471 | if (hvlpevent_need_ack(event)) { | ||
472 | event->xRc = HvLpEvent_Rc_InvalidSubtype; | ||
473 | HvCallEvent_ackLpEvent(event); | ||
474 | } | ||
475 | } | ||
476 | |||
477 | bevent = (struct viocdlpevent *)event; | ||
478 | |||
479 | switch (event->xSubtype & VIOMINOR_SUBTYPE_MASK) { | ||
480 | case viocdopen: | ||
481 | if (event->xRc == 0) { | ||
482 | di = &viocd_diskinfo[bevent->disk]; | ||
483 | blk_queue_logical_block_size(di->viocd_disk->queue, | ||
484 | bevent->block_size); | ||
485 | set_capacity(di->viocd_disk, | ||
486 | bevent->media_size * | ||
487 | bevent->block_size / 512); | ||
488 | } | ||
489 | /* FALLTHROUGH !! */ | ||
490 | case viocdlockdoor: | ||
491 | pwe = (struct viocd_waitevent *)event->xCorrelationToken; | ||
492 | return_complete: | ||
493 | pwe->rc = event->xRc; | ||
494 | pwe->sub_result = bevent->sub_result; | ||
495 | complete(&pwe->com); | ||
496 | break; | ||
497 | |||
498 | case viocdcheck: | ||
499 | pwe = (struct viocd_waitevent *)event->xCorrelationToken; | ||
500 | pwe->changed = bevent->flags; | ||
501 | goto return_complete; | ||
502 | |||
503 | case viocdclose: | ||
504 | break; | ||
505 | |||
506 | case viocdwrite: | ||
507 | case viocdread: | ||
508 | /* | ||
509 | * Since this is running in interrupt mode, we need to | ||
510 | * make sure we're not stepping on any global I/O operations | ||
511 | */ | ||
512 | di = &viocd_diskinfo[bevent->disk]; | ||
513 | spin_lock_irqsave(&viocd_reqlock, flags); | ||
514 | dma_unmap_single(di->dev, bevent->token, bevent->len, | ||
515 | ((event->xSubtype & VIOMINOR_SUBTYPE_MASK) == viocdread) | ||
516 | ? DMA_FROM_DEVICE : DMA_TO_DEVICE); | ||
517 | req = (struct request *)bevent->event.xCorrelationToken; | ||
518 | rwreq--; | ||
519 | |||
520 | if (event->xRc != HvLpEvent_Rc_Good) { | ||
521 | const struct vio_error_entry *err = | ||
522 | vio_lookup_rc(viocd_err_table, | ||
523 | bevent->sub_result); | ||
524 | pr_warning("request %p failed with rc %d:0x%04X: %s\n", | ||
525 | req, event->xRc, | ||
526 | bevent->sub_result, err->msg); | ||
527 | __blk_end_request_all(req, -EIO); | ||
528 | } else | ||
529 | __blk_end_request_all(req, 0); | ||
530 | |||
531 | /* restart handling of incoming requests */ | ||
532 | spin_unlock_irqrestore(&viocd_reqlock, flags); | ||
533 | restart_all_queues(bevent->disk); | ||
534 | break; | ||
535 | |||
536 | default: | ||
537 | pr_warning("message with invalid subtype %0x04X!\n", | ||
538 | event->xSubtype & VIOMINOR_SUBTYPE_MASK); | ||
539 | if (hvlpevent_need_ack(event)) { | ||
540 | event->xRc = HvLpEvent_Rc_InvalidSubtype; | ||
541 | HvCallEvent_ackLpEvent(event); | ||
542 | } | ||
543 | } | ||
544 | } | ||
545 | |||
546 | static int viocd_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, | ||
547 | void *arg) | ||
548 | { | ||
549 | return -EINVAL; | ||
550 | } | ||
551 | |||
552 | static struct cdrom_device_ops viocd_dops = { | ||
553 | .open = viocd_open, | ||
554 | .release = viocd_release, | ||
555 | .check_events = viocd_check_events, | ||
556 | .lock_door = viocd_lock_door, | ||
557 | .generic_packet = viocd_packet, | ||
558 | .audio_ioctl = viocd_audio_ioctl, | ||
559 | .capability = CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED | CDC_SELECT_DISC | CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET | CDC_DRIVE_STATUS | CDC_GENERIC_PACKET | CDC_CD_R | CDC_CD_RW | CDC_DVD | CDC_DVD_R | CDC_DVD_RAM | CDC_RAM | ||
560 | }; | ||
561 | |||
562 | static int find_capability(const char *type) | ||
563 | { | ||
564 | struct capability_entry *entry; | ||
565 | |||
566 | for(entry = capability_table; entry->type; ++entry) | ||
567 | if(!strncmp(entry->type, type, 4)) | ||
568 | break; | ||
569 | return entry->capability; | ||
570 | } | ||
571 | |||
572 | static int viocd_probe(struct vio_dev *vdev, const struct vio_device_id *id) | ||
573 | { | ||
574 | struct gendisk *gendisk; | ||
575 | int deviceno; | ||
576 | struct disk_info *d; | ||
577 | struct cdrom_device_info *c; | ||
578 | struct request_queue *q; | ||
579 | struct device_node *node = vdev->dev.of_node; | ||
580 | |||
581 | deviceno = vdev->unit_address; | ||
582 | if (deviceno >= VIOCD_MAX_CD) | ||
583 | return -ENODEV; | ||
584 | if (!node) | ||
585 | return -ENODEV; | ||
586 | |||
587 | if (deviceno >= viocd_numdev) | ||
588 | viocd_numdev = deviceno + 1; | ||
589 | |||
590 | d = &viocd_diskinfo[deviceno]; | ||
591 | d->rsrcname = of_get_property(node, "linux,vio_rsrcname", NULL); | ||
592 | d->type = of_get_property(node, "linux,vio_type", NULL); | ||
593 | d->model = of_get_property(node, "linux,vio_model", NULL); | ||
594 | |||
595 | c = &d->viocd_info; | ||
596 | |||
597 | c->ops = &viocd_dops; | ||
598 | c->speed = 4; | ||
599 | c->capacity = 1; | ||
600 | c->handle = d; | ||
601 | c->mask = ~find_capability(d->type); | ||
602 | sprintf(c->name, VIOCD_DEVICE "%c", 'a' + deviceno); | ||
603 | |||
604 | if (register_cdrom(c) != 0) { | ||
605 | pr_warning("Cannot register viocd CD-ROM %s!\n", c->name); | ||
606 | goto out; | ||
607 | } | ||
608 | pr_info("cd %s is iSeries resource %10.10s type %4.4s, model %3.3s\n", | ||
609 | c->name, d->rsrcname, d->type, d->model); | ||
610 | q = blk_init_queue(do_viocd_request, &viocd_reqlock); | ||
611 | if (q == NULL) { | ||
612 | pr_warning("Cannot allocate queue for %s!\n", c->name); | ||
613 | goto out_unregister_cdrom; | ||
614 | } | ||
615 | gendisk = alloc_disk(1); | ||
616 | if (gendisk == NULL) { | ||
617 | pr_warning("Cannot create gendisk for %s!\n", c->name); | ||
618 | goto out_cleanup_queue; | ||
619 | } | ||
620 | gendisk->major = VIOCD_MAJOR; | ||
621 | gendisk->first_minor = deviceno; | ||
622 | strncpy(gendisk->disk_name, c->name, | ||
623 | sizeof(gendisk->disk_name)); | ||
624 | blk_queue_max_segments(q, 1); | ||
625 | blk_queue_max_hw_sectors(q, 4096 / 512); | ||
626 | gendisk->queue = q; | ||
627 | gendisk->fops = &viocd_fops; | ||
628 | gendisk->flags = GENHD_FL_CD | GENHD_FL_REMOVABLE | | ||
629 | GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE; | ||
630 | set_capacity(gendisk, 0); | ||
631 | gendisk->private_data = d; | ||
632 | d->viocd_disk = gendisk; | ||
633 | d->dev = &vdev->dev; | ||
634 | gendisk->driverfs_dev = d->dev; | ||
635 | add_disk(gendisk); | ||
636 | return 0; | ||
637 | |||
638 | out_cleanup_queue: | ||
639 | blk_cleanup_queue(q); | ||
640 | out_unregister_cdrom: | ||
641 | unregister_cdrom(c); | ||
642 | out: | ||
643 | return -ENODEV; | ||
644 | } | ||
645 | |||
646 | static int viocd_remove(struct vio_dev *vdev) | ||
647 | { | ||
648 | struct disk_info *d = &viocd_diskinfo[vdev->unit_address]; | ||
649 | |||
650 | unregister_cdrom(&d->viocd_info); | ||
651 | del_gendisk(d->viocd_disk); | ||
652 | blk_cleanup_queue(d->viocd_disk->queue); | ||
653 | put_disk(d->viocd_disk); | ||
654 | return 0; | ||
655 | } | ||
656 | |||
657 | /** | ||
658 | * viocd_device_table: Used by vio.c to match devices that we | ||
659 | * support. | ||
660 | */ | ||
661 | static struct vio_device_id viocd_device_table[] __devinitdata = { | ||
662 | { "block", "IBM,iSeries-viocd" }, | ||
663 | { "", "" } | ||
664 | }; | ||
665 | MODULE_DEVICE_TABLE(vio, viocd_device_table); | ||
666 | |||
667 | static struct vio_driver viocd_driver = { | ||
668 | .id_table = viocd_device_table, | ||
669 | .probe = viocd_probe, | ||
670 | .remove = viocd_remove, | ||
671 | .driver = { | ||
672 | .name = "viocd", | ||
673 | .owner = THIS_MODULE, | ||
674 | } | ||
675 | }; | ||
676 | |||
677 | static int __init viocd_init(void) | ||
678 | { | ||
679 | int ret = 0; | ||
680 | |||
681 | if (!firmware_has_feature(FW_FEATURE_ISERIES)) | ||
682 | return -ENODEV; | ||
683 | |||
684 | if (viopath_hostLp == HvLpIndexInvalid) { | ||
685 | vio_set_hostlp(); | ||
686 | /* If we don't have a host, bail out */ | ||
687 | if (viopath_hostLp == HvLpIndexInvalid) | ||
688 | return -ENODEV; | ||
689 | } | ||
690 | |||
691 | pr_info("vers " VIOCD_VERS ", hosting partition %d\n", viopath_hostLp); | ||
692 | |||
693 | if (register_blkdev(VIOCD_MAJOR, VIOCD_DEVICE) != 0) { | ||
694 | pr_warning("Unable to get major %d for %s\n", | ||
695 | VIOCD_MAJOR, VIOCD_DEVICE); | ||
696 | return -EIO; | ||
697 | } | ||
698 | |||
699 | ret = viopath_open(viopath_hostLp, viomajorsubtype_cdio, | ||
700 | MAX_CD_REQ + 2); | ||
701 | if (ret) { | ||
702 | pr_warning("error opening path to host partition %d\n", | ||
703 | viopath_hostLp); | ||
704 | goto out_unregister; | ||
705 | } | ||
706 | |||
707 | /* Initialize our request handler */ | ||
708 | vio_setHandler(viomajorsubtype_cdio, vio_handle_cd_event); | ||
709 | |||
710 | spin_lock_init(&viocd_reqlock); | ||
711 | |||
712 | ret = vio_register_driver(&viocd_driver); | ||
713 | if (ret) | ||
714 | goto out_free_info; | ||
715 | |||
716 | proc_create("iSeries/viocd", S_IFREG|S_IRUGO, NULL, | ||
717 | &proc_viocd_operations); | ||
718 | return 0; | ||
719 | |||
720 | out_free_info: | ||
721 | vio_clearHandler(viomajorsubtype_cdio); | ||
722 | viopath_close(viopath_hostLp, viomajorsubtype_cdio, MAX_CD_REQ + 2); | ||
723 | out_unregister: | ||
724 | unregister_blkdev(VIOCD_MAJOR, VIOCD_DEVICE); | ||
725 | return ret; | ||
726 | } | ||
727 | |||
728 | static void __exit viocd_exit(void) | ||
729 | { | ||
730 | remove_proc_entry("iSeries/viocd", NULL); | ||
731 | vio_unregister_driver(&viocd_driver); | ||
732 | viopath_close(viopath_hostLp, viomajorsubtype_cdio, MAX_CD_REQ + 2); | ||
733 | vio_clearHandler(viomajorsubtype_cdio); | ||
734 | unregister_blkdev(VIOCD_MAJOR, VIOCD_DEVICE); | ||
735 | } | ||
736 | |||
737 | module_init(viocd_init); | ||
738 | module_exit(viocd_exit); | ||
739 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c deleted file mode 100644 index 8b34c65511eb..000000000000 --- a/drivers/char/viotape.c +++ /dev/null | |||
@@ -1,1041 +0,0 @@ | |||
1 | /* -*- linux-c -*- | ||
2 | * drivers/char/viotape.c | ||
3 | * | ||
4 | * iSeries Virtual Tape | ||
5 | * | ||
6 | * Authors: Dave Boutcher <boutcher@us.ibm.com> | ||
7 | * Ryan Arnold <ryanarn@us.ibm.com> | ||
8 | * Colin Devilbiss <devilbis@us.ibm.com> | ||
9 | * Stephen Rothwell | ||
10 | * | ||
11 | * (C) Copyright 2000-2004 IBM Corporation | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License as | ||
15 | * published by the Free Software Foundation; either version 2 of the | ||
16 | * License, or (at your option) anyu later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, but | ||
19 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
21 | * General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, write to the Free Software Foundation, | ||
25 | * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
26 | * | ||
27 | * This routine provides access to tape drives owned and managed by an OS/400 | ||
28 | * partition running on the same box as this Linux partition. | ||
29 | * | ||
30 | * All tape operations are performed by sending messages back and forth to | ||
31 | * the OS/400 partition. The format of the messages is defined in | ||
32 | * iseries/vio.h | ||
33 | */ | ||
34 | #include <linux/module.h> | ||
35 | #include <linux/kernel.h> | ||
36 | #include <linux/errno.h> | ||
37 | #include <linux/init.h> | ||
38 | #include <linux/wait.h> | ||
39 | #include <linux/spinlock.h> | ||
40 | #include <linux/mtio.h> | ||
41 | #include <linux/device.h> | ||
42 | #include <linux/dma-mapping.h> | ||
43 | #include <linux/fs.h> | ||
44 | #include <linux/cdev.h> | ||
45 | #include <linux/major.h> | ||
46 | #include <linux/completion.h> | ||
47 | #include <linux/proc_fs.h> | ||
48 | #include <linux/seq_file.h> | ||
49 | #include <linux/mutex.h> | ||
50 | #include <linux/slab.h> | ||
51 | |||
52 | #include <asm/uaccess.h> | ||
53 | #include <asm/ioctls.h> | ||
54 | #include <asm/firmware.h> | ||
55 | #include <asm/vio.h> | ||
56 | #include <asm/iseries/vio.h> | ||
57 | #include <asm/iseries/hv_lp_event.h> | ||
58 | #include <asm/iseries/hv_call_event.h> | ||
59 | #include <asm/iseries/hv_lp_config.h> | ||
60 | |||
61 | #define VIOTAPE_VERSION "1.2" | ||
62 | #define VIOTAPE_MAXREQ 1 | ||
63 | |||
64 | #define VIOTAPE_KERN_WARN KERN_WARNING "viotape: " | ||
65 | #define VIOTAPE_KERN_INFO KERN_INFO "viotape: " | ||
66 | |||
67 | static DEFINE_MUTEX(proc_viotape_mutex); | ||
68 | static int viotape_numdev; | ||
69 | |||
70 | /* | ||
71 | * The minor number follows the conventions of the SCSI tape drives. The | ||
72 | * rewind and mode are encoded in the minor #. We use this struct to break | ||
73 | * them out | ||
74 | */ | ||
75 | struct viot_devinfo_struct { | ||
76 | int devno; | ||
77 | int mode; | ||
78 | int rewind; | ||
79 | }; | ||
80 | |||
81 | #define VIOTAPOP_RESET 0 | ||
82 | #define VIOTAPOP_FSF 1 | ||
83 | #define VIOTAPOP_BSF 2 | ||
84 | #define VIOTAPOP_FSR 3 | ||
85 | #define VIOTAPOP_BSR 4 | ||
86 | #define VIOTAPOP_WEOF 5 | ||
87 | #define VIOTAPOP_REW 6 | ||
88 | #define VIOTAPOP_NOP 7 | ||
89 | #define VIOTAPOP_EOM 8 | ||
90 | #define VIOTAPOP_ERASE 9 | ||
91 | #define VIOTAPOP_SETBLK 10 | ||
92 | #define VIOTAPOP_SETDENSITY 11 | ||
93 | #define VIOTAPOP_SETPOS 12 | ||
94 | #define VIOTAPOP_GETPOS 13 | ||
95 | #define VIOTAPOP_SETPART 14 | ||
96 | #define VIOTAPOP_UNLOAD 15 | ||
97 | |||
98 | enum viotaperc { | ||
99 | viotape_InvalidRange = 0x0601, | ||
100 | viotape_InvalidToken = 0x0602, | ||
101 | viotape_DMAError = 0x0603, | ||
102 | viotape_UseError = 0x0604, | ||
103 | viotape_ReleaseError = 0x0605, | ||
104 | viotape_InvalidTape = 0x0606, | ||
105 | viotape_InvalidOp = 0x0607, | ||
106 | viotape_TapeErr = 0x0608, | ||
107 | |||
108 | viotape_AllocTimedOut = 0x0640, | ||
109 | viotape_BOTEnc = 0x0641, | ||
110 | viotape_BlankTape = 0x0642, | ||
111 | viotape_BufferEmpty = 0x0643, | ||
112 | viotape_CleanCartFound = 0x0644, | ||
113 | viotape_CmdNotAllowed = 0x0645, | ||
114 | viotape_CmdNotSupported = 0x0646, | ||
115 | viotape_DataCheck = 0x0647, | ||
116 | viotape_DecompressErr = 0x0648, | ||
117 | viotape_DeviceTimeout = 0x0649, | ||
118 | viotape_DeviceUnavail = 0x064a, | ||
119 | viotape_DeviceBusy = 0x064b, | ||
120 | viotape_EndOfMedia = 0x064c, | ||
121 | viotape_EndOfTape = 0x064d, | ||
122 | viotape_EquipCheck = 0x064e, | ||
123 | viotape_InsufficientRs = 0x064f, | ||
124 | viotape_InvalidLogBlk = 0x0650, | ||
125 | viotape_LengthError = 0x0651, | ||
126 | viotape_LibDoorOpen = 0x0652, | ||
127 | viotape_LoadFailure = 0x0653, | ||
128 | viotape_NotCapable = 0x0654, | ||
129 | viotape_NotOperational = 0x0655, | ||
130 | viotape_NotReady = 0x0656, | ||
131 | viotape_OpCancelled = 0x0657, | ||
132 | viotape_PhyLinkErr = 0x0658, | ||
133 | viotape_RdyNotBOT = 0x0659, | ||
134 | viotape_TapeMark = 0x065a, | ||
135 | viotape_WriteProt = 0x065b | ||
136 | }; | ||
137 | |||
138 | static const struct vio_error_entry viotape_err_table[] = { | ||
139 | { viotape_InvalidRange, EIO, "Internal error" }, | ||
140 | { viotape_InvalidToken, EIO, "Internal error" }, | ||
141 | { viotape_DMAError, EIO, "DMA error" }, | ||
142 | { viotape_UseError, EIO, "Internal error" }, | ||
143 | { viotape_ReleaseError, EIO, "Internal error" }, | ||
144 | { viotape_InvalidTape, EIO, "Invalid tape device" }, | ||
145 | { viotape_InvalidOp, EIO, "Invalid operation" }, | ||
146 | { viotape_TapeErr, EIO, "Tape error" }, | ||
147 | { viotape_AllocTimedOut, EBUSY, "Allocate timed out" }, | ||
148 | { viotape_BOTEnc, EIO, "Beginning of tape encountered" }, | ||
149 | { viotape_BlankTape, EIO, "Blank tape" }, | ||
150 | { viotape_BufferEmpty, EIO, "Buffer empty" }, | ||
151 | { viotape_CleanCartFound, ENOMEDIUM, "Cleaning cartridge found" }, | ||
152 | { viotape_CmdNotAllowed, EIO, "Command not allowed" }, | ||
153 | { viotape_CmdNotSupported, EIO, "Command not supported" }, | ||
154 | { viotape_DataCheck, EIO, "Data check" }, | ||
155 | { viotape_DecompressErr, EIO, "Decompression error" }, | ||
156 | { viotape_DeviceTimeout, EBUSY, "Device timeout" }, | ||
157 | { viotape_DeviceUnavail, EIO, "Device unavailable" }, | ||
158 | { viotape_DeviceBusy, EBUSY, "Device busy" }, | ||
159 | { viotape_EndOfMedia, ENOSPC, "End of media" }, | ||
160 | { viotape_EndOfTape, ENOSPC, "End of tape" }, | ||
161 | { viotape_EquipCheck, EIO, "Equipment check" }, | ||
162 | { viotape_InsufficientRs, EOVERFLOW, "Insufficient tape resources" }, | ||
163 | { viotape_InvalidLogBlk, EIO, "Invalid logical block location" }, | ||
164 | { viotape_LengthError, EOVERFLOW, "Length error" }, | ||
165 | { viotape_LibDoorOpen, EBUSY, "Door open" }, | ||
166 | { viotape_LoadFailure, ENOMEDIUM, "Load failure" }, | ||
167 | { viotape_NotCapable, EIO, "Not capable" }, | ||
168 | { viotape_NotOperational, EIO, "Not operational" }, | ||
169 | { viotape_NotReady, EIO, "Not ready" }, | ||
170 | { viotape_OpCancelled, EIO, "Operation cancelled" }, | ||
171 | { viotape_PhyLinkErr, EIO, "Physical link error" }, | ||
172 | { viotape_RdyNotBOT, EIO, "Ready but not beginning of tape" }, | ||
173 | { viotape_TapeMark, EIO, "Tape mark" }, | ||
174 | { viotape_WriteProt, EROFS, "Write protection error" }, | ||
175 | { 0, 0, NULL }, | ||
176 | }; | ||
177 | |||
178 | /* Maximum number of tapes we support */ | ||
179 | #define VIOTAPE_MAX_TAPE HVMAXARCHITECTEDVIRTUALTAPES | ||
180 | #define MAX_PARTITIONS 4 | ||
181 | |||
182 | /* defines for current tape state */ | ||
183 | #define VIOT_IDLE 0 | ||
184 | #define VIOT_READING 1 | ||
185 | #define VIOT_WRITING 2 | ||
186 | |||
187 | /* Our info on the tapes */ | ||
188 | static struct { | ||
189 | const char *rsrcname; | ||
190 | const char *type; | ||
191 | const char *model; | ||
192 | } viotape_unitinfo[VIOTAPE_MAX_TAPE]; | ||
193 | |||
194 | static struct mtget viomtget[VIOTAPE_MAX_TAPE]; | ||
195 | |||
196 | static struct class *tape_class; | ||
197 | |||
198 | static struct device *tape_device[VIOTAPE_MAX_TAPE]; | ||
199 | |||
200 | /* | ||
201 | * maintain the current state of each tape (and partition) | ||
202 | * so that we know when to write EOF marks. | ||
203 | */ | ||
204 | static struct { | ||
205 | unsigned char cur_part; | ||
206 | unsigned char part_stat_rwi[MAX_PARTITIONS]; | ||
207 | } state[VIOTAPE_MAX_TAPE]; | ||
208 | |||
209 | /* We single-thread */ | ||
210 | static struct semaphore reqSem; | ||
211 | |||
212 | /* | ||
213 | * When we send a request, we use this struct to get the response back | ||
214 | * from the interrupt handler | ||
215 | */ | ||
216 | struct op_struct { | ||
217 | void *buffer; | ||
218 | dma_addr_t dmaaddr; | ||
219 | size_t count; | ||
220 | int rc; | ||
221 | int non_blocking; | ||
222 | struct completion com; | ||
223 | struct device *dev; | ||
224 | struct op_struct *next; | ||
225 | }; | ||
226 | |||
227 | static spinlock_t op_struct_list_lock; | ||
228 | static struct op_struct *op_struct_list; | ||
229 | |||
230 | /* forward declaration to resolve interdependence */ | ||
231 | static int chg_state(int index, unsigned char new_state, struct file *file); | ||
232 | |||
233 | /* procfs support */ | ||
234 | static int proc_viotape_show(struct seq_file *m, void *v) | ||
235 | { | ||
236 | int i; | ||
237 | |||
238 | seq_printf(m, "viotape driver version " VIOTAPE_VERSION "\n"); | ||
239 | for (i = 0; i < viotape_numdev; i++) { | ||
240 | seq_printf(m, "viotape device %d is iSeries resource %10.10s" | ||
241 | "type %4.4s, model %3.3s\n", | ||
242 | i, viotape_unitinfo[i].rsrcname, | ||
243 | viotape_unitinfo[i].type, | ||
244 | viotape_unitinfo[i].model); | ||
245 | } | ||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | static int proc_viotape_open(struct inode *inode, struct file *file) | ||
250 | { | ||
251 | return single_open(file, proc_viotape_show, NULL); | ||
252 | } | ||
253 | |||
254 | static const struct file_operations proc_viotape_operations = { | ||
255 | .owner = THIS_MODULE, | ||
256 | .open = proc_viotape_open, | ||
257 | .read = seq_read, | ||
258 | .llseek = seq_lseek, | ||
259 | .release = single_release, | ||
260 | }; | ||
261 | |||
262 | /* Decode the device minor number into its parts */ | ||
263 | void get_dev_info(struct inode *ino, struct viot_devinfo_struct *devi) | ||
264 | { | ||
265 | devi->devno = iminor(ino) & 0x1F; | ||
266 | devi->mode = (iminor(ino) & 0x60) >> 5; | ||
267 | /* if bit is set in the minor, do _not_ rewind automatically */ | ||
268 | devi->rewind = (iminor(ino) & 0x80) == 0; | ||
269 | } | ||
270 | |||
271 | /* This is called only from the exit and init paths, so no need for locking */ | ||
272 | static void clear_op_struct_pool(void) | ||
273 | { | ||
274 | while (op_struct_list) { | ||
275 | struct op_struct *toFree = op_struct_list; | ||
276 | op_struct_list = op_struct_list->next; | ||
277 | kfree(toFree); | ||
278 | } | ||
279 | } | ||
280 | |||
281 | /* Likewise, this is only called from the init path */ | ||
282 | static int add_op_structs(int structs) | ||
283 | { | ||
284 | int i; | ||
285 | |||
286 | for (i = 0; i < structs; ++i) { | ||
287 | struct op_struct *new_struct = | ||
288 | kmalloc(sizeof(*new_struct), GFP_KERNEL); | ||
289 | if (!new_struct) { | ||
290 | clear_op_struct_pool(); | ||
291 | return -ENOMEM; | ||
292 | } | ||
293 | new_struct->next = op_struct_list; | ||
294 | op_struct_list = new_struct; | ||
295 | } | ||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | /* Allocate an op structure from our pool */ | ||
300 | static struct op_struct *get_op_struct(void) | ||
301 | { | ||
302 | struct op_struct *retval; | ||
303 | unsigned long flags; | ||
304 | |||
305 | spin_lock_irqsave(&op_struct_list_lock, flags); | ||
306 | retval = op_struct_list; | ||
307 | if (retval) | ||
308 | op_struct_list = retval->next; | ||
309 | spin_unlock_irqrestore(&op_struct_list_lock, flags); | ||
310 | if (retval) { | ||
311 | memset(retval, 0, sizeof(*retval)); | ||
312 | init_completion(&retval->com); | ||
313 | } | ||
314 | |||
315 | return retval; | ||
316 | } | ||
317 | |||
318 | /* Return an op structure to our pool */ | ||
319 | static void free_op_struct(struct op_struct *op_struct) | ||
320 | { | ||
321 | unsigned long flags; | ||
322 | |||
323 | spin_lock_irqsave(&op_struct_list_lock, flags); | ||
324 | op_struct->next = op_struct_list; | ||
325 | op_struct_list = op_struct; | ||
326 | spin_unlock_irqrestore(&op_struct_list_lock, flags); | ||
327 | } | ||
328 | |||
329 | /* Map our tape return codes to errno values */ | ||
330 | int tape_rc_to_errno(int tape_rc, char *operation, int tapeno) | ||
331 | { | ||
332 | const struct vio_error_entry *err; | ||
333 | |||
334 | if (tape_rc == 0) | ||
335 | return 0; | ||
336 | |||
337 | err = vio_lookup_rc(viotape_err_table, tape_rc); | ||
338 | printk(VIOTAPE_KERN_WARN "error(%s) 0x%04x on Device %d (%-10s): %s\n", | ||
339 | operation, tape_rc, tapeno, | ||
340 | viotape_unitinfo[tapeno].rsrcname, err->msg); | ||
341 | return -err->errno; | ||
342 | } | ||
343 | |||
344 | /* Write */ | ||
345 | static ssize_t viotap_write(struct file *file, const char *buf, | ||
346 | size_t count, loff_t * ppos) | ||
347 | { | ||
348 | HvLpEvent_Rc hvrc; | ||
349 | unsigned short flags = file->f_flags; | ||
350 | int noblock = ((flags & O_NONBLOCK) != 0); | ||
351 | ssize_t ret; | ||
352 | struct viot_devinfo_struct devi; | ||
353 | struct op_struct *op = get_op_struct(); | ||
354 | |||
355 | if (op == NULL) | ||
356 | return -ENOMEM; | ||
357 | |||
358 | get_dev_info(file->f_path.dentry->d_inode, &devi); | ||
359 | |||
360 | /* | ||
361 | * We need to make sure we can send a request. We use | ||
362 | * a semaphore to keep track of # requests in use. If | ||
363 | * we are non-blocking, make sure we don't block on the | ||
364 | * semaphore | ||
365 | */ | ||
366 | if (noblock) { | ||
367 | if (down_trylock(&reqSem)) { | ||
368 | ret = -EWOULDBLOCK; | ||
369 | goto free_op; | ||
370 | } | ||
371 | } else | ||
372 | down(&reqSem); | ||
373 | |||
374 | /* Allocate a DMA buffer */ | ||
375 | op->dev = tape_device[devi.devno]; | ||
376 | op->buffer = dma_alloc_coherent(op->dev, count, &op->dmaaddr, | ||
377 | GFP_ATOMIC); | ||
378 | |||
379 | if (op->buffer == NULL) { | ||
380 | printk(VIOTAPE_KERN_WARN | ||
381 | "error allocating dma buffer for len %ld\n", | ||
382 | count); | ||
383 | ret = -EFAULT; | ||
384 | goto up_sem; | ||
385 | } | ||
386 | |||
387 | /* Copy the data into the buffer */ | ||
388 | if (copy_from_user(op->buffer, buf, count)) { | ||
389 | printk(VIOTAPE_KERN_WARN "tape: error on copy from user\n"); | ||
390 | ret = -EFAULT; | ||
391 | goto free_dma; | ||
392 | } | ||
393 | |||
394 | op->non_blocking = noblock; | ||
395 | init_completion(&op->com); | ||
396 | op->count = count; | ||
397 | |||
398 | hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, | ||
399 | HvLpEvent_Type_VirtualIo, | ||
400 | viomajorsubtype_tape | viotapewrite, | ||
401 | HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, | ||
402 | viopath_sourceinst(viopath_hostLp), | ||
403 | viopath_targetinst(viopath_hostLp), | ||
404 | (u64)(unsigned long)op, VIOVERSION << 16, | ||
405 | ((u64)devi.devno << 48) | op->dmaaddr, count, 0, 0); | ||
406 | if (hvrc != HvLpEvent_Rc_Good) { | ||
407 | printk(VIOTAPE_KERN_WARN "hv error on op %d\n", | ||
408 | (int)hvrc); | ||
409 | ret = -EIO; | ||
410 | goto free_dma; | ||
411 | } | ||
412 | |||
413 | if (noblock) | ||
414 | return count; | ||
415 | |||
416 | wait_for_completion(&op->com); | ||
417 | |||
418 | if (op->rc) | ||
419 | ret = tape_rc_to_errno(op->rc, "write", devi.devno); | ||
420 | else { | ||
421 | chg_state(devi.devno, VIOT_WRITING, file); | ||
422 | ret = op->count; | ||
423 | } | ||
424 | |||
425 | free_dma: | ||
426 | dma_free_coherent(op->dev, count, op->buffer, op->dmaaddr); | ||
427 | up_sem: | ||
428 | up(&reqSem); | ||
429 | free_op: | ||
430 | free_op_struct(op); | ||
431 | return ret; | ||
432 | } | ||
433 | |||
434 | /* read */ | ||
435 | static ssize_t viotap_read(struct file *file, char *buf, size_t count, | ||
436 | loff_t *ptr) | ||
437 | { | ||
438 | HvLpEvent_Rc hvrc; | ||
439 | unsigned short flags = file->f_flags; | ||
440 | struct op_struct *op = get_op_struct(); | ||
441 | int noblock = ((flags & O_NONBLOCK) != 0); | ||
442 | ssize_t ret; | ||
443 | struct viot_devinfo_struct devi; | ||
444 | |||
445 | if (op == NULL) | ||
446 | return -ENOMEM; | ||
447 | |||
448 | get_dev_info(file->f_path.dentry->d_inode, &devi); | ||
449 | |||
450 | /* | ||
451 | * We need to make sure we can send a request. We use | ||
452 | * a semaphore to keep track of # requests in use. If | ||
453 | * we are non-blocking, make sure we don't block on the | ||
454 | * semaphore | ||
455 | */ | ||
456 | if (noblock) { | ||
457 | if (down_trylock(&reqSem)) { | ||
458 | ret = -EWOULDBLOCK; | ||
459 | goto free_op; | ||
460 | } | ||
461 | } else | ||
462 | down(&reqSem); | ||
463 | |||
464 | chg_state(devi.devno, VIOT_READING, file); | ||
465 | |||
466 | /* Allocate a DMA buffer */ | ||
467 | op->dev = tape_device[devi.devno]; | ||
468 | op->buffer = dma_alloc_coherent(op->dev, count, &op->dmaaddr, | ||
469 | GFP_ATOMIC); | ||
470 | if (op->buffer == NULL) { | ||
471 | ret = -EFAULT; | ||
472 | goto up_sem; | ||
473 | } | ||
474 | |||
475 | op->count = count; | ||
476 | init_completion(&op->com); | ||
477 | |||
478 | hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, | ||
479 | HvLpEvent_Type_VirtualIo, | ||
480 | viomajorsubtype_tape | viotaperead, | ||
481 | HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, | ||
482 | viopath_sourceinst(viopath_hostLp), | ||
483 | viopath_targetinst(viopath_hostLp), | ||
484 | (u64)(unsigned long)op, VIOVERSION << 16, | ||
485 | ((u64)devi.devno << 48) | op->dmaaddr, count, 0, 0); | ||
486 | if (hvrc != HvLpEvent_Rc_Good) { | ||
487 | printk(VIOTAPE_KERN_WARN "tape hv error on op %d\n", | ||
488 | (int)hvrc); | ||
489 | ret = -EIO; | ||
490 | goto free_dma; | ||
491 | } | ||
492 | |||
493 | wait_for_completion(&op->com); | ||
494 | |||
495 | if (op->rc) | ||
496 | ret = tape_rc_to_errno(op->rc, "read", devi.devno); | ||
497 | else { | ||
498 | ret = op->count; | ||
499 | if (ret && copy_to_user(buf, op->buffer, ret)) { | ||
500 | printk(VIOTAPE_KERN_WARN "error on copy_to_user\n"); | ||
501 | ret = -EFAULT; | ||
502 | } | ||
503 | } | ||
504 | |||
505 | free_dma: | ||
506 | dma_free_coherent(op->dev, count, op->buffer, op->dmaaddr); | ||
507 | up_sem: | ||
508 | up(&reqSem); | ||
509 | free_op: | ||
510 | free_op_struct(op); | ||
511 | return ret; | ||
512 | } | ||
513 | |||
514 | /* ioctl */ | ||
515 | static int viotap_ioctl(struct inode *inode, struct file *file, | ||
516 | unsigned int cmd, unsigned long arg) | ||
517 | { | ||
518 | HvLpEvent_Rc hvrc; | ||
519 | int ret; | ||
520 | struct viot_devinfo_struct devi; | ||
521 | struct mtop mtc; | ||
522 | u32 myOp; | ||
523 | struct op_struct *op = get_op_struct(); | ||
524 | |||
525 | if (op == NULL) | ||
526 | return -ENOMEM; | ||
527 | |||
528 | get_dev_info(file->f_path.dentry->d_inode, &devi); | ||
529 | |||
530 | down(&reqSem); | ||
531 | |||
532 | ret = -EINVAL; | ||
533 | |||
534 | switch (cmd) { | ||
535 | case MTIOCTOP: | ||
536 | ret = -EFAULT; | ||
537 | /* | ||
538 | * inode is null if and only if we (the kernel) | ||
539 | * made the request | ||
540 | */ | ||
541 | if (inode == NULL) | ||
542 | memcpy(&mtc, (void *) arg, sizeof(struct mtop)); | ||
543 | else if (copy_from_user((char *)&mtc, (char *)arg, | ||
544 | sizeof(struct mtop))) | ||
545 | goto free_op; | ||
546 | |||
547 | ret = -EIO; | ||
548 | switch (mtc.mt_op) { | ||
549 | case MTRESET: | ||
550 | myOp = VIOTAPOP_RESET; | ||
551 | break; | ||
552 | case MTFSF: | ||
553 | myOp = VIOTAPOP_FSF; | ||
554 | break; | ||
555 | case MTBSF: | ||
556 | myOp = VIOTAPOP_BSF; | ||
557 | break; | ||
558 | case MTFSR: | ||
559 | myOp = VIOTAPOP_FSR; | ||
560 | break; | ||
561 | case MTBSR: | ||
562 | myOp = VIOTAPOP_BSR; | ||
563 | break; | ||
564 | case MTWEOF: | ||
565 | myOp = VIOTAPOP_WEOF; | ||
566 | break; | ||
567 | case MTREW: | ||
568 | myOp = VIOTAPOP_REW; | ||
569 | break; | ||
570 | case MTNOP: | ||
571 | myOp = VIOTAPOP_NOP; | ||
572 | break; | ||
573 | case MTEOM: | ||
574 | myOp = VIOTAPOP_EOM; | ||
575 | break; | ||
576 | case MTERASE: | ||
577 | myOp = VIOTAPOP_ERASE; | ||
578 | break; | ||
579 | case MTSETBLK: | ||
580 | myOp = VIOTAPOP_SETBLK; | ||
581 | break; | ||
582 | case MTSETDENSITY: | ||
583 | myOp = VIOTAPOP_SETDENSITY; | ||
584 | break; | ||
585 | case MTTELL: | ||
586 | myOp = VIOTAPOP_GETPOS; | ||
587 | break; | ||
588 | case MTSEEK: | ||
589 | myOp = VIOTAPOP_SETPOS; | ||
590 | break; | ||
591 | case MTSETPART: | ||
592 | myOp = VIOTAPOP_SETPART; | ||
593 | break; | ||
594 | case MTOFFL: | ||
595 | myOp = VIOTAPOP_UNLOAD; | ||
596 | break; | ||
597 | default: | ||
598 | printk(VIOTAPE_KERN_WARN "MTIOCTOP called " | ||
599 | "with invalid op 0x%x\n", mtc.mt_op); | ||
600 | goto free_op; | ||
601 | } | ||
602 | |||
603 | /* | ||
604 | * if we moved the head, we are no longer | ||
605 | * reading or writing | ||
606 | */ | ||
607 | switch (mtc.mt_op) { | ||
608 | case MTFSF: | ||
609 | case MTBSF: | ||
610 | case MTFSR: | ||
611 | case MTBSR: | ||
612 | case MTTELL: | ||
613 | case MTSEEK: | ||
614 | case MTREW: | ||
615 | chg_state(devi.devno, VIOT_IDLE, file); | ||
616 | } | ||
617 | |||
618 | init_completion(&op->com); | ||
619 | hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, | ||
620 | HvLpEvent_Type_VirtualIo, | ||
621 | viomajorsubtype_tape | viotapeop, | ||
622 | HvLpEvent_AckInd_DoAck, | ||
623 | HvLpEvent_AckType_ImmediateAck, | ||
624 | viopath_sourceinst(viopath_hostLp), | ||
625 | viopath_targetinst(viopath_hostLp), | ||
626 | (u64)(unsigned long)op, | ||
627 | VIOVERSION << 16, | ||
628 | ((u64)devi.devno << 48), 0, | ||
629 | (((u64)myOp) << 32) | mtc.mt_count, 0); | ||
630 | if (hvrc != HvLpEvent_Rc_Good) { | ||
631 | printk(VIOTAPE_KERN_WARN "hv error on op %d\n", | ||
632 | (int)hvrc); | ||
633 | goto free_op; | ||
634 | } | ||
635 | wait_for_completion(&op->com); | ||
636 | ret = tape_rc_to_errno(op->rc, "tape operation", devi.devno); | ||
637 | goto free_op; | ||
638 | |||
639 | case MTIOCGET: | ||
640 | ret = -EIO; | ||
641 | init_completion(&op->com); | ||
642 | hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, | ||
643 | HvLpEvent_Type_VirtualIo, | ||
644 | viomajorsubtype_tape | viotapegetstatus, | ||
645 | HvLpEvent_AckInd_DoAck, | ||
646 | HvLpEvent_AckType_ImmediateAck, | ||
647 | viopath_sourceinst(viopath_hostLp), | ||
648 | viopath_targetinst(viopath_hostLp), | ||
649 | (u64)(unsigned long)op, VIOVERSION << 16, | ||
650 | ((u64)devi.devno << 48), 0, 0, 0); | ||
651 | if (hvrc != HvLpEvent_Rc_Good) { | ||
652 | printk(VIOTAPE_KERN_WARN "hv error on op %d\n", | ||
653 | (int)hvrc); | ||
654 | goto free_op; | ||
655 | } | ||
656 | wait_for_completion(&op->com); | ||
657 | |||
658 | /* Operation is complete - grab the error code */ | ||
659 | ret = tape_rc_to_errno(op->rc, "get status", devi.devno); | ||
660 | free_op_struct(op); | ||
661 | up(&reqSem); | ||
662 | |||
663 | if ((ret == 0) && copy_to_user((void *)arg, | ||
664 | &viomtget[devi.devno], | ||
665 | sizeof(viomtget[0]))) | ||
666 | ret = -EFAULT; | ||
667 | return ret; | ||
668 | case MTIOCPOS: | ||
669 | printk(VIOTAPE_KERN_WARN "Got an (unsupported) MTIOCPOS\n"); | ||
670 | break; | ||
671 | default: | ||
672 | printk(VIOTAPE_KERN_WARN "got an unsupported ioctl 0x%0x\n", | ||
673 | cmd); | ||
674 | break; | ||
675 | } | ||
676 | |||
677 | free_op: | ||
678 | free_op_struct(op); | ||
679 | up(&reqSem); | ||
680 | return ret; | ||
681 | } | ||
682 | |||
683 | static long viotap_unlocked_ioctl(struct file *file, | ||
684 | unsigned int cmd, unsigned long arg) | ||
685 | { | ||
686 | long rc; | ||
687 | |||
688 | mutex_lock(&proc_viotape_mutex); | ||
689 | rc = viotap_ioctl(file->f_path.dentry->d_inode, file, cmd, arg); | ||
690 | mutex_unlock(&proc_viotape_mutex); | ||
691 | return rc; | ||
692 | } | ||
693 | |||
694 | static int viotap_open(struct inode *inode, struct file *file) | ||
695 | { | ||
696 | HvLpEvent_Rc hvrc; | ||
697 | struct viot_devinfo_struct devi; | ||
698 | int ret; | ||
699 | struct op_struct *op = get_op_struct(); | ||
700 | |||
701 | if (op == NULL) | ||
702 | return -ENOMEM; | ||
703 | |||
704 | mutex_lock(&proc_viotape_mutex); | ||
705 | get_dev_info(file->f_path.dentry->d_inode, &devi); | ||
706 | |||
707 | /* Note: We currently only support one mode! */ | ||
708 | if ((devi.devno >= viotape_numdev) || (devi.mode)) { | ||
709 | ret = -ENODEV; | ||
710 | goto free_op; | ||
711 | } | ||
712 | |||
713 | init_completion(&op->com); | ||
714 | |||
715 | hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, | ||
716 | HvLpEvent_Type_VirtualIo, | ||
717 | viomajorsubtype_tape | viotapeopen, | ||
718 | HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, | ||
719 | viopath_sourceinst(viopath_hostLp), | ||
720 | viopath_targetinst(viopath_hostLp), | ||
721 | (u64)(unsigned long)op, VIOVERSION << 16, | ||
722 | ((u64)devi.devno << 48), 0, 0, 0); | ||
723 | if (hvrc != 0) { | ||
724 | printk(VIOTAPE_KERN_WARN "bad rc on signalLpEvent %d\n", | ||
725 | (int) hvrc); | ||
726 | ret = -EIO; | ||
727 | goto free_op; | ||
728 | } | ||
729 | |||
730 | wait_for_completion(&op->com); | ||
731 | ret = tape_rc_to_errno(op->rc, "open", devi.devno); | ||
732 | |||
733 | free_op: | ||
734 | free_op_struct(op); | ||
735 | mutex_unlock(&proc_viotape_mutex); | ||
736 | return ret; | ||
737 | } | ||
738 | |||
739 | |||
740 | static int viotap_release(struct inode *inode, struct file *file) | ||
741 | { | ||
742 | HvLpEvent_Rc hvrc; | ||
743 | struct viot_devinfo_struct devi; | ||
744 | int ret = 0; | ||
745 | struct op_struct *op = get_op_struct(); | ||
746 | |||
747 | if (op == NULL) | ||
748 | return -ENOMEM; | ||
749 | init_completion(&op->com); | ||
750 | |||
751 | get_dev_info(file->f_path.dentry->d_inode, &devi); | ||
752 | |||
753 | if (devi.devno >= viotape_numdev) { | ||
754 | ret = -ENODEV; | ||
755 | goto free_op; | ||
756 | } | ||
757 | |||
758 | chg_state(devi.devno, VIOT_IDLE, file); | ||
759 | |||
760 | if (devi.rewind) { | ||
761 | hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, | ||
762 | HvLpEvent_Type_VirtualIo, | ||
763 | viomajorsubtype_tape | viotapeop, | ||
764 | HvLpEvent_AckInd_DoAck, | ||
765 | HvLpEvent_AckType_ImmediateAck, | ||
766 | viopath_sourceinst(viopath_hostLp), | ||
767 | viopath_targetinst(viopath_hostLp), | ||
768 | (u64)(unsigned long)op, VIOVERSION << 16, | ||
769 | ((u64)devi.devno << 48), 0, | ||
770 | ((u64)VIOTAPOP_REW) << 32, 0); | ||
771 | wait_for_completion(&op->com); | ||
772 | |||
773 | tape_rc_to_errno(op->rc, "rewind", devi.devno); | ||
774 | } | ||
775 | |||
776 | hvrc = HvCallEvent_signalLpEventFast(viopath_hostLp, | ||
777 | HvLpEvent_Type_VirtualIo, | ||
778 | viomajorsubtype_tape | viotapeclose, | ||
779 | HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, | ||
780 | viopath_sourceinst(viopath_hostLp), | ||
781 | viopath_targetinst(viopath_hostLp), | ||
782 | (u64)(unsigned long)op, VIOVERSION << 16, | ||
783 | ((u64)devi.devno << 48), 0, 0, 0); | ||
784 | if (hvrc != 0) { | ||
785 | printk(VIOTAPE_KERN_WARN "bad rc on signalLpEvent %d\n", | ||
786 | (int) hvrc); | ||
787 | ret = -EIO; | ||
788 | goto free_op; | ||
789 | } | ||
790 | |||
791 | wait_for_completion(&op->com); | ||
792 | |||
793 | if (op->rc) | ||
794 | printk(VIOTAPE_KERN_WARN "close failed\n"); | ||
795 | |||
796 | free_op: | ||
797 | free_op_struct(op); | ||
798 | return ret; | ||
799 | } | ||
800 | |||
801 | const struct file_operations viotap_fops = { | ||
802 | .owner = THIS_MODULE, | ||
803 | .read = viotap_read, | ||
804 | .write = viotap_write, | ||
805 | .unlocked_ioctl = viotap_unlocked_ioctl, | ||
806 | .open = viotap_open, | ||
807 | .release = viotap_release, | ||
808 | .llseek = noop_llseek, | ||
809 | }; | ||
810 | |||
811 | /* Handle interrupt events for tape */ | ||
812 | static void vioHandleTapeEvent(struct HvLpEvent *event) | ||
813 | { | ||
814 | int tapeminor; | ||
815 | struct op_struct *op; | ||
816 | struct viotapelpevent *tevent = (struct viotapelpevent *)event; | ||
817 | |||
818 | if (event == NULL) { | ||
819 | /* Notification that a partition went away! */ | ||
820 | if (!viopath_isactive(viopath_hostLp)) { | ||
821 | /* TODO! Clean up */ | ||
822 | } | ||
823 | return; | ||
824 | } | ||
825 | |||
826 | tapeminor = event->xSubtype & VIOMINOR_SUBTYPE_MASK; | ||
827 | op = (struct op_struct *)event->xCorrelationToken; | ||
828 | switch (tapeminor) { | ||
829 | case viotapeopen: | ||
830 | case viotapeclose: | ||
831 | op->rc = tevent->sub_type_result; | ||
832 | complete(&op->com); | ||
833 | break; | ||
834 | case viotaperead: | ||
835 | op->rc = tevent->sub_type_result; | ||
836 | op->count = tevent->len; | ||
837 | complete(&op->com); | ||
838 | break; | ||
839 | case viotapewrite: | ||
840 | if (op->non_blocking) { | ||
841 | dma_free_coherent(op->dev, op->count, | ||
842 | op->buffer, op->dmaaddr); | ||
843 | free_op_struct(op); | ||
844 | up(&reqSem); | ||
845 | } else { | ||
846 | op->rc = tevent->sub_type_result; | ||
847 | op->count = tevent->len; | ||
848 | complete(&op->com); | ||
849 | } | ||
850 | break; | ||
851 | case viotapeop: | ||
852 | case viotapegetpos: | ||
853 | case viotapesetpos: | ||
854 | case viotapegetstatus: | ||
855 | if (op) { | ||
856 | op->count = tevent->u.op.count; | ||
857 | op->rc = tevent->sub_type_result; | ||
858 | if (!op->non_blocking) | ||
859 | complete(&op->com); | ||
860 | } | ||
861 | break; | ||
862 | default: | ||
863 | printk(VIOTAPE_KERN_WARN "weird ack\n"); | ||
864 | } | ||
865 | } | ||
866 | |||
867 | static int viotape_probe(struct vio_dev *vdev, const struct vio_device_id *id) | ||
868 | { | ||
869 | int i = vdev->unit_address; | ||
870 | int j; | ||
871 | struct device_node *node = vdev->dev.of_node; | ||
872 | |||
873 | if (i >= VIOTAPE_MAX_TAPE) | ||
874 | return -ENODEV; | ||
875 | if (!node) | ||
876 | return -ENODEV; | ||
877 | |||
878 | if (i >= viotape_numdev) | ||
879 | viotape_numdev = i + 1; | ||
880 | |||
881 | tape_device[i] = &vdev->dev; | ||
882 | viotape_unitinfo[i].rsrcname = of_get_property(node, | ||
883 | "linux,vio_rsrcname", NULL); | ||
884 | viotape_unitinfo[i].type = of_get_property(node, "linux,vio_type", | ||
885 | NULL); | ||
886 | viotape_unitinfo[i].model = of_get_property(node, "linux,vio_model", | ||
887 | NULL); | ||
888 | |||
889 | state[i].cur_part = 0; | ||
890 | for (j = 0; j < MAX_PARTITIONS; ++j) | ||
891 | state[i].part_stat_rwi[j] = VIOT_IDLE; | ||
892 | device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i), NULL, | ||
893 | "iseries!vt%d", i); | ||
894 | device_create(tape_class, NULL, MKDEV(VIOTAPE_MAJOR, i | 0x80), NULL, | ||
895 | "iseries!nvt%d", i); | ||
896 | printk(VIOTAPE_KERN_INFO "tape iseries/vt%d is iSeries " | ||
897 | "resource %10.10s type %4.4s, model %3.3s\n", | ||
898 | i, viotape_unitinfo[i].rsrcname, | ||
899 | viotape_unitinfo[i].type, viotape_unitinfo[i].model); | ||
900 | return 0; | ||
901 | } | ||
902 | |||
903 | static int viotape_remove(struct vio_dev *vdev) | ||
904 | { | ||
905 | int i = vdev->unit_address; | ||
906 | |||
907 | device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80)); | ||
908 | device_destroy(tape_class, MKDEV(VIOTAPE_MAJOR, i)); | ||
909 | return 0; | ||
910 | } | ||
911 | |||
912 | /** | ||
913 | * viotape_device_table: Used by vio.c to match devices that we | ||
914 | * support. | ||
915 | */ | ||
916 | static struct vio_device_id viotape_device_table[] __devinitdata = { | ||
917 | { "byte", "IBM,iSeries-viotape" }, | ||
918 | { "", "" } | ||
919 | }; | ||
920 | MODULE_DEVICE_TABLE(vio, viotape_device_table); | ||
921 | |||
922 | static struct vio_driver viotape_driver = { | ||
923 | .id_table = viotape_device_table, | ||
924 | .probe = viotape_probe, | ||
925 | .remove = viotape_remove, | ||
926 | .driver = { | ||
927 | .name = "viotape", | ||
928 | .owner = THIS_MODULE, | ||
929 | } | ||
930 | }; | ||
931 | |||
932 | |||
933 | int __init viotap_init(void) | ||
934 | { | ||
935 | int ret; | ||
936 | |||
937 | if (!firmware_has_feature(FW_FEATURE_ISERIES)) | ||
938 | return -ENODEV; | ||
939 | |||
940 | op_struct_list = NULL; | ||
941 | if ((ret = add_op_structs(VIOTAPE_MAXREQ)) < 0) { | ||
942 | printk(VIOTAPE_KERN_WARN "couldn't allocate op structs\n"); | ||
943 | return ret; | ||
944 | } | ||
945 | spin_lock_init(&op_struct_list_lock); | ||
946 | |||
947 | sema_init(&reqSem, VIOTAPE_MAXREQ); | ||
948 | |||
949 | if (viopath_hostLp == HvLpIndexInvalid) { | ||
950 | vio_set_hostlp(); | ||
951 | if (viopath_hostLp == HvLpIndexInvalid) { | ||
952 | ret = -ENODEV; | ||
953 | goto clear_op; | ||
954 | } | ||
955 | } | ||
956 | |||
957 | ret = viopath_open(viopath_hostLp, viomajorsubtype_tape, | ||
958 | VIOTAPE_MAXREQ + 2); | ||
959 | if (ret) { | ||
960 | printk(VIOTAPE_KERN_WARN | ||
961 | "error on viopath_open to hostlp %d\n", ret); | ||
962 | ret = -EIO; | ||
963 | goto clear_op; | ||
964 | } | ||
965 | |||
966 | printk(VIOTAPE_KERN_INFO "vers " VIOTAPE_VERSION | ||
967 | ", hosting partition %d\n", viopath_hostLp); | ||
968 | |||
969 | vio_setHandler(viomajorsubtype_tape, vioHandleTapeEvent); | ||
970 | |||
971 | ret = register_chrdev(VIOTAPE_MAJOR, "viotape", &viotap_fops); | ||
972 | if (ret < 0) { | ||
973 | printk(VIOTAPE_KERN_WARN "Error registering viotape device\n"); | ||
974 | goto clear_handler; | ||
975 | } | ||
976 | |||
977 | tape_class = class_create(THIS_MODULE, "tape"); | ||
978 | if (IS_ERR(tape_class)) { | ||
979 | printk(VIOTAPE_KERN_WARN "Unable to allocate class\n"); | ||
980 | ret = PTR_ERR(tape_class); | ||
981 | goto unreg_chrdev; | ||
982 | } | ||
983 | |||
984 | ret = vio_register_driver(&viotape_driver); | ||
985 | if (ret) | ||
986 | goto unreg_class; | ||
987 | |||
988 | proc_create("iSeries/viotape", S_IFREG|S_IRUGO, NULL, | ||
989 | &proc_viotape_operations); | ||
990 | |||
991 | return 0; | ||
992 | |||
993 | unreg_class: | ||
994 | class_destroy(tape_class); | ||
995 | unreg_chrdev: | ||
996 | unregister_chrdev(VIOTAPE_MAJOR, "viotape"); | ||
997 | clear_handler: | ||
998 | vio_clearHandler(viomajorsubtype_tape); | ||
999 | viopath_close(viopath_hostLp, viomajorsubtype_tape, VIOTAPE_MAXREQ + 2); | ||
1000 | clear_op: | ||
1001 | clear_op_struct_pool(); | ||
1002 | return ret; | ||
1003 | } | ||
1004 | |||
1005 | /* Give a new state to the tape object */ | ||
1006 | static int chg_state(int index, unsigned char new_state, struct file *file) | ||
1007 | { | ||
1008 | unsigned char *cur_state = | ||
1009 | &state[index].part_stat_rwi[state[index].cur_part]; | ||
1010 | int rc = 0; | ||
1011 | |||
1012 | /* if the same state, don't bother */ | ||
1013 | if (*cur_state == new_state) | ||
1014 | return 0; | ||
1015 | |||
1016 | /* write an EOF if changing from writing to some other state */ | ||
1017 | if (*cur_state == VIOT_WRITING) { | ||
1018 | struct mtop write_eof = { MTWEOF, 1 }; | ||
1019 | |||
1020 | rc = viotap_ioctl(NULL, file, MTIOCTOP, | ||
1021 | (unsigned long)&write_eof); | ||
1022 | } | ||
1023 | *cur_state = new_state; | ||
1024 | return rc; | ||
1025 | } | ||
1026 | |||
1027 | /* Cleanup */ | ||
1028 | static void __exit viotap_exit(void) | ||
1029 | { | ||
1030 | remove_proc_entry("iSeries/viotape", NULL); | ||
1031 | vio_unregister_driver(&viotape_driver); | ||
1032 | class_destroy(tape_class); | ||
1033 | unregister_chrdev(VIOTAPE_MAJOR, "viotape"); | ||
1034 | viopath_close(viopath_hostLp, viomajorsubtype_tape, VIOTAPE_MAXREQ + 2); | ||
1035 | vio_clearHandler(viomajorsubtype_tape); | ||
1036 | clear_op_struct_pool(); | ||
1037 | } | ||
1038 | |||
1039 | MODULE_LICENSE("GPL"); | ||
1040 | module_init(viotap_init); | ||
1041 | module_exit(viotap_exit); | ||
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index d0c41188d4e5..0409cf35adda 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig | |||
@@ -190,6 +190,17 @@ config GPIO_VX855 | |||
190 | additional drivers must be enabled in order to use the | 190 | additional drivers must be enabled in order to use the |
191 | functionality of the device. | 191 | functionality of the device. |
192 | 192 | ||
193 | config GPIO_GE_FPGA | ||
194 | bool "GE FPGA based GPIO" | ||
195 | depends on GE_FPGA | ||
196 | help | ||
197 | Support for common GPIO functionality provided on some GE Single Board | ||
198 | Computers. | ||
199 | |||
200 | This driver provides basic support (configure as input or output, read | ||
201 | and write pin state) for GPIO implemented in a number of GE single | ||
202 | board computers. | ||
203 | |||
193 | comment "I2C GPIO expanders:" | 204 | comment "I2C GPIO expanders:" |
194 | 205 | ||
195 | config GPIO_MAX7300 | 206 | config GPIO_MAX7300 |
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index fa10df604c01..9a8fb54ae462 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile | |||
@@ -16,6 +16,7 @@ obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o | |||
16 | obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o | 16 | obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o |
17 | obj-$(CONFIG_ARCH_DAVINCI) += gpio-davinci.o | 17 | obj-$(CONFIG_ARCH_DAVINCI) += gpio-davinci.o |
18 | obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o | 18 | obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o |
19 | obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o | ||
19 | obj-$(CONFIG_GPIO_IT8761E) += gpio-it8761e.o | 20 | obj-$(CONFIG_GPIO_IT8761E) += gpio-it8761e.o |
20 | obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o | 21 | obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o |
21 | obj-$(CONFIG_ARCH_KS8695) += gpio-ks8695.o | 22 | obj-$(CONFIG_ARCH_KS8695) += gpio-ks8695.o |
diff --git a/arch/powerpc/platforms/86xx/gef_gpio.c b/drivers/gpio/gpio-ge.c index 2a703365e664..7b95a4a8318c 100644 --- a/arch/powerpc/platforms/86xx/gef_gpio.c +++ b/drivers/gpio/gpio-ge.c | |||
@@ -14,7 +14,7 @@ | |||
14 | * | 14 | * |
15 | * Configuration of output modes (totem-pole/open-drain) | 15 | * Configuration of output modes (totem-pole/open-drain) |
16 | * Interrupt configuration - interrupts are always generated the FPGA relies on | 16 | * Interrupt configuration - interrupts are always generated the FPGA relies on |
17 | * the I/O interrupt controllers mask to stop them propergating | 17 | * the I/O interrupt controllers mask to stop them propergating |
18 | */ | 18 | */ |
19 | 19 | ||
20 | #include <linux/kernel.h> | 20 | #include <linux/kernel.h> |
@@ -162,6 +162,34 @@ static int __init gef_gpio_init(void) | |||
162 | } | 162 | } |
163 | } | 163 | } |
164 | 164 | ||
165 | for_each_compatible_node(np, NULL, "ge,imp3a-gpio") { | ||
166 | |||
167 | pr_debug("%s: Initialising GE GPIO\n", np->full_name); | ||
168 | |||
169 | /* Allocate chip structure */ | ||
170 | gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL); | ||
171 | if (!gef_gpio_chip) { | ||
172 | pr_err("%s: Unable to allocate structure\n", | ||
173 | np->full_name); | ||
174 | continue; | ||
175 | } | ||
176 | |||
177 | /* Setup pointers to chip functions */ | ||
178 | gef_gpio_chip->gc.of_gpio_n_cells = 2; | ||
179 | gef_gpio_chip->gc.ngpio = 16; | ||
180 | gef_gpio_chip->gc.direction_input = gef_gpio_dir_in; | ||
181 | gef_gpio_chip->gc.direction_output = gef_gpio_dir_out; | ||
182 | gef_gpio_chip->gc.get = gef_gpio_get; | ||
183 | gef_gpio_chip->gc.set = gef_gpio_set; | ||
184 | |||
185 | /* This function adds a memory mapped GPIO chip */ | ||
186 | retval = of_mm_gpiochip_add(np, gef_gpio_chip); | ||
187 | if (retval) { | ||
188 | kfree(gef_gpio_chip); | ||
189 | pr_err("%s: Unable to add GPIO\n", np->full_name); | ||
190 | } | ||
191 | } | ||
192 | |||
165 | return 0; | 193 | return 0; |
166 | }; | 194 | }; |
167 | arch_initcall(gef_gpio_init); | 195 | arch_initcall(gef_gpio_init); |
diff --git a/drivers/misc/carma/carma-fpga.c b/drivers/misc/carma/carma-fpga.c index 366bc156e34d..8c279da07410 100644 --- a/drivers/misc/carma/carma-fpga.c +++ b/drivers/misc/carma/carma-fpga.c | |||
@@ -560,6 +560,9 @@ static void data_enable_interrupts(struct fpga_device *priv) | |||
560 | 560 | ||
561 | /* flush the writes */ | 561 | /* flush the writes */ |
562 | fpga_read_reg(priv, 0, MMAP_REG_STATUS); | 562 | fpga_read_reg(priv, 0, MMAP_REG_STATUS); |
563 | fpga_read_reg(priv, 1, MMAP_REG_STATUS); | ||
564 | fpga_read_reg(priv, 2, MMAP_REG_STATUS); | ||
565 | fpga_read_reg(priv, 3, MMAP_REG_STATUS); | ||
563 | 566 | ||
564 | /* switch back to the external interrupt source */ | 567 | /* switch back to the external interrupt source */ |
565 | iowrite32be(0x3F, priv->regs + SYS_IRQ_SOURCE_CTL); | 568 | iowrite32be(0x3F, priv->regs + SYS_IRQ_SOURCE_CTL); |
@@ -591,8 +594,12 @@ static void data_dma_cb(void *data) | |||
591 | list_move_tail(&priv->inflight->entry, &priv->used); | 594 | list_move_tail(&priv->inflight->entry, &priv->used); |
592 | priv->inflight = NULL; | 595 | priv->inflight = NULL; |
593 | 596 | ||
594 | /* clear the FPGA status and re-enable interrupts */ | 597 | /* |
595 | data_enable_interrupts(priv); | 598 | * If data dumping is still enabled, then clear the FPGA |
599 | * status registers and re-enable FPGA interrupts | ||
600 | */ | ||
601 | if (priv->enabled) | ||
602 | data_enable_interrupts(priv); | ||
596 | 603 | ||
597 | spin_unlock_irqrestore(&priv->lock, flags); | 604 | spin_unlock_irqrestore(&priv->lock, flags); |
598 | 605 | ||
@@ -708,6 +715,15 @@ static irqreturn_t data_irq(int irq, void *dev_id) | |||
708 | 715 | ||
709 | spin_lock(&priv->lock); | 716 | spin_lock(&priv->lock); |
710 | 717 | ||
718 | /* | ||
719 | * This is an error case that should never happen. | ||
720 | * | ||
721 | * If this driver has a bug and manages to re-enable interrupts while | ||
722 | * a DMA is in progress, then we will hit this statement and should | ||
723 | * start paying attention immediately. | ||
724 | */ | ||
725 | BUG_ON(priv->inflight != NULL); | ||
726 | |||
711 | /* hide the interrupt by switching the IRQ driver to GPIO */ | 727 | /* hide the interrupt by switching the IRQ driver to GPIO */ |
712 | data_disable_interrupts(priv); | 728 | data_disable_interrupts(priv); |
713 | 729 | ||
@@ -762,11 +778,15 @@ out: | |||
762 | */ | 778 | */ |
763 | static int data_device_enable(struct fpga_device *priv) | 779 | static int data_device_enable(struct fpga_device *priv) |
764 | { | 780 | { |
781 | bool enabled; | ||
765 | u32 val; | 782 | u32 val; |
766 | int ret; | 783 | int ret; |
767 | 784 | ||
768 | /* multiple enables are safe: they do nothing */ | 785 | /* multiple enables are safe: they do nothing */ |
769 | if (priv->enabled) | 786 | spin_lock_irq(&priv->lock); |
787 | enabled = priv->enabled; | ||
788 | spin_unlock_irq(&priv->lock); | ||
789 | if (enabled) | ||
770 | return 0; | 790 | return 0; |
771 | 791 | ||
772 | /* check that the FPGAs are programmed */ | 792 | /* check that the FPGAs are programmed */ |
@@ -797,6 +817,9 @@ static int data_device_enable(struct fpga_device *priv) | |||
797 | goto out_error; | 817 | goto out_error; |
798 | } | 818 | } |
799 | 819 | ||
820 | /* prevent the FPGAs from generating interrupts */ | ||
821 | data_disable_interrupts(priv); | ||
822 | |||
800 | /* hookup the irq handler */ | 823 | /* hookup the irq handler */ |
801 | ret = request_irq(priv->irq, data_irq, IRQF_SHARED, drv_name, priv); | 824 | ret = request_irq(priv->irq, data_irq, IRQF_SHARED, drv_name, priv); |
802 | if (ret) { | 825 | if (ret) { |
@@ -804,11 +827,13 @@ static int data_device_enable(struct fpga_device *priv) | |||
804 | goto out_error; | 827 | goto out_error; |
805 | } | 828 | } |
806 | 829 | ||
807 | /* switch to the external FPGA IRQ line */ | 830 | /* allow the DMA callback to re-enable FPGA interrupts */ |
808 | data_enable_interrupts(priv); | 831 | spin_lock_irq(&priv->lock); |
809 | |||
810 | /* success, we're enabled */ | ||
811 | priv->enabled = true; | 832 | priv->enabled = true; |
833 | spin_unlock_irq(&priv->lock); | ||
834 | |||
835 | /* allow the FPGAs to generate interrupts */ | ||
836 | data_enable_interrupts(priv); | ||
812 | return 0; | 837 | return 0; |
813 | 838 | ||
814 | out_error: | 839 | out_error: |
@@ -834,41 +859,40 @@ out_error: | |||
834 | */ | 859 | */ |
835 | static int data_device_disable(struct fpga_device *priv) | 860 | static int data_device_disable(struct fpga_device *priv) |
836 | { | 861 | { |
837 | int ret; | 862 | spin_lock_irq(&priv->lock); |
838 | 863 | ||
839 | /* allow multiple disable */ | 864 | /* allow multiple disable */ |
840 | if (!priv->enabled) | 865 | if (!priv->enabled) { |
866 | spin_unlock_irq(&priv->lock); | ||
841 | return 0; | 867 | return 0; |
868 | } | ||
869 | |||
870 | /* | ||
871 | * Mark the device disabled | ||
872 | * | ||
873 | * This stops DMA callbacks from re-enabling interrupts | ||
874 | */ | ||
875 | priv->enabled = false; | ||
842 | 876 | ||
843 | /* switch to the internal GPIO IRQ line */ | 877 | /* prevent the FPGAs from generating interrupts */ |
844 | data_disable_interrupts(priv); | 878 | data_disable_interrupts(priv); |
845 | 879 | ||
880 | /* wait until all ongoing DMA has finished */ | ||
881 | while (priv->inflight != NULL) { | ||
882 | spin_unlock_irq(&priv->lock); | ||
883 | wait_event(priv->wait, priv->inflight == NULL); | ||
884 | spin_lock_irq(&priv->lock); | ||
885 | } | ||
886 | |||
887 | spin_unlock_irq(&priv->lock); | ||
888 | |||
846 | /* unhook the irq handler */ | 889 | /* unhook the irq handler */ |
847 | free_irq(priv->irq, priv); | 890 | free_irq(priv->irq, priv); |
848 | 891 | ||
849 | /* | ||
850 | * wait for all outstanding DMA to complete | ||
851 | * | ||
852 | * Device interrupts are disabled, therefore another buffer cannot | ||
853 | * be marked inflight. | ||
854 | */ | ||
855 | ret = wait_event_interruptible(priv->wait, priv->inflight == NULL); | ||
856 | if (ret) | ||
857 | return ret; | ||
858 | |||
859 | /* free the correlation table */ | 892 | /* free the correlation table */ |
860 | sg_free_table(&priv->corl_table); | 893 | sg_free_table(&priv->corl_table); |
861 | priv->corl_nents = 0; | 894 | priv->corl_nents = 0; |
862 | 895 | ||
863 | /* | ||
864 | * We are taking the spinlock not to protect priv->enabled, but instead | ||
865 | * to make sure that there are no readers in the process of altering | ||
866 | * the free or used lists while we are setting this flag. | ||
867 | */ | ||
868 | spin_lock_irq(&priv->lock); | ||
869 | priv->enabled = false; | ||
870 | spin_unlock_irq(&priv->lock); | ||
871 | |||
872 | /* free all buffers: the free and used lists are not being changed */ | 896 | /* free all buffers: the free and used lists are not being changed */ |
873 | data_free_buffers(priv); | 897 | data_free_buffers(priv); |
874 | return 0; | 898 | return 0; |
@@ -896,15 +920,6 @@ static unsigned int list_num_entries(struct list_head *list) | |||
896 | static int data_debug_show(struct seq_file *f, void *offset) | 920 | static int data_debug_show(struct seq_file *f, void *offset) |
897 | { | 921 | { |
898 | struct fpga_device *priv = f->private; | 922 | struct fpga_device *priv = f->private; |
899 | int ret; | ||
900 | |||
901 | /* | ||
902 | * Lock the mutex first, so that we get an accurate value for enable | ||
903 | * Lock the spinlock next, to get accurate list counts | ||
904 | */ | ||
905 | ret = mutex_lock_interruptible(&priv->mutex); | ||
906 | if (ret) | ||
907 | return ret; | ||
908 | 923 | ||
909 | spin_lock_irq(&priv->lock); | 924 | spin_lock_irq(&priv->lock); |
910 | 925 | ||
@@ -917,7 +932,6 @@ static int data_debug_show(struct seq_file *f, void *offset) | |||
917 | seq_printf(f, "num_dropped: %d\n", priv->num_dropped); | 932 | seq_printf(f, "num_dropped: %d\n", priv->num_dropped); |
918 | 933 | ||
919 | spin_unlock_irq(&priv->lock); | 934 | spin_unlock_irq(&priv->lock); |
920 | mutex_unlock(&priv->mutex); | ||
921 | return 0; | 935 | return 0; |
922 | } | 936 | } |
923 | 937 | ||
@@ -970,7 +984,13 @@ static ssize_t data_en_show(struct device *dev, struct device_attribute *attr, | |||
970 | char *buf) | 984 | char *buf) |
971 | { | 985 | { |
972 | struct fpga_device *priv = dev_get_drvdata(dev); | 986 | struct fpga_device *priv = dev_get_drvdata(dev); |
973 | return snprintf(buf, PAGE_SIZE, "%u\n", priv->enabled); | 987 | int ret; |
988 | |||
989 | spin_lock_irq(&priv->lock); | ||
990 | ret = snprintf(buf, PAGE_SIZE, "%u\n", priv->enabled); | ||
991 | spin_unlock_irq(&priv->lock); | ||
992 | |||
993 | return ret; | ||
974 | } | 994 | } |
975 | 995 | ||
976 | static ssize_t data_en_set(struct device *dev, struct device_attribute *attr, | 996 | static ssize_t data_en_set(struct device *dev, struct device_attribute *attr, |
@@ -986,6 +1006,7 @@ static ssize_t data_en_set(struct device *dev, struct device_attribute *attr, | |||
986 | return -EINVAL; | 1006 | return -EINVAL; |
987 | } | 1007 | } |
988 | 1008 | ||
1009 | /* protect against concurrent enable/disable */ | ||
989 | ret = mutex_lock_interruptible(&priv->mutex); | 1010 | ret = mutex_lock_interruptible(&priv->mutex); |
990 | if (ret) | 1011 | if (ret) |
991 | return ret; | 1012 | return ret; |
@@ -1079,6 +1100,7 @@ static ssize_t data_read(struct file *filp, char __user *ubuf, size_t count, | |||
1079 | struct fpga_reader *reader = filp->private_data; | 1100 | struct fpga_reader *reader = filp->private_data; |
1080 | struct fpga_device *priv = reader->priv; | 1101 | struct fpga_device *priv = reader->priv; |
1081 | struct list_head *used = &priv->used; | 1102 | struct list_head *used = &priv->used; |
1103 | bool drop_buffer = false; | ||
1082 | struct data_buf *dbuf; | 1104 | struct data_buf *dbuf; |
1083 | size_t avail; | 1105 | size_t avail; |
1084 | void *data; | 1106 | void *data; |
@@ -1166,10 +1188,12 @@ have_buffer: | |||
1166 | * One of two things has happened, the device is disabled, or the | 1188 | * One of two things has happened, the device is disabled, or the |
1167 | * device has been reconfigured underneath us. In either case, we | 1189 | * device has been reconfigured underneath us. In either case, we |
1168 | * should just throw away the buffer. | 1190 | * should just throw away the buffer. |
1191 | * | ||
1192 | * Lockdep complains if this is done under the spinlock, so we | ||
1193 | * handle it during the unlock path. | ||
1169 | */ | 1194 | */ |
1170 | if (!priv->enabled || dbuf->size != priv->bufsize) { | 1195 | if (!priv->enabled || dbuf->size != priv->bufsize) { |
1171 | videobuf_dma_unmap(priv->dev, &dbuf->vb); | 1196 | drop_buffer = true; |
1172 | data_free_buffer(dbuf); | ||
1173 | goto out_unlock; | 1197 | goto out_unlock; |
1174 | } | 1198 | } |
1175 | 1199 | ||
@@ -1178,6 +1202,12 @@ have_buffer: | |||
1178 | 1202 | ||
1179 | out_unlock: | 1203 | out_unlock: |
1180 | spin_unlock_irq(&priv->lock); | 1204 | spin_unlock_irq(&priv->lock); |
1205 | |||
1206 | if (drop_buffer) { | ||
1207 | videobuf_dma_unmap(priv->dev, &dbuf->vb); | ||
1208 | data_free_buffer(dbuf); | ||
1209 | } | ||
1210 | |||
1181 | return count; | 1211 | return count; |
1182 | } | 1212 | } |
1183 | 1213 | ||
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 31b034b7eba3..3b1d6da874e0 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig | |||
@@ -462,6 +462,16 @@ config MTD_NAND_FSL_ELBC | |||
462 | Enabling this option will enable you to use this to control | 462 | Enabling this option will enable you to use this to control |
463 | external NAND devices. | 463 | external NAND devices. |
464 | 464 | ||
465 | config MTD_NAND_FSL_IFC | ||
466 | tristate "NAND support for Freescale IFC controller" | ||
467 | depends on MTD_NAND && FSL_SOC | ||
468 | select FSL_IFC | ||
469 | help | ||
470 | Various Freescale chips e.g P1010, include a NAND Flash machine | ||
471 | with built-in hardware ECC capabilities. | ||
472 | Enabling this option will enable you to use this to control | ||
473 | external NAND devices. | ||
474 | |||
465 | config MTD_NAND_FSL_UPM | 475 | config MTD_NAND_FSL_UPM |
466 | tristate "Support for NAND on Freescale UPM" | 476 | tristate "Support for NAND on Freescale UPM" |
467 | depends on PPC_83xx || PPC_85xx | 477 | depends on PPC_83xx || PPC_85xx |
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 618f4ba23699..19bc8cb1d187 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile | |||
@@ -37,6 +37,7 @@ obj-$(CONFIG_MTD_ALAUDA) += alauda.o | |||
37 | obj-$(CONFIG_MTD_NAND_PASEMI) += pasemi_nand.o | 37 | obj-$(CONFIG_MTD_NAND_PASEMI) += pasemi_nand.o |
38 | obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o | 38 | obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o |
39 | obj-$(CONFIG_MTD_NAND_FSL_ELBC) += fsl_elbc_nand.o | 39 | obj-$(CONFIG_MTD_NAND_FSL_ELBC) += fsl_elbc_nand.o |
40 | obj-$(CONFIG_MTD_NAND_FSL_IFC) += fsl_ifc_nand.o | ||
40 | obj-$(CONFIG_MTD_NAND_FSL_UPM) += fsl_upm.o | 41 | obj-$(CONFIG_MTD_NAND_FSL_UPM) += fsl_upm.o |
41 | obj-$(CONFIG_MTD_NAND_SH_FLCTL) += sh_flctl.o | 42 | obj-$(CONFIG_MTD_NAND_SH_FLCTL) += sh_flctl.o |
42 | obj-$(CONFIG_MTD_NAND_MXC) += mxc_nand.o | 43 | obj-$(CONFIG_MTD_NAND_MXC) += mxc_nand.o |
diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c new file mode 100644 index 000000000000..c30ac7b83d28 --- /dev/null +++ b/drivers/mtd/nand/fsl_ifc_nand.c | |||
@@ -0,0 +1,1072 @@ | |||
1 | /* | ||
2 | * Freescale Integrated Flash Controller NAND driver | ||
3 | * | ||
4 | * Copyright 2011-2012 Freescale Semiconductor, Inc | ||
5 | * | ||
6 | * Author: Dipen Dudhat <Dipen.Dudhat@freescale.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 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/types.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include <linux/mtd/mtd.h> | ||
29 | #include <linux/mtd/nand.h> | ||
30 | #include <linux/mtd/partitions.h> | ||
31 | #include <linux/mtd/nand_ecc.h> | ||
32 | #include <asm/fsl_ifc.h> | ||
33 | |||
34 | #define ERR_BYTE 0xFF /* Value returned for read | ||
35 | bytes when read failed */ | ||
36 | #define IFC_TIMEOUT_MSECS 500 /* Maximum number of mSecs to wait | ||
37 | for IFC NAND Machine */ | ||
38 | |||
39 | struct fsl_ifc_ctrl; | ||
40 | |||
41 | /* mtd information per set */ | ||
42 | struct fsl_ifc_mtd { | ||
43 | struct mtd_info mtd; | ||
44 | struct nand_chip chip; | ||
45 | struct fsl_ifc_ctrl *ctrl; | ||
46 | |||
47 | struct device *dev; | ||
48 | int bank; /* Chip select bank number */ | ||
49 | unsigned int bufnum_mask; /* bufnum = page & bufnum_mask */ | ||
50 | u8 __iomem *vbase; /* Chip select base virtual address */ | ||
51 | }; | ||
52 | |||
53 | /* overview of the fsl ifc controller */ | ||
54 | struct fsl_ifc_nand_ctrl { | ||
55 | struct nand_hw_control controller; | ||
56 | struct fsl_ifc_mtd *chips[FSL_IFC_BANK_COUNT]; | ||
57 | |||
58 | u8 __iomem *addr; /* Address of assigned IFC buffer */ | ||
59 | unsigned int page; /* Last page written to / read from */ | ||
60 | unsigned int read_bytes;/* Number of bytes read during command */ | ||
61 | unsigned int column; /* Saved column from SEQIN */ | ||
62 | unsigned int index; /* Pointer to next byte to 'read' */ | ||
63 | unsigned int oob; /* Non zero if operating on OOB data */ | ||
64 | unsigned int eccread; /* Non zero for a full-page ECC read */ | ||
65 | unsigned int counter; /* counter for the initializations */ | ||
66 | }; | ||
67 | |||
68 | static struct fsl_ifc_nand_ctrl *ifc_nand_ctrl; | ||
69 | |||
70 | /* 512-byte page with 4-bit ECC, 8-bit */ | ||
71 | static struct nand_ecclayout oob_512_8bit_ecc4 = { | ||
72 | .eccbytes = 8, | ||
73 | .eccpos = {8, 9, 10, 11, 12, 13, 14, 15}, | ||
74 | .oobfree = { {0, 5}, {6, 2} }, | ||
75 | }; | ||
76 | |||
77 | /* 512-byte page with 4-bit ECC, 16-bit */ | ||
78 | static struct nand_ecclayout oob_512_16bit_ecc4 = { | ||
79 | .eccbytes = 8, | ||
80 | .eccpos = {8, 9, 10, 11, 12, 13, 14, 15}, | ||
81 | .oobfree = { {2, 6}, }, | ||
82 | }; | ||
83 | |||
84 | /* 2048-byte page size with 4-bit ECC */ | ||
85 | static struct nand_ecclayout oob_2048_ecc4 = { | ||
86 | .eccbytes = 32, | ||
87 | .eccpos = { | ||
88 | 8, 9, 10, 11, 12, 13, 14, 15, | ||
89 | 16, 17, 18, 19, 20, 21, 22, 23, | ||
90 | 24, 25, 26, 27, 28, 29, 30, 31, | ||
91 | 32, 33, 34, 35, 36, 37, 38, 39, | ||
92 | }, | ||
93 | .oobfree = { {2, 6}, {40, 24} }, | ||
94 | }; | ||
95 | |||
96 | /* 4096-byte page size with 4-bit ECC */ | ||
97 | static struct nand_ecclayout oob_4096_ecc4 = { | ||
98 | .eccbytes = 64, | ||
99 | .eccpos = { | ||
100 | 8, 9, 10, 11, 12, 13, 14, 15, | ||
101 | 16, 17, 18, 19, 20, 21, 22, 23, | ||
102 | 24, 25, 26, 27, 28, 29, 30, 31, | ||
103 | 32, 33, 34, 35, 36, 37, 38, 39, | ||
104 | 40, 41, 42, 43, 44, 45, 46, 47, | ||
105 | 48, 49, 50, 51, 52, 53, 54, 55, | ||
106 | 56, 57, 58, 59, 60, 61, 62, 63, | ||
107 | 64, 65, 66, 67, 68, 69, 70, 71, | ||
108 | }, | ||
109 | .oobfree = { {2, 6}, {72, 56} }, | ||
110 | }; | ||
111 | |||
112 | /* 4096-byte page size with 8-bit ECC -- requires 218-byte OOB */ | ||
113 | static struct nand_ecclayout oob_4096_ecc8 = { | ||
114 | .eccbytes = 128, | ||
115 | .eccpos = { | ||
116 | 8, 9, 10, 11, 12, 13, 14, 15, | ||
117 | 16, 17, 18, 19, 20, 21, 22, 23, | ||
118 | 24, 25, 26, 27, 28, 29, 30, 31, | ||
119 | 32, 33, 34, 35, 36, 37, 38, 39, | ||
120 | 40, 41, 42, 43, 44, 45, 46, 47, | ||
121 | 48, 49, 50, 51, 52, 53, 54, 55, | ||
122 | 56, 57, 58, 59, 60, 61, 62, 63, | ||
123 | 64, 65, 66, 67, 68, 69, 70, 71, | ||
124 | 72, 73, 74, 75, 76, 77, 78, 79, | ||
125 | 80, 81, 82, 83, 84, 85, 86, 87, | ||
126 | 88, 89, 90, 91, 92, 93, 94, 95, | ||
127 | 96, 97, 98, 99, 100, 101, 102, 103, | ||
128 | 104, 105, 106, 107, 108, 109, 110, 111, | ||
129 | 112, 113, 114, 115, 116, 117, 118, 119, | ||
130 | 120, 121, 122, 123, 124, 125, 126, 127, | ||
131 | 128, 129, 130, 131, 132, 133, 134, 135, | ||
132 | }, | ||
133 | .oobfree = { {2, 6}, {136, 82} }, | ||
134 | }; | ||
135 | |||
136 | |||
137 | /* | ||
138 | * Generic flash bbt descriptors | ||
139 | */ | ||
140 | static u8 bbt_pattern[] = {'B', 'b', 't', '0' }; | ||
141 | static u8 mirror_pattern[] = {'1', 't', 'b', 'B' }; | ||
142 | |||
143 | static struct nand_bbt_descr bbt_main_descr = { | ||
144 | .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | | ||
145 | NAND_BBT_2BIT | NAND_BBT_VERSION, | ||
146 | .offs = 2, /* 0 on 8-bit small page */ | ||
147 | .len = 4, | ||
148 | .veroffs = 6, | ||
149 | .maxblocks = 4, | ||
150 | .pattern = bbt_pattern, | ||
151 | }; | ||
152 | |||
153 | static struct nand_bbt_descr bbt_mirror_descr = { | ||
154 | .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE | | ||
155 | NAND_BBT_2BIT | NAND_BBT_VERSION, | ||
156 | .offs = 2, /* 0 on 8-bit small page */ | ||
157 | .len = 4, | ||
158 | .veroffs = 6, | ||
159 | .maxblocks = 4, | ||
160 | .pattern = mirror_pattern, | ||
161 | }; | ||
162 | |||
163 | /* | ||
164 | * Set up the IFC hardware block and page address fields, and the ifc nand | ||
165 | * structure addr field to point to the correct IFC buffer in memory | ||
166 | */ | ||
167 | static void set_addr(struct mtd_info *mtd, int column, int page_addr, int oob) | ||
168 | { | ||
169 | struct nand_chip *chip = mtd->priv; | ||
170 | struct fsl_ifc_mtd *priv = chip->priv; | ||
171 | struct fsl_ifc_ctrl *ctrl = priv->ctrl; | ||
172 | struct fsl_ifc_regs __iomem *ifc = ctrl->regs; | ||
173 | int buf_num; | ||
174 | |||
175 | ifc_nand_ctrl->page = page_addr; | ||
176 | /* Program ROW0/COL0 */ | ||
177 | out_be32(&ifc->ifc_nand.row0, page_addr); | ||
178 | out_be32(&ifc->ifc_nand.col0, (oob ? IFC_NAND_COL_MS : 0) | column); | ||
179 | |||
180 | buf_num = page_addr & priv->bufnum_mask; | ||
181 | |||
182 | ifc_nand_ctrl->addr = priv->vbase + buf_num * (mtd->writesize * 2); | ||
183 | ifc_nand_ctrl->index = column; | ||
184 | |||
185 | /* for OOB data point to the second half of the buffer */ | ||
186 | if (oob) | ||
187 | ifc_nand_ctrl->index += mtd->writesize; | ||
188 | } | ||
189 | |||
190 | static int is_blank(struct mtd_info *mtd, unsigned int bufnum) | ||
191 | { | ||
192 | struct nand_chip *chip = mtd->priv; | ||
193 | struct fsl_ifc_mtd *priv = chip->priv; | ||
194 | u8 __iomem *addr = priv->vbase + bufnum * (mtd->writesize * 2); | ||
195 | u32 __iomem *mainarea = (u32 *)addr; | ||
196 | u8 __iomem *oob = addr + mtd->writesize; | ||
197 | int i; | ||
198 | |||
199 | for (i = 0; i < mtd->writesize / 4; i++) { | ||
200 | if (__raw_readl(&mainarea[i]) != 0xffffffff) | ||
201 | return 0; | ||
202 | } | ||
203 | |||
204 | for (i = 0; i < chip->ecc.layout->eccbytes; i++) { | ||
205 | int pos = chip->ecc.layout->eccpos[i]; | ||
206 | |||
207 | if (__raw_readb(&oob[pos]) != 0xff) | ||
208 | return 0; | ||
209 | } | ||
210 | |||
211 | return 1; | ||
212 | } | ||
213 | |||
214 | /* returns nonzero if entire page is blank */ | ||
215 | static int check_read_ecc(struct mtd_info *mtd, struct fsl_ifc_ctrl *ctrl, | ||
216 | u32 *eccstat, unsigned int bufnum) | ||
217 | { | ||
218 | u32 reg = eccstat[bufnum / 4]; | ||
219 | int errors; | ||
220 | |||
221 | errors = (reg >> ((3 - bufnum % 4) * 8)) & 15; | ||
222 | |||
223 | return errors; | ||
224 | } | ||
225 | |||
226 | /* | ||
227 | * execute IFC NAND command and wait for it to complete | ||
228 | */ | ||
229 | static void fsl_ifc_run_command(struct mtd_info *mtd) | ||
230 | { | ||
231 | struct nand_chip *chip = mtd->priv; | ||
232 | struct fsl_ifc_mtd *priv = chip->priv; | ||
233 | struct fsl_ifc_ctrl *ctrl = priv->ctrl; | ||
234 | struct fsl_ifc_nand_ctrl *nctrl = ifc_nand_ctrl; | ||
235 | struct fsl_ifc_regs __iomem *ifc = ctrl->regs; | ||
236 | u32 eccstat[4]; | ||
237 | int i; | ||
238 | |||
239 | /* set the chip select for NAND Transaction */ | ||
240 | out_be32(&ifc->ifc_nand.nand_csel, priv->bank << IFC_NAND_CSEL_SHIFT); | ||
241 | |||
242 | dev_vdbg(priv->dev, | ||
243 | "%s: fir0=%08x fcr0=%08x\n", | ||
244 | __func__, | ||
245 | in_be32(&ifc->ifc_nand.nand_fir0), | ||
246 | in_be32(&ifc->ifc_nand.nand_fcr0)); | ||
247 | |||
248 | ctrl->nand_stat = 0; | ||
249 | |||
250 | /* start read/write seq */ | ||
251 | out_be32(&ifc->ifc_nand.nandseq_strt, IFC_NAND_SEQ_STRT_FIR_STRT); | ||
252 | |||
253 | /* wait for command complete flag or timeout */ | ||
254 | wait_event_timeout(ctrl->nand_wait, ctrl->nand_stat, | ||
255 | IFC_TIMEOUT_MSECS * HZ/1000); | ||
256 | |||
257 | /* ctrl->nand_stat will be updated from IRQ context */ | ||
258 | if (!ctrl->nand_stat) | ||
259 | dev_err(priv->dev, "Controller is not responding\n"); | ||
260 | if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_FTOER) | ||
261 | dev_err(priv->dev, "NAND Flash Timeout Error\n"); | ||
262 | if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_WPER) | ||
263 | dev_err(priv->dev, "NAND Flash Write Protect Error\n"); | ||
264 | |||
265 | if (nctrl->eccread) { | ||
266 | int errors; | ||
267 | int bufnum = nctrl->page & priv->bufnum_mask; | ||
268 | int sector = bufnum * chip->ecc.steps; | ||
269 | int sector_end = sector + chip->ecc.steps - 1; | ||
270 | |||
271 | for (i = sector / 4; i <= sector_end / 4; i++) | ||
272 | eccstat[i] = in_be32(&ifc->ifc_nand.nand_eccstat[i]); | ||
273 | |||
274 | for (i = sector; i <= sector_end; i++) { | ||
275 | errors = check_read_ecc(mtd, ctrl, eccstat, i); | ||
276 | |||
277 | if (errors == 15) { | ||
278 | /* | ||
279 | * Uncorrectable error. | ||
280 | * OK only if the whole page is blank. | ||
281 | * | ||
282 | * We disable ECCER reporting due to... | ||
283 | * erratum IFC-A002770 -- so report it now if we | ||
284 | * see an uncorrectable error in ECCSTAT. | ||
285 | */ | ||
286 | if (!is_blank(mtd, bufnum)) | ||
287 | ctrl->nand_stat |= | ||
288 | IFC_NAND_EVTER_STAT_ECCER; | ||
289 | break; | ||
290 | } | ||
291 | |||
292 | mtd->ecc_stats.corrected += errors; | ||
293 | } | ||
294 | |||
295 | nctrl->eccread = 0; | ||
296 | } | ||
297 | } | ||
298 | |||
299 | static void fsl_ifc_do_read(struct nand_chip *chip, | ||
300 | int oob, | ||
301 | struct mtd_info *mtd) | ||
302 | { | ||
303 | struct fsl_ifc_mtd *priv = chip->priv; | ||
304 | struct fsl_ifc_ctrl *ctrl = priv->ctrl; | ||
305 | struct fsl_ifc_regs __iomem *ifc = ctrl->regs; | ||
306 | |||
307 | /* Program FIR/IFC_NAND_FCR0 for Small/Large page */ | ||
308 | if (mtd->writesize > 512) { | ||
309 | out_be32(&ifc->ifc_nand.nand_fir0, | ||
310 | (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | | ||
311 | (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) | | ||
312 | (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) | | ||
313 | (IFC_FIR_OP_CMD1 << IFC_NAND_FIR0_OP3_SHIFT) | | ||
314 | (IFC_FIR_OP_RBCD << IFC_NAND_FIR0_OP4_SHIFT)); | ||
315 | out_be32(&ifc->ifc_nand.nand_fir1, 0x0); | ||
316 | |||
317 | out_be32(&ifc->ifc_nand.nand_fcr0, | ||
318 | (NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT) | | ||
319 | (NAND_CMD_READSTART << IFC_NAND_FCR0_CMD1_SHIFT)); | ||
320 | } else { | ||
321 | out_be32(&ifc->ifc_nand.nand_fir0, | ||
322 | (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | | ||
323 | (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) | | ||
324 | (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) | | ||
325 | (IFC_FIR_OP_RBCD << IFC_NAND_FIR0_OP3_SHIFT)); | ||
326 | out_be32(&ifc->ifc_nand.nand_fir1, 0x0); | ||
327 | |||
328 | if (oob) | ||
329 | out_be32(&ifc->ifc_nand.nand_fcr0, | ||
330 | NAND_CMD_READOOB << IFC_NAND_FCR0_CMD0_SHIFT); | ||
331 | else | ||
332 | out_be32(&ifc->ifc_nand.nand_fcr0, | ||
333 | NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT); | ||
334 | } | ||
335 | } | ||
336 | |||
337 | /* cmdfunc send commands to the IFC NAND Machine */ | ||
338 | static void fsl_ifc_cmdfunc(struct mtd_info *mtd, unsigned int command, | ||
339 | int column, int page_addr) { | ||
340 | struct nand_chip *chip = mtd->priv; | ||
341 | struct fsl_ifc_mtd *priv = chip->priv; | ||
342 | struct fsl_ifc_ctrl *ctrl = priv->ctrl; | ||
343 | struct fsl_ifc_regs __iomem *ifc = ctrl->regs; | ||
344 | |||
345 | /* clear the read buffer */ | ||
346 | ifc_nand_ctrl->read_bytes = 0; | ||
347 | if (command != NAND_CMD_PAGEPROG) | ||
348 | ifc_nand_ctrl->index = 0; | ||
349 | |||
350 | switch (command) { | ||
351 | /* READ0 read the entire buffer to use hardware ECC. */ | ||
352 | case NAND_CMD_READ0: | ||
353 | out_be32(&ifc->ifc_nand.nand_fbcr, 0); | ||
354 | set_addr(mtd, 0, page_addr, 0); | ||
355 | |||
356 | ifc_nand_ctrl->read_bytes = mtd->writesize + mtd->oobsize; | ||
357 | ifc_nand_ctrl->index += column; | ||
358 | |||
359 | if (chip->ecc.mode == NAND_ECC_HW) | ||
360 | ifc_nand_ctrl->eccread = 1; | ||
361 | |||
362 | fsl_ifc_do_read(chip, 0, mtd); | ||
363 | fsl_ifc_run_command(mtd); | ||
364 | return; | ||
365 | |||
366 | /* READOOB reads only the OOB because no ECC is performed. */ | ||
367 | case NAND_CMD_READOOB: | ||
368 | out_be32(&ifc->ifc_nand.nand_fbcr, mtd->oobsize - column); | ||
369 | set_addr(mtd, column, page_addr, 1); | ||
370 | |||
371 | ifc_nand_ctrl->read_bytes = mtd->writesize + mtd->oobsize; | ||
372 | |||
373 | fsl_ifc_do_read(chip, 1, mtd); | ||
374 | fsl_ifc_run_command(mtd); | ||
375 | |||
376 | return; | ||
377 | |||
378 | /* READID must read all 8 possible bytes */ | ||
379 | case NAND_CMD_READID: | ||
380 | out_be32(&ifc->ifc_nand.nand_fir0, | ||
381 | (IFC_FIR_OP_CMD0 << IFC_NAND_FIR0_OP0_SHIFT) | | ||
382 | (IFC_FIR_OP_UA << IFC_NAND_FIR0_OP1_SHIFT) | | ||
383 | (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP2_SHIFT)); | ||
384 | out_be32(&ifc->ifc_nand.nand_fcr0, | ||
385 | NAND_CMD_READID << IFC_NAND_FCR0_CMD0_SHIFT); | ||
386 | /* 8 bytes for manuf, device and exts */ | ||
387 | out_be32(&ifc->ifc_nand.nand_fbcr, 8); | ||
388 | ifc_nand_ctrl->read_bytes = 8; | ||
389 | |||
390 | set_addr(mtd, 0, 0, 0); | ||
391 | fsl_ifc_run_command(mtd); | ||
392 | return; | ||
393 | |||
394 | /* ERASE1 stores the block and page address */ | ||
395 | case NAND_CMD_ERASE1: | ||
396 | set_addr(mtd, 0, page_addr, 0); | ||
397 | return; | ||
398 | |||
399 | /* ERASE2 uses the block and page address from ERASE1 */ | ||
400 | case NAND_CMD_ERASE2: | ||
401 | out_be32(&ifc->ifc_nand.nand_fir0, | ||
402 | (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | | ||
403 | (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP1_SHIFT) | | ||
404 | (IFC_FIR_OP_CMD1 << IFC_NAND_FIR0_OP2_SHIFT)); | ||
405 | |||
406 | out_be32(&ifc->ifc_nand.nand_fcr0, | ||
407 | (NAND_CMD_ERASE1 << IFC_NAND_FCR0_CMD0_SHIFT) | | ||
408 | (NAND_CMD_ERASE2 << IFC_NAND_FCR0_CMD1_SHIFT)); | ||
409 | |||
410 | out_be32(&ifc->ifc_nand.nand_fbcr, 0); | ||
411 | ifc_nand_ctrl->read_bytes = 0; | ||
412 | fsl_ifc_run_command(mtd); | ||
413 | return; | ||
414 | |||
415 | /* SEQIN sets up the addr buffer and all registers except the length */ | ||
416 | case NAND_CMD_SEQIN: { | ||
417 | u32 nand_fcr0; | ||
418 | ifc_nand_ctrl->column = column; | ||
419 | ifc_nand_ctrl->oob = 0; | ||
420 | |||
421 | if (mtd->writesize > 512) { | ||
422 | nand_fcr0 = | ||
423 | (NAND_CMD_SEQIN << IFC_NAND_FCR0_CMD0_SHIFT) | | ||
424 | (NAND_CMD_PAGEPROG << IFC_NAND_FCR0_CMD1_SHIFT); | ||
425 | |||
426 | out_be32(&ifc->ifc_nand.nand_fir0, | ||
427 | (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | | ||
428 | (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP1_SHIFT) | | ||
429 | (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP2_SHIFT) | | ||
430 | (IFC_FIR_OP_WBCD << IFC_NAND_FIR0_OP3_SHIFT) | | ||
431 | (IFC_FIR_OP_CW1 << IFC_NAND_FIR0_OP4_SHIFT)); | ||
432 | } else { | ||
433 | nand_fcr0 = ((NAND_CMD_PAGEPROG << | ||
434 | IFC_NAND_FCR0_CMD1_SHIFT) | | ||
435 | (NAND_CMD_SEQIN << | ||
436 | IFC_NAND_FCR0_CMD2_SHIFT)); | ||
437 | |||
438 | out_be32(&ifc->ifc_nand.nand_fir0, | ||
439 | (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | | ||
440 | (IFC_FIR_OP_CMD2 << IFC_NAND_FIR0_OP1_SHIFT) | | ||
441 | (IFC_FIR_OP_CA0 << IFC_NAND_FIR0_OP2_SHIFT) | | ||
442 | (IFC_FIR_OP_RA0 << IFC_NAND_FIR0_OP3_SHIFT) | | ||
443 | (IFC_FIR_OP_WBCD << IFC_NAND_FIR0_OP4_SHIFT)); | ||
444 | out_be32(&ifc->ifc_nand.nand_fir1, | ||
445 | (IFC_FIR_OP_CW1 << IFC_NAND_FIR1_OP5_SHIFT)); | ||
446 | |||
447 | if (column >= mtd->writesize) | ||
448 | nand_fcr0 |= | ||
449 | NAND_CMD_READOOB << IFC_NAND_FCR0_CMD0_SHIFT; | ||
450 | else | ||
451 | nand_fcr0 |= | ||
452 | NAND_CMD_READ0 << IFC_NAND_FCR0_CMD0_SHIFT; | ||
453 | } | ||
454 | |||
455 | if (column >= mtd->writesize) { | ||
456 | /* OOB area --> READOOB */ | ||
457 | column -= mtd->writesize; | ||
458 | ifc_nand_ctrl->oob = 1; | ||
459 | } | ||
460 | out_be32(&ifc->ifc_nand.nand_fcr0, nand_fcr0); | ||
461 | set_addr(mtd, column, page_addr, ifc_nand_ctrl->oob); | ||
462 | return; | ||
463 | } | ||
464 | |||
465 | /* PAGEPROG reuses all of the setup from SEQIN and adds the length */ | ||
466 | case NAND_CMD_PAGEPROG: { | ||
467 | if (ifc_nand_ctrl->oob) { | ||
468 | out_be32(&ifc->ifc_nand.nand_fbcr, | ||
469 | ifc_nand_ctrl->index - ifc_nand_ctrl->column); | ||
470 | } else { | ||
471 | out_be32(&ifc->ifc_nand.nand_fbcr, 0); | ||
472 | } | ||
473 | |||
474 | fsl_ifc_run_command(mtd); | ||
475 | return; | ||
476 | } | ||
477 | |||
478 | case NAND_CMD_STATUS: | ||
479 | out_be32(&ifc->ifc_nand.nand_fir0, | ||
480 | (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | | ||
481 | (IFC_FIR_OP_RB << IFC_NAND_FIR0_OP1_SHIFT)); | ||
482 | out_be32(&ifc->ifc_nand.nand_fcr0, | ||
483 | NAND_CMD_STATUS << IFC_NAND_FCR0_CMD0_SHIFT); | ||
484 | out_be32(&ifc->ifc_nand.nand_fbcr, 1); | ||
485 | set_addr(mtd, 0, 0, 0); | ||
486 | ifc_nand_ctrl->read_bytes = 1; | ||
487 | |||
488 | fsl_ifc_run_command(mtd); | ||
489 | |||
490 | /* | ||
491 | * The chip always seems to report that it is | ||
492 | * write-protected, even when it is not. | ||
493 | */ | ||
494 | setbits8(ifc_nand_ctrl->addr, NAND_STATUS_WP); | ||
495 | return; | ||
496 | |||
497 | case NAND_CMD_RESET: | ||
498 | out_be32(&ifc->ifc_nand.nand_fir0, | ||
499 | IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT); | ||
500 | out_be32(&ifc->ifc_nand.nand_fcr0, | ||
501 | NAND_CMD_RESET << IFC_NAND_FCR0_CMD0_SHIFT); | ||
502 | fsl_ifc_run_command(mtd); | ||
503 | return; | ||
504 | |||
505 | default: | ||
506 | dev_err(priv->dev, "%s: error, unsupported command 0x%x.\n", | ||
507 | __func__, command); | ||
508 | } | ||
509 | } | ||
510 | |||
511 | static void fsl_ifc_select_chip(struct mtd_info *mtd, int chip) | ||
512 | { | ||
513 | /* The hardware does not seem to support multiple | ||
514 | * chips per bank. | ||
515 | */ | ||
516 | } | ||
517 | |||
518 | /* | ||
519 | * Write buf to the IFC NAND Controller Data Buffer | ||
520 | */ | ||
521 | static void fsl_ifc_write_buf(struct mtd_info *mtd, const u8 *buf, int len) | ||
522 | { | ||
523 | struct nand_chip *chip = mtd->priv; | ||
524 | struct fsl_ifc_mtd *priv = chip->priv; | ||
525 | unsigned int bufsize = mtd->writesize + mtd->oobsize; | ||
526 | |||
527 | if (len <= 0) { | ||
528 | dev_err(priv->dev, "%s: len %d bytes", __func__, len); | ||
529 | return; | ||
530 | } | ||
531 | |||
532 | if ((unsigned int)len > bufsize - ifc_nand_ctrl->index) { | ||
533 | dev_err(priv->dev, | ||
534 | "%s: beyond end of buffer (%d requested, %u available)\n", | ||
535 | __func__, len, bufsize - ifc_nand_ctrl->index); | ||
536 | len = bufsize - ifc_nand_ctrl->index; | ||
537 | } | ||
538 | |||
539 | memcpy_toio(&ifc_nand_ctrl->addr[ifc_nand_ctrl->index], buf, len); | ||
540 | ifc_nand_ctrl->index += len; | ||
541 | } | ||
542 | |||
543 | /* | ||
544 | * Read a byte from either the IFC hardware buffer | ||
545 | * read function for 8-bit buswidth | ||
546 | */ | ||
547 | static uint8_t fsl_ifc_read_byte(struct mtd_info *mtd) | ||
548 | { | ||
549 | struct nand_chip *chip = mtd->priv; | ||
550 | struct fsl_ifc_mtd *priv = chip->priv; | ||
551 | |||
552 | /* | ||
553 | * If there are still bytes in the IFC buffer, then use the | ||
554 | * next byte. | ||
555 | */ | ||
556 | if (ifc_nand_ctrl->index < ifc_nand_ctrl->read_bytes) | ||
557 | return in_8(&ifc_nand_ctrl->addr[ifc_nand_ctrl->index++]); | ||
558 | |||
559 | dev_err(priv->dev, "%s: beyond end of buffer\n", __func__); | ||
560 | return ERR_BYTE; | ||
561 | } | ||
562 | |||
563 | /* | ||
564 | * Read two bytes from the IFC hardware buffer | ||
565 | * read function for 16-bit buswith | ||
566 | */ | ||
567 | static uint8_t fsl_ifc_read_byte16(struct mtd_info *mtd) | ||
568 | { | ||
569 | struct nand_chip *chip = mtd->priv; | ||
570 | struct fsl_ifc_mtd *priv = chip->priv; | ||
571 | uint16_t data; | ||
572 | |||
573 | /* | ||
574 | * If there are still bytes in the IFC buffer, then use the | ||
575 | * next byte. | ||
576 | */ | ||
577 | if (ifc_nand_ctrl->index < ifc_nand_ctrl->read_bytes) { | ||
578 | data = in_be16((uint16_t *)&ifc_nand_ctrl-> | ||
579 | addr[ifc_nand_ctrl->index]); | ||
580 | ifc_nand_ctrl->index += 2; | ||
581 | return (uint8_t) data; | ||
582 | } | ||
583 | |||
584 | dev_err(priv->dev, "%s: beyond end of buffer\n", __func__); | ||
585 | return ERR_BYTE; | ||
586 | } | ||
587 | |||
588 | /* | ||
589 | * Read from the IFC Controller Data Buffer | ||
590 | */ | ||
591 | static void fsl_ifc_read_buf(struct mtd_info *mtd, u8 *buf, int len) | ||
592 | { | ||
593 | struct nand_chip *chip = mtd->priv; | ||
594 | struct fsl_ifc_mtd *priv = chip->priv; | ||
595 | int avail; | ||
596 | |||
597 | if (len < 0) { | ||
598 | dev_err(priv->dev, "%s: len %d bytes", __func__, len); | ||
599 | return; | ||
600 | } | ||
601 | |||
602 | avail = min((unsigned int)len, | ||
603 | ifc_nand_ctrl->read_bytes - ifc_nand_ctrl->index); | ||
604 | memcpy_fromio(buf, &ifc_nand_ctrl->addr[ifc_nand_ctrl->index], avail); | ||
605 | ifc_nand_ctrl->index += avail; | ||
606 | |||
607 | if (len > avail) | ||
608 | dev_err(priv->dev, | ||
609 | "%s: beyond end of buffer (%d requested, %d available)\n", | ||
610 | __func__, len, avail); | ||
611 | } | ||
612 | |||
613 | /* | ||
614 | * Verify buffer against the IFC Controller Data Buffer | ||
615 | */ | ||
616 | static int fsl_ifc_verify_buf(struct mtd_info *mtd, | ||
617 | const u_char *buf, int len) | ||
618 | { | ||
619 | struct nand_chip *chip = mtd->priv; | ||
620 | struct fsl_ifc_mtd *priv = chip->priv; | ||
621 | struct fsl_ifc_ctrl *ctrl = priv->ctrl; | ||
622 | struct fsl_ifc_nand_ctrl *nctrl = ifc_nand_ctrl; | ||
623 | int i; | ||
624 | |||
625 | if (len < 0) { | ||
626 | dev_err(priv->dev, "%s: write_buf of %d bytes", __func__, len); | ||
627 | return -EINVAL; | ||
628 | } | ||
629 | |||
630 | if ((unsigned int)len > nctrl->read_bytes - nctrl->index) { | ||
631 | dev_err(priv->dev, | ||
632 | "%s: beyond end of buffer (%d requested, %u available)\n", | ||
633 | __func__, len, nctrl->read_bytes - nctrl->index); | ||
634 | |||
635 | nctrl->index = nctrl->read_bytes; | ||
636 | return -EINVAL; | ||
637 | } | ||
638 | |||
639 | for (i = 0; i < len; i++) | ||
640 | if (in_8(&nctrl->addr[nctrl->index + i]) != buf[i]) | ||
641 | break; | ||
642 | |||
643 | nctrl->index += len; | ||
644 | |||
645 | if (i != len) | ||
646 | return -EIO; | ||
647 | if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC) | ||
648 | return -EIO; | ||
649 | |||
650 | return 0; | ||
651 | } | ||
652 | |||
653 | /* | ||
654 | * This function is called after Program and Erase Operations to | ||
655 | * check for success or failure. | ||
656 | */ | ||
657 | static int fsl_ifc_wait(struct mtd_info *mtd, struct nand_chip *chip) | ||
658 | { | ||
659 | struct fsl_ifc_mtd *priv = chip->priv; | ||
660 | struct fsl_ifc_ctrl *ctrl = priv->ctrl; | ||
661 | struct fsl_ifc_regs __iomem *ifc = ctrl->regs; | ||
662 | u32 nand_fsr; | ||
663 | |||
664 | /* Use READ_STATUS command, but wait for the device to be ready */ | ||
665 | out_be32(&ifc->ifc_nand.nand_fir0, | ||
666 | (IFC_FIR_OP_CW0 << IFC_NAND_FIR0_OP0_SHIFT) | | ||
667 | (IFC_FIR_OP_RDSTAT << IFC_NAND_FIR0_OP1_SHIFT)); | ||
668 | out_be32(&ifc->ifc_nand.nand_fcr0, NAND_CMD_STATUS << | ||
669 | IFC_NAND_FCR0_CMD0_SHIFT); | ||
670 | out_be32(&ifc->ifc_nand.nand_fbcr, 1); | ||
671 | set_addr(mtd, 0, 0, 0); | ||
672 | ifc_nand_ctrl->read_bytes = 1; | ||
673 | |||
674 | fsl_ifc_run_command(mtd); | ||
675 | |||
676 | nand_fsr = in_be32(&ifc->ifc_nand.nand_fsr); | ||
677 | |||
678 | /* | ||
679 | * The chip always seems to report that it is | ||
680 | * write-protected, even when it is not. | ||
681 | */ | ||
682 | return nand_fsr | NAND_STATUS_WP; | ||
683 | } | ||
684 | |||
685 | static int fsl_ifc_read_page(struct mtd_info *mtd, | ||
686 | struct nand_chip *chip, | ||
687 | uint8_t *buf, int page) | ||
688 | { | ||
689 | struct fsl_ifc_mtd *priv = chip->priv; | ||
690 | struct fsl_ifc_ctrl *ctrl = priv->ctrl; | ||
691 | |||
692 | fsl_ifc_read_buf(mtd, buf, mtd->writesize); | ||
693 | fsl_ifc_read_buf(mtd, chip->oob_poi, mtd->oobsize); | ||
694 | |||
695 | if (ctrl->nand_stat & IFC_NAND_EVTER_STAT_ECCER) | ||
696 | dev_err(priv->dev, "NAND Flash ECC Uncorrectable Error\n"); | ||
697 | |||
698 | if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC) | ||
699 | mtd->ecc_stats.failed++; | ||
700 | |||
701 | return 0; | ||
702 | } | ||
703 | |||
704 | /* ECC will be calculated automatically, and errors will be detected in | ||
705 | * waitfunc. | ||
706 | */ | ||
707 | static void fsl_ifc_write_page(struct mtd_info *mtd, | ||
708 | struct nand_chip *chip, | ||
709 | const uint8_t *buf) | ||
710 | { | ||
711 | fsl_ifc_write_buf(mtd, buf, mtd->writesize); | ||
712 | fsl_ifc_write_buf(mtd, chip->oob_poi, mtd->oobsize); | ||
713 | } | ||
714 | |||
715 | static int fsl_ifc_chip_init_tail(struct mtd_info *mtd) | ||
716 | { | ||
717 | struct nand_chip *chip = mtd->priv; | ||
718 | struct fsl_ifc_mtd *priv = chip->priv; | ||
719 | |||
720 | dev_dbg(priv->dev, "%s: nand->numchips = %d\n", __func__, | ||
721 | chip->numchips); | ||
722 | dev_dbg(priv->dev, "%s: nand->chipsize = %lld\n", __func__, | ||
723 | chip->chipsize); | ||
724 | dev_dbg(priv->dev, "%s: nand->pagemask = %8x\n", __func__, | ||
725 | chip->pagemask); | ||
726 | dev_dbg(priv->dev, "%s: nand->chip_delay = %d\n", __func__, | ||
727 | chip->chip_delay); | ||
728 | dev_dbg(priv->dev, "%s: nand->badblockpos = %d\n", __func__, | ||
729 | chip->badblockpos); | ||
730 | dev_dbg(priv->dev, "%s: nand->chip_shift = %d\n", __func__, | ||
731 | chip->chip_shift); | ||
732 | dev_dbg(priv->dev, "%s: nand->page_shift = %d\n", __func__, | ||
733 | chip->page_shift); | ||
734 | dev_dbg(priv->dev, "%s: nand->phys_erase_shift = %d\n", __func__, | ||
735 | chip->phys_erase_shift); | ||
736 | dev_dbg(priv->dev, "%s: nand->ecclayout = %p\n", __func__, | ||
737 | chip->ecclayout); | ||
738 | dev_dbg(priv->dev, "%s: nand->ecc.mode = %d\n", __func__, | ||
739 | chip->ecc.mode); | ||
740 | dev_dbg(priv->dev, "%s: nand->ecc.steps = %d\n", __func__, | ||
741 | chip->ecc.steps); | ||
742 | dev_dbg(priv->dev, "%s: nand->ecc.bytes = %d\n", __func__, | ||
743 | chip->ecc.bytes); | ||
744 | dev_dbg(priv->dev, "%s: nand->ecc.total = %d\n", __func__, | ||
745 | chip->ecc.total); | ||
746 | dev_dbg(priv->dev, "%s: nand->ecc.layout = %p\n", __func__, | ||
747 | chip->ecc.layout); | ||
748 | dev_dbg(priv->dev, "%s: mtd->flags = %08x\n", __func__, mtd->flags); | ||
749 | dev_dbg(priv->dev, "%s: mtd->size = %lld\n", __func__, mtd->size); | ||
750 | dev_dbg(priv->dev, "%s: mtd->erasesize = %d\n", __func__, | ||
751 | mtd->erasesize); | ||
752 | dev_dbg(priv->dev, "%s: mtd->writesize = %d\n", __func__, | ||
753 | mtd->writesize); | ||
754 | dev_dbg(priv->dev, "%s: mtd->oobsize = %d\n", __func__, | ||
755 | mtd->oobsize); | ||
756 | |||
757 | return 0; | ||
758 | } | ||
759 | |||
760 | static int fsl_ifc_chip_init(struct fsl_ifc_mtd *priv) | ||
761 | { | ||
762 | struct fsl_ifc_ctrl *ctrl = priv->ctrl; | ||
763 | struct fsl_ifc_regs __iomem *ifc = ctrl->regs; | ||
764 | struct nand_chip *chip = &priv->chip; | ||
765 | struct nand_ecclayout *layout; | ||
766 | u32 csor; | ||
767 | |||
768 | /* Fill in fsl_ifc_mtd structure */ | ||
769 | priv->mtd.priv = chip; | ||
770 | priv->mtd.owner = THIS_MODULE; | ||
771 | |||
772 | /* fill in nand_chip structure */ | ||
773 | /* set up function call table */ | ||
774 | if ((in_be32(&ifc->cspr_cs[priv->bank].cspr)) & CSPR_PORT_SIZE_16) | ||
775 | chip->read_byte = fsl_ifc_read_byte16; | ||
776 | else | ||
777 | chip->read_byte = fsl_ifc_read_byte; | ||
778 | |||
779 | chip->write_buf = fsl_ifc_write_buf; | ||
780 | chip->read_buf = fsl_ifc_read_buf; | ||
781 | chip->verify_buf = fsl_ifc_verify_buf; | ||
782 | chip->select_chip = fsl_ifc_select_chip; | ||
783 | chip->cmdfunc = fsl_ifc_cmdfunc; | ||
784 | chip->waitfunc = fsl_ifc_wait; | ||
785 | |||
786 | chip->bbt_td = &bbt_main_descr; | ||
787 | chip->bbt_md = &bbt_mirror_descr; | ||
788 | |||
789 | out_be32(&ifc->ifc_nand.ncfgr, 0x0); | ||
790 | |||
791 | /* set up nand options */ | ||
792 | chip->options = NAND_NO_READRDY | NAND_NO_AUTOINCR; | ||
793 | chip->bbt_options = NAND_BBT_USE_FLASH; | ||
794 | |||
795 | |||
796 | if (in_be32(&ifc->cspr_cs[priv->bank].cspr) & CSPR_PORT_SIZE_16) { | ||
797 | chip->read_byte = fsl_ifc_read_byte16; | ||
798 | chip->options |= NAND_BUSWIDTH_16; | ||
799 | } else { | ||
800 | chip->read_byte = fsl_ifc_read_byte; | ||
801 | } | ||
802 | |||
803 | chip->controller = &ifc_nand_ctrl->controller; | ||
804 | chip->priv = priv; | ||
805 | |||
806 | chip->ecc.read_page = fsl_ifc_read_page; | ||
807 | chip->ecc.write_page = fsl_ifc_write_page; | ||
808 | |||
809 | csor = in_be32(&ifc->csor_cs[priv->bank].csor); | ||
810 | |||
811 | /* Hardware generates ECC per 512 Bytes */ | ||
812 | chip->ecc.size = 512; | ||
813 | chip->ecc.bytes = 8; | ||
814 | |||
815 | switch (csor & CSOR_NAND_PGS_MASK) { | ||
816 | case CSOR_NAND_PGS_512: | ||
817 | if (chip->options & NAND_BUSWIDTH_16) { | ||
818 | layout = &oob_512_16bit_ecc4; | ||
819 | } else { | ||
820 | layout = &oob_512_8bit_ecc4; | ||
821 | |||
822 | /* Avoid conflict with bad block marker */ | ||
823 | bbt_main_descr.offs = 0; | ||
824 | bbt_mirror_descr.offs = 0; | ||
825 | } | ||
826 | |||
827 | priv->bufnum_mask = 15; | ||
828 | break; | ||
829 | |||
830 | case CSOR_NAND_PGS_2K: | ||
831 | layout = &oob_2048_ecc4; | ||
832 | priv->bufnum_mask = 3; | ||
833 | break; | ||
834 | |||
835 | case CSOR_NAND_PGS_4K: | ||
836 | if ((csor & CSOR_NAND_ECC_MODE_MASK) == | ||
837 | CSOR_NAND_ECC_MODE_4) { | ||
838 | layout = &oob_4096_ecc4; | ||
839 | } else { | ||
840 | layout = &oob_4096_ecc8; | ||
841 | chip->ecc.bytes = 16; | ||
842 | } | ||
843 | |||
844 | priv->bufnum_mask = 1; | ||
845 | break; | ||
846 | |||
847 | default: | ||
848 | dev_err(priv->dev, "bad csor %#x: bad page size\n", csor); | ||
849 | return -ENODEV; | ||
850 | } | ||
851 | |||
852 | /* Must also set CSOR_NAND_ECC_ENC_EN if DEC_EN set */ | ||
853 | if (csor & CSOR_NAND_ECC_DEC_EN) { | ||
854 | chip->ecc.mode = NAND_ECC_HW; | ||
855 | chip->ecc.layout = layout; | ||
856 | } else { | ||
857 | chip->ecc.mode = NAND_ECC_SOFT; | ||
858 | } | ||
859 | |||
860 | return 0; | ||
861 | } | ||
862 | |||
863 | static int fsl_ifc_chip_remove(struct fsl_ifc_mtd *priv) | ||
864 | { | ||
865 | nand_release(&priv->mtd); | ||
866 | |||
867 | kfree(priv->mtd.name); | ||
868 | |||
869 | if (priv->vbase) | ||
870 | iounmap(priv->vbase); | ||
871 | |||
872 | ifc_nand_ctrl->chips[priv->bank] = NULL; | ||
873 | dev_set_drvdata(priv->dev, NULL); | ||
874 | kfree(priv); | ||
875 | |||
876 | return 0; | ||
877 | } | ||
878 | |||
879 | static int match_bank(struct fsl_ifc_regs __iomem *ifc, int bank, | ||
880 | phys_addr_t addr) | ||
881 | { | ||
882 | u32 cspr = in_be32(&ifc->cspr_cs[bank].cspr); | ||
883 | |||
884 | if (!(cspr & CSPR_V)) | ||
885 | return 0; | ||
886 | if ((cspr & CSPR_MSEL) != CSPR_MSEL_NAND) | ||
887 | return 0; | ||
888 | |||
889 | return (cspr & CSPR_BA) == convert_ifc_address(addr); | ||
890 | } | ||
891 | |||
892 | static DEFINE_MUTEX(fsl_ifc_nand_mutex); | ||
893 | |||
894 | static int __devinit fsl_ifc_nand_probe(struct platform_device *dev) | ||
895 | { | ||
896 | struct fsl_ifc_regs __iomem *ifc; | ||
897 | struct fsl_ifc_mtd *priv; | ||
898 | struct resource res; | ||
899 | static const char *part_probe_types[] | ||
900 | = { "cmdlinepart", "RedBoot", "ofpart", NULL }; | ||
901 | int ret; | ||
902 | int bank; | ||
903 | struct device_node *node = dev->dev.of_node; | ||
904 | struct mtd_part_parser_data ppdata; | ||
905 | |||
906 | ppdata.of_node = dev->dev.of_node; | ||
907 | if (!fsl_ifc_ctrl_dev || !fsl_ifc_ctrl_dev->regs) | ||
908 | return -ENODEV; | ||
909 | ifc = fsl_ifc_ctrl_dev->regs; | ||
910 | |||
911 | /* get, allocate and map the memory resource */ | ||
912 | ret = of_address_to_resource(node, 0, &res); | ||
913 | if (ret) { | ||
914 | dev_err(&dev->dev, "%s: failed to get resource\n", __func__); | ||
915 | return ret; | ||
916 | } | ||
917 | |||
918 | /* find which chip select it is connected to */ | ||
919 | for (bank = 0; bank < FSL_IFC_BANK_COUNT; bank++) { | ||
920 | if (match_bank(ifc, bank, res.start)) | ||
921 | break; | ||
922 | } | ||
923 | |||
924 | if (bank >= FSL_IFC_BANK_COUNT) { | ||
925 | dev_err(&dev->dev, "%s: address did not match any chip selects\n", | ||
926 | __func__); | ||
927 | return -ENODEV; | ||
928 | } | ||
929 | |||
930 | priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL); | ||
931 | if (!priv) | ||
932 | return -ENOMEM; | ||
933 | |||
934 | mutex_lock(&fsl_ifc_nand_mutex); | ||
935 | if (!fsl_ifc_ctrl_dev->nand) { | ||
936 | ifc_nand_ctrl = kzalloc(sizeof(*ifc_nand_ctrl), GFP_KERNEL); | ||
937 | if (!ifc_nand_ctrl) { | ||
938 | dev_err(&dev->dev, "failed to allocate memory\n"); | ||
939 | mutex_unlock(&fsl_ifc_nand_mutex); | ||
940 | return -ENOMEM; | ||
941 | } | ||
942 | |||
943 | ifc_nand_ctrl->read_bytes = 0; | ||
944 | ifc_nand_ctrl->index = 0; | ||
945 | ifc_nand_ctrl->addr = NULL; | ||
946 | fsl_ifc_ctrl_dev->nand = ifc_nand_ctrl; | ||
947 | |||
948 | spin_lock_init(&ifc_nand_ctrl->controller.lock); | ||
949 | init_waitqueue_head(&ifc_nand_ctrl->controller.wq); | ||
950 | } else { | ||
951 | ifc_nand_ctrl = fsl_ifc_ctrl_dev->nand; | ||
952 | } | ||
953 | mutex_unlock(&fsl_ifc_nand_mutex); | ||
954 | |||
955 | ifc_nand_ctrl->chips[bank] = priv; | ||
956 | priv->bank = bank; | ||
957 | priv->ctrl = fsl_ifc_ctrl_dev; | ||
958 | priv->dev = &dev->dev; | ||
959 | |||
960 | priv->vbase = ioremap(res.start, resource_size(&res)); | ||
961 | if (!priv->vbase) { | ||
962 | dev_err(priv->dev, "%s: failed to map chip region\n", __func__); | ||
963 | ret = -ENOMEM; | ||
964 | goto err; | ||
965 | } | ||
966 | |||
967 | dev_set_drvdata(priv->dev, priv); | ||
968 | |||
969 | out_be32(&ifc->ifc_nand.nand_evter_en, | ||
970 | IFC_NAND_EVTER_EN_OPC_EN | | ||
971 | IFC_NAND_EVTER_EN_FTOER_EN | | ||
972 | IFC_NAND_EVTER_EN_WPER_EN); | ||
973 | |||
974 | /* enable NAND Machine Interrupts */ | ||
975 | out_be32(&ifc->ifc_nand.nand_evter_intr_en, | ||
976 | IFC_NAND_EVTER_INTR_OPCIR_EN | | ||
977 | IFC_NAND_EVTER_INTR_FTOERIR_EN | | ||
978 | IFC_NAND_EVTER_INTR_WPERIR_EN); | ||
979 | |||
980 | priv->mtd.name = kasprintf(GFP_KERNEL, "%x.flash", (unsigned)res.start); | ||
981 | if (!priv->mtd.name) { | ||
982 | ret = -ENOMEM; | ||
983 | goto err; | ||
984 | } | ||
985 | |||
986 | ret = fsl_ifc_chip_init(priv); | ||
987 | if (ret) | ||
988 | goto err; | ||
989 | |||
990 | ret = nand_scan_ident(&priv->mtd, 1, NULL); | ||
991 | if (ret) | ||
992 | goto err; | ||
993 | |||
994 | ret = fsl_ifc_chip_init_tail(&priv->mtd); | ||
995 | if (ret) | ||
996 | goto err; | ||
997 | |||
998 | ret = nand_scan_tail(&priv->mtd); | ||
999 | if (ret) | ||
1000 | goto err; | ||
1001 | |||
1002 | /* First look for RedBoot table or partitions on the command | ||
1003 | * line, these take precedence over device tree information */ | ||
1004 | mtd_device_parse_register(&priv->mtd, part_probe_types, &ppdata, | ||
1005 | NULL, 0); | ||
1006 | |||
1007 | dev_info(priv->dev, "IFC NAND device at 0x%llx, bank %d\n", | ||
1008 | (unsigned long long)res.start, priv->bank); | ||
1009 | return 0; | ||
1010 | |||
1011 | err: | ||
1012 | fsl_ifc_chip_remove(priv); | ||
1013 | return ret; | ||
1014 | } | ||
1015 | |||
1016 | static int fsl_ifc_nand_remove(struct platform_device *dev) | ||
1017 | { | ||
1018 | struct fsl_ifc_mtd *priv = dev_get_drvdata(&dev->dev); | ||
1019 | |||
1020 | fsl_ifc_chip_remove(priv); | ||
1021 | |||
1022 | mutex_lock(&fsl_ifc_nand_mutex); | ||
1023 | ifc_nand_ctrl->counter--; | ||
1024 | if (!ifc_nand_ctrl->counter) { | ||
1025 | fsl_ifc_ctrl_dev->nand = NULL; | ||
1026 | kfree(ifc_nand_ctrl); | ||
1027 | } | ||
1028 | mutex_unlock(&fsl_ifc_nand_mutex); | ||
1029 | |||
1030 | return 0; | ||
1031 | } | ||
1032 | |||
1033 | static const struct of_device_id fsl_ifc_nand_match[] = { | ||
1034 | { | ||
1035 | .compatible = "fsl,ifc-nand", | ||
1036 | }, | ||
1037 | {} | ||
1038 | }; | ||
1039 | |||
1040 | static struct platform_driver fsl_ifc_nand_driver = { | ||
1041 | .driver = { | ||
1042 | .name = "fsl,ifc-nand", | ||
1043 | .owner = THIS_MODULE, | ||
1044 | .of_match_table = fsl_ifc_nand_match, | ||
1045 | }, | ||
1046 | .probe = fsl_ifc_nand_probe, | ||
1047 | .remove = fsl_ifc_nand_remove, | ||
1048 | }; | ||
1049 | |||
1050 | static int __init fsl_ifc_nand_init(void) | ||
1051 | { | ||
1052 | int ret; | ||
1053 | |||
1054 | ret = platform_driver_register(&fsl_ifc_nand_driver); | ||
1055 | if (ret) | ||
1056 | printk(KERN_ERR "fsl-ifc: Failed to register platform" | ||
1057 | "driver\n"); | ||
1058 | |||
1059 | return ret; | ||
1060 | } | ||
1061 | |||
1062 | static void __exit fsl_ifc_nand_exit(void) | ||
1063 | { | ||
1064 | platform_driver_unregister(&fsl_ifc_nand_driver); | ||
1065 | } | ||
1066 | |||
1067 | module_init(fsl_ifc_nand_init); | ||
1068 | module_exit(fsl_ifc_nand_exit); | ||
1069 | |||
1070 | MODULE_LICENSE("GPL"); | ||
1071 | MODULE_AUTHOR("Freescale"); | ||
1072 | MODULE_DESCRIPTION("Freescale Integrated Flash Controller MTD NAND driver"); | ||
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index d3d18e89cb57..4e89103204dc 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig | |||
@@ -974,9 +974,8 @@ config SCSI_IPS | |||
974 | 974 | ||
975 | config SCSI_IBMVSCSI | 975 | config SCSI_IBMVSCSI |
976 | tristate "IBM Virtual SCSI support" | 976 | tristate "IBM Virtual SCSI support" |
977 | depends on PPC_PSERIES || PPC_ISERIES | 977 | depends on PPC_PSERIES |
978 | select SCSI_SRP_ATTRS | 978 | select SCSI_SRP_ATTRS |
979 | select VIOPATH if PPC_ISERIES | ||
980 | help | 979 | help |
981 | This is the IBM POWER Virtual SCSI Client | 980 | This is the IBM POWER Virtual SCSI Client |
982 | 981 | ||
diff --git a/drivers/scsi/ibmvscsi/Makefile b/drivers/scsi/ibmvscsi/Makefile index a423d9633625..ff5b5c5538ee 100644 --- a/drivers/scsi/ibmvscsi/Makefile +++ b/drivers/scsi/ibmvscsi/Makefile | |||
@@ -1,7 +1,6 @@ | |||
1 | obj-$(CONFIG_SCSI_IBMVSCSI) += ibmvscsic.o | 1 | obj-$(CONFIG_SCSI_IBMVSCSI) += ibmvscsic.o |
2 | 2 | ||
3 | ibmvscsic-y += ibmvscsi.o | 3 | ibmvscsic-y += ibmvscsi.o |
4 | ibmvscsic-$(CONFIG_PPC_ISERIES) += iseries_vscsi.o | ||
5 | ibmvscsic-$(CONFIG_PPC_PSERIES) += rpa_vscsi.o | 4 | ibmvscsic-$(CONFIG_PPC_PSERIES) += rpa_vscsi.o |
6 | 5 | ||
7 | obj-$(CONFIG_SCSI_IBMVSCSIS) += ibmvstgt.o | 6 | obj-$(CONFIG_SCSI_IBMVSCSIS) += ibmvstgt.o |
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 3d391dc3f11f..e984951baeb6 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c | |||
@@ -55,13 +55,7 @@ | |||
55 | * and sends a CRQ message back to inform the client that the request has | 55 | * and sends a CRQ message back to inform the client that the request has |
56 | * completed. | 56 | * completed. |
57 | * | 57 | * |
58 | * Note that some of the underlying infrastructure is different between | 58 | * TODO: This is currently pretty tied to the IBM pSeries hypervisor |
59 | * machines conforming to the "RS/6000 Platform Architecture" (RPA) and | ||
60 | * the older iSeries hypervisor models. To support both, some low level | ||
61 | * routines have been broken out into rpa_vscsi.c and iseries_vscsi.c. | ||
62 | * The Makefile should pick one, not two, not zero, of these. | ||
63 | * | ||
64 | * TODO: This is currently pretty tied to the IBM i/pSeries hypervisor | ||
65 | * interfaces. It would be really nice to abstract this above an RDMA | 59 | * interfaces. It would be really nice to abstract this above an RDMA |
66 | * layer. | 60 | * layer. |
67 | */ | 61 | */ |
@@ -2085,9 +2079,7 @@ int __init ibmvscsi_module_init(void) | |||
2085 | driver_template.can_queue = max_requests; | 2079 | driver_template.can_queue = max_requests; |
2086 | max_events = max_requests + 2; | 2080 | max_events = max_requests + 2; |
2087 | 2081 | ||
2088 | if (firmware_has_feature(FW_FEATURE_ISERIES)) | 2082 | if (firmware_has_feature(FW_FEATURE_VIO)) |
2089 | ibmvscsi_ops = &iseriesvscsi_ops; | ||
2090 | else if (firmware_has_feature(FW_FEATURE_VIO)) | ||
2091 | ibmvscsi_ops = &rpavscsi_ops; | 2083 | ibmvscsi_ops = &rpavscsi_ops; |
2092 | else | 2084 | else |
2093 | return -ENODEV; | 2085 | return -ENODEV; |
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.h b/drivers/scsi/ibmvscsi/ibmvscsi.h index 02197a2b22b9..c503e1776014 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.h +++ b/drivers/scsi/ibmvscsi/ibmvscsi.h | |||
@@ -127,7 +127,6 @@ struct ibmvscsi_ops { | |||
127 | int (*resume) (struct ibmvscsi_host_data *hostdata); | 127 | int (*resume) (struct ibmvscsi_host_data *hostdata); |
128 | }; | 128 | }; |
129 | 129 | ||
130 | extern struct ibmvscsi_ops iseriesvscsi_ops; | ||
131 | extern struct ibmvscsi_ops rpavscsi_ops; | 130 | extern struct ibmvscsi_ops rpavscsi_ops; |
132 | 131 | ||
133 | #endif /* IBMVSCSI_H */ | 132 | #endif /* IBMVSCSI_H */ |
diff --git a/drivers/scsi/ibmvscsi/iseries_vscsi.c b/drivers/scsi/ibmvscsi/iseries_vscsi.c deleted file mode 100644 index f4776451a754..000000000000 --- a/drivers/scsi/ibmvscsi/iseries_vscsi.c +++ /dev/null | |||
@@ -1,173 +0,0 @@ | |||
1 | /* ------------------------------------------------------------ | ||
2 | * iSeries_vscsi.c | ||
3 | * (C) Copyright IBM Corporation 1994, 2003 | ||
4 | * Authors: Colin DeVilbiss (devilbis@us.ibm.com) | ||
5 | * Santiago Leon (santil@us.ibm.com) | ||
6 | * Dave Boutcher (sleddog@us.ibm.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 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 | ||
21 | * USA | ||
22 | * | ||
23 | * ------------------------------------------------------------ | ||
24 | * iSeries-specific functions of the SCSI host adapter for Virtual I/O devices | ||
25 | * | ||
26 | * This driver allows the Linux SCSI peripheral drivers to directly | ||
27 | * access devices in the hosting partition, either on an iSeries | ||
28 | * hypervisor system or a converged hypervisor system. | ||
29 | */ | ||
30 | |||
31 | #include <asm/iseries/vio.h> | ||
32 | #include <asm/iseries/hv_lp_event.h> | ||
33 | #include <asm/iseries/hv_types.h> | ||
34 | #include <asm/iseries/hv_lp_config.h> | ||
35 | #include <asm/vio.h> | ||
36 | #include <linux/device.h> | ||
37 | #include "ibmvscsi.h" | ||
38 | |||
39 | /* global variables */ | ||
40 | static struct ibmvscsi_host_data *single_host_data; | ||
41 | |||
42 | /* ------------------------------------------------------------ | ||
43 | * Routines for direct interpartition interaction | ||
44 | */ | ||
45 | struct srp_lp_event { | ||
46 | struct HvLpEvent lpevt; /* 0x00-0x17 */ | ||
47 | u32 reserved1; /* 0x18-0x1B; unused */ | ||
48 | u16 version; /* 0x1C-0x1D; unused */ | ||
49 | u16 subtype_rc; /* 0x1E-0x1F; unused */ | ||
50 | struct viosrp_crq crq; /* 0x20-0x3F */ | ||
51 | }; | ||
52 | |||
53 | /** | ||
54 | * standard interface for handling logical partition events. | ||
55 | */ | ||
56 | static void iseriesvscsi_handle_event(struct HvLpEvent *lpevt) | ||
57 | { | ||
58 | struct srp_lp_event *evt = (struct srp_lp_event *)lpevt; | ||
59 | |||
60 | if (!evt) { | ||
61 | printk(KERN_ERR "ibmvscsi: received null event\n"); | ||
62 | return; | ||
63 | } | ||
64 | |||
65 | if (single_host_data == NULL) { | ||
66 | printk(KERN_ERR | ||
67 | "ibmvscsi: received event, no adapter present\n"); | ||
68 | return; | ||
69 | } | ||
70 | |||
71 | ibmvscsi_handle_crq(&evt->crq, single_host_data); | ||
72 | } | ||
73 | |||
74 | /* ------------------------------------------------------------ | ||
75 | * Routines for driver initialization | ||
76 | */ | ||
77 | static int iseriesvscsi_init_crq_queue(struct crq_queue *queue, | ||
78 | struct ibmvscsi_host_data *hostdata, | ||
79 | int max_requests) | ||
80 | { | ||
81 | int rc; | ||
82 | |||
83 | single_host_data = hostdata; | ||
84 | rc = viopath_open(viopath_hostLp, viomajorsubtype_scsi, max_requests); | ||
85 | if (rc < 0) { | ||
86 | printk("viopath_open failed with rc %d in open_event_path\n", | ||
87 | rc); | ||
88 | goto viopath_open_failed; | ||
89 | } | ||
90 | |||
91 | rc = vio_setHandler(viomajorsubtype_scsi, iseriesvscsi_handle_event); | ||
92 | if (rc < 0) { | ||
93 | printk("vio_setHandler failed with rc %d in open_event_path\n", | ||
94 | rc); | ||
95 | goto vio_setHandler_failed; | ||
96 | } | ||
97 | return 0; | ||
98 | |||
99 | vio_setHandler_failed: | ||
100 | viopath_close(viopath_hostLp, viomajorsubtype_scsi, max_requests); | ||
101 | viopath_open_failed: | ||
102 | return -1; | ||
103 | } | ||
104 | |||
105 | static void iseriesvscsi_release_crq_queue(struct crq_queue *queue, | ||
106 | struct ibmvscsi_host_data *hostdata, | ||
107 | int max_requests) | ||
108 | { | ||
109 | vio_clearHandler(viomajorsubtype_scsi); | ||
110 | viopath_close(viopath_hostLp, viomajorsubtype_scsi, max_requests); | ||
111 | } | ||
112 | |||
113 | /** | ||
114 | * reset_crq_queue: - resets a crq after a failure | ||
115 | * @queue: crq_queue to initialize and register | ||
116 | * @hostdata: ibmvscsi_host_data of host | ||
117 | * | ||
118 | * no-op for iSeries | ||
119 | */ | ||
120 | static int iseriesvscsi_reset_crq_queue(struct crq_queue *queue, | ||
121 | struct ibmvscsi_host_data *hostdata) | ||
122 | { | ||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | /** | ||
127 | * reenable_crq_queue: - reenables a crq after a failure | ||
128 | * @queue: crq_queue to initialize and register | ||
129 | * @hostdata: ibmvscsi_host_data of host | ||
130 | * | ||
131 | * no-op for iSeries | ||
132 | */ | ||
133 | static int iseriesvscsi_reenable_crq_queue(struct crq_queue *queue, | ||
134 | struct ibmvscsi_host_data *hostdata) | ||
135 | { | ||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | /** | ||
140 | * iseriesvscsi_send_crq: - Send a CRQ | ||
141 | * @hostdata: the adapter | ||
142 | * @word1: the first 64 bits of the data | ||
143 | * @word2: the second 64 bits of the data | ||
144 | */ | ||
145 | static int iseriesvscsi_send_crq(struct ibmvscsi_host_data *hostdata, | ||
146 | u64 word1, u64 word2) | ||
147 | { | ||
148 | single_host_data = hostdata; | ||
149 | return HvCallEvent_signalLpEventFast(viopath_hostLp, | ||
150 | HvLpEvent_Type_VirtualIo, | ||
151 | viomajorsubtype_scsi, | ||
152 | HvLpEvent_AckInd_NoAck, | ||
153 | HvLpEvent_AckType_ImmediateAck, | ||
154 | viopath_sourceinst(viopath_hostLp), | ||
155 | viopath_targetinst(viopath_hostLp), | ||
156 | 0, | ||
157 | VIOVERSION << 16, word1, word2, 0, | ||
158 | 0); | ||
159 | } | ||
160 | |||
161 | static int iseriesvscsi_resume(struct ibmvscsi_host_data *hostdata) | ||
162 | { | ||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | struct ibmvscsi_ops iseriesvscsi_ops = { | ||
167 | .init_crq_queue = iseriesvscsi_init_crq_queue, | ||
168 | .release_crq_queue = iseriesvscsi_release_crq_queue, | ||
169 | .reset_crq_queue = iseriesvscsi_reset_crq_queue, | ||
170 | .reenable_crq_queue = iseriesvscsi_reenable_crq_queue, | ||
171 | .send_crq = iseriesvscsi_send_crq, | ||
172 | .resume = iseriesvscsi_resume, | ||
173 | }; | ||
diff --git a/drivers/tty/hvc/Kconfig b/drivers/tty/hvc/Kconfig index 4222035acfb7..48cb8d3d1758 100644 --- a/drivers/tty/hvc/Kconfig +++ b/drivers/tty/hvc/Kconfig | |||
@@ -24,16 +24,6 @@ config HVC_OLD_HVSI | |||
24 | depends on HVC_CONSOLE | 24 | depends on HVC_CONSOLE |
25 | default n | 25 | default n |
26 | 26 | ||
27 | config HVC_ISERIES | ||
28 | bool "iSeries Hypervisor Virtual Console support" | ||
29 | depends on PPC_ISERIES | ||
30 | default y | ||
31 | select HVC_DRIVER | ||
32 | select HVC_IRQ | ||
33 | select VIOPATH | ||
34 | help | ||
35 | iSeries machines support a hypervisor virtual console. | ||
36 | |||
37 | config HVC_OPAL | 27 | config HVC_OPAL |
38 | bool "OPAL Console support" | 28 | bool "OPAL Console support" |
39 | depends on PPC_POWERNV | 29 | depends on PPC_POWERNV |
@@ -81,6 +71,10 @@ config HVC_UDBG | |||
81 | depends on PPC && EXPERIMENTAL | 71 | depends on PPC && EXPERIMENTAL |
82 | select HVC_DRIVER | 72 | select HVC_DRIVER |
83 | default n | 73 | default n |
74 | help | ||
75 | This is meant to be used during HW bring up or debugging when | ||
76 | no other console mechanism exist but udbg, to get you a quick | ||
77 | console for userspace. Do NOT enable in production kernels. | ||
84 | 78 | ||
85 | config HVC_DCC | 79 | config HVC_DCC |
86 | bool "ARM JTAG DCC console" | 80 | bool "ARM JTAG DCC console" |
diff --git a/drivers/tty/hvc/Makefile b/drivers/tty/hvc/Makefile index 89abf40bc73d..4ca3723b0a3a 100644 --- a/drivers/tty/hvc/Makefile +++ b/drivers/tty/hvc/Makefile | |||
@@ -1,7 +1,6 @@ | |||
1 | obj-$(CONFIG_HVC_CONSOLE) += hvc_vio.o hvsi_lib.o | 1 | obj-$(CONFIG_HVC_CONSOLE) += hvc_vio.o hvsi_lib.o |
2 | obj-$(CONFIG_HVC_OPAL) += hvc_opal.o hvsi_lib.o | 2 | obj-$(CONFIG_HVC_OPAL) += hvc_opal.o hvsi_lib.o |
3 | obj-$(CONFIG_HVC_OLD_HVSI) += hvsi.o | 3 | obj-$(CONFIG_HVC_OLD_HVSI) += hvsi.o |
4 | obj-$(CONFIG_HVC_ISERIES) += hvc_iseries.o | ||
5 | obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o | 4 | obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o |
6 | obj-$(CONFIG_HVC_TILE) += hvc_tile.o | 5 | obj-$(CONFIG_HVC_TILE) += hvc_tile.o |
7 | obj-$(CONFIG_HVC_DCC) += hvc_dcc.o | 6 | obj-$(CONFIG_HVC_DCC) += hvc_dcc.o |
diff --git a/drivers/tty/hvc/hvc_iseries.c b/drivers/tty/hvc/hvc_iseries.c deleted file mode 100644 index 3f4a897bf4d7..000000000000 --- a/drivers/tty/hvc/hvc_iseries.c +++ /dev/null | |||
@@ -1,599 +0,0 @@ | |||
1 | /* | ||
2 | * iSeries vio driver interface to hvc_console.c | ||
3 | * | ||
4 | * This code is based heavily on hvc_vio.c and viocons.c | ||
5 | * | ||
6 | * Copyright (C) 2006 Stephen Rothwell, IBM Corporation | ||
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 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | */ | ||
22 | #include <stdarg.h> | ||
23 | #include <linux/types.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/spinlock.h> | ||
28 | #include <linux/console.h> | ||
29 | |||
30 | #include <asm/hvconsole.h> | ||
31 | #include <asm/vio.h> | ||
32 | #include <asm/prom.h> | ||
33 | #include <asm/firmware.h> | ||
34 | #include <asm/iseries/vio.h> | ||
35 | #include <asm/iseries/hv_call.h> | ||
36 | #include <asm/iseries/hv_lp_config.h> | ||
37 | #include <asm/iseries/hv_lp_event.h> | ||
38 | |||
39 | #include "hvc_console.h" | ||
40 | |||
41 | #define VTTY_PORTS 10 | ||
42 | |||
43 | static DEFINE_SPINLOCK(consolelock); | ||
44 | static DEFINE_SPINLOCK(consoleloglock); | ||
45 | |||
46 | static const char hvc_driver_name[] = "hvc_console"; | ||
47 | |||
48 | #define IN_BUF_SIZE 200 | ||
49 | |||
50 | /* | ||
51 | * Our port information. | ||
52 | */ | ||
53 | static struct port_info { | ||
54 | HvLpIndex lp; | ||
55 | u64 seq; /* sequence number of last HV send */ | ||
56 | u64 ack; /* last ack from HV */ | ||
57 | struct hvc_struct *hp; | ||
58 | int in_start; | ||
59 | int in_end; | ||
60 | unsigned char in_buf[IN_BUF_SIZE]; | ||
61 | } port_info[VTTY_PORTS] = { | ||
62 | [ 0 ... VTTY_PORTS - 1 ] = { | ||
63 | .lp = HvLpIndexInvalid | ||
64 | } | ||
65 | }; | ||
66 | |||
67 | #define viochar_is_console(pi) ((pi) == &port_info[0]) | ||
68 | |||
69 | static struct vio_device_id hvc_driver_table[] __devinitdata = { | ||
70 | {"serial", "IBM,iSeries-vty"}, | ||
71 | { "", "" } | ||
72 | }; | ||
73 | MODULE_DEVICE_TABLE(vio, hvc_driver_table); | ||
74 | |||
75 | static void hvlog(char *fmt, ...) | ||
76 | { | ||
77 | int i; | ||
78 | unsigned long flags; | ||
79 | va_list args; | ||
80 | static char buf[256]; | ||
81 | |||
82 | spin_lock_irqsave(&consoleloglock, flags); | ||
83 | va_start(args, fmt); | ||
84 | i = vscnprintf(buf, sizeof(buf) - 1, fmt, args); | ||
85 | va_end(args); | ||
86 | buf[i++] = '\r'; | ||
87 | HvCall_writeLogBuffer(buf, i); | ||
88 | spin_unlock_irqrestore(&consoleloglock, flags); | ||
89 | } | ||
90 | |||
91 | /* | ||
92 | * Initialize the common fields in a charLpEvent | ||
93 | */ | ||
94 | static void init_data_event(struct viocharlpevent *viochar, HvLpIndex lp) | ||
95 | { | ||
96 | struct HvLpEvent *hev = &viochar->event; | ||
97 | |||
98 | memset(viochar, 0, sizeof(struct viocharlpevent)); | ||
99 | |||
100 | hev->flags = HV_LP_EVENT_VALID | HV_LP_EVENT_DEFERRED_ACK | | ||
101 | HV_LP_EVENT_INT; | ||
102 | hev->xType = HvLpEvent_Type_VirtualIo; | ||
103 | hev->xSubtype = viomajorsubtype_chario | viochardata; | ||
104 | hev->xSourceLp = HvLpConfig_getLpIndex(); | ||
105 | hev->xTargetLp = lp; | ||
106 | hev->xSizeMinus1 = sizeof(struct viocharlpevent); | ||
107 | hev->xSourceInstanceId = viopath_sourceinst(lp); | ||
108 | hev->xTargetInstanceId = viopath_targetinst(lp); | ||
109 | } | ||
110 | |||
111 | static int get_chars(uint32_t vtermno, char *buf, int count) | ||
112 | { | ||
113 | struct port_info *pi; | ||
114 | int n = 0; | ||
115 | unsigned long flags; | ||
116 | |||
117 | if (vtermno >= VTTY_PORTS) | ||
118 | return -EINVAL; | ||
119 | if (count == 0) | ||
120 | return 0; | ||
121 | |||
122 | pi = &port_info[vtermno]; | ||
123 | spin_lock_irqsave(&consolelock, flags); | ||
124 | |||
125 | if (pi->in_end == 0) | ||
126 | goto done; | ||
127 | |||
128 | n = pi->in_end - pi->in_start; | ||
129 | if (n > count) | ||
130 | n = count; | ||
131 | memcpy(buf, &pi->in_buf[pi->in_start], n); | ||
132 | pi->in_start += n; | ||
133 | if (pi->in_start == pi->in_end) { | ||
134 | pi->in_start = 0; | ||
135 | pi->in_end = 0; | ||
136 | } | ||
137 | done: | ||
138 | spin_unlock_irqrestore(&consolelock, flags); | ||
139 | return n; | ||
140 | } | ||
141 | |||
142 | static int put_chars(uint32_t vtermno, const char *buf, int count) | ||
143 | { | ||
144 | struct viocharlpevent *viochar; | ||
145 | struct port_info *pi; | ||
146 | HvLpEvent_Rc hvrc; | ||
147 | unsigned long flags; | ||
148 | int sent = 0; | ||
149 | |||
150 | if (vtermno >= VTTY_PORTS) | ||
151 | return -EINVAL; | ||
152 | |||
153 | pi = &port_info[vtermno]; | ||
154 | |||
155 | spin_lock_irqsave(&consolelock, flags); | ||
156 | |||
157 | if (viochar_is_console(pi) && !viopath_isactive(pi->lp)) { | ||
158 | HvCall_writeLogBuffer(buf, count); | ||
159 | sent = count; | ||
160 | goto done; | ||
161 | } | ||
162 | |||
163 | viochar = vio_get_event_buffer(viomajorsubtype_chario); | ||
164 | if (viochar == NULL) { | ||
165 | hvlog("\n\rviocons: Can't get viochar buffer."); | ||
166 | goto done; | ||
167 | } | ||
168 | |||
169 | while ((count > 0) && ((pi->seq - pi->ack) < VIOCHAR_WINDOW)) { | ||
170 | int len; | ||
171 | |||
172 | len = (count > VIOCHAR_MAX_DATA) ? VIOCHAR_MAX_DATA : count; | ||
173 | |||
174 | if (viochar_is_console(pi)) | ||
175 | HvCall_writeLogBuffer(buf, len); | ||
176 | |||
177 | init_data_event(viochar, pi->lp); | ||
178 | |||
179 | viochar->len = len; | ||
180 | viochar->event.xCorrelationToken = pi->seq++; | ||
181 | viochar->event.xSizeMinus1 = | ||
182 | offsetof(struct viocharlpevent, data) + len; | ||
183 | |||
184 | memcpy(viochar->data, buf, len); | ||
185 | |||
186 | hvrc = HvCallEvent_signalLpEvent(&viochar->event); | ||
187 | if (hvrc) | ||
188 | hvlog("\n\rerror sending event! return code %d\n\r", | ||
189 | (int)hvrc); | ||
190 | sent += len; | ||
191 | count -= len; | ||
192 | buf += len; | ||
193 | } | ||
194 | |||
195 | vio_free_event_buffer(viomajorsubtype_chario, viochar); | ||
196 | done: | ||
197 | spin_unlock_irqrestore(&consolelock, flags); | ||
198 | return sent; | ||
199 | } | ||
200 | |||
201 | static const struct hv_ops hvc_get_put_ops = { | ||
202 | .get_chars = get_chars, | ||
203 | .put_chars = put_chars, | ||
204 | .notifier_add = notifier_add_irq, | ||
205 | .notifier_del = notifier_del_irq, | ||
206 | .notifier_hangup = notifier_hangup_irq, | ||
207 | }; | ||
208 | |||
209 | static int __devinit hvc_vio_probe(struct vio_dev *vdev, | ||
210 | const struct vio_device_id *id) | ||
211 | { | ||
212 | struct hvc_struct *hp; | ||
213 | struct port_info *pi; | ||
214 | |||
215 | /* probed with invalid parameters. */ | ||
216 | if (!vdev || !id) | ||
217 | return -EPERM; | ||
218 | |||
219 | if (vdev->unit_address >= VTTY_PORTS) | ||
220 | return -ENODEV; | ||
221 | |||
222 | pi = &port_info[vdev->unit_address]; | ||
223 | |||
224 | hp = hvc_alloc(vdev->unit_address, vdev->irq, &hvc_get_put_ops, | ||
225 | VIOCHAR_MAX_DATA); | ||
226 | if (IS_ERR(hp)) | ||
227 | return PTR_ERR(hp); | ||
228 | pi->hp = hp; | ||
229 | dev_set_drvdata(&vdev->dev, pi); | ||
230 | |||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | static int __devexit hvc_vio_remove(struct vio_dev *vdev) | ||
235 | { | ||
236 | struct port_info *pi = dev_get_drvdata(&vdev->dev); | ||
237 | struct hvc_struct *hp = pi->hp; | ||
238 | |||
239 | return hvc_remove(hp); | ||
240 | } | ||
241 | |||
242 | static struct vio_driver hvc_vio_driver = { | ||
243 | .id_table = hvc_driver_table, | ||
244 | .probe = hvc_vio_probe, | ||
245 | .remove = __devexit_p(hvc_vio_remove), | ||
246 | .driver = { | ||
247 | .name = hvc_driver_name, | ||
248 | .owner = THIS_MODULE, | ||
249 | } | ||
250 | }; | ||
251 | |||
252 | static void hvc_open_event(struct HvLpEvent *event) | ||
253 | { | ||
254 | unsigned long flags; | ||
255 | struct viocharlpevent *cevent = (struct viocharlpevent *)event; | ||
256 | u8 port = cevent->virtual_device; | ||
257 | struct port_info *pi; | ||
258 | int reject = 0; | ||
259 | |||
260 | if (hvlpevent_is_ack(event)) { | ||
261 | if (port >= VTTY_PORTS) | ||
262 | return; | ||
263 | |||
264 | spin_lock_irqsave(&consolelock, flags); | ||
265 | |||
266 | pi = &port_info[port]; | ||
267 | if (event->xRc == HvLpEvent_Rc_Good) { | ||
268 | pi->seq = pi->ack = 0; | ||
269 | /* | ||
270 | * This line allows connections from the primary | ||
271 | * partition but once one is connected from the | ||
272 | * primary partition nothing short of a reboot | ||
273 | * of linux will allow access from the hosting | ||
274 | * partition again without a required iSeries fix. | ||
275 | */ | ||
276 | pi->lp = event->xTargetLp; | ||
277 | } | ||
278 | |||
279 | spin_unlock_irqrestore(&consolelock, flags); | ||
280 | if (event->xRc != HvLpEvent_Rc_Good) | ||
281 | printk(KERN_WARNING | ||
282 | "hvc: handle_open_event: event->xRc == (%d).\n", | ||
283 | event->xRc); | ||
284 | |||
285 | if (event->xCorrelationToken != 0) { | ||
286 | atomic_t *aptr= (atomic_t *)event->xCorrelationToken; | ||
287 | atomic_set(aptr, 1); | ||
288 | } else | ||
289 | printk(KERN_WARNING | ||
290 | "hvc: weird...got open ack without atomic\n"); | ||
291 | return; | ||
292 | } | ||
293 | |||
294 | /* This had better require an ack, otherwise complain */ | ||
295 | if (!hvlpevent_need_ack(event)) { | ||
296 | printk(KERN_WARNING "hvc: viocharopen without ack bit!\n"); | ||
297 | return; | ||
298 | } | ||
299 | |||
300 | spin_lock_irqsave(&consolelock, flags); | ||
301 | |||
302 | /* Make sure this is a good virtual tty */ | ||
303 | if (port >= VTTY_PORTS) { | ||
304 | event->xRc = HvLpEvent_Rc_SubtypeError; | ||
305 | cevent->subtype_result_code = viorc_openRejected; | ||
306 | /* | ||
307 | * Flag state here since we can't printk while holding | ||
308 | * the consolelock spinlock. | ||
309 | */ | ||
310 | reject = 1; | ||
311 | } else { | ||
312 | pi = &port_info[port]; | ||
313 | if ((pi->lp != HvLpIndexInvalid) && | ||
314 | (pi->lp != event->xSourceLp)) { | ||
315 | /* | ||
316 | * If this is tty is already connected to a different | ||
317 | * partition, fail. | ||
318 | */ | ||
319 | event->xRc = HvLpEvent_Rc_SubtypeError; | ||
320 | cevent->subtype_result_code = viorc_openRejected; | ||
321 | reject = 2; | ||
322 | } else { | ||
323 | pi->lp = event->xSourceLp; | ||
324 | event->xRc = HvLpEvent_Rc_Good; | ||
325 | cevent->subtype_result_code = viorc_good; | ||
326 | pi->seq = pi->ack = 0; | ||
327 | } | ||
328 | } | ||
329 | |||
330 | spin_unlock_irqrestore(&consolelock, flags); | ||
331 | |||
332 | if (reject == 1) | ||
333 | printk(KERN_WARNING "hvc: open rejected: bad virtual tty.\n"); | ||
334 | else if (reject == 2) | ||
335 | printk(KERN_WARNING "hvc: open rejected: console in exclusive " | ||
336 | "use by another partition.\n"); | ||
337 | |||
338 | /* Return the acknowledgement */ | ||
339 | HvCallEvent_ackLpEvent(event); | ||
340 | } | ||
341 | |||
342 | /* | ||
343 | * Handle a close charLpEvent. This should ONLY be an Interrupt because the | ||
344 | * virtual console should never actually issue a close event to the hypervisor | ||
345 | * because the virtual console never goes away. A close event coming from the | ||
346 | * hypervisor simply means that there are no client consoles connected to the | ||
347 | * virtual console. | ||
348 | */ | ||
349 | static void hvc_close_event(struct HvLpEvent *event) | ||
350 | { | ||
351 | unsigned long flags; | ||
352 | struct viocharlpevent *cevent = (struct viocharlpevent *)event; | ||
353 | u8 port = cevent->virtual_device; | ||
354 | |||
355 | if (!hvlpevent_is_int(event)) { | ||
356 | printk(KERN_WARNING | ||
357 | "hvc: got unexpected close acknowledgement\n"); | ||
358 | return; | ||
359 | } | ||
360 | |||
361 | if (port >= VTTY_PORTS) { | ||
362 | printk(KERN_WARNING | ||
363 | "hvc: close message from invalid virtual device.\n"); | ||
364 | return; | ||
365 | } | ||
366 | |||
367 | /* For closes, just mark the console partition invalid */ | ||
368 | spin_lock_irqsave(&consolelock, flags); | ||
369 | |||
370 | if (port_info[port].lp == event->xSourceLp) | ||
371 | port_info[port].lp = HvLpIndexInvalid; | ||
372 | |||
373 | spin_unlock_irqrestore(&consolelock, flags); | ||
374 | } | ||
375 | |||
376 | static void hvc_data_event(struct HvLpEvent *event) | ||
377 | { | ||
378 | unsigned long flags; | ||
379 | struct viocharlpevent *cevent = (struct viocharlpevent *)event; | ||
380 | struct port_info *pi; | ||
381 | int n; | ||
382 | u8 port = cevent->virtual_device; | ||
383 | |||
384 | if (port >= VTTY_PORTS) { | ||
385 | printk(KERN_WARNING "hvc: data on invalid virtual device %d\n", | ||
386 | port); | ||
387 | return; | ||
388 | } | ||
389 | if (cevent->len == 0) | ||
390 | return; | ||
391 | |||
392 | /* | ||
393 | * Change 05/01/2003 - Ryan Arnold: If a partition other than | ||
394 | * the current exclusive partition tries to send us data | ||
395 | * events then just drop them on the floor because we don't | ||
396 | * want his stinking data. He isn't authorized to receive | ||
397 | * data because he wasn't the first one to get the console, | ||
398 | * therefore he shouldn't be allowed to send data either. | ||
399 | * This will work without an iSeries fix. | ||
400 | */ | ||
401 | pi = &port_info[port]; | ||
402 | if (pi->lp != event->xSourceLp) | ||
403 | return; | ||
404 | |||
405 | spin_lock_irqsave(&consolelock, flags); | ||
406 | |||
407 | n = IN_BUF_SIZE - pi->in_end; | ||
408 | if (n > cevent->len) | ||
409 | n = cevent->len; | ||
410 | if (n > 0) { | ||
411 | memcpy(&pi->in_buf[pi->in_end], cevent->data, n); | ||
412 | pi->in_end += n; | ||
413 | } | ||
414 | spin_unlock_irqrestore(&consolelock, flags); | ||
415 | if (n == 0) | ||
416 | printk(KERN_WARNING "hvc: input buffer overflow\n"); | ||
417 | } | ||
418 | |||
419 | static void hvc_ack_event(struct HvLpEvent *event) | ||
420 | { | ||
421 | struct viocharlpevent *cevent = (struct viocharlpevent *)event; | ||
422 | unsigned long flags; | ||
423 | u8 port = cevent->virtual_device; | ||
424 | |||
425 | if (port >= VTTY_PORTS) { | ||
426 | printk(KERN_WARNING "hvc: data on invalid virtual device\n"); | ||
427 | return; | ||
428 | } | ||
429 | |||
430 | spin_lock_irqsave(&consolelock, flags); | ||
431 | port_info[port].ack = event->xCorrelationToken; | ||
432 | spin_unlock_irqrestore(&consolelock, flags); | ||
433 | } | ||
434 | |||
435 | static void hvc_config_event(struct HvLpEvent *event) | ||
436 | { | ||
437 | struct viocharlpevent *cevent = (struct viocharlpevent *)event; | ||
438 | |||
439 | if (cevent->data[0] == 0x01) | ||
440 | printk(KERN_INFO "hvc: window resized to %d: %d: %d: %d\n", | ||
441 | cevent->data[1], cevent->data[2], | ||
442 | cevent->data[3], cevent->data[4]); | ||
443 | else | ||
444 | printk(KERN_WARNING "hvc: unknown config event\n"); | ||
445 | } | ||
446 | |||
447 | static void hvc_handle_event(struct HvLpEvent *event) | ||
448 | { | ||
449 | int charminor; | ||
450 | |||
451 | if (event == NULL) | ||
452 | return; | ||
453 | |||
454 | charminor = event->xSubtype & VIOMINOR_SUBTYPE_MASK; | ||
455 | switch (charminor) { | ||
456 | case viocharopen: | ||
457 | hvc_open_event(event); | ||
458 | break; | ||
459 | case viocharclose: | ||
460 | hvc_close_event(event); | ||
461 | break; | ||
462 | case viochardata: | ||
463 | hvc_data_event(event); | ||
464 | break; | ||
465 | case viocharack: | ||
466 | hvc_ack_event(event); | ||
467 | break; | ||
468 | case viocharconfig: | ||
469 | hvc_config_event(event); | ||
470 | break; | ||
471 | default: | ||
472 | if (hvlpevent_is_int(event) && hvlpevent_need_ack(event)) { | ||
473 | event->xRc = HvLpEvent_Rc_InvalidSubtype; | ||
474 | HvCallEvent_ackLpEvent(event); | ||
475 | } | ||
476 | } | ||
477 | } | ||
478 | |||
479 | static int __init send_open(HvLpIndex remoteLp, void *sem) | ||
480 | { | ||
481 | return HvCallEvent_signalLpEventFast(remoteLp, | ||
482 | HvLpEvent_Type_VirtualIo, | ||
483 | viomajorsubtype_chario | viocharopen, | ||
484 | HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck, | ||
485 | viopath_sourceinst(remoteLp), | ||
486 | viopath_targetinst(remoteLp), | ||
487 | (u64)(unsigned long)sem, VIOVERSION << 16, | ||
488 | 0, 0, 0, 0); | ||
489 | } | ||
490 | |||
491 | static int __init hvc_vio_init(void) | ||
492 | { | ||
493 | atomic_t wait_flag; | ||
494 | int rc; | ||
495 | |||
496 | if (!firmware_has_feature(FW_FEATURE_ISERIES)) | ||
497 | return -EIO; | ||
498 | |||
499 | /* +2 for fudge */ | ||
500 | rc = viopath_open(HvLpConfig_getPrimaryLpIndex(), | ||
501 | viomajorsubtype_chario, VIOCHAR_WINDOW + 2); | ||
502 | if (rc) | ||
503 | printk(KERN_WARNING "hvc: error opening to primary %d\n", rc); | ||
504 | |||
505 | if (viopath_hostLp == HvLpIndexInvalid) | ||
506 | vio_set_hostlp(); | ||
507 | |||
508 | /* | ||
509 | * And if the primary is not the same as the hosting LP, open to the | ||
510 | * hosting lp | ||
511 | */ | ||
512 | if ((viopath_hostLp != HvLpIndexInvalid) && | ||
513 | (viopath_hostLp != HvLpConfig_getPrimaryLpIndex())) { | ||
514 | printk(KERN_INFO "hvc: open path to hosting (%d)\n", | ||
515 | viopath_hostLp); | ||
516 | rc = viopath_open(viopath_hostLp, viomajorsubtype_chario, | ||
517 | VIOCHAR_WINDOW + 2); /* +2 for fudge */ | ||
518 | if (rc) | ||
519 | printk(KERN_WARNING | ||
520 | "error opening to partition %d: %d\n", | ||
521 | viopath_hostLp, rc); | ||
522 | } | ||
523 | |||
524 | if (vio_setHandler(viomajorsubtype_chario, hvc_handle_event) < 0) | ||
525 | printk(KERN_WARNING | ||
526 | "hvc: error seting handler for console events!\n"); | ||
527 | |||
528 | /* | ||
529 | * First, try to open the console to the hosting lp. | ||
530 | * Wait on a semaphore for the response. | ||
531 | */ | ||
532 | atomic_set(&wait_flag, 0); | ||
533 | if ((viopath_isactive(viopath_hostLp)) && | ||
534 | (send_open(viopath_hostLp, &wait_flag) == 0)) { | ||
535 | printk(KERN_INFO "hvc: hosting partition %d\n", viopath_hostLp); | ||
536 | while (atomic_read(&wait_flag) == 0) | ||
537 | mb(); | ||
538 | atomic_set(&wait_flag, 0); | ||
539 | } | ||
540 | |||
541 | /* | ||
542 | * If we don't have an active console, try the primary | ||
543 | */ | ||
544 | if ((!viopath_isactive(port_info[0].lp)) && | ||
545 | (viopath_isactive(HvLpConfig_getPrimaryLpIndex())) && | ||
546 | (send_open(HvLpConfig_getPrimaryLpIndex(), &wait_flag) == 0)) { | ||
547 | printk(KERN_INFO "hvc: opening console to primary partition\n"); | ||
548 | while (atomic_read(&wait_flag) == 0) | ||
549 | mb(); | ||
550 | } | ||
551 | |||
552 | /* Register as a vio device to receive callbacks */ | ||
553 | rc = vio_register_driver(&hvc_vio_driver); | ||
554 | |||
555 | return rc; | ||
556 | } | ||
557 | module_init(hvc_vio_init); /* after drivers/char/hvc_console.c */ | ||
558 | |||
559 | static void __exit hvc_vio_exit(void) | ||
560 | { | ||
561 | vio_unregister_driver(&hvc_vio_driver); | ||
562 | } | ||
563 | module_exit(hvc_vio_exit); | ||
564 | |||
565 | /* the device tree order defines our numbering */ | ||
566 | static int __init hvc_find_vtys(void) | ||
567 | { | ||
568 | struct device_node *vty; | ||
569 | int num_found = 0; | ||
570 | |||
571 | for (vty = of_find_node_by_name(NULL, "vty"); vty != NULL; | ||
572 | vty = of_find_node_by_name(vty, "vty")) { | ||
573 | const uint32_t *vtermno; | ||
574 | |||
575 | /* We have statically defined space for only a certain number | ||
576 | * of console adapters. | ||
577 | */ | ||
578 | if ((num_found >= MAX_NR_HVC_CONSOLES) || | ||
579 | (num_found >= VTTY_PORTS)) { | ||
580 | of_node_put(vty); | ||
581 | break; | ||
582 | } | ||
583 | |||
584 | vtermno = of_get_property(vty, "reg", NULL); | ||
585 | if (!vtermno) | ||
586 | continue; | ||
587 | |||
588 | if (!of_device_is_compatible(vty, "IBM,iSeries-vty")) | ||
589 | continue; | ||
590 | |||
591 | if (num_found == 0) | ||
592 | add_preferred_console("hvc", 0, NULL); | ||
593 | hvc_instantiate(*vtermno, num_found, &hvc_get_put_ops); | ||
594 | ++num_found; | ||
595 | } | ||
596 | |||
597 | return num_found; | ||
598 | } | ||
599 | console_initcall(hvc_find_vtys); | ||
diff --git a/drivers/tty/hvc/hvc_udbg.c b/drivers/tty/hvc/hvc_udbg.c index 4c9b13e7748c..72228276fe31 100644 --- a/drivers/tty/hvc/hvc_udbg.c +++ b/drivers/tty/hvc/hvc_udbg.c | |||
@@ -36,7 +36,7 @@ static int hvc_udbg_put(uint32_t vtermno, const char *buf, int count) | |||
36 | { | 36 | { |
37 | int i; | 37 | int i; |
38 | 38 | ||
39 | for (i = 0; i < count; i++) | 39 | for (i = 0; i < count && udbg_putc; i++) |
40 | udbg_putc(buf[i]); | 40 | udbg_putc(buf[i]); |
41 | 41 | ||
42 | return i; | 42 | return i; |
@@ -67,6 +67,9 @@ static int __init hvc_udbg_init(void) | |||
67 | { | 67 | { |
68 | struct hvc_struct *hp; | 68 | struct hvc_struct *hp; |
69 | 69 | ||
70 | if (!udbg_putc) | ||
71 | return -ENODEV; | ||
72 | |||
70 | BUG_ON(hvc_udbg_dev); | 73 | BUG_ON(hvc_udbg_dev); |
71 | 74 | ||
72 | hp = hvc_alloc(0, 0, &hvc_udbg_ops, 16); | 75 | hp = hvc_alloc(0, 0, &hvc_udbg_ops, 16); |
@@ -88,6 +91,9 @@ module_exit(hvc_udbg_exit); | |||
88 | 91 | ||
89 | static int __init hvc_udbg_console_init(void) | 92 | static int __init hvc_udbg_console_init(void) |
90 | { | 93 | { |
94 | if (!udbg_putc) | ||
95 | return -ENODEV; | ||
96 | |||
91 | hvc_instantiate(0, 0, &hvc_udbg_ops); | 97 | hvc_instantiate(0, 0, &hvc_udbg_ops); |
92 | add_preferred_console("hvc", 0, NULL); | 98 | add_preferred_console("hvc", 0, NULL); |
93 | 99 | ||
diff --git a/drivers/tty/hvc/hvc_vio.c b/drivers/tty/hvc/hvc_vio.c index fc3c3ad6c072..3a0d53d6368f 100644 --- a/drivers/tty/hvc/hvc_vio.c +++ b/drivers/tty/hvc/hvc_vio.c | |||
@@ -46,7 +46,6 @@ | |||
46 | #include <asm/hvconsole.h> | 46 | #include <asm/hvconsole.h> |
47 | #include <asm/vio.h> | 47 | #include <asm/vio.h> |
48 | #include <asm/prom.h> | 48 | #include <asm/prom.h> |
49 | #include <asm/firmware.h> | ||
50 | #include <asm/hvsi.h> | 49 | #include <asm/hvsi.h> |
51 | #include <asm/udbg.h> | 50 | #include <asm/udbg.h> |
52 | 51 | ||
@@ -322,9 +321,6 @@ static int __init hvc_vio_init(void) | |||
322 | { | 321 | { |
323 | int rc; | 322 | int rc; |
324 | 323 | ||
325 | if (firmware_has_feature(FW_FEATURE_ISERIES)) | ||
326 | return -EIO; | ||
327 | |||
328 | /* Register as a vio device to receive callbacks */ | 324 | /* Register as a vio device to receive callbacks */ |
329 | rc = vio_register_driver(&hvc_vio_driver); | 325 | rc = vio_register_driver(&hvc_vio_driver); |
330 | 326 | ||
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 76e7764488e6..665beb68f670 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig | |||
@@ -853,7 +853,7 @@ config SERIAL_MPC52xx_CONSOLE_BAUD | |||
853 | 853 | ||
854 | config SERIAL_ICOM | 854 | config SERIAL_ICOM |
855 | tristate "IBM Multiport Serial Adapter" | 855 | tristate "IBM Multiport Serial Adapter" |
856 | depends on PCI && (PPC_ISERIES || PPC_PSERIES) | 856 | depends on PCI && PPC_PSERIES |
857 | select SERIAL_CORE | 857 | select SERIAL_CORE |
858 | select FW_LOADER | 858 | select FW_LOADER |
859 | help | 859 | help |
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index df9e8f0e327d..7e9e8f4d8f0c 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig | |||
@@ -1039,7 +1039,7 @@ config LANTIQ_WDT | |||
1039 | 1039 | ||
1040 | config GEF_WDT | 1040 | config GEF_WDT |
1041 | tristate "GE Watchdog Timer" | 1041 | tristate "GE Watchdog Timer" |
1042 | depends on GEF_SBC610 || GEF_SBC310 || GEF_PPC9A | 1042 | depends on GE_FPGA |
1043 | ---help--- | 1043 | ---help--- |
1044 | Watchdog timer found in a number of GE single board computers. | 1044 | Watchdog timer found in a number of GE single board computers. |
1045 | 1045 | ||
diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c index b0f450a2bb7c..0d5071d29985 100644 --- a/fs/proc/vmcore.c +++ b/fs/proc/vmcore.c | |||
@@ -700,3 +700,26 @@ static int __init vmcore_init(void) | |||
700 | return 0; | 700 | return 0; |
701 | } | 701 | } |
702 | module_init(vmcore_init) | 702 | module_init(vmcore_init) |
703 | |||
704 | /* Cleanup function for vmcore module. */ | ||
705 | void vmcore_cleanup(void) | ||
706 | { | ||
707 | struct list_head *pos, *next; | ||
708 | |||
709 | if (proc_vmcore) { | ||
710 | remove_proc_entry(proc_vmcore->name, proc_vmcore->parent); | ||
711 | proc_vmcore = NULL; | ||
712 | } | ||
713 | |||
714 | /* clear the vmcore list. */ | ||
715 | list_for_each_safe(pos, next, &vmcore_list) { | ||
716 | struct vmcore *m; | ||
717 | |||
718 | m = list_entry(pos, struct vmcore, list); | ||
719 | list_del(&m->list); | ||
720 | kfree(m); | ||
721 | } | ||
722 | kfree(elfcorebuf); | ||
723 | elfcorebuf = NULL; | ||
724 | } | ||
725 | EXPORT_SYMBOL_GPL(vmcore_cleanup); | ||
diff --git a/include/linux/atomic.h b/include/linux/atomic.h index 42b77b5446d2..70cfcb2d63c4 100644 --- a/include/linux/atomic.h +++ b/include/linux/atomic.h | |||
@@ -24,7 +24,9 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u) | |||
24 | * Atomically increments @v by 1, so long as @v is non-zero. | 24 | * Atomically increments @v by 1, so long as @v is non-zero. |
25 | * Returns non-zero if @v was non-zero, and zero otherwise. | 25 | * Returns non-zero if @v was non-zero, and zero otherwise. |
26 | */ | 26 | */ |
27 | #ifndef atomic_inc_not_zero | ||
27 | #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) | 28 | #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) |
29 | #endif | ||
28 | 30 | ||
29 | /** | 31 | /** |
30 | * atomic_inc_not_zero_hint - increment if not null | 32 | * atomic_inc_not_zero_hint - increment if not null |
diff --git a/include/linux/device.h b/include/linux/device.h index 7c46bc32fcbf..5ad17cccdd71 100644 --- a/include/linux/device.h +++ b/include/linux/device.h | |||
@@ -262,10 +262,6 @@ extern int __must_check driver_create_file(struct device_driver *driver, | |||
262 | extern void driver_remove_file(struct device_driver *driver, | 262 | extern void driver_remove_file(struct device_driver *driver, |
263 | const struct driver_attribute *attr); | 263 | const struct driver_attribute *attr); |
264 | 264 | ||
265 | extern int __must_check driver_add_kobj(struct device_driver *drv, | ||
266 | struct kobject *kobj, | ||
267 | const char *fmt, ...); | ||
268 | |||
269 | extern int __must_check driver_for_each_device(struct device_driver *drv, | 265 | extern int __must_check driver_for_each_device(struct device_driver *drv, |
270 | struct device *start, | 266 | struct device *start, |
271 | void *data, | 267 | void *data, |
diff --git a/include/linux/of.h b/include/linux/of.h index f02d8b2f799d..d46a18ffbebb 100644 --- a/include/linux/of.h +++ b/include/linux/of.h | |||
@@ -58,6 +58,9 @@ struct device_node { | |||
58 | struct kref kref; | 58 | struct kref kref; |
59 | unsigned long _flags; | 59 | unsigned long _flags; |
60 | void *data; | 60 | void *data; |
61 | #if defined(CONFIG_EEH) | ||
62 | struct eeh_dev *edev; | ||
63 | #endif | ||
61 | #if defined(CONFIG_SPARC) | 64 | #if defined(CONFIG_SPARC) |
62 | char *path_component_name; | 65 | char *path_component_name; |
63 | unsigned int unique_id; | 66 | unsigned int unique_id; |
@@ -72,6 +75,13 @@ struct of_phandle_args { | |||
72 | uint32_t args[MAX_PHANDLE_ARGS]; | 75 | uint32_t args[MAX_PHANDLE_ARGS]; |
73 | }; | 76 | }; |
74 | 77 | ||
78 | #if defined(CONFIG_EEH) | ||
79 | static inline struct eeh_dev *of_node_to_eeh_dev(struct device_node *dn) | ||
80 | { | ||
81 | return dn->edev; | ||
82 | } | ||
83 | #endif | ||
84 | |||
75 | #ifdef CONFIG_OF_DYNAMIC | 85 | #ifdef CONFIG_OF_DYNAMIC |
76 | extern struct device_node *of_node_get(struct device_node *node); | 86 | extern struct device_node *of_node_get(struct device_node *node); |
77 | extern void of_node_put(struct device_node *node); | 87 | extern void of_node_put(struct device_node *node); |
diff --git a/include/linux/pci.h b/include/linux/pci.h index b843fe79583b..27bf521bcebd 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h | |||
@@ -1660,6 +1660,13 @@ static inline void pci_set_bus_of_node(struct pci_bus *bus) { } | |||
1660 | static inline void pci_release_bus_of_node(struct pci_bus *bus) { } | 1660 | static inline void pci_release_bus_of_node(struct pci_bus *bus) { } |
1661 | #endif /* CONFIG_OF */ | 1661 | #endif /* CONFIG_OF */ |
1662 | 1662 | ||
1663 | #ifdef CONFIG_EEH | ||
1664 | static inline struct eeh_dev *pci_dev_to_eeh_dev(struct pci_dev *pdev) | ||
1665 | { | ||
1666 | return pdev->dev.archdata.edev; | ||
1667 | } | ||
1668 | #endif | ||
1669 | |||
1663 | /** | 1670 | /** |
1664 | * pci_find_upstream_pcie_bridge - find upstream PCIe-to-PCI bridge of a device | 1671 | * pci_find_upstream_pcie_bridge - find upstream PCIe-to-PCI bridge of a device |
1665 | * @pdev: the PCI device | 1672 | * @pdev: the PCI device |
diff --git a/init/do_mounts_rd.c b/init/do_mounts_rd.c index 887629e24c54..01f1306aa26e 100644 --- a/init/do_mounts_rd.c +++ b/init/do_mounts_rd.c | |||
@@ -178,7 +178,7 @@ int __init rd_load_image(char *from) | |||
178 | char *buf = NULL; | 178 | char *buf = NULL; |
179 | unsigned short rotate = 0; | 179 | unsigned short rotate = 0; |
180 | decompress_fn decompressor = NULL; | 180 | decompress_fn decompressor = NULL; |
181 | #if !defined(CONFIG_S390) && !defined(CONFIG_PPC_ISERIES) | 181 | #if !defined(CONFIG_S390) |
182 | char rotator[4] = { '|' , '/' , '-' , '\\' }; | 182 | char rotator[4] = { '|' , '/' , '-' , '\\' }; |
183 | #endif | 183 | #endif |
184 | 184 | ||
@@ -264,7 +264,7 @@ int __init rd_load_image(char *from) | |||
264 | } | 264 | } |
265 | sys_read(in_fd, buf, BLOCK_SIZE); | 265 | sys_read(in_fd, buf, BLOCK_SIZE); |
266 | sys_write(out_fd, buf, BLOCK_SIZE); | 266 | sys_write(out_fd, buf, BLOCK_SIZE); |
267 | #if !defined(CONFIG_S390) && !defined(CONFIG_PPC_ISERIES) | 267 | #if !defined(CONFIG_S390) |
268 | if (!(i % 16)) { | 268 | if (!(i % 16)) { |
269 | printk("%c\b", rotator[rotate & 0x3]); | 269 | printk("%c\b", rotator[rotate & 0x3]); |
270 | rotate++; | 270 | rotate++; |