diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-01-30 21:37:27 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-01-30 21:37:27 -0500 |
commit | 8af03e782cae1e0a0f530ddd22301cdd12cf9dc0 (patch) | |
tree | c4af13a38bd3cc1a811a37f2358491f171052070 /arch/powerpc/platforms | |
parent | 6232665040f9a23fafd9d94d4ae8d5a2dc850f65 (diff) | |
parent | 99e139126ab2e84be67969650f92eb37c12ab5cd (diff) |
Merge branch 'for-2.6.25' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc
* 'for-2.6.25' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc: (454 commits)
[POWERPC] Cell IOMMU fixed mapping support
[POWERPC] Split out the ioid fetching/checking logic
[POWERPC] Add support to cell_iommu_setup_page_tables() for multiple windows
[POWERPC] Split out the IOMMU logic from cell_dma_dev_setup()
[POWERPC] Split cell_iommu_setup_hardware() into two parts
[POWERPC] Split out the logic that allocates struct iommus
[POWERPC] Allocate the hash table under 1G on cell
[POWERPC] Add set_dma_ops() to match get_dma_ops()
[POWERPC] 83xx: Clean up / convert mpc83xx board DTS files to v1 format.
[POWERPC] 85xx: Only invalidate TLB0 and TLB1
[POWERPC] 83xx: Fix typo in mpc837x compatible entries
[POWERPC] 85xx: convert sbc85* boards to use machine_device_initcall
[POWERPC] 83xx: rework platform Kconfig
[POWERPC] 85xx: rework platform Kconfig
[POWERPC] 86xx: Remove unused IRQ defines
[POWERPC] QE: Explicitly set address-cells and size cells for muram
[POWERPC] Convert StorCenter DTS file to /dts-v1/ format.
[POWERPC] 86xx: Convert all 86xx DTS files to /dts-v1/ format.
[PPC] Remove 85xx from arch/ppc
[PPC] Remove 83xx from arch/ppc
...
Diffstat (limited to 'arch/powerpc/platforms')
151 files changed, 6576 insertions, 2719 deletions
diff --git a/arch/powerpc/platforms/40x/Kconfig b/arch/powerpc/platforms/40x/Kconfig index 8f6699fcc145..74f31177e47a 100644 --- a/arch/powerpc/platforms/40x/Kconfig +++ b/arch/powerpc/platforms/40x/Kconfig | |||
@@ -14,28 +14,34 @@ | |||
14 | # help | 14 | # help |
15 | # This option enables support for the CPCI405 board. | 15 | # This option enables support for the CPCI405 board. |
16 | 16 | ||
17 | #config EP405 | 17 | config EP405 |
18 | # bool "EP405/EP405PC" | 18 | bool "EP405/EP405PC" |
19 | # depends on 40x | 19 | depends on 40x |
20 | # default n | 20 | default n |
21 | # select 405GP | 21 | select 405GP |
22 | # help | 22 | select PCI |
23 | # This option enables support for the EP405/EP405PC boards. | 23 | help |
24 | 24 | This option enables support for the EP405/EP405PC boards. | |
25 | #config EP405PC | ||
26 | # bool "EP405PC Support" | ||
27 | # depends on EP405 | ||
28 | # default y | ||
29 | # help | ||
30 | # This option enables support for the extra features of the EP405PC board. | ||
31 | 25 | ||
32 | config KILAUEA | 26 | config KILAUEA |
33 | bool "Kilauea" | 27 | bool "Kilauea" |
34 | depends on 40x | 28 | depends on 40x |
35 | default n | 29 | default n |
30 | select 405EX | ||
31 | select PPC4xx_PCI_EXPRESS | ||
36 | help | 32 | help |
37 | This option enables support for the AMCC PPC405EX evaluation board. | 33 | This option enables support for the AMCC PPC405EX evaluation board. |
38 | 34 | ||
35 | config MAKALU | ||
36 | bool "Makalu" | ||
37 | depends on 40x | ||
38 | default n | ||
39 | select 405EX | ||
40 | select PCI | ||
41 | select PPC4xx_PCI_EXPRESS | ||
42 | help | ||
43 | This option enables support for the AMCC PPC405EX board. | ||
44 | |||
39 | #config REDWOOD_5 | 45 | #config REDWOOD_5 |
40 | # bool "Redwood-5" | 46 | # bool "Redwood-5" |
41 | # depends on 40x | 47 | # depends on 40x |
@@ -65,6 +71,7 @@ config WALNUT | |||
65 | depends on 40x | 71 | depends on 40x |
66 | default y | 72 | default y |
67 | select 405GP | 73 | select 405GP |
74 | select PCI | ||
68 | help | 75 | help |
69 | This option enables support for the IBM PPC405GP evaluation board. | 76 | This option enables support for the IBM PPC405GP evaluation board. |
70 | 77 | ||
@@ -105,6 +112,11 @@ config 405GP | |||
105 | config 405EP | 112 | config 405EP |
106 | bool | 113 | bool |
107 | 114 | ||
115 | config 405EX | ||
116 | bool | ||
117 | select IBM_NEW_EMAC_EMAC4 | ||
118 | select IBM_NEW_EMAC_RGMII | ||
119 | |||
108 | config 405GPR | 120 | config 405GPR |
109 | bool | 121 | bool |
110 | 122 | ||
diff --git a/arch/powerpc/platforms/40x/Makefile b/arch/powerpc/platforms/40x/Makefile index 51dadeee6fc6..5533a5c8ce4e 100644 --- a/arch/powerpc/platforms/40x/Makefile +++ b/arch/powerpc/platforms/40x/Makefile | |||
@@ -1,3 +1,5 @@ | |||
1 | obj-$(CONFIG_KILAUEA) += kilauea.o | 1 | obj-$(CONFIG_KILAUEA) += kilauea.o |
2 | obj-$(CONFIG_MAKALU) += makalu.o | ||
2 | obj-$(CONFIG_WALNUT) += walnut.o | 3 | obj-$(CONFIG_WALNUT) += walnut.o |
3 | obj-$(CONFIG_XILINX_VIRTEX_GENERIC_BOARD) += virtex.o | 4 | obj-$(CONFIG_XILINX_VIRTEX_GENERIC_BOARD) += virtex.o |
5 | obj-$(CONFIG_EP405) += ep405.o | ||
diff --git a/arch/powerpc/platforms/40x/ep405.c b/arch/powerpc/platforms/40x/ep405.c new file mode 100644 index 000000000000..13d1345026da --- /dev/null +++ b/arch/powerpc/platforms/40x/ep405.c | |||
@@ -0,0 +1,123 @@ | |||
1 | /* | ||
2 | * Architecture- / platform-specific boot-time initialization code for | ||
3 | * IBM PowerPC 4xx based boards. Adapted from original | ||
4 | * code by Gary Thomas, Cort Dougan <cort@fsmlabs.com>, and Dan Malek | ||
5 | * <dan@net4x.com>. | ||
6 | * | ||
7 | * Copyright(c) 1999-2000 Grant Erickson <grant@lcse.umn.edu> | ||
8 | * | ||
9 | * Rewritten and ported to the merged powerpc tree: | ||
10 | * Copyright 2007 IBM Corporation | ||
11 | * Josh Boyer <jwboyer@linux.vnet.ibm.com> | ||
12 | * | ||
13 | * Adapted to EP405 by Ben. Herrenschmidt <benh@kernel.crashing.org> | ||
14 | * | ||
15 | * TODO: Wire up the PCI IRQ mux and the southbridge interrupts | ||
16 | * | ||
17 | * 2002 (c) MontaVista, Software, Inc. This file is licensed under | ||
18 | * the terms of the GNU General Public License version 2. This program | ||
19 | * is licensed "as is" without any warranty of any kind, whether express | ||
20 | * or implied. | ||
21 | */ | ||
22 | |||
23 | #include <linux/init.h> | ||
24 | #include <linux/of_platform.h> | ||
25 | |||
26 | #include <asm/machdep.h> | ||
27 | #include <asm/prom.h> | ||
28 | #include <asm/udbg.h> | ||
29 | #include <asm/time.h> | ||
30 | #include <asm/uic.h> | ||
31 | #include <asm/pci-bridge.h> | ||
32 | |||
33 | static struct device_node *bcsr_node; | ||
34 | static void __iomem *bcsr_regs; | ||
35 | |||
36 | /* BCSR registers */ | ||
37 | #define BCSR_ID 0 | ||
38 | #define BCSR_PCI_CTRL 1 | ||
39 | #define BCSR_FLASH_NV_POR_CTRL 2 | ||
40 | #define BCSR_FENET_UART_CTRL 3 | ||
41 | #define BCSR_PCI_IRQ 4 | ||
42 | #define BCSR_XIRQ_SELECT 5 | ||
43 | #define BCSR_XIRQ_ROUTING 6 | ||
44 | #define BCSR_XIRQ_STATUS 7 | ||
45 | #define BCSR_XIRQ_STATUS2 8 | ||
46 | #define BCSR_SW_STAT_LED_CTRL 9 | ||
47 | #define BCSR_GPIO_IRQ_PAR_CTRL 10 | ||
48 | /* there's more, can't be bothered typing them tho */ | ||
49 | |||
50 | |||
51 | static __initdata struct of_device_id ep405_of_bus[] = { | ||
52 | { .compatible = "ibm,plb3", }, | ||
53 | { .compatible = "ibm,opb", }, | ||
54 | { .compatible = "ibm,ebc", }, | ||
55 | {}, | ||
56 | }; | ||
57 | |||
58 | static int __init ep405_device_probe(void) | ||
59 | { | ||
60 | of_platform_bus_probe(NULL, ep405_of_bus, NULL); | ||
61 | |||
62 | return 0; | ||
63 | } | ||
64 | machine_device_initcall(ep405, ep405_device_probe); | ||
65 | |||
66 | static void __init ep405_init_bcsr(void) | ||
67 | { | ||
68 | const u8 *irq_routing; | ||
69 | int i; | ||
70 | |||
71 | /* Find the bloody thing & map it */ | ||
72 | bcsr_node = of_find_compatible_node(NULL, NULL, "ep405-bcsr"); | ||
73 | if (bcsr_node == NULL) { | ||
74 | printk(KERN_ERR "EP405 BCSR not found !\n"); | ||
75 | return; | ||
76 | } | ||
77 | bcsr_regs = of_iomap(bcsr_node, 0); | ||
78 | if (bcsr_regs == NULL) { | ||
79 | printk(KERN_ERR "EP405 BCSR failed to map !\n"); | ||
80 | return; | ||
81 | } | ||
82 | |||
83 | /* Get the irq-routing property and apply the routing to the CPLD */ | ||
84 | irq_routing = of_get_property(bcsr_node, "irq-routing", NULL); | ||
85 | if (irq_routing == NULL) | ||
86 | return; | ||
87 | for (i = 0; i < 16; i++) { | ||
88 | u8 irq = irq_routing[i]; | ||
89 | out_8(bcsr_regs + BCSR_XIRQ_SELECT, i); | ||
90 | out_8(bcsr_regs + BCSR_XIRQ_ROUTING, irq); | ||
91 | } | ||
92 | in_8(bcsr_regs + BCSR_XIRQ_SELECT); | ||
93 | mb(); | ||
94 | out_8(bcsr_regs + BCSR_GPIO_IRQ_PAR_CTRL, 0xfe); | ||
95 | } | ||
96 | |||
97 | static void __init ep405_setup_arch(void) | ||
98 | { | ||
99 | /* Find & init the BCSR CPLD */ | ||
100 | ep405_init_bcsr(); | ||
101 | |||
102 | ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC; | ||
103 | } | ||
104 | |||
105 | static int __init ep405_probe(void) | ||
106 | { | ||
107 | unsigned long root = of_get_flat_dt_root(); | ||
108 | |||
109 | if (!of_flat_dt_is_compatible(root, "ep405")) | ||
110 | return 0; | ||
111 | |||
112 | return 1; | ||
113 | } | ||
114 | |||
115 | define_machine(ep405) { | ||
116 | .name = "EP405", | ||
117 | .probe = ep405_probe, | ||
118 | .setup_arch = ep405_setup_arch, | ||
119 | .progress = udbg_progress, | ||
120 | .init_IRQ = uic_init_tree, | ||
121 | .get_irq = uic_get_irq, | ||
122 | .calibrate_decr = generic_calibrate_decr, | ||
123 | }; | ||
diff --git a/arch/powerpc/platforms/40x/kilauea.c b/arch/powerpc/platforms/40x/kilauea.c index 1bffdbdd21b1..f9206a7fede0 100644 --- a/arch/powerpc/platforms/40x/kilauea.c +++ b/arch/powerpc/platforms/40x/kilauea.c | |||
@@ -19,8 +19,9 @@ | |||
19 | #include <asm/udbg.h> | 19 | #include <asm/udbg.h> |
20 | #include <asm/time.h> | 20 | #include <asm/time.h> |
21 | #include <asm/uic.h> | 21 | #include <asm/uic.h> |
22 | #include <asm/pci-bridge.h> | ||
22 | 23 | ||
23 | static struct of_device_id kilauea_of_bus[] = { | 24 | static __initdata struct of_device_id kilauea_of_bus[] = { |
24 | { .compatible = "ibm,plb4", }, | 25 | { .compatible = "ibm,plb4", }, |
25 | { .compatible = "ibm,opb", }, | 26 | { .compatible = "ibm,opb", }, |
26 | { .compatible = "ibm,ebc", }, | 27 | { .compatible = "ibm,ebc", }, |
@@ -29,14 +30,11 @@ static struct of_device_id kilauea_of_bus[] = { | |||
29 | 30 | ||
30 | static int __init kilauea_device_probe(void) | 31 | static int __init kilauea_device_probe(void) |
31 | { | 32 | { |
32 | if (!machine_is(kilauea)) | ||
33 | return 0; | ||
34 | |||
35 | of_platform_bus_probe(NULL, kilauea_of_bus, NULL); | 33 | of_platform_bus_probe(NULL, kilauea_of_bus, NULL); |
36 | 34 | ||
37 | return 0; | 35 | return 0; |
38 | } | 36 | } |
39 | device_initcall(kilauea_device_probe); | 37 | machine_device_initcall(kilauea, kilauea_device_probe); |
40 | 38 | ||
41 | static int __init kilauea_probe(void) | 39 | static int __init kilauea_probe(void) |
42 | { | 40 | { |
@@ -45,6 +43,8 @@ static int __init kilauea_probe(void) | |||
45 | if (!of_flat_dt_is_compatible(root, "amcc,kilauea")) | 43 | if (!of_flat_dt_is_compatible(root, "amcc,kilauea")) |
46 | return 0; | 44 | return 0; |
47 | 45 | ||
46 | ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC; | ||
47 | |||
48 | return 1; | 48 | return 1; |
49 | } | 49 | } |
50 | 50 | ||
diff --git a/arch/powerpc/platforms/40x/makalu.c b/arch/powerpc/platforms/40x/makalu.c new file mode 100644 index 000000000000..4e4df72fc9cd --- /dev/null +++ b/arch/powerpc/platforms/40x/makalu.c | |||
@@ -0,0 +1,58 @@ | |||
1 | /* | ||
2 | * Makalu board specific routines | ||
3 | * | ||
4 | * Copyright 2007 DENX Software Engineering, Stefan Roese <sr@denx.de> | ||
5 | * | ||
6 | * Based on the Walnut code by | ||
7 | * Josh Boyer <jwboyer@linux.vnet.ibm.com> | ||
8 | * Copyright 2007 IBM Corporation | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License as published by the | ||
12 | * Free Software Foundation; either version 2 of the License, or (at your | ||
13 | * option) any later version. | ||
14 | */ | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/of_platform.h> | ||
17 | #include <asm/machdep.h> | ||
18 | #include <asm/prom.h> | ||
19 | #include <asm/udbg.h> | ||
20 | #include <asm/time.h> | ||
21 | #include <asm/uic.h> | ||
22 | #include <asm/pci-bridge.h> | ||
23 | |||
24 | static __initdata struct of_device_id makalu_of_bus[] = { | ||
25 | { .compatible = "ibm,plb4", }, | ||
26 | { .compatible = "ibm,opb", }, | ||
27 | { .compatible = "ibm,ebc", }, | ||
28 | {}, | ||
29 | }; | ||
30 | |||
31 | static int __init makalu_device_probe(void) | ||
32 | { | ||
33 | of_platform_bus_probe(NULL, makalu_of_bus, NULL); | ||
34 | |||
35 | return 0; | ||
36 | } | ||
37 | machine_device_initcall(makalu, makalu_device_probe); | ||
38 | |||
39 | static int __init makalu_probe(void) | ||
40 | { | ||
41 | unsigned long root = of_get_flat_dt_root(); | ||
42 | |||
43 | if (!of_flat_dt_is_compatible(root, "amcc,makalu")) | ||
44 | return 0; | ||
45 | |||
46 | ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC; | ||
47 | |||
48 | return 1; | ||
49 | } | ||
50 | |||
51 | define_machine(makalu) { | ||
52 | .name = "Makalu", | ||
53 | .probe = makalu_probe, | ||
54 | .progress = udbg_progress, | ||
55 | .init_IRQ = uic_init_tree, | ||
56 | .get_irq = uic_get_irq, | ||
57 | .calibrate_decr = generic_calibrate_decr, | ||
58 | }; | ||
diff --git a/arch/powerpc/platforms/40x/virtex.c b/arch/powerpc/platforms/40x/virtex.c index 14bbc328170f..88b66444dfb2 100644 --- a/arch/powerpc/platforms/40x/virtex.c +++ b/arch/powerpc/platforms/40x/virtex.c | |||
@@ -15,16 +15,23 @@ | |||
15 | #include <asm/time.h> | 15 | #include <asm/time.h> |
16 | #include <asm/xilinx_intc.h> | 16 | #include <asm/xilinx_intc.h> |
17 | 17 | ||
18 | static struct of_device_id xilinx_of_bus_ids[] __initdata = { | ||
19 | { .compatible = "xlnx,plb-v46-1.00.a", }, | ||
20 | { .compatible = "xlnx,plb-v34-1.01.a", }, | ||
21 | { .compatible = "xlnx,plb-v34-1.02.a", }, | ||
22 | { .compatible = "xlnx,opb-v20-1.10.c", }, | ||
23 | { .compatible = "xlnx,dcr-v29-1.00.a", }, | ||
24 | { .compatible = "xlnx,compound", }, | ||
25 | {} | ||
26 | }; | ||
27 | |||
18 | static int __init virtex_device_probe(void) | 28 | static int __init virtex_device_probe(void) |
19 | { | 29 | { |
20 | if (!machine_is(virtex)) | 30 | of_platform_bus_probe(NULL, xilinx_of_bus_ids, NULL); |
21 | return 0; | ||
22 | |||
23 | of_platform_bus_probe(NULL, NULL, NULL); | ||
24 | 31 | ||
25 | return 0; | 32 | return 0; |
26 | } | 33 | } |
27 | device_initcall(virtex_device_probe); | 34 | machine_device_initcall(virtex, virtex_device_probe); |
28 | 35 | ||
29 | static int __init virtex_probe(void) | 36 | static int __init virtex_probe(void) |
30 | { | 37 | { |
diff --git a/arch/powerpc/platforms/40x/walnut.c b/arch/powerpc/platforms/40x/walnut.c index ff6db2431798..5d9edd917f92 100644 --- a/arch/powerpc/platforms/40x/walnut.c +++ b/arch/powerpc/platforms/40x/walnut.c | |||
@@ -24,8 +24,9 @@ | |||
24 | #include <asm/udbg.h> | 24 | #include <asm/udbg.h> |
25 | #include <asm/time.h> | 25 | #include <asm/time.h> |
26 | #include <asm/uic.h> | 26 | #include <asm/uic.h> |
27 | #include <asm/pci-bridge.h> | ||
27 | 28 | ||
28 | static struct of_device_id walnut_of_bus[] = { | 29 | static __initdata struct of_device_id walnut_of_bus[] = { |
29 | { .compatible = "ibm,plb3", }, | 30 | { .compatible = "ibm,plb3", }, |
30 | { .compatible = "ibm,opb", }, | 31 | { .compatible = "ibm,opb", }, |
31 | { .compatible = "ibm,ebc", }, | 32 | { .compatible = "ibm,ebc", }, |
@@ -34,15 +35,12 @@ static struct of_device_id walnut_of_bus[] = { | |||
34 | 35 | ||
35 | static int __init walnut_device_probe(void) | 36 | static int __init walnut_device_probe(void) |
36 | { | 37 | { |
37 | if (!machine_is(walnut)) | ||
38 | return 0; | ||
39 | |||
40 | /* FIXME: do bus probe here */ | ||
41 | of_platform_bus_probe(NULL, walnut_of_bus, NULL); | 38 | of_platform_bus_probe(NULL, walnut_of_bus, NULL); |
39 | of_instantiate_rtc(); | ||
42 | 40 | ||
43 | return 0; | 41 | return 0; |
44 | } | 42 | } |
45 | device_initcall(walnut_device_probe); | 43 | machine_device_initcall(walnut, walnut_device_probe); |
46 | 44 | ||
47 | static int __init walnut_probe(void) | 45 | static int __init walnut_probe(void) |
48 | { | 46 | { |
@@ -51,6 +49,8 @@ static int __init walnut_probe(void) | |||
51 | if (!of_flat_dt_is_compatible(root, "ibm,walnut")) | 49 | if (!of_flat_dt_is_compatible(root, "ibm,walnut")) |
52 | return 0; | 50 | return 0; |
53 | 51 | ||
52 | ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC; | ||
53 | |||
54 | return 1; | 54 | return 1; |
55 | } | 55 | } |
56 | 56 | ||
diff --git a/arch/powerpc/platforms/44x/Kconfig b/arch/powerpc/platforms/44x/Kconfig index 8390cc164135..c062c4cbbed5 100644 --- a/arch/powerpc/platforms/44x/Kconfig +++ b/arch/powerpc/platforms/44x/Kconfig | |||
@@ -3,6 +3,7 @@ config BAMBOO | |||
3 | depends on 44x | 3 | depends on 44x |
4 | default n | 4 | default n |
5 | select 440EP | 5 | select 440EP |
6 | select PCI | ||
6 | help | 7 | help |
7 | This option enables support for the IBM PPC440EP evaluation board. | 8 | This option enables support for the IBM PPC440EP evaluation board. |
8 | 9 | ||
@@ -11,6 +12,8 @@ config EBONY | |||
11 | depends on 44x | 12 | depends on 44x |
12 | default y | 13 | default y |
13 | select 440GP | 14 | select 440GP |
15 | select PCI | ||
16 | select OF_RTC | ||
14 | help | 17 | help |
15 | This option enables support for the IBM PPC440GP evaluation board. | 18 | This option enables support for the IBM PPC440GP evaluation board. |
16 | 19 | ||
@@ -22,6 +25,48 @@ config SEQUOIA | |||
22 | help | 25 | help |
23 | This option enables support for the AMCC PPC440EPX evaluation board. | 26 | This option enables support for the AMCC PPC440EPX evaluation board. |
24 | 27 | ||
28 | config TAISHAN | ||
29 | bool "Taishan" | ||
30 | depends on 44x | ||
31 | default n | ||
32 | select 440GX | ||
33 | select PCI | ||
34 | help | ||
35 | This option enables support for the AMCC PPC440GX "Taishan" | ||
36 | evaluation board. | ||
37 | |||
38 | config KATMAI | ||
39 | bool "Katmai" | ||
40 | depends on 44x | ||
41 | default n | ||
42 | select 440SPe | ||
43 | select PCI | ||
44 | select PPC4xx_PCI_EXPRESS | ||
45 | help | ||
46 | This option enables support for the AMCC PPC440SPe evaluation board. | ||
47 | |||
48 | config RAINIER | ||
49 | bool "Rainier" | ||
50 | depends on 44x | ||
51 | default n | ||
52 | select 440GRX | ||
53 | select PCI | ||
54 | help | ||
55 | This option enables support for the AMCC PPC440GRX evaluation board. | ||
56 | |||
57 | config WARP | ||
58 | bool "PIKA Warp" | ||
59 | depends on 44x | ||
60 | default n | ||
61 | select 440EP | ||
62 | help | ||
63 | This option enables support for the PIKA Warp(tm) Appliance. The Warp | ||
64 | is a small computer replacement with up to 9 ports of FXO/FXS plus VOIP | ||
65 | stations and trunks. | ||
66 | |||
67 | See http://www.pikatechnologies.com/ and follow the "PIKA for Computer | ||
68 | Telephony Developers" link for more information. | ||
69 | |||
25 | #config LUAN | 70 | #config LUAN |
26 | # bool "Luan" | 71 | # bool "Luan" |
27 | # depends on 44x | 72 | # depends on 44x |
@@ -44,6 +89,7 @@ config 440EP | |||
44 | select PPC_FPU | 89 | select PPC_FPU |
45 | select IBM440EP_ERR42 | 90 | select IBM440EP_ERR42 |
46 | select IBM_NEW_EMAC_ZMII | 91 | select IBM_NEW_EMAC_ZMII |
92 | select USB_ARCH_HAS_OHCI | ||
47 | 93 | ||
48 | config 440EPX | 94 | config 440EPX |
49 | bool | 95 | bool |
@@ -52,20 +98,29 @@ config 440EPX | |||
52 | select IBM_NEW_EMAC_RGMII | 98 | select IBM_NEW_EMAC_RGMII |
53 | select IBM_NEW_EMAC_ZMII | 99 | select IBM_NEW_EMAC_ZMII |
54 | 100 | ||
101 | config 440GRX | ||
102 | bool | ||
103 | select IBM_NEW_EMAC_EMAC4 | ||
104 | select IBM_NEW_EMAC_RGMII | ||
105 | select IBM_NEW_EMAC_ZMII | ||
106 | |||
55 | config 440GP | 107 | config 440GP |
56 | bool | 108 | bool |
57 | select IBM_NEW_EMAC_ZMII | 109 | select IBM_NEW_EMAC_ZMII |
58 | 110 | ||
59 | config 440GX | 111 | config 440GX |
60 | bool | 112 | bool |
113 | select IBM_NEW_EMAC_EMAC4 | ||
114 | select IBM_NEW_EMAC_RGMII | ||
115 | select IBM_NEW_EMAC_ZMII #test only | ||
116 | select IBM_NEW_EMAC_TAH #test only | ||
61 | 117 | ||
62 | config 440SP | 118 | config 440SP |
63 | bool | 119 | bool |
64 | 120 | ||
65 | config 440A | 121 | config 440SPe |
122 | select IBM_NEW_EMAC_EMAC4 | ||
66 | bool | 123 | bool |
67 | depends on 440GX || 440EPX | ||
68 | default y | ||
69 | 124 | ||
70 | # 44x errata/workaround config symbols, selected by the CPU models above | 125 | # 44x errata/workaround config symbols, selected by the CPU models above |
71 | config IBM440EP_ERR42 | 126 | config IBM440EP_ERR42 |
diff --git a/arch/powerpc/platforms/44x/Makefile b/arch/powerpc/platforms/44x/Makefile index 10ce6740cc7d..0864d4f1cbc2 100644 --- a/arch/powerpc/platforms/44x/Makefile +++ b/arch/powerpc/platforms/44x/Makefile | |||
@@ -1,4 +1,9 @@ | |||
1 | obj-$(CONFIG_44x) := misc_44x.o | 1 | obj-$(CONFIG_44x) := misc_44x.o |
2 | obj-$(CONFIG_EBONY) += ebony.o | 2 | obj-$(CONFIG_EBONY) += ebony.o |
3 | obj-$(CONFIG_BAMBOO) += bamboo.o | 3 | obj-$(CONFIG_TAISHAN) += taishan.o |
4 | obj-$(CONFIG_BAMBOO) += bamboo.o | ||
4 | obj-$(CONFIG_SEQUOIA) += sequoia.o | 5 | obj-$(CONFIG_SEQUOIA) += sequoia.o |
6 | obj-$(CONFIG_KATMAI) += katmai.o | ||
7 | obj-$(CONFIG_RAINIER) += rainier.o | ||
8 | obj-$(CONFIG_WARP) += warp.o | ||
9 | obj-$(CONFIG_WARP) += warp-nand.o | ||
diff --git a/arch/powerpc/platforms/44x/bamboo.c b/arch/powerpc/platforms/44x/bamboo.c index be23f112184f..fb9a22a7e8d0 100644 --- a/arch/powerpc/platforms/44x/bamboo.c +++ b/arch/powerpc/platforms/44x/bamboo.c | |||
@@ -21,9 +21,11 @@ | |||
21 | #include <asm/udbg.h> | 21 | #include <asm/udbg.h> |
22 | #include <asm/time.h> | 22 | #include <asm/time.h> |
23 | #include <asm/uic.h> | 23 | #include <asm/uic.h> |
24 | #include <asm/pci-bridge.h> | ||
25 | |||
24 | #include "44x.h" | 26 | #include "44x.h" |
25 | 27 | ||
26 | static struct of_device_id bamboo_of_bus[] = { | 28 | static __initdata struct of_device_id bamboo_of_bus[] = { |
27 | { .compatible = "ibm,plb4", }, | 29 | { .compatible = "ibm,plb4", }, |
28 | { .compatible = "ibm,opb", }, | 30 | { .compatible = "ibm,opb", }, |
29 | { .compatible = "ibm,ebc", }, | 31 | { .compatible = "ibm,ebc", }, |
@@ -32,14 +34,11 @@ static struct of_device_id bamboo_of_bus[] = { | |||
32 | 34 | ||
33 | static int __init bamboo_device_probe(void) | 35 | static int __init bamboo_device_probe(void) |
34 | { | 36 | { |
35 | if (!machine_is(bamboo)) | ||
36 | return 0; | ||
37 | |||
38 | of_platform_bus_probe(NULL, bamboo_of_bus, NULL); | 37 | of_platform_bus_probe(NULL, bamboo_of_bus, NULL); |
39 | 38 | ||
40 | return 0; | 39 | return 0; |
41 | } | 40 | } |
42 | device_initcall(bamboo_device_probe); | 41 | machine_device_initcall(bamboo, bamboo_device_probe); |
43 | 42 | ||
44 | static int __init bamboo_probe(void) | 43 | static int __init bamboo_probe(void) |
45 | { | 44 | { |
@@ -48,6 +47,8 @@ static int __init bamboo_probe(void) | |||
48 | if (!of_flat_dt_is_compatible(root, "amcc,bamboo")) | 47 | if (!of_flat_dt_is_compatible(root, "amcc,bamboo")) |
49 | return 0; | 48 | return 0; |
50 | 49 | ||
50 | ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC; | ||
51 | |||
51 | return 1; | 52 | return 1; |
52 | } | 53 | } |
53 | 54 | ||
diff --git a/arch/powerpc/platforms/44x/ebony.c b/arch/powerpc/platforms/44x/ebony.c index 6cd3476767cc..1a8d467bff85 100644 --- a/arch/powerpc/platforms/44x/ebony.c +++ b/arch/powerpc/platforms/44x/ebony.c | |||
@@ -18,16 +18,18 @@ | |||
18 | 18 | ||
19 | #include <linux/init.h> | 19 | #include <linux/init.h> |
20 | #include <linux/of_platform.h> | 20 | #include <linux/of_platform.h> |
21 | #include <linux/rtc.h> | ||
21 | 22 | ||
22 | #include <asm/machdep.h> | 23 | #include <asm/machdep.h> |
23 | #include <asm/prom.h> | 24 | #include <asm/prom.h> |
24 | #include <asm/udbg.h> | 25 | #include <asm/udbg.h> |
25 | #include <asm/time.h> | 26 | #include <asm/time.h> |
26 | #include <asm/uic.h> | 27 | #include <asm/uic.h> |
28 | #include <asm/pci-bridge.h> | ||
27 | 29 | ||
28 | #include "44x.h" | 30 | #include "44x.h" |
29 | 31 | ||
30 | static struct of_device_id ebony_of_bus[] = { | 32 | static __initdata struct of_device_id ebony_of_bus[] = { |
31 | { .compatible = "ibm,plb4", }, | 33 | { .compatible = "ibm,plb4", }, |
32 | { .compatible = "ibm,opb", }, | 34 | { .compatible = "ibm,opb", }, |
33 | { .compatible = "ibm,ebc", }, | 35 | { .compatible = "ibm,ebc", }, |
@@ -36,14 +38,12 @@ static struct of_device_id ebony_of_bus[] = { | |||
36 | 38 | ||
37 | static int __init ebony_device_probe(void) | 39 | static int __init ebony_device_probe(void) |
38 | { | 40 | { |
39 | if (!machine_is(ebony)) | ||
40 | return 0; | ||
41 | |||
42 | of_platform_bus_probe(NULL, ebony_of_bus, NULL); | 41 | of_platform_bus_probe(NULL, ebony_of_bus, NULL); |
42 | of_instantiate_rtc(); | ||
43 | 43 | ||
44 | return 0; | 44 | return 0; |
45 | } | 45 | } |
46 | device_initcall(ebony_device_probe); | 46 | machine_device_initcall(ebony, ebony_device_probe); |
47 | 47 | ||
48 | /* | 48 | /* |
49 | * Called very early, MMU is off, device-tree isn't unflattened | 49 | * Called very early, MMU is off, device-tree isn't unflattened |
@@ -55,6 +55,8 @@ static int __init ebony_probe(void) | |||
55 | if (!of_flat_dt_is_compatible(root, "ibm,ebony")) | 55 | if (!of_flat_dt_is_compatible(root, "ibm,ebony")) |
56 | return 0; | 56 | return 0; |
57 | 57 | ||
58 | ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC; | ||
59 | |||
58 | return 1; | 60 | return 1; |
59 | } | 61 | } |
60 | 62 | ||
diff --git a/arch/powerpc/platforms/44x/katmai.c b/arch/powerpc/platforms/44x/katmai.c new file mode 100644 index 000000000000..11134121f272 --- /dev/null +++ b/arch/powerpc/platforms/44x/katmai.c | |||
@@ -0,0 +1,63 @@ | |||
1 | /* | ||
2 | * Katmai board specific routines | ||
3 | * | ||
4 | * Benjamin Herrenschmidt <benh@kernel.crashing.org> | ||
5 | * Copyright 2007 IBM Corp. | ||
6 | * | ||
7 | * Based on the Bamboo code by | ||
8 | * Josh Boyer <jwboyer@linux.vnet.ibm.com> | ||
9 | * Copyright 2007 IBM Corporation | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify it | ||
12 | * under the terms of the GNU General Public License as published by the | ||
13 | * Free Software Foundation; either version 2 of the License, or (at your | ||
14 | * option) any later version. | ||
15 | */ | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/of_platform.h> | ||
18 | |||
19 | #include <asm/machdep.h> | ||
20 | #include <asm/prom.h> | ||
21 | #include <asm/udbg.h> | ||
22 | #include <asm/time.h> | ||
23 | #include <asm/uic.h> | ||
24 | #include <asm/pci-bridge.h> | ||
25 | |||
26 | #include "44x.h" | ||
27 | |||
28 | static __initdata struct of_device_id katmai_of_bus[] = { | ||
29 | { .compatible = "ibm,plb4", }, | ||
30 | { .compatible = "ibm,opb", }, | ||
31 | { .compatible = "ibm,ebc", }, | ||
32 | {}, | ||
33 | }; | ||
34 | |||
35 | static int __init katmai_device_probe(void) | ||
36 | { | ||
37 | of_platform_bus_probe(NULL, katmai_of_bus, NULL); | ||
38 | |||
39 | return 0; | ||
40 | } | ||
41 | machine_device_initcall(katmai, katmai_device_probe); | ||
42 | |||
43 | static int __init katmai_probe(void) | ||
44 | { | ||
45 | unsigned long root = of_get_flat_dt_root(); | ||
46 | |||
47 | if (!of_flat_dt_is_compatible(root, "amcc,katmai")) | ||
48 | return 0; | ||
49 | |||
50 | ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC; | ||
51 | |||
52 | return 1; | ||
53 | } | ||
54 | |||
55 | define_machine(katmai) { | ||
56 | .name = "Katmai", | ||
57 | .probe = katmai_probe, | ||
58 | .progress = udbg_progress, | ||
59 | .init_IRQ = uic_init_tree, | ||
60 | .get_irq = uic_get_irq, | ||
61 | .restart = ppc44x_reset_system, | ||
62 | .calibrate_decr = generic_calibrate_decr, | ||
63 | }; | ||
diff --git a/arch/powerpc/platforms/44x/rainier.c b/arch/powerpc/platforms/44x/rainier.c new file mode 100644 index 000000000000..a7fae1cf69c1 --- /dev/null +++ b/arch/powerpc/platforms/44x/rainier.c | |||
@@ -0,0 +1,62 @@ | |||
1 | /* | ||
2 | * Rainier board specific routines | ||
3 | * | ||
4 | * Valentine Barshak <vbarshak@ru.mvista.com> | ||
5 | * Copyright 2007 MontaVista Software Inc. | ||
6 | * | ||
7 | * Based on the Bamboo code by | ||
8 | * Josh Boyer <jwboyer@linux.vnet.ibm.com> | ||
9 | * Copyright 2007 IBM Corporation | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify it | ||
12 | * under the terms of the GNU General Public License as published by the | ||
13 | * Free Software Foundation; either version 2 of the License, or (at your | ||
14 | * option) any later version. | ||
15 | */ | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/of_platform.h> | ||
18 | |||
19 | #include <asm/machdep.h> | ||
20 | #include <asm/prom.h> | ||
21 | #include <asm/udbg.h> | ||
22 | #include <asm/time.h> | ||
23 | #include <asm/uic.h> | ||
24 | #include <asm/pci-bridge.h> | ||
25 | #include "44x.h" | ||
26 | |||
27 | static __initdata struct of_device_id rainier_of_bus[] = { | ||
28 | { .compatible = "ibm,plb4", }, | ||
29 | { .compatible = "ibm,opb", }, | ||
30 | { .compatible = "ibm,ebc", }, | ||
31 | {}, | ||
32 | }; | ||
33 | |||
34 | static int __init rainier_device_probe(void) | ||
35 | { | ||
36 | of_platform_bus_probe(NULL, rainier_of_bus, NULL); | ||
37 | |||
38 | return 0; | ||
39 | } | ||
40 | machine_device_initcall(rainier, rainier_device_probe); | ||
41 | |||
42 | static int __init rainier_probe(void) | ||
43 | { | ||
44 | unsigned long root = of_get_flat_dt_root(); | ||
45 | |||
46 | if (!of_flat_dt_is_compatible(root, "amcc,rainier")) | ||
47 | return 0; | ||
48 | |||
49 | ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC; | ||
50 | |||
51 | return 1; | ||
52 | } | ||
53 | |||
54 | define_machine(rainier) { | ||
55 | .name = "Rainier", | ||
56 | .probe = rainier_probe, | ||
57 | .progress = udbg_progress, | ||
58 | .init_IRQ = uic_init_tree, | ||
59 | .get_irq = uic_get_irq, | ||
60 | .restart = ppc44x_reset_system, | ||
61 | .calibrate_decr = generic_calibrate_decr, | ||
62 | }; | ||
diff --git a/arch/powerpc/platforms/44x/sequoia.c b/arch/powerpc/platforms/44x/sequoia.c index 21a9dd14f297..d279db42c896 100644 --- a/arch/powerpc/platforms/44x/sequoia.c +++ b/arch/powerpc/platforms/44x/sequoia.c | |||
@@ -21,9 +21,11 @@ | |||
21 | #include <asm/udbg.h> | 21 | #include <asm/udbg.h> |
22 | #include <asm/time.h> | 22 | #include <asm/time.h> |
23 | #include <asm/uic.h> | 23 | #include <asm/uic.h> |
24 | #include <asm/pci-bridge.h> | ||
25 | |||
24 | #include "44x.h" | 26 | #include "44x.h" |
25 | 27 | ||
26 | static struct of_device_id sequoia_of_bus[] = { | 28 | static __initdata struct of_device_id sequoia_of_bus[] = { |
27 | { .compatible = "ibm,plb4", }, | 29 | { .compatible = "ibm,plb4", }, |
28 | { .compatible = "ibm,opb", }, | 30 | { .compatible = "ibm,opb", }, |
29 | { .compatible = "ibm,ebc", }, | 31 | { .compatible = "ibm,ebc", }, |
@@ -32,14 +34,11 @@ static struct of_device_id sequoia_of_bus[] = { | |||
32 | 34 | ||
33 | static int __init sequoia_device_probe(void) | 35 | static int __init sequoia_device_probe(void) |
34 | { | 36 | { |
35 | if (!machine_is(sequoia)) | ||
36 | return 0; | ||
37 | |||
38 | of_platform_bus_probe(NULL, sequoia_of_bus, NULL); | 37 | of_platform_bus_probe(NULL, sequoia_of_bus, NULL); |
39 | 38 | ||
40 | return 0; | 39 | return 0; |
41 | } | 40 | } |
42 | device_initcall(sequoia_device_probe); | 41 | machine_device_initcall(sequoia, sequoia_device_probe); |
43 | 42 | ||
44 | static int __init sequoia_probe(void) | 43 | static int __init sequoia_probe(void) |
45 | { | 44 | { |
@@ -48,6 +47,8 @@ static int __init sequoia_probe(void) | |||
48 | if (!of_flat_dt_is_compatible(root, "amcc,sequoia")) | 47 | if (!of_flat_dt_is_compatible(root, "amcc,sequoia")) |
49 | return 0; | 48 | return 0; |
50 | 49 | ||
50 | ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC; | ||
51 | |||
51 | return 1; | 52 | return 1; |
52 | } | 53 | } |
53 | 54 | ||
diff --git a/arch/powerpc/platforms/44x/taishan.c b/arch/powerpc/platforms/44x/taishan.c new file mode 100644 index 000000000000..28ab7e2e02c3 --- /dev/null +++ b/arch/powerpc/platforms/44x/taishan.c | |||
@@ -0,0 +1,73 @@ | |||
1 | /* | ||
2 | * Taishan board specific routines based off ebony.c code | ||
3 | * original copyrights below | ||
4 | * | ||
5 | * Matt Porter <mporter@kernel.crashing.org> | ||
6 | * Copyright 2002-2005 MontaVista Software Inc. | ||
7 | * | ||
8 | * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net> | ||
9 | * Copyright (c) 2003-2005 Zultys Technologies | ||
10 | * | ||
11 | * Rewritten and ported to the merged powerpc tree: | ||
12 | * Copyright 2007 David Gibson <dwg@au1.ibm.com>, IBM Corporation. | ||
13 | * | ||
14 | * Modified from ebony.c for taishan: | ||
15 | * Copyright 2007 Hugh Blemings <hugh@au.ibm.com>, IBM Corporation. | ||
16 | * | ||
17 | * This program is free software; you can redistribute it and/or modify it | ||
18 | * under the terms of the GNU General Public License as published by the | ||
19 | * Free Software Foundation; either version 2 of the License, or (at your | ||
20 | * option) any later version. | ||
21 | */ | ||
22 | |||
23 | #include <linux/init.h> | ||
24 | #include <linux/of_platform.h> | ||
25 | |||
26 | #include <asm/machdep.h> | ||
27 | #include <asm/prom.h> | ||
28 | #include <asm/udbg.h> | ||
29 | #include <asm/time.h> | ||
30 | #include <asm/uic.h> | ||
31 | #include <asm/pci-bridge.h> | ||
32 | |||
33 | #include "44x.h" | ||
34 | |||
35 | static __initdata struct of_device_id taishan_of_bus[] = { | ||
36 | { .compatible = "ibm,plb4", }, | ||
37 | { .compatible = "ibm,opb", }, | ||
38 | { .compatible = "ibm,ebc", }, | ||
39 | {}, | ||
40 | }; | ||
41 | |||
42 | static int __init taishan_device_probe(void) | ||
43 | { | ||
44 | of_platform_bus_probe(NULL, taishan_of_bus, NULL); | ||
45 | |||
46 | return 0; | ||
47 | } | ||
48 | machine_device_initcall(taishan, taishan_device_probe); | ||
49 | |||
50 | /* | ||
51 | * Called very early, MMU is off, device-tree isn't unflattened | ||
52 | */ | ||
53 | static int __init taishan_probe(void) | ||
54 | { | ||
55 | unsigned long root = of_get_flat_dt_root(); | ||
56 | |||
57 | if (!of_flat_dt_is_compatible(root, "amcc,taishan")) | ||
58 | return 0; | ||
59 | |||
60 | ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC; | ||
61 | |||
62 | return 1; | ||
63 | } | ||
64 | |||
65 | define_machine(taishan) { | ||
66 | .name = "Taishan", | ||
67 | .probe = taishan_probe, | ||
68 | .progress = udbg_progress, | ||
69 | .init_IRQ = uic_init_tree, | ||
70 | .get_irq = uic_get_irq, | ||
71 | .restart = ppc44x_reset_system, | ||
72 | .calibrate_decr = generic_calibrate_decr, | ||
73 | }; | ||
diff --git a/arch/powerpc/platforms/44x/warp-nand.c b/arch/powerpc/platforms/44x/warp-nand.c new file mode 100644 index 000000000000..84ab78ff8c03 --- /dev/null +++ b/arch/powerpc/platforms/44x/warp-nand.c | |||
@@ -0,0 +1,105 @@ | |||
1 | /* | ||
2 | * PIKA Warp(tm) NAND flash specific routines | ||
3 | * | ||
4 | * Copyright (c) 2008 PIKA Technologies | ||
5 | * Sean MacLennan <smaclennan@pikatech.com> | ||
6 | */ | ||
7 | |||
8 | #include <linux/platform_device.h> | ||
9 | #include <linux/mtd/mtd.h> | ||
10 | #include <linux/mtd/map.h> | ||
11 | #include <linux/mtd/partitions.h> | ||
12 | #include <linux/mtd/nand.h> | ||
13 | #include <linux/mtd/ndfc.h> | ||
14 | |||
15 | #ifdef CONFIG_MTD_NAND_NDFC | ||
16 | |||
17 | #define CS_NAND_0 1 /* use chip select 1 for NAND device 0 */ | ||
18 | |||
19 | #define WARP_NAND_FLASH_REG_ADDR 0xD0000000UL | ||
20 | #define WARP_NAND_FLASH_REG_SIZE 0x2000 | ||
21 | |||
22 | static struct resource warp_ndfc = { | ||
23 | .start = WARP_NAND_FLASH_REG_ADDR, | ||
24 | .end = WARP_NAND_FLASH_REG_ADDR + WARP_NAND_FLASH_REG_SIZE, | ||
25 | .flags = IORESOURCE_MEM, | ||
26 | }; | ||
27 | |||
28 | static struct mtd_partition nand_parts[] = { | ||
29 | { | ||
30 | .name = "kernel", | ||
31 | .offset = 0, | ||
32 | .size = 0x0200000 | ||
33 | }, | ||
34 | { | ||
35 | .name = "root", | ||
36 | .offset = 0x0200000, | ||
37 | .size = 0x3400000 | ||
38 | }, | ||
39 | { | ||
40 | .name = "user", | ||
41 | .offset = 0x3600000, | ||
42 | .size = 0x0A00000 | ||
43 | }, | ||
44 | }; | ||
45 | |||
46 | struct ndfc_controller_settings warp_ndfc_settings = { | ||
47 | .ccr_settings = (NDFC_CCR_BS(CS_NAND_0) | NDFC_CCR_ARAC1), | ||
48 | .ndfc_erpn = 0, | ||
49 | }; | ||
50 | |||
51 | static struct ndfc_chip_settings warp_chip0_settings = { | ||
52 | .bank_settings = 0x80002222, | ||
53 | }; | ||
54 | |||
55 | struct platform_nand_ctrl warp_nand_ctrl = { | ||
56 | .priv = &warp_ndfc_settings, | ||
57 | }; | ||
58 | |||
59 | static struct platform_device warp_ndfc_device = { | ||
60 | .name = "ndfc-nand", | ||
61 | .id = 0, | ||
62 | .dev = { | ||
63 | .platform_data = &warp_nand_ctrl, | ||
64 | }, | ||
65 | .num_resources = 1, | ||
66 | .resource = &warp_ndfc, | ||
67 | }; | ||
68 | |||
69 | static struct nand_ecclayout nand_oob_16 = { | ||
70 | .eccbytes = 3, | ||
71 | .eccpos = { 0, 1, 2, 3, 6, 7 }, | ||
72 | .oobfree = { {.offset = 8, .length = 16} } | ||
73 | }; | ||
74 | |||
75 | static struct platform_nand_chip warp_nand_chip0 = { | ||
76 | .nr_chips = 1, | ||
77 | .chip_offset = CS_NAND_0, | ||
78 | .nr_partitions = ARRAY_SIZE(nand_parts), | ||
79 | .partitions = nand_parts, | ||
80 | .chip_delay = 50, | ||
81 | .ecclayout = &nand_oob_16, | ||
82 | .priv = &warp_chip0_settings, | ||
83 | }; | ||
84 | |||
85 | static struct platform_device warp_nand_device = { | ||
86 | .name = "ndfc-chip", | ||
87 | .id = 0, | ||
88 | .num_resources = 1, | ||
89 | .resource = &warp_ndfc, | ||
90 | .dev = { | ||
91 | .platform_data = &warp_nand_chip0, | ||
92 | .parent = &warp_ndfc_device.dev, | ||
93 | } | ||
94 | }; | ||
95 | |||
96 | static int warp_setup_nand_flash(void) | ||
97 | { | ||
98 | platform_device_register(&warp_ndfc_device); | ||
99 | platform_device_register(&warp_nand_device); | ||
100 | |||
101 | return 0; | ||
102 | } | ||
103 | device_initcall(warp_setup_nand_flash); | ||
104 | |||
105 | #endif | ||
diff --git a/arch/powerpc/platforms/44x/warp.c b/arch/powerpc/platforms/44x/warp.c new file mode 100644 index 000000000000..8f01563dbd2a --- /dev/null +++ b/arch/powerpc/platforms/44x/warp.c | |||
@@ -0,0 +1,153 @@ | |||
1 | /* | ||
2 | * PIKA Warp(tm) board specific routines | ||
3 | * | ||
4 | * Copyright (c) 2008 PIKA Technologies | ||
5 | * Sean MacLennan <smaclennan@pikatech.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | */ | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/of_platform.h> | ||
14 | #include <linux/kthread.h> | ||
15 | |||
16 | #include <asm/machdep.h> | ||
17 | #include <asm/prom.h> | ||
18 | #include <asm/udbg.h> | ||
19 | #include <asm/time.h> | ||
20 | #include <asm/uic.h> | ||
21 | |||
22 | #include "44x.h" | ||
23 | |||
24 | |||
25 | static __initdata struct of_device_id warp_of_bus[] = { | ||
26 | { .compatible = "ibm,plb4", }, | ||
27 | { .compatible = "ibm,opb", }, | ||
28 | { .compatible = "ibm,ebc", }, | ||
29 | {}, | ||
30 | }; | ||
31 | |||
32 | static int __init warp_device_probe(void) | ||
33 | { | ||
34 | of_platform_bus_probe(NULL, warp_of_bus, NULL); | ||
35 | return 0; | ||
36 | } | ||
37 | machine_device_initcall(warp, warp_device_probe); | ||
38 | |||
39 | static int __init warp_probe(void) | ||
40 | { | ||
41 | unsigned long root = of_get_flat_dt_root(); | ||
42 | |||
43 | return of_flat_dt_is_compatible(root, "pika,warp"); | ||
44 | } | ||
45 | |||
46 | define_machine(warp) { | ||
47 | .name = "Warp", | ||
48 | .probe = warp_probe, | ||
49 | .progress = udbg_progress, | ||
50 | .init_IRQ = uic_init_tree, | ||
51 | .get_irq = uic_get_irq, | ||
52 | .restart = ppc44x_reset_system, | ||
53 | .calibrate_decr = generic_calibrate_decr, | ||
54 | }; | ||
55 | |||
56 | |||
57 | #define LED_GREEN (0x80000000 >> 0) | ||
58 | #define LED_RED (0x80000000 >> 1) | ||
59 | |||
60 | |||
61 | /* This is for the power LEDs 1 = on, 0 = off, -1 = leave alone */ | ||
62 | void warp_set_power_leds(int green, int red) | ||
63 | { | ||
64 | static void __iomem *gpio_base = NULL; | ||
65 | unsigned leds; | ||
66 | |||
67 | if (gpio_base == NULL) { | ||
68 | struct device_node *np; | ||
69 | |||
70 | /* Power LEDS are on the second GPIO controller */ | ||
71 | np = of_find_compatible_node(NULL, NULL, "ibm,gpio-440EP"); | ||
72 | if (np) | ||
73 | np = of_find_compatible_node(np, NULL, "ibm,gpio-440EP"); | ||
74 | if (np == NULL) { | ||
75 | printk(KERN_ERR __FILE__ ": Unable to find gpio\n"); | ||
76 | return; | ||
77 | } | ||
78 | |||
79 | gpio_base = of_iomap(np, 0); | ||
80 | of_node_put(np); | ||
81 | if (gpio_base == NULL) { | ||
82 | printk(KERN_ERR __FILE__ ": Unable to map gpio"); | ||
83 | return; | ||
84 | } | ||
85 | } | ||
86 | |||
87 | leds = in_be32(gpio_base); | ||
88 | |||
89 | switch (green) { | ||
90 | case 0: leds &= ~LED_GREEN; break; | ||
91 | case 1: leds |= LED_GREEN; break; | ||
92 | } | ||
93 | switch (red) { | ||
94 | case 0: leds &= ~LED_RED; break; | ||
95 | case 1: leds |= LED_RED; break; | ||
96 | } | ||
97 | |||
98 | out_be32(gpio_base, leds); | ||
99 | } | ||
100 | EXPORT_SYMBOL(warp_set_power_leds); | ||
101 | |||
102 | |||
103 | #ifdef CONFIG_SENSORS_AD7414 | ||
104 | static int pika_dtm_thread(void __iomem *fpga) | ||
105 | { | ||
106 | extern int ad7414_get_temp(int index); | ||
107 | |||
108 | while (!kthread_should_stop()) { | ||
109 | int temp = ad7414_get_temp(0); | ||
110 | |||
111 | out_be32(fpga, temp); | ||
112 | |||
113 | set_current_state(TASK_INTERRUPTIBLE); | ||
114 | schedule_timeout(HZ); | ||
115 | } | ||
116 | |||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | static int __init pika_dtm_start(void) | ||
121 | { | ||
122 | struct task_struct *dtm_thread; | ||
123 | struct device_node *np; | ||
124 | struct resource res; | ||
125 | void __iomem *fpga; | ||
126 | |||
127 | np = of_find_compatible_node(NULL, NULL, "pika,fpga"); | ||
128 | if (np == NULL) | ||
129 | return -ENOENT; | ||
130 | |||
131 | /* We do not call of_iomap here since it would map in the entire | ||
132 | * fpga space, which is over 8k. | ||
133 | */ | ||
134 | if (of_address_to_resource(np, 0, &res)) { | ||
135 | of_node_put(np); | ||
136 | return -ENOENT; | ||
137 | } | ||
138 | of_node_put(np); | ||
139 | |||
140 | fpga = ioremap(res.start + 0x20, 4); | ||
141 | if (fpga == NULL) | ||
142 | return -ENOENT; | ||
143 | |||
144 | dtm_thread = kthread_run(pika_dtm_thread, fpga + 0x20, "pika-dtm"); | ||
145 | if (IS_ERR(dtm_thread)) { | ||
146 | iounmap(fpga); | ||
147 | return PTR_ERR(dtm_thread); | ||
148 | } | ||
149 | |||
150 | return 0; | ||
151 | } | ||
152 | device_initcall(pika_dtm_start); | ||
153 | #endif | ||
diff --git a/arch/powerpc/platforms/52xx/Kconfig b/arch/powerpc/platforms/52xx/Kconfig index 2938d4927b83..515f244c90bb 100644 --- a/arch/powerpc/platforms/52xx/Kconfig +++ b/arch/powerpc/platforms/52xx/Kconfig | |||
@@ -1,38 +1,48 @@ | |||
1 | config PPC_MPC52xx | 1 | config PPC_MPC52xx |
2 | bool | 2 | bool "52xx-based boards" |
3 | depends on PPC_MULTIPLATFORM && PPC32 | ||
3 | select FSL_SOC | 4 | select FSL_SOC |
4 | select PPC_CLOCK | 5 | select PPC_CLOCK |
5 | default n | ||
6 | |||
7 | config PPC_MPC5200 | ||
8 | bool | ||
9 | select PPC_MPC52xx | ||
10 | default n | ||
11 | 6 | ||
12 | config PPC_MPC5200_BUGFIX | 7 | config PPC_MPC5200_SIMPLE |
13 | bool "MPC5200 (L25R) bugfix support" | 8 | bool "Generic support for simple MPC5200 based boards" |
14 | depends on PPC_MPC5200 | 9 | depends on PPC_MPC52xx |
15 | default n | 10 | select DEFAULT_UIMAGE |
11 | select WANT_DEVICE_TREE | ||
16 | help | 12 | help |
17 | Enable workarounds for original MPC5200 errata. This is not required | 13 | This option enables support for a simple MPC52xx based boards which |
18 | for MPC5200B based boards. | 14 | do not need a custom platform specific setup. Such boards are |
15 | supported assuming the following: | ||
19 | 16 | ||
20 | It is safe to say 'Y' here | 17 | - GPIO pins are configured by the firmware, |
18 | - CDM configuration (clocking) is setup correctly by firmware, | ||
19 | - if the 'fsl,has-wdt' property is present in one of the | ||
20 | gpt nodes, then it is safe to use such gpt to reset the board, | ||
21 | - PCI is supported if enabled in the kernel configuration | ||
22 | and if there is a PCI bus node defined in the device tree. | ||
23 | |||
24 | Boards that are compatible with this generic platform support | ||
25 | are: 'tqc,tqm5200', 'promess,motionpro', 'schindler,cm5200'. | ||
21 | 26 | ||
22 | config PPC_EFIKA | 27 | config PPC_EFIKA |
23 | bool "bPlan Efika 5k2. MPC5200B based computer" | 28 | bool "bPlan Efika 5k2. MPC5200B based computer" |
24 | depends on PPC_MULTIPLATFORM && PPC32 | 29 | depends on PPC_MPC52xx |
25 | select PPC_RTAS | 30 | select PPC_RTAS |
26 | select RTAS_PROC | 31 | select RTAS_PROC |
27 | select PPC_MPC52xx | ||
28 | select PPC_NATIVE | 32 | select PPC_NATIVE |
29 | default n | ||
30 | 33 | ||
31 | config PPC_LITE5200 | 34 | config PPC_LITE5200 |
32 | bool "Freescale Lite5200 Eval Board" | 35 | bool "Freescale Lite5200 Eval Board" |
33 | depends on PPC_MULTIPLATFORM && PPC32 | 36 | depends on PPC_MPC52xx |
37 | select DEFAULT_UIMAGE | ||
34 | select WANT_DEVICE_TREE | 38 | select WANT_DEVICE_TREE |
35 | select PPC_MPC5200 | ||
36 | default n | ||
37 | 39 | ||
40 | config PPC_MPC5200_BUGFIX | ||
41 | bool "MPC5200 (L25R) bugfix support" | ||
42 | depends on PPC_MPC52xx | ||
43 | help | ||
44 | Enable workarounds for original MPC5200 errata. This is not required | ||
45 | for MPC5200B based boards. | ||
46 | |||
47 | It is safe to say 'Y' here | ||
38 | 48 | ||
diff --git a/arch/powerpc/platforms/52xx/Makefile b/arch/powerpc/platforms/52xx/Makefile index 307dbc178091..fe1b81bb5224 100644 --- a/arch/powerpc/platforms/52xx/Makefile +++ b/arch/powerpc/platforms/52xx/Makefile | |||
@@ -6,6 +6,7 @@ obj-y += mpc52xx_pic.o mpc52xx_common.o | |||
6 | obj-$(CONFIG_PCI) += mpc52xx_pci.o | 6 | obj-$(CONFIG_PCI) += mpc52xx_pci.o |
7 | endif | 7 | endif |
8 | 8 | ||
9 | obj-$(CONFIG_PPC_MPC5200_SIMPLE) += mpc5200_simple.o | ||
9 | obj-$(CONFIG_PPC_EFIKA) += efika.o | 10 | obj-$(CONFIG_PPC_EFIKA) += efika.o |
10 | obj-$(CONFIG_PPC_LITE5200) += lite5200.o | 11 | obj-$(CONFIG_PPC_LITE5200) += lite5200.o |
11 | 12 | ||
diff --git a/arch/powerpc/platforms/52xx/efika.c b/arch/powerpc/platforms/52xx/efika.c index a0da70c8b502..a2068faef6ea 100644 --- a/arch/powerpc/platforms/52xx/efika.c +++ b/arch/powerpc/platforms/52xx/efika.c | |||
@@ -180,6 +180,9 @@ static void __init efika_setup_arch(void) | |||
180 | { | 180 | { |
181 | rtas_initialize(); | 181 | rtas_initialize(); |
182 | 182 | ||
183 | /* Map important registers from the internal memory map */ | ||
184 | mpc52xx_map_common_devices(); | ||
185 | |||
183 | efika_pcisetup(); | 186 | efika_pcisetup(); |
184 | 187 | ||
185 | #ifdef CONFIG_PM | 188 | #ifdef CONFIG_PM |
diff --git a/arch/powerpc/platforms/52xx/lite5200.c b/arch/powerpc/platforms/52xx/lite5200.c index 25d2bfa3d9dc..956f459e175c 100644 --- a/arch/powerpc/platforms/52xx/lite5200.c +++ b/arch/powerpc/platforms/52xx/lite5200.c | |||
@@ -32,6 +32,19 @@ | |||
32 | * | 32 | * |
33 | */ | 33 | */ |
34 | 34 | ||
35 | /* mpc5200 device tree match tables */ | ||
36 | static struct of_device_id mpc5200_cdm_ids[] __initdata = { | ||
37 | { .compatible = "fsl,mpc5200-cdm", }, | ||
38 | { .compatible = "mpc5200-cdm", }, | ||
39 | {} | ||
40 | }; | ||
41 | |||
42 | static struct of_device_id mpc5200_gpio_ids[] __initdata = { | ||
43 | { .compatible = "fsl,mpc5200-gpio", }, | ||
44 | { .compatible = "mpc5200-gpio", }, | ||
45 | {} | ||
46 | }; | ||
47 | |||
35 | /* | 48 | /* |
36 | * Fix clock configuration. | 49 | * Fix clock configuration. |
37 | * | 50 | * |
@@ -42,10 +55,12 @@ | |||
42 | static void __init | 55 | static void __init |
43 | lite5200_fix_clock_config(void) | 56 | lite5200_fix_clock_config(void) |
44 | { | 57 | { |
58 | struct device_node *np; | ||
45 | struct mpc52xx_cdm __iomem *cdm; | 59 | struct mpc52xx_cdm __iomem *cdm; |
46 | |||
47 | /* Map zones */ | 60 | /* Map zones */ |
48 | cdm = mpc52xx_find_and_map("mpc5200-cdm"); | 61 | np = of_find_matching_node(NULL, mpc5200_cdm_ids); |
62 | cdm = of_iomap(np, 0); | ||
63 | of_node_put(np); | ||
49 | if (!cdm) { | 64 | if (!cdm) { |
50 | printk(KERN_ERR "%s() failed; expect abnormal behaviour\n", | 65 | printk(KERN_ERR "%s() failed; expect abnormal behaviour\n", |
51 | __FUNCTION__); | 66 | __FUNCTION__); |
@@ -74,10 +89,13 @@ lite5200_fix_clock_config(void) | |||
74 | static void __init | 89 | static void __init |
75 | lite5200_fix_port_config(void) | 90 | lite5200_fix_port_config(void) |
76 | { | 91 | { |
92 | struct device_node *np; | ||
77 | struct mpc52xx_gpio __iomem *gpio; | 93 | struct mpc52xx_gpio __iomem *gpio; |
78 | u32 port_config; | 94 | u32 port_config; |
79 | 95 | ||
80 | gpio = mpc52xx_find_and_map("mpc5200-gpio"); | 96 | np = of_find_matching_node(NULL, mpc5200_gpio_ids); |
97 | gpio = of_iomap(np, 0); | ||
98 | of_node_put(np); | ||
81 | if (!gpio) { | 99 | if (!gpio) { |
82 | printk(KERN_ERR "%s() failed. expect abnormal behavior\n", | 100 | printk(KERN_ERR "%s() failed. expect abnormal behavior\n", |
83 | __FUNCTION__); | 101 | __FUNCTION__); |
@@ -131,22 +149,18 @@ static void lite5200_resume_finish(void __iomem *mbar) | |||
131 | 149 | ||
132 | static void __init lite5200_setup_arch(void) | 150 | static void __init lite5200_setup_arch(void) |
133 | { | 151 | { |
134 | #ifdef CONFIG_PCI | ||
135 | struct device_node *np; | ||
136 | #endif | ||
137 | |||
138 | if (ppc_md.progress) | 152 | if (ppc_md.progress) |
139 | ppc_md.progress("lite5200_setup_arch()", 0); | 153 | ppc_md.progress("lite5200_setup_arch()", 0); |
140 | 154 | ||
141 | /* Fix things that firmware should have done. */ | 155 | /* Map important registers from the internal memory map */ |
142 | lite5200_fix_clock_config(); | 156 | mpc52xx_map_common_devices(); |
143 | lite5200_fix_port_config(); | ||
144 | 157 | ||
145 | /* Some mpc5200 & mpc5200b related configuration */ | 158 | /* Some mpc5200 & mpc5200b related configuration */ |
146 | mpc5200_setup_xlb_arbiter(); | 159 | mpc5200_setup_xlb_arbiter(); |
147 | 160 | ||
148 | /* Map wdt for mpc52xx_restart() */ | 161 | /* Fix things that firmware should have done. */ |
149 | mpc52xx_map_wdt(); | 162 | lite5200_fix_clock_config(); |
163 | lite5200_fix_port_config(); | ||
150 | 164 | ||
151 | #ifdef CONFIG_PM | 165 | #ifdef CONFIG_PM |
152 | mpc52xx_suspend.board_suspend_prepare = lite5200_suspend_prepare; | 166 | mpc52xx_suspend.board_suspend_prepare = lite5200_suspend_prepare; |
@@ -154,13 +168,7 @@ static void __init lite5200_setup_arch(void) | |||
154 | lite5200_pm_init(); | 168 | lite5200_pm_init(); |
155 | #endif | 169 | #endif |
156 | 170 | ||
157 | #ifdef CONFIG_PCI | 171 | mpc52xx_setup_pci(); |
158 | np = of_find_node_by_type(NULL, "pci"); | ||
159 | if (np) { | ||
160 | mpc52xx_add_bridge(np); | ||
161 | of_node_put(np); | ||
162 | } | ||
163 | #endif | ||
164 | } | 172 | } |
165 | 173 | ||
166 | /* | 174 | /* |
diff --git a/arch/powerpc/platforms/52xx/lite5200_pm.c b/arch/powerpc/platforms/52xx/lite5200_pm.c index ffa14aff5248..c0f13e8deb0b 100644 --- a/arch/powerpc/platforms/52xx/lite5200_pm.c +++ b/arch/powerpc/platforms/52xx/lite5200_pm.c | |||
@@ -42,6 +42,15 @@ static int lite5200_pm_set_target(suspend_state_t state) | |||
42 | 42 | ||
43 | static int lite5200_pm_prepare(void) | 43 | static int lite5200_pm_prepare(void) |
44 | { | 44 | { |
45 | struct device_node *np; | ||
46 | const struct of_device_id immr_ids[] = { | ||
47 | { .compatible = "fsl,mpc5200-immr", }, | ||
48 | { .compatible = "fsl,mpc5200b-immr", }, | ||
49 | { .type = "soc", .compatible = "mpc5200", }, /* lite5200 */ | ||
50 | { .type = "builtin", .compatible = "mpc5200", }, /* efika */ | ||
51 | {} | ||
52 | }; | ||
53 | |||
45 | /* deep sleep? let mpc52xx code handle that */ | 54 | /* deep sleep? let mpc52xx code handle that */ |
46 | if (lite5200_pm_target_state == PM_SUSPEND_STANDBY) | 55 | if (lite5200_pm_target_state == PM_SUSPEND_STANDBY) |
47 | return mpc52xx_pm_prepare(); | 56 | return mpc52xx_pm_prepare(); |
@@ -50,7 +59,9 @@ static int lite5200_pm_prepare(void) | |||
50 | return -EINVAL; | 59 | return -EINVAL; |
51 | 60 | ||
52 | /* map registers */ | 61 | /* map registers */ |
53 | mbar = mpc52xx_find_and_map("mpc5200"); | 62 | np = of_find_matching_node(NULL, immr_ids); |
63 | mbar = of_iomap(np, 0); | ||
64 | of_node_put(np); | ||
54 | if (!mbar) { | 65 | if (!mbar) { |
55 | printk(KERN_ERR "%s:%i Error mapping registers\n", __func__, __LINE__); | 66 | printk(KERN_ERR "%s:%i Error mapping registers\n", __func__, __LINE__); |
56 | return -ENOSYS; | 67 | return -ENOSYS; |
diff --git a/arch/powerpc/platforms/52xx/mpc5200_simple.c b/arch/powerpc/platforms/52xx/mpc5200_simple.c new file mode 100644 index 000000000000..c48b82bc2aad --- /dev/null +++ b/arch/powerpc/platforms/52xx/mpc5200_simple.c | |||
@@ -0,0 +1,85 @@ | |||
1 | /* | ||
2 | * Support for 'mpc5200-simple-platform' compatible boards. | ||
3 | * | ||
4 | * Written by Marian Balakowicz <m8@semihalf.com> | ||
5 | * Copyright (C) 2007 Semihalf | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | * Description: | ||
13 | * This code implements support for a simple MPC52xx based boards which | ||
14 | * do not need a custom platform specific setup. Such boards are | ||
15 | * supported assuming the following: | ||
16 | * | ||
17 | * - GPIO pins are configured by the firmware, | ||
18 | * - CDM configuration (clocking) is setup correctly by firmware, | ||
19 | * - if the 'fsl,has-wdt' property is present in one of the | ||
20 | * gpt nodes, then it is safe to use such gpt to reset the board, | ||
21 | * - PCI is supported if enabled in the kernel configuration | ||
22 | * and if there is a PCI bus node defined in the device tree. | ||
23 | * | ||
24 | * Boards that are compatible with this generic platform support | ||
25 | * are listed in a 'board' table. | ||
26 | */ | ||
27 | |||
28 | #undef DEBUG | ||
29 | #include <asm/time.h> | ||
30 | #include <asm/prom.h> | ||
31 | #include <asm/machdep.h> | ||
32 | #include <asm/mpc52xx.h> | ||
33 | |||
34 | /* | ||
35 | * Setup the architecture | ||
36 | */ | ||
37 | static void __init mpc5200_simple_setup_arch(void) | ||
38 | { | ||
39 | if (ppc_md.progress) | ||
40 | ppc_md.progress("mpc5200_simple_setup_arch()", 0); | ||
41 | |||
42 | /* Map important registers from the internal memory map */ | ||
43 | mpc52xx_map_common_devices(); | ||
44 | |||
45 | /* Some mpc5200 & mpc5200b related configuration */ | ||
46 | mpc5200_setup_xlb_arbiter(); | ||
47 | |||
48 | mpc52xx_setup_pci(); | ||
49 | } | ||
50 | |||
51 | /* list of the supported boards */ | ||
52 | static char *board[] __initdata = { | ||
53 | "promess,motionpro", | ||
54 | "schindler,cm5200", | ||
55 | "tqc,tqm5200", | ||
56 | NULL | ||
57 | }; | ||
58 | |||
59 | /* | ||
60 | * Called very early, MMU is off, device-tree isn't unflattened | ||
61 | */ | ||
62 | static int __init mpc5200_simple_probe(void) | ||
63 | { | ||
64 | unsigned long node = of_get_flat_dt_root(); | ||
65 | int i = 0; | ||
66 | |||
67 | while (board[i]) { | ||
68 | if (of_flat_dt_is_compatible(node, board[i])) | ||
69 | break; | ||
70 | i++; | ||
71 | } | ||
72 | |||
73 | return (board[i] != NULL); | ||
74 | } | ||
75 | |||
76 | define_machine(mpc5200_simple_platform) { | ||
77 | .name = "mpc5200-simple-platform", | ||
78 | .probe = mpc5200_simple_probe, | ||
79 | .setup_arch = mpc5200_simple_setup_arch, | ||
80 | .init = mpc52xx_declare_of_platform_devices, | ||
81 | .init_IRQ = mpc52xx_init_irq, | ||
82 | .get_irq = mpc52xx_get_irq, | ||
83 | .restart = mpc52xx_restart, | ||
84 | .calibrate_decr = generic_calibrate_decr, | ||
85 | }; | ||
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_common.c b/arch/powerpc/platforms/52xx/mpc52xx_common.c index 9850685c5429..9aa4425d80b2 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_common.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_common.c | |||
@@ -13,57 +13,38 @@ | |||
13 | #undef DEBUG | 13 | #undef DEBUG |
14 | 14 | ||
15 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
16 | #include <linux/spinlock.h> | ||
16 | #include <linux/of_platform.h> | 17 | #include <linux/of_platform.h> |
17 | #include <asm/io.h> | 18 | #include <asm/io.h> |
18 | #include <asm/prom.h> | 19 | #include <asm/prom.h> |
19 | #include <asm/mpc52xx.h> | 20 | #include <asm/mpc52xx.h> |
20 | 21 | ||
22 | /* MPC5200 device tree match tables */ | ||
23 | static struct of_device_id mpc52xx_xlb_ids[] __initdata = { | ||
24 | { .compatible = "fsl,mpc5200-xlb", }, | ||
25 | { .compatible = "mpc5200-xlb", }, | ||
26 | {} | ||
27 | }; | ||
28 | static struct of_device_id mpc52xx_bus_ids[] __initdata = { | ||
29 | { .compatible = "fsl,mpc5200-immr", }, | ||
30 | { .compatible = "fsl,mpc5200b-immr", }, | ||
31 | { .compatible = "fsl,lpb", }, | ||
32 | |||
33 | /* depreciated matches; shouldn't be used in new device trees */ | ||
34 | { .type = "builtin", .compatible = "mpc5200", }, /* efika */ | ||
35 | { .type = "soc", .compatible = "mpc5200", }, /* lite5200 */ | ||
36 | {} | ||
37 | }; | ||
38 | |||
21 | /* | 39 | /* |
22 | * This variable is mapped in mpc52xx_map_wdt() and used in mpc52xx_restart(). | 40 | * This variable is mapped in mpc52xx_map_wdt() and used in mpc52xx_restart(). |
23 | * Permanent mapping is required because mpc52xx_restart() can be called | 41 | * Permanent mapping is required because mpc52xx_restart() can be called |
24 | * from interrupt context while node mapping (which calls ioremap()) | 42 | * from interrupt context while node mapping (which calls ioremap()) |
25 | * cannot be used at such point. | 43 | * cannot be used at such point. |
26 | */ | 44 | */ |
27 | static volatile struct mpc52xx_gpt *mpc52xx_wdt = NULL; | 45 | static spinlock_t mpc52xx_lock = SPIN_LOCK_UNLOCKED; |
28 | 46 | static struct mpc52xx_gpt __iomem *mpc52xx_wdt; | |
29 | static void __iomem * | 47 | static struct mpc52xx_cdm __iomem *mpc52xx_cdm; |
30 | mpc52xx_map_node(struct device_node *ofn) | ||
31 | { | ||
32 | const u32 *regaddr_p; | ||
33 | u64 regaddr64, size64; | ||
34 | |||
35 | if (!ofn) | ||
36 | return NULL; | ||
37 | |||
38 | regaddr_p = of_get_address(ofn, 0, &size64, NULL); | ||
39 | if (!regaddr_p) { | ||
40 | of_node_put(ofn); | ||
41 | return NULL; | ||
42 | } | ||
43 | |||
44 | regaddr64 = of_translate_address(ofn, regaddr_p); | ||
45 | |||
46 | of_node_put(ofn); | ||
47 | |||
48 | return ioremap((u32)regaddr64, (u32)size64); | ||
49 | } | ||
50 | |||
51 | void __iomem * | ||
52 | mpc52xx_find_and_map(const char *compatible) | ||
53 | { | ||
54 | return mpc52xx_map_node( | ||
55 | of_find_compatible_node(NULL, NULL, compatible)); | ||
56 | } | ||
57 | |||
58 | EXPORT_SYMBOL(mpc52xx_find_and_map); | ||
59 | |||
60 | void __iomem * | ||
61 | mpc52xx_find_and_map_path(const char *path) | ||
62 | { | ||
63 | return mpc52xx_map_node(of_find_node_by_path(path)); | ||
64 | } | ||
65 | |||
66 | EXPORT_SYMBOL(mpc52xx_find_and_map_path); | ||
67 | 48 | ||
68 | /** | 49 | /** |
69 | * mpc52xx_find_ipb_freq - Find the IPB bus frequency for a device | 50 | * mpc52xx_find_ipb_freq - Find the IPB bus frequency for a device |
@@ -101,9 +82,12 @@ EXPORT_SYMBOL(mpc52xx_find_ipb_freq); | |||
101 | void __init | 82 | void __init |
102 | mpc5200_setup_xlb_arbiter(void) | 83 | mpc5200_setup_xlb_arbiter(void) |
103 | { | 84 | { |
85 | struct device_node *np; | ||
104 | struct mpc52xx_xlb __iomem *xlb; | 86 | struct mpc52xx_xlb __iomem *xlb; |
105 | 87 | ||
106 | xlb = mpc52xx_find_and_map("mpc5200-xlb"); | 88 | np = of_find_matching_node(NULL, mpc52xx_xlb_ids); |
89 | xlb = of_iomap(np, 0); | ||
90 | of_node_put(np); | ||
107 | if (!xlb) { | 91 | if (!xlb) { |
108 | printk(KERN_ERR __FILE__ ": " | 92 | printk(KERN_ERR __FILE__ ": " |
109 | "Error mapping XLB in mpc52xx_setup_cpu(). " | 93 | "Error mapping XLB in mpc52xx_setup_cpu(). " |
@@ -124,41 +108,101 @@ mpc5200_setup_xlb_arbiter(void) | |||
124 | iounmap(xlb); | 108 | iounmap(xlb); |
125 | } | 109 | } |
126 | 110 | ||
111 | /** | ||
112 | * mpc52xx_declare_of_platform_devices: register internal devices and children | ||
113 | * of the localplus bus to the of_platform | ||
114 | * bus. | ||
115 | */ | ||
127 | void __init | 116 | void __init |
128 | mpc52xx_declare_of_platform_devices(void) | 117 | mpc52xx_declare_of_platform_devices(void) |
129 | { | 118 | { |
130 | /* Find every child of the SOC node and add it to of_platform */ | 119 | /* Find every child of the SOC node and add it to of_platform */ |
131 | if (of_platform_bus_probe(NULL, NULL, NULL)) | 120 | if (of_platform_bus_probe(NULL, mpc52xx_bus_ids, NULL)) |
132 | printk(KERN_ERR __FILE__ ": " | 121 | printk(KERN_ERR __FILE__ ": " |
133 | "Error while probing of_platform bus\n"); | 122 | "Error while probing of_platform bus\n"); |
134 | } | 123 | } |
135 | 124 | ||
125 | /* | ||
126 | * match tables used by mpc52xx_map_common_devices() | ||
127 | */ | ||
128 | static struct of_device_id mpc52xx_gpt_ids[] __initdata = { | ||
129 | { .compatible = "fsl,mpc5200-gpt", }, | ||
130 | { .compatible = "mpc5200-gpt", }, /* old */ | ||
131 | {} | ||
132 | }; | ||
133 | static struct of_device_id mpc52xx_cdm_ids[] __initdata = { | ||
134 | { .compatible = "fsl,mpc5200-cdm", }, | ||
135 | { .compatible = "mpc5200-cdm", }, /* old */ | ||
136 | {} | ||
137 | }; | ||
138 | |||
139 | /** | ||
140 | * mpc52xx_map_common_devices: iomap devices required by common code | ||
141 | */ | ||
136 | void __init | 142 | void __init |
137 | mpc52xx_map_wdt(void) | 143 | mpc52xx_map_common_devices(void) |
138 | { | 144 | { |
139 | const void *has_wdt; | ||
140 | struct device_node *np; | 145 | struct device_node *np; |
141 | 146 | ||
142 | /* mpc52xx_wdt is mapped here and used in mpc52xx_restart, | 147 | /* mpc52xx_wdt is mapped here and used in mpc52xx_restart, |
143 | * possibly from a interrupt context. wdt is only implement | 148 | * possibly from a interrupt context. wdt is only implement |
144 | * on a gpt0, so check has-wdt property before mapping. | 149 | * on a gpt0, so check has-wdt property before mapping. |
145 | */ | 150 | */ |
146 | for_each_compatible_node(np, NULL, "fsl,mpc5200-gpt") { | 151 | for_each_matching_node(np, mpc52xx_gpt_ids) { |
147 | has_wdt = of_get_property(np, "fsl,has-wdt", NULL); | 152 | if (of_get_property(np, "fsl,has-wdt", NULL) || |
148 | if (has_wdt) { | 153 | of_get_property(np, "has-wdt", NULL)) { |
149 | mpc52xx_wdt = mpc52xx_map_node(np); | 154 | mpc52xx_wdt = of_iomap(np, 0); |
150 | return; | 155 | of_node_put(np); |
156 | break; | ||
151 | } | 157 | } |
152 | } | 158 | } |
153 | for_each_compatible_node(np, NULL, "mpc5200-gpt") { | 159 | |
154 | has_wdt = of_get_property(np, "has-wdt", NULL); | 160 | /* Clock Distribution Module, used by PSC clock setting function */ |
155 | if (has_wdt) { | 161 | np = of_find_matching_node(NULL, mpc52xx_cdm_ids); |
156 | mpc52xx_wdt = mpc52xx_map_node(np); | 162 | mpc52xx_cdm = of_iomap(np, 0); |
157 | return; | 163 | of_node_put(np); |
158 | } | 164 | } |
165 | |||
166 | /** | ||
167 | * mpc52xx_set_psc_clkdiv: Set clock divider in the CDM for PSC ports | ||
168 | * | ||
169 | * @psc_id: id of psc port; must be 1,2,3 or 6 | ||
170 | * @clkdiv: clock divider value to put into CDM PSC register. | ||
171 | */ | ||
172 | int mpc52xx_set_psc_clkdiv(int psc_id, int clkdiv) | ||
173 | { | ||
174 | unsigned long flags; | ||
175 | u16 __iomem *reg; | ||
176 | u32 val; | ||
177 | u32 mask; | ||
178 | u32 mclken_div; | ||
179 | |||
180 | if (!mpc52xx_cdm) | ||
181 | return -ENODEV; | ||
182 | |||
183 | mclken_div = 0x8000 | (clkdiv & 0x1FF); | ||
184 | switch (psc_id) { | ||
185 | case 1: reg = &mpc52xx_cdm->mclken_div_psc1; mask = 0x20; break; | ||
186 | case 2: reg = &mpc52xx_cdm->mclken_div_psc2; mask = 0x40; break; | ||
187 | case 3: reg = &mpc52xx_cdm->mclken_div_psc3; mask = 0x80; break; | ||
188 | case 6: reg = &mpc52xx_cdm->mclken_div_psc6; mask = 0x10; break; | ||
189 | default: | ||
190 | return -ENODEV; | ||
159 | } | 191 | } |
192 | |||
193 | /* Set the rate and enable the clock */ | ||
194 | spin_lock_irqsave(&mpc52xx_lock, flags); | ||
195 | out_be16(reg, mclken_div); | ||
196 | val = in_be32(&mpc52xx_cdm->clk_enables); | ||
197 | out_be32(&mpc52xx_cdm->clk_enables, val | mask); | ||
198 | spin_unlock_irqrestore(&mpc52xx_lock, flags); | ||
199 | |||
200 | return 0; | ||
160 | } | 201 | } |
161 | 202 | ||
203 | /** | ||
204 | * mpc52xx_restart: ppc_md->restart hook for mpc5200 using the watchdog timer | ||
205 | */ | ||
162 | void | 206 | void |
163 | mpc52xx_restart(char *cmd) | 207 | mpc52xx_restart(char *cmd) |
164 | { | 208 | { |
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pci.c b/arch/powerpc/platforms/52xx/mpc52xx_pci.c index 4c6c82a684b1..e3428ddd9040 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pci.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pci.c | |||
@@ -99,6 +99,12 @@ struct mpc52xx_pci { | |||
99 | u8 reserved6[4]; /* PCI + 0xFC */ | 99 | u8 reserved6[4]; /* PCI + 0xFC */ |
100 | }; | 100 | }; |
101 | 101 | ||
102 | /* MPC5200 device tree match tables */ | ||
103 | const struct of_device_id mpc52xx_pci_ids[] __initdata = { | ||
104 | { .type = "pci", .compatible = "fsl,mpc5200-pci", }, | ||
105 | { .type = "pci", .compatible = "mpc5200-pci", }, | ||
106 | {} | ||
107 | }; | ||
102 | 108 | ||
103 | /* ======================================================================== */ | 109 | /* ======================================================================== */ |
104 | /* PCI configuration acess */ | 110 | /* PCI configuration acess */ |
@@ -363,7 +369,7 @@ mpc52xx_add_bridge(struct device_node *node) | |||
363 | 369 | ||
364 | pr_debug("Adding MPC52xx PCI host bridge %s\n", node->full_name); | 370 | pr_debug("Adding MPC52xx PCI host bridge %s\n", node->full_name); |
365 | 371 | ||
366 | pci_assign_all_buses = 1; | 372 | ppc_pci_flags |= PPC_PCI_REASSIGN_ALL_BUS; |
367 | 373 | ||
368 | if (of_address_to_resource(node, 0, &rsrc) != 0) { | 374 | if (of_address_to_resource(node, 0, &rsrc) != 0) { |
369 | printk(KERN_ERR "Can't get %s resources\n", node->full_name); | 375 | printk(KERN_ERR "Can't get %s resources\n", node->full_name); |
@@ -406,3 +412,15 @@ mpc52xx_add_bridge(struct device_node *node) | |||
406 | 412 | ||
407 | return 0; | 413 | return 0; |
408 | } | 414 | } |
415 | |||
416 | void __init mpc52xx_setup_pci(void) | ||
417 | { | ||
418 | struct device_node *pci; | ||
419 | |||
420 | pci = of_find_matching_node(NULL, mpc52xx_pci_ids); | ||
421 | if (!pci) | ||
422 | return; | ||
423 | |||
424 | mpc52xx_add_bridge(pci); | ||
425 | of_node_put(pci); | ||
426 | } | ||
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pic.c b/arch/powerpc/platforms/52xx/mpc52xx_pic.c index 61100f270c68..d0dead8b9a95 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pic.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pic.c | |||
@@ -29,6 +29,18 @@ | |||
29 | * | 29 | * |
30 | */ | 30 | */ |
31 | 31 | ||
32 | /* MPC5200 device tree match tables */ | ||
33 | static struct of_device_id mpc52xx_pic_ids[] __initdata = { | ||
34 | { .compatible = "fsl,mpc5200-pic", }, | ||
35 | { .compatible = "mpc5200-pic", }, | ||
36 | {} | ||
37 | }; | ||
38 | static struct of_device_id mpc52xx_sdma_ids[] __initdata = { | ||
39 | { .compatible = "fsl,mpc5200-bestcomm", }, | ||
40 | { .compatible = "mpc5200-bestcomm", }, | ||
41 | {} | ||
42 | }; | ||
43 | |||
32 | static struct mpc52xx_intr __iomem *intr; | 44 | static struct mpc52xx_intr __iomem *intr; |
33 | static struct mpc52xx_sdma __iomem *sdma; | 45 | static struct mpc52xx_sdma __iomem *sdma; |
34 | static struct irq_host *mpc52xx_irqhost = NULL; | 46 | static struct irq_host *mpc52xx_irqhost = NULL; |
@@ -364,16 +376,18 @@ void __init mpc52xx_init_irq(void) | |||
364 | { | 376 | { |
365 | u32 intr_ctrl; | 377 | u32 intr_ctrl; |
366 | struct device_node *picnode; | 378 | struct device_node *picnode; |
379 | struct device_node *np; | ||
367 | 380 | ||
368 | /* Remap the necessary zones */ | 381 | /* Remap the necessary zones */ |
369 | picnode = of_find_compatible_node(NULL, NULL, "mpc5200-pic"); | 382 | picnode = of_find_matching_node(NULL, mpc52xx_pic_ids); |
370 | 383 | intr = of_iomap(picnode, 0); | |
371 | intr = mpc52xx_find_and_map("mpc5200-pic"); | ||
372 | if (!intr) | 384 | if (!intr) |
373 | panic(__FILE__ ": find_and_map failed on 'mpc5200-pic'. " | 385 | panic(__FILE__ ": find_and_map failed on 'mpc5200-pic'. " |
374 | "Check node !"); | 386 | "Check node !"); |
375 | 387 | ||
376 | sdma = mpc52xx_find_and_map("mpc5200-bestcomm"); | 388 | np = of_find_matching_node(NULL, mpc52xx_sdma_ids); |
389 | sdma = of_iomap(np, 0); | ||
390 | of_node_put(np); | ||
377 | if (!sdma) | 391 | if (!sdma) |
378 | panic(__FILE__ ": find_and_map failed on 'mpc5200-bestcomm'. " | 392 | panic(__FILE__ ": find_and_map failed on 'mpc5200-bestcomm'. " |
379 | "Check node !"); | 393 | "Check node !"); |
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pm.c b/arch/powerpc/platforms/52xx/mpc52xx_pm.c index 7ffa7babf254..c72d3304387f 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pm.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pm.c | |||
@@ -59,10 +59,21 @@ int mpc52xx_set_wakeup_gpio(u8 pin, u8 level) | |||
59 | 59 | ||
60 | int mpc52xx_pm_prepare(void) | 60 | int mpc52xx_pm_prepare(void) |
61 | { | 61 | { |
62 | struct device_node *np; | ||
63 | const struct of_device_id immr_ids[] = { | ||
64 | { .compatible = "fsl,mpc5200-immr", }, | ||
65 | { .compatible = "fsl,mpc5200b-immr", }, | ||
66 | { .type = "soc", .compatible = "mpc5200", }, /* lite5200 */ | ||
67 | { .type = "builtin", .compatible = "mpc5200", }, /* efika */ | ||
68 | {} | ||
69 | }; | ||
70 | |||
62 | /* map the whole register space */ | 71 | /* map the whole register space */ |
63 | mbar = mpc52xx_find_and_map("mpc5200"); | 72 | np = of_find_matching_node(NULL, immr_ids); |
73 | mbar = of_iomap(np, 0); | ||
74 | of_node_put(np); | ||
64 | if (!mbar) { | 75 | if (!mbar) { |
65 | printk(KERN_ERR "%s:%i Error mapping registers\n", __func__, __LINE__); | 76 | pr_err("mpc52xx_pm_prepare(): could not map registers\n"); |
66 | return -ENOSYS; | 77 | return -ENOSYS; |
67 | } | 78 | } |
68 | /* these offsets are from mpc5200 users manual */ | 79 | /* these offsets are from mpc5200 users manual */ |
diff --git a/arch/powerpc/platforms/82xx/Kconfig b/arch/powerpc/platforms/82xx/Kconfig index 541fbb815631..4fad6c7bf9f1 100644 --- a/arch/powerpc/platforms/82xx/Kconfig +++ b/arch/powerpc/platforms/82xx/Kconfig | |||
@@ -26,6 +26,19 @@ config PQ2FADS | |||
26 | help | 26 | help |
27 | This option enables support for the PQ2FADS board | 27 | This option enables support for the PQ2FADS board |
28 | 28 | ||
29 | config EP8248E | ||
30 | bool "Embedded Planet EP8248E (a.k.a. CWH-PPC-8248N-VE)" | ||
31 | select 8272 | ||
32 | select 8260 | ||
33 | select FSL_SOC | ||
34 | select PPC_CPM_NEW_BINDING | ||
35 | select MDIO_BITBANG | ||
36 | help | ||
37 | This enables support for the Embedded Planet EP8248E board. | ||
38 | |||
39 | This board is also resold by Freescale as the QUICCStart | ||
40 | MPC8248 Evaluation System and/or the CWH-PPC-8248N-VE. | ||
41 | |||
29 | endchoice | 42 | endchoice |
30 | 43 | ||
31 | config PQ2ADS | 44 | config PQ2ADS |
diff --git a/arch/powerpc/platforms/82xx/Makefile b/arch/powerpc/platforms/82xx/Makefile index 68c8b0c9772b..6cd5cd59bf2a 100644 --- a/arch/powerpc/platforms/82xx/Makefile +++ b/arch/powerpc/platforms/82xx/Makefile | |||
@@ -5,3 +5,4 @@ obj-$(CONFIG_MPC8272_ADS) += mpc8272_ads.o | |||
5 | obj-$(CONFIG_CPM2) += pq2.o | 5 | obj-$(CONFIG_CPM2) += pq2.o |
6 | obj-$(CONFIG_PQ2_ADS_PCI_PIC) += pq2ads-pci-pic.o | 6 | obj-$(CONFIG_PQ2_ADS_PCI_PIC) += pq2ads-pci-pic.o |
7 | obj-$(CONFIG_PQ2FADS) += pq2fads.o | 7 | obj-$(CONFIG_PQ2FADS) += pq2fads.o |
8 | obj-$(CONFIG_EP8248E) += ep8248e.o | ||
diff --git a/arch/powerpc/platforms/82xx/ep8248e.c b/arch/powerpc/platforms/82xx/ep8248e.c new file mode 100644 index 000000000000..ba93d8ae9b0c --- /dev/null +++ b/arch/powerpc/platforms/82xx/ep8248e.c | |||
@@ -0,0 +1,324 @@ | |||
1 | /* | ||
2 | * Embedded Planet EP8248E support | ||
3 | * | ||
4 | * Copyright 2007 Freescale Semiconductor, Inc. | ||
5 | * Author: Scott Wood <scottwood@freescale.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/init.h> | ||
14 | #include <linux/interrupt.h> | ||
15 | #include <linux/fsl_devices.h> | ||
16 | #include <linux/mdio-bitbang.h> | ||
17 | #include <linux/of_platform.h> | ||
18 | |||
19 | #include <asm/io.h> | ||
20 | #include <asm/cpm2.h> | ||
21 | #include <asm/udbg.h> | ||
22 | #include <asm/machdep.h> | ||
23 | #include <asm/time.h> | ||
24 | #include <asm/mpc8260.h> | ||
25 | #include <asm/prom.h> | ||
26 | |||
27 | #include <sysdev/fsl_soc.h> | ||
28 | #include <sysdev/cpm2_pic.h> | ||
29 | |||
30 | #include "pq2.h" | ||
31 | |||
32 | static u8 __iomem *ep8248e_bcsr; | ||
33 | static struct device_node *ep8248e_bcsr_node; | ||
34 | |||
35 | #define BCSR7_SCC2_ENABLE 0x10 | ||
36 | |||
37 | #define BCSR8_PHY1_ENABLE 0x80 | ||
38 | #define BCSR8_PHY1_POWER 0x40 | ||
39 | #define BCSR8_PHY2_ENABLE 0x20 | ||
40 | #define BCSR8_PHY2_POWER 0x10 | ||
41 | #define BCSR8_MDIO_READ 0x04 | ||
42 | #define BCSR8_MDIO_CLOCK 0x02 | ||
43 | #define BCSR8_MDIO_DATA 0x01 | ||
44 | |||
45 | #define BCSR9_USB_ENABLE 0x80 | ||
46 | #define BCSR9_USB_POWER 0x40 | ||
47 | #define BCSR9_USB_HOST 0x20 | ||
48 | #define BCSR9_USB_FULL_SPEED_TARGET 0x10 | ||
49 | |||
50 | static void __init ep8248e_pic_init(void) | ||
51 | { | ||
52 | struct device_node *np = of_find_compatible_node(NULL, NULL, "fsl,pq2-pic"); | ||
53 | if (!np) { | ||
54 | printk(KERN_ERR "PIC init: can not find cpm-pic node\n"); | ||
55 | return; | ||
56 | } | ||
57 | |||
58 | cpm2_pic_init(np); | ||
59 | of_node_put(np); | ||
60 | } | ||
61 | |||
62 | static void ep8248e_set_mdc(struct mdiobb_ctrl *ctrl, int level) | ||
63 | { | ||
64 | if (level) | ||
65 | setbits8(&ep8248e_bcsr[8], BCSR8_MDIO_CLOCK); | ||
66 | else | ||
67 | clrbits8(&ep8248e_bcsr[8], BCSR8_MDIO_CLOCK); | ||
68 | |||
69 | /* Read back to flush the write. */ | ||
70 | in_8(&ep8248e_bcsr[8]); | ||
71 | } | ||
72 | |||
73 | static void ep8248e_set_mdio_dir(struct mdiobb_ctrl *ctrl, int output) | ||
74 | { | ||
75 | if (output) | ||
76 | clrbits8(&ep8248e_bcsr[8], BCSR8_MDIO_READ); | ||
77 | else | ||
78 | setbits8(&ep8248e_bcsr[8], BCSR8_MDIO_READ); | ||
79 | |||
80 | /* Read back to flush the write. */ | ||
81 | in_8(&ep8248e_bcsr[8]); | ||
82 | } | ||
83 | |||
84 | static void ep8248e_set_mdio_data(struct mdiobb_ctrl *ctrl, int data) | ||
85 | { | ||
86 | if (data) | ||
87 | setbits8(&ep8248e_bcsr[8], BCSR8_MDIO_DATA); | ||
88 | else | ||
89 | clrbits8(&ep8248e_bcsr[8], BCSR8_MDIO_DATA); | ||
90 | |||
91 | /* Read back to flush the write. */ | ||
92 | in_8(&ep8248e_bcsr[8]); | ||
93 | } | ||
94 | |||
95 | static int ep8248e_get_mdio_data(struct mdiobb_ctrl *ctrl) | ||
96 | { | ||
97 | return in_8(&ep8248e_bcsr[8]) & BCSR8_MDIO_DATA; | ||
98 | } | ||
99 | |||
100 | static const struct mdiobb_ops ep8248e_mdio_ops = { | ||
101 | .set_mdc = ep8248e_set_mdc, | ||
102 | .set_mdio_dir = ep8248e_set_mdio_dir, | ||
103 | .set_mdio_data = ep8248e_set_mdio_data, | ||
104 | .get_mdio_data = ep8248e_get_mdio_data, | ||
105 | .owner = THIS_MODULE, | ||
106 | }; | ||
107 | |||
108 | static struct mdiobb_ctrl ep8248e_mdio_ctrl = { | ||
109 | .ops = &ep8248e_mdio_ops, | ||
110 | }; | ||
111 | |||
112 | static int __devinit ep8248e_mdio_probe(struct of_device *ofdev, | ||
113 | const struct of_device_id *match) | ||
114 | { | ||
115 | struct mii_bus *bus; | ||
116 | struct resource res; | ||
117 | struct device_node *node; | ||
118 | int ret, i; | ||
119 | |||
120 | node = of_get_parent(ofdev->node); | ||
121 | of_node_put(node); | ||
122 | if (node != ep8248e_bcsr_node) | ||
123 | return -ENODEV; | ||
124 | |||
125 | ret = of_address_to_resource(ofdev->node, 0, &res); | ||
126 | if (ret) | ||
127 | return ret; | ||
128 | |||
129 | bus = alloc_mdio_bitbang(&ep8248e_mdio_ctrl); | ||
130 | if (!bus) | ||
131 | return -ENOMEM; | ||
132 | |||
133 | bus->phy_mask = 0; | ||
134 | bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); | ||
135 | |||
136 | for (i = 0; i < PHY_MAX_ADDR; i++) | ||
137 | bus->irq[i] = -1; | ||
138 | |||
139 | bus->name = "ep8248e-mdio-bitbang"; | ||
140 | bus->dev = &ofdev->dev; | ||
141 | bus->id = res.start; | ||
142 | |||
143 | return mdiobus_register(bus); | ||
144 | } | ||
145 | |||
146 | static int ep8248e_mdio_remove(struct of_device *ofdev) | ||
147 | { | ||
148 | BUG(); | ||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | static const struct of_device_id ep8248e_mdio_match[] = { | ||
153 | { | ||
154 | .compatible = "fsl,ep8248e-mdio-bitbang", | ||
155 | }, | ||
156 | {}, | ||
157 | }; | ||
158 | |||
159 | static struct of_platform_driver ep8248e_mdio_driver = { | ||
160 | .driver = { | ||
161 | .name = "ep8248e-mdio-bitbang", | ||
162 | }, | ||
163 | .match_table = ep8248e_mdio_match, | ||
164 | .probe = ep8248e_mdio_probe, | ||
165 | .remove = ep8248e_mdio_remove, | ||
166 | }; | ||
167 | |||
168 | struct cpm_pin { | ||
169 | int port, pin, flags; | ||
170 | }; | ||
171 | |||
172 | static __initdata struct cpm_pin ep8248e_pins[] = { | ||
173 | /* SMC1 */ | ||
174 | {2, 4, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, | ||
175 | {2, 5, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, | ||
176 | |||
177 | /* SCC1 */ | ||
178 | {2, 14, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, | ||
179 | {2, 15, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, | ||
180 | {3, 29, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, | ||
181 | {3, 30, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, | ||
182 | {3, 31, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, | ||
183 | |||
184 | /* FCC1 */ | ||
185 | {0, 14, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, | ||
186 | {0, 15, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, | ||
187 | {0, 16, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, | ||
188 | {0, 17, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, | ||
189 | {0, 18, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, | ||
190 | {0, 19, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, | ||
191 | {0, 20, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, | ||
192 | {0, 21, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, | ||
193 | {0, 26, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, | ||
194 | {0, 27, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, | ||
195 | {0, 28, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, | ||
196 | {0, 29, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, | ||
197 | {0, 30, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, | ||
198 | {0, 31, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, | ||
199 | {2, 21, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, | ||
200 | {2, 22, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, | ||
201 | |||
202 | /* FCC2 */ | ||
203 | {1, 18, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, | ||
204 | {1, 19, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, | ||
205 | {1, 20, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, | ||
206 | {1, 21, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, | ||
207 | {1, 22, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, | ||
208 | {1, 23, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, | ||
209 | {1, 24, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, | ||
210 | {1, 25, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, | ||
211 | {1, 26, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, | ||
212 | {1, 27, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, | ||
213 | {1, 28, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, | ||
214 | {1, 29, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, | ||
215 | {1, 30, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, | ||
216 | {1, 31, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, | ||
217 | {2, 18, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, | ||
218 | {2, 19, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, | ||
219 | |||
220 | /* I2C */ | ||
221 | {4, 14, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, | ||
222 | {4, 15, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, | ||
223 | |||
224 | /* USB */ | ||
225 | {2, 10, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, | ||
226 | {2, 11, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, | ||
227 | {2, 20, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, | ||
228 | {2, 24, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, | ||
229 | {3, 23, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, | ||
230 | {3, 24, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, | ||
231 | {3, 25, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, | ||
232 | }; | ||
233 | |||
234 | static void __init init_ioports(void) | ||
235 | { | ||
236 | int i; | ||
237 | |||
238 | for (i = 0; i < ARRAY_SIZE(ep8248e_pins); i++) { | ||
239 | const struct cpm_pin *pin = &ep8248e_pins[i]; | ||
240 | cpm2_set_pin(pin->port, pin->pin, pin->flags); | ||
241 | } | ||
242 | |||
243 | cpm2_smc_clk_setup(CPM_CLK_SMC1, CPM_BRG7); | ||
244 | cpm2_clk_setup(CPM_CLK_SCC1, CPM_BRG1, CPM_CLK_RX); | ||
245 | cpm2_clk_setup(CPM_CLK_SCC1, CPM_BRG1, CPM_CLK_TX); | ||
246 | cpm2_clk_setup(CPM_CLK_SCC3, CPM_CLK8, CPM_CLK_TX); /* USB */ | ||
247 | cpm2_clk_setup(CPM_CLK_FCC1, CPM_CLK11, CPM_CLK_RX); | ||
248 | cpm2_clk_setup(CPM_CLK_FCC1, CPM_CLK10, CPM_CLK_TX); | ||
249 | cpm2_clk_setup(CPM_CLK_FCC2, CPM_CLK13, CPM_CLK_RX); | ||
250 | cpm2_clk_setup(CPM_CLK_FCC2, CPM_CLK14, CPM_CLK_TX); | ||
251 | } | ||
252 | |||
253 | static void __init ep8248e_setup_arch(void) | ||
254 | { | ||
255 | if (ppc_md.progress) | ||
256 | ppc_md.progress("ep8248e_setup_arch()", 0); | ||
257 | |||
258 | cpm2_reset(); | ||
259 | |||
260 | /* When this is set, snooping CPM DMA from RAM causes | ||
261 | * machine checks. See erratum SIU18. | ||
262 | */ | ||
263 | clrbits32(&cpm2_immr->im_siu_conf.siu_82xx.sc_bcr, MPC82XX_BCR_PLDP); | ||
264 | |||
265 | ep8248e_bcsr_node = | ||
266 | of_find_compatible_node(NULL, NULL, "fsl,ep8248e-bcsr"); | ||
267 | if (!ep8248e_bcsr_node) { | ||
268 | printk(KERN_ERR "No bcsr in device tree\n"); | ||
269 | return; | ||
270 | } | ||
271 | |||
272 | ep8248e_bcsr = of_iomap(ep8248e_bcsr_node, 0); | ||
273 | if (!ep8248e_bcsr) { | ||
274 | printk(KERN_ERR "Cannot map BCSR registers\n"); | ||
275 | of_node_put(ep8248e_bcsr_node); | ||
276 | ep8248e_bcsr_node = NULL; | ||
277 | return; | ||
278 | } | ||
279 | |||
280 | setbits8(&ep8248e_bcsr[7], BCSR7_SCC2_ENABLE); | ||
281 | setbits8(&ep8248e_bcsr[8], BCSR8_PHY1_ENABLE | BCSR8_PHY1_POWER | | ||
282 | BCSR8_PHY2_ENABLE | BCSR8_PHY2_POWER); | ||
283 | |||
284 | init_ioports(); | ||
285 | |||
286 | if (ppc_md.progress) | ||
287 | ppc_md.progress("ep8248e_setup_arch(), finish", 0); | ||
288 | } | ||
289 | |||
290 | static __initdata struct of_device_id of_bus_ids[] = { | ||
291 | { .compatible = "simple-bus", }, | ||
292 | { .compatible = "fsl,ep8248e-bcsr", }, | ||
293 | {}, | ||
294 | }; | ||
295 | |||
296 | static int __init declare_of_platform_devices(void) | ||
297 | { | ||
298 | of_platform_bus_probe(NULL, of_bus_ids, NULL); | ||
299 | of_register_platform_driver(&ep8248e_mdio_driver); | ||
300 | |||
301 | return 0; | ||
302 | } | ||
303 | machine_device_initcall(ep8248e, declare_of_platform_devices); | ||
304 | |||
305 | /* | ||
306 | * Called very early, device-tree isn't unflattened | ||
307 | */ | ||
308 | static int __init ep8248e_probe(void) | ||
309 | { | ||
310 | unsigned long root = of_get_flat_dt_root(); | ||
311 | return of_flat_dt_is_compatible(root, "fsl,ep8248e"); | ||
312 | } | ||
313 | |||
314 | define_machine(ep8248e) | ||
315 | { | ||
316 | .name = "Embedded Planet EP8248E", | ||
317 | .probe = ep8248e_probe, | ||
318 | .setup_arch = ep8248e_setup_arch, | ||
319 | .init_IRQ = ep8248e_pic_init, | ||
320 | .get_irq = cpm2_get_irq, | ||
321 | .calibrate_decr = generic_calibrate_decr, | ||
322 | .restart = pq2_restart, | ||
323 | .progress = udbg_progress, | ||
324 | }; | ||
diff --git a/arch/powerpc/platforms/82xx/mpc8272_ads.c b/arch/powerpc/platforms/82xx/mpc8272_ads.c index fd83440eb287..3fce6b375dbc 100644 --- a/arch/powerpc/platforms/82xx/mpc8272_ads.c +++ b/arch/powerpc/platforms/82xx/mpc8272_ads.c | |||
@@ -165,14 +165,11 @@ static struct of_device_id __initdata of_bus_ids[] = { | |||
165 | 165 | ||
166 | static int __init declare_of_platform_devices(void) | 166 | static int __init declare_of_platform_devices(void) |
167 | { | 167 | { |
168 | if (!machine_is(mpc8272_ads)) | ||
169 | return 0; | ||
170 | |||
171 | /* Publish the QE devices */ | 168 | /* Publish the QE devices */ |
172 | of_platform_bus_probe(NULL, of_bus_ids, NULL); | 169 | of_platform_bus_probe(NULL, of_bus_ids, NULL); |
173 | return 0; | 170 | return 0; |
174 | } | 171 | } |
175 | device_initcall(declare_of_platform_devices); | 172 | machine_device_initcall(mpc8272_ads, declare_of_platform_devices); |
176 | 173 | ||
177 | /* | 174 | /* |
178 | * Called very early, device-tree isn't unflattened | 175 | * Called very early, device-tree isn't unflattened |
diff --git a/arch/powerpc/platforms/82xx/pq2.c b/arch/powerpc/platforms/82xx/pq2.c index a497cbaa1ac5..1b75902fad64 100644 --- a/arch/powerpc/platforms/82xx/pq2.c +++ b/arch/powerpc/platforms/82xx/pq2.c | |||
@@ -53,13 +53,13 @@ static void __init pq2_pci_add_bridge(struct device_node *np) | |||
53 | if (of_address_to_resource(np, 0, &r) || r.end - r.start < 0x10b) | 53 | if (of_address_to_resource(np, 0, &r) || r.end - r.start < 0x10b) |
54 | goto err; | 54 | goto err; |
55 | 55 | ||
56 | pci_assign_all_buses = 1; | 56 | ppc_pci_flags |= PPC_PCI_REASSIGN_ALL_BUS; |
57 | 57 | ||
58 | hose = pcibios_alloc_controller(np); | 58 | hose = pcibios_alloc_controller(np); |
59 | if (!hose) | 59 | if (!hose) |
60 | return; | 60 | return; |
61 | 61 | ||
62 | hose->arch_data = np; | 62 | hose->dn = np; |
63 | 63 | ||
64 | setup_indirect_pci(hose, r.start + 0x100, r.start + 0x104, 0); | 64 | setup_indirect_pci(hose, r.start + 0x100, r.start + 0x104, 0); |
65 | pci_process_bridge_OF_ranges(hose, np, 1); | 65 | pci_process_bridge_OF_ranges(hose, np, 1); |
diff --git a/arch/powerpc/platforms/82xx/pq2fads.c b/arch/powerpc/platforms/82xx/pq2fads.c index 4f457a9c79ae..68196e349994 100644 --- a/arch/powerpc/platforms/82xx/pq2fads.c +++ b/arch/powerpc/platforms/82xx/pq2fads.c | |||
@@ -15,12 +15,12 @@ | |||
15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
16 | #include <linux/interrupt.h> | 16 | #include <linux/interrupt.h> |
17 | #include <linux/fsl_devices.h> | 17 | #include <linux/fsl_devices.h> |
18 | #include <linux/of_platform.h> | ||
18 | 19 | ||
19 | #include <asm/io.h> | 20 | #include <asm/io.h> |
20 | #include <asm/cpm2.h> | 21 | #include <asm/cpm2.h> |
21 | #include <asm/udbg.h> | 22 | #include <asm/udbg.h> |
22 | #include <asm/machdep.h> | 23 | #include <asm/machdep.h> |
23 | #include <asm/of_platform.h> | ||
24 | #include <asm/time.h> | 24 | #include <asm/time.h> |
25 | 25 | ||
26 | #include <sysdev/fsl_soc.h> | 26 | #include <sysdev/fsl_soc.h> |
@@ -176,14 +176,11 @@ static struct of_device_id __initdata of_bus_ids[] = { | |||
176 | 176 | ||
177 | static int __init declare_of_platform_devices(void) | 177 | static int __init declare_of_platform_devices(void) |
178 | { | 178 | { |
179 | if (!machine_is(pq2fads)) | ||
180 | return 0; | ||
181 | |||
182 | /* Publish the QE devices */ | 179 | /* Publish the QE devices */ |
183 | of_platform_bus_probe(NULL, of_bus_ids, NULL); | 180 | of_platform_bus_probe(NULL, of_bus_ids, NULL); |
184 | return 0; | 181 | return 0; |
185 | } | 182 | } |
186 | device_initcall(declare_of_platform_devices); | 183 | machine_device_initcall(pq2fads, declare_of_platform_devices); |
187 | 184 | ||
188 | define_machine(pq2fads) | 185 | define_machine(pq2fads) |
189 | { | 186 | { |
diff --git a/arch/powerpc/platforms/83xx/Kconfig b/arch/powerpc/platforms/83xx/Kconfig index ec305f18abd8..13587e2e8680 100644 --- a/arch/powerpc/platforms/83xx/Kconfig +++ b/arch/powerpc/platforms/83xx/Kconfig | |||
@@ -1,18 +1,23 @@ | |||
1 | choice | 1 | menuconfig MPC83xx |
2 | prompt "83xx Board Type" | 2 | bool "83xx Board Type" |
3 | depends on PPC_83xx | 3 | depends on PPC_83xx |
4 | default MPC834x_MDS | 4 | select PPC_UDBG_16550 |
5 | select PPC_INDIRECT_PCI | ||
6 | |||
7 | if MPC83xx | ||
5 | 8 | ||
6 | config MPC8313_RDB | 9 | config MPC831x_RDB |
7 | bool "Freescale MPC8313 RDB" | 10 | bool "Freescale MPC831x RDB" |
8 | select DEFAULT_UIMAGE | 11 | select DEFAULT_UIMAGE |
12 | select PPC_MPC831x | ||
9 | help | 13 | help |
10 | This option enables support for the MPC8313 RDB board. | 14 | This option enables support for the MPC8313 RDB and MPC8315 RDB boards. |
11 | 15 | ||
12 | config MPC832x_MDS | 16 | config MPC832x_MDS |
13 | bool "Freescale MPC832x MDS" | 17 | bool "Freescale MPC832x MDS" |
14 | select DEFAULT_UIMAGE | 18 | select DEFAULT_UIMAGE |
15 | select QUICC_ENGINE | 19 | select QUICC_ENGINE |
20 | select PPC_MPC832x | ||
16 | help | 21 | help |
17 | This option enables support for the MPC832x MDS evaluation board. | 22 | This option enables support for the MPC832x MDS evaluation board. |
18 | 23 | ||
@@ -20,12 +25,14 @@ config MPC832x_RDB | |||
20 | bool "Freescale MPC832x RDB" | 25 | bool "Freescale MPC832x RDB" |
21 | select DEFAULT_UIMAGE | 26 | select DEFAULT_UIMAGE |
22 | select QUICC_ENGINE | 27 | select QUICC_ENGINE |
28 | select PPC_MPC832x | ||
23 | help | 29 | help |
24 | This option enables support for the MPC8323 RDB board. | 30 | This option enables support for the MPC8323 RDB board. |
25 | 31 | ||
26 | config MPC834x_MDS | 32 | config MPC834x_MDS |
27 | bool "Freescale MPC834x MDS" | 33 | bool "Freescale MPC834x MDS" |
28 | select DEFAULT_UIMAGE | 34 | select DEFAULT_UIMAGE |
35 | select PPC_MPC834x | ||
29 | help | 36 | help |
30 | This option enables support for the MPC 834x MDS evaluation board. | 37 | This option enables support for the MPC 834x MDS evaluation board. |
31 | 38 | ||
@@ -37,6 +44,7 @@ config MPC834x_MDS | |||
37 | config MPC834x_ITX | 44 | config MPC834x_ITX |
38 | bool "Freescale MPC834x ITX" | 45 | bool "Freescale MPC834x ITX" |
39 | select DEFAULT_UIMAGE | 46 | select DEFAULT_UIMAGE |
47 | select PPC_MPC834x | ||
40 | help | 48 | help |
41 | This option enables support for the MPC 834x ITX evaluation board. | 49 | This option enables support for the MPC 834x ITX evaluation board. |
42 | 50 | ||
@@ -50,28 +58,41 @@ config MPC836x_MDS | |||
50 | help | 58 | help |
51 | This option enables support for the MPC836x MDS Processor Board. | 59 | This option enables support for the MPC836x MDS Processor Board. |
52 | 60 | ||
53 | endchoice | 61 | config MPC837x_MDS |
62 | bool "Freescale MPC837x MDS" | ||
63 | select DEFAULT_UIMAGE | ||
64 | select PPC_MPC837x | ||
65 | help | ||
66 | This option enables support for the MPC837x MDS Processor Board. | ||
67 | |||
68 | config MPC837x_RDB | ||
69 | bool "Freescale MPC837x RDB" | ||
70 | select DEFAULT_UIMAGE | ||
71 | select PPC_MPC837x | ||
72 | help | ||
73 | This option enables support for the MPC837x RDB Board. | ||
74 | |||
75 | config SBC834x | ||
76 | bool "Wind River SBC834x" | ||
77 | select DEFAULT_UIMAGE | ||
78 | select PPC_MPC834x | ||
79 | help | ||
80 | This option enables support for the Wind River SBC834x board. | ||
81 | |||
82 | endif | ||
54 | 83 | ||
84 | # used for usb | ||
55 | config PPC_MPC831x | 85 | config PPC_MPC831x |
56 | bool | 86 | bool |
57 | select PPC_UDBG_16550 | ||
58 | select PPC_INDIRECT_PCI | ||
59 | default y if MPC8313_RDB | ||
60 | 87 | ||
88 | # used for math-emu | ||
61 | config PPC_MPC832x | 89 | config PPC_MPC832x |
62 | bool | 90 | bool |
63 | select PPC_UDBG_16550 | ||
64 | select PPC_INDIRECT_PCI | ||
65 | default y if MPC832x_MDS || MPC832x_RDB | ||
66 | 91 | ||
67 | config MPC834x | 92 | # used for usb |
93 | config PPC_MPC834x | ||
68 | bool | 94 | bool |
69 | select PPC_UDBG_16550 | ||
70 | select PPC_INDIRECT_PCI | ||
71 | default y if MPC834x_MDS || MPC834x_ITX | ||
72 | 95 | ||
73 | config PPC_MPC836x | 96 | # used for usb |
97 | config PPC_MPC837x | ||
74 | bool | 98 | bool |
75 | select PPC_UDBG_16550 | ||
76 | select PPC_INDIRECT_PCI | ||
77 | default y if MPC836x_MDS | ||
diff --git a/arch/powerpc/platforms/83xx/Makefile b/arch/powerpc/platforms/83xx/Makefile index 5a98f885779f..7e6dd3e259d8 100644 --- a/arch/powerpc/platforms/83xx/Makefile +++ b/arch/powerpc/platforms/83xx/Makefile | |||
@@ -3,9 +3,12 @@ | |||
3 | # | 3 | # |
4 | obj-y := misc.o usb.o | 4 | obj-y := misc.o usb.o |
5 | obj-$(CONFIG_PCI) += pci.o | 5 | obj-$(CONFIG_PCI) += pci.o |
6 | obj-$(CONFIG_MPC8313_RDB) += mpc8313_rdb.o | 6 | obj-$(CONFIG_MPC831x_RDB) += mpc831x_rdb.o |
7 | obj-$(CONFIG_MPC832x_RDB) += mpc832x_rdb.o | 7 | obj-$(CONFIG_MPC832x_RDB) += mpc832x_rdb.o |
8 | obj-$(CONFIG_MPC834x_MDS) += mpc834x_mds.o | 8 | obj-$(CONFIG_MPC834x_MDS) += mpc834x_mds.o |
9 | obj-$(CONFIG_MPC834x_ITX) += mpc834x_itx.o | 9 | obj-$(CONFIG_MPC834x_ITX) += mpc834x_itx.o |
10 | obj-$(CONFIG_MPC836x_MDS) += mpc836x_mds.o | 10 | obj-$(CONFIG_MPC836x_MDS) += mpc836x_mds.o |
11 | obj-$(CONFIG_MPC832x_MDS) += mpc832x_mds.o | 11 | obj-$(CONFIG_MPC832x_MDS) += mpc832x_mds.o |
12 | obj-$(CONFIG_MPC837x_MDS) += mpc837x_mds.o | ||
13 | obj-$(CONFIG_SBC834x) += sbc834x.o | ||
14 | obj-$(CONFIG_MPC837x_RDB) += mpc837x_rdb.o | ||
diff --git a/arch/powerpc/platforms/83xx/mpc8313_rdb.c b/arch/powerpc/platforms/83xx/mpc831x_rdb.c index 33766b8f2594..c4db5172b27a 100644 --- a/arch/powerpc/platforms/83xx/mpc8313_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc831x_rdb.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * arch/powerpc/platforms/83xx/mpc8313_rdb.c | 2 | * arch/powerpc/platforms/83xx/mpc831x_rdb.c |
3 | * | 3 | * |
4 | * Description: MPC8313x RDB board specific routines. | 4 | * Description: MPC831x RDB board specific routines. |
5 | * This file is based on mpc834x_sys.c | 5 | * This file is based on mpc834x_sys.c |
6 | * Author: Lo Wlison <r43300@freescale.com> | 6 | * Author: Lo Wlison <r43300@freescale.com> |
7 | * | 7 | * |
@@ -14,6 +14,7 @@ | |||
14 | */ | 14 | */ |
15 | 15 | ||
16 | #include <linux/pci.h> | 16 | #include <linux/pci.h> |
17 | #include <linux/of_platform.h> | ||
17 | 18 | ||
18 | #include <asm/time.h> | 19 | #include <asm/time.h> |
19 | #include <asm/ipic.h> | 20 | #include <asm/ipic.h> |
@@ -21,26 +22,17 @@ | |||
21 | 22 | ||
22 | #include "mpc83xx.h" | 23 | #include "mpc83xx.h" |
23 | 24 | ||
24 | #undef DEBUG | 25 | /* |
25 | #ifdef DEBUG | ||
26 | #define DBG(fmt...) udbg_printf(fmt) | ||
27 | #else | ||
28 | #define DBG(fmt...) | ||
29 | #endif | ||
30 | |||
31 | /* ************************************************************************ | ||
32 | * | ||
33 | * Setup the architecture | 26 | * Setup the architecture |
34 | * | ||
35 | */ | 27 | */ |
36 | static void __init mpc8313_rdb_setup_arch(void) | 28 | static void __init mpc831x_rdb_setup_arch(void) |
37 | { | 29 | { |
38 | #ifdef CONFIG_PCI | 30 | #ifdef CONFIG_PCI |
39 | struct device_node *np; | 31 | struct device_node *np; |
40 | #endif | 32 | #endif |
41 | 33 | ||
42 | if (ppc_md.progress) | 34 | if (ppc_md.progress) |
43 | ppc_md.progress("mpc8313_rdb_setup_arch()", 0); | 35 | ppc_md.progress("mpc831x_rdb_setup_arch()", 0); |
44 | 36 | ||
45 | #ifdef CONFIG_PCI | 37 | #ifdef CONFIG_PCI |
46 | for_each_compatible_node(np, "pci", "fsl,mpc8349-pci") | 38 | for_each_compatible_node(np, "pci", "fsl,mpc8349-pci") |
@@ -49,7 +41,7 @@ static void __init mpc8313_rdb_setup_arch(void) | |||
49 | mpc831x_usb_cfg(); | 41 | mpc831x_usb_cfg(); |
50 | } | 42 | } |
51 | 43 | ||
52 | void __init mpc8313_rdb_init_IRQ(void) | 44 | void __init mpc831x_rdb_init_IRQ(void) |
53 | { | 45 | { |
54 | struct device_node *np; | 46 | struct device_node *np; |
55 | 47 | ||
@@ -68,18 +60,31 @@ void __init mpc8313_rdb_init_IRQ(void) | |||
68 | /* | 60 | /* |
69 | * Called very early, MMU is off, device-tree isn't unflattened | 61 | * Called very early, MMU is off, device-tree isn't unflattened |
70 | */ | 62 | */ |
71 | static int __init mpc8313_rdb_probe(void) | 63 | static int __init mpc831x_rdb_probe(void) |
72 | { | 64 | { |
73 | unsigned long root = of_get_flat_dt_root(); | 65 | unsigned long root = of_get_flat_dt_root(); |
74 | 66 | ||
75 | return of_flat_dt_is_compatible(root, "MPC8313ERDB"); | 67 | return of_flat_dt_is_compatible(root, "MPC8313ERDB") || |
68 | of_flat_dt_is_compatible(root, "fsl,mpc8315erdb"); | ||
69 | } | ||
70 | |||
71 | static struct of_device_id __initdata of_bus_ids[] = { | ||
72 | { .compatible = "simple-bus" }, | ||
73 | {}, | ||
74 | }; | ||
75 | |||
76 | static int __init declare_of_platform_devices(void) | ||
77 | { | ||
78 | of_platform_bus_probe(NULL, of_bus_ids, NULL); | ||
79 | return 0; | ||
76 | } | 80 | } |
81 | machine_device_initcall(mpc831x_rdb, declare_of_platform_devices); | ||
77 | 82 | ||
78 | define_machine(mpc8313_rdb) { | 83 | define_machine(mpc831x_rdb) { |
79 | .name = "MPC8313 RDB", | 84 | .name = "MPC831x RDB", |
80 | .probe = mpc8313_rdb_probe, | 85 | .probe = mpc831x_rdb_probe, |
81 | .setup_arch = mpc8313_rdb_setup_arch, | 86 | .setup_arch = mpc831x_rdb_setup_arch, |
82 | .init_IRQ = mpc8313_rdb_init_IRQ, | 87 | .init_IRQ = mpc831x_rdb_init_IRQ, |
83 | .get_irq = ipic_get_irq, | 88 | .get_irq = ipic_get_irq, |
84 | .restart = mpc83xx_restart, | 89 | .restart = mpc83xx_restart, |
85 | .time_init = mpc83xx_time_init, | 90 | .time_init = mpc83xx_time_init, |
diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.c b/arch/powerpc/platforms/83xx/mpc832x_mds.c index 39ee7a13b25a..6dbc6eabcb02 100644 --- a/arch/powerpc/platforms/83xx/mpc832x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc832x_mds.c | |||
@@ -23,9 +23,9 @@ | |||
23 | #include <linux/seq_file.h> | 23 | #include <linux/seq_file.h> |
24 | #include <linux/root_dev.h> | 24 | #include <linux/root_dev.h> |
25 | #include <linux/initrd.h> | 25 | #include <linux/initrd.h> |
26 | #include <linux/of_platform.h> | ||
27 | #include <linux/of_device.h> | ||
26 | 28 | ||
27 | #include <asm/of_device.h> | ||
28 | #include <asm/of_platform.h> | ||
29 | #include <asm/system.h> | 29 | #include <asm/system.h> |
30 | #include <asm/atomic.h> | 30 | #include <asm/atomic.h> |
31 | #include <asm/time.h> | 31 | #include <asm/time.h> |
@@ -105,20 +105,18 @@ static struct of_device_id mpc832x_ids[] = { | |||
105 | { .type = "soc", }, | 105 | { .type = "soc", }, |
106 | { .compatible = "soc", }, | 106 | { .compatible = "soc", }, |
107 | { .type = "qe", }, | 107 | { .type = "qe", }, |
108 | { .compatible = "fsl,qe", }, | ||
108 | {}, | 109 | {}, |
109 | }; | 110 | }; |
110 | 111 | ||
111 | static int __init mpc832x_declare_of_platform_devices(void) | 112 | static int __init mpc832x_declare_of_platform_devices(void) |
112 | { | 113 | { |
113 | if (!machine_is(mpc832x_mds)) | ||
114 | return 0; | ||
115 | |||
116 | /* Publish the QE devices */ | 114 | /* Publish the QE devices */ |
117 | of_platform_bus_probe(NULL, mpc832x_ids, NULL); | 115 | of_platform_bus_probe(NULL, mpc832x_ids, NULL); |
118 | 116 | ||
119 | return 0; | 117 | return 0; |
120 | } | 118 | } |
121 | device_initcall(mpc832x_declare_of_platform_devices); | 119 | machine_device_initcall(mpc832x_mds, mpc832x_declare_of_platform_devices); |
122 | 120 | ||
123 | static void __init mpc832x_sys_init_IRQ(void) | 121 | static void __init mpc832x_sys_init_IRQ(void) |
124 | { | 122 | { |
@@ -137,10 +135,12 @@ static void __init mpc832x_sys_init_IRQ(void) | |||
137 | of_node_put(np); | 135 | of_node_put(np); |
138 | 136 | ||
139 | #ifdef CONFIG_QUICC_ENGINE | 137 | #ifdef CONFIG_QUICC_ENGINE |
140 | np = of_find_node_by_type(NULL, "qeic"); | 138 | np = of_find_compatible_node(NULL, NULL, "fsl,qe-ic"); |
141 | if (!np) | 139 | if (!np) { |
142 | return; | 140 | np = of_find_node_by_type(NULL, "qeic"); |
143 | 141 | if (!np) | |
142 | return; | ||
143 | } | ||
144 | qe_ic_init(np, 0, qe_ic_cascade_low_ipic, qe_ic_cascade_high_ipic); | 144 | qe_ic_init(np, 0, qe_ic_cascade_low_ipic, qe_ic_cascade_high_ipic); |
145 | of_node_put(np); | 145 | of_node_put(np); |
146 | #endif /* CONFIG_QUICC_ENGINE */ | 146 | #endif /* CONFIG_QUICC_ENGINE */ |
diff --git a/arch/powerpc/platforms/83xx/mpc832x_rdb.c b/arch/powerpc/platforms/83xx/mpc832x_rdb.c index d4bd04001b99..9f0fd88b2b1f 100644 --- a/arch/powerpc/platforms/83xx/mpc832x_rdb.c +++ b/arch/powerpc/platforms/83xx/mpc832x_rdb.c | |||
@@ -19,8 +19,8 @@ | |||
19 | #include <linux/spi/spi.h> | 19 | #include <linux/spi/spi.h> |
20 | #include <linux/spi/mmc_spi.h> | 20 | #include <linux/spi/mmc_spi.h> |
21 | #include <linux/mmc/host.h> | 21 | #include <linux/mmc/host.h> |
22 | #include <linux/of_platform.h> | ||
22 | 23 | ||
23 | #include <asm/of_platform.h> | ||
24 | #include <asm/time.h> | 24 | #include <asm/time.h> |
25 | #include <asm/ipic.h> | 25 | #include <asm/ipic.h> |
26 | #include <asm/udbg.h> | 26 | #include <asm/udbg.h> |
@@ -63,9 +63,6 @@ static struct spi_board_info mpc832x_spi_boardinfo = { | |||
63 | 63 | ||
64 | static int __init mpc832x_spi_init(void) | 64 | static int __init mpc832x_spi_init(void) |
65 | { | 65 | { |
66 | if (!machine_is(mpc832x_rdb)) | ||
67 | return 0; | ||
68 | |||
69 | par_io_config_pin(3, 0, 3, 0, 1, 0); /* SPI1 MOSI, I/O */ | 66 | par_io_config_pin(3, 0, 3, 0, 1, 0); /* SPI1 MOSI, I/O */ |
70 | par_io_config_pin(3, 1, 3, 0, 1, 0); /* SPI1 MISO, I/O */ | 67 | par_io_config_pin(3, 1, 3, 0, 1, 0); /* SPI1 MISO, I/O */ |
71 | par_io_config_pin(3, 2, 3, 0, 1, 0); /* SPI1 CLK, I/O */ | 68 | par_io_config_pin(3, 2, 3, 0, 1, 0); /* SPI1 CLK, I/O */ |
@@ -80,7 +77,7 @@ static int __init mpc832x_spi_init(void) | |||
80 | mpc83xx_spi_deactivate_cs); | 77 | mpc83xx_spi_deactivate_cs); |
81 | } | 78 | } |
82 | 79 | ||
83 | device_initcall(mpc832x_spi_init); | 80 | machine_device_initcall(mpc832x_rdb, mpc832x_spi_init); |
84 | 81 | ||
85 | /* ************************************************************************ | 82 | /* ************************************************************************ |
86 | * | 83 | * |
@@ -118,20 +115,18 @@ static struct of_device_id mpc832x_ids[] = { | |||
118 | { .type = "soc", }, | 115 | { .type = "soc", }, |
119 | { .compatible = "soc", }, | 116 | { .compatible = "soc", }, |
120 | { .type = "qe", }, | 117 | { .type = "qe", }, |
118 | { .compatible = "fsl,qe", }, | ||
121 | {}, | 119 | {}, |
122 | }; | 120 | }; |
123 | 121 | ||
124 | static int __init mpc832x_declare_of_platform_devices(void) | 122 | static int __init mpc832x_declare_of_platform_devices(void) |
125 | { | 123 | { |
126 | if (!machine_is(mpc832x_rdb)) | ||
127 | return 0; | ||
128 | |||
129 | /* Publish the QE devices */ | 124 | /* Publish the QE devices */ |
130 | of_platform_bus_probe(NULL, mpc832x_ids, NULL); | 125 | of_platform_bus_probe(NULL, mpc832x_ids, NULL); |
131 | 126 | ||
132 | return 0; | 127 | return 0; |
133 | } | 128 | } |
134 | device_initcall(mpc832x_declare_of_platform_devices); | 129 | machine_device_initcall(mpc832x_rdb, mpc832x_declare_of_platform_devices); |
135 | 130 | ||
136 | void __init mpc832x_rdb_init_IRQ(void) | 131 | void __init mpc832x_rdb_init_IRQ(void) |
137 | { | 132 | { |
@@ -151,10 +146,12 @@ void __init mpc832x_rdb_init_IRQ(void) | |||
151 | of_node_put(np); | 146 | of_node_put(np); |
152 | 147 | ||
153 | #ifdef CONFIG_QUICC_ENGINE | 148 | #ifdef CONFIG_QUICC_ENGINE |
154 | np = of_find_node_by_type(NULL, "qeic"); | 149 | np = of_find_compatible_node(NULL, NULL, "fsl,qe-ic"); |
155 | if (!np) | 150 | if (!np) { |
156 | return; | 151 | np = of_find_node_by_type(NULL, "qeic"); |
157 | 152 | if (!np) | |
153 | return; | ||
154 | } | ||
158 | qe_ic_init(np, 0, qe_ic_cascade_low_ipic, qe_ic_cascade_high_ipic); | 155 | qe_ic_init(np, 0, qe_ic_cascade_low_ipic, qe_ic_cascade_high_ipic); |
159 | of_node_put(np); | 156 | of_node_put(np); |
160 | #endif /* CONFIG_QUICC_ENGINE */ | 157 | #endif /* CONFIG_QUICC_ENGINE */ |
diff --git a/arch/powerpc/platforms/83xx/mpc834x_itx.c b/arch/powerpc/platforms/83xx/mpc834x_itx.c index aa768199432d..50e8f632061c 100644 --- a/arch/powerpc/platforms/83xx/mpc834x_itx.c +++ b/arch/powerpc/platforms/83xx/mpc834x_itx.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
24 | #include <linux/seq_file.h> | 24 | #include <linux/seq_file.h> |
25 | #include <linux/root_dev.h> | 25 | #include <linux/root_dev.h> |
26 | #include <linux/of_platform.h> | ||
26 | 27 | ||
27 | #include <asm/system.h> | 28 | #include <asm/system.h> |
28 | #include <asm/atomic.h> | 29 | #include <asm/atomic.h> |
@@ -37,6 +38,17 @@ | |||
37 | 38 | ||
38 | #include "mpc83xx.h" | 39 | #include "mpc83xx.h" |
39 | 40 | ||
41 | static struct of_device_id __initdata mpc834x_itx_ids[] = { | ||
42 | { .compatible = "fsl,pq2pro-localbus", }, | ||
43 | {}, | ||
44 | }; | ||
45 | |||
46 | static int __init mpc834x_itx_declare_of_platform_devices(void) | ||
47 | { | ||
48 | return of_platform_bus_probe(NULL, mpc834x_itx_ids, NULL); | ||
49 | } | ||
50 | machine_device_initcall(mpc834x_itx, mpc834x_itx_declare_of_platform_devices); | ||
51 | |||
40 | /* ************************************************************************ | 52 | /* ************************************************************************ |
41 | * | 53 | * |
42 | * Setup the architecture | 54 | * Setup the architecture |
diff --git a/arch/powerpc/platforms/83xx/mpc834x_mds.c b/arch/powerpc/platforms/83xx/mpc834x_mds.c index a81bb3ce6b94..2b8a0a3f8557 100644 --- a/arch/powerpc/platforms/83xx/mpc834x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc834x_mds.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
24 | #include <linux/seq_file.h> | 24 | #include <linux/seq_file.h> |
25 | #include <linux/root_dev.h> | 25 | #include <linux/root_dev.h> |
26 | #include <linux/of_platform.h> | ||
26 | 27 | ||
27 | #include <asm/system.h> | 28 | #include <asm/system.h> |
28 | #include <asm/atomic.h> | 29 | #include <asm/atomic.h> |
@@ -106,14 +107,27 @@ static void __init mpc834x_mds_init_IRQ(void) | |||
106 | ipic_set_default_priority(); | 107 | ipic_set_default_priority(); |
107 | } | 108 | } |
108 | 109 | ||
110 | static struct of_device_id mpc834x_ids[] = { | ||
111 | { .type = "soc", }, | ||
112 | { .compatible = "soc", }, | ||
113 | {}, | ||
114 | }; | ||
115 | |||
116 | static int __init mpc834x_declare_of_platform_devices(void) | ||
117 | { | ||
118 | of_platform_bus_probe(NULL, mpc834x_ids, NULL); | ||
119 | return 0; | ||
120 | } | ||
121 | machine_device_initcall(mpc834x_mds, mpc834x_declare_of_platform_devices); | ||
122 | |||
109 | /* | 123 | /* |
110 | * Called very early, MMU is off, device-tree isn't unflattened | 124 | * Called very early, MMU is off, device-tree isn't unflattened |
111 | */ | 125 | */ |
112 | static int __init mpc834x_mds_probe(void) | 126 | static int __init mpc834x_mds_probe(void) |
113 | { | 127 | { |
114 | unsigned long root = of_get_flat_dt_root(); | 128 | unsigned long root = of_get_flat_dt_root(); |
115 | 129 | ||
116 | return of_flat_dt_is_compatible(root, "MPC834xMDS"); | 130 | return of_flat_dt_is_compatible(root, "MPC834xMDS"); |
117 | } | 131 | } |
118 | 132 | ||
119 | define_machine(mpc834x_mds) { | 133 | define_machine(mpc834x_mds) { |
diff --git a/arch/powerpc/platforms/83xx/mpc836x_mds.c b/arch/powerpc/platforms/83xx/mpc836x_mds.c index e40012f8f488..c2e5de60c055 100644 --- a/arch/powerpc/platforms/83xx/mpc836x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc836x_mds.c | |||
@@ -29,9 +29,9 @@ | |||
29 | #include <linux/seq_file.h> | 29 | #include <linux/seq_file.h> |
30 | #include <linux/root_dev.h> | 30 | #include <linux/root_dev.h> |
31 | #include <linux/initrd.h> | 31 | #include <linux/initrd.h> |
32 | #include <linux/of_platform.h> | ||
33 | #include <linux/of_device.h> | ||
32 | 34 | ||
33 | #include <asm/of_device.h> | ||
34 | #include <asm/of_platform.h> | ||
35 | #include <asm/system.h> | 35 | #include <asm/system.h> |
36 | #include <asm/atomic.h> | 36 | #include <asm/atomic.h> |
37 | #include <asm/time.h> | 37 | #include <asm/time.h> |
@@ -136,20 +136,18 @@ static struct of_device_id mpc836x_ids[] = { | |||
136 | { .type = "soc", }, | 136 | { .type = "soc", }, |
137 | { .compatible = "soc", }, | 137 | { .compatible = "soc", }, |
138 | { .type = "qe", }, | 138 | { .type = "qe", }, |
139 | { .compatible = "fsl,qe", }, | ||
139 | {}, | 140 | {}, |
140 | }; | 141 | }; |
141 | 142 | ||
142 | static int __init mpc836x_declare_of_platform_devices(void) | 143 | static int __init mpc836x_declare_of_platform_devices(void) |
143 | { | 144 | { |
144 | if (!machine_is(mpc836x_mds)) | ||
145 | return 0; | ||
146 | |||
147 | /* Publish the QE devices */ | 145 | /* Publish the QE devices */ |
148 | of_platform_bus_probe(NULL, mpc836x_ids, NULL); | 146 | of_platform_bus_probe(NULL, mpc836x_ids, NULL); |
149 | 147 | ||
150 | return 0; | 148 | return 0; |
151 | } | 149 | } |
152 | device_initcall(mpc836x_declare_of_platform_devices); | 150 | machine_device_initcall(mpc836x_mds, mpc836x_declare_of_platform_devices); |
153 | 151 | ||
154 | static void __init mpc836x_mds_init_IRQ(void) | 152 | static void __init mpc836x_mds_init_IRQ(void) |
155 | { | 153 | { |
@@ -168,10 +166,12 @@ static void __init mpc836x_mds_init_IRQ(void) | |||
168 | of_node_put(np); | 166 | of_node_put(np); |
169 | 167 | ||
170 | #ifdef CONFIG_QUICC_ENGINE | 168 | #ifdef CONFIG_QUICC_ENGINE |
171 | np = of_find_node_by_type(NULL, "qeic"); | 169 | np = of_find_compatible_node(NULL, NULL, "fsl,qe-ic"); |
172 | if (!np) | 170 | if (!np) { |
173 | return; | 171 | np = of_find_node_by_type(NULL, "qeic"); |
174 | 172 | if (!np) | |
173 | return; | ||
174 | } | ||
175 | qe_ic_init(np, 0, qe_ic_cascade_low_ipic, qe_ic_cascade_high_ipic); | 175 | qe_ic_init(np, 0, qe_ic_cascade_low_ipic, qe_ic_cascade_high_ipic); |
176 | of_node_put(np); | 176 | of_node_put(np); |
177 | #endif /* CONFIG_QUICC_ENGINE */ | 177 | #endif /* CONFIG_QUICC_ENGINE */ |
diff --git a/arch/powerpc/platforms/83xx/mpc837x_mds.c b/arch/powerpc/platforms/83xx/mpc837x_mds.c new file mode 100644 index 000000000000..8a9c26973605 --- /dev/null +++ b/arch/powerpc/platforms/83xx/mpc837x_mds.c | |||
@@ -0,0 +1,147 @@ | |||
1 | /* | ||
2 | * arch/powerpc/platforms/83xx/mpc837x_mds.c | ||
3 | * | ||
4 | * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved. | ||
5 | * | ||
6 | * MPC837x MDS board specific routines | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/pci.h> | ||
15 | #include <linux/of.h> | ||
16 | #include <linux/of_platform.h> | ||
17 | |||
18 | #include <asm/time.h> | ||
19 | #include <asm/ipic.h> | ||
20 | #include <asm/udbg.h> | ||
21 | #include <asm/prom.h> | ||
22 | |||
23 | #include "mpc83xx.h" | ||
24 | |||
25 | #define BCSR12_USB_SER_MASK 0x8a | ||
26 | #define BCSR12_USB_SER_PIN 0x80 | ||
27 | #define BCSR12_USB_SER_DEVICE 0x02 | ||
28 | extern int mpc837x_usb_cfg(void); | ||
29 | |||
30 | static int mpc837xmds_usb_cfg(void) | ||
31 | { | ||
32 | struct device_node *np; | ||
33 | const void *phy_type, *mode; | ||
34 | void __iomem *bcsr_regs = NULL; | ||
35 | u8 bcsr12; | ||
36 | int ret; | ||
37 | |||
38 | ret = mpc837x_usb_cfg(); | ||
39 | if (ret) | ||
40 | return ret; | ||
41 | /* Map BCSR area */ | ||
42 | np = of_find_node_by_name(NULL, "bcsr"); | ||
43 | if (np) { | ||
44 | struct resource res; | ||
45 | |||
46 | of_address_to_resource(np, 0, &res); | ||
47 | bcsr_regs = ioremap(res.start, res.end - res.start + 1); | ||
48 | of_node_put(np); | ||
49 | } | ||
50 | if (!bcsr_regs) | ||
51 | return -1; | ||
52 | |||
53 | np = of_find_node_by_name(NULL, "usb"); | ||
54 | if (!np) | ||
55 | return -ENODEV; | ||
56 | phy_type = of_get_property(np, "phy_type", NULL); | ||
57 | if (phy_type && !strcmp(phy_type, "ulpi")) { | ||
58 | clrbits8(bcsr_regs + 12, BCSR12_USB_SER_PIN); | ||
59 | } else if (phy_type && !strcmp(phy_type, "serial")) { | ||
60 | mode = of_get_property(np, "dr_mode", NULL); | ||
61 | bcsr12 = in_8(bcsr_regs + 12) & ~BCSR12_USB_SER_MASK; | ||
62 | bcsr12 |= BCSR12_USB_SER_PIN; | ||
63 | if (mode && !strcmp(mode, "peripheral")) | ||
64 | bcsr12 |= BCSR12_USB_SER_DEVICE; | ||
65 | out_8(bcsr_regs + 12, bcsr12); | ||
66 | } else { | ||
67 | printk(KERN_ERR "USB DR: unsupported PHY\n"); | ||
68 | } | ||
69 | |||
70 | of_node_put(np); | ||
71 | iounmap(bcsr_regs); | ||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | /* ************************************************************************ | ||
76 | * | ||
77 | * Setup the architecture | ||
78 | * | ||
79 | */ | ||
80 | static void __init mpc837x_mds_setup_arch(void) | ||
81 | { | ||
82 | #ifdef CONFIG_PCI | ||
83 | struct device_node *np; | ||
84 | #endif | ||
85 | |||
86 | if (ppc_md.progress) | ||
87 | ppc_md.progress("mpc837x_mds_setup_arch()", 0); | ||
88 | |||
89 | #ifdef CONFIG_PCI | ||
90 | for_each_compatible_node(np, "pci", "fsl,mpc8349-pci") | ||
91 | mpc83xx_add_bridge(np); | ||
92 | #endif | ||
93 | mpc837xmds_usb_cfg(); | ||
94 | } | ||
95 | |||
96 | static struct of_device_id mpc837x_ids[] = { | ||
97 | { .type = "soc", }, | ||
98 | { .compatible = "soc", }, | ||
99 | {}, | ||
100 | }; | ||
101 | |||
102 | static int __init mpc837x_declare_of_platform_devices(void) | ||
103 | { | ||
104 | /* Publish of_device */ | ||
105 | of_platform_bus_probe(NULL, mpc837x_ids, NULL); | ||
106 | |||
107 | return 0; | ||
108 | } | ||
109 | machine_device_initcall(mpc837x_mds, mpc837x_declare_of_platform_devices); | ||
110 | |||
111 | static void __init mpc837x_mds_init_IRQ(void) | ||
112 | { | ||
113 | struct device_node *np; | ||
114 | |||
115 | np = of_find_compatible_node(NULL, NULL, "fsl,ipic"); | ||
116 | if (!np) | ||
117 | return; | ||
118 | |||
119 | ipic_init(np, 0); | ||
120 | |||
121 | /* Initialize the default interrupt mapping priorities, | ||
122 | * in case the boot rom changed something on us. | ||
123 | */ | ||
124 | ipic_set_default_priority(); | ||
125 | } | ||
126 | |||
127 | /* | ||
128 | * Called very early, MMU is off, device-tree isn't unflattened | ||
129 | */ | ||
130 | static int __init mpc837x_mds_probe(void) | ||
131 | { | ||
132 | unsigned long root = of_get_flat_dt_root(); | ||
133 | |||
134 | return of_flat_dt_is_compatible(root, "fsl,mpc837xmds"); | ||
135 | } | ||
136 | |||
137 | define_machine(mpc837x_mds) { | ||
138 | .name = "MPC837x MDS", | ||
139 | .probe = mpc837x_mds_probe, | ||
140 | .setup_arch = mpc837x_mds_setup_arch, | ||
141 | .init_IRQ = mpc837x_mds_init_IRQ, | ||
142 | .get_irq = ipic_get_irq, | ||
143 | .restart = mpc83xx_restart, | ||
144 | .time_init = mpc83xx_time_init, | ||
145 | .calibrate_decr = generic_calibrate_decr, | ||
146 | .progress = udbg_progress, | ||
147 | }; | ||
diff --git a/arch/powerpc/platforms/83xx/mpc837x_rdb.c b/arch/powerpc/platforms/83xx/mpc837x_rdb.c new file mode 100644 index 000000000000..2293ae51383d --- /dev/null +++ b/arch/powerpc/platforms/83xx/mpc837x_rdb.c | |||
@@ -0,0 +1,99 @@ | |||
1 | /* | ||
2 | * arch/powerpc/platforms/83xx/mpc837x_rdb.c | ||
3 | * | ||
4 | * Copyright (C) 2007 Freescale Semicondutor, Inc. All rights reserved. | ||
5 | * | ||
6 | * MPC837x RDB board specific routines | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/pci.h> | ||
15 | #include <linux/of_platform.h> | ||
16 | |||
17 | #include <asm/time.h> | ||
18 | #include <asm/ipic.h> | ||
19 | #include <asm/udbg.h> | ||
20 | |||
21 | #include "mpc83xx.h" | ||
22 | |||
23 | extern int mpc837x_usb_cfg(void); | ||
24 | |||
25 | /* ************************************************************************ | ||
26 | * | ||
27 | * Setup the architecture | ||
28 | * | ||
29 | */ | ||
30 | static void __init mpc837x_rdb_setup_arch(void) | ||
31 | { | ||
32 | #ifdef CONFIG_PCI | ||
33 | struct device_node *np; | ||
34 | #endif | ||
35 | |||
36 | if (ppc_md.progress) | ||
37 | ppc_md.progress("mpc837x_rdb_setup_arch()", 0); | ||
38 | |||
39 | #ifdef CONFIG_PCI | ||
40 | for_each_compatible_node(np, "pci", "fsl,mpc8349-pci") | ||
41 | mpc83xx_add_bridge(np); | ||
42 | #endif | ||
43 | mpc837x_usb_cfg(); | ||
44 | } | ||
45 | |||
46 | static struct of_device_id mpc837x_ids[] = { | ||
47 | { .type = "soc", }, | ||
48 | { .compatible = "soc", }, | ||
49 | {}, | ||
50 | }; | ||
51 | |||
52 | static int __init mpc837x_declare_of_platform_devices(void) | ||
53 | { | ||
54 | /* Publish of_device */ | ||
55 | of_platform_bus_probe(NULL, mpc837x_ids, NULL); | ||
56 | |||
57 | return 0; | ||
58 | } | ||
59 | machine_device_initcall(mpc837x_rdb, mpc837x_declare_of_platform_devices); | ||
60 | |||
61 | static void __init mpc837x_rdb_init_IRQ(void) | ||
62 | { | ||
63 | struct device_node *np; | ||
64 | |||
65 | np = of_find_compatible_node(NULL, NULL, "fsl,ipic"); | ||
66 | if (!np) | ||
67 | return; | ||
68 | |||
69 | ipic_init(np, 0); | ||
70 | |||
71 | /* Initialize the default interrupt mapping priorities, | ||
72 | * in case the boot rom changed something on us. | ||
73 | */ | ||
74 | ipic_set_default_priority(); | ||
75 | } | ||
76 | |||
77 | /* | ||
78 | * Called very early, MMU is off, device-tree isn't unflattened | ||
79 | */ | ||
80 | static int __init mpc837x_rdb_probe(void) | ||
81 | { | ||
82 | unsigned long root = of_get_flat_dt_root(); | ||
83 | |||
84 | return of_flat_dt_is_compatible(root, "fsl,mpc8377rdb") || | ||
85 | of_flat_dt_is_compatible(root, "fsl,mpc8378rdb") || | ||
86 | of_flat_dt_is_compatible(root, "fsl,mpc8379rdb"); | ||
87 | } | ||
88 | |||
89 | define_machine(mpc837x_rdb) { | ||
90 | .name = "MPC837x RDB", | ||
91 | .probe = mpc837x_rdb_probe, | ||
92 | .setup_arch = mpc837x_rdb_setup_arch, | ||
93 | .init_IRQ = mpc837x_rdb_init_IRQ, | ||
94 | .get_irq = ipic_get_irq, | ||
95 | .restart = mpc83xx_restart, | ||
96 | .time_init = mpc83xx_time_init, | ||
97 | .calibrate_decr = generic_calibrate_decr, | ||
98 | .progress = udbg_progress, | ||
99 | }; | ||
diff --git a/arch/powerpc/platforms/83xx/mpc83xx.h b/arch/powerpc/platforms/83xx/mpc83xx.h index b778cb4f3fb5..88bb748aff0d 100644 --- a/arch/powerpc/platforms/83xx/mpc83xx.h +++ b/arch/powerpc/platforms/83xx/mpc83xx.h | |||
@@ -14,6 +14,7 @@ | |||
14 | #define MPC83XX_SCCR_USB_DRCM_11 0x00300000 | 14 | #define MPC83XX_SCCR_USB_DRCM_11 0x00300000 |
15 | #define MPC83XX_SCCR_USB_DRCM_01 0x00100000 | 15 | #define MPC83XX_SCCR_USB_DRCM_01 0x00100000 |
16 | #define MPC83XX_SCCR_USB_DRCM_10 0x00200000 | 16 | #define MPC83XX_SCCR_USB_DRCM_10 0x00200000 |
17 | #define MPC837X_SCCR_USB_DRCM_11 0x00c00000 | ||
17 | 18 | ||
18 | /* system i/o configuration register low */ | 19 | /* system i/o configuration register low */ |
19 | #define MPC83XX_SICRL_OFFS 0x114 | 20 | #define MPC83XX_SICRL_OFFS 0x114 |
@@ -22,6 +23,8 @@ | |||
22 | #define MPC834X_SICRL_USB1 0x20000000 | 23 | #define MPC834X_SICRL_USB1 0x20000000 |
23 | #define MPC831X_SICRL_USB_MASK 0x00000c00 | 24 | #define MPC831X_SICRL_USB_MASK 0x00000c00 |
24 | #define MPC831X_SICRL_USB_ULPI 0x00000800 | 25 | #define MPC831X_SICRL_USB_ULPI 0x00000800 |
26 | #define MPC837X_SICRL_USB_MASK 0xf0000000 | ||
27 | #define MPC837X_SICRL_USB_ULPI 0x50000000 | ||
25 | 28 | ||
26 | /* system i/o configuration register high */ | 29 | /* system i/o configuration register high */ |
27 | #define MPC83XX_SICRH_OFFS 0x118 | 30 | #define MPC83XX_SICRH_OFFS 0x118 |
diff --git a/arch/powerpc/platforms/83xx/pci.c b/arch/powerpc/platforms/83xx/pci.c index 80425d7b14f8..14f1080c6c9d 100644 --- a/arch/powerpc/platforms/83xx/pci.c +++ b/arch/powerpc/platforms/83xx/pci.c | |||
@@ -54,7 +54,7 @@ int __init mpc83xx_add_bridge(struct device_node *dev) | |||
54 | " bus 0\n", dev->full_name); | 54 | " bus 0\n", dev->full_name); |
55 | } | 55 | } |
56 | 56 | ||
57 | pci_assign_all_buses = 1; | 57 | ppc_pci_flags |= PPC_PCI_REASSIGN_ALL_BUS; |
58 | hose = pcibios_alloc_controller(dev); | 58 | hose = pcibios_alloc_controller(dev); |
59 | if (!hose) | 59 | if (!hose) |
60 | return -ENOMEM; | 60 | return -ENOMEM; |
diff --git a/arch/powerpc/platforms/83xx/sbc834x.c b/arch/powerpc/platforms/83xx/sbc834x.c new file mode 100644 index 000000000000..cf382474a83d --- /dev/null +++ b/arch/powerpc/platforms/83xx/sbc834x.c | |||
@@ -0,0 +1,115 @@ | |||
1 | /* | ||
2 | * arch/powerpc/platforms/83xx/sbc834x.c | ||
3 | * | ||
4 | * Wind River SBC834x board specific routines | ||
5 | * | ||
6 | * By Paul Gortmaker (see MAINTAINERS for contact information) | ||
7 | * | ||
8 | * Based largely on the mpc834x_mds.c support by Kumar Gala. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License as published by the | ||
12 | * Free Software Foundation; either version 2 of the License, or (at your | ||
13 | * option) any later version. | ||
14 | */ | ||
15 | |||
16 | #include <linux/stddef.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/errno.h> | ||
20 | #include <linux/reboot.h> | ||
21 | #include <linux/pci.h> | ||
22 | #include <linux/kdev_t.h> | ||
23 | #include <linux/major.h> | ||
24 | #include <linux/console.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/seq_file.h> | ||
27 | #include <linux/root_dev.h> | ||
28 | #include <linux/of_platform.h> | ||
29 | |||
30 | #include <asm/system.h> | ||
31 | #include <asm/atomic.h> | ||
32 | #include <asm/time.h> | ||
33 | #include <asm/io.h> | ||
34 | #include <asm/machdep.h> | ||
35 | #include <asm/ipic.h> | ||
36 | #include <asm/irq.h> | ||
37 | #include <asm/prom.h> | ||
38 | #include <asm/udbg.h> | ||
39 | #include <sysdev/fsl_soc.h> | ||
40 | |||
41 | #include "mpc83xx.h" | ||
42 | |||
43 | /* ************************************************************************ | ||
44 | * | ||
45 | * Setup the architecture | ||
46 | * | ||
47 | */ | ||
48 | static void __init sbc834x_setup_arch(void) | ||
49 | { | ||
50 | #ifdef CONFIG_PCI | ||
51 | struct device_node *np; | ||
52 | #endif | ||
53 | |||
54 | if (ppc_md.progress) | ||
55 | ppc_md.progress("sbc834x_setup_arch()", 0); | ||
56 | |||
57 | #ifdef CONFIG_PCI | ||
58 | for_each_compatible_node(np, "pci", "fsl,mpc8349-pci") | ||
59 | mpc83xx_add_bridge(np); | ||
60 | #endif | ||
61 | |||
62 | } | ||
63 | |||
64 | static void __init sbc834x_init_IRQ(void) | ||
65 | { | ||
66 | struct device_node *np; | ||
67 | |||
68 | np = of_find_node_by_type(NULL, "ipic"); | ||
69 | if (!np) | ||
70 | return; | ||
71 | |||
72 | ipic_init(np, 0); | ||
73 | |||
74 | /* Initialize the default interrupt mapping priorities, | ||
75 | * in case the boot rom changed something on us. | ||
76 | */ | ||
77 | ipic_set_default_priority(); | ||
78 | |||
79 | of_node_put(np); | ||
80 | } | ||
81 | |||
82 | static struct __initdata of_device_id sbc834x_ids[] = { | ||
83 | { .type = "soc", }, | ||
84 | { .compatible = "soc", }, | ||
85 | {}, | ||
86 | }; | ||
87 | |||
88 | static int __init sbc834x_declare_of_platform_devices(void) | ||
89 | { | ||
90 | of_platform_bus_probe(NULL, sbc834x_ids, NULL); | ||
91 | return 0; | ||
92 | } | ||
93 | machine_device_initcall(sbc834x, sbc834x_declare_of_platform_devices); | ||
94 | |||
95 | /* | ||
96 | * Called very early, MMU is off, device-tree isn't unflattened | ||
97 | */ | ||
98 | static int __init sbc834x_probe(void) | ||
99 | { | ||
100 | unsigned long root = of_get_flat_dt_root(); | ||
101 | |||
102 | return of_flat_dt_is_compatible(root, "SBC834x"); | ||
103 | } | ||
104 | |||
105 | define_machine(sbc834x) { | ||
106 | .name = "SBC834x", | ||
107 | .probe = sbc834x_probe, | ||
108 | .setup_arch = sbc834x_setup_arch, | ||
109 | .init_IRQ = sbc834x_init_IRQ, | ||
110 | .get_irq = ipic_get_irq, | ||
111 | .restart = mpc83xx_restart, | ||
112 | .time_init = mpc83xx_time_init, | ||
113 | .calibrate_decr = generic_calibrate_decr, | ||
114 | .progress = udbg_progress, | ||
115 | }; | ||
diff --git a/arch/powerpc/platforms/83xx/usb.c b/arch/powerpc/platforms/83xx/usb.c index b45160f8d084..681230a30acd 100644 --- a/arch/powerpc/platforms/83xx/usb.c +++ b/arch/powerpc/platforms/83xx/usb.c | |||
@@ -22,7 +22,7 @@ | |||
22 | #include "mpc83xx.h" | 22 | #include "mpc83xx.h" |
23 | 23 | ||
24 | 24 | ||
25 | #ifdef CONFIG_MPC834x | 25 | #ifdef CONFIG_PPC_MPC834x |
26 | int mpc834x_usb_cfg(void) | 26 | int mpc834x_usb_cfg(void) |
27 | { | 27 | { |
28 | unsigned long sccr, sicrl, sicrh; | 28 | unsigned long sccr, sicrl, sicrh; |
@@ -41,7 +41,7 @@ int mpc834x_usb_cfg(void) | |||
41 | sicrl = in_be32(immap + MPC83XX_SICRL_OFFS) & ~MPC834X_SICRL_USB_MASK; | 41 | sicrl = in_be32(immap + MPC83XX_SICRL_OFFS) & ~MPC834X_SICRL_USB_MASK; |
42 | sicrh = in_be32(immap + MPC83XX_SICRH_OFFS) & ~MPC834X_SICRH_USB_UTMI; | 42 | sicrh = in_be32(immap + MPC83XX_SICRH_OFFS) & ~MPC834X_SICRH_USB_UTMI; |
43 | 43 | ||
44 | np = of_find_compatible_node(NULL, "usb", "fsl-usb2-dr"); | 44 | np = of_find_compatible_node(NULL, NULL, "fsl-usb2-dr"); |
45 | if (np) { | 45 | if (np) { |
46 | sccr |= MPC83XX_SCCR_USB_DRCM_11; /* 1:3 */ | 46 | sccr |= MPC83XX_SCCR_USB_DRCM_11; /* 1:3 */ |
47 | 47 | ||
@@ -67,7 +67,7 @@ int mpc834x_usb_cfg(void) | |||
67 | port0_is_dr = 1; | 67 | port0_is_dr = 1; |
68 | of_node_put(np); | 68 | of_node_put(np); |
69 | } | 69 | } |
70 | np = of_find_compatible_node(NULL, "usb", "fsl-usb2-mph"); | 70 | np = of_find_compatible_node(NULL, NULL, "fsl-usb2-mph"); |
71 | if (np) { | 71 | if (np) { |
72 | sccr |= MPC83XX_SCCR_USB_MPHCM_11; /* 1:3 */ | 72 | sccr |= MPC83XX_SCCR_USB_MPHCM_11; /* 1:3 */ |
73 | 73 | ||
@@ -96,7 +96,7 @@ int mpc834x_usb_cfg(void) | |||
96 | iounmap(immap); | 96 | iounmap(immap); |
97 | return 0; | 97 | return 0; |
98 | } | 98 | } |
99 | #endif /* CONFIG_MPC834x */ | 99 | #endif /* CONFIG_PPC_MPC834x */ |
100 | 100 | ||
101 | #ifdef CONFIG_PPC_MPC831x | 101 | #ifdef CONFIG_PPC_MPC831x |
102 | int mpc831x_usb_cfg(void) | 102 | int mpc831x_usb_cfg(void) |
@@ -111,7 +111,7 @@ int mpc831x_usb_cfg(void) | |||
111 | const void *dr_mode; | 111 | const void *dr_mode; |
112 | #endif | 112 | #endif |
113 | 113 | ||
114 | np = of_find_compatible_node(NULL, "usb", "fsl-usb2-dr"); | 114 | np = of_find_compatible_node(NULL, NULL, "fsl-usb2-dr"); |
115 | if (!np) | 115 | if (!np) |
116 | return -ENODEV; | 116 | return -ENODEV; |
117 | prop = of_get_property(np, "phy_type", NULL); | 117 | prop = of_get_property(np, "phy_type", NULL); |
@@ -179,3 +179,43 @@ int mpc831x_usb_cfg(void) | |||
179 | return ret; | 179 | return ret; |
180 | } | 180 | } |
181 | #endif /* CONFIG_PPC_MPC831x */ | 181 | #endif /* CONFIG_PPC_MPC831x */ |
182 | |||
183 | #ifdef CONFIG_PPC_MPC837x | ||
184 | int mpc837x_usb_cfg(void) | ||
185 | { | ||
186 | void __iomem *immap; | ||
187 | struct device_node *np = NULL; | ||
188 | const void *prop; | ||
189 | int ret = 0; | ||
190 | |||
191 | np = of_find_compatible_node(NULL, NULL, "fsl-usb2-dr"); | ||
192 | if (!np) | ||
193 | return -ENODEV; | ||
194 | prop = of_get_property(np, "phy_type", NULL); | ||
195 | |||
196 | if (!prop || (strcmp(prop, "ulpi") && strcmp(prop, "serial"))) { | ||
197 | printk(KERN_WARNING "837x USB PHY type not supported\n"); | ||
198 | of_node_put(np); | ||
199 | return -EINVAL; | ||
200 | } | ||
201 | |||
202 | /* Map IMMR space for pin and clock settings */ | ||
203 | immap = ioremap(get_immrbase(), 0x1000); | ||
204 | if (!immap) { | ||
205 | of_node_put(np); | ||
206 | return -ENOMEM; | ||
207 | } | ||
208 | |||
209 | /* Configure clock */ | ||
210 | clrsetbits_be32(immap + MPC83XX_SCCR_OFFS, MPC837X_SCCR_USB_DRCM_11, | ||
211 | MPC837X_SCCR_USB_DRCM_11); | ||
212 | |||
213 | /* Configure pin mux for ULPI/serial */ | ||
214 | clrsetbits_be32(immap + MPC83XX_SICRL_OFFS, MPC837X_SICRL_USB_MASK, | ||
215 | MPC837X_SICRL_USB_ULPI); | ||
216 | |||
217 | iounmap(immap); | ||
218 | of_node_put(np); | ||
219 | return ret; | ||
220 | } | ||
221 | #endif /* CONFIG_PPC_MPC837x */ | ||
diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig index 7748a3a426db..7e76ddbd5821 100644 --- a/arch/powerpc/platforms/85xx/Kconfig +++ b/arch/powerpc/platforms/85xx/Kconfig | |||
@@ -1,7 +1,14 @@ | |||
1 | choice | 1 | menuconfig MPC85xx |
2 | prompt "Machine Type" | 2 | bool "Machine Type" |
3 | depends on PPC_85xx | 3 | depends on PPC_85xx |
4 | default MPC8540_ADS | 4 | select PPC_UDBG_16550 |
5 | select PPC_INDIRECT_PCI if PCI | ||
6 | select MPIC | ||
7 | select FSL_PCI if PCI | ||
8 | select SERIAL_8250_SHARE_IRQ if SERIAL_8250 | ||
9 | default y | ||
10 | |||
11 | if MPC85xx | ||
5 | 12 | ||
6 | config MPC8540_ADS | 13 | config MPC8540_ADS |
7 | bool "Freescale MPC8540 ADS" | 14 | bool "Freescale MPC8540 ADS" |
@@ -13,6 +20,7 @@ config MPC8560_ADS | |||
13 | bool "Freescale MPC8560 ADS" | 20 | bool "Freescale MPC8560 ADS" |
14 | select DEFAULT_UIMAGE | 21 | select DEFAULT_UIMAGE |
15 | select PPC_CPM_NEW_BINDING | 22 | select PPC_CPM_NEW_BINDING |
23 | select CPM2 | ||
16 | help | 24 | help |
17 | This option enables support for the MPC 8560 ADS board | 25 | This option enables support for the MPC 8560 ADS board |
18 | 26 | ||
@@ -38,25 +46,64 @@ config MPC85xx_DS | |||
38 | help | 46 | help |
39 | This option enables support for the MPC85xx DS (MPC8544 DS) board | 47 | This option enables support for the MPC85xx DS (MPC8544 DS) board |
40 | 48 | ||
41 | endchoice | 49 | config STX_GP3 |
50 | bool "Silicon Turnkey Express GP3" | ||
51 | help | ||
52 | This option enables support for the Silicon Turnkey Express GP3 | ||
53 | board. | ||
54 | select CPM2 | ||
55 | select DEFAULT_UIMAGE | ||
56 | select PPC_CPM_NEW_BINDING | ||
42 | 57 | ||
43 | config MPC8540 | 58 | config TQM8540 |
44 | bool | 59 | bool "TQ Components TQM8540" |
45 | select PPC_UDBG_16550 | 60 | help |
46 | select PPC_INDIRECT_PCI | 61 | This option enables support for the TQ Components TQM8540 board. |
47 | default y if MPC8540_ADS || MPC85xx_CDS | 62 | select DEFAULT_UIMAGE |
63 | select PPC_CPM_NEW_BINDING | ||
64 | select TQM85xx | ||
48 | 65 | ||
49 | config MPC8560 | 66 | config TQM8541 |
50 | bool | 67 | bool "TQ Components TQM8541" |
68 | help | ||
69 | This option enables support for the TQ Components TQM8541 board. | ||
70 | select DEFAULT_UIMAGE | ||
71 | select PPC_CPM_NEW_BINDING | ||
72 | select TQM85xx | ||
73 | select CPM2 | ||
74 | |||
75 | config TQM8555 | ||
76 | bool "TQ Components TQM8555" | ||
77 | help | ||
78 | This option enables support for the TQ Components TQM8555 board. | ||
79 | select DEFAULT_UIMAGE | ||
80 | select PPC_CPM_NEW_BINDING | ||
81 | select TQM85xx | ||
51 | select CPM2 | 82 | select CPM2 |
52 | default y if MPC8560_ADS | ||
53 | 83 | ||
54 | config MPC85xx | 84 | config TQM8560 |
85 | bool "TQ Components TQM8560" | ||
86 | help | ||
87 | This option enables support for the TQ Components TQM8560 board. | ||
88 | select DEFAULT_UIMAGE | ||
89 | select PPC_CPM_NEW_BINDING | ||
90 | select TQM85xx | ||
91 | select CPM2 | ||
92 | |||
93 | config SBC8548 | ||
94 | bool "Wind River SBC8548" | ||
95 | select DEFAULT_UIMAGE | ||
96 | help | ||
97 | This option enables support for the Wind River SBC8548 board | ||
98 | |||
99 | config SBC8560 | ||
100 | bool "Wind River SBC8560" | ||
101 | select DEFAULT_UIMAGE | ||
102 | select PPC_CPM_NEW_BINDING if CPM2 | ||
103 | help | ||
104 | This option enables support for the Wind River SBC8560 board | ||
105 | |||
106 | endif # MPC85xx | ||
107 | |||
108 | config TQM85xx | ||
55 | bool | 109 | bool |
56 | select PPC_UDBG_16550 | ||
57 | select PPC_INDIRECT_PCI if PCI | ||
58 | select MPIC | ||
59 | select FSL_PCI if PCI | ||
60 | select SERIAL_8250_SHARE_IRQ if SERIAL_8250 | ||
61 | default y if MPC8540_ADS || MPC85xx_CDS || MPC8560_ADS \ | ||
62 | || MPC85xx_MDS || MPC85xx_DS | ||
diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile index 5eca92023ec8..cb7af4ebd75f 100644 --- a/arch/powerpc/platforms/85xx/Makefile +++ b/arch/powerpc/platforms/85xx/Makefile | |||
@@ -6,3 +6,7 @@ obj-$(CONFIG_MPC8560_ADS) += mpc85xx_ads.o | |||
6 | obj-$(CONFIG_MPC85xx_CDS) += mpc85xx_cds.o | 6 | obj-$(CONFIG_MPC85xx_CDS) += mpc85xx_cds.o |
7 | obj-$(CONFIG_MPC85xx_DS) += mpc85xx_ds.o | 7 | obj-$(CONFIG_MPC85xx_DS) += mpc85xx_ds.o |
8 | obj-$(CONFIG_MPC85xx_MDS) += mpc85xx_mds.o | 8 | obj-$(CONFIG_MPC85xx_MDS) += mpc85xx_mds.o |
9 | obj-$(CONFIG_STX_GP3) += stx_gp3.o | ||
10 | obj-$(CONFIG_TQM85xx) += tqm85xx.o | ||
11 | obj-$(CONFIG_SBC8560) += sbc8560.o | ||
12 | obj-$(CONFIG_SBC8548) += sbc8548.o | ||
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c index bccdc25f83a2..4e0305096114 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c | |||
@@ -52,9 +52,9 @@ static void cpm2_cascade(unsigned int irq, struct irq_desc *desc) | |||
52 | { | 52 | { |
53 | int cascade_irq; | 53 | int cascade_irq; |
54 | 54 | ||
55 | while ((cascade_irq = cpm2_get_irq()) >= 0) { | 55 | while ((cascade_irq = cpm2_get_irq()) >= 0) |
56 | generic_handle_irq(cascade_irq); | 56 | generic_handle_irq(cascade_irq); |
57 | } | 57 | |
58 | desc->chip->eoi(irq); | 58 | desc->chip->eoi(irq); |
59 | } | 59 | } |
60 | 60 | ||
@@ -70,13 +70,12 @@ static void __init mpc85xx_ads_pic_init(void) | |||
70 | #endif | 70 | #endif |
71 | 71 | ||
72 | np = of_find_node_by_type(np, "open-pic"); | 72 | np = of_find_node_by_type(np, "open-pic"); |
73 | 73 | if (!np) { | |
74 | if (np == NULL) { | ||
75 | printk(KERN_ERR "Could not find open-pic node\n"); | 74 | printk(KERN_ERR "Could not find open-pic node\n"); |
76 | return; | 75 | return; |
77 | } | 76 | } |
78 | 77 | ||
79 | if(of_address_to_resource(np, 0, &r)) { | 78 | if (of_address_to_resource(np, 0, &r)) { |
80 | printk(KERN_ERR "Could not map mpic register space\n"); | 79 | printk(KERN_ERR "Could not map mpic register space\n"); |
81 | of_node_put(np); | 80 | of_node_put(np); |
82 | return; | 81 | return; |
@@ -100,6 +99,7 @@ static void __init mpc85xx_ads_pic_init(void) | |||
100 | irq = irq_of_parse_and_map(np, 0); | 99 | irq = irq_of_parse_and_map(np, 0); |
101 | 100 | ||
102 | cpm2_pic_init(np); | 101 | cpm2_pic_init(np); |
102 | of_node_put(np); | ||
103 | set_irq_chained_handler(irq, cpm2_cascade); | 103 | set_irq_chained_handler(irq, cpm2_cascade); |
104 | #endif | 104 | #endif |
105 | } | 105 | } |
@@ -112,7 +112,7 @@ struct cpm_pin { | |||
112 | int port, pin, flags; | 112 | int port, pin, flags; |
113 | }; | 113 | }; |
114 | 114 | ||
115 | static struct cpm_pin mpc8560_ads_pins[] = { | 115 | static const struct cpm_pin mpc8560_ads_pins[] = { |
116 | /* SCC1 */ | 116 | /* SCC1 */ |
117 | {3, 29, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, | 117 | {3, 29, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, |
118 | {3, 30, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, | 118 | {3, 30, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, |
@@ -233,13 +233,11 @@ static struct of_device_id __initdata of_bus_ids[] = { | |||
233 | 233 | ||
234 | static int __init declare_of_platform_devices(void) | 234 | static int __init declare_of_platform_devices(void) |
235 | { | 235 | { |
236 | if (!machine_is(mpc85xx_ads)) | ||
237 | return 0; | ||
238 | |||
239 | of_platform_bus_probe(NULL, of_bus_ids, NULL); | 236 | of_platform_bus_probe(NULL, of_bus_ids, NULL); |
237 | |||
240 | return 0; | 238 | return 0; |
241 | } | 239 | } |
242 | device_initcall(declare_of_platform_devices); | 240 | machine_device_initcall(mpc85xx_ads, declare_of_platform_devices); |
243 | 241 | ||
244 | /* | 242 | /* |
245 | * Called very early, device-tree isn't unflattened | 243 | * Called very early, device-tree isn't unflattened |
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c index 4d063eec6210..8b1de7884be6 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c | |||
@@ -222,9 +222,6 @@ static int mpc85xx_cds_8259_attach(void) | |||
222 | struct device_node *cascade_node = NULL; | 222 | struct device_node *cascade_node = NULL; |
223 | int cascade_irq; | 223 | int cascade_irq; |
224 | 224 | ||
225 | if (!machine_is(mpc85xx_cds)) | ||
226 | return 0; | ||
227 | |||
228 | /* Initialize the i8259 controller */ | 225 | /* Initialize the i8259 controller */ |
229 | for_each_node_by_type(np, "interrupt-controller") | 226 | for_each_node_by_type(np, "interrupt-controller") |
230 | if (of_device_is_compatible(np, "chrp,iic")) { | 227 | if (of_device_is_compatible(np, "chrp,iic")) { |
@@ -262,8 +259,7 @@ static int mpc85xx_cds_8259_attach(void) | |||
262 | 259 | ||
263 | return 0; | 260 | return 0; |
264 | } | 261 | } |
265 | 262 | machine_device_initcall(mpc85xx_cds, mpc85xx_cds_8259_attach); | |
266 | device_initcall(mpc85xx_cds_8259_attach); | ||
267 | 263 | ||
268 | #endif /* CONFIG_PPC_I8259 */ | 264 | #endif /* CONFIG_PPC_I8259 */ |
269 | 265 | ||
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ds.c b/arch/powerpc/platforms/85xx/mpc85xx_ds.c index 59c121a97ac7..bdb3d0b38cd2 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ds.c | |||
@@ -123,7 +123,7 @@ static int mpc85xx_exclude_device(struct pci_controller *hose, | |||
123 | struct device_node* node; | 123 | struct device_node* node; |
124 | struct resource rsrc; | 124 | struct resource rsrc; |
125 | 125 | ||
126 | node = (struct device_node *)hose->arch_data; | 126 | node = hose->dn; |
127 | of_address_to_resource(node, 0, &rsrc); | 127 | of_address_to_resource(node, 0, &rsrc); |
128 | 128 | ||
129 | if ((rsrc.start & 0xfffff) == primary_phb_addr) { | 129 | if ((rsrc.start & 0xfffff) == primary_phb_addr) { |
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c index 61b3eedf41b9..25f8bc75e838 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c | |||
@@ -30,9 +30,9 @@ | |||
30 | #include <linux/initrd.h> | 30 | #include <linux/initrd.h> |
31 | #include <linux/module.h> | 31 | #include <linux/module.h> |
32 | #include <linux/fsl_devices.h> | 32 | #include <linux/fsl_devices.h> |
33 | #include <linux/of_platform.h> | ||
34 | #include <linux/of_device.h> | ||
33 | 35 | ||
34 | #include <asm/of_device.h> | ||
35 | #include <asm/of_platform.h> | ||
36 | #include <asm/system.h> | 36 | #include <asm/system.h> |
37 | #include <asm/atomic.h> | 37 | #include <asm/atomic.h> |
38 | #include <asm/time.h> | 38 | #include <asm/time.h> |
@@ -94,21 +94,25 @@ static void __init mpc85xx_mds_setup_arch(void) | |||
94 | #endif | 94 | #endif |
95 | 95 | ||
96 | #ifdef CONFIG_QUICC_ENGINE | 96 | #ifdef CONFIG_QUICC_ENGINE |
97 | if ((np = of_find_node_by_name(NULL, "qe")) != NULL) { | 97 | np = of_find_compatible_node(NULL, NULL, "fsl,qe"); |
98 | qe_reset(); | 98 | if (!np) { |
99 | of_node_put(np); | 99 | np = of_find_node_by_name(NULL, "qe"); |
100 | if (!np) | ||
101 | return; | ||
100 | } | 102 | } |
101 | 103 | ||
102 | if ((np = of_find_node_by_name(NULL, "par_io")) != NULL) { | 104 | qe_reset(); |
103 | struct device_node *ucc = NULL; | 105 | of_node_put(np); |
106 | |||
107 | np = of_find_node_by_name(NULL, "par_io"); | ||
108 | if (np) { | ||
109 | struct device_node *ucc; | ||
104 | 110 | ||
105 | par_io_init(np); | 111 | par_io_init(np); |
106 | of_node_put(np); | 112 | of_node_put(np); |
107 | 113 | ||
108 | for ( ;(ucc = of_find_node_by_name(ucc, "ucc")) != NULL;) | 114 | for_each_node_by_name(ucc, "ucc") |
109 | par_io_of_config(ucc); | 115 | par_io_of_config(ucc); |
110 | |||
111 | of_node_put(ucc); | ||
112 | } | 116 | } |
113 | 117 | ||
114 | if (bcsr_regs) { | 118 | if (bcsr_regs) { |
@@ -131,7 +135,6 @@ static void __init mpc85xx_mds_setup_arch(void) | |||
131 | 135 | ||
132 | iounmap(bcsr_regs); | 136 | iounmap(bcsr_regs); |
133 | } | 137 | } |
134 | |||
135 | #endif /* CONFIG_QUICC_ENGINE */ | 138 | #endif /* CONFIG_QUICC_ENGINE */ |
136 | } | 139 | } |
137 | 140 | ||
@@ -139,20 +142,18 @@ static struct of_device_id mpc85xx_ids[] = { | |||
139 | { .type = "soc", }, | 142 | { .type = "soc", }, |
140 | { .compatible = "soc", }, | 143 | { .compatible = "soc", }, |
141 | { .type = "qe", }, | 144 | { .type = "qe", }, |
145 | { .compatible = "fsl,qe", }, | ||
142 | {}, | 146 | {}, |
143 | }; | 147 | }; |
144 | 148 | ||
145 | static int __init mpc85xx_publish_devices(void) | 149 | static int __init mpc85xx_publish_devices(void) |
146 | { | 150 | { |
147 | if (!machine_is(mpc85xx_mds)) | ||
148 | return 0; | ||
149 | |||
150 | /* Publish the QE devices */ | 151 | /* Publish the QE devices */ |
151 | of_platform_bus_probe(NULL,mpc85xx_ids,NULL); | 152 | of_platform_bus_probe(NULL, mpc85xx_ids, NULL); |
152 | 153 | ||
153 | return 0; | 154 | return 0; |
154 | } | 155 | } |
155 | device_initcall(mpc85xx_publish_devices); | 156 | machine_device_initcall(mpc85xx_mds, mpc85xx_publish_devices); |
156 | 157 | ||
157 | static void __init mpc85xx_mds_pic_init(void) | 158 | static void __init mpc85xx_mds_pic_init(void) |
158 | { | 159 | { |
@@ -179,10 +180,12 @@ static void __init mpc85xx_mds_pic_init(void) | |||
179 | mpic_init(mpic); | 180 | mpic_init(mpic); |
180 | 181 | ||
181 | #ifdef CONFIG_QUICC_ENGINE | 182 | #ifdef CONFIG_QUICC_ENGINE |
182 | np = of_find_node_by_type(NULL, "qeic"); | 183 | np = of_find_compatible_node(NULL, NULL, "fsl,qe-ic"); |
183 | if (!np) | 184 | if (!np) { |
184 | return; | 185 | np = of_find_node_by_type(NULL, "qeic"); |
185 | 186 | if (!np) | |
187 | return; | ||
188 | } | ||
186 | qe_ic_init(np, 0, qe_ic_cascade_muxed_mpic, NULL); | 189 | qe_ic_init(np, 0, qe_ic_cascade_muxed_mpic, NULL); |
187 | of_node_put(np); | 190 | of_node_put(np); |
188 | #endif /* CONFIG_QUICC_ENGINE */ | 191 | #endif /* CONFIG_QUICC_ENGINE */ |
diff --git a/arch/powerpc/platforms/85xx/sbc8548.c b/arch/powerpc/platforms/85xx/sbc8548.c new file mode 100644 index 000000000000..488facb99fe8 --- /dev/null +++ b/arch/powerpc/platforms/85xx/sbc8548.c | |||
@@ -0,0 +1,167 @@ | |||
1 | /* | ||
2 | * Wind River SBC8548 setup and early boot code. | ||
3 | * | ||
4 | * Copyright 2007 Wind River Systems Inc. | ||
5 | * | ||
6 | * By Paul Gortmaker (see MAINTAINERS for contact information) | ||
7 | * | ||
8 | * Based largely on the MPC8548CDS support - Copyright 2005 Freescale Inc. | ||
9 | * | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify it | ||
12 | * under the terms of the GNU General Public License as published by the | ||
13 | * Free Software Foundation; either version 2 of the License, or (at your | ||
14 | * option) any later version. | ||
15 | */ | ||
16 | |||
17 | #include <linux/stddef.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/errno.h> | ||
21 | #include <linux/reboot.h> | ||
22 | #include <linux/pci.h> | ||
23 | #include <linux/kdev_t.h> | ||
24 | #include <linux/major.h> | ||
25 | #include <linux/console.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/seq_file.h> | ||
28 | #include <linux/initrd.h> | ||
29 | #include <linux/module.h> | ||
30 | #include <linux/interrupt.h> | ||
31 | #include <linux/fsl_devices.h> | ||
32 | #include <linux/of_platform.h> | ||
33 | |||
34 | #include <asm/system.h> | ||
35 | #include <asm/pgtable.h> | ||
36 | #include <asm/page.h> | ||
37 | #include <asm/atomic.h> | ||
38 | #include <asm/time.h> | ||
39 | #include <asm/io.h> | ||
40 | #include <asm/machdep.h> | ||
41 | #include <asm/ipic.h> | ||
42 | #include <asm/pci-bridge.h> | ||
43 | #include <asm/irq.h> | ||
44 | #include <mm/mmu_decl.h> | ||
45 | #include <asm/prom.h> | ||
46 | #include <asm/udbg.h> | ||
47 | #include <asm/mpic.h> | ||
48 | |||
49 | #include <sysdev/fsl_soc.h> | ||
50 | #include <sysdev/fsl_pci.h> | ||
51 | |||
52 | static void __init sbc8548_pic_init(void) | ||
53 | { | ||
54 | struct mpic *mpic; | ||
55 | struct resource r; | ||
56 | struct device_node *np = NULL; | ||
57 | |||
58 | np = of_find_node_by_type(np, "open-pic"); | ||
59 | |||
60 | if (np == NULL) { | ||
61 | printk(KERN_ERR "Could not find open-pic node\n"); | ||
62 | return; | ||
63 | } | ||
64 | |||
65 | if (of_address_to_resource(np, 0, &r)) { | ||
66 | printk(KERN_ERR "Failed to map mpic register space\n"); | ||
67 | of_node_put(np); | ||
68 | return; | ||
69 | } | ||
70 | |||
71 | mpic = mpic_alloc(np, r.start, | ||
72 | MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, | ||
73 | 0, 256, " OpenPIC "); | ||
74 | BUG_ON(mpic == NULL); | ||
75 | |||
76 | /* Return the mpic node */ | ||
77 | of_node_put(np); | ||
78 | |||
79 | mpic_init(mpic); | ||
80 | } | ||
81 | |||
82 | /* | ||
83 | * Setup the architecture | ||
84 | */ | ||
85 | static void __init sbc8548_setup_arch(void) | ||
86 | { | ||
87 | #ifdef CONFIG_PCI | ||
88 | struct device_node *np; | ||
89 | #endif | ||
90 | |||
91 | if (ppc_md.progress) | ||
92 | ppc_md.progress("sbc8548_setup_arch()", 0); | ||
93 | |||
94 | #ifdef CONFIG_PCI | ||
95 | for_each_node_by_type(np, "pci") { | ||
96 | if (of_device_is_compatible(np, "fsl,mpc8540-pci") || | ||
97 | of_device_is_compatible(np, "fsl,mpc8548-pcie")) { | ||
98 | struct resource rsrc; | ||
99 | of_address_to_resource(np, 0, &rsrc); | ||
100 | if ((rsrc.start & 0xfffff) == 0x8000) | ||
101 | fsl_add_bridge(np, 1); | ||
102 | else | ||
103 | fsl_add_bridge(np, 0); | ||
104 | } | ||
105 | } | ||
106 | #endif | ||
107 | } | ||
108 | |||
109 | static void sbc8548_show_cpuinfo(struct seq_file *m) | ||
110 | { | ||
111 | uint pvid, svid, phid1; | ||
112 | uint memsize = total_memory; | ||
113 | |||
114 | pvid = mfspr(SPRN_PVR); | ||
115 | svid = mfspr(SPRN_SVR); | ||
116 | |||
117 | seq_printf(m, "Vendor\t\t: Wind River\n"); | ||
118 | seq_printf(m, "Machine\t\t: SBC8548\n"); | ||
119 | seq_printf(m, "PVR\t\t: 0x%x\n", pvid); | ||
120 | seq_printf(m, "SVR\t\t: 0x%x\n", svid); | ||
121 | |||
122 | /* Display cpu Pll setting */ | ||
123 | phid1 = mfspr(SPRN_HID1); | ||
124 | seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f)); | ||
125 | |||
126 | /* Display the amount of memory */ | ||
127 | seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024)); | ||
128 | } | ||
129 | |||
130 | static struct of_device_id __initdata of_bus_ids[] = { | ||
131 | { .name = "soc", }, | ||
132 | { .type = "soc", }, | ||
133 | {}, | ||
134 | }; | ||
135 | |||
136 | static int __init declare_of_platform_devices(void) | ||
137 | { | ||
138 | of_platform_bus_probe(NULL, of_bus_ids, NULL); | ||
139 | |||
140 | return 0; | ||
141 | } | ||
142 | machine_device_initcall(sbc8548, declare_of_platform_devices); | ||
143 | |||
144 | /* | ||
145 | * Called very early, device-tree isn't unflattened | ||
146 | */ | ||
147 | static int __init sbc8548_probe(void) | ||
148 | { | ||
149 | unsigned long root = of_get_flat_dt_root(); | ||
150 | |||
151 | return of_flat_dt_is_compatible(root, "SBC8548"); | ||
152 | } | ||
153 | |||
154 | define_machine(sbc8548) { | ||
155 | .name = "SBC8548", | ||
156 | .probe = sbc8548_probe, | ||
157 | .setup_arch = sbc8548_setup_arch, | ||
158 | .init_IRQ = sbc8548_pic_init, | ||
159 | .show_cpuinfo = sbc8548_show_cpuinfo, | ||
160 | .get_irq = mpic_get_irq, | ||
161 | .restart = fsl_rstcr_restart, | ||
162 | #ifdef CONFIG_PCI | ||
163 | .pcibios_fixup_bus = fsl_pcibios_fixup_bus, | ||
164 | #endif | ||
165 | .calibrate_decr = generic_calibrate_decr, | ||
166 | .progress = udbg_progress, | ||
167 | }; | ||
diff --git a/arch/powerpc/platforms/85xx/sbc8560.c b/arch/powerpc/platforms/85xx/sbc8560.c new file mode 100644 index 000000000000..2c580cd24e4f --- /dev/null +++ b/arch/powerpc/platforms/85xx/sbc8560.c | |||
@@ -0,0 +1,283 @@ | |||
1 | /* | ||
2 | * Wind River SBC8560 setup and early boot code. | ||
3 | * | ||
4 | * Copyright 2007 Wind River Systems Inc. | ||
5 | * | ||
6 | * By Paul Gortmaker (see MAINTAINERS for contact information) | ||
7 | * | ||
8 | * Based largely on the MPC8560ADS support - Copyright 2005 Freescale Inc. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License as published by the | ||
12 | * Free Software Foundation; either version 2 of the License, or (at your | ||
13 | * option) any later version. | ||
14 | */ | ||
15 | |||
16 | #include <linux/stddef.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/pci.h> | ||
19 | #include <linux/kdev_t.h> | ||
20 | #include <linux/delay.h> | ||
21 | #include <linux/seq_file.h> | ||
22 | #include <linux/of_platform.h> | ||
23 | |||
24 | #include <asm/system.h> | ||
25 | #include <asm/time.h> | ||
26 | #include <asm/machdep.h> | ||
27 | #include <asm/pci-bridge.h> | ||
28 | #include <asm/mpic.h> | ||
29 | #include <mm/mmu_decl.h> | ||
30 | #include <asm/udbg.h> | ||
31 | |||
32 | #include <sysdev/fsl_soc.h> | ||
33 | #include <sysdev/fsl_pci.h> | ||
34 | |||
35 | #ifdef CONFIG_CPM2 | ||
36 | #include <asm/cpm2.h> | ||
37 | #include <sysdev/cpm2_pic.h> | ||
38 | #endif | ||
39 | |||
40 | #ifdef CONFIG_CPM2 | ||
41 | |||
42 | static void cpm2_cascade(unsigned int irq, struct irq_desc *desc) | ||
43 | { | ||
44 | int cascade_irq; | ||
45 | |||
46 | while ((cascade_irq = cpm2_get_irq()) >= 0) | ||
47 | generic_handle_irq(cascade_irq); | ||
48 | |||
49 | desc->chip->eoi(irq); | ||
50 | } | ||
51 | |||
52 | #endif /* CONFIG_CPM2 */ | ||
53 | |||
54 | static void __init sbc8560_pic_init(void) | ||
55 | { | ||
56 | struct mpic *mpic; | ||
57 | struct resource r; | ||
58 | struct device_node *np = NULL; | ||
59 | #ifdef CONFIG_CPM2 | ||
60 | int irq; | ||
61 | #endif | ||
62 | |||
63 | np = of_find_node_by_type(np, "open-pic"); | ||
64 | if (!np) { | ||
65 | printk(KERN_ERR "Could not find open-pic node\n"); | ||
66 | return; | ||
67 | } | ||
68 | |||
69 | if (of_address_to_resource(np, 0, &r)) { | ||
70 | printk(KERN_ERR "Could not map mpic register space\n"); | ||
71 | of_node_put(np); | ||
72 | return; | ||
73 | } | ||
74 | |||
75 | mpic = mpic_alloc(np, r.start, | ||
76 | MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, | ||
77 | 0, 256, " OpenPIC "); | ||
78 | BUG_ON(mpic == NULL); | ||
79 | of_node_put(np); | ||
80 | |||
81 | mpic_init(mpic); | ||
82 | |||
83 | #ifdef CONFIG_CPM2 | ||
84 | /* Setup CPM2 PIC */ | ||
85 | np = of_find_compatible_node(NULL, NULL, "fsl,cpm2-pic"); | ||
86 | if (np == NULL) { | ||
87 | printk(KERN_ERR "PIC init: can not find fsl,cpm2-pic node\n"); | ||
88 | return; | ||
89 | } | ||
90 | irq = irq_of_parse_and_map(np, 0); | ||
91 | |||
92 | cpm2_pic_init(np); | ||
93 | of_node_put(np); | ||
94 | set_irq_chained_handler(irq, cpm2_cascade); | ||
95 | #endif | ||
96 | } | ||
97 | |||
98 | /* | ||
99 | * Setup the architecture | ||
100 | */ | ||
101 | #ifdef CONFIG_CPM2 | ||
102 | struct cpm_pin { | ||
103 | int port, pin, flags; | ||
104 | }; | ||
105 | |||
106 | static const struct cpm_pin sbc8560_pins[] = { | ||
107 | /* SCC1 */ | ||
108 | {3, 29, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, | ||
109 | {3, 30, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, | ||
110 | {3, 31, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, | ||
111 | |||
112 | /* SCC2 */ | ||
113 | {3, 26, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, | ||
114 | {3, 27, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, | ||
115 | {3, 28, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, | ||
116 | |||
117 | /* FCC2 */ | ||
118 | {1, 18, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, | ||
119 | {1, 19, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, | ||
120 | {1, 20, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, | ||
121 | {1, 21, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, | ||
122 | {1, 22, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, | ||
123 | {1, 23, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, | ||
124 | {1, 24, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, | ||
125 | {1, 25, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, | ||
126 | {1, 26, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, | ||
127 | {1, 27, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, | ||
128 | {1, 28, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, | ||
129 | {1, 29, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, | ||
130 | {1, 30, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, | ||
131 | {1, 31, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, | ||
132 | {2, 18, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, /* CLK14 */ | ||
133 | {2, 19, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, /* CLK13 */ | ||
134 | |||
135 | /* FCC3 */ | ||
136 | {1, 4, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, | ||
137 | {1, 5, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, | ||
138 | {1, 6, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, | ||
139 | {1, 7, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, | ||
140 | {1, 8, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, | ||
141 | {1, 9, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, | ||
142 | {1, 10, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, | ||
143 | {1, 11, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, | ||
144 | {1, 12, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, | ||
145 | {1, 13, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, | ||
146 | {1, 14, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, | ||
147 | {1, 15, CPM_PIN_OUTPUT | CPM_PIN_PRIMARY}, | ||
148 | {1, 16, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, | ||
149 | {1, 17, CPM_PIN_INPUT | CPM_PIN_PRIMARY}, | ||
150 | {2, 16, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, /* CLK16 */ | ||
151 | {2, 17, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, /* CLK15 */ | ||
152 | }; | ||
153 | |||
154 | static void __init init_ioports(void) | ||
155 | { | ||
156 | int i; | ||
157 | |||
158 | for (i = 0; i < ARRAY_SIZE(sbc8560_pins); i++) { | ||
159 | struct cpm_pin *pin = &sbc8560_pins[i]; | ||
160 | cpm2_set_pin(pin->port, pin->pin, pin->flags); | ||
161 | } | ||
162 | |||
163 | cpm2_clk_setup(CPM_CLK_SCC1, CPM_BRG1, CPM_CLK_RX); | ||
164 | cpm2_clk_setup(CPM_CLK_SCC1, CPM_BRG1, CPM_CLK_TX); | ||
165 | cpm2_clk_setup(CPM_CLK_SCC2, CPM_BRG2, CPM_CLK_RX); | ||
166 | cpm2_clk_setup(CPM_CLK_SCC2, CPM_BRG2, CPM_CLK_TX); | ||
167 | cpm2_clk_setup(CPM_CLK_FCC2, CPM_CLK13, CPM_CLK_RX); | ||
168 | cpm2_clk_setup(CPM_CLK_FCC2, CPM_CLK14, CPM_CLK_TX); | ||
169 | cpm2_clk_setup(CPM_CLK_FCC3, CPM_CLK15, CPM_CLK_RX); | ||
170 | cpm2_clk_setup(CPM_CLK_FCC3, CPM_CLK16, CPM_CLK_TX); | ||
171 | } | ||
172 | #endif | ||
173 | |||
174 | static void __init sbc8560_setup_arch(void) | ||
175 | { | ||
176 | #ifdef CONFIG_PCI | ||
177 | struct device_node *np; | ||
178 | #endif | ||
179 | |||
180 | if (ppc_md.progress) | ||
181 | ppc_md.progress("sbc8560_setup_arch()", 0); | ||
182 | |||
183 | #ifdef CONFIG_CPM2 | ||
184 | cpm2_reset(); | ||
185 | init_ioports(); | ||
186 | #endif | ||
187 | |||
188 | #ifdef CONFIG_PCI | ||
189 | for_each_compatible_node(np, "pci", "fsl,mpc8540-pci") | ||
190 | fsl_add_bridge(np, 1); | ||
191 | #endif | ||
192 | } | ||
193 | |||
194 | static void sbc8560_show_cpuinfo(struct seq_file *m) | ||
195 | { | ||
196 | uint pvid, svid, phid1; | ||
197 | uint memsize = total_memory; | ||
198 | |||
199 | pvid = mfspr(SPRN_PVR); | ||
200 | svid = mfspr(SPRN_SVR); | ||
201 | |||
202 | seq_printf(m, "Vendor\t\t: Wind River\n"); | ||
203 | seq_printf(m, "Machine\t\t: SBC8560\n"); | ||
204 | seq_printf(m, "PVR\t\t: 0x%x\n", pvid); | ||
205 | seq_printf(m, "SVR\t\t: 0x%x\n", svid); | ||
206 | |||
207 | /* Display cpu Pll setting */ | ||
208 | phid1 = mfspr(SPRN_HID1); | ||
209 | seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f)); | ||
210 | |||
211 | /* Display the amount of memory */ | ||
212 | seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024)); | ||
213 | } | ||
214 | |||
215 | static struct of_device_id __initdata of_bus_ids[] = { | ||
216 | { .name = "soc", }, | ||
217 | { .type = "soc", }, | ||
218 | { .name = "cpm", }, | ||
219 | { .name = "localbus", }, | ||
220 | {}, | ||
221 | }; | ||
222 | |||
223 | static int __init declare_of_platform_devices(void) | ||
224 | { | ||
225 | of_platform_bus_probe(NULL, of_bus_ids, NULL); | ||
226 | |||
227 | return 0; | ||
228 | } | ||
229 | machine_device_initcall(sbc8560, declare_of_platform_devices); | ||
230 | |||
231 | /* | ||
232 | * Called very early, device-tree isn't unflattened | ||
233 | */ | ||
234 | static int __init sbc8560_probe(void) | ||
235 | { | ||
236 | unsigned long root = of_get_flat_dt_root(); | ||
237 | |||
238 | return of_flat_dt_is_compatible(root, "SBC8560"); | ||
239 | } | ||
240 | |||
241 | #ifdef CONFIG_RTC_DRV_M48T59 | ||
242 | static int __init sbc8560_rtc_init(void) | ||
243 | { | ||
244 | struct device_node *np; | ||
245 | struct resource res; | ||
246 | struct platform_device *rtc_dev; | ||
247 | |||
248 | np = of_find_compatible_node(NULL, NULL, "m48t59"); | ||
249 | if (np == NULL) { | ||
250 | printk("No RTC in DTB. Has it been eaten by wild dogs?\n"); | ||
251 | return -ENODEV; | ||
252 | } | ||
253 | |||
254 | of_address_to_resource(np, 0, &res); | ||
255 | of_node_put(np); | ||
256 | |||
257 | printk("Found RTC (m48t59) at i/o 0x%x\n", res.start); | ||
258 | |||
259 | rtc_dev = platform_device_register_simple("rtc-m48t59", 0, &res, 1); | ||
260 | |||
261 | if (IS_ERR(rtc_dev)) { | ||
262 | printk("Registering sbc8560 RTC device failed\n"); | ||
263 | return PTR_ERR(rtc_dev); | ||
264 | } | ||
265 | |||
266 | return 0; | ||
267 | } | ||
268 | |||
269 | arch_initcall(sbc8560_rtc_init); | ||
270 | |||
271 | #endif /* M48T59 */ | ||
272 | |||
273 | define_machine(sbc8560) { | ||
274 | .name = "SBC8560", | ||
275 | .probe = sbc8560_probe, | ||
276 | .setup_arch = sbc8560_setup_arch, | ||
277 | .init_IRQ = sbc8560_pic_init, | ||
278 | .show_cpuinfo = sbc8560_show_cpuinfo, | ||
279 | .get_irq = mpic_get_irq, | ||
280 | .restart = fsl_rstcr_restart, | ||
281 | .calibrate_decr = generic_calibrate_decr, | ||
282 | .progress = udbg_progress, | ||
283 | }; | ||
diff --git a/arch/powerpc/platforms/85xx/stx_gp3.c b/arch/powerpc/platforms/85xx/stx_gp3.c new file mode 100644 index 000000000000..18499d7c9d9e --- /dev/null +++ b/arch/powerpc/platforms/85xx/stx_gp3.c | |||
@@ -0,0 +1,183 @@ | |||
1 | /* | ||
2 | * Based on MPC8560 ADS and arch/ppc stx_gp3 ports | ||
3 | * | ||
4 | * Maintained by Kumar Gala (see MAINTAINERS for contact information) | ||
5 | * | ||
6 | * Copyright 2008 Freescale Semiconductor Inc. | ||
7 | * | ||
8 | * Dan Malek <dan@embeddededge.com> | ||
9 | * Copyright 2004 Embedded Edge, LLC | ||
10 | * | ||
11 | * Copied from mpc8560_ads.c | ||
12 | * Copyright 2002, 2003 Motorola Inc. | ||
13 | * | ||
14 | * Ported to 2.6, Matt Porter <mporter@kernel.crashing.org> | ||
15 | * Copyright 2004-2005 MontaVista Software, Inc. | ||
16 | * | ||
17 | * This program is free software; you can redistribute it and/or modify it | ||
18 | * under the terms of the GNU General Public License as published by the | ||
19 | * Free Software Foundation; either version 2 of the License, or (at your | ||
20 | * option) any later version. | ||
21 | */ | ||
22 | |||
23 | #include <linux/stddef.h> | ||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/pci.h> | ||
26 | #include <linux/kdev_t.h> | ||
27 | #include <linux/delay.h> | ||
28 | #include <linux/seq_file.h> | ||
29 | #include <linux/of_platform.h> | ||
30 | |||
31 | #include <asm/system.h> | ||
32 | #include <asm/time.h> | ||
33 | #include <asm/machdep.h> | ||
34 | #include <asm/pci-bridge.h> | ||
35 | #include <asm/mpic.h> | ||
36 | #include <asm/prom.h> | ||
37 | #include <mm/mmu_decl.h> | ||
38 | #include <asm/udbg.h> | ||
39 | |||
40 | #include <sysdev/fsl_soc.h> | ||
41 | #include <sysdev/fsl_pci.h> | ||
42 | |||
43 | #ifdef CONFIG_CPM2 | ||
44 | #include <asm/cpm2.h> | ||
45 | #include <sysdev/cpm2_pic.h> | ||
46 | |||
47 | static void cpm2_cascade(unsigned int irq, struct irq_desc *desc) | ||
48 | { | ||
49 | int cascade_irq; | ||
50 | |||
51 | while ((cascade_irq = cpm2_get_irq()) >= 0) | ||
52 | generic_handle_irq(cascade_irq); | ||
53 | |||
54 | desc->chip->eoi(irq); | ||
55 | } | ||
56 | #endif /* CONFIG_CPM2 */ | ||
57 | |||
58 | static void __init stx_gp3_pic_init(void) | ||
59 | { | ||
60 | struct mpic *mpic; | ||
61 | struct resource r; | ||
62 | struct device_node *np; | ||
63 | #ifdef CONFIG_CPM2 | ||
64 | int irq; | ||
65 | #endif | ||
66 | |||
67 | np = of_find_node_by_type(NULL, "open-pic"); | ||
68 | if (!np) { | ||
69 | printk(KERN_ERR "Could not find open-pic node\n"); | ||
70 | return; | ||
71 | } | ||
72 | |||
73 | if (of_address_to_resource(np, 0, &r)) { | ||
74 | printk(KERN_ERR "Could not map mpic register space\n"); | ||
75 | of_node_put(np); | ||
76 | return; | ||
77 | } | ||
78 | |||
79 | mpic = mpic_alloc(np, r.start, | ||
80 | MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, | ||
81 | 0, 256, " OpenPIC "); | ||
82 | BUG_ON(mpic == NULL); | ||
83 | of_node_put(np); | ||
84 | |||
85 | mpic_init(mpic); | ||
86 | |||
87 | #ifdef CONFIG_CPM2 | ||
88 | /* Setup CPM2 PIC */ | ||
89 | np = of_find_compatible_node(NULL, NULL, "fsl,cpm2-pic"); | ||
90 | if (np == NULL) { | ||
91 | printk(KERN_ERR "PIC init: can not find fsl,cpm2-pic node\n"); | ||
92 | return; | ||
93 | } | ||
94 | irq = irq_of_parse_and_map(np, 0); | ||
95 | |||
96 | if (irq == NO_IRQ) { | ||
97 | of_node_put(np); | ||
98 | printk(KERN_ERR "PIC init: got no IRQ for cpm cascade\n"); | ||
99 | return; | ||
100 | } | ||
101 | |||
102 | cpm2_pic_init(np); | ||
103 | of_node_put(np); | ||
104 | set_irq_chained_handler(irq, cpm2_cascade); | ||
105 | #endif | ||
106 | } | ||
107 | |||
108 | /* | ||
109 | * Setup the architecture | ||
110 | */ | ||
111 | static void __init stx_gp3_setup_arch(void) | ||
112 | { | ||
113 | #ifdef CONFIG_PCI | ||
114 | struct device_node *np; | ||
115 | #endif | ||
116 | |||
117 | if (ppc_md.progress) | ||
118 | ppc_md.progress("stx_gp3_setup_arch()", 0); | ||
119 | |||
120 | #ifdef CONFIG_CPM2 | ||
121 | cpm2_reset(); | ||
122 | #endif | ||
123 | |||
124 | #ifdef CONFIG_PCI | ||
125 | for_each_compatible_node(np, "pci", "fsl,mpc8540-pci") | ||
126 | fsl_add_bridge(np, 1); | ||
127 | #endif | ||
128 | } | ||
129 | |||
130 | static void stx_gp3_show_cpuinfo(struct seq_file *m) | ||
131 | { | ||
132 | uint pvid, svid, phid1; | ||
133 | uint memsize = total_memory; | ||
134 | |||
135 | pvid = mfspr(SPRN_PVR); | ||
136 | svid = mfspr(SPRN_SVR); | ||
137 | |||
138 | seq_printf(m, "Vendor\t\t: RPC Electronics STx \n"); | ||
139 | seq_printf(m, "PVR\t\t: 0x%x\n", pvid); | ||
140 | seq_printf(m, "SVR\t\t: 0x%x\n", svid); | ||
141 | |||
142 | /* Display cpu Pll setting */ | ||
143 | phid1 = mfspr(SPRN_HID1); | ||
144 | seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f)); | ||
145 | |||
146 | /* Display the amount of memory */ | ||
147 | seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024)); | ||
148 | } | ||
149 | |||
150 | static struct of_device_id __initdata of_bus_ids[] = { | ||
151 | { .compatible = "simple-bus", }, | ||
152 | {}, | ||
153 | }; | ||
154 | |||
155 | static int __init declare_of_platform_devices(void) | ||
156 | { | ||
157 | of_platform_bus_probe(NULL, of_bus_ids, NULL); | ||
158 | |||
159 | return 0; | ||
160 | } | ||
161 | machine_device_initcall(stx_gp3, declare_of_platform_devices); | ||
162 | |||
163 | /* | ||
164 | * Called very early, device-tree isn't unflattened | ||
165 | */ | ||
166 | static int __init stx_gp3_probe(void) | ||
167 | { | ||
168 | unsigned long root = of_get_flat_dt_root(); | ||
169 | |||
170 | return of_flat_dt_is_compatible(root, "stx,gp3-8560"); | ||
171 | } | ||
172 | |||
173 | define_machine(stx_gp3) { | ||
174 | .name = "STX GP3", | ||
175 | .probe = stx_gp3_probe, | ||
176 | .setup_arch = stx_gp3_setup_arch, | ||
177 | .init_IRQ = stx_gp3_pic_init, | ||
178 | .show_cpuinfo = stx_gp3_show_cpuinfo, | ||
179 | .get_irq = mpic_get_irq, | ||
180 | .restart = fsl_rstcr_restart, | ||
181 | .calibrate_decr = generic_calibrate_decr, | ||
182 | .progress = udbg_progress, | ||
183 | }; | ||
diff --git a/arch/powerpc/platforms/85xx/tqm85xx.c b/arch/powerpc/platforms/85xx/tqm85xx.c new file mode 100644 index 000000000000..77681acf1bae --- /dev/null +++ b/arch/powerpc/platforms/85xx/tqm85xx.c | |||
@@ -0,0 +1,187 @@ | |||
1 | /* | ||
2 | * Based on MPC8560 ADS and arch/ppc tqm85xx ports | ||
3 | * | ||
4 | * Maintained by Kumar Gala (see MAINTAINERS for contact information) | ||
5 | * | ||
6 | * Copyright 2008 Freescale Semiconductor Inc. | ||
7 | * | ||
8 | * Copyright (c) 2005-2006 DENX Software Engineering | ||
9 | * Stefan Roese <sr@denx.de> | ||
10 | * | ||
11 | * Based on original work by | ||
12 | * Kumar Gala <kumar.gala@freescale.com> | ||
13 | * Copyright 2004 Freescale Semiconductor Inc. | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or modify it | ||
16 | * under the terms of the GNU General Public License as published by the | ||
17 | * Free Software Foundation; either version 2 of the License, or (at your | ||
18 | * option) any later version. | ||
19 | */ | ||
20 | |||
21 | #include <linux/stddef.h> | ||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/pci.h> | ||
24 | #include <linux/kdev_t.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/seq_file.h> | ||
27 | #include <linux/of_platform.h> | ||
28 | |||
29 | #include <asm/system.h> | ||
30 | #include <asm/time.h> | ||
31 | #include <asm/machdep.h> | ||
32 | #include <asm/pci-bridge.h> | ||
33 | #include <asm/mpic.h> | ||
34 | #include <asm/prom.h> | ||
35 | #include <mm/mmu_decl.h> | ||
36 | #include <asm/udbg.h> | ||
37 | |||
38 | #include <sysdev/fsl_soc.h> | ||
39 | #include <sysdev/fsl_pci.h> | ||
40 | |||
41 | #ifdef CONFIG_CPM2 | ||
42 | #include <asm/cpm2.h> | ||
43 | #include <sysdev/cpm2_pic.h> | ||
44 | |||
45 | static void cpm2_cascade(unsigned int irq, struct irq_desc *desc) | ||
46 | { | ||
47 | int cascade_irq; | ||
48 | |||
49 | while ((cascade_irq = cpm2_get_irq()) >= 0) | ||
50 | generic_handle_irq(cascade_irq); | ||
51 | |||
52 | desc->chip->eoi(irq); | ||
53 | } | ||
54 | #endif /* CONFIG_CPM2 */ | ||
55 | |||
56 | static void __init tqm85xx_pic_init(void) | ||
57 | { | ||
58 | struct mpic *mpic; | ||
59 | struct resource r; | ||
60 | struct device_node *np; | ||
61 | #ifdef CONFIG_CPM2 | ||
62 | int irq; | ||
63 | #endif | ||
64 | |||
65 | np = of_find_node_by_type(NULL, "open-pic"); | ||
66 | if (!np) { | ||
67 | printk(KERN_ERR "Could not find open-pic node\n"); | ||
68 | return; | ||
69 | } | ||
70 | |||
71 | if (of_address_to_resource(np, 0, &r)) { | ||
72 | printk(KERN_ERR "Could not map mpic register space\n"); | ||
73 | of_node_put(np); | ||
74 | return; | ||
75 | } | ||
76 | |||
77 | mpic = mpic_alloc(np, r.start, | ||
78 | MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, | ||
79 | 0, 256, " OpenPIC "); | ||
80 | BUG_ON(mpic == NULL); | ||
81 | of_node_put(np); | ||
82 | |||
83 | mpic_init(mpic); | ||
84 | |||
85 | #ifdef CONFIG_CPM2 | ||
86 | /* Setup CPM2 PIC */ | ||
87 | np = of_find_compatible_node(NULL, NULL, "fsl,cpm2-pic"); | ||
88 | if (np == NULL) { | ||
89 | printk(KERN_ERR "PIC init: can not find fsl,cpm2-pic node\n"); | ||
90 | return; | ||
91 | } | ||
92 | irq = irq_of_parse_and_map(np, 0); | ||
93 | |||
94 | if (irq == NO_IRQ) { | ||
95 | of_node_put(np); | ||
96 | printk(KERN_ERR "PIC init: got no IRQ for cpm cascade\n"); | ||
97 | return; | ||
98 | } | ||
99 | |||
100 | cpm2_pic_init(np); | ||
101 | of_node_put(np); | ||
102 | set_irq_chained_handler(irq, cpm2_cascade); | ||
103 | #endif | ||
104 | } | ||
105 | |||
106 | /* | ||
107 | * Setup the architecture | ||
108 | */ | ||
109 | static void __init tqm85xx_setup_arch(void) | ||
110 | { | ||
111 | #ifdef CONFIG_PCI | ||
112 | struct device_node *np; | ||
113 | #endif | ||
114 | |||
115 | if (ppc_md.progress) | ||
116 | ppc_md.progress("tqm85xx_setup_arch()", 0); | ||
117 | |||
118 | #ifdef CONFIG_CPM2 | ||
119 | cpm2_reset(); | ||
120 | #endif | ||
121 | |||
122 | #ifdef CONFIG_PCI | ||
123 | for_each_compatible_node(np, "pci", "fsl,mpc8540-pci") | ||
124 | fsl_add_bridge(np, 1); | ||
125 | #endif | ||
126 | } | ||
127 | |||
128 | static void tqm85xx_show_cpuinfo(struct seq_file *m) | ||
129 | { | ||
130 | uint pvid, svid, phid1; | ||
131 | uint memsize = total_memory; | ||
132 | |||
133 | pvid = mfspr(SPRN_PVR); | ||
134 | svid = mfspr(SPRN_SVR); | ||
135 | |||
136 | seq_printf(m, "Vendor\t\t: TQ Components\n"); | ||
137 | seq_printf(m, "PVR\t\t: 0x%x\n", pvid); | ||
138 | seq_printf(m, "SVR\t\t: 0x%x\n", svid); | ||
139 | |||
140 | /* Display cpu Pll setting */ | ||
141 | phid1 = mfspr(SPRN_HID1); | ||
142 | seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f)); | ||
143 | |||
144 | /* Display the amount of memory */ | ||
145 | seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024)); | ||
146 | } | ||
147 | |||
148 | static struct of_device_id __initdata of_bus_ids[] = { | ||
149 | { .compatible = "simple-bus", }, | ||
150 | {}, | ||
151 | }; | ||
152 | |||
153 | static int __init declare_of_platform_devices(void) | ||
154 | { | ||
155 | of_platform_bus_probe(NULL, of_bus_ids, NULL); | ||
156 | |||
157 | return 0; | ||
158 | } | ||
159 | machine_device_initcall(tqm85xx, declare_of_platform_devices); | ||
160 | |||
161 | /* | ||
162 | * Called very early, device-tree isn't unflattened | ||
163 | */ | ||
164 | static int __init tqm85xx_probe(void) | ||
165 | { | ||
166 | unsigned long root = of_get_flat_dt_root(); | ||
167 | |||
168 | if ((of_flat_dt_is_compatible(root, "tqm,8540")) || | ||
169 | (of_flat_dt_is_compatible(root, "tqm,8541")) || | ||
170 | (of_flat_dt_is_compatible(root, "tqm,8555")) || | ||
171 | (of_flat_dt_is_compatible(root, "tqm,8560"))) | ||
172 | return 1; | ||
173 | |||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | define_machine(tqm85xx) { | ||
178 | .name = "TQM85xx", | ||
179 | .probe = tqm85xx_probe, | ||
180 | .setup_arch = tqm85xx_setup_arch, | ||
181 | .init_IRQ = tqm85xx_pic_init, | ||
182 | .show_cpuinfo = tqm85xx_show_cpuinfo, | ||
183 | .get_irq = mpic_get_irq, | ||
184 | .restart = fsl_rstcr_restart, | ||
185 | .calibrate_decr = generic_calibrate_decr, | ||
186 | .progress = udbg_progress, | ||
187 | }; | ||
diff --git a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c index 6390895e5e92..0b07485641fe 100644 --- a/arch/powerpc/platforms/86xx/mpc8610_hpcd.c +++ b/arch/powerpc/platforms/86xx/mpc8610_hpcd.c | |||
@@ -34,9 +34,24 @@ | |||
34 | 34 | ||
35 | #include <asm/mpic.h> | 35 | #include <asm/mpic.h> |
36 | 36 | ||
37 | #include <linux/of_platform.h> | ||
37 | #include <sysdev/fsl_pci.h> | 38 | #include <sysdev/fsl_pci.h> |
38 | #include <sysdev/fsl_soc.h> | 39 | #include <sysdev/fsl_soc.h> |
39 | 40 | ||
41 | static struct of_device_id __initdata mpc8610_ids[] = { | ||
42 | { .compatible = "fsl,mpc8610-immr", }, | ||
43 | {} | ||
44 | }; | ||
45 | |||
46 | static int __init mpc8610_declare_of_platform_devices(void) | ||
47 | { | ||
48 | /* Without this call, the SSI device driver won't get probed. */ | ||
49 | of_platform_bus_probe(NULL, mpc8610_ids, NULL); | ||
50 | |||
51 | return 0; | ||
52 | } | ||
53 | machine_device_initcall(mpc86xx_hpcd, mpc8610_declare_of_platform_devices); | ||
54 | |||
40 | void __init | 55 | void __init |
41 | mpc86xx_hpcd_init_irq(void) | 56 | mpc86xx_hpcd_init_irq(void) |
42 | { | 57 | { |
@@ -124,7 +139,7 @@ static void __devinit quirk_uli5229(struct pci_dev *dev) | |||
124 | static void __devinit final_uli5288(struct pci_dev *dev) | 139 | static void __devinit final_uli5288(struct pci_dev *dev) |
125 | { | 140 | { |
126 | struct pci_controller *hose = pci_bus_to_host(dev->bus); | 141 | struct pci_controller *hose = pci_bus_to_host(dev->bus); |
127 | struct device_node *hosenode = hose ? hose->arch_data : NULL; | 142 | struct device_node *hosenode = hose ? hose->dn : NULL; |
128 | struct of_irq oirq; | 143 | struct of_irq oirq; |
129 | int virq, pin = 2; | 144 | int virq, pin = 2; |
130 | u32 laddr[3]; | 145 | u32 laddr[3]; |
diff --git a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c index 32a531aebcb7..cfbe8c52e263 100644 --- a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c +++ b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/kdev_t.h> | 18 | #include <linux/kdev_t.h> |
19 | #include <linux/delay.h> | 19 | #include <linux/delay.h> |
20 | #include <linux/seq_file.h> | 20 | #include <linux/seq_file.h> |
21 | #include <linux/of_platform.h> | ||
21 | 22 | ||
22 | #include <asm/system.h> | 23 | #include <asm/system.h> |
23 | #include <asm/time.h> | 24 | #include <asm/time.h> |
@@ -116,7 +117,7 @@ static int mpc86xx_exclude_device(struct pci_controller *hose, | |||
116 | struct device_node* node; | 117 | struct device_node* node; |
117 | struct resource rsrc; | 118 | struct resource rsrc; |
118 | 119 | ||
119 | node = (struct device_node *)hose->arch_data; | 120 | node = hose->dn; |
120 | of_address_to_resource(node, 0, &rsrc); | 121 | of_address_to_resource(node, 0, &rsrc); |
121 | 122 | ||
122 | if ((rsrc.start & 0xfffff) == 0x8000) { | 123 | if ((rsrc.start & 0xfffff) == 0x8000) { |
@@ -212,6 +213,19 @@ mpc86xx_time_init(void) | |||
212 | return 0; | 213 | return 0; |
213 | } | 214 | } |
214 | 215 | ||
216 | static __initdata struct of_device_id of_bus_ids[] = { | ||
217 | { .compatible = "simple-bus", }, | ||
218 | {}, | ||
219 | }; | ||
220 | |||
221 | static int __init declare_of_platform_devices(void) | ||
222 | { | ||
223 | of_platform_bus_probe(NULL, of_bus_ids, NULL); | ||
224 | |||
225 | return 0; | ||
226 | } | ||
227 | machine_device_initcall(mpc86xx_hpcn, declare_of_platform_devices); | ||
228 | |||
215 | define_machine(mpc86xx_hpcn) { | 229 | define_machine(mpc86xx_hpcn) { |
216 | .name = "MPC86xx HPCN", | 230 | .name = "MPC86xx HPCN", |
217 | .probe = mpc86xx_hpcn_probe, | 231 | .probe = mpc86xx_hpcn_probe, |
diff --git a/arch/powerpc/platforms/8xx/Kconfig b/arch/powerpc/platforms/8xx/Kconfig index bd28655043a0..7fd224ca233d 100644 --- a/arch/powerpc/platforms/8xx/Kconfig +++ b/arch/powerpc/platforms/8xx/Kconfig | |||
@@ -18,6 +18,7 @@ config MPC8XXFADS | |||
18 | config MPC86XADS | 18 | config MPC86XADS |
19 | bool "MPC86XADS" | 19 | bool "MPC86XADS" |
20 | select CPM1 | 20 | select CPM1 |
21 | select PPC_CPM_NEW_BINDING | ||
21 | help | 22 | help |
22 | MPC86x Application Development System by Freescale Semiconductor. | 23 | MPC86x Application Development System by Freescale Semiconductor. |
23 | The MPC86xADS is meant to serve as a platform for s/w and h/w | 24 | The MPC86xADS is meant to serve as a platform for s/w and h/w |
@@ -43,6 +44,15 @@ config PPC_EP88XC | |||
43 | This board is also resold by Freescale as the QUICCStart | 44 | This board is also resold by Freescale as the QUICCStart |
44 | MPC885 Evaluation System and/or the CWH-PPC-885XN-VE. | 45 | MPC885 Evaluation System and/or the CWH-PPC-885XN-VE. |
45 | 46 | ||
47 | config PPC_ADDER875 | ||
48 | bool "Analogue & Micro Adder 875" | ||
49 | select CPM1 | ||
50 | select PPC_CPM_NEW_BINDING | ||
51 | select REDBOOT | ||
52 | help | ||
53 | This enables support for the Analogue & Micro Adder 875 | ||
54 | board. | ||
55 | |||
46 | endchoice | 56 | endchoice |
47 | 57 | ||
48 | menu "Freescale Ethernet driver platform-specific options" | 58 | menu "Freescale Ethernet driver platform-specific options" |
diff --git a/arch/powerpc/platforms/8xx/Makefile b/arch/powerpc/platforms/8xx/Makefile index 8b7098018b59..7b71d9c8fb45 100644 --- a/arch/powerpc/platforms/8xx/Makefile +++ b/arch/powerpc/platforms/8xx/Makefile | |||
@@ -5,3 +5,4 @@ obj-$(CONFIG_PPC_8xx) += m8xx_setup.o | |||
5 | obj-$(CONFIG_MPC885ADS) += mpc885ads_setup.o | 5 | obj-$(CONFIG_MPC885ADS) += mpc885ads_setup.o |
6 | obj-$(CONFIG_MPC86XADS) += mpc86xads_setup.o | 6 | obj-$(CONFIG_MPC86XADS) += mpc86xads_setup.o |
7 | obj-$(CONFIG_PPC_EP88XC) += ep88xc.o | 7 | obj-$(CONFIG_PPC_EP88XC) += ep88xc.o |
8 | obj-$(CONFIG_PPC_ADDER875) += adder875.o | ||
diff --git a/arch/powerpc/platforms/8xx/adder875.c b/arch/powerpc/platforms/8xx/adder875.c new file mode 100644 index 000000000000..c6bc0783c3b0 --- /dev/null +++ b/arch/powerpc/platforms/8xx/adder875.c | |||
@@ -0,0 +1,118 @@ | |||
1 | /* Analogue & Micro Adder MPC875 board support | ||
2 | * | ||
3 | * Author: Scott Wood <scottwood@freescale.com> | ||
4 | * | ||
5 | * Copyright (c) 2007 Freescale Semiconductor, Inc. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License, version 2, as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/init.h> | ||
13 | #include <linux/fs_enet_pd.h> | ||
14 | #include <linux/of_platform.h> | ||
15 | |||
16 | #include <asm/time.h> | ||
17 | #include <asm/machdep.h> | ||
18 | #include <asm/commproc.h> | ||
19 | #include <asm/fs_pd.h> | ||
20 | #include <asm/udbg.h> | ||
21 | #include <asm/prom.h> | ||
22 | |||
23 | #include <sysdev/commproc.h> | ||
24 | |||
25 | struct cpm_pin { | ||
26 | int port, pin, flags; | ||
27 | }; | ||
28 | |||
29 | static __initdata struct cpm_pin adder875_pins[] = { | ||
30 | /* SMC1 */ | ||
31 | {CPM_PORTB, 24, CPM_PIN_INPUT}, /* RX */ | ||
32 | {CPM_PORTB, 25, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, /* TX */ | ||
33 | |||
34 | /* MII1 */ | ||
35 | {CPM_PORTA, 0, CPM_PIN_INPUT}, | ||
36 | {CPM_PORTA, 1, CPM_PIN_INPUT}, | ||
37 | {CPM_PORTA, 2, CPM_PIN_INPUT}, | ||
38 | {CPM_PORTA, 3, CPM_PIN_INPUT}, | ||
39 | {CPM_PORTA, 4, CPM_PIN_OUTPUT}, | ||
40 | {CPM_PORTA, 10, CPM_PIN_OUTPUT}, | ||
41 | {CPM_PORTA, 11, CPM_PIN_OUTPUT}, | ||
42 | {CPM_PORTB, 19, CPM_PIN_INPUT}, | ||
43 | {CPM_PORTB, 31, CPM_PIN_INPUT}, | ||
44 | {CPM_PORTC, 12, CPM_PIN_INPUT}, | ||
45 | {CPM_PORTC, 13, CPM_PIN_INPUT}, | ||
46 | {CPM_PORTE, 30, CPM_PIN_OUTPUT}, | ||
47 | {CPM_PORTE, 31, CPM_PIN_OUTPUT}, | ||
48 | |||
49 | /* MII2 */ | ||
50 | {CPM_PORTE, 14, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, | ||
51 | {CPM_PORTE, 15, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, | ||
52 | {CPM_PORTE, 16, CPM_PIN_OUTPUT}, | ||
53 | {CPM_PORTE, 17, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, | ||
54 | {CPM_PORTE, 18, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, | ||
55 | {CPM_PORTE, 19, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, | ||
56 | {CPM_PORTE, 20, CPM_PIN_OUTPUT | CPM_PIN_SECONDARY}, | ||
57 | {CPM_PORTE, 21, CPM_PIN_OUTPUT}, | ||
58 | {CPM_PORTE, 22, CPM_PIN_OUTPUT}, | ||
59 | {CPM_PORTE, 23, CPM_PIN_OUTPUT}, | ||
60 | {CPM_PORTE, 24, CPM_PIN_OUTPUT}, | ||
61 | {CPM_PORTE, 25, CPM_PIN_OUTPUT}, | ||
62 | {CPM_PORTE, 26, CPM_PIN_OUTPUT}, | ||
63 | {CPM_PORTE, 27, CPM_PIN_OUTPUT}, | ||
64 | {CPM_PORTE, 28, CPM_PIN_OUTPUT}, | ||
65 | {CPM_PORTE, 29, CPM_PIN_OUTPUT}, | ||
66 | }; | ||
67 | |||
68 | static void __init init_ioports(void) | ||
69 | { | ||
70 | int i; | ||
71 | |||
72 | for (i = 0; i < ARRAY_SIZE(adder875_pins); i++) { | ||
73 | const struct cpm_pin *pin = &adder875_pins[i]; | ||
74 | cpm1_set_pin(pin->port, pin->pin, pin->flags); | ||
75 | } | ||
76 | |||
77 | cpm1_clk_setup(CPM_CLK_SMC1, CPM_BRG1, CPM_CLK_RTX); | ||
78 | |||
79 | /* Set FEC1 and FEC2 to MII mode */ | ||
80 | clrbits32(&mpc8xx_immr->im_cpm.cp_cptr, 0x00000180); | ||
81 | } | ||
82 | |||
83 | static void __init adder875_setup(void) | ||
84 | { | ||
85 | cpm_reset(); | ||
86 | init_ioports(); | ||
87 | } | ||
88 | |||
89 | static int __init adder875_probe(void) | ||
90 | { | ||
91 | unsigned long root = of_get_flat_dt_root(); | ||
92 | return of_flat_dt_is_compatible(root, "analogue-and-micro,adder875"); | ||
93 | } | ||
94 | |||
95 | static __initdata struct of_device_id of_bus_ids[] = { | ||
96 | { .compatible = "simple-bus", }, | ||
97 | {}, | ||
98 | }; | ||
99 | |||
100 | static int __init declare_of_platform_devices(void) | ||
101 | { | ||
102 | of_platform_bus_probe(NULL, of_bus_ids, NULL); | ||
103 | return 0; | ||
104 | } | ||
105 | machine_device_initcall(adder875, declare_of_platform_devices); | ||
106 | |||
107 | define_machine(adder875) { | ||
108 | .name = "Adder MPC875", | ||
109 | .probe = adder875_probe, | ||
110 | .setup_arch = adder875_setup, | ||
111 | .init_IRQ = m8xx_pic_init, | ||
112 | .get_irq = mpc8xx_get_irq, | ||
113 | .restart = mpc8xx_restart, | ||
114 | .calibrate_decr = generic_calibrate_decr, | ||
115 | .set_rtc_time = mpc8xx_set_rtc_time, | ||
116 | .get_rtc_time = mpc8xx_get_rtc_time, | ||
117 | .progress = udbg_progress, | ||
118 | }; | ||
diff --git a/arch/powerpc/platforms/8xx/ep88xc.c b/arch/powerpc/platforms/8xx/ep88xc.c index c518b6cc5fab..a8dffa005775 100644 --- a/arch/powerpc/platforms/8xx/ep88xc.c +++ b/arch/powerpc/platforms/8xx/ep88xc.c | |||
@@ -16,8 +16,9 @@ | |||
16 | #include <asm/io.h> | 16 | #include <asm/io.h> |
17 | #include <asm/udbg.h> | 17 | #include <asm/udbg.h> |
18 | #include <asm/commproc.h> | 18 | #include <asm/commproc.h> |
19 | #include <asm/cpm1.h> | ||
19 | 20 | ||
20 | #include <sysdev/commproc.h> | 21 | #include "mpc8xx.h" |
21 | 22 | ||
22 | struct cpm_pin { | 23 | struct cpm_pin { |
23 | int port, pin, flags; | 24 | int port, pin, flags; |
@@ -155,18 +156,17 @@ static struct of_device_id __initdata of_bus_ids[] = { | |||
155 | static int __init declare_of_platform_devices(void) | 156 | static int __init declare_of_platform_devices(void) |
156 | { | 157 | { |
157 | /* Publish the QE devices */ | 158 | /* Publish the QE devices */ |
158 | if (machine_is(ep88xc)) | 159 | of_platform_bus_probe(NULL, of_bus_ids, NULL); |
159 | of_platform_bus_probe(NULL, of_bus_ids, NULL); | ||
160 | 160 | ||
161 | return 0; | 161 | return 0; |
162 | } | 162 | } |
163 | device_initcall(declare_of_platform_devices); | 163 | machine_device_initcall(ep88xc, declare_of_platform_devices); |
164 | 164 | ||
165 | define_machine(ep88xc) { | 165 | define_machine(ep88xc) { |
166 | .name = "Embedded Planet EP88xC", | 166 | .name = "Embedded Planet EP88xC", |
167 | .probe = ep88xc_probe, | 167 | .probe = ep88xc_probe, |
168 | .setup_arch = ep88xc_setup_arch, | 168 | .setup_arch = ep88xc_setup_arch, |
169 | .init_IRQ = m8xx_pic_init, | 169 | .init_IRQ = mpc8xx_pics_init, |
170 | .get_irq = mpc8xx_get_irq, | 170 | .get_irq = mpc8xx_get_irq, |
171 | .restart = mpc8xx_restart, | 171 | .restart = mpc8xx_restart, |
172 | .calibrate_decr = mpc8xx_calibrate_decr, | 172 | .calibrate_decr = mpc8xx_calibrate_decr, |
diff --git a/arch/powerpc/platforms/8xx/m8xx_setup.c b/arch/powerpc/platforms/8xx/m8xx_setup.c index d35eda80e9e6..184f998d1be2 100644 --- a/arch/powerpc/platforms/8xx/m8xx_setup.c +++ b/arch/powerpc/platforms/8xx/m8xx_setup.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/init.h> | 16 | #include <linux/init.h> |
17 | #include <linux/time.h> | 17 | #include <linux/time.h> |
18 | #include <linux/rtc.h> | 18 | #include <linux/rtc.h> |
19 | #include <linux/fsl_devices.h> | ||
19 | 20 | ||
20 | #include <asm/io.h> | 21 | #include <asm/io.h> |
21 | #include <asm/mpc8xx.h> | 22 | #include <asm/mpc8xx.h> |
@@ -25,13 +26,11 @@ | |||
25 | #include <mm/mmu_decl.h> | 26 | #include <mm/mmu_decl.h> |
26 | 27 | ||
27 | #include <sysdev/mpc8xx_pic.h> | 28 | #include <sysdev/mpc8xx_pic.h> |
28 | #include <sysdev/commproc.h> | ||
29 | 29 | ||
30 | #ifdef CONFIG_PCMCIA_M8XX | 30 | #include "mpc8xx.h" |
31 | |||
31 | struct mpc8xx_pcmcia_ops m8xx_pcmcia_ops; | 32 | struct mpc8xx_pcmcia_ops m8xx_pcmcia_ops; |
32 | #endif | ||
33 | 33 | ||
34 | void m8xx_calibrate_decr(void); | ||
35 | extern int cpm_pic_init(void); | 34 | extern int cpm_pic_init(void); |
36 | extern int cpm_get_irq(void); | 35 | extern int cpm_get_irq(void); |
37 | 36 | ||
@@ -120,7 +119,7 @@ void __init mpc8xx_calibrate_decr(void) | |||
120 | ppc_tb_freq /= 16; | 119 | ppc_tb_freq /= 16; |
121 | ppc_proc_freq = 50000000; | 120 | ppc_proc_freq = 50000000; |
122 | if (!get_freq("clock-frequency", &ppc_proc_freq)) | 121 | if (!get_freq("clock-frequency", &ppc_proc_freq)) |
123 | printk(KERN_ERR "WARNING: Estimating processor frequency" | 122 | printk(KERN_ERR "WARNING: Estimating processor frequency " |
124 | "(not found)\n"); | 123 | "(not found)\n"); |
125 | 124 | ||
126 | printk("Decrementer Frequency = 0x%lx\n", ppc_tb_freq); | 125 | printk("Decrementer Frequency = 0x%lx\n", ppc_tb_freq); |
@@ -237,13 +236,13 @@ static void cpm_cascade(unsigned int irq, struct irq_desc *desc) | |||
237 | desc->chip->eoi(irq); | 236 | desc->chip->eoi(irq); |
238 | } | 237 | } |
239 | 238 | ||
240 | /* Initialize the internal interrupt controller. The number of | 239 | /* Initialize the internal interrupt controllers. The number of |
241 | * interrupts supported can vary with the processor type, and the | 240 | * interrupts supported can vary with the processor type, and the |
242 | * 82xx family can have up to 64. | 241 | * 82xx family can have up to 64. |
243 | * External interrupts can be either edge or level triggered, and | 242 | * External interrupts can be either edge or level triggered, and |
244 | * need to be initialized by the appropriate driver. | 243 | * need to be initialized by the appropriate driver. |
245 | */ | 244 | */ |
246 | void __init m8xx_pic_init(void) | 245 | void __init mpc8xx_pics_init(void) |
247 | { | 246 | { |
248 | int irq; | 247 | int irq; |
249 | 248 | ||
diff --git a/arch/powerpc/platforms/8xx/mpc86xads.h b/arch/powerpc/platforms/8xx/mpc86xads.h index cffa194ccf1f..17b1fe75e0b2 100644 --- a/arch/powerpc/platforms/8xx/mpc86xads.h +++ b/arch/powerpc/platforms/8xx/mpc86xads.h | |||
@@ -15,27 +15,6 @@ | |||
15 | #ifndef __ASM_MPC86XADS_H__ | 15 | #ifndef __ASM_MPC86XADS_H__ |
16 | #define __ASM_MPC86XADS_H__ | 16 | #define __ASM_MPC86XADS_H__ |
17 | 17 | ||
18 | #include <sysdev/fsl_soc.h> | ||
19 | |||
20 | /* U-Boot maps BCSR to 0xff080000 */ | ||
21 | #define BCSR_ADDR ((uint)0xff080000) | ||
22 | #define BCSR_SIZE ((uint)32) | ||
23 | #define BCSR0 ((uint)(BCSR_ADDR + 0x00)) | ||
24 | #define BCSR1 ((uint)(BCSR_ADDR + 0x04)) | ||
25 | #define BCSR2 ((uint)(BCSR_ADDR + 0x08)) | ||
26 | #define BCSR3 ((uint)(BCSR_ADDR + 0x0c)) | ||
27 | #define BCSR4 ((uint)(BCSR_ADDR + 0x10)) | ||
28 | |||
29 | #define CFG_PHYDEV_ADDR ((uint)0xff0a0000) | ||
30 | #define BCSR5 ((uint)(CFG_PHYDEV_ADDR + 0x300)) | ||
31 | |||
32 | #define MPC8xx_CPM_OFFSET (0x9c0) | ||
33 | #define CPM_MAP_ADDR (get_immrbase() + MPC8xx_CPM_OFFSET) | ||
34 | #define CPM_IRQ_OFFSET 16 // for compability with cpm_uart driver | ||
35 | |||
36 | #define PCMCIA_MEM_ADDR ((uint)0xff020000) | ||
37 | #define PCMCIA_MEM_SIZE ((uint)(64 * 1024)) | ||
38 | |||
39 | /* Bits of interest in the BCSRs. | 18 | /* Bits of interest in the BCSRs. |
40 | */ | 19 | */ |
41 | #define BCSR1_ETHEN ((uint)0x20000000) | 20 | #define BCSR1_ETHEN ((uint)0x20000000) |
@@ -64,28 +43,5 @@ | |||
64 | #define BCSR5_MII1_EN 0x02 | 43 | #define BCSR5_MII1_EN 0x02 |
65 | #define BCSR5_MII1_RST 0x01 | 44 | #define BCSR5_MII1_RST 0x01 |
66 | 45 | ||
67 | /* Interrupt level assignments */ | ||
68 | #define PHY_INTERRUPT SIU_IRQ7 /* PHY link change interrupt */ | ||
69 | #define SIU_INT_FEC1 SIU_LEVEL1 /* FEC1 interrupt */ | ||
70 | #define FEC_INTERRUPT SIU_INT_FEC1 /* FEC interrupt */ | ||
71 | |||
72 | /* We don't use the 8259 */ | ||
73 | #define NR_8259_INTS 0 | ||
74 | |||
75 | /* CPM Ethernet through SCC1 */ | ||
76 | #define PA_ENET_RXD ((ushort)0x0001) | ||
77 | #define PA_ENET_TXD ((ushort)0x0002) | ||
78 | #define PA_ENET_TCLK ((ushort)0x0100) | ||
79 | #define PA_ENET_RCLK ((ushort)0x0200) | ||
80 | #define PB_ENET_TENA ((uint)0x00001000) | ||
81 | #define PC_ENET_CLSN ((ushort)0x0010) | ||
82 | #define PC_ENET_RENA ((ushort)0x0020) | ||
83 | |||
84 | /* Control bits in the SICR to route TCLK (CLK1) and RCLK (CLK2) to | ||
85 | * SCC1. Also, make sure GR1 (bit 24) and SC1 (bit 25) are zero. | ||
86 | */ | ||
87 | #define SICR_ENET_MASK ((uint)0x000000ff) | ||
88 | #define SICR_ENET_CLKRT ((uint)0x0000002c) | ||
89 | |||
90 | #endif /* __ASM_MPC86XADS_H__ */ | 46 | #endif /* __ASM_MPC86XADS_H__ */ |
91 | #endif /* __KERNEL__ */ | 47 | #endif /* __KERNEL__ */ |
diff --git a/arch/powerpc/platforms/8xx/mpc86xads_setup.c b/arch/powerpc/platforms/8xx/mpc86xads_setup.c index 49012835f453..c028a5b71bbb 100644 --- a/arch/powerpc/platforms/8xx/mpc86xads_setup.c +++ b/arch/powerpc/platforms/8xx/mpc86xads_setup.c | |||
@@ -6,273 +6,141 @@ | |||
6 | * | 6 | * |
7 | * Copyright 2005 MontaVista Software Inc. | 7 | * Copyright 2005 MontaVista Software Inc. |
8 | * | 8 | * |
9 | * Heavily modified by Scott Wood <scottwood@freescale.com> | ||
10 | * Copyright 2007 Freescale Semiconductor, Inc. | ||
11 | * | ||
9 | * This file is licensed under the terms of the GNU General Public License | 12 | * This file is licensed under the terms of the GNU General Public License |
10 | * version 2. This program is licensed "as is" without any warranty of any | 13 | * version 2. This program is licensed "as is" without any warranty of any |
11 | * kind, whether express or implied. | 14 | * kind, whether express or implied. |
12 | */ | 15 | */ |
13 | 16 | ||
14 | #include <linux/init.h> | 17 | #include <linux/init.h> |
15 | #include <linux/module.h> | 18 | #include <linux/of_platform.h> |
16 | #include <linux/param.h> | ||
17 | #include <linux/string.h> | ||
18 | #include <linux/ioport.h> | ||
19 | #include <linux/device.h> | ||
20 | #include <linux/delay.h> | ||
21 | #include <linux/root_dev.h> | ||
22 | |||
23 | #include <linux/fs_enet_pd.h> | ||
24 | #include <linux/fs_uart_pd.h> | ||
25 | #include <linux/mii.h> | ||
26 | 19 | ||
27 | #include <asm/delay.h> | ||
28 | #include <asm/io.h> | 20 | #include <asm/io.h> |
29 | #include <asm/machdep.h> | 21 | #include <asm/machdep.h> |
30 | #include <asm/page.h> | ||
31 | #include <asm/processor.h> | ||
32 | #include <asm/system.h> | 22 | #include <asm/system.h> |
33 | #include <asm/time.h> | 23 | #include <asm/time.h> |
34 | #include <asm/mpc8xx.h> | ||
35 | #include <asm/8xx_immap.h> | 24 | #include <asm/8xx_immap.h> |
36 | #include <asm/commproc.h> | 25 | #include <asm/cpm1.h> |
37 | #include <asm/fs_pd.h> | 26 | #include <asm/fs_pd.h> |
38 | #include <asm/prom.h> | 27 | #include <asm/udbg.h> |
39 | 28 | ||
40 | #include <sysdev/commproc.h> | 29 | #include "mpc86xads.h" |
30 | #include "mpc8xx.h" | ||
41 | 31 | ||
42 | static void init_smc1_uart_ioports(struct fs_uart_platform_info* fpi); | 32 | struct cpm_pin { |
43 | static void init_smc2_uart_ioports(struct fs_uart_platform_info* fpi); | 33 | int port, pin, flags; |
44 | static void init_scc1_ioports(struct fs_platform_info* ptr); | 34 | }; |
45 | 35 | ||
46 | void __init mpc86xads_board_setup(void) | 36 | static struct cpm_pin mpc866ads_pins[] = { |
47 | { | 37 | /* SMC1 */ |
48 | cpm8xx_t *cp; | 38 | {CPM_PORTB, 24, CPM_PIN_INPUT}, /* RX */ |
49 | unsigned int *bcsr_io; | 39 | {CPM_PORTB, 25, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, /* TX */ |
50 | u8 tmpval8; | 40 | |
41 | /* SMC2 */ | ||
42 | {CPM_PORTB, 21, CPM_PIN_INPUT}, /* RX */ | ||
43 | {CPM_PORTB, 20, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, /* TX */ | ||
44 | |||
45 | /* SCC1 */ | ||
46 | {CPM_PORTA, 6, CPM_PIN_INPUT}, /* CLK1 */ | ||
47 | {CPM_PORTA, 7, CPM_PIN_INPUT}, /* CLK2 */ | ||
48 | {CPM_PORTA, 14, CPM_PIN_INPUT}, /* TX */ | ||
49 | {CPM_PORTA, 15, CPM_PIN_INPUT}, /* RX */ | ||
50 | {CPM_PORTB, 19, CPM_PIN_INPUT | CPM_PIN_SECONDARY}, /* TENA */ | ||
51 | {CPM_PORTC, 10, CPM_PIN_INPUT | CPM_PIN_SECONDARY | CPM_PIN_GPIO}, /* RENA */ | ||
52 | {CPM_PORTC, 11, CPM_PIN_INPUT | CPM_PIN_SECONDARY | CPM_PIN_GPIO}, /* CLSN */ | ||
53 | |||
54 | /* MII */ | ||
55 | {CPM_PORTD, 3, CPM_PIN_OUTPUT}, | ||
56 | {CPM_PORTD, 4, CPM_PIN_OUTPUT}, | ||
57 | {CPM_PORTD, 5, CPM_PIN_OUTPUT}, | ||
58 | {CPM_PORTD, 6, CPM_PIN_OUTPUT}, | ||
59 | {CPM_PORTD, 7, CPM_PIN_OUTPUT}, | ||
60 | {CPM_PORTD, 8, CPM_PIN_OUTPUT}, | ||
61 | {CPM_PORTD, 9, CPM_PIN_OUTPUT}, | ||
62 | {CPM_PORTD, 10, CPM_PIN_OUTPUT}, | ||
63 | {CPM_PORTD, 11, CPM_PIN_OUTPUT}, | ||
64 | {CPM_PORTD, 12, CPM_PIN_OUTPUT}, | ||
65 | {CPM_PORTD, 13, CPM_PIN_OUTPUT}, | ||
66 | {CPM_PORTD, 14, CPM_PIN_OUTPUT}, | ||
67 | {CPM_PORTD, 15, CPM_PIN_OUTPUT}, | ||
68 | }; | ||
51 | 69 | ||
52 | bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); | 70 | static void __init init_ioports(void) |
53 | cp = (cpm8xx_t *)immr_map(im_cpm); | 71 | { |
72 | int i; | ||
54 | 73 | ||
55 | if (bcsr_io == NULL) { | 74 | for (i = 0; i < ARRAY_SIZE(mpc866ads_pins); i++) { |
56 | printk(KERN_CRIT "Could not remap BCSR\n"); | 75 | struct cpm_pin *pin = &mpc866ads_pins[i]; |
57 | return; | 76 | cpm1_set_pin(pin->port, pin->pin, pin->flags); |
58 | } | 77 | } |
59 | #ifdef CONFIG_SERIAL_CPM_SMC1 | ||
60 | clrbits32(bcsr_io, BCSR1_RS232EN_1); | ||
61 | clrbits32(&cp->cp_simode, 0xe0000000 >> 17); /* brg1 */ | ||
62 | tmpval8 = in_8(&(cp->cp_smc[0].smc_smcm)) | (SMCM_RX | SMCM_TX); | ||
63 | out_8(&(cp->cp_smc[0].smc_smcm), tmpval8); | ||
64 | clrbits16(&cp->cp_smc[0].smc_smcmr, SMCMR_REN | SMCMR_TEN); | ||
65 | #else | ||
66 | setbits32(bcsr_io,BCSR1_RS232EN_1); | ||
67 | out_be16(&cp->cp_smc[0].smc_smcmr, 0); | ||
68 | out_8(&cp->cp_smc[0].smc_smce, 0); | ||
69 | #endif | ||
70 | 78 | ||
71 | #ifdef CONFIG_SERIAL_CPM_SMC2 | 79 | cpm1_clk_setup(CPM_CLK_SMC1, CPM_BRG1, CPM_CLK_RTX); |
72 | clrbits32(bcsr_io,BCSR1_RS232EN_2); | 80 | cpm1_clk_setup(CPM_CLK_SMC2, CPM_BRG2, CPM_CLK_RTX); |
73 | clrbits32(&cp->cp_simode, 0xe0000000 >> 1); | 81 | cpm1_clk_setup(CPM_CLK_SCC1, CPM_CLK1, CPM_CLK_TX); |
74 | setbits32(&cp->cp_simode, 0x20000000 >> 1); /* brg2 */ | 82 | cpm1_clk_setup(CPM_CLK_SCC1, CPM_CLK2, CPM_CLK_RX); |
75 | tmpval8 = in_8(&(cp->cp_smc[1].smc_smcm)) | (SMCM_RX | SMCM_TX); | ||
76 | out_8(&(cp->cp_smc[1].smc_smcm), tmpval8); | ||
77 | clrbits16(&cp->cp_smc[1].smc_smcmr, SMCMR_REN | SMCMR_TEN); | ||
78 | 83 | ||
79 | init_smc2_uart_ioports(0); | 84 | /* Set FEC1 and FEC2 to MII mode */ |
80 | #else | 85 | clrbits32(&mpc8xx_immr->im_cpm.cp_cptr, 0x00000180); |
81 | setbits32(bcsr_io,BCSR1_RS232EN_2); | ||
82 | out_be16(&cp->cp_smc[1].smc_smcmr, 0); | ||
83 | out_8(&cp->cp_smc[1].smc_smce, 0); | ||
84 | #endif | ||
85 | immr_unmap(cp); | ||
86 | iounmap(bcsr_io); | ||
87 | } | 86 | } |
88 | 87 | ||
89 | 88 | static void __init mpc86xads_setup_arch(void) | |
90 | static void init_fec1_ioports(struct fs_platform_info* ptr) | ||
91 | { | 89 | { |
92 | iop8xx_t *io_port = (iop8xx_t *)immr_map(im_ioport); | 90 | struct device_node *np; |
93 | 91 | u32 __iomem *bcsr_io; | |
94 | /* configure FEC1 pins */ | ||
95 | |||
96 | setbits16(&io_port->iop_pdpar, 0x1fff); | ||
97 | setbits16(&io_port->iop_pddir, 0x1fff); | ||
98 | |||
99 | immr_unmap(io_port); | ||
100 | } | ||
101 | 92 | ||
102 | void init_fec_ioports(struct fs_platform_info *fpi) | 93 | cpm_reset(); |
103 | { | 94 | init_ioports(); |
104 | int fec_no = fs_get_fec_index(fpi->fs_no); | ||
105 | 95 | ||
106 | switch (fec_no) { | 96 | np = of_find_compatible_node(NULL, NULL, "fsl,mpc866ads-bcsr"); |
107 | case 0: | 97 | if (!np) { |
108 | init_fec1_ioports(fpi); | 98 | printk(KERN_CRIT "Could not find fsl,mpc866ads-bcsr node\n"); |
109 | break; | ||
110 | default: | ||
111 | printk(KERN_ERR "init_fec_ioports: invalid FEC number\n"); | ||
112 | return; | 99 | return; |
113 | } | 100 | } |
114 | } | ||
115 | |||
116 | static void init_scc1_ioports(struct fs_platform_info* fpi) | ||
117 | { | ||
118 | unsigned *bcsr_io; | ||
119 | iop8xx_t *io_port; | ||
120 | cpm8xx_t *cp; | ||
121 | 101 | ||
122 | bcsr_io = ioremap(BCSR_ADDR, BCSR_SIZE); | 102 | bcsr_io = of_iomap(np, 0); |
123 | io_port = (iop8xx_t *)immr_map(im_ioport); | 103 | of_node_put(np); |
124 | cp = (cpm8xx_t *)immr_map(im_cpm); | ||
125 | 104 | ||
126 | if (bcsr_io == NULL) { | 105 | if (bcsr_io == NULL) { |
127 | printk(KERN_CRIT "Could not remap BCSR\n"); | 106 | printk(KERN_CRIT "Could not remap BCSR\n"); |
128 | return; | 107 | return; |
129 | } | 108 | } |
130 | 109 | ||
131 | /* Configure port A pins for Txd and Rxd. | 110 | clrbits32(bcsr_io, BCSR1_RS232EN_1 | BCSR1_RS232EN_2 | BCSR1_ETHEN); |
132 | */ | ||
133 | setbits16(&io_port->iop_papar, PA_ENET_RXD | PA_ENET_TXD); | ||
134 | clrbits16(&io_port->iop_padir, PA_ENET_RXD | PA_ENET_TXD); | ||
135 | clrbits16(&io_port->iop_paodr, PA_ENET_TXD); | ||
136 | |||
137 | /* Configure port C pins to enable CLSN and RENA. | ||
138 | */ | ||
139 | clrbits16(&io_port->iop_pcpar, PC_ENET_CLSN | PC_ENET_RENA); | ||
140 | clrbits16(&io_port->iop_pcdir, PC_ENET_CLSN | PC_ENET_RENA); | ||
141 | setbits16(&io_port->iop_pcso, PC_ENET_CLSN | PC_ENET_RENA); | ||
142 | |||
143 | /* Configure port A for TCLK and RCLK. | ||
144 | */ | ||
145 | setbits16(&io_port->iop_papar, PA_ENET_TCLK | PA_ENET_RCLK); | ||
146 | clrbits16(&io_port->iop_padir, PA_ENET_TCLK | PA_ENET_RCLK); | ||
147 | clrbits32(&cp->cp_pbpar, PB_ENET_TENA); | ||
148 | clrbits32(&cp->cp_pbdir, PB_ENET_TENA); | ||
149 | |||
150 | /* Configure Serial Interface clock routing. | ||
151 | * First, clear all SCC bits to zero, then set the ones we want. | ||
152 | */ | ||
153 | clrbits32(&cp->cp_sicr, SICR_ENET_MASK); | ||
154 | setbits32(&cp->cp_sicr, SICR_ENET_CLKRT); | ||
155 | |||
156 | /* In the original SCC enet driver the following code is placed at | ||
157 | the end of the initialization */ | ||
158 | setbits32(&cp->cp_pbpar, PB_ENET_TENA); | ||
159 | setbits32(&cp->cp_pbdir, PB_ENET_TENA); | ||
160 | |||
161 | clrbits32(bcsr_io+1, BCSR1_ETHEN); | ||
162 | iounmap(bcsr_io); | 111 | iounmap(bcsr_io); |
163 | immr_unmap(cp); | ||
164 | immr_unmap(io_port); | ||
165 | } | 112 | } |
166 | 113 | ||
167 | void init_scc_ioports(struct fs_platform_info *fpi) | 114 | static int __init mpc86xads_probe(void) |
168 | { | ||
169 | int scc_no = fs_get_scc_index(fpi->fs_no); | ||
170 | |||
171 | switch (scc_no) { | ||
172 | case 0: | ||
173 | init_scc1_ioports(fpi); | ||
174 | break; | ||
175 | default: | ||
176 | printk(KERN_ERR "init_scc_ioports: invalid SCC number\n"); | ||
177 | return; | ||
178 | } | ||
179 | } | ||
180 | |||
181 | |||
182 | |||
183 | static void init_smc1_uart_ioports(struct fs_uart_platform_info* ptr) | ||
184 | { | 115 | { |
185 | unsigned *bcsr_io; | 116 | unsigned long root = of_get_flat_dt_root(); |
186 | cpm8xx_t *cp = (cpm8xx_t *)immr_map(im_cpm); | 117 | return of_flat_dt_is_compatible(root, "fsl,mpc866ads"); |
187 | |||
188 | setbits32(&cp->cp_pbpar, 0x000000c0); | ||
189 | clrbits32(&cp->cp_pbdir, 0x000000c0); | ||
190 | clrbits16(&cp->cp_pbodr, 0x00c0); | ||
191 | immr_unmap(cp); | ||
192 | |||
193 | bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); | ||
194 | |||
195 | if (bcsr_io == NULL) { | ||
196 | printk(KERN_CRIT "Could not remap BCSR1\n"); | ||
197 | return; | ||
198 | } | ||
199 | clrbits32(bcsr_io,BCSR1_RS232EN_1); | ||
200 | iounmap(bcsr_io); | ||
201 | } | 118 | } |
202 | 119 | ||
203 | static void init_smc2_uart_ioports(struct fs_uart_platform_info* fpi) | 120 | static struct of_device_id __initdata of_bus_ids[] = { |
204 | { | 121 | { .name = "soc", }, |
205 | unsigned *bcsr_io; | 122 | { .name = "cpm", }, |
206 | cpm8xx_t *cp = (cpm8xx_t *)immr_map(im_cpm); | 123 | { .name = "localbus", }, |
207 | 124 | {}, | |
208 | setbits32(&cp->cp_pbpar, 0x00000c00); | 125 | }; |
209 | clrbits32(&cp->cp_pbdir, 0x00000c00); | ||
210 | clrbits16(&cp->cp_pbodr, 0x0c00); | ||
211 | immr_unmap(cp); | ||
212 | |||
213 | bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); | ||
214 | |||
215 | if (bcsr_io == NULL) { | ||
216 | printk(KERN_CRIT "Could not remap BCSR1\n"); | ||
217 | return; | ||
218 | } | ||
219 | clrbits32(bcsr_io,BCSR1_RS232EN_2); | ||
220 | iounmap(bcsr_io); | ||
221 | } | ||
222 | 126 | ||
223 | void init_smc_ioports(struct fs_uart_platform_info *data) | 127 | static int __init declare_of_platform_devices(void) |
224 | { | 128 | { |
225 | int smc_no = fs_uart_id_fsid2smc(data->fs_no); | 129 | of_platform_bus_probe(NULL, of_bus_ids, NULL); |
226 | |||
227 | switch (smc_no) { | ||
228 | case 0: | ||
229 | init_smc1_uart_ioports(data); | ||
230 | data->brg = data->clk_rx; | ||
231 | break; | ||
232 | case 1: | ||
233 | init_smc2_uart_ioports(data); | ||
234 | data->brg = data->clk_rx; | ||
235 | break; | ||
236 | default: | ||
237 | printk(KERN_ERR "init_scc_ioports: invalid SCC number\n"); | ||
238 | return; | ||
239 | } | ||
240 | } | ||
241 | 130 | ||
242 | int platform_device_skip(const char *model, int id) | ||
243 | { | ||
244 | return 0; | 131 | return 0; |
245 | } | 132 | } |
246 | 133 | machine_device_initcall(mpc86x_ads, declare_of_platform_devices); | |
247 | static void __init mpc86xads_setup_arch(void) | ||
248 | { | ||
249 | cpm_reset(); | ||
250 | |||
251 | mpc86xads_board_setup(); | ||
252 | |||
253 | ROOT_DEV = Root_NFS; | ||
254 | } | ||
255 | |||
256 | static int __init mpc86xads_probe(void) | ||
257 | { | ||
258 | char *model = of_get_flat_dt_prop(of_get_flat_dt_root(), | ||
259 | "model", NULL); | ||
260 | if (model == NULL) | ||
261 | return 0; | ||
262 | if (strcmp(model, "MPC866ADS")) | ||
263 | return 0; | ||
264 | |||
265 | return 1; | ||
266 | } | ||
267 | 134 | ||
268 | define_machine(mpc86x_ads) { | 135 | define_machine(mpc86x_ads) { |
269 | .name = "MPC86x ADS", | 136 | .name = "MPC86x ADS", |
270 | .probe = mpc86xads_probe, | 137 | .probe = mpc86xads_probe, |
271 | .setup_arch = mpc86xads_setup_arch, | 138 | .setup_arch = mpc86xads_setup_arch, |
272 | .init_IRQ = m8xx_pic_init, | 139 | .init_IRQ = mpc8xx_pics_init, |
273 | .get_irq = mpc8xx_get_irq, | 140 | .get_irq = mpc8xx_get_irq, |
274 | .restart = mpc8xx_restart, | 141 | .restart = mpc8xx_restart, |
275 | .calibrate_decr = mpc8xx_calibrate_decr, | 142 | .calibrate_decr = mpc8xx_calibrate_decr, |
276 | .set_rtc_time = mpc8xx_set_rtc_time, | 143 | .set_rtc_time = mpc8xx_set_rtc_time, |
277 | .get_rtc_time = mpc8xx_get_rtc_time, | 144 | .get_rtc_time = mpc8xx_get_rtc_time, |
145 | .progress = udbg_progress, | ||
278 | }; | 146 | }; |
diff --git a/arch/powerpc/platforms/8xx/mpc885ads_setup.c b/arch/powerpc/platforms/8xx/mpc885ads_setup.c index 2cf1b6a75173..6e7ded0233f6 100644 --- a/arch/powerpc/platforms/8xx/mpc885ads_setup.c +++ b/arch/powerpc/platforms/8xx/mpc885ads_setup.c | |||
@@ -36,11 +36,12 @@ | |||
36 | #include <asm/time.h> | 36 | #include <asm/time.h> |
37 | #include <asm/mpc8xx.h> | 37 | #include <asm/mpc8xx.h> |
38 | #include <asm/8xx_immap.h> | 38 | #include <asm/8xx_immap.h> |
39 | #include <asm/commproc.h> | 39 | #include <asm/cpm1.h> |
40 | #include <asm/fs_pd.h> | 40 | #include <asm/fs_pd.h> |
41 | #include <asm/udbg.h> | 41 | #include <asm/udbg.h> |
42 | 42 | ||
43 | #include <sysdev/commproc.h> | 43 | #include "mpc885ads.h" |
44 | #include "mpc8xx.h" | ||
44 | 45 | ||
45 | static u32 __iomem *bcsr, *bcsr5; | 46 | static u32 __iomem *bcsr, *bcsr5; |
46 | 47 | ||
@@ -264,18 +265,17 @@ static struct of_device_id __initdata of_bus_ids[] = { | |||
264 | static int __init declare_of_platform_devices(void) | 265 | static int __init declare_of_platform_devices(void) |
265 | { | 266 | { |
266 | /* Publish the QE devices */ | 267 | /* Publish the QE devices */ |
267 | if (machine_is(mpc885_ads)) | 268 | of_platform_bus_probe(NULL, of_bus_ids, NULL); |
268 | of_platform_bus_probe(NULL, of_bus_ids, NULL); | ||
269 | 269 | ||
270 | return 0; | 270 | return 0; |
271 | } | 271 | } |
272 | device_initcall(declare_of_platform_devices); | 272 | machine_device_initcall(mpc885_ads, declare_of_platform_devices); |
273 | 273 | ||
274 | define_machine(mpc885_ads) { | 274 | define_machine(mpc885_ads) { |
275 | .name = "Freescale MPC885 ADS", | 275 | .name = "Freescale MPC885 ADS", |
276 | .probe = mpc885ads_probe, | 276 | .probe = mpc885ads_probe, |
277 | .setup_arch = mpc885ads_setup_arch, | 277 | .setup_arch = mpc885ads_setup_arch, |
278 | .init_IRQ = m8xx_pic_init, | 278 | .init_IRQ = mpc8xx_pics_init, |
279 | .get_irq = mpc8xx_get_irq, | 279 | .get_irq = mpc8xx_get_irq, |
280 | .restart = mpc8xx_restart, | 280 | .restart = mpc8xx_restart, |
281 | .calibrate_decr = mpc8xx_calibrate_decr, | 281 | .calibrate_decr = mpc8xx_calibrate_decr, |
diff --git a/arch/powerpc/platforms/8xx/mpc8xx.h b/arch/powerpc/platforms/8xx/mpc8xx.h new file mode 100644 index 000000000000..239a243a6161 --- /dev/null +++ b/arch/powerpc/platforms/8xx/mpc8xx.h | |||
@@ -0,0 +1,21 @@ | |||
1 | /* | ||
2 | * Prototypes, etc. for the Freescale MPC8xx embedded cpu chips | ||
3 | * May need to be cleaned as the port goes on ... | ||
4 | * | ||
5 | * Copyright (C) 2008 Jochen Friedrich <jochen@scram.de> | ||
6 | * | ||
7 | * This file is licensed under the terms of the GNU General Public License | ||
8 | * version 2. This program is licensed "as is" without any warranty of any | ||
9 | * kind, whether express or implied. | ||
10 | */ | ||
11 | #ifndef __MPC8xx_H | ||
12 | #define __MPC8xx_H | ||
13 | |||
14 | extern void mpc8xx_restart(char *cmd); | ||
15 | extern void mpc8xx_calibrate_decr(void); | ||
16 | extern int mpc8xx_set_rtc_time(struct rtc_time *tm); | ||
17 | extern void mpc8xx_get_rtc_time(struct rtc_time *tm); | ||
18 | extern void mpc8xx_pics_init(void); | ||
19 | extern unsigned int mpc8xx_get_irq(void); | ||
20 | |||
21 | #endif /* __MPC8xx_H */ | ||
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig index ea22cad2cd0a..fdce10c4f074 100644 --- a/arch/powerpc/platforms/Kconfig +++ b/arch/powerpc/platforms/Kconfig | |||
@@ -21,7 +21,8 @@ config PPC_83xx | |||
21 | bool "Freescale 83xx" | 21 | bool "Freescale 83xx" |
22 | depends on 6xx | 22 | depends on 6xx |
23 | select FSL_SOC | 23 | select FSL_SOC |
24 | select 83xx | 24 | select MPC83xx |
25 | select IPIC | ||
25 | select WANT_DEVICE_TREE | 26 | select WANT_DEVICE_TREE |
26 | 27 | ||
27 | config PPC_86xx | 28 | config PPC_86xx |
@@ -80,6 +81,10 @@ config XICS | |||
80 | bool | 81 | bool |
81 | default y | 82 | default y |
82 | 83 | ||
84 | config IPIC | ||
85 | bool | ||
86 | default n | ||
87 | |||
83 | config MPIC | 88 | config MPIC |
84 | bool | 89 | bool |
85 | default n | 90 | default n |
@@ -265,6 +270,7 @@ config TAU_AVERAGE | |||
265 | config QUICC_ENGINE | 270 | config QUICC_ENGINE |
266 | bool | 271 | bool |
267 | select PPC_LIB_RHEAP | 272 | select PPC_LIB_RHEAP |
273 | select CRC32 | ||
268 | help | 274 | help |
269 | The QUICC Engine (QE) is a new generation of communications | 275 | The QUICC Engine (QE) is a new generation of communications |
270 | coprocessors on Freescale embedded CPUs (akin to CPM in older chips). | 276 | coprocessors on Freescale embedded CPUs (akin to CPM in older chips). |
@@ -272,8 +278,8 @@ config QUICC_ENGINE | |||
272 | for a machine with a QE coprocessor. | 278 | for a machine with a QE coprocessor. |
273 | 279 | ||
274 | config CPM2 | 280 | config CPM2 |
275 | bool | 281 | bool "Enable support for the CPM2 (Communications Processor Module)" |
276 | default n | 282 | depends on MPC85xx || 8260 |
277 | select CPM | 283 | select CPM |
278 | select PPC_LIB_RHEAP | 284 | select PPC_LIB_RHEAP |
279 | help | 285 | help |
@@ -315,6 +321,12 @@ config FSL_ULI1575 | |||
315 | config CPM | 321 | config CPM |
316 | bool | 322 | bool |
317 | 323 | ||
324 | config OF_RTC | ||
325 | bool | ||
326 | help | ||
327 | Uses information from the OF or flattened device tree to instatiate | ||
328 | platform devices for direct mapped RTC chips like the DS1742 or DS1743. | ||
329 | |||
318 | source "arch/powerpc/sysdev/bestcomm/Kconfig" | 330 | source "arch/powerpc/sysdev/bestcomm/Kconfig" |
319 | 331 | ||
320 | endmenu | 332 | endmenu |
diff --git a/arch/powerpc/platforms/Kconfig.cputype b/arch/powerpc/platforms/Kconfig.cputype index 99684ea606af..7fc41104d53e 100644 --- a/arch/powerpc/platforms/Kconfig.cputype +++ b/arch/powerpc/platforms/Kconfig.cputype | |||
@@ -29,8 +29,8 @@ config PPC_85xx | |||
29 | bool "Freescale 85xx" | 29 | bool "Freescale 85xx" |
30 | select E500 | 30 | select E500 |
31 | select FSL_SOC | 31 | select FSL_SOC |
32 | select 85xx | ||
33 | select WANT_DEVICE_TREE | 32 | select WANT_DEVICE_TREE |
33 | select MPC85xx | ||
34 | 34 | ||
35 | config PPC_8xx | 35 | config PPC_8xx |
36 | bool "Freescale 8xx" | 36 | bool "Freescale 8xx" |
@@ -43,6 +43,7 @@ config 40x | |||
43 | bool "AMCC 40x" | 43 | bool "AMCC 40x" |
44 | select PPC_DCR_NATIVE | 44 | select PPC_DCR_NATIVE |
45 | select WANT_DEVICE_TREE | 45 | select WANT_DEVICE_TREE |
46 | select PPC_UDBG_16550 | ||
46 | 47 | ||
47 | config 44x | 48 | config 44x |
48 | bool "AMCC 44x" | 49 | bool "AMCC 44x" |
@@ -92,14 +93,6 @@ config 6xx | |||
92 | config 8xx | 93 | config 8xx |
93 | bool | 94 | bool |
94 | 95 | ||
95 | # this is temp to handle compat with arch=ppc | ||
96 | config 83xx | ||
97 | bool | ||
98 | |||
99 | # this is temp to handle compat with arch=ppc | ||
100 | config 85xx | ||
101 | bool | ||
102 | |||
103 | config E500 | 96 | config E500 |
104 | bool | 97 | bool |
105 | 98 | ||
diff --git a/arch/powerpc/platforms/cell/Makefile b/arch/powerpc/platforms/cell/Makefile index 39d695cb9693..c89964c6fb1f 100644 --- a/arch/powerpc/platforms/cell/Makefile +++ b/arch/powerpc/platforms/cell/Makefile | |||
@@ -20,7 +20,7 @@ spu-manage-$(CONFIG_PPC_CELL_NATIVE) += spu_manage.o | |||
20 | 20 | ||
21 | obj-$(CONFIG_SPU_BASE) += spu_callbacks.o spu_base.o \ | 21 | obj-$(CONFIG_SPU_BASE) += spu_callbacks.o spu_base.o \ |
22 | spu_notify.o \ | 22 | spu_notify.o \ |
23 | spu_syscalls.o \ | 23 | spu_syscalls.o spu_fault.o \ |
24 | $(spu-priv1-y) \ | 24 | $(spu-priv1-y) \ |
25 | $(spu-manage-y) \ | 25 | $(spu-manage-y) \ |
26 | spufs/ | 26 | spufs/ |
diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq.c b/arch/powerpc/platforms/cell/cbe_cpufreq.c index 13d5a87f13b1..ec7c8f45a215 100644 --- a/arch/powerpc/platforms/cell/cbe_cpufreq.c +++ b/arch/powerpc/platforms/cell/cbe_cpufreq.c | |||
@@ -21,8 +21,9 @@ | |||
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <linux/cpufreq.h> | 23 | #include <linux/cpufreq.h> |
24 | #include <linux/of_platform.h> | ||
25 | |||
24 | #include <asm/machdep.h> | 26 | #include <asm/machdep.h> |
25 | #include <asm/of_platform.h> | ||
26 | #include <asm/prom.h> | 27 | #include <asm/prom.h> |
27 | #include <asm/cell-regs.h> | 28 | #include <asm/cell-regs.h> |
28 | #include "cbe_cpufreq.h" | 29 | #include "cbe_cpufreq.h" |
diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq_pmi.c b/arch/powerpc/platforms/cell/cbe_cpufreq_pmi.c index 6a2c1b0a9a94..69288f653144 100644 --- a/arch/powerpc/platforms/cell/cbe_cpufreq_pmi.c +++ b/arch/powerpc/platforms/cell/cbe_cpufreq_pmi.c | |||
@@ -23,7 +23,8 @@ | |||
23 | #include <linux/kernel.h> | 23 | #include <linux/kernel.h> |
24 | #include <linux/types.h> | 24 | #include <linux/types.h> |
25 | #include <linux/timer.h> | 25 | #include <linux/timer.h> |
26 | #include <asm/of_platform.h> | 26 | #include <linux/of_platform.h> |
27 | |||
27 | #include <asm/processor.h> | 28 | #include <asm/processor.h> |
28 | #include <asm/prom.h> | 29 | #include <asm/prom.h> |
29 | #include <asm/pmi.h> | 30 | #include <asm/pmi.h> |
diff --git a/arch/powerpc/platforms/cell/cbe_regs.c b/arch/powerpc/platforms/cell/cbe_regs.c index 16a9b07e7b0c..dbc338f187a2 100644 --- a/arch/powerpc/platforms/cell/cbe_regs.c +++ b/arch/powerpc/platforms/cell/cbe_regs.c | |||
@@ -9,13 +9,13 @@ | |||
9 | #include <linux/percpu.h> | 9 | #include <linux/percpu.h> |
10 | #include <linux/types.h> | 10 | #include <linux/types.h> |
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
12 | #include <linux/of_device.h> | ||
13 | #include <linux/of_platform.h> | ||
12 | 14 | ||
13 | #include <asm/io.h> | 15 | #include <asm/io.h> |
14 | #include <asm/pgtable.h> | 16 | #include <asm/pgtable.h> |
15 | #include <asm/prom.h> | 17 | #include <asm/prom.h> |
16 | #include <asm/ptrace.h> | 18 | #include <asm/ptrace.h> |
17 | #include <asm/of_device.h> | ||
18 | #include <asm/of_platform.h> | ||
19 | #include <asm/cell-regs.h> | 19 | #include <asm/cell-regs.h> |
20 | 20 | ||
21 | /* | 21 | /* |
@@ -256,6 +256,7 @@ void __init cbe_regs_init(void) | |||
256 | printk(KERN_ERR "cbe_regs: More BE chips than supported" | 256 | printk(KERN_ERR "cbe_regs: More BE chips than supported" |
257 | "!\n"); | 257 | "!\n"); |
258 | cbe_regs_map_count--; | 258 | cbe_regs_map_count--; |
259 | of_node_put(cpu); | ||
259 | return; | 260 | return; |
260 | } | 261 | } |
261 | map->cpu_node = cpu; | 262 | map->cpu_node = cpu; |
diff --git a/arch/powerpc/platforms/cell/io-workarounds.c b/arch/powerpc/platforms/cell/io-workarounds.c index 9d7c2ef940a8..979d4b67efb4 100644 --- a/arch/powerpc/platforms/cell/io-workarounds.c +++ b/arch/powerpc/platforms/cell/io-workarounds.c | |||
@@ -238,7 +238,7 @@ static void __init spider_pci_setup_chip(struct spider_pci_bus *bus) | |||
238 | static void __init spider_pci_add_one(struct pci_controller *phb) | 238 | static void __init spider_pci_add_one(struct pci_controller *phb) |
239 | { | 239 | { |
240 | struct spider_pci_bus *bus = &spider_pci_busses[spider_pci_count]; | 240 | struct spider_pci_bus *bus = &spider_pci_busses[spider_pci_count]; |
241 | struct device_node *np = phb->arch_data; | 241 | struct device_node *np = phb->dn; |
242 | struct resource rsrc; | 242 | struct resource rsrc; |
243 | void __iomem *regs; | 243 | void __iomem *regs; |
244 | 244 | ||
@@ -309,15 +309,12 @@ static int __init spider_pci_workaround_init(void) | |||
309 | { | 309 | { |
310 | struct pci_controller *phb; | 310 | struct pci_controller *phb; |
311 | 311 | ||
312 | if (!machine_is(cell)) | ||
313 | return 0; | ||
314 | |||
315 | /* Find spider bridges. We assume they have been all probed | 312 | /* Find spider bridges. We assume they have been all probed |
316 | * in setup_arch(). If that was to change, we would need to | 313 | * in setup_arch(). If that was to change, we would need to |
317 | * update this code to cope with dynamically added busses | 314 | * update this code to cope with dynamically added busses |
318 | */ | 315 | */ |
319 | list_for_each_entry(phb, &hose_list, list_node) { | 316 | list_for_each_entry(phb, &hose_list, list_node) { |
320 | struct device_node *np = phb->arch_data; | 317 | struct device_node *np = phb->dn; |
321 | const char *model = of_get_property(np, "model", NULL); | 318 | const char *model = of_get_property(np, "model", NULL); |
322 | 319 | ||
323 | /* If no model property or name isn't exactly "pci", skip */ | 320 | /* If no model property or name isn't exactly "pci", skip */ |
@@ -343,4 +340,4 @@ static int __init spider_pci_workaround_init(void) | |||
343 | 340 | ||
344 | return 0; | 341 | return 0; |
345 | } | 342 | } |
346 | arch_initcall(spider_pci_workaround_init); | 343 | machine_arch_initcall(cell, spider_pci_workaround_init); |
diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c index faabc3fdc130..df330666ccc9 100644 --- a/arch/powerpc/platforms/cell/iommu.c +++ b/arch/powerpc/platforms/cell/iommu.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * IOMMU implementation for Cell Broadband Processor Architecture | 2 | * IOMMU implementation for Cell Broadband Processor Architecture |
3 | * | 3 | * |
4 | * (C) Copyright IBM Corporation 2006 | 4 | * (C) Copyright IBM Corporation 2006-2008 |
5 | * | 5 | * |
6 | * Author: Jeremy Kerr <jk@ozlabs.org> | 6 | * Author: Jeremy Kerr <jk@ozlabs.org> |
7 | * | 7 | * |
@@ -26,14 +26,15 @@ | |||
26 | #include <linux/init.h> | 26 | #include <linux/init.h> |
27 | #include <linux/interrupt.h> | 27 | #include <linux/interrupt.h> |
28 | #include <linux/notifier.h> | 28 | #include <linux/notifier.h> |
29 | #include <linux/of_platform.h> | ||
29 | 30 | ||
30 | #include <asm/prom.h> | 31 | #include <asm/prom.h> |
31 | #include <asm/iommu.h> | 32 | #include <asm/iommu.h> |
32 | #include <asm/machdep.h> | 33 | #include <asm/machdep.h> |
33 | #include <asm/pci-bridge.h> | 34 | #include <asm/pci-bridge.h> |
34 | #include <asm/udbg.h> | 35 | #include <asm/udbg.h> |
35 | #include <asm/of_platform.h> | ||
36 | #include <asm/lmb.h> | 36 | #include <asm/lmb.h> |
37 | #include <asm/firmware.h> | ||
37 | #include <asm/cell-regs.h> | 38 | #include <asm/cell-regs.h> |
38 | 39 | ||
39 | #include "interrupt.h" | 40 | #include "interrupt.h" |
@@ -305,29 +306,28 @@ static int cell_iommu_find_ioc(int nid, unsigned long *base) | |||
305 | return -ENODEV; | 306 | return -ENODEV; |
306 | } | 307 | } |
307 | 308 | ||
308 | static void cell_iommu_setup_hardware(struct cbe_iommu *iommu, unsigned long size) | 309 | static void cell_iommu_setup_page_tables(struct cbe_iommu *iommu, |
310 | unsigned long dbase, unsigned long dsize, | ||
311 | unsigned long fbase, unsigned long fsize) | ||
309 | { | 312 | { |
310 | struct page *page; | 313 | struct page *page; |
311 | int ret, i; | 314 | int i; |
312 | unsigned long reg, segments, pages_per_segment, ptab_size, n_pte_pages; | 315 | unsigned long reg, segments, pages_per_segment, ptab_size, stab_size, |
313 | unsigned long xlate_base; | 316 | n_pte_pages, base; |
314 | unsigned int virq; | ||
315 | |||
316 | if (cell_iommu_find_ioc(iommu->nid, &xlate_base)) | ||
317 | panic("%s: missing IOC register mappings for node %d\n", | ||
318 | __FUNCTION__, iommu->nid); | ||
319 | 317 | ||
320 | iommu->xlate_regs = ioremap(xlate_base, IOC_Reg_Size); | 318 | base = dbase; |
321 | iommu->cmd_regs = iommu->xlate_regs + IOC_IOCmd_Offset; | 319 | if (fsize != 0) |
320 | base = min(fbase, dbase); | ||
322 | 321 | ||
323 | segments = size >> IO_SEGMENT_SHIFT; | 322 | segments = max(dbase + dsize, fbase + fsize) >> IO_SEGMENT_SHIFT; |
324 | pages_per_segment = 1ull << IO_PAGENO_BITS; | 323 | pages_per_segment = 1ull << IO_PAGENO_BITS; |
325 | 324 | ||
326 | pr_debug("%s: iommu[%d]: segments: %lu, pages per segment: %lu\n", | 325 | pr_debug("%s: iommu[%d]: segments: %lu, pages per segment: %lu\n", |
327 | __FUNCTION__, iommu->nid, segments, pages_per_segment); | 326 | __FUNCTION__, iommu->nid, segments, pages_per_segment); |
328 | 327 | ||
329 | /* set up the segment table */ | 328 | /* set up the segment table */ |
330 | page = alloc_pages_node(iommu->nid, GFP_KERNEL, 0); | 329 | stab_size = segments * sizeof(unsigned long); |
330 | page = alloc_pages_node(iommu->nid, GFP_KERNEL, get_order(stab_size)); | ||
331 | BUG_ON(!page); | 331 | BUG_ON(!page); |
332 | iommu->stab = page_address(page); | 332 | iommu->stab = page_address(page); |
333 | clear_page(iommu->stab); | 333 | clear_page(iommu->stab); |
@@ -371,11 +371,25 @@ static void cell_iommu_setup_hardware(struct cbe_iommu *iommu, unsigned long siz | |||
371 | } | 371 | } |
372 | 372 | ||
373 | pr_debug("Setting up IOMMU stab:\n"); | 373 | pr_debug("Setting up IOMMU stab:\n"); |
374 | for (i = 0; i * (1ul << IO_SEGMENT_SHIFT) < size; i++) { | 374 | for (i = base >> IO_SEGMENT_SHIFT; i < segments; i++) { |
375 | iommu->stab[i] = reg | | 375 | iommu->stab[i] = reg | |
376 | (__pa(iommu->ptab) + n_pte_pages * IOMMU_PAGE_SIZE * i); | 376 | (__pa(iommu->ptab) + n_pte_pages * IOMMU_PAGE_SIZE * i); |
377 | pr_debug("\t[%d] 0x%016lx\n", i, iommu->stab[i]); | 377 | pr_debug("\t[%d] 0x%016lx\n", i, iommu->stab[i]); |
378 | } | 378 | } |
379 | } | ||
380 | |||
381 | static void cell_iommu_enable_hardware(struct cbe_iommu *iommu) | ||
382 | { | ||
383 | int ret; | ||
384 | unsigned long reg, xlate_base; | ||
385 | unsigned int virq; | ||
386 | |||
387 | if (cell_iommu_find_ioc(iommu->nid, &xlate_base)) | ||
388 | panic("%s: missing IOC register mappings for node %d\n", | ||
389 | __FUNCTION__, iommu->nid); | ||
390 | |||
391 | iommu->xlate_regs = ioremap(xlate_base, IOC_Reg_Size); | ||
392 | iommu->cmd_regs = iommu->xlate_regs + IOC_IOCmd_Offset; | ||
379 | 393 | ||
380 | /* ensure that the STEs have updated */ | 394 | /* ensure that the STEs have updated */ |
381 | mb(); | 395 | mb(); |
@@ -405,6 +419,13 @@ static void cell_iommu_setup_hardware(struct cbe_iommu *iommu, unsigned long siz | |||
405 | out_be64(iommu->cmd_regs + IOC_IOCmd_Cfg, reg); | 419 | out_be64(iommu->cmd_regs + IOC_IOCmd_Cfg, reg); |
406 | } | 420 | } |
407 | 421 | ||
422 | static void cell_iommu_setup_hardware(struct cbe_iommu *iommu, | ||
423 | unsigned long base, unsigned long size) | ||
424 | { | ||
425 | cell_iommu_setup_page_tables(iommu, base, size, 0, 0); | ||
426 | cell_iommu_enable_hardware(iommu); | ||
427 | } | ||
428 | |||
408 | #if 0/* Unused for now */ | 429 | #if 0/* Unused for now */ |
409 | static struct iommu_window *find_window(struct cbe_iommu *iommu, | 430 | static struct iommu_window *find_window(struct cbe_iommu *iommu, |
410 | unsigned long offset, unsigned long size) | 431 | unsigned long offset, unsigned long size) |
@@ -422,25 +443,36 @@ static struct iommu_window *find_window(struct cbe_iommu *iommu, | |||
422 | } | 443 | } |
423 | #endif | 444 | #endif |
424 | 445 | ||
446 | static inline u32 cell_iommu_get_ioid(struct device_node *np) | ||
447 | { | ||
448 | const u32 *ioid; | ||
449 | |||
450 | ioid = of_get_property(np, "ioid", NULL); | ||
451 | if (ioid == NULL) { | ||
452 | printk(KERN_WARNING "iommu: missing ioid for %s using 0\n", | ||
453 | np->full_name); | ||
454 | return 0; | ||
455 | } | ||
456 | |||
457 | return *ioid; | ||
458 | } | ||
459 | |||
425 | static struct iommu_window * __init | 460 | static struct iommu_window * __init |
426 | cell_iommu_setup_window(struct cbe_iommu *iommu, struct device_node *np, | 461 | cell_iommu_setup_window(struct cbe_iommu *iommu, struct device_node *np, |
427 | unsigned long offset, unsigned long size, | 462 | unsigned long offset, unsigned long size, |
428 | unsigned long pte_offset) | 463 | unsigned long pte_offset) |
429 | { | 464 | { |
430 | struct iommu_window *window; | 465 | struct iommu_window *window; |
431 | const unsigned int *ioid; | 466 | u32 ioid; |
432 | 467 | ||
433 | ioid = of_get_property(np, "ioid", NULL); | 468 | ioid = cell_iommu_get_ioid(np); |
434 | if (ioid == NULL) | ||
435 | printk(KERN_WARNING "iommu: missing ioid for %s using 0\n", | ||
436 | np->full_name); | ||
437 | 469 | ||
438 | window = kmalloc_node(sizeof(*window), GFP_KERNEL, iommu->nid); | 470 | window = kmalloc_node(sizeof(*window), GFP_KERNEL, iommu->nid); |
439 | BUG_ON(window == NULL); | 471 | BUG_ON(window == NULL); |
440 | 472 | ||
441 | window->offset = offset; | 473 | window->offset = offset; |
442 | window->size = size; | 474 | window->size = size; |
443 | window->ioid = ioid ? *ioid : 0; | 475 | window->ioid = ioid; |
444 | window->iommu = iommu; | 476 | window->iommu = iommu; |
445 | window->pte_offset = pte_offset; | 477 | window->pte_offset = pte_offset; |
446 | 478 | ||
@@ -489,16 +521,17 @@ static struct cbe_iommu *cell_iommu_for_node(int nid) | |||
489 | return NULL; | 521 | return NULL; |
490 | } | 522 | } |
491 | 523 | ||
492 | static void cell_dma_dev_setup(struct device *dev) | 524 | static unsigned long cell_dma_direct_offset; |
525 | |||
526 | static unsigned long dma_iommu_fixed_base; | ||
527 | struct dma_mapping_ops dma_iommu_fixed_ops; | ||
528 | |||
529 | static void cell_dma_dev_setup_iommu(struct device *dev) | ||
493 | { | 530 | { |
494 | struct iommu_window *window; | 531 | struct iommu_window *window; |
495 | struct cbe_iommu *iommu; | 532 | struct cbe_iommu *iommu; |
496 | struct dev_archdata *archdata = &dev->archdata; | 533 | struct dev_archdata *archdata = &dev->archdata; |
497 | 534 | ||
498 | /* If we run without iommu, no need to do anything */ | ||
499 | if (get_pci_dma_ops() == &dma_direct_ops) | ||
500 | return; | ||
501 | |||
502 | /* Current implementation uses the first window available in that | 535 | /* Current implementation uses the first window available in that |
503 | * node's iommu. We -might- do something smarter later though it may | 536 | * node's iommu. We -might- do something smarter later though it may |
504 | * never be necessary | 537 | * never be necessary |
@@ -515,6 +548,23 @@ static void cell_dma_dev_setup(struct device *dev) | |||
515 | archdata->dma_data = &window->table; | 548 | archdata->dma_data = &window->table; |
516 | } | 549 | } |
517 | 550 | ||
551 | static void cell_dma_dev_setup_static(struct device *dev); | ||
552 | |||
553 | static void cell_dma_dev_setup(struct device *dev) | ||
554 | { | ||
555 | struct dev_archdata *archdata = &dev->archdata; | ||
556 | |||
557 | /* Order is important here, these are not mutually exclusive */ | ||
558 | if (get_dma_ops(dev) == &dma_iommu_fixed_ops) | ||
559 | cell_dma_dev_setup_static(dev); | ||
560 | else if (get_pci_dma_ops() == &dma_iommu_ops) | ||
561 | cell_dma_dev_setup_iommu(dev); | ||
562 | else if (get_pci_dma_ops() == &dma_direct_ops) | ||
563 | archdata->dma_data = (void *)cell_dma_direct_offset; | ||
564 | else | ||
565 | BUG(); | ||
566 | } | ||
567 | |||
518 | static void cell_pci_dma_dev_setup(struct pci_dev *dev) | 568 | static void cell_pci_dma_dev_setup(struct pci_dev *dev) |
519 | { | 569 | { |
520 | cell_dma_dev_setup(&dev->dev); | 570 | cell_dma_dev_setup(&dev->dev); |
@@ -560,10 +610,9 @@ static int __init cell_iommu_get_window(struct device_node *np, | |||
560 | return 0; | 610 | return 0; |
561 | } | 611 | } |
562 | 612 | ||
563 | static void __init cell_iommu_init_one(struct device_node *np, unsigned long offset) | 613 | static struct cbe_iommu * __init cell_iommu_alloc(struct device_node *np) |
564 | { | 614 | { |
565 | struct cbe_iommu *iommu; | 615 | struct cbe_iommu *iommu; |
566 | unsigned long base, size; | ||
567 | int nid, i; | 616 | int nid, i; |
568 | 617 | ||
569 | /* Get node ID */ | 618 | /* Get node ID */ |
@@ -571,7 +620,7 @@ static void __init cell_iommu_init_one(struct device_node *np, unsigned long off | |||
571 | if (nid < 0) { | 620 | if (nid < 0) { |
572 | printk(KERN_ERR "iommu: failed to get node for %s\n", | 621 | printk(KERN_ERR "iommu: failed to get node for %s\n", |
573 | np->full_name); | 622 | np->full_name); |
574 | return; | 623 | return NULL; |
575 | } | 624 | } |
576 | pr_debug("iommu: setting up iommu for node %d (%s)\n", | 625 | pr_debug("iommu: setting up iommu for node %d (%s)\n", |
577 | nid, np->full_name); | 626 | nid, np->full_name); |
@@ -587,7 +636,7 @@ static void __init cell_iommu_init_one(struct device_node *np, unsigned long off | |||
587 | if (cbe_nr_iommus >= NR_IOMMUS) { | 636 | if (cbe_nr_iommus >= NR_IOMMUS) { |
588 | printk(KERN_ERR "iommu: too many IOMMUs detected ! (%s)\n", | 637 | printk(KERN_ERR "iommu: too many IOMMUs detected ! (%s)\n", |
589 | np->full_name); | 638 | np->full_name); |
590 | return; | 639 | return NULL; |
591 | } | 640 | } |
592 | 641 | ||
593 | /* Init base fields */ | 642 | /* Init base fields */ |
@@ -598,6 +647,19 @@ static void __init cell_iommu_init_one(struct device_node *np, unsigned long off | |||
598 | snprintf(iommu->name, sizeof(iommu->name), "iommu%d", i); | 647 | snprintf(iommu->name, sizeof(iommu->name), "iommu%d", i); |
599 | INIT_LIST_HEAD(&iommu->windows); | 648 | INIT_LIST_HEAD(&iommu->windows); |
600 | 649 | ||
650 | return iommu; | ||
651 | } | ||
652 | |||
653 | static void __init cell_iommu_init_one(struct device_node *np, | ||
654 | unsigned long offset) | ||
655 | { | ||
656 | struct cbe_iommu *iommu; | ||
657 | unsigned long base, size; | ||
658 | |||
659 | iommu = cell_iommu_alloc(np); | ||
660 | if (!iommu) | ||
661 | return; | ||
662 | |||
601 | /* Obtain a window for it */ | 663 | /* Obtain a window for it */ |
602 | cell_iommu_get_window(np, &base, &size); | 664 | cell_iommu_get_window(np, &base, &size); |
603 | 665 | ||
@@ -605,7 +667,7 @@ static void __init cell_iommu_init_one(struct device_node *np, unsigned long off | |||
605 | base, base + size - 1); | 667 | base, base + size - 1); |
606 | 668 | ||
607 | /* Initialize the hardware */ | 669 | /* Initialize the hardware */ |
608 | cell_iommu_setup_hardware(iommu, size); | 670 | cell_iommu_setup_hardware(iommu, base, size); |
609 | 671 | ||
610 | /* Setup the iommu_table */ | 672 | /* Setup the iommu_table */ |
611 | cell_iommu_setup_window(iommu, np, base, size, | 673 | cell_iommu_setup_window(iommu, np, base, size, |
@@ -653,7 +715,7 @@ static int __init cell_iommu_init_disabled(void) | |||
653 | 715 | ||
654 | /* If we have no Axon, we set up the spider DMA magic offset */ | 716 | /* If we have no Axon, we set up the spider DMA magic offset */ |
655 | if (of_find_node_by_name(NULL, "axon") == NULL) | 717 | if (of_find_node_by_name(NULL, "axon") == NULL) |
656 | dma_direct_offset = SPIDER_DMA_OFFSET; | 718 | cell_dma_direct_offset = SPIDER_DMA_OFFSET; |
657 | 719 | ||
658 | /* Now we need to check to see where the memory is mapped | 720 | /* Now we need to check to see where the memory is mapped |
659 | * in PCI space. We assume that all busses use the same dma | 721 | * in PCI space. We assume that all busses use the same dma |
@@ -687,20 +749,274 @@ static int __init cell_iommu_init_disabled(void) | |||
687 | return -ENODEV; | 749 | return -ENODEV; |
688 | } | 750 | } |
689 | 751 | ||
690 | dma_direct_offset += base; | 752 | cell_dma_direct_offset += base; |
753 | |||
754 | if (cell_dma_direct_offset != 0) | ||
755 | ppc_md.pci_dma_dev_setup = cell_pci_dma_dev_setup; | ||
691 | 756 | ||
692 | printk("iommu: disabled, direct DMA offset is 0x%lx\n", | 757 | printk("iommu: disabled, direct DMA offset is 0x%lx\n", |
693 | dma_direct_offset); | 758 | cell_dma_direct_offset); |
694 | 759 | ||
695 | return 0; | 760 | return 0; |
696 | } | 761 | } |
697 | 762 | ||
698 | static int __init cell_iommu_init(void) | 763 | /* |
764 | * Fixed IOMMU mapping support | ||
765 | * | ||
766 | * This code adds support for setting up a fixed IOMMU mapping on certain | ||
767 | * cell machines. For 64-bit devices this avoids the performance overhead of | ||
768 | * mapping and unmapping pages at runtime. 32-bit devices are unable to use | ||
769 | * the fixed mapping. | ||
770 | * | ||
771 | * The fixed mapping is established at boot, and maps all of physical memory | ||
772 | * 1:1 into device space at some offset. On machines with < 30 GB of memory | ||
773 | * we setup the fixed mapping immediately above the normal IOMMU window. | ||
774 | * | ||
775 | * For example a machine with 4GB of memory would end up with the normal | ||
776 | * IOMMU window from 0-2GB and the fixed mapping window from 2GB to 6GB. In | ||
777 | * this case a 64-bit device wishing to DMA to 1GB would be told to DMA to | ||
778 | * 3GB, plus any offset required by firmware. The firmware offset is encoded | ||
779 | * in the "dma-ranges" property. | ||
780 | * | ||
781 | * On machines with 30GB or more of memory, we are unable to place the fixed | ||
782 | * mapping above the normal IOMMU window as we would run out of address space. | ||
783 | * Instead we move the normal IOMMU window to coincide with the hash page | ||
784 | * table, this region does not need to be part of the fixed mapping as no | ||
785 | * device should ever be DMA'ing to it. We then setup the fixed mapping | ||
786 | * from 0 to 32GB. | ||
787 | */ | ||
788 | |||
789 | static u64 cell_iommu_get_fixed_address(struct device *dev) | ||
699 | { | 790 | { |
791 | u64 cpu_addr, size, best_size, pci_addr = OF_BAD_ADDR; | ||
792 | struct device_node *tmp, *np; | ||
793 | const u32 *ranges = NULL; | ||
794 | int i, len, best; | ||
795 | |||
796 | np = dev->archdata.of_node; | ||
797 | of_node_get(np); | ||
798 | ranges = of_get_property(np, "dma-ranges", &len); | ||
799 | while (!ranges && np) { | ||
800 | tmp = of_get_parent(np); | ||
801 | of_node_put(np); | ||
802 | np = tmp; | ||
803 | ranges = of_get_property(np, "dma-ranges", &len); | ||
804 | } | ||
805 | |||
806 | if (!ranges) { | ||
807 | dev_dbg(dev, "iommu: no dma-ranges found\n"); | ||
808 | goto out; | ||
809 | } | ||
810 | |||
811 | len /= sizeof(u32); | ||
812 | |||
813 | /* dma-ranges format: | ||
814 | * 1 cell: pci space | ||
815 | * 2 cells: pci address | ||
816 | * 2 cells: parent address | ||
817 | * 2 cells: size | ||
818 | */ | ||
819 | for (i = 0, best = -1, best_size = 0; i < len; i += 7) { | ||
820 | cpu_addr = of_translate_dma_address(np, ranges +i + 3); | ||
821 | size = of_read_number(ranges + i + 5, 2); | ||
822 | |||
823 | if (cpu_addr == 0 && size > best_size) { | ||
824 | best = i; | ||
825 | best_size = size; | ||
826 | } | ||
827 | } | ||
828 | |||
829 | if (best >= 0) | ||
830 | pci_addr = of_read_number(ranges + best + 1, 2); | ||
831 | else | ||
832 | dev_dbg(dev, "iommu: no suitable range found!\n"); | ||
833 | |||
834 | out: | ||
835 | of_node_put(np); | ||
836 | |||
837 | return pci_addr; | ||
838 | } | ||
839 | |||
840 | static int dma_set_mask_and_switch(struct device *dev, u64 dma_mask) | ||
841 | { | ||
842 | if (!dev->dma_mask || !dma_supported(dev, dma_mask)) | ||
843 | return -EIO; | ||
844 | |||
845 | if (dma_mask == DMA_BIT_MASK(64)) { | ||
846 | if (cell_iommu_get_fixed_address(dev) == OF_BAD_ADDR) | ||
847 | dev_dbg(dev, "iommu: 64-bit OK, but bad addr\n"); | ||
848 | else { | ||
849 | dev_dbg(dev, "iommu: 64-bit OK, using fixed ops\n"); | ||
850 | set_dma_ops(dev, &dma_iommu_fixed_ops); | ||
851 | cell_dma_dev_setup(dev); | ||
852 | } | ||
853 | } else { | ||
854 | dev_dbg(dev, "iommu: not 64-bit, using default ops\n"); | ||
855 | set_dma_ops(dev, get_pci_dma_ops()); | ||
856 | } | ||
857 | |||
858 | *dev->dma_mask = dma_mask; | ||
859 | |||
860 | return 0; | ||
861 | } | ||
862 | |||
863 | static void cell_dma_dev_setup_static(struct device *dev) | ||
864 | { | ||
865 | struct dev_archdata *archdata = &dev->archdata; | ||
866 | u64 addr; | ||
867 | |||
868 | addr = cell_iommu_get_fixed_address(dev) + dma_iommu_fixed_base; | ||
869 | archdata->dma_data = (void *)addr; | ||
870 | |||
871 | dev_dbg(dev, "iommu: fixed addr = %lx\n", addr); | ||
872 | } | ||
873 | |||
874 | static void cell_iommu_setup_fixed_ptab(struct cbe_iommu *iommu, | ||
875 | struct device_node *np, unsigned long dbase, unsigned long dsize, | ||
876 | unsigned long fbase, unsigned long fsize) | ||
877 | { | ||
878 | unsigned long base_pte, uaddr, *io_pte; | ||
879 | int i; | ||
880 | |||
881 | dma_iommu_fixed_base = fbase; | ||
882 | |||
883 | /* convert from bytes into page table indices */ | ||
884 | dbase = dbase >> IOMMU_PAGE_SHIFT; | ||
885 | dsize = dsize >> IOMMU_PAGE_SHIFT; | ||
886 | fbase = fbase >> IOMMU_PAGE_SHIFT; | ||
887 | fsize = fsize >> IOMMU_PAGE_SHIFT; | ||
888 | |||
889 | pr_debug("iommu: mapping 0x%lx pages from 0x%lx\n", fsize, fbase); | ||
890 | |||
891 | io_pte = iommu->ptab; | ||
892 | base_pte = IOPTE_PP_W | IOPTE_PP_R | IOPTE_M | IOPTE_SO_RW | ||
893 | | (cell_iommu_get_ioid(np) & IOPTE_IOID_Mask); | ||
894 | |||
895 | uaddr = 0; | ||
896 | for (i = fbase; i < fbase + fsize; i++, uaddr += IOMMU_PAGE_SIZE) { | ||
897 | /* Don't touch the dynamic region */ | ||
898 | if (i >= dbase && i < (dbase + dsize)) { | ||
899 | pr_debug("iommu: static/dynamic overlap, skipping\n"); | ||
900 | continue; | ||
901 | } | ||
902 | io_pte[i] = base_pte | (__pa(uaddr) & IOPTE_RPN_Mask); | ||
903 | } | ||
904 | |||
905 | mb(); | ||
906 | } | ||
907 | |||
908 | static int __init cell_iommu_fixed_mapping_init(void) | ||
909 | { | ||
910 | unsigned long dbase, dsize, fbase, fsize, hbase, hend; | ||
911 | struct cbe_iommu *iommu; | ||
700 | struct device_node *np; | 912 | struct device_node *np; |
701 | 913 | ||
702 | if (!machine_is(cell)) | 914 | /* The fixed mapping is only supported on axon machines */ |
703 | return -ENODEV; | 915 | np = of_find_node_by_name(NULL, "axon"); |
916 | if (!np) { | ||
917 | pr_debug("iommu: fixed mapping disabled, no axons found\n"); | ||
918 | return -1; | ||
919 | } | ||
920 | |||
921 | /* The default setup is to have the fixed mapping sit after the | ||
922 | * dynamic region, so find the top of the largest IOMMU window | ||
923 | * on any axon, then add the size of RAM and that's our max value. | ||
924 | * If that is > 32GB we have to do other shennanigans. | ||
925 | */ | ||
926 | fbase = 0; | ||
927 | for_each_node_by_name(np, "axon") { | ||
928 | cell_iommu_get_window(np, &dbase, &dsize); | ||
929 | fbase = max(fbase, dbase + dsize); | ||
930 | } | ||
931 | |||
932 | fbase = _ALIGN_UP(fbase, 1 << IO_SEGMENT_SHIFT); | ||
933 | fsize = lmb_phys_mem_size(); | ||
934 | |||
935 | if ((fbase + fsize) <= 0x800000000) | ||
936 | hbase = 0; /* use the device tree window */ | ||
937 | else { | ||
938 | /* If we're over 32 GB we need to cheat. We can't map all of | ||
939 | * RAM with the fixed mapping, and also fit the dynamic | ||
940 | * region. So try to place the dynamic region where the hash | ||
941 | * table sits, drivers never need to DMA to it, we don't | ||
942 | * need a fixed mapping for that area. | ||
943 | */ | ||
944 | if (!htab_address) { | ||
945 | pr_debug("iommu: htab is NULL, on LPAR? Huh?\n"); | ||
946 | return -1; | ||
947 | } | ||
948 | hbase = __pa(htab_address); | ||
949 | hend = hbase + htab_size_bytes; | ||
950 | |||
951 | /* The window must start and end on a segment boundary */ | ||
952 | if ((hbase != _ALIGN_UP(hbase, 1 << IO_SEGMENT_SHIFT)) || | ||
953 | (hend != _ALIGN_UP(hend, 1 << IO_SEGMENT_SHIFT))) { | ||
954 | pr_debug("iommu: hash window not segment aligned\n"); | ||
955 | return -1; | ||
956 | } | ||
957 | |||
958 | /* Check the hash window fits inside the real DMA window */ | ||
959 | for_each_node_by_name(np, "axon") { | ||
960 | cell_iommu_get_window(np, &dbase, &dsize); | ||
961 | |||
962 | if (hbase < dbase || (hend > (dbase + dsize))) { | ||
963 | pr_debug("iommu: hash window doesn't fit in" | ||
964 | "real DMA window\n"); | ||
965 | return -1; | ||
966 | } | ||
967 | } | ||
968 | |||
969 | fbase = 0; | ||
970 | } | ||
971 | |||
972 | /* Setup the dynamic regions */ | ||
973 | for_each_node_by_name(np, "axon") { | ||
974 | iommu = cell_iommu_alloc(np); | ||
975 | BUG_ON(!iommu); | ||
976 | |||
977 | if (hbase == 0) | ||
978 | cell_iommu_get_window(np, &dbase, &dsize); | ||
979 | else { | ||
980 | dbase = hbase; | ||
981 | dsize = htab_size_bytes; | ||
982 | } | ||
983 | |||
984 | pr_debug("iommu: setting up %d, dynamic window %lx-%lx " \ | ||
985 | "fixed window %lx-%lx\n", iommu->nid, dbase, | ||
986 | dbase + dsize, fbase, fbase + fsize); | ||
987 | |||
988 | cell_iommu_setup_page_tables(iommu, dbase, dsize, fbase, fsize); | ||
989 | cell_iommu_setup_fixed_ptab(iommu, np, dbase, dsize, | ||
990 | fbase, fsize); | ||
991 | cell_iommu_enable_hardware(iommu); | ||
992 | cell_iommu_setup_window(iommu, np, dbase, dsize, 0); | ||
993 | } | ||
994 | |||
995 | dma_iommu_fixed_ops = dma_direct_ops; | ||
996 | dma_iommu_fixed_ops.set_dma_mask = dma_set_mask_and_switch; | ||
997 | |||
998 | dma_iommu_ops.set_dma_mask = dma_set_mask_and_switch; | ||
999 | set_pci_dma_ops(&dma_iommu_ops); | ||
1000 | |||
1001 | printk(KERN_DEBUG "IOMMU fixed mapping established.\n"); | ||
1002 | |||
1003 | return 0; | ||
1004 | } | ||
1005 | |||
1006 | static int iommu_fixed_disabled; | ||
1007 | |||
1008 | static int __init setup_iommu_fixed(char *str) | ||
1009 | { | ||
1010 | if (strcmp(str, "off") == 0) | ||
1011 | iommu_fixed_disabled = 1; | ||
1012 | |||
1013 | return 1; | ||
1014 | } | ||
1015 | __setup("iommu_fixed=", setup_iommu_fixed); | ||
1016 | |||
1017 | static int __init cell_iommu_init(void) | ||
1018 | { | ||
1019 | struct device_node *np; | ||
704 | 1020 | ||
705 | /* If IOMMU is disabled or we have little enough RAM to not need | 1021 | /* If IOMMU is disabled or we have little enough RAM to not need |
706 | * to enable it, we setup a direct mapping. | 1022 | * to enable it, we setup a direct mapping. |
@@ -717,6 +1033,9 @@ static int __init cell_iommu_init(void) | |||
717 | ppc_md.tce_build = tce_build_cell; | 1033 | ppc_md.tce_build = tce_build_cell; |
718 | ppc_md.tce_free = tce_free_cell; | 1034 | ppc_md.tce_free = tce_free_cell; |
719 | 1035 | ||
1036 | if (!iommu_fixed_disabled && cell_iommu_fixed_mapping_init() == 0) | ||
1037 | goto bail; | ||
1038 | |||
720 | /* Create an iommu for each /axon node. */ | 1039 | /* Create an iommu for each /axon node. */ |
721 | for_each_node_by_name(np, "axon") { | 1040 | for_each_node_by_name(np, "axon") { |
722 | if (np->parent == NULL || np->parent->parent != NULL) | 1041 | if (np->parent == NULL || np->parent->parent != NULL) |
@@ -744,5 +1063,6 @@ static int __init cell_iommu_init(void) | |||
744 | 1063 | ||
745 | return 0; | 1064 | return 0; |
746 | } | 1065 | } |
747 | arch_initcall(cell_iommu_init); | 1066 | machine_arch_initcall(cell, cell_iommu_init); |
1067 | machine_arch_initcall(celleb_native, cell_iommu_init); | ||
748 | 1068 | ||
diff --git a/arch/powerpc/platforms/cell/pmu.c b/arch/powerpc/platforms/cell/pmu.c index 1ed303678887..69ed0d7f1646 100644 --- a/arch/powerpc/platforms/cell/pmu.c +++ b/arch/powerpc/platforms/cell/pmu.c | |||
@@ -213,7 +213,7 @@ u32 cbe_read_pm(u32 cpu, enum pm_reg_name reg) | |||
213 | break; | 213 | break; |
214 | 214 | ||
215 | case pm_interval: | 215 | case pm_interval: |
216 | READ_SHADOW_REG(val, pm_interval); | 216 | READ_MMIO_UPPER32(val, pm_interval); |
217 | break; | 217 | break; |
218 | 218 | ||
219 | case pm_start_stop: | 219 | case pm_start_stop: |
@@ -381,9 +381,6 @@ static int __init cbe_init_pm_irq(void) | |||
381 | unsigned int irq; | 381 | unsigned int irq; |
382 | int rc, node; | 382 | int rc, node; |
383 | 383 | ||
384 | if (!machine_is(cell)) | ||
385 | return 0; | ||
386 | |||
387 | for_each_node(node) { | 384 | for_each_node(node) { |
388 | irq = irq_create_mapping(NULL, IIC_IRQ_IOEX_PMI | | 385 | irq = irq_create_mapping(NULL, IIC_IRQ_IOEX_PMI | |
389 | (node << IIC_IRQ_NODE_SHIFT)); | 386 | (node << IIC_IRQ_NODE_SHIFT)); |
@@ -404,7 +401,7 @@ static int __init cbe_init_pm_irq(void) | |||
404 | 401 | ||
405 | return 0; | 402 | return 0; |
406 | } | 403 | } |
407 | arch_initcall(cbe_init_pm_irq); | 404 | machine_arch_initcall(cell, cbe_init_pm_irq); |
408 | 405 | ||
409 | void cbe_sync_irq(int node) | 406 | void cbe_sync_irq(int node) |
410 | { | 407 | { |
diff --git a/arch/powerpc/platforms/cell/setup.c b/arch/powerpc/platforms/cell/setup.c index 98e7ef8e6fc6..e6534b519c9a 100644 --- a/arch/powerpc/platforms/cell/setup.c +++ b/arch/powerpc/platforms/cell/setup.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/console.h> | 30 | #include <linux/console.h> |
31 | #include <linux/mutex.h> | 31 | #include <linux/mutex.h> |
32 | #include <linux/memory_hotplug.h> | 32 | #include <linux/memory_hotplug.h> |
33 | #include <linux/of_platform.h> | ||
33 | 34 | ||
34 | #include <asm/mmu.h> | 35 | #include <asm/mmu.h> |
35 | #include <asm/processor.h> | 36 | #include <asm/processor.h> |
@@ -51,7 +52,6 @@ | |||
51 | #include <asm/spu_priv1.h> | 52 | #include <asm/spu_priv1.h> |
52 | #include <asm/udbg.h> | 53 | #include <asm/udbg.h> |
53 | #include <asm/mpic.h> | 54 | #include <asm/mpic.h> |
54 | #include <asm/of_platform.h> | ||
55 | #include <asm/cell-regs.h> | 55 | #include <asm/cell-regs.h> |
56 | 56 | ||
57 | #include "interrupt.h" | 57 | #include "interrupt.h" |
@@ -85,9 +85,6 @@ static int __init cell_publish_devices(void) | |||
85 | { | 85 | { |
86 | int node; | 86 | int node; |
87 | 87 | ||
88 | if (!machine_is(cell)) | ||
89 | return 0; | ||
90 | |||
91 | /* Publish OF platform devices for southbridge IOs */ | 88 | /* Publish OF platform devices for southbridge IOs */ |
92 | of_platform_bus_probe(NULL, NULL, NULL); | 89 | of_platform_bus_probe(NULL, NULL, NULL); |
93 | 90 | ||
@@ -101,7 +98,7 @@ static int __init cell_publish_devices(void) | |||
101 | } | 98 | } |
102 | return 0; | 99 | return 0; |
103 | } | 100 | } |
104 | device_initcall(cell_publish_devices); | 101 | machine_device_initcall(cell, cell_publish_devices); |
105 | 102 | ||
106 | static void cell_mpic_cascade(unsigned int irq, struct irq_desc *desc) | 103 | static void cell_mpic_cascade(unsigned int irq, struct irq_desc *desc) |
107 | { | 104 | { |
diff --git a/arch/powerpc/platforms/cell/smp.c b/arch/powerpc/platforms/cell/smp.c index e4438456c867..efb3964457b1 100644 --- a/arch/powerpc/platforms/cell/smp.c +++ b/arch/powerpc/platforms/cell/smp.c | |||
@@ -42,6 +42,7 @@ | |||
42 | #include <asm/firmware.h> | 42 | #include <asm/firmware.h> |
43 | #include <asm/system.h> | 43 | #include <asm/system.h> |
44 | #include <asm/rtas.h> | 44 | #include <asm/rtas.h> |
45 | #include <asm/cputhreads.h> | ||
45 | 46 | ||
46 | #include "interrupt.h" | 47 | #include "interrupt.h" |
47 | #include <asm/udbg.h> | 48 | #include <asm/udbg.h> |
@@ -182,7 +183,7 @@ static int smp_cell_cpu_bootable(unsigned int nr) | |||
182 | */ | 183 | */ |
183 | if (system_state < SYSTEM_RUNNING && | 184 | if (system_state < SYSTEM_RUNNING && |
184 | cpu_has_feature(CPU_FTR_SMT) && | 185 | cpu_has_feature(CPU_FTR_SMT) && |
185 | !smt_enabled_at_boot && nr % 2 != 0) | 186 | !smt_enabled_at_boot && cpu_thread_in_core(nr) != 0) |
186 | return 0; | 187 | return 0; |
187 | 188 | ||
188 | return 1; | 189 | return 1; |
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index a08862203643..e45cfa84911f 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/linux_logo.h> | 34 | #include <linux/linux_logo.h> |
35 | #include <asm/spu.h> | 35 | #include <asm/spu.h> |
36 | #include <asm/spu_priv1.h> | 36 | #include <asm/spu_priv1.h> |
37 | #include <asm/spu_csa.h> | ||
37 | #include <asm/xmon.h> | 38 | #include <asm/xmon.h> |
38 | #include <asm/prom.h> | 39 | #include <asm/prom.h> |
39 | 40 | ||
@@ -47,6 +48,13 @@ struct cbe_spu_info cbe_spu_info[MAX_NUMNODES]; | |||
47 | EXPORT_SYMBOL_GPL(cbe_spu_info); | 48 | EXPORT_SYMBOL_GPL(cbe_spu_info); |
48 | 49 | ||
49 | /* | 50 | /* |
51 | * The spufs fault-handling code needs to call force_sig_info to raise signals | ||
52 | * on DMA errors. Export it here to avoid general kernel-wide access to this | ||
53 | * function | ||
54 | */ | ||
55 | EXPORT_SYMBOL_GPL(force_sig_info); | ||
56 | |||
57 | /* | ||
50 | * Protects cbe_spu_info and spu->number. | 58 | * Protects cbe_spu_info and spu->number. |
51 | */ | 59 | */ |
52 | static DEFINE_SPINLOCK(spu_lock); | 60 | static DEFINE_SPINLOCK(spu_lock); |
@@ -66,6 +74,10 @@ static LIST_HEAD(spu_full_list); | |||
66 | static DEFINE_SPINLOCK(spu_full_list_lock); | 74 | static DEFINE_SPINLOCK(spu_full_list_lock); |
67 | static DEFINE_MUTEX(spu_full_list_mutex); | 75 | static DEFINE_MUTEX(spu_full_list_mutex); |
68 | 76 | ||
77 | struct spu_slb { | ||
78 | u64 esid, vsid; | ||
79 | }; | ||
80 | |||
69 | void spu_invalidate_slbs(struct spu *spu) | 81 | void spu_invalidate_slbs(struct spu *spu) |
70 | { | 82 | { |
71 | struct spu_priv2 __iomem *priv2 = spu->priv2; | 83 | struct spu_priv2 __iomem *priv2 = spu->priv2; |
@@ -114,40 +126,36 @@ void spu_associate_mm(struct spu *spu, struct mm_struct *mm) | |||
114 | } | 126 | } |
115 | EXPORT_SYMBOL_GPL(spu_associate_mm); | 127 | EXPORT_SYMBOL_GPL(spu_associate_mm); |
116 | 128 | ||
117 | static int __spu_trap_invalid_dma(struct spu *spu) | 129 | int spu_64k_pages_available(void) |
118 | { | 130 | { |
119 | pr_debug("%s\n", __FUNCTION__); | 131 | return mmu_psize_defs[MMU_PAGE_64K].shift != 0; |
120 | spu->dma_callback(spu, SPE_EVENT_INVALID_DMA); | ||
121 | return 0; | ||
122 | } | 132 | } |
133 | EXPORT_SYMBOL_GPL(spu_64k_pages_available); | ||
123 | 134 | ||
124 | static int __spu_trap_dma_align(struct spu *spu) | 135 | static void spu_restart_dma(struct spu *spu) |
125 | { | 136 | { |
126 | pr_debug("%s\n", __FUNCTION__); | 137 | struct spu_priv2 __iomem *priv2 = spu->priv2; |
127 | spu->dma_callback(spu, SPE_EVENT_DMA_ALIGNMENT); | ||
128 | return 0; | ||
129 | } | ||
130 | 138 | ||
131 | static int __spu_trap_error(struct spu *spu) | 139 | if (!test_bit(SPU_CONTEXT_SWITCH_PENDING, &spu->flags)) |
132 | { | 140 | out_be64(&priv2->mfc_control_RW, MFC_CNTL_RESTART_DMA_COMMAND); |
133 | pr_debug("%s\n", __FUNCTION__); | ||
134 | spu->dma_callback(spu, SPE_EVENT_SPE_ERROR); | ||
135 | return 0; | ||
136 | } | 141 | } |
137 | 142 | ||
138 | static void spu_restart_dma(struct spu *spu) | 143 | static inline void spu_load_slb(struct spu *spu, int slbe, struct spu_slb *slb) |
139 | { | 144 | { |
140 | struct spu_priv2 __iomem *priv2 = spu->priv2; | 145 | struct spu_priv2 __iomem *priv2 = spu->priv2; |
141 | 146 | ||
142 | if (!test_bit(SPU_CONTEXT_SWITCH_PENDING, &spu->flags)) | 147 | pr_debug("%s: adding SLB[%d] 0x%016lx 0x%016lx\n", |
143 | out_be64(&priv2->mfc_control_RW, MFC_CNTL_RESTART_DMA_COMMAND); | 148 | __func__, slbe, slb->vsid, slb->esid); |
149 | |||
150 | out_be64(&priv2->slb_index_W, slbe); | ||
151 | out_be64(&priv2->slb_vsid_RW, slb->vsid); | ||
152 | out_be64(&priv2->slb_esid_RW, slb->esid); | ||
144 | } | 153 | } |
145 | 154 | ||
146 | static int __spu_trap_data_seg(struct spu *spu, unsigned long ea) | 155 | static int __spu_trap_data_seg(struct spu *spu, unsigned long ea) |
147 | { | 156 | { |
148 | struct spu_priv2 __iomem *priv2 = spu->priv2; | ||
149 | struct mm_struct *mm = spu->mm; | 157 | struct mm_struct *mm = spu->mm; |
150 | u64 esid, vsid, llp; | 158 | struct spu_slb slb; |
151 | int psize; | 159 | int psize; |
152 | 160 | ||
153 | pr_debug("%s\n", __FUNCTION__); | 161 | pr_debug("%s\n", __FUNCTION__); |
@@ -159,7 +167,7 @@ static int __spu_trap_data_seg(struct spu *spu, unsigned long ea) | |||
159 | printk("%s: invalid access during switch!\n", __func__); | 167 | printk("%s: invalid access during switch!\n", __func__); |
160 | return 1; | 168 | return 1; |
161 | } | 169 | } |
162 | esid = (ea & ESID_MASK) | SLB_ESID_V; | 170 | slb.esid = (ea & ESID_MASK) | SLB_ESID_V; |
163 | 171 | ||
164 | switch(REGION_ID(ea)) { | 172 | switch(REGION_ID(ea)) { |
165 | case USER_REGION_ID: | 173 | case USER_REGION_ID: |
@@ -168,21 +176,21 @@ static int __spu_trap_data_seg(struct spu *spu, unsigned long ea) | |||
168 | #else | 176 | #else |
169 | psize = mm->context.user_psize; | 177 | psize = mm->context.user_psize; |
170 | #endif | 178 | #endif |
171 | vsid = (get_vsid(mm->context.id, ea, MMU_SEGSIZE_256M) << SLB_VSID_SHIFT) | | 179 | slb.vsid = (get_vsid(mm->context.id, ea, MMU_SEGSIZE_256M) |
172 | SLB_VSID_USER; | 180 | << SLB_VSID_SHIFT) | SLB_VSID_USER; |
173 | break; | 181 | break; |
174 | case VMALLOC_REGION_ID: | 182 | case VMALLOC_REGION_ID: |
175 | if (ea < VMALLOC_END) | 183 | if (ea < VMALLOC_END) |
176 | psize = mmu_vmalloc_psize; | 184 | psize = mmu_vmalloc_psize; |
177 | else | 185 | else |
178 | psize = mmu_io_psize; | 186 | psize = mmu_io_psize; |
179 | vsid = (get_kernel_vsid(ea, MMU_SEGSIZE_256M) << SLB_VSID_SHIFT) | | 187 | slb.vsid = (get_kernel_vsid(ea, MMU_SEGSIZE_256M) |
180 | SLB_VSID_KERNEL; | 188 | << SLB_VSID_SHIFT) | SLB_VSID_KERNEL; |
181 | break; | 189 | break; |
182 | case KERNEL_REGION_ID: | 190 | case KERNEL_REGION_ID: |
183 | psize = mmu_linear_psize; | 191 | psize = mmu_linear_psize; |
184 | vsid = (get_kernel_vsid(ea, MMU_SEGSIZE_256M) << SLB_VSID_SHIFT) | | 192 | slb.vsid = (get_kernel_vsid(ea, MMU_SEGSIZE_256M) |
185 | SLB_VSID_KERNEL; | 193 | << SLB_VSID_SHIFT) | SLB_VSID_KERNEL; |
186 | break; | 194 | break; |
187 | default: | 195 | default: |
188 | /* Future: support kernel segments so that drivers | 196 | /* Future: support kernel segments so that drivers |
@@ -191,11 +199,9 @@ static int __spu_trap_data_seg(struct spu *spu, unsigned long ea) | |||
191 | pr_debug("invalid region access at %016lx\n", ea); | 199 | pr_debug("invalid region access at %016lx\n", ea); |
192 | return 1; | 200 | return 1; |
193 | } | 201 | } |
194 | llp = mmu_psize_defs[psize].sllp; | 202 | slb.vsid |= mmu_psize_defs[psize].sllp; |
195 | 203 | ||
196 | out_be64(&priv2->slb_index_W, spu->slb_replace); | 204 | spu_load_slb(spu, spu->slb_replace, &slb); |
197 | out_be64(&priv2->slb_vsid_RW, vsid | llp); | ||
198 | out_be64(&priv2->slb_esid_RW, esid); | ||
199 | 205 | ||
200 | spu->slb_replace++; | 206 | spu->slb_replace++; |
201 | if (spu->slb_replace >= 8) | 207 | if (spu->slb_replace >= 8) |
@@ -225,13 +231,83 @@ static int __spu_trap_data_map(struct spu *spu, unsigned long ea, u64 dsisr) | |||
225 | return 1; | 231 | return 1; |
226 | } | 232 | } |
227 | 233 | ||
234 | spu->class_0_pending = 0; | ||
228 | spu->dar = ea; | 235 | spu->dar = ea; |
229 | spu->dsisr = dsisr; | 236 | spu->dsisr = dsisr; |
230 | mb(); | 237 | |
231 | spu->stop_callback(spu); | 238 | spu->stop_callback(spu); |
239 | |||
240 | return 0; | ||
241 | } | ||
242 | |||
243 | static void __spu_kernel_slb(void *addr, struct spu_slb *slb) | ||
244 | { | ||
245 | unsigned long ea = (unsigned long)addr; | ||
246 | u64 llp; | ||
247 | |||
248 | if (REGION_ID(ea) == KERNEL_REGION_ID) | ||
249 | llp = mmu_psize_defs[mmu_linear_psize].sllp; | ||
250 | else | ||
251 | llp = mmu_psize_defs[mmu_virtual_psize].sllp; | ||
252 | |||
253 | slb->vsid = (get_kernel_vsid(ea, MMU_SEGSIZE_256M) << SLB_VSID_SHIFT) | | ||
254 | SLB_VSID_KERNEL | llp; | ||
255 | slb->esid = (ea & ESID_MASK) | SLB_ESID_V; | ||
256 | } | ||
257 | |||
258 | /** | ||
259 | * Given an array of @nr_slbs SLB entries, @slbs, return non-zero if the | ||
260 | * address @new_addr is present. | ||
261 | */ | ||
262 | static inline int __slb_present(struct spu_slb *slbs, int nr_slbs, | ||
263 | void *new_addr) | ||
264 | { | ||
265 | unsigned long ea = (unsigned long)new_addr; | ||
266 | int i; | ||
267 | |||
268 | for (i = 0; i < nr_slbs; i++) | ||
269 | if (!((slbs[i].esid ^ ea) & ESID_MASK)) | ||
270 | return 1; | ||
271 | |||
232 | return 0; | 272 | return 0; |
233 | } | 273 | } |
234 | 274 | ||
275 | /** | ||
276 | * Setup the SPU kernel SLBs, in preparation for a context save/restore. We | ||
277 | * need to map both the context save area, and the save/restore code. | ||
278 | * | ||
279 | * Because the lscsa and code may cross segment boundaires, we check to see | ||
280 | * if mappings are required for the start and end of each range. We currently | ||
281 | * assume that the mappings are smaller that one segment - if not, something | ||
282 | * is seriously wrong. | ||
283 | */ | ||
284 | void spu_setup_kernel_slbs(struct spu *spu, struct spu_lscsa *lscsa, | ||
285 | void *code, int code_size) | ||
286 | { | ||
287 | struct spu_slb slbs[4]; | ||
288 | int i, nr_slbs = 0; | ||
289 | /* start and end addresses of both mappings */ | ||
290 | void *addrs[] = { | ||
291 | lscsa, (void *)lscsa + sizeof(*lscsa) - 1, | ||
292 | code, code + code_size - 1 | ||
293 | }; | ||
294 | |||
295 | /* check the set of addresses, and create a new entry in the slbs array | ||
296 | * if there isn't already a SLB for that address */ | ||
297 | for (i = 0; i < ARRAY_SIZE(addrs); i++) { | ||
298 | if (__slb_present(slbs, nr_slbs, addrs[i])) | ||
299 | continue; | ||
300 | |||
301 | __spu_kernel_slb(addrs[i], &slbs[nr_slbs]); | ||
302 | nr_slbs++; | ||
303 | } | ||
304 | |||
305 | /* Add the set of SLBs */ | ||
306 | for (i = 0; i < nr_slbs; i++) | ||
307 | spu_load_slb(spu, i, &slbs[i]); | ||
308 | } | ||
309 | EXPORT_SYMBOL_GPL(spu_setup_kernel_slbs); | ||
310 | |||
235 | static irqreturn_t | 311 | static irqreturn_t |
236 | spu_irq_class_0(int irq, void *data) | 312 | spu_irq_class_0(int irq, void *data) |
237 | { | 313 | { |
@@ -240,12 +316,13 @@ spu_irq_class_0(int irq, void *data) | |||
240 | 316 | ||
241 | spu = data; | 317 | spu = data; |
242 | 318 | ||
319 | spin_lock(&spu->register_lock); | ||
243 | mask = spu_int_mask_get(spu, 0); | 320 | mask = spu_int_mask_get(spu, 0); |
244 | stat = spu_int_stat_get(spu, 0); | 321 | stat = spu_int_stat_get(spu, 0) & mask; |
245 | stat &= mask; | ||
246 | 322 | ||
247 | spin_lock(&spu->register_lock); | ||
248 | spu->class_0_pending |= stat; | 323 | spu->class_0_pending |= stat; |
324 | spu->dsisr = spu_mfc_dsisr_get(spu); | ||
325 | spu->dar = spu_mfc_dar_get(spu); | ||
249 | spin_unlock(&spu->register_lock); | 326 | spin_unlock(&spu->register_lock); |
250 | 327 | ||
251 | spu->stop_callback(spu); | 328 | spu->stop_callback(spu); |
@@ -255,31 +332,6 @@ spu_irq_class_0(int irq, void *data) | |||
255 | return IRQ_HANDLED; | 332 | return IRQ_HANDLED; |
256 | } | 333 | } |
257 | 334 | ||
258 | int | ||
259 | spu_irq_class_0_bottom(struct spu *spu) | ||
260 | { | ||
261 | unsigned long flags; | ||
262 | unsigned long stat; | ||
263 | |||
264 | spin_lock_irqsave(&spu->register_lock, flags); | ||
265 | stat = spu->class_0_pending; | ||
266 | spu->class_0_pending = 0; | ||
267 | |||
268 | if (stat & 1) /* invalid DMA alignment */ | ||
269 | __spu_trap_dma_align(spu); | ||
270 | |||
271 | if (stat & 2) /* invalid MFC DMA */ | ||
272 | __spu_trap_invalid_dma(spu); | ||
273 | |||
274 | if (stat & 4) /* error on SPU */ | ||
275 | __spu_trap_error(spu); | ||
276 | |||
277 | spin_unlock_irqrestore(&spu->register_lock, flags); | ||
278 | |||
279 | return (stat & 0x7) ? -EIO : 0; | ||
280 | } | ||
281 | EXPORT_SYMBOL_GPL(spu_irq_class_0_bottom); | ||
282 | |||
283 | static irqreturn_t | 335 | static irqreturn_t |
284 | spu_irq_class_1(int irq, void *data) | 336 | spu_irq_class_1(int irq, void *data) |
285 | { | 337 | { |
@@ -294,24 +346,23 @@ spu_irq_class_1(int irq, void *data) | |||
294 | stat = spu_int_stat_get(spu, 1) & mask; | 346 | stat = spu_int_stat_get(spu, 1) & mask; |
295 | dar = spu_mfc_dar_get(spu); | 347 | dar = spu_mfc_dar_get(spu); |
296 | dsisr = spu_mfc_dsisr_get(spu); | 348 | dsisr = spu_mfc_dsisr_get(spu); |
297 | if (stat & 2) /* mapping fault */ | 349 | if (stat & CLASS1_STORAGE_FAULT_INTR) |
298 | spu_mfc_dsisr_set(spu, 0ul); | 350 | spu_mfc_dsisr_set(spu, 0ul); |
299 | spu_int_stat_clear(spu, 1, stat); | 351 | spu_int_stat_clear(spu, 1, stat); |
300 | spin_unlock(&spu->register_lock); | 352 | spin_unlock(&spu->register_lock); |
301 | pr_debug("%s: %lx %lx %lx %lx\n", __FUNCTION__, mask, stat, | 353 | pr_debug("%s: %lx %lx %lx %lx\n", __FUNCTION__, mask, stat, |
302 | dar, dsisr); | 354 | dar, dsisr); |
303 | 355 | ||
304 | if (stat & 1) /* segment fault */ | 356 | if (stat & CLASS1_SEGMENT_FAULT_INTR) |
305 | __spu_trap_data_seg(spu, dar); | 357 | __spu_trap_data_seg(spu, dar); |
306 | 358 | ||
307 | if (stat & 2) { /* mapping fault */ | 359 | if (stat & CLASS1_STORAGE_FAULT_INTR) |
308 | __spu_trap_data_map(spu, dar, dsisr); | 360 | __spu_trap_data_map(spu, dar, dsisr); |
309 | } | ||
310 | 361 | ||
311 | if (stat & 4) /* ls compare & suspend on get */ | 362 | if (stat & CLASS1_LS_COMPARE_SUSPEND_ON_GET_INTR) |
312 | ; | 363 | ; |
313 | 364 | ||
314 | if (stat & 8) /* ls compare & suspend on put */ | 365 | if (stat & CLASS1_LS_COMPARE_SUSPEND_ON_PUT_INTR) |
315 | ; | 366 | ; |
316 | 367 | ||
317 | return stat ? IRQ_HANDLED : IRQ_NONE; | 368 | return stat ? IRQ_HANDLED : IRQ_NONE; |
@@ -323,6 +374,8 @@ spu_irq_class_2(int irq, void *data) | |||
323 | struct spu *spu; | 374 | struct spu *spu; |
324 | unsigned long stat; | 375 | unsigned long stat; |
325 | unsigned long mask; | 376 | unsigned long mask; |
377 | const int mailbox_intrs = | ||
378 | CLASS2_MAILBOX_THRESHOLD_INTR | CLASS2_MAILBOX_INTR; | ||
326 | 379 | ||
327 | spu = data; | 380 | spu = data; |
328 | spin_lock(&spu->register_lock); | 381 | spin_lock(&spu->register_lock); |
@@ -330,31 +383,30 @@ spu_irq_class_2(int irq, void *data) | |||
330 | mask = spu_int_mask_get(spu, 2); | 383 | mask = spu_int_mask_get(spu, 2); |
331 | /* ignore interrupts we're not waiting for */ | 384 | /* ignore interrupts we're not waiting for */ |
332 | stat &= mask; | 385 | stat &= mask; |
333 | /* | 386 | |
334 | * mailbox interrupts (0x1 and 0x10) are level triggered. | 387 | /* mailbox interrupts are level triggered. mask them now before |
335 | * mask them now before acknowledging. | 388 | * acknowledging */ |
336 | */ | 389 | if (stat & mailbox_intrs) |
337 | if (stat & 0x11) | 390 | spu_int_mask_and(spu, 2, ~(stat & mailbox_intrs)); |
338 | spu_int_mask_and(spu, 2, ~(stat & 0x11)); | ||
339 | /* acknowledge all interrupts before the callbacks */ | 391 | /* acknowledge all interrupts before the callbacks */ |
340 | spu_int_stat_clear(spu, 2, stat); | 392 | spu_int_stat_clear(spu, 2, stat); |
341 | spin_unlock(&spu->register_lock); | 393 | spin_unlock(&spu->register_lock); |
342 | 394 | ||
343 | pr_debug("class 2 interrupt %d, %lx, %lx\n", irq, stat, mask); | 395 | pr_debug("class 2 interrupt %d, %lx, %lx\n", irq, stat, mask); |
344 | 396 | ||
345 | if (stat & 1) /* PPC core mailbox */ | 397 | if (stat & CLASS2_MAILBOX_INTR) |
346 | spu->ibox_callback(spu); | 398 | spu->ibox_callback(spu); |
347 | 399 | ||
348 | if (stat & 2) /* SPU stop-and-signal */ | 400 | if (stat & CLASS2_SPU_STOP_INTR) |
349 | spu->stop_callback(spu); | 401 | spu->stop_callback(spu); |
350 | 402 | ||
351 | if (stat & 4) /* SPU halted */ | 403 | if (stat & CLASS2_SPU_HALT_INTR) |
352 | spu->stop_callback(spu); | 404 | spu->stop_callback(spu); |
353 | 405 | ||
354 | if (stat & 8) /* DMA tag group complete */ | 406 | if (stat & CLASS2_SPU_DMA_TAG_GROUP_COMPLETE_INTR) |
355 | spu->mfc_callback(spu); | 407 | spu->mfc_callback(spu); |
356 | 408 | ||
357 | if (stat & 0x10) /* SPU mailbox threshold */ | 409 | if (stat & CLASS2_MAILBOX_THRESHOLD_INTR) |
358 | spu->wbox_callback(spu); | 410 | spu->wbox_callback(spu); |
359 | 411 | ||
360 | spu->stats.class2_intr++; | 412 | spu->stats.class2_intr++; |
@@ -479,13 +531,27 @@ EXPORT_SYMBOL_GPL(spu_add_sysdev_attr); | |||
479 | int spu_add_sysdev_attr_group(struct attribute_group *attrs) | 531 | int spu_add_sysdev_attr_group(struct attribute_group *attrs) |
480 | { | 532 | { |
481 | struct spu *spu; | 533 | struct spu *spu; |
534 | int rc = 0; | ||
482 | 535 | ||
483 | mutex_lock(&spu_full_list_mutex); | 536 | mutex_lock(&spu_full_list_mutex); |
484 | list_for_each_entry(spu, &spu_full_list, full_list) | 537 | list_for_each_entry(spu, &spu_full_list, full_list) { |
485 | sysfs_create_group(&spu->sysdev.kobj, attrs); | 538 | rc = sysfs_create_group(&spu->sysdev.kobj, attrs); |
539 | |||
540 | /* we're in trouble here, but try unwinding anyway */ | ||
541 | if (rc) { | ||
542 | printk(KERN_ERR "%s: can't create sysfs group '%s'\n", | ||
543 | __func__, attrs->name); | ||
544 | |||
545 | list_for_each_entry_continue_reverse(spu, | ||
546 | &spu_full_list, full_list) | ||
547 | sysfs_remove_group(&spu->sysdev.kobj, attrs); | ||
548 | break; | ||
549 | } | ||
550 | } | ||
551 | |||
486 | mutex_unlock(&spu_full_list_mutex); | 552 | mutex_unlock(&spu_full_list_mutex); |
487 | 553 | ||
488 | return 0; | 554 | return rc; |
489 | } | 555 | } |
490 | EXPORT_SYMBOL_GPL(spu_add_sysdev_attr_group); | 556 | EXPORT_SYMBOL_GPL(spu_add_sysdev_attr_group); |
491 | 557 | ||
diff --git a/arch/powerpc/platforms/cell/spu_fault.c b/arch/powerpc/platforms/cell/spu_fault.c new file mode 100644 index 000000000000..c8b1cd42905d --- /dev/null +++ b/arch/powerpc/platforms/cell/spu_fault.c | |||
@@ -0,0 +1,98 @@ | |||
1 | /* | ||
2 | * SPU mm fault handler | ||
3 | * | ||
4 | * (C) Copyright IBM Deutschland Entwicklung GmbH 2007 | ||
5 | * | ||
6 | * Author: Arnd Bergmann <arndb@de.ibm.com> | ||
7 | * Author: Jeremy Kerr <jk@ozlabs.org> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2, or (at your option) | ||
12 | * any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
22 | */ | ||
23 | #include <linux/sched.h> | ||
24 | #include <linux/mm.h> | ||
25 | #include <linux/module.h> | ||
26 | |||
27 | #include <asm/spu.h> | ||
28 | #include <asm/spu_csa.h> | ||
29 | |||
30 | /* | ||
31 | * This ought to be kept in sync with the powerpc specific do_page_fault | ||
32 | * function. Currently, there are a few corner cases that we haven't had | ||
33 | * to handle fortunately. | ||
34 | */ | ||
35 | int spu_handle_mm_fault(struct mm_struct *mm, unsigned long ea, | ||
36 | unsigned long dsisr, unsigned *flt) | ||
37 | { | ||
38 | struct vm_area_struct *vma; | ||
39 | unsigned long is_write; | ||
40 | int ret; | ||
41 | |||
42 | #if 0 | ||
43 | if (!IS_VALID_EA(ea)) { | ||
44 | return -EFAULT; | ||
45 | } | ||
46 | #endif /* XXX */ | ||
47 | if (mm == NULL) { | ||
48 | return -EFAULT; | ||
49 | } | ||
50 | if (mm->pgd == NULL) { | ||
51 | return -EFAULT; | ||
52 | } | ||
53 | |||
54 | down_read(&mm->mmap_sem); | ||
55 | vma = find_vma(mm, ea); | ||
56 | if (!vma) | ||
57 | goto bad_area; | ||
58 | if (vma->vm_start <= ea) | ||
59 | goto good_area; | ||
60 | if (!(vma->vm_flags & VM_GROWSDOWN)) | ||
61 | goto bad_area; | ||
62 | if (expand_stack(vma, ea)) | ||
63 | goto bad_area; | ||
64 | good_area: | ||
65 | is_write = dsisr & MFC_DSISR_ACCESS_PUT; | ||
66 | if (is_write) { | ||
67 | if (!(vma->vm_flags & VM_WRITE)) | ||
68 | goto bad_area; | ||
69 | } else { | ||
70 | if (dsisr & MFC_DSISR_ACCESS_DENIED) | ||
71 | goto bad_area; | ||
72 | if (!(vma->vm_flags & (VM_READ | VM_EXEC))) | ||
73 | goto bad_area; | ||
74 | } | ||
75 | ret = 0; | ||
76 | *flt = handle_mm_fault(mm, vma, ea, is_write); | ||
77 | if (unlikely(*flt & VM_FAULT_ERROR)) { | ||
78 | if (*flt & VM_FAULT_OOM) { | ||
79 | ret = -ENOMEM; | ||
80 | goto bad_area; | ||
81 | } else if (*flt & VM_FAULT_SIGBUS) { | ||
82 | ret = -EFAULT; | ||
83 | goto bad_area; | ||
84 | } | ||
85 | BUG(); | ||
86 | } | ||
87 | if (*flt & VM_FAULT_MAJOR) | ||
88 | current->maj_flt++; | ||
89 | else | ||
90 | current->min_flt++; | ||
91 | up_read(&mm->mmap_sem); | ||
92 | return ret; | ||
93 | |||
94 | bad_area: | ||
95 | up_read(&mm->mmap_sem); | ||
96 | return -EFAULT; | ||
97 | } | ||
98 | EXPORT_SYMBOL_GPL(spu_handle_mm_fault); | ||
diff --git a/arch/powerpc/platforms/cell/spu_manage.c b/arch/powerpc/platforms/cell/spu_manage.c index 1b010707488d..d351bdebf5f1 100644 --- a/arch/powerpc/platforms/cell/spu_manage.c +++ b/arch/powerpc/platforms/cell/spu_manage.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <asm/firmware.h> | 35 | #include <asm/firmware.h> |
36 | #include <asm/prom.h> | 36 | #include <asm/prom.h> |
37 | 37 | ||
38 | #include "spufs/spufs.h" | ||
38 | #include "interrupt.h" | 39 | #include "interrupt.h" |
39 | 40 | ||
40 | struct device_node *spu_devnode(struct spu *spu) | 41 | struct device_node *spu_devnode(struct spu *spu) |
@@ -345,7 +346,7 @@ static int __init of_create_spu(struct spu *spu, void *data) | |||
345 | } | 346 | } |
346 | ret = spu_map_interrupts_old(spu, spe); | 347 | ret = spu_map_interrupts_old(spu, spe); |
347 | if (ret) { | 348 | if (ret) { |
348 | printk(KERN_ERR "%s: could not map interrupts", | 349 | printk(KERN_ERR "%s: could not map interrupts\n", |
349 | spu->name); | 350 | spu->name); |
350 | goto out_unmap; | 351 | goto out_unmap; |
351 | } | 352 | } |
@@ -369,6 +370,16 @@ static int of_destroy_spu(struct spu *spu) | |||
369 | return 0; | 370 | return 0; |
370 | } | 371 | } |
371 | 372 | ||
373 | static void enable_spu_by_master_run(struct spu_context *ctx) | ||
374 | { | ||
375 | ctx->ops->master_start(ctx); | ||
376 | } | ||
377 | |||
378 | static void disable_spu_by_master_run(struct spu_context *ctx) | ||
379 | { | ||
380 | ctx->ops->master_stop(ctx); | ||
381 | } | ||
382 | |||
372 | /* Hardcoded affinity idxs for qs20 */ | 383 | /* Hardcoded affinity idxs for qs20 */ |
373 | #define QS20_SPES_PER_BE 8 | 384 | #define QS20_SPES_PER_BE 8 |
374 | static int qs20_reg_idxs[QS20_SPES_PER_BE] = { 0, 2, 4, 6, 7, 5, 3, 1 }; | 385 | static int qs20_reg_idxs[QS20_SPES_PER_BE] = { 0, 2, 4, 6, 7, 5, 3, 1 }; |
@@ -411,10 +422,15 @@ static void init_affinity_qs20_harcoded(void) | |||
411 | 422 | ||
412 | static int of_has_vicinity(void) | 423 | static int of_has_vicinity(void) |
413 | { | 424 | { |
414 | struct spu* spu; | 425 | struct device_node *dn; |
415 | 426 | ||
416 | spu = list_first_entry(&cbe_spu_info[0].spus, struct spu, cbe_list); | 427 | for_each_node_by_type(dn, "spe") { |
417 | return of_find_property(spu_devnode(spu), "vicinity", NULL) != NULL; | 428 | if (of_find_property(dn, "vicinity", NULL)) { |
429 | of_node_put(dn); | ||
430 | return 1; | ||
431 | } | ||
432 | } | ||
433 | return 0; | ||
418 | } | 434 | } |
419 | 435 | ||
420 | static struct spu *devnode_spu(int cbe, struct device_node *dn) | 436 | static struct spu *devnode_spu(int cbe, struct device_node *dn) |
@@ -525,7 +541,7 @@ static int __init init_affinity(void) | |||
525 | if (of_flat_dt_is_compatible(root, "IBM,CPBW-1.0")) | 541 | if (of_flat_dt_is_compatible(root, "IBM,CPBW-1.0")) |
526 | init_affinity_qs20_harcoded(); | 542 | init_affinity_qs20_harcoded(); |
527 | else | 543 | else |
528 | printk("No affinity configuration found"); | 544 | printk("No affinity configuration found\n"); |
529 | } | 545 | } |
530 | 546 | ||
531 | return 0; | 547 | return 0; |
@@ -535,5 +551,7 @@ const struct spu_management_ops spu_management_of_ops = { | |||
535 | .enumerate_spus = of_enumerate_spus, | 551 | .enumerate_spus = of_enumerate_spus, |
536 | .create_spu = of_create_spu, | 552 | .create_spu = of_create_spu, |
537 | .destroy_spu = of_destroy_spu, | 553 | .destroy_spu = of_destroy_spu, |
554 | .enable_spu = enable_spu_by_master_run, | ||
555 | .disable_spu = disable_spu_by_master_run, | ||
538 | .init_affinity = init_affinity, | 556 | .init_affinity = init_affinity, |
539 | }; | 557 | }; |
diff --git a/arch/powerpc/platforms/cell/spufs/Makefile b/arch/powerpc/platforms/cell/spufs/Makefile index 328afcf89503..d3a349fb42e5 100644 --- a/arch/powerpc/platforms/cell/spufs/Makefile +++ b/arch/powerpc/platforms/cell/spufs/Makefile | |||
@@ -1,8 +1,8 @@ | |||
1 | obj-y += switch.o fault.o lscsa_alloc.o | ||
2 | 1 | ||
3 | obj-$(CONFIG_SPU_FS) += spufs.o | 2 | obj-$(CONFIG_SPU_FS) += spufs.o |
4 | spufs-y += inode.o file.o context.o syscalls.o coredump.o | 3 | spufs-y += inode.o file.o context.o syscalls.o coredump.o |
5 | spufs-y += sched.o backing_ops.o hw_ops.o run.o gang.o | 4 | spufs-y += sched.o backing_ops.o hw_ops.o run.o gang.o |
5 | spufs-y += switch.o fault.o lscsa_alloc.o | ||
6 | 6 | ||
7 | # Rules to build switch.o with the help of SPU tool chain | 7 | # Rules to build switch.o with the help of SPU tool chain |
8 | SPU_CROSS := spu- | 8 | SPU_CROSS := spu- |
diff --git a/arch/powerpc/platforms/cell/spufs/backing_ops.c b/arch/powerpc/platforms/cell/spufs/backing_ops.c index ec01214e51ee..50d98a154aaf 100644 --- a/arch/powerpc/platforms/cell/spufs/backing_ops.c +++ b/arch/powerpc/platforms/cell/spufs/backing_ops.c | |||
@@ -106,16 +106,20 @@ static unsigned int spu_backing_mbox_stat_poll(struct spu_context *ctx, | |||
106 | if (stat & 0xff0000) | 106 | if (stat & 0xff0000) |
107 | ret |= POLLIN | POLLRDNORM; | 107 | ret |= POLLIN | POLLRDNORM; |
108 | else { | 108 | else { |
109 | ctx->csa.priv1.int_stat_class0_RW &= ~0x1; | 109 | ctx->csa.priv1.int_stat_class2_RW &= |
110 | ctx->csa.priv1.int_mask_class2_RW |= 0x1; | 110 | ~CLASS2_MAILBOX_INTR; |
111 | ctx->csa.priv1.int_mask_class2_RW |= | ||
112 | CLASS2_ENABLE_MAILBOX_INTR; | ||
111 | } | 113 | } |
112 | } | 114 | } |
113 | if (events & (POLLOUT | POLLWRNORM)) { | 115 | if (events & (POLLOUT | POLLWRNORM)) { |
114 | if (stat & 0x00ff00) | 116 | if (stat & 0x00ff00) |
115 | ret = POLLOUT | POLLWRNORM; | 117 | ret = POLLOUT | POLLWRNORM; |
116 | else { | 118 | else { |
117 | ctx->csa.priv1.int_stat_class0_RW &= ~0x10; | 119 | ctx->csa.priv1.int_stat_class2_RW &= |
118 | ctx->csa.priv1.int_mask_class2_RW |= 0x10; | 120 | ~CLASS2_MAILBOX_THRESHOLD_INTR; |
121 | ctx->csa.priv1.int_mask_class2_RW |= | ||
122 | CLASS2_ENABLE_MAILBOX_THRESHOLD_INTR; | ||
119 | } | 123 | } |
120 | } | 124 | } |
121 | spin_unlock_irq(&ctx->csa.register_lock); | 125 | spin_unlock_irq(&ctx->csa.register_lock); |
@@ -139,7 +143,7 @@ static int spu_backing_ibox_read(struct spu_context *ctx, u32 * data) | |||
139 | ret = 4; | 143 | ret = 4; |
140 | } else { | 144 | } else { |
141 | /* make sure we get woken up by the interrupt */ | 145 | /* make sure we get woken up by the interrupt */ |
142 | ctx->csa.priv1.int_mask_class2_RW |= 0x1UL; | 146 | ctx->csa.priv1.int_mask_class2_RW |= CLASS2_ENABLE_MAILBOX_INTR; |
143 | ret = 0; | 147 | ret = 0; |
144 | } | 148 | } |
145 | spin_unlock(&ctx->csa.register_lock); | 149 | spin_unlock(&ctx->csa.register_lock); |
@@ -169,7 +173,8 @@ static int spu_backing_wbox_write(struct spu_context *ctx, u32 data) | |||
169 | } else { | 173 | } else { |
170 | /* make sure we get woken up by the interrupt when space | 174 | /* make sure we get woken up by the interrupt when space |
171 | becomes available */ | 175 | becomes available */ |
172 | ctx->csa.priv1.int_mask_class2_RW |= 0x10; | 176 | ctx->csa.priv1.int_mask_class2_RW |= |
177 | CLASS2_ENABLE_MAILBOX_THRESHOLD_INTR; | ||
173 | ret = 0; | 178 | ret = 0; |
174 | } | 179 | } |
175 | spin_unlock(&ctx->csa.register_lock); | 180 | spin_unlock(&ctx->csa.register_lock); |
@@ -268,6 +273,11 @@ static char *spu_backing_get_ls(struct spu_context *ctx) | |||
268 | return ctx->csa.lscsa->ls; | 273 | return ctx->csa.lscsa->ls; |
269 | } | 274 | } |
270 | 275 | ||
276 | static void spu_backing_privcntl_write(struct spu_context *ctx, u64 val) | ||
277 | { | ||
278 | ctx->csa.priv2.spu_privcntl_RW = val; | ||
279 | } | ||
280 | |||
271 | static u32 spu_backing_runcntl_read(struct spu_context *ctx) | 281 | static u32 spu_backing_runcntl_read(struct spu_context *ctx) |
272 | { | 282 | { |
273 | return ctx->csa.prob.spu_runcntl_RW; | 283 | return ctx->csa.prob.spu_runcntl_RW; |
@@ -285,6 +295,11 @@ static void spu_backing_runcntl_write(struct spu_context *ctx, u32 val) | |||
285 | spin_unlock(&ctx->csa.register_lock); | 295 | spin_unlock(&ctx->csa.register_lock); |
286 | } | 296 | } |
287 | 297 | ||
298 | static void spu_backing_runcntl_stop(struct spu_context *ctx) | ||
299 | { | ||
300 | spu_backing_runcntl_write(ctx, SPU_RUNCNTL_STOP); | ||
301 | } | ||
302 | |||
288 | static void spu_backing_master_start(struct spu_context *ctx) | 303 | static void spu_backing_master_start(struct spu_context *ctx) |
289 | { | 304 | { |
290 | struct spu_state *csa = &ctx->csa; | 305 | struct spu_state *csa = &ctx->csa; |
@@ -358,7 +373,7 @@ static int spu_backing_send_mfc_command(struct spu_context *ctx, | |||
358 | 373 | ||
359 | static void spu_backing_restart_dma(struct spu_context *ctx) | 374 | static void spu_backing_restart_dma(struct spu_context *ctx) |
360 | { | 375 | { |
361 | /* nothing to do here */ | 376 | ctx->csa.priv2.mfc_control_RW |= MFC_CNTL_RESTART_DMA_COMMAND; |
362 | } | 377 | } |
363 | 378 | ||
364 | struct spu_context_ops spu_backing_ops = { | 379 | struct spu_context_ops spu_backing_ops = { |
@@ -379,8 +394,10 @@ struct spu_context_ops spu_backing_ops = { | |||
379 | .npc_write = spu_backing_npc_write, | 394 | .npc_write = spu_backing_npc_write, |
380 | .status_read = spu_backing_status_read, | 395 | .status_read = spu_backing_status_read, |
381 | .get_ls = spu_backing_get_ls, | 396 | .get_ls = spu_backing_get_ls, |
397 | .privcntl_write = spu_backing_privcntl_write, | ||
382 | .runcntl_read = spu_backing_runcntl_read, | 398 | .runcntl_read = spu_backing_runcntl_read, |
383 | .runcntl_write = spu_backing_runcntl_write, | 399 | .runcntl_write = spu_backing_runcntl_write, |
400 | .runcntl_stop = spu_backing_runcntl_stop, | ||
384 | .master_start = spu_backing_master_start, | 401 | .master_start = spu_backing_master_start, |
385 | .master_stop = spu_backing_master_stop, | 402 | .master_stop = spu_backing_master_stop, |
386 | .set_mfc_query = spu_backing_set_mfc_query, | 403 | .set_mfc_query = spu_backing_set_mfc_query, |
diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c index adf0a030d6fe..133995ed5cc7 100644 --- a/arch/powerpc/platforms/cell/spufs/context.c +++ b/arch/powerpc/platforms/cell/spufs/context.c | |||
@@ -52,6 +52,7 @@ struct spu_context *alloc_spu_context(struct spu_gang *gang) | |||
52 | init_waitqueue_head(&ctx->wbox_wq); | 52 | init_waitqueue_head(&ctx->wbox_wq); |
53 | init_waitqueue_head(&ctx->stop_wq); | 53 | init_waitqueue_head(&ctx->stop_wq); |
54 | init_waitqueue_head(&ctx->mfc_wq); | 54 | init_waitqueue_head(&ctx->mfc_wq); |
55 | init_waitqueue_head(&ctx->run_wq); | ||
55 | ctx->state = SPU_STATE_SAVED; | 56 | ctx->state = SPU_STATE_SAVED; |
56 | ctx->ops = &spu_backing_ops; | 57 | ctx->ops = &spu_backing_ops; |
57 | ctx->owner = get_task_mm(current); | 58 | ctx->owner = get_task_mm(current); |
@@ -105,7 +106,17 @@ int put_spu_context(struct spu_context *ctx) | |||
105 | void spu_forget(struct spu_context *ctx) | 106 | void spu_forget(struct spu_context *ctx) |
106 | { | 107 | { |
107 | struct mm_struct *mm; | 108 | struct mm_struct *mm; |
108 | spu_acquire_saved(ctx); | 109 | |
110 | /* | ||
111 | * This is basically an open-coded spu_acquire_saved, except that | ||
112 | * we don't acquire the state mutex interruptible. | ||
113 | */ | ||
114 | mutex_lock(&ctx->state_mutex); | ||
115 | if (ctx->state != SPU_STATE_SAVED) { | ||
116 | set_bit(SPU_SCHED_WAS_ACTIVE, &ctx->sched_flags); | ||
117 | spu_deactivate(ctx); | ||
118 | } | ||
119 | |||
109 | mm = ctx->owner; | 120 | mm = ctx->owner; |
110 | ctx->owner = NULL; | 121 | ctx->owner = NULL; |
111 | mmput(mm); | 122 | mmput(mm); |
@@ -133,47 +144,23 @@ void spu_unmap_mappings(struct spu_context *ctx) | |||
133 | } | 144 | } |
134 | 145 | ||
135 | /** | 146 | /** |
136 | * spu_acquire_runnable - lock spu contex and make sure it is in runnable state | 147 | * spu_acquire_saved - lock spu contex and make sure it is in saved state |
137 | * @ctx: spu contex to lock | 148 | * @ctx: spu contex to lock |
138 | * | ||
139 | * Note: | ||
140 | * Returns 0 and with the context locked on success | ||
141 | * Returns negative error and with the context _unlocked_ on failure. | ||
142 | */ | 149 | */ |
143 | int spu_acquire_runnable(struct spu_context *ctx, unsigned long flags) | 150 | int spu_acquire_saved(struct spu_context *ctx) |
144 | { | 151 | { |
145 | int ret = -EINVAL; | 152 | int ret; |
146 | |||
147 | spu_acquire(ctx); | ||
148 | if (ctx->state == SPU_STATE_SAVED) { | ||
149 | /* | ||
150 | * Context is about to be freed, so we can't acquire it anymore. | ||
151 | */ | ||
152 | if (!ctx->owner) | ||
153 | goto out_unlock; | ||
154 | ret = spu_activate(ctx, flags); | ||
155 | if (ret) | ||
156 | goto out_unlock; | ||
157 | } | ||
158 | 153 | ||
159 | return 0; | 154 | ret = spu_acquire(ctx); |
160 | 155 | if (ret) | |
161 | out_unlock: | 156 | return ret; |
162 | spu_release(ctx); | ||
163 | return ret; | ||
164 | } | ||
165 | 157 | ||
166 | /** | ||
167 | * spu_acquire_saved - lock spu contex and make sure it is in saved state | ||
168 | * @ctx: spu contex to lock | ||
169 | */ | ||
170 | void spu_acquire_saved(struct spu_context *ctx) | ||
171 | { | ||
172 | spu_acquire(ctx); | ||
173 | if (ctx->state != SPU_STATE_SAVED) { | 158 | if (ctx->state != SPU_STATE_SAVED) { |
174 | set_bit(SPU_SCHED_WAS_ACTIVE, &ctx->sched_flags); | 159 | set_bit(SPU_SCHED_WAS_ACTIVE, &ctx->sched_flags); |
175 | spu_deactivate(ctx); | 160 | spu_deactivate(ctx); |
176 | } | 161 | } |
162 | |||
163 | return 0; | ||
177 | } | 164 | } |
178 | 165 | ||
179 | /** | 166 | /** |
diff --git a/arch/powerpc/platforms/cell/spufs/coredump.c b/arch/powerpc/platforms/cell/spufs/coredump.c index 80f62363e1ce..0c6a96b82b2d 100644 --- a/arch/powerpc/platforms/cell/spufs/coredump.c +++ b/arch/powerpc/platforms/cell/spufs/coredump.c | |||
@@ -148,7 +148,9 @@ int spufs_coredump_extra_notes_size(void) | |||
148 | 148 | ||
149 | fd = 0; | 149 | fd = 0; |
150 | while ((ctx = coredump_next_context(&fd)) != NULL) { | 150 | while ((ctx = coredump_next_context(&fd)) != NULL) { |
151 | spu_acquire_saved(ctx); | 151 | rc = spu_acquire_saved(ctx); |
152 | if (rc) | ||
153 | break; | ||
152 | rc = spufs_ctx_note_size(ctx, fd); | 154 | rc = spufs_ctx_note_size(ctx, fd); |
153 | spu_release_saved(ctx); | 155 | spu_release_saved(ctx); |
154 | if (rc < 0) | 156 | if (rc < 0) |
@@ -224,7 +226,9 @@ int spufs_coredump_extra_notes_write(struct file *file, loff_t *foffset) | |||
224 | 226 | ||
225 | fd = 0; | 227 | fd = 0; |
226 | while ((ctx = coredump_next_context(&fd)) != NULL) { | 228 | while ((ctx = coredump_next_context(&fd)) != NULL) { |
227 | spu_acquire_saved(ctx); | 229 | rc = spu_acquire_saved(ctx); |
230 | if (rc) | ||
231 | return rc; | ||
228 | 232 | ||
229 | for (j = 0; spufs_coredump_read[j].name != NULL; j++) { | 233 | for (j = 0; spufs_coredump_read[j].name != NULL; j++) { |
230 | rc = spufs_arch_write_note(ctx, j, file, fd, foffset); | 234 | rc = spufs_arch_write_note(ctx, j, file, fd, foffset); |
diff --git a/arch/powerpc/platforms/cell/spufs/fault.c b/arch/powerpc/platforms/cell/spufs/fault.c index 917eab4be486..eff4d291ba85 100644 --- a/arch/powerpc/platforms/cell/spufs/fault.c +++ b/arch/powerpc/platforms/cell/spufs/fault.c | |||
@@ -28,117 +28,71 @@ | |||
28 | 28 | ||
29 | #include "spufs.h" | 29 | #include "spufs.h" |
30 | 30 | ||
31 | /* | 31 | /** |
32 | * This ought to be kept in sync with the powerpc specific do_page_fault | 32 | * Handle an SPE event, depending on context SPU_CREATE_EVENTS_ENABLED flag. |
33 | * function. Currently, there are a few corner cases that we haven't had | 33 | * |
34 | * to handle fortunately. | 34 | * If the context was created with events, we just set the return event. |
35 | * Otherwise, send an appropriate signal to the process. | ||
35 | */ | 36 | */ |
36 | static int spu_handle_mm_fault(struct mm_struct *mm, unsigned long ea, | 37 | static void spufs_handle_event(struct spu_context *ctx, |
37 | unsigned long dsisr, unsigned *flt) | 38 | unsigned long ea, int type) |
38 | { | 39 | { |
39 | struct vm_area_struct *vma; | 40 | siginfo_t info; |
40 | unsigned long is_write; | ||
41 | int ret; | ||
42 | 41 | ||
43 | #if 0 | 42 | if (ctx->flags & SPU_CREATE_EVENTS_ENABLED) { |
44 | if (!IS_VALID_EA(ea)) { | 43 | ctx->event_return |= type; |
45 | return -EFAULT; | 44 | wake_up_all(&ctx->stop_wq); |
46 | } | 45 | return; |
47 | #endif /* XXX */ | ||
48 | if (mm == NULL) { | ||
49 | return -EFAULT; | ||
50 | } | ||
51 | if (mm->pgd == NULL) { | ||
52 | return -EFAULT; | ||
53 | } | 46 | } |
54 | 47 | ||
55 | down_read(&mm->mmap_sem); | 48 | memset(&info, 0, sizeof(info)); |
56 | vma = find_vma(mm, ea); | 49 | |
57 | if (!vma) | 50 | switch (type) { |
58 | goto bad_area; | 51 | case SPE_EVENT_INVALID_DMA: |
59 | if (vma->vm_start <= ea) | 52 | info.si_signo = SIGBUS; |
60 | goto good_area; | 53 | info.si_code = BUS_OBJERR; |
61 | if (!(vma->vm_flags & VM_GROWSDOWN)) | 54 | break; |
62 | goto bad_area; | 55 | case SPE_EVENT_SPE_DATA_STORAGE: |
63 | if (expand_stack(vma, ea)) | 56 | info.si_signo = SIGSEGV; |
64 | goto bad_area; | 57 | info.si_addr = (void __user *)ea; |
65 | good_area: | 58 | info.si_code = SEGV_ACCERR; |
66 | is_write = dsisr & MFC_DSISR_ACCESS_PUT; | 59 | ctx->ops->restart_dma(ctx); |
67 | if (is_write) { | 60 | break; |
68 | if (!(vma->vm_flags & VM_WRITE)) | 61 | case SPE_EVENT_DMA_ALIGNMENT: |
69 | goto bad_area; | 62 | info.si_signo = SIGBUS; |
70 | } else { | 63 | /* DAR isn't set for an alignment fault :( */ |
71 | if (dsisr & MFC_DSISR_ACCESS_DENIED) | 64 | info.si_code = BUS_ADRALN; |
72 | goto bad_area; | 65 | break; |
73 | if (!(vma->vm_flags & (VM_READ | VM_EXEC))) | 66 | case SPE_EVENT_SPE_ERROR: |
74 | goto bad_area; | 67 | info.si_signo = SIGILL; |
68 | info.si_addr = (void __user *)(unsigned long) | ||
69 | ctx->ops->npc_read(ctx) - 4; | ||
70 | info.si_code = ILL_ILLOPC; | ||
71 | break; | ||
75 | } | 72 | } |
76 | ret = 0; | ||
77 | *flt = handle_mm_fault(mm, vma, ea, is_write); | ||
78 | if (unlikely(*flt & VM_FAULT_ERROR)) { | ||
79 | if (*flt & VM_FAULT_OOM) { | ||
80 | ret = -ENOMEM; | ||
81 | goto bad_area; | ||
82 | } else if (*flt & VM_FAULT_SIGBUS) { | ||
83 | ret = -EFAULT; | ||
84 | goto bad_area; | ||
85 | } | ||
86 | BUG(); | ||
87 | } | ||
88 | if (*flt & VM_FAULT_MAJOR) | ||
89 | current->maj_flt++; | ||
90 | else | ||
91 | current->min_flt++; | ||
92 | up_read(&mm->mmap_sem); | ||
93 | return ret; | ||
94 | 73 | ||
95 | bad_area: | 74 | if (info.si_signo) |
96 | up_read(&mm->mmap_sem); | 75 | force_sig_info(info.si_signo, &info, current); |
97 | return -EFAULT; | ||
98 | } | 76 | } |
99 | 77 | ||
100 | static void spufs_handle_dma_error(struct spu_context *ctx, | 78 | int spufs_handle_class0(struct spu_context *ctx) |
101 | unsigned long ea, int type) | ||
102 | { | 79 | { |
103 | if (ctx->flags & SPU_CREATE_EVENTS_ENABLED) { | 80 | unsigned long stat = ctx->csa.class_0_pending & CLASS0_INTR_MASK; |
104 | ctx->event_return |= type; | ||
105 | wake_up_all(&ctx->stop_wq); | ||
106 | } else { | ||
107 | siginfo_t info; | ||
108 | memset(&info, 0, sizeof(info)); | ||
109 | |||
110 | switch (type) { | ||
111 | case SPE_EVENT_INVALID_DMA: | ||
112 | info.si_signo = SIGBUS; | ||
113 | info.si_code = BUS_OBJERR; | ||
114 | break; | ||
115 | case SPE_EVENT_SPE_DATA_STORAGE: | ||
116 | info.si_signo = SIGBUS; | ||
117 | info.si_addr = (void __user *)ea; | ||
118 | info.si_code = BUS_ADRERR; | ||
119 | break; | ||
120 | case SPE_EVENT_DMA_ALIGNMENT: | ||
121 | info.si_signo = SIGBUS; | ||
122 | /* DAR isn't set for an alignment fault :( */ | ||
123 | info.si_code = BUS_ADRALN; | ||
124 | break; | ||
125 | case SPE_EVENT_SPE_ERROR: | ||
126 | info.si_signo = SIGILL; | ||
127 | info.si_addr = (void __user *)(unsigned long) | ||
128 | ctx->ops->npc_read(ctx) - 4; | ||
129 | info.si_code = ILL_ILLOPC; | ||
130 | break; | ||
131 | } | ||
132 | if (info.si_signo) | ||
133 | force_sig_info(info.si_signo, &info, current); | ||
134 | } | ||
135 | } | ||
136 | 81 | ||
137 | void spufs_dma_callback(struct spu *spu, int type) | 82 | if (likely(!stat)) |
138 | { | 83 | return 0; |
139 | spufs_handle_dma_error(spu->ctx, spu->dar, type); | 84 | |
85 | if (stat & CLASS0_DMA_ALIGNMENT_INTR) | ||
86 | spufs_handle_event(ctx, ctx->csa.dar, SPE_EVENT_DMA_ALIGNMENT); | ||
87 | |||
88 | if (stat & CLASS0_INVALID_DMA_COMMAND_INTR) | ||
89 | spufs_handle_event(ctx, ctx->csa.dar, SPE_EVENT_INVALID_DMA); | ||
90 | |||
91 | if (stat & CLASS0_SPU_ERROR_INTR) | ||
92 | spufs_handle_event(ctx, ctx->csa.dar, SPE_EVENT_SPE_ERROR); | ||
93 | |||
94 | return -EIO; | ||
140 | } | 95 | } |
141 | EXPORT_SYMBOL_GPL(spufs_dma_callback); | ||
142 | 96 | ||
143 | /* | 97 | /* |
144 | * bottom half handler for page faults, we can't do this from | 98 | * bottom half handler for page faults, we can't do this from |
@@ -154,7 +108,7 @@ int spufs_handle_class1(struct spu_context *ctx) | |||
154 | u64 ea, dsisr, access; | 108 | u64 ea, dsisr, access; |
155 | unsigned long flags; | 109 | unsigned long flags; |
156 | unsigned flt = 0; | 110 | unsigned flt = 0; |
157 | int ret; | 111 | int ret, ret2; |
158 | 112 | ||
159 | /* | 113 | /* |
160 | * dar and dsisr get passed from the registers | 114 | * dar and dsisr get passed from the registers |
@@ -165,16 +119,8 @@ int spufs_handle_class1(struct spu_context *ctx) | |||
165 | * in time, we can still expect to get the same fault | 119 | * in time, we can still expect to get the same fault |
166 | * the immediately after the context restore. | 120 | * the immediately after the context restore. |
167 | */ | 121 | */ |
168 | if (ctx->state == SPU_STATE_RUNNABLE) { | 122 | ea = ctx->csa.dar; |
169 | ea = ctx->spu->dar; | 123 | dsisr = ctx->csa.dsisr; |
170 | dsisr = ctx->spu->dsisr; | ||
171 | ctx->spu->dar= ctx->spu->dsisr = 0; | ||
172 | } else { | ||
173 | ea = ctx->csa.priv1.mfc_dar_RW; | ||
174 | dsisr = ctx->csa.priv1.mfc_dsisr_RW; | ||
175 | ctx->csa.priv1.mfc_dar_RW = 0; | ||
176 | ctx->csa.priv1.mfc_dsisr_RW = 0; | ||
177 | } | ||
178 | 124 | ||
179 | if (!(dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED))) | 125 | if (!(dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED))) |
180 | return 0; | 126 | return 0; |
@@ -201,7 +147,22 @@ int spufs_handle_class1(struct spu_context *ctx) | |||
201 | if (ret) | 147 | if (ret) |
202 | ret = spu_handle_mm_fault(current->mm, ea, dsisr, &flt); | 148 | ret = spu_handle_mm_fault(current->mm, ea, dsisr, &flt); |
203 | 149 | ||
204 | spu_acquire(ctx); | 150 | /* |
151 | * If spu_acquire fails due to a pending signal we just want to return | ||
152 | * EINTR to userspace even if that means missing the dma restart or | ||
153 | * updating the page fault statistics. | ||
154 | */ | ||
155 | ret2 = spu_acquire(ctx); | ||
156 | if (ret2) | ||
157 | goto out; | ||
158 | |||
159 | /* | ||
160 | * Clear dsisr under ctxt lock after handling the fault, so that | ||
161 | * time slicing will not preempt the context while the page fault | ||
162 | * handler is running. Context switch code removes mappings. | ||
163 | */ | ||
164 | ctx->csa.dar = ctx->csa.dsisr = 0; | ||
165 | |||
205 | /* | 166 | /* |
206 | * If we handled the fault successfully and are in runnable | 167 | * If we handled the fault successfully and are in runnable |
207 | * state, restart the DMA. | 168 | * state, restart the DMA. |
@@ -222,9 +183,9 @@ int spufs_handle_class1(struct spu_context *ctx) | |||
222 | if (ctx->spu) | 183 | if (ctx->spu) |
223 | ctx->ops->restart_dma(ctx); | 184 | ctx->ops->restart_dma(ctx); |
224 | } else | 185 | } else |
225 | spufs_handle_dma_error(ctx, ea, SPE_EVENT_SPE_DATA_STORAGE); | 186 | spufs_handle_event(ctx, ea, SPE_EVENT_SPE_DATA_STORAGE); |
226 | 187 | ||
188 | out: | ||
227 | spuctx_switch_state(ctx, SPU_UTIL_SYSTEM); | 189 | spuctx_switch_state(ctx, SPU_UTIL_SYSTEM); |
228 | return ret; | 190 | return ret; |
229 | } | 191 | } |
230 | EXPORT_SYMBOL_GPL(spufs_handle_class1); | ||
diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index d9e56a503795..3fcd06418b01 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c | |||
@@ -40,6 +40,120 @@ | |||
40 | 40 | ||
41 | #define SPUFS_MMAP_4K (PAGE_SIZE == 0x1000) | 41 | #define SPUFS_MMAP_4K (PAGE_SIZE == 0x1000) |
42 | 42 | ||
43 | /* Simple attribute files */ | ||
44 | struct spufs_attr { | ||
45 | int (*get)(void *, u64 *); | ||
46 | int (*set)(void *, u64); | ||
47 | char get_buf[24]; /* enough to store a u64 and "\n\0" */ | ||
48 | char set_buf[24]; | ||
49 | void *data; | ||
50 | const char *fmt; /* format for read operation */ | ||
51 | struct mutex mutex; /* protects access to these buffers */ | ||
52 | }; | ||
53 | |||
54 | static int spufs_attr_open(struct inode *inode, struct file *file, | ||
55 | int (*get)(void *, u64 *), int (*set)(void *, u64), | ||
56 | const char *fmt) | ||
57 | { | ||
58 | struct spufs_attr *attr; | ||
59 | |||
60 | attr = kmalloc(sizeof(*attr), GFP_KERNEL); | ||
61 | if (!attr) | ||
62 | return -ENOMEM; | ||
63 | |||
64 | attr->get = get; | ||
65 | attr->set = set; | ||
66 | attr->data = inode->i_private; | ||
67 | attr->fmt = fmt; | ||
68 | mutex_init(&attr->mutex); | ||
69 | file->private_data = attr; | ||
70 | |||
71 | return nonseekable_open(inode, file); | ||
72 | } | ||
73 | |||
74 | static int spufs_attr_release(struct inode *inode, struct file *file) | ||
75 | { | ||
76 | kfree(file->private_data); | ||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | static ssize_t spufs_attr_read(struct file *file, char __user *buf, | ||
81 | size_t len, loff_t *ppos) | ||
82 | { | ||
83 | struct spufs_attr *attr; | ||
84 | size_t size; | ||
85 | ssize_t ret; | ||
86 | |||
87 | attr = file->private_data; | ||
88 | if (!attr->get) | ||
89 | return -EACCES; | ||
90 | |||
91 | ret = mutex_lock_interruptible(&attr->mutex); | ||
92 | if (ret) | ||
93 | return ret; | ||
94 | |||
95 | if (*ppos) { /* continued read */ | ||
96 | size = strlen(attr->get_buf); | ||
97 | } else { /* first read */ | ||
98 | u64 val; | ||
99 | ret = attr->get(attr->data, &val); | ||
100 | if (ret) | ||
101 | goto out; | ||
102 | |||
103 | size = scnprintf(attr->get_buf, sizeof(attr->get_buf), | ||
104 | attr->fmt, (unsigned long long)val); | ||
105 | } | ||
106 | |||
107 | ret = simple_read_from_buffer(buf, len, ppos, attr->get_buf, size); | ||
108 | out: | ||
109 | mutex_unlock(&attr->mutex); | ||
110 | return ret; | ||
111 | } | ||
112 | |||
113 | static ssize_t spufs_attr_write(struct file *file, const char __user *buf, | ||
114 | size_t len, loff_t *ppos) | ||
115 | { | ||
116 | struct spufs_attr *attr; | ||
117 | u64 val; | ||
118 | size_t size; | ||
119 | ssize_t ret; | ||
120 | |||
121 | attr = file->private_data; | ||
122 | if (!attr->set) | ||
123 | return -EACCES; | ||
124 | |||
125 | ret = mutex_lock_interruptible(&attr->mutex); | ||
126 | if (ret) | ||
127 | return ret; | ||
128 | |||
129 | ret = -EFAULT; | ||
130 | size = min(sizeof(attr->set_buf) - 1, len); | ||
131 | if (copy_from_user(attr->set_buf, buf, size)) | ||
132 | goto out; | ||
133 | |||
134 | ret = len; /* claim we got the whole input */ | ||
135 | attr->set_buf[size] = '\0'; | ||
136 | val = simple_strtol(attr->set_buf, NULL, 0); | ||
137 | attr->set(attr->data, val); | ||
138 | out: | ||
139 | mutex_unlock(&attr->mutex); | ||
140 | return ret; | ||
141 | } | ||
142 | |||
143 | #define DEFINE_SPUFS_SIMPLE_ATTRIBUTE(__fops, __get, __set, __fmt) \ | ||
144 | static int __fops ## _open(struct inode *inode, struct file *file) \ | ||
145 | { \ | ||
146 | __simple_attr_check_format(__fmt, 0ull); \ | ||
147 | return spufs_attr_open(inode, file, __get, __set, __fmt); \ | ||
148 | } \ | ||
149 | static struct file_operations __fops = { \ | ||
150 | .owner = THIS_MODULE, \ | ||
151 | .open = __fops ## _open, \ | ||
152 | .release = spufs_attr_release, \ | ||
153 | .read = spufs_attr_read, \ | ||
154 | .write = spufs_attr_write, \ | ||
155 | }; | ||
156 | |||
43 | 157 | ||
44 | static int | 158 | static int |
45 | spufs_mem_open(struct inode *inode, struct file *file) | 159 | spufs_mem_open(struct inode *inode, struct file *file) |
@@ -84,9 +198,12 @@ spufs_mem_read(struct file *file, char __user *buffer, | |||
84 | struct spu_context *ctx = file->private_data; | 198 | struct spu_context *ctx = file->private_data; |
85 | ssize_t ret; | 199 | ssize_t ret; |
86 | 200 | ||
87 | spu_acquire(ctx); | 201 | ret = spu_acquire(ctx); |
202 | if (ret) | ||
203 | return ret; | ||
88 | ret = __spufs_mem_read(ctx, buffer, size, pos); | 204 | ret = __spufs_mem_read(ctx, buffer, size, pos); |
89 | spu_release(ctx); | 205 | spu_release(ctx); |
206 | |||
90 | return ret; | 207 | return ret; |
91 | } | 208 | } |
92 | 209 | ||
@@ -106,7 +223,10 @@ spufs_mem_write(struct file *file, const char __user *buffer, | |||
106 | if (size > LS_SIZE - pos) | 223 | if (size > LS_SIZE - pos) |
107 | size = LS_SIZE - pos; | 224 | size = LS_SIZE - pos; |
108 | 225 | ||
109 | spu_acquire(ctx); | 226 | ret = spu_acquire(ctx); |
227 | if (ret) | ||
228 | return ret; | ||
229 | |||
110 | local_store = ctx->ops->get_ls(ctx); | 230 | local_store = ctx->ops->get_ls(ctx); |
111 | ret = copy_from_user(local_store + pos, buffer, size); | 231 | ret = copy_from_user(local_store + pos, buffer, size); |
112 | spu_release(ctx); | 232 | spu_release(ctx); |
@@ -146,7 +266,8 @@ static unsigned long spufs_mem_mmap_nopfn(struct vm_area_struct *vma, | |||
146 | pr_debug("spufs_mem_mmap_nopfn address=0x%lx -> 0x%lx, offset=0x%lx\n", | 266 | pr_debug("spufs_mem_mmap_nopfn address=0x%lx -> 0x%lx, offset=0x%lx\n", |
147 | addr0, address, offset); | 267 | addr0, address, offset); |
148 | 268 | ||
149 | spu_acquire(ctx); | 269 | if (spu_acquire(ctx)) |
270 | return NOPFN_REFAULT; | ||
150 | 271 | ||
151 | if (ctx->state == SPU_STATE_SAVED) { | 272 | if (ctx->state == SPU_STATE_SAVED) { |
152 | vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) | 273 | vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) |
@@ -236,23 +357,32 @@ static unsigned long spufs_ps_nopfn(struct vm_area_struct *vma, | |||
236 | { | 357 | { |
237 | struct spu_context *ctx = vma->vm_file->private_data; | 358 | struct spu_context *ctx = vma->vm_file->private_data; |
238 | unsigned long area, offset = address - vma->vm_start; | 359 | unsigned long area, offset = address - vma->vm_start; |
239 | int ret; | ||
240 | 360 | ||
241 | offset += vma->vm_pgoff << PAGE_SHIFT; | 361 | offset += vma->vm_pgoff << PAGE_SHIFT; |
242 | if (offset >= ps_size) | 362 | if (offset >= ps_size) |
243 | return NOPFN_SIGBUS; | 363 | return NOPFN_SIGBUS; |
244 | 364 | ||
245 | /* error here usually means a signal.. we might want to test | 365 | /* |
246 | * the error code more precisely though | 366 | * We have to wait for context to be loaded before we have |
367 | * pages to hand out to the user, but we don't want to wait | ||
368 | * with the mmap_sem held. | ||
369 | * It is possible to drop the mmap_sem here, but then we need | ||
370 | * to return NOPFN_REFAULT because the mappings may have | ||
371 | * hanged. | ||
247 | */ | 372 | */ |
248 | ret = spu_acquire_runnable(ctx, 0); | 373 | if (spu_acquire(ctx)) |
249 | if (ret) | ||
250 | return NOPFN_REFAULT; | 374 | return NOPFN_REFAULT; |
251 | 375 | ||
252 | area = ctx->spu->problem_phys + ps_offs; | 376 | if (ctx->state == SPU_STATE_SAVED) { |
253 | vm_insert_pfn(vma, address, (area + offset) >> PAGE_SHIFT); | 377 | up_read(¤t->mm->mmap_sem); |
254 | spu_release(ctx); | 378 | spufs_wait(ctx->run_wq, ctx->state == SPU_STATE_RUNNABLE); |
379 | down_read(¤t->mm->mmap_sem); | ||
380 | } else { | ||
381 | area = ctx->spu->problem_phys + ps_offs; | ||
382 | vm_insert_pfn(vma, address, (area + offset) >> PAGE_SHIFT); | ||
383 | } | ||
255 | 384 | ||
385 | spu_release(ctx); | ||
256 | return NOPFN_REFAULT; | 386 | return NOPFN_REFAULT; |
257 | } | 387 | } |
258 | 388 | ||
@@ -286,25 +416,32 @@ static int spufs_cntl_mmap(struct file *file, struct vm_area_struct *vma) | |||
286 | #define spufs_cntl_mmap NULL | 416 | #define spufs_cntl_mmap NULL |
287 | #endif /* !SPUFS_MMAP_4K */ | 417 | #endif /* !SPUFS_MMAP_4K */ |
288 | 418 | ||
289 | static u64 spufs_cntl_get(void *data) | 419 | static int spufs_cntl_get(void *data, u64 *val) |
290 | { | 420 | { |
291 | struct spu_context *ctx = data; | 421 | struct spu_context *ctx = data; |
292 | u64 val; | 422 | int ret; |
293 | 423 | ||
294 | spu_acquire(ctx); | 424 | ret = spu_acquire(ctx); |
295 | val = ctx->ops->status_read(ctx); | 425 | if (ret) |
426 | return ret; | ||
427 | *val = ctx->ops->status_read(ctx); | ||
296 | spu_release(ctx); | 428 | spu_release(ctx); |
297 | 429 | ||
298 | return val; | 430 | return 0; |
299 | } | 431 | } |
300 | 432 | ||
301 | static void spufs_cntl_set(void *data, u64 val) | 433 | static int spufs_cntl_set(void *data, u64 val) |
302 | { | 434 | { |
303 | struct spu_context *ctx = data; | 435 | struct spu_context *ctx = data; |
436 | int ret; | ||
304 | 437 | ||
305 | spu_acquire(ctx); | 438 | ret = spu_acquire(ctx); |
439 | if (ret) | ||
440 | return ret; | ||
306 | ctx->ops->runcntl_write(ctx, val); | 441 | ctx->ops->runcntl_write(ctx, val); |
307 | spu_release(ctx); | 442 | spu_release(ctx); |
443 | |||
444 | return 0; | ||
308 | } | 445 | } |
309 | 446 | ||
310 | static int spufs_cntl_open(struct inode *inode, struct file *file) | 447 | static int spufs_cntl_open(struct inode *inode, struct file *file) |
@@ -317,7 +454,7 @@ static int spufs_cntl_open(struct inode *inode, struct file *file) | |||
317 | if (!i->i_openers++) | 454 | if (!i->i_openers++) |
318 | ctx->cntl = inode->i_mapping; | 455 | ctx->cntl = inode->i_mapping; |
319 | mutex_unlock(&ctx->mapping_lock); | 456 | mutex_unlock(&ctx->mapping_lock); |
320 | return simple_attr_open(inode, file, spufs_cntl_get, | 457 | return spufs_attr_open(inode, file, spufs_cntl_get, |
321 | spufs_cntl_set, "0x%08lx"); | 458 | spufs_cntl_set, "0x%08lx"); |
322 | } | 459 | } |
323 | 460 | ||
@@ -327,7 +464,7 @@ spufs_cntl_release(struct inode *inode, struct file *file) | |||
327 | struct spufs_inode_info *i = SPUFS_I(inode); | 464 | struct spufs_inode_info *i = SPUFS_I(inode); |
328 | struct spu_context *ctx = i->i_ctx; | 465 | struct spu_context *ctx = i->i_ctx; |
329 | 466 | ||
330 | simple_attr_close(inode, file); | 467 | spufs_attr_release(inode, file); |
331 | 468 | ||
332 | mutex_lock(&ctx->mapping_lock); | 469 | mutex_lock(&ctx->mapping_lock); |
333 | if (!--i->i_openers) | 470 | if (!--i->i_openers) |
@@ -339,8 +476,8 @@ spufs_cntl_release(struct inode *inode, struct file *file) | |||
339 | static const struct file_operations spufs_cntl_fops = { | 476 | static const struct file_operations spufs_cntl_fops = { |
340 | .open = spufs_cntl_open, | 477 | .open = spufs_cntl_open, |
341 | .release = spufs_cntl_release, | 478 | .release = spufs_cntl_release, |
342 | .read = simple_attr_read, | 479 | .read = spufs_attr_read, |
343 | .write = simple_attr_write, | 480 | .write = spufs_attr_write, |
344 | .mmap = spufs_cntl_mmap, | 481 | .mmap = spufs_cntl_mmap, |
345 | }; | 482 | }; |
346 | 483 | ||
@@ -368,7 +505,9 @@ spufs_regs_read(struct file *file, char __user *buffer, | |||
368 | int ret; | 505 | int ret; |
369 | struct spu_context *ctx = file->private_data; | 506 | struct spu_context *ctx = file->private_data; |
370 | 507 | ||
371 | spu_acquire_saved(ctx); | 508 | ret = spu_acquire_saved(ctx); |
509 | if (ret) | ||
510 | return ret; | ||
372 | ret = __spufs_regs_read(ctx, buffer, size, pos); | 511 | ret = __spufs_regs_read(ctx, buffer, size, pos); |
373 | spu_release_saved(ctx); | 512 | spu_release_saved(ctx); |
374 | return ret; | 513 | return ret; |
@@ -387,7 +526,9 @@ spufs_regs_write(struct file *file, const char __user *buffer, | |||
387 | return -EFBIG; | 526 | return -EFBIG; |
388 | *pos += size; | 527 | *pos += size; |
389 | 528 | ||
390 | spu_acquire_saved(ctx); | 529 | ret = spu_acquire_saved(ctx); |
530 | if (ret) | ||
531 | return ret; | ||
391 | 532 | ||
392 | ret = copy_from_user(lscsa->gprs + *pos - size, | 533 | ret = copy_from_user(lscsa->gprs + *pos - size, |
393 | buffer, size) ? -EFAULT : size; | 534 | buffer, size) ? -EFAULT : size; |
@@ -419,7 +560,9 @@ spufs_fpcr_read(struct file *file, char __user * buffer, | |||
419 | int ret; | 560 | int ret; |
420 | struct spu_context *ctx = file->private_data; | 561 | struct spu_context *ctx = file->private_data; |
421 | 562 | ||
422 | spu_acquire_saved(ctx); | 563 | ret = spu_acquire_saved(ctx); |
564 | if (ret) | ||
565 | return ret; | ||
423 | ret = __spufs_fpcr_read(ctx, buffer, size, pos); | 566 | ret = __spufs_fpcr_read(ctx, buffer, size, pos); |
424 | spu_release_saved(ctx); | 567 | spu_release_saved(ctx); |
425 | return ret; | 568 | return ret; |
@@ -436,10 +579,12 @@ spufs_fpcr_write(struct file *file, const char __user * buffer, | |||
436 | size = min_t(ssize_t, sizeof(lscsa->fpcr) - *pos, size); | 579 | size = min_t(ssize_t, sizeof(lscsa->fpcr) - *pos, size); |
437 | if (size <= 0) | 580 | if (size <= 0) |
438 | return -EFBIG; | 581 | return -EFBIG; |
439 | *pos += size; | ||
440 | 582 | ||
441 | spu_acquire_saved(ctx); | 583 | ret = spu_acquire_saved(ctx); |
584 | if (ret) | ||
585 | return ret; | ||
442 | 586 | ||
587 | *pos += size; | ||
443 | ret = copy_from_user((char *)&lscsa->fpcr + *pos - size, | 588 | ret = copy_from_user((char *)&lscsa->fpcr + *pos - size, |
444 | buffer, size) ? -EFAULT : size; | 589 | buffer, size) ? -EFAULT : size; |
445 | 590 | ||
@@ -486,7 +631,10 @@ static ssize_t spufs_mbox_read(struct file *file, char __user *buf, | |||
486 | 631 | ||
487 | udata = (void __user *)buf; | 632 | udata = (void __user *)buf; |
488 | 633 | ||
489 | spu_acquire(ctx); | 634 | count = spu_acquire(ctx); |
635 | if (count) | ||
636 | return count; | ||
637 | |||
490 | for (count = 0; (count + 4) <= len; count += 4, udata++) { | 638 | for (count = 0; (count + 4) <= len; count += 4, udata++) { |
491 | int ret; | 639 | int ret; |
492 | ret = ctx->ops->mbox_read(ctx, &mbox_data); | 640 | ret = ctx->ops->mbox_read(ctx, &mbox_data); |
@@ -522,12 +670,15 @@ static ssize_t spufs_mbox_stat_read(struct file *file, char __user *buf, | |||
522 | size_t len, loff_t *pos) | 670 | size_t len, loff_t *pos) |
523 | { | 671 | { |
524 | struct spu_context *ctx = file->private_data; | 672 | struct spu_context *ctx = file->private_data; |
673 | ssize_t ret; | ||
525 | u32 mbox_stat; | 674 | u32 mbox_stat; |
526 | 675 | ||
527 | if (len < 4) | 676 | if (len < 4) |
528 | return -EINVAL; | 677 | return -EINVAL; |
529 | 678 | ||
530 | spu_acquire(ctx); | 679 | ret = spu_acquire(ctx); |
680 | if (ret) | ||
681 | return ret; | ||
531 | 682 | ||
532 | mbox_stat = ctx->ops->mbox_stat_read(ctx) & 0xff; | 683 | mbox_stat = ctx->ops->mbox_stat_read(ctx) & 0xff; |
533 | 684 | ||
@@ -562,6 +713,9 @@ void spufs_ibox_callback(struct spu *spu) | |||
562 | { | 713 | { |
563 | struct spu_context *ctx = spu->ctx; | 714 | struct spu_context *ctx = spu->ctx; |
564 | 715 | ||
716 | if (!ctx) | ||
717 | return; | ||
718 | |||
565 | wake_up_all(&ctx->ibox_wq); | 719 | wake_up_all(&ctx->ibox_wq); |
566 | kill_fasync(&ctx->ibox_fasync, SIGIO, POLLIN); | 720 | kill_fasync(&ctx->ibox_fasync, SIGIO, POLLIN); |
567 | } | 721 | } |
@@ -593,7 +747,9 @@ static ssize_t spufs_ibox_read(struct file *file, char __user *buf, | |||
593 | 747 | ||
594 | udata = (void __user *)buf; | 748 | udata = (void __user *)buf; |
595 | 749 | ||
596 | spu_acquire(ctx); | 750 | count = spu_acquire(ctx); |
751 | if (count) | ||
752 | return count; | ||
597 | 753 | ||
598 | /* wait only for the first element */ | 754 | /* wait only for the first element */ |
599 | count = 0; | 755 | count = 0; |
@@ -639,7 +795,11 @@ static unsigned int spufs_ibox_poll(struct file *file, poll_table *wait) | |||
639 | 795 | ||
640 | poll_wait(file, &ctx->ibox_wq, wait); | 796 | poll_wait(file, &ctx->ibox_wq, wait); |
641 | 797 | ||
642 | spu_acquire(ctx); | 798 | /* |
799 | * For now keep this uninterruptible and also ignore the rule | ||
800 | * that poll should not sleep. Will be fixed later. | ||
801 | */ | ||
802 | mutex_lock(&ctx->state_mutex); | ||
643 | mask = ctx->ops->mbox_stat_poll(ctx, POLLIN | POLLRDNORM); | 803 | mask = ctx->ops->mbox_stat_poll(ctx, POLLIN | POLLRDNORM); |
644 | spu_release(ctx); | 804 | spu_release(ctx); |
645 | 805 | ||
@@ -657,12 +817,15 @@ static ssize_t spufs_ibox_stat_read(struct file *file, char __user *buf, | |||
657 | size_t len, loff_t *pos) | 817 | size_t len, loff_t *pos) |
658 | { | 818 | { |
659 | struct spu_context *ctx = file->private_data; | 819 | struct spu_context *ctx = file->private_data; |
820 | ssize_t ret; | ||
660 | u32 ibox_stat; | 821 | u32 ibox_stat; |
661 | 822 | ||
662 | if (len < 4) | 823 | if (len < 4) |
663 | return -EINVAL; | 824 | return -EINVAL; |
664 | 825 | ||
665 | spu_acquire(ctx); | 826 | ret = spu_acquire(ctx); |
827 | if (ret) | ||
828 | return ret; | ||
666 | ibox_stat = (ctx->ops->mbox_stat_read(ctx) >> 16) & 0xff; | 829 | ibox_stat = (ctx->ops->mbox_stat_read(ctx) >> 16) & 0xff; |
667 | spu_release(ctx); | 830 | spu_release(ctx); |
668 | 831 | ||
@@ -698,6 +861,9 @@ void spufs_wbox_callback(struct spu *spu) | |||
698 | { | 861 | { |
699 | struct spu_context *ctx = spu->ctx; | 862 | struct spu_context *ctx = spu->ctx; |
700 | 863 | ||
864 | if (!ctx) | ||
865 | return; | ||
866 | |||
701 | wake_up_all(&ctx->wbox_wq); | 867 | wake_up_all(&ctx->wbox_wq); |
702 | kill_fasync(&ctx->wbox_fasync, SIGIO, POLLOUT); | 868 | kill_fasync(&ctx->wbox_fasync, SIGIO, POLLOUT); |
703 | } | 869 | } |
@@ -731,7 +897,9 @@ static ssize_t spufs_wbox_write(struct file *file, const char __user *buf, | |||
731 | if (__get_user(wbox_data, udata)) | 897 | if (__get_user(wbox_data, udata)) |
732 | return -EFAULT; | 898 | return -EFAULT; |
733 | 899 | ||
734 | spu_acquire(ctx); | 900 | count = spu_acquire(ctx); |
901 | if (count) | ||
902 | return count; | ||
735 | 903 | ||
736 | /* | 904 | /* |
737 | * make sure we can at least write one element, by waiting | 905 | * make sure we can at least write one element, by waiting |
@@ -772,7 +940,11 @@ static unsigned int spufs_wbox_poll(struct file *file, poll_table *wait) | |||
772 | 940 | ||
773 | poll_wait(file, &ctx->wbox_wq, wait); | 941 | poll_wait(file, &ctx->wbox_wq, wait); |
774 | 942 | ||
775 | spu_acquire(ctx); | 943 | /* |
944 | * For now keep this uninterruptible and also ignore the rule | ||
945 | * that poll should not sleep. Will be fixed later. | ||
946 | */ | ||
947 | mutex_lock(&ctx->state_mutex); | ||
776 | mask = ctx->ops->mbox_stat_poll(ctx, POLLOUT | POLLWRNORM); | 948 | mask = ctx->ops->mbox_stat_poll(ctx, POLLOUT | POLLWRNORM); |
777 | spu_release(ctx); | 949 | spu_release(ctx); |
778 | 950 | ||
@@ -790,12 +962,15 @@ static ssize_t spufs_wbox_stat_read(struct file *file, char __user *buf, | |||
790 | size_t len, loff_t *pos) | 962 | size_t len, loff_t *pos) |
791 | { | 963 | { |
792 | struct spu_context *ctx = file->private_data; | 964 | struct spu_context *ctx = file->private_data; |
965 | ssize_t ret; | ||
793 | u32 wbox_stat; | 966 | u32 wbox_stat; |
794 | 967 | ||
795 | if (len < 4) | 968 | if (len < 4) |
796 | return -EINVAL; | 969 | return -EINVAL; |
797 | 970 | ||
798 | spu_acquire(ctx); | 971 | ret = spu_acquire(ctx); |
972 | if (ret) | ||
973 | return ret; | ||
799 | wbox_stat = (ctx->ops->mbox_stat_read(ctx) >> 8) & 0xff; | 974 | wbox_stat = (ctx->ops->mbox_stat_read(ctx) >> 8) & 0xff; |
800 | spu_release(ctx); | 975 | spu_release(ctx); |
801 | 976 | ||
@@ -866,7 +1041,9 @@ static ssize_t spufs_signal1_read(struct file *file, char __user *buf, | |||
866 | int ret; | 1041 | int ret; |
867 | struct spu_context *ctx = file->private_data; | 1042 | struct spu_context *ctx = file->private_data; |
868 | 1043 | ||
869 | spu_acquire_saved(ctx); | 1044 | ret = spu_acquire_saved(ctx); |
1045 | if (ret) | ||
1046 | return ret; | ||
870 | ret = __spufs_signal1_read(ctx, buf, len, pos); | 1047 | ret = __spufs_signal1_read(ctx, buf, len, pos); |
871 | spu_release_saved(ctx); | 1048 | spu_release_saved(ctx); |
872 | 1049 | ||
@@ -877,6 +1054,7 @@ static ssize_t spufs_signal1_write(struct file *file, const char __user *buf, | |||
877 | size_t len, loff_t *pos) | 1054 | size_t len, loff_t *pos) |
878 | { | 1055 | { |
879 | struct spu_context *ctx; | 1056 | struct spu_context *ctx; |
1057 | ssize_t ret; | ||
880 | u32 data; | 1058 | u32 data; |
881 | 1059 | ||
882 | ctx = file->private_data; | 1060 | ctx = file->private_data; |
@@ -887,7 +1065,9 @@ static ssize_t spufs_signal1_write(struct file *file, const char __user *buf, | |||
887 | if (copy_from_user(&data, buf, 4)) | 1065 | if (copy_from_user(&data, buf, 4)) |
888 | return -EFAULT; | 1066 | return -EFAULT; |
889 | 1067 | ||
890 | spu_acquire(ctx); | 1068 | ret = spu_acquire(ctx); |
1069 | if (ret) | ||
1070 | return ret; | ||
891 | ctx->ops->signal1_write(ctx, data); | 1071 | ctx->ops->signal1_write(ctx, data); |
892 | spu_release(ctx); | 1072 | spu_release(ctx); |
893 | 1073 | ||
@@ -997,7 +1177,9 @@ static ssize_t spufs_signal2_read(struct file *file, char __user *buf, | |||
997 | struct spu_context *ctx = file->private_data; | 1177 | struct spu_context *ctx = file->private_data; |
998 | int ret; | 1178 | int ret; |
999 | 1179 | ||
1000 | spu_acquire_saved(ctx); | 1180 | ret = spu_acquire_saved(ctx); |
1181 | if (ret) | ||
1182 | return ret; | ||
1001 | ret = __spufs_signal2_read(ctx, buf, len, pos); | 1183 | ret = __spufs_signal2_read(ctx, buf, len, pos); |
1002 | spu_release_saved(ctx); | 1184 | spu_release_saved(ctx); |
1003 | 1185 | ||
@@ -1008,6 +1190,7 @@ static ssize_t spufs_signal2_write(struct file *file, const char __user *buf, | |||
1008 | size_t len, loff_t *pos) | 1190 | size_t len, loff_t *pos) |
1009 | { | 1191 | { |
1010 | struct spu_context *ctx; | 1192 | struct spu_context *ctx; |
1193 | ssize_t ret; | ||
1011 | u32 data; | 1194 | u32 data; |
1012 | 1195 | ||
1013 | ctx = file->private_data; | 1196 | ctx = file->private_data; |
@@ -1018,7 +1201,9 @@ static ssize_t spufs_signal2_write(struct file *file, const char __user *buf, | |||
1018 | if (copy_from_user(&data, buf, 4)) | 1201 | if (copy_from_user(&data, buf, 4)) |
1019 | return -EFAULT; | 1202 | return -EFAULT; |
1020 | 1203 | ||
1021 | spu_acquire(ctx); | 1204 | ret = spu_acquire(ctx); |
1205 | if (ret) | ||
1206 | return ret; | ||
1022 | ctx->ops->signal2_write(ctx, data); | 1207 | ctx->ops->signal2_write(ctx, data); |
1023 | spu_release(ctx); | 1208 | spu_release(ctx); |
1024 | 1209 | ||
@@ -1086,33 +1271,42 @@ static const struct file_operations spufs_signal2_nosched_fops = { | |||
1086 | #define SPU_ATTR_ACQUIRE_SAVED 2 | 1271 | #define SPU_ATTR_ACQUIRE_SAVED 2 |
1087 | 1272 | ||
1088 | #define DEFINE_SPUFS_ATTRIBUTE(__name, __get, __set, __fmt, __acquire) \ | 1273 | #define DEFINE_SPUFS_ATTRIBUTE(__name, __get, __set, __fmt, __acquire) \ |
1089 | static u64 __##__get(void *data) \ | 1274 | static int __##__get(void *data, u64 *val) \ |
1090 | { \ | 1275 | { \ |
1091 | struct spu_context *ctx = data; \ | 1276 | struct spu_context *ctx = data; \ |
1092 | u64 ret; \ | 1277 | int ret = 0; \ |
1093 | \ | 1278 | \ |
1094 | if (__acquire == SPU_ATTR_ACQUIRE) { \ | 1279 | if (__acquire == SPU_ATTR_ACQUIRE) { \ |
1095 | spu_acquire(ctx); \ | 1280 | ret = spu_acquire(ctx); \ |
1096 | ret = __get(ctx); \ | 1281 | if (ret) \ |
1282 | return ret; \ | ||
1283 | *val = __get(ctx); \ | ||
1097 | spu_release(ctx); \ | 1284 | spu_release(ctx); \ |
1098 | } else if (__acquire == SPU_ATTR_ACQUIRE_SAVED) { \ | 1285 | } else if (__acquire == SPU_ATTR_ACQUIRE_SAVED) { \ |
1099 | spu_acquire_saved(ctx); \ | 1286 | ret = spu_acquire_saved(ctx); \ |
1100 | ret = __get(ctx); \ | 1287 | if (ret) \ |
1288 | return ret; \ | ||
1289 | *val = __get(ctx); \ | ||
1101 | spu_release_saved(ctx); \ | 1290 | spu_release_saved(ctx); \ |
1102 | } else \ | 1291 | } else \ |
1103 | ret = __get(ctx); \ | 1292 | *val = __get(ctx); \ |
1104 | \ | 1293 | \ |
1105 | return ret; \ | 1294 | return 0; \ |
1106 | } \ | 1295 | } \ |
1107 | DEFINE_SIMPLE_ATTRIBUTE(__name, __##__get, __set, __fmt); | 1296 | DEFINE_SPUFS_SIMPLE_ATTRIBUTE(__name, __##__get, __set, __fmt); |
1108 | 1297 | ||
1109 | static void spufs_signal1_type_set(void *data, u64 val) | 1298 | static int spufs_signal1_type_set(void *data, u64 val) |
1110 | { | 1299 | { |
1111 | struct spu_context *ctx = data; | 1300 | struct spu_context *ctx = data; |
1301 | int ret; | ||
1112 | 1302 | ||
1113 | spu_acquire(ctx); | 1303 | ret = spu_acquire(ctx); |
1304 | if (ret) | ||
1305 | return ret; | ||
1114 | ctx->ops->signal1_type_set(ctx, val); | 1306 | ctx->ops->signal1_type_set(ctx, val); |
1115 | spu_release(ctx); | 1307 | spu_release(ctx); |
1308 | |||
1309 | return 0; | ||
1116 | } | 1310 | } |
1117 | 1311 | ||
1118 | static u64 spufs_signal1_type_get(struct spu_context *ctx) | 1312 | static u64 spufs_signal1_type_get(struct spu_context *ctx) |
@@ -1123,13 +1317,18 @@ DEFINE_SPUFS_ATTRIBUTE(spufs_signal1_type, spufs_signal1_type_get, | |||
1123 | spufs_signal1_type_set, "%llu", SPU_ATTR_ACQUIRE); | 1317 | spufs_signal1_type_set, "%llu", SPU_ATTR_ACQUIRE); |
1124 | 1318 | ||
1125 | 1319 | ||
1126 | static void spufs_signal2_type_set(void *data, u64 val) | 1320 | static int spufs_signal2_type_set(void *data, u64 val) |
1127 | { | 1321 | { |
1128 | struct spu_context *ctx = data; | 1322 | struct spu_context *ctx = data; |
1323 | int ret; | ||
1129 | 1324 | ||
1130 | spu_acquire(ctx); | 1325 | ret = spu_acquire(ctx); |
1326 | if (ret) | ||
1327 | return ret; | ||
1131 | ctx->ops->signal2_type_set(ctx, val); | 1328 | ctx->ops->signal2_type_set(ctx, val); |
1132 | spu_release(ctx); | 1329 | spu_release(ctx); |
1330 | |||
1331 | return 0; | ||
1133 | } | 1332 | } |
1134 | 1333 | ||
1135 | static u64 spufs_signal2_type_get(struct spu_context *ctx) | 1334 | static u64 spufs_signal2_type_get(struct spu_context *ctx) |
@@ -1329,6 +1528,9 @@ void spufs_mfc_callback(struct spu *spu) | |||
1329 | { | 1528 | { |
1330 | struct spu_context *ctx = spu->ctx; | 1529 | struct spu_context *ctx = spu->ctx; |
1331 | 1530 | ||
1531 | if (!ctx) | ||
1532 | return; | ||
1533 | |||
1332 | wake_up_all(&ctx->mfc_wq); | 1534 | wake_up_all(&ctx->mfc_wq); |
1333 | 1535 | ||
1334 | pr_debug("%s %s\n", __FUNCTION__, spu->name); | 1536 | pr_debug("%s %s\n", __FUNCTION__, spu->name); |
@@ -1375,12 +1577,17 @@ static ssize_t spufs_mfc_read(struct file *file, char __user *buffer, | |||
1375 | if (size != 4) | 1577 | if (size != 4) |
1376 | goto out; | 1578 | goto out; |
1377 | 1579 | ||
1378 | spu_acquire(ctx); | 1580 | ret = spu_acquire(ctx); |
1581 | if (ret) | ||
1582 | return ret; | ||
1583 | |||
1584 | ret = -EINVAL; | ||
1379 | if (file->f_flags & O_NONBLOCK) { | 1585 | if (file->f_flags & O_NONBLOCK) { |
1380 | status = ctx->ops->read_mfc_tagstatus(ctx); | 1586 | status = ctx->ops->read_mfc_tagstatus(ctx); |
1381 | if (!(status & ctx->tagwait)) | 1587 | if (!(status & ctx->tagwait)) |
1382 | ret = -EAGAIN; | 1588 | ret = -EAGAIN; |
1383 | else | 1589 | else |
1590 | /* XXX(hch): shouldn't we clear ret here? */ | ||
1384 | ctx->tagwait &= ~status; | 1591 | ctx->tagwait &= ~status; |
1385 | } else { | 1592 | } else { |
1386 | ret = spufs_wait(ctx->mfc_wq, | 1593 | ret = spufs_wait(ctx->mfc_wq, |
@@ -1505,7 +1712,11 @@ static ssize_t spufs_mfc_write(struct file *file, const char __user *buffer, | |||
1505 | if (ret) | 1712 | if (ret) |
1506 | goto out; | 1713 | goto out; |
1507 | 1714 | ||
1508 | ret = spu_acquire_runnable(ctx, 0); | 1715 | ret = spu_acquire(ctx); |
1716 | if (ret) | ||
1717 | goto out; | ||
1718 | |||
1719 | ret = spufs_wait(ctx->run_wq, ctx->state == SPU_STATE_RUNNABLE); | ||
1509 | if (ret) | 1720 | if (ret) |
1510 | goto out; | 1721 | goto out; |
1511 | 1722 | ||
@@ -1539,7 +1750,11 @@ static unsigned int spufs_mfc_poll(struct file *file,poll_table *wait) | |||
1539 | 1750 | ||
1540 | poll_wait(file, &ctx->mfc_wq, wait); | 1751 | poll_wait(file, &ctx->mfc_wq, wait); |
1541 | 1752 | ||
1542 | spu_acquire(ctx); | 1753 | /* |
1754 | * For now keep this uninterruptible and also ignore the rule | ||
1755 | * that poll should not sleep. Will be fixed later. | ||
1756 | */ | ||
1757 | mutex_lock(&ctx->state_mutex); | ||
1543 | ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2); | 1758 | ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2); |
1544 | free_elements = ctx->ops->get_mfc_free_elements(ctx); | 1759 | free_elements = ctx->ops->get_mfc_free_elements(ctx); |
1545 | tagstatus = ctx->ops->read_mfc_tagstatus(ctx); | 1760 | tagstatus = ctx->ops->read_mfc_tagstatus(ctx); |
@@ -1562,7 +1777,9 @@ static int spufs_mfc_flush(struct file *file, fl_owner_t id) | |||
1562 | struct spu_context *ctx = file->private_data; | 1777 | struct spu_context *ctx = file->private_data; |
1563 | int ret; | 1778 | int ret; |
1564 | 1779 | ||
1565 | spu_acquire(ctx); | 1780 | ret = spu_acquire(ctx); |
1781 | if (ret) | ||
1782 | return ret; | ||
1566 | #if 0 | 1783 | #if 0 |
1567 | /* this currently hangs */ | 1784 | /* this currently hangs */ |
1568 | ret = spufs_wait(ctx->mfc_wq, | 1785 | ret = spufs_wait(ctx->mfc_wq, |
@@ -1605,12 +1822,18 @@ static const struct file_operations spufs_mfc_fops = { | |||
1605 | .mmap = spufs_mfc_mmap, | 1822 | .mmap = spufs_mfc_mmap, |
1606 | }; | 1823 | }; |
1607 | 1824 | ||
1608 | static void spufs_npc_set(void *data, u64 val) | 1825 | static int spufs_npc_set(void *data, u64 val) |
1609 | { | 1826 | { |
1610 | struct spu_context *ctx = data; | 1827 | struct spu_context *ctx = data; |
1611 | spu_acquire(ctx); | 1828 | int ret; |
1829 | |||
1830 | ret = spu_acquire(ctx); | ||
1831 | if (ret) | ||
1832 | return ret; | ||
1612 | ctx->ops->npc_write(ctx, val); | 1833 | ctx->ops->npc_write(ctx, val); |
1613 | spu_release(ctx); | 1834 | spu_release(ctx); |
1835 | |||
1836 | return 0; | ||
1614 | } | 1837 | } |
1615 | 1838 | ||
1616 | static u64 spufs_npc_get(struct spu_context *ctx) | 1839 | static u64 spufs_npc_get(struct spu_context *ctx) |
@@ -1620,13 +1843,19 @@ static u64 spufs_npc_get(struct spu_context *ctx) | |||
1620 | DEFINE_SPUFS_ATTRIBUTE(spufs_npc_ops, spufs_npc_get, spufs_npc_set, | 1843 | DEFINE_SPUFS_ATTRIBUTE(spufs_npc_ops, spufs_npc_get, spufs_npc_set, |
1621 | "0x%llx\n", SPU_ATTR_ACQUIRE); | 1844 | "0x%llx\n", SPU_ATTR_ACQUIRE); |
1622 | 1845 | ||
1623 | static void spufs_decr_set(void *data, u64 val) | 1846 | static int spufs_decr_set(void *data, u64 val) |
1624 | { | 1847 | { |
1625 | struct spu_context *ctx = data; | 1848 | struct spu_context *ctx = data; |
1626 | struct spu_lscsa *lscsa = ctx->csa.lscsa; | 1849 | struct spu_lscsa *lscsa = ctx->csa.lscsa; |
1627 | spu_acquire_saved(ctx); | 1850 | int ret; |
1851 | |||
1852 | ret = spu_acquire_saved(ctx); | ||
1853 | if (ret) | ||
1854 | return ret; | ||
1628 | lscsa->decr.slot[0] = (u32) val; | 1855 | lscsa->decr.slot[0] = (u32) val; |
1629 | spu_release_saved(ctx); | 1856 | spu_release_saved(ctx); |
1857 | |||
1858 | return 0; | ||
1630 | } | 1859 | } |
1631 | 1860 | ||
1632 | static u64 spufs_decr_get(struct spu_context *ctx) | 1861 | static u64 spufs_decr_get(struct spu_context *ctx) |
@@ -1637,15 +1866,21 @@ static u64 spufs_decr_get(struct spu_context *ctx) | |||
1637 | DEFINE_SPUFS_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set, | 1866 | DEFINE_SPUFS_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set, |
1638 | "0x%llx\n", SPU_ATTR_ACQUIRE_SAVED); | 1867 | "0x%llx\n", SPU_ATTR_ACQUIRE_SAVED); |
1639 | 1868 | ||
1640 | static void spufs_decr_status_set(void *data, u64 val) | 1869 | static int spufs_decr_status_set(void *data, u64 val) |
1641 | { | 1870 | { |
1642 | struct spu_context *ctx = data; | 1871 | struct spu_context *ctx = data; |
1643 | spu_acquire_saved(ctx); | 1872 | int ret; |
1873 | |||
1874 | ret = spu_acquire_saved(ctx); | ||
1875 | if (ret) | ||
1876 | return ret; | ||
1644 | if (val) | 1877 | if (val) |
1645 | ctx->csa.priv2.mfc_control_RW |= MFC_CNTL_DECREMENTER_RUNNING; | 1878 | ctx->csa.priv2.mfc_control_RW |= MFC_CNTL_DECREMENTER_RUNNING; |
1646 | else | 1879 | else |
1647 | ctx->csa.priv2.mfc_control_RW &= ~MFC_CNTL_DECREMENTER_RUNNING; | 1880 | ctx->csa.priv2.mfc_control_RW &= ~MFC_CNTL_DECREMENTER_RUNNING; |
1648 | spu_release_saved(ctx); | 1881 | spu_release_saved(ctx); |
1882 | |||
1883 | return 0; | ||
1649 | } | 1884 | } |
1650 | 1885 | ||
1651 | static u64 spufs_decr_status_get(struct spu_context *ctx) | 1886 | static u64 spufs_decr_status_get(struct spu_context *ctx) |
@@ -1659,13 +1894,19 @@ DEFINE_SPUFS_ATTRIBUTE(spufs_decr_status_ops, spufs_decr_status_get, | |||
1659 | spufs_decr_status_set, "0x%llx\n", | 1894 | spufs_decr_status_set, "0x%llx\n", |
1660 | SPU_ATTR_ACQUIRE_SAVED); | 1895 | SPU_ATTR_ACQUIRE_SAVED); |
1661 | 1896 | ||
1662 | static void spufs_event_mask_set(void *data, u64 val) | 1897 | static int spufs_event_mask_set(void *data, u64 val) |
1663 | { | 1898 | { |
1664 | struct spu_context *ctx = data; | 1899 | struct spu_context *ctx = data; |
1665 | struct spu_lscsa *lscsa = ctx->csa.lscsa; | 1900 | struct spu_lscsa *lscsa = ctx->csa.lscsa; |
1666 | spu_acquire_saved(ctx); | 1901 | int ret; |
1902 | |||
1903 | ret = spu_acquire_saved(ctx); | ||
1904 | if (ret) | ||
1905 | return ret; | ||
1667 | lscsa->event_mask.slot[0] = (u32) val; | 1906 | lscsa->event_mask.slot[0] = (u32) val; |
1668 | spu_release_saved(ctx); | 1907 | spu_release_saved(ctx); |
1908 | |||
1909 | return 0; | ||
1669 | } | 1910 | } |
1670 | 1911 | ||
1671 | static u64 spufs_event_mask_get(struct spu_context *ctx) | 1912 | static u64 spufs_event_mask_get(struct spu_context *ctx) |
@@ -1690,13 +1931,19 @@ static u64 spufs_event_status_get(struct spu_context *ctx) | |||
1690 | DEFINE_SPUFS_ATTRIBUTE(spufs_event_status_ops, spufs_event_status_get, | 1931 | DEFINE_SPUFS_ATTRIBUTE(spufs_event_status_ops, spufs_event_status_get, |
1691 | NULL, "0x%llx\n", SPU_ATTR_ACQUIRE_SAVED) | 1932 | NULL, "0x%llx\n", SPU_ATTR_ACQUIRE_SAVED) |
1692 | 1933 | ||
1693 | static void spufs_srr0_set(void *data, u64 val) | 1934 | static int spufs_srr0_set(void *data, u64 val) |
1694 | { | 1935 | { |
1695 | struct spu_context *ctx = data; | 1936 | struct spu_context *ctx = data; |
1696 | struct spu_lscsa *lscsa = ctx->csa.lscsa; | 1937 | struct spu_lscsa *lscsa = ctx->csa.lscsa; |
1697 | spu_acquire_saved(ctx); | 1938 | int ret; |
1939 | |||
1940 | ret = spu_acquire_saved(ctx); | ||
1941 | if (ret) | ||
1942 | return ret; | ||
1698 | lscsa->srr0.slot[0] = (u32) val; | 1943 | lscsa->srr0.slot[0] = (u32) val; |
1699 | spu_release_saved(ctx); | 1944 | spu_release_saved(ctx); |
1945 | |||
1946 | return 0; | ||
1700 | } | 1947 | } |
1701 | 1948 | ||
1702 | static u64 spufs_srr0_get(struct spu_context *ctx) | 1949 | static u64 spufs_srr0_get(struct spu_context *ctx) |
@@ -1727,10 +1974,12 @@ static u64 spufs_object_id_get(struct spu_context *ctx) | |||
1727 | return ctx->object_id; | 1974 | return ctx->object_id; |
1728 | } | 1975 | } |
1729 | 1976 | ||
1730 | static void spufs_object_id_set(void *data, u64 id) | 1977 | static int spufs_object_id_set(void *data, u64 id) |
1731 | { | 1978 | { |
1732 | struct spu_context *ctx = data; | 1979 | struct spu_context *ctx = data; |
1733 | ctx->object_id = id; | 1980 | ctx->object_id = id; |
1981 | |||
1982 | return 0; | ||
1734 | } | 1983 | } |
1735 | 1984 | ||
1736 | DEFINE_SPUFS_ATTRIBUTE(spufs_object_id_ops, spufs_object_id_get, | 1985 | DEFINE_SPUFS_ATTRIBUTE(spufs_object_id_ops, spufs_object_id_get, |
@@ -1777,13 +2026,13 @@ static const struct file_operations spufs_caps_fops = { | |||
1777 | static ssize_t __spufs_mbox_info_read(struct spu_context *ctx, | 2026 | static ssize_t __spufs_mbox_info_read(struct spu_context *ctx, |
1778 | char __user *buf, size_t len, loff_t *pos) | 2027 | char __user *buf, size_t len, loff_t *pos) |
1779 | { | 2028 | { |
1780 | u32 mbox_stat; | ||
1781 | u32 data; | 2029 | u32 data; |
1782 | 2030 | ||
1783 | mbox_stat = ctx->csa.prob.mb_stat_R; | 2031 | /* EOF if there's no entry in the mbox */ |
1784 | if (mbox_stat & 0x0000ff) { | 2032 | if (!(ctx->csa.prob.mb_stat_R & 0x0000ff)) |
1785 | data = ctx->csa.prob.pu_mb_R; | 2033 | return 0; |
1786 | } | 2034 | |
2035 | data = ctx->csa.prob.pu_mb_R; | ||
1787 | 2036 | ||
1788 | return simple_read_from_buffer(buf, len, pos, &data, sizeof data); | 2037 | return simple_read_from_buffer(buf, len, pos, &data, sizeof data); |
1789 | } | 2038 | } |
@@ -1797,7 +2046,9 @@ static ssize_t spufs_mbox_info_read(struct file *file, char __user *buf, | |||
1797 | if (!access_ok(VERIFY_WRITE, buf, len)) | 2046 | if (!access_ok(VERIFY_WRITE, buf, len)) |
1798 | return -EFAULT; | 2047 | return -EFAULT; |
1799 | 2048 | ||
1800 | spu_acquire_saved(ctx); | 2049 | ret = spu_acquire_saved(ctx); |
2050 | if (ret) | ||
2051 | return ret; | ||
1801 | spin_lock(&ctx->csa.register_lock); | 2052 | spin_lock(&ctx->csa.register_lock); |
1802 | ret = __spufs_mbox_info_read(ctx, buf, len, pos); | 2053 | ret = __spufs_mbox_info_read(ctx, buf, len, pos); |
1803 | spin_unlock(&ctx->csa.register_lock); | 2054 | spin_unlock(&ctx->csa.register_lock); |
@@ -1815,13 +2066,13 @@ static const struct file_operations spufs_mbox_info_fops = { | |||
1815 | static ssize_t __spufs_ibox_info_read(struct spu_context *ctx, | 2066 | static ssize_t __spufs_ibox_info_read(struct spu_context *ctx, |
1816 | char __user *buf, size_t len, loff_t *pos) | 2067 | char __user *buf, size_t len, loff_t *pos) |
1817 | { | 2068 | { |
1818 | u32 ibox_stat; | ||
1819 | u32 data; | 2069 | u32 data; |
1820 | 2070 | ||
1821 | ibox_stat = ctx->csa.prob.mb_stat_R; | 2071 | /* EOF if there's no entry in the ibox */ |
1822 | if (ibox_stat & 0xff0000) { | 2072 | if (!(ctx->csa.prob.mb_stat_R & 0xff0000)) |
1823 | data = ctx->csa.priv2.puint_mb_R; | 2073 | return 0; |
1824 | } | 2074 | |
2075 | data = ctx->csa.priv2.puint_mb_R; | ||
1825 | 2076 | ||
1826 | return simple_read_from_buffer(buf, len, pos, &data, sizeof data); | 2077 | return simple_read_from_buffer(buf, len, pos, &data, sizeof data); |
1827 | } | 2078 | } |
@@ -1835,7 +2086,9 @@ static ssize_t spufs_ibox_info_read(struct file *file, char __user *buf, | |||
1835 | if (!access_ok(VERIFY_WRITE, buf, len)) | 2086 | if (!access_ok(VERIFY_WRITE, buf, len)) |
1836 | return -EFAULT; | 2087 | return -EFAULT; |
1837 | 2088 | ||
1838 | spu_acquire_saved(ctx); | 2089 | ret = spu_acquire_saved(ctx); |
2090 | if (ret) | ||
2091 | return ret; | ||
1839 | spin_lock(&ctx->csa.register_lock); | 2092 | spin_lock(&ctx->csa.register_lock); |
1840 | ret = __spufs_ibox_info_read(ctx, buf, len, pos); | 2093 | ret = __spufs_ibox_info_read(ctx, buf, len, pos); |
1841 | spin_unlock(&ctx->csa.register_lock); | 2094 | spin_unlock(&ctx->csa.register_lock); |
@@ -1876,7 +2129,9 @@ static ssize_t spufs_wbox_info_read(struct file *file, char __user *buf, | |||
1876 | if (!access_ok(VERIFY_WRITE, buf, len)) | 2129 | if (!access_ok(VERIFY_WRITE, buf, len)) |
1877 | return -EFAULT; | 2130 | return -EFAULT; |
1878 | 2131 | ||
1879 | spu_acquire_saved(ctx); | 2132 | ret = spu_acquire_saved(ctx); |
2133 | if (ret) | ||
2134 | return ret; | ||
1880 | spin_lock(&ctx->csa.register_lock); | 2135 | spin_lock(&ctx->csa.register_lock); |
1881 | ret = __spufs_wbox_info_read(ctx, buf, len, pos); | 2136 | ret = __spufs_wbox_info_read(ctx, buf, len, pos); |
1882 | spin_unlock(&ctx->csa.register_lock); | 2137 | spin_unlock(&ctx->csa.register_lock); |
@@ -1926,7 +2181,9 @@ static ssize_t spufs_dma_info_read(struct file *file, char __user *buf, | |||
1926 | if (!access_ok(VERIFY_WRITE, buf, len)) | 2181 | if (!access_ok(VERIFY_WRITE, buf, len)) |
1927 | return -EFAULT; | 2182 | return -EFAULT; |
1928 | 2183 | ||
1929 | spu_acquire_saved(ctx); | 2184 | ret = spu_acquire_saved(ctx); |
2185 | if (ret) | ||
2186 | return ret; | ||
1930 | spin_lock(&ctx->csa.register_lock); | 2187 | spin_lock(&ctx->csa.register_lock); |
1931 | ret = __spufs_dma_info_read(ctx, buf, len, pos); | 2188 | ret = __spufs_dma_info_read(ctx, buf, len, pos); |
1932 | spin_unlock(&ctx->csa.register_lock); | 2189 | spin_unlock(&ctx->csa.register_lock); |
@@ -1977,7 +2234,9 @@ static ssize_t spufs_proxydma_info_read(struct file *file, char __user *buf, | |||
1977 | struct spu_context *ctx = file->private_data; | 2234 | struct spu_context *ctx = file->private_data; |
1978 | int ret; | 2235 | int ret; |
1979 | 2236 | ||
1980 | spu_acquire_saved(ctx); | 2237 | ret = spu_acquire_saved(ctx); |
2238 | if (ret) | ||
2239 | return ret; | ||
1981 | spin_lock(&ctx->csa.register_lock); | 2240 | spin_lock(&ctx->csa.register_lock); |
1982 | ret = __spufs_proxydma_info_read(ctx, buf, len, pos); | 2241 | ret = __spufs_proxydma_info_read(ctx, buf, len, pos); |
1983 | spin_unlock(&ctx->csa.register_lock); | 2242 | spin_unlock(&ctx->csa.register_lock); |
@@ -2066,8 +2325,12 @@ static unsigned long long spufs_class2_intrs(struct spu_context *ctx) | |||
2066 | static int spufs_show_stat(struct seq_file *s, void *private) | 2325 | static int spufs_show_stat(struct seq_file *s, void *private) |
2067 | { | 2326 | { |
2068 | struct spu_context *ctx = s->private; | 2327 | struct spu_context *ctx = s->private; |
2328 | int ret; | ||
2329 | |||
2330 | ret = spu_acquire(ctx); | ||
2331 | if (ret) | ||
2332 | return ret; | ||
2069 | 2333 | ||
2070 | spu_acquire(ctx); | ||
2071 | seq_printf(s, "%s %llu %llu %llu %llu " | 2334 | seq_printf(s, "%s %llu %llu %llu %llu " |
2072 | "%llu %llu %llu %llu %llu %llu %llu %llu\n", | 2335 | "%llu %llu %llu %llu %llu %llu %llu %llu\n", |
2073 | ctx_state_names[ctx->stats.util_state], | 2336 | ctx_state_names[ctx->stats.util_state], |
diff --git a/arch/powerpc/platforms/cell/spufs/hw_ops.c b/arch/powerpc/platforms/cell/spufs/hw_ops.c index fc4ed1ffbd4f..64f8540b832c 100644 --- a/arch/powerpc/platforms/cell/spufs/hw_ops.c +++ b/arch/powerpc/platforms/cell/spufs/hw_ops.c | |||
@@ -76,16 +76,18 @@ static unsigned int spu_hw_mbox_stat_poll(struct spu_context *ctx, | |||
76 | if (stat & 0xff0000) | 76 | if (stat & 0xff0000) |
77 | ret |= POLLIN | POLLRDNORM; | 77 | ret |= POLLIN | POLLRDNORM; |
78 | else { | 78 | else { |
79 | spu_int_stat_clear(spu, 2, 0x1); | 79 | spu_int_stat_clear(spu, 2, CLASS2_MAILBOX_INTR); |
80 | spu_int_mask_or(spu, 2, 0x1); | 80 | spu_int_mask_or(spu, 2, CLASS2_ENABLE_MAILBOX_INTR); |
81 | } | 81 | } |
82 | } | 82 | } |
83 | if (events & (POLLOUT | POLLWRNORM)) { | 83 | if (events & (POLLOUT | POLLWRNORM)) { |
84 | if (stat & 0x00ff00) | 84 | if (stat & 0x00ff00) |
85 | ret = POLLOUT | POLLWRNORM; | 85 | ret = POLLOUT | POLLWRNORM; |
86 | else { | 86 | else { |
87 | spu_int_stat_clear(spu, 2, 0x10); | 87 | spu_int_stat_clear(spu, 2, |
88 | spu_int_mask_or(spu, 2, 0x10); | 88 | CLASS2_MAILBOX_THRESHOLD_INTR); |
89 | spu_int_mask_or(spu, 2, | ||
90 | CLASS2_ENABLE_MAILBOX_THRESHOLD_INTR); | ||
89 | } | 91 | } |
90 | } | 92 | } |
91 | spin_unlock_irq(&spu->register_lock); | 93 | spin_unlock_irq(&spu->register_lock); |
@@ -106,7 +108,7 @@ static int spu_hw_ibox_read(struct spu_context *ctx, u32 * data) | |||
106 | ret = 4; | 108 | ret = 4; |
107 | } else { | 109 | } else { |
108 | /* make sure we get woken up by the interrupt */ | 110 | /* make sure we get woken up by the interrupt */ |
109 | spu_int_mask_or(spu, 2, 0x1); | 111 | spu_int_mask_or(spu, 2, CLASS2_ENABLE_MAILBOX_INTR); |
110 | ret = 0; | 112 | ret = 0; |
111 | } | 113 | } |
112 | spin_unlock_irq(&spu->register_lock); | 114 | spin_unlock_irq(&spu->register_lock); |
@@ -127,7 +129,7 @@ static int spu_hw_wbox_write(struct spu_context *ctx, u32 data) | |||
127 | } else { | 129 | } else { |
128 | /* make sure we get woken up by the interrupt when space | 130 | /* make sure we get woken up by the interrupt when space |
129 | becomes available */ | 131 | becomes available */ |
130 | spu_int_mask_or(spu, 2, 0x10); | 132 | spu_int_mask_or(spu, 2, CLASS2_ENABLE_MAILBOX_THRESHOLD_INTR); |
131 | ret = 0; | 133 | ret = 0; |
132 | } | 134 | } |
133 | spin_unlock_irq(&spu->register_lock); | 135 | spin_unlock_irq(&spu->register_lock); |
@@ -206,6 +208,11 @@ static char *spu_hw_get_ls(struct spu_context *ctx) | |||
206 | return ctx->spu->local_store; | 208 | return ctx->spu->local_store; |
207 | } | 209 | } |
208 | 210 | ||
211 | static void spu_hw_privcntl_write(struct spu_context *ctx, u64 val) | ||
212 | { | ||
213 | out_be64(&ctx->spu->priv2->spu_privcntl_RW, val); | ||
214 | } | ||
215 | |||
209 | static u32 spu_hw_runcntl_read(struct spu_context *ctx) | 216 | static u32 spu_hw_runcntl_read(struct spu_context *ctx) |
210 | { | 217 | { |
211 | return in_be32(&ctx->spu->problem->spu_runcntl_RW); | 218 | return in_be32(&ctx->spu->problem->spu_runcntl_RW); |
@@ -215,11 +222,21 @@ static void spu_hw_runcntl_write(struct spu_context *ctx, u32 val) | |||
215 | { | 222 | { |
216 | spin_lock_irq(&ctx->spu->register_lock); | 223 | spin_lock_irq(&ctx->spu->register_lock); |
217 | if (val & SPU_RUNCNTL_ISOLATE) | 224 | if (val & SPU_RUNCNTL_ISOLATE) |
218 | out_be64(&ctx->spu->priv2->spu_privcntl_RW, 4LL); | 225 | spu_hw_privcntl_write(ctx, |
226 | SPU_PRIVCNT_LOAD_REQUEST_ENABLE_MASK); | ||
219 | out_be32(&ctx->spu->problem->spu_runcntl_RW, val); | 227 | out_be32(&ctx->spu->problem->spu_runcntl_RW, val); |
220 | spin_unlock_irq(&ctx->spu->register_lock); | 228 | spin_unlock_irq(&ctx->spu->register_lock); |
221 | } | 229 | } |
222 | 230 | ||
231 | static void spu_hw_runcntl_stop(struct spu_context *ctx) | ||
232 | { | ||
233 | spin_lock_irq(&ctx->spu->register_lock); | ||
234 | out_be32(&ctx->spu->problem->spu_runcntl_RW, SPU_RUNCNTL_STOP); | ||
235 | while (in_be32(&ctx->spu->problem->spu_status_R) & SPU_STATUS_RUNNING) | ||
236 | cpu_relax(); | ||
237 | spin_unlock_irq(&ctx->spu->register_lock); | ||
238 | } | ||
239 | |||
223 | static void spu_hw_master_start(struct spu_context *ctx) | 240 | static void spu_hw_master_start(struct spu_context *ctx) |
224 | { | 241 | { |
225 | struct spu *spu = ctx->spu; | 242 | struct spu *spu = ctx->spu; |
@@ -319,8 +336,10 @@ struct spu_context_ops spu_hw_ops = { | |||
319 | .npc_write = spu_hw_npc_write, | 336 | .npc_write = spu_hw_npc_write, |
320 | .status_read = spu_hw_status_read, | 337 | .status_read = spu_hw_status_read, |
321 | .get_ls = spu_hw_get_ls, | 338 | .get_ls = spu_hw_get_ls, |
339 | .privcntl_write = spu_hw_privcntl_write, | ||
322 | .runcntl_read = spu_hw_runcntl_read, | 340 | .runcntl_read = spu_hw_runcntl_read, |
323 | .runcntl_write = spu_hw_runcntl_write, | 341 | .runcntl_write = spu_hw_runcntl_write, |
342 | .runcntl_stop = spu_hw_runcntl_stop, | ||
324 | .master_start = spu_hw_master_start, | 343 | .master_start = spu_hw_master_start, |
325 | .master_stop = spu_hw_master_stop, | 344 | .master_stop = spu_hw_master_stop, |
326 | .set_mfc_query = spu_hw_set_mfc_query, | 345 | .set_mfc_query = spu_hw_set_mfc_query, |
diff --git a/arch/powerpc/platforms/cell/spufs/lscsa_alloc.c b/arch/powerpc/platforms/cell/spufs/lscsa_alloc.c index f4b3c052dabf..0e9f325c9ff7 100644 --- a/arch/powerpc/platforms/cell/spufs/lscsa_alloc.c +++ b/arch/powerpc/platforms/cell/spufs/lscsa_alloc.c | |||
@@ -28,6 +28,8 @@ | |||
28 | #include <asm/spu_csa.h> | 28 | #include <asm/spu_csa.h> |
29 | #include <asm/mmu.h> | 29 | #include <asm/mmu.h> |
30 | 30 | ||
31 | #include "spufs.h" | ||
32 | |||
31 | static int spu_alloc_lscsa_std(struct spu_state *csa) | 33 | static int spu_alloc_lscsa_std(struct spu_state *csa) |
32 | { | 34 | { |
33 | struct spu_lscsa *lscsa; | 35 | struct spu_lscsa *lscsa; |
@@ -73,7 +75,7 @@ int spu_alloc_lscsa(struct spu_state *csa) | |||
73 | int i, j, n_4k; | 75 | int i, j, n_4k; |
74 | 76 | ||
75 | /* Check availability of 64K pages */ | 77 | /* Check availability of 64K pages */ |
76 | if (mmu_psize_defs[MMU_PAGE_64K].shift == 0) | 78 | if (!spu_64k_pages_available()) |
77 | goto fail; | 79 | goto fail; |
78 | 80 | ||
79 | csa->use_big_pages = 1; | 81 | csa->use_big_pages = 1; |
diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c index 1ce5e22ea5f4..c01a09da1e56 100644 --- a/arch/powerpc/platforms/cell/spufs/run.c +++ b/arch/powerpc/platforms/cell/spufs/run.c | |||
@@ -15,24 +15,55 @@ void spufs_stop_callback(struct spu *spu) | |||
15 | { | 15 | { |
16 | struct spu_context *ctx = spu->ctx; | 16 | struct spu_context *ctx = spu->ctx; |
17 | 17 | ||
18 | wake_up_all(&ctx->stop_wq); | 18 | /* |
19 | * It should be impossible to preempt a context while an exception | ||
20 | * is being processed, since the context switch code is specially | ||
21 | * coded to deal with interrupts ... But, just in case, sanity check | ||
22 | * the context pointer. It is OK to return doing nothing since | ||
23 | * the exception will be regenerated when the context is resumed. | ||
24 | */ | ||
25 | if (ctx) { | ||
26 | /* Copy exception arguments into module specific structure */ | ||
27 | ctx->csa.class_0_pending = spu->class_0_pending; | ||
28 | ctx->csa.dsisr = spu->dsisr; | ||
29 | ctx->csa.dar = spu->dar; | ||
30 | |||
31 | /* ensure that the exception status has hit memory before a | ||
32 | * thread waiting on the context's stop queue is woken */ | ||
33 | smp_wmb(); | ||
34 | |||
35 | wake_up_all(&ctx->stop_wq); | ||
36 | } | ||
37 | |||
38 | /* Clear callback arguments from spu structure */ | ||
39 | spu->class_0_pending = 0; | ||
40 | spu->dsisr = 0; | ||
41 | spu->dar = 0; | ||
19 | } | 42 | } |
20 | 43 | ||
21 | static inline int spu_stopped(struct spu_context *ctx, u32 *stat) | 44 | int spu_stopped(struct spu_context *ctx, u32 *stat) |
22 | { | 45 | { |
23 | struct spu *spu; | 46 | u64 dsisr; |
24 | u64 pte_fault; | 47 | u32 stopped; |
25 | 48 | ||
26 | *stat = ctx->ops->status_read(ctx); | 49 | *stat = ctx->ops->status_read(ctx); |
27 | 50 | ||
28 | spu = ctx->spu; | 51 | if (test_bit(SPU_SCHED_NOTIFY_ACTIVE, &ctx->sched_flags)) |
29 | if (ctx->state != SPU_STATE_RUNNABLE || | ||
30 | test_bit(SPU_SCHED_NOTIFY_ACTIVE, &ctx->sched_flags)) | ||
31 | return 1; | 52 | return 1; |
32 | pte_fault = spu->dsisr & | 53 | |
33 | (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED); | 54 | stopped = SPU_STATUS_INVALID_INSTR | SPU_STATUS_SINGLE_STEP | |
34 | return (!(*stat & SPU_STATUS_RUNNING) || pte_fault || spu->class_0_pending) ? | 55 | SPU_STATUS_STOPPED_BY_HALT | SPU_STATUS_STOPPED_BY_STOP; |
35 | 1 : 0; | 56 | if (*stat & stopped) |
57 | return 1; | ||
58 | |||
59 | dsisr = ctx->csa.dsisr; | ||
60 | if (dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED)) | ||
61 | return 1; | ||
62 | |||
63 | if (ctx->csa.class_0_pending) | ||
64 | return 1; | ||
65 | |||
66 | return 0; | ||
36 | } | 67 | } |
37 | 68 | ||
38 | static int spu_setup_isolated(struct spu_context *ctx) | 69 | static int spu_setup_isolated(struct spu_context *ctx) |
@@ -128,34 +159,66 @@ out: | |||
128 | 159 | ||
129 | static int spu_run_init(struct spu_context *ctx, u32 *npc) | 160 | static int spu_run_init(struct spu_context *ctx, u32 *npc) |
130 | { | 161 | { |
162 | unsigned long runcntl = SPU_RUNCNTL_RUNNABLE; | ||
163 | int ret; | ||
164 | |||
131 | spuctx_switch_state(ctx, SPU_UTIL_SYSTEM); | 165 | spuctx_switch_state(ctx, SPU_UTIL_SYSTEM); |
132 | 166 | ||
133 | if (ctx->flags & SPU_CREATE_ISOLATE) { | 167 | /* |
134 | unsigned long runcntl; | 168 | * NOSCHED is synchronous scheduling with respect to the caller. |
169 | * The caller waits for the context to be loaded. | ||
170 | */ | ||
171 | if (ctx->flags & SPU_CREATE_NOSCHED) { | ||
172 | if (ctx->state == SPU_STATE_SAVED) { | ||
173 | ret = spu_activate(ctx, 0); | ||
174 | if (ret) | ||
175 | return ret; | ||
176 | } | ||
177 | } | ||
135 | 178 | ||
179 | /* | ||
180 | * Apply special setup as required. | ||
181 | */ | ||
182 | if (ctx->flags & SPU_CREATE_ISOLATE) { | ||
136 | if (!(ctx->ops->status_read(ctx) & SPU_STATUS_ISOLATED_STATE)) { | 183 | if (!(ctx->ops->status_read(ctx) & SPU_STATUS_ISOLATED_STATE)) { |
137 | int ret = spu_setup_isolated(ctx); | 184 | ret = spu_setup_isolated(ctx); |
138 | if (ret) | 185 | if (ret) |
139 | return ret; | 186 | return ret; |
140 | } | 187 | } |
141 | 188 | ||
142 | /* if userspace has set the runcntrl register (eg, to issue an | 189 | /* |
143 | * isolated exit), we need to re-set it here */ | 190 | * If userspace has set the runcntrl register (eg, to |
191 | * issue an isolated exit), we need to re-set it here | ||
192 | */ | ||
144 | runcntl = ctx->ops->runcntl_read(ctx) & | 193 | runcntl = ctx->ops->runcntl_read(ctx) & |
145 | (SPU_RUNCNTL_RUNNABLE | SPU_RUNCNTL_ISOLATE); | 194 | (SPU_RUNCNTL_RUNNABLE | SPU_RUNCNTL_ISOLATE); |
146 | if (runcntl == 0) | 195 | if (runcntl == 0) |
147 | runcntl = SPU_RUNCNTL_RUNNABLE; | 196 | runcntl = SPU_RUNCNTL_RUNNABLE; |
197 | } | ||
198 | |||
199 | if (ctx->flags & SPU_CREATE_NOSCHED) { | ||
200 | spuctx_switch_state(ctx, SPU_UTIL_USER); | ||
148 | ctx->ops->runcntl_write(ctx, runcntl); | 201 | ctx->ops->runcntl_write(ctx, runcntl); |
149 | } else { | 202 | } else { |
150 | unsigned long mode = SPU_PRIVCNTL_MODE_NORMAL; | 203 | unsigned long privcntl; |
151 | ctx->ops->npc_write(ctx, *npc); | 204 | |
152 | if (test_thread_flag(TIF_SINGLESTEP)) | 205 | if (test_thread_flag(TIF_SINGLESTEP)) |
153 | mode = SPU_PRIVCNTL_MODE_SINGLE_STEP; | 206 | privcntl = SPU_PRIVCNTL_MODE_SINGLE_STEP; |
154 | out_be64(&ctx->spu->priv2->spu_privcntl_RW, mode); | 207 | else |
155 | ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE); | 208 | privcntl = SPU_PRIVCNTL_MODE_NORMAL; |
156 | } | ||
157 | 209 | ||
158 | spuctx_switch_state(ctx, SPU_UTIL_USER); | 210 | ctx->ops->npc_write(ctx, *npc); |
211 | ctx->ops->privcntl_write(ctx, privcntl); | ||
212 | ctx->ops->runcntl_write(ctx, runcntl); | ||
213 | |||
214 | if (ctx->state == SPU_STATE_SAVED) { | ||
215 | ret = spu_activate(ctx, 0); | ||
216 | if (ret) | ||
217 | return ret; | ||
218 | } else { | ||
219 | spuctx_switch_state(ctx, SPU_UTIL_USER); | ||
220 | } | ||
221 | } | ||
159 | 222 | ||
160 | return 0; | 223 | return 0; |
161 | } | 224 | } |
@@ -165,6 +228,8 @@ static int spu_run_fini(struct spu_context *ctx, u32 *npc, | |||
165 | { | 228 | { |
166 | int ret = 0; | 229 | int ret = 0; |
167 | 230 | ||
231 | spu_del_from_rq(ctx); | ||
232 | |||
168 | *status = ctx->ops->status_read(ctx); | 233 | *status = ctx->ops->status_read(ctx); |
169 | *npc = ctx->ops->npc_read(ctx); | 234 | *npc = ctx->ops->npc_read(ctx); |
170 | 235 | ||
@@ -177,26 +242,6 @@ static int spu_run_fini(struct spu_context *ctx, u32 *npc, | |||
177 | return ret; | 242 | return ret; |
178 | } | 243 | } |
179 | 244 | ||
180 | static int spu_reacquire_runnable(struct spu_context *ctx, u32 *npc, | ||
181 | u32 *status) | ||
182 | { | ||
183 | int ret; | ||
184 | |||
185 | ret = spu_run_fini(ctx, npc, status); | ||
186 | if (ret) | ||
187 | return ret; | ||
188 | |||
189 | if (*status & (SPU_STATUS_STOPPED_BY_STOP | SPU_STATUS_STOPPED_BY_HALT)) | ||
190 | return *status; | ||
191 | |||
192 | ret = spu_acquire_runnable(ctx, 0); | ||
193 | if (ret) | ||
194 | return ret; | ||
195 | |||
196 | spuctx_switch_state(ctx, SPU_UTIL_USER); | ||
197 | return 0; | ||
198 | } | ||
199 | |||
200 | /* | 245 | /* |
201 | * SPU syscall restarting is tricky because we violate the basic | 246 | * SPU syscall restarting is tricky because we violate the basic |
202 | * assumption that the signal handler is running on the interrupted | 247 | * assumption that the signal handler is running on the interrupted |
@@ -247,7 +292,7 @@ static int spu_process_callback(struct spu_context *ctx) | |||
247 | u32 ls_pointer, npc; | 292 | u32 ls_pointer, npc; |
248 | void __iomem *ls; | 293 | void __iomem *ls; |
249 | long spu_ret; | 294 | long spu_ret; |
250 | int ret; | 295 | int ret, ret2; |
251 | 296 | ||
252 | /* get syscall block from local store */ | 297 | /* get syscall block from local store */ |
253 | npc = ctx->ops->npc_read(ctx) & ~3; | 298 | npc = ctx->ops->npc_read(ctx) & ~3; |
@@ -269,9 +314,11 @@ static int spu_process_callback(struct spu_context *ctx) | |||
269 | if (spu_ret <= -ERESTARTSYS) { | 314 | if (spu_ret <= -ERESTARTSYS) { |
270 | ret = spu_handle_restartsys(ctx, &spu_ret, &npc); | 315 | ret = spu_handle_restartsys(ctx, &spu_ret, &npc); |
271 | } | 316 | } |
272 | spu_acquire(ctx); | 317 | ret2 = spu_acquire(ctx); |
273 | if (ret == -ERESTARTSYS) | 318 | if (ret == -ERESTARTSYS) |
274 | return ret; | 319 | return ret; |
320 | if (ret2) | ||
321 | return -EINTR; | ||
275 | } | 322 | } |
276 | 323 | ||
277 | /* write result, jump over indirect pointer */ | 324 | /* write result, jump over indirect pointer */ |
@@ -281,18 +328,6 @@ static int spu_process_callback(struct spu_context *ctx) | |||
281 | return ret; | 328 | return ret; |
282 | } | 329 | } |
283 | 330 | ||
284 | static inline int spu_process_events(struct spu_context *ctx) | ||
285 | { | ||
286 | struct spu *spu = ctx->spu; | ||
287 | int ret = 0; | ||
288 | |||
289 | if (spu->class_0_pending) | ||
290 | ret = spu_irq_class_0_bottom(spu); | ||
291 | if (!ret && signal_pending(current)) | ||
292 | ret = -ERESTARTSYS; | ||
293 | return ret; | ||
294 | } | ||
295 | |||
296 | long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *event) | 331 | long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *event) |
297 | { | 332 | { |
298 | int ret; | 333 | int ret; |
@@ -302,29 +337,14 @@ long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *event) | |||
302 | if (mutex_lock_interruptible(&ctx->run_mutex)) | 337 | if (mutex_lock_interruptible(&ctx->run_mutex)) |
303 | return -ERESTARTSYS; | 338 | return -ERESTARTSYS; |
304 | 339 | ||
305 | ctx->ops->master_start(ctx); | 340 | spu_enable_spu(ctx); |
306 | ctx->event_return = 0; | 341 | ctx->event_return = 0; |
307 | 342 | ||
308 | spu_acquire(ctx); | 343 | ret = spu_acquire(ctx); |
309 | if (ctx->state == SPU_STATE_SAVED) { | 344 | if (ret) |
310 | __spu_update_sched_info(ctx); | 345 | goto out_unlock; |
311 | spu_set_timeslice(ctx); | ||
312 | 346 | ||
313 | ret = spu_activate(ctx, 0); | 347 | spu_update_sched_info(ctx); |
314 | if (ret) { | ||
315 | spu_release(ctx); | ||
316 | goto out; | ||
317 | } | ||
318 | } else { | ||
319 | /* | ||
320 | * We have to update the scheduling priority under active_mutex | ||
321 | * to protect against find_victim(). | ||
322 | * | ||
323 | * No need to update the timeslice ASAP, it will get updated | ||
324 | * once the current one has expired. | ||
325 | */ | ||
326 | spu_update_sched_info(ctx); | ||
327 | } | ||
328 | 348 | ||
329 | ret = spu_run_init(ctx, npc); | 349 | ret = spu_run_init(ctx, npc); |
330 | if (ret) { | 350 | if (ret) { |
@@ -358,14 +378,12 @@ long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *event) | |||
358 | if (ret) | 378 | if (ret) |
359 | break; | 379 | break; |
360 | 380 | ||
361 | if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) { | 381 | ret = spufs_handle_class0(ctx); |
362 | ret = spu_reacquire_runnable(ctx, npc, &status); | 382 | if (ret) |
363 | if (ret) | 383 | break; |
364 | goto out2; | ||
365 | continue; | ||
366 | } | ||
367 | ret = spu_process_events(ctx); | ||
368 | 384 | ||
385 | if (signal_pending(current)) | ||
386 | ret = -ERESTARTSYS; | ||
369 | } while (!ret && !(status & (SPU_STATUS_STOPPED_BY_STOP | | 387 | } while (!ret && !(status & (SPU_STATUS_STOPPED_BY_STOP | |
370 | SPU_STATUS_STOPPED_BY_HALT | | 388 | SPU_STATUS_STOPPED_BY_HALT | |
371 | SPU_STATUS_SINGLE_STEP))); | 389 | SPU_STATUS_SINGLE_STEP))); |
@@ -376,11 +394,10 @@ long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *event) | |||
376 | ctx->stats.libassist++; | 394 | ctx->stats.libassist++; |
377 | 395 | ||
378 | 396 | ||
379 | ctx->ops->master_stop(ctx); | 397 | spu_disable_spu(ctx); |
380 | ret = spu_run_fini(ctx, npc, &status); | 398 | ret = spu_run_fini(ctx, npc, &status); |
381 | spu_yield(ctx); | 399 | spu_yield(ctx); |
382 | 400 | ||
383 | out2: | ||
384 | if ((ret == 0) || | 401 | if ((ret == 0) || |
385 | ((ret == -ERESTARTSYS) && | 402 | ((ret == -ERESTARTSYS) && |
386 | ((status & SPU_STATUS_STOPPED_BY_HALT) || | 403 | ((status & SPU_STATUS_STOPPED_BY_HALT) || |
@@ -401,6 +418,7 @@ out2: | |||
401 | 418 | ||
402 | out: | 419 | out: |
403 | *event = ctx->event_return; | 420 | *event = ctx->event_return; |
421 | out_unlock: | ||
404 | mutex_unlock(&ctx->run_mutex); | 422 | mutex_unlock(&ctx->run_mutex); |
405 | return ret; | 423 | return ret; |
406 | } | 424 | } |
diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index 9ad53e637aee..00d914232af1 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c | |||
@@ -58,6 +58,7 @@ static unsigned long spu_avenrun[3]; | |||
58 | static struct spu_prio_array *spu_prio; | 58 | static struct spu_prio_array *spu_prio; |
59 | static struct task_struct *spusched_task; | 59 | static struct task_struct *spusched_task; |
60 | static struct timer_list spusched_timer; | 60 | static struct timer_list spusched_timer; |
61 | static struct timer_list spuloadavg_timer; | ||
61 | 62 | ||
62 | /* | 63 | /* |
63 | * Priority of a normal, non-rt, non-niced'd process (aka nice level 0). | 64 | * Priority of a normal, non-rt, non-niced'd process (aka nice level 0). |
@@ -105,15 +106,21 @@ void spu_set_timeslice(struct spu_context *ctx) | |||
105 | void __spu_update_sched_info(struct spu_context *ctx) | 106 | void __spu_update_sched_info(struct spu_context *ctx) |
106 | { | 107 | { |
107 | /* | 108 | /* |
108 | * 32-Bit assignment are atomic on powerpc, and we don't care about | 109 | * assert that the context is not on the runqueue, so it is safe |
109 | * memory ordering here because retriving the controlling thread is | 110 | * to change its scheduling parameters. |
110 | * per defintion racy. | 111 | */ |
112 | BUG_ON(!list_empty(&ctx->rq)); | ||
113 | |||
114 | /* | ||
115 | * 32-Bit assignments are atomic on powerpc, and we don't care about | ||
116 | * memory ordering here because retrieving the controlling thread is | ||
117 | * per definition racy. | ||
111 | */ | 118 | */ |
112 | ctx->tid = current->pid; | 119 | ctx->tid = current->pid; |
113 | 120 | ||
114 | /* | 121 | /* |
115 | * We do our own priority calculations, so we normally want | 122 | * We do our own priority calculations, so we normally want |
116 | * ->static_prio to start with. Unfortunately thies field | 123 | * ->static_prio to start with. Unfortunately this field |
117 | * contains junk for threads with a realtime scheduling | 124 | * contains junk for threads with a realtime scheduling |
118 | * policy so we have to look at ->prio in this case. | 125 | * policy so we have to look at ->prio in this case. |
119 | */ | 126 | */ |
@@ -124,23 +131,32 @@ void __spu_update_sched_info(struct spu_context *ctx) | |||
124 | ctx->policy = current->policy; | 131 | ctx->policy = current->policy; |
125 | 132 | ||
126 | /* | 133 | /* |
127 | * A lot of places that don't hold list_mutex poke into | 134 | * TO DO: the context may be loaded, so we may need to activate |
128 | * cpus_allowed, including grab_runnable_context which | 135 | * it again on a different node. But it shouldn't hurt anything |
129 | * already holds the runq_lock. So abuse runq_lock | 136 | * to update its parameters, because we know that the scheduler |
130 | * to protect this field aswell. | 137 | * is not actively looking at this field, since it is not on the |
138 | * runqueue. The context will be rescheduled on the proper node | ||
139 | * if it is timesliced or preempted. | ||
131 | */ | 140 | */ |
132 | spin_lock(&spu_prio->runq_lock); | ||
133 | ctx->cpus_allowed = current->cpus_allowed; | 141 | ctx->cpus_allowed = current->cpus_allowed; |
134 | spin_unlock(&spu_prio->runq_lock); | ||
135 | } | 142 | } |
136 | 143 | ||
137 | void spu_update_sched_info(struct spu_context *ctx) | 144 | void spu_update_sched_info(struct spu_context *ctx) |
138 | { | 145 | { |
139 | int node = ctx->spu->node; | 146 | int node; |
140 | 147 | ||
141 | mutex_lock(&cbe_spu_info[node].list_mutex); | 148 | if (ctx->state == SPU_STATE_RUNNABLE) { |
142 | __spu_update_sched_info(ctx); | 149 | node = ctx->spu->node; |
143 | mutex_unlock(&cbe_spu_info[node].list_mutex); | 150 | |
151 | /* | ||
152 | * Take list_mutex to sync with find_victim(). | ||
153 | */ | ||
154 | mutex_lock(&cbe_spu_info[node].list_mutex); | ||
155 | __spu_update_sched_info(ctx); | ||
156 | mutex_unlock(&cbe_spu_info[node].list_mutex); | ||
157 | } else { | ||
158 | __spu_update_sched_info(ctx); | ||
159 | } | ||
144 | } | 160 | } |
145 | 161 | ||
146 | static int __node_allowed(struct spu_context *ctx, int node) | 162 | static int __node_allowed(struct spu_context *ctx, int node) |
@@ -174,7 +190,7 @@ void do_notify_spus_active(void) | |||
174 | * Wake up the active spu_contexts. | 190 | * Wake up the active spu_contexts. |
175 | * | 191 | * |
176 | * When the awakened processes see their "notify_active" flag is set, | 192 | * When the awakened processes see their "notify_active" flag is set, |
177 | * they will call spu_switch_notify(); | 193 | * they will call spu_switch_notify(). |
178 | */ | 194 | */ |
179 | for_each_online_node(node) { | 195 | for_each_online_node(node) { |
180 | struct spu *spu; | 196 | struct spu *spu; |
@@ -221,7 +237,6 @@ static void spu_bind_context(struct spu *spu, struct spu_context *ctx) | |||
221 | spu->wbox_callback = spufs_wbox_callback; | 237 | spu->wbox_callback = spufs_wbox_callback; |
222 | spu->stop_callback = spufs_stop_callback; | 238 | spu->stop_callback = spufs_stop_callback; |
223 | spu->mfc_callback = spufs_mfc_callback; | 239 | spu->mfc_callback = spufs_mfc_callback; |
224 | spu->dma_callback = spufs_dma_callback; | ||
225 | mb(); | 240 | mb(); |
226 | spu_unmap_mappings(ctx); | 241 | spu_unmap_mappings(ctx); |
227 | spu_restore(&ctx->csa, spu); | 242 | spu_restore(&ctx->csa, spu); |
@@ -409,7 +424,6 @@ static void spu_unbind_context(struct spu *spu, struct spu_context *ctx) | |||
409 | spu->wbox_callback = NULL; | 424 | spu->wbox_callback = NULL; |
410 | spu->stop_callback = NULL; | 425 | spu->stop_callback = NULL; |
411 | spu->mfc_callback = NULL; | 426 | spu->mfc_callback = NULL; |
412 | spu->dma_callback = NULL; | ||
413 | spu_associate_mm(spu, NULL); | 427 | spu_associate_mm(spu, NULL); |
414 | spu->pid = 0; | 428 | spu->pid = 0; |
415 | spu->tgid = 0; | 429 | spu->tgid = 0; |
@@ -454,6 +468,13 @@ static void __spu_add_to_rq(struct spu_context *ctx) | |||
454 | } | 468 | } |
455 | } | 469 | } |
456 | 470 | ||
471 | static void spu_add_to_rq(struct spu_context *ctx) | ||
472 | { | ||
473 | spin_lock(&spu_prio->runq_lock); | ||
474 | __spu_add_to_rq(ctx); | ||
475 | spin_unlock(&spu_prio->runq_lock); | ||
476 | } | ||
477 | |||
457 | static void __spu_del_from_rq(struct spu_context *ctx) | 478 | static void __spu_del_from_rq(struct spu_context *ctx) |
458 | { | 479 | { |
459 | int prio = ctx->prio; | 480 | int prio = ctx->prio; |
@@ -468,10 +489,24 @@ static void __spu_del_from_rq(struct spu_context *ctx) | |||
468 | } | 489 | } |
469 | } | 490 | } |
470 | 491 | ||
492 | void spu_del_from_rq(struct spu_context *ctx) | ||
493 | { | ||
494 | spin_lock(&spu_prio->runq_lock); | ||
495 | __spu_del_from_rq(ctx); | ||
496 | spin_unlock(&spu_prio->runq_lock); | ||
497 | } | ||
498 | |||
471 | static void spu_prio_wait(struct spu_context *ctx) | 499 | static void spu_prio_wait(struct spu_context *ctx) |
472 | { | 500 | { |
473 | DEFINE_WAIT(wait); | 501 | DEFINE_WAIT(wait); |
474 | 502 | ||
503 | /* | ||
504 | * The caller must explicitly wait for a context to be loaded | ||
505 | * if the nosched flag is set. If NOSCHED is not set, the caller | ||
506 | * queues the context and waits for an spu event or error. | ||
507 | */ | ||
508 | BUG_ON(!(ctx->flags & SPU_CREATE_NOSCHED)); | ||
509 | |||
475 | spin_lock(&spu_prio->runq_lock); | 510 | spin_lock(&spu_prio->runq_lock); |
476 | prepare_to_wait_exclusive(&ctx->stop_wq, &wait, TASK_INTERRUPTIBLE); | 511 | prepare_to_wait_exclusive(&ctx->stop_wq, &wait, TASK_INTERRUPTIBLE); |
477 | if (!signal_pending(current)) { | 512 | if (!signal_pending(current)) { |
@@ -555,7 +590,7 @@ static struct spu *find_victim(struct spu_context *ctx) | |||
555 | /* | 590 | /* |
556 | * Look for a possible preemption candidate on the local node first. | 591 | * Look for a possible preemption candidate on the local node first. |
557 | * If there is no candidate look at the other nodes. This isn't | 592 | * If there is no candidate look at the other nodes. This isn't |
558 | * exactly fair, but so far the whole spu schedule tries to keep | 593 | * exactly fair, but so far the whole spu scheduler tries to keep |
559 | * a strong node affinity. We might want to fine-tune this in | 594 | * a strong node affinity. We might want to fine-tune this in |
560 | * the future. | 595 | * the future. |
561 | */ | 596 | */ |
@@ -571,6 +606,7 @@ static struct spu *find_victim(struct spu_context *ctx) | |||
571 | struct spu_context *tmp = spu->ctx; | 606 | struct spu_context *tmp = spu->ctx; |
572 | 607 | ||
573 | if (tmp && tmp->prio > ctx->prio && | 608 | if (tmp && tmp->prio > ctx->prio && |
609 | !(tmp->flags & SPU_CREATE_NOSCHED) && | ||
574 | (!victim || tmp->prio > victim->prio)) | 610 | (!victim || tmp->prio > victim->prio)) |
575 | victim = spu->ctx; | 611 | victim = spu->ctx; |
576 | } | 612 | } |
@@ -582,6 +618,10 @@ static struct spu *find_victim(struct spu_context *ctx) | |||
582 | * higher priority contexts before lower priority | 618 | * higher priority contexts before lower priority |
583 | * ones, so this is safe until we introduce | 619 | * ones, so this is safe until we introduce |
584 | * priority inheritance schemes. | 620 | * priority inheritance schemes. |
621 | * | ||
622 | * XXX if the highest priority context is locked, | ||
623 | * this can loop a long time. Might be better to | ||
624 | * look at another context or give up after X retries. | ||
585 | */ | 625 | */ |
586 | if (!mutex_trylock(&victim->state_mutex)) { | 626 | if (!mutex_trylock(&victim->state_mutex)) { |
587 | victim = NULL; | 627 | victim = NULL; |
@@ -589,10 +629,10 @@ static struct spu *find_victim(struct spu_context *ctx) | |||
589 | } | 629 | } |
590 | 630 | ||
591 | spu = victim->spu; | 631 | spu = victim->spu; |
592 | if (!spu) { | 632 | if (!spu || victim->prio <= ctx->prio) { |
593 | /* | 633 | /* |
594 | * This race can happen because we've dropped | 634 | * This race can happen because we've dropped |
595 | * the active list mutex. No a problem, just | 635 | * the active list mutex. Not a problem, just |
596 | * restart the search. | 636 | * restart the search. |
597 | */ | 637 | */ |
598 | mutex_unlock(&victim->state_mutex); | 638 | mutex_unlock(&victim->state_mutex); |
@@ -607,13 +647,10 @@ static struct spu *find_victim(struct spu_context *ctx) | |||
607 | 647 | ||
608 | victim->stats.invol_ctx_switch++; | 648 | victim->stats.invol_ctx_switch++; |
609 | spu->stats.invol_ctx_switch++; | 649 | spu->stats.invol_ctx_switch++; |
650 | spu_add_to_rq(victim); | ||
651 | |||
610 | mutex_unlock(&victim->state_mutex); | 652 | mutex_unlock(&victim->state_mutex); |
611 | /* | 653 | |
612 | * We need to break out of the wait loop in spu_run | ||
613 | * manually to ensure this context gets put on the | ||
614 | * runqueue again ASAP. | ||
615 | */ | ||
616 | wake_up(&victim->stop_wq); | ||
617 | return spu; | 654 | return spu; |
618 | } | 655 | } |
619 | } | 656 | } |
@@ -621,6 +658,50 @@ static struct spu *find_victim(struct spu_context *ctx) | |||
621 | return NULL; | 658 | return NULL; |
622 | } | 659 | } |
623 | 660 | ||
661 | static void __spu_schedule(struct spu *spu, struct spu_context *ctx) | ||
662 | { | ||
663 | int node = spu->node; | ||
664 | int success = 0; | ||
665 | |||
666 | spu_set_timeslice(ctx); | ||
667 | |||
668 | mutex_lock(&cbe_spu_info[node].list_mutex); | ||
669 | if (spu->ctx == NULL) { | ||
670 | spu_bind_context(spu, ctx); | ||
671 | cbe_spu_info[node].nr_active++; | ||
672 | spu->alloc_state = SPU_USED; | ||
673 | success = 1; | ||
674 | } | ||
675 | mutex_unlock(&cbe_spu_info[node].list_mutex); | ||
676 | |||
677 | if (success) | ||
678 | wake_up_all(&ctx->run_wq); | ||
679 | else | ||
680 | spu_add_to_rq(ctx); | ||
681 | } | ||
682 | |||
683 | static void spu_schedule(struct spu *spu, struct spu_context *ctx) | ||
684 | { | ||
685 | /* not a candidate for interruptible because it's called either | ||
686 | from the scheduler thread or from spu_deactivate */ | ||
687 | mutex_lock(&ctx->state_mutex); | ||
688 | __spu_schedule(spu, ctx); | ||
689 | spu_release(ctx); | ||
690 | } | ||
691 | |||
692 | static void spu_unschedule(struct spu *spu, struct spu_context *ctx) | ||
693 | { | ||
694 | int node = spu->node; | ||
695 | |||
696 | mutex_lock(&cbe_spu_info[node].list_mutex); | ||
697 | cbe_spu_info[node].nr_active--; | ||
698 | spu->alloc_state = SPU_FREE; | ||
699 | spu_unbind_context(spu, ctx); | ||
700 | ctx->stats.invol_ctx_switch++; | ||
701 | spu->stats.invol_ctx_switch++; | ||
702 | mutex_unlock(&cbe_spu_info[node].list_mutex); | ||
703 | } | ||
704 | |||
624 | /** | 705 | /** |
625 | * spu_activate - find a free spu for a context and execute it | 706 | * spu_activate - find a free spu for a context and execute it |
626 | * @ctx: spu context to schedule | 707 | * @ctx: spu context to schedule |
@@ -632,39 +713,47 @@ static struct spu *find_victim(struct spu_context *ctx) | |||
632 | */ | 713 | */ |
633 | int spu_activate(struct spu_context *ctx, unsigned long flags) | 714 | int spu_activate(struct spu_context *ctx, unsigned long flags) |
634 | { | 715 | { |
635 | do { | 716 | struct spu *spu; |
636 | struct spu *spu; | ||
637 | 717 | ||
638 | /* | 718 | /* |
639 | * If there are multiple threads waiting for a single context | 719 | * If there are multiple threads waiting for a single context |
640 | * only one actually binds the context while the others will | 720 | * only one actually binds the context while the others will |
641 | * only be able to acquire the state_mutex once the context | 721 | * only be able to acquire the state_mutex once the context |
642 | * already is in runnable state. | 722 | * already is in runnable state. |
643 | */ | 723 | */ |
644 | if (ctx->spu) | 724 | if (ctx->spu) |
645 | return 0; | 725 | return 0; |
646 | 726 | ||
647 | spu = spu_get_idle(ctx); | 727 | spu_activate_top: |
648 | /* | 728 | if (signal_pending(current)) |
649 | * If this is a realtime thread we try to get it running by | 729 | return -ERESTARTSYS; |
650 | * preempting a lower priority thread. | ||
651 | */ | ||
652 | if (!spu && rt_prio(ctx->prio)) | ||
653 | spu = find_victim(ctx); | ||
654 | if (spu) { | ||
655 | int node = spu->node; | ||
656 | 730 | ||
657 | mutex_lock(&cbe_spu_info[node].list_mutex); | 731 | spu = spu_get_idle(ctx); |
658 | spu_bind_context(spu, ctx); | 732 | /* |
659 | cbe_spu_info[node].nr_active++; | 733 | * If this is a realtime thread we try to get it running by |
660 | mutex_unlock(&cbe_spu_info[node].list_mutex); | 734 | * preempting a lower priority thread. |
661 | return 0; | 735 | */ |
662 | } | 736 | if (!spu && rt_prio(ctx->prio)) |
737 | spu = find_victim(ctx); | ||
738 | if (spu) { | ||
739 | unsigned long runcntl; | ||
740 | |||
741 | runcntl = ctx->ops->runcntl_read(ctx); | ||
742 | __spu_schedule(spu, ctx); | ||
743 | if (runcntl & SPU_RUNCNTL_RUNNABLE) | ||
744 | spuctx_switch_state(ctx, SPU_UTIL_USER); | ||
663 | 745 | ||
746 | return 0; | ||
747 | } | ||
748 | |||
749 | if (ctx->flags & SPU_CREATE_NOSCHED) { | ||
664 | spu_prio_wait(ctx); | 750 | spu_prio_wait(ctx); |
665 | } while (!signal_pending(current)); | 751 | goto spu_activate_top; |
752 | } | ||
666 | 753 | ||
667 | return -ERESTARTSYS; | 754 | spu_add_to_rq(ctx); |
755 | |||
756 | return 0; | ||
668 | } | 757 | } |
669 | 758 | ||
670 | /** | 759 | /** |
@@ -706,21 +795,19 @@ static int __spu_deactivate(struct spu_context *ctx, int force, int max_prio) | |||
706 | if (spu) { | 795 | if (spu) { |
707 | new = grab_runnable_context(max_prio, spu->node); | 796 | new = grab_runnable_context(max_prio, spu->node); |
708 | if (new || force) { | 797 | if (new || force) { |
709 | int node = spu->node; | 798 | spu_unschedule(spu, ctx); |
710 | 799 | if (new) { | |
711 | mutex_lock(&cbe_spu_info[node].list_mutex); | 800 | if (new->flags & SPU_CREATE_NOSCHED) |
712 | spu_unbind_context(spu, ctx); | 801 | wake_up(&new->stop_wq); |
713 | spu->alloc_state = SPU_FREE; | 802 | else { |
714 | cbe_spu_info[node].nr_active--; | 803 | spu_release(ctx); |
715 | mutex_unlock(&cbe_spu_info[node].list_mutex); | 804 | spu_schedule(spu, new); |
716 | 805 | /* this one can't easily be made | |
717 | ctx->stats.vol_ctx_switch++; | 806 | interruptible */ |
718 | spu->stats.vol_ctx_switch++; | 807 | mutex_lock(&ctx->state_mutex); |
719 | 808 | } | |
720 | if (new) | 809 | } |
721 | wake_up(&new->stop_wq); | ||
722 | } | 810 | } |
723 | |||
724 | } | 811 | } |
725 | 812 | ||
726 | return new != NULL; | 813 | return new != NULL; |
@@ -757,43 +844,38 @@ void spu_yield(struct spu_context *ctx) | |||
757 | 844 | ||
758 | static noinline void spusched_tick(struct spu_context *ctx) | 845 | static noinline void spusched_tick(struct spu_context *ctx) |
759 | { | 846 | { |
847 | struct spu_context *new = NULL; | ||
848 | struct spu *spu = NULL; | ||
849 | u32 status; | ||
850 | |||
851 | if (spu_acquire(ctx)) | ||
852 | BUG(); /* a kernel thread never has signals pending */ | ||
853 | |||
854 | if (ctx->state != SPU_STATE_RUNNABLE) | ||
855 | goto out; | ||
856 | if (spu_stopped(ctx, &status)) | ||
857 | goto out; | ||
760 | if (ctx->flags & SPU_CREATE_NOSCHED) | 858 | if (ctx->flags & SPU_CREATE_NOSCHED) |
761 | return; | 859 | goto out; |
762 | if (ctx->policy == SCHED_FIFO) | 860 | if (ctx->policy == SCHED_FIFO) |
763 | return; | 861 | goto out; |
764 | 862 | ||
765 | if (--ctx->time_slice) | 863 | if (--ctx->time_slice) |
766 | return; | 864 | goto out; |
767 | 865 | ||
768 | /* | 866 | spu = ctx->spu; |
769 | * Unfortunately list_mutex ranks outside of state_mutex, so | 867 | new = grab_runnable_context(ctx->prio + 1, spu->node); |
770 | * we have to trylock here. If we fail give the context another | 868 | if (new) { |
771 | * tick and try again. | 869 | spu_unschedule(spu, ctx); |
772 | */ | 870 | spu_add_to_rq(ctx); |
773 | if (mutex_trylock(&ctx->state_mutex)) { | ||
774 | struct spu *spu = ctx->spu; | ||
775 | struct spu_context *new; | ||
776 | |||
777 | new = grab_runnable_context(ctx->prio + 1, spu->node); | ||
778 | if (new) { | ||
779 | spu_unbind_context(spu, ctx); | ||
780 | ctx->stats.invol_ctx_switch++; | ||
781 | spu->stats.invol_ctx_switch++; | ||
782 | spu->alloc_state = SPU_FREE; | ||
783 | cbe_spu_info[spu->node].nr_active--; | ||
784 | wake_up(&new->stop_wq); | ||
785 | /* | ||
786 | * We need to break out of the wait loop in | ||
787 | * spu_run manually to ensure this context | ||
788 | * gets put on the runqueue again ASAP. | ||
789 | */ | ||
790 | wake_up(&ctx->stop_wq); | ||
791 | } | ||
792 | spu_set_timeslice(ctx); | ||
793 | mutex_unlock(&ctx->state_mutex); | ||
794 | } else { | 871 | } else { |
795 | ctx->time_slice++; | 872 | ctx->time_slice++; |
796 | } | 873 | } |
874 | out: | ||
875 | spu_release(ctx); | ||
876 | |||
877 | if (new) | ||
878 | spu_schedule(spu, new); | ||
797 | } | 879 | } |
798 | 880 | ||
799 | /** | 881 | /** |
@@ -817,35 +899,31 @@ static unsigned long count_active_contexts(void) | |||
817 | } | 899 | } |
818 | 900 | ||
819 | /** | 901 | /** |
820 | * spu_calc_load - given tick count, update the avenrun load estimates. | 902 | * spu_calc_load - update the avenrun load estimates. |
821 | * @tick: tick count | ||
822 | * | 903 | * |
823 | * No locking against reading these values from userspace, as for | 904 | * No locking against reading these values from userspace, as for |
824 | * the CPU loadavg code. | 905 | * the CPU loadavg code. |
825 | */ | 906 | */ |
826 | static void spu_calc_load(unsigned long ticks) | 907 | static void spu_calc_load(void) |
827 | { | 908 | { |
828 | unsigned long active_tasks; /* fixed-point */ | 909 | unsigned long active_tasks; /* fixed-point */ |
829 | static int count = LOAD_FREQ; | 910 | |
830 | 911 | active_tasks = count_active_contexts() * FIXED_1; | |
831 | count -= ticks; | 912 | CALC_LOAD(spu_avenrun[0], EXP_1, active_tasks); |
832 | 913 | CALC_LOAD(spu_avenrun[1], EXP_5, active_tasks); | |
833 | if (unlikely(count < 0)) { | 914 | CALC_LOAD(spu_avenrun[2], EXP_15, active_tasks); |
834 | active_tasks = count_active_contexts() * FIXED_1; | ||
835 | do { | ||
836 | CALC_LOAD(spu_avenrun[0], EXP_1, active_tasks); | ||
837 | CALC_LOAD(spu_avenrun[1], EXP_5, active_tasks); | ||
838 | CALC_LOAD(spu_avenrun[2], EXP_15, active_tasks); | ||
839 | count += LOAD_FREQ; | ||
840 | } while (count < 0); | ||
841 | } | ||
842 | } | 915 | } |
843 | 916 | ||
844 | static void spusched_wake(unsigned long data) | 917 | static void spusched_wake(unsigned long data) |
845 | { | 918 | { |
846 | mod_timer(&spusched_timer, jiffies + SPUSCHED_TICK); | 919 | mod_timer(&spusched_timer, jiffies + SPUSCHED_TICK); |
847 | wake_up_process(spusched_task); | 920 | wake_up_process(spusched_task); |
848 | spu_calc_load(SPUSCHED_TICK); | 921 | } |
922 | |||
923 | static void spuloadavg_wake(unsigned long data) | ||
924 | { | ||
925 | mod_timer(&spuloadavg_timer, jiffies + LOAD_FREQ); | ||
926 | spu_calc_load(); | ||
849 | } | 927 | } |
850 | 928 | ||
851 | static int spusched_thread(void *unused) | 929 | static int spusched_thread(void *unused) |
@@ -857,17 +935,58 @@ static int spusched_thread(void *unused) | |||
857 | set_current_state(TASK_INTERRUPTIBLE); | 935 | set_current_state(TASK_INTERRUPTIBLE); |
858 | schedule(); | 936 | schedule(); |
859 | for (node = 0; node < MAX_NUMNODES; node++) { | 937 | for (node = 0; node < MAX_NUMNODES; node++) { |
860 | mutex_lock(&cbe_spu_info[node].list_mutex); | 938 | struct mutex *mtx = &cbe_spu_info[node].list_mutex; |
861 | list_for_each_entry(spu, &cbe_spu_info[node].spus, cbe_list) | 939 | |
862 | if (spu->ctx) | 940 | mutex_lock(mtx); |
863 | spusched_tick(spu->ctx); | 941 | list_for_each_entry(spu, &cbe_spu_info[node].spus, |
864 | mutex_unlock(&cbe_spu_info[node].list_mutex); | 942 | cbe_list) { |
943 | struct spu_context *ctx = spu->ctx; | ||
944 | |||
945 | if (ctx) { | ||
946 | mutex_unlock(mtx); | ||
947 | spusched_tick(ctx); | ||
948 | mutex_lock(mtx); | ||
949 | } | ||
950 | } | ||
951 | mutex_unlock(mtx); | ||
865 | } | 952 | } |
866 | } | 953 | } |
867 | 954 | ||
868 | return 0; | 955 | return 0; |
869 | } | 956 | } |
870 | 957 | ||
958 | void spuctx_switch_state(struct spu_context *ctx, | ||
959 | enum spu_utilization_state new_state) | ||
960 | { | ||
961 | unsigned long long curtime; | ||
962 | signed long long delta; | ||
963 | struct timespec ts; | ||
964 | struct spu *spu; | ||
965 | enum spu_utilization_state old_state; | ||
966 | |||
967 | ktime_get_ts(&ts); | ||
968 | curtime = timespec_to_ns(&ts); | ||
969 | delta = curtime - ctx->stats.tstamp; | ||
970 | |||
971 | WARN_ON(!mutex_is_locked(&ctx->state_mutex)); | ||
972 | WARN_ON(delta < 0); | ||
973 | |||
974 | spu = ctx->spu; | ||
975 | old_state = ctx->stats.util_state; | ||
976 | ctx->stats.util_state = new_state; | ||
977 | ctx->stats.tstamp = curtime; | ||
978 | |||
979 | /* | ||
980 | * Update the physical SPU utilization statistics. | ||
981 | */ | ||
982 | if (spu) { | ||
983 | ctx->stats.times[old_state] += delta; | ||
984 | spu->stats.times[old_state] += delta; | ||
985 | spu->stats.util_state = new_state; | ||
986 | spu->stats.tstamp = curtime; | ||
987 | } | ||
988 | } | ||
989 | |||
871 | #define LOAD_INT(x) ((x) >> FSHIFT) | 990 | #define LOAD_INT(x) ((x) >> FSHIFT) |
872 | #define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100) | 991 | #define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100) |
873 | 992 | ||
@@ -881,7 +1000,7 @@ static int show_spu_loadavg(struct seq_file *s, void *private) | |||
881 | 1000 | ||
882 | /* | 1001 | /* |
883 | * Note that last_pid doesn't really make much sense for the | 1002 | * Note that last_pid doesn't really make much sense for the |
884 | * SPU loadavg (it even seems very odd on the CPU side..), | 1003 | * SPU loadavg (it even seems very odd on the CPU side...), |
885 | * but we include it here to have a 100% compatible interface. | 1004 | * but we include it here to have a 100% compatible interface. |
886 | */ | 1005 | */ |
887 | seq_printf(s, "%d.%02d %d.%02d %d.%02d %ld/%d %d\n", | 1006 | seq_printf(s, "%d.%02d %d.%02d %d.%02d %ld/%d %d\n", |
@@ -922,6 +1041,7 @@ int __init spu_sched_init(void) | |||
922 | spin_lock_init(&spu_prio->runq_lock); | 1041 | spin_lock_init(&spu_prio->runq_lock); |
923 | 1042 | ||
924 | setup_timer(&spusched_timer, spusched_wake, 0); | 1043 | setup_timer(&spusched_timer, spusched_wake, 0); |
1044 | setup_timer(&spuloadavg_timer, spuloadavg_wake, 0); | ||
925 | 1045 | ||
926 | spusched_task = kthread_run(spusched_thread, NULL, "spusched"); | 1046 | spusched_task = kthread_run(spusched_thread, NULL, "spusched"); |
927 | if (IS_ERR(spusched_task)) { | 1047 | if (IS_ERR(spusched_task)) { |
@@ -929,6 +1049,8 @@ int __init spu_sched_init(void) | |||
929 | goto out_free_spu_prio; | 1049 | goto out_free_spu_prio; |
930 | } | 1050 | } |
931 | 1051 | ||
1052 | mod_timer(&spuloadavg_timer, 0); | ||
1053 | |||
932 | entry = create_proc_entry("spu_loadavg", 0, NULL); | 1054 | entry = create_proc_entry("spu_loadavg", 0, NULL); |
933 | if (!entry) | 1055 | if (!entry) |
934 | goto out_stop_kthread; | 1056 | goto out_stop_kthread; |
@@ -954,6 +1076,7 @@ void spu_sched_exit(void) | |||
954 | remove_proc_entry("spu_loadavg", NULL); | 1076 | remove_proc_entry("spu_loadavg", NULL); |
955 | 1077 | ||
956 | del_timer_sync(&spusched_timer); | 1078 | del_timer_sync(&spusched_timer); |
1079 | del_timer_sync(&spuloadavg_timer); | ||
957 | kthread_stop(spusched_task); | 1080 | kthread_stop(spusched_task); |
958 | 1081 | ||
959 | for (node = 0; node < MAX_NUMNODES; node++) { | 1082 | for (node = 0; node < MAX_NUMNODES; node++) { |
diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index ca47b991bda5..0e114038ea6f 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h | |||
@@ -71,6 +71,7 @@ struct spu_context { | |||
71 | wait_queue_head_t wbox_wq; | 71 | wait_queue_head_t wbox_wq; |
72 | wait_queue_head_t stop_wq; | 72 | wait_queue_head_t stop_wq; |
73 | wait_queue_head_t mfc_wq; | 73 | wait_queue_head_t mfc_wq; |
74 | wait_queue_head_t run_wq; | ||
74 | struct fasync_struct *ibox_fasync; | 75 | struct fasync_struct *ibox_fasync; |
75 | struct fasync_struct *wbox_fasync; | 76 | struct fasync_struct *wbox_fasync; |
76 | struct fasync_struct *mfc_fasync; | 77 | struct fasync_struct *mfc_fasync; |
@@ -168,8 +169,10 @@ struct spu_context_ops { | |||
168 | void (*npc_write) (struct spu_context * ctx, u32 data); | 169 | void (*npc_write) (struct spu_context * ctx, u32 data); |
169 | u32(*status_read) (struct spu_context * ctx); | 170 | u32(*status_read) (struct spu_context * ctx); |
170 | char*(*get_ls) (struct spu_context * ctx); | 171 | char*(*get_ls) (struct spu_context * ctx); |
172 | void (*privcntl_write) (struct spu_context *ctx, u64 data); | ||
171 | u32 (*runcntl_read) (struct spu_context * ctx); | 173 | u32 (*runcntl_read) (struct spu_context * ctx); |
172 | void (*runcntl_write) (struct spu_context * ctx, u32 data); | 174 | void (*runcntl_write) (struct spu_context * ctx, u32 data); |
175 | void (*runcntl_stop) (struct spu_context * ctx); | ||
173 | void (*master_start) (struct spu_context * ctx); | 176 | void (*master_start) (struct spu_context * ctx); |
174 | void (*master_stop) (struct spu_context * ctx); | 177 | void (*master_stop) (struct spu_context * ctx); |
175 | int (*set_mfc_query)(struct spu_context * ctx, u32 mask, u32 mode); | 178 | int (*set_mfc_query)(struct spu_context * ctx, u32 mask, u32 mode); |
@@ -219,15 +222,16 @@ void spu_gang_add_ctx(struct spu_gang *gang, struct spu_context *ctx); | |||
219 | 222 | ||
220 | /* fault handling */ | 223 | /* fault handling */ |
221 | int spufs_handle_class1(struct spu_context *ctx); | 224 | int spufs_handle_class1(struct spu_context *ctx); |
225 | int spufs_handle_class0(struct spu_context *ctx); | ||
222 | 226 | ||
223 | /* affinity */ | 227 | /* affinity */ |
224 | struct spu *affinity_check(struct spu_context *ctx); | 228 | struct spu *affinity_check(struct spu_context *ctx); |
225 | 229 | ||
226 | /* context management */ | 230 | /* context management */ |
227 | extern atomic_t nr_spu_contexts; | 231 | extern atomic_t nr_spu_contexts; |
228 | static inline void spu_acquire(struct spu_context *ctx) | 232 | static inline int __must_check spu_acquire(struct spu_context *ctx) |
229 | { | 233 | { |
230 | mutex_lock(&ctx->state_mutex); | 234 | return mutex_lock_interruptible(&ctx->state_mutex); |
231 | } | 235 | } |
232 | 236 | ||
233 | static inline void spu_release(struct spu_context *ctx) | 237 | static inline void spu_release(struct spu_context *ctx) |
@@ -242,10 +246,11 @@ int put_spu_context(struct spu_context *ctx); | |||
242 | void spu_unmap_mappings(struct spu_context *ctx); | 246 | void spu_unmap_mappings(struct spu_context *ctx); |
243 | 247 | ||
244 | void spu_forget(struct spu_context *ctx); | 248 | void spu_forget(struct spu_context *ctx); |
245 | int spu_acquire_runnable(struct spu_context *ctx, unsigned long flags); | 249 | int __must_check spu_acquire_saved(struct spu_context *ctx); |
246 | void spu_acquire_saved(struct spu_context *ctx); | ||
247 | void spu_release_saved(struct spu_context *ctx); | 250 | void spu_release_saved(struct spu_context *ctx); |
248 | 251 | ||
252 | int spu_stopped(struct spu_context *ctx, u32 * stat); | ||
253 | void spu_del_from_rq(struct spu_context *ctx); | ||
249 | int spu_activate(struct spu_context *ctx, unsigned long flags); | 254 | int spu_activate(struct spu_context *ctx, unsigned long flags); |
250 | void spu_deactivate(struct spu_context *ctx); | 255 | void spu_deactivate(struct spu_context *ctx); |
251 | void spu_yield(struct spu_context *ctx); | 256 | void spu_yield(struct spu_context *ctx); |
@@ -279,7 +284,9 @@ extern char *isolated_loader; | |||
279 | } \ | 284 | } \ |
280 | spu_release(ctx); \ | 285 | spu_release(ctx); \ |
281 | schedule(); \ | 286 | schedule(); \ |
282 | spu_acquire(ctx); \ | 287 | __ret = spu_acquire(ctx); \ |
288 | if (__ret) \ | ||
289 | break; \ | ||
283 | } \ | 290 | } \ |
284 | finish_wait(&(wq), &__wait); \ | 291 | finish_wait(&(wq), &__wait); \ |
285 | __ret; \ | 292 | __ret; \ |
@@ -306,41 +313,16 @@ struct spufs_coredump_reader { | |||
306 | extern struct spufs_coredump_reader spufs_coredump_read[]; | 313 | extern struct spufs_coredump_reader spufs_coredump_read[]; |
307 | extern int spufs_coredump_num_notes; | 314 | extern int spufs_coredump_num_notes; |
308 | 315 | ||
309 | /* | 316 | extern int spu_init_csa(struct spu_state *csa); |
310 | * This function is a little bit too large for an inline, but | 317 | extern void spu_fini_csa(struct spu_state *csa); |
311 | * as fault.c is built into the kernel we can't move it out of | 318 | extern int spu_save(struct spu_state *prev, struct spu *spu); |
312 | * line. | 319 | extern int spu_restore(struct spu_state *new, struct spu *spu); |
313 | */ | 320 | extern int spu_switch(struct spu_state *prev, struct spu_state *new, |
314 | static inline void spuctx_switch_state(struct spu_context *ctx, | 321 | struct spu *spu); |
315 | enum spu_utilization_state new_state) | 322 | extern int spu_alloc_lscsa(struct spu_state *csa); |
316 | { | 323 | extern void spu_free_lscsa(struct spu_state *csa); |
317 | unsigned long long curtime; | 324 | |
318 | signed long long delta; | 325 | extern void spuctx_switch_state(struct spu_context *ctx, |
319 | struct timespec ts; | 326 | enum spu_utilization_state new_state); |
320 | struct spu *spu; | ||
321 | enum spu_utilization_state old_state; | ||
322 | |||
323 | ktime_get_ts(&ts); | ||
324 | curtime = timespec_to_ns(&ts); | ||
325 | delta = curtime - ctx->stats.tstamp; | ||
326 | |||
327 | WARN_ON(!mutex_is_locked(&ctx->state_mutex)); | ||
328 | WARN_ON(delta < 0); | ||
329 | |||
330 | spu = ctx->spu; | ||
331 | old_state = ctx->stats.util_state; | ||
332 | ctx->stats.util_state = new_state; | ||
333 | ctx->stats.tstamp = curtime; | ||
334 | |||
335 | /* | ||
336 | * Update the physical SPU utilization statistics. | ||
337 | */ | ||
338 | if (spu) { | ||
339 | ctx->stats.times[old_state] += delta; | ||
340 | spu->stats.times[old_state] += delta; | ||
341 | spu->stats.util_state = new_state; | ||
342 | spu->stats.tstamp = curtime; | ||
343 | } | ||
344 | } | ||
345 | 327 | ||
346 | #endif | 328 | #endif |
diff --git a/arch/powerpc/platforms/cell/spufs/switch.c b/arch/powerpc/platforms/cell/spufs/switch.c index 3d64c81cc6e2..6063c88c26d2 100644 --- a/arch/powerpc/platforms/cell/spufs/switch.c +++ b/arch/powerpc/platforms/cell/spufs/switch.c | |||
@@ -48,6 +48,8 @@ | |||
48 | #include <asm/spu_csa.h> | 48 | #include <asm/spu_csa.h> |
49 | #include <asm/mmu_context.h> | 49 | #include <asm/mmu_context.h> |
50 | 50 | ||
51 | #include "spufs.h" | ||
52 | |||
51 | #include "spu_save_dump.h" | 53 | #include "spu_save_dump.h" |
52 | #include "spu_restore_dump.h" | 54 | #include "spu_restore_dump.h" |
53 | 55 | ||
@@ -691,35 +693,9 @@ static inline void resume_mfc_queue(struct spu_state *csa, struct spu *spu) | |||
691 | out_be64(&priv2->mfc_control_RW, MFC_CNTL_RESUME_DMA_QUEUE); | 693 | out_be64(&priv2->mfc_control_RW, MFC_CNTL_RESUME_DMA_QUEUE); |
692 | } | 694 | } |
693 | 695 | ||
694 | static inline void get_kernel_slb(u64 ea, u64 slb[2]) | 696 | static inline void setup_mfc_slbs(struct spu_state *csa, struct spu *spu, |
697 | unsigned int *code, int code_size) | ||
695 | { | 698 | { |
696 | u64 llp; | ||
697 | |||
698 | if (REGION_ID(ea) == KERNEL_REGION_ID) | ||
699 | llp = mmu_psize_defs[mmu_linear_psize].sllp; | ||
700 | else | ||
701 | llp = mmu_psize_defs[mmu_virtual_psize].sllp; | ||
702 | slb[0] = (get_kernel_vsid(ea, MMU_SEGSIZE_256M) << SLB_VSID_SHIFT) | | ||
703 | SLB_VSID_KERNEL | llp; | ||
704 | slb[1] = (ea & ESID_MASK) | SLB_ESID_V; | ||
705 | } | ||
706 | |||
707 | static inline void load_mfc_slb(struct spu *spu, u64 slb[2], int slbe) | ||
708 | { | ||
709 | struct spu_priv2 __iomem *priv2 = spu->priv2; | ||
710 | |||
711 | out_be64(&priv2->slb_index_W, slbe); | ||
712 | eieio(); | ||
713 | out_be64(&priv2->slb_vsid_RW, slb[0]); | ||
714 | out_be64(&priv2->slb_esid_RW, slb[1]); | ||
715 | eieio(); | ||
716 | } | ||
717 | |||
718 | static inline void setup_mfc_slbs(struct spu_state *csa, struct spu *spu) | ||
719 | { | ||
720 | u64 code_slb[2]; | ||
721 | u64 lscsa_slb[2]; | ||
722 | |||
723 | /* Save, Step 47: | 699 | /* Save, Step 47: |
724 | * Restore, Step 30. | 700 | * Restore, Step 30. |
725 | * If MFC_SR1[R]=1, write 0 to SLB_Invalidate_All | 701 | * If MFC_SR1[R]=1, write 0 to SLB_Invalidate_All |
@@ -735,11 +711,7 @@ static inline void setup_mfc_slbs(struct spu_state *csa, struct spu *spu) | |||
735 | * translation is desired by OS environment). | 711 | * translation is desired by OS environment). |
736 | */ | 712 | */ |
737 | spu_invalidate_slbs(spu); | 713 | spu_invalidate_slbs(spu); |
738 | get_kernel_slb((unsigned long)&spu_save_code[0], code_slb); | 714 | spu_setup_kernel_slbs(spu, csa->lscsa, code, code_size); |
739 | get_kernel_slb((unsigned long)csa->lscsa, lscsa_slb); | ||
740 | load_mfc_slb(spu, code_slb, 0); | ||
741 | if ((lscsa_slb[0] != code_slb[0]) || (lscsa_slb[1] != code_slb[1])) | ||
742 | load_mfc_slb(spu, lscsa_slb, 1); | ||
743 | } | 715 | } |
744 | 716 | ||
745 | static inline void set_switch_active(struct spu_state *csa, struct spu *spu) | 717 | static inline void set_switch_active(struct spu_state *csa, struct spu *spu) |
@@ -768,9 +740,9 @@ static inline void enable_interrupts(struct spu_state *csa, struct spu *spu) | |||
768 | * (translation) interrupts. | 740 | * (translation) interrupts. |
769 | */ | 741 | */ |
770 | spin_lock_irq(&spu->register_lock); | 742 | spin_lock_irq(&spu->register_lock); |
771 | spu_int_stat_clear(spu, 0, ~0ul); | 743 | spu_int_stat_clear(spu, 0, CLASS0_INTR_MASK); |
772 | spu_int_stat_clear(spu, 1, ~0ul); | 744 | spu_int_stat_clear(spu, 1, CLASS1_INTR_MASK); |
773 | spu_int_stat_clear(spu, 2, ~0ul); | 745 | spu_int_stat_clear(spu, 2, CLASS2_INTR_MASK); |
774 | spu_int_mask_set(spu, 0, 0ul); | 746 | spu_int_mask_set(spu, 0, 0ul); |
775 | spu_int_mask_set(spu, 1, class1_mask); | 747 | spu_int_mask_set(spu, 1, class1_mask); |
776 | spu_int_mask_set(spu, 2, 0ul); | 748 | spu_int_mask_set(spu, 2, 0ul); |
@@ -927,8 +899,8 @@ static inline void wait_tag_complete(struct spu_state *csa, struct spu *spu) | |||
927 | POLL_WHILE_FALSE(in_be32(&prob->dma_tagstatus_R) & mask); | 899 | POLL_WHILE_FALSE(in_be32(&prob->dma_tagstatus_R) & mask); |
928 | 900 | ||
929 | local_irq_save(flags); | 901 | local_irq_save(flags); |
930 | spu_int_stat_clear(spu, 0, ~(0ul)); | 902 | spu_int_stat_clear(spu, 0, CLASS0_INTR_MASK); |
931 | spu_int_stat_clear(spu, 2, ~(0ul)); | 903 | spu_int_stat_clear(spu, 2, CLASS2_INTR_MASK); |
932 | local_irq_restore(flags); | 904 | local_irq_restore(flags); |
933 | } | 905 | } |
934 | 906 | ||
@@ -946,8 +918,8 @@ static inline void wait_spu_stopped(struct spu_state *csa, struct spu *spu) | |||
946 | POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING); | 918 | POLL_WHILE_TRUE(in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING); |
947 | 919 | ||
948 | local_irq_save(flags); | 920 | local_irq_save(flags); |
949 | spu_int_stat_clear(spu, 0, ~(0ul)); | 921 | spu_int_stat_clear(spu, 0, CLASS0_INTR_MASK); |
950 | spu_int_stat_clear(spu, 2, ~(0ul)); | 922 | spu_int_stat_clear(spu, 2, CLASS2_INTR_MASK); |
951 | local_irq_restore(flags); | 923 | local_irq_restore(flags); |
952 | } | 924 | } |
953 | 925 | ||
@@ -1423,9 +1395,9 @@ static inline void clear_interrupts(struct spu_state *csa, struct spu *spu) | |||
1423 | spu_int_mask_set(spu, 0, 0ul); | 1395 | spu_int_mask_set(spu, 0, 0ul); |
1424 | spu_int_mask_set(spu, 1, 0ul); | 1396 | spu_int_mask_set(spu, 1, 0ul); |
1425 | spu_int_mask_set(spu, 2, 0ul); | 1397 | spu_int_mask_set(spu, 2, 0ul); |
1426 | spu_int_stat_clear(spu, 0, ~0ul); | 1398 | spu_int_stat_clear(spu, 0, CLASS0_INTR_MASK); |
1427 | spu_int_stat_clear(spu, 1, ~0ul); | 1399 | spu_int_stat_clear(spu, 1, CLASS1_INTR_MASK); |
1428 | spu_int_stat_clear(spu, 2, ~0ul); | 1400 | spu_int_stat_clear(spu, 2, CLASS2_INTR_MASK); |
1429 | spin_unlock_irq(&spu->register_lock); | 1401 | spin_unlock_irq(&spu->register_lock); |
1430 | } | 1402 | } |
1431 | 1403 | ||
@@ -1866,7 +1838,8 @@ static void save_lscsa(struct spu_state *prev, struct spu *spu) | |||
1866 | */ | 1838 | */ |
1867 | 1839 | ||
1868 | resume_mfc_queue(prev, spu); /* Step 46. */ | 1840 | resume_mfc_queue(prev, spu); /* Step 46. */ |
1869 | setup_mfc_slbs(prev, spu); /* Step 47. */ | 1841 | /* Step 47. */ |
1842 | setup_mfc_slbs(prev, spu, spu_save_code, sizeof(spu_save_code)); | ||
1870 | set_switch_active(prev, spu); /* Step 48. */ | 1843 | set_switch_active(prev, spu); /* Step 48. */ |
1871 | enable_interrupts(prev, spu); /* Step 49. */ | 1844 | enable_interrupts(prev, spu); /* Step 49. */ |
1872 | save_ls_16kb(prev, spu); /* Step 50. */ | 1845 | save_ls_16kb(prev, spu); /* Step 50. */ |
@@ -1971,7 +1944,8 @@ static void restore_lscsa(struct spu_state *next, struct spu *spu) | |||
1971 | setup_spu_status_part1(next, spu); /* Step 27. */ | 1944 | setup_spu_status_part1(next, spu); /* Step 27. */ |
1972 | setup_spu_status_part2(next, spu); /* Step 28. */ | 1945 | setup_spu_status_part2(next, spu); /* Step 28. */ |
1973 | restore_mfc_rag(next, spu); /* Step 29. */ | 1946 | restore_mfc_rag(next, spu); /* Step 29. */ |
1974 | setup_mfc_slbs(next, spu); /* Step 30. */ | 1947 | /* Step 30. */ |
1948 | setup_mfc_slbs(next, spu, spu_restore_code, sizeof(spu_restore_code)); | ||
1975 | set_spu_npc(next, spu); /* Step 31. */ | 1949 | set_spu_npc(next, spu); /* Step 31. */ |
1976 | set_signot1(next, spu); /* Step 32. */ | 1950 | set_signot1(next, spu); /* Step 32. */ |
1977 | set_signot2(next, spu); /* Step 33. */ | 1951 | set_signot2(next, spu); /* Step 33. */ |
@@ -2103,10 +2077,6 @@ int spu_save(struct spu_state *prev, struct spu *spu) | |||
2103 | int rc; | 2077 | int rc; |
2104 | 2078 | ||
2105 | acquire_spu_lock(spu); /* Step 1. */ | 2079 | acquire_spu_lock(spu); /* Step 1. */ |
2106 | prev->dar = spu->dar; | ||
2107 | prev->dsisr = spu->dsisr; | ||
2108 | spu->dar = 0; | ||
2109 | spu->dsisr = 0; | ||
2110 | rc = __do_spu_save(prev, spu); /* Steps 2-53. */ | 2080 | rc = __do_spu_save(prev, spu); /* Steps 2-53. */ |
2111 | release_spu_lock(spu); | 2081 | release_spu_lock(spu); |
2112 | if (rc != 0 && rc != 2 && rc != 6) { | 2082 | if (rc != 0 && rc != 2 && rc != 6) { |
@@ -2133,9 +2103,6 @@ int spu_restore(struct spu_state *new, struct spu *spu) | |||
2133 | acquire_spu_lock(spu); | 2103 | acquire_spu_lock(spu); |
2134 | harvest(NULL, spu); | 2104 | harvest(NULL, spu); |
2135 | spu->slb_replace = 0; | 2105 | spu->slb_replace = 0; |
2136 | new->dar = 0; | ||
2137 | new->dsisr = 0; | ||
2138 | spu->class_0_pending = 0; | ||
2139 | rc = __do_spu_restore(new, spu); | 2106 | rc = __do_spu_restore(new, spu); |
2140 | release_spu_lock(spu); | 2107 | release_spu_lock(spu); |
2141 | if (rc) { | 2108 | if (rc) { |
@@ -2215,10 +2182,8 @@ int spu_init_csa(struct spu_state *csa) | |||
2215 | 2182 | ||
2216 | return 0; | 2183 | return 0; |
2217 | } | 2184 | } |
2218 | EXPORT_SYMBOL_GPL(spu_init_csa); | ||
2219 | 2185 | ||
2220 | void spu_fini_csa(struct spu_state *csa) | 2186 | void spu_fini_csa(struct spu_state *csa) |
2221 | { | 2187 | { |
2222 | spu_free_lscsa(csa); | 2188 | spu_free_lscsa(csa); |
2223 | } | 2189 | } |
2224 | EXPORT_SYMBOL_GPL(spu_fini_csa); | ||
diff --git a/arch/powerpc/platforms/celleb/Kconfig b/arch/powerpc/platforms/celleb/Kconfig index 04748d410fc9..372891edcdd2 100644 --- a/arch/powerpc/platforms/celleb/Kconfig +++ b/arch/powerpc/platforms/celleb/Kconfig | |||
@@ -2,6 +2,8 @@ config PPC_CELLEB | |||
2 | bool "Toshiba's Cell Reference Set 'Celleb' Architecture" | 2 | bool "Toshiba's Cell Reference Set 'Celleb' Architecture" |
3 | depends on PPC_MULTIPLATFORM && PPC64 | 3 | depends on PPC_MULTIPLATFORM && PPC64 |
4 | select PPC_CELL | 4 | select PPC_CELL |
5 | select PPC_CELL_NATIVE | ||
6 | select PPC_RTAS | ||
5 | select PPC_INDIRECT_IO | 7 | select PPC_INDIRECT_IO |
6 | select PPC_OF_PLATFORM_PCI | 8 | select PPC_OF_PLATFORM_PCI |
7 | select HAS_TXX9_SERIAL | 9 | select HAS_TXX9_SERIAL |
diff --git a/arch/powerpc/platforms/celleb/io-workarounds.c b/arch/powerpc/platforms/celleb/io-workarounds.c index 2b912140bcbb..423339be1bac 100644 --- a/arch/powerpc/platforms/celleb/io-workarounds.c +++ b/arch/powerpc/platforms/celleb/io-workarounds.c | |||
@@ -22,6 +22,7 @@ | |||
22 | 22 | ||
23 | #undef DEBUG | 23 | #undef DEBUG |
24 | 24 | ||
25 | #include <linux/of.h> | ||
25 | #include <linux/of_device.h> | 26 | #include <linux/of_device.h> |
26 | #include <linux/irq.h> | 27 | #include <linux/irq.h> |
27 | 28 | ||
@@ -222,7 +223,7 @@ void __init celleb_pci_add_one(struct pci_controller *phb, | |||
222 | void (*dummy_read)(struct pci_controller *)) | 223 | void (*dummy_read)(struct pci_controller *)) |
223 | { | 224 | { |
224 | struct celleb_pci_bus *bus = &celleb_pci_busses[celleb_pci_count]; | 225 | struct celleb_pci_bus *bus = &celleb_pci_busses[celleb_pci_count]; |
225 | struct device_node *np = phb->arch_data; | 226 | struct device_node *np = phb->dn; |
226 | 227 | ||
227 | if (celleb_pci_count >= MAX_CELLEB_PCI_BUS) { | 228 | if (celleb_pci_count >= MAX_CELLEB_PCI_BUS) { |
228 | printk(KERN_ERR "Too many pci bridges, workarounds" | 229 | printk(KERN_ERR "Too many pci bridges, workarounds" |
@@ -256,13 +257,13 @@ int __init celleb_pci_workaround_init(void) | |||
256 | 257 | ||
257 | celleb_dummy_page_va = kmalloc(PAGE_SIZE, GFP_KERNEL); | 258 | celleb_dummy_page_va = kmalloc(PAGE_SIZE, GFP_KERNEL); |
258 | if (!celleb_dummy_page_va) { | 259 | if (!celleb_dummy_page_va) { |
259 | printk(KERN_ERR "Celleb: dummy read disabled." | 260 | printk(KERN_ERR "Celleb: dummy read disabled. " |
260 | "Alloc celleb_dummy_page_va failed\n"); | 261 | "Alloc celleb_dummy_page_va failed\n"); |
261 | return 1; | 262 | return 1; |
262 | } | 263 | } |
263 | 264 | ||
264 | list_for_each_entry(phb, &hose_list, list_node) { | 265 | list_for_each_entry(phb, &hose_list, list_node) { |
265 | node = phb->arch_data; | 266 | node = phb->dn; |
266 | match = of_match_node(celleb_pci_workaround_match, node); | 267 | match = of_match_node(celleb_pci_workaround_match, node); |
267 | 268 | ||
268 | if (match) { | 269 | if (match) { |
diff --git a/arch/powerpc/platforms/celleb/iommu.c b/arch/powerpc/platforms/celleb/iommu.c index 755d869d8553..93b0efddd658 100644 --- a/arch/powerpc/platforms/celleb/iommu.c +++ b/arch/powerpc/platforms/celleb/iommu.c | |||
@@ -22,8 +22,9 @@ | |||
22 | #include <linux/init.h> | 22 | #include <linux/init.h> |
23 | #include <linux/dma-mapping.h> | 23 | #include <linux/dma-mapping.h> |
24 | #include <linux/pci.h> | 24 | #include <linux/pci.h> |
25 | #include <linux/of_platform.h> | ||
25 | 26 | ||
26 | #include <asm/of_platform.h> | 27 | #include <asm/machdep.h> |
27 | 28 | ||
28 | #include "beat_wrapper.h" | 29 | #include "beat_wrapper.h" |
29 | 30 | ||
@@ -51,6 +52,8 @@ static int __init find_dma_window(u64 *io_space_id, u64 *ioid, | |||
51 | return 0; | 52 | return 0; |
52 | } | 53 | } |
53 | 54 | ||
55 | static unsigned long celleb_dma_direct_offset; | ||
56 | |||
54 | static void __init celleb_init_direct_mapping(void) | 57 | static void __init celleb_init_direct_mapping(void) |
55 | { | 58 | { |
56 | u64 lpar_addr, io_addr; | 59 | u64 lpar_addr, io_addr; |
@@ -68,7 +71,18 @@ static void __init celleb_init_direct_mapping(void) | |||
68 | ioid, DMA_FLAGS); | 71 | ioid, DMA_FLAGS); |
69 | } | 72 | } |
70 | 73 | ||
71 | dma_direct_offset = dma_base; | 74 | celleb_dma_direct_offset = dma_base; |
75 | } | ||
76 | |||
77 | static void celleb_dma_dev_setup(struct device *dev) | ||
78 | { | ||
79 | dev->archdata.dma_ops = get_pci_dma_ops(); | ||
80 | dev->archdata.dma_data = (void *)celleb_dma_direct_offset; | ||
81 | } | ||
82 | |||
83 | static void celleb_pci_dma_dev_setup(struct pci_dev *pdev) | ||
84 | { | ||
85 | celleb_dma_dev_setup(&pdev->dev); | ||
72 | } | 86 | } |
73 | 87 | ||
74 | static int celleb_of_bus_notify(struct notifier_block *nb, | 88 | static int celleb_of_bus_notify(struct notifier_block *nb, |
@@ -80,7 +94,7 @@ static int celleb_of_bus_notify(struct notifier_block *nb, | |||
80 | if (action != BUS_NOTIFY_ADD_DEVICE) | 94 | if (action != BUS_NOTIFY_ADD_DEVICE) |
81 | return 0; | 95 | return 0; |
82 | 96 | ||
83 | dev->archdata.dma_ops = get_pci_dma_ops(); | 97 | celleb_dma_dev_setup(dev); |
84 | 98 | ||
85 | return 0; | 99 | return 0; |
86 | } | 100 | } |
@@ -91,14 +105,12 @@ static struct notifier_block celleb_of_bus_notifier = { | |||
91 | 105 | ||
92 | static int __init celleb_init_iommu(void) | 106 | static int __init celleb_init_iommu(void) |
93 | { | 107 | { |
94 | if (!machine_is(celleb)) | ||
95 | return -ENODEV; | ||
96 | |||
97 | celleb_init_direct_mapping(); | 108 | celleb_init_direct_mapping(); |
98 | set_pci_dma_ops(&dma_direct_ops); | 109 | set_pci_dma_ops(&dma_direct_ops); |
110 | ppc_md.pci_dma_dev_setup = celleb_pci_dma_dev_setup; | ||
99 | bus_register_notifier(&of_platform_bus_type, &celleb_of_bus_notifier); | 111 | bus_register_notifier(&of_platform_bus_type, &celleb_of_bus_notifier); |
100 | 112 | ||
101 | return 0; | 113 | return 0; |
102 | } | 114 | } |
103 | 115 | ||
104 | arch_initcall(celleb_init_iommu); | 116 | machine_arch_initcall(celleb_beat, celleb_init_iommu); |
diff --git a/arch/powerpc/platforms/celleb/pci.c b/arch/powerpc/platforms/celleb/pci.c index 6bc32fda7a6b..51b390d34e4d 100644 --- a/arch/powerpc/platforms/celleb/pci.c +++ b/arch/powerpc/platforms/celleb/pci.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/init.h> | 31 | #include <linux/init.h> |
32 | #include <linux/bootmem.h> | 32 | #include <linux/bootmem.h> |
33 | #include <linux/pci_regs.h> | 33 | #include <linux/pci_regs.h> |
34 | #include <linux/of.h> | ||
34 | #include <linux/of_device.h> | 35 | #include <linux/of_device.h> |
35 | 36 | ||
36 | #include <asm/io.h> | 37 | #include <asm/io.h> |
@@ -138,8 +139,6 @@ static void celleb_config_read_fake(unsigned char *config, int where, | |||
138 | *val = celleb_fake_config_readl(p); | 139 | *val = celleb_fake_config_readl(p); |
139 | break; | 140 | break; |
140 | } | 141 | } |
141 | |||
142 | return; | ||
143 | } | 142 | } |
144 | 143 | ||
145 | static void celleb_config_write_fake(unsigned char *config, int where, | 144 | static void celleb_config_write_fake(unsigned char *config, int where, |
@@ -158,7 +157,6 @@ static void celleb_config_write_fake(unsigned char *config, int where, | |||
158 | celleb_fake_config_writel(val, p); | 157 | celleb_fake_config_writel(val, p); |
159 | break; | 158 | break; |
160 | } | 159 | } |
161 | return; | ||
162 | } | 160 | } |
163 | 161 | ||
164 | static int celleb_fake_pci_read_config(struct pci_bus *bus, | 162 | static int celleb_fake_pci_read_config(struct pci_bus *bus, |
@@ -351,6 +349,10 @@ static int __init celleb_setup_fake_pci_device(struct device_node *node, | |||
351 | wi1 = of_get_property(node, "vendor-id", NULL); | 349 | wi1 = of_get_property(node, "vendor-id", NULL); |
352 | wi2 = of_get_property(node, "class-code", NULL); | 350 | wi2 = of_get_property(node, "class-code", NULL); |
353 | wi3 = of_get_property(node, "revision-id", NULL); | 351 | wi3 = of_get_property(node, "revision-id", NULL); |
352 | if (!wi0 || !wi1 || !wi2 || !wi3) { | ||
353 | printk(KERN_ERR "PCI: Missing device tree properties.\n"); | ||
354 | goto error; | ||
355 | } | ||
354 | 356 | ||
355 | celleb_config_write_fake(*config, PCI_DEVICE_ID, 2, wi0[0] & 0xffff); | 357 | celleb_config_write_fake(*config, PCI_DEVICE_ID, 2, wi0[0] & 0xffff); |
356 | celleb_config_write_fake(*config, PCI_VENDOR_ID, 2, wi1[0] & 0xffff); | 358 | celleb_config_write_fake(*config, PCI_VENDOR_ID, 2, wi1[0] & 0xffff); |
@@ -372,6 +374,10 @@ static int __init celleb_setup_fake_pci_device(struct device_node *node, | |||
372 | celleb_setup_pci_base_addrs(hose, devno, fn, num_base_addr); | 374 | celleb_setup_pci_base_addrs(hose, devno, fn, num_base_addr); |
373 | 375 | ||
374 | li = of_get_property(node, "interrupts", &rlen); | 376 | li = of_get_property(node, "interrupts", &rlen); |
377 | if (!li) { | ||
378 | printk(KERN_ERR "PCI: interrupts not found.\n"); | ||
379 | goto error; | ||
380 | } | ||
375 | val = li[0]; | 381 | val = li[0]; |
376 | celleb_config_write_fake(*config, PCI_INTERRUPT_PIN, 1, 1); | 382 | celleb_config_write_fake(*config, PCI_INTERRUPT_PIN, 1, 1); |
377 | celleb_config_write_fake(*config, PCI_INTERRUPT_LINE, 1, val); | 383 | celleb_config_write_fake(*config, PCI_INTERRUPT_LINE, 1, val); |
@@ -475,7 +481,7 @@ static struct of_device_id celleb_phb_match[] __initdata = { | |||
475 | 481 | ||
476 | int __init celleb_setup_phb(struct pci_controller *phb) | 482 | int __init celleb_setup_phb(struct pci_controller *phb) |
477 | { | 483 | { |
478 | struct device_node *dev = phb->arch_data; | 484 | struct device_node *dev = phb->dn; |
479 | const struct of_device_id *match; | 485 | const struct of_device_id *match; |
480 | int (*setup_func)(struct device_node *, struct pci_controller *); | 486 | int (*setup_func)(struct device_node *, struct pci_controller *); |
481 | 487 | ||
diff --git a/arch/powerpc/platforms/celleb/scc_epci.c b/arch/powerpc/platforms/celleb/scc_epci.c index 9d076426676c..a3c7cfbcb323 100644 --- a/arch/powerpc/platforms/celleb/scc_epci.c +++ b/arch/powerpc/platforms/celleb/scc_epci.c | |||
@@ -95,7 +95,7 @@ void __init epci_workaround_init(struct pci_controller *hose) | |||
95 | private->dummy_page_da = dma_map_single(hose->parent, | 95 | private->dummy_page_da = dma_map_single(hose->parent, |
96 | celleb_dummy_page_va, PAGE_SIZE, DMA_FROM_DEVICE); | 96 | celleb_dummy_page_va, PAGE_SIZE, DMA_FROM_DEVICE); |
97 | if (private->dummy_page_da == DMA_ERROR_CODE) { | 97 | if (private->dummy_page_da == DMA_ERROR_CODE) { |
98 | printk(KERN_ERR "EPCI: dummy read disabled." | 98 | printk(KERN_ERR "EPCI: dummy read disabled. " |
99 | "Map dummy page failed.\n"); | 99 | "Map dummy page failed.\n"); |
100 | return; | 100 | return; |
101 | } | 101 | } |
diff --git a/arch/powerpc/platforms/celleb/scc_uhc.c b/arch/powerpc/platforms/celleb/scc_uhc.c index b59c38a06e3e..cb4307994087 100644 --- a/arch/powerpc/platforms/celleb/scc_uhc.c +++ b/arch/powerpc/platforms/celleb/scc_uhc.c | |||
@@ -47,7 +47,8 @@ static void enable_scc_uhc(struct pci_dev *dev) | |||
47 | u32 val = 0; | 47 | u32 val = 0; |
48 | int i; | 48 | int i; |
49 | 49 | ||
50 | if (!machine_is(celleb)) | 50 | if (!machine_is(celleb_beat) && |
51 | !machine_is(celleb_native)) | ||
51 | return; | 52 | return; |
52 | 53 | ||
53 | uhc_base = ioremap(pci_resource_start(dev, 0), | 54 | uhc_base = ioremap(pci_resource_start(dev, 0), |
diff --git a/arch/powerpc/platforms/celleb/setup.c b/arch/powerpc/platforms/celleb/setup.c index ddfb35ae741f..f27ae1e3fb58 100644 --- a/arch/powerpc/platforms/celleb/setup.c +++ b/arch/powerpc/platforms/celleb/setup.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include <linux/seq_file.h> | 40 | #include <linux/seq_file.h> |
41 | #include <linux/root_dev.h> | 41 | #include <linux/root_dev.h> |
42 | #include <linux/console.h> | 42 | #include <linux/console.h> |
43 | #include <linux/of_platform.h> | ||
43 | 44 | ||
44 | #include <asm/mmu.h> | 45 | #include <asm/mmu.h> |
45 | #include <asm/processor.h> | 46 | #include <asm/processor.h> |
@@ -52,12 +53,16 @@ | |||
52 | #include <asm/time.h> | 53 | #include <asm/time.h> |
53 | #include <asm/spu_priv1.h> | 54 | #include <asm/spu_priv1.h> |
54 | #include <asm/firmware.h> | 55 | #include <asm/firmware.h> |
55 | #include <asm/of_platform.h> | 56 | #include <asm/rtas.h> |
57 | #include <asm/cell-regs.h> | ||
56 | 58 | ||
57 | #include "interrupt.h" | 59 | #include "interrupt.h" |
58 | #include "beat_wrapper.h" | 60 | #include "beat_wrapper.h" |
59 | #include "beat.h" | 61 | #include "beat.h" |
60 | #include "pci.h" | 62 | #include "pci.h" |
63 | #include "../cell/interrupt.h" | ||
64 | #include "../cell/pervasive.h" | ||
65 | #include "../cell/ras.h" | ||
61 | 66 | ||
62 | static char celleb_machine_type[128] = "Celleb"; | 67 | static char celleb_machine_type[128] = "Celleb"; |
63 | 68 | ||
@@ -88,61 +93,122 @@ static void celleb_progress(char *s, unsigned short hex) | |||
88 | printk("*** %04x : %s\n", hex, s ? s : ""); | 93 | printk("*** %04x : %s\n", hex, s ? s : ""); |
89 | } | 94 | } |
90 | 95 | ||
91 | static void __init celleb_setup_arch(void) | 96 | static void __init celleb_setup_arch_common(void) |
97 | { | ||
98 | /* init to some ~sane value until calibrate_delay() runs */ | ||
99 | loops_per_jiffy = 50000000; | ||
100 | |||
101 | #ifdef CONFIG_DUMMY_CONSOLE | ||
102 | conswitchp = &dummy_con; | ||
103 | #endif | ||
104 | } | ||
105 | |||
106 | static struct of_device_id celleb_bus_ids[] __initdata = { | ||
107 | { .type = "scc", }, | ||
108 | { .type = "ioif", }, /* old style */ | ||
109 | {}, | ||
110 | }; | ||
111 | |||
112 | static int __init celleb_publish_devices(void) | ||
113 | { | ||
114 | /* Publish OF platform devices for southbridge IOs */ | ||
115 | of_platform_bus_probe(NULL, celleb_bus_ids, NULL); | ||
116 | |||
117 | celleb_pci_workaround_init(); | ||
118 | |||
119 | return 0; | ||
120 | } | ||
121 | machine_device_initcall(celleb_beat, celleb_publish_devices); | ||
122 | machine_device_initcall(celleb_native, celleb_publish_devices); | ||
123 | |||
124 | |||
125 | /* | ||
126 | * functions for Celleb-Beat | ||
127 | */ | ||
128 | static void __init celleb_setup_arch_beat(void) | ||
92 | { | 129 | { |
93 | #ifdef CONFIG_SPU_BASE | 130 | #ifdef CONFIG_SPU_BASE |
94 | spu_priv1_ops = &spu_priv1_beat_ops; | 131 | spu_priv1_ops = &spu_priv1_beat_ops; |
95 | spu_management_ops = &spu_management_of_ops; | 132 | spu_management_ops = &spu_management_of_ops; |
96 | #endif | 133 | #endif |
97 | 134 | ||
98 | #ifdef CONFIG_SMP | 135 | #ifdef CONFIG_SMP |
99 | smp_init_celleb(); | 136 | smp_init_celleb(); |
100 | #endif | 137 | #endif |
101 | 138 | ||
102 | /* init to some ~sane value until calibrate_delay() runs */ | 139 | celleb_setup_arch_common(); |
103 | loops_per_jiffy = 50000000; | ||
104 | |||
105 | #ifdef CONFIG_DUMMY_CONSOLE | ||
106 | conswitchp = &dummy_con; | ||
107 | #endif | ||
108 | } | 140 | } |
109 | 141 | ||
110 | static int __init celleb_probe(void) | 142 | static int __init celleb_probe_beat(void) |
111 | { | 143 | { |
112 | unsigned long root = of_get_flat_dt_root(); | 144 | unsigned long root = of_get_flat_dt_root(); |
113 | 145 | ||
114 | if (!of_flat_dt_is_compatible(root, "Beat")) | 146 | if (!of_flat_dt_is_compatible(root, "Beat")) |
115 | return 0; | 147 | return 0; |
116 | 148 | ||
117 | powerpc_firmware_features |= FW_FEATURE_CELLEB_POSSIBLE; | 149 | powerpc_firmware_features |= FW_FEATURE_CELLEB_ALWAYS |
150 | | FW_FEATURE_BEAT | FW_FEATURE_LPAR; | ||
118 | hpte_init_beat_v3(); | 151 | hpte_init_beat_v3(); |
152 | |||
119 | return 1; | 153 | return 1; |
120 | } | 154 | } |
121 | 155 | ||
122 | static struct of_device_id celleb_bus_ids[] __initdata = { | ||
123 | { .type = "scc", }, | ||
124 | { .type = "ioif", }, /* old style */ | ||
125 | {}, | ||
126 | }; | ||
127 | 156 | ||
128 | static int __init celleb_publish_devices(void) | 157 | /* |
158 | * functions for Celleb-native | ||
159 | */ | ||
160 | static void __init celleb_init_IRQ_native(void) | ||
129 | { | 161 | { |
130 | if (!machine_is(celleb)) | 162 | iic_init_IRQ(); |
131 | return 0; | 163 | spider_init_IRQ(); |
164 | } | ||
132 | 165 | ||
133 | /* Publish OF platform devices for southbridge IOs */ | 166 | static void __init celleb_setup_arch_native(void) |
134 | of_platform_bus_probe(NULL, celleb_bus_ids, NULL); | 167 | { |
168 | #ifdef CONFIG_SPU_BASE | ||
169 | spu_priv1_ops = &spu_priv1_mmio_ops; | ||
170 | spu_management_ops = &spu_management_of_ops; | ||
171 | #endif | ||
135 | 172 | ||
136 | celleb_pci_workaround_init(); | 173 | cbe_regs_init(); |
137 | 174 | ||
138 | return 0; | 175 | #ifdef CONFIG_CBE_RAS |
176 | cbe_ras_init(); | ||
177 | #endif | ||
178 | |||
179 | #ifdef CONFIG_SMP | ||
180 | smp_init_cell(); | ||
181 | #endif | ||
182 | |||
183 | cbe_pervasive_init(); | ||
184 | |||
185 | /* XXX: nvram initialization should be added */ | ||
186 | |||
187 | celleb_setup_arch_common(); | ||
139 | } | 188 | } |
140 | device_initcall(celleb_publish_devices); | ||
141 | 189 | ||
142 | define_machine(celleb) { | 190 | static int __init celleb_probe_native(void) |
143 | .name = "Cell Reference Set", | 191 | { |
144 | .probe = celleb_probe, | 192 | unsigned long root = of_get_flat_dt_root(); |
145 | .setup_arch = celleb_setup_arch, | 193 | |
194 | if (of_flat_dt_is_compatible(root, "Beat") || | ||
195 | !of_flat_dt_is_compatible(root, "TOSHIBA,Celleb")) | ||
196 | return 0; | ||
197 | |||
198 | powerpc_firmware_features |= FW_FEATURE_CELLEB_ALWAYS; | ||
199 | hpte_init_native(); | ||
200 | |||
201 | return 1; | ||
202 | } | ||
203 | |||
204 | |||
205 | /* | ||
206 | * machine definitions | ||
207 | */ | ||
208 | define_machine(celleb_beat) { | ||
209 | .name = "Cell Reference Set (Beat)", | ||
210 | .probe = celleb_probe_beat, | ||
211 | .setup_arch = celleb_setup_arch_beat, | ||
146 | .show_cpuinfo = celleb_show_cpuinfo, | 212 | .show_cpuinfo = celleb_show_cpuinfo, |
147 | .restart = beat_restart, | 213 | .restart = beat_restart, |
148 | .power_off = beat_power_off, | 214 | .power_off = beat_power_off, |
@@ -167,3 +233,26 @@ define_machine(celleb) { | |||
167 | .machine_crash_shutdown = default_machine_crash_shutdown, | 233 | .machine_crash_shutdown = default_machine_crash_shutdown, |
168 | #endif | 234 | #endif |
169 | }; | 235 | }; |
236 | |||
237 | define_machine(celleb_native) { | ||
238 | .name = "Cell Reference Set (native)", | ||
239 | .probe = celleb_probe_native, | ||
240 | .setup_arch = celleb_setup_arch_native, | ||
241 | .show_cpuinfo = celleb_show_cpuinfo, | ||
242 | .restart = rtas_restart, | ||
243 | .power_off = rtas_power_off, | ||
244 | .halt = rtas_halt, | ||
245 | .get_boot_time = rtas_get_boot_time, | ||
246 | .get_rtc_time = rtas_get_rtc_time, | ||
247 | .set_rtc_time = rtas_set_rtc_time, | ||
248 | .calibrate_decr = generic_calibrate_decr, | ||
249 | .progress = celleb_progress, | ||
250 | .pci_probe_mode = celleb_pci_probe_mode, | ||
251 | .pci_setup_phb = celleb_setup_phb, | ||
252 | .init_IRQ = celleb_init_IRQ_native, | ||
253 | #ifdef CONFIG_KEXEC | ||
254 | .machine_kexec = default_machine_kexec, | ||
255 | .machine_kexec_prepare = default_machine_kexec_prepare, | ||
256 | .machine_crash_shutdown = default_machine_crash_shutdown, | ||
257 | #endif | ||
258 | }; | ||
diff --git a/arch/powerpc/platforms/chrp/pci.c b/arch/powerpc/platforms/chrp/pci.c index 0340a342f772..609c46db4a1b 100644 --- a/arch/powerpc/platforms/chrp/pci.c +++ b/arch/powerpc/platforms/chrp/pci.c | |||
@@ -198,7 +198,7 @@ static void __init setup_peg2(struct pci_controller *hose, struct device_node *d | |||
198 | printk ("RTAS supporting Pegasos OF not found, please upgrade" | 198 | printk ("RTAS supporting Pegasos OF not found, please upgrade" |
199 | " your firmware\n"); | 199 | " your firmware\n"); |
200 | } | 200 | } |
201 | pci_assign_all_buses = 1; | 201 | ppc_pci_flags |= PPC_PCI_REASSIGN_ALL_BUS; |
202 | /* keep the reference to the root node */ | 202 | /* keep the reference to the root node */ |
203 | } | 203 | } |
204 | 204 | ||
@@ -354,7 +354,7 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, | |||
354 | * mode as well. The same fixup must be done to the class-code property in | 354 | * mode as well. The same fixup must be done to the class-code property in |
355 | * the IDE node /pci@80000000/ide@C,1 | 355 | * the IDE node /pci@80000000/ide@C,1 |
356 | */ | 356 | */ |
357 | static void __devinit chrp_pci_fixup_vt8231_ata(struct pci_dev *viaide) | 357 | static void chrp_pci_fixup_vt8231_ata(struct pci_dev *viaide) |
358 | { | 358 | { |
359 | u8 progif; | 359 | u8 progif; |
360 | struct pci_dev *viaisa; | 360 | struct pci_dev *viaisa; |
@@ -375,4 +375,4 @@ static void __devinit chrp_pci_fixup_vt8231_ata(struct pci_dev *viaide) | |||
375 | 375 | ||
376 | pci_dev_put(viaisa); | 376 | pci_dev_put(viaisa); |
377 | } | 377 | } |
378 | DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1, chrp_pci_fixup_vt8231_ata); | 378 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1, chrp_pci_fixup_vt8231_ata); |
diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c index 59306261f5b2..116babbaaf81 100644 --- a/arch/powerpc/platforms/chrp/setup.c +++ b/arch/powerpc/platforms/chrp/setup.c | |||
@@ -115,7 +115,7 @@ void chrp_show_cpuinfo(struct seq_file *m) | |||
115 | seq_printf(m, "machine\t\t: CHRP %s\n", model); | 115 | seq_printf(m, "machine\t\t: CHRP %s\n", model); |
116 | 116 | ||
117 | /* longtrail (goldengate) stuff */ | 117 | /* longtrail (goldengate) stuff */ |
118 | if (!strncmp(model, "IBM,LongTrail", 13)) { | 118 | if (model && !strncmp(model, "IBM,LongTrail", 13)) { |
119 | /* VLSI VAS96011/12 `Golden Gate 2' */ | 119 | /* VLSI VAS96011/12 `Golden Gate 2' */ |
120 | /* Memory banks */ | 120 | /* Memory banks */ |
121 | sdramen = (in_le32(gg2_pci_config_base + GG2_PCI_DRAM_CTRL) | 121 | sdramen = (in_le32(gg2_pci_config_base + GG2_PCI_DRAM_CTRL) |
@@ -203,15 +203,20 @@ static void __init sio_fixup_irq(const char *name, u8 device, u8 level, | |||
203 | static void __init sio_init(void) | 203 | static void __init sio_init(void) |
204 | { | 204 | { |
205 | struct device_node *root; | 205 | struct device_node *root; |
206 | const char *model; | ||
206 | 207 | ||
207 | if ((root = of_find_node_by_path("/")) && | 208 | root = of_find_node_by_path("/"); |
208 | !strncmp(of_get_property(root, "model", NULL), | 209 | if (!root) |
209 | "IBM,LongTrail", 13)) { | 210 | return; |
211 | |||
212 | model = of_get_property(root, "model", NULL); | ||
213 | if (model && !strncmp(model, "IBM,LongTrail", 13)) { | ||
210 | /* logical device 0 (KBC/Keyboard) */ | 214 | /* logical device 0 (KBC/Keyboard) */ |
211 | sio_fixup_irq("keyboard", 0, 1, 2); | 215 | sio_fixup_irq("keyboard", 0, 1, 2); |
212 | /* select logical device 1 (KBC/Mouse) */ | 216 | /* select logical device 1 (KBC/Mouse) */ |
213 | sio_fixup_irq("mouse", 1, 12, 2); | 217 | sio_fixup_irq("mouse", 1, 12, 2); |
214 | } | 218 | } |
219 | |||
215 | of_node_put(root); | 220 | of_node_put(root); |
216 | } | 221 | } |
217 | 222 | ||
@@ -251,6 +256,57 @@ static void briq_restart(char *cmd) | |||
251 | for(;;); | 256 | for(;;); |
252 | } | 257 | } |
253 | 258 | ||
259 | /* | ||
260 | * Per default, input/output-device points to the keyboard/screen | ||
261 | * If no card is installed, the built-in serial port is used as a fallback. | ||
262 | * But unfortunately, the firmware does not connect /chosen/{stdin,stdout} | ||
263 | * the the built-in serial node. Instead, a /failsafe node is created. | ||
264 | */ | ||
265 | static void chrp_init_early(void) | ||
266 | { | ||
267 | struct device_node *node; | ||
268 | const char *property; | ||
269 | |||
270 | if (strstr(cmd_line, "console=")) | ||
271 | return; | ||
272 | /* find the boot console from /chosen/stdout */ | ||
273 | if (!of_chosen) | ||
274 | return; | ||
275 | node = of_find_node_by_path("/"); | ||
276 | if (!node) | ||
277 | return; | ||
278 | property = of_get_property(node, "model", NULL); | ||
279 | if (!property) | ||
280 | goto out_put; | ||
281 | if (strcmp(property, "Pegasos2")) | ||
282 | goto out_put; | ||
283 | /* this is a Pegasos2 */ | ||
284 | property = of_get_property(of_chosen, "linux,stdout-path", NULL); | ||
285 | if (!property) | ||
286 | goto out_put; | ||
287 | of_node_put(node); | ||
288 | node = of_find_node_by_path(property); | ||
289 | if (!node) | ||
290 | return; | ||
291 | property = of_get_property(node, "device_type", NULL); | ||
292 | if (!property) | ||
293 | goto out_put; | ||
294 | if (strcmp(property, "serial")) | ||
295 | goto out_put; | ||
296 | /* | ||
297 | * The 9pin connector is either /failsafe | ||
298 | * or /pci@80000000/isa@C/serial@i2F8 | ||
299 | * The optional graphics card has also type 'serial' in VGA mode. | ||
300 | */ | ||
301 | property = of_get_property(node, "name", NULL); | ||
302 | if (!property) | ||
303 | goto out_put; | ||
304 | if (!strcmp(property, "failsafe") || !strcmp(property, "serial")) | ||
305 | add_preferred_console("ttyS", 0, NULL); | ||
306 | out_put: | ||
307 | of_node_put(node); | ||
308 | } | ||
309 | |||
254 | void __init chrp_setup_arch(void) | 310 | void __init chrp_setup_arch(void) |
255 | { | 311 | { |
256 | struct device_node *root = of_find_node_by_path("/"); | 312 | struct device_node *root = of_find_node_by_path("/"); |
@@ -594,6 +650,7 @@ define_machine(chrp) { | |||
594 | .probe = chrp_probe, | 650 | .probe = chrp_probe, |
595 | .setup_arch = chrp_setup_arch, | 651 | .setup_arch = chrp_setup_arch, |
596 | .init = chrp_init2, | 652 | .init = chrp_init2, |
653 | .init_early = chrp_init_early, | ||
597 | .show_cpuinfo = chrp_show_cpuinfo, | 654 | .show_cpuinfo = chrp_show_cpuinfo, |
598 | .init_IRQ = chrp_init_IRQ, | 655 | .init_IRQ = chrp_init_IRQ, |
599 | .restart = rtas_restart, | 656 | .restart = rtas_restart, |
diff --git a/arch/powerpc/platforms/embedded6xx/Kconfig b/arch/powerpc/platforms/embedded6xx/Kconfig index 8924095a7928..6c8083757938 100644 --- a/arch/powerpc/platforms/embedded6xx/Kconfig +++ b/arch/powerpc/platforms/embedded6xx/Kconfig | |||
@@ -9,6 +9,8 @@ config LINKSTATION | |||
9 | select FSL_SOC | 9 | select FSL_SOC |
10 | select PPC_UDBG_16550 if SERIAL_8250 | 10 | select PPC_UDBG_16550 if SERIAL_8250 |
11 | select DEFAULT_UIMAGE | 11 | select DEFAULT_UIMAGE |
12 | select MPC10X_OPENPIC | ||
13 | select MPC10X_BRIDGE | ||
12 | help | 14 | help |
13 | Select LINKSTATION if configuring for one of PPC- (MPC8241) | 15 | Select LINKSTATION if configuring for one of PPC- (MPC8241) |
14 | based NAS systems from Buffalo Technology. So far only | 16 | based NAS systems from Buffalo Technology. So far only |
@@ -16,6 +18,19 @@ config LINKSTATION | |||
16 | Linkstation-I HD-HLAN and HD-HGLAN versions, and PPC-based | 18 | Linkstation-I HD-HLAN and HD-HGLAN versions, and PPC-based |
17 | Terastation systems should be supported too. | 19 | Terastation systems should be supported too. |
18 | 20 | ||
21 | config STORCENTER | ||
22 | bool "IOMEGA StorCenter" | ||
23 | depends on EMBEDDED6xx | ||
24 | select MPIC | ||
25 | select FSL_SOC | ||
26 | select PPC_UDBG_16550 if SERIAL_8250 | ||
27 | select WANT_DEVICE_TREE | ||
28 | select MPC10X_OPENPIC | ||
29 | select MPC10X_BRIDGE | ||
30 | help | ||
31 | Select STORCENTER if configuring for the iomega StorCenter | ||
32 | with an 8241 CPU in it. | ||
33 | |||
19 | config MPC7448HPC2 | 34 | config MPC7448HPC2 |
20 | bool "Freescale MPC7448HPC2(Taiga)" | 35 | bool "Freescale MPC7448HPC2(Taiga)" |
21 | depends on EMBEDDED6xx | 36 | depends on EMBEDDED6xx |
@@ -23,6 +38,7 @@ config MPC7448HPC2 | |||
23 | select DEFAULT_UIMAGE | 38 | select DEFAULT_UIMAGE |
24 | select PPC_UDBG_16550 | 39 | select PPC_UDBG_16550 |
25 | select WANT_DEVICE_TREE | 40 | select WANT_DEVICE_TREE |
41 | select TSI108_BRIDGE | ||
26 | help | 42 | help |
27 | Select MPC7448HPC2 if configuring for Freescale MPC7448HPC2 (Taiga) | 43 | Select MPC7448HPC2 if configuring for Freescale MPC7448HPC2 (Taiga) |
28 | platform | 44 | platform |
@@ -33,6 +49,7 @@ config PPC_HOLLY | |||
33 | select TSI108_BRIDGE | 49 | select TSI108_BRIDGE |
34 | select PPC_UDBG_16550 | 50 | select PPC_UDBG_16550 |
35 | select WANT_DEVICE_TREE | 51 | select WANT_DEVICE_TREE |
52 | select TSI108_BRIDGE | ||
36 | help | 53 | help |
37 | Select PPC_HOLLY if configuring for an IBM 750GX/CL Eval | 54 | Select PPC_HOLLY if configuring for an IBM 750GX/CL Eval |
38 | Board with TSI108/9 bridge (Hickory/Holly) | 55 | Board with TSI108/9 bridge (Hickory/Holly) |
@@ -48,17 +65,13 @@ config PPC_PRPMC2800 | |||
48 | 65 | ||
49 | config TSI108_BRIDGE | 66 | config TSI108_BRIDGE |
50 | bool | 67 | bool |
51 | depends on MPC7448HPC2 || PPC_HOLLY | ||
52 | select PCI | 68 | select PCI |
53 | select MPIC | 69 | select MPIC |
54 | select MPIC_WEIRD | 70 | select MPIC_WEIRD |
55 | default y | ||
56 | 71 | ||
57 | config MPC10X_BRIDGE | 72 | config MPC10X_BRIDGE |
58 | bool | 73 | bool |
59 | depends on LINKSTATION | ||
60 | select PPC_INDIRECT_PCI | 74 | select PPC_INDIRECT_PCI |
61 | default y | ||
62 | 75 | ||
63 | config MV64X60 | 76 | config MV64X60 |
64 | bool | 77 | bool |
@@ -67,8 +80,6 @@ config MV64X60 | |||
67 | 80 | ||
68 | config MPC10X_OPENPIC | 81 | config MPC10X_OPENPIC |
69 | bool | 82 | bool |
70 | depends on LINKSTATION | ||
71 | default y | ||
72 | 83 | ||
73 | config MPC10X_STORE_GATHERING | 84 | config MPC10X_STORE_GATHERING |
74 | bool "Enable MPC10x store gathering" | 85 | bool "Enable MPC10x store gathering" |
diff --git a/arch/powerpc/platforms/embedded6xx/Makefile b/arch/powerpc/platforms/embedded6xx/Makefile index 844947cfc5db..06524d3ffd2e 100644 --- a/arch/powerpc/platforms/embedded6xx/Makefile +++ b/arch/powerpc/platforms/embedded6xx/Makefile | |||
@@ -3,5 +3,6 @@ | |||
3 | # | 3 | # |
4 | obj-$(CONFIG_MPC7448HPC2) += mpc7448_hpc2.o | 4 | obj-$(CONFIG_MPC7448HPC2) += mpc7448_hpc2.o |
5 | obj-$(CONFIG_LINKSTATION) += linkstation.o ls_uart.o | 5 | obj-$(CONFIG_LINKSTATION) += linkstation.o ls_uart.o |
6 | obj-$(CONFIG_STORCENTER) += storcenter.o | ||
6 | obj-$(CONFIG_PPC_HOLLY) += holly.o | 7 | obj-$(CONFIG_PPC_HOLLY) += holly.o |
7 | obj-$(CONFIG_PPC_PRPMC2800) += prpmc2800.o | 8 | obj-$(CONFIG_PPC_PRPMC2800) += prpmc2800.o |
diff --git a/arch/powerpc/platforms/embedded6xx/holly.c b/arch/powerpc/platforms/embedded6xx/holly.c index b6de2b5223dd..b21fde589ca7 100644 --- a/arch/powerpc/platforms/embedded6xx/holly.c +++ b/arch/powerpc/platforms/embedded6xx/holly.c | |||
@@ -20,12 +20,12 @@ | |||
20 | #include <linux/console.h> | 20 | #include <linux/console.h> |
21 | #include <linux/delay.h> | 21 | #include <linux/delay.h> |
22 | #include <linux/irq.h> | 22 | #include <linux/irq.h> |
23 | #include <linux/ide.h> | ||
24 | #include <linux/seq_file.h> | 23 | #include <linux/seq_file.h> |
25 | #include <linux/root_dev.h> | 24 | #include <linux/root_dev.h> |
26 | #include <linux/serial.h> | 25 | #include <linux/serial.h> |
27 | #include <linux/tty.h> | 26 | #include <linux/tty.h> |
28 | #include <linux/serial_core.h> | 27 | #include <linux/serial_core.h> |
28 | #include <linux/of_platform.h> | ||
29 | 29 | ||
30 | #include <asm/system.h> | 30 | #include <asm/system.h> |
31 | #include <asm/time.h> | 31 | #include <asm/time.h> |
@@ -39,7 +39,6 @@ | |||
39 | #include <asm/tsi108_irq.h> | 39 | #include <asm/tsi108_irq.h> |
40 | #include <asm/tsi108_pci.h> | 40 | #include <asm/tsi108_pci.h> |
41 | #include <asm/mpic.h> | 41 | #include <asm/mpic.h> |
42 | #include <asm/of_platform.h> | ||
43 | 42 | ||
44 | #undef DEBUG | 43 | #undef DEBUG |
45 | 44 | ||
diff --git a/arch/powerpc/platforms/embedded6xx/ls_uart.c b/arch/powerpc/platforms/embedded6xx/ls_uart.c index c99264cedda5..9d891bd5df5a 100644 --- a/arch/powerpc/platforms/embedded6xx/ls_uart.c +++ b/arch/powerpc/platforms/embedded6xx/ls_uart.c | |||
@@ -117,9 +117,6 @@ static int __init ls_uarts_init(void) | |||
117 | phys_addr_t phys_addr; | 117 | phys_addr_t phys_addr; |
118 | int len; | 118 | int len; |
119 | 119 | ||
120 | if (!machine_is(linkstation)) | ||
121 | return 0; | ||
122 | |||
123 | avr = of_find_node_by_path("/soc10x/serial@80004500"); | 120 | avr = of_find_node_by_path("/soc10x/serial@80004500"); |
124 | if (!avr) | 121 | if (!avr) |
125 | return -EINVAL; | 122 | return -EINVAL; |
@@ -142,4 +139,4 @@ static int __init ls_uarts_init(void) | |||
142 | return 0; | 139 | return 0; |
143 | } | 140 | } |
144 | 141 | ||
145 | late_initcall(ls_uarts_init); | 142 | machine_late_initcall(linkstation, ls_uarts_init); |
diff --git a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c index a2c04b9d42b1..d4f8bf581e3a 100644 --- a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c +++ b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c | |||
@@ -53,8 +53,6 @@ | |||
53 | 53 | ||
54 | #define MPC7448HPC2_PCI_CFG_PHYS 0xfb000000 | 54 | #define MPC7448HPC2_PCI_CFG_PHYS 0xfb000000 |
55 | 55 | ||
56 | extern void _nmask_and_or_msr(unsigned long nmask, unsigned long or_val); | ||
57 | |||
58 | int mpc7448_hpc2_exclude_device(struct pci_controller *hose, | 56 | int mpc7448_hpc2_exclude_device(struct pci_controller *hose, |
59 | u_char bus, u_char devfn) | 57 | u_char bus, u_char devfn) |
60 | { | 58 | { |
diff --git a/arch/powerpc/platforms/embedded6xx/storcenter.c b/arch/powerpc/platforms/embedded6xx/storcenter.c new file mode 100644 index 000000000000..e12e9d298716 --- /dev/null +++ b/arch/powerpc/platforms/embedded6xx/storcenter.c | |||
@@ -0,0 +1,192 @@ | |||
1 | /* | ||
2 | * Board setup routines for the storcenter | ||
3 | * | ||
4 | * Copyright 2007 (C) Oyvind Repvik (nail@nslu2-linux.org) | ||
5 | * Copyright 2007 Andy Wilcox, Jon Loeliger | ||
6 | * | ||
7 | * Based on linkstation.c by G. Liakhovetski | ||
8 | * | ||
9 | * This file is licensed under the terms of the GNU General Public License | ||
10 | * version 2. This program is licensed "as is" without any warranty of | ||
11 | * any kind, whether express or implied. | ||
12 | */ | ||
13 | |||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/pci.h> | ||
16 | #include <linux/initrd.h> | ||
17 | #include <linux/mtd/physmap.h> | ||
18 | #include <linux/of_platform.h> | ||
19 | |||
20 | #include <asm/system.h> | ||
21 | #include <asm/time.h> | ||
22 | #include <asm/prom.h> | ||
23 | #include <asm/mpic.h> | ||
24 | #include <asm/pci-bridge.h> | ||
25 | |||
26 | #include "mpc10x.h" | ||
27 | |||
28 | |||
29 | #ifdef CONFIG_MTD_PHYSMAP | ||
30 | static struct mtd_partition storcenter_physmap_partitions[] = { | ||
31 | { | ||
32 | .name = "kernel", | ||
33 | .offset = 0x000000, | ||
34 | .size = 0x170000, | ||
35 | }, | ||
36 | { | ||
37 | .name = "rootfs", | ||
38 | .offset = 0x170000, | ||
39 | .size = 0x590000, | ||
40 | }, | ||
41 | { | ||
42 | .name = "uboot", | ||
43 | .offset = 0x700000, | ||
44 | .size = 0x040000, | ||
45 | }, | ||
46 | { | ||
47 | .name = "config", | ||
48 | .offset = 0x740000, | ||
49 | .size = 0x0c0000, | ||
50 | }, | ||
51 | }; | ||
52 | #endif | ||
53 | |||
54 | |||
55 | static __initdata struct of_device_id storcenter_of_bus[] = { | ||
56 | { .name = "soc", }, | ||
57 | {}, | ||
58 | }; | ||
59 | |||
60 | static int __init storcenter_device_probe(void) | ||
61 | { | ||
62 | of_platform_bus_probe(NULL, storcenter_of_bus, NULL); | ||
63 | return 0; | ||
64 | } | ||
65 | machine_device_initcall(storcenter, storcenter_device_probe); | ||
66 | |||
67 | |||
68 | static int __init storcenter_add_bridge(struct device_node *dev) | ||
69 | { | ||
70 | #ifdef CONFIG_PCI | ||
71 | int len; | ||
72 | struct pci_controller *hose; | ||
73 | const int *bus_range; | ||
74 | |||
75 | printk("Adding PCI host bridge %s\n", dev->full_name); | ||
76 | |||
77 | hose = pcibios_alloc_controller(dev); | ||
78 | if (hose == NULL) | ||
79 | return -ENOMEM; | ||
80 | |||
81 | bus_range = of_get_property(dev, "bus-range", &len); | ||
82 | hose->first_busno = bus_range ? bus_range[0] : 0; | ||
83 | hose->last_busno = bus_range ? bus_range[1] : 0xff; | ||
84 | |||
85 | setup_indirect_pci(hose, MPC10X_MAPB_CNFG_ADDR, MPC10X_MAPB_CNFG_DATA, 0); | ||
86 | |||
87 | /* Interpret the "ranges" property */ | ||
88 | /* This also maps the I/O region and sets isa_io/mem_base */ | ||
89 | pci_process_bridge_OF_ranges(hose, dev, 1); | ||
90 | #endif | ||
91 | |||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | static void __init storcenter_setup_arch(void) | ||
96 | { | ||
97 | struct device_node *np; | ||
98 | |||
99 | #ifdef CONFIG_MTD_PHYSMAP | ||
100 | physmap_set_partitions(storcenter_physmap_partitions, | ||
101 | ARRAY_SIZE(storcenter_physmap_partitions)); | ||
102 | #endif | ||
103 | |||
104 | /* Lookup PCI host bridges */ | ||
105 | for_each_compatible_node(np, "pci", "mpc10x-pci") | ||
106 | storcenter_add_bridge(np); | ||
107 | |||
108 | printk(KERN_INFO "IOMEGA StorCenter\n"); | ||
109 | } | ||
110 | |||
111 | /* | ||
112 | * Interrupt setup and service. Interrrupts on the turbostation come | ||
113 | * from the four PCI slots plus onboard 8241 devices: I2C, DUART. | ||
114 | */ | ||
115 | static void __init storcenter_init_IRQ(void) | ||
116 | { | ||
117 | struct mpic *mpic; | ||
118 | struct device_node *dnp; | ||
119 | const void *prop; | ||
120 | int size; | ||
121 | phys_addr_t paddr; | ||
122 | |||
123 | dnp = of_find_node_by_type(NULL, "open-pic"); | ||
124 | if (dnp == NULL) | ||
125 | return; | ||
126 | |||
127 | prop = of_get_property(dnp, "reg", &size); | ||
128 | if (prop == NULL) { | ||
129 | of_node_put(dnp); | ||
130 | return; | ||
131 | } | ||
132 | |||
133 | paddr = (phys_addr_t)of_translate_address(dnp, prop); | ||
134 | mpic = mpic_alloc(dnp, paddr, MPIC_PRIMARY | MPIC_WANTS_RESET, | ||
135 | 4, 32, " EPIC "); | ||
136 | |||
137 | of_node_put(dnp); | ||
138 | |||
139 | BUG_ON(mpic == NULL); | ||
140 | |||
141 | /* PCI IRQs */ | ||
142 | /* | ||
143 | * 2.6.12 patch: | ||
144 | * openpic_set_sources(0, 5, OpenPIC_Addr + 0x10200); | ||
145 | * openpic_set_sources(5, 2, OpenPIC_Addr + 0x11120); | ||
146 | * first_irq, num_irqs, __iomem first_ISR | ||
147 | * o_ss: i, src: 0, fdf50200 | ||
148 | * o_ss: i, src: 1, fdf50220 | ||
149 | * o_ss: i, src: 2, fdf50240 | ||
150 | * o_ss: i, src: 3, fdf50260 | ||
151 | * o_ss: i, src: 4, fdf50280 | ||
152 | * o_ss: i, src: 5, fdf51120 | ||
153 | * o_ss: i, src: 6, fdf51140 | ||
154 | */ | ||
155 | mpic_assign_isu(mpic, 0, paddr + 0x10200); | ||
156 | mpic_assign_isu(mpic, 1, paddr + 0x10220); | ||
157 | mpic_assign_isu(mpic, 2, paddr + 0x10240); | ||
158 | mpic_assign_isu(mpic, 3, paddr + 0x10260); | ||
159 | mpic_assign_isu(mpic, 4, paddr + 0x10280); | ||
160 | mpic_assign_isu(mpic, 5, paddr + 0x11120); | ||
161 | mpic_assign_isu(mpic, 6, paddr + 0x11140); | ||
162 | |||
163 | mpic_init(mpic); | ||
164 | } | ||
165 | |||
166 | static void storcenter_restart(char *cmd) | ||
167 | { | ||
168 | local_irq_disable(); | ||
169 | |||
170 | /* Set exception prefix high - to the firmware */ | ||
171 | _nmask_and_or_msr(0, MSR_IP); | ||
172 | |||
173 | /* Wait for reset to happen */ | ||
174 | for (;;) ; | ||
175 | } | ||
176 | |||
177 | static int __init storcenter_probe(void) | ||
178 | { | ||
179 | unsigned long root = of_get_flat_dt_root(); | ||
180 | |||
181 | return of_flat_dt_is_compatible(root, "storcenter"); | ||
182 | } | ||
183 | |||
184 | define_machine(storcenter){ | ||
185 | .name = "IOMEGA StorCenter", | ||
186 | .probe = storcenter_probe, | ||
187 | .setup_arch = storcenter_setup_arch, | ||
188 | .init_IRQ = storcenter_init_IRQ, | ||
189 | .get_irq = mpic_get_irq, | ||
190 | .restart = storcenter_restart, | ||
191 | .calibrate_decr = generic_calibrate_decr, | ||
192 | }; | ||
diff --git a/arch/powerpc/platforms/iseries/Makefile b/arch/powerpc/platforms/iseries/Makefile index a65f1b44abf8..cc7161ff1666 100644 --- a/arch/powerpc/platforms/iseries/Makefile +++ b/arch/powerpc/platforms/iseries/Makefile | |||
@@ -5,7 +5,7 @@ extra-y += dt.o | |||
5 | obj-y += exception.o | 5 | obj-y += exception.o |
6 | obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o dt_mod.o mf.o lpevents.o \ | 6 | obj-y += hvlog.o hvlpconfig.o lpardata.o setup.o dt_mod.o mf.o lpevents.o \ |
7 | hvcall.o proc.o htab.o iommu.o misc.o irq.o | 7 | hvcall.o proc.o htab.o iommu.o misc.o irq.o |
8 | obj-$(CONFIG_PCI) += pci.o vpdinfo.o | 8 | obj-$(CONFIG_PCI) += pci.o |
9 | obj-$(CONFIG_SMP) += smp.o | 9 | obj-$(CONFIG_SMP) += smp.o |
10 | obj-$(CONFIG_VIOPATH) += viopath.o vio.o | 10 | obj-$(CONFIG_VIOPATH) += viopath.o vio.o |
11 | obj-$(CONFIG_MODULES) += ksyms.o | 11 | obj-$(CONFIG_MODULES) += ksyms.o |
diff --git a/arch/powerpc/platforms/iseries/iommu.c b/arch/powerpc/platforms/iseries/iommu.c index 49e9c664ea89..6a0c6f6675cd 100644 --- a/arch/powerpc/platforms/iseries/iommu.c +++ b/arch/powerpc/platforms/iseries/iommu.c | |||
@@ -163,8 +163,10 @@ static struct iommu_table *iommu_table_find(struct iommu_table * tbl) | |||
163 | (it->it_type == TCE_PCI) && | 163 | (it->it_type == TCE_PCI) && |
164 | (it->it_offset == tbl->it_offset) && | 164 | (it->it_offset == tbl->it_offset) && |
165 | (it->it_index == tbl->it_index) && | 165 | (it->it_index == tbl->it_index) && |
166 | (it->it_size == tbl->it_size)) | 166 | (it->it_size == tbl->it_size)) { |
167 | of_node_put(node); | ||
167 | return it; | 168 | return it; |
169 | } | ||
168 | } | 170 | } |
169 | return NULL; | 171 | return NULL; |
170 | } | 172 | } |
diff --git a/arch/powerpc/platforms/iseries/lpevents.c b/arch/powerpc/platforms/iseries/lpevents.c index 275f49449839..e5b40e3e0082 100644 --- a/arch/powerpc/platforms/iseries/lpevents.c +++ b/arch/powerpc/platforms/iseries/lpevents.c | |||
@@ -239,7 +239,7 @@ int HvLpEvent_unregisterHandler(HvLpEvent_Type eventType) | |||
239 | * other CPUs, and that the deleted handler isn't | 239 | * other CPUs, and that the deleted handler isn't |
240 | * still running on another CPU when we return. | 240 | * still running on another CPU when we return. |
241 | */ | 241 | */ |
242 | synchronize_rcu(); | 242 | synchronize_sched(); |
243 | return 0; | 243 | return 0; |
244 | } | 244 | } |
245 | } | 245 | } |
diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c index da87162000f0..cc562e4c2f32 100644 --- a/arch/powerpc/platforms/iseries/pci.c +++ b/arch/powerpc/platforms/iseries/pci.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2001 Allan Trautman, IBM Corporation | 2 | * Copyright (C) 2001 Allan Trautman, IBM Corporation |
3 | * Copyright (C) 2005,2007 Stephen Rothwell, IBM Corp | ||
3 | * | 4 | * |
4 | * iSeries specific routines for PCI. | 5 | * iSeries specific routines for PCI. |
5 | * | 6 | * |
@@ -19,13 +20,18 @@ | |||
19 | * along with this program; if not, write to the Free Software | 20 | * along with this program; if not, write to the Free Software |
20 | * 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 |
21 | */ | 22 | */ |
23 | |||
24 | #undef DEBUG | ||
25 | |||
22 | #include <linux/kernel.h> | 26 | #include <linux/kernel.h> |
23 | #include <linux/list.h> | 27 | #include <linux/list.h> |
24 | #include <linux/string.h> | 28 | #include <linux/string.h> |
25 | #include <linux/init.h> | 29 | #include <linux/init.h> |
26 | #include <linux/module.h> | 30 | #include <linux/module.h> |
27 | #include <linux/pci.h> | 31 | #include <linux/pci.h> |
32 | #include <linux/of.h> | ||
28 | 33 | ||
34 | #include <asm/types.h> | ||
29 | #include <asm/io.h> | 35 | #include <asm/io.h> |
30 | #include <asm/irq.h> | 36 | #include <asm/irq.h> |
31 | #include <asm/prom.h> | 37 | #include <asm/prom.h> |
@@ -35,6 +41,7 @@ | |||
35 | #include <asm/abs_addr.h> | 41 | #include <asm/abs_addr.h> |
36 | #include <asm/firmware.h> | 42 | #include <asm/firmware.h> |
37 | 43 | ||
44 | #include <asm/iseries/hv_types.h> | ||
38 | #include <asm/iseries/hv_call_xm.h> | 45 | #include <asm/iseries/hv_call_xm.h> |
39 | #include <asm/iseries/mf.h> | 46 | #include <asm/iseries/mf.h> |
40 | #include <asm/iseries/iommu.h> | 47 | #include <asm/iseries/iommu.h> |
@@ -45,15 +52,8 @@ | |||
45 | #include "pci.h" | 52 | #include "pci.h" |
46 | #include "call_pci.h" | 53 | #include "call_pci.h" |
47 | 54 | ||
48 | /* | 55 | #define PCI_RETRY_MAX 3 |
49 | * Forward declares of prototypes. | 56 | static int limit_pci_retries = 1; /* Set Retry Error on. */ |
50 | */ | ||
51 | static struct device_node *find_Device_Node(int bus, int devfn); | ||
52 | |||
53 | static int Pci_Retry_Max = 3; /* Only retry 3 times */ | ||
54 | static int Pci_Error_Flag = 1; /* Set Retry Error on. */ | ||
55 | |||
56 | static struct pci_ops iSeries_pci_ops; | ||
57 | 57 | ||
58 | /* | 58 | /* |
59 | * Table defines | 59 | * Table defines |
@@ -62,6 +62,7 @@ static struct pci_ops iSeries_pci_ops; | |||
62 | #define IOMM_TABLE_MAX_ENTRIES 1024 | 62 | #define IOMM_TABLE_MAX_ENTRIES 1024 |
63 | #define IOMM_TABLE_ENTRY_SIZE 0x0000000000400000UL | 63 | #define IOMM_TABLE_ENTRY_SIZE 0x0000000000400000UL |
64 | #define BASE_IO_MEMORY 0xE000000000000000UL | 64 | #define BASE_IO_MEMORY 0xE000000000000000UL |
65 | #define END_IO_MEMORY 0xEFFFFFFFFFFFFFFFUL | ||
65 | 66 | ||
66 | static unsigned long max_io_memory = BASE_IO_MEMORY; | 67 | static unsigned long max_io_memory = BASE_IO_MEMORY; |
67 | static long current_iomm_table_entry; | 68 | static long current_iomm_table_entry; |
@@ -70,12 +71,237 @@ static long current_iomm_table_entry; | |||
70 | * Lookup Tables. | 71 | * Lookup Tables. |
71 | */ | 72 | */ |
72 | static struct device_node *iomm_table[IOMM_TABLE_MAX_ENTRIES]; | 73 | static struct device_node *iomm_table[IOMM_TABLE_MAX_ENTRIES]; |
73 | static u8 iobar_table[IOMM_TABLE_MAX_ENTRIES]; | 74 | static u64 ds_addr_table[IOMM_TABLE_MAX_ENTRIES]; |
74 | 75 | ||
75 | static const char pci_io_text[] = "iSeries PCI I/O"; | ||
76 | static DEFINE_SPINLOCK(iomm_table_lock); | 76 | static DEFINE_SPINLOCK(iomm_table_lock); |
77 | 77 | ||
78 | /* | 78 | /* |
79 | * Generate a Direct Select Address for the Hypervisor | ||
80 | */ | ||
81 | static inline u64 iseries_ds_addr(struct device_node *node) | ||
82 | { | ||
83 | struct pci_dn *pdn = PCI_DN(node); | ||
84 | const u32 *sbp = of_get_property(node, "linux,subbus", NULL); | ||
85 | |||
86 | return ((u64)pdn->busno << 48) + ((u64)(sbp ? *sbp : 0) << 40) | ||
87 | + ((u64)0x10 << 32); | ||
88 | } | ||
89 | |||
90 | /* | ||
91 | * Size of Bus VPD data | ||
92 | */ | ||
93 | #define BUS_VPDSIZE 1024 | ||
94 | |||
95 | /* | ||
96 | * Bus Vpd Tags | ||
97 | */ | ||
98 | #define VPD_END_OF_AREA 0x79 | ||
99 | #define VPD_ID_STRING 0x82 | ||
100 | #define VPD_VENDOR_AREA 0x84 | ||
101 | |||
102 | /* | ||
103 | * Mfg Area Tags | ||
104 | */ | ||
105 | #define VPD_FRU_FRAME_ID 0x4649 /* "FI" */ | ||
106 | #define VPD_SLOT_MAP_FORMAT 0x4D46 /* "MF" */ | ||
107 | #define VPD_SLOT_MAP 0x534D /* "SM" */ | ||
108 | |||
109 | /* | ||
110 | * Structures of the areas | ||
111 | */ | ||
112 | struct mfg_vpd_area { | ||
113 | u16 tag; | ||
114 | u8 length; | ||
115 | u8 data1; | ||
116 | u8 data2; | ||
117 | }; | ||
118 | #define MFG_ENTRY_SIZE 3 | ||
119 | |||
120 | struct slot_map { | ||
121 | u8 agent; | ||
122 | u8 secondary_agent; | ||
123 | u8 phb; | ||
124 | char card_location[3]; | ||
125 | char parms[8]; | ||
126 | char reserved[2]; | ||
127 | }; | ||
128 | #define SLOT_ENTRY_SIZE 16 | ||
129 | |||
130 | /* | ||
131 | * Parse the Slot Area | ||
132 | */ | ||
133 | static void __init iseries_parse_slot_area(struct slot_map *map, int len, | ||
134 | HvAgentId agent, u8 *phb, char card[4]) | ||
135 | { | ||
136 | /* | ||
137 | * Parse Slot label until we find the one requested | ||
138 | */ | ||
139 | while (len > 0) { | ||
140 | if (map->agent == agent) { | ||
141 | /* | ||
142 | * If Phb wasn't found, grab the entry first one found. | ||
143 | */ | ||
144 | if (*phb == 0xff) | ||
145 | *phb = map->phb; | ||
146 | /* Found it, extract the data. */ | ||
147 | if (map->phb == *phb) { | ||
148 | memcpy(card, &map->card_location, 3); | ||
149 | card[3] = 0; | ||
150 | break; | ||
151 | } | ||
152 | } | ||
153 | /* Point to the next Slot */ | ||
154 | map = (struct slot_map *)((char *)map + SLOT_ENTRY_SIZE); | ||
155 | len -= SLOT_ENTRY_SIZE; | ||
156 | } | ||
157 | } | ||
158 | |||
159 | /* | ||
160 | * Parse the Mfg Area | ||
161 | */ | ||
162 | static void __init iseries_parse_mfg_area(struct mfg_vpd_area *area, int len, | ||
163 | HvAgentId agent, u8 *phb, u8 *frame, char card[4]) | ||
164 | { | ||
165 | u16 slot_map_fmt = 0; | ||
166 | |||
167 | /* Parse Mfg Data */ | ||
168 | while (len > 0) { | ||
169 | int mfg_tag_len = area->length; | ||
170 | /* Frame ID (FI 4649020310 ) */ | ||
171 | if (area->tag == VPD_FRU_FRAME_ID) | ||
172 | *frame = area->data1; | ||
173 | /* Slot Map Format (MF 4D46020004 ) */ | ||
174 | else if (area->tag == VPD_SLOT_MAP_FORMAT) | ||
175 | slot_map_fmt = (area->data1 * 256) | ||
176 | + area->data2; | ||
177 | /* Slot Map (SM 534D90 */ | ||
178 | else if (area->tag == VPD_SLOT_MAP) { | ||
179 | struct slot_map *slot_map; | ||
180 | |||
181 | if (slot_map_fmt == 0x1004) | ||
182 | slot_map = (struct slot_map *)((char *)area | ||
183 | + MFG_ENTRY_SIZE + 1); | ||
184 | else | ||
185 | slot_map = (struct slot_map *)((char *)area | ||
186 | + MFG_ENTRY_SIZE); | ||
187 | iseries_parse_slot_area(slot_map, mfg_tag_len, | ||
188 | agent, phb, card); | ||
189 | } | ||
190 | /* | ||
191 | * Point to the next Mfg Area | ||
192 | * Use defined size, sizeof give wrong answer | ||
193 | */ | ||
194 | area = (struct mfg_vpd_area *)((char *)area + mfg_tag_len | ||
195 | + MFG_ENTRY_SIZE); | ||
196 | len -= (mfg_tag_len + MFG_ENTRY_SIZE); | ||
197 | } | ||
198 | } | ||
199 | |||
200 | /* | ||
201 | * Look for "BUS".. Data is not Null terminated. | ||
202 | * PHBID of 0xFF indicates PHB was not found in VPD Data. | ||
203 | */ | ||
204 | static u8 __init iseries_parse_phbid(u8 *area, int len) | ||
205 | { | ||
206 | while (len > 0) { | ||
207 | if ((*area == 'B') && (*(area + 1) == 'U') | ||
208 | && (*(area + 2) == 'S')) { | ||
209 | area += 3; | ||
210 | while (*area == ' ') | ||
211 | area++; | ||
212 | return *area & 0x0F; | ||
213 | } | ||
214 | area++; | ||
215 | len--; | ||
216 | } | ||
217 | return 0xff; | ||
218 | } | ||
219 | |||
220 | /* | ||
221 | * Parse out the VPD Areas | ||
222 | */ | ||
223 | static void __init iseries_parse_vpd(u8 *data, int data_len, | ||
224 | HvAgentId agent, u8 *frame, char card[4]) | ||
225 | { | ||
226 | u8 phb = 0xff; | ||
227 | |||
228 | while (data_len > 0) { | ||
229 | int len; | ||
230 | u8 tag = *data; | ||
231 | |||
232 | if (tag == VPD_END_OF_AREA) | ||
233 | break; | ||
234 | len = *(data + 1) + (*(data + 2) * 256); | ||
235 | data += 3; | ||
236 | data_len -= 3; | ||
237 | if (tag == VPD_ID_STRING) | ||
238 | phb = iseries_parse_phbid(data, len); | ||
239 | else if (tag == VPD_VENDOR_AREA) | ||
240 | iseries_parse_mfg_area((struct mfg_vpd_area *)data, len, | ||
241 | agent, &phb, frame, card); | ||
242 | /* Point to next Area. */ | ||
243 | data += len; | ||
244 | data_len -= len; | ||
245 | } | ||
246 | } | ||
247 | |||
248 | static int __init iseries_get_location_code(u16 bus, HvAgentId agent, | ||
249 | u8 *frame, char card[4]) | ||
250 | { | ||
251 | int status = 0; | ||
252 | int bus_vpd_len = 0; | ||
253 | u8 *bus_vpd = kmalloc(BUS_VPDSIZE, GFP_KERNEL); | ||
254 | |||
255 | if (bus_vpd == NULL) { | ||
256 | printk("PCI: Bus VPD Buffer allocation failure.\n"); | ||
257 | return 0; | ||
258 | } | ||
259 | bus_vpd_len = HvCallPci_getBusVpd(bus, iseries_hv_addr(bus_vpd), | ||
260 | BUS_VPDSIZE); | ||
261 | if (bus_vpd_len == 0) { | ||
262 | printk("PCI: Bus VPD Buffer zero length.\n"); | ||
263 | goto out_free; | ||
264 | } | ||
265 | /* printk("PCI: bus_vpd: %p, %d\n",bus_vpd, bus_vpd_len); */ | ||
266 | /* Make sure this is what I think it is */ | ||
267 | if (*bus_vpd != VPD_ID_STRING) { | ||
268 | printk("PCI: Bus VPD Buffer missing starting tag.\n"); | ||
269 | goto out_free; | ||
270 | } | ||
271 | iseries_parse_vpd(bus_vpd, bus_vpd_len, agent, frame, card); | ||
272 | status = 1; | ||
273 | out_free: | ||
274 | kfree(bus_vpd); | ||
275 | return status; | ||
276 | } | ||
277 | |||
278 | /* | ||
279 | * Prints the device information. | ||
280 | * - Pass in pci_dev* pointer to the device. | ||
281 | * - Pass in the device count | ||
282 | * | ||
283 | * Format: | ||
284 | * PCI: Bus 0, Device 26, Vendor 0x12AE Frame 1, Card C10 Ethernet | ||
285 | * controller | ||
286 | */ | ||
287 | static void __init iseries_device_information(struct pci_dev *pdev, | ||
288 | u16 bus, HvSubBusNumber subbus) | ||
289 | { | ||
290 | u8 frame = 0; | ||
291 | char card[4]; | ||
292 | HvAgentId agent; | ||
293 | |||
294 | agent = ISERIES_PCI_AGENTID(ISERIES_GET_DEVICE_FROM_SUBBUS(subbus), | ||
295 | ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus)); | ||
296 | |||
297 | if (iseries_get_location_code(bus, agent, &frame, card)) { | ||
298 | printk(KERN_INFO "PCI: %s, Vendor %04X Frame%3d, " | ||
299 | "Card %4s 0x%04X\n", pci_name(pdev), pdev->vendor, | ||
300 | frame, card, (int)(pdev->class >> 8)); | ||
301 | } | ||
302 | } | ||
303 | |||
304 | /* | ||
79 | * iomm_table_allocate_entry | 305 | * iomm_table_allocate_entry |
80 | * | 306 | * |
81 | * Adds pci_dev entry in address translation table | 307 | * Adds pci_dev entry in address translation table |
@@ -87,7 +313,7 @@ static DEFINE_SPINLOCK(iomm_table_lock); | |||
87 | * - CurrentIndex is incremented to keep track of the last entry. | 313 | * - CurrentIndex is incremented to keep track of the last entry. |
88 | * - Builds the resource entry for allocated BARs. | 314 | * - Builds the resource entry for allocated BARs. |
89 | */ | 315 | */ |
90 | static void iomm_table_allocate_entry(struct pci_dev *dev, int bar_num) | 316 | static void __init iomm_table_allocate_entry(struct pci_dev *dev, int bar_num) |
91 | { | 317 | { |
92 | struct resource *bar_res = &dev->resource[bar_num]; | 318 | struct resource *bar_res = &dev->resource[bar_num]; |
93 | long bar_size = pci_resource_len(dev, bar_num); | 319 | long bar_size = pci_resource_len(dev, bar_num); |
@@ -101,7 +327,6 @@ static void iomm_table_allocate_entry(struct pci_dev *dev, int bar_num) | |||
101 | * Set Resource values. | 327 | * Set Resource values. |
102 | */ | 328 | */ |
103 | spin_lock(&iomm_table_lock); | 329 | spin_lock(&iomm_table_lock); |
104 | bar_res->name = pci_io_text; | ||
105 | bar_res->start = BASE_IO_MEMORY + | 330 | bar_res->start = BASE_IO_MEMORY + |
106 | IOMM_TABLE_ENTRY_SIZE * current_iomm_table_entry; | 331 | IOMM_TABLE_ENTRY_SIZE * current_iomm_table_entry; |
107 | bar_res->end = bar_res->start + bar_size - 1; | 332 | bar_res->end = bar_res->start + bar_size - 1; |
@@ -110,7 +335,8 @@ static void iomm_table_allocate_entry(struct pci_dev *dev, int bar_num) | |||
110 | */ | 335 | */ |
111 | while (bar_size > 0 ) { | 336 | while (bar_size > 0 ) { |
112 | iomm_table[current_iomm_table_entry] = dev->sysdata; | 337 | iomm_table[current_iomm_table_entry] = dev->sysdata; |
113 | iobar_table[current_iomm_table_entry] = bar_num; | 338 | ds_addr_table[current_iomm_table_entry] = |
339 | iseries_ds_addr(dev->sysdata) | (bar_num << 24); | ||
114 | bar_size -= IOMM_TABLE_ENTRY_SIZE; | 340 | bar_size -= IOMM_TABLE_ENTRY_SIZE; |
115 | ++current_iomm_table_entry; | 341 | ++current_iomm_table_entry; |
116 | } | 342 | } |
@@ -130,7 +356,7 @@ static void iomm_table_allocate_entry(struct pci_dev *dev, int bar_num) | |||
130 | * - Loops through The Bar resources(0 - 5) including the ROM | 356 | * - Loops through The Bar resources(0 - 5) including the ROM |
131 | * is resource(6). | 357 | * is resource(6). |
132 | */ | 358 | */ |
133 | static void allocate_device_bars(struct pci_dev *dev) | 359 | static void __init allocate_device_bars(struct pci_dev *dev) |
134 | { | 360 | { |
135 | int bar_num; | 361 | int bar_num; |
136 | 362 | ||
@@ -145,79 +371,19 @@ static void allocate_device_bars(struct pci_dev *dev) | |||
145 | * PCI: Read Vendor Failed 0x18.58.10 Rc: 0x00xx | 371 | * PCI: Read Vendor Failed 0x18.58.10 Rc: 0x00xx |
146 | * PCI: Connect Bus Unit Failed 0x18.58.10 Rc: 0x00xx | 372 | * PCI: Connect Bus Unit Failed 0x18.58.10 Rc: 0x00xx |
147 | */ | 373 | */ |
148 | static void pci_Log_Error(char *Error_Text, int Bus, int SubBus, | 374 | static void pci_log_error(char *error, int bus, int subbus, |
149 | int AgentId, int HvRc) | 375 | int agent, int hv_res) |
150 | { | 376 | { |
151 | if (HvRc == 0x0302) | 377 | if (hv_res == 0x0302) |
152 | return; | 378 | return; |
153 | printk(KERN_ERR "PCI: %s Failed: 0x%02X.%02X.%02X Rc: 0x%04X", | 379 | printk(KERN_ERR "PCI: %s Failed: 0x%02X.%02X.%02X Rc: 0x%04X", |
154 | Error_Text, Bus, SubBus, AgentId, HvRc); | 380 | error, bus, subbus, agent, hv_res); |
155 | } | ||
156 | |||
157 | /* | ||
158 | * iSeries_pci_final_fixup(void) | ||
159 | */ | ||
160 | void __init iSeries_pci_final_fixup(void) | ||
161 | { | ||
162 | struct pci_dev *pdev = NULL; | ||
163 | struct device_node *node; | ||
164 | int DeviceCount = 0; | ||
165 | |||
166 | /* Fix up at the device node and pci_dev relationship */ | ||
167 | mf_display_src(0xC9000100); | ||
168 | |||
169 | printk("pcibios_final_fixup\n"); | ||
170 | for_each_pci_dev(pdev) { | ||
171 | node = find_Device_Node(pdev->bus->number, pdev->devfn); | ||
172 | printk("pci dev %p (%x.%x), node %p\n", pdev, | ||
173 | pdev->bus->number, pdev->devfn, node); | ||
174 | |||
175 | if (node != NULL) { | ||
176 | struct pci_dn *pdn = PCI_DN(node); | ||
177 | const u32 *agent; | ||
178 | |||
179 | agent = of_get_property(node, "linux,agent-id", NULL); | ||
180 | if ((pdn != NULL) && (agent != NULL)) { | ||
181 | u8 irq = iSeries_allocate_IRQ(pdn->busno, 0, | ||
182 | pdn->bussubno); | ||
183 | int err; | ||
184 | |||
185 | err = HvCallXm_connectBusUnit(pdn->busno, pdn->bussubno, | ||
186 | *agent, irq); | ||
187 | if (err) | ||
188 | pci_Log_Error("Connect Bus Unit", | ||
189 | pdn->busno, pdn->bussubno, *agent, err); | ||
190 | else { | ||
191 | err = HvCallPci_configStore8(pdn->busno, pdn->bussubno, | ||
192 | *agent, | ||
193 | PCI_INTERRUPT_LINE, | ||
194 | irq); | ||
195 | if (err) | ||
196 | pci_Log_Error("PciCfgStore Irq Failed!", | ||
197 | pdn->busno, pdn->bussubno, *agent, err); | ||
198 | } | ||
199 | if (!err) | ||
200 | pdev->irq = irq; | ||
201 | } | ||
202 | |||
203 | ++DeviceCount; | ||
204 | pdev->sysdata = (void *)node; | ||
205 | PCI_DN(node)->pcidev = pdev; | ||
206 | allocate_device_bars(pdev); | ||
207 | iSeries_Device_Information(pdev, DeviceCount); | ||
208 | iommu_devnode_init_iSeries(pdev, node); | ||
209 | } else | ||
210 | printk("PCI: Device Tree not found for 0x%016lX\n", | ||
211 | (unsigned long)pdev); | ||
212 | } | ||
213 | iSeries_activate_IRQs(); | ||
214 | mf_display_src(0xC9000200); | ||
215 | } | 381 | } |
216 | 382 | ||
217 | /* | 383 | /* |
218 | * Look down the chain to find the matching Device Device | 384 | * Look down the chain to find the matching Device Device |
219 | */ | 385 | */ |
220 | static struct device_node *find_Device_Node(int bus, int devfn) | 386 | static struct device_node *find_device_node(int bus, int devfn) |
221 | { | 387 | { |
222 | struct device_node *node; | 388 | struct device_node *node; |
223 | 389 | ||
@@ -230,22 +396,66 @@ static struct device_node *find_Device_Node(int bus, int devfn) | |||
230 | return NULL; | 396 | return NULL; |
231 | } | 397 | } |
232 | 398 | ||
233 | #if 0 | ||
234 | /* | 399 | /* |
235 | * Returns the device node for the passed pci_dev | 400 | * iSeries_pcibios_fixup_resources |
236 | * Sanity Check Node PciDev to passed pci_dev | 401 | * |
237 | * If none is found, returns a NULL which the client must handle. | 402 | * Fixes up all resources for devices |
238 | */ | 403 | */ |
239 | static struct device_node *get_Device_Node(struct pci_dev *pdev) | 404 | void __init iSeries_pcibios_fixup_resources(struct pci_dev *pdev) |
240 | { | 405 | { |
406 | const u32 *agent; | ||
407 | const u32 *sub_bus; | ||
408 | unsigned char bus = pdev->bus->number; | ||
241 | struct device_node *node; | 409 | struct device_node *node; |
410 | int i; | ||
411 | |||
412 | node = find_device_node(bus, pdev->devfn); | ||
413 | pr_debug("PCI: iSeries %s, pdev %p, node %p\n", | ||
414 | pci_name(pdev), pdev, node); | ||
415 | if (!node) { | ||
416 | printk("PCI: %s disabled, device tree entry not found !\n", | ||
417 | pci_name(pdev)); | ||
418 | for (i = 0; i <= PCI_ROM_RESOURCE; i++) | ||
419 | pdev->resource[i].flags = 0; | ||
420 | return; | ||
421 | } | ||
422 | sub_bus = of_get_property(node, "linux,subbus", NULL); | ||
423 | agent = of_get_property(node, "linux,agent-id", NULL); | ||
424 | if (agent && sub_bus) { | ||
425 | u8 irq = iSeries_allocate_IRQ(bus, 0, *sub_bus); | ||
426 | int err; | ||
427 | |||
428 | err = HvCallXm_connectBusUnit(bus, *sub_bus, *agent, irq); | ||
429 | if (err) | ||
430 | pci_log_error("Connect Bus Unit", | ||
431 | bus, *sub_bus, *agent, err); | ||
432 | else { | ||
433 | err = HvCallPci_configStore8(bus, *sub_bus, | ||
434 | *agent, PCI_INTERRUPT_LINE, irq); | ||
435 | if (err) | ||
436 | pci_log_error("PciCfgStore Irq Failed!", | ||
437 | bus, *sub_bus, *agent, err); | ||
438 | else | ||
439 | pdev->irq = irq; | ||
440 | } | ||
441 | } | ||
242 | 442 | ||
243 | node = pdev->sysdata; | 443 | pdev->sysdata = node; |
244 | if (node == NULL || PCI_DN(node)->pcidev != pdev) | 444 | allocate_device_bars(pdev); |
245 | node = find_Device_Node(pdev->bus->number, pdev->devfn); | 445 | iseries_device_information(pdev, bus, *sub_bus); |
246 | return node; | 446 | iommu_devnode_init_iSeries(pdev, node); |
447 | } | ||
448 | |||
449 | /* | ||
450 | * iSeries_pci_final_fixup(void) | ||
451 | */ | ||
452 | void __init iSeries_pci_final_fixup(void) | ||
453 | { | ||
454 | /* Fix up at the device node and pci_dev relationship */ | ||
455 | mf_display_src(0xC9000100); | ||
456 | iSeries_activate_IRQs(); | ||
457 | mf_display_src(0xC9000200); | ||
247 | } | 458 | } |
248 | #endif | ||
249 | 459 | ||
250 | /* | 460 | /* |
251 | * Config space read and write functions. | 461 | * Config space read and write functions. |
@@ -269,7 +479,7 @@ static u64 hv_cfg_write_func[4] = { | |||
269 | static int iSeries_pci_read_config(struct pci_bus *bus, unsigned int devfn, | 479 | static int iSeries_pci_read_config(struct pci_bus *bus, unsigned int devfn, |
270 | int offset, int size, u32 *val) | 480 | int offset, int size, u32 *val) |
271 | { | 481 | { |
272 | struct device_node *node = find_Device_Node(bus->number, devfn); | 482 | struct device_node *node = find_device_node(bus->number, devfn); |
273 | u64 fn; | 483 | u64 fn; |
274 | struct HvCallPci_LoadReturn ret; | 484 | struct HvCallPci_LoadReturn ret; |
275 | 485 | ||
@@ -299,7 +509,7 @@ static int iSeries_pci_read_config(struct pci_bus *bus, unsigned int devfn, | |||
299 | static int iSeries_pci_write_config(struct pci_bus *bus, unsigned int devfn, | 509 | static int iSeries_pci_write_config(struct pci_bus *bus, unsigned int devfn, |
300 | int offset, int size, u32 val) | 510 | int offset, int size, u32 val) |
301 | { | 511 | { |
302 | struct device_node *node = find_Device_Node(bus->number, devfn); | 512 | struct device_node *node = find_device_node(bus->number, devfn); |
303 | u64 fn; | 513 | u64 fn; |
304 | u64 ret; | 514 | u64 ret; |
305 | 515 | ||
@@ -331,22 +541,22 @@ static struct pci_ops iSeries_pci_ops = { | |||
331 | * PCI: Device 23.90 ReadL Retry( 1) | 541 | * PCI: Device 23.90 ReadL Retry( 1) |
332 | * PCI: Device 23.90 ReadL Retry Successful(1) | 542 | * PCI: Device 23.90 ReadL Retry Successful(1) |
333 | */ | 543 | */ |
334 | static int CheckReturnCode(char *TextHdr, struct device_node *DevNode, | 544 | static int check_return_code(char *type, struct device_node *dn, |
335 | int *retry, u64 ret) | 545 | int *retry, u64 ret) |
336 | { | 546 | { |
337 | if (ret != 0) { | 547 | if (ret != 0) { |
338 | struct pci_dn *pdn = PCI_DN(DevNode); | 548 | struct pci_dn *pdn = PCI_DN(dn); |
339 | 549 | ||
340 | (*retry)++; | 550 | (*retry)++; |
341 | printk("PCI: %s: Device 0x%04X:%02X I/O Error(%2d): 0x%04X\n", | 551 | printk("PCI: %s: Device 0x%04X:%02X I/O Error(%2d): 0x%04X\n", |
342 | TextHdr, pdn->busno, pdn->devfn, | 552 | type, pdn->busno, pdn->devfn, |
343 | *retry, (int)ret); | 553 | *retry, (int)ret); |
344 | /* | 554 | /* |
345 | * Bump the retry and check for retry count exceeded. | 555 | * Bump the retry and check for retry count exceeded. |
346 | * If, Exceeded, panic the system. | 556 | * If, Exceeded, panic the system. |
347 | */ | 557 | */ |
348 | if (((*retry) > Pci_Retry_Max) && | 558 | if (((*retry) > PCI_RETRY_MAX) && |
349 | (Pci_Error_Flag > 0)) { | 559 | (limit_pci_retries > 0)) { |
350 | mf_display_src(0xB6000103); | 560 | mf_display_src(0xB6000103); |
351 | panic_timeout = 0; | 561 | panic_timeout = 0; |
352 | panic("PCI: Hardware I/O Error, SRC B6000103, " | 562 | panic("PCI: Hardware I/O Error, SRC B6000103, " |
@@ -363,28 +573,39 @@ static int CheckReturnCode(char *TextHdr, struct device_node *DevNode, | |||
363 | * the exposure of being device global. | 573 | * the exposure of being device global. |
364 | */ | 574 | */ |
365 | static inline struct device_node *xlate_iomm_address( | 575 | static inline struct device_node *xlate_iomm_address( |
366 | const volatile void __iomem *IoAddress, | 576 | const volatile void __iomem *addr, |
367 | u64 *dsaptr, u64 *BarOffsetPtr) | 577 | u64 *dsaptr, u64 *bar_offset, const char *func) |
368 | { | 578 | { |
369 | unsigned long OrigIoAddr; | 579 | unsigned long orig_addr; |
370 | unsigned long BaseIoAddr; | 580 | unsigned long base_addr; |
371 | unsigned long TableIndex; | 581 | unsigned long ind; |
372 | struct device_node *DevNode; | 582 | struct device_node *dn; |
583 | |||
584 | orig_addr = (unsigned long __force)addr; | ||
585 | if ((orig_addr < BASE_IO_MEMORY) || (orig_addr >= max_io_memory)) { | ||
586 | static unsigned long last_jiffies; | ||
587 | static int num_printed; | ||
373 | 588 | ||
374 | OrigIoAddr = (unsigned long __force)IoAddress; | 589 | if ((jiffies - last_jiffies) > 60 * HZ) { |
375 | if ((OrigIoAddr < BASE_IO_MEMORY) || (OrigIoAddr >= max_io_memory)) | 590 | last_jiffies = jiffies; |
591 | num_printed = 0; | ||
592 | } | ||
593 | if (num_printed++ < 10) | ||
594 | printk(KERN_ERR | ||
595 | "iSeries_%s: invalid access at IO address %p\n", | ||
596 | func, addr); | ||
376 | return NULL; | 597 | return NULL; |
377 | BaseIoAddr = OrigIoAddr - BASE_IO_MEMORY; | 598 | } |
378 | TableIndex = BaseIoAddr / IOMM_TABLE_ENTRY_SIZE; | 599 | base_addr = orig_addr - BASE_IO_MEMORY; |
379 | DevNode = iomm_table[TableIndex]; | 600 | ind = base_addr / IOMM_TABLE_ENTRY_SIZE; |
380 | 601 | dn = iomm_table[ind]; | |
381 | if (DevNode != NULL) { | 602 | |
382 | int barnum = iobar_table[TableIndex]; | 603 | if (dn != NULL) { |
383 | *dsaptr = iseries_ds_addr(DevNode) | (barnum << 24); | 604 | *dsaptr = ds_addr_table[ind]; |
384 | *BarOffsetPtr = BaseIoAddr % IOMM_TABLE_ENTRY_SIZE; | 605 | *bar_offset = base_addr % IOMM_TABLE_ENTRY_SIZE; |
385 | } else | 606 | } else |
386 | panic("PCI: Invalid PCI IoAddress detected!\n"); | 607 | panic("PCI: Invalid PCI IO address detected!\n"); |
387 | return DevNode; | 608 | return dn; |
388 | } | 609 | } |
389 | 610 | ||
390 | /* | 611 | /* |
@@ -392,91 +613,58 @@ static inline struct device_node *xlate_iomm_address( | |||
392 | * On MM I/O error, all ones are returned and iSeries_pci_IoError is cal | 613 | * On MM I/O error, all ones are returned and iSeries_pci_IoError is cal |
393 | * else, data is returned in Big Endian format. | 614 | * else, data is returned in Big Endian format. |
394 | */ | 615 | */ |
395 | static u8 iSeries_Read_Byte(const volatile void __iomem *IoAddress) | 616 | static u8 iseries_readb(const volatile void __iomem *addr) |
396 | { | 617 | { |
397 | u64 BarOffset; | 618 | u64 bar_offset; |
398 | u64 dsa; | 619 | u64 dsa; |
399 | int retry = 0; | 620 | int retry = 0; |
400 | struct HvCallPci_LoadReturn ret; | 621 | struct HvCallPci_LoadReturn ret; |
401 | struct device_node *DevNode = | 622 | struct device_node *dn = |
402 | xlate_iomm_address(IoAddress, &dsa, &BarOffset); | 623 | xlate_iomm_address(addr, &dsa, &bar_offset, "read_byte"); |
403 | |||
404 | if (DevNode == NULL) { | ||
405 | static unsigned long last_jiffies; | ||
406 | static int num_printed; | ||
407 | 624 | ||
408 | if ((jiffies - last_jiffies) > 60 * HZ) { | 625 | if (dn == NULL) |
409 | last_jiffies = jiffies; | ||
410 | num_printed = 0; | ||
411 | } | ||
412 | if (num_printed++ < 10) | ||
413 | printk(KERN_ERR "iSeries_Read_Byte: invalid access at IO address %p\n", | ||
414 | IoAddress); | ||
415 | return 0xff; | 626 | return 0xff; |
416 | } | ||
417 | do { | 627 | do { |
418 | HvCall3Ret16(HvCallPciBarLoad8, &ret, dsa, BarOffset, 0); | 628 | HvCall3Ret16(HvCallPciBarLoad8, &ret, dsa, bar_offset, 0); |
419 | } while (CheckReturnCode("RDB", DevNode, &retry, ret.rc) != 0); | 629 | } while (check_return_code("RDB", dn, &retry, ret.rc) != 0); |
420 | 630 | ||
421 | return ret.value; | 631 | return ret.value; |
422 | } | 632 | } |
423 | 633 | ||
424 | static u16 iSeries_Read_Word(const volatile void __iomem *IoAddress) | 634 | static u16 iseries_readw_be(const volatile void __iomem *addr) |
425 | { | 635 | { |
426 | u64 BarOffset; | 636 | u64 bar_offset; |
427 | u64 dsa; | 637 | u64 dsa; |
428 | int retry = 0; | 638 | int retry = 0; |
429 | struct HvCallPci_LoadReturn ret; | 639 | struct HvCallPci_LoadReturn ret; |
430 | struct device_node *DevNode = | 640 | struct device_node *dn = |
431 | xlate_iomm_address(IoAddress, &dsa, &BarOffset); | 641 | xlate_iomm_address(addr, &dsa, &bar_offset, "read_word"); |
432 | 642 | ||
433 | if (DevNode == NULL) { | 643 | if (dn == NULL) |
434 | static unsigned long last_jiffies; | ||
435 | static int num_printed; | ||
436 | |||
437 | if ((jiffies - last_jiffies) > 60 * HZ) { | ||
438 | last_jiffies = jiffies; | ||
439 | num_printed = 0; | ||
440 | } | ||
441 | if (num_printed++ < 10) | ||
442 | printk(KERN_ERR "iSeries_Read_Word: invalid access at IO address %p\n", | ||
443 | IoAddress); | ||
444 | return 0xffff; | 644 | return 0xffff; |
445 | } | ||
446 | do { | 645 | do { |
447 | HvCall3Ret16(HvCallPciBarLoad16, &ret, dsa, | 646 | HvCall3Ret16(HvCallPciBarLoad16, &ret, dsa, |
448 | BarOffset, 0); | 647 | bar_offset, 0); |
449 | } while (CheckReturnCode("RDW", DevNode, &retry, ret.rc) != 0); | 648 | } while (check_return_code("RDW", dn, &retry, ret.rc) != 0); |
450 | 649 | ||
451 | return ret.value; | 650 | return ret.value; |
452 | } | 651 | } |
453 | 652 | ||
454 | static u32 iSeries_Read_Long(const volatile void __iomem *IoAddress) | 653 | static u32 iseries_readl_be(const volatile void __iomem *addr) |
455 | { | 654 | { |
456 | u64 BarOffset; | 655 | u64 bar_offset; |
457 | u64 dsa; | 656 | u64 dsa; |
458 | int retry = 0; | 657 | int retry = 0; |
459 | struct HvCallPci_LoadReturn ret; | 658 | struct HvCallPci_LoadReturn ret; |
460 | struct device_node *DevNode = | 659 | struct device_node *dn = |
461 | xlate_iomm_address(IoAddress, &dsa, &BarOffset); | 660 | xlate_iomm_address(addr, &dsa, &bar_offset, "read_long"); |
462 | |||
463 | if (DevNode == NULL) { | ||
464 | static unsigned long last_jiffies; | ||
465 | static int num_printed; | ||
466 | 661 | ||
467 | if ((jiffies - last_jiffies) > 60 * HZ) { | 662 | if (dn == NULL) |
468 | last_jiffies = jiffies; | ||
469 | num_printed = 0; | ||
470 | } | ||
471 | if (num_printed++ < 10) | ||
472 | printk(KERN_ERR "iSeries_Read_Long: invalid access at IO address %p\n", | ||
473 | IoAddress); | ||
474 | return 0xffffffff; | 663 | return 0xffffffff; |
475 | } | ||
476 | do { | 664 | do { |
477 | HvCall3Ret16(HvCallPciBarLoad32, &ret, dsa, | 665 | HvCall3Ret16(HvCallPciBarLoad32, &ret, dsa, |
478 | BarOffset, 0); | 666 | bar_offset, 0); |
479 | } while (CheckReturnCode("RDL", DevNode, &retry, ret.rc) != 0); | 667 | } while (check_return_code("RDL", dn, &retry, ret.rc) != 0); |
480 | 668 | ||
481 | return ret.value; | 669 | return ret.value; |
482 | } | 670 | } |
@@ -485,134 +673,72 @@ static u32 iSeries_Read_Long(const volatile void __iomem *IoAddress) | |||
485 | * Write MM I/O Instructions for the iSeries | 673 | * Write MM I/O Instructions for the iSeries |
486 | * | 674 | * |
487 | */ | 675 | */ |
488 | static void iSeries_Write_Byte(u8 data, volatile void __iomem *IoAddress) | 676 | static void iseries_writeb(u8 data, volatile void __iomem *addr) |
489 | { | 677 | { |
490 | u64 BarOffset; | 678 | u64 bar_offset; |
491 | u64 dsa; | 679 | u64 dsa; |
492 | int retry = 0; | 680 | int retry = 0; |
493 | u64 rc; | 681 | u64 rc; |
494 | struct device_node *DevNode = | 682 | struct device_node *dn = |
495 | xlate_iomm_address(IoAddress, &dsa, &BarOffset); | 683 | xlate_iomm_address(addr, &dsa, &bar_offset, "write_byte"); |
496 | |||
497 | if (DevNode == NULL) { | ||
498 | static unsigned long last_jiffies; | ||
499 | static int num_printed; | ||
500 | 684 | ||
501 | if ((jiffies - last_jiffies) > 60 * HZ) { | 685 | if (dn == NULL) |
502 | last_jiffies = jiffies; | ||
503 | num_printed = 0; | ||
504 | } | ||
505 | if (num_printed++ < 10) | ||
506 | printk(KERN_ERR "iSeries_Write_Byte: invalid access at IO address %p\n", IoAddress); | ||
507 | return; | 686 | return; |
508 | } | ||
509 | do { | 687 | do { |
510 | rc = HvCall4(HvCallPciBarStore8, dsa, BarOffset, data, 0); | 688 | rc = HvCall4(HvCallPciBarStore8, dsa, bar_offset, data, 0); |
511 | } while (CheckReturnCode("WWB", DevNode, &retry, rc) != 0); | 689 | } while (check_return_code("WWB", dn, &retry, rc) != 0); |
512 | } | 690 | } |
513 | 691 | ||
514 | static void iSeries_Write_Word(u16 data, volatile void __iomem *IoAddress) | 692 | static void iseries_writew_be(u16 data, volatile void __iomem *addr) |
515 | { | 693 | { |
516 | u64 BarOffset; | 694 | u64 bar_offset; |
517 | u64 dsa; | 695 | u64 dsa; |
518 | int retry = 0; | 696 | int retry = 0; |
519 | u64 rc; | 697 | u64 rc; |
520 | struct device_node *DevNode = | 698 | struct device_node *dn = |
521 | xlate_iomm_address(IoAddress, &dsa, &BarOffset); | 699 | xlate_iomm_address(addr, &dsa, &bar_offset, "write_word"); |
522 | 700 | ||
523 | if (DevNode == NULL) { | 701 | if (dn == NULL) |
524 | static unsigned long last_jiffies; | ||
525 | static int num_printed; | ||
526 | |||
527 | if ((jiffies - last_jiffies) > 60 * HZ) { | ||
528 | last_jiffies = jiffies; | ||
529 | num_printed = 0; | ||
530 | } | ||
531 | if (num_printed++ < 10) | ||
532 | printk(KERN_ERR "iSeries_Write_Word: invalid access at IO address %p\n", | ||
533 | IoAddress); | ||
534 | return; | 702 | return; |
535 | } | ||
536 | do { | 703 | do { |
537 | rc = HvCall4(HvCallPciBarStore16, dsa, BarOffset, data, 0); | 704 | rc = HvCall4(HvCallPciBarStore16, dsa, bar_offset, data, 0); |
538 | } while (CheckReturnCode("WWW", DevNode, &retry, rc) != 0); | 705 | } while (check_return_code("WWW", dn, &retry, rc) != 0); |
539 | } | 706 | } |
540 | 707 | ||
541 | static void iSeries_Write_Long(u32 data, volatile void __iomem *IoAddress) | 708 | static void iseries_writel_be(u32 data, volatile void __iomem *addr) |
542 | { | 709 | { |
543 | u64 BarOffset; | 710 | u64 bar_offset; |
544 | u64 dsa; | 711 | u64 dsa; |
545 | int retry = 0; | 712 | int retry = 0; |
546 | u64 rc; | 713 | u64 rc; |
547 | struct device_node *DevNode = | 714 | struct device_node *dn = |
548 | xlate_iomm_address(IoAddress, &dsa, &BarOffset); | 715 | xlate_iomm_address(addr, &dsa, &bar_offset, "write_long"); |
549 | |||
550 | if (DevNode == NULL) { | ||
551 | static unsigned long last_jiffies; | ||
552 | static int num_printed; | ||
553 | 716 | ||
554 | if ((jiffies - last_jiffies) > 60 * HZ) { | 717 | if (dn == NULL) |
555 | last_jiffies = jiffies; | ||
556 | num_printed = 0; | ||
557 | } | ||
558 | if (num_printed++ < 10) | ||
559 | printk(KERN_ERR "iSeries_Write_Long: invalid access at IO address %p\n", | ||
560 | IoAddress); | ||
561 | return; | 718 | return; |
562 | } | ||
563 | do { | 719 | do { |
564 | rc = HvCall4(HvCallPciBarStore32, dsa, BarOffset, data, 0); | 720 | rc = HvCall4(HvCallPciBarStore32, dsa, bar_offset, data, 0); |
565 | } while (CheckReturnCode("WWL", DevNode, &retry, rc) != 0); | 721 | } while (check_return_code("WWL", dn, &retry, rc) != 0); |
566 | } | ||
567 | |||
568 | static u8 iseries_readb(const volatile void __iomem *addr) | ||
569 | { | ||
570 | return iSeries_Read_Byte(addr); | ||
571 | } | 722 | } |
572 | 723 | ||
573 | static u16 iseries_readw(const volatile void __iomem *addr) | 724 | static u16 iseries_readw(const volatile void __iomem *addr) |
574 | { | 725 | { |
575 | return le16_to_cpu(iSeries_Read_Word(addr)); | 726 | return le16_to_cpu(iseries_readw_be(addr)); |
576 | } | 727 | } |
577 | 728 | ||
578 | static u32 iseries_readl(const volatile void __iomem *addr) | 729 | static u32 iseries_readl(const volatile void __iomem *addr) |
579 | { | 730 | { |
580 | return le32_to_cpu(iSeries_Read_Long(addr)); | 731 | return le32_to_cpu(iseries_readl_be(addr)); |
581 | } | ||
582 | |||
583 | static u16 iseries_readw_be(const volatile void __iomem *addr) | ||
584 | { | ||
585 | return iSeries_Read_Word(addr); | ||
586 | } | ||
587 | |||
588 | static u32 iseries_readl_be(const volatile void __iomem *addr) | ||
589 | { | ||
590 | return iSeries_Read_Long(addr); | ||
591 | } | ||
592 | |||
593 | static void iseries_writeb(u8 data, volatile void __iomem *addr) | ||
594 | { | ||
595 | iSeries_Write_Byte(data, addr); | ||
596 | } | 732 | } |
597 | 733 | ||
598 | static void iseries_writew(u16 data, volatile void __iomem *addr) | 734 | static void iseries_writew(u16 data, volatile void __iomem *addr) |
599 | { | 735 | { |
600 | iSeries_Write_Word(cpu_to_le16(data), addr); | 736 | iseries_writew_be(cpu_to_le16(data), addr); |
601 | } | 737 | } |
602 | 738 | ||
603 | static void iseries_writel(u32 data, volatile void __iomem *addr) | 739 | static void iseries_writel(u32 data, volatile void __iomem *addr) |
604 | { | 740 | { |
605 | iSeries_Write_Long(cpu_to_le32(data), addr); | 741 | iseries_writel(cpu_to_le32(data), addr); |
606 | } | ||
607 | |||
608 | static void iseries_writew_be(u16 data, volatile void __iomem *addr) | ||
609 | { | ||
610 | iSeries_Write_Word(data, addr); | ||
611 | } | ||
612 | |||
613 | static void iseries_writel_be(u32 data, volatile void __iomem *addr) | ||
614 | { | ||
615 | iSeries_Write_Long(data, addr); | ||
616 | } | 742 | } |
617 | 743 | ||
618 | static void iseries_readsb(const volatile void __iomem *addr, void *buf, | 744 | static void iseries_readsb(const volatile void __iomem *addr, void *buf, |
@@ -620,7 +746,7 @@ static void iseries_readsb(const volatile void __iomem *addr, void *buf, | |||
620 | { | 746 | { |
621 | u8 *dst = buf; | 747 | u8 *dst = buf; |
622 | while(count-- > 0) | 748 | while(count-- > 0) |
623 | *(dst++) = iSeries_Read_Byte(addr); | 749 | *(dst++) = iseries_readb(addr); |
624 | } | 750 | } |
625 | 751 | ||
626 | static void iseries_readsw(const volatile void __iomem *addr, void *buf, | 752 | static void iseries_readsw(const volatile void __iomem *addr, void *buf, |
@@ -628,7 +754,7 @@ static void iseries_readsw(const volatile void __iomem *addr, void *buf, | |||
628 | { | 754 | { |
629 | u16 *dst = buf; | 755 | u16 *dst = buf; |
630 | while(count-- > 0) | 756 | while(count-- > 0) |
631 | *(dst++) = iSeries_Read_Word(addr); | 757 | *(dst++) = iseries_readw_be(addr); |
632 | } | 758 | } |
633 | 759 | ||
634 | static void iseries_readsl(const volatile void __iomem *addr, void *buf, | 760 | static void iseries_readsl(const volatile void __iomem *addr, void *buf, |
@@ -636,7 +762,7 @@ static void iseries_readsl(const volatile void __iomem *addr, void *buf, | |||
636 | { | 762 | { |
637 | u32 *dst = buf; | 763 | u32 *dst = buf; |
638 | while(count-- > 0) | 764 | while(count-- > 0) |
639 | *(dst++) = iSeries_Read_Long(addr); | 765 | *(dst++) = iseries_readl_be(addr); |
640 | } | 766 | } |
641 | 767 | ||
642 | static void iseries_writesb(volatile void __iomem *addr, const void *buf, | 768 | static void iseries_writesb(volatile void __iomem *addr, const void *buf, |
@@ -644,7 +770,7 @@ static void iseries_writesb(volatile void __iomem *addr, const void *buf, | |||
644 | { | 770 | { |
645 | const u8 *src = buf; | 771 | const u8 *src = buf; |
646 | while(count-- > 0) | 772 | while(count-- > 0) |
647 | iSeries_Write_Byte(*(src++), addr); | 773 | iseries_writeb(*(src++), addr); |
648 | } | 774 | } |
649 | 775 | ||
650 | static void iseries_writesw(volatile void __iomem *addr, const void *buf, | 776 | static void iseries_writesw(volatile void __iomem *addr, const void *buf, |
@@ -652,7 +778,7 @@ static void iseries_writesw(volatile void __iomem *addr, const void *buf, | |||
652 | { | 778 | { |
653 | const u16 *src = buf; | 779 | const u16 *src = buf; |
654 | while(count-- > 0) | 780 | while(count-- > 0) |
655 | iSeries_Write_Word(*(src++), addr); | 781 | iseries_writew_be(*(src++), addr); |
656 | } | 782 | } |
657 | 783 | ||
658 | static void iseries_writesl(volatile void __iomem *addr, const void *buf, | 784 | static void iseries_writesl(volatile void __iomem *addr, const void *buf, |
@@ -660,7 +786,7 @@ static void iseries_writesl(volatile void __iomem *addr, const void *buf, | |||
660 | { | 786 | { |
661 | const u32 *src = buf; | 787 | const u32 *src = buf; |
662 | while(count-- > 0) | 788 | while(count-- > 0) |
663 | iSeries_Write_Long(*(src++), addr); | 789 | iseries_writel_be(*(src++), addr); |
664 | } | 790 | } |
665 | 791 | ||
666 | static void iseries_memset_io(volatile void __iomem *addr, int c, | 792 | static void iseries_memset_io(volatile void __iomem *addr, int c, |
@@ -669,7 +795,7 @@ static void iseries_memset_io(volatile void __iomem *addr, int c, | |||
669 | volatile char __iomem *d = addr; | 795 | volatile char __iomem *d = addr; |
670 | 796 | ||
671 | while (n-- > 0) | 797 | while (n-- > 0) |
672 | iSeries_Write_Byte(c, d++); | 798 | iseries_writeb(c, d++); |
673 | } | 799 | } |
674 | 800 | ||
675 | static void iseries_memcpy_fromio(void *dest, const volatile void __iomem *src, | 801 | static void iseries_memcpy_fromio(void *dest, const volatile void __iomem *src, |
@@ -679,7 +805,7 @@ static void iseries_memcpy_fromio(void *dest, const volatile void __iomem *src, | |||
679 | const volatile char __iomem *s = src; | 805 | const volatile char __iomem *s = src; |
680 | 806 | ||
681 | while (n-- > 0) | 807 | while (n-- > 0) |
682 | *d++ = iSeries_Read_Byte(s++); | 808 | *d++ = iseries_readb(s++); |
683 | } | 809 | } |
684 | 810 | ||
685 | static void iseries_memcpy_toio(volatile void __iomem *dest, const void *src, | 811 | static void iseries_memcpy_toio(volatile void __iomem *dest, const void *src, |
@@ -689,7 +815,7 @@ static void iseries_memcpy_toio(volatile void __iomem *dest, const void *src, | |||
689 | volatile char __iomem *d = dest; | 815 | volatile char __iomem *d = dest; |
690 | 816 | ||
691 | while (n-- > 0) | 817 | while (n-- > 0) |
692 | iSeries_Write_Byte(*s++, d++); | 818 | iseries_writeb(*s++, d++); |
693 | } | 819 | } |
694 | 820 | ||
695 | /* We only set MMIO ops. The default PIO ops will be default | 821 | /* We only set MMIO ops. The default PIO ops will be default |
@@ -742,6 +868,8 @@ void __init iSeries_pcibios_init(void) | |||
742 | /* Install IO hooks */ | 868 | /* Install IO hooks */ |
743 | ppc_pci_io = iseries_pci_io; | 869 | ppc_pci_io = iseries_pci_io; |
744 | 870 | ||
871 | pci_probe_only = 1; | ||
872 | |||
745 | /* iSeries has no IO space in the common sense, it needs to set | 873 | /* iSeries has no IO space in the common sense, it needs to set |
746 | * the IO base to 0 | 874 | * the IO base to 0 |
747 | */ | 875 | */ |
@@ -767,11 +895,21 @@ void __init iSeries_pcibios_init(void) | |||
767 | phb = pcibios_alloc_controller(node); | 895 | phb = pcibios_alloc_controller(node); |
768 | if (phb == NULL) | 896 | if (phb == NULL) |
769 | continue; | 897 | continue; |
898 | /* All legacy iSeries PHBs are in domain zero */ | ||
899 | phb->global_number = 0; | ||
770 | 900 | ||
771 | phb->pci_mem_offset = bus; | ||
772 | phb->first_busno = bus; | 901 | phb->first_busno = bus; |
773 | phb->last_busno = bus; | 902 | phb->last_busno = bus; |
774 | phb->ops = &iSeries_pci_ops; | 903 | phb->ops = &iSeries_pci_ops; |
904 | phb->io_base_virt = (void __iomem *)_IO_BASE; | ||
905 | phb->io_resource.flags = IORESOURCE_IO; | ||
906 | phb->io_resource.start = BASE_IO_MEMORY; | ||
907 | phb->io_resource.end = END_IO_MEMORY; | ||
908 | phb->io_resource.name = "iSeries PCI IO"; | ||
909 | phb->mem_resources[0].flags = IORESOURCE_MEM; | ||
910 | phb->mem_resources[0].start = BASE_IO_MEMORY; | ||
911 | phb->mem_resources[0].end = END_IO_MEMORY; | ||
912 | phb->mem_resources[0].name = "Series PCI MEM"; | ||
775 | } | 913 | } |
776 | 914 | ||
777 | of_node_put(root); | 915 | of_node_put(root); |
diff --git a/arch/powerpc/platforms/iseries/pci.h b/arch/powerpc/platforms/iseries/pci.h index 33a8489fde54..d9cf974c2718 100644 --- a/arch/powerpc/platforms/iseries/pci.h +++ b/arch/powerpc/platforms/iseries/pci.h | |||
@@ -30,10 +30,6 @@ | |||
30 | * End Change Activity | 30 | * End Change Activity |
31 | */ | 31 | */ |
32 | 32 | ||
33 | #include <asm/pci-bridge.h> | ||
34 | |||
35 | struct pci_dev; /* For Forward Reference */ | ||
36 | |||
37 | /* | 33 | /* |
38 | * Decodes Linux DevFn to iSeries DevFn, bridge device, or function. | 34 | * Decodes Linux DevFn to iSeries DevFn, bridge device, or function. |
39 | * For Linux, see PCI_SLOT and PCI_FUNC in include/linux/pci.h | 35 | * For Linux, see PCI_SLOT and PCI_FUNC in include/linux/pci.h |
@@ -47,17 +43,16 @@ struct pci_dev; /* For Forward Reference */ | |||
47 | #define ISERIES_GET_DEVICE_FROM_SUBBUS(subbus) ((subbus >> 5) & 0x7) | 43 | #define ISERIES_GET_DEVICE_FROM_SUBBUS(subbus) ((subbus >> 5) & 0x7) |
48 | #define ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus) ((subbus >> 2) & 0x7) | 44 | #define ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus) ((subbus >> 2) & 0x7) |
49 | 45 | ||
50 | /* | 46 | struct pci_dev; |
51 | * Generate a Direct Select Address for the Hypervisor | 47 | |
52 | */ | 48 | #ifdef CONFIG_PCI |
53 | static inline u64 iseries_ds_addr(struct device_node *node) | 49 | extern void iSeries_pcibios_init(void); |
54 | { | 50 | extern void iSeries_pci_final_fixup(void); |
55 | struct pci_dn *pdn = PCI_DN(node); | 51 | extern void iSeries_pcibios_fixup_resources(struct pci_dev *dev); |
56 | 52 | #else | |
57 | return ((u64)pdn->busno << 48) + ((u64)pdn->bussubno << 40) | 53 | static inline void iSeries_pcibios_init(void) { } |
58 | + ((u64)0x10 << 32); | 54 | static inline void iSeries_pci_final_fixup(void) { } |
59 | } | 55 | static inline void iSeries_pcibios_fixup_resources(struct pci_dev *dev) {} |
60 | 56 | #endif | |
61 | extern void iSeries_Device_Information(struct pci_dev*, int); | ||
62 | 57 | ||
63 | #endif /* _PLATFORMS_ISERIES_PCI_H */ | 58 | #endif /* _PLATFORMS_ISERIES_PCI_H */ |
diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c index 0877a8834110..b72120751bbe 100644 --- a/arch/powerpc/platforms/iseries/setup.c +++ b/arch/powerpc/platforms/iseries/setup.c | |||
@@ -63,6 +63,7 @@ | |||
63 | #include "main_store.h" | 63 | #include "main_store.h" |
64 | #include "call_sm.h" | 64 | #include "call_sm.h" |
65 | #include "call_hpt.h" | 65 | #include "call_hpt.h" |
66 | #include "pci.h" | ||
66 | 67 | ||
67 | #ifdef DEBUG | 68 | #ifdef DEBUG |
68 | #define DBG(fmt...) udbg_printf(fmt) | 69 | #define DBG(fmt...) udbg_printf(fmt) |
@@ -74,11 +75,6 @@ | |||
74 | static unsigned long build_iSeries_Memory_Map(void); | 75 | static unsigned long build_iSeries_Memory_Map(void); |
75 | static void iseries_shared_idle(void); | 76 | static void iseries_shared_idle(void); |
76 | static void iseries_dedicated_idle(void); | 77 | static void iseries_dedicated_idle(void); |
77 | #ifdef CONFIG_PCI | ||
78 | extern void iSeries_pci_final_fixup(void); | ||
79 | #else | ||
80 | static void iSeries_pci_final_fixup(void) { } | ||
81 | #endif | ||
82 | 78 | ||
83 | 79 | ||
84 | struct MemoryBlock { | 80 | struct MemoryBlock { |
@@ -112,13 +108,13 @@ static unsigned long iSeries_process_Condor_mainstore_vpd( | |||
112 | * correctly. | 108 | * correctly. |
113 | */ | 109 | */ |
114 | mb_array[0].logicalStart = 0; | 110 | mb_array[0].logicalStart = 0; |
115 | mb_array[0].logicalEnd = 0x100000000; | 111 | mb_array[0].logicalEnd = 0x100000000UL; |
116 | mb_array[0].absStart = 0; | 112 | mb_array[0].absStart = 0; |
117 | mb_array[0].absEnd = 0x100000000; | 113 | mb_array[0].absEnd = 0x100000000UL; |
118 | 114 | ||
119 | if (holeSize) { | 115 | if (holeSize) { |
120 | numMemoryBlocks = 2; | 116 | numMemoryBlocks = 2; |
121 | holeStart = holeStart & 0x000fffffffffffff; | 117 | holeStart = holeStart & 0x000fffffffffffffUL; |
122 | holeStart = addr_to_chunk(holeStart); | 118 | holeStart = addr_to_chunk(holeStart); |
123 | holeFirstChunk = holeStart; | 119 | holeFirstChunk = holeStart; |
124 | holeSize = addr_to_chunk(holeSize); | 120 | holeSize = addr_to_chunk(holeSize); |
@@ -128,9 +124,9 @@ static unsigned long iSeries_process_Condor_mainstore_vpd( | |||
128 | mb_array[0].logicalEnd = holeFirstChunk; | 124 | mb_array[0].logicalEnd = holeFirstChunk; |
129 | mb_array[0].absEnd = holeFirstChunk; | 125 | mb_array[0].absEnd = holeFirstChunk; |
130 | mb_array[1].logicalStart = holeFirstChunk; | 126 | mb_array[1].logicalStart = holeFirstChunk; |
131 | mb_array[1].logicalEnd = 0x100000000 - holeSizeChunks; | 127 | mb_array[1].logicalEnd = 0x100000000UL - holeSizeChunks; |
132 | mb_array[1].absStart = holeFirstChunk + holeSizeChunks; | 128 | mb_array[1].absStart = holeFirstChunk + holeSizeChunks; |
133 | mb_array[1].absEnd = 0x100000000; | 129 | mb_array[1].absEnd = 0x100000000UL; |
134 | } | 130 | } |
135 | return numMemoryBlocks; | 131 | return numMemoryBlocks; |
136 | } | 132 | } |
@@ -234,9 +230,9 @@ static unsigned long iSeries_process_Regatta_mainstore_vpd( | |||
234 | mb_array[i].logicalEnd, | 230 | mb_array[i].logicalEnd, |
235 | mb_array[i].absStart, mb_array[i].absEnd); | 231 | mb_array[i].absStart, mb_array[i].absEnd); |
236 | mb_array[i].absStart = addr_to_chunk(mb_array[i].absStart & | 232 | mb_array[i].absStart = addr_to_chunk(mb_array[i].absStart & |
237 | 0x000fffffffffffff); | 233 | 0x000fffffffffffffUL); |
238 | mb_array[i].absEnd = addr_to_chunk(mb_array[i].absEnd & | 234 | mb_array[i].absEnd = addr_to_chunk(mb_array[i].absEnd & |
239 | 0x000fffffffffffff); | 235 | 0x000fffffffffffffUL); |
240 | mb_array[i].logicalStart = | 236 | mb_array[i].logicalStart = |
241 | addr_to_chunk(mb_array[i].logicalStart); | 237 | addr_to_chunk(mb_array[i].logicalStart); |
242 | mb_array[i].logicalEnd = addr_to_chunk(mb_array[i].logicalEnd); | 238 | mb_array[i].logicalEnd = addr_to_chunk(mb_array[i].logicalEnd); |
@@ -320,7 +316,7 @@ struct mschunks_map mschunks_map = { | |||
320 | }; | 316 | }; |
321 | EXPORT_SYMBOL(mschunks_map); | 317 | EXPORT_SYMBOL(mschunks_map); |
322 | 318 | ||
323 | void mschunks_alloc(unsigned long num_chunks) | 319 | static void mschunks_alloc(unsigned long num_chunks) |
324 | { | 320 | { |
325 | klimit = _ALIGN(klimit, sizeof(u32)); | 321 | klimit = _ALIGN(klimit, sizeof(u32)); |
326 | mschunks_map.mapping = (u32 *)klimit; | 322 | mschunks_map.mapping = (u32 *)klimit; |
@@ -499,6 +495,8 @@ static void __init iSeries_setup_arch(void) | |||
499 | itVpdAreas.xSlicMaxLogicalProcs); | 495 | itVpdAreas.xSlicMaxLogicalProcs); |
500 | printk("Max physical processors = %d\n", | 496 | printk("Max physical processors = %d\n", |
501 | itVpdAreas.xSlicMaxPhysicalProcs); | 497 | itVpdAreas.xSlicMaxPhysicalProcs); |
498 | |||
499 | iSeries_pcibios_init(); | ||
502 | } | 500 | } |
503 | 501 | ||
504 | static void iSeries_show_cpuinfo(struct seq_file *m) | 502 | static void iSeries_show_cpuinfo(struct seq_file *m) |
@@ -641,24 +639,25 @@ static int __init iseries_probe(void) | |||
641 | } | 639 | } |
642 | 640 | ||
643 | define_machine(iseries) { | 641 | define_machine(iseries) { |
644 | .name = "iSeries", | 642 | .name = "iSeries", |
645 | .setup_arch = iSeries_setup_arch, | 643 | .setup_arch = iSeries_setup_arch, |
646 | .show_cpuinfo = iSeries_show_cpuinfo, | 644 | .show_cpuinfo = iSeries_show_cpuinfo, |
647 | .init_IRQ = iSeries_init_IRQ, | 645 | .init_IRQ = iSeries_init_IRQ, |
648 | .get_irq = iSeries_get_irq, | 646 | .get_irq = iSeries_get_irq, |
649 | .init_early = iSeries_init_early, | 647 | .init_early = iSeries_init_early, |
650 | .pcibios_fixup = iSeries_pci_final_fixup, | 648 | .pcibios_fixup = iSeries_pci_final_fixup, |
651 | .restart = mf_reboot, | 649 | .pcibios_fixup_resources= iSeries_pcibios_fixup_resources, |
652 | .power_off = mf_power_off, | 650 | .restart = mf_reboot, |
653 | .halt = mf_power_off, | 651 | .power_off = mf_power_off, |
654 | .get_boot_time = iSeries_get_boot_time, | 652 | .halt = mf_power_off, |
655 | .set_rtc_time = iSeries_set_rtc_time, | 653 | .get_boot_time = iSeries_get_boot_time, |
656 | .get_rtc_time = iSeries_get_rtc_time, | 654 | .set_rtc_time = iSeries_set_rtc_time, |
657 | .calibrate_decr = generic_calibrate_decr, | 655 | .get_rtc_time = iSeries_get_rtc_time, |
658 | .progress = iSeries_progress, | 656 | .calibrate_decr = generic_calibrate_decr, |
659 | .probe = iseries_probe, | 657 | .progress = iSeries_progress, |
660 | .ioremap = iseries_ioremap, | 658 | .probe = iseries_probe, |
661 | .iounmap = iseries_iounmap, | 659 | .ioremap = iseries_ioremap, |
660 | .iounmap = iseries_iounmap, | ||
662 | /* XXX Implement enable_pmcs for iSeries */ | 661 | /* XXX Implement enable_pmcs for iSeries */ |
663 | }; | 662 | }; |
664 | 663 | ||
diff --git a/arch/powerpc/platforms/iseries/setup.h b/arch/powerpc/platforms/iseries/setup.h index 0a47ac53c959..729754bbb018 100644 --- a/arch/powerpc/platforms/iseries/setup.h +++ b/arch/powerpc/platforms/iseries/setup.h | |||
@@ -17,6 +17,7 @@ | |||
17 | #ifndef __ISERIES_SETUP_H__ | 17 | #ifndef __ISERIES_SETUP_H__ |
18 | #define __ISERIES_SETUP_H__ | 18 | #define __ISERIES_SETUP_H__ |
19 | 19 | ||
20 | extern void *iSeries_early_setup(void); | ||
20 | extern unsigned long iSeries_get_boot_time(void); | 21 | extern unsigned long iSeries_get_boot_time(void); |
21 | extern int iSeries_set_rtc_time(struct rtc_time *tm); | 22 | extern int iSeries_set_rtc_time(struct rtc_time *tm); |
22 | extern void iSeries_get_rtc_time(struct rtc_time *tm); | 23 | extern void iSeries_get_rtc_time(struct rtc_time *tm); |
diff --git a/arch/powerpc/platforms/iseries/vpdinfo.c b/arch/powerpc/platforms/iseries/vpdinfo.c deleted file mode 100644 index 9f83878a0c2e..000000000000 --- a/arch/powerpc/platforms/iseries/vpdinfo.c +++ /dev/null | |||
@@ -1,275 +0,0 @@ | |||
1 | /* | ||
2 | * This code gets the card location of the hardware | ||
3 | * Copyright (C) 2001 <Allan H Trautman> <IBM Corp> | ||
4 | * Copyright (C) 2005 Stephen Rothwel, IBM Corp | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the: | ||
18 | * Free Software Foundation, Inc., | ||
19 | * 59 Temple Place, Suite 330, | ||
20 | * Boston, MA 02111-1307 USA | ||
21 | * | ||
22 | * Change Activity: | ||
23 | * Created, Feb 2, 2001 | ||
24 | * Ported to ppc64, August 20, 2001 | ||
25 | * End Change Activity | ||
26 | */ | ||
27 | #include <linux/init.h> | ||
28 | #include <linux/module.h> | ||
29 | #include <linux/pci.h> | ||
30 | |||
31 | #include <asm/types.h> | ||
32 | #include <asm/resource.h> | ||
33 | #include <asm/abs_addr.h> | ||
34 | #include <asm/pci-bridge.h> | ||
35 | #include <asm/iseries/hv_types.h> | ||
36 | |||
37 | #include "pci.h" | ||
38 | #include "call_pci.h" | ||
39 | |||
40 | /* | ||
41 | * Size of Bus VPD data | ||
42 | */ | ||
43 | #define BUS_VPDSIZE 1024 | ||
44 | |||
45 | /* | ||
46 | * Bus Vpd Tags | ||
47 | */ | ||
48 | #define VpdEndOfAreaTag 0x79 | ||
49 | #define VpdIdStringTag 0x82 | ||
50 | #define VpdVendorAreaTag 0x84 | ||
51 | |||
52 | /* | ||
53 | * Mfg Area Tags | ||
54 | */ | ||
55 | #define VpdFruFrameId 0x4649 // "FI" | ||
56 | #define VpdSlotMapFormat 0x4D46 // "MF" | ||
57 | #define VpdSlotMap 0x534D // "SM" | ||
58 | |||
59 | /* | ||
60 | * Structures of the areas | ||
61 | */ | ||
62 | struct MfgVpdAreaStruct { | ||
63 | u16 Tag; | ||
64 | u8 TagLength; | ||
65 | u8 AreaData1; | ||
66 | u8 AreaData2; | ||
67 | }; | ||
68 | typedef struct MfgVpdAreaStruct MfgArea; | ||
69 | #define MFG_ENTRY_SIZE 3 | ||
70 | |||
71 | struct SlotMapStruct { | ||
72 | u8 AgentId; | ||
73 | u8 SecondaryAgentId; | ||
74 | u8 PhbId; | ||
75 | char CardLocation[3]; | ||
76 | char Parms[8]; | ||
77 | char Reserved[2]; | ||
78 | }; | ||
79 | typedef struct SlotMapStruct SlotMap; | ||
80 | #define SLOT_ENTRY_SIZE 16 | ||
81 | |||
82 | /* | ||
83 | * Parse the Slot Area | ||
84 | */ | ||
85 | static void __init iSeries_Parse_SlotArea(SlotMap *MapPtr, int MapLen, | ||
86 | HvAgentId agent, u8 *PhbId, char card[4]) | ||
87 | { | ||
88 | int SlotMapLen = MapLen; | ||
89 | SlotMap *SlotMapPtr = MapPtr; | ||
90 | |||
91 | /* | ||
92 | * Parse Slot label until we find the one requested | ||
93 | */ | ||
94 | while (SlotMapLen > 0) { | ||
95 | if (SlotMapPtr->AgentId == agent) { | ||
96 | /* | ||
97 | * If Phb wasn't found, grab the entry first one found. | ||
98 | */ | ||
99 | if (*PhbId == 0xff) | ||
100 | *PhbId = SlotMapPtr->PhbId; | ||
101 | /* Found it, extract the data. */ | ||
102 | if (SlotMapPtr->PhbId == *PhbId) { | ||
103 | memcpy(card, &SlotMapPtr->CardLocation, 3); | ||
104 | card[3] = 0; | ||
105 | break; | ||
106 | } | ||
107 | } | ||
108 | /* Point to the next Slot */ | ||
109 | SlotMapPtr = (SlotMap *)((char *)SlotMapPtr + SLOT_ENTRY_SIZE); | ||
110 | SlotMapLen -= SLOT_ENTRY_SIZE; | ||
111 | } | ||
112 | } | ||
113 | |||
114 | /* | ||
115 | * Parse the Mfg Area | ||
116 | */ | ||
117 | static void __init iSeries_Parse_MfgArea(u8 *AreaData, int AreaLen, | ||
118 | HvAgentId agent, u8 *PhbId, | ||
119 | u8 *frame, char card[4]) | ||
120 | { | ||
121 | MfgArea *MfgAreaPtr = (MfgArea *)AreaData; | ||
122 | int MfgAreaLen = AreaLen; | ||
123 | u16 SlotMapFmt = 0; | ||
124 | |||
125 | /* Parse Mfg Data */ | ||
126 | while (MfgAreaLen > 0) { | ||
127 | int MfgTagLen = MfgAreaPtr->TagLength; | ||
128 | /* Frame ID (FI 4649020310 ) */ | ||
129 | if (MfgAreaPtr->Tag == VpdFruFrameId) /* FI */ | ||
130 | *frame = MfgAreaPtr->AreaData1; | ||
131 | /* Slot Map Format (MF 4D46020004 ) */ | ||
132 | else if (MfgAreaPtr->Tag == VpdSlotMapFormat) /* MF */ | ||
133 | SlotMapFmt = (MfgAreaPtr->AreaData1 * 256) | ||
134 | + MfgAreaPtr->AreaData2; | ||
135 | /* Slot Map (SM 534D90 */ | ||
136 | else if (MfgAreaPtr->Tag == VpdSlotMap) { /* SM */ | ||
137 | SlotMap *SlotMapPtr; | ||
138 | |||
139 | if (SlotMapFmt == 0x1004) | ||
140 | SlotMapPtr = (SlotMap *)((char *)MfgAreaPtr | ||
141 | + MFG_ENTRY_SIZE + 1); | ||
142 | else | ||
143 | SlotMapPtr = (SlotMap *)((char *)MfgAreaPtr | ||
144 | + MFG_ENTRY_SIZE); | ||
145 | iSeries_Parse_SlotArea(SlotMapPtr, MfgTagLen, | ||
146 | agent, PhbId, card); | ||
147 | } | ||
148 | /* | ||
149 | * Point to the next Mfg Area | ||
150 | * Use defined size, sizeof give wrong answer | ||
151 | */ | ||
152 | MfgAreaPtr = (MfgArea *)((char *)MfgAreaPtr + MfgTagLen | ||
153 | + MFG_ENTRY_SIZE); | ||
154 | MfgAreaLen -= (MfgTagLen + MFG_ENTRY_SIZE); | ||
155 | } | ||
156 | } | ||
157 | |||
158 | /* | ||
159 | * Look for "BUS".. Data is not Null terminated. | ||
160 | * PHBID of 0xFF indicates PHB was not found in VPD Data. | ||
161 | */ | ||
162 | static int __init iSeries_Parse_PhbId(u8 *AreaPtr, int AreaLength) | ||
163 | { | ||
164 | u8 *PhbPtr = AreaPtr; | ||
165 | int DataLen = AreaLength; | ||
166 | char PhbId = 0xFF; | ||
167 | |||
168 | while (DataLen > 0) { | ||
169 | if ((*PhbPtr == 'B') && (*(PhbPtr + 1) == 'U') | ||
170 | && (*(PhbPtr + 2) == 'S')) { | ||
171 | PhbPtr += 3; | ||
172 | while (*PhbPtr == ' ') | ||
173 | ++PhbPtr; | ||
174 | PhbId = (*PhbPtr & 0x0F); | ||
175 | break; | ||
176 | } | ||
177 | ++PhbPtr; | ||
178 | --DataLen; | ||
179 | } | ||
180 | return PhbId; | ||
181 | } | ||
182 | |||
183 | /* | ||
184 | * Parse out the VPD Areas | ||
185 | */ | ||
186 | static void __init iSeries_Parse_Vpd(u8 *VpdData, int VpdDataLen, | ||
187 | HvAgentId agent, u8 *frame, char card[4]) | ||
188 | { | ||
189 | u8 *TagPtr = VpdData; | ||
190 | int DataLen = VpdDataLen - 3; | ||
191 | u8 PhbId = 0xff; | ||
192 | |||
193 | while ((*TagPtr != VpdEndOfAreaTag) && (DataLen > 0)) { | ||
194 | int AreaLen = *(TagPtr + 1) + (*(TagPtr + 2) * 256); | ||
195 | u8 *AreaData = TagPtr + 3; | ||
196 | |||
197 | if (*TagPtr == VpdIdStringTag) | ||
198 | PhbId = iSeries_Parse_PhbId(AreaData, AreaLen); | ||
199 | else if (*TagPtr == VpdVendorAreaTag) | ||
200 | iSeries_Parse_MfgArea(AreaData, AreaLen, | ||
201 | agent, &PhbId, frame, card); | ||
202 | /* Point to next Area. */ | ||
203 | TagPtr = AreaData + AreaLen; | ||
204 | DataLen -= AreaLen; | ||
205 | } | ||
206 | } | ||
207 | |||
208 | static int __init iSeries_Get_Location_Code(u16 bus, HvAgentId agent, | ||
209 | u8 *frame, char card[4]) | ||
210 | { | ||
211 | int status = 0; | ||
212 | int BusVpdLen = 0; | ||
213 | u8 *BusVpdPtr = kmalloc(BUS_VPDSIZE, GFP_KERNEL); | ||
214 | |||
215 | if (BusVpdPtr == NULL) { | ||
216 | printk("PCI: Bus VPD Buffer allocation failure.\n"); | ||
217 | return 0; | ||
218 | } | ||
219 | BusVpdLen = HvCallPci_getBusVpd(bus, iseries_hv_addr(BusVpdPtr), | ||
220 | BUS_VPDSIZE); | ||
221 | if (BusVpdLen == 0) { | ||
222 | printk("PCI: Bus VPD Buffer zero length.\n"); | ||
223 | goto out_free; | ||
224 | } | ||
225 | /* printk("PCI: BusVpdPtr: %p, %d\n",BusVpdPtr, BusVpdLen); */ | ||
226 | /* Make sure this is what I think it is */ | ||
227 | if (*BusVpdPtr != VpdIdStringTag) { /* 0x82 */ | ||
228 | printk("PCI: Bus VPD Buffer missing starting tag.\n"); | ||
229 | goto out_free; | ||
230 | } | ||
231 | iSeries_Parse_Vpd(BusVpdPtr, BusVpdLen, agent, frame, card); | ||
232 | status = 1; | ||
233 | out_free: | ||
234 | kfree(BusVpdPtr); | ||
235 | return status; | ||
236 | } | ||
237 | |||
238 | /* | ||
239 | * Prints the device information. | ||
240 | * - Pass in pci_dev* pointer to the device. | ||
241 | * - Pass in the device count | ||
242 | * | ||
243 | * Format: | ||
244 | * PCI: Bus 0, Device 26, Vendor 0x12AE Frame 1, Card C10 Ethernet | ||
245 | * controller | ||
246 | */ | ||
247 | void __init iSeries_Device_Information(struct pci_dev *PciDev, int count) | ||
248 | { | ||
249 | struct device_node *DevNode = PciDev->sysdata; | ||
250 | struct pci_dn *pdn; | ||
251 | u16 bus; | ||
252 | u8 frame = 0; | ||
253 | char card[4]; | ||
254 | HvSubBusNumber subbus; | ||
255 | HvAgentId agent; | ||
256 | |||
257 | if (DevNode == NULL) { | ||
258 | printk("%d. PCI: iSeries_Device_Information DevNode is NULL\n", | ||
259 | count); | ||
260 | return; | ||
261 | } | ||
262 | |||
263 | pdn = PCI_DN(DevNode); | ||
264 | bus = pdn->busno; | ||
265 | subbus = pdn->bussubno; | ||
266 | agent = ISERIES_PCI_AGENTID(ISERIES_GET_DEVICE_FROM_SUBBUS(subbus), | ||
267 | ISERIES_GET_FUNCTION_FROM_SUBBUS(subbus)); | ||
268 | |||
269 | if (iSeries_Get_Location_Code(bus, agent, &frame, card)) { | ||
270 | printk("%d. PCI: Bus%3d, Device%3d, Vendor %04X Frame%3d, " | ||
271 | "Card %4s 0x%04X\n", count, bus, | ||
272 | PCI_SLOT(PciDev->devfn), PciDev->vendor, frame, | ||
273 | card, (int)(PciDev->class >> 8)); | ||
274 | } | ||
275 | } | ||
diff --git a/arch/powerpc/platforms/maple/Kconfig b/arch/powerpc/platforms/maple/Kconfig index f7c95eb5d8ba..a6467a5591fa 100644 --- a/arch/powerpc/platforms/maple/Kconfig +++ b/arch/powerpc/platforms/maple/Kconfig | |||
@@ -1,6 +1,7 @@ | |||
1 | config PPC_MAPLE | 1 | config PPC_MAPLE |
2 | depends on PPC_MULTIPLATFORM && PPC64 | 2 | depends on PPC_MULTIPLATFORM && PPC64 |
3 | bool "Maple 970FX Evaluation Board" | 3 | bool "Maple 970FX Evaluation Board" |
4 | select PCI | ||
4 | select MPIC | 5 | select MPIC |
5 | select U3_DART | 6 | select U3_DART |
6 | select MPIC_U3_HT_IRQS | 7 | select MPIC_U3_HT_IRQS |
diff --git a/arch/powerpc/platforms/maple/pci.c b/arch/powerpc/platforms/maple/pci.c index 771ed0cf29a5..3ffa0ac170ee 100644 --- a/arch/powerpc/platforms/maple/pci.c +++ b/arch/powerpc/platforms/maple/pci.c | |||
@@ -558,7 +558,7 @@ void __init maple_pci_init(void) | |||
558 | * safe assumptions hopefully. | 558 | * safe assumptions hopefully. |
559 | */ | 559 | */ |
560 | if (u3_agp) { | 560 | if (u3_agp) { |
561 | struct device_node *np = u3_agp->arch_data; | 561 | struct device_node *np = u3_agp->dn; |
562 | PCI_DN(np)->busno = 0xf0; | 562 | PCI_DN(np)->busno = 0xf0; |
563 | for (np = np->child; np; np = np->sibling) | 563 | for (np = np->child; np; np = np->sibling) |
564 | PCI_DN(np)->busno = 0xf0; | 564 | PCI_DN(np)->busno = 0xf0; |
diff --git a/arch/powerpc/platforms/maple/setup.c b/arch/powerpc/platforms/maple/setup.c index 144177d77cf1..3ce2d73b4177 100644 --- a/arch/powerpc/platforms/maple/setup.c +++ b/arch/powerpc/platforms/maple/setup.c | |||
@@ -42,6 +42,7 @@ | |||
42 | #include <linux/serial.h> | 42 | #include <linux/serial.h> |
43 | #include <linux/smp.h> | 43 | #include <linux/smp.h> |
44 | #include <linux/bitops.h> | 44 | #include <linux/bitops.h> |
45 | #include <linux/of_device.h> | ||
45 | 46 | ||
46 | #include <asm/processor.h> | 47 | #include <asm/processor.h> |
47 | #include <asm/sections.h> | 48 | #include <asm/sections.h> |
@@ -56,7 +57,6 @@ | |||
56 | #include <asm/dma.h> | 57 | #include <asm/dma.h> |
57 | #include <asm/cputable.h> | 58 | #include <asm/cputable.h> |
58 | #include <asm/time.h> | 59 | #include <asm/time.h> |
59 | #include <asm/of_device.h> | ||
60 | #include <asm/lmb.h> | 60 | #include <asm/lmb.h> |
61 | #include <asm/mpic.h> | 61 | #include <asm/mpic.h> |
62 | #include <asm/rtas.h> | 62 | #include <asm/rtas.h> |
diff --git a/arch/powerpc/platforms/pasemi/Kconfig b/arch/powerpc/platforms/pasemi/Kconfig index 735e1536cbfc..348e0619e3e5 100644 --- a/arch/powerpc/platforms/pasemi/Kconfig +++ b/arch/powerpc/platforms/pasemi/Kconfig | |||
@@ -3,6 +3,7 @@ config PPC_PASEMI | |||
3 | bool "PA Semi SoC-based platforms" | 3 | bool "PA Semi SoC-based platforms" |
4 | default n | 4 | default n |
5 | select MPIC | 5 | select MPIC |
6 | select PCI | ||
6 | select PPC_UDBG_16550 | 7 | select PPC_UDBG_16550 |
7 | select PPC_NATIVE | 8 | select PPC_NATIVE |
8 | select MPIC_BROKEN_REGREAD | 9 | select MPIC_BROKEN_REGREAD |
@@ -17,7 +18,7 @@ config PPC_PASEMI_IOMMU | |||
17 | bool "PA Semi IOMMU support" | 18 | bool "PA Semi IOMMU support" |
18 | depends on PPC_PASEMI | 19 | depends on PPC_PASEMI |
19 | help | 20 | help |
20 | IOMMU support for PA6T-1682M | 21 | IOMMU support for PA Semi PWRficient |
21 | 22 | ||
22 | config PPC_PASEMI_IOMMU_DMA_FORCE | 23 | config PPC_PASEMI_IOMMU_DMA_FORCE |
23 | bool "Force DMA engine to use IOMMU" | 24 | bool "Force DMA engine to use IOMMU" |
@@ -36,13 +37,4 @@ config PPC_PASEMI_MDIO | |||
36 | help | 37 | help |
37 | Driver for MDIO via GPIO on PWRficient platforms | 38 | Driver for MDIO via GPIO on PWRficient platforms |
38 | 39 | ||
39 | config ELECTRA_IDE | ||
40 | tristate "Electra IDE driver" | ||
41 | default y | ||
42 | depends on PPC_PASEMI && ATA | ||
43 | select PATA_PLATFORM | ||
44 | help | ||
45 | This includes driver support for the Electra on-board IDE | ||
46 | interface. | ||
47 | |||
48 | endmenu | 40 | endmenu |
diff --git a/arch/powerpc/platforms/pasemi/Makefile b/arch/powerpc/platforms/pasemi/Makefile index e636daa7a80e..8f52d7515793 100644 --- a/arch/powerpc/platforms/pasemi/Makefile +++ b/arch/powerpc/platforms/pasemi/Makefile | |||
@@ -1,4 +1,3 @@ | |||
1 | obj-y += setup.o pci.o time.o idle.o powersave.o iommu.o dma_lib.o | 1 | obj-y += setup.o pci.o time.o idle.o powersave.o iommu.o dma_lib.o |
2 | obj-$(CONFIG_PPC_PASEMI_MDIO) += gpio_mdio.o | 2 | obj-$(CONFIG_PPC_PASEMI_MDIO) += gpio_mdio.o |
3 | obj-$(CONFIG_ELECTRA_IDE) += electra_ide.o | ||
4 | obj-$(CONFIG_PPC_PASEMI_CPUFREQ) += cpufreq.o | 3 | obj-$(CONFIG_PPC_PASEMI_CPUFREQ) += cpufreq.o |
diff --git a/arch/powerpc/platforms/pasemi/cpufreq.c b/arch/powerpc/platforms/pasemi/cpufreq.c index 1cfb8b0c8fec..58556b028a4c 100644 --- a/arch/powerpc/platforms/pasemi/cpufreq.c +++ b/arch/powerpc/platforms/pasemi/cpufreq.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <asm/io.h> | 32 | #include <asm/io.h> |
33 | #include <asm/prom.h> | 33 | #include <asm/prom.h> |
34 | #include <asm/time.h> | 34 | #include <asm/time.h> |
35 | #include <asm/smp.h> | ||
35 | 36 | ||
36 | #define SDCASR_REG 0x0100 | 37 | #define SDCASR_REG 0x0100 |
37 | #define SDCASR_REG_STRIDE 0x1000 | 38 | #define SDCASR_REG_STRIDE 0x1000 |
@@ -124,6 +125,11 @@ static void set_astate(int cpu, unsigned int astate) | |||
124 | local_irq_restore(flags); | 125 | local_irq_restore(flags); |
125 | } | 126 | } |
126 | 127 | ||
128 | int check_astate(void) | ||
129 | { | ||
130 | return get_cur_astate(hard_smp_processor_id()); | ||
131 | } | ||
132 | |||
127 | void restore_astate(int cpu) | 133 | void restore_astate(int cpu) |
128 | { | 134 | { |
129 | set_astate(cpu, current_astate); | 135 | set_astate(cpu, current_astate); |
@@ -147,7 +153,10 @@ static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy) | |||
147 | if (!cpu) | 153 | if (!cpu) |
148 | goto out; | 154 | goto out; |
149 | 155 | ||
150 | dn = of_find_compatible_node(NULL, "sdc", "1682m-sdc"); | 156 | dn = of_find_compatible_node(NULL, NULL, "1682m-sdc"); |
157 | if (!dn) | ||
158 | dn = of_find_compatible_node(NULL, NULL, | ||
159 | "pasemi,pwrficient-sdc"); | ||
151 | if (!dn) | 160 | if (!dn) |
152 | goto out; | 161 | goto out; |
153 | err = of_address_to_resource(dn, 0, &res); | 162 | err = of_address_to_resource(dn, 0, &res); |
@@ -160,7 +169,10 @@ static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy) | |||
160 | goto out; | 169 | goto out; |
161 | } | 170 | } |
162 | 171 | ||
163 | dn = of_find_compatible_node(NULL, "gizmo", "1682m-gizmo"); | 172 | dn = of_find_compatible_node(NULL, NULL, "1682m-gizmo"); |
173 | if (!dn) | ||
174 | dn = of_find_compatible_node(NULL, NULL, | ||
175 | "pasemi,pwrficient-gizmo"); | ||
164 | if (!dn) { | 176 | if (!dn) { |
165 | err = -ENODEV; | 177 | err = -ENODEV; |
166 | goto out_unmap_sdcasr; | 178 | goto out_unmap_sdcasr; |
@@ -292,7 +304,8 @@ static struct cpufreq_driver pas_cpufreq_driver = { | |||
292 | 304 | ||
293 | static int __init pas_cpufreq_init(void) | 305 | static int __init pas_cpufreq_init(void) |
294 | { | 306 | { |
295 | if (!machine_is_compatible("PA6T-1682M")) | 307 | if (!machine_is_compatible("PA6T-1682M") && |
308 | !machine_is_compatible("pasemi,pwrficient")) | ||
296 | return -ENODEV; | 309 | return -ENODEV; |
297 | 310 | ||
298 | return cpufreq_register_driver(&pas_cpufreq_driver); | 311 | return cpufreq_register_driver(&pas_cpufreq_driver); |
diff --git a/arch/powerpc/platforms/pasemi/electra_ide.c b/arch/powerpc/platforms/pasemi/electra_ide.c deleted file mode 100644 index 12fb0c949263..000000000000 --- a/arch/powerpc/platforms/pasemi/electra_ide.c +++ /dev/null | |||
@@ -1,96 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007 PA Semi, Inc | ||
3 | * | ||
4 | * Maintained by: Olof Johansson <olof@lixom.net> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #include <linux/platform_device.h> | ||
21 | |||
22 | #include <asm/prom.h> | ||
23 | #include <asm/system.h> | ||
24 | |||
25 | /* The electra IDE interface is incredibly simple: Just a device on the localbus | ||
26 | * with interrupts hooked up to one of the GPIOs. The device tree contains the | ||
27 | * address window and interrupt mappings already, and the pata_platform driver handles | ||
28 | * the rest. We just need to hook the two up. | ||
29 | */ | ||
30 | |||
31 | #define MAX_IFS 4 /* really, we have only one */ | ||
32 | |||
33 | static struct platform_device *pdevs[MAX_IFS]; | ||
34 | |||
35 | static int __devinit electra_ide_init(void) | ||
36 | { | ||
37 | struct device_node *np; | ||
38 | struct resource r[3]; | ||
39 | int ret = 0; | ||
40 | int i; | ||
41 | |||
42 | np = of_find_compatible_node(NULL, "ide", "electra-ide"); | ||
43 | i = 0; | ||
44 | |||
45 | while (np && i < MAX_IFS) { | ||
46 | memset(r, 0, sizeof(r)); | ||
47 | |||
48 | /* pata_platform wants two address ranges: one for the base registers, | ||
49 | * another for the control (altstatus). It's located at offset 0x3f6 in | ||
50 | * the window, but the device tree only has one large register window | ||
51 | * that covers both ranges. So we need to split it up by hand here: | ||
52 | */ | ||
53 | |||
54 | ret = of_address_to_resource(np, 0, &r[0]); | ||
55 | if (ret) | ||
56 | goto out; | ||
57 | ret = of_address_to_resource(np, 0, &r[1]); | ||
58 | if (ret) | ||
59 | goto out; | ||
60 | |||
61 | r[1].start += 0x3f6; | ||
62 | r[0].end = r[1].start-1; | ||
63 | |||
64 | r[2].start = irq_of_parse_and_map(np, 0); | ||
65 | r[2].end = irq_of_parse_and_map(np, 0); | ||
66 | r[2].flags = IORESOURCE_IRQ; | ||
67 | |||
68 | pr_debug("registering platform device at 0x%lx/0x%lx, irq is %ld\n", | ||
69 | r[0].start, r[1].start, r[2].start); | ||
70 | pdevs[i] = platform_device_register_simple("pata_platform", i, r, 3); | ||
71 | if (IS_ERR(pdevs[i])) { | ||
72 | ret = PTR_ERR(pdevs[i]); | ||
73 | pdevs[i] = NULL; | ||
74 | goto out; | ||
75 | } | ||
76 | np = of_find_compatible_node(np, "ide", "electra-ide"); | ||
77 | } | ||
78 | out: | ||
79 | return ret; | ||
80 | } | ||
81 | module_init(electra_ide_init); | ||
82 | |||
83 | static void __devexit electra_ide_exit(void) | ||
84 | { | ||
85 | int i; | ||
86 | |||
87 | for (i = 0; i < MAX_IFS; i++) | ||
88 | if (pdevs[i]) | ||
89 | platform_device_unregister(pdevs[i]); | ||
90 | } | ||
91 | module_exit(electra_ide_exit); | ||
92 | |||
93 | |||
94 | MODULE_LICENSE("GPL"); | ||
95 | MODULE_AUTHOR ("Olof Johansson <olof@lixom.net>"); | ||
96 | MODULE_DESCRIPTION("PA Semi Electra IDE driver"); | ||
diff --git a/arch/powerpc/platforms/pasemi/gpio_mdio.c b/arch/powerpc/platforms/pasemi/gpio_mdio.c index dae9f658122e..b46542990cf8 100644 --- a/arch/powerpc/platforms/pasemi/gpio_mdio.c +++ b/arch/powerpc/platforms/pasemi/gpio_mdio.c | |||
@@ -30,7 +30,7 @@ | |||
30 | #include <linux/interrupt.h> | 30 | #include <linux/interrupt.h> |
31 | #include <linux/phy.h> | 31 | #include <linux/phy.h> |
32 | #include <linux/platform_device.h> | 32 | #include <linux/platform_device.h> |
33 | #include <asm/of_platform.h> | 33 | #include <linux/of_platform.h> |
34 | 34 | ||
35 | #define DELAY 1 | 35 | #define DELAY 1 |
36 | 36 | ||
@@ -218,45 +218,27 @@ static int __devinit gpio_mdio_probe(struct of_device *ofdev, | |||
218 | const struct of_device_id *match) | 218 | const struct of_device_id *match) |
219 | { | 219 | { |
220 | struct device *dev = &ofdev->dev; | 220 | struct device *dev = &ofdev->dev; |
221 | struct device_node *np = ofdev->node; | 221 | struct device_node *phy_dn, *np = ofdev->node; |
222 | struct device_node *gpio_np; | ||
223 | struct mii_bus *new_bus; | 222 | struct mii_bus *new_bus; |
224 | struct resource res; | ||
225 | struct gpio_priv *priv; | 223 | struct gpio_priv *priv; |
226 | const unsigned int *prop; | 224 | const unsigned int *prop; |
227 | int err = 0; | 225 | int err; |
228 | int i; | 226 | int i; |
229 | 227 | ||
230 | gpio_np = of_find_compatible_node(NULL, "gpio", "1682m-gpio"); | 228 | err = -ENOMEM; |
231 | |||
232 | if (!gpio_np) | ||
233 | return -ENODEV; | ||
234 | |||
235 | err = of_address_to_resource(gpio_np, 0, &res); | ||
236 | of_node_put(gpio_np); | ||
237 | |||
238 | if (err) | ||
239 | return -EINVAL; | ||
240 | |||
241 | if (!gpio_regs) | ||
242 | gpio_regs = ioremap(res.start, 0x100); | ||
243 | |||
244 | if (!gpio_regs) | ||
245 | return -EPERM; | ||
246 | |||
247 | priv = kzalloc(sizeof(struct gpio_priv), GFP_KERNEL); | 229 | priv = kzalloc(sizeof(struct gpio_priv), GFP_KERNEL); |
248 | if (priv == NULL) | 230 | if (!priv) |
249 | return -ENOMEM; | 231 | goto out; |
250 | 232 | ||
251 | new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL); | 233 | new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL); |
252 | 234 | ||
253 | if (new_bus == NULL) | 235 | if (!new_bus) |
254 | return -ENOMEM; | 236 | goto out_free_priv; |
255 | 237 | ||
256 | new_bus->name = "pasemi gpio mdio bus", | 238 | new_bus->name = "pasemi gpio mdio bus"; |
257 | new_bus->read = &gpio_mdio_read, | 239 | new_bus->read = &gpio_mdio_read; |
258 | new_bus->write = &gpio_mdio_write, | 240 | new_bus->write = &gpio_mdio_write; |
259 | new_bus->reset = &gpio_mdio_reset, | 241 | new_bus->reset = &gpio_mdio_reset; |
260 | 242 | ||
261 | prop = of_get_property(np, "reg", NULL); | 243 | prop = of_get_property(np, "reg", NULL); |
262 | new_bus->id = *prop; | 244 | new_bus->id = *prop; |
@@ -265,9 +247,24 @@ static int __devinit gpio_mdio_probe(struct of_device *ofdev, | |||
265 | new_bus->phy_mask = 0; | 247 | new_bus->phy_mask = 0; |
266 | 248 | ||
267 | new_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL); | 249 | new_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL); |
268 | for(i = 0; i < PHY_MAX_ADDR; ++i) | ||
269 | new_bus->irq[i] = irq_create_mapping(NULL, 10); | ||
270 | 250 | ||
251 | if (!new_bus->irq) | ||
252 | goto out_free_bus; | ||
253 | |||
254 | for (i = 0; i < PHY_MAX_ADDR; i++) | ||
255 | new_bus->irq[i] = NO_IRQ; | ||
256 | |||
257 | for (phy_dn = of_get_next_child(np, NULL); | ||
258 | phy_dn != NULL; | ||
259 | phy_dn = of_get_next_child(np, phy_dn)) { | ||
260 | const unsigned int *ip, *regp; | ||
261 | |||
262 | ip = of_get_property(phy_dn, "interrupts", NULL); | ||
263 | regp = of_get_property(phy_dn, "reg", NULL); | ||
264 | if (!ip || !regp || *regp >= PHY_MAX_ADDR) | ||
265 | continue; | ||
266 | new_bus->irq[*regp] = irq_create_mapping(NULL, *ip); | ||
267 | } | ||
271 | 268 | ||
272 | prop = of_get_property(np, "mdc-pin", NULL); | 269 | prop = of_get_property(np, "mdc-pin", NULL); |
273 | priv->mdc_pin = *prop; | 270 | priv->mdc_pin = *prop; |
@@ -280,17 +277,21 @@ static int __devinit gpio_mdio_probe(struct of_device *ofdev, | |||
280 | 277 | ||
281 | err = mdiobus_register(new_bus); | 278 | err = mdiobus_register(new_bus); |
282 | 279 | ||
283 | if (0 != err) { | 280 | if (err != 0) { |
284 | printk(KERN_ERR "%s: Cannot register as MDIO bus, err %d\n", | 281 | printk(KERN_ERR "%s: Cannot register as MDIO bus, err %d\n", |
285 | new_bus->name, err); | 282 | new_bus->name, err); |
286 | goto bus_register_fail; | 283 | goto out_free_irq; |
287 | } | 284 | } |
288 | 285 | ||
289 | return 0; | 286 | return 0; |
290 | 287 | ||
291 | bus_register_fail: | 288 | out_free_irq: |
289 | kfree(new_bus->irq); | ||
290 | out_free_bus: | ||
292 | kfree(new_bus); | 291 | kfree(new_bus); |
293 | 292 | out_free_priv: | |
293 | kfree(priv); | ||
294 | out: | ||
294 | return err; | 295 | return err; |
295 | } | 296 | } |
296 | 297 | ||
@@ -317,6 +318,7 @@ static struct of_device_id gpio_mdio_match[] = | |||
317 | }, | 318 | }, |
318 | {}, | 319 | {}, |
319 | }; | 320 | }; |
321 | MODULE_DEVICE_TABLE(of, gpio_mdio_match); | ||
320 | 322 | ||
321 | static struct of_platform_driver gpio_mdio_driver = | 323 | static struct of_platform_driver gpio_mdio_driver = |
322 | { | 324 | { |
@@ -330,12 +332,32 @@ static struct of_platform_driver gpio_mdio_driver = | |||
330 | 332 | ||
331 | int gpio_mdio_init(void) | 333 | int gpio_mdio_init(void) |
332 | { | 334 | { |
335 | struct device_node *np; | ||
336 | |||
337 | np = of_find_compatible_node(NULL, NULL, "1682m-gpio"); | ||
338 | if (!np) | ||
339 | np = of_find_compatible_node(NULL, NULL, | ||
340 | "pasemi,pwrficient-gpio"); | ||
341 | if (!np) | ||
342 | return -ENODEV; | ||
343 | gpio_regs = of_iomap(np, 0); | ||
344 | of_node_put(np); | ||
345 | |||
346 | if (!gpio_regs) | ||
347 | return -ENODEV; | ||
348 | |||
333 | return of_register_platform_driver(&gpio_mdio_driver); | 349 | return of_register_platform_driver(&gpio_mdio_driver); |
334 | } | 350 | } |
351 | module_init(gpio_mdio_init); | ||
335 | 352 | ||
336 | void gpio_mdio_exit(void) | 353 | void gpio_mdio_exit(void) |
337 | { | 354 | { |
338 | of_unregister_platform_driver(&gpio_mdio_driver); | 355 | of_unregister_platform_driver(&gpio_mdio_driver); |
356 | if (gpio_regs) | ||
357 | iounmap(gpio_regs); | ||
339 | } | 358 | } |
340 | device_initcall(gpio_mdio_init); | 359 | module_exit(gpio_mdio_exit); |
341 | 360 | ||
361 | MODULE_LICENSE("GPL"); | ||
362 | MODULE_AUTHOR("Olof Johansson <olof@lixom.net>"); | ||
363 | MODULE_DESCRIPTION("Driver for MDIO over GPIO on PA Semi PWRficient-based boards"); | ||
diff --git a/arch/powerpc/platforms/pasemi/idle.c b/arch/powerpc/platforms/pasemi/idle.c index d8e1fcc78513..43911d8b0206 100644 --- a/arch/powerpc/platforms/pasemi/idle.c +++ b/arch/powerpc/platforms/pasemi/idle.c | |||
@@ -74,9 +74,6 @@ static int pasemi_system_reset_exception(struct pt_regs *regs) | |||
74 | 74 | ||
75 | static int __init pasemi_idle_init(void) | 75 | static int __init pasemi_idle_init(void) |
76 | { | 76 | { |
77 | if (!machine_is(pasemi)) | ||
78 | return -ENODEV; | ||
79 | |||
80 | #ifndef CONFIG_PPC_PASEMI_CPUFREQ | 77 | #ifndef CONFIG_PPC_PASEMI_CPUFREQ |
81 | printk(KERN_WARNING "No cpufreq driver, powersavings modes disabled\n"); | 78 | printk(KERN_WARNING "No cpufreq driver, powersavings modes disabled\n"); |
82 | current_mode = 0; | 79 | current_mode = 0; |
@@ -88,7 +85,7 @@ static int __init pasemi_idle_init(void) | |||
88 | 85 | ||
89 | return 0; | 86 | return 0; |
90 | } | 87 | } |
91 | late_initcall(pasemi_idle_init); | 88 | machine_late_initcall(pasemi, pasemi_idle_init); |
92 | 89 | ||
93 | static int __init idle_param(char *p) | 90 | static int __init idle_param(char *p) |
94 | { | 91 | { |
diff --git a/arch/powerpc/platforms/pasemi/pasemi.h b/arch/powerpc/platforms/pasemi/pasemi.h index 58b344c6fc38..b1e524f7489d 100644 --- a/arch/powerpc/platforms/pasemi/pasemi.h +++ b/arch/powerpc/platforms/pasemi/pasemi.h | |||
@@ -17,8 +17,14 @@ extern void idle_doze(void); | |||
17 | 17 | ||
18 | /* Restore astate to last set */ | 18 | /* Restore astate to last set */ |
19 | #ifdef CONFIG_PPC_PASEMI_CPUFREQ | 19 | #ifdef CONFIG_PPC_PASEMI_CPUFREQ |
20 | extern int check_astate(void); | ||
20 | extern void restore_astate(int cpu); | 21 | extern void restore_astate(int cpu); |
21 | #else | 22 | #else |
23 | static inline int check_astate(void) | ||
24 | { | ||
25 | /* Always return >0 so we never power save */ | ||
26 | return 1; | ||
27 | } | ||
22 | static inline void restore_astate(int cpu) | 28 | static inline void restore_astate(int cpu) |
23 | { | 29 | { |
24 | } | 30 | } |
diff --git a/arch/powerpc/platforms/pasemi/powersave.S b/arch/powerpc/platforms/pasemi/powersave.S index 6d0fba6aab17..56f45adcd089 100644 --- a/arch/powerpc/platforms/pasemi/powersave.S +++ b/arch/powerpc/platforms/pasemi/powersave.S | |||
@@ -62,7 +62,16 @@ sleep_common: | |||
62 | mflr r0 | 62 | mflr r0 |
63 | std r0, 16(r1) | 63 | std r0, 16(r1) |
64 | stdu r1,-64(r1) | 64 | stdu r1,-64(r1) |
65 | #ifdef CONFIG_PPC_PASEMI_CPUFREQ | ||
66 | std r3, 48(r1) | ||
65 | 67 | ||
68 | /* Only do power savings when in astate 0 */ | ||
69 | bl .check_astate | ||
70 | cmpwi r3,0 | ||
71 | bne 1f | ||
72 | |||
73 | ld r3, 48(r1) | ||
74 | #endif | ||
66 | LOAD_REG_IMMEDIATE(r6,MSR_DR|MSR_IR|MSR_ME|MSR_EE) | 75 | LOAD_REG_IMMEDIATE(r6,MSR_DR|MSR_IR|MSR_ME|MSR_EE) |
67 | mfmsr r4 | 76 | mfmsr r4 |
68 | andc r5,r4,r6 | 77 | andc r5,r4,r6 |
@@ -73,7 +82,7 @@ sleep_common: | |||
73 | 82 | ||
74 | mtmsrd r4,0 | 83 | mtmsrd r4,0 |
75 | 84 | ||
76 | addi r1,r1,64 | 85 | 1: addi r1,r1,64 |
77 | ld r0,16(r1) | 86 | ld r0,16(r1) |
78 | mtlr r0 | 87 | mtlr r0 |
79 | blr | 88 | blr |
diff --git a/arch/powerpc/platforms/pasemi/setup.c b/arch/powerpc/platforms/pasemi/setup.c index 3d62060498b4..c64fb5bfb37e 100644 --- a/arch/powerpc/platforms/pasemi/setup.c +++ b/arch/powerpc/platforms/pasemi/setup.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/delay.h> | 27 | #include <linux/delay.h> |
28 | #include <linux/console.h> | 28 | #include <linux/console.h> |
29 | #include <linux/pci.h> | 29 | #include <linux/pci.h> |
30 | #include <linux/of_platform.h> | ||
30 | 31 | ||
31 | #include <asm/prom.h> | 32 | #include <asm/prom.h> |
32 | #include <asm/system.h> | 33 | #include <asm/system.h> |
@@ -35,7 +36,7 @@ | |||
35 | #include <asm/mpic.h> | 36 | #include <asm/mpic.h> |
36 | #include <asm/smp.h> | 37 | #include <asm/smp.h> |
37 | #include <asm/time.h> | 38 | #include <asm/time.h> |
38 | #include <asm/of_platform.h> | 39 | #include <asm/mmu.h> |
39 | 40 | ||
40 | #include <pcmcia/ss.h> | 41 | #include <pcmcia/ss.h> |
41 | #include <pcmcia/cistpl.h> | 42 | #include <pcmcia/cistpl.h> |
@@ -43,6 +44,10 @@ | |||
43 | 44 | ||
44 | #include "pasemi.h" | 45 | #include "pasemi.h" |
45 | 46 | ||
47 | #if !defined(CONFIG_SMP) | ||
48 | static void smp_send_stop(void) {} | ||
49 | #endif | ||
50 | |||
46 | /* SDC reset register, must be pre-mapped at reset time */ | 51 | /* SDC reset register, must be pre-mapped at reset time */ |
47 | static void __iomem *reset_reg; | 52 | static void __iomem *reset_reg; |
48 | 53 | ||
@@ -56,10 +61,14 @@ struct mce_regs { | |||
56 | 61 | ||
57 | static struct mce_regs mce_regs[MAX_MCE_REGS]; | 62 | static struct mce_regs mce_regs[MAX_MCE_REGS]; |
58 | static int num_mce_regs; | 63 | static int num_mce_regs; |
64 | static int nmi_virq = NO_IRQ; | ||
59 | 65 | ||
60 | 66 | ||
61 | static void pas_restart(char *cmd) | 67 | static void pas_restart(char *cmd) |
62 | { | 68 | { |
69 | /* Need to put others cpu in hold loop so they're not sleeping */ | ||
70 | smp_send_stop(); | ||
71 | udelay(10000); | ||
63 | printk("Restarting...\n"); | 72 | printk("Restarting...\n"); |
64 | while (1) | 73 | while (1) |
65 | out_le32(reset_reg, 0x6000000); | 74 | out_le32(reset_reg, 0x6000000); |
@@ -126,9 +135,6 @@ static int __init pas_setup_mce_regs(void) | |||
126 | struct pci_dev *dev; | 135 | struct pci_dev *dev; |
127 | int reg; | 136 | int reg; |
128 | 137 | ||
129 | if (!machine_is(pasemi)) | ||
130 | return -ENODEV; | ||
131 | |||
132 | /* Remap various SoC status registers for use by the MCE handler */ | 138 | /* Remap various SoC status registers for use by the MCE handler */ |
133 | 139 | ||
134 | reg = 0; | 140 | reg = 0; |
@@ -172,7 +178,7 @@ static int __init pas_setup_mce_regs(void) | |||
172 | 178 | ||
173 | return 0; | 179 | return 0; |
174 | } | 180 | } |
175 | device_initcall(pas_setup_mce_regs); | 181 | machine_device_initcall(pasemi, pas_setup_mce_regs); |
176 | 182 | ||
177 | static __init void pas_init_IRQ(void) | 183 | static __init void pas_init_IRQ(void) |
178 | { | 184 | { |
@@ -181,6 +187,8 @@ static __init void pas_init_IRQ(void) | |||
181 | unsigned long openpic_addr; | 187 | unsigned long openpic_addr; |
182 | const unsigned int *opprop; | 188 | const unsigned int *opprop; |
183 | int naddr, opplen; | 189 | int naddr, opplen; |
190 | int mpic_flags; | ||
191 | const unsigned int *nmiprop; | ||
184 | struct mpic *mpic; | 192 | struct mpic *mpic; |
185 | 193 | ||
186 | mpic_node = NULL; | 194 | mpic_node = NULL; |
@@ -213,13 +221,26 @@ static __init void pas_init_IRQ(void) | |||
213 | openpic_addr = of_read_number(opprop, naddr); | 221 | openpic_addr = of_read_number(opprop, naddr); |
214 | printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic_addr); | 222 | printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic_addr); |
215 | 223 | ||
224 | mpic_flags = MPIC_PRIMARY | MPIC_LARGE_VECTORS | MPIC_NO_BIAS; | ||
225 | |||
226 | nmiprop = of_get_property(mpic_node, "nmi-source", NULL); | ||
227 | if (nmiprop) | ||
228 | mpic_flags |= MPIC_ENABLE_MCK; | ||
229 | |||
216 | mpic = mpic_alloc(mpic_node, openpic_addr, | 230 | mpic = mpic_alloc(mpic_node, openpic_addr, |
217 | MPIC_PRIMARY|MPIC_LARGE_VECTORS, | 231 | mpic_flags, 0, 0, "PASEMI-OPIC"); |
218 | 0, 0, " PAS-OPIC "); | ||
219 | BUG_ON(!mpic); | 232 | BUG_ON(!mpic); |
220 | 233 | ||
221 | mpic_assign_isu(mpic, 0, openpic_addr + 0x10000); | 234 | mpic_assign_isu(mpic, 0, openpic_addr + 0x10000); |
222 | mpic_init(mpic); | 235 | mpic_init(mpic); |
236 | /* The NMI/MCK source needs to be prio 15 */ | ||
237 | if (nmiprop) { | ||
238 | nmi_virq = irq_create_mapping(NULL, *nmiprop); | ||
239 | mpic_irq_set_priority(nmi_virq, 15); | ||
240 | set_irq_type(nmi_virq, IRQ_TYPE_EDGE_RISING); | ||
241 | mpic_unmask_irq(nmi_virq); | ||
242 | } | ||
243 | |||
223 | of_node_put(mpic_node); | 244 | of_node_put(mpic_node); |
224 | of_node_put(root); | 245 | of_node_put(root); |
225 | } | 246 | } |
@@ -239,6 +260,14 @@ static int pas_machine_check_handler(struct pt_regs *regs) | |||
239 | 260 | ||
240 | srr0 = regs->nip; | 261 | srr0 = regs->nip; |
241 | srr1 = regs->msr; | 262 | srr1 = regs->msr; |
263 | |||
264 | if (nmi_virq != NO_IRQ && mpic_get_mcirq() == nmi_virq) { | ||
265 | printk(KERN_ERR "NMI delivered\n"); | ||
266 | debugger(regs); | ||
267 | mpic_end_irq(nmi_virq); | ||
268 | goto out; | ||
269 | } | ||
270 | |||
242 | dsisr = mfspr(SPRN_DSISR); | 271 | dsisr = mfspr(SPRN_DSISR); |
243 | printk(KERN_ERR "Machine Check on CPU %d\n", cpu); | 272 | printk(KERN_ERR "Machine Check on CPU %d\n", cpu); |
244 | printk(KERN_ERR "SRR0 0x%016lx SRR1 0x%016lx\n", srr0, srr1); | 273 | printk(KERN_ERR "SRR0 0x%016lx SRR1 0x%016lx\n", srr0, srr1); |
@@ -295,14 +324,14 @@ static int pas_machine_check_handler(struct pt_regs *regs) | |||
295 | int i; | 324 | int i; |
296 | 325 | ||
297 | printk(KERN_ERR "slb contents:\n"); | 326 | printk(KERN_ERR "slb contents:\n"); |
298 | for (i = 0; i < SLB_NUM_ENTRIES; i++) { | 327 | for (i = 0; i < mmu_slb_size; i++) { |
299 | asm volatile("slbmfee %0,%1" : "=r" (e) : "r" (i)); | 328 | asm volatile("slbmfee %0,%1" : "=r" (e) : "r" (i)); |
300 | asm volatile("slbmfev %0,%1" : "=r" (v) : "r" (i)); | 329 | asm volatile("slbmfev %0,%1" : "=r" (v) : "r" (i)); |
301 | printk(KERN_ERR "%02d %016lx %016lx\n", i, e, v); | 330 | printk(KERN_ERR "%02d %016lx %016lx\n", i, e, v); |
302 | } | 331 | } |
303 | } | 332 | } |
304 | 333 | ||
305 | 334 | out: | |
306 | /* SRR1[62] is from MSR[62] if recoverable, so pass that back */ | 335 | /* SRR1[62] is from MSR[62] if recoverable, so pass that back */ |
307 | return !!(srr1 & 0x2); | 336 | return !!(srr1 & 0x2); |
308 | } | 337 | } |
@@ -362,16 +391,17 @@ static inline void pasemi_pcmcia_init(void) | |||
362 | 391 | ||
363 | 392 | ||
364 | static struct of_device_id pasemi_bus_ids[] = { | 393 | static struct of_device_id pasemi_bus_ids[] = { |
394 | /* Unfortunately needed for legacy firmwares */ | ||
365 | { .type = "localbus", }, | 395 | { .type = "localbus", }, |
366 | { .type = "sdc", }, | 396 | { .type = "sdc", }, |
397 | /* These are the proper entries, which newer firmware uses */ | ||
398 | { .compatible = "pasemi,localbus", }, | ||
399 | { .compatible = "pasemi,sdc", }, | ||
367 | {}, | 400 | {}, |
368 | }; | 401 | }; |
369 | 402 | ||
370 | static int __init pasemi_publish_devices(void) | 403 | static int __init pasemi_publish_devices(void) |
371 | { | 404 | { |
372 | if (!machine_is(pasemi)) | ||
373 | return 0; | ||
374 | |||
375 | pasemi_pcmcia_init(); | 405 | pasemi_pcmcia_init(); |
376 | 406 | ||
377 | /* Publish OF platform devices for SDC and other non-PCI devices */ | 407 | /* Publish OF platform devices for SDC and other non-PCI devices */ |
@@ -379,7 +409,7 @@ static int __init pasemi_publish_devices(void) | |||
379 | 409 | ||
380 | return 0; | 410 | return 0; |
381 | } | 411 | } |
382 | device_initcall(pasemi_publish_devices); | 412 | machine_device_initcall(pasemi, pasemi_publish_devices); |
383 | 413 | ||
384 | 414 | ||
385 | /* | 415 | /* |
@@ -389,7 +419,8 @@ static int __init pas_probe(void) | |||
389 | { | 419 | { |
390 | unsigned long root = of_get_flat_dt_root(); | 420 | unsigned long root = of_get_flat_dt_root(); |
391 | 421 | ||
392 | if (!of_flat_dt_is_compatible(root, "PA6T-1682M")) | 422 | if (!of_flat_dt_is_compatible(root, "PA6T-1682M") && |
423 | !of_flat_dt_is_compatible(root, "pasemi,pwrficient")) | ||
393 | return 0; | 424 | return 0; |
394 | 425 | ||
395 | hpte_init_native(); | 426 | hpte_init_native(); |
@@ -400,7 +431,7 @@ static int __init pas_probe(void) | |||
400 | } | 431 | } |
401 | 432 | ||
402 | define_machine(pasemi) { | 433 | define_machine(pasemi) { |
403 | .name = "PA Semi PA6T-1682M", | 434 | .name = "PA Semi PWRficient", |
404 | .probe = pas_probe, | 435 | .probe = pas_probe, |
405 | .setup_arch = pas_setup_arch, | 436 | .setup_arch = pas_setup_arch, |
406 | .init_early = pas_init_early, | 437 | .init_early = pas_init_early, |
diff --git a/arch/powerpc/platforms/powermac/low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c index da2007e3db0e..21226b74c9b2 100644 --- a/arch/powerpc/platforms/powermac/low_i2c.c +++ b/arch/powerpc/platforms/powermac/low_i2c.c | |||
@@ -585,8 +585,7 @@ static void __init kw_i2c_probe(void) | |||
585 | struct device_node *np, *child, *parent; | 585 | struct device_node *np, *child, *parent; |
586 | 586 | ||
587 | /* Probe keywest-i2c busses */ | 587 | /* Probe keywest-i2c busses */ |
588 | for (np = NULL; | 588 | for_each_compatible_node(np, "i2c","keywest-i2c") { |
589 | (np = of_find_compatible_node(np, "i2c","keywest-i2c")) != NULL;){ | ||
590 | struct pmac_i2c_host_kw *host; | 589 | struct pmac_i2c_host_kw *host; |
591 | int multibus, chans, i; | 590 | int multibus, chans, i; |
592 | 591 | ||
@@ -1462,9 +1461,6 @@ int __init pmac_i2c_init(void) | |||
1462 | return 0; | 1461 | return 0; |
1463 | i2c_inited = 1; | 1462 | i2c_inited = 1; |
1464 | 1463 | ||
1465 | if (!machine_is(powermac)) | ||
1466 | return 0; | ||
1467 | |||
1468 | /* Probe keywest-i2c busses */ | 1464 | /* Probe keywest-i2c busses */ |
1469 | kw_i2c_probe(); | 1465 | kw_i2c_probe(); |
1470 | 1466 | ||
@@ -1483,7 +1479,7 @@ int __init pmac_i2c_init(void) | |||
1483 | 1479 | ||
1484 | return 0; | 1480 | return 0; |
1485 | } | 1481 | } |
1486 | arch_initcall(pmac_i2c_init); | 1482 | machine_arch_initcall(powermac, pmac_i2c_init); |
1487 | 1483 | ||
1488 | /* Since pmac_i2c_init can be called too early for the platform device | 1484 | /* Since pmac_i2c_init can be called too early for the platform device |
1489 | * registration, we need to do it at a later time. In our case, subsys | 1485 | * registration, we need to do it at a later time. In our case, subsys |
@@ -1515,4 +1511,4 @@ static int __init pmac_i2c_create_platform_devices(void) | |||
1515 | 1511 | ||
1516 | return 0; | 1512 | return 0; |
1517 | } | 1513 | } |
1518 | subsys_initcall(pmac_i2c_create_platform_devices); | 1514 | machine_subsys_initcall(powermac, pmac_i2c_create_platform_devices); |
diff --git a/arch/powerpc/platforms/powermac/pci.c b/arch/powerpc/platforms/powermac/pci.c index f852ae3e0ee4..1c58db9d42cb 100644 --- a/arch/powerpc/platforms/powermac/pci.c +++ b/arch/powerpc/platforms/powermac/pci.c | |||
@@ -40,8 +40,6 @@ | |||
40 | static int has_uninorth; | 40 | static int has_uninorth; |
41 | #ifdef CONFIG_PPC64 | 41 | #ifdef CONFIG_PPC64 |
42 | static struct pci_controller *u3_agp; | 42 | static struct pci_controller *u3_agp; |
43 | static struct pci_controller *u4_pcie; | ||
44 | static struct pci_controller *u3_ht; | ||
45 | #else | 43 | #else |
46 | static int has_second_ohare; | 44 | static int has_second_ohare; |
47 | #endif /* CONFIG_PPC64 */ | 45 | #endif /* CONFIG_PPC64 */ |
@@ -314,12 +312,15 @@ static int u3_ht_skip_device(struct pci_controller *hose, | |||
314 | 312 | ||
315 | /* We only allow config cycles to devices that are in OF device-tree | 313 | /* We only allow config cycles to devices that are in OF device-tree |
316 | * as we are apparently having some weird things going on with some | 314 | * as we are apparently having some weird things going on with some |
317 | * revs of K2 on recent G5s | 315 | * revs of K2 on recent G5s, except for the host bridge itself, which |
316 | * is missing from the tree but we know we can probe. | ||
318 | */ | 317 | */ |
319 | if (bus->self) | 318 | if (bus->self) |
320 | busdn = pci_device_to_OF_node(bus->self); | 319 | busdn = pci_device_to_OF_node(bus->self); |
320 | else if (devfn == 0) | ||
321 | return 0; | ||
321 | else | 322 | else |
322 | busdn = hose->arch_data; | 323 | busdn = hose->dn; |
323 | for (dn = busdn->child; dn; dn = dn->sibling) | 324 | for (dn = busdn->child; dn; dn = dn->sibling) |
324 | if (PCI_DN(dn) && PCI_DN(dn)->devfn == devfn) | 325 | if (PCI_DN(dn) && PCI_DN(dn)->devfn == devfn) |
325 | break; | 326 | break; |
@@ -344,14 +345,15 @@ static int u3_ht_skip_device(struct pci_controller *hose, | |||
344 | + (((unsigned int)bus) << 16) \ | 345 | + (((unsigned int)bus) << 16) \ |
345 | + 0x01000000UL) | 346 | + 0x01000000UL) |
346 | 347 | ||
347 | static volatile void __iomem *u3_ht_cfg_access(struct pci_controller* hose, | 348 | static void __iomem *u3_ht_cfg_access(struct pci_controller *hose, u8 bus, |
348 | u8 bus, u8 devfn, u8 offset) | 349 | u8 devfn, u8 offset, int *swap) |
349 | { | 350 | { |
351 | *swap = 1; | ||
350 | if (bus == hose->first_busno) { | 352 | if (bus == hose->first_busno) { |
351 | /* For now, we don't self probe U3 HT bridge */ | 353 | if (devfn != 0) |
352 | if (PCI_SLOT(devfn) == 0) | 354 | return hose->cfg_data + U3_HT_CFA0(devfn, offset); |
353 | return NULL; | 355 | *swap = 0; |
354 | return hose->cfg_data + U3_HT_CFA0(devfn, offset); | 356 | return ((void __iomem *)hose->cfg_addr) + (offset << 2); |
355 | } else | 357 | } else |
356 | return hose->cfg_data + U3_HT_CFA1(bus, devfn, offset); | 358 | return hose->cfg_data + U3_HT_CFA1(bus, devfn, offset); |
357 | } | 359 | } |
@@ -360,14 +362,15 @@ static int u3_ht_read_config(struct pci_bus *bus, unsigned int devfn, | |||
360 | int offset, int len, u32 *val) | 362 | int offset, int len, u32 *val) |
361 | { | 363 | { |
362 | struct pci_controller *hose; | 364 | struct pci_controller *hose; |
363 | volatile void __iomem *addr; | 365 | void __iomem *addr; |
366 | int swap; | ||
364 | 367 | ||
365 | hose = pci_bus_to_host(bus); | 368 | hose = pci_bus_to_host(bus); |
366 | if (hose == NULL) | 369 | if (hose == NULL) |
367 | return PCIBIOS_DEVICE_NOT_FOUND; | 370 | return PCIBIOS_DEVICE_NOT_FOUND; |
368 | if (offset >= 0x100) | 371 | if (offset >= 0x100) |
369 | return PCIBIOS_BAD_REGISTER_NUMBER; | 372 | return PCIBIOS_BAD_REGISTER_NUMBER; |
370 | addr = u3_ht_cfg_access(hose, bus->number, devfn, offset); | 373 | addr = u3_ht_cfg_access(hose, bus->number, devfn, offset, &swap); |
371 | if (!addr) | 374 | if (!addr) |
372 | return PCIBIOS_DEVICE_NOT_FOUND; | 375 | return PCIBIOS_DEVICE_NOT_FOUND; |
373 | 376 | ||
@@ -397,10 +400,10 @@ static int u3_ht_read_config(struct pci_bus *bus, unsigned int devfn, | |||
397 | *val = in_8(addr); | 400 | *val = in_8(addr); |
398 | break; | 401 | break; |
399 | case 2: | 402 | case 2: |
400 | *val = in_le16(addr); | 403 | *val = swap ? in_le16(addr) : in_be16(addr); |
401 | break; | 404 | break; |
402 | default: | 405 | default: |
403 | *val = in_le32(addr); | 406 | *val = swap ? in_le32(addr) : in_be32(addr); |
404 | break; | 407 | break; |
405 | } | 408 | } |
406 | return PCIBIOS_SUCCESSFUL; | 409 | return PCIBIOS_SUCCESSFUL; |
@@ -410,14 +413,15 @@ static int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn, | |||
410 | int offset, int len, u32 val) | 413 | int offset, int len, u32 val) |
411 | { | 414 | { |
412 | struct pci_controller *hose; | 415 | struct pci_controller *hose; |
413 | volatile void __iomem *addr; | 416 | void __iomem *addr; |
417 | int swap; | ||
414 | 418 | ||
415 | hose = pci_bus_to_host(bus); | 419 | hose = pci_bus_to_host(bus); |
416 | if (hose == NULL) | 420 | if (hose == NULL) |
417 | return PCIBIOS_DEVICE_NOT_FOUND; | 421 | return PCIBIOS_DEVICE_NOT_FOUND; |
418 | if (offset >= 0x100) | 422 | if (offset >= 0x100) |
419 | return PCIBIOS_BAD_REGISTER_NUMBER; | 423 | return PCIBIOS_BAD_REGISTER_NUMBER; |
420 | addr = u3_ht_cfg_access(hose, bus->number, devfn, offset); | 424 | addr = u3_ht_cfg_access(hose, bus->number, devfn, offset, &swap); |
421 | if (!addr) | 425 | if (!addr) |
422 | return PCIBIOS_DEVICE_NOT_FOUND; | 426 | return PCIBIOS_DEVICE_NOT_FOUND; |
423 | 427 | ||
@@ -439,10 +443,10 @@ static int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn, | |||
439 | out_8(addr, val); | 443 | out_8(addr, val); |
440 | break; | 444 | break; |
441 | case 2: | 445 | case 2: |
442 | out_le16(addr, val); | 446 | swap ? out_le16(addr, val) : out_be16(addr, val); |
443 | break; | 447 | break; |
444 | default: | 448 | default: |
445 | out_le32((u32 __iomem *)addr, val); | 449 | swap ? out_le32(addr, val) : out_be32(addr, val); |
446 | break; | 450 | break; |
447 | } | 451 | } |
448 | return PCIBIOS_SUCCESSFUL; | 452 | return PCIBIOS_SUCCESSFUL; |
@@ -725,7 +729,7 @@ static void __init setup_bandit(struct pci_controller *hose, | |||
725 | static int __init setup_uninorth(struct pci_controller *hose, | 729 | static int __init setup_uninorth(struct pci_controller *hose, |
726 | struct resource *addr) | 730 | struct resource *addr) |
727 | { | 731 | { |
728 | pci_assign_all_buses = 1; | 732 | ppc_pci_flags |= PPC_PCI_REASSIGN_ALL_BUS; |
729 | has_uninorth = 1; | 733 | has_uninorth = 1; |
730 | hose->ops = ¯isc_pci_ops; | 734 | hose->ops = ¯isc_pci_ops; |
731 | hose->cfg_addr = ioremap(addr->start + 0x800000, 0x1000); | 735 | hose->cfg_addr = ioremap(addr->start + 0x800000, 0x1000); |
@@ -773,31 +777,72 @@ static void __init setup_u4_pcie(struct pci_controller* hose) | |||
773 | */ | 777 | */ |
774 | hose->first_busno = 0x00; | 778 | hose->first_busno = 0x00; |
775 | hose->last_busno = 0xff; | 779 | hose->last_busno = 0xff; |
776 | u4_pcie = hose; | ||
777 | } | 780 | } |
778 | 781 | ||
779 | static void __init setup_u3_ht(struct pci_controller* hose) | 782 | static void __init parse_region_decode(struct pci_controller *hose, |
783 | u32 decode) | ||
780 | { | 784 | { |
781 | struct device_node *np = (struct device_node *)hose->arch_data; | 785 | unsigned long base, end, next = -1; |
782 | struct pci_controller *other = NULL; | 786 | int i, cur = -1; |
783 | int i, cur; | ||
784 | 787 | ||
788 | /* Iterate through all bits. We ignore the last bit as this region is | ||
789 | * reserved for the ROM among other niceties | ||
790 | */ | ||
791 | for (i = 0; i < 31; i++) { | ||
792 | if ((decode & (0x80000000 >> i)) == 0) | ||
793 | continue; | ||
794 | if (i < 16) { | ||
795 | base = 0xf0000000 | (((u32)i) << 24); | ||
796 | end = base + 0x00ffffff; | ||
797 | } else { | ||
798 | base = ((u32)i-16) << 28; | ||
799 | end = base + 0x0fffffff; | ||
800 | } | ||
801 | if (base != next) { | ||
802 | if (++cur >= 3) { | ||
803 | printk(KERN_WARNING "PCI: Too many ranges !\n"); | ||
804 | break; | ||
805 | } | ||
806 | hose->mem_resources[cur].flags = IORESOURCE_MEM; | ||
807 | hose->mem_resources[cur].name = hose->dn->full_name; | ||
808 | hose->mem_resources[cur].start = base; | ||
809 | hose->mem_resources[cur].end = end; | ||
810 | DBG(" %d: 0x%08lx-0x%08lx\n", cur, base, end); | ||
811 | } else { | ||
812 | DBG(" : -0x%08lx\n", end); | ||
813 | hose->mem_resources[cur].end = end; | ||
814 | } | ||
815 | next = end + 1; | ||
816 | } | ||
817 | } | ||
818 | |||
819 | static void __init setup_u3_ht(struct pci_controller* hose) | ||
820 | { | ||
821 | struct device_node *np = hose->dn; | ||
822 | struct resource cfg_res, self_res; | ||
823 | u32 decode; | ||
785 | 824 | ||
786 | hose->ops = &u3_ht_pci_ops; | 825 | hose->ops = &u3_ht_pci_ops; |
787 | 826 | ||
788 | /* We hard code the address because of the different size of | 827 | /* Get base addresses from OF tree |
789 | * the reg address cell, we shall fix that by killing struct | ||
790 | * reg_property and using some accessor functions instead | ||
791 | */ | 828 | */ |
792 | hose->cfg_data = ioremap(0xf2000000, 0x02000000); | 829 | if (of_address_to_resource(np, 0, &cfg_res) || |
830 | of_address_to_resource(np, 1, &self_res)) { | ||
831 | printk(KERN_ERR "PCI: Failed to get U3/U4 HT resources !\n"); | ||
832 | return; | ||
833 | } | ||
834 | |||
835 | /* Map external cfg space access into cfg_data and self registers | ||
836 | * into cfg_addr | ||
837 | */ | ||
838 | hose->cfg_data = ioremap(cfg_res.start, 0x02000000); | ||
839 | hose->cfg_addr = ioremap(self_res.start, | ||
840 | self_res.end - self_res.start + 1); | ||
793 | 841 | ||
794 | /* | 842 | /* |
795 | * /ht node doesn't expose a "ranges" property, so we "remove" | 843 | * /ht node doesn't expose a "ranges" property, we read the register |
796 | * regions that have been allocated to AGP. So far, this version of | 844 | * that controls the decoding logic and use that for memory regions. |
797 | * the code doesn't assign any of the 0xfxxxxxxx "fine" memory regions | 845 | * The IO region is hard coded since it is fixed in HW as well. |
798 | * to /ht. We need to fix that sooner or later by either parsing all | ||
799 | * child "ranges" properties or figuring out the U3 address space | ||
800 | * decoding logic and then read its configuration register (if any). | ||
801 | */ | 846 | */ |
802 | hose->io_base_phys = 0xf4000000; | 847 | hose->io_base_phys = 0xf4000000; |
803 | hose->pci_io_size = 0x00400000; | 848 | hose->pci_io_size = 0x00400000; |
@@ -808,76 +853,33 @@ static void __init setup_u3_ht(struct pci_controller* hose) | |||
808 | hose->pci_mem_offset = 0; | 853 | hose->pci_mem_offset = 0; |
809 | hose->first_busno = 0; | 854 | hose->first_busno = 0; |
810 | hose->last_busno = 0xef; | 855 | hose->last_busno = 0xef; |
811 | hose->mem_resources[0].name = np->full_name; | ||
812 | hose->mem_resources[0].start = 0x80000000; | ||
813 | hose->mem_resources[0].end = 0xefffffff; | ||
814 | hose->mem_resources[0].flags = IORESOURCE_MEM; | ||
815 | |||
816 | u3_ht = hose; | ||
817 | 856 | ||
818 | if (u3_agp != NULL) | 857 | /* Note: fix offset when cfg_addr becomes a void * */ |
819 | other = u3_agp; | 858 | decode = in_be32(hose->cfg_addr + 0x80); |
820 | else if (u4_pcie != NULL) | ||
821 | other = u4_pcie; | ||
822 | |||
823 | if (other == NULL) { | ||
824 | DBG("U3/4 has no AGP/PCIE, using full resource range\n"); | ||
825 | return; | ||
826 | } | ||
827 | 859 | ||
828 | /* Fixup bus range vs. PCIE */ | 860 | DBG("PCI: Apple HT bridge decode register: 0x%08x\n", decode); |
829 | if (u4_pcie) | ||
830 | hose->last_busno = u4_pcie->first_busno - 1; | ||
831 | 861 | ||
832 | /* We "remove" the AGP resources from the resources allocated to HT, | 862 | /* NOTE: The decode register setup is a bit weird... region |
833 | * that is we create "holes". However, that code does assumptions | 863 | * 0xf8000000 for example is marked as enabled in there while it's |
834 | * that so far happen to be true (cross fingers...), typically that | 864 | & actually the memory controller registers. |
835 | * resources in the AGP node are properly ordered | 865 | * That means that we are incorrectly attributing it to HT. |
866 | * | ||
867 | * In a similar vein, region 0xf4000000 is actually the HT IO space but | ||
868 | * also marked as enabled in here and 0xf9000000 is used by some other | ||
869 | * internal bits of the northbridge. | ||
870 | * | ||
871 | * Unfortunately, we can't just mask out those bit as we would end | ||
872 | * up with more regions than we can cope (linux can only cope with | ||
873 | * 3 memory regions for a PHB at this stage). | ||
874 | * | ||
875 | * So for now, we just do a little hack. We happen to -know- that | ||
876 | * Apple firmware doesn't assign things below 0xfa000000 for that | ||
877 | * bridge anyway so we mask out all bits we don't want. | ||
836 | */ | 878 | */ |
837 | cur = 0; | 879 | decode &= 0x003fffff; |
838 | for (i=0; i<3; i++) { | 880 | |
839 | struct resource *res = &other->mem_resources[i]; | 881 | /* Now parse the resulting bits and build resources */ |
840 | if (res->flags != IORESOURCE_MEM) | 882 | parse_region_decode(hose, decode); |
841 | continue; | ||
842 | /* We don't care about "fine" resources */ | ||
843 | if (res->start >= 0xf0000000) | ||
844 | continue; | ||
845 | /* Check if it's just a matter of "shrinking" us in one | ||
846 | * direction | ||
847 | */ | ||
848 | if (hose->mem_resources[cur].start == res->start) { | ||
849 | DBG("U3/HT: shrink start of %d, %08lx -> %08lx\n", | ||
850 | cur, hose->mem_resources[cur].start, | ||
851 | res->end + 1); | ||
852 | hose->mem_resources[cur].start = res->end + 1; | ||
853 | continue; | ||
854 | } | ||
855 | if (hose->mem_resources[cur].end == res->end) { | ||
856 | DBG("U3/HT: shrink end of %d, %08lx -> %08lx\n", | ||
857 | cur, hose->mem_resources[cur].end, | ||
858 | res->start - 1); | ||
859 | hose->mem_resources[cur].end = res->start - 1; | ||
860 | continue; | ||
861 | } | ||
862 | /* No, it's not the case, we need a hole */ | ||
863 | if (cur == 2) { | ||
864 | /* not enough resources for a hole, we drop part | ||
865 | * of the range | ||
866 | */ | ||
867 | printk(KERN_WARNING "Running out of resources" | ||
868 | " for /ht host !\n"); | ||
869 | hose->mem_resources[cur].end = res->start - 1; | ||
870 | continue; | ||
871 | } | ||
872 | cur++; | ||
873 | DBG("U3/HT: hole, %d end at %08lx, %d start at %08lx\n", | ||
874 | cur-1, res->start - 1, cur, res->end + 1); | ||
875 | hose->mem_resources[cur].name = np->full_name; | ||
876 | hose->mem_resources[cur].flags = IORESOURCE_MEM; | ||
877 | hose->mem_resources[cur].start = res->end + 1; | ||
878 | hose->mem_resources[cur].end = hose->mem_resources[cur-1].end; | ||
879 | hose->mem_resources[cur-1].end = res->start - 1; | ||
880 | } | ||
881 | } | 883 | } |
882 | #endif /* CONFIG_PPC64 */ | 884 | #endif /* CONFIG_PPC64 */ |
883 | 885 | ||
@@ -994,6 +996,8 @@ void __init pmac_pci_init(void) | |||
994 | struct device_node *np, *root; | 996 | struct device_node *np, *root; |
995 | struct device_node *ht = NULL; | 997 | struct device_node *ht = NULL; |
996 | 998 | ||
999 | ppc_pci_flags = PPC_PCI_CAN_SKIP_ISA_ALIGN; | ||
1000 | |||
997 | root = of_find_node_by_path("/"); | 1001 | root = of_find_node_by_path("/"); |
998 | if (root == NULL) { | 1002 | if (root == NULL) { |
999 | printk(KERN_CRIT "pmac_pci_init: can't find root " | 1003 | printk(KERN_CRIT "pmac_pci_init: can't find root " |
@@ -1032,15 +1036,15 @@ void __init pmac_pci_init(void) | |||
1032 | * future though | 1036 | * future though |
1033 | */ | 1037 | */ |
1034 | if (u3_agp) { | 1038 | if (u3_agp) { |
1035 | struct device_node *np = u3_agp->arch_data; | 1039 | struct device_node *np = u3_agp->dn; |
1036 | PCI_DN(np)->busno = 0xf0; | 1040 | PCI_DN(np)->busno = 0xf0; |
1037 | for (np = np->child; np; np = np->sibling) | 1041 | for (np = np->child; np; np = np->sibling) |
1038 | PCI_DN(np)->busno = 0xf0; | 1042 | PCI_DN(np)->busno = 0xf0; |
1039 | } | 1043 | } |
1040 | /* pmac_check_ht_link(); */ | 1044 | /* pmac_check_ht_link(); */ |
1041 | 1045 | ||
1042 | /* Tell pci.c to not use the common resource allocation mechanism */ | 1046 | /* We can allocate missing resources if any */ |
1043 | pci_probe_only = 1; | 1047 | pci_probe_only = 0; |
1044 | 1048 | ||
1045 | #else /* CONFIG_PPC64 */ | 1049 | #else /* CONFIG_PPC64 */ |
1046 | init_p2pbridge(); | 1050 | init_p2pbridge(); |
@@ -1051,13 +1055,13 @@ void __init pmac_pci_init(void) | |||
1051 | * some offset between bus number and domains for now when we | 1055 | * some offset between bus number and domains for now when we |
1052 | * assign all busses should help for now | 1056 | * assign all busses should help for now |
1053 | */ | 1057 | */ |
1054 | if (pci_assign_all_buses) | 1058 | if (ppc_pci_flags & PPC_PCI_REASSIGN_ALL_BUS) |
1055 | pcibios_assign_bus_offset = 0x10; | 1059 | pcibios_assign_bus_offset = 0x10; |
1056 | #endif | 1060 | #endif |
1057 | } | 1061 | } |
1058 | 1062 | ||
1059 | int | 1063 | #ifdef CONFIG_PPC32 |
1060 | pmac_pci_enable_device_hook(struct pci_dev *dev, int initial) | 1064 | int pmac_pci_enable_device_hook(struct pci_dev *dev) |
1061 | { | 1065 | { |
1062 | struct device_node* node; | 1066 | struct device_node* node; |
1063 | int updatecfg = 0; | 1067 | int updatecfg = 0; |
@@ -1099,24 +1103,21 @@ pmac_pci_enable_device_hook(struct pci_dev *dev, int initial) | |||
1099 | updatecfg = 1; | 1103 | updatecfg = 1; |
1100 | } | 1104 | } |
1101 | 1105 | ||
1106 | /* | ||
1107 | * Fixup various header fields on 32 bits. We don't do that on | ||
1108 | * 64 bits as some of these have strange values behind the HT | ||
1109 | * bridge and we must not, for example, enable MWI or set the | ||
1110 | * cache line size on them. | ||
1111 | */ | ||
1102 | if (updatecfg) { | 1112 | if (updatecfg) { |
1103 | u16 cmd; | 1113 | u16 cmd; |
1104 | 1114 | ||
1105 | /* | ||
1106 | * Make sure PCI is correctly configured | ||
1107 | * | ||
1108 | * We use old pci_bios versions of the function since, by | ||
1109 | * default, gmac is not powered up, and so will be absent | ||
1110 | * from the kernel initial PCI lookup. | ||
1111 | * | ||
1112 | * Should be replaced by 2.4 new PCI mechanisms and really | ||
1113 | * register the device. | ||
1114 | */ | ||
1115 | pci_read_config_word(dev, PCI_COMMAND, &cmd); | 1115 | pci_read_config_word(dev, PCI_COMMAND, &cmd); |
1116 | cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | 1116 | cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
1117 | | PCI_COMMAND_INVALIDATE; | 1117 | | PCI_COMMAND_INVALIDATE; |
1118 | pci_write_config_word(dev, PCI_COMMAND, cmd); | 1118 | pci_write_config_word(dev, PCI_COMMAND, cmd); |
1119 | pci_write_config_byte(dev, PCI_LATENCY_TIMER, 16); | 1119 | pci_write_config_byte(dev, PCI_LATENCY_TIMER, 16); |
1120 | |||
1120 | pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, | 1121 | pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, |
1121 | L1_CACHE_BYTES >> 2); | 1122 | L1_CACHE_BYTES >> 2); |
1122 | } | 1123 | } |
@@ -1124,6 +1125,18 @@ pmac_pci_enable_device_hook(struct pci_dev *dev, int initial) | |||
1124 | return 0; | 1125 | return 0; |
1125 | } | 1126 | } |
1126 | 1127 | ||
1128 | void __devinit pmac_pci_fixup_ohci(struct pci_dev *dev) | ||
1129 | { | ||
1130 | struct device_node *node = pci_device_to_OF_node(dev); | ||
1131 | |||
1132 | /* We don't want to assign resources to USB controllers | ||
1133 | * absent from the OF tree (iBook second controller) | ||
1134 | */ | ||
1135 | if (dev->class == PCI_CLASS_SERIAL_USB_OHCI && !node) | ||
1136 | dev->resource[0].flags = 0; | ||
1137 | } | ||
1138 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_APPLE, PCI_ANY_ID, pmac_pci_fixup_ohci); | ||
1139 | |||
1127 | /* We power down some devices after they have been probed. They'll | 1140 | /* We power down some devices after they have been probed. They'll |
1128 | * be powered back on later on | 1141 | * be powered back on later on |
1129 | */ | 1142 | */ |
@@ -1171,7 +1184,6 @@ void __init pmac_pcibios_after_init(void) | |||
1171 | of_node_put(nd); | 1184 | of_node_put(nd); |
1172 | } | 1185 | } |
1173 | 1186 | ||
1174 | #ifdef CONFIG_PPC32 | ||
1175 | void pmac_pci_fixup_cardbus(struct pci_dev* dev) | 1187 | void pmac_pci_fixup_cardbus(struct pci_dev* dev) |
1176 | { | 1188 | { |
1177 | if (!machine_is(powermac)) | 1189 | if (!machine_is(powermac)) |
@@ -1259,7 +1271,7 @@ void pmac_pci_fixup_pciata(struct pci_dev* dev) | |||
1259 | } | 1271 | } |
1260 | } | 1272 | } |
1261 | DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, pmac_pci_fixup_pciata); | 1273 | DECLARE_PCI_FIXUP_EARLY(PCI_ANY_ID, PCI_ANY_ID, pmac_pci_fixup_pciata); |
1262 | #endif | 1274 | #endif /* CONFIG_PPC32 */ |
1263 | 1275 | ||
1264 | /* | 1276 | /* |
1265 | * Disable second function on K2-SATA, it's broken | 1277 | * Disable second function on K2-SATA, it's broken |
diff --git a/arch/powerpc/platforms/powermac/pfunc_base.c b/arch/powerpc/platforms/powermac/pfunc_base.c index 45d54b9ad9e0..db20de512f3e 100644 --- a/arch/powerpc/platforms/powermac/pfunc_base.c +++ b/arch/powerpc/platforms/powermac/pfunc_base.c | |||
@@ -363,8 +363,7 @@ int __init pmac_pfunc_base_install(void) | |||
363 | 363 | ||
364 | return 0; | 364 | return 0; |
365 | } | 365 | } |
366 | 366 | machine_arch_initcall(powermac, pmac_pfunc_base_install); | |
367 | arch_initcall(pmac_pfunc_base_install); | ||
368 | 367 | ||
369 | #ifdef CONFIG_PM | 368 | #ifdef CONFIG_PM |
370 | 369 | ||
diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c index 84c0d4ef76a2..40736400ef80 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c | |||
@@ -690,6 +690,5 @@ static int __init init_pmacpic_sysfs(void) | |||
690 | sysdev_driver_register(&pmacpic_sysclass, &driver_pmacpic); | 690 | sysdev_driver_register(&pmacpic_sysclass, &driver_pmacpic); |
691 | return 0; | 691 | return 0; |
692 | } | 692 | } |
693 | 693 | machine_subsys_initcall(powermac, init_pmacpic_sysfs); | |
694 | subsys_initcall(init_pmacpic_sysfs); | ||
695 | 694 | ||
diff --git a/arch/powerpc/platforms/powermac/pmac.h b/arch/powerpc/platforms/powermac/pmac.h index fcde070f7054..b3abaaf61eb4 100644 --- a/arch/powerpc/platforms/powermac/pmac.h +++ b/arch/powerpc/platforms/powermac/pmac.h | |||
@@ -26,7 +26,7 @@ extern void pmac_pci_init(void); | |||
26 | extern void pmac_nvram_update(void); | 26 | extern void pmac_nvram_update(void); |
27 | extern unsigned char pmac_nvram_read_byte(int addr); | 27 | extern unsigned char pmac_nvram_read_byte(int addr); |
28 | extern void pmac_nvram_write_byte(int addr, unsigned char val); | 28 | extern void pmac_nvram_write_byte(int addr, unsigned char val); |
29 | extern int pmac_pci_enable_device_hook(struct pci_dev *dev, int initial); | 29 | extern int pmac_pci_enable_device_hook(struct pci_dev *dev); |
30 | extern void pmac_pcibios_after_init(void); | 30 | extern void pmac_pcibios_after_init(void); |
31 | extern int of_show_percpuinfo(struct seq_file *m, int i); | 31 | extern int of_show_percpuinfo(struct seq_file *m, int i); |
32 | 32 | ||
diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index 02c533096627..36ff1b6b7fac 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c | |||
@@ -51,6 +51,8 @@ | |||
51 | #include <linux/root_dev.h> | 51 | #include <linux/root_dev.h> |
52 | #include <linux/bitops.h> | 52 | #include <linux/bitops.h> |
53 | #include <linux/suspend.h> | 53 | #include <linux/suspend.h> |
54 | #include <linux/of_device.h> | ||
55 | #include <linux/of_platform.h> | ||
54 | 56 | ||
55 | #include <asm/reg.h> | 57 | #include <asm/reg.h> |
56 | #include <asm/sections.h> | 58 | #include <asm/sections.h> |
@@ -68,8 +70,6 @@ | |||
68 | #include <asm/btext.h> | 70 | #include <asm/btext.h> |
69 | #include <asm/pmac_feature.h> | 71 | #include <asm/pmac_feature.h> |
70 | #include <asm/time.h> | 72 | #include <asm/time.h> |
71 | #include <asm/of_device.h> | ||
72 | #include <asm/of_platform.h> | ||
73 | #include <asm/mmu_context.h> | 73 | #include <asm/mmu_context.h> |
74 | #include <asm/iommu.h> | 74 | #include <asm/iommu.h> |
75 | #include <asm/smu.h> | 75 | #include <asm/smu.h> |
@@ -94,7 +94,6 @@ extern struct machdep_calls pmac_md; | |||
94 | #define DEFAULT_ROOT_DEVICE Root_SDA1 /* sda1 - slightly silly choice */ | 94 | #define DEFAULT_ROOT_DEVICE Root_SDA1 /* sda1 - slightly silly choice */ |
95 | 95 | ||
96 | #ifdef CONFIG_PPC64 | 96 | #ifdef CONFIG_PPC64 |
97 | #include <asm/udbg.h> | ||
98 | int sccdbg; | 97 | int sccdbg; |
99 | #endif | 98 | #endif |
100 | 99 | ||
@@ -398,17 +397,13 @@ static int initializing = 1; | |||
398 | 397 | ||
399 | static int pmac_late_init(void) | 398 | static int pmac_late_init(void) |
400 | { | 399 | { |
401 | if (!machine_is(powermac)) | ||
402 | return -ENODEV; | ||
403 | |||
404 | initializing = 0; | 400 | initializing = 0; |
405 | /* this is udbg (which is __init) and we can later use it during | 401 | /* this is udbg (which is __init) and we can later use it during |
406 | * cpu hotplug (in smp_core99_kick_cpu) */ | 402 | * cpu hotplug (in smp_core99_kick_cpu) */ |
407 | ppc_md.progress = NULL; | 403 | ppc_md.progress = NULL; |
408 | return 0; | 404 | return 0; |
409 | } | 405 | } |
410 | 406 | machine_late_initcall(powermac, pmac_late_init); | |
411 | late_initcall(pmac_late_init); | ||
412 | 407 | ||
413 | /* | 408 | /* |
414 | * This is __init_refok because we check for "initializing" before | 409 | * This is __init_refok because we check for "initializing" before |
@@ -535,9 +530,6 @@ static int __init pmac_declare_of_platform_devices(void) | |||
535 | if (machine_is(chrp)) | 530 | if (machine_is(chrp)) |
536 | return -1; | 531 | return -1; |
537 | 532 | ||
538 | if (!machine_is(powermac)) | ||
539 | return 0; | ||
540 | |||
541 | np = of_find_node_by_name(NULL, "valkyrie"); | 533 | np = of_find_node_by_name(NULL, "valkyrie"); |
542 | if (np) | 534 | if (np) |
543 | of_platform_device_create(np, "valkyrie", NULL); | 535 | of_platform_device_create(np, "valkyrie", NULL); |
@@ -552,8 +544,7 @@ static int __init pmac_declare_of_platform_devices(void) | |||
552 | 544 | ||
553 | return 0; | 545 | return 0; |
554 | } | 546 | } |
555 | 547 | machine_device_initcall(powermac, pmac_declare_of_platform_devices); | |
556 | device_initcall(pmac_declare_of_platform_devices); | ||
557 | 548 | ||
558 | /* | 549 | /* |
559 | * Called very early, MMU is off, device-tree isn't unflattened | 550 | * Called very early, MMU is off, device-tree isn't unflattened |
@@ -613,9 +604,11 @@ static int pmac_pci_probe_mode(struct pci_bus *bus) | |||
613 | 604 | ||
614 | /* We need to use normal PCI probing for the AGP bus, | 605 | /* We need to use normal PCI probing for the AGP bus, |
615 | * since the device for the AGP bridge isn't in the tree. | 606 | * since the device for the AGP bridge isn't in the tree. |
607 | * Same for the PCIe host on U4 and the HT host bridge. | ||
616 | */ | 608 | */ |
617 | if (bus->self == NULL && (of_device_is_compatible(node, "u3-agp") || | 609 | if (bus->self == NULL && (of_device_is_compatible(node, "u3-agp") || |
618 | of_device_is_compatible(node, "u4-pcie"))) | 610 | of_device_is_compatible(node, "u4-pcie") || |
611 | of_device_is_compatible(node, "u3-ht"))) | ||
619 | return PCI_PROBE_NORMAL; | 612 | return PCI_PROBE_NORMAL; |
620 | return PCI_PROBE_DEVTREE; | 613 | return PCI_PROBE_DEVTREE; |
621 | } | 614 | } |
diff --git a/arch/powerpc/platforms/powermac/time.c b/arch/powerpc/platforms/powermac/time.c index bf9da56942e8..bbbefd64ab59 100644 --- a/arch/powerpc/platforms/powermac/time.c +++ b/arch/powerpc/platforms/powermac/time.c | |||
@@ -84,12 +84,14 @@ long __init pmac_time_init(void) | |||
84 | return delta; | 84 | return delta; |
85 | } | 85 | } |
86 | 86 | ||
87 | #if defined(CONFIG_ADB_CUDA) || defined(CONFIG_ADB_PMU) | ||
87 | static void to_rtc_time(unsigned long now, struct rtc_time *tm) | 88 | static void to_rtc_time(unsigned long now, struct rtc_time *tm) |
88 | { | 89 | { |
89 | to_tm(now, tm); | 90 | to_tm(now, tm); |
90 | tm->tm_year -= 1900; | 91 | tm->tm_year -= 1900; |
91 | tm->tm_mon -= 1; | 92 | tm->tm_mon -= 1; |
92 | } | 93 | } |
94 | #endif | ||
93 | 95 | ||
94 | static unsigned long from_rtc_time(struct rtc_time *tm) | 96 | static unsigned long from_rtc_time(struct rtc_time *tm) |
95 | { | 97 | { |
diff --git a/arch/powerpc/platforms/ps3/Kconfig b/arch/powerpc/platforms/ps3/Kconfig index 298f1c9679fb..a5f4e95dfc3d 100644 --- a/arch/powerpc/platforms/ps3/Kconfig +++ b/arch/powerpc/platforms/ps3/Kconfig | |||
@@ -61,17 +61,6 @@ config PS3_DYNAMIC_DMA | |||
61 | This support is mainly for Linux kernel development. If unsure, | 61 | This support is mainly for Linux kernel development. If unsure, |
62 | say N. | 62 | say N. |
63 | 63 | ||
64 | config PS3_USE_LPAR_ADDR | ||
65 | depends on PPC_PS3 && EXPERIMENTAL | ||
66 | bool "PS3 use lpar address space" | ||
67 | default y | ||
68 | help | ||
69 | This option is solely for experimentation by experts. Disables | ||
70 | translation of lpar addresses. SPE support currently won't work | ||
71 | without this set to y. | ||
72 | |||
73 | If you have any doubt, choose the default y. | ||
74 | |||
75 | config PS3_VUART | 64 | config PS3_VUART |
76 | depends on PPC_PS3 | 65 | depends on PPC_PS3 |
77 | tristate | 66 | tristate |
@@ -138,4 +127,17 @@ config PS3_FLASH | |||
138 | be disabled on the kernel command line using "ps3flash=off", to | 127 | be disabled on the kernel command line using "ps3flash=off", to |
139 | not allocate this fixed buffer. | 128 | not allocate this fixed buffer. |
140 | 129 | ||
130 | config PS3_LPM | ||
131 | tristate "PS3 Logical Performance Monitor support" | ||
132 | depends on PPC_PS3 | ||
133 | help | ||
134 | Include support for the PS3 Logical Performance Monitor. | ||
135 | |||
136 | This support is required to use the logical performance monitor | ||
137 | of the PS3's LV1 hypervisor. | ||
138 | |||
139 | If you intend to use the advanced performance monitoring and | ||
140 | profiling support of the Cell processor with programs like | ||
141 | oprofile and perfmon2, then say Y or M, otherwise say N. | ||
142 | |||
141 | endmenu | 143 | endmenu |
diff --git a/arch/powerpc/platforms/ps3/device-init.c b/arch/powerpc/platforms/ps3/device-init.c index fd063fe0c9b3..9d251d0ca8c6 100644 --- a/arch/powerpc/platforms/ps3/device-init.c +++ b/arch/powerpc/platforms/ps3/device-init.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/kernel.h> | 23 | #include <linux/kernel.h> |
24 | #include <linux/kthread.h> | 24 | #include <linux/kthread.h> |
25 | #include <linux/init.h> | 25 | #include <linux/init.h> |
26 | #include <linux/reboot.h> | ||
26 | 27 | ||
27 | #include <asm/firmware.h> | 28 | #include <asm/firmware.h> |
28 | #include <asm/lv1call.h> | 29 | #include <asm/lv1call.h> |
@@ -30,6 +31,89 @@ | |||
30 | 31 | ||
31 | #include "platform.h" | 32 | #include "platform.h" |
32 | 33 | ||
34 | static int __init ps3_register_lpm_devices(void) | ||
35 | { | ||
36 | int result; | ||
37 | u64 tmp1; | ||
38 | u64 tmp2; | ||
39 | struct ps3_system_bus_device *dev; | ||
40 | |||
41 | pr_debug(" -> %s:%d\n", __func__, __LINE__); | ||
42 | |||
43 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | ||
44 | if (!dev) | ||
45 | return -ENOMEM; | ||
46 | |||
47 | dev->match_id = PS3_MATCH_ID_LPM; | ||
48 | dev->dev_type = PS3_DEVICE_TYPE_LPM; | ||
49 | |||
50 | /* The current lpm driver only supports a single BE processor. */ | ||
51 | |||
52 | result = ps3_repository_read_be_node_id(0, &dev->lpm.node_id); | ||
53 | |||
54 | if (result) { | ||
55 | pr_debug("%s:%d: ps3_repository_read_be_node_id failed \n", | ||
56 | __func__, __LINE__); | ||
57 | goto fail_read_repo; | ||
58 | } | ||
59 | |||
60 | result = ps3_repository_read_lpm_privileges(dev->lpm.node_id, &tmp1, | ||
61 | &dev->lpm.rights); | ||
62 | |||
63 | if (result) { | ||
64 | pr_debug("%s:%d: ps3_repository_read_lpm_privleges failed \n", | ||
65 | __func__, __LINE__); | ||
66 | goto fail_read_repo; | ||
67 | } | ||
68 | |||
69 | lv1_get_logical_partition_id(&tmp2); | ||
70 | |||
71 | if (tmp1 != tmp2) { | ||
72 | pr_debug("%s:%d: wrong lpar\n", | ||
73 | __func__, __LINE__); | ||
74 | result = -ENODEV; | ||
75 | goto fail_rights; | ||
76 | } | ||
77 | |||
78 | if (!(dev->lpm.rights & PS3_LPM_RIGHTS_USE_LPM)) { | ||
79 | pr_debug("%s:%d: don't have rights to use lpm\n", | ||
80 | __func__, __LINE__); | ||
81 | result = -EPERM; | ||
82 | goto fail_rights; | ||
83 | } | ||
84 | |||
85 | pr_debug("%s:%d: pu_id %lu, rights %lu(%lxh)\n", | ||
86 | __func__, __LINE__, dev->lpm.pu_id, dev->lpm.rights, | ||
87 | dev->lpm.rights); | ||
88 | |||
89 | result = ps3_repository_read_pu_id(0, &dev->lpm.pu_id); | ||
90 | |||
91 | if (result) { | ||
92 | pr_debug("%s:%d: ps3_repository_read_pu_id failed \n", | ||
93 | __func__, __LINE__); | ||
94 | goto fail_read_repo; | ||
95 | } | ||
96 | |||
97 | result = ps3_system_bus_device_register(dev); | ||
98 | |||
99 | if (result) { | ||
100 | pr_debug("%s:%d ps3_system_bus_device_register failed\n", | ||
101 | __func__, __LINE__); | ||
102 | goto fail_register; | ||
103 | } | ||
104 | |||
105 | pr_debug(" <- %s:%d\n", __func__, __LINE__); | ||
106 | return 0; | ||
107 | |||
108 | |||
109 | fail_register: | ||
110 | fail_rights: | ||
111 | fail_read_repo: | ||
112 | kfree(dev); | ||
113 | pr_debug(" <- %s:%d: failed\n", __func__, __LINE__); | ||
114 | return result; | ||
115 | } | ||
116 | |||
33 | /** | 117 | /** |
34 | * ps3_setup_gelic_device - Setup and register a gelic device instance. | 118 | * ps3_setup_gelic_device - Setup and register a gelic device instance. |
35 | * | 119 | * |
@@ -238,166 +322,6 @@ static int __init ps3_setup_vuart_device(enum ps3_match_id match_id, | |||
238 | return result; | 322 | return result; |
239 | } | 323 | } |
240 | 324 | ||
241 | static int ps3stor_wait_for_completion(u64 dev_id, u64 tag, | ||
242 | unsigned int timeout) | ||
243 | { | ||
244 | int result = -1; | ||
245 | unsigned int retries = 0; | ||
246 | u64 status; | ||
247 | |||
248 | for (retries = 0; retries < timeout; retries++) { | ||
249 | result = lv1_storage_check_async_status(dev_id, tag, &status); | ||
250 | if (!result) | ||
251 | break; | ||
252 | |||
253 | msleep(1); | ||
254 | } | ||
255 | |||
256 | if (result) | ||
257 | pr_debug("%s:%u: check_async_status: %s, status %lx\n", | ||
258 | __func__, __LINE__, ps3_result(result), status); | ||
259 | |||
260 | return result; | ||
261 | } | ||
262 | |||
263 | /** | ||
264 | * ps3_storage_wait_for_device - Wait for a storage device to become ready. | ||
265 | * @repo: The repository device to wait for. | ||
266 | * | ||
267 | * Uses the hypervisor's storage device notification mechanism to wait until | ||
268 | * a storage device is ready. The device notification mechanism uses a | ||
269 | * psuedo device (id = -1) to asynchronously notify the guest when storage | ||
270 | * devices become ready. The notification device has a block size of 512 | ||
271 | * bytes. | ||
272 | */ | ||
273 | |||
274 | static int ps3_storage_wait_for_device(const struct ps3_repository_device *repo) | ||
275 | { | ||
276 | int error = -ENODEV; | ||
277 | int result; | ||
278 | const u64 notification_dev_id = (u64)-1LL; | ||
279 | const unsigned int timeout = HZ; | ||
280 | u64 lpar; | ||
281 | u64 tag; | ||
282 | void *buf; | ||
283 | enum ps3_notify_type { | ||
284 | notify_device_ready = 0, | ||
285 | notify_region_probe = 1, | ||
286 | notify_region_update = 2, | ||
287 | }; | ||
288 | struct { | ||
289 | u64 operation_code; /* must be zero */ | ||
290 | u64 event_mask; /* OR of 1UL << enum ps3_notify_type */ | ||
291 | } *notify_cmd; | ||
292 | struct { | ||
293 | u64 event_type; /* enum ps3_notify_type */ | ||
294 | u64 bus_id; | ||
295 | u64 dev_id; | ||
296 | u64 dev_type; | ||
297 | u64 dev_port; | ||
298 | } *notify_event; | ||
299 | |||
300 | pr_debug(" -> %s:%u: (%u:%u:%u)\n", __func__, __LINE__, repo->bus_id, | ||
301 | repo->dev_id, repo->dev_type); | ||
302 | |||
303 | buf = kzalloc(512, GFP_KERNEL); | ||
304 | if (!buf) | ||
305 | return -ENOMEM; | ||
306 | |||
307 | lpar = ps3_mm_phys_to_lpar(__pa(buf)); | ||
308 | notify_cmd = buf; | ||
309 | notify_event = buf; | ||
310 | |||
311 | result = lv1_open_device(repo->bus_id, notification_dev_id, 0); | ||
312 | if (result) { | ||
313 | printk(KERN_ERR "%s:%u: lv1_open_device %s\n", __func__, | ||
314 | __LINE__, ps3_result(result)); | ||
315 | goto fail_free; | ||
316 | } | ||
317 | |||
318 | /* Setup and write the request for device notification. */ | ||
319 | |||
320 | notify_cmd->operation_code = 0; /* must be zero */ | ||
321 | notify_cmd->event_mask = 1UL << notify_region_probe; | ||
322 | |||
323 | result = lv1_storage_write(notification_dev_id, 0, 0, 1, 0, lpar, | ||
324 | &tag); | ||
325 | if (result) { | ||
326 | printk(KERN_ERR "%s:%u: write failed %s\n", __func__, __LINE__, | ||
327 | ps3_result(result)); | ||
328 | goto fail_close; | ||
329 | } | ||
330 | |||
331 | /* Wait for the write completion */ | ||
332 | |||
333 | result = ps3stor_wait_for_completion(notification_dev_id, tag, | ||
334 | timeout); | ||
335 | if (result) { | ||
336 | printk(KERN_ERR "%s:%u: write not completed %s\n", __func__, | ||
337 | __LINE__, ps3_result(result)); | ||
338 | goto fail_close; | ||
339 | } | ||
340 | |||
341 | /* Loop here processing the requested notification events. */ | ||
342 | |||
343 | while (1) { | ||
344 | memset(notify_event, 0, sizeof(*notify_event)); | ||
345 | |||
346 | result = lv1_storage_read(notification_dev_id, 0, 0, 1, 0, | ||
347 | lpar, &tag); | ||
348 | if (result) { | ||
349 | printk(KERN_ERR "%s:%u: write failed %s\n", __func__, | ||
350 | __LINE__, ps3_result(result)); | ||
351 | break; | ||
352 | } | ||
353 | |||
354 | result = ps3stor_wait_for_completion(notification_dev_id, tag, | ||
355 | timeout); | ||
356 | if (result) { | ||
357 | printk(KERN_ERR "%s:%u: read not completed %s\n", | ||
358 | __func__, __LINE__, ps3_result(result)); | ||
359 | break; | ||
360 | } | ||
361 | |||
362 | pr_debug("%s:%d: notify event (%u:%u:%u): event_type 0x%lx, " | ||
363 | "port %lu\n", __func__, __LINE__, repo->bus_index, | ||
364 | repo->dev_index, repo->dev_type, | ||
365 | notify_event->event_type, notify_event->dev_port); | ||
366 | |||
367 | if (notify_event->event_type != notify_region_probe || | ||
368 | notify_event->bus_id != repo->bus_id) { | ||
369 | pr_debug("%s:%u: bad notify_event: event %lu, " | ||
370 | "dev_id %lu, dev_type %lu\n", | ||
371 | __func__, __LINE__, notify_event->event_type, | ||
372 | notify_event->dev_id, notify_event->dev_type); | ||
373 | break; | ||
374 | } | ||
375 | |||
376 | if (notify_event->dev_id == repo->dev_id && | ||
377 | notify_event->dev_type == repo->dev_type) { | ||
378 | pr_debug("%s:%u: device ready (%u:%u:%u)\n", __func__, | ||
379 | __LINE__, repo->bus_index, repo->dev_index, | ||
380 | repo->dev_type); | ||
381 | error = 0; | ||
382 | break; | ||
383 | } | ||
384 | |||
385 | if (notify_event->dev_id == repo->dev_id && | ||
386 | notify_event->dev_type == PS3_DEV_TYPE_NOACCESS) { | ||
387 | pr_debug("%s:%u: no access: dev_id %u\n", __func__, | ||
388 | __LINE__, repo->dev_id); | ||
389 | break; | ||
390 | } | ||
391 | } | ||
392 | |||
393 | fail_close: | ||
394 | lv1_close_device(repo->bus_id, notification_dev_id); | ||
395 | fail_free: | ||
396 | kfree(buf); | ||
397 | pr_debug(" <- %s:%u\n", __func__, __LINE__); | ||
398 | return error; | ||
399 | } | ||
400 | |||
401 | static int ps3_setup_storage_dev(const struct ps3_repository_device *repo, | 325 | static int ps3_setup_storage_dev(const struct ps3_repository_device *repo, |
402 | enum ps3_match_id match_id) | 326 | enum ps3_match_id match_id) |
403 | { | 327 | { |
@@ -449,16 +373,6 @@ static int ps3_setup_storage_dev(const struct ps3_repository_device *repo, | |||
449 | goto fail_find_interrupt; | 373 | goto fail_find_interrupt; |
450 | } | 374 | } |
451 | 375 | ||
452 | /* FIXME: Arrange to only do this on a 'cold' boot */ | ||
453 | |||
454 | result = ps3_storage_wait_for_device(repo); | ||
455 | if (result) { | ||
456 | printk(KERN_ERR "%s:%u: storage_notification failed %d\n", | ||
457 | __func__, __LINE__, result); | ||
458 | result = -ENODEV; | ||
459 | goto fail_probe_notification; | ||
460 | } | ||
461 | |||
462 | for (i = 0; i < num_regions; i++) { | 376 | for (i = 0; i < num_regions; i++) { |
463 | unsigned int id; | 377 | unsigned int id; |
464 | u64 start, size; | 378 | u64 start, size; |
@@ -494,7 +408,6 @@ static int ps3_setup_storage_dev(const struct ps3_repository_device *repo, | |||
494 | 408 | ||
495 | fail_device_register: | 409 | fail_device_register: |
496 | fail_read_region: | 410 | fail_read_region: |
497 | fail_probe_notification: | ||
498 | fail_find_interrupt: | 411 | fail_find_interrupt: |
499 | kfree(p); | 412 | kfree(p); |
500 | fail_malloc: | 413 | fail_malloc: |
@@ -659,62 +572,268 @@ static int ps3_register_repository_device( | |||
659 | return result; | 572 | return result; |
660 | } | 573 | } |
661 | 574 | ||
575 | static void ps3_find_and_add_device(u64 bus_id, u64 dev_id) | ||
576 | { | ||
577 | struct ps3_repository_device repo; | ||
578 | int res; | ||
579 | unsigned int retries; | ||
580 | unsigned long rem; | ||
581 | |||
582 | /* | ||
583 | * On some firmware versions (e.g. 1.90), the device may not show up | ||
584 | * in the repository immediately | ||
585 | */ | ||
586 | for (retries = 0; retries < 10; retries++) { | ||
587 | res = ps3_repository_find_device_by_id(&repo, bus_id, dev_id); | ||
588 | if (!res) | ||
589 | goto found; | ||
590 | |||
591 | rem = msleep_interruptible(100); | ||
592 | if (rem) | ||
593 | break; | ||
594 | } | ||
595 | pr_warning("%s:%u: device %lu:%lu not found\n", __func__, __LINE__, | ||
596 | bus_id, dev_id); | ||
597 | return; | ||
598 | |||
599 | found: | ||
600 | if (retries) | ||
601 | pr_debug("%s:%u: device %lu:%lu found after %u retries\n", | ||
602 | __func__, __LINE__, bus_id, dev_id, retries); | ||
603 | |||
604 | ps3_register_repository_device(&repo); | ||
605 | return; | ||
606 | } | ||
607 | |||
608 | #define PS3_NOTIFICATION_DEV_ID ULONG_MAX | ||
609 | #define PS3_NOTIFICATION_INTERRUPT_ID 0 | ||
610 | |||
611 | struct ps3_notification_device { | ||
612 | struct ps3_system_bus_device sbd; | ||
613 | spinlock_t lock; | ||
614 | u64 tag; | ||
615 | u64 lv1_status; | ||
616 | struct completion done; | ||
617 | }; | ||
618 | |||
619 | enum ps3_notify_type { | ||
620 | notify_device_ready = 0, | ||
621 | notify_region_probe = 1, | ||
622 | notify_region_update = 2, | ||
623 | }; | ||
624 | |||
625 | struct ps3_notify_cmd { | ||
626 | u64 operation_code; /* must be zero */ | ||
627 | u64 event_mask; /* OR of 1UL << enum ps3_notify_type */ | ||
628 | }; | ||
629 | |||
630 | struct ps3_notify_event { | ||
631 | u64 event_type; /* enum ps3_notify_type */ | ||
632 | u64 bus_id; | ||
633 | u64 dev_id; | ||
634 | u64 dev_type; | ||
635 | u64 dev_port; | ||
636 | }; | ||
637 | |||
638 | static irqreturn_t ps3_notification_interrupt(int irq, void *data) | ||
639 | { | ||
640 | struct ps3_notification_device *dev = data; | ||
641 | int res; | ||
642 | u64 tag, status; | ||
643 | |||
644 | spin_lock(&dev->lock); | ||
645 | res = lv1_storage_get_async_status(PS3_NOTIFICATION_DEV_ID, &tag, | ||
646 | &status); | ||
647 | if (tag != dev->tag) | ||
648 | pr_err("%s:%u: tag mismatch, got %lx, expected %lx\n", | ||
649 | __func__, __LINE__, tag, dev->tag); | ||
650 | |||
651 | if (res) { | ||
652 | pr_err("%s:%u: res %d status 0x%lx\n", __func__, __LINE__, res, | ||
653 | status); | ||
654 | } else { | ||
655 | pr_debug("%s:%u: completed, status 0x%lx\n", __func__, | ||
656 | __LINE__, status); | ||
657 | dev->lv1_status = status; | ||
658 | complete(&dev->done); | ||
659 | } | ||
660 | spin_unlock(&dev->lock); | ||
661 | return IRQ_HANDLED; | ||
662 | } | ||
663 | |||
664 | static int ps3_notification_read_write(struct ps3_notification_device *dev, | ||
665 | u64 lpar, int write) | ||
666 | { | ||
667 | const char *op = write ? "write" : "read"; | ||
668 | unsigned long flags; | ||
669 | int res; | ||
670 | |||
671 | init_completion(&dev->done); | ||
672 | spin_lock_irqsave(&dev->lock, flags); | ||
673 | res = write ? lv1_storage_write(dev->sbd.dev_id, 0, 0, 1, 0, lpar, | ||
674 | &dev->tag) | ||
675 | : lv1_storage_read(dev->sbd.dev_id, 0, 0, 1, 0, lpar, | ||
676 | &dev->tag); | ||
677 | spin_unlock_irqrestore(&dev->lock, flags); | ||
678 | if (res) { | ||
679 | pr_err("%s:%u: %s failed %d\n", __func__, __LINE__, op, res); | ||
680 | return -EPERM; | ||
681 | } | ||
682 | pr_debug("%s:%u: notification %s issued\n", __func__, __LINE__, op); | ||
683 | |||
684 | res = wait_event_interruptible(dev->done.wait, | ||
685 | dev->done.done || kthread_should_stop()); | ||
686 | if (kthread_should_stop()) | ||
687 | res = -EINTR; | ||
688 | if (res) { | ||
689 | pr_debug("%s:%u: interrupted %s\n", __func__, __LINE__, op); | ||
690 | return res; | ||
691 | } | ||
692 | |||
693 | if (dev->lv1_status) { | ||
694 | pr_err("%s:%u: %s not completed, status 0x%lx\n", __func__, | ||
695 | __LINE__, op, dev->lv1_status); | ||
696 | return -EIO; | ||
697 | } | ||
698 | pr_debug("%s:%u: notification %s completed\n", __func__, __LINE__, op); | ||
699 | |||
700 | return 0; | ||
701 | } | ||
702 | |||
703 | static struct task_struct *probe_task; | ||
704 | |||
662 | /** | 705 | /** |
663 | * ps3_probe_thread - Background repository probing at system startup. | 706 | * ps3_probe_thread - Background repository probing at system startup. |
664 | * | 707 | * |
665 | * This implementation only supports background probing on a single bus. | 708 | * This implementation only supports background probing on a single bus. |
709 | * It uses the hypervisor's storage device notification mechanism to wait until | ||
710 | * a storage device is ready. The device notification mechanism uses a | ||
711 | * pseudo device to asynchronously notify the guest when storage devices become | ||
712 | * ready. The notification device has a block size of 512 bytes. | ||
666 | */ | 713 | */ |
667 | 714 | ||
668 | static int ps3_probe_thread(void *data) | 715 | static int ps3_probe_thread(void *data) |
669 | { | 716 | { |
670 | struct ps3_repository_device *repo = data; | 717 | struct ps3_notification_device dev; |
671 | int result; | 718 | int res; |
672 | unsigned int ms = 250; | 719 | unsigned int irq; |
720 | u64 lpar; | ||
721 | void *buf; | ||
722 | struct ps3_notify_cmd *notify_cmd; | ||
723 | struct ps3_notify_event *notify_event; | ||
673 | 724 | ||
674 | pr_debug(" -> %s:%u: kthread started\n", __func__, __LINE__); | 725 | pr_debug(" -> %s:%u: kthread started\n", __func__, __LINE__); |
675 | 726 | ||
727 | buf = kzalloc(512, GFP_KERNEL); | ||
728 | if (!buf) | ||
729 | return -ENOMEM; | ||
730 | |||
731 | lpar = ps3_mm_phys_to_lpar(__pa(buf)); | ||
732 | notify_cmd = buf; | ||
733 | notify_event = buf; | ||
734 | |||
735 | /* dummy system bus device */ | ||
736 | dev.sbd.bus_id = (u64)data; | ||
737 | dev.sbd.dev_id = PS3_NOTIFICATION_DEV_ID; | ||
738 | dev.sbd.interrupt_id = PS3_NOTIFICATION_INTERRUPT_ID; | ||
739 | |||
740 | res = lv1_open_device(dev.sbd.bus_id, dev.sbd.dev_id, 0); | ||
741 | if (res) { | ||
742 | pr_err("%s:%u: lv1_open_device failed %s\n", __func__, | ||
743 | __LINE__, ps3_result(res)); | ||
744 | goto fail_free; | ||
745 | } | ||
746 | |||
747 | res = ps3_sb_event_receive_port_setup(&dev.sbd, PS3_BINDING_CPU_ANY, | ||
748 | &irq); | ||
749 | if (res) { | ||
750 | pr_err("%s:%u: ps3_sb_event_receive_port_setup failed %d\n", | ||
751 | __func__, __LINE__, res); | ||
752 | goto fail_close_device; | ||
753 | } | ||
754 | |||
755 | spin_lock_init(&dev.lock); | ||
756 | |||
757 | res = request_irq(irq, ps3_notification_interrupt, IRQF_DISABLED, | ||
758 | "ps3_notification", &dev); | ||
759 | if (res) { | ||
760 | pr_err("%s:%u: request_irq failed %d\n", __func__, __LINE__, | ||
761 | res); | ||
762 | goto fail_sb_event_receive_port_destroy; | ||
763 | } | ||
764 | |||
765 | /* Setup and write the request for device notification. */ | ||
766 | notify_cmd->operation_code = 0; /* must be zero */ | ||
767 | notify_cmd->event_mask = 1UL << notify_region_probe; | ||
768 | |||
769 | res = ps3_notification_read_write(&dev, lpar, 1); | ||
770 | if (res) | ||
771 | goto fail_free_irq; | ||
772 | |||
773 | /* Loop here processing the requested notification events. */ | ||
676 | do { | 774 | do { |
677 | try_to_freeze(); | 775 | try_to_freeze(); |
678 | 776 | ||
679 | pr_debug("%s:%u: probing...\n", __func__, __LINE__); | 777 | memset(notify_event, 0, sizeof(*notify_event)); |
680 | 778 | ||
681 | do { | 779 | res = ps3_notification_read_write(&dev, lpar, 0); |
682 | result = ps3_repository_find_device(repo); | 780 | if (res) |
683 | |||
684 | if (result == -ENODEV) | ||
685 | pr_debug("%s:%u: nothing new\n", __func__, | ||
686 | __LINE__); | ||
687 | else if (result) | ||
688 | pr_debug("%s:%u: find device error.\n", | ||
689 | __func__, __LINE__); | ||
690 | else { | ||
691 | pr_debug("%s:%u: found device (%u:%u:%u)\n", | ||
692 | __func__, __LINE__, repo->bus_index, | ||
693 | repo->dev_index, repo->dev_type); | ||
694 | ps3_register_repository_device(repo); | ||
695 | ps3_repository_bump_device(repo); | ||
696 | ms = 250; | ||
697 | } | ||
698 | } while (!result); | ||
699 | |||
700 | pr_debug("%s:%u: ms %u\n", __func__, __LINE__, ms); | ||
701 | |||
702 | if ( ms > 60000) | ||
703 | break; | 781 | break; |
704 | 782 | ||
705 | msleep_interruptible(ms); | 783 | pr_debug("%s:%u: notify event type 0x%lx bus id %lu dev id %lu" |
784 | " type %lu port %lu\n", __func__, __LINE__, | ||
785 | notify_event->event_type, notify_event->bus_id, | ||
786 | notify_event->dev_id, notify_event->dev_type, | ||
787 | notify_event->dev_port); | ||
706 | 788 | ||
707 | /* An exponential backoff. */ | 789 | if (notify_event->event_type != notify_region_probe || |
708 | ms <<= 1; | 790 | notify_event->bus_id != dev.sbd.bus_id) { |
791 | pr_warning("%s:%u: bad notify_event: event %lu, " | ||
792 | "dev_id %lu, dev_type %lu\n", | ||
793 | __func__, __LINE__, notify_event->event_type, | ||
794 | notify_event->dev_id, | ||
795 | notify_event->dev_type); | ||
796 | continue; | ||
797 | } | ||
798 | |||
799 | ps3_find_and_add_device(dev.sbd.bus_id, notify_event->dev_id); | ||
709 | 800 | ||
710 | } while (!kthread_should_stop()); | 801 | } while (!kthread_should_stop()); |
711 | 802 | ||
803 | fail_free_irq: | ||
804 | free_irq(irq, &dev); | ||
805 | fail_sb_event_receive_port_destroy: | ||
806 | ps3_sb_event_receive_port_destroy(&dev.sbd, irq); | ||
807 | fail_close_device: | ||
808 | lv1_close_device(dev.sbd.bus_id, dev.sbd.dev_id); | ||
809 | fail_free: | ||
810 | kfree(buf); | ||
811 | |||
812 | probe_task = NULL; | ||
813 | |||
712 | pr_debug(" <- %s:%u: kthread finished\n", __func__, __LINE__); | 814 | pr_debug(" <- %s:%u: kthread finished\n", __func__, __LINE__); |
713 | 815 | ||
714 | return 0; | 816 | return 0; |
715 | } | 817 | } |
716 | 818 | ||
717 | /** | 819 | /** |
820 | * ps3_stop_probe_thread - Stops the background probe thread. | ||
821 | * | ||
822 | */ | ||
823 | |||
824 | static int ps3_stop_probe_thread(struct notifier_block *nb, unsigned long code, | ||
825 | void *data) | ||
826 | { | ||
827 | if (probe_task) | ||
828 | kthread_stop(probe_task); | ||
829 | return 0; | ||
830 | } | ||
831 | |||
832 | static struct notifier_block nb = { | ||
833 | .notifier_call = ps3_stop_probe_thread | ||
834 | }; | ||
835 | |||
836 | /** | ||
718 | * ps3_start_probe_thread - Starts the background probe thread. | 837 | * ps3_start_probe_thread - Starts the background probe thread. |
719 | * | 838 | * |
720 | */ | 839 | */ |
@@ -723,7 +842,7 @@ static int __init ps3_start_probe_thread(enum ps3_bus_type bus_type) | |||
723 | { | 842 | { |
724 | int result; | 843 | int result; |
725 | struct task_struct *task; | 844 | struct task_struct *task; |
726 | static struct ps3_repository_device repo; /* must be static */ | 845 | struct ps3_repository_device repo; |
727 | 846 | ||
728 | pr_debug(" -> %s:%d\n", __func__, __LINE__); | 847 | pr_debug(" -> %s:%d\n", __func__, __LINE__); |
729 | 848 | ||
@@ -746,7 +865,8 @@ static int __init ps3_start_probe_thread(enum ps3_bus_type bus_type) | |||
746 | return -ENODEV; | 865 | return -ENODEV; |
747 | } | 866 | } |
748 | 867 | ||
749 | task = kthread_run(ps3_probe_thread, &repo, "ps3-probe-%u", bus_type); | 868 | task = kthread_run(ps3_probe_thread, (void *)repo.bus_id, |
869 | "ps3-probe-%u", bus_type); | ||
750 | 870 | ||
751 | if (IS_ERR(task)) { | 871 | if (IS_ERR(task)) { |
752 | result = PTR_ERR(task); | 872 | result = PTR_ERR(task); |
@@ -755,6 +875,9 @@ static int __init ps3_start_probe_thread(enum ps3_bus_type bus_type) | |||
755 | return result; | 875 | return result; |
756 | } | 876 | } |
757 | 877 | ||
878 | probe_task = task; | ||
879 | register_reboot_notifier(&nb); | ||
880 | |||
758 | pr_debug(" <- %s:%d\n", __func__, __LINE__); | 881 | pr_debug(" <- %s:%d\n", __func__, __LINE__); |
759 | return 0; | 882 | return 0; |
760 | } | 883 | } |
@@ -787,6 +910,8 @@ static int __init ps3_register_devices(void) | |||
787 | 910 | ||
788 | ps3_register_sound_devices(); | 911 | ps3_register_sound_devices(); |
789 | 912 | ||
913 | ps3_register_lpm_devices(); | ||
914 | |||
790 | pr_debug(" <- %s:%d\n", __func__, __LINE__); | 915 | pr_debug(" <- %s:%d\n", __func__, __LINE__); |
791 | return 0; | 916 | return 0; |
792 | } | 917 | } |
diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c index 7bb3e1620974..68900476c842 100644 --- a/arch/powerpc/platforms/ps3/mm.c +++ b/arch/powerpc/platforms/ps3/mm.c | |||
@@ -36,11 +36,6 @@ | |||
36 | #endif | 36 | #endif |
37 | 37 | ||
38 | enum { | 38 | enum { |
39 | #if defined(CONFIG_PS3_USE_LPAR_ADDR) | ||
40 | USE_LPAR_ADDR = 1, | ||
41 | #else | ||
42 | USE_LPAR_ADDR = 0, | ||
43 | #endif | ||
44 | #if defined(CONFIG_PS3_DYNAMIC_DMA) | 39 | #if defined(CONFIG_PS3_DYNAMIC_DMA) |
45 | USE_DYNAMIC_DMA = 1, | 40 | USE_DYNAMIC_DMA = 1, |
46 | #else | 41 | #else |
@@ -137,11 +132,8 @@ static struct map map; | |||
137 | unsigned long ps3_mm_phys_to_lpar(unsigned long phys_addr) | 132 | unsigned long ps3_mm_phys_to_lpar(unsigned long phys_addr) |
138 | { | 133 | { |
139 | BUG_ON(is_kernel_addr(phys_addr)); | 134 | BUG_ON(is_kernel_addr(phys_addr)); |
140 | if (USE_LPAR_ADDR) | 135 | return (phys_addr < map.rm.size || phys_addr >= map.total) |
141 | return phys_addr; | 136 | ? phys_addr : phys_addr + map.r1.offset; |
142 | else | ||
143 | return (phys_addr < map.rm.size || phys_addr >= map.total) | ||
144 | ? phys_addr : phys_addr + map.r1.offset; | ||
145 | } | 137 | } |
146 | 138 | ||
147 | EXPORT_SYMBOL(ps3_mm_phys_to_lpar); | 139 | EXPORT_SYMBOL(ps3_mm_phys_to_lpar); |
@@ -309,7 +301,7 @@ static int __init ps3_mm_add_memory(void) | |||
309 | 301 | ||
310 | BUG_ON(!mem_init_done); | 302 | BUG_ON(!mem_init_done); |
311 | 303 | ||
312 | start_addr = USE_LPAR_ADDR ? map.r1.base : map.rm.size; | 304 | start_addr = map.rm.size; |
313 | start_pfn = start_addr >> PAGE_SHIFT; | 305 | start_pfn = start_addr >> PAGE_SHIFT; |
314 | nr_pages = (map.r1.size + PAGE_SIZE - 1) >> PAGE_SHIFT; | 306 | nr_pages = (map.r1.size + PAGE_SIZE - 1) >> PAGE_SHIFT; |
315 | 307 | ||
@@ -359,7 +351,7 @@ static unsigned long dma_sb_lpar_to_bus(struct ps3_dma_region *r, | |||
359 | static void __maybe_unused _dma_dump_region(const struct ps3_dma_region *r, | 351 | static void __maybe_unused _dma_dump_region(const struct ps3_dma_region *r, |
360 | const char *func, int line) | 352 | const char *func, int line) |
361 | { | 353 | { |
362 | DBG("%s:%d: dev %u:%u\n", func, line, r->dev->bus_id, | 354 | DBG("%s:%d: dev %lu:%lu\n", func, line, r->dev->bus_id, |
363 | r->dev->dev_id); | 355 | r->dev->dev_id); |
364 | DBG("%s:%d: page_size %u\n", func, line, r->page_size); | 356 | DBG("%s:%d: page_size %u\n", func, line, r->page_size); |
365 | DBG("%s:%d: bus_addr %lxh\n", func, line, r->bus_addr); | 357 | DBG("%s:%d: bus_addr %lxh\n", func, line, r->bus_addr); |
@@ -394,7 +386,7 @@ struct dma_chunk { | |||
394 | static void _dma_dump_chunk (const struct dma_chunk* c, const char* func, | 386 | static void _dma_dump_chunk (const struct dma_chunk* c, const char* func, |
395 | int line) | 387 | int line) |
396 | { | 388 | { |
397 | DBG("%s:%d: r.dev %u:%u\n", func, line, | 389 | DBG("%s:%d: r.dev %lu:%lu\n", func, line, |
398 | c->region->dev->bus_id, c->region->dev->dev_id); | 390 | c->region->dev->bus_id, c->region->dev->dev_id); |
399 | DBG("%s:%d: r.bus_addr %lxh\n", func, line, c->region->bus_addr); | 391 | DBG("%s:%d: r.bus_addr %lxh\n", func, line, c->region->bus_addr); |
400 | DBG("%s:%d: r.page_size %u\n", func, line, c->region->page_size); | 392 | DBG("%s:%d: r.page_size %u\n", func, line, c->region->page_size); |
@@ -658,7 +650,7 @@ static int dma_sb_region_create(struct ps3_dma_region *r) | |||
658 | BUG_ON(!r); | 650 | BUG_ON(!r); |
659 | 651 | ||
660 | if (!r->dev->bus_id) { | 652 | if (!r->dev->bus_id) { |
661 | pr_info("%s:%d: %u:%u no dma\n", __func__, __LINE__, | 653 | pr_info("%s:%d: %lu:%lu no dma\n", __func__, __LINE__, |
662 | r->dev->bus_id, r->dev->dev_id); | 654 | r->dev->bus_id, r->dev->dev_id); |
663 | return 0; | 655 | return 0; |
664 | } | 656 | } |
@@ -724,7 +716,7 @@ static int dma_sb_region_free(struct ps3_dma_region *r) | |||
724 | BUG_ON(!r); | 716 | BUG_ON(!r); |
725 | 717 | ||
726 | if (!r->dev->bus_id) { | 718 | if (!r->dev->bus_id) { |
727 | pr_info("%s:%d: %u:%u no dma\n", __func__, __LINE__, | 719 | pr_info("%s:%d: %lu:%lu no dma\n", __func__, __LINE__, |
728 | r->dev->bus_id, r->dev->dev_id); | 720 | r->dev->bus_id, r->dev->dev_id); |
729 | return 0; | 721 | return 0; |
730 | } | 722 | } |
@@ -1007,7 +999,7 @@ static int dma_sb_region_create_linear(struct ps3_dma_region *r) | |||
1007 | 999 | ||
1008 | if (r->offset + r->len > map.rm.size) { | 1000 | if (r->offset + r->len > map.rm.size) { |
1009 | /* Map (part of) 2nd RAM chunk */ | 1001 | /* Map (part of) 2nd RAM chunk */ |
1010 | virt_addr = USE_LPAR_ADDR ? map.r1.base : map.rm.size; | 1002 | virt_addr = map.rm.size; |
1011 | len = r->len; | 1003 | len = r->len; |
1012 | if (r->offset >= map.rm.size) | 1004 | if (r->offset >= map.rm.size) |
1013 | virt_addr += r->offset - map.rm.size; | 1005 | virt_addr += r->offset - map.rm.size; |
diff --git a/arch/powerpc/platforms/ps3/platform.h b/arch/powerpc/platforms/ps3/platform.h index 01f0c9506e11..235c13ebacd9 100644 --- a/arch/powerpc/platforms/ps3/platform.h +++ b/arch/powerpc/platforms/ps3/platform.h | |||
@@ -89,13 +89,11 @@ enum ps3_dev_type { | |||
89 | PS3_DEV_TYPE_STOR_ROM = TYPE_ROM, /* 5 */ | 89 | PS3_DEV_TYPE_STOR_ROM = TYPE_ROM, /* 5 */ |
90 | PS3_DEV_TYPE_SB_GPIO = 6, | 90 | PS3_DEV_TYPE_SB_GPIO = 6, |
91 | PS3_DEV_TYPE_STOR_FLASH = TYPE_RBC, /* 14 */ | 91 | PS3_DEV_TYPE_STOR_FLASH = TYPE_RBC, /* 14 */ |
92 | PS3_DEV_TYPE_STOR_DUMMY = 32, | ||
93 | PS3_DEV_TYPE_NOACCESS = 255, | ||
94 | }; | 92 | }; |
95 | 93 | ||
96 | int ps3_repository_read_bus_str(unsigned int bus_index, const char *bus_str, | 94 | int ps3_repository_read_bus_str(unsigned int bus_index, const char *bus_str, |
97 | u64 *value); | 95 | u64 *value); |
98 | int ps3_repository_read_bus_id(unsigned int bus_index, unsigned int *bus_id); | 96 | int ps3_repository_read_bus_id(unsigned int bus_index, u64 *bus_id); |
99 | int ps3_repository_read_bus_type(unsigned int bus_index, | 97 | int ps3_repository_read_bus_type(unsigned int bus_index, |
100 | enum ps3_bus_type *bus_type); | 98 | enum ps3_bus_type *bus_type); |
101 | int ps3_repository_read_bus_num_dev(unsigned int bus_index, | 99 | int ps3_repository_read_bus_num_dev(unsigned int bus_index, |
@@ -119,7 +117,7 @@ enum ps3_reg_type { | |||
119 | int ps3_repository_read_dev_str(unsigned int bus_index, | 117 | int ps3_repository_read_dev_str(unsigned int bus_index, |
120 | unsigned int dev_index, const char *dev_str, u64 *value); | 118 | unsigned int dev_index, const char *dev_str, u64 *value); |
121 | int ps3_repository_read_dev_id(unsigned int bus_index, unsigned int dev_index, | 119 | int ps3_repository_read_dev_id(unsigned int bus_index, unsigned int dev_index, |
122 | unsigned int *dev_id); | 120 | u64 *dev_id); |
123 | int ps3_repository_read_dev_type(unsigned int bus_index, | 121 | int ps3_repository_read_dev_type(unsigned int bus_index, |
124 | unsigned int dev_index, enum ps3_dev_type *dev_type); | 122 | unsigned int dev_index, enum ps3_dev_type *dev_type); |
125 | int ps3_repository_read_dev_intr(unsigned int bus_index, | 123 | int ps3_repository_read_dev_intr(unsigned int bus_index, |
@@ -138,21 +136,17 @@ int ps3_repository_read_dev_reg(unsigned int bus_index, | |||
138 | /* repository bus enumerators */ | 136 | /* repository bus enumerators */ |
139 | 137 | ||
140 | struct ps3_repository_device { | 138 | struct ps3_repository_device { |
141 | enum ps3_bus_type bus_type; | ||
142 | unsigned int bus_index; | 139 | unsigned int bus_index; |
143 | unsigned int bus_id; | ||
144 | enum ps3_dev_type dev_type; | ||
145 | unsigned int dev_index; | 140 | unsigned int dev_index; |
146 | unsigned int dev_id; | 141 | enum ps3_bus_type bus_type; |
142 | enum ps3_dev_type dev_type; | ||
143 | u64 bus_id; | ||
144 | u64 dev_id; | ||
147 | }; | 145 | }; |
148 | 146 | ||
149 | static inline struct ps3_repository_device *ps3_repository_bump_device( | ||
150 | struct ps3_repository_device *repo) | ||
151 | { | ||
152 | repo->dev_index++; | ||
153 | return repo; | ||
154 | } | ||
155 | int ps3_repository_find_device(struct ps3_repository_device *repo); | 147 | int ps3_repository_find_device(struct ps3_repository_device *repo); |
148 | int ps3_repository_find_device_by_id(struct ps3_repository_device *repo, | ||
149 | u64 bus_id, u64 dev_id); | ||
156 | int ps3_repository_find_devices(enum ps3_bus_type bus_type, | 150 | int ps3_repository_find_devices(enum ps3_bus_type bus_type, |
157 | int (*callback)(const struct ps3_repository_device *repo)); | 151 | int (*callback)(const struct ps3_repository_device *repo)); |
158 | int ps3_repository_find_bus(enum ps3_bus_type bus_type, unsigned int from, | 152 | int ps3_repository_find_bus(enum ps3_bus_type bus_type, unsigned int from, |
@@ -186,10 +180,10 @@ int ps3_repository_read_stor_dev_region(unsigned int bus_index, | |||
186 | unsigned int dev_index, unsigned int region_index, | 180 | unsigned int dev_index, unsigned int region_index, |
187 | unsigned int *region_id, u64 *region_start, u64 *region_size); | 181 | unsigned int *region_id, u64 *region_start, u64 *region_size); |
188 | 182 | ||
189 | /* repository pu and memory info */ | 183 | /* repository logical pu and memory info */ |
190 | 184 | ||
191 | int ps3_repository_read_num_pu(unsigned int *num_pu); | 185 | int ps3_repository_read_num_pu(u64 *num_pu); |
192 | int ps3_repository_read_ppe_id(unsigned int *pu_index, unsigned int *ppe_id); | 186 | int ps3_repository_read_pu_id(unsigned int pu_index, u64 *pu_id); |
193 | int ps3_repository_read_rm_base(unsigned int ppe_id, u64 *rm_base); | 187 | int ps3_repository_read_rm_base(unsigned int ppe_id, u64 *rm_base); |
194 | int ps3_repository_read_rm_size(unsigned int ppe_id, u64 *rm_size); | 188 | int ps3_repository_read_rm_size(unsigned int ppe_id, u64 *rm_size); |
195 | int ps3_repository_read_region_total(u64 *region_total); | 189 | int ps3_repository_read_region_total(u64 *region_total); |
@@ -200,9 +194,15 @@ int ps3_repository_read_mm_info(u64 *rm_base, u64 *rm_size, | |||
200 | 194 | ||
201 | int ps3_repository_read_num_be(unsigned int *num_be); | 195 | int ps3_repository_read_num_be(unsigned int *num_be); |
202 | int ps3_repository_read_be_node_id(unsigned int be_index, u64 *node_id); | 196 | int ps3_repository_read_be_node_id(unsigned int be_index, u64 *node_id); |
197 | int ps3_repository_read_be_id(u64 node_id, u64 *be_id); | ||
203 | int ps3_repository_read_tb_freq(u64 node_id, u64 *tb_freq); | 198 | int ps3_repository_read_tb_freq(u64 node_id, u64 *tb_freq); |
204 | int ps3_repository_read_be_tb_freq(unsigned int be_index, u64 *tb_freq); | 199 | int ps3_repository_read_be_tb_freq(unsigned int be_index, u64 *tb_freq); |
205 | 200 | ||
201 | /* repository performance monitor info */ | ||
202 | |||
203 | int ps3_repository_read_lpm_privileges(unsigned int be_index, u64 *lpar, | ||
204 | u64 *rights); | ||
205 | |||
206 | /* repository 'Other OS' area */ | 206 | /* repository 'Other OS' area */ |
207 | 207 | ||
208 | int ps3_repository_read_boot_dat_addr(u64 *lpar_addr); | 208 | int ps3_repository_read_boot_dat_addr(u64 *lpar_addr); |
diff --git a/arch/powerpc/platforms/ps3/repository.c b/arch/powerpc/platforms/ps3/repository.c index 1c94824f7b63..22063adeb38b 100644 --- a/arch/powerpc/platforms/ps3/repository.c +++ b/arch/powerpc/platforms/ps3/repository.c | |||
@@ -33,7 +33,7 @@ enum ps3_lpar_id { | |||
33 | }; | 33 | }; |
34 | 34 | ||
35 | #define dump_field(_a, _b) _dump_field(_a, _b, __func__, __LINE__) | 35 | #define dump_field(_a, _b) _dump_field(_a, _b, __func__, __LINE__) |
36 | static void _dump_field(const char *hdr, u64 n, const char* func, int line) | 36 | static void _dump_field(const char *hdr, u64 n, const char *func, int line) |
37 | { | 37 | { |
38 | #if defined(DEBUG) | 38 | #if defined(DEBUG) |
39 | char s[16]; | 39 | char s[16]; |
@@ -50,8 +50,8 @@ static void _dump_field(const char *hdr, u64 n, const char* func, int line) | |||
50 | 50 | ||
51 | #define dump_node_name(_a, _b, _c, _d, _e) \ | 51 | #define dump_node_name(_a, _b, _c, _d, _e) \ |
52 | _dump_node_name(_a, _b, _c, _d, _e, __func__, __LINE__) | 52 | _dump_node_name(_a, _b, _c, _d, _e, __func__, __LINE__) |
53 | static void _dump_node_name (unsigned int lpar_id, u64 n1, u64 n2, u64 n3, | 53 | static void _dump_node_name(unsigned int lpar_id, u64 n1, u64 n2, u64 n3, |
54 | u64 n4, const char* func, int line) | 54 | u64 n4, const char *func, int line) |
55 | { | 55 | { |
56 | pr_debug("%s:%d: lpar: %u\n", func, line, lpar_id); | 56 | pr_debug("%s:%d: lpar: %u\n", func, line, lpar_id); |
57 | _dump_field("n1: ", n1, func, line); | 57 | _dump_field("n1: ", n1, func, line); |
@@ -63,7 +63,7 @@ static void _dump_node_name (unsigned int lpar_id, u64 n1, u64 n2, u64 n3, | |||
63 | #define dump_node(_a, _b, _c, _d, _e, _f, _g) \ | 63 | #define dump_node(_a, _b, _c, _d, _e, _f, _g) \ |
64 | _dump_node(_a, _b, _c, _d, _e, _f, _g, __func__, __LINE__) | 64 | _dump_node(_a, _b, _c, _d, _e, _f, _g, __func__, __LINE__) |
65 | static void _dump_node(unsigned int lpar_id, u64 n1, u64 n2, u64 n3, u64 n4, | 65 | static void _dump_node(unsigned int lpar_id, u64 n1, u64 n2, u64 n3, u64 n4, |
66 | u64 v1, u64 v2, const char* func, int line) | 66 | u64 v1, u64 v2, const char *func, int line) |
67 | { | 67 | { |
68 | pr_debug("%s:%d: lpar: %u\n", func, line, lpar_id); | 68 | pr_debug("%s:%d: lpar: %u\n", func, line, lpar_id); |
69 | _dump_field("n1: ", n1, func, line); | 69 | _dump_field("n1: ", n1, func, line); |
@@ -165,21 +165,18 @@ int ps3_repository_read_bus_str(unsigned int bus_index, const char *bus_str, | |||
165 | make_first_field("bus", bus_index), | 165 | make_first_field("bus", bus_index), |
166 | make_field(bus_str, 0), | 166 | make_field(bus_str, 0), |
167 | 0, 0, | 167 | 0, 0, |
168 | value, 0); | 168 | value, NULL); |
169 | } | 169 | } |
170 | 170 | ||
171 | int ps3_repository_read_bus_id(unsigned int bus_index, unsigned int *bus_id) | 171 | int ps3_repository_read_bus_id(unsigned int bus_index, u64 *bus_id) |
172 | { | 172 | { |
173 | int result; | 173 | int result; |
174 | u64 v1; | ||
175 | u64 v2; /* unused */ | ||
176 | 174 | ||
177 | result = read_node(PS3_LPAR_ID_PME, | 175 | result = read_node(PS3_LPAR_ID_PME, |
178 | make_first_field("bus", bus_index), | 176 | make_first_field("bus", bus_index), |
179 | make_field("id", 0), | 177 | make_field("id", 0), |
180 | 0, 0, | 178 | 0, 0, |
181 | &v1, &v2); | 179 | bus_id, NULL); |
182 | *bus_id = v1; | ||
183 | return result; | 180 | return result; |
184 | } | 181 | } |
185 | 182 | ||
@@ -193,7 +190,7 @@ int ps3_repository_read_bus_type(unsigned int bus_index, | |||
193 | make_first_field("bus", bus_index), | 190 | make_first_field("bus", bus_index), |
194 | make_field("type", 0), | 191 | make_field("type", 0), |
195 | 0, 0, | 192 | 0, 0, |
196 | &v1, 0); | 193 | &v1, NULL); |
197 | *bus_type = v1; | 194 | *bus_type = v1; |
198 | return result; | 195 | return result; |
199 | } | 196 | } |
@@ -208,7 +205,7 @@ int ps3_repository_read_bus_num_dev(unsigned int bus_index, | |||
208 | make_first_field("bus", bus_index), | 205 | make_first_field("bus", bus_index), |
209 | make_field("num_dev", 0), | 206 | make_field("num_dev", 0), |
210 | 0, 0, | 207 | 0, 0, |
211 | &v1, 0); | 208 | &v1, NULL); |
212 | *num_dev = v1; | 209 | *num_dev = v1; |
213 | return result; | 210 | return result; |
214 | } | 211 | } |
@@ -221,22 +218,20 @@ int ps3_repository_read_dev_str(unsigned int bus_index, | |||
221 | make_field("dev", dev_index), | 218 | make_field("dev", dev_index), |
222 | make_field(dev_str, 0), | 219 | make_field(dev_str, 0), |
223 | 0, | 220 | 0, |
224 | value, 0); | 221 | value, NULL); |
225 | } | 222 | } |
226 | 223 | ||
227 | int ps3_repository_read_dev_id(unsigned int bus_index, unsigned int dev_index, | 224 | int ps3_repository_read_dev_id(unsigned int bus_index, unsigned int dev_index, |
228 | unsigned int *dev_id) | 225 | u64 *dev_id) |
229 | { | 226 | { |
230 | int result; | 227 | int result; |
231 | u64 v1; | ||
232 | 228 | ||
233 | result = read_node(PS3_LPAR_ID_PME, | 229 | result = read_node(PS3_LPAR_ID_PME, |
234 | make_first_field("bus", bus_index), | 230 | make_first_field("bus", bus_index), |
235 | make_field("dev", dev_index), | 231 | make_field("dev", dev_index), |
236 | make_field("id", 0), | 232 | make_field("id", 0), |
237 | 0, | 233 | 0, |
238 | &v1, 0); | 234 | dev_id, NULL); |
239 | *dev_id = v1; | ||
240 | return result; | 235 | return result; |
241 | } | 236 | } |
242 | 237 | ||
@@ -251,14 +246,14 @@ int ps3_repository_read_dev_type(unsigned int bus_index, | |||
251 | make_field("dev", dev_index), | 246 | make_field("dev", dev_index), |
252 | make_field("type", 0), | 247 | make_field("type", 0), |
253 | 0, | 248 | 0, |
254 | &v1, 0); | 249 | &v1, NULL); |
255 | *dev_type = v1; | 250 | *dev_type = v1; |
256 | return result; | 251 | return result; |
257 | } | 252 | } |
258 | 253 | ||
259 | int ps3_repository_read_dev_intr(unsigned int bus_index, | 254 | int ps3_repository_read_dev_intr(unsigned int bus_index, |
260 | unsigned int dev_index, unsigned int intr_index, | 255 | unsigned int dev_index, unsigned int intr_index, |
261 | enum ps3_interrupt_type *intr_type, unsigned int* interrupt_id) | 256 | enum ps3_interrupt_type *intr_type, unsigned int *interrupt_id) |
262 | { | 257 | { |
263 | int result; | 258 | int result; |
264 | u64 v1; | 259 | u64 v1; |
@@ -287,7 +282,7 @@ int ps3_repository_read_dev_reg_type(unsigned int bus_index, | |||
287 | make_field("dev", dev_index), | 282 | make_field("dev", dev_index), |
288 | make_field("reg", reg_index), | 283 | make_field("reg", reg_index), |
289 | make_field("type", 0), | 284 | make_field("type", 0), |
290 | &v1, 0); | 285 | &v1, NULL); |
291 | *reg_type = v1; | 286 | *reg_type = v1; |
292 | return result; | 287 | return result; |
293 | } | 288 | } |
@@ -332,7 +327,7 @@ int ps3_repository_find_device(struct ps3_repository_device *repo) | |||
332 | return result; | 327 | return result; |
333 | } | 328 | } |
334 | 329 | ||
335 | pr_debug("%s:%d: bus_type %u, bus_index %u, bus_id %u, num_dev %u\n", | 330 | pr_debug("%s:%d: bus_type %u, bus_index %u, bus_id %lu, num_dev %u\n", |
336 | __func__, __LINE__, tmp.bus_type, tmp.bus_index, tmp.bus_id, | 331 | __func__, __LINE__, tmp.bus_type, tmp.bus_index, tmp.bus_id, |
337 | num_dev); | 332 | num_dev); |
338 | 333 | ||
@@ -349,47 +344,95 @@ int ps3_repository_find_device(struct ps3_repository_device *repo) | |||
349 | return result; | 344 | return result; |
350 | } | 345 | } |
351 | 346 | ||
352 | if (tmp.bus_type == PS3_BUS_TYPE_STORAGE) { | 347 | result = ps3_repository_read_dev_id(tmp.bus_index, tmp.dev_index, |
353 | /* | 348 | &tmp.dev_id); |
354 | * A storage device may show up in the repository before the | ||
355 | * hypervisor has finished probing its type and regions | ||
356 | */ | ||
357 | unsigned int num_regions; | ||
358 | |||
359 | if (tmp.dev_type == PS3_DEV_TYPE_STOR_DUMMY) { | ||
360 | pr_debug("%s:%u storage device not ready\n", __func__, | ||
361 | __LINE__); | ||
362 | return -ENODEV; | ||
363 | } | ||
364 | 349 | ||
365 | result = ps3_repository_read_stor_dev_num_regions(tmp.bus_index, | 350 | if (result) { |
366 | tmp.dev_index, | 351 | pr_debug("%s:%d ps3_repository_read_dev_id failed\n", __func__, |
367 | &num_regions); | 352 | __LINE__); |
353 | return result; | ||
354 | } | ||
355 | |||
356 | pr_debug("%s:%d: found: dev_type %u, dev_index %u, dev_id %lu\n", | ||
357 | __func__, __LINE__, tmp.dev_type, tmp.dev_index, tmp.dev_id); | ||
358 | |||
359 | *repo = tmp; | ||
360 | return 0; | ||
361 | } | ||
362 | |||
363 | int ps3_repository_find_device_by_id(struct ps3_repository_device *repo, | ||
364 | u64 bus_id, u64 dev_id) | ||
365 | { | ||
366 | int result = -ENODEV; | ||
367 | struct ps3_repository_device tmp; | ||
368 | unsigned int num_dev; | ||
369 | |||
370 | pr_debug(" -> %s:%u: find device by id %lu:%lu\n", __func__, __LINE__, | ||
371 | bus_id, dev_id); | ||
372 | |||
373 | for (tmp.bus_index = 0; tmp.bus_index < 10; tmp.bus_index++) { | ||
374 | result = ps3_repository_read_bus_id(tmp.bus_index, | ||
375 | &tmp.bus_id); | ||
368 | if (result) { | 376 | if (result) { |
369 | pr_debug("%s:%d read_stor_dev_num_regions failed\n", | 377 | pr_debug("%s:%u read_bus_id(%u) failed\n", __func__, |
370 | __func__, __LINE__); | 378 | __LINE__, tmp.bus_index); |
371 | return result; | 379 | return result; |
372 | } | 380 | } |
373 | 381 | ||
374 | if (!num_regions) { | 382 | if (tmp.bus_id == bus_id) |
375 | pr_debug("%s:%u storage device has no regions yet\n", | 383 | goto found_bus; |
376 | __func__, __LINE__); | 384 | |
377 | return -ENODEV; | 385 | pr_debug("%s:%u: skip, bus_id %lu\n", __func__, __LINE__, |
378 | } | 386 | tmp.bus_id); |
379 | } | 387 | } |
388 | pr_debug(" <- %s:%u: bus not found\n", __func__, __LINE__); | ||
389 | return result; | ||
380 | 390 | ||
381 | result = ps3_repository_read_dev_id(tmp.bus_index, tmp.dev_index, | 391 | found_bus: |
382 | &tmp.dev_id); | 392 | result = ps3_repository_read_bus_type(tmp.bus_index, &tmp.bus_type); |
393 | if (result) { | ||
394 | pr_debug("%s:%u read_bus_type(%u) failed\n", __func__, | ||
395 | __LINE__, tmp.bus_index); | ||
396 | return result; | ||
397 | } | ||
383 | 398 | ||
399 | result = ps3_repository_read_bus_num_dev(tmp.bus_index, &num_dev); | ||
384 | if (result) { | 400 | if (result) { |
385 | pr_debug("%s:%d ps3_repository_read_dev_id failed\n", __func__, | 401 | pr_debug("%s:%u read_bus_num_dev failed\n", __func__, |
386 | __LINE__); | 402 | __LINE__); |
387 | return result; | 403 | return result; |
388 | } | 404 | } |
389 | 405 | ||
390 | pr_debug("%s:%d: found: dev_type %u, dev_index %u, dev_id %u\n", | 406 | for (tmp.dev_index = 0; tmp.dev_index < num_dev; tmp.dev_index++) { |
391 | __func__, __LINE__, tmp.dev_type, tmp.dev_index, tmp.dev_id); | 407 | result = ps3_repository_read_dev_id(tmp.bus_index, |
408 | tmp.dev_index, | ||
409 | &tmp.dev_id); | ||
410 | if (result) { | ||
411 | pr_debug("%s:%u read_dev_id(%u:%u) failed\n", __func__, | ||
412 | __LINE__, tmp.bus_index, tmp.dev_index); | ||
413 | return result; | ||
414 | } | ||
392 | 415 | ||
416 | if (tmp.dev_id == dev_id) | ||
417 | goto found_dev; | ||
418 | |||
419 | pr_debug("%s:%u: skip, dev_id %lu\n", __func__, __LINE__, | ||
420 | tmp.dev_id); | ||
421 | } | ||
422 | pr_debug(" <- %s:%u: dev not found\n", __func__, __LINE__); | ||
423 | return result; | ||
424 | |||
425 | found_dev: | ||
426 | result = ps3_repository_read_dev_type(tmp.bus_index, tmp.dev_index, | ||
427 | &tmp.dev_type); | ||
428 | if (result) { | ||
429 | pr_debug("%s:%u read_dev_type failed\n", __func__, __LINE__); | ||
430 | return result; | ||
431 | } | ||
432 | |||
433 | pr_debug(" <- %s:%u: found: type (%u:%u) index (%u:%u) id (%lu:%lu)\n", | ||
434 | __func__, __LINE__, tmp.bus_type, tmp.dev_type, tmp.bus_index, | ||
435 | tmp.dev_index, tmp.bus_id, tmp.dev_id); | ||
393 | *repo = tmp; | 436 | *repo = tmp; |
394 | return 0; | 437 | return 0; |
395 | } | 438 | } |
@@ -402,50 +445,34 @@ int __devinit ps3_repository_find_devices(enum ps3_bus_type bus_type, | |||
402 | 445 | ||
403 | pr_debug(" -> %s:%d: find bus_type %u\n", __func__, __LINE__, bus_type); | 446 | pr_debug(" -> %s:%d: find bus_type %u\n", __func__, __LINE__, bus_type); |
404 | 447 | ||
405 | for (repo.bus_index = 0; repo.bus_index < 10; repo.bus_index++) { | 448 | repo.bus_type = bus_type; |
449 | result = ps3_repository_find_bus(repo.bus_type, 0, &repo.bus_index); | ||
450 | if (result) { | ||
451 | pr_debug(" <- %s:%u: bus not found\n", __func__, __LINE__); | ||
452 | return result; | ||
453 | } | ||
406 | 454 | ||
407 | result = ps3_repository_read_bus_type(repo.bus_index, | 455 | result = ps3_repository_read_bus_id(repo.bus_index, &repo.bus_id); |
408 | &repo.bus_type); | 456 | if (result) { |
457 | pr_debug("%s:%d read_bus_id(%u) failed\n", __func__, __LINE__, | ||
458 | repo.bus_index); | ||
459 | return result; | ||
460 | } | ||
409 | 461 | ||
410 | if (result) { | 462 | for (repo.dev_index = 0; ; repo.dev_index++) { |
411 | pr_debug("%s:%d read_bus_type(%u) failed\n", | 463 | result = ps3_repository_find_device(&repo); |
412 | __func__, __LINE__, repo.bus_index); | 464 | if (result == -ENODEV) { |
465 | result = 0; | ||
466 | break; | ||
467 | } else if (result) | ||
413 | break; | 468 | break; |
414 | } | ||
415 | |||
416 | if (repo.bus_type != bus_type) { | ||
417 | pr_debug("%s:%d: skip, bus_type %u\n", __func__, | ||
418 | __LINE__, repo.bus_type); | ||
419 | continue; | ||
420 | } | ||
421 | |||
422 | result = ps3_repository_read_bus_id(repo.bus_index, | ||
423 | &repo.bus_id); | ||
424 | 469 | ||
470 | result = callback(&repo); | ||
425 | if (result) { | 471 | if (result) { |
426 | pr_debug("%s:%d read_bus_id(%u) failed\n", | 472 | pr_debug("%s:%d: abort at callback\n", __func__, |
427 | __func__, __LINE__, repo.bus_index); | 473 | __LINE__); |
428 | continue; | 474 | break; |
429 | } | ||
430 | |||
431 | for (repo.dev_index = 0; ; repo.dev_index++) { | ||
432 | result = ps3_repository_find_device(&repo); | ||
433 | |||
434 | if (result == -ENODEV) { | ||
435 | result = 0; | ||
436 | break; | ||
437 | } else if (result) | ||
438 | break; | ||
439 | |||
440 | result = callback(&repo); | ||
441 | |||
442 | if (result) { | ||
443 | pr_debug("%s:%d: abort at callback\n", __func__, | ||
444 | __LINE__); | ||
445 | break; | ||
446 | } | ||
447 | } | 475 | } |
448 | break; | ||
449 | } | 476 | } |
450 | 477 | ||
451 | pr_debug(" <- %s:%d\n", __func__, __LINE__); | 478 | pr_debug(" <- %s:%d\n", __func__, __LINE__); |
@@ -561,7 +588,7 @@ int ps3_repository_read_stor_dev_port(unsigned int bus_index, | |||
561 | make_first_field("bus", bus_index), | 588 | make_first_field("bus", bus_index), |
562 | make_field("dev", dev_index), | 589 | make_field("dev", dev_index), |
563 | make_field("port", 0), | 590 | make_field("port", 0), |
564 | 0, port, 0); | 591 | 0, port, NULL); |
565 | } | 592 | } |
566 | 593 | ||
567 | int ps3_repository_read_stor_dev_blk_size(unsigned int bus_index, | 594 | int ps3_repository_read_stor_dev_blk_size(unsigned int bus_index, |
@@ -571,7 +598,7 @@ int ps3_repository_read_stor_dev_blk_size(unsigned int bus_index, | |||
571 | make_first_field("bus", bus_index), | 598 | make_first_field("bus", bus_index), |
572 | make_field("dev", dev_index), | 599 | make_field("dev", dev_index), |
573 | make_field("blk_size", 0), | 600 | make_field("blk_size", 0), |
574 | 0, blk_size, 0); | 601 | 0, blk_size, NULL); |
575 | } | 602 | } |
576 | 603 | ||
577 | int ps3_repository_read_stor_dev_num_blocks(unsigned int bus_index, | 604 | int ps3_repository_read_stor_dev_num_blocks(unsigned int bus_index, |
@@ -581,7 +608,7 @@ int ps3_repository_read_stor_dev_num_blocks(unsigned int bus_index, | |||
581 | make_first_field("bus", bus_index), | 608 | make_first_field("bus", bus_index), |
582 | make_field("dev", dev_index), | 609 | make_field("dev", dev_index), |
583 | make_field("n_blocks", 0), | 610 | make_field("n_blocks", 0), |
584 | 0, num_blocks, 0); | 611 | 0, num_blocks, NULL); |
585 | } | 612 | } |
586 | 613 | ||
587 | int ps3_repository_read_stor_dev_num_regions(unsigned int bus_index, | 614 | int ps3_repository_read_stor_dev_num_regions(unsigned int bus_index, |
@@ -594,7 +621,7 @@ int ps3_repository_read_stor_dev_num_regions(unsigned int bus_index, | |||
594 | make_first_field("bus", bus_index), | 621 | make_first_field("bus", bus_index), |
595 | make_field("dev", dev_index), | 622 | make_field("dev", dev_index), |
596 | make_field("n_regs", 0), | 623 | make_field("n_regs", 0), |
597 | 0, &v1, 0); | 624 | 0, &v1, NULL); |
598 | *num_regions = v1; | 625 | *num_regions = v1; |
599 | return result; | 626 | return result; |
600 | } | 627 | } |
@@ -611,7 +638,7 @@ int ps3_repository_read_stor_dev_region_id(unsigned int bus_index, | |||
611 | make_field("dev", dev_index), | 638 | make_field("dev", dev_index), |
612 | make_field("region", region_index), | 639 | make_field("region", region_index), |
613 | make_field("id", 0), | 640 | make_field("id", 0), |
614 | &v1, 0); | 641 | &v1, NULL); |
615 | *region_id = v1; | 642 | *region_id = v1; |
616 | return result; | 643 | return result; |
617 | } | 644 | } |
@@ -624,7 +651,7 @@ int ps3_repository_read_stor_dev_region_size(unsigned int bus_index, | |||
624 | make_field("dev", dev_index), | 651 | make_field("dev", dev_index), |
625 | make_field("region", region_index), | 652 | make_field("region", region_index), |
626 | make_field("size", 0), | 653 | make_field("size", 0), |
627 | region_size, 0); | 654 | region_size, NULL); |
628 | } | 655 | } |
629 | 656 | ||
630 | int ps3_repository_read_stor_dev_region_start(unsigned int bus_index, | 657 | int ps3_repository_read_stor_dev_region_start(unsigned int bus_index, |
@@ -635,7 +662,7 @@ int ps3_repository_read_stor_dev_region_start(unsigned int bus_index, | |||
635 | make_field("dev", dev_index), | 662 | make_field("dev", dev_index), |
636 | make_field("region", region_index), | 663 | make_field("region", region_index), |
637 | make_field("start", 0), | 664 | make_field("start", 0), |
638 | region_start, 0); | 665 | region_start, NULL); |
639 | } | 666 | } |
640 | 667 | ||
641 | int ps3_repository_read_stor_dev_info(unsigned int bus_index, | 668 | int ps3_repository_read_stor_dev_info(unsigned int bus_index, |
@@ -684,6 +711,35 @@ int ps3_repository_read_stor_dev_region(unsigned int bus_index, | |||
684 | return result; | 711 | return result; |
685 | } | 712 | } |
686 | 713 | ||
714 | /** | ||
715 | * ps3_repository_read_num_pu - Number of logical PU processors for this lpar. | ||
716 | */ | ||
717 | |||
718 | int ps3_repository_read_num_pu(u64 *num_pu) | ||
719 | { | ||
720 | *num_pu = 0; | ||
721 | return read_node(PS3_LPAR_ID_CURRENT, | ||
722 | make_first_field("bi", 0), | ||
723 | make_field("pun", 0), | ||
724 | 0, 0, | ||
725 | num_pu, NULL); | ||
726 | } | ||
727 | |||
728 | /** | ||
729 | * ps3_repository_read_pu_id - Read the logical PU id. | ||
730 | * @pu_index: Zero based index. | ||
731 | * @pu_id: The logical PU id. | ||
732 | */ | ||
733 | |||
734 | int ps3_repository_read_pu_id(unsigned int pu_index, u64 *pu_id) | ||
735 | { | ||
736 | return read_node(PS3_LPAR_ID_CURRENT, | ||
737 | make_first_field("bi", 0), | ||
738 | make_field("pu", pu_index), | ||
739 | 0, 0, | ||
740 | pu_id, NULL); | ||
741 | } | ||
742 | |||
687 | int ps3_repository_read_rm_size(unsigned int ppe_id, u64 *rm_size) | 743 | int ps3_repository_read_rm_size(unsigned int ppe_id, u64 *rm_size) |
688 | { | 744 | { |
689 | return read_node(PS3_LPAR_ID_CURRENT, | 745 | return read_node(PS3_LPAR_ID_CURRENT, |
@@ -691,7 +747,7 @@ int ps3_repository_read_rm_size(unsigned int ppe_id, u64 *rm_size) | |||
691 | make_field("pu", 0), | 747 | make_field("pu", 0), |
692 | ppe_id, | 748 | ppe_id, |
693 | make_field("rm_size", 0), | 749 | make_field("rm_size", 0), |
694 | rm_size, 0); | 750 | rm_size, NULL); |
695 | } | 751 | } |
696 | 752 | ||
697 | int ps3_repository_read_region_total(u64 *region_total) | 753 | int ps3_repository_read_region_total(u64 *region_total) |
@@ -700,7 +756,7 @@ int ps3_repository_read_region_total(u64 *region_total) | |||
700 | make_first_field("bi", 0), | 756 | make_first_field("bi", 0), |
701 | make_field("rgntotal", 0), | 757 | make_field("rgntotal", 0), |
702 | 0, 0, | 758 | 0, 0, |
703 | region_total, 0); | 759 | region_total, NULL); |
704 | } | 760 | } |
705 | 761 | ||
706 | /** | 762 | /** |
@@ -736,7 +792,7 @@ int ps3_repository_read_num_spu_reserved(unsigned int *num_spu_reserved) | |||
736 | make_first_field("bi", 0), | 792 | make_first_field("bi", 0), |
737 | make_field("spun", 0), | 793 | make_field("spun", 0), |
738 | 0, 0, | 794 | 0, 0, |
739 | &v1, 0); | 795 | &v1, NULL); |
740 | *num_spu_reserved = v1; | 796 | *num_spu_reserved = v1; |
741 | return result; | 797 | return result; |
742 | } | 798 | } |
@@ -755,7 +811,7 @@ int ps3_repository_read_num_spu_resource_id(unsigned int *num_resource_id) | |||
755 | make_first_field("bi", 0), | 811 | make_first_field("bi", 0), |
756 | make_field("spursvn", 0), | 812 | make_field("spursvn", 0), |
757 | 0, 0, | 813 | 0, 0, |
758 | &v1, 0); | 814 | &v1, NULL); |
759 | *num_resource_id = v1; | 815 | *num_resource_id = v1; |
760 | return result; | 816 | return result; |
761 | } | 817 | } |
@@ -768,7 +824,7 @@ int ps3_repository_read_num_spu_resource_id(unsigned int *num_resource_id) | |||
768 | */ | 824 | */ |
769 | 825 | ||
770 | int ps3_repository_read_spu_resource_id(unsigned int res_index, | 826 | int ps3_repository_read_spu_resource_id(unsigned int res_index, |
771 | enum ps3_spu_resource_type* resource_type, unsigned int *resource_id) | 827 | enum ps3_spu_resource_type *resource_type, unsigned int *resource_id) |
772 | { | 828 | { |
773 | int result; | 829 | int result; |
774 | u64 v1; | 830 | u64 v1; |
@@ -785,14 +841,14 @@ int ps3_repository_read_spu_resource_id(unsigned int res_index, | |||
785 | return result; | 841 | return result; |
786 | } | 842 | } |
787 | 843 | ||
788 | int ps3_repository_read_boot_dat_address(u64 *address) | 844 | static int ps3_repository_read_boot_dat_address(u64 *address) |
789 | { | 845 | { |
790 | return read_node(PS3_LPAR_ID_CURRENT, | 846 | return read_node(PS3_LPAR_ID_CURRENT, |
791 | make_first_field("bi", 0), | 847 | make_first_field("bi", 0), |
792 | make_field("boot_dat", 0), | 848 | make_field("boot_dat", 0), |
793 | make_field("address", 0), | 849 | make_field("address", 0), |
794 | 0, | 850 | 0, |
795 | address, 0); | 851 | address, NULL); |
796 | } | 852 | } |
797 | 853 | ||
798 | int ps3_repository_read_boot_dat_size(unsigned int *size) | 854 | int ps3_repository_read_boot_dat_size(unsigned int *size) |
@@ -805,7 +861,7 @@ int ps3_repository_read_boot_dat_size(unsigned int *size) | |||
805 | make_field("boot_dat", 0), | 861 | make_field("boot_dat", 0), |
806 | make_field("size", 0), | 862 | make_field("size", 0), |
807 | 0, | 863 | 0, |
808 | &v1, 0); | 864 | &v1, NULL); |
809 | *size = v1; | 865 | *size = v1; |
810 | return result; | 866 | return result; |
811 | } | 867 | } |
@@ -820,7 +876,7 @@ int ps3_repository_read_vuart_av_port(unsigned int *port) | |||
820 | make_field("vir_uart", 0), | 876 | make_field("vir_uart", 0), |
821 | make_field("port", 0), | 877 | make_field("port", 0), |
822 | make_field("avset", 0), | 878 | make_field("avset", 0), |
823 | &v1, 0); | 879 | &v1, NULL); |
824 | *port = v1; | 880 | *port = v1; |
825 | return result; | 881 | return result; |
826 | } | 882 | } |
@@ -835,7 +891,7 @@ int ps3_repository_read_vuart_sysmgr_port(unsigned int *port) | |||
835 | make_field("vir_uart", 0), | 891 | make_field("vir_uart", 0), |
836 | make_field("port", 0), | 892 | make_field("port", 0), |
837 | make_field("sysmgr", 0), | 893 | make_field("sysmgr", 0), |
838 | &v1, 0); | 894 | &v1, NULL); |
839 | *port = v1; | 895 | *port = v1; |
840 | return result; | 896 | return result; |
841 | } | 897 | } |
@@ -856,6 +912,10 @@ int ps3_repository_read_boot_dat_info(u64 *lpar_addr, unsigned int *size) | |||
856 | : ps3_repository_read_boot_dat_size(size); | 912 | : ps3_repository_read_boot_dat_size(size); |
857 | } | 913 | } |
858 | 914 | ||
915 | /** | ||
916 | * ps3_repository_read_num_be - Number of physical BE processors in the system. | ||
917 | */ | ||
918 | |||
859 | int ps3_repository_read_num_be(unsigned int *num_be) | 919 | int ps3_repository_read_num_be(unsigned int *num_be) |
860 | { | 920 | { |
861 | int result; | 921 | int result; |
@@ -866,11 +926,17 @@ int ps3_repository_read_num_be(unsigned int *num_be) | |||
866 | 0, | 926 | 0, |
867 | 0, | 927 | 0, |
868 | 0, | 928 | 0, |
869 | &v1, 0); | 929 | &v1, NULL); |
870 | *num_be = v1; | 930 | *num_be = v1; |
871 | return result; | 931 | return result; |
872 | } | 932 | } |
873 | 933 | ||
934 | /** | ||
935 | * ps3_repository_read_be_node_id - Read the physical BE processor node id. | ||
936 | * @be_index: Zero based index. | ||
937 | * @node_id: The BE processor node id. | ||
938 | */ | ||
939 | |||
874 | int ps3_repository_read_be_node_id(unsigned int be_index, u64 *node_id) | 940 | int ps3_repository_read_be_node_id(unsigned int be_index, u64 *node_id) |
875 | { | 941 | { |
876 | return read_node(PS3_LPAR_ID_PME, | 942 | return read_node(PS3_LPAR_ID_PME, |
@@ -878,7 +944,23 @@ int ps3_repository_read_be_node_id(unsigned int be_index, u64 *node_id) | |||
878 | 0, | 944 | 0, |
879 | 0, | 945 | 0, |
880 | 0, | 946 | 0, |
881 | node_id, 0); | 947 | node_id, NULL); |
948 | } | ||
949 | |||
950 | /** | ||
951 | * ps3_repository_read_be_id - Read the physical BE processor id. | ||
952 | * @node_id: The BE processor node id. | ||
953 | * @be_id: The BE processor id. | ||
954 | */ | ||
955 | |||
956 | int ps3_repository_read_be_id(u64 node_id, u64 *be_id) | ||
957 | { | ||
958 | return read_node(PS3_LPAR_ID_PME, | ||
959 | make_first_field("be", 0), | ||
960 | node_id, | ||
961 | 0, | ||
962 | 0, | ||
963 | be_id, NULL); | ||
882 | } | 964 | } |
883 | 965 | ||
884 | int ps3_repository_read_tb_freq(u64 node_id, u64 *tb_freq) | 966 | int ps3_repository_read_tb_freq(u64 node_id, u64 *tb_freq) |
@@ -888,7 +970,7 @@ int ps3_repository_read_tb_freq(u64 node_id, u64 *tb_freq) | |||
888 | node_id, | 970 | node_id, |
889 | make_field("clock", 0), | 971 | make_field("clock", 0), |
890 | 0, | 972 | 0, |
891 | tb_freq, 0); | 973 | tb_freq, NULL); |
892 | } | 974 | } |
893 | 975 | ||
894 | int ps3_repository_read_be_tb_freq(unsigned int be_index, u64 *tb_freq) | 976 | int ps3_repository_read_be_tb_freq(unsigned int be_index, u64 *tb_freq) |
@@ -897,11 +979,29 @@ int ps3_repository_read_be_tb_freq(unsigned int be_index, u64 *tb_freq) | |||
897 | u64 node_id; | 979 | u64 node_id; |
898 | 980 | ||
899 | *tb_freq = 0; | 981 | *tb_freq = 0; |
900 | result = ps3_repository_read_be_node_id(0, &node_id); | 982 | result = ps3_repository_read_be_node_id(be_index, &node_id); |
901 | return result ? result | 983 | return result ? result |
902 | : ps3_repository_read_tb_freq(node_id, tb_freq); | 984 | : ps3_repository_read_tb_freq(node_id, tb_freq); |
903 | } | 985 | } |
904 | 986 | ||
987 | int ps3_repository_read_lpm_privileges(unsigned int be_index, u64 *lpar, | ||
988 | u64 *rights) | ||
989 | { | ||
990 | int result; | ||
991 | u64 node_id; | ||
992 | |||
993 | *lpar = 0; | ||
994 | *rights = 0; | ||
995 | result = ps3_repository_read_be_node_id(be_index, &node_id); | ||
996 | return result ? result | ||
997 | : read_node(PS3_LPAR_ID_PME, | ||
998 | make_first_field("be", 0), | ||
999 | node_id, | ||
1000 | make_field("lpm", 0), | ||
1001 | make_field("priv", 0), | ||
1002 | lpar, rights); | ||
1003 | } | ||
1004 | |||
905 | #if defined(DEBUG) | 1005 | #if defined(DEBUG) |
906 | 1006 | ||
907 | int ps3_repository_dump_resource_info(const struct ps3_repository_device *repo) | 1007 | int ps3_repository_dump_resource_info(const struct ps3_repository_device *repo) |
@@ -1034,7 +1134,7 @@ static int dump_device_info(struct ps3_repository_device *repo, | |||
1034 | continue; | 1134 | continue; |
1035 | } | 1135 | } |
1036 | 1136 | ||
1037 | pr_debug("%s:%d (%u:%u): dev_type %u, dev_id %u\n", __func__, | 1137 | pr_debug("%s:%d (%u:%u): dev_type %u, dev_id %lu\n", __func__, |
1038 | __LINE__, repo->bus_index, repo->dev_index, | 1138 | __LINE__, repo->bus_index, repo->dev_index, |
1039 | repo->dev_type, repo->dev_id); | 1139 | repo->dev_type, repo->dev_id); |
1040 | 1140 | ||
@@ -1091,7 +1191,7 @@ int ps3_repository_dump_bus_info(void) | |||
1091 | continue; | 1191 | continue; |
1092 | } | 1192 | } |
1093 | 1193 | ||
1094 | pr_debug("%s:%d bus_%u: bus_type %u, bus_id %u, num_dev %u\n", | 1194 | pr_debug("%s:%d bus_%u: bus_type %u, bus_id %lu, num_dev %u\n", |
1095 | __func__, __LINE__, repo.bus_index, repo.bus_type, | 1195 | __func__, __LINE__, repo.bus_index, repo.bus_type, |
1096 | repo.bus_id, num_dev); | 1196 | repo.bus_id, num_dev); |
1097 | 1197 | ||
diff --git a/arch/powerpc/platforms/ps3/spu.c b/arch/powerpc/platforms/ps3/spu.c index d1630a074acf..5ad41189b494 100644 --- a/arch/powerpc/platforms/ps3/spu.c +++ b/arch/powerpc/platforms/ps3/spu.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <asm/spu_priv1.h> | 28 | #include <asm/spu_priv1.h> |
29 | #include <asm/lv1call.h> | 29 | #include <asm/lv1call.h> |
30 | 30 | ||
31 | #include "../cell/spufs/spufs.h" | ||
31 | #include "platform.h" | 32 | #include "platform.h" |
32 | 33 | ||
33 | /* spu_management_ops */ | 34 | /* spu_management_ops */ |
@@ -419,10 +420,34 @@ static int ps3_init_affinity(void) | |||
419 | return 0; | 420 | return 0; |
420 | } | 421 | } |
421 | 422 | ||
423 | /** | ||
424 | * ps3_enable_spu - Enable SPU run control. | ||
425 | * | ||
426 | * An outstanding enhancement for the PS3 would be to add a guard to check | ||
427 | * for incorrect access to the spu problem state when the spu context is | ||
428 | * disabled. This check could be implemented with a flag added to the spu | ||
429 | * context that would inhibit mapping problem state pages, and a routine | ||
430 | * to unmap spu problem state pages. When the spu is enabled with | ||
431 | * ps3_enable_spu() the flag would be set allowing pages to be mapped, | ||
432 | * and when the spu is disabled with ps3_disable_spu() the flag would be | ||
433 | * cleared and the mapped problem state pages would be unmapped. | ||
434 | */ | ||
435 | |||
436 | static void ps3_enable_spu(struct spu_context *ctx) | ||
437 | { | ||
438 | } | ||
439 | |||
440 | static void ps3_disable_spu(struct spu_context *ctx) | ||
441 | { | ||
442 | ctx->ops->runcntl_stop(ctx); | ||
443 | } | ||
444 | |||
422 | const struct spu_management_ops spu_management_ps3_ops = { | 445 | const struct spu_management_ops spu_management_ps3_ops = { |
423 | .enumerate_spus = ps3_enumerate_spus, | 446 | .enumerate_spus = ps3_enumerate_spus, |
424 | .create_spu = ps3_create_spu, | 447 | .create_spu = ps3_create_spu, |
425 | .destroy_spu = ps3_destroy_spu, | 448 | .destroy_spu = ps3_destroy_spu, |
449 | .enable_spu = ps3_enable_spu, | ||
450 | .disable_spu = ps3_disable_spu, | ||
426 | .init_affinity = ps3_init_affinity, | 451 | .init_affinity = ps3_init_affinity, |
427 | }; | 452 | }; |
428 | 453 | ||
@@ -505,8 +530,6 @@ static void mfc_sr1_set(struct spu *spu, u64 sr1) | |||
505 | static const u64 allowed = ~(MFC_STATE1_LOCAL_STORAGE_DECODE_MASK | 530 | static const u64 allowed = ~(MFC_STATE1_LOCAL_STORAGE_DECODE_MASK |
506 | | MFC_STATE1_PROBLEM_STATE_MASK); | 531 | | MFC_STATE1_PROBLEM_STATE_MASK); |
507 | 532 | ||
508 | sr1 |= MFC_STATE1_MASTER_RUN_CONTROL_MASK; | ||
509 | |||
510 | BUG_ON((sr1 & allowed) != (spu_pdata(spu)->cache.sr1 & allowed)); | 533 | BUG_ON((sr1 & allowed) != (spu_pdata(spu)->cache.sr1 & allowed)); |
511 | 534 | ||
512 | spu_pdata(spu)->cache.sr1 = sr1; | 535 | spu_pdata(spu)->cache.sr1 = sr1; |
diff --git a/arch/powerpc/platforms/ps3/system-bus.c b/arch/powerpc/platforms/ps3/system-bus.c index 6405f4a36763..43c493fca2d0 100644 --- a/arch/powerpc/platforms/ps3/system-bus.c +++ b/arch/powerpc/platforms/ps3/system-bus.c | |||
@@ -42,8 +42,8 @@ struct { | |||
42 | int gpu; | 42 | int gpu; |
43 | } static usage_hack; | 43 | } static usage_hack; |
44 | 44 | ||
45 | static int ps3_is_device(struct ps3_system_bus_device *dev, | 45 | static int ps3_is_device(struct ps3_system_bus_device *dev, u64 bus_id, |
46 | unsigned int bus_id, unsigned int dev_id) | 46 | u64 dev_id) |
47 | { | 47 | { |
48 | return dev->bus_id == bus_id && dev->dev_id == dev_id; | 48 | return dev->bus_id == bus_id && dev->dev_id == dev_id; |
49 | } | 49 | } |
@@ -182,8 +182,8 @@ int ps3_open_hv_device(struct ps3_system_bus_device *dev) | |||
182 | case PS3_MATCH_ID_SYSTEM_MANAGER: | 182 | case PS3_MATCH_ID_SYSTEM_MANAGER: |
183 | pr_debug("%s:%d: unsupported match_id: %u\n", __func__, | 183 | pr_debug("%s:%d: unsupported match_id: %u\n", __func__, |
184 | __LINE__, dev->match_id); | 184 | __LINE__, dev->match_id); |
185 | pr_debug("%s:%d: bus_id: %u\n", __func__, | 185 | pr_debug("%s:%d: bus_id: %lu\n", __func__, __LINE__, |
186 | __LINE__, dev->bus_id); | 186 | dev->bus_id); |
187 | BUG(); | 187 | BUG(); |
188 | return -EINVAL; | 188 | return -EINVAL; |
189 | 189 | ||
@@ -220,8 +220,8 @@ int ps3_close_hv_device(struct ps3_system_bus_device *dev) | |||
220 | case PS3_MATCH_ID_SYSTEM_MANAGER: | 220 | case PS3_MATCH_ID_SYSTEM_MANAGER: |
221 | pr_debug("%s:%d: unsupported match_id: %u\n", __func__, | 221 | pr_debug("%s:%d: unsupported match_id: %u\n", __func__, |
222 | __LINE__, dev->match_id); | 222 | __LINE__, dev->match_id); |
223 | pr_debug("%s:%d: bus_id: %u\n", __func__, | 223 | pr_debug("%s:%d: bus_id: %lu\n", __func__, __LINE__, |
224 | __LINE__, dev->bus_id); | 224 | dev->bus_id); |
225 | BUG(); | 225 | BUG(); |
226 | return -EINVAL; | 226 | return -EINVAL; |
227 | 227 | ||
@@ -240,7 +240,7 @@ EXPORT_SYMBOL_GPL(ps3_close_hv_device); | |||
240 | static void _dump_mmio_region(const struct ps3_mmio_region* r, | 240 | static void _dump_mmio_region(const struct ps3_mmio_region* r, |
241 | const char* func, int line) | 241 | const char* func, int line) |
242 | { | 242 | { |
243 | pr_debug("%s:%d: dev %u:%u\n", func, line, r->dev->bus_id, | 243 | pr_debug("%s:%d: dev %lu:%lu\n", func, line, r->dev->bus_id, |
244 | r->dev->dev_id); | 244 | r->dev->dev_id); |
245 | pr_debug("%s:%d: bus_addr %lxh\n", func, line, r->bus_addr); | 245 | pr_debug("%s:%d: bus_addr %lxh\n", func, line, r->bus_addr); |
246 | pr_debug("%s:%d: len %lxh\n", func, line, r->len); | 246 | pr_debug("%s:%d: len %lxh\n", func, line, r->len); |
@@ -715,6 +715,7 @@ int ps3_system_bus_device_register(struct ps3_system_bus_device *dev) | |||
715 | static unsigned int dev_ioc0_count; | 715 | static unsigned int dev_ioc0_count; |
716 | static unsigned int dev_sb_count; | 716 | static unsigned int dev_sb_count; |
717 | static unsigned int dev_vuart_count; | 717 | static unsigned int dev_vuart_count; |
718 | static unsigned int dev_lpm_count; | ||
718 | 719 | ||
719 | if (!dev->core.parent) | 720 | if (!dev->core.parent) |
720 | dev->core.parent = &ps3_system_bus; | 721 | dev->core.parent = &ps3_system_bus; |
@@ -737,6 +738,10 @@ int ps3_system_bus_device_register(struct ps3_system_bus_device *dev) | |||
737 | snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), | 738 | snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), |
738 | "vuart_%02x", ++dev_vuart_count); | 739 | "vuart_%02x", ++dev_vuart_count); |
739 | break; | 740 | break; |
741 | case PS3_DEVICE_TYPE_LPM: | ||
742 | snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), | ||
743 | "lpm_%02x", ++dev_lpm_count); | ||
744 | break; | ||
740 | default: | 745 | default: |
741 | BUG(); | 746 | BUG(); |
742 | }; | 747 | }; |
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index fb3d636e088b..9eb539ee5f9a 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c | |||
@@ -29,6 +29,8 @@ | |||
29 | #include <linux/rbtree.h> | 29 | #include <linux/rbtree.h> |
30 | #include <linux/seq_file.h> | 30 | #include <linux/seq_file.h> |
31 | #include <linux/spinlock.h> | 31 | #include <linux/spinlock.h> |
32 | #include <linux/of.h> | ||
33 | |||
32 | #include <asm/atomic.h> | 34 | #include <asm/atomic.h> |
33 | #include <asm/eeh.h> | 35 | #include <asm/eeh.h> |
34 | #include <asm/eeh_event.h> | 36 | #include <asm/eeh_event.h> |
@@ -169,7 +171,6 @@ static void rtas_slot_error_detail(struct pci_dn *pdn, int severity, | |||
169 | */ | 171 | */ |
170 | static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len) | 172 | static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len) |
171 | { | 173 | { |
172 | struct device_node *dn; | ||
173 | struct pci_dev *dev = pdn->pcidev; | 174 | struct pci_dev *dev = pdn->pcidev; |
174 | u32 cfg; | 175 | u32 cfg; |
175 | int cap, i; | 176 | int cap, i; |
@@ -243,12 +244,12 @@ static size_t gather_pci_data(struct pci_dn *pdn, char * buf, size_t len) | |||
243 | 244 | ||
244 | /* Gather status on devices under the bridge */ | 245 | /* Gather status on devices under the bridge */ |
245 | if (dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) { | 246 | if (dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) { |
246 | dn = pdn->node->child; | 247 | struct device_node *dn; |
247 | while (dn) { | 248 | |
249 | for_each_child_of_node(pdn->node, dn) { | ||
248 | pdn = PCI_DN(dn); | 250 | pdn = PCI_DN(dn); |
249 | if (pdn) | 251 | if (pdn) |
250 | n += gather_pci_data(pdn, buf+n, len-n); | 252 | n += gather_pci_data(pdn, buf+n, len-n); |
251 | dn = dn->sibling; | ||
252 | } | 253 | } |
253 | } | 254 | } |
254 | 255 | ||
@@ -372,7 +373,7 @@ struct device_node * find_device_pe(struct device_node *dn) | |||
372 | return dn; | 373 | return dn; |
373 | } | 374 | } |
374 | 375 | ||
375 | /** Mark all devices that are peers of this device as failed. | 376 | /** Mark all devices that are children of this device as failed. |
376 | * Mark the device driver too, so that it can see the failure | 377 | * Mark the device driver too, so that it can see the failure |
377 | * immediately; this is critical, since some drivers poll | 378 | * immediately; this is critical, since some drivers poll |
378 | * status registers in interrupts ... If a driver is polling, | 379 | * status registers in interrupts ... If a driver is polling, |
@@ -380,9 +381,11 @@ struct device_node * find_device_pe(struct device_node *dn) | |||
380 | * an interrupt context, which is bad. | 381 | * an interrupt context, which is bad. |
381 | */ | 382 | */ |
382 | 383 | ||
383 | static void __eeh_mark_slot (struct device_node *dn, int mode_flag) | 384 | static void __eeh_mark_slot(struct device_node *parent, int mode_flag) |
384 | { | 385 | { |
385 | while (dn) { | 386 | struct device_node *dn; |
387 | |||
388 | for_each_child_of_node(parent, dn) { | ||
386 | if (PCI_DN(dn)) { | 389 | if (PCI_DN(dn)) { |
387 | /* Mark the pci device driver too */ | 390 | /* Mark the pci device driver too */ |
388 | struct pci_dev *dev = PCI_DN(dn)->pcidev; | 391 | struct pci_dev *dev = PCI_DN(dn)->pcidev; |
@@ -392,10 +395,8 @@ static void __eeh_mark_slot (struct device_node *dn, int mode_flag) | |||
392 | if (dev && dev->driver) | 395 | if (dev && dev->driver) |
393 | dev->error_state = pci_channel_io_frozen; | 396 | dev->error_state = pci_channel_io_frozen; |
394 | 397 | ||
395 | if (dn->child) | 398 | __eeh_mark_slot(dn, mode_flag); |
396 | __eeh_mark_slot (dn->child, mode_flag); | ||
397 | } | 399 | } |
398 | dn = dn->sibling; | ||
399 | } | 400 | } |
400 | } | 401 | } |
401 | 402 | ||
@@ -415,19 +416,19 @@ void eeh_mark_slot (struct device_node *dn, int mode_flag) | |||
415 | if (dev) | 416 | if (dev) |
416 | dev->error_state = pci_channel_io_frozen; | 417 | dev->error_state = pci_channel_io_frozen; |
417 | 418 | ||
418 | __eeh_mark_slot (dn->child, mode_flag); | 419 | __eeh_mark_slot(dn, mode_flag); |
419 | } | 420 | } |
420 | 421 | ||
421 | static void __eeh_clear_slot (struct device_node *dn, int mode_flag) | 422 | static void __eeh_clear_slot(struct device_node *parent, int mode_flag) |
422 | { | 423 | { |
423 | while (dn) { | 424 | struct device_node *dn; |
425 | |||
426 | for_each_child_of_node(parent, dn) { | ||
424 | if (PCI_DN(dn)) { | 427 | if (PCI_DN(dn)) { |
425 | PCI_DN(dn)->eeh_mode &= ~mode_flag; | 428 | PCI_DN(dn)->eeh_mode &= ~mode_flag; |
426 | PCI_DN(dn)->eeh_check_count = 0; | 429 | PCI_DN(dn)->eeh_check_count = 0; |
427 | if (dn->child) | 430 | __eeh_clear_slot(dn, mode_flag); |
428 | __eeh_clear_slot (dn->child, mode_flag); | ||
429 | } | 431 | } |
430 | dn = dn->sibling; | ||
431 | } | 432 | } |
432 | } | 433 | } |
433 | 434 | ||
@@ -444,7 +445,7 @@ void eeh_clear_slot (struct device_node *dn, int mode_flag) | |||
444 | 445 | ||
445 | PCI_DN(dn)->eeh_mode &= ~mode_flag; | 446 | PCI_DN(dn)->eeh_mode &= ~mode_flag; |
446 | PCI_DN(dn)->eeh_check_count = 0; | 447 | PCI_DN(dn)->eeh_check_count = 0; |
447 | __eeh_clear_slot (dn->child, mode_flag); | 448 | __eeh_clear_slot(dn, mode_flag); |
448 | spin_unlock_irqrestore(&confirm_error_lock, flags); | 449 | spin_unlock_irqrestore(&confirm_error_lock, flags); |
449 | } | 450 | } |
450 | 451 | ||
@@ -480,6 +481,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) | |||
480 | no_dn++; | 481 | no_dn++; |
481 | return 0; | 482 | return 0; |
482 | } | 483 | } |
484 | dn = find_device_pe(dn); | ||
483 | pdn = PCI_DN(dn); | 485 | pdn = PCI_DN(dn); |
484 | 486 | ||
485 | /* Access to IO BARs might get this far and still not want checking. */ | 487 | /* Access to IO BARs might get this far and still not want checking. */ |
@@ -545,7 +547,7 @@ int eeh_dn_check_failure(struct device_node *dn, struct pci_dev *dev) | |||
545 | 547 | ||
546 | /* Note that config-io to empty slots may fail; | 548 | /* Note that config-io to empty slots may fail; |
547 | * they are empty when they don't have children. */ | 549 | * they are empty when they don't have children. */ |
548 | if ((rets[0] == 5) && (dn->child == NULL)) { | 550 | if ((rets[0] == 5) && (rets[2] == 0) && (dn->child == NULL)) { |
549 | false_positives++; | 551 | false_positives++; |
550 | pdn->eeh_false_positives ++; | 552 | pdn->eeh_false_positives ++; |
551 | rc = 0; | 553 | rc = 0; |
@@ -848,11 +850,8 @@ void eeh_restore_bars(struct pci_dn *pdn) | |||
848 | if ((pdn->eeh_mode & EEH_MODE_SUPPORTED) && !IS_BRIDGE(pdn->class_code)) | 850 | if ((pdn->eeh_mode & EEH_MODE_SUPPORTED) && !IS_BRIDGE(pdn->class_code)) |
849 | __restore_bars (pdn); | 851 | __restore_bars (pdn); |
850 | 852 | ||
851 | dn = pdn->node->child; | 853 | for_each_child_of_node(pdn->node, dn) |
852 | while (dn) { | ||
853 | eeh_restore_bars (PCI_DN(dn)); | 854 | eeh_restore_bars (PCI_DN(dn)); |
854 | dn = dn->sibling; | ||
855 | } | ||
856 | } | 855 | } |
857 | 856 | ||
858 | /** | 857 | /** |
@@ -1130,7 +1129,8 @@ static void eeh_add_device_early(struct device_node *dn) | |||
1130 | void eeh_add_device_tree_early(struct device_node *dn) | 1129 | void eeh_add_device_tree_early(struct device_node *dn) |
1131 | { | 1130 | { |
1132 | struct device_node *sib; | 1131 | struct device_node *sib; |
1133 | for (sib = dn->child; sib; sib = sib->sibling) | 1132 | |
1133 | for_each_child_of_node(dn, sib) | ||
1134 | eeh_add_device_tree_early(sib); | 1134 | eeh_add_device_tree_early(sib); |
1135 | eeh_add_device_early(dn); | 1135 | eeh_add_device_early(dn); |
1136 | } | 1136 | } |
diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c index 57e025e84ab4..68ea5eee39a8 100644 --- a/arch/powerpc/platforms/pseries/eeh_driver.c +++ b/arch/powerpc/platforms/pseries/eeh_driver.c | |||
@@ -310,8 +310,6 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event) | |||
310 | const char *location, *pci_str, *drv_str; | 310 | const char *location, *pci_str, *drv_str; |
311 | 311 | ||
312 | frozen_dn = find_device_pe(event->dn); | 312 | frozen_dn = find_device_pe(event->dn); |
313 | frozen_bus = pcibios_find_pci_bus(frozen_dn); | ||
314 | |||
315 | if (!frozen_dn) { | 313 | if (!frozen_dn) { |
316 | 314 | ||
317 | location = of_get_property(event->dn, "ibm,loc-code", NULL); | 315 | location = of_get_property(event->dn, "ibm,loc-code", NULL); |
@@ -321,6 +319,8 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event) | |||
321 | location, pci_name(event->dev)); | 319 | location, pci_name(event->dev)); |
322 | return NULL; | 320 | return NULL; |
323 | } | 321 | } |
322 | |||
323 | frozen_bus = pcibios_find_pci_bus(frozen_dn); | ||
324 | location = of_get_property(frozen_dn, "ibm,loc-code", NULL); | 324 | location = of_get_property(frozen_dn, "ibm,loc-code", NULL); |
325 | location = location ? location : "unknown"; | 325 | location = location ? location : "unknown"; |
326 | 326 | ||
@@ -354,13 +354,6 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event) | |||
354 | if (frozen_pdn->eeh_freeze_count > EEH_MAX_ALLOWED_FREEZES) | 354 | if (frozen_pdn->eeh_freeze_count > EEH_MAX_ALLOWED_FREEZES) |
355 | goto excess_failures; | 355 | goto excess_failures; |
356 | 356 | ||
357 | /* Get the current PCI slot state. */ | ||
358 | rc = eeh_wait_for_slot_status (frozen_pdn, MAX_WAIT_FOR_RECOVERY*1000); | ||
359 | if (rc < 0) { | ||
360 | printk(KERN_WARNING "EEH: Permanent failure\n"); | ||
361 | goto hard_fail; | ||
362 | } | ||
363 | |||
364 | printk(KERN_WARNING | 357 | printk(KERN_WARNING |
365 | "EEH: This PCI device has failed %d times in the last hour:\n", | 358 | "EEH: This PCI device has failed %d times in the last hour:\n", |
366 | frozen_pdn->eeh_freeze_count); | 359 | frozen_pdn->eeh_freeze_count); |
@@ -376,6 +369,14 @@ struct pci_dn * handle_eeh_events (struct eeh_event *event) | |||
376 | */ | 369 | */ |
377 | pci_walk_bus(frozen_bus, eeh_report_error, &result); | 370 | pci_walk_bus(frozen_bus, eeh_report_error, &result); |
378 | 371 | ||
372 | /* Get the current PCI slot state. This can take a long time, | ||
373 | * sometimes over 3 seconds for certain systems. */ | ||
374 | rc = eeh_wait_for_slot_status (frozen_pdn, MAX_WAIT_FOR_RECOVERY*1000); | ||
375 | if (rc < 0) { | ||
376 | printk(KERN_WARNING "EEH: Permanent failure\n"); | ||
377 | goto hard_fail; | ||
378 | } | ||
379 | |||
379 | /* Since rtas may enable MMIO when posting the error log, | 380 | /* Since rtas may enable MMIO when posting the error log, |
380 | * don't post the error log until after all dev drivers | 381 | * don't post the error log until after all dev drivers |
381 | * have been informed. | 382 | * have been informed. |
diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index be17d2395072..a65c76308201 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c | |||
@@ -251,7 +251,7 @@ static void iommu_table_setparms(struct pci_controller *phb, | |||
251 | const unsigned long *basep; | 251 | const unsigned long *basep; |
252 | const u32 *sizep; | 252 | const u32 *sizep; |
253 | 253 | ||
254 | node = (struct device_node *)phb->arch_data; | 254 | node = phb->dn; |
255 | 255 | ||
256 | basep = of_get_property(node, "linux,tce-base", NULL); | 256 | basep = of_get_property(node, "linux,tce-base", NULL); |
257 | sizep = of_get_property(node, "linux,tce-size", NULL); | 257 | sizep = of_get_property(node, "linux,tce-size", NULL); |
@@ -296,11 +296,12 @@ static void iommu_table_setparms(struct pci_controller *phb, | |||
296 | static void iommu_table_setparms_lpar(struct pci_controller *phb, | 296 | static void iommu_table_setparms_lpar(struct pci_controller *phb, |
297 | struct device_node *dn, | 297 | struct device_node *dn, |
298 | struct iommu_table *tbl, | 298 | struct iommu_table *tbl, |
299 | const void *dma_window) | 299 | const void *dma_window, |
300 | int bussubno) | ||
300 | { | 301 | { |
301 | unsigned long offset, size; | 302 | unsigned long offset, size; |
302 | 303 | ||
303 | tbl->it_busno = PCI_DN(dn)->bussubno; | 304 | tbl->it_busno = bussubno; |
304 | of_parse_dma_window(dn, dma_window, &tbl->it_index, &offset, &size); | 305 | of_parse_dma_window(dn, dma_window, &tbl->it_index, &offset, &size); |
305 | 306 | ||
306 | tbl->it_base = 0; | 307 | tbl->it_base = 0; |
@@ -420,17 +421,10 @@ static void pci_dma_bus_setup_pSeriesLP(struct pci_bus *bus) | |||
420 | pdn->full_name, ppci->iommu_table); | 421 | pdn->full_name, ppci->iommu_table); |
421 | 422 | ||
422 | if (!ppci->iommu_table) { | 423 | if (!ppci->iommu_table) { |
423 | /* Bussubno hasn't been copied yet. | ||
424 | * Do it now because iommu_table_setparms_lpar needs it. | ||
425 | */ | ||
426 | |||
427 | ppci->bussubno = bus->number; | ||
428 | |||
429 | tbl = kmalloc_node(sizeof(struct iommu_table), GFP_KERNEL, | 424 | tbl = kmalloc_node(sizeof(struct iommu_table), GFP_KERNEL, |
430 | ppci->phb->node); | 425 | ppci->phb->node); |
431 | 426 | iommu_table_setparms_lpar(ppci->phb, pdn, tbl, dma_window, | |
432 | iommu_table_setparms_lpar(ppci->phb, pdn, tbl, dma_window); | 427 | bus->number); |
433 | |||
434 | ppci->iommu_table = iommu_init_table(tbl, ppci->phb->node); | 428 | ppci->iommu_table = iommu_init_table(tbl, ppci->phb->node); |
435 | DBG(" created table: %p\n", ppci->iommu_table); | 429 | DBG(" created table: %p\n", ppci->iommu_table); |
436 | } | 430 | } |
@@ -523,14 +517,10 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev) | |||
523 | 517 | ||
524 | pci = PCI_DN(pdn); | 518 | pci = PCI_DN(pdn); |
525 | if (!pci->iommu_table) { | 519 | if (!pci->iommu_table) { |
526 | /* iommu_table_setparms_lpar needs bussubno. */ | ||
527 | pci->bussubno = pci->phb->bus->number; | ||
528 | |||
529 | tbl = kmalloc_node(sizeof(struct iommu_table), GFP_KERNEL, | 520 | tbl = kmalloc_node(sizeof(struct iommu_table), GFP_KERNEL, |
530 | pci->phb->node); | 521 | pci->phb->node); |
531 | 522 | iommu_table_setparms_lpar(pci->phb, pdn, tbl, dma_window, | |
532 | iommu_table_setparms_lpar(pci->phb, pdn, tbl, dma_window); | 523 | pci->phb->bus->number); |
533 | |||
534 | pci->iommu_table = iommu_init_table(tbl, pci->phb->node); | 524 | pci->iommu_table = iommu_init_table(tbl, pci->phb->node); |
535 | DBG(" created table: %p\n", pci->iommu_table); | 525 | DBG(" created table: %p\n", pci->iommu_table); |
536 | } else { | 526 | } else { |
@@ -556,7 +546,7 @@ static int iommu_reconfig_notifier(struct notifier_block *nb, unsigned long acti | |||
556 | case PSERIES_RECONFIG_REMOVE: | 546 | case PSERIES_RECONFIG_REMOVE: |
557 | if (pci && pci->iommu_table && | 547 | if (pci && pci->iommu_table && |
558 | of_get_property(np, "ibm,dma-window", NULL)) | 548 | of_get_property(np, "ibm,dma-window", NULL)) |
559 | iommu_free_table(np); | 549 | iommu_free_table(pci->iommu_table, np->full_name); |
560 | break; | 550 | break; |
561 | default: | 551 | default: |
562 | err = NOTIFY_DONE; | 552 | err = NOTIFY_DONE; |
diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c index 47f0e0857f0e..5a5a19e40bb4 100644 --- a/arch/powerpc/platforms/pseries/pci_dlpar.c +++ b/arch/powerpc/platforms/pseries/pci_dlpar.c | |||
@@ -83,7 +83,7 @@ EXPORT_SYMBOL_GPL(pcibios_remove_pci_devices); | |||
83 | 83 | ||
84 | /* Must be called before pci_bus_add_devices */ | 84 | /* Must be called before pci_bus_add_devices */ |
85 | void | 85 | void |
86 | pcibios_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus) | 86 | pcibios_fixup_new_pci_devices(struct pci_bus *bus) |
87 | { | 87 | { |
88 | struct pci_dev *dev; | 88 | struct pci_dev *dev; |
89 | 89 | ||
@@ -98,8 +98,6 @@ pcibios_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus) | |||
98 | /* Fill device archdata and setup iommu table */ | 98 | /* Fill device archdata and setup iommu table */ |
99 | pcibios_setup_new_device(dev); | 99 | pcibios_setup_new_device(dev); |
100 | 100 | ||
101 | if(fix_bus) | ||
102 | pcibios_fixup_device_resources(dev, bus); | ||
103 | pci_read_irq_line(dev); | 101 | pci_read_irq_line(dev); |
104 | for (i = 0; i < PCI_NUM_RESOURCES; i++) { | 102 | for (i = 0; i < PCI_NUM_RESOURCES; i++) { |
105 | struct resource *r = &dev->resource[i]; | 103 | struct resource *r = &dev->resource[i]; |
@@ -132,8 +130,8 @@ pcibios_pci_config_bridge(struct pci_dev *dev) | |||
132 | 130 | ||
133 | pci_scan_child_bus(child_bus); | 131 | pci_scan_child_bus(child_bus); |
134 | 132 | ||
135 | /* Fixup new pci devices without touching bus struct */ | 133 | /* Fixup new pci devices */ |
136 | pcibios_fixup_new_pci_devices(child_bus, 0); | 134 | pcibios_fixup_new_pci_devices(child_bus); |
137 | 135 | ||
138 | /* Make the discovered devices available */ | 136 | /* Make the discovered devices available */ |
139 | pci_bus_add_devices(child_bus); | 137 | pci_bus_add_devices(child_bus); |
@@ -169,7 +167,7 @@ pcibios_add_pci_devices(struct pci_bus * bus) | |||
169 | /* use ofdt-based probe */ | 167 | /* use ofdt-based probe */ |
170 | of_scan_bus(dn, bus); | 168 | of_scan_bus(dn, bus); |
171 | if (!list_empty(&bus->devices)) { | 169 | if (!list_empty(&bus->devices)) { |
172 | pcibios_fixup_new_pci_devices(bus, 0); | 170 | pcibios_fixup_new_pci_devices(bus); |
173 | pci_bus_add_devices(bus); | 171 | pci_bus_add_devices(bus); |
174 | eeh_add_device_tree_late(bus); | 172 | eeh_add_device_tree_late(bus); |
175 | } | 173 | } |
@@ -178,7 +176,7 @@ pcibios_add_pci_devices(struct pci_bus * bus) | |||
178 | slotno = PCI_SLOT(PCI_DN(dn->child)->devfn); | 176 | slotno = PCI_SLOT(PCI_DN(dn->child)->devfn); |
179 | num = pci_scan_slot(bus, PCI_DEVFN(slotno, 0)); | 177 | num = pci_scan_slot(bus, PCI_DEVFN(slotno, 0)); |
180 | if (num) { | 178 | if (num) { |
181 | pcibios_fixup_new_pci_devices(bus, 1); | 179 | pcibios_fixup_new_pci_devices(bus); |
182 | pci_bus_add_devices(bus); | 180 | pci_bus_add_devices(bus); |
183 | eeh_add_device_tree_late(bus); | 181 | eeh_add_device_tree_late(bus); |
184 | } | 182 | } |
@@ -208,7 +206,7 @@ struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn) | |||
208 | eeh_add_device_tree_early(dn); | 206 | eeh_add_device_tree_early(dn); |
209 | 207 | ||
210 | scan_phb(phb); | 208 | scan_phb(phb); |
211 | pcibios_fixup_new_pci_devices(phb->bus, 0); | 209 | pcibios_fixup_new_pci_devices(phb->bus); |
212 | pci_bus_add_devices(phb->bus); | 210 | pci_bus_add_devices(phb->bus); |
213 | eeh_add_device_tree_late(phb->bus); | 211 | eeh_add_device_tree_late(phb->bus); |
214 | 212 | ||
diff --git a/arch/powerpc/platforms/pseries/plpar_wrappers.h b/arch/powerpc/platforms/pseries/plpar_wrappers.h index d003c80fa31d..d8680b589dc9 100644 --- a/arch/powerpc/platforms/pseries/plpar_wrappers.h +++ b/arch/powerpc/platforms/pseries/plpar_wrappers.h | |||
@@ -8,11 +8,6 @@ static inline long poll_pending(void) | |||
8 | return plpar_hcall_norets(H_POLL_PENDING); | 8 | return plpar_hcall_norets(H_POLL_PENDING); |
9 | } | 9 | } |
10 | 10 | ||
11 | static inline long prod_processor(void) | ||
12 | { | ||
13 | return plpar_hcall_norets(H_PROD); | ||
14 | } | ||
15 | |||
16 | static inline long cede_processor(void) | 11 | static inline long cede_processor(void) |
17 | { | 12 | { |
18 | return plpar_hcall_norets(H_CEDE); | 13 | return plpar_hcall_norets(H_CEDE); |
diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c index 116305b22a2b..ea4c65917a64 100644 --- a/arch/powerpc/platforms/pseries/smp.c +++ b/arch/powerpc/platforms/pseries/smp.c | |||
@@ -46,6 +46,7 @@ | |||
46 | #include <asm/pSeries_reconfig.h> | 46 | #include <asm/pSeries_reconfig.h> |
47 | #include <asm/mpic.h> | 47 | #include <asm/mpic.h> |
48 | #include <asm/vdso_datapage.h> | 48 | #include <asm/vdso_datapage.h> |
49 | #include <asm/cputhreads.h> | ||
49 | 50 | ||
50 | #include "plpar_wrappers.h" | 51 | #include "plpar_wrappers.h" |
51 | #include "pseries.h" | 52 | #include "pseries.h" |
@@ -202,7 +203,7 @@ static int smp_pSeries_cpu_bootable(unsigned int nr) | |||
202 | */ | 203 | */ |
203 | if (system_state < SYSTEM_RUNNING && | 204 | if (system_state < SYSTEM_RUNNING && |
204 | cpu_has_feature(CPU_FTR_SMT) && | 205 | cpu_has_feature(CPU_FTR_SMT) && |
205 | !smt_enabled_at_boot && nr % 2 != 0) | 206 | !smt_enabled_at_boot && cpu_thread_in_core(nr) != 0) |
206 | return 0; | 207 | return 0; |
207 | 208 | ||
208 | return 1; | 209 | return 1; |
diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c index 66e7d68ffeb1..8f8dd9c3ca6b 100644 --- a/arch/powerpc/platforms/pseries/xics.c +++ b/arch/powerpc/platforms/pseries/xics.c | |||
@@ -87,19 +87,25 @@ static int ibm_int_off; | |||
87 | /* Direct HW low level accessors */ | 87 | /* Direct HW low level accessors */ |
88 | 88 | ||
89 | 89 | ||
90 | static inline unsigned int direct_xirr_info_get(int n_cpu) | 90 | static inline unsigned int direct_xirr_info_get(void) |
91 | { | 91 | { |
92 | return in_be32(&xics_per_cpu[n_cpu]->xirr.word); | 92 | int cpu = smp_processor_id(); |
93 | |||
94 | return in_be32(&xics_per_cpu[cpu]->xirr.word); | ||
93 | } | 95 | } |
94 | 96 | ||
95 | static inline void direct_xirr_info_set(int n_cpu, int value) | 97 | static inline void direct_xirr_info_set(int value) |
96 | { | 98 | { |
97 | out_be32(&xics_per_cpu[n_cpu]->xirr.word, value); | 99 | int cpu = smp_processor_id(); |
100 | |||
101 | out_be32(&xics_per_cpu[cpu]->xirr.word, value); | ||
98 | } | 102 | } |
99 | 103 | ||
100 | static inline void direct_cppr_info(int n_cpu, u8 value) | 104 | static inline void direct_cppr_info(u8 value) |
101 | { | 105 | { |
102 | out_8(&xics_per_cpu[n_cpu]->xirr.bytes[0], value); | 106 | int cpu = smp_processor_id(); |
107 | |||
108 | out_8(&xics_per_cpu[cpu]->xirr.bytes[0], value); | ||
103 | } | 109 | } |
104 | 110 | ||
105 | static inline void direct_qirr_info(int n_cpu, u8 value) | 111 | static inline void direct_qirr_info(int n_cpu, u8 value) |
@@ -111,7 +117,7 @@ static inline void direct_qirr_info(int n_cpu, u8 value) | |||
111 | /* LPAR low level accessors */ | 117 | /* LPAR low level accessors */ |
112 | 118 | ||
113 | 119 | ||
114 | static inline unsigned int lpar_xirr_info_get(int n_cpu) | 120 | static inline unsigned int lpar_xirr_info_get(void) |
115 | { | 121 | { |
116 | unsigned long lpar_rc; | 122 | unsigned long lpar_rc; |
117 | unsigned long return_value; | 123 | unsigned long return_value; |
@@ -122,7 +128,7 @@ static inline unsigned int lpar_xirr_info_get(int n_cpu) | |||
122 | return (unsigned int)return_value; | 128 | return (unsigned int)return_value; |
123 | } | 129 | } |
124 | 130 | ||
125 | static inline void lpar_xirr_info_set(int n_cpu, int value) | 131 | static inline void lpar_xirr_info_set(int value) |
126 | { | 132 | { |
127 | unsigned long lpar_rc; | 133 | unsigned long lpar_rc; |
128 | unsigned long val64 = value & 0xffffffff; | 134 | unsigned long val64 = value & 0xffffffff; |
@@ -133,7 +139,7 @@ static inline void lpar_xirr_info_set(int n_cpu, int value) | |||
133 | val64); | 139 | val64); |
134 | } | 140 | } |
135 | 141 | ||
136 | static inline void lpar_cppr_info(int n_cpu, u8 value) | 142 | static inline void lpar_cppr_info(u8 value) |
137 | { | 143 | { |
138 | unsigned long lpar_rc; | 144 | unsigned long lpar_rc; |
139 | 145 | ||
@@ -275,21 +281,19 @@ static unsigned int xics_startup(unsigned int virq) | |||
275 | 281 | ||
276 | static void xics_eoi_direct(unsigned int virq) | 282 | static void xics_eoi_direct(unsigned int virq) |
277 | { | 283 | { |
278 | int cpu = smp_processor_id(); | ||
279 | unsigned int irq = (unsigned int)irq_map[virq].hwirq; | 284 | unsigned int irq = (unsigned int)irq_map[virq].hwirq; |
280 | 285 | ||
281 | iosync(); | 286 | iosync(); |
282 | direct_xirr_info_set(cpu, (0xff << 24) | irq); | 287 | direct_xirr_info_set((0xff << 24) | irq); |
283 | } | 288 | } |
284 | 289 | ||
285 | 290 | ||
286 | static void xics_eoi_lpar(unsigned int virq) | 291 | static void xics_eoi_lpar(unsigned int virq) |
287 | { | 292 | { |
288 | int cpu = smp_processor_id(); | ||
289 | unsigned int irq = (unsigned int)irq_map[virq].hwirq; | 293 | unsigned int irq = (unsigned int)irq_map[virq].hwirq; |
290 | 294 | ||
291 | iosync(); | 295 | iosync(); |
292 | lpar_xirr_info_set(cpu, (0xff << 24) | irq); | 296 | lpar_xirr_info_set((0xff << 24) | irq); |
293 | } | 297 | } |
294 | 298 | ||
295 | static inline unsigned int xics_remap_irq(unsigned int vec) | 299 | static inline unsigned int xics_remap_irq(unsigned int vec) |
@@ -312,16 +316,12 @@ static inline unsigned int xics_remap_irq(unsigned int vec) | |||
312 | 316 | ||
313 | static unsigned int xics_get_irq_direct(void) | 317 | static unsigned int xics_get_irq_direct(void) |
314 | { | 318 | { |
315 | unsigned int cpu = smp_processor_id(); | 319 | return xics_remap_irq(direct_xirr_info_get()); |
316 | |||
317 | return xics_remap_irq(direct_xirr_info_get(cpu)); | ||
318 | } | 320 | } |
319 | 321 | ||
320 | static unsigned int xics_get_irq_lpar(void) | 322 | static unsigned int xics_get_irq_lpar(void) |
321 | { | 323 | { |
322 | unsigned int cpu = smp_processor_id(); | 324 | return xics_remap_irq(lpar_xirr_info_get()); |
323 | |||
324 | return xics_remap_irq(lpar_xirr_info_get(cpu)); | ||
325 | } | 325 | } |
326 | 326 | ||
327 | #ifdef CONFIG_SMP | 327 | #ifdef CONFIG_SMP |
@@ -387,12 +387,12 @@ void xics_cause_IPI(int cpu) | |||
387 | 387 | ||
388 | #endif /* CONFIG_SMP */ | 388 | #endif /* CONFIG_SMP */ |
389 | 389 | ||
390 | static void xics_set_cpu_priority(int cpu, unsigned char cppr) | 390 | static void xics_set_cpu_priority(unsigned char cppr) |
391 | { | 391 | { |
392 | if (firmware_has_feature(FW_FEATURE_LPAR)) | 392 | if (firmware_has_feature(FW_FEATURE_LPAR)) |
393 | lpar_cppr_info(cpu, cppr); | 393 | lpar_cppr_info(cppr); |
394 | else | 394 | else |
395 | direct_cppr_info(cpu, cppr); | 395 | direct_cppr_info(cppr); |
396 | iosync(); | 396 | iosync(); |
397 | } | 397 | } |
398 | 398 | ||
@@ -440,9 +440,7 @@ static void xics_set_affinity(unsigned int virq, cpumask_t cpumask) | |||
440 | 440 | ||
441 | void xics_setup_cpu(void) | 441 | void xics_setup_cpu(void) |
442 | { | 442 | { |
443 | int cpu = smp_processor_id(); | 443 | xics_set_cpu_priority(0xff); |
444 | |||
445 | xics_set_cpu_priority(cpu, 0xff); | ||
446 | 444 | ||
447 | /* | 445 | /* |
448 | * Put the calling processor into the GIQ. This is really only | 446 | * Put the calling processor into the GIQ. This is really only |
@@ -783,7 +781,7 @@ void xics_teardown_cpu(int secondary) | |||
783 | unsigned int ipi; | 781 | unsigned int ipi; |
784 | struct irq_desc *desc; | 782 | struct irq_desc *desc; |
785 | 783 | ||
786 | xics_set_cpu_priority(cpu, 0); | 784 | xics_set_cpu_priority(0); |
787 | 785 | ||
788 | /* | 786 | /* |
789 | * Clear IPI | 787 | * Clear IPI |
@@ -824,10 +822,11 @@ void xics_teardown_cpu(int secondary) | |||
824 | void xics_migrate_irqs_away(void) | 822 | void xics_migrate_irqs_away(void) |
825 | { | 823 | { |
826 | int status; | 824 | int status; |
827 | unsigned int irq, virq, cpu = smp_processor_id(); | 825 | int cpu = smp_processor_id(), hw_cpu = hard_smp_processor_id(); |
826 | unsigned int irq, virq; | ||
828 | 827 | ||
829 | /* Reject any interrupt that was queued to us... */ | 828 | /* Reject any interrupt that was queued to us... */ |
830 | xics_set_cpu_priority(cpu, 0); | 829 | xics_set_cpu_priority(0); |
831 | 830 | ||
832 | /* remove ourselves from the global interrupt queue */ | 831 | /* remove ourselves from the global interrupt queue */ |
833 | status = rtas_set_indicator_fast(GLOBAL_INTERRUPT_QUEUE, | 832 | status = rtas_set_indicator_fast(GLOBAL_INTERRUPT_QUEUE, |
@@ -835,7 +834,7 @@ void xics_migrate_irqs_away(void) | |||
835 | WARN_ON(status < 0); | 834 | WARN_ON(status < 0); |
836 | 835 | ||
837 | /* Allow IPIs again... */ | 836 | /* Allow IPIs again... */ |
838 | xics_set_cpu_priority(cpu, DEFAULT_PRIORITY); | 837 | xics_set_cpu_priority(DEFAULT_PRIORITY); |
839 | 838 | ||
840 | for_each_irq(virq) { | 839 | for_each_irq(virq) { |
841 | struct irq_desc *desc; | 840 | struct irq_desc *desc; |
@@ -874,7 +873,7 @@ void xics_migrate_irqs_away(void) | |||
874 | * The irq has to be migrated only in the single cpu | 873 | * The irq has to be migrated only in the single cpu |
875 | * case. | 874 | * case. |
876 | */ | 875 | */ |
877 | if (xics_status[0] != get_hard_smp_processor_id(cpu)) | 876 | if (xics_status[0] != hw_cpu) |
878 | goto unlock; | 877 | goto unlock; |
879 | 878 | ||
880 | printk(KERN_WARNING "IRQ %u affinity broken off cpu %u\n", | 879 | printk(KERN_WARNING "IRQ %u affinity broken off cpu %u\n", |
diff --git a/arch/powerpc/platforms/pseries/xics.h b/arch/powerpc/platforms/pseries/xics.h index db0ec3ba3ae2..9ffd809d29e2 100644 --- a/arch/powerpc/platforms/pseries/xics.h +++ b/arch/powerpc/platforms/pseries/xics.h | |||
@@ -21,9 +21,6 @@ extern void xics_cause_IPI(int cpu); | |||
21 | extern void xics_request_IPIs(void); | 21 | extern void xics_request_IPIs(void); |
22 | extern void xics_migrate_irqs_away(void); | 22 | extern void xics_migrate_irqs_away(void); |
23 | 23 | ||
24 | /* first argument is ignored for now*/ | ||
25 | void pSeriesLP_cppr_info(int n_cpu, u8 value); | ||
26 | |||
27 | struct xics_ipi_struct { | 24 | struct xics_ipi_struct { |
28 | volatile unsigned long value; | 25 | volatile unsigned long value; |
29 | } ____cacheline_aligned; | 26 | } ____cacheline_aligned; |