diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-07-26 01:59:39 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-07-26 01:59:39 -0400 |
commit | 184475029a724b6b900d88fc3a5f462a6107d5af (patch) | |
tree | 408320b46df221a2424bf94282b1b8e5b7aff7a1 /arch/powerpc/sysdev | |
parent | 3b76eefe0f970c2e19f165d4a1650abc523d10bc (diff) | |
parent | f1f4ee01c0d3dce0e3aa7d04e4332677db7af478 (diff) |
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc
* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc: (99 commits)
drivers/virt: add missing linux/interrupt.h to fsl_hypervisor.c
powerpc/85xx: fix mpic configuration in CAMP mode
powerpc: Copy back TIF flags on return from softirq stack
powerpc/64: Make server perfmon only built on ppc64 server devices
powerpc/pseries: Fix hvc_vio.c build due to recent changes
powerpc: Exporting boot_cpuid_phys
powerpc: Add CFAR to oops output
hvc_console: Add kdb support
powerpc/pseries: Fix hvterm_raw_get_chars to accept < 16 chars, fixing xmon
powerpc/irq: Quieten irq mapping printks
powerpc: Enable lockup and hung task detectors in pseries and ppc64 defeconfigs
powerpc: Add mpt2sas driver to pseries and ppc64 defconfig
powerpc: Disable IRQs off tracer in ppc64 defconfig
powerpc: Sync pseries and ppc64 defconfigs
powerpc/pseries/hvconsole: Fix dropped console output
hvc_console: Improve tty/console put_chars handling
powerpc/kdump: Fix timeout in crash_kexec_wait_realmode
powerpc/mm: Fix output of total_ram.
powerpc/cpufreq: Add cpufreq driver for Momentum Maple boards
powerpc: Correct annotations of pmu registration functions
...
Fix up trivial Kconfig/Makefile conflicts in arch/powerpc, drivers, and
drivers/cpufreq
Diffstat (limited to 'arch/powerpc/sysdev')
-rw-r--r-- | arch/powerpc/sysdev/Makefile | 1 | ||||
-rw-r--r-- | arch/powerpc/sysdev/ehv_pic.c | 302 | ||||
-rw-r--r-- | arch/powerpc/sysdev/fsl_pci.c | 83 | ||||
-rw-r--r-- | arch/powerpc/sysdev/fsl_soc.c | 27 | ||||
-rw-r--r-- | arch/powerpc/sysdev/fsl_soc.h | 3 | ||||
-rw-r--r-- | arch/powerpc/sysdev/mpic.c | 38 | ||||
-rw-r--r-- | arch/powerpc/sysdev/ppc4xx_pci.c | 147 |
7 files changed, 438 insertions, 163 deletions
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile index 0efa990e3344..cf736ca0cf05 100644 --- a/arch/powerpc/sysdev/Makefile +++ b/arch/powerpc/sysdev/Makefile | |||
@@ -4,6 +4,7 @@ ccflags-$(CONFIG_PPC64) := -mno-minimal-toc | |||
4 | 4 | ||
5 | mpic-msi-obj-$(CONFIG_PCI_MSI) += mpic_msi.o mpic_u3msi.o mpic_pasemi_msi.o | 5 | mpic-msi-obj-$(CONFIG_PCI_MSI) += mpic_msi.o mpic_u3msi.o mpic_pasemi_msi.o |
6 | obj-$(CONFIG_MPIC) += mpic.o $(mpic-msi-obj-y) | 6 | obj-$(CONFIG_MPIC) += mpic.o $(mpic-msi-obj-y) |
7 | obj-$(CONFIG_PPC_EPAPR_HV_PIC) += ehv_pic.o | ||
7 | fsl-msi-obj-$(CONFIG_PCI_MSI) += fsl_msi.o | 8 | fsl-msi-obj-$(CONFIG_PCI_MSI) += fsl_msi.o |
8 | obj-$(CONFIG_PPC_MSI_BITMAP) += msi_bitmap.o | 9 | obj-$(CONFIG_PPC_MSI_BITMAP) += msi_bitmap.o |
9 | 10 | ||
diff --git a/arch/powerpc/sysdev/ehv_pic.c b/arch/powerpc/sysdev/ehv_pic.c new file mode 100644 index 000000000000..af1a5df46b3e --- /dev/null +++ b/arch/powerpc/sysdev/ehv_pic.c | |||
@@ -0,0 +1,302 @@ | |||
1 | /* | ||
2 | * Driver for ePAPR Embedded Hypervisor PIC | ||
3 | * | ||
4 | * Copyright 2008-2011 Freescale Semiconductor, Inc. | ||
5 | * | ||
6 | * Author: Ashish Kalra <ashish.kalra@freescale.com> | ||
7 | * | ||
8 | * This file is licensed under the terms of the GNU General Public License | ||
9 | * version 2. This program is licensed "as is" without any warranty of any | ||
10 | * kind, whether express or implied. | ||
11 | */ | ||
12 | |||
13 | #include <linux/types.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/irq.h> | ||
17 | #include <linux/smp.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/spinlock.h> | ||
21 | #include <linux/of.h> | ||
22 | |||
23 | #include <asm/io.h> | ||
24 | #include <asm/irq.h> | ||
25 | #include <asm/smp.h> | ||
26 | #include <asm/machdep.h> | ||
27 | #include <asm/ehv_pic.h> | ||
28 | #include <asm/fsl_hcalls.h> | ||
29 | |||
30 | #include "../../../kernel/irq/settings.h" | ||
31 | |||
32 | static struct ehv_pic *global_ehv_pic; | ||
33 | static DEFINE_SPINLOCK(ehv_pic_lock); | ||
34 | |||
35 | static u32 hwirq_intspec[NR_EHV_PIC_INTS]; | ||
36 | static u32 __iomem *mpic_percpu_base_vaddr; | ||
37 | |||
38 | #define IRQ_TYPE_MPIC_DIRECT 4 | ||
39 | #define MPIC_EOI 0x00B0 | ||
40 | |||
41 | /* | ||
42 | * Linux descriptor level callbacks | ||
43 | */ | ||
44 | |||
45 | void ehv_pic_unmask_irq(struct irq_data *d) | ||
46 | { | ||
47 | unsigned int src = virq_to_hw(d->irq); | ||
48 | |||
49 | ev_int_set_mask(src, 0); | ||
50 | } | ||
51 | |||
52 | void ehv_pic_mask_irq(struct irq_data *d) | ||
53 | { | ||
54 | unsigned int src = virq_to_hw(d->irq); | ||
55 | |||
56 | ev_int_set_mask(src, 1); | ||
57 | } | ||
58 | |||
59 | void ehv_pic_end_irq(struct irq_data *d) | ||
60 | { | ||
61 | unsigned int src = virq_to_hw(d->irq); | ||
62 | |||
63 | ev_int_eoi(src); | ||
64 | } | ||
65 | |||
66 | void ehv_pic_direct_end_irq(struct irq_data *d) | ||
67 | { | ||
68 | out_be32(mpic_percpu_base_vaddr + MPIC_EOI / 4, 0); | ||
69 | } | ||
70 | |||
71 | int ehv_pic_set_affinity(struct irq_data *d, const struct cpumask *dest, | ||
72 | bool force) | ||
73 | { | ||
74 | unsigned int src = virq_to_hw(d->irq); | ||
75 | unsigned int config, prio, cpu_dest; | ||
76 | int cpuid = irq_choose_cpu(dest); | ||
77 | unsigned long flags; | ||
78 | |||
79 | spin_lock_irqsave(&ehv_pic_lock, flags); | ||
80 | ev_int_get_config(src, &config, &prio, &cpu_dest); | ||
81 | ev_int_set_config(src, config, prio, cpuid); | ||
82 | spin_unlock_irqrestore(&ehv_pic_lock, flags); | ||
83 | |||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | static unsigned int ehv_pic_type_to_vecpri(unsigned int type) | ||
88 | { | ||
89 | /* Now convert sense value */ | ||
90 | |||
91 | switch (type & IRQ_TYPE_SENSE_MASK) { | ||
92 | case IRQ_TYPE_EDGE_RISING: | ||
93 | return EHV_PIC_INFO(VECPRI_SENSE_EDGE) | | ||
94 | EHV_PIC_INFO(VECPRI_POLARITY_POSITIVE); | ||
95 | |||
96 | case IRQ_TYPE_EDGE_FALLING: | ||
97 | case IRQ_TYPE_EDGE_BOTH: | ||
98 | return EHV_PIC_INFO(VECPRI_SENSE_EDGE) | | ||
99 | EHV_PIC_INFO(VECPRI_POLARITY_NEGATIVE); | ||
100 | |||
101 | case IRQ_TYPE_LEVEL_HIGH: | ||
102 | return EHV_PIC_INFO(VECPRI_SENSE_LEVEL) | | ||
103 | EHV_PIC_INFO(VECPRI_POLARITY_POSITIVE); | ||
104 | |||
105 | case IRQ_TYPE_LEVEL_LOW: | ||
106 | default: | ||
107 | return EHV_PIC_INFO(VECPRI_SENSE_LEVEL) | | ||
108 | EHV_PIC_INFO(VECPRI_POLARITY_NEGATIVE); | ||
109 | } | ||
110 | } | ||
111 | |||
112 | int ehv_pic_set_irq_type(struct irq_data *d, unsigned int flow_type) | ||
113 | { | ||
114 | unsigned int src = virq_to_hw(d->irq); | ||
115 | struct irq_desc *desc = irq_to_desc(d->irq); | ||
116 | unsigned int vecpri, vold, vnew, prio, cpu_dest; | ||
117 | unsigned long flags; | ||
118 | |||
119 | if (flow_type == IRQ_TYPE_NONE) | ||
120 | flow_type = IRQ_TYPE_LEVEL_LOW; | ||
121 | |||
122 | irq_settings_clr_level(desc); | ||
123 | irq_settings_set_trigger_mask(desc, flow_type); | ||
124 | if (flow_type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) | ||
125 | irq_settings_set_level(desc); | ||
126 | |||
127 | vecpri = ehv_pic_type_to_vecpri(flow_type); | ||
128 | |||
129 | spin_lock_irqsave(&ehv_pic_lock, flags); | ||
130 | ev_int_get_config(src, &vold, &prio, &cpu_dest); | ||
131 | vnew = vold & ~(EHV_PIC_INFO(VECPRI_POLARITY_MASK) | | ||
132 | EHV_PIC_INFO(VECPRI_SENSE_MASK)); | ||
133 | vnew |= vecpri; | ||
134 | |||
135 | /* | ||
136 | * TODO : Add specific interface call for platform to set | ||
137 | * individual interrupt priorities. | ||
138 | * platform currently using static/default priority for all ints | ||
139 | */ | ||
140 | |||
141 | prio = 8; | ||
142 | |||
143 | ev_int_set_config(src, vecpri, prio, cpu_dest); | ||
144 | |||
145 | spin_unlock_irqrestore(&ehv_pic_lock, flags); | ||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | static struct irq_chip ehv_pic_irq_chip = { | ||
150 | .irq_mask = ehv_pic_mask_irq, | ||
151 | .irq_unmask = ehv_pic_unmask_irq, | ||
152 | .irq_eoi = ehv_pic_end_irq, | ||
153 | .irq_set_type = ehv_pic_set_irq_type, | ||
154 | }; | ||
155 | |||
156 | static struct irq_chip ehv_pic_direct_eoi_irq_chip = { | ||
157 | .irq_mask = ehv_pic_mask_irq, | ||
158 | .irq_unmask = ehv_pic_unmask_irq, | ||
159 | .irq_eoi = ehv_pic_direct_end_irq, | ||
160 | .irq_set_type = ehv_pic_set_irq_type, | ||
161 | }; | ||
162 | |||
163 | /* Return an interrupt vector or NO_IRQ if no interrupt is pending. */ | ||
164 | unsigned int ehv_pic_get_irq(void) | ||
165 | { | ||
166 | int irq; | ||
167 | |||
168 | BUG_ON(global_ehv_pic == NULL); | ||
169 | |||
170 | if (global_ehv_pic->coreint_flag) | ||
171 | irq = mfspr(SPRN_EPR); /* if core int mode */ | ||
172 | else | ||
173 | ev_int_iack(0, &irq); /* legacy mode */ | ||
174 | |||
175 | if (irq == 0xFFFF) /* 0xFFFF --> no irq is pending */ | ||
176 | return NO_IRQ; | ||
177 | |||
178 | /* | ||
179 | * this will also setup revmap[] in the slow path for the first | ||
180 | * time, next calls will always use fast path by indexing revmap | ||
181 | */ | ||
182 | return irq_linear_revmap(global_ehv_pic->irqhost, irq); | ||
183 | } | ||
184 | |||
185 | static int ehv_pic_host_match(struct irq_host *h, struct device_node *node) | ||
186 | { | ||
187 | /* Exact match, unless ehv_pic node is NULL */ | ||
188 | return h->of_node == NULL || h->of_node == node; | ||
189 | } | ||
190 | |||
191 | static int ehv_pic_host_map(struct irq_host *h, unsigned int virq, | ||
192 | irq_hw_number_t hw) | ||
193 | { | ||
194 | struct ehv_pic *ehv_pic = h->host_data; | ||
195 | struct irq_chip *chip; | ||
196 | |||
197 | /* Default chip */ | ||
198 | chip = &ehv_pic->hc_irq; | ||
199 | |||
200 | if (mpic_percpu_base_vaddr) | ||
201 | if (hwirq_intspec[hw] & IRQ_TYPE_MPIC_DIRECT) | ||
202 | chip = &ehv_pic_direct_eoi_irq_chip; | ||
203 | |||
204 | irq_set_chip_data(virq, chip); | ||
205 | /* | ||
206 | * using handle_fasteoi_irq as our irq handler, this will | ||
207 | * only call the eoi callback and suitable for the MPIC | ||
208 | * controller which set ISR/IPR automatically and clear the | ||
209 | * highest priority active interrupt in ISR/IPR when we do | ||
210 | * a specific eoi | ||
211 | */ | ||
212 | irq_set_chip_and_handler(virq, chip, handle_fasteoi_irq); | ||
213 | |||
214 | /* Set default irq type */ | ||
215 | irq_set_irq_type(virq, IRQ_TYPE_NONE); | ||
216 | |||
217 | return 0; | ||
218 | } | ||
219 | |||
220 | static int ehv_pic_host_xlate(struct irq_host *h, struct device_node *ct, | ||
221 | const u32 *intspec, unsigned int intsize, | ||
222 | irq_hw_number_t *out_hwirq, unsigned int *out_flags) | ||
223 | |||
224 | { | ||
225 | /* | ||
226 | * interrupt sense values coming from the guest device tree | ||
227 | * interrupt specifiers can have four possible sense and | ||
228 | * level encoding information and they need to | ||
229 | * be translated between firmware type & linux type. | ||
230 | */ | ||
231 | |||
232 | static unsigned char map_of_senses_to_linux_irqtype[4] = { | ||
233 | IRQ_TYPE_EDGE_FALLING, | ||
234 | IRQ_TYPE_EDGE_RISING, | ||
235 | IRQ_TYPE_LEVEL_LOW, | ||
236 | IRQ_TYPE_LEVEL_HIGH, | ||
237 | }; | ||
238 | |||
239 | *out_hwirq = intspec[0]; | ||
240 | if (intsize > 1) { | ||
241 | hwirq_intspec[intspec[0]] = intspec[1]; | ||
242 | *out_flags = map_of_senses_to_linux_irqtype[intspec[1] & | ||
243 | ~IRQ_TYPE_MPIC_DIRECT]; | ||
244 | } else { | ||
245 | *out_flags = IRQ_TYPE_NONE; | ||
246 | } | ||
247 | |||
248 | return 0; | ||
249 | } | ||
250 | |||
251 | static struct irq_host_ops ehv_pic_host_ops = { | ||
252 | .match = ehv_pic_host_match, | ||
253 | .map = ehv_pic_host_map, | ||
254 | .xlate = ehv_pic_host_xlate, | ||
255 | }; | ||
256 | |||
257 | void __init ehv_pic_init(void) | ||
258 | { | ||
259 | struct device_node *np, *np2; | ||
260 | struct ehv_pic *ehv_pic; | ||
261 | int coreint_flag = 1; | ||
262 | |||
263 | np = of_find_compatible_node(NULL, NULL, "epapr,hv-pic"); | ||
264 | if (!np) { | ||
265 | pr_err("ehv_pic_init: could not find epapr,hv-pic node\n"); | ||
266 | return; | ||
267 | } | ||
268 | |||
269 | if (!of_find_property(np, "has-external-proxy", NULL)) | ||
270 | coreint_flag = 0; | ||
271 | |||
272 | ehv_pic = kzalloc(sizeof(struct ehv_pic), GFP_KERNEL); | ||
273 | if (!ehv_pic) { | ||
274 | of_node_put(np); | ||
275 | return; | ||
276 | } | ||
277 | |||
278 | ehv_pic->irqhost = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, | ||
279 | NR_EHV_PIC_INTS, &ehv_pic_host_ops, 0); | ||
280 | |||
281 | if (!ehv_pic->irqhost) { | ||
282 | of_node_put(np); | ||
283 | return; | ||
284 | } | ||
285 | |||
286 | np2 = of_find_compatible_node(NULL, NULL, "fsl,hv-mpic-per-cpu"); | ||
287 | if (np2) { | ||
288 | mpic_percpu_base_vaddr = of_iomap(np2, 0); | ||
289 | if (!mpic_percpu_base_vaddr) | ||
290 | pr_err("ehv_pic_init: of_iomap failed\n"); | ||
291 | |||
292 | of_node_put(np2); | ||
293 | } | ||
294 | |||
295 | ehv_pic->irqhost->host_data = ehv_pic; | ||
296 | ehv_pic->hc_irq = ehv_pic_irq_chip; | ||
297 | ehv_pic->hc_irq.irq_set_affinity = ehv_pic_set_affinity; | ||
298 | ehv_pic->coreint_flag = coreint_flag; | ||
299 | |||
300 | global_ehv_pic = ehv_pic; | ||
301 | irq_set_default_host(global_ehv_pic->irqhost); | ||
302 | } | ||
diff --git a/arch/powerpc/sysdev/fsl_pci.c b/arch/powerpc/sysdev/fsl_pci.c index ba5cb3fa7074..3bba8bdb58b0 100644 --- a/arch/powerpc/sysdev/fsl_pci.c +++ b/arch/powerpc/sysdev/fsl_pci.c | |||
@@ -38,10 +38,17 @@ static int fsl_pcie_bus_fixup, is_mpc83xx_pci; | |||
38 | 38 | ||
39 | static void __init quirk_fsl_pcie_header(struct pci_dev *dev) | 39 | static void __init quirk_fsl_pcie_header(struct pci_dev *dev) |
40 | { | 40 | { |
41 | u8 progif; | ||
42 | |||
41 | /* if we aren't a PCIe don't bother */ | 43 | /* if we aren't a PCIe don't bother */ |
42 | if (!pci_find_capability(dev, PCI_CAP_ID_EXP)) | 44 | if (!pci_find_capability(dev, PCI_CAP_ID_EXP)) |
43 | return; | 45 | return; |
44 | 46 | ||
47 | /* if we aren't in host mode don't bother */ | ||
48 | pci_read_config_byte(dev, PCI_CLASS_PROG, &progif); | ||
49 | if (progif & 0x1) | ||
50 | return; | ||
51 | |||
45 | dev->class = PCI_CLASS_BRIDGE_PCI << 8; | 52 | dev->class = PCI_CLASS_BRIDGE_PCI << 8; |
46 | fsl_pcie_bus_fixup = 1; | 53 | fsl_pcie_bus_fixup = 1; |
47 | return; | 54 | return; |
@@ -323,6 +330,7 @@ int __init fsl_add_bridge(struct device_node *dev, int is_primary) | |||
323 | struct pci_controller *hose; | 330 | struct pci_controller *hose; |
324 | struct resource rsrc; | 331 | struct resource rsrc; |
325 | const int *bus_range; | 332 | const int *bus_range; |
333 | u8 progif; | ||
326 | 334 | ||
327 | if (!of_device_is_available(dev)) { | 335 | if (!of_device_is_available(dev)) { |
328 | pr_warning("%s: disabled\n", dev->full_name); | 336 | pr_warning("%s: disabled\n", dev->full_name); |
@@ -353,6 +361,18 @@ int __init fsl_add_bridge(struct device_node *dev, int is_primary) | |||
353 | 361 | ||
354 | setup_indirect_pci(hose, rsrc.start, rsrc.start + 0x4, | 362 | setup_indirect_pci(hose, rsrc.start, rsrc.start + 0x4, |
355 | PPC_INDIRECT_TYPE_BIG_ENDIAN); | 363 | PPC_INDIRECT_TYPE_BIG_ENDIAN); |
364 | |||
365 | early_read_config_byte(hose, 0, 0, PCI_CLASS_PROG, &progif); | ||
366 | if ((progif & 1) == 1) { | ||
367 | /* unmap cfg_data & cfg_addr separately if not on same page */ | ||
368 | if (((unsigned long)hose->cfg_data & PAGE_MASK) != | ||
369 | ((unsigned long)hose->cfg_addr & PAGE_MASK)) | ||
370 | iounmap(hose->cfg_data); | ||
371 | iounmap(hose->cfg_addr); | ||
372 | pcibios_free_controller(hose); | ||
373 | return 0; | ||
374 | } | ||
375 | |||
356 | setup_pci_cmd(hose); | 376 | setup_pci_cmd(hose); |
357 | 377 | ||
358 | /* check PCI express link status */ | 378 | /* check PCI express link status */ |
@@ -380,70 +400,11 @@ int __init fsl_add_bridge(struct device_node *dev, int is_primary) | |||
380 | 400 | ||
381 | return 0; | 401 | return 0; |
382 | } | 402 | } |
383 | |||
384 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8548E, quirk_fsl_pcie_header); | ||
385 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8548, quirk_fsl_pcie_header); | ||
386 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8543E, quirk_fsl_pcie_header); | ||
387 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8543, quirk_fsl_pcie_header); | ||
388 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8547E, quirk_fsl_pcie_header); | ||
389 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8545E, quirk_fsl_pcie_header); | ||
390 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8545, quirk_fsl_pcie_header); | ||
391 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8569E, quirk_fsl_pcie_header); | ||
392 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8569, quirk_fsl_pcie_header); | ||
393 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8568E, quirk_fsl_pcie_header); | ||
394 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8568, quirk_fsl_pcie_header); | ||
395 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8567E, quirk_fsl_pcie_header); | ||
396 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8567, quirk_fsl_pcie_header); | ||
397 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8533E, quirk_fsl_pcie_header); | ||
398 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8533, quirk_fsl_pcie_header); | ||
399 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8544E, quirk_fsl_pcie_header); | ||
400 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8544, quirk_fsl_pcie_header); | ||
401 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8572E, quirk_fsl_pcie_header); | ||
402 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8572, quirk_fsl_pcie_header); | ||
403 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8536E, quirk_fsl_pcie_header); | ||
404 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8536, quirk_fsl_pcie_header); | ||
405 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8641, quirk_fsl_pcie_header); | ||
406 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8641D, quirk_fsl_pcie_header); | ||
407 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8610, quirk_fsl_pcie_header); | ||
408 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P1011E, quirk_fsl_pcie_header); | ||
409 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P1011, quirk_fsl_pcie_header); | ||
410 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P1013E, quirk_fsl_pcie_header); | ||
411 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P1013, quirk_fsl_pcie_header); | ||
412 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P1020E, quirk_fsl_pcie_header); | ||
413 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P1020, quirk_fsl_pcie_header); | ||
414 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P1021E, quirk_fsl_pcie_header); | ||
415 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P1021, quirk_fsl_pcie_header); | ||
416 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P1022E, quirk_fsl_pcie_header); | ||
417 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P1022, quirk_fsl_pcie_header); | ||
418 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P2010E, quirk_fsl_pcie_header); | ||
419 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P2010, quirk_fsl_pcie_header); | ||
420 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P2020E, quirk_fsl_pcie_header); | ||
421 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P2020, quirk_fsl_pcie_header); | ||
422 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P2040E, quirk_fsl_pcie_header); | ||
423 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P2040, quirk_fsl_pcie_header); | ||
424 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P3041E, quirk_fsl_pcie_header); | ||
425 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P3041, quirk_fsl_pcie_header); | ||
426 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P4040E, quirk_fsl_pcie_header); | ||
427 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P4040, quirk_fsl_pcie_header); | ||
428 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P4080E, quirk_fsl_pcie_header); | ||
429 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P4080, quirk_fsl_pcie_header); | ||
430 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P5010E, quirk_fsl_pcie_header); | ||
431 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P5010, quirk_fsl_pcie_header); | ||
432 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P5020E, quirk_fsl_pcie_header); | ||
433 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_P5020, quirk_fsl_pcie_header); | ||
434 | #endif /* CONFIG_FSL_SOC_BOOKE || CONFIG_PPC_86xx */ | 403 | #endif /* CONFIG_FSL_SOC_BOOKE || CONFIG_PPC_86xx */ |
435 | 404 | ||
436 | #if defined(CONFIG_PPC_83xx) || defined(CONFIG_PPC_MPC512x) | 405 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_FREESCALE, PCI_ANY_ID, quirk_fsl_pcie_header); |
437 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8308, quirk_fsl_pcie_header); | ||
438 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8314E, quirk_fsl_pcie_header); | ||
439 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8314, quirk_fsl_pcie_header); | ||
440 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8315E, quirk_fsl_pcie_header); | ||
441 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8315, quirk_fsl_pcie_header); | ||
442 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8377E, quirk_fsl_pcie_header); | ||
443 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8377, quirk_fsl_pcie_header); | ||
444 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8378E, quirk_fsl_pcie_header); | ||
445 | DECLARE_PCI_FIXUP_HEADER(0x1957, PCI_DEVICE_ID_MPC8378, quirk_fsl_pcie_header); | ||
446 | 406 | ||
407 | #if defined(CONFIG_PPC_83xx) || defined(CONFIG_PPC_MPC512x) | ||
447 | struct mpc83xx_pcie_priv { | 408 | struct mpc83xx_pcie_priv { |
448 | void __iomem *cfg_type0; | 409 | void __iomem *cfg_type0; |
449 | void __iomem *cfg_type1; | 410 | void __iomem *cfg_type1; |
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c index 19e5015e039b..265313e8396b 100644 --- a/arch/powerpc/sysdev/fsl_soc.c +++ b/arch/powerpc/sysdev/fsl_soc.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include <sysdev/fsl_soc.h> | 41 | #include <sysdev/fsl_soc.h> |
42 | #include <mm/mmu_decl.h> | 42 | #include <mm/mmu_decl.h> |
43 | #include <asm/cpm2.h> | 43 | #include <asm/cpm2.h> |
44 | #include <asm/fsl_hcalls.h> /* For the Freescale hypervisor */ | ||
44 | 45 | ||
45 | extern void init_fcc_ioports(struct fs_platform_info*); | 46 | extern void init_fcc_ioports(struct fs_platform_info*); |
46 | extern void init_fec_ioports(struct fs_platform_info*); | 47 | extern void init_fec_ioports(struct fs_platform_info*); |
@@ -252,3 +253,29 @@ void fsl_rstcr_restart(char *cmd) | |||
252 | struct platform_diu_data_ops diu_ops; | 253 | struct platform_diu_data_ops diu_ops; |
253 | EXPORT_SYMBOL(diu_ops); | 254 | EXPORT_SYMBOL(diu_ops); |
254 | #endif | 255 | #endif |
256 | |||
257 | /* | ||
258 | * Restart the current partition | ||
259 | * | ||
260 | * This function should be assigned to the ppc_md.restart function pointer, | ||
261 | * to initiate a partition restart when we're running under the Freescale | ||
262 | * hypervisor. | ||
263 | */ | ||
264 | void fsl_hv_restart(char *cmd) | ||
265 | { | ||
266 | pr_info("hv restart\n"); | ||
267 | fh_partition_restart(-1); | ||
268 | } | ||
269 | |||
270 | /* | ||
271 | * Halt the current partition | ||
272 | * | ||
273 | * This function should be assigned to the ppc_md.power_off and ppc_md.halt | ||
274 | * function pointers, to shut down the partition when we're running under | ||
275 | * the Freescale hypervisor. | ||
276 | */ | ||
277 | void fsl_hv_halt(void) | ||
278 | { | ||
279 | pr_info("hv exit\n"); | ||
280 | fh_partition_stop(-1); | ||
281 | } | ||
diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h index 53609489a62b..2ece02beb8ff 100644 --- a/arch/powerpc/sysdev/fsl_soc.h +++ b/arch/powerpc/sysdev/fsl_soc.h | |||
@@ -36,5 +36,8 @@ struct platform_diu_data_ops { | |||
36 | extern struct platform_diu_data_ops diu_ops; | 36 | extern struct platform_diu_data_ops diu_ops; |
37 | #endif | 37 | #endif |
38 | 38 | ||
39 | void fsl_hv_restart(char *cmd); | ||
40 | void fsl_hv_halt(void); | ||
41 | |||
39 | #endif | 42 | #endif |
40 | #endif | 43 | #endif |
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index 58d7a534f877..d5d3ff3d757e 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c | |||
@@ -598,42 +598,6 @@ static void __init mpic_scan_ht_pics(struct mpic *mpic) | |||
598 | 598 | ||
599 | #endif /* CONFIG_MPIC_U3_HT_IRQS */ | 599 | #endif /* CONFIG_MPIC_U3_HT_IRQS */ |
600 | 600 | ||
601 | #ifdef CONFIG_SMP | ||
602 | static int irq_choose_cpu(const struct cpumask *mask) | ||
603 | { | ||
604 | int cpuid; | ||
605 | |||
606 | if (cpumask_equal(mask, cpu_all_mask)) { | ||
607 | static int irq_rover = 0; | ||
608 | static DEFINE_RAW_SPINLOCK(irq_rover_lock); | ||
609 | unsigned long flags; | ||
610 | |||
611 | /* Round-robin distribution... */ | ||
612 | do_round_robin: | ||
613 | raw_spin_lock_irqsave(&irq_rover_lock, flags); | ||
614 | |||
615 | irq_rover = cpumask_next(irq_rover, cpu_online_mask); | ||
616 | if (irq_rover >= nr_cpu_ids) | ||
617 | irq_rover = cpumask_first(cpu_online_mask); | ||
618 | |||
619 | cpuid = irq_rover; | ||
620 | |||
621 | raw_spin_unlock_irqrestore(&irq_rover_lock, flags); | ||
622 | } else { | ||
623 | cpuid = cpumask_first_and(mask, cpu_online_mask); | ||
624 | if (cpuid >= nr_cpu_ids) | ||
625 | goto do_round_robin; | ||
626 | } | ||
627 | |||
628 | return get_hard_smp_processor_id(cpuid); | ||
629 | } | ||
630 | #else | ||
631 | static int irq_choose_cpu(const struct cpumask *mask) | ||
632 | { | ||
633 | return hard_smp_processor_id(); | ||
634 | } | ||
635 | #endif | ||
636 | |||
637 | /* Find an mpic associated with a given linux interrupt */ | 601 | /* Find an mpic associated with a given linux interrupt */ |
638 | static struct mpic *mpic_find(unsigned int irq) | 602 | static struct mpic *mpic_find(unsigned int irq) |
639 | { | 603 | { |
@@ -849,7 +813,7 @@ static void mpic_unmask_tm(struct irq_data *d) | |||
849 | struct mpic *mpic = mpic_from_irq_data(d); | 813 | struct mpic *mpic = mpic_from_irq_data(d); |
850 | unsigned int src = virq_to_hw(d->irq) - mpic->timer_vecs[0]; | 814 | unsigned int src = virq_to_hw(d->irq) - mpic->timer_vecs[0]; |
851 | 815 | ||
852 | DBG("%s: enable_tm: %d (tm %d)\n", mpic->name, irq, src); | 816 | DBG("%s: enable_tm: %d (tm %d)\n", mpic->name, d->irq, src); |
853 | mpic_tm_write(src, mpic_tm_read(src) & ~MPIC_VECPRI_MASK); | 817 | mpic_tm_write(src, mpic_tm_read(src) & ~MPIC_VECPRI_MASK); |
854 | mpic_tm_read(src); | 818 | mpic_tm_read(src); |
855 | } | 819 | } |
diff --git a/arch/powerpc/sysdev/ppc4xx_pci.c b/arch/powerpc/sysdev/ppc4xx_pci.c index deda60a7f996..2ec4f3bb8160 100644 --- a/arch/powerpc/sysdev/ppc4xx_pci.c +++ b/arch/powerpc/sysdev/ppc4xx_pci.c | |||
@@ -650,12 +650,74 @@ struct ppc4xx_pciex_hwops | |||
650 | int (*core_init)(struct device_node *np); | 650 | int (*core_init)(struct device_node *np); |
651 | int (*port_init_hw)(struct ppc4xx_pciex_port *port); | 651 | int (*port_init_hw)(struct ppc4xx_pciex_port *port); |
652 | int (*setup_utl)(struct ppc4xx_pciex_port *port); | 652 | int (*setup_utl)(struct ppc4xx_pciex_port *port); |
653 | void (*check_link)(struct ppc4xx_pciex_port *port); | ||
653 | }; | 654 | }; |
654 | 655 | ||
655 | static struct ppc4xx_pciex_hwops *ppc4xx_pciex_hwops; | 656 | static struct ppc4xx_pciex_hwops *ppc4xx_pciex_hwops; |
656 | 657 | ||
657 | #ifdef CONFIG_44x | 658 | #ifdef CONFIG_44x |
658 | 659 | ||
660 | static int __init ppc4xx_pciex_wait_on_sdr(struct ppc4xx_pciex_port *port, | ||
661 | unsigned int sdr_offset, | ||
662 | unsigned int mask, | ||
663 | unsigned int value, | ||
664 | int timeout_ms) | ||
665 | { | ||
666 | u32 val; | ||
667 | |||
668 | while(timeout_ms--) { | ||
669 | val = mfdcri(SDR0, port->sdr_base + sdr_offset); | ||
670 | if ((val & mask) == value) { | ||
671 | pr_debug("PCIE%d: Wait on SDR %x success with tm %d (%08x)\n", | ||
672 | port->index, sdr_offset, timeout_ms, val); | ||
673 | return 0; | ||
674 | } | ||
675 | msleep(1); | ||
676 | } | ||
677 | return -1; | ||
678 | } | ||
679 | |||
680 | static int __init ppc4xx_pciex_port_reset_sdr(struct ppc4xx_pciex_port *port) | ||
681 | { | ||
682 | /* Wait for reset to complete */ | ||
683 | if (ppc4xx_pciex_wait_on_sdr(port, PESDRn_RCSSTS, 1 << 20, 0, 10)) { | ||
684 | printk(KERN_WARNING "PCIE%d: PGRST failed\n", | ||
685 | port->index); | ||
686 | return -1; | ||
687 | } | ||
688 | return 0; | ||
689 | } | ||
690 | |||
691 | static void __init ppc4xx_pciex_check_link_sdr(struct ppc4xx_pciex_port *port) | ||
692 | { | ||
693 | printk(KERN_INFO "PCIE%d: Checking link...\n", port->index); | ||
694 | |||
695 | /* Check for card presence detect if supported, if not, just wait for | ||
696 | * link unconditionally. | ||
697 | * | ||
698 | * note that we don't fail if there is no link, we just filter out | ||
699 | * config space accesses. That way, it will be easier to implement | ||
700 | * hotplug later on. | ||
701 | */ | ||
702 | if (!port->has_ibpre || | ||
703 | !ppc4xx_pciex_wait_on_sdr(port, PESDRn_LOOP, | ||
704 | 1 << 28, 1 << 28, 100)) { | ||
705 | printk(KERN_INFO | ||
706 | "PCIE%d: Device detected, waiting for link...\n", | ||
707 | port->index); | ||
708 | if (ppc4xx_pciex_wait_on_sdr(port, PESDRn_LOOP, | ||
709 | 0x1000, 0x1000, 2000)) | ||
710 | printk(KERN_WARNING | ||
711 | "PCIE%d: Link up failed\n", port->index); | ||
712 | else { | ||
713 | printk(KERN_INFO | ||
714 | "PCIE%d: link is up !\n", port->index); | ||
715 | port->link = 1; | ||
716 | } | ||
717 | } else | ||
718 | printk(KERN_INFO "PCIE%d: No device detected.\n", port->index); | ||
719 | } | ||
720 | |||
659 | /* Check various reset bits of the 440SPe PCIe core */ | 721 | /* Check various reset bits of the 440SPe PCIe core */ |
660 | static int __init ppc440spe_pciex_check_reset(struct device_node *np) | 722 | static int __init ppc440spe_pciex_check_reset(struct device_node *np) |
661 | { | 723 | { |
@@ -806,7 +868,7 @@ static int ppc440spe_pciex_init_port_hw(struct ppc4xx_pciex_port *port) | |||
806 | dcri_clrset(SDR0, port->sdr_base + PESDRn_RCSSET, | 868 | dcri_clrset(SDR0, port->sdr_base + PESDRn_RCSSET, |
807 | (1 << 24) | (1 << 16), 1 << 12); | 869 | (1 << 24) | (1 << 16), 1 << 12); |
808 | 870 | ||
809 | return 0; | 871 | return ppc4xx_pciex_port_reset_sdr(port); |
810 | } | 872 | } |
811 | 873 | ||
812 | static int ppc440speA_pciex_init_port_hw(struct ppc4xx_pciex_port *port) | 874 | static int ppc440speA_pciex_init_port_hw(struct ppc4xx_pciex_port *port) |
@@ -856,6 +918,7 @@ static struct ppc4xx_pciex_hwops ppc440speA_pcie_hwops __initdata = | |||
856 | .core_init = ppc440spe_pciex_core_init, | 918 | .core_init = ppc440spe_pciex_core_init, |
857 | .port_init_hw = ppc440speA_pciex_init_port_hw, | 919 | .port_init_hw = ppc440speA_pciex_init_port_hw, |
858 | .setup_utl = ppc440speA_pciex_init_utl, | 920 | .setup_utl = ppc440speA_pciex_init_utl, |
921 | .check_link = ppc4xx_pciex_check_link_sdr, | ||
859 | }; | 922 | }; |
860 | 923 | ||
861 | static struct ppc4xx_pciex_hwops ppc440speB_pcie_hwops __initdata = | 924 | static struct ppc4xx_pciex_hwops ppc440speB_pcie_hwops __initdata = |
@@ -863,6 +926,7 @@ static struct ppc4xx_pciex_hwops ppc440speB_pcie_hwops __initdata = | |||
863 | .core_init = ppc440spe_pciex_core_init, | 926 | .core_init = ppc440spe_pciex_core_init, |
864 | .port_init_hw = ppc440speB_pciex_init_port_hw, | 927 | .port_init_hw = ppc440speB_pciex_init_port_hw, |
865 | .setup_utl = ppc440speB_pciex_init_utl, | 928 | .setup_utl = ppc440speB_pciex_init_utl, |
929 | .check_link = ppc4xx_pciex_check_link_sdr, | ||
866 | }; | 930 | }; |
867 | 931 | ||
868 | static int __init ppc460ex_pciex_core_init(struct device_node *np) | 932 | static int __init ppc460ex_pciex_core_init(struct device_node *np) |
@@ -944,7 +1008,7 @@ static int ppc460ex_pciex_init_port_hw(struct ppc4xx_pciex_port *port) | |||
944 | 1008 | ||
945 | port->has_ibpre = 1; | 1009 | port->has_ibpre = 1; |
946 | 1010 | ||
947 | return 0; | 1011 | return ppc4xx_pciex_port_reset_sdr(port); |
948 | } | 1012 | } |
949 | 1013 | ||
950 | static int ppc460ex_pciex_init_utl(struct ppc4xx_pciex_port *port) | 1014 | static int ppc460ex_pciex_init_utl(struct ppc4xx_pciex_port *port) |
@@ -972,6 +1036,7 @@ static struct ppc4xx_pciex_hwops ppc460ex_pcie_hwops __initdata = | |||
972 | .core_init = ppc460ex_pciex_core_init, | 1036 | .core_init = ppc460ex_pciex_core_init, |
973 | .port_init_hw = ppc460ex_pciex_init_port_hw, | 1037 | .port_init_hw = ppc460ex_pciex_init_port_hw, |
974 | .setup_utl = ppc460ex_pciex_init_utl, | 1038 | .setup_utl = ppc460ex_pciex_init_utl, |
1039 | .check_link = ppc4xx_pciex_check_link_sdr, | ||
975 | }; | 1040 | }; |
976 | 1041 | ||
977 | static int __init ppc460sx_pciex_core_init(struct device_node *np) | 1042 | static int __init ppc460sx_pciex_core_init(struct device_node *np) |
@@ -1075,7 +1140,7 @@ static int ppc460sx_pciex_init_port_hw(struct ppc4xx_pciex_port *port) | |||
1075 | 1140 | ||
1076 | port->has_ibpre = 1; | 1141 | port->has_ibpre = 1; |
1077 | 1142 | ||
1078 | return 0; | 1143 | return ppc4xx_pciex_port_reset_sdr(port); |
1079 | } | 1144 | } |
1080 | 1145 | ||
1081 | static int ppc460sx_pciex_init_utl(struct ppc4xx_pciex_port *port) | 1146 | static int ppc460sx_pciex_init_utl(struct ppc4xx_pciex_port *port) |
@@ -1089,6 +1154,7 @@ static struct ppc4xx_pciex_hwops ppc460sx_pcie_hwops __initdata = { | |||
1089 | .core_init = ppc460sx_pciex_core_init, | 1154 | .core_init = ppc460sx_pciex_core_init, |
1090 | .port_init_hw = ppc460sx_pciex_init_port_hw, | 1155 | .port_init_hw = ppc460sx_pciex_init_port_hw, |
1091 | .setup_utl = ppc460sx_pciex_init_utl, | 1156 | .setup_utl = ppc460sx_pciex_init_utl, |
1157 | .check_link = ppc4xx_pciex_check_link_sdr, | ||
1092 | }; | 1158 | }; |
1093 | 1159 | ||
1094 | #endif /* CONFIG_44x */ | 1160 | #endif /* CONFIG_44x */ |
@@ -1154,7 +1220,7 @@ static int ppc405ex_pciex_init_port_hw(struct ppc4xx_pciex_port *port) | |||
1154 | 1220 | ||
1155 | port->has_ibpre = 1; | 1221 | port->has_ibpre = 1; |
1156 | 1222 | ||
1157 | return 0; | 1223 | return ppc4xx_pciex_port_reset_sdr(port); |
1158 | } | 1224 | } |
1159 | 1225 | ||
1160 | static int ppc405ex_pciex_init_utl(struct ppc4xx_pciex_port *port) | 1226 | static int ppc405ex_pciex_init_utl(struct ppc4xx_pciex_port *port) |
@@ -1183,11 +1249,11 @@ static struct ppc4xx_pciex_hwops ppc405ex_pcie_hwops __initdata = | |||
1183 | .core_init = ppc405ex_pciex_core_init, | 1249 | .core_init = ppc405ex_pciex_core_init, |
1184 | .port_init_hw = ppc405ex_pciex_init_port_hw, | 1250 | .port_init_hw = ppc405ex_pciex_init_port_hw, |
1185 | .setup_utl = ppc405ex_pciex_init_utl, | 1251 | .setup_utl = ppc405ex_pciex_init_utl, |
1252 | .check_link = ppc4xx_pciex_check_link_sdr, | ||
1186 | }; | 1253 | }; |
1187 | 1254 | ||
1188 | #endif /* CONFIG_40x */ | 1255 | #endif /* CONFIG_40x */ |
1189 | 1256 | ||
1190 | |||
1191 | /* Check that the core has been initied and if not, do it */ | 1257 | /* Check that the core has been initied and if not, do it */ |
1192 | static int __init ppc4xx_pciex_check_core_init(struct device_node *np) | 1258 | static int __init ppc4xx_pciex_check_core_init(struct device_node *np) |
1193 | { | 1259 | { |
@@ -1261,26 +1327,6 @@ static void __init ppc4xx_pciex_port_init_mapping(struct ppc4xx_pciex_port *port | |||
1261 | dcr_write(port->dcrs, DCRO_PEGPL_MSGMSK, 0); | 1327 | dcr_write(port->dcrs, DCRO_PEGPL_MSGMSK, 0); |
1262 | } | 1328 | } |
1263 | 1329 | ||
1264 | static int __init ppc4xx_pciex_wait_on_sdr(struct ppc4xx_pciex_port *port, | ||
1265 | unsigned int sdr_offset, | ||
1266 | unsigned int mask, | ||
1267 | unsigned int value, | ||
1268 | int timeout_ms) | ||
1269 | { | ||
1270 | u32 val; | ||
1271 | |||
1272 | while(timeout_ms--) { | ||
1273 | val = mfdcri(SDR0, port->sdr_base + sdr_offset); | ||
1274 | if ((val & mask) == value) { | ||
1275 | pr_debug("PCIE%d: Wait on SDR %x success with tm %d (%08x)\n", | ||
1276 | port->index, sdr_offset, timeout_ms, val); | ||
1277 | return 0; | ||
1278 | } | ||
1279 | msleep(1); | ||
1280 | } | ||
1281 | return -1; | ||
1282 | } | ||
1283 | |||
1284 | static int __init ppc4xx_pciex_port_init(struct ppc4xx_pciex_port *port) | 1330 | static int __init ppc4xx_pciex_port_init(struct ppc4xx_pciex_port *port) |
1285 | { | 1331 | { |
1286 | int rc = 0; | 1332 | int rc = 0; |
@@ -1291,40 +1337,8 @@ static int __init ppc4xx_pciex_port_init(struct ppc4xx_pciex_port *port) | |||
1291 | if (rc != 0) | 1337 | if (rc != 0) |
1292 | return rc; | 1338 | return rc; |
1293 | 1339 | ||
1294 | printk(KERN_INFO "PCIE%d: Checking link...\n", | 1340 | if (ppc4xx_pciex_hwops->check_link) |
1295 | port->index); | 1341 | ppc4xx_pciex_hwops->check_link(port); |
1296 | |||
1297 | /* Wait for reset to complete */ | ||
1298 | if (ppc4xx_pciex_wait_on_sdr(port, PESDRn_RCSSTS, 1 << 20, 0, 10)) { | ||
1299 | printk(KERN_WARNING "PCIE%d: PGRST failed\n", | ||
1300 | port->index); | ||
1301 | return -1; | ||
1302 | } | ||
1303 | |||
1304 | /* Check for card presence detect if supported, if not, just wait for | ||
1305 | * link unconditionally. | ||
1306 | * | ||
1307 | * note that we don't fail if there is no link, we just filter out | ||
1308 | * config space accesses. That way, it will be easier to implement | ||
1309 | * hotplug later on. | ||
1310 | */ | ||
1311 | if (!port->has_ibpre || | ||
1312 | !ppc4xx_pciex_wait_on_sdr(port, PESDRn_LOOP, | ||
1313 | 1 << 28, 1 << 28, 100)) { | ||
1314 | printk(KERN_INFO | ||
1315 | "PCIE%d: Device detected, waiting for link...\n", | ||
1316 | port->index); | ||
1317 | if (ppc4xx_pciex_wait_on_sdr(port, PESDRn_LOOP, | ||
1318 | 0x1000, 0x1000, 2000)) | ||
1319 | printk(KERN_WARNING | ||
1320 | "PCIE%d: Link up failed\n", port->index); | ||
1321 | else { | ||
1322 | printk(KERN_INFO | ||
1323 | "PCIE%d: link is up !\n", port->index); | ||
1324 | port->link = 1; | ||
1325 | } | ||
1326 | } else | ||
1327 | printk(KERN_INFO "PCIE%d: No device detected.\n", port->index); | ||
1328 | 1342 | ||
1329 | /* | 1343 | /* |
1330 | * Initialize mapping: disable all regions and configure | 1344 | * Initialize mapping: disable all regions and configure |
@@ -1347,14 +1361,17 @@ static int __init ppc4xx_pciex_port_init(struct ppc4xx_pciex_port *port) | |||
1347 | /* | 1361 | /* |
1348 | * Check for VC0 active and assert RDY. | 1362 | * Check for VC0 active and assert RDY. |
1349 | */ | 1363 | */ |
1350 | if (port->link && | 1364 | if (port->sdr_base) { |
1351 | ppc4xx_pciex_wait_on_sdr(port, PESDRn_RCSSTS, | 1365 | if (port->link && |
1352 | 1 << 16, 1 << 16, 5000)) { | 1366 | ppc4xx_pciex_wait_on_sdr(port, PESDRn_RCSSTS, |
1353 | printk(KERN_INFO "PCIE%d: VC0 not active\n", port->index); | 1367 | 1 << 16, 1 << 16, 5000)) { |
1354 | port->link = 0; | 1368 | printk(KERN_INFO "PCIE%d: VC0 not active\n", port->index); |
1369 | port->link = 0; | ||
1370 | } | ||
1371 | |||
1372 | dcri_clrset(SDR0, port->sdr_base + PESDRn_RCSSET, 0, 1 << 20); | ||
1355 | } | 1373 | } |
1356 | 1374 | ||
1357 | dcri_clrset(SDR0, port->sdr_base + PESDRn_RCSSET, 0, 1 << 20); | ||
1358 | msleep(100); | 1375 | msleep(100); |
1359 | 1376 | ||
1360 | return 0; | 1377 | return 0; |