diff options
Diffstat (limited to 'arch/powerpc/platforms')
28 files changed, 921 insertions, 101 deletions
diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig index 69d668c072ae..0f979c5c756b 100644 --- a/arch/powerpc/platforms/44x/Kconfig +++ b/arch/powerpc/platforms/44x/Kconfig | |||
@@ -17,6 +17,16 @@ config BAMBOO | |||
17 | help | 17 | help |
18 | This option enables support for the IBM PPC440EP evaluation board. | 18 | This option enables support for the IBM PPC440EP evaluation board. |
19 | 19 | ||
20 | config BLUESTONE | ||
21 | bool "Bluestone" | ||
22 | depends on 44x | ||
23 | default n | ||
24 | select PPC44x_SIMPLE | ||
25 | select APM821xx | ||
26 | select IBM_NEW_EMAC_RGMII | ||
27 | help | ||
28 | This option enables support for the APM APM821xx Evaluation board. | ||
29 | |||
20 | config EBONY | 30 | config EBONY |
21 | bool "Ebony" | 31 | bool "Ebony" |
22 | depends on 44x | 32 | depends on 44x |
@@ -293,6 +303,12 @@ config 460SX | |||
293 | select IBM_NEW_EMAC_ZMII | 303 | select IBM_NEW_EMAC_ZMII |
294 | select IBM_NEW_EMAC_TAH | 304 | select IBM_NEW_EMAC_TAH |
295 | 305 | ||
306 | config APM821xx | ||
307 | bool | ||
308 | select PPC_FPU | ||
309 | select IBM_NEW_EMAC_EMAC4 | ||
310 | select IBM_NEW_EMAC_TAH | ||
311 | |||
296 | # 44x errata/workaround config symbols, selected by the CPU models above | 312 | # 44x errata/workaround config symbols, selected by the CPU models above |
297 | config IBM440EP_ERR42 | 313 | config IBM440EP_ERR42 |
298 | bool | 314 | bool |
diff --git a/arch/powerpc/platforms/44x/ppc44x_simple.c b/arch/powerpc/platforms/44x/ppc44x_simple.c index 5f7a29d7f590..7ddcba3b9397 100644 --- a/arch/powerpc/platforms/44x/ppc44x_simple.c +++ b/arch/powerpc/platforms/44x/ppc44x_simple.c | |||
@@ -52,6 +52,7 @@ machine_device_initcall(ppc44x_simple, ppc44x_device_probe); | |||
52 | static char *board[] __initdata = { | 52 | static char *board[] __initdata = { |
53 | "amcc,arches", | 53 | "amcc,arches", |
54 | "amcc,bamboo", | 54 | "amcc,bamboo", |
55 | "amcc,bluestone", | ||
55 | "amcc,canyonlands", | 56 | "amcc,canyonlands", |
56 | "amcc,glacier", | 57 | "amcc,glacier", |
57 | "ibm,ebony", | 58 | "ibm,ebony", |
diff --git a/arch/powerpc/platforms/83xx/Kconfig b/arch/powerpc/platforms/83xx/Kconfig index 021763a32c2f..73f4135f3a1a 100644 --- a/arch/powerpc/platforms/83xx/Kconfig +++ b/arch/powerpc/platforms/83xx/Kconfig | |||
@@ -10,12 +10,12 @@ menuconfig PPC_83xx | |||
10 | if PPC_83xx | 10 | if PPC_83xx |
11 | 11 | ||
12 | config MPC830x_RDB | 12 | config MPC830x_RDB |
13 | bool "Freescale MPC830x RDB" | 13 | bool "Freescale MPC830x RDB and derivatives" |
14 | select DEFAULT_UIMAGE | 14 | select DEFAULT_UIMAGE |
15 | select PPC_MPC831x | 15 | select PPC_MPC831x |
16 | select FSL_GTM | 16 | select FSL_GTM |
17 | help | 17 | help |
18 | This option enables support for the MPC8308 RDB board. | 18 | This option enables support for the MPC8308 RDB and MPC8308 P1M boards. |
19 | 19 | ||
20 | config MPC831x_RDB | 20 | config MPC831x_RDB |
21 | bool "Freescale MPC831x RDB" | 21 | bool "Freescale MPC831x RDB" |
diff --git a/arch/powerpc/platforms/83xx/mpc830x_rdb.c b/arch/powerpc/platforms/83xx/mpc830x_rdb.c index ac102ee9abe8..846831d495b5 100644 --- a/arch/powerpc/platforms/83xx/mpc830x_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc830x_rdb.c | |||
@@ -65,7 +65,8 @@ static int __init mpc830x_rdb_probe(void) | |||
65 | unsigned long root = of_get_flat_dt_root(); | 65 | unsigned long root = of_get_flat_dt_root(); |
66 | 66 | ||
67 | return of_flat_dt_is_compatible(root, "MPC8308RDB") || | 67 | return of_flat_dt_is_compatible(root, "MPC8308RDB") || |
68 | of_flat_dt_is_compatible(root, "fsl,mpc8308rdb"); | 68 | of_flat_dt_is_compatible(root, "fsl,mpc8308rdb") || |
69 | of_flat_dt_is_compatible(root, "denx,mpc8308_p1m"); | ||
69 | } | 70 | } |
70 | 71 | ||
71 | static struct of_device_id __initdata of_bus_ids[] = { | 72 | static struct of_device_id __initdata of_bus_ids[] = { |
diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig index bea1f5905ad4..b6976e1726e4 100644 --- a/arch/powerpc/platforms/85xx/Kconfig +++ b/arch/powerpc/platforms/85xx/Kconfig | |||
@@ -11,6 +11,8 @@ menuconfig FSL_SOC_BOOKE | |||
11 | 11 | ||
12 | if FSL_SOC_BOOKE | 12 | if FSL_SOC_BOOKE |
13 | 13 | ||
14 | if PPC32 | ||
15 | |||
14 | config MPC8540_ADS | 16 | config MPC8540_ADS |
15 | bool "Freescale MPC8540 ADS" | 17 | bool "Freescale MPC8540 ADS" |
16 | select DEFAULT_UIMAGE | 18 | select DEFAULT_UIMAGE |
@@ -153,10 +155,20 @@ config SBC8560 | |||
153 | help | 155 | help |
154 | This option enables support for the Wind River SBC8560 board | 156 | This option enables support for the Wind River SBC8560 board |
155 | 157 | ||
158 | config P3041_DS | ||
159 | bool "Freescale P3041 DS" | ||
160 | select DEFAULT_UIMAGE | ||
161 | select PPC_E500MC | ||
162 | select PHYS_64BIT | ||
163 | select SWIOTLB | ||
164 | select MPC8xxx_GPIO | ||
165 | select HAS_RAPIDIO | ||
166 | help | ||
167 | This option enables support for the P3041 DS board | ||
168 | |||
156 | config P4080_DS | 169 | config P4080_DS |
157 | bool "Freescale P4080 DS" | 170 | bool "Freescale P4080 DS" |
158 | select DEFAULT_UIMAGE | 171 | select DEFAULT_UIMAGE |
159 | select PPC_FSL_BOOK3E | ||
160 | select PPC_E500MC | 172 | select PPC_E500MC |
161 | select PHYS_64BIT | 173 | select PHYS_64BIT |
162 | select SWIOTLB | 174 | select SWIOTLB |
@@ -165,6 +177,20 @@ config P4080_DS | |||
165 | help | 177 | help |
166 | This option enables support for the P4080 DS board | 178 | This option enables support for the P4080 DS board |
167 | 179 | ||
180 | endif # PPC32 | ||
181 | |||
182 | config P5020_DS | ||
183 | bool "Freescale P5020 DS" | ||
184 | select DEFAULT_UIMAGE | ||
185 | select E500 | ||
186 | select PPC_E500MC | ||
187 | select PHYS_64BIT | ||
188 | select SWIOTLB | ||
189 | select MPC8xxx_GPIO | ||
190 | select HAS_RAPIDIO | ||
191 | help | ||
192 | This option enables support for the P5020 DS board | ||
193 | |||
168 | endif # FSL_SOC_BOOKE | 194 | endif # FSL_SOC_BOOKE |
169 | 195 | ||
170 | config TQM85xx | 196 | config TQM85xx |
diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile index a2ec3f8f4d06..dd70db77d63e 100644 --- a/arch/powerpc/platforms/85xx/Makefile +++ b/arch/powerpc/platforms/85xx/Makefile | |||
@@ -11,7 +11,9 @@ obj-$(CONFIG_MPC85xx_DS) += mpc85xx_ds.o | |||
11 | obj-$(CONFIG_MPC85xx_MDS) += mpc85xx_mds.o | 11 | obj-$(CONFIG_MPC85xx_MDS) += mpc85xx_mds.o |
12 | obj-$(CONFIG_MPC85xx_RDB) += mpc85xx_rdb.o | 12 | obj-$(CONFIG_MPC85xx_RDB) += mpc85xx_rdb.o |
13 | obj-$(CONFIG_P1022_DS) += p1022_ds.o | 13 | obj-$(CONFIG_P1022_DS) += p1022_ds.o |
14 | obj-$(CONFIG_P3041_DS) += p3041_ds.o corenet_ds.o | ||
14 | obj-$(CONFIG_P4080_DS) += p4080_ds.o corenet_ds.o | 15 | obj-$(CONFIG_P4080_DS) += p4080_ds.o corenet_ds.o |
16 | obj-$(CONFIG_P5020_DS) += p5020_ds.o corenet_ds.o | ||
15 | obj-$(CONFIG_STX_GP3) += stx_gp3.o | 17 | obj-$(CONFIG_STX_GP3) += stx_gp3.o |
16 | obj-$(CONFIG_TQM85xx) += tqm85xx.o | 18 | obj-$(CONFIG_TQM85xx) += tqm85xx.o |
17 | obj-$(CONFIG_SBC8560) += sbc8560.o | 19 | obj-$(CONFIG_SBC8560) += sbc8560.o |
diff --git a/arch/powerpc/platforms/85xx/p1022_ds.c b/arch/powerpc/platforms/85xx/p1022_ds.c index 34e00902ce86..2b390d19a1d1 100644 --- a/arch/powerpc/platforms/85xx/p1022_ds.c +++ b/arch/powerpc/platforms/85xx/p1022_ds.c | |||
@@ -112,6 +112,8 @@ static struct of_device_id __initdata p1022_ds_ids[] = { | |||
112 | { .compatible = "soc", }, | 112 | { .compatible = "soc", }, |
113 | { .compatible = "simple-bus", }, | 113 | { .compatible = "simple-bus", }, |
114 | { .compatible = "gianfar", }, | 114 | { .compatible = "gianfar", }, |
115 | /* So that the DMA channel nodes can be probed individually: */ | ||
116 | { .compatible = "fsl,eloplus-dma", }, | ||
115 | {}, | 117 | {}, |
116 | }; | 118 | }; |
117 | 119 | ||
diff --git a/arch/powerpc/platforms/85xx/p3041_ds.c b/arch/powerpc/platforms/85xx/p3041_ds.c new file mode 100644 index 000000000000..0ed52e18298c --- /dev/null +++ b/arch/powerpc/platforms/85xx/p3041_ds.c | |||
@@ -0,0 +1,64 @@ | |||
1 | /* | ||
2 | * P3041 DS Setup | ||
3 | * | ||
4 | * Maintained by Kumar Gala (see MAINTAINERS for contact information) | ||
5 | * | ||
6 | * Copyright 2009-2010 Freescale Semiconductor Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/pci.h> | ||
16 | #include <linux/kdev_t.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/phy.h> | ||
20 | |||
21 | #include <asm/system.h> | ||
22 | #include <asm/time.h> | ||
23 | #include <asm/machdep.h> | ||
24 | #include <asm/pci-bridge.h> | ||
25 | #include <mm/mmu_decl.h> | ||
26 | #include <asm/prom.h> | ||
27 | #include <asm/udbg.h> | ||
28 | #include <asm/mpic.h> | ||
29 | |||
30 | #include <linux/of_platform.h> | ||
31 | #include <sysdev/fsl_soc.h> | ||
32 | #include <sysdev/fsl_pci.h> | ||
33 | |||
34 | #include "corenet_ds.h" | ||
35 | |||
36 | /* | ||
37 | * Called very early, device-tree isn't unflattened | ||
38 | */ | ||
39 | static int __init p3041_ds_probe(void) | ||
40 | { | ||
41 | unsigned long root = of_get_flat_dt_root(); | ||
42 | |||
43 | return of_flat_dt_is_compatible(root, "fsl,P3041DS"); | ||
44 | } | ||
45 | |||
46 | define_machine(p3041_ds) { | ||
47 | .name = "P3041 DS", | ||
48 | .probe = p3041_ds_probe, | ||
49 | .setup_arch = corenet_ds_setup_arch, | ||
50 | .init_IRQ = corenet_ds_pic_init, | ||
51 | #ifdef CONFIG_PCI | ||
52 | .pcibios_fixup_bus = fsl_pcibios_fixup_bus, | ||
53 | #endif | ||
54 | .get_irq = mpic_get_coreint_irq, | ||
55 | .restart = fsl_rstcr_restart, | ||
56 | .calibrate_decr = generic_calibrate_decr, | ||
57 | .progress = udbg_progress, | ||
58 | }; | ||
59 | |||
60 | machine_device_initcall(p3041_ds, corenet_ds_publish_devices); | ||
61 | |||
62 | #ifdef CONFIG_SWIOTLB | ||
63 | machine_arch_initcall(p3041_ds, swiotlb_setup_bus_notifier); | ||
64 | #endif | ||
diff --git a/arch/powerpc/platforms/85xx/p5020_ds.c b/arch/powerpc/platforms/85xx/p5020_ds.c new file mode 100644 index 000000000000..7467b712ee00 --- /dev/null +++ b/arch/powerpc/platforms/85xx/p5020_ds.c | |||
@@ -0,0 +1,69 @@ | |||
1 | /* | ||
2 | * P5020 DS Setup | ||
3 | * | ||
4 | * Maintained by Kumar Gala (see MAINTAINERS for contact information) | ||
5 | * | ||
6 | * Copyright 2009-2010 Freescale Semiconductor Inc. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/pci.h> | ||
16 | #include <linux/kdev_t.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/phy.h> | ||
20 | |||
21 | #include <asm/system.h> | ||
22 | #include <asm/time.h> | ||
23 | #include <asm/machdep.h> | ||
24 | #include <asm/pci-bridge.h> | ||
25 | #include <mm/mmu_decl.h> | ||
26 | #include <asm/prom.h> | ||
27 | #include <asm/udbg.h> | ||
28 | #include <asm/mpic.h> | ||
29 | |||
30 | #include <linux/of_platform.h> | ||
31 | #include <sysdev/fsl_soc.h> | ||
32 | #include <sysdev/fsl_pci.h> | ||
33 | |||
34 | #include "corenet_ds.h" | ||
35 | |||
36 | /* | ||
37 | * Called very early, device-tree isn't unflattened | ||
38 | */ | ||
39 | static int __init p5020_ds_probe(void) | ||
40 | { | ||
41 | unsigned long root = of_get_flat_dt_root(); | ||
42 | |||
43 | return of_flat_dt_is_compatible(root, "fsl,P5020DS"); | ||
44 | } | ||
45 | |||
46 | define_machine(p5020_ds) { | ||
47 | .name = "P5020 DS", | ||
48 | .probe = p5020_ds_probe, | ||
49 | .setup_arch = corenet_ds_setup_arch, | ||
50 | .init_IRQ = corenet_ds_pic_init, | ||
51 | #ifdef CONFIG_PCI | ||
52 | .pcibios_fixup_bus = fsl_pcibios_fixup_bus, | ||
53 | #endif | ||
54 | /* coreint doesn't play nice with lazy EE, use legacy mpic for now */ | ||
55 | #ifdef CONFIG_PPC64 | ||
56 | .get_irq = mpic_get_irq, | ||
57 | #else | ||
58 | .get_irq = mpic_get_coreint_irq, | ||
59 | #endif | ||
60 | .restart = fsl_rstcr_restart, | ||
61 | .calibrate_decr = generic_calibrate_decr, | ||
62 | .progress = udbg_progress, | ||
63 | }; | ||
64 | |||
65 | machine_device_initcall(p5020_ds, corenet_ds_publish_devices); | ||
66 | |||
67 | #ifdef CONFIG_SWIOTLB | ||
68 | machine_arch_initcall(p5020_ds, swiotlb_setup_bus_notifier); | ||
69 | #endif | ||
diff --git a/arch/powerpc/platforms/85xx/smp.c b/arch/powerpc/platforms/85xx/smp.c index a6b106557be4..5c91a992f02b 100644 --- a/arch/powerpc/platforms/85xx/smp.c +++ b/arch/powerpc/platforms/85xx/smp.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/delay.h> | 16 | #include <linux/delay.h> |
17 | #include <linux/of.h> | 17 | #include <linux/of.h> |
18 | #include <linux/kexec.h> | 18 | #include <linux/kexec.h> |
19 | #include <linux/highmem.h> | ||
19 | 20 | ||
20 | #include <asm/machdep.h> | 21 | #include <asm/machdep.h> |
21 | #include <asm/pgtable.h> | 22 | #include <asm/pgtable.h> |
@@ -79,6 +80,7 @@ smp_85xx_kick_cpu(int nr) | |||
79 | local_irq_save(flags); | 80 | local_irq_save(flags); |
80 | 81 | ||
81 | out_be32(bptr_vaddr + BOOT_ENTRY_PIR, nr); | 82 | out_be32(bptr_vaddr + BOOT_ENTRY_PIR, nr); |
83 | #ifdef CONFIG_PPC32 | ||
82 | out_be32(bptr_vaddr + BOOT_ENTRY_ADDR_LOWER, __pa(__early_start)); | 84 | out_be32(bptr_vaddr + BOOT_ENTRY_ADDR_LOWER, __pa(__early_start)); |
83 | 85 | ||
84 | if (!ioremappable) | 86 | if (!ioremappable) |
@@ -88,6 +90,12 @@ smp_85xx_kick_cpu(int nr) | |||
88 | /* Wait a bit for the CPU to ack. */ | 90 | /* Wait a bit for the CPU to ack. */ |
89 | while ((__secondary_hold_acknowledge != nr) && (++n < 1000)) | 91 | while ((__secondary_hold_acknowledge != nr) && (++n < 1000)) |
90 | mdelay(1); | 92 | mdelay(1); |
93 | #else | ||
94 | out_be64((u64 *)(bptr_vaddr + BOOT_ENTRY_ADDR_UPPER), | ||
95 | __pa((u64)*((unsigned long long *) generic_secondary_smp_init))); | ||
96 | |||
97 | smp_generic_kick_cpu(nr); | ||
98 | #endif | ||
91 | 99 | ||
92 | local_irq_restore(flags); | 100 | local_irq_restore(flags); |
93 | 101 | ||
@@ -114,19 +122,15 @@ struct smp_ops_t smp_85xx_ops = { | |||
114 | }; | 122 | }; |
115 | 123 | ||
116 | #ifdef CONFIG_KEXEC | 124 | #ifdef CONFIG_KEXEC |
117 | static int kexec_down_cpus = 0; | 125 | atomic_t kexec_down_cpus = ATOMIC_INIT(0); |
118 | 126 | ||
119 | void mpc85xx_smp_kexec_cpu_down(int crash_shutdown, int secondary) | 127 | void mpc85xx_smp_kexec_cpu_down(int crash_shutdown, int secondary) |
120 | { | 128 | { |
121 | mpic_teardown_this_cpu(1); | 129 | local_irq_disable(); |
122 | |||
123 | /* When crashing, this gets called on all CPU's we only | ||
124 | * take down the non-boot cpus */ | ||
125 | if (smp_processor_id() != boot_cpuid) | ||
126 | { | ||
127 | local_irq_disable(); | ||
128 | kexec_down_cpus++; | ||
129 | 130 | ||
131 | if (secondary) { | ||
132 | atomic_inc(&kexec_down_cpus); | ||
133 | /* loop forever */ | ||
130 | while (1); | 134 | while (1); |
131 | } | 135 | } |
132 | } | 136 | } |
@@ -137,16 +141,65 @@ static void mpc85xx_smp_kexec_down(void *arg) | |||
137 | ppc_md.kexec_cpu_down(0,1); | 141 | ppc_md.kexec_cpu_down(0,1); |
138 | } | 142 | } |
139 | 143 | ||
140 | static void mpc85xx_smp_machine_kexec(struct kimage *image) | 144 | static void map_and_flush(unsigned long paddr) |
141 | { | 145 | { |
142 | int timeout = 2000; | 146 | struct page *page = pfn_to_page(paddr >> PAGE_SHIFT); |
147 | unsigned long kaddr = (unsigned long)kmap(page); | ||
148 | |||
149 | flush_dcache_range(kaddr, kaddr + PAGE_SIZE); | ||
150 | kunmap(page); | ||
151 | } | ||
152 | |||
153 | /** | ||
154 | * Before we reset the other cores, we need to flush relevant cache | ||
155 | * out to memory so we don't get anything corrupted, some of these flushes | ||
156 | * are performed out of an overabundance of caution as interrupts are not | ||
157 | * disabled yet and we can switch cores | ||
158 | */ | ||
159 | static void mpc85xx_smp_flush_dcache_kexec(struct kimage *image) | ||
160 | { | ||
161 | kimage_entry_t *ptr, entry; | ||
162 | unsigned long paddr; | ||
143 | int i; | 163 | int i; |
144 | 164 | ||
145 | set_cpus_allowed(current, cpumask_of_cpu(boot_cpuid)); | 165 | if (image->type == KEXEC_TYPE_DEFAULT) { |
166 | /* normal kexec images are stored in temporary pages */ | ||
167 | for (ptr = &image->head; (entry = *ptr) && !(entry & IND_DONE); | ||
168 | ptr = (entry & IND_INDIRECTION) ? | ||
169 | phys_to_virt(entry & PAGE_MASK) : ptr + 1) { | ||
170 | if (!(entry & IND_DESTINATION)) { | ||
171 | map_and_flush(entry); | ||
172 | } | ||
173 | } | ||
174 | /* flush out last IND_DONE page */ | ||
175 | map_and_flush(entry); | ||
176 | } else { | ||
177 | /* crash type kexec images are copied to the crash region */ | ||
178 | for (i = 0; i < image->nr_segments; i++) { | ||
179 | struct kexec_segment *seg = &image->segment[i]; | ||
180 | for (paddr = seg->mem; paddr < seg->mem + seg->memsz; | ||
181 | paddr += PAGE_SIZE) { | ||
182 | map_and_flush(paddr); | ||
183 | } | ||
184 | } | ||
185 | } | ||
186 | |||
187 | /* also flush the kimage struct to be passed in as well */ | ||
188 | flush_dcache_range((unsigned long)image, | ||
189 | (unsigned long)image + sizeof(*image)); | ||
190 | } | ||
191 | |||
192 | static void mpc85xx_smp_machine_kexec(struct kimage *image) | ||
193 | { | ||
194 | int timeout = INT_MAX; | ||
195 | int i, num_cpus = num_present_cpus(); | ||
196 | |||
197 | mpc85xx_smp_flush_dcache_kexec(image); | ||
146 | 198 | ||
147 | smp_call_function(mpc85xx_smp_kexec_down, NULL, 0); | 199 | if (image->type == KEXEC_TYPE_DEFAULT) |
200 | smp_call_function(mpc85xx_smp_kexec_down, NULL, 0); | ||
148 | 201 | ||
149 | while ( (kexec_down_cpus != (num_online_cpus() - 1)) && | 202 | while ( (atomic_read(&kexec_down_cpus) != (num_cpus - 1)) && |
150 | ( timeout > 0 ) ) | 203 | ( timeout > 0 ) ) |
151 | { | 204 | { |
152 | timeout--; | 205 | timeout--; |
@@ -155,7 +208,7 @@ static void mpc85xx_smp_machine_kexec(struct kimage *image) | |||
155 | if ( !timeout ) | 208 | if ( !timeout ) |
156 | printk(KERN_ERR "Unable to bring down secondary cpu(s)"); | 209 | printk(KERN_ERR "Unable to bring down secondary cpu(s)"); |
157 | 210 | ||
158 | for (i = 0; i < num_present_cpus(); i++) | 211 | for (i = 0; i < num_cpus; i++) |
159 | { | 212 | { |
160 | if ( i == smp_processor_id() ) continue; | 213 | if ( i == smp_processor_id() ) continue; |
161 | mpic_reset_core(i); | 214 | mpic_reset_core(i); |
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype index d361f8119b1e..111138c55f9c 100644 --- a/arch/powerpc/platforms/Kconfig.cputype +++ b/arch/powerpc/platforms/Kconfig.cputype | |||
@@ -125,6 +125,7 @@ config 8xx | |||
125 | 125 | ||
126 | config E500 | 126 | config E500 |
127 | select FSL_EMB_PERFMON | 127 | select FSL_EMB_PERFMON |
128 | select PPC_FSL_BOOK3E | ||
128 | bool | 129 | bool |
129 | 130 | ||
130 | config PPC_E500MC | 131 | config PPC_E500MC |
@@ -166,9 +167,14 @@ config BOOKE | |||
166 | 167 | ||
167 | config FSL_BOOKE | 168 | config FSL_BOOKE |
168 | bool | 169 | bool |
169 | depends on E200 || E500 | 170 | depends on (E200 || E500) && PPC32 |
170 | default y | 171 | default y |
171 | 172 | ||
173 | # this is for common code between PPC32 & PPC64 FSL BOOKE | ||
174 | config PPC_FSL_BOOK3E | ||
175 | bool | ||
176 | select FSL_EMB_PERFMON | ||
177 | default y if FSL_BOOKE | ||
172 | 178 | ||
173 | config PTE_64BIT | 179 | config PTE_64BIT |
174 | bool | 180 | bool |
diff --git a/arch/powerpc/platforms/cell/ras.c b/arch/powerpc/platforms/cell/ras.c index 1d3c4effea10..5ec1e47a0d77 100644 --- a/arch/powerpc/platforms/cell/ras.c +++ b/arch/powerpc/platforms/cell/ras.c | |||
@@ -173,8 +173,10 @@ static int __init cbe_ptcal_enable(void) | |||
173 | return -ENODEV; | 173 | return -ENODEV; |
174 | 174 | ||
175 | size = of_get_property(np, "ibm,cbe-ptcal-size", NULL); | 175 | size = of_get_property(np, "ibm,cbe-ptcal-size", NULL); |
176 | if (!size) | 176 | if (!size) { |
177 | of_node_put(np); | ||
177 | return -ENODEV; | 178 | return -ENODEV; |
179 | } | ||
178 | 180 | ||
179 | pr_debug("%s: enabling PTCAL, size = 0x%x\n", __func__, *size); | 181 | pr_debug("%s: enabling PTCAL, size = 0x%x\n", __func__, *size); |
180 | order = get_order(*size); | 182 | order = get_order(*size); |
diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c index 5876e888e412..3f2e557344a3 100644 --- a/arch/powerpc/platforms/cell/spider-pic.c +++ b/arch/powerpc/platforms/cell/spider-pic.c | |||
@@ -258,8 +258,10 @@ static unsigned int __init spider_find_cascade_and_node(struct spider_pic *pic) | |||
258 | return NO_IRQ; | 258 | return NO_IRQ; |
259 | imap += intsize + 1; | 259 | imap += intsize + 1; |
260 | tmp = of_get_property(iic, "#interrupt-cells", NULL); | 260 | tmp = of_get_property(iic, "#interrupt-cells", NULL); |
261 | if (tmp == NULL) | 261 | if (tmp == NULL) { |
262 | of_node_put(iic); | ||
262 | return NO_IRQ; | 263 | return NO_IRQ; |
264 | } | ||
263 | intsize = *tmp; | 265 | intsize = *tmp; |
264 | /* Assume unit is last entry of interrupt specifier */ | 266 | /* Assume unit is last entry of interrupt specifier */ |
265 | unit = imap[intsize - 1]; | 267 | unit = imap[intsize - 1]; |
diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index 1a40da92154c..02f7b113a31b 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c | |||
@@ -154,6 +154,7 @@ static const struct file_operations __fops = { \ | |||
154 | .release = spufs_attr_release, \ | 154 | .release = spufs_attr_release, \ |
155 | .read = spufs_attr_read, \ | 155 | .read = spufs_attr_read, \ |
156 | .write = spufs_attr_write, \ | 156 | .write = spufs_attr_write, \ |
157 | .llseek = generic_file_llseek, \ | ||
157 | }; | 158 | }; |
158 | 159 | ||
159 | 160 | ||
@@ -521,6 +522,7 @@ static const struct file_operations spufs_cntl_fops = { | |||
521 | .release = spufs_cntl_release, | 522 | .release = spufs_cntl_release, |
522 | .read = simple_attr_read, | 523 | .read = simple_attr_read, |
523 | .write = simple_attr_write, | 524 | .write = simple_attr_write, |
525 | .llseek = generic_file_llseek, | ||
524 | .mmap = spufs_cntl_mmap, | 526 | .mmap = spufs_cntl_mmap, |
525 | }; | 527 | }; |
526 | 528 | ||
@@ -714,6 +716,7 @@ static ssize_t spufs_mbox_read(struct file *file, char __user *buf, | |||
714 | static const struct file_operations spufs_mbox_fops = { | 716 | static const struct file_operations spufs_mbox_fops = { |
715 | .open = spufs_pipe_open, | 717 | .open = spufs_pipe_open, |
716 | .read = spufs_mbox_read, | 718 | .read = spufs_mbox_read, |
719 | .llseek = no_llseek, | ||
717 | }; | 720 | }; |
718 | 721 | ||
719 | static ssize_t spufs_mbox_stat_read(struct file *file, char __user *buf, | 722 | static ssize_t spufs_mbox_stat_read(struct file *file, char __user *buf, |
@@ -743,6 +746,7 @@ static ssize_t spufs_mbox_stat_read(struct file *file, char __user *buf, | |||
743 | static const struct file_operations spufs_mbox_stat_fops = { | 746 | static const struct file_operations spufs_mbox_stat_fops = { |
744 | .open = spufs_pipe_open, | 747 | .open = spufs_pipe_open, |
745 | .read = spufs_mbox_stat_read, | 748 | .read = spufs_mbox_stat_read, |
749 | .llseek = no_llseek, | ||
746 | }; | 750 | }; |
747 | 751 | ||
748 | /* low-level ibox access function */ | 752 | /* low-level ibox access function */ |
@@ -863,6 +867,7 @@ static const struct file_operations spufs_ibox_fops = { | |||
863 | .read = spufs_ibox_read, | 867 | .read = spufs_ibox_read, |
864 | .poll = spufs_ibox_poll, | 868 | .poll = spufs_ibox_poll, |
865 | .fasync = spufs_ibox_fasync, | 869 | .fasync = spufs_ibox_fasync, |
870 | .llseek = no_llseek, | ||
866 | }; | 871 | }; |
867 | 872 | ||
868 | static ssize_t spufs_ibox_stat_read(struct file *file, char __user *buf, | 873 | static ssize_t spufs_ibox_stat_read(struct file *file, char __user *buf, |
@@ -890,6 +895,7 @@ static ssize_t spufs_ibox_stat_read(struct file *file, char __user *buf, | |||
890 | static const struct file_operations spufs_ibox_stat_fops = { | 895 | static const struct file_operations spufs_ibox_stat_fops = { |
891 | .open = spufs_pipe_open, | 896 | .open = spufs_pipe_open, |
892 | .read = spufs_ibox_stat_read, | 897 | .read = spufs_ibox_stat_read, |
898 | .llseek = no_llseek, | ||
893 | }; | 899 | }; |
894 | 900 | ||
895 | /* low-level mailbox write */ | 901 | /* low-level mailbox write */ |
@@ -1011,6 +1017,7 @@ static const struct file_operations spufs_wbox_fops = { | |||
1011 | .write = spufs_wbox_write, | 1017 | .write = spufs_wbox_write, |
1012 | .poll = spufs_wbox_poll, | 1018 | .poll = spufs_wbox_poll, |
1013 | .fasync = spufs_wbox_fasync, | 1019 | .fasync = spufs_wbox_fasync, |
1020 | .llseek = no_llseek, | ||
1014 | }; | 1021 | }; |
1015 | 1022 | ||
1016 | static ssize_t spufs_wbox_stat_read(struct file *file, char __user *buf, | 1023 | static ssize_t spufs_wbox_stat_read(struct file *file, char __user *buf, |
@@ -1038,6 +1045,7 @@ static ssize_t spufs_wbox_stat_read(struct file *file, char __user *buf, | |||
1038 | static const struct file_operations spufs_wbox_stat_fops = { | 1045 | static const struct file_operations spufs_wbox_stat_fops = { |
1039 | .open = spufs_pipe_open, | 1046 | .open = spufs_pipe_open, |
1040 | .read = spufs_wbox_stat_read, | 1047 | .read = spufs_wbox_stat_read, |
1048 | .llseek = no_llseek, | ||
1041 | }; | 1049 | }; |
1042 | 1050 | ||
1043 | static int spufs_signal1_open(struct inode *inode, struct file *file) | 1051 | static int spufs_signal1_open(struct inode *inode, struct file *file) |
@@ -1166,6 +1174,7 @@ static const struct file_operations spufs_signal1_fops = { | |||
1166 | .read = spufs_signal1_read, | 1174 | .read = spufs_signal1_read, |
1167 | .write = spufs_signal1_write, | 1175 | .write = spufs_signal1_write, |
1168 | .mmap = spufs_signal1_mmap, | 1176 | .mmap = spufs_signal1_mmap, |
1177 | .llseek = no_llseek, | ||
1169 | }; | 1178 | }; |
1170 | 1179 | ||
1171 | static const struct file_operations spufs_signal1_nosched_fops = { | 1180 | static const struct file_operations spufs_signal1_nosched_fops = { |
@@ -1173,6 +1182,7 @@ static const struct file_operations spufs_signal1_nosched_fops = { | |||
1173 | .release = spufs_signal1_release, | 1182 | .release = spufs_signal1_release, |
1174 | .write = spufs_signal1_write, | 1183 | .write = spufs_signal1_write, |
1175 | .mmap = spufs_signal1_mmap, | 1184 | .mmap = spufs_signal1_mmap, |
1185 | .llseek = no_llseek, | ||
1176 | }; | 1186 | }; |
1177 | 1187 | ||
1178 | static int spufs_signal2_open(struct inode *inode, struct file *file) | 1188 | static int spufs_signal2_open(struct inode *inode, struct file *file) |
@@ -1305,6 +1315,7 @@ static const struct file_operations spufs_signal2_fops = { | |||
1305 | .read = spufs_signal2_read, | 1315 | .read = spufs_signal2_read, |
1306 | .write = spufs_signal2_write, | 1316 | .write = spufs_signal2_write, |
1307 | .mmap = spufs_signal2_mmap, | 1317 | .mmap = spufs_signal2_mmap, |
1318 | .llseek = no_llseek, | ||
1308 | }; | 1319 | }; |
1309 | 1320 | ||
1310 | static const struct file_operations spufs_signal2_nosched_fops = { | 1321 | static const struct file_operations spufs_signal2_nosched_fops = { |
@@ -1312,6 +1323,7 @@ static const struct file_operations spufs_signal2_nosched_fops = { | |||
1312 | .release = spufs_signal2_release, | 1323 | .release = spufs_signal2_release, |
1313 | .write = spufs_signal2_write, | 1324 | .write = spufs_signal2_write, |
1314 | .mmap = spufs_signal2_mmap, | 1325 | .mmap = spufs_signal2_mmap, |
1326 | .llseek = no_llseek, | ||
1315 | }; | 1327 | }; |
1316 | 1328 | ||
1317 | /* | 1329 | /* |
@@ -1451,6 +1463,7 @@ static const struct file_operations spufs_mss_fops = { | |||
1451 | .open = spufs_mss_open, | 1463 | .open = spufs_mss_open, |
1452 | .release = spufs_mss_release, | 1464 | .release = spufs_mss_release, |
1453 | .mmap = spufs_mss_mmap, | 1465 | .mmap = spufs_mss_mmap, |
1466 | .llseek = no_llseek, | ||
1454 | }; | 1467 | }; |
1455 | 1468 | ||
1456 | static int | 1469 | static int |
@@ -1508,6 +1521,7 @@ static const struct file_operations spufs_psmap_fops = { | |||
1508 | .open = spufs_psmap_open, | 1521 | .open = spufs_psmap_open, |
1509 | .release = spufs_psmap_release, | 1522 | .release = spufs_psmap_release, |
1510 | .mmap = spufs_psmap_mmap, | 1523 | .mmap = spufs_psmap_mmap, |
1524 | .llseek = no_llseek, | ||
1511 | }; | 1525 | }; |
1512 | 1526 | ||
1513 | 1527 | ||
@@ -1871,6 +1885,7 @@ static const struct file_operations spufs_mfc_fops = { | |||
1871 | .fsync = spufs_mfc_fsync, | 1885 | .fsync = spufs_mfc_fsync, |
1872 | .fasync = spufs_mfc_fasync, | 1886 | .fasync = spufs_mfc_fasync, |
1873 | .mmap = spufs_mfc_mmap, | 1887 | .mmap = spufs_mfc_mmap, |
1888 | .llseek = no_llseek, | ||
1874 | }; | 1889 | }; |
1875 | 1890 | ||
1876 | static int spufs_npc_set(void *data, u64 val) | 1891 | static int spufs_npc_set(void *data, u64 val) |
@@ -2246,6 +2261,7 @@ static ssize_t spufs_dma_info_read(struct file *file, char __user *buf, | |||
2246 | static const struct file_operations spufs_dma_info_fops = { | 2261 | static const struct file_operations spufs_dma_info_fops = { |
2247 | .open = spufs_info_open, | 2262 | .open = spufs_info_open, |
2248 | .read = spufs_dma_info_read, | 2263 | .read = spufs_dma_info_read, |
2264 | .llseek = no_llseek, | ||
2249 | }; | 2265 | }; |
2250 | 2266 | ||
2251 | static ssize_t __spufs_proxydma_info_read(struct spu_context *ctx, | 2267 | static ssize_t __spufs_proxydma_info_read(struct spu_context *ctx, |
@@ -2299,6 +2315,7 @@ static ssize_t spufs_proxydma_info_read(struct file *file, char __user *buf, | |||
2299 | static const struct file_operations spufs_proxydma_info_fops = { | 2315 | static const struct file_operations spufs_proxydma_info_fops = { |
2300 | .open = spufs_info_open, | 2316 | .open = spufs_info_open, |
2301 | .read = spufs_proxydma_info_read, | 2317 | .read = spufs_proxydma_info_read, |
2318 | .llseek = no_llseek, | ||
2302 | }; | 2319 | }; |
2303 | 2320 | ||
2304 | static int spufs_show_tid(struct seq_file *s, void *private) | 2321 | static int spufs_show_tid(struct seq_file *s, void *private) |
@@ -2585,6 +2602,7 @@ static const struct file_operations spufs_switch_log_fops = { | |||
2585 | .read = spufs_switch_log_read, | 2602 | .read = spufs_switch_log_read, |
2586 | .poll = spufs_switch_log_poll, | 2603 | .poll = spufs_switch_log_poll, |
2587 | .release = spufs_switch_log_release, | 2604 | .release = spufs_switch_log_release, |
2605 | .llseek = no_llseek, | ||
2588 | }; | 2606 | }; |
2589 | 2607 | ||
2590 | /** | 2608 | /** |
diff --git a/arch/powerpc/platforms/chrp/nvram.c b/arch/powerpc/platforms/chrp/nvram.c index ba3588f2d8e0..d3ceff04ffc7 100644 --- a/arch/powerpc/platforms/chrp/nvram.c +++ b/arch/powerpc/platforms/chrp/nvram.c | |||
@@ -74,8 +74,10 @@ void __init chrp_nvram_init(void) | |||
74 | return; | 74 | return; |
75 | 75 | ||
76 | nbytes_p = of_get_property(nvram, "#bytes", &proplen); | 76 | nbytes_p = of_get_property(nvram, "#bytes", &proplen); |
77 | if (nbytes_p == NULL || proplen != sizeof(unsigned int)) | 77 | if (nbytes_p == NULL || proplen != sizeof(unsigned int)) { |
78 | of_node_put(nvram); | ||
78 | return; | 79 | return; |
80 | } | ||
79 | 81 | ||
80 | nvram_size = *nbytes_p; | 82 | nvram_size = *nbytes_p; |
81 | 83 | ||
diff --git a/arch/powerpc/platforms/iseries/Makefile b/arch/powerpc/platforms/iseries/Makefile index ce014928d460..a7602b11ed9d 100644 --- a/arch/powerpc/platforms/iseries/Makefile +++ b/arch/powerpc/platforms/iseries/Makefile | |||
@@ -1,4 +1,4 @@ | |||
1 | EXTRA_CFLAGS += -mno-minimal-toc | 1 | ccflags-y := -mno-minimal-toc |
2 | 2 | ||
3 | obj-y += exception.o | 3 | obj-y += exception.o |
4 | obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o dt.o mf.o lpevents.o \ | 4 | obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o dt.o mf.o lpevents.o \ |
diff --git a/arch/powerpc/platforms/iseries/dt.c b/arch/powerpc/platforms/iseries/dt.c index 7f45a51fe793..fdb7384c0c4f 100644 --- a/arch/powerpc/platforms/iseries/dt.c +++ b/arch/powerpc/platforms/iseries/dt.c | |||
@@ -243,7 +243,7 @@ static void __init dt_cpus(struct iseries_flat_dt *dt) | |||
243 | pft_size[1] = __ilog2(HvCallHpt_getHptPages() * HW_PAGE_SIZE); | 243 | pft_size[1] = __ilog2(HvCallHpt_getHptPages() * HW_PAGE_SIZE); |
244 | 244 | ||
245 | for (i = 0; i < NR_CPUS; i++) { | 245 | for (i = 0; i < NR_CPUS; i++) { |
246 | if (lppaca[i].dyn_proc_status >= 2) | 246 | if (lppaca_of(i).dyn_proc_status >= 2) |
247 | continue; | 247 | continue; |
248 | 248 | ||
249 | snprintf(p, 32 - (p - buf), "@%d", i); | 249 | snprintf(p, 32 - (p - buf), "@%d", i); |
@@ -251,7 +251,7 @@ static void __init dt_cpus(struct iseries_flat_dt *dt) | |||
251 | 251 | ||
252 | dt_prop_str(dt, "device_type", device_type_cpu); | 252 | dt_prop_str(dt, "device_type", device_type_cpu); |
253 | 253 | ||
254 | index = lppaca[i].dyn_hv_phys_proc_index; | 254 | index = lppaca_of(i).dyn_hv_phys_proc_index; |
255 | d = &xIoHriProcessorVpd[index]; | 255 | d = &xIoHriProcessorVpd[index]; |
256 | 256 | ||
257 | dt_prop_u32(dt, "i-cache-size", d->xInstCacheSize * 1024); | 257 | dt_prop_u32(dt, "i-cache-size", d->xInstCacheSize * 1024); |
diff --git a/arch/powerpc/platforms/iseries/smp.c b/arch/powerpc/platforms/iseries/smp.c index 6590850045af..6c6029914dbc 100644 --- a/arch/powerpc/platforms/iseries/smp.c +++ b/arch/powerpc/platforms/iseries/smp.c | |||
@@ -91,7 +91,7 @@ static void smp_iSeries_kick_cpu(int nr) | |||
91 | BUG_ON((nr < 0) || (nr >= NR_CPUS)); | 91 | BUG_ON((nr < 0) || (nr >= NR_CPUS)); |
92 | 92 | ||
93 | /* Verify that our partition has a processor nr */ | 93 | /* Verify that our partition has a processor nr */ |
94 | if (lppaca[nr].dyn_proc_status >= 2) | 94 | if (lppaca_of(nr).dyn_proc_status >= 2) |
95 | return; | 95 | return; |
96 | 96 | ||
97 | /* The processor is currently spinning, waiting | 97 | /* The processor is currently spinning, waiting |
diff --git a/arch/powerpc/platforms/maple/setup.c b/arch/powerpc/platforms/maple/setup.c index 3fff8d979b41..fe34c3d9bb74 100644 --- a/arch/powerpc/platforms/maple/setup.c +++ b/arch/powerpc/platforms/maple/setup.c | |||
@@ -358,6 +358,7 @@ static int __init maple_cpc925_edac_setup(void) | |||
358 | model = (const unsigned char *)of_get_property(np, "model", NULL); | 358 | model = (const unsigned char *)of_get_property(np, "model", NULL); |
359 | if (!model) { | 359 | if (!model) { |
360 | printk(KERN_ERR "%s: Unabel to get model info\n", __func__); | 360 | printk(KERN_ERR "%s: Unabel to get model info\n", __func__); |
361 | of_node_put(np); | ||
361 | return -ENODEV; | 362 | return -ENODEV; |
362 | } | 363 | } |
363 | 364 | ||
diff --git a/arch/powerpc/platforms/powermac/pfunc_core.c b/arch/powerpc/platforms/powermac/pfunc_core.c index cec635942657..b0c3777528a1 100644 --- a/arch/powerpc/platforms/powermac/pfunc_core.c +++ b/arch/powerpc/platforms/powermac/pfunc_core.c | |||
@@ -837,8 +837,10 @@ struct pmf_function *__pmf_find_function(struct device_node *target, | |||
837 | return NULL; | 837 | return NULL; |
838 | find_it: | 838 | find_it: |
839 | dev = pmf_find_device(actor); | 839 | dev = pmf_find_device(actor); |
840 | if (dev == NULL) | 840 | if (dev == NULL) { |
841 | return NULL; | 841 | result = NULL; |
842 | goto out; | ||
843 | } | ||
842 | 844 | ||
843 | list_for_each_entry(func, &dev->functions, link) { | 845 | list_for_each_entry(func, &dev->functions, link) { |
844 | if (name && strcmp(name, func->name)) | 846 | if (name && strcmp(name, func->name)) |
@@ -850,8 +852,9 @@ struct pmf_function *__pmf_find_function(struct device_node *target, | |||
850 | result = func; | 852 | result = func; |
851 | break; | 853 | break; |
852 | } | 854 | } |
853 | of_node_put(actor); | ||
854 | pmf_put_device(dev); | 855 | pmf_put_device(dev); |
856 | out: | ||
857 | of_node_put(actor); | ||
855 | return result; | 858 | return result; |
856 | } | 859 | } |
857 | 860 | ||
diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile index 046ace9c4381..59eb8bdaa79d 100644 --- a/arch/powerpc/platforms/pseries/Makefile +++ b/arch/powerpc/platforms/pseries/Makefile | |||
@@ -1,14 +1,9 @@ | |||
1 | ifeq ($(CONFIG_PPC64),y) | 1 | ccflags-$(CONFIG_PPC64) := -mno-minimal-toc |
2 | EXTRA_CFLAGS += -mno-minimal-toc | 2 | ccflags-$(CONFIG_PPC_PSERIES_DEBUG) += -DDEBUG |
3 | endif | ||
4 | |||
5 | ifeq ($(CONFIG_PPC_PSERIES_DEBUG),y) | ||
6 | EXTRA_CFLAGS += -DDEBUG | ||
7 | endif | ||
8 | 3 | ||
9 | obj-y := lpar.o hvCall.o nvram.o reconfig.o \ | 4 | obj-y := lpar.o hvCall.o nvram.o reconfig.o \ |
10 | setup.o iommu.o event_sources.o ras.o \ | 5 | setup.o iommu.o event_sources.o ras.o \ |
11 | firmware.o power.o dlpar.o | 6 | firmware.o power.o dlpar.o mobility.o |
12 | obj-$(CONFIG_SMP) += smp.o | 7 | obj-$(CONFIG_SMP) += smp.o |
13 | obj-$(CONFIG_XICS) += xics.o | 8 | obj-$(CONFIG_XICS) += xics.o |
14 | obj-$(CONFIG_SCANLOG) += scanlog.o | 9 | obj-$(CONFIG_SCANLOG) += scanlog.o |
@@ -23,7 +18,7 @@ obj-$(CONFIG_MEMORY_HOTPLUG) += hotplug-memory.o | |||
23 | obj-$(CONFIG_HVC_CONSOLE) += hvconsole.o | 18 | obj-$(CONFIG_HVC_CONSOLE) += hvconsole.o |
24 | obj-$(CONFIG_HVCS) += hvcserver.o | 19 | obj-$(CONFIG_HVCS) += hvcserver.o |
25 | obj-$(CONFIG_HCALL_STATS) += hvCall_inst.o | 20 | obj-$(CONFIG_HCALL_STATS) += hvCall_inst.o |
26 | obj-$(CONFIG_PHYP_DUMP) += phyp_dump.o | 21 | obj-$(CONFIG_PHYP_DUMP) += phyp_dump.o |
27 | obj-$(CONFIG_CMM) += cmm.o | 22 | obj-$(CONFIG_CMM) += cmm.o |
28 | obj-$(CONFIG_DTL) += dtl.o | 23 | obj-$(CONFIG_DTL) += dtl.o |
29 | 24 | ||
diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c index 72d8054fa739..b74a9230edc9 100644 --- a/arch/powerpc/platforms/pseries/dlpar.c +++ b/arch/powerpc/platforms/pseries/dlpar.c | |||
@@ -33,7 +33,7 @@ struct cc_workarea { | |||
33 | u32 prop_offset; | 33 | u32 prop_offset; |
34 | }; | 34 | }; |
35 | 35 | ||
36 | static void dlpar_free_cc_property(struct property *prop) | 36 | void dlpar_free_cc_property(struct property *prop) |
37 | { | 37 | { |
38 | kfree(prop->name); | 38 | kfree(prop->name); |
39 | kfree(prop->value); | 39 | kfree(prop->value); |
@@ -55,13 +55,12 @@ static struct property *dlpar_parse_cc_property(struct cc_workarea *ccwa) | |||
55 | 55 | ||
56 | prop->length = ccwa->prop_length; | 56 | prop->length = ccwa->prop_length; |
57 | value = (char *)ccwa + ccwa->prop_offset; | 57 | value = (char *)ccwa + ccwa->prop_offset; |
58 | prop->value = kzalloc(prop->length, GFP_KERNEL); | 58 | prop->value = kmemdup(value, prop->length, GFP_KERNEL); |
59 | if (!prop->value) { | 59 | if (!prop->value) { |
60 | dlpar_free_cc_property(prop); | 60 | dlpar_free_cc_property(prop); |
61 | return NULL; | 61 | return NULL; |
62 | } | 62 | } |
63 | 63 | ||
64 | memcpy(prop->value, value, prop->length); | ||
65 | return prop; | 64 | return prop; |
66 | } | 65 | } |
67 | 66 | ||
@@ -102,7 +101,7 @@ static void dlpar_free_one_cc_node(struct device_node *dn) | |||
102 | kfree(dn); | 101 | kfree(dn); |
103 | } | 102 | } |
104 | 103 | ||
105 | static void dlpar_free_cc_nodes(struct device_node *dn) | 104 | void dlpar_free_cc_nodes(struct device_node *dn) |
106 | { | 105 | { |
107 | if (dn->child) | 106 | if (dn->child) |
108 | dlpar_free_cc_nodes(dn->child); | 107 | dlpar_free_cc_nodes(dn->child); |
diff --git a/arch/powerpc/platforms/pseries/dtl.c b/arch/powerpc/platforms/pseries/dtl.c index a00addb55945..c371bc06434b 100644 --- a/arch/powerpc/platforms/pseries/dtl.c +++ b/arch/powerpc/platforms/pseries/dtl.c | |||
@@ -23,37 +23,22 @@ | |||
23 | #include <linux/init.h> | 23 | #include <linux/init.h> |
24 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
25 | #include <linux/debugfs.h> | 25 | #include <linux/debugfs.h> |
26 | #include <linux/spinlock.h> | ||
26 | #include <asm/smp.h> | 27 | #include <asm/smp.h> |
27 | #include <asm/system.h> | 28 | #include <asm/system.h> |
28 | #include <asm/uaccess.h> | 29 | #include <asm/uaccess.h> |
29 | #include <asm/firmware.h> | 30 | #include <asm/firmware.h> |
31 | #include <asm/lppaca.h> | ||
30 | 32 | ||
31 | #include "plpar_wrappers.h" | 33 | #include "plpar_wrappers.h" |
32 | 34 | ||
33 | /* | ||
34 | * Layout of entries in the hypervisor's DTL buffer. Although we don't | ||
35 | * actually access the internals of an entry (we only need to know the size), | ||
36 | * we might as well define it here for reference. | ||
37 | */ | ||
38 | struct dtl_entry { | ||
39 | u8 dispatch_reason; | ||
40 | u8 preempt_reason; | ||
41 | u16 processor_id; | ||
42 | u32 enqueue_to_dispatch_time; | ||
43 | u32 ready_to_enqueue_time; | ||
44 | u32 waiting_to_ready_time; | ||
45 | u64 timebase; | ||
46 | u64 fault_addr; | ||
47 | u64 srr0; | ||
48 | u64 srr1; | ||
49 | }; | ||
50 | |||
51 | struct dtl { | 35 | struct dtl { |
52 | struct dtl_entry *buf; | 36 | struct dtl_entry *buf; |
53 | struct dentry *file; | 37 | struct dentry *file; |
54 | int cpu; | 38 | int cpu; |
55 | int buf_entries; | 39 | int buf_entries; |
56 | u64 last_idx; | 40 | u64 last_idx; |
41 | spinlock_t lock; | ||
57 | }; | 42 | }; |
58 | static DEFINE_PER_CPU(struct dtl, cpu_dtl); | 43 | static DEFINE_PER_CPU(struct dtl, cpu_dtl); |
59 | 44 | ||
@@ -72,25 +57,97 @@ static u8 dtl_event_mask = 0x7; | |||
72 | static int dtl_buf_entries = (16 * 85); | 57 | static int dtl_buf_entries = (16 * 85); |
73 | 58 | ||
74 | 59 | ||
75 | static int dtl_enable(struct dtl *dtl) | 60 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING |
61 | struct dtl_ring { | ||
62 | u64 write_index; | ||
63 | struct dtl_entry *write_ptr; | ||
64 | struct dtl_entry *buf; | ||
65 | struct dtl_entry *buf_end; | ||
66 | u8 saved_dtl_mask; | ||
67 | }; | ||
68 | |||
69 | static DEFINE_PER_CPU(struct dtl_ring, dtl_rings); | ||
70 | |||
71 | static atomic_t dtl_count; | ||
72 | |||
73 | /* | ||
74 | * The cpu accounting code controls the DTL ring buffer, and we get | ||
75 | * given entries as they are processed. | ||
76 | */ | ||
77 | static void consume_dtle(struct dtl_entry *dtle, u64 index) | ||
76 | { | 78 | { |
77 | unsigned long addr; | 79 | struct dtl_ring *dtlr = &__get_cpu_var(dtl_rings); |
78 | int ret, hwcpu; | 80 | struct dtl_entry *wp = dtlr->write_ptr; |
81 | struct lppaca *vpa = local_paca->lppaca_ptr; | ||
79 | 82 | ||
80 | /* only allow one reader */ | 83 | if (!wp) |
81 | if (dtl->buf) | 84 | return; |
82 | return -EBUSY; | ||
83 | 85 | ||
84 | /* we need to store the original allocation size for use during read */ | 86 | *wp = *dtle; |
85 | dtl->buf_entries = dtl_buf_entries; | 87 | barrier(); |
86 | 88 | ||
87 | dtl->buf = kmalloc_node(dtl->buf_entries * sizeof(struct dtl_entry), | 89 | /* check for hypervisor ring buffer overflow, ignore this entry if so */ |
88 | GFP_KERNEL, cpu_to_node(dtl->cpu)); | 90 | if (index + N_DISPATCH_LOG < vpa->dtl_idx) |
89 | if (!dtl->buf) { | 91 | return; |
90 | printk(KERN_WARNING "%s: buffer alloc failed for cpu %d\n", | 92 | |
91 | __func__, dtl->cpu); | 93 | ++wp; |
92 | return -ENOMEM; | 94 | if (wp == dtlr->buf_end) |
93 | } | 95 | wp = dtlr->buf; |
96 | dtlr->write_ptr = wp; | ||
97 | |||
98 | /* incrementing write_index makes the new entry visible */ | ||
99 | smp_wmb(); | ||
100 | ++dtlr->write_index; | ||
101 | } | ||
102 | |||
103 | static int dtl_start(struct dtl *dtl) | ||
104 | { | ||
105 | struct dtl_ring *dtlr = &per_cpu(dtl_rings, dtl->cpu); | ||
106 | |||
107 | dtlr->buf = dtl->buf; | ||
108 | dtlr->buf_end = dtl->buf + dtl->buf_entries; | ||
109 | dtlr->write_index = 0; | ||
110 | |||
111 | /* setting write_ptr enables logging into our buffer */ | ||
112 | smp_wmb(); | ||
113 | dtlr->write_ptr = dtl->buf; | ||
114 | |||
115 | /* enable event logging */ | ||
116 | dtlr->saved_dtl_mask = lppaca_of(dtl->cpu).dtl_enable_mask; | ||
117 | lppaca_of(dtl->cpu).dtl_enable_mask |= dtl_event_mask; | ||
118 | |||
119 | dtl_consumer = consume_dtle; | ||
120 | atomic_inc(&dtl_count); | ||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | static void dtl_stop(struct dtl *dtl) | ||
125 | { | ||
126 | struct dtl_ring *dtlr = &per_cpu(dtl_rings, dtl->cpu); | ||
127 | |||
128 | dtlr->write_ptr = NULL; | ||
129 | smp_wmb(); | ||
130 | |||
131 | dtlr->buf = NULL; | ||
132 | |||
133 | /* restore dtl_enable_mask */ | ||
134 | lppaca_of(dtl->cpu).dtl_enable_mask = dtlr->saved_dtl_mask; | ||
135 | |||
136 | if (atomic_dec_and_test(&dtl_count)) | ||
137 | dtl_consumer = NULL; | ||
138 | } | ||
139 | |||
140 | static u64 dtl_current_index(struct dtl *dtl) | ||
141 | { | ||
142 | return per_cpu(dtl_rings, dtl->cpu).write_index; | ||
143 | } | ||
144 | |||
145 | #else /* CONFIG_VIRT_CPU_ACCOUNTING */ | ||
146 | |||
147 | static int dtl_start(struct dtl *dtl) | ||
148 | { | ||
149 | unsigned long addr; | ||
150 | int ret, hwcpu; | ||
94 | 151 | ||
95 | /* Register our dtl buffer with the hypervisor. The HV expects the | 152 | /* Register our dtl buffer with the hypervisor. The HV expects the |
96 | * buffer size to be passed in the second word of the buffer */ | 153 | * buffer size to be passed in the second word of the buffer */ |
@@ -102,34 +159,82 @@ static int dtl_enable(struct dtl *dtl) | |||
102 | if (ret) { | 159 | if (ret) { |
103 | printk(KERN_WARNING "%s: DTL registration for cpu %d (hw %d) " | 160 | printk(KERN_WARNING "%s: DTL registration for cpu %d (hw %d) " |
104 | "failed with %d\n", __func__, dtl->cpu, hwcpu, ret); | 161 | "failed with %d\n", __func__, dtl->cpu, hwcpu, ret); |
105 | kfree(dtl->buf); | ||
106 | return -EIO; | 162 | return -EIO; |
107 | } | 163 | } |
108 | 164 | ||
109 | /* set our initial buffer indices */ | 165 | /* set our initial buffer indices */ |
110 | dtl->last_idx = lppaca[dtl->cpu].dtl_idx = 0; | 166 | lppaca_of(dtl->cpu).dtl_idx = 0; |
111 | 167 | ||
112 | /* ensure that our updates to the lppaca fields have occurred before | 168 | /* ensure that our updates to the lppaca fields have occurred before |
113 | * we actually enable the logging */ | 169 | * we actually enable the logging */ |
114 | smp_wmb(); | 170 | smp_wmb(); |
115 | 171 | ||
116 | /* enable event logging */ | 172 | /* enable event logging */ |
117 | lppaca[dtl->cpu].dtl_enable_mask = dtl_event_mask; | 173 | lppaca_of(dtl->cpu).dtl_enable_mask = dtl_event_mask; |
118 | 174 | ||
119 | return 0; | 175 | return 0; |
120 | } | 176 | } |
121 | 177 | ||
122 | static void dtl_disable(struct dtl *dtl) | 178 | static void dtl_stop(struct dtl *dtl) |
123 | { | 179 | { |
124 | int hwcpu = get_hard_smp_processor_id(dtl->cpu); | 180 | int hwcpu = get_hard_smp_processor_id(dtl->cpu); |
125 | 181 | ||
126 | lppaca[dtl->cpu].dtl_enable_mask = 0x0; | 182 | lppaca_of(dtl->cpu).dtl_enable_mask = 0x0; |
127 | 183 | ||
128 | unregister_dtl(hwcpu, __pa(dtl->buf)); | 184 | unregister_dtl(hwcpu, __pa(dtl->buf)); |
185 | } | ||
186 | |||
187 | static u64 dtl_current_index(struct dtl *dtl) | ||
188 | { | ||
189 | return lppaca_of(dtl->cpu).dtl_idx; | ||
190 | } | ||
191 | #endif /* CONFIG_VIRT_CPU_ACCOUNTING */ | ||
192 | |||
193 | static int dtl_enable(struct dtl *dtl) | ||
194 | { | ||
195 | long int n_entries; | ||
196 | long int rc; | ||
197 | struct dtl_entry *buf = NULL; | ||
129 | 198 | ||
199 | /* only allow one reader */ | ||
200 | if (dtl->buf) | ||
201 | return -EBUSY; | ||
202 | |||
203 | n_entries = dtl_buf_entries; | ||
204 | buf = kmalloc_node(n_entries * sizeof(struct dtl_entry), | ||
205 | GFP_KERNEL, cpu_to_node(dtl->cpu)); | ||
206 | if (!buf) { | ||
207 | printk(KERN_WARNING "%s: buffer alloc failed for cpu %d\n", | ||
208 | __func__, dtl->cpu); | ||
209 | return -ENOMEM; | ||
210 | } | ||
211 | |||
212 | spin_lock(&dtl->lock); | ||
213 | rc = -EBUSY; | ||
214 | if (!dtl->buf) { | ||
215 | /* store the original allocation size for use during read */ | ||
216 | dtl->buf_entries = n_entries; | ||
217 | dtl->buf = buf; | ||
218 | dtl->last_idx = 0; | ||
219 | rc = dtl_start(dtl); | ||
220 | if (rc) | ||
221 | dtl->buf = NULL; | ||
222 | } | ||
223 | spin_unlock(&dtl->lock); | ||
224 | |||
225 | if (rc) | ||
226 | kfree(buf); | ||
227 | return rc; | ||
228 | } | ||
229 | |||
230 | static void dtl_disable(struct dtl *dtl) | ||
231 | { | ||
232 | spin_lock(&dtl->lock); | ||
233 | dtl_stop(dtl); | ||
130 | kfree(dtl->buf); | 234 | kfree(dtl->buf); |
131 | dtl->buf = NULL; | 235 | dtl->buf = NULL; |
132 | dtl->buf_entries = 0; | 236 | dtl->buf_entries = 0; |
237 | spin_unlock(&dtl->lock); | ||
133 | } | 238 | } |
134 | 239 | ||
135 | /* file interface */ | 240 | /* file interface */ |
@@ -157,8 +262,9 @@ static int dtl_file_release(struct inode *inode, struct file *filp) | |||
157 | static ssize_t dtl_file_read(struct file *filp, char __user *buf, size_t len, | 262 | static ssize_t dtl_file_read(struct file *filp, char __user *buf, size_t len, |
158 | loff_t *pos) | 263 | loff_t *pos) |
159 | { | 264 | { |
160 | int rc, cur_idx, last_idx, n_read, n_req, read_size; | 265 | long int rc, n_read, n_req, read_size; |
161 | struct dtl *dtl; | 266 | struct dtl *dtl; |
267 | u64 cur_idx, last_idx, i; | ||
162 | 268 | ||
163 | if ((len % sizeof(struct dtl_entry)) != 0) | 269 | if ((len % sizeof(struct dtl_entry)) != 0) |
164 | return -EINVAL; | 270 | return -EINVAL; |
@@ -171,41 +277,48 @@ static ssize_t dtl_file_read(struct file *filp, char __user *buf, size_t len, | |||
171 | /* actual number of entries read */ | 277 | /* actual number of entries read */ |
172 | n_read = 0; | 278 | n_read = 0; |
173 | 279 | ||
174 | cur_idx = lppaca[dtl->cpu].dtl_idx; | 280 | spin_lock(&dtl->lock); |
281 | |||
282 | cur_idx = dtl_current_index(dtl); | ||
175 | last_idx = dtl->last_idx; | 283 | last_idx = dtl->last_idx; |
176 | 284 | ||
177 | if (cur_idx - last_idx > dtl->buf_entries) { | 285 | if (last_idx + dtl->buf_entries <= cur_idx) |
178 | pr_debug("%s: hv buffer overflow for cpu %d, samples lost\n", | 286 | last_idx = cur_idx - dtl->buf_entries + 1; |
179 | __func__, dtl->cpu); | 287 | |
180 | } | 288 | if (last_idx + n_req > cur_idx) |
289 | n_req = cur_idx - last_idx; | ||
290 | |||
291 | if (n_req > 0) | ||
292 | dtl->last_idx = last_idx + n_req; | ||
293 | |||
294 | spin_unlock(&dtl->lock); | ||
295 | |||
296 | if (n_req <= 0) | ||
297 | return 0; | ||
181 | 298 | ||
182 | cur_idx %= dtl->buf_entries; | 299 | i = last_idx % dtl->buf_entries; |
183 | last_idx %= dtl->buf_entries; | ||
184 | 300 | ||
185 | /* read the tail of the buffer if we've wrapped */ | 301 | /* read the tail of the buffer if we've wrapped */ |
186 | if (last_idx > cur_idx) { | 302 | if (i + n_req > dtl->buf_entries) { |
187 | read_size = min(n_req, dtl->buf_entries - last_idx); | 303 | read_size = dtl->buf_entries - i; |
188 | 304 | ||
189 | rc = copy_to_user(buf, &dtl->buf[last_idx], | 305 | rc = copy_to_user(buf, &dtl->buf[i], |
190 | read_size * sizeof(struct dtl_entry)); | 306 | read_size * sizeof(struct dtl_entry)); |
191 | if (rc) | 307 | if (rc) |
192 | return -EFAULT; | 308 | return -EFAULT; |
193 | 309 | ||
194 | last_idx = 0; | 310 | i = 0; |
195 | n_req -= read_size; | 311 | n_req -= read_size; |
196 | n_read += read_size; | 312 | n_read += read_size; |
197 | buf += read_size * sizeof(struct dtl_entry); | 313 | buf += read_size * sizeof(struct dtl_entry); |
198 | } | 314 | } |
199 | 315 | ||
200 | /* .. and now the head */ | 316 | /* .. and now the head */ |
201 | read_size = min(n_req, cur_idx - last_idx); | 317 | rc = copy_to_user(buf, &dtl->buf[i], n_req * sizeof(struct dtl_entry)); |
202 | rc = copy_to_user(buf, &dtl->buf[last_idx], | ||
203 | read_size * sizeof(struct dtl_entry)); | ||
204 | if (rc) | 318 | if (rc) |
205 | return -EFAULT; | 319 | return -EFAULT; |
206 | 320 | ||
207 | n_read += read_size; | 321 | n_read += n_req; |
208 | dtl->last_idx += n_read; | ||
209 | 322 | ||
210 | return n_read * sizeof(struct dtl_entry); | 323 | return n_read * sizeof(struct dtl_entry); |
211 | } | 324 | } |
@@ -263,6 +376,7 @@ static int dtl_init(void) | |||
263 | /* set up the per-cpu log structures */ | 376 | /* set up the per-cpu log structures */ |
264 | for_each_possible_cpu(i) { | 377 | for_each_possible_cpu(i) { |
265 | struct dtl *dtl = &per_cpu(cpu_dtl, i); | 378 | struct dtl *dtl = &per_cpu(cpu_dtl, i); |
379 | spin_lock_init(&dtl->lock); | ||
266 | dtl->cpu = i; | 380 | dtl->cpu = i; |
267 | 381 | ||
268 | rc = dtl_setup_file(dtl); | 382 | rc = dtl_setup_file(dtl); |
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index cf79b46d8f88..f129040d974c 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c | |||
@@ -248,11 +248,13 @@ void vpa_init(int cpu) | |||
248 | int hwcpu = get_hard_smp_processor_id(cpu); | 248 | int hwcpu = get_hard_smp_processor_id(cpu); |
249 | unsigned long addr; | 249 | unsigned long addr; |
250 | long ret; | 250 | long ret; |
251 | struct paca_struct *pp; | ||
252 | struct dtl_entry *dtl; | ||
251 | 253 | ||
252 | if (cpu_has_feature(CPU_FTR_ALTIVEC)) | 254 | if (cpu_has_feature(CPU_FTR_ALTIVEC)) |
253 | lppaca[cpu].vmxregs_in_use = 1; | 255 | lppaca_of(cpu).vmxregs_in_use = 1; |
254 | 256 | ||
255 | addr = __pa(&lppaca[cpu]); | 257 | addr = __pa(&lppaca_of(cpu)); |
256 | ret = register_vpa(hwcpu, addr); | 258 | ret = register_vpa(hwcpu, addr); |
257 | 259 | ||
258 | if (ret) { | 260 | if (ret) { |
@@ -274,6 +276,25 @@ void vpa_init(int cpu) | |||
274 | "registration for cpu %d (hw %d) of area %lx " | 276 | "registration for cpu %d (hw %d) of area %lx " |
275 | "returns %ld\n", cpu, hwcpu, addr, ret); | 277 | "returns %ld\n", cpu, hwcpu, addr, ret); |
276 | } | 278 | } |
279 | |||
280 | /* | ||
281 | * Register dispatch trace log, if one has been allocated. | ||
282 | */ | ||
283 | pp = &paca[cpu]; | ||
284 | dtl = pp->dispatch_log; | ||
285 | if (dtl) { | ||
286 | pp->dtl_ridx = 0; | ||
287 | pp->dtl_curr = dtl; | ||
288 | lppaca_of(cpu).dtl_idx = 0; | ||
289 | |||
290 | /* hypervisor reads buffer length from this field */ | ||
291 | dtl->enqueue_to_dispatch_time = DISPATCH_LOG_BYTES; | ||
292 | ret = register_dtl(hwcpu, __pa(dtl)); | ||
293 | if (ret) | ||
294 | pr_warn("DTL registration failed for cpu %d (%ld)\n", | ||
295 | cpu, ret); | ||
296 | lppaca_of(cpu).dtl_enable_mask = 2; | ||
297 | } | ||
277 | } | 298 | } |
278 | 299 | ||
279 | static long pSeries_lpar_hpte_insert(unsigned long hpte_group, | 300 | static long pSeries_lpar_hpte_insert(unsigned long hpte_group, |
diff --git a/arch/powerpc/platforms/pseries/mobility.c b/arch/powerpc/platforms/pseries/mobility.c new file mode 100644 index 000000000000..3e7f651e50ac --- /dev/null +++ b/arch/powerpc/platforms/pseries/mobility.c | |||
@@ -0,0 +1,362 @@ | |||
1 | /* | ||
2 | * Support for Partition Mobility/Migration | ||
3 | * | ||
4 | * Copyright (C) 2010 Nathan Fontenot | ||
5 | * Copyright (C) 2010 IBM Corporation | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License version | ||
9 | * 2 as published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/kobject.h> | ||
14 | #include <linux/smp.h> | ||
15 | #include <linux/completion.h> | ||
16 | #include <linux/device.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/slab.h> | ||
19 | |||
20 | #include <asm/rtas.h> | ||
21 | #include "pseries.h" | ||
22 | |||
23 | static struct kobject *mobility_kobj; | ||
24 | |||
25 | struct update_props_workarea { | ||
26 | u32 phandle; | ||
27 | u32 state; | ||
28 | u64 reserved; | ||
29 | u32 nprops; | ||
30 | }; | ||
31 | |||
32 | #define NODE_ACTION_MASK 0xff000000 | ||
33 | #define NODE_COUNT_MASK 0x00ffffff | ||
34 | |||
35 | #define DELETE_DT_NODE 0x01000000 | ||
36 | #define UPDATE_DT_NODE 0x02000000 | ||
37 | #define ADD_DT_NODE 0x03000000 | ||
38 | |||
39 | static int mobility_rtas_call(int token, char *buf) | ||
40 | { | ||
41 | int rc; | ||
42 | |||
43 | spin_lock(&rtas_data_buf_lock); | ||
44 | |||
45 | memcpy(rtas_data_buf, buf, RTAS_DATA_BUF_SIZE); | ||
46 | rc = rtas_call(token, 2, 1, NULL, rtas_data_buf, 1); | ||
47 | memcpy(buf, rtas_data_buf, RTAS_DATA_BUF_SIZE); | ||
48 | |||
49 | spin_unlock(&rtas_data_buf_lock); | ||
50 | return rc; | ||
51 | } | ||
52 | |||
53 | static int delete_dt_node(u32 phandle) | ||
54 | { | ||
55 | struct device_node *dn; | ||
56 | |||
57 | dn = of_find_node_by_phandle(phandle); | ||
58 | if (!dn) | ||
59 | return -ENOENT; | ||
60 | |||
61 | dlpar_detach_node(dn); | ||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | static int update_dt_property(struct device_node *dn, struct property **prop, | ||
66 | const char *name, u32 vd, char *value) | ||
67 | { | ||
68 | struct property *new_prop = *prop; | ||
69 | struct property *old_prop; | ||
70 | int more = 0; | ||
71 | |||
72 | /* A negative 'vd' value indicates that only part of the new property | ||
73 | * value is contained in the buffer and we need to call | ||
74 | * ibm,update-properties again to get the rest of the value. | ||
75 | * | ||
76 | * A negative value is also the two's compliment of the actual value. | ||
77 | */ | ||
78 | if (vd & 0x80000000) { | ||
79 | vd = ~vd + 1; | ||
80 | more = 1; | ||
81 | } | ||
82 | |||
83 | if (new_prop) { | ||
84 | /* partial property fixup */ | ||
85 | char *new_data = kzalloc(new_prop->length + vd, GFP_KERNEL); | ||
86 | if (!new_data) | ||
87 | return -ENOMEM; | ||
88 | |||
89 | memcpy(new_data, new_prop->value, new_prop->length); | ||
90 | memcpy(new_data + new_prop->length, value, vd); | ||
91 | |||
92 | kfree(new_prop->value); | ||
93 | new_prop->value = new_data; | ||
94 | new_prop->length += vd; | ||
95 | } else { | ||
96 | new_prop = kzalloc(sizeof(*new_prop), GFP_KERNEL); | ||
97 | if (!new_prop) | ||
98 | return -ENOMEM; | ||
99 | |||
100 | new_prop->name = kstrdup(name, GFP_KERNEL); | ||
101 | if (!new_prop->name) { | ||
102 | kfree(new_prop); | ||
103 | return -ENOMEM; | ||
104 | } | ||
105 | |||
106 | new_prop->length = vd; | ||
107 | new_prop->value = kzalloc(new_prop->length, GFP_KERNEL); | ||
108 | if (!new_prop->value) { | ||
109 | kfree(new_prop->name); | ||
110 | kfree(new_prop); | ||
111 | return -ENOMEM; | ||
112 | } | ||
113 | |||
114 | memcpy(new_prop->value, value, vd); | ||
115 | *prop = new_prop; | ||
116 | } | ||
117 | |||
118 | if (!more) { | ||
119 | old_prop = of_find_property(dn, new_prop->name, NULL); | ||
120 | if (old_prop) | ||
121 | prom_update_property(dn, new_prop, old_prop); | ||
122 | else | ||
123 | prom_add_property(dn, new_prop); | ||
124 | |||
125 | new_prop = NULL; | ||
126 | } | ||
127 | |||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static int update_dt_node(u32 phandle) | ||
132 | { | ||
133 | struct update_props_workarea *upwa; | ||
134 | struct device_node *dn; | ||
135 | struct property *prop = NULL; | ||
136 | int i, rc; | ||
137 | char *prop_data; | ||
138 | char *rtas_buf; | ||
139 | int update_properties_token; | ||
140 | |||
141 | update_properties_token = rtas_token("ibm,update-properties"); | ||
142 | if (update_properties_token == RTAS_UNKNOWN_SERVICE) | ||
143 | return -EINVAL; | ||
144 | |||
145 | rtas_buf = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL); | ||
146 | if (!rtas_buf) | ||
147 | return -ENOMEM; | ||
148 | |||
149 | dn = of_find_node_by_phandle(phandle); | ||
150 | if (!dn) { | ||
151 | kfree(rtas_buf); | ||
152 | return -ENOENT; | ||
153 | } | ||
154 | |||
155 | upwa = (struct update_props_workarea *)&rtas_buf[0]; | ||
156 | upwa->phandle = phandle; | ||
157 | |||
158 | do { | ||
159 | rc = mobility_rtas_call(update_properties_token, rtas_buf); | ||
160 | if (rc < 0) | ||
161 | break; | ||
162 | |||
163 | prop_data = rtas_buf + sizeof(*upwa); | ||
164 | |||
165 | for (i = 0; i < upwa->nprops; i++) { | ||
166 | char *prop_name; | ||
167 | u32 vd; | ||
168 | |||
169 | prop_name = prop_data + 1; | ||
170 | prop_data += strlen(prop_name) + 1; | ||
171 | vd = *prop_data++; | ||
172 | |||
173 | switch (vd) { | ||
174 | case 0x00000000: | ||
175 | /* name only property, nothing to do */ | ||
176 | break; | ||
177 | |||
178 | case 0x80000000: | ||
179 | prop = of_find_property(dn, prop_name, NULL); | ||
180 | prom_remove_property(dn, prop); | ||
181 | prop = NULL; | ||
182 | break; | ||
183 | |||
184 | default: | ||
185 | rc = update_dt_property(dn, &prop, prop_name, | ||
186 | vd, prop_data); | ||
187 | if (rc) { | ||
188 | printk(KERN_ERR "Could not update %s" | ||
189 | " property\n", prop_name); | ||
190 | } | ||
191 | |||
192 | prop_data += vd; | ||
193 | } | ||
194 | } | ||
195 | } while (rc == 1); | ||
196 | |||
197 | of_node_put(dn); | ||
198 | kfree(rtas_buf); | ||
199 | return 0; | ||
200 | } | ||
201 | |||
202 | static int add_dt_node(u32 parent_phandle, u32 drc_index) | ||
203 | { | ||
204 | struct device_node *dn; | ||
205 | struct device_node *parent_dn; | ||
206 | int rc; | ||
207 | |||
208 | dn = dlpar_configure_connector(drc_index); | ||
209 | if (!dn) | ||
210 | return -ENOENT; | ||
211 | |||
212 | parent_dn = of_find_node_by_phandle(parent_phandle); | ||
213 | if (!parent_dn) { | ||
214 | dlpar_free_cc_nodes(dn); | ||
215 | return -ENOENT; | ||
216 | } | ||
217 | |||
218 | dn->parent = parent_dn; | ||
219 | rc = dlpar_attach_node(dn); | ||
220 | if (rc) | ||
221 | dlpar_free_cc_nodes(dn); | ||
222 | |||
223 | of_node_put(parent_dn); | ||
224 | return rc; | ||
225 | } | ||
226 | |||
227 | static int pseries_devicetree_update(void) | ||
228 | { | ||
229 | char *rtas_buf; | ||
230 | u32 *data; | ||
231 | int update_nodes_token; | ||
232 | int rc; | ||
233 | |||
234 | update_nodes_token = rtas_token("ibm,update-nodes"); | ||
235 | if (update_nodes_token == RTAS_UNKNOWN_SERVICE) | ||
236 | return -EINVAL; | ||
237 | |||
238 | rtas_buf = kzalloc(RTAS_DATA_BUF_SIZE, GFP_KERNEL); | ||
239 | if (!rtas_buf) | ||
240 | return -ENOMEM; | ||
241 | |||
242 | do { | ||
243 | rc = mobility_rtas_call(update_nodes_token, rtas_buf); | ||
244 | if (rc && rc != 1) | ||
245 | break; | ||
246 | |||
247 | data = (u32 *)rtas_buf + 4; | ||
248 | while (*data & NODE_ACTION_MASK) { | ||
249 | int i; | ||
250 | u32 action = *data & NODE_ACTION_MASK; | ||
251 | int node_count = *data & NODE_COUNT_MASK; | ||
252 | |||
253 | data++; | ||
254 | |||
255 | for (i = 0; i < node_count; i++) { | ||
256 | u32 phandle = *data++; | ||
257 | u32 drc_index; | ||
258 | |||
259 | switch (action) { | ||
260 | case DELETE_DT_NODE: | ||
261 | delete_dt_node(phandle); | ||
262 | break; | ||
263 | case UPDATE_DT_NODE: | ||
264 | update_dt_node(phandle); | ||
265 | break; | ||
266 | case ADD_DT_NODE: | ||
267 | drc_index = *data++; | ||
268 | add_dt_node(phandle, drc_index); | ||
269 | break; | ||
270 | } | ||
271 | } | ||
272 | } | ||
273 | } while (rc == 1); | ||
274 | |||
275 | kfree(rtas_buf); | ||
276 | return rc; | ||
277 | } | ||
278 | |||
279 | void post_mobility_fixup(void) | ||
280 | { | ||
281 | int rc; | ||
282 | int activate_fw_token; | ||
283 | |||
284 | rc = pseries_devicetree_update(); | ||
285 | if (rc) { | ||
286 | printk(KERN_ERR "Initial post-mobility device tree update " | ||
287 | "failed: %d\n", rc); | ||
288 | return; | ||
289 | } | ||
290 | |||
291 | activate_fw_token = rtas_token("ibm,activate-firmware"); | ||
292 | if (activate_fw_token == RTAS_UNKNOWN_SERVICE) { | ||
293 | printk(KERN_ERR "Could not make post-mobility " | ||
294 | "activate-fw call.\n"); | ||
295 | return; | ||
296 | } | ||
297 | |||
298 | rc = rtas_call(activate_fw_token, 0, 1, NULL); | ||
299 | if (!rc) { | ||
300 | rc = pseries_devicetree_update(); | ||
301 | if (rc) | ||
302 | printk(KERN_ERR "Secondary post-mobility device tree " | ||
303 | "update failed: %d\n", rc); | ||
304 | } else { | ||
305 | printk(KERN_ERR "Post-mobility activate-fw failed: %d\n", rc); | ||
306 | return; | ||
307 | } | ||
308 | |||
309 | return; | ||
310 | } | ||
311 | |||
312 | static ssize_t migrate_store(struct class *class, struct class_attribute *attr, | ||
313 | const char *buf, size_t count) | ||
314 | { | ||
315 | struct rtas_args args; | ||
316 | u64 streamid; | ||
317 | int rc; | ||
318 | |||
319 | rc = strict_strtoull(buf, 0, &streamid); | ||
320 | if (rc) | ||
321 | return rc; | ||
322 | |||
323 | memset(&args, 0, sizeof(args)); | ||
324 | args.token = rtas_token("ibm,suspend-me"); | ||
325 | args.nargs = 2; | ||
326 | args.nret = 1; | ||
327 | |||
328 | args.args[0] = streamid >> 32 ; | ||
329 | args.args[1] = streamid & 0xffffffff; | ||
330 | args.rets = &args.args[args.nargs]; | ||
331 | |||
332 | do { | ||
333 | args.rets[0] = 0; | ||
334 | rc = rtas_ibm_suspend_me(&args); | ||
335 | if (!rc && args.rets[0] == RTAS_NOT_SUSPENDABLE) | ||
336 | ssleep(1); | ||
337 | } while (!rc && args.rets[0] == RTAS_NOT_SUSPENDABLE); | ||
338 | |||
339 | if (rc) | ||
340 | return rc; | ||
341 | else if (args.rets[0]) | ||
342 | return args.rets[0]; | ||
343 | |||
344 | post_mobility_fixup(); | ||
345 | return count; | ||
346 | } | ||
347 | |||
348 | static CLASS_ATTR(migration, S_IWUSR, NULL, migrate_store); | ||
349 | |||
350 | static int __init mobility_sysfs_init(void) | ||
351 | { | ||
352 | int rc; | ||
353 | |||
354 | mobility_kobj = kobject_create_and_add("mobility", kernel_kobj); | ||
355 | if (!mobility_kobj) | ||
356 | return -ENOMEM; | ||
357 | |||
358 | rc = sysfs_create_file(mobility_kobj, &class_attr_migration.attr); | ||
359 | |||
360 | return rc; | ||
361 | } | ||
362 | device_initcall(mobility_sysfs_init); | ||
diff --git a/arch/powerpc/platforms/pseries/pseries.h b/arch/powerpc/platforms/pseries/pseries.h index 40c93cad91d2..e9f6d2859c3c 100644 --- a/arch/powerpc/platforms/pseries/pseries.h +++ b/arch/powerpc/platforms/pseries/pseries.h | |||
@@ -17,6 +17,8 @@ struct device_node; | |||
17 | extern void request_event_sources_irqs(struct device_node *np, | 17 | extern void request_event_sources_irqs(struct device_node *np, |
18 | irq_handler_t handler, const char *name); | 18 | irq_handler_t handler, const char *name); |
19 | 19 | ||
20 | #include <linux/of.h> | ||
21 | |||
20 | extern void __init fw_feature_init(const char *hypertas, unsigned long len); | 22 | extern void __init fw_feature_init(const char *hypertas, unsigned long len); |
21 | 23 | ||
22 | struct pt_regs; | 24 | struct pt_regs; |
@@ -47,4 +49,11 @@ extern unsigned long rtas_poweron_auto; | |||
47 | 49 | ||
48 | extern void find_udbg_vterm(void); | 50 | extern void find_udbg_vterm(void); |
49 | 51 | ||
52 | /* Dynamic logical Partitioning/Mobility */ | ||
53 | extern void dlpar_free_cc_nodes(struct device_node *); | ||
54 | extern void dlpar_free_cc_property(struct property *); | ||
55 | extern struct device_node *dlpar_configure_connector(u32); | ||
56 | extern int dlpar_attach_node(struct device_node *); | ||
57 | extern int dlpar_detach_node(struct device_node *); | ||
58 | |||
50 | #endif /* _PSERIES_PSERIES_H */ | 59 | #endif /* _PSERIES_PSERIES_H */ |
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index a6d19e3a505e..d345bfd56bbe 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c | |||
@@ -273,6 +273,58 @@ static struct notifier_block pci_dn_reconfig_nb = { | |||
273 | .notifier_call = pci_dn_reconfig_notifier, | 273 | .notifier_call = pci_dn_reconfig_notifier, |
274 | }; | 274 | }; |
275 | 275 | ||
276 | #ifdef CONFIG_VIRT_CPU_ACCOUNTING | ||
277 | /* | ||
278 | * Allocate space for the dispatch trace log for all possible cpus | ||
279 | * and register the buffers with the hypervisor. This is used for | ||
280 | * computing time stolen by the hypervisor. | ||
281 | */ | ||
282 | static int alloc_dispatch_logs(void) | ||
283 | { | ||
284 | int cpu, ret; | ||
285 | struct paca_struct *pp; | ||
286 | struct dtl_entry *dtl; | ||
287 | |||
288 | if (!firmware_has_feature(FW_FEATURE_SPLPAR)) | ||
289 | return 0; | ||
290 | |||
291 | for_each_possible_cpu(cpu) { | ||
292 | pp = &paca[cpu]; | ||
293 | dtl = kmalloc_node(DISPATCH_LOG_BYTES, GFP_KERNEL, | ||
294 | cpu_to_node(cpu)); | ||
295 | if (!dtl) { | ||
296 | pr_warn("Failed to allocate dispatch trace log for cpu %d\n", | ||
297 | cpu); | ||
298 | pr_warn("Stolen time statistics will be unreliable\n"); | ||
299 | break; | ||
300 | } | ||
301 | |||
302 | pp->dtl_ridx = 0; | ||
303 | pp->dispatch_log = dtl; | ||
304 | pp->dispatch_log_end = dtl + N_DISPATCH_LOG; | ||
305 | pp->dtl_curr = dtl; | ||
306 | } | ||
307 | |||
308 | /* Register the DTL for the current (boot) cpu */ | ||
309 | dtl = get_paca()->dispatch_log; | ||
310 | get_paca()->dtl_ridx = 0; | ||
311 | get_paca()->dtl_curr = dtl; | ||
312 | get_paca()->lppaca_ptr->dtl_idx = 0; | ||
313 | |||
314 | /* hypervisor reads buffer length from this field */ | ||
315 | dtl->enqueue_to_dispatch_time = DISPATCH_LOG_BYTES; | ||
316 | ret = register_dtl(hard_smp_processor_id(), __pa(dtl)); | ||
317 | if (ret) | ||
318 | pr_warn("DTL registration failed for boot cpu %d (%d)\n", | ||
319 | smp_processor_id(), ret); | ||
320 | get_paca()->lppaca_ptr->dtl_enable_mask = 2; | ||
321 | |||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | early_initcall(alloc_dispatch_logs); | ||
326 | #endif /* CONFIG_VIRT_CPU_ACCOUNTING */ | ||
327 | |||
276 | static void __init pSeries_setup_arch(void) | 328 | static void __init pSeries_setup_arch(void) |
277 | { | 329 | { |
278 | /* Discover PIC type and setup ppc_md accordingly */ | 330 | /* Discover PIC type and setup ppc_md accordingly */ |
diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c index 67e2c4bdac8f..7b96e5a270ce 100644 --- a/arch/powerpc/platforms/pseries/xics.c +++ b/arch/powerpc/platforms/pseries/xics.c | |||
@@ -178,7 +178,7 @@ static int get_irq_server(unsigned int virq, const struct cpumask *cpumask, | |||
178 | if (!distribute_irqs) | 178 | if (!distribute_irqs) |
179 | return default_server; | 179 | return default_server; |
180 | 180 | ||
181 | if (!cpumask_equal(cpumask, cpu_all_mask)) { | 181 | if (!cpumask_subset(cpu_possible_mask, cpumask)) { |
182 | int server = cpumask_first_and(cpu_online_mask, cpumask); | 182 | int server = cpumask_first_and(cpu_online_mask, cpumask); |
183 | 183 | ||
184 | if (server < nr_cpu_ids) | 184 | if (server < nr_cpu_ids) |