diff options
Diffstat (limited to 'arch')
33 files changed, 2163 insertions, 750 deletions
diff --git a/arch/ppc64/Kconfig b/arch/ppc64/Kconfig index 6448231cb10..cb27068bfcd 100644 --- a/arch/ppc64/Kconfig +++ b/arch/ppc64/Kconfig | |||
@@ -77,6 +77,10 @@ config PPC_PSERIES | |||
77 | bool " IBM pSeries & new iSeries" | 77 | bool " IBM pSeries & new iSeries" |
78 | default y | 78 | default y |
79 | 79 | ||
80 | config PPC_BPA | ||
81 | bool " Broadband Processor Architecture" | ||
82 | depends on PPC_MULTIPLATFORM | ||
83 | |||
80 | config PPC_PMAC | 84 | config PPC_PMAC |
81 | depends on PPC_MULTIPLATFORM | 85 | depends on PPC_MULTIPLATFORM |
82 | bool " Apple G5 based machines" | 86 | bool " Apple G5 based machines" |
@@ -106,6 +110,21 @@ config PPC_OF | |||
106 | bool | 110 | bool |
107 | default y | 111 | default y |
108 | 112 | ||
113 | config XICS | ||
114 | depends on PPC_PSERIES | ||
115 | bool | ||
116 | default y | ||
117 | |||
118 | config MPIC | ||
119 | depends on PPC_PSERIES || PPC_PMAC || PPC_MAPLE | ||
120 | bool | ||
121 | default y | ||
122 | |||
123 | config BPA_IIC | ||
124 | depends on PPC_BPA | ||
125 | bool | ||
126 | default y | ||
127 | |||
109 | # VMX is pSeries only for now until somebody writes the iSeries | 128 | # VMX is pSeries only for now until somebody writes the iSeries |
110 | # exception vectors for it | 129 | # exception vectors for it |
111 | config ALTIVEC | 130 | config ALTIVEC |
@@ -292,7 +311,7 @@ config MSCHUNKS | |||
292 | 311 | ||
293 | config PPC_RTAS | 312 | config PPC_RTAS |
294 | bool | 313 | bool |
295 | depends on PPC_PSERIES | 314 | depends on PPC_PSERIES || PPC_BPA |
296 | default y | 315 | default y |
297 | 316 | ||
298 | config RTAS_PROC | 317 | config RTAS_PROC |
diff --git a/arch/ppc64/Makefile b/arch/ppc64/Makefile index 33c752ceca4..731b8475833 100644 --- a/arch/ppc64/Makefile +++ b/arch/ppc64/Makefile | |||
@@ -90,12 +90,14 @@ boot := arch/ppc64/boot | |||
90 | boottarget-$(CONFIG_PPC_PSERIES) := zImage zImage.initrd | 90 | boottarget-$(CONFIG_PPC_PSERIES) := zImage zImage.initrd |
91 | boottarget-$(CONFIG_PPC_MAPLE) := zImage zImage.initrd | 91 | boottarget-$(CONFIG_PPC_MAPLE) := zImage zImage.initrd |
92 | boottarget-$(CONFIG_PPC_ISERIES) := vmlinux.sminitrd vmlinux.initrd vmlinux.sm | 92 | boottarget-$(CONFIG_PPC_ISERIES) := vmlinux.sminitrd vmlinux.initrd vmlinux.sm |
93 | boottarget-$(CONFIG_PPC_BPA) := zImage zImage.initrd | ||
93 | $(boottarget-y): vmlinux | 94 | $(boottarget-y): vmlinux |
94 | $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ | 95 | $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ |
95 | 96 | ||
96 | bootimage-$(CONFIG_PPC_PSERIES) := $(boot)/zImage | 97 | bootimage-$(CONFIG_PPC_PSERIES) := $(boot)/zImage |
97 | bootimage-$(CONFIG_PPC_PMAC) := vmlinux | 98 | bootimage-$(CONFIG_PPC_PMAC) := vmlinux |
98 | bootimage-$(CONFIG_PPC_MAPLE) := $(boot)/zImage | 99 | bootimage-$(CONFIG_PPC_MAPLE) := $(boot)/zImage |
100 | bootimage-$(CONFIG_PPC_BPA) := zImage | ||
99 | bootimage-$(CONFIG_PPC_ISERIES) := vmlinux | 101 | bootimage-$(CONFIG_PPC_ISERIES) := vmlinux |
100 | BOOTIMAGE := $(bootimage-y) | 102 | BOOTIMAGE := $(bootimage-y) |
101 | install: vmlinux | 103 | install: vmlinux |
diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile index b5e167cf1a0..dffbfb7ac8d 100644 --- a/arch/ppc64/kernel/Makefile +++ b/arch/ppc64/kernel/Makefile | |||
@@ -27,17 +27,21 @@ obj-$(CONFIG_PPC_ISERIES) += HvCall.o HvLpConfig.o LparData.o \ | |||
27 | mf.o HvLpEvent.o iSeries_proc.o iSeries_htab.o \ | 27 | mf.o HvLpEvent.o iSeries_proc.o iSeries_htab.o \ |
28 | iSeries_iommu.o | 28 | iSeries_iommu.o |
29 | 29 | ||
30 | obj-$(CONFIG_PPC_MULTIPLATFORM) += nvram.o i8259.o prom_init.o prom.o mpic.o | 30 | obj-$(CONFIG_PPC_MULTIPLATFORM) += nvram.o i8259.o prom_init.o prom.o |
31 | 31 | ||
32 | obj-$(CONFIG_PPC_PSERIES) += pSeries_pci.o pSeries_lpar.o pSeries_hvCall.o \ | 32 | obj-$(CONFIG_PPC_PSERIES) += pSeries_pci.o pSeries_lpar.o pSeries_hvCall.o \ |
33 | pSeries_nvram.o rtasd.o ras.o pSeries_reconfig.o \ | 33 | pSeries_nvram.o rtasd.o ras.o pSeries_reconfig.o \ |
34 | xics.o rtas.o pSeries_setup.o pSeries_iommu.o | 34 | pSeries_setup.o pSeries_iommu.o |
35 | |||
36 | obj-$(CONFIG_PPC_BPA) += bpa_setup.o bpa_iommu.o bpa_nvram.o \ | ||
37 | bpa_iic.o spider-pic.o | ||
35 | 38 | ||
36 | obj-$(CONFIG_EEH) += eeh.o | 39 | obj-$(CONFIG_EEH) += eeh.o |
37 | obj-$(CONFIG_PROC_FS) += proc_ppc64.o | 40 | obj-$(CONFIG_PROC_FS) += proc_ppc64.o |
38 | obj-$(CONFIG_RTAS_FLASH) += rtas_flash.o | 41 | obj-$(CONFIG_RTAS_FLASH) += rtas_flash.o |
39 | obj-$(CONFIG_SMP) += smp.o | 42 | obj-$(CONFIG_SMP) += smp.o |
40 | obj-$(CONFIG_MODULES) += module.o ppc_ksyms.o | 43 | obj-$(CONFIG_MODULES) += module.o ppc_ksyms.o |
44 | obj-$(CONFIG_PPC_RTAS) += rtas.o rtas_pci.o | ||
41 | obj-$(CONFIG_RTAS_PROC) += rtas-proc.o | 45 | obj-$(CONFIG_RTAS_PROC) += rtas-proc.o |
42 | obj-$(CONFIG_SCANLOG) += scanlog.o | 46 | obj-$(CONFIG_SCANLOG) += scanlog.o |
43 | obj-$(CONFIG_VIOPATH) += viopath.o | 47 | obj-$(CONFIG_VIOPATH) += viopath.o |
@@ -46,6 +50,8 @@ obj-$(CONFIG_HVC_CONSOLE) += hvconsole.o | |||
46 | obj-$(CONFIG_BOOTX_TEXT) += btext.o | 50 | obj-$(CONFIG_BOOTX_TEXT) += btext.o |
47 | obj-$(CONFIG_HVCS) += hvcserver.o | 51 | obj-$(CONFIG_HVCS) += hvcserver.o |
48 | obj-$(CONFIG_IBMVIO) += vio.o | 52 | obj-$(CONFIG_IBMVIO) += vio.o |
53 | obj-$(CONFIG_XICS) += xics.o | ||
54 | obj-$(CONFIG_MPIC) += mpic.o | ||
49 | 55 | ||
50 | obj-$(CONFIG_PPC_PMAC) += pmac_setup.o pmac_feature.o pmac_pci.o \ | 56 | obj-$(CONFIG_PPC_PMAC) += pmac_setup.o pmac_feature.o pmac_pci.o \ |
51 | pmac_time.o pmac_nvram.o pmac_low_i2c.o | 57 | pmac_time.o pmac_nvram.o pmac_low_i2c.o |
@@ -58,6 +64,7 @@ ifdef CONFIG_SMP | |||
58 | obj-$(CONFIG_PPC_PMAC) += pmac_smp.o smp-tbsync.o | 64 | obj-$(CONFIG_PPC_PMAC) += pmac_smp.o smp-tbsync.o |
59 | obj-$(CONFIG_PPC_ISERIES) += iSeries_smp.o | 65 | obj-$(CONFIG_PPC_ISERIES) += iSeries_smp.o |
60 | obj-$(CONFIG_PPC_PSERIES) += pSeries_smp.o | 66 | obj-$(CONFIG_PPC_PSERIES) += pSeries_smp.o |
67 | obj-$(CONFIG_PPC_BPA) += pSeries_smp.o | ||
61 | obj-$(CONFIG_PPC_MAPLE) += smp-tbsync.o | 68 | obj-$(CONFIG_PPC_MAPLE) += smp-tbsync.o |
62 | endif | 69 | endif |
63 | 70 | ||
diff --git a/arch/ppc64/kernel/bpa_iic.c b/arch/ppc64/kernel/bpa_iic.c new file mode 100644 index 00000000000..c8f3dc3fad7 --- /dev/null +++ b/arch/ppc64/kernel/bpa_iic.c | |||
@@ -0,0 +1,270 @@ | |||
1 | /* | ||
2 | * BPA Internal Interrupt Controller | ||
3 | * | ||
4 | * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 | ||
5 | * | ||
6 | * Author: Arnd Bergmann <arndb@de.ibm.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2, or (at your option) | ||
11 | * any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | */ | ||
22 | |||
23 | #include <linux/config.h> | ||
24 | #include <linux/interrupt.h> | ||
25 | #include <linux/irq.h> | ||
26 | #include <linux/percpu.h> | ||
27 | #include <linux/types.h> | ||
28 | |||
29 | #include <asm/io.h> | ||
30 | #include <asm/pgtable.h> | ||
31 | #include <asm/prom.h> | ||
32 | #include <asm/ptrace.h> | ||
33 | |||
34 | #include "bpa_iic.h" | ||
35 | |||
36 | struct iic_pending_bits { | ||
37 | u32 data; | ||
38 | u8 flags; | ||
39 | u8 class; | ||
40 | u8 source; | ||
41 | u8 prio; | ||
42 | }; | ||
43 | |||
44 | enum iic_pending_flags { | ||
45 | IIC_VALID = 0x80, | ||
46 | IIC_IPI = 0x40, | ||
47 | }; | ||
48 | |||
49 | struct iic_regs { | ||
50 | struct iic_pending_bits pending; | ||
51 | struct iic_pending_bits pending_destr; | ||
52 | u64 generate; | ||
53 | u64 prio; | ||
54 | }; | ||
55 | |||
56 | struct iic { | ||
57 | struct iic_regs __iomem *regs; | ||
58 | }; | ||
59 | |||
60 | static DEFINE_PER_CPU(struct iic, iic); | ||
61 | |||
62 | void iic_local_enable(void) | ||
63 | { | ||
64 | out_be64(&__get_cpu_var(iic).regs->prio, 0xff); | ||
65 | } | ||
66 | |||
67 | void iic_local_disable(void) | ||
68 | { | ||
69 | out_be64(&__get_cpu_var(iic).regs->prio, 0x0); | ||
70 | } | ||
71 | |||
72 | static unsigned int iic_startup(unsigned int irq) | ||
73 | { | ||
74 | return 0; | ||
75 | } | ||
76 | |||
77 | static void iic_enable(unsigned int irq) | ||
78 | { | ||
79 | iic_local_enable(); | ||
80 | } | ||
81 | |||
82 | static void iic_disable(unsigned int irq) | ||
83 | { | ||
84 | } | ||
85 | |||
86 | static void iic_end(unsigned int irq) | ||
87 | { | ||
88 | iic_local_enable(); | ||
89 | } | ||
90 | |||
91 | static struct hw_interrupt_type iic_pic = { | ||
92 | .typename = " BPA-IIC ", | ||
93 | .startup = iic_startup, | ||
94 | .enable = iic_enable, | ||
95 | .disable = iic_disable, | ||
96 | .end = iic_end, | ||
97 | }; | ||
98 | |||
99 | static int iic_external_get_irq(struct iic_pending_bits pending) | ||
100 | { | ||
101 | int irq; | ||
102 | unsigned char node, unit; | ||
103 | |||
104 | node = pending.source >> 4; | ||
105 | unit = pending.source & 0xf; | ||
106 | irq = -1; | ||
107 | |||
108 | /* | ||
109 | * This mapping is specific to the Broadband | ||
110 | * Engine. We might need to get the numbers | ||
111 | * from the device tree to support future CPUs. | ||
112 | */ | ||
113 | switch (unit) { | ||
114 | case 0x00: | ||
115 | case 0x0b: | ||
116 | /* | ||
117 | * One of these units can be connected | ||
118 | * to an external interrupt controller. | ||
119 | */ | ||
120 | if (pending.prio > 0x3f || | ||
121 | pending.class != 2) | ||
122 | break; | ||
123 | irq = IIC_EXT_OFFSET | ||
124 | + spider_get_irq(pending.prio + node * IIC_NODE_STRIDE) | ||
125 | + node * IIC_NODE_STRIDE; | ||
126 | break; | ||
127 | case 0x01 ... 0x04: | ||
128 | case 0x07 ... 0x0a: | ||
129 | /* | ||
130 | * These units are connected to the SPEs | ||
131 | */ | ||
132 | if (pending.class > 2) | ||
133 | break; | ||
134 | irq = IIC_SPE_OFFSET | ||
135 | + pending.class * IIC_CLASS_STRIDE | ||
136 | + node * IIC_NODE_STRIDE | ||
137 | + unit; | ||
138 | break; | ||
139 | } | ||
140 | if (irq == -1) | ||
141 | printk(KERN_WARNING "Unexpected interrupt class %02x, " | ||
142 | "source %02x, prio %02x, cpu %02x\n", pending.class, | ||
143 | pending.source, pending.prio, smp_processor_id()); | ||
144 | return irq; | ||
145 | } | ||
146 | |||
147 | /* Get an IRQ number from the pending state register of the IIC */ | ||
148 | int iic_get_irq(struct pt_regs *regs) | ||
149 | { | ||
150 | struct iic *iic; | ||
151 | int irq; | ||
152 | struct iic_pending_bits pending; | ||
153 | |||
154 | iic = &__get_cpu_var(iic); | ||
155 | *(unsigned long *) &pending = | ||
156 | in_be64((unsigned long __iomem *) &iic->regs->pending_destr); | ||
157 | |||
158 | irq = -1; | ||
159 | if (pending.flags & IIC_VALID) { | ||
160 | if (pending.flags & IIC_IPI) { | ||
161 | irq = IIC_IPI_OFFSET + (pending.prio >> 4); | ||
162 | /* | ||
163 | if (irq > 0x80) | ||
164 | printk(KERN_WARNING "Unexpected IPI prio %02x" | ||
165 | "on CPU %02x\n", pending.prio, | ||
166 | smp_processor_id()); | ||
167 | */ | ||
168 | } else { | ||
169 | irq = iic_external_get_irq(pending); | ||
170 | } | ||
171 | } | ||
172 | return irq; | ||
173 | } | ||
174 | |||
175 | static struct iic_regs __iomem *find_iic(int cpu) | ||
176 | { | ||
177 | struct device_node *np; | ||
178 | int nodeid = cpu / 2; | ||
179 | unsigned long regs; | ||
180 | struct iic_regs __iomem *iic_regs; | ||
181 | |||
182 | for (np = of_find_node_by_type(NULL, "cpu"); | ||
183 | np; | ||
184 | np = of_find_node_by_type(np, "cpu")) { | ||
185 | if (nodeid == *(int *)get_property(np, "node-id", NULL)) | ||
186 | break; | ||
187 | } | ||
188 | |||
189 | if (!np) { | ||
190 | printk(KERN_WARNING "IIC: CPU %d not found\n", cpu); | ||
191 | iic_regs = NULL; | ||
192 | } else { | ||
193 | regs = *(long *)get_property(np, "iic", NULL); | ||
194 | |||
195 | /* hack until we have decided on the devtree info */ | ||
196 | regs += 0x400; | ||
197 | if (cpu & 1) | ||
198 | regs += 0x20; | ||
199 | |||
200 | printk(KERN_DEBUG "IIC for CPU %d at %lx\n", cpu, regs); | ||
201 | iic_regs = __ioremap(regs, sizeof(struct iic_regs), | ||
202 | _PAGE_NO_CACHE); | ||
203 | } | ||
204 | return iic_regs; | ||
205 | } | ||
206 | |||
207 | #ifdef CONFIG_SMP | ||
208 | void iic_setup_cpu(void) | ||
209 | { | ||
210 | out_be64(&__get_cpu_var(iic).regs->prio, 0xff); | ||
211 | } | ||
212 | |||
213 | void iic_cause_IPI(int cpu, int mesg) | ||
214 | { | ||
215 | out_be64(&per_cpu(iic, cpu).regs->generate, mesg); | ||
216 | } | ||
217 | |||
218 | static irqreturn_t iic_ipi_action(int irq, void *dev_id, struct pt_regs *regs) | ||
219 | { | ||
220 | |||
221 | smp_message_recv(irq - IIC_IPI_OFFSET, regs); | ||
222 | return IRQ_HANDLED; | ||
223 | } | ||
224 | |||
225 | static void iic_request_ipi(int irq, const char *name) | ||
226 | { | ||
227 | /* IPIs are marked SA_INTERRUPT as they must run with irqs | ||
228 | * disabled */ | ||
229 | get_irq_desc(irq)->handler = &iic_pic; | ||
230 | get_irq_desc(irq)->status |= IRQ_PER_CPU; | ||
231 | request_irq(irq, iic_ipi_action, SA_INTERRUPT, name, NULL); | ||
232 | } | ||
233 | |||
234 | void iic_request_IPIs(void) | ||
235 | { | ||
236 | iic_request_ipi(IIC_IPI_OFFSET + PPC_MSG_CALL_FUNCTION, "IPI-call"); | ||
237 | iic_request_ipi(IIC_IPI_OFFSET + PPC_MSG_RESCHEDULE, "IPI-resched"); | ||
238 | #ifdef CONFIG_DEBUGGER | ||
239 | iic_request_ipi(IIC_IPI_OFFSET + PPC_MSG_DEBUGGER_BREAK, "IPI-debug"); | ||
240 | #endif /* CONFIG_DEBUGGER */ | ||
241 | } | ||
242 | #endif /* CONFIG_SMP */ | ||
243 | |||
244 | static void iic_setup_spe_handlers(void) | ||
245 | { | ||
246 | int be, isrc; | ||
247 | |||
248 | /* Assume two threads per BE are present */ | ||
249 | for (be=0; be < num_present_cpus() / 2; be++) { | ||
250 | for (isrc = 0; isrc < IIC_CLASS_STRIDE * 3; isrc++) { | ||
251 | int irq = IIC_NODE_STRIDE * be + IIC_SPE_OFFSET + isrc; | ||
252 | get_irq_desc(irq)->handler = &iic_pic; | ||
253 | } | ||
254 | } | ||
255 | } | ||
256 | |||
257 | void iic_init_IRQ(void) | ||
258 | { | ||
259 | int cpu, irq_offset; | ||
260 | struct iic *iic; | ||
261 | |||
262 | irq_offset = 0; | ||
263 | for_each_cpu(cpu) { | ||
264 | iic = &per_cpu(iic, cpu); | ||
265 | iic->regs = find_iic(cpu); | ||
266 | if (iic->regs) | ||
267 | out_be64(&iic->regs->prio, 0xff); | ||
268 | } | ||
269 | iic_setup_spe_handlers(); | ||
270 | } | ||
diff --git a/arch/ppc64/kernel/bpa_iic.h b/arch/ppc64/kernel/bpa_iic.h new file mode 100644 index 00000000000..6833c302216 --- /dev/null +++ b/arch/ppc64/kernel/bpa_iic.h | |||
@@ -0,0 +1,62 @@ | |||
1 | #ifndef ASM_BPA_IIC_H | ||
2 | #define ASM_BPA_IIC_H | ||
3 | #ifdef __KERNEL__ | ||
4 | /* | ||
5 | * Mapping of IIC pending bits into per-node | ||
6 | * interrupt numbers. | ||
7 | * | ||
8 | * IRQ FF CC SS PP FF CC SS PP Description | ||
9 | * | ||
10 | * 00-3f 80 02 +0 00 - 80 02 +0 3f South Bridge | ||
11 | * 00-3f 80 02 +b 00 - 80 02 +b 3f South Bridge | ||
12 | * 41-4a 80 00 +1 ** - 80 00 +a ** SPU Class 0 | ||
13 | * 51-5a 80 01 +1 ** - 80 01 +a ** SPU Class 1 | ||
14 | * 61-6a 80 02 +1 ** - 80 02 +a ** SPU Class 2 | ||
15 | * 70-7f C0 ** ** 00 - C0 ** ** 0f IPI | ||
16 | * | ||
17 | * F flags | ||
18 | * C class | ||
19 | * S source | ||
20 | * P Priority | ||
21 | * + node number | ||
22 | * * don't care | ||
23 | * | ||
24 | * A node consists of a Broadband Engine and an optional | ||
25 | * south bridge device providing a maximum of 64 IRQs. | ||
26 | * The south bridge may be connected to either IOIF0 | ||
27 | * or IOIF1. | ||
28 | * Each SPE is represented as three IRQ lines, one per | ||
29 | * interrupt class. | ||
30 | * 16 IRQ numbers are reserved for inter processor | ||
31 | * interruptions, although these are only used in the | ||
32 | * range of the first node. | ||
33 | * | ||
34 | * This scheme needs 128 IRQ numbers per BIF node ID, | ||
35 | * which means that with the total of 512 lines | ||
36 | * available, we can have a maximum of four nodes. | ||
37 | */ | ||
38 | |||
39 | enum { | ||
40 | IIC_EXT_OFFSET = 0x00, /* Start of south bridge IRQs */ | ||
41 | IIC_NUM_EXT = 0x40, /* Number of south bridge IRQs */ | ||
42 | IIC_SPE_OFFSET = 0x40, /* Start of SPE interrupts */ | ||
43 | IIC_CLASS_STRIDE = 0x10, /* SPE IRQs per class */ | ||
44 | IIC_IPI_OFFSET = 0x70, /* Start of IPI IRQs */ | ||
45 | IIC_NUM_IPIS = 0x10, /* IRQs reserved for IPI */ | ||
46 | IIC_NODE_STRIDE = 0x80, /* Total IRQs per node */ | ||
47 | }; | ||
48 | |||
49 | extern void iic_init_IRQ(void); | ||
50 | extern int iic_get_irq(struct pt_regs *regs); | ||
51 | extern void iic_cause_IPI(int cpu, int mesg); | ||
52 | extern void iic_request_IPIs(void); | ||
53 | extern void iic_setup_cpu(void); | ||
54 | extern void iic_local_enable(void); | ||
55 | extern void iic_local_disable(void); | ||
56 | |||
57 | |||
58 | extern void spider_init_IRQ(void); | ||
59 | extern int spider_get_irq(unsigned long int_pending); | ||
60 | |||
61 | #endif | ||
62 | #endif /* ASM_BPA_IIC_H */ | ||
diff --git a/arch/ppc64/kernel/bpa_iommu.c b/arch/ppc64/kernel/bpa_iommu.c new file mode 100644 index 00000000000..f33a7bccb0d --- /dev/null +++ b/arch/ppc64/kernel/bpa_iommu.c | |||
@@ -0,0 +1,377 @@ | |||
1 | /* | ||
2 | * IOMMU implementation for Broadband Processor Architecture | ||
3 | * We just establish a linear mapping at boot by setting all the | ||
4 | * IOPT cache entries in the CPU. | ||
5 | * The mapping functions should be identical to pci_direct_iommu, | ||
6 | * except for the handling of the high order bit that is required | ||
7 | * by the Spider bridge. These should be split into a separate | ||
8 | * file at the point where we get a different bridge chip. | ||
9 | * | ||
10 | * Copyright (C) 2005 IBM Deutschland Entwicklung GmbH, | ||
11 | * Arnd Bergmann <arndb@de.ibm.com> | ||
12 | * | ||
13 | * Based on linear mapping | ||
14 | * Copyright (C) 2003 Benjamin Herrenschmidt (benh@kernel.crashing.org) | ||
15 | * | ||
16 | * This program is free software; you can redistribute it and/or | ||
17 | * modify it under the terms of the GNU General Public License | ||
18 | * as published by the Free Software Foundation; either version | ||
19 | * 2 of the License, or (at your option) any later version. | ||
20 | */ | ||
21 | |||
22 | #undef DEBUG | ||
23 | |||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/pci.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/string.h> | ||
28 | #include <linux/init.h> | ||
29 | #include <linux/bootmem.h> | ||
30 | #include <linux/mm.h> | ||
31 | #include <linux/dma-mapping.h> | ||
32 | |||
33 | #include <asm/sections.h> | ||
34 | #include <asm/iommu.h> | ||
35 | #include <asm/io.h> | ||
36 | #include <asm/prom.h> | ||
37 | #include <asm/pci-bridge.h> | ||
38 | #include <asm/machdep.h> | ||
39 | #include <asm/pmac_feature.h> | ||
40 | #include <asm/abs_addr.h> | ||
41 | #include <asm/system.h> | ||
42 | |||
43 | #include "pci.h" | ||
44 | #include "bpa_iommu.h" | ||
45 | |||
46 | static inline unsigned long | ||
47 | get_iopt_entry(unsigned long real_address, unsigned long ioid, | ||
48 | unsigned long prot) | ||
49 | { | ||
50 | return (prot & IOPT_PROT_MASK) | ||
51 | | (IOPT_COHERENT) | ||
52 | | (IOPT_ORDER_VC) | ||
53 | | (real_address & IOPT_RPN_MASK) | ||
54 | | (ioid & IOPT_IOID_MASK); | ||
55 | } | ||
56 | |||
57 | typedef struct { | ||
58 | unsigned long val; | ||
59 | } ioste; | ||
60 | |||
61 | static inline ioste | ||
62 | mk_ioste(unsigned long val) | ||
63 | { | ||
64 | ioste ioste = { .val = val, }; | ||
65 | return ioste; | ||
66 | } | ||
67 | |||
68 | static inline ioste | ||
69 | get_iost_entry(unsigned long iopt_base, unsigned long io_address, unsigned page_size) | ||
70 | { | ||
71 | unsigned long ps; | ||
72 | unsigned long iostep; | ||
73 | unsigned long nnpt; | ||
74 | unsigned long shift; | ||
75 | |||
76 | switch (page_size) { | ||
77 | case 0x1000000: | ||
78 | ps = IOST_PS_16M; | ||
79 | nnpt = 0; /* one page per segment */ | ||
80 | shift = 5; /* segment has 16 iopt entries */ | ||
81 | break; | ||
82 | |||
83 | case 0x100000: | ||
84 | ps = IOST_PS_1M; | ||
85 | nnpt = 0; /* one page per segment */ | ||
86 | shift = 1; /* segment has 256 iopt entries */ | ||
87 | break; | ||
88 | |||
89 | case 0x10000: | ||
90 | ps = IOST_PS_64K; | ||
91 | nnpt = 0x07; /* 8 pages per io page table */ | ||
92 | shift = 0; /* all entries are used */ | ||
93 | break; | ||
94 | |||
95 | case 0x1000: | ||
96 | ps = IOST_PS_4K; | ||
97 | nnpt = 0x7f; /* 128 pages per io page table */ | ||
98 | shift = 0; /* all entries are used */ | ||
99 | break; | ||
100 | |||
101 | default: /* not a known compile time constant */ | ||
102 | BUILD_BUG_ON(1); | ||
103 | break; | ||
104 | } | ||
105 | |||
106 | iostep = iopt_base + | ||
107 | /* need 8 bytes per iopte */ | ||
108 | (((io_address / page_size * 8) | ||
109 | /* align io page tables on 4k page boundaries */ | ||
110 | << shift) | ||
111 | /* nnpt+1 pages go into each iopt */ | ||
112 | & ~(nnpt << 12)); | ||
113 | |||
114 | nnpt++; /* this seems to work, but the documentation is not clear | ||
115 | about wether we put nnpt or nnpt-1 into the ioste bits. | ||
116 | In theory, this can't work for 4k pages. */ | ||
117 | return mk_ioste(IOST_VALID_MASK | ||
118 | | (iostep & IOST_PT_BASE_MASK) | ||
119 | | ((nnpt << 5) & IOST_NNPT_MASK) | ||
120 | | (ps & IOST_PS_MASK)); | ||
121 | } | ||
122 | |||
123 | /* compute the address of an io pte */ | ||
124 | static inline unsigned long | ||
125 | get_ioptep(ioste iost_entry, unsigned long io_address) | ||
126 | { | ||
127 | unsigned long iopt_base; | ||
128 | unsigned long page_size; | ||
129 | unsigned long page_number; | ||
130 | unsigned long iopt_offset; | ||
131 | |||
132 | iopt_base = iost_entry.val & IOST_PT_BASE_MASK; | ||
133 | page_size = iost_entry.val & IOST_PS_MASK; | ||
134 | |||
135 | /* decode page size to compute page number */ | ||
136 | page_number = (io_address & 0x0fffffff) >> (10 + 2 * page_size); | ||
137 | /* page number is an offset into the io page table */ | ||
138 | iopt_offset = (page_number << 3) & 0x7fff8ul; | ||
139 | return iopt_base + iopt_offset; | ||
140 | } | ||
141 | |||
142 | /* compute the tag field of the iopt cache entry */ | ||
143 | static inline unsigned long | ||
144 | get_ioc_tag(ioste iost_entry, unsigned long io_address) | ||
145 | { | ||
146 | unsigned long iopte = get_ioptep(iost_entry, io_address); | ||
147 | |||
148 | return IOPT_VALID_MASK | ||
149 | | ((iopte & 0x00000000000000ff8ul) >> 3) | ||
150 | | ((iopte & 0x0000003fffffc0000ul) >> 9); | ||
151 | } | ||
152 | |||
153 | /* compute the hashed 6 bit index for the 4-way associative pte cache */ | ||
154 | static inline unsigned long | ||
155 | get_ioc_hash(ioste iost_entry, unsigned long io_address) | ||
156 | { | ||
157 | unsigned long iopte = get_ioptep(iost_entry, io_address); | ||
158 | |||
159 | return ((iopte & 0x000000000000001f8ul) >> 3) | ||
160 | ^ ((iopte & 0x00000000000020000ul) >> 17) | ||
161 | ^ ((iopte & 0x00000000000010000ul) >> 15) | ||
162 | ^ ((iopte & 0x00000000000008000ul) >> 13) | ||
163 | ^ ((iopte & 0x00000000000004000ul) >> 11) | ||
164 | ^ ((iopte & 0x00000000000002000ul) >> 9) | ||
165 | ^ ((iopte & 0x00000000000001000ul) >> 7); | ||
166 | } | ||
167 | |||
168 | /* same as above, but pretend that we have a simpler 1-way associative | ||
169 | pte cache with an 8 bit index */ | ||
170 | static inline unsigned long | ||
171 | get_ioc_hash_1way(ioste iost_entry, unsigned long io_address) | ||
172 | { | ||
173 | unsigned long iopte = get_ioptep(iost_entry, io_address); | ||
174 | |||
175 | return ((iopte & 0x000000000000001f8ul) >> 3) | ||
176 | ^ ((iopte & 0x00000000000020000ul) >> 17) | ||
177 | ^ ((iopte & 0x00000000000010000ul) >> 15) | ||
178 | ^ ((iopte & 0x00000000000008000ul) >> 13) | ||
179 | ^ ((iopte & 0x00000000000004000ul) >> 11) | ||
180 | ^ ((iopte & 0x00000000000002000ul) >> 9) | ||
181 | ^ ((iopte & 0x00000000000001000ul) >> 7) | ||
182 | ^ ((iopte & 0x0000000000000c000ul) >> 8); | ||
183 | } | ||
184 | |||
185 | static inline ioste | ||
186 | get_iost_cache(void __iomem *base, unsigned long index) | ||
187 | { | ||
188 | unsigned long __iomem *p = (base + IOC_ST_CACHE_DIR); | ||
189 | return mk_ioste(in_be64(&p[index])); | ||
190 | } | ||
191 | |||
192 | static inline void | ||
193 | set_iost_cache(void __iomem *base, unsigned long index, ioste ste) | ||
194 | { | ||
195 | unsigned long __iomem *p = (base + IOC_ST_CACHE_DIR); | ||
196 | pr_debug("ioste %02lx was %016lx, store %016lx", index, | ||
197 | get_iost_cache(base, index).val, ste.val); | ||
198 | out_be64(&p[index], ste.val); | ||
199 | pr_debug(" now %016lx\n", get_iost_cache(base, index).val); | ||
200 | } | ||
201 | |||
202 | static inline unsigned long | ||
203 | get_iopt_cache(void __iomem *base, unsigned long index, unsigned long *tag) | ||
204 | { | ||
205 | unsigned long __iomem *tags = (void *)(base + IOC_PT_CACHE_DIR); | ||
206 | unsigned long __iomem *p = (void *)(base + IOC_PT_CACHE_REG); | ||
207 | |||
208 | *tag = tags[index]; | ||
209 | rmb(); | ||
210 | return *p; | ||
211 | } | ||
212 | |||
213 | static inline void | ||
214 | set_iopt_cache(void __iomem *base, unsigned long index, | ||
215 | unsigned long tag, unsigned long val) | ||
216 | { | ||
217 | unsigned long __iomem *tags = base + IOC_PT_CACHE_DIR; | ||
218 | unsigned long __iomem *p = base + IOC_PT_CACHE_REG; | ||
219 | pr_debug("iopt %02lx was v%016lx/t%016lx, store v%016lx/t%016lx\n", | ||
220 | index, get_iopt_cache(base, index, &oldtag), oldtag, val, tag); | ||
221 | |||
222 | out_be64(p, val); | ||
223 | out_be64(&tags[index], tag); | ||
224 | } | ||
225 | |||
226 | static inline void | ||
227 | set_iost_origin(void __iomem *base) | ||
228 | { | ||
229 | unsigned long __iomem *p = base + IOC_ST_ORIGIN; | ||
230 | unsigned long origin = IOSTO_ENABLE | IOSTO_SW; | ||
231 | |||
232 | pr_debug("iost_origin %016lx, now %016lx\n", in_be64(p), origin); | ||
233 | out_be64(p, origin); | ||
234 | } | ||
235 | |||
236 | static inline void | ||
237 | set_iocmd_config(void __iomem *base) | ||
238 | { | ||
239 | unsigned long __iomem *p = base + 0xc00; | ||
240 | unsigned long conf; | ||
241 | |||
242 | conf = in_be64(p); | ||
243 | pr_debug("iost_conf %016lx, now %016lx\n", conf, conf | IOCMD_CONF_TE); | ||
244 | out_be64(p, conf | IOCMD_CONF_TE); | ||
245 | } | ||
246 | |||
247 | /* FIXME: get these from the device tree */ | ||
248 | #define ioc_base 0x20000511000ull | ||
249 | #define ioc_mmio_base 0x20000510000ull | ||
250 | #define ioid 0x48a | ||
251 | #define iopt_phys_offset (- 0x20000000) /* We have a 512MB offset from the SB */ | ||
252 | #define io_page_size 0x1000000 | ||
253 | |||
254 | static unsigned long map_iopt_entry(unsigned long address) | ||
255 | { | ||
256 | switch (address >> 20) { | ||
257 | case 0x600: | ||
258 | address = 0x24020000000ull; /* spider i/o */ | ||
259 | break; | ||
260 | default: | ||
261 | address += iopt_phys_offset; | ||
262 | break; | ||
263 | } | ||
264 | |||
265 | return get_iopt_entry(address, ioid, IOPT_PROT_RW); | ||
266 | } | ||
267 | |||
268 | static void iommu_bus_setup_null(struct pci_bus *b) { } | ||
269 | static void iommu_dev_setup_null(struct pci_dev *d) { } | ||
270 | |||
271 | /* initialize the iommu to support a simple linear mapping | ||
272 | * for each DMA window used by any device. For now, we | ||
273 | * happen to know that there is only one DMA window in use, | ||
274 | * starting at iopt_phys_offset. */ | ||
275 | static void bpa_map_iommu(void) | ||
276 | { | ||
277 | unsigned long address; | ||
278 | void __iomem *base; | ||
279 | ioste ioste; | ||
280 | unsigned long index; | ||
281 | |||
282 | base = __ioremap(ioc_base, 0x1000, _PAGE_NO_CACHE); | ||
283 | pr_debug("%lx mapped to %p\n", ioc_base, base); | ||
284 | set_iocmd_config(base); | ||
285 | iounmap(base); | ||
286 | |||
287 | base = __ioremap(ioc_mmio_base, 0x1000, _PAGE_NO_CACHE); | ||
288 | pr_debug("%lx mapped to %p\n", ioc_mmio_base, base); | ||
289 | |||
290 | set_iost_origin(base); | ||
291 | |||
292 | for (address = 0; address < 0x100000000ul; address += io_page_size) { | ||
293 | ioste = get_iost_entry(0x10000000000ul, address, io_page_size); | ||
294 | if ((address & 0xfffffff) == 0) /* segment start */ | ||
295 | set_iost_cache(base, address >> 28, ioste); | ||
296 | index = get_ioc_hash_1way(ioste, address); | ||
297 | pr_debug("addr %08lx, index %02lx, ioste %016lx\n", | ||
298 | address, index, ioste.val); | ||
299 | set_iopt_cache(base, | ||
300 | get_ioc_hash_1way(ioste, address), | ||
301 | get_ioc_tag(ioste, address), | ||
302 | map_iopt_entry(address)); | ||
303 | } | ||
304 | iounmap(base); | ||
305 | } | ||
306 | |||
307 | |||
308 | static void *bpa_alloc_coherent(struct device *hwdev, size_t size, | ||
309 | dma_addr_t *dma_handle, unsigned int __nocast flag) | ||
310 | { | ||
311 | void *ret; | ||
312 | |||
313 | ret = (void *)__get_free_pages(flag, get_order(size)); | ||
314 | if (ret != NULL) { | ||
315 | memset(ret, 0, size); | ||
316 | *dma_handle = virt_to_abs(ret) | BPA_DMA_VALID; | ||
317 | } | ||
318 | return ret; | ||
319 | } | ||
320 | |||
321 | static void bpa_free_coherent(struct device *hwdev, size_t size, | ||
322 | void *vaddr, dma_addr_t dma_handle) | ||
323 | { | ||
324 | free_pages((unsigned long)vaddr, get_order(size)); | ||
325 | } | ||
326 | |||
327 | static dma_addr_t bpa_map_single(struct device *hwdev, void *ptr, | ||
328 | size_t size, enum dma_data_direction direction) | ||
329 | { | ||
330 | return virt_to_abs(ptr) | BPA_DMA_VALID; | ||
331 | } | ||
332 | |||
333 | static void bpa_unmap_single(struct device *hwdev, dma_addr_t dma_addr, | ||
334 | size_t size, enum dma_data_direction direction) | ||
335 | { | ||
336 | } | ||
337 | |||
338 | static int bpa_map_sg(struct device *hwdev, struct scatterlist *sg, | ||
339 | int nents, enum dma_data_direction direction) | ||
340 | { | ||
341 | int i; | ||
342 | |||
343 | for (i = 0; i < nents; i++, sg++) { | ||
344 | sg->dma_address = (page_to_phys(sg->page) + sg->offset) | ||
345 | | BPA_DMA_VALID; | ||
346 | sg->dma_length = sg->length; | ||
347 | } | ||
348 | |||
349 | return nents; | ||
350 | } | ||
351 | |||
352 | static void bpa_unmap_sg(struct device *hwdev, struct scatterlist *sg, | ||
353 | int nents, enum dma_data_direction direction) | ||
354 | { | ||
355 | } | ||
356 | |||
357 | static int bpa_dma_supported(struct device *dev, u64 mask) | ||
358 | { | ||
359 | return mask < 0x100000000ull; | ||
360 | } | ||
361 | |||
362 | void bpa_init_iommu(void) | ||
363 | { | ||
364 | bpa_map_iommu(); | ||
365 | |||
366 | /* Direct I/O, IOMMU off */ | ||
367 | ppc_md.iommu_dev_setup = iommu_dev_setup_null; | ||
368 | ppc_md.iommu_bus_setup = iommu_bus_setup_null; | ||
369 | |||
370 | pci_dma_ops.alloc_coherent = bpa_alloc_coherent; | ||
371 | pci_dma_ops.free_coherent = bpa_free_coherent; | ||
372 | pci_dma_ops.map_single = bpa_map_single; | ||
373 | pci_dma_ops.unmap_single = bpa_unmap_single; | ||
374 | pci_dma_ops.map_sg = bpa_map_sg; | ||
375 | pci_dma_ops.unmap_sg = bpa_unmap_sg; | ||
376 | pci_dma_ops.dma_supported = bpa_dma_supported; | ||
377 | } | ||
diff --git a/arch/ppc64/kernel/bpa_iommu.h b/arch/ppc64/kernel/bpa_iommu.h new file mode 100644 index 00000000000..e547d77dfa0 --- /dev/null +++ b/arch/ppc64/kernel/bpa_iommu.h | |||
@@ -0,0 +1,65 @@ | |||
1 | #ifndef BPA_IOMMU_H | ||
2 | #define BPA_IOMMU_H | ||
3 | |||
4 | /* some constants */ | ||
5 | enum { | ||
6 | /* segment table entries */ | ||
7 | IOST_VALID_MASK = 0x8000000000000000ul, | ||
8 | IOST_TAG_MASK = 0x3000000000000000ul, | ||
9 | IOST_PT_BASE_MASK = 0x000003fffffff000ul, | ||
10 | IOST_NNPT_MASK = 0x0000000000000fe0ul, | ||
11 | IOST_PS_MASK = 0x000000000000000ful, | ||
12 | |||
13 | IOST_PS_4K = 0x1, | ||
14 | IOST_PS_64K = 0x3, | ||
15 | IOST_PS_1M = 0x5, | ||
16 | IOST_PS_16M = 0x7, | ||
17 | |||
18 | /* iopt tag register */ | ||
19 | IOPT_VALID_MASK = 0x0000000200000000ul, | ||
20 | IOPT_TAG_MASK = 0x00000001fffffffful, | ||
21 | |||
22 | /* iopt cache register */ | ||
23 | IOPT_PROT_MASK = 0xc000000000000000ul, | ||
24 | IOPT_PROT_NONE = 0x0000000000000000ul, | ||
25 | IOPT_PROT_READ = 0x4000000000000000ul, | ||
26 | IOPT_PROT_WRITE = 0x8000000000000000ul, | ||
27 | IOPT_PROT_RW = 0xc000000000000000ul, | ||
28 | IOPT_COHERENT = 0x2000000000000000ul, | ||
29 | |||
30 | IOPT_ORDER_MASK = 0x1800000000000000ul, | ||
31 | /* order access to same IOID/VC on same address */ | ||
32 | IOPT_ORDER_ADDR = 0x0800000000000000ul, | ||
33 | /* similar, but only after a write access */ | ||
34 | IOPT_ORDER_WRITES = 0x1000000000000000ul, | ||
35 | /* Order all accesses to same IOID/VC */ | ||
36 | IOPT_ORDER_VC = 0x1800000000000000ul, | ||
37 | |||
38 | IOPT_RPN_MASK = 0x000003fffffff000ul, | ||
39 | IOPT_HINT_MASK = 0x0000000000000800ul, | ||
40 | IOPT_IOID_MASK = 0x00000000000007fful, | ||
41 | |||
42 | IOSTO_ENABLE = 0x8000000000000000ul, | ||
43 | IOSTO_ORIGIN = 0x000003fffffff000ul, | ||
44 | IOSTO_HW = 0x0000000000000800ul, | ||
45 | IOSTO_SW = 0x0000000000000400ul, | ||
46 | |||
47 | IOCMD_CONF_TE = 0x0000800000000000ul, | ||
48 | |||
49 | /* memory mapped registers */ | ||
50 | IOC_PT_CACHE_DIR = 0x000, | ||
51 | IOC_ST_CACHE_DIR = 0x800, | ||
52 | IOC_PT_CACHE_REG = 0x910, | ||
53 | IOC_ST_ORIGIN = 0x918, | ||
54 | IOC_CONF = 0x930, | ||
55 | |||
56 | /* The high bit needs to be set on every DMA address, | ||
57 | only 2GB are addressable */ | ||
58 | BPA_DMA_VALID = 0x80000000, | ||
59 | BPA_DMA_MASK = 0x7fffffff, | ||
60 | }; | ||
61 | |||
62 | |||
63 | void bpa_init_iommu(void); | ||
64 | |||
65 | #endif | ||
diff --git a/arch/ppc64/kernel/bpa_nvram.c b/arch/ppc64/kernel/bpa_nvram.c new file mode 100644 index 00000000000..06a119cfceb --- /dev/null +++ b/arch/ppc64/kernel/bpa_nvram.c | |||
@@ -0,0 +1,118 @@ | |||
1 | /* | ||
2 | * NVRAM for CPBW | ||
3 | * | ||
4 | * (C) Copyright IBM Corp. 2005 | ||
5 | * | ||
6 | * Authors : Utz Bacher <utz.bacher@de.ibm.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2, or (at your option) | ||
11 | * any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | */ | ||
22 | |||
23 | #include <linux/fs.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/spinlock.h> | ||
27 | #include <linux/types.h> | ||
28 | |||
29 | #include <asm/machdep.h> | ||
30 | #include <asm/nvram.h> | ||
31 | #include <asm/prom.h> | ||
32 | |||
33 | static void __iomem *bpa_nvram_start; | ||
34 | static long bpa_nvram_len; | ||
35 | static spinlock_t bpa_nvram_lock = SPIN_LOCK_UNLOCKED; | ||
36 | |||
37 | static ssize_t bpa_nvram_read(char *buf, size_t count, loff_t *index) | ||
38 | { | ||
39 | unsigned long flags; | ||
40 | |||
41 | if (*index >= bpa_nvram_len) | ||
42 | return 0; | ||
43 | if (*index + count > bpa_nvram_len) | ||
44 | count = bpa_nvram_len - *index; | ||
45 | |||
46 | spin_lock_irqsave(&bpa_nvram_lock, flags); | ||
47 | |||
48 | memcpy_fromio(buf, bpa_nvram_start + *index, count); | ||
49 | |||
50 | spin_unlock_irqrestore(&bpa_nvram_lock, flags); | ||
51 | |||
52 | *index += count; | ||
53 | return count; | ||
54 | } | ||
55 | |||
56 | static ssize_t bpa_nvram_write(char *buf, size_t count, loff_t *index) | ||
57 | { | ||
58 | unsigned long flags; | ||
59 | |||
60 | if (*index >= bpa_nvram_len) | ||
61 | return 0; | ||
62 | if (*index + count > bpa_nvram_len) | ||
63 | count = bpa_nvram_len - *index; | ||
64 | |||
65 | spin_lock_irqsave(&bpa_nvram_lock, flags); | ||
66 | |||
67 | memcpy_toio(bpa_nvram_start + *index, buf, count); | ||
68 | |||
69 | spin_unlock_irqrestore(&bpa_nvram_lock, flags); | ||
70 | |||
71 | *index += count; | ||
72 | return count; | ||
73 | } | ||
74 | |||
75 | static ssize_t bpa_nvram_get_size(void) | ||
76 | { | ||
77 | return bpa_nvram_len; | ||
78 | } | ||
79 | |||
80 | int __init bpa_nvram_init(void) | ||
81 | { | ||
82 | struct device_node *nvram_node; | ||
83 | unsigned long *buffer; | ||
84 | int proplen; | ||
85 | unsigned long nvram_addr; | ||
86 | int ret; | ||
87 | |||
88 | ret = -ENODEV; | ||
89 | nvram_node = of_find_node_by_type(NULL, "nvram"); | ||
90 | if (!nvram_node) | ||
91 | goto out; | ||
92 | |||
93 | ret = -EIO; | ||
94 | buffer = (unsigned long *)get_property(nvram_node, "reg", &proplen); | ||
95 | if (proplen != 2*sizeof(unsigned long)) | ||
96 | goto out; | ||
97 | |||
98 | ret = -ENODEV; | ||
99 | nvram_addr = buffer[0]; | ||
100 | bpa_nvram_len = buffer[1]; | ||
101 | if ( (!bpa_nvram_len) || (!nvram_addr) ) | ||
102 | goto out; | ||
103 | |||
104 | bpa_nvram_start = ioremap(nvram_addr, bpa_nvram_len); | ||
105 | if (!bpa_nvram_start) | ||
106 | goto out; | ||
107 | |||
108 | printk(KERN_INFO "BPA NVRAM, %luk mapped to %p\n", | ||
109 | bpa_nvram_len >> 10, bpa_nvram_start); | ||
110 | |||
111 | ppc_md.nvram_read = bpa_nvram_read; | ||
112 | ppc_md.nvram_write = bpa_nvram_write; | ||
113 | ppc_md.nvram_size = bpa_nvram_get_size; | ||
114 | |||
115 | out: | ||
116 | of_node_put(nvram_node); | ||
117 | return ret; | ||
118 | } | ||
diff --git a/arch/ppc64/kernel/bpa_setup.c b/arch/ppc64/kernel/bpa_setup.c new file mode 100644 index 00000000000..57b3db66f45 --- /dev/null +++ b/arch/ppc64/kernel/bpa_setup.c | |||
@@ -0,0 +1,140 @@ | |||
1 | /* | ||
2 | * linux/arch/ppc/kernel/bpa_setup.c | ||
3 | * | ||
4 | * Copyright (C) 1995 Linus Torvalds | ||
5 | * Adapted from 'alpha' version by Gary Thomas | ||
6 | * Modified by Cort Dougan (cort@cs.nmt.edu) | ||
7 | * Modified by PPC64 Team, IBM Corp | ||
8 | * Modified by BPA Team, IBM Deutschland Entwicklung GmbH | ||
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 | #undef DEBUG | ||
16 | |||
17 | #include <linux/config.h> | ||
18 | #include <linux/sched.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/mm.h> | ||
21 | #include <linux/stddef.h> | ||
22 | #include <linux/unistd.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/user.h> | ||
25 | #include <linux/reboot.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/delay.h> | ||
28 | #include <linux/irq.h> | ||
29 | #include <linux/seq_file.h> | ||
30 | #include <linux/root_dev.h> | ||
31 | #include <linux/console.h> | ||
32 | |||
33 | #include <asm/mmu.h> | ||
34 | #include <asm/processor.h> | ||
35 | #include <asm/io.h> | ||
36 | #include <asm/pgtable.h> | ||
37 | #include <asm/prom.h> | ||
38 | #include <asm/rtas.h> | ||
39 | #include <asm/pci-bridge.h> | ||
40 | #include <asm/iommu.h> | ||
41 | #include <asm/dma.h> | ||
42 | #include <asm/machdep.h> | ||
43 | #include <asm/time.h> | ||
44 | #include <asm/nvram.h> | ||
45 | #include <asm/cputable.h> | ||
46 | |||
47 | #include "pci.h" | ||
48 | #include "bpa_iic.h" | ||
49 | #include "bpa_iommu.h" | ||
50 | |||
51 | #ifdef DEBUG | ||
52 | #define DBG(fmt...) udbg_printf(fmt) | ||
53 | #else | ||
54 | #define DBG(fmt...) | ||
55 | #endif | ||
56 | |||
57 | void bpa_get_cpuinfo(struct seq_file *m) | ||
58 | { | ||
59 | struct device_node *root; | ||
60 | const char *model = ""; | ||
61 | |||
62 | root = of_find_node_by_path("/"); | ||
63 | if (root) | ||
64 | model = get_property(root, "model", NULL); | ||
65 | seq_printf(m, "machine\t\t: BPA %s\n", model); | ||
66 | of_node_put(root); | ||
67 | } | ||
68 | |||
69 | static void bpa_progress(char *s, unsigned short hex) | ||
70 | { | ||
71 | printk("*** %04x : %s\n", hex, s ? s : ""); | ||
72 | } | ||
73 | |||
74 | static void __init bpa_setup_arch(void) | ||
75 | { | ||
76 | ppc_md.init_IRQ = iic_init_IRQ; | ||
77 | ppc_md.get_irq = iic_get_irq; | ||
78 | |||
79 | #ifdef CONFIG_SMP | ||
80 | smp_init_pSeries(); | ||
81 | #endif | ||
82 | |||
83 | /* init to some ~sane value until calibrate_delay() runs */ | ||
84 | loops_per_jiffy = 50000000; | ||
85 | |||
86 | if (ROOT_DEV == 0) { | ||
87 | printk("No ramdisk, default root is /dev/hda2\n"); | ||
88 | ROOT_DEV = Root_HDA2; | ||
89 | } | ||
90 | |||
91 | /* Find and initialize PCI host bridges */ | ||
92 | init_pci_config_tokens(); | ||
93 | find_and_init_phbs(); | ||
94 | spider_init_IRQ(); | ||
95 | #ifdef CONFIG_DUMMY_CONSOLE | ||
96 | conswitchp = &dummy_con; | ||
97 | #endif | ||
98 | |||
99 | bpa_nvram_init(); | ||
100 | } | ||
101 | |||
102 | /* | ||
103 | * Early initialization. Relocation is on but do not reference unbolted pages | ||
104 | */ | ||
105 | static void __init bpa_init_early(void) | ||
106 | { | ||
107 | DBG(" -> bpa_init_early()\n"); | ||
108 | |||
109 | hpte_init_native(); | ||
110 | |||
111 | bpa_init_iommu(); | ||
112 | |||
113 | ppc64_interrupt_controller = IC_BPA_IIC; | ||
114 | |||
115 | DBG(" <- bpa_init_early()\n"); | ||
116 | } | ||
117 | |||
118 | |||
119 | static int __init bpa_probe(int platform) | ||
120 | { | ||
121 | if (platform != PLATFORM_BPA) | ||
122 | return 0; | ||
123 | |||
124 | return 1; | ||
125 | } | ||
126 | |||
127 | struct machdep_calls __initdata bpa_md = { | ||
128 | .probe = bpa_probe, | ||
129 | .setup_arch = bpa_setup_arch, | ||
130 | .init_early = bpa_init_early, | ||
131 | .get_cpuinfo = bpa_get_cpuinfo, | ||
132 | .restart = rtas_restart, | ||
133 | .power_off = rtas_power_off, | ||
134 | .halt = rtas_halt, | ||
135 | .get_boot_time = rtas_get_boot_time, | ||
136 | .get_rtc_time = rtas_get_rtc_time, | ||
137 | .set_rtc_time = rtas_set_rtc_time, | ||
138 | .calibrate_decr = generic_calibrate_decr, | ||
139 | .progress = bpa_progress, | ||
140 | }; | ||
diff --git a/arch/ppc64/kernel/cpu_setup_power4.S b/arch/ppc64/kernel/cpu_setup_power4.S index 3bd95182085..42fc08cf87a 100644 --- a/arch/ppc64/kernel/cpu_setup_power4.S +++ b/arch/ppc64/kernel/cpu_setup_power4.S | |||
@@ -73,7 +73,21 @@ _GLOBAL(__970_cpu_preinit) | |||
73 | 73 | ||
74 | _GLOBAL(__setup_cpu_power4) | 74 | _GLOBAL(__setup_cpu_power4) |
75 | blr | 75 | blr |
76 | 76 | ||
77 | _GLOBAL(__setup_cpu_be) | ||
78 | /* Set large page sizes LP=0: 16MB, LP=1: 64KB */ | ||
79 | addi r3, 0, 0 | ||
80 | ori r3, r3, HID6_LB | ||
81 | sldi r3, r3, 32 | ||
82 | nor r3, r3, r3 | ||
83 | mfspr r4, SPRN_HID6 | ||
84 | and r4, r4, r3 | ||
85 | addi r3, 0, 0x02000 | ||
86 | sldi r3, r3, 32 | ||
87 | or r4, r4, r3 | ||
88 | mtspr SPRN_HID6, r4 | ||
89 | blr | ||
90 | |||
77 | _GLOBAL(__setup_cpu_ppc970) | 91 | _GLOBAL(__setup_cpu_ppc970) |
78 | mfspr r0,SPRN_HID0 | 92 | mfspr r0,SPRN_HID0 |
79 | li r11,5 /* clear DOZE and SLEEP */ | 93 | li r11,5 /* clear DOZE and SLEEP */ |
diff --git a/arch/ppc64/kernel/cputable.c b/arch/ppc64/kernel/cputable.c index 8644a864805..1d162c7c59d 100644 --- a/arch/ppc64/kernel/cputable.c +++ b/arch/ppc64/kernel/cputable.c | |||
@@ -34,6 +34,7 @@ EXPORT_SYMBOL(cur_cpu_spec); | |||
34 | extern void __setup_cpu_power3(unsigned long offset, struct cpu_spec* spec); | 34 | extern void __setup_cpu_power3(unsigned long offset, struct cpu_spec* spec); |
35 | extern void __setup_cpu_power4(unsigned long offset, struct cpu_spec* spec); | 35 | extern void __setup_cpu_power4(unsigned long offset, struct cpu_spec* spec); |
36 | extern void __setup_cpu_ppc970(unsigned long offset, struct cpu_spec* spec); | 36 | extern void __setup_cpu_ppc970(unsigned long offset, struct cpu_spec* spec); |
37 | extern void __setup_cpu_be(unsigned long offset, struct cpu_spec* spec); | ||
37 | 38 | ||
38 | 39 | ||
39 | /* We only set the altivec features if the kernel was compiled with altivec | 40 | /* We only set the altivec features if the kernel was compiled with altivec |
@@ -162,6 +163,16 @@ struct cpu_spec cpu_specs[] = { | |||
162 | __setup_cpu_power4, | 163 | __setup_cpu_power4, |
163 | COMMON_PPC64_FW | 164 | COMMON_PPC64_FW |
164 | }, | 165 | }, |
166 | { /* BE DD1.x */ | ||
167 | 0xffff0000, 0x00700000, "Broadband Engine", | ||
168 | CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | | ||
169 | CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP | | ||
170 | CPU_FTR_SMT, | ||
171 | COMMON_USER_PPC64 | PPC_FEATURE_HAS_ALTIVEC_COMP, | ||
172 | 128, 128, | ||
173 | __setup_cpu_be, | ||
174 | COMMON_PPC64_FW | ||
175 | }, | ||
165 | { /* default match */ | 176 | { /* default match */ |
166 | 0x00000000, 0x00000000, "POWER4 (compatible)", | 177 | 0x00000000, 0x00000000, "POWER4 (compatible)", |
167 | CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | | 178 | CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | |
diff --git a/arch/ppc64/kernel/iSeries_setup.c b/arch/ppc64/kernel/iSeries_setup.c index b31962436fe..86966ce76b5 100644 --- a/arch/ppc64/kernel/iSeries_setup.c +++ b/arch/ppc64/kernel/iSeries_setup.c | |||
@@ -671,9 +671,6 @@ static void __init iSeries_bolt_kernel(unsigned long saddr, unsigned long eaddr) | |||
671 | } | 671 | } |
672 | } | 672 | } |
673 | 673 | ||
674 | extern unsigned long ppc_proc_freq; | ||
675 | extern unsigned long ppc_tb_freq; | ||
676 | |||
677 | /* | 674 | /* |
678 | * Document me. | 675 | * Document me. |
679 | */ | 676 | */ |
@@ -772,8 +769,6 @@ static void iSeries_halt(void) | |||
772 | mf_power_off(); | 769 | mf_power_off(); |
773 | } | 770 | } |
774 | 771 | ||
775 | extern void setup_default_decr(void); | ||
776 | |||
777 | /* | 772 | /* |
778 | * void __init iSeries_calibrate_decr() | 773 | * void __init iSeries_calibrate_decr() |
779 | * | 774 | * |
diff --git a/arch/ppc64/kernel/irq.c b/arch/ppc64/kernel/irq.c index d860467b8f0..3defc8c33ad 100644 --- a/arch/ppc64/kernel/irq.c +++ b/arch/ppc64/kernel/irq.c | |||
@@ -395,6 +395,9 @@ int virt_irq_create_mapping(unsigned int real_irq) | |||
395 | if (ppc64_interrupt_controller == IC_OPEN_PIC) | 395 | if (ppc64_interrupt_controller == IC_OPEN_PIC) |
396 | return real_irq; /* no mapping for openpic (for now) */ | 396 | return real_irq; /* no mapping for openpic (for now) */ |
397 | 397 | ||
398 | if (ppc64_interrupt_controller == IC_BPA_IIC) | ||
399 | return real_irq; /* no mapping for iic either */ | ||
400 | |||
398 | /* don't map interrupts < MIN_VIRT_IRQ */ | 401 | /* don't map interrupts < MIN_VIRT_IRQ */ |
399 | if (real_irq < MIN_VIRT_IRQ) { | 402 | if (real_irq < MIN_VIRT_IRQ) { |
400 | virt_irq_to_real_map[real_irq] = real_irq; | 403 | virt_irq_to_real_map[real_irq] = real_irq; |
diff --git a/arch/ppc64/kernel/maple_setup.c b/arch/ppc64/kernel/maple_setup.c index 8cf95a27178..da8900b51f4 100644 --- a/arch/ppc64/kernel/maple_setup.c +++ b/arch/ppc64/kernel/maple_setup.c | |||
@@ -78,17 +78,77 @@ extern int maple_pci_get_legacy_ide_irq(struct pci_dev *dev, int channel); | |||
78 | extern void generic_find_legacy_serial_ports(u64 *physport, | 78 | extern void generic_find_legacy_serial_ports(u64 *physport, |
79 | unsigned int *default_speed); | 79 | unsigned int *default_speed); |
80 | 80 | ||
81 | |||
82 | static void maple_restart(char *cmd) | 81 | static void maple_restart(char *cmd) |
83 | { | 82 | { |
83 | unsigned int maple_nvram_base; | ||
84 | unsigned int maple_nvram_offset; | ||
85 | unsigned int maple_nvram_command; | ||
86 | struct device_node *rtcs; | ||
87 | |||
88 | /* find NVRAM device */ | ||
89 | rtcs = find_compatible_devices("nvram", "AMD8111"); | ||
90 | if (rtcs && rtcs->addrs) { | ||
91 | maple_nvram_base = rtcs->addrs[0].address; | ||
92 | } else { | ||
93 | printk(KERN_EMERG "Maple: Unable to find NVRAM\n"); | ||
94 | printk(KERN_EMERG "Maple: Manual Restart Required\n"); | ||
95 | return; | ||
96 | } | ||
97 | |||
98 | /* find service processor device */ | ||
99 | rtcs = find_devices("service-processor"); | ||
100 | if (!rtcs) { | ||
101 | printk(KERN_EMERG "Maple: Unable to find Service Processor\n"); | ||
102 | printk(KERN_EMERG "Maple: Manual Restart Required\n"); | ||
103 | return; | ||
104 | } | ||
105 | maple_nvram_offset = *(unsigned int*) get_property(rtcs, | ||
106 | "restart-addr", NULL); | ||
107 | maple_nvram_command = *(unsigned int*) get_property(rtcs, | ||
108 | "restart-value", NULL); | ||
109 | |||
110 | /* send command */ | ||
111 | outb_p(maple_nvram_command, maple_nvram_base + maple_nvram_offset); | ||
112 | for (;;) ; | ||
84 | } | 113 | } |
85 | 114 | ||
86 | static void maple_power_off(void) | 115 | static void maple_power_off(void) |
87 | { | 116 | { |
117 | unsigned int maple_nvram_base; | ||
118 | unsigned int maple_nvram_offset; | ||
119 | unsigned int maple_nvram_command; | ||
120 | struct device_node *rtcs; | ||
121 | |||
122 | /* find NVRAM device */ | ||
123 | rtcs = find_compatible_devices("nvram", "AMD8111"); | ||
124 | if (rtcs && rtcs->addrs) { | ||
125 | maple_nvram_base = rtcs->addrs[0].address; | ||
126 | } else { | ||
127 | printk(KERN_EMERG "Maple: Unable to find NVRAM\n"); | ||
128 | printk(KERN_EMERG "Maple: Manual Power-Down Required\n"); | ||
129 | return; | ||
130 | } | ||
131 | |||
132 | /* find service processor device */ | ||
133 | rtcs = find_devices("service-processor"); | ||
134 | if (!rtcs) { | ||
135 | printk(KERN_EMERG "Maple: Unable to find Service Processor\n"); | ||
136 | printk(KERN_EMERG "Maple: Manual Power-Down Required\n"); | ||
137 | return; | ||
138 | } | ||
139 | maple_nvram_offset = *(unsigned int*) get_property(rtcs, | ||
140 | "power-off-addr", NULL); | ||
141 | maple_nvram_command = *(unsigned int*) get_property(rtcs, | ||
142 | "power-off-value", NULL); | ||
143 | |||
144 | /* send command */ | ||
145 | outb_p(maple_nvram_command, maple_nvram_base + maple_nvram_offset); | ||
146 | for (;;) ; | ||
88 | } | 147 | } |
89 | 148 | ||
90 | static void maple_halt(void) | 149 | static void maple_halt(void) |
91 | { | 150 | { |
151 | maple_power_off(); | ||
92 | } | 152 | } |
93 | 153 | ||
94 | #ifdef CONFIG_SMP | 154 | #ifdef CONFIG_SMP |
@@ -235,6 +295,6 @@ struct machdep_calls __initdata maple_md = { | |||
235 | .get_boot_time = maple_get_boot_time, | 295 | .get_boot_time = maple_get_boot_time, |
236 | .set_rtc_time = maple_set_rtc_time, | 296 | .set_rtc_time = maple_set_rtc_time, |
237 | .get_rtc_time = maple_get_rtc_time, | 297 | .get_rtc_time = maple_get_rtc_time, |
238 | .calibrate_decr = maple_calibrate_decr, | 298 | .calibrate_decr = generic_calibrate_decr, |
239 | .progress = maple_progress, | 299 | .progress = maple_progress, |
240 | }; | 300 | }; |
diff --git a/arch/ppc64/kernel/maple_time.c b/arch/ppc64/kernel/maple_time.c index 07ce7895b43..d65210abcd0 100644 --- a/arch/ppc64/kernel/maple_time.c +++ b/arch/ppc64/kernel/maple_time.c | |||
@@ -42,11 +42,8 @@ | |||
42 | #define DBG(x...) | 42 | #define DBG(x...) |
43 | #endif | 43 | #endif |
44 | 44 | ||
45 | extern void setup_default_decr(void); | ||
46 | extern void GregorianDay(struct rtc_time * tm); | 45 | extern void GregorianDay(struct rtc_time * tm); |
47 | 46 | ||
48 | extern unsigned long ppc_tb_freq; | ||
49 | extern unsigned long ppc_proc_freq; | ||
50 | static int maple_rtc_addr; | 47 | static int maple_rtc_addr; |
51 | 48 | ||
52 | static int maple_clock_read(int addr) | 49 | static int maple_clock_read(int addr) |
@@ -176,51 +173,3 @@ void __init maple_get_boot_time(struct rtc_time *tm) | |||
176 | maple_get_rtc_time(tm); | 173 | maple_get_rtc_time(tm); |
177 | } | 174 | } |
178 | 175 | ||
179 | /* XXX FIXME: Some sane defaults: 125 MHz timebase, 1GHz processor */ | ||
180 | #define DEFAULT_TB_FREQ 125000000UL | ||
181 | #define DEFAULT_PROC_FREQ (DEFAULT_TB_FREQ * 8) | ||
182 | |||
183 | void __init maple_calibrate_decr(void) | ||
184 | { | ||
185 | struct device_node *cpu; | ||
186 | struct div_result divres; | ||
187 | unsigned int *fp = NULL; | ||
188 | |||
189 | /* | ||
190 | * The cpu node should have a timebase-frequency property | ||
191 | * to tell us the rate at which the decrementer counts. | ||
192 | */ | ||
193 | cpu = of_find_node_by_type(NULL, "cpu"); | ||
194 | |||
195 | ppc_tb_freq = DEFAULT_TB_FREQ; | ||
196 | if (cpu != 0) | ||
197 | fp = (unsigned int *)get_property(cpu, "timebase-frequency", NULL); | ||
198 | if (fp != NULL) | ||
199 | ppc_tb_freq = *fp; | ||
200 | else | ||
201 | printk(KERN_ERR "WARNING: Estimating decrementer frequency (not found)\n"); | ||
202 | fp = NULL; | ||
203 | ppc_proc_freq = DEFAULT_PROC_FREQ; | ||
204 | if (cpu != 0) | ||
205 | fp = (unsigned int *)get_property(cpu, "clock-frequency", NULL); | ||
206 | if (fp != NULL) | ||
207 | ppc_proc_freq = *fp; | ||
208 | else | ||
209 | printk(KERN_ERR "WARNING: Estimating processor frequency (not found)\n"); | ||
210 | |||
211 | of_node_put(cpu); | ||
212 | |||
213 | printk(KERN_INFO "time_init: decrementer frequency = %lu.%.6lu MHz\n", | ||
214 | ppc_tb_freq/1000000, ppc_tb_freq%1000000); | ||
215 | printk(KERN_INFO "time_init: processor frequency = %lu.%.6lu MHz\n", | ||
216 | ppc_proc_freq/1000000, ppc_proc_freq%1000000); | ||
217 | |||
218 | tb_ticks_per_jiffy = ppc_tb_freq / HZ; | ||
219 | tb_ticks_per_sec = tb_ticks_per_jiffy * HZ; | ||
220 | tb_ticks_per_usec = ppc_tb_freq / 1000000; | ||
221 | tb_to_us = mulhwu_scale_factor(ppc_tb_freq, 1000000); | ||
222 | div128_by_32(1024*1024, 0, tb_ticks_per_sec, &divres); | ||
223 | tb_to_xs = divres.result_low; | ||
224 | |||
225 | setup_default_decr(); | ||
226 | } | ||
diff --git a/arch/ppc64/kernel/mpic.h b/arch/ppc64/kernel/mpic.h index 571b3c99e06..63e177143ea 100644 --- a/arch/ppc64/kernel/mpic.h +++ b/arch/ppc64/kernel/mpic.h | |||
@@ -265,3 +265,6 @@ extern void mpic_send_ipi(unsigned int ipi_no, unsigned int cpu_mask); | |||
265 | extern int mpic_get_one_irq(struct mpic *mpic, struct pt_regs *regs); | 265 | extern int mpic_get_one_irq(struct mpic *mpic, struct pt_regs *regs); |
266 | /* This one gets to the primary mpic */ | 266 | /* This one gets to the primary mpic */ |
267 | extern int mpic_get_irq(struct pt_regs *regs); | 267 | extern int mpic_get_irq(struct pt_regs *regs); |
268 | |||
269 | /* global mpic for pSeries */ | ||
270 | extern struct mpic *pSeries_mpic; | ||
diff --git a/arch/ppc64/kernel/pSeries_pci.c b/arch/ppc64/kernel/pSeries_pci.c index 0b1cca28140..1f5f141fb7a 100644 --- a/arch/ppc64/kernel/pSeries_pci.c +++ b/arch/ppc64/kernel/pSeries_pci.c | |||
@@ -1,13 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | * pSeries_pci.c | 2 | * arch/ppc64/kernel/pSeries_pci.c |
3 | * | 3 | * |
4 | * Copyright (C) 2001 Dave Engebretsen, IBM Corporation | 4 | * Copyright (C) 2001 Dave Engebretsen, IBM Corporation |
5 | * Copyright (C) 2003 Anton Blanchard <anton@au.ibm.com>, IBM | 5 | * Copyright (C) 2003 Anton Blanchard <anton@au.ibm.com>, IBM |
6 | * | 6 | * |
7 | * pSeries specific routines for PCI. | 7 | * pSeries specific routines for PCI. |
8 | * | 8 | * |
9 | * Based on code from pci.c and chrp_pci.c | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License as published by | 10 | * it under the terms of the GNU General Public License as published by |
13 | * the Free Software Foundation; either version 2 of the License, or | 11 | * the Free Software Foundation; either version 2 of the License, or |
@@ -23,430 +21,18 @@ | |||
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
24 | */ | 22 | */ |
25 | 23 | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/ioport.h> | ||
26 | #include <linux/kernel.h> | 26 | #include <linux/kernel.h> |
27 | #include <linux/threads.h> | ||
28 | #include <linux/pci.h> | 27 | #include <linux/pci.h> |
29 | #include <linux/string.h> | 28 | #include <linux/string.h> |
30 | #include <linux/init.h> | ||
31 | #include <linux/bootmem.h> | ||
32 | 29 | ||
33 | #include <asm/io.h> | ||
34 | #include <asm/pgtable.h> | ||
35 | #include <asm/irq.h> | ||
36 | #include <asm/prom.h> | ||
37 | #include <asm/machdep.h> | ||
38 | #include <asm/pci-bridge.h> | 30 | #include <asm/pci-bridge.h> |
39 | #include <asm/iommu.h> | 31 | #include <asm/prom.h> |
40 | #include <asm/rtas.h> | ||
41 | 32 | ||
42 | #include "mpic.h" | ||
43 | #include "pci.h" | 33 | #include "pci.h" |
44 | 34 | ||
45 | /* RTAS tokens */ | 35 | static int __initdata s7a_workaround = -1; |
46 | static int read_pci_config; | ||
47 | static int write_pci_config; | ||
48 | static int ibm_read_pci_config; | ||
49 | static int ibm_write_pci_config; | ||
50 | |||
51 | static int s7a_workaround; | ||
52 | |||
53 | extern struct mpic *pSeries_mpic; | ||
54 | |||
55 | static int config_access_valid(struct device_node *dn, int where) | ||
56 | { | ||
57 | if (where < 256) | ||
58 | return 1; | ||
59 | if (where < 4096 && dn->pci_ext_config_space) | ||
60 | return 1; | ||
61 | |||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | static int rtas_read_config(struct device_node *dn, int where, int size, u32 *val) | ||
66 | { | ||
67 | int returnval = -1; | ||
68 | unsigned long buid, addr; | ||
69 | int ret; | ||
70 | |||
71 | if (!dn) | ||
72 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
73 | if (!config_access_valid(dn, where)) | ||
74 | return PCIBIOS_BAD_REGISTER_NUMBER; | ||
75 | |||
76 | addr = ((where & 0xf00) << 20) | (dn->busno << 16) | | ||
77 | (dn->devfn << 8) | (where & 0xff); | ||
78 | buid = dn->phb->buid; | ||
79 | if (buid) { | ||
80 | ret = rtas_call(ibm_read_pci_config, 4, 2, &returnval, | ||
81 | addr, buid >> 32, buid & 0xffffffff, size); | ||
82 | } else { | ||
83 | ret = rtas_call(read_pci_config, 2, 2, &returnval, addr, size); | ||
84 | } | ||
85 | *val = returnval; | ||
86 | |||
87 | if (ret) | ||
88 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
89 | |||
90 | if (returnval == EEH_IO_ERROR_VALUE(size) | ||
91 | && eeh_dn_check_failure (dn, NULL)) | ||
92 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
93 | |||
94 | return PCIBIOS_SUCCESSFUL; | ||
95 | } | ||
96 | |||
97 | static int rtas_pci_read_config(struct pci_bus *bus, | ||
98 | unsigned int devfn, | ||
99 | int where, int size, u32 *val) | ||
100 | { | ||
101 | struct device_node *busdn, *dn; | ||
102 | |||
103 | if (bus->self) | ||
104 | busdn = pci_device_to_OF_node(bus->self); | ||
105 | else | ||
106 | busdn = bus->sysdata; /* must be a phb */ | ||
107 | |||
108 | /* Search only direct children of the bus */ | ||
109 | for (dn = busdn->child; dn; dn = dn->sibling) | ||
110 | if (dn->devfn == devfn) | ||
111 | return rtas_read_config(dn, where, size, val); | ||
112 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
113 | } | ||
114 | |||
115 | static int rtas_write_config(struct device_node *dn, int where, int size, u32 val) | ||
116 | { | ||
117 | unsigned long buid, addr; | ||
118 | int ret; | ||
119 | |||
120 | if (!dn) | ||
121 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
122 | if (!config_access_valid(dn, where)) | ||
123 | return PCIBIOS_BAD_REGISTER_NUMBER; | ||
124 | |||
125 | addr = ((where & 0xf00) << 20) | (dn->busno << 16) | | ||
126 | (dn->devfn << 8) | (where & 0xff); | ||
127 | buid = dn->phb->buid; | ||
128 | if (buid) { | ||
129 | ret = rtas_call(ibm_write_pci_config, 5, 1, NULL, addr, buid >> 32, buid & 0xffffffff, size, (ulong) val); | ||
130 | } else { | ||
131 | ret = rtas_call(write_pci_config, 3, 1, NULL, addr, size, (ulong)val); | ||
132 | } | ||
133 | |||
134 | if (ret) | ||
135 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
136 | |||
137 | return PCIBIOS_SUCCESSFUL; | ||
138 | } | ||
139 | |||
140 | static int rtas_pci_write_config(struct pci_bus *bus, | ||
141 | unsigned int devfn, | ||
142 | int where, int size, u32 val) | ||
143 | { | ||
144 | struct device_node *busdn, *dn; | ||
145 | |||
146 | if (bus->self) | ||
147 | busdn = pci_device_to_OF_node(bus->self); | ||
148 | else | ||
149 | busdn = bus->sysdata; /* must be a phb */ | ||
150 | |||
151 | /* Search only direct children of the bus */ | ||
152 | for (dn = busdn->child; dn; dn = dn->sibling) | ||
153 | if (dn->devfn == devfn) | ||
154 | return rtas_write_config(dn, where, size, val); | ||
155 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
156 | } | ||
157 | |||
158 | struct pci_ops rtas_pci_ops = { | ||
159 | rtas_pci_read_config, | ||
160 | rtas_pci_write_config | ||
161 | }; | ||
162 | |||
163 | int is_python(struct device_node *dev) | ||
164 | { | ||
165 | char *model = (char *)get_property(dev, "model", NULL); | ||
166 | |||
167 | if (model && strstr(model, "Python")) | ||
168 | return 1; | ||
169 | |||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | static int get_phb_reg_prop(struct device_node *dev, | ||
174 | unsigned int addr_size_words, | ||
175 | struct reg_property64 *reg) | ||
176 | { | ||
177 | unsigned int *ui_ptr = NULL, len; | ||
178 | |||
179 | /* Found a PHB, now figure out where his registers are mapped. */ | ||
180 | ui_ptr = (unsigned int *)get_property(dev, "reg", &len); | ||
181 | if (ui_ptr == NULL) | ||
182 | return 1; | ||
183 | |||
184 | if (addr_size_words == 1) { | ||
185 | reg->address = ((struct reg_property32 *)ui_ptr)->address; | ||
186 | reg->size = ((struct reg_property32 *)ui_ptr)->size; | ||
187 | } else { | ||
188 | *reg = *((struct reg_property64 *)ui_ptr); | ||
189 | } | ||
190 | |||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | static void python_countermeasures(struct device_node *dev, | ||
195 | unsigned int addr_size_words) | ||
196 | { | ||
197 | struct reg_property64 reg_struct; | ||
198 | void __iomem *chip_regs; | ||
199 | volatile u32 val; | ||
200 | |||
201 | if (get_phb_reg_prop(dev, addr_size_words, ®_struct)) | ||
202 | return; | ||
203 | |||
204 | /* Python's register file is 1 MB in size. */ | ||
205 | chip_regs = ioremap(reg_struct.address & ~(0xfffffUL), 0x100000); | ||
206 | |||
207 | /* | ||
208 | * Firmware doesn't always clear this bit which is critical | ||
209 | * for good performance - Anton | ||
210 | */ | ||
211 | |||
212 | #define PRG_CL_RESET_VALID 0x00010000 | ||
213 | |||
214 | val = in_be32(chip_regs + 0xf6030); | ||
215 | if (val & PRG_CL_RESET_VALID) { | ||
216 | printk(KERN_INFO "Python workaround: "); | ||
217 | val &= ~PRG_CL_RESET_VALID; | ||
218 | out_be32(chip_regs + 0xf6030, val); | ||
219 | /* | ||
220 | * We must read it back for changes to | ||
221 | * take effect | ||
222 | */ | ||
223 | val = in_be32(chip_regs + 0xf6030); | ||
224 | printk("reg0: %x\n", val); | ||
225 | } | ||
226 | |||
227 | iounmap(chip_regs); | ||
228 | } | ||
229 | |||
230 | void __init init_pci_config_tokens (void) | ||
231 | { | ||
232 | read_pci_config = rtas_token("read-pci-config"); | ||
233 | write_pci_config = rtas_token("write-pci-config"); | ||
234 | ibm_read_pci_config = rtas_token("ibm,read-pci-config"); | ||
235 | ibm_write_pci_config = rtas_token("ibm,write-pci-config"); | ||
236 | } | ||
237 | |||
238 | unsigned long __devinit get_phb_buid (struct device_node *phb) | ||
239 | { | ||
240 | int addr_cells; | ||
241 | unsigned int *buid_vals; | ||
242 | unsigned int len; | ||
243 | unsigned long buid; | ||
244 | |||
245 | if (ibm_read_pci_config == -1) return 0; | ||
246 | |||
247 | /* PHB's will always be children of the root node, | ||
248 | * or so it is promised by the current firmware. */ | ||
249 | if (phb->parent == NULL) | ||
250 | return 0; | ||
251 | if (phb->parent->parent) | ||
252 | return 0; | ||
253 | |||
254 | buid_vals = (unsigned int *) get_property(phb, "reg", &len); | ||
255 | if (buid_vals == NULL) | ||
256 | return 0; | ||
257 | |||
258 | addr_cells = prom_n_addr_cells(phb); | ||
259 | if (addr_cells == 1) { | ||
260 | buid = (unsigned long) buid_vals[0]; | ||
261 | } else { | ||
262 | buid = (((unsigned long)buid_vals[0]) << 32UL) | | ||
263 | (((unsigned long)buid_vals[1]) & 0xffffffff); | ||
264 | } | ||
265 | return buid; | ||
266 | } | ||
267 | |||
268 | static int phb_set_bus_ranges(struct device_node *dev, | ||
269 | struct pci_controller *phb) | ||
270 | { | ||
271 | int *bus_range; | ||
272 | unsigned int len; | ||
273 | |||
274 | bus_range = (int *) get_property(dev, "bus-range", &len); | ||
275 | if (bus_range == NULL || len < 2 * sizeof(int)) { | ||
276 | return 1; | ||
277 | } | ||
278 | |||
279 | phb->first_busno = bus_range[0]; | ||
280 | phb->last_busno = bus_range[1]; | ||
281 | |||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | static int __devinit setup_phb(struct device_node *dev, | ||
286 | struct pci_controller *phb, | ||
287 | unsigned int addr_size_words) | ||
288 | { | ||
289 | pci_setup_pci_controller(phb); | ||
290 | |||
291 | if (is_python(dev)) | ||
292 | python_countermeasures(dev, addr_size_words); | ||
293 | |||
294 | if (phb_set_bus_ranges(dev, phb)) | ||
295 | return 1; | ||
296 | |||
297 | phb->arch_data = dev; | ||
298 | phb->ops = &rtas_pci_ops; | ||
299 | phb->buid = get_phb_buid(dev); | ||
300 | |||
301 | return 0; | ||
302 | } | ||
303 | |||
304 | static void __devinit add_linux_pci_domain(struct device_node *dev, | ||
305 | struct pci_controller *phb, | ||
306 | struct property *of_prop) | ||
307 | { | ||
308 | memset(of_prop, 0, sizeof(struct property)); | ||
309 | of_prop->name = "linux,pci-domain"; | ||
310 | of_prop->length = sizeof(phb->global_number); | ||
311 | of_prop->value = (unsigned char *)&of_prop[1]; | ||
312 | memcpy(of_prop->value, &phb->global_number, sizeof(phb->global_number)); | ||
313 | prom_add_property(dev, of_prop); | ||
314 | } | ||
315 | |||
316 | static struct pci_controller * __init alloc_phb(struct device_node *dev, | ||
317 | unsigned int addr_size_words) | ||
318 | { | ||
319 | struct pci_controller *phb; | ||
320 | struct property *of_prop; | ||
321 | |||
322 | phb = alloc_bootmem(sizeof(struct pci_controller)); | ||
323 | if (phb == NULL) | ||
324 | return NULL; | ||
325 | |||
326 | of_prop = alloc_bootmem(sizeof(struct property) + | ||
327 | sizeof(phb->global_number)); | ||
328 | if (!of_prop) | ||
329 | return NULL; | ||
330 | |||
331 | if (setup_phb(dev, phb, addr_size_words)) | ||
332 | return NULL; | ||
333 | |||
334 | add_linux_pci_domain(dev, phb, of_prop); | ||
335 | |||
336 | return phb; | ||
337 | } | ||
338 | |||
339 | static struct pci_controller * __devinit alloc_phb_dynamic(struct device_node *dev, unsigned int addr_size_words) | ||
340 | { | ||
341 | struct pci_controller *phb; | ||
342 | |||
343 | phb = (struct pci_controller *)kmalloc(sizeof(struct pci_controller), | ||
344 | GFP_KERNEL); | ||
345 | if (phb == NULL) | ||
346 | return NULL; | ||
347 | |||
348 | if (setup_phb(dev, phb, addr_size_words)) | ||
349 | return NULL; | ||
350 | |||
351 | phb->is_dynamic = 1; | ||
352 | |||
353 | /* TODO: linux,pci-domain? */ | ||
354 | |||
355 | return phb; | ||
356 | } | ||
357 | |||
358 | unsigned long __init find_and_init_phbs(void) | ||
359 | { | ||
360 | struct device_node *node; | ||
361 | struct pci_controller *phb; | ||
362 | unsigned int root_size_cells = 0; | ||
363 | unsigned int index; | ||
364 | unsigned int *opprop = NULL; | ||
365 | struct device_node *root = of_find_node_by_path("/"); | ||
366 | |||
367 | if (ppc64_interrupt_controller == IC_OPEN_PIC) { | ||
368 | opprop = (unsigned int *)get_property(root, | ||
369 | "platform-open-pic", NULL); | ||
370 | } | ||
371 | |||
372 | root_size_cells = prom_n_size_cells(root); | ||
373 | |||
374 | index = 0; | ||
375 | |||
376 | for (node = of_get_next_child(root, NULL); | ||
377 | node != NULL; | ||
378 | node = of_get_next_child(root, node)) { | ||
379 | if (node->type == NULL || strcmp(node->type, "pci") != 0) | ||
380 | continue; | ||
381 | |||
382 | phb = alloc_phb(node, root_size_cells); | ||
383 | if (!phb) | ||
384 | continue; | ||
385 | |||
386 | pci_process_bridge_OF_ranges(phb, node); | ||
387 | pci_setup_phb_io(phb, index == 0); | ||
388 | |||
389 | if (ppc64_interrupt_controller == IC_OPEN_PIC && pSeries_mpic) { | ||
390 | int addr = root_size_cells * (index + 2) - 1; | ||
391 | mpic_assign_isu(pSeries_mpic, index, opprop[addr]); | ||
392 | } | ||
393 | |||
394 | index++; | ||
395 | } | ||
396 | |||
397 | of_node_put(root); | ||
398 | pci_devs_phb_init(); | ||
399 | |||
400 | /* | ||
401 | * pci_probe_only and pci_assign_all_buses can be set via properties | ||
402 | * in chosen. | ||
403 | */ | ||
404 | if (of_chosen) { | ||
405 | int *prop; | ||
406 | |||
407 | prop = (int *)get_property(of_chosen, "linux,pci-probe-only", | ||
408 | NULL); | ||
409 | if (prop) | ||
410 | pci_probe_only = *prop; | ||
411 | |||
412 | prop = (int *)get_property(of_chosen, | ||
413 | "linux,pci-assign-all-buses", NULL); | ||
414 | if (prop) | ||
415 | pci_assign_all_buses = *prop; | ||
416 | } | ||
417 | |||
418 | return 0; | ||
419 | } | ||
420 | |||
421 | struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn) | ||
422 | { | ||
423 | struct device_node *root = of_find_node_by_path("/"); | ||
424 | unsigned int root_size_cells = 0; | ||
425 | struct pci_controller *phb; | ||
426 | struct pci_bus *bus; | ||
427 | int primary; | ||
428 | |||
429 | root_size_cells = prom_n_size_cells(root); | ||
430 | |||
431 | primary = list_empty(&hose_list); | ||
432 | phb = alloc_phb_dynamic(dn, root_size_cells); | ||
433 | if (!phb) | ||
434 | return NULL; | ||
435 | |||
436 | pci_process_bridge_OF_ranges(phb, dn); | ||
437 | |||
438 | pci_setup_phb_io_dynamic(phb, primary); | ||
439 | of_node_put(root); | ||
440 | |||
441 | pci_devs_phb_init_dynamic(phb); | ||
442 | phb->last_busno = 0xff; | ||
443 | bus = pci_scan_bus(phb->first_busno, phb->ops, phb->arch_data); | ||
444 | phb->bus = bus; | ||
445 | phb->last_busno = bus->subordinate; | ||
446 | |||
447 | return phb; | ||
448 | } | ||
449 | EXPORT_SYMBOL(init_phb_dynamic); | ||
450 | 36 | ||
451 | #if 0 | 37 | #if 0 |
452 | void pcibios_name_device(struct pci_dev *dev) | 38 | void pcibios_name_device(struct pci_dev *dev) |
@@ -474,11 +60,12 @@ void pcibios_name_device(struct pci_dev *dev) | |||
474 | DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pcibios_name_device); | 60 | DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pcibios_name_device); |
475 | #endif | 61 | #endif |
476 | 62 | ||
477 | static void check_s7a(void) | 63 | static void __init check_s7a(void) |
478 | { | 64 | { |
479 | struct device_node *root; | 65 | struct device_node *root; |
480 | char *model; | 66 | char *model; |
481 | 67 | ||
68 | s7a_workaround = 0; | ||
482 | root = of_find_node_by_path("/"); | 69 | root = of_find_node_by_path("/"); |
483 | if (root) { | 70 | if (root) { |
484 | model = get_property(root, "model", NULL); | 71 | model = get_property(root, "model", NULL); |
@@ -488,55 +75,23 @@ static void check_s7a(void) | |||
488 | } | 75 | } |
489 | } | 76 | } |
490 | 77 | ||
491 | /* RPA-specific bits for removing PHBs */ | 78 | void __devinit pSeries_irq_bus_setup(struct pci_bus *bus) |
492 | int pcibios_remove_root_bus(struct pci_controller *phb) | ||
493 | { | 79 | { |
494 | struct pci_bus *b = phb->bus; | 80 | struct pci_dev *dev; |
495 | struct resource *res; | ||
496 | int rc, i; | ||
497 | |||
498 | res = b->resource[0]; | ||
499 | if (!res->flags) { | ||
500 | printk(KERN_ERR "%s: no IO resource for PHB %s\n", __FUNCTION__, | ||
501 | b->name); | ||
502 | return 1; | ||
503 | } | ||
504 | |||
505 | rc = unmap_bus_range(b); | ||
506 | if (rc) { | ||
507 | printk(KERN_ERR "%s: failed to unmap IO on bus %s\n", | ||
508 | __FUNCTION__, b->name); | ||
509 | return 1; | ||
510 | } | ||
511 | 81 | ||
512 | if (release_resource(res)) { | 82 | if (s7a_workaround < 0) |
513 | printk(KERN_ERR "%s: failed to release IO on bus %s\n", | 83 | check_s7a(); |
514 | __FUNCTION__, b->name); | 84 | list_for_each_entry(dev, &bus->devices, bus_list) { |
515 | return 1; | 85 | pci_read_irq_line(dev); |
516 | } | 86 | if (s7a_workaround) { |
517 | 87 | if (dev->irq > 16) { | |
518 | for (i = 1; i < 3; ++i) { | 88 | dev->irq -= 3; |
519 | res = b->resource[i]; | 89 | pci_write_config_byte(dev, PCI_INTERRUPT_LINE, |
520 | if (!res->flags && i == 0) { | 90 | dev->irq); |
521 | printk(KERN_ERR "%s: no MEM resource for PHB %s\n", | 91 | } |
522 | __FUNCTION__, b->name); | ||
523 | return 1; | ||
524 | } | ||
525 | if (res->flags && release_resource(res)) { | ||
526 | printk(KERN_ERR | ||
527 | "%s: failed to release IO %d on bus %s\n", | ||
528 | __FUNCTION__, i, b->name); | ||
529 | return 1; | ||
530 | } | 92 | } |
531 | } | 93 | } |
532 | |||
533 | list_del(&phb->list_node); | ||
534 | if (phb->is_dynamic) | ||
535 | kfree(phb); | ||
536 | |||
537 | return 0; | ||
538 | } | 94 | } |
539 | EXPORT_SYMBOL(pcibios_remove_root_bus); | ||
540 | 95 | ||
541 | static void __init pSeries_request_regions(void) | 96 | static void __init pSeries_request_regions(void) |
542 | { | 97 | { |
@@ -553,20 +108,6 @@ static void __init pSeries_request_regions(void) | |||
553 | 108 | ||
554 | void __init pSeries_final_fixup(void) | 109 | void __init pSeries_final_fixup(void) |
555 | { | 110 | { |
556 | struct pci_dev *dev = NULL; | ||
557 | |||
558 | check_s7a(); | ||
559 | |||
560 | for_each_pci_dev(dev) { | ||
561 | pci_read_irq_line(dev); | ||
562 | if (s7a_workaround) { | ||
563 | if (dev->irq > 16) { | ||
564 | dev->irq -= 3; | ||
565 | pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); | ||
566 | } | ||
567 | } | ||
568 | } | ||
569 | |||
570 | phbs_remap_io(); | 111 | phbs_remap_io(); |
571 | pSeries_request_regions(); | 112 | pSeries_request_regions(); |
572 | 113 | ||
diff --git a/arch/ppc64/kernel/pSeries_setup.c b/arch/ppc64/kernel/pSeries_setup.c index 6c0d1d58a55..f2b41243342 100644 --- a/arch/ppc64/kernel/pSeries_setup.c +++ b/arch/ppc64/kernel/pSeries_setup.c | |||
@@ -71,11 +71,6 @@ | |||
71 | #define DBG(fmt...) | 71 | #define DBG(fmt...) |
72 | #endif | 72 | #endif |
73 | 73 | ||
74 | extern void pSeries_final_fixup(void); | ||
75 | |||
76 | extern void pSeries_get_boot_time(struct rtc_time *rtc_time); | ||
77 | extern void pSeries_get_rtc_time(struct rtc_time *rtc_time); | ||
78 | extern int pSeries_set_rtc_time(struct rtc_time *rtc_time); | ||
79 | extern void find_udbg_vterm(void); | 74 | extern void find_udbg_vterm(void); |
80 | extern void system_reset_fwnmi(void); /* from head.S */ | 75 | extern void system_reset_fwnmi(void); /* from head.S */ |
81 | extern void machine_check_fwnmi(void); /* from head.S */ | 76 | extern void machine_check_fwnmi(void); /* from head.S */ |
@@ -84,9 +79,6 @@ extern void generic_find_legacy_serial_ports(u64 *physport, | |||
84 | 79 | ||
85 | int fwnmi_active; /* TRUE if an FWNMI handler is present */ | 80 | int fwnmi_active; /* TRUE if an FWNMI handler is present */ |
86 | 81 | ||
87 | extern unsigned long ppc_proc_freq; | ||
88 | extern unsigned long ppc_tb_freq; | ||
89 | |||
90 | extern void pSeries_system_reset_exception(struct pt_regs *regs); | 82 | extern void pSeries_system_reset_exception(struct pt_regs *regs); |
91 | extern int pSeries_machine_check_exception(struct pt_regs *regs); | 83 | extern int pSeries_machine_check_exception(struct pt_regs *regs); |
92 | 84 | ||
@@ -381,171 +373,6 @@ static void __init pSeries_init_early(void) | |||
381 | } | 373 | } |
382 | 374 | ||
383 | 375 | ||
384 | static void pSeries_progress(char *s, unsigned short hex) | ||
385 | { | ||
386 | struct device_node *root; | ||
387 | int width, *p; | ||
388 | char *os; | ||
389 | static int display_character, set_indicator; | ||
390 | static int max_width; | ||
391 | static DEFINE_SPINLOCK(progress_lock); | ||
392 | static int pending_newline = 0; /* did last write end with unprinted newline? */ | ||
393 | |||
394 | if (!rtas.base) | ||
395 | return; | ||
396 | |||
397 | if (max_width == 0) { | ||
398 | if ((root = find_path_device("/rtas")) && | ||
399 | (p = (unsigned int *)get_property(root, | ||
400 | "ibm,display-line-length", | ||
401 | NULL))) | ||
402 | max_width = *p; | ||
403 | else | ||
404 | max_width = 0x10; | ||
405 | display_character = rtas_token("display-character"); | ||
406 | set_indicator = rtas_token("set-indicator"); | ||
407 | } | ||
408 | |||
409 | if (display_character == RTAS_UNKNOWN_SERVICE) { | ||
410 | /* use hex display if available */ | ||
411 | if (set_indicator != RTAS_UNKNOWN_SERVICE) | ||
412 | rtas_call(set_indicator, 3, 1, NULL, 6, 0, hex); | ||
413 | return; | ||
414 | } | ||
415 | |||
416 | spin_lock(&progress_lock); | ||
417 | |||
418 | /* | ||
419 | * Last write ended with newline, but we didn't print it since | ||
420 | * it would just clear the bottom line of output. Print it now | ||
421 | * instead. | ||
422 | * | ||
423 | * If no newline is pending, print a CR to start output at the | ||
424 | * beginning of the line. | ||
425 | */ | ||
426 | if (pending_newline) { | ||
427 | rtas_call(display_character, 1, 1, NULL, '\r'); | ||
428 | rtas_call(display_character, 1, 1, NULL, '\n'); | ||
429 | pending_newline = 0; | ||
430 | } else { | ||
431 | rtas_call(display_character, 1, 1, NULL, '\r'); | ||
432 | } | ||
433 | |||
434 | width = max_width; | ||
435 | os = s; | ||
436 | while (*os) { | ||
437 | if (*os == '\n' || *os == '\r') { | ||
438 | /* Blank to end of line. */ | ||
439 | while (width-- > 0) | ||
440 | rtas_call(display_character, 1, 1, NULL, ' '); | ||
441 | |||
442 | /* If newline is the last character, save it | ||
443 | * until next call to avoid bumping up the | ||
444 | * display output. | ||
445 | */ | ||
446 | if (*os == '\n' && !os[1]) { | ||
447 | pending_newline = 1; | ||
448 | spin_unlock(&progress_lock); | ||
449 | return; | ||
450 | } | ||
451 | |||
452 | /* RTAS wants CR-LF, not just LF */ | ||
453 | |||
454 | if (*os == '\n') { | ||
455 | rtas_call(display_character, 1, 1, NULL, '\r'); | ||
456 | rtas_call(display_character, 1, 1, NULL, '\n'); | ||
457 | } else { | ||
458 | /* CR might be used to re-draw a line, so we'll | ||
459 | * leave it alone and not add LF. | ||
460 | */ | ||
461 | rtas_call(display_character, 1, 1, NULL, *os); | ||
462 | } | ||
463 | |||
464 | width = max_width; | ||
465 | } else { | ||
466 | width--; | ||
467 | rtas_call(display_character, 1, 1, NULL, *os); | ||
468 | } | ||
469 | |||
470 | os++; | ||
471 | |||
472 | /* if we overwrite the screen length */ | ||
473 | if (width <= 0) | ||
474 | while ((*os != 0) && (*os != '\n') && (*os != '\r')) | ||
475 | os++; | ||
476 | } | ||
477 | |||
478 | /* Blank to end of line. */ | ||
479 | while (width-- > 0) | ||
480 | rtas_call(display_character, 1, 1, NULL, ' '); | ||
481 | |||
482 | spin_unlock(&progress_lock); | ||
483 | } | ||
484 | |||
485 | extern void setup_default_decr(void); | ||
486 | |||
487 | /* Some sane defaults: 125 MHz timebase, 1GHz processor */ | ||
488 | #define DEFAULT_TB_FREQ 125000000UL | ||
489 | #define DEFAULT_PROC_FREQ (DEFAULT_TB_FREQ * 8) | ||
490 | |||
491 | static void __init pSeries_calibrate_decr(void) | ||
492 | { | ||
493 | struct device_node *cpu; | ||
494 | struct div_result divres; | ||
495 | unsigned int *fp; | ||
496 | int node_found; | ||
497 | |||
498 | /* | ||
499 | * The cpu node should have a timebase-frequency property | ||
500 | * to tell us the rate at which the decrementer counts. | ||
501 | */ | ||
502 | cpu = of_find_node_by_type(NULL, "cpu"); | ||
503 | |||
504 | ppc_tb_freq = DEFAULT_TB_FREQ; /* hardcoded default */ | ||
505 | node_found = 0; | ||
506 | if (cpu != 0) { | ||
507 | fp = (unsigned int *)get_property(cpu, "timebase-frequency", | ||
508 | NULL); | ||
509 | if (fp != 0) { | ||
510 | node_found = 1; | ||
511 | ppc_tb_freq = *fp; | ||
512 | } | ||
513 | } | ||
514 | if (!node_found) | ||
515 | printk(KERN_ERR "WARNING: Estimating decrementer frequency " | ||
516 | "(not found)\n"); | ||
517 | |||
518 | ppc_proc_freq = DEFAULT_PROC_FREQ; | ||
519 | node_found = 0; | ||
520 | if (cpu != 0) { | ||
521 | fp = (unsigned int *)get_property(cpu, "clock-frequency", | ||
522 | NULL); | ||
523 | if (fp != 0) { | ||
524 | node_found = 1; | ||
525 | ppc_proc_freq = *fp; | ||
526 | } | ||
527 | } | ||
528 | if (!node_found) | ||
529 | printk(KERN_ERR "WARNING: Estimating processor frequency " | ||
530 | "(not found)\n"); | ||
531 | |||
532 | of_node_put(cpu); | ||
533 | |||
534 | printk(KERN_INFO "time_init: decrementer frequency = %lu.%.6lu MHz\n", | ||
535 | ppc_tb_freq/1000000, ppc_tb_freq%1000000); | ||
536 | printk(KERN_INFO "time_init: processor frequency = %lu.%.6lu MHz\n", | ||
537 | ppc_proc_freq/1000000, ppc_proc_freq%1000000); | ||
538 | |||
539 | tb_ticks_per_jiffy = ppc_tb_freq / HZ; | ||
540 | tb_ticks_per_sec = tb_ticks_per_jiffy * HZ; | ||
541 | tb_ticks_per_usec = ppc_tb_freq / 1000000; | ||
542 | tb_to_us = mulhwu_scale_factor(ppc_tb_freq, 1000000); | ||
543 | div128_by_32(1024*1024, 0, tb_ticks_per_sec, &divres); | ||
544 | tb_to_xs = divres.result_low; | ||
545 | |||
546 | setup_default_decr(); | ||
547 | } | ||
548 | |||
549 | static int pSeries_check_legacy_ioport(unsigned int baseport) | 376 | static int pSeries_check_legacy_ioport(unsigned int baseport) |
550 | { | 377 | { |
551 | struct device_node *np; | 378 | struct device_node *np; |
@@ -596,16 +423,17 @@ struct machdep_calls __initdata pSeries_md = { | |||
596 | .get_cpuinfo = pSeries_get_cpuinfo, | 423 | .get_cpuinfo = pSeries_get_cpuinfo, |
597 | .log_error = pSeries_log_error, | 424 | .log_error = pSeries_log_error, |
598 | .pcibios_fixup = pSeries_final_fixup, | 425 | .pcibios_fixup = pSeries_final_fixup, |
426 | .irq_bus_setup = pSeries_irq_bus_setup, | ||
599 | .restart = rtas_restart, | 427 | .restart = rtas_restart, |
600 | .power_off = rtas_power_off, | 428 | .power_off = rtas_power_off, |
601 | .halt = rtas_halt, | 429 | .halt = rtas_halt, |
602 | .panic = rtas_os_term, | 430 | .panic = rtas_os_term, |
603 | .cpu_die = pSeries_mach_cpu_die, | 431 | .cpu_die = pSeries_mach_cpu_die, |
604 | .get_boot_time = pSeries_get_boot_time, | 432 | .get_boot_time = rtas_get_boot_time, |
605 | .get_rtc_time = pSeries_get_rtc_time, | 433 | .get_rtc_time = rtas_get_rtc_time, |
606 | .set_rtc_time = pSeries_set_rtc_time, | 434 | .set_rtc_time = rtas_set_rtc_time, |
607 | .calibrate_decr = pSeries_calibrate_decr, | 435 | .calibrate_decr = generic_calibrate_decr, |
608 | .progress = pSeries_progress, | 436 | .progress = rtas_progress, |
609 | .check_legacy_ioport = pSeries_check_legacy_ioport, | 437 | .check_legacy_ioport = pSeries_check_legacy_ioport, |
610 | .system_reset_exception = pSeries_system_reset_exception, | 438 | .system_reset_exception = pSeries_system_reset_exception, |
611 | .machine_check_exception = pSeries_machine_check_exception, | 439 | .machine_check_exception = pSeries_machine_check_exception, |
diff --git a/arch/ppc64/kernel/pSeries_smp.c b/arch/ppc64/kernel/pSeries_smp.c index 4203bd020c8..30154140f7e 100644 --- a/arch/ppc64/kernel/pSeries_smp.c +++ b/arch/ppc64/kernel/pSeries_smp.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * SMP support for pSeries machines. | 2 | * SMP support for pSeries and BPA machines. |
3 | * | 3 | * |
4 | * Dave Engebretsen, Peter Bergner, and | 4 | * Dave Engebretsen, Peter Bergner, and |
5 | * Mike Corrigan {engebret|bergner|mikec}@us.ibm.com | 5 | * Mike Corrigan {engebret|bergner|mikec}@us.ibm.com |
@@ -47,6 +47,7 @@ | |||
47 | #include <asm/pSeries_reconfig.h> | 47 | #include <asm/pSeries_reconfig.h> |
48 | 48 | ||
49 | #include "mpic.h" | 49 | #include "mpic.h" |
50 | #include "bpa_iic.h" | ||
50 | 51 | ||
51 | #ifdef DEBUG | 52 | #ifdef DEBUG |
52 | #define DBG(fmt...) udbg_printf(fmt) | 53 | #define DBG(fmt...) udbg_printf(fmt) |
@@ -286,6 +287,7 @@ static inline int __devinit smp_startup_cpu(unsigned int lcpu) | |||
286 | return 1; | 287 | return 1; |
287 | } | 288 | } |
288 | 289 | ||
290 | #ifdef CONFIG_XICS | ||
289 | static inline void smp_xics_do_message(int cpu, int msg) | 291 | static inline void smp_xics_do_message(int cpu, int msg) |
290 | { | 292 | { |
291 | set_bit(msg, &xics_ipi_message[cpu].value); | 293 | set_bit(msg, &xics_ipi_message[cpu].value); |
@@ -327,6 +329,37 @@ static void __devinit smp_xics_setup_cpu(int cpu) | |||
327 | cpu_clear(cpu, of_spin_map); | 329 | cpu_clear(cpu, of_spin_map); |
328 | 330 | ||
329 | } | 331 | } |
332 | #endif /* CONFIG_XICS */ | ||
333 | #ifdef CONFIG_BPA_IIC | ||
334 | static void smp_iic_message_pass(int target, int msg) | ||
335 | { | ||
336 | unsigned int i; | ||
337 | |||
338 | if (target < NR_CPUS) { | ||
339 | iic_cause_IPI(target, msg); | ||
340 | } else { | ||
341 | for_each_online_cpu(i) { | ||
342 | if (target == MSG_ALL_BUT_SELF | ||
343 | && i == smp_processor_id()) | ||
344 | continue; | ||
345 | iic_cause_IPI(i, msg); | ||
346 | } | ||
347 | } | ||
348 | } | ||
349 | |||
350 | static int __init smp_iic_probe(void) | ||
351 | { | ||
352 | iic_request_IPIs(); | ||
353 | |||
354 | return cpus_weight(cpu_possible_map); | ||
355 | } | ||
356 | |||
357 | static void __devinit smp_iic_setup_cpu(int cpu) | ||
358 | { | ||
359 | if (cpu != boot_cpuid) | ||
360 | iic_setup_cpu(); | ||
361 | } | ||
362 | #endif /* CONFIG_BPA_IIC */ | ||
330 | 363 | ||
331 | static DEFINE_SPINLOCK(timebase_lock); | 364 | static DEFINE_SPINLOCK(timebase_lock); |
332 | static unsigned long timebase = 0; | 365 | static unsigned long timebase = 0; |
@@ -381,14 +414,15 @@ static int smp_pSeries_cpu_bootable(unsigned int nr) | |||
381 | 414 | ||
382 | return 1; | 415 | return 1; |
383 | } | 416 | } |
384 | 417 | #ifdef CONFIG_MPIC | |
385 | static struct smp_ops_t pSeries_mpic_smp_ops = { | 418 | static struct smp_ops_t pSeries_mpic_smp_ops = { |
386 | .message_pass = smp_mpic_message_pass, | 419 | .message_pass = smp_mpic_message_pass, |
387 | .probe = smp_mpic_probe, | 420 | .probe = smp_mpic_probe, |
388 | .kick_cpu = smp_pSeries_kick_cpu, | 421 | .kick_cpu = smp_pSeries_kick_cpu, |
389 | .setup_cpu = smp_mpic_setup_cpu, | 422 | .setup_cpu = smp_mpic_setup_cpu, |
390 | }; | 423 | }; |
391 | 424 | #endif | |
425 | #ifdef CONFIG_XICS | ||
392 | static struct smp_ops_t pSeries_xics_smp_ops = { | 426 | static struct smp_ops_t pSeries_xics_smp_ops = { |
393 | .message_pass = smp_xics_message_pass, | 427 | .message_pass = smp_xics_message_pass, |
394 | .probe = smp_xics_probe, | 428 | .probe = smp_xics_probe, |
@@ -396,6 +430,16 @@ static struct smp_ops_t pSeries_xics_smp_ops = { | |||
396 | .setup_cpu = smp_xics_setup_cpu, | 430 | .setup_cpu = smp_xics_setup_cpu, |
397 | .cpu_bootable = smp_pSeries_cpu_bootable, | 431 | .cpu_bootable = smp_pSeries_cpu_bootable, |
398 | }; | 432 | }; |
433 | #endif | ||
434 | #ifdef CONFIG_BPA_IIC | ||
435 | static struct smp_ops_t bpa_iic_smp_ops = { | ||
436 | .message_pass = smp_iic_message_pass, | ||
437 | .probe = smp_iic_probe, | ||
438 | .kick_cpu = smp_pSeries_kick_cpu, | ||
439 | .setup_cpu = smp_iic_setup_cpu, | ||
440 | .cpu_bootable = smp_pSeries_cpu_bootable, | ||
441 | }; | ||
442 | #endif | ||
399 | 443 | ||
400 | /* This is called very early */ | 444 | /* This is called very early */ |
401 | void __init smp_init_pSeries(void) | 445 | void __init smp_init_pSeries(void) |
@@ -404,10 +448,25 @@ void __init smp_init_pSeries(void) | |||
404 | 448 | ||
405 | DBG(" -> smp_init_pSeries()\n"); | 449 | DBG(" -> smp_init_pSeries()\n"); |
406 | 450 | ||
407 | if (ppc64_interrupt_controller == IC_OPEN_PIC) | 451 | switch (ppc64_interrupt_controller) { |
452 | #ifdef CONFIG_MPIC | ||
453 | case IC_OPEN_PIC: | ||
408 | smp_ops = &pSeries_mpic_smp_ops; | 454 | smp_ops = &pSeries_mpic_smp_ops; |
409 | else | 455 | break; |
456 | #endif | ||
457 | #ifdef CONFIG_XICS | ||
458 | case IC_PPC_XIC: | ||
410 | smp_ops = &pSeries_xics_smp_ops; | 459 | smp_ops = &pSeries_xics_smp_ops; |
460 | break; | ||
461 | #endif | ||
462 | #ifdef CONFIG_BPA_IIC | ||
463 | case IC_BPA_IIC: | ||
464 | smp_ops = &bpa_iic_smp_ops; | ||
465 | break; | ||
466 | #endif | ||
467 | default: | ||
468 | panic("Invalid interrupt controller"); | ||
469 | } | ||
411 | 470 | ||
412 | #ifdef CONFIG_HOTPLUG_CPU | 471 | #ifdef CONFIG_HOTPLUG_CPU |
413 | smp_ops->cpu_disable = pSeries_cpu_disable; | 472 | smp_ops->cpu_disable = pSeries_cpu_disable; |
diff --git a/arch/ppc64/kernel/pci.c b/arch/ppc64/kernel/pci.c index 2bf0513f3ec..580676f87d2 100644 --- a/arch/ppc64/kernel/pci.c +++ b/arch/ppc64/kernel/pci.c | |||
@@ -902,6 +902,9 @@ void __devinit pcibios_fixup_bus(struct pci_bus *bus) | |||
902 | list_for_each_entry(dev, &bus->devices, bus_list) | 902 | list_for_each_entry(dev, &bus->devices, bus_list) |
903 | ppc_md.iommu_dev_setup(dev); | 903 | ppc_md.iommu_dev_setup(dev); |
904 | 904 | ||
905 | if (ppc_md.irq_bus_setup) | ||
906 | ppc_md.irq_bus_setup(bus); | ||
907 | |||
905 | if (!pci_probe_only) | 908 | if (!pci_probe_only) |
906 | return; | 909 | return; |
907 | 910 | ||
diff --git a/arch/ppc64/kernel/pci.h b/arch/ppc64/kernel/pci.h index 0fd7d849aa7..26be78b13af 100644 --- a/arch/ppc64/kernel/pci.h +++ b/arch/ppc64/kernel/pci.h | |||
@@ -40,10 +40,14 @@ struct device_node *fetch_dev_dn(struct pci_dev *dev); | |||
40 | void pci_addr_cache_insert_device(struct pci_dev *dev); | 40 | void pci_addr_cache_insert_device(struct pci_dev *dev); |
41 | void pci_addr_cache_remove_device(struct pci_dev *dev); | 41 | void pci_addr_cache_remove_device(struct pci_dev *dev); |
42 | 42 | ||
43 | /* From pSeries_pci.h */ | 43 | /* From rtas_pci.h */ |
44 | void init_pci_config_tokens (void); | 44 | void init_pci_config_tokens (void); |
45 | unsigned long get_phb_buid (struct device_node *); | 45 | unsigned long get_phb_buid (struct device_node *); |
46 | 46 | ||
47 | /* From pSeries_pci.h */ | ||
48 | extern void pSeries_final_fixup(void); | ||
49 | extern void pSeries_irq_bus_setup(struct pci_bus *bus); | ||
50 | |||
47 | extern unsigned long pci_probe_only; | 51 | extern unsigned long pci_probe_only; |
48 | extern unsigned long pci_assign_all_buses; | 52 | extern unsigned long pci_assign_all_buses; |
49 | extern int pci_read_irq_line(struct pci_dev *pci_dev); | 53 | extern int pci_read_irq_line(struct pci_dev *pci_dev); |
diff --git a/arch/ppc64/kernel/pmac_time.c b/arch/ppc64/kernel/pmac_time.c index f24827581dd..3059edb09cc 100644 --- a/arch/ppc64/kernel/pmac_time.c +++ b/arch/ppc64/kernel/pmac_time.c | |||
@@ -40,11 +40,6 @@ | |||
40 | #define DBG(x...) | 40 | #define DBG(x...) |
41 | #endif | 41 | #endif |
42 | 42 | ||
43 | extern void setup_default_decr(void); | ||
44 | |||
45 | extern unsigned long ppc_tb_freq; | ||
46 | extern unsigned long ppc_proc_freq; | ||
47 | |||
48 | /* Apparently the RTC stores seconds since 1 Jan 1904 */ | 43 | /* Apparently the RTC stores seconds since 1 Jan 1904 */ |
49 | #define RTC_OFFSET 2082844800 | 44 | #define RTC_OFFSET 2082844800 |
50 | 45 | ||
@@ -161,8 +156,7 @@ void __init pmac_get_boot_time(struct rtc_time *tm) | |||
161 | 156 | ||
162 | /* | 157 | /* |
163 | * Query the OF and get the decr frequency. | 158 | * Query the OF and get the decr frequency. |
164 | * This was taken from the pmac time_init() when merging the prep/pmac | 159 | * FIXME: merge this with generic_calibrate_decr |
165 | * time functions. | ||
166 | */ | 160 | */ |
167 | void __init pmac_calibrate_decr(void) | 161 | void __init pmac_calibrate_decr(void) |
168 | { | 162 | { |
diff --git a/arch/ppc64/kernel/proc_ppc64.c b/arch/ppc64/kernel/proc_ppc64.c index 0914b0669b0..a87c66a9652 100644 --- a/arch/ppc64/kernel/proc_ppc64.c +++ b/arch/ppc64/kernel/proc_ppc64.c | |||
@@ -53,7 +53,7 @@ static int __init proc_ppc64_create(void) | |||
53 | if (!root) | 53 | if (!root) |
54 | return 1; | 54 | return 1; |
55 | 55 | ||
56 | if (!(systemcfg->platform & PLATFORM_PSERIES)) | 56 | if (!(systemcfg->platform & (PLATFORM_PSERIES | PLATFORM_BPA))) |
57 | return 0; | 57 | return 0; |
58 | 58 | ||
59 | if (!proc_mkdir("rtas", root)) | 59 | if (!proc_mkdir("rtas", root)) |
diff --git a/arch/ppc64/kernel/prom_init.c b/arch/ppc64/kernel/prom_init.c index b7683abfbe6..e248a7950ae 100644 --- a/arch/ppc64/kernel/prom_init.c +++ b/arch/ppc64/kernel/prom_init.c | |||
@@ -1915,9 +1915,9 @@ unsigned long __init prom_init(unsigned long r3, unsigned long r4, unsigned long | |||
1915 | prom_send_capabilities(); | 1915 | prom_send_capabilities(); |
1916 | 1916 | ||
1917 | /* | 1917 | /* |
1918 | * On pSeries, copy the CPU hold code | 1918 | * On pSeries and BPA, copy the CPU hold code |
1919 | */ | 1919 | */ |
1920 | if (RELOC(of_platform) & PLATFORM_PSERIES) | 1920 | if (RELOC(of_platform) & (PLATFORM_PSERIES | PLATFORM_BPA)) |
1921 | copy_and_flush(0, KERNELBASE - offset, 0x100, 0); | 1921 | copy_and_flush(0, KERNELBASE - offset, 0x100, 0); |
1922 | 1922 | ||
1923 | /* | 1923 | /* |
diff --git a/arch/ppc64/kernel/rtas-proc.c b/arch/ppc64/kernel/rtas-proc.c index 28b1f1521f2..1f3ff860fdf 100644 --- a/arch/ppc64/kernel/rtas-proc.c +++ b/arch/ppc64/kernel/rtas-proc.c | |||
@@ -371,11 +371,11 @@ static ssize_t ppc_rtas_progress_write(struct file *file, | |||
371 | /* Lets see if the user passed hexdigits */ | 371 | /* Lets see if the user passed hexdigits */ |
372 | hex = simple_strtoul(progress_led, NULL, 10); | 372 | hex = simple_strtoul(progress_led, NULL, 10); |
373 | 373 | ||
374 | ppc_md.progress ((char *)progress_led, hex); | 374 | rtas_progress ((char *)progress_led, hex); |
375 | return count; | 375 | return count; |
376 | 376 | ||
377 | /* clear the line */ | 377 | /* clear the line */ |
378 | /* ppc_md.progress(" ", 0xffff);*/ | 378 | /* rtas_progress(" ", 0xffff);*/ |
379 | } | 379 | } |
380 | /* ****************************************************************** */ | 380 | /* ****************************************************************** */ |
381 | static int ppc_rtas_progress_show(struct seq_file *m, void *v) | 381 | static int ppc_rtas_progress_show(struct seq_file *m, void *v) |
diff --git a/arch/ppc64/kernel/rtas.c b/arch/ppc64/kernel/rtas.c index 5575603def2..5e8eb33b8e5 100644 --- a/arch/ppc64/kernel/rtas.c +++ b/arch/ppc64/kernel/rtas.c | |||
@@ -91,6 +91,123 @@ call_rtas_display_status_delay(unsigned char c) | |||
91 | } | 91 | } |
92 | } | 92 | } |
93 | 93 | ||
94 | void | ||
95 | rtas_progress(char *s, unsigned short hex) | ||
96 | { | ||
97 | struct device_node *root; | ||
98 | int width, *p; | ||
99 | char *os; | ||
100 | static int display_character, set_indicator; | ||
101 | static int display_width, display_lines, *row_width, form_feed; | ||
102 | static DEFINE_SPINLOCK(progress_lock); | ||
103 | static int current_line; | ||
104 | static int pending_newline = 0; /* did last write end with unprinted newline? */ | ||
105 | |||
106 | if (!rtas.base) | ||
107 | return; | ||
108 | |||
109 | if (display_width == 0) { | ||
110 | display_width = 0x10; | ||
111 | if ((root = find_path_device("/rtas"))) { | ||
112 | if ((p = (unsigned int *)get_property(root, | ||
113 | "ibm,display-line-length", NULL))) | ||
114 | display_width = *p; | ||
115 | if ((p = (unsigned int *)get_property(root, | ||
116 | "ibm,form-feed", NULL))) | ||
117 | form_feed = *p; | ||
118 | if ((p = (unsigned int *)get_property(root, | ||
119 | "ibm,display-number-of-lines", NULL))) | ||
120 | display_lines = *p; | ||
121 | row_width = (unsigned int *)get_property(root, | ||
122 | "ibm,display-truncation-length", NULL); | ||
123 | } | ||
124 | display_character = rtas_token("display-character"); | ||
125 | set_indicator = rtas_token("set-indicator"); | ||
126 | } | ||
127 | |||
128 | if (display_character == RTAS_UNKNOWN_SERVICE) { | ||
129 | /* use hex display if available */ | ||
130 | if (set_indicator != RTAS_UNKNOWN_SERVICE) | ||
131 | rtas_call(set_indicator, 3, 1, NULL, 6, 0, hex); | ||
132 | return; | ||
133 | } | ||
134 | |||
135 | spin_lock(&progress_lock); | ||
136 | |||
137 | /* | ||
138 | * Last write ended with newline, but we didn't print it since | ||
139 | * it would just clear the bottom line of output. Print it now | ||
140 | * instead. | ||
141 | * | ||
142 | * If no newline is pending and form feed is supported, clear the | ||
143 | * display with a form feed; otherwise, print a CR to start output | ||
144 | * at the beginning of the line. | ||
145 | */ | ||
146 | if (pending_newline) { | ||
147 | rtas_call(display_character, 1, 1, NULL, '\r'); | ||
148 | rtas_call(display_character, 1, 1, NULL, '\n'); | ||
149 | pending_newline = 0; | ||
150 | } else { | ||
151 | current_line = 0; | ||
152 | if (form_feed) | ||
153 | rtas_call(display_character, 1, 1, NULL, | ||
154 | (char)form_feed); | ||
155 | else | ||
156 | rtas_call(display_character, 1, 1, NULL, '\r'); | ||
157 | } | ||
158 | |||
159 | if (row_width) | ||
160 | width = row_width[current_line]; | ||
161 | else | ||
162 | width = display_width; | ||
163 | os = s; | ||
164 | while (*os) { | ||
165 | if (*os == '\n' || *os == '\r') { | ||
166 | /* If newline is the last character, save it | ||
167 | * until next call to avoid bumping up the | ||
168 | * display output. | ||
169 | */ | ||
170 | if (*os == '\n' && !os[1]) { | ||
171 | pending_newline = 1; | ||
172 | current_line++; | ||
173 | if (current_line > display_lines-1) | ||
174 | current_line = display_lines-1; | ||
175 | spin_unlock(&progress_lock); | ||
176 | return; | ||
177 | } | ||
178 | |||
179 | /* RTAS wants CR-LF, not just LF */ | ||
180 | |||
181 | if (*os == '\n') { | ||
182 | rtas_call(display_character, 1, 1, NULL, '\r'); | ||
183 | rtas_call(display_character, 1, 1, NULL, '\n'); | ||
184 | } else { | ||
185 | /* CR might be used to re-draw a line, so we'll | ||
186 | * leave it alone and not add LF. | ||
187 | */ | ||
188 | rtas_call(display_character, 1, 1, NULL, *os); | ||
189 | } | ||
190 | |||
191 | if (row_width) | ||
192 | width = row_width[current_line]; | ||
193 | else | ||
194 | width = display_width; | ||
195 | } else { | ||
196 | width--; | ||
197 | rtas_call(display_character, 1, 1, NULL, *os); | ||
198 | } | ||
199 | |||
200 | os++; | ||
201 | |||
202 | /* if we overwrite the screen length */ | ||
203 | if (width <= 0) | ||
204 | while ((*os != 0) && (*os != '\n') && (*os != '\r')) | ||
205 | os++; | ||
206 | } | ||
207 | |||
208 | spin_unlock(&progress_lock); | ||
209 | } | ||
210 | |||
94 | int | 211 | int |
95 | rtas_token(const char *service) | 212 | rtas_token(const char *service) |
96 | { | 213 | { |
@@ -425,8 +542,8 @@ rtas_flash_firmware(void) | |||
425 | 542 | ||
426 | printk(KERN_ALERT "FLASH: flash image is %ld bytes\n", image_size); | 543 | printk(KERN_ALERT "FLASH: flash image is %ld bytes\n", image_size); |
427 | printk(KERN_ALERT "FLASH: performing flash and reboot\n"); | 544 | printk(KERN_ALERT "FLASH: performing flash and reboot\n"); |
428 | ppc_md.progress("Flashing \n", 0x0); | 545 | rtas_progress("Flashing \n", 0x0); |
429 | ppc_md.progress("Please Wait... ", 0x0); | 546 | rtas_progress("Please Wait... ", 0x0); |
430 | printk(KERN_ALERT "FLASH: this will take several minutes. Do not power off!\n"); | 547 | printk(KERN_ALERT "FLASH: this will take several minutes. Do not power off!\n"); |
431 | status = rtas_call(update_token, 1, 1, NULL, rtas_block_list); | 548 | status = rtas_call(update_token, 1, 1, NULL, rtas_block_list); |
432 | switch (status) { /* should only get "bad" status */ | 549 | switch (status) { /* should only get "bad" status */ |
diff --git a/arch/ppc64/kernel/rtas_pci.c b/arch/ppc64/kernel/rtas_pci.c new file mode 100644 index 00000000000..1048817befb --- /dev/null +++ b/arch/ppc64/kernel/rtas_pci.c | |||
@@ -0,0 +1,495 @@ | |||
1 | /* | ||
2 | * arch/ppc64/kernel/rtas_pci.c | ||
3 | * | ||
4 | * Copyright (C) 2001 Dave Engebretsen, IBM Corporation | ||
5 | * Copyright (C) 2003 Anton Blanchard <anton@au.ibm.com>, IBM | ||
6 | * | ||
7 | * RTAS specific routines for PCI. | ||
8 | * | ||
9 | * Based on code from pci.c, chrp_pci.c and pSeries_pci.c | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | * GNU General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with this program; if not, write to the Free Software | ||
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
24 | */ | ||
25 | |||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/threads.h> | ||
28 | #include <linux/pci.h> | ||
29 | #include <linux/string.h> | ||
30 | #include <linux/init.h> | ||
31 | #include <linux/bootmem.h> | ||
32 | |||
33 | #include <asm/io.h> | ||
34 | #include <asm/pgtable.h> | ||
35 | #include <asm/irq.h> | ||
36 | #include <asm/prom.h> | ||
37 | #include <asm/machdep.h> | ||
38 | #include <asm/pci-bridge.h> | ||
39 | #include <asm/iommu.h> | ||
40 | #include <asm/rtas.h> | ||
41 | |||
42 | #include "mpic.h" | ||
43 | #include "pci.h" | ||
44 | |||
45 | /* RTAS tokens */ | ||
46 | static int read_pci_config; | ||
47 | static int write_pci_config; | ||
48 | static int ibm_read_pci_config; | ||
49 | static int ibm_write_pci_config; | ||
50 | |||
51 | static int config_access_valid(struct device_node *dn, int where) | ||
52 | { | ||
53 | if (where < 256) | ||
54 | return 1; | ||
55 | if (where < 4096 && dn->pci_ext_config_space) | ||
56 | return 1; | ||
57 | |||
58 | return 0; | ||
59 | } | ||
60 | |||
61 | static int rtas_read_config(struct device_node *dn, int where, int size, u32 *val) | ||
62 | { | ||
63 | int returnval = -1; | ||
64 | unsigned long buid, addr; | ||
65 | int ret; | ||
66 | |||
67 | if (!dn) | ||
68 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
69 | if (!config_access_valid(dn, where)) | ||
70 | return PCIBIOS_BAD_REGISTER_NUMBER; | ||
71 | |||
72 | addr = ((where & 0xf00) << 20) | (dn->busno << 16) | | ||
73 | (dn->devfn << 8) | (where & 0xff); | ||
74 | buid = dn->phb->buid; | ||
75 | if (buid) { | ||
76 | ret = rtas_call(ibm_read_pci_config, 4, 2, &returnval, | ||
77 | addr, buid >> 32, buid & 0xffffffff, size); | ||
78 | } else { | ||
79 | ret = rtas_call(read_pci_config, 2, 2, &returnval, addr, size); | ||
80 | } | ||
81 | *val = returnval; | ||
82 | |||
83 | if (ret) | ||
84 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
85 | |||
86 | if (returnval == EEH_IO_ERROR_VALUE(size) | ||
87 | && eeh_dn_check_failure (dn, NULL)) | ||
88 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
89 | |||
90 | return PCIBIOS_SUCCESSFUL; | ||
91 | } | ||
92 | |||
93 | static int rtas_pci_read_config(struct pci_bus *bus, | ||
94 | unsigned int devfn, | ||
95 | int where, int size, u32 *val) | ||
96 | { | ||
97 | struct device_node *busdn, *dn; | ||
98 | |||
99 | if (bus->self) | ||
100 | busdn = pci_device_to_OF_node(bus->self); | ||
101 | else | ||
102 | busdn = bus->sysdata; /* must be a phb */ | ||
103 | |||
104 | /* Search only direct children of the bus */ | ||
105 | for (dn = busdn->child; dn; dn = dn->sibling) | ||
106 | if (dn->devfn == devfn) | ||
107 | return rtas_read_config(dn, where, size, val); | ||
108 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
109 | } | ||
110 | |||
111 | static int rtas_write_config(struct device_node *dn, int where, int size, u32 val) | ||
112 | { | ||
113 | unsigned long buid, addr; | ||
114 | int ret; | ||
115 | |||
116 | if (!dn) | ||
117 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
118 | if (!config_access_valid(dn, where)) | ||
119 | return PCIBIOS_BAD_REGISTER_NUMBER; | ||
120 | |||
121 | addr = ((where & 0xf00) << 20) | (dn->busno << 16) | | ||
122 | (dn->devfn << 8) | (where & 0xff); | ||
123 | buid = dn->phb->buid; | ||
124 | if (buid) { | ||
125 | ret = rtas_call(ibm_write_pci_config, 5, 1, NULL, addr, buid >> 32, buid & 0xffffffff, size, (ulong) val); | ||
126 | } else { | ||
127 | ret = rtas_call(write_pci_config, 3, 1, NULL, addr, size, (ulong)val); | ||
128 | } | ||
129 | |||
130 | if (ret) | ||
131 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
132 | |||
133 | return PCIBIOS_SUCCESSFUL; | ||
134 | } | ||
135 | |||
136 | static int rtas_pci_write_config(struct pci_bus *bus, | ||
137 | unsigned int devfn, | ||
138 | int where, int size, u32 val) | ||
139 | { | ||
140 | struct device_node *busdn, *dn; | ||
141 | |||
142 | if (bus->self) | ||
143 | busdn = pci_device_to_OF_node(bus->self); | ||
144 | else | ||
145 | busdn = bus->sysdata; /* must be a phb */ | ||
146 | |||
147 | /* Search only direct children of the bus */ | ||
148 | for (dn = busdn->child; dn; dn = dn->sibling) | ||
149 | if (dn->devfn == devfn) | ||
150 | return rtas_write_config(dn, where, size, val); | ||
151 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
152 | } | ||
153 | |||
154 | struct pci_ops rtas_pci_ops = { | ||
155 | rtas_pci_read_config, | ||
156 | rtas_pci_write_config | ||
157 | }; | ||
158 | |||
159 | int is_python(struct device_node *dev) | ||
160 | { | ||
161 | char *model = (char *)get_property(dev, "model", NULL); | ||
162 | |||
163 | if (model && strstr(model, "Python")) | ||
164 | return 1; | ||
165 | |||
166 | return 0; | ||
167 | } | ||
168 | |||
169 | static int get_phb_reg_prop(struct device_node *dev, | ||
170 | unsigned int addr_size_words, | ||
171 | struct reg_property64 *reg) | ||
172 | { | ||
173 | unsigned int *ui_ptr = NULL, len; | ||
174 | |||
175 | /* Found a PHB, now figure out where his registers are mapped. */ | ||
176 | ui_ptr = (unsigned int *)get_property(dev, "reg", &len); | ||
177 | if (ui_ptr == NULL) | ||
178 | return 1; | ||
179 | |||
180 | if (addr_size_words == 1) { | ||
181 | reg->address = ((struct reg_property32 *)ui_ptr)->address; | ||
182 | reg->size = ((struct reg_property32 *)ui_ptr)->size; | ||
183 | } else { | ||
184 | *reg = *((struct reg_property64 *)ui_ptr); | ||
185 | } | ||
186 | |||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | static void python_countermeasures(struct device_node *dev, | ||
191 | unsigned int addr_size_words) | ||
192 | { | ||
193 | struct reg_property64 reg_struct; | ||
194 | void __iomem *chip_regs; | ||
195 | volatile u32 val; | ||
196 | |||
197 | if (get_phb_reg_prop(dev, addr_size_words, ®_struct)) | ||
198 | return; | ||
199 | |||
200 | /* Python's register file is 1 MB in size. */ | ||
201 | chip_regs = ioremap(reg_struct.address & ~(0xfffffUL), 0x100000); | ||
202 | |||
203 | /* | ||
204 | * Firmware doesn't always clear this bit which is critical | ||
205 | * for good performance - Anton | ||
206 | */ | ||
207 | |||
208 | #define PRG_CL_RESET_VALID 0x00010000 | ||
209 | |||
210 | val = in_be32(chip_regs + 0xf6030); | ||
211 | if (val & PRG_CL_RESET_VALID) { | ||
212 | printk(KERN_INFO "Python workaround: "); | ||
213 | val &= ~PRG_CL_RESET_VALID; | ||
214 | out_be32(chip_regs + 0xf6030, val); | ||
215 | /* | ||
216 | * We must read it back for changes to | ||
217 | * take effect | ||
218 | */ | ||
219 | val = in_be32(chip_regs + 0xf6030); | ||
220 | printk("reg0: %x\n", val); | ||
221 | } | ||
222 | |||
223 | iounmap(chip_regs); | ||
224 | } | ||
225 | |||
226 | void __init init_pci_config_tokens (void) | ||
227 | { | ||
228 | read_pci_config = rtas_token("read-pci-config"); | ||
229 | write_pci_config = rtas_token("write-pci-config"); | ||
230 | ibm_read_pci_config = rtas_token("ibm,read-pci-config"); | ||
231 | ibm_write_pci_config = rtas_token("ibm,write-pci-config"); | ||
232 | } | ||
233 | |||
234 | unsigned long __devinit get_phb_buid (struct device_node *phb) | ||
235 | { | ||
236 | int addr_cells; | ||
237 | unsigned int *buid_vals; | ||
238 | unsigned int len; | ||
239 | unsigned long buid; | ||
240 | |||
241 | if (ibm_read_pci_config == -1) return 0; | ||
242 | |||
243 | /* PHB's will always be children of the root node, | ||
244 | * or so it is promised by the current firmware. */ | ||
245 | if (phb->parent == NULL) | ||
246 | return 0; | ||
247 | if (phb->parent->parent) | ||
248 | return 0; | ||
249 | |||
250 | buid_vals = (unsigned int *) get_property(phb, "reg", &len); | ||
251 | if (buid_vals == NULL) | ||
252 | return 0; | ||
253 | |||
254 | addr_cells = prom_n_addr_cells(phb); | ||
255 | if (addr_cells == 1) { | ||
256 | buid = (unsigned long) buid_vals[0]; | ||
257 | } else { | ||
258 | buid = (((unsigned long)buid_vals[0]) << 32UL) | | ||
259 | (((unsigned long)buid_vals[1]) & 0xffffffff); | ||
260 | } | ||
261 | return buid; | ||
262 | } | ||
263 | |||
264 | static int phb_set_bus_ranges(struct device_node *dev, | ||
265 | struct pci_controller *phb) | ||
266 | { | ||
267 | int *bus_range; | ||
268 | unsigned int len; | ||
269 | |||
270 | bus_range = (int *) get_property(dev, "bus-range", &len); | ||
271 | if (bus_range == NULL || len < 2 * sizeof(int)) { | ||
272 | return 1; | ||
273 | } | ||
274 | |||
275 | phb->first_busno = bus_range[0]; | ||
276 | phb->last_busno = bus_range[1]; | ||
277 | |||
278 | return 0; | ||
279 | } | ||
280 | |||
281 | static int __devinit setup_phb(struct device_node *dev, | ||
282 | struct pci_controller *phb, | ||
283 | unsigned int addr_size_words) | ||
284 | { | ||
285 | pci_setup_pci_controller(phb); | ||
286 | |||
287 | if (is_python(dev)) | ||
288 | python_countermeasures(dev, addr_size_words); | ||
289 | |||
290 | if (phb_set_bus_ranges(dev, phb)) | ||
291 | return 1; | ||
292 | |||
293 | phb->arch_data = dev; | ||
294 | phb->ops = &rtas_pci_ops; | ||
295 | phb->buid = get_phb_buid(dev); | ||
296 | |||
297 | return 0; | ||
298 | } | ||
299 | |||
300 | static void __devinit add_linux_pci_domain(struct device_node *dev, | ||
301 | struct pci_controller *phb, | ||
302 | struct property *of_prop) | ||
303 | { | ||
304 | memset(of_prop, 0, sizeof(struct property)); | ||
305 | of_prop->name = "linux,pci-domain"; | ||
306 | of_prop->length = sizeof(phb->global_number); | ||
307 | of_prop->value = (unsigned char *)&of_prop[1]; | ||
308 | memcpy(of_prop->value, &phb->global_number, sizeof(phb->global_number)); | ||
309 | prom_add_property(dev, of_prop); | ||
310 | } | ||
311 | |||
312 | static struct pci_controller * __init alloc_phb(struct device_node *dev, | ||
313 | unsigned int addr_size_words) | ||
314 | { | ||
315 | struct pci_controller *phb; | ||
316 | struct property *of_prop; | ||
317 | |||
318 | phb = alloc_bootmem(sizeof(struct pci_controller)); | ||
319 | if (phb == NULL) | ||
320 | return NULL; | ||
321 | |||
322 | of_prop = alloc_bootmem(sizeof(struct property) + | ||
323 | sizeof(phb->global_number)); | ||
324 | if (!of_prop) | ||
325 | return NULL; | ||
326 | |||
327 | if (setup_phb(dev, phb, addr_size_words)) | ||
328 | return NULL; | ||
329 | |||
330 | add_linux_pci_domain(dev, phb, of_prop); | ||
331 | |||
332 | return phb; | ||
333 | } | ||
334 | |||
335 | static struct pci_controller * __devinit alloc_phb_dynamic(struct device_node *dev, unsigned int addr_size_words) | ||
336 | { | ||
337 | struct pci_controller *phb; | ||
338 | |||
339 | phb = (struct pci_controller *)kmalloc(sizeof(struct pci_controller), | ||
340 | GFP_KERNEL); | ||
341 | if (phb == NULL) | ||
342 | return NULL; | ||
343 | |||
344 | if (setup_phb(dev, phb, addr_size_words)) | ||
345 | return NULL; | ||
346 | |||
347 | phb->is_dynamic = 1; | ||
348 | |||
349 | /* TODO: linux,pci-domain? */ | ||
350 | |||
351 | return phb; | ||
352 | } | ||
353 | |||
354 | unsigned long __init find_and_init_phbs(void) | ||
355 | { | ||
356 | struct device_node *node; | ||
357 | struct pci_controller *phb; | ||
358 | unsigned int root_size_cells = 0; | ||
359 | unsigned int index; | ||
360 | unsigned int *opprop = NULL; | ||
361 | struct device_node *root = of_find_node_by_path("/"); | ||
362 | |||
363 | if (ppc64_interrupt_controller == IC_OPEN_PIC) { | ||
364 | opprop = (unsigned int *)get_property(root, | ||
365 | "platform-open-pic", NULL); | ||
366 | } | ||
367 | |||
368 | root_size_cells = prom_n_size_cells(root); | ||
369 | |||
370 | index = 0; | ||
371 | |||
372 | for (node = of_get_next_child(root, NULL); | ||
373 | node != NULL; | ||
374 | node = of_get_next_child(root, node)) { | ||
375 | if (node->type == NULL || strcmp(node->type, "pci") != 0) | ||
376 | continue; | ||
377 | |||
378 | phb = alloc_phb(node, root_size_cells); | ||
379 | if (!phb) | ||
380 | continue; | ||
381 | |||
382 | pci_process_bridge_OF_ranges(phb, node); | ||
383 | pci_setup_phb_io(phb, index == 0); | ||
384 | #ifdef CONFIG_PPC_PSERIES | ||
385 | if (ppc64_interrupt_controller == IC_OPEN_PIC && pSeries_mpic) { | ||
386 | int addr = root_size_cells * (index + 2) - 1; | ||
387 | mpic_assign_isu(pSeries_mpic, index, opprop[addr]); | ||
388 | } | ||
389 | #endif | ||
390 | index++; | ||
391 | } | ||
392 | |||
393 | of_node_put(root); | ||
394 | pci_devs_phb_init(); | ||
395 | |||
396 | /* | ||
397 | * pci_probe_only and pci_assign_all_buses can be set via properties | ||
398 | * in chosen. | ||
399 | */ | ||
400 | if (of_chosen) { | ||
401 | int *prop; | ||
402 | |||
403 | prop = (int *)get_property(of_chosen, "linux,pci-probe-only", | ||
404 | NULL); | ||
405 | if (prop) | ||
406 | pci_probe_only = *prop; | ||
407 | |||
408 | prop = (int *)get_property(of_chosen, | ||
409 | "linux,pci-assign-all-buses", NULL); | ||
410 | if (prop) | ||
411 | pci_assign_all_buses = *prop; | ||
412 | } | ||
413 | |||
414 | return 0; | ||
415 | } | ||
416 | |||
417 | struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn) | ||
418 | { | ||
419 | struct device_node *root = of_find_node_by_path("/"); | ||
420 | unsigned int root_size_cells = 0; | ||
421 | struct pci_controller *phb; | ||
422 | struct pci_bus *bus; | ||
423 | int primary; | ||
424 | |||
425 | root_size_cells = prom_n_size_cells(root); | ||
426 | |||
427 | primary = list_empty(&hose_list); | ||
428 | phb = alloc_phb_dynamic(dn, root_size_cells); | ||
429 | if (!phb) | ||
430 | return NULL; | ||
431 | |||
432 | pci_process_bridge_OF_ranges(phb, dn); | ||
433 | |||
434 | pci_setup_phb_io_dynamic(phb, primary); | ||
435 | of_node_put(root); | ||
436 | |||
437 | pci_devs_phb_init_dynamic(phb); | ||
438 | phb->last_busno = 0xff; | ||
439 | bus = pci_scan_bus(phb->first_busno, phb->ops, phb->arch_data); | ||
440 | phb->bus = bus; | ||
441 | phb->last_busno = bus->subordinate; | ||
442 | |||
443 | return phb; | ||
444 | } | ||
445 | EXPORT_SYMBOL(init_phb_dynamic); | ||
446 | |||
447 | /* RPA-specific bits for removing PHBs */ | ||
448 | int pcibios_remove_root_bus(struct pci_controller *phb) | ||
449 | { | ||
450 | struct pci_bus *b = phb->bus; | ||
451 | struct resource *res; | ||
452 | int rc, i; | ||
453 | |||
454 | res = b->resource[0]; | ||
455 | if (!res->flags) { | ||
456 | printk(KERN_ERR "%s: no IO resource for PHB %s\n", __FUNCTION__, | ||
457 | b->name); | ||
458 | return 1; | ||
459 | } | ||
460 | |||
461 | rc = unmap_bus_range(b); | ||
462 | if (rc) { | ||
463 | printk(KERN_ERR "%s: failed to unmap IO on bus %s\n", | ||
464 | __FUNCTION__, b->name); | ||
465 | return 1; | ||
466 | } | ||
467 | |||
468 | if (release_resource(res)) { | ||
469 | printk(KERN_ERR "%s: failed to release IO on bus %s\n", | ||
470 | __FUNCTION__, b->name); | ||
471 | return 1; | ||
472 | } | ||
473 | |||
474 | for (i = 1; i < 3; ++i) { | ||
475 | res = b->resource[i]; | ||
476 | if (!res->flags && i == 0) { | ||
477 | printk(KERN_ERR "%s: no MEM resource for PHB %s\n", | ||
478 | __FUNCTION__, b->name); | ||
479 | return 1; | ||
480 | } | ||
481 | if (res->flags && release_resource(res)) { | ||
482 | printk(KERN_ERR | ||
483 | "%s: failed to release IO %d on bus %s\n", | ||
484 | __FUNCTION__, i, b->name); | ||
485 | return 1; | ||
486 | } | ||
487 | } | ||
488 | |||
489 | list_del(&phb->list_node); | ||
490 | if (phb->is_dynamic) | ||
491 | kfree(phb); | ||
492 | |||
493 | return 0; | ||
494 | } | ||
495 | EXPORT_SYMBOL(pcibios_remove_root_bus); | ||
diff --git a/arch/ppc64/kernel/rtc.c b/arch/ppc64/kernel/rtc.c index de02aedbe08..d729fefa0df 100644 --- a/arch/ppc64/kernel/rtc.c +++ b/arch/ppc64/kernel/rtc.c | |||
@@ -301,7 +301,7 @@ void iSeries_get_boot_time(struct rtc_time *tm) | |||
301 | #ifdef CONFIG_PPC_RTAS | 301 | #ifdef CONFIG_PPC_RTAS |
302 | #define MAX_RTC_WAIT 5000 /* 5 sec */ | 302 | #define MAX_RTC_WAIT 5000 /* 5 sec */ |
303 | #define RTAS_CLOCK_BUSY (-2) | 303 | #define RTAS_CLOCK_BUSY (-2) |
304 | void pSeries_get_boot_time(struct rtc_time *rtc_tm) | 304 | void rtas_get_boot_time(struct rtc_time *rtc_tm) |
305 | { | 305 | { |
306 | int ret[8]; | 306 | int ret[8]; |
307 | int error, wait_time; | 307 | int error, wait_time; |
@@ -336,7 +336,7 @@ void pSeries_get_boot_time(struct rtc_time *rtc_tm) | |||
336 | * and if a delay is needed to read the clock. In this case we just | 336 | * and if a delay is needed to read the clock. In this case we just |
337 | * silently return without updating rtc_tm. | 337 | * silently return without updating rtc_tm. |
338 | */ | 338 | */ |
339 | void pSeries_get_rtc_time(struct rtc_time *rtc_tm) | 339 | void rtas_get_rtc_time(struct rtc_time *rtc_tm) |
340 | { | 340 | { |
341 | int ret[8]; | 341 | int ret[8]; |
342 | int error, wait_time; | 342 | int error, wait_time; |
@@ -371,7 +371,7 @@ void pSeries_get_rtc_time(struct rtc_time *rtc_tm) | |||
371 | rtc_tm->tm_year = ret[0] - 1900; | 371 | rtc_tm->tm_year = ret[0] - 1900; |
372 | } | 372 | } |
373 | 373 | ||
374 | int pSeries_set_rtc_time(struct rtc_time *tm) | 374 | int rtas_set_rtc_time(struct rtc_time *tm) |
375 | { | 375 | { |
376 | int error, wait_time; | 376 | int error, wait_time; |
377 | unsigned long max_wait_tb; | 377 | unsigned long max_wait_tb; |
diff --git a/arch/ppc64/kernel/setup.c b/arch/ppc64/kernel/setup.c index 9e70ac90dec..0a47a5ef428 100644 --- a/arch/ppc64/kernel/setup.c +++ b/arch/ppc64/kernel/setup.c | |||
@@ -344,6 +344,7 @@ static void __init setup_cpu_maps(void) | |||
344 | extern struct machdep_calls pSeries_md; | 344 | extern struct machdep_calls pSeries_md; |
345 | extern struct machdep_calls pmac_md; | 345 | extern struct machdep_calls pmac_md; |
346 | extern struct machdep_calls maple_md; | 346 | extern struct machdep_calls maple_md; |
347 | extern struct machdep_calls bpa_md; | ||
347 | 348 | ||
348 | /* Ultimately, stuff them in an elf section like initcalls... */ | 349 | /* Ultimately, stuff them in an elf section like initcalls... */ |
349 | static struct machdep_calls __initdata *machines[] = { | 350 | static struct machdep_calls __initdata *machines[] = { |
@@ -356,6 +357,9 @@ static struct machdep_calls __initdata *machines[] = { | |||
356 | #ifdef CONFIG_PPC_MAPLE | 357 | #ifdef CONFIG_PPC_MAPLE |
357 | &maple_md, | 358 | &maple_md, |
358 | #endif /* CONFIG_PPC_MAPLE */ | 359 | #endif /* CONFIG_PPC_MAPLE */ |
360 | #ifdef CONFIG_PPC_BPA | ||
361 | &bpa_md, | ||
362 | #endif | ||
359 | NULL | 363 | NULL |
360 | }; | 364 | }; |
361 | 365 | ||
@@ -679,6 +683,12 @@ void machine_restart(char *cmd) | |||
679 | if (ppc_md.nvram_sync) | 683 | if (ppc_md.nvram_sync) |
680 | ppc_md.nvram_sync(); | 684 | ppc_md.nvram_sync(); |
681 | ppc_md.restart(cmd); | 685 | ppc_md.restart(cmd); |
686 | #ifdef CONFIG_SMP | ||
687 | smp_send_stop(); | ||
688 | #endif | ||
689 | printk(KERN_EMERG "System Halted, OK to turn off power\n"); | ||
690 | local_irq_disable(); | ||
691 | while (1) ; | ||
682 | } | 692 | } |
683 | 693 | ||
684 | EXPORT_SYMBOL(machine_restart); | 694 | EXPORT_SYMBOL(machine_restart); |
@@ -688,6 +698,12 @@ void machine_power_off(void) | |||
688 | if (ppc_md.nvram_sync) | 698 | if (ppc_md.nvram_sync) |
689 | ppc_md.nvram_sync(); | 699 | ppc_md.nvram_sync(); |
690 | ppc_md.power_off(); | 700 | ppc_md.power_off(); |
701 | #ifdef CONFIG_SMP | ||
702 | smp_send_stop(); | ||
703 | #endif | ||
704 | printk(KERN_EMERG "System Halted, OK to turn off power\n"); | ||
705 | local_irq_disable(); | ||
706 | while (1) ; | ||
691 | } | 707 | } |
692 | 708 | ||
693 | EXPORT_SYMBOL(machine_power_off); | 709 | EXPORT_SYMBOL(machine_power_off); |
@@ -697,13 +713,16 @@ void machine_halt(void) | |||
697 | if (ppc_md.nvram_sync) | 713 | if (ppc_md.nvram_sync) |
698 | ppc_md.nvram_sync(); | 714 | ppc_md.nvram_sync(); |
699 | ppc_md.halt(); | 715 | ppc_md.halt(); |
716 | #ifdef CONFIG_SMP | ||
717 | smp_send_stop(); | ||
718 | #endif | ||
719 | printk(KERN_EMERG "System Halted, OK to turn off power\n"); | ||
720 | local_irq_disable(); | ||
721 | while (1) ; | ||
700 | } | 722 | } |
701 | 723 | ||
702 | EXPORT_SYMBOL(machine_halt); | 724 | EXPORT_SYMBOL(machine_halt); |
703 | 725 | ||
704 | unsigned long ppc_proc_freq; | ||
705 | unsigned long ppc_tb_freq; | ||
706 | |||
707 | static int ppc64_panic_event(struct notifier_block *this, | 726 | static int ppc64_panic_event(struct notifier_block *this, |
708 | unsigned long event, void *ptr) | 727 | unsigned long event, void *ptr) |
709 | { | 728 | { |
@@ -1080,11 +1099,11 @@ void __init setup_arch(char **cmdline_p) | |||
1080 | static void ppc64_do_msg(unsigned int src, const char *msg) | 1099 | static void ppc64_do_msg(unsigned int src, const char *msg) |
1081 | { | 1100 | { |
1082 | if (ppc_md.progress) { | 1101 | if (ppc_md.progress) { |
1083 | char buf[32]; | 1102 | char buf[128]; |
1084 | 1103 | ||
1085 | sprintf(buf, "%08x \n", src); | 1104 | sprintf(buf, "%08X\n", src); |
1086 | ppc_md.progress(buf, 0); | 1105 | ppc_md.progress(buf, 0); |
1087 | sprintf(buf, "%-16s", msg); | 1106 | snprintf(buf, 128, "%s", msg); |
1088 | ppc_md.progress(buf, 0); | 1107 | ppc_md.progress(buf, 0); |
1089 | } | 1108 | } |
1090 | } | 1109 | } |
@@ -1118,7 +1137,7 @@ void ppc64_dump_msg(unsigned int src, const char *msg) | |||
1118 | } | 1137 | } |
1119 | 1138 | ||
1120 | /* This should only be called on processor 0 during calibrate decr */ | 1139 | /* This should only be called on processor 0 during calibrate decr */ |
1121 | void setup_default_decr(void) | 1140 | void __init setup_default_decr(void) |
1122 | { | 1141 | { |
1123 | struct paca_struct *lpaca = get_paca(); | 1142 | struct paca_struct *lpaca = get_paca(); |
1124 | 1143 | ||
diff --git a/arch/ppc64/kernel/smp.c b/arch/ppc64/kernel/smp.c index 9ef5d36d6b2..2fcddfcb594 100644 --- a/arch/ppc64/kernel/smp.c +++ b/arch/ppc64/kernel/smp.c | |||
@@ -71,7 +71,7 @@ void smp_call_function_interrupt(void); | |||
71 | 71 | ||
72 | int smt_enabled_at_boot = 1; | 72 | int smt_enabled_at_boot = 1; |
73 | 73 | ||
74 | #ifdef CONFIG_PPC_MULTIPLATFORM | 74 | #ifdef CONFIG_MPIC |
75 | void smp_mpic_message_pass(int target, int msg) | 75 | void smp_mpic_message_pass(int target, int msg) |
76 | { | 76 | { |
77 | /* make sure we're sending something that translates to an IPI */ | 77 | /* make sure we're sending something that translates to an IPI */ |
@@ -128,7 +128,7 @@ void __devinit smp_generic_kick_cpu(int nr) | |||
128 | smp_mb(); | 128 | smp_mb(); |
129 | } | 129 | } |
130 | 130 | ||
131 | #endif /* CONFIG_PPC_MULTIPLATFORM */ | 131 | #endif /* CONFIG_MPIC */ |
132 | 132 | ||
133 | static void __init smp_space_timers(unsigned int max_cpus) | 133 | static void __init smp_space_timers(unsigned int max_cpus) |
134 | { | 134 | { |
diff --git a/arch/ppc64/kernel/spider-pic.c b/arch/ppc64/kernel/spider-pic.c new file mode 100644 index 00000000000..d5c9a02fb11 --- /dev/null +++ b/arch/ppc64/kernel/spider-pic.c | |||
@@ -0,0 +1,191 @@ | |||
1 | /* | ||
2 | * External Interrupt Controller on Spider South Bridge | ||
3 | * | ||
4 | * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 | ||
5 | * | ||
6 | * Author: Arnd Bergmann <arndb@de.ibm.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2, or (at your option) | ||
11 | * any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | */ | ||
22 | |||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/irq.h> | ||
25 | |||
26 | #include <asm/pgtable.h> | ||
27 | #include <asm/prom.h> | ||
28 | #include <asm/io.h> | ||
29 | |||
30 | #include "bpa_iic.h" | ||
31 | |||
32 | /* register layout taken from Spider spec, table 7.4-4 */ | ||
33 | enum { | ||
34 | TIR_DEN = 0x004, /* Detection Enable Register */ | ||
35 | TIR_MSK = 0x084, /* Mask Level Register */ | ||
36 | TIR_EDC = 0x0c0, /* Edge Detection Clear Register */ | ||
37 | TIR_PNDA = 0x100, /* Pending Register A */ | ||
38 | TIR_PNDB = 0x104, /* Pending Register B */ | ||
39 | TIR_CS = 0x144, /* Current Status Register */ | ||
40 | TIR_LCSA = 0x150, /* Level Current Status Register A */ | ||
41 | TIR_LCSB = 0x154, /* Level Current Status Register B */ | ||
42 | TIR_LCSC = 0x158, /* Level Current Status Register C */ | ||
43 | TIR_LCSD = 0x15c, /* Level Current Status Register D */ | ||
44 | TIR_CFGA = 0x200, /* Setting Register A0 */ | ||
45 | TIR_CFGB = 0x204, /* Setting Register B0 */ | ||
46 | /* 0x208 ... 0x3ff Setting Register An/Bn */ | ||
47 | TIR_PPNDA = 0x400, /* Packet Pending Register A */ | ||
48 | TIR_PPNDB = 0x404, /* Packet Pending Register B */ | ||
49 | TIR_PIERA = 0x408, /* Packet Output Error Register A */ | ||
50 | TIR_PIERB = 0x40c, /* Packet Output Error Register B */ | ||
51 | TIR_PIEN = 0x444, /* Packet Output Enable Register */ | ||
52 | TIR_PIPND = 0x454, /* Packet Output Pending Register */ | ||
53 | TIRDID = 0x484, /* Spider Device ID Register */ | ||
54 | REISTIM = 0x500, /* Reissue Command Timeout Time Setting */ | ||
55 | REISTIMEN = 0x504, /* Reissue Command Timeout Setting */ | ||
56 | REISWAITEN = 0x508, /* Reissue Wait Control*/ | ||
57 | }; | ||
58 | |||
59 | static void __iomem *spider_pics[4]; | ||
60 | |||
61 | static void __iomem *spider_get_pic(int irq) | ||
62 | { | ||
63 | int node = irq / IIC_NODE_STRIDE; | ||
64 | irq %= IIC_NODE_STRIDE; | ||
65 | |||
66 | if (irq >= IIC_EXT_OFFSET && | ||
67 | irq < IIC_EXT_OFFSET + IIC_NUM_EXT && | ||
68 | spider_pics) | ||
69 | return spider_pics[node]; | ||
70 | return NULL; | ||
71 | } | ||
72 | |||
73 | static int spider_get_nr(unsigned int irq) | ||
74 | { | ||
75 | return (irq % IIC_NODE_STRIDE) - IIC_EXT_OFFSET; | ||
76 | } | ||
77 | |||
78 | static void __iomem *spider_get_irq_config(int irq) | ||
79 | { | ||
80 | void __iomem *pic; | ||
81 | pic = spider_get_pic(irq); | ||
82 | return pic + TIR_CFGA + 8 * spider_get_nr(irq); | ||
83 | } | ||
84 | |||
85 | static void spider_enable_irq(unsigned int irq) | ||
86 | { | ||
87 | void __iomem *cfg = spider_get_irq_config(irq); | ||
88 | irq = spider_get_nr(irq); | ||
89 | |||
90 | out_be32(cfg, in_be32(cfg) | 0x3107000eu); | ||
91 | out_be32(cfg + 4, in_be32(cfg + 4) | 0x00020000u | irq); | ||
92 | } | ||
93 | |||
94 | static void spider_disable_irq(unsigned int irq) | ||
95 | { | ||
96 | void __iomem *cfg = spider_get_irq_config(irq); | ||
97 | irq = spider_get_nr(irq); | ||
98 | |||
99 | out_be32(cfg, in_be32(cfg) & ~0x30000000u); | ||
100 | } | ||
101 | |||
102 | static unsigned int spider_startup_irq(unsigned int irq) | ||
103 | { | ||
104 | spider_enable_irq(irq); | ||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | static void spider_shutdown_irq(unsigned int irq) | ||
109 | { | ||
110 | spider_disable_irq(irq); | ||
111 | } | ||
112 | |||
113 | static void spider_end_irq(unsigned int irq) | ||
114 | { | ||
115 | spider_enable_irq(irq); | ||
116 | } | ||
117 | |||
118 | static void spider_ack_irq(unsigned int irq) | ||
119 | { | ||
120 | spider_disable_irq(irq); | ||
121 | iic_local_enable(); | ||
122 | } | ||
123 | |||
124 | static struct hw_interrupt_type spider_pic = { | ||
125 | .typename = " SPIDER ", | ||
126 | .startup = spider_startup_irq, | ||
127 | .shutdown = spider_shutdown_irq, | ||
128 | .enable = spider_enable_irq, | ||
129 | .disable = spider_disable_irq, | ||
130 | .ack = spider_ack_irq, | ||
131 | .end = spider_end_irq, | ||
132 | }; | ||
133 | |||
134 | |||
135 | int spider_get_irq(unsigned long int_pending) | ||
136 | { | ||
137 | void __iomem *regs = spider_get_pic(int_pending); | ||
138 | unsigned long cs; | ||
139 | int irq; | ||
140 | |||
141 | cs = in_be32(regs + TIR_CS); | ||
142 | |||
143 | irq = cs >> 24; | ||
144 | if (irq != 63) | ||
145 | return irq; | ||
146 | |||
147 | return -1; | ||
148 | } | ||
149 | |||
150 | void spider_init_IRQ(void) | ||
151 | { | ||
152 | int node; | ||
153 | struct device_node *dn; | ||
154 | unsigned int *property; | ||
155 | long spiderpic; | ||
156 | int n; | ||
157 | |||
158 | /* FIXME: detect multiple PICs as soon as the device tree has them */ | ||
159 | for (node = 0; node < 1; node++) { | ||
160 | dn = of_find_node_by_path("/"); | ||
161 | n = prom_n_addr_cells(dn); | ||
162 | property = (unsigned int *) get_property(dn, | ||
163 | "platform-spider-pic", NULL); | ||
164 | |||
165 | if (!property) | ||
166 | continue; | ||
167 | for (spiderpic = 0; n > 0; --n) | ||
168 | spiderpic = (spiderpic << 32) + *property++; | ||
169 | printk(KERN_DEBUG "SPIDER addr: %lx\n", spiderpic); | ||
170 | spider_pics[node] = __ioremap(spiderpic, 0x800, _PAGE_NO_CACHE); | ||
171 | for (n = 0; n < IIC_NUM_EXT; n++) { | ||
172 | int irq = n + IIC_EXT_OFFSET + node * IIC_NODE_STRIDE; | ||
173 | get_irq_desc(irq)->handler = &spider_pic; | ||
174 | |||
175 | /* do not mask any interrupts because of level */ | ||
176 | out_be32(spider_pics[node] + TIR_MSK, 0x0); | ||
177 | |||
178 | /* disable edge detection clear */ | ||
179 | /* out_be32(spider_pics[node] + TIR_EDC, 0x0); */ | ||
180 | |||
181 | /* enable interrupt packets to be output */ | ||
182 | out_be32(spider_pics[node] + TIR_PIEN, | ||
183 | in_be32(spider_pics[node] + TIR_PIEN) | 0x1); | ||
184 | |||
185 | /* Enable the interrupt detection enable bit. Do this last! */ | ||
186 | out_be32(spider_pics[node] + TIR_DEN, | ||
187 | in_be32(spider_pics[node] +TIR_DEN) | 0x1); | ||
188 | |||
189 | } | ||
190 | } | ||
191 | } | ||
diff --git a/arch/ppc64/kernel/time.c b/arch/ppc64/kernel/time.c index 33364a7d2cd..2348a75e050 100644 --- a/arch/ppc64/kernel/time.c +++ b/arch/ppc64/kernel/time.c | |||
@@ -107,6 +107,9 @@ void ppc_adjtimex(void); | |||
107 | 107 | ||
108 | static unsigned adjusting_time = 0; | 108 | static unsigned adjusting_time = 0; |
109 | 109 | ||
110 | unsigned long ppc_proc_freq; | ||
111 | unsigned long ppc_tb_freq; | ||
112 | |||
110 | static __inline__ void timer_check_rtc(void) | 113 | static __inline__ void timer_check_rtc(void) |
111 | { | 114 | { |
112 | /* | 115 | /* |
@@ -472,6 +475,66 @@ int do_settimeofday(struct timespec *tv) | |||
472 | 475 | ||
473 | EXPORT_SYMBOL(do_settimeofday); | 476 | EXPORT_SYMBOL(do_settimeofday); |
474 | 477 | ||
478 | #if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_MAPLE) || defined(CONFIG_PPC_BPA) | ||
479 | void __init generic_calibrate_decr(void) | ||
480 | { | ||
481 | struct device_node *cpu; | ||
482 | struct div_result divres; | ||
483 | unsigned int *fp; | ||
484 | int node_found; | ||
485 | |||
486 | /* | ||
487 | * The cpu node should have a timebase-frequency property | ||
488 | * to tell us the rate at which the decrementer counts. | ||
489 | */ | ||
490 | cpu = of_find_node_by_type(NULL, "cpu"); | ||
491 | |||
492 | ppc_tb_freq = DEFAULT_TB_FREQ; /* hardcoded default */ | ||
493 | node_found = 0; | ||
494 | if (cpu != 0) { | ||
495 | fp = (unsigned int *)get_property(cpu, "timebase-frequency", | ||
496 | NULL); | ||
497 | if (fp != 0) { | ||
498 | node_found = 1; | ||
499 | ppc_tb_freq = *fp; | ||
500 | } | ||
501 | } | ||
502 | if (!node_found) | ||
503 | printk(KERN_ERR "WARNING: Estimating decrementer frequency " | ||
504 | "(not found)\n"); | ||
505 | |||
506 | ppc_proc_freq = DEFAULT_PROC_FREQ; | ||
507 | node_found = 0; | ||
508 | if (cpu != 0) { | ||
509 | fp = (unsigned int *)get_property(cpu, "clock-frequency", | ||
510 | NULL); | ||
511 | if (fp != 0) { | ||
512 | node_found = 1; | ||
513 | ppc_proc_freq = *fp; | ||
514 | } | ||
515 | } | ||
516 | if (!node_found) | ||
517 | printk(KERN_ERR "WARNING: Estimating processor frequency " | ||
518 | "(not found)\n"); | ||
519 | |||
520 | of_node_put(cpu); | ||
521 | |||
522 | printk(KERN_INFO "time_init: decrementer frequency = %lu.%.6lu MHz\n", | ||
523 | ppc_tb_freq/1000000, ppc_tb_freq%1000000); | ||
524 | printk(KERN_INFO "time_init: processor frequency = %lu.%.6lu MHz\n", | ||
525 | ppc_proc_freq/1000000, ppc_proc_freq%1000000); | ||
526 | |||
527 | tb_ticks_per_jiffy = ppc_tb_freq / HZ; | ||
528 | tb_ticks_per_sec = tb_ticks_per_jiffy * HZ; | ||
529 | tb_ticks_per_usec = ppc_tb_freq / 1000000; | ||
530 | tb_to_us = mulhwu_scale_factor(ppc_tb_freq, 1000000); | ||
531 | div128_by_32(1024*1024, 0, tb_ticks_per_sec, &divres); | ||
532 | tb_to_xs = divres.result_low; | ||
533 | |||
534 | setup_default_decr(); | ||
535 | } | ||
536 | #endif | ||
537 | |||
475 | void __init time_init(void) | 538 | void __init time_init(void) |
476 | { | 539 | { |
477 | /* This function is only called on the boot processor */ | 540 | /* This function is only called on the boot processor */ |
diff --git a/arch/ppc64/kernel/traps.c b/arch/ppc64/kernel/traps.c index 7e52cb2605e..a8d5e83ee89 100644 --- a/arch/ppc64/kernel/traps.c +++ b/arch/ppc64/kernel/traps.c | |||
@@ -126,6 +126,10 @@ int die(const char *str, struct pt_regs *regs, long err) | |||
126 | printk("POWERMAC "); | 126 | printk("POWERMAC "); |
127 | nl = 1; | 127 | nl = 1; |
128 | break; | 128 | break; |
129 | case PLATFORM_BPA: | ||
130 | printk("BPA "); | ||
131 | nl = 1; | ||
132 | break; | ||
129 | } | 133 | } |
130 | if (nl) | 134 | if (nl) |
131 | printk("\n"); | 135 | printk("\n"); |