aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/boot/dts/hcu4.dts168
-rw-r--r--arch/powerpc/boot/dts/mpc8548cds.dts567
-rw-r--r--arch/powerpc/boot/dts/p1010si.dtsi376
-rw-r--r--arch/powerpc/boot/dts/p1020rdb_camp_core0.dts213
-rw-r--r--arch/powerpc/boot/dts/p1020rdb_camp_core1.dts148
-rw-r--r--arch/powerpc/boot/dts/p1020si.dtsi377
-rw-r--r--arch/powerpc/boot/dts/p1022ds.dts657
-rw-r--r--arch/powerpc/boot/dts/p2020rdb_camp_core0.dts204
-rw-r--r--arch/powerpc/boot/dts/p2020rdb_camp_core1.dts228
-rw-r--r--arch/powerpc/boot/dts/p2020si.dtsi382
-rw-r--r--arch/powerpc/boot/dts/p2040rdb.dts166
-rw-r--r--arch/powerpc/boot/dts/p2040si.dtsi623
-rw-r--r--arch/powerpc/boot/dts/p3041si.dtsi660
-rw-r--r--arch/powerpc/boot/dts/p4080si.dtsi661
-rw-r--r--arch/powerpc/boot/dts/p5020si.dtsi652
-rw-r--r--arch/powerpc/boot/dts/sbc8560.dts406
-rw-r--r--arch/powerpc/boot/flatdevtree_env.h27
-rw-r--r--arch/powerpc/configs/40x/hcu4_defconfig80
-rw-r--r--arch/powerpc/configs/85xx/sbc8560_defconfig65
-rw-r--r--arch/powerpc/configs/iseries_defconfig236
-rw-r--r--arch/powerpc/include/asm/abs_addr.h75
-rw-r--r--arch/powerpc/include/asm/auxvec.h19
-rw-r--r--arch/powerpc/include/asm/bitsperlong.h12
-rw-r--r--arch/powerpc/include/asm/byteorder.h12
-rw-r--r--arch/powerpc/include/asm/errno.h11
-rw-r--r--arch/powerpc/include/asm/fcntl.h11
-rw-r--r--arch/powerpc/include/asm/ioctl.h13
-rw-r--r--arch/powerpc/include/asm/ioctls.h116
-rw-r--r--arch/powerpc/include/asm/ipcbuf.h34
-rw-r--r--arch/powerpc/include/asm/iseries/alpaca.h31
-rw-r--r--arch/powerpc/include/asm/iseries/hv_call.h111
-rw-r--r--arch/powerpc/include/asm/iseries/hv_call_event.h201
-rw-r--r--arch/powerpc/include/asm/iseries/hv_call_sc.h50
-rw-r--r--arch/powerpc/include/asm/iseries/hv_call_xm.h61
-rw-r--r--arch/powerpc/include/asm/iseries/hv_lp_config.h128
-rw-r--r--arch/powerpc/include/asm/iseries/hv_lp_event.h162
-rw-r--r--arch/powerpc/include/asm/iseries/hv_types.h112
-rw-r--r--arch/powerpc/include/asm/iseries/iommu.h37
-rw-r--r--arch/powerpc/include/asm/iseries/it_lp_queue.h78
-rw-r--r--arch/powerpc/include/asm/iseries/lpar_map.h85
-rw-r--r--arch/powerpc/include/asm/iseries/mf.h51
-rw-r--r--arch/powerpc/include/asm/iseries/vio.h265
-rw-r--r--arch/powerpc/include/asm/kvm.h290
-rw-r--r--arch/powerpc/include/asm/kvm_e500.h84
-rw-r--r--arch/powerpc/include/asm/linkage.h6
-rw-r--r--arch/powerpc/include/asm/memblock.h8
-rw-r--r--arch/powerpc/include/asm/msgbuf.h33
-rw-r--r--arch/powerpc/include/asm/pSeries_reconfig.h35
-rw-r--r--arch/powerpc/include/asm/param.h1
-rw-r--r--arch/powerpc/include/asm/phyp_dump.h47
-rw-r--r--arch/powerpc/include/asm/poll.h1
-rw-r--r--arch/powerpc/include/asm/posix_types.h128
-rw-r--r--arch/powerpc/include/asm/ps3fb.h45
-rw-r--r--arch/powerpc/include/asm/resource.h1
-rw-r--r--arch/powerpc/include/asm/rwsem.h132
-rw-r--r--arch/powerpc/include/asm/seccomp.h16
-rw-r--r--arch/powerpc/include/asm/sembuf.h36
-rw-r--r--arch/powerpc/include/asm/shmbuf.h59
-rw-r--r--arch/powerpc/include/asm/sigcontext.h87
-rw-r--r--arch/powerpc/include/asm/siginfo.h21
-rw-r--r--arch/powerpc/include/asm/socket.h72
-rw-r--r--arch/powerpc/include/asm/sockios.h20
-rw-r--r--arch/powerpc/include/asm/stat.h81
-rw-r--r--arch/powerpc/include/asm/statfs.h6
-rw-r--r--arch/powerpc/include/asm/system.h545
-rw-r--r--arch/powerpc/include/asm/termbits.h210
-rw-r--r--arch/powerpc/include/asm/ucontext.h40
-rw-r--r--arch/powerpc/kernel/cpu_setup_power7.S95
-rw-r--r--arch/powerpc/kernel/e500-pmu.c134
-rw-r--r--arch/powerpc/kernel/init_task.c29
-rw-r--r--arch/powerpc/kernel/mpc7450-pmu.c422
-rw-r--r--arch/powerpc/kernel/perf_callchain.c492
-rw-r--r--arch/powerpc/kernel/perf_event.c1432
-rw-r--r--arch/powerpc/kernel/perf_event_fsl_emb.c688
-rw-r--r--arch/powerpc/kernel/power4-pmu.c621
-rw-r--r--arch/powerpc/kernel/power5+-pmu.c690
-rw-r--r--arch/powerpc/kernel/power5-pmu.c629
-rw-r--r--arch/powerpc/kernel/power6-pmu.c552
-rw-r--r--arch/powerpc/kernel/power7-pmu.c377
-rw-r--r--arch/powerpc/kernel/ppc970-pmu.c502
-rw-r--r--arch/powerpc/kvm/e500_tlb.h196
-rw-r--r--arch/powerpc/platforms/40x/hcu4.c61
-rw-r--r--arch/powerpc/platforms/85xx/p2040_rdb.c88
-rw-r--r--arch/powerpc/platforms/85xx/sbc8560.c318
-rw-r--r--arch/powerpc/platforms/86xx/gef_gpio.c170
-rw-r--r--arch/powerpc/platforms/86xx/gef_pic.c252
-rw-r--r--arch/powerpc/platforms/86xx/gef_pic.h11
-rw-r--r--arch/powerpc/platforms/iseries/Kconfig38
-rw-r--r--arch/powerpc/platforms/iseries/Makefile9
-rw-r--r--arch/powerpc/platforms/iseries/call_hpt.h102
-rw-r--r--arch/powerpc/platforms/iseries/call_pci.h309
-rw-r--r--arch/powerpc/platforms/iseries/call_sm.h37
-rw-r--r--arch/powerpc/platforms/iseries/dt.c643
-rw-r--r--arch/powerpc/platforms/iseries/exception.S311
-rw-r--r--arch/powerpc/platforms/iseries/exception.h58
-rw-r--r--arch/powerpc/platforms/iseries/htab.c257
-rw-r--r--arch/powerpc/platforms/iseries/hvcall.S94
-rw-r--r--arch/powerpc/platforms/iseries/hvlog.c35
-rw-r--r--arch/powerpc/platforms/iseries/hvlpconfig.c39
-rw-r--r--arch/powerpc/platforms/iseries/iommu.c260
-rw-r--r--arch/powerpc/platforms/iseries/ipl_parms.h68
-rw-r--r--arch/powerpc/platforms/iseries/irq.c400
-rw-r--r--arch/powerpc/platforms/iseries/irq.h13
-rw-r--r--arch/powerpc/platforms/iseries/it_exp_vpd_panel.h51
-rw-r--r--arch/powerpc/platforms/iseries/it_lp_naca.h80
-rw-r--r--arch/powerpc/platforms/iseries/ksyms.c21
-rw-r--r--arch/powerpc/platforms/iseries/lpardata.c319
-rw-r--r--arch/powerpc/platforms/iseries/lpevents.c341
-rw-r--r--arch/powerpc/platforms/iseries/main_store.h165
-rw-r--r--arch/powerpc/platforms/iseries/mf.c1274
-rw-r--r--arch/powerpc/platforms/iseries/misc.S26
-rw-r--r--arch/powerpc/platforms/iseries/naca.h24
-rw-r--r--arch/powerpc/platforms/iseries/pci.c920
-rw-r--r--arch/powerpc/platforms/iseries/pci.h58
-rw-r--r--arch/powerpc/platforms/iseries/proc.c120
-rw-r--r--arch/powerpc/platforms/iseries/processor_vpd.h85
-rw-r--r--arch/powerpc/platforms/iseries/release_data.h63
-rw-r--r--arch/powerpc/platforms/iseries/setup.c717
-rw-r--r--arch/powerpc/platforms/iseries/setup.h27
-rw-r--r--arch/powerpc/platforms/iseries/smp.c89
-rw-r--r--arch/powerpc/platforms/iseries/spcomm_area.h34
-rw-r--r--arch/powerpc/platforms/iseries/vio.c556
-rw-r--r--arch/powerpc/platforms/iseries/viopath.c677
-rw-r--r--arch/powerpc/platforms/iseries/vpd_areas.h88
-rw-r--r--arch/powerpc/platforms/pseries/phyp_dump.c513
-rw-r--r--arch/powerpc/sysdev/mpc8xxx_gpio.c395
-rw-r--r--arch/powerpc/xmon/start.c34
127 files changed, 27684 insertions, 0 deletions
diff --git a/arch/powerpc/boot/dts/hcu4.dts b/arch/powerpc/boot/dts/hcu4.dts
new file mode 100644
index 00000000000..7988598da4c
--- /dev/null
+++ b/arch/powerpc/boot/dts/hcu4.dts
@@ -0,0 +1,168 @@
1/*
2* Device Tree Source for Netstal Maschinen HCU4
3* based on the IBM Walnut
4*
5* Copyright 2008
6* Niklaus Giger <niklaus.giger@member.fsf.org>
7*
8* Copyright 2007 IBM Corp.
9* Josh Boyer <jwboyer@linux.vnet.ibm.com>
10*
11* This file is licensed under the terms of the GNU General Public
12* License version 2. This program is licensed "as is" without
13* any warranty of any kind, whether express or implied.
14*/
15
16/dts-v1/;
17
18/ {
19 #address-cells = <0x1>;
20 #size-cells = <0x1>;
21 model = "netstal,hcu4";
22 compatible = "netstal,hcu4";
23 dcr-parent = <0x1>;
24
25 aliases {
26 ethernet0 = "/plb/opb/ethernet@ef600800";
27 serial0 = "/plb/opb/serial@ef600300";
28 };
29
30 cpus {
31 #address-cells = <0x1>;
32 #size-cells = <0x0>;
33
34 cpu@0 {
35 device_type = "cpu";
36 model = "PowerPC,405GPr";
37 reg = <0x0>;
38 clock-frequency = <0>; /* Filled in by U-Boot */
39 timebase-frequency = <0x0>; /* Filled in by U-Boot */
40 i-cache-line-size = <0x20>;
41 d-cache-line-size = <0x20>;
42 i-cache-size = <0x4000>;
43 d-cache-size = <0x4000>;
44 dcr-controller;
45 dcr-access-method = "native";
46 linux,phandle = <0x1>;
47 };
48 };
49
50 memory {
51 device_type = "memory";
52 reg = <0x0 0x0>; /* Filled in by U-Boot */
53 };
54
55 UIC0: interrupt-controller {
56 compatible = "ibm,uic";
57 interrupt-controller;
58 cell-index = <0x0>;
59 dcr-reg = <0xc0 0x9>;
60 #address-cells = <0x0>;
61 #size-cells = <0x0>;
62 #interrupt-cells = <0x2>;
63 linux,phandle = <0x2>;
64 };
65
66 plb {
67 compatible = "ibm,plb3";
68 #address-cells = <0x1>;
69 #size-cells = <0x1>;
70 ranges;
71 clock-frequency = <0x0>; /* Filled in by U-Boot */
72
73 SDRAM0: memory-controller {
74 compatible = "ibm,sdram-405gp";
75 dcr-reg = <0x10 0x2>;
76 };
77
78 MAL: mcmal {
79 compatible = "ibm,mcmal-405gp", "ibm,mcmal";
80 dcr-reg = <0x180 0x62>;
81 num-tx-chans = <0x1>;
82 num-rx-chans = <0x1>;
83 interrupt-parent = <0x2>;
84 interrupts = <0xb 0x4 0xc 0x4 0xa 0x4 0xd 0x4 0xe 0x4>;
85 linux,phandle = <0x3>;
86 };
87
88 POB0: opb {
89 compatible = "ibm,opb-405gp", "ibm,opb";
90 #address-cells = <0x1>;
91 #size-cells = <0x1>;
92 ranges = <0xef600000 0xef600000 0xa00000>;
93 dcr-reg = <0xa0 0x5>;
94 clock-frequency = <0x0>; /* Filled in by U-Boot */
95
96 UART0: serial@ef600300 {
97 device_type = "serial";
98 compatible = "ns16550";
99 reg = <0xef600300 0x8>;
100 virtual-reg = <0xef600300>;
101 clock-frequency = <0x0>;/* Filled in by U-Boot */
102 current-speed = <0>; /* Filled in by U-Boot */
103 interrupt-parent = <0x2>;
104 interrupts = <0x0 0x4>;
105 };
106
107 IIC: i2c@ef600500 {
108 compatible = "ibm,iic-405gp", "ibm,iic";
109 reg = <0xef600500 0x11>;
110 interrupt-parent = <0x2>;
111 interrupts = <0x2 0x4>;
112 };
113
114 GPIO: gpio@ef600700 {
115 compatible = "ibm,gpio-405gp";
116 reg = <0xef600700 0x20>;
117 };
118
119 EMAC: ethernet@ef600800 {
120 device_type = "network";
121 compatible = "ibm,emac-405gp", "ibm,emac";
122 interrupt-parent = <0x2>;
123 interrupts = <0xf 0x4 0x9 0x4>;
124 local-mac-address = [00 00 00 00 00 00];
125 reg = <0xef600800 0x70>;
126 mal-device = <0x3>;
127 mal-tx-channel = <0x0>;
128 mal-rx-channel = <0x0>;
129 cell-index = <0x0>;
130 max-frame-size = <0x5dc>;
131 rx-fifo-size = <0x1000>;
132 tx-fifo-size = <0x800>;
133 phy-mode = "rmii";
134 phy-map = <0x1>;
135 };
136 };
137
138 EBC0: ebc {
139 compatible = "ibm,ebc-405gp", "ibm,ebc";
140 dcr-reg = <0x12 0x2>;
141 #address-cells = <0x2>;
142 #size-cells = <0x1>;
143 clock-frequency = <0x0>; /* Filled in by U-Boot */
144
145 sram@0,0 {
146 reg = <0x0 0x0 0x80000>;
147 };
148
149 flash@0,80000 {
150 compatible = "jedec-flash";
151 bank-width = <0x1>;
152 reg = <0x0 0x80000 0x80000>;
153 #address-cells = <0x1>;
154 #size-cells = <0x1>;
155
156 partition@0 {
157 label = "OpenBIOS";
158 reg = <0x0 0x80000>;
159 read-only;
160 };
161 };
162 };
163 };
164
165 chosen {
166 linux,stdout-path = "/plb/opb/serial@ef600300";
167 };
168};
diff --git a/arch/powerpc/boot/dts/mpc8548cds.dts b/arch/powerpc/boot/dts/mpc8548cds.dts
new file mode 100644
index 00000000000..a17a5572fb7
--- /dev/null
+++ b/arch/powerpc/boot/dts/mpc8548cds.dts
@@ -0,0 +1,567 @@
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/dts-v1/;
13
14/ {
15 model = "MPC8548CDS";
16 compatible = "MPC8548CDS", "MPC85xxCDS";
17 #address-cells = <1>;
18 #size-cells = <1>;
19
20 aliases {
21 ethernet0 = &enet0;
22 ethernet1 = &enet1;
23 ethernet2 = &enet2;
24 ethernet3 = &enet3;
25 serial0 = &serial0;
26 serial1 = &serial1;
27 pci0 = &pci0;
28 pci1 = &pci1;
29 pci2 = &pci2;
30 };
31
32 cpus {
33 #address-cells = <1>;
34 #size-cells = <0>;
35
36 PowerPC,8548@0 {
37 device_type = "cpu";
38 reg = <0x0>;
39 d-cache-line-size = <32>; // 32 bytes
40 i-cache-line-size = <32>; // 32 bytes
41 d-cache-size = <0x8000>; // L1, 32K
42 i-cache-size = <0x8000>; // L1, 32K
43 timebase-frequency = <0>; // 33 MHz, from uboot
44 bus-frequency = <0>; // 166 MHz
45 clock-frequency = <0>; // 825 MHz, from uboot
46 next-level-cache = <&L2>;
47 };
48 };
49
50 memory {
51 device_type = "memory";
52 reg = <0x0 0x8000000>; // 128M at 0x0
53 };
54
55 soc8548@e0000000 {
56 #address-cells = <1>;
57 #size-cells = <1>;
58 device_type = "soc";
59 compatible = "simple-bus";
60 ranges = <0x0 0xe0000000 0x100000>;
61 bus-frequency = <0>;
62
63 ecm-law@0 {
64 compatible = "fsl,ecm-law";
65 reg = <0x0 0x1000>;
66 fsl,num-laws = <10>;
67 };
68
69 ecm@1000 {
70 compatible = "fsl,mpc8548-ecm", "fsl,ecm";
71 reg = <0x1000 0x1000>;
72 interrupts = <17 2>;
73 interrupt-parent = <&mpic>;
74 };
75
76 memory-controller@2000 {
77 compatible = "fsl,mpc8548-memory-controller";
78 reg = <0x2000 0x1000>;
79 interrupt-parent = <&mpic>;
80 interrupts = <18 2>;
81 };
82
83 L2: l2-cache-controller@20000 {
84 compatible = "fsl,mpc8548-l2-cache-controller";
85 reg = <0x20000 0x1000>;
86 cache-line-size = <32>; // 32 bytes
87 cache-size = <0x80000>; // L2, 512K
88 interrupt-parent = <&mpic>;
89 interrupts = <16 2>;
90 };
91
92 i2c@3000 {
93 #address-cells = <1>;
94 #size-cells = <0>;
95 cell-index = <0>;
96 compatible = "fsl-i2c";
97 reg = <0x3000 0x100>;
98 interrupts = <43 2>;
99 interrupt-parent = <&mpic>;
100 dfsrr;
101
102 eeprom@50 {
103 compatible = "atmel,24c64";
104 reg = <0x50>;
105 };
106
107 eeprom@56 {
108 compatible = "atmel,24c64";
109 reg = <0x56>;
110 };
111
112 eeprom@57 {
113 compatible = "atmel,24c64";
114 reg = <0x57>;
115 };
116 };
117
118 i2c@3100 {
119 #address-cells = <1>;
120 #size-cells = <0>;
121 cell-index = <1>;
122 compatible = "fsl-i2c";
123 reg = <0x3100 0x100>;
124 interrupts = <43 2>;
125 interrupt-parent = <&mpic>;
126 dfsrr;
127
128 eeprom@50 {
129 compatible = "atmel,24c64";
130 reg = <0x50>;
131 };
132 };
133
134 dma@21300 {
135 #address-cells = <1>;
136 #size-cells = <1>;
137 compatible = "fsl,mpc8548-dma", "fsl,eloplus-dma";
138 reg = <0x21300 0x4>;
139 ranges = <0x0 0x21100 0x200>;
140 cell-index = <0>;
141 dma-channel@0 {
142 compatible = "fsl,mpc8548-dma-channel",
143 "fsl,eloplus-dma-channel";
144 reg = <0x0 0x80>;
145 cell-index = <0>;
146 interrupt-parent = <&mpic>;
147 interrupts = <20 2>;
148 };
149 dma-channel@80 {
150 compatible = "fsl,mpc8548-dma-channel",
151 "fsl,eloplus-dma-channel";
152 reg = <0x80 0x80>;
153 cell-index = <1>;
154 interrupt-parent = <&mpic>;
155 interrupts = <21 2>;
156 };
157 dma-channel@100 {
158 compatible = "fsl,mpc8548-dma-channel",
159 "fsl,eloplus-dma-channel";
160 reg = <0x100 0x80>;
161 cell-index = <2>;
162 interrupt-parent = <&mpic>;
163 interrupts = <22 2>;
164 };
165 dma-channel@180 {
166 compatible = "fsl,mpc8548-dma-channel",
167 "fsl,eloplus-dma-channel";
168 reg = <0x180 0x80>;
169 cell-index = <3>;
170 interrupt-parent = <&mpic>;
171 interrupts = <23 2>;
172 };
173 };
174
175 enet0: ethernet@24000 {
176 #address-cells = <1>;
177 #size-cells = <1>;
178 cell-index = <0>;
179 device_type = "network";
180 model = "eTSEC";
181 compatible = "gianfar";
182 reg = <0x24000 0x1000>;
183 ranges = <0x0 0x24000 0x1000>;
184 local-mac-address = [ 00 00 00 00 00 00 ];
185 interrupts = <29 2 30 2 34 2>;
186 interrupt-parent = <&mpic>;
187 tbi-handle = <&tbi0>;
188 phy-handle = <&phy0>;
189
190 mdio@520 {
191 #address-cells = <1>;
192 #size-cells = <0>;
193 compatible = "fsl,gianfar-mdio";
194 reg = <0x520 0x20>;
195
196 phy0: ethernet-phy@0 {
197 interrupt-parent = <&mpic>;
198 interrupts = <5 1>;
199 reg = <0x0>;
200 device_type = "ethernet-phy";
201 };
202 phy1: ethernet-phy@1 {
203 interrupt-parent = <&mpic>;
204 interrupts = <5 1>;
205 reg = <0x1>;
206 device_type = "ethernet-phy";
207 };
208 phy2: ethernet-phy@2 {
209 interrupt-parent = <&mpic>;
210 interrupts = <5 1>;
211 reg = <0x2>;
212 device_type = "ethernet-phy";
213 };
214 phy3: ethernet-phy@3 {
215 interrupt-parent = <&mpic>;
216 interrupts = <5 1>;
217 reg = <0x3>;
218 device_type = "ethernet-phy";
219 };
220 tbi0: tbi-phy@11 {
221 reg = <0x11>;
222 device_type = "tbi-phy";
223 };
224 };
225 };
226
227 enet1: ethernet@25000 {
228 #address-cells = <1>;
229 #size-cells = <1>;
230 cell-index = <1>;
231 device_type = "network";
232 model = "eTSEC";
233 compatible = "gianfar";
234 reg = <0x25000 0x1000>;
235 ranges = <0x0 0x25000 0x1000>;
236 local-mac-address = [ 00 00 00 00 00 00 ];
237 interrupts = <35 2 36 2 40 2>;
238 interrupt-parent = <&mpic>;
239 tbi-handle = <&tbi1>;
240 phy-handle = <&phy1>;
241
242 mdio@520 {
243 #address-cells = <1>;
244 #size-cells = <0>;
245 compatible = "fsl,gianfar-tbi";
246 reg = <0x520 0x20>;
247
248 tbi1: tbi-phy@11 {
249 reg = <0x11>;
250 device_type = "tbi-phy";
251 };
252 };
253 };
254
255 enet2: ethernet@26000 {
256 #address-cells = <1>;
257 #size-cells = <1>;
258 cell-index = <2>;
259 device_type = "network";
260 model = "eTSEC";
261 compatible = "gianfar";
262 reg = <0x26000 0x1000>;
263 ranges = <0x0 0x26000 0x1000>;
264 local-mac-address = [ 00 00 00 00 00 00 ];
265 interrupts = <31 2 32 2 33 2>;
266 interrupt-parent = <&mpic>;
267 tbi-handle = <&tbi2>;
268 phy-handle = <&phy2>;
269
270 mdio@520 {
271 #address-cells = <1>;
272 #size-cells = <0>;
273 compatible = "fsl,gianfar-tbi";
274 reg = <0x520 0x20>;
275
276 tbi2: tbi-phy@11 {
277 reg = <0x11>;
278 device_type = "tbi-phy";
279 };
280 };
281 };
282
283 enet3: ethernet@27000 {
284 #address-cells = <1>;
285 #size-cells = <1>;
286 cell-index = <3>;
287 device_type = "network";
288 model = "eTSEC";
289 compatible = "gianfar";
290 reg = <0x27000 0x1000>;
291 ranges = <0x0 0x27000 0x1000>;
292 local-mac-address = [ 00 00 00 00 00 00 ];
293 interrupts = <37 2 38 2 39 2>;
294 interrupt-parent = <&mpic>;
295 tbi-handle = <&tbi3>;
296 phy-handle = <&phy3>;
297
298 mdio@520 {
299 #address-cells = <1>;
300 #size-cells = <0>;
301 compatible = "fsl,gianfar-tbi";
302 reg = <0x520 0x20>;
303
304 tbi3: tbi-phy@11 {
305 reg = <0x11>;
306 device_type = "tbi-phy";
307 };
308 };
309 };
310
311 serial0: serial@4500 {
312 cell-index = <0>;
313 device_type = "serial";
314 compatible = "ns16550";
315 reg = <0x4500 0x100>; // reg base, size
316 clock-frequency = <0>; // should we fill in in uboot?
317 interrupts = <42 2>;
318 interrupt-parent = <&mpic>;
319 };
320
321 serial1: serial@4600 {
322 cell-index = <1>;
323 device_type = "serial";
324 compatible = "ns16550";
325 reg = <0x4600 0x100>; // reg base, size
326 clock-frequency = <0>; // should we fill in in uboot?
327 interrupts = <42 2>;
328 interrupt-parent = <&mpic>;
329 };
330
331 global-utilities@e0000 { //global utilities reg
332 compatible = "fsl,mpc8548-guts";
333 reg = <0xe0000 0x1000>;
334 fsl,has-rstcr;
335 };
336
337 crypto@30000 {
338 compatible = "fsl,sec2.1", "fsl,sec2.0";
339 reg = <0x30000 0x10000>;
340 interrupts = <45 2>;
341 interrupt-parent = <&mpic>;
342 fsl,num-channels = <4>;
343 fsl,channel-fifo-len = <24>;
344 fsl,exec-units-mask = <0xfe>;
345 fsl,descriptor-types-mask = <0x12b0ebf>;
346 };
347
348 mpic: pic@40000 {
349 interrupt-controller;
350 #address-cells = <0>;
351 #interrupt-cells = <2>;
352 reg = <0x40000 0x40000>;
353 compatible = "chrp,open-pic";
354 device_type = "open-pic";
355 };
356 };
357
358 pci0: pci@e0008000 {
359 interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
360 interrupt-map = <
361 /* IDSEL 0x4 (PCIX Slot 2) */
362 0x2000 0x0 0x0 0x1 &mpic 0x0 0x1
363 0x2000 0x0 0x0 0x2 &mpic 0x1 0x1
364 0x2000 0x0 0x0 0x3 &mpic 0x2 0x1
365 0x2000 0x0 0x0 0x4 &mpic 0x3 0x1
366
367 /* IDSEL 0x5 (PCIX Slot 3) */
368 0x2800 0x0 0x0 0x1 &mpic 0x1 0x1
369 0x2800 0x0 0x0 0x2 &mpic 0x2 0x1
370 0x2800 0x0 0x0 0x3 &mpic 0x3 0x1
371 0x2800 0x0 0x0 0x4 &mpic 0x0 0x1
372
373 /* IDSEL 0x6 (PCIX Slot 4) */
374 0x3000 0x0 0x0 0x1 &mpic 0x2 0x1
375 0x3000 0x0 0x0 0x2 &mpic 0x3 0x1
376 0x3000 0x0 0x0 0x3 &mpic 0x0 0x1
377 0x3000 0x0 0x0 0x4 &mpic 0x1 0x1
378
379 /* IDSEL 0x8 (PCIX Slot 5) */
380 0x4000 0x0 0x0 0x1 &mpic 0x0 0x1
381 0x4000 0x0 0x0 0x2 &mpic 0x1 0x1
382 0x4000 0x0 0x0 0x3 &mpic 0x2 0x1
383 0x4000 0x0 0x0 0x4 &mpic 0x3 0x1
384
385 /* IDSEL 0xC (Tsi310 bridge) */
386 0x6000 0x0 0x0 0x1 &mpic 0x0 0x1
387 0x6000 0x0 0x0 0x2 &mpic 0x1 0x1
388 0x6000 0x0 0x0 0x3 &mpic 0x2 0x1
389 0x6000 0x0 0x0 0x4 &mpic 0x3 0x1
390
391 /* IDSEL 0x14 (Slot 2) */
392 0xa000 0x0 0x0 0x1 &mpic 0x0 0x1
393 0xa000 0x0 0x0 0x2 &mpic 0x1 0x1
394 0xa000 0x0 0x0 0x3 &mpic 0x2 0x1
395 0xa000 0x0 0x0 0x4 &mpic 0x3 0x1
396
397 /* IDSEL 0x15 (Slot 3) */
398 0xa800 0x0 0x0 0x1 &mpic 0x1 0x1
399 0xa800 0x0 0x0 0x2 &mpic 0x2 0x1
400 0xa800 0x0 0x0 0x3 &mpic 0x3 0x1
401 0xa800 0x0 0x0 0x4 &mpic 0x0 0x1
402
403 /* IDSEL 0x16 (Slot 4) */
404 0xb000 0x0 0x0 0x1 &mpic 0x2 0x1
405 0xb000 0x0 0x0 0x2 &mpic 0x3 0x1
406 0xb000 0x0 0x0 0x3 &mpic 0x0 0x1
407 0xb000 0x0 0x0 0x4 &mpic 0x1 0x1
408
409 /* IDSEL 0x18 (Slot 5) */
410 0xc000 0x0 0x0 0x1 &mpic 0x0 0x1
411 0xc000 0x0 0x0 0x2 &mpic 0x1 0x1
412 0xc000 0x0 0x0 0x3 &mpic 0x2 0x1
413 0xc000 0x0 0x0 0x4 &mpic 0x3 0x1
414
415 /* IDSEL 0x1C (Tsi310 bridge PCI primary) */
416 0xe000 0x0 0x0 0x1 &mpic 0x0 0x1
417 0xe000 0x0 0x0 0x2 &mpic 0x1 0x1
418 0xe000 0x0 0x0 0x3 &mpic 0x2 0x1
419 0xe000 0x0 0x0 0x4 &mpic 0x3 0x1>;
420
421 interrupt-parent = <&mpic>;
422 interrupts = <24 2>;
423 bus-range = <0 0>;
424 ranges = <0x2000000 0x0 0x80000000 0x80000000 0x0 0x10000000
425 0x1000000 0x0 0x0 0xe2000000 0x0 0x800000>;
426 clock-frequency = <66666666>;
427 #interrupt-cells = <1>;
428 #size-cells = <2>;
429 #address-cells = <3>;
430 reg = <0xe0008000 0x1000>;
431 compatible = "fsl,mpc8540-pcix", "fsl,mpc8540-pci";
432 device_type = "pci";
433
434 pci_bridge@1c {
435 interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
436 interrupt-map = <
437
438 /* IDSEL 0x00 (PrPMC Site) */
439 0000 0x0 0x0 0x1 &mpic 0x0 0x1
440 0000 0x0 0x0 0x2 &mpic 0x1 0x1
441 0000 0x0 0x0 0x3 &mpic 0x2 0x1
442 0000 0x0 0x0 0x4 &mpic 0x3 0x1
443
444 /* IDSEL 0x04 (VIA chip) */
445 0x2000 0x0 0x0 0x1 &mpic 0x0 0x1
446 0x2000 0x0 0x0 0x2 &mpic 0x1 0x1
447 0x2000 0x0 0x0 0x3 &mpic 0x2 0x1
448 0x2000 0x0 0x0 0x4 &mpic 0x3 0x1
449
450 /* IDSEL 0x05 (8139) */
451 0x2800 0x0 0x0 0x1 &mpic 0x1 0x1
452
453 /* IDSEL 0x06 (Slot 6) */
454 0x3000 0x0 0x0 0x1 &mpic 0x2 0x1
455 0x3000 0x0 0x0 0x2 &mpic 0x3 0x1
456 0x3000 0x0 0x0 0x3 &mpic 0x0 0x1
457 0x3000 0x0 0x0 0x4 &mpic 0x1 0x1
458
459 /* IDESL 0x07 (Slot 7) */
460 0x3800 0x0 0x0 0x1 &mpic 0x3 0x1
461 0x3800 0x0 0x0 0x2 &mpic 0x0 0x1
462 0x3800 0x0 0x0 0x3 &mpic 0x1 0x1
463 0x3800 0x0 0x0 0x4 &mpic 0x2 0x1>;
464
465 reg = <0xe000 0x0 0x0 0x0 0x0>;
466 #interrupt-cells = <1>;
467 #size-cells = <2>;
468 #address-cells = <3>;
469 ranges = <0x2000000 0x0 0x80000000
470 0x2000000 0x0 0x80000000
471 0x0 0x20000000
472 0x1000000 0x0 0x0
473 0x1000000 0x0 0x0
474 0x0 0x80000>;
475 clock-frequency = <33333333>;
476
477 isa@4 {
478 device_type = "isa";
479 #interrupt-cells = <2>;
480 #size-cells = <1>;
481 #address-cells = <2>;
482 reg = <0x2000 0x0 0x0 0x0 0x0>;
483 ranges = <0x1 0x0 0x1000000 0x0 0x0 0x1000>;
484 interrupt-parent = <&i8259>;
485
486 i8259: interrupt-controller@20 {
487 interrupt-controller;
488 device_type = "interrupt-controller";
489 reg = <0x1 0x20 0x2
490 0x1 0xa0 0x2
491 0x1 0x4d0 0x2>;
492 #address-cells = <0>;
493 #interrupt-cells = <2>;
494 compatible = "chrp,iic";
495 interrupts = <0 1>;
496 interrupt-parent = <&mpic>;
497 };
498
499 rtc@70 {
500 compatible = "pnpPNP,b00";
501 reg = <0x1 0x70 0x2>;
502 };
503 };
504 };
505 };
506
507 pci1: pci@e0009000 {
508 interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
509 interrupt-map = <
510
511 /* IDSEL 0x15 */
512 0xa800 0x0 0x0 0x1 &mpic 0xb 0x1
513 0xa800 0x0 0x0 0x2 &mpic 0x1 0x1
514 0xa800 0x0 0x0 0x3 &mpic 0x2 0x1
515 0xa800 0x0 0x0 0x4 &mpic 0x3 0x1>;
516
517 interrupt-parent = <&mpic>;
518 interrupts = <25 2>;
519 bus-range = <0 0>;
520 ranges = <0x2000000 0x0 0x90000000 0x90000000 0x0 0x10000000
521 0x1000000 0x0 0x0 0xe2800000 0x0 0x800000>;
522 clock-frequency = <66666666>;
523 #interrupt-cells = <1>;
524 #size-cells = <2>;
525 #address-cells = <3>;
526 reg = <0xe0009000 0x1000>;
527 compatible = "fsl,mpc8540-pci";
528 device_type = "pci";
529 };
530
531 pci2: pcie@e000a000 {
532 interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
533 interrupt-map = <
534
535 /* IDSEL 0x0 (PEX) */
536 00000 0x0 0x0 0x1 &mpic 0x0 0x1
537 00000 0x0 0x0 0x2 &mpic 0x1 0x1
538 00000 0x0 0x0 0x3 &mpic 0x2 0x1
539 00000 0x0 0x0 0x4 &mpic 0x3 0x1>;
540
541 interrupt-parent = <&mpic>;
542 interrupts = <26 2>;
543 bus-range = <0 255>;
544 ranges = <0x2000000 0x0 0xa0000000 0xa0000000 0x0 0x20000000
545 0x1000000 0x0 0x0 0xe3000000 0x0 0x100000>;
546 clock-frequency = <33333333>;
547 #interrupt-cells = <1>;
548 #size-cells = <2>;
549 #address-cells = <3>;
550 reg = <0xe000a000 0x1000>;
551 compatible = "fsl,mpc8548-pcie";
552 device_type = "pci";
553 pcie@0 {
554 reg = <0x0 0x0 0x0 0x0 0x0>;
555 #size-cells = <2>;
556 #address-cells = <3>;
557 device_type = "pci";
558 ranges = <0x2000000 0x0 0xa0000000
559 0x2000000 0x0 0xa0000000
560 0x0 0x20000000
561
562 0x1000000 0x0 0x0
563 0x1000000 0x0 0x0
564 0x0 0x100000>;
565 };
566 };
567};
diff --git a/arch/powerpc/boot/dts/p1010si.dtsi b/arch/powerpc/boot/dts/p1010si.dtsi
new file mode 100644
index 00000000000..7f51104f2e3
--- /dev/null
+++ b/arch/powerpc/boot/dts/p1010si.dtsi
@@ -0,0 +1,376 @@
1/*
2 * P1010si Device Tree Source
3 *
4 * Copyright 2011 Freescale Semiconductor Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version.
10 */
11
12/dts-v1/;
13/ {
14 compatible = "fsl,P1010";
15 #address-cells = <2>;
16 #size-cells = <2>;
17
18 cpus {
19 #address-cells = <1>;
20 #size-cells = <0>;
21
22 PowerPC,P1010@0 {
23 device_type = "cpu";
24 reg = <0x0>;
25 next-level-cache = <&L2>;
26 };
27 };
28
29 ifc@ffe1e000 {
30 #address-cells = <2>;
31 #size-cells = <1>;
32 compatible = "fsl,ifc", "simple-bus";
33 reg = <0x0 0xffe1e000 0 0x2000>;
34 interrupts = <16 2 19 2>;
35 interrupt-parent = <&mpic>;
36 };
37
38 soc@ffe00000 {
39 #address-cells = <1>;
40 #size-cells = <1>;
41 device_type = "soc";
42 compatible = "fsl,p1010-immr", "simple-bus";
43 ranges = <0x0 0x0 0xffe00000 0x100000>;
44 bus-frequency = <0>; // Filled out by uboot.
45
46 ecm-law@0 {
47 compatible = "fsl,ecm-law";
48 reg = <0x0 0x1000>;
49 fsl,num-laws = <12>;
50 };
51
52 ecm@1000 {
53 compatible = "fsl,p1010-ecm", "fsl,ecm";
54 reg = <0x1000 0x1000>;
55 interrupts = <16 2>;
56 interrupt-parent = <&mpic>;
57 };
58
59 memory-controller@2000 {
60 compatible = "fsl,p1010-memory-controller";
61 reg = <0x2000 0x1000>;
62 interrupt-parent = <&mpic>;
63 interrupts = <16 2>;
64 };
65
66 i2c@3000 {
67 #address-cells = <1>;
68 #size-cells = <0>;
69 cell-index = <0>;
70 compatible = "fsl-i2c";
71 reg = <0x3000 0x100>;
72 interrupts = <43 2>;
73 interrupt-parent = <&mpic>;
74 dfsrr;
75 };
76
77 i2c@3100 {
78 #address-cells = <1>;
79 #size-cells = <0>;
80 cell-index = <1>;
81 compatible = "fsl-i2c";
82 reg = <0x3100 0x100>;
83 interrupts = <43 2>;
84 interrupt-parent = <&mpic>;
85 dfsrr;
86 };
87
88 serial0: serial@4500 {
89 cell-index = <0>;
90 device_type = "serial";
91 compatible = "ns16550";
92 reg = <0x4500 0x100>;
93 clock-frequency = <0>;
94 interrupts = <42 2>;
95 interrupt-parent = <&mpic>;
96 };
97
98 serial1: serial@4600 {
99 cell-index = <1>;
100 device_type = "serial";
101 compatible = "ns16550";
102 reg = <0x4600 0x100>;
103 clock-frequency = <0>;
104 interrupts = <42 2>;
105 interrupt-parent = <&mpic>;
106 };
107
108 spi@7000 {
109 #address-cells = <1>;
110 #size-cells = <0>;
111 compatible = "fsl,mpc8536-espi";
112 reg = <0x7000 0x1000>;
113 interrupts = <59 0x2>;
114 interrupt-parent = <&mpic>;
115 fsl,espi-num-chipselects = <1>;
116 };
117
118 gpio: gpio-controller@f000 {
119 #gpio-cells = <2>;
120 compatible = "fsl,mpc8572-gpio";
121 reg = <0xf000 0x100>;
122 interrupts = <47 0x2>;
123 interrupt-parent = <&mpic>;
124 gpio-controller;
125 };
126
127 sata@18000 {
128 compatible = "fsl,pq-sata-v2";
129 reg = <0x18000 0x1000>;
130 cell-index = <1>;
131 interrupts = <74 0x2>;
132 interrupt-parent = <&mpic>;
133 };
134
135 sata@19000 {
136 compatible = "fsl,pq-sata-v2";
137 reg = <0x19000 0x1000>;
138 cell-index = <2>;
139 interrupts = <41 0x2>;
140 interrupt-parent = <&mpic>;
141 };
142
143 can0@1c000 {
144 compatible = "fsl,flexcan-v1.0";
145 reg = <0x1c000 0x1000>;
146 interrupts = <48 0x2>;
147 interrupt-parent = <&mpic>;
148 fsl,flexcan-clock-divider = <2>;
149 };
150
151 can1@1d000 {
152 compatible = "fsl,flexcan-v1.0";
153 reg = <0x1d000 0x1000>;
154 interrupts = <61 0x2>;
155 interrupt-parent = <&mpic>;
156 fsl,flexcan-clock-divider = <2>;
157 };
158
159 L2: l2-cache-controller@20000 {
160 compatible = "fsl,p1010-l2-cache-controller",
161 "fsl,p1014-l2-cache-controller";
162 reg = <0x20000 0x1000>;
163 cache-line-size = <32>; // 32 bytes
164 cache-size = <0x40000>; // L2,256K
165 interrupt-parent = <&mpic>;
166 interrupts = <16 2>;
167 };
168
169 dma@21300 {
170 #address-cells = <1>;
171 #size-cells = <1>;
172 compatible = "fsl,p1010-dma", "fsl,eloplus-dma";
173 reg = <0x21300 0x4>;
174 ranges = <0x0 0x21100 0x200>;
175 cell-index = <0>;
176 dma-channel@0 {
177 compatible = "fsl,p1010-dma-channel", "fsl,eloplus-dma-channel";
178 reg = <0x0 0x80>;
179 cell-index = <0>;
180 interrupt-parent = <&mpic>;
181 interrupts = <20 2>;
182 };
183 dma-channel@80 {
184 compatible = "fsl,p1010-dma-channel", "fsl,eloplus-dma-channel";
185 reg = <0x80 0x80>;
186 cell-index = <1>;
187 interrupt-parent = <&mpic>;
188 interrupts = <21 2>;
189 };
190 dma-channel@100 {
191 compatible = "fsl,p1010-dma-channel", "fsl,eloplus-dma-channel";
192 reg = <0x100 0x80>;
193 cell-index = <2>;
194 interrupt-parent = <&mpic>;
195 interrupts = <22 2>;
196 };
197 dma-channel@180 {
198 compatible = "fsl,p1010-dma-channel", "fsl,eloplus-dma-channel";
199 reg = <0x180 0x80>;
200 cell-index = <3>;
201 interrupt-parent = <&mpic>;
202 interrupts = <23 2>;
203 };
204 };
205
206 usb@22000 {
207 compatible = "fsl-usb2-dr";
208 reg = <0x22000 0x1000>;
209 #address-cells = <1>;
210 #size-cells = <0>;
211 interrupt-parent = <&mpic>;
212 interrupts = <28 0x2>;
213 dr_mode = "host";
214 };
215
216 mdio@24000 {
217 #address-cells = <1>;
218 #size-cells = <0>;
219 compatible = "fsl,etsec2-mdio";
220 reg = <0x24000 0x1000 0xb0030 0x4>;
221 };
222
223 mdio@25000 {
224 #address-cells = <1>;
225 #size-cells = <0>;
226 compatible = "fsl,etsec2-tbi";
227 reg = <0x25000 0x1000 0xb1030 0x4>;
228 tbi0: tbi-phy@11 {
229 reg = <0x11>;
230 device_type = "tbi-phy";
231 };
232 };
233
234 mdio@26000 {
235 #address-cells = <1>;
236 #size-cells = <0>;
237 compatible = "fsl,etsec2-tbi";
238 reg = <0x26000 0x1000 0xb1030 0x4>;
239 tbi1: tbi-phy@11 {
240 reg = <0x11>;
241 device_type = "tbi-phy";
242 };
243 };
244
245 sdhci@2e000 {
246 compatible = "fsl,esdhc";
247 reg = <0x2e000 0x1000>;
248 interrupts = <72 0x8>;
249 interrupt-parent = <&mpic>;
250 /* Filled in by U-Boot */
251 clock-frequency = <0>;
252 fsl,sdhci-auto-cmd12;
253 };
254
255 enet0: ethernet@b0000 {
256 #address-cells = <1>;
257 #size-cells = <1>;
258 device_type = "network";
259 model = "eTSEC";
260 compatible = "fsl,etsec2";
261 fsl,num_rx_queues = <0x8>;
262 fsl,num_tx_queues = <0x8>;
263 local-mac-address = [ 00 00 00 00 00 00 ];
264 interrupt-parent = <&mpic>;
265
266 queue-group@0 {
267 #address-cells = <1>;
268 #size-cells = <1>;
269 reg = <0xb0000 0x1000>;
270 fsl,rx-bit-map = <0xff>;
271 fsl,tx-bit-map = <0xff>;
272 interrupts = <29 2 30 2 34 2>;
273 };
274
275 };
276
277 enet1: ethernet@b1000 {
278 #address-cells = <1>;
279 #size-cells = <1>;
280 device_type = "network";
281 model = "eTSEC";
282 compatible = "fsl,etsec2";
283 fsl,num_rx_queues = <0x8>;
284 fsl,num_tx_queues = <0x8>;
285 local-mac-address = [ 00 00 00 00 00 00 ];
286 interrupt-parent = <&mpic>;
287
288 queue-group@0 {
289 #address-cells = <1>;
290 #size-cells = <1>;
291 reg = <0xb1000 0x1000>;
292 fsl,rx-bit-map = <0xff>;
293 fsl,tx-bit-map = <0xff>;
294 interrupts = <35 2 36 2 40 2>;
295 };
296
297 };
298
299 enet2: ethernet@b2000 {
300 #address-cells = <1>;
301 #size-cells = <1>;
302 device_type = "network";
303 model = "eTSEC";
304 compatible = "fsl,etsec2";
305 fsl,num_rx_queues = <0x8>;
306 fsl,num_tx_queues = <0x8>;
307 local-mac-address = [ 00 00 00 00 00 00 ];
308 interrupt-parent = <&mpic>;
309
310 queue-group@0 {
311 #address-cells = <1>;
312 #size-cells = <1>;
313 reg = <0xb2000 0x1000>;
314 fsl,rx-bit-map = <0xff>;
315 fsl,tx-bit-map = <0xff>;
316 interrupts = <31 2 32 2 33 2>;
317 };
318
319 };
320
321 mpic: pic@40000 {
322 interrupt-controller;
323 #address-cells = <0>;
324 #interrupt-cells = <2>;
325 reg = <0x40000 0x40000>;
326 compatible = "chrp,open-pic";
327 device_type = "open-pic";
328 };
329
330 msi@41600 {
331 compatible = "fsl,p1010-msi", "fsl,mpic-msi";
332 reg = <0x41600 0x80>;
333 msi-available-ranges = <0 0x100>;
334 interrupts = <
335 0xe0 0
336 0xe1 0
337 0xe2 0
338 0xe3 0
339 0xe4 0
340 0xe5 0
341 0xe6 0
342 0xe7 0>;
343 interrupt-parent = <&mpic>;
344 };
345
346 global-utilities@e0000 { //global utilities block
347 compatible = "fsl,p1010-guts";
348 reg = <0xe0000 0x1000>;
349 fsl,has-rstcr;
350 };
351 };
352
353 pci0: pcie@ffe09000 {
354 compatible = "fsl,p1010-pcie", "fsl,qoriq-pcie-v2.3", "fsl,qoriq-pcie-v2.2";
355 device_type = "pci";
356 #size-cells = <2>;
357 #address-cells = <3>;
358 reg = <0 0xffe09000 0 0x1000>;
359 bus-range = <0 255>;
360 clock-frequency = <33333333>;
361 interrupt-parent = <&mpic>;
362 interrupts = <16 2>;
363 };
364
365 pci1: pcie@ffe0a000 {
366 compatible = "fsl,p1010-pcie", "fsl,qoriq-pcie-v2.3", "fsl,qoriq-pcie-v2.2";
367 device_type = "pci";
368 #size-cells = <2>;
369 #address-cells = <3>;
370 reg = <0 0xffe0a000 0 0x1000>;
371 bus-range = <0 255>;
372 clock-frequency = <33333333>;
373 interrupt-parent = <&mpic>;
374 interrupts = <16 2>;
375 };
376};
diff --git a/arch/powerpc/boot/dts/p1020rdb_camp_core0.dts b/arch/powerpc/boot/dts/p1020rdb_camp_core0.dts
new file mode 100644
index 00000000000..f0bf7f42f09
--- /dev/null
+++ b/arch/powerpc/boot/dts/p1020rdb_camp_core0.dts
@@ -0,0 +1,213 @@
1/*
2 * P1020 RDB Core0 Device Tree Source in CAMP mode.
3 *
4 * In CAMP mode, each core needs to have its own dts. Only mpic and L2 cache
5 * can be shared, all the other devices must be assigned to one core only.
6 * This dts file allows core0 to have memory, l2, i2c, spi, gpio, 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 2011 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/ "p1020si.dtsi"
20
21/ {
22 model = "fsl,P1020RDB";
23 compatible = "fsl,P1020RDB", "fsl,MPC85XXRDB-CAMP";
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 i2c@3000 {
49 rtc@68 {
50 compatible = "dallas,ds1339";
51 reg = <0x68>;
52 };
53 };
54
55 serial1: serial@4600 {
56 status = "disabled";
57 };
58
59 spi@7000 {
60 fsl_m25p80@0 {
61 #address-cells = <1>;
62 #size-cells = <1>;
63 compatible = "fsl,espi-flash";
64 reg = <0>;
65 linux,modalias = "fsl_m25p80";
66 spi-max-frequency = <40000000>;
67
68 partition@0 {
69 /* 512KB for u-boot Bootloader Image */
70 reg = <0x0 0x00080000>;
71 label = "SPI (RO) U-Boot Image";
72 read-only;
73 };
74
75 partition@80000 {
76 /* 512KB for DTB Image */
77 reg = <0x00080000 0x00080000>;
78 label = "SPI (RO) DTB Image";
79 read-only;
80 };
81
82 partition@100000 {
83 /* 4MB for Linux Kernel Image */
84 reg = <0x00100000 0x00400000>;
85 label = "SPI (RO) Linux Kernel Image";
86 read-only;
87 };
88
89 partition@500000 {
90 /* 4MB for Compressed RFS Image */
91 reg = <0x00500000 0x00400000>;
92 label = "SPI (RO) Compressed RFS Image";
93 read-only;
94 };
95
96 partition@900000 {
97 /* 7MB for JFFS2 based RFS */
98 reg = <0x00900000 0x00700000>;
99 label = "SPI (RW) JFFS2 RFS";
100 };
101 };
102 };
103
104 mdio@24000 {
105 phy0: ethernet-phy@0 {
106 interrupt-parent = <&mpic>;
107 interrupts = <3 1>;
108 reg = <0x0>;
109 };
110 phy1: ethernet-phy@1 {
111 interrupt-parent = <&mpic>;
112 interrupts = <2 1>;
113 reg = <0x1>;
114 };
115 };
116
117 mdio@25000 {
118 tbi0: tbi-phy@11 {
119 reg = <0x11>;
120 device_type = "tbi-phy";
121 };
122 };
123
124 enet0: ethernet@b0000 {
125 status = "disabled";
126 };
127
128 enet1: ethernet@b1000 {
129 phy-handle = <&phy0>;
130 tbi-handle = <&tbi0>;
131 phy-connection-type = "sgmii";
132 };
133
134 enet2: ethernet@b2000 {
135 phy-handle = <&phy1>;
136 phy-connection-type = "rgmii-id";
137 };
138
139 usb@22000 {
140 phy_type = "ulpi";
141 };
142
143 /* USB2 is shared with localbus, so it must be disabled
144 by default. We can't put 'status = "disabled";' here
145 since U-Boot doesn't clear the status property when
146 it enables USB2. OTOH, U-Boot does create a new node
147 when there isn't any. So, just comment it out.
148 usb@23000 {
149 phy_type = "ulpi";
150 };
151 */
152
153 mpic: pic@40000 {
154 protected-sources = <
155 42 29 30 34 /* serial1, enet0-queue-group0 */
156 17 18 24 45 /* enet0-queue-group1, crypto */
157 >;
158 };
159
160 };
161
162 pci0: pcie@ffe09000 {
163 ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000
164 0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>;
165 interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
166 interrupt-map = <
167 /* IDSEL 0x0 */
168 0000 0x0 0x0 0x1 &mpic 0x4 0x1
169 0000 0x0 0x0 0x2 &mpic 0x5 0x1
170 0000 0x0 0x0 0x3 &mpic 0x6 0x1
171 0000 0x0 0x0 0x4 &mpic 0x7 0x1
172 >;
173 pcie@0 {
174 reg = <0x0 0x0 0x0 0x0 0x0>;
175 #size-cells = <2>;
176 #address-cells = <3>;
177 device_type = "pci";
178 ranges = <0x2000000 0x0 0xa0000000
179 0x2000000 0x0 0xa0000000
180 0x0 0x20000000
181
182 0x1000000 0x0 0x0
183 0x1000000 0x0 0x0
184 0x0 0x100000>;
185 };
186 };
187
188 pci1: pcie@ffe0a000 {
189 ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000
190 0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>;
191 interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
192 interrupt-map = <
193 /* IDSEL 0x0 */
194 0000 0x0 0x0 0x1 &mpic 0x0 0x1
195 0000 0x0 0x0 0x2 &mpic 0x1 0x1
196 0000 0x0 0x0 0x3 &mpic 0x2 0x1
197 0000 0x0 0x0 0x4 &mpic 0x3 0x1
198 >;
199 pcie@0 {
200 reg = <0x0 0x0 0x0 0x0 0x0>;
201 #size-cells = <2>;
202 #address-cells = <3>;
203 device_type = "pci";
204 ranges = <0x2000000 0x0 0x80000000
205 0x2000000 0x0 0x80000000
206 0x0 0x20000000
207
208 0x1000000 0x0 0x0
209 0x1000000 0x0 0x0
210 0x0 0x100000>;
211 };
212 };
213};
diff --git a/arch/powerpc/boot/dts/p1020rdb_camp_core1.dts b/arch/powerpc/boot/dts/p1020rdb_camp_core1.dts
new file mode 100644
index 00000000000..6ec02204a44
--- /dev/null
+++ b/arch/powerpc/boot/dts/p1020rdb_camp_core1.dts
@@ -0,0 +1,148 @@
1/*
2 * P1020 RDB Core1 Device Tree Source in CAMP mode.
3 *
4 * In CAMP mode, each core needs to have its own dts. Only mpic and L2 cache
5 * can be shared, all the other devices must be assigned to one core only.
6 * This dts allows core1 to have l2, eth0, crypto.
7 *
8 * Please note to add "-b 1" for core1's dts compiling.
9 *
10 * Copyright 2011 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/ "p1020si.dtsi"
19
20/ {
21 model = "fsl,P1020RDB";
22 compatible = "fsl,P1020RDB", "fsl,MPC85XXRDB-CAMP";
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 enet0: ethernet@b0000 {
89 fixed-link = <1 1 1000 0 0>;
90 phy-connection-type = "rgmii-id";
91
92 };
93
94 enet1: ethernet@b1000 {
95 status = "disabled";
96 };
97
98 enet2: ethernet@b2000 {
99 status = "disabled";
100 };
101
102 usb@22000 {
103 status = "disabled";
104 };
105
106 sdhci@2e000 {
107 status = "disabled";
108 };
109
110 mpic: pic@40000 {
111 protected-sources = <
112 16 /* ecm, mem, L2, pci0, pci1 */
113 43 42 59 /* i2c, serial0, spi */
114 47 63 62 /* gpio, tdm */
115 20 21 22 23 /* dma */
116 03 02 /* mdio */
117 35 36 40 /* enet1-queue-group0 */
118 51 52 67 /* enet1-queue-group1 */
119 31 32 33 /* enet2-queue-group0 */
120 25 26 27 /* enet2-queue-group1 */
121 28 72 58 /* usb, sdhci, crypto */
122 0xb0 0xb1 0xb2 /* message */
123 0xb3 0xb4 0xb5
124 0xb6 0xb7
125 0xe0 0xe1 0xe2 /* msi */
126 0xe3 0xe4 0xe5
127 0xe6 0xe7 /* sdhci, crypto , pci */
128 >;
129 };
130
131 msi@41600 {
132 status = "disabled";
133 };
134
135 global-utilities@e0000 { //global utilities block
136 status = "disabled";
137 };
138
139 };
140
141 pci0: pcie@ffe09000 {
142 status = "disabled";
143 };
144
145 pci1: pcie@ffe0a000 {
146 status = "disabled";
147 };
148};
diff --git a/arch/powerpc/boot/dts/p1020si.dtsi b/arch/powerpc/boot/dts/p1020si.dtsi
new file mode 100644
index 00000000000..5c5acb66c3f
--- /dev/null
+++ b/arch/powerpc/boot/dts/p1020si.dtsi
@@ -0,0 +1,377 @@
1/*
2 * P1020si Device Tree Source
3 *
4 * Copyright 2011 Freescale Semiconductor Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version.
10 */
11
12/dts-v1/;
13/ {
14 compatible = "fsl,P1020";
15 #address-cells = <2>;
16 #size-cells = <2>;
17
18 cpus {
19 #address-cells = <1>;
20 #size-cells = <0>;
21
22 PowerPC,P1020@0 {
23 device_type = "cpu";
24 reg = <0x0>;
25 next-level-cache = <&L2>;
26 };
27
28 PowerPC,P1020@1 {
29 device_type = "cpu";
30 reg = <0x1>;
31 next-level-cache = <&L2>;
32 };
33 };
34
35 localbus@ffe05000 {
36 #address-cells = <2>;
37 #size-cells = <1>;
38 compatible = "fsl,p1020-elbc", "fsl,elbc", "simple-bus";
39 reg = <0 0xffe05000 0 0x1000>;
40 interrupts = <19 2>;
41 interrupt-parent = <&mpic>;
42 };
43
44 soc@ffe00000 {
45 #address-cells = <1>;
46 #size-cells = <1>;
47 device_type = "soc";
48 compatible = "fsl,p1020-immr", "simple-bus";
49 ranges = <0x0 0x0 0xffe00000 0x100000>;
50 bus-frequency = <0>; // Filled out by uboot.
51
52 ecm-law@0 {
53 compatible = "fsl,ecm-law";
54 reg = <0x0 0x1000>;
55 fsl,num-laws = <12>;
56 };
57
58 ecm@1000 {
59 compatible = "fsl,p1020-ecm", "fsl,ecm";
60 reg = <0x1000 0x1000>;
61 interrupts = <16 2>;
62 interrupt-parent = <&mpic>;
63 };
64
65 memory-controller@2000 {
66 compatible = "fsl,p1020-memory-controller";
67 reg = <0x2000 0x1000>;
68 interrupt-parent = <&mpic>;
69 interrupts = <16 2>;
70 };
71
72 i2c@3000 {
73 #address-cells = <1>;
74 #size-cells = <0>;
75 cell-index = <0>;
76 compatible = "fsl-i2c";
77 reg = <0x3000 0x100>;
78 interrupts = <43 2>;
79 interrupt-parent = <&mpic>;
80 dfsrr;
81 };
82
83 i2c@3100 {
84 #address-cells = <1>;
85 #size-cells = <0>;
86 cell-index = <1>;
87 compatible = "fsl-i2c";
88 reg = <0x3100 0x100>;
89 interrupts = <43 2>;
90 interrupt-parent = <&mpic>;
91 dfsrr;
92 };
93
94 serial0: serial@4500 {
95 cell-index = <0>;
96 device_type = "serial";
97 compatible = "ns16550";
98 reg = <0x4500 0x100>;
99 clock-frequency = <0>;
100 interrupts = <42 2>;
101 interrupt-parent = <&mpic>;
102 };
103
104 serial1: serial@4600 {
105 cell-index = <1>;
106 device_type = "serial";
107 compatible = "ns16550";
108 reg = <0x4600 0x100>;
109 clock-frequency = <0>;
110 interrupts = <42 2>;
111 interrupt-parent = <&mpic>;
112 };
113
114 spi@7000 {
115 cell-index = <0>;
116 #address-cells = <1>;
117 #size-cells = <0>;
118 compatible = "fsl,espi";
119 reg = <0x7000 0x1000>;
120 interrupts = <59 0x2>;
121 interrupt-parent = <&mpic>;
122 mode = "cpu";
123 };
124
125 gpio: gpio-controller@f000 {
126 #gpio-cells = <2>;
127 compatible = "fsl,mpc8572-gpio";
128 reg = <0xf000 0x100>;
129 interrupts = <47 0x2>;
130 interrupt-parent = <&mpic>;
131 gpio-controller;
132 };
133
134 L2: l2-cache-controller@20000 {
135 compatible = "fsl,p1020-l2-cache-controller";
136 reg = <0x20000 0x1000>;
137 cache-line-size = <32>; // 32 bytes
138 cache-size = <0x40000>; // L2,256K
139 interrupt-parent = <&mpic>;
140 interrupts = <16 2>;
141 };
142
143 dma@21300 {
144 #address-cells = <1>;
145 #size-cells = <1>;
146 compatible = "fsl,eloplus-dma";
147 reg = <0x21300 0x4>;
148 ranges = <0x0 0x21100 0x200>;
149 cell-index = <0>;
150 dma-channel@0 {
151 compatible = "fsl,eloplus-dma-channel";
152 reg = <0x0 0x80>;
153 cell-index = <0>;
154 interrupt-parent = <&mpic>;
155 interrupts = <20 2>;
156 };
157 dma-channel@80 {
158 compatible = "fsl,eloplus-dma-channel";
159 reg = <0x80 0x80>;
160 cell-index = <1>;
161 interrupt-parent = <&mpic>;
162 interrupts = <21 2>;
163 };
164 dma-channel@100 {
165 compatible = "fsl,eloplus-dma-channel";
166 reg = <0x100 0x80>;
167 cell-index = <2>;
168 interrupt-parent = <&mpic>;
169 interrupts = <22 2>;
170 };
171 dma-channel@180 {
172 compatible = "fsl,eloplus-dma-channel";
173 reg = <0x180 0x80>;
174 cell-index = <3>;
175 interrupt-parent = <&mpic>;
176 interrupts = <23 2>;
177 };
178 };
179
180 mdio@24000 {
181 #address-cells = <1>;
182 #size-cells = <0>;
183 compatible = "fsl,etsec2-mdio";
184 reg = <0x24000 0x1000 0xb0030 0x4>;
185
186 };
187
188 mdio@25000 {
189 #address-cells = <1>;
190 #size-cells = <0>;
191 compatible = "fsl,etsec2-tbi";
192 reg = <0x25000 0x1000 0xb1030 0x4>;
193
194 };
195
196 enet0: ethernet@b0000 {
197 #address-cells = <1>;
198 #size-cells = <1>;
199 device_type = "network";
200 model = "eTSEC";
201 compatible = "fsl,etsec2";
202 fsl,num_rx_queues = <0x8>;
203 fsl,num_tx_queues = <0x8>;
204 local-mac-address = [ 00 00 00 00 00 00 ];
205 interrupt-parent = <&mpic>;
206
207 queue-group@0 {
208 #address-cells = <1>;
209 #size-cells = <1>;
210 reg = <0xb0000 0x1000>;
211 interrupts = <29 2 30 2 34 2>;
212 };
213
214 queue-group@1 {
215 #address-cells = <1>;
216 #size-cells = <1>;
217 reg = <0xb4000 0x1000>;
218 interrupts = <17 2 18 2 24 2>;
219 };
220 };
221
222 enet1: ethernet@b1000 {
223 #address-cells = <1>;
224 #size-cells = <1>;
225 device_type = "network";
226 model = "eTSEC";
227 compatible = "fsl,etsec2";
228 fsl,num_rx_queues = <0x8>;
229 fsl,num_tx_queues = <0x8>;
230 local-mac-address = [ 00 00 00 00 00 00 ];
231 interrupt-parent = <&mpic>;
232
233 queue-group@0 {
234 #address-cells = <1>;
235 #size-cells = <1>;
236 reg = <0xb1000 0x1000>;
237 interrupts = <35 2 36 2 40 2>;
238 };
239
240 queue-group@1 {
241 #address-cells = <1>;
242 #size-cells = <1>;
243 reg = <0xb5000 0x1000>;
244 interrupts = <51 2 52 2 67 2>;
245 };
246 };
247
248 enet2: ethernet@b2000 {
249 #address-cells = <1>;
250 #size-cells = <1>;
251 device_type = "network";
252 model = "eTSEC";
253 compatible = "fsl,etsec2";
254 fsl,num_rx_queues = <0x8>;
255 fsl,num_tx_queues = <0x8>;
256 local-mac-address = [ 00 00 00 00 00 00 ];
257 interrupt-parent = <&mpic>;
258
259 queue-group@0 {
260 #address-cells = <1>;
261 #size-cells = <1>;
262 reg = <0xb2000 0x1000>;
263 interrupts = <31 2 32 2 33 2>;
264 };
265
266 queue-group@1 {
267 #address-cells = <1>;
268 #size-cells = <1>;
269 reg = <0xb6000 0x1000>;
270 interrupts = <25 2 26 2 27 2>;
271 };
272 };
273
274 usb@22000 {
275 #address-cells = <1>;
276 #size-cells = <0>;
277 compatible = "fsl-usb2-dr";
278 reg = <0x22000 0x1000>;
279 interrupt-parent = <&mpic>;
280 interrupts = <28 0x2>;
281 };
282
283 /* USB2 is shared with localbus, so it must be disabled
284 by default. We can't put 'status = "disabled";' here
285 since U-Boot doesn't clear the status property when
286 it enables USB2. OTOH, U-Boot does create a new node
287 when there isn't any. So, just comment it out.
288 usb@23000 {
289 #address-cells = <1>;
290 #size-cells = <0>;
291 compatible = "fsl-usb2-dr";
292 reg = <0x23000 0x1000>;
293 interrupt-parent = <&mpic>;
294 interrupts = <46 0x2>;
295 phy_type = "ulpi";
296 };
297 */
298
299 sdhci@2e000 {
300 compatible = "fsl,p1020-esdhc", "fsl,esdhc";
301 reg = <0x2e000 0x1000>;
302 interrupts = <72 0x2>;
303 interrupt-parent = <&mpic>;
304 /* Filled in by U-Boot */
305 clock-frequency = <0>;
306 };
307
308 crypto@30000 {
309 compatible = "fsl,sec3.1", "fsl,sec3.0", "fsl,sec2.4",
310 "fsl,sec2.2", "fsl,sec2.1", "fsl,sec2.0";
311 reg = <0x30000 0x10000>;
312 interrupts = <45 2 58 2>;
313 interrupt-parent = <&mpic>;
314 fsl,num-channels = <4>;
315 fsl,channel-fifo-len = <24>;
316 fsl,exec-units-mask = <0xbfe>;
317 fsl,descriptor-types-mask = <0x3ab0ebf>;
318 };
319
320 mpic: pic@40000 {
321 interrupt-controller;
322 #address-cells = <0>;
323 #interrupt-cells = <2>;
324 reg = <0x40000 0x40000>;
325 compatible = "chrp,open-pic";
326 device_type = "open-pic";
327 };
328
329 msi@41600 {
330 compatible = "fsl,p1020-msi", "fsl,mpic-msi";
331 reg = <0x41600 0x80>;
332 msi-available-ranges = <0 0x100>;
333 interrupts = <
334 0xe0 0
335 0xe1 0
336 0xe2 0
337 0xe3 0
338 0xe4 0
339 0xe5 0
340 0xe6 0
341 0xe7 0>;
342 interrupt-parent = <&mpic>;
343 };
344
345 global-utilities@e0000 { //global utilities block
346 compatible = "fsl,p1020-guts","fsl,p2020-guts";
347 reg = <0xe0000 0x1000>;
348 fsl,has-rstcr;
349 };
350 };
351
352 pci0: pcie@ffe09000 {
353 compatible = "fsl,mpc8548-pcie";
354 device_type = "pci";
355 #interrupt-cells = <1>;
356 #size-cells = <2>;
357 #address-cells = <3>;
358 reg = <0 0xffe09000 0 0x1000>;
359 bus-range = <0 255>;
360 clock-frequency = <33333333>;
361 interrupt-parent = <&mpic>;
362 interrupts = <16 2>;
363 };
364
365 pci1: pcie@ffe0a000 {
366 compatible = "fsl,mpc8548-pcie";
367 device_type = "pci";
368 #interrupt-cells = <1>;
369 #size-cells = <2>;
370 #address-cells = <3>;
371 reg = <0 0xffe0a000 0 0x1000>;
372 bus-range = <0 255>;
373 clock-frequency = <33333333>;
374 interrupt-parent = <&mpic>;
375 interrupts = <16 2>;
376 };
377};
diff --git a/arch/powerpc/boot/dts/p1022ds.dts b/arch/powerpc/boot/dts/p1022ds.dts
new file mode 100644
index 00000000000..1be9743ab5e
--- /dev/null
+++ b/arch/powerpc/boot/dts/p1022ds.dts
@@ -0,0 +1,657 @@
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/dts-v1/;
12/ {
13 model = "fsl,P1022";
14 compatible = "fsl,P1022DS";
15 #address-cells = <2>;
16 #size-cells = <2>;
17 interrupt-parent = <&mpic>;
18
19 aliases {
20 ethernet0 = &enet0;
21 ethernet1 = &enet1;
22 serial0 = &serial0;
23 serial1 = &serial1;
24 pci0 = &pci0;
25 pci1 = &pci1;
26 pci2 = &pci2;
27 };
28
29 cpus {
30 #address-cells = <1>;
31 #size-cells = <0>;
32
33 PowerPC,P1022@0 {
34 device_type = "cpu";
35 reg = <0x0>;
36 next-level-cache = <&L2>;
37 };
38
39 PowerPC,P1022@1 {
40 device_type = "cpu";
41 reg = <0x1>;
42 next-level-cache = <&L2>;
43 };
44 };
45
46 memory {
47 device_type = "memory";
48 };
49
50 localbus@fffe05000 {
51 #address-cells = <2>;
52 #size-cells = <1>;
53 compatible = "fsl,p1022-elbc", "fsl,elbc", "simple-bus";
54 reg = <0 0xffe05000 0 0x1000>;
55 interrupts = <19 2 0 0>;
56
57 ranges = <0x0 0x0 0xf 0xe8000000 0x08000000
58 0x1 0x0 0xf 0xe0000000 0x08000000
59 0x2 0x0 0x0 0xffa00000 0x00040000
60 0x3 0x0 0xf 0xffdf0000 0x00008000>;
61
62 nor@0,0 {
63 #address-cells = <1>;
64 #size-cells = <1>;
65 compatible = "cfi-flash";
66 reg = <0x0 0x0 0x8000000>;
67 bank-width = <2>;
68 device-width = <1>;
69
70 partition@0 {
71 reg = <0x0 0x03000000>;
72 label = "ramdisk-nor";
73 read-only;
74 };
75
76 partition@3000000 {
77 reg = <0x03000000 0x00e00000>;
78 label = "diagnostic-nor";
79 read-only;
80 };
81
82 partition@3e00000 {
83 reg = <0x03e00000 0x00200000>;
84 label = "dink-nor";
85 read-only;
86 };
87
88 partition@4000000 {
89 reg = <0x04000000 0x00400000>;
90 label = "kernel-nor";
91 read-only;
92 };
93
94 partition@4400000 {
95 reg = <0x04400000 0x03b00000>;
96 label = "jffs2-nor";
97 };
98
99 partition@7f00000 {
100 reg = <0x07f00000 0x00080000>;
101 label = "dtb-nor";
102 read-only;
103 };
104
105 partition@7f80000 {
106 reg = <0x07f80000 0x00080000>;
107 label = "u-boot-nor";
108 read-only;
109 };
110 };
111
112 nand@2,0 {
113 #address-cells = <1>;
114 #size-cells = <1>;
115 compatible = "fsl,elbc-fcm-nand";
116 reg = <0x2 0x0 0x40000>;
117
118 partition@0 {
119 reg = <0x0 0x02000000>;
120 label = "u-boot-nand";
121 read-only;
122 };
123
124 partition@2000000 {
125 reg = <0x02000000 0x10000000>;
126 label = "jffs2-nand";
127 };
128
129 partition@12000000 {
130 reg = <0x12000000 0x10000000>;
131 label = "ramdisk-nand";
132 read-only;
133 };
134
135 partition@22000000 {
136 reg = <0x22000000 0x04000000>;
137 label = "kernel-nand";
138 };
139
140 partition@26000000 {
141 reg = <0x26000000 0x01000000>;
142 label = "dtb-nand";
143 read-only;
144 };
145
146 partition@27000000 {
147 reg = <0x27000000 0x19000000>;
148 label = "reserved-nand";
149 };
150 };
151
152 board-control@3,0 {
153 compatible = "fsl,p1022ds-pixis";
154 reg = <3 0 0x30>;
155 interrupt-parent = <&mpic>;
156 /*
157 * IRQ8 is generated if the "EVENT" switch is pressed
158 * and PX_CTL[EVESEL] is set to 00.
159 */
160 interrupts = <8 8 0 0>;
161 };
162 };
163
164 soc@fffe00000 {
165 #address-cells = <1>;
166 #size-cells = <1>;
167 device_type = "soc";
168 compatible = "fsl,p1022-immr", "simple-bus";
169 ranges = <0x0 0xf 0xffe00000 0x100000>;
170 bus-frequency = <0>; // Filled out by uboot.
171
172 ecm-law@0 {
173 compatible = "fsl,ecm-law";
174 reg = <0x0 0x1000>;
175 fsl,num-laws = <12>;
176 };
177
178 ecm@1000 {
179 compatible = "fsl,p1022-ecm", "fsl,ecm";
180 reg = <0x1000 0x1000>;
181 interrupts = <16 2 0 0>;
182 };
183
184 memory-controller@2000 {
185 compatible = "fsl,p1022-memory-controller";
186 reg = <0x2000 0x1000>;
187 interrupts = <16 2 0 0>;
188 };
189
190 i2c@3000 {
191 #address-cells = <1>;
192 #size-cells = <0>;
193 cell-index = <0>;
194 compatible = "fsl-i2c";
195 reg = <0x3000 0x100>;
196 interrupts = <43 2 0 0>;
197 dfsrr;
198 };
199
200 i2c@3100 {
201 #address-cells = <1>;
202 #size-cells = <0>;
203 cell-index = <1>;
204 compatible = "fsl-i2c";
205 reg = <0x3100 0x100>;
206 interrupts = <43 2 0 0>;
207 dfsrr;
208
209 wm8776:codec@1a {
210 compatible = "wlf,wm8776";
211 reg = <0x1a>;
212 /*
213 * clock-frequency will be set by U-Boot if
214 * the clock is enabled.
215 */
216 };
217 };
218
219 serial0: serial@4500 {
220 cell-index = <0>;
221 device_type = "serial";
222 compatible = "ns16550";
223 reg = <0x4500 0x100>;
224 clock-frequency = <0>;
225 interrupts = <42 2 0 0>;
226 };
227
228 serial1: serial@4600 {
229 cell-index = <1>;
230 device_type = "serial";
231 compatible = "ns16550";
232 reg = <0x4600 0x100>;
233 clock-frequency = <0>;
234 interrupts = <42 2 0 0>;
235 };
236
237 spi@7000 {
238 cell-index = <0>;
239 #address-cells = <1>;
240 #size-cells = <0>;
241 compatible = "fsl,espi";
242 reg = <0x7000 0x1000>;
243 interrupts = <59 0x2 0 0>;
244 espi,num-ss-bits = <4>;
245 mode = "cpu";
246
247 fsl_m25p80@0 {
248 #address-cells = <1>;
249 #size-cells = <1>;
250 compatible = "fsl,espi-flash";
251 reg = <0>;
252 linux,modalias = "fsl_m25p80";
253 spi-max-frequency = <40000000>; /* input clock */
254 partition@0 {
255 label = "u-boot-spi";
256 reg = <0x00000000 0x00100000>;
257 read-only;
258 };
259 partition@100000 {
260 label = "kernel-spi";
261 reg = <0x00100000 0x00500000>;
262 read-only;
263 };
264 partition@600000 {
265 label = "dtb-spi";
266 reg = <0x00600000 0x00100000>;
267 read-only;
268 };
269 partition@700000 {
270 label = "file system-spi";
271 reg = <0x00700000 0x00900000>;
272 };
273 };
274 };
275
276 ssi@15000 {
277 compatible = "fsl,mpc8610-ssi";
278 cell-index = <0>;
279 reg = <0x15000 0x100>;
280 interrupts = <75 2 0 0>;
281 fsl,mode = "i2s-slave";
282 codec-handle = <&wm8776>;
283 fsl,playback-dma = <&dma00>;
284 fsl,capture-dma = <&dma01>;
285 fsl,fifo-depth = <15>;
286 fsl,ssi-asynchronous;
287 };
288
289 dma@c300 {
290 #address-cells = <1>;
291 #size-cells = <1>;
292 compatible = "fsl,eloplus-dma";
293 reg = <0xc300 0x4>;
294 ranges = <0x0 0xc100 0x200>;
295 cell-index = <1>;
296 dma00: dma-channel@0 {
297 compatible = "fsl,ssi-dma-channel";
298 reg = <0x0 0x80>;
299 cell-index = <0>;
300 interrupts = <76 2 0 0>;
301 };
302 dma01: dma-channel@80 {
303 compatible = "fsl,ssi-dma-channel";
304 reg = <0x80 0x80>;
305 cell-index = <1>;
306 interrupts = <77 2 0 0>;
307 };
308 dma-channel@100 {
309 compatible = "fsl,eloplus-dma-channel";
310 reg = <0x100 0x80>;
311 cell-index = <2>;
312 interrupts = <78 2 0 0>;
313 };
314 dma-channel@180 {
315 compatible = "fsl,eloplus-dma-channel";
316 reg = <0x180 0x80>;
317 cell-index = <3>;
318 interrupts = <79 2 0 0>;
319 };
320 };
321
322 gpio: gpio-controller@f000 {
323 #gpio-cells = <2>;
324 compatible = "fsl,mpc8572-gpio";
325 reg = <0xf000 0x100>;
326 interrupts = <47 0x2 0 0>;
327 gpio-controller;
328 };
329
330 L2: l2-cache-controller@20000 {
331 compatible = "fsl,p1022-l2-cache-controller";
332 reg = <0x20000 0x1000>;
333 cache-line-size = <32>; // 32 bytes
334 cache-size = <0x40000>; // L2, 256K
335 interrupts = <16 2 0 0>;
336 };
337
338 dma@21300 {
339 #address-cells = <1>;
340 #size-cells = <1>;
341 compatible = "fsl,eloplus-dma";
342 reg = <0x21300 0x4>;
343 ranges = <0x0 0x21100 0x200>;
344 cell-index = <0>;
345 dma-channel@0 {
346 compatible = "fsl,eloplus-dma-channel";
347 reg = <0x0 0x80>;
348 cell-index = <0>;
349 interrupts = <20 2 0 0>;
350 };
351 dma-channel@80 {
352 compatible = "fsl,eloplus-dma-channel";
353 reg = <0x80 0x80>;
354 cell-index = <1>;
355 interrupts = <21 2 0 0>;
356 };
357 dma-channel@100 {
358 compatible = "fsl,eloplus-dma-channel";
359 reg = <0x100 0x80>;
360 cell-index = <2>;
361 interrupts = <22 2 0 0>;
362 };
363 dma-channel@180 {
364 compatible = "fsl,eloplus-dma-channel";
365 reg = <0x180 0x80>;
366 cell-index = <3>;
367 interrupts = <23 2 0 0>;
368 };
369 };
370
371 usb@22000 {
372 #address-cells = <1>;
373 #size-cells = <0>;
374 compatible = "fsl-usb2-dr";
375 reg = <0x22000 0x1000>;
376 interrupts = <28 0x2 0 0>;
377 phy_type = "ulpi";
378 };
379
380 mdio@24000 {
381 #address-cells = <1>;
382 #size-cells = <0>;
383 compatible = "fsl,etsec2-mdio";
384 reg = <0x24000 0x1000 0xb0030 0x4>;
385
386 phy0: ethernet-phy@0 {
387 interrupts = <3 1 0 0>;
388 reg = <0x1>;
389 };
390 phy1: ethernet-phy@1 {
391 interrupts = <9 1 0 0>;
392 reg = <0x2>;
393 };
394 };
395
396 mdio@25000 {
397 #address-cells = <1>;
398 #size-cells = <0>;
399 compatible = "fsl,etsec2-mdio";
400 reg = <0x25000 0x1000 0xb1030 0x4>;
401 };
402
403 enet0: ethernet@B0000 {
404 #address-cells = <1>;
405 #size-cells = <1>;
406 cell-index = <0>;
407 device_type = "network";
408 model = "eTSEC";
409 compatible = "fsl,etsec2";
410 fsl,num_rx_queues = <0x8>;
411 fsl,num_tx_queues = <0x8>;
412 fsl,magic-packet;
413 fsl,wake-on-filer;
414 local-mac-address = [ 00 00 00 00 00 00 ];
415 phy-handle = <&phy0>;
416 phy-connection-type = "rgmii-id";
417 queue-group@0{
418 #address-cells = <1>;
419 #size-cells = <1>;
420 reg = <0xB0000 0x1000>;
421 interrupts = <29 2 0 0 30 2 0 0 34 2 0 0>;
422 };
423 queue-group@1{
424 #address-cells = <1>;
425 #size-cells = <1>;
426 reg = <0xB4000 0x1000>;
427 interrupts = <17 2 0 0 18 2 0 0 24 2 0 0>;
428 };
429 };
430
431 enet1: ethernet@B1000 {
432 #address-cells = <1>;
433 #size-cells = <1>;
434 cell-index = <0>;
435 device_type = "network";
436 model = "eTSEC";
437 compatible = "fsl,etsec2";
438 fsl,num_rx_queues = <0x8>;
439 fsl,num_tx_queues = <0x8>;
440 local-mac-address = [ 00 00 00 00 00 00 ];
441 phy-handle = <&phy1>;
442 phy-connection-type = "rgmii-id";
443 queue-group@0{
444 #address-cells = <1>;
445 #size-cells = <1>;
446 reg = <0xB1000 0x1000>;
447 interrupts = <35 2 0 0 36 2 0 0 40 2 0 0>;
448 };
449 queue-group@1{
450 #address-cells = <1>;
451 #size-cells = <1>;
452 reg = <0xB5000 0x1000>;
453 interrupts = <51 2 0 0 52 2 0 0 67 2 0 0>;
454 };
455 };
456
457 sdhci@2e000 {
458 compatible = "fsl,p1022-esdhc", "fsl,esdhc";
459 reg = <0x2e000 0x1000>;
460 interrupts = <72 0x2 0 0>;
461 fsl,sdhci-auto-cmd12;
462 /* Filled in by U-Boot */
463 clock-frequency = <0>;
464 };
465
466 crypto@30000 {
467 compatible = "fsl,sec3.3", "fsl,sec3.1", "fsl,sec3.0",
468 "fsl,sec2.4", "fsl,sec2.2", "fsl,sec2.1",
469 "fsl,sec2.0";
470 reg = <0x30000 0x10000>;
471 interrupts = <45 2 0 0 58 2 0 0>;
472 fsl,num-channels = <4>;
473 fsl,channel-fifo-len = <24>;
474 fsl,exec-units-mask = <0x97c>;
475 fsl,descriptor-types-mask = <0x3a30abf>;
476 };
477
478 sata@18000 {
479 compatible = "fsl,p1022-sata", "fsl,pq-sata-v2";
480 reg = <0x18000 0x1000>;
481 cell-index = <1>;
482 interrupts = <74 0x2 0 0>;
483 };
484
485 sata@19000 {
486 compatible = "fsl,p1022-sata", "fsl,pq-sata-v2";
487 reg = <0x19000 0x1000>;
488 cell-index = <2>;
489 interrupts = <41 0x2 0 0>;
490 };
491
492 power@e0070{
493 compatible = "fsl,mpc8536-pmc", "fsl,mpc8548-pmc";
494 reg = <0xe0070 0x20>;
495 };
496
497 display@10000 {
498 compatible = "fsl,diu", "fsl,p1022-diu";
499 reg = <0x10000 1000>;
500 interrupts = <64 2 0 0>;
501 };
502
503 timer@41100 {
504 compatible = "fsl,mpic-global-timer";
505 reg = <0x41100 0x100 0x41300 4>;
506 interrupts = <0 0 3 0
507 1 0 3 0
508 2 0 3 0
509 3 0 3 0>;
510 };
511
512 timer@42100 {
513 compatible = "fsl,mpic-global-timer";
514 reg = <0x42100 0x100 0x42300 4>;
515 interrupts = <4 0 3 0
516 5 0 3 0
517 6 0 3 0
518 7 0 3 0>;
519 };
520
521 mpic: pic@40000 {
522 interrupt-controller;
523 #address-cells = <0>;
524 #interrupt-cells = <4>;
525 reg = <0x40000 0x40000>;
526 compatible = "fsl,mpic";
527 device_type = "open-pic";
528 };
529
530 msi@41600 {
531 compatible = "fsl,p1022-msi", "fsl,mpic-msi";
532 reg = <0x41600 0x80>;
533 msi-available-ranges = <0 0x100>;
534 interrupts = <
535 0xe0 0 0 0
536 0xe1 0 0 0
537 0xe2 0 0 0
538 0xe3 0 0 0
539 0xe4 0 0 0
540 0xe5 0 0 0
541 0xe6 0 0 0
542 0xe7 0 0 0>;
543 };
544
545 global-utilities@e0000 { //global utilities block
546 compatible = "fsl,p1022-guts";
547 reg = <0xe0000 0x1000>;
548 fsl,has-rstcr;
549 };
550 };
551
552 pci0: pcie@fffe09000 {
553 compatible = "fsl,p1022-pcie";
554 device_type = "pci";
555 #interrupt-cells = <1>;
556 #size-cells = <2>;
557 #address-cells = <3>;
558 reg = <0xf 0xffe09000 0 0x1000>;
559 bus-range = <0 255>;
560 ranges = <0x2000000 0x0 0xa0000000 0xc 0x20000000 0x0 0x20000000
561 0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>;
562 clock-frequency = <33333333>;
563 interrupts = <16 2 0 0>;
564 interrupt-map-mask = <0xf800 0 0 7>;
565 interrupt-map = <
566 /* IDSEL 0x0 */
567 0000 0 0 1 &mpic 4 1
568 0000 0 0 2 &mpic 5 1
569 0000 0 0 3 &mpic 6 1
570 0000 0 0 4 &mpic 7 1
571 >;
572 pcie@0 {
573 reg = <0x0 0x0 0x0 0x0 0x0>;
574 #size-cells = <2>;
575 #address-cells = <3>;
576 device_type = "pci";
577 ranges = <0x2000000 0x0 0xe0000000
578 0x2000000 0x0 0xe0000000
579 0x0 0x20000000
580
581 0x1000000 0x0 0x0
582 0x1000000 0x0 0x0
583 0x0 0x100000>;
584 };
585 };
586
587 pci1: pcie@fffe0a000 {
588 compatible = "fsl,p1022-pcie";
589 device_type = "pci";
590 #interrupt-cells = <1>;
591 #size-cells = <2>;
592 #address-cells = <3>;
593 reg = <0xf 0xffe0a000 0 0x1000>;
594 bus-range = <0 255>;
595 ranges = <0x2000000 0x0 0xc0000000 0xc 0x40000000 0x0 0x20000000
596 0x1000000 0x0 0x00000000 0xf 0xffc20000 0x0 0x10000>;
597 clock-frequency = <33333333>;
598 interrupts = <16 2 0 0>;
599 interrupt-map-mask = <0xf800 0 0 7>;
600 interrupt-map = <
601 /* IDSEL 0x0 */
602 0000 0 0 1 &mpic 0 1
603 0000 0 0 2 &mpic 1 1
604 0000 0 0 3 &mpic 2 1
605 0000 0 0 4 &mpic 3 1
606 >;
607 pcie@0 {
608 reg = <0x0 0x0 0x0 0x0 0x0>;
609 #size-cells = <2>;
610 #address-cells = <3>;
611 device_type = "pci";
612 ranges = <0x2000000 0x0 0xe0000000
613 0x2000000 0x0 0xe0000000
614 0x0 0x20000000
615
616 0x1000000 0x0 0x0
617 0x1000000 0x0 0x0
618 0x0 0x100000>;
619 };
620 };
621
622
623 pci2: pcie@fffe0b000 {
624 compatible = "fsl,p1022-pcie";
625 device_type = "pci";
626 #interrupt-cells = <1>;
627 #size-cells = <2>;
628 #address-cells = <3>;
629 reg = <0xf 0xffe0b000 0 0x1000>;
630 bus-range = <0 255>;
631 ranges = <0x2000000 0x0 0x80000000 0xc 0x00000000 0x0 0x20000000
632 0x1000000 0x0 0x00000000 0xf 0xffc00000 0x0 0x10000>;
633 clock-frequency = <33333333>;
634 interrupts = <16 2 0 0>;
635 interrupt-map-mask = <0xf800 0 0 7>;
636 interrupt-map = <
637 /* IDSEL 0x0 */
638 0000 0 0 1 &mpic 8 1
639 0000 0 0 2 &mpic 9 1
640 0000 0 0 3 &mpic 10 1
641 0000 0 0 4 &mpic 11 1
642 >;
643 pcie@0 {
644 reg = <0x0 0x0 0x0 0x0 0x0>;
645 #size-cells = <2>;
646 #address-cells = <3>;
647 device_type = "pci";
648 ranges = <0x2000000 0x0 0xe0000000
649 0x2000000 0x0 0xe0000000
650 0x0 0x20000000
651
652 0x1000000 0x0 0x0
653 0x1000000 0x0 0x0
654 0x0 0x100000>;
655 };
656 };
657};
diff --git a/arch/powerpc/boot/dts/p2020rdb_camp_core0.dts b/arch/powerpc/boot/dts/p2020rdb_camp_core0.dts
new file mode 100644
index 00000000000..fc8ddddfccb
--- /dev/null
+++ b/arch/powerpc/boot/dts/p2020rdb_camp_core0.dts
@@ -0,0 +1,204 @@
1/*
2 * P2020 RDB Core0 Device Tree Source in CAMP mode.
3 *
4 * In CAMP mode, each core needs to have its own dts. Only mpic and L2 cache
5 * can be shared, all the other devices must be assigned to one core only.
6 * This dts file allows core0 to have memory, l2, i2c, spi, gpio, dma1, usb,
7 * eth1, eth2, sdhc, crypto, global-util, pci0.
8 *
9 * Copyright 2009-2011 Freescale Semiconductor Inc.
10 *
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the
13 * Free Software Foundation; either version 2 of the License, or (at your
14 * option) any later version.
15 */
16
17/include/ "p2020si.dtsi"
18
19/ {
20 model = "fsl,P2020RDB";
21 compatible = "fsl,P2020RDB", "fsl,MPC85XXRDB-CAMP";
22
23 aliases {
24 ethernet1 = &enet1;
25 ethernet2 = &enet2;
26 serial0 = &serial0;
27 pci0 = &pci0;
28 };
29
30 cpus {
31 PowerPC,P2020@1 {
32 status = "disabled";
33 };
34
35 };
36
37 memory {
38 device_type = "memory";
39 };
40
41 localbus@ffe05000 {
42 status = "disabled";
43 };
44
45 soc@ffe00000 {
46 i2c@3000 {
47 rtc@68 {
48 compatible = "dallas,ds1339";
49 reg = <0x68>;
50 };
51 };
52
53 serial1: serial@4600 {
54 status = "disabled";
55 };
56
57 spi@7000 {
58
59 fsl_m25p80@0 {
60 #address-cells = <1>;
61 #size-cells = <1>;
62 compatible = "fsl,espi-flash";
63 reg = <0>;
64 linux,modalias = "fsl_m25p80";
65 modal = "s25sl128b";
66 spi-max-frequency = <50000000>;
67 mode = <0>;
68
69 partition@0 {
70 /* 512KB for u-boot Bootloader Image */
71 reg = <0x0 0x00080000>;
72 label = "SPI (RO) U-Boot Image";
73 read-only;
74 };
75
76 partition@80000 {
77 /* 512KB for DTB Image */
78 reg = <0x00080000 0x00080000>;
79 label = "SPI (RO) DTB Image";
80 read-only;
81 };
82
83 partition@100000 {
84 /* 4MB for Linux Kernel Image */
85 reg = <0x00100000 0x00400000>;
86 label = "SPI (RO) Linux Kernel Image";
87 read-only;
88 };
89
90 partition@500000 {
91 /* 4MB for Compressed RFS Image */
92 reg = <0x00500000 0x00400000>;
93 label = "SPI (RO) Compressed RFS Image";
94 read-only;
95 };
96
97 partition@900000 {
98 /* 7MB for JFFS2 based RFS */
99 reg = <0x00900000 0x00700000>;
100 label = "SPI (RW) JFFS2 RFS";
101 };
102 };
103 };
104
105 dma@c300 {
106 status = "disabled";
107 };
108
109 usb@22000 {
110 phy_type = "ulpi";
111 };
112
113 mdio@24520 {
114
115 phy0: ethernet-phy@0 {
116 interrupt-parent = <&mpic>;
117 interrupts = <3 1>;
118 reg = <0x0>;
119 };
120 phy1: ethernet-phy@1 {
121 interrupt-parent = <&mpic>;
122 interrupts = <3 1>;
123 reg = <0x1>;
124 };
125 };
126
127 mdio@25520 {
128 tbi0: tbi-phy@11 {
129 reg = <0x11>;
130 device_type = "tbi-phy";
131 };
132 };
133
134 mdio@26520 {
135 status = "disabled";
136 };
137
138 enet0: ethernet@24000 {
139 status = "disabled";
140 };
141
142 enet1: ethernet@25000 {
143 tbi-handle = <&tbi0>;
144 phy-handle = <&phy0>;
145 phy-connection-type = "sgmii";
146
147 };
148
149 enet2: ethernet@26000 {
150 phy-handle = <&phy1>;
151 phy-connection-type = "rgmii-id";
152 };
153
154
155 mpic: pic@40000 {
156 protected-sources = <
157 42 76 77 78 79 /* serial1 , dma2 */
158 29 30 34 26 /* enet0, pci1 */
159 0xe0 0xe1 0xe2 0xe3 /* msi */
160 0xe4 0xe5 0xe6 0xe7
161 >;
162 };
163
164 msi@41600 {
165 status = "disabled";
166 };
167
168
169 };
170
171 pci0: pcie@ffe08000 {
172 status = "disabled";
173 };
174
175 pci1: pcie@ffe09000 {
176 ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000
177 0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>;
178 interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
179 interrupt-map = <
180 /* IDSEL 0x0 */
181 0000 0x0 0x0 0x1 &mpic 0x4 0x1
182 0000 0x0 0x0 0x2 &mpic 0x5 0x1
183 0000 0x0 0x0 0x3 &mpic 0x6 0x1
184 0000 0x0 0x0 0x4 &mpic 0x7 0x1
185 >;
186 pcie@0 {
187 reg = <0x0 0x0 0x0 0x0 0x0>;
188 #size-cells = <2>;
189 #address-cells = <3>;
190 device_type = "pci";
191 ranges = <0x2000000 0x0 0xa0000000
192 0x2000000 0x0 0xa0000000
193 0x0 0x20000000
194
195 0x1000000 0x0 0x0
196 0x1000000 0x0 0x0
197 0x0 0x100000>;
198 };
199 };
200
201 pci2: pcie@ffe0a000 {
202 status = "disabled";
203 };
204};
diff --git a/arch/powerpc/boot/dts/p2020rdb_camp_core1.dts b/arch/powerpc/boot/dts/p2020rdb_camp_core1.dts
new file mode 100644
index 00000000000..261c34ba45e
--- /dev/null
+++ b/arch/powerpc/boot/dts/p2020rdb_camp_core1.dts
@@ -0,0 +1,228 @@
1/*
2 * P2020 RDB Core1 Device Tree Source in CAMP mode.
3 *
4 * In CAMP mode, each core needs to have its own dts. Only mpic and L2 cache
5 * can be shared, all the other devices must be assigned to one core only.
6 * This dts allows core1 to have l2, dma2, eth0, pci1, msi.
7 *
8 * Please note to add "-b 1" for core1's dts compiling.
9 *
10 * Copyright 2009-2011 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/ "p2020si.dtsi"
19
20/ {
21 model = "fsl,P2020RDB";
22 compatible = "fsl,P2020RDB", "fsl,MPC85XXRDB-CAMP";
23
24 aliases {
25 ethernet0 = &enet0;
26 serial0 = &serial1;
27 pci1 = &pci1;
28 };
29
30 cpus {
31 PowerPC,P2020@0 {
32 status = "disabled";
33 };
34 };
35
36 memory {
37 device_type = "memory";
38 };
39
40 localbus@ffe05000 {
41 status = "disabled";
42 };
43
44 soc@ffe00000 {
45 ecm-law@0 {
46 status = "disabled";
47 };
48
49 ecm@1000 {
50 status = "disabled";
51 };
52
53 memory-controller@2000 {
54 status = "disabled";
55 };
56
57 i2c@3000 {
58 status = "disabled";
59 };
60
61 i2c@3100 {
62 status = "disabled";
63 };
64
65 serial0: serial@4500 {
66 status = "disabled";
67 };
68
69 spi@7000 {
70 status = "disabled";
71 };
72
73 dma@c300 {
74 #address-cells = <1>;
75 #size-cells = <1>;
76 compatible = "fsl,eloplus-dma";
77 reg = <0xc300 0x4>;
78 ranges = <0x0 0xc100 0x200>;
79 cell-index = <1>;
80 dma-channel@0 {
81 compatible = "fsl,eloplus-dma-channel";
82 reg = <0x0 0x80>;
83 cell-index = <0>;
84 interrupt-parent = <&mpic>;
85 interrupts = <76 2>;
86 };
87 dma-channel@80 {
88 compatible = "fsl,eloplus-dma-channel";
89 reg = <0x80 0x80>;
90 cell-index = <1>;
91 interrupt-parent = <&mpic>;
92 interrupts = <77 2>;
93 };
94 dma-channel@100 {
95 compatible = "fsl,eloplus-dma-channel";
96 reg = <0x100 0x80>;
97 cell-index = <2>;
98 interrupt-parent = <&mpic>;
99 interrupts = <78 2>;
100 };
101 dma-channel@180 {
102 compatible = "fsl,eloplus-dma-channel";
103 reg = <0x180 0x80>;
104 cell-index = <3>;
105 interrupt-parent = <&mpic>;
106 interrupts = <79 2>;
107 };
108 };
109
110 gpio: gpio-controller@f000 {
111 status = "disabled";
112 };
113
114 L2: l2-cache-controller@20000 {
115 compatible = "fsl,p2020-l2-cache-controller";
116 reg = <0x20000 0x1000>;
117 cache-line-size = <32>; // 32 bytes
118 cache-size = <0x80000>; // L2,512K
119 interrupt-parent = <&mpic>;
120 };
121
122 dma@21300 {
123 status = "disabled";
124 };
125
126 usb@22000 {
127 status = "disabled";
128 };
129
130 mdio@24520 {
131 status = "disabled";
132 };
133
134 mdio@25520 {
135 status = "disabled";
136 };
137
138 mdio@26520 {
139 status = "disabled";
140 };
141
142 enet0: ethernet@24000 {
143 fixed-link = <1 1 1000 0 0>;
144 phy-connection-type = "rgmii-id";
145
146 };
147
148 enet1: ethernet@25000 {
149 status = "disabled";
150 };
151
152 enet2: ethernet@26000 {
153 status = "disabled";
154 };
155
156 sdhci@2e000 {
157 status = "disabled";
158 };
159
160 crypto@30000 {
161 status = "disabled";
162 };
163
164 mpic: pic@40000 {
165 protected-sources = <
166 17 18 43 42 59 47 /*ecm, mem, i2c, serial0, spi,gpio */
167 16 20 21 22 23 28 /* L2, dma1, USB */
168 03 35 36 40 31 32 33 /* mdio, enet1, enet2 */
169 72 45 58 25 /* sdhci, crypto , pci */
170 >;
171 };
172
173 msi@41600 {
174 compatible = "fsl,p2020-msi", "fsl,mpic-msi";
175 reg = <0x41600 0x80>;
176 msi-available-ranges = <0 0x100>;
177 interrupts = <
178 0xe0 0
179 0xe1 0
180 0xe2 0
181 0xe3 0
182 0xe4 0
183 0xe5 0
184 0xe6 0
185 0xe7 0>;
186 interrupt-parent = <&mpic>;
187 };
188
189 global-utilities@e0000 { //global utilities block
190 status = "disabled";
191 };
192
193 };
194
195 pci0: pcie@ffe08000 {
196 status = "disabled";
197 };
198
199 pci1: pcie@ffe09000 {
200 status = "disabled";
201 };
202
203 pci2: pcie@ffe0a000 {
204 ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000
205 0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>;
206 interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
207 interrupt-map = <
208 /* IDSEL 0x0 */
209 0000 0x0 0x0 0x1 &mpic 0x0 0x1
210 0000 0x0 0x0 0x2 &mpic 0x1 0x1
211 0000 0x0 0x0 0x3 &mpic 0x2 0x1
212 0000 0x0 0x0 0x4 &mpic 0x3 0x1
213 >;
214 pcie@0 {
215 reg = <0x0 0x0 0x0 0x0 0x0>;
216 #size-cells = <2>;
217 #address-cells = <3>;
218 device_type = "pci";
219 ranges = <0x2000000 0x0 0x80000000
220 0x2000000 0x0 0x80000000
221 0x0 0x20000000
222
223 0x1000000 0x0 0x0
224 0x1000000 0x0 0x0
225 0x0 0x100000>;
226 };
227 };
228};
diff --git a/arch/powerpc/boot/dts/p2020si.dtsi b/arch/powerpc/boot/dts/p2020si.dtsi
new file mode 100644
index 00000000000..6def17f265d
--- /dev/null
+++ b/arch/powerpc/boot/dts/p2020si.dtsi
@@ -0,0 +1,382 @@
1/*
2 * P2020 Device Tree Source
3 *
4 * Copyright 2011 Freescale Semiconductor Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version.
10 */
11
12/dts-v1/;
13/ {
14 compatible = "fsl,P2020";
15 #address-cells = <2>;
16 #size-cells = <2>;
17
18 cpus {
19 #address-cells = <1>;
20 #size-cells = <0>;
21
22 PowerPC,P2020@0 {
23 device_type = "cpu";
24 reg = <0x0>;
25 next-level-cache = <&L2>;
26 };
27
28 PowerPC,P2020@1 {
29 device_type = "cpu";
30 reg = <0x1>;
31 next-level-cache = <&L2>;
32 };
33 };
34
35 localbus@ffe05000 {
36 #address-cells = <2>;
37 #size-cells = <1>;
38 compatible = "fsl,p2020-elbc", "fsl,elbc", "simple-bus";
39 reg = <0 0xffe05000 0 0x1000>;
40 interrupts = <19 2>;
41 interrupt-parent = <&mpic>;
42 };
43
44 soc@ffe00000 {
45 #address-cells = <1>;
46 #size-cells = <1>;
47 device_type = "soc";
48 compatible = "fsl,p2020-immr", "simple-bus";
49 ranges = <0x0 0x0 0xffe00000 0x100000>;
50 bus-frequency = <0>; // Filled out by uboot.
51
52 ecm-law@0 {
53 compatible = "fsl,ecm-law";
54 reg = <0x0 0x1000>;
55 fsl,num-laws = <12>;
56 };
57
58 ecm@1000 {
59 compatible = "fsl,p2020-ecm", "fsl,ecm";
60 reg = <0x1000 0x1000>;
61 interrupts = <17 2>;
62 interrupt-parent = <&mpic>;
63 };
64
65 memory-controller@2000 {
66 compatible = "fsl,p2020-memory-controller";
67 reg = <0x2000 0x1000>;
68 interrupt-parent = <&mpic>;
69 interrupts = <18 2>;
70 };
71
72 i2c@3000 {
73 #address-cells = <1>;
74 #size-cells = <0>;
75 cell-index = <0>;
76 compatible = "fsl-i2c";
77 reg = <0x3000 0x100>;
78 interrupts = <43 2>;
79 interrupt-parent = <&mpic>;
80 dfsrr;
81 };
82
83 i2c@3100 {
84 #address-cells = <1>;
85 #size-cells = <0>;
86 cell-index = <1>;
87 compatible = "fsl-i2c";
88 reg = <0x3100 0x100>;
89 interrupts = <43 2>;
90 interrupt-parent = <&mpic>;
91 dfsrr;
92 };
93
94 serial0: serial@4500 {
95 cell-index = <0>;
96 device_type = "serial";
97 compatible = "ns16550";
98 reg = <0x4500 0x100>;
99 clock-frequency = <0>;
100 interrupts = <42 2>;
101 interrupt-parent = <&mpic>;
102 };
103
104 serial1: serial@4600 {
105 cell-index = <1>;
106 device_type = "serial";
107 compatible = "ns16550";
108 reg = <0x4600 0x100>;
109 clock-frequency = <0>;
110 interrupts = <42 2>;
111 interrupt-parent = <&mpic>;
112 };
113
114 spi@7000 {
115 cell-index = <0>;
116 #address-cells = <1>;
117 #size-cells = <0>;
118 compatible = "fsl,espi";
119 reg = <0x7000 0x1000>;
120 interrupts = <59 0x2>;
121 interrupt-parent = <&mpic>;
122 mode = "cpu";
123 };
124
125 dma@c300 {
126 #address-cells = <1>;
127 #size-cells = <1>;
128 compatible = "fsl,eloplus-dma";
129 reg = <0xc300 0x4>;
130 ranges = <0x0 0xc100 0x200>;
131 cell-index = <1>;
132 dma-channel@0 {
133 compatible = "fsl,eloplus-dma-channel";
134 reg = <0x0 0x80>;
135 cell-index = <0>;
136 interrupt-parent = <&mpic>;
137 interrupts = <76 2>;
138 };
139 dma-channel@80 {
140 compatible = "fsl,eloplus-dma-channel";
141 reg = <0x80 0x80>;
142 cell-index = <1>;
143 interrupt-parent = <&mpic>;
144 interrupts = <77 2>;
145 };
146 dma-channel@100 {
147 compatible = "fsl,eloplus-dma-channel";
148 reg = <0x100 0x80>;
149 cell-index = <2>;
150 interrupt-parent = <&mpic>;
151 interrupts = <78 2>;
152 };
153 dma-channel@180 {
154 compatible = "fsl,eloplus-dma-channel";
155 reg = <0x180 0x80>;
156 cell-index = <3>;
157 interrupt-parent = <&mpic>;
158 interrupts = <79 2>;
159 };
160 };
161
162 gpio: gpio-controller@f000 {
163 #gpio-cells = <2>;
164 compatible = "fsl,mpc8572-gpio";
165 reg = <0xf000 0x100>;
166 interrupts = <47 0x2>;
167 interrupt-parent = <&mpic>;
168 gpio-controller;
169 };
170
171 L2: l2-cache-controller@20000 {
172 compatible = "fsl,p2020-l2-cache-controller";
173 reg = <0x20000 0x1000>;
174 cache-line-size = <32>; // 32 bytes
175 cache-size = <0x80000>; // L2,512K
176 interrupt-parent = <&mpic>;
177 interrupts = <16 2>;
178 };
179
180 dma@21300 {
181 #address-cells = <1>;
182 #size-cells = <1>;
183 compatible = "fsl,eloplus-dma";
184 reg = <0x21300 0x4>;
185 ranges = <0x0 0x21100 0x200>;
186 cell-index = <0>;
187 dma-channel@0 {
188 compatible = "fsl,eloplus-dma-channel";
189 reg = <0x0 0x80>;
190 cell-index = <0>;
191 interrupt-parent = <&mpic>;
192 interrupts = <20 2>;
193 };
194 dma-channel@80 {
195 compatible = "fsl,eloplus-dma-channel";
196 reg = <0x80 0x80>;
197 cell-index = <1>;
198 interrupt-parent = <&mpic>;
199 interrupts = <21 2>;
200 };
201 dma-channel@100 {
202 compatible = "fsl,eloplus-dma-channel";
203 reg = <0x100 0x80>;
204 cell-index = <2>;
205 interrupt-parent = <&mpic>;
206 interrupts = <22 2>;
207 };
208 dma-channel@180 {
209 compatible = "fsl,eloplus-dma-channel";
210 reg = <0x180 0x80>;
211 cell-index = <3>;
212 interrupt-parent = <&mpic>;
213 interrupts = <23 2>;
214 };
215 };
216
217 usb@22000 {
218 #address-cells = <1>;
219 #size-cells = <0>;
220 compatible = "fsl-usb2-dr";
221 reg = <0x22000 0x1000>;
222 interrupt-parent = <&mpic>;
223 interrupts = <28 0x2>;
224 };
225
226 mdio@24520 {
227 #address-cells = <1>;
228 #size-cells = <0>;
229 compatible = "fsl,gianfar-mdio";
230 reg = <0x24520 0x20>;
231 };
232
233 mdio@25520 {
234 #address-cells = <1>;
235 #size-cells = <0>;
236 compatible = "fsl,gianfar-tbi";
237 reg = <0x26520 0x20>;
238 };
239
240 mdio@26520 {
241 #address-cells = <1>;
242 #size-cells = <0>;
243 compatible = "fsl,gianfar-tbi";
244 reg = <0x520 0x20>;
245 };
246
247 enet0: ethernet@24000 {
248 #address-cells = <1>;
249 #size-cells = <1>;
250 cell-index = <0>;
251 device_type = "network";
252 model = "eTSEC";
253 compatible = "gianfar";
254 reg = <0x24000 0x1000>;
255 ranges = <0x0 0x24000 0x1000>;
256 local-mac-address = [ 00 00 00 00 00 00 ];
257 interrupts = <29 2 30 2 34 2>;
258 interrupt-parent = <&mpic>;
259 };
260
261 enet1: ethernet@25000 {
262 #address-cells = <1>;
263 #size-cells = <1>;
264 cell-index = <1>;
265 device_type = "network";
266 model = "eTSEC";
267 compatible = "gianfar";
268 reg = <0x25000 0x1000>;
269 ranges = <0x0 0x25000 0x1000>;
270 local-mac-address = [ 00 00 00 00 00 00 ];
271 interrupts = <35 2 36 2 40 2>;
272 interrupt-parent = <&mpic>;
273
274 };
275
276 enet2: ethernet@26000 {
277 #address-cells = <1>;
278 #size-cells = <1>;
279 cell-index = <2>;
280 device_type = "network";
281 model = "eTSEC";
282 compatible = "gianfar";
283 reg = <0x26000 0x1000>;
284 ranges = <0x0 0x26000 0x1000>;
285 local-mac-address = [ 00 00 00 00 00 00 ];
286 interrupts = <31 2 32 2 33 2>;
287 interrupt-parent = <&mpic>;
288
289 };
290
291 sdhci@2e000 {
292 compatible = "fsl,p2020-esdhc", "fsl,esdhc";
293 reg = <0x2e000 0x1000>;
294 interrupts = <72 0x2>;
295 interrupt-parent = <&mpic>;
296 /* Filled in by U-Boot */
297 clock-frequency = <0>;
298 };
299
300 crypto@30000 {
301 compatible = "fsl,sec3.1", "fsl,sec3.0", "fsl,sec2.4",
302 "fsl,sec2.2", "fsl,sec2.1", "fsl,sec2.0";
303 reg = <0x30000 0x10000>;
304 interrupts = <45 2 58 2>;
305 interrupt-parent = <&mpic>;
306 fsl,num-channels = <4>;
307 fsl,channel-fifo-len = <24>;
308 fsl,exec-units-mask = <0xbfe>;
309 fsl,descriptor-types-mask = <0x3ab0ebf>;
310 };
311
312 mpic: pic@40000 {
313 interrupt-controller;
314 #address-cells = <0>;
315 #interrupt-cells = <2>;
316 reg = <0x40000 0x40000>;
317 compatible = "chrp,open-pic";
318 device_type = "open-pic";
319 };
320
321 msi@41600 {
322 compatible = "fsl,p2020-msi", "fsl,mpic-msi";
323 reg = <0x41600 0x80>;
324 msi-available-ranges = <0 0x100>;
325 interrupts = <
326 0xe0 0
327 0xe1 0
328 0xe2 0
329 0xe3 0
330 0xe4 0
331 0xe5 0
332 0xe6 0
333 0xe7 0>;
334 interrupt-parent = <&mpic>;
335 };
336
337 global-utilities@e0000 { //global utilities block
338 compatible = "fsl,p2020-guts";
339 reg = <0xe0000 0x1000>;
340 fsl,has-rstcr;
341 };
342 };
343
344 pci0: pcie@ffe08000 {
345 compatible = "fsl,mpc8548-pcie";
346 device_type = "pci";
347 #interrupt-cells = <1>;
348 #size-cells = <2>;
349 #address-cells = <3>;
350 reg = <0 0xffe08000 0 0x1000>;
351 bus-range = <0 255>;
352 clock-frequency = <33333333>;
353 interrupt-parent = <&mpic>;
354 interrupts = <24 2>;
355 };
356
357 pci1: pcie@ffe09000 {
358 compatible = "fsl,mpc8548-pcie";
359 device_type = "pci";
360 #interrupt-cells = <1>;
361 #size-cells = <2>;
362 #address-cells = <3>;
363 reg = <0 0xffe09000 0 0x1000>;
364 bus-range = <0 255>;
365 clock-frequency = <33333333>;
366 interrupt-parent = <&mpic>;
367 interrupts = <25 2>;
368 };
369
370 pci2: pcie@ffe0a000 {
371 compatible = "fsl,mpc8548-pcie";
372 device_type = "pci";
373 #interrupt-cells = <1>;
374 #size-cells = <2>;
375 #address-cells = <3>;
376 reg = <0 0xffe0a000 0 0x1000>;
377 bus-range = <0 255>;
378 clock-frequency = <33333333>;
379 interrupt-parent = <&mpic>;
380 interrupts = <26 2>;
381 };
382};
diff --git a/arch/powerpc/boot/dts/p2040rdb.dts b/arch/powerpc/boot/dts/p2040rdb.dts
new file mode 100644
index 00000000000..7d84e391c63
--- /dev/null
+++ b/arch/powerpc/boot/dts/p2040rdb.dts
@@ -0,0 +1,166 @@
1/*
2 * P2040RDB 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/ "p2040si.dtsi"
36
37/ {
38 model = "fsl,P2040RDB";
39 compatible = "fsl,P2040RDB";
40 #address-cells = <2>;
41 #size-cells = <2>;
42 interrupt-parent = <&mpic>;
43
44 memory {
45 device_type = "memory";
46 };
47
48 soc: soc@ffe000000 {
49 spi@110000 {
50 flash@0 {
51 #address-cells = <1>;
52 #size-cells = <1>;
53 compatible = "spansion,s25sl12801";
54 reg = <0>;
55 spi-max-frequency = <40000000>; /* input clock */
56 partition@u-boot {
57 label = "u-boot";
58 reg = <0x00000000 0x00100000>;
59 read-only;
60 };
61 partition@kernel {
62 label = "kernel";
63 reg = <0x00100000 0x00500000>;
64 read-only;
65 };
66 partition@dtb {
67 label = "dtb";
68 reg = <0x00600000 0x00100000>;
69 read-only;
70 };
71 partition@fs {
72 label = "file system";
73 reg = <0x00700000 0x00900000>;
74 };
75 };
76 };
77
78 i2c@118000 {
79 lm75b@48 {
80 compatible = "nxp,lm75a";
81 reg = <0x48>;
82 };
83 eeprom@50 {
84 compatible = "at24,24c256";
85 reg = <0x50>;
86 };
87 rtc@68 {
88 compatible = "pericom,pt7c4338";
89 reg = <0x68>;
90 };
91 };
92
93 i2c@118100 {
94 eeprom@50 {
95 compatible = "at24,24c256";
96 reg = <0x50>;
97 };
98 };
99
100 usb0: usb@210000 {
101 phy_type = "utmi";
102 };
103
104 usb1: usb@211000 {
105 dr_mode = "host";
106 phy_type = "utmi";
107 };
108 };
109
110 localbus@ffe124000 {
111 reg = <0xf 0xfe124000 0 0x1000>;
112 ranges = <0 0 0xf 0xe8000000 0x08000000>;
113
114 flash@0,0 {
115 compatible = "cfi-flash";
116 reg = <0 0 0x08000000>;
117 bank-width = <2>;
118 device-width = <2>;
119 };
120 };
121
122 pci0: pcie@ffe200000 {
123 reg = <0xf 0xfe200000 0 0x1000>;
124 ranges = <0x02000000 0 0xe0000000 0xc 0x00000000 0x0 0x20000000
125 0x01000000 0 0x00000000 0xf 0xf8000000 0x0 0x00010000>;
126 pcie@0 {
127 ranges = <0x02000000 0 0xe0000000
128 0x02000000 0 0xe0000000
129 0 0x20000000
130
131 0x01000000 0 0x00000000
132 0x01000000 0 0x00000000
133 0 0x00010000>;
134 };
135 };
136
137 pci1: pcie@ffe201000 {
138 reg = <0xf 0xfe201000 0 0x1000>;
139 ranges = <0x02000000 0x0 0xe0000000 0xc 0x20000000 0x0 0x20000000
140 0x01000000 0x0 0x00000000 0xf 0xf8010000 0x0 0x00010000>;
141 pcie@0 {
142 ranges = <0x02000000 0 0xe0000000
143 0x02000000 0 0xe0000000
144 0 0x20000000
145
146 0x01000000 0 0x00000000
147 0x01000000 0 0x00000000
148 0 0x00010000>;
149 };
150 };
151
152 pci2: pcie@ffe202000 {
153 reg = <0xf 0xfe202000 0 0x1000>;
154 ranges = <0x02000000 0 0xe0000000 0xc 0x40000000 0 0x20000000
155 0x01000000 0 0x00000000 0xf 0xf8020000 0 0x00010000>;
156 pcie@0 {
157 ranges = <0x02000000 0 0xe0000000
158 0x02000000 0 0xe0000000
159 0 0x20000000
160
161 0x01000000 0 0x00000000
162 0x01000000 0 0x00000000
163 0 0x00010000>;
164 };
165 };
166};
diff --git a/arch/powerpc/boot/dts/p2040si.dtsi b/arch/powerpc/boot/dts/p2040si.dtsi
new file mode 100644
index 00000000000..5fdbb24c076
--- /dev/null
+++ b/arch/powerpc/boot/dts/p2040si.dtsi
@@ -0,0 +1,623 @@
1/*
2 * P2040 Silicon 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/dts-v1/;
36
37/ {
38 compatible = "fsl,P2040";
39 #address-cells = <2>;
40 #size-cells = <2>;
41 interrupt-parent = <&mpic>;
42
43 aliases {
44 ccsr = &soc;
45
46 serial0 = &serial0;
47 serial1 = &serial1;
48 serial2 = &serial2;
49 serial3 = &serial3;
50 pci0 = &pci0;
51 pci1 = &pci1;
52 pci2 = &pci2;
53 usb0 = &usb0;
54 usb1 = &usb1;
55 dma0 = &dma0;
56 dma1 = &dma1;
57 sdhc = &sdhc;
58 msi0 = &msi0;
59 msi1 = &msi1;
60 msi2 = &msi2;
61
62 crypto = &crypto;
63 sec_jr0 = &sec_jr0;
64 sec_jr1 = &sec_jr1;
65 sec_jr2 = &sec_jr2;
66 sec_jr3 = &sec_jr3;
67 rtic_a = &rtic_a;
68 rtic_b = &rtic_b;
69 rtic_c = &rtic_c;
70 rtic_d = &rtic_d;
71 sec_mon = &sec_mon;
72 };
73
74 cpus {
75 #address-cells = <1>;
76 #size-cells = <0>;
77
78 cpu0: PowerPC,e500mc@0 {
79 device_type = "cpu";
80 reg = <0>;
81 next-level-cache = <&L2_0>;
82 L2_0: l2-cache {
83 next-level-cache = <&cpc>;
84 };
85 };
86 cpu1: PowerPC,e500mc@1 {
87 device_type = "cpu";
88 reg = <1>;
89 next-level-cache = <&L2_1>;
90 L2_1: l2-cache {
91 next-level-cache = <&cpc>;
92 };
93 };
94 cpu2: PowerPC,e500mc@2 {
95 device_type = "cpu";
96 reg = <2>;
97 next-level-cache = <&L2_2>;
98 L2_2: l2-cache {
99 next-level-cache = <&cpc>;
100 };
101 };
102 cpu3: PowerPC,e500mc@3 {
103 device_type = "cpu";
104 reg = <3>;
105 next-level-cache = <&L2_3>;
106 L2_3: l2-cache {
107 next-level-cache = <&cpc>;
108 };
109 };
110 };
111
112 soc: soc@ffe000000 {
113 #address-cells = <1>;
114 #size-cells = <1>;
115 device_type = "soc";
116 compatible = "simple-bus";
117 ranges = <0x00000000 0xf 0xfe000000 0x1000000>;
118 reg = <0xf 0xfe000000 0 0x00001000>;
119
120 soc-sram-error {
121 compatible = "fsl,soc-sram-error";
122 interrupts = <16 2 1 29>;
123 };
124
125 corenet-law@0 {
126 compatible = "fsl,corenet-law";
127 reg = <0x0 0x1000>;
128 fsl,num-laws = <32>;
129 };
130
131 memory-controller@8000 {
132 compatible = "fsl,qoriq-memory-controller-v4.5", "fsl,qoriq-memory-controller";
133 reg = <0x8000 0x1000>;
134 interrupts = <16 2 1 23>;
135 };
136
137 cpc: l3-cache-controller@10000 {
138 compatible = "fsl,p2040-l3-cache-controller", "fsl,p4080-l3-cache-controller", "cache";
139 reg = <0x10000 0x1000>;
140 interrupts = <16 2 1 27>;
141 };
142
143 corenet-cf@18000 {
144 compatible = "fsl,corenet-cf";
145 reg = <0x18000 0x1000>;
146 interrupts = <16 2 1 31>;
147 fsl,ccf-num-csdids = <32>;
148 fsl,ccf-num-snoopids = <32>;
149 };
150
151 iommu@20000 {
152 compatible = "fsl,pamu-v1.0", "fsl,pamu";
153 reg = <0x20000 0x4000>;
154 interrupts = <
155 24 2 0 0
156 16 2 1 30>;
157 };
158
159 mpic: pic@40000 {
160 clock-frequency = <0>;
161 interrupt-controller;
162 #address-cells = <0>;
163 #interrupt-cells = <4>;
164 reg = <0x40000 0x40000>;
165 compatible = "fsl,mpic", "chrp,open-pic";
166 device_type = "open-pic";
167 };
168
169 msi0: msi@41600 {
170 compatible = "fsl,mpic-msi";
171 reg = <0x41600 0x200>;
172 msi-available-ranges = <0 0x100>;
173 interrupts = <
174 0xe0 0 0 0
175 0xe1 0 0 0
176 0xe2 0 0 0
177 0xe3 0 0 0
178 0xe4 0 0 0
179 0xe5 0 0 0
180 0xe6 0 0 0
181 0xe7 0 0 0>;
182 };
183
184 msi1: msi@41800 {
185 compatible = "fsl,mpic-msi";
186 reg = <0x41800 0x200>;
187 msi-available-ranges = <0 0x100>;
188 interrupts = <
189 0xe8 0 0 0
190 0xe9 0 0 0
191 0xea 0 0 0
192 0xeb 0 0 0
193 0xec 0 0 0
194 0xed 0 0 0
195 0xee 0 0 0
196 0xef 0 0 0>;
197 };
198
199 msi2: msi@41a00 {
200 compatible = "fsl,mpic-msi";
201 reg = <0x41a00 0x200>;
202 msi-available-ranges = <0 0x100>;
203 interrupts = <
204 0xf0 0 0 0
205 0xf1 0 0 0
206 0xf2 0 0 0
207 0xf3 0 0 0
208 0xf4 0 0 0
209 0xf5 0 0 0
210 0xf6 0 0 0
211 0xf7 0 0 0>;
212 };
213
214 guts: global-utilities@e0000 {
215 compatible = "fsl,qoriq-device-config-1.0";
216 reg = <0xe0000 0xe00>;
217 fsl,has-rstcr;
218 #sleep-cells = <1>;
219 fsl,liodn-bits = <12>;
220 };
221
222 pins: global-utilities@e0e00 {
223 compatible = "fsl,qoriq-pin-control-1.0";
224 reg = <0xe0e00 0x200>;
225 #sleep-cells = <2>;
226 };
227
228 clockgen: global-utilities@e1000 {
229 compatible = "fsl,p2040-clockgen", "fsl,qoriq-clockgen-1.0";
230 reg = <0xe1000 0x1000>;
231 clock-frequency = <0>;
232 };
233
234 rcpm: global-utilities@e2000 {
235 compatible = "fsl,qoriq-rcpm-1.0";
236 reg = <0xe2000 0x1000>;
237 #sleep-cells = <1>;
238 };
239
240 sfp: sfp@e8000 {
241 compatible = "fsl,p2040-sfp", "fsl,qoriq-sfp-1.0";
242 reg = <0xe8000 0x1000>;
243 };
244
245 serdes: serdes@ea000 {
246 compatible = "fsl,p2040-serdes";
247 reg = <0xea000 0x1000>;
248 };
249
250 dma0: dma@100300 {
251 #address-cells = <1>;
252 #size-cells = <1>;
253 compatible = "fsl,p2040-dma", "fsl,eloplus-dma";
254 reg = <0x100300 0x4>;
255 ranges = <0x0 0x100100 0x200>;
256 cell-index = <0>;
257 dma-channel@0 {
258 compatible = "fsl,p2040-dma-channel",
259 "fsl,eloplus-dma-channel";
260 reg = <0x0 0x80>;
261 cell-index = <0>;
262 interrupts = <28 2 0 0>;
263 };
264 dma-channel@80 {
265 compatible = "fsl,p2040-dma-channel",
266 "fsl,eloplus-dma-channel";
267 reg = <0x80 0x80>;
268 cell-index = <1>;
269 interrupts = <29 2 0 0>;
270 };
271 dma-channel@100 {
272 compatible = "fsl,p2040-dma-channel",
273 "fsl,eloplus-dma-channel";
274 reg = <0x100 0x80>;
275 cell-index = <2>;
276 interrupts = <30 2 0 0>;
277 };
278 dma-channel@180 {
279 compatible = "fsl,p2040-dma-channel",
280 "fsl,eloplus-dma-channel";
281 reg = <0x180 0x80>;
282 cell-index = <3>;
283 interrupts = <31 2 0 0>;
284 };
285 };
286
287 dma1: dma@101300 {
288 #address-cells = <1>;
289 #size-cells = <1>;
290 compatible = "fsl,p2040-dma", "fsl,eloplus-dma";
291 reg = <0x101300 0x4>;
292 ranges = <0x0 0x101100 0x200>;
293 cell-index = <1>;
294 dma-channel@0 {
295 compatible = "fsl,p2040-dma-channel",
296 "fsl,eloplus-dma-channel";
297 reg = <0x0 0x80>;
298 cell-index = <0>;
299 interrupts = <32 2 0 0>;
300 };
301 dma-channel@80 {
302 compatible = "fsl,p2040-dma-channel",
303 "fsl,eloplus-dma-channel";
304 reg = <0x80 0x80>;
305 cell-index = <1>;
306 interrupts = <33 2 0 0>;
307 };
308 dma-channel@100 {
309 compatible = "fsl,p2040-dma-channel",
310 "fsl,eloplus-dma-channel";
311 reg = <0x100 0x80>;
312 cell-index = <2>;
313 interrupts = <34 2 0 0>;
314 };
315 dma-channel@180 {
316 compatible = "fsl,p2040-dma-channel",
317 "fsl,eloplus-dma-channel";
318 reg = <0x180 0x80>;
319 cell-index = <3>;
320 interrupts = <35 2 0 0>;
321 };
322 };
323
324 spi@110000 {
325 #address-cells = <1>;
326 #size-cells = <0>;
327 compatible = "fsl,p2040-espi", "fsl,mpc8536-espi";
328 reg = <0x110000 0x1000>;
329 interrupts = <53 0x2 0 0>;
330 fsl,espi-num-chipselects = <4>;
331
332 };
333
334 sdhc: sdhc@114000 {
335 compatible = "fsl,p2040-esdhc", "fsl,esdhc";
336 reg = <0x114000 0x1000>;
337 interrupts = <48 2 0 0>;
338 sdhci,auto-cmd12;
339 clock-frequency = <0>;
340 };
341
342
343 i2c@118000 {
344 #address-cells = <1>;
345 #size-cells = <0>;
346 cell-index = <0>;
347 compatible = "fsl-i2c";
348 reg = <0x118000 0x100>;
349 interrupts = <38 2 0 0>;
350 dfsrr;
351 };
352
353 i2c@118100 {
354 #address-cells = <1>;
355 #size-cells = <0>;
356 cell-index = <1>;
357 compatible = "fsl-i2c";
358 reg = <0x118100 0x100>;
359 interrupts = <38 2 0 0>;
360 dfsrr;
361 };
362
363 i2c@119000 {
364 #address-cells = <1>;
365 #size-cells = <0>;
366 cell-index = <2>;
367 compatible = "fsl-i2c";
368 reg = <0x119000 0x100>;
369 interrupts = <39 2 0 0>;
370 dfsrr;
371 };
372
373 i2c@119100 {
374 #address-cells = <1>;
375 #size-cells = <0>;
376 cell-index = <3>;
377 compatible = "fsl-i2c";
378 reg = <0x119100 0x100>;
379 interrupts = <39 2 0 0>;
380 dfsrr;
381 };
382
383 serial0: serial@11c500 {
384 cell-index = <0>;
385 device_type = "serial";
386 compatible = "ns16550";
387 reg = <0x11c500 0x100>;
388 clock-frequency = <0>;
389 interrupts = <36 2 0 0>;
390 };
391
392 serial1: serial@11c600 {
393 cell-index = <1>;
394 device_type = "serial";
395 compatible = "ns16550";
396 reg = <0x11c600 0x100>;
397 clock-frequency = <0>;
398 interrupts = <36 2 0 0>;
399 };
400
401 serial2: serial@11d500 {
402 cell-index = <2>;
403 device_type = "serial";
404 compatible = "ns16550";
405 reg = <0x11d500 0x100>;
406 clock-frequency = <0>;
407 interrupts = <37 2 0 0>;
408 };
409
410 serial3: serial@11d600 {
411 cell-index = <3>;
412 device_type = "serial";
413 compatible = "ns16550";
414 reg = <0x11d600 0x100>;
415 clock-frequency = <0>;
416 interrupts = <37 2 0 0>;
417 };
418
419 gpio0: gpio@130000 {
420 compatible = "fsl,p2040-gpio", "fsl,qoriq-gpio";
421 reg = <0x130000 0x1000>;
422 interrupts = <55 2 0 0>;
423 #gpio-cells = <2>;
424 gpio-controller;
425 };
426
427 usb0: usb@210000 {
428 compatible = "fsl,p2040-usb2-mph",
429 "fsl,mpc85xx-usb2-mph", "fsl-usb2-mph";
430 reg = <0x210000 0x1000>;
431 #address-cells = <1>;
432 #size-cells = <0>;
433 interrupts = <44 0x2 0 0>;
434 port0;
435 };
436
437 usb1: usb@211000 {
438 compatible = "fsl,p2040-usb2-dr",
439 "fsl,mpc85xx-usb2-dr", "fsl-usb2-dr";
440 reg = <0x211000 0x1000>;
441 #address-cells = <1>;
442 #size-cells = <0>;
443 interrupts = <45 0x2 0 0>;
444 };
445
446 sata@220000 {
447 compatible = "fsl,p2040-sata", "fsl,pq-sata-v2";
448 reg = <0x220000 0x1000>;
449 interrupts = <68 0x2 0 0>;
450 };
451
452 sata@221000 {
453 compatible = "fsl,p2040-sata", "fsl,pq-sata-v2";
454 reg = <0x221000 0x1000>;
455 interrupts = <69 0x2 0 0>;
456 };
457
458 crypto: crypto@300000 {
459 compatible = "fsl,sec-v4.2", "fsl,sec-v4.0";
460 #address-cells = <1>;
461 #size-cells = <1>;
462 reg = <0x300000 0x10000>;
463 ranges = <0 0x300000 0x10000>;
464 interrupts = <92 2 0 0>;
465
466 sec_jr0: jr@1000 {
467 compatible = "fsl,sec-v4.2-job-ring",
468 "fsl,sec-v4.0-job-ring";
469 reg = <0x1000 0x1000>;
470 interrupts = <88 2 0 0>;
471 };
472
473 sec_jr1: jr@2000 {
474 compatible = "fsl,sec-v4.2-job-ring",
475 "fsl,sec-v4.0-job-ring";
476 reg = <0x2000 0x1000>;
477 interrupts = <89 2 0 0>;
478 };
479
480 sec_jr2: jr@3000 {
481 compatible = "fsl,sec-v4.2-job-ring",
482 "fsl,sec-v4.0-job-ring";
483 reg = <0x3000 0x1000>;
484 interrupts = <90 2 0 0>;
485 };
486
487 sec_jr3: jr@4000 {
488 compatible = "fsl,sec-v4.2-job-ring",
489 "fsl,sec-v4.0-job-ring";
490 reg = <0x4000 0x1000>;
491 interrupts = <91 2 0 0>;
492 };
493
494 rtic@6000 {
495 compatible = "fsl,sec-v4.2-rtic",
496 "fsl,sec-v4.0-rtic";
497 #address-cells = <1>;
498 #size-cells = <1>;
499 reg = <0x6000 0x100>;
500 ranges = <0x0 0x6100 0xe00>;
501
502 rtic_a: rtic-a@0 {
503 compatible = "fsl,sec-v4.2-rtic-memory",
504 "fsl,sec-v4.0-rtic-memory";
505 reg = <0x00 0x20 0x100 0x80>;
506 };
507
508 rtic_b: rtic-b@20 {
509 compatible = "fsl,sec-v4.2-rtic-memory",
510 "fsl,sec-v4.0-rtic-memory";
511 reg = <0x20 0x20 0x200 0x80>;
512 };
513
514 rtic_c: rtic-c@40 {
515 compatible = "fsl,sec-v4.2-rtic-memory",
516 "fsl,sec-v4.0-rtic-memory";
517 reg = <0x40 0x20 0x300 0x80>;
518 };
519
520 rtic_d: rtic-d@60 {
521 compatible = "fsl,sec-v4.2-rtic-memory",
522 "fsl,sec-v4.0-rtic-memory";
523 reg = <0x60 0x20 0x500 0x80>;
524 };
525 };
526 };
527
528 sec_mon: sec_mon@314000 {
529 compatible = "fsl,sec-v4.2-mon", "fsl,sec-v4.0-mon";
530 reg = <0x314000 0x1000>;
531 interrupts = <93 2 0 0>;
532 };
533
534 };
535
536 localbus@ffe124000 {
537 compatible = "fsl,p2040-elbc", "fsl,elbc", "simple-bus";
538 interrupts = <25 2 0 0>;
539 #address-cells = <2>;
540 #size-cells = <1>;
541 };
542
543 pci0: pcie@ffe200000 {
544 compatible = "fsl,p2040-pcie", "fsl,qoriq-pcie-v2.2";
545 device_type = "pci";
546 #size-cells = <2>;
547 #address-cells = <3>;
548 bus-range = <0x0 0xff>;
549 clock-frequency = <0x1fca055>;
550 fsl,msi = <&msi0>;
551 interrupts = <16 2 1 15>;
552 pcie@0 {
553 reg = <0 0 0 0 0>;
554 #interrupt-cells = <1>;
555 #size-cells = <2>;
556 #address-cells = <3>;
557 device_type = "pci";
558 interrupts = <16 2 1 15>;
559 interrupt-map-mask = <0xf800 0 0 7>;
560 interrupt-map = <
561 /* IDSEL 0x0 */
562 0000 0 0 1 &mpic 40 1 0 0
563 0000 0 0 2 &mpic 1 1 0 0
564 0000 0 0 3 &mpic 2 1 0 0
565 0000 0 0 4 &mpic 3 1 0 0
566 >;
567 };
568 };
569
570 pci1: pcie@ffe201000 {
571 compatible = "fsl,p2040-pcie", "fsl,qoriq-pcie-v2.2";
572 device_type = "pci";
573 #size-cells = <2>;
574 #address-cells = <3>;
575 bus-range = <0 0xff>;
576 clock-frequency = <0x1fca055>;
577 fsl,msi = <&msi1>;
578 interrupts = <16 2 1 14>;
579 pcie@0 {
580 reg = <0 0 0 0 0>;
581 #interrupt-cells = <1>;
582 #size-cells = <2>;
583 #address-cells = <3>;
584 device_type = "pci";
585 interrupts = <16 2 1 14>;
586 interrupt-map-mask = <0xf800 0 0 7>;
587 interrupt-map = <
588 /* IDSEL 0x0 */
589 0000 0 0 1 &mpic 41 1 0 0
590 0000 0 0 2 &mpic 5 1 0 0
591 0000 0 0 3 &mpic 6 1 0 0
592 0000 0 0 4 &mpic 7 1 0 0
593 >;
594 };
595 };
596
597 pci2: pcie@ffe202000 {
598 compatible = "fsl,p2040-pcie", "fsl,qoriq-pcie-v2.2";
599 device_type = "pci";
600 #size-cells = <2>;
601 #address-cells = <3>;
602 bus-range = <0x0 0xff>;
603 clock-frequency = <0x1fca055>;
604 fsl,msi = <&msi2>;
605 interrupts = <16 2 1 13>;
606 pcie@0 {
607 reg = <0 0 0 0 0>;
608 #interrupt-cells = <1>;
609 #size-cells = <2>;
610 #address-cells = <3>;
611 device_type = "pci";
612 interrupts = <16 2 1 13>;
613 interrupt-map-mask = <0xf800 0 0 7>;
614 interrupt-map = <
615 /* IDSEL 0x0 */
616 0000 0 0 1 &mpic 42 1 0 0
617 0000 0 0 2 &mpic 9 1 0 0
618 0000 0 0 3 &mpic 10 1 0 0
619 0000 0 0 4 &mpic 11 1 0 0
620 >;
621 };
622 };
623};
diff --git a/arch/powerpc/boot/dts/p3041si.dtsi b/arch/powerpc/boot/dts/p3041si.dtsi
new file mode 100644
index 00000000000..8b695801f50
--- /dev/null
+++ b/arch/powerpc/boot/dts/p3041si.dtsi
@@ -0,0 +1,660 @@
1/*
2 * P3041 Silicon Device Tree Source
3 *
4 * Copyright 2010-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/dts-v1/;
36
37/ {
38 compatible = "fsl,P3041";
39 #address-cells = <2>;
40 #size-cells = <2>;
41 interrupt-parent = <&mpic>;
42
43 aliases {
44 ccsr = &soc;
45
46 serial0 = &serial0;
47 serial1 = &serial1;
48 serial2 = &serial2;
49 serial3 = &serial3;
50 pci0 = &pci0;
51 pci1 = &pci1;
52 pci2 = &pci2;
53 pci3 = &pci3;
54 usb0 = &usb0;
55 usb1 = &usb1;
56 dma0 = &dma0;
57 dma1 = &dma1;
58 sdhc = &sdhc;
59 msi0 = &msi0;
60 msi1 = &msi1;
61 msi2 = &msi2;
62
63 crypto = &crypto;
64 sec_jr0 = &sec_jr0;
65 sec_jr1 = &sec_jr1;
66 sec_jr2 = &sec_jr2;
67 sec_jr3 = &sec_jr3;
68 rtic_a = &rtic_a;
69 rtic_b = &rtic_b;
70 rtic_c = &rtic_c;
71 rtic_d = &rtic_d;
72 sec_mon = &sec_mon;
73
74/*
75 rio0 = &rapidio0;
76 */
77 };
78
79 cpus {
80 #address-cells = <1>;
81 #size-cells = <0>;
82
83 cpu0: PowerPC,e500mc@0 {
84 device_type = "cpu";
85 reg = <0>;
86 next-level-cache = <&L2_0>;
87 L2_0: l2-cache {
88 next-level-cache = <&cpc>;
89 };
90 };
91 cpu1: PowerPC,e500mc@1 {
92 device_type = "cpu";
93 reg = <1>;
94 next-level-cache = <&L2_1>;
95 L2_1: l2-cache {
96 next-level-cache = <&cpc>;
97 };
98 };
99 cpu2: PowerPC,e500mc@2 {
100 device_type = "cpu";
101 reg = <2>;
102 next-level-cache = <&L2_2>;
103 L2_2: l2-cache {
104 next-level-cache = <&cpc>;
105 };
106 };
107 cpu3: PowerPC,e500mc@3 {
108 device_type = "cpu";
109 reg = <3>;
110 next-level-cache = <&L2_3>;
111 L2_3: l2-cache {
112 next-level-cache = <&cpc>;
113 };
114 };
115 };
116
117 soc: soc@ffe000000 {
118 #address-cells = <1>;
119 #size-cells = <1>;
120 device_type = "soc";
121 compatible = "simple-bus";
122 ranges = <0x00000000 0xf 0xfe000000 0x1000000>;
123 reg = <0xf 0xfe000000 0 0x00001000>;
124
125 soc-sram-error {
126 compatible = "fsl,soc-sram-error";
127 interrupts = <16 2 1 29>;
128 };
129
130 corenet-law@0 {
131 compatible = "fsl,corenet-law";
132 reg = <0x0 0x1000>;
133 fsl,num-laws = <32>;
134 };
135
136 memory-controller@8000 {
137 compatible = "fsl,qoriq-memory-controller-v4.5", "fsl,qoriq-memory-controller";
138 reg = <0x8000 0x1000>;
139 interrupts = <16 2 1 23>;
140 };
141
142 cpc: l3-cache-controller@10000 {
143 compatible = "fsl,p3041-l3-cache-controller", "fsl,p4080-l3-cache-controller", "cache";
144 reg = <0x10000 0x1000>;
145 interrupts = <16 2 1 27>;
146 };
147
148 corenet-cf@18000 {
149 compatible = "fsl,corenet-cf";
150 reg = <0x18000 0x1000>;
151 interrupts = <16 2 1 31>;
152 fsl,ccf-num-csdids = <32>;
153 fsl,ccf-num-snoopids = <32>;
154 };
155
156 iommu@20000 {
157 compatible = "fsl,pamu-v1.0", "fsl,pamu";
158 reg = <0x20000 0x4000>;
159 interrupts = <
160 24 2 0 0
161 16 2 1 30>;
162 };
163
164 mpic: pic@40000 {
165 clock-frequency = <0>;
166 interrupt-controller;
167 #address-cells = <0>;
168 #interrupt-cells = <4>;
169 reg = <0x40000 0x40000>;
170 compatible = "fsl,mpic", "chrp,open-pic";
171 device_type = "open-pic";
172 };
173
174 msi0: msi@41600 {
175 compatible = "fsl,mpic-msi";
176 reg = <0x41600 0x200>;
177 msi-available-ranges = <0 0x100>;
178 interrupts = <
179 0xe0 0 0 0
180 0xe1 0 0 0
181 0xe2 0 0 0
182 0xe3 0 0 0
183 0xe4 0 0 0
184 0xe5 0 0 0
185 0xe6 0 0 0
186 0xe7 0 0 0>;
187 };
188
189 msi1: msi@41800 {
190 compatible = "fsl,mpic-msi";
191 reg = <0x41800 0x200>;
192 msi-available-ranges = <0 0x100>;
193 interrupts = <
194 0xe8 0 0 0
195 0xe9 0 0 0
196 0xea 0 0 0
197 0xeb 0 0 0
198 0xec 0 0 0
199 0xed 0 0 0
200 0xee 0 0 0
201 0xef 0 0 0>;
202 };
203
204 msi2: msi@41a00 {
205 compatible = "fsl,mpic-msi";
206 reg = <0x41a00 0x200>;
207 msi-available-ranges = <0 0x100>;
208 interrupts = <
209 0xf0 0 0 0
210 0xf1 0 0 0
211 0xf2 0 0 0
212 0xf3 0 0 0
213 0xf4 0 0 0
214 0xf5 0 0 0
215 0xf6 0 0 0
216 0xf7 0 0 0>;
217 };
218
219 guts: global-utilities@e0000 {
220 compatible = "fsl,qoriq-device-config-1.0";
221 reg = <0xe0000 0xe00>;
222 fsl,has-rstcr;
223 #sleep-cells = <1>;
224 fsl,liodn-bits = <12>;
225 };
226
227 pins: global-utilities@e0e00 {
228 compatible = "fsl,qoriq-pin-control-1.0";
229 reg = <0xe0e00 0x200>;
230 #sleep-cells = <2>;
231 };
232
233 clockgen: global-utilities@e1000 {
234 compatible = "fsl,p3041-clockgen", "fsl,qoriq-clockgen-1.0";
235 reg = <0xe1000 0x1000>;
236 clock-frequency = <0>;
237 };
238
239 rcpm: global-utilities@e2000 {
240 compatible = "fsl,qoriq-rcpm-1.0";
241 reg = <0xe2000 0x1000>;
242 #sleep-cells = <1>;
243 };
244
245 sfp: sfp@e8000 {
246 compatible = "fsl,p3041-sfp", "fsl,qoriq-sfp-1.0";
247 reg = <0xe8000 0x1000>;
248 };
249
250 serdes: serdes@ea000 {
251 compatible = "fsl,p3041-serdes";
252 reg = <0xea000 0x1000>;
253 };
254
255 dma0: dma@100300 {
256 #address-cells = <1>;
257 #size-cells = <1>;
258 compatible = "fsl,p3041-dma", "fsl,eloplus-dma";
259 reg = <0x100300 0x4>;
260 ranges = <0x0 0x100100 0x200>;
261 cell-index = <0>;
262 dma-channel@0 {
263 compatible = "fsl,p3041-dma-channel",
264 "fsl,eloplus-dma-channel";
265 reg = <0x0 0x80>;
266 cell-index = <0>;
267 interrupts = <28 2 0 0>;
268 };
269 dma-channel@80 {
270 compatible = "fsl,p3041-dma-channel",
271 "fsl,eloplus-dma-channel";
272 reg = <0x80 0x80>;
273 cell-index = <1>;
274 interrupts = <29 2 0 0>;
275 };
276 dma-channel@100 {
277 compatible = "fsl,p3041-dma-channel",
278 "fsl,eloplus-dma-channel";
279 reg = <0x100 0x80>;
280 cell-index = <2>;
281 interrupts = <30 2 0 0>;
282 };
283 dma-channel@180 {
284 compatible = "fsl,p3041-dma-channel",
285 "fsl,eloplus-dma-channel";
286 reg = <0x180 0x80>;
287 cell-index = <3>;
288 interrupts = <31 2 0 0>;
289 };
290 };
291
292 dma1: dma@101300 {
293 #address-cells = <1>;
294 #size-cells = <1>;
295 compatible = "fsl,p3041-dma", "fsl,eloplus-dma";
296 reg = <0x101300 0x4>;
297 ranges = <0x0 0x101100 0x200>;
298 cell-index = <1>;
299 dma-channel@0 {
300 compatible = "fsl,p3041-dma-channel",
301 "fsl,eloplus-dma-channel";
302 reg = <0x0 0x80>;
303 cell-index = <0>;
304 interrupts = <32 2 0 0>;
305 };
306 dma-channel@80 {
307 compatible = "fsl,p3041-dma-channel",
308 "fsl,eloplus-dma-channel";
309 reg = <0x80 0x80>;
310 cell-index = <1>;
311 interrupts = <33 2 0 0>;
312 };
313 dma-channel@100 {
314 compatible = "fsl,p3041-dma-channel",
315 "fsl,eloplus-dma-channel";
316 reg = <0x100 0x80>;
317 cell-index = <2>;
318 interrupts = <34 2 0 0>;
319 };
320 dma-channel@180 {
321 compatible = "fsl,p3041-dma-channel",
322 "fsl,eloplus-dma-channel";
323 reg = <0x180 0x80>;
324 cell-index = <3>;
325 interrupts = <35 2 0 0>;
326 };
327 };
328
329 spi@110000 {
330 #address-cells = <1>;
331 #size-cells = <0>;
332 compatible = "fsl,p3041-espi", "fsl,mpc8536-espi";
333 reg = <0x110000 0x1000>;
334 interrupts = <53 0x2 0 0>;
335 fsl,espi-num-chipselects = <4>;
336 };
337
338 sdhc: sdhc@114000 {
339 compatible = "fsl,p3041-esdhc", "fsl,esdhc";
340 reg = <0x114000 0x1000>;
341 interrupts = <48 2 0 0>;
342 sdhci,auto-cmd12;
343 clock-frequency = <0>;
344 };
345
346 i2c@118000 {
347 #address-cells = <1>;
348 #size-cells = <0>;
349 cell-index = <0>;
350 compatible = "fsl-i2c";
351 reg = <0x118000 0x100>;
352 interrupts = <38 2 0 0>;
353 dfsrr;
354 };
355
356 i2c@118100 {
357 #address-cells = <1>;
358 #size-cells = <0>;
359 cell-index = <1>;
360 compatible = "fsl-i2c";
361 reg = <0x118100 0x100>;
362 interrupts = <38 2 0 0>;
363 dfsrr;
364 };
365
366 i2c@119000 {
367 #address-cells = <1>;
368 #size-cells = <0>;
369 cell-index = <2>;
370 compatible = "fsl-i2c";
371 reg = <0x119000 0x100>;
372 interrupts = <39 2 0 0>;
373 dfsrr;
374 };
375
376 i2c@119100 {
377 #address-cells = <1>;
378 #size-cells = <0>;
379 cell-index = <3>;
380 compatible = "fsl-i2c";
381 reg = <0x119100 0x100>;
382 interrupts = <39 2 0 0>;
383 dfsrr;
384 };
385
386 serial0: serial@11c500 {
387 cell-index = <0>;
388 device_type = "serial";
389 compatible = "ns16550";
390 reg = <0x11c500 0x100>;
391 clock-frequency = <0>;
392 interrupts = <36 2 0 0>;
393 };
394
395 serial1: serial@11c600 {
396 cell-index = <1>;
397 device_type = "serial";
398 compatible = "ns16550";
399 reg = <0x11c600 0x100>;
400 clock-frequency = <0>;
401 interrupts = <36 2 0 0>;
402 };
403
404 serial2: serial@11d500 {
405 cell-index = <2>;
406 device_type = "serial";
407 compatible = "ns16550";
408 reg = <0x11d500 0x100>;
409 clock-frequency = <0>;
410 interrupts = <37 2 0 0>;
411 };
412
413 serial3: serial@11d600 {
414 cell-index = <3>;
415 device_type = "serial";
416 compatible = "ns16550";
417 reg = <0x11d600 0x100>;
418 clock-frequency = <0>;
419 interrupts = <37 2 0 0>;
420 };
421
422 gpio0: gpio@130000 {
423 compatible = "fsl,p3041-gpio", "fsl,qoriq-gpio";
424 reg = <0x130000 0x1000>;
425 interrupts = <55 2 0 0>;
426 #gpio-cells = <2>;
427 gpio-controller;
428 };
429
430 usb0: usb@210000 {
431 compatible = "fsl,p3041-usb2-mph",
432 "fsl,mpc85xx-usb2-mph", "fsl-usb2-mph";
433 reg = <0x210000 0x1000>;
434 #address-cells = <1>;
435 #size-cells = <0>;
436 interrupts = <44 0x2 0 0>;
437 phy_type = "utmi";
438 port0;
439 };
440
441 usb1: usb@211000 {
442 compatible = "fsl,p3041-usb2-dr",
443 "fsl,mpc85xx-usb2-dr", "fsl-usb2-dr";
444 reg = <0x211000 0x1000>;
445 #address-cells = <1>;
446 #size-cells = <0>;
447 interrupts = <45 0x2 0 0>;
448 dr_mode = "host";
449 phy_type = "utmi";
450 };
451
452 sata@220000 {
453 compatible = "fsl,p3041-sata", "fsl,pq-sata-v2";
454 reg = <0x220000 0x1000>;
455 interrupts = <68 0x2 0 0>;
456 };
457
458 sata@221000 {
459 compatible = "fsl,p3041-sata", "fsl,pq-sata-v2";
460 reg = <0x221000 0x1000>;
461 interrupts = <69 0x2 0 0>;
462 };
463
464 crypto: crypto@300000 {
465 compatible = "fsl,sec-v4.2", "fsl,sec-v4.0";
466 #address-cells = <1>;
467 #size-cells = <1>;
468 reg = <0x300000 0x10000>;
469 ranges = <0 0x300000 0x10000>;
470 interrupts = <92 2 0 0>;
471
472 sec_jr0: jr@1000 {
473 compatible = "fsl,sec-v4.2-job-ring",
474 "fsl,sec-v4.0-job-ring";
475 reg = <0x1000 0x1000>;
476 interrupts = <88 2 0 0>;
477 };
478
479 sec_jr1: jr@2000 {
480 compatible = "fsl,sec-v4.2-job-ring",
481 "fsl,sec-v4.0-job-ring";
482 reg = <0x2000 0x1000>;
483 interrupts = <89 2 0 0>;
484 };
485
486 sec_jr2: jr@3000 {
487 compatible = "fsl,sec-v4.2-job-ring",
488 "fsl,sec-v4.0-job-ring";
489 reg = <0x3000 0x1000>;
490 interrupts = <90 2 0 0>;
491 };
492
493 sec_jr3: jr@4000 {
494 compatible = "fsl,sec-v4.2-job-ring",
495 "fsl,sec-v4.0-job-ring";
496 reg = <0x4000 0x1000>;
497 interrupts = <91 2 0 0>;
498 };
499
500 rtic@6000 {
501 compatible = "fsl,sec-v4.2-rtic",
502 "fsl,sec-v4.0-rtic";
503 #address-cells = <1>;
504 #size-cells = <1>;
505 reg = <0x6000 0x100>;
506 ranges = <0x0 0x6100 0xe00>;
507
508 rtic_a: rtic-a@0 {
509 compatible = "fsl,sec-v4.2-rtic-memory",
510 "fsl,sec-v4.0-rtic-memory";
511 reg = <0x00 0x20 0x100 0x80>;
512 };
513
514 rtic_b: rtic-b@20 {
515 compatible = "fsl,sec-v4.2-rtic-memory",
516 "fsl,sec-v4.0-rtic-memory";
517 reg = <0x20 0x20 0x200 0x80>;
518 };
519
520 rtic_c: rtic-c@40 {
521 compatible = "fsl,sec-v4.2-rtic-memory",
522 "fsl,sec-v4.0-rtic-memory";
523 reg = <0x40 0x20 0x300 0x80>;
524 };
525
526 rtic_d: rtic-d@60 {
527 compatible = "fsl,sec-v4.2-rtic-memory",
528 "fsl,sec-v4.0-rtic-memory";
529 reg = <0x60 0x20 0x500 0x80>;
530 };
531 };
532 };
533
534 sec_mon: sec_mon@314000 {
535 compatible = "fsl,sec-v4.2-mon", "fsl,sec-v4.0-mon";
536 reg = <0x314000 0x1000>;
537 interrupts = <93 2 0 0>;
538 };
539 };
540
541/*
542 rapidio0: rapidio@ffe0c0000
543*/
544
545 localbus@ffe124000 {
546 compatible = "fsl,p3041-elbc", "fsl,elbc", "simple-bus";
547 interrupts = <25 2 0 0>;
548 #address-cells = <2>;
549 #size-cells = <1>;
550 };
551
552 pci0: pcie@ffe200000 {
553 compatible = "fsl,p3041-pcie", "fsl,qoriq-pcie-v2.2";
554 device_type = "pci";
555 #size-cells = <2>;
556 #address-cells = <3>;
557 bus-range = <0x0 0xff>;
558 clock-frequency = <0x1fca055>;
559 fsl,msi = <&msi0>;
560 interrupts = <16 2 1 15>;
561
562 pcie@0 {
563 reg = <0 0 0 0 0>;
564 #interrupt-cells = <1>;
565 #size-cells = <2>;
566 #address-cells = <3>;
567 device_type = "pci";
568 interrupts = <16 2 1 15>;
569 interrupt-map-mask = <0xf800 0 0 7>;
570 interrupt-map = <
571 /* IDSEL 0x0 */
572 0000 0 0 1 &mpic 40 1 0 0
573 0000 0 0 2 &mpic 1 1 0 0
574 0000 0 0 3 &mpic 2 1 0 0
575 0000 0 0 4 &mpic 3 1 0 0
576 >;
577 };
578 };
579
580 pci1: pcie@ffe201000 {
581 compatible = "fsl,p3041-pcie", "fsl,qoriq-pcie-v2.2";
582 device_type = "pci";
583 #size-cells = <2>;
584 #address-cells = <3>;
585 bus-range = <0 0xff>;
586 clock-frequency = <0x1fca055>;
587 fsl,msi = <&msi1>;
588 interrupts = <16 2 1 14>;
589 pcie@0 {
590 reg = <0 0 0 0 0>;
591 #interrupt-cells = <1>;
592 #size-cells = <2>;
593 #address-cells = <3>;
594 device_type = "pci";
595 interrupts = <16 2 1 14>;
596 interrupt-map-mask = <0xf800 0 0 7>;
597 interrupt-map = <
598 /* IDSEL 0x0 */
599 0000 0 0 1 &mpic 41 1 0 0
600 0000 0 0 2 &mpic 5 1 0 0
601 0000 0 0 3 &mpic 6 1 0 0
602 0000 0 0 4 &mpic 7 1 0 0
603 >;
604 };
605 };
606
607 pci2: pcie@ffe202000 {
608 compatible = "fsl,p3041-pcie", "fsl,qoriq-pcie-v2.2";
609 device_type = "pci";
610 #size-cells = <2>;
611 #address-cells = <3>;
612 bus-range = <0x0 0xff>;
613 clock-frequency = <0x1fca055>;
614 fsl,msi = <&msi2>;
615 interrupts = <16 2 1 13>;
616 pcie@0 {
617 reg = <0 0 0 0 0>;
618 #interrupt-cells = <1>;
619 #size-cells = <2>;
620 #address-cells = <3>;
621 device_type = "pci";
622 interrupts = <16 2 1 13>;
623 interrupt-map-mask = <0xf800 0 0 7>;
624 interrupt-map = <
625 /* IDSEL 0x0 */
626 0000 0 0 1 &mpic 42 1 0 0
627 0000 0 0 2 &mpic 9 1 0 0
628 0000 0 0 3 &mpic 10 1 0 0
629 0000 0 0 4 &mpic 11 1 0 0
630 >;
631 };
632 };
633
634 pci3: pcie@ffe203000 {
635 compatible = "fsl,p3041-pcie", "fsl,qoriq-pcie-v2.2";
636 device_type = "pci";
637 #size-cells = <2>;
638 #address-cells = <3>;
639 bus-range = <0x0 0xff>;
640 clock-frequency = <0x1fca055>;
641 fsl,msi = <&msi2>;
642 interrupts = <16 2 1 12>;
643 pcie@0 {
644 reg = <0 0 0 0 0>;
645 #interrupt-cells = <1>;
646 #size-cells = <2>;
647 #address-cells = <3>;
648 device_type = "pci";
649 interrupts = <16 2 1 12>;
650 interrupt-map-mask = <0xf800 0 0 7>;
651 interrupt-map = <
652 /* IDSEL 0x0 */
653 0000 0 0 1 &mpic 43 1 0 0
654 0000 0 0 2 &mpic 0 1 0 0
655 0000 0 0 3 &mpic 4 1 0 0
656 0000 0 0 4 &mpic 8 1 0 0
657 >;
658 };
659 };
660};
diff --git a/arch/powerpc/boot/dts/p4080si.dtsi b/arch/powerpc/boot/dts/p4080si.dtsi
new file mode 100644
index 00000000000..b71051f506c
--- /dev/null
+++ b/arch/powerpc/boot/dts/p4080si.dtsi
@@ -0,0 +1,661 @@
1/*
2 * P4080 Silicon Device Tree Source
3 *
4 * Copyright 2009-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/dts-v1/;
36
37/ {
38 compatible = "fsl,P4080";
39 #address-cells = <2>;
40 #size-cells = <2>;
41 interrupt-parent = <&mpic>;
42
43 aliases {
44 ccsr = &soc;
45
46 serial0 = &serial0;
47 serial1 = &serial1;
48 serial2 = &serial2;
49 serial3 = &serial3;
50 pci0 = &pci0;
51 pci1 = &pci1;
52 pci2 = &pci2;
53 usb0 = &usb0;
54 usb1 = &usb1;
55 dma0 = &dma0;
56 dma1 = &dma1;
57 sdhc = &sdhc;
58 msi0 = &msi0;
59 msi1 = &msi1;
60 msi2 = &msi2;
61
62 crypto = &crypto;
63 sec_jr0 = &sec_jr0;
64 sec_jr1 = &sec_jr1;
65 sec_jr2 = &sec_jr2;
66 sec_jr3 = &sec_jr3;
67 rtic_a = &rtic_a;
68 rtic_b = &rtic_b;
69 rtic_c = &rtic_c;
70 rtic_d = &rtic_d;
71 sec_mon = &sec_mon;
72
73 rio0 = &rapidio0;
74 };
75
76 cpus {
77 #address-cells = <1>;
78 #size-cells = <0>;
79
80 cpu0: PowerPC,4080@0 {
81 device_type = "cpu";
82 reg = <0>;
83 next-level-cache = <&L2_0>;
84 L2_0: l2-cache {
85 next-level-cache = <&cpc>;
86 };
87 };
88 cpu1: PowerPC,4080@1 {
89 device_type = "cpu";
90 reg = <1>;
91 next-level-cache = <&L2_1>;
92 L2_1: l2-cache {
93 next-level-cache = <&cpc>;
94 };
95 };
96 cpu2: PowerPC,4080@2 {
97 device_type = "cpu";
98 reg = <2>;
99 next-level-cache = <&L2_2>;
100 L2_2: l2-cache {
101 next-level-cache = <&cpc>;
102 };
103 };
104 cpu3: PowerPC,4080@3 {
105 device_type = "cpu";
106 reg = <3>;
107 next-level-cache = <&L2_3>;
108 L2_3: l2-cache {
109 next-level-cache = <&cpc>;
110 };
111 };
112 cpu4: PowerPC,4080@4 {
113 device_type = "cpu";
114 reg = <4>;
115 next-level-cache = <&L2_4>;
116 L2_4: l2-cache {
117 next-level-cache = <&cpc>;
118 };
119 };
120 cpu5: PowerPC,4080@5 {
121 device_type = "cpu";
122 reg = <5>;
123 next-level-cache = <&L2_5>;
124 L2_5: l2-cache {
125 next-level-cache = <&cpc>;
126 };
127 };
128 cpu6: PowerPC,4080@6 {
129 device_type = "cpu";
130 reg = <6>;
131 next-level-cache = <&L2_6>;
132 L2_6: l2-cache {
133 next-level-cache = <&cpc>;
134 };
135 };
136 cpu7: PowerPC,4080@7 {
137 device_type = "cpu";
138 reg = <7>;
139 next-level-cache = <&L2_7>;
140 L2_7: l2-cache {
141 next-level-cache = <&cpc>;
142 };
143 };
144 };
145
146 soc: soc@ffe000000 {
147 #address-cells = <1>;
148 #size-cells = <1>;
149 device_type = "soc";
150 compatible = "simple-bus";
151 ranges = <0x00000000 0xf 0xfe000000 0x1000000>;
152 reg = <0xf 0xfe000000 0 0x00001000>;
153
154 soc-sram-error {
155 compatible = "fsl,soc-sram-error";
156 interrupts = <16 2 1 29>;
157 };
158
159 corenet-law@0 {
160 compatible = "fsl,corenet-law";
161 reg = <0x0 0x1000>;
162 fsl,num-laws = <32>;
163 };
164
165 memory-controller@8000 {
166 compatible = "fsl,qoriq-memory-controller-v4.4", "fsl,qoriq-memory-controller";
167 reg = <0x8000 0x1000>;
168 interrupts = <16 2 1 23>;
169 };
170
171 memory-controller@9000 {
172 compatible = "fsl,qoriq-memory-controller-v4.4","fsl,qoriq-memory-controller";
173 reg = <0x9000 0x1000>;
174 interrupts = <16 2 1 22>;
175 };
176
177 cpc: l3-cache-controller@10000 {
178 compatible = "fsl,p4080-l3-cache-controller", "cache";
179 reg = <0x10000 0x1000
180 0x11000 0x1000>;
181 interrupts = <16 2 1 27
182 16 2 1 26>;
183 };
184
185 corenet-cf@18000 {
186 compatible = "fsl,corenet-cf";
187 reg = <0x18000 0x1000>;
188 interrupts = <16 2 1 31>;
189 fsl,ccf-num-csdids = <32>;
190 fsl,ccf-num-snoopids = <32>;
191 };
192
193 iommu@20000 {
194 compatible = "fsl,pamu-v1.0", "fsl,pamu";
195 reg = <0x20000 0x5000>;
196 interrupts = <
197 24 2 0 0
198 16 2 1 30>;
199 };
200
201 mpic: pic@40000 {
202 clock-frequency = <0>;
203 interrupt-controller;
204 #address-cells = <0>;
205 #interrupt-cells = <4>;
206 reg = <0x40000 0x40000>;
207 compatible = "fsl,mpic", "chrp,open-pic";
208 device_type = "open-pic";
209 };
210
211 msi0: msi@41600 {
212 compatible = "fsl,mpic-msi";
213 reg = <0x41600 0x200>;
214 msi-available-ranges = <0 0x100>;
215 interrupts = <
216 0xe0 0 0 0
217 0xe1 0 0 0
218 0xe2 0 0 0
219 0xe3 0 0 0
220 0xe4 0 0 0
221 0xe5 0 0 0
222 0xe6 0 0 0
223 0xe7 0 0 0>;
224 };
225
226 msi1: msi@41800 {
227 compatible = "fsl,mpic-msi";
228 reg = <0x41800 0x200>;
229 msi-available-ranges = <0 0x100>;
230 interrupts = <
231 0xe8 0 0 0
232 0xe9 0 0 0
233 0xea 0 0 0
234 0xeb 0 0 0
235 0xec 0 0 0
236 0xed 0 0 0
237 0xee 0 0 0
238 0xef 0 0 0>;
239 };
240
241 msi2: msi@41a00 {
242 compatible = "fsl,mpic-msi";
243 reg = <0x41a00 0x200>;
244 msi-available-ranges = <0 0x100>;
245 interrupts = <
246 0xf0 0 0 0
247 0xf1 0 0 0
248 0xf2 0 0 0
249 0xf3 0 0 0
250 0xf4 0 0 0
251 0xf5 0 0 0
252 0xf6 0 0 0
253 0xf7 0 0 0>;
254 };
255
256 guts: global-utilities@e0000 {
257 compatible = "fsl,qoriq-device-config-1.0";
258 reg = <0xe0000 0xe00>;
259 fsl,has-rstcr;
260 #sleep-cells = <1>;
261 fsl,liodn-bits = <12>;
262 };
263
264 pins: global-utilities@e0e00 {
265 compatible = "fsl,qoriq-pin-control-1.0";
266 reg = <0xe0e00 0x200>;
267 #sleep-cells = <2>;
268 };
269
270 clockgen: global-utilities@e1000 {
271 compatible = "fsl,p4080-clockgen", "fsl,qoriq-clockgen-1.0";
272 reg = <0xe1000 0x1000>;
273 clock-frequency = <0>;
274 };
275
276 rcpm: global-utilities@e2000 {
277 compatible = "fsl,qoriq-rcpm-1.0";
278 reg = <0xe2000 0x1000>;
279 #sleep-cells = <1>;
280 };
281
282 sfp: sfp@e8000 {
283 compatible = "fsl,p4080-sfp", "fsl,qoriq-sfp-1.0";
284 reg = <0xe8000 0x1000>;
285 };
286
287 serdes: serdes@ea000 {
288 compatible = "fsl,p4080-serdes";
289 reg = <0xea000 0x1000>;
290 };
291
292 dma0: dma@100300 {
293 #address-cells = <1>;
294 #size-cells = <1>;
295 compatible = "fsl,p4080-dma", "fsl,eloplus-dma";
296 reg = <0x100300 0x4>;
297 ranges = <0x0 0x100100 0x200>;
298 cell-index = <0>;
299 dma-channel@0 {
300 compatible = "fsl,p4080-dma-channel",
301 "fsl,eloplus-dma-channel";
302 reg = <0x0 0x80>;
303 cell-index = <0>;
304 interrupts = <28 2 0 0>;
305 };
306 dma-channel@80 {
307 compatible = "fsl,p4080-dma-channel",
308 "fsl,eloplus-dma-channel";
309 reg = <0x80 0x80>;
310 cell-index = <1>;
311 interrupts = <29 2 0 0>;
312 };
313 dma-channel@100 {
314 compatible = "fsl,p4080-dma-channel",
315 "fsl,eloplus-dma-channel";
316 reg = <0x100 0x80>;
317 cell-index = <2>;
318 interrupts = <30 2 0 0>;
319 };
320 dma-channel@180 {
321 compatible = "fsl,p4080-dma-channel",
322 "fsl,eloplus-dma-channel";
323 reg = <0x180 0x80>;
324 cell-index = <3>;
325 interrupts = <31 2 0 0>;
326 };
327 };
328
329 dma1: dma@101300 {
330 #address-cells = <1>;
331 #size-cells = <1>;
332 compatible = "fsl,p4080-dma", "fsl,eloplus-dma";
333 reg = <0x101300 0x4>;
334 ranges = <0x0 0x101100 0x200>;
335 cell-index = <1>;
336 dma-channel@0 {
337 compatible = "fsl,p4080-dma-channel",
338 "fsl,eloplus-dma-channel";
339 reg = <0x0 0x80>;
340 cell-index = <0>;
341 interrupts = <32 2 0 0>;
342 };
343 dma-channel@80 {
344 compatible = "fsl,p4080-dma-channel",
345 "fsl,eloplus-dma-channel";
346 reg = <0x80 0x80>;
347 cell-index = <1>;
348 interrupts = <33 2 0 0>;
349 };
350 dma-channel@100 {
351 compatible = "fsl,p4080-dma-channel",
352 "fsl,eloplus-dma-channel";
353 reg = <0x100 0x80>;
354 cell-index = <2>;
355 interrupts = <34 2 0 0>;
356 };
357 dma-channel@180 {
358 compatible = "fsl,p4080-dma-channel",
359 "fsl,eloplus-dma-channel";
360 reg = <0x180 0x80>;
361 cell-index = <3>;
362 interrupts = <35 2 0 0>;
363 };
364 };
365
366 spi@110000 {
367 #address-cells = <1>;
368 #size-cells = <0>;
369 compatible = "fsl,p4080-espi", "fsl,mpc8536-espi";
370 reg = <0x110000 0x1000>;
371 interrupts = <53 0x2 0 0>;
372 fsl,espi-num-chipselects = <4>;
373 };
374
375 sdhc: sdhc@114000 {
376 compatible = "fsl,p4080-esdhc", "fsl,esdhc";
377 reg = <0x114000 0x1000>;
378 interrupts = <48 2 0 0>;
379 voltage-ranges = <3300 3300>;
380 sdhci,auto-cmd12;
381 clock-frequency = <0>;
382 };
383
384 i2c@118000 {
385 #address-cells = <1>;
386 #size-cells = <0>;
387 cell-index = <0>;
388 compatible = "fsl-i2c";
389 reg = <0x118000 0x100>;
390 interrupts = <38 2 0 0>;
391 dfsrr;
392 };
393
394 i2c@118100 {
395 #address-cells = <1>;
396 #size-cells = <0>;
397 cell-index = <1>;
398 compatible = "fsl-i2c";
399 reg = <0x118100 0x100>;
400 interrupts = <38 2 0 0>;
401 dfsrr;
402 };
403
404 i2c@119000 {
405 #address-cells = <1>;
406 #size-cells = <0>;
407 cell-index = <2>;
408 compatible = "fsl-i2c";
409 reg = <0x119000 0x100>;
410 interrupts = <39 2 0 0>;
411 dfsrr;
412 };
413
414 i2c@119100 {
415 #address-cells = <1>;
416 #size-cells = <0>;
417 cell-index = <3>;
418 compatible = "fsl-i2c";
419 reg = <0x119100 0x100>;
420 interrupts = <39 2 0 0>;
421 dfsrr;
422 };
423
424 serial0: serial@11c500 {
425 cell-index = <0>;
426 device_type = "serial";
427 compatible = "ns16550";
428 reg = <0x11c500 0x100>;
429 clock-frequency = <0>;
430 interrupts = <36 2 0 0>;
431 };
432
433 serial1: serial@11c600 {
434 cell-index = <1>;
435 device_type = "serial";
436 compatible = "ns16550";
437 reg = <0x11c600 0x100>;
438 clock-frequency = <0>;
439 interrupts = <36 2 0 0>;
440 };
441
442 serial2: serial@11d500 {
443 cell-index = <2>;
444 device_type = "serial";
445 compatible = "ns16550";
446 reg = <0x11d500 0x100>;
447 clock-frequency = <0>;
448 interrupts = <37 2 0 0>;
449 };
450
451 serial3: serial@11d600 {
452 cell-index = <3>;
453 device_type = "serial";
454 compatible = "ns16550";
455 reg = <0x11d600 0x100>;
456 clock-frequency = <0>;
457 interrupts = <37 2 0 0>;
458 };
459
460 gpio0: gpio@130000 {
461 compatible = "fsl,p4080-gpio", "fsl,qoriq-gpio";
462 reg = <0x130000 0x1000>;
463 interrupts = <55 2 0 0>;
464 #gpio-cells = <2>;
465 gpio-controller;
466 };
467
468 usb0: usb@210000 {
469 compatible = "fsl,p4080-usb2-mph",
470 "fsl,mpc85xx-usb2-mph", "fsl-usb2-mph";
471 reg = <0x210000 0x1000>;
472 #address-cells = <1>;
473 #size-cells = <0>;
474 interrupts = <44 0x2 0 0>;
475 };
476
477 usb1: usb@211000 {
478 compatible = "fsl,p4080-usb2-dr",
479 "fsl,mpc85xx-usb2-dr", "fsl-usb2-dr";
480 reg = <0x211000 0x1000>;
481 #address-cells = <1>;
482 #size-cells = <0>;
483 interrupts = <45 0x2 0 0>;
484 };
485
486 crypto: crypto@300000 {
487 compatible = "fsl,sec-v4.0";
488 #address-cells = <1>;
489 #size-cells = <1>;
490 reg = <0x300000 0x10000>;
491 ranges = <0 0x300000 0x10000>;
492 interrupt-parent = <&mpic>;
493 interrupts = <92 2 0 0>;
494
495 sec_jr0: jr@1000 {
496 compatible = "fsl,sec-v4.0-job-ring";
497 reg = <0x1000 0x1000>;
498 interrupt-parent = <&mpic>;
499 interrupts = <88 2 0 0>;
500 };
501
502 sec_jr1: jr@2000 {
503 compatible = "fsl,sec-v4.0-job-ring";
504 reg = <0x2000 0x1000>;
505 interrupt-parent = <&mpic>;
506 interrupts = <89 2 0 0>;
507 };
508
509 sec_jr2: jr@3000 {
510 compatible = "fsl,sec-v4.0-job-ring";
511 reg = <0x3000 0x1000>;
512 interrupt-parent = <&mpic>;
513 interrupts = <90 2 0 0>;
514 };
515
516 sec_jr3: jr@4000 {
517 compatible = "fsl,sec-v4.0-job-ring";
518 reg = <0x4000 0x1000>;
519 interrupt-parent = <&mpic>;
520 interrupts = <91 2 0 0>;
521 };
522
523 rtic@6000 {
524 compatible = "fsl,sec-v4.0-rtic";
525 #address-cells = <1>;
526 #size-cells = <1>;
527 reg = <0x6000 0x100>;
528 ranges = <0x0 0x6100 0xe00>;
529
530 rtic_a: rtic-a@0 {
531 compatible = "fsl,sec-v4.0-rtic-memory";
532 reg = <0x00 0x20 0x100 0x80>;
533 };
534
535 rtic_b: rtic-b@20 {
536 compatible = "fsl,sec-v4.0-rtic-memory";
537 reg = <0x20 0x20 0x200 0x80>;
538 };
539
540 rtic_c: rtic-c@40 {
541 compatible = "fsl,sec-v4.0-rtic-memory";
542 reg = <0x40 0x20 0x300 0x80>;
543 };
544
545 rtic_d: rtic-d@60 {
546 compatible = "fsl,sec-v4.0-rtic-memory";
547 reg = <0x60 0x20 0x500 0x80>;
548 };
549 };
550 };
551
552 sec_mon: sec_mon@314000 {
553 compatible = "fsl,sec-v4.0-mon";
554 reg = <0x314000 0x1000>;
555 interrupt-parent = <&mpic>;
556 interrupts = <93 2 0 0>;
557 };
558 };
559
560 rapidio0: rapidio@ffe0c0000 {
561 #address-cells = <2>;
562 #size-cells = <2>;
563 compatible = "fsl,rapidio-delta";
564 interrupts = <
565 16 2 1 11 /* err_irq */
566 56 2 0 0 /* bell_outb_irq */
567 57 2 0 0 /* bell_inb_irq */
568 60 2 0 0 /* msg1_tx_irq */
569 61 2 0 0 /* msg1_rx_irq */
570 62 2 0 0 /* msg2_tx_irq */
571 63 2 0 0>; /* msg2_rx_irq */
572 };
573
574 localbus@ffe124000 {
575 compatible = "fsl,p4080-elbc", "fsl,elbc", "simple-bus";
576 interrupts = <25 2 0 0>;
577 #address-cells = <2>;
578 #size-cells = <1>;
579 };
580
581 pci0: pcie@ffe200000 {
582 compatible = "fsl,p4080-pcie";
583 device_type = "pci";
584 #size-cells = <2>;
585 #address-cells = <3>;
586 bus-range = <0x0 0xff>;
587 clock-frequency = <0x1fca055>;
588 fsl,msi = <&msi0>;
589 interrupts = <16 2 1 15>;
590 pcie@0 {
591 reg = <0 0 0 0 0>;
592 #interrupt-cells = <1>;
593 #size-cells = <2>;
594 #address-cells = <3>;
595 device_type = "pci";
596 interrupts = <16 2 1 15>;
597 interrupt-map-mask = <0xf800 0 0 7>;
598 interrupt-map = <
599 /* IDSEL 0x0 */
600 0000 0 0 1 &mpic 40 1 0 0
601 0000 0 0 2 &mpic 1 1 0 0
602 0000 0 0 3 &mpic 2 1 0 0
603 0000 0 0 4 &mpic 3 1 0 0
604 >;
605 };
606 };
607
608 pci1: pcie@ffe201000 {
609 compatible = "fsl,p4080-pcie";
610 device_type = "pci";
611 #size-cells = <2>;
612 #address-cells = <3>;
613 bus-range = <0 0xff>;
614 clock-frequency = <0x1fca055>;
615 fsl,msi = <&msi1>;
616 interrupts = <16 2 1 14>;
617 pcie@0 {
618 reg = <0 0 0 0 0>;
619 #interrupt-cells = <1>;
620 #size-cells = <2>;
621 #address-cells = <3>;
622 device_type = "pci";
623 interrupts = <16 2 1 14>;
624 interrupt-map-mask = <0xf800 0 0 7>;
625 interrupt-map = <
626 /* IDSEL 0x0 */
627 0000 0 0 1 &mpic 41 1 0 0
628 0000 0 0 2 &mpic 5 1 0 0
629 0000 0 0 3 &mpic 6 1 0 0
630 0000 0 0 4 &mpic 7 1 0 0
631 >;
632 };
633 };
634
635 pci2: pcie@ffe202000 {
636 compatible = "fsl,p4080-pcie";
637 device_type = "pci";
638 #size-cells = <2>;
639 #address-cells = <3>;
640 bus-range = <0x0 0xff>;
641 clock-frequency = <0x1fca055>;
642 fsl,msi = <&msi2>;
643 interrupts = <16 2 1 13>;
644 pcie@0 {
645 reg = <0 0 0 0 0>;
646 #interrupt-cells = <1>;
647 #size-cells = <2>;
648 #address-cells = <3>;
649 device_type = "pci";
650 interrupts = <16 2 1 13>;
651 interrupt-map-mask = <0xf800 0 0 7>;
652 interrupt-map = <
653 /* IDSEL 0x0 */
654 0000 0 0 1 &mpic 42 1 0 0
655 0000 0 0 2 &mpic 9 1 0 0
656 0000 0 0 3 &mpic 10 1 0 0
657 0000 0 0 4 &mpic 11 1 0 0
658 >;
659 };
660 };
661};
diff --git a/arch/powerpc/boot/dts/p5020si.dtsi b/arch/powerpc/boot/dts/p5020si.dtsi
new file mode 100644
index 00000000000..5e6048ec55b
--- /dev/null
+++ b/arch/powerpc/boot/dts/p5020si.dtsi
@@ -0,0 +1,652 @@
1/*
2 * P5020 Silicon Device Tree Source
3 *
4 * Copyright 2010-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/dts-v1/;
36
37/ {
38 compatible = "fsl,P5020";
39 #address-cells = <2>;
40 #size-cells = <2>;
41 interrupt-parent = <&mpic>;
42
43 aliases {
44 ccsr = &soc;
45
46 serial0 = &serial0;
47 serial1 = &serial1;
48 serial2 = &serial2;
49 serial3 = &serial3;
50 pci0 = &pci0;
51 pci1 = &pci1;
52 pci2 = &pci2;
53 pci3 = &pci3;
54 usb0 = &usb0;
55 usb1 = &usb1;
56 dma0 = &dma0;
57 dma1 = &dma1;
58 sdhc = &sdhc;
59 msi0 = &msi0;
60 msi1 = &msi1;
61 msi2 = &msi2;
62
63 crypto = &crypto;
64 sec_jr0 = &sec_jr0;
65 sec_jr1 = &sec_jr1;
66 sec_jr2 = &sec_jr2;
67 sec_jr3 = &sec_jr3;
68 rtic_a = &rtic_a;
69 rtic_b = &rtic_b;
70 rtic_c = &rtic_c;
71 rtic_d = &rtic_d;
72 sec_mon = &sec_mon;
73
74/*
75 rio0 = &rapidio0;
76 */
77 };
78
79 cpus {
80 #address-cells = <1>;
81 #size-cells = <0>;
82
83 cpu0: PowerPC,e5500@0 {
84 device_type = "cpu";
85 reg = <0>;
86 next-level-cache = <&L2_0>;
87 L2_0: l2-cache {
88 next-level-cache = <&cpc>;
89 };
90 };
91 cpu1: PowerPC,e5500@1 {
92 device_type = "cpu";
93 reg = <1>;
94 next-level-cache = <&L2_1>;
95 L2_1: l2-cache {
96 next-level-cache = <&cpc>;
97 };
98 };
99 };
100
101 soc: soc@ffe000000 {
102 #address-cells = <1>;
103 #size-cells = <1>;
104 device_type = "soc";
105 compatible = "simple-bus";
106 ranges = <0x00000000 0xf 0xfe000000 0x1000000>;
107 reg = <0xf 0xfe000000 0 0x00001000>;
108
109 soc-sram-error {
110 compatible = "fsl,soc-sram-error";
111 interrupts = <16 2 1 29>;
112 };
113
114 corenet-law@0 {
115 compatible = "fsl,corenet-law";
116 reg = <0x0 0x1000>;
117 fsl,num-laws = <32>;
118 };
119
120 memory-controller@8000 {
121 compatible = "fsl,qoriq-memory-controller-v4.5", "fsl,qoriq-memory-controller";
122 reg = <0x8000 0x1000>;
123 interrupts = <16 2 1 23>;
124 };
125
126 memory-controller@9000 {
127 compatible = "fsl,qoriq-memory-controller-v4.5", "fsl,qoriq-memory-controller";
128 reg = <0x9000 0x1000>;
129 interrupts = <16 2 1 22>;
130 };
131
132 cpc: l3-cache-controller@10000 {
133 compatible = "fsl,p5020-l3-cache-controller", "fsl,p4080-l3-cache-controller", "cache";
134 reg = <0x10000 0x1000
135 0x11000 0x1000>;
136 interrupts = <16 2 1 27
137 16 2 1 26>;
138 };
139
140 corenet-cf@18000 {
141 compatible = "fsl,corenet-cf";
142 reg = <0x18000 0x1000>;
143 interrupts = <16 2 1 31>;
144 fsl,ccf-num-csdids = <32>;
145 fsl,ccf-num-snoopids = <32>;
146 };
147
148 iommu@20000 {
149 compatible = "fsl,pamu-v1.0", "fsl,pamu";
150 reg = <0x20000 0x4000>;
151 interrupts = <
152 24 2 0 0
153 16 2 1 30>;
154 };
155
156 mpic: pic@40000 {
157 clock-frequency = <0>;
158 interrupt-controller;
159 #address-cells = <0>;
160 #interrupt-cells = <4>;
161 reg = <0x40000 0x40000>;
162 compatible = "fsl,mpic", "chrp,open-pic";
163 device_type = "open-pic";
164 };
165
166 msi0: msi@41600 {
167 compatible = "fsl,mpic-msi";
168 reg = <0x41600 0x200>;
169 msi-available-ranges = <0 0x100>;
170 interrupts = <
171 0xe0 0 0 0
172 0xe1 0 0 0
173 0xe2 0 0 0
174 0xe3 0 0 0
175 0xe4 0 0 0
176 0xe5 0 0 0
177 0xe6 0 0 0
178 0xe7 0 0 0>;
179 };
180
181 msi1: msi@41800 {
182 compatible = "fsl,mpic-msi";
183 reg = <0x41800 0x200>;
184 msi-available-ranges = <0 0x100>;
185 interrupts = <
186 0xe8 0 0 0
187 0xe9 0 0 0
188 0xea 0 0 0
189 0xeb 0 0 0
190 0xec 0 0 0
191 0xed 0 0 0
192 0xee 0 0 0
193 0xef 0 0 0>;
194 };
195
196 msi2: msi@41a00 {
197 compatible = "fsl,mpic-msi";
198 reg = <0x41a00 0x200>;
199 msi-available-ranges = <0 0x100>;
200 interrupts = <
201 0xf0 0 0 0
202 0xf1 0 0 0
203 0xf2 0 0 0
204 0xf3 0 0 0
205 0xf4 0 0 0
206 0xf5 0 0 0
207 0xf6 0 0 0
208 0xf7 0 0 0>;
209 };
210
211 guts: global-utilities@e0000 {
212 compatible = "fsl,qoriq-device-config-1.0";
213 reg = <0xe0000 0xe00>;
214 fsl,has-rstcr;
215 #sleep-cells = <1>;
216 fsl,liodn-bits = <12>;
217 };
218
219 pins: global-utilities@e0e00 {
220 compatible = "fsl,qoriq-pin-control-1.0";
221 reg = <0xe0e00 0x200>;
222 #sleep-cells = <2>;
223 };
224
225 clockgen: global-utilities@e1000 {
226 compatible = "fsl,p5020-clockgen", "fsl,qoriq-clockgen-1.0";
227 reg = <0xe1000 0x1000>;
228 clock-frequency = <0>;
229 };
230
231 rcpm: global-utilities@e2000 {
232 compatible = "fsl,qoriq-rcpm-1.0";
233 reg = <0xe2000 0x1000>;
234 #sleep-cells = <1>;
235 };
236
237 sfp: sfp@e8000 {
238 compatible = "fsl,p5020-sfp", "fsl,qoriq-sfp-1.0";
239 reg = <0xe8000 0x1000>;
240 };
241
242 serdes: serdes@ea000 {
243 compatible = "fsl,p5020-serdes";
244 reg = <0xea000 0x1000>;
245 };
246
247 dma0: dma@100300 {
248 #address-cells = <1>;
249 #size-cells = <1>;
250 compatible = "fsl,p5020-dma", "fsl,eloplus-dma";
251 reg = <0x100300 0x4>;
252 ranges = <0x0 0x100100 0x200>;
253 cell-index = <0>;
254 dma-channel@0 {
255 compatible = "fsl,p5020-dma-channel",
256 "fsl,eloplus-dma-channel";
257 reg = <0x0 0x80>;
258 cell-index = <0>;
259 interrupts = <28 2 0 0>;
260 };
261 dma-channel@80 {
262 compatible = "fsl,p5020-dma-channel",
263 "fsl,eloplus-dma-channel";
264 reg = <0x80 0x80>;
265 cell-index = <1>;
266 interrupts = <29 2 0 0>;
267 };
268 dma-channel@100 {
269 compatible = "fsl,p5020-dma-channel",
270 "fsl,eloplus-dma-channel";
271 reg = <0x100 0x80>;
272 cell-index = <2>;
273 interrupts = <30 2 0 0>;
274 };
275 dma-channel@180 {
276 compatible = "fsl,p5020-dma-channel",
277 "fsl,eloplus-dma-channel";
278 reg = <0x180 0x80>;
279 cell-index = <3>;
280 interrupts = <31 2 0 0>;
281 };
282 };
283
284 dma1: dma@101300 {
285 #address-cells = <1>;
286 #size-cells = <1>;
287 compatible = "fsl,p5020-dma", "fsl,eloplus-dma";
288 reg = <0x101300 0x4>;
289 ranges = <0x0 0x101100 0x200>;
290 cell-index = <1>;
291 dma-channel@0 {
292 compatible = "fsl,p5020-dma-channel",
293 "fsl,eloplus-dma-channel";
294 reg = <0x0 0x80>;
295 cell-index = <0>;
296 interrupts = <32 2 0 0>;
297 };
298 dma-channel@80 {
299 compatible = "fsl,p5020-dma-channel",
300 "fsl,eloplus-dma-channel";
301 reg = <0x80 0x80>;
302 cell-index = <1>;
303 interrupts = <33 2 0 0>;
304 };
305 dma-channel@100 {
306 compatible = "fsl,p5020-dma-channel",
307 "fsl,eloplus-dma-channel";
308 reg = <0x100 0x80>;
309 cell-index = <2>;
310 interrupts = <34 2 0 0>;
311 };
312 dma-channel@180 {
313 compatible = "fsl,p5020-dma-channel",
314 "fsl,eloplus-dma-channel";
315 reg = <0x180 0x80>;
316 cell-index = <3>;
317 interrupts = <35 2 0 0>;
318 };
319 };
320
321 spi@110000 {
322 #address-cells = <1>;
323 #size-cells = <0>;
324 compatible = "fsl,p5020-espi", "fsl,mpc8536-espi";
325 reg = <0x110000 0x1000>;
326 interrupts = <53 0x2 0 0>;
327 fsl,espi-num-chipselects = <4>;
328 };
329
330 sdhc: sdhc@114000 {
331 compatible = "fsl,p5020-esdhc", "fsl,esdhc";
332 reg = <0x114000 0x1000>;
333 interrupts = <48 2 0 0>;
334 sdhci,auto-cmd12;
335 clock-frequency = <0>;
336 };
337
338 i2c@118000 {
339 #address-cells = <1>;
340 #size-cells = <0>;
341 cell-index = <0>;
342 compatible = "fsl-i2c";
343 reg = <0x118000 0x100>;
344 interrupts = <38 2 0 0>;
345 dfsrr;
346 };
347
348 i2c@118100 {
349 #address-cells = <1>;
350 #size-cells = <0>;
351 cell-index = <1>;
352 compatible = "fsl-i2c";
353 reg = <0x118100 0x100>;
354 interrupts = <38 2 0 0>;
355 dfsrr;
356 };
357
358 i2c@119000 {
359 #address-cells = <1>;
360 #size-cells = <0>;
361 cell-index = <2>;
362 compatible = "fsl-i2c";
363 reg = <0x119000 0x100>;
364 interrupts = <39 2 0 0>;
365 dfsrr;
366 };
367
368 i2c@119100 {
369 #address-cells = <1>;
370 #size-cells = <0>;
371 cell-index = <3>;
372 compatible = "fsl-i2c";
373 reg = <0x119100 0x100>;
374 interrupts = <39 2 0 0>;
375 dfsrr;
376 };
377
378 serial0: serial@11c500 {
379 cell-index = <0>;
380 device_type = "serial";
381 compatible = "ns16550";
382 reg = <0x11c500 0x100>;
383 clock-frequency = <0>;
384 interrupts = <36 2 0 0>;
385 };
386
387 serial1: serial@11c600 {
388 cell-index = <1>;
389 device_type = "serial";
390 compatible = "ns16550";
391 reg = <0x11c600 0x100>;
392 clock-frequency = <0>;
393 interrupts = <36 2 0 0>;
394 };
395
396 serial2: serial@11d500 {
397 cell-index = <2>;
398 device_type = "serial";
399 compatible = "ns16550";
400 reg = <0x11d500 0x100>;
401 clock-frequency = <0>;
402 interrupts = <37 2 0 0>;
403 };
404
405 serial3: serial@11d600 {
406 cell-index = <3>;
407 device_type = "serial";
408 compatible = "ns16550";
409 reg = <0x11d600 0x100>;
410 clock-frequency = <0>;
411 interrupts = <37 2 0 0>;
412 };
413
414 gpio0: gpio@130000 {
415 compatible = "fsl,p5020-gpio", "fsl,qoriq-gpio";
416 reg = <0x130000 0x1000>;
417 interrupts = <55 2 0 0>;
418 #gpio-cells = <2>;
419 gpio-controller;
420 };
421
422 usb0: usb@210000 {
423 compatible = "fsl,p5020-usb2-mph",
424 "fsl,mpc85xx-usb2-mph", "fsl-usb2-mph";
425 reg = <0x210000 0x1000>;
426 #address-cells = <1>;
427 #size-cells = <0>;
428 interrupts = <44 0x2 0 0>;
429 phy_type = "utmi";
430 port0;
431 };
432
433 usb1: usb@211000 {
434 compatible = "fsl,p5020-usb2-dr",
435 "fsl,mpc85xx-usb2-dr", "fsl-usb2-dr";
436 reg = <0x211000 0x1000>;
437 #address-cells = <1>;
438 #size-cells = <0>;
439 interrupts = <45 0x2 0 0>;
440 dr_mode = "host";
441 phy_type = "utmi";
442 };
443
444 sata@220000 {
445 compatible = "fsl,p5020-sata", "fsl,pq-sata-v2";
446 reg = <0x220000 0x1000>;
447 interrupts = <68 0x2 0 0>;
448 };
449
450 sata@221000 {
451 compatible = "fsl,p5020-sata", "fsl,pq-sata-v2";
452 reg = <0x221000 0x1000>;
453 interrupts = <69 0x2 0 0>;
454 };
455
456 crypto: crypto@300000 {
457 compatible = "fsl,sec-v4.2", "fsl,sec-v4.0";
458 #address-cells = <1>;
459 #size-cells = <1>;
460 reg = <0x300000 0x10000>;
461 ranges = <0 0x300000 0x10000>;
462 interrupts = <92 2 0 0>;
463
464 sec_jr0: jr@1000 {
465 compatible = "fsl,sec-v4.2-job-ring",
466 "fsl,sec-v4.0-job-ring";
467 reg = <0x1000 0x1000>;
468 interrupts = <88 2 0 0>;
469 };
470
471 sec_jr1: jr@2000 {
472 compatible = "fsl,sec-v4.2-job-ring",
473 "fsl,sec-v4.0-job-ring";
474 reg = <0x2000 0x1000>;
475 interrupts = <89 2 0 0>;
476 };
477
478 sec_jr2: jr@3000 {
479 compatible = "fsl,sec-v4.2-job-ring",
480 "fsl,sec-v4.0-job-ring";
481 reg = <0x3000 0x1000>;
482 interrupts = <90 2 0 0>;
483 };
484
485 sec_jr3: jr@4000 {
486 compatible = "fsl,sec-v4.2-job-ring",
487 "fsl,sec-v4.0-job-ring";
488 reg = <0x4000 0x1000>;
489 interrupts = <91 2 0 0>;
490 };
491
492 rtic@6000 {
493 compatible = "fsl,sec-v4.2-rtic",
494 "fsl,sec-v4.0-rtic";
495 #address-cells = <1>;
496 #size-cells = <1>;
497 reg = <0x6000 0x100>;
498 ranges = <0x0 0x6100 0xe00>;
499
500 rtic_a: rtic-a@0 {
501 compatible = "fsl,sec-v4.2-rtic-memory",
502 "fsl,sec-v4.0-rtic-memory";
503 reg = <0x00 0x20 0x100 0x80>;
504 };
505
506 rtic_b: rtic-b@20 {
507 compatible = "fsl,sec-v4.2-rtic-memory",
508 "fsl,sec-v4.0-rtic-memory";
509 reg = <0x20 0x20 0x200 0x80>;
510 };
511
512 rtic_c: rtic-c@40 {
513 compatible = "fsl,sec-v4.2-rtic-memory",
514 "fsl,sec-v4.0-rtic-memory";
515 reg = <0x40 0x20 0x300 0x80>;
516 };
517
518 rtic_d: rtic-d@60 {
519 compatible = "fsl,sec-v4.2-rtic-memory",
520 "fsl,sec-v4.0-rtic-memory";
521 reg = <0x60 0x20 0x500 0x80>;
522 };
523 };
524 };
525
526 sec_mon: sec_mon@314000 {
527 compatible = "fsl,sec-v4.2-mon", "fsl,sec-v4.0-mon";
528 reg = <0x314000 0x1000>;
529 interrupts = <93 2 0 0>;
530 };
531 };
532
533/*
534 rapidio0: rapidio@ffe0c0000
535*/
536
537 localbus@ffe124000 {
538 compatible = "fsl,p5020-elbc", "fsl,elbc", "simple-bus";
539 interrupts = <25 2 0 0>;
540 #address-cells = <2>;
541 #size-cells = <1>;
542 };
543
544 pci0: pcie@ffe200000 {
545 compatible = "fsl,p5020-pcie", "fsl,qoriq-pcie-v2.2";
546 device_type = "pci";
547 #size-cells = <2>;
548 #address-cells = <3>;
549 bus-range = <0x0 0xff>;
550 clock-frequency = <0x1fca055>;
551 fsl,msi = <&msi0>;
552 interrupts = <16 2 1 15>;
553
554 pcie@0 {
555 reg = <0 0 0 0 0>;
556 #interrupt-cells = <1>;
557 #size-cells = <2>;
558 #address-cells = <3>;
559 device_type = "pci";
560 interrupts = <16 2 1 15>;
561 interrupt-map-mask = <0xf800 0 0 7>;
562 interrupt-map = <
563 /* IDSEL 0x0 */
564 0000 0 0 1 &mpic 40 1 0 0
565 0000 0 0 2 &mpic 1 1 0 0
566 0000 0 0 3 &mpic 2 1 0 0
567 0000 0 0 4 &mpic 3 1 0 0
568 >;
569 };
570 };
571
572 pci1: pcie@ffe201000 {
573 compatible = "fsl,p5020-pcie", "fsl,qoriq-pcie-v2.2";
574 device_type = "pci";
575 #size-cells = <2>;
576 #address-cells = <3>;
577 bus-range = <0 0xff>;
578 clock-frequency = <0x1fca055>;
579 fsl,msi = <&msi1>;
580 interrupts = <16 2 1 14>;
581 pcie@0 {
582 reg = <0 0 0 0 0>;
583 #interrupt-cells = <1>;
584 #size-cells = <2>;
585 #address-cells = <3>;
586 device_type = "pci";
587 interrupts = <16 2 1 14>;
588 interrupt-map-mask = <0xf800 0 0 7>;
589 interrupt-map = <
590 /* IDSEL 0x0 */
591 0000 0 0 1 &mpic 41 1 0 0
592 0000 0 0 2 &mpic 5 1 0 0
593 0000 0 0 3 &mpic 6 1 0 0
594 0000 0 0 4 &mpic 7 1 0 0
595 >;
596 };
597 };
598
599 pci2: pcie@ffe202000 {
600 compatible = "fsl,p5020-pcie", "fsl,qoriq-pcie-v2.2";
601 device_type = "pci";
602 #size-cells = <2>;
603 #address-cells = <3>;
604 bus-range = <0x0 0xff>;
605 clock-frequency = <0x1fca055>;
606 fsl,msi = <&msi2>;
607 interrupts = <16 2 1 13>;
608 pcie@0 {
609 reg = <0 0 0 0 0>;
610 #interrupt-cells = <1>;
611 #size-cells = <2>;
612 #address-cells = <3>;
613 device_type = "pci";
614 interrupts = <16 2 1 13>;
615 interrupt-map-mask = <0xf800 0 0 7>;
616 interrupt-map = <
617 /* IDSEL 0x0 */
618 0000 0 0 1 &mpic 42 1 0 0
619 0000 0 0 2 &mpic 9 1 0 0
620 0000 0 0 3 &mpic 10 1 0 0
621 0000 0 0 4 &mpic 11 1 0 0
622 >;
623 };
624 };
625
626 pci3: pcie@ffe203000 {
627 compatible = "fsl,p5020-pcie", "fsl,qoriq-pcie-v2.2";
628 device_type = "pci";
629 #size-cells = <2>;
630 #address-cells = <3>;
631 bus-range = <0x0 0xff>;
632 clock-frequency = <0x1fca055>;
633 fsl,msi = <&msi2>;
634 interrupts = <16 2 1 12>;
635 pcie@0 {
636 reg = <0 0 0 0 0>;
637 #interrupt-cells = <1>;
638 #size-cells = <2>;
639 #address-cells = <3>;
640 device_type = "pci";
641 interrupts = <16 2 1 12>;
642 interrupt-map-mask = <0xf800 0 0 7>;
643 interrupt-map = <
644 /* IDSEL 0x0 */
645 0000 0 0 1 &mpic 43 1 0 0
646 0000 0 0 2 &mpic 0 1 0 0
647 0000 0 0 3 &mpic 4 1 0 0
648 0000 0 0 4 &mpic 8 1 0 0
649 >;
650 };
651 };
652};
diff --git a/arch/powerpc/boot/dts/sbc8560.dts b/arch/powerpc/boot/dts/sbc8560.dts
new file mode 100644
index 00000000000..9e13ed8a119
--- /dev/null
+++ b/arch/powerpc/boot/dts/sbc8560.dts
@@ -0,0 +1,406 @@
1/*
2 * SBC8560 Device Tree Source
3 *
4 * Copyright 2007 Wind River Systems Inc.
5 *
6 * Paul Gortmaker (see MAINTAINERS for contact information)
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 */
13
14/dts-v1/;
15
16/ {
17 model = "SBC8560";
18 compatible = "SBC8560";
19 #address-cells = <1>;
20 #size-cells = <1>;
21
22 aliases {
23 ethernet0 = &enet0;
24 ethernet1 = &enet1;
25 ethernet2 = &enet2;
26 ethernet3 = &enet3;
27 serial0 = &serial0;
28 serial1 = &serial1;
29 pci0 = &pci0;
30 };
31
32 cpus {
33 #address-cells = <1>;
34 #size-cells = <0>;
35
36 PowerPC,8560@0 {
37 device_type = "cpu";
38 reg = <0>;
39 d-cache-line-size = <0x20>; // 32 bytes
40 i-cache-line-size = <0x20>; // 32 bytes
41 d-cache-size = <0x8000>; // L1, 32K
42 i-cache-size = <0x8000>; // L1, 32K
43 timebase-frequency = <0>; // From uboot
44 bus-frequency = <0>;
45 clock-frequency = <0>;
46 next-level-cache = <&L2>;
47 };
48 };
49
50 memory {
51 device_type = "memory";
52 reg = <0x00000000 0x20000000>;
53 };
54
55 soc@ff700000 {
56 #address-cells = <1>;
57 #size-cells = <1>;
58 device_type = "soc";
59 ranges = <0x0 0xff700000 0x00100000>;
60 clock-frequency = <0>;
61
62 ecm-law@0 {
63 compatible = "fsl,ecm-law";
64 reg = <0x0 0x1000>;
65 fsl,num-laws = <8>;
66 };
67
68 ecm@1000 {
69 compatible = "fsl,mpc8560-ecm", "fsl,ecm";
70 reg = <0x1000 0x1000>;
71 interrupts = <17 2>;
72 interrupt-parent = <&mpic>;
73 };
74
75 memory-controller@2000 {
76 compatible = "fsl,mpc8560-memory-controller";
77 reg = <0x2000 0x1000>;
78 interrupt-parent = <&mpic>;
79 interrupts = <0x12 0x2>;
80 };
81
82 L2: l2-cache-controller@20000 {
83 compatible = "fsl,mpc8560-l2-cache-controller";
84 reg = <0x20000 0x1000>;
85 cache-line-size = <0x20>; // 32 bytes
86 cache-size = <0x40000>; // L2, 256K
87 interrupt-parent = <&mpic>;
88 interrupts = <0x10 0x2>;
89 };
90
91 i2c@3000 {
92 #address-cells = <1>;
93 #size-cells = <0>;
94 cell-index = <0>;
95 compatible = "fsl-i2c";
96 reg = <0x3000 0x100>;
97 interrupts = <0x2b 0x2>;
98 interrupt-parent = <&mpic>;
99 dfsrr;
100 };
101
102 i2c@3100 {
103 #address-cells = <1>;
104 #size-cells = <0>;
105 cell-index = <1>;
106 compatible = "fsl-i2c";
107 reg = <0x3100 0x100>;
108 interrupts = <0x2b 0x2>;
109 interrupt-parent = <&mpic>;
110 dfsrr;
111 };
112
113 dma@21300 {
114 #address-cells = <1>;
115 #size-cells = <1>;
116 compatible = "fsl,mpc8560-dma", "fsl,eloplus-dma";
117 reg = <0x21300 0x4>;
118 ranges = <0x0 0x21100 0x200>;
119 cell-index = <0>;
120 dma-channel@0 {
121 compatible = "fsl,mpc8560-dma-channel",
122 "fsl,eloplus-dma-channel";
123 reg = <0x0 0x80>;
124 cell-index = <0>;
125 interrupt-parent = <&mpic>;
126 interrupts = <20 2>;
127 };
128 dma-channel@80 {
129 compatible = "fsl,mpc8560-dma-channel",
130 "fsl,eloplus-dma-channel";
131 reg = <0x80 0x80>;
132 cell-index = <1>;
133 interrupt-parent = <&mpic>;
134 interrupts = <21 2>;
135 };
136 dma-channel@100 {
137 compatible = "fsl,mpc8560-dma-channel",
138 "fsl,eloplus-dma-channel";
139 reg = <0x100 0x80>;
140 cell-index = <2>;
141 interrupt-parent = <&mpic>;
142 interrupts = <22 2>;
143 };
144 dma-channel@180 {
145 compatible = "fsl,mpc8560-dma-channel",
146 "fsl,eloplus-dma-channel";
147 reg = <0x180 0x80>;
148 cell-index = <3>;
149 interrupt-parent = <&mpic>;
150 interrupts = <23 2>;
151 };
152 };
153
154 enet0: ethernet@24000 {
155 #address-cells = <1>;
156 #size-cells = <1>;
157 cell-index = <0>;
158 device_type = "network";
159 model = "TSEC";
160 compatible = "gianfar";
161 reg = <0x24000 0x1000>;
162 ranges = <0x0 0x24000 0x1000>;
163 local-mac-address = [ 00 00 00 00 00 00 ];
164 interrupts = <0x1d 0x2 0x1e 0x2 0x22 0x2>;
165 interrupt-parent = <&mpic>;
166 tbi-handle = <&tbi0>;
167 phy-handle = <&phy0>;
168
169 mdio@520 {
170 #address-cells = <1>;
171 #size-cells = <0>;
172 compatible = "fsl,gianfar-mdio";
173 reg = <0x520 0x20>;
174 phy0: ethernet-phy@19 {
175 interrupt-parent = <&mpic>;
176 interrupts = <0x6 0x1>;
177 reg = <0x19>;
178 device_type = "ethernet-phy";
179 };
180 phy1: ethernet-phy@1a {
181 interrupt-parent = <&mpic>;
182 interrupts = <0x7 0x1>;
183 reg = <0x1a>;
184 device_type = "ethernet-phy";
185 };
186 phy2: ethernet-phy@1b {
187 interrupt-parent = <&mpic>;
188 interrupts = <0x8 0x1>;
189 reg = <0x1b>;
190 device_type = "ethernet-phy";
191 };
192 phy3: ethernet-phy@1c {
193 interrupt-parent = <&mpic>;
194 interrupts = <0x8 0x1>;
195 reg = <0x1c>;
196 device_type = "ethernet-phy";
197 };
198 tbi0: tbi-phy@11 {
199 reg = <0x11>;
200 device_type = "tbi-phy";
201 };
202 };
203 };
204
205 enet1: ethernet@25000 {
206 #address-cells = <1>;
207 #size-cells = <1>;
208 cell-index = <1>;
209 device_type = "network";
210 model = "TSEC";
211 compatible = "gianfar";
212 reg = <0x25000 0x1000>;
213 ranges = <0x0 0x25000 0x1000>;
214 local-mac-address = [ 00 00 00 00 00 00 ];
215 interrupts = <0x23 0x2 0x24 0x2 0x28 0x2>;
216 interrupt-parent = <&mpic>;
217 tbi-handle = <&tbi1>;
218 phy-handle = <&phy1>;
219
220 mdio@520 {
221 #address-cells = <1>;
222 #size-cells = <0>;
223 compatible = "fsl,gianfar-tbi";
224 reg = <0x520 0x20>;
225
226 tbi1: tbi-phy@11 {
227 reg = <0x11>;
228 device_type = "tbi-phy";
229 };
230 };
231 };
232
233 mpic: pic@40000 {
234 interrupt-controller;
235 #address-cells = <0>;
236 #interrupt-cells = <2>;
237 compatible = "chrp,open-pic";
238 reg = <0x40000 0x40000>;
239 device_type = "open-pic";
240 };
241
242 cpm@919c0 {
243 #address-cells = <1>;
244 #size-cells = <1>;
245 compatible = "fsl,mpc8560-cpm", "fsl,cpm2";
246 reg = <0x919c0 0x30>;
247 ranges;
248
249 muram@80000 {
250 #address-cells = <1>;
251 #size-cells = <1>;
252 ranges = <0x0 0x80000 0x10000>;
253
254 data@0 {
255 compatible = "fsl,cpm-muram-data";
256 reg = <0x0 0x4000 0x9000 0x2000>;
257 };
258 };
259
260 brg@919f0 {
261 compatible = "fsl,mpc8560-brg",
262 "fsl,cpm2-brg",
263 "fsl,cpm-brg";
264 reg = <0x919f0 0x10 0x915f0 0x10>;
265 clock-frequency = <165000000>;
266 };
267
268 cpmpic: pic@90c00 {
269 interrupt-controller;
270 #address-cells = <0>;
271 #interrupt-cells = <2>;
272 interrupts = <0x2e 0x2>;
273 interrupt-parent = <&mpic>;
274 reg = <0x90c00 0x80>;
275 compatible = "fsl,mpc8560-cpm-pic", "fsl,cpm2-pic";
276 };
277
278 enet2: ethernet@91320 {
279 device_type = "network";
280 compatible = "fsl,mpc8560-fcc-enet",
281 "fsl,cpm2-fcc-enet";
282 reg = <0x91320 0x20 0x88500 0x100 0x913b0 0x1>;
283 local-mac-address = [ 00 00 00 00 00 00 ];
284 fsl,cpm-command = <0x16200300>;
285 interrupts = <0x21 0x8>;
286 interrupt-parent = <&cpmpic>;
287 phy-handle = <&phy2>;
288 };
289
290 enet3: ethernet@91340 {
291 device_type = "network";
292 compatible = "fsl,mpc8560-fcc-enet",
293 "fsl,cpm2-fcc-enet";
294 reg = <0x91340 0x20 0x88600 0x100 0x913d0 0x1>;
295 local-mac-address = [ 00 00 00 00 00 00 ];
296 fsl,cpm-command = <0x1a400300>;
297 interrupts = <0x22 0x8>;
298 interrupt-parent = <&cpmpic>;
299 phy-handle = <&phy3>;
300 };
301 };
302
303 global-utilities@e0000 {
304 compatible = "fsl,mpc8560-guts";
305 reg = <0xe0000 0x1000>;
306 };
307 };
308
309 pci0: pci@ff708000 {
310 #interrupt-cells = <1>;
311 #size-cells = <2>;
312 #address-cells = <3>;
313 compatible = "fsl,mpc8540-pcix", "fsl,mpc8540-pci";
314 device_type = "pci";
315 reg = <0xff708000 0x1000>;
316 clock-frequency = <66666666>;
317 interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
318 interrupt-map = <
319
320 /* IDSEL 0x02 */
321 0x1000 0x0 0x0 0x1 &mpic 0x2 0x1
322 0x1000 0x0 0x0 0x2 &mpic 0x3 0x1
323 0x1000 0x0 0x0 0x3 &mpic 0x4 0x1
324 0x1000 0x0 0x0 0x4 &mpic 0x5 0x1>;
325
326 interrupt-parent = <&mpic>;
327 interrupts = <0x18 0x2>;
328 bus-range = <0x0 0x0>;
329 ranges = <0x02000000 0x0 0x80000000 0x80000000 0x0 0x20000000
330 0x01000000 0x0 0x00000000 0xe2000000 0x0 0x00100000>;
331 };
332
333 localbus@ff705000 {
334 compatible = "fsl,mpc8560-localbus";
335 #address-cells = <2>;
336 #size-cells = <1>;
337 reg = <0xff705000 0x100>; // BRx, ORx, etc.
338
339 ranges = <
340 0x0 0x0 0xff800000 0x0800000 // 8MB boot flash
341 0x1 0x0 0xe4000000 0x4000000 // 64MB flash
342 0x3 0x0 0x20000000 0x4000000 // 64MB SDRAM
343 0x4 0x0 0x24000000 0x4000000 // 64MB SDRAM
344 0x5 0x0 0xfc000000 0x0c00000 // EPLD
345 0x6 0x0 0xe0000000 0x4000000 // 64MB flash
346 0x7 0x0 0x80000000 0x0200000 // ATM1,2
347 >;
348
349 epld@5,0 {
350 compatible = "wrs,epld-localbus";
351 #address-cells = <2>;
352 #size-cells = <1>;
353 reg = <0x5 0x0 0xc00000>;
354 ranges = <
355 0x0 0x0 0x5 0x000000 0x1fff // LED disp.
356 0x1 0x0 0x5 0x100000 0x1fff // switches
357 0x2 0x0 0x5 0x200000 0x1fff // ID reg.
358 0x3 0x0 0x5 0x300000 0x1fff // status reg.
359 0x4 0x0 0x5 0x400000 0x1fff // reset reg.
360 0x5 0x0 0x5 0x500000 0x1fff // Wind port
361 0x7 0x0 0x5 0x700000 0x1fff // UART #1
362 0x8 0x0 0x5 0x800000 0x1fff // UART #2
363 0x9 0x0 0x5 0x900000 0x1fff // RTC
364 0xb 0x0 0x5 0xb00000 0x1fff // EEPROM
365 >;
366
367 bidr@2,0 {
368 compatible = "wrs,sbc8560-bidr";
369 reg = <0x2 0x0 0x10>;
370 };
371
372 bcsr@3,0 {
373 compatible = "wrs,sbc8560-bcsr";
374 reg = <0x3 0x0 0x10>;
375 };
376
377 brstcr@4,0 {
378 compatible = "wrs,sbc8560-brstcr";
379 reg = <0x4 0x0 0x10>;
380 };
381
382 serial0: serial@7,0 {
383 device_type = "serial";
384 compatible = "ns16550";
385 reg = <0x7 0x0 0x100>;
386 clock-frequency = <1843200>;
387 interrupts = <0x9 0x2>;
388 interrupt-parent = <&mpic>;
389 };
390
391 serial1: serial@8,0 {
392 device_type = "serial";
393 compatible = "ns16550";
394 reg = <0x8 0x0 0x100>;
395 clock-frequency = <1843200>;
396 interrupts = <0xa 0x2>;
397 interrupt-parent = <&mpic>;
398 };
399
400 rtc@9,0 {
401 compatible = "m48t59";
402 reg = <0x9 0x0 0x1fff>;
403 };
404 };
405 };
406};
diff --git a/arch/powerpc/boot/flatdevtree_env.h b/arch/powerpc/boot/flatdevtree_env.h
new file mode 100644
index 00000000000..66e0ebb1a36
--- /dev/null
+++ b/arch/powerpc/boot/flatdevtree_env.h
@@ -0,0 +1,27 @@
1/*
2 * This file adds the header file glue so that the shared files
3 * flatdevicetree.[ch] can compile and work in the powerpc bootwrapper.
4 *
5 * strncmp & strchr copied from <file:lib/string.c>
6 * Copyright (C) 1991, 1992 Linus Torvalds
7 *
8 * Maintained by: Mark A. Greer <mgreer@mvista.com>
9 */
10#ifndef _PPC_BOOT_FLATDEVTREE_ENV_H_
11#define _PPC_BOOT_FLATDEVTREE_ENV_H_
12
13#include <stdarg.h>
14#include <stddef.h>
15#include "types.h"
16#include "string.h"
17#include "stdio.h"
18#include "ops.h"
19
20#define be16_to_cpu(x) (x)
21#define cpu_to_be16(x) (x)
22#define be32_to_cpu(x) (x)
23#define cpu_to_be32(x) (x)
24#define be64_to_cpu(x) (x)
25#define cpu_to_be64(x) (x)
26
27#endif /* _PPC_BOOT_FLATDEVTREE_ENV_H_ */
diff --git a/arch/powerpc/configs/40x/hcu4_defconfig b/arch/powerpc/configs/40x/hcu4_defconfig
new file mode 100644
index 00000000000..ebeb4accad6
--- /dev/null
+++ b/arch/powerpc/configs/40x/hcu4_defconfig
@@ -0,0 +1,80 @@
1CONFIG_40x=y
2CONFIG_EXPERIMENTAL=y
3CONFIG_SYSVIPC=y
4CONFIG_POSIX_MQUEUE=y
5CONFIG_LOG_BUF_SHIFT=14
6CONFIG_BLK_DEV_INITRD=y
7# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
8CONFIG_EXPERT=y
9CONFIG_KALLSYMS_ALL=y
10CONFIG_KALLSYMS_EXTRA_PASS=y
11CONFIG_MODULES=y
12CONFIG_MODULE_UNLOAD=y
13# CONFIG_BLK_DEV_BSG is not set
14CONFIG_HCU4=y
15# CONFIG_WALNUT is not set
16CONFIG_SPARSE_IRQ=y
17CONFIG_PCI=y
18CONFIG_NET=y
19CONFIG_PACKET=y
20CONFIG_UNIX=y
21CONFIG_INET=y
22CONFIG_IP_PNP=y
23CONFIG_IP_PNP_DHCP=y
24CONFIG_IP_PNP_BOOTP=y
25# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
26# CONFIG_INET_XFRM_MODE_TUNNEL is not set
27# CONFIG_INET_XFRM_MODE_BEET is not set
28# CONFIG_INET_LRO is not set
29# CONFIG_IPV6 is not set
30CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
31CONFIG_CONNECTOR=y
32CONFIG_MTD=y
33CONFIG_MTD_PARTITIONS=y
34CONFIG_MTD_CMDLINE_PARTS=y
35CONFIG_MTD_OF_PARTS=y
36CONFIG_MTD_CHAR=y
37CONFIG_MTD_BLOCK=m
38CONFIG_MTD_CFI=y
39CONFIG_MTD_JEDECPROBE=y
40CONFIG_MTD_CFI_AMDSTD=y
41CONFIG_MTD_PHYSMAP_OF=y
42CONFIG_PROC_DEVICETREE=y
43CONFIG_BLK_DEV_RAM=y
44CONFIG_BLK_DEV_RAM_SIZE=35000
45CONFIG_NETDEVICES=y
46CONFIG_NET_ETHERNET=y
47CONFIG_IBM_NEW_EMAC=y
48# CONFIG_INPUT is not set
49# CONFIG_SERIO is not set
50# CONFIG_VT is not set
51CONFIG_SERIAL_8250=y
52CONFIG_SERIAL_8250_CONSOLE=y
53CONFIG_SERIAL_8250_EXTENDED=y
54CONFIG_SERIAL_8250_SHARE_IRQ=y
55CONFIG_SERIAL_OF_PLATFORM=y
56# CONFIG_HW_RANDOM is not set
57# CONFIG_HWMON is not set
58CONFIG_VIDEO_OUTPUT_CONTROL=m
59# CONFIG_USB_SUPPORT is not set
60CONFIG_EXT2_FS=y
61CONFIG_INOTIFY=y
62CONFIG_PROC_KCORE=y
63CONFIG_TMPFS=y
64CONFIG_CRAMFS=y
65CONFIG_NFS_FS=y
66CONFIG_NFS_V3=y
67CONFIG_ROOT_NFS=y
68CONFIG_MAGIC_SYSRQ=y
69CONFIG_DEBUG_FS=y
70CONFIG_DEBUG_KERNEL=y
71CONFIG_DETECT_HUNG_TASK=y
72# CONFIG_RCU_CPU_STALL_DETECTOR is not set
73CONFIG_SYSCTL_SYSCALL_CHECK=y
74CONFIG_CRYPTO=y
75CONFIG_CRYPTO_CBC=y
76CONFIG_CRYPTO_ECB=y
77CONFIG_CRYPTO_PCBC=y
78CONFIG_CRYPTO_MD5=y
79CONFIG_CRYPTO_DES=y
80# CONFIG_CRYPTO_ANSI_CPRNG is not set
diff --git a/arch/powerpc/configs/85xx/sbc8560_defconfig b/arch/powerpc/configs/85xx/sbc8560_defconfig
new file mode 100644
index 00000000000..f7fdb0318e4
--- /dev/null
+++ b/arch/powerpc/configs/85xx/sbc8560_defconfig
@@ -0,0 +1,65 @@
1CONFIG_PPC_85xx=y
2CONFIG_EXPERIMENTAL=y
3CONFIG_SYSVIPC=y
4CONFIG_LOG_BUF_SHIFT=14
5CONFIG_BLK_DEV_INITRD=y
6# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
7CONFIG_EXPERT=y
8CONFIG_SLAB=y
9# CONFIG_BLK_DEV_BSG is not set
10CONFIG_SBC8560=y
11CONFIG_BINFMT_MISC=y
12CONFIG_SPARSE_IRQ=y
13# CONFIG_SECCOMP is not set
14CONFIG_NET=y
15CONFIG_PACKET=y
16CONFIG_UNIX=y
17CONFIG_XFRM_USER=y
18CONFIG_INET=y
19CONFIG_IP_MULTICAST=y
20CONFIG_IP_PNP=y
21CONFIG_IP_PNP_DHCP=y
22CONFIG_IP_PNP_BOOTP=y
23CONFIG_SYN_COOKIES=y
24# CONFIG_INET_LRO is not set
25# CONFIG_IPV6 is not set
26CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
27# CONFIG_FW_LOADER is not set
28CONFIG_PROC_DEVICETREE=y
29CONFIG_BLK_DEV_LOOP=y
30CONFIG_BLK_DEV_RAM=y
31CONFIG_BLK_DEV_RAM_SIZE=32768
32CONFIG_NETDEVICES=y
33CONFIG_BROADCOM_PHY=y
34CONFIG_NET_ETHERNET=y
35CONFIG_MII=y
36CONFIG_GIANFAR=y
37# CONFIG_INPUT_MOUSEDEV is not set
38# CONFIG_INPUT_KEYBOARD is not set
39# CONFIG_INPUT_MOUSE is not set
40# CONFIG_SERIO is not set
41# CONFIG_VT is not set
42CONFIG_SERIAL_8250=y
43CONFIG_SERIAL_8250_CONSOLE=y
44CONFIG_SERIAL_8250_NR_UARTS=2
45CONFIG_SERIAL_8250_RUNTIME_UARTS=2
46# CONFIG_HW_RANDOM is not set
47CONFIG_VIDEO_OUTPUT_CONTROL=y
48CONFIG_RTC_CLASS=y
49CONFIG_RTC_DRV_M48T59=y
50CONFIG_INOTIFY=y
51CONFIG_PROC_KCORE=y
52CONFIG_TMPFS=y
53CONFIG_NFS_FS=y
54CONFIG_ROOT_NFS=y
55CONFIG_PARTITION_ADVANCED=y
56# CONFIG_MSDOS_PARTITION is not set
57CONFIG_MAGIC_SYSRQ=y
58CONFIG_DEBUG_KERNEL=y
59CONFIG_DETECT_HUNG_TASK=y
60CONFIG_DEBUG_MUTEXES=y
61# CONFIG_DEBUG_BUGVERBOSE is not set
62# CONFIG_RCU_CPU_STALL_DETECTOR is not set
63CONFIG_SYSCTL_SYSCALL_CHECK=y
64CONFIG_PPC_EARLY_DEBUG=y
65# CONFIG_CRYPTO_ANSI_CPRNG is not set
diff --git a/arch/powerpc/configs/iseries_defconfig b/arch/powerpc/configs/iseries_defconfig
new file mode 100644
index 00000000000..27c46d67996
--- /dev/null
+++ b/arch/powerpc/configs/iseries_defconfig
@@ -0,0 +1,236 @@
1CONFIG_PPC64=y
2CONFIG_SMP=y
3CONFIG_EXPERIMENTAL=y
4CONFIG_SYSVIPC=y
5CONFIG_POSIX_MQUEUE=y
6CONFIG_AUDIT=y
7CONFIG_AUDITSYSCALL=y
8CONFIG_IKCONFIG=y
9CONFIG_IKCONFIG_PROC=y
10CONFIG_BLK_DEV_INITRD=y
11# CONFIG_COMPAT_BRK is not set
12CONFIG_MODULES=y
13CONFIG_MODULE_UNLOAD=y
14CONFIG_MODVERSIONS=y
15CONFIG_MODULE_SRCVERSION_ALL=y
16# CONFIG_PPC_PSERIES is not set
17CONFIG_LPARCFG=y
18CONFIG_PPC_ISERIES=y
19CONFIG_VIODASD=y
20CONFIG_VIOCD=m
21CONFIG_VIOTAPE=m
22# CONFIG_PPC_PMAC is not set
23CONFIG_NO_HZ=y
24CONFIG_HIGH_RES_TIMERS=y
25CONFIG_IRQ_ALL_CPUS=y
26# CONFIG_MIGRATION is not set
27CONFIG_PACKET=y
28CONFIG_UNIX=y
29CONFIG_XFRM_USER=m
30CONFIG_XFRM_SUB_POLICY=y
31CONFIG_NET_KEY=m
32CONFIG_INET=y
33CONFIG_IP_MULTICAST=y
34CONFIG_NET_IPIP=y
35CONFIG_SYN_COOKIES=y
36CONFIG_INET_AH=m
37CONFIG_INET_ESP=m
38CONFIG_INET_IPCOMP=m
39CONFIG_INET_XFRM_MODE_BEET=m
40# CONFIG_INET_LRO is not set
41# CONFIG_IPV6 is not set
42CONFIG_NETFILTER=y
43CONFIG_NETFILTER_NETLINK_QUEUE=m
44CONFIG_NETFILTER_NETLINK_LOG=m
45CONFIG_NF_CONNTRACK=m
46CONFIG_NF_CONNTRACK_EVENTS=y
47# CONFIG_NF_CT_PROTO_SCTP is not set
48CONFIG_NF_CONNTRACK_FTP=m
49CONFIG_NF_CONNTRACK_IRC=m
50CONFIG_NF_CONNTRACK_TFTP=m
51CONFIG_NF_CT_NETLINK=m
52CONFIG_NETFILTER_TPROXY=m
53CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
54CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
55CONFIG_NETFILTER_XT_TARGET_DSCP=m
56CONFIG_NETFILTER_XT_TARGET_MARK=m
57CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
58CONFIG_NETFILTER_XT_TARGET_TPROXY=m
59CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m
60CONFIG_NETFILTER_XT_MATCH_COMMENT=m
61CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
62CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
63CONFIG_NETFILTER_XT_MATCH_DSCP=m
64CONFIG_NETFILTER_XT_MATCH_IPRANGE=m
65CONFIG_NETFILTER_XT_MATCH_LENGTH=m
66CONFIG_NETFILTER_XT_MATCH_LIMIT=m
67CONFIG_NETFILTER_XT_MATCH_MAC=m
68CONFIG_NETFILTER_XT_MATCH_MARK=m
69CONFIG_NETFILTER_XT_MATCH_OWNER=m
70CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
71CONFIG_NETFILTER_XT_MATCH_RATEEST=m
72CONFIG_NETFILTER_XT_MATCH_REALM=m
73CONFIG_NETFILTER_XT_MATCH_RECENT=m
74CONFIG_NETFILTER_XT_MATCH_STRING=m
75CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
76CONFIG_NETFILTER_XT_MATCH_TIME=m
77CONFIG_NF_CONNTRACK_IPV4=m
78CONFIG_IP_NF_QUEUE=m
79CONFIG_IP_NF_IPTABLES=m
80CONFIG_IP_NF_MATCH_ADDRTYPE=m
81CONFIG_IP_NF_MATCH_ECN=m
82CONFIG_IP_NF_MATCH_TTL=m
83CONFIG_IP_NF_FILTER=m
84CONFIG_IP_NF_TARGET_REJECT=m
85CONFIG_IP_NF_TARGET_LOG=m
86CONFIG_IP_NF_TARGET_ULOG=m
87CONFIG_NF_NAT=m
88CONFIG_IP_NF_TARGET_MASQUERADE=m
89CONFIG_IP_NF_TARGET_NETMAP=m
90CONFIG_IP_NF_TARGET_REDIRECT=m
91CONFIG_IP_NF_MANGLE=m
92CONFIG_IP_NF_TARGET_CLUSTERIP=m
93CONFIG_IP_NF_TARGET_ECN=m
94CONFIG_IP_NF_TARGET_TTL=m
95CONFIG_IP_NF_RAW=m
96CONFIG_IP_NF_ARPTABLES=m
97CONFIG_IP_NF_ARPFILTER=m
98CONFIG_IP_NF_ARP_MANGLE=m
99CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
100CONFIG_PROC_DEVICETREE=y
101CONFIG_BLK_DEV_LOOP=y
102CONFIG_BLK_DEV_NBD=m
103CONFIG_BLK_DEV_RAM=y
104CONFIG_BLK_DEV_RAM_SIZE=65536
105CONFIG_SCSI=y
106CONFIG_BLK_DEV_SD=y
107CONFIG_CHR_DEV_ST=y
108CONFIG_BLK_DEV_SR=y
109CONFIG_BLK_DEV_SR_VENDOR=y
110CONFIG_CHR_DEV_SG=y
111CONFIG_SCSI_MULTI_LUN=y
112CONFIG_SCSI_CONSTANTS=y
113CONFIG_SCSI_SPI_ATTRS=y
114CONFIG_SCSI_FC_ATTRS=y
115CONFIG_SCSI_SAS_LIBSAS=m
116CONFIG_SCSI_IBMVSCSI=m
117CONFIG_MD=y
118CONFIG_BLK_DEV_MD=y
119CONFIG_MD_LINEAR=y
120CONFIG_MD_RAID0=y
121CONFIG_MD_RAID1=y
122CONFIG_MD_RAID10=m
123CONFIG_MD_MULTIPATH=m
124CONFIG_MD_FAULTY=m
125CONFIG_BLK_DEV_DM=y
126CONFIG_DM_CRYPT=m
127CONFIG_DM_SNAPSHOT=m
128CONFIG_DM_MIRROR=m
129CONFIG_DM_ZERO=m
130CONFIG_NETDEVICES=y
131CONFIG_DUMMY=m
132CONFIG_BONDING=m
133CONFIG_TUN=m
134CONFIG_NET_ETHERNET=y
135CONFIG_NET_PCI=y
136CONFIG_PCNET32=y
137CONFIG_E100=y
138CONFIG_ACENIC=m
139CONFIG_E1000=m
140CONFIG_ISERIES_VETH=y
141CONFIG_PPP=m
142CONFIG_PPP_ASYNC=m
143CONFIG_PPP_SYNC_TTY=m
144CONFIG_PPP_DEFLATE=m
145CONFIG_PPP_BSDCOMP=m
146CONFIG_PPPOE=m
147CONFIG_NETCONSOLE=y
148CONFIG_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
153CONFIG_SERIAL_ICOM=m
154# CONFIG_HW_RANDOM is not set
155CONFIG_GEN_RTC=y
156CONFIG_RAW_DRIVER=y
157# CONFIG_HWMON is not set
158# CONFIG_HID_SUPPORT is not set
159# CONFIG_USB_SUPPORT is not set
160CONFIG_EXT2_FS=y
161CONFIG_EXT2_FS_XATTR=y
162CONFIG_EXT2_FS_POSIX_ACL=y
163CONFIG_EXT2_FS_SECURITY=y
164CONFIG_EXT2_FS_XIP=y
165CONFIG_EXT3_FS=y
166CONFIG_EXT3_FS_POSIX_ACL=y
167CONFIG_EXT3_FS_SECURITY=y
168CONFIG_EXT4_FS=y
169CONFIG_REISERFS_FS=y
170CONFIG_REISERFS_FS_XATTR=y
171CONFIG_REISERFS_FS_POSIX_ACL=y
172CONFIG_REISERFS_FS_SECURITY=y
173CONFIG_JFS_FS=m
174CONFIG_JFS_POSIX_ACL=y
175CONFIG_JFS_SECURITY=y
176CONFIG_XFS_FS=m
177CONFIG_XFS_POSIX_ACL=y
178CONFIG_GFS2_FS=m
179CONFIG_AUTOFS_FS=m
180CONFIG_ISO9660_FS=y
181CONFIG_JOLIET=y
182CONFIG_ZISOFS=y
183CONFIG_UDF_FS=m
184CONFIG_MSDOS_FS=y
185CONFIG_VFAT_FS=y
186CONFIG_PROC_KCORE=y
187CONFIG_TMPFS=y
188CONFIG_TMPFS_POSIX_ACL=y
189CONFIG_CRAMFS=y
190CONFIG_NFS_FS=y
191CONFIG_NFS_V3=y
192CONFIG_NFS_V3_ACL=y
193CONFIG_NFS_V4=y
194CONFIG_NFSD=m
195CONFIG_NFSD_V3_ACL=y
196CONFIG_NFSD_V4=y
197CONFIG_RPCSEC_GSS_SPKM3=m
198CONFIG_CIFS=m
199CONFIG_CIFS_XATTR=y
200CONFIG_CIFS_POSIX=y
201CONFIG_NLS_CODEPAGE_437=y
202CONFIG_NLS_ASCII=y
203CONFIG_NLS_ISO8859_1=y
204CONFIG_DLM=m
205CONFIG_CRC_T10DIF=y
206CONFIG_MAGIC_SYSRQ=y
207CONFIG_DEBUG_FS=y
208CONFIG_DEBUG_KERNEL=y
209# CONFIG_RCU_CPU_STALL_DETECTOR is not set
210CONFIG_LATENCYTOP=y
211CONFIG_SYSCTL_SYSCALL_CHECK=y
212CONFIG_DEBUG_STACKOVERFLOW=y
213CONFIG_DEBUG_STACK_USAGE=y
214CONFIG_CRYPTO_NULL=m
215CONFIG_CRYPTO_TEST=m
216CONFIG_CRYPTO_ECB=m
217CONFIG_CRYPTO_PCBC=m
218CONFIG_CRYPTO_HMAC=y
219CONFIG_CRYPTO_MD4=m
220CONFIG_CRYPTO_MICHAEL_MIC=m
221CONFIG_CRYPTO_SHA256=m
222CONFIG_CRYPTO_SHA512=m
223CONFIG_CRYPTO_TGR192=m
224CONFIG_CRYPTO_WP512=m
225CONFIG_CRYPTO_AES=m
226CONFIG_CRYPTO_ANUBIS=m
227CONFIG_CRYPTO_ARC4=m
228CONFIG_CRYPTO_BLOWFISH=m
229CONFIG_CRYPTO_CAST6=m
230CONFIG_CRYPTO_KHAZAD=m
231CONFIG_CRYPTO_SEED=m
232CONFIG_CRYPTO_SERPENT=m
233CONFIG_CRYPTO_TEA=m
234CONFIG_CRYPTO_TWOFISH=m
235# CONFIG_CRYPTO_ANSI_CPRNG is not set
236# CONFIG_CRYPTO_HW is not set
diff --git a/arch/powerpc/include/asm/abs_addr.h b/arch/powerpc/include/asm/abs_addr.h
new file mode 100644
index 00000000000..5ab0b71531b
--- /dev/null
+++ b/arch/powerpc/include/asm/abs_addr.h
@@ -0,0 +1,75 @@
1#ifndef _ASM_POWERPC_ABS_ADDR_H
2#define _ASM_POWERPC_ABS_ADDR_H
3#ifdef __KERNEL__
4
5
6/*
7 * c 2001 PPC 64 Team, IBM Corp
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#include <linux/memblock.h>
16
17#include <asm/types.h>
18#include <asm/page.h>
19#include <asm/prom.h>
20#include <asm/firmware.h>
21
22struct mschunks_map {
23 unsigned long num_chunks;
24 unsigned long chunk_size;
25 unsigned long chunk_shift;
26 unsigned long chunk_mask;
27 u32 *mapping;
28};
29
30extern struct mschunks_map mschunks_map;
31
32/* Chunks are 256 KB */
33#define MSCHUNKS_CHUNK_SHIFT (18)
34#define MSCHUNKS_CHUNK_SIZE (1UL << MSCHUNKS_CHUNK_SHIFT)
35#define MSCHUNKS_OFFSET_MASK (MSCHUNKS_CHUNK_SIZE - 1)
36
37static inline unsigned long chunk_to_addr(unsigned long chunk)
38{
39 return chunk << MSCHUNKS_CHUNK_SHIFT;
40}
41
42static inline unsigned long addr_to_chunk(unsigned long addr)
43{
44 return addr >> MSCHUNKS_CHUNK_SHIFT;
45}
46
47static inline unsigned long phys_to_abs(unsigned long pa)
48{
49 unsigned long chunk;
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}
62
63/* Convenience macros */
64#define virt_to_abs(va) phys_to_abs(__pa(va))
65#define abs_to_virt(aa) __va(aa)
66
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__ */
75#endif /* _ASM_POWERPC_ABS_ADDR_H */
diff --git a/arch/powerpc/include/asm/auxvec.h b/arch/powerpc/include/asm/auxvec.h
new file mode 100644
index 00000000000..19a099b62cd
--- /dev/null
+++ b/arch/powerpc/include/asm/auxvec.h
@@ -0,0 +1,19 @@
1#ifndef _ASM_POWERPC_AUXVEC_H
2#define _ASM_POWERPC_AUXVEC_H
3
4/*
5 * We need to put in some extra aux table entries to tell glibc what
6 * the cache block size is, so it can use the dcbz instruction safely.
7 */
8#define AT_DCACHEBSIZE 19
9#define AT_ICACHEBSIZE 20
10#define AT_UCACHEBSIZE 21
11/* A special ignored type value for PPC, for glibc compatibility. */
12#define AT_IGNOREPPC 22
13
14/* The vDSO location. We have to use the same value as x86 for glibc's
15 * sake :-)
16 */
17#define AT_SYSINFO_EHDR 33
18
19#endif
diff --git a/arch/powerpc/include/asm/bitsperlong.h b/arch/powerpc/include/asm/bitsperlong.h
new file mode 100644
index 00000000000..5f1659032c4
--- /dev/null
+++ b/arch/powerpc/include/asm/bitsperlong.h
@@ -0,0 +1,12 @@
1#ifndef __ASM_POWERPC_BITSPERLONG_H
2#define __ASM_POWERPC_BITSPERLONG_H
3
4#if defined(__powerpc64__)
5# define __BITS_PER_LONG 64
6#else
7# define __BITS_PER_LONG 32
8#endif
9
10#include <asm-generic/bitsperlong.h>
11
12#endif /* __ASM_POWERPC_BITSPERLONG_H */
diff --git a/arch/powerpc/include/asm/byteorder.h b/arch/powerpc/include/asm/byteorder.h
new file mode 100644
index 00000000000..aa6cc4fac96
--- /dev/null
+++ b/arch/powerpc/include/asm/byteorder.h
@@ -0,0 +1,12 @@
1#ifndef _ASM_POWERPC_BYTEORDER_H
2#define _ASM_POWERPC_BYTEORDER_H
3
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#include <linux/byteorder/big_endian.h>
11
12#endif /* _ASM_POWERPC_BYTEORDER_H */
diff --git a/arch/powerpc/include/asm/errno.h b/arch/powerpc/include/asm/errno.h
new file mode 100644
index 00000000000..8c145fd17d8
--- /dev/null
+++ b/arch/powerpc/include/asm/errno.h
@@ -0,0 +1,11 @@
1#ifndef _ASM_POWERPC_ERRNO_H
2#define _ASM_POWERPC_ERRNO_H
3
4#include <asm-generic/errno.h>
5
6#undef EDEADLOCK
7#define EDEADLOCK 58 /* File locking deadlock error */
8
9#define _LAST_ERRNO 516
10
11#endif /* _ASM_POWERPC_ERRNO_H */
diff --git a/arch/powerpc/include/asm/fcntl.h b/arch/powerpc/include/asm/fcntl.h
new file mode 100644
index 00000000000..ce5c4516d40
--- /dev/null
+++ b/arch/powerpc/include/asm/fcntl.h
@@ -0,0 +1,11 @@
1#ifndef _ASM_FCNTL_H
2#define _ASM_FCNTL_H
3
4#define O_DIRECTORY 040000 /* must be a directory */
5#define O_NOFOLLOW 0100000 /* don't follow links */
6#define O_LARGEFILE 0200000
7#define O_DIRECT 0400000 /* direct disk access hint */
8
9#include <asm-generic/fcntl.h>
10
11#endif /* _ASM_FCNTL_H */
diff --git a/arch/powerpc/include/asm/ioctl.h b/arch/powerpc/include/asm/ioctl.h
new file mode 100644
index 00000000000..57d68304218
--- /dev/null
+++ b/arch/powerpc/include/asm/ioctl.h
@@ -0,0 +1,13 @@
1#ifndef _ASM_POWERPC_IOCTL_H
2#define _ASM_POWERPC_IOCTL_H
3
4#define _IOC_SIZEBITS 13
5#define _IOC_DIRBITS 3
6
7#define _IOC_NONE 1U
8#define _IOC_READ 2U
9#define _IOC_WRITE 4U
10
11#include <asm-generic/ioctl.h>
12
13#endif /* _ASM_POWERPC_IOCTL_H */
diff --git a/arch/powerpc/include/asm/ioctls.h b/arch/powerpc/include/asm/ioctls.h
new file mode 100644
index 00000000000..e9b78870aaa
--- /dev/null
+++ b/arch/powerpc/include/asm/ioctls.h
@@ -0,0 +1,116 @@
1#ifndef _ASM_POWERPC_IOCTLS_H
2#define _ASM_POWERPC_IOCTLS_H
3
4#include <asm/ioctl.h>
5
6#define FIOCLEX _IO('f', 1)
7#define FIONCLEX _IO('f', 2)
8#define FIOASYNC _IOW('f', 125, int)
9#define FIONBIO _IOW('f', 126, int)
10#define FIONREAD _IOR('f', 127, int)
11#define TIOCINQ FIONREAD
12#define FIOQSIZE _IOR('f', 128, loff_t)
13
14#define TIOCGETP _IOR('t', 8, struct sgttyb)
15#define TIOCSETP _IOW('t', 9, struct sgttyb)
16#define TIOCSETN _IOW('t', 10, struct sgttyb) /* TIOCSETP wo flush */
17
18#define TIOCSETC _IOW('t', 17, struct tchars)
19#define TIOCGETC _IOR('t', 18, struct tchars)
20#define TCGETS _IOR('t', 19, struct termios)
21#define TCSETS _IOW('t', 20, struct termios)
22#define TCSETSW _IOW('t', 21, struct termios)
23#define TCSETSF _IOW('t', 22, struct termios)
24
25#define TCGETA _IOR('t', 23, struct termio)
26#define TCSETA _IOW('t', 24, struct termio)
27#define TCSETAW _IOW('t', 25, struct termio)
28#define TCSETAF _IOW('t', 28, struct termio)
29
30#define TCSBRK _IO('t', 29)
31#define TCXONC _IO('t', 30)
32#define TCFLSH _IO('t', 31)
33
34#define TIOCSWINSZ _IOW('t', 103, struct winsize)
35#define TIOCGWINSZ _IOR('t', 104, struct winsize)
36#define TIOCSTART _IO('t', 110) /* start output, like ^Q */
37#define TIOCSTOP _IO('t', 111) /* stop output, like ^S */
38#define TIOCOUTQ _IOR('t', 115, int) /* output queue size */
39
40#define TIOCGLTC _IOR('t', 116, struct ltchars)
41#define TIOCSLTC _IOW('t', 117, struct ltchars)
42#define TIOCSPGRP _IOW('t', 118, int)
43#define TIOCGPGRP _IOR('t', 119, int)
44
45#define TIOCEXCL 0x540C
46#define TIOCNXCL 0x540D
47#define TIOCSCTTY 0x540E
48
49#define TIOCSTI 0x5412
50#define TIOCMGET 0x5415
51#define TIOCMBIS 0x5416
52#define TIOCMBIC 0x5417
53#define TIOCMSET 0x5418
54# define TIOCM_LE 0x001
55# define TIOCM_DTR 0x002
56# define TIOCM_RTS 0x004
57# define TIOCM_ST 0x008
58# define TIOCM_SR 0x010
59# define TIOCM_CTS 0x020
60# define TIOCM_CAR 0x040
61# define TIOCM_RNG 0x080
62# define TIOCM_DSR 0x100
63# define TIOCM_CD TIOCM_CAR
64# define TIOCM_RI TIOCM_RNG
65#define TIOCM_OUT1 0x2000
66#define TIOCM_OUT2 0x4000
67#define TIOCM_LOOP 0x8000
68
69#define TIOCGSOFTCAR 0x5419
70#define TIOCSSOFTCAR 0x541A
71#define TIOCLINUX 0x541C
72#define TIOCCONS 0x541D
73#define TIOCGSERIAL 0x541E
74#define TIOCSSERIAL 0x541F
75#define TIOCPKT 0x5420
76# define TIOCPKT_DATA 0
77# define TIOCPKT_FLUSHREAD 1
78# define TIOCPKT_FLUSHWRITE 2
79# define TIOCPKT_STOP 4
80# define TIOCPKT_START 8
81# define TIOCPKT_NOSTOP 16
82# define TIOCPKT_DOSTOP 32
83# define TIOCPKT_IOCTL 64
84
85
86#define TIOCNOTTY 0x5422
87#define TIOCSETD 0x5423
88#define TIOCGETD 0x5424
89#define TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */
90#define TIOCSBRK 0x5427 /* BSD compatibility */
91#define TIOCCBRK 0x5428 /* BSD compatibility */
92#define TIOCGSID 0x5429 /* Return the session ID of FD */
93#define TIOCGRS485 0x542e
94#define TIOCSRS485 0x542f
95#define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
96#define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */
97#define TIOCGDEV _IOR('T',0x32, unsigned int) /* Get primary device node of /dev/console */
98#define TIOCSIG _IOW('T',0x36, int) /* Generate signal on Pty slave */
99#define TIOCVHANGUP 0x5437
100
101#define TIOCSERCONFIG 0x5453
102#define TIOCSERGWILD 0x5454
103#define TIOCSERSWILD 0x5455
104#define TIOCGLCKTRMIOS 0x5456
105#define TIOCSLCKTRMIOS 0x5457
106#define TIOCSERGSTRUCT 0x5458 /* For debugging only */
107#define TIOCSERGETLSR 0x5459 /* Get line status register */
108 /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
109# define TIOCSER_TEMT 0x01 /* Transmitter physically empty */
110#define TIOCSERGETMULTI 0x545A /* Get multiport config */
111#define TIOCSERSETMULTI 0x545B /* Set multiport config */
112
113#define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */
114#define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */
115
116#endif /* _ASM_POWERPC_IOCTLS_H */
diff --git a/arch/powerpc/include/asm/ipcbuf.h b/arch/powerpc/include/asm/ipcbuf.h
new file mode 100644
index 00000000000..2c3e1d94db1
--- /dev/null
+++ b/arch/powerpc/include/asm/ipcbuf.h
@@ -0,0 +1,34 @@
1#ifndef _ASM_POWERPC_IPCBUF_H
2#define _ASM_POWERPC_IPCBUF_H
3
4/*
5 * The ipc64_perm structure for the powerpc is identical to
6 * kern_ipc_perm as we have always had 32-bit UIDs and GIDs in the
7 * kernel. Note extra padding because this structure is passed back
8 * and forth between kernel and user space. Pad space is left for:
9 * - 1 32-bit value to fill up for 8-byte alignment
10 * - 2 miscellaneous 64-bit values
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version
15 * 2 of the License, or (at your option) any later version.
16 */
17
18#include <linux/types.h>
19
20struct ipc64_perm
21{
22 __kernel_key_t key;
23 __kernel_uid_t uid;
24 __kernel_gid_t gid;
25 __kernel_uid_t cuid;
26 __kernel_gid_t cgid;
27 __kernel_mode_t mode;
28 unsigned int seq;
29 unsigned int __pad1;
30 unsigned long long __unused1;
31 unsigned long long __unused2;
32};
33
34#endif /* _ASM_POWERPC_IPCBUF_H */
diff --git a/arch/powerpc/include/asm/iseries/alpaca.h b/arch/powerpc/include/asm/iseries/alpaca.h
new file mode 100644
index 00000000000..c0cce6727a6
--- /dev/null
+++ b/arch/powerpc/include/asm/iseries/alpaca.h
@@ -0,0 +1,31 @@
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 */
26struct 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
new file mode 100644
index 00000000000..162d653ad51
--- /dev/null
+++ b/arch/powerpc/include/asm/iseries/hv_call.h
@@ -0,0 +1,111 @@
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
78static 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
88static inline void HvCall_yieldProcessor(unsigned typeOfYield, u64 yieldParm)
89{
90 HvCall2(HvCallBaseYieldProcessor, typeOfYield, yieldParm);
91}
92
93static inline void HvCall_setEnabledInterrupts(u64 enabledInterrupts)
94{
95 HvCall1(HvCallBaseSetEnabledInterrupts, enabledInterrupts);
96}
97
98static inline void HvCall_setLogBufferFormatAndCodepage(int format,
99 u32 codePage)
100{
101 HvCall2(HvCallBaseSetLogBufferFormatAndCodePage, format, codePage);
102}
103
104extern void HvCall_writeLogBuffer(const void *buffer, u64 bufLen);
105
106static 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
new file mode 100644
index 00000000000..cc029d388e1
--- /dev/null
+++ b/arch/powerpc/include/asm/iseries/hv_call_event.h
@@ -0,0 +1,201 @@
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
31struct HvLpEvent;
32
33typedef u8 HvLpEvent_Type;
34typedef u8 HvLpEvent_AckInd;
35typedef u8 HvLpEvent_AckType;
36
37typedef u8 HvLpDma_Direction;
38typedef u8 HvLpDma_AddressType;
39
40typedef u64 HvLpEvent_Rc;
41typedef 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
60static inline void HvCallEvent_getOverflowLpEvents(u8 queueIndex)
61{
62 HvCall1(HvCallEventGetOverflowLpEvents, queueIndex);
63}
64
65static inline void HvCallEvent_setInterLpQueueIndex(u8 queueIndex)
66{
67 HvCall1(HvCallEventSetInterLpQueueIndex, queueIndex);
68}
69
70static inline void HvCallEvent_setLpEventStack(u8 queueIndex,
71 char *eventStackAddr, u32 eventStackSize)
72{
73 HvCall3(HvCallEventSetLpEventStack, queueIndex,
74 virt_to_abs(eventStackAddr), eventStackSize);
75}
76
77static inline void HvCallEvent_setLpEventQueueInterruptProc(u8 queueIndex,
78 u16 lpLogicalProcIndex)
79{
80 HvCall2(HvCallEventSetLpEventQueueInterruptProc, queueIndex,
81 lpLogicalProcIndex);
82}
83
84static inline HvLpEvent_Rc HvCallEvent_signalLpEvent(struct HvLpEvent *event)
85{
86 return HvCall1(HvCallEventSignalLpEvent, virt_to_abs(event));
87}
88
89static 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
119extern void *iseries_hv_alloc(size_t size, dma_addr_t *dma_handle, gfp_t flag);
120extern void iseries_hv_free(size_t size, void *vaddr, dma_addr_t dma_handle);
121extern dma_addr_t iseries_hv_map(void *vaddr, size_t size,
122 enum dma_data_direction direction);
123extern void iseries_hv_unmap(dma_addr_t dma_handle, size_t size,
124 enum dma_data_direction direction);
125
126static inline HvLpEvent_Rc HvCallEvent_ackLpEvent(struct HvLpEvent *event)
127{
128 return HvCall1(HvCallEventAckLpEvent, virt_to_abs(event));
129}
130
131static inline HvLpEvent_Rc HvCallEvent_cancelLpEvent(struct HvLpEvent *event)
132{
133 return HvCall1(HvCallEventCancelLpEvent, virt_to_abs(event));
134}
135
136static inline HvLpInstanceId HvCallEvent_getSourceLpInstanceId(
137 HvLpIndex targetLp, HvLpEvent_Type type)
138{
139 return HvCall2(HvCallEventGetSourceLpInstanceId, targetLp, type);
140}
141
142static inline HvLpInstanceId HvCallEvent_getTargetLpInstanceId(
143 HvLpIndex targetLp, HvLpEvent_Type type)
144{
145 return HvCall2(HvCallEventGetTargetLpInstanceId, targetLp, type);
146}
147
148static inline void HvCallEvent_openLpEventPath(HvLpIndex targetLp,
149 HvLpEvent_Type type)
150{
151 HvCall2(HvCallEventOpenLpEventPath, targetLp, type);
152}
153
154static inline void HvCallEvent_closeLpEventPath(HvLpIndex targetLp,
155 HvLpEvent_Type type)
156{
157 HvCall2(HvCallEventCloseLpEventPath, targetLp, type);
158}
159
160static 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
194static 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
new file mode 100644
index 00000000000..f5d21095925
--- /dev/null
+++ b/arch/powerpc/include/asm/iseries/hv_call_sc.h
@@ -0,0 +1,50 @@
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
32extern u64 HvCall0(u64);
33extern u64 HvCall1(u64, u64);
34extern u64 HvCall2(u64, u64, u64);
35extern u64 HvCall3(u64, u64, u64, u64);
36extern u64 HvCall4(u64, u64, u64, u64, u64);
37extern u64 HvCall5(u64, u64, u64, u64, u64, u64);
38extern u64 HvCall6(u64, u64, u64, u64, u64, u64, u64);
39extern u64 HvCall7(u64, u64, u64, u64, u64, u64, u64, u64);
40
41extern u64 HvCall0Ret16(u64, void *);
42extern u64 HvCall1Ret16(u64, void *, u64);
43extern u64 HvCall2Ret16(u64, void *, u64, u64);
44extern u64 HvCall3Ret16(u64, void *, u64, u64, u64);
45extern u64 HvCall4Ret16(u64, void *, u64, u64, u64, u64);
46extern u64 HvCall5Ret16(u64, void *, u64, u64, u64, u64, u64);
47extern u64 HvCall6Ret16(u64, void *, u64, u64, u64, u64, u64, u64);
48extern 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
new file mode 100644
index 00000000000..392ac3f54df
--- /dev/null
+++ b/arch/powerpc/include/asm/iseries/hv_call_xm.h
@@ -0,0 +1,61 @@
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
19static inline void HvCallXm_getTceTableParms(u64 cb)
20{
21 HvCall1(HvCallXmGetTceTableParms, cb);
22}
23
24static inline u64 HvCallXm_setTce(u64 tceTableToken, u64 tceOffset, u64 tce)
25{
26 return HvCall3(HvCallXmSetTce, tceTableToken, tceOffset, tce);
27}
28
29static 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
36static inline u64 HvCallXm_testBus(u16 busNumber)
37{
38 return HvCall1(HvCallXmTestBus, busNumber);
39}
40
41static inline u64 HvCallXm_testBusUnit(u16 busNumber, u8 subBusNumber,
42 u8 deviceId)
43{
44 return HvCall2(HvCallXmTestBusUnit, busNumber,
45 (subBusNumber << 8) | deviceId);
46}
47
48static 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
56static 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
new file mode 100644
index 00000000000..a006fd1e4a2
--- /dev/null
+++ b/arch/powerpc/include/asm/iseries/hv_lp_config.h
@@ -0,0 +1,128 @@
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
29enum {
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
45extern HvLpIndex HvLpConfig_getLpIndex_outline(void);
46extern HvLpIndex HvLpConfig_getLpIndex(void);
47extern HvLpIndex HvLpConfig_getPrimaryLpIndex(void);
48
49static inline u64 HvLpConfig_getMsChunks(void)
50{
51 return HvCall2(HvCallCfgGetMsChunks, HvLpConfig_getLpIndex(),
52 HvCallCfg_Cur);
53}
54
55static inline u64 HvLpConfig_getSystemPhysicalProcessors(void)
56{
57 return HvCall0(HvCallCfgGetSystemPhysicalProcessors);
58}
59
60static inline u64 HvLpConfig_getNumProcsInSharedPool(HvLpSharedPoolIndex sPI)
61{
62 return (u16)HvCall1(HvCallCfgGetNumProcsInSharedPool, sPI);
63}
64
65static inline u64 HvLpConfig_getPhysicalProcessors(void)
66{
67 return HvCall2(HvCallCfgGetPhysicalProcessors, HvLpConfig_getLpIndex(),
68 HvCallCfg_Cur);
69}
70
71static inline HvLpSharedPoolIndex HvLpConfig_getSharedPoolIndex(void)
72{
73 return HvCall1(HvCallCfgGetSharedPoolIndex, HvLpConfig_getLpIndex());
74}
75
76static inline u64 HvLpConfig_getSharedProcUnits(void)
77{
78 return HvCall2(HvCallCfgGetSharedProcUnits, HvLpConfig_getLpIndex(),
79 HvCallCfg_Cur);
80}
81
82static inline u64 HvLpConfig_getMaxSharedProcUnits(void)
83{
84 return HvCall2(HvCallCfgGetSharedProcUnits, HvLpConfig_getLpIndex(),
85 HvCallCfg_Max);
86}
87
88static inline u64 HvLpConfig_getMaxPhysicalProcessors(void)
89{
90 return HvCall2(HvCallCfgGetPhysicalProcessors, HvLpConfig_getLpIndex(),
91 HvCallCfg_Max);
92}
93
94static 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
107static inline HvLpVirtualLanIndexMap HvLpConfig_getVirtualLanIndexMap(void)
108{
109 return HvLpConfig_getVirtualLanIndexMapForLp(
110 HvLpConfig_getLpIndex_outline());
111}
112
113static 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
123static 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
new file mode 100644
index 00000000000..8f5da7d7720
--- /dev/null
+++ b/arch/powerpc/include/asm/iseries/hv_lp_event.h
@@ -0,0 +1,162 @@
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
34struct 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
53typedef void (*LpEventHandler)(struct HvLpEvent *);
54
55/* Register a handler for an event type - returns 0 on success */
56extern 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 */
68extern 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 */
77extern 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 */
83extern 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
137static inline int hvlpevent_is_valid(struct HvLpEvent *h)
138{
139 return h->flags & HV_LP_EVENT_VALID;
140}
141
142static inline void hvlpevent_invalidate(struct HvLpEvent *h)
143{
144 h->flags &= ~ HV_LP_EVENT_VALID;
145}
146
147static inline int hvlpevent_is_int(struct HvLpEvent *h)
148{
149 return h->flags & HV_LP_EVENT_INT;
150}
151
152static inline int hvlpevent_is_ack(struct HvLpEvent *h)
153{
154 return !hvlpevent_is_int(h);
155}
156
157static 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
new file mode 100644
index 00000000000..c3e6d2a1d1c
--- /dev/null
+++ b/arch/powerpc/include/asm/iseries/hv_types.h
@@ -0,0 +1,112 @@
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
27typedef u8 HvLpIndex;
28typedef u16 HvLpInstanceId;
29typedef u64 HvLpTOD;
30typedef u64 HvLpSystemSerialNum;
31typedef u8 HvLpDeviceSerialNum[12];
32typedef u16 HvLpSanHwSet;
33typedef u16 HvLpBus;
34typedef u16 HvLpBoard;
35typedef u16 HvLpCard;
36typedef u8 HvLpDeviceType[4];
37typedef u8 HvLpDeviceModel[3];
38typedef u64 HvIoToken;
39typedef u8 HvLpName[8];
40typedef u32 HvIoId;
41typedef u64 HvRealMemoryIndex;
42typedef u32 HvLpIndexMap; /* Must hold HVMAXARCHITECTEDLPS bits!!! */
43typedef u16 HvLpVrmIndex;
44typedef u32 HvXmGenerationId;
45typedef u8 HvLpBusPool;
46typedef u8 HvLpSharedPoolIndex;
47typedef u16 HvLpSharedProcUnitsX100;
48typedef u8 HvLpVirtualLanIndex;
49typedef u16 HvLpVirtualLanIndexMap; /* Must hold HVMAXARCHITECTEDVIRTUALLANS bits!!! */
50typedef u16 HvBusNumber; /* Hypervisor Bus Number */
51typedef u8 HvSubBusNumber; /* Hypervisor SubBus Number */
52typedef 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 */
74enum {
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
107struct 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
new file mode 100644
index 00000000000..1b9692c6089
--- /dev/null
+++ b/arch/powerpc/include/asm/iseries/iommu.h
@@ -0,0 +1,37 @@
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
24struct pci_dev;
25struct vio_dev;
26struct device_node;
27struct iommu_table;
28
29/* Get table parameters from HV */
30extern void iommu_table_getparms_iSeries(unsigned long busno,
31 unsigned char slotno, unsigned char virtbus,
32 struct iommu_table *tbl);
33
34extern struct iommu_table *vio_build_iommu_table_iseries(struct vio_dev *dev);
35extern 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
new file mode 100644
index 00000000000..42827883882
--- /dev/null
+++ b/arch/powerpc/include/asm/iseries/it_lp_queue.h
@@ -0,0 +1,78 @@
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
41struct 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
72extern struct hvlpevent_queue hvlpevent_queue;
73
74extern int hvlpevent_is_pending(void);
75extern void process_hvlpevents(void);
76extern 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
new file mode 100644
index 00000000000..5e9f3e128ee
--- /dev/null
+++ b/arch/powerpc/include/asm/iseries/lpar_map.h
@@ -0,0 +1,85 @@
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__
62struct 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
78extern 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
new file mode 100644
index 00000000000..eb851a9c9e5
--- /dev/null
+++ b/arch/powerpc/include/asm/iseries/mf.h
@@ -0,0 +1,51 @@
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
33struct rtc_time;
34
35typedef void (*MFCompleteHandler)(void *clientToken, int returnCode);
36
37extern void mf_allocate_lp_events(HvLpIndex targetLp, HvLpEvent_Type type,
38 unsigned size, unsigned amount, MFCompleteHandler hdlr,
39 void *userToken);
40extern void mf_deallocate_lp_events(HvLpIndex targetLp, HvLpEvent_Type type,
41 unsigned count, MFCompleteHandler hdlr, void *userToken);
42
43extern void mf_power_off(void);
44extern void mf_reboot(char *cmd);
45
46extern void mf_display_src(u32 word);
47extern void mf_display_progress(u16 value);
48
49extern 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
new file mode 100644
index 00000000000..f9ac0d00b95
--- /dev/null
+++ b/arch/powerpc/include/asm/iseries/vio.h
@@ -0,0 +1,265 @@
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
56struct 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
65struct rw_data {
66 u64 offset;
67 struct {
68 u32 token;
69 u32 reserved;
70 u64 len;
71 } dma_info[VIOMAXBLOCKDMA];
72};
73
74struct 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
90enum vioblocksubtype {
91 vioblockopen = 0x0001,
92 vioblockclose = 0x0002,
93 vioblockread = 0x0003,
94 vioblockwrite = 0x0004,
95 vioblockflush = 0x0005,
96 vioblockcheck = 0x0007
97};
98
99struct 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
113enum viocdsubtype {
114 viocdopen = 0x0001,
115 viocdclose = 0x0002,
116 viocdread = 0x0003,
117 viocdwrite = 0x0004,
118 viocdlockdoor = 0x0005,
119 viocdgetinfo = 0x0006,
120 viocdcheck = 0x0007
121};
122
123struct 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
152enum 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 */
168typedef void (vio_event_handler_t) (struct HvLpEvent * event);
169
170extern int viopath_open(HvLpIndex remoteLp, int subtype, int numReq);
171extern int viopath_close(HvLpIndex remoteLp, int subtype, int numReq);
172extern int vio_setHandler(int subtype, vio_event_handler_t * beh);
173extern int vio_clearHandler(int subtype);
174extern int viopath_isactive(HvLpIndex lp);
175extern HvLpInstanceId viopath_sourceinst(HvLpIndex lp);
176extern HvLpInstanceId viopath_targetinst(HvLpIndex lp);
177extern void vio_set_hostlp(void);
178extern void *vio_get_event_buffer(int subtype);
179extern void vio_free_event_buffer(int subtype, void *buffer);
180
181extern struct vio_dev *vio_create_viodasd(u32 unit);
182
183extern HvLpIndex viopath_hostLp;
184extern 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 */
200struct vio_error_entry {
201 u16 rc;
202 int errno;
203 const char *msg;
204};
205extern const struct vio_error_entry *vio_lookup_rc(
206 const struct vio_error_entry *local_table, u16 rc);
207
208enum 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
218enum vioconfigsubtype {
219 vioconfigget = 0x0001,
220};
221
222enum 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 */
241struct 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
253enum viocharsubtype {
254 viocharopen = 0x0001,
255 viocharclose = 0x0002,
256 viochardata = 0x0003,
257 viocharack = 0x0004,
258 viocharconfig = 0x0005
259};
260
261enum viochar_rc {
262 viochar_rc_ebusy = 1
263};
264
265#endif /* _ASM_POWERPC_ISERIES_VIO_H */
diff --git a/arch/powerpc/include/asm/kvm.h b/arch/powerpc/include/asm/kvm.h
new file mode 100644
index 00000000000..a4f6c85431f
--- /dev/null
+++ b/arch/powerpc/include/asm/kvm.h
@@ -0,0 +1,290 @@
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License, version 2, as
4 * published by the Free Software Foundation.
5 *
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 * GNU General Public License for more details.
10 *
11 * You should have received a copy of the GNU General Public License
12 * along with this program; if not, write to the Free Software
13 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
14 *
15 * Copyright IBM Corp. 2007
16 *
17 * Authors: Hollis Blanchard <hollisb@us.ibm.com>
18 */
19
20#ifndef __LINUX_KVM_POWERPC_H
21#define __LINUX_KVM_POWERPC_H
22
23#include <linux/types.h>
24
25/* Select powerpc specific features in <linux/kvm.h> */
26#define __KVM_HAVE_SPAPR_TCE
27#define __KVM_HAVE_PPC_SMT
28
29struct kvm_regs {
30 __u64 pc;
31 __u64 cr;
32 __u64 ctr;
33 __u64 lr;
34 __u64 xer;
35 __u64 msr;
36 __u64 srr0;
37 __u64 srr1;
38 __u64 pid;
39
40 __u64 sprg0;
41 __u64 sprg1;
42 __u64 sprg2;
43 __u64 sprg3;
44 __u64 sprg4;
45 __u64 sprg5;
46 __u64 sprg6;
47 __u64 sprg7;
48
49 __u64 gpr[32];
50};
51
52#define KVM_SREGS_E_IMPL_NONE 0
53#define KVM_SREGS_E_IMPL_FSL 1
54
55#define KVM_SREGS_E_FSL_PIDn (1 << 0) /* PID1/PID2 */
56
57/*
58 * Feature bits indicate which sections of the sregs struct are valid,
59 * both in KVM_GET_SREGS and KVM_SET_SREGS. On KVM_SET_SREGS, registers
60 * corresponding to unset feature bits will not be modified. This allows
61 * restoring a checkpoint made without that feature, while keeping the
62 * default values of the new registers.
63 *
64 * KVM_SREGS_E_BASE contains:
65 * CSRR0/1 (refers to SRR2/3 on 40x)
66 * ESR
67 * DEAR
68 * MCSR
69 * TSR
70 * TCR
71 * DEC
72 * TB
73 * VRSAVE (USPRG0)
74 */
75#define KVM_SREGS_E_BASE (1 << 0)
76
77/*
78 * KVM_SREGS_E_ARCH206 contains:
79 *
80 * PIR
81 * MCSRR0/1
82 * DECAR
83 * IVPR
84 */
85#define KVM_SREGS_E_ARCH206 (1 << 1)
86
87/*
88 * Contains EPCR, plus the upper half of 64-bit registers
89 * that are 32-bit on 32-bit implementations.
90 */
91#define KVM_SREGS_E_64 (1 << 2)
92
93#define KVM_SREGS_E_SPRG8 (1 << 3)
94#define KVM_SREGS_E_MCIVPR (1 << 4)
95
96/*
97 * IVORs are used -- contains IVOR0-15, plus additional IVORs
98 * in combination with an appropriate feature bit.
99 */
100#define KVM_SREGS_E_IVOR (1 << 5)
101
102/*
103 * Contains MAS0-4, MAS6-7, TLBnCFG, MMUCFG.
104 * Also TLBnPS if MMUCFG[MAVN] = 1.
105 */
106#define KVM_SREGS_E_ARCH206_MMU (1 << 6)
107
108/* DBSR, DBCR, IAC, DAC, DVC */
109#define KVM_SREGS_E_DEBUG (1 << 7)
110
111/* Enhanced debug -- DSRR0/1, SPRG9 */
112#define KVM_SREGS_E_ED (1 << 8)
113
114/* Embedded Floating Point (SPE) -- IVOR32-34 if KVM_SREGS_E_IVOR */
115#define KVM_SREGS_E_SPE (1 << 9)
116
117/* External Proxy (EXP) -- EPR */
118#define KVM_SREGS_EXP (1 << 10)
119
120/* External PID (E.PD) -- EPSC/EPLC */
121#define KVM_SREGS_E_PD (1 << 11)
122
123/* Processor Control (E.PC) -- IVOR36-37 if KVM_SREGS_E_IVOR */
124#define KVM_SREGS_E_PC (1 << 12)
125
126/* Page table (E.PT) -- EPTCFG */
127#define KVM_SREGS_E_PT (1 << 13)
128
129/* Embedded Performance Monitor (E.PM) -- IVOR35 if KVM_SREGS_E_IVOR */
130#define KVM_SREGS_E_PM (1 << 14)
131
132/*
133 * Special updates:
134 *
135 * Some registers may change even while a vcpu is not running.
136 * To avoid losing these changes, by default these registers are
137 * not updated by KVM_SET_SREGS. To force an update, set the bit
138 * in u.e.update_special corresponding to the register to be updated.
139 *
140 * The update_special field is zero on return from KVM_GET_SREGS.
141 *
142 * When restoring a checkpoint, the caller can set update_special
143 * to 0xffffffff to ensure that everything is restored, even new features
144 * that the caller doesn't know about.
145 */
146#define KVM_SREGS_E_UPDATE_MCSR (1 << 0)
147#define KVM_SREGS_E_UPDATE_TSR (1 << 1)
148#define KVM_SREGS_E_UPDATE_DEC (1 << 2)
149#define KVM_SREGS_E_UPDATE_DBSR (1 << 3)
150
151/*
152 * In KVM_SET_SREGS, reserved/pad fields must be left untouched from a
153 * previous KVM_GET_REGS.
154 *
155 * Unless otherwise indicated, setting any register with KVM_SET_SREGS
156 * directly sets its value. It does not trigger any special semantics such
157 * as write-one-to-clear. Calling KVM_SET_SREGS on an unmodified struct
158 * just received from KVM_GET_SREGS is always a no-op.
159 */
160struct kvm_sregs {
161 __u32 pvr;
162 union {
163 struct {
164 __u64 sdr1;
165 struct {
166 struct {
167 __u64 slbe;
168 __u64 slbv;
169 } slb[64];
170 } ppc64;
171 struct {
172 __u32 sr[16];
173 __u64 ibat[8];
174 __u64 dbat[8];
175 } ppc32;
176 } s;
177 struct {
178 union {
179 struct { /* KVM_SREGS_E_IMPL_FSL */
180 __u32 features; /* KVM_SREGS_E_FSL_ */
181 __u32 svr;
182 __u64 mcar;
183 __u32 hid0;
184
185 /* KVM_SREGS_E_FSL_PIDn */
186 __u32 pid1, pid2;
187 } fsl;
188 __u8 pad[256];
189 } impl;
190
191 __u32 features; /* KVM_SREGS_E_ */
192 __u32 impl_id; /* KVM_SREGS_E_IMPL_ */
193 __u32 update_special; /* KVM_SREGS_E_UPDATE_ */
194 __u32 pir; /* read-only */
195 __u64 sprg8;
196 __u64 sprg9; /* E.ED */
197 __u64 csrr0;
198 __u64 dsrr0; /* E.ED */
199 __u64 mcsrr0;
200 __u32 csrr1;
201 __u32 dsrr1; /* E.ED */
202 __u32 mcsrr1;
203 __u32 esr;
204 __u64 dear;
205 __u64 ivpr;
206 __u64 mcivpr;
207 __u64 mcsr; /* KVM_SREGS_E_UPDATE_MCSR */
208
209 __u32 tsr; /* KVM_SREGS_E_UPDATE_TSR */
210 __u32 tcr;
211 __u32 decar;
212 __u32 dec; /* KVM_SREGS_E_UPDATE_DEC */
213
214 /*
215 * Userspace can read TB directly, but the
216 * value reported here is consistent with "dec".
217 *
218 * Read-only.
219 */
220 __u64 tb;
221
222 __u32 dbsr; /* KVM_SREGS_E_UPDATE_DBSR */
223 __u32 dbcr[3];
224 __u32 iac[4];
225 __u32 dac[2];
226 __u32 dvc[2];
227 __u8 num_iac; /* read-only */
228 __u8 num_dac; /* read-only */
229 __u8 num_dvc; /* read-only */
230 __u8 pad;
231
232 __u32 epr; /* EXP */
233 __u32 vrsave; /* a.k.a. USPRG0 */
234 __u32 epcr; /* KVM_SREGS_E_64 */
235
236 __u32 mas0;
237 __u32 mas1;
238 __u64 mas2;
239 __u64 mas7_3;
240 __u32 mas4;
241 __u32 mas6;
242
243 __u32 ivor_low[16]; /* IVOR0-15 */
244 __u32 ivor_high[18]; /* IVOR32+, plus room to expand */
245
246 __u32 mmucfg; /* read-only */
247 __u32 eptcfg; /* E.PT, read-only */
248 __u32 tlbcfg[4];/* read-only */
249 __u32 tlbps[4]; /* read-only */
250
251 __u32 eplc, epsc; /* E.PD */
252 } e;
253 __u8 pad[1020];
254 } u;
255};
256
257struct kvm_fpu {
258 __u64 fpr[32];
259};
260
261struct kvm_debug_exit_arch {
262};
263
264/* for KVM_SET_GUEST_DEBUG */
265struct kvm_guest_debug_arch {
266};
267
268#define KVM_REG_MASK 0x001f
269#define KVM_REG_EXT_MASK 0xffe0
270#define KVM_REG_GPR 0x0000
271#define KVM_REG_FPR 0x0020
272#define KVM_REG_QPR 0x0040
273#define KVM_REG_FQPR 0x0060
274
275#define KVM_INTERRUPT_SET -1U
276#define KVM_INTERRUPT_UNSET -2U
277#define KVM_INTERRUPT_SET_LEVEL -3U
278
279/* for KVM_CAP_SPAPR_TCE */
280struct kvm_create_spapr_tce {
281 __u64 liobn;
282 __u32 window_size;
283};
284
285/* for KVM_ALLOCATE_RMA */
286struct kvm_allocate_rma {
287 __u64 rma_size;
288};
289
290#endif /* __LINUX_KVM_POWERPC_H */
diff --git a/arch/powerpc/include/asm/kvm_e500.h b/arch/powerpc/include/asm/kvm_e500.h
new file mode 100644
index 00000000000..adbfca9dd10
--- /dev/null
+++ b/arch/powerpc/include/asm/kvm_e500.h
@@ -0,0 +1,84 @@
1/*
2 * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All rights reserved.
3 *
4 * Author: Yu Liu, <yu.liu@freescale.com>
5 *
6 * Description:
7 * This file is derived from arch/powerpc/include/asm/kvm_44x.h,
8 * by Hollis Blanchard <hollisb@us.ibm.com>.
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, version 2, as
12 * published by the Free Software Foundation.
13 */
14
15#ifndef __ASM_KVM_E500_H__
16#define __ASM_KVM_E500_H__
17
18#include <linux/kvm_host.h>
19
20#define BOOKE_INTERRUPT_SIZE 36
21
22#define E500_PID_NUM 3
23#define E500_TLB_NUM 2
24
25struct tlbe{
26 u32 mas1;
27 u32 mas2;
28 u32 mas3;
29 u32 mas7;
30};
31
32#define E500_TLB_VALID 1
33#define E500_TLB_DIRTY 2
34
35struct tlbe_priv {
36 pfn_t pfn;
37 unsigned int flags; /* E500_TLB_* */
38};
39
40struct vcpu_id_table;
41
42struct kvmppc_vcpu_e500 {
43 /* Unmodified copy of the guest's TLB. */
44 struct tlbe *gtlb_arch[E500_TLB_NUM];
45
46 /* KVM internal information associated with each guest TLB entry */
47 struct tlbe_priv *gtlb_priv[E500_TLB_NUM];
48
49 unsigned int gtlb_size[E500_TLB_NUM];
50 unsigned int gtlb_nv[E500_TLB_NUM];
51
52 u32 host_pid[E500_PID_NUM];
53 u32 pid[E500_PID_NUM];
54 u32 svr;
55
56 u32 mas0;
57 u32 mas1;
58 u32 mas2;
59 u32 mas3;
60 u32 mas4;
61 u32 mas5;
62 u32 mas6;
63 u32 mas7;
64
65 /* vcpu id table */
66 struct vcpu_id_table *idt;
67
68 u32 l1csr0;
69 u32 l1csr1;
70 u32 hid0;
71 u32 hid1;
72 u32 tlb0cfg;
73 u32 tlb1cfg;
74 u64 mcar;
75
76 struct kvm_vcpu vcpu;
77};
78
79static inline struct kvmppc_vcpu_e500 *to_e500(struct kvm_vcpu *vcpu)
80{
81 return container_of(vcpu, struct kvmppc_vcpu_e500, vcpu);
82}
83
84#endif /* __ASM_KVM_E500_H__ */
diff --git a/arch/powerpc/include/asm/linkage.h b/arch/powerpc/include/asm/linkage.h
new file mode 100644
index 00000000000..e1c4ac1cc4b
--- /dev/null
+++ b/arch/powerpc/include/asm/linkage.h
@@ -0,0 +1,6 @@
1#ifndef _ASM_POWERPC_LINKAGE_H
2#define _ASM_POWERPC_LINKAGE_H
3
4/* Nothing to see here... */
5
6#endif /* _ASM_POWERPC_LINKAGE_H */
diff --git a/arch/powerpc/include/asm/memblock.h b/arch/powerpc/include/asm/memblock.h
new file mode 100644
index 00000000000..43efc345065
--- /dev/null
+++ b/arch/powerpc/include/asm/memblock.h
@@ -0,0 +1,8 @@
1#ifndef _ASM_POWERPC_MEMBLOCK_H
2#define _ASM_POWERPC_MEMBLOCK_H
3
4#include <asm/udbg.h>
5
6#define MEMBLOCK_DBG(fmt...) udbg_printf(fmt)
7
8#endif /* _ASM_POWERPC_MEMBLOCK_H */
diff --git a/arch/powerpc/include/asm/msgbuf.h b/arch/powerpc/include/asm/msgbuf.h
new file mode 100644
index 00000000000..dd76743c753
--- /dev/null
+++ b/arch/powerpc/include/asm/msgbuf.h
@@ -0,0 +1,33 @@
1#ifndef _ASM_POWERPC_MSGBUF_H
2#define _ASM_POWERPC_MSGBUF_H
3
4/*
5 * The msqid64_ds structure for the PowerPC architecture.
6 * Note extra padding because this structure is passed back and forth
7 * between kernel and user space.
8 */
9
10struct msqid64_ds {
11 struct ipc64_perm msg_perm;
12#ifndef __powerpc64__
13 unsigned int __unused1;
14#endif
15 __kernel_time_t msg_stime; /* last msgsnd time */
16#ifndef __powerpc64__
17 unsigned int __unused2;
18#endif
19 __kernel_time_t msg_rtime; /* last msgrcv time */
20#ifndef __powerpc64__
21 unsigned int __unused3;
22#endif
23 __kernel_time_t msg_ctime; /* last change time */
24 unsigned long msg_cbytes; /* current number of bytes on queue */
25 unsigned long msg_qnum; /* number of messages in queue */
26 unsigned long msg_qbytes; /* max number of bytes on queue */
27 __kernel_pid_t msg_lspid; /* pid of last msgsnd */
28 __kernel_pid_t msg_lrpid; /* last receive pid */
29 unsigned long __unused4;
30 unsigned long __unused5;
31};
32
33#endif /* _ASM_POWERPC_MSGBUF_H */
diff --git a/arch/powerpc/include/asm/pSeries_reconfig.h b/arch/powerpc/include/asm/pSeries_reconfig.h
new file mode 100644
index 00000000000..23cd6cc30bc
--- /dev/null
+++ b/arch/powerpc/include/asm/pSeries_reconfig.h
@@ -0,0 +1,35 @@
1#ifndef _PPC64_PSERIES_RECONFIG_H
2#define _PPC64_PSERIES_RECONFIG_H
3#ifdef __KERNEL__
4
5#include <linux/notifier.h>
6
7/*
8 * Use this API if your code needs to know about OF device nodes being
9 * added or removed on pSeries systems.
10 */
11
12#define PSERIES_RECONFIG_ADD 0x0001
13#define PSERIES_RECONFIG_REMOVE 0x0002
14#define PSERIES_DRCONF_MEM_ADD 0x0003
15#define PSERIES_DRCONF_MEM_REMOVE 0x0004
16
17#ifdef CONFIG_PPC_PSERIES
18extern int pSeries_reconfig_notifier_register(struct notifier_block *);
19extern void pSeries_reconfig_notifier_unregister(struct notifier_block *);
20extern int pSeries_reconfig_notify(unsigned long action, void *p);
21/* Not the best place to put this, will be fixed when we move some
22 * of the rtas suspend-me stuff to pseries */
23extern void pSeries_coalesce_init(void);
24#else /* !CONFIG_PPC_PSERIES */
25static inline int pSeries_reconfig_notifier_register(struct notifier_block *nb)
26{
27 return 0;
28}
29static inline void pSeries_reconfig_notifier_unregister(struct notifier_block *nb) { }
30static inline void pSeries_coalesce_init(void) { }
31#endif /* CONFIG_PPC_PSERIES */
32
33
34#endif /* __KERNEL__ */
35#endif /* _PPC64_PSERIES_RECONFIG_H */
diff --git a/arch/powerpc/include/asm/param.h b/arch/powerpc/include/asm/param.h
new file mode 100644
index 00000000000..965d4542797
--- /dev/null
+++ b/arch/powerpc/include/asm/param.h
@@ -0,0 +1 @@
#include <asm-generic/param.h>
diff --git a/arch/powerpc/include/asm/phyp_dump.h b/arch/powerpc/include/asm/phyp_dump.h
new file mode 100644
index 00000000000..fa74c6c3e10
--- /dev/null
+++ b/arch/powerpc/include/asm/phyp_dump.h
@@ -0,0 +1,47 @@
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
23struct 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
41extern struct phyp_dump *phyp_dump_info;
42
43int 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/poll.h b/arch/powerpc/include/asm/poll.h
new file mode 100644
index 00000000000..c98509d3149
--- /dev/null
+++ b/arch/powerpc/include/asm/poll.h
@@ -0,0 +1 @@
#include <asm-generic/poll.h>
diff --git a/arch/powerpc/include/asm/posix_types.h b/arch/powerpc/include/asm/posix_types.h
new file mode 100644
index 00000000000..c4e396b540d
--- /dev/null
+++ b/arch/powerpc/include/asm/posix_types.h
@@ -0,0 +1,128 @@
1#ifndef _ASM_POWERPC_POSIX_TYPES_H
2#define _ASM_POWERPC_POSIX_TYPES_H
3
4/*
5 * This file is generally used by user-level software, so you need to
6 * be a little careful about namespace pollution etc. Also, we cannot
7 * assume GCC is being used.
8 */
9
10typedef unsigned long __kernel_ino_t;
11typedef unsigned int __kernel_mode_t;
12typedef long __kernel_off_t;
13typedef int __kernel_pid_t;
14typedef unsigned int __kernel_uid_t;
15typedef unsigned int __kernel_gid_t;
16typedef long __kernel_ptrdiff_t;
17typedef long __kernel_time_t;
18typedef long __kernel_clock_t;
19typedef int __kernel_timer_t;
20typedef int __kernel_clockid_t;
21typedef long __kernel_suseconds_t;
22typedef int __kernel_daddr_t;
23typedef char * __kernel_caddr_t;
24typedef unsigned short __kernel_uid16_t;
25typedef unsigned short __kernel_gid16_t;
26typedef unsigned int __kernel_uid32_t;
27typedef unsigned int __kernel_gid32_t;
28typedef unsigned int __kernel_old_uid_t;
29typedef unsigned int __kernel_old_gid_t;
30
31#ifdef __powerpc64__
32typedef unsigned long __kernel_nlink_t;
33typedef int __kernel_ipc_pid_t;
34typedef unsigned long __kernel_size_t;
35typedef long __kernel_ssize_t;
36typedef unsigned long __kernel_old_dev_t;
37#else
38typedef unsigned short __kernel_nlink_t;
39typedef short __kernel_ipc_pid_t;
40typedef unsigned int __kernel_size_t;
41typedef int __kernel_ssize_t;
42typedef unsigned int __kernel_old_dev_t;
43#endif
44
45#ifdef __powerpc64__
46typedef long long __kernel_loff_t;
47#else
48#ifdef __GNUC__
49typedef long long __kernel_loff_t;
50#endif
51#endif
52
53typedef struct {
54 int val[2];
55} __kernel_fsid_t;
56
57#ifndef __GNUC__
58
59#define __FD_SET(d, set) ((set)->fds_bits[__FDELT(d)] |= __FDMASK(d))
60#define __FD_CLR(d, set) ((set)->fds_bits[__FDELT(d)] &= ~__FDMASK(d))
61#define __FD_ISSET(d, set) (((set)->fds_bits[__FDELT(d)] & __FDMASK(d)) != 0)
62#define __FD_ZERO(set) \
63 ((void) memset ((void *) (set), 0, sizeof (__kernel_fd_set)))
64
65#else /* __GNUC__ */
66
67#if defined(__KERNEL__)
68/* With GNU C, use inline functions instead so args are evaluated only once: */
69
70#undef __FD_SET
71static __inline__ void __FD_SET(unsigned long fd, __kernel_fd_set *fdsetp)
72{
73 unsigned long _tmp = fd / __NFDBITS;
74 unsigned long _rem = fd % __NFDBITS;
75 fdsetp->fds_bits[_tmp] |= (1UL<<_rem);
76}
77
78#undef __FD_CLR
79static __inline__ void __FD_CLR(unsigned long fd, __kernel_fd_set *fdsetp)
80{
81 unsigned long _tmp = fd / __NFDBITS;
82 unsigned long _rem = fd % __NFDBITS;
83 fdsetp->fds_bits[_tmp] &= ~(1UL<<_rem);
84}
85
86#undef __FD_ISSET
87static __inline__ int __FD_ISSET(unsigned long fd, __kernel_fd_set *p)
88{
89 unsigned long _tmp = fd / __NFDBITS;
90 unsigned long _rem = fd % __NFDBITS;
91 return (p->fds_bits[_tmp] & (1UL<<_rem)) != 0;
92}
93
94/*
95 * This will unroll the loop for the normal constant case (8 ints,
96 * for a 256-bit fd_set)
97 */
98#undef __FD_ZERO
99static __inline__ void __FD_ZERO(__kernel_fd_set *p)
100{
101 unsigned long *tmp = (unsigned long *)p->fds_bits;
102 int i;
103
104 if (__builtin_constant_p(__FDSET_LONGS)) {
105 switch (__FDSET_LONGS) {
106 case 16:
107 tmp[12] = 0; tmp[13] = 0; tmp[14] = 0; tmp[15] = 0;
108 tmp[ 8] = 0; tmp[ 9] = 0; tmp[10] = 0; tmp[11] = 0;
109
110 case 8:
111 tmp[ 4] = 0; tmp[ 5] = 0; tmp[ 6] = 0; tmp[ 7] = 0;
112
113 case 4:
114 tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0;
115 return;
116 }
117 }
118 i = __FDSET_LONGS;
119 while (i) {
120 i--;
121 *tmp = 0;
122 tmp++;
123 }
124}
125
126#endif /* defined(__KERNEL__) */
127#endif /* __GNUC__ */
128#endif /* _ASM_POWERPC_POSIX_TYPES_H */
diff --git a/arch/powerpc/include/asm/ps3fb.h b/arch/powerpc/include/asm/ps3fb.h
new file mode 100644
index 00000000000..e7233a84968
--- /dev/null
+++ b/arch/powerpc/include/asm/ps3fb.h
@@ -0,0 +1,45 @@
1/*
2 * Copyright (C) 2006 Sony Computer Entertainment Inc.
3 * Copyright 2006, 2007 Sony Corporation
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published
7 * by the Free Software Foundation; version 2 of the License.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19#ifndef _ASM_POWERPC_PS3FB_H_
20#define _ASM_POWERPC_PS3FB_H_
21
22#include <linux/types.h>
23#include <linux/ioctl.h>
24
25/* ioctl */
26#define PS3FB_IOCTL_SETMODE _IOW('r', 1, int) /* set video mode */
27#define PS3FB_IOCTL_GETMODE _IOR('r', 2, int) /* get video mode */
28#define PS3FB_IOCTL_SCREENINFO _IOR('r', 3, int) /* get screen info */
29#define PS3FB_IOCTL_ON _IO('r', 4) /* use IOCTL_FSEL */
30#define PS3FB_IOCTL_OFF _IO('r', 5) /* return to normal-flip */
31#define PS3FB_IOCTL_FSEL _IOW('r', 6, int) /* blit and flip request */
32
33#ifndef FBIO_WAITFORVSYNC
34#define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32) /* wait for vsync */
35#endif
36
37struct ps3fb_ioctl_res {
38 __u32 xres; /* frame buffer x_size */
39 __u32 yres; /* frame buffer y_size */
40 __u32 xoff; /* margine x */
41 __u32 yoff; /* margine y */
42 __u32 num_frames; /* num of frame buffers */
43};
44
45#endif /* _ASM_POWERPC_PS3FB_H_ */
diff --git a/arch/powerpc/include/asm/resource.h b/arch/powerpc/include/asm/resource.h
new file mode 100644
index 00000000000..04bc4db8921
--- /dev/null
+++ b/arch/powerpc/include/asm/resource.h
@@ -0,0 +1 @@
#include <asm-generic/resource.h>
diff --git a/arch/powerpc/include/asm/rwsem.h b/arch/powerpc/include/asm/rwsem.h
new file mode 100644
index 00000000000..bb1e2cdeb9b
--- /dev/null
+++ b/arch/powerpc/include/asm/rwsem.h
@@ -0,0 +1,132 @@
1#ifndef _ASM_POWERPC_RWSEM_H
2#define _ASM_POWERPC_RWSEM_H
3
4#ifndef _LINUX_RWSEM_H
5#error "Please don't include <asm/rwsem.h> directly, use <linux/rwsem.h> instead."
6#endif
7
8#ifdef __KERNEL__
9
10/*
11 * R/W semaphores for PPC using the stuff in lib/rwsem.c.
12 * Adapted largely from include/asm-i386/rwsem.h
13 * by Paul Mackerras <paulus@samba.org>.
14 */
15
16/*
17 * the semaphore definition
18 */
19#ifdef CONFIG_PPC64
20# define RWSEM_ACTIVE_MASK 0xffffffffL
21#else
22# define RWSEM_ACTIVE_MASK 0x0000ffffL
23#endif
24
25#define RWSEM_UNLOCKED_VALUE 0x00000000L
26#define RWSEM_ACTIVE_BIAS 0x00000001L
27#define RWSEM_WAITING_BIAS (-RWSEM_ACTIVE_MASK-1)
28#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS
29#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
30
31/*
32 * lock for reading
33 */
34static inline void __down_read(struct rw_semaphore *sem)
35{
36 if (unlikely(atomic_long_inc_return((atomic_long_t *)&sem->count) <= 0))
37 rwsem_down_read_failed(sem);
38}
39
40static inline int __down_read_trylock(struct rw_semaphore *sem)
41{
42 long tmp;
43
44 while ((tmp = sem->count) >= 0) {
45 if (tmp == cmpxchg(&sem->count, tmp,
46 tmp + RWSEM_ACTIVE_READ_BIAS)) {
47 return 1;
48 }
49 }
50 return 0;
51}
52
53/*
54 * lock for writing
55 */
56static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
57{
58 long tmp;
59
60 tmp = atomic_long_add_return(RWSEM_ACTIVE_WRITE_BIAS,
61 (atomic_long_t *)&sem->count);
62 if (unlikely(tmp != RWSEM_ACTIVE_WRITE_BIAS))
63 rwsem_down_write_failed(sem);
64}
65
66static inline void __down_write(struct rw_semaphore *sem)
67{
68 __down_write_nested(sem, 0);
69}
70
71static inline int __down_write_trylock(struct rw_semaphore *sem)
72{
73 long tmp;
74
75 tmp = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE,
76 RWSEM_ACTIVE_WRITE_BIAS);
77 return tmp == RWSEM_UNLOCKED_VALUE;
78}
79
80/*
81 * unlock after reading
82 */
83static inline void __up_read(struct rw_semaphore *sem)
84{
85 long tmp;
86
87 tmp = atomic_long_dec_return((atomic_long_t *)&sem->count);
88 if (unlikely(tmp < -1 && (tmp & RWSEM_ACTIVE_MASK) == 0))
89 rwsem_wake(sem);
90}
91
92/*
93 * unlock after writing
94 */
95static inline void __up_write(struct rw_semaphore *sem)
96{
97 if (unlikely(atomic_long_sub_return(RWSEM_ACTIVE_WRITE_BIAS,
98 (atomic_long_t *)&sem->count) < 0))
99 rwsem_wake(sem);
100}
101
102/*
103 * implement atomic add functionality
104 */
105static inline void rwsem_atomic_add(long delta, struct rw_semaphore *sem)
106{
107 atomic_long_add(delta, (atomic_long_t *)&sem->count);
108}
109
110/*
111 * downgrade write lock to read lock
112 */
113static inline void __downgrade_write(struct rw_semaphore *sem)
114{
115 long tmp;
116
117 tmp = atomic_long_add_return(-RWSEM_WAITING_BIAS,
118 (atomic_long_t *)&sem->count);
119 if (tmp < 0)
120 rwsem_downgrade_wake(sem);
121}
122
123/*
124 * implement exchange and add functionality
125 */
126static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem)
127{
128 return atomic_long_add_return(delta, (atomic_long_t *)&sem->count);
129}
130
131#endif /* __KERNEL__ */
132#endif /* _ASM_POWERPC_RWSEM_H */
diff --git a/arch/powerpc/include/asm/seccomp.h b/arch/powerpc/include/asm/seccomp.h
new file mode 100644
index 00000000000..00c1d9133cf
--- /dev/null
+++ b/arch/powerpc/include/asm/seccomp.h
@@ -0,0 +1,16 @@
1#ifndef _ASM_POWERPC_SECCOMP_H
2#define _ASM_POWERPC_SECCOMP_H
3
4#include <linux/unistd.h>
5
6#define __NR_seccomp_read __NR_read
7#define __NR_seccomp_write __NR_write
8#define __NR_seccomp_exit __NR_exit
9#define __NR_seccomp_sigreturn __NR_rt_sigreturn
10
11#define __NR_seccomp_read_32 __NR_read
12#define __NR_seccomp_write_32 __NR_write
13#define __NR_seccomp_exit_32 __NR_exit
14#define __NR_seccomp_sigreturn_32 __NR_sigreturn
15
16#endif /* _ASM_POWERPC_SECCOMP_H */
diff --git a/arch/powerpc/include/asm/sembuf.h b/arch/powerpc/include/asm/sembuf.h
new file mode 100644
index 00000000000..99a41938ae3
--- /dev/null
+++ b/arch/powerpc/include/asm/sembuf.h
@@ -0,0 +1,36 @@
1#ifndef _ASM_POWERPC_SEMBUF_H
2#define _ASM_POWERPC_SEMBUF_H
3
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/*
12 * The semid64_ds structure for PPC architecture.
13 * Note extra padding because this structure is passed back and forth
14 * between kernel and user space.
15 *
16 * Pad space is left for:
17 * - 64-bit time_t to solve y2038 problem
18 * - 2 miscellaneous 32-bit values
19 */
20
21struct semid64_ds {
22 struct ipc64_perm sem_perm; /* permissions .. see ipc.h */
23#ifndef __powerpc64__
24 unsigned long __unused1;
25#endif
26 __kernel_time_t sem_otime; /* last semop time */
27#ifndef __powerpc64__
28 unsigned long __unused2;
29#endif
30 __kernel_time_t sem_ctime; /* last change time */
31 unsigned long sem_nsems; /* no. of semaphores in array */
32 unsigned long __unused3;
33 unsigned long __unused4;
34};
35
36#endif /* _ASM_POWERPC_SEMBUF_H */
diff --git a/arch/powerpc/include/asm/shmbuf.h b/arch/powerpc/include/asm/shmbuf.h
new file mode 100644
index 00000000000..8efa39698b6
--- /dev/null
+++ b/arch/powerpc/include/asm/shmbuf.h
@@ -0,0 +1,59 @@
1#ifndef _ASM_POWERPC_SHMBUF_H
2#define _ASM_POWERPC_SHMBUF_H
3
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/*
12 * The shmid64_ds structure for PPC architecture.
13 *
14 * Note extra padding because this structure is passed back and forth
15 * between kernel and user space.
16 *
17 * Pad space is left for:
18 * - 64-bit time_t to solve y2038 problem
19 * - 2 miscellaneous 32-bit values
20 */
21
22struct shmid64_ds {
23 struct ipc64_perm shm_perm; /* operation perms */
24#ifndef __powerpc64__
25 unsigned long __unused1;
26#endif
27 __kernel_time_t shm_atime; /* last attach time */
28#ifndef __powerpc64__
29 unsigned long __unused2;
30#endif
31 __kernel_time_t shm_dtime; /* last detach time */
32#ifndef __powerpc64__
33 unsigned long __unused3;
34#endif
35 __kernel_time_t shm_ctime; /* last change time */
36#ifndef __powerpc64__
37 unsigned long __unused4;
38#endif
39 size_t shm_segsz; /* size of segment (bytes) */
40 __kernel_pid_t shm_cpid; /* pid of creator */
41 __kernel_pid_t shm_lpid; /* pid of last operator */
42 unsigned long shm_nattch; /* no. of current attaches */
43 unsigned long __unused5;
44 unsigned long __unused6;
45};
46
47struct shminfo64 {
48 unsigned long shmmax;
49 unsigned long shmmin;
50 unsigned long shmmni;
51 unsigned long shmseg;
52 unsigned long shmall;
53 unsigned long __unused1;
54 unsigned long __unused2;
55 unsigned long __unused3;
56 unsigned long __unused4;
57};
58
59#endif /* _ASM_POWERPC_SHMBUF_H */
diff --git a/arch/powerpc/include/asm/sigcontext.h b/arch/powerpc/include/asm/sigcontext.h
new file mode 100644
index 00000000000..9c1f24fd5d1
--- /dev/null
+++ b/arch/powerpc/include/asm/sigcontext.h
@@ -0,0 +1,87 @@
1#ifndef _ASM_POWERPC_SIGCONTEXT_H
2#define _ASM_POWERPC_SIGCONTEXT_H
3
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#include <linux/compiler.h>
11#include <asm/ptrace.h>
12#ifdef __powerpc64__
13#include <asm/elf.h>
14#endif
15
16struct sigcontext {
17 unsigned long _unused[4];
18 int signal;
19#ifdef __powerpc64__
20 int _pad0;
21#endif
22 unsigned long handler;
23 unsigned long oldmask;
24 struct pt_regs __user *regs;
25#ifdef __powerpc64__
26 elf_gregset_t gp_regs;
27 elf_fpregset_t fp_regs;
28/*
29 * To maintain compatibility with current implementations the sigcontext is
30 * extended by appending a pointer (v_regs) to a quadword type (elf_vrreg_t)
31 * followed by an unstructured (vmx_reserve) field of 69 doublewords. This
32 * allows the array of vector registers to be quadword aligned independent of
33 * the alignment of the containing sigcontext or ucontext. It is the
34 * responsibility of the code setting the sigcontext to set this pointer to
35 * either NULL (if this processor does not support the VMX feature) or the
36 * address of the first quadword within the allocated (vmx_reserve) area.
37 *
38 * The pointer (v_regs) of vector type (elf_vrreg_t) is type compatible with
39 * an array of 34 quadword entries (elf_vrregset_t). The entries with
40 * indexes 0-31 contain the corresponding vector registers. The entry with
41 * index 32 contains the vscr as the last word (offset 12) within the
42 * quadword. This allows the vscr to be stored as either a quadword (since
43 * it must be copied via a vector register to/from storage) or as a word.
44 * The entry with index 33 contains the vrsave as the first word (offset 0)
45 * within the quadword.
46 *
47 * Part of the VSX data is stored here also by extending vmx_restore
48 * by an additional 32 double words. Architecturally the layout of
49 * the VSR registers and how they overlap on top of the legacy FPR and
50 * VR registers is shown below:
51 *
52 * VSR doubleword 0 VSR doubleword 1
53 * ----------------------------------------------------------------
54 * VSR[0] | FPR[0] | |
55 * ----------------------------------------------------------------
56 * VSR[1] | FPR[1] | |
57 * ----------------------------------------------------------------
58 * | ... | |
59 * | ... | |
60 * ----------------------------------------------------------------
61 * VSR[30] | FPR[30] | |
62 * ----------------------------------------------------------------
63 * VSR[31] | FPR[31] | |
64 * ----------------------------------------------------------------
65 * VSR[32] | VR[0] |
66 * ----------------------------------------------------------------
67 * VSR[33] | VR[1] |
68 * ----------------------------------------------------------------
69 * | ... |
70 * | ... |
71 * ----------------------------------------------------------------
72 * VSR[62] | VR[30] |
73 * ----------------------------------------------------------------
74 * VSR[63] | VR[31] |
75 * ----------------------------------------------------------------
76 *
77 * FPR/VSR 0-31 doubleword 0 is stored in fp_regs, and VMX/VSR 32-63
78 * is stored at the start of vmx_reserve. vmx_reserve is extended for
79 * backwards compatility to store VSR 0-31 doubleword 1 after the VMX
80 * registers and vscr/vrsave.
81 */
82 elf_vrreg_t __user *v_regs;
83 long vmx_reserve[ELF_NVRREG+ELF_NVRREG+32+1];
84#endif
85};
86
87#endif /* _ASM_POWERPC_SIGCONTEXT_H */
diff --git a/arch/powerpc/include/asm/siginfo.h b/arch/powerpc/include/asm/siginfo.h
new file mode 100644
index 00000000000..49495b0534e
--- /dev/null
+++ b/arch/powerpc/include/asm/siginfo.h
@@ -0,0 +1,21 @@
1#ifndef _ASM_POWERPC_SIGINFO_H
2#define _ASM_POWERPC_SIGINFO_H
3
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#ifdef __powerpc64__
12# define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int))
13# define SI_PAD_SIZE32 ((SI_MAX_SIZE/sizeof(int)) - 3)
14#endif
15
16#include <asm-generic/siginfo.h>
17
18#undef NSIGTRAP
19#define NSIGTRAP 4
20
21#endif /* _ASM_POWERPC_SIGINFO_H */
diff --git a/arch/powerpc/include/asm/socket.h b/arch/powerpc/include/asm/socket.h
new file mode 100644
index 00000000000..866f7606da6
--- /dev/null
+++ b/arch/powerpc/include/asm/socket.h
@@ -0,0 +1,72 @@
1#ifndef _ASM_POWERPC_SOCKET_H
2#define _ASM_POWERPC_SOCKET_H
3
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/sockios.h>
12
13/* For setsockopt(2) */
14#define SOL_SOCKET 1
15
16#define SO_DEBUG 1
17#define SO_REUSEADDR 2
18#define SO_TYPE 3
19#define SO_ERROR 4
20#define SO_DONTROUTE 5
21#define SO_BROADCAST 6
22#define SO_SNDBUF 7
23#define SO_RCVBUF 8
24#define SO_SNDBUFFORCE 32
25#define SO_RCVBUFFORCE 33
26#define SO_KEEPALIVE 9
27#define SO_OOBINLINE 10
28#define SO_NO_CHECK 11
29#define SO_PRIORITY 12
30#define SO_LINGER 13
31#define SO_BSDCOMPAT 14
32/* To add :#define SO_REUSEPORT 15 */
33#define SO_RCVLOWAT 16
34#define SO_SNDLOWAT 17
35#define SO_RCVTIMEO 18
36#define SO_SNDTIMEO 19
37#define SO_PASSCRED 20
38#define SO_PEERCRED 21
39
40/* Security levels - as per NRL IPv6 - don't actually do anything */
41#define SO_SECURITY_AUTHENTICATION 22
42#define SO_SECURITY_ENCRYPTION_TRANSPORT 23
43#define SO_SECURITY_ENCRYPTION_NETWORK 24
44
45#define SO_BINDTODEVICE 25
46
47/* Socket filtering */
48#define SO_ATTACH_FILTER 26
49#define SO_DETACH_FILTER 27
50
51#define SO_PEERNAME 28
52#define SO_TIMESTAMP 29
53#define SCM_TIMESTAMP SO_TIMESTAMP
54
55#define SO_ACCEPTCONN 30
56
57#define SO_PEERSEC 31
58#define SO_PASSSEC 34
59#define SO_TIMESTAMPNS 35
60#define SCM_TIMESTAMPNS SO_TIMESTAMPNS
61
62#define SO_MARK 36
63
64#define SO_TIMESTAMPING 37
65#define SCM_TIMESTAMPING SO_TIMESTAMPING
66
67#define SO_PROTOCOL 38
68#define SO_DOMAIN 39
69
70#define SO_RXQ_OVFL 40
71
72#endif /* _ASM_POWERPC_SOCKET_H */
diff --git a/arch/powerpc/include/asm/sockios.h b/arch/powerpc/include/asm/sockios.h
new file mode 100644
index 00000000000..55cef7675a3
--- /dev/null
+++ b/arch/powerpc/include/asm/sockios.h
@@ -0,0 +1,20 @@
1#ifndef _ASM_POWERPC_SOCKIOS_H
2#define _ASM_POWERPC_SOCKIOS_H
3
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/* Socket-level I/O control calls. */
12#define FIOSETOWN 0x8901
13#define SIOCSPGRP 0x8902
14#define FIOGETOWN 0x8903
15#define SIOCGPGRP 0x8904
16#define SIOCATMARK 0x8905
17#define SIOCGSTAMP 0x8906 /* Get stamp (timeval) */
18#define SIOCGSTAMPNS 0x8907 /* Get stamp (timespec) */
19
20#endif /* _ASM_POWERPC_SOCKIOS_H */
diff --git a/arch/powerpc/include/asm/stat.h b/arch/powerpc/include/asm/stat.h
new file mode 100644
index 00000000000..e4edc510b53
--- /dev/null
+++ b/arch/powerpc/include/asm/stat.h
@@ -0,0 +1,81 @@
1#ifndef _ASM_POWERPC_STAT_H
2#define _ASM_POWERPC_STAT_H
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
11#define STAT_HAVE_NSEC 1
12
13#ifndef __powerpc64__
14struct __old_kernel_stat {
15 unsigned short st_dev;
16 unsigned short st_ino;
17 unsigned short st_mode;
18 unsigned short st_nlink;
19 unsigned short st_uid;
20 unsigned short st_gid;
21 unsigned short st_rdev;
22 unsigned long st_size;
23 unsigned long st_atime;
24 unsigned long st_mtime;
25 unsigned long st_ctime;
26};
27#endif /* !__powerpc64__ */
28
29struct stat {
30 unsigned long st_dev;
31 ino_t st_ino;
32#ifdef __powerpc64__
33 nlink_t st_nlink;
34 mode_t st_mode;
35#else
36 mode_t st_mode;
37 nlink_t st_nlink;
38#endif
39 uid_t st_uid;
40 gid_t st_gid;
41 unsigned long st_rdev;
42 off_t st_size;
43 unsigned long st_blksize;
44 unsigned long st_blocks;
45 unsigned long st_atime;
46 unsigned long st_atime_nsec;
47 unsigned long st_mtime;
48 unsigned long st_mtime_nsec;
49 unsigned long st_ctime;
50 unsigned long st_ctime_nsec;
51 unsigned long __unused4;
52 unsigned long __unused5;
53#ifdef __powerpc64__
54 unsigned long __unused6;
55#endif
56};
57
58/* This matches struct stat64 in glibc2.1. Only used for 32 bit. */
59struct stat64 {
60 unsigned long long st_dev; /* Device. */
61 unsigned long long st_ino; /* File serial number. */
62 unsigned int st_mode; /* File mode. */
63 unsigned int st_nlink; /* Link count. */
64 unsigned int st_uid; /* User ID of the file's owner. */
65 unsigned int st_gid; /* Group ID of the file's group. */
66 unsigned long long st_rdev; /* Device number, if device. */
67 unsigned short __pad2;
68 long long st_size; /* Size of file, in bytes. */
69 int st_blksize; /* Optimal block size for I/O. */
70 long long st_blocks; /* Number 512-byte blocks allocated. */
71 int st_atime; /* Time of last access. */
72 unsigned int st_atime_nsec;
73 int st_mtime; /* Time of last modification. */
74 unsigned int st_mtime_nsec;
75 int st_ctime; /* Time of last status change. */
76 unsigned int st_ctime_nsec;
77 unsigned int __unused4;
78 unsigned int __unused5;
79};
80
81#endif /* _ASM_POWERPC_STAT_H */
diff --git a/arch/powerpc/include/asm/statfs.h b/arch/powerpc/include/asm/statfs.h
new file mode 100644
index 00000000000..5244834583a
--- /dev/null
+++ b/arch/powerpc/include/asm/statfs.h
@@ -0,0 +1,6 @@
1#ifndef _ASM_POWERPC_STATFS_H
2#define _ASM_POWERPC_STATFS_H
3
4#include <asm-generic/statfs.h>
5
6#endif
diff --git a/arch/powerpc/include/asm/system.h b/arch/powerpc/include/asm/system.h
new file mode 100644
index 00000000000..e30a13d1ee7
--- /dev/null
+++ b/arch/powerpc/include/asm/system.h
@@ -0,0 +1,545 @@
1/*
2 * Copyright (C) 1999 Cort Dougan <cort@cs.nmt.edu>
3 */
4#ifndef _ASM_POWERPC_SYSTEM_H
5#define _ASM_POWERPC_SYSTEM_H
6
7#include <linux/kernel.h>
8#include <linux/irqflags.h>
9
10#include <asm/hw_irq.h>
11
12/*
13 * Memory barrier.
14 * The sync instruction guarantees that all memory accesses initiated
15 * by this processor have been performed (with respect to all other
16 * mechanisms that access memory). The eieio instruction is a barrier
17 * providing an ordering (separately) for (a) cacheable stores and (b)
18 * loads and stores to non-cacheable memory (e.g. I/O devices).
19 *
20 * mb() prevents loads and stores being reordered across this point.
21 * rmb() prevents loads being reordered across this point.
22 * wmb() prevents stores being reordered across this point.
23 * read_barrier_depends() prevents data-dependent loads being reordered
24 * across this point (nop on PPC).
25 *
26 * *mb() variants without smp_ prefix must order all types of memory
27 * operations with one another. sync is the only instruction sufficient
28 * to do this.
29 *
30 * For the smp_ barriers, ordering is for cacheable memory operations
31 * only. We have to use the sync instruction for smp_mb(), since lwsync
32 * doesn't order loads with respect to previous stores. Lwsync can be
33 * used for smp_rmb() and smp_wmb().
34 *
35 * However, on CPUs that don't support lwsync, lwsync actually maps to a
36 * heavy-weight sync, so smp_wmb() can be a lighter-weight eieio.
37 */
38#define mb() __asm__ __volatile__ ("sync" : : : "memory")
39#define rmb() __asm__ __volatile__ ("sync" : : : "memory")
40#define wmb() __asm__ __volatile__ ("sync" : : : "memory")
41#define read_barrier_depends() do { } while(0)
42
43#define set_mb(var, value) do { var = value; mb(); } while (0)
44
45#ifdef __KERNEL__
46#define AT_VECTOR_SIZE_ARCH 6 /* entries in ARCH_DLINFO */
47#ifdef CONFIG_SMP
48
49#ifdef __SUBARCH_HAS_LWSYNC
50# define SMPWMB LWSYNC
51#else
52# define SMPWMB eieio
53#endif
54
55#define smp_mb() mb()
56#define smp_rmb() __asm__ __volatile__ (stringify_in_c(LWSYNC) : : :"memory")
57#define smp_wmb() __asm__ __volatile__ (stringify_in_c(SMPWMB) : : :"memory")
58#define smp_read_barrier_depends() read_barrier_depends()
59#else
60#define smp_mb() barrier()
61#define smp_rmb() barrier()
62#define smp_wmb() barrier()
63#define smp_read_barrier_depends() do { } while(0)
64#endif /* CONFIG_SMP */
65
66/*
67 * This is a barrier which prevents following instructions from being
68 * started until the value of the argument x is known. For example, if
69 * x is a variable loaded from memory, this prevents following
70 * instructions from being executed until the load has been performed.
71 */
72#define data_barrier(x) \
73 asm volatile("twi 0,%0,0; isync" : : "r" (x) : "memory");
74
75struct task_struct;
76struct pt_regs;
77
78#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
79
80extern int (*__debugger)(struct pt_regs *regs);
81extern int (*__debugger_ipi)(struct pt_regs *regs);
82extern int (*__debugger_bpt)(struct pt_regs *regs);
83extern int (*__debugger_sstep)(struct pt_regs *regs);
84extern int (*__debugger_iabr_match)(struct pt_regs *regs);
85extern int (*__debugger_dabr_match)(struct pt_regs *regs);
86extern int (*__debugger_fault_handler)(struct pt_regs *regs);
87
88#define DEBUGGER_BOILERPLATE(__NAME) \
89static inline int __NAME(struct pt_regs *regs) \
90{ \
91 if (unlikely(__ ## __NAME)) \
92 return __ ## __NAME(regs); \
93 return 0; \
94}
95
96DEBUGGER_BOILERPLATE(debugger)
97DEBUGGER_BOILERPLATE(debugger_ipi)
98DEBUGGER_BOILERPLATE(debugger_bpt)
99DEBUGGER_BOILERPLATE(debugger_sstep)
100DEBUGGER_BOILERPLATE(debugger_iabr_match)
101DEBUGGER_BOILERPLATE(debugger_dabr_match)
102DEBUGGER_BOILERPLATE(debugger_fault_handler)
103
104#else
105static inline int debugger(struct pt_regs *regs) { return 0; }
106static inline int debugger_ipi(struct pt_regs *regs) { return 0; }
107static inline int debugger_bpt(struct pt_regs *regs) { return 0; }
108static inline int debugger_sstep(struct pt_regs *regs) { return 0; }
109static inline int debugger_iabr_match(struct pt_regs *regs) { return 0; }
110static inline int debugger_dabr_match(struct pt_regs *regs) { return 0; }
111static inline int debugger_fault_handler(struct pt_regs *regs) { return 0; }
112#endif
113
114extern int set_dabr(unsigned long dabr);
115#ifdef CONFIG_PPC_ADV_DEBUG_REGS
116extern void do_send_trap(struct pt_regs *regs, unsigned long address,
117 unsigned long error_code, int signal_code, int brkpt);
118#else
119extern void do_dabr(struct pt_regs *regs, unsigned long address,
120 unsigned long error_code);
121#endif
122extern void print_backtrace(unsigned long *);
123extern void flush_instruction_cache(void);
124extern void hard_reset_now(void);
125extern void poweroff_now(void);
126
127#ifdef CONFIG_6xx
128extern long _get_L2CR(void);
129extern long _get_L3CR(void);
130extern void _set_L2CR(unsigned long);
131extern void _set_L3CR(unsigned long);
132#else
133#define _get_L2CR() 0L
134#define _get_L3CR() 0L
135#define _set_L2CR(val) do { } while(0)
136#define _set_L3CR(val) do { } while(0)
137#endif
138
139extern void via_cuda_init(void);
140extern void read_rtc_time(void);
141extern void pmac_find_display(void);
142extern void giveup_fpu(struct task_struct *);
143extern void disable_kernel_fp(void);
144extern void enable_kernel_fp(void);
145extern void flush_fp_to_thread(struct task_struct *);
146extern void enable_kernel_altivec(void);
147extern void giveup_altivec(struct task_struct *);
148extern void load_up_altivec(struct task_struct *);
149extern int emulate_altivec(struct pt_regs *);
150extern void __giveup_vsx(struct task_struct *);
151extern void giveup_vsx(struct task_struct *);
152extern void enable_kernel_spe(void);
153extern void giveup_spe(struct task_struct *);
154extern void load_up_spe(struct task_struct *);
155extern int fix_alignment(struct pt_regs *);
156extern void cvt_fd(float *from, double *to);
157extern void cvt_df(double *from, float *to);
158
159#ifndef CONFIG_SMP
160extern void discard_lazy_cpu_state(void);
161#else
162static inline void discard_lazy_cpu_state(void)
163{
164}
165#endif
166
167#ifdef CONFIG_ALTIVEC
168extern void flush_altivec_to_thread(struct task_struct *);
169#else
170static inline void flush_altivec_to_thread(struct task_struct *t)
171{
172}
173#endif
174
175#ifdef CONFIG_VSX
176extern void flush_vsx_to_thread(struct task_struct *);
177#else
178static inline void flush_vsx_to_thread(struct task_struct *t)
179{
180}
181#endif
182
183#ifdef CONFIG_SPE
184extern void flush_spe_to_thread(struct task_struct *);
185#else
186static inline void flush_spe_to_thread(struct task_struct *t)
187{
188}
189#endif
190
191extern int call_rtas(const char *, int, int, unsigned long *, ...);
192extern void cacheable_memzero(void *p, unsigned int nb);
193extern void *cacheable_memcpy(void *, const void *, unsigned int);
194extern int do_page_fault(struct pt_regs *, unsigned long, unsigned long);
195extern void bad_page_fault(struct pt_regs *, unsigned long, int);
196extern int die(const char *, struct pt_regs *, long);
197extern void _exception(int, struct pt_regs *, int, unsigned long);
198extern void _nmask_and_or_msr(unsigned long nmask, unsigned long or_val);
199
200#ifdef CONFIG_BOOKE_WDT
201extern u32 booke_wdt_enabled;
202extern u32 booke_wdt_period;
203#endif /* CONFIG_BOOKE_WDT */
204
205struct device_node;
206extern void note_scsi_host(struct device_node *, void *);
207
208extern struct task_struct *__switch_to(struct task_struct *,
209 struct task_struct *);
210#define switch_to(prev, next, last) ((last) = __switch_to((prev), (next)))
211
212struct thread_struct;
213extern struct task_struct *_switch(struct thread_struct *prev,
214 struct thread_struct *next);
215
216extern unsigned int rtas_data;
217extern int mem_init_done; /* set on boot once kmalloc can be called */
218extern int init_bootmem_done; /* set once bootmem is available */
219extern phys_addr_t memory_limit;
220extern unsigned long klimit;
221extern void *zalloc_maybe_bootmem(size_t size, gfp_t mask);
222
223extern int powersave_nap; /* set if nap mode can be used in idle loop */
224
225/*
226 * Atomic exchange
227 *
228 * Changes the memory location '*ptr' to be val and returns
229 * the previous value stored there.
230 */
231static __always_inline unsigned long
232__xchg_u32(volatile void *p, unsigned long val)
233{
234 unsigned long prev;
235
236 __asm__ __volatile__(
237 PPC_RELEASE_BARRIER
238"1: lwarx %0,0,%2 \n"
239 PPC405_ERR77(0,%2)
240" stwcx. %3,0,%2 \n\
241 bne- 1b"
242 PPC_ACQUIRE_BARRIER
243 : "=&r" (prev), "+m" (*(volatile unsigned int *)p)
244 : "r" (p), "r" (val)
245 : "cc", "memory");
246
247 return prev;
248}
249
250/*
251 * Atomic exchange
252 *
253 * Changes the memory location '*ptr' to be val and returns
254 * the previous value stored there.
255 */
256static __always_inline unsigned long
257__xchg_u32_local(volatile void *p, unsigned long val)
258{
259 unsigned long prev;
260
261 __asm__ __volatile__(
262"1: lwarx %0,0,%2 \n"
263 PPC405_ERR77(0,%2)
264" stwcx. %3,0,%2 \n\
265 bne- 1b"
266 : "=&r" (prev), "+m" (*(volatile unsigned int *)p)
267 : "r" (p), "r" (val)
268 : "cc", "memory");
269
270 return prev;
271}
272
273#ifdef CONFIG_PPC64
274static __always_inline unsigned long
275__xchg_u64(volatile void *p, unsigned long val)
276{
277 unsigned long prev;
278
279 __asm__ __volatile__(
280 PPC_RELEASE_BARRIER
281"1: ldarx %0,0,%2 \n"
282 PPC405_ERR77(0,%2)
283" stdcx. %3,0,%2 \n\
284 bne- 1b"
285 PPC_ACQUIRE_BARRIER
286 : "=&r" (prev), "+m" (*(volatile unsigned long *)p)
287 : "r" (p), "r" (val)
288 : "cc", "memory");
289
290 return prev;
291}
292
293static __always_inline unsigned long
294__xchg_u64_local(volatile void *p, unsigned long val)
295{
296 unsigned long prev;
297
298 __asm__ __volatile__(
299"1: ldarx %0,0,%2 \n"
300 PPC405_ERR77(0,%2)
301" stdcx. %3,0,%2 \n\
302 bne- 1b"
303 : "=&r" (prev), "+m" (*(volatile unsigned long *)p)
304 : "r" (p), "r" (val)
305 : "cc", "memory");
306
307 return prev;
308}
309#endif
310
311/*
312 * This function doesn't exist, so you'll get a linker error
313 * if something tries to do an invalid xchg().
314 */
315extern void __xchg_called_with_bad_pointer(void);
316
317static __always_inline unsigned long
318__xchg(volatile void *ptr, unsigned long x, unsigned int size)
319{
320 switch (size) {
321 case 4:
322 return __xchg_u32(ptr, x);
323#ifdef CONFIG_PPC64
324 case 8:
325 return __xchg_u64(ptr, x);
326#endif
327 }
328 __xchg_called_with_bad_pointer();
329 return x;
330}
331
332static __always_inline unsigned long
333__xchg_local(volatile void *ptr, unsigned long x, unsigned int size)
334{
335 switch (size) {
336 case 4:
337 return __xchg_u32_local(ptr, x);
338#ifdef CONFIG_PPC64
339 case 8:
340 return __xchg_u64_local(ptr, x);
341#endif
342 }
343 __xchg_called_with_bad_pointer();
344 return x;
345}
346#define xchg(ptr,x) \
347 ({ \
348 __typeof__(*(ptr)) _x_ = (x); \
349 (__typeof__(*(ptr))) __xchg((ptr), (unsigned long)_x_, sizeof(*(ptr))); \
350 })
351
352#define xchg_local(ptr,x) \
353 ({ \
354 __typeof__(*(ptr)) _x_ = (x); \
355 (__typeof__(*(ptr))) __xchg_local((ptr), \
356 (unsigned long)_x_, sizeof(*(ptr))); \
357 })
358
359/*
360 * Compare and exchange - if *p == old, set it to new,
361 * and return the old value of *p.
362 */
363#define __HAVE_ARCH_CMPXCHG 1
364
365static __always_inline unsigned long
366__cmpxchg_u32(volatile unsigned int *p, unsigned long old, unsigned long new)
367{
368 unsigned int prev;
369
370 __asm__ __volatile__ (
371 PPC_RELEASE_BARRIER
372"1: lwarx %0,0,%2 # __cmpxchg_u32\n\
373 cmpw 0,%0,%3\n\
374 bne- 2f\n"
375 PPC405_ERR77(0,%2)
376" stwcx. %4,0,%2\n\
377 bne- 1b"
378 PPC_ACQUIRE_BARRIER
379 "\n\
3802:"
381 : "=&r" (prev), "+m" (*p)
382 : "r" (p), "r" (old), "r" (new)
383 : "cc", "memory");
384
385 return prev;
386}
387
388static __always_inline unsigned long
389__cmpxchg_u32_local(volatile unsigned int *p, unsigned long old,
390 unsigned long new)
391{
392 unsigned int prev;
393
394 __asm__ __volatile__ (
395"1: lwarx %0,0,%2 # __cmpxchg_u32\n\
396 cmpw 0,%0,%3\n\
397 bne- 2f\n"
398 PPC405_ERR77(0,%2)
399" stwcx. %4,0,%2\n\
400 bne- 1b"
401 "\n\
4022:"
403 : "=&r" (prev), "+m" (*p)
404 : "r" (p), "r" (old), "r" (new)
405 : "cc", "memory");
406
407 return prev;
408}
409
410#ifdef CONFIG_PPC64
411static __always_inline unsigned long
412__cmpxchg_u64(volatile unsigned long *p, unsigned long old, unsigned long new)
413{
414 unsigned long prev;
415
416 __asm__ __volatile__ (
417 PPC_RELEASE_BARRIER
418"1: ldarx %0,0,%2 # __cmpxchg_u64\n\
419 cmpd 0,%0,%3\n\
420 bne- 2f\n\
421 stdcx. %4,0,%2\n\
422 bne- 1b"
423 PPC_ACQUIRE_BARRIER
424 "\n\
4252:"
426 : "=&r" (prev), "+m" (*p)
427 : "r" (p), "r" (old), "r" (new)
428 : "cc", "memory");
429
430 return prev;
431}
432
433static __always_inline unsigned long
434__cmpxchg_u64_local(volatile unsigned long *p, unsigned long old,
435 unsigned long new)
436{
437 unsigned long prev;
438
439 __asm__ __volatile__ (
440"1: ldarx %0,0,%2 # __cmpxchg_u64\n\
441 cmpd 0,%0,%3\n\
442 bne- 2f\n\
443 stdcx. %4,0,%2\n\
444 bne- 1b"
445 "\n\
4462:"
447 : "=&r" (prev), "+m" (*p)
448 : "r" (p), "r" (old), "r" (new)
449 : "cc", "memory");
450
451 return prev;
452}
453#endif
454
455/* This function doesn't exist, so you'll get a linker error
456 if something tries to do an invalid cmpxchg(). */
457extern void __cmpxchg_called_with_bad_pointer(void);
458
459static __always_inline unsigned long
460__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new,
461 unsigned int size)
462{
463 switch (size) {
464 case 4:
465 return __cmpxchg_u32(ptr, old, new);
466#ifdef CONFIG_PPC64
467 case 8:
468 return __cmpxchg_u64(ptr, old, new);
469#endif
470 }
471 __cmpxchg_called_with_bad_pointer();
472 return old;
473}
474
475static __always_inline unsigned long
476__cmpxchg_local(volatile void *ptr, unsigned long old, unsigned long new,
477 unsigned int size)
478{
479 switch (size) {
480 case 4:
481 return __cmpxchg_u32_local(ptr, old, new);
482#ifdef CONFIG_PPC64
483 case 8:
484 return __cmpxchg_u64_local(ptr, old, new);
485#endif
486 }
487 __cmpxchg_called_with_bad_pointer();
488 return old;
489}
490
491#define cmpxchg(ptr, o, n) \
492 ({ \
493 __typeof__(*(ptr)) _o_ = (o); \
494 __typeof__(*(ptr)) _n_ = (n); \
495 (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_, \
496 (unsigned long)_n_, sizeof(*(ptr))); \
497 })
498
499
500#define cmpxchg_local(ptr, o, n) \
501 ({ \
502 __typeof__(*(ptr)) _o_ = (o); \
503 __typeof__(*(ptr)) _n_ = (n); \
504 (__typeof__(*(ptr))) __cmpxchg_local((ptr), (unsigned long)_o_, \
505 (unsigned long)_n_, sizeof(*(ptr))); \
506 })
507
508#ifdef CONFIG_PPC64
509/*
510 * We handle most unaligned accesses in hardware. On the other hand
511 * unaligned DMA can be very expensive on some ppc64 IO chips (it does
512 * powers of 2 writes until it reaches sufficient alignment).
513 *
514 * Based on this we disable the IP header alignment in network drivers.
515 */
516#define NET_IP_ALIGN 0
517
518#define cmpxchg64(ptr, o, n) \
519 ({ \
520 BUILD_BUG_ON(sizeof(*(ptr)) != 8); \
521 cmpxchg((ptr), (o), (n)); \
522 })
523#define cmpxchg64_local(ptr, o, n) \
524 ({ \
525 BUILD_BUG_ON(sizeof(*(ptr)) != 8); \
526 cmpxchg_local((ptr), (o), (n)); \
527 })
528#else
529#include <asm-generic/cmpxchg-local.h>
530#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
531#endif
532
533extern unsigned long arch_align_stack(unsigned long sp);
534
535/* Used in very early kernel initialization. */
536extern unsigned long reloc_offset(void);
537extern unsigned long add_reloc_offset(unsigned long);
538extern void reloc_got2(unsigned long);
539
540#define PTRRELOC(x) ((typeof(x)) add_reloc_offset((unsigned long)(x)))
541
542extern struct dentry *powerpc_debugfs_root;
543
544#endif /* __KERNEL__ */
545#endif /* _ASM_POWERPC_SYSTEM_H */
diff --git a/arch/powerpc/include/asm/termbits.h b/arch/powerpc/include/asm/termbits.h
new file mode 100644
index 00000000000..549d700e18f
--- /dev/null
+++ b/arch/powerpc/include/asm/termbits.h
@@ -0,0 +1,210 @@
1#ifndef _ASM_POWERPC_TERMBITS_H
2#define _ASM_POWERPC_TERMBITS_H
3
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
11typedef unsigned char cc_t;
12typedef unsigned int speed_t;
13typedef unsigned int tcflag_t;
14
15/*
16 * termios type and macro definitions. Be careful about adding stuff
17 * to this file since it's used in GNU libc and there are strict rules
18 * concerning namespace pollution.
19 */
20
21#define NCCS 19
22struct termios {
23 tcflag_t c_iflag; /* input mode flags */
24 tcflag_t c_oflag; /* output mode flags */
25 tcflag_t c_cflag; /* control mode flags */
26 tcflag_t c_lflag; /* local mode flags */
27 cc_t c_cc[NCCS]; /* control characters */
28 cc_t c_line; /* line discipline (== c_cc[19]) */
29 speed_t c_ispeed; /* input speed */
30 speed_t c_ospeed; /* output speed */
31};
32
33/* For PowerPC the termios and ktermios are the same */
34
35struct ktermios {
36 tcflag_t c_iflag; /* input mode flags */
37 tcflag_t c_oflag; /* output mode flags */
38 tcflag_t c_cflag; /* control mode flags */
39 tcflag_t c_lflag; /* local mode flags */
40 cc_t c_cc[NCCS]; /* control characters */
41 cc_t c_line; /* line discipline (== c_cc[19]) */
42 speed_t c_ispeed; /* input speed */
43 speed_t c_ospeed; /* output speed */
44};
45
46/* c_cc characters */
47#define VINTR 0
48#define VQUIT 1
49#define VERASE 2
50#define VKILL 3
51#define VEOF 4
52#define VMIN 5
53#define VEOL 6
54#define VTIME 7
55#define VEOL2 8
56#define VSWTC 9
57#define VWERASE 10
58#define VREPRINT 11
59#define VSUSP 12
60#define VSTART 13
61#define VSTOP 14
62#define VLNEXT 15
63#define VDISCARD 16
64
65/* c_iflag bits */
66#define IGNBRK 0000001
67#define BRKINT 0000002
68#define IGNPAR 0000004
69#define PARMRK 0000010
70#define INPCK 0000020
71#define ISTRIP 0000040
72#define INLCR 0000100
73#define IGNCR 0000200
74#define ICRNL 0000400
75#define IXON 0001000
76#define IXOFF 0002000
77#define IXANY 0004000
78#define IUCLC 0010000
79#define IMAXBEL 0020000
80#define IUTF8 0040000
81
82/* c_oflag bits */
83#define OPOST 0000001
84#define ONLCR 0000002
85#define OLCUC 0000004
86
87#define OCRNL 0000010
88#define ONOCR 0000020
89#define ONLRET 0000040
90
91#define OFILL 00000100
92#define OFDEL 00000200
93#define NLDLY 00001400
94#define NL0 00000000
95#define NL1 00000400
96#define NL2 00001000
97#define NL3 00001400
98#define TABDLY 00006000
99#define TAB0 00000000
100#define TAB1 00002000
101#define TAB2 00004000
102#define TAB3 00006000
103#define XTABS 00006000 /* required by POSIX to == TAB3 */
104#define CRDLY 00030000
105#define CR0 00000000
106#define CR1 00010000
107#define CR2 00020000
108#define CR3 00030000
109#define FFDLY 00040000
110#define FF0 00000000
111#define FF1 00040000
112#define BSDLY 00100000
113#define BS0 00000000
114#define BS1 00100000
115#define VTDLY 00200000
116#define VT0 00000000
117#define VT1 00200000
118
119/* c_cflag bit meaning */
120#define CBAUD 0000377
121#define B0 0000000 /* hang up */
122#define B50 0000001
123#define B75 0000002
124#define B110 0000003
125#define B134 0000004
126#define B150 0000005
127#define B200 0000006
128#define B300 0000007
129#define B600 0000010
130#define B1200 0000011
131#define B1800 0000012
132#define B2400 0000013
133#define B4800 0000014
134#define B9600 0000015
135#define B19200 0000016
136#define B38400 0000017
137#define EXTA B19200
138#define EXTB B38400
139#define CBAUDEX 0000000
140#define B57600 00020
141#define B115200 00021
142#define B230400 00022
143#define B460800 00023
144#define B500000 00024
145#define B576000 00025
146#define B921600 00026
147#define B1000000 00027
148#define B1152000 00030
149#define B1500000 00031
150#define B2000000 00032
151#define B2500000 00033
152#define B3000000 00034
153#define B3500000 00035
154#define B4000000 00036
155#define BOTHER 00037
156
157#define CIBAUD 077600000
158#define IBSHIFT 16 /* Shift from CBAUD to CIBAUD */
159
160#define CSIZE 00001400
161#define CS5 00000000
162#define CS6 00000400
163#define CS7 00001000
164#define CS8 00001400
165
166#define CSTOPB 00002000
167#define CREAD 00004000
168#define PARENB 00010000
169#define PARODD 00020000
170#define HUPCL 00040000
171
172#define CLOCAL 00100000
173#define CMSPAR 010000000000 /* mark or space (stick) parity */
174#define CRTSCTS 020000000000 /* flow control */
175
176/* c_lflag bits */
177#define ISIG 0x00000080
178#define ICANON 0x00000100
179#define XCASE 0x00004000
180#define ECHO 0x00000008
181#define ECHOE 0x00000002
182#define ECHOK 0x00000004
183#define ECHONL 0x00000010
184#define NOFLSH 0x80000000
185#define TOSTOP 0x00400000
186#define ECHOCTL 0x00000040
187#define ECHOPRT 0x00000020
188#define ECHOKE 0x00000001
189#define FLUSHO 0x00800000
190#define PENDIN 0x20000000
191#define IEXTEN 0x00000400
192#define EXTPROC 0x10000000
193
194/* Values for the ACTION argument to `tcflow'. */
195#define TCOOFF 0
196#define TCOON 1
197#define TCIOFF 2
198#define TCION 3
199
200/* Values for the QUEUE_SELECTOR argument to `tcflush'. */
201#define TCIFLUSH 0
202#define TCOFLUSH 1
203#define TCIOFLUSH 2
204
205/* Values for the OPTIONAL_ACTIONS argument to `tcsetattr'. */
206#define TCSANOW 0
207#define TCSADRAIN 1
208#define TCSAFLUSH 2
209
210#endif /* _ASM_POWERPC_TERMBITS_H */
diff --git a/arch/powerpc/include/asm/ucontext.h b/arch/powerpc/include/asm/ucontext.h
new file mode 100644
index 00000000000..d9a4ddf0cc8
--- /dev/null
+++ b/arch/powerpc/include/asm/ucontext.h
@@ -0,0 +1,40 @@
1#ifndef _ASM_POWERPC_UCONTEXT_H
2#define _ASM_POWERPC_UCONTEXT_H
3
4#ifdef __powerpc64__
5#include <asm/sigcontext.h>
6#else
7#include <asm/elf.h>
8#endif
9#include <asm/signal.h>
10
11#ifndef __powerpc64__
12struct mcontext {
13 elf_gregset_t mc_gregs;
14 elf_fpregset_t mc_fregs;
15 unsigned long mc_pad[2];
16 elf_vrregset_t mc_vregs __attribute__((__aligned__(16)));
17};
18#endif
19
20struct ucontext {
21 unsigned long uc_flags;
22 struct ucontext __user *uc_link;
23 stack_t uc_stack;
24#ifndef __powerpc64__
25 int uc_pad[7];
26 struct mcontext __user *uc_regs;/* points to uc_mcontext field */
27#endif
28 sigset_t uc_sigmask;
29 /* glibc has 1024-bit signal masks, ours are 64-bit */
30#ifdef __powerpc64__
31 sigset_t __unused[15]; /* Allow for uc_sigmask growth */
32 struct sigcontext uc_mcontext; /* last for extensibility */
33#else
34 int uc_maskext[30];
35 int uc_pad2[3];
36 struct mcontext uc_mcontext;
37#endif
38};
39
40#endif /* _ASM_POWERPC_UCONTEXT_H */
diff --git a/arch/powerpc/kernel/cpu_setup_power7.S b/arch/powerpc/kernel/cpu_setup_power7.S
new file mode 100644
index 00000000000..76797c5105d
--- /dev/null
+++ b/arch/powerpc/kernel/cpu_setup_power7.S
@@ -0,0 +1,95 @@
1/*
2 * This file contains low level CPU setup functions.
3 * Copyright (C) 2003 Benjamin Herrenschmidt (benh@kernel.crashing.org)
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
12#include <asm/processor.h>
13#include <asm/page.h>
14#include <asm/cputable.h>
15#include <asm/ppc_asm.h>
16#include <asm/asm-offsets.h>
17#include <asm/cache.h>
18
19/* Entry: r3 = crap, r4 = ptr to cputable entry
20 *
21 * Note that we can be called twice for pseudo-PVRs
22 */
23_GLOBAL(__setup_cpu_power7)
24 mflr r11
25 bl __init_hvmode_206
26 mtlr r11
27 beqlr
28 li r0,0
29 mtspr SPRN_LPID,r0
30 bl __init_LPCR
31 bl __init_TLB
32 mtlr r11
33 blr
34
35_GLOBAL(__restore_cpu_power7)
36 mflr r11
37 mfmsr r3
38 rldicl. r0,r3,4,63
39 beqlr
40 li r0,0
41 mtspr SPRN_LPID,r0
42 bl __init_LPCR
43 bl __init_TLB
44 mtlr r11
45 blr
46
47__init_hvmode_206:
48 /* Disable CPU_FTR_HVMODE and exit if MSR:HV is not set */
49 mfmsr r3
50 rldicl. r0,r3,4,63
51 bnelr
52 ld r5,CPU_SPEC_FEATURES(r4)
53 LOAD_REG_IMMEDIATE(r6,CPU_FTR_HVMODE)
54 xor r5,r5,r6
55 std r5,CPU_SPEC_FEATURES(r4)
56 blr
57
58__init_LPCR:
59 /* Setup a sane LPCR:
60 *
61 * LPES = 0b01 (HSRR0/1 used for 0x500)
62 * PECE = 0b111
63 * DPFD = 4
64 * HDICE = 0
65 * VC = 0b100 (VPM0=1, VPM1=0, ISL=0)
66 * VRMASD = 0b10000 (L=1, LP=00)
67 *
68 * Other bits untouched for now
69 */
70 mfspr r3,SPRN_LPCR
71 li r5,1
72 rldimi r3,r5, LPCR_LPES_SH, 64-LPCR_LPES_SH-2
73 ori r3,r3,(LPCR_PECE0|LPCR_PECE1|LPCR_PECE2)
74 li r5,4
75 rldimi r3,r5, LPCR_DPFD_SH, 64-LPCR_DPFD_SH-3
76 clrrdi r3,r3,1 /* clear HDICE */
77 li r5,4
78 rldimi r3,r5, LPCR_VC_SH, 0
79 li r5,0x10
80 rldimi r3,r5, LPCR_VRMASD_SH, 64-LPCR_VRMASD_SH-5
81 mtspr SPRN_LPCR,r3
82 isync
83 blr
84
85__init_TLB:
86 /* Clear the TLB */
87 li r6,128
88 mtctr r6
89 li r7,0xc00 /* IS field = 0b11 */
90 ptesync
912: tlbiel r7
92 addi r7,r7,0x1000
93 bdnz 2b
94 ptesync
951: blr
diff --git a/arch/powerpc/kernel/e500-pmu.c b/arch/powerpc/kernel/e500-pmu.c
new file mode 100644
index 00000000000..cb2e2949c8d
--- /dev/null
+++ b/arch/powerpc/kernel/e500-pmu.c
@@ -0,0 +1,134 @@
1/*
2 * Performance counter support for e500 family processors.
3 *
4 * Copyright 2008-2009 Paul Mackerras, IBM Corporation.
5 * Copyright 2010 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; either version
10 * 2 of the License, or (at your option) any later version.
11 */
12#include <linux/string.h>
13#include <linux/perf_event.h>
14#include <asm/reg.h>
15#include <asm/cputable.h>
16
17/*
18 * Map of generic hardware event types to hardware events
19 * Zero if unsupported
20 */
21static int e500_generic_events[] = {
22 [PERF_COUNT_HW_CPU_CYCLES] = 1,
23 [PERF_COUNT_HW_INSTRUCTIONS] = 2,
24 [PERF_COUNT_HW_CACHE_MISSES] = 41, /* Data L1 cache reloads */
25 [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 12,
26 [PERF_COUNT_HW_BRANCH_MISSES] = 15,
27};
28
29#define C(x) PERF_COUNT_HW_CACHE_##x
30
31/*
32 * Table of generalized cache-related events.
33 * 0 means not supported, -1 means nonsensical, other values
34 * are event codes.
35 */
36static int e500_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
37 /*
38 * D-cache misses are not split into read/write/prefetch;
39 * use raw event 41.
40 */
41 [C(L1D)] = { /* RESULT_ACCESS RESULT_MISS */
42 [C(OP_READ)] = { 27, 0 },
43 [C(OP_WRITE)] = { 28, 0 },
44 [C(OP_PREFETCH)] = { 29, 0 },
45 },
46 [C(L1I)] = { /* RESULT_ACCESS RESULT_MISS */
47 [C(OP_READ)] = { 2, 60 },
48 [C(OP_WRITE)] = { -1, -1 },
49 [C(OP_PREFETCH)] = { 0, 0 },
50 },
51 /*
52 * Assuming LL means L2, it's not a good match for this model.
53 * It allocates only on L1 castout or explicit prefetch, and
54 * does not have separate read/write events (but it does have
55 * separate instruction/data events).
56 */
57 [C(LL)] = { /* RESULT_ACCESS RESULT_MISS */
58 [C(OP_READ)] = { 0, 0 },
59 [C(OP_WRITE)] = { 0, 0 },
60 [C(OP_PREFETCH)] = { 0, 0 },
61 },
62 /*
63 * There are data/instruction MMU misses, but that's a miss on
64 * the chip's internal level-one TLB which is probably not
65 * what the user wants. Instead, unified level-two TLB misses
66 * are reported here.
67 */
68 [C(DTLB)] = { /* RESULT_ACCESS RESULT_MISS */
69 [C(OP_READ)] = { 26, 66 },
70 [C(OP_WRITE)] = { -1, -1 },
71 [C(OP_PREFETCH)] = { -1, -1 },
72 },
73 [C(BPU)] = { /* RESULT_ACCESS RESULT_MISS */
74 [C(OP_READ)] = { 12, 15 },
75 [C(OP_WRITE)] = { -1, -1 },
76 [C(OP_PREFETCH)] = { -1, -1 },
77 },
78 [C(NODE)] = { /* RESULT_ACCESS RESULT_MISS */
79 [C(OP_READ)] = { -1, -1 },
80 [C(OP_WRITE)] = { -1, -1 },
81 [C(OP_PREFETCH)] = { -1, -1 },
82 },
83};
84
85static int num_events = 128;
86
87/* Upper half of event id is PMLCb, for threshold events */
88static u64 e500_xlate_event(u64 event_id)
89{
90 u32 event_low = (u32)event_id;
91 u64 ret;
92
93 if (event_low >= num_events)
94 return 0;
95
96 ret = FSL_EMB_EVENT_VALID;
97
98 if (event_low >= 76 && event_low <= 81) {
99 ret |= FSL_EMB_EVENT_RESTRICTED;
100 ret |= event_id &
101 (FSL_EMB_EVENT_THRESHMUL | FSL_EMB_EVENT_THRESH);
102 } else if (event_id &
103 (FSL_EMB_EVENT_THRESHMUL | FSL_EMB_EVENT_THRESH)) {
104 /* Threshold requested on non-threshold event */
105 return 0;
106 }
107
108 return ret;
109}
110
111static struct fsl_emb_pmu e500_pmu = {
112 .name = "e500 family",
113 .n_counter = 4,
114 .n_restricted = 2,
115 .xlate_event = e500_xlate_event,
116 .n_generic = ARRAY_SIZE(e500_generic_events),
117 .generic_events = e500_generic_events,
118 .cache_events = &e500_cache_events,
119};
120
121static int init_e500_pmu(void)
122{
123 if (!cur_cpu_spec->oprofile_cpu_type)
124 return -ENODEV;
125
126 if (!strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc/e500mc"))
127 num_events = 256;
128 else if (strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc/e500"))
129 return -ENODEV;
130
131 return register_fsl_emb_pmu(&e500_pmu);
132}
133
134early_initcall(init_e500_pmu);
diff --git a/arch/powerpc/kernel/init_task.c b/arch/powerpc/kernel/init_task.c
new file mode 100644
index 00000000000..2375b7eb1c7
--- /dev/null
+++ b/arch/powerpc/kernel/init_task.c
@@ -0,0 +1,29 @@
1#include <linux/mm.h>
2#include <linux/module.h>
3#include <linux/sched.h>
4#include <linux/init.h>
5#include <linux/init_task.h>
6#include <linux/fs.h>
7#include <linux/mqueue.h>
8#include <asm/uaccess.h>
9
10static struct signal_struct init_signals = INIT_SIGNALS(init_signals);
11static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand);
12/*
13 * Initial thread structure.
14 *
15 * We need to make sure that this is 16384-byte aligned due to the
16 * way process stacks are handled. This is done by having a special
17 * "init_task" linker map entry..
18 */
19union thread_union init_thread_union __init_task_data =
20 { INIT_THREAD_INFO(init_task) };
21
22/*
23 * Initial task structure.
24 *
25 * All other task structs will be allocated on slabs in fork.c
26 */
27struct task_struct init_task = INIT_TASK(init_task);
28
29EXPORT_SYMBOL(init_task);
diff --git a/arch/powerpc/kernel/mpc7450-pmu.c b/arch/powerpc/kernel/mpc7450-pmu.c
new file mode 100644
index 00000000000..fe21b515ca4
--- /dev/null
+++ b/arch/powerpc/kernel/mpc7450-pmu.c
@@ -0,0 +1,422 @@
1/*
2 * Performance counter support for MPC7450-family processors.
3 *
4 * Copyright 2008-2009 Paul Mackerras, IBM Corporation.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11#include <linux/string.h>
12#include <linux/perf_event.h>
13#include <asm/reg.h>
14#include <asm/cputable.h>
15
16#define N_COUNTER 6 /* Number of hardware counters */
17#define MAX_ALT 3 /* Maximum number of event alternative codes */
18
19/*
20 * Bits in event code for MPC7450 family
21 */
22#define PM_THRMULT_MSKS 0x40000
23#define PM_THRESH_SH 12
24#define PM_THRESH_MSK 0x3f
25#define PM_PMC_SH 8
26#define PM_PMC_MSK 7
27#define PM_PMCSEL_MSK 0x7f
28
29/*
30 * Classify events according to how specific their PMC requirements are.
31 * Result is:
32 * 0: can go on any PMC
33 * 1: can go on PMCs 1-4
34 * 2: can go on PMCs 1,2,4
35 * 3: can go on PMCs 1 or 2
36 * 4: can only go on one PMC
37 * -1: event code is invalid
38 */
39#define N_CLASSES 5
40
41static int mpc7450_classify_event(u32 event)
42{
43 int pmc;
44
45 pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
46 if (pmc) {
47 if (pmc > N_COUNTER)
48 return -1;
49 return 4;
50 }
51 event &= PM_PMCSEL_MSK;
52 if (event <= 1)
53 return 0;
54 if (event <= 7)
55 return 1;
56 if (event <= 13)
57 return 2;
58 if (event <= 22)
59 return 3;
60 return -1;
61}
62
63/*
64 * Events using threshold and possible threshold scale:
65 * code scale? name
66 * 11e N PM_INSTQ_EXCEED_CYC
67 * 11f N PM_ALTV_IQ_EXCEED_CYC
68 * 128 Y PM_DTLB_SEARCH_EXCEED_CYC
69 * 12b Y PM_LD_MISS_EXCEED_L1_CYC
70 * 220 N PM_CQ_EXCEED_CYC
71 * 30c N PM_GPR_RB_EXCEED_CYC
72 * 30d ? PM_FPR_IQ_EXCEED_CYC ?
73 * 311 Y PM_ITLB_SEARCH_EXCEED
74 * 410 N PM_GPR_IQ_EXCEED_CYC
75 */
76
77/*
78 * Return use of threshold and threshold scale bits:
79 * 0 = uses neither, 1 = uses threshold, 2 = uses both
80 */
81static int mpc7450_threshold_use(u32 event)
82{
83 int pmc, sel;
84
85 pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
86 sel = event & PM_PMCSEL_MSK;
87 switch (pmc) {
88 case 1:
89 if (sel == 0x1e || sel == 0x1f)
90 return 1;
91 if (sel == 0x28 || sel == 0x2b)
92 return 2;
93 break;
94 case 2:
95 if (sel == 0x20)
96 return 1;
97 break;
98 case 3:
99 if (sel == 0xc || sel == 0xd)
100 return 1;
101 if (sel == 0x11)
102 return 2;
103 break;
104 case 4:
105 if (sel == 0x10)
106 return 1;
107 break;
108 }
109 return 0;
110}
111
112/*
113 * Layout of constraint bits:
114 * 33222222222211111111110000000000
115 * 10987654321098765432109876543210
116 * |< >< > < > < ><><><><><><>
117 * TS TV G4 G3 G2P6P5P4P3P2P1
118 *
119 * P1 - P6
120 * 0 - 11: Count of events needing PMC1 .. PMC6
121 *
122 * G2
123 * 12 - 14: Count of events needing PMC1 or PMC2
124 *
125 * G3
126 * 16 - 18: Count of events needing PMC1, PMC2 or PMC4
127 *
128 * G4
129 * 20 - 23: Count of events needing PMC1, PMC2, PMC3 or PMC4
130 *
131 * TV
132 * 24 - 29: Threshold value requested
133 *
134 * TS
135 * 30: Threshold scale value requested
136 */
137
138static u32 pmcbits[N_COUNTER][2] = {
139 { 0x00844002, 0x00111001 }, /* PMC1 mask, value: P1,G2,G3,G4 */
140 { 0x00844008, 0x00111004 }, /* PMC2: P2,G2,G3,G4 */
141 { 0x00800020, 0x00100010 }, /* PMC3: P3,G4 */
142 { 0x00840080, 0x00110040 }, /* PMC4: P4,G3,G4 */
143 { 0x00000200, 0x00000100 }, /* PMC5: P5 */
144 { 0x00000800, 0x00000400 } /* PMC6: P6 */
145};
146
147static u32 classbits[N_CLASSES - 1][2] = {
148 { 0x00000000, 0x00000000 }, /* class 0: no constraint */
149 { 0x00800000, 0x00100000 }, /* class 1: G4 */
150 { 0x00040000, 0x00010000 }, /* class 2: G3 */
151 { 0x00004000, 0x00001000 }, /* class 3: G2 */
152};
153
154static int mpc7450_get_constraint(u64 event, unsigned long *maskp,
155 unsigned long *valp)
156{
157 int pmc, class;
158 u32 mask, value;
159 int thresh, tuse;
160
161 class = mpc7450_classify_event(event);
162 if (class < 0)
163 return -1;
164 if (class == 4) {
165 pmc = ((unsigned int)event >> PM_PMC_SH) & PM_PMC_MSK;
166 mask = pmcbits[pmc - 1][0];
167 value = pmcbits[pmc - 1][1];
168 } else {
169 mask = classbits[class][0];
170 value = classbits[class][1];
171 }
172
173 tuse = mpc7450_threshold_use(event);
174 if (tuse) {
175 thresh = ((unsigned int)event >> PM_THRESH_SH) & PM_THRESH_MSK;
176 mask |= 0x3f << 24;
177 value |= thresh << 24;
178 if (tuse == 2) {
179 mask |= 0x40000000;
180 if ((unsigned int)event & PM_THRMULT_MSKS)
181 value |= 0x40000000;
182 }
183 }
184
185 *maskp = mask;
186 *valp = value;
187 return 0;
188}
189
190static const unsigned int event_alternatives[][MAX_ALT] = {
191 { 0x217, 0x317 }, /* PM_L1_DCACHE_MISS */
192 { 0x418, 0x50f, 0x60f }, /* PM_SNOOP_RETRY */
193 { 0x502, 0x602 }, /* PM_L2_HIT */
194 { 0x503, 0x603 }, /* PM_L3_HIT */
195 { 0x504, 0x604 }, /* PM_L2_ICACHE_MISS */
196 { 0x505, 0x605 }, /* PM_L3_ICACHE_MISS */
197 { 0x506, 0x606 }, /* PM_L2_DCACHE_MISS */
198 { 0x507, 0x607 }, /* PM_L3_DCACHE_MISS */
199 { 0x50a, 0x623 }, /* PM_LD_HIT_L3 */
200 { 0x50b, 0x624 }, /* PM_ST_HIT_L3 */
201 { 0x50d, 0x60d }, /* PM_L2_TOUCH_HIT */
202 { 0x50e, 0x60e }, /* PM_L3_TOUCH_HIT */
203 { 0x512, 0x612 }, /* PM_INT_LOCAL */
204 { 0x513, 0x61d }, /* PM_L2_MISS */
205 { 0x514, 0x61e }, /* PM_L3_MISS */
206};
207
208/*
209 * Scan the alternatives table for a match and return the
210 * index into the alternatives table if found, else -1.
211 */
212static int find_alternative(u32 event)
213{
214 int i, j;
215
216 for (i = 0; i < ARRAY_SIZE(event_alternatives); ++i) {
217 if (event < event_alternatives[i][0])
218 break;
219 for (j = 0; j < MAX_ALT && event_alternatives[i][j]; ++j)
220 if (event == event_alternatives[i][j])
221 return i;
222 }
223 return -1;
224}
225
226static int mpc7450_get_alternatives(u64 event, unsigned int flags, u64 alt[])
227{
228 int i, j, nalt = 1;
229 u32 ae;
230
231 alt[0] = event;
232 nalt = 1;
233 i = find_alternative((u32)event);
234 if (i >= 0) {
235 for (j = 0; j < MAX_ALT; ++j) {
236 ae = event_alternatives[i][j];
237 if (ae && ae != (u32)event)
238 alt[nalt++] = ae;
239 }
240 }
241 return nalt;
242}
243
244/*
245 * Bitmaps of which PMCs each class can use for classes 0 - 3.
246 * Bit i is set if PMC i+1 is usable.
247 */
248static const u8 classmap[N_CLASSES] = {
249 0x3f, 0x0f, 0x0b, 0x03, 0
250};
251
252/* Bit position and width of each PMCSEL field */
253static const int pmcsel_shift[N_COUNTER] = {
254 6, 0, 27, 22, 17, 11
255};
256static const u32 pmcsel_mask[N_COUNTER] = {
257 0x7f, 0x3f, 0x1f, 0x1f, 0x1f, 0x3f
258};
259
260/*
261 * Compute MMCR0/1/2 values for a set of events.
262 */
263static int mpc7450_compute_mmcr(u64 event[], int n_ev,
264 unsigned int hwc[], unsigned long mmcr[])
265{
266 u8 event_index[N_CLASSES][N_COUNTER];
267 int n_classevent[N_CLASSES];
268 int i, j, class, tuse;
269 u32 pmc_inuse = 0, pmc_avail;
270 u32 mmcr0 = 0, mmcr1 = 0, mmcr2 = 0;
271 u32 ev, pmc, thresh;
272
273 if (n_ev > N_COUNTER)
274 return -1;
275
276 /* First pass: count usage in each class */
277 for (i = 0; i < N_CLASSES; ++i)
278 n_classevent[i] = 0;
279 for (i = 0; i < n_ev; ++i) {
280 class = mpc7450_classify_event(event[i]);
281 if (class < 0)
282 return -1;
283 j = n_classevent[class]++;
284 event_index[class][j] = i;
285 }
286
287 /* Second pass: allocate PMCs from most specific event to least */
288 for (class = N_CLASSES - 1; class >= 0; --class) {
289 for (i = 0; i < n_classevent[class]; ++i) {
290 ev = event[event_index[class][i]];
291 if (class == 4) {
292 pmc = (ev >> PM_PMC_SH) & PM_PMC_MSK;
293 if (pmc_inuse & (1 << (pmc - 1)))
294 return -1;
295 } else {
296 /* Find a suitable PMC */
297 pmc_avail = classmap[class] & ~pmc_inuse;
298 if (!pmc_avail)
299 return -1;
300 pmc = ffs(pmc_avail);
301 }
302 pmc_inuse |= 1 << (pmc - 1);
303
304 tuse = mpc7450_threshold_use(ev);
305 if (tuse) {
306 thresh = (ev >> PM_THRESH_SH) & PM_THRESH_MSK;
307 mmcr0 |= thresh << 16;
308 if (tuse == 2 && (ev & PM_THRMULT_MSKS))
309 mmcr2 = 0x80000000;
310 }
311 ev &= pmcsel_mask[pmc - 1];
312 ev <<= pmcsel_shift[pmc - 1];
313 if (pmc <= 2)
314 mmcr0 |= ev;
315 else
316 mmcr1 |= ev;
317 hwc[event_index[class][i]] = pmc - 1;
318 }
319 }
320
321 if (pmc_inuse & 1)
322 mmcr0 |= MMCR0_PMC1CE;
323 if (pmc_inuse & 0x3e)
324 mmcr0 |= MMCR0_PMCnCE;
325
326 /* Return MMCRx values */
327 mmcr[0] = mmcr0;
328 mmcr[1] = mmcr1;
329 mmcr[2] = mmcr2;
330 return 0;
331}
332
333/*
334 * Disable counting by a PMC.
335 * Note that the pmc argument is 0-based here, not 1-based.
336 */
337static void mpc7450_disable_pmc(unsigned int pmc, unsigned long mmcr[])
338{
339 if (pmc <= 1)
340 mmcr[0] &= ~(pmcsel_mask[pmc] << pmcsel_shift[pmc]);
341 else
342 mmcr[1] &= ~(pmcsel_mask[pmc] << pmcsel_shift[pmc]);
343}
344
345static int mpc7450_generic_events[] = {
346 [PERF_COUNT_HW_CPU_CYCLES] = 1,
347 [PERF_COUNT_HW_INSTRUCTIONS] = 2,
348 [PERF_COUNT_HW_CACHE_MISSES] = 0x217, /* PM_L1_DCACHE_MISS */
349 [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x122, /* PM_BR_CMPL */
350 [PERF_COUNT_HW_BRANCH_MISSES] = 0x41c, /* PM_BR_MPRED */
351};
352
353#define C(x) PERF_COUNT_HW_CACHE_##x
354
355/*
356 * Table of generalized cache-related events.
357 * 0 means not supported, -1 means nonsensical, other values
358 * are event codes.
359 */
360static int mpc7450_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
361 [C(L1D)] = { /* RESULT_ACCESS RESULT_MISS */
362 [C(OP_READ)] = { 0, 0x225 },
363 [C(OP_WRITE)] = { 0, 0x227 },
364 [C(OP_PREFETCH)] = { 0, 0 },
365 },
366 [C(L1I)] = { /* RESULT_ACCESS RESULT_MISS */
367 [C(OP_READ)] = { 0x129, 0x115 },
368 [C(OP_WRITE)] = { -1, -1 },
369 [C(OP_PREFETCH)] = { 0x634, 0 },
370 },
371 [C(LL)] = { /* RESULT_ACCESS RESULT_MISS */
372 [C(OP_READ)] = { 0, 0 },
373 [C(OP_WRITE)] = { 0, 0 },
374 [C(OP_PREFETCH)] = { 0, 0 },
375 },
376 [C(DTLB)] = { /* RESULT_ACCESS RESULT_MISS */
377 [C(OP_READ)] = { 0, 0x312 },
378 [C(OP_WRITE)] = { -1, -1 },
379 [C(OP_PREFETCH)] = { -1, -1 },
380 },
381 [C(ITLB)] = { /* RESULT_ACCESS RESULT_MISS */
382 [C(OP_READ)] = { 0, 0x223 },
383 [C(OP_WRITE)] = { -1, -1 },
384 [C(OP_PREFETCH)] = { -1, -1 },
385 },
386 [C(BPU)] = { /* RESULT_ACCESS RESULT_MISS */
387 [C(OP_READ)] = { 0x122, 0x41c },
388 [C(OP_WRITE)] = { -1, -1 },
389 [C(OP_PREFETCH)] = { -1, -1 },
390 },
391 [C(NODE)] = { /* RESULT_ACCESS RESULT_MISS */
392 [C(OP_READ)] = { -1, -1 },
393 [C(OP_WRITE)] = { -1, -1 },
394 [C(OP_PREFETCH)] = { -1, -1 },
395 },
396};
397
398struct power_pmu mpc7450_pmu = {
399 .name = "MPC7450 family",
400 .n_counter = N_COUNTER,
401 .max_alternatives = MAX_ALT,
402 .add_fields = 0x00111555ul,
403 .test_adder = 0x00301000ul,
404 .compute_mmcr = mpc7450_compute_mmcr,
405 .get_constraint = mpc7450_get_constraint,
406 .get_alternatives = mpc7450_get_alternatives,
407 .disable_pmc = mpc7450_disable_pmc,
408 .n_generic = ARRAY_SIZE(mpc7450_generic_events),
409 .generic_events = mpc7450_generic_events,
410 .cache_events = &mpc7450_cache_events,
411};
412
413static int __init init_mpc7450_pmu(void)
414{
415 if (!cur_cpu_spec->oprofile_cpu_type ||
416 strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc/7450"))
417 return -ENODEV;
418
419 return register_power_pmu(&mpc7450_pmu);
420}
421
422early_initcall(init_mpc7450_pmu);
diff --git a/arch/powerpc/kernel/perf_callchain.c b/arch/powerpc/kernel/perf_callchain.c
new file mode 100644
index 00000000000..564c1d8bdb5
--- /dev/null
+++ b/arch/powerpc/kernel/perf_callchain.c
@@ -0,0 +1,492 @@
1/*
2 * Performance counter callchain support - powerpc architecture code
3 *
4 * Copyright © 2009 Paul Mackerras, IBM Corporation.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11#include <linux/kernel.h>
12#include <linux/sched.h>
13#include <linux/perf_event.h>
14#include <linux/percpu.h>
15#include <linux/uaccess.h>
16#include <linux/mm.h>
17#include <asm/ptrace.h>
18#include <asm/pgtable.h>
19#include <asm/sigcontext.h>
20#include <asm/ucontext.h>
21#include <asm/vdso.h>
22#ifdef CONFIG_PPC64
23#include "ppc32.h"
24#endif
25
26
27/*
28 * Is sp valid as the address of the next kernel stack frame after prev_sp?
29 * The next frame may be in a different stack area but should not go
30 * back down in the same stack area.
31 */
32static int valid_next_sp(unsigned long sp, unsigned long prev_sp)
33{
34 if (sp & 0xf)
35 return 0; /* must be 16-byte aligned */
36 if (!validate_sp(sp, current, STACK_FRAME_OVERHEAD))
37 return 0;
38 if (sp >= prev_sp + STACK_FRAME_OVERHEAD)
39 return 1;
40 /*
41 * sp could decrease when we jump off an interrupt stack
42 * back to the regular process stack.
43 */
44 if ((sp & ~(THREAD_SIZE - 1)) != (prev_sp & ~(THREAD_SIZE - 1)))
45 return 1;
46 return 0;
47}
48
49void
50perf_callchain_kernel(struct perf_callchain_entry *entry, struct pt_regs *regs)
51{
52 unsigned long sp, next_sp;
53 unsigned long next_ip;
54 unsigned long lr;
55 long level = 0;
56 unsigned long *fp;
57
58 lr = regs->link;
59 sp = regs->gpr[1];
60 perf_callchain_store(entry, regs->nip);
61
62 if (!validate_sp(sp, current, STACK_FRAME_OVERHEAD))
63 return;
64
65 for (;;) {
66 fp = (unsigned long *) sp;
67 next_sp = fp[0];
68
69 if (next_sp == sp + STACK_INT_FRAME_SIZE &&
70 fp[STACK_FRAME_MARKER] == STACK_FRAME_REGS_MARKER) {
71 /*
72 * This looks like an interrupt frame for an
73 * interrupt that occurred in the kernel
74 */
75 regs = (struct pt_regs *)(sp + STACK_FRAME_OVERHEAD);
76 next_ip = regs->nip;
77 lr = regs->link;
78 level = 0;
79 perf_callchain_store(entry, PERF_CONTEXT_KERNEL);
80
81 } else {
82 if (level == 0)
83 next_ip = lr;
84 else
85 next_ip = fp[STACK_FRAME_LR_SAVE];
86
87 /*
88 * We can't tell which of the first two addresses
89 * we get are valid, but we can filter out the
90 * obviously bogus ones here. We replace them
91 * with 0 rather than removing them entirely so
92 * that userspace can tell which is which.
93 */
94 if ((level == 1 && next_ip == lr) ||
95 (level <= 1 && !kernel_text_address(next_ip)))
96 next_ip = 0;
97
98 ++level;
99 }
100
101 perf_callchain_store(entry, next_ip);
102 if (!valid_next_sp(next_sp, sp))
103 return;
104 sp = next_sp;
105 }
106}
107
108#ifdef CONFIG_PPC64
109/*
110 * On 64-bit we don't want to invoke hash_page on user addresses from
111 * interrupt context, so if the access faults, we read the page tables
112 * to find which page (if any) is mapped and access it directly.
113 */
114static int read_user_stack_slow(void __user *ptr, void *ret, int nb)
115{
116 pgd_t *pgdir;
117 pte_t *ptep, pte;
118 unsigned shift;
119 unsigned long addr = (unsigned long) ptr;
120 unsigned long offset;
121 unsigned long pfn;
122 void *kaddr;
123
124 pgdir = current->mm->pgd;
125 if (!pgdir)
126 return -EFAULT;
127
128 ptep = find_linux_pte_or_hugepte(pgdir, addr, &shift);
129 if (!shift)
130 shift = PAGE_SHIFT;
131
132 /* align address to page boundary */
133 offset = addr & ((1UL << shift) - 1);
134 addr -= offset;
135
136 if (ptep == NULL)
137 return -EFAULT;
138 pte = *ptep;
139 if (!pte_present(pte) || !(pte_val(pte) & _PAGE_USER))
140 return -EFAULT;
141 pfn = pte_pfn(pte);
142 if (!page_is_ram(pfn))
143 return -EFAULT;
144
145 /* no highmem to worry about here */
146 kaddr = pfn_to_kaddr(pfn);
147 memcpy(ret, kaddr + offset, nb);
148 return 0;
149}
150
151static int read_user_stack_64(unsigned long __user *ptr, unsigned long *ret)
152{
153 if ((unsigned long)ptr > TASK_SIZE - sizeof(unsigned long) ||
154 ((unsigned long)ptr & 7))
155 return -EFAULT;
156
157 pagefault_disable();
158 if (!__get_user_inatomic(*ret, ptr)) {
159 pagefault_enable();
160 return 0;
161 }
162 pagefault_enable();
163
164 return read_user_stack_slow(ptr, ret, 8);
165}
166
167static int read_user_stack_32(unsigned int __user *ptr, unsigned int *ret)
168{
169 if ((unsigned long)ptr > TASK_SIZE - sizeof(unsigned int) ||
170 ((unsigned long)ptr & 3))
171 return -EFAULT;
172
173 pagefault_disable();
174 if (!__get_user_inatomic(*ret, ptr)) {
175 pagefault_enable();
176 return 0;
177 }
178 pagefault_enable();
179
180 return read_user_stack_slow(ptr, ret, 4);
181}
182
183static inline int valid_user_sp(unsigned long sp, int is_64)
184{
185 if (!sp || (sp & 7) || sp > (is_64 ? TASK_SIZE : 0x100000000UL) - 32)
186 return 0;
187 return 1;
188}
189
190/*
191 * 64-bit user processes use the same stack frame for RT and non-RT signals.
192 */
193struct signal_frame_64 {
194 char dummy[__SIGNAL_FRAMESIZE];
195 struct ucontext uc;
196 unsigned long unused[2];
197 unsigned int tramp[6];
198 struct siginfo *pinfo;
199 void *puc;
200 struct siginfo info;
201 char abigap[288];
202};
203
204static int is_sigreturn_64_address(unsigned long nip, unsigned long fp)
205{
206 if (nip == fp + offsetof(struct signal_frame_64, tramp))
207 return 1;
208 if (vdso64_rt_sigtramp && current->mm->context.vdso_base &&
209 nip == current->mm->context.vdso_base + vdso64_rt_sigtramp)
210 return 1;
211 return 0;
212}
213
214/*
215 * Do some sanity checking on the signal frame pointed to by sp.
216 * We check the pinfo and puc pointers in the frame.
217 */
218static int sane_signal_64_frame(unsigned long sp)
219{
220 struct signal_frame_64 __user *sf;
221 unsigned long pinfo, puc;
222
223 sf = (struct signal_frame_64 __user *) sp;
224 if (read_user_stack_64((unsigned long __user *) &sf->pinfo, &pinfo) ||
225 read_user_stack_64((unsigned long __user *) &sf->puc, &puc))
226 return 0;
227 return pinfo == (unsigned long) &sf->info &&
228 puc == (unsigned long) &sf->uc;
229}
230
231static void perf_callchain_user_64(struct perf_callchain_entry *entry,
232 struct pt_regs *regs)
233{
234 unsigned long sp, next_sp;
235 unsigned long next_ip;
236 unsigned long lr;
237 long level = 0;
238 struct signal_frame_64 __user *sigframe;
239 unsigned long __user *fp, *uregs;
240
241 next_ip = regs->nip;
242 lr = regs->link;
243 sp = regs->gpr[1];
244 perf_callchain_store(entry, next_ip);
245
246 for (;;) {
247 fp = (unsigned long __user *) sp;
248 if (!valid_user_sp(sp, 1) || read_user_stack_64(fp, &next_sp))
249 return;
250 if (level > 0 && read_user_stack_64(&fp[2], &next_ip))
251 return;
252
253 /*
254 * Note: the next_sp - sp >= signal frame size check
255 * is true when next_sp < sp, which can happen when
256 * transitioning from an alternate signal stack to the
257 * normal stack.
258 */
259 if (next_sp - sp >= sizeof(struct signal_frame_64) &&
260 (is_sigreturn_64_address(next_ip, sp) ||
261 (level <= 1 && is_sigreturn_64_address(lr, sp))) &&
262 sane_signal_64_frame(sp)) {
263 /*
264 * This looks like an signal frame
265 */
266 sigframe = (struct signal_frame_64 __user *) sp;
267 uregs = sigframe->uc.uc_mcontext.gp_regs;
268 if (read_user_stack_64(&uregs[PT_NIP], &next_ip) ||
269 read_user_stack_64(&uregs[PT_LNK], &lr) ||
270 read_user_stack_64(&uregs[PT_R1], &sp))
271 return;
272 level = 0;
273 perf_callchain_store(entry, PERF_CONTEXT_USER);
274 perf_callchain_store(entry, next_ip);
275 continue;
276 }
277
278 if (level == 0)
279 next_ip = lr;
280 perf_callchain_store(entry, next_ip);
281 ++level;
282 sp = next_sp;
283 }
284}
285
286static inline int current_is_64bit(void)
287{
288 /*
289 * We can't use test_thread_flag() here because we may be on an
290 * interrupt stack, and the thread flags don't get copied over
291 * from the thread_info on the main stack to the interrupt stack.
292 */
293 return !test_ti_thread_flag(task_thread_info(current), TIF_32BIT);
294}
295
296#else /* CONFIG_PPC64 */
297/*
298 * On 32-bit we just access the address and let hash_page create a
299 * HPTE if necessary, so there is no need to fall back to reading
300 * the page tables. Since this is called at interrupt level,
301 * do_page_fault() won't treat a DSI as a page fault.
302 */
303static int read_user_stack_32(unsigned int __user *ptr, unsigned int *ret)
304{
305 int rc;
306
307 if ((unsigned long)ptr > TASK_SIZE - sizeof(unsigned int) ||
308 ((unsigned long)ptr & 3))
309 return -EFAULT;
310
311 pagefault_disable();
312 rc = __get_user_inatomic(*ret, ptr);
313 pagefault_enable();
314
315 return rc;
316}
317
318static inline void perf_callchain_user_64(struct perf_callchain_entry *entry,
319 struct pt_regs *regs)
320{
321}
322
323static inline int current_is_64bit(void)
324{
325 return 0;
326}
327
328static inline int valid_user_sp(unsigned long sp, int is_64)
329{
330 if (!sp || (sp & 7) || sp > TASK_SIZE - 32)
331 return 0;
332 return 1;
333}
334
335#define __SIGNAL_FRAMESIZE32 __SIGNAL_FRAMESIZE
336#define sigcontext32 sigcontext
337#define mcontext32 mcontext
338#define ucontext32 ucontext
339#define compat_siginfo_t struct siginfo
340
341#endif /* CONFIG_PPC64 */
342
343/*
344 * Layout for non-RT signal frames
345 */
346struct signal_frame_32 {
347 char dummy[__SIGNAL_FRAMESIZE32];
348 struct sigcontext32 sctx;
349 struct mcontext32 mctx;
350 int abigap[56];
351};
352
353/*
354 * Layout for RT signal frames
355 */
356struct rt_signal_frame_32 {
357 char dummy[__SIGNAL_FRAMESIZE32 + 16];
358 compat_siginfo_t info;
359 struct ucontext32 uc;
360 int abigap[56];
361};
362
363static int is_sigreturn_32_address(unsigned int nip, unsigned int fp)
364{
365 if (nip == fp + offsetof(struct signal_frame_32, mctx.mc_pad))
366 return 1;
367 if (vdso32_sigtramp && current->mm->context.vdso_base &&
368 nip == current->mm->context.vdso_base + vdso32_sigtramp)
369 return 1;
370 return 0;
371}
372
373static int is_rt_sigreturn_32_address(unsigned int nip, unsigned int fp)
374{
375 if (nip == fp + offsetof(struct rt_signal_frame_32,
376 uc.uc_mcontext.mc_pad))
377 return 1;
378 if (vdso32_rt_sigtramp && current->mm->context.vdso_base &&
379 nip == current->mm->context.vdso_base + vdso32_rt_sigtramp)
380 return 1;
381 return 0;
382}
383
384static int sane_signal_32_frame(unsigned int sp)
385{
386 struct signal_frame_32 __user *sf;
387 unsigned int regs;
388
389 sf = (struct signal_frame_32 __user *) (unsigned long) sp;
390 if (read_user_stack_32((unsigned int __user *) &sf->sctx.regs, &regs))
391 return 0;
392 return regs == (unsigned long) &sf->mctx;
393}
394
395static int sane_rt_signal_32_frame(unsigned int sp)
396{
397 struct rt_signal_frame_32 __user *sf;
398 unsigned int regs;
399
400 sf = (struct rt_signal_frame_32 __user *) (unsigned long) sp;
401 if (read_user_stack_32((unsigned int __user *) &sf->uc.uc_regs, &regs))
402 return 0;
403 return regs == (unsigned long) &sf->uc.uc_mcontext;
404}
405
406static unsigned int __user *signal_frame_32_regs(unsigned int sp,
407 unsigned int next_sp, unsigned int next_ip)
408{
409 struct mcontext32 __user *mctx = NULL;
410 struct signal_frame_32 __user *sf;
411 struct rt_signal_frame_32 __user *rt_sf;
412
413 /*
414 * Note: the next_sp - sp >= signal frame size check
415 * is true when next_sp < sp, for example, when
416 * transitioning from an alternate signal stack to the
417 * normal stack.
418 */
419 if (next_sp - sp >= sizeof(struct signal_frame_32) &&
420 is_sigreturn_32_address(next_ip, sp) &&
421 sane_signal_32_frame(sp)) {
422 sf = (struct signal_frame_32 __user *) (unsigned long) sp;
423 mctx = &sf->mctx;
424 }
425
426 if (!mctx && next_sp - sp >= sizeof(struct rt_signal_frame_32) &&
427 is_rt_sigreturn_32_address(next_ip, sp) &&
428 sane_rt_signal_32_frame(sp)) {
429 rt_sf = (struct rt_signal_frame_32 __user *) (unsigned long) sp;
430 mctx = &rt_sf->uc.uc_mcontext;
431 }
432
433 if (!mctx)
434 return NULL;
435 return mctx->mc_gregs;
436}
437
438static void perf_callchain_user_32(struct perf_callchain_entry *entry,
439 struct pt_regs *regs)
440{
441 unsigned int sp, next_sp;
442 unsigned int next_ip;
443 unsigned int lr;
444 long level = 0;
445 unsigned int __user *fp, *uregs;
446
447 next_ip = regs->nip;
448 lr = regs->link;
449 sp = regs->gpr[1];
450 perf_callchain_store(entry, next_ip);
451
452 while (entry->nr < PERF_MAX_STACK_DEPTH) {
453 fp = (unsigned int __user *) (unsigned long) sp;
454 if (!valid_user_sp(sp, 0) || read_user_stack_32(fp, &next_sp))
455 return;
456 if (level > 0 && read_user_stack_32(&fp[1], &next_ip))
457 return;
458
459 uregs = signal_frame_32_regs(sp, next_sp, next_ip);
460 if (!uregs && level <= 1)
461 uregs = signal_frame_32_regs(sp, next_sp, lr);
462 if (uregs) {
463 /*
464 * This looks like an signal frame, so restart
465 * the stack trace with the values in it.
466 */
467 if (read_user_stack_32(&uregs[PT_NIP], &next_ip) ||
468 read_user_stack_32(&uregs[PT_LNK], &lr) ||
469 read_user_stack_32(&uregs[PT_R1], &sp))
470 return;
471 level = 0;
472 perf_callchain_store(entry, PERF_CONTEXT_USER);
473 perf_callchain_store(entry, next_ip);
474 continue;
475 }
476
477 if (level == 0)
478 next_ip = lr;
479 perf_callchain_store(entry, next_ip);
480 ++level;
481 sp = next_sp;
482 }
483}
484
485void
486perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
487{
488 if (current_is_64bit())
489 perf_callchain_user_64(entry, regs);
490 else
491 perf_callchain_user_32(entry, regs);
492}
diff --git a/arch/powerpc/kernel/perf_event.c b/arch/powerpc/kernel/perf_event.c
new file mode 100644
index 00000000000..10a140f82cb
--- /dev/null
+++ b/arch/powerpc/kernel/perf_event.c
@@ -0,0 +1,1432 @@
1/*
2 * Performance event support - powerpc architecture code
3 *
4 * Copyright 2008-2009 Paul Mackerras, IBM Corporation.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11#include <linux/kernel.h>
12#include <linux/sched.h>
13#include <linux/perf_event.h>
14#include <linux/percpu.h>
15#include <linux/hardirq.h>
16#include <asm/reg.h>
17#include <asm/pmc.h>
18#include <asm/machdep.h>
19#include <asm/firmware.h>
20#include <asm/ptrace.h>
21
22struct cpu_hw_events {
23 int n_events;
24 int n_percpu;
25 int disabled;
26 int n_added;
27 int n_limited;
28 u8 pmcs_enabled;
29 struct perf_event *event[MAX_HWEVENTS];
30 u64 events[MAX_HWEVENTS];
31 unsigned int flags[MAX_HWEVENTS];
32 unsigned long mmcr[3];
33 struct perf_event *limited_counter[MAX_LIMITED_HWCOUNTERS];
34 u8 limited_hwidx[MAX_LIMITED_HWCOUNTERS];
35 u64 alternatives[MAX_HWEVENTS][MAX_EVENT_ALTERNATIVES];
36 unsigned long amasks[MAX_HWEVENTS][MAX_EVENT_ALTERNATIVES];
37 unsigned long avalues[MAX_HWEVENTS][MAX_EVENT_ALTERNATIVES];
38
39 unsigned int group_flag;
40 int n_txn_start;
41};
42DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events);
43
44struct power_pmu *ppmu;
45
46/*
47 * Normally, to ignore kernel events we set the FCS (freeze counters
48 * in supervisor mode) bit in MMCR0, but if the kernel runs with the
49 * hypervisor bit set in the MSR, or if we are running on a processor
50 * where the hypervisor bit is forced to 1 (as on Apple G5 processors),
51 * then we need to use the FCHV bit to ignore kernel events.
52 */
53static unsigned int freeze_events_kernel = MMCR0_FCS;
54
55/*
56 * 32-bit doesn't have MMCRA but does have an MMCR2,
57 * and a few other names are different.
58 */
59#ifdef CONFIG_PPC32
60
61#define MMCR0_FCHV 0
62#define MMCR0_PMCjCE MMCR0_PMCnCE
63
64#define SPRN_MMCRA SPRN_MMCR2
65#define MMCRA_SAMPLE_ENABLE 0
66
67static inline unsigned long perf_ip_adjust(struct pt_regs *regs)
68{
69 return 0;
70}
71static inline void perf_get_data_addr(struct pt_regs *regs, u64 *addrp) { }
72static inline u32 perf_get_misc_flags(struct pt_regs *regs)
73{
74 return 0;
75}
76static inline void perf_read_regs(struct pt_regs *regs) { }
77static inline int perf_intr_is_nmi(struct pt_regs *regs)
78{
79 return 0;
80}
81
82#endif /* CONFIG_PPC32 */
83
84/*
85 * Things that are specific to 64-bit implementations.
86 */
87#ifdef CONFIG_PPC64
88
89static inline unsigned long perf_ip_adjust(struct pt_regs *regs)
90{
91 unsigned long mmcra = regs->dsisr;
92
93 if ((mmcra & MMCRA_SAMPLE_ENABLE) && !(ppmu->flags & PPMU_ALT_SIPR)) {
94 unsigned long slot = (mmcra & MMCRA_SLOT) >> MMCRA_SLOT_SHIFT;
95 if (slot > 1)
96 return 4 * (slot - 1);
97 }
98 return 0;
99}
100
101/*
102 * The user wants a data address recorded.
103 * If we're not doing instruction sampling, give them the SDAR
104 * (sampled data address). If we are doing instruction sampling, then
105 * only give them the SDAR if it corresponds to the instruction
106 * pointed to by SIAR; this is indicated by the [POWER6_]MMCRA_SDSYNC
107 * bit in MMCRA.
108 */
109static inline void perf_get_data_addr(struct pt_regs *regs, u64 *addrp)
110{
111 unsigned long mmcra = regs->dsisr;
112 unsigned long sdsync = (ppmu->flags & PPMU_ALT_SIPR) ?
113 POWER6_MMCRA_SDSYNC : MMCRA_SDSYNC;
114
115 if (!(mmcra & MMCRA_SAMPLE_ENABLE) || (mmcra & sdsync))
116 *addrp = mfspr(SPRN_SDAR);
117}
118
119static inline u32 perf_get_misc_flags(struct pt_regs *regs)
120{
121 unsigned long mmcra = regs->dsisr;
122 unsigned long sihv = MMCRA_SIHV;
123 unsigned long sipr = MMCRA_SIPR;
124
125 if (TRAP(regs) != 0xf00)
126 return 0; /* not a PMU interrupt */
127
128 if (ppmu->flags & PPMU_ALT_SIPR) {
129 sihv = POWER6_MMCRA_SIHV;
130 sipr = POWER6_MMCRA_SIPR;
131 }
132
133 /* PR has priority over HV, so order below is important */
134 if (mmcra & sipr)
135 return PERF_RECORD_MISC_USER;
136 if ((mmcra & sihv) && (freeze_events_kernel != MMCR0_FCHV))
137 return PERF_RECORD_MISC_HYPERVISOR;
138 return PERF_RECORD_MISC_KERNEL;
139}
140
141/*
142 * Overload regs->dsisr to store MMCRA so we only need to read it once
143 * on each interrupt.
144 */
145static inline void perf_read_regs(struct pt_regs *regs)
146{
147 regs->dsisr = mfspr(SPRN_MMCRA);
148}
149
150/*
151 * If interrupts were soft-disabled when a PMU interrupt occurs, treat
152 * it as an NMI.
153 */
154static inline int perf_intr_is_nmi(struct pt_regs *regs)
155{
156 return !regs->softe;
157}
158
159#endif /* CONFIG_PPC64 */
160
161static void perf_event_interrupt(struct pt_regs *regs);
162
163void perf_event_print_debug(void)
164{
165}
166
167/*
168 * Read one performance monitor counter (PMC).
169 */
170static unsigned long read_pmc(int idx)
171{
172 unsigned long val;
173
174 switch (idx) {
175 case 1:
176 val = mfspr(SPRN_PMC1);
177 break;
178 case 2:
179 val = mfspr(SPRN_PMC2);
180 break;
181 case 3:
182 val = mfspr(SPRN_PMC3);
183 break;
184 case 4:
185 val = mfspr(SPRN_PMC4);
186 break;
187 case 5:
188 val = mfspr(SPRN_PMC5);
189 break;
190 case 6:
191 val = mfspr(SPRN_PMC6);
192 break;
193#ifdef CONFIG_PPC64
194 case 7:
195 val = mfspr(SPRN_PMC7);
196 break;
197 case 8:
198 val = mfspr(SPRN_PMC8);
199 break;
200#endif /* CONFIG_PPC64 */
201 default:
202 printk(KERN_ERR "oops trying to read PMC%d\n", idx);
203 val = 0;
204 }
205 return val;
206}
207
208/*
209 * Write one PMC.
210 */
211static void write_pmc(int idx, unsigned long val)
212{
213 switch (idx) {
214 case 1:
215 mtspr(SPRN_PMC1, val);
216 break;
217 case 2:
218 mtspr(SPRN_PMC2, val);
219 break;
220 case 3:
221 mtspr(SPRN_PMC3, val);
222 break;
223 case 4:
224 mtspr(SPRN_PMC4, val);
225 break;
226 case 5:
227 mtspr(SPRN_PMC5, val);
228 break;
229 case 6:
230 mtspr(SPRN_PMC6, val);
231 break;
232#ifdef CONFIG_PPC64
233 case 7:
234 mtspr(SPRN_PMC7, val);
235 break;
236 case 8:
237 mtspr(SPRN_PMC8, val);
238 break;
239#endif /* CONFIG_PPC64 */
240 default:
241 printk(KERN_ERR "oops trying to write PMC%d\n", idx);
242 }
243}
244
245/*
246 * Check if a set of events can all go on the PMU at once.
247 * If they can't, this will look at alternative codes for the events
248 * and see if any combination of alternative codes is feasible.
249 * The feasible set is returned in event_id[].
250 */
251static int power_check_constraints(struct cpu_hw_events *cpuhw,
252 u64 event_id[], unsigned int cflags[],
253 int n_ev)
254{
255 unsigned long mask, value, nv;
256 unsigned long smasks[MAX_HWEVENTS], svalues[MAX_HWEVENTS];
257 int n_alt[MAX_HWEVENTS], choice[MAX_HWEVENTS];
258 int i, j;
259 unsigned long addf = ppmu->add_fields;
260 unsigned long tadd = ppmu->test_adder;
261
262 if (n_ev > ppmu->n_counter)
263 return -1;
264
265 /* First see if the events will go on as-is */
266 for (i = 0; i < n_ev; ++i) {
267 if ((cflags[i] & PPMU_LIMITED_PMC_REQD)
268 && !ppmu->limited_pmc_event(event_id[i])) {
269 ppmu->get_alternatives(event_id[i], cflags[i],
270 cpuhw->alternatives[i]);
271 event_id[i] = cpuhw->alternatives[i][0];
272 }
273 if (ppmu->get_constraint(event_id[i], &cpuhw->amasks[i][0],
274 &cpuhw->avalues[i][0]))
275 return -1;
276 }
277 value = mask = 0;
278 for (i = 0; i < n_ev; ++i) {
279 nv = (value | cpuhw->avalues[i][0]) +
280 (value & cpuhw->avalues[i][0] & addf);
281 if ((((nv + tadd) ^ value) & mask) != 0 ||
282 (((nv + tadd) ^ cpuhw->avalues[i][0]) &
283 cpuhw->amasks[i][0]) != 0)
284 break;
285 value = nv;
286 mask |= cpuhw->amasks[i][0];
287 }
288 if (i == n_ev)
289 return 0; /* all OK */
290
291 /* doesn't work, gather alternatives... */
292 if (!ppmu->get_alternatives)
293 return -1;
294 for (i = 0; i < n_ev; ++i) {
295 choice[i] = 0;
296 n_alt[i] = ppmu->get_alternatives(event_id[i], cflags[i],
297 cpuhw->alternatives[i]);
298 for (j = 1; j < n_alt[i]; ++j)
299 ppmu->get_constraint(cpuhw->alternatives[i][j],
300 &cpuhw->amasks[i][j],
301 &cpuhw->avalues[i][j]);
302 }
303
304 /* enumerate all possibilities and see if any will work */
305 i = 0;
306 j = -1;
307 value = mask = nv = 0;
308 while (i < n_ev) {
309 if (j >= 0) {
310 /* we're backtracking, restore context */
311 value = svalues[i];
312 mask = smasks[i];
313 j = choice[i];
314 }
315 /*
316 * See if any alternative k for event_id i,
317 * where k > j, will satisfy the constraints.
318 */
319 while (++j < n_alt[i]) {
320 nv = (value | cpuhw->avalues[i][j]) +
321 (value & cpuhw->avalues[i][j] & addf);
322 if ((((nv + tadd) ^ value) & mask) == 0 &&
323 (((nv + tadd) ^ cpuhw->avalues[i][j])
324 & cpuhw->amasks[i][j]) == 0)
325 break;
326 }
327 if (j >= n_alt[i]) {
328 /*
329 * No feasible alternative, backtrack
330 * to event_id i-1 and continue enumerating its
331 * alternatives from where we got up to.
332 */
333 if (--i < 0)
334 return -1;
335 } else {
336 /*
337 * Found a feasible alternative for event_id i,
338 * remember where we got up to with this event_id,
339 * go on to the next event_id, and start with
340 * the first alternative for it.
341 */
342 choice[i] = j;
343 svalues[i] = value;
344 smasks[i] = mask;
345 value = nv;
346 mask |= cpuhw->amasks[i][j];
347 ++i;
348 j = -1;
349 }
350 }
351
352 /* OK, we have a feasible combination, tell the caller the solution */
353 for (i = 0; i < n_ev; ++i)
354 event_id[i] = cpuhw->alternatives[i][choice[i]];
355 return 0;
356}
357
358/*
359 * Check if newly-added events have consistent settings for
360 * exclude_{user,kernel,hv} with each other and any previously
361 * added events.
362 */
363static int check_excludes(struct perf_event **ctrs, unsigned int cflags[],
364 int n_prev, int n_new)
365{
366 int eu = 0, ek = 0, eh = 0;
367 int i, n, first;
368 struct perf_event *event;
369
370 n = n_prev + n_new;
371 if (n <= 1)
372 return 0;
373
374 first = 1;
375 for (i = 0; i < n; ++i) {
376 if (cflags[i] & PPMU_LIMITED_PMC_OK) {
377 cflags[i] &= ~PPMU_LIMITED_PMC_REQD;
378 continue;
379 }
380 event = ctrs[i];
381 if (first) {
382 eu = event->attr.exclude_user;
383 ek = event->attr.exclude_kernel;
384 eh = event->attr.exclude_hv;
385 first = 0;
386 } else if (event->attr.exclude_user != eu ||
387 event->attr.exclude_kernel != ek ||
388 event->attr.exclude_hv != eh) {
389 return -EAGAIN;
390 }
391 }
392
393 if (eu || ek || eh)
394 for (i = 0; i < n; ++i)
395 if (cflags[i] & PPMU_LIMITED_PMC_OK)
396 cflags[i] |= PPMU_LIMITED_PMC_REQD;
397
398 return 0;
399}
400
401static u64 check_and_compute_delta(u64 prev, u64 val)
402{
403 u64 delta = (val - prev) & 0xfffffffful;
404
405 /*
406 * POWER7 can roll back counter values, if the new value is smaller
407 * than the previous value it will cause the delta and the counter to
408 * have bogus values unless we rolled a counter over. If a coutner is
409 * rolled back, it will be smaller, but within 256, which is the maximum
410 * number of events to rollback at once. If we dectect a rollback
411 * return 0. This can lead to a small lack of precision in the
412 * counters.
413 */
414 if (prev > val && (prev - val) < 256)
415 delta = 0;
416
417 return delta;
418}
419
420static void power_pmu_read(struct perf_event *event)
421{
422 s64 val, delta, prev;
423
424 if (event->hw.state & PERF_HES_STOPPED)
425 return;
426
427 if (!event->hw.idx)
428 return;
429 /*
430 * Performance monitor interrupts come even when interrupts
431 * are soft-disabled, as long as interrupts are hard-enabled.
432 * Therefore we treat them like NMIs.
433 */
434 do {
435 prev = local64_read(&event->hw.prev_count);
436 barrier();
437 val = read_pmc(event->hw.idx);
438 delta = check_and_compute_delta(prev, val);
439 if (!delta)
440 return;
441 } while (local64_cmpxchg(&event->hw.prev_count, prev, val) != prev);
442
443 local64_add(delta, &event->count);
444 local64_sub(delta, &event->hw.period_left);
445}
446
447/*
448 * On some machines, PMC5 and PMC6 can't be written, don't respect
449 * the freeze conditions, and don't generate interrupts. This tells
450 * us if `event' is using such a PMC.
451 */
452static int is_limited_pmc(int pmcnum)
453{
454 return (ppmu->flags & PPMU_LIMITED_PMC5_6)
455 && (pmcnum == 5 || pmcnum == 6);
456}
457
458static void freeze_limited_counters(struct cpu_hw_events *cpuhw,
459 unsigned long pmc5, unsigned long pmc6)
460{
461 struct perf_event *event;
462 u64 val, prev, delta;
463 int i;
464
465 for (i = 0; i < cpuhw->n_limited; ++i) {
466 event = cpuhw->limited_counter[i];
467 if (!event->hw.idx)
468 continue;
469 val = (event->hw.idx == 5) ? pmc5 : pmc6;
470 prev = local64_read(&event->hw.prev_count);
471 event->hw.idx = 0;
472 delta = check_and_compute_delta(prev, val);
473 if (delta)
474 local64_add(delta, &event->count);
475 }
476}
477
478static void thaw_limited_counters(struct cpu_hw_events *cpuhw,
479 unsigned long pmc5, unsigned long pmc6)
480{
481 struct perf_event *event;
482 u64 val, prev;
483 int i;
484
485 for (i = 0; i < cpuhw->n_limited; ++i) {
486 event = cpuhw->limited_counter[i];
487 event->hw.idx = cpuhw->limited_hwidx[i];
488 val = (event->hw.idx == 5) ? pmc5 : pmc6;
489 prev = local64_read(&event->hw.prev_count);
490 if (check_and_compute_delta(prev, val))
491 local64_set(&event->hw.prev_count, val);
492 perf_event_update_userpage(event);
493 }
494}
495
496/*
497 * Since limited events don't respect the freeze conditions, we
498 * have to read them immediately after freezing or unfreezing the
499 * other events. We try to keep the values from the limited
500 * events as consistent as possible by keeping the delay (in
501 * cycles and instructions) between freezing/unfreezing and reading
502 * the limited events as small and consistent as possible.
503 * Therefore, if any limited events are in use, we read them
504 * both, and always in the same order, to minimize variability,
505 * and do it inside the same asm that writes MMCR0.
506 */
507static void write_mmcr0(struct cpu_hw_events *cpuhw, unsigned long mmcr0)
508{
509 unsigned long pmc5, pmc6;
510
511 if (!cpuhw->n_limited) {
512 mtspr(SPRN_MMCR0, mmcr0);
513 return;
514 }
515
516 /*
517 * Write MMCR0, then read PMC5 and PMC6 immediately.
518 * To ensure we don't get a performance monitor interrupt
519 * between writing MMCR0 and freezing/thawing the limited
520 * events, we first write MMCR0 with the event overflow
521 * interrupt enable bits turned off.
522 */
523 asm volatile("mtspr %3,%2; mfspr %0,%4; mfspr %1,%5"
524 : "=&r" (pmc5), "=&r" (pmc6)
525 : "r" (mmcr0 & ~(MMCR0_PMC1CE | MMCR0_PMCjCE)),
526 "i" (SPRN_MMCR0),
527 "i" (SPRN_PMC5), "i" (SPRN_PMC6));
528
529 if (mmcr0 & MMCR0_FC)
530 freeze_limited_counters(cpuhw, pmc5, pmc6);
531 else
532 thaw_limited_counters(cpuhw, pmc5, pmc6);
533
534 /*
535 * Write the full MMCR0 including the event overflow interrupt
536 * enable bits, if necessary.
537 */
538 if (mmcr0 & (MMCR0_PMC1CE | MMCR0_PMCjCE))
539 mtspr(SPRN_MMCR0, mmcr0);
540}
541
542/*
543 * Disable all events to prevent PMU interrupts and to allow
544 * events to be added or removed.
545 */
546static void power_pmu_disable(struct pmu *pmu)
547{
548 struct cpu_hw_events *cpuhw;
549 unsigned long flags;
550
551 if (!ppmu)
552 return;
553 local_irq_save(flags);
554 cpuhw = &__get_cpu_var(cpu_hw_events);
555
556 if (!cpuhw->disabled) {
557 cpuhw->disabled = 1;
558 cpuhw->n_added = 0;
559
560 /*
561 * Check if we ever enabled the PMU on this cpu.
562 */
563 if (!cpuhw->pmcs_enabled) {
564 ppc_enable_pmcs();
565 cpuhw->pmcs_enabled = 1;
566 }
567
568 /*
569 * Disable instruction sampling if it was enabled
570 */
571 if (cpuhw->mmcr[2] & MMCRA_SAMPLE_ENABLE) {
572 mtspr(SPRN_MMCRA,
573 cpuhw->mmcr[2] & ~MMCRA_SAMPLE_ENABLE);
574 mb();
575 }
576
577 /*
578 * Set the 'freeze counters' bit.
579 * The barrier is to make sure the mtspr has been
580 * executed and the PMU has frozen the events
581 * before we return.
582 */
583 write_mmcr0(cpuhw, mfspr(SPRN_MMCR0) | MMCR0_FC);
584 mb();
585 }
586 local_irq_restore(flags);
587}
588
589/*
590 * Re-enable all events if disable == 0.
591 * If we were previously disabled and events were added, then
592 * put the new config on the PMU.
593 */
594static void power_pmu_enable(struct pmu *pmu)
595{
596 struct perf_event *event;
597 struct cpu_hw_events *cpuhw;
598 unsigned long flags;
599 long i;
600 unsigned long val;
601 s64 left;
602 unsigned int hwc_index[MAX_HWEVENTS];
603 int n_lim;
604 int idx;
605
606 if (!ppmu)
607 return;
608 local_irq_save(flags);
609 cpuhw = &__get_cpu_var(cpu_hw_events);
610 if (!cpuhw->disabled) {
611 local_irq_restore(flags);
612 return;
613 }
614 cpuhw->disabled = 0;
615
616 /*
617 * If we didn't change anything, or only removed events,
618 * no need to recalculate MMCR* settings and reset the PMCs.
619 * Just reenable the PMU with the current MMCR* settings
620 * (possibly updated for removal of events).
621 */
622 if (!cpuhw->n_added) {
623 mtspr(SPRN_MMCRA, cpuhw->mmcr[2] & ~MMCRA_SAMPLE_ENABLE);
624 mtspr(SPRN_MMCR1, cpuhw->mmcr[1]);
625 if (cpuhw->n_events == 0)
626 ppc_set_pmu_inuse(0);
627 goto out_enable;
628 }
629
630 /*
631 * Compute MMCR* values for the new set of events
632 */
633 if (ppmu->compute_mmcr(cpuhw->events, cpuhw->n_events, hwc_index,
634 cpuhw->mmcr)) {
635 /* shouldn't ever get here */
636 printk(KERN_ERR "oops compute_mmcr failed\n");
637 goto out;
638 }
639
640 /*
641 * Add in MMCR0 freeze bits corresponding to the
642 * attr.exclude_* bits for the first event.
643 * We have already checked that all events have the
644 * same values for these bits as the first event.
645 */
646 event = cpuhw->event[0];
647 if (event->attr.exclude_user)
648 cpuhw->mmcr[0] |= MMCR0_FCP;
649 if (event->attr.exclude_kernel)
650 cpuhw->mmcr[0] |= freeze_events_kernel;
651 if (event->attr.exclude_hv)
652 cpuhw->mmcr[0] |= MMCR0_FCHV;
653
654 /*
655 * Write the new configuration to MMCR* with the freeze
656 * bit set and set the hardware events to their initial values.
657 * Then unfreeze the events.
658 */
659 ppc_set_pmu_inuse(1);
660 mtspr(SPRN_MMCRA, cpuhw->mmcr[2] & ~MMCRA_SAMPLE_ENABLE);
661 mtspr(SPRN_MMCR1, cpuhw->mmcr[1]);
662 mtspr(SPRN_MMCR0, (cpuhw->mmcr[0] & ~(MMCR0_PMC1CE | MMCR0_PMCjCE))
663 | MMCR0_FC);
664
665 /*
666 * Read off any pre-existing events that need to move
667 * to another PMC.
668 */
669 for (i = 0; i < cpuhw->n_events; ++i) {
670 event = cpuhw->event[i];
671 if (event->hw.idx && event->hw.idx != hwc_index[i] + 1) {
672 power_pmu_read(event);
673 write_pmc(event->hw.idx, 0);
674 event->hw.idx = 0;
675 }
676 }
677
678 /*
679 * Initialize the PMCs for all the new and moved events.
680 */
681 cpuhw->n_limited = n_lim = 0;
682 for (i = 0; i < cpuhw->n_events; ++i) {
683 event = cpuhw->event[i];
684 if (event->hw.idx)
685 continue;
686 idx = hwc_index[i] + 1;
687 if (is_limited_pmc(idx)) {
688 cpuhw->limited_counter[n_lim] = event;
689 cpuhw->limited_hwidx[n_lim] = idx;
690 ++n_lim;
691 continue;
692 }
693 val = 0;
694 if (event->hw.sample_period) {
695 left = local64_read(&event->hw.period_left);
696 if (left < 0x80000000L)
697 val = 0x80000000L - left;
698 }
699 local64_set(&event->hw.prev_count, val);
700 event->hw.idx = idx;
701 if (event->hw.state & PERF_HES_STOPPED)
702 val = 0;
703 write_pmc(idx, val);
704 perf_event_update_userpage(event);
705 }
706 cpuhw->n_limited = n_lim;
707 cpuhw->mmcr[0] |= MMCR0_PMXE | MMCR0_FCECE;
708
709 out_enable:
710 mb();
711 write_mmcr0(cpuhw, cpuhw->mmcr[0]);
712
713 /*
714 * Enable instruction sampling if necessary
715 */
716 if (cpuhw->mmcr[2] & MMCRA_SAMPLE_ENABLE) {
717 mb();
718 mtspr(SPRN_MMCRA, cpuhw->mmcr[2]);
719 }
720
721 out:
722 local_irq_restore(flags);
723}
724
725static int collect_events(struct perf_event *group, int max_count,
726 struct perf_event *ctrs[], u64 *events,
727 unsigned int *flags)
728{
729 int n = 0;
730 struct perf_event *event;
731
732 if (!is_software_event(group)) {
733 if (n >= max_count)
734 return -1;
735 ctrs[n] = group;
736 flags[n] = group->hw.event_base;
737 events[n++] = group->hw.config;
738 }
739 list_for_each_entry(event, &group->sibling_list, group_entry) {
740 if (!is_software_event(event) &&
741 event->state != PERF_EVENT_STATE_OFF) {
742 if (n >= max_count)
743 return -1;
744 ctrs[n] = event;
745 flags[n] = event->hw.event_base;
746 events[n++] = event->hw.config;
747 }
748 }
749 return n;
750}
751
752/*
753 * Add a event to the PMU.
754 * If all events are not already frozen, then we disable and
755 * re-enable the PMU in order to get hw_perf_enable to do the
756 * actual work of reconfiguring the PMU.
757 */
758static int power_pmu_add(struct perf_event *event, int ef_flags)
759{
760 struct cpu_hw_events *cpuhw;
761 unsigned long flags;
762 int n0;
763 int ret = -EAGAIN;
764
765 local_irq_save(flags);
766 perf_pmu_disable(event->pmu);
767
768 /*
769 * Add the event to the list (if there is room)
770 * and check whether the total set is still feasible.
771 */
772 cpuhw = &__get_cpu_var(cpu_hw_events);
773 n0 = cpuhw->n_events;
774 if (n0 >= ppmu->n_counter)
775 goto out;
776 cpuhw->event[n0] = event;
777 cpuhw->events[n0] = event->hw.config;
778 cpuhw->flags[n0] = event->hw.event_base;
779
780 if (!(ef_flags & PERF_EF_START))
781 event->hw.state = PERF_HES_STOPPED | PERF_HES_UPTODATE;
782
783 /*
784 * If group events scheduling transaction was started,
785 * skip the schedulability test here, it will be performed
786 * at commit time(->commit_txn) as a whole
787 */
788 if (cpuhw->group_flag & PERF_EVENT_TXN)
789 goto nocheck;
790
791 if (check_excludes(cpuhw->event, cpuhw->flags, n0, 1))
792 goto out;
793 if (power_check_constraints(cpuhw, cpuhw->events, cpuhw->flags, n0 + 1))
794 goto out;
795 event->hw.config = cpuhw->events[n0];
796
797nocheck:
798 ++cpuhw->n_events;
799 ++cpuhw->n_added;
800
801 ret = 0;
802 out:
803 perf_pmu_enable(event->pmu);
804 local_irq_restore(flags);
805 return ret;
806}
807
808/*
809 * Remove a event from the PMU.
810 */
811static void power_pmu_del(struct perf_event *event, int ef_flags)
812{
813 struct cpu_hw_events *cpuhw;
814 long i;
815 unsigned long flags;
816
817 local_irq_save(flags);
818 perf_pmu_disable(event->pmu);
819
820 power_pmu_read(event);
821
822 cpuhw = &__get_cpu_var(cpu_hw_events);
823 for (i = 0; i < cpuhw->n_events; ++i) {
824 if (event == cpuhw->event[i]) {
825 while (++i < cpuhw->n_events) {
826 cpuhw->event[i-1] = cpuhw->event[i];
827 cpuhw->events[i-1] = cpuhw->events[i];
828 cpuhw->flags[i-1] = cpuhw->flags[i];
829 }
830 --cpuhw->n_events;
831 ppmu->disable_pmc(event->hw.idx - 1, cpuhw->mmcr);
832 if (event->hw.idx) {
833 write_pmc(event->hw.idx, 0);
834 event->hw.idx = 0;
835 }
836 perf_event_update_userpage(event);
837 break;
838 }
839 }
840 for (i = 0; i < cpuhw->n_limited; ++i)
841 if (event == cpuhw->limited_counter[i])
842 break;
843 if (i < cpuhw->n_limited) {
844 while (++i < cpuhw->n_limited) {
845 cpuhw->limited_counter[i-1] = cpuhw->limited_counter[i];
846 cpuhw->limited_hwidx[i-1] = cpuhw->limited_hwidx[i];
847 }
848 --cpuhw->n_limited;
849 }
850 if (cpuhw->n_events == 0) {
851 /* disable exceptions if no events are running */
852 cpuhw->mmcr[0] &= ~(MMCR0_PMXE | MMCR0_FCECE);
853 }
854
855 perf_pmu_enable(event->pmu);
856 local_irq_restore(flags);
857}
858
859/*
860 * POWER-PMU does not support disabling individual counters, hence
861 * program their cycle counter to their max value and ignore the interrupts.
862 */
863
864static void power_pmu_start(struct perf_event *event, int ef_flags)
865{
866 unsigned long flags;
867 s64 left;
868
869 if (!event->hw.idx || !event->hw.sample_period)
870 return;
871
872 if (!(event->hw.state & PERF_HES_STOPPED))
873 return;
874
875 if (ef_flags & PERF_EF_RELOAD)
876 WARN_ON_ONCE(!(event->hw.state & PERF_HES_UPTODATE));
877
878 local_irq_save(flags);
879 perf_pmu_disable(event->pmu);
880
881 event->hw.state = 0;
882 left = local64_read(&event->hw.period_left);
883 write_pmc(event->hw.idx, left);
884
885 perf_event_update_userpage(event);
886 perf_pmu_enable(event->pmu);
887 local_irq_restore(flags);
888}
889
890static void power_pmu_stop(struct perf_event *event, int ef_flags)
891{
892 unsigned long flags;
893
894 if (!event->hw.idx || !event->hw.sample_period)
895 return;
896
897 if (event->hw.state & PERF_HES_STOPPED)
898 return;
899
900 local_irq_save(flags);
901 perf_pmu_disable(event->pmu);
902
903 power_pmu_read(event);
904 event->hw.state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
905 write_pmc(event->hw.idx, 0);
906
907 perf_event_update_userpage(event);
908 perf_pmu_enable(event->pmu);
909 local_irq_restore(flags);
910}
911
912/*
913 * Start group events scheduling transaction
914 * Set the flag to make pmu::enable() not perform the
915 * schedulability test, it will be performed at commit time
916 */
917void power_pmu_start_txn(struct pmu *pmu)
918{
919 struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
920
921 perf_pmu_disable(pmu);
922 cpuhw->group_flag |= PERF_EVENT_TXN;
923 cpuhw->n_txn_start = cpuhw->n_events;
924}
925
926/*
927 * Stop group events scheduling transaction
928 * Clear the flag and pmu::enable() will perform the
929 * schedulability test.
930 */
931void power_pmu_cancel_txn(struct pmu *pmu)
932{
933 struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
934
935 cpuhw->group_flag &= ~PERF_EVENT_TXN;
936 perf_pmu_enable(pmu);
937}
938
939/*
940 * Commit group events scheduling transaction
941 * Perform the group schedulability test as a whole
942 * Return 0 if success
943 */
944int power_pmu_commit_txn(struct pmu *pmu)
945{
946 struct cpu_hw_events *cpuhw;
947 long i, n;
948
949 if (!ppmu)
950 return -EAGAIN;
951 cpuhw = &__get_cpu_var(cpu_hw_events);
952 n = cpuhw->n_events;
953 if (check_excludes(cpuhw->event, cpuhw->flags, 0, n))
954 return -EAGAIN;
955 i = power_check_constraints(cpuhw, cpuhw->events, cpuhw->flags, n);
956 if (i < 0)
957 return -EAGAIN;
958
959 for (i = cpuhw->n_txn_start; i < n; ++i)
960 cpuhw->event[i]->hw.config = cpuhw->events[i];
961
962 cpuhw->group_flag &= ~PERF_EVENT_TXN;
963 perf_pmu_enable(pmu);
964 return 0;
965}
966
967/*
968 * Return 1 if we might be able to put event on a limited PMC,
969 * or 0 if not.
970 * A event can only go on a limited PMC if it counts something
971 * that a limited PMC can count, doesn't require interrupts, and
972 * doesn't exclude any processor mode.
973 */
974static int can_go_on_limited_pmc(struct perf_event *event, u64 ev,
975 unsigned int flags)
976{
977 int n;
978 u64 alt[MAX_EVENT_ALTERNATIVES];
979
980 if (event->attr.exclude_user
981 || event->attr.exclude_kernel
982 || event->attr.exclude_hv
983 || event->attr.sample_period)
984 return 0;
985
986 if (ppmu->limited_pmc_event(ev))
987 return 1;
988
989 /*
990 * The requested event_id isn't on a limited PMC already;
991 * see if any alternative code goes on a limited PMC.
992 */
993 if (!ppmu->get_alternatives)
994 return 0;
995
996 flags |= PPMU_LIMITED_PMC_OK | PPMU_LIMITED_PMC_REQD;
997 n = ppmu->get_alternatives(ev, flags, alt);
998
999 return n > 0;
1000}
1001
1002/*
1003 * Find an alternative event_id that goes on a normal PMC, if possible,
1004 * and return the event_id code, or 0 if there is no such alternative.
1005 * (Note: event_id code 0 is "don't count" on all machines.)
1006 */
1007static u64 normal_pmc_alternative(u64 ev, unsigned long flags)
1008{
1009 u64 alt[MAX_EVENT_ALTERNATIVES];
1010 int n;
1011
1012 flags &= ~(PPMU_LIMITED_PMC_OK | PPMU_LIMITED_PMC_REQD);
1013 n = ppmu->get_alternatives(ev, flags, alt);
1014 if (!n)
1015 return 0;
1016 return alt[0];
1017}
1018
1019/* Number of perf_events counting hardware events */
1020static atomic_t num_events;
1021/* Used to avoid races in calling reserve/release_pmc_hardware */
1022static DEFINE_MUTEX(pmc_reserve_mutex);
1023
1024/*
1025 * Release the PMU if this is the last perf_event.
1026 */
1027static void hw_perf_event_destroy(struct perf_event *event)
1028{
1029 if (!atomic_add_unless(&num_events, -1, 1)) {
1030 mutex_lock(&pmc_reserve_mutex);
1031 if (atomic_dec_return(&num_events) == 0)
1032 release_pmc_hardware();
1033 mutex_unlock(&pmc_reserve_mutex);
1034 }
1035}
1036
1037/*
1038 * Translate a generic cache event_id config to a raw event_id code.
1039 */
1040static int hw_perf_cache_event(u64 config, u64 *eventp)
1041{
1042 unsigned long type, op, result;
1043 int ev;
1044
1045 if (!ppmu->cache_events)
1046 return -EINVAL;
1047
1048 /* unpack config */
1049 type = config & 0xff;
1050 op = (config >> 8) & 0xff;
1051 result = (config >> 16) & 0xff;
1052
1053 if (type >= PERF_COUNT_HW_CACHE_MAX ||
1054 op >= PERF_COUNT_HW_CACHE_OP_MAX ||
1055 result >= PERF_COUNT_HW_CACHE_RESULT_MAX)
1056 return -EINVAL;
1057
1058 ev = (*ppmu->cache_events)[type][op][result];
1059 if (ev == 0)
1060 return -EOPNOTSUPP;
1061 if (ev == -1)
1062 return -EINVAL;
1063 *eventp = ev;
1064 return 0;
1065}
1066
1067static int power_pmu_event_init(struct perf_event *event)
1068{
1069 u64 ev;
1070 unsigned long flags;
1071 struct perf_event *ctrs[MAX_HWEVENTS];
1072 u64 events[MAX_HWEVENTS];
1073 unsigned int cflags[MAX_HWEVENTS];
1074 int n;
1075 int err;
1076 struct cpu_hw_events *cpuhw;
1077
1078 if (!ppmu)
1079 return -ENOENT;
1080
1081 switch (event->attr.type) {
1082 case PERF_TYPE_HARDWARE:
1083 ev = event->attr.config;
1084 if (ev >= ppmu->n_generic || ppmu->generic_events[ev] == 0)
1085 return -EOPNOTSUPP;
1086 ev = ppmu->generic_events[ev];
1087 break;
1088 case PERF_TYPE_HW_CACHE:
1089 err = hw_perf_cache_event(event->attr.config, &ev);
1090 if (err)
1091 return err;
1092 break;
1093 case PERF_TYPE_RAW:
1094 ev = event->attr.config;
1095 break;
1096 default:
1097 return -ENOENT;
1098 }
1099
1100 event->hw.config_base = ev;
1101 event->hw.idx = 0;
1102
1103 /*
1104 * If we are not running on a hypervisor, force the
1105 * exclude_hv bit to 0 so that we don't care what
1106 * the user set it to.
1107 */
1108 if (!firmware_has_feature(FW_FEATURE_LPAR))
1109 event->attr.exclude_hv = 0;
1110
1111 /*
1112 * If this is a per-task event, then we can use
1113 * PM_RUN_* events interchangeably with their non RUN_*
1114 * equivalents, e.g. PM_RUN_CYC instead of PM_CYC.
1115 * XXX we should check if the task is an idle task.
1116 */
1117 flags = 0;
1118 if (event->attach_state & PERF_ATTACH_TASK)
1119 flags |= PPMU_ONLY_COUNT_RUN;
1120
1121 /*
1122 * If this machine has limited events, check whether this
1123 * event_id could go on a limited event.
1124 */
1125 if (ppmu->flags & PPMU_LIMITED_PMC5_6) {
1126 if (can_go_on_limited_pmc(event, ev, flags)) {
1127 flags |= PPMU_LIMITED_PMC_OK;
1128 } else if (ppmu->limited_pmc_event(ev)) {
1129 /*
1130 * The requested event_id is on a limited PMC,
1131 * but we can't use a limited PMC; see if any
1132 * alternative goes on a normal PMC.
1133 */
1134 ev = normal_pmc_alternative(ev, flags);
1135 if (!ev)
1136 return -EINVAL;
1137 }
1138 }
1139
1140 /*
1141 * If this is in a group, check if it can go on with all the
1142 * other hardware events in the group. We assume the event
1143 * hasn't been linked into its leader's sibling list at this point.
1144 */
1145 n = 0;
1146 if (event->group_leader != event) {
1147 n = collect_events(event->group_leader, ppmu->n_counter - 1,
1148 ctrs, events, cflags);
1149 if (n < 0)
1150 return -EINVAL;
1151 }
1152 events[n] = ev;
1153 ctrs[n] = event;
1154 cflags[n] = flags;
1155 if (check_excludes(ctrs, cflags, n, 1))
1156 return -EINVAL;
1157
1158 cpuhw = &get_cpu_var(cpu_hw_events);
1159 err = power_check_constraints(cpuhw, events, cflags, n + 1);
1160 put_cpu_var(cpu_hw_events);
1161 if (err)
1162 return -EINVAL;
1163
1164 event->hw.config = events[n];
1165 event->hw.event_base = cflags[n];
1166 event->hw.last_period = event->hw.sample_period;
1167 local64_set(&event->hw.period_left, event->hw.last_period);
1168
1169 /*
1170 * See if we need to reserve the PMU.
1171 * If no events are currently in use, then we have to take a
1172 * mutex to ensure that we don't race with another task doing
1173 * reserve_pmc_hardware or release_pmc_hardware.
1174 */
1175 err = 0;
1176 if (!atomic_inc_not_zero(&num_events)) {
1177 mutex_lock(&pmc_reserve_mutex);
1178 if (atomic_read(&num_events) == 0 &&
1179 reserve_pmc_hardware(perf_event_interrupt))
1180 err = -EBUSY;
1181 else
1182 atomic_inc(&num_events);
1183 mutex_unlock(&pmc_reserve_mutex);
1184 }
1185 event->destroy = hw_perf_event_destroy;
1186
1187 return err;
1188}
1189
1190struct pmu power_pmu = {
1191 .pmu_enable = power_pmu_enable,
1192 .pmu_disable = power_pmu_disable,
1193 .event_init = power_pmu_event_init,
1194 .add = power_pmu_add,
1195 .del = power_pmu_del,
1196 .start = power_pmu_start,
1197 .stop = power_pmu_stop,
1198 .read = power_pmu_read,
1199 .start_txn = power_pmu_start_txn,
1200 .cancel_txn = power_pmu_cancel_txn,
1201 .commit_txn = power_pmu_commit_txn,
1202};
1203
1204/*
1205 * A counter has overflowed; update its count and record
1206 * things if requested. Note that interrupts are hard-disabled
1207 * here so there is no possibility of being interrupted.
1208 */
1209static void record_and_restart(struct perf_event *event, unsigned long val,
1210 struct pt_regs *regs)
1211{
1212 u64 period = event->hw.sample_period;
1213 s64 prev, delta, left;
1214 int record = 0;
1215
1216 if (event->hw.state & PERF_HES_STOPPED) {
1217 write_pmc(event->hw.idx, 0);
1218 return;
1219 }
1220
1221 /* we don't have to worry about interrupts here */
1222 prev = local64_read(&event->hw.prev_count);
1223 delta = check_and_compute_delta(prev, val);
1224 local64_add(delta, &event->count);
1225
1226 /*
1227 * See if the total period for this event has expired,
1228 * and update for the next period.
1229 */
1230 val = 0;
1231 left = local64_read(&event->hw.period_left) - delta;
1232 if (period) {
1233 if (left <= 0) {
1234 left += period;
1235 if (left <= 0)
1236 left = period;
1237 record = 1;
1238 event->hw.last_period = event->hw.sample_period;
1239 }
1240 if (left < 0x80000000LL)
1241 val = 0x80000000LL - left;
1242 }
1243
1244 write_pmc(event->hw.idx, val);
1245 local64_set(&event->hw.prev_count, val);
1246 local64_set(&event->hw.period_left, left);
1247 perf_event_update_userpage(event);
1248
1249 /*
1250 * Finally record data if requested.
1251 */
1252 if (record) {
1253 struct perf_sample_data data;
1254
1255 perf_sample_data_init(&data, ~0ULL);
1256 data.period = event->hw.last_period;
1257
1258 if (event->attr.sample_type & PERF_SAMPLE_ADDR)
1259 perf_get_data_addr(regs, &data.addr);
1260
1261 if (perf_event_overflow(event, &data, regs))
1262 power_pmu_stop(event, 0);
1263 }
1264}
1265
1266/*
1267 * Called from generic code to get the misc flags (i.e. processor mode)
1268 * for an event_id.
1269 */
1270unsigned long perf_misc_flags(struct pt_regs *regs)
1271{
1272 u32 flags = perf_get_misc_flags(regs);
1273
1274 if (flags)
1275 return flags;
1276 return user_mode(regs) ? PERF_RECORD_MISC_USER :
1277 PERF_RECORD_MISC_KERNEL;
1278}
1279
1280/*
1281 * Called from generic code to get the instruction pointer
1282 * for an event_id.
1283 */
1284unsigned long perf_instruction_pointer(struct pt_regs *regs)
1285{
1286 unsigned long ip;
1287
1288 if (TRAP(regs) != 0xf00)
1289 return regs->nip; /* not a PMU interrupt */
1290
1291 ip = mfspr(SPRN_SIAR) + perf_ip_adjust(regs);
1292 return ip;
1293}
1294
1295static bool pmc_overflow(unsigned long val)
1296{
1297 if ((int)val < 0)
1298 return true;
1299
1300 /*
1301 * Events on POWER7 can roll back if a speculative event doesn't
1302 * eventually complete. Unfortunately in some rare cases they will
1303 * raise a performance monitor exception. We need to catch this to
1304 * ensure we reset the PMC. In all cases the PMC will be 256 or less
1305 * cycles from overflow.
1306 *
1307 * We only do this if the first pass fails to find any overflowing
1308 * PMCs because a user might set a period of less than 256 and we
1309 * don't want to mistakenly reset them.
1310 */
1311 if (__is_processor(PV_POWER7) && ((0x80000000 - val) <= 256))
1312 return true;
1313
1314 return false;
1315}
1316
1317/*
1318 * Performance monitor interrupt stuff
1319 */
1320static void perf_event_interrupt(struct pt_regs *regs)
1321{
1322 int i;
1323 struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
1324 struct perf_event *event;
1325 unsigned long val;
1326 int found = 0;
1327 int nmi;
1328
1329 if (cpuhw->n_limited)
1330 freeze_limited_counters(cpuhw, mfspr(SPRN_PMC5),
1331 mfspr(SPRN_PMC6));
1332
1333 perf_read_regs(regs);
1334
1335 nmi = perf_intr_is_nmi(regs);
1336 if (nmi)
1337 nmi_enter();
1338 else
1339 irq_enter();
1340
1341 for (i = 0; i < cpuhw->n_events; ++i) {
1342 event = cpuhw->event[i];
1343 if (!event->hw.idx || is_limited_pmc(event->hw.idx))
1344 continue;
1345 val = read_pmc(event->hw.idx);
1346 if ((int)val < 0) {
1347 /* event has overflowed */
1348 found = 1;
1349 record_and_restart(event, val, regs);
1350 }
1351 }
1352
1353 /*
1354 * In case we didn't find and reset the event that caused
1355 * the interrupt, scan all events and reset any that are
1356 * negative, to avoid getting continual interrupts.
1357 * Any that we processed in the previous loop will not be negative.
1358 */
1359 if (!found) {
1360 for (i = 0; i < ppmu->n_counter; ++i) {
1361 if (is_limited_pmc(i + 1))
1362 continue;
1363 val = read_pmc(i + 1);
1364 if (pmc_overflow(val))
1365 write_pmc(i + 1, 0);
1366 }
1367 }
1368
1369 /*
1370 * Reset MMCR0 to its normal value. This will set PMXE and
1371 * clear FC (freeze counters) and PMAO (perf mon alert occurred)
1372 * and thus allow interrupts to occur again.
1373 * XXX might want to use MSR.PM to keep the events frozen until
1374 * we get back out of this interrupt.
1375 */
1376 write_mmcr0(cpuhw, cpuhw->mmcr[0]);
1377
1378 if (nmi)
1379 nmi_exit();
1380 else
1381 irq_exit();
1382}
1383
1384static void power_pmu_setup(int cpu)
1385{
1386 struct cpu_hw_events *cpuhw = &per_cpu(cpu_hw_events, cpu);
1387
1388 if (!ppmu)
1389 return;
1390 memset(cpuhw, 0, sizeof(*cpuhw));
1391 cpuhw->mmcr[0] = MMCR0_FC;
1392}
1393
1394static int __cpuinit
1395power_pmu_notifier(struct notifier_block *self, unsigned long action, void *hcpu)
1396{
1397 unsigned int cpu = (long)hcpu;
1398
1399 switch (action & ~CPU_TASKS_FROZEN) {
1400 case CPU_UP_PREPARE:
1401 power_pmu_setup(cpu);
1402 break;
1403
1404 default:
1405 break;
1406 }
1407
1408 return NOTIFY_OK;
1409}
1410
1411int __cpuinit register_power_pmu(struct power_pmu *pmu)
1412{
1413 if (ppmu)
1414 return -EBUSY; /* something's already registered */
1415
1416 ppmu = pmu;
1417 pr_info("%s performance monitor hardware support registered\n",
1418 pmu->name);
1419
1420#ifdef MSR_HV
1421 /*
1422 * Use FCHV to ignore kernel events if MSR.HV is set.
1423 */
1424 if (mfmsr() & MSR_HV)
1425 freeze_events_kernel = MMCR0_FCHV;
1426#endif /* CONFIG_PPC64 */
1427
1428 perf_pmu_register(&power_pmu, "cpu", PERF_TYPE_RAW);
1429 perf_cpu_notifier(power_pmu_notifier);
1430
1431 return 0;
1432}
diff --git a/arch/powerpc/kernel/perf_event_fsl_emb.c b/arch/powerpc/kernel/perf_event_fsl_emb.c
new file mode 100644
index 00000000000..0a6d2a9d569
--- /dev/null
+++ b/arch/powerpc/kernel/perf_event_fsl_emb.c
@@ -0,0 +1,688 @@
1/*
2 * Performance event support - Freescale Embedded Performance Monitor
3 *
4 * Copyright 2008-2009 Paul Mackerras, IBM Corporation.
5 * Copyright 2010 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; either version
10 * 2 of the License, or (at your option) any later version.
11 */
12#include <linux/kernel.h>
13#include <linux/sched.h>
14#include <linux/perf_event.h>
15#include <linux/percpu.h>
16#include <linux/hardirq.h>
17#include <asm/reg_fsl_emb.h>
18#include <asm/pmc.h>
19#include <asm/machdep.h>
20#include <asm/firmware.h>
21#include <asm/ptrace.h>
22
23struct cpu_hw_events {
24 int n_events;
25 int disabled;
26 u8 pmcs_enabled;
27 struct perf_event *event[MAX_HWEVENTS];
28};
29static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events);
30
31static struct fsl_emb_pmu *ppmu;
32
33/* Number of perf_events counting hardware events */
34static atomic_t num_events;
35/* Used to avoid races in calling reserve/release_pmc_hardware */
36static DEFINE_MUTEX(pmc_reserve_mutex);
37
38/*
39 * If interrupts were soft-disabled when a PMU interrupt occurs, treat
40 * it as an NMI.
41 */
42static inline int perf_intr_is_nmi(struct pt_regs *regs)
43{
44#ifdef __powerpc64__
45 return !regs->softe;
46#else
47 return 0;
48#endif
49}
50
51static void perf_event_interrupt(struct pt_regs *regs);
52
53/*
54 * Read one performance monitor counter (PMC).
55 */
56static unsigned long read_pmc(int idx)
57{
58 unsigned long val;
59
60 switch (idx) {
61 case 0:
62 val = mfpmr(PMRN_PMC0);
63 break;
64 case 1:
65 val = mfpmr(PMRN_PMC1);
66 break;
67 case 2:
68 val = mfpmr(PMRN_PMC2);
69 break;
70 case 3:
71 val = mfpmr(PMRN_PMC3);
72 break;
73 default:
74 printk(KERN_ERR "oops trying to read PMC%d\n", idx);
75 val = 0;
76 }
77 return val;
78}
79
80/*
81 * Write one PMC.
82 */
83static void write_pmc(int idx, unsigned long val)
84{
85 switch (idx) {
86 case 0:
87 mtpmr(PMRN_PMC0, val);
88 break;
89 case 1:
90 mtpmr(PMRN_PMC1, val);
91 break;
92 case 2:
93 mtpmr(PMRN_PMC2, val);
94 break;
95 case 3:
96 mtpmr(PMRN_PMC3, val);
97 break;
98 default:
99 printk(KERN_ERR "oops trying to write PMC%d\n", idx);
100 }
101
102 isync();
103}
104
105/*
106 * Write one local control A register
107 */
108static void write_pmlca(int idx, unsigned long val)
109{
110 switch (idx) {
111 case 0:
112 mtpmr(PMRN_PMLCA0, val);
113 break;
114 case 1:
115 mtpmr(PMRN_PMLCA1, val);
116 break;
117 case 2:
118 mtpmr(PMRN_PMLCA2, val);
119 break;
120 case 3:
121 mtpmr(PMRN_PMLCA3, val);
122 break;
123 default:
124 printk(KERN_ERR "oops trying to write PMLCA%d\n", idx);
125 }
126
127 isync();
128}
129
130/*
131 * Write one local control B register
132 */
133static void write_pmlcb(int idx, unsigned long val)
134{
135 switch (idx) {
136 case 0:
137 mtpmr(PMRN_PMLCB0, val);
138 break;
139 case 1:
140 mtpmr(PMRN_PMLCB1, val);
141 break;
142 case 2:
143 mtpmr(PMRN_PMLCB2, val);
144 break;
145 case 3:
146 mtpmr(PMRN_PMLCB3, val);
147 break;
148 default:
149 printk(KERN_ERR "oops trying to write PMLCB%d\n", idx);
150 }
151
152 isync();
153}
154
155static void fsl_emb_pmu_read(struct perf_event *event)
156{
157 s64 val, delta, prev;
158
159 if (event->hw.state & PERF_HES_STOPPED)
160 return;
161
162 /*
163 * Performance monitor interrupts come even when interrupts
164 * are soft-disabled, as long as interrupts are hard-enabled.
165 * Therefore we treat them like NMIs.
166 */
167 do {
168 prev = local64_read(&event->hw.prev_count);
169 barrier();
170 val = read_pmc(event->hw.idx);
171 } while (local64_cmpxchg(&event->hw.prev_count, prev, val) != prev);
172
173 /* The counters are only 32 bits wide */
174 delta = (val - prev) & 0xfffffffful;
175 local64_add(delta, &event->count);
176 local64_sub(delta, &event->hw.period_left);
177}
178
179/*
180 * Disable all events to prevent PMU interrupts and to allow
181 * events to be added or removed.
182 */
183static void fsl_emb_pmu_disable(struct pmu *pmu)
184{
185 struct cpu_hw_events *cpuhw;
186 unsigned long flags;
187
188 local_irq_save(flags);
189 cpuhw = &__get_cpu_var(cpu_hw_events);
190
191 if (!cpuhw->disabled) {
192 cpuhw->disabled = 1;
193
194 /*
195 * Check if we ever enabled the PMU on this cpu.
196 */
197 if (!cpuhw->pmcs_enabled) {
198 ppc_enable_pmcs();
199 cpuhw->pmcs_enabled = 1;
200 }
201
202 if (atomic_read(&num_events)) {
203 /*
204 * Set the 'freeze all counters' bit, and disable
205 * interrupts. The barrier is to make sure the
206 * mtpmr has been executed and the PMU has frozen
207 * the events before we return.
208 */
209
210 mtpmr(PMRN_PMGC0, PMGC0_FAC);
211 isync();
212 }
213 }
214 local_irq_restore(flags);
215}
216
217/*
218 * Re-enable all events if disable == 0.
219 * If we were previously disabled and events were added, then
220 * put the new config on the PMU.
221 */
222static void fsl_emb_pmu_enable(struct pmu *pmu)
223{
224 struct cpu_hw_events *cpuhw;
225 unsigned long flags;
226
227 local_irq_save(flags);
228 cpuhw = &__get_cpu_var(cpu_hw_events);
229 if (!cpuhw->disabled)
230 goto out;
231
232 cpuhw->disabled = 0;
233 ppc_set_pmu_inuse(cpuhw->n_events != 0);
234
235 if (cpuhw->n_events > 0) {
236 mtpmr(PMRN_PMGC0, PMGC0_PMIE | PMGC0_FCECE);
237 isync();
238 }
239
240 out:
241 local_irq_restore(flags);
242}
243
244static int collect_events(struct perf_event *group, int max_count,
245 struct perf_event *ctrs[])
246{
247 int n = 0;
248 struct perf_event *event;
249
250 if (!is_software_event(group)) {
251 if (n >= max_count)
252 return -1;
253 ctrs[n] = group;
254 n++;
255 }
256 list_for_each_entry(event, &group->sibling_list, group_entry) {
257 if (!is_software_event(event) &&
258 event->state != PERF_EVENT_STATE_OFF) {
259 if (n >= max_count)
260 return -1;
261 ctrs[n] = event;
262 n++;
263 }
264 }
265 return n;
266}
267
268/* context locked on entry */
269static int fsl_emb_pmu_add(struct perf_event *event, int flags)
270{
271 struct cpu_hw_events *cpuhw;
272 int ret = -EAGAIN;
273 int num_counters = ppmu->n_counter;
274 u64 val;
275 int i;
276
277 perf_pmu_disable(event->pmu);
278 cpuhw = &get_cpu_var(cpu_hw_events);
279
280 if (event->hw.config & FSL_EMB_EVENT_RESTRICTED)
281 num_counters = ppmu->n_restricted;
282
283 /*
284 * Allocate counters from top-down, so that restricted-capable
285 * counters are kept free as long as possible.
286 */
287 for (i = num_counters - 1; i >= 0; i--) {
288 if (cpuhw->event[i])
289 continue;
290
291 break;
292 }
293
294 if (i < 0)
295 goto out;
296
297 event->hw.idx = i;
298 cpuhw->event[i] = event;
299 ++cpuhw->n_events;
300
301 val = 0;
302 if (event->hw.sample_period) {
303 s64 left = local64_read(&event->hw.period_left);
304 if (left < 0x80000000L)
305 val = 0x80000000L - left;
306 }
307 local64_set(&event->hw.prev_count, val);
308
309 if (!(flags & PERF_EF_START)) {
310 event->hw.state = PERF_HES_STOPPED | PERF_HES_UPTODATE;
311 val = 0;
312 }
313
314 write_pmc(i, val);
315 perf_event_update_userpage(event);
316
317 write_pmlcb(i, event->hw.config >> 32);
318 write_pmlca(i, event->hw.config_base);
319
320 ret = 0;
321 out:
322 put_cpu_var(cpu_hw_events);
323 perf_pmu_enable(event->pmu);
324 return ret;
325}
326
327/* context locked on entry */
328static void fsl_emb_pmu_del(struct perf_event *event, int flags)
329{
330 struct cpu_hw_events *cpuhw;
331 int i = event->hw.idx;
332
333 perf_pmu_disable(event->pmu);
334 if (i < 0)
335 goto out;
336
337 fsl_emb_pmu_read(event);
338
339 cpuhw = &get_cpu_var(cpu_hw_events);
340
341 WARN_ON(event != cpuhw->event[event->hw.idx]);
342
343 write_pmlca(i, 0);
344 write_pmlcb(i, 0);
345 write_pmc(i, 0);
346
347 cpuhw->event[i] = NULL;
348 event->hw.idx = -1;
349
350 /*
351 * TODO: if at least one restricted event exists, and we
352 * just freed up a non-restricted-capable counter, and
353 * there is a restricted-capable counter occupied by
354 * a non-restricted event, migrate that event to the
355 * vacated counter.
356 */
357
358 cpuhw->n_events--;
359
360 out:
361 perf_pmu_enable(event->pmu);
362 put_cpu_var(cpu_hw_events);
363}
364
365static void fsl_emb_pmu_start(struct perf_event *event, int ef_flags)
366{
367 unsigned long flags;
368 s64 left;
369
370 if (event->hw.idx < 0 || !event->hw.sample_period)
371 return;
372
373 if (!(event->hw.state & PERF_HES_STOPPED))
374 return;
375
376 if (ef_flags & PERF_EF_RELOAD)
377 WARN_ON_ONCE(!(event->hw.state & PERF_HES_UPTODATE));
378
379 local_irq_save(flags);
380 perf_pmu_disable(event->pmu);
381
382 event->hw.state = 0;
383 left = local64_read(&event->hw.period_left);
384 write_pmc(event->hw.idx, left);
385
386 perf_event_update_userpage(event);
387 perf_pmu_enable(event->pmu);
388 local_irq_restore(flags);
389}
390
391static void fsl_emb_pmu_stop(struct perf_event *event, int ef_flags)
392{
393 unsigned long flags;
394
395 if (event->hw.idx < 0 || !event->hw.sample_period)
396 return;
397
398 if (event->hw.state & PERF_HES_STOPPED)
399 return;
400
401 local_irq_save(flags);
402 perf_pmu_disable(event->pmu);
403
404 fsl_emb_pmu_read(event);
405 event->hw.state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
406 write_pmc(event->hw.idx, 0);
407
408 perf_event_update_userpage(event);
409 perf_pmu_enable(event->pmu);
410 local_irq_restore(flags);
411}
412
413/*
414 * Release the PMU if this is the last perf_event.
415 */
416static void hw_perf_event_destroy(struct perf_event *event)
417{
418 if (!atomic_add_unless(&num_events, -1, 1)) {
419 mutex_lock(&pmc_reserve_mutex);
420 if (atomic_dec_return(&num_events) == 0)
421 release_pmc_hardware();
422 mutex_unlock(&pmc_reserve_mutex);
423 }
424}
425
426/*
427 * Translate a generic cache event_id config to a raw event_id code.
428 */
429static int hw_perf_cache_event(u64 config, u64 *eventp)
430{
431 unsigned long type, op, result;
432 int ev;
433
434 if (!ppmu->cache_events)
435 return -EINVAL;
436
437 /* unpack config */
438 type = config & 0xff;
439 op = (config >> 8) & 0xff;
440 result = (config >> 16) & 0xff;
441
442 if (type >= PERF_COUNT_HW_CACHE_MAX ||
443 op >= PERF_COUNT_HW_CACHE_OP_MAX ||
444 result >= PERF_COUNT_HW_CACHE_RESULT_MAX)
445 return -EINVAL;
446
447 ev = (*ppmu->cache_events)[type][op][result];
448 if (ev == 0)
449 return -EOPNOTSUPP;
450 if (ev == -1)
451 return -EINVAL;
452 *eventp = ev;
453 return 0;
454}
455
456static int fsl_emb_pmu_event_init(struct perf_event *event)
457{
458 u64 ev;
459 struct perf_event *events[MAX_HWEVENTS];
460 int n;
461 int err;
462 int num_restricted;
463 int i;
464
465 switch (event->attr.type) {
466 case PERF_TYPE_HARDWARE:
467 ev = event->attr.config;
468 if (ev >= ppmu->n_generic || ppmu->generic_events[ev] == 0)
469 return -EOPNOTSUPP;
470 ev = ppmu->generic_events[ev];
471 break;
472
473 case PERF_TYPE_HW_CACHE:
474 err = hw_perf_cache_event(event->attr.config, &ev);
475 if (err)
476 return err;
477 break;
478
479 case PERF_TYPE_RAW:
480 ev = event->attr.config;
481 break;
482
483 default:
484 return -ENOENT;
485 }
486
487 event->hw.config = ppmu->xlate_event(ev);
488 if (!(event->hw.config & FSL_EMB_EVENT_VALID))
489 return -EINVAL;
490
491 /*
492 * If this is in a group, check if it can go on with all the
493 * other hardware events in the group. We assume the event
494 * hasn't been linked into its leader's sibling list at this point.
495 */
496 n = 0;
497 if (event->group_leader != event) {
498 n = collect_events(event->group_leader,
499 ppmu->n_counter - 1, events);
500 if (n < 0)
501 return -EINVAL;
502 }
503
504 if (event->hw.config & FSL_EMB_EVENT_RESTRICTED) {
505 num_restricted = 0;
506 for (i = 0; i < n; i++) {
507 if (events[i]->hw.config & FSL_EMB_EVENT_RESTRICTED)
508 num_restricted++;
509 }
510
511 if (num_restricted >= ppmu->n_restricted)
512 return -EINVAL;
513 }
514
515 event->hw.idx = -1;
516
517 event->hw.config_base = PMLCA_CE | PMLCA_FCM1 |
518 (u32)((ev << 16) & PMLCA_EVENT_MASK);
519
520 if (event->attr.exclude_user)
521 event->hw.config_base |= PMLCA_FCU;
522 if (event->attr.exclude_kernel)
523 event->hw.config_base |= PMLCA_FCS;
524 if (event->attr.exclude_idle)
525 return -ENOTSUPP;
526
527 event->hw.last_period = event->hw.sample_period;
528 local64_set(&event->hw.period_left, event->hw.last_period);
529
530 /*
531 * See if we need to reserve the PMU.
532 * If no events are currently in use, then we have to take a
533 * mutex to ensure that we don't race with another task doing
534 * reserve_pmc_hardware or release_pmc_hardware.
535 */
536 err = 0;
537 if (!atomic_inc_not_zero(&num_events)) {
538 mutex_lock(&pmc_reserve_mutex);
539 if (atomic_read(&num_events) == 0 &&
540 reserve_pmc_hardware(perf_event_interrupt))
541 err = -EBUSY;
542 else
543 atomic_inc(&num_events);
544 mutex_unlock(&pmc_reserve_mutex);
545
546 mtpmr(PMRN_PMGC0, PMGC0_FAC);
547 isync();
548 }
549 event->destroy = hw_perf_event_destroy;
550
551 return err;
552}
553
554static struct pmu fsl_emb_pmu = {
555 .pmu_enable = fsl_emb_pmu_enable,
556 .pmu_disable = fsl_emb_pmu_disable,
557 .event_init = fsl_emb_pmu_event_init,
558 .add = fsl_emb_pmu_add,
559 .del = fsl_emb_pmu_del,
560 .start = fsl_emb_pmu_start,
561 .stop = fsl_emb_pmu_stop,
562 .read = fsl_emb_pmu_read,
563};
564
565/*
566 * A counter has overflowed; update its count and record
567 * things if requested. Note that interrupts are hard-disabled
568 * here so there is no possibility of being interrupted.
569 */
570static void record_and_restart(struct perf_event *event, unsigned long val,
571 struct pt_regs *regs)
572{
573 u64 period = event->hw.sample_period;
574 s64 prev, delta, left;
575 int record = 0;
576
577 if (event->hw.state & PERF_HES_STOPPED) {
578 write_pmc(event->hw.idx, 0);
579 return;
580 }
581
582 /* we don't have to worry about interrupts here */
583 prev = local64_read(&event->hw.prev_count);
584 delta = (val - prev) & 0xfffffffful;
585 local64_add(delta, &event->count);
586
587 /*
588 * See if the total period for this event has expired,
589 * and update for the next period.
590 */
591 val = 0;
592 left = local64_read(&event->hw.period_left) - delta;
593 if (period) {
594 if (left <= 0) {
595 left += period;
596 if (left <= 0)
597 left = period;
598 record = 1;
599 event->hw.last_period = event->hw.sample_period;
600 }
601 if (left < 0x80000000LL)
602 val = 0x80000000LL - left;
603 }
604
605 write_pmc(event->hw.idx, val);
606 local64_set(&event->hw.prev_count, val);
607 local64_set(&event->hw.period_left, left);
608 perf_event_update_userpage(event);
609
610 /*
611 * Finally record data if requested.
612 */
613 if (record) {
614 struct perf_sample_data data;
615
616 perf_sample_data_init(&data, 0);
617 data.period = event->hw.last_period;
618
619 if (perf_event_overflow(event, &data, regs))
620 fsl_emb_pmu_stop(event, 0);
621 }
622}
623
624static void perf_event_interrupt(struct pt_regs *regs)
625{
626 int i;
627 struct cpu_hw_events *cpuhw = &__get_cpu_var(cpu_hw_events);
628 struct perf_event *event;
629 unsigned long val;
630 int found = 0;
631 int nmi;
632
633 nmi = perf_intr_is_nmi(regs);
634 if (nmi)
635 nmi_enter();
636 else
637 irq_enter();
638
639 for (i = 0; i < ppmu->n_counter; ++i) {
640 event = cpuhw->event[i];
641
642 val = read_pmc(i);
643 if ((int)val < 0) {
644 if (event) {
645 /* event has overflowed */
646 found = 1;
647 record_and_restart(event, val, regs);
648 } else {
649 /*
650 * Disabled counter is negative,
651 * reset it just in case.
652 */
653 write_pmc(i, 0);
654 }
655 }
656 }
657
658 /* PMM will keep counters frozen until we return from the interrupt. */
659 mtmsr(mfmsr() | MSR_PMM);
660 mtpmr(PMRN_PMGC0, PMGC0_PMIE | PMGC0_FCECE);
661 isync();
662
663 if (nmi)
664 nmi_exit();
665 else
666 irq_exit();
667}
668
669void hw_perf_event_setup(int cpu)
670{
671 struct cpu_hw_events *cpuhw = &per_cpu(cpu_hw_events, cpu);
672
673 memset(cpuhw, 0, sizeof(*cpuhw));
674}
675
676int register_fsl_emb_pmu(struct fsl_emb_pmu *pmu)
677{
678 if (ppmu)
679 return -EBUSY; /* something's already registered */
680
681 ppmu = pmu;
682 pr_info("%s performance monitor hardware support registered\n",
683 pmu->name);
684
685 perf_pmu_register(&fsl_emb_pmu, "cpu", PERF_TYPE_RAW);
686
687 return 0;
688}
diff --git a/arch/powerpc/kernel/power4-pmu.c b/arch/powerpc/kernel/power4-pmu.c
new file mode 100644
index 00000000000..b4f1dda4d08
--- /dev/null
+++ b/arch/powerpc/kernel/power4-pmu.c
@@ -0,0 +1,621 @@
1/*
2 * Performance counter support for POWER4 (GP) and POWER4+ (GQ) processors.
3 *
4 * Copyright 2009 Paul Mackerras, IBM Corporation.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11#include <linux/kernel.h>
12#include <linux/perf_event.h>
13#include <linux/string.h>
14#include <asm/reg.h>
15#include <asm/cputable.h>
16
17/*
18 * Bits in event code for POWER4
19 */
20#define PM_PMC_SH 12 /* PMC number (1-based) for direct events */
21#define PM_PMC_MSK 0xf
22#define PM_UNIT_SH 8 /* TTMMUX number and setting - unit select */
23#define PM_UNIT_MSK 0xf
24#define PM_LOWER_SH 6
25#define PM_LOWER_MSK 1
26#define PM_LOWER_MSKS 0x40
27#define PM_BYTE_SH 4 /* Byte number of event bus to use */
28#define PM_BYTE_MSK 3
29#define PM_PMCSEL_MSK 7
30
31/*
32 * Unit code values
33 */
34#define PM_FPU 1
35#define PM_ISU1 2
36#define PM_IFU 3
37#define PM_IDU0 4
38#define PM_ISU1_ALT 6
39#define PM_ISU2 7
40#define PM_IFU_ALT 8
41#define PM_LSU0 9
42#define PM_LSU1 0xc
43#define PM_GPS 0xf
44
45/*
46 * Bits in MMCR0 for POWER4
47 */
48#define MMCR0_PMC1SEL_SH 8
49#define MMCR0_PMC2SEL_SH 1
50#define MMCR_PMCSEL_MSK 0x1f
51
52/*
53 * Bits in MMCR1 for POWER4
54 */
55#define MMCR1_TTM0SEL_SH 62
56#define MMCR1_TTC0SEL_SH 61
57#define MMCR1_TTM1SEL_SH 59
58#define MMCR1_TTC1SEL_SH 58
59#define MMCR1_TTM2SEL_SH 56
60#define MMCR1_TTC2SEL_SH 55
61#define MMCR1_TTM3SEL_SH 53
62#define MMCR1_TTC3SEL_SH 52
63#define MMCR1_TTMSEL_MSK 3
64#define MMCR1_TD_CP_DBG0SEL_SH 50
65#define MMCR1_TD_CP_DBG1SEL_SH 48
66#define MMCR1_TD_CP_DBG2SEL_SH 46
67#define MMCR1_TD_CP_DBG3SEL_SH 44
68#define MMCR1_DEBUG0SEL_SH 43
69#define MMCR1_DEBUG1SEL_SH 42
70#define MMCR1_DEBUG2SEL_SH 41
71#define MMCR1_DEBUG3SEL_SH 40
72#define MMCR1_PMC1_ADDER_SEL_SH 39
73#define MMCR1_PMC2_ADDER_SEL_SH 38
74#define MMCR1_PMC6_ADDER_SEL_SH 37
75#define MMCR1_PMC5_ADDER_SEL_SH 36
76#define MMCR1_PMC8_ADDER_SEL_SH 35
77#define MMCR1_PMC7_ADDER_SEL_SH 34
78#define MMCR1_PMC3_ADDER_SEL_SH 33
79#define MMCR1_PMC4_ADDER_SEL_SH 32
80#define MMCR1_PMC3SEL_SH 27
81#define MMCR1_PMC4SEL_SH 22
82#define MMCR1_PMC5SEL_SH 17
83#define MMCR1_PMC6SEL_SH 12
84#define MMCR1_PMC7SEL_SH 7
85#define MMCR1_PMC8SEL_SH 2 /* note bit 0 is in MMCRA for GP */
86
87static short mmcr1_adder_bits[8] = {
88 MMCR1_PMC1_ADDER_SEL_SH,
89 MMCR1_PMC2_ADDER_SEL_SH,
90 MMCR1_PMC3_ADDER_SEL_SH,
91 MMCR1_PMC4_ADDER_SEL_SH,
92 MMCR1_PMC5_ADDER_SEL_SH,
93 MMCR1_PMC6_ADDER_SEL_SH,
94 MMCR1_PMC7_ADDER_SEL_SH,
95 MMCR1_PMC8_ADDER_SEL_SH
96};
97
98/*
99 * Bits in MMCRA
100 */
101#define MMCRA_PMC8SEL0_SH 17 /* PMC8SEL bit 0 for GP */
102
103/*
104 * Layout of constraint bits:
105 * 6666555555555544444444443333333333222222222211111111110000000000
106 * 3210987654321098765432109876543210987654321098765432109876543210
107 * |[ >[ >[ >|||[ >[ >< >< >< >< ><><><><><><><><>
108 * | UC1 UC2 UC3 ||| PS1 PS2 B0 B1 B2 B3 P1P2P3P4P5P6P7P8
109 * \SMPL ||\TTC3SEL
110 * |\TTC_IFU_SEL
111 * \TTM2SEL0
112 *
113 * SMPL - SAMPLE_ENABLE constraint
114 * 56: SAMPLE_ENABLE value 0x0100_0000_0000_0000
115 *
116 * UC1 - unit constraint 1: can't have all three of FPU/ISU1/IDU0|ISU2
117 * 55: UC1 error 0x0080_0000_0000_0000
118 * 54: FPU events needed 0x0040_0000_0000_0000
119 * 53: ISU1 events needed 0x0020_0000_0000_0000
120 * 52: IDU0|ISU2 events needed 0x0010_0000_0000_0000
121 *
122 * UC2 - unit constraint 2: can't have all three of FPU/IFU/LSU0
123 * 51: UC2 error 0x0008_0000_0000_0000
124 * 50: FPU events needed 0x0004_0000_0000_0000
125 * 49: IFU events needed 0x0002_0000_0000_0000
126 * 48: LSU0 events needed 0x0001_0000_0000_0000
127 *
128 * UC3 - unit constraint 3: can't have all four of LSU0/IFU/IDU0|ISU2/ISU1
129 * 47: UC3 error 0x8000_0000_0000
130 * 46: LSU0 events needed 0x4000_0000_0000
131 * 45: IFU events needed 0x2000_0000_0000
132 * 44: IDU0|ISU2 events needed 0x1000_0000_0000
133 * 43: ISU1 events needed 0x0800_0000_0000
134 *
135 * TTM2SEL0
136 * 42: 0 = IDU0 events needed
137 * 1 = ISU2 events needed 0x0400_0000_0000
138 *
139 * TTC_IFU_SEL
140 * 41: 0 = IFU.U events needed
141 * 1 = IFU.L events needed 0x0200_0000_0000
142 *
143 * TTC3SEL
144 * 40: 0 = LSU1.U events needed
145 * 1 = LSU1.L events needed 0x0100_0000_0000
146 *
147 * PS1
148 * 39: PS1 error 0x0080_0000_0000
149 * 36-38: count of events needing PMC1/2/5/6 0x0070_0000_0000
150 *
151 * PS2
152 * 35: PS2 error 0x0008_0000_0000
153 * 32-34: count of events needing PMC3/4/7/8 0x0007_0000_0000
154 *
155 * B0
156 * 28-31: Byte 0 event source 0xf000_0000
157 * 1 = FPU
158 * 2 = ISU1
159 * 3 = IFU
160 * 4 = IDU0
161 * 7 = ISU2
162 * 9 = LSU0
163 * c = LSU1
164 * f = GPS
165 *
166 * B1, B2, B3
167 * 24-27, 20-23, 16-19: Byte 1, 2, 3 event sources
168 *
169 * P8
170 * 15: P8 error 0x8000
171 * 14-15: Count of events needing PMC8
172 *
173 * P1..P7
174 * 0-13: Count of events needing PMC1..PMC7
175 *
176 * Note: this doesn't allow events using IFU.U to be combined with events
177 * using IFU.L, though that is feasible (using TTM0 and TTM2). However
178 * there are no listed events for IFU.L (they are debug events not
179 * verified for performance monitoring) so this shouldn't cause a
180 * problem.
181 */
182
183static struct unitinfo {
184 unsigned long value, mask;
185 int unit;
186 int lowerbit;
187} p4_unitinfo[16] = {
188 [PM_FPU] = { 0x44000000000000ul, 0x88000000000000ul, PM_FPU, 0 },
189 [PM_ISU1] = { 0x20080000000000ul, 0x88000000000000ul, PM_ISU1, 0 },
190 [PM_ISU1_ALT] =
191 { 0x20080000000000ul, 0x88000000000000ul, PM_ISU1, 0 },
192 [PM_IFU] = { 0x02200000000000ul, 0x08820000000000ul, PM_IFU, 41 },
193 [PM_IFU_ALT] =
194 { 0x02200000000000ul, 0x08820000000000ul, PM_IFU, 41 },
195 [PM_IDU0] = { 0x10100000000000ul, 0x80840000000000ul, PM_IDU0, 1 },
196 [PM_ISU2] = { 0x10140000000000ul, 0x80840000000000ul, PM_ISU2, 0 },
197 [PM_LSU0] = { 0x01400000000000ul, 0x08800000000000ul, PM_LSU0, 0 },
198 [PM_LSU1] = { 0x00000000000000ul, 0x00010000000000ul, PM_LSU1, 40 },
199 [PM_GPS] = { 0x00000000000000ul, 0x00000000000000ul, PM_GPS, 0 }
200};
201
202static unsigned char direct_marked_event[8] = {
203 (1<<2) | (1<<3), /* PMC1: PM_MRK_GRP_DISP, PM_MRK_ST_CMPL */
204 (1<<3) | (1<<5), /* PMC2: PM_THRESH_TIMEO, PM_MRK_BRU_FIN */
205 (1<<3), /* PMC3: PM_MRK_ST_CMPL_INT */
206 (1<<4) | (1<<5), /* PMC4: PM_MRK_GRP_CMPL, PM_MRK_CRU_FIN */
207 (1<<4) | (1<<5), /* PMC5: PM_MRK_GRP_TIMEO */
208 (1<<3) | (1<<4) | (1<<5),
209 /* PMC6: PM_MRK_ST_GPS, PM_MRK_FXU_FIN, PM_MRK_GRP_ISSUED */
210 (1<<4) | (1<<5), /* PMC7: PM_MRK_FPU_FIN, PM_MRK_INST_FIN */
211 (1<<4), /* PMC8: PM_MRK_LSU_FIN */
212};
213
214/*
215 * Returns 1 if event counts things relating to marked instructions
216 * and thus needs the MMCRA_SAMPLE_ENABLE bit set, or 0 if not.
217 */
218static int p4_marked_instr_event(u64 event)
219{
220 int pmc, psel, unit, byte, bit;
221 unsigned int mask;
222
223 pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
224 psel = event & PM_PMCSEL_MSK;
225 if (pmc) {
226 if (direct_marked_event[pmc - 1] & (1 << psel))
227 return 1;
228 if (psel == 0) /* add events */
229 bit = (pmc <= 4)? pmc - 1: 8 - pmc;
230 else if (psel == 6) /* decode events */
231 bit = 4;
232 else
233 return 0;
234 } else
235 bit = psel;
236
237 byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
238 unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
239 mask = 0;
240 switch (unit) {
241 case PM_LSU1:
242 if (event & PM_LOWER_MSKS)
243 mask = 1 << 28; /* byte 7 bit 4 */
244 else
245 mask = 6 << 24; /* byte 3 bits 1 and 2 */
246 break;
247 case PM_LSU0:
248 /* byte 3, bit 3; byte 2 bits 0,2,3,4,5; byte 1 */
249 mask = 0x083dff00;
250 }
251 return (mask >> (byte * 8 + bit)) & 1;
252}
253
254static int p4_get_constraint(u64 event, unsigned long *maskp,
255 unsigned long *valp)
256{
257 int pmc, byte, unit, lower, sh;
258 unsigned long mask = 0, value = 0;
259 int grp = -1;
260
261 pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
262 if (pmc) {
263 if (pmc > 8)
264 return -1;
265 sh = (pmc - 1) * 2;
266 mask |= 2 << sh;
267 value |= 1 << sh;
268 grp = ((pmc - 1) >> 1) & 1;
269 }
270 unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
271 byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
272 if (unit) {
273 lower = (event >> PM_LOWER_SH) & PM_LOWER_MSK;
274
275 /*
276 * Bus events on bytes 0 and 2 can be counted
277 * on PMC1/2/5/6; bytes 1 and 3 on PMC3/4/7/8.
278 */
279 if (!pmc)
280 grp = byte & 1;
281
282 if (!p4_unitinfo[unit].unit)
283 return -1;
284 mask |= p4_unitinfo[unit].mask;
285 value |= p4_unitinfo[unit].value;
286 sh = p4_unitinfo[unit].lowerbit;
287 if (sh > 1)
288 value |= (unsigned long)lower << sh;
289 else if (lower != sh)
290 return -1;
291 unit = p4_unitinfo[unit].unit;
292
293 /* Set byte lane select field */
294 mask |= 0xfULL << (28 - 4 * byte);
295 value |= (unsigned long)unit << (28 - 4 * byte);
296 }
297 if (grp == 0) {
298 /* increment PMC1/2/5/6 field */
299 mask |= 0x8000000000ull;
300 value |= 0x1000000000ull;
301 } else {
302 /* increment PMC3/4/7/8 field */
303 mask |= 0x800000000ull;
304 value |= 0x100000000ull;
305 }
306
307 /* Marked instruction events need sample_enable set */
308 if (p4_marked_instr_event(event)) {
309 mask |= 1ull << 56;
310 value |= 1ull << 56;
311 }
312
313 /* PMCSEL=6 decode events on byte 2 need sample_enable clear */
314 if (pmc && (event & PM_PMCSEL_MSK) == 6 && byte == 2)
315 mask |= 1ull << 56;
316
317 *maskp = mask;
318 *valp = value;
319 return 0;
320}
321
322static unsigned int ppc_inst_cmpl[] = {
323 0x1001, 0x4001, 0x6001, 0x7001, 0x8001
324};
325
326static int p4_get_alternatives(u64 event, unsigned int flags, u64 alt[])
327{
328 int i, j, na;
329
330 alt[0] = event;
331 na = 1;
332
333 /* 2 possibilities for PM_GRP_DISP_REJECT */
334 if (event == 0x8003 || event == 0x0224) {
335 alt[1] = event ^ (0x8003 ^ 0x0224);
336 return 2;
337 }
338
339 /* 2 possibilities for PM_ST_MISS_L1 */
340 if (event == 0x0c13 || event == 0x0c23) {
341 alt[1] = event ^ (0x0c13 ^ 0x0c23);
342 return 2;
343 }
344
345 /* several possibilities for PM_INST_CMPL */
346 for (i = 0; i < ARRAY_SIZE(ppc_inst_cmpl); ++i) {
347 if (event == ppc_inst_cmpl[i]) {
348 for (j = 0; j < ARRAY_SIZE(ppc_inst_cmpl); ++j)
349 if (j != i)
350 alt[na++] = ppc_inst_cmpl[j];
351 break;
352 }
353 }
354
355 return na;
356}
357
358static int p4_compute_mmcr(u64 event[], int n_ev,
359 unsigned int hwc[], unsigned long mmcr[])
360{
361 unsigned long mmcr0 = 0, mmcr1 = 0, mmcra = 0;
362 unsigned int pmc, unit, byte, psel, lower;
363 unsigned int ttm, grp;
364 unsigned int pmc_inuse = 0;
365 unsigned int pmc_grp_use[2];
366 unsigned char busbyte[4];
367 unsigned char unituse[16];
368 unsigned int unitlower = 0;
369 int i;
370
371 if (n_ev > 8)
372 return -1;
373
374 /* First pass to count resource use */
375 pmc_grp_use[0] = pmc_grp_use[1] = 0;
376 memset(busbyte, 0, sizeof(busbyte));
377 memset(unituse, 0, sizeof(unituse));
378 for (i = 0; i < n_ev; ++i) {
379 pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
380 if (pmc) {
381 if (pmc_inuse & (1 << (pmc - 1)))
382 return -1;
383 pmc_inuse |= 1 << (pmc - 1);
384 /* count 1/2/5/6 vs 3/4/7/8 use */
385 ++pmc_grp_use[((pmc - 1) >> 1) & 1];
386 }
387 unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
388 byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK;
389 lower = (event[i] >> PM_LOWER_SH) & PM_LOWER_MSK;
390 if (unit) {
391 if (!pmc)
392 ++pmc_grp_use[byte & 1];
393 if (unit == 6 || unit == 8)
394 /* map alt ISU1/IFU codes: 6->2, 8->3 */
395 unit = (unit >> 1) - 1;
396 if (busbyte[byte] && busbyte[byte] != unit)
397 return -1;
398 busbyte[byte] = unit;
399 lower <<= unit;
400 if (unituse[unit] && lower != (unitlower & lower))
401 return -1;
402 unituse[unit] = 1;
403 unitlower |= lower;
404 }
405 }
406 if (pmc_grp_use[0] > 4 || pmc_grp_use[1] > 4)
407 return -1;
408
409 /*
410 * Assign resources and set multiplexer selects.
411 *
412 * Units 1,2,3 are on TTM0, 4,6,7 on TTM1, 8,10 on TTM2.
413 * Each TTMx can only select one unit, but since
414 * units 2 and 6 are both ISU1, and 3 and 8 are both IFU,
415 * we have some choices.
416 */
417 if (unituse[2] & (unituse[1] | (unituse[3] & unituse[9]))) {
418 unituse[6] = 1; /* Move 2 to 6 */
419 unituse[2] = 0;
420 }
421 if (unituse[3] & (unituse[1] | unituse[2])) {
422 unituse[8] = 1; /* Move 3 to 8 */
423 unituse[3] = 0;
424 unitlower = (unitlower & ~8) | ((unitlower & 8) << 5);
425 }
426 /* Check only one unit per TTMx */
427 if (unituse[1] + unituse[2] + unituse[3] > 1 ||
428 unituse[4] + unituse[6] + unituse[7] > 1 ||
429 unituse[8] + unituse[9] > 1 ||
430 (unituse[5] | unituse[10] | unituse[11] |
431 unituse[13] | unituse[14]))
432 return -1;
433
434 /* Set TTMxSEL fields. Note, units 1-3 => TTM0SEL codes 0-2 */
435 mmcr1 |= (unsigned long)(unituse[3] * 2 + unituse[2])
436 << MMCR1_TTM0SEL_SH;
437 mmcr1 |= (unsigned long)(unituse[7] * 3 + unituse[6] * 2)
438 << MMCR1_TTM1SEL_SH;
439 mmcr1 |= (unsigned long)unituse[9] << MMCR1_TTM2SEL_SH;
440
441 /* Set TTCxSEL fields. */
442 if (unitlower & 0xe)
443 mmcr1 |= 1ull << MMCR1_TTC0SEL_SH;
444 if (unitlower & 0xf0)
445 mmcr1 |= 1ull << MMCR1_TTC1SEL_SH;
446 if (unitlower & 0xf00)
447 mmcr1 |= 1ull << MMCR1_TTC2SEL_SH;
448 if (unitlower & 0x7000)
449 mmcr1 |= 1ull << MMCR1_TTC3SEL_SH;
450
451 /* Set byte lane select fields. */
452 for (byte = 0; byte < 4; ++byte) {
453 unit = busbyte[byte];
454 if (!unit)
455 continue;
456 if (unit == 0xf) {
457 /* special case for GPS */
458 mmcr1 |= 1ull << (MMCR1_DEBUG0SEL_SH - byte);
459 } else {
460 if (!unituse[unit])
461 ttm = unit - 1; /* 2->1, 3->2 */
462 else
463 ttm = unit >> 2;
464 mmcr1 |= (unsigned long)ttm
465 << (MMCR1_TD_CP_DBG0SEL_SH - 2 * byte);
466 }
467 }
468
469 /* Second pass: assign PMCs, set PMCxSEL and PMCx_ADDER_SEL fields */
470 for (i = 0; i < n_ev; ++i) {
471 pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
472 unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
473 byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK;
474 psel = event[i] & PM_PMCSEL_MSK;
475 if (!pmc) {
476 /* Bus event or 00xxx direct event (off or cycles) */
477 if (unit)
478 psel |= 0x10 | ((byte & 2) << 2);
479 for (pmc = 0; pmc < 8; ++pmc) {
480 if (pmc_inuse & (1 << pmc))
481 continue;
482 grp = (pmc >> 1) & 1;
483 if (unit) {
484 if (grp == (byte & 1))
485 break;
486 } else if (pmc_grp_use[grp] < 4) {
487 ++pmc_grp_use[grp];
488 break;
489 }
490 }
491 pmc_inuse |= 1 << pmc;
492 } else {
493 /* Direct event */
494 --pmc;
495 if (psel == 0 && (byte & 2))
496 /* add events on higher-numbered bus */
497 mmcr1 |= 1ull << mmcr1_adder_bits[pmc];
498 else if (psel == 6 && byte == 3)
499 /* seem to need to set sample_enable here */
500 mmcra |= MMCRA_SAMPLE_ENABLE;
501 psel |= 8;
502 }
503 if (pmc <= 1)
504 mmcr0 |= psel << (MMCR0_PMC1SEL_SH - 7 * pmc);
505 else
506 mmcr1 |= psel << (MMCR1_PMC3SEL_SH - 5 * (pmc - 2));
507 if (pmc == 7) /* PMC8 */
508 mmcra |= (psel & 1) << MMCRA_PMC8SEL0_SH;
509 hwc[i] = pmc;
510 if (p4_marked_instr_event(event[i]))
511 mmcra |= MMCRA_SAMPLE_ENABLE;
512 }
513
514 if (pmc_inuse & 1)
515 mmcr0 |= MMCR0_PMC1CE;
516 if (pmc_inuse & 0xfe)
517 mmcr0 |= MMCR0_PMCjCE;
518
519 mmcra |= 0x2000; /* mark only one IOP per PPC instruction */
520
521 /* Return MMCRx values */
522 mmcr[0] = mmcr0;
523 mmcr[1] = mmcr1;
524 mmcr[2] = mmcra;
525 return 0;
526}
527
528static void p4_disable_pmc(unsigned int pmc, unsigned long mmcr[])
529{
530 /*
531 * Setting the PMCxSEL field to 0 disables PMC x.
532 * (Note that pmc is 0-based here, not 1-based.)
533 */
534 if (pmc <= 1) {
535 mmcr[0] &= ~(0x1fUL << (MMCR0_PMC1SEL_SH - 7 * pmc));
536 } else {
537 mmcr[1] &= ~(0x1fUL << (MMCR1_PMC3SEL_SH - 5 * (pmc - 2)));
538 if (pmc == 7)
539 mmcr[2] &= ~(1UL << MMCRA_PMC8SEL0_SH);
540 }
541}
542
543static int p4_generic_events[] = {
544 [PERF_COUNT_HW_CPU_CYCLES] = 7,
545 [PERF_COUNT_HW_INSTRUCTIONS] = 0x1001,
546 [PERF_COUNT_HW_CACHE_REFERENCES] = 0x8c10, /* PM_LD_REF_L1 */
547 [PERF_COUNT_HW_CACHE_MISSES] = 0x3c10, /* PM_LD_MISS_L1 */
548 [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x330, /* PM_BR_ISSUED */
549 [PERF_COUNT_HW_BRANCH_MISSES] = 0x331, /* PM_BR_MPRED_CR */
550};
551
552#define C(x) PERF_COUNT_HW_CACHE_##x
553
554/*
555 * Table of generalized cache-related events.
556 * 0 means not supported, -1 means nonsensical, other values
557 * are event codes.
558 */
559static int power4_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
560 [C(L1D)] = { /* RESULT_ACCESS RESULT_MISS */
561 [C(OP_READ)] = { 0x8c10, 0x3c10 },
562 [C(OP_WRITE)] = { 0x7c10, 0xc13 },
563 [C(OP_PREFETCH)] = { 0xc35, 0 },
564 },
565 [C(L1I)] = { /* RESULT_ACCESS RESULT_MISS */
566 [C(OP_READ)] = { 0, 0 },
567 [C(OP_WRITE)] = { -1, -1 },
568 [C(OP_PREFETCH)] = { 0, 0 },
569 },
570 [C(LL)] = { /* RESULT_ACCESS RESULT_MISS */
571 [C(OP_READ)] = { 0, 0 },
572 [C(OP_WRITE)] = { 0, 0 },
573 [C(OP_PREFETCH)] = { 0xc34, 0 },
574 },
575 [C(DTLB)] = { /* RESULT_ACCESS RESULT_MISS */
576 [C(OP_READ)] = { 0, 0x904 },
577 [C(OP_WRITE)] = { -1, -1 },
578 [C(OP_PREFETCH)] = { -1, -1 },
579 },
580 [C(ITLB)] = { /* RESULT_ACCESS RESULT_MISS */
581 [C(OP_READ)] = { 0, 0x900 },
582 [C(OP_WRITE)] = { -1, -1 },
583 [C(OP_PREFETCH)] = { -1, -1 },
584 },
585 [C(BPU)] = { /* RESULT_ACCESS RESULT_MISS */
586 [C(OP_READ)] = { 0x330, 0x331 },
587 [C(OP_WRITE)] = { -1, -1 },
588 [C(OP_PREFETCH)] = { -1, -1 },
589 },
590 [C(NODE)] = { /* RESULT_ACCESS RESULT_MISS */
591 [C(OP_READ)] = { -1, -1 },
592 [C(OP_WRITE)] = { -1, -1 },
593 [C(OP_PREFETCH)] = { -1, -1 },
594 },
595};
596
597static struct power_pmu power4_pmu = {
598 .name = "POWER4/4+",
599 .n_counter = 8,
600 .max_alternatives = 5,
601 .add_fields = 0x0000001100005555ul,
602 .test_adder = 0x0011083300000000ul,
603 .compute_mmcr = p4_compute_mmcr,
604 .get_constraint = p4_get_constraint,
605 .get_alternatives = p4_get_alternatives,
606 .disable_pmc = p4_disable_pmc,
607 .n_generic = ARRAY_SIZE(p4_generic_events),
608 .generic_events = p4_generic_events,
609 .cache_events = &power4_cache_events,
610};
611
612static int __init init_power4_pmu(void)
613{
614 if (!cur_cpu_spec->oprofile_cpu_type ||
615 strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power4"))
616 return -ENODEV;
617
618 return register_power_pmu(&power4_pmu);
619}
620
621early_initcall(init_power4_pmu);
diff --git a/arch/powerpc/kernel/power5+-pmu.c b/arch/powerpc/kernel/power5+-pmu.c
new file mode 100644
index 00000000000..a8757baa28f
--- /dev/null
+++ b/arch/powerpc/kernel/power5+-pmu.c
@@ -0,0 +1,690 @@
1/*
2 * Performance counter support for POWER5+/++ (not POWER5) processors.
3 *
4 * Copyright 2009 Paul Mackerras, IBM Corporation.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11#include <linux/kernel.h>
12#include <linux/perf_event.h>
13#include <linux/string.h>
14#include <asm/reg.h>
15#include <asm/cputable.h>
16
17/*
18 * Bits in event code for POWER5+ (POWER5 GS) and POWER5++ (POWER5 GS DD3)
19 */
20#define PM_PMC_SH 20 /* PMC number (1-based) for direct events */
21#define PM_PMC_MSK 0xf
22#define PM_PMC_MSKS (PM_PMC_MSK << PM_PMC_SH)
23#define PM_UNIT_SH 16 /* TTMMUX number and setting - unit select */
24#define PM_UNIT_MSK 0xf
25#define PM_BYTE_SH 12 /* Byte number of event bus to use */
26#define PM_BYTE_MSK 7
27#define PM_GRS_SH 8 /* Storage subsystem mux select */
28#define PM_GRS_MSK 7
29#define PM_BUSEVENT_MSK 0x80 /* Set if event uses event bus */
30#define PM_PMCSEL_MSK 0x7f
31
32/* Values in PM_UNIT field */
33#define PM_FPU 0
34#define PM_ISU0 1
35#define PM_IFU 2
36#define PM_ISU1 3
37#define PM_IDU 4
38#define PM_ISU0_ALT 6
39#define PM_GRS 7
40#define PM_LSU0 8
41#define PM_LSU1 0xc
42#define PM_LASTUNIT 0xc
43
44/*
45 * Bits in MMCR1 for POWER5+
46 */
47#define MMCR1_TTM0SEL_SH 62
48#define MMCR1_TTM1SEL_SH 60
49#define MMCR1_TTM2SEL_SH 58
50#define MMCR1_TTM3SEL_SH 56
51#define MMCR1_TTMSEL_MSK 3
52#define MMCR1_TD_CP_DBG0SEL_SH 54
53#define MMCR1_TD_CP_DBG1SEL_SH 52
54#define MMCR1_TD_CP_DBG2SEL_SH 50
55#define MMCR1_TD_CP_DBG3SEL_SH 48
56#define MMCR1_GRS_L2SEL_SH 46
57#define MMCR1_GRS_L2SEL_MSK 3
58#define MMCR1_GRS_L3SEL_SH 44
59#define MMCR1_GRS_L3SEL_MSK 3
60#define MMCR1_GRS_MCSEL_SH 41
61#define MMCR1_GRS_MCSEL_MSK 7
62#define MMCR1_GRS_FABSEL_SH 39
63#define MMCR1_GRS_FABSEL_MSK 3
64#define MMCR1_PMC1_ADDER_SEL_SH 35
65#define MMCR1_PMC2_ADDER_SEL_SH 34
66#define MMCR1_PMC3_ADDER_SEL_SH 33
67#define MMCR1_PMC4_ADDER_SEL_SH 32
68#define MMCR1_PMC1SEL_SH 25
69#define MMCR1_PMC2SEL_SH 17
70#define MMCR1_PMC3SEL_SH 9
71#define MMCR1_PMC4SEL_SH 1
72#define MMCR1_PMCSEL_SH(n) (MMCR1_PMC1SEL_SH - (n) * 8)
73#define MMCR1_PMCSEL_MSK 0x7f
74
75/*
76 * Layout of constraint bits:
77 * 6666555555555544444444443333333333222222222211111111110000000000
78 * 3210987654321098765432109876543210987654321098765432109876543210
79 * [ ><><>< ><> <><>[ > < >< >< >< ><><><><><><>
80 * NC G0G1G2 G3 T0T1 UC B0 B1 B2 B3 P6P5P4P3P2P1
81 *
82 * NC - number of counters
83 * 51: NC error 0x0008_0000_0000_0000
84 * 48-50: number of events needing PMC1-4 0x0007_0000_0000_0000
85 *
86 * G0..G3 - GRS mux constraints
87 * 46-47: GRS_L2SEL value
88 * 44-45: GRS_L3SEL value
89 * 41-44: GRS_MCSEL value
90 * 39-40: GRS_FABSEL value
91 * Note that these match up with their bit positions in MMCR1
92 *
93 * T0 - TTM0 constraint
94 * 36-37: TTM0SEL value (0=FPU, 2=IFU, 3=ISU1) 0x30_0000_0000
95 *
96 * T1 - TTM1 constraint
97 * 34-35: TTM1SEL value (0=IDU, 3=GRS) 0x0c_0000_0000
98 *
99 * UC - unit constraint: can't have all three of FPU|IFU|ISU1, ISU0, IDU|GRS
100 * 33: UC3 error 0x02_0000_0000
101 * 32: FPU|IFU|ISU1 events needed 0x01_0000_0000
102 * 31: ISU0 events needed 0x01_8000_0000
103 * 30: IDU|GRS events needed 0x00_4000_0000
104 *
105 * B0
106 * 24-27: Byte 0 event source 0x0f00_0000
107 * Encoding as for the event code
108 *
109 * B1, B2, B3
110 * 20-23, 16-19, 12-15: Byte 1, 2, 3 event sources
111 *
112 * P6
113 * 11: P6 error 0x800
114 * 10-11: Count of events needing PMC6
115 *
116 * P1..P5
117 * 0-9: Count of events needing PMC1..PMC5
118 */
119
120static const int grsel_shift[8] = {
121 MMCR1_GRS_L2SEL_SH, MMCR1_GRS_L2SEL_SH, MMCR1_GRS_L2SEL_SH,
122 MMCR1_GRS_L3SEL_SH, MMCR1_GRS_L3SEL_SH, MMCR1_GRS_L3SEL_SH,
123 MMCR1_GRS_MCSEL_SH, MMCR1_GRS_FABSEL_SH
124};
125
126/* Masks and values for using events from the various units */
127static unsigned long unit_cons[PM_LASTUNIT+1][2] = {
128 [PM_FPU] = { 0x3200000000ul, 0x0100000000ul },
129 [PM_ISU0] = { 0x0200000000ul, 0x0080000000ul },
130 [PM_ISU1] = { 0x3200000000ul, 0x3100000000ul },
131 [PM_IFU] = { 0x3200000000ul, 0x2100000000ul },
132 [PM_IDU] = { 0x0e00000000ul, 0x0040000000ul },
133 [PM_GRS] = { 0x0e00000000ul, 0x0c40000000ul },
134};
135
136static int power5p_get_constraint(u64 event, unsigned long *maskp,
137 unsigned long *valp)
138{
139 int pmc, byte, unit, sh;
140 int bit, fmask;
141 unsigned long mask = 0, value = 0;
142
143 pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
144 if (pmc) {
145 if (pmc > 6)
146 return -1;
147 sh = (pmc - 1) * 2;
148 mask |= 2 << sh;
149 value |= 1 << sh;
150 if (pmc >= 5 && !(event == 0x500009 || event == 0x600005))
151 return -1;
152 }
153 if (event & PM_BUSEVENT_MSK) {
154 unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
155 if (unit > PM_LASTUNIT)
156 return -1;
157 if (unit == PM_ISU0_ALT)
158 unit = PM_ISU0;
159 mask |= unit_cons[unit][0];
160 value |= unit_cons[unit][1];
161 byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
162 if (byte >= 4) {
163 if (unit != PM_LSU1)
164 return -1;
165 /* Map LSU1 low word (bytes 4-7) to unit LSU1+1 */
166 ++unit;
167 byte &= 3;
168 }
169 if (unit == PM_GRS) {
170 bit = event & 7;
171 fmask = (bit == 6)? 7: 3;
172 sh = grsel_shift[bit];
173 mask |= (unsigned long)fmask << sh;
174 value |= (unsigned long)((event >> PM_GRS_SH) & fmask)
175 << sh;
176 }
177 /* Set byte lane select field */
178 mask |= 0xfUL << (24 - 4 * byte);
179 value |= (unsigned long)unit << (24 - 4 * byte);
180 }
181 if (pmc < 5) {
182 /* need a counter from PMC1-4 set */
183 mask |= 0x8000000000000ul;
184 value |= 0x1000000000000ul;
185 }
186 *maskp = mask;
187 *valp = value;
188 return 0;
189}
190
191static int power5p_limited_pmc_event(u64 event)
192{
193 int pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
194
195 return pmc == 5 || pmc == 6;
196}
197
198#define MAX_ALT 3 /* at most 3 alternatives for any event */
199
200static const unsigned int event_alternatives[][MAX_ALT] = {
201 { 0x100c0, 0x40001f }, /* PM_GCT_FULL_CYC */
202 { 0x120e4, 0x400002 }, /* PM_GRP_DISP_REJECT */
203 { 0x230e2, 0x323087 }, /* PM_BR_PRED_CR */
204 { 0x230e3, 0x223087, 0x3230a0 }, /* PM_BR_PRED_TA */
205 { 0x410c7, 0x441084 }, /* PM_THRD_L2MISS_BOTH_CYC */
206 { 0x800c4, 0xc20e0 }, /* PM_DTLB_MISS */
207 { 0xc50c6, 0xc60e0 }, /* PM_MRK_DTLB_MISS */
208 { 0x100005, 0x600005 }, /* PM_RUN_CYC */
209 { 0x100009, 0x200009 }, /* PM_INST_CMPL */
210 { 0x200015, 0x300015 }, /* PM_LSU_LMQ_SRQ_EMPTY_CYC */
211 { 0x300009, 0x400009 }, /* PM_INST_DISP */
212};
213
214/*
215 * Scan the alternatives table for a match and return the
216 * index into the alternatives table if found, else -1.
217 */
218static int find_alternative(unsigned int event)
219{
220 int i, j;
221
222 for (i = 0; i < ARRAY_SIZE(event_alternatives); ++i) {
223 if (event < event_alternatives[i][0])
224 break;
225 for (j = 0; j < MAX_ALT && event_alternatives[i][j]; ++j)
226 if (event == event_alternatives[i][j])
227 return i;
228 }
229 return -1;
230}
231
232static const unsigned char bytedecode_alternatives[4][4] = {
233 /* PMC 1 */ { 0x21, 0x23, 0x25, 0x27 },
234 /* PMC 2 */ { 0x07, 0x17, 0x0e, 0x1e },
235 /* PMC 3 */ { 0x20, 0x22, 0x24, 0x26 },
236 /* PMC 4 */ { 0x07, 0x17, 0x0e, 0x1e }
237};
238
239/*
240 * Some direct events for decodes of event bus byte 3 have alternative
241 * PMCSEL values on other counters. This returns the alternative
242 * event code for those that do, or -1 otherwise. This also handles
243 * alternative PCMSEL values for add events.
244 */
245static s64 find_alternative_bdecode(u64 event)
246{
247 int pmc, altpmc, pp, j;
248
249 pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
250 if (pmc == 0 || pmc > 4)
251 return -1;
252 altpmc = 5 - pmc; /* 1 <-> 4, 2 <-> 3 */
253 pp = event & PM_PMCSEL_MSK;
254 for (j = 0; j < 4; ++j) {
255 if (bytedecode_alternatives[pmc - 1][j] == pp) {
256 return (event & ~(PM_PMC_MSKS | PM_PMCSEL_MSK)) |
257 (altpmc << PM_PMC_SH) |
258 bytedecode_alternatives[altpmc - 1][j];
259 }
260 }
261
262 /* new decode alternatives for power5+ */
263 if (pmc == 1 && (pp == 0x0d || pp == 0x0e))
264 return event + (2 << PM_PMC_SH) + (0x2e - 0x0d);
265 if (pmc == 3 && (pp == 0x2e || pp == 0x2f))
266 return event - (2 << PM_PMC_SH) - (0x2e - 0x0d);
267
268 /* alternative add event encodings */
269 if (pp == 0x10 || pp == 0x28)
270 return ((event ^ (0x10 ^ 0x28)) & ~PM_PMC_MSKS) |
271 (altpmc << PM_PMC_SH);
272
273 return -1;
274}
275
276static int power5p_get_alternatives(u64 event, unsigned int flags, u64 alt[])
277{
278 int i, j, nalt = 1;
279 int nlim;
280 s64 ae;
281
282 alt[0] = event;
283 nalt = 1;
284 nlim = power5p_limited_pmc_event(event);
285 i = find_alternative(event);
286 if (i >= 0) {
287 for (j = 0; j < MAX_ALT; ++j) {
288 ae = event_alternatives[i][j];
289 if (ae && ae != event)
290 alt[nalt++] = ae;
291 nlim += power5p_limited_pmc_event(ae);
292 }
293 } else {
294 ae = find_alternative_bdecode(event);
295 if (ae > 0)
296 alt[nalt++] = ae;
297 }
298
299 if (flags & PPMU_ONLY_COUNT_RUN) {
300 /*
301 * We're only counting in RUN state,
302 * so PM_CYC is equivalent to PM_RUN_CYC
303 * and PM_INST_CMPL === PM_RUN_INST_CMPL.
304 * This doesn't include alternatives that don't provide
305 * any extra flexibility in assigning PMCs (e.g.
306 * 0x100005 for PM_RUN_CYC vs. 0xf for PM_CYC).
307 * Note that even with these additional alternatives
308 * we never end up with more than 3 alternatives for any event.
309 */
310 j = nalt;
311 for (i = 0; i < nalt; ++i) {
312 switch (alt[i]) {
313 case 0xf: /* PM_CYC */
314 alt[j++] = 0x600005; /* PM_RUN_CYC */
315 ++nlim;
316 break;
317 case 0x600005: /* PM_RUN_CYC */
318 alt[j++] = 0xf;
319 break;
320 case 0x100009: /* PM_INST_CMPL */
321 alt[j++] = 0x500009; /* PM_RUN_INST_CMPL */
322 ++nlim;
323 break;
324 case 0x500009: /* PM_RUN_INST_CMPL */
325 alt[j++] = 0x100009; /* PM_INST_CMPL */
326 alt[j++] = 0x200009;
327 break;
328 }
329 }
330 nalt = j;
331 }
332
333 if (!(flags & PPMU_LIMITED_PMC_OK) && nlim) {
334 /* remove the limited PMC events */
335 j = 0;
336 for (i = 0; i < nalt; ++i) {
337 if (!power5p_limited_pmc_event(alt[i])) {
338 alt[j] = alt[i];
339 ++j;
340 }
341 }
342 nalt = j;
343 } else if ((flags & PPMU_LIMITED_PMC_REQD) && nlim < nalt) {
344 /* remove all but the limited PMC events */
345 j = 0;
346 for (i = 0; i < nalt; ++i) {
347 if (power5p_limited_pmc_event(alt[i])) {
348 alt[j] = alt[i];
349 ++j;
350 }
351 }
352 nalt = j;
353 }
354
355 return nalt;
356}
357
358/*
359 * Map of which direct events on which PMCs are marked instruction events.
360 * Indexed by PMCSEL value, bit i (LE) set if PMC i is a marked event.
361 * Bit 0 is set if it is marked for all PMCs.
362 * The 0x80 bit indicates a byte decode PMCSEL value.
363 */
364static unsigned char direct_event_is_marked[0x28] = {
365 0, /* 00 */
366 0x1f, /* 01 PM_IOPS_CMPL */
367 0x2, /* 02 PM_MRK_GRP_DISP */
368 0xe, /* 03 PM_MRK_ST_CMPL, PM_MRK_ST_GPS, PM_MRK_ST_CMPL_INT */
369 0, /* 04 */
370 0x1c, /* 05 PM_MRK_BRU_FIN, PM_MRK_INST_FIN, PM_MRK_CRU_FIN */
371 0x80, /* 06 */
372 0x80, /* 07 */
373 0, 0, 0,/* 08 - 0a */
374 0x18, /* 0b PM_THRESH_TIMEO, PM_MRK_GRP_TIMEO */
375 0, /* 0c */
376 0x80, /* 0d */
377 0x80, /* 0e */
378 0, /* 0f */
379 0, /* 10 */
380 0x14, /* 11 PM_MRK_GRP_BR_REDIR, PM_MRK_GRP_IC_MISS */
381 0, /* 12 */
382 0x10, /* 13 PM_MRK_GRP_CMPL */
383 0x1f, /* 14 PM_GRP_MRK, PM_MRK_{FXU,FPU,LSU}_FIN */
384 0x2, /* 15 PM_MRK_GRP_ISSUED */
385 0x80, /* 16 */
386 0x80, /* 17 */
387 0, 0, 0, 0, 0,
388 0x80, /* 1d */
389 0x80, /* 1e */
390 0, /* 1f */
391 0x80, /* 20 */
392 0x80, /* 21 */
393 0x80, /* 22 */
394 0x80, /* 23 */
395 0x80, /* 24 */
396 0x80, /* 25 */
397 0x80, /* 26 */
398 0x80, /* 27 */
399};
400
401/*
402 * Returns 1 if event counts things relating to marked instructions
403 * and thus needs the MMCRA_SAMPLE_ENABLE bit set, or 0 if not.
404 */
405static int power5p_marked_instr_event(u64 event)
406{
407 int pmc, psel;
408 int bit, byte, unit;
409 u32 mask;
410
411 pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
412 psel = event & PM_PMCSEL_MSK;
413 if (pmc >= 5)
414 return 0;
415
416 bit = -1;
417 if (psel < sizeof(direct_event_is_marked)) {
418 if (direct_event_is_marked[psel] & (1 << pmc))
419 return 1;
420 if (direct_event_is_marked[psel] & 0x80)
421 bit = 4;
422 else if (psel == 0x08)
423 bit = pmc - 1;
424 else if (psel == 0x10)
425 bit = 4 - pmc;
426 else if (psel == 0x1b && (pmc == 1 || pmc == 3))
427 bit = 4;
428 } else if ((psel & 0x48) == 0x40) {
429 bit = psel & 7;
430 } else if (psel == 0x28) {
431 bit = pmc - 1;
432 } else if (pmc == 3 && (psel == 0x2e || psel == 0x2f)) {
433 bit = 4;
434 }
435
436 if (!(event & PM_BUSEVENT_MSK) || bit == -1)
437 return 0;
438
439 byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
440 unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
441 if (unit == PM_LSU0) {
442 /* byte 1 bits 0-7, byte 2 bits 0,2-4,6 */
443 mask = 0x5dff00;
444 } else if (unit == PM_LSU1 && byte >= 4) {
445 byte -= 4;
446 /* byte 5 bits 6-7, byte 6 bits 0,4, byte 7 bits 0-4,6 */
447 mask = 0x5f11c000;
448 } else
449 return 0;
450
451 return (mask >> (byte * 8 + bit)) & 1;
452}
453
454static int power5p_compute_mmcr(u64 event[], int n_ev,
455 unsigned int hwc[], unsigned long mmcr[])
456{
457 unsigned long mmcr1 = 0;
458 unsigned long mmcra = 0;
459 unsigned int pmc, unit, byte, psel;
460 unsigned int ttm;
461 int i, isbus, bit, grsel;
462 unsigned int pmc_inuse = 0;
463 unsigned char busbyte[4];
464 unsigned char unituse[16];
465 int ttmuse;
466
467 if (n_ev > 6)
468 return -1;
469
470 /* First pass to count resource use */
471 memset(busbyte, 0, sizeof(busbyte));
472 memset(unituse, 0, sizeof(unituse));
473 for (i = 0; i < n_ev; ++i) {
474 pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
475 if (pmc) {
476 if (pmc > 6)
477 return -1;
478 if (pmc_inuse & (1 << (pmc - 1)))
479 return -1;
480 pmc_inuse |= 1 << (pmc - 1);
481 }
482 if (event[i] & PM_BUSEVENT_MSK) {
483 unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
484 byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK;
485 if (unit > PM_LASTUNIT)
486 return -1;
487 if (unit == PM_ISU0_ALT)
488 unit = PM_ISU0;
489 if (byte >= 4) {
490 if (unit != PM_LSU1)
491 return -1;
492 ++unit;
493 byte &= 3;
494 }
495 if (busbyte[byte] && busbyte[byte] != unit)
496 return -1;
497 busbyte[byte] = unit;
498 unituse[unit] = 1;
499 }
500 }
501
502 /*
503 * Assign resources and set multiplexer selects.
504 *
505 * PM_ISU0 can go either on TTM0 or TTM1, but that's the only
506 * choice we have to deal with.
507 */
508 if (unituse[PM_ISU0] &
509 (unituse[PM_FPU] | unituse[PM_IFU] | unituse[PM_ISU1])) {
510 unituse[PM_ISU0_ALT] = 1; /* move ISU to TTM1 */
511 unituse[PM_ISU0] = 0;
512 }
513 /* Set TTM[01]SEL fields. */
514 ttmuse = 0;
515 for (i = PM_FPU; i <= PM_ISU1; ++i) {
516 if (!unituse[i])
517 continue;
518 if (ttmuse++)
519 return -1;
520 mmcr1 |= (unsigned long)i << MMCR1_TTM0SEL_SH;
521 }
522 ttmuse = 0;
523 for (; i <= PM_GRS; ++i) {
524 if (!unituse[i])
525 continue;
526 if (ttmuse++)
527 return -1;
528 mmcr1 |= (unsigned long)(i & 3) << MMCR1_TTM1SEL_SH;
529 }
530 if (ttmuse > 1)
531 return -1;
532
533 /* Set byte lane select fields, TTM[23]SEL and GRS_*SEL. */
534 for (byte = 0; byte < 4; ++byte) {
535 unit = busbyte[byte];
536 if (!unit)
537 continue;
538 if (unit == PM_ISU0 && unituse[PM_ISU0_ALT]) {
539 /* get ISU0 through TTM1 rather than TTM0 */
540 unit = PM_ISU0_ALT;
541 } else if (unit == PM_LSU1 + 1) {
542 /* select lower word of LSU1 for this byte */
543 mmcr1 |= 1ul << (MMCR1_TTM3SEL_SH + 3 - byte);
544 }
545 ttm = unit >> 2;
546 mmcr1 |= (unsigned long)ttm
547 << (MMCR1_TD_CP_DBG0SEL_SH - 2 * byte);
548 }
549
550 /* Second pass: assign PMCs, set PMCxSEL and PMCx_ADDER_SEL fields */
551 for (i = 0; i < n_ev; ++i) {
552 pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
553 unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
554 byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK;
555 psel = event[i] & PM_PMCSEL_MSK;
556 isbus = event[i] & PM_BUSEVENT_MSK;
557 if (!pmc) {
558 /* Bus event or any-PMC direct event */
559 for (pmc = 0; pmc < 4; ++pmc) {
560 if (!(pmc_inuse & (1 << pmc)))
561 break;
562 }
563 if (pmc >= 4)
564 return -1;
565 pmc_inuse |= 1 << pmc;
566 } else if (pmc <= 4) {
567 /* Direct event */
568 --pmc;
569 if (isbus && (byte & 2) &&
570 (psel == 8 || psel == 0x10 || psel == 0x28))
571 /* add events on higher-numbered bus */
572 mmcr1 |= 1ul << (MMCR1_PMC1_ADDER_SEL_SH - pmc);
573 } else {
574 /* Instructions or run cycles on PMC5/6 */
575 --pmc;
576 }
577 if (isbus && unit == PM_GRS) {
578 bit = psel & 7;
579 grsel = (event[i] >> PM_GRS_SH) & PM_GRS_MSK;
580 mmcr1 |= (unsigned long)grsel << grsel_shift[bit];
581 }
582 if (power5p_marked_instr_event(event[i]))
583 mmcra |= MMCRA_SAMPLE_ENABLE;
584 if ((psel & 0x58) == 0x40 && (byte & 1) != ((pmc >> 1) & 1))
585 /* select alternate byte lane */
586 psel |= 0x10;
587 if (pmc <= 3)
588 mmcr1 |= psel << MMCR1_PMCSEL_SH(pmc);
589 hwc[i] = pmc;
590 }
591
592 /* Return MMCRx values */
593 mmcr[0] = 0;
594 if (pmc_inuse & 1)
595 mmcr[0] = MMCR0_PMC1CE;
596 if (pmc_inuse & 0x3e)
597 mmcr[0] |= MMCR0_PMCjCE;
598 mmcr[1] = mmcr1;
599 mmcr[2] = mmcra;
600 return 0;
601}
602
603static void power5p_disable_pmc(unsigned int pmc, unsigned long mmcr[])
604{
605 if (pmc <= 3)
606 mmcr[1] &= ~(0x7fUL << MMCR1_PMCSEL_SH(pmc));
607}
608
609static int power5p_generic_events[] = {
610 [PERF_COUNT_HW_CPU_CYCLES] = 0xf,
611 [PERF_COUNT_HW_INSTRUCTIONS] = 0x100009,
612 [PERF_COUNT_HW_CACHE_REFERENCES] = 0x1c10a8, /* LD_REF_L1 */
613 [PERF_COUNT_HW_CACHE_MISSES] = 0x3c1088, /* LD_MISS_L1 */
614 [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x230e4, /* BR_ISSUED */
615 [PERF_COUNT_HW_BRANCH_MISSES] = 0x230e5, /* BR_MPRED_CR */
616};
617
618#define C(x) PERF_COUNT_HW_CACHE_##x
619
620/*
621 * Table of generalized cache-related events.
622 * 0 means not supported, -1 means nonsensical, other values
623 * are event codes.
624 */
625static int power5p_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
626 [C(L1D)] = { /* RESULT_ACCESS RESULT_MISS */
627 [C(OP_READ)] = { 0x1c10a8, 0x3c1088 },
628 [C(OP_WRITE)] = { 0x2c10a8, 0xc10c3 },
629 [C(OP_PREFETCH)] = { 0xc70e7, -1 },
630 },
631 [C(L1I)] = { /* RESULT_ACCESS RESULT_MISS */
632 [C(OP_READ)] = { 0, 0 },
633 [C(OP_WRITE)] = { -1, -1 },
634 [C(OP_PREFETCH)] = { 0, 0 },
635 },
636 [C(LL)] = { /* RESULT_ACCESS RESULT_MISS */
637 [C(OP_READ)] = { 0, 0 },
638 [C(OP_WRITE)] = { 0, 0 },
639 [C(OP_PREFETCH)] = { 0xc50c3, 0 },
640 },
641 [C(DTLB)] = { /* RESULT_ACCESS RESULT_MISS */
642 [C(OP_READ)] = { 0xc20e4, 0x800c4 },
643 [C(OP_WRITE)] = { -1, -1 },
644 [C(OP_PREFETCH)] = { -1, -1 },
645 },
646 [C(ITLB)] = { /* RESULT_ACCESS RESULT_MISS */
647 [C(OP_READ)] = { 0, 0x800c0 },
648 [C(OP_WRITE)] = { -1, -1 },
649 [C(OP_PREFETCH)] = { -1, -1 },
650 },
651 [C(BPU)] = { /* RESULT_ACCESS RESULT_MISS */
652 [C(OP_READ)] = { 0x230e4, 0x230e5 },
653 [C(OP_WRITE)] = { -1, -1 },
654 [C(OP_PREFETCH)] = { -1, -1 },
655 },
656 [C(NODE)] = { /* RESULT_ACCESS RESULT_MISS */
657 [C(OP_READ)] = { -1, -1 },
658 [C(OP_WRITE)] = { -1, -1 },
659 [C(OP_PREFETCH)] = { -1, -1 },
660 },
661};
662
663static struct power_pmu power5p_pmu = {
664 .name = "POWER5+/++",
665 .n_counter = 6,
666 .max_alternatives = MAX_ALT,
667 .add_fields = 0x7000000000055ul,
668 .test_adder = 0x3000040000000ul,
669 .compute_mmcr = power5p_compute_mmcr,
670 .get_constraint = power5p_get_constraint,
671 .get_alternatives = power5p_get_alternatives,
672 .disable_pmc = power5p_disable_pmc,
673 .limited_pmc_event = power5p_limited_pmc_event,
674 .flags = PPMU_LIMITED_PMC5_6,
675 .n_generic = ARRAY_SIZE(power5p_generic_events),
676 .generic_events = power5p_generic_events,
677 .cache_events = &power5p_cache_events,
678};
679
680static int __init init_power5p_pmu(void)
681{
682 if (!cur_cpu_spec->oprofile_cpu_type ||
683 (strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power5+")
684 && strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power5++")))
685 return -ENODEV;
686
687 return register_power_pmu(&power5p_pmu);
688}
689
690early_initcall(init_power5p_pmu);
diff --git a/arch/powerpc/kernel/power5-pmu.c b/arch/powerpc/kernel/power5-pmu.c
new file mode 100644
index 00000000000..e7f06eb7a86
--- /dev/null
+++ b/arch/powerpc/kernel/power5-pmu.c
@@ -0,0 +1,629 @@
1/*
2 * Performance counter support for POWER5 (not POWER5++) processors.
3 *
4 * Copyright 2009 Paul Mackerras, IBM Corporation.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11#include <linux/kernel.h>
12#include <linux/perf_event.h>
13#include <linux/string.h>
14#include <asm/reg.h>
15#include <asm/cputable.h>
16
17/*
18 * Bits in event code for POWER5 (not POWER5++)
19 */
20#define PM_PMC_SH 20 /* PMC number (1-based) for direct events */
21#define PM_PMC_MSK 0xf
22#define PM_PMC_MSKS (PM_PMC_MSK << PM_PMC_SH)
23#define PM_UNIT_SH 16 /* TTMMUX number and setting - unit select */
24#define PM_UNIT_MSK 0xf
25#define PM_BYTE_SH 12 /* Byte number of event bus to use */
26#define PM_BYTE_MSK 7
27#define PM_GRS_SH 8 /* Storage subsystem mux select */
28#define PM_GRS_MSK 7
29#define PM_BUSEVENT_MSK 0x80 /* Set if event uses event bus */
30#define PM_PMCSEL_MSK 0x7f
31
32/* Values in PM_UNIT field */
33#define PM_FPU 0
34#define PM_ISU0 1
35#define PM_IFU 2
36#define PM_ISU1 3
37#define PM_IDU 4
38#define PM_ISU0_ALT 6
39#define PM_GRS 7
40#define PM_LSU0 8
41#define PM_LSU1 0xc
42#define PM_LASTUNIT 0xc
43
44/*
45 * Bits in MMCR1 for POWER5
46 */
47#define MMCR1_TTM0SEL_SH 62
48#define MMCR1_TTM1SEL_SH 60
49#define MMCR1_TTM2SEL_SH 58
50#define MMCR1_TTM3SEL_SH 56
51#define MMCR1_TTMSEL_MSK 3
52#define MMCR1_TD_CP_DBG0SEL_SH 54
53#define MMCR1_TD_CP_DBG1SEL_SH 52
54#define MMCR1_TD_CP_DBG2SEL_SH 50
55#define MMCR1_TD_CP_DBG3SEL_SH 48
56#define MMCR1_GRS_L2SEL_SH 46
57#define MMCR1_GRS_L2SEL_MSK 3
58#define MMCR1_GRS_L3SEL_SH 44
59#define MMCR1_GRS_L3SEL_MSK 3
60#define MMCR1_GRS_MCSEL_SH 41
61#define MMCR1_GRS_MCSEL_MSK 7
62#define MMCR1_GRS_FABSEL_SH 39
63#define MMCR1_GRS_FABSEL_MSK 3
64#define MMCR1_PMC1_ADDER_SEL_SH 35
65#define MMCR1_PMC2_ADDER_SEL_SH 34
66#define MMCR1_PMC3_ADDER_SEL_SH 33
67#define MMCR1_PMC4_ADDER_SEL_SH 32
68#define MMCR1_PMC1SEL_SH 25
69#define MMCR1_PMC2SEL_SH 17
70#define MMCR1_PMC3SEL_SH 9
71#define MMCR1_PMC4SEL_SH 1
72#define MMCR1_PMCSEL_SH(n) (MMCR1_PMC1SEL_SH - (n) * 8)
73#define MMCR1_PMCSEL_MSK 0x7f
74
75/*
76 * Layout of constraint bits:
77 * 6666555555555544444444443333333333222222222211111111110000000000
78 * 3210987654321098765432109876543210987654321098765432109876543210
79 * <><>[ ><><>< ><> [ >[ >[ >< >< >< >< ><><><><><><>
80 * T0T1 NC G0G1G2 G3 UC PS1PS2 B0 B1 B2 B3 P6P5P4P3P2P1
81 *
82 * T0 - TTM0 constraint
83 * 54-55: TTM0SEL value (0=FPU, 2=IFU, 3=ISU1) 0xc0_0000_0000_0000
84 *
85 * T1 - TTM1 constraint
86 * 52-53: TTM1SEL value (0=IDU, 3=GRS) 0x30_0000_0000_0000
87 *
88 * NC - number of counters
89 * 51: NC error 0x0008_0000_0000_0000
90 * 48-50: number of events needing PMC1-4 0x0007_0000_0000_0000
91 *
92 * G0..G3 - GRS mux constraints
93 * 46-47: GRS_L2SEL value
94 * 44-45: GRS_L3SEL value
95 * 41-44: GRS_MCSEL value
96 * 39-40: GRS_FABSEL value
97 * Note that these match up with their bit positions in MMCR1
98 *
99 * UC - unit constraint: can't have all three of FPU|IFU|ISU1, ISU0, IDU|GRS
100 * 37: UC3 error 0x20_0000_0000
101 * 36: FPU|IFU|ISU1 events needed 0x10_0000_0000
102 * 35: ISU0 events needed 0x08_0000_0000
103 * 34: IDU|GRS events needed 0x04_0000_0000
104 *
105 * PS1
106 * 33: PS1 error 0x2_0000_0000
107 * 31-32: count of events needing PMC1/2 0x1_8000_0000
108 *
109 * PS2
110 * 30: PS2 error 0x4000_0000
111 * 28-29: count of events needing PMC3/4 0x3000_0000
112 *
113 * B0
114 * 24-27: Byte 0 event source 0x0f00_0000
115 * Encoding as for the event code
116 *
117 * B1, B2, B3
118 * 20-23, 16-19, 12-15: Byte 1, 2, 3 event sources
119 *
120 * P1..P6
121 * 0-11: Count of events needing PMC1..PMC6
122 */
123
124static const int grsel_shift[8] = {
125 MMCR1_GRS_L2SEL_SH, MMCR1_GRS_L2SEL_SH, MMCR1_GRS_L2SEL_SH,
126 MMCR1_GRS_L3SEL_SH, MMCR1_GRS_L3SEL_SH, MMCR1_GRS_L3SEL_SH,
127 MMCR1_GRS_MCSEL_SH, MMCR1_GRS_FABSEL_SH
128};
129
130/* Masks and values for using events from the various units */
131static unsigned long unit_cons[PM_LASTUNIT+1][2] = {
132 [PM_FPU] = { 0xc0002000000000ul, 0x00001000000000ul },
133 [PM_ISU0] = { 0x00002000000000ul, 0x00000800000000ul },
134 [PM_ISU1] = { 0xc0002000000000ul, 0xc0001000000000ul },
135 [PM_IFU] = { 0xc0002000000000ul, 0x80001000000000ul },
136 [PM_IDU] = { 0x30002000000000ul, 0x00000400000000ul },
137 [PM_GRS] = { 0x30002000000000ul, 0x30000400000000ul },
138};
139
140static int power5_get_constraint(u64 event, unsigned long *maskp,
141 unsigned long *valp)
142{
143 int pmc, byte, unit, sh;
144 int bit, fmask;
145 unsigned long mask = 0, value = 0;
146 int grp = -1;
147
148 pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
149 if (pmc) {
150 if (pmc > 6)
151 return -1;
152 sh = (pmc - 1) * 2;
153 mask |= 2 << sh;
154 value |= 1 << sh;
155 if (pmc <= 4)
156 grp = (pmc - 1) >> 1;
157 else if (event != 0x500009 && event != 0x600005)
158 return -1;
159 }
160 if (event & PM_BUSEVENT_MSK) {
161 unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
162 if (unit > PM_LASTUNIT)
163 return -1;
164 if (unit == PM_ISU0_ALT)
165 unit = PM_ISU0;
166 mask |= unit_cons[unit][0];
167 value |= unit_cons[unit][1];
168 byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
169 if (byte >= 4) {
170 if (unit != PM_LSU1)
171 return -1;
172 /* Map LSU1 low word (bytes 4-7) to unit LSU1+1 */
173 ++unit;
174 byte &= 3;
175 }
176 if (unit == PM_GRS) {
177 bit = event & 7;
178 fmask = (bit == 6)? 7: 3;
179 sh = grsel_shift[bit];
180 mask |= (unsigned long)fmask << sh;
181 value |= (unsigned long)((event >> PM_GRS_SH) & fmask)
182 << sh;
183 }
184 /*
185 * Bus events on bytes 0 and 2 can be counted
186 * on PMC1/2; bytes 1 and 3 on PMC3/4.
187 */
188 if (!pmc)
189 grp = byte & 1;
190 /* Set byte lane select field */
191 mask |= 0xfUL << (24 - 4 * byte);
192 value |= (unsigned long)unit << (24 - 4 * byte);
193 }
194 if (grp == 0) {
195 /* increment PMC1/2 field */
196 mask |= 0x200000000ul;
197 value |= 0x080000000ul;
198 } else if (grp == 1) {
199 /* increment PMC3/4 field */
200 mask |= 0x40000000ul;
201 value |= 0x10000000ul;
202 }
203 if (pmc < 5) {
204 /* need a counter from PMC1-4 set */
205 mask |= 0x8000000000000ul;
206 value |= 0x1000000000000ul;
207 }
208 *maskp = mask;
209 *valp = value;
210 return 0;
211}
212
213#define MAX_ALT 3 /* at most 3 alternatives for any event */
214
215static const unsigned int event_alternatives[][MAX_ALT] = {
216 { 0x120e4, 0x400002 }, /* PM_GRP_DISP_REJECT */
217 { 0x410c7, 0x441084 }, /* PM_THRD_L2MISS_BOTH_CYC */
218 { 0x100005, 0x600005 }, /* PM_RUN_CYC */
219 { 0x100009, 0x200009, 0x500009 }, /* PM_INST_CMPL */
220 { 0x300009, 0x400009 }, /* PM_INST_DISP */
221};
222
223/*
224 * Scan the alternatives table for a match and return the
225 * index into the alternatives table if found, else -1.
226 */
227static int find_alternative(u64 event)
228{
229 int i, j;
230
231 for (i = 0; i < ARRAY_SIZE(event_alternatives); ++i) {
232 if (event < event_alternatives[i][0])
233 break;
234 for (j = 0; j < MAX_ALT && event_alternatives[i][j]; ++j)
235 if (event == event_alternatives[i][j])
236 return i;
237 }
238 return -1;
239}
240
241static const unsigned char bytedecode_alternatives[4][4] = {
242 /* PMC 1 */ { 0x21, 0x23, 0x25, 0x27 },
243 /* PMC 2 */ { 0x07, 0x17, 0x0e, 0x1e },
244 /* PMC 3 */ { 0x20, 0x22, 0x24, 0x26 },
245 /* PMC 4 */ { 0x07, 0x17, 0x0e, 0x1e }
246};
247
248/*
249 * Some direct events for decodes of event bus byte 3 have alternative
250 * PMCSEL values on other counters. This returns the alternative
251 * event code for those that do, or -1 otherwise.
252 */
253static s64 find_alternative_bdecode(u64 event)
254{
255 int pmc, altpmc, pp, j;
256
257 pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
258 if (pmc == 0 || pmc > 4)
259 return -1;
260 altpmc = 5 - pmc; /* 1 <-> 4, 2 <-> 3 */
261 pp = event & PM_PMCSEL_MSK;
262 for (j = 0; j < 4; ++j) {
263 if (bytedecode_alternatives[pmc - 1][j] == pp) {
264 return (event & ~(PM_PMC_MSKS | PM_PMCSEL_MSK)) |
265 (altpmc << PM_PMC_SH) |
266 bytedecode_alternatives[altpmc - 1][j];
267 }
268 }
269 return -1;
270}
271
272static int power5_get_alternatives(u64 event, unsigned int flags, u64 alt[])
273{
274 int i, j, nalt = 1;
275 s64 ae;
276
277 alt[0] = event;
278 nalt = 1;
279 i = find_alternative(event);
280 if (i >= 0) {
281 for (j = 0; j < MAX_ALT; ++j) {
282 ae = event_alternatives[i][j];
283 if (ae && ae != event)
284 alt[nalt++] = ae;
285 }
286 } else {
287 ae = find_alternative_bdecode(event);
288 if (ae > 0)
289 alt[nalt++] = ae;
290 }
291 return nalt;
292}
293
294/*
295 * Map of which direct events on which PMCs are marked instruction events.
296 * Indexed by PMCSEL value, bit i (LE) set if PMC i is a marked event.
297 * Bit 0 is set if it is marked for all PMCs.
298 * The 0x80 bit indicates a byte decode PMCSEL value.
299 */
300static unsigned char direct_event_is_marked[0x28] = {
301 0, /* 00 */
302 0x1f, /* 01 PM_IOPS_CMPL */
303 0x2, /* 02 PM_MRK_GRP_DISP */
304 0xe, /* 03 PM_MRK_ST_CMPL, PM_MRK_ST_GPS, PM_MRK_ST_CMPL_INT */
305 0, /* 04 */
306 0x1c, /* 05 PM_MRK_BRU_FIN, PM_MRK_INST_FIN, PM_MRK_CRU_FIN */
307 0x80, /* 06 */
308 0x80, /* 07 */
309 0, 0, 0,/* 08 - 0a */
310 0x18, /* 0b PM_THRESH_TIMEO, PM_MRK_GRP_TIMEO */
311 0, /* 0c */
312 0x80, /* 0d */
313 0x80, /* 0e */
314 0, /* 0f */
315 0, /* 10 */
316 0x14, /* 11 PM_MRK_GRP_BR_REDIR, PM_MRK_GRP_IC_MISS */
317 0, /* 12 */
318 0x10, /* 13 PM_MRK_GRP_CMPL */
319 0x1f, /* 14 PM_GRP_MRK, PM_MRK_{FXU,FPU,LSU}_FIN */
320 0x2, /* 15 PM_MRK_GRP_ISSUED */
321 0x80, /* 16 */
322 0x80, /* 17 */
323 0, 0, 0, 0, 0,
324 0x80, /* 1d */
325 0x80, /* 1e */
326 0, /* 1f */
327 0x80, /* 20 */
328 0x80, /* 21 */
329 0x80, /* 22 */
330 0x80, /* 23 */
331 0x80, /* 24 */
332 0x80, /* 25 */
333 0x80, /* 26 */
334 0x80, /* 27 */
335};
336
337/*
338 * Returns 1 if event counts things relating to marked instructions
339 * and thus needs the MMCRA_SAMPLE_ENABLE bit set, or 0 if not.
340 */
341static int power5_marked_instr_event(u64 event)
342{
343 int pmc, psel;
344 int bit, byte, unit;
345 u32 mask;
346
347 pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
348 psel = event & PM_PMCSEL_MSK;
349 if (pmc >= 5)
350 return 0;
351
352 bit = -1;
353 if (psel < sizeof(direct_event_is_marked)) {
354 if (direct_event_is_marked[psel] & (1 << pmc))
355 return 1;
356 if (direct_event_is_marked[psel] & 0x80)
357 bit = 4;
358 else if (psel == 0x08)
359 bit = pmc - 1;
360 else if (psel == 0x10)
361 bit = 4 - pmc;
362 else if (psel == 0x1b && (pmc == 1 || pmc == 3))
363 bit = 4;
364 } else if ((psel & 0x58) == 0x40)
365 bit = psel & 7;
366
367 if (!(event & PM_BUSEVENT_MSK))
368 return 0;
369
370 byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
371 unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
372 if (unit == PM_LSU0) {
373 /* byte 1 bits 0-7, byte 2 bits 0,2-4,6 */
374 mask = 0x5dff00;
375 } else if (unit == PM_LSU1 && byte >= 4) {
376 byte -= 4;
377 /* byte 4 bits 1,3,5,7, byte 5 bits 6-7, byte 7 bits 0-4,6 */
378 mask = 0x5f00c0aa;
379 } else
380 return 0;
381
382 return (mask >> (byte * 8 + bit)) & 1;
383}
384
385static int power5_compute_mmcr(u64 event[], int n_ev,
386 unsigned int hwc[], unsigned long mmcr[])
387{
388 unsigned long mmcr1 = 0;
389 unsigned long mmcra = MMCRA_SDAR_DCACHE_MISS | MMCRA_SDAR_ERAT_MISS;
390 unsigned int pmc, unit, byte, psel;
391 unsigned int ttm, grp;
392 int i, isbus, bit, grsel;
393 unsigned int pmc_inuse = 0;
394 unsigned int pmc_grp_use[2];
395 unsigned char busbyte[4];
396 unsigned char unituse[16];
397 int ttmuse;
398
399 if (n_ev > 6)
400 return -1;
401
402 /* First pass to count resource use */
403 pmc_grp_use[0] = pmc_grp_use[1] = 0;
404 memset(busbyte, 0, sizeof(busbyte));
405 memset(unituse, 0, sizeof(unituse));
406 for (i = 0; i < n_ev; ++i) {
407 pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
408 if (pmc) {
409 if (pmc > 6)
410 return -1;
411 if (pmc_inuse & (1 << (pmc - 1)))
412 return -1;
413 pmc_inuse |= 1 << (pmc - 1);
414 /* count 1/2 vs 3/4 use */
415 if (pmc <= 4)
416 ++pmc_grp_use[(pmc - 1) >> 1];
417 }
418 if (event[i] & PM_BUSEVENT_MSK) {
419 unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
420 byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK;
421 if (unit > PM_LASTUNIT)
422 return -1;
423 if (unit == PM_ISU0_ALT)
424 unit = PM_ISU0;
425 if (byte >= 4) {
426 if (unit != PM_LSU1)
427 return -1;
428 ++unit;
429 byte &= 3;
430 }
431 if (!pmc)
432 ++pmc_grp_use[byte & 1];
433 if (busbyte[byte] && busbyte[byte] != unit)
434 return -1;
435 busbyte[byte] = unit;
436 unituse[unit] = 1;
437 }
438 }
439 if (pmc_grp_use[0] > 2 || pmc_grp_use[1] > 2)
440 return -1;
441
442 /*
443 * Assign resources and set multiplexer selects.
444 *
445 * PM_ISU0 can go either on TTM0 or TTM1, but that's the only
446 * choice we have to deal with.
447 */
448 if (unituse[PM_ISU0] &
449 (unituse[PM_FPU] | unituse[PM_IFU] | unituse[PM_ISU1])) {
450 unituse[PM_ISU0_ALT] = 1; /* move ISU to TTM1 */
451 unituse[PM_ISU0] = 0;
452 }
453 /* Set TTM[01]SEL fields. */
454 ttmuse = 0;
455 for (i = PM_FPU; i <= PM_ISU1; ++i) {
456 if (!unituse[i])
457 continue;
458 if (ttmuse++)
459 return -1;
460 mmcr1 |= (unsigned long)i << MMCR1_TTM0SEL_SH;
461 }
462 ttmuse = 0;
463 for (; i <= PM_GRS; ++i) {
464 if (!unituse[i])
465 continue;
466 if (ttmuse++)
467 return -1;
468 mmcr1 |= (unsigned long)(i & 3) << MMCR1_TTM1SEL_SH;
469 }
470 if (ttmuse > 1)
471 return -1;
472
473 /* Set byte lane select fields, TTM[23]SEL and GRS_*SEL. */
474 for (byte = 0; byte < 4; ++byte) {
475 unit = busbyte[byte];
476 if (!unit)
477 continue;
478 if (unit == PM_ISU0 && unituse[PM_ISU0_ALT]) {
479 /* get ISU0 through TTM1 rather than TTM0 */
480 unit = PM_ISU0_ALT;
481 } else if (unit == PM_LSU1 + 1) {
482 /* select lower word of LSU1 for this byte */
483 mmcr1 |= 1ul << (MMCR1_TTM3SEL_SH + 3 - byte);
484 }
485 ttm = unit >> 2;
486 mmcr1 |= (unsigned long)ttm
487 << (MMCR1_TD_CP_DBG0SEL_SH - 2 * byte);
488 }
489
490 /* Second pass: assign PMCs, set PMCxSEL and PMCx_ADDER_SEL fields */
491 for (i = 0; i < n_ev; ++i) {
492 pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
493 unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
494 byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK;
495 psel = event[i] & PM_PMCSEL_MSK;
496 isbus = event[i] & PM_BUSEVENT_MSK;
497 if (!pmc) {
498 /* Bus event or any-PMC direct event */
499 for (pmc = 0; pmc < 4; ++pmc) {
500 if (pmc_inuse & (1 << pmc))
501 continue;
502 grp = (pmc >> 1) & 1;
503 if (isbus) {
504 if (grp == (byte & 1))
505 break;
506 } else if (pmc_grp_use[grp] < 2) {
507 ++pmc_grp_use[grp];
508 break;
509 }
510 }
511 pmc_inuse |= 1 << pmc;
512 } else if (pmc <= 4) {
513 /* Direct event */
514 --pmc;
515 if ((psel == 8 || psel == 0x10) && isbus && (byte & 2))
516 /* add events on higher-numbered bus */
517 mmcr1 |= 1ul << (MMCR1_PMC1_ADDER_SEL_SH - pmc);
518 } else {
519 /* Instructions or run cycles on PMC5/6 */
520 --pmc;
521 }
522 if (isbus && unit == PM_GRS) {
523 bit = psel & 7;
524 grsel = (event[i] >> PM_GRS_SH) & PM_GRS_MSK;
525 mmcr1 |= (unsigned long)grsel << grsel_shift[bit];
526 }
527 if (power5_marked_instr_event(event[i]))
528 mmcra |= MMCRA_SAMPLE_ENABLE;
529 if (pmc <= 3)
530 mmcr1 |= psel << MMCR1_PMCSEL_SH(pmc);
531 hwc[i] = pmc;
532 }
533
534 /* Return MMCRx values */
535 mmcr[0] = 0;
536 if (pmc_inuse & 1)
537 mmcr[0] = MMCR0_PMC1CE;
538 if (pmc_inuse & 0x3e)
539 mmcr[0] |= MMCR0_PMCjCE;
540 mmcr[1] = mmcr1;
541 mmcr[2] = mmcra;
542 return 0;
543}
544
545static void power5_disable_pmc(unsigned int pmc, unsigned long mmcr[])
546{
547 if (pmc <= 3)
548 mmcr[1] &= ~(0x7fUL << MMCR1_PMCSEL_SH(pmc));
549}
550
551static int power5_generic_events[] = {
552 [PERF_COUNT_HW_CPU_CYCLES] = 0xf,
553 [PERF_COUNT_HW_INSTRUCTIONS] = 0x100009,
554 [PERF_COUNT_HW_CACHE_REFERENCES] = 0x4c1090, /* LD_REF_L1 */
555 [PERF_COUNT_HW_CACHE_MISSES] = 0x3c1088, /* LD_MISS_L1 */
556 [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x230e4, /* BR_ISSUED */
557 [PERF_COUNT_HW_BRANCH_MISSES] = 0x230e5, /* BR_MPRED_CR */
558};
559
560#define C(x) PERF_COUNT_HW_CACHE_##x
561
562/*
563 * Table of generalized cache-related events.
564 * 0 means not supported, -1 means nonsensical, other values
565 * are event codes.
566 */
567static int power5_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
568 [C(L1D)] = { /* RESULT_ACCESS RESULT_MISS */
569 [C(OP_READ)] = { 0x4c1090, 0x3c1088 },
570 [C(OP_WRITE)] = { 0x3c1090, 0xc10c3 },
571 [C(OP_PREFETCH)] = { 0xc70e7, 0 },
572 },
573 [C(L1I)] = { /* RESULT_ACCESS RESULT_MISS */
574 [C(OP_READ)] = { 0, 0 },
575 [C(OP_WRITE)] = { -1, -1 },
576 [C(OP_PREFETCH)] = { 0, 0 },
577 },
578 [C(LL)] = { /* RESULT_ACCESS RESULT_MISS */
579 [C(OP_READ)] = { 0, 0x3c309b },
580 [C(OP_WRITE)] = { 0, 0 },
581 [C(OP_PREFETCH)] = { 0xc50c3, 0 },
582 },
583 [C(DTLB)] = { /* RESULT_ACCESS RESULT_MISS */
584 [C(OP_READ)] = { 0x2c4090, 0x800c4 },
585 [C(OP_WRITE)] = { -1, -1 },
586 [C(OP_PREFETCH)] = { -1, -1 },
587 },
588 [C(ITLB)] = { /* RESULT_ACCESS RESULT_MISS */
589 [C(OP_READ)] = { 0, 0x800c0 },
590 [C(OP_WRITE)] = { -1, -1 },
591 [C(OP_PREFETCH)] = { -1, -1 },
592 },
593 [C(BPU)] = { /* RESULT_ACCESS RESULT_MISS */
594 [C(OP_READ)] = { 0x230e4, 0x230e5 },
595 [C(OP_WRITE)] = { -1, -1 },
596 [C(OP_PREFETCH)] = { -1, -1 },
597 },
598 [C(NODE)] = { /* RESULT_ACCESS RESULT_MISS */
599 [C(OP_READ)] = { -1, -1 },
600 [C(OP_WRITE)] = { -1, -1 },
601 [C(OP_PREFETCH)] = { -1, -1 },
602 },
603};
604
605static struct power_pmu power5_pmu = {
606 .name = "POWER5",
607 .n_counter = 6,
608 .max_alternatives = MAX_ALT,
609 .add_fields = 0x7000090000555ul,
610 .test_adder = 0x3000490000000ul,
611 .compute_mmcr = power5_compute_mmcr,
612 .get_constraint = power5_get_constraint,
613 .get_alternatives = power5_get_alternatives,
614 .disable_pmc = power5_disable_pmc,
615 .n_generic = ARRAY_SIZE(power5_generic_events),
616 .generic_events = power5_generic_events,
617 .cache_events = &power5_cache_events,
618};
619
620static int __init init_power5_pmu(void)
621{
622 if (!cur_cpu_spec->oprofile_cpu_type ||
623 strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power5"))
624 return -ENODEV;
625
626 return register_power_pmu(&power5_pmu);
627}
628
629early_initcall(init_power5_pmu);
diff --git a/arch/powerpc/kernel/power6-pmu.c b/arch/powerpc/kernel/power6-pmu.c
new file mode 100644
index 00000000000..03b95e2c6d6
--- /dev/null
+++ b/arch/powerpc/kernel/power6-pmu.c
@@ -0,0 +1,552 @@
1/*
2 * Performance counter support for POWER6 processors.
3 *
4 * Copyright 2008-2009 Paul Mackerras, IBM Corporation.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11#include <linux/kernel.h>
12#include <linux/perf_event.h>
13#include <linux/string.h>
14#include <asm/reg.h>
15#include <asm/cputable.h>
16
17/*
18 * Bits in event code for POWER6
19 */
20#define PM_PMC_SH 20 /* PMC number (1-based) for direct events */
21#define PM_PMC_MSK 0x7
22#define PM_PMC_MSKS (PM_PMC_MSK << PM_PMC_SH)
23#define PM_UNIT_SH 16 /* Unit event comes (TTMxSEL encoding) */
24#define PM_UNIT_MSK 0xf
25#define PM_UNIT_MSKS (PM_UNIT_MSK << PM_UNIT_SH)
26#define PM_LLAV 0x8000 /* Load lookahead match value */
27#define PM_LLA 0x4000 /* Load lookahead match enable */
28#define PM_BYTE_SH 12 /* Byte of event bus to use */
29#define PM_BYTE_MSK 3
30#define PM_SUBUNIT_SH 8 /* Subunit event comes from (NEST_SEL enc.) */
31#define PM_SUBUNIT_MSK 7
32#define PM_SUBUNIT_MSKS (PM_SUBUNIT_MSK << PM_SUBUNIT_SH)
33#define PM_PMCSEL_MSK 0xff /* PMCxSEL value */
34#define PM_BUSEVENT_MSK 0xf3700
35
36/*
37 * Bits in MMCR1 for POWER6
38 */
39#define MMCR1_TTM0SEL_SH 60
40#define MMCR1_TTMSEL_SH(n) (MMCR1_TTM0SEL_SH - (n) * 4)
41#define MMCR1_TTMSEL_MSK 0xf
42#define MMCR1_TTMSEL(m, n) (((m) >> MMCR1_TTMSEL_SH(n)) & MMCR1_TTMSEL_MSK)
43#define MMCR1_NESTSEL_SH 45
44#define MMCR1_NESTSEL_MSK 0x7
45#define MMCR1_NESTSEL(m) (((m) >> MMCR1_NESTSEL_SH) & MMCR1_NESTSEL_MSK)
46#define MMCR1_PMC1_LLA (1ul << 44)
47#define MMCR1_PMC1_LLA_VALUE (1ul << 39)
48#define MMCR1_PMC1_ADDR_SEL (1ul << 35)
49#define MMCR1_PMC1SEL_SH 24
50#define MMCR1_PMCSEL_SH(n) (MMCR1_PMC1SEL_SH - (n) * 8)
51#define MMCR1_PMCSEL_MSK 0xff
52
53/*
54 * Map of which direct events on which PMCs are marked instruction events.
55 * Indexed by PMCSEL value >> 1.
56 * Bottom 4 bits are a map of which PMCs are interesting,
57 * top 4 bits say what sort of event:
58 * 0 = direct marked event,
59 * 1 = byte decode event,
60 * 4 = add/and event (PMC1 -> bits 0 & 4),
61 * 5 = add/and event (PMC1 -> bits 1 & 5),
62 * 6 = add/and event (PMC1 -> bits 2 & 6),
63 * 7 = add/and event (PMC1 -> bits 3 & 7).
64 */
65static unsigned char direct_event_is_marked[0x60 >> 1] = {
66 0, /* 00 */
67 0, /* 02 */
68 0, /* 04 */
69 0x07, /* 06 PM_MRK_ST_CMPL, PM_MRK_ST_GPS, PM_MRK_ST_CMPL_INT */
70 0x04, /* 08 PM_MRK_DFU_FIN */
71 0x06, /* 0a PM_MRK_IFU_FIN, PM_MRK_INST_FIN */
72 0, /* 0c */
73 0, /* 0e */
74 0x02, /* 10 PM_MRK_INST_DISP */
75 0x08, /* 12 PM_MRK_LSU_DERAT_MISS */
76 0, /* 14 */
77 0, /* 16 */
78 0x0c, /* 18 PM_THRESH_TIMEO, PM_MRK_INST_FIN */
79 0x0f, /* 1a PM_MRK_INST_DISP, PM_MRK_{FXU,FPU,LSU}_FIN */
80 0x01, /* 1c PM_MRK_INST_ISSUED */
81 0, /* 1e */
82 0, /* 20 */
83 0, /* 22 */
84 0, /* 24 */
85 0, /* 26 */
86 0x15, /* 28 PM_MRK_DATA_FROM_L2MISS, PM_MRK_DATA_FROM_L3MISS */
87 0, /* 2a */
88 0, /* 2c */
89 0, /* 2e */
90 0x4f, /* 30 */
91 0x7f, /* 32 */
92 0x4f, /* 34 */
93 0x5f, /* 36 */
94 0x6f, /* 38 */
95 0x4f, /* 3a */
96 0, /* 3c */
97 0x08, /* 3e PM_MRK_INST_TIMEO */
98 0x1f, /* 40 */
99 0x1f, /* 42 */
100 0x1f, /* 44 */
101 0x1f, /* 46 */
102 0x1f, /* 48 */
103 0x1f, /* 4a */
104 0x1f, /* 4c */
105 0x1f, /* 4e */
106 0, /* 50 */
107 0x05, /* 52 PM_MRK_BR_TAKEN, PM_MRK_BR_MPRED */
108 0x1c, /* 54 PM_MRK_PTEG_FROM_L3MISS, PM_MRK_PTEG_FROM_L2MISS */
109 0x02, /* 56 PM_MRK_LD_MISS_L1 */
110 0, /* 58 */
111 0, /* 5a */
112 0, /* 5c */
113 0, /* 5e */
114};
115
116/*
117 * Masks showing for each unit which bits are marked events.
118 * These masks are in LE order, i.e. 0x00000001 is byte 0, bit 0.
119 */
120static u32 marked_bus_events[16] = {
121 0x01000000, /* direct events set 1: byte 3 bit 0 */
122 0x00010000, /* direct events set 2: byte 2 bit 0 */
123 0, 0, 0, 0, /* IDU, IFU, nest: nothing */
124 0x00000088, /* VMX set 1: byte 0 bits 3, 7 */
125 0x000000c0, /* VMX set 2: byte 0 bits 4-7 */
126 0x04010000, /* LSU set 1: byte 2 bit 0, byte 3 bit 2 */
127 0xff010000u, /* LSU set 2: byte 2 bit 0, all of byte 3 */
128 0, /* LSU set 3 */
129 0x00000010, /* VMX set 3: byte 0 bit 4 */
130 0, /* BFP set 1 */
131 0x00000022, /* BFP set 2: byte 0 bits 1, 5 */
132 0, 0
133};
134
135/*
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.
138 */
139static int power6_marked_instr_event(u64 event)
140{
141 int pmc, psel, ptype;
142 int bit, byte, unit;
143 u32 mask;
144
145 pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
146 psel = (event & PM_PMCSEL_MSK) >> 1; /* drop edge/level bit */
147 if (pmc >= 5)
148 return 0;
149
150 bit = -1;
151 if (psel < sizeof(direct_event_is_marked)) {
152 ptype = direct_event_is_marked[psel];
153 if (pmc == 0 || !(ptype & (1 << (pmc - 1))))
154 return 0;
155 ptype >>= 4;
156 if (ptype == 0)
157 return 1;
158 if (ptype == 1)
159 bit = 0;
160 else
161 bit = ptype ^ (pmc - 1);
162 } else if ((psel & 0x48) == 0x40)
163 bit = psel & 7;
164
165 if (!(event & PM_BUSEVENT_MSK) || bit == -1)
166 return 0;
167
168 byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
169 unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
170 mask = marked_bus_events[unit];
171 return (mask >> (byte * 8 + bit)) & 1;
172}
173
174/*
175 * Assign PMC numbers and compute MMCR1 value for a set of events
176 */
177static int p6_compute_mmcr(u64 event[], int n_ev,
178 unsigned int hwc[], unsigned long mmcr[])
179{
180 unsigned long mmcr1 = 0;
181 unsigned long mmcra = MMCRA_SDAR_DCACHE_MISS | MMCRA_SDAR_ERAT_MISS;
182 int i;
183 unsigned int pmc, ev, b, u, s, psel;
184 unsigned int ttmset = 0;
185 unsigned int pmc_inuse = 0;
186
187 if (n_ev > 6)
188 return -1;
189 for (i = 0; i < n_ev; ++i) {
190 pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
191 if (pmc) {
192 if (pmc_inuse & (1 << (pmc - 1)))
193 return -1; /* collision! */
194 pmc_inuse |= 1 << (pmc - 1);
195 }
196 }
197 for (i = 0; i < n_ev; ++i) {
198 ev = event[i];
199 pmc = (ev >> PM_PMC_SH) & PM_PMC_MSK;
200 if (pmc) {
201 --pmc;
202 } else {
203 /* can go on any PMC; find a free one */
204 for (pmc = 0; pmc < 4; ++pmc)
205 if (!(pmc_inuse & (1 << pmc)))
206 break;
207 if (pmc >= 4)
208 return -1;
209 pmc_inuse |= 1 << pmc;
210 }
211 hwc[i] = pmc;
212 psel = ev & PM_PMCSEL_MSK;
213 if (ev & PM_BUSEVENT_MSK) {
214 /* this event uses the event bus */
215 b = (ev >> PM_BYTE_SH) & PM_BYTE_MSK;
216 u = (ev >> PM_UNIT_SH) & PM_UNIT_MSK;
217 /* check for conflict on this byte of event bus */
218 if ((ttmset & (1 << b)) && MMCR1_TTMSEL(mmcr1, b) != u)
219 return -1;
220 mmcr1 |= (unsigned long)u << MMCR1_TTMSEL_SH(b);
221 ttmset |= 1 << b;
222 if (u == 5) {
223 /* Nest events have a further mux */
224 s = (ev >> PM_SUBUNIT_SH) & PM_SUBUNIT_MSK;
225 if ((ttmset & 0x10) &&
226 MMCR1_NESTSEL(mmcr1) != s)
227 return -1;
228 ttmset |= 0x10;
229 mmcr1 |= (unsigned long)s << MMCR1_NESTSEL_SH;
230 }
231 if (0x30 <= psel && psel <= 0x3d) {
232 /* these need the PMCx_ADDR_SEL bits */
233 if (b >= 2)
234 mmcr1 |= MMCR1_PMC1_ADDR_SEL >> pmc;
235 }
236 /* bus select values are different for PMC3/4 */
237 if (pmc >= 2 && (psel & 0x90) == 0x80)
238 psel ^= 0x20;
239 }
240 if (ev & PM_LLA) {
241 mmcr1 |= MMCR1_PMC1_LLA >> pmc;
242 if (ev & PM_LLAV)
243 mmcr1 |= MMCR1_PMC1_LLA_VALUE >> pmc;
244 }
245 if (power6_marked_instr_event(event[i]))
246 mmcra |= MMCRA_SAMPLE_ENABLE;
247 if (pmc < 4)
248 mmcr1 |= (unsigned long)psel << MMCR1_PMCSEL_SH(pmc);
249 }
250 mmcr[0] = 0;
251 if (pmc_inuse & 1)
252 mmcr[0] = MMCR0_PMC1CE;
253 if (pmc_inuse & 0xe)
254 mmcr[0] |= MMCR0_PMCjCE;
255 mmcr[1] = mmcr1;
256 mmcr[2] = mmcra;
257 return 0;
258}
259
260/*
261 * Layout of constraint bits:
262 *
263 * 0-1 add field: number of uses of PMC1 (max 1)
264 * 2-3, 4-5, 6-7, 8-9, 10-11: ditto for PMC2, 3, 4, 5, 6
265 * 12-15 add field: number of uses of PMC1-4 (max 4)
266 * 16-19 select field: unit on byte 0 of event bus
267 * 20-23, 24-27, 28-31 ditto for bytes 1, 2, 3
268 * 32-34 select field: nest (subunit) event selector
269 */
270static int p6_get_constraint(u64 event, unsigned long *maskp,
271 unsigned long *valp)
272{
273 int pmc, byte, sh, subunit;
274 unsigned long mask = 0, value = 0;
275
276 pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
277 if (pmc) {
278 if (pmc > 4 && !(event == 0x500009 || event == 0x600005))
279 return -1;
280 sh = (pmc - 1) * 2;
281 mask |= 2 << sh;
282 value |= 1 << sh;
283 }
284 if (event & PM_BUSEVENT_MSK) {
285 byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
286 sh = byte * 4 + (16 - PM_UNIT_SH);
287 mask |= PM_UNIT_MSKS << sh;
288 value |= (unsigned long)(event & PM_UNIT_MSKS) << sh;
289 if ((event & PM_UNIT_MSKS) == (5 << PM_UNIT_SH)) {
290 subunit = (event >> PM_SUBUNIT_SH) & PM_SUBUNIT_MSK;
291 mask |= (unsigned long)PM_SUBUNIT_MSK << 32;
292 value |= (unsigned long)subunit << 32;
293 }
294 }
295 if (pmc <= 4) {
296 mask |= 0x8000; /* add field for count of PMC1-4 uses */
297 value |= 0x1000;
298 }
299 *maskp = mask;
300 *valp = value;
301 return 0;
302}
303
304static int p6_limited_pmc_event(u64 event)
305{
306 int pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
307
308 return pmc == 5 || pmc == 6;
309}
310
311#define MAX_ALT 4 /* at most 4 alternatives for any event */
312
313static const unsigned int event_alternatives[][MAX_ALT] = {
314 { 0x0130e8, 0x2000f6, 0x3000fc }, /* PM_PTEG_RELOAD_VALID */
315 { 0x080080, 0x10000d, 0x30000c, 0x4000f0 }, /* PM_LD_MISS_L1 */
316 { 0x080088, 0x200054, 0x3000f0 }, /* PM_ST_MISS_L1 */
317 { 0x10000a, 0x2000f4, 0x600005 }, /* PM_RUN_CYC */
318 { 0x10000b, 0x2000f5 }, /* PM_RUN_COUNT */
319 { 0x10000e, 0x400010 }, /* PM_PURR */
320 { 0x100010, 0x4000f8 }, /* PM_FLUSH */
321 { 0x10001a, 0x200010 }, /* PM_MRK_INST_DISP */
322 { 0x100026, 0x3000f8 }, /* PM_TB_BIT_TRANS */
323 { 0x100054, 0x2000f0 }, /* PM_ST_FIN */
324 { 0x100056, 0x2000fc }, /* PM_L1_ICACHE_MISS */
325 { 0x1000f0, 0x40000a }, /* PM_INST_IMC_MATCH_CMPL */
326 { 0x1000f8, 0x200008 }, /* PM_GCT_EMPTY_CYC */
327 { 0x1000fc, 0x400006 }, /* PM_LSU_DERAT_MISS_CYC */
328 { 0x20000e, 0x400007 }, /* PM_LSU_DERAT_MISS */
329 { 0x200012, 0x300012 }, /* PM_INST_DISP */
330 { 0x2000f2, 0x3000f2 }, /* PM_INST_DISP */
331 { 0x2000f8, 0x300010 }, /* PM_EXT_INT */
332 { 0x2000fe, 0x300056 }, /* PM_DATA_FROM_L2MISS */
333 { 0x2d0030, 0x30001a }, /* PM_MRK_FPU_FIN */
334 { 0x30000a, 0x400018 }, /* PM_MRK_INST_FIN */
335 { 0x3000f6, 0x40000e }, /* PM_L1_DCACHE_RELOAD_VALID */
336 { 0x3000fe, 0x400056 }, /* PM_DATA_FROM_L3MISS */
337};
338
339/*
340 * This could be made more efficient with a binary search on
341 * a presorted list, if necessary
342 */
343static int find_alternatives_list(u64 event)
344{
345 int i, j;
346 unsigned int alt;
347
348 for (i = 0; i < ARRAY_SIZE(event_alternatives); ++i) {
349 if (event < event_alternatives[i][0])
350 return -1;
351 for (j = 0; j < MAX_ALT; ++j) {
352 alt = event_alternatives[i][j];
353 if (!alt || event < alt)
354 break;
355 if (event == alt)
356 return i;
357 }
358 }
359 return -1;
360}
361
362static int p6_get_alternatives(u64 event, unsigned int flags, u64 alt[])
363{
364 int i, j, nlim;
365 unsigned int psel, pmc;
366 unsigned int nalt = 1;
367 u64 aevent;
368
369 alt[0] = event;
370 nlim = p6_limited_pmc_event(event);
371
372 /* check the alternatives table */
373 i = find_alternatives_list(event);
374 if (i >= 0) {
375 /* copy out alternatives from list */
376 for (j = 0; j < MAX_ALT; ++j) {
377 aevent = event_alternatives[i][j];
378 if (!aevent)
379 break;
380 if (aevent != event)
381 alt[nalt++] = aevent;
382 nlim += p6_limited_pmc_event(aevent);
383 }
384
385 } else {
386 /* Check for alternative ways of computing sum events */
387 /* PMCSEL 0x32 counter N == PMCSEL 0x34 counter 5-N */
388 psel = event & (PM_PMCSEL_MSK & ~1); /* ignore edge bit */
389 pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
390 if (pmc && (psel == 0x32 || psel == 0x34))
391 alt[nalt++] = ((event ^ 0x6) & ~PM_PMC_MSKS) |
392 ((5 - pmc) << PM_PMC_SH);
393
394 /* PMCSEL 0x38 counter N == PMCSEL 0x3a counter N+/-2 */
395 if (pmc && (psel == 0x38 || psel == 0x3a))
396 alt[nalt++] = ((event ^ 0x2) & ~PM_PMC_MSKS) |
397 ((pmc > 2? pmc - 2: pmc + 2) << PM_PMC_SH);
398 }
399
400 if (flags & PPMU_ONLY_COUNT_RUN) {
401 /*
402 * We're only counting in RUN state,
403 * so PM_CYC is equivalent to PM_RUN_CYC,
404 * PM_INST_CMPL === PM_RUN_INST_CMPL, PM_PURR === PM_RUN_PURR.
405 * This doesn't include alternatives that don't provide
406 * any extra flexibility in assigning PMCs (e.g.
407 * 0x10000a for PM_RUN_CYC vs. 0x1e for PM_CYC).
408 * Note that even with these additional alternatives
409 * we never end up with more than 4 alternatives for any event.
410 */
411 j = nalt;
412 for (i = 0; i < nalt; ++i) {
413 switch (alt[i]) {
414 case 0x1e: /* PM_CYC */
415 alt[j++] = 0x600005; /* PM_RUN_CYC */
416 ++nlim;
417 break;
418 case 0x10000a: /* PM_RUN_CYC */
419 alt[j++] = 0x1e; /* PM_CYC */
420 break;
421 case 2: /* PM_INST_CMPL */
422 alt[j++] = 0x500009; /* PM_RUN_INST_CMPL */
423 ++nlim;
424 break;
425 case 0x500009: /* PM_RUN_INST_CMPL */
426 alt[j++] = 2; /* PM_INST_CMPL */
427 break;
428 case 0x10000e: /* PM_PURR */
429 alt[j++] = 0x4000f4; /* PM_RUN_PURR */
430 break;
431 case 0x4000f4: /* PM_RUN_PURR */
432 alt[j++] = 0x10000e; /* PM_PURR */
433 break;
434 }
435 }
436 nalt = j;
437 }
438
439 if (!(flags & PPMU_LIMITED_PMC_OK) && nlim) {
440 /* remove the limited PMC events */
441 j = 0;
442 for (i = 0; i < nalt; ++i) {
443 if (!p6_limited_pmc_event(alt[i])) {
444 alt[j] = alt[i];
445 ++j;
446 }
447 }
448 nalt = j;
449 } else if ((flags & PPMU_LIMITED_PMC_REQD) && nlim < nalt) {
450 /* remove all but the limited PMC events */
451 j = 0;
452 for (i = 0; i < nalt; ++i) {
453 if (p6_limited_pmc_event(alt[i])) {
454 alt[j] = alt[i];
455 ++j;
456 }
457 }
458 nalt = j;
459 }
460
461 return nalt;
462}
463
464static void p6_disable_pmc(unsigned int pmc, unsigned long mmcr[])
465{
466 /* Set PMCxSEL to 0 to disable PMCx */
467 if (pmc <= 3)
468 mmcr[1] &= ~(0xffUL << MMCR1_PMCSEL_SH(pmc));
469}
470
471static int power6_generic_events[] = {
472 [PERF_COUNT_HW_CPU_CYCLES] = 0x1e,
473 [PERF_COUNT_HW_INSTRUCTIONS] = 2,
474 [PERF_COUNT_HW_CACHE_REFERENCES] = 0x280030, /* LD_REF_L1 */
475 [PERF_COUNT_HW_CACHE_MISSES] = 0x30000c, /* LD_MISS_L1 */
476 [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x410a0, /* BR_PRED */
477 [PERF_COUNT_HW_BRANCH_MISSES] = 0x400052, /* BR_MPRED */
478};
479
480#define C(x) PERF_COUNT_HW_CACHE_##x
481
482/*
483 * Table of generalized cache-related events.
484 * 0 means not supported, -1 means nonsensical, other values
485 * are event codes.
486 * The "DTLB" and "ITLB" events relate to the DERAT and IERAT.
487 */
488static int power6_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
489 [C(L1D)] = { /* RESULT_ACCESS RESULT_MISS */
490 [C(OP_READ)] = { 0x80082, 0x80080 },
491 [C(OP_WRITE)] = { 0x80086, 0x80088 },
492 [C(OP_PREFETCH)] = { 0x810a4, 0 },
493 },
494 [C(L1I)] = { /* RESULT_ACCESS RESULT_MISS */
495 [C(OP_READ)] = { 0, 0x100056 },
496 [C(OP_WRITE)] = { -1, -1 },
497 [C(OP_PREFETCH)] = { 0x4008c, 0 },
498 },
499 [C(LL)] = { /* RESULT_ACCESS RESULT_MISS */
500 [C(OP_READ)] = { 0x150730, 0x250532 },
501 [C(OP_WRITE)] = { 0x250432, 0x150432 },
502 [C(OP_PREFETCH)] = { 0x810a6, 0 },
503 },
504 [C(DTLB)] = { /* RESULT_ACCESS RESULT_MISS */
505 [C(OP_READ)] = { 0, 0x20000e },
506 [C(OP_WRITE)] = { -1, -1 },
507 [C(OP_PREFETCH)] = { -1, -1 },
508 },
509 [C(ITLB)] = { /* RESULT_ACCESS RESULT_MISS */
510 [C(OP_READ)] = { 0, 0x420ce },
511 [C(OP_WRITE)] = { -1, -1 },
512 [C(OP_PREFETCH)] = { -1, -1 },
513 },
514 [C(BPU)] = { /* RESULT_ACCESS RESULT_MISS */
515 [C(OP_READ)] = { 0x430e6, 0x400052 },
516 [C(OP_WRITE)] = { -1, -1 },
517 [C(OP_PREFETCH)] = { -1, -1 },
518 },
519 [C(NODE)] = { /* RESULT_ACCESS RESULT_MISS */
520 [C(OP_READ)] = { -1, -1 },
521 [C(OP_WRITE)] = { -1, -1 },
522 [C(OP_PREFETCH)] = { -1, -1 },
523 },
524};
525
526static struct power_pmu power6_pmu = {
527 .name = "POWER6",
528 .n_counter = 6,
529 .max_alternatives = MAX_ALT,
530 .add_fields = 0x1555,
531 .test_adder = 0x3000,
532 .compute_mmcr = p6_compute_mmcr,
533 .get_constraint = p6_get_constraint,
534 .get_alternatives = p6_get_alternatives,
535 .disable_pmc = p6_disable_pmc,
536 .limited_pmc_event = p6_limited_pmc_event,
537 .flags = PPMU_LIMITED_PMC5_6 | PPMU_ALT_SIPR,
538 .n_generic = ARRAY_SIZE(power6_generic_events),
539 .generic_events = power6_generic_events,
540 .cache_events = &power6_cache_events,
541};
542
543static int __init init_power6_pmu(void)
544{
545 if (!cur_cpu_spec->oprofile_cpu_type ||
546 strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power6"))
547 return -ENODEV;
548
549 return register_power_pmu(&power6_pmu);
550}
551
552early_initcall(init_power6_pmu);
diff --git a/arch/powerpc/kernel/power7-pmu.c b/arch/powerpc/kernel/power7-pmu.c
new file mode 100644
index 00000000000..de83d6060dd
--- /dev/null
+++ b/arch/powerpc/kernel/power7-pmu.c
@@ -0,0 +1,377 @@
1/*
2 * Performance counter support for POWER7 processors.
3 *
4 * Copyright 2009 Paul Mackerras, IBM Corporation.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11#include <linux/kernel.h>
12#include <linux/perf_event.h>
13#include <linux/string.h>
14#include <asm/reg.h>
15#include <asm/cputable.h>
16
17/*
18 * Bits in event code for POWER7
19 */
20#define PM_PMC_SH 16 /* PMC number (1-based) for direct events */
21#define PM_PMC_MSK 0xf
22#define PM_PMC_MSKS (PM_PMC_MSK << PM_PMC_SH)
23#define PM_UNIT_SH 12 /* TTMMUX number and setting - unit select */
24#define PM_UNIT_MSK 0xf
25#define PM_COMBINE_SH 11 /* Combined event bit */
26#define PM_COMBINE_MSK 1
27#define PM_COMBINE_MSKS 0x800
28#define PM_L2SEL_SH 8 /* L2 event select */
29#define PM_L2SEL_MSK 7
30#define PM_PMCSEL_MSK 0xff
31
32/*
33 * Bits in MMCR1 for POWER7
34 */
35#define MMCR1_TTM0SEL_SH 60
36#define MMCR1_TTM1SEL_SH 56
37#define MMCR1_TTM2SEL_SH 52
38#define MMCR1_TTM3SEL_SH 48
39#define MMCR1_TTMSEL_MSK 0xf
40#define MMCR1_L2SEL_SH 45
41#define MMCR1_L2SEL_MSK 7
42#define MMCR1_PMC1_COMBINE_SH 35
43#define MMCR1_PMC2_COMBINE_SH 34
44#define MMCR1_PMC3_COMBINE_SH 33
45#define MMCR1_PMC4_COMBINE_SH 32
46#define MMCR1_PMC1SEL_SH 24
47#define MMCR1_PMC2SEL_SH 16
48#define MMCR1_PMC3SEL_SH 8
49#define MMCR1_PMC4SEL_SH 0
50#define MMCR1_PMCSEL_SH(n) (MMCR1_PMC1SEL_SH - (n) * 8)
51#define MMCR1_PMCSEL_MSK 0xff
52
53/*
54 * Layout of constraint bits:
55 * 6666555555555544444444443333333333222222222211111111110000000000
56 * 3210987654321098765432109876543210987654321098765432109876543210
57 * [ ><><><><><><>
58 * NC P6P5P4P3P2P1
59 *
60 * NC - number of counters
61 * 15: NC error 0x8000
62 * 12-14: number of events needing PMC1-4 0x7000
63 *
64 * P6
65 * 11: P6 error 0x800
66 * 10-11: Count of events needing PMC6
67 *
68 * P1..P5
69 * 0-9: Count of events needing PMC1..PMC5
70 */
71
72static int power7_get_constraint(u64 event, unsigned long *maskp,
73 unsigned long *valp)
74{
75 int pmc, sh;
76 unsigned long mask = 0, value = 0;
77
78 pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
79 if (pmc) {
80 if (pmc > 6)
81 return -1;
82 sh = (pmc - 1) * 2;
83 mask |= 2 << sh;
84 value |= 1 << sh;
85 if (pmc >= 5 && !(event == 0x500fa || event == 0x600f4))
86 return -1;
87 }
88 if (pmc < 5) {
89 /* need a counter from PMC1-4 set */
90 mask |= 0x8000;
91 value |= 0x1000;
92 }
93 *maskp = mask;
94 *valp = value;
95 return 0;
96}
97
98#define MAX_ALT 2 /* at most 2 alternatives for any event */
99
100static const unsigned int event_alternatives[][MAX_ALT] = {
101 { 0x200f2, 0x300f2 }, /* PM_INST_DISP */
102 { 0x200f4, 0x600f4 }, /* PM_RUN_CYC */
103 { 0x400fa, 0x500fa }, /* PM_RUN_INST_CMPL */
104};
105
106/*
107 * Scan the alternatives table for a match and return the
108 * index into the alternatives table if found, else -1.
109 */
110static int find_alternative(u64 event)
111{
112 int i, j;
113
114 for (i = 0; i < ARRAY_SIZE(event_alternatives); ++i) {
115 if (event < event_alternatives[i][0])
116 break;
117 for (j = 0; j < MAX_ALT && event_alternatives[i][j]; ++j)
118 if (event == event_alternatives[i][j])
119 return i;
120 }
121 return -1;
122}
123
124static s64 find_alternative_decode(u64 event)
125{
126 int pmc, psel;
127
128 /* this only handles the 4x decode events */
129 pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
130 psel = event & PM_PMCSEL_MSK;
131 if ((pmc == 2 || pmc == 4) && (psel & ~7) == 0x40)
132 return event - (1 << PM_PMC_SH) + 8;
133 if ((pmc == 1 || pmc == 3) && (psel & ~7) == 0x48)
134 return event + (1 << PM_PMC_SH) - 8;
135 return -1;
136}
137
138static int power7_get_alternatives(u64 event, unsigned int flags, u64 alt[])
139{
140 int i, j, nalt = 1;
141 s64 ae;
142
143 alt[0] = event;
144 nalt = 1;
145 i = find_alternative(event);
146 if (i >= 0) {
147 for (j = 0; j < MAX_ALT; ++j) {
148 ae = event_alternatives[i][j];
149 if (ae && ae != event)
150 alt[nalt++] = ae;
151 }
152 } else {
153 ae = find_alternative_decode(event);
154 if (ae > 0)
155 alt[nalt++] = ae;
156 }
157
158 if (flags & PPMU_ONLY_COUNT_RUN) {
159 /*
160 * We're only counting in RUN state,
161 * so PM_CYC is equivalent to PM_RUN_CYC
162 * and PM_INST_CMPL === PM_RUN_INST_CMPL.
163 * This doesn't include alternatives that don't provide
164 * any extra flexibility in assigning PMCs.
165 */
166 j = nalt;
167 for (i = 0; i < nalt; ++i) {
168 switch (alt[i]) {
169 case 0x1e: /* PM_CYC */
170 alt[j++] = 0x600f4; /* PM_RUN_CYC */
171 break;
172 case 0x600f4: /* PM_RUN_CYC */
173 alt[j++] = 0x1e;
174 break;
175 case 0x2: /* PM_PPC_CMPL */
176 alt[j++] = 0x500fa; /* PM_RUN_INST_CMPL */
177 break;
178 case 0x500fa: /* PM_RUN_INST_CMPL */
179 alt[j++] = 0x2; /* PM_PPC_CMPL */
180 break;
181 }
182 }
183 nalt = j;
184 }
185
186 return nalt;
187}
188
189/*
190 * Returns 1 if event counts things relating to marked instructions
191 * and thus needs the MMCRA_SAMPLE_ENABLE bit set, or 0 if not.
192 */
193static int power7_marked_instr_event(u64 event)
194{
195 int pmc, psel;
196 int unit;
197
198 pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
199 unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
200 psel = event & PM_PMCSEL_MSK & ~1; /* trim off edge/level bit */
201 if (pmc >= 5)
202 return 0;
203
204 switch (psel >> 4) {
205 case 2:
206 return pmc == 2 || pmc == 4;
207 case 3:
208 if (psel == 0x3c)
209 return pmc == 1;
210 if (psel == 0x3e)
211 return pmc != 2;
212 return 1;
213 case 4:
214 case 5:
215 return unit == 0xd;
216 case 6:
217 if (psel == 0x64)
218 return pmc >= 3;
219 case 8:
220 return unit == 0xd;
221 }
222 return 0;
223}
224
225static int power7_compute_mmcr(u64 event[], int n_ev,
226 unsigned int hwc[], unsigned long mmcr[])
227{
228 unsigned long mmcr1 = 0;
229 unsigned long mmcra = MMCRA_SDAR_DCACHE_MISS | MMCRA_SDAR_ERAT_MISS;
230 unsigned int pmc, unit, combine, l2sel, psel;
231 unsigned int pmc_inuse = 0;
232 int i;
233
234 /* First pass to count resource use */
235 for (i = 0; i < n_ev; ++i) {
236 pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
237 if (pmc) {
238 if (pmc > 6)
239 return -1;
240 if (pmc_inuse & (1 << (pmc - 1)))
241 return -1;
242 pmc_inuse |= 1 << (pmc - 1);
243 }
244 }
245
246 /* Second pass: assign PMCs, set all MMCR1 fields */
247 for (i = 0; i < n_ev; ++i) {
248 pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
249 unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
250 combine = (event[i] >> PM_COMBINE_SH) & PM_COMBINE_MSK;
251 l2sel = (event[i] >> PM_L2SEL_SH) & PM_L2SEL_MSK;
252 psel = event[i] & PM_PMCSEL_MSK;
253 if (!pmc) {
254 /* Bus event or any-PMC direct event */
255 for (pmc = 0; pmc < 4; ++pmc) {
256 if (!(pmc_inuse & (1 << pmc)))
257 break;
258 }
259 if (pmc >= 4)
260 return -1;
261 pmc_inuse |= 1 << pmc;
262 } else {
263 /* Direct or decoded event */
264 --pmc;
265 }
266 if (pmc <= 3) {
267 mmcr1 |= (unsigned long) unit
268 << (MMCR1_TTM0SEL_SH - 4 * pmc);
269 mmcr1 |= (unsigned long) combine
270 << (MMCR1_PMC1_COMBINE_SH - pmc);
271 mmcr1 |= psel << MMCR1_PMCSEL_SH(pmc);
272 if (unit == 6) /* L2 events */
273 mmcr1 |= (unsigned long) l2sel
274 << MMCR1_L2SEL_SH;
275 }
276 if (power7_marked_instr_event(event[i]))
277 mmcra |= MMCRA_SAMPLE_ENABLE;
278 hwc[i] = pmc;
279 }
280
281 /* Return MMCRx values */
282 mmcr[0] = 0;
283 if (pmc_inuse & 1)
284 mmcr[0] = MMCR0_PMC1CE;
285 if (pmc_inuse & 0x3e)
286 mmcr[0] |= MMCR0_PMCjCE;
287 mmcr[1] = mmcr1;
288 mmcr[2] = mmcra;
289 return 0;
290}
291
292static void power7_disable_pmc(unsigned int pmc, unsigned long mmcr[])
293{
294 if (pmc <= 3)
295 mmcr[1] &= ~(0xffUL << MMCR1_PMCSEL_SH(pmc));
296}
297
298static int power7_generic_events[] = {
299 [PERF_COUNT_HW_CPU_CYCLES] = 0x1e,
300 [PERF_COUNT_HW_INSTRUCTIONS] = 2,
301 [PERF_COUNT_HW_CACHE_REFERENCES] = 0xc880, /* LD_REF_L1_LSU*/
302 [PERF_COUNT_HW_CACHE_MISSES] = 0x400f0, /* LD_MISS_L1 */
303 [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x10068, /* BRU_FIN */
304 [PERF_COUNT_HW_BRANCH_MISSES] = 0x400f6, /* BR_MPRED */
305};
306
307#define C(x) PERF_COUNT_HW_CACHE_##x
308
309/*
310 * Table of generalized cache-related events.
311 * 0 means not supported, -1 means nonsensical, other values
312 * are event codes.
313 */
314static int power7_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
315 [C(L1D)] = { /* RESULT_ACCESS RESULT_MISS */
316 [C(OP_READ)] = { 0xc880, 0x400f0 },
317 [C(OP_WRITE)] = { 0, 0x300f0 },
318 [C(OP_PREFETCH)] = { 0xd8b8, 0 },
319 },
320 [C(L1I)] = { /* RESULT_ACCESS RESULT_MISS */
321 [C(OP_READ)] = { 0, 0x200fc },
322 [C(OP_WRITE)] = { -1, -1 },
323 [C(OP_PREFETCH)] = { 0x408a, 0 },
324 },
325 [C(LL)] = { /* RESULT_ACCESS RESULT_MISS */
326 [C(OP_READ)] = { 0x16080, 0x26080 },
327 [C(OP_WRITE)] = { 0x16082, 0x26082 },
328 [C(OP_PREFETCH)] = { 0, 0 },
329 },
330 [C(DTLB)] = { /* RESULT_ACCESS RESULT_MISS */
331 [C(OP_READ)] = { 0, 0x300fc },
332 [C(OP_WRITE)] = { -1, -1 },
333 [C(OP_PREFETCH)] = { -1, -1 },
334 },
335 [C(ITLB)] = { /* RESULT_ACCESS RESULT_MISS */
336 [C(OP_READ)] = { 0, 0x400fc },
337 [C(OP_WRITE)] = { -1, -1 },
338 [C(OP_PREFETCH)] = { -1, -1 },
339 },
340 [C(BPU)] = { /* RESULT_ACCESS RESULT_MISS */
341 [C(OP_READ)] = { 0x10068, 0x400f6 },
342 [C(OP_WRITE)] = { -1, -1 },
343 [C(OP_PREFETCH)] = { -1, -1 },
344 },
345 [C(NODE)] = { /* RESULT_ACCESS RESULT_MISS */
346 [C(OP_READ)] = { -1, -1 },
347 [C(OP_WRITE)] = { -1, -1 },
348 [C(OP_PREFETCH)] = { -1, -1 },
349 },
350};
351
352static struct power_pmu power7_pmu = {
353 .name = "POWER7",
354 .n_counter = 6,
355 .max_alternatives = MAX_ALT + 1,
356 .add_fields = 0x1555ul,
357 .test_adder = 0x3000ul,
358 .compute_mmcr = power7_compute_mmcr,
359 .get_constraint = power7_get_constraint,
360 .get_alternatives = power7_get_alternatives,
361 .disable_pmc = power7_disable_pmc,
362 .flags = PPMU_ALT_SIPR,
363 .n_generic = ARRAY_SIZE(power7_generic_events),
364 .generic_events = power7_generic_events,
365 .cache_events = &power7_cache_events,
366};
367
368static int __init init_power7_pmu(void)
369{
370 if (!cur_cpu_spec->oprofile_cpu_type ||
371 strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/power7"))
372 return -ENODEV;
373
374 return register_power_pmu(&power7_pmu);
375}
376
377early_initcall(init_power7_pmu);
diff --git a/arch/powerpc/kernel/ppc970-pmu.c b/arch/powerpc/kernel/ppc970-pmu.c
new file mode 100644
index 00000000000..8c219020696
--- /dev/null
+++ b/arch/powerpc/kernel/ppc970-pmu.c
@@ -0,0 +1,502 @@
1/*
2 * Performance counter support for PPC970-family processors.
3 *
4 * Copyright 2008-2009 Paul Mackerras, IBM Corporation.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11#include <linux/string.h>
12#include <linux/perf_event.h>
13#include <asm/reg.h>
14#include <asm/cputable.h>
15
16/*
17 * Bits in event code for PPC970
18 */
19#define PM_PMC_SH 12 /* PMC number (1-based) for direct events */
20#define PM_PMC_MSK 0xf
21#define PM_UNIT_SH 8 /* TTMMUX number and setting - unit select */
22#define PM_UNIT_MSK 0xf
23#define PM_SPCSEL_SH 6
24#define PM_SPCSEL_MSK 3
25#define PM_BYTE_SH 4 /* Byte number of event bus to use */
26#define PM_BYTE_MSK 3
27#define PM_PMCSEL_MSK 0xf
28
29/* Values in PM_UNIT field */
30#define PM_NONE 0
31#define PM_FPU 1
32#define PM_VPU 2
33#define PM_ISU 3
34#define PM_IFU 4
35#define PM_IDU 5
36#define PM_STS 6
37#define PM_LSU0 7
38#define PM_LSU1U 8
39#define PM_LSU1L 9
40#define PM_LASTUNIT 9
41
42/*
43 * Bits in MMCR0 for PPC970
44 */
45#define MMCR0_PMC1SEL_SH 8
46#define MMCR0_PMC2SEL_SH 1
47#define MMCR_PMCSEL_MSK 0x1f
48
49/*
50 * Bits in MMCR1 for PPC970
51 */
52#define MMCR1_TTM0SEL_SH 62
53#define MMCR1_TTM1SEL_SH 59
54#define MMCR1_TTM3SEL_SH 53
55#define MMCR1_TTMSEL_MSK 3
56#define MMCR1_TD_CP_DBG0SEL_SH 50
57#define MMCR1_TD_CP_DBG1SEL_SH 48
58#define MMCR1_TD_CP_DBG2SEL_SH 46
59#define MMCR1_TD_CP_DBG3SEL_SH 44
60#define MMCR1_PMC1_ADDER_SEL_SH 39
61#define MMCR1_PMC2_ADDER_SEL_SH 38
62#define MMCR1_PMC6_ADDER_SEL_SH 37
63#define MMCR1_PMC5_ADDER_SEL_SH 36
64#define MMCR1_PMC8_ADDER_SEL_SH 35
65#define MMCR1_PMC7_ADDER_SEL_SH 34
66#define MMCR1_PMC3_ADDER_SEL_SH 33
67#define MMCR1_PMC4_ADDER_SEL_SH 32
68#define MMCR1_PMC3SEL_SH 27
69#define MMCR1_PMC4SEL_SH 22
70#define MMCR1_PMC5SEL_SH 17
71#define MMCR1_PMC6SEL_SH 12
72#define MMCR1_PMC7SEL_SH 7
73#define MMCR1_PMC8SEL_SH 2
74
75static short mmcr1_adder_bits[8] = {
76 MMCR1_PMC1_ADDER_SEL_SH,
77 MMCR1_PMC2_ADDER_SEL_SH,
78 MMCR1_PMC3_ADDER_SEL_SH,
79 MMCR1_PMC4_ADDER_SEL_SH,
80 MMCR1_PMC5_ADDER_SEL_SH,
81 MMCR1_PMC6_ADDER_SEL_SH,
82 MMCR1_PMC7_ADDER_SEL_SH,
83 MMCR1_PMC8_ADDER_SEL_SH
84};
85
86/*
87 * Layout of constraint bits:
88 * 6666555555555544444444443333333333222222222211111111110000000000
89 * 3210987654321098765432109876543210987654321098765432109876543210
90 * <><><>[ >[ >[ >< >< >< >< ><><><><><><><><>
91 * SPT0T1 UC PS1 PS2 B0 B1 B2 B3 P1P2P3P4P5P6P7P8
92 *
93 * SP - SPCSEL constraint
94 * 48-49: SPCSEL value 0x3_0000_0000_0000
95 *
96 * T0 - TTM0 constraint
97 * 46-47: TTM0SEL value (0=FPU, 2=IFU, 3=VPU) 0xC000_0000_0000
98 *
99 * T1 - TTM1 constraint
100 * 44-45: TTM1SEL value (0=IDU, 3=STS) 0x3000_0000_0000
101 *
102 * UC - unit constraint: can't have all three of FPU|IFU|VPU, ISU, IDU|STS
103 * 43: UC3 error 0x0800_0000_0000
104 * 42: FPU|IFU|VPU events needed 0x0400_0000_0000
105 * 41: ISU events needed 0x0200_0000_0000
106 * 40: IDU|STS events needed 0x0100_0000_0000
107 *
108 * PS1
109 * 39: PS1 error 0x0080_0000_0000
110 * 36-38: count of events needing PMC1/2/5/6 0x0070_0000_0000
111 *
112 * PS2
113 * 35: PS2 error 0x0008_0000_0000
114 * 32-34: count of events needing PMC3/4/7/8 0x0007_0000_0000
115 *
116 * B0
117 * 28-31: Byte 0 event source 0xf000_0000
118 * Encoding as for the event code
119 *
120 * B1, B2, B3
121 * 24-27, 20-23, 16-19: Byte 1, 2, 3 event sources
122 *
123 * P1
124 * 15: P1 error 0x8000
125 * 14-15: Count of events needing PMC1
126 *
127 * P2..P8
128 * 0-13: Count of events needing PMC2..PMC8
129 */
130
131static unsigned char direct_marked_event[8] = {
132 (1<<2) | (1<<3), /* PMC1: PM_MRK_GRP_DISP, PM_MRK_ST_CMPL */
133 (1<<3) | (1<<5), /* PMC2: PM_THRESH_TIMEO, PM_MRK_BRU_FIN */
134 (1<<3) | (1<<5), /* PMC3: PM_MRK_ST_CMPL_INT, PM_MRK_VMX_FIN */
135 (1<<4) | (1<<5), /* PMC4: PM_MRK_GRP_CMPL, PM_MRK_CRU_FIN */
136 (1<<4) | (1<<5), /* PMC5: PM_GRP_MRK, PM_MRK_GRP_TIMEO */
137 (1<<3) | (1<<4) | (1<<5),
138 /* PMC6: PM_MRK_ST_STS, PM_MRK_FXU_FIN, PM_MRK_GRP_ISSUED */
139 (1<<4) | (1<<5), /* PMC7: PM_MRK_FPU_FIN, PM_MRK_INST_FIN */
140 (1<<4) /* PMC8: PM_MRK_LSU_FIN */
141};
142
143/*
144 * Returns 1 if event counts things relating to marked instructions
145 * and thus needs the MMCRA_SAMPLE_ENABLE bit set, or 0 if not.
146 */
147static int p970_marked_instr_event(u64 event)
148{
149 int pmc, psel, unit, byte, bit;
150 unsigned int mask;
151
152 pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
153 psel = event & PM_PMCSEL_MSK;
154 if (pmc) {
155 if (direct_marked_event[pmc - 1] & (1 << psel))
156 return 1;
157 if (psel == 0) /* add events */
158 bit = (pmc <= 4)? pmc - 1: 8 - pmc;
159 else if (psel == 7 || psel == 13) /* decode events */
160 bit = 4;
161 else
162 return 0;
163 } else
164 bit = psel;
165
166 byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
167 unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
168 mask = 0;
169 switch (unit) {
170 case PM_VPU:
171 mask = 0x4c; /* byte 0 bits 2,3,6 */
172 break;
173 case PM_LSU0:
174 /* byte 2 bits 0,2,3,4,6; all of byte 1 */
175 mask = 0x085dff00;
176 break;
177 case PM_LSU1L:
178 mask = 0x50 << 24; /* byte 3 bits 4,6 */
179 break;
180 }
181 return (mask >> (byte * 8 + bit)) & 1;
182}
183
184/* Masks and values for using events from the various units */
185static unsigned long unit_cons[PM_LASTUNIT+1][2] = {
186 [PM_FPU] = { 0xc80000000000ull, 0x040000000000ull },
187 [PM_VPU] = { 0xc80000000000ull, 0xc40000000000ull },
188 [PM_ISU] = { 0x080000000000ull, 0x020000000000ull },
189 [PM_IFU] = { 0xc80000000000ull, 0x840000000000ull },
190 [PM_IDU] = { 0x380000000000ull, 0x010000000000ull },
191 [PM_STS] = { 0x380000000000ull, 0x310000000000ull },
192};
193
194static int p970_get_constraint(u64 event, unsigned long *maskp,
195 unsigned long *valp)
196{
197 int pmc, byte, unit, sh, spcsel;
198 unsigned long mask = 0, value = 0;
199 int grp = -1;
200
201 pmc = (event >> PM_PMC_SH) & PM_PMC_MSK;
202 if (pmc) {
203 if (pmc > 8)
204 return -1;
205 sh = (pmc - 1) * 2;
206 mask |= 2 << sh;
207 value |= 1 << sh;
208 grp = ((pmc - 1) >> 1) & 1;
209 }
210 unit = (event >> PM_UNIT_SH) & PM_UNIT_MSK;
211 if (unit) {
212 if (unit > PM_LASTUNIT)
213 return -1;
214 mask |= unit_cons[unit][0];
215 value |= unit_cons[unit][1];
216 byte = (event >> PM_BYTE_SH) & PM_BYTE_MSK;
217 /*
218 * Bus events on bytes 0 and 2 can be counted
219 * on PMC1/2/5/6; bytes 1 and 3 on PMC3/4/7/8.
220 */
221 if (!pmc)
222 grp = byte & 1;
223 /* Set byte lane select field */
224 mask |= 0xfULL << (28 - 4 * byte);
225 value |= (unsigned long)unit << (28 - 4 * byte);
226 }
227 if (grp == 0) {
228 /* increment PMC1/2/5/6 field */
229 mask |= 0x8000000000ull;
230 value |= 0x1000000000ull;
231 } else if (grp == 1) {
232 /* increment PMC3/4/7/8 field */
233 mask |= 0x800000000ull;
234 value |= 0x100000000ull;
235 }
236 spcsel = (event >> PM_SPCSEL_SH) & PM_SPCSEL_MSK;
237 if (spcsel) {
238 mask |= 3ull << 48;
239 value |= (unsigned long)spcsel << 48;
240 }
241 *maskp = mask;
242 *valp = value;
243 return 0;
244}
245
246static int p970_get_alternatives(u64 event, unsigned int flags, u64 alt[])
247{
248 alt[0] = event;
249
250 /* 2 alternatives for LSU empty */
251 if (event == 0x2002 || event == 0x3002) {
252 alt[1] = event ^ 0x1000;
253 return 2;
254 }
255
256 return 1;
257}
258
259static int p970_compute_mmcr(u64 event[], int n_ev,
260 unsigned int hwc[], unsigned long mmcr[])
261{
262 unsigned long mmcr0 = 0, mmcr1 = 0, mmcra = 0;
263 unsigned int pmc, unit, byte, psel;
264 unsigned int ttm, grp;
265 unsigned int pmc_inuse = 0;
266 unsigned int pmc_grp_use[2];
267 unsigned char busbyte[4];
268 unsigned char unituse[16];
269 unsigned char unitmap[] = { 0, 0<<3, 3<<3, 1<<3, 2<<3, 0|4, 3|4 };
270 unsigned char ttmuse[2];
271 unsigned char pmcsel[8];
272 int i;
273 int spcsel;
274
275 if (n_ev > 8)
276 return -1;
277
278 /* First pass to count resource use */
279 pmc_grp_use[0] = pmc_grp_use[1] = 0;
280 memset(busbyte, 0, sizeof(busbyte));
281 memset(unituse, 0, sizeof(unituse));
282 for (i = 0; i < n_ev; ++i) {
283 pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
284 if (pmc) {
285 if (pmc_inuse & (1 << (pmc - 1)))
286 return -1;
287 pmc_inuse |= 1 << (pmc - 1);
288 /* count 1/2/5/6 vs 3/4/7/8 use */
289 ++pmc_grp_use[((pmc - 1) >> 1) & 1];
290 }
291 unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
292 byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK;
293 if (unit) {
294 if (unit > PM_LASTUNIT)
295 return -1;
296 if (!pmc)
297 ++pmc_grp_use[byte & 1];
298 if (busbyte[byte] && busbyte[byte] != unit)
299 return -1;
300 busbyte[byte] = unit;
301 unituse[unit] = 1;
302 }
303 }
304 if (pmc_grp_use[0] > 4 || pmc_grp_use[1] > 4)
305 return -1;
306
307 /*
308 * Assign resources and set multiplexer selects.
309 *
310 * PM_ISU can go either on TTM0 or TTM1, but that's the only
311 * choice we have to deal with.
312 */
313 if (unituse[PM_ISU] &
314 (unituse[PM_FPU] | unituse[PM_IFU] | unituse[PM_VPU]))
315 unitmap[PM_ISU] = 2 | 4; /* move ISU to TTM1 */
316 /* Set TTM[01]SEL fields. */
317 ttmuse[0] = ttmuse[1] = 0;
318 for (i = PM_FPU; i <= PM_STS; ++i) {
319 if (!unituse[i])
320 continue;
321 ttm = unitmap[i];
322 ++ttmuse[(ttm >> 2) & 1];
323 mmcr1 |= (unsigned long)(ttm & ~4) << MMCR1_TTM1SEL_SH;
324 }
325 /* Check only one unit per TTMx */
326 if (ttmuse[0] > 1 || ttmuse[1] > 1)
327 return -1;
328
329 /* Set byte lane select fields and TTM3SEL. */
330 for (byte = 0; byte < 4; ++byte) {
331 unit = busbyte[byte];
332 if (!unit)
333 continue;
334 if (unit <= PM_STS)
335 ttm = (unitmap[unit] >> 2) & 1;
336 else if (unit == PM_LSU0)
337 ttm = 2;
338 else {
339 ttm = 3;
340 if (unit == PM_LSU1L && byte >= 2)
341 mmcr1 |= 1ull << (MMCR1_TTM3SEL_SH + 3 - byte);
342 }
343 mmcr1 |= (unsigned long)ttm
344 << (MMCR1_TD_CP_DBG0SEL_SH - 2 * byte);
345 }
346
347 /* Second pass: assign PMCs, set PMCxSEL and PMCx_ADDER_SEL fields */
348 memset(pmcsel, 0x8, sizeof(pmcsel)); /* 8 means don't count */
349 for (i = 0; i < n_ev; ++i) {
350 pmc = (event[i] >> PM_PMC_SH) & PM_PMC_MSK;
351 unit = (event[i] >> PM_UNIT_SH) & PM_UNIT_MSK;
352 byte = (event[i] >> PM_BYTE_SH) & PM_BYTE_MSK;
353 psel = event[i] & PM_PMCSEL_MSK;
354 if (!pmc) {
355 /* Bus event or any-PMC direct event */
356 if (unit)
357 psel |= 0x10 | ((byte & 2) << 2);
358 else
359 psel |= 8;
360 for (pmc = 0; pmc < 8; ++pmc) {
361 if (pmc_inuse & (1 << pmc))
362 continue;
363 grp = (pmc >> 1) & 1;
364 if (unit) {
365 if (grp == (byte & 1))
366 break;
367 } else if (pmc_grp_use[grp] < 4) {
368 ++pmc_grp_use[grp];
369 break;
370 }
371 }
372 pmc_inuse |= 1 << pmc;
373 } else {
374 /* Direct event */
375 --pmc;
376 if (psel == 0 && (byte & 2))
377 /* add events on higher-numbered bus */
378 mmcr1 |= 1ull << mmcr1_adder_bits[pmc];
379 }
380 pmcsel[pmc] = psel;
381 hwc[i] = pmc;
382 spcsel = (event[i] >> PM_SPCSEL_SH) & PM_SPCSEL_MSK;
383 mmcr1 |= spcsel;
384 if (p970_marked_instr_event(event[i]))
385 mmcra |= MMCRA_SAMPLE_ENABLE;
386 }
387 for (pmc = 0; pmc < 2; ++pmc)
388 mmcr0 |= pmcsel[pmc] << (MMCR0_PMC1SEL_SH - 7 * pmc);
389 for (; pmc < 8; ++pmc)
390 mmcr1 |= (unsigned long)pmcsel[pmc]
391 << (MMCR1_PMC3SEL_SH - 5 * (pmc - 2));
392 if (pmc_inuse & 1)
393 mmcr0 |= MMCR0_PMC1CE;
394 if (pmc_inuse & 0xfe)
395 mmcr0 |= MMCR0_PMCjCE;
396
397 mmcra |= 0x2000; /* mark only one IOP per PPC instruction */
398
399 /* Return MMCRx values */
400 mmcr[0] = mmcr0;
401 mmcr[1] = mmcr1;
402 mmcr[2] = mmcra;
403 return 0;
404}
405
406static void p970_disable_pmc(unsigned int pmc, unsigned long mmcr[])
407{
408 int shift, i;
409
410 if (pmc <= 1) {
411 shift = MMCR0_PMC1SEL_SH - 7 * pmc;
412 i = 0;
413 } else {
414 shift = MMCR1_PMC3SEL_SH - 5 * (pmc - 2);
415 i = 1;
416 }
417 /*
418 * Setting the PMCxSEL field to 0x08 disables PMC x.
419 */
420 mmcr[i] = (mmcr[i] & ~(0x1fUL << shift)) | (0x08UL << shift);
421}
422
423static int ppc970_generic_events[] = {
424 [PERF_COUNT_HW_CPU_CYCLES] = 7,
425 [PERF_COUNT_HW_INSTRUCTIONS] = 1,
426 [PERF_COUNT_HW_CACHE_REFERENCES] = 0x8810, /* PM_LD_REF_L1 */
427 [PERF_COUNT_HW_CACHE_MISSES] = 0x3810, /* PM_LD_MISS_L1 */
428 [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x431, /* PM_BR_ISSUED */
429 [PERF_COUNT_HW_BRANCH_MISSES] = 0x327, /* PM_GRP_BR_MPRED */
430};
431
432#define C(x) PERF_COUNT_HW_CACHE_##x
433
434/*
435 * Table of generalized cache-related events.
436 * 0 means not supported, -1 means nonsensical, other values
437 * are event codes.
438 */
439static int ppc970_cache_events[C(MAX)][C(OP_MAX)][C(RESULT_MAX)] = {
440 [C(L1D)] = { /* RESULT_ACCESS RESULT_MISS */
441 [C(OP_READ)] = { 0x8810, 0x3810 },
442 [C(OP_WRITE)] = { 0x7810, 0x813 },
443 [C(OP_PREFETCH)] = { 0x731, 0 },
444 },
445 [C(L1I)] = { /* RESULT_ACCESS RESULT_MISS */
446 [C(OP_READ)] = { 0, 0 },
447 [C(OP_WRITE)] = { -1, -1 },
448 [C(OP_PREFETCH)] = { 0, 0 },
449 },
450 [C(LL)] = { /* RESULT_ACCESS RESULT_MISS */
451 [C(OP_READ)] = { 0, 0 },
452 [C(OP_WRITE)] = { 0, 0 },
453 [C(OP_PREFETCH)] = { 0x733, 0 },
454 },
455 [C(DTLB)] = { /* RESULT_ACCESS RESULT_MISS */
456 [C(OP_READ)] = { 0, 0x704 },
457 [C(OP_WRITE)] = { -1, -1 },
458 [C(OP_PREFETCH)] = { -1, -1 },
459 },
460 [C(ITLB)] = { /* RESULT_ACCESS RESULT_MISS */
461 [C(OP_READ)] = { 0, 0x700 },
462 [C(OP_WRITE)] = { -1, -1 },
463 [C(OP_PREFETCH)] = { -1, -1 },
464 },
465 [C(BPU)] = { /* RESULT_ACCESS RESULT_MISS */
466 [C(OP_READ)] = { 0x431, 0x327 },
467 [C(OP_WRITE)] = { -1, -1 },
468 [C(OP_PREFETCH)] = { -1, -1 },
469 },
470 [C(NODE)] = { /* RESULT_ACCESS RESULT_MISS */
471 [C(OP_READ)] = { -1, -1 },
472 [C(OP_WRITE)] = { -1, -1 },
473 [C(OP_PREFETCH)] = { -1, -1 },
474 },
475};
476
477static struct power_pmu ppc970_pmu = {
478 .name = "PPC970/FX/MP",
479 .n_counter = 8,
480 .max_alternatives = 2,
481 .add_fields = 0x001100005555ull,
482 .test_adder = 0x013300000000ull,
483 .compute_mmcr = p970_compute_mmcr,
484 .get_constraint = p970_get_constraint,
485 .get_alternatives = p970_get_alternatives,
486 .disable_pmc = p970_disable_pmc,
487 .n_generic = ARRAY_SIZE(ppc970_generic_events),
488 .generic_events = ppc970_generic_events,
489 .cache_events = &ppc970_cache_events,
490};
491
492static int __init init_ppc970_pmu(void)
493{
494 if (!cur_cpu_spec->oprofile_cpu_type ||
495 (strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/970")
496 && strcmp(cur_cpu_spec->oprofile_cpu_type, "ppc64/970MP")))
497 return -ENODEV;
498
499 return register_power_pmu(&ppc970_pmu);
500}
501
502early_initcall(init_ppc970_pmu);
diff --git a/arch/powerpc/kvm/e500_tlb.h b/arch/powerpc/kvm/e500_tlb.h
new file mode 100644
index 00000000000..59b88e99a23
--- /dev/null
+++ b/arch/powerpc/kvm/e500_tlb.h
@@ -0,0 +1,196 @@
1/*
2 * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All rights reserved.
3 *
4 * Author: Yu Liu, yu.liu@freescale.com
5 *
6 * Description:
7 * This file is based on arch/powerpc/kvm/44x_tlb.h,
8 * by Hollis Blanchard <hollisb@us.ibm.com>.
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, version 2, as
12 * published by the Free Software Foundation.
13 */
14
15#ifndef __KVM_E500_TLB_H__
16#define __KVM_E500_TLB_H__
17
18#include <linux/kvm_host.h>
19#include <asm/mmu-book3e.h>
20#include <asm/tlb.h>
21#include <asm/kvm_e500.h>
22
23#define KVM_E500_TLB0_WAY_SIZE_BIT 7 /* Fixed */
24#define KVM_E500_TLB0_WAY_SIZE (1UL << KVM_E500_TLB0_WAY_SIZE_BIT)
25#define KVM_E500_TLB0_WAY_SIZE_MASK (KVM_E500_TLB0_WAY_SIZE - 1)
26
27#define KVM_E500_TLB0_WAY_NUM_BIT 1 /* No greater than 7 */
28#define KVM_E500_TLB0_WAY_NUM (1UL << KVM_E500_TLB0_WAY_NUM_BIT)
29#define KVM_E500_TLB0_WAY_NUM_MASK (KVM_E500_TLB0_WAY_NUM - 1)
30
31#define KVM_E500_TLB0_SIZE (KVM_E500_TLB0_WAY_SIZE * KVM_E500_TLB0_WAY_NUM)
32#define KVM_E500_TLB1_SIZE 16
33
34#define index_of(tlbsel, esel) (((tlbsel) << 16) | ((esel) & 0xFFFF))
35#define tlbsel_of(index) ((index) >> 16)
36#define esel_of(index) ((index) & 0xFFFF)
37
38#define E500_TLB_USER_PERM_MASK (MAS3_UX|MAS3_UR|MAS3_UW)
39#define E500_TLB_SUPER_PERM_MASK (MAS3_SX|MAS3_SR|MAS3_SW)
40#define MAS2_ATTRIB_MASK \
41 (MAS2_X0 | MAS2_X1)
42#define MAS3_ATTRIB_MASK \
43 (MAS3_U0 | MAS3_U1 | MAS3_U2 | MAS3_U3 \
44 | E500_TLB_USER_PERM_MASK | E500_TLB_SUPER_PERM_MASK)
45
46extern void kvmppc_dump_tlbs(struct kvm_vcpu *);
47extern int kvmppc_e500_emul_mt_mmucsr0(struct kvmppc_vcpu_e500 *, ulong);
48extern int kvmppc_e500_emul_tlbwe(struct kvm_vcpu *);
49extern int kvmppc_e500_emul_tlbre(struct kvm_vcpu *);
50extern int kvmppc_e500_emul_tlbivax(struct kvm_vcpu *, int, int);
51extern int kvmppc_e500_emul_tlbsx(struct kvm_vcpu *, int);
52extern int kvmppc_e500_tlb_search(struct kvm_vcpu *, gva_t, unsigned int, int);
53extern void kvmppc_e500_tlb_put(struct kvm_vcpu *);
54extern void kvmppc_e500_tlb_load(struct kvm_vcpu *, int);
55extern int kvmppc_e500_tlb_init(struct kvmppc_vcpu_e500 *);
56extern void kvmppc_e500_tlb_uninit(struct kvmppc_vcpu_e500 *);
57extern void kvmppc_e500_tlb_setup(struct kvmppc_vcpu_e500 *);
58extern void kvmppc_e500_recalc_shadow_pid(struct kvmppc_vcpu_e500 *);
59
60/* TLB helper functions */
61static inline unsigned int get_tlb_size(const struct tlbe *tlbe)
62{
63 return (tlbe->mas1 >> 7) & 0x1f;
64}
65
66static inline gva_t get_tlb_eaddr(const struct tlbe *tlbe)
67{
68 return tlbe->mas2 & 0xfffff000;
69}
70
71static inline u64 get_tlb_bytes(const struct tlbe *tlbe)
72{
73 unsigned int pgsize = get_tlb_size(tlbe);
74 return 1ULL << 10 << pgsize;
75}
76
77static inline gva_t get_tlb_end(const struct tlbe *tlbe)
78{
79 u64 bytes = get_tlb_bytes(tlbe);
80 return get_tlb_eaddr(tlbe) + bytes - 1;
81}
82
83static inline u64 get_tlb_raddr(const struct tlbe *tlbe)
84{
85 u64 rpn = tlbe->mas7;
86 return (rpn << 32) | (tlbe->mas3 & 0xfffff000);
87}
88
89static inline unsigned int get_tlb_tid(const struct tlbe *tlbe)
90{
91 return (tlbe->mas1 >> 16) & 0xff;
92}
93
94static inline unsigned int get_tlb_ts(const struct tlbe *tlbe)
95{
96 return (tlbe->mas1 >> 12) & 0x1;
97}
98
99static inline unsigned int get_tlb_v(const struct tlbe *tlbe)
100{
101 return (tlbe->mas1 >> 31) & 0x1;
102}
103
104static inline unsigned int get_tlb_iprot(const struct tlbe *tlbe)
105{
106 return (tlbe->mas1 >> 30) & 0x1;
107}
108
109static inline unsigned int get_cur_pid(struct kvm_vcpu *vcpu)
110{
111 return vcpu->arch.pid & 0xff;
112}
113
114static inline unsigned int get_cur_as(struct kvm_vcpu *vcpu)
115{
116 return !!(vcpu->arch.shared->msr & (MSR_IS | MSR_DS));
117}
118
119static inline unsigned int get_cur_pr(struct kvm_vcpu *vcpu)
120{
121 return !!(vcpu->arch.shared->msr & MSR_PR);
122}
123
124static inline unsigned int get_cur_spid(
125 const struct kvmppc_vcpu_e500 *vcpu_e500)
126{
127 return (vcpu_e500->mas6 >> 16) & 0xff;
128}
129
130static inline unsigned int get_cur_sas(
131 const struct kvmppc_vcpu_e500 *vcpu_e500)
132{
133 return vcpu_e500->mas6 & 0x1;
134}
135
136static inline unsigned int get_tlb_tlbsel(
137 const struct kvmppc_vcpu_e500 *vcpu_e500)
138{
139 /*
140 * Manual says that tlbsel has 2 bits wide.
141 * Since we only have two TLBs, only lower bit is used.
142 */
143 return (vcpu_e500->mas0 >> 28) & 0x1;
144}
145
146static inline unsigned int get_tlb_nv_bit(
147 const struct kvmppc_vcpu_e500 *vcpu_e500)
148{
149 return vcpu_e500->mas0 & 0xfff;
150}
151
152static inline unsigned int get_tlb_esel_bit(
153 const struct kvmppc_vcpu_e500 *vcpu_e500)
154{
155 return (vcpu_e500->mas0 >> 16) & 0xfff;
156}
157
158static inline unsigned int get_tlb_esel(
159 const struct kvmppc_vcpu_e500 *vcpu_e500,
160 int tlbsel)
161{
162 unsigned int esel = get_tlb_esel_bit(vcpu_e500);
163
164 if (tlbsel == 0) {
165 esel &= KVM_E500_TLB0_WAY_NUM_MASK;
166 esel |= ((vcpu_e500->mas2 >> 12) & KVM_E500_TLB0_WAY_SIZE_MASK)
167 << KVM_E500_TLB0_WAY_NUM_BIT;
168 } else {
169 esel &= KVM_E500_TLB1_SIZE - 1;
170 }
171
172 return esel;
173}
174
175static inline int tlbe_is_host_safe(const struct kvm_vcpu *vcpu,
176 const struct tlbe *tlbe)
177{
178 gpa_t gpa;
179
180 if (!get_tlb_v(tlbe))
181 return 0;
182
183 /* Does it match current guest AS? */
184 /* XXX what about IS != DS? */
185 if (get_tlb_ts(tlbe) != !!(vcpu->arch.shared->msr & MSR_IS))
186 return 0;
187
188 gpa = get_tlb_raddr(tlbe);
189 if (!gfn_to_memslot(vcpu->kvm, gpa >> PAGE_SHIFT))
190 /* Mapping is not for RAM. */
191 return 0;
192
193 return 1;
194}
195
196#endif /* __KVM_E500_TLB_H__ */
diff --git a/arch/powerpc/platforms/40x/hcu4.c b/arch/powerpc/platforms/40x/hcu4.c
new file mode 100644
index 00000000000..60b2afecab7
--- /dev/null
+++ b/arch/powerpc/platforms/40x/hcu4.c
@@ -0,0 +1,61 @@
1/*
2 * Architecture- / platform-specific boot-time initialization code for
3 * IBM PowerPC 4xx based boards. Adapted from original
4 * code by Gary Thomas, Cort Dougan <cort@fsmlabs.com>, and Dan Malek
5 * <dan@net4x.com>.
6 *
7 * Copyright(c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
8 *
9 * Rewritten and ported to the merged powerpc tree:
10 * Copyright 2007 IBM Corporation
11 * Josh Boyer <jwboyer@linux.vnet.ibm.com>
12 *
13 * 2002 (c) MontaVista, Software, Inc. This file is licensed under
14 * the terms of the GNU General Public License version 2. This program
15 * is licensed "as is" without any warranty of any kind, whether express
16 * or implied.
17 */
18
19#include <linux/init.h>
20#include <linux/of_platform.h>
21
22#include <asm/machdep.h>
23#include <asm/prom.h>
24#include <asm/udbg.h>
25#include <asm/time.h>
26#include <asm/uic.h>
27#include <asm/ppc4xx.h>
28
29static __initdata struct of_device_id hcu4_of_bus[] = {
30 { .compatible = "ibm,plb3", },
31 { .compatible = "ibm,opb", },
32 { .compatible = "ibm,ebc", },
33 {},
34};
35
36static int __init hcu4_device_probe(void)
37{
38 of_platform_bus_probe(NULL, hcu4_of_bus, NULL);
39 return 0;
40}
41machine_device_initcall(hcu4, hcu4_device_probe);
42
43static int __init hcu4_probe(void)
44{
45 unsigned long root = of_get_flat_dt_root();
46
47 if (!of_flat_dt_is_compatible(root, "netstal,hcu4"))
48 return 0;
49
50 return 1;
51}
52
53define_machine(hcu4) {
54 .name = "HCU4",
55 .probe = hcu4_probe,
56 .progress = udbg_progress,
57 .init_IRQ = uic_init_tree,
58 .get_irq = uic_get_irq,
59 .restart = ppc4xx_reset_system,
60 .calibrate_decr = generic_calibrate_decr,
61};
diff --git a/arch/powerpc/platforms/85xx/p2040_rdb.c b/arch/powerpc/platforms/85xx/p2040_rdb.c
new file mode 100644
index 00000000000..32b56ac73df
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/p2040_rdb.c
@@ -0,0 +1,88 @@
1/*
2 * P2040 RDB Setup
3 *
4 * Copyright 2011 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 <linux/kernel.h>
13#include <linux/pci.h>
14#include <linux/kdev_t.h>
15#include <linux/delay.h>
16#include <linux/interrupt.h>
17#include <linux/phy.h>
18
19#include <asm/system.h>
20#include <asm/time.h>
21#include <asm/machdep.h>
22#include <asm/pci-bridge.h>
23#include <mm/mmu_decl.h>
24#include <asm/prom.h>
25#include <asm/udbg.h>
26#include <asm/mpic.h>
27
28#include <linux/of_platform.h>
29#include <sysdev/fsl_soc.h>
30#include <sysdev/fsl_pci.h>
31#include <asm/ehv_pic.h>
32
33#include "corenet_ds.h"
34
35/*
36 * Called very early, device-tree isn't unflattened
37 */
38static int __init p2040_rdb_probe(void)
39{
40 unsigned long root = of_get_flat_dt_root();
41#ifdef CONFIG_SMP
42 extern struct smp_ops_t smp_85xx_ops;
43#endif
44
45 if (of_flat_dt_is_compatible(root, "fsl,P2040RDB"))
46 return 1;
47
48 /* Check if we're running under the Freescale hypervisor */
49 if (of_flat_dt_is_compatible(root, "fsl,P2040RDB-hv")) {
50 ppc_md.init_IRQ = ehv_pic_init;
51 ppc_md.get_irq = ehv_pic_get_irq;
52 ppc_md.restart = fsl_hv_restart;
53 ppc_md.power_off = fsl_hv_halt;
54 ppc_md.halt = fsl_hv_halt;
55#ifdef CONFIG_SMP
56 /*
57 * Disable the timebase sync operations because we can't write
58 * to the timebase registers under the hypervisor.
59 */
60 smp_85xx_ops.give_timebase = NULL;
61 smp_85xx_ops.take_timebase = NULL;
62#endif
63 return 1;
64 }
65
66 return 0;
67}
68
69define_machine(p2040_rdb) {
70 .name = "P2040 RDB",
71 .probe = p2040_rdb_probe,
72 .setup_arch = corenet_ds_setup_arch,
73 .init_IRQ = corenet_ds_pic_init,
74#ifdef CONFIG_PCI
75 .pcibios_fixup_bus = fsl_pcibios_fixup_bus,
76#endif
77 .get_irq = mpic_get_coreint_irq,
78 .restart = fsl_rstcr_restart,
79 .calibrate_decr = generic_calibrate_decr,
80 .progress = udbg_progress,
81 .power_save = e500_idle,
82};
83
84machine_device_initcall(p2040_rdb, corenet_ds_publish_devices);
85
86#ifdef CONFIG_SWIOTLB
87machine_arch_initcall(p2040_rdb, swiotlb_setup_bus_notifier);
88#endif
diff --git a/arch/powerpc/platforms/85xx/sbc8560.c b/arch/powerpc/platforms/85xx/sbc8560.c
new file mode 100644
index 00000000000..09ced722175
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/sbc8560.c
@@ -0,0 +1,318 @@
1/*
2 * Wind River SBC8560 setup and early boot code.
3 *
4 * Copyright 2007 Wind River Systems Inc.
5 *
6 * By Paul Gortmaker (see MAINTAINERS for contact information)
7 *
8 * Based largely on the MPC8560ADS support - Copyright 2005 Freescale Inc.
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 <linux/stddef.h>
17#include <linux/kernel.h>
18#include <linux/pci.h>
19#include <linux/kdev_t.h>
20#include <linux/delay.h>
21#include <linux/seq_file.h>
22#include <linux/of_platform.h>
23
24#include <asm/system.h>
25#include <asm/time.h>
26#include <asm/machdep.h>
27#include <asm/pci-bridge.h>
28#include <asm/mpic.h>
29#include <mm/mmu_decl.h>
30#include <asm/udbg.h>
31
32#include <sysdev/fsl_soc.h>
33#include <sysdev/fsl_pci.h>
34
35#ifdef CONFIG_CPM2
36#include <asm/cpm2.h>
37#include <sysdev/cpm2_pic.h>
38#endif
39
40#ifdef CONFIG_CPM2
41
42static void cpm2_cascade(unsigned int irq, struct irq_desc *desc)
43{
44 struct irq_chip *chip = irq_desc_get_chip(desc);
45 int cascade_irq;
46
47 while ((cascade_irq = cpm2_get_irq()) >= 0)
48 generic_handle_irq(cascade_irq);
49
50 chip->irq_eoi(&desc->irq_data);
51}
52
53#endif /* CONFIG_CPM2 */
54
55static void __init sbc8560_pic_init(void)
56{
57 struct mpic *mpic;
58 struct resource r;
59 struct device_node *np = NULL;
60#ifdef CONFIG_CPM2
61 int irq;
62#endif
63
64 np = of_find_node_by_type(np, "open-pic");
65 if (!np) {
66 printk(KERN_ERR "Could not find open-pic node\n");
67 return;
68 }
69
70 if (of_address_to_resource(np, 0, &r)) {
71 printk(KERN_ERR "Could not map mpic register space\n");
72 of_node_put(np);
73 return;
74 }
75
76 mpic = mpic_alloc(np, r.start,
77 MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN,
78 0, 256, " OpenPIC ");
79 BUG_ON(mpic == NULL);
80 of_node_put(np);
81
82 mpic_init(mpic);
83
84#ifdef CONFIG_CPM2
85 /* Setup CPM2 PIC */
86 np = of_find_compatible_node(NULL, NULL, "fsl,cpm2-pic");
87 if (np == NULL) {
88 printk(KERN_ERR "PIC init: can not find fsl,cpm2-pic node\n");
89 return;
90 }
91 irq = irq_of_parse_and_map(np, 0);
92
93 cpm2_pic_init(np);
94 of_node_put(np);
95 irq_set_chained_handler(irq, cpm2_cascade);
96#endif
97}
98
99/*
100 * Setup the architecture
101 */
102#ifdef CONFIG_CPM2
103struct cpm_pin {
104 int port, pin, flags;
105};
106
107static const struct cpm_pin sbc8560_pins[] = {
108 /* SCC1 */
109 {3, 29, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
110 {3, 30, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY},
111 {3, 31, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
112
113 /* SCC2 */
114 {3, 26, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
115 {3, 27, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
116 {3, 28, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
117
118 /* FCC2 */
119 {1, 18, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
120 {1, 19, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
121 {1, 20, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
122 {1, 21, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
123 {1, 22, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
124 {1, 23, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
125 {1, 24, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
126 {1, 25, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
127 {1, 26, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
128 {1, 27, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
129 {1, 28, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
130 {1, 29, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY},
131 {1, 30, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
132 {1, 31, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
133 {2, 18, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, /* CLK14 */
134 {2, 19, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, /* CLK13 */
135
136 /* FCC3 */
137 {1, 4, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
138 {1, 5, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
139 {1, 6, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
140 {1, 7, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
141 {1, 8, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
142 {1, 9, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
143 {1, 10, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
144 {1, 11, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
145 {1, 12, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
146 {1, 13, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
147 {1, 14, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
148 {1, 15, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY},
149 {1, 16, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
150 {1, 17, CPM_PIN_INPUT | CPM_PIN_PRIMARY},
151 {2, 16, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, /* CLK16 */
152 {2, 17, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, /* CLK15 */
153};
154
155static void __init init_ioports(void)
156{
157 int i;
158
159 for (i = 0; i < ARRAY_SIZE(sbc8560_pins); i++) {
160 const struct cpm_pin *pin = &sbc8560_pins[i];
161 cpm2_set_pin(pin->port, pin->pin, pin->flags);
162 }
163
164 cpm2_clk_setup(CPM_CLK_SCC1, CPM_BRG1, CPM_CLK_RX);
165 cpm2_clk_setup(CPM_CLK_SCC1, CPM_BRG1, CPM_CLK_TX);
166 cpm2_clk_setup(CPM_CLK_SCC2, CPM_BRG2, CPM_CLK_RX);
167 cpm2_clk_setup(CPM_CLK_SCC2, CPM_BRG2, CPM_CLK_TX);
168 cpm2_clk_setup(CPM_CLK_FCC2, CPM_CLK13, CPM_CLK_RX);
169 cpm2_clk_setup(CPM_CLK_FCC2, CPM_CLK14, CPM_CLK_TX);
170 cpm2_clk_setup(CPM_CLK_FCC3, CPM_CLK15, CPM_CLK_RX);
171 cpm2_clk_setup(CPM_CLK_FCC3, CPM_CLK16, CPM_CLK_TX);
172}
173#endif
174
175static void __init sbc8560_setup_arch(void)
176{
177#ifdef CONFIG_PCI
178 struct device_node *np;
179#endif
180
181 if (ppc_md.progress)
182 ppc_md.progress("sbc8560_setup_arch()", 0);
183
184#ifdef CONFIG_CPM2
185 cpm2_reset();
186 init_ioports();
187#endif
188
189#ifdef CONFIG_PCI
190 for_each_compatible_node(np, "pci", "fsl,mpc8540-pci")
191 fsl_add_bridge(np, 1);
192#endif
193}
194
195static void sbc8560_show_cpuinfo(struct seq_file *m)
196{
197 uint pvid, svid, phid1;
198
199 pvid = mfspr(SPRN_PVR);
200 svid = mfspr(SPRN_SVR);
201
202 seq_printf(m, "Vendor\t\t: Wind River\n");
203 seq_printf(m, "PVR\t\t: 0x%x\n", pvid);
204 seq_printf(m, "SVR\t\t: 0x%x\n", svid);
205
206 /* Display cpu Pll setting */
207 phid1 = mfspr(SPRN_HID1);
208 seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f));
209}
210
211static struct of_device_id __initdata of_bus_ids[] = {
212 { .name = "soc", },
213 { .type = "soc", },
214 { .name = "cpm", },
215 { .name = "localbus", },
216 { .compatible = "simple-bus", },
217 { .compatible = "gianfar", },
218 {},
219};
220
221static int __init declare_of_platform_devices(void)
222{
223 of_platform_bus_probe(NULL, of_bus_ids, NULL);
224
225 return 0;
226}
227machine_device_initcall(sbc8560, declare_of_platform_devices);
228
229/*
230 * Called very early, device-tree isn't unflattened
231 */
232static int __init sbc8560_probe(void)
233{
234 unsigned long root = of_get_flat_dt_root();
235
236 return of_flat_dt_is_compatible(root, "SBC8560");
237}
238
239#ifdef CONFIG_RTC_DRV_M48T59
240static int __init sbc8560_rtc_init(void)
241{
242 struct device_node *np;
243 struct resource res;
244 struct platform_device *rtc_dev;
245
246 np = of_find_compatible_node(NULL, NULL, "m48t59");
247 if (np == NULL) {
248 printk("No RTC in DTB. Has it been eaten by wild dogs?\n");
249 return -ENODEV;
250 }
251
252 of_address_to_resource(np, 0, &res);
253 of_node_put(np);
254
255 printk("Found RTC (m48t59) at i/o 0x%x\n", res.start);
256
257 rtc_dev = platform_device_register_simple("rtc-m48t59", 0, &res, 1);
258
259 if (IS_ERR(rtc_dev)) {
260 printk("Registering sbc8560 RTC device failed\n");
261 return PTR_ERR(rtc_dev);
262 }
263
264 return 0;
265}
266
267arch_initcall(sbc8560_rtc_init);
268
269#endif /* M48T59 */
270
271static __u8 __iomem *brstcr;
272
273static int __init sbc8560_bdrstcr_init(void)
274{
275 struct device_node *np;
276 struct resource res;
277
278 np = of_find_compatible_node(NULL, NULL, "wrs,sbc8560-brstcr");
279 if (np == NULL) {
280 printk(KERN_WARNING "sbc8560: No board specific RSTCR in DTB.\n");
281 return -ENODEV;
282 }
283
284 of_address_to_resource(np, 0, &res);
285
286 printk(KERN_INFO "sbc8560: Found BRSTCR at i/o 0x%x\n", res.start);
287
288 brstcr = ioremap(res.start, resource_size(&res));
289 if(!brstcr)
290 printk(KERN_WARNING "sbc8560: ioremap of brstcr failed.\n");
291
292 of_node_put(np);
293
294 return 0;
295}
296
297arch_initcall(sbc8560_bdrstcr_init);
298
299void sbc8560_rstcr_restart(char * cmd)
300{
301 local_irq_disable();
302 if(brstcr)
303 clrbits8(brstcr, 0x80);
304
305 while(1);
306}
307
308define_machine(sbc8560) {
309 .name = "SBC8560",
310 .probe = sbc8560_probe,
311 .setup_arch = sbc8560_setup_arch,
312 .init_IRQ = sbc8560_pic_init,
313 .show_cpuinfo = sbc8560_show_cpuinfo,
314 .get_irq = mpic_get_irq,
315 .restart = sbc8560_rstcr_restart,
316 .calibrate_decr = generic_calibrate_decr,
317 .progress = udbg_progress,
318};
diff --git a/arch/powerpc/platforms/86xx/gef_gpio.c b/arch/powerpc/platforms/86xx/gef_gpio.c
new file mode 100644
index 00000000000..4ff7b1e7bba
--- /dev/null
+++ b/arch/powerpc/platforms/86xx/gef_gpio.c
@@ -0,0 +1,170 @@
1/*
2 * Driver for GE FPGA based GPIO
3 *
4 * Author: Martyn Welch <martyn.welch@ge.com>
5 *
6 * 2008 (c) GE Intelligent Platforms Embedded Systems, Inc.
7 *
8 * This file is licensed under the terms of the GNU General Public License
9 * version 2. This program is licensed "as is" without any warranty of any
10 * kind, whether express or implied.
11 */
12
13/* TODO
14 *
15 * Configuration of output modes (totem-pole/open-drain)
16 * Interrupt configuration - interrupts are always generated the FPGA relies on
17 * the I/O interrupt controllers mask to stop them propergating
18 */
19
20#include <linux/kernel.h>
21#include <linux/compiler.h>
22#include <linux/init.h>
23#include <linux/io.h>
24#include <linux/of.h>
25#include <linux/of_device.h>
26#include <linux/of_platform.h>
27#include <linux/of_gpio.h>
28#include <linux/gpio.h>
29#include <linux/slab.h>
30
31#define GEF_GPIO_DIRECT 0x00
32#define GEF_GPIO_IN 0x04
33#define GEF_GPIO_OUT 0x08
34#define GEF_GPIO_TRIG 0x0C
35#define GEF_GPIO_POLAR_A 0x10
36#define GEF_GPIO_POLAR_B 0x14
37#define GEF_GPIO_INT_STAT 0x18
38#define GEF_GPIO_OVERRUN 0x1C
39#define GEF_GPIO_MODE 0x20
40
41static void _gef_gpio_set(void __iomem *reg, unsigned int offset, int value)
42{
43 unsigned int data;
44
45 data = ioread32be(reg);
46 /* value: 0=low; 1=high */
47 if (value & 0x1)
48 data = data | (0x1 << offset);
49 else
50 data = data & ~(0x1 << offset);
51
52 iowrite32be(data, reg);
53}
54
55
56static int gef_gpio_dir_in(struct gpio_chip *chip, unsigned offset)
57{
58 unsigned int data;
59 struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
60
61 data = ioread32be(mmchip->regs + GEF_GPIO_DIRECT);
62 data = data | (0x1 << offset);
63 iowrite32be(data, mmchip->regs + GEF_GPIO_DIRECT);
64
65 return 0;
66}
67
68static int gef_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int value)
69{
70 unsigned int data;
71 struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
72
73 /* Set direction before switching to input */
74 _gef_gpio_set(mmchip->regs + GEF_GPIO_OUT, offset, value);
75
76 data = ioread32be(mmchip->regs + GEF_GPIO_DIRECT);
77 data = data & ~(0x1 << offset);
78 iowrite32be(data, mmchip->regs + GEF_GPIO_DIRECT);
79
80 return 0;
81}
82
83static int gef_gpio_get(struct gpio_chip *chip, unsigned offset)
84{
85 unsigned int data;
86 int state = 0;
87 struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
88
89 data = ioread32be(mmchip->regs + GEF_GPIO_IN);
90 state = (int)((data >> offset) & 0x1);
91
92 return state;
93}
94
95static void gef_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
96{
97 struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
98
99 _gef_gpio_set(mmchip->regs + GEF_GPIO_OUT, offset, value);
100}
101
102static int __init gef_gpio_init(void)
103{
104 struct device_node *np;
105 int retval;
106 struct of_mm_gpio_chip *gef_gpio_chip;
107
108 for_each_compatible_node(np, NULL, "gef,sbc610-gpio") {
109
110 pr_debug("%s: Initialising GEF GPIO\n", np->full_name);
111
112 /* Allocate chip structure */
113 gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL);
114 if (!gef_gpio_chip) {
115 pr_err("%s: Unable to allocate structure\n",
116 np->full_name);
117 continue;
118 }
119
120 /* Setup pointers to chip functions */
121 gef_gpio_chip->gc.of_gpio_n_cells = 2;
122 gef_gpio_chip->gc.ngpio = 19;
123 gef_gpio_chip->gc.direction_input = gef_gpio_dir_in;
124 gef_gpio_chip->gc.direction_output = gef_gpio_dir_out;
125 gef_gpio_chip->gc.get = gef_gpio_get;
126 gef_gpio_chip->gc.set = gef_gpio_set;
127
128 /* This function adds a memory mapped GPIO chip */
129 retval = of_mm_gpiochip_add(np, gef_gpio_chip);
130 if (retval) {
131 kfree(gef_gpio_chip);
132 pr_err("%s: Unable to add GPIO\n", np->full_name);
133 }
134 }
135
136 for_each_compatible_node(np, NULL, "gef,sbc310-gpio") {
137
138 pr_debug("%s: Initialising GEF GPIO\n", np->full_name);
139
140 /* Allocate chip structure */
141 gef_gpio_chip = kzalloc(sizeof(*gef_gpio_chip), GFP_KERNEL);
142 if (!gef_gpio_chip) {
143 pr_err("%s: Unable to allocate structure\n",
144 np->full_name);
145 continue;
146 }
147
148 /* Setup pointers to chip functions */
149 gef_gpio_chip->gc.of_gpio_n_cells = 2;
150 gef_gpio_chip->gc.ngpio = 6;
151 gef_gpio_chip->gc.direction_input = gef_gpio_dir_in;
152 gef_gpio_chip->gc.direction_output = gef_gpio_dir_out;
153 gef_gpio_chip->gc.get = gef_gpio_get;
154 gef_gpio_chip->gc.set = gef_gpio_set;
155
156 /* This function adds a memory mapped GPIO chip */
157 retval = of_mm_gpiochip_add(np, gef_gpio_chip);
158 if (retval) {
159 kfree(gef_gpio_chip);
160 pr_err("%s: Unable to add GPIO\n", np->full_name);
161 }
162 }
163
164 return 0;
165};
166arch_initcall(gef_gpio_init);
167
168MODULE_DESCRIPTION("GE I/O FPGA GPIO driver");
169MODULE_AUTHOR("Martyn Welch <martyn.welch@ge.com");
170MODULE_LICENSE("GPL");
diff --git a/arch/powerpc/platforms/86xx/gef_pic.c b/arch/powerpc/platforms/86xx/gef_pic.c
new file mode 100644
index 00000000000..94594e58594
--- /dev/null
+++ b/arch/powerpc/platforms/86xx/gef_pic.c
@@ -0,0 +1,252 @@
1/*
2 * Interrupt handling for GE FPGA based PIC
3 *
4 * Author: Martyn Welch <martyn.welch@ge.com>
5 *
6 * 2008 (c) GE Intelligent Platforms Embedded Systems, Inc.
7 *
8 * This file is licensed under the terms of the GNU General Public License
9 * version 2. This program is licensed "as is" without any warranty of any
10 * kind, whether express or implied.
11 */
12
13#include <linux/stddef.h>
14#include <linux/kernel.h>
15#include <linux/init.h>
16#include <linux/irq.h>
17#include <linux/interrupt.h>
18#include <linux/spinlock.h>
19
20#include <asm/byteorder.h>
21#include <asm/io.h>
22#include <asm/prom.h>
23#include <asm/irq.h>
24
25#include "gef_pic.h"
26
27#define DEBUG
28#undef DEBUG
29
30#ifdef DEBUG
31#define DBG(fmt...) do { printk(KERN_DEBUG "gef_pic: " fmt); } while (0)
32#else
33#define DBG(fmt...) do { } while (0)
34#endif
35
36#define GEF_PIC_NUM_IRQS 32
37
38/* Interrupt Controller Interface Registers */
39#define GEF_PIC_INTR_STATUS 0x0000
40
41#define GEF_PIC_INTR_MASK(cpu) (0x0010 + (0x4 * cpu))
42#define GEF_PIC_CPU0_INTR_MASK GEF_PIC_INTR_MASK(0)
43#define GEF_PIC_CPU1_INTR_MASK GEF_PIC_INTR_MASK(1)
44
45#define GEF_PIC_MCP_MASK(cpu) (0x0018 + (0x4 * cpu))
46#define GEF_PIC_CPU0_MCP_MASK GEF_PIC_MCP_MASK(0)
47#define GEF_PIC_CPU1_MCP_MASK GEF_PIC_MCP_MASK(1)
48
49
50static DEFINE_RAW_SPINLOCK(gef_pic_lock);
51
52static void __iomem *gef_pic_irq_reg_base;
53static struct irq_host *gef_pic_irq_host;
54static int gef_pic_cascade_irq;
55
56/*
57 * Interrupt Controller Handling
58 *
59 * The interrupt controller handles interrupts for most on board interrupts,
60 * apart from PCI interrupts. For example on SBC610:
61 *
62 * 17:31 RO Reserved
63 * 16 RO PCI Express Doorbell 3 Status
64 * 15 RO PCI Express Doorbell 2 Status
65 * 14 RO PCI Express Doorbell 1 Status
66 * 13 RO PCI Express Doorbell 0 Status
67 * 12 RO Real Time Clock Interrupt Status
68 * 11 RO Temperature Interrupt Status
69 * 10 RO Temperature Critical Interrupt Status
70 * 9 RO Ethernet PHY1 Interrupt Status
71 * 8 RO Ethernet PHY3 Interrupt Status
72 * 7 RO PEX8548 Interrupt Status
73 * 6 RO Reserved
74 * 5 RO Watchdog 0 Interrupt Status
75 * 4 RO Watchdog 1 Interrupt Status
76 * 3 RO AXIS Message FIFO A Interrupt Status
77 * 2 RO AXIS Message FIFO B Interrupt Status
78 * 1 RO AXIS Message FIFO C Interrupt Status
79 * 0 RO AXIS Message FIFO D Interrupt Status
80 *
81 * Interrupts can be forwarded to one of two output lines. Nothing
82 * clever is done, so if the masks are incorrectly set, a single input
83 * interrupt could generate interrupts on both output lines!
84 *
85 * The dual lines are there to allow the chained interrupts to be easily
86 * passed into two different cores. We currently do not use this functionality
87 * in this driver.
88 *
89 * Controller can also be configured to generate Machine checks (MCP), again on
90 * two lines, to be attached to two different cores. It is suggested that these
91 * should be masked out.
92 */
93
94void gef_pic_cascade(unsigned int irq, struct irq_desc *desc)
95{
96 struct irq_chip *chip = irq_desc_get_chip(desc);
97 unsigned int cascade_irq;
98
99 /*
100 * See if we actually have an interrupt, call generic handling code if
101 * we do.
102 */
103 cascade_irq = gef_pic_get_irq();
104
105 if (cascade_irq != NO_IRQ)
106 generic_handle_irq(cascade_irq);
107
108 chip->irq_eoi(&desc->irq_data);
109}
110
111static void gef_pic_mask(struct irq_data *d)
112{
113 unsigned long flags;
114 unsigned int hwirq = irqd_to_hwirq(d);
115 u32 mask;
116
117 raw_spin_lock_irqsave(&gef_pic_lock, flags);
118 mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0));
119 mask &= ~(1 << hwirq);
120 out_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0), mask);
121 raw_spin_unlock_irqrestore(&gef_pic_lock, flags);
122}
123
124static void gef_pic_mask_ack(struct irq_data *d)
125{
126 /* Don't think we actually have to do anything to ack an interrupt,
127 * we just need to clear down the devices interrupt and it will go away
128 */
129 gef_pic_mask(d);
130}
131
132static void gef_pic_unmask(struct irq_data *d)
133{
134 unsigned long flags;
135 unsigned int hwirq = irqd_to_hwirq(d);
136 u32 mask;
137
138 raw_spin_lock_irqsave(&gef_pic_lock, flags);
139 mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0));
140 mask |= (1 << hwirq);
141 out_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0), mask);
142 raw_spin_unlock_irqrestore(&gef_pic_lock, flags);
143}
144
145static struct irq_chip gef_pic_chip = {
146 .name = "gefp",
147 .irq_mask = gef_pic_mask,
148 .irq_mask_ack = gef_pic_mask_ack,
149 .irq_unmask = gef_pic_unmask,
150};
151
152
153/* When an interrupt is being configured, this call allows some flexibilty
154 * in deciding which irq_chip structure is used
155 */
156static int gef_pic_host_map(struct irq_host *h, unsigned int virq,
157 irq_hw_number_t hwirq)
158{
159 /* All interrupts are LEVEL sensitive */
160 irq_set_status_flags(virq, IRQ_LEVEL);
161 irq_set_chip_and_handler(virq, &gef_pic_chip, handle_level_irq);
162
163 return 0;
164}
165
166static int gef_pic_host_xlate(struct irq_host *h, struct device_node *ct,
167 const u32 *intspec, unsigned int intsize,
168 irq_hw_number_t *out_hwirq, unsigned int *out_flags)
169{
170
171 *out_hwirq = intspec[0];
172 if (intsize > 1)
173 *out_flags = intspec[1];
174 else
175 *out_flags = IRQ_TYPE_LEVEL_HIGH;
176
177 return 0;
178}
179
180static struct irq_host_ops gef_pic_host_ops = {
181 .map = gef_pic_host_map,
182 .xlate = gef_pic_host_xlate,
183};
184
185
186/*
187 * Initialisation of PIC, this should be called in BSP
188 */
189void __init gef_pic_init(struct device_node *np)
190{
191 unsigned long flags;
192
193 /* Map the devices registers into memory */
194 gef_pic_irq_reg_base = of_iomap(np, 0);
195
196 raw_spin_lock_irqsave(&gef_pic_lock, flags);
197
198 /* Initialise everything as masked. */
199 out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU0_INTR_MASK, 0);
200 out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU1_INTR_MASK, 0);
201
202 out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU0_MCP_MASK, 0);
203 out_be32(gef_pic_irq_reg_base + GEF_PIC_CPU1_MCP_MASK, 0);
204
205 raw_spin_unlock_irqrestore(&gef_pic_lock, flags);
206
207 /* Map controller */
208 gef_pic_cascade_irq = irq_of_parse_and_map(np, 0);
209 if (gef_pic_cascade_irq == NO_IRQ) {
210 printk(KERN_ERR "SBC610: failed to map cascade interrupt");
211 return;
212 }
213
214 /* Setup an irq_host structure */
215 gef_pic_irq_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR,
216 GEF_PIC_NUM_IRQS,
217 &gef_pic_host_ops, NO_IRQ);
218 if (gef_pic_irq_host == NULL)
219 return;
220
221 /* Chain with parent controller */
222 irq_set_chained_handler(gef_pic_cascade_irq, gef_pic_cascade);
223}
224
225/*
226 * This is called when we receive an interrupt with apparently comes from this
227 * chip - check, returning the highest interrupt generated or return NO_IRQ
228 */
229unsigned int gef_pic_get_irq(void)
230{
231 u32 cause, mask, active;
232 unsigned int virq = NO_IRQ;
233 int hwirq;
234
235 cause = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_STATUS);
236
237 mask = in_be32(gef_pic_irq_reg_base + GEF_PIC_INTR_MASK(0));
238
239 active = cause & mask;
240
241 if (active) {
242 for (hwirq = GEF_PIC_NUM_IRQS - 1; hwirq > -1; hwirq--) {
243 if (active & (0x1 << hwirq))
244 break;
245 }
246 virq = irq_linear_revmap(gef_pic_irq_host,
247 (irq_hw_number_t)hwirq);
248 }
249
250 return virq;
251}
252
diff --git a/arch/powerpc/platforms/86xx/gef_pic.h b/arch/powerpc/platforms/86xx/gef_pic.h
new file mode 100644
index 00000000000..6149916da3f
--- /dev/null
+++ b/arch/powerpc/platforms/86xx/gef_pic.h
@@ -0,0 +1,11 @@
1#ifndef __GEF_PIC_H__
2#define __GEF_PIC_H__
3
4#include <linux/init.h>
5
6void gef_pic_cascade(unsigned int, struct irq_desc *);
7unsigned int gef_pic_get_irq(void);
8void gef_pic_init(struct device_node *);
9
10#endif /* __GEF_PIC_H__ */
11
diff --git a/arch/powerpc/platforms/iseries/Kconfig b/arch/powerpc/platforms/iseries/Kconfig
new file mode 100644
index 00000000000..b57cda3a081
--- /dev/null
+++ b/arch/powerpc/platforms/iseries/Kconfig
@@ -0,0 +1,38 @@
1config PPC_ISERIES
2 bool "IBM Legacy iSeries"
3 depends on PPC64 && PPC_BOOK3S
4 select PPC_SMP_MUXED_IPI
5 select PPC_INDIRECT_PIO
6 select PPC_INDIRECT_MMIO
7 select PPC_PCI_CHOICE if EXPERT
8
9menu "iSeries device drivers"
10 depends on PPC_ISERIES
11
12config VIODASD
13 tristate "iSeries Virtual I/O disk support"
14 depends on BLOCK
15 select VIOPATH
16 help
17 If you are running on an iSeries system and you want to use
18 virtual disks created and managed by OS/400, say Y.
19
20config VIOCD
21 tristate "iSeries Virtual I/O CD support"
22 depends on BLOCK
23 select VIOPATH
24 help
25 If you are running Linux on an IBM iSeries system and you want to
26 read a CD drive owned by OS/400, say Y here.
27
28config VIOTAPE
29 tristate "iSeries Virtual Tape Support"
30 select VIOPATH
31 help
32 If you are running Linux on an iSeries system and you want Linux
33 to read and/or write a tape drive owned by OS/400, say Y here.
34
35endmenu
36
37config VIOPATH
38 bool
diff --git a/arch/powerpc/platforms/iseries/Makefile b/arch/powerpc/platforms/iseries/Makefile
new file mode 100644
index 00000000000..a7602b11ed9
--- /dev/null
+++ b/arch/powerpc/platforms/iseries/Makefile
@@ -0,0 +1,9 @@
1ccflags-y := -mno-minimal-toc
2
3obj-y += exception.o
4obj-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
6obj-$(CONFIG_PCI) += pci.o
7obj-$(CONFIG_SMP) += smp.o
8obj-$(CONFIG_VIOPATH) += viopath.o vio.o
9obj-$(CONFIG_MODULES) += ksyms.o
diff --git a/arch/powerpc/platforms/iseries/call_hpt.h b/arch/powerpc/platforms/iseries/call_hpt.h
new file mode 100644
index 00000000000..8d95fe4b554
--- /dev/null
+++ b/arch/powerpc/platforms/iseries/call_hpt.h
@@ -0,0 +1,102 @@
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
43static inline u64 HvCallHpt_getHptAddress(void)
44{
45 return HvCall0(HvCallHptGetHptAddress);
46}
47
48static inline u64 HvCallHpt_getHptPages(void)
49{
50 return HvCall0(HvCallHptGetHptPages);
51}
52
53static inline void HvCallHpt_setPp(u32 hpteIndex, u8 value)
54{
55 HvCall2(HvCallHptSetPp, hpteIndex, value);
56}
57
58static inline void HvCallHpt_setSwBits(u32 hpteIndex, u8 bitson, u8 bitsoff)
59{
60 HvCall3(HvCallHptSetSwBits, hpteIndex, bitson, bitsoff);
61}
62
63static inline void HvCallHpt_invalidateNoSyncICache(u32 hpteIndex)
64{
65 HvCall1(HvCallHptInvalidateNoSyncICache, hpteIndex);
66}
67
68static 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
79static inline u64 HvCallHpt_findValid(struct hash_pte *hpte, u64 vpn)
80{
81 return HvCall3Ret16(HvCallHptFindValid, hpte, vpn, 0, 0);
82}
83
84static 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
91static inline void HvCallHpt_get(struct hash_pte *hpte, u32 hpteIndex)
92{
93 HvCall2Ret16(HvCallHptGet, hpte, hpteIndex, 0);
94}
95
96static 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
new file mode 100644
index 00000000000..dbdf69850ed
--- /dev/null
+++ b/arch/powerpc/platforms/iseries/call_pci.h
@@ -0,0 +1,309 @@
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 */
35struct 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
43union HvDsaMap {
44 u64 DsaAddr;
45 struct HvCallPci_DsaAddr Dsa;
46};
47
48struct HvCallPci_LoadReturn {
49 u64 rc;
50 u64 value;
51};
52
53enum 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
63struct HvCallPci_DeviceInfo {
64 u32 deviceType; /* See DeviceType enum for values */
65};
66
67struct HvCallPci_BusUnitInfo {
68 u32 sizeReturned; /* length of data returned */
69 u32 deviceType; /* see DeviceType enum for values */
70};
71
72struct 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 */
86enum {HvCallPci_MaxBusUnitInfoSize = 128};
87
88struct 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
99enum 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
129static 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
148static 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
167static 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
181static 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
198static 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
213static 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
227static 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
241static 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
255static 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
269static 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
283static 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
298static 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
new file mode 100644
index 00000000000..c7e251619f4
--- /dev/null
+++ b/arch/powerpc/platforms/iseries/call_sm.h
@@ -0,0 +1,37 @@
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
31static 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
new file mode 100644
index 00000000000..f0491cc2890
--- /dev/null
+++ b/arch/powerpc/platforms/iseries/dt.c
@@ -0,0 +1,643 @@
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 */
56extern char __dt_strings_start[];
57extern char __dt_strings_end[];
58
59#define DS(s) ({ \
60 static const char __s[] __attribute__((section(".dt_strings"))) = s; \
61 __s; \
62})
63
64struct iseries_flat_dt {
65 struct boot_param_header header;
66 u64 reserve_map[2];
67};
68
69static 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 */
75static char __initdata device_type_cpu[] = "cpu";
76static char __initdata device_type_memory[] = "memory";
77static char __initdata device_type_serial[] = "serial";
78static char __initdata device_type_network[] = "network";
79static char __initdata device_type_pci[] = "pci";
80static char __initdata device_type_vdevice[] = "vdevice";
81static char __initdata device_type_vscsi[] = "vscsi";
82
83
84/* EBCDIC to ASCII conversion routines */
85
86static 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
107static 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
120static 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
151static 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
158static 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
165static 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
172static 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
180static 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
203static 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
210static 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
225static 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
279static 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
299static 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
310static 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
328static 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
373struct pci_class_name {
374 u16 code;
375 const char *name;
376 const char *type;
377};
378
379static struct pci_class_name __initdata pci_class_name[] = {
380 { PCI_CLASS_NETWORK_ETHERNET, "ethernet", device_type_network },
381};
382
383static 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 */
397static 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
491static 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
532static 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
563static 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
599static 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
606void * __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
new file mode 100644
index 00000000000..f519ee17ff7
--- /dev/null
+++ b/arch/powerpc/platforms/iseries/exception.S
@@ -0,0 +1,311 @@
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
41system_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 */
561: 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
64iSeries_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
802:
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
99iSeries_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
1153:
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
127iSeries_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
147data_access_iSeries:
148 mtspr SPRN_SPRG_SCRATCH0,r13
149BEGIN_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
169FTR_SECTION_ELSE
170 EXCEPTION_PROLOG_1(PACA_EXGEN, NOTEST, 0)
171 EXCEPTION_PROLOG_ISERIES_1
172ALT_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
184data_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
207instruction_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__
229slb_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
252system_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
262decrementer_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
272hardware_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 */
2983: stdu r0,8(r8)
299 bdnz 3b
3004:
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
new file mode 100644
index 00000000000..50271b550a9
--- /dev/null
+++ b/arch/powerpc/platforms/iseries/exception.h
@@ -0,0 +1,58 @@
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; \
39label##_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; \
48label##_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
new file mode 100644
index 00000000000..3ae66ab9d5e
--- /dev/null
+++ b/arch/powerpc/platforms/iseries/htab.c
@@ -0,0 +1,257 @@
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
22static spinlock_t iSeries_hlocks[64] __cacheline_aligned_in_smp;
23
24/*
25 * Very primitive algorithm for picking up a lock
26 */
27static 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
34static 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
41static 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
100static 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
108static 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 */
144static 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 */
177static 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 */
207static 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
224static 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
245void __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
new file mode 100644
index 00000000000..07ae6ad5f49
--- /dev/null
+++ b/arch/powerpc/platforms/iseries/hvcall.S
@@ -0,0 +1,94 @@
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
new file mode 100644
index 00000000000..f476d71194f
--- /dev/null
+++ b/arch/powerpc/platforms/iseries/hvlog.c
@@ -0,0 +1,35 @@
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
17void 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
new file mode 100644
index 00000000000..f0475f0b185
--- /dev/null
+++ b/arch/powerpc/platforms/iseries/hvlpconfig.c
@@ -0,0 +1,39 @@
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/module.h>
20#include <asm/iseries/hv_lp_config.h>
21#include "it_lp_naca.h"
22
23HvLpIndex HvLpConfig_getLpIndex_outline(void)
24{
25 return HvLpConfig_getLpIndex();
26}
27EXPORT_SYMBOL(HvLpConfig_getLpIndex_outline);
28
29HvLpIndex HvLpConfig_getLpIndex(void)
30{
31 return itLpNaca.xLpIndex;
32}
33EXPORT_SYMBOL(HvLpConfig_getLpIndex);
34
35HvLpIndex HvLpConfig_getPrimaryLpIndex(void)
36{
37 return itLpNaca.xPrimaryLpIndex;
38}
39EXPORT_SYMBOL_GPL(HvLpConfig_getPrimaryLpIndex);
diff --git a/arch/powerpc/platforms/iseries/iommu.c b/arch/powerpc/platforms/iseries/iommu.c
new file mode 100644
index 00000000000..d8b76335bd1
--- /dev/null
+++ b/arch/powerpc/platforms/iseries/iommu.c
@@ -0,0 +1,260 @@
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/module.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
45static 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
78static 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 */
94struct 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 */
117void 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 */
154static 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
178static 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
203static struct iommu_table veth_iommu_table;
204static struct iommu_table vio_iommu_table;
205
206void *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}
211EXPORT_SYMBOL_GPL(iseries_hv_alloc);
212
213void 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}
217EXPORT_SYMBOL_GPL(iseries_hv_free);
218
219dma_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
227void 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
233void __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
246struct 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
253void 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
new file mode 100644
index 00000000000..83e4ca42fc5
--- /dev/null
+++ b/arch/powerpc/platforms/iseries/ipl_parms.h
@@ -0,0 +1,68 @@
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
31struct 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
new file mode 100644
index 00000000000..b2103453eb0
--- /dev/null
+++ b/arch/powerpc/platforms/iseries/irq.c
@@ -0,0 +1,400 @@
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
48enum 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
60struct 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
82static DEFINE_SPINLOCK(pending_irqs_lock);
83static int num_pending_irqs;
84static int pending_irqs[NR_IRQS];
85
86static 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
144static 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 */
169static 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 */
186static 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 */
210void __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 */
232static 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 */
255static 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
271static 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
279static 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 */
293int __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 */
311unsigned 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
345static int iseries_irq_host_map(struct irq_host *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
353static int iseries_irq_host_match(struct irq_host *h, struct device_node *np)
354{
355 /* Match all */
356 return 1;
357}
358
359static struct irq_host_ops iseries_irq_host_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 */
368void __init iSeries_init_IRQ(void)
369{
370 /* Register PCI event handler and open an event path */
371 struct irq_host *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_alloc_host(NULL, IRQ_HOST_MAP_NOMAP, 0,
384 &iseries_irq_host_ops, 0);
385 BUG_ON(host == NULL);
386 irq_set_default_host(host);
387
388 ret = HvLpEvent_registerHandler(HvLpEvent_Type_PciIo,
389 &pci_event_handler);
390 if (ret == 0) {
391 ret = HvLpEvent_openPath(HvLpEvent_Type_PciIo, 0);
392 if (ret != 0)
393 printk(KERN_ERR "iseries_init_IRQ: open event path "
394 "failed with rc 0x%x\n", ret);
395 } else
396 printk(KERN_ERR "iseries_init_IRQ: register handler "
397 "failed with rc 0x%x\n", ret);
398}
399
400#endif /* CONFIG_PCI */
diff --git a/arch/powerpc/platforms/iseries/irq.h b/arch/powerpc/platforms/iseries/irq.h
new file mode 100644
index 00000000000..a1c23607403
--- /dev/null
+++ b/arch/powerpc/platforms/iseries/irq.h
@@ -0,0 +1,13 @@
1#ifndef _ISERIES_IRQ_H
2#define _ISERIES_IRQ_H
3
4#ifdef CONFIG_PCI
5extern void iSeries_init_IRQ(void);
6extern int iSeries_allocate_IRQ(HvBusNumber, HvSubBusNumber, u32);
7extern void iSeries_activate_IRQs(void);
8#else
9#define iSeries_init_IRQ NULL
10#endif
11extern 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
new file mode 100644
index 00000000000..6de9097b7f5
--- /dev/null
+++ b/arch/powerpc/platforms/iseries/it_exp_vpd_panel.h
@@ -0,0 +1,51 @@
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
30struct 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
49extern 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
new file mode 100644
index 00000000000..cf6dcf6ef07
--- /dev/null
+++ b/arch/powerpc/platforms/iseries/it_lp_naca.h
@@ -0,0 +1,80 @@
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
28struct 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
73extern 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
new file mode 100644
index 00000000000..2430848b98e
--- /dev/null
+++ b/arch/powerpc/platforms/iseries/ksyms.c
@@ -0,0 +1,21 @@
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/module.h>
10
11#include <asm/hw_irq.h>
12#include <asm/iseries/hv_call_sc.h>
13
14EXPORT_SYMBOL(HvCall0);
15EXPORT_SYMBOL(HvCall1);
16EXPORT_SYMBOL(HvCall2);
17EXPORT_SYMBOL(HvCall3);
18EXPORT_SYMBOL(HvCall4);
19EXPORT_SYMBOL(HvCall5);
20EXPORT_SYMBOL(HvCall6);
21EXPORT_SYMBOL(HvCall7);
diff --git a/arch/powerpc/platforms/iseries/lpardata.c b/arch/powerpc/platforms/iseries/lpardata.c
new file mode 100644
index 00000000000..98bd2d37038
--- /dev/null
+++ b/arch/powerpc/platforms/iseries/lpardata.c
@@ -0,0 +1,319 @@
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/module.h>
12#include <linux/bitops.h>
13#include <asm/processor.h>
14#include <asm/ptrace.h>
15#include <asm/abs_addr.h>
16#include <asm/lppaca.h>
17#include <asm/paca.h>
18#include <asm/iseries/lpar_map.h>
19#include <asm/iseries/it_lp_queue.h>
20#include <asm/iseries/alpaca.h>
21
22#include "naca.h"
23#include "vpd_areas.h"
24#include "spcomm_area.h"
25#include "ipl_parms.h"
26#include "processor_vpd.h"
27#include "release_data.h"
28#include "it_exp_vpd_panel.h"
29#include "it_lp_naca.h"
30
31/* The HvReleaseData is the root of the information shared between
32 * the hypervisor and Linux.
33 */
34const struct HvReleaseData hvReleaseData = {
35 .xDesc = 0xc8a5d9c4, /* "HvRD" ebcdic */
36 .xSize = sizeof(struct HvReleaseData),
37 .xVpdAreasPtrOffset = offsetof(struct naca_struct, xItVpdAreas),
38 .xSlicNacaAddr = &naca, /* 64-bit Naca address */
39 .xMsNucDataOffset = LPARMAP_PHYS,
40 .xFlags = HVREL_TAGSINACTIVE /* tags inactive */
41 /* 64 bit */
42 /* shared processors */
43 /* HMT allowed */
44 | 6, /* TEMP: This allows non-GA driver */
45 .xVrmIndex = 4, /* We are v5r2m0 */
46 .xMinSupportedPlicVrmIndex = 3, /* v5r1m0 */
47 .xMinCompatablePlicVrmIndex = 3, /* v5r1m0 */
48 .xVrmName = { 0xd3, 0x89, 0x95, 0xa4, /* "Linux 2.4.64" ebcdic */
49 0xa7, 0x40, 0xf2, 0x4b,
50 0xf4, 0x4b, 0xf6, 0xf4 },
51};
52
53/*
54 * The NACA. The first dword of the naca is required by the iSeries
55 * hypervisor to point to itVpdAreas. The hypervisor finds the NACA
56 * through the pointer in hvReleaseData.
57 */
58struct naca_struct naca = {
59 .xItVpdAreas = &itVpdAreas,
60 .xRamDisk = 0,
61 .xRamDiskSize = 0,
62};
63
64struct ItLpRegSave {
65 u32 xDesc; // Eye catcher "LpRS" ebcdic 000-003
66 u16 xSize; // Size of this class 004-005
67 u8 xInUse; // Area is live 006-007
68 u8 xRsvd1[9]; // Reserved 007-00F
69
70 u8 xFixedRegSave[352]; // Fixed Register Save Area 010-16F
71 u32 xCTRL; // Control Register 170-173
72 u32 xDEC; // Decrementer 174-177
73 u32 xFPSCR; // FP Status and Control Reg 178-17B
74 u32 xPVR; // Processor Version Number 17C-17F
75
76 u64 xMMCR0; // Monitor Mode Control Reg 0 180-187
77 u32 xPMC1; // Perf Monitor Counter 1 188-18B
78 u32 xPMC2; // Perf Monitor Counter 2 18C-18F
79 u32 xPMC3; // Perf Monitor Counter 3 190-193
80 u32 xPMC4; // Perf Monitor Counter 4 194-197
81 u32 xPIR; // Processor ID Reg 198-19B
82
83 u32 xMMCR1; // Monitor Mode Control Reg 1 19C-19F
84 u32 xMMCRA; // Monitor Mode Control Reg A 1A0-1A3
85 u32 xPMC5; // Perf Monitor Counter 5 1A4-1A7
86 u32 xPMC6; // Perf Monitor Counter 6 1A8-1AB
87 u32 xPMC7; // Perf Monitor Counter 7 1AC-1AF
88 u32 xPMC8; // Perf Monitor Counter 8 1B0-1B3
89 u32 xTSC; // Thread Switch Control 1B4-1B7
90 u32 xTST; // Thread Switch Timeout 1B8-1BB
91 u32 xRsvd; // Reserved 1BC-1BF
92
93 u64 xACCR; // Address Compare Control Reg 1C0-1C7
94 u64 xIMR; // Instruction Match Register 1C8-1CF
95 u64 xSDR1; // Storage Description Reg 1 1D0-1D7
96 u64 xSPRG0; // Special Purpose Reg General0 1D8-1DF
97 u64 xSPRG1; // Special Purpose Reg General1 1E0-1E7
98 u64 xSPRG2; // Special Purpose Reg General2 1E8-1EF
99 u64 xSPRG3; // Special Purpose Reg General3 1F0-1F7
100 u64 xTB; // Time Base Register 1F8-1FF
101
102 u64 xFPR[32]; // Floating Point Registers 200-2FF
103
104 u64 xMSR; // Machine State Register 300-307
105 u64 xNIA; // Next Instruction Address 308-30F
106
107 u64 xDABR; // Data Address Breakpoint Reg 310-317
108 u64 xIABR; // Inst Address Breakpoint Reg 318-31F
109
110 u64 xHID0; // HW Implementation Dependent0 320-327
111
112 u64 xHID4; // HW Implementation Dependent4 328-32F
113 u64 xSCOMd; // SCON Data Reg (SPRG4) 330-337
114 u64 xSCOMc; // SCON Command Reg (SPRG5) 338-33F
115 u64 xSDAR; // Sample Data Address Register 340-347
116 u64 xSIAR; // Sample Inst Address Register 348-34F
117
118 u8 xRsvd3[176]; // Reserved 350-3FF
119};
120
121extern void system_reset_iSeries(void);
122extern void machine_check_iSeries(void);
123extern void data_access_iSeries(void);
124extern void instruction_access_iSeries(void);
125extern void hardware_interrupt_iSeries(void);
126extern void alignment_iSeries(void);
127extern void program_check_iSeries(void);
128extern void fp_unavailable_iSeries(void);
129extern void decrementer_iSeries(void);
130extern void trap_0a_iSeries(void);
131extern void trap_0b_iSeries(void);
132extern void system_call_iSeries(void);
133extern void single_step_iSeries(void);
134extern void trap_0e_iSeries(void);
135extern void performance_monitor_iSeries(void);
136extern void data_access_slb_iSeries(void);
137extern void instruction_access_slb_iSeries(void);
138
139struct ItLpNaca itLpNaca = {
140 .xDesc = 0xd397d581, /* "LpNa" ebcdic */
141 .xSize = 0x0400, /* size of ItLpNaca */
142 .xIntHdlrOffset = 0x0300, /* offset to int array */
143 .xMaxIntHdlrEntries = 19, /* # ents */
144 .xPrimaryLpIndex = 0, /* Part # of primary */
145 .xServiceLpIndex = 0, /* Part # of serv */
146 .xLpIndex = 0, /* Part # of me */
147 .xMaxLpQueues = 0, /* # of LP queues */
148 .xLpQueueOffset = 0x100, /* offset of start of LP queues */
149 .xPirEnvironMode = 0, /* Piranha stuff */
150 .xPirConsoleMode = 0,
151 .xPirDasdMode = 0,
152 .flags = 0,
153 .xSpVpdFormat = 0,
154 .xIntProcRatio = 0,
155 .xPlicVrmIndex = 0, /* VRM index of PLIC */
156 .xMinSupportedSlicVrmInd = 0, /* min supported SLIC */
157 .xMinCompatableSlicVrmInd = 0, /* min compat SLIC */
158 .xLoadAreaAddr = 0, /* 64-bit addr of load area */
159 .xLoadAreaChunks = 0, /* chunks for load area */
160 .xPaseSysCallCRMask = 0, /* PASE mask */
161 .xSlicSegmentTablePtr = 0, /* seg table */
162 .xOldLpQueue = { 0 }, /* Old LP Queue */
163 .xInterruptHdlr = {
164 (u64)system_reset_iSeries, /* 0x100 System Reset */
165 (u64)machine_check_iSeries, /* 0x200 Machine Check */
166 (u64)data_access_iSeries, /* 0x300 Data Access */
167 (u64)instruction_access_iSeries, /* 0x400 Instruction Access */
168 (u64)hardware_interrupt_iSeries, /* 0x500 External */
169 (u64)alignment_iSeries, /* 0x600 Alignment */
170 (u64)program_check_iSeries, /* 0x700 Program Check */
171 (u64)fp_unavailable_iSeries, /* 0x800 FP Unavailable */
172 (u64)decrementer_iSeries, /* 0x900 Decrementer */
173 (u64)trap_0a_iSeries, /* 0xa00 Trap 0A */
174 (u64)trap_0b_iSeries, /* 0xb00 Trap 0B */
175 (u64)system_call_iSeries, /* 0xc00 System Call */
176 (u64)single_step_iSeries, /* 0xd00 Single Step */
177 (u64)trap_0e_iSeries, /* 0xe00 Trap 0E */
178 (u64)performance_monitor_iSeries,/* 0xf00 Performance Monitor */
179 0, /* int 0x1000 */
180 0, /* int 0x1010 */
181 0, /* int 0x1020 CPU ctls */
182 (u64)hardware_interrupt_iSeries, /* SC Ret Hdlr */
183 (u64)data_access_slb_iSeries, /* 0x380 D-SLB */
184 (u64)instruction_access_slb_iSeries /* 0x480 I-SLB */
185 }
186};
187
188/* May be filled in by the hypervisor so cannot end up in the BSS */
189static struct ItIplParmsReal xItIplParmsReal __attribute__((__section__(".data")));
190
191/* May be filled in by the hypervisor so cannot end up in the BSS */
192struct ItExtVpdPanel xItExtVpdPanel __attribute__((__section__(".data")));
193
194#define maxPhysicalProcessors 32
195
196struct IoHriProcessorVpd xIoHriProcessorVpd[maxPhysicalProcessors] = {
197 {
198 .xInstCacheOperandSize = 32,
199 .xDataCacheOperandSize = 32,
200 .xProcFreq = 50000000,
201 .xTimeBaseFreq = 50000000,
202 .xPVR = 0x3600
203 }
204};
205
206/* Space for Main Store Vpd 27,200 bytes */
207/* May be filled in by the hypervisor so cannot end up in the BSS */
208u64 xMsVpd[3400] __attribute__((__section__(".data")));
209
210/* Space for Recovery Log Buffer */
211/* May be filled in by the hypervisor so cannot end up in the BSS */
212static u64 xRecoveryLogBuffer[32] __attribute__((__section__(".data")));
213
214static const struct SpCommArea xSpCommArea = {
215 .xDesc = 0xE2D7C3C2,
216 .xFormat = 1,
217};
218
219static const struct ItLpRegSave iseries_reg_save[] = {
220 [0 ... (NR_CPUS-1)] = {
221 .xDesc = 0xd397d9e2, /* "LpRS" */
222 .xSize = sizeof(struct ItLpRegSave),
223 },
224};
225
226#define ALPACA_INIT(number) \
227{ \
228 .lppaca_ptr = &lppaca[number], \
229 .reg_save_ptr = &iseries_reg_save[number], \
230}
231
232const struct alpaca alpaca[] = {
233 ALPACA_INIT( 0),
234#if NR_CPUS > 1
235 ALPACA_INIT( 1), ALPACA_INIT( 2), ALPACA_INIT( 3),
236#if NR_CPUS > 4
237 ALPACA_INIT( 4), ALPACA_INIT( 5), ALPACA_INIT( 6), ALPACA_INIT( 7),
238#if NR_CPUS > 8
239 ALPACA_INIT( 8), ALPACA_INIT( 9), ALPACA_INIT(10), ALPACA_INIT(11),
240 ALPACA_INIT(12), ALPACA_INIT(13), ALPACA_INIT(14), ALPACA_INIT(15),
241 ALPACA_INIT(16), ALPACA_INIT(17), ALPACA_INIT(18), ALPACA_INIT(19),
242 ALPACA_INIT(20), ALPACA_INIT(21), ALPACA_INIT(22), ALPACA_INIT(23),
243 ALPACA_INIT(24), ALPACA_INIT(25), ALPACA_INIT(26), ALPACA_INIT(27),
244 ALPACA_INIT(28), ALPACA_INIT(29), ALPACA_INIT(30), ALPACA_INIT(31),
245#if NR_CPUS > 32
246 ALPACA_INIT(32), ALPACA_INIT(33), ALPACA_INIT(34), ALPACA_INIT(35),
247 ALPACA_INIT(36), ALPACA_INIT(37), ALPACA_INIT(38), ALPACA_INIT(39),
248 ALPACA_INIT(40), ALPACA_INIT(41), ALPACA_INIT(42), ALPACA_INIT(43),
249 ALPACA_INIT(44), ALPACA_INIT(45), ALPACA_INIT(46), ALPACA_INIT(47),
250 ALPACA_INIT(48), ALPACA_INIT(49), ALPACA_INIT(50), ALPACA_INIT(51),
251 ALPACA_INIT(52), ALPACA_INIT(53), ALPACA_INIT(54), ALPACA_INIT(55),
252 ALPACA_INIT(56), ALPACA_INIT(57), ALPACA_INIT(58), ALPACA_INIT(59),
253 ALPACA_INIT(60), ALPACA_INIT(61), ALPACA_INIT(62), ALPACA_INIT(63),
254#endif
255#endif
256#endif
257#endif
258};
259
260/* The LparMap data is now located at offset 0x6000 in head.S
261 * It was put there so that the HvReleaseData could address it
262 * with a 32-bit offset as required by the iSeries hypervisor
263 *
264 * The Naca has a pointer to the ItVpdAreas. The hypervisor finds
265 * the Naca via the HvReleaseData area. The HvReleaseData has the
266 * offset into the Naca of the pointer to the ItVpdAreas.
267 */
268const struct ItVpdAreas itVpdAreas = {
269 .xSlicDesc = 0xc9a3e5c1, /* "ItVA" */
270 .xSlicSize = sizeof(struct ItVpdAreas),
271 .xSlicVpdEntries = ItVpdMaxEntries, /* # VPD array entries */
272 .xSlicDmaEntries = ItDmaMaxEntries, /* # DMA array entries */
273 .xSlicMaxLogicalProcs = NR_CPUS * 2, /* Max logical procs */
274 .xSlicMaxPhysicalProcs = maxPhysicalProcessors, /* Max physical procs */
275 .xSlicDmaToksOffset = offsetof(struct ItVpdAreas, xPlicDmaToks),
276 .xSlicVpdAdrsOffset = offsetof(struct ItVpdAreas, xSlicVpdAdrs),
277 .xSlicDmaLensOffset = offsetof(struct ItVpdAreas, xPlicDmaLens),
278 .xSlicVpdLensOffset = offsetof(struct ItVpdAreas, xSlicVpdLens),
279 .xSlicMaxSlotLabels = 0, /* max slot labels */
280 .xSlicMaxLpQueues = 1, /* max LP queues */
281 .xPlicDmaLens = { 0 }, /* DMA lengths */
282 .xPlicDmaToks = { 0 }, /* DMA tokens */
283 .xSlicVpdLens = { /* VPD lengths */
284 0,0,0, /* 0 - 2 */
285 sizeof(xItExtVpdPanel), /* 3 Extended VPD */
286 sizeof(struct alpaca), /* 4 length of (fake) Paca */
287 0, /* 5 */
288 sizeof(struct ItIplParmsReal),/* 6 length of IPL parms */
289 26992, /* 7 length of MS VPD */
290 0, /* 8 */
291 sizeof(struct ItLpNaca),/* 9 length of LP Naca */
292 0, /* 10 */
293 256, /* 11 length of Recovery Log Buf */
294 sizeof(struct SpCommArea), /* 12 length of SP Comm Area */
295 0,0,0, /* 13 - 15 */
296 sizeof(struct IoHriProcessorVpd),/* 16 length of Proc Vpd */
297 0,0,0,0,0,0, /* 17 - 22 */
298 sizeof(struct hvlpevent_queue), /* 23 length of Lp Queue */
299 0,0 /* 24 - 25 */
300 },
301 .xSlicVpdAdrs = { /* VPD addresses */
302 0,0,0, /* 0 - 2 */
303 &xItExtVpdPanel, /* 3 Extended VPD */
304 &alpaca[0], /* 4 first (fake) Paca */
305 0, /* 5 */
306 &xItIplParmsReal, /* 6 IPL parms */
307 &xMsVpd, /* 7 MS Vpd */
308 0, /* 8 */
309 &itLpNaca, /* 9 LpNaca */
310 0, /* 10 */
311 &xRecoveryLogBuffer, /* 11 Recovery Log Buffer */
312 &xSpCommArea, /* 12 SP Comm Area */
313 0,0,0, /* 13 - 15 */
314 &xIoHriProcessorVpd, /* 16 Proc Vpd */
315 0,0,0,0,0,0, /* 17 - 22 */
316 &hvlpevent_queue, /* 23 Lp Queue */
317 0,0
318 }
319};
diff --git a/arch/powerpc/platforms/iseries/lpevents.c b/arch/powerpc/platforms/iseries/lpevents.c
new file mode 100644
index 00000000000..b0f8a857ec0
--- /dev/null
+++ b/arch/powerpc/platforms/iseries/lpevents.c
@@ -0,0 +1,341 @@
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/module.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 */
32struct hvlpevent_queue hvlpevent_queue __attribute__((__section__(".data")));
33
34DEFINE_PER_CPU(unsigned long[HvLpEvent_Type_NumTypes], hvlpevent_counts);
35
36static 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 */
49static LpEventHandler lpEventHandler[HvLpEvent_Type_NumTypes];
50static unsigned lpEventHandlerPaths[HvLpEvent_Type_NumTypes];
51
52static 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
78static unsigned long spread_lpevents = NR_CPUS;
79
80int 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
93static 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
120void 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
179static 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
198void __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 */
219int 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}
227EXPORT_SYMBOL(HvLpEvent_registerHandler);
228
229int 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}
248EXPORT_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 */
255int 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
268int 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
282static 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
319static int proc_lpevents_open(struct inode *inode, struct file *file)
320{
321 return single_open(file, proc_lpevents_show, NULL);
322}
323
324static 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
331static 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
new file mode 100644
index 00000000000..1a7a3f50e40
--- /dev/null
+++ b/arch/powerpc/platforms/iseries/main_store.h
@@ -0,0 +1,165 @@
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 */
23struct 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 */
64struct __attribute((packed)) IoHriMainStoreChipInfo1 {
65 u32 chipMfgID;
66 char chipECLevel[4];
67};
68
69struct IoHriMainStoreVpdIdData {
70 char typeNumber[4];
71 char modelNumber[4];
72 char partNumber[12];
73 char serialNumber[12];
74};
75
76struct __attribute((packed)) IoHriMainStoreVpdFruData {
77 char fruLabel[8];
78 u8 numberOfSlots;
79 u8 pluggingType;
80 u16 slotMapIndex;
81};
82
83struct __attribute((packed)) IoHriMainStoreAdrRangeBlock {
84 void *blockStart;
85 void *blockEnd;
86 u32 blockProcChipId;
87};
88
89#define MaxAreaAdrRangeBlocks 4
90
91struct __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
145struct 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
163extern 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
new file mode 100644
index 00000000000..62dabe3c2bf
--- /dev/null
+++ b/arch/powerpc/platforms/iseries/mf.c
@@ -0,0 +1,1274 @@
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/proc_fs.h>
34#include <linux/dma-mapping.h>
35#include <linux/bcd.h>
36#include <linux/rtc.h>
37#include <linux/slab.h>
38
39#include <asm/time.h>
40#include <asm/uaccess.h>
41#include <asm/paca.h>
42#include <asm/abs_addr.h>
43#include <asm/firmware.h>
44#include <asm/iseries/mf.h>
45#include <asm/iseries/hv_lp_config.h>
46#include <asm/iseries/hv_lp_event.h>
47#include <asm/iseries/it_lp_queue.h>
48
49#include "setup.h"
50
51static int mf_initialized;
52
53/*
54 * This is the structure layout for the Machine Facilities LPAR event
55 * flows.
56 */
57struct vsp_cmd_data {
58 u64 token;
59 u16 cmd;
60 HvLpIndex lp_index;
61 u8 result_code;
62 u32 reserved;
63 union {
64 u64 state; /* GetStateOut */
65 u64 ipl_type; /* GetIplTypeOut, Function02SelectIplTypeIn */
66 u64 ipl_mode; /* GetIplModeOut, Function02SelectIplModeIn */
67 u64 page[4]; /* GetSrcHistoryIn */
68 u64 flag; /* GetAutoIplWhenPrimaryIplsOut,
69 SetAutoIplWhenPrimaryIplsIn,
70 WhiteButtonPowerOffIn,
71 Function08FastPowerOffIn,
72 IsSpcnRackPowerIncompleteOut */
73 struct {
74 u64 token;
75 u64 address_type;
76 u64 side;
77 u32 length;
78 u32 offset;
79 } kern; /* SetKernelImageIn, GetKernelImageIn,
80 SetKernelCmdLineIn, GetKernelCmdLineIn */
81 u32 length_out; /* GetKernelImageOut, GetKernelCmdLineOut */
82 u8 reserved[80];
83 } sub_data;
84};
85
86struct vsp_rsp_data {
87 struct completion com;
88 struct vsp_cmd_data *response;
89};
90
91struct alloc_data {
92 u16 size;
93 u16 type;
94 u32 count;
95 u16 reserved1;
96 u8 reserved2;
97 HvLpIndex target_lp;
98};
99
100struct ce_msg_data;
101
102typedef void (*ce_msg_comp_hdlr)(void *token, struct ce_msg_data *vsp_cmd_rsp);
103
104struct ce_msg_comp_data {
105 ce_msg_comp_hdlr handler;
106 void *token;
107};
108
109struct ce_msg_data {
110 u8 ce_msg[12];
111 char reserved[4];
112 struct ce_msg_comp_data *completion;
113};
114
115struct io_mf_lp_event {
116 struct HvLpEvent hp_lp_event;
117 u16 subtype_result_code;
118 u16 reserved1;
119 u32 reserved2;
120 union {
121 struct alloc_data alloc;
122 struct ce_msg_data ce_msg;
123 struct vsp_cmd_data vsp_cmd;
124 } data;
125};
126
127#define subtype_data(a, b, c, d) \
128 (((a) << 24) + ((b) << 16) + ((c) << 8) + (d))
129
130/*
131 * All outgoing event traffic is kept on a FIFO queue. The first
132 * pointer points to the one that is outstanding, and all new
133 * requests get stuck on the end. Also, we keep a certain number of
134 * preallocated pending events so that we can operate very early in
135 * the boot up sequence (before kmalloc is ready).
136 */
137struct pending_event {
138 struct pending_event *next;
139 struct io_mf_lp_event event;
140 MFCompleteHandler hdlr;
141 char dma_data[72];
142 unsigned dma_data_length;
143 unsigned remote_address;
144};
145static spinlock_t pending_event_spinlock;
146static struct pending_event *pending_event_head;
147static struct pending_event *pending_event_tail;
148static struct pending_event *pending_event_avail;
149#define PENDING_EVENT_PREALLOC_LEN 16
150static struct pending_event pending_event_prealloc[PENDING_EVENT_PREALLOC_LEN];
151
152/*
153 * Put a pending event onto the available queue, so it can get reused.
154 * Attention! You must have the pending_event_spinlock before calling!
155 */
156static void free_pending_event(struct pending_event *ev)
157{
158 if (ev != NULL) {
159 ev->next = pending_event_avail;
160 pending_event_avail = ev;
161 }
162}
163
164/*
165 * Enqueue the outbound event onto the stack. If the queue was
166 * empty to begin with, we must also issue it via the Hypervisor
167 * interface. There is a section of code below that will touch
168 * the first stack pointer without the protection of the pending_event_spinlock.
169 * This is OK, because we know that nobody else will be modifying
170 * the first pointer when we do this.
171 */
172static int signal_event(struct pending_event *ev)
173{
174 int rc = 0;
175 unsigned long flags;
176 int go = 1;
177 struct pending_event *ev1;
178 HvLpEvent_Rc hv_rc;
179
180 /* enqueue the event */
181 if (ev != NULL) {
182 ev->next = NULL;
183 spin_lock_irqsave(&pending_event_spinlock, flags);
184 if (pending_event_head == NULL)
185 pending_event_head = ev;
186 else {
187 go = 0;
188 pending_event_tail->next = ev;
189 }
190 pending_event_tail = ev;
191 spin_unlock_irqrestore(&pending_event_spinlock, flags);
192 }
193
194 /* send the event */
195 while (go) {
196 go = 0;
197
198 /* any DMA data to send beforehand? */
199 if (pending_event_head->dma_data_length > 0)
200 HvCallEvent_dmaToSp(pending_event_head->dma_data,
201 pending_event_head->remote_address,
202 pending_event_head->dma_data_length,
203 HvLpDma_Direction_LocalToRemote);
204
205 hv_rc = HvCallEvent_signalLpEvent(
206 &pending_event_head->event.hp_lp_event);
207 if (hv_rc != HvLpEvent_Rc_Good) {
208 printk(KERN_ERR "mf.c: HvCallEvent_signalLpEvent() "
209 "failed with %d\n", (int)hv_rc);
210
211 spin_lock_irqsave(&pending_event_spinlock, flags);
212 ev1 = pending_event_head;
213 pending_event_head = pending_event_head->next;
214 if (pending_event_head != NULL)
215 go = 1;
216 spin_unlock_irqrestore(&pending_event_spinlock, flags);
217
218 if (ev1 == ev)
219 rc = -EIO;
220 else if (ev1->hdlr != NULL)
221 (*ev1->hdlr)((void *)ev1->event.hp_lp_event.xCorrelationToken, -EIO);
222
223 spin_lock_irqsave(&pending_event_spinlock, flags);
224 free_pending_event(ev1);
225 spin_unlock_irqrestore(&pending_event_spinlock, flags);
226 }
227 }
228
229 return rc;
230}
231
232/*
233 * Allocate a new pending_event structure, and initialize it.
234 */
235static struct pending_event *new_pending_event(void)
236{
237 struct pending_event *ev = NULL;
238 HvLpIndex primary_lp = HvLpConfig_getPrimaryLpIndex();
239 unsigned long flags;
240 struct HvLpEvent *hev;
241
242 spin_lock_irqsave(&pending_event_spinlock, flags);
243 if (pending_event_avail != NULL) {
244 ev = pending_event_avail;
245 pending_event_avail = pending_event_avail->next;
246 }
247 spin_unlock_irqrestore(&pending_event_spinlock, flags);
248 if (ev == NULL) {
249 ev = kmalloc(sizeof(struct pending_event), GFP_ATOMIC);
250 if (ev == NULL) {
251 printk(KERN_ERR "mf.c: unable to kmalloc %ld bytes\n",
252 sizeof(struct pending_event));
253 return NULL;
254 }
255 }
256 memset(ev, 0, sizeof(struct pending_event));
257 hev = &ev->event.hp_lp_event;
258 hev->flags = HV_LP_EVENT_VALID | HV_LP_EVENT_DO_ACK | HV_LP_EVENT_INT;
259 hev->xType = HvLpEvent_Type_MachineFac;
260 hev->xSourceLp = HvLpConfig_getLpIndex();
261 hev->xTargetLp = primary_lp;
262 hev->xSizeMinus1 = sizeof(ev->event) - 1;
263 hev->xRc = HvLpEvent_Rc_Good;
264 hev->xSourceInstanceId = HvCallEvent_getSourceLpInstanceId(primary_lp,
265 HvLpEvent_Type_MachineFac);
266 hev->xTargetInstanceId = HvCallEvent_getTargetLpInstanceId(primary_lp,
267 HvLpEvent_Type_MachineFac);
268
269 return ev;
270}
271
272static int __maybe_unused
273signal_vsp_instruction(struct vsp_cmd_data *vsp_cmd)
274{
275 struct pending_event *ev = new_pending_event();
276 int rc;
277 struct vsp_rsp_data response;
278
279 if (ev == NULL)
280 return -ENOMEM;
281
282 init_completion(&response.com);
283 response.response = vsp_cmd;
284 ev->event.hp_lp_event.xSubtype = 6;
285 ev->event.hp_lp_event.x.xSubtypeData =
286 subtype_data('M', 'F', 'V', 'I');
287 ev->event.data.vsp_cmd.token = (u64)&response;
288 ev->event.data.vsp_cmd.cmd = vsp_cmd->cmd;
289 ev->event.data.vsp_cmd.lp_index = HvLpConfig_getLpIndex();
290 ev->event.data.vsp_cmd.result_code = 0xFF;
291 ev->event.data.vsp_cmd.reserved = 0;
292 memcpy(&(ev->event.data.vsp_cmd.sub_data),
293 &(vsp_cmd->sub_data), sizeof(vsp_cmd->sub_data));
294 mb();
295
296 rc = signal_event(ev);
297 if (rc == 0)
298 wait_for_completion(&response.com);
299 return rc;
300}
301
302
303/*
304 * Send a 12-byte CE message to the primary partition VSP object
305 */
306static int signal_ce_msg(char *ce_msg, struct ce_msg_comp_data *completion)
307{
308 struct pending_event *ev = new_pending_event();
309
310 if (ev == NULL)
311 return -ENOMEM;
312
313 ev->event.hp_lp_event.xSubtype = 0;
314 ev->event.hp_lp_event.x.xSubtypeData =
315 subtype_data('M', 'F', 'C', 'E');
316 memcpy(ev->event.data.ce_msg.ce_msg, ce_msg, 12);
317 ev->event.data.ce_msg.completion = completion;
318 return signal_event(ev);
319}
320
321/*
322 * Send a 12-byte CE message (with no data) to the primary partition VSP object
323 */
324static int signal_ce_msg_simple(u8 ce_op, struct ce_msg_comp_data *completion)
325{
326 u8 ce_msg[12];
327
328 memset(ce_msg, 0, sizeof(ce_msg));
329 ce_msg[3] = ce_op;
330 return signal_ce_msg(ce_msg, completion);
331}
332
333/*
334 * Send a 12-byte CE message and DMA data to the primary partition VSP object
335 */
336static int dma_and_signal_ce_msg(char *ce_msg,
337 struct ce_msg_comp_data *completion, void *dma_data,
338 unsigned dma_data_length, unsigned remote_address)
339{
340 struct pending_event *ev = new_pending_event();
341
342 if (ev == NULL)
343 return -ENOMEM;
344
345 ev->event.hp_lp_event.xSubtype = 0;
346 ev->event.hp_lp_event.x.xSubtypeData =
347 subtype_data('M', 'F', 'C', 'E');
348 memcpy(ev->event.data.ce_msg.ce_msg, ce_msg, 12);
349 ev->event.data.ce_msg.completion = completion;
350 memcpy(ev->dma_data, dma_data, dma_data_length);
351 ev->dma_data_length = dma_data_length;
352 ev->remote_address = remote_address;
353 return signal_event(ev);
354}
355
356/*
357 * Initiate a nice (hopefully) shutdown of Linux. We simply are
358 * going to try and send the init process a SIGINT signal. If
359 * this fails (why?), we'll simply force it off in a not-so-nice
360 * manner.
361 */
362static int shutdown(void)
363{
364 int rc = kill_cad_pid(SIGINT, 1);
365
366 if (rc) {
367 printk(KERN_ALERT "mf.c: SIGINT to init failed (%d), "
368 "hard shutdown commencing\n", rc);
369 mf_power_off();
370 } else
371 printk(KERN_INFO "mf.c: init has been successfully notified "
372 "to proceed with shutdown\n");
373 return rc;
374}
375
376/*
377 * The primary partition VSP object is sending us a new
378 * event flow. Handle it...
379 */
380static void handle_int(struct io_mf_lp_event *event)
381{
382 struct ce_msg_data *ce_msg_data;
383 struct ce_msg_data *pce_msg_data;
384 unsigned long flags;
385 struct pending_event *pev;
386
387 /* ack the interrupt */
388 event->hp_lp_event.xRc = HvLpEvent_Rc_Good;
389 HvCallEvent_ackLpEvent(&event->hp_lp_event);
390
391 /* process interrupt */
392 switch (event->hp_lp_event.xSubtype) {
393 case 0: /* CE message */
394 ce_msg_data = &event->data.ce_msg;
395 switch (ce_msg_data->ce_msg[3]) {
396 case 0x5B: /* power control notification */
397 if ((ce_msg_data->ce_msg[5] & 0x20) != 0) {
398 printk(KERN_INFO "mf.c: Commencing partition shutdown\n");
399 if (shutdown() == 0)
400 signal_ce_msg_simple(0xDB, NULL);
401 }
402 break;
403 case 0xC0: /* get time */
404 spin_lock_irqsave(&pending_event_spinlock, flags);
405 pev = pending_event_head;
406 if (pev != NULL)
407 pending_event_head = pending_event_head->next;
408 spin_unlock_irqrestore(&pending_event_spinlock, flags);
409 if (pev == NULL)
410 break;
411 pce_msg_data = &pev->event.data.ce_msg;
412 if (pce_msg_data->ce_msg[3] != 0x40)
413 break;
414 if (pce_msg_data->completion != NULL) {
415 ce_msg_comp_hdlr handler =
416 pce_msg_data->completion->handler;
417 void *token = pce_msg_data->completion->token;
418
419 if (handler != NULL)
420 (*handler)(token, ce_msg_data);
421 }
422 spin_lock_irqsave(&pending_event_spinlock, flags);
423 free_pending_event(pev);
424 spin_unlock_irqrestore(&pending_event_spinlock, flags);
425 /* send next waiting event */
426 if (pending_event_head != NULL)
427 signal_event(NULL);
428 break;
429 }
430 break;
431 case 1: /* IT sys shutdown */
432 printk(KERN_INFO "mf.c: Commencing system shutdown\n");
433 shutdown();
434 break;
435 }
436}
437
438/*
439 * The primary partition VSP object is acknowledging the receipt
440 * of a flow we sent to them. If there are other flows queued
441 * up, we must send another one now...
442 */
443static void handle_ack(struct io_mf_lp_event *event)
444{
445 unsigned long flags;
446 struct pending_event *two = NULL;
447 unsigned long free_it = 0;
448 struct ce_msg_data *ce_msg_data;
449 struct ce_msg_data *pce_msg_data;
450 struct vsp_rsp_data *rsp;
451
452 /* handle current event */
453 if (pending_event_head == NULL) {
454 printk(KERN_ERR "mf.c: stack empty for receiving ack\n");
455 return;
456 }
457
458 switch (event->hp_lp_event.xSubtype) {
459 case 0: /* CE msg */
460 ce_msg_data = &event->data.ce_msg;
461 if (ce_msg_data->ce_msg[3] != 0x40) {
462 free_it = 1;
463 break;
464 }
465 if (ce_msg_data->ce_msg[2] == 0)
466 break;
467 free_it = 1;
468 pce_msg_data = &pending_event_head->event.data.ce_msg;
469 if (pce_msg_data->completion != NULL) {
470 ce_msg_comp_hdlr handler =
471 pce_msg_data->completion->handler;
472 void *token = pce_msg_data->completion->token;
473
474 if (handler != NULL)
475 (*handler)(token, ce_msg_data);
476 }
477 break;
478 case 4: /* allocate */
479 case 5: /* deallocate */
480 if (pending_event_head->hdlr != NULL)
481 (*pending_event_head->hdlr)((void *)event->hp_lp_event.xCorrelationToken, event->data.alloc.count);
482 free_it = 1;
483 break;
484 case 6:
485 free_it = 1;
486 rsp = (struct vsp_rsp_data *)event->data.vsp_cmd.token;
487 if (rsp == NULL) {
488 printk(KERN_ERR "mf.c: no rsp\n");
489 break;
490 }
491 if (rsp->response != NULL)
492 memcpy(rsp->response, &event->data.vsp_cmd,
493 sizeof(event->data.vsp_cmd));
494 complete(&rsp->com);
495 break;
496 }
497
498 /* remove from queue */
499 spin_lock_irqsave(&pending_event_spinlock, flags);
500 if ((pending_event_head != NULL) && (free_it == 1)) {
501 struct pending_event *oldHead = pending_event_head;
502
503 pending_event_head = pending_event_head->next;
504 two = pending_event_head;
505 free_pending_event(oldHead);
506 }
507 spin_unlock_irqrestore(&pending_event_spinlock, flags);
508
509 /* send next waiting event */
510 if (two != NULL)
511 signal_event(NULL);
512}
513
514/*
515 * This is the generic event handler we are registering with
516 * the Hypervisor. Ensure the flows are for us, and then
517 * parse it enough to know if it is an interrupt or an
518 * acknowledge.
519 */
520static void hv_handler(struct HvLpEvent *event)
521{
522 if ((event != NULL) && (event->xType == HvLpEvent_Type_MachineFac)) {
523 if (hvlpevent_is_ack(event))
524 handle_ack((struct io_mf_lp_event *)event);
525 else
526 handle_int((struct io_mf_lp_event *)event);
527 } else
528 printk(KERN_ERR "mf.c: alien event received\n");
529}
530
531/*
532 * Global kernel interface to allocate and seed events into the
533 * Hypervisor.
534 */
535void mf_allocate_lp_events(HvLpIndex target_lp, HvLpEvent_Type type,
536 unsigned size, unsigned count, MFCompleteHandler hdlr,
537 void *user_token)
538{
539 struct pending_event *ev = new_pending_event();
540 int rc;
541
542 if (ev == NULL) {
543 rc = -ENOMEM;
544 } else {
545 ev->event.hp_lp_event.xSubtype = 4;
546 ev->event.hp_lp_event.xCorrelationToken = (u64)user_token;
547 ev->event.hp_lp_event.x.xSubtypeData =
548 subtype_data('M', 'F', 'M', 'A');
549 ev->event.data.alloc.target_lp = target_lp;
550 ev->event.data.alloc.type = type;
551 ev->event.data.alloc.size = size;
552 ev->event.data.alloc.count = count;
553 ev->hdlr = hdlr;
554 rc = signal_event(ev);
555 }
556 if ((rc != 0) && (hdlr != NULL))
557 (*hdlr)(user_token, rc);
558}
559EXPORT_SYMBOL(mf_allocate_lp_events);
560
561/*
562 * Global kernel interface to unseed and deallocate events already in
563 * Hypervisor.
564 */
565void mf_deallocate_lp_events(HvLpIndex target_lp, HvLpEvent_Type type,
566 unsigned count, MFCompleteHandler hdlr, void *user_token)
567{
568 struct pending_event *ev = new_pending_event();
569 int rc;
570
571 if (ev == NULL)
572 rc = -ENOMEM;
573 else {
574 ev->event.hp_lp_event.xSubtype = 5;
575 ev->event.hp_lp_event.xCorrelationToken = (u64)user_token;
576 ev->event.hp_lp_event.x.xSubtypeData =
577 subtype_data('M', 'F', 'M', 'D');
578 ev->event.data.alloc.target_lp = target_lp;
579 ev->event.data.alloc.type = type;
580 ev->event.data.alloc.count = count;
581 ev->hdlr = hdlr;
582 rc = signal_event(ev);
583 }
584 if ((rc != 0) && (hdlr != NULL))
585 (*hdlr)(user_token, rc);
586}
587EXPORT_SYMBOL(mf_deallocate_lp_events);
588
589/*
590 * Global kernel interface to tell the VSP object in the primary
591 * partition to power this partition off.
592 */
593void mf_power_off(void)
594{
595 printk(KERN_INFO "mf.c: Down it goes...\n");
596 signal_ce_msg_simple(0x4d, NULL);
597 for (;;)
598 ;
599}
600
601/*
602 * Global kernel interface to tell the VSP object in the primary
603 * partition to reboot this partition.
604 */
605void mf_reboot(char *cmd)
606{
607 printk(KERN_INFO "mf.c: Preparing to bounce...\n");
608 signal_ce_msg_simple(0x4e, NULL);
609 for (;;)
610 ;
611}
612
613/*
614 * Display a single word SRC onto the VSP control panel.
615 */
616void mf_display_src(u32 word)
617{
618 u8 ce[12];
619
620 memset(ce, 0, sizeof(ce));
621 ce[3] = 0x4a;
622 ce[7] = 0x01;
623 ce[8] = word >> 24;
624 ce[9] = word >> 16;
625 ce[10] = word >> 8;
626 ce[11] = word;
627 signal_ce_msg(ce, NULL);
628}
629
630/*
631 * Display a single word SRC of the form "PROGXXXX" on the VSP control panel.
632 */
633static __init void mf_display_progress_src(u16 value)
634{
635 u8 ce[12];
636 u8 src[72];
637
638 memcpy(ce, "\x00\x00\x04\x4A\x00\x00\x00\x48\x00\x00\x00\x00", 12);
639 memcpy(src, "\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00"
640 "\x00\x00\x00\x00\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\x00PROGxxxx ",
643 72);
644 src[6] = value >> 8;
645 src[7] = value & 255;
646 src[44] = "0123456789ABCDEF"[(value >> 12) & 15];
647 src[45] = "0123456789ABCDEF"[(value >> 8) & 15];
648 src[46] = "0123456789ABCDEF"[(value >> 4) & 15];
649 src[47] = "0123456789ABCDEF"[value & 15];
650 dma_and_signal_ce_msg(ce, NULL, src, sizeof(src), 9 * 64 * 1024);
651}
652
653/*
654 * Clear the VSP control panel. Used to "erase" an SRC that was
655 * previously displayed.
656 */
657static void mf_clear_src(void)
658{
659 signal_ce_msg_simple(0x4b, NULL);
660}
661
662void __init mf_display_progress(u16 value)
663{
664 if (!mf_initialized)
665 return;
666
667 if (0xFFFF == value)
668 mf_clear_src();
669 else
670 mf_display_progress_src(value);
671}
672
673/*
674 * Initialization code here.
675 */
676void __init mf_init(void)
677{
678 int i;
679
680 spin_lock_init(&pending_event_spinlock);
681
682 for (i = 0; i < PENDING_EVENT_PREALLOC_LEN; i++)
683 free_pending_event(&pending_event_prealloc[i]);
684
685 HvLpEvent_registerHandler(HvLpEvent_Type_MachineFac, &hv_handler);
686
687 /* virtual continue ack */
688 signal_ce_msg_simple(0x57, NULL);
689
690 mf_initialized = 1;
691 mb();
692
693 printk(KERN_NOTICE "mf.c: iSeries Linux LPAR Machine Facilities "
694 "initialized\n");
695}
696
697struct rtc_time_data {
698 struct completion com;
699 struct ce_msg_data ce_msg;
700 int rc;
701};
702
703static void get_rtc_time_complete(void *token, struct ce_msg_data *ce_msg)
704{
705 struct rtc_time_data *rtc = token;
706
707 memcpy(&rtc->ce_msg, ce_msg, sizeof(rtc->ce_msg));
708 rtc->rc = 0;
709 complete(&rtc->com);
710}
711
712static int mf_set_rtc(struct rtc_time *tm)
713{
714 char ce_time[12];
715 u8 day, mon, hour, min, sec, y1, y2;
716 unsigned year;
717
718 year = 1900 + tm->tm_year;
719 y1 = year / 100;
720 y2 = year % 100;
721
722 sec = tm->tm_sec;
723 min = tm->tm_min;
724 hour = tm->tm_hour;
725 day = tm->tm_mday;
726 mon = tm->tm_mon + 1;
727
728 sec = bin2bcd(sec);
729 min = bin2bcd(min);
730 hour = bin2bcd(hour);
731 mon = bin2bcd(mon);
732 day = bin2bcd(day);
733 y1 = bin2bcd(y1);
734 y2 = bin2bcd(y2);
735
736 memset(ce_time, 0, sizeof(ce_time));
737 ce_time[3] = 0x41;
738 ce_time[4] = y1;
739 ce_time[5] = y2;
740 ce_time[6] = sec;
741 ce_time[7] = min;
742 ce_time[8] = hour;
743 ce_time[10] = day;
744 ce_time[11] = mon;
745
746 return signal_ce_msg(ce_time, NULL);
747}
748
749static int rtc_set_tm(int rc, u8 *ce_msg, struct rtc_time *tm)
750{
751 tm->tm_wday = 0;
752 tm->tm_yday = 0;
753 tm->tm_isdst = 0;
754 if (rc) {
755 tm->tm_sec = 0;
756 tm->tm_min = 0;
757 tm->tm_hour = 0;
758 tm->tm_mday = 15;
759 tm->tm_mon = 5;
760 tm->tm_year = 52;
761 return rc;
762 }
763
764 if ((ce_msg[2] == 0xa9) ||
765 (ce_msg[2] == 0xaf)) {
766 /* TOD clock is not set */
767 tm->tm_sec = 1;
768 tm->tm_min = 1;
769 tm->tm_hour = 1;
770 tm->tm_mday = 10;
771 tm->tm_mon = 8;
772 tm->tm_year = 71;
773 mf_set_rtc(tm);
774 }
775 {
776 u8 year = ce_msg[5];
777 u8 sec = ce_msg[6];
778 u8 min = ce_msg[7];
779 u8 hour = ce_msg[8];
780 u8 day = ce_msg[10];
781 u8 mon = ce_msg[11];
782
783 sec = bcd2bin(sec);
784 min = bcd2bin(min);
785 hour = bcd2bin(hour);
786 day = bcd2bin(day);
787 mon = bcd2bin(mon);
788 year = bcd2bin(year);
789
790 if (year <= 69)
791 year += 100;
792
793 tm->tm_sec = sec;
794 tm->tm_min = min;
795 tm->tm_hour = hour;
796 tm->tm_mday = day;
797 tm->tm_mon = mon;
798 tm->tm_year = year;
799 }
800
801 return 0;
802}
803
804static int mf_get_rtc(struct rtc_time *tm)
805{
806 struct ce_msg_comp_data ce_complete;
807 struct rtc_time_data rtc_data;
808 int rc;
809
810 memset(&ce_complete, 0, sizeof(ce_complete));
811 memset(&rtc_data, 0, sizeof(rtc_data));
812 init_completion(&rtc_data.com);
813 ce_complete.handler = &get_rtc_time_complete;
814 ce_complete.token = &rtc_data;
815 rc = signal_ce_msg_simple(0x40, &ce_complete);
816 if (rc)
817 return rc;
818 wait_for_completion(&rtc_data.com);
819 return rtc_set_tm(rtc_data.rc, rtc_data.ce_msg.ce_msg, tm);
820}
821
822struct boot_rtc_time_data {
823 int busy;
824 struct ce_msg_data ce_msg;
825 int rc;
826};
827
828static void get_boot_rtc_time_complete(void *token, struct ce_msg_data *ce_msg)
829{
830 struct boot_rtc_time_data *rtc = token;
831
832 memcpy(&rtc->ce_msg, ce_msg, sizeof(rtc->ce_msg));
833 rtc->rc = 0;
834 rtc->busy = 0;
835}
836
837static int mf_get_boot_rtc(struct rtc_time *tm)
838{
839 struct ce_msg_comp_data ce_complete;
840 struct boot_rtc_time_data rtc_data;
841 int rc;
842
843 memset(&ce_complete, 0, sizeof(ce_complete));
844 memset(&rtc_data, 0, sizeof(rtc_data));
845 rtc_data.busy = 1;
846 ce_complete.handler = &get_boot_rtc_time_complete;
847 ce_complete.token = &rtc_data;
848 rc = signal_ce_msg_simple(0x40, &ce_complete);
849 if (rc)
850 return rc;
851 /* We need to poll here as we are not yet taking interrupts */
852 while (rtc_data.busy) {
853 if (hvlpevent_is_pending())
854 process_hvlpevents();
855 }
856 return rtc_set_tm(rtc_data.rc, rtc_data.ce_msg.ce_msg, tm);
857}
858
859#ifdef CONFIG_PROC_FS
860static int mf_cmdline_proc_show(struct seq_file *m, void *v)
861{
862 char *page, *p;
863 struct vsp_cmd_data vsp_cmd;
864 int rc;
865 dma_addr_t dma_addr;
866
867 /* The HV appears to return no more than 256 bytes of command line */
868 page = kmalloc(256, GFP_KERNEL);
869 if (!page)
870 return -ENOMEM;
871
872 dma_addr = iseries_hv_map(page, 256, DMA_FROM_DEVICE);
873 if (dma_addr == DMA_ERROR_CODE) {
874 kfree(page);
875 return -ENOMEM;
876 }
877 memset(page, 0, 256);
878 memset(&vsp_cmd, 0, sizeof(vsp_cmd));
879 vsp_cmd.cmd = 33;
880 vsp_cmd.sub_data.kern.token = dma_addr;
881 vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex;
882 vsp_cmd.sub_data.kern.side = (u64)m->private;
883 vsp_cmd.sub_data.kern.length = 256;
884 mb();
885 rc = signal_vsp_instruction(&vsp_cmd);
886 iseries_hv_unmap(dma_addr, 256, DMA_FROM_DEVICE);
887 if (rc) {
888 kfree(page);
889 return rc;
890 }
891 if (vsp_cmd.result_code != 0) {
892 kfree(page);
893 return -ENOMEM;
894 }
895 p = page;
896 while (p - page < 256) {
897 if (*p == '\0' || *p == '\n') {
898 *p = '\n';
899 break;
900 }
901 p++;
902
903 }
904 seq_write(m, page, p - page);
905 kfree(page);
906 return 0;
907}
908
909static int mf_cmdline_proc_open(struct inode *inode, struct file *file)
910{
911 return single_open(file, mf_cmdline_proc_show, PDE(inode)->data);
912}
913
914#if 0
915static int mf_getVmlinuxChunk(char *buffer, int *size, int offset, u64 side)
916{
917 struct vsp_cmd_data vsp_cmd;
918 int rc;
919 int len = *size;
920 dma_addr_t dma_addr;
921
922 dma_addr = iseries_hv_map(buffer, len, DMA_FROM_DEVICE);
923 memset(buffer, 0, len);
924 memset(&vsp_cmd, 0, sizeof(vsp_cmd));
925 vsp_cmd.cmd = 32;
926 vsp_cmd.sub_data.kern.token = dma_addr;
927 vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex;
928 vsp_cmd.sub_data.kern.side = side;
929 vsp_cmd.sub_data.kern.offset = offset;
930 vsp_cmd.sub_data.kern.length = len;
931 mb();
932 rc = signal_vsp_instruction(&vsp_cmd);
933 if (rc == 0) {
934 if (vsp_cmd.result_code == 0)
935 *size = vsp_cmd.sub_data.length_out;
936 else
937 rc = -ENOMEM;
938 }
939
940 iseries_hv_unmap(dma_addr, len, DMA_FROM_DEVICE);
941
942 return rc;
943}
944
945static int proc_mf_dump_vmlinux(char *page, char **start, off_t off,
946 int count, int *eof, void *data)
947{
948 int sizeToGet = count;
949
950 if (!capable(CAP_SYS_ADMIN))
951 return -EACCES;
952
953 if (mf_getVmlinuxChunk(page, &sizeToGet, off, (u64)data) == 0) {
954 if (sizeToGet != 0) {
955 *start = page + off;
956 return sizeToGet;
957 }
958 *eof = 1;
959 return 0;
960 }
961 *eof = 1;
962 return 0;
963}
964#endif
965
966static int mf_side_proc_show(struct seq_file *m, void *v)
967{
968 char mf_current_side = ' ';
969 struct vsp_cmd_data vsp_cmd;
970
971 memset(&vsp_cmd, 0, sizeof(vsp_cmd));
972 vsp_cmd.cmd = 2;
973 vsp_cmd.sub_data.ipl_type = 0;
974 mb();
975
976 if (signal_vsp_instruction(&vsp_cmd) == 0) {
977 if (vsp_cmd.result_code == 0) {
978 switch (vsp_cmd.sub_data.ipl_type) {
979 case 0: mf_current_side = 'A';
980 break;
981 case 1: mf_current_side = 'B';
982 break;
983 case 2: mf_current_side = 'C';
984 break;
985 default: mf_current_side = 'D';
986 break;
987 }
988 }
989 }
990
991 seq_printf(m, "%c\n", mf_current_side);
992 return 0;
993}
994
995static int mf_side_proc_open(struct inode *inode, struct file *file)
996{
997 return single_open(file, mf_side_proc_show, NULL);
998}
999
1000static ssize_t mf_side_proc_write(struct file *file, const char __user *buffer,
1001 size_t count, loff_t *pos)
1002{
1003 char side;
1004 u64 newSide;
1005 struct vsp_cmd_data vsp_cmd;
1006
1007 if (!capable(CAP_SYS_ADMIN))
1008 return -EACCES;
1009
1010 if (count == 0)
1011 return 0;
1012
1013 if (get_user(side, buffer))
1014 return -EFAULT;
1015
1016 switch (side) {
1017 case 'A': newSide = 0;
1018 break;
1019 case 'B': newSide = 1;
1020 break;
1021 case 'C': newSide = 2;
1022 break;
1023 case 'D': newSide = 3;
1024 break;
1025 default:
1026 printk(KERN_ERR "mf_proc.c: proc_mf_change_side: invalid side\n");
1027 return -EINVAL;
1028 }
1029
1030 memset(&vsp_cmd, 0, sizeof(vsp_cmd));
1031 vsp_cmd.sub_data.ipl_type = newSide;
1032 vsp_cmd.cmd = 10;
1033
1034 (void)signal_vsp_instruction(&vsp_cmd);
1035
1036 return count;
1037}
1038
1039static const struct file_operations mf_side_proc_fops = {
1040 .owner = THIS_MODULE,
1041 .open = mf_side_proc_open,
1042 .read = seq_read,
1043 .llseek = seq_lseek,
1044 .release = single_release,
1045 .write = mf_side_proc_write,
1046};
1047
1048static int mf_src_proc_show(struct seq_file *m, void *v)
1049{
1050 return 0;
1051}
1052
1053static int mf_src_proc_open(struct inode *inode, struct file *file)
1054{
1055 return single_open(file, mf_src_proc_show, NULL);
1056}
1057
1058static ssize_t mf_src_proc_write(struct file *file, const char __user *buffer,
1059 size_t count, loff_t *pos)
1060{
1061 char stkbuf[10];
1062
1063 if (!capable(CAP_SYS_ADMIN))
1064 return -EACCES;
1065
1066 if ((count < 4) && (count != 1)) {
1067 printk(KERN_ERR "mf_proc: invalid src\n");
1068 return -EINVAL;
1069 }
1070
1071 if (count > (sizeof(stkbuf) - 1))
1072 count = sizeof(stkbuf) - 1;
1073 if (copy_from_user(stkbuf, buffer, count))
1074 return -EFAULT;
1075
1076 if ((count == 1) && (*stkbuf == '\0'))
1077 mf_clear_src();
1078 else
1079 mf_display_src(*(u32 *)stkbuf);
1080
1081 return count;
1082}
1083
1084static const struct file_operations mf_src_proc_fops = {
1085 .owner = THIS_MODULE,
1086 .open = mf_src_proc_open,
1087 .read = seq_read,
1088 .llseek = seq_lseek,
1089 .release = single_release,
1090 .write = mf_src_proc_write,
1091};
1092
1093static ssize_t mf_cmdline_proc_write(struct file *file, const char __user *buffer,
1094 size_t count, loff_t *pos)
1095{
1096 void *data = PDE(file->f_path.dentry->d_inode)->data;
1097 struct vsp_cmd_data vsp_cmd;
1098 dma_addr_t dma_addr;
1099 char *page;
1100 int ret = -EACCES;
1101
1102 if (!capable(CAP_SYS_ADMIN))
1103 goto out;
1104
1105 dma_addr = 0;
1106 page = iseries_hv_alloc(count, &dma_addr, GFP_ATOMIC);
1107 ret = -ENOMEM;
1108 if (page == NULL)
1109 goto out;
1110
1111 ret = -EFAULT;
1112 if (copy_from_user(page, buffer, count))
1113 goto out_free;
1114
1115 memset(&vsp_cmd, 0, sizeof(vsp_cmd));
1116 vsp_cmd.cmd = 31;
1117 vsp_cmd.sub_data.kern.token = dma_addr;
1118 vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex;
1119 vsp_cmd.sub_data.kern.side = (u64)data;
1120 vsp_cmd.sub_data.kern.length = count;
1121 mb();
1122 (void)signal_vsp_instruction(&vsp_cmd);
1123 ret = count;
1124
1125out_free:
1126 iseries_hv_free(count, page, dma_addr);
1127out:
1128 return ret;
1129}
1130
1131static const struct file_operations mf_cmdline_proc_fops = {
1132 .owner = THIS_MODULE,
1133 .open = mf_cmdline_proc_open,
1134 .read = seq_read,
1135 .llseek = seq_lseek,
1136 .release = single_release,
1137 .write = mf_cmdline_proc_write,
1138};
1139
1140static ssize_t proc_mf_change_vmlinux(struct file *file,
1141 const char __user *buf,
1142 size_t count, loff_t *ppos)
1143{
1144 struct proc_dir_entry *dp = PDE(file->f_path.dentry->d_inode);
1145 ssize_t rc;
1146 dma_addr_t dma_addr;
1147 char *page;
1148 struct vsp_cmd_data vsp_cmd;
1149
1150 rc = -EACCES;
1151 if (!capable(CAP_SYS_ADMIN))
1152 goto out;
1153
1154 dma_addr = 0;
1155 page = iseries_hv_alloc(count, &dma_addr, GFP_ATOMIC);
1156 rc = -ENOMEM;
1157 if (page == NULL) {
1158 printk(KERN_ERR "mf.c: couldn't allocate memory to set vmlinux chunk\n");
1159 goto out;
1160 }
1161 rc = -EFAULT;
1162 if (copy_from_user(page, buf, count))
1163 goto out_free;
1164
1165 memset(&vsp_cmd, 0, sizeof(vsp_cmd));
1166 vsp_cmd.cmd = 30;
1167 vsp_cmd.sub_data.kern.token = dma_addr;
1168 vsp_cmd.sub_data.kern.address_type = HvLpDma_AddressType_TceIndex;
1169 vsp_cmd.sub_data.kern.side = (u64)dp->data;
1170 vsp_cmd.sub_data.kern.offset = *ppos;
1171 vsp_cmd.sub_data.kern.length = count;
1172 mb();
1173 rc = signal_vsp_instruction(&vsp_cmd);
1174 if (rc)
1175 goto out_free;
1176 rc = -ENOMEM;
1177 if (vsp_cmd.result_code != 0)
1178 goto out_free;
1179
1180 *ppos += count;
1181 rc = count;
1182out_free:
1183 iseries_hv_free(count, page, dma_addr);
1184out:
1185 return rc;
1186}
1187
1188static const struct file_operations proc_vmlinux_operations = {
1189 .write = proc_mf_change_vmlinux,
1190 .llseek = default_llseek,
1191};
1192
1193static int __init mf_proc_init(void)
1194{
1195 struct proc_dir_entry *mf_proc_root;
1196 struct proc_dir_entry *ent;
1197 struct proc_dir_entry *mf;
1198 char name[2];
1199 int i;
1200
1201 if (!firmware_has_feature(FW_FEATURE_ISERIES))
1202 return 0;
1203
1204 mf_proc_root = proc_mkdir("iSeries/mf", NULL);
1205 if (!mf_proc_root)
1206 return 1;
1207
1208 name[1] = '\0';
1209 for (i = 0; i < 4; i++) {
1210 name[0] = 'A' + i;
1211 mf = proc_mkdir(name, mf_proc_root);
1212 if (!mf)
1213 return 1;
1214
1215 ent = proc_create_data("cmdline", S_IRUSR|S_IWUSR, mf,
1216 &mf_cmdline_proc_fops, (void *)(long)i);
1217 if (!ent)
1218 return 1;
1219
1220 if (i == 3) /* no vmlinux entry for 'D' */
1221 continue;
1222
1223 ent = proc_create_data("vmlinux", S_IFREG|S_IWUSR, mf,
1224 &proc_vmlinux_operations,
1225 (void *)(long)i);
1226 if (!ent)
1227 return 1;
1228 }
1229
1230 ent = proc_create("side", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root,
1231 &mf_side_proc_fops);
1232 if (!ent)
1233 return 1;
1234
1235 ent = proc_create("src", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root,
1236 &mf_src_proc_fops);
1237 if (!ent)
1238 return 1;
1239
1240 return 0;
1241}
1242
1243__initcall(mf_proc_init);
1244
1245#endif /* CONFIG_PROC_FS */
1246
1247/*
1248 * Get the RTC from the virtual service processor
1249 * This requires flowing LpEvents to the primary partition
1250 */
1251void iSeries_get_rtc_time(struct rtc_time *rtc_tm)
1252{
1253 mf_get_rtc(rtc_tm);
1254 rtc_tm->tm_mon--;
1255}
1256
1257/*
1258 * Set the RTC in the virtual service processor
1259 * This requires flowing LpEvents to the primary partition
1260 */
1261int iSeries_set_rtc_time(struct rtc_time *tm)
1262{
1263 mf_set_rtc(tm);
1264 return 0;
1265}
1266
1267unsigned long iSeries_get_boot_time(void)
1268{
1269 struct rtc_time tm;
1270
1271 mf_get_boot_rtc(&tm);
1272 return mktime(tm.tm_year + 1900, tm.tm_mon, tm.tm_mday,
1273 tm.tm_hour, tm.tm_min, tm.tm_sec);
1274}
diff --git a/arch/powerpc/platforms/iseries/misc.S b/arch/powerpc/platforms/iseries/misc.S
new file mode 100644
index 00000000000..2c6ff0fdac9
--- /dev/null
+++ b/arch/powerpc/platforms/iseries/misc.S
@@ -0,0 +1,26 @@
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
new file mode 100644
index 00000000000..f01708e1286
--- /dev/null
+++ b/arch/powerpc/platforms/iseries/naca.h
@@ -0,0 +1,24 @@
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
15struct 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
22extern 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
new file mode 100644
index 00000000000..ab3962b0d24
--- /dev/null
+++ b/arch/powerpc/platforms/iseries/pci.c
@@ -0,0 +1,920 @@
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/module.h>
33#include <linux/pci.h>
34#include <linux/of.h>
35#include <linux/ratelimit.h>
36
37#include <asm/types.h>
38#include <asm/io.h>
39#include <asm/irq.h>
40#include <asm/prom.h>
41#include <asm/machdep.h>
42#include <asm/pci-bridge.h>
43#include <asm/iommu.h>
44#include <asm/abs_addr.h>
45#include <asm/firmware.h>
46
47#include <asm/iseries/hv_types.h>
48#include <asm/iseries/hv_call_xm.h>
49#include <asm/iseries/mf.h>
50#include <asm/iseries/iommu.h>
51
52#include <asm/ppc-pci.h>
53
54#include "irq.h"
55#include "pci.h"
56#include "call_pci.h"
57
58#define PCI_RETRY_MAX 3
59static int limit_pci_retries = 1; /* Set Retry Error on. */
60
61/*
62 * Table defines
63 * Each Entry size is 4 MB * 1024 Entries = 4GB I/O address space.
64 */
65#define IOMM_TABLE_MAX_ENTRIES 1024
66#define IOMM_TABLE_ENTRY_SIZE 0x0000000000400000UL
67#define BASE_IO_MEMORY 0xE000000000000000UL
68#define END_IO_MEMORY 0xEFFFFFFFFFFFFFFFUL
69
70static unsigned long max_io_memory = BASE_IO_MEMORY;
71static long current_iomm_table_entry;
72
73/*
74 * Lookup Tables.
75 */
76static struct device_node *iomm_table[IOMM_TABLE_MAX_ENTRIES];
77static u64 ds_addr_table[IOMM_TABLE_MAX_ENTRIES];
78
79static DEFINE_SPINLOCK(iomm_table_lock);
80
81/*
82 * Generate a Direct Select Address for the Hypervisor
83 */
84static inline u64 iseries_ds_addr(struct device_node *node)
85{
86 struct pci_dn *pdn = PCI_DN(node);
87 const u32 *sbp = of_get_property(node, "linux,subbus", NULL);
88
89 return ((u64)pdn->busno << 48) + ((u64)(sbp ? *sbp : 0) << 40)
90 + ((u64)0x10 << 32);
91}
92
93/*
94 * Size of Bus VPD data
95 */
96#define BUS_VPDSIZE 1024
97
98/*
99 * Bus Vpd Tags
100 */
101#define VPD_END_OF_AREA 0x79
102#define VPD_ID_STRING 0x82
103#define VPD_VENDOR_AREA 0x84
104
105/*
106 * Mfg Area Tags
107 */
108#define VPD_FRU_FRAME_ID 0x4649 /* "FI" */
109#define VPD_SLOT_MAP_FORMAT 0x4D46 /* "MF" */
110#define VPD_SLOT_MAP 0x534D /* "SM" */
111
112/*
113 * Structures of the areas
114 */
115struct mfg_vpd_area {
116 u16 tag;
117 u8 length;
118 u8 data1;
119 u8 data2;
120};
121#define MFG_ENTRY_SIZE 3
122
123struct slot_map {
124 u8 agent;
125 u8 secondary_agent;
126 u8 phb;
127 char card_location[3];
128 char parms[8];
129 char reserved[2];
130};
131#define SLOT_ENTRY_SIZE 16
132
133/*
134 * Parse the Slot Area
135 */
136static void __init iseries_parse_slot_area(struct slot_map *map, int len,
137 HvAgentId agent, u8 *phb, char card[4])
138{
139 /*
140 * Parse Slot label until we find the one requested
141 */
142 while (len > 0) {
143 if (map->agent == agent) {
144 /*
145 * If Phb wasn't found, grab the entry first one found.
146 */
147 if (*phb == 0xff)
148 *phb = map->phb;
149 /* Found it, extract the data. */
150 if (map->phb == *phb) {
151 memcpy(card, &map->card_location, 3);
152 card[3] = 0;
153 break;
154 }
155 }
156 /* Point to the next Slot */
157 map = (struct slot_map *)((char *)map + SLOT_ENTRY_SIZE);
158 len -= SLOT_ENTRY_SIZE;
159 }
160}
161
162/*
163 * Parse the Mfg Area
164 */
165static void __init iseries_parse_mfg_area(struct mfg_vpd_area *area, int len,
166 HvAgentId agent, u8 *phb, u8 *frame, char card[4])
167{
168 u16 slot_map_fmt = 0;
169
170 /* Parse Mfg Data */
171 while (len > 0) {
172 int mfg_tag_len = area->length;
173 /* Frame ID (FI 4649020310 ) */
174 if (area->tag == VPD_FRU_FRAME_ID)
175 *frame = area->data1;
176 /* Slot Map Format (MF 4D46020004 ) */
177 else if (area->tag == VPD_SLOT_MAP_FORMAT)
178 slot_map_fmt = (area->data1 * 256)
179 + area->data2;
180 /* Slot Map (SM 534D90 */
181 else if (area->tag == VPD_SLOT_MAP) {
182 struct slot_map *slot_map;
183
184 if (slot_map_fmt == 0x1004)
185 slot_map = (struct slot_map *)((char *)area
186 + MFG_ENTRY_SIZE + 1);
187 else
188 slot_map = (struct slot_map *)((char *)area
189 + MFG_ENTRY_SIZE);
190 iseries_parse_slot_area(slot_map, mfg_tag_len,
191 agent, phb, card);
192 }
193 /*
194 * Point to the next Mfg Area
195 * Use defined size, sizeof give wrong answer
196 */
197 area = (struct mfg_vpd_area *)((char *)area + mfg_tag_len
198 + MFG_ENTRY_SIZE);
199 len -= (mfg_tag_len + MFG_ENTRY_SIZE);
200 }
201}
202
203/*
204 * Look for "BUS".. Data is not Null terminated.
205 * PHBID of 0xFF indicates PHB was not found in VPD Data.
206 */
207static u8 __init iseries_parse_phbid(u8 *area, int len)
208{
209 while (len > 0) {
210 if ((*area == 'B') && (*(area + 1) == 'U')
211 && (*(area + 2) == 'S')) {
212 area += 3;
213 while (*area == ' ')
214 area++;
215 return *area & 0x0F;
216 }
217 area++;
218 len--;
219 }
220 return 0xff;
221}
222
223/*
224 * Parse out the VPD Areas
225 */
226static void __init iseries_parse_vpd(u8 *data, int data_len,
227 HvAgentId agent, u8 *frame, char card[4])
228{
229 u8 phb = 0xff;
230
231 while (data_len > 0) {
232 int len;
233 u8 tag = *data;
234
235 if (tag == VPD_END_OF_AREA)
236 break;
237 len = *(data + 1) + (*(data + 2) * 256);
238 data += 3;
239 data_len -= 3;
240 if (tag == VPD_ID_STRING)
241 phb = iseries_parse_phbid(data, len);
242 else if (tag == VPD_VENDOR_AREA)
243 iseries_parse_mfg_area((struct mfg_vpd_area *)data, len,
244 agent, &phb, frame, card);
245 /* Point to next Area. */
246 data += len;
247 data_len -= len;
248 }
249}
250
251static int __init iseries_get_location_code(u16 bus, HvAgentId agent,
252 u8 *frame, char card[4])
253{
254 int status = 0;
255 int bus_vpd_len = 0;
256 u8 *bus_vpd = kmalloc(BUS_VPDSIZE, GFP_KERNEL);
257
258 if (bus_vpd == NULL) {
259 printk("PCI: Bus VPD Buffer allocation failure.\n");
260 return 0;
261 }
262 bus_vpd_len = HvCallPci_getBusVpd(bus, iseries_hv_addr(bus_vpd),
263 BUS_VPDSIZE);
264 if (bus_vpd_len == 0) {
265 printk("PCI: Bus VPD Buffer zero length.\n");
266 goto out_free;
267 }
268 /* printk("PCI: bus_vpd: %p, %d\n",bus_vpd, bus_vpd_len); */
269 /* Make sure this is what I think it is */
270 if (*bus_vpd != VPD_ID_STRING) {
271 printk("PCI: Bus VPD Buffer missing starting tag.\n");
272 goto out_free;
273 }
274 iseries_parse_vpd(bus_vpd, bus_vpd_len, agent, frame, card);
275 status = 1;
276out_free:
277 kfree(bus_vpd);
278 return status;
279}
280
281/*
282 * Prints the device information.
283 * - Pass in pci_dev* pointer to the device.
284 * - Pass in the device count
285 *
286 * Format:
287 * PCI: Bus 0, Device 26, Vendor 0x12AE Frame 1, Card C10 Ethernet
288 * controller
289 */
290static void __init iseries_device_information(struct pci_dev *pdev,
291 u16 bus, HvSubBusNumber subbus)
292{
293 u8 frame = 0;
294 char card[4];
295 HvAgentId agent;
296
297 agent = ISERIES_PCI_AGENTID(ISERIES_GET_DEVICE_FROM_SUBBUS(subbus),
298 ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus));
299
300 if (iseries_get_location_code(bus, agent, &frame, card)) {
301 printk(KERN_INFO "PCI: %s, Vendor %04X Frame%3d, "
302 "Card %4s 0x%04X\n", pci_name(pdev), pdev->vendor,
303 frame, card, (int)(pdev->class >> 8));
304 }
305}
306
307/*
308 * iomm_table_allocate_entry
309 *
310 * Adds pci_dev entry in address translation table
311 *
312 * - Allocates the number of entries required in table base on BAR
313 * size.
314 * - Allocates starting at BASE_IO_MEMORY and increases.
315 * - The size is round up to be a multiple of entry size.
316 * - CurrentIndex is incremented to keep track of the last entry.
317 * - Builds the resource entry for allocated BARs.
318 */
319static void __init iomm_table_allocate_entry(struct pci_dev *dev, int bar_num)
320{
321 struct resource *bar_res = &dev->resource[bar_num];
322 long bar_size = pci_resource_len(dev, bar_num);
323 struct device_node *dn = pci_device_to_OF_node(dev);
324
325 /*
326 * No space to allocate, quick exit, skip Allocation.
327 */
328 if (bar_size == 0)
329 return;
330 /*
331 * Set Resource values.
332 */
333 spin_lock(&iomm_table_lock);
334 bar_res->start = BASE_IO_MEMORY +
335 IOMM_TABLE_ENTRY_SIZE * current_iomm_table_entry;
336 bar_res->end = bar_res->start + bar_size - 1;
337 /*
338 * Allocate the number of table entries needed for BAR.
339 */
340 while (bar_size > 0 ) {
341 iomm_table[current_iomm_table_entry] = dn;
342 ds_addr_table[current_iomm_table_entry] =
343 iseries_ds_addr(dn) | (bar_num << 24);
344 bar_size -= IOMM_TABLE_ENTRY_SIZE;
345 ++current_iomm_table_entry;
346 }
347 max_io_memory = BASE_IO_MEMORY +
348 IOMM_TABLE_ENTRY_SIZE * current_iomm_table_entry;
349 spin_unlock(&iomm_table_lock);
350}
351
352/*
353 * allocate_device_bars
354 *
355 * - Allocates ALL pci_dev BAR's and updates the resources with the
356 * BAR value. BARS with zero length will have the resources
357 * The HvCallPci_getBarParms is used to get the size of the BAR
358 * space. It calls iomm_table_allocate_entry to allocate
359 * each entry.
360 * - Loops through The Bar resources(0 - 5) including the ROM
361 * is resource(6).
362 */
363static void __init allocate_device_bars(struct pci_dev *dev)
364{
365 int bar_num;
366
367 for (bar_num = 0; bar_num <= PCI_ROM_RESOURCE; ++bar_num)
368 iomm_table_allocate_entry(dev, bar_num);
369}
370
371/*
372 * Log error information to system console.
373 * Filter out the device not there errors.
374 * PCI: EADs Connect Failed 0x18.58.10 Rc: 0x00xx
375 * PCI: Read Vendor Failed 0x18.58.10 Rc: 0x00xx
376 * PCI: Connect Bus Unit Failed 0x18.58.10 Rc: 0x00xx
377 */
378static void pci_log_error(char *error, int bus, int subbus,
379 int agent, int hv_res)
380{
381 if (hv_res == 0x0302)
382 return;
383 printk(KERN_ERR "PCI: %s Failed: 0x%02X.%02X.%02X Rc: 0x%04X",
384 error, bus, subbus, agent, hv_res);
385}
386
387/*
388 * Look down the chain to find the matching Device Device
389 */
390static struct device_node *find_device_node(int bus, int devfn)
391{
392 struct device_node *node;
393
394 for (node = NULL; (node = of_find_all_nodes(node)); ) {
395 struct pci_dn *pdn = PCI_DN(node);
396
397 if (pdn && (bus == pdn->busno) && (devfn == pdn->devfn))
398 return node;
399 }
400 return NULL;
401}
402
403/*
404 * iSeries_pcibios_fixup_resources
405 *
406 * Fixes up all resources for devices
407 */
408void __init iSeries_pcibios_fixup_resources(struct pci_dev *pdev)
409{
410 const u32 *agent;
411 const u32 *sub_bus;
412 unsigned char bus = pdev->bus->number;
413 struct device_node *node;
414 int i;
415
416 node = pci_device_to_OF_node(pdev);
417 pr_debug("PCI: iSeries %s, pdev %p, node %p\n",
418 pci_name(pdev), pdev, node);
419 if (!node) {
420 printk("PCI: %s disabled, device tree entry not found !\n",
421 pci_name(pdev));
422 for (i = 0; i <= PCI_ROM_RESOURCE; i++)
423 pdev->resource[i].flags = 0;
424 return;
425 }
426 sub_bus = of_get_property(node, "linux,subbus", NULL);
427 agent = of_get_property(node, "linux,agent-id", NULL);
428 if (agent && sub_bus) {
429 u8 irq = iSeries_allocate_IRQ(bus, 0, *sub_bus);
430 int err;
431
432 err = HvCallXm_connectBusUnit(bus, *sub_bus, *agent, irq);
433 if (err)
434 pci_log_error("Connect Bus Unit",
435 bus, *sub_bus, *agent, err);
436 else {
437 err = HvCallPci_configStore8(bus, *sub_bus,
438 *agent, PCI_INTERRUPT_LINE, irq);
439 if (err)
440 pci_log_error("PciCfgStore Irq Failed!",
441 bus, *sub_bus, *agent, err);
442 else
443 pdev->irq = irq;
444 }
445 }
446
447 allocate_device_bars(pdev);
448 if (likely(sub_bus))
449 iseries_device_information(pdev, bus, *sub_bus);
450 else
451 printk(KERN_ERR "PCI: Device node %s has missing or invalid "
452 "linux,subbus property\n", node->full_name);
453}
454
455/*
456 * iSeries_pci_final_fixup(void)
457 */
458void __init iSeries_pci_final_fixup(void)
459{
460 /* Fix up at the device node and pci_dev relationship */
461 mf_display_src(0xC9000100);
462 iSeries_activate_IRQs();
463 mf_display_src(0xC9000200);
464}
465
466/*
467 * Config space read and write functions.
468 * For now at least, we look for the device node for the bus and devfn
469 * that we are asked to access. It may be possible to translate the devfn
470 * to a subbus and deviceid more directly.
471 */
472static u64 hv_cfg_read_func[4] = {
473 HvCallPciConfigLoad8, HvCallPciConfigLoad16,
474 HvCallPciConfigLoad32, HvCallPciConfigLoad32
475};
476
477static u64 hv_cfg_write_func[4] = {
478 HvCallPciConfigStore8, HvCallPciConfigStore16,
479 HvCallPciConfigStore32, HvCallPciConfigStore32
480};
481
482/*
483 * Read PCI config space
484 */
485static int iSeries_pci_read_config(struct pci_bus *bus, unsigned int devfn,
486 int offset, int size, u32 *val)
487{
488 struct device_node *node = find_device_node(bus->number, devfn);
489 u64 fn;
490 struct HvCallPci_LoadReturn ret;
491
492 if (node == NULL)
493 return PCIBIOS_DEVICE_NOT_FOUND;
494 if (offset > 255) {
495 *val = ~0;
496 return PCIBIOS_BAD_REGISTER_NUMBER;
497 }
498
499 fn = hv_cfg_read_func[(size - 1) & 3];
500 HvCall3Ret16(fn, &ret, iseries_ds_addr(node), offset, 0);
501
502 if (ret.rc != 0) {
503 *val = ~0;
504 return PCIBIOS_DEVICE_NOT_FOUND; /* or something */
505 }
506
507 *val = ret.value;
508 return 0;
509}
510
511/*
512 * Write PCI config space
513 */
514
515static int iSeries_pci_write_config(struct pci_bus *bus, unsigned int devfn,
516 int offset, int size, u32 val)
517{
518 struct device_node *node = find_device_node(bus->number, devfn);
519 u64 fn;
520 u64 ret;
521
522 if (node == NULL)
523 return PCIBIOS_DEVICE_NOT_FOUND;
524 if (offset > 255)
525 return PCIBIOS_BAD_REGISTER_NUMBER;
526
527 fn = hv_cfg_write_func[(size - 1) & 3];
528 ret = HvCall4(fn, iseries_ds_addr(node), offset, val, 0);
529
530 if (ret != 0)
531 return PCIBIOS_DEVICE_NOT_FOUND;
532
533 return 0;
534}
535
536static struct pci_ops iSeries_pci_ops = {
537 .read = iSeries_pci_read_config,
538 .write = iSeries_pci_write_config
539};
540
541/*
542 * Check Return Code
543 * -> On Failure, print and log information.
544 * Increment Retry Count, if exceeds max, panic partition.
545 *
546 * PCI: Device 23.90 ReadL I/O Error( 0): 0x1234
547 * PCI: Device 23.90 ReadL Retry( 1)
548 * PCI: Device 23.90 ReadL Retry Successful(1)
549 */
550static int check_return_code(char *type, struct device_node *dn,
551 int *retry, u64 ret)
552{
553 if (ret != 0) {
554 struct pci_dn *pdn = PCI_DN(dn);
555
556 (*retry)++;
557 printk("PCI: %s: Device 0x%04X:%02X I/O Error(%2d): 0x%04X\n",
558 type, pdn->busno, pdn->devfn,
559 *retry, (int)ret);
560 /*
561 * Bump the retry and check for retry count exceeded.
562 * If, Exceeded, panic the system.
563 */
564 if (((*retry) > PCI_RETRY_MAX) &&
565 (limit_pci_retries > 0)) {
566 mf_display_src(0xB6000103);
567 panic_timeout = 0;
568 panic("PCI: Hardware I/O Error, SRC B6000103, "
569 "Automatic Reboot Disabled.\n");
570 }
571 return -1; /* Retry Try */
572 }
573 return 0;
574}
575
576/*
577 * Translate the I/O Address into a device node, bar, and bar offset.
578 * Note: Make sure the passed variable end up on the stack to avoid
579 * the exposure of being device global.
580 */
581static inline struct device_node *xlate_iomm_address(
582 const volatile void __iomem *addr,
583 u64 *dsaptr, u64 *bar_offset, const char *func)
584{
585 unsigned long orig_addr;
586 unsigned long base_addr;
587 unsigned long ind;
588 struct device_node *dn;
589
590 orig_addr = (unsigned long __force)addr;
591 if ((orig_addr < BASE_IO_MEMORY) || (orig_addr >= max_io_memory)) {
592 static DEFINE_RATELIMIT_STATE(ratelimit, 60 * HZ, 10);
593
594 if (__ratelimit(&ratelimit))
595 printk(KERN_ERR
596 "iSeries_%s: invalid access at IO address %p\n",
597 func, addr);
598 return NULL;
599 }
600 base_addr = orig_addr - BASE_IO_MEMORY;
601 ind = base_addr / IOMM_TABLE_ENTRY_SIZE;
602 dn = iomm_table[ind];
603
604 if (dn != NULL) {
605 *dsaptr = ds_addr_table[ind];
606 *bar_offset = base_addr % IOMM_TABLE_ENTRY_SIZE;
607 } else
608 panic("PCI: Invalid PCI IO address detected!\n");
609 return dn;
610}
611
612/*
613 * Read MM I/O Instructions for the iSeries
614 * On MM I/O error, all ones are returned and iSeries_pci_IoError is cal
615 * else, data is returned in Big Endian format.
616 */
617static u8 iseries_readb(const volatile void __iomem *addr)
618{
619 u64 bar_offset;
620 u64 dsa;
621 int retry = 0;
622 struct HvCallPci_LoadReturn ret;
623 struct device_node *dn =
624 xlate_iomm_address(addr, &dsa, &bar_offset, "read_byte");
625
626 if (dn == NULL)
627 return 0xff;
628 do {
629 HvCall3Ret16(HvCallPciBarLoad8, &ret, dsa, bar_offset, 0);
630 } while (check_return_code("RDB", dn, &retry, ret.rc) != 0);
631
632 return ret.value;
633}
634
635static u16 iseries_readw_be(const volatile void __iomem *addr)
636{
637 u64 bar_offset;
638 u64 dsa;
639 int retry = 0;
640 struct HvCallPci_LoadReturn ret;
641 struct device_node *dn =
642 xlate_iomm_address(addr, &dsa, &bar_offset, "read_word");
643
644 if (dn == NULL)
645 return 0xffff;
646 do {
647 HvCall3Ret16(HvCallPciBarLoad16, &ret, dsa,
648 bar_offset, 0);
649 } while (check_return_code("RDW", dn, &retry, ret.rc) != 0);
650
651 return ret.value;
652}
653
654static u32 iseries_readl_be(const volatile void __iomem *addr)
655{
656 u64 bar_offset;
657 u64 dsa;
658 int retry = 0;
659 struct HvCallPci_LoadReturn ret;
660 struct device_node *dn =
661 xlate_iomm_address(addr, &dsa, &bar_offset, "read_long");
662
663 if (dn == NULL)
664 return 0xffffffff;
665 do {
666 HvCall3Ret16(HvCallPciBarLoad32, &ret, dsa,
667 bar_offset, 0);
668 } while (check_return_code("RDL", dn, &retry, ret.rc) != 0);
669
670 return ret.value;
671}
672
673/*
674 * Write MM I/O Instructions for the iSeries
675 *
676 */
677static void iseries_writeb(u8 data, volatile void __iomem *addr)
678{
679 u64 bar_offset;
680 u64 dsa;
681 int retry = 0;
682 u64 rc;
683 struct device_node *dn =
684 xlate_iomm_address(addr, &dsa, &bar_offset, "write_byte");
685
686 if (dn == NULL)
687 return;
688 do {
689 rc = HvCall4(HvCallPciBarStore8, dsa, bar_offset, data, 0);
690 } while (check_return_code("WWB", dn, &retry, rc) != 0);
691}
692
693static void iseries_writew_be(u16 data, volatile void __iomem *addr)
694{
695 u64 bar_offset;
696 u64 dsa;
697 int retry = 0;
698 u64 rc;
699 struct device_node *dn =
700 xlate_iomm_address(addr, &dsa, &bar_offset, "write_word");
701
702 if (dn == NULL)
703 return;
704 do {
705 rc = HvCall4(HvCallPciBarStore16, dsa, bar_offset, data, 0);
706 } while (check_return_code("WWW", dn, &retry, rc) != 0);
707}
708
709static void iseries_writel_be(u32 data, volatile void __iomem *addr)
710{
711 u64 bar_offset;
712 u64 dsa;
713 int retry = 0;
714 u64 rc;
715 struct device_node *dn =
716 xlate_iomm_address(addr, &dsa, &bar_offset, "write_long");
717
718 if (dn == NULL)
719 return;
720 do {
721 rc = HvCall4(HvCallPciBarStore32, dsa, bar_offset, data, 0);
722 } while (check_return_code("WWL", dn, &retry, rc) != 0);
723}
724
725static u16 iseries_readw(const volatile void __iomem *addr)
726{
727 return le16_to_cpu(iseries_readw_be(addr));
728}
729
730static u32 iseries_readl(const volatile void __iomem *addr)
731{
732 return le32_to_cpu(iseries_readl_be(addr));
733}
734
735static void iseries_writew(u16 data, volatile void __iomem *addr)
736{
737 iseries_writew_be(cpu_to_le16(data), addr);
738}
739
740static void iseries_writel(u32 data, volatile void __iomem *addr)
741{
742 iseries_writel(cpu_to_le32(data), addr);
743}
744
745static void iseries_readsb(const volatile void __iomem *addr, void *buf,
746 unsigned long count)
747{
748 u8 *dst = buf;
749 while(count-- > 0)
750 *(dst++) = iseries_readb(addr);
751}
752
753static void iseries_readsw(const volatile void __iomem *addr, void *buf,
754 unsigned long count)
755{
756 u16 *dst = buf;
757 while(count-- > 0)
758 *(dst++) = iseries_readw_be(addr);
759}
760
761static void iseries_readsl(const volatile void __iomem *addr, void *buf,
762 unsigned long count)
763{
764 u32 *dst = buf;
765 while(count-- > 0)
766 *(dst++) = iseries_readl_be(addr);
767}
768
769static void iseries_writesb(volatile void __iomem *addr, const void *buf,
770 unsigned long count)
771{
772 const u8 *src = buf;
773 while(count-- > 0)
774 iseries_writeb(*(src++), addr);
775}
776
777static void iseries_writesw(volatile void __iomem *addr, const void *buf,
778 unsigned long count)
779{
780 const u16 *src = buf;
781 while(count-- > 0)
782 iseries_writew_be(*(src++), addr);
783}
784
785static void iseries_writesl(volatile void __iomem *addr, const void *buf,
786 unsigned long count)
787{
788 const u32 *src = buf;
789 while(count-- > 0)
790 iseries_writel_be(*(src++), addr);
791}
792
793static void iseries_memset_io(volatile void __iomem *addr, int c,
794 unsigned long n)
795{
796 volatile char __iomem *d = addr;
797
798 while (n-- > 0)
799 iseries_writeb(c, d++);
800}
801
802static void iseries_memcpy_fromio(void *dest, const volatile void __iomem *src,
803 unsigned long n)
804{
805 char *d = dest;
806 const volatile char __iomem *s = src;
807
808 while (n-- > 0)
809 *d++ = iseries_readb(s++);
810}
811
812static void iseries_memcpy_toio(volatile void __iomem *dest, const void *src,
813 unsigned long n)
814{
815 const char *s = src;
816 volatile char __iomem *d = dest;
817
818 while (n-- > 0)
819 iseries_writeb(*s++, d++);
820}
821
822/* We only set MMIO ops. The default PIO ops will be default
823 * to the MMIO ops + pci_io_base which is 0 on iSeries as
824 * expected so both should work.
825 *
826 * Note that we don't implement the readq/writeq versions as
827 * I don't know of an HV call for doing so. Thus, the default
828 * operation will be used instead, which will fault a the value
829 * return by iSeries for MMIO addresses always hits a non mapped
830 * area. This is as good as the BUG() we used to have there.
831 */
832static struct ppc_pci_io __initdata iseries_pci_io = {
833 .readb = iseries_readb,
834 .readw = iseries_readw,
835 .readl = iseries_readl,
836 .readw_be = iseries_readw_be,
837 .readl_be = iseries_readl_be,
838 .writeb = iseries_writeb,
839 .writew = iseries_writew,
840 .writel = iseries_writel,
841 .writew_be = iseries_writew_be,
842 .writel_be = iseries_writel_be,
843 .readsb = iseries_readsb,
844 .readsw = iseries_readsw,
845 .readsl = iseries_readsl,
846 .writesb = iseries_writesb,
847 .writesw = iseries_writesw,
848 .writesl = iseries_writesl,
849 .memset_io = iseries_memset_io,
850 .memcpy_fromio = iseries_memcpy_fromio,
851 .memcpy_toio = iseries_memcpy_toio,
852};
853
854/*
855 * iSeries_pcibios_init
856 *
857 * Description:
858 * This function checks for all possible system PCI host bridges that connect
859 * PCI buses. The system hypervisor is queried as to the guest partition
860 * ownership status. A pci_controller is built for any bus which is partially
861 * owned or fully owned by this guest partition.
862 */
863void __init iSeries_pcibios_init(void)
864{
865 struct pci_controller *phb;
866 struct device_node *root = of_find_node_by_path("/");
867 struct device_node *node = NULL;
868
869 /* Install IO hooks */
870 ppc_pci_io = iseries_pci_io;
871
872 pci_probe_only = 1;
873
874 /* iSeries has no IO space in the common sense, it needs to set
875 * the IO base to 0
876 */
877 pci_io_base = 0;
878
879 if (root == NULL) {
880 printk(KERN_CRIT "iSeries_pcibios_init: can't find root "
881 "of device tree\n");
882 return;
883 }
884 while ((node = of_get_next_child(root, node)) != NULL) {
885 HvBusNumber bus;
886 const u32 *busp;
887
888 if ((node->type == NULL) || (strcmp(node->type, "pci") != 0))
889 continue;
890
891 busp = of_get_property(node, "bus-range", NULL);
892 if (busp == NULL)
893 continue;
894 bus = *busp;
895 printk("bus %d appears to exist\n", bus);
896 phb = pcibios_alloc_controller(node);
897 if (phb == NULL)
898 continue;
899 /* All legacy iSeries PHBs are in domain zero */
900 phb->global_number = 0;
901
902 phb->first_busno = bus;
903 phb->last_busno = bus;
904 phb->ops = &iSeries_pci_ops;
905 phb->io_base_virt = (void __iomem *)_IO_BASE;
906 phb->io_resource.flags = IORESOURCE_IO;
907 phb->io_resource.start = BASE_IO_MEMORY;
908 phb->io_resource.end = END_IO_MEMORY;
909 phb->io_resource.name = "iSeries PCI IO";
910 phb->mem_resources[0].flags = IORESOURCE_MEM;
911 phb->mem_resources[0].start = BASE_IO_MEMORY;
912 phb->mem_resources[0].end = END_IO_MEMORY;
913 phb->mem_resources[0].name = "Series PCI MEM";
914 }
915
916 of_node_put(root);
917
918 pci_devs_phb_init();
919}
920
diff --git a/arch/powerpc/platforms/iseries/pci.h b/arch/powerpc/platforms/iseries/pci.h
new file mode 100644
index 00000000000..d9cf974c271
--- /dev/null
+++ b/arch/powerpc/platforms/iseries/pci.h
@@ -0,0 +1,58 @@
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
46struct pci_dev;
47
48#ifdef CONFIG_PCI
49extern void iSeries_pcibios_init(void);
50extern void iSeries_pci_final_fixup(void);
51extern void iSeries_pcibios_fixup_resources(struct pci_dev *dev);
52#else
53static inline void iSeries_pcibios_init(void) { }
54static inline void iSeries_pci_final_fixup(void) { }
55static 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
new file mode 100644
index 00000000000..06763682db4
--- /dev/null
+++ b/arch/powerpc/platforms/iseries/proc.c
@@ -0,0 +1,120 @@
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
33static 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}
46core_initcall(iseries_proc_create);
47
48static unsigned long startTitan = 0;
49static unsigned long startTb = 0;
50
51static 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
99static int proc_titantod_open(struct inode *inode, struct file *file)
100{
101 return single_open(file, proc_titantod_show, NULL);
102}
103
104static 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
111static 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
new file mode 100644
index 00000000000..7ac5d0d0dbf
--- /dev/null
+++ b/arch/powerpc/platforms/iseries/processor_vpd.h
@@ -0,0 +1,85 @@
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 */
26struct 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
83extern 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
new file mode 100644
index 00000000000..6ad7d843e8f
--- /dev/null
+++ b/arch/powerpc/platforms/iseries/release_data.h
@@ -0,0 +1,63 @@
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
46struct 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
61extern 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
new file mode 100644
index 00000000000..c25a0815c26
--- /dev/null
+++ b/arch/powerpc/platforms/iseries/setup.c
@@ -0,0 +1,717 @@
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/seq_file.h>
25#include <linux/kdev_t.h>
26#include <linux/kexec.h>
27#include <linux/major.h>
28#include <linux/root_dev.h>
29#include <linux/kernel.h>
30#include <linux/hrtimer.h>
31#include <linux/tick.h>
32
33#include <asm/processor.h>
34#include <asm/machdep.h>
35#include <asm/page.h>
36#include <asm/mmu.h>
37#include <asm/pgtable.h>
38#include <asm/mmu_context.h>
39#include <asm/cputable.h>
40#include <asm/sections.h>
41#include <asm/iommu.h>
42#include <asm/firmware.h>
43#include <asm/system.h>
44#include <asm/time.h>
45#include <asm/paca.h>
46#include <asm/cache.h>
47#include <asm/abs_addr.h>
48#include <asm/iseries/hv_lp_config.h>
49#include <asm/iseries/hv_call_event.h>
50#include <asm/iseries/hv_call_xm.h>
51#include <asm/iseries/it_lp_queue.h>
52#include <asm/iseries/mf.h>
53#include <asm/iseries/hv_lp_event.h>
54#include <asm/iseries/lpar_map.h>
55#include <asm/udbg.h>
56#include <asm/irq.h>
57
58#include "naca.h"
59#include "setup.h"
60#include "irq.h"
61#include "vpd_areas.h"
62#include "processor_vpd.h"
63#include "it_lp_naca.h"
64#include "main_store.h"
65#include "call_sm.h"
66#include "call_hpt.h"
67#include "pci.h"
68
69#ifdef DEBUG
70#define DBG(fmt...) udbg_printf(fmt)
71#else
72#define DBG(fmt...)
73#endif
74
75/* Function Prototypes */
76static unsigned long build_iSeries_Memory_Map(void);
77static void iseries_shared_idle(void);
78static void iseries_dedicated_idle(void);
79
80
81struct MemoryBlock {
82 unsigned long absStart;
83 unsigned long absEnd;
84 unsigned long logicalStart;
85 unsigned long logicalEnd;
86};
87
88/*
89 * Process the main store vpd to determine where the holes in memory are
90 * and return the number of physical blocks and fill in the array of
91 * block data.
92 */
93static unsigned long iSeries_process_Condor_mainstore_vpd(
94 struct MemoryBlock *mb_array, unsigned long max_entries)
95{
96 unsigned long holeFirstChunk, holeSizeChunks;
97 unsigned long numMemoryBlocks = 1;
98 struct IoHriMainStoreSegment4 *msVpd =
99 (struct IoHriMainStoreSegment4 *)xMsVpd;
100 unsigned long holeStart = msVpd->nonInterleavedBlocksStartAdr;
101 unsigned long holeEnd = msVpd->nonInterleavedBlocksEndAdr;
102 unsigned long holeSize = holeEnd - holeStart;
103
104 printk("Mainstore_VPD: Condor\n");
105 /*
106 * Determine if absolute memory has any
107 * holes so that we can interpret the
108 * access map we get back from the hypervisor
109 * correctly.
110 */
111 mb_array[0].logicalStart = 0;
112 mb_array[0].logicalEnd = 0x100000000UL;
113 mb_array[0].absStart = 0;
114 mb_array[0].absEnd = 0x100000000UL;
115
116 if (holeSize) {
117 numMemoryBlocks = 2;
118 holeStart = holeStart & 0x000fffffffffffffUL;
119 holeStart = addr_to_chunk(holeStart);
120 holeFirstChunk = holeStart;
121 holeSize = addr_to_chunk(holeSize);
122 holeSizeChunks = holeSize;
123 printk( "Main store hole: start chunk = %0lx, size = %0lx chunks\n",
124 holeFirstChunk, holeSizeChunks );
125 mb_array[0].logicalEnd = holeFirstChunk;
126 mb_array[0].absEnd = holeFirstChunk;
127 mb_array[1].logicalStart = holeFirstChunk;
128 mb_array[1].logicalEnd = 0x100000000UL - holeSizeChunks;
129 mb_array[1].absStart = holeFirstChunk + holeSizeChunks;
130 mb_array[1].absEnd = 0x100000000UL;
131 }
132 return numMemoryBlocks;
133}
134
135#define MaxSegmentAreas 32
136#define MaxSegmentAdrRangeBlocks 128
137#define MaxAreaRangeBlocks 4
138
139static unsigned long iSeries_process_Regatta_mainstore_vpd(
140 struct MemoryBlock *mb_array, unsigned long max_entries)
141{
142 struct IoHriMainStoreSegment5 *msVpdP =
143 (struct IoHriMainStoreSegment5 *)xMsVpd;
144 unsigned long numSegmentBlocks = 0;
145 u32 existsBits = msVpdP->msAreaExists;
146 unsigned long area_num;
147
148 printk("Mainstore_VPD: Regatta\n");
149
150 for (area_num = 0; area_num < MaxSegmentAreas; ++area_num ) {
151 unsigned long numAreaBlocks;
152 struct IoHriMainStoreArea4 *currentArea;
153
154 if (existsBits & 0x80000000) {
155 unsigned long block_num;
156
157 currentArea = &msVpdP->msAreaArray[area_num];
158 numAreaBlocks = currentArea->numAdrRangeBlocks;
159 printk("ms_vpd: processing area %2ld blocks=%ld",
160 area_num, numAreaBlocks);
161 for (block_num = 0; block_num < numAreaBlocks;
162 ++block_num ) {
163 /* Process an address range block */
164 struct MemoryBlock tempBlock;
165 unsigned long i;
166
167 tempBlock.absStart =
168 (unsigned long)currentArea->xAdrRangeBlock[block_num].blockStart;
169 tempBlock.absEnd =
170 (unsigned long)currentArea->xAdrRangeBlock[block_num].blockEnd;
171 tempBlock.logicalStart = 0;
172 tempBlock.logicalEnd = 0;
173 printk("\n block %ld absStart=%016lx absEnd=%016lx",
174 block_num, tempBlock.absStart,
175 tempBlock.absEnd);
176
177 for (i = 0; i < numSegmentBlocks; ++i) {
178 if (mb_array[i].absStart ==
179 tempBlock.absStart)
180 break;
181 }
182 if (i == numSegmentBlocks) {
183 if (numSegmentBlocks == max_entries)
184 panic("iSeries_process_mainstore_vpd: too many memory blocks");
185 mb_array[numSegmentBlocks] = tempBlock;
186 ++numSegmentBlocks;
187 } else
188 printk(" (duplicate)");
189 }
190 printk("\n");
191 }
192 existsBits <<= 1;
193 }
194 /* Now sort the blocks found into ascending sequence */
195 if (numSegmentBlocks > 1) {
196 unsigned long m, n;
197
198 for (m = 0; m < numSegmentBlocks - 1; ++m) {
199 for (n = numSegmentBlocks - 1; m < n; --n) {
200 if (mb_array[n].absStart <
201 mb_array[n-1].absStart) {
202 struct MemoryBlock tempBlock;
203
204 tempBlock = mb_array[n];
205 mb_array[n] = mb_array[n-1];
206 mb_array[n-1] = tempBlock;
207 }
208 }
209 }
210 }
211 /*
212 * Assign "logical" addresses to each block. These
213 * addresses correspond to the hypervisor "bitmap" space.
214 * Convert all addresses into units of 256K chunks.
215 */
216 {
217 unsigned long i, nextBitmapAddress;
218
219 printk("ms_vpd: %ld sorted memory blocks\n", numSegmentBlocks);
220 nextBitmapAddress = 0;
221 for (i = 0; i < numSegmentBlocks; ++i) {
222 unsigned long length = mb_array[i].absEnd -
223 mb_array[i].absStart;
224
225 mb_array[i].logicalStart = nextBitmapAddress;
226 mb_array[i].logicalEnd = nextBitmapAddress + length;
227 nextBitmapAddress += length;
228 printk(" Bitmap range: %016lx - %016lx\n"
229 " Absolute range: %016lx - %016lx\n",
230 mb_array[i].logicalStart,
231 mb_array[i].logicalEnd,
232 mb_array[i].absStart, mb_array[i].absEnd);
233 mb_array[i].absStart = addr_to_chunk(mb_array[i].absStart &
234 0x000fffffffffffffUL);
235 mb_array[i].absEnd = addr_to_chunk(mb_array[i].absEnd &
236 0x000fffffffffffffUL);
237 mb_array[i].logicalStart =
238 addr_to_chunk(mb_array[i].logicalStart);
239 mb_array[i].logicalEnd = addr_to_chunk(mb_array[i].logicalEnd);
240 }
241 }
242
243 return numSegmentBlocks;
244}
245
246static unsigned long iSeries_process_mainstore_vpd(struct MemoryBlock *mb_array,
247 unsigned long max_entries)
248{
249 unsigned long i;
250 unsigned long mem_blocks = 0;
251
252 if (mmu_has_feature(MMU_FTR_SLB))
253 mem_blocks = iSeries_process_Regatta_mainstore_vpd(mb_array,
254 max_entries);
255 else
256 mem_blocks = iSeries_process_Condor_mainstore_vpd(mb_array,
257 max_entries);
258
259 printk("Mainstore_VPD: numMemoryBlocks = %ld\n", mem_blocks);
260 for (i = 0; i < mem_blocks; ++i) {
261 printk("Mainstore_VPD: block %3ld logical chunks %016lx - %016lx\n"
262 " abs chunks %016lx - %016lx\n",
263 i, mb_array[i].logicalStart, mb_array[i].logicalEnd,
264 mb_array[i].absStart, mb_array[i].absEnd);
265 }
266 return mem_blocks;
267}
268
269static void __init iSeries_get_cmdline(void)
270{
271 char *p, *q;
272
273 /* copy the command line parameter from the primary VSP */
274 HvCallEvent_dmaToSp(cmd_line, 2 * 64* 1024, 256,
275 HvLpDma_Direction_RemoteToLocal);
276
277 p = cmd_line;
278 q = cmd_line + 255;
279 while(p < q) {
280 if (!*p || *p == '\n')
281 break;
282 ++p;
283 }
284 *p = 0;
285}
286
287static void __init iSeries_init_early(void)
288{
289 DBG(" -> iSeries_init_early()\n");
290
291 /* Snapshot the timebase, for use in later recalibration */
292 iSeries_time_init_early();
293
294 /*
295 * Initialize the DMA/TCE management
296 */
297 iommu_init_early_iSeries();
298
299 /* Initialize machine-dependency vectors */
300#ifdef CONFIG_SMP
301 smp_init_iSeries();
302#endif
303
304 /* Associate Lp Event Queue 0 with processor 0 */
305 HvCallEvent_setLpEventQueueInterruptProc(0, 0);
306
307 mf_init();
308
309 DBG(" <- iSeries_init_early()\n");
310}
311
312struct mschunks_map mschunks_map = {
313 /* XXX We don't use these, but Piranha might need them. */
314 .chunk_size = MSCHUNKS_CHUNK_SIZE,
315 .chunk_shift = MSCHUNKS_CHUNK_SHIFT,
316 .chunk_mask = MSCHUNKS_OFFSET_MASK,
317};
318EXPORT_SYMBOL(mschunks_map);
319
320static void mschunks_alloc(unsigned long num_chunks)
321{
322 klimit = _ALIGN(klimit, sizeof(u32));
323 mschunks_map.mapping = (u32 *)klimit;
324 klimit += num_chunks * sizeof(u32);
325 mschunks_map.num_chunks = num_chunks;
326}
327
328/*
329 * The iSeries may have very large memories ( > 128 GB ) and a partition
330 * may get memory in "chunks" that may be anywhere in the 2**52 real
331 * address space. The chunks are 256K in size. To map this to the
332 * memory model Linux expects, the AS/400 specific code builds a
333 * translation table to translate what Linux thinks are "physical"
334 * addresses to the actual real addresses. This allows us to make
335 * it appear to Linux that we have contiguous memory starting at
336 * physical address zero while in fact this could be far from the truth.
337 * To avoid confusion, I'll let the words physical and/or real address
338 * apply to the Linux addresses while I'll use "absolute address" to
339 * refer to the actual hardware real address.
340 *
341 * build_iSeries_Memory_Map gets information from the Hypervisor and
342 * looks at the Main Store VPD to determine the absolute addresses
343 * of the memory that has been assigned to our partition and builds
344 * a table used to translate Linux's physical addresses to these
345 * absolute addresses. Absolute addresses are needed when
346 * communicating with the hypervisor (e.g. to build HPT entries)
347 *
348 * Returns the physical memory size
349 */
350
351static unsigned long __init build_iSeries_Memory_Map(void)
352{
353 u32 loadAreaFirstChunk, loadAreaLastChunk, loadAreaSize;
354 u32 nextPhysChunk;
355 u32 hptFirstChunk, hptLastChunk, hptSizeChunks, hptSizePages;
356 u32 totalChunks,moreChunks;
357 u32 currChunk, thisChunk, absChunk;
358 u32 currDword;
359 u32 chunkBit;
360 u64 map;
361 struct MemoryBlock mb[32];
362 unsigned long numMemoryBlocks, curBlock;
363
364 /* Chunk size on iSeries is 256K bytes */
365 totalChunks = (u32)HvLpConfig_getMsChunks();
366 mschunks_alloc(totalChunks);
367
368 /*
369 * Get absolute address of our load area
370 * and map it to physical address 0
371 * This guarantees that the loadarea ends up at physical 0
372 * otherwise, it might not be returned by PLIC as the first
373 * chunks
374 */
375
376 loadAreaFirstChunk = (u32)addr_to_chunk(itLpNaca.xLoadAreaAddr);
377 loadAreaSize = itLpNaca.xLoadAreaChunks;
378
379 /*
380 * Only add the pages already mapped here.
381 * Otherwise we might add the hpt pages
382 * The rest of the pages of the load area
383 * aren't in the HPT yet and can still
384 * be assigned an arbitrary physical address
385 */
386 if ((loadAreaSize * 64) > HvPagesToMap)
387 loadAreaSize = HvPagesToMap / 64;
388
389 loadAreaLastChunk = loadAreaFirstChunk + loadAreaSize - 1;
390
391 /*
392 * TODO Do we need to do something if the HPT is in the 64MB load area?
393 * This would be required if the itLpNaca.xLoadAreaChunks includes
394 * the HPT size
395 */
396
397 printk("Mapping load area - physical addr = 0000000000000000\n"
398 " absolute addr = %016lx\n",
399 chunk_to_addr(loadAreaFirstChunk));
400 printk("Load area size %dK\n", loadAreaSize * 256);
401
402 for (nextPhysChunk = 0; nextPhysChunk < loadAreaSize; ++nextPhysChunk)
403 mschunks_map.mapping[nextPhysChunk] =
404 loadAreaFirstChunk + nextPhysChunk;
405
406 /*
407 * Get absolute address of our HPT and remember it so
408 * we won't map it to any physical address
409 */
410 hptFirstChunk = (u32)addr_to_chunk(HvCallHpt_getHptAddress());
411 hptSizePages = (u32)HvCallHpt_getHptPages();
412 hptSizeChunks = hptSizePages >>
413 (MSCHUNKS_CHUNK_SHIFT - HW_PAGE_SHIFT);
414 hptLastChunk = hptFirstChunk + hptSizeChunks - 1;
415
416 printk("HPT absolute addr = %016lx, size = %dK\n",
417 chunk_to_addr(hptFirstChunk), hptSizeChunks * 256);
418
419 /*
420 * Determine if absolute memory has any
421 * holes so that we can interpret the
422 * access map we get back from the hypervisor
423 * correctly.
424 */
425 numMemoryBlocks = iSeries_process_mainstore_vpd(mb, 32);
426
427 /*
428 * Process the main store access map from the hypervisor
429 * to build up our physical -> absolute translation table
430 */
431 curBlock = 0;
432 currChunk = 0;
433 currDword = 0;
434 moreChunks = totalChunks;
435
436 while (moreChunks) {
437 map = HvCallSm_get64BitsOfAccessMap(itLpNaca.xLpIndex,
438 currDword);
439 thisChunk = currChunk;
440 while (map) {
441 chunkBit = map >> 63;
442 map <<= 1;
443 if (chunkBit) {
444 --moreChunks;
445 while (thisChunk >= mb[curBlock].logicalEnd) {
446 ++curBlock;
447 if (curBlock >= numMemoryBlocks)
448 panic("out of memory blocks");
449 }
450 if (thisChunk < mb[curBlock].logicalStart)
451 panic("memory block error");
452
453 absChunk = mb[curBlock].absStart +
454 (thisChunk - mb[curBlock].logicalStart);
455 if (((absChunk < hptFirstChunk) ||
456 (absChunk > hptLastChunk)) &&
457 ((absChunk < loadAreaFirstChunk) ||
458 (absChunk > loadAreaLastChunk))) {
459 mschunks_map.mapping[nextPhysChunk] =
460 absChunk;
461 ++nextPhysChunk;
462 }
463 }
464 ++thisChunk;
465 }
466 ++currDword;
467 currChunk += 64;
468 }
469
470 /*
471 * main store size (in chunks) is
472 * totalChunks - hptSizeChunks
473 * which should be equal to
474 * nextPhysChunk
475 */
476 return chunk_to_addr(nextPhysChunk);
477}
478
479/*
480 * Document me.
481 */
482static void __init iSeries_setup_arch(void)
483{
484 if (get_lppaca()->shared_proc) {
485 ppc_md.idle_loop = iseries_shared_idle;
486 printk(KERN_DEBUG "Using shared processor idle loop\n");
487 } else {
488 ppc_md.idle_loop = iseries_dedicated_idle;
489 printk(KERN_DEBUG "Using dedicated idle loop\n");
490 }
491
492 /* Setup the Lp Event Queue */
493 setup_hvlpevent_queue();
494
495 printk("Max logical processors = %d\n",
496 itVpdAreas.xSlicMaxLogicalProcs);
497 printk("Max physical processors = %d\n",
498 itVpdAreas.xSlicMaxPhysicalProcs);
499
500 iSeries_pcibios_init();
501}
502
503static void iSeries_show_cpuinfo(struct seq_file *m)
504{
505 seq_printf(m, "machine\t\t: 64-bit iSeries Logical Partition\n");
506}
507
508static void __init iSeries_progress(char * st, unsigned short code)
509{
510 printk("Progress: [%04x] - %s\n", (unsigned)code, st);
511 mf_display_progress(code);
512}
513
514static void __init iSeries_fixup_klimit(void)
515{
516 /*
517 * Change klimit to take into account any ram disk
518 * that may be included
519 */
520 if (naca.xRamDisk)
521 klimit = KERNELBASE + (u64)naca.xRamDisk +
522 (naca.xRamDiskSize * HW_PAGE_SIZE);
523}
524
525static int __init iSeries_src_init(void)
526{
527 /* clear the progress line */
528 if (firmware_has_feature(FW_FEATURE_ISERIES))
529 ppc_md.progress(" ", 0xffff);
530 return 0;
531}
532
533late_initcall(iSeries_src_init);
534
535static inline void process_iSeries_events(void)
536{
537 asm volatile ("li 0,0x5555; sc" : : : "r0", "r3");
538}
539
540static void yield_shared_processor(void)
541{
542 unsigned long tb;
543
544 HvCall_setEnabledInterrupts(HvCall_MaskIPI |
545 HvCall_MaskLpEvent |
546 HvCall_MaskLpProd |
547 HvCall_MaskTimeout);
548
549 tb = get_tb();
550 /* Compute future tb value when yield should expire */
551 HvCall_yieldProcessor(HvCall_YieldTimed, tb+tb_ticks_per_jiffy);
552
553 /*
554 * The decrementer stops during the yield. Force a fake decrementer
555 * here and let the timer_interrupt code sort out the actual time.
556 */
557 get_lppaca()->int_dword.fields.decr_int = 1;
558 ppc64_runlatch_on();
559 process_iSeries_events();
560}
561
562static void iseries_shared_idle(void)
563{
564 while (1) {
565 tick_nohz_stop_sched_tick(1);
566 while (!need_resched() && !hvlpevent_is_pending()) {
567 local_irq_disable();
568 ppc64_runlatch_off();
569
570 /* Recheck with irqs off */
571 if (!need_resched() && !hvlpevent_is_pending())
572 yield_shared_processor();
573
574 HMT_medium();
575 local_irq_enable();
576 }
577
578 ppc64_runlatch_on();
579 tick_nohz_restart_sched_tick();
580
581 if (hvlpevent_is_pending())
582 process_iSeries_events();
583
584 preempt_enable_no_resched();
585 schedule();
586 preempt_disable();
587 }
588}
589
590static void iseries_dedicated_idle(void)
591{
592 set_thread_flag(TIF_POLLING_NRFLAG);
593
594 while (1) {
595 tick_nohz_stop_sched_tick(1);
596 if (!need_resched()) {
597 while (!need_resched()) {
598 ppc64_runlatch_off();
599 HMT_low();
600
601 if (hvlpevent_is_pending()) {
602 HMT_medium();
603 ppc64_runlatch_on();
604 process_iSeries_events();
605 }
606 }
607
608 HMT_medium();
609 }
610
611 ppc64_runlatch_on();
612 tick_nohz_restart_sched_tick();
613 preempt_enable_no_resched();
614 schedule();
615 preempt_disable();
616 }
617}
618
619static void __iomem *iseries_ioremap(phys_addr_t address, unsigned long size,
620 unsigned long flags, void *caller)
621{
622 return (void __iomem *)address;
623}
624
625static void iseries_iounmap(volatile void __iomem *token)
626{
627}
628
629static int __init iseries_probe(void)
630{
631 unsigned long root = of_get_flat_dt_root();
632 if (!of_flat_dt_is_compatible(root, "IBM,iSeries"))
633 return 0;
634
635 hpte_init_iSeries();
636 /* iSeries does not support 16M pages */
637 cur_cpu_spec->mmu_features &= ~MMU_FTR_16M_PAGE;
638
639 return 1;
640}
641
642#ifdef CONFIG_KEXEC
643static int iseries_kexec_prepare(struct kimage *image)
644{
645 return -ENOSYS;
646}
647#endif
648
649define_machine(iseries) {
650 .name = "iSeries",
651 .setup_arch = iSeries_setup_arch,
652 .show_cpuinfo = iSeries_show_cpuinfo,
653 .init_IRQ = iSeries_init_IRQ,
654 .get_irq = iSeries_get_irq,
655 .init_early = iSeries_init_early,
656 .pcibios_fixup = iSeries_pci_final_fixup,
657 .pcibios_fixup_resources= iSeries_pcibios_fixup_resources,
658 .restart = mf_reboot,
659 .power_off = mf_power_off,
660 .halt = mf_power_off,
661 .get_boot_time = iSeries_get_boot_time,
662 .set_rtc_time = iSeries_set_rtc_time,
663 .get_rtc_time = iSeries_get_rtc_time,
664 .calibrate_decr = generic_calibrate_decr,
665 .progress = iSeries_progress,
666 .probe = iseries_probe,
667 .ioremap = iseries_ioremap,
668 .iounmap = iseries_iounmap,
669#ifdef CONFIG_KEXEC
670 .machine_kexec_prepare = iseries_kexec_prepare,
671#endif
672 /* XXX Implement enable_pmcs for iSeries */
673};
674
675void * __init iSeries_early_setup(void)
676{
677 unsigned long phys_mem_size;
678
679 /* Identify CPU type. This is done again by the common code later
680 * on but calling this function multiple times is fine.
681 */
682 identify_cpu(0, mfspr(SPRN_PVR));
683 initialise_paca(&boot_paca, 0);
684
685 powerpc_firmware_features |= FW_FEATURE_ISERIES;
686 powerpc_firmware_features |= FW_FEATURE_LPAR;
687
688#ifdef CONFIG_SMP
689 /* On iSeries we know we can never have more than 64 cpus */
690 nr_cpu_ids = max(nr_cpu_ids, 64);
691#endif
692
693 iSeries_fixup_klimit();
694
695 /*
696 * Initialize the table which translate Linux physical addresses to
697 * AS/400 absolute addresses
698 */
699 phys_mem_size = build_iSeries_Memory_Map();
700
701 iSeries_get_cmdline();
702
703 return (void *) __pa(build_flat_dt(phys_mem_size));
704}
705
706static void hvputc(char c)
707{
708 if (c == '\n')
709 hvputc('\r');
710
711 HvCall_writeLogBuffer(&c, 1);
712}
713
714void __init udbg_init_iseries(void)
715{
716 udbg_putc = hvputc;
717}
diff --git a/arch/powerpc/platforms/iseries/setup.h b/arch/powerpc/platforms/iseries/setup.h
new file mode 100644
index 00000000000..729754bbb01
--- /dev/null
+++ b/arch/powerpc/platforms/iseries/setup.h
@@ -0,0 +1,27 @@
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
20extern void *iSeries_early_setup(void);
21extern unsigned long iSeries_get_boot_time(void);
22extern int iSeries_set_rtc_time(struct rtc_time *tm);
23extern void iSeries_get_rtc_time(struct rtc_time *tm);
24
25extern 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
new file mode 100644
index 00000000000..8bda9be06fa
--- /dev/null
+++ b/arch/powerpc/platforms/iseries/smp.c
@@ -0,0 +1,89 @@
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/module.h>
19#include <linux/sched.h>
20#include <linux/smp.h>
21#include <linux/interrupt.h>
22#include <linux/kernel_stat.h>
23#include <linux/delay.h>
24#include <linux/init.h>
25#include <linux/spinlock.h>
26#include <linux/cache.h>
27#include <linux/err.h>
28#include <linux/sysdev.h>
29#include <linux/cpu.h>
30
31#include <asm/ptrace.h>
32#include <linux/atomic.h>
33#include <asm/irq.h>
34#include <asm/page.h>
35#include <asm/pgtable.h>
36#include <asm/io.h>
37#include <asm/smp.h>
38#include <asm/paca.h>
39#include <asm/iseries/hv_call.h>
40#include <asm/time.h>
41#include <asm/machdep.h>
42#include <asm/cputable.h>
43#include <asm/system.h>
44
45static void smp_iSeries_cause_ipi(int cpu, unsigned long data)
46{
47 HvCall_sendIPI(&(paca[cpu]));
48}
49
50static int smp_iSeries_probe(void)
51{
52 return cpumask_weight(cpu_possible_mask);
53}
54
55static int smp_iSeries_kick_cpu(int nr)
56{
57 BUG_ON((nr < 0) || (nr >= NR_CPUS));
58
59 /* Verify that our partition has a processor nr */
60 if (lppaca_of(nr).dyn_proc_status >= 2)
61 return -ENOENT;
62
63 /* The processor is currently spinning, waiting
64 * for the cpu_start field to become non-zero
65 * After we set cpu_start, the processor will
66 * continue on to secondary_start in iSeries_head.S
67 */
68 paca[nr].cpu_start = 1;
69
70 return 0;
71}
72
73static void __devinit smp_iSeries_setup_cpu(int nr)
74{
75}
76
77static struct smp_ops_t iSeries_smp_ops = {
78 .message_pass = NULL, /* Use smp_muxed_ipi_message_pass */
79 .cause_ipi = smp_iSeries_cause_ipi,
80 .probe = smp_iSeries_probe,
81 .kick_cpu = smp_iSeries_kick_cpu,
82 .setup_cpu = smp_iSeries_setup_cpu,
83};
84
85/* This is called very early. */
86void __init smp_init_iSeries(void)
87{
88 smp_ops = &iSeries_smp_ops;
89}
diff --git a/arch/powerpc/platforms/iseries/spcomm_area.h b/arch/powerpc/platforms/iseries/spcomm_area.h
new file mode 100644
index 00000000000..598b7c14573
--- /dev/null
+++ b/arch/powerpc/platforms/iseries/spcomm_area.h
@@ -0,0 +1,34 @@
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
23struct 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
new file mode 100644
index 00000000000..b6db7cef83b
--- /dev/null
+++ b/arch/powerpc/platforms/iseries/vio.c
@@ -0,0 +1,556 @@
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/module.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
50struct vio_waitevent {
51 struct completion com;
52 int rc;
53 u16 sub_result;
54};
55
56struct vio_resource {
57 char rsrcname[10];
58 char type[4];
59 char model[3];
60};
61
62static 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
78static void free_property(struct property *np)
79{
80 kfree(np);
81}
82
83static 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
101static 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
117static 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
128static 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
139static 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), &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 */
190struct 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}
209EXPORT_SYMBOL_GPL(vio_create_viodasd);
210
211static 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
256static 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
262retry:
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
311static 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
334static 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
374static 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 */
446static 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
466static 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
524static 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}
556arch_initcall(iseries_vio_init);
diff --git a/arch/powerpc/platforms/iseries/viopath.c b/arch/powerpc/platforms/iseries/viopath.c
new file mode 100644
index 00000000000..2376069cdc1
--- /dev/null
+++ b/arch/powerpc/platforms/iseries/viopath.c
@@ -0,0 +1,677 @@
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/module.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 */
58static 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
67static 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 */
73static unsigned char event_buffer[VIO_MAX_SUBTYPES * 256]
74 __attribute__((__aligned__(4096)));
75static atomic_t event_buffer_available[VIO_MAX_SUBTYPES];
76static int event_buffer_initialised;
77
78static 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 */
85struct 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 */
96static u8 viomonseq = 22;
97
98/* Our hosting logical partition. We get this at startup
99 * time, and different modules access this variable directly.
100 */
101HvLpIndex viopath_hostLp = HvLpIndexInvalid;
102EXPORT_SYMBOL(viopath_hostLp);
103HvLpIndex viopath_ourLp = HvLpIndexInvalid;
104EXPORT_SYMBOL(viopath_ourLp);
105
106/* For each kind of incoming event we set a pointer to a
107 * routine to call.
108 */
109static 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
114static 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
170static int proc_viopath_open(struct inode *inode, struct file *file)
171{
172 return single_open(file, proc_viopath_show, NULL);
173}
174
175static 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
182static 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 */
195int 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}
204EXPORT_SYMBOL(viopath_isactive);
205
206/*
207 * We cache the source and target instance ids for each
208 * partition.
209 */
210HvLpInstanceId viopath_sourceinst(HvLpIndex lp)
211{
212 return viopathStatus[lp].mSourceInst;
213}
214EXPORT_SYMBOL(viopath_sourceinst);
215
216HvLpInstanceId viopath_targetinst(HvLpIndex lp)
217{
218 return viopathStatus[lp].mTargetInst;
219}
220EXPORT_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 */
228static 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
261static 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
311int 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}
321EXPORT_SYMBOL(vio_setHandler);
322
323int 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}
333EXPORT_SYMBOL(vio_clearHandler);
334
335static 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 */
357void 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}
376EXPORT_SYMBOL(vio_set_hostlp);
377
378static 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
454static 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
465static 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
486int 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}
554EXPORT_SYMBOL(viopath_open);
555
556int 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}
608EXPORT_SYMBOL(viopath_close);
609
610void *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}
621EXPORT_SYMBOL(vio_get_event_buffer);
622
623void 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}
646EXPORT_SYMBOL(vio_free_event_buffer);
647
648static const struct vio_error_entry vio_no_error =
649 { 0, 0, "Non-VIO Error" };
650static const struct vio_error_entry vio_unknown_error =
651 { 0, EIO, "Unknown Error" };
652
653static 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
661const 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}
677EXPORT_SYMBOL(vio_lookup_rc);
diff --git a/arch/powerpc/platforms/iseries/vpd_areas.h b/arch/powerpc/platforms/iseries/vpd_areas.h
new file mode 100644
index 00000000000..feb001f3a5f
--- /dev/null
+++ b/arch/powerpc/platforms/iseries/vpd_areas.h
@@ -0,0 +1,88 @@
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
63struct 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
86extern const struct ItVpdAreas itVpdAreas;
87
88#endif /* _ISERIES_VPD_AREAS_H */
diff --git a/arch/powerpc/platforms/pseries/phyp_dump.c b/arch/powerpc/platforms/pseries/phyp_dump.c
new file mode 100644
index 00000000000..6e7742da007
--- /dev/null
+++ b/arch/powerpc/platforms/pseries/phyp_dump.c
@@ -0,0 +1,513 @@
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 */
30static struct phyp_dump phyp_dump_vars;
31struct phyp_dump *phyp_dump_info = &phyp_dump_vars;
32
33static int ibm_configure_kernel_dump;
34/* ------------------------------------------------- */
35/* RTAS interfaces to declare the dump regions */
36
37struct 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
47struct 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 */
66static 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 */
87static 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
131static 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
189static 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
197static struct kobj_attribute pdl = __ATTR(phyp_dump_active, 0600,
198 show_phyp_dump_active,
199 NULL);
200
201static 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
232static
233void 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 */
266static 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 */
291static void
292track_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 */
331static 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
363static 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
383static struct kobj_attribute rr = __ATTR(release_region, 0600,
384 show_release_region,
385 store_release_region);
386
387static 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}
455machine_subsys_initcall(pseries, phyp_dump_setup);
456
457int __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 */
489static 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}
503early_param("phyp_dump", early_phyp_dump_enabled);
504
505/* Look for phyp_dump_reserve_size= cmdline option */
506static 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}
513early_param("phyp_dump_reserve_size", early_phyp_dump_reserve_size);
diff --git a/arch/powerpc/sysdev/mpc8xxx_gpio.c b/arch/powerpc/sysdev/mpc8xxx_gpio.c
new file mode 100644
index 00000000000..fb4963abdf5
--- /dev/null
+++ b/arch/powerpc/sysdev/mpc8xxx_gpio.c
@@ -0,0 +1,395 @@
1/*
2 * GPIOs on MPC512x/8349/8572/8610 and compatible
3 *
4 * Copyright (C) 2008 Peter Korsgaard <jacmet@sunsite.dk>
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 <linux/kernel.h>
12#include <linux/init.h>
13#include <linux/spinlock.h>
14#include <linux/io.h>
15#include <linux/of.h>
16#include <linux/of_gpio.h>
17#include <linux/gpio.h>
18#include <linux/slab.h>
19#include <linux/irq.h>
20
21#define MPC8XXX_GPIO_PINS 32
22
23#define GPIO_DIR 0x00
24#define GPIO_ODR 0x04
25#define GPIO_DAT 0x08
26#define GPIO_IER 0x0c
27#define GPIO_IMR 0x10
28#define GPIO_ICR 0x14
29#define GPIO_ICR2 0x18
30
31struct mpc8xxx_gpio_chip {
32 struct of_mm_gpio_chip mm_gc;
33 spinlock_t lock;
34
35 /*
36 * shadowed data register to be able to clear/set output pins in
37 * open drain mode safely
38 */
39 u32 data;
40 struct irq_host *irq;
41 void *of_dev_id_data;
42};
43
44static inline u32 mpc8xxx_gpio2mask(unsigned int gpio)
45{
46 return 1u << (MPC8XXX_GPIO_PINS - 1 - gpio);
47}
48
49static inline struct mpc8xxx_gpio_chip *
50to_mpc8xxx_gpio_chip(struct of_mm_gpio_chip *mm)
51{
52 return container_of(mm, struct mpc8xxx_gpio_chip, mm_gc);
53}
54
55static void mpc8xxx_gpio_save_regs(struct of_mm_gpio_chip *mm)
56{
57 struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
58
59 mpc8xxx_gc->data = in_be32(mm->regs + GPIO_DAT);
60}
61
62/* Workaround GPIO 1 errata on MPC8572/MPC8536. The status of GPIOs
63 * defined as output cannot be determined by reading GPDAT register,
64 * so we use shadow data register instead. The status of input pins
65 * is determined by reading GPDAT register.
66 */
67static int mpc8572_gpio_get(struct gpio_chip *gc, unsigned int gpio)
68{
69 u32 val;
70 struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
71 struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
72
73 val = in_be32(mm->regs + GPIO_DAT) & ~in_be32(mm->regs + GPIO_DIR);
74
75 return (val | mpc8xxx_gc->data) & mpc8xxx_gpio2mask(gpio);
76}
77
78static int mpc8xxx_gpio_get(struct gpio_chip *gc, unsigned int gpio)
79{
80 struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
81
82 return in_be32(mm->regs + GPIO_DAT) & mpc8xxx_gpio2mask(gpio);
83}
84
85static void mpc8xxx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
86{
87 struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
88 struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
89 unsigned long flags;
90
91 spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
92
93 if (val)
94 mpc8xxx_gc->data |= mpc8xxx_gpio2mask(gpio);
95 else
96 mpc8xxx_gc->data &= ~mpc8xxx_gpio2mask(gpio);
97
98 out_be32(mm->regs + GPIO_DAT, mpc8xxx_gc->data);
99
100 spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
101}
102
103static int mpc8xxx_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
104{
105 struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
106 struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
107 unsigned long flags;
108
109 spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
110
111 clrbits32(mm->regs + GPIO_DIR, mpc8xxx_gpio2mask(gpio));
112
113 spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
114
115 return 0;
116}
117
118static int mpc8xxx_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
119{
120 struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
121 struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
122 unsigned long flags;
123
124 mpc8xxx_gpio_set(gc, gpio, val);
125
126 spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
127
128 setbits32(mm->regs + GPIO_DIR, mpc8xxx_gpio2mask(gpio));
129
130 spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
131
132 return 0;
133}
134
135static int mpc8xxx_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
136{
137 struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);
138 struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);
139
140 if (mpc8xxx_gc->irq && offset < MPC8XXX_GPIO_PINS)
141 return irq_create_mapping(mpc8xxx_gc->irq, offset);
142 else
143 return -ENXIO;
144}
145
146static void mpc8xxx_gpio_irq_cascade(unsigned int irq, struct irq_desc *desc)
147{
148 struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_desc_get_handler_data(desc);
149 struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc;
150 unsigned int mask;
151
152 mask = in_be32(mm->regs + GPIO_IER) & in_be32(mm->regs + GPIO_IMR);
153 if (mask)
154 generic_handle_irq(irq_linear_revmap(mpc8xxx_gc->irq,
155 32 - ffs(mask)));
156}
157
158static void mpc8xxx_irq_unmask(struct irq_data *d)
159{
160 struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d);
161 struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc;
162 unsigned long flags;
163
164 spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
165
166 setbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(irqd_to_hwirq(d)));
167
168 spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
169}
170
171static void mpc8xxx_irq_mask(struct irq_data *d)
172{
173 struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d);
174 struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc;
175 unsigned long flags;
176
177 spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
178
179 clrbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(irqd_to_hwirq(d)));
180
181 spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
182}
183
184static void mpc8xxx_irq_ack(struct irq_data *d)
185{
186 struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d);
187 struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc;
188
189 out_be32(mm->regs + GPIO_IER, mpc8xxx_gpio2mask(irqd_to_hwirq(d)));
190}
191
192static int mpc8xxx_irq_set_type(struct irq_data *d, unsigned int flow_type)
193{
194 struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d);
195 struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc;
196 unsigned long flags;
197
198 switch (flow_type) {
199 case IRQ_TYPE_EDGE_FALLING:
200 spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
201 setbits32(mm->regs + GPIO_ICR,
202 mpc8xxx_gpio2mask(irqd_to_hwirq(d)));
203 spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
204 break;
205
206 case IRQ_TYPE_EDGE_BOTH:
207 spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
208 clrbits32(mm->regs + GPIO_ICR,
209 mpc8xxx_gpio2mask(irqd_to_hwirq(d)));
210 spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
211 break;
212
213 default:
214 return -EINVAL;
215 }
216
217 return 0;
218}
219
220static int mpc512x_irq_set_type(struct irq_data *d, unsigned int flow_type)
221{
222 struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d);
223 struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc;
224 unsigned long gpio = irqd_to_hwirq(d);
225 void __iomem *reg;
226 unsigned int shift;
227 unsigned long flags;
228
229 if (gpio < 16) {
230 reg = mm->regs + GPIO_ICR;
231 shift = (15 - gpio) * 2;
232 } else {
233 reg = mm->regs + GPIO_ICR2;
234 shift = (15 - (gpio % 16)) * 2;
235 }
236
237 switch (flow_type) {
238 case IRQ_TYPE_EDGE_FALLING:
239 case IRQ_TYPE_LEVEL_LOW:
240 spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
241 clrsetbits_be32(reg, 3 << shift, 2 << shift);
242 spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
243 break;
244
245 case IRQ_TYPE_EDGE_RISING:
246 case IRQ_TYPE_LEVEL_HIGH:
247 spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
248 clrsetbits_be32(reg, 3 << shift, 1 << shift);
249 spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
250 break;
251
252 case IRQ_TYPE_EDGE_BOTH:
253 spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
254 clrbits32(reg, 3 << shift);
255 spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
256 break;
257
258 default:
259 return -EINVAL;
260 }
261
262 return 0;
263}
264
265static struct irq_chip mpc8xxx_irq_chip = {
266 .name = "mpc8xxx-gpio",
267 .irq_unmask = mpc8xxx_irq_unmask,
268 .irq_mask = mpc8xxx_irq_mask,
269 .irq_ack = mpc8xxx_irq_ack,
270 .irq_set_type = mpc8xxx_irq_set_type,
271};
272
273static int mpc8xxx_gpio_irq_map(struct irq_host *h, unsigned int virq,
274 irq_hw_number_t hw)
275{
276 struct mpc8xxx_gpio_chip *mpc8xxx_gc = h->host_data;
277
278 if (mpc8xxx_gc->of_dev_id_data)
279 mpc8xxx_irq_chip.irq_set_type = mpc8xxx_gc->of_dev_id_data;
280
281 irq_set_chip_data(virq, h->host_data);
282 irq_set_chip_and_handler(virq, &mpc8xxx_irq_chip, handle_level_irq);
283 irq_set_irq_type(virq, IRQ_TYPE_NONE);
284
285 return 0;
286}
287
288static int mpc8xxx_gpio_irq_xlate(struct irq_host *h, struct device_node *ct,
289 const u32 *intspec, unsigned int intsize,
290 irq_hw_number_t *out_hwirq,
291 unsigned int *out_flags)
292
293{
294 /* interrupt sense values coming from the device tree equal either
295 * EDGE_FALLING or EDGE_BOTH
296 */
297 *out_hwirq = intspec[0];
298 *out_flags = intspec[1];
299
300 return 0;
301}
302
303static struct irq_host_ops mpc8xxx_gpio_irq_ops = {
304 .map = mpc8xxx_gpio_irq_map,
305 .xlate = mpc8xxx_gpio_irq_xlate,
306};
307
308static struct of_device_id mpc8xxx_gpio_ids[] __initdata = {
309 { .compatible = "fsl,mpc8349-gpio", },
310 { .compatible = "fsl,mpc8572-gpio", },
311 { .compatible = "fsl,mpc8610-gpio", },
312 { .compatible = "fsl,mpc5121-gpio", .data = mpc512x_irq_set_type, },
313 { .compatible = "fsl,qoriq-gpio", },
314 {}
315};
316
317static void __init mpc8xxx_add_controller(struct device_node *np)
318{
319 struct mpc8xxx_gpio_chip *mpc8xxx_gc;
320 struct of_mm_gpio_chip *mm_gc;
321 struct gpio_chip *gc;
322 const struct of_device_id *id;
323 unsigned hwirq;
324 int ret;
325
326 mpc8xxx_gc = kzalloc(sizeof(*mpc8xxx_gc), GFP_KERNEL);
327 if (!mpc8xxx_gc) {
328 ret = -ENOMEM;
329 goto err;
330 }
331
332 spin_lock_init(&mpc8xxx_gc->lock);
333
334 mm_gc = &mpc8xxx_gc->mm_gc;
335 gc = &mm_gc->gc;
336
337 mm_gc->save_regs = mpc8xxx_gpio_save_regs;
338 gc->ngpio = MPC8XXX_GPIO_PINS;
339 gc->direction_input = mpc8xxx_gpio_dir_in;
340 gc->direction_output = mpc8xxx_gpio_dir_out;
341 if (of_device_is_compatible(np, "fsl,mpc8572-gpio"))
342 gc->get = mpc8572_gpio_get;
343 else
344 gc->get = mpc8xxx_gpio_get;
345 gc->set = mpc8xxx_gpio_set;
346 gc->to_irq = mpc8xxx_gpio_to_irq;
347
348 ret = of_mm_gpiochip_add(np, mm_gc);
349 if (ret)
350 goto err;
351
352 hwirq = irq_of_parse_and_map(np, 0);
353 if (hwirq == NO_IRQ)
354 goto skip_irq;
355
356 mpc8xxx_gc->irq =
357 irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, MPC8XXX_GPIO_PINS,
358 &mpc8xxx_gpio_irq_ops, MPC8XXX_GPIO_PINS);
359 if (!mpc8xxx_gc->irq)
360 goto skip_irq;
361
362 id = of_match_node(mpc8xxx_gpio_ids, np);
363 if (id)
364 mpc8xxx_gc->of_dev_id_data = id->data;
365
366 mpc8xxx_gc->irq->host_data = mpc8xxx_gc;
367
368 /* ack and mask all irqs */
369 out_be32(mm_gc->regs + GPIO_IER, 0xffffffff);
370 out_be32(mm_gc->regs + GPIO_IMR, 0);
371
372 irq_set_handler_data(hwirq, mpc8xxx_gc);
373 irq_set_chained_handler(hwirq, mpc8xxx_gpio_irq_cascade);
374
375skip_irq:
376 return;
377
378err:
379 pr_err("%s: registration failed with status %d\n",
380 np->full_name, ret);
381 kfree(mpc8xxx_gc);
382
383 return;
384}
385
386static int __init mpc8xxx_add_gpiochips(void)
387{
388 struct device_node *np;
389
390 for_each_matching_node(np, mpc8xxx_gpio_ids)
391 mpc8xxx_add_controller(np);
392
393 return 0;
394}
395arch_initcall(mpc8xxx_add_gpiochips);
diff --git a/arch/powerpc/xmon/start.c b/arch/powerpc/xmon/start.c
new file mode 100644
index 00000000000..8864de2af38
--- /dev/null
+++ b/arch/powerpc/xmon/start.c
@@ -0,0 +1,34 @@
1/*
2 * Copyright (C) 1996 Paul Mackerras.
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 <asm/machdep.h>
10#include <asm/udbg.h>
11#include "nonstdio.h"
12
13void xmon_map_scc(void)
14{
15}
16
17int xmon_write(const void *ptr, int nb)
18{
19 return udbg_write(ptr, nb);
20}
21
22int xmon_readchar(void)
23{
24 if (udbg_getc)
25 return udbg_getc();
26 return -1;
27}
28
29int xmon_read_poll(void)
30{
31 if (udbg_getc_poll)
32 return udbg_getc_poll();
33 return -1;
34}