diff options
author | Linus Torvalds <torvalds@g5.osdl.org> | 2005-08-29 20:11:29 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-08-29 20:11:29 -0400 |
commit | 40193713df2cdb9c233b3fc2029ecdccb40cb1e4 (patch) | |
tree | db2ce73665b250672f5f5c0cf7544ec370c122f9 /arch/ppc64/kernel | |
parent | 8f3d17fb7bcb7c255197d11469fb5e9695c9d2f4 (diff) | |
parent | c594adad5653491813959277fb87a2fef54c4e05 (diff) |
Merge HEAD from master.kernel.org:/pub/scm/linux/kernel/git/paulus/ppc64-2.6
Diffstat (limited to 'arch/ppc64/kernel')
28 files changed, 1177 insertions, 1044 deletions
diff --git a/arch/ppc64/kernel/LparData.c b/arch/ppc64/kernel/LparData.c index 1c11031c838e..0a9c23ca2f0c 100644 --- a/arch/ppc64/kernel/LparData.c +++ b/arch/ppc64/kernel/LparData.c | |||
@@ -51,6 +51,17 @@ struct HvReleaseData hvReleaseData = { | |||
51 | 0xf4, 0x4b, 0xf6, 0xf4 }, | 51 | 0xf4, 0x4b, 0xf6, 0xf4 }, |
52 | }; | 52 | }; |
53 | 53 | ||
54 | /* | ||
55 | * The NACA. The first dword of the naca is required by the iSeries | ||
56 | * hypervisor to point to itVpdAreas. The hypervisor finds the NACA | ||
57 | * through the pointer in hvReleaseData. | ||
58 | */ | ||
59 | struct naca_struct naca = { | ||
60 | .xItVpdAreas = &itVpdAreas, | ||
61 | .xRamDisk = 0, | ||
62 | .xRamDiskSize = 0, | ||
63 | }; | ||
64 | |||
54 | extern void system_reset_iSeries(void); | 65 | extern void system_reset_iSeries(void); |
55 | extern void machine_check_iSeries(void); | 66 | extern void machine_check_iSeries(void); |
56 | extern void data_access_iSeries(void); | 67 | extern void data_access_iSeries(void); |
@@ -214,29 +225,3 @@ struct ItVpdAreas itVpdAreas = { | |||
214 | 0,0 | 225 | 0,0 |
215 | } | 226 | } |
216 | }; | 227 | }; |
217 | |||
218 | struct msChunks msChunks; | ||
219 | EXPORT_SYMBOL(msChunks); | ||
220 | |||
221 | /* Depending on whether this is called from iSeries or pSeries setup | ||
222 | * code, the location of the msChunks struct may or may not have | ||
223 | * to be reloc'd, so we force the caller to do that for us by passing | ||
224 | * in a pointer to the structure. | ||
225 | */ | ||
226 | unsigned long | ||
227 | msChunks_alloc(unsigned long mem, unsigned long num_chunks, unsigned long chunk_size) | ||
228 | { | ||
229 | unsigned long offset = reloc_offset(); | ||
230 | struct msChunks *_msChunks = PTRRELOC(&msChunks); | ||
231 | |||
232 | _msChunks->num_chunks = num_chunks; | ||
233 | _msChunks->chunk_size = chunk_size; | ||
234 | _msChunks->chunk_shift = __ilog2(chunk_size); | ||
235 | _msChunks->chunk_mask = (1UL<<_msChunks->chunk_shift)-1; | ||
236 | |||
237 | mem = _ALIGN(mem, sizeof(msChunks_entry)); | ||
238 | _msChunks->abs = (msChunks_entry *)(mem + offset); | ||
239 | mem += num_chunks * sizeof(msChunks_entry); | ||
240 | |||
241 | return mem; | ||
242 | } | ||
diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index 2ecccb6b4f8c..f4b3bfcc109d 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile | |||
@@ -11,7 +11,7 @@ obj-y := setup.o entry.o traps.o irq.o idle.o dma.o \ | |||
11 | udbg.o binfmt_elf32.o sys_ppc32.o ioctl32.o \ | 11 | udbg.o binfmt_elf32.o sys_ppc32.o ioctl32.o \ |
12 | ptrace32.o signal32.o rtc.o init_task.o \ | 12 | ptrace32.o signal32.o rtc.o init_task.o \ |
13 | lmb.o cputable.o cpu_setup_power4.o idle_power4.o \ | 13 | lmb.o cputable.o cpu_setup_power4.o idle_power4.o \ |
14 | iommu.o sysfs.o vdso.o pmc.o | 14 | iommu.o sysfs.o vdso.o pmc.o firmware.o |
15 | obj-y += vdso32/ vdso64/ | 15 | obj-y += vdso32/ vdso64/ |
16 | 16 | ||
17 | obj-$(CONFIG_PPC_OF) += of_device.o | 17 | obj-$(CONFIG_PPC_OF) += of_device.o |
@@ -50,7 +50,10 @@ obj-$(CONFIG_LPARCFG) += lparcfg.o | |||
50 | obj-$(CONFIG_HVC_CONSOLE) += hvconsole.o | 50 | obj-$(CONFIG_HVC_CONSOLE) += hvconsole.o |
51 | obj-$(CONFIG_BOOTX_TEXT) += btext.o | 51 | obj-$(CONFIG_BOOTX_TEXT) += btext.o |
52 | obj-$(CONFIG_HVCS) += hvcserver.o | 52 | obj-$(CONFIG_HVCS) += hvcserver.o |
53 | obj-$(CONFIG_IBMVIO) += vio.o | 53 | |
54 | vio-obj-$(CONFIG_PPC_PSERIES) += pSeries_vio.o | ||
55 | vio-obj-$(CONFIG_PPC_ISERIES) += iSeries_vio.o | ||
56 | obj-$(CONFIG_IBMVIO) += vio.o $(vio-obj-y) | ||
54 | obj-$(CONFIG_XICS) += xics.o | 57 | obj-$(CONFIG_XICS) += xics.o |
55 | obj-$(CONFIG_MPIC) += mpic.o | 58 | obj-$(CONFIG_MPIC) += mpic.o |
56 | 59 | ||
diff --git a/arch/ppc64/kernel/asm-offsets.c b/arch/ppc64/kernel/asm-offsets.c index abb9e5b5da03..17e35d0fed09 100644 --- a/arch/ppc64/kernel/asm-offsets.c +++ b/arch/ppc64/kernel/asm-offsets.c | |||
@@ -94,7 +94,8 @@ int main(void) | |||
94 | DEFINE(PACASLBCACHEPTR, offsetof(struct paca_struct, slb_cache_ptr)); | 94 | DEFINE(PACASLBCACHEPTR, offsetof(struct paca_struct, slb_cache_ptr)); |
95 | DEFINE(PACACONTEXTID, offsetof(struct paca_struct, context.id)); | 95 | DEFINE(PACACONTEXTID, offsetof(struct paca_struct, context.id)); |
96 | #ifdef CONFIG_HUGETLB_PAGE | 96 | #ifdef CONFIG_HUGETLB_PAGE |
97 | DEFINE(PACAHTLBSEGS, offsetof(struct paca_struct, context.htlb_segs)); | 97 | DEFINE(PACALOWHTLBAREAS, offsetof(struct paca_struct, context.low_htlb_areas)); |
98 | DEFINE(PACAHIGHHTLBAREAS, offsetof(struct paca_struct, context.high_htlb_areas)); | ||
98 | #endif /* CONFIG_HUGETLB_PAGE */ | 99 | #endif /* CONFIG_HUGETLB_PAGE */ |
99 | DEFINE(PACADEFAULTDECR, offsetof(struct paca_struct, default_decr)); | 100 | DEFINE(PACADEFAULTDECR, offsetof(struct paca_struct, default_decr)); |
100 | DEFINE(PACA_EXGEN, offsetof(struct paca_struct, exgen)); | 101 | DEFINE(PACA_EXGEN, offsetof(struct paca_struct, exgen)); |
diff --git a/arch/ppc64/kernel/cputable.c b/arch/ppc64/kernel/cputable.c index 77cec42f9525..4847f2ac8c9f 100644 --- a/arch/ppc64/kernel/cputable.c +++ b/arch/ppc64/kernel/cputable.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * Modifications for ppc64: | 6 | * Modifications for ppc64: |
7 | * Copyright (C) 2003 Dave Engebretsen <engebret@us.ibm.com> | 7 | * Copyright (C) 2003 Dave Engebretsen <engebret@us.ibm.com> |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or | 9 | * This program is free software; you can redistribute it and/or |
10 | * modify it under the terms of the GNU General Public License | 10 | * modify it under the terms of the GNU General Public License |
11 | * as published by the Free Software Foundation; either version | 11 | * as published by the Free Software Foundation; either version |
@@ -60,7 +60,6 @@ struct cpu_spec cpu_specs[] = { | |||
60 | .icache_bsize = 128, | 60 | .icache_bsize = 128, |
61 | .dcache_bsize = 128, | 61 | .dcache_bsize = 128, |
62 | .cpu_setup = __setup_cpu_power3, | 62 | .cpu_setup = __setup_cpu_power3, |
63 | .firmware_features = COMMON_PPC64_FW, | ||
64 | }, | 63 | }, |
65 | { /* Power3+ */ | 64 | { /* Power3+ */ |
66 | .pvr_mask = 0xffff0000, | 65 | .pvr_mask = 0xffff0000, |
@@ -73,7 +72,6 @@ struct cpu_spec cpu_specs[] = { | |||
73 | .icache_bsize = 128, | 72 | .icache_bsize = 128, |
74 | .dcache_bsize = 128, | 73 | .dcache_bsize = 128, |
75 | .cpu_setup = __setup_cpu_power3, | 74 | .cpu_setup = __setup_cpu_power3, |
76 | .firmware_features = COMMON_PPC64_FW, | ||
77 | }, | 75 | }, |
78 | { /* Northstar */ | 76 | { /* Northstar */ |
79 | .pvr_mask = 0xffff0000, | 77 | .pvr_mask = 0xffff0000, |
@@ -86,7 +84,6 @@ struct cpu_spec cpu_specs[] = { | |||
86 | .icache_bsize = 128, | 84 | .icache_bsize = 128, |
87 | .dcache_bsize = 128, | 85 | .dcache_bsize = 128, |
88 | .cpu_setup = __setup_cpu_power3, | 86 | .cpu_setup = __setup_cpu_power3, |
89 | .firmware_features = COMMON_PPC64_FW, | ||
90 | }, | 87 | }, |
91 | { /* Pulsar */ | 88 | { /* Pulsar */ |
92 | .pvr_mask = 0xffff0000, | 89 | .pvr_mask = 0xffff0000, |
@@ -99,7 +96,6 @@ struct cpu_spec cpu_specs[] = { | |||
99 | .icache_bsize = 128, | 96 | .icache_bsize = 128, |
100 | .dcache_bsize = 128, | 97 | .dcache_bsize = 128, |
101 | .cpu_setup = __setup_cpu_power3, | 98 | .cpu_setup = __setup_cpu_power3, |
102 | .firmware_features = COMMON_PPC64_FW, | ||
103 | }, | 99 | }, |
104 | { /* I-star */ | 100 | { /* I-star */ |
105 | .pvr_mask = 0xffff0000, | 101 | .pvr_mask = 0xffff0000, |
@@ -112,7 +108,6 @@ struct cpu_spec cpu_specs[] = { | |||
112 | .icache_bsize = 128, | 108 | .icache_bsize = 128, |
113 | .dcache_bsize = 128, | 109 | .dcache_bsize = 128, |
114 | .cpu_setup = __setup_cpu_power3, | 110 | .cpu_setup = __setup_cpu_power3, |
115 | .firmware_features = COMMON_PPC64_FW, | ||
116 | }, | 111 | }, |
117 | { /* S-star */ | 112 | { /* S-star */ |
118 | .pvr_mask = 0xffff0000, | 113 | .pvr_mask = 0xffff0000, |
@@ -125,7 +120,6 @@ struct cpu_spec cpu_specs[] = { | |||
125 | .icache_bsize = 128, | 120 | .icache_bsize = 128, |
126 | .dcache_bsize = 128, | 121 | .dcache_bsize = 128, |
127 | .cpu_setup = __setup_cpu_power3, | 122 | .cpu_setup = __setup_cpu_power3, |
128 | .firmware_features = COMMON_PPC64_FW, | ||
129 | }, | 123 | }, |
130 | { /* Power4 */ | 124 | { /* Power4 */ |
131 | .pvr_mask = 0xffff0000, | 125 | .pvr_mask = 0xffff0000, |
@@ -138,7 +132,6 @@ struct cpu_spec cpu_specs[] = { | |||
138 | .icache_bsize = 128, | 132 | .icache_bsize = 128, |
139 | .dcache_bsize = 128, | 133 | .dcache_bsize = 128, |
140 | .cpu_setup = __setup_cpu_power4, | 134 | .cpu_setup = __setup_cpu_power4, |
141 | .firmware_features = COMMON_PPC64_FW, | ||
142 | }, | 135 | }, |
143 | { /* Power4+ */ | 136 | { /* Power4+ */ |
144 | .pvr_mask = 0xffff0000, | 137 | .pvr_mask = 0xffff0000, |
@@ -151,7 +144,6 @@ struct cpu_spec cpu_specs[] = { | |||
151 | .icache_bsize = 128, | 144 | .icache_bsize = 128, |
152 | .dcache_bsize = 128, | 145 | .dcache_bsize = 128, |
153 | .cpu_setup = __setup_cpu_power4, | 146 | .cpu_setup = __setup_cpu_power4, |
154 | .firmware_features = COMMON_PPC64_FW, | ||
155 | }, | 147 | }, |
156 | { /* PPC970 */ | 148 | { /* PPC970 */ |
157 | .pvr_mask = 0xffff0000, | 149 | .pvr_mask = 0xffff0000, |
@@ -166,7 +158,6 @@ struct cpu_spec cpu_specs[] = { | |||
166 | .icache_bsize = 128, | 158 | .icache_bsize = 128, |
167 | .dcache_bsize = 128, | 159 | .dcache_bsize = 128, |
168 | .cpu_setup = __setup_cpu_ppc970, | 160 | .cpu_setup = __setup_cpu_ppc970, |
169 | .firmware_features = COMMON_PPC64_FW, | ||
170 | }, | 161 | }, |
171 | { /* PPC970FX */ | 162 | { /* PPC970FX */ |
172 | .pvr_mask = 0xffff0000, | 163 | .pvr_mask = 0xffff0000, |
@@ -181,7 +172,6 @@ struct cpu_spec cpu_specs[] = { | |||
181 | .icache_bsize = 128, | 172 | .icache_bsize = 128, |
182 | .dcache_bsize = 128, | 173 | .dcache_bsize = 128, |
183 | .cpu_setup = __setup_cpu_ppc970, | 174 | .cpu_setup = __setup_cpu_ppc970, |
184 | .firmware_features = COMMON_PPC64_FW, | ||
185 | }, | 175 | }, |
186 | { /* PPC970MP */ | 176 | { /* PPC970MP */ |
187 | .pvr_mask = 0xffff0000, | 177 | .pvr_mask = 0xffff0000, |
@@ -196,7 +186,6 @@ struct cpu_spec cpu_specs[] = { | |||
196 | .icache_bsize = 128, | 186 | .icache_bsize = 128, |
197 | .dcache_bsize = 128, | 187 | .dcache_bsize = 128, |
198 | .cpu_setup = __setup_cpu_ppc970, | 188 | .cpu_setup = __setup_cpu_ppc970, |
199 | .firmware_features = COMMON_PPC64_FW, | ||
200 | }, | 189 | }, |
201 | { /* Power5 */ | 190 | { /* Power5 */ |
202 | .pvr_mask = 0xffff0000, | 191 | .pvr_mask = 0xffff0000, |
@@ -211,7 +200,6 @@ struct cpu_spec cpu_specs[] = { | |||
211 | .icache_bsize = 128, | 200 | .icache_bsize = 128, |
212 | .dcache_bsize = 128, | 201 | .dcache_bsize = 128, |
213 | .cpu_setup = __setup_cpu_power4, | 202 | .cpu_setup = __setup_cpu_power4, |
214 | .firmware_features = COMMON_PPC64_FW, | ||
215 | }, | 203 | }, |
216 | { /* Power5 */ | 204 | { /* Power5 */ |
217 | .pvr_mask = 0xffff0000, | 205 | .pvr_mask = 0xffff0000, |
@@ -226,7 +214,6 @@ struct cpu_spec cpu_specs[] = { | |||
226 | .icache_bsize = 128, | 214 | .icache_bsize = 128, |
227 | .dcache_bsize = 128, | 215 | .dcache_bsize = 128, |
228 | .cpu_setup = __setup_cpu_power4, | 216 | .cpu_setup = __setup_cpu_power4, |
229 | .firmware_features = COMMON_PPC64_FW, | ||
230 | }, | 217 | }, |
231 | { /* BE DD1.x */ | 218 | { /* BE DD1.x */ |
232 | .pvr_mask = 0xffff0000, | 219 | .pvr_mask = 0xffff0000, |
@@ -241,7 +228,6 @@ struct cpu_spec cpu_specs[] = { | |||
241 | .icache_bsize = 128, | 228 | .icache_bsize = 128, |
242 | .dcache_bsize = 128, | 229 | .dcache_bsize = 128, |
243 | .cpu_setup = __setup_cpu_be, | 230 | .cpu_setup = __setup_cpu_be, |
244 | .firmware_features = COMMON_PPC64_FW, | ||
245 | }, | 231 | }, |
246 | { /* default match */ | 232 | { /* default match */ |
247 | .pvr_mask = 0x00000000, | 233 | .pvr_mask = 0x00000000, |
@@ -254,29 +240,5 @@ struct cpu_spec cpu_specs[] = { | |||
254 | .icache_bsize = 128, | 240 | .icache_bsize = 128, |
255 | .dcache_bsize = 128, | 241 | .dcache_bsize = 128, |
256 | .cpu_setup = __setup_cpu_power4, | 242 | .cpu_setup = __setup_cpu_power4, |
257 | .firmware_features = COMMON_PPC64_FW, | ||
258 | } | 243 | } |
259 | }; | 244 | }; |
260 | |||
261 | firmware_feature_t firmware_features_table[FIRMWARE_MAX_FEATURES] = { | ||
262 | {FW_FEATURE_PFT, "hcall-pft"}, | ||
263 | {FW_FEATURE_TCE, "hcall-tce"}, | ||
264 | {FW_FEATURE_SPRG0, "hcall-sprg0"}, | ||
265 | {FW_FEATURE_DABR, "hcall-dabr"}, | ||
266 | {FW_FEATURE_COPY, "hcall-copy"}, | ||
267 | {FW_FEATURE_ASR, "hcall-asr"}, | ||
268 | {FW_FEATURE_DEBUG, "hcall-debug"}, | ||
269 | {FW_FEATURE_PERF, "hcall-perf"}, | ||
270 | {FW_FEATURE_DUMP, "hcall-dump"}, | ||
271 | {FW_FEATURE_INTERRUPT, "hcall-interrupt"}, | ||
272 | {FW_FEATURE_MIGRATE, "hcall-migrate"}, | ||
273 | {FW_FEATURE_PERFMON, "hcall-perfmon"}, | ||
274 | {FW_FEATURE_CRQ, "hcall-crq"}, | ||
275 | {FW_FEATURE_VIO, "hcall-vio"}, | ||
276 | {FW_FEATURE_RDMA, "hcall-rdma"}, | ||
277 | {FW_FEATURE_LLAN, "hcall-lLAN"}, | ||
278 | {FW_FEATURE_BULK, "hcall-bulk"}, | ||
279 | {FW_FEATURE_XDABR, "hcall-xdabr"}, | ||
280 | {FW_FEATURE_MULTITCE, "hcall-multi-tce"}, | ||
281 | {FW_FEATURE_SPLPAR, "hcall-splpar"}, | ||
282 | }; | ||
diff --git a/arch/ppc64/kernel/firmware.c b/arch/ppc64/kernel/firmware.c new file mode 100644 index 000000000000..d8432c0fb27d --- /dev/null +++ b/arch/ppc64/kernel/firmware.c | |||
@@ -0,0 +1,47 @@ | |||
1 | /* | ||
2 | * arch/ppc64/kernel/firmware.c | ||
3 | * | ||
4 | * Extracted from cputable.c | ||
5 | * | ||
6 | * Copyright (C) 2001 Ben. Herrenschmidt (benh@kernel.crashing.org) | ||
7 | * | ||
8 | * Modifications for ppc64: | ||
9 | * Copyright (C) 2003 Dave Engebretsen <engebret@us.ibm.com> | ||
10 | * Copyright (C) 2005 Stephen Rothwell, IBM Corporation | ||
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/config.h> | ||
19 | |||
20 | #include <asm/firmware.h> | ||
21 | |||
22 | unsigned long ppc64_firmware_features; | ||
23 | |||
24 | #ifdef CONFIG_PPC_PSERIES | ||
25 | firmware_feature_t firmware_features_table[FIRMWARE_MAX_FEATURES] = { | ||
26 | {FW_FEATURE_PFT, "hcall-pft"}, | ||
27 | {FW_FEATURE_TCE, "hcall-tce"}, | ||
28 | {FW_FEATURE_SPRG0, "hcall-sprg0"}, | ||
29 | {FW_FEATURE_DABR, "hcall-dabr"}, | ||
30 | {FW_FEATURE_COPY, "hcall-copy"}, | ||
31 | {FW_FEATURE_ASR, "hcall-asr"}, | ||
32 | {FW_FEATURE_DEBUG, "hcall-debug"}, | ||
33 | {FW_FEATURE_PERF, "hcall-perf"}, | ||
34 | {FW_FEATURE_DUMP, "hcall-dump"}, | ||
35 | {FW_FEATURE_INTERRUPT, "hcall-interrupt"}, | ||
36 | {FW_FEATURE_MIGRATE, "hcall-migrate"}, | ||
37 | {FW_FEATURE_PERFMON, "hcall-perfmon"}, | ||
38 | {FW_FEATURE_CRQ, "hcall-crq"}, | ||
39 | {FW_FEATURE_VIO, "hcall-vio"}, | ||
40 | {FW_FEATURE_RDMA, "hcall-rdma"}, | ||
41 | {FW_FEATURE_LLAN, "hcall-lLAN"}, | ||
42 | {FW_FEATURE_BULK, "hcall-bulk"}, | ||
43 | {FW_FEATURE_XDABR, "hcall-xdabr"}, | ||
44 | {FW_FEATURE_MULTITCE, "hcall-multi-tce"}, | ||
45 | {FW_FEATURE_SPLPAR, "hcall-splpar"}, | ||
46 | }; | ||
47 | #endif | ||
diff --git a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S index accaa052d31f..cccec4902646 100644 --- a/arch/ppc64/kernel/head.S +++ b/arch/ppc64/kernel/head.S | |||
@@ -23,14 +23,11 @@ | |||
23 | * 2 of the License, or (at your option) any later version. | 23 | * 2 of the License, or (at your option) any later version. |
24 | */ | 24 | */ |
25 | 25 | ||
26 | #define SECONDARY_PROCESSORS | ||
27 | |||
28 | #include <linux/config.h> | 26 | #include <linux/config.h> |
29 | #include <linux/threads.h> | 27 | #include <linux/threads.h> |
30 | #include <asm/processor.h> | 28 | #include <asm/processor.h> |
31 | #include <asm/page.h> | 29 | #include <asm/page.h> |
32 | #include <asm/mmu.h> | 30 | #include <asm/mmu.h> |
33 | #include <asm/naca.h> | ||
34 | #include <asm/systemcfg.h> | 31 | #include <asm/systemcfg.h> |
35 | #include <asm/ppc_asm.h> | 32 | #include <asm/ppc_asm.h> |
36 | #include <asm/offsets.h> | 33 | #include <asm/offsets.h> |
@@ -45,18 +42,13 @@ | |||
45 | #endif | 42 | #endif |
46 | 43 | ||
47 | /* | 44 | /* |
48 | * hcall interface to pSeries LPAR | ||
49 | */ | ||
50 | #define H_SET_ASR 0x30 | ||
51 | |||
52 | /* | ||
53 | * We layout physical memory as follows: | 45 | * We layout physical memory as follows: |
54 | * 0x0000 - 0x00ff : Secondary processor spin code | 46 | * 0x0000 - 0x00ff : Secondary processor spin code |
55 | * 0x0100 - 0x2fff : pSeries Interrupt prologs | 47 | * 0x0100 - 0x2fff : pSeries Interrupt prologs |
56 | * 0x3000 - 0x3fff : Interrupt support | 48 | * 0x3000 - 0x5fff : interrupt support, iSeries and common interrupt prologs |
57 | * 0x4000 - 0x4fff : NACA | 49 | * 0x6000 - 0x6fff : Initial (CPU0) segment table |
58 | * 0x6000 : iSeries and common interrupt prologs | 50 | * 0x7000 - 0x7fff : FWNMI data area |
59 | * 0x9000 - 0x9fff : Initial segment table | 51 | * 0x8000 - : Early init and support code |
60 | */ | 52 | */ |
61 | 53 | ||
62 | /* | 54 | /* |
@@ -94,6 +86,7 @@ END_FTR_SECTION(0, 1) | |||
94 | 86 | ||
95 | /* Catch branch to 0 in real mode */ | 87 | /* Catch branch to 0 in real mode */ |
96 | trap | 88 | trap |
89 | |||
97 | #ifdef CONFIG_PPC_ISERIES | 90 | #ifdef CONFIG_PPC_ISERIES |
98 | /* | 91 | /* |
99 | * At offset 0x20, there is a pointer to iSeries LPAR data. | 92 | * At offset 0x20, there is a pointer to iSeries LPAR data. |
@@ -103,12 +96,12 @@ END_FTR_SECTION(0, 1) | |||
103 | .llong hvReleaseData-KERNELBASE | 96 | .llong hvReleaseData-KERNELBASE |
104 | 97 | ||
105 | /* | 98 | /* |
106 | * At offset 0x28 and 0x30 are offsets to the msChunks | 99 | * At offset 0x28 and 0x30 are offsets to the mschunks_map |
107 | * array (used by the iSeries LPAR debugger to do translation | 100 | * array (used by the iSeries LPAR debugger to do translation |
108 | * between physical addresses and absolute addresses) and | 101 | * between physical addresses and absolute addresses) and |
109 | * to the pidhash table (also used by the debugger) | 102 | * to the pidhash table (also used by the debugger) |
110 | */ | 103 | */ |
111 | .llong msChunks-KERNELBASE | 104 | .llong mschunks_map-KERNELBASE |
112 | .llong 0 /* pidhash-KERNELBASE SFRXXX */ | 105 | .llong 0 /* pidhash-KERNELBASE SFRXXX */ |
113 | 106 | ||
114 | /* Offset 0x38 - Pointer to start of embedded System.map */ | 107 | /* Offset 0x38 - Pointer to start of embedded System.map */ |
@@ -120,7 +113,7 @@ embedded_sysmap_start: | |||
120 | embedded_sysmap_end: | 113 | embedded_sysmap_end: |
121 | .llong 0 | 114 | .llong 0 |
122 | 115 | ||
123 | #else /* CONFIG_PPC_ISERIES */ | 116 | #endif /* CONFIG_PPC_ISERIES */ |
124 | 117 | ||
125 | /* Secondary processors spin on this value until it goes to 1. */ | 118 | /* Secondary processors spin on this value until it goes to 1. */ |
126 | .globl __secondary_hold_spinloop | 119 | .globl __secondary_hold_spinloop |
@@ -155,7 +148,7 @@ _GLOBAL(__secondary_hold) | |||
155 | std r24,__secondary_hold_acknowledge@l(0) | 148 | std r24,__secondary_hold_acknowledge@l(0) |
156 | sync | 149 | sync |
157 | 150 | ||
158 | /* All secondary cpu's wait here until told to start. */ | 151 | /* All secondary cpus wait here until told to start. */ |
159 | 100: ld r4,__secondary_hold_spinloop@l(0) | 152 | 100: ld r4,__secondary_hold_spinloop@l(0) |
160 | cmpdi 0,r4,1 | 153 | cmpdi 0,r4,1 |
161 | bne 100b | 154 | bne 100b |
@@ -170,7 +163,6 @@ _GLOBAL(__secondary_hold) | |||
170 | BUG_OPCODE | 163 | BUG_OPCODE |
171 | #endif | 164 | #endif |
172 | #endif | 165 | #endif |
173 | #endif | ||
174 | 166 | ||
175 | /* This value is used to mark exception frames on the stack. */ | 167 | /* This value is used to mark exception frames on the stack. */ |
176 | .section ".toc","aw" | 168 | .section ".toc","aw" |
@@ -502,33 +494,37 @@ system_call_pSeries: | |||
502 | STD_EXCEPTION_PSERIES(0x1300, instruction_breakpoint) | 494 | STD_EXCEPTION_PSERIES(0x1300, instruction_breakpoint) |
503 | STD_EXCEPTION_PSERIES(0x1700, altivec_assist) | 495 | STD_EXCEPTION_PSERIES(0x1700, altivec_assist) |
504 | 496 | ||
497 | . = 0x3000 | ||
498 | |||
499 | /*** pSeries interrupt support ***/ | ||
500 | |||
505 | /* moved from 0xf00 */ | 501 | /* moved from 0xf00 */ |
506 | STD_EXCEPTION_PSERIES(0x3000, performance_monitor) | 502 | STD_EXCEPTION_PSERIES(., performance_monitor) |
507 | 503 | ||
508 | . = 0x3100 | 504 | .align 7 |
509 | _GLOBAL(do_stab_bolted_pSeries) | 505 | _GLOBAL(do_stab_bolted_pSeries) |
510 | mtcrf 0x80,r12 | 506 | mtcrf 0x80,r12 |
511 | mfspr r12,SPRG2 | 507 | mfspr r12,SPRG2 |
512 | EXCEPTION_PROLOG_PSERIES(PACA_EXSLB, .do_stab_bolted) | 508 | EXCEPTION_PROLOG_PSERIES(PACA_EXSLB, .do_stab_bolted) |
513 | 509 | ||
514 | 510 | /* | |
515 | /* Space for the naca. Architected to be located at real address | 511 | * Vectors for the FWNMI option. Share common code. |
516 | * NACA_PHYS_ADDR. Various tools rely on this location being fixed. | 512 | */ |
517 | * The first dword of the naca is required by iSeries LPAR to | 513 | .globl system_reset_fwnmi |
518 | * point to itVpdAreas. On pSeries native, this value is not used. | 514 | system_reset_fwnmi: |
519 | */ | 515 | HMT_MEDIUM |
520 | . = NACA_PHYS_ADDR | 516 | mtspr SPRG1,r13 /* save r13 */ |
521 | .globl __end_interrupts | 517 | RUNLATCH_ON(r13) |
522 | __end_interrupts: | 518 | EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common) |
523 | #ifdef CONFIG_PPC_ISERIES | ||
524 | .globl naca | ||
525 | naca: | ||
526 | .llong itVpdAreas | ||
527 | .llong 0 /* xRamDisk */ | ||
528 | .llong 0 /* xRamDiskSize */ | ||
529 | 519 | ||
530 | . = 0x6100 | 520 | .globl machine_check_fwnmi |
521 | machine_check_fwnmi: | ||
522 | HMT_MEDIUM | ||
523 | mtspr SPRG1,r13 /* save r13 */ | ||
524 | RUNLATCH_ON(r13) | ||
525 | EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common) | ||
531 | 526 | ||
527 | #ifdef CONFIG_PPC_ISERIES | ||
532 | /*** ISeries-LPAR interrupt handlers ***/ | 528 | /*** ISeries-LPAR interrupt handlers ***/ |
533 | 529 | ||
534 | STD_EXCEPTION_ISERIES(0x200, machine_check, PACA_EXMC) | 530 | STD_EXCEPTION_ISERIES(0x200, machine_check, PACA_EXMC) |
@@ -626,9 +622,7 @@ system_reset_iSeries: | |||
626 | 622 | ||
627 | cmpwi 0,r23,0 | 623 | cmpwi 0,r23,0 |
628 | beq iSeries_secondary_smp_loop /* Loop until told to go */ | 624 | beq iSeries_secondary_smp_loop /* Loop until told to go */ |
629 | #ifdef SECONDARY_PROCESSORS | ||
630 | bne .__secondary_start /* Loop until told to go */ | 625 | bne .__secondary_start /* Loop until told to go */ |
631 | #endif | ||
632 | iSeries_secondary_smp_loop: | 626 | iSeries_secondary_smp_loop: |
633 | /* Let the Hypervisor know we are alive */ | 627 | /* Let the Hypervisor know we are alive */ |
634 | /* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */ | 628 | /* 8002 is a call to HvCallCfg::getLps, a harmless Hypervisor function */ |
@@ -671,51 +665,8 @@ hardware_interrupt_iSeries_masked: | |||
671 | ld r13,PACA_EXGEN+EX_R13(r13) | 665 | ld r13,PACA_EXGEN+EX_R13(r13) |
672 | rfid | 666 | rfid |
673 | b . /* prevent speculative execution */ | 667 | b . /* prevent speculative execution */ |
674 | #endif | ||
675 | |||
676 | /* | ||
677 | * Data area reserved for FWNMI option. | ||
678 | */ | ||
679 | .= 0x7000 | ||
680 | .globl fwnmi_data_area | ||
681 | fwnmi_data_area: | ||
682 | |||
683 | #ifdef CONFIG_PPC_ISERIES | ||
684 | . = LPARMAP_PHYS | ||
685 | #include "lparmap.s" | ||
686 | #endif /* CONFIG_PPC_ISERIES */ | 668 | #endif /* CONFIG_PPC_ISERIES */ |
687 | 669 | ||
688 | /* | ||
689 | * Vectors for the FWNMI option. Share common code. | ||
690 | */ | ||
691 | . = 0x8000 | ||
692 | .globl system_reset_fwnmi | ||
693 | system_reset_fwnmi: | ||
694 | HMT_MEDIUM | ||
695 | mtspr SPRG1,r13 /* save r13 */ | ||
696 | RUNLATCH_ON(r13) | ||
697 | EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common) | ||
698 | .globl machine_check_fwnmi | ||
699 | machine_check_fwnmi: | ||
700 | HMT_MEDIUM | ||
701 | mtspr SPRG1,r13 /* save r13 */ | ||
702 | RUNLATCH_ON(r13) | ||
703 | EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common) | ||
704 | |||
705 | /* | ||
706 | * Space for the initial segment table | ||
707 | * For LPAR, the hypervisor must fill in at least one entry | ||
708 | * before we get control (with relocate on) | ||
709 | */ | ||
710 | . = STAB0_PHYS_ADDR | ||
711 | .globl __start_stab | ||
712 | __start_stab: | ||
713 | |||
714 | . = (STAB0_PHYS_ADDR + PAGE_SIZE) | ||
715 | .globl __end_stab | ||
716 | __end_stab: | ||
717 | |||
718 | |||
719 | /*** Common interrupt handlers ***/ | 670 | /*** Common interrupt handlers ***/ |
720 | 671 | ||
721 | STD_EXCEPTION_COMMON(0x100, system_reset, .system_reset_exception) | 672 | STD_EXCEPTION_COMMON(0x100, system_reset, .system_reset_exception) |
@@ -752,8 +703,8 @@ machine_check_common: | |||
752 | * R9 contains the saved CR, r13 points to the paca, | 703 | * R9 contains the saved CR, r13 points to the paca, |
753 | * r10 contains the (bad) kernel stack pointer, | 704 | * r10 contains the (bad) kernel stack pointer, |
754 | * r11 and r12 contain the saved SRR0 and SRR1. | 705 | * r11 and r12 contain the saved SRR0 and SRR1. |
755 | * We switch to using the paca guard page as an emergency stack, | 706 | * We switch to using an emergency stack, save the registers there, |
756 | * save the registers there, and call kernel_bad_stack(), which panics. | 707 | * and call kernel_bad_stack(), which panics. |
757 | */ | 708 | */ |
758 | bad_stack: | 709 | bad_stack: |
759 | ld r1,PACAEMERGSP(r13) | 710 | ld r1,PACAEMERGSP(r13) |
@@ -906,6 +857,62 @@ fp_unavailable_common: | |||
906 | bl .kernel_fp_unavailable_exception | 857 | bl .kernel_fp_unavailable_exception |
907 | BUG_OPCODE | 858 | BUG_OPCODE |
908 | 859 | ||
860 | /* | ||
861 | * load_up_fpu(unused, unused, tsk) | ||
862 | * Disable FP for the task which had the FPU previously, | ||
863 | * and save its floating-point registers in its thread_struct. | ||
864 | * Enables the FPU for use in the kernel on return. | ||
865 | * On SMP we know the fpu is free, since we give it up every | ||
866 | * switch (ie, no lazy save of the FP registers). | ||
867 | * On entry: r13 == 'current' && last_task_used_math != 'current' | ||
868 | */ | ||
869 | _STATIC(load_up_fpu) | ||
870 | mfmsr r5 /* grab the current MSR */ | ||
871 | ori r5,r5,MSR_FP | ||
872 | mtmsrd r5 /* enable use of fpu now */ | ||
873 | isync | ||
874 | /* | ||
875 | * For SMP, we don't do lazy FPU switching because it just gets too | ||
876 | * horrendously complex, especially when a task switches from one CPU | ||
877 | * to another. Instead we call giveup_fpu in switch_to. | ||
878 | * | ||
879 | */ | ||
880 | #ifndef CONFIG_SMP | ||
881 | ld r3,last_task_used_math@got(r2) | ||
882 | ld r4,0(r3) | ||
883 | cmpdi 0,r4,0 | ||
884 | beq 1f | ||
885 | /* Save FP state to last_task_used_math's THREAD struct */ | ||
886 | addi r4,r4,THREAD | ||
887 | SAVE_32FPRS(0, r4) | ||
888 | mffs fr0 | ||
889 | stfd fr0,THREAD_FPSCR(r4) | ||
890 | /* Disable FP for last_task_used_math */ | ||
891 | ld r5,PT_REGS(r4) | ||
892 | ld r4,_MSR-STACK_FRAME_OVERHEAD(r5) | ||
893 | li r6,MSR_FP|MSR_FE0|MSR_FE1 | ||
894 | andc r4,r4,r6 | ||
895 | std r4,_MSR-STACK_FRAME_OVERHEAD(r5) | ||
896 | 1: | ||
897 | #endif /* CONFIG_SMP */ | ||
898 | /* enable use of FP after return */ | ||
899 | ld r4,PACACURRENT(r13) | ||
900 | addi r5,r4,THREAD /* Get THREAD */ | ||
901 | ld r4,THREAD_FPEXC_MODE(r5) | ||
902 | ori r12,r12,MSR_FP | ||
903 | or r12,r12,r4 | ||
904 | std r12,_MSR(r1) | ||
905 | lfd fr0,THREAD_FPSCR(r5) | ||
906 | mtfsf 0xff,fr0 | ||
907 | REST_32FPRS(0, r5) | ||
908 | #ifndef CONFIG_SMP | ||
909 | /* Update last_task_used_math to 'current' */ | ||
910 | subi r4,r5,THREAD /* Back to 'current' */ | ||
911 | std r4,0(r3) | ||
912 | #endif /* CONFIG_SMP */ | ||
913 | /* restore registers and return */ | ||
914 | b fast_exception_return | ||
915 | |||
909 | .align 7 | 916 | .align 7 |
910 | .globl altivec_unavailable_common | 917 | .globl altivec_unavailable_common |
911 | altivec_unavailable_common: | 918 | altivec_unavailable_common: |
@@ -921,6 +928,80 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC) | |||
921 | bl .altivec_unavailable_exception | 928 | bl .altivec_unavailable_exception |
922 | b .ret_from_except | 929 | b .ret_from_except |
923 | 930 | ||
931 | #ifdef CONFIG_ALTIVEC | ||
932 | /* | ||
933 | * load_up_altivec(unused, unused, tsk) | ||
934 | * Disable VMX for the task which had it previously, | ||
935 | * and save its vector registers in its thread_struct. | ||
936 | * Enables the VMX for use in the kernel on return. | ||
937 | * On SMP we know the VMX is free, since we give it up every | ||
938 | * switch (ie, no lazy save of the vector registers). | ||
939 | * On entry: r13 == 'current' && last_task_used_altivec != 'current' | ||
940 | */ | ||
941 | _STATIC(load_up_altivec) | ||
942 | mfmsr r5 /* grab the current MSR */ | ||
943 | oris r5,r5,MSR_VEC@h | ||
944 | mtmsrd r5 /* enable use of VMX now */ | ||
945 | isync | ||
946 | |||
947 | /* | ||
948 | * For SMP, we don't do lazy VMX switching because it just gets too | ||
949 | * horrendously complex, especially when a task switches from one CPU | ||
950 | * to another. Instead we call giveup_altvec in switch_to. | ||
951 | * VRSAVE isn't dealt with here, that is done in the normal context | ||
952 | * switch code. Note that we could rely on vrsave value to eventually | ||
953 | * avoid saving all of the VREGs here... | ||
954 | */ | ||
955 | #ifndef CONFIG_SMP | ||
956 | ld r3,last_task_used_altivec@got(r2) | ||
957 | ld r4,0(r3) | ||
958 | cmpdi 0,r4,0 | ||
959 | beq 1f | ||
960 | /* Save VMX state to last_task_used_altivec's THREAD struct */ | ||
961 | addi r4,r4,THREAD | ||
962 | SAVE_32VRS(0,r5,r4) | ||
963 | mfvscr vr0 | ||
964 | li r10,THREAD_VSCR | ||
965 | stvx vr0,r10,r4 | ||
966 | /* Disable VMX for last_task_used_altivec */ | ||
967 | ld r5,PT_REGS(r4) | ||
968 | ld r4,_MSR-STACK_FRAME_OVERHEAD(r5) | ||
969 | lis r6,MSR_VEC@h | ||
970 | andc r4,r4,r6 | ||
971 | std r4,_MSR-STACK_FRAME_OVERHEAD(r5) | ||
972 | 1: | ||
973 | #endif /* CONFIG_SMP */ | ||
974 | /* Hack: if we get an altivec unavailable trap with VRSAVE | ||
975 | * set to all zeros, we assume this is a broken application | ||
976 | * that fails to set it properly, and thus we switch it to | ||
977 | * all 1's | ||
978 | */ | ||
979 | mfspr r4,SPRN_VRSAVE | ||
980 | cmpdi 0,r4,0 | ||
981 | bne+ 1f | ||
982 | li r4,-1 | ||
983 | mtspr SPRN_VRSAVE,r4 | ||
984 | 1: | ||
985 | /* enable use of VMX after return */ | ||
986 | ld r4,PACACURRENT(r13) | ||
987 | addi r5,r4,THREAD /* Get THREAD */ | ||
988 | oris r12,r12,MSR_VEC@h | ||
989 | std r12,_MSR(r1) | ||
990 | li r4,1 | ||
991 | li r10,THREAD_VSCR | ||
992 | stw r4,THREAD_USED_VR(r5) | ||
993 | lvx vr0,r10,r5 | ||
994 | mtvscr vr0 | ||
995 | REST_32VRS(0,r4,r5) | ||
996 | #ifndef CONFIG_SMP | ||
997 | /* Update last_task_used_math to 'current' */ | ||
998 | subi r4,r5,THREAD /* Back to 'current' */ | ||
999 | std r4,0(r3) | ||
1000 | #endif /* CONFIG_SMP */ | ||
1001 | /* restore registers and return */ | ||
1002 | b fast_exception_return | ||
1003 | #endif /* CONFIG_ALTIVEC */ | ||
1004 | |||
924 | /* | 1005 | /* |
925 | * Hash table stuff | 1006 | * Hash table stuff |
926 | */ | 1007 | */ |
@@ -1167,6 +1248,28 @@ unrecov_slb: | |||
1167 | bl .unrecoverable_exception | 1248 | bl .unrecoverable_exception |
1168 | b 1b | 1249 | b 1b |
1169 | 1250 | ||
1251 | /* | ||
1252 | * Space for CPU0's segment table. | ||
1253 | * | ||
1254 | * On iSeries, the hypervisor must fill in at least one entry before | ||
1255 | * we get control (with relocate on). The address is give to the hv | ||
1256 | * as a page number (see xLparMap in LparData.c), so this must be at a | ||
1257 | * fixed address (the linker can't compute (u64)&initial_stab >> | ||
1258 | * PAGE_SHIFT). | ||
1259 | */ | ||
1260 | . = STAB0_PHYS_ADDR /* 0x6000 */ | ||
1261 | .globl initial_stab | ||
1262 | initial_stab: | ||
1263 | .space 4096 | ||
1264 | |||
1265 | /* | ||
1266 | * Data area reserved for FWNMI option. | ||
1267 | * This address (0x7000) is fixed by the RPA. | ||
1268 | */ | ||
1269 | .= 0x7000 | ||
1270 | .globl fwnmi_data_area | ||
1271 | fwnmi_data_area: | ||
1272 | .space PAGE_SIZE | ||
1170 | 1273 | ||
1171 | /* | 1274 | /* |
1172 | * On pSeries, secondary processors spin in the following code. | 1275 | * On pSeries, secondary processors spin in the following code. |
@@ -1200,7 +1303,7 @@ _GLOBAL(pSeries_secondary_smp_init) | |||
1200 | b .kexec_wait /* next kernel might do better */ | 1303 | b .kexec_wait /* next kernel might do better */ |
1201 | 1304 | ||
1202 | 2: mtspr SPRG3,r13 /* Save vaddr of paca in SPRG3 */ | 1305 | 2: mtspr SPRG3,r13 /* Save vaddr of paca in SPRG3 */ |
1203 | /* From now on, r24 is expected to be logica cpuid */ | 1306 | /* From now on, r24 is expected to be logical cpuid */ |
1204 | mr r24,r5 | 1307 | mr r24,r5 |
1205 | 3: HMT_LOW | 1308 | 3: HMT_LOW |
1206 | lbz r23,PACAPROCSTART(r13) /* Test if this processor should */ | 1309 | lbz r23,PACAPROCSTART(r13) /* Test if this processor should */ |
@@ -1213,10 +1316,8 @@ _GLOBAL(pSeries_secondary_smp_init) | |||
1213 | 1316 | ||
1214 | cmpwi 0,r23,0 | 1317 | cmpwi 0,r23,0 |
1215 | #ifdef CONFIG_SMP | 1318 | #ifdef CONFIG_SMP |
1216 | #ifdef SECONDARY_PROCESSORS | ||
1217 | bne .__secondary_start | 1319 | bne .__secondary_start |
1218 | #endif | 1320 | #endif |
1219 | #endif | ||
1220 | b 3b /* Loop until told to go */ | 1321 | b 3b /* Loop until told to go */ |
1221 | 1322 | ||
1222 | #ifdef CONFIG_PPC_ISERIES | 1323 | #ifdef CONFIG_PPC_ISERIES |
@@ -1430,228 +1531,6 @@ _GLOBAL(copy_and_flush) | |||
1430 | .align 8 | 1531 | .align 8 |
1431 | copy_to_here: | 1532 | copy_to_here: |
1432 | 1533 | ||
1433 | /* | ||
1434 | * load_up_fpu(unused, unused, tsk) | ||
1435 | * Disable FP for the task which had the FPU previously, | ||
1436 | * and save its floating-point registers in its thread_struct. | ||
1437 | * Enables the FPU for use in the kernel on return. | ||
1438 | * On SMP we know the fpu is free, since we give it up every | ||
1439 | * switch (ie, no lazy save of the FP registers). | ||
1440 | * On entry: r13 == 'current' && last_task_used_math != 'current' | ||
1441 | */ | ||
1442 | _STATIC(load_up_fpu) | ||
1443 | mfmsr r5 /* grab the current MSR */ | ||
1444 | ori r5,r5,MSR_FP | ||
1445 | mtmsrd r5 /* enable use of fpu now */ | ||
1446 | isync | ||
1447 | /* | ||
1448 | * For SMP, we don't do lazy FPU switching because it just gets too | ||
1449 | * horrendously complex, especially when a task switches from one CPU | ||
1450 | * to another. Instead we call giveup_fpu in switch_to. | ||
1451 | * | ||
1452 | */ | ||
1453 | #ifndef CONFIG_SMP | ||
1454 | ld r3,last_task_used_math@got(r2) | ||
1455 | ld r4,0(r3) | ||
1456 | cmpdi 0,r4,0 | ||
1457 | beq 1f | ||
1458 | /* Save FP state to last_task_used_math's THREAD struct */ | ||
1459 | addi r4,r4,THREAD | ||
1460 | SAVE_32FPRS(0, r4) | ||
1461 | mffs fr0 | ||
1462 | stfd fr0,THREAD_FPSCR(r4) | ||
1463 | /* Disable FP for last_task_used_math */ | ||
1464 | ld r5,PT_REGS(r4) | ||
1465 | ld r4,_MSR-STACK_FRAME_OVERHEAD(r5) | ||
1466 | li r6,MSR_FP|MSR_FE0|MSR_FE1 | ||
1467 | andc r4,r4,r6 | ||
1468 | std r4,_MSR-STACK_FRAME_OVERHEAD(r5) | ||
1469 | 1: | ||
1470 | #endif /* CONFIG_SMP */ | ||
1471 | /* enable use of FP after return */ | ||
1472 | ld r4,PACACURRENT(r13) | ||
1473 | addi r5,r4,THREAD /* Get THREAD */ | ||
1474 | ld r4,THREAD_FPEXC_MODE(r5) | ||
1475 | ori r12,r12,MSR_FP | ||
1476 | or r12,r12,r4 | ||
1477 | std r12,_MSR(r1) | ||
1478 | lfd fr0,THREAD_FPSCR(r5) | ||
1479 | mtfsf 0xff,fr0 | ||
1480 | REST_32FPRS(0, r5) | ||
1481 | #ifndef CONFIG_SMP | ||
1482 | /* Update last_task_used_math to 'current' */ | ||
1483 | subi r4,r5,THREAD /* Back to 'current' */ | ||
1484 | std r4,0(r3) | ||
1485 | #endif /* CONFIG_SMP */ | ||
1486 | /* restore registers and return */ | ||
1487 | b fast_exception_return | ||
1488 | |||
1489 | /* | ||
1490 | * disable_kernel_fp() | ||
1491 | * Disable the FPU. | ||
1492 | */ | ||
1493 | _GLOBAL(disable_kernel_fp) | ||
1494 | mfmsr r3 | ||
1495 | rldicl r0,r3,(63-MSR_FP_LG),1 | ||
1496 | rldicl r3,r0,(MSR_FP_LG+1),0 | ||
1497 | mtmsrd r3 /* disable use of fpu now */ | ||
1498 | isync | ||
1499 | blr | ||
1500 | |||
1501 | /* | ||
1502 | * giveup_fpu(tsk) | ||
1503 | * Disable FP for the task given as the argument, | ||
1504 | * and save the floating-point registers in its thread_struct. | ||
1505 | * Enables the FPU for use in the kernel on return. | ||
1506 | */ | ||
1507 | _GLOBAL(giveup_fpu) | ||
1508 | mfmsr r5 | ||
1509 | ori r5,r5,MSR_FP | ||
1510 | mtmsrd r5 /* enable use of fpu now */ | ||
1511 | isync | ||
1512 | cmpdi 0,r3,0 | ||
1513 | beqlr- /* if no previous owner, done */ | ||
1514 | addi r3,r3,THREAD /* want THREAD of task */ | ||
1515 | ld r5,PT_REGS(r3) | ||
1516 | cmpdi 0,r5,0 | ||
1517 | SAVE_32FPRS(0, r3) | ||
1518 | mffs fr0 | ||
1519 | stfd fr0,THREAD_FPSCR(r3) | ||
1520 | beq 1f | ||
1521 | ld r4,_MSR-STACK_FRAME_OVERHEAD(r5) | ||
1522 | li r3,MSR_FP|MSR_FE0|MSR_FE1 | ||
1523 | andc r4,r4,r3 /* disable FP for previous task */ | ||
1524 | std r4,_MSR-STACK_FRAME_OVERHEAD(r5) | ||
1525 | 1: | ||
1526 | #ifndef CONFIG_SMP | ||
1527 | li r5,0 | ||
1528 | ld r4,last_task_used_math@got(r2) | ||
1529 | std r5,0(r4) | ||
1530 | #endif /* CONFIG_SMP */ | ||
1531 | blr | ||
1532 | |||
1533 | |||
1534 | #ifdef CONFIG_ALTIVEC | ||
1535 | |||
1536 | /* | ||
1537 | * load_up_altivec(unused, unused, tsk) | ||
1538 | * Disable VMX for the task which had it previously, | ||
1539 | * and save its vector registers in its thread_struct. | ||
1540 | * Enables the VMX for use in the kernel on return. | ||
1541 | * On SMP we know the VMX is free, since we give it up every | ||
1542 | * switch (ie, no lazy save of the vector registers). | ||
1543 | * On entry: r13 == 'current' && last_task_used_altivec != 'current' | ||
1544 | */ | ||
1545 | _STATIC(load_up_altivec) | ||
1546 | mfmsr r5 /* grab the current MSR */ | ||
1547 | oris r5,r5,MSR_VEC@h | ||
1548 | mtmsrd r5 /* enable use of VMX now */ | ||
1549 | isync | ||
1550 | |||
1551 | /* | ||
1552 | * For SMP, we don't do lazy VMX switching because it just gets too | ||
1553 | * horrendously complex, especially when a task switches from one CPU | ||
1554 | * to another. Instead we call giveup_altvec in switch_to. | ||
1555 | * VRSAVE isn't dealt with here, that is done in the normal context | ||
1556 | * switch code. Note that we could rely on vrsave value to eventually | ||
1557 | * avoid saving all of the VREGs here... | ||
1558 | */ | ||
1559 | #ifndef CONFIG_SMP | ||
1560 | ld r3,last_task_used_altivec@got(r2) | ||
1561 | ld r4,0(r3) | ||
1562 | cmpdi 0,r4,0 | ||
1563 | beq 1f | ||
1564 | /* Save VMX state to last_task_used_altivec's THREAD struct */ | ||
1565 | addi r4,r4,THREAD | ||
1566 | SAVE_32VRS(0,r5,r4) | ||
1567 | mfvscr vr0 | ||
1568 | li r10,THREAD_VSCR | ||
1569 | stvx vr0,r10,r4 | ||
1570 | /* Disable VMX for last_task_used_altivec */ | ||
1571 | ld r5,PT_REGS(r4) | ||
1572 | ld r4,_MSR-STACK_FRAME_OVERHEAD(r5) | ||
1573 | lis r6,MSR_VEC@h | ||
1574 | andc r4,r4,r6 | ||
1575 | std r4,_MSR-STACK_FRAME_OVERHEAD(r5) | ||
1576 | 1: | ||
1577 | #endif /* CONFIG_SMP */ | ||
1578 | /* Hack: if we get an altivec unavailable trap with VRSAVE | ||
1579 | * set to all zeros, we assume this is a broken application | ||
1580 | * that fails to set it properly, and thus we switch it to | ||
1581 | * all 1's | ||
1582 | */ | ||
1583 | mfspr r4,SPRN_VRSAVE | ||
1584 | cmpdi 0,r4,0 | ||
1585 | bne+ 1f | ||
1586 | li r4,-1 | ||
1587 | mtspr SPRN_VRSAVE,r4 | ||
1588 | 1: | ||
1589 | /* enable use of VMX after return */ | ||
1590 | ld r4,PACACURRENT(r13) | ||
1591 | addi r5,r4,THREAD /* Get THREAD */ | ||
1592 | oris r12,r12,MSR_VEC@h | ||
1593 | std r12,_MSR(r1) | ||
1594 | li r4,1 | ||
1595 | li r10,THREAD_VSCR | ||
1596 | stw r4,THREAD_USED_VR(r5) | ||
1597 | lvx vr0,r10,r5 | ||
1598 | mtvscr vr0 | ||
1599 | REST_32VRS(0,r4,r5) | ||
1600 | #ifndef CONFIG_SMP | ||
1601 | /* Update last_task_used_math to 'current' */ | ||
1602 | subi r4,r5,THREAD /* Back to 'current' */ | ||
1603 | std r4,0(r3) | ||
1604 | #endif /* CONFIG_SMP */ | ||
1605 | /* restore registers and return */ | ||
1606 | b fast_exception_return | ||
1607 | |||
1608 | /* | ||
1609 | * disable_kernel_altivec() | ||
1610 | * Disable the VMX. | ||
1611 | */ | ||
1612 | _GLOBAL(disable_kernel_altivec) | ||
1613 | mfmsr r3 | ||
1614 | rldicl r0,r3,(63-MSR_VEC_LG),1 | ||
1615 | rldicl r3,r0,(MSR_VEC_LG+1),0 | ||
1616 | mtmsrd r3 /* disable use of VMX now */ | ||
1617 | isync | ||
1618 | blr | ||
1619 | |||
1620 | /* | ||
1621 | * giveup_altivec(tsk) | ||
1622 | * Disable VMX for the task given as the argument, | ||
1623 | * and save the vector registers in its thread_struct. | ||
1624 | * Enables the VMX for use in the kernel on return. | ||
1625 | */ | ||
1626 | _GLOBAL(giveup_altivec) | ||
1627 | mfmsr r5 | ||
1628 | oris r5,r5,MSR_VEC@h | ||
1629 | mtmsrd r5 /* enable use of VMX now */ | ||
1630 | isync | ||
1631 | cmpdi 0,r3,0 | ||
1632 | beqlr- /* if no previous owner, done */ | ||
1633 | addi r3,r3,THREAD /* want THREAD of task */ | ||
1634 | ld r5,PT_REGS(r3) | ||
1635 | cmpdi 0,r5,0 | ||
1636 | SAVE_32VRS(0,r4,r3) | ||
1637 | mfvscr vr0 | ||
1638 | li r4,THREAD_VSCR | ||
1639 | stvx vr0,r4,r3 | ||
1640 | beq 1f | ||
1641 | ld r4,_MSR-STACK_FRAME_OVERHEAD(r5) | ||
1642 | lis r3,MSR_VEC@h | ||
1643 | andc r4,r4,r3 /* disable FP for previous task */ | ||
1644 | std r4,_MSR-STACK_FRAME_OVERHEAD(r5) | ||
1645 | 1: | ||
1646 | #ifndef CONFIG_SMP | ||
1647 | li r5,0 | ||
1648 | ld r4,last_task_used_altivec@got(r2) | ||
1649 | std r5,0(r4) | ||
1650 | #endif /* CONFIG_SMP */ | ||
1651 | blr | ||
1652 | |||
1653 | #endif /* CONFIG_ALTIVEC */ | ||
1654 | |||
1655 | #ifdef CONFIG_SMP | 1534 | #ifdef CONFIG_SMP |
1656 | #ifdef CONFIG_PPC_PMAC | 1535 | #ifdef CONFIG_PPC_PMAC |
1657 | /* | 1536 | /* |
@@ -2002,9 +1881,6 @@ _STATIC(start_here_common) | |||
2002 | 1881 | ||
2003 | bl .start_kernel | 1882 | bl .start_kernel |
2004 | 1883 | ||
2005 | _GLOBAL(__setup_cpu_power3) | ||
2006 | blr | ||
2007 | |||
2008 | _GLOBAL(hmt_init) | 1884 | _GLOBAL(hmt_init) |
2009 | #ifdef CONFIG_HMT | 1885 | #ifdef CONFIG_HMT |
2010 | LOADADDR(r5, hmt_thread_data) | 1886 | LOADADDR(r5, hmt_thread_data) |
@@ -2095,20 +1971,19 @@ _GLOBAL(smp_release_cpus) | |||
2095 | 1971 | ||
2096 | /* | 1972 | /* |
2097 | * We put a few things here that have to be page-aligned. | 1973 | * We put a few things here that have to be page-aligned. |
2098 | * This stuff goes at the beginning of the data segment, | 1974 | * This stuff goes at the beginning of the bss, which is page-aligned. |
2099 | * which is page-aligned. | ||
2100 | */ | 1975 | */ |
2101 | .data | 1976 | .section ".bss" |
1977 | |||
2102 | .align 12 | 1978 | .align 12 |
2103 | .globl sdata | 1979 | |
2104 | sdata: | ||
2105 | .globl empty_zero_page | 1980 | .globl empty_zero_page |
2106 | empty_zero_page: | 1981 | empty_zero_page: |
2107 | .space 4096 | 1982 | .space PAGE_SIZE |
2108 | 1983 | ||
2109 | .globl swapper_pg_dir | 1984 | .globl swapper_pg_dir |
2110 | swapper_pg_dir: | 1985 | swapper_pg_dir: |
2111 | .space 4096 | 1986 | .space PAGE_SIZE |
2112 | 1987 | ||
2113 | /* | 1988 | /* |
2114 | * This space gets a copy of optional info passed to us by the bootstrap | 1989 | * This space gets a copy of optional info passed to us by the bootstrap |
diff --git a/arch/ppc64/kernel/iSeries_htab.c b/arch/ppc64/kernel/iSeries_htab.c index b0250ae4a72a..2192055a90a0 100644 --- a/arch/ppc64/kernel/iSeries_htab.c +++ b/arch/ppc64/kernel/iSeries_htab.c | |||
@@ -41,6 +41,7 @@ static long iSeries_hpte_insert(unsigned long hpte_group, unsigned long va, | |||
41 | unsigned long prpn, unsigned long vflags, | 41 | unsigned long prpn, unsigned long vflags, |
42 | unsigned long rflags) | 42 | unsigned long rflags) |
43 | { | 43 | { |
44 | unsigned long arpn; | ||
44 | long slot; | 45 | long slot; |
45 | hpte_t lhpte; | 46 | hpte_t lhpte; |
46 | int secondary = 0; | 47 | int secondary = 0; |
@@ -70,8 +71,10 @@ static long iSeries_hpte_insert(unsigned long hpte_group, unsigned long va, | |||
70 | slot &= 0x7fffffffffffffff; | 71 | slot &= 0x7fffffffffffffff; |
71 | } | 72 | } |
72 | 73 | ||
74 | arpn = phys_to_abs(prpn << PAGE_SHIFT) >> PAGE_SHIFT; | ||
75 | |||
73 | lhpte.v = (va >> 23) << HPTE_V_AVPN_SHIFT | vflags | HPTE_V_VALID; | 76 | lhpte.v = (va >> 23) << HPTE_V_AVPN_SHIFT | vflags | HPTE_V_VALID; |
74 | lhpte.r = (physRpn_to_absRpn(prpn) << HPTE_R_RPN_SHIFT) | rflags; | 77 | lhpte.r = (arpn << HPTE_R_RPN_SHIFT) | rflags; |
75 | 78 | ||
76 | /* Now fill in the actual HPTE */ | 79 | /* Now fill in the actual HPTE */ |
77 | HvCallHpt_addValidate(slot, secondary, &lhpte); | 80 | HvCallHpt_addValidate(slot, secondary, &lhpte); |
diff --git a/arch/ppc64/kernel/iSeries_setup.c b/arch/ppc64/kernel/iSeries_setup.c index a649edbb23b6..3ffefbbc6623 100644 --- a/arch/ppc64/kernel/iSeries_setup.c +++ b/arch/ppc64/kernel/iSeries_setup.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <asm/cputable.h> | 39 | #include <asm/cputable.h> |
40 | #include <asm/sections.h> | 40 | #include <asm/sections.h> |
41 | #include <asm/iommu.h> | 41 | #include <asm/iommu.h> |
42 | #include <asm/firmware.h> | ||
42 | 43 | ||
43 | #include <asm/time.h> | 44 | #include <asm/time.h> |
44 | #include "iSeries_setup.h" | 45 | #include "iSeries_setup.h" |
@@ -314,6 +315,8 @@ static void __init iSeries_init_early(void) | |||
314 | 315 | ||
315 | DBG(" -> iSeries_init_early()\n"); | 316 | DBG(" -> iSeries_init_early()\n"); |
316 | 317 | ||
318 | ppc64_firmware_features = FW_FEATURE_ISERIES; | ||
319 | |||
317 | ppcdbg_initialize(); | 320 | ppcdbg_initialize(); |
318 | 321 | ||
319 | #if defined(CONFIG_BLK_DEV_INITRD) | 322 | #if defined(CONFIG_BLK_DEV_INITRD) |
@@ -412,6 +415,22 @@ static void __init iSeries_init_early(void) | |||
412 | DBG(" <- iSeries_init_early()\n"); | 415 | DBG(" <- iSeries_init_early()\n"); |
413 | } | 416 | } |
414 | 417 | ||
418 | struct mschunks_map mschunks_map = { | ||
419 | /* XXX We don't use these, but Piranha might need them. */ | ||
420 | .chunk_size = MSCHUNKS_CHUNK_SIZE, | ||
421 | .chunk_shift = MSCHUNKS_CHUNK_SHIFT, | ||
422 | .chunk_mask = MSCHUNKS_OFFSET_MASK, | ||
423 | }; | ||
424 | EXPORT_SYMBOL(mschunks_map); | ||
425 | |||
426 | void mschunks_alloc(unsigned long num_chunks) | ||
427 | { | ||
428 | klimit = _ALIGN(klimit, sizeof(u32)); | ||
429 | mschunks_map.mapping = (u32 *)klimit; | ||
430 | klimit += num_chunks * sizeof(u32); | ||
431 | mschunks_map.num_chunks = num_chunks; | ||
432 | } | ||
433 | |||
415 | /* | 434 | /* |
416 | * The iSeries may have very large memories ( > 128 GB ) and a partition | 435 | * The iSeries may have very large memories ( > 128 GB ) and a partition |
417 | * may get memory in "chunks" that may be anywhere in the 2**52 real | 436 | * may get memory in "chunks" that may be anywhere in the 2**52 real |
@@ -449,7 +468,7 @@ static void __init build_iSeries_Memory_Map(void) | |||
449 | 468 | ||
450 | /* Chunk size on iSeries is 256K bytes */ | 469 | /* Chunk size on iSeries is 256K bytes */ |
451 | totalChunks = (u32)HvLpConfig_getMsChunks(); | 470 | totalChunks = (u32)HvLpConfig_getMsChunks(); |
452 | klimit = msChunks_alloc(klimit, totalChunks, 1UL << 18); | 471 | mschunks_alloc(totalChunks); |
453 | 472 | ||
454 | /* | 473 | /* |
455 | * Get absolute address of our load area | 474 | * Get absolute address of our load area |
@@ -486,7 +505,7 @@ static void __init build_iSeries_Memory_Map(void) | |||
486 | printk("Load area size %dK\n", loadAreaSize * 256); | 505 | printk("Load area size %dK\n", loadAreaSize * 256); |
487 | 506 | ||
488 | for (nextPhysChunk = 0; nextPhysChunk < loadAreaSize; ++nextPhysChunk) | 507 | for (nextPhysChunk = 0; nextPhysChunk < loadAreaSize; ++nextPhysChunk) |
489 | msChunks.abs[nextPhysChunk] = | 508 | mschunks_map.mapping[nextPhysChunk] = |
490 | loadAreaFirstChunk + nextPhysChunk; | 509 | loadAreaFirstChunk + nextPhysChunk; |
491 | 510 | ||
492 | /* | 511 | /* |
@@ -495,7 +514,7 @@ static void __init build_iSeries_Memory_Map(void) | |||
495 | */ | 514 | */ |
496 | hptFirstChunk = (u32)addr_to_chunk(HvCallHpt_getHptAddress()); | 515 | hptFirstChunk = (u32)addr_to_chunk(HvCallHpt_getHptAddress()); |
497 | hptSizePages = (u32)HvCallHpt_getHptPages(); | 516 | hptSizePages = (u32)HvCallHpt_getHptPages(); |
498 | hptSizeChunks = hptSizePages >> (msChunks.chunk_shift - PAGE_SHIFT); | 517 | hptSizeChunks = hptSizePages >> (MSCHUNKS_CHUNK_SHIFT - PAGE_SHIFT); |
499 | hptLastChunk = hptFirstChunk + hptSizeChunks - 1; | 518 | hptLastChunk = hptFirstChunk + hptSizeChunks - 1; |
500 | 519 | ||
501 | printk("HPT absolute addr = %016lx, size = %dK\n", | 520 | printk("HPT absolute addr = %016lx, size = %dK\n", |
@@ -552,7 +571,8 @@ static void __init build_iSeries_Memory_Map(void) | |||
552 | (absChunk > hptLastChunk)) && | 571 | (absChunk > hptLastChunk)) && |
553 | ((absChunk < loadAreaFirstChunk) || | 572 | ((absChunk < loadAreaFirstChunk) || |
554 | (absChunk > loadAreaLastChunk))) { | 573 | (absChunk > loadAreaLastChunk))) { |
555 | msChunks.abs[nextPhysChunk] = absChunk; | 574 | mschunks_map.mapping[nextPhysChunk] = |
575 | absChunk; | ||
556 | ++nextPhysChunk; | 576 | ++nextPhysChunk; |
557 | } | 577 | } |
558 | } | 578 | } |
@@ -944,6 +964,8 @@ void __init iSeries_early_setup(void) | |||
944 | ppc_md.calibrate_decr = iSeries_calibrate_decr; | 964 | ppc_md.calibrate_decr = iSeries_calibrate_decr; |
945 | ppc_md.progress = iSeries_progress; | 965 | ppc_md.progress = iSeries_progress; |
946 | 966 | ||
967 | /* XXX Implement enable_pmcs for iSeries */ | ||
968 | |||
947 | if (get_paca()->lppaca.shared_proc) { | 969 | if (get_paca()->lppaca.shared_proc) { |
948 | ppc_md.idle_loop = iseries_shared_idle; | 970 | ppc_md.idle_loop = iseries_shared_idle; |
949 | printk(KERN_INFO "Using shared processor idle loop\n"); | 971 | printk(KERN_INFO "Using shared processor idle loop\n"); |
diff --git a/arch/ppc64/kernel/iSeries_vio.c b/arch/ppc64/kernel/iSeries_vio.c new file mode 100644 index 000000000000..b4268cc4ba48 --- /dev/null +++ b/arch/ppc64/kernel/iSeries_vio.c | |||
@@ -0,0 +1,144 @@ | |||
1 | /* | ||
2 | * IBM PowerPC iSeries Virtual I/O Infrastructure Support. | ||
3 | * | ||
4 | * Copyright (c) 2005 Stephen Rothwell, IBM Corp. | ||
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/types.h> | ||
12 | #include <linux/device.h> | ||
13 | #include <linux/init.h> | ||
14 | |||
15 | #include <asm/vio.h> | ||
16 | #include <asm/iommu.h> | ||
17 | #include <asm/abs_addr.h> | ||
18 | #include <asm/page.h> | ||
19 | #include <asm/iSeries/vio.h> | ||
20 | #include <asm/iSeries/HvTypes.h> | ||
21 | #include <asm/iSeries/HvLpConfig.h> | ||
22 | #include <asm/iSeries/HvCallXm.h> | ||
23 | |||
24 | struct device *iSeries_vio_dev = &vio_bus_device.dev; | ||
25 | EXPORT_SYMBOL(iSeries_vio_dev); | ||
26 | |||
27 | static struct iommu_table veth_iommu_table; | ||
28 | static struct iommu_table vio_iommu_table; | ||
29 | |||
30 | static void __init iommu_vio_init(void) | ||
31 | { | ||
32 | struct iommu_table *t; | ||
33 | struct iommu_table_cb cb; | ||
34 | unsigned long cbp; | ||
35 | unsigned long itc_entries; | ||
36 | |||
37 | cb.itc_busno = 255; /* Bus 255 is the virtual bus */ | ||
38 | cb.itc_virtbus = 0xff; /* Ask for virtual bus */ | ||
39 | |||
40 | cbp = virt_to_abs(&cb); | ||
41 | HvCallXm_getTceTableParms(cbp); | ||
42 | |||
43 | itc_entries = cb.itc_size * PAGE_SIZE / sizeof(union tce_entry); | ||
44 | veth_iommu_table.it_size = itc_entries / 2; | ||
45 | veth_iommu_table.it_busno = cb.itc_busno; | ||
46 | veth_iommu_table.it_offset = cb.itc_offset; | ||
47 | veth_iommu_table.it_index = cb.itc_index; | ||
48 | veth_iommu_table.it_type = TCE_VB; | ||
49 | veth_iommu_table.it_blocksize = 1; | ||
50 | |||
51 | t = iommu_init_table(&veth_iommu_table); | ||
52 | |||
53 | if (!t) | ||
54 | printk("Virtual Bus VETH TCE table failed.\n"); | ||
55 | |||
56 | vio_iommu_table.it_size = itc_entries - veth_iommu_table.it_size; | ||
57 | vio_iommu_table.it_busno = cb.itc_busno; | ||
58 | vio_iommu_table.it_offset = cb.itc_offset + | ||
59 | veth_iommu_table.it_size; | ||
60 | vio_iommu_table.it_index = cb.itc_index; | ||
61 | vio_iommu_table.it_type = TCE_VB; | ||
62 | vio_iommu_table.it_blocksize = 1; | ||
63 | |||
64 | t = iommu_init_table(&vio_iommu_table); | ||
65 | |||
66 | if (!t) | ||
67 | printk("Virtual Bus VIO TCE table failed.\n"); | ||
68 | } | ||
69 | |||
70 | /** | ||
71 | * vio_register_device: - Register a new vio device. | ||
72 | * @voidev: The device to register. | ||
73 | */ | ||
74 | static struct vio_dev *__init vio_register_device_iseries(char *type, | ||
75 | uint32_t unit_num) | ||
76 | { | ||
77 | struct vio_dev *viodev; | ||
78 | |||
79 | /* allocate a vio_dev for this node */ | ||
80 | viodev = kmalloc(sizeof(struct vio_dev), GFP_KERNEL); | ||
81 | if (!viodev) | ||
82 | return NULL; | ||
83 | memset(viodev, 0, sizeof(struct vio_dev)); | ||
84 | |||
85 | snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%s%d", type, unit_num); | ||
86 | |||
87 | return vio_register_device_common(viodev, viodev->dev.bus_id, type, | ||
88 | unit_num, &vio_iommu_table); | ||
89 | } | ||
90 | |||
91 | void __init probe_bus_iseries(void) | ||
92 | { | ||
93 | HvLpIndexMap vlan_map; | ||
94 | struct vio_dev *viodev; | ||
95 | int i; | ||
96 | |||
97 | /* there is only one of each of these */ | ||
98 | vio_register_device_iseries("viocons", 0); | ||
99 | vio_register_device_iseries("vscsi", 0); | ||
100 | |||
101 | vlan_map = HvLpConfig_getVirtualLanIndexMap(); | ||
102 | for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++) { | ||
103 | if ((vlan_map & (0x8000 >> i)) == 0) | ||
104 | continue; | ||
105 | viodev = vio_register_device_iseries("vlan", i); | ||
106 | /* veth is special and has it own iommu_table */ | ||
107 | viodev->iommu_table = &veth_iommu_table; | ||
108 | } | ||
109 | for (i = 0; i < HVMAXARCHITECTEDVIRTUALDISKS; i++) | ||
110 | vio_register_device_iseries("viodasd", i); | ||
111 | for (i = 0; i < HVMAXARCHITECTEDVIRTUALCDROMS; i++) | ||
112 | vio_register_device_iseries("viocd", i); | ||
113 | for (i = 0; i < HVMAXARCHITECTEDVIRTUALTAPES; i++) | ||
114 | vio_register_device_iseries("viotape", i); | ||
115 | } | ||
116 | |||
117 | /** | ||
118 | * vio_match_device_iseries: - Tell if a iSeries VIO device matches a | ||
119 | * vio_device_id | ||
120 | */ | ||
121 | static int vio_match_device_iseries(const struct vio_device_id *id, | ||
122 | const struct vio_dev *dev) | ||
123 | { | ||
124 | return strncmp(dev->type, id->type, strlen(id->type)) == 0; | ||
125 | } | ||
126 | |||
127 | /** | ||
128 | * vio_bus_init_iseries: - Initialize the iSeries virtual IO bus | ||
129 | */ | ||
130 | static int __init vio_bus_init_iseries(void) | ||
131 | { | ||
132 | int err; | ||
133 | |||
134 | err = vio_bus_init(vio_match_device_iseries, NULL, NULL); | ||
135 | if (err == 0) { | ||
136 | iommu_vio_init(); | ||
137 | vio_bus_device.iommu_table = &vio_iommu_table; | ||
138 | iSeries_vio_dev = &vio_bus_device.dev; | ||
139 | probe_bus_iseries(); | ||
140 | } | ||
141 | return err; | ||
142 | } | ||
143 | |||
144 | __initcall(vio_bus_init_iseries); | ||
diff --git a/arch/ppc64/kernel/lmb.c b/arch/ppc64/kernel/lmb.c index d6c6bd03d2a4..5adaca2ddc9d 100644 --- a/arch/ppc64/kernel/lmb.c +++ b/arch/ppc64/kernel/lmb.c | |||
@@ -28,33 +28,28 @@ void lmb_dump_all(void) | |||
28 | { | 28 | { |
29 | #ifdef DEBUG | 29 | #ifdef DEBUG |
30 | unsigned long i; | 30 | unsigned long i; |
31 | struct lmb *_lmb = &lmb; | ||
32 | 31 | ||
33 | udbg_printf("lmb_dump_all:\n"); | 32 | udbg_printf("lmb_dump_all:\n"); |
34 | udbg_printf(" memory.cnt = 0x%lx\n", | 33 | udbg_printf(" memory.cnt = 0x%lx\n", |
35 | _lmb->memory.cnt); | 34 | lmb.memory.cnt); |
36 | udbg_printf(" memory.size = 0x%lx\n", | 35 | udbg_printf(" memory.size = 0x%lx\n", |
37 | _lmb->memory.size); | 36 | lmb.memory.size); |
38 | for (i=0; i < _lmb->memory.cnt ;i++) { | 37 | for (i=0; i < lmb.memory.cnt ;i++) { |
39 | udbg_printf(" memory.region[0x%x].base = 0x%lx\n", | 38 | udbg_printf(" memory.region[0x%x].base = 0x%lx\n", |
40 | i, _lmb->memory.region[i].base); | 39 | i, lmb.memory.region[i].base); |
41 | udbg_printf(" .physbase = 0x%lx\n", | ||
42 | _lmb->memory.region[i].physbase); | ||
43 | udbg_printf(" .size = 0x%lx\n", | 40 | udbg_printf(" .size = 0x%lx\n", |
44 | _lmb->memory.region[i].size); | 41 | lmb.memory.region[i].size); |
45 | } | 42 | } |
46 | 43 | ||
47 | udbg_printf("\n reserved.cnt = 0x%lx\n", | 44 | udbg_printf("\n reserved.cnt = 0x%lx\n", |
48 | _lmb->reserved.cnt); | 45 | lmb.reserved.cnt); |
49 | udbg_printf(" reserved.size = 0x%lx\n", | 46 | udbg_printf(" reserved.size = 0x%lx\n", |
50 | _lmb->reserved.size); | 47 | lmb.reserved.size); |
51 | for (i=0; i < _lmb->reserved.cnt ;i++) { | 48 | for (i=0; i < lmb.reserved.cnt ;i++) { |
52 | udbg_printf(" reserved.region[0x%x].base = 0x%lx\n", | 49 | udbg_printf(" reserved.region[0x%x].base = 0x%lx\n", |
53 | i, _lmb->reserved.region[i].base); | 50 | i, lmb.reserved.region[i].base); |
54 | udbg_printf(" .physbase = 0x%lx\n", | ||
55 | _lmb->reserved.region[i].physbase); | ||
56 | udbg_printf(" .size = 0x%lx\n", | 51 | udbg_printf(" .size = 0x%lx\n", |
57 | _lmb->reserved.region[i].size); | 52 | lmb.reserved.region[i].size); |
58 | } | 53 | } |
59 | #endif /* DEBUG */ | 54 | #endif /* DEBUG */ |
60 | } | 55 | } |
@@ -98,7 +93,6 @@ lmb_coalesce_regions(struct lmb_region *rgn, unsigned long r1, unsigned long r2) | |||
98 | rgn->region[r1].size += rgn->region[r2].size; | 93 | rgn->region[r1].size += rgn->region[r2].size; |
99 | for (i=r2; i < rgn->cnt-1; i++) { | 94 | for (i=r2; i < rgn->cnt-1; i++) { |
100 | rgn->region[i].base = rgn->region[i+1].base; | 95 | rgn->region[i].base = rgn->region[i+1].base; |
101 | rgn->region[i].physbase = rgn->region[i+1].physbase; | ||
102 | rgn->region[i].size = rgn->region[i+1].size; | 96 | rgn->region[i].size = rgn->region[i+1].size; |
103 | } | 97 | } |
104 | rgn->cnt--; | 98 | rgn->cnt--; |
@@ -108,49 +102,29 @@ lmb_coalesce_regions(struct lmb_region *rgn, unsigned long r1, unsigned long r2) | |||
108 | void __init | 102 | void __init |
109 | lmb_init(void) | 103 | lmb_init(void) |
110 | { | 104 | { |
111 | struct lmb *_lmb = &lmb; | ||
112 | |||
113 | /* Create a dummy zero size LMB which will get coalesced away later. | 105 | /* Create a dummy zero size LMB which will get coalesced away later. |
114 | * This simplifies the lmb_add() code below... | 106 | * This simplifies the lmb_add() code below... |
115 | */ | 107 | */ |
116 | _lmb->memory.region[0].base = 0; | 108 | lmb.memory.region[0].base = 0; |
117 | _lmb->memory.region[0].size = 0; | 109 | lmb.memory.region[0].size = 0; |
118 | _lmb->memory.cnt = 1; | 110 | lmb.memory.cnt = 1; |
119 | 111 | ||
120 | /* Ditto. */ | 112 | /* Ditto. */ |
121 | _lmb->reserved.region[0].base = 0; | 113 | lmb.reserved.region[0].base = 0; |
122 | _lmb->reserved.region[0].size = 0; | 114 | lmb.reserved.region[0].size = 0; |
123 | _lmb->reserved.cnt = 1; | 115 | lmb.reserved.cnt = 1; |
124 | } | 116 | } |
125 | 117 | ||
126 | /* This routine called with relocation disabled. */ | 118 | /* This routine called with relocation disabled. */ |
127 | void __init | 119 | void __init |
128 | lmb_analyze(void) | 120 | lmb_analyze(void) |
129 | { | 121 | { |
130 | unsigned long i; | 122 | int i; |
131 | unsigned long mem_size = 0; | 123 | |
132 | unsigned long size_mask = 0; | 124 | lmb.memory.size = 0; |
133 | struct lmb *_lmb = &lmb; | ||
134 | #ifdef CONFIG_MSCHUNKS | ||
135 | unsigned long physbase = 0; | ||
136 | #endif | ||
137 | |||
138 | for (i=0; i < _lmb->memory.cnt; i++) { | ||
139 | unsigned long lmb_size; | ||
140 | |||
141 | lmb_size = _lmb->memory.region[i].size; | ||
142 | |||
143 | #ifdef CONFIG_MSCHUNKS | ||
144 | _lmb->memory.region[i].physbase = physbase; | ||
145 | physbase += lmb_size; | ||
146 | #else | ||
147 | _lmb->memory.region[i].physbase = _lmb->memory.region[i].base; | ||
148 | #endif | ||
149 | mem_size += lmb_size; | ||
150 | size_mask |= lmb_size; | ||
151 | } | ||
152 | 125 | ||
153 | _lmb->memory.size = mem_size; | 126 | for (i = 0; i < lmb.memory.cnt; i++) |
127 | lmb.memory.size += lmb.memory.region[i].size; | ||
154 | } | 128 | } |
155 | 129 | ||
156 | /* This routine called with relocation disabled. */ | 130 | /* This routine called with relocation disabled. */ |
@@ -168,7 +142,6 @@ lmb_add_region(struct lmb_region *rgn, unsigned long base, unsigned long size) | |||
168 | adjacent = lmb_addrs_adjacent(base,size,rgnbase,rgnsize); | 142 | adjacent = lmb_addrs_adjacent(base,size,rgnbase,rgnsize); |
169 | if ( adjacent > 0 ) { | 143 | if ( adjacent > 0 ) { |
170 | rgn->region[i].base -= size; | 144 | rgn->region[i].base -= size; |
171 | rgn->region[i].physbase -= size; | ||
172 | rgn->region[i].size += size; | 145 | rgn->region[i].size += size; |
173 | coalesced++; | 146 | coalesced++; |
174 | break; | 147 | break; |
@@ -195,11 +168,9 @@ lmb_add_region(struct lmb_region *rgn, unsigned long base, unsigned long size) | |||
195 | for (i=rgn->cnt-1; i >= 0; i--) { | 168 | for (i=rgn->cnt-1; i >= 0; i--) { |
196 | if (base < rgn->region[i].base) { | 169 | if (base < rgn->region[i].base) { |
197 | rgn->region[i+1].base = rgn->region[i].base; | 170 | rgn->region[i+1].base = rgn->region[i].base; |
198 | rgn->region[i+1].physbase = rgn->region[i].physbase; | ||
199 | rgn->region[i+1].size = rgn->region[i].size; | 171 | rgn->region[i+1].size = rgn->region[i].size; |
200 | } else { | 172 | } else { |
201 | rgn->region[i+1].base = base; | 173 | rgn->region[i+1].base = base; |
202 | rgn->region[i+1].physbase = lmb_abs_to_phys(base); | ||
203 | rgn->region[i+1].size = size; | 174 | rgn->region[i+1].size = size; |
204 | break; | 175 | break; |
205 | } | 176 | } |
@@ -213,12 +184,11 @@ lmb_add_region(struct lmb_region *rgn, unsigned long base, unsigned long size) | |||
213 | long __init | 184 | long __init |
214 | lmb_add(unsigned long base, unsigned long size) | 185 | lmb_add(unsigned long base, unsigned long size) |
215 | { | 186 | { |
216 | struct lmb *_lmb = &lmb; | 187 | struct lmb_region *_rgn = &(lmb.memory); |
217 | struct lmb_region *_rgn = &(_lmb->memory); | ||
218 | 188 | ||
219 | /* On pSeries LPAR systems, the first LMB is our RMO region. */ | 189 | /* On pSeries LPAR systems, the first LMB is our RMO region. */ |
220 | if ( base == 0 ) | 190 | if ( base == 0 ) |
221 | _lmb->rmo_size = size; | 191 | lmb.rmo_size = size; |
222 | 192 | ||
223 | return lmb_add_region(_rgn, base, size); | 193 | return lmb_add_region(_rgn, base, size); |
224 | 194 | ||
@@ -227,8 +197,7 @@ lmb_add(unsigned long base, unsigned long size) | |||
227 | long __init | 197 | long __init |
228 | lmb_reserve(unsigned long base, unsigned long size) | 198 | lmb_reserve(unsigned long base, unsigned long size) |
229 | { | 199 | { |
230 | struct lmb *_lmb = &lmb; | 200 | struct lmb_region *_rgn = &(lmb.reserved); |
231 | struct lmb_region *_rgn = &(_lmb->reserved); | ||
232 | 201 | ||
233 | return lmb_add_region(_rgn, base, size); | 202 | return lmb_add_region(_rgn, base, size); |
234 | } | 203 | } |
@@ -260,13 +229,10 @@ lmb_alloc_base(unsigned long size, unsigned long align, unsigned long max_addr) | |||
260 | { | 229 | { |
261 | long i, j; | 230 | long i, j; |
262 | unsigned long base = 0; | 231 | unsigned long base = 0; |
263 | struct lmb *_lmb = &lmb; | ||
264 | struct lmb_region *_mem = &(_lmb->memory); | ||
265 | struct lmb_region *_rsv = &(_lmb->reserved); | ||
266 | 232 | ||
267 | for (i=_mem->cnt-1; i >= 0; i--) { | 233 | for (i=lmb.memory.cnt-1; i >= 0; i--) { |
268 | unsigned long lmbbase = _mem->region[i].base; | 234 | unsigned long lmbbase = lmb.memory.region[i].base; |
269 | unsigned long lmbsize = _mem->region[i].size; | 235 | unsigned long lmbsize = lmb.memory.region[i].size; |
270 | 236 | ||
271 | if ( max_addr == LMB_ALLOC_ANYWHERE ) | 237 | if ( max_addr == LMB_ALLOC_ANYWHERE ) |
272 | base = _ALIGN_DOWN(lmbbase+lmbsize-size, align); | 238 | base = _ALIGN_DOWN(lmbbase+lmbsize-size, align); |
@@ -276,8 +242,8 @@ lmb_alloc_base(unsigned long size, unsigned long align, unsigned long max_addr) | |||
276 | continue; | 242 | continue; |
277 | 243 | ||
278 | while ( (lmbbase <= base) && | 244 | while ( (lmbbase <= base) && |
279 | ((j = lmb_overlaps_region(_rsv,base,size)) >= 0) ) { | 245 | ((j = lmb_overlaps_region(&lmb.reserved,base,size)) >= 0) ) { |
280 | base = _ALIGN_DOWN(_rsv->region[j].base-size, align); | 246 | base = _ALIGN_DOWN(lmb.reserved.region[j].base-size, align); |
281 | } | 247 | } |
282 | 248 | ||
283 | if ( (base != 0) && (lmbbase <= base) ) | 249 | if ( (base != 0) && (lmbbase <= base) ) |
@@ -287,62 +253,24 @@ lmb_alloc_base(unsigned long size, unsigned long align, unsigned long max_addr) | |||
287 | if ( i < 0 ) | 253 | if ( i < 0 ) |
288 | return 0; | 254 | return 0; |
289 | 255 | ||
290 | lmb_add_region(_rsv, base, size); | 256 | lmb_add_region(&lmb.reserved, base, size); |
291 | 257 | ||
292 | return base; | 258 | return base; |
293 | } | 259 | } |
294 | 260 | ||
261 | /* You must call lmb_analyze() before this. */ | ||
295 | unsigned long __init | 262 | unsigned long __init |
296 | lmb_phys_mem_size(void) | 263 | lmb_phys_mem_size(void) |
297 | { | 264 | { |
298 | struct lmb *_lmb = &lmb; | 265 | return lmb.memory.size; |
299 | #ifdef CONFIG_MSCHUNKS | ||
300 | return _lmb->memory.size; | ||
301 | #else | ||
302 | struct lmb_region *_mem = &(_lmb->memory); | ||
303 | unsigned long total = 0; | ||
304 | int i; | ||
305 | |||
306 | /* add all physical memory to the bootmem map */ | ||
307 | for (i=0; i < _mem->cnt; i++) | ||
308 | total += _mem->region[i].size; | ||
309 | return total; | ||
310 | #endif /* CONFIG_MSCHUNKS */ | ||
311 | } | 266 | } |
312 | 267 | ||
313 | unsigned long __init | 268 | unsigned long __init |
314 | lmb_end_of_DRAM(void) | 269 | lmb_end_of_DRAM(void) |
315 | { | 270 | { |
316 | struct lmb *_lmb = &lmb; | 271 | int idx = lmb.memory.cnt - 1; |
317 | struct lmb_region *_mem = &(_lmb->memory); | ||
318 | int idx = _mem->cnt - 1; | ||
319 | |||
320 | #ifdef CONFIG_MSCHUNKS | ||
321 | return (_mem->region[idx].physbase + _mem->region[idx].size); | ||
322 | #else | ||
323 | return (_mem->region[idx].base + _mem->region[idx].size); | ||
324 | #endif /* CONFIG_MSCHUNKS */ | ||
325 | |||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | unsigned long __init | ||
330 | lmb_abs_to_phys(unsigned long aa) | ||
331 | { | ||
332 | unsigned long i, pa = aa; | ||
333 | struct lmb *_lmb = &lmb; | ||
334 | struct lmb_region *_mem = &(_lmb->memory); | ||
335 | |||
336 | for (i=0; i < _mem->cnt; i++) { | ||
337 | unsigned long lmbbase = _mem->region[i].base; | ||
338 | unsigned long lmbsize = _mem->region[i].size; | ||
339 | if ( lmb_addrs_overlap(aa,1,lmbbase,lmbsize) ) { | ||
340 | pa = _mem->region[i].physbase + (aa - lmbbase); | ||
341 | break; | ||
342 | } | ||
343 | } | ||
344 | 272 | ||
345 | return pa; | 273 | return (lmb.memory.region[idx].base + lmb.memory.region[idx].size); |
346 | } | 274 | } |
347 | 275 | ||
348 | /* | 276 | /* |
@@ -353,20 +281,19 @@ void __init lmb_enforce_memory_limit(void) | |||
353 | { | 281 | { |
354 | extern unsigned long memory_limit; | 282 | extern unsigned long memory_limit; |
355 | unsigned long i, limit; | 283 | unsigned long i, limit; |
356 | struct lmb_region *mem = &(lmb.memory); | ||
357 | 284 | ||
358 | if (! memory_limit) | 285 | if (! memory_limit) |
359 | return; | 286 | return; |
360 | 287 | ||
361 | limit = memory_limit; | 288 | limit = memory_limit; |
362 | for (i = 0; i < mem->cnt; i++) { | 289 | for (i = 0; i < lmb.memory.cnt; i++) { |
363 | if (limit > mem->region[i].size) { | 290 | if (limit > lmb.memory.region[i].size) { |
364 | limit -= mem->region[i].size; | 291 | limit -= lmb.memory.region[i].size; |
365 | continue; | 292 | continue; |
366 | } | 293 | } |
367 | 294 | ||
368 | mem->region[i].size = limit; | 295 | lmb.memory.region[i].size = limit; |
369 | mem->cnt = i + 1; | 296 | lmb.memory.cnt = i + 1; |
370 | break; | 297 | break; |
371 | } | 298 | } |
372 | } | 299 | } |
diff --git a/arch/ppc64/kernel/lparcfg.c b/arch/ppc64/kernel/lparcfg.c index 02e96627fa66..9d034ff062b1 100644 --- a/arch/ppc64/kernel/lparcfg.c +++ b/arch/ppc64/kernel/lparcfg.c | |||
@@ -29,7 +29,7 @@ | |||
29 | #include <asm/iSeries/HvLpConfig.h> | 29 | #include <asm/iSeries/HvLpConfig.h> |
30 | #include <asm/lppaca.h> | 30 | #include <asm/lppaca.h> |
31 | #include <asm/hvcall.h> | 31 | #include <asm/hvcall.h> |
32 | #include <asm/cputable.h> | 32 | #include <asm/firmware.h> |
33 | #include <asm/rtas.h> | 33 | #include <asm/rtas.h> |
34 | #include <asm/system.h> | 34 | #include <asm/system.h> |
35 | #include <asm/time.h> | 35 | #include <asm/time.h> |
@@ -377,7 +377,7 @@ static int lparcfg_data(struct seq_file *m, void *v) | |||
377 | 377 | ||
378 | partition_active_processors = lparcfg_count_active_processors(); | 378 | partition_active_processors = lparcfg_count_active_processors(); |
379 | 379 | ||
380 | if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) { | 380 | if (firmware_has_feature(FW_FEATURE_SPLPAR)) { |
381 | unsigned long h_entitled, h_unallocated; | 381 | unsigned long h_entitled, h_unallocated; |
382 | unsigned long h_aggregation, h_resource; | 382 | unsigned long h_aggregation, h_resource; |
383 | unsigned long pool_idle_time, pool_procs; | 383 | unsigned long pool_idle_time, pool_procs; |
@@ -571,7 +571,7 @@ int __init lparcfg_init(void) | |||
571 | mode_t mode = S_IRUSR; | 571 | mode_t mode = S_IRUSR; |
572 | 572 | ||
573 | /* Allow writing if we have FW_FEATURE_SPLPAR */ | 573 | /* Allow writing if we have FW_FEATURE_SPLPAR */ |
574 | if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) { | 574 | if (firmware_has_feature(FW_FEATURE_SPLPAR)) { |
575 | lparcfg_fops.write = lparcfg_write; | 575 | lparcfg_fops.write = lparcfg_write; |
576 | mode |= S_IWUSR; | 576 | mode |= S_IWUSR; |
577 | } | 577 | } |
diff --git a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S index a05b50b738e9..474df0a862bf 100644 --- a/arch/ppc64/kernel/misc.S +++ b/arch/ppc64/kernel/misc.S | |||
@@ -680,6 +680,104 @@ _GLOBAL(kernel_thread) | |||
680 | ld r30,-16(r1) | 680 | ld r30,-16(r1) |
681 | blr | 681 | blr |
682 | 682 | ||
683 | /* | ||
684 | * disable_kernel_fp() | ||
685 | * Disable the FPU. | ||
686 | */ | ||
687 | _GLOBAL(disable_kernel_fp) | ||
688 | mfmsr r3 | ||
689 | rldicl r0,r3,(63-MSR_FP_LG),1 | ||
690 | rldicl r3,r0,(MSR_FP_LG+1),0 | ||
691 | mtmsrd r3 /* disable use of fpu now */ | ||
692 | isync | ||
693 | blr | ||
694 | |||
695 | /* | ||
696 | * giveup_fpu(tsk) | ||
697 | * Disable FP for the task given as the argument, | ||
698 | * and save the floating-point registers in its thread_struct. | ||
699 | * Enables the FPU for use in the kernel on return. | ||
700 | */ | ||
701 | _GLOBAL(giveup_fpu) | ||
702 | mfmsr r5 | ||
703 | ori r5,r5,MSR_FP | ||
704 | mtmsrd r5 /* enable use of fpu now */ | ||
705 | isync | ||
706 | cmpdi 0,r3,0 | ||
707 | beqlr- /* if no previous owner, done */ | ||
708 | addi r3,r3,THREAD /* want THREAD of task */ | ||
709 | ld r5,PT_REGS(r3) | ||
710 | cmpdi 0,r5,0 | ||
711 | SAVE_32FPRS(0, r3) | ||
712 | mffs fr0 | ||
713 | stfd fr0,THREAD_FPSCR(r3) | ||
714 | beq 1f | ||
715 | ld r4,_MSR-STACK_FRAME_OVERHEAD(r5) | ||
716 | li r3,MSR_FP|MSR_FE0|MSR_FE1 | ||
717 | andc r4,r4,r3 /* disable FP for previous task */ | ||
718 | std r4,_MSR-STACK_FRAME_OVERHEAD(r5) | ||
719 | 1: | ||
720 | #ifndef CONFIG_SMP | ||
721 | li r5,0 | ||
722 | ld r4,last_task_used_math@got(r2) | ||
723 | std r5,0(r4) | ||
724 | #endif /* CONFIG_SMP */ | ||
725 | blr | ||
726 | |||
727 | #ifdef CONFIG_ALTIVEC | ||
728 | |||
729 | #if 0 /* this has no callers for now */ | ||
730 | /* | ||
731 | * disable_kernel_altivec() | ||
732 | * Disable the VMX. | ||
733 | */ | ||
734 | _GLOBAL(disable_kernel_altivec) | ||
735 | mfmsr r3 | ||
736 | rldicl r0,r3,(63-MSR_VEC_LG),1 | ||
737 | rldicl r3,r0,(MSR_VEC_LG+1),0 | ||
738 | mtmsrd r3 /* disable use of VMX now */ | ||
739 | isync | ||
740 | blr | ||
741 | #endif /* 0 */ | ||
742 | |||
743 | /* | ||
744 | * giveup_altivec(tsk) | ||
745 | * Disable VMX for the task given as the argument, | ||
746 | * and save the vector registers in its thread_struct. | ||
747 | * Enables the VMX for use in the kernel on return. | ||
748 | */ | ||
749 | _GLOBAL(giveup_altivec) | ||
750 | mfmsr r5 | ||
751 | oris r5,r5,MSR_VEC@h | ||
752 | mtmsrd r5 /* enable use of VMX now */ | ||
753 | isync | ||
754 | cmpdi 0,r3,0 | ||
755 | beqlr- /* if no previous owner, done */ | ||
756 | addi r3,r3,THREAD /* want THREAD of task */ | ||
757 | ld r5,PT_REGS(r3) | ||
758 | cmpdi 0,r5,0 | ||
759 | SAVE_32VRS(0,r4,r3) | ||
760 | mfvscr vr0 | ||
761 | li r4,THREAD_VSCR | ||
762 | stvx vr0,r4,r3 | ||
763 | beq 1f | ||
764 | ld r4,_MSR-STACK_FRAME_OVERHEAD(r5) | ||
765 | lis r3,MSR_VEC@h | ||
766 | andc r4,r4,r3 /* disable FP for previous task */ | ||
767 | std r4,_MSR-STACK_FRAME_OVERHEAD(r5) | ||
768 | 1: | ||
769 | #ifndef CONFIG_SMP | ||
770 | li r5,0 | ||
771 | ld r4,last_task_used_altivec@got(r2) | ||
772 | std r5,0(r4) | ||
773 | #endif /* CONFIG_SMP */ | ||
774 | blr | ||
775 | |||
776 | #endif /* CONFIG_ALTIVEC */ | ||
777 | |||
778 | _GLOBAL(__setup_cpu_power3) | ||
779 | blr | ||
780 | |||
683 | /* kexec_wait(phys_cpu) | 781 | /* kexec_wait(phys_cpu) |
684 | * | 782 | * |
685 | * wait for the flag to change, indicating this kernel is going away but | 783 | * wait for the flag to change, indicating this kernel is going away but |
diff --git a/arch/ppc64/kernel/pSeries_iommu.c b/arch/ppc64/kernel/pSeries_iommu.c index 69130522a87e..9d5e1e7fc389 100644 --- a/arch/ppc64/kernel/pSeries_iommu.c +++ b/arch/ppc64/kernel/pSeries_iommu.c | |||
@@ -45,6 +45,7 @@ | |||
45 | #include <asm/plpar_wrappers.h> | 45 | #include <asm/plpar_wrappers.h> |
46 | #include <asm/pSeries_reconfig.h> | 46 | #include <asm/pSeries_reconfig.h> |
47 | #include <asm/systemcfg.h> | 47 | #include <asm/systemcfg.h> |
48 | #include <asm/firmware.h> | ||
48 | #include "pci.h" | 49 | #include "pci.h" |
49 | 50 | ||
50 | #define DBG(fmt...) | 51 | #define DBG(fmt...) |
@@ -546,7 +547,7 @@ void iommu_init_early_pSeries(void) | |||
546 | } | 547 | } |
547 | 548 | ||
548 | if (systemcfg->platform & PLATFORM_LPAR) { | 549 | if (systemcfg->platform & PLATFORM_LPAR) { |
549 | if (cur_cpu_spec->firmware_features & FW_FEATURE_MULTITCE) { | 550 | if (firmware_has_feature(FW_FEATURE_MULTITCE)) { |
550 | ppc_md.tce_build = tce_buildmulti_pSeriesLP; | 551 | ppc_md.tce_build = tce_buildmulti_pSeriesLP; |
551 | ppc_md.tce_free = tce_freemulti_pSeriesLP; | 552 | ppc_md.tce_free = tce_freemulti_pSeriesLP; |
552 | } else { | 553 | } else { |
diff --git a/arch/ppc64/kernel/pSeries_lpar.c b/arch/ppc64/kernel/pSeries_lpar.c index 74dd144dcce8..0a3ddc9227c5 100644 --- a/arch/ppc64/kernel/pSeries_lpar.c +++ b/arch/ppc64/kernel/pSeries_lpar.c | |||
@@ -52,7 +52,6 @@ EXPORT_SYMBOL(plpar_hcall_4out); | |||
52 | EXPORT_SYMBOL(plpar_hcall_norets); | 52 | EXPORT_SYMBOL(plpar_hcall_norets); |
53 | EXPORT_SYMBOL(plpar_hcall_8arg_2ret); | 53 | EXPORT_SYMBOL(plpar_hcall_8arg_2ret); |
54 | 54 | ||
55 | extern void fw_feature_init(void); | ||
56 | extern void pSeries_find_serial_port(void); | 55 | extern void pSeries_find_serial_port(void); |
57 | 56 | ||
58 | 57 | ||
@@ -279,7 +278,6 @@ long pSeries_lpar_hpte_insert(unsigned long hpte_group, | |||
279 | unsigned long va, unsigned long prpn, | 278 | unsigned long va, unsigned long prpn, |
280 | unsigned long vflags, unsigned long rflags) | 279 | unsigned long vflags, unsigned long rflags) |
281 | { | 280 | { |
282 | unsigned long arpn = physRpn_to_absRpn(prpn); | ||
283 | unsigned long lpar_rc; | 281 | unsigned long lpar_rc; |
284 | unsigned long flags; | 282 | unsigned long flags; |
285 | unsigned long slot; | 283 | unsigned long slot; |
@@ -290,7 +288,7 @@ long pSeries_lpar_hpte_insert(unsigned long hpte_group, | |||
290 | if (vflags & HPTE_V_LARGE) | 288 | if (vflags & HPTE_V_LARGE) |
291 | hpte_v &= ~(1UL << HPTE_V_AVPN_SHIFT); | 289 | hpte_v &= ~(1UL << HPTE_V_AVPN_SHIFT); |
292 | 290 | ||
293 | hpte_r = (arpn << HPTE_R_RPN_SHIFT) | rflags; | 291 | hpte_r = (prpn << HPTE_R_RPN_SHIFT) | rflags; |
294 | 292 | ||
295 | /* Now fill in the actual HPTE */ | 293 | /* Now fill in the actual HPTE */ |
296 | /* Set CEC cookie to 0 */ | 294 | /* Set CEC cookie to 0 */ |
diff --git a/arch/ppc64/kernel/pSeries_setup.c b/arch/ppc64/kernel/pSeries_setup.c index 5bec956e44a0..f0f0630cf07c 100644 --- a/arch/ppc64/kernel/pSeries_setup.c +++ b/arch/ppc64/kernel/pSeries_setup.c | |||
@@ -60,7 +60,8 @@ | |||
60 | #include <asm/nvram.h> | 60 | #include <asm/nvram.h> |
61 | #include <asm/plpar_wrappers.h> | 61 | #include <asm/plpar_wrappers.h> |
62 | #include <asm/xics.h> | 62 | #include <asm/xics.h> |
63 | #include <asm/cputable.h> | 63 | #include <asm/firmware.h> |
64 | #include <asm/pmc.h> | ||
64 | 65 | ||
65 | #include "i8259.h" | 66 | #include "i8259.h" |
66 | #include "mpic.h" | 67 | #include "mpic.h" |
@@ -187,6 +188,21 @@ static void __init pSeries_setup_mpic(void) | |||
187 | " MPIC "); | 188 | " MPIC "); |
188 | } | 189 | } |
189 | 190 | ||
191 | static void pseries_lpar_enable_pmcs(void) | ||
192 | { | ||
193 | unsigned long set, reset; | ||
194 | |||
195 | power4_enable_pmcs(); | ||
196 | |||
197 | set = 1UL << 63; | ||
198 | reset = 0; | ||
199 | plpar_hcall_norets(H_PERFMON, set, reset); | ||
200 | |||
201 | /* instruct hypervisor to maintain PMCs */ | ||
202 | if (firmware_has_feature(FW_FEATURE_SPLPAR)) | ||
203 | get_paca()->lppaca.pmcregs_in_use = 1; | ||
204 | } | ||
205 | |||
190 | static void __init pSeries_setup_arch(void) | 206 | static void __init pSeries_setup_arch(void) |
191 | { | 207 | { |
192 | /* Fixup ppc_md depending on the type of interrupt controller */ | 208 | /* Fixup ppc_md depending on the type of interrupt controller */ |
@@ -231,11 +247,9 @@ static void __init pSeries_setup_arch(void) | |||
231 | 247 | ||
232 | pSeries_nvram_init(); | 248 | pSeries_nvram_init(); |
233 | 249 | ||
234 | if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) | ||
235 | vpa_init(boot_cpuid); | ||
236 | |||
237 | /* Choose an idle loop */ | 250 | /* Choose an idle loop */ |
238 | if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) { | 251 | if (firmware_has_feature(FW_FEATURE_SPLPAR)) { |
252 | vpa_init(boot_cpuid); | ||
239 | if (get_paca()->lppaca.shared_proc) { | 253 | if (get_paca()->lppaca.shared_proc) { |
240 | printk(KERN_INFO "Using shared processor idle loop\n"); | 254 | printk(KERN_INFO "Using shared processor idle loop\n"); |
241 | ppc_md.idle_loop = pseries_shared_idle; | 255 | ppc_md.idle_loop = pseries_shared_idle; |
@@ -247,6 +261,11 @@ static void __init pSeries_setup_arch(void) | |||
247 | printk(KERN_INFO "Using default idle loop\n"); | 261 | printk(KERN_INFO "Using default idle loop\n"); |
248 | ppc_md.idle_loop = default_idle; | 262 | ppc_md.idle_loop = default_idle; |
249 | } | 263 | } |
264 | |||
265 | if (systemcfg->platform & PLATFORM_LPAR) | ||
266 | ppc_md.enable_pmcs = pseries_lpar_enable_pmcs; | ||
267 | else | ||
268 | ppc_md.enable_pmcs = power4_enable_pmcs; | ||
250 | } | 269 | } |
251 | 270 | ||
252 | static int __init pSeries_init_panel(void) | 271 | static int __init pSeries_init_panel(void) |
@@ -260,11 +279,11 @@ static int __init pSeries_init_panel(void) | |||
260 | arch_initcall(pSeries_init_panel); | 279 | arch_initcall(pSeries_init_panel); |
261 | 280 | ||
262 | 281 | ||
263 | /* Build up the firmware_features bitmask field | 282 | /* Build up the ppc64_firmware_features bitmask field |
264 | * using contents of device-tree/ibm,hypertas-functions. | 283 | * using contents of device-tree/ibm,hypertas-functions. |
265 | * Ultimately this functionality may be moved into prom.c prom_init(). | 284 | * Ultimately this functionality may be moved into prom.c prom_init(). |
266 | */ | 285 | */ |
267 | void __init fw_feature_init(void) | 286 | static void __init fw_feature_init(void) |
268 | { | 287 | { |
269 | struct device_node * dn; | 288 | struct device_node * dn; |
270 | char * hypertas; | 289 | char * hypertas; |
@@ -272,7 +291,7 @@ void __init fw_feature_init(void) | |||
272 | 291 | ||
273 | DBG(" -> fw_feature_init()\n"); | 292 | DBG(" -> fw_feature_init()\n"); |
274 | 293 | ||
275 | cur_cpu_spec->firmware_features = 0; | 294 | ppc64_firmware_features = 0; |
276 | dn = of_find_node_by_path("/rtas"); | 295 | dn = of_find_node_by_path("/rtas"); |
277 | if (dn == NULL) { | 296 | if (dn == NULL) { |
278 | printk(KERN_ERR "WARNING ! Cannot find RTAS in device-tree !\n"); | 297 | printk(KERN_ERR "WARNING ! Cannot find RTAS in device-tree !\n"); |
@@ -288,7 +307,7 @@ void __init fw_feature_init(void) | |||
288 | if ((firmware_features_table[i].name) && | 307 | if ((firmware_features_table[i].name) && |
289 | (strcmp(firmware_features_table[i].name,hypertas))==0) { | 308 | (strcmp(firmware_features_table[i].name,hypertas))==0) { |
290 | /* we have a match */ | 309 | /* we have a match */ |
291 | cur_cpu_spec->firmware_features |= | 310 | ppc64_firmware_features |= |
292 | (firmware_features_table[i].val); | 311 | (firmware_features_table[i].val); |
293 | break; | 312 | break; |
294 | } | 313 | } |
@@ -302,7 +321,7 @@ void __init fw_feature_init(void) | |||
302 | of_node_put(dn); | 321 | of_node_put(dn); |
303 | no_rtas: | 322 | no_rtas: |
304 | printk(KERN_INFO "firmware_features = 0x%lx\n", | 323 | printk(KERN_INFO "firmware_features = 0x%lx\n", |
305 | cur_cpu_spec->firmware_features); | 324 | ppc64_firmware_features); |
306 | 325 | ||
307 | DBG(" <- fw_feature_init()\n"); | 326 | DBG(" <- fw_feature_init()\n"); |
308 | } | 327 | } |
diff --git a/arch/ppc64/kernel/pSeries_smp.c b/arch/ppc64/kernel/pSeries_smp.c index 62c55a123560..79c7f3223665 100644 --- a/arch/ppc64/kernel/pSeries_smp.c +++ b/arch/ppc64/kernel/pSeries_smp.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include <asm/machdep.h> | 41 | #include <asm/machdep.h> |
42 | #include <asm/xics.h> | 42 | #include <asm/xics.h> |
43 | #include <asm/cputable.h> | 43 | #include <asm/cputable.h> |
44 | #include <asm/firmware.h> | ||
44 | #include <asm/system.h> | 45 | #include <asm/system.h> |
45 | #include <asm/rtas.h> | 46 | #include <asm/rtas.h> |
46 | #include <asm/plpar_wrappers.h> | 47 | #include <asm/plpar_wrappers.h> |
@@ -326,7 +327,7 @@ static void __devinit smp_xics_setup_cpu(int cpu) | |||
326 | if (cpu != boot_cpuid) | 327 | if (cpu != boot_cpuid) |
327 | xics_setup_cpu(); | 328 | xics_setup_cpu(); |
328 | 329 | ||
329 | if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) | 330 | if (firmware_has_feature(FW_FEATURE_SPLPAR)) |
330 | vpa_init(cpu); | 331 | vpa_init(cpu); |
331 | 332 | ||
332 | cpu_clear(cpu, of_spin_map); | 333 | cpu_clear(cpu, of_spin_map); |
diff --git a/arch/ppc64/kernel/pSeries_vio.c b/arch/ppc64/kernel/pSeries_vio.c new file mode 100644 index 000000000000..338f9e1bdc09 --- /dev/null +++ b/arch/ppc64/kernel/pSeries_vio.c | |||
@@ -0,0 +1,266 @@ | |||
1 | /* | ||
2 | * IBM PowerPC pSeries Virtual I/O Infrastructure Support. | ||
3 | * | ||
4 | * Copyright (c) 2003-2005 IBM Corp. | ||
5 | * Dave Engebretsen engebret@us.ibm.com | ||
6 | * Santiago Leon santil@us.ibm.com | ||
7 | * Hollis Blanchard <hollisb@us.ibm.com> | ||
8 | * Stephen Rothwell | ||
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 <linux/init.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/mm.h> | ||
19 | #include <linux/kobject.h> | ||
20 | #include <asm/iommu.h> | ||
21 | #include <asm/dma.h> | ||
22 | #include <asm/vio.h> | ||
23 | #include <asm/hvcall.h> | ||
24 | |||
25 | extern struct subsystem devices_subsys; /* needed for vio_find_name() */ | ||
26 | |||
27 | static void probe_bus_pseries(void) | ||
28 | { | ||
29 | struct device_node *node_vroot, *of_node; | ||
30 | |||
31 | node_vroot = find_devices("vdevice"); | ||
32 | if ((node_vroot == NULL) || (node_vroot->child == NULL)) | ||
33 | /* this machine doesn't do virtual IO, and that's ok */ | ||
34 | return; | ||
35 | |||
36 | /* | ||
37 | * Create struct vio_devices for each virtual device in the device tree. | ||
38 | * Drivers will associate with them later. | ||
39 | */ | ||
40 | for (of_node = node_vroot->child; of_node != NULL; | ||
41 | of_node = of_node->sibling) { | ||
42 | printk(KERN_DEBUG "%s: processing %p\n", __FUNCTION__, of_node); | ||
43 | vio_register_device_node(of_node); | ||
44 | } | ||
45 | } | ||
46 | |||
47 | /** | ||
48 | * vio_match_device_pseries: - Tell if a pSeries VIO device matches a | ||
49 | * vio_device_id | ||
50 | */ | ||
51 | static int vio_match_device_pseries(const struct vio_device_id *id, | ||
52 | const struct vio_dev *dev) | ||
53 | { | ||
54 | return (strncmp(dev->type, id->type, strlen(id->type)) == 0) && | ||
55 | device_is_compatible(dev->dev.platform_data, id->compat); | ||
56 | } | ||
57 | |||
58 | static void vio_release_device_pseries(struct device *dev) | ||
59 | { | ||
60 | /* XXX free TCE table */ | ||
61 | of_node_put(dev->platform_data); | ||
62 | } | ||
63 | |||
64 | static ssize_t viodev_show_devspec(struct device *dev, | ||
65 | struct device_attribute *attr, char *buf) | ||
66 | { | ||
67 | struct device_node *of_node = dev->platform_data; | ||
68 | |||
69 | return sprintf(buf, "%s\n", of_node->full_name); | ||
70 | } | ||
71 | DEVICE_ATTR(devspec, S_IRUSR | S_IRGRP | S_IROTH, viodev_show_devspec, NULL); | ||
72 | |||
73 | static void vio_unregister_device_pseries(struct vio_dev *viodev) | ||
74 | { | ||
75 | device_remove_file(&viodev->dev, &dev_attr_devspec); | ||
76 | } | ||
77 | |||
78 | /** | ||
79 | * vio_bus_init_pseries: - Initialize the pSeries virtual IO bus | ||
80 | */ | ||
81 | static int __init vio_bus_init_pseries(void) | ||
82 | { | ||
83 | int err; | ||
84 | |||
85 | err = vio_bus_init(vio_match_device_pseries, | ||
86 | vio_unregister_device_pseries, | ||
87 | vio_release_device_pseries); | ||
88 | if (err == 0) | ||
89 | probe_bus_pseries(); | ||
90 | return err; | ||
91 | } | ||
92 | |||
93 | __initcall(vio_bus_init_pseries); | ||
94 | |||
95 | /** | ||
96 | * vio_build_iommu_table: - gets the dma information from OF and | ||
97 | * builds the TCE tree. | ||
98 | * @dev: the virtual device. | ||
99 | * | ||
100 | * Returns a pointer to the built tce tree, or NULL if it can't | ||
101 | * find property. | ||
102 | */ | ||
103 | static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev) | ||
104 | { | ||
105 | unsigned int *dma_window; | ||
106 | struct iommu_table *newTceTable; | ||
107 | unsigned long offset; | ||
108 | int dma_window_property_size; | ||
109 | |||
110 | dma_window = (unsigned int *) get_property(dev->dev.platform_data, "ibm,my-dma-window", &dma_window_property_size); | ||
111 | if(!dma_window) { | ||
112 | return NULL; | ||
113 | } | ||
114 | |||
115 | newTceTable = (struct iommu_table *) kmalloc(sizeof(struct iommu_table), GFP_KERNEL); | ||
116 | |||
117 | /* There should be some code to extract the phys-encoded offset | ||
118 | using prom_n_addr_cells(). However, according to a comment | ||
119 | on earlier versions, it's always zero, so we don't bother */ | ||
120 | offset = dma_window[1] >> PAGE_SHIFT; | ||
121 | |||
122 | /* TCE table size - measured in tce entries */ | ||
123 | newTceTable->it_size = dma_window[4] >> PAGE_SHIFT; | ||
124 | /* offset for VIO should always be 0 */ | ||
125 | newTceTable->it_offset = offset; | ||
126 | newTceTable->it_busno = 0; | ||
127 | newTceTable->it_index = (unsigned long)dma_window[0]; | ||
128 | newTceTable->it_type = TCE_VB; | ||
129 | |||
130 | return iommu_init_table(newTceTable); | ||
131 | } | ||
132 | |||
133 | /** | ||
134 | * vio_register_device_node: - Register a new vio device. | ||
135 | * @of_node: The OF node for this device. | ||
136 | * | ||
137 | * Creates and initializes a vio_dev structure from the data in | ||
138 | * of_node (dev.platform_data) and adds it to the list of virtual devices. | ||
139 | * Returns a pointer to the created vio_dev or NULL if node has | ||
140 | * NULL device_type or compatible fields. | ||
141 | */ | ||
142 | struct vio_dev * __devinit vio_register_device_node(struct device_node *of_node) | ||
143 | { | ||
144 | struct vio_dev *viodev; | ||
145 | unsigned int *unit_address; | ||
146 | unsigned int *irq_p; | ||
147 | |||
148 | /* we need the 'device_type' property, in order to match with drivers */ | ||
149 | if ((NULL == of_node->type)) { | ||
150 | printk(KERN_WARNING | ||
151 | "%s: node %s missing 'device_type'\n", __FUNCTION__, | ||
152 | of_node->name ? of_node->name : "<unknown>"); | ||
153 | return NULL; | ||
154 | } | ||
155 | |||
156 | unit_address = (unsigned int *)get_property(of_node, "reg", NULL); | ||
157 | if (!unit_address) { | ||
158 | printk(KERN_WARNING "%s: node %s missing 'reg'\n", __FUNCTION__, | ||
159 | of_node->name ? of_node->name : "<unknown>"); | ||
160 | return NULL; | ||
161 | } | ||
162 | |||
163 | /* allocate a vio_dev for this node */ | ||
164 | viodev = kmalloc(sizeof(struct vio_dev), GFP_KERNEL); | ||
165 | if (!viodev) { | ||
166 | return NULL; | ||
167 | } | ||
168 | memset(viodev, 0, sizeof(struct vio_dev)); | ||
169 | |||
170 | viodev->dev.platform_data = of_node_get(of_node); | ||
171 | |||
172 | viodev->irq = NO_IRQ; | ||
173 | irq_p = (unsigned int *)get_property(of_node, "interrupts", NULL); | ||
174 | if (irq_p) { | ||
175 | int virq = virt_irq_create_mapping(*irq_p); | ||
176 | if (virq == NO_IRQ) { | ||
177 | printk(KERN_ERR "Unable to allocate interrupt " | ||
178 | "number for %s\n", of_node->full_name); | ||
179 | } else | ||
180 | viodev->irq = irq_offset_up(virq); | ||
181 | } | ||
182 | |||
183 | snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%x", *unit_address); | ||
184 | |||
185 | /* register with generic device framework */ | ||
186 | if (vio_register_device_common(viodev, of_node->name, of_node->type, | ||
187 | *unit_address, vio_build_iommu_table(viodev)) | ||
188 | == NULL) { | ||
189 | /* XXX free TCE table */ | ||
190 | kfree(viodev); | ||
191 | return NULL; | ||
192 | } | ||
193 | device_create_file(&viodev->dev, &dev_attr_devspec); | ||
194 | |||
195 | return viodev; | ||
196 | } | ||
197 | EXPORT_SYMBOL(vio_register_device_node); | ||
198 | |||
199 | /** | ||
200 | * vio_get_attribute: - get attribute for virtual device | ||
201 | * @vdev: The vio device to get property. | ||
202 | * @which: The property/attribute to be extracted. | ||
203 | * @length: Pointer to length of returned data size (unused if NULL). | ||
204 | * | ||
205 | * Calls prom.c's get_property() to return the value of the | ||
206 | * attribute specified by the preprocessor constant @which | ||
207 | */ | ||
208 | const void * vio_get_attribute(struct vio_dev *vdev, void* which, int* length) | ||
209 | { | ||
210 | return get_property(vdev->dev.platform_data, (char*)which, length); | ||
211 | } | ||
212 | EXPORT_SYMBOL(vio_get_attribute); | ||
213 | |||
214 | /* vio_find_name() - internal because only vio.c knows how we formatted the | ||
215 | * kobject name | ||
216 | * XXX once vio_bus_type.devices is actually used as a kset in | ||
217 | * drivers/base/bus.c, this function should be removed in favor of | ||
218 | * "device_find(kobj_name, &vio_bus_type)" | ||
219 | */ | ||
220 | static struct vio_dev *vio_find_name(const char *kobj_name) | ||
221 | { | ||
222 | struct kobject *found; | ||
223 | |||
224 | found = kset_find_obj(&devices_subsys.kset, kobj_name); | ||
225 | if (!found) | ||
226 | return NULL; | ||
227 | |||
228 | return to_vio_dev(container_of(found, struct device, kobj)); | ||
229 | } | ||
230 | |||
231 | /** | ||
232 | * vio_find_node - find an already-registered vio_dev | ||
233 | * @vnode: device_node of the virtual device we're looking for | ||
234 | */ | ||
235 | struct vio_dev *vio_find_node(struct device_node *vnode) | ||
236 | { | ||
237 | uint32_t *unit_address; | ||
238 | char kobj_name[BUS_ID_SIZE]; | ||
239 | |||
240 | /* construct the kobject name from the device node */ | ||
241 | unit_address = (uint32_t *)get_property(vnode, "reg", NULL); | ||
242 | if (!unit_address) | ||
243 | return NULL; | ||
244 | snprintf(kobj_name, BUS_ID_SIZE, "%x", *unit_address); | ||
245 | |||
246 | return vio_find_name(kobj_name); | ||
247 | } | ||
248 | EXPORT_SYMBOL(vio_find_node); | ||
249 | |||
250 | int vio_enable_interrupts(struct vio_dev *dev) | ||
251 | { | ||
252 | int rc = h_vio_signal(dev->unit_address, VIO_IRQ_ENABLE); | ||
253 | if (rc != H_Success) | ||
254 | printk(KERN_ERR "vio: Error 0x%x enabling interrupts\n", rc); | ||
255 | return rc; | ||
256 | } | ||
257 | EXPORT_SYMBOL(vio_enable_interrupts); | ||
258 | |||
259 | int vio_disable_interrupts(struct vio_dev *dev) | ||
260 | { | ||
261 | int rc = h_vio_signal(dev->unit_address, VIO_IRQ_DISABLE); | ||
262 | if (rc != H_Success) | ||
263 | printk(KERN_ERR "vio: Error 0x%x disabling interrupts\n", rc); | ||
264 | return rc; | ||
265 | } | ||
266 | EXPORT_SYMBOL(vio_disable_interrupts); | ||
diff --git a/arch/ppc64/kernel/pacaData.c b/arch/ppc64/kernel/pacaData.c index 6316188737b6..6182a2cd90a5 100644 --- a/arch/ppc64/kernel/pacaData.c +++ b/arch/ppc64/kernel/pacaData.c | |||
@@ -78,7 +78,7 @@ extern unsigned long __toc_start; | |||
78 | 78 | ||
79 | #define BOOTCPU_PACA_INIT(number) \ | 79 | #define BOOTCPU_PACA_INIT(number) \ |
80 | { \ | 80 | { \ |
81 | PACA_INIT_COMMON(number, 1, 0, STAB0_VIRT_ADDR) \ | 81 | PACA_INIT_COMMON(number, 1, 0, (u64)&initial_stab) \ |
82 | PACA_INIT_ISERIES(number) \ | 82 | PACA_INIT_ISERIES(number) \ |
83 | } | 83 | } |
84 | 84 | ||
@@ -90,7 +90,7 @@ extern unsigned long __toc_start; | |||
90 | 90 | ||
91 | #define BOOTCPU_PACA_INIT(number) \ | 91 | #define BOOTCPU_PACA_INIT(number) \ |
92 | { \ | 92 | { \ |
93 | PACA_INIT_COMMON(number, 1, STAB0_PHYS_ADDR, STAB0_VIRT_ADDR) \ | 93 | PACA_INIT_COMMON(number, 1, STAB0_PHYS_ADDR, (u64)&initial_stab) \ |
94 | } | 94 | } |
95 | #endif | 95 | #endif |
96 | 96 | ||
diff --git a/arch/ppc64/kernel/pmac_setup.c b/arch/ppc64/kernel/pmac_setup.c index e40877fa67cd..8ff86a766cdf 100644 --- a/arch/ppc64/kernel/pmac_setup.c +++ b/arch/ppc64/kernel/pmac_setup.c | |||
@@ -71,6 +71,7 @@ | |||
71 | #include <asm/of_device.h> | 71 | #include <asm/of_device.h> |
72 | #include <asm/lmb.h> | 72 | #include <asm/lmb.h> |
73 | #include <asm/smu.h> | 73 | #include <asm/smu.h> |
74 | #include <asm/pmc.h> | ||
74 | 75 | ||
75 | #include "pmac.h" | 76 | #include "pmac.h" |
76 | #include "mpic.h" | 77 | #include "mpic.h" |
@@ -511,4 +512,5 @@ struct machdep_calls __initdata pmac_md = { | |||
511 | .progress = pmac_progress, | 512 | .progress = pmac_progress, |
512 | .check_legacy_ioport = pmac_check_legacy_ioport, | 513 | .check_legacy_ioport = pmac_check_legacy_ioport, |
513 | .idle_loop = native_idle, | 514 | .idle_loop = native_idle, |
515 | .enable_pmcs = power4_enable_pmcs, | ||
514 | }; | 516 | }; |
diff --git a/arch/ppc64/kernel/pmc.c b/arch/ppc64/kernel/pmc.c index 67be773f9c00..cdfec7438d01 100644 --- a/arch/ppc64/kernel/pmc.c +++ b/arch/ppc64/kernel/pmc.c | |||
@@ -65,3 +65,24 @@ void release_pmc_hardware(void) | |||
65 | spin_unlock(&pmc_owner_lock); | 65 | spin_unlock(&pmc_owner_lock); |
66 | } | 66 | } |
67 | EXPORT_SYMBOL_GPL(release_pmc_hardware); | 67 | EXPORT_SYMBOL_GPL(release_pmc_hardware); |
68 | |||
69 | void power4_enable_pmcs(void) | ||
70 | { | ||
71 | unsigned long hid0; | ||
72 | |||
73 | hid0 = mfspr(HID0); | ||
74 | hid0 |= 1UL << (63 - 20); | ||
75 | |||
76 | /* POWER4 requires the following sequence */ | ||
77 | asm volatile( | ||
78 | "sync\n" | ||
79 | "mtspr %1, %0\n" | ||
80 | "mfspr %0, %1\n" | ||
81 | "mfspr %0, %1\n" | ||
82 | "mfspr %0, %1\n" | ||
83 | "mfspr %0, %1\n" | ||
84 | "mfspr %0, %1\n" | ||
85 | "mfspr %0, %1\n" | ||
86 | "isync" : "=&r" (hid0) : "i" (HID0), "0" (hid0): | ||
87 | "memory"); | ||
88 | } | ||
diff --git a/arch/ppc64/kernel/process.c b/arch/ppc64/kernel/process.c index f7cae05e40fb..7a7e027653ad 100644 --- a/arch/ppc64/kernel/process.c +++ b/arch/ppc64/kernel/process.c | |||
@@ -50,6 +50,7 @@ | |||
50 | #include <asm/machdep.h> | 50 | #include <asm/machdep.h> |
51 | #include <asm/iSeries/HvCallHpt.h> | 51 | #include <asm/iSeries/HvCallHpt.h> |
52 | #include <asm/cputable.h> | 52 | #include <asm/cputable.h> |
53 | #include <asm/firmware.h> | ||
53 | #include <asm/sections.h> | 54 | #include <asm/sections.h> |
54 | #include <asm/tlbflush.h> | 55 | #include <asm/tlbflush.h> |
55 | #include <asm/time.h> | 56 | #include <asm/time.h> |
@@ -202,11 +203,10 @@ struct task_struct *__switch_to(struct task_struct *prev, | |||
202 | new_thread = &new->thread; | 203 | new_thread = &new->thread; |
203 | old_thread = ¤t->thread; | 204 | old_thread = ¤t->thread; |
204 | 205 | ||
205 | /* Collect purr utilization data per process and per processor wise */ | 206 | /* Collect purr utilization data per process and per processor |
206 | /* purr is nothing but processor time base */ | 207 | * wise purr is nothing but processor time base |
207 | 208 | */ | |
208 | #if defined(CONFIG_PPC_PSERIES) | 209 | if (firmware_has_feature(FW_FEATURE_SPLPAR)) { |
209 | if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) { | ||
210 | struct cpu_usage *cu = &__get_cpu_var(cpu_usage_array); | 210 | struct cpu_usage *cu = &__get_cpu_var(cpu_usage_array); |
211 | long unsigned start_tb, current_tb; | 211 | long unsigned start_tb, current_tb; |
212 | start_tb = old_thread->start_tb; | 212 | start_tb = old_thread->start_tb; |
@@ -214,8 +214,6 @@ struct task_struct *__switch_to(struct task_struct *prev, | |||
214 | old_thread->accum_tb += (current_tb - start_tb); | 214 | old_thread->accum_tb += (current_tb - start_tb); |
215 | new_thread->start_tb = current_tb; | 215 | new_thread->start_tb = current_tb; |
216 | } | 216 | } |
217 | #endif | ||
218 | |||
219 | 217 | ||
220 | local_irq_save(flags); | 218 | local_irq_save(flags); |
221 | last = _switch(old_thread, new_thread); | 219 | last = _switch(old_thread, new_thread); |
diff --git a/arch/ppc64/kernel/prom.c b/arch/ppc64/kernel/prom.c index 5aca01ddd81f..b21848826791 100644 --- a/arch/ppc64/kernel/prom.c +++ b/arch/ppc64/kernel/prom.c | |||
@@ -625,8 +625,8 @@ void __init finish_device_tree(void) | |||
625 | 625 | ||
626 | static inline char *find_flat_dt_string(u32 offset) | 626 | static inline char *find_flat_dt_string(u32 offset) |
627 | { | 627 | { |
628 | return ((char *)initial_boot_params) + initial_boot_params->off_dt_strings | 628 | return ((char *)initial_boot_params) + |
629 | + offset; | 629 | initial_boot_params->off_dt_strings + offset; |
630 | } | 630 | } |
631 | 631 | ||
632 | /** | 632 | /** |
@@ -635,26 +635,33 @@ static inline char *find_flat_dt_string(u32 offset) | |||
635 | * unflatten the tree | 635 | * unflatten the tree |
636 | */ | 636 | */ |
637 | static int __init scan_flat_dt(int (*it)(unsigned long node, | 637 | static int __init scan_flat_dt(int (*it)(unsigned long node, |
638 | const char *full_path, void *data), | 638 | const char *uname, int depth, |
639 | void *data), | ||
639 | void *data) | 640 | void *data) |
640 | { | 641 | { |
641 | unsigned long p = ((unsigned long)initial_boot_params) + | 642 | unsigned long p = ((unsigned long)initial_boot_params) + |
642 | initial_boot_params->off_dt_struct; | 643 | initial_boot_params->off_dt_struct; |
643 | int rc = 0; | 644 | int rc = 0; |
645 | int depth = -1; | ||
644 | 646 | ||
645 | do { | 647 | do { |
646 | u32 tag = *((u32 *)p); | 648 | u32 tag = *((u32 *)p); |
647 | char *pathp; | 649 | char *pathp; |
648 | 650 | ||
649 | p += 4; | 651 | p += 4; |
650 | if (tag == OF_DT_END_NODE) | 652 | if (tag == OF_DT_END_NODE) { |
653 | depth --; | ||
654 | continue; | ||
655 | } | ||
656 | if (tag == OF_DT_NOP) | ||
651 | continue; | 657 | continue; |
652 | if (tag == OF_DT_END) | 658 | if (tag == OF_DT_END) |
653 | break; | 659 | break; |
654 | if (tag == OF_DT_PROP) { | 660 | if (tag == OF_DT_PROP) { |
655 | u32 sz = *((u32 *)p); | 661 | u32 sz = *((u32 *)p); |
656 | p += 8; | 662 | p += 8; |
657 | p = _ALIGN(p, sz >= 8 ? 8 : 4); | 663 | if (initial_boot_params->version < 0x10) |
664 | p = _ALIGN(p, sz >= 8 ? 8 : 4); | ||
658 | p += sz; | 665 | p += sz; |
659 | p = _ALIGN(p, 4); | 666 | p = _ALIGN(p, 4); |
660 | continue; | 667 | continue; |
@@ -664,9 +671,18 @@ static int __init scan_flat_dt(int (*it)(unsigned long node, | |||
664 | " device tree !\n", tag); | 671 | " device tree !\n", tag); |
665 | return -EINVAL; | 672 | return -EINVAL; |
666 | } | 673 | } |
674 | depth++; | ||
667 | pathp = (char *)p; | 675 | pathp = (char *)p; |
668 | p = _ALIGN(p + strlen(pathp) + 1, 4); | 676 | p = _ALIGN(p + strlen(pathp) + 1, 4); |
669 | rc = it(p, pathp, data); | 677 | if ((*pathp) == '/') { |
678 | char *lp, *np; | ||
679 | for (lp = NULL, np = pathp; *np; np++) | ||
680 | if ((*np) == '/') | ||
681 | lp = np+1; | ||
682 | if (lp != NULL) | ||
683 | pathp = lp; | ||
684 | } | ||
685 | rc = it(p, pathp, depth, data); | ||
670 | if (rc != 0) | 686 | if (rc != 0) |
671 | break; | 687 | break; |
672 | } while(1); | 688 | } while(1); |
@@ -689,17 +705,21 @@ static void* __init get_flat_dt_prop(unsigned long node, const char *name, | |||
689 | const char *nstr; | 705 | const char *nstr; |
690 | 706 | ||
691 | p += 4; | 707 | p += 4; |
708 | if (tag == OF_DT_NOP) | ||
709 | continue; | ||
692 | if (tag != OF_DT_PROP) | 710 | if (tag != OF_DT_PROP) |
693 | return NULL; | 711 | return NULL; |
694 | 712 | ||
695 | sz = *((u32 *)p); | 713 | sz = *((u32 *)p); |
696 | noff = *((u32 *)(p + 4)); | 714 | noff = *((u32 *)(p + 4)); |
697 | p += 8; | 715 | p += 8; |
698 | p = _ALIGN(p, sz >= 8 ? 8 : 4); | 716 | if (initial_boot_params->version < 0x10) |
717 | p = _ALIGN(p, sz >= 8 ? 8 : 4); | ||
699 | 718 | ||
700 | nstr = find_flat_dt_string(noff); | 719 | nstr = find_flat_dt_string(noff); |
701 | if (nstr == NULL) { | 720 | if (nstr == NULL) { |
702 | printk(KERN_WARNING "Can't find property index name !\n"); | 721 | printk(KERN_WARNING "Can't find property index" |
722 | " name !\n"); | ||
703 | return NULL; | 723 | return NULL; |
704 | } | 724 | } |
705 | if (strcmp(name, nstr) == 0) { | 725 | if (strcmp(name, nstr) == 0) { |
@@ -713,7 +733,7 @@ static void* __init get_flat_dt_prop(unsigned long node, const char *name, | |||
713 | } | 733 | } |
714 | 734 | ||
715 | static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size, | 735 | static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size, |
716 | unsigned long align) | 736 | unsigned long align) |
717 | { | 737 | { |
718 | void *res; | 738 | void *res; |
719 | 739 | ||
@@ -727,13 +747,16 @@ static void *__init unflatten_dt_alloc(unsigned long *mem, unsigned long size, | |||
727 | static unsigned long __init unflatten_dt_node(unsigned long mem, | 747 | static unsigned long __init unflatten_dt_node(unsigned long mem, |
728 | unsigned long *p, | 748 | unsigned long *p, |
729 | struct device_node *dad, | 749 | struct device_node *dad, |
730 | struct device_node ***allnextpp) | 750 | struct device_node ***allnextpp, |
751 | unsigned long fpsize) | ||
731 | { | 752 | { |
732 | struct device_node *np; | 753 | struct device_node *np; |
733 | struct property *pp, **prev_pp = NULL; | 754 | struct property *pp, **prev_pp = NULL; |
734 | char *pathp; | 755 | char *pathp; |
735 | u32 tag; | 756 | u32 tag; |
736 | unsigned int l; | 757 | unsigned int l, allocl; |
758 | int has_name = 0; | ||
759 | int new_format = 0; | ||
737 | 760 | ||
738 | tag = *((u32 *)(*p)); | 761 | tag = *((u32 *)(*p)); |
739 | if (tag != OF_DT_BEGIN_NODE) { | 762 | if (tag != OF_DT_BEGIN_NODE) { |
@@ -742,21 +765,62 @@ static unsigned long __init unflatten_dt_node(unsigned long mem, | |||
742 | } | 765 | } |
743 | *p += 4; | 766 | *p += 4; |
744 | pathp = (char *)*p; | 767 | pathp = (char *)*p; |
745 | l = strlen(pathp) + 1; | 768 | l = allocl = strlen(pathp) + 1; |
746 | *p = _ALIGN(*p + l, 4); | 769 | *p = _ALIGN(*p + l, 4); |
747 | 770 | ||
748 | np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + l, | 771 | /* version 0x10 has a more compact unit name here instead of the full |
772 | * path. we accumulate the full path size using "fpsize", we'll rebuild | ||
773 | * it later. We detect this because the first character of the name is | ||
774 | * not '/'. | ||
775 | */ | ||
776 | if ((*pathp) != '/') { | ||
777 | new_format = 1; | ||
778 | if (fpsize == 0) { | ||
779 | /* root node: special case. fpsize accounts for path | ||
780 | * plus terminating zero. root node only has '/', so | ||
781 | * fpsize should be 2, but we want to avoid the first | ||
782 | * level nodes to have two '/' so we use fpsize 1 here | ||
783 | */ | ||
784 | fpsize = 1; | ||
785 | allocl = 2; | ||
786 | } else { | ||
787 | /* account for '/' and path size minus terminal 0 | ||
788 | * already in 'l' | ||
789 | */ | ||
790 | fpsize += l; | ||
791 | allocl = fpsize; | ||
792 | } | ||
793 | } | ||
794 | |||
795 | |||
796 | np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl, | ||
749 | __alignof__(struct device_node)); | 797 | __alignof__(struct device_node)); |
750 | if (allnextpp) { | 798 | if (allnextpp) { |
751 | memset(np, 0, sizeof(*np)); | 799 | memset(np, 0, sizeof(*np)); |
752 | np->full_name = ((char*)np) + sizeof(struct device_node); | 800 | np->full_name = ((char*)np) + sizeof(struct device_node); |
753 | memcpy(np->full_name, pathp, l); | 801 | if (new_format) { |
802 | char *p = np->full_name; | ||
803 | /* rebuild full path for new format */ | ||
804 | if (dad && dad->parent) { | ||
805 | strcpy(p, dad->full_name); | ||
806 | #ifdef DEBUG | ||
807 | if ((strlen(p) + l + 1) != allocl) { | ||
808 | DBG("%s: p: %d, l: %d, a: %d\n", | ||
809 | pathp, strlen(p), l, allocl); | ||
810 | } | ||
811 | #endif | ||
812 | p += strlen(p); | ||
813 | } | ||
814 | *(p++) = '/'; | ||
815 | memcpy(p, pathp, l); | ||
816 | } else | ||
817 | memcpy(np->full_name, pathp, l); | ||
754 | prev_pp = &np->properties; | 818 | prev_pp = &np->properties; |
755 | **allnextpp = np; | 819 | **allnextpp = np; |
756 | *allnextpp = &np->allnext; | 820 | *allnextpp = &np->allnext; |
757 | if (dad != NULL) { | 821 | if (dad != NULL) { |
758 | np->parent = dad; | 822 | np->parent = dad; |
759 | /* we temporarily use the `next' field as `last_child'. */ | 823 | /* we temporarily use the next field as `last_child'*/ |
760 | if (dad->next == 0) | 824 | if (dad->next == 0) |
761 | dad->child = np; | 825 | dad->child = np; |
762 | else | 826 | else |
@@ -770,18 +834,26 @@ static unsigned long __init unflatten_dt_node(unsigned long mem, | |||
770 | char *pname; | 834 | char *pname; |
771 | 835 | ||
772 | tag = *((u32 *)(*p)); | 836 | tag = *((u32 *)(*p)); |
837 | if (tag == OF_DT_NOP) { | ||
838 | *p += 4; | ||
839 | continue; | ||
840 | } | ||
773 | if (tag != OF_DT_PROP) | 841 | if (tag != OF_DT_PROP) |
774 | break; | 842 | break; |
775 | *p += 4; | 843 | *p += 4; |
776 | sz = *((u32 *)(*p)); | 844 | sz = *((u32 *)(*p)); |
777 | noff = *((u32 *)((*p) + 4)); | 845 | noff = *((u32 *)((*p) + 4)); |
778 | *p = _ALIGN((*p) + 8, sz >= 8 ? 8 : 4); | 846 | *p += 8; |
847 | if (initial_boot_params->version < 0x10) | ||
848 | *p = _ALIGN(*p, sz >= 8 ? 8 : 4); | ||
779 | 849 | ||
780 | pname = find_flat_dt_string(noff); | 850 | pname = find_flat_dt_string(noff); |
781 | if (pname == NULL) { | 851 | if (pname == NULL) { |
782 | printk("Can't find property name in list !\n"); | 852 | printk("Can't find property name in list !\n"); |
783 | break; | 853 | break; |
784 | } | 854 | } |
855 | if (strcmp(pname, "name") == 0) | ||
856 | has_name = 1; | ||
785 | l = strlen(pname) + 1; | 857 | l = strlen(pname) + 1; |
786 | pp = unflatten_dt_alloc(&mem, sizeof(struct property), | 858 | pp = unflatten_dt_alloc(&mem, sizeof(struct property), |
787 | __alignof__(struct property)); | 859 | __alignof__(struct property)); |
@@ -801,6 +873,36 @@ static unsigned long __init unflatten_dt_node(unsigned long mem, | |||
801 | } | 873 | } |
802 | *p = _ALIGN((*p) + sz, 4); | 874 | *p = _ALIGN((*p) + sz, 4); |
803 | } | 875 | } |
876 | /* with version 0x10 we may not have the name property, recreate | ||
877 | * it here from the unit name if absent | ||
878 | */ | ||
879 | if (!has_name) { | ||
880 | char *p = pathp, *ps = pathp, *pa = NULL; | ||
881 | int sz; | ||
882 | |||
883 | while (*p) { | ||
884 | if ((*p) == '@') | ||
885 | pa = p; | ||
886 | if ((*p) == '/') | ||
887 | ps = p + 1; | ||
888 | p++; | ||
889 | } | ||
890 | if (pa < ps) | ||
891 | pa = p; | ||
892 | sz = (pa - ps) + 1; | ||
893 | pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz, | ||
894 | __alignof__(struct property)); | ||
895 | if (allnextpp) { | ||
896 | pp->name = "name"; | ||
897 | pp->length = sz; | ||
898 | pp->value = (unsigned char *)(pp + 1); | ||
899 | *prev_pp = pp; | ||
900 | prev_pp = &pp->next; | ||
901 | memcpy(pp->value, ps, sz - 1); | ||
902 | ((char *)pp->value)[sz - 1] = 0; | ||
903 | DBG("fixed up name for %s -> %s\n", pathp, pp->value); | ||
904 | } | ||
905 | } | ||
804 | if (allnextpp) { | 906 | if (allnextpp) { |
805 | *prev_pp = NULL; | 907 | *prev_pp = NULL; |
806 | np->name = get_property(np, "name", NULL); | 908 | np->name = get_property(np, "name", NULL); |
@@ -812,11 +914,11 @@ static unsigned long __init unflatten_dt_node(unsigned long mem, | |||
812 | np->type = "<NULL>"; | 914 | np->type = "<NULL>"; |
813 | } | 915 | } |
814 | while (tag == OF_DT_BEGIN_NODE) { | 916 | while (tag == OF_DT_BEGIN_NODE) { |
815 | mem = unflatten_dt_node(mem, p, np, allnextpp); | 917 | mem = unflatten_dt_node(mem, p, np, allnextpp, fpsize); |
816 | tag = *((u32 *)(*p)); | 918 | tag = *((u32 *)(*p)); |
817 | } | 919 | } |
818 | if (tag != OF_DT_END_NODE) { | 920 | if (tag != OF_DT_END_NODE) { |
819 | printk("Weird tag at start of node: %x\n", tag); | 921 | printk("Weird tag at end of node: %x\n", tag); |
820 | return mem; | 922 | return mem; |
821 | } | 923 | } |
822 | *p += 4; | 924 | *p += 4; |
@@ -842,21 +944,32 @@ void __init unflatten_device_tree(void) | |||
842 | /* First pass, scan for size */ | 944 | /* First pass, scan for size */ |
843 | start = ((unsigned long)initial_boot_params) + | 945 | start = ((unsigned long)initial_boot_params) + |
844 | initial_boot_params->off_dt_struct; | 946 | initial_boot_params->off_dt_struct; |
845 | size = unflatten_dt_node(0, &start, NULL, NULL); | 947 | size = unflatten_dt_node(0, &start, NULL, NULL, 0); |
948 | size = (size | 3) + 1; | ||
846 | 949 | ||
847 | DBG(" size is %lx, allocating...\n", size); | 950 | DBG(" size is %lx, allocating...\n", size); |
848 | 951 | ||
849 | /* Allocate memory for the expanded device tree */ | 952 | /* Allocate memory for the expanded device tree */ |
850 | mem = (unsigned long)abs_to_virt(lmb_alloc(size, | 953 | mem = lmb_alloc(size + 4, __alignof__(struct device_node)); |
851 | __alignof__(struct device_node))); | 954 | if (!mem) { |
955 | DBG("Couldn't allocate memory with lmb_alloc()!\n"); | ||
956 | panic("Couldn't allocate memory with lmb_alloc()!\n"); | ||
957 | } | ||
958 | mem = (unsigned long)abs_to_virt(mem); | ||
959 | |||
960 | ((u32 *)mem)[size / 4] = 0xdeadbeef; | ||
961 | |||
852 | DBG(" unflattening...\n", mem); | 962 | DBG(" unflattening...\n", mem); |
853 | 963 | ||
854 | /* Second pass, do actual unflattening */ | 964 | /* Second pass, do actual unflattening */ |
855 | start = ((unsigned long)initial_boot_params) + | 965 | start = ((unsigned long)initial_boot_params) + |
856 | initial_boot_params->off_dt_struct; | 966 | initial_boot_params->off_dt_struct; |
857 | unflatten_dt_node(mem, &start, NULL, &allnextp); | 967 | unflatten_dt_node(mem, &start, NULL, &allnextp, 0); |
858 | if (*((u32 *)start) != OF_DT_END) | 968 | if (*((u32 *)start) != OF_DT_END) |
859 | printk(KERN_WARNING "Weird tag at end of tree: %x\n", *((u32 *)start)); | 969 | printk(KERN_WARNING "Weird tag at end of tree: %08x\n", *((u32 *)start)); |
970 | if (((u32 *)mem)[size / 4] != 0xdeadbeef) | ||
971 | printk(KERN_WARNING "End of tree marker overwritten: %08x\n", | ||
972 | ((u32 *)mem)[size / 4] ); | ||
860 | *allnextp = NULL; | 973 | *allnextp = NULL; |
861 | 974 | ||
862 | /* Get pointer to OF "/chosen" node for use everywhere */ | 975 | /* Get pointer to OF "/chosen" node for use everywhere */ |
@@ -880,7 +993,7 @@ void __init unflatten_device_tree(void) | |||
880 | 993 | ||
881 | 994 | ||
882 | static int __init early_init_dt_scan_cpus(unsigned long node, | 995 | static int __init early_init_dt_scan_cpus(unsigned long node, |
883 | const char *full_path, void *data) | 996 | const char *uname, int depth, void *data) |
884 | { | 997 | { |
885 | char *type = get_flat_dt_prop(node, "device_type", NULL); | 998 | char *type = get_flat_dt_prop(node, "device_type", NULL); |
886 | u32 *prop; | 999 | u32 *prop; |
@@ -947,13 +1060,15 @@ static int __init early_init_dt_scan_cpus(unsigned long node, | |||
947 | } | 1060 | } |
948 | 1061 | ||
949 | static int __init early_init_dt_scan_chosen(unsigned long node, | 1062 | static int __init early_init_dt_scan_chosen(unsigned long node, |
950 | const char *full_path, void *data) | 1063 | const char *uname, int depth, void *data) |
951 | { | 1064 | { |
952 | u32 *prop; | 1065 | u32 *prop; |
953 | u64 *prop64; | 1066 | u64 *prop64; |
954 | extern unsigned long memory_limit, tce_alloc_start, tce_alloc_end; | 1067 | extern unsigned long memory_limit, tce_alloc_start, tce_alloc_end; |
955 | 1068 | ||
956 | if (strcmp(full_path, "/chosen") != 0) | 1069 | DBG("search \"chosen\", depth: %d, uname: %s\n", depth, uname); |
1070 | |||
1071 | if (depth != 1 || strcmp(uname, "chosen") != 0) | ||
957 | return 0; | 1072 | return 0; |
958 | 1073 | ||
959 | /* get platform type */ | 1074 | /* get platform type */ |
@@ -1003,18 +1118,20 @@ static int __init early_init_dt_scan_chosen(unsigned long node, | |||
1003 | } | 1118 | } |
1004 | 1119 | ||
1005 | static int __init early_init_dt_scan_root(unsigned long node, | 1120 | static int __init early_init_dt_scan_root(unsigned long node, |
1006 | const char *full_path, void *data) | 1121 | const char *uname, int depth, void *data) |
1007 | { | 1122 | { |
1008 | u32 *prop; | 1123 | u32 *prop; |
1009 | 1124 | ||
1010 | if (strcmp(full_path, "/") != 0) | 1125 | if (depth != 0) |
1011 | return 0; | 1126 | return 0; |
1012 | 1127 | ||
1013 | prop = (u32 *)get_flat_dt_prop(node, "#size-cells", NULL); | 1128 | prop = (u32 *)get_flat_dt_prop(node, "#size-cells", NULL); |
1014 | dt_root_size_cells = (prop == NULL) ? 1 : *prop; | 1129 | dt_root_size_cells = (prop == NULL) ? 1 : *prop; |
1015 | 1130 | DBG("dt_root_size_cells = %x\n", dt_root_size_cells); | |
1131 | |||
1016 | prop = (u32 *)get_flat_dt_prop(node, "#address-cells", NULL); | 1132 | prop = (u32 *)get_flat_dt_prop(node, "#address-cells", NULL); |
1017 | dt_root_addr_cells = (prop == NULL) ? 2 : *prop; | 1133 | dt_root_addr_cells = (prop == NULL) ? 2 : *prop; |
1134 | DBG("dt_root_addr_cells = %x\n", dt_root_addr_cells); | ||
1018 | 1135 | ||
1019 | /* break now */ | 1136 | /* break now */ |
1020 | return 1; | 1137 | return 1; |
@@ -1042,7 +1159,7 @@ static unsigned long __init dt_mem_next_cell(int s, cell_t **cellp) | |||
1042 | 1159 | ||
1043 | 1160 | ||
1044 | static int __init early_init_dt_scan_memory(unsigned long node, | 1161 | static int __init early_init_dt_scan_memory(unsigned long node, |
1045 | const char *full_path, void *data) | 1162 | const char *uname, int depth, void *data) |
1046 | { | 1163 | { |
1047 | char *type = get_flat_dt_prop(node, "device_type", NULL); | 1164 | char *type = get_flat_dt_prop(node, "device_type", NULL); |
1048 | cell_t *reg, *endp; | 1165 | cell_t *reg, *endp; |
@@ -1058,7 +1175,9 @@ static int __init early_init_dt_scan_memory(unsigned long node, | |||
1058 | 1175 | ||
1059 | endp = reg + (l / sizeof(cell_t)); | 1176 | endp = reg + (l / sizeof(cell_t)); |
1060 | 1177 | ||
1061 | DBG("memory scan node %s ...\n", full_path); | 1178 | DBG("memory scan node %s ..., reg size %ld, data: %x %x %x %x, ...\n", |
1179 | uname, l, reg[0], reg[1], reg[2], reg[3]); | ||
1180 | |||
1062 | while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) { | 1181 | while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) { |
1063 | unsigned long base, size; | 1182 | unsigned long base, size; |
1064 | 1183 | ||
@@ -1469,10 +1588,11 @@ struct device_node *of_find_node_by_path(const char *path) | |||
1469 | struct device_node *np = allnodes; | 1588 | struct device_node *np = allnodes; |
1470 | 1589 | ||
1471 | read_lock(&devtree_lock); | 1590 | read_lock(&devtree_lock); |
1472 | for (; np != 0; np = np->allnext) | 1591 | for (; np != 0; np = np->allnext) { |
1473 | if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0 | 1592 | if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0 |
1474 | && of_node_get(np)) | 1593 | && of_node_get(np)) |
1475 | break; | 1594 | break; |
1595 | } | ||
1476 | read_unlock(&devtree_lock); | 1596 | read_unlock(&devtree_lock); |
1477 | return np; | 1597 | return np; |
1478 | } | 1598 | } |
diff --git a/arch/ppc64/kernel/prom_init.c b/arch/ppc64/kernel/prom_init.c index dbbe6c79d8da..adcf972711fc 100644 --- a/arch/ppc64/kernel/prom_init.c +++ b/arch/ppc64/kernel/prom_init.c | |||
@@ -1534,7 +1534,8 @@ static unsigned long __init dt_find_string(char *str) | |||
1534 | */ | 1534 | */ |
1535 | #define MAX_PROPERTY_NAME 64 | 1535 | #define MAX_PROPERTY_NAME 64 |
1536 | 1536 | ||
1537 | static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start, | 1537 | static void __init scan_dt_build_strings(phandle node, |
1538 | unsigned long *mem_start, | ||
1538 | unsigned long *mem_end) | 1539 | unsigned long *mem_end) |
1539 | { | 1540 | { |
1540 | unsigned long offset = reloc_offset(); | 1541 | unsigned long offset = reloc_offset(); |
@@ -1547,16 +1548,21 @@ static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start, | |||
1547 | /* get and store all property names */ | 1548 | /* get and store all property names */ |
1548 | prev_name = RELOC(""); | 1549 | prev_name = RELOC(""); |
1549 | for (;;) { | 1550 | for (;;) { |
1550 | int rc; | ||
1551 | |||
1552 | /* 64 is max len of name including nul. */ | 1551 | /* 64 is max len of name including nul. */ |
1553 | namep = make_room(mem_start, mem_end, MAX_PROPERTY_NAME, 1); | 1552 | namep = make_room(mem_start, mem_end, MAX_PROPERTY_NAME, 1); |
1554 | rc = call_prom("nextprop", 3, 1, node, prev_name, namep); | 1553 | if (call_prom("nextprop", 3, 1, node, prev_name, namep) != 1) { |
1555 | if (rc != 1) { | ||
1556 | /* No more nodes: unwind alloc */ | 1554 | /* No more nodes: unwind alloc */ |
1557 | *mem_start = (unsigned long)namep; | 1555 | *mem_start = (unsigned long)namep; |
1558 | break; | 1556 | break; |
1559 | } | 1557 | } |
1558 | |||
1559 | /* skip "name" */ | ||
1560 | if (strcmp(namep, RELOC("name")) == 0) { | ||
1561 | *mem_start = (unsigned long)namep; | ||
1562 | prev_name = RELOC("name"); | ||
1563 | continue; | ||
1564 | } | ||
1565 | /* get/create string entry */ | ||
1560 | soff = dt_find_string(namep); | 1566 | soff = dt_find_string(namep); |
1561 | if (soff != 0) { | 1567 | if (soff != 0) { |
1562 | *mem_start = (unsigned long)namep; | 1568 | *mem_start = (unsigned long)namep; |
@@ -1571,7 +1577,7 @@ static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start, | |||
1571 | 1577 | ||
1572 | /* do all our children */ | 1578 | /* do all our children */ |
1573 | child = call_prom("child", 1, 1, node); | 1579 | child = call_prom("child", 1, 1, node); |
1574 | while (child != (phandle)0) { | 1580 | while (child != 0) { |
1575 | scan_dt_build_strings(child, mem_start, mem_end); | 1581 | scan_dt_build_strings(child, mem_start, mem_end); |
1576 | child = call_prom("peer", 1, 1, child); | 1582 | child = call_prom("peer", 1, 1, child); |
1577 | } | 1583 | } |
@@ -1580,16 +1586,13 @@ static void __init scan_dt_build_strings(phandle node, unsigned long *mem_start, | |||
1580 | static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, | 1586 | static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, |
1581 | unsigned long *mem_end) | 1587 | unsigned long *mem_end) |
1582 | { | 1588 | { |
1583 | int l, align; | ||
1584 | phandle child; | 1589 | phandle child; |
1585 | char *namep, *prev_name, *sstart, *p, *ep; | 1590 | char *namep, *prev_name, *sstart, *p, *ep, *lp, *path; |
1586 | unsigned long soff; | 1591 | unsigned long soff; |
1587 | unsigned char *valp; | 1592 | unsigned char *valp; |
1588 | unsigned long offset = reloc_offset(); | 1593 | unsigned long offset = reloc_offset(); |
1589 | char pname[MAX_PROPERTY_NAME]; | 1594 | static char pname[MAX_PROPERTY_NAME]; |
1590 | char *path; | 1595 | int l; |
1591 | |||
1592 | path = RELOC(prom_scratch); | ||
1593 | 1596 | ||
1594 | dt_push_token(OF_DT_BEGIN_NODE, mem_start, mem_end); | 1597 | dt_push_token(OF_DT_BEGIN_NODE, mem_start, mem_end); |
1595 | 1598 | ||
@@ -1599,23 +1602,33 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, | |||
1599 | namep, *mem_end - *mem_start); | 1602 | namep, *mem_end - *mem_start); |
1600 | if (l >= 0) { | 1603 | if (l >= 0) { |
1601 | /* Didn't fit? Get more room. */ | 1604 | /* Didn't fit? Get more room. */ |
1602 | if (l+1 > *mem_end - *mem_start) { | 1605 | if ((l+1) > (*mem_end - *mem_start)) { |
1603 | namep = make_room(mem_start, mem_end, l+1, 1); | 1606 | namep = make_room(mem_start, mem_end, l+1, 1); |
1604 | call_prom("package-to-path", 3, 1, node, namep, l); | 1607 | call_prom("package-to-path", 3, 1, node, namep, l); |
1605 | } | 1608 | } |
1606 | namep[l] = '\0'; | 1609 | namep[l] = '\0'; |
1610 | |||
1607 | /* Fixup an Apple bug where they have bogus \0 chars in the | 1611 | /* Fixup an Apple bug where they have bogus \0 chars in the |
1608 | * middle of the path in some properties | 1612 | * middle of the path in some properties |
1609 | */ | 1613 | */ |
1610 | for (p = namep, ep = namep + l; p < ep; p++) | 1614 | for (p = namep, ep = namep + l; p < ep; p++) |
1611 | if (*p == '\0') { | 1615 | if (*p == '\0') { |
1612 | memmove(p, p+1, ep - p); | 1616 | memmove(p, p+1, ep - p); |
1613 | ep--; l--; | 1617 | ep--; l--; p--; |
1614 | } | 1618 | } |
1615 | *mem_start = _ALIGN(((unsigned long) namep) + strlen(namep) + 1, 4); | 1619 | |
1620 | /* now try to extract the unit name in that mess */ | ||
1621 | for (p = namep, lp = NULL; *p; p++) | ||
1622 | if (*p == '/') | ||
1623 | lp = p + 1; | ||
1624 | if (lp != NULL) | ||
1625 | memmove(namep, lp, strlen(lp) + 1); | ||
1626 | *mem_start = _ALIGN(((unsigned long) namep) + | ||
1627 | strlen(namep) + 1, 4); | ||
1616 | } | 1628 | } |
1617 | 1629 | ||
1618 | /* get it again for debugging */ | 1630 | /* get it again for debugging */ |
1631 | path = RELOC(prom_scratch); | ||
1619 | memset(path, 0, PROM_SCRATCH_SIZE); | 1632 | memset(path, 0, PROM_SCRATCH_SIZE); |
1620 | call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-1); | 1633 | call_prom("package-to-path", 3, 1, node, path, PROM_SCRATCH_SIZE-1); |
1621 | 1634 | ||
@@ -1623,23 +1636,27 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, | |||
1623 | prev_name = RELOC(""); | 1636 | prev_name = RELOC(""); |
1624 | sstart = (char *)RELOC(dt_string_start); | 1637 | sstart = (char *)RELOC(dt_string_start); |
1625 | for (;;) { | 1638 | for (;;) { |
1626 | int rc; | 1639 | if (call_prom("nextprop", 3, 1, node, prev_name, |
1627 | 1640 | RELOC(pname)) != 1) | |
1628 | rc = call_prom("nextprop", 3, 1, node, prev_name, pname); | ||
1629 | if (rc != 1) | ||
1630 | break; | 1641 | break; |
1631 | 1642 | ||
1643 | /* skip "name" */ | ||
1644 | if (strcmp(RELOC(pname), RELOC("name")) == 0) { | ||
1645 | prev_name = RELOC("name"); | ||
1646 | continue; | ||
1647 | } | ||
1648 | |||
1632 | /* find string offset */ | 1649 | /* find string offset */ |
1633 | soff = dt_find_string(pname); | 1650 | soff = dt_find_string(RELOC(pname)); |
1634 | if (soff == 0) { | 1651 | if (soff == 0) { |
1635 | prom_printf("WARNING: Can't find string index for <%s>, node %s\n", | 1652 | prom_printf("WARNING: Can't find string index for" |
1636 | pname, path); | 1653 | " <%s>, node %s\n", RELOC(pname), path); |
1637 | break; | 1654 | break; |
1638 | } | 1655 | } |
1639 | prev_name = sstart + soff; | 1656 | prev_name = sstart + soff; |
1640 | 1657 | ||
1641 | /* get length */ | 1658 | /* get length */ |
1642 | l = call_prom("getproplen", 2, 1, node, pname); | 1659 | l = call_prom("getproplen", 2, 1, node, RELOC(pname)); |
1643 | 1660 | ||
1644 | /* sanity checks */ | 1661 | /* sanity checks */ |
1645 | if (l == PROM_ERROR) | 1662 | if (l == PROM_ERROR) |
@@ -1648,7 +1665,7 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, | |||
1648 | prom_printf("WARNING: ignoring large property "); | 1665 | prom_printf("WARNING: ignoring large property "); |
1649 | /* It seems OF doesn't null-terminate the path :-( */ | 1666 | /* It seems OF doesn't null-terminate the path :-( */ |
1650 | prom_printf("[%s] ", path); | 1667 | prom_printf("[%s] ", path); |
1651 | prom_printf("%s length 0x%x\n", pname, l); | 1668 | prom_printf("%s length 0x%x\n", RELOC(pname), l); |
1652 | continue; | 1669 | continue; |
1653 | } | 1670 | } |
1654 | 1671 | ||
@@ -1658,17 +1675,16 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, | |||
1658 | dt_push_token(soff, mem_start, mem_end); | 1675 | dt_push_token(soff, mem_start, mem_end); |
1659 | 1676 | ||
1660 | /* push property content */ | 1677 | /* push property content */ |
1661 | align = (l >= 8) ? 8 : 4; | 1678 | valp = make_room(mem_start, mem_end, l, 4); |
1662 | valp = make_room(mem_start, mem_end, l, align); | 1679 | call_prom("getprop", 4, 1, node, RELOC(pname), valp, l); |
1663 | call_prom("getprop", 4, 1, node, pname, valp, l); | ||
1664 | *mem_start = _ALIGN(*mem_start, 4); | 1680 | *mem_start = _ALIGN(*mem_start, 4); |
1665 | } | 1681 | } |
1666 | 1682 | ||
1667 | /* Add a "linux,phandle" property. */ | 1683 | /* Add a "linux,phandle" property. */ |
1668 | soff = dt_find_string(RELOC("linux,phandle")); | 1684 | soff = dt_find_string(RELOC("linux,phandle")); |
1669 | if (soff == 0) | 1685 | if (soff == 0) |
1670 | prom_printf("WARNING: Can't find string index for <linux-phandle>" | 1686 | prom_printf("WARNING: Can't find string index for" |
1671 | " node %s\n", path); | 1687 | " <linux-phandle> node %s\n", path); |
1672 | else { | 1688 | else { |
1673 | dt_push_token(OF_DT_PROP, mem_start, mem_end); | 1689 | dt_push_token(OF_DT_PROP, mem_start, mem_end); |
1674 | dt_push_token(4, mem_start, mem_end); | 1690 | dt_push_token(4, mem_start, mem_end); |
@@ -1679,7 +1695,7 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start, | |||
1679 | 1695 | ||
1680 | /* do all our children */ | 1696 | /* do all our children */ |
1681 | child = call_prom("child", 1, 1, node); | 1697 | child = call_prom("child", 1, 1, node); |
1682 | while (child != (phandle)0) { | 1698 | while (child != 0) { |
1683 | scan_dt_build_struct(child, mem_start, mem_end); | 1699 | scan_dt_build_struct(child, mem_start, mem_end); |
1684 | child = call_prom("peer", 1, 1, child); | 1700 | child = call_prom("peer", 1, 1, child); |
1685 | } | 1701 | } |
@@ -1718,7 +1734,8 @@ static void __init flatten_device_tree(void) | |||
1718 | 1734 | ||
1719 | /* Build header and make room for mem rsv map */ | 1735 | /* Build header and make room for mem rsv map */ |
1720 | mem_start = _ALIGN(mem_start, 4); | 1736 | mem_start = _ALIGN(mem_start, 4); |
1721 | hdr = make_room(&mem_start, &mem_end, sizeof(struct boot_param_header), 4); | 1737 | hdr = make_room(&mem_start, &mem_end, |
1738 | sizeof(struct boot_param_header), 4); | ||
1722 | RELOC(dt_header_start) = (unsigned long)hdr; | 1739 | RELOC(dt_header_start) = (unsigned long)hdr; |
1723 | rsvmap = make_room(&mem_start, &mem_end, sizeof(mem_reserve_map), 8); | 1740 | rsvmap = make_room(&mem_start, &mem_end, sizeof(mem_reserve_map), 8); |
1724 | 1741 | ||
@@ -1731,11 +1748,11 @@ static void __init flatten_device_tree(void) | |||
1731 | namep = make_room(&mem_start, &mem_end, 16, 1); | 1748 | namep = make_room(&mem_start, &mem_end, 16, 1); |
1732 | strcpy(namep, RELOC("linux,phandle")); | 1749 | strcpy(namep, RELOC("linux,phandle")); |
1733 | mem_start = (unsigned long)namep + strlen(namep) + 1; | 1750 | mem_start = (unsigned long)namep + strlen(namep) + 1; |
1734 | RELOC(dt_string_end) = mem_start; | ||
1735 | 1751 | ||
1736 | /* Build string array */ | 1752 | /* Build string array */ |
1737 | prom_printf("Building dt strings...\n"); | 1753 | prom_printf("Building dt strings...\n"); |
1738 | scan_dt_build_strings(root, &mem_start, &mem_end); | 1754 | scan_dt_build_strings(root, &mem_start, &mem_end); |
1755 | RELOC(dt_string_end) = mem_start; | ||
1739 | 1756 | ||
1740 | /* Build structure */ | 1757 | /* Build structure */ |
1741 | mem_start = PAGE_ALIGN(mem_start); | 1758 | mem_start = PAGE_ALIGN(mem_start); |
@@ -1750,9 +1767,11 @@ static void __init flatten_device_tree(void) | |||
1750 | hdr->totalsize = RELOC(dt_struct_end) - RELOC(dt_header_start); | 1767 | hdr->totalsize = RELOC(dt_struct_end) - RELOC(dt_header_start); |
1751 | hdr->off_dt_struct = RELOC(dt_struct_start) - RELOC(dt_header_start); | 1768 | hdr->off_dt_struct = RELOC(dt_struct_start) - RELOC(dt_header_start); |
1752 | hdr->off_dt_strings = RELOC(dt_string_start) - RELOC(dt_header_start); | 1769 | hdr->off_dt_strings = RELOC(dt_string_start) - RELOC(dt_header_start); |
1770 | hdr->dt_strings_size = RELOC(dt_string_end) - RELOC(dt_string_start); | ||
1753 | hdr->off_mem_rsvmap = ((unsigned long)rsvmap) - RELOC(dt_header_start); | 1771 | hdr->off_mem_rsvmap = ((unsigned long)rsvmap) - RELOC(dt_header_start); |
1754 | hdr->version = OF_DT_VERSION; | 1772 | hdr->version = OF_DT_VERSION; |
1755 | hdr->last_comp_version = 1; | 1773 | /* Version 16 is not backward compatible */ |
1774 | hdr->last_comp_version = 0x10; | ||
1756 | 1775 | ||
1757 | /* Reserve the whole thing and copy the reserve map in, we | 1776 | /* Reserve the whole thing and copy the reserve map in, we |
1758 | * also bump mem_reserve_cnt to cause further reservations to | 1777 | * also bump mem_reserve_cnt to cause further reservations to |
@@ -1808,6 +1827,9 @@ static void __init fixup_device_tree(void) | |||
1808 | /* does it need fixup ? */ | 1827 | /* does it need fixup ? */ |
1809 | if (prom_getproplen(i2c, "interrupts") > 0) | 1828 | if (prom_getproplen(i2c, "interrupts") > 0) |
1810 | return; | 1829 | return; |
1830 | |||
1831 | prom_printf("fixing up bogus interrupts for u3 i2c...\n"); | ||
1832 | |||
1811 | /* interrupt on this revision of u3 is number 0 and level */ | 1833 | /* interrupt on this revision of u3 is number 0 and level */ |
1812 | interrupts[0] = 0; | 1834 | interrupts[0] = 0; |
1813 | interrupts[1] = 1; | 1835 | interrupts[1] = 1; |
diff --git a/arch/ppc64/kernel/rtas_pci.c b/arch/ppc64/kernel/rtas_pci.c index 1048817befb8..1dccadaddd1d 100644 --- a/arch/ppc64/kernel/rtas_pci.c +++ b/arch/ppc64/kernel/rtas_pci.c | |||
@@ -58,6 +58,21 @@ static int config_access_valid(struct device_node *dn, int where) | |||
58 | return 0; | 58 | return 0; |
59 | } | 59 | } |
60 | 60 | ||
61 | static int of_device_available(struct device_node * dn) | ||
62 | { | ||
63 | char * status; | ||
64 | |||
65 | status = get_property(dn, "status", NULL); | ||
66 | |||
67 | if (!status) | ||
68 | return 1; | ||
69 | |||
70 | if (!strcmp(status, "okay")) | ||
71 | return 1; | ||
72 | |||
73 | return 0; | ||
74 | } | ||
75 | |||
61 | static int rtas_read_config(struct device_node *dn, int where, int size, u32 *val) | 76 | static int rtas_read_config(struct device_node *dn, int where, int size, u32 *val) |
62 | { | 77 | { |
63 | int returnval = -1; | 78 | int returnval = -1; |
@@ -103,7 +118,7 @@ static int rtas_pci_read_config(struct pci_bus *bus, | |||
103 | 118 | ||
104 | /* Search only direct children of the bus */ | 119 | /* Search only direct children of the bus */ |
105 | for (dn = busdn->child; dn; dn = dn->sibling) | 120 | for (dn = busdn->child; dn; dn = dn->sibling) |
106 | if (dn->devfn == devfn) | 121 | if (dn->devfn == devfn && of_device_available(dn)) |
107 | return rtas_read_config(dn, where, size, val); | 122 | return rtas_read_config(dn, where, size, val); |
108 | return PCIBIOS_DEVICE_NOT_FOUND; | 123 | return PCIBIOS_DEVICE_NOT_FOUND; |
109 | } | 124 | } |
@@ -146,7 +161,7 @@ static int rtas_pci_write_config(struct pci_bus *bus, | |||
146 | 161 | ||
147 | /* Search only direct children of the bus */ | 162 | /* Search only direct children of the bus */ |
148 | for (dn = busdn->child; dn; dn = dn->sibling) | 163 | for (dn = busdn->child; dn; dn = dn->sibling) |
149 | if (dn->devfn == devfn) | 164 | if (dn->devfn == devfn && of_device_available(dn)) |
150 | return rtas_write_config(dn, where, size, val); | 165 | return rtas_write_config(dn, where, size, val); |
151 | return PCIBIOS_DEVICE_NOT_FOUND; | 166 | return PCIBIOS_DEVICE_NOT_FOUND; |
152 | } | 167 | } |
diff --git a/arch/ppc64/kernel/setup.c b/arch/ppc64/kernel/setup.c index e9c24d2dbd91..ee3b20de2e7a 100644 --- a/arch/ppc64/kernel/setup.c +++ b/arch/ppc64/kernel/setup.c | |||
@@ -536,15 +536,19 @@ static void __init check_for_initrd(void) | |||
536 | 536 | ||
537 | DBG(" -> check_for_initrd()\n"); | 537 | DBG(" -> check_for_initrd()\n"); |
538 | 538 | ||
539 | prop = (u64 *)get_property(of_chosen, "linux,initrd-start", NULL); | 539 | if (of_chosen) { |
540 | if (prop != NULL) { | 540 | prop = (u64 *)get_property(of_chosen, |
541 | initrd_start = (unsigned long)__va(*prop); | 541 | "linux,initrd-start", NULL); |
542 | prop = (u64 *)get_property(of_chosen, "linux,initrd-end", NULL); | ||
543 | if (prop != NULL) { | 542 | if (prop != NULL) { |
544 | initrd_end = (unsigned long)__va(*prop); | 543 | initrd_start = (unsigned long)__va(*prop); |
545 | initrd_below_start_ok = 1; | 544 | prop = (u64 *)get_property(of_chosen, |
546 | } else | 545 | "linux,initrd-end", NULL); |
547 | initrd_start = 0; | 546 | if (prop != NULL) { |
547 | initrd_end = (unsigned long)__va(*prop); | ||
548 | initrd_below_start_ok = 1; | ||
549 | } else | ||
550 | initrd_start = 0; | ||
551 | } | ||
548 | } | 552 | } |
549 | 553 | ||
550 | /* If we were passed an initrd, set the ROOT_DEV properly if the values | 554 | /* If we were passed an initrd, set the ROOT_DEV properly if the values |
@@ -627,7 +631,7 @@ void __init setup_system(void) | |||
627 | * Initialize xmon | 631 | * Initialize xmon |
628 | */ | 632 | */ |
629 | #ifdef CONFIG_XMON_DEFAULT | 633 | #ifdef CONFIG_XMON_DEFAULT |
630 | xmon_init(); | 634 | xmon_init(1); |
631 | #endif | 635 | #endif |
632 | /* | 636 | /* |
633 | * Register early console | 637 | * Register early console |
@@ -1343,11 +1347,13 @@ static int __init early_xmon(char *p) | |||
1343 | /* ensure xmon is enabled */ | 1347 | /* ensure xmon is enabled */ |
1344 | if (p) { | 1348 | if (p) { |
1345 | if (strncmp(p, "on", 2) == 0) | 1349 | if (strncmp(p, "on", 2) == 0) |
1346 | xmon_init(); | 1350 | xmon_init(1); |
1351 | if (strncmp(p, "off", 3) == 0) | ||
1352 | xmon_init(0); | ||
1347 | if (strncmp(p, "early", 5) != 0) | 1353 | if (strncmp(p, "early", 5) != 0) |
1348 | return 0; | 1354 | return 0; |
1349 | } | 1355 | } |
1350 | xmon_init(); | 1356 | xmon_init(1); |
1351 | debugger(NULL); | 1357 | debugger(NULL); |
1352 | 1358 | ||
1353 | return 0; | 1359 | return 0; |
diff --git a/arch/ppc64/kernel/sysfs.c b/arch/ppc64/kernel/sysfs.c index 02b8ac4e0168..f311ee7c0070 100644 --- a/arch/ppc64/kernel/sysfs.c +++ b/arch/ppc64/kernel/sysfs.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <asm/current.h> | 13 | #include <asm/current.h> |
14 | #include <asm/processor.h> | 14 | #include <asm/processor.h> |
15 | #include <asm/cputable.h> | 15 | #include <asm/cputable.h> |
16 | #include <asm/firmware.h> | ||
16 | #include <asm/hvcall.h> | 17 | #include <asm/hvcall.h> |
17 | #include <asm/prom.h> | 18 | #include <asm/prom.h> |
18 | #include <asm/systemcfg.h> | 19 | #include <asm/systemcfg.h> |
@@ -100,6 +101,8 @@ static int __init setup_smt_snooze_delay(char *str) | |||
100 | } | 101 | } |
101 | __setup("smt-snooze-delay=", setup_smt_snooze_delay); | 102 | __setup("smt-snooze-delay=", setup_smt_snooze_delay); |
102 | 103 | ||
104 | #endif /* CONFIG_PPC_MULTIPLATFORM */ | ||
105 | |||
103 | /* | 106 | /* |
104 | * Enabling PMCs will slow partition context switch times so we only do | 107 | * Enabling PMCs will slow partition context switch times so we only do |
105 | * it the first time we write to the PMCs. | 108 | * it the first time we write to the PMCs. |
@@ -109,65 +112,15 @@ static DEFINE_PER_CPU(char, pmcs_enabled); | |||
109 | 112 | ||
110 | void ppc64_enable_pmcs(void) | 113 | void ppc64_enable_pmcs(void) |
111 | { | 114 | { |
112 | unsigned long hid0; | ||
113 | #ifdef CONFIG_PPC_PSERIES | ||
114 | unsigned long set, reset; | ||
115 | #endif /* CONFIG_PPC_PSERIES */ | ||
116 | |||
117 | /* Only need to enable them once */ | 115 | /* Only need to enable them once */ |
118 | if (__get_cpu_var(pmcs_enabled)) | 116 | if (__get_cpu_var(pmcs_enabled)) |
119 | return; | 117 | return; |
120 | 118 | ||
121 | __get_cpu_var(pmcs_enabled) = 1; | 119 | __get_cpu_var(pmcs_enabled) = 1; |
122 | 120 | ||
123 | switch (systemcfg->platform) { | 121 | if (ppc_md.enable_pmcs) |
124 | case PLATFORM_PSERIES: | 122 | ppc_md.enable_pmcs(); |
125 | case PLATFORM_POWERMAC: | ||
126 | hid0 = mfspr(HID0); | ||
127 | hid0 |= 1UL << (63 - 20); | ||
128 | |||
129 | /* POWER4 requires the following sequence */ | ||
130 | asm volatile( | ||
131 | "sync\n" | ||
132 | "mtspr %1, %0\n" | ||
133 | "mfspr %0, %1\n" | ||
134 | "mfspr %0, %1\n" | ||
135 | "mfspr %0, %1\n" | ||
136 | "mfspr %0, %1\n" | ||
137 | "mfspr %0, %1\n" | ||
138 | "mfspr %0, %1\n" | ||
139 | "isync" : "=&r" (hid0) : "i" (HID0), "0" (hid0): | ||
140 | "memory"); | ||
141 | break; | ||
142 | |||
143 | #ifdef CONFIG_PPC_PSERIES | ||
144 | case PLATFORM_PSERIES_LPAR: | ||
145 | set = 1UL << 63; | ||
146 | reset = 0; | ||
147 | plpar_hcall_norets(H_PERFMON, set, reset); | ||
148 | break; | ||
149 | #endif /* CONFIG_PPC_PSERIES */ | ||
150 | |||
151 | default: | ||
152 | break; | ||
153 | } | ||
154 | |||
155 | #ifdef CONFIG_PPC_PSERIES | ||
156 | /* instruct hypervisor to maintain PMCs */ | ||
157 | if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) | ||
158 | get_paca()->lppaca.pmcregs_in_use = 1; | ||
159 | #endif /* CONFIG_PPC_PSERIES */ | ||
160 | } | 123 | } |
161 | |||
162 | #else | ||
163 | |||
164 | /* PMC stuff */ | ||
165 | void ppc64_enable_pmcs(void) | ||
166 | { | ||
167 | /* XXX Implement for iseries */ | ||
168 | } | ||
169 | #endif /* CONFIG_PPC_MULTIPLATFORM */ | ||
170 | |||
171 | EXPORT_SYMBOL(ppc64_enable_pmcs); | 124 | EXPORT_SYMBOL(ppc64_enable_pmcs); |
172 | 125 | ||
173 | /* XXX convert to rusty's on_one_cpu */ | 126 | /* XXX convert to rusty's on_one_cpu */ |
diff --git a/arch/ppc64/kernel/time.c b/arch/ppc64/kernel/time.c index 909462e1adea..1696e1b05bb9 100644 --- a/arch/ppc64/kernel/time.c +++ b/arch/ppc64/kernel/time.c | |||
@@ -67,6 +67,7 @@ | |||
67 | #include <asm/prom.h> | 67 | #include <asm/prom.h> |
68 | #include <asm/sections.h> | 68 | #include <asm/sections.h> |
69 | #include <asm/systemcfg.h> | 69 | #include <asm/systemcfg.h> |
70 | #include <asm/firmware.h> | ||
70 | 71 | ||
71 | u64 jiffies_64 __cacheline_aligned_in_smp = INITIAL_JIFFIES; | 72 | u64 jiffies_64 __cacheline_aligned_in_smp = INITIAL_JIFFIES; |
72 | 73 | ||
@@ -370,13 +371,11 @@ int timer_interrupt(struct pt_regs * regs) | |||
370 | process_hvlpevents(regs); | 371 | process_hvlpevents(regs); |
371 | #endif | 372 | #endif |
372 | 373 | ||
373 | /* collect purr register values often, for accurate calculations */ | 374 | /* collect purr register values often, for accurate calculations */ |
374 | #if defined(CONFIG_PPC_PSERIES) | 375 | if (firmware_has_feature(FW_FEATURE_SPLPAR)) { |
375 | if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) { | ||
376 | struct cpu_usage *cu = &__get_cpu_var(cpu_usage_array); | 376 | struct cpu_usage *cu = &__get_cpu_var(cpu_usage_array); |
377 | cu->current_tb = mfspr(SPRN_PURR); | 377 | cu->current_tb = mfspr(SPRN_PURR); |
378 | } | 378 | } |
379 | #endif | ||
380 | 379 | ||
381 | irq_exit(); | 380 | irq_exit(); |
382 | 381 | ||
diff --git a/arch/ppc64/kernel/vio.c b/arch/ppc64/kernel/vio.c index 0c0ba71ac0e8..3b790bafcaad 100644 --- a/arch/ppc64/kernel/vio.c +++ b/arch/ppc64/kernel/vio.c | |||
@@ -1,10 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | * IBM PowerPC Virtual I/O Infrastructure Support. | 2 | * IBM PowerPC Virtual I/O Infrastructure Support. |
3 | * | 3 | * |
4 | * Copyright (c) 2003 IBM Corp. | 4 | * Copyright (c) 2003-2005 IBM Corp. |
5 | * Dave Engebretsen engebret@us.ibm.com | 5 | * Dave Engebretsen engebret@us.ibm.com |
6 | * Santiago Leon santil@us.ibm.com | 6 | * Santiago Leon santil@us.ibm.com |
7 | * Hollis Blanchard <hollisb@us.ibm.com> | 7 | * Hollis Blanchard <hollisb@us.ibm.com> |
8 | * Stephen Rothwell | ||
8 | * | 9 | * |
9 | * This program is free software; you can redistribute it and/or | 10 | * This program is free software; you can redistribute it and/or |
10 | * modify it under the terms of the GNU General Public License | 11 | * modify it under the terms of the GNU General Public License |
@@ -14,57 +15,27 @@ | |||
14 | 15 | ||
15 | #include <linux/init.h> | 16 | #include <linux/init.h> |
16 | #include <linux/console.h> | 17 | #include <linux/console.h> |
17 | #include <linux/version.h> | ||
18 | #include <linux/module.h> | 18 | #include <linux/module.h> |
19 | #include <linux/kobject.h> | ||
20 | #include <linux/mm.h> | 19 | #include <linux/mm.h> |
21 | #include <linux/dma-mapping.h> | 20 | #include <linux/dma-mapping.h> |
22 | #include <asm/rtas.h> | ||
23 | #include <asm/iommu.h> | 21 | #include <asm/iommu.h> |
24 | #include <asm/dma.h> | 22 | #include <asm/dma.h> |
25 | #include <asm/ppcdebug.h> | ||
26 | #include <asm/vio.h> | 23 | #include <asm/vio.h> |
27 | #include <asm/hvcall.h> | ||
28 | #include <asm/iSeries/vio.h> | ||
29 | #include <asm/iSeries/HvTypes.h> | ||
30 | #include <asm/iSeries/HvCallXm.h> | ||
31 | #include <asm/iSeries/HvLpConfig.h> | ||
32 | |||
33 | #define DBGENTER() pr_debug("%s entered\n", __FUNCTION__) | ||
34 | |||
35 | extern struct subsystem devices_subsys; /* needed for vio_find_name() */ | ||
36 | 24 | ||
37 | static const struct vio_device_id *vio_match_device( | 25 | static const struct vio_device_id *vio_match_device( |
38 | const struct vio_device_id *, const struct vio_dev *); | 26 | const struct vio_device_id *, const struct vio_dev *); |
39 | 27 | ||
40 | #ifdef CONFIG_PPC_PSERIES | 28 | struct vio_dev vio_bus_device = { /* fake "parent" device */ |
41 | static struct iommu_table *vio_build_iommu_table(struct vio_dev *); | ||
42 | static int vio_num_address_cells; | ||
43 | #endif | ||
44 | #ifdef CONFIG_PPC_ISERIES | ||
45 | static struct iommu_table veth_iommu_table; | ||
46 | static struct iommu_table vio_iommu_table; | ||
47 | #endif | ||
48 | static struct vio_dev vio_bus_device = { /* fake "parent" device */ | ||
49 | .name = vio_bus_device.dev.bus_id, | 29 | .name = vio_bus_device.dev.bus_id, |
50 | .type = "", | 30 | .type = "", |
51 | #ifdef CONFIG_PPC_ISERIES | ||
52 | .iommu_table = &vio_iommu_table, | ||
53 | #endif | ||
54 | .dev.bus_id = "vio", | 31 | .dev.bus_id = "vio", |
55 | .dev.bus = &vio_bus_type, | 32 | .dev.bus = &vio_bus_type, |
56 | }; | 33 | }; |
57 | 34 | ||
58 | #ifdef CONFIG_PPC_ISERIES | 35 | static int (*is_match)(const struct vio_device_id *id, |
59 | static struct vio_dev *__init vio_register_device_iseries(char *type, | 36 | const struct vio_dev *dev); |
60 | uint32_t unit_num); | 37 | static void (*unregister_device_callback)(struct vio_dev *dev); |
61 | 38 | static void (*release_device_callback)(struct device *dev); | |
62 | struct device *iSeries_vio_dev = &vio_bus_device.dev; | ||
63 | EXPORT_SYMBOL(iSeries_vio_dev); | ||
64 | |||
65 | #define device_is_compatible(a, b) 1 | ||
66 | |||
67 | #endif | ||
68 | 39 | ||
69 | /* convert from struct device to struct vio_dev and pass to driver. | 40 | /* convert from struct device to struct vio_dev and pass to driver. |
70 | * dev->driver has already been set by generic code because vio_bus_match | 41 | * dev->driver has already been set by generic code because vio_bus_match |
@@ -76,8 +47,6 @@ static int vio_bus_probe(struct device *dev) | |||
76 | const struct vio_device_id *id; | 47 | const struct vio_device_id *id; |
77 | int error = -ENODEV; | 48 | int error = -ENODEV; |
78 | 49 | ||
79 | DBGENTER(); | ||
80 | |||
81 | if (!viodrv->probe) | 50 | if (!viodrv->probe) |
82 | return error; | 51 | return error; |
83 | 52 | ||
@@ -95,8 +64,6 @@ static int vio_bus_remove(struct device *dev) | |||
95 | struct vio_dev *viodev = to_vio_dev(dev); | 64 | struct vio_dev *viodev = to_vio_dev(dev); |
96 | struct vio_driver *viodrv = to_vio_driver(dev->driver); | 65 | struct vio_driver *viodrv = to_vio_driver(dev->driver); |
97 | 66 | ||
98 | DBGENTER(); | ||
99 | |||
100 | if (viodrv->remove) { | 67 | if (viodrv->remove) { |
101 | return viodrv->remove(viodev); | 68 | return viodrv->remove(viodev); |
102 | } | 69 | } |
@@ -146,178 +113,65 @@ EXPORT_SYMBOL(vio_unregister_driver); | |||
146 | static const struct vio_device_id * vio_match_device(const struct vio_device_id *ids, | 113 | static const struct vio_device_id * vio_match_device(const struct vio_device_id *ids, |
147 | const struct vio_dev *dev) | 114 | const struct vio_dev *dev) |
148 | { | 115 | { |
149 | DBGENTER(); | ||
150 | |||
151 | while (ids->type) { | 116 | while (ids->type) { |
152 | if ((strncmp(dev->type, ids->type, strlen(ids->type)) == 0) && | 117 | if (is_match(ids, dev)) |
153 | device_is_compatible(dev->dev.platform_data, ids->compat)) | ||
154 | return ids; | 118 | return ids; |
155 | ids++; | 119 | ids++; |
156 | } | 120 | } |
157 | return NULL; | 121 | return NULL; |
158 | } | 122 | } |
159 | 123 | ||
160 | #ifdef CONFIG_PPC_ISERIES | ||
161 | void __init iommu_vio_init(void) | ||
162 | { | ||
163 | struct iommu_table *t; | ||
164 | struct iommu_table_cb cb; | ||
165 | unsigned long cbp; | ||
166 | unsigned long itc_entries; | ||
167 | |||
168 | cb.itc_busno = 255; /* Bus 255 is the virtual bus */ | ||
169 | cb.itc_virtbus = 0xff; /* Ask for virtual bus */ | ||
170 | |||
171 | cbp = virt_to_abs(&cb); | ||
172 | HvCallXm_getTceTableParms(cbp); | ||
173 | |||
174 | itc_entries = cb.itc_size * PAGE_SIZE / sizeof(union tce_entry); | ||
175 | veth_iommu_table.it_size = itc_entries / 2; | ||
176 | veth_iommu_table.it_busno = cb.itc_busno; | ||
177 | veth_iommu_table.it_offset = cb.itc_offset; | ||
178 | veth_iommu_table.it_index = cb.itc_index; | ||
179 | veth_iommu_table.it_type = TCE_VB; | ||
180 | veth_iommu_table.it_blocksize = 1; | ||
181 | |||
182 | t = iommu_init_table(&veth_iommu_table); | ||
183 | |||
184 | if (!t) | ||
185 | printk("Virtual Bus VETH TCE table failed.\n"); | ||
186 | |||
187 | vio_iommu_table.it_size = itc_entries - veth_iommu_table.it_size; | ||
188 | vio_iommu_table.it_busno = cb.itc_busno; | ||
189 | vio_iommu_table.it_offset = cb.itc_offset + | ||
190 | veth_iommu_table.it_size; | ||
191 | vio_iommu_table.it_index = cb.itc_index; | ||
192 | vio_iommu_table.it_type = TCE_VB; | ||
193 | vio_iommu_table.it_blocksize = 1; | ||
194 | |||
195 | t = iommu_init_table(&vio_iommu_table); | ||
196 | |||
197 | if (!t) | ||
198 | printk("Virtual Bus VIO TCE table failed.\n"); | ||
199 | } | ||
200 | #endif | ||
201 | |||
202 | #ifdef CONFIG_PPC_PSERIES | ||
203 | static void probe_bus_pseries(void) | ||
204 | { | ||
205 | struct device_node *node_vroot, *of_node; | ||
206 | |||
207 | node_vroot = find_devices("vdevice"); | ||
208 | if ((node_vroot == NULL) || (node_vroot->child == NULL)) | ||
209 | /* this machine doesn't do virtual IO, and that's ok */ | ||
210 | return; | ||
211 | |||
212 | vio_num_address_cells = prom_n_addr_cells(node_vroot->child); | ||
213 | |||
214 | /* | ||
215 | * Create struct vio_devices for each virtual device in the device tree. | ||
216 | * Drivers will associate with them later. | ||
217 | */ | ||
218 | for (of_node = node_vroot->child; of_node != NULL; | ||
219 | of_node = of_node->sibling) { | ||
220 | printk(KERN_DEBUG "%s: processing %p\n", __FUNCTION__, of_node); | ||
221 | vio_register_device_node(of_node); | ||
222 | } | ||
223 | } | ||
224 | #endif | ||
225 | |||
226 | #ifdef CONFIG_PPC_ISERIES | ||
227 | static void probe_bus_iseries(void) | ||
228 | { | ||
229 | HvLpIndexMap vlan_map = HvLpConfig_getVirtualLanIndexMap(); | ||
230 | struct vio_dev *viodev; | ||
231 | int i; | ||
232 | |||
233 | /* there is only one of each of these */ | ||
234 | vio_register_device_iseries("viocons", 0); | ||
235 | vio_register_device_iseries("vscsi", 0); | ||
236 | |||
237 | vlan_map = HvLpConfig_getVirtualLanIndexMap(); | ||
238 | for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++) { | ||
239 | if ((vlan_map & (0x8000 >> i)) == 0) | ||
240 | continue; | ||
241 | viodev = vio_register_device_iseries("vlan", i); | ||
242 | /* veth is special and has it own iommu_table */ | ||
243 | viodev->iommu_table = &veth_iommu_table; | ||
244 | } | ||
245 | for (i = 0; i < HVMAXARCHITECTEDVIRTUALDISKS; i++) | ||
246 | vio_register_device_iseries("viodasd", i); | ||
247 | for (i = 0; i < HVMAXARCHITECTEDVIRTUALCDROMS; i++) | ||
248 | vio_register_device_iseries("viocd", i); | ||
249 | for (i = 0; i < HVMAXARCHITECTEDVIRTUALTAPES; i++) | ||
250 | vio_register_device_iseries("viotape", i); | ||
251 | } | ||
252 | #endif | ||
253 | |||
254 | /** | 124 | /** |
255 | * vio_bus_init: - Initialize the virtual IO bus | 125 | * vio_bus_init: - Initialize the virtual IO bus |
256 | */ | 126 | */ |
257 | static int __init vio_bus_init(void) | 127 | int __init vio_bus_init(int (*match_func)(const struct vio_device_id *id, |
128 | const struct vio_dev *dev), | ||
129 | void (*unregister_dev)(struct vio_dev *), | ||
130 | void (*release_dev)(struct device *)) | ||
258 | { | 131 | { |
259 | int err; | 132 | int err; |
260 | 133 | ||
134 | is_match = match_func; | ||
135 | unregister_device_callback = unregister_dev; | ||
136 | release_device_callback = release_dev; | ||
137 | |||
261 | err = bus_register(&vio_bus_type); | 138 | err = bus_register(&vio_bus_type); |
262 | if (err) { | 139 | if (err) { |
263 | printk(KERN_ERR "failed to register VIO bus\n"); | 140 | printk(KERN_ERR "failed to register VIO bus\n"); |
264 | return err; | 141 | return err; |
265 | } | 142 | } |
266 | 143 | ||
267 | /* the fake parent of all vio devices, just to give us a nice directory */ | 144 | /* the fake parent of all vio devices, just to give us |
145 | * a nice directory | ||
146 | */ | ||
268 | err = device_register(&vio_bus_device.dev); | 147 | err = device_register(&vio_bus_device.dev); |
269 | if (err) { | 148 | if (err) { |
270 | printk(KERN_WARNING "%s: device_register returned %i\n", __FUNCTION__, | 149 | printk(KERN_WARNING "%s: device_register returned %i\n", |
271 | err); | 150 | __FUNCTION__, err); |
272 | return err; | 151 | return err; |
273 | } | 152 | } |
274 | 153 | ||
275 | #ifdef CONFIG_PPC_PSERIES | ||
276 | probe_bus_pseries(); | ||
277 | #endif | ||
278 | #ifdef CONFIG_PPC_ISERIES | ||
279 | probe_bus_iseries(); | ||
280 | #endif | ||
281 | |||
282 | return 0; | 154 | return 0; |
283 | } | 155 | } |
284 | 156 | ||
285 | __initcall(vio_bus_init); | ||
286 | |||
287 | /* vio_dev refcount hit 0 */ | 157 | /* vio_dev refcount hit 0 */ |
288 | static void __devinit vio_dev_release(struct device *dev) | 158 | static void __devinit vio_dev_release(struct device *dev) |
289 | { | 159 | { |
290 | DBGENTER(); | 160 | if (release_device_callback) |
291 | 161 | release_device_callback(dev); | |
292 | #ifdef CONFIG_PPC_PSERIES | ||
293 | /* XXX free TCE table */ | ||
294 | of_node_put(dev->platform_data); | ||
295 | #endif | ||
296 | kfree(to_vio_dev(dev)); | 162 | kfree(to_vio_dev(dev)); |
297 | } | 163 | } |
298 | 164 | ||
299 | #ifdef CONFIG_PPC_PSERIES | ||
300 | static ssize_t viodev_show_devspec(struct device *dev, struct device_attribute *attr, char *buf) | ||
301 | { | ||
302 | struct device_node *of_node = dev->platform_data; | ||
303 | |||
304 | return sprintf(buf, "%s\n", of_node->full_name); | ||
305 | } | ||
306 | DEVICE_ATTR(devspec, S_IRUSR | S_IRGRP | S_IROTH, viodev_show_devspec, NULL); | ||
307 | #endif | ||
308 | |||
309 | static ssize_t viodev_show_name(struct device *dev, struct device_attribute *attr, char *buf) | 165 | static ssize_t viodev_show_name(struct device *dev, struct device_attribute *attr, char *buf) |
310 | { | 166 | { |
311 | return sprintf(buf, "%s\n", to_vio_dev(dev)->name); | 167 | return sprintf(buf, "%s\n", to_vio_dev(dev)->name); |
312 | } | 168 | } |
313 | DEVICE_ATTR(name, S_IRUSR | S_IRGRP | S_IROTH, viodev_show_name, NULL); | 169 | DEVICE_ATTR(name, S_IRUSR | S_IRGRP | S_IROTH, viodev_show_name, NULL); |
314 | 170 | ||
315 | static struct vio_dev * __devinit vio_register_device_common( | 171 | struct vio_dev * __devinit vio_register_device_common( |
316 | struct vio_dev *viodev, char *name, char *type, | 172 | struct vio_dev *viodev, char *name, char *type, |
317 | uint32_t unit_address, struct iommu_table *iommu_table) | 173 | uint32_t unit_address, struct iommu_table *iommu_table) |
318 | { | 174 | { |
319 | DBGENTER(); | ||
320 | |||
321 | viodev->name = name; | 175 | viodev->name = name; |
322 | viodev->type = type; | 176 | viodev->type = type; |
323 | viodev->unit_address = unit_address; | 177 | viodev->unit_address = unit_address; |
@@ -338,222 +192,15 @@ static struct vio_dev * __devinit vio_register_device_common( | |||
338 | return viodev; | 192 | return viodev; |
339 | } | 193 | } |
340 | 194 | ||
341 | #ifdef CONFIG_PPC_PSERIES | ||
342 | /** | ||
343 | * vio_register_device_node: - Register a new vio device. | ||
344 | * @of_node: The OF node for this device. | ||
345 | * | ||
346 | * Creates and initializes a vio_dev structure from the data in | ||
347 | * of_node (dev.platform_data) and adds it to the list of virtual devices. | ||
348 | * Returns a pointer to the created vio_dev or NULL if node has | ||
349 | * NULL device_type or compatible fields. | ||
350 | */ | ||
351 | struct vio_dev * __devinit vio_register_device_node(struct device_node *of_node) | ||
352 | { | ||
353 | struct vio_dev *viodev; | ||
354 | unsigned int *unit_address; | ||
355 | unsigned int *irq_p; | ||
356 | |||
357 | DBGENTER(); | ||
358 | |||
359 | /* we need the 'device_type' property, in order to match with drivers */ | ||
360 | if ((NULL == of_node->type)) { | ||
361 | printk(KERN_WARNING | ||
362 | "%s: node %s missing 'device_type'\n", __FUNCTION__, | ||
363 | of_node->name ? of_node->name : "<unknown>"); | ||
364 | return NULL; | ||
365 | } | ||
366 | |||
367 | unit_address = (unsigned int *)get_property(of_node, "reg", NULL); | ||
368 | if (!unit_address) { | ||
369 | printk(KERN_WARNING "%s: node %s missing 'reg'\n", __FUNCTION__, | ||
370 | of_node->name ? of_node->name : "<unknown>"); | ||
371 | return NULL; | ||
372 | } | ||
373 | |||
374 | /* allocate a vio_dev for this node */ | ||
375 | viodev = kmalloc(sizeof(struct vio_dev), GFP_KERNEL); | ||
376 | if (!viodev) { | ||
377 | return NULL; | ||
378 | } | ||
379 | memset(viodev, 0, sizeof(struct vio_dev)); | ||
380 | |||
381 | viodev->dev.platform_data = of_node_get(of_node); | ||
382 | |||
383 | viodev->irq = NO_IRQ; | ||
384 | irq_p = (unsigned int *)get_property(of_node, "interrupts", NULL); | ||
385 | if (irq_p) { | ||
386 | int virq = virt_irq_create_mapping(*irq_p); | ||
387 | if (virq == NO_IRQ) { | ||
388 | printk(KERN_ERR "Unable to allocate interrupt " | ||
389 | "number for %s\n", of_node->full_name); | ||
390 | } else | ||
391 | viodev->irq = irq_offset_up(virq); | ||
392 | } | ||
393 | |||
394 | snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%x", *unit_address); | ||
395 | |||
396 | /* register with generic device framework */ | ||
397 | if (vio_register_device_common(viodev, of_node->name, of_node->type, | ||
398 | *unit_address, vio_build_iommu_table(viodev)) | ||
399 | == NULL) { | ||
400 | /* XXX free TCE table */ | ||
401 | kfree(viodev); | ||
402 | return NULL; | ||
403 | } | ||
404 | device_create_file(&viodev->dev, &dev_attr_devspec); | ||
405 | |||
406 | return viodev; | ||
407 | } | ||
408 | EXPORT_SYMBOL(vio_register_device_node); | ||
409 | #endif | ||
410 | |||
411 | #ifdef CONFIG_PPC_ISERIES | ||
412 | /** | ||
413 | * vio_register_device: - Register a new vio device. | ||
414 | * @voidev: The device to register. | ||
415 | */ | ||
416 | static struct vio_dev *__init vio_register_device_iseries(char *type, | ||
417 | uint32_t unit_num) | ||
418 | { | ||
419 | struct vio_dev *viodev; | ||
420 | |||
421 | DBGENTER(); | ||
422 | |||
423 | /* allocate a vio_dev for this node */ | ||
424 | viodev = kmalloc(sizeof(struct vio_dev), GFP_KERNEL); | ||
425 | if (!viodev) | ||
426 | return NULL; | ||
427 | memset(viodev, 0, sizeof(struct vio_dev)); | ||
428 | |||
429 | snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%s%d", type, unit_num); | ||
430 | |||
431 | return vio_register_device_common(viodev, viodev->dev.bus_id, type, | ||
432 | unit_num, &vio_iommu_table); | ||
433 | } | ||
434 | #endif | ||
435 | |||
436 | void __devinit vio_unregister_device(struct vio_dev *viodev) | 195 | void __devinit vio_unregister_device(struct vio_dev *viodev) |
437 | { | 196 | { |
438 | DBGENTER(); | 197 | if (unregister_device_callback) |
439 | #ifdef CONFIG_PPC_PSERIES | 198 | unregister_device_callback(viodev); |
440 | device_remove_file(&viodev->dev, &dev_attr_devspec); | ||
441 | #endif | ||
442 | device_remove_file(&viodev->dev, &dev_attr_name); | 199 | device_remove_file(&viodev->dev, &dev_attr_name); |
443 | device_unregister(&viodev->dev); | 200 | device_unregister(&viodev->dev); |
444 | } | 201 | } |
445 | EXPORT_SYMBOL(vio_unregister_device); | 202 | EXPORT_SYMBOL(vio_unregister_device); |
446 | 203 | ||
447 | #ifdef CONFIG_PPC_PSERIES | ||
448 | /** | ||
449 | * vio_get_attribute: - get attribute for virtual device | ||
450 | * @vdev: The vio device to get property. | ||
451 | * @which: The property/attribute to be extracted. | ||
452 | * @length: Pointer to length of returned data size (unused if NULL). | ||
453 | * | ||
454 | * Calls prom.c's get_property() to return the value of the | ||
455 | * attribute specified by the preprocessor constant @which | ||
456 | */ | ||
457 | const void * vio_get_attribute(struct vio_dev *vdev, void* which, int* length) | ||
458 | { | ||
459 | return get_property(vdev->dev.platform_data, (char*)which, length); | ||
460 | } | ||
461 | EXPORT_SYMBOL(vio_get_attribute); | ||
462 | |||
463 | /* vio_find_name() - internal because only vio.c knows how we formatted the | ||
464 | * kobject name | ||
465 | * XXX once vio_bus_type.devices is actually used as a kset in | ||
466 | * drivers/base/bus.c, this function should be removed in favor of | ||
467 | * "device_find(kobj_name, &vio_bus_type)" | ||
468 | */ | ||
469 | static struct vio_dev *vio_find_name(const char *kobj_name) | ||
470 | { | ||
471 | struct kobject *found; | ||
472 | |||
473 | found = kset_find_obj(&devices_subsys.kset, kobj_name); | ||
474 | if (!found) | ||
475 | return NULL; | ||
476 | |||
477 | return to_vio_dev(container_of(found, struct device, kobj)); | ||
478 | } | ||
479 | |||
480 | /** | ||
481 | * vio_find_node - find an already-registered vio_dev | ||
482 | * @vnode: device_node of the virtual device we're looking for | ||
483 | */ | ||
484 | struct vio_dev *vio_find_node(struct device_node *vnode) | ||
485 | { | ||
486 | uint32_t *unit_address; | ||
487 | char kobj_name[BUS_ID_SIZE]; | ||
488 | |||
489 | /* construct the kobject name from the device node */ | ||
490 | unit_address = (uint32_t *)get_property(vnode, "reg", NULL); | ||
491 | if (!unit_address) | ||
492 | return NULL; | ||
493 | snprintf(kobj_name, BUS_ID_SIZE, "%x", *unit_address); | ||
494 | |||
495 | return vio_find_name(kobj_name); | ||
496 | } | ||
497 | EXPORT_SYMBOL(vio_find_node); | ||
498 | |||
499 | /** | ||
500 | * vio_build_iommu_table: - gets the dma information from OF and builds the TCE tree. | ||
501 | * @dev: the virtual device. | ||
502 | * | ||
503 | * Returns a pointer to the built tce tree, or NULL if it can't | ||
504 | * find property. | ||
505 | */ | ||
506 | static struct iommu_table * vio_build_iommu_table(struct vio_dev *dev) | ||
507 | { | ||
508 | unsigned int *dma_window; | ||
509 | struct iommu_table *newTceTable; | ||
510 | unsigned long offset; | ||
511 | int dma_window_property_size; | ||
512 | |||
513 | dma_window = (unsigned int *) get_property(dev->dev.platform_data, "ibm,my-dma-window", &dma_window_property_size); | ||
514 | if(!dma_window) { | ||
515 | return NULL; | ||
516 | } | ||
517 | |||
518 | newTceTable = (struct iommu_table *) kmalloc(sizeof(struct iommu_table), GFP_KERNEL); | ||
519 | |||
520 | /* There should be some code to extract the phys-encoded offset | ||
521 | using prom_n_addr_cells(). However, according to a comment | ||
522 | on earlier versions, it's always zero, so we don't bother */ | ||
523 | offset = dma_window[1] >> PAGE_SHIFT; | ||
524 | |||
525 | /* TCE table size - measured in tce entries */ | ||
526 | newTceTable->it_size = dma_window[4] >> PAGE_SHIFT; | ||
527 | /* offset for VIO should always be 0 */ | ||
528 | newTceTable->it_offset = offset; | ||
529 | newTceTable->it_busno = 0; | ||
530 | newTceTable->it_index = (unsigned long)dma_window[0]; | ||
531 | newTceTable->it_type = TCE_VB; | ||
532 | |||
533 | return iommu_init_table(newTceTable); | ||
534 | } | ||
535 | |||
536 | int vio_enable_interrupts(struct vio_dev *dev) | ||
537 | { | ||
538 | int rc = h_vio_signal(dev->unit_address, VIO_IRQ_ENABLE); | ||
539 | if (rc != H_Success) { | ||
540 | printk(KERN_ERR "vio: Error 0x%x enabling interrupts\n", rc); | ||
541 | } | ||
542 | return rc; | ||
543 | } | ||
544 | EXPORT_SYMBOL(vio_enable_interrupts); | ||
545 | |||
546 | int vio_disable_interrupts(struct vio_dev *dev) | ||
547 | { | ||
548 | int rc = h_vio_signal(dev->unit_address, VIO_IRQ_DISABLE); | ||
549 | if (rc != H_Success) { | ||
550 | printk(KERN_ERR "vio: Error 0x%x disabling interrupts\n", rc); | ||
551 | } | ||
552 | return rc; | ||
553 | } | ||
554 | EXPORT_SYMBOL(vio_disable_interrupts); | ||
555 | #endif | ||
556 | |||
557 | static dma_addr_t vio_map_single(struct device *dev, void *vaddr, | 204 | static dma_addr_t vio_map_single(struct device *dev, void *vaddr, |
558 | size_t size, enum dma_data_direction direction) | 205 | size_t size, enum dma_data_direction direction) |
559 | { | 206 | { |
@@ -617,8 +264,6 @@ static int vio_bus_match(struct device *dev, struct device_driver *drv) | |||
617 | const struct vio_device_id *ids = vio_drv->id_table; | 264 | const struct vio_device_id *ids = vio_drv->id_table; |
618 | const struct vio_device_id *found_id; | 265 | const struct vio_device_id *found_id; |
619 | 266 | ||
620 | DBGENTER(); | ||
621 | |||
622 | if (!ids) | 267 | if (!ids) |
623 | return 0; | 268 | return 0; |
624 | 269 | ||