diff options
Diffstat (limited to 'arch/powerpc/platforms')
120 files changed, 8878 insertions, 2001 deletions
diff --git a/arch/powerpc/platforms/52xx/Makefile b/arch/powerpc/platforms/52xx/Makefile index a46184a0c750..07cdbcacf156 100644 --- a/arch/powerpc/platforms/52xx/Makefile +++ b/arch/powerpc/platforms/52xx/Makefile | |||
@@ -3,7 +3,8 @@ | |||
3 | # | 3 | # |
4 | ifeq ($(CONFIG_PPC_MERGE),y) | 4 | ifeq ($(CONFIG_PPC_MERGE),y) |
5 | obj-y += mpc52xx_pic.o mpc52xx_common.o | 5 | obj-y += mpc52xx_pic.o mpc52xx_common.o |
6 | obj-$(CONFIG_PCI) += mpc52xx_pci.o | ||
6 | endif | 7 | endif |
7 | 8 | ||
8 | obj-$(CONFIG_PPC_EFIKA) += efika-setup.o efika-pci.o | 9 | obj-$(CONFIG_PPC_EFIKA) += efika.o |
9 | obj-$(CONFIG_PPC_LITE5200) += lite5200.o | 10 | obj-$(CONFIG_PPC_LITE5200) += lite5200.o |
diff --git a/arch/powerpc/platforms/52xx/efika-pci.c b/arch/powerpc/platforms/52xx/efika-pci.c deleted file mode 100644 index 62e05b2a9227..000000000000 --- a/arch/powerpc/platforms/52xx/efika-pci.c +++ /dev/null | |||
@@ -1,119 +0,0 @@ | |||
1 | |||
2 | #include <linux/kernel.h> | ||
3 | #include <linux/pci.h> | ||
4 | #include <linux/string.h> | ||
5 | #include <linux/init.h> | ||
6 | |||
7 | #include <asm/io.h> | ||
8 | #include <asm/irq.h> | ||
9 | #include <asm/prom.h> | ||
10 | #include <asm/machdep.h> | ||
11 | #include <asm/sections.h> | ||
12 | #include <asm/pci-bridge.h> | ||
13 | #include <asm/rtas.h> | ||
14 | |||
15 | #include "efika.h" | ||
16 | |||
17 | #ifdef CONFIG_PCI | ||
18 | /* | ||
19 | * Access functions for PCI config space using RTAS calls. | ||
20 | */ | ||
21 | static int rtas_read_config(struct pci_bus *bus, unsigned int devfn, int offset, | ||
22 | int len, u32 * val) | ||
23 | { | ||
24 | struct pci_controller *hose = bus->sysdata; | ||
25 | unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8) | ||
26 | | (((bus->number - hose->first_busno) & 0xff) << 16) | ||
27 | | (hose->index << 24); | ||
28 | int ret = -1; | ||
29 | int rval; | ||
30 | |||
31 | rval = rtas_call(rtas_token("read-pci-config"), 2, 2, &ret, addr, len); | ||
32 | *val = ret; | ||
33 | return rval ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; | ||
34 | } | ||
35 | |||
36 | static int rtas_write_config(struct pci_bus *bus, unsigned int devfn, | ||
37 | int offset, int len, u32 val) | ||
38 | { | ||
39 | struct pci_controller *hose = bus->sysdata; | ||
40 | unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8) | ||
41 | | (((bus->number - hose->first_busno) & 0xff) << 16) | ||
42 | | (hose->index << 24); | ||
43 | int rval; | ||
44 | |||
45 | rval = rtas_call(rtas_token("write-pci-config"), 3, 1, NULL, | ||
46 | addr, len, val); | ||
47 | return rval ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; | ||
48 | } | ||
49 | |||
50 | static struct pci_ops rtas_pci_ops = { | ||
51 | rtas_read_config, | ||
52 | rtas_write_config | ||
53 | }; | ||
54 | |||
55 | void __init efika_pcisetup(void) | ||
56 | { | ||
57 | const int *bus_range; | ||
58 | int len; | ||
59 | struct pci_controller *hose; | ||
60 | struct device_node *root; | ||
61 | struct device_node *pcictrl; | ||
62 | |||
63 | root = of_find_node_by_path("/"); | ||
64 | if (root == NULL) { | ||
65 | printk(KERN_WARNING EFIKA_PLATFORM_NAME | ||
66 | ": Unable to find the root node\n"); | ||
67 | return; | ||
68 | } | ||
69 | |||
70 | for (pcictrl = NULL;;) { | ||
71 | pcictrl = of_get_next_child(root, pcictrl); | ||
72 | if ((pcictrl == NULL) || (strcmp(pcictrl->name, "pci") == 0)) | ||
73 | break; | ||
74 | } | ||
75 | |||
76 | of_node_put(root); | ||
77 | |||
78 | if (pcictrl == NULL) { | ||
79 | printk(KERN_WARNING EFIKA_PLATFORM_NAME | ||
80 | ": Unable to find the PCI bridge node\n"); | ||
81 | return; | ||
82 | } | ||
83 | |||
84 | bus_range = get_property(pcictrl, "bus-range", &len); | ||
85 | if (bus_range == NULL || len < 2 * sizeof(int)) { | ||
86 | printk(KERN_WARNING EFIKA_PLATFORM_NAME | ||
87 | ": Can't get bus-range for %s\n", pcictrl->full_name); | ||
88 | return; | ||
89 | } | ||
90 | |||
91 | if (bus_range[1] == bus_range[0]) | ||
92 | printk(KERN_INFO EFIKA_PLATFORM_NAME ": PCI bus %d", | ||
93 | bus_range[0]); | ||
94 | else | ||
95 | printk(KERN_INFO EFIKA_PLATFORM_NAME ": PCI buses %d..%d", | ||
96 | bus_range[0], bus_range[1]); | ||
97 | printk(" controlled by %s\n", pcictrl->full_name); | ||
98 | printk("\n"); | ||
99 | |||
100 | hose = pcibios_alloc_controller(); | ||
101 | if (!hose) { | ||
102 | printk(KERN_WARNING EFIKA_PLATFORM_NAME | ||
103 | ": Can't allocate PCI controller structure for %s\n", | ||
104 | pcictrl->full_name); | ||
105 | return; | ||
106 | } | ||
107 | |||
108 | hose->arch_data = of_node_get(pcictrl); | ||
109 | hose->first_busno = bus_range[0]; | ||
110 | hose->last_busno = bus_range[1]; | ||
111 | hose->ops = &rtas_pci_ops; | ||
112 | |||
113 | pci_process_bridge_OF_ranges(hose, pcictrl, 0); | ||
114 | } | ||
115 | |||
116 | #else | ||
117 | void __init efika_pcisetup(void) | ||
118 | {} | ||
119 | #endif | ||
diff --git a/arch/powerpc/platforms/52xx/efika-setup.c b/arch/powerpc/platforms/52xx/efika-setup.c deleted file mode 100644 index 110c980ed1e0..000000000000 --- a/arch/powerpc/platforms/52xx/efika-setup.c +++ /dev/null | |||
@@ -1,150 +0,0 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Efika 5K2 platform setup | ||
4 | * Some code really inspired from the lite5200b platform. | ||
5 | * | ||
6 | * Copyright (C) 2006 bplan GmbH | ||
7 | * | ||
8 | * This file is licensed under the terms of the GNU General Public License | ||
9 | * version 2. This program is licensed "as is" without any warranty of any | ||
10 | * kind, whether express or implied. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/errno.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <linux/reboot.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/utsrelease.h> | ||
20 | #include <linux/seq_file.h> | ||
21 | #include <linux/root_dev.h> | ||
22 | #include <linux/initrd.h> | ||
23 | #include <linux/timer.h> | ||
24 | #include <linux/pci.h> | ||
25 | |||
26 | #include <asm/pgtable.h> | ||
27 | #include <asm/prom.h> | ||
28 | #include <asm/time.h> | ||
29 | #include <asm/machdep.h> | ||
30 | #include <asm/rtas.h> | ||
31 | #include <asm/of_device.h> | ||
32 | #include <asm/of_platform.h> | ||
33 | #include <asm/mpc52xx.h> | ||
34 | |||
35 | #include "efika.h" | ||
36 | |||
37 | static void efika_show_cpuinfo(struct seq_file *m) | ||
38 | { | ||
39 | struct device_node *root; | ||
40 | const char *revision = NULL; | ||
41 | const char *codegendescription = NULL; | ||
42 | const char *codegenvendor = NULL; | ||
43 | |||
44 | root = of_find_node_by_path("/"); | ||
45 | if (root) { | ||
46 | revision = get_property(root, "revision", NULL); | ||
47 | codegendescription = | ||
48 | get_property(root, "CODEGEN,description", NULL); | ||
49 | codegenvendor = get_property(root, "CODEGEN,vendor", NULL); | ||
50 | |||
51 | of_node_put(root); | ||
52 | } | ||
53 | |||
54 | if (codegendescription) | ||
55 | seq_printf(m, "machine\t\t: %s\n", codegendescription); | ||
56 | else | ||
57 | seq_printf(m, "machine\t\t: Efika\n"); | ||
58 | |||
59 | if (revision) | ||
60 | seq_printf(m, "revision\t: %s\n", revision); | ||
61 | |||
62 | if (codegenvendor) | ||
63 | seq_printf(m, "vendor\t\t: %s\n", codegenvendor); | ||
64 | |||
65 | of_node_put(root); | ||
66 | } | ||
67 | |||
68 | static void __init efika_setup_arch(void) | ||
69 | { | ||
70 | rtas_initialize(); | ||
71 | |||
72 | #ifdef CONFIG_BLK_DEV_INITRD | ||
73 | initrd_below_start_ok = 1; | ||
74 | |||
75 | if (initrd_start) | ||
76 | ROOT_DEV = Root_RAM0; | ||
77 | else | ||
78 | #endif | ||
79 | ROOT_DEV = Root_SDA2; /* sda2 (sda1 is for the kernel) */ | ||
80 | |||
81 | efika_pcisetup(); | ||
82 | |||
83 | if (ppc_md.progress) | ||
84 | ppc_md.progress("Linux/PPC " UTS_RELEASE " runnung on Efika ;-)\n", 0x0); | ||
85 | } | ||
86 | |||
87 | static void __init efika_init(void) | ||
88 | { | ||
89 | struct device_node *np; | ||
90 | struct device_node *cnp = NULL; | ||
91 | const u32 *base; | ||
92 | |||
93 | /* Find every child of the SOC node and add it to of_platform */ | ||
94 | np = of_find_node_by_name(NULL, "builtin"); | ||
95 | if (np) { | ||
96 | char name[BUS_ID_SIZE]; | ||
97 | while ((cnp = of_get_next_child(np, cnp))) { | ||
98 | strcpy(name, cnp->name); | ||
99 | |||
100 | base = get_property(cnp, "reg", NULL); | ||
101 | if (base == NULL) | ||
102 | continue; | ||
103 | |||
104 | snprintf(name+strlen(name), BUS_ID_SIZE, "@%x", *base); | ||
105 | of_platform_device_create(cnp, name, NULL); | ||
106 | |||
107 | printk(KERN_INFO EFIKA_PLATFORM_NAME" : Added %s (type '%s' at '%s') to the known devices\n", name, cnp->type, cnp->full_name); | ||
108 | } | ||
109 | } | ||
110 | |||
111 | if (ppc_md.progress) | ||
112 | ppc_md.progress(" Have fun with your Efika! ", 0x7777); | ||
113 | } | ||
114 | |||
115 | static int __init efika_probe(void) | ||
116 | { | ||
117 | char *model = of_get_flat_dt_prop(of_get_flat_dt_root(), | ||
118 | "model", NULL); | ||
119 | |||
120 | if (model == NULL) | ||
121 | return 0; | ||
122 | if (strcmp(model, "EFIKA5K2")) | ||
123 | return 0; | ||
124 | |||
125 | ISA_DMA_THRESHOLD = ~0L; | ||
126 | DMA_MODE_READ = 0x44; | ||
127 | DMA_MODE_WRITE = 0x48; | ||
128 | |||
129 | return 1; | ||
130 | } | ||
131 | |||
132 | define_machine(efika) | ||
133 | { | ||
134 | .name = EFIKA_PLATFORM_NAME, | ||
135 | .probe = efika_probe, | ||
136 | .setup_arch = efika_setup_arch, | ||
137 | .init = efika_init, | ||
138 | .show_cpuinfo = efika_show_cpuinfo, | ||
139 | .init_IRQ = mpc52xx_init_irq, | ||
140 | .get_irq = mpc52xx_get_irq, | ||
141 | .restart = rtas_restart, | ||
142 | .power_off = rtas_power_off, | ||
143 | .halt = rtas_halt, | ||
144 | .set_rtc_time = rtas_set_rtc_time, | ||
145 | .get_rtc_time = rtas_get_rtc_time, | ||
146 | .progress = rtas_progress, | ||
147 | .get_boot_time = rtas_get_boot_time, | ||
148 | .calibrate_decr = generic_calibrate_decr, | ||
149 | .phys_mem_access_prot = pci_phys_mem_access_prot, | ||
150 | }; | ||
diff --git a/arch/powerpc/platforms/52xx/efika.c b/arch/powerpc/platforms/52xx/efika.c new file mode 100644 index 000000000000..8de034116681 --- /dev/null +++ b/arch/powerpc/platforms/52xx/efika.c | |||
@@ -0,0 +1,243 @@ | |||
1 | /* | ||
2 | * Efika 5K2 platform code | ||
3 | * Some code really inspired from the lite5200b platform. | ||
4 | * | ||
5 | * Copyright (C) 2006 bplan GmbH | ||
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 | |||
12 | #include <linux/errno.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/slab.h> | ||
15 | #include <linux/reboot.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/utsrelease.h> | ||
18 | #include <linux/seq_file.h> | ||
19 | #include <linux/string.h> | ||
20 | #include <linux/root_dev.h> | ||
21 | #include <linux/initrd.h> | ||
22 | #include <linux/timer.h> | ||
23 | #include <linux/pci.h> | ||
24 | |||
25 | #include <asm/io.h> | ||
26 | #include <asm/irq.h> | ||
27 | #include <asm/sections.h> | ||
28 | #include <asm/pci-bridge.h> | ||
29 | #include <asm/pgtable.h> | ||
30 | #include <asm/prom.h> | ||
31 | #include <asm/time.h> | ||
32 | #include <asm/machdep.h> | ||
33 | #include <asm/rtas.h> | ||
34 | #include <asm/of_device.h> | ||
35 | #include <asm/of_platform.h> | ||
36 | #include <asm/mpc52xx.h> | ||
37 | |||
38 | |||
39 | #define EFIKA_PLATFORM_NAME "Efika" | ||
40 | |||
41 | |||
42 | /* ------------------------------------------------------------------------ */ | ||
43 | /* PCI accesses thru RTAS */ | ||
44 | /* ------------------------------------------------------------------------ */ | ||
45 | |||
46 | #ifdef CONFIG_PCI | ||
47 | |||
48 | /* | ||
49 | * Access functions for PCI config space using RTAS calls. | ||
50 | */ | ||
51 | static int rtas_read_config(struct pci_bus *bus, unsigned int devfn, int offset, | ||
52 | int len, u32 * val) | ||
53 | { | ||
54 | struct pci_controller *hose = bus->sysdata; | ||
55 | unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8) | ||
56 | | (((bus->number - hose->first_busno) & 0xff) << 16) | ||
57 | | (hose->index << 24); | ||
58 | int ret = -1; | ||
59 | int rval; | ||
60 | |||
61 | rval = rtas_call(rtas_token("read-pci-config"), 2, 2, &ret, addr, len); | ||
62 | *val = ret; | ||
63 | return rval ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; | ||
64 | } | ||
65 | |||
66 | static int rtas_write_config(struct pci_bus *bus, unsigned int devfn, | ||
67 | int offset, int len, u32 val) | ||
68 | { | ||
69 | struct pci_controller *hose = bus->sysdata; | ||
70 | unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8) | ||
71 | | (((bus->number - hose->first_busno) & 0xff) << 16) | ||
72 | | (hose->index << 24); | ||
73 | int rval; | ||
74 | |||
75 | rval = rtas_call(rtas_token("write-pci-config"), 3, 1, NULL, | ||
76 | addr, len, val); | ||
77 | return rval ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; | ||
78 | } | ||
79 | |||
80 | static struct pci_ops rtas_pci_ops = { | ||
81 | rtas_read_config, | ||
82 | rtas_write_config | ||
83 | }; | ||
84 | |||
85 | |||
86 | void __init efika_pcisetup(void) | ||
87 | { | ||
88 | const int *bus_range; | ||
89 | int len; | ||
90 | struct pci_controller *hose; | ||
91 | struct device_node *root; | ||
92 | struct device_node *pcictrl; | ||
93 | |||
94 | root = of_find_node_by_path("/"); | ||
95 | if (root == NULL) { | ||
96 | printk(KERN_WARNING EFIKA_PLATFORM_NAME | ||
97 | ": Unable to find the root node\n"); | ||
98 | return; | ||
99 | } | ||
100 | |||
101 | for (pcictrl = NULL;;) { | ||
102 | pcictrl = of_get_next_child(root, pcictrl); | ||
103 | if ((pcictrl == NULL) || (strcmp(pcictrl->name, "pci") == 0)) | ||
104 | break; | ||
105 | } | ||
106 | |||
107 | of_node_put(root); | ||
108 | |||
109 | if (pcictrl == NULL) { | ||
110 | printk(KERN_WARNING EFIKA_PLATFORM_NAME | ||
111 | ": Unable to find the PCI bridge node\n"); | ||
112 | return; | ||
113 | } | ||
114 | |||
115 | bus_range = get_property(pcictrl, "bus-range", &len); | ||
116 | if (bus_range == NULL || len < 2 * sizeof(int)) { | ||
117 | printk(KERN_WARNING EFIKA_PLATFORM_NAME | ||
118 | ": Can't get bus-range for %s\n", pcictrl->full_name); | ||
119 | return; | ||
120 | } | ||
121 | |||
122 | if (bus_range[1] == bus_range[0]) | ||
123 | printk(KERN_INFO EFIKA_PLATFORM_NAME ": PCI bus %d", | ||
124 | bus_range[0]); | ||
125 | else | ||
126 | printk(KERN_INFO EFIKA_PLATFORM_NAME ": PCI buses %d..%d", | ||
127 | bus_range[0], bus_range[1]); | ||
128 | printk(" controlled by %s\n", pcictrl->full_name); | ||
129 | printk("\n"); | ||
130 | |||
131 | hose = pcibios_alloc_controller(); | ||
132 | if (!hose) { | ||
133 | printk(KERN_WARNING EFIKA_PLATFORM_NAME | ||
134 | ": Can't allocate PCI controller structure for %s\n", | ||
135 | pcictrl->full_name); | ||
136 | return; | ||
137 | } | ||
138 | |||
139 | hose->arch_data = of_node_get(pcictrl); | ||
140 | hose->first_busno = bus_range[0]; | ||
141 | hose->last_busno = bus_range[1]; | ||
142 | hose->ops = &rtas_pci_ops; | ||
143 | |||
144 | pci_process_bridge_OF_ranges(hose, pcictrl, 0); | ||
145 | } | ||
146 | |||
147 | #else | ||
148 | void __init efika_pcisetup(void) | ||
149 | {} | ||
150 | #endif | ||
151 | |||
152 | |||
153 | |||
154 | /* ------------------------------------------------------------------------ */ | ||
155 | /* Platform setup */ | ||
156 | /* ------------------------------------------------------------------------ */ | ||
157 | |||
158 | static void efika_show_cpuinfo(struct seq_file *m) | ||
159 | { | ||
160 | struct device_node *root; | ||
161 | const char *revision = NULL; | ||
162 | const char *codegendescription = NULL; | ||
163 | const char *codegenvendor = NULL; | ||
164 | |||
165 | root = of_find_node_by_path("/"); | ||
166 | if (!root) | ||
167 | return; | ||
168 | |||
169 | revision = get_property(root, "revision", NULL); | ||
170 | codegendescription = | ||
171 | get_property(root, "CODEGEN,description", NULL); | ||
172 | codegenvendor = get_property(root, "CODEGEN,vendor", NULL); | ||
173 | |||
174 | if (codegendescription) | ||
175 | seq_printf(m, "machine\t\t: %s\n", codegendescription); | ||
176 | else | ||
177 | seq_printf(m, "machine\t\t: Efika\n"); | ||
178 | |||
179 | if (revision) | ||
180 | seq_printf(m, "revision\t: %s\n", revision); | ||
181 | |||
182 | if (codegenvendor) | ||
183 | seq_printf(m, "vendor\t\t: %s\n", codegenvendor); | ||
184 | |||
185 | of_node_put(root); | ||
186 | } | ||
187 | |||
188 | static void __init efika_setup_arch(void) | ||
189 | { | ||
190 | rtas_initialize(); | ||
191 | |||
192 | #ifdef CONFIG_BLK_DEV_INITRD | ||
193 | initrd_below_start_ok = 1; | ||
194 | |||
195 | if (initrd_start) | ||
196 | ROOT_DEV = Root_RAM0; | ||
197 | else | ||
198 | #endif | ||
199 | ROOT_DEV = Root_SDA2; /* sda2 (sda1 is for the kernel) */ | ||
200 | |||
201 | efika_pcisetup(); | ||
202 | |||
203 | if (ppc_md.progress) | ||
204 | ppc_md.progress("Linux/PPC " UTS_RELEASE " running on Efika ;-)\n", 0x0); | ||
205 | } | ||
206 | |||
207 | static int __init efika_probe(void) | ||
208 | { | ||
209 | char *model = of_get_flat_dt_prop(of_get_flat_dt_root(), | ||
210 | "model", NULL); | ||
211 | |||
212 | if (model == NULL) | ||
213 | return 0; | ||
214 | if (strcmp(model, "EFIKA5K2")) | ||
215 | return 0; | ||
216 | |||
217 | ISA_DMA_THRESHOLD = ~0L; | ||
218 | DMA_MODE_READ = 0x44; | ||
219 | DMA_MODE_WRITE = 0x48; | ||
220 | |||
221 | return 1; | ||
222 | } | ||
223 | |||
224 | define_machine(efika) | ||
225 | { | ||
226 | .name = EFIKA_PLATFORM_NAME, | ||
227 | .probe = efika_probe, | ||
228 | .setup_arch = efika_setup_arch, | ||
229 | .init = mpc52xx_declare_of_platform_devices, | ||
230 | .show_cpuinfo = efika_show_cpuinfo, | ||
231 | .init_IRQ = mpc52xx_init_irq, | ||
232 | .get_irq = mpc52xx_get_irq, | ||
233 | .restart = rtas_restart, | ||
234 | .power_off = rtas_power_off, | ||
235 | .halt = rtas_halt, | ||
236 | .set_rtc_time = rtas_set_rtc_time, | ||
237 | .get_rtc_time = rtas_get_rtc_time, | ||
238 | .progress = rtas_progress, | ||
239 | .get_boot_time = rtas_get_boot_time, | ||
240 | .calibrate_decr = generic_calibrate_decr, | ||
241 | .phys_mem_access_prot = pci_phys_mem_access_prot, | ||
242 | }; | ||
243 | |||
diff --git a/arch/powerpc/platforms/52xx/efika.h b/arch/powerpc/platforms/52xx/efika.h deleted file mode 100644 index 2f060fd097d7..000000000000 --- a/arch/powerpc/platforms/52xx/efika.h +++ /dev/null | |||
@@ -1,19 +0,0 @@ | |||
1 | /* | ||
2 | * Efika 5K2 platform setup - Header file | ||
3 | * | ||
4 | * Copyright (C) 2006 bplan GmbH | ||
5 | * | ||
6 | * This file is licensed under the terms of the GNU General Public License | ||
7 | * version 2. This program is licensed "as is" without any warranty of any | ||
8 | * kind, whether express or implied. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #ifndef __ARCH_POWERPC_EFIKA__ | ||
13 | #define __ARCH_POWERPC_EFIKA__ | ||
14 | |||
15 | #define EFIKA_PLATFORM_NAME "Efika" | ||
16 | |||
17 | extern void __init efika_pcisetup(void); | ||
18 | |||
19 | #endif | ||
diff --git a/arch/powerpc/platforms/52xx/lite5200.c b/arch/powerpc/platforms/52xx/lite5200.c index 0f21bab33f6c..cc3b40de21dd 100644 --- a/arch/powerpc/platforms/52xx/lite5200.c +++ b/arch/powerpc/platforms/52xx/lite5200.c | |||
@@ -51,13 +51,13 @@ | |||
51 | */ | 51 | */ |
52 | 52 | ||
53 | static void __init | 53 | static void __init |
54 | lite52xx_setup_cpu(void) | 54 | lite5200_setup_cpu(void) |
55 | { | 55 | { |
56 | struct mpc52xx_gpio __iomem *gpio; | 56 | struct mpc52xx_gpio __iomem *gpio; |
57 | u32 port_config; | 57 | u32 port_config; |
58 | 58 | ||
59 | /* Map zones */ | 59 | /* Map zones */ |
60 | gpio = mpc52xx_find_and_map("mpc52xx-gpio"); | 60 | gpio = mpc52xx_find_and_map("mpc5200-gpio"); |
61 | if (!gpio) { | 61 | if (!gpio) { |
62 | printk(KERN_ERR __FILE__ ": " | 62 | printk(KERN_ERR __FILE__ ": " |
63 | "Error while mapping GPIO register for port config. " | 63 | "Error while mapping GPIO register for port config. " |
@@ -85,12 +85,12 @@ error: | |||
85 | iounmap(gpio); | 85 | iounmap(gpio); |
86 | } | 86 | } |
87 | 87 | ||
88 | static void __init lite52xx_setup_arch(void) | 88 | static void __init lite5200_setup_arch(void) |
89 | { | 89 | { |
90 | struct device_node *np; | 90 | struct device_node *np; |
91 | 91 | ||
92 | if (ppc_md.progress) | 92 | if (ppc_md.progress) |
93 | ppc_md.progress("lite52xx_setup_arch()", 0); | 93 | ppc_md.progress("lite5200_setup_arch()", 0); |
94 | 94 | ||
95 | np = of_find_node_by_type(NULL, "cpu"); | 95 | np = of_find_node_by_type(NULL, "cpu"); |
96 | if (np) { | 96 | if (np) { |
@@ -105,7 +105,13 @@ static void __init lite52xx_setup_arch(void) | |||
105 | 105 | ||
106 | /* CPU & Port mux setup */ | 106 | /* CPU & Port mux setup */ |
107 | mpc52xx_setup_cpu(); /* Generic */ | 107 | mpc52xx_setup_cpu(); /* Generic */ |
108 | lite52xx_setup_cpu(); /* Platorm specific */ | 108 | lite5200_setup_cpu(); /* Platorm specific */ |
109 | |||
110 | #ifdef CONFIG_PCI | ||
111 | np = of_find_node_by_type(np, "pci"); | ||
112 | if (np) | ||
113 | mpc52xx_add_bridge(np); | ||
114 | #endif | ||
109 | 115 | ||
110 | #ifdef CONFIG_BLK_DEV_INITRD | 116 | #ifdef CONFIG_BLK_DEV_INITRD |
111 | if (initrd_start) | 117 | if (initrd_start) |
@@ -120,7 +126,7 @@ static void __init lite52xx_setup_arch(void) | |||
120 | 126 | ||
121 | } | 127 | } |
122 | 128 | ||
123 | void lite52xx_show_cpuinfo(struct seq_file *m) | 129 | void lite5200_show_cpuinfo(struct seq_file *m) |
124 | { | 130 | { |
125 | struct device_node* np = of_find_all_nodes(NULL); | 131 | struct device_node* np = of_find_all_nodes(NULL); |
126 | const char *model = NULL; | 132 | const char *model = NULL; |
@@ -137,25 +143,26 @@ void lite52xx_show_cpuinfo(struct seq_file *m) | |||
137 | /* | 143 | /* |
138 | * Called very early, MMU is off, device-tree isn't unflattened | 144 | * Called very early, MMU is off, device-tree isn't unflattened |
139 | */ | 145 | */ |
140 | static int __init lite52xx_probe(void) | 146 | static int __init lite5200_probe(void) |
141 | { | 147 | { |
142 | unsigned long node = of_get_flat_dt_root(); | 148 | unsigned long node = of_get_flat_dt_root(); |
143 | const char *model = of_get_flat_dt_prop(node, "model", NULL); | 149 | const char *model = of_get_flat_dt_prop(node, "model", NULL); |
144 | 150 | ||
145 | if (!of_flat_dt_is_compatible(node, "lite52xx")) | 151 | if (!of_flat_dt_is_compatible(node, "fsl,lite5200") && |
152 | !of_flat_dt_is_compatible(node, "fsl,lite5200b")) | ||
146 | return 0; | 153 | return 0; |
147 | pr_debug("%s board w/ mpc52xx found\n", model ? model : "unknown"); | 154 | pr_debug("%s board found\n", model ? model : "unknown"); |
148 | 155 | ||
149 | return 1; | 156 | return 1; |
150 | } | 157 | } |
151 | 158 | ||
152 | define_machine(lite52xx) { | 159 | define_machine(lite5200) { |
153 | .name = "lite52xx", | 160 | .name = "lite5200", |
154 | .probe = lite52xx_probe, | 161 | .probe = lite5200_probe, |
155 | .setup_arch = lite52xx_setup_arch, | 162 | .setup_arch = lite5200_setup_arch, |
156 | .init = mpc52xx_declare_of_platform_devices, | 163 | .init = mpc52xx_declare_of_platform_devices, |
157 | .init_IRQ = mpc52xx_init_irq, | 164 | .init_IRQ = mpc52xx_init_irq, |
158 | .get_irq = mpc52xx_get_irq, | 165 | .get_irq = mpc52xx_get_irq, |
159 | .show_cpuinfo = lite52xx_show_cpuinfo, | 166 | .show_cpuinfo = lite5200_show_cpuinfo, |
160 | .calibrate_decr = generic_calibrate_decr, | 167 | .calibrate_decr = generic_calibrate_decr, |
161 | }; | 168 | }; |
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_common.c b/arch/powerpc/platforms/52xx/mpc52xx_common.c index cc40889074bd..ed0cb694aea8 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_common.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_common.c | |||
@@ -83,8 +83,8 @@ mpc52xx_setup_cpu(void) | |||
83 | struct mpc52xx_xlb __iomem *xlb; | 83 | struct mpc52xx_xlb __iomem *xlb; |
84 | 84 | ||
85 | /* Map zones */ | 85 | /* Map zones */ |
86 | cdm = mpc52xx_find_and_map("mpc52xx-cdm"); | 86 | cdm = mpc52xx_find_and_map("mpc5200-cdm"); |
87 | xlb = mpc52xx_find_and_map("mpc52xx-xlb"); | 87 | xlb = mpc52xx_find_and_map("mpc5200-xlb"); |
88 | 88 | ||
89 | if (!cdm || !xlb) { | 89 | if (!cdm || !xlb) { |
90 | printk(KERN_ERR __FILE__ ": " | 90 | printk(KERN_ERR __FILE__ ": " |
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pci.c b/arch/powerpc/platforms/52xx/mpc52xx_pci.c new file mode 100644 index 000000000000..faf161bdbc1c --- /dev/null +++ b/arch/powerpc/platforms/52xx/mpc52xx_pci.c | |||
@@ -0,0 +1,412 @@ | |||
1 | /* | ||
2 | * PCI code for the Freescale MPC52xx embedded CPU. | ||
3 | * | ||
4 | * Copyright (C) 2006 Secret Lab Technologies Ltd. | ||
5 | * Grant Likely <grant.likely@secretlab.ca> | ||
6 | * Copyright (C) 2004 Sylvain Munaut <tnt@246tNt.com> | ||
7 | * | ||
8 | * This file is licensed under the terms of the GNU General Public License | ||
9 | * version 2. This program is licensed "as is" without any warranty of any | ||
10 | * kind, whether express or implied. | ||
11 | */ | ||
12 | |||
13 | #undef DEBUG | ||
14 | |||
15 | #include <asm/pci.h> | ||
16 | #include <asm/mpc52xx.h> | ||
17 | #include <asm/delay.h> | ||
18 | #include <asm/machdep.h> | ||
19 | #include <linux/kernel.h> | ||
20 | |||
21 | |||
22 | /* ======================================================================== */ | ||
23 | /* PCI windows config */ | ||
24 | /* ======================================================================== */ | ||
25 | |||
26 | #define MPC52xx_PCI_TARGET_IO 0xf0000000 | ||
27 | #define MPC52xx_PCI_TARGET_MEM 0x00000000 | ||
28 | |||
29 | |||
30 | /* ======================================================================== */ | ||
31 | /* Structures mapping & Defines for PCI Unit */ | ||
32 | /* ======================================================================== */ | ||
33 | |||
34 | #define MPC52xx_PCI_GSCR_BM 0x40000000 | ||
35 | #define MPC52xx_PCI_GSCR_PE 0x20000000 | ||
36 | #define MPC52xx_PCI_GSCR_SE 0x10000000 | ||
37 | #define MPC52xx_PCI_GSCR_XLB2PCI_MASK 0x07000000 | ||
38 | #define MPC52xx_PCI_GSCR_XLB2PCI_SHIFT 24 | ||
39 | #define MPC52xx_PCI_GSCR_IPG2PCI_MASK 0x00070000 | ||
40 | #define MPC52xx_PCI_GSCR_IPG2PCI_SHIFT 16 | ||
41 | #define MPC52xx_PCI_GSCR_BME 0x00004000 | ||
42 | #define MPC52xx_PCI_GSCR_PEE 0x00002000 | ||
43 | #define MPC52xx_PCI_GSCR_SEE 0x00001000 | ||
44 | #define MPC52xx_PCI_GSCR_PR 0x00000001 | ||
45 | |||
46 | |||
47 | #define MPC52xx_PCI_IWBTAR_TRANSLATION(proc_ad,pci_ad,size) \ | ||
48 | ( ( (proc_ad) & 0xff000000 ) | \ | ||
49 | ( (((size) - 1) >> 8) & 0x00ff0000 ) | \ | ||
50 | ( ((pci_ad) >> 16) & 0x0000ff00 ) ) | ||
51 | |||
52 | #define MPC52xx_PCI_IWCR_PACK(win0,win1,win2) (((win0) << 24) | \ | ||
53 | ((win1) << 16) | \ | ||
54 | ((win2) << 8)) | ||
55 | |||
56 | #define MPC52xx_PCI_IWCR_DISABLE 0x0 | ||
57 | #define MPC52xx_PCI_IWCR_ENABLE 0x1 | ||
58 | #define MPC52xx_PCI_IWCR_READ 0x0 | ||
59 | #define MPC52xx_PCI_IWCR_READ_LINE 0x2 | ||
60 | #define MPC52xx_PCI_IWCR_READ_MULTI 0x4 | ||
61 | #define MPC52xx_PCI_IWCR_MEM 0x0 | ||
62 | #define MPC52xx_PCI_IWCR_IO 0x8 | ||
63 | |||
64 | #define MPC52xx_PCI_TCR_P 0x01000000 | ||
65 | #define MPC52xx_PCI_TCR_LD 0x00010000 | ||
66 | |||
67 | #define MPC52xx_PCI_TBATR_DISABLE 0x0 | ||
68 | #define MPC52xx_PCI_TBATR_ENABLE 0x1 | ||
69 | |||
70 | struct mpc52xx_pci { | ||
71 | u32 idr; /* PCI + 0x00 */ | ||
72 | u32 scr; /* PCI + 0x04 */ | ||
73 | u32 ccrir; /* PCI + 0x08 */ | ||
74 | u32 cr1; /* PCI + 0x0C */ | ||
75 | u32 bar0; /* PCI + 0x10 */ | ||
76 | u32 bar1; /* PCI + 0x14 */ | ||
77 | u8 reserved1[16]; /* PCI + 0x18 */ | ||
78 | u32 ccpr; /* PCI + 0x28 */ | ||
79 | u32 sid; /* PCI + 0x2C */ | ||
80 | u32 erbar; /* PCI + 0x30 */ | ||
81 | u32 cpr; /* PCI + 0x34 */ | ||
82 | u8 reserved2[4]; /* PCI + 0x38 */ | ||
83 | u32 cr2; /* PCI + 0x3C */ | ||
84 | u8 reserved3[32]; /* PCI + 0x40 */ | ||
85 | u32 gscr; /* PCI + 0x60 */ | ||
86 | u32 tbatr0; /* PCI + 0x64 */ | ||
87 | u32 tbatr1; /* PCI + 0x68 */ | ||
88 | u32 tcr; /* PCI + 0x6C */ | ||
89 | u32 iw0btar; /* PCI + 0x70 */ | ||
90 | u32 iw1btar; /* PCI + 0x74 */ | ||
91 | u32 iw2btar; /* PCI + 0x78 */ | ||
92 | u8 reserved4[4]; /* PCI + 0x7C */ | ||
93 | u32 iwcr; /* PCI + 0x80 */ | ||
94 | u32 icr; /* PCI + 0x84 */ | ||
95 | u32 isr; /* PCI + 0x88 */ | ||
96 | u32 arb; /* PCI + 0x8C */ | ||
97 | u8 reserved5[104]; /* PCI + 0x90 */ | ||
98 | u32 car; /* PCI + 0xF8 */ | ||
99 | u8 reserved6[4]; /* PCI + 0xFC */ | ||
100 | }; | ||
101 | |||
102 | |||
103 | /* ======================================================================== */ | ||
104 | /* PCI configuration acess */ | ||
105 | /* ======================================================================== */ | ||
106 | |||
107 | static int | ||
108 | mpc52xx_pci_read_config(struct pci_bus *bus, unsigned int devfn, | ||
109 | int offset, int len, u32 *val) | ||
110 | { | ||
111 | struct pci_controller *hose = bus->sysdata; | ||
112 | u32 value; | ||
113 | |||
114 | if (ppc_md.pci_exclude_device) | ||
115 | if (ppc_md.pci_exclude_device(bus->number, devfn)) | ||
116 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
117 | |||
118 | out_be32(hose->cfg_addr, | ||
119 | (1 << 31) | | ||
120 | ((bus->number - hose->bus_offset) << 16) | | ||
121 | (devfn << 8) | | ||
122 | (offset & 0xfc)); | ||
123 | mb(); | ||
124 | |||
125 | #if defined(CONFIG_PPC_MPC5200_BUGFIX) | ||
126 | if (bus->number != hose->bus_offset) { | ||
127 | /* workaround for the bug 435 of the MPC5200 (L25R); | ||
128 | * Don't do 32 bits config access during type-1 cycles */ | ||
129 | switch (len) { | ||
130 | case 1: | ||
131 | value = in_8(((u8 __iomem *)hose->cfg_data) + | ||
132 | (offset & 3)); | ||
133 | break; | ||
134 | case 2: | ||
135 | value = in_le16(((u16 __iomem *)hose->cfg_data) + | ||
136 | ((offset>>1) & 1)); | ||
137 | break; | ||
138 | |||
139 | default: | ||
140 | value = in_le16((u16 __iomem *)hose->cfg_data) | | ||
141 | (in_le16(((u16 __iomem *)hose->cfg_data) + 1) << 16); | ||
142 | break; | ||
143 | } | ||
144 | } | ||
145 | else | ||
146 | #endif | ||
147 | { | ||
148 | value = in_le32(hose->cfg_data); | ||
149 | |||
150 | if (len != 4) { | ||
151 | value >>= ((offset & 0x3) << 3); | ||
152 | value &= 0xffffffff >> (32 - (len << 3)); | ||
153 | } | ||
154 | } | ||
155 | |||
156 | *val = value; | ||
157 | |||
158 | out_be32(hose->cfg_addr, 0); | ||
159 | mb(); | ||
160 | |||
161 | return PCIBIOS_SUCCESSFUL; | ||
162 | } | ||
163 | |||
164 | static int | ||
165 | mpc52xx_pci_write_config(struct pci_bus *bus, unsigned int devfn, | ||
166 | int offset, int len, u32 val) | ||
167 | { | ||
168 | struct pci_controller *hose = bus->sysdata; | ||
169 | u32 value, mask; | ||
170 | |||
171 | if (ppc_md.pci_exclude_device) | ||
172 | if (ppc_md.pci_exclude_device(bus->number, devfn)) | ||
173 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
174 | |||
175 | out_be32(hose->cfg_addr, | ||
176 | (1 << 31) | | ||
177 | ((bus->number - hose->bus_offset) << 16) | | ||
178 | (devfn << 8) | | ||
179 | (offset & 0xfc)); | ||
180 | mb(); | ||
181 | |||
182 | #if defined(CONFIG_PPC_MPC5200_BUGFIX) | ||
183 | if (bus->number != hose->bus_offset) { | ||
184 | /* workaround for the bug 435 of the MPC5200 (L25R); | ||
185 | * Don't do 32 bits config access during type-1 cycles */ | ||
186 | switch (len) { | ||
187 | case 1: | ||
188 | out_8(((u8 __iomem *)hose->cfg_data) + | ||
189 | (offset & 3), val); | ||
190 | break; | ||
191 | case 2: | ||
192 | out_le16(((u16 __iomem *)hose->cfg_data) + | ||
193 | ((offset>>1) & 1), val); | ||
194 | break; | ||
195 | |||
196 | default: | ||
197 | out_le16((u16 __iomem *)hose->cfg_data, | ||
198 | (u16)val); | ||
199 | out_le16(((u16 __iomem *)hose->cfg_data) + 1, | ||
200 | (u16)(val>>16)); | ||
201 | break; | ||
202 | } | ||
203 | } | ||
204 | else | ||
205 | #endif | ||
206 | { | ||
207 | if (len != 4) { | ||
208 | value = in_le32(hose->cfg_data); | ||
209 | |||
210 | offset = (offset & 0x3) << 3; | ||
211 | mask = (0xffffffff >> (32 - (len << 3))); | ||
212 | mask <<= offset; | ||
213 | |||
214 | value &= ~mask; | ||
215 | val = value | ((val << offset) & mask); | ||
216 | } | ||
217 | |||
218 | out_le32(hose->cfg_data, val); | ||
219 | } | ||
220 | mb(); | ||
221 | |||
222 | out_be32(hose->cfg_addr, 0); | ||
223 | mb(); | ||
224 | |||
225 | return PCIBIOS_SUCCESSFUL; | ||
226 | } | ||
227 | |||
228 | static struct pci_ops mpc52xx_pci_ops = { | ||
229 | .read = mpc52xx_pci_read_config, | ||
230 | .write = mpc52xx_pci_write_config | ||
231 | }; | ||
232 | |||
233 | |||
234 | /* ======================================================================== */ | ||
235 | /* PCI setup */ | ||
236 | /* ======================================================================== */ | ||
237 | |||
238 | static void __init | ||
239 | mpc52xx_pci_setup(struct pci_controller *hose, | ||
240 | struct mpc52xx_pci __iomem *pci_regs) | ||
241 | { | ||
242 | struct resource *res; | ||
243 | u32 tmp; | ||
244 | int iwcr0 = 0, iwcr1 = 0, iwcr2 = 0; | ||
245 | |||
246 | pr_debug("mpc52xx_pci_setup(hose=%p, pci_regs=%p)\n", hose, pci_regs); | ||
247 | |||
248 | /* pci_process_bridge_OF_ranges() found all our addresses for us; | ||
249 | * now store them in the right places */ | ||
250 | hose->cfg_addr = &pci_regs->car; | ||
251 | hose->cfg_data = hose->io_base_virt; | ||
252 | |||
253 | /* Control regs */ | ||
254 | tmp = in_be32(&pci_regs->scr); | ||
255 | tmp |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY; | ||
256 | out_be32(&pci_regs->scr, tmp); | ||
257 | |||
258 | /* Memory windows */ | ||
259 | res = &hose->mem_resources[0]; | ||
260 | if (res->flags) { | ||
261 | pr_debug("mem_resource[0] = {.start=%x, .end=%x, .flags=%lx}\n", | ||
262 | res->start, res->end, res->flags); | ||
263 | out_be32(&pci_regs->iw0btar, | ||
264 | MPC52xx_PCI_IWBTAR_TRANSLATION(res->start, res->start, | ||
265 | res->end - res->start + 1)); | ||
266 | iwcr0 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_MEM; | ||
267 | if (res->flags & IORESOURCE_PREFETCH) | ||
268 | iwcr0 |= MPC52xx_PCI_IWCR_READ_MULTI; | ||
269 | else | ||
270 | iwcr0 |= MPC52xx_PCI_IWCR_READ; | ||
271 | } | ||
272 | |||
273 | res = &hose->mem_resources[1]; | ||
274 | if (res->flags) { | ||
275 | pr_debug("mem_resource[1] = {.start=%x, .end=%x, .flags=%lx}\n", | ||
276 | res->start, res->end, res->flags); | ||
277 | out_be32(&pci_regs->iw1btar, | ||
278 | MPC52xx_PCI_IWBTAR_TRANSLATION(res->start, res->start, | ||
279 | res->end - res->start + 1)); | ||
280 | iwcr1 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_MEM; | ||
281 | if (res->flags & IORESOURCE_PREFETCH) | ||
282 | iwcr1 |= MPC52xx_PCI_IWCR_READ_MULTI; | ||
283 | else | ||
284 | iwcr1 |= MPC52xx_PCI_IWCR_READ; | ||
285 | } | ||
286 | |||
287 | /* IO resources */ | ||
288 | res = &hose->io_resource; | ||
289 | if (!res) { | ||
290 | printk(KERN_ERR "%s: Didn't find IO resources\n", __FILE__); | ||
291 | return; | ||
292 | } | ||
293 | pr_debug(".io_resource={.start=%x,.end=%x,.flags=%lx} " | ||
294 | ".io_base_phys=0x%p\n", | ||
295 | res->start, res->end, res->flags, (void*)hose->io_base_phys); | ||
296 | out_be32(&pci_regs->iw2btar, | ||
297 | MPC52xx_PCI_IWBTAR_TRANSLATION(hose->io_base_phys, | ||
298 | res->start, | ||
299 | res->end - res->start + 1)); | ||
300 | iwcr2 = MPC52xx_PCI_IWCR_ENABLE | MPC52xx_PCI_IWCR_IO; | ||
301 | |||
302 | /* Set all the IWCR fields at once; they're in the same reg */ | ||
303 | out_be32(&pci_regs->iwcr, MPC52xx_PCI_IWCR_PACK(iwcr0, iwcr1, iwcr2)); | ||
304 | |||
305 | out_be32(&pci_regs->tbatr0, | ||
306 | MPC52xx_PCI_TBATR_ENABLE | MPC52xx_PCI_TARGET_IO ); | ||
307 | out_be32(&pci_regs->tbatr1, | ||
308 | MPC52xx_PCI_TBATR_ENABLE | MPC52xx_PCI_TARGET_MEM ); | ||
309 | |||
310 | out_be32(&pci_regs->tcr, MPC52xx_PCI_TCR_LD); | ||
311 | |||
312 | tmp = in_be32(&pci_regs->gscr); | ||
313 | #if 0 | ||
314 | /* Reset the exteral bus ( internal PCI controller is NOT resetted ) */ | ||
315 | /* Not necessary and can be a bad thing if for example the bootloader | ||
316 | is displaying a splash screen or ... Just left here for | ||
317 | documentation purpose if anyone need it */ | ||
318 | out_be32(&pci_regs->gscr, tmp | MPC52xx_PCI_GSCR_PR); | ||
319 | udelay(50); | ||
320 | #endif | ||
321 | |||
322 | /* Make sure the PCI bridge is out of reset */ | ||
323 | out_be32(&pci_regs->gscr, tmp & ~MPC52xx_PCI_GSCR_PR); | ||
324 | } | ||
325 | |||
326 | static void | ||
327 | mpc52xx_pci_fixup_resources(struct pci_dev *dev) | ||
328 | { | ||
329 | int i; | ||
330 | |||
331 | pr_debug("mpc52xx_pci_fixup_resources() %.4x:%.4x\n", | ||
332 | dev->vendor, dev->device); | ||
333 | |||
334 | /* We don't rely on boot loader for PCI and resets all | ||
335 | devices */ | ||
336 | for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { | ||
337 | struct resource *res = &dev->resource[i]; | ||
338 | if (res->end > res->start) { /* Only valid resources */ | ||
339 | res->end -= res->start; | ||
340 | res->start = 0; | ||
341 | res->flags |= IORESOURCE_UNSET; | ||
342 | } | ||
343 | } | ||
344 | |||
345 | /* The PCI Host bridge of MPC52xx has a prefetch memory resource | ||
346 | fixed to 1Gb. Doesn't fit in the resource system so we remove it */ | ||
347 | if ( (dev->vendor == PCI_VENDOR_ID_MOTOROLA) && | ||
348 | ( dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200 | ||
349 | || dev->device == PCI_DEVICE_ID_MOTOROLA_MPC5200B) ) { | ||
350 | struct resource *res = &dev->resource[1]; | ||
351 | res->start = res->end = res->flags = 0; | ||
352 | } | ||
353 | } | ||
354 | |||
355 | int __init | ||
356 | mpc52xx_add_bridge(struct device_node *node) | ||
357 | { | ||
358 | int len; | ||
359 | struct mpc52xx_pci __iomem *pci_regs; | ||
360 | struct pci_controller *hose; | ||
361 | const int *bus_range; | ||
362 | struct resource rsrc; | ||
363 | |||
364 | pr_debug("Adding MPC52xx PCI host bridge %s\n", node->full_name); | ||
365 | |||
366 | pci_assign_all_buses = 1; | ||
367 | |||
368 | if (of_address_to_resource(node, 0, &rsrc) != 0) { | ||
369 | printk(KERN_ERR "Can't get %s resources\n", node->full_name); | ||
370 | return -EINVAL; | ||
371 | } | ||
372 | |||
373 | bus_range = get_property(node, "bus-range", &len); | ||
374 | if (bus_range == NULL || len < 2 * sizeof(int)) { | ||
375 | printk(KERN_WARNING "Can't get %s bus-range, assume bus 0\n", | ||
376 | node->full_name); | ||
377 | bus_range = NULL; | ||
378 | } | ||
379 | |||
380 | /* There are some PCI quirks on the 52xx, register the hook to | ||
381 | * fix them. */ | ||
382 | ppc_md.pcibios_fixup_resources = mpc52xx_pci_fixup_resources; | ||
383 | |||
384 | /* Alloc and initialize the pci controller. Values in the device | ||
385 | * tree are needed to configure the 52xx PCI controller. Rather | ||
386 | * than parse the tree here, let pci_process_bridge_OF_ranges() | ||
387 | * do it for us and extract the values after the fact */ | ||
388 | hose = pcibios_alloc_controller(); | ||
389 | if (!hose) | ||
390 | return -ENOMEM; | ||
391 | |||
392 | hose->arch_data = node; | ||
393 | hose->set_cfg_type = 1; | ||
394 | |||
395 | hose->first_busno = bus_range ? bus_range[0] : 0; | ||
396 | hose->last_busno = bus_range ? bus_range[1] : 0xff; | ||
397 | |||
398 | hose->bus_offset = 0; | ||
399 | hose->ops = &mpc52xx_pci_ops; | ||
400 | |||
401 | pci_regs = ioremap(rsrc.start, rsrc.end - rsrc.start + 1); | ||
402 | if (!pci_regs) | ||
403 | return -ENOMEM; | ||
404 | |||
405 | pci_process_bridge_OF_ranges(hose, node, 1); | ||
406 | |||
407 | /* Finish setting up PCI using values obtained by | ||
408 | * pci_proces_bridge_OF_ranges */ | ||
409 | mpc52xx_pci_setup(hose, pci_regs); | ||
410 | |||
411 | return 0; | ||
412 | } | ||
diff --git a/arch/powerpc/platforms/52xx/mpc52xx_pic.c b/arch/powerpc/platforms/52xx/mpc52xx_pic.c index cd91a6c3aafa..c75192567e55 100644 --- a/arch/powerpc/platforms/52xx/mpc52xx_pic.c +++ b/arch/powerpc/platforms/52xx/mpc52xx_pic.c | |||
@@ -383,16 +383,16 @@ void __init mpc52xx_init_irq(void) | |||
383 | struct device_node *picnode; | 383 | struct device_node *picnode; |
384 | 384 | ||
385 | /* Remap the necessary zones */ | 385 | /* Remap the necessary zones */ |
386 | picnode = of_find_compatible_node(NULL, NULL, "mpc52xx-pic"); | 386 | picnode = of_find_compatible_node(NULL, NULL, "mpc5200-pic"); |
387 | 387 | ||
388 | intr = mpc52xx_find_and_map("mpc52xx-pic"); | 388 | intr = mpc52xx_find_and_map("mpc5200-pic"); |
389 | if (!intr) | 389 | if (!intr) |
390 | panic(__FILE__ ": find_and_map failed on 'mpc52xx-pic'. " | 390 | panic(__FILE__ ": find_and_map failed on 'mpc5200-pic'. " |
391 | "Check node !"); | 391 | "Check node !"); |
392 | 392 | ||
393 | sdma = mpc52xx_find_and_map("mpc52xx-bestcomm"); | 393 | sdma = mpc52xx_find_and_map("mpc5200-bestcomm"); |
394 | if (!sdma) | 394 | if (!sdma) |
395 | panic(__FILE__ ": find_and_map failed on 'mpc52xx-bestcomm'. " | 395 | panic(__FILE__ ": find_and_map failed on 'mpc5200-bestcomm'. " |
396 | "Check node !"); | 396 | "Check node !"); |
397 | 397 | ||
398 | /* Disable all interrupt sources. */ | 398 | /* Disable all interrupt sources. */ |
diff --git a/arch/powerpc/platforms/82xx/mpc82xx.c b/arch/powerpc/platforms/82xx/mpc82xx.c index 0f5b30dc60da..74e7892cdfcf 100644 --- a/arch/powerpc/platforms/82xx/mpc82xx.c +++ b/arch/powerpc/platforms/82xx/mpc82xx.c | |||
@@ -50,7 +50,7 @@ | |||
50 | #include <sysdev/fsl_soc.h> | 50 | #include <sysdev/fsl_soc.h> |
51 | #include <sysdev/cpm2_pic.h> | 51 | #include <sysdev/cpm2_pic.h> |
52 | 52 | ||
53 | #include "pq2ads_pd.h" | 53 | #include "pq2ads.h" |
54 | 54 | ||
55 | static int __init get_freq(char *name, unsigned long *val) | 55 | static int __init get_freq(char *name, unsigned long *val) |
56 | { | 56 | { |
diff --git a/arch/powerpc/platforms/82xx/mpc82xx_ads.c b/arch/powerpc/platforms/82xx/mpc82xx_ads.c index ea880f1f0dcd..7334c1a15b90 100644 --- a/arch/powerpc/platforms/82xx/mpc82xx_ads.c +++ b/arch/powerpc/platforms/82xx/mpc82xx_ads.c | |||
@@ -51,7 +51,7 @@ | |||
51 | #include <sysdev/fsl_soc.h> | 51 | #include <sysdev/fsl_soc.h> |
52 | #include <../sysdev/cpm2_pic.h> | 52 | #include <../sysdev/cpm2_pic.h> |
53 | 53 | ||
54 | #include "pq2ads_pd.h" | 54 | #include "pq2ads.h" |
55 | 55 | ||
56 | #ifdef CONFIG_PCI | 56 | #ifdef CONFIG_PCI |
57 | static uint pci_clk_frq; | 57 | static uint pci_clk_frq; |
diff --git a/arch/powerpc/platforms/82xx/pq2ads.h b/arch/powerpc/platforms/82xx/pq2ads.h index fb2f92bcd770..5b5cca6c8c88 100644 --- a/arch/powerpc/platforms/82xx/pq2ads.h +++ b/arch/powerpc/platforms/82xx/pq2ads.h | |||
@@ -22,6 +22,7 @@ | |||
22 | #ifndef __MACH_ADS8260_DEFS | 22 | #ifndef __MACH_ADS8260_DEFS |
23 | #define __MACH_ADS8260_DEFS | 23 | #define __MACH_ADS8260_DEFS |
24 | 24 | ||
25 | #include <linux/seq_file.h> | ||
25 | #include <asm/ppcboot.h> | 26 | #include <asm/ppcboot.h> |
26 | 27 | ||
27 | /* For our show_cpuinfo hooks. */ | 28 | /* For our show_cpuinfo hooks. */ |
@@ -46,12 +47,12 @@ | |||
46 | #define BCSR1_RS232_EN1 ((uint)0x02000000) /* 0 ==enable */ | 47 | #define BCSR1_RS232_EN1 ((uint)0x02000000) /* 0 ==enable */ |
47 | #define BCSR1_RS232_EN2 ((uint)0x01000000) /* 0 ==enable */ | 48 | #define BCSR1_RS232_EN2 ((uint)0x01000000) /* 0 ==enable */ |
48 | #define BCSR3_FETHIEN2 ((uint)0x10000000) /* 0 == enable*/ | 49 | #define BCSR3_FETHIEN2 ((uint)0x10000000) /* 0 == enable*/ |
49 | #define BCSR3_FETH2_RS ((uint)0x80000000) /* 0 == reset */ | 50 | #define BCSR3_FETH2_RST ((uint)0x80000000) /* 0 == reset */ |
50 | 51 | ||
51 | /* cpm serial driver works with constants below */ | 52 | /* cpm serial driver works with constants below */ |
52 | 53 | ||
53 | #define SIU_INT_SMC1 ((uint)0x04+CPM_IRQ_OFFSET) | 54 | #define SIU_INT_SMC1 ((uint)0x04+CPM_IRQ_OFFSET) |
54 | #define SIU_INT_SMC2i ((uint)0x05+CPM_IRQ_OFFSET) | 55 | #define SIU_INT_SMC2 ((uint)0x05+CPM_IRQ_OFFSET) |
55 | #define SIU_INT_SCC1 ((uint)0x28+CPM_IRQ_OFFSET) | 56 | #define SIU_INT_SCC1 ((uint)0x28+CPM_IRQ_OFFSET) |
56 | #define SIU_INT_SCC2 ((uint)0x29+CPM_IRQ_OFFSET) | 57 | #define SIU_INT_SCC2 ((uint)0x29+CPM_IRQ_OFFSET) |
57 | #define SIU_INT_SCC3 ((uint)0x2a+CPM_IRQ_OFFSET) | 58 | #define SIU_INT_SCC3 ((uint)0x2a+CPM_IRQ_OFFSET) |
diff --git a/arch/powerpc/platforms/83xx/Kconfig b/arch/powerpc/platforms/83xx/Kconfig index edcd5b875b66..713b31a16ce9 100644 --- a/arch/powerpc/platforms/83xx/Kconfig +++ b/arch/powerpc/platforms/83xx/Kconfig | |||
@@ -3,7 +3,13 @@ menu "Platform support" | |||
3 | 3 | ||
4 | choice | 4 | choice |
5 | prompt "Machine Type" | 5 | prompt "Machine Type" |
6 | default MPC834x_SYS | 6 | default MPC834x_MDS |
7 | |||
8 | config MPC8313_RDB | ||
9 | bool "Freescale MPC8313 RDB" | ||
10 | select DEFAULT_UIMAGE | ||
11 | help | ||
12 | This option enables support for the MPC8313 RDB board. | ||
7 | 13 | ||
8 | config MPC832x_MDS | 14 | config MPC832x_MDS |
9 | bool "Freescale MPC832x MDS" | 15 | bool "Freescale MPC832x MDS" |
@@ -12,13 +18,13 @@ config MPC832x_MDS | |||
12 | help | 18 | help |
13 | This option enables support for the MPC832x MDS evaluation board. | 19 | This option enables support for the MPC832x MDS evaluation board. |
14 | 20 | ||
15 | config MPC834x_SYS | 21 | config MPC834x_MDS |
16 | bool "Freescale MPC834x SYS" | 22 | bool "Freescale MPC834x MDS" |
17 | select DEFAULT_UIMAGE | 23 | select DEFAULT_UIMAGE |
18 | help | 24 | help |
19 | This option enables support for the MPC 834x SYS evaluation board. | 25 | This option enables support for the MPC 834x MDS evaluation board. |
20 | 26 | ||
21 | Be aware that PCI buses can only function when SYS board is plugged | 27 | Be aware that PCI buses can only function when MDS board is plugged |
22 | into the PIB (Platform IO Board) board from Freescale which provide | 28 | into the PIB (Platform IO Board) board from Freescale which provide |
23 | 3 PCI slots. The PIBs PCI initialization is the bootloader's | 29 | 3 PCI slots. The PIBs PCI initialization is the bootloader's |
24 | responsibility. | 30 | responsibility. |
@@ -32,15 +38,21 @@ config MPC834x_ITX | |||
32 | Be aware that PCI initialization is the bootloader's | 38 | Be aware that PCI initialization is the bootloader's |
33 | responsibility. | 39 | responsibility. |
34 | 40 | ||
35 | config MPC8360E_PB | 41 | config MPC836x_MDS |
36 | bool "Freescale MPC8360E PB" | 42 | bool "Freescale MPC836x MDS" |
37 | select DEFAULT_UIMAGE | 43 | select DEFAULT_UIMAGE |
38 | select QUICC_ENGINE | 44 | select QUICC_ENGINE |
39 | help | 45 | help |
40 | This option enables support for the MPC836x EMDS Processor Board. | 46 | This option enables support for the MPC836x MDS Processor Board. |
41 | 47 | ||
42 | endchoice | 48 | endchoice |
43 | 49 | ||
50 | config PPC_MPC831x | ||
51 | bool | ||
52 | select PPC_UDBG_16550 | ||
53 | select PPC_INDIRECT_PCI | ||
54 | default y if MPC8313_RDB | ||
55 | |||
44 | config PPC_MPC832x | 56 | config PPC_MPC832x |
45 | bool | 57 | bool |
46 | select PPC_UDBG_16550 | 58 | select PPC_UDBG_16550 |
@@ -51,12 +63,12 @@ config MPC834x | |||
51 | bool | 63 | bool |
52 | select PPC_UDBG_16550 | 64 | select PPC_UDBG_16550 |
53 | select PPC_INDIRECT_PCI | 65 | select PPC_INDIRECT_PCI |
54 | default y if MPC834x_SYS || MPC834x_ITX | 66 | default y if MPC834x_MDS || MPC834x_ITX |
55 | 67 | ||
56 | config PPC_MPC836x | 68 | config PPC_MPC836x |
57 | bool | 69 | bool |
58 | select PPC_UDBG_16550 | 70 | select PPC_UDBG_16550 |
59 | select PPC_INDIRECT_PCI | 71 | select PPC_INDIRECT_PCI |
60 | default y if MPC8360E_PB | 72 | default y if MPC836x_MDS |
61 | 73 | ||
62 | endmenu | 74 | endmenu |
diff --git a/arch/powerpc/platforms/83xx/Makefile b/arch/powerpc/platforms/83xx/Makefile index f1aa7e24a938..dfc970d0df10 100644 --- a/arch/powerpc/platforms/83xx/Makefile +++ b/arch/powerpc/platforms/83xx/Makefile | |||
@@ -3,7 +3,8 @@ | |||
3 | # | 3 | # |
4 | obj-y := misc.o | 4 | obj-y := misc.o |
5 | obj-$(CONFIG_PCI) += pci.o | 5 | obj-$(CONFIG_PCI) += pci.o |
6 | obj-$(CONFIG_MPC834x_SYS) += mpc834x_sys.o | 6 | obj-$(CONFIG_MPC8313_RDB) += mpc8313_rdb.o |
7 | obj-$(CONFIG_MPC834x_MDS) += mpc834x_mds.o | ||
7 | obj-$(CONFIG_MPC834x_ITX) += mpc834x_itx.o | 8 | obj-$(CONFIG_MPC834x_ITX) += mpc834x_itx.o |
8 | obj-$(CONFIG_MPC8360E_PB) += mpc8360e_pb.o | 9 | obj-$(CONFIG_MPC836x_MDS) += mpc836x_mds.o |
9 | obj-$(CONFIG_MPC832x_MDS) += mpc832x_mds.o | 10 | obj-$(CONFIG_MPC832x_MDS) += mpc832x_mds.o |
diff --git a/arch/powerpc/platforms/83xx/misc.c b/arch/powerpc/platforms/83xx/misc.c index f0c6df61faa9..f01806c940e1 100644 --- a/arch/powerpc/platforms/83xx/misc.c +++ b/arch/powerpc/platforms/83xx/misc.c | |||
@@ -18,23 +18,36 @@ | |||
18 | 18 | ||
19 | #include "mpc83xx.h" | 19 | #include "mpc83xx.h" |
20 | 20 | ||
21 | static __be32 __iomem *restart_reg_base; | ||
22 | |||
23 | static int __init mpc83xx_restart_init(void) | ||
24 | { | ||
25 | /* map reset restart_reg_baseister space */ | ||
26 | restart_reg_base = ioremap(get_immrbase() + 0x900, 0xff); | ||
27 | |||
28 | return 0; | ||
29 | } | ||
30 | |||
31 | arch_initcall(mpc83xx_restart_init); | ||
32 | |||
21 | void mpc83xx_restart(char *cmd) | 33 | void mpc83xx_restart(char *cmd) |
22 | { | 34 | { |
23 | #define RST_OFFSET 0x00000900 | 35 | #define RST_OFFSET 0x00000900 |
24 | #define RST_PROT_REG 0x00000018 | 36 | #define RST_PROT_REG 0x00000018 |
25 | #define RST_CTRL_REG 0x0000001c | 37 | #define RST_CTRL_REG 0x0000001c |
26 | __be32 __iomem *reg; | ||
27 | |||
28 | /* map reset register space */ | ||
29 | reg = ioremap(get_immrbase() + 0x900, 0xff); | ||
30 | 38 | ||
31 | local_irq_disable(); | 39 | local_irq_disable(); |
32 | 40 | ||
33 | /* enable software reset "RSTE" */ | 41 | if (restart_reg_base) { |
34 | out_be32(reg + (RST_PROT_REG >> 2), 0x52535445); | 42 | /* enable software reset "RSTE" */ |
43 | out_be32(restart_reg_base + (RST_PROT_REG >> 2), 0x52535445); | ||
44 | |||
45 | /* set software hard reset */ | ||
46 | out_be32(restart_reg_base + (RST_CTRL_REG >> 2), 0x2); | ||
47 | } else { | ||
48 | printk (KERN_EMERG "Error: Restart registers not mapped, spinning!\n"); | ||
49 | } | ||
35 | 50 | ||
36 | /* set software hard reset */ | ||
37 | out_be32(reg + (RST_CTRL_REG >> 2), 0x2); | ||
38 | for (;;) ; | 51 | for (;;) ; |
39 | } | 52 | } |
40 | 53 | ||
diff --git a/arch/powerpc/platforms/83xx/mpc8313_rdb.c b/arch/powerpc/platforms/83xx/mpc8313_rdb.c new file mode 100644 index 000000000000..32e9e9492841 --- /dev/null +++ b/arch/powerpc/platforms/83xx/mpc8313_rdb.c | |||
@@ -0,0 +1,92 @@ | |||
1 | /* | ||
2 | * arch/powerpc/platforms/83xx/mpc8313_rdb.c | ||
3 | * | ||
4 | * Description: MPC8313x RDB board specific routines. | ||
5 | * This file is based on mpc834x_sys.c | ||
6 | * Author: Lo Wlison <r43300@freescale.com> | ||
7 | * | ||
8 | * Copyright (C) Freescale Semiconductor, Inc. 2006. All rights reserved. | ||
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/pci.h> | ||
17 | |||
18 | #include <asm/time.h> | ||
19 | #include <asm/ipic.h> | ||
20 | #include <asm/udbg.h> | ||
21 | |||
22 | #include "mpc83xx.h" | ||
23 | |||
24 | #undef DEBUG | ||
25 | #ifdef DEBUG | ||
26 | #define DBG(fmt...) udbg_printf(fmt) | ||
27 | #else | ||
28 | #define DBG(fmt...) | ||
29 | #endif | ||
30 | |||
31 | #ifndef CONFIG_PCI | ||
32 | unsigned long isa_io_base = 0; | ||
33 | unsigned long isa_mem_base = 0; | ||
34 | #endif | ||
35 | |||
36 | /* ************************************************************************ | ||
37 | * | ||
38 | * Setup the architecture | ||
39 | * | ||
40 | */ | ||
41 | static void __init mpc8313_rdb_setup_arch(void) | ||
42 | { | ||
43 | struct device_node *np; | ||
44 | |||
45 | if (ppc_md.progress) | ||
46 | ppc_md.progress("mpc8313_rdb_setup_arch()", 0); | ||
47 | |||
48 | #ifdef CONFIG_PCI | ||
49 | for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) | ||
50 | add_bridge(np); | ||
51 | |||
52 | ppc_md.pci_exclude_device = mpc83xx_exclude_device; | ||
53 | #endif | ||
54 | } | ||
55 | |||
56 | void __init mpc8313_rdb_init_IRQ(void) | ||
57 | { | ||
58 | struct device_node *np; | ||
59 | |||
60 | np = of_find_node_by_type(NULL, "ipic"); | ||
61 | if (!np) | ||
62 | return; | ||
63 | |||
64 | ipic_init(np, 0); | ||
65 | |||
66 | /* Initialize the default interrupt mapping priorities, | ||
67 | * in case the boot rom changed something on us. | ||
68 | */ | ||
69 | ipic_set_default_priority(); | ||
70 | } | ||
71 | |||
72 | /* | ||
73 | * Called very early, MMU is off, device-tree isn't unflattened | ||
74 | */ | ||
75 | static int __init mpc8313_rdb_probe(void) | ||
76 | { | ||
77 | unsigned long root = of_get_flat_dt_root(); | ||
78 | |||
79 | return of_flat_dt_is_compatible(root, "MPC8313ERDB"); | ||
80 | } | ||
81 | |||
82 | define_machine(mpc8313_rdb) { | ||
83 | .name = "MPC8313 RDB", | ||
84 | .probe = mpc8313_rdb_probe, | ||
85 | .setup_arch = mpc8313_rdb_setup_arch, | ||
86 | .init_IRQ = mpc8313_rdb_init_IRQ, | ||
87 | .get_irq = ipic_get_irq, | ||
88 | .restart = mpc83xx_restart, | ||
89 | .time_init = mpc83xx_time_init, | ||
90 | .calibrate_decr = generic_calibrate_decr, | ||
91 | .progress = udbg_progress, | ||
92 | }; | ||
diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.c b/arch/powerpc/platforms/83xx/mpc832x_mds.c index 4d471190be8d..17e3a3c6d8b4 100644 --- a/arch/powerpc/platforms/83xx/mpc832x_mds.c +++ b/arch/powerpc/platforms/83xx/mpc832x_mds.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/initrd.h> | 25 | #include <linux/initrd.h> |
26 | 26 | ||
27 | #include <asm/of_device.h> | 27 | #include <asm/of_device.h> |
28 | #include <asm/of_platform.h> | ||
28 | #include <asm/system.h> | 29 | #include <asm/system.h> |
29 | #include <asm/atomic.h> | 30 | #include <asm/atomic.h> |
30 | #include <asm/time.h> | 31 | #include <asm/time.h> |
@@ -56,11 +57,6 @@ unsigned long isa_mem_base = 0; | |||
56 | 57 | ||
57 | static u8 *bcsr_regs = NULL; | 58 | static u8 *bcsr_regs = NULL; |
58 | 59 | ||
59 | u8 *get_bcsr(void) | ||
60 | { | ||
61 | return bcsr_regs; | ||
62 | } | ||
63 | |||
64 | /* ************************************************************************ | 60 | /* ************************************************************************ |
65 | * | 61 | * |
66 | * Setup the architecture | 62 | * Setup the architecture |
@@ -73,17 +69,6 @@ static void __init mpc832x_sys_setup_arch(void) | |||
73 | if (ppc_md.progress) | 69 | if (ppc_md.progress) |
74 | ppc_md.progress("mpc832x_sys_setup_arch()", 0); | 70 | ppc_md.progress("mpc832x_sys_setup_arch()", 0); |
75 | 71 | ||
76 | np = of_find_node_by_type(NULL, "cpu"); | ||
77 | if (np != 0) { | ||
78 | unsigned int *fp = | ||
79 | (int *)get_property(np, "clock-frequency", NULL); | ||
80 | if (fp != 0) | ||
81 | loops_per_jiffy = *fp / HZ; | ||
82 | else | ||
83 | loops_per_jiffy = 50000000 / HZ; | ||
84 | of_node_put(np); | ||
85 | } | ||
86 | |||
87 | /* Map BCSR area */ | 72 | /* Map BCSR area */ |
88 | np = of_find_node_by_name(NULL, "bcsr"); | 73 | np = of_find_node_by_name(NULL, "bcsr"); |
89 | if (np != 0) { | 74 | if (np != 0) { |
@@ -120,42 +105,30 @@ static void __init mpc832x_sys_setup_arch(void) | |||
120 | iounmap(bcsr_regs); | 105 | iounmap(bcsr_regs); |
121 | of_node_put(np); | 106 | of_node_put(np); |
122 | } | 107 | } |
123 | |||
124 | #endif /* CONFIG_QUICC_ENGINE */ | 108 | #endif /* CONFIG_QUICC_ENGINE */ |
125 | |||
126 | #ifdef CONFIG_BLK_DEV_INITRD | ||
127 | if (initrd_start) | ||
128 | ROOT_DEV = Root_RAM0; | ||
129 | else | ||
130 | #endif | ||
131 | #ifdef CONFIG_ROOT_NFS | ||
132 | ROOT_DEV = Root_NFS; | ||
133 | #else | ||
134 | ROOT_DEV = Root_HDA1; | ||
135 | #endif | ||
136 | } | 109 | } |
137 | 110 | ||
111 | static struct of_device_id mpc832x_ids[] = { | ||
112 | { .type = "soc", }, | ||
113 | { .compatible = "soc", }, | ||
114 | { .type = "qe", }, | ||
115 | {}, | ||
116 | }; | ||
117 | |||
138 | static int __init mpc832x_declare_of_platform_devices(void) | 118 | static int __init mpc832x_declare_of_platform_devices(void) |
139 | { | 119 | { |
140 | struct device_node *np; | 120 | if (!machine_is(mpc832x_mds)) |
141 | 121 | return 0; | |
142 | for (np = NULL; (np = of_find_compatible_node(np, "network", | ||
143 | "ucc_geth")) != NULL;) { | ||
144 | int ucc_num; | ||
145 | char bus_id[BUS_ID_SIZE]; | ||
146 | 122 | ||
147 | ucc_num = *((uint *) get_property(np, "device-id", NULL)) - 1; | 123 | /* Publish the QE devices */ |
148 | snprintf(bus_id, BUS_ID_SIZE, "ucc_geth.%u", ucc_num); | 124 | of_platform_bus_probe(NULL, mpc832x_ids, NULL); |
149 | of_platform_device_create(np, bus_id, NULL); | ||
150 | } | ||
151 | 125 | ||
152 | return 0; | 126 | return 0; |
153 | } | 127 | } |
154 | device_initcall(mpc832x_declare_of_platform_devices); | 128 | device_initcall(mpc832x_declare_of_platform_devices); |
155 | 129 | ||
156 | void __init mpc832x_sys_init_IRQ(void) | 130 | static void __init mpc832x_sys_init_IRQ(void) |
157 | { | 131 | { |
158 | |||
159 | struct device_node *np; | 132 | struct device_node *np; |
160 | 133 | ||
161 | np = of_find_node_by_type(NULL, "ipic"); | 134 | np = of_find_node_by_type(NULL, "ipic"); |
@@ -188,6 +161,9 @@ static int __init mpc832x_rtc_hookup(void) | |||
188 | { | 161 | { |
189 | struct timespec tv; | 162 | struct timespec tv; |
190 | 163 | ||
164 | if (!machine_is(mpc832x_mds)) | ||
165 | return 0; | ||
166 | |||
191 | ppc_md.get_rtc_time = ds1374_get_rtc_time; | 167 | ppc_md.get_rtc_time = ds1374_get_rtc_time; |
192 | ppc_md.set_rtc_time = ds1374_set_rtc_time; | 168 | ppc_md.set_rtc_time = ds1374_set_rtc_time; |
193 | 169 | ||
@@ -206,17 +182,9 @@ late_initcall(mpc832x_rtc_hookup); | |||
206 | */ | 182 | */ |
207 | static int __init mpc832x_sys_probe(void) | 183 | static int __init mpc832x_sys_probe(void) |
208 | { | 184 | { |
209 | char *model = of_get_flat_dt_prop(of_get_flat_dt_root(), | 185 | unsigned long root = of_get_flat_dt_root(); |
210 | "model", NULL); | ||
211 | |||
212 | if (model == NULL) | ||
213 | return 0; | ||
214 | if (strcmp(model, "MPC8323EMDS")) | ||
215 | return 0; | ||
216 | |||
217 | DBG("%s found\n", model); | ||
218 | 186 | ||
219 | return 1; | 187 | return of_flat_dt_is_compatible(root, "MPC832xMDS"); |
220 | } | 188 | } |
221 | 189 | ||
222 | define_machine(mpc832x_mds) { | 190 | define_machine(mpc832x_mds) { |
diff --git a/arch/powerpc/platforms/83xx/mpc834x_itx.c b/arch/powerpc/platforms/83xx/mpc834x_itx.c index 314c42ac6048..3c009f6d4a4f 100644 --- a/arch/powerpc/platforms/83xx/mpc834x_itx.c +++ b/arch/powerpc/platforms/83xx/mpc834x_itx.c | |||
@@ -38,8 +38,6 @@ | |||
38 | 38 | ||
39 | #include "mpc83xx.h" | 39 | #include "mpc83xx.h" |
40 | 40 | ||
41 | #include <platforms/83xx/mpc834x_sys.h> | ||
42 | |||
43 | #ifndef CONFIG_PCI | 41 | #ifndef CONFIG_PCI |
44 | unsigned long isa_io_base = 0; | 42 | unsigned long isa_io_base = 0; |
45 | unsigned long isa_mem_base = 0; | 43 | unsigned long isa_mem_base = 0; |
@@ -57,31 +55,15 @@ static void __init mpc834x_itx_setup_arch(void) | |||
57 | if (ppc_md.progress) | 55 | if (ppc_md.progress) |
58 | ppc_md.progress("mpc834x_itx_setup_arch()", 0); | 56 | ppc_md.progress("mpc834x_itx_setup_arch()", 0); |
59 | 57 | ||
60 | np = of_find_node_by_type(NULL, "cpu"); | ||
61 | if (np != 0) { | ||
62 | const unsigned int *fp = | ||
63 | get_property(np, "clock-frequency", NULL); | ||
64 | if (fp != 0) | ||
65 | loops_per_jiffy = *fp / HZ; | ||
66 | else | ||
67 | loops_per_jiffy = 50000000 / HZ; | ||
68 | of_node_put(np); | ||
69 | } | ||
70 | #ifdef CONFIG_PCI | 58 | #ifdef CONFIG_PCI |
71 | for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) | 59 | for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) |
72 | add_bridge(np); | 60 | add_bridge(np); |
73 | 61 | ||
74 | ppc_md.pci_exclude_device = mpc83xx_exclude_device; | 62 | ppc_md.pci_exclude_device = mpc83xx_exclude_device; |
75 | #endif | 63 | #endif |
76 | |||
77 | #ifdef CONFIG_ROOT_NFS | ||
78 | ROOT_DEV = Root_NFS; | ||
79 | #else | ||
80 | ROOT_DEV = Root_HDA1; | ||
81 | #endif | ||
82 | } | 64 | } |
83 | 65 | ||
84 | void __init mpc834x_itx_init_IRQ(void) | 66 | static void __init mpc834x_itx_init_IRQ(void) |
85 | { | 67 | { |
86 | struct device_node *np; | 68 | struct device_node *np; |
87 | 69 | ||
@@ -102,10 +84,9 @@ void __init mpc834x_itx_init_IRQ(void) | |||
102 | */ | 84 | */ |
103 | static int __init mpc834x_itx_probe(void) | 85 | static int __init mpc834x_itx_probe(void) |
104 | { | 86 | { |
105 | /* We always match for now, eventually we should look at the flat | 87 | unsigned long root = of_get_flat_dt_root(); |
106 | dev tree to ensure this is the board we are suppose to run on | 88 | |
107 | */ | 89 | return of_flat_dt_is_compatible(root, "MPC834xMITX"); |
108 | return 1; | ||
109 | } | 90 | } |
110 | 91 | ||
111 | define_machine(mpc834x_itx) { | 92 | define_machine(mpc834x_itx) { |
diff --git a/arch/powerpc/platforms/83xx/mpc834x_sys.c b/arch/powerpc/platforms/83xx/mpc834x_mds.c index 80b735a414d9..e5d819166874 100644 --- a/arch/powerpc/platforms/83xx/mpc834x_sys.c +++ b/arch/powerpc/platforms/83xx/mpc834x_mds.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * arch/powerpc/platforms/83xx/mpc834x_sys.c | 2 | * arch/powerpc/platforms/83xx/mpc834x_mds.c |
3 | * | 3 | * |
4 | * MPC834x SYS board specific routines | 4 | * MPC834x MDS board specific routines |
5 | * | 5 | * |
6 | * Maintainer: Kumar Gala <galak@kernel.crashing.org> | 6 | * Maintainer: Kumar Gala <galak@kernel.crashing.org> |
7 | * | 7 | * |
@@ -43,28 +43,88 @@ unsigned long isa_io_base = 0; | |||
43 | unsigned long isa_mem_base = 0; | 43 | unsigned long isa_mem_base = 0; |
44 | #endif | 44 | #endif |
45 | 45 | ||
46 | #define BCSR5_INT_USB 0x02 | ||
47 | /* Note: This is only for PB, not for PB+PIB | ||
48 | * On PB only port0 is connected using ULPI */ | ||
49 | static int mpc834x_usb_cfg(void) | ||
50 | { | ||
51 | unsigned long sccr, sicrl; | ||
52 | void __iomem *immap; | ||
53 | void __iomem *bcsr_regs = NULL; | ||
54 | u8 bcsr5; | ||
55 | struct device_node *np = NULL; | ||
56 | int port0_is_dr = 0; | ||
57 | |||
58 | if ((np = of_find_compatible_node(np, "usb", "fsl-usb2-dr")) != NULL) | ||
59 | port0_is_dr = 1; | ||
60 | if ((np = of_find_compatible_node(np, "usb", "fsl-usb2-mph")) != NULL){ | ||
61 | if (port0_is_dr) { | ||
62 | printk(KERN_WARNING | ||
63 | "There is only one USB port on PB board! \n"); | ||
64 | return -1; | ||
65 | } else if (!port0_is_dr) | ||
66 | /* No usb port enabled */ | ||
67 | return -1; | ||
68 | } | ||
69 | |||
70 | immap = ioremap(get_immrbase(), 0x1000); | ||
71 | if (!immap) | ||
72 | return -1; | ||
73 | |||
74 | /* Configure clock */ | ||
75 | sccr = in_be32(immap + MPC83XX_SCCR_OFFS); | ||
76 | if (port0_is_dr) | ||
77 | sccr |= MPC83XX_SCCR_USB_DRCM_11; /* 1:3 */ | ||
78 | else | ||
79 | sccr |= MPC83XX_SCCR_USB_MPHCM_11; /* 1:3 */ | ||
80 | out_be32(immap + MPC83XX_SCCR_OFFS, sccr); | ||
81 | |||
82 | /* Configure Pin */ | ||
83 | sicrl = in_be32(immap + MPC83XX_SICRL_OFFS); | ||
84 | /* set port0 only */ | ||
85 | if (port0_is_dr) | ||
86 | sicrl |= MPC83XX_SICRL_USB0; | ||
87 | else | ||
88 | sicrl &= ~(MPC83XX_SICRL_USB0); | ||
89 | out_be32(immap + MPC83XX_SICRL_OFFS, sicrl); | ||
90 | |||
91 | iounmap(immap); | ||
92 | |||
93 | /* Map BCSR area */ | ||
94 | np = of_find_node_by_name(NULL, "bcsr"); | ||
95 | if (np != 0) { | ||
96 | struct resource res; | ||
97 | |||
98 | of_address_to_resource(np, 0, &res); | ||
99 | bcsr_regs = ioremap(res.start, res.end - res.start + 1); | ||
100 | of_node_put(np); | ||
101 | } | ||
102 | if (!bcsr_regs) | ||
103 | return -1; | ||
104 | |||
105 | /* | ||
106 | * if MDS board is plug into PIB board, | ||
107 | * force to use the PHY on MDS board | ||
108 | */ | ||
109 | bcsr5 = in_8(bcsr_regs + 5); | ||
110 | if (!(bcsr5 & BCSR5_INT_USB)) | ||
111 | out_8(bcsr_regs + 5, (bcsr5 | BCSR5_INT_USB)); | ||
112 | iounmap(bcsr_regs); | ||
113 | return 0; | ||
114 | } | ||
115 | |||
46 | /* ************************************************************************ | 116 | /* ************************************************************************ |
47 | * | 117 | * |
48 | * Setup the architecture | 118 | * Setup the architecture |
49 | * | 119 | * |
50 | */ | 120 | */ |
51 | static void __init mpc834x_sys_setup_arch(void) | 121 | static void __init mpc834x_mds_setup_arch(void) |
52 | { | 122 | { |
53 | struct device_node *np; | 123 | struct device_node *np; |
54 | 124 | ||
55 | if (ppc_md.progress) | 125 | if (ppc_md.progress) |
56 | ppc_md.progress("mpc834x_sys_setup_arch()", 0); | 126 | ppc_md.progress("mpc834x_mds_setup_arch()", 0); |
57 | 127 | ||
58 | np = of_find_node_by_type(NULL, "cpu"); | ||
59 | if (np != 0) { | ||
60 | const unsigned int *fp = | ||
61 | get_property(np, "clock-frequency", NULL); | ||
62 | if (fp != 0) | ||
63 | loops_per_jiffy = *fp / HZ; | ||
64 | else | ||
65 | loops_per_jiffy = 50000000 / HZ; | ||
66 | of_node_put(np); | ||
67 | } | ||
68 | #ifdef CONFIG_PCI | 128 | #ifdef CONFIG_PCI |
69 | for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) | 129 | for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) |
70 | add_bridge(np); | 130 | add_bridge(np); |
@@ -72,14 +132,10 @@ static void __init mpc834x_sys_setup_arch(void) | |||
72 | ppc_md.pci_exclude_device = mpc83xx_exclude_device; | 132 | ppc_md.pci_exclude_device = mpc83xx_exclude_device; |
73 | #endif | 133 | #endif |
74 | 134 | ||
75 | #ifdef CONFIG_ROOT_NFS | 135 | mpc834x_usb_cfg(); |
76 | ROOT_DEV = Root_NFS; | ||
77 | #else | ||
78 | ROOT_DEV = Root_HDA1; | ||
79 | #endif | ||
80 | } | 136 | } |
81 | 137 | ||
82 | void __init mpc834x_sys_init_IRQ(void) | 138 | static void __init mpc834x_mds_init_IRQ(void) |
83 | { | 139 | { |
84 | struct device_node *np; | 140 | struct device_node *np; |
85 | 141 | ||
@@ -103,6 +159,9 @@ static int __init mpc834x_rtc_hookup(void) | |||
103 | { | 159 | { |
104 | struct timespec tv; | 160 | struct timespec tv; |
105 | 161 | ||
162 | if (!machine_is(mpc834x_mds)) | ||
163 | return 0; | ||
164 | |||
106 | ppc_md.get_rtc_time = ds1374_get_rtc_time; | 165 | ppc_md.get_rtc_time = ds1374_get_rtc_time; |
107 | ppc_md.set_rtc_time = ds1374_set_rtc_time; | 166 | ppc_md.set_rtc_time = ds1374_set_rtc_time; |
108 | 167 | ||
@@ -119,19 +178,18 @@ late_initcall(mpc834x_rtc_hookup); | |||
119 | /* | 178 | /* |
120 | * Called very early, MMU is off, device-tree isn't unflattened | 179 | * Called very early, MMU is off, device-tree isn't unflattened |
121 | */ | 180 | */ |
122 | static int __init mpc834x_sys_probe(void) | 181 | static int __init mpc834x_mds_probe(void) |
123 | { | 182 | { |
124 | /* We always match for now, eventually we should look at the flat | 183 | unsigned long root = of_get_flat_dt_root(); |
125 | dev tree to ensure this is the board we are suppose to run on | 184 | |
126 | */ | 185 | return of_flat_dt_is_compatible(root, "MPC834xMDS"); |
127 | return 1; | ||
128 | } | 186 | } |
129 | 187 | ||
130 | define_machine(mpc834x_sys) { | 188 | define_machine(mpc834x_mds) { |
131 | .name = "MPC834x SYS", | 189 | .name = "MPC834x MDS", |
132 | .probe = mpc834x_sys_probe, | 190 | .probe = mpc834x_mds_probe, |
133 | .setup_arch = mpc834x_sys_setup_arch, | 191 | .setup_arch = mpc834x_mds_setup_arch, |
134 | .init_IRQ = mpc834x_sys_init_IRQ, | 192 | .init_IRQ = mpc834x_mds_init_IRQ, |
135 | .get_irq = ipic_get_irq, | 193 | .get_irq = ipic_get_irq, |
136 | .restart = mpc83xx_restart, | 194 | .restart = mpc83xx_restart, |
137 | .time_init = mpc83xx_time_init, | 195 | .time_init = mpc83xx_time_init, |
diff --git a/arch/powerpc/platforms/83xx/mpc834x_sys.h b/arch/powerpc/platforms/83xx/mpc834x_sys.h deleted file mode 100644 index 7d5bbef084e7..000000000000 --- a/arch/powerpc/platforms/83xx/mpc834x_sys.h +++ /dev/null | |||
@@ -1,23 +0,0 @@ | |||
1 | /* | ||
2 | * arch/powerpc/platforms/83xx/mpc834x_sys.h | ||
3 | * | ||
4 | * MPC834X SYS common board definitions | ||
5 | * | ||
6 | * Maintainer: Kumar Gala <galak@kernel.crashing.org> | ||
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 | |||
15 | #ifndef __MACH_MPC83XX_SYS_H__ | ||
16 | #define __MACH_MPC83XX_SYS_H__ | ||
17 | |||
18 | #define PIRQA MPC83xx_IRQ_EXT4 | ||
19 | #define PIRQB MPC83xx_IRQ_EXT5 | ||
20 | #define PIRQC MPC83xx_IRQ_EXT6 | ||
21 | #define PIRQD MPC83xx_IRQ_EXT7 | ||
22 | |||
23 | #endif /* __MACH_MPC83XX_SYS_H__ */ | ||
diff --git a/arch/powerpc/platforms/83xx/mpc8360e_pb.c b/arch/powerpc/platforms/83xx/mpc836x_mds.c index 53b92a904e8e..526ed090a446 100644 --- a/arch/powerpc/platforms/83xx/mpc8360e_pb.c +++ b/arch/powerpc/platforms/83xx/mpc836x_mds.c | |||
@@ -5,12 +5,12 @@ | |||
5 | * Yin Olivia <Hong-hua.Yin@freescale.com> | 5 | * Yin Olivia <Hong-hua.Yin@freescale.com> |
6 | * | 6 | * |
7 | * Description: | 7 | * Description: |
8 | * MPC8360E MDS PB board specific routines. | 8 | * MPC8360E MDS board specific routines. |
9 | * | 9 | * |
10 | * Changelog: | 10 | * Changelog: |
11 | * Jun 21, 2006 Initial version | 11 | * Jun 21, 2006 Initial version |
12 | * | 12 | * |
13 | * This program is free software; you can redistribute it and/or modify it | 13 | * This program is free software; you can redistribute it and/or modify it |
14 | * under the terms of the GNU General Public License as published by the | 14 | * under the terms of the GNU General Public License as published by the |
15 | * Free Software Foundation; either version 2 of the License, or (at your | 15 | * Free Software Foundation; either version 2 of the License, or (at your |
16 | * option) any later version. | 16 | * option) any later version. |
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/initrd.h> | 31 | #include <linux/initrd.h> |
32 | 32 | ||
33 | #include <asm/of_device.h> | 33 | #include <asm/of_device.h> |
34 | #include <asm/of_platform.h> | ||
34 | #include <asm/system.h> | 35 | #include <asm/system.h> |
35 | #include <asm/atomic.h> | 36 | #include <asm/atomic.h> |
36 | #include <asm/time.h> | 37 | #include <asm/time.h> |
@@ -61,33 +62,17 @@ unsigned long isa_mem_base = 0; | |||
61 | 62 | ||
62 | static u8 *bcsr_regs = NULL; | 63 | static u8 *bcsr_regs = NULL; |
63 | 64 | ||
64 | u8 *get_bcsr(void) | ||
65 | { | ||
66 | return bcsr_regs; | ||
67 | } | ||
68 | |||
69 | /* ************************************************************************ | 65 | /* ************************************************************************ |
70 | * | 66 | * |
71 | * Setup the architecture | 67 | * Setup the architecture |
72 | * | 68 | * |
73 | */ | 69 | */ |
74 | static void __init mpc8360_sys_setup_arch(void) | 70 | static void __init mpc836x_mds_setup_arch(void) |
75 | { | 71 | { |
76 | struct device_node *np; | 72 | struct device_node *np; |
77 | 73 | ||
78 | if (ppc_md.progress) | 74 | if (ppc_md.progress) |
79 | ppc_md.progress("mpc8360_sys_setup_arch()", 0); | 75 | ppc_md.progress("mpc836x_mds_setup_arch()", 0); |
80 | |||
81 | np = of_find_node_by_type(NULL, "cpu"); | ||
82 | if (np != 0) { | ||
83 | const unsigned int *fp = | ||
84 | get_property(np, "clock-frequency", NULL); | ||
85 | if (fp != 0) | ||
86 | loops_per_jiffy = *fp / HZ; | ||
87 | else | ||
88 | loops_per_jiffy = 50000000 / HZ; | ||
89 | of_node_put(np); | ||
90 | } | ||
91 | 76 | ||
92 | /* Map BCSR area */ | 77 | /* Map BCSR area */ |
93 | np = of_find_node_by_name(NULL, "bcsr"); | 78 | np = of_find_node_by_name(NULL, "bcsr"); |
@@ -127,40 +112,29 @@ static void __init mpc8360_sys_setup_arch(void) | |||
127 | } | 112 | } |
128 | 113 | ||
129 | #endif /* CONFIG_QUICC_ENGINE */ | 114 | #endif /* CONFIG_QUICC_ENGINE */ |
130 | |||
131 | #ifdef CONFIG_BLK_DEV_INITRD | ||
132 | if (initrd_start) | ||
133 | ROOT_DEV = Root_RAM0; | ||
134 | else | ||
135 | #endif | ||
136 | #ifdef CONFIG_ROOT_NFS | ||
137 | ROOT_DEV = Root_NFS; | ||
138 | #else | ||
139 | ROOT_DEV = Root_HDA1; | ||
140 | #endif | ||
141 | } | 115 | } |
142 | 116 | ||
143 | static int __init mpc8360_declare_of_platform_devices(void) | 117 | static struct of_device_id mpc836x_ids[] = { |
144 | { | 118 | { .type = "soc", }, |
145 | struct device_node *np; | 119 | { .compatible = "soc", }, |
120 | { .type = "qe", }, | ||
121 | {}, | ||
122 | }; | ||
146 | 123 | ||
147 | for (np = NULL; (np = of_find_compatible_node(np, "network", | 124 | static int __init mpc836x_declare_of_platform_devices(void) |
148 | "ucc_geth")) != NULL;) { | 125 | { |
149 | int ucc_num; | 126 | if (!machine_is(mpc836x_mds)) |
150 | char bus_id[BUS_ID_SIZE]; | 127 | return 0; |
151 | 128 | ||
152 | ucc_num = *((uint *) get_property(np, "device-id", NULL)) - 1; | 129 | /* Publish the QE devices */ |
153 | snprintf(bus_id, BUS_ID_SIZE, "ucc_geth.%u", ucc_num); | 130 | of_platform_bus_probe(NULL, mpc836x_ids, NULL); |
154 | of_platform_device_create(np, bus_id, NULL); | ||
155 | } | ||
156 | 131 | ||
157 | return 0; | 132 | return 0; |
158 | } | 133 | } |
159 | device_initcall(mpc8360_declare_of_platform_devices); | 134 | device_initcall(mpc836x_declare_of_platform_devices); |
160 | 135 | ||
161 | void __init mpc8360_sys_init_IRQ(void) | 136 | static void __init mpc836x_mds_init_IRQ(void) |
162 | { | 137 | { |
163 | |||
164 | struct device_node *np; | 138 | struct device_node *np; |
165 | 139 | ||
166 | np = of_find_node_by_type(NULL, "ipic"); | 140 | np = of_find_node_by_type(NULL, "ipic"); |
@@ -193,6 +167,9 @@ static int __init mpc8360_rtc_hookup(void) | |||
193 | { | 167 | { |
194 | struct timespec tv; | 168 | struct timespec tv; |
195 | 169 | ||
170 | if (!machine_is(mpc836x_mds)) | ||
171 | return 0; | ||
172 | |||
196 | ppc_md.get_rtc_time = ds1374_get_rtc_time; | 173 | ppc_md.get_rtc_time = ds1374_get_rtc_time; |
197 | ppc_md.set_rtc_time = ds1374_set_rtc_time; | 174 | ppc_md.set_rtc_time = ds1374_set_rtc_time; |
198 | 175 | ||
@@ -209,28 +186,21 @@ late_initcall(mpc8360_rtc_hookup); | |||
209 | /* | 186 | /* |
210 | * Called very early, MMU is off, device-tree isn't unflattened | 187 | * Called very early, MMU is off, device-tree isn't unflattened |
211 | */ | 188 | */ |
212 | static int __init mpc8360_sys_probe(void) | 189 | static int __init mpc836x_mds_probe(void) |
213 | { | 190 | { |
214 | char *model = of_get_flat_dt_prop(of_get_flat_dt_root(), | 191 | unsigned long root = of_get_flat_dt_root(); |
215 | "model", NULL); | ||
216 | if (model == NULL) | ||
217 | return 0; | ||
218 | if (strcmp(model, "MPC8360EPB")) | ||
219 | return 0; | ||
220 | |||
221 | DBG("MPC8360EMDS-PB found\n"); | ||
222 | 192 | ||
223 | return 1; | 193 | return of_flat_dt_is_compatible(root, "MPC836xMDS"); |
224 | } | 194 | } |
225 | 195 | ||
226 | define_machine(mpc8360_sys) { | 196 | define_machine(mpc836x_mds) { |
227 | .name = "MPC8360E PB", | 197 | .name = "MPC836x MDS", |
228 | .probe = mpc8360_sys_probe, | 198 | .probe = mpc836x_mds_probe, |
229 | .setup_arch = mpc8360_sys_setup_arch, | 199 | .setup_arch = mpc836x_mds_setup_arch, |
230 | .init_IRQ = mpc8360_sys_init_IRQ, | 200 | .init_IRQ = mpc836x_mds_init_IRQ, |
231 | .get_irq = ipic_get_irq, | 201 | .get_irq = ipic_get_irq, |
232 | .restart = mpc83xx_restart, | 202 | .restart = mpc83xx_restart, |
233 | .time_init = mpc83xx_time_init, | 203 | .time_init = mpc83xx_time_init, |
234 | .calibrate_decr = generic_calibrate_decr, | 204 | .calibrate_decr = generic_calibrate_decr, |
235 | .progress = udbg_progress, | 205 | .progress = udbg_progress, |
236 | }; | 206 | }; |
diff --git a/arch/powerpc/platforms/83xx/mpc83xx.h b/arch/powerpc/platforms/83xx/mpc83xx.h index 01cae106912b..9cd03b59c8f4 100644 --- a/arch/powerpc/platforms/83xx/mpc83xx.h +++ b/arch/powerpc/platforms/83xx/mpc83xx.h | |||
@@ -4,6 +4,24 @@ | |||
4 | #include <linux/init.h> | 4 | #include <linux/init.h> |
5 | #include <linux/device.h> | 5 | #include <linux/device.h> |
6 | 6 | ||
7 | /* System Clock Control Register */ | ||
8 | #define MPC83XX_SCCR_OFFS 0xA08 | ||
9 | #define MPC83XX_SCCR_USB_MPHCM_11 0x00c00000 | ||
10 | #define MPC83XX_SCCR_USB_MPHCM_01 0x00400000 | ||
11 | #define MPC83XX_SCCR_USB_MPHCM_10 0x00800000 | ||
12 | #define MPC83XX_SCCR_USB_DRCM_11 0x00300000 | ||
13 | #define MPC83XX_SCCR_USB_DRCM_01 0x00100000 | ||
14 | #define MPC83XX_SCCR_USB_DRCM_10 0x00200000 | ||
15 | |||
16 | /* system i/o configuration register low */ | ||
17 | #define MPC83XX_SICRL_OFFS 0x114 | ||
18 | #define MPC83XX_SICRL_USB0 0x40000000 | ||
19 | #define MPC83XX_SICRL_USB1 0x20000000 | ||
20 | |||
21 | /* system i/o configuration register high */ | ||
22 | #define MPC83XX_SICRH_OFFS 0x118 | ||
23 | #define MPC83XX_SICRH_USB_UTMI 0x00020000 | ||
24 | |||
7 | /* | 25 | /* |
8 | * Declaration for the various functions exported by the | 26 | * Declaration for the various functions exported by the |
9 | * mpc83xx_* files. Mostly for use by mpc83xx_setup | 27 | * mpc83xx_* files. Mostly for use by mpc83xx_setup |
diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig index 0584f3c7e884..eb661ccf2dab 100644 --- a/arch/powerpc/platforms/85xx/Kconfig +++ b/arch/powerpc/platforms/85xx/Kconfig | |||
@@ -23,6 +23,13 @@ config MPC85xx_CDS | |||
23 | help | 23 | help |
24 | This option enables support for the MPC85xx CDS board | 24 | This option enables support for the MPC85xx CDS board |
25 | 25 | ||
26 | config MPC85xx_MDS | ||
27 | bool "Freescale MPC85xx MDS" | ||
28 | select DEFAULT_UIMAGE | ||
29 | # select QUICC_ENGINE | ||
30 | help | ||
31 | This option enables support for the MPC85xx MDS board | ||
32 | |||
26 | endchoice | 33 | endchoice |
27 | 34 | ||
28 | config MPC8540 | 35 | config MPC8540 |
@@ -36,6 +43,12 @@ config MPC8560 | |||
36 | select PPC_INDIRECT_PCI | 43 | select PPC_INDIRECT_PCI |
37 | default y if MPC8560_ADS | 44 | default y if MPC8560_ADS |
38 | 45 | ||
46 | config MPC85xx | ||
47 | bool | ||
48 | select PPC_UDBG_16550 | ||
49 | select PPC_INDIRECT_PCI | ||
50 | default y if MPC8540_ADS || MPC85xx_CDS || MPC8560_ADS || MPC85xx_MDS | ||
51 | |||
39 | config PPC_INDIRECT_PCI_BE | 52 | config PPC_INDIRECT_PCI_BE |
40 | bool | 53 | bool |
41 | depends on PPC_85xx | 54 | depends on PPC_85xx |
diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile index 282f5d0d0152..4e63917ada9d 100644 --- a/arch/powerpc/platforms/85xx/Makefile +++ b/arch/powerpc/platforms/85xx/Makefile | |||
@@ -5,3 +5,4 @@ obj-$(CONFIG_PPC_85xx) += misc.o pci.o | |||
5 | obj-$(CONFIG_MPC8540_ADS) += mpc85xx_ads.o | 5 | obj-$(CONFIG_MPC8540_ADS) += mpc85xx_ads.o |
6 | obj-$(CONFIG_MPC8560_ADS) += mpc85xx_ads.o | 6 | obj-$(CONFIG_MPC8560_ADS) += mpc85xx_ads.o |
7 | obj-$(CONFIG_MPC85xx_CDS) += mpc85xx_cds.o | 7 | obj-$(CONFIG_MPC85xx_CDS) += mpc85xx_cds.o |
8 | obj-$(CONFIG_MPC85xx_MDS) += mpc85xx_mds.o | ||
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c index bda2e55e6c4c..8ed034aeca5f 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c | |||
@@ -17,7 +17,6 @@ | |||
17 | #include <linux/kdev_t.h> | 17 | #include <linux/kdev_t.h> |
18 | #include <linux/delay.h> | 18 | #include <linux/delay.h> |
19 | #include <linux/seq_file.h> | 19 | #include <linux/seq_file.h> |
20 | #include <linux/root_dev.h> | ||
21 | 20 | ||
22 | #include <asm/system.h> | 21 | #include <asm/system.h> |
23 | #include <asm/time.h> | 22 | #include <asm/time.h> |
@@ -45,8 +44,7 @@ unsigned long isa_mem_base = 0; | |||
45 | #endif | 44 | #endif |
46 | 45 | ||
47 | #ifdef CONFIG_PCI | 46 | #ifdef CONFIG_PCI |
48 | int | 47 | static int mpc85xx_exclude_device(u_char bus, u_char devfn) |
49 | mpc85xx_exclude_device(u_char bus, u_char devfn) | ||
50 | { | 48 | { |
51 | if (bus == 0 && PCI_SLOT(devfn) == 0) | 49 | if (bus == 0 && PCI_SLOT(devfn) == 0) |
52 | return PCIBIOS_DEVICE_NOT_FOUND; | 50 | return PCIBIOS_DEVICE_NOT_FOUND; |
@@ -69,7 +67,7 @@ static void cpm2_cascade(unsigned int irq, struct irq_desc *desc) | |||
69 | 67 | ||
70 | #endif /* CONFIG_CPM2 */ | 68 | #endif /* CONFIG_CPM2 */ |
71 | 69 | ||
72 | void __init mpc85xx_ads_pic_init(void) | 70 | static void __init mpc85xx_ads_pic_init(void) |
73 | { | 71 | { |
74 | struct mpic *mpic; | 72 | struct mpic *mpic; |
75 | struct resource r; | 73 | struct resource r; |
@@ -246,15 +244,9 @@ static void __init mpc85xx_ads_setup_arch(void) | |||
246 | add_bridge(np); | 244 | add_bridge(np); |
247 | ppc_md.pci_exclude_device = mpc85xx_exclude_device; | 245 | ppc_md.pci_exclude_device = mpc85xx_exclude_device; |
248 | #endif | 246 | #endif |
249 | |||
250 | #ifdef CONFIG_ROOT_NFS | ||
251 | ROOT_DEV = Root_NFS; | ||
252 | #else | ||
253 | ROOT_DEV = Root_HDA1; | ||
254 | #endif | ||
255 | } | 247 | } |
256 | 248 | ||
257 | void mpc85xx_ads_show_cpuinfo(struct seq_file *m) | 249 | static void mpc85xx_ads_show_cpuinfo(struct seq_file *m) |
258 | { | 250 | { |
259 | uint pvid, svid, phid1; | 251 | uint pvid, svid, phid1; |
260 | uint memsize = total_memory; | 252 | uint memsize = total_memory; |
@@ -280,10 +272,9 @@ void mpc85xx_ads_show_cpuinfo(struct seq_file *m) | |||
280 | */ | 272 | */ |
281 | static int __init mpc85xx_ads_probe(void) | 273 | static int __init mpc85xx_ads_probe(void) |
282 | { | 274 | { |
283 | /* We always match for now, eventually we should look at the flat | 275 | unsigned long root = of_get_flat_dt_root(); |
284 | dev tree to ensure this is the board we are suppose to run on | 276 | |
285 | */ | 277 | return of_flat_dt_is_compatible(root, "MPC85xxADS"); |
286 | return 1; | ||
287 | } | 278 | } |
288 | 279 | ||
289 | define_machine(mpc85xx_ads) { | 280 | define_machine(mpc85xx_ads) { |
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c index 953cd5dd3f54..4232686be441 100644 --- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c +++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c | |||
@@ -22,7 +22,6 @@ | |||
22 | #include <linux/console.h> | 22 | #include <linux/console.h> |
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> | ||
26 | #include <linux/initrd.h> | 25 | #include <linux/initrd.h> |
27 | #include <linux/module.h> | 26 | #include <linux/module.h> |
28 | #include <linux/fsl_devices.h> | 27 | #include <linux/fsl_devices.h> |
@@ -56,7 +55,6 @@ unsigned long isa_mem_base = 0; | |||
56 | static int cds_pci_slot = 2; | 55 | static int cds_pci_slot = 2; |
57 | static volatile u8 *cadmus; | 56 | static volatile u8 *cadmus; |
58 | 57 | ||
59 | |||
60 | #ifdef CONFIG_PCI | 58 | #ifdef CONFIG_PCI |
61 | 59 | ||
62 | #define ARCADIA_HOST_BRIDGE_IDSEL 17 | 60 | #define ARCADIA_HOST_BRIDGE_IDSEL 17 |
@@ -64,8 +62,7 @@ static volatile u8 *cadmus; | |||
64 | 62 | ||
65 | extern int mpc85xx_pci2_busno; | 63 | extern int mpc85xx_pci2_busno; |
66 | 64 | ||
67 | int | 65 | static int mpc85xx_exclude_device(u_char bus, u_char devfn) |
68 | mpc85xx_exclude_device(u_char bus, u_char devfn) | ||
69 | { | 66 | { |
70 | if (bus == 0 && PCI_SLOT(devfn) == 0) | 67 | if (bus == 0 && PCI_SLOT(devfn) == 0) |
71 | return PCIBIOS_DEVICE_NOT_FOUND; | 68 | return PCIBIOS_DEVICE_NOT_FOUND; |
@@ -81,8 +78,7 @@ mpc85xx_exclude_device(u_char bus, u_char devfn) | |||
81 | return PCIBIOS_SUCCESSFUL; | 78 | return PCIBIOS_SUCCESSFUL; |
82 | } | 79 | } |
83 | 80 | ||
84 | void __init | 81 | static void __init mpc85xx_cds_pcibios_fixup(void) |
85 | mpc85xx_cds_pcibios_fixup(void) | ||
86 | { | 82 | { |
87 | struct pci_dev *dev; | 83 | struct pci_dev *dev; |
88 | u_char c; | 84 | u_char c; |
@@ -144,7 +140,7 @@ static void mpc85xx_8259_cascade(unsigned int irq, struct irq_desc *desc) | |||
144 | #endif /* PPC_I8259 */ | 140 | #endif /* PPC_I8259 */ |
145 | #endif /* CONFIG_PCI */ | 141 | #endif /* CONFIG_PCI */ |
146 | 142 | ||
147 | void __init mpc85xx_cds_pic_init(void) | 143 | static void __init mpc85xx_cds_pic_init(void) |
148 | { | 144 | { |
149 | struct mpic *mpic; | 145 | struct mpic *mpic; |
150 | struct resource r; | 146 | struct resource r; |
@@ -224,12 +220,10 @@ void __init mpc85xx_cds_pic_init(void) | |||
224 | #endif /* CONFIG_PPC_I8259 */ | 220 | #endif /* CONFIG_PPC_I8259 */ |
225 | } | 221 | } |
226 | 222 | ||
227 | |||
228 | /* | 223 | /* |
229 | * Setup the architecture | 224 | * Setup the architecture |
230 | */ | 225 | */ |
231 | static void __init | 226 | static void __init mpc85xx_cds_setup_arch(void) |
232 | mpc85xx_cds_setup_arch(void) | ||
233 | { | 227 | { |
234 | struct device_node *cpu; | 228 | struct device_node *cpu; |
235 | #ifdef CONFIG_PCI | 229 | #ifdef CONFIG_PCI |
@@ -268,17 +262,9 @@ mpc85xx_cds_setup_arch(void) | |||
268 | ppc_md.pcibios_fixup = mpc85xx_cds_pcibios_fixup; | 262 | ppc_md.pcibios_fixup = mpc85xx_cds_pcibios_fixup; |
269 | ppc_md.pci_exclude_device = mpc85xx_exclude_device; | 263 | ppc_md.pci_exclude_device = mpc85xx_exclude_device; |
270 | #endif | 264 | #endif |
271 | |||
272 | #ifdef CONFIG_ROOT_NFS | ||
273 | ROOT_DEV = Root_NFS; | ||
274 | #else | ||
275 | ROOT_DEV = Root_HDA1; | ||
276 | #endif | ||
277 | } | 265 | } |
278 | 266 | ||
279 | 267 | static void mpc85xx_cds_show_cpuinfo(struct seq_file *m) | |
280 | void | ||
281 | mpc85xx_cds_show_cpuinfo(struct seq_file *m) | ||
282 | { | 268 | { |
283 | uint pvid, svid, phid1; | 269 | uint pvid, svid, phid1; |
284 | uint memsize = total_memory; | 270 | uint memsize = total_memory; |
@@ -305,11 +291,9 @@ mpc85xx_cds_show_cpuinfo(struct seq_file *m) | |||
305 | */ | 291 | */ |
306 | static int __init mpc85xx_cds_probe(void) | 292 | static int __init mpc85xx_cds_probe(void) |
307 | { | 293 | { |
308 | /* We always match for now, eventually we should look at | 294 | unsigned long root = of_get_flat_dt_root(); |
309 | * the flat dev tree to ensure this is the board we are | 295 | |
310 | * supposed to run on | 296 | return of_flat_dt_is_compatible(root, "MPC85xxCDS"); |
311 | */ | ||
312 | return 1; | ||
313 | } | 297 | } |
314 | 298 | ||
315 | define_machine(mpc85xx_cds) { | 299 | define_machine(mpc85xx_cds) { |
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c new file mode 100644 index 000000000000..81144d2ae455 --- /dev/null +++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c | |||
@@ -0,0 +1,234 @@ | |||
1 | /* | ||
2 | * Copyright (C) Freescale Semicondutor, Inc. 2006-2007. All rights reserved. | ||
3 | * | ||
4 | * Author: Andy Fleming <afleming@freescale.com> | ||
5 | * | ||
6 | * Based on 83xx/mpc8360e_pb.c by: | ||
7 | * Li Yang <LeoLi@freescale.com> | ||
8 | * Yin Olivia <Hong-hua.Yin@freescale.com> | ||
9 | * | ||
10 | * Description: | ||
11 | * MPC85xx MDS board specific routines. | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify it | ||
14 | * under the terms of the GNU General Public License as published by the | ||
15 | * Free Software Foundation; either version 2 of the License, or (at your | ||
16 | * option) any later version. | ||
17 | */ | ||
18 | |||
19 | #include <linux/stddef.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/errno.h> | ||
23 | #include <linux/reboot.h> | ||
24 | #include <linux/pci.h> | ||
25 | #include <linux/kdev_t.h> | ||
26 | #include <linux/major.h> | ||
27 | #include <linux/console.h> | ||
28 | #include <linux/delay.h> | ||
29 | #include <linux/seq_file.h> | ||
30 | #include <linux/initrd.h> | ||
31 | #include <linux/module.h> | ||
32 | #include <linux/fsl_devices.h> | ||
33 | |||
34 | #include <asm/of_device.h> | ||
35 | #include <asm/of_platform.h> | ||
36 | #include <asm/system.h> | ||
37 | #include <asm/atomic.h> | ||
38 | #include <asm/time.h> | ||
39 | #include <asm/io.h> | ||
40 | #include <asm/machdep.h> | ||
41 | #include <asm/bootinfo.h> | ||
42 | #include <asm/pci-bridge.h> | ||
43 | #include <asm/mpc85xx.h> | ||
44 | #include <asm/irq.h> | ||
45 | #include <mm/mmu_decl.h> | ||
46 | #include <asm/prom.h> | ||
47 | #include <asm/udbg.h> | ||
48 | #include <sysdev/fsl_soc.h> | ||
49 | #include <asm/qe.h> | ||
50 | #include <asm/qe_ic.h> | ||
51 | #include <asm/mpic.h> | ||
52 | |||
53 | #include "mpc85xx.h" | ||
54 | |||
55 | #undef DEBUG | ||
56 | #ifdef DEBUG | ||
57 | #define DBG(fmt...) udbg_printf(fmt) | ||
58 | #else | ||
59 | #define DBG(fmt...) | ||
60 | #endif | ||
61 | |||
62 | #ifndef CONFIG_PCI | ||
63 | unsigned long isa_io_base = 0; | ||
64 | unsigned long isa_mem_base = 0; | ||
65 | #endif | ||
66 | |||
67 | /* ************************************************************************ | ||
68 | * | ||
69 | * Setup the architecture | ||
70 | * | ||
71 | */ | ||
72 | static void __init mpc85xx_mds_setup_arch(void) | ||
73 | { | ||
74 | struct device_node *np; | ||
75 | static u8 *bcsr_regs = NULL; | ||
76 | |||
77 | if (ppc_md.progress) | ||
78 | ppc_md.progress("mpc85xx_mds_setup_arch()", 0); | ||
79 | |||
80 | np = of_find_node_by_type(NULL, "cpu"); | ||
81 | if (np != NULL) { | ||
82 | const unsigned int *fp = | ||
83 | get_property(np, "clock-frequency", NULL); | ||
84 | if (fp != NULL) | ||
85 | loops_per_jiffy = *fp / HZ; | ||
86 | else | ||
87 | loops_per_jiffy = 50000000 / HZ; | ||
88 | of_node_put(np); | ||
89 | } | ||
90 | |||
91 | /* Map BCSR area */ | ||
92 | np = of_find_node_by_name(NULL, "bcsr"); | ||
93 | if (np != NULL) { | ||
94 | struct resource res; | ||
95 | |||
96 | of_address_to_resource(np, 0, &res); | ||
97 | bcsr_regs = ioremap(res.start, res.end - res.start +1); | ||
98 | of_node_put(np); | ||
99 | } | ||
100 | |||
101 | #ifdef CONFIG_PCI | ||
102 | for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) { | ||
103 | add_bridge(np); | ||
104 | } | ||
105 | of_node_put(np); | ||
106 | #endif | ||
107 | |||
108 | #ifdef CONFIG_QUICC_ENGINE | ||
109 | if ((np = of_find_node_by_name(NULL, "qe")) != NULL) { | ||
110 | qe_reset(); | ||
111 | of_node_put(np); | ||
112 | } | ||
113 | |||
114 | if ((np = of_find_node_by_name(NULL, "par_io")) != NULL) { | ||
115 | struct device_node *ucc = NULL; | ||
116 | |||
117 | par_io_init(np); | ||
118 | of_node_put(np); | ||
119 | |||
120 | for ( ;(ucc = of_find_node_by_name(ucc, "ucc")) != NULL;) | ||
121 | par_io_of_config(ucc); | ||
122 | |||
123 | of_node_put(ucc); | ||
124 | } | ||
125 | |||
126 | if (bcsr_regs) { | ||
127 | u8 bcsr_phy; | ||
128 | |||
129 | /* Reset the Ethernet PHY */ | ||
130 | bcsr_phy = in_be8(&bcsr_regs[9]); | ||
131 | bcsr_phy &= ~0x20; | ||
132 | out_be8(&bcsr_regs[9], bcsr_phy); | ||
133 | |||
134 | udelay(1000); | ||
135 | |||
136 | bcsr_phy = in_be8(&bcsr_regs[9]); | ||
137 | bcsr_phy |= 0x20; | ||
138 | out_be8(&bcsr_regs[9], bcsr_phy); | ||
139 | |||
140 | iounmap(bcsr_regs); | ||
141 | } | ||
142 | |||
143 | #endif /* CONFIG_QUICC_ENGINE */ | ||
144 | } | ||
145 | |||
146 | static struct of_device_id mpc85xx_ids[] = { | ||
147 | { .type = "soc", }, | ||
148 | { .compatible = "soc", }, | ||
149 | { .type = "qe", }, | ||
150 | {}, | ||
151 | }; | ||
152 | |||
153 | static int __init mpc85xx_publish_devices(void) | ||
154 | { | ||
155 | if (!machine_is(mpc85xx_mds)) | ||
156 | return 0; | ||
157 | |||
158 | /* Publish the QE devices */ | ||
159 | of_platform_bus_probe(NULL,mpc85xx_ids,NULL); | ||
160 | |||
161 | return 0; | ||
162 | } | ||
163 | device_initcall(mpc85xx_publish_devices); | ||
164 | |||
165 | static void __init mpc85xx_mds_pic_init(void) | ||
166 | { | ||
167 | struct mpic *mpic; | ||
168 | struct resource r; | ||
169 | struct device_node *np = NULL; | ||
170 | |||
171 | np = of_find_node_by_type(NULL, "open-pic"); | ||
172 | if (!np) | ||
173 | return; | ||
174 | |||
175 | if (of_address_to_resource(np, 0, &r)) { | ||
176 | printk(KERN_ERR "Failed to map mpic register space\n"); | ||
177 | of_node_put(np); | ||
178 | return; | ||
179 | } | ||
180 | |||
181 | mpic = mpic_alloc(np, r.start, | ||
182 | MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN, | ||
183 | 4, 0, " OpenPIC "); | ||
184 | BUG_ON(mpic == NULL); | ||
185 | of_node_put(np); | ||
186 | |||
187 | /* Internal Interrupts */ | ||
188 | mpic_assign_isu(mpic, 0, r.start + 0x10200); | ||
189 | mpic_assign_isu(mpic, 1, r.start + 0x10280); | ||
190 | mpic_assign_isu(mpic, 2, r.start + 0x10300); | ||
191 | mpic_assign_isu(mpic, 3, r.start + 0x10380); | ||
192 | mpic_assign_isu(mpic, 4, r.start + 0x10400); | ||
193 | mpic_assign_isu(mpic, 5, r.start + 0x10480); | ||
194 | mpic_assign_isu(mpic, 6, r.start + 0x10500); | ||
195 | mpic_assign_isu(mpic, 7, r.start + 0x10580); | ||
196 | mpic_assign_isu(mpic, 8, r.start + 0x10600); | ||
197 | mpic_assign_isu(mpic, 9, r.start + 0x10680); | ||
198 | mpic_assign_isu(mpic, 10, r.start + 0x10700); | ||
199 | mpic_assign_isu(mpic, 11, r.start + 0x10780); | ||
200 | |||
201 | /* External Interrupts */ | ||
202 | mpic_assign_isu(mpic, 12, r.start + 0x10000); | ||
203 | mpic_assign_isu(mpic, 13, r.start + 0x10080); | ||
204 | mpic_assign_isu(mpic, 14, r.start + 0x10100); | ||
205 | |||
206 | mpic_init(mpic); | ||
207 | |||
208 | #ifdef CONFIG_QUICC_ENGINE | ||
209 | np = of_find_node_by_type(NULL, "qeic"); | ||
210 | if (!np) | ||
211 | return; | ||
212 | |||
213 | qe_ic_init(np, 0); | ||
214 | of_node_put(np); | ||
215 | #endif /* CONFIG_QUICC_ENGINE */ | ||
216 | } | ||
217 | |||
218 | static int __init mpc85xx_mds_probe(void) | ||
219 | { | ||
220 | unsigned long root = of_get_flat_dt_root(); | ||
221 | |||
222 | return of_flat_dt_is_compatible(root, "MPC85xxMDS"); | ||
223 | } | ||
224 | |||
225 | define_machine(mpc85xx_mds) { | ||
226 | .name = "MPC85xx MDS", | ||
227 | .probe = mpc85xx_mds_probe, | ||
228 | .setup_arch = mpc85xx_mds_setup_arch, | ||
229 | .init_IRQ = mpc85xx_mds_pic_init, | ||
230 | .get_irq = mpic_get_irq, | ||
231 | .restart = mpc85xx_restart, | ||
232 | .calibrate_decr = generic_calibrate_decr, | ||
233 | .progress = udbg_progress, | ||
234 | }; | ||
diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig index d1ecc0f9ab58..0c70944d0e37 100644 --- a/arch/powerpc/platforms/86xx/Kconfig +++ b/arch/powerpc/platforms/86xx/Kconfig | |||
@@ -8,6 +8,7 @@ choice | |||
8 | config MPC8641_HPCN | 8 | config MPC8641_HPCN |
9 | bool "Freescale MPC8641 HPCN" | 9 | bool "Freescale MPC8641 HPCN" |
10 | select PPC_I8259 | 10 | select PPC_I8259 |
11 | select DEFAULT_UIMAGE | ||
11 | help | 12 | help |
12 | This option enables support for the MPC8641 HPCN board. | 13 | This option enables support for the MPC8641 HPCN board. |
13 | 14 | ||
diff --git a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c index f4dd5f2f8a28..f42f801cf84e 100644 --- a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c +++ b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c | |||
@@ -18,7 +18,6 @@ | |||
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/root_dev.h> | ||
22 | 21 | ||
23 | #include <asm/system.h> | 22 | #include <asm/system.h> |
24 | #include <asm/time.h> | 23 | #include <asm/time.h> |
@@ -120,6 +119,8 @@ mpc86xx_hpcn_init_irq(void) | |||
120 | DBG("mpc86xxhpcn: cascade mapped to irq %d\n", cascade_irq); | 119 | DBG("mpc86xxhpcn: cascade mapped to irq %d\n", cascade_irq); |
121 | 120 | ||
122 | i8259_init(cascade_node, 0); | 121 | i8259_init(cascade_node, 0); |
122 | of_node_put(cascade_node); | ||
123 | |||
123 | set_irq_chained_handler(cascade_irq, mpc86xx_8259_cascade); | 124 | set_irq_chained_handler(cascade_irq, mpc86xx_8259_cascade); |
124 | #endif | 125 | #endif |
125 | } | 126 | } |
@@ -365,12 +366,6 @@ mpc86xx_hpcn_setup_arch(void) | |||
365 | 366 | ||
366 | printk("MPC86xx HPCN board from Freescale Semiconductor\n"); | 367 | printk("MPC86xx HPCN board from Freescale Semiconductor\n"); |
367 | 368 | ||
368 | #ifdef CONFIG_ROOT_NFS | ||
369 | ROOT_DEV = Root_NFS; | ||
370 | #else | ||
371 | ROOT_DEV = Root_HDA1; | ||
372 | #endif | ||
373 | |||
374 | #ifdef CONFIG_SMP | 369 | #ifdef CONFIG_SMP |
375 | mpc86xx_smp_init(); | 370 | mpc86xx_smp_init(); |
376 | #endif | 371 | #endif |
diff --git a/arch/powerpc/platforms/86xx/mpc86xx_smp.c b/arch/powerpc/platforms/86xx/mpc86xx_smp.c index bb7fb41933ad..7ef0c6854799 100644 --- a/arch/powerpc/platforms/86xx/mpc86xx_smp.c +++ b/arch/powerpc/platforms/86xx/mpc86xx_smp.c | |||
@@ -65,7 +65,6 @@ smp_86xx_kick_cpu(int nr) | |||
65 | pr_debug("smp_86xx_kick_cpu: kick CPU #%d\n", nr); | 65 | pr_debug("smp_86xx_kick_cpu: kick CPU #%d\n", nr); |
66 | 66 | ||
67 | local_irq_save(flags); | 67 | local_irq_save(flags); |
68 | local_irq_disable(); | ||
69 | 68 | ||
70 | /* Save reset vector */ | 69 | /* Save reset vector */ |
71 | save_vector = *vector; | 70 | save_vector = *vector; |
diff --git a/arch/powerpc/platforms/8xx/Kconfig b/arch/powerpc/platforms/8xx/Kconfig index c8c0ba3cf8e8..beea6834bb7e 100644 --- a/arch/powerpc/platforms/8xx/Kconfig +++ b/arch/powerpc/platforms/8xx/Kconfig | |||
@@ -1,105 +1,16 @@ | |||
1 | menu "Platform support" | ||
2 | depends on PPC_8xx | ||
3 | |||
1 | config FADS | 4 | config FADS |
2 | bool | 5 | bool |
3 | 6 | ||
7 | config CPM1 | ||
8 | bool | ||
9 | |||
4 | choice | 10 | choice |
5 | prompt "8xx Machine Type" | 11 | prompt "8xx Machine Type" |
6 | depends on 8xx | 12 | depends on 8xx |
7 | default RPXLITE | 13 | default MPC885ADS |
8 | |||
9 | config RPXLITE | ||
10 | bool "RPX-Lite" | ||
11 | ---help--- | ||
12 | Single-board computers based around the PowerPC MPC8xx chips and | ||
13 | intended for embedded applications. The following types are | ||
14 | supported: | ||
15 | |||
16 | RPX-Lite: | ||
17 | Embedded Planet RPX Lite. PC104 form-factor SBC based on the MPC823. | ||
18 | |||
19 | RPX-Classic: | ||
20 | Embedded Planet RPX Classic Low-fat. Credit-card-size SBC based on | ||
21 | the MPC 860 | ||
22 | |||
23 | BSE-IP: | ||
24 | Bright Star Engineering ip-Engine. | ||
25 | |||
26 | TQM823L: | ||
27 | TQM850L: | ||
28 | TQM855L: | ||
29 | TQM860L: | ||
30 | MPC8xx based family of mini modules, half credit card size, | ||
31 | up to 64 MB of RAM, 8 MB Flash, (Fast) Ethernet, 2 x serial ports, | ||
32 | 2 x CAN bus interface, ... | ||
33 | Manufacturer: TQ Components, www.tq-group.de | ||
34 | Date of Release: October (?) 1999 | ||
35 | End of Life: not yet :-) | ||
36 | URL: | ||
37 | - module: <http://www.denx.de/PDF/TQM8xxLHWM201.pdf> | ||
38 | - starter kit: <http://www.denx.de/PDF/STK8xxLHWM201.pdf> | ||
39 | - images: <http://www.denx.de/embedded-ppc-en.html> | ||
40 | |||
41 | FPS850L: | ||
42 | FingerPrint Sensor System (based on TQM850L) | ||
43 | Manufacturer: IKENDI AG, <http://www.ikendi.com/> | ||
44 | Date of Release: November 1999 | ||
45 | End of life: end 2000 ? | ||
46 | URL: see TQM850L | ||
47 | |||
48 | IVMS8: | ||
49 | MPC860 based board used in the "Integrated Voice Mail System", | ||
50 | Small Version (8 voice channels) | ||
51 | Manufacturer: Speech Design, <http://www.speech-design.de/> | ||
52 | Date of Release: December 2000 (?) | ||
53 | End of life: - | ||
54 | URL: <http://www.speech-design.de/> | ||
55 | |||
56 | IVML24: | ||
57 | MPC860 based board used in the "Integrated Voice Mail System", | ||
58 | Large Version (24 voice channels) | ||
59 | Manufacturer: Speech Design, <http://www.speech-design.de/> | ||
60 | Date of Release: March 2001 (?) | ||
61 | End of life: - | ||
62 | URL: <http://www.speech-design.de/> | ||
63 | |||
64 | HERMES: | ||
65 | Hermes-Pro ISDN/LAN router with integrated 8 x hub | ||
66 | Manufacturer: Multidata Gesellschaft fur Datentechnik und Informatik | ||
67 | <http://www.multidata.de/> | ||
68 | Date of Release: 2000 (?) | ||
69 | End of life: - | ||
70 | URL: <http://www.multidata.de/english/products/hpro.htm> | ||
71 | |||
72 | IP860: | ||
73 | VMEBus IP (Industry Pack) carrier board with MPC860 | ||
74 | Manufacturer: MicroSys GmbH, <http://www.microsys.de/> | ||
75 | Date of Release: ? | ||
76 | End of life: - | ||
77 | URL: <http://www.microsys.de/html/ip860.html> | ||
78 | |||
79 | PCU_E: | ||
80 | PCU = Peripheral Controller Unit, Extended | ||
81 | Manufacturer: Siemens AG, ICN (Information and Communication Networks) | ||
82 | <http://www.siemens.de/page/1,3771,224315-1-999_2_226207-0,00.html> | ||
83 | Date of Release: April 2001 | ||
84 | End of life: August 2001 | ||
85 | URL: n. a. | ||
86 | |||
87 | config RPXCLASSIC | ||
88 | bool "RPX-Classic" | ||
89 | help | ||
90 | The RPX-Classic is a single-board computer based on the Motorola | ||
91 | MPC860. It features 16MB of DRAM and a variable amount of flash, | ||
92 | I2C EEPROM, thermal monitoring, a PCMCIA slot, a DIP switch and two | ||
93 | LEDs. Variants with Ethernet ports exist. Say Y here to support it | ||
94 | directly. | ||
95 | |||
96 | config BSEIP | ||
97 | bool "BSE-IP" | ||
98 | help | ||
99 | Say Y here to support the Bright Star Engineering ipEngine SBC. | ||
100 | This is a credit-card-sized device featuring a MPC823 processor, | ||
101 | 26MB DRAM, 4MB flash, Ethernet, a 16K-gate FPGA, USB, an LCD/video | ||
102 | controller, and two RS232 ports. | ||
103 | 14 | ||
104 | config MPC8XXFADS | 15 | config MPC8XXFADS |
105 | bool "FADS" | 16 | bool "FADS" |
@@ -107,110 +18,58 @@ config MPC8XXFADS | |||
107 | 18 | ||
108 | config MPC86XADS | 19 | config MPC86XADS |
109 | bool "MPC86XADS" | 20 | bool "MPC86XADS" |
21 | select CPM1 | ||
110 | help | 22 | help |
111 | MPC86x Application Development System by Freescale Semiconductor. | 23 | MPC86x Application Development System by Freescale Semiconductor. |
112 | 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 |
113 | development around the MPC86X processor families. | 25 | development around the MPC86X processor families. |
114 | select FADS | ||
115 | 26 | ||
116 | config MPC885ADS | 27 | config MPC885ADS |
117 | bool "MPC885ADS" | 28 | bool "MPC885ADS" |
29 | select CPM1 | ||
118 | help | 30 | help |
119 | Freescale Semiconductor MPC885 Application Development System (ADS). | 31 | Freescale Semiconductor MPC885 Application Development System (ADS). |
120 | Also known as DUET. | 32 | Also known as DUET. |
121 | The MPC885ADS is meant to serve as a platform for s/w and h/w | 33 | The MPC885ADS is meant to serve as a platform for s/w and h/w |
122 | development around the MPC885 processor family. | 34 | development around the MPC885 processor family. |
123 | 35 | ||
124 | config TQM823L | 36 | endchoice |
125 | bool "TQM823L" | ||
126 | help | ||
127 | Say Y here to support the TQM823L, one of an MPC8xx-based family of | ||
128 | mini SBCs (half credit-card size) from TQ Components first released | ||
129 | in late 1999. Technical references are at | ||
130 | <http://www.denx.de/PDF/TQM8xxLHWM201.pdf>, and | ||
131 | <http://www.denx.de/PDF/STK8xxLHWM201.pdf>, and an image at | ||
132 | <http://www.denx.de/embedded-ppc-en.html>. | ||
133 | |||
134 | config TQM850L | ||
135 | bool "TQM850L" | ||
136 | help | ||
137 | Say Y here to support the TQM850L, one of an MPC8xx-based family of | ||
138 | mini SBCs (half credit-card size) from TQ Components first released | ||
139 | in late 1999. Technical references are at | ||
140 | <http://www.denx.de/PDF/TQM8xxLHWM201.pdf>, and | ||
141 | <http://www.denx.de/PDF/STK8xxLHWM201.pdf>, and an image at | ||
142 | <http://www.denx.de/embedded-ppc-en.html>. | ||
143 | |||
144 | config TQM855L | ||
145 | bool "TQM855L" | ||
146 | help | ||
147 | Say Y here to support the TQM855L, one of an MPC8xx-based family of | ||
148 | mini SBCs (half credit-card size) from TQ Components first released | ||
149 | in late 1999. Technical references are at | ||
150 | <http://www.denx.de/PDF/TQM8xxLHWM201.pdf>, and | ||
151 | <http://www.denx.de/PDF/STK8xxLHWM201.pdf>, and an image at | ||
152 | <http://www.denx.de/embedded-ppc-en.html>. | ||
153 | |||
154 | config TQM860L | ||
155 | bool "TQM860L" | ||
156 | help | ||
157 | Say Y here to support the TQM860L, one of an MPC8xx-based family of | ||
158 | mini SBCs (half credit-card size) from TQ Components first released | ||
159 | in late 1999. Technical references are at | ||
160 | <http://www.denx.de/PDF/TQM8xxLHWM201.pdf>, and | ||
161 | <http://www.denx.de/PDF/STK8xxLHWM201.pdf>, and an image at | ||
162 | <http://www.denx.de/embedded-ppc-en.html>. | ||
163 | |||
164 | config FPS850L | ||
165 | bool "FPS850L" | ||
166 | |||
167 | config IVMS8 | ||
168 | bool "IVMS8" | ||
169 | help | ||
170 | Say Y here to support the Integrated Voice-Mail Small 8-channel SBC | ||
171 | from Speech Design, released March 2001. The manufacturer's website | ||
172 | is at <http://www.speech-design.de/>. | ||
173 | |||
174 | config IVML24 | ||
175 | bool "IVML24" | ||
176 | help | ||
177 | Say Y here to support the Integrated Voice-Mail Large 24-channel SBC | ||
178 | from Speech Design, released March 2001. The manufacturer's website | ||
179 | is at <http://www.speech-design.de/>. | ||
180 | |||
181 | config HERMES_PRO | ||
182 | bool "HERMES" | ||
183 | |||
184 | config IP860 | ||
185 | bool "IP860" | ||
186 | |||
187 | config LWMON | ||
188 | bool "LWMON" | ||
189 | |||
190 | config PCU_E | ||
191 | bool "PCU_E" | ||
192 | |||
193 | config CCM | ||
194 | bool "CCM" | ||
195 | |||
196 | config LANTEC | ||
197 | bool "LANTEC" | ||
198 | 37 | ||
199 | config MBX | 38 | menu "Freescale Ethernet driver platform-specific options" |
200 | bool "MBX" | 39 | depends on (FS_ENET && MPC885ADS) |
201 | help | 40 | |
202 | MBX is a line of Motorola single-board computer based around the | 41 | config MPC8xx_SECOND_ETH |
203 | MPC821 and MPC860 processors, and intended for embedded-controller | 42 | bool "Second Ethernet channel" |
204 | applications. Say Y here to support these boards directly. | 43 | depends on MPC885ADS |
44 | default y | ||
45 | help | ||
46 | This enables support for second Ethernet on MPC885ADS and MPC86xADS boards. | ||
47 | The latter will use SCC1, for 885ADS you can select it below. | ||
48 | |||
49 | choice | ||
50 | prompt "Second Ethernet channel" | ||
51 | depends on MPC8xx_SECOND_ETH | ||
52 | default MPC8xx_SECOND_ETH_FEC2 | ||
53 | |||
54 | config MPC8xx_SECOND_ETH_FEC2 | ||
55 | bool "FEC2" | ||
56 | depends on MPC885ADS | ||
57 | help | ||
58 | Enable FEC2 to serve as 2-nd Ethernet channel. Note that SMC2 | ||
59 | (often 2-nd UART) will not work if this is enabled. | ||
60 | |||
61 | config MPC8xx_SECOND_ETH_SCC3 | ||
62 | bool "SCC3" | ||
63 | depends on MPC885ADS | ||
64 | help | ||
65 | Enable SCC3 to serve as 2-nd Ethernet channel. Note that SMC1 | ||
66 | (often 1-nd UART) will not work if this is enabled. | ||
67 | |||
68 | endchoice | ||
205 | 69 | ||
206 | config WINCEPT | 70 | endmenu |
207 | bool "WinCept" | ||
208 | help | ||
209 | The Wincept 100/110 is a Motorola single-board computer based on the | ||
210 | MPC821 PowerPC, introduced in 1998 and designed to be used in | ||
211 | thin-client machines. Say Y to support it directly. | ||
212 | 71 | ||
213 | endchoice | 72 | endmenu |
214 | 73 | ||
215 | # | 74 | # |
216 | # MPC8xx Communication options | 75 | # MPC8xx Communication options |
@@ -219,79 +78,6 @@ endchoice | |||
219 | menu "MPC8xx CPM Options" | 78 | menu "MPC8xx CPM Options" |
220 | depends on 8xx | 79 | depends on 8xx |
221 | 80 | ||
222 | config SCC_ENET | ||
223 | bool "CPM SCC Ethernet" | ||
224 | depends on NET_ETHERNET | ||
225 | help | ||
226 | Enable Ethernet support via the Motorola MPC8xx serial | ||
227 | communications controller. | ||
228 | |||
229 | choice | ||
230 | prompt "SCC used for Ethernet" | ||
231 | depends on SCC_ENET | ||
232 | default SCC1_ENET | ||
233 | |||
234 | config SCC1_ENET | ||
235 | bool "SCC1" | ||
236 | help | ||
237 | Use MPC8xx serial communications controller 1 to drive Ethernet | ||
238 | (default). | ||
239 | |||
240 | config SCC2_ENET | ||
241 | bool "SCC2" | ||
242 | help | ||
243 | Use MPC8xx serial communications controller 2 to drive Ethernet. | ||
244 | |||
245 | config SCC3_ENET | ||
246 | bool "SCC3" | ||
247 | help | ||
248 | Use MPC8xx serial communications controller 3 to drive Ethernet. | ||
249 | |||
250 | endchoice | ||
251 | |||
252 | config FEC_ENET | ||
253 | bool "860T FEC Ethernet" | ||
254 | depends on NET_ETHERNET | ||
255 | help | ||
256 | Enable Ethernet support via the Fast Ethernet Controller (FCC) on | ||
257 | the Motorola MPC8260. | ||
258 | |||
259 | config USE_MDIO | ||
260 | bool "Use MDIO for PHY configuration" | ||
261 | depends on FEC_ENET | ||
262 | help | ||
263 | On some boards the hardware configuration of the ethernet PHY can be | ||
264 | used without any software interaction over the MDIO interface, so | ||
265 | all MII code can be omitted. Say N here if unsure or if you don't | ||
266 | need link status reports. | ||
267 | |||
268 | config FEC_AM79C874 | ||
269 | bool "Support AMD79C874 PHY" | ||
270 | depends on USE_MDIO | ||
271 | |||
272 | config FEC_LXT970 | ||
273 | bool "Support LXT970 PHY" | ||
274 | depends on USE_MDIO | ||
275 | |||
276 | config FEC_LXT971 | ||
277 | bool "Support LXT971 PHY" | ||
278 | depends on USE_MDIO | ||
279 | |||
280 | config FEC_QS6612 | ||
281 | bool "Support QS6612 PHY" | ||
282 | depends on USE_MDIO | ||
283 | |||
284 | config ENET_BIG_BUFFERS | ||
285 | bool "Use Big CPM Ethernet Buffers" | ||
286 | depends on SCC_ENET || FEC_ENET | ||
287 | help | ||
288 | Allocate large buffers for MPC8xx Ethernet. Increases throughput | ||
289 | and decreases the likelihood of dropped packets, but costs memory. | ||
290 | |||
291 | config HTDMSOUND | ||
292 | bool "Embedded Planet HIOX Audio" | ||
293 | depends on SOUND=y | ||
294 | |||
295 | # This doesn't really belong here, but it is convenient to ask | 81 | # This doesn't really belong here, but it is convenient to ask |
296 | # 8xx specific questions. | 82 | # 8xx specific questions. |
297 | comment "Generic MPC8xx Options" | 83 | comment "Generic MPC8xx Options" |
diff --git a/arch/powerpc/platforms/8xx/Makefile b/arch/powerpc/platforms/8xx/Makefile new file mode 100644 index 000000000000..5e2dae3afd2f --- /dev/null +++ b/arch/powerpc/platforms/8xx/Makefile | |||
@@ -0,0 +1,6 @@ | |||
1 | # | ||
2 | # Makefile for the PowerPC 8xx linux kernel. | ||
3 | # | ||
4 | obj-$(CONFIG_PPC_8xx) += m8xx_setup.o | ||
5 | obj-$(CONFIG_MPC885ADS) += mpc885ads_setup.o | ||
6 | obj-$(CONFIG_MPC86XADS) += mpc86xads_setup.o | ||
diff --git a/arch/powerpc/platforms/8xx/m8xx_setup.c b/arch/powerpc/platforms/8xx/m8xx_setup.c new file mode 100644 index 000000000000..9ed7125f0150 --- /dev/null +++ b/arch/powerpc/platforms/8xx/m8xx_setup.c | |||
@@ -0,0 +1,303 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1995 Linus Torvalds | ||
3 | * Adapted from 'alpha' version by Gary Thomas | ||
4 | * Modified by Cort Dougan (cort@cs.nmt.edu) | ||
5 | * Modified for MBX using prep/chrp/pmac functions by Dan (dmalek@jlc.net) | ||
6 | * Further modified for generic 8xx by Dan. | ||
7 | */ | ||
8 | |||
9 | /* | ||
10 | * bootup setup stuff.. | ||
11 | */ | ||
12 | |||
13 | #include <linux/errno.h> | ||
14 | #include <linux/sched.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/mm.h> | ||
17 | #include <linux/stddef.h> | ||
18 | #include <linux/unistd.h> | ||
19 | #include <linux/ptrace.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <linux/user.h> | ||
22 | #include <linux/a.out.h> | ||
23 | #include <linux/tty.h> | ||
24 | #include <linux/major.h> | ||
25 | #include <linux/interrupt.h> | ||
26 | #include <linux/reboot.h> | ||
27 | #include <linux/init.h> | ||
28 | #include <linux/initrd.h> | ||
29 | #include <linux/ioport.h> | ||
30 | #include <linux/bootmem.h> | ||
31 | #include <linux/seq_file.h> | ||
32 | #include <linux/root_dev.h> | ||
33 | #include <linux/time.h> | ||
34 | #include <linux/rtc.h> | ||
35 | |||
36 | #include <asm/mmu.h> | ||
37 | #include <asm/reg.h> | ||
38 | #include <asm/residual.h> | ||
39 | #include <asm/io.h> | ||
40 | #include <asm/pgtable.h> | ||
41 | #include <asm/mpc8xx.h> | ||
42 | #include <asm/8xx_immap.h> | ||
43 | #include <asm/machdep.h> | ||
44 | #include <asm/bootinfo.h> | ||
45 | #include <asm/time.h> | ||
46 | #include <asm/prom.h> | ||
47 | #include <asm/fs_pd.h> | ||
48 | #include <mm/mmu_decl.h> | ||
49 | |||
50 | #include "sysdev/mpc8xx_pic.h" | ||
51 | |||
52 | void m8xx_calibrate_decr(void); | ||
53 | extern void m8xx_wdt_handler_install(bd_t *bp); | ||
54 | extern int cpm_pic_init(void); | ||
55 | extern int cpm_get_irq(void); | ||
56 | |||
57 | /* A place holder for time base interrupts, if they are ever enabled. */ | ||
58 | irqreturn_t timebase_interrupt(int irq, void * dev) | ||
59 | { | ||
60 | printk ("timebase_interrupt()\n"); | ||
61 | |||
62 | return IRQ_HANDLED; | ||
63 | } | ||
64 | |||
65 | static struct irqaction tbint_irqaction = { | ||
66 | .handler = timebase_interrupt, | ||
67 | .mask = CPU_MASK_NONE, | ||
68 | .name = "tbint", | ||
69 | }; | ||
70 | |||
71 | /* per-board overridable init_internal_rtc() function. */ | ||
72 | void __init __attribute__ ((weak)) | ||
73 | init_internal_rtc(void) | ||
74 | { | ||
75 | sit8xx_t *sys_tmr = (sit8xx_t *) immr_map(im_sit); | ||
76 | |||
77 | /* Disable the RTC one second and alarm interrupts. */ | ||
78 | clrbits16(&sys_tmr->sit_rtcsc, (RTCSC_SIE | RTCSC_ALE)); | ||
79 | |||
80 | /* Enable the RTC */ | ||
81 | setbits16(&sys_tmr->sit_rtcsc, (RTCSC_RTF | RTCSC_RTE)); | ||
82 | immr_unmap(sys_tmr); | ||
83 | } | ||
84 | |||
85 | static int __init get_freq(char *name, unsigned long *val) | ||
86 | { | ||
87 | struct device_node *cpu; | ||
88 | unsigned int *fp; | ||
89 | int found = 0; | ||
90 | |||
91 | /* The cpu node should have timebase and clock frequency properties */ | ||
92 | cpu = of_find_node_by_type(NULL, "cpu"); | ||
93 | |||
94 | if (cpu) { | ||
95 | fp = (unsigned int *)get_property(cpu, name, NULL); | ||
96 | if (fp) { | ||
97 | found = 1; | ||
98 | *val = *fp++; | ||
99 | } | ||
100 | |||
101 | of_node_put(cpu); | ||
102 | } | ||
103 | |||
104 | return found; | ||
105 | } | ||
106 | |||
107 | /* The decrementer counts at the system (internal) clock frequency divided by | ||
108 | * sixteen, or external oscillator divided by four. We force the processor | ||
109 | * to use system clock divided by sixteen. | ||
110 | */ | ||
111 | void __init mpc8xx_calibrate_decr(void) | ||
112 | { | ||
113 | struct device_node *cpu; | ||
114 | cark8xx_t *clk_r1; | ||
115 | car8xx_t *clk_r2; | ||
116 | sitk8xx_t *sys_tmr1; | ||
117 | sit8xx_t *sys_tmr2; | ||
118 | int irq, virq; | ||
119 | |||
120 | clk_r1 = (cark8xx_t *) immr_map(im_clkrstk); | ||
121 | |||
122 | /* Unlock the SCCR. */ | ||
123 | out_be32(&clk_r1->cark_sccrk, ~KAPWR_KEY); | ||
124 | out_be32(&clk_r1->cark_sccrk, KAPWR_KEY); | ||
125 | immr_unmap(clk_r1); | ||
126 | |||
127 | /* Force all 8xx processors to use divide by 16 processor clock. */ | ||
128 | clk_r2 = (car8xx_t *) immr_map(im_clkrst); | ||
129 | setbits32(&clk_r2->car_sccr, 0x02000000); | ||
130 | immr_unmap(clk_r2); | ||
131 | |||
132 | /* Processor frequency is MHz. | ||
133 | */ | ||
134 | ppc_tb_freq = 50000000; | ||
135 | if (!get_freq("bus-frequency", &ppc_tb_freq)) { | ||
136 | printk(KERN_ERR "WARNING: Estimating decrementer frequency " | ||
137 | "(not found)\n"); | ||
138 | } | ||
139 | ppc_tb_freq /= 16; | ||
140 | ppc_proc_freq = 50000000; | ||
141 | if (!get_freq("clock-frequency", &ppc_proc_freq)) | ||
142 | printk(KERN_ERR "WARNING: Estimating processor frequency" | ||
143 | "(not found)\n"); | ||
144 | |||
145 | printk("Decrementer Frequency = 0x%lx\n", ppc_tb_freq); | ||
146 | |||
147 | /* Perform some more timer/timebase initialization. This used | ||
148 | * to be done elsewhere, but other changes caused it to get | ||
149 | * called more than once....that is a bad thing. | ||
150 | * | ||
151 | * First, unlock all of the registers we are going to modify. | ||
152 | * To protect them from corruption during power down, registers | ||
153 | * that are maintained by keep alive power are "locked". To | ||
154 | * modify these registers we have to write the key value to | ||
155 | * the key location associated with the register. | ||
156 | * Some boards power up with these unlocked, while others | ||
157 | * are locked. Writing anything (including the unlock code?) | ||
158 | * to the unlocked registers will lock them again. So, here | ||
159 | * we guarantee the registers are locked, then we unlock them | ||
160 | * for our use. | ||
161 | */ | ||
162 | sys_tmr1 = (sitk8xx_t *) immr_map(im_sitk); | ||
163 | out_be32(&sys_tmr1->sitk_tbscrk, ~KAPWR_KEY); | ||
164 | out_be32(&sys_tmr1->sitk_rtcsck, ~KAPWR_KEY); | ||
165 | out_be32(&sys_tmr1->sitk_tbk, ~KAPWR_KEY); | ||
166 | out_be32(&sys_tmr1->sitk_tbscrk, KAPWR_KEY); | ||
167 | out_be32(&sys_tmr1->sitk_rtcsck, KAPWR_KEY); | ||
168 | out_be32(&sys_tmr1->sitk_tbk, KAPWR_KEY); | ||
169 | immr_unmap(sys_tmr1); | ||
170 | |||
171 | init_internal_rtc(); | ||
172 | |||
173 | /* Enabling the decrementer also enables the timebase interrupts | ||
174 | * (or from the other point of view, to get decrementer interrupts | ||
175 | * we have to enable the timebase). The decrementer interrupt | ||
176 | * is wired into the vector table, nothing to do here for that. | ||
177 | */ | ||
178 | cpu = of_find_node_by_type(NULL, "cpu"); | ||
179 | virq= irq_of_parse_and_map(cpu, 0); | ||
180 | irq = irq_map[virq].hwirq; | ||
181 | |||
182 | sys_tmr2 = (sit8xx_t *) immr_map(im_sit); | ||
183 | out_be16(&sys_tmr2->sit_tbscr, ((1 << (7 - (irq/2))) << 8) | | ||
184 | (TBSCR_TBF | TBSCR_TBE)); | ||
185 | immr_unmap(sys_tmr2); | ||
186 | |||
187 | if (setup_irq(virq, &tbint_irqaction)) | ||
188 | panic("Could not allocate timer IRQ!"); | ||
189 | |||
190 | #ifdef CONFIG_8xx_WDT | ||
191 | /* Install watchdog timer handler early because it might be | ||
192 | * already enabled by the bootloader | ||
193 | */ | ||
194 | m8xx_wdt_handler_install(binfo); | ||
195 | #endif | ||
196 | } | ||
197 | |||
198 | /* The RTC on the MPC8xx is an internal register. | ||
199 | * We want to protect this during power down, so we need to unlock, | ||
200 | * modify, and re-lock. | ||
201 | */ | ||
202 | |||
203 | int mpc8xx_set_rtc_time(struct rtc_time *tm) | ||
204 | { | ||
205 | sitk8xx_t *sys_tmr1; | ||
206 | sit8xx_t *sys_tmr2; | ||
207 | int time; | ||
208 | |||
209 | sys_tmr1 = (sitk8xx_t *) immr_map(im_sitk); | ||
210 | sys_tmr2 = (sit8xx_t *) immr_map(im_sit); | ||
211 | time = mktime(tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, | ||
212 | tm->tm_hour, tm->tm_min, tm->tm_sec); | ||
213 | |||
214 | out_be32(&sys_tmr1->sitk_rtck, KAPWR_KEY); | ||
215 | out_be32(&sys_tmr2->sit_rtc, time); | ||
216 | out_be32(&sys_tmr1->sitk_rtck, ~KAPWR_KEY); | ||
217 | |||
218 | immr_unmap(sys_tmr2); | ||
219 | immr_unmap(sys_tmr1); | ||
220 | return 0; | ||
221 | } | ||
222 | |||
223 | void mpc8xx_get_rtc_time(struct rtc_time *tm) | ||
224 | { | ||
225 | unsigned long data; | ||
226 | sit8xx_t *sys_tmr = (sit8xx_t *) immr_map(im_sit); | ||
227 | |||
228 | /* Get time from the RTC. */ | ||
229 | data = in_be32(&sys_tmr->sit_rtc); | ||
230 | to_tm(data, tm); | ||
231 | tm->tm_year -= 1900; | ||
232 | tm->tm_mon -= 1; | ||
233 | immr_unmap(sys_tmr); | ||
234 | return; | ||
235 | } | ||
236 | |||
237 | void mpc8xx_restart(char *cmd) | ||
238 | { | ||
239 | __volatile__ unsigned char dummy; | ||
240 | car8xx_t * clk_r = (car8xx_t *) immr_map(im_clkrst); | ||
241 | |||
242 | |||
243 | local_irq_disable(); | ||
244 | |||
245 | setbits32(&clk_r->car_plprcr, 0x00000080); | ||
246 | /* Clear the ME bit in MSR to cause checkstop on machine check | ||
247 | */ | ||
248 | mtmsr(mfmsr() & ~0x1000); | ||
249 | |||
250 | dummy = in_8(&clk_r->res[0]); | ||
251 | printk("Restart failed\n"); | ||
252 | while(1); | ||
253 | } | ||
254 | |||
255 | void mpc8xx_show_cpuinfo(struct seq_file *m) | ||
256 | { | ||
257 | struct device_node *root; | ||
258 | uint memsize = total_memory; | ||
259 | const char *model = ""; | ||
260 | |||
261 | seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n"); | ||
262 | |||
263 | root = of_find_node_by_path("/"); | ||
264 | if (root) | ||
265 | model = get_property(root, "model", NULL); | ||
266 | seq_printf(m, "Machine\t\t: %s\n", model); | ||
267 | of_node_put(root); | ||
268 | |||
269 | seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024)); | ||
270 | } | ||
271 | |||
272 | static void cpm_cascade(unsigned int irq, struct irq_desc *desc) | ||
273 | { | ||
274 | int cascade_irq; | ||
275 | |||
276 | if ((cascade_irq = cpm_get_irq()) >= 0) { | ||
277 | struct irq_desc *cdesc = irq_desc + cascade_irq; | ||
278 | |||
279 | generic_handle_irq(cascade_irq); | ||
280 | cdesc->chip->eoi(cascade_irq); | ||
281 | } | ||
282 | desc->chip->eoi(irq); | ||
283 | } | ||
284 | |||
285 | /* Initialize the internal interrupt controller. The number of | ||
286 | * interrupts supported can vary with the processor type, and the | ||
287 | * 82xx family can have up to 64. | ||
288 | * External interrupts can be either edge or level triggered, and | ||
289 | * need to be initialized by the appropriate driver. | ||
290 | */ | ||
291 | void __init m8xx_pic_init(void) | ||
292 | { | ||
293 | int irq; | ||
294 | |||
295 | if (mpc8xx_pic_init()) { | ||
296 | printk(KERN_ERR "Failed interrupt 8xx controller initialization\n"); | ||
297 | return; | ||
298 | } | ||
299 | |||
300 | irq = cpm_pic_init(); | ||
301 | if (irq != NO_IRQ) | ||
302 | set_irq_chained_handler(irq, cpm_cascade); | ||
303 | } | ||
diff --git a/arch/powerpc/platforms/8xx/mpc86xads.h b/arch/powerpc/platforms/8xx/mpc86xads.h new file mode 100644 index 000000000000..b5d19dd0619c --- /dev/null +++ b/arch/powerpc/platforms/8xx/mpc86xads.h | |||
@@ -0,0 +1,95 @@ | |||
1 | /* | ||
2 | * A collection of structures, addresses, and values associated with | ||
3 | * the Freescale MPC86xADS board. | ||
4 | * Copied from the FADS stuff. | ||
5 | * | ||
6 | * Author: MontaVista Software, Inc. | ||
7 | * source@mvista.com | ||
8 | * | ||
9 | * 2005 (c) MontaVista Software, Inc. This file is licensed under the | ||
10 | * terms of the GNU General Public License version 2. This program is licensed | ||
11 | * "as is" without any warranty of any kind, whether express or implied. | ||
12 | */ | ||
13 | |||
14 | #ifdef __KERNEL__ | ||
15 | #ifndef __ASM_MPC86XADS_H__ | ||
16 | #define __ASM_MPC86XADS_H__ | ||
17 | |||
18 | #include <asm/ppcboot.h> | ||
19 | #include <sysdev/fsl_soc.h> | ||
20 | |||
21 | /* U-Boot maps BCSR to 0xff080000 */ | ||
22 | #define BCSR_ADDR ((uint)0xff080000) | ||
23 | #define BCSR_SIZE ((uint)32) | ||
24 | #define BCSR0 ((uint)(BCSR_ADDR + 0x00)) | ||
25 | #define BCSR1 ((uint)(BCSR_ADDR + 0x04)) | ||
26 | #define BCSR2 ((uint)(BCSR_ADDR + 0x08)) | ||
27 | #define BCSR3 ((uint)(BCSR_ADDR + 0x0c)) | ||
28 | #define BCSR4 ((uint)(BCSR_ADDR + 0x10)) | ||
29 | |||
30 | #define CFG_PHYDEV_ADDR ((uint)0xff0a0000) | ||
31 | #define BCSR5 ((uint)(CFG_PHYDEV_ADDR + 0x300)) | ||
32 | |||
33 | #define IMAP_ADDR (get_immrbase()) | ||
34 | #define IMAP_SIZE ((uint)(64 * 1024)) | ||
35 | |||
36 | #define MPC8xx_CPM_OFFSET (0x9c0) | ||
37 | #define CPM_MAP_ADDR (get_immrbase() + MPC8xx_CPM_OFFSET) | ||
38 | #define CPM_IRQ_OFFSET 16 // for compability with cpm_uart driver | ||
39 | |||
40 | #define PCMCIA_MEM_ADDR (uint)0xff020000) | ||
41 | #define PCMCIA_MEM_SIZE ((uint)(64 * 1024)) | ||
42 | |||
43 | /* Bits of interest in the BCSRs. | ||
44 | */ | ||
45 | #define BCSR1_ETHEN ((uint)0x20000000) | ||
46 | #define BCSR1_IRDAEN ((uint)0x10000000) | ||
47 | #define BCSR1_RS232EN_1 ((uint)0x01000000) | ||
48 | #define BCSR1_PCCEN ((uint)0x00800000) | ||
49 | #define BCSR1_PCCVCC0 ((uint)0x00400000) | ||
50 | #define BCSR1_PCCVPP0 ((uint)0x00200000) | ||
51 | #define BCSR1_PCCVPP1 ((uint)0x00100000) | ||
52 | #define BCSR1_PCCVPP_MASK (BCSR1_PCCVPP0 | BCSR1_PCCVPP1) | ||
53 | #define BCSR1_RS232EN_2 ((uint)0x00040000) | ||
54 | #define BCSR1_PCCVCC1 ((uint)0x00010000) | ||
55 | #define BCSR1_PCCVCC_MASK (BCSR1_PCCVCC0 | BCSR1_PCCVCC1) | ||
56 | |||
57 | #define BCSR4_ETH10_RST ((uint)0x80000000) /* 10Base-T PHY reset*/ | ||
58 | #define BCSR4_USB_LO_SPD ((uint)0x04000000) | ||
59 | #define BCSR4_USB_VCC ((uint)0x02000000) | ||
60 | #define BCSR4_USB_FULL_SPD ((uint)0x00040000) | ||
61 | #define BCSR4_USB_EN ((uint)0x00020000) | ||
62 | |||
63 | #define BCSR5_MII2_EN 0x40 | ||
64 | #define BCSR5_MII2_RST 0x20 | ||
65 | #define BCSR5_T1_RST 0x10 | ||
66 | #define BCSR5_ATM155_RST 0x08 | ||
67 | #define BCSR5_ATM25_RST 0x04 | ||
68 | #define BCSR5_MII1_EN 0x02 | ||
69 | #define BCSR5_MII1_RST 0x01 | ||
70 | |||
71 | /* Interrupt level assignments */ | ||
72 | #define PHY_INTERRUPT SIU_IRQ7 /* PHY link change interrupt */ | ||
73 | #define SIU_INT_FEC1 SIU_LEVEL1 /* FEC1 interrupt */ | ||
74 | #define FEC_INTERRUPT SIU_INT_FEC1 /* FEC interrupt */ | ||
75 | |||
76 | /* We don't use the 8259 */ | ||
77 | #define NR_8259_INTS 0 | ||
78 | |||
79 | /* CPM Ethernet through SCC1 */ | ||
80 | #define PA_ENET_RXD ((ushort)0x0001) | ||
81 | #define PA_ENET_TXD ((ushort)0x0002) | ||
82 | #define PA_ENET_TCLK ((ushort)0x0100) | ||
83 | #define PA_ENET_RCLK ((ushort)0x0200) | ||
84 | #define PB_ENET_TENA ((uint)0x00001000) | ||
85 | #define PC_ENET_CLSN ((ushort)0x0010) | ||
86 | #define PC_ENET_RENA ((ushort)0x0020) | ||
87 | |||
88 | /* Control bits in the SICR to route TCLK (CLK1) and RCLK (CLK2) to | ||
89 | * SCC1. Also, make sure GR1 (bit 24) and SC1 (bit 25) are zero. | ||
90 | */ | ||
91 | #define SICR_ENET_MASK ((uint)0x000000ff) | ||
92 | #define SICR_ENET_CLKRT ((uint)0x0000002c) | ||
93 | |||
94 | #endif /* __ASM_MPC86XADS_H__ */ | ||
95 | #endif /* __KERNEL__ */ | ||
diff --git a/arch/powerpc/platforms/8xx/mpc86xads_setup.c b/arch/powerpc/platforms/8xx/mpc86xads_setup.c new file mode 100644 index 000000000000..ef52ce701b0e --- /dev/null +++ b/arch/powerpc/platforms/8xx/mpc86xads_setup.c | |||
@@ -0,0 +1,301 @@ | |||
1 | /*arch/ppc/platforms/mpc86xads-setup.c | ||
2 | * | ||
3 | * Platform setup for the Freescale mpc86xads board | ||
4 | * | ||
5 | * Vitaly Bordug <vbordug@ru.mvista.com> | ||
6 | * | ||
7 | * Copyright 2005 MontaVista Software Inc. | ||
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 any | ||
11 | * kind, whether express or implied. | ||
12 | */ | ||
13 | |||
14 | #include <linux/init.h> | ||
15 | #include <linux/module.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 | |||
27 | #include <asm/delay.h> | ||
28 | #include <asm/io.h> | ||
29 | #include <asm/machdep.h> | ||
30 | #include <asm/page.h> | ||
31 | #include <asm/processor.h> | ||
32 | #include <asm/system.h> | ||
33 | #include <asm/time.h> | ||
34 | #include <asm/ppcboot.h> | ||
35 | #include <asm/mpc8xx.h> | ||
36 | #include <asm/8xx_immap.h> | ||
37 | #include <asm/commproc.h> | ||
38 | #include <asm/fs_pd.h> | ||
39 | #include <asm/prom.h> | ||
40 | |||
41 | extern void cpm_reset(void); | ||
42 | extern void mpc8xx_show_cpuinfo(struct seq_file*); | ||
43 | extern void mpc8xx_restart(char *cmd); | ||
44 | extern void mpc8xx_calibrate_decr(void); | ||
45 | extern int mpc8xx_set_rtc_time(struct rtc_time *tm); | ||
46 | extern void mpc8xx_get_rtc_time(struct rtc_time *tm); | ||
47 | extern void m8xx_pic_init(void); | ||
48 | extern unsigned int mpc8xx_get_irq(void); | ||
49 | |||
50 | static void init_smc1_uart_ioports(struct fs_uart_platform_info* fpi); | ||
51 | static void init_smc2_uart_ioports(struct fs_uart_platform_info* fpi); | ||
52 | static void init_scc1_ioports(struct fs_platform_info* ptr); | ||
53 | |||
54 | void __init mpc86xads_board_setup(void) | ||
55 | { | ||
56 | cpm8xx_t *cp; | ||
57 | unsigned int *bcsr_io; | ||
58 | u8 tmpval8; | ||
59 | |||
60 | bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); | ||
61 | cp = (cpm8xx_t *)immr_map(im_cpm); | ||
62 | |||
63 | if (bcsr_io == NULL) { | ||
64 | printk(KERN_CRIT "Could not remap BCSR\n"); | ||
65 | return; | ||
66 | } | ||
67 | #ifdef CONFIG_SERIAL_CPM_SMC1 | ||
68 | clrbits32(bcsr_io, BCSR1_RS232EN_1); | ||
69 | clrbits32(&cp->cp_simode, 0xe0000000 >> 17); /* brg1 */ | ||
70 | tmpval8 = in_8(&(cp->cp_smc[0].smc_smcm)) | (SMCM_RX | SMCM_TX); | ||
71 | out_8(&(cp->cp_smc[0].smc_smcm), tmpval8); | ||
72 | clrbits16(&cp->cp_smc[0].smc_smcmr, SMCMR_REN | SMCMR_TEN); | ||
73 | #else | ||
74 | setbits32(bcsr_io,BCSR1_RS232EN_1); | ||
75 | out_be16(&cp->cp_smc[0].smc_smcmr, 0); | ||
76 | out_8(&cp->cp_smc[0].smc_smce, 0); | ||
77 | #endif | ||
78 | |||
79 | #ifdef CONFIG_SERIAL_CPM_SMC2 | ||
80 | clrbits32(bcsr_io,BCSR1_RS232EN_2); | ||
81 | clrbits32(&cp->cp_simode, 0xe0000000 >> 1); | ||
82 | setbits32(&cp->cp_simode, 0x20000000 >> 1); /* brg2 */ | ||
83 | tmpval8 = in_8(&(cp->cp_smc[1].smc_smcm)) | (SMCM_RX | SMCM_TX); | ||
84 | out_8(&(cp->cp_smc[1].smc_smcm), tmpval8); | ||
85 | clrbits16(&cp->cp_smc[1].smc_smcmr, SMCMR_REN | SMCMR_TEN); | ||
86 | |||
87 | init_smc2_uart_ioports(0); | ||
88 | #else | ||
89 | setbits32(bcsr_io,BCSR1_RS232EN_2); | ||
90 | out_be16(&cp->cp_smc[1].smc_smcmr, 0); | ||
91 | out_8(&cp->cp_smc[1].smc_smce, 0); | ||
92 | #endif | ||
93 | immr_unmap(cp); | ||
94 | iounmap(bcsr_io); | ||
95 | } | ||
96 | |||
97 | |||
98 | static void init_fec1_ioports(struct fs_platform_info* ptr) | ||
99 | { | ||
100 | iop8xx_t *io_port = (iop8xx_t *)immr_map(im_ioport); | ||
101 | |||
102 | /* configure FEC1 pins */ | ||
103 | |||
104 | setbits16(&io_port->iop_pdpar, 0x1fff); | ||
105 | setbits16(&io_port->iop_pddir, 0x1fff); | ||
106 | |||
107 | immr_unmap(io_port); | ||
108 | } | ||
109 | |||
110 | void init_fec_ioports(struct fs_platform_info *fpi) | ||
111 | { | ||
112 | int fec_no = fs_get_fec_index(fpi->fs_no); | ||
113 | |||
114 | switch (fec_no) { | ||
115 | case 0: | ||
116 | init_fec1_ioports(fpi); | ||
117 | break; | ||
118 | default: | ||
119 | printk(KERN_ERR "init_fec_ioports: invalid FEC number\n"); | ||
120 | return; | ||
121 | } | ||
122 | } | ||
123 | |||
124 | static void init_scc1_ioports(struct fs_platform_info* fpi) | ||
125 | { | ||
126 | unsigned *bcsr_io; | ||
127 | iop8xx_t *io_port; | ||
128 | cpm8xx_t *cp; | ||
129 | |||
130 | bcsr_io = ioremap(BCSR_ADDR, BCSR_SIZE); | ||
131 | io_port = (iop8xx_t *)immr_map(im_ioport); | ||
132 | cp = (cpm8xx_t *)immr_map(im_cpm); | ||
133 | |||
134 | if (bcsr_io == NULL) { | ||
135 | printk(KERN_CRIT "Could not remap BCSR\n"); | ||
136 | return; | ||
137 | } | ||
138 | |||
139 | /* Configure port A pins for Txd and Rxd. | ||
140 | */ | ||
141 | setbits16(&io_port->iop_papar, PA_ENET_RXD | PA_ENET_TXD); | ||
142 | clrbits16(&io_port->iop_padir, PA_ENET_RXD | PA_ENET_TXD); | ||
143 | clrbits16(&io_port->iop_paodr, PA_ENET_TXD); | ||
144 | |||
145 | /* Configure port C pins to enable CLSN and RENA. | ||
146 | */ | ||
147 | clrbits16(&io_port->iop_pcpar, PC_ENET_CLSN | PC_ENET_RENA); | ||
148 | clrbits16(&io_port->iop_pcdir, PC_ENET_CLSN | PC_ENET_RENA); | ||
149 | setbits16(&io_port->iop_pcso, PC_ENET_CLSN | PC_ENET_RENA); | ||
150 | |||
151 | /* Configure port A for TCLK and RCLK. | ||
152 | */ | ||
153 | setbits16(&io_port->iop_papar, PA_ENET_TCLK | PA_ENET_RCLK); | ||
154 | clrbits16(&io_port->iop_padir, PA_ENET_TCLK | PA_ENET_RCLK); | ||
155 | clrbits32(&cp->cp_pbpar, PB_ENET_TENA); | ||
156 | clrbits32(&cp->cp_pbdir, PB_ENET_TENA); | ||
157 | |||
158 | /* Configure Serial Interface clock routing. | ||
159 | * First, clear all SCC bits to zero, then set the ones we want. | ||
160 | */ | ||
161 | clrbits32(&cp->cp_sicr, SICR_ENET_MASK); | ||
162 | setbits32(&cp->cp_sicr, SICR_ENET_CLKRT); | ||
163 | |||
164 | /* In the original SCC enet driver the following code is placed at | ||
165 | the end of the initialization */ | ||
166 | setbits32(&cp->cp_pbpar, PB_ENET_TENA); | ||
167 | setbits32(&cp->cp_pbdir, PB_ENET_TENA); | ||
168 | |||
169 | clrbits32(bcsr_io+1, BCSR1_ETHEN); | ||
170 | iounmap(bcsr_io); | ||
171 | immr_unmap(cp); | ||
172 | immr_unmap(io_port); | ||
173 | } | ||
174 | |||
175 | void init_scc_ioports(struct fs_platform_info *fpi) | ||
176 | { | ||
177 | int scc_no = fs_get_scc_index(fpi->fs_no); | ||
178 | |||
179 | switch (scc_no) { | ||
180 | case 0: | ||
181 | init_scc1_ioports(fpi); | ||
182 | break; | ||
183 | default: | ||
184 | printk(KERN_ERR "init_scc_ioports: invalid SCC number\n"); | ||
185 | return; | ||
186 | } | ||
187 | } | ||
188 | |||
189 | |||
190 | |||
191 | static void init_smc1_uart_ioports(struct fs_uart_platform_info* ptr) | ||
192 | { | ||
193 | unsigned *bcsr_io; | ||
194 | cpm8xx_t *cp = (cpm8xx_t *)immr_map(im_cpm); | ||
195 | |||
196 | setbits32(&cp->cp_pbpar, 0x000000c0); | ||
197 | clrbits32(&cp->cp_pbdir, 0x000000c0); | ||
198 | clrbits16(&cp->cp_pbodr, 0x00c0); | ||
199 | immr_unmap(cp); | ||
200 | |||
201 | bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); | ||
202 | |||
203 | if (bcsr_io == NULL) { | ||
204 | printk(KERN_CRIT "Could not remap BCSR1\n"); | ||
205 | return; | ||
206 | } | ||
207 | clrbits32(bcsr_io,BCSR1_RS232EN_1); | ||
208 | iounmap(bcsr_io); | ||
209 | } | ||
210 | |||
211 | static void init_smc2_uart_ioports(struct fs_uart_platform_info* fpi) | ||
212 | { | ||
213 | unsigned *bcsr_io; | ||
214 | cpm8xx_t *cp = (cpm8xx_t *)immr_map(im_cpm); | ||
215 | |||
216 | setbits32(&cp->cp_pbpar, 0x00000c00); | ||
217 | clrbits32(&cp->cp_pbdir, 0x00000c00); | ||
218 | clrbits16(&cp->cp_pbodr, 0x0c00); | ||
219 | immr_unmap(cp); | ||
220 | |||
221 | bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); | ||
222 | |||
223 | if (bcsr_io == NULL) { | ||
224 | printk(KERN_CRIT "Could not remap BCSR1\n"); | ||
225 | return; | ||
226 | } | ||
227 | clrbits32(bcsr_io,BCSR1_RS232EN_2); | ||
228 | iounmap(bcsr_io); | ||
229 | } | ||
230 | |||
231 | void init_smc_ioports(struct fs_uart_platform_info *data) | ||
232 | { | ||
233 | int smc_no = fs_uart_id_fsid2smc(data->fs_no); | ||
234 | |||
235 | switch (smc_no) { | ||
236 | case 0: | ||
237 | init_smc1_uart_ioports(data); | ||
238 | data->brg = data->clk_rx; | ||
239 | break; | ||
240 | case 1: | ||
241 | init_smc2_uart_ioports(data); | ||
242 | data->brg = data->clk_rx; | ||
243 | break; | ||
244 | default: | ||
245 | printk(KERN_ERR "init_scc_ioports: invalid SCC number\n"); | ||
246 | return; | ||
247 | } | ||
248 | } | ||
249 | |||
250 | int platform_device_skip(char *model, int id) | ||
251 | { | ||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | static void __init mpc86xads_setup_arch(void) | ||
256 | { | ||
257 | struct device_node *cpu; | ||
258 | |||
259 | cpu = of_find_node_by_type(NULL, "cpu"); | ||
260 | if (cpu != 0) { | ||
261 | const unsigned int *fp; | ||
262 | |||
263 | fp = get_property(cpu, "clock-frequency", NULL); | ||
264 | if (fp != 0) | ||
265 | loops_per_jiffy = *fp / HZ; | ||
266 | else | ||
267 | loops_per_jiffy = 50000000 / HZ; | ||
268 | of_node_put(cpu); | ||
269 | } | ||
270 | |||
271 | cpm_reset(); | ||
272 | |||
273 | mpc86xads_board_setup(); | ||
274 | |||
275 | ROOT_DEV = Root_NFS; | ||
276 | } | ||
277 | |||
278 | static int __init mpc86xads_probe(void) | ||
279 | { | ||
280 | char *model = of_get_flat_dt_prop(of_get_flat_dt_root(), | ||
281 | "model", NULL); | ||
282 | if (model == NULL) | ||
283 | return 0; | ||
284 | if (strcmp(model, "MPC866ADS")) | ||
285 | return 0; | ||
286 | |||
287 | return 1; | ||
288 | } | ||
289 | |||
290 | define_machine(mpc86x_ads) { | ||
291 | .name = "MPC86x ADS", | ||
292 | .probe = mpc86xads_probe, | ||
293 | .setup_arch = mpc86xads_setup_arch, | ||
294 | .init_IRQ = m8xx_pic_init, | ||
295 | .show_cpuinfo = mpc8xx_show_cpuinfo, | ||
296 | .get_irq = mpc8xx_get_irq, | ||
297 | .restart = mpc8xx_restart, | ||
298 | .calibrate_decr = mpc8xx_calibrate_decr, | ||
299 | .set_rtc_time = mpc8xx_set_rtc_time, | ||
300 | .get_rtc_time = mpc8xx_get_rtc_time, | ||
301 | }; | ||
diff --git a/arch/powerpc/platforms/8xx/mpc885ads.h b/arch/powerpc/platforms/8xx/mpc885ads.h new file mode 100644 index 000000000000..30cbebfe84c5 --- /dev/null +++ b/arch/powerpc/platforms/8xx/mpc885ads.h | |||
@@ -0,0 +1,95 @@ | |||
1 | /* | ||
2 | * A collection of structures, addresses, and values associated with | ||
3 | * the Freescale MPC885ADS board. | ||
4 | * Copied from the FADS stuff. | ||
5 | * | ||
6 | * Author: MontaVista Software, Inc. | ||
7 | * source@mvista.com | ||
8 | * | ||
9 | * 2005 (c) MontaVista Software, Inc. This file is licensed under the | ||
10 | * terms of the GNU General Public License version 2. This program is licensed | ||
11 | * "as is" without any warranty of any kind, whether express or implied. | ||
12 | */ | ||
13 | |||
14 | #ifdef __KERNEL__ | ||
15 | #ifndef __ASM_MPC885ADS_H__ | ||
16 | #define __ASM_MPC885ADS_H__ | ||
17 | |||
18 | #include <asm/ppcboot.h> | ||
19 | #include <sysdev/fsl_soc.h> | ||
20 | |||
21 | /* U-Boot maps BCSR to 0xff080000 */ | ||
22 | #define BCSR_ADDR ((uint)0xff080000) | ||
23 | #define BCSR_SIZE ((uint)32) | ||
24 | #define BCSR0 ((uint)(BCSR_ADDR + 0x00)) | ||
25 | #define BCSR1 ((uint)(BCSR_ADDR + 0x04)) | ||
26 | #define BCSR2 ((uint)(BCSR_ADDR + 0x08)) | ||
27 | #define BCSR3 ((uint)(BCSR_ADDR + 0x0c)) | ||
28 | #define BCSR4 ((uint)(BCSR_ADDR + 0x10)) | ||
29 | |||
30 | #define CFG_PHYDEV_ADDR ((uint)0xff0a0000) | ||
31 | #define BCSR5 ((uint)(CFG_PHYDEV_ADDR + 0x300)) | ||
32 | |||
33 | #define IMAP_ADDR (get_immrbase()) | ||
34 | #define IMAP_SIZE ((uint)(64 * 1024)) | ||
35 | |||
36 | #define MPC8xx_CPM_OFFSET (0x9c0) | ||
37 | #define CPM_MAP_ADDR (get_immrbase() + MPC8xx_CPM_OFFSET) | ||
38 | #define CPM_IRQ_OFFSET 16 // for compability with cpm_uart driver | ||
39 | |||
40 | #define PCMCIA_MEM_ADDR (uint)0xff020000) | ||
41 | #define PCMCIA_MEM_SIZE ((uint)(64 * 1024)) | ||
42 | |||
43 | /* Bits of interest in the BCSRs. | ||
44 | */ | ||
45 | #define BCSR1_ETHEN ((uint)0x20000000) | ||
46 | #define BCSR1_IRDAEN ((uint)0x10000000) | ||
47 | #define BCSR1_RS232EN_1 ((uint)0x01000000) | ||
48 | #define BCSR1_PCCEN ((uint)0x00800000) | ||
49 | #define BCSR1_PCCVCC0 ((uint)0x00400000) | ||
50 | #define BCSR1_PCCVPP0 ((uint)0x00200000) | ||
51 | #define BCSR1_PCCVPP1 ((uint)0x00100000) | ||
52 | #define BCSR1_PCCVPP_MASK (BCSR1_PCCVPP0 | BCSR1_PCCVPP1) | ||
53 | #define BCSR1_RS232EN_2 ((uint)0x00040000) | ||
54 | #define BCSR1_PCCVCC1 ((uint)0x00010000) | ||
55 | #define BCSR1_PCCVCC_MASK (BCSR1_PCCVCC0 | BCSR1_PCCVCC1) | ||
56 | |||
57 | #define BCSR4_ETH10_RST ((uint)0x80000000) /* 10Base-T PHY reset*/ | ||
58 | #define BCSR4_USB_LO_SPD ((uint)0x04000000) | ||
59 | #define BCSR4_USB_VCC ((uint)0x02000000) | ||
60 | #define BCSR4_USB_FULL_SPD ((uint)0x00040000) | ||
61 | #define BCSR4_USB_EN ((uint)0x00020000) | ||
62 | |||
63 | #define BCSR5_MII2_EN 0x40 | ||
64 | #define BCSR5_MII2_RST 0x20 | ||
65 | #define BCSR5_T1_RST 0x10 | ||
66 | #define BCSR5_ATM155_RST 0x08 | ||
67 | #define BCSR5_ATM25_RST 0x04 | ||
68 | #define BCSR5_MII1_EN 0x02 | ||
69 | #define BCSR5_MII1_RST 0x01 | ||
70 | |||
71 | /* Interrupt level assignments */ | ||
72 | #define PHY_INTERRUPT SIU_IRQ7 /* PHY link change interrupt */ | ||
73 | #define SIU_INT_FEC1 SIU_LEVEL1 /* FEC1 interrupt */ | ||
74 | #define SIU_INT_FEC2 SIU_LEVEL3 /* FEC2 interrupt */ | ||
75 | #define FEC_INTERRUPT SIU_INT_FEC1 /* FEC interrupt */ | ||
76 | |||
77 | /* We don't use the 8259 */ | ||
78 | #define NR_8259_INTS 0 | ||
79 | |||
80 | /* CPM Ethernet through SCC3 */ | ||
81 | #define PA_ENET_RXD ((ushort)0x0040) | ||
82 | #define PA_ENET_TXD ((ushort)0x0080) | ||
83 | #define PE_ENET_TCLK ((uint)0x00004000) | ||
84 | #define PE_ENET_RCLK ((uint)0x00008000) | ||
85 | #define PE_ENET_TENA ((uint)0x00000010) | ||
86 | #define PC_ENET_CLSN ((ushort)0x0400) | ||
87 | #define PC_ENET_RENA ((ushort)0x0800) | ||
88 | |||
89 | /* Control bits in the SICR to route TCLK (CLK5) and RCLK (CLK6) to | ||
90 | * SCC3. Also, make sure GR3 (bit 8) and SC3 (bit 9) are zero */ | ||
91 | #define SICR_ENET_MASK ((uint)0x00ff0000) | ||
92 | #define SICR_ENET_CLKRT ((uint)0x002c0000) | ||
93 | |||
94 | #endif /* __ASM_MPC885ADS_H__ */ | ||
95 | #endif /* __KERNEL__ */ | ||
diff --git a/arch/powerpc/platforms/8xx/mpc885ads_setup.c b/arch/powerpc/platforms/8xx/mpc885ads_setup.c new file mode 100644 index 000000000000..c5fefdf66c0a --- /dev/null +++ b/arch/powerpc/platforms/8xx/mpc885ads_setup.c | |||
@@ -0,0 +1,387 @@ | |||
1 | /*arch/ppc/platforms/mpc885ads-setup.c | ||
2 | * | ||
3 | * Platform setup for the Freescale mpc885ads board | ||
4 | * | ||
5 | * Vitaly Bordug <vbordug@ru.mvista.com> | ||
6 | * | ||
7 | * Copyright 2005 MontaVista Software Inc. | ||
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 any | ||
11 | * kind, whether express or implied. | ||
12 | */ | ||
13 | |||
14 | #include <linux/init.h> | ||
15 | #include <linux/module.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 | |||
27 | #include <asm/delay.h> | ||
28 | #include <asm/io.h> | ||
29 | #include <asm/machdep.h> | ||
30 | #include <asm/page.h> | ||
31 | #include <asm/processor.h> | ||
32 | #include <asm/system.h> | ||
33 | #include <asm/time.h> | ||
34 | #include <asm/ppcboot.h> | ||
35 | #include <asm/mpc8xx.h> | ||
36 | #include <asm/8xx_immap.h> | ||
37 | #include <asm/commproc.h> | ||
38 | #include <asm/fs_pd.h> | ||
39 | #include <asm/prom.h> | ||
40 | |||
41 | extern void cpm_reset(void); | ||
42 | extern void mpc8xx_show_cpuinfo(struct seq_file*); | ||
43 | extern void mpc8xx_restart(char *cmd); | ||
44 | extern void mpc8xx_calibrate_decr(void); | ||
45 | extern int mpc8xx_set_rtc_time(struct rtc_time *tm); | ||
46 | extern void mpc8xx_get_rtc_time(struct rtc_time *tm); | ||
47 | extern void m8xx_pic_init(void); | ||
48 | extern unsigned int mpc8xx_get_irq(void); | ||
49 | |||
50 | static void init_smc1_uart_ioports(struct fs_uart_platform_info* fpi); | ||
51 | static void init_smc2_uart_ioports(struct fs_uart_platform_info* fpi); | ||
52 | static void init_scc3_ioports(struct fs_platform_info* ptr); | ||
53 | |||
54 | void __init mpc885ads_board_setup(void) | ||
55 | { | ||
56 | cpm8xx_t *cp; | ||
57 | unsigned int *bcsr_io; | ||
58 | u8 tmpval8; | ||
59 | |||
60 | #ifdef CONFIG_FS_ENET | ||
61 | iop8xx_t *io_port; | ||
62 | #endif | ||
63 | |||
64 | bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); | ||
65 | cp = (cpm8xx_t *)immr_map(im_cpm); | ||
66 | |||
67 | if (bcsr_io == NULL) { | ||
68 | printk(KERN_CRIT "Could not remap BCSR\n"); | ||
69 | return; | ||
70 | } | ||
71 | #ifdef CONFIG_SERIAL_CPM_SMC1 | ||
72 | clrbits32(bcsr_io, BCSR1_RS232EN_1); | ||
73 | clrbits32(&cp->cp_simode, 0xe0000000 >> 17); /* brg1 */ | ||
74 | tmpval8 = in_8(&(cp->cp_smc[0].smc_smcm)) | (SMCM_RX | SMCM_TX); | ||
75 | out_8(&(cp->cp_smc[0].smc_smcm), tmpval8); | ||
76 | clrbits16(&cp->cp_smc[0].smc_smcmr, SMCMR_REN | SMCMR_TEN); /* brg1 */ | ||
77 | #else | ||
78 | setbits32(bcsr_io,BCSR1_RS232EN_1); | ||
79 | out_be16(&cp->cp_smc[0].smc_smcmr, 0); | ||
80 | out_8(&cp->cp_smc[0].smc_smce, 0); | ||
81 | #endif | ||
82 | |||
83 | #ifdef CONFIG_SERIAL_CPM_SMC2 | ||
84 | clrbits32(bcsr_io,BCSR1_RS232EN_2); | ||
85 | clrbits32(&cp->cp_simode, 0xe0000000 >> 1); | ||
86 | setbits32(&cp->cp_simode, 0x20000000 >> 1); /* brg2 */ | ||
87 | tmpval8 = in_8(&(cp->cp_smc[1].smc_smcm)) | (SMCM_RX | SMCM_TX); | ||
88 | out_8(&(cp->cp_smc[1].smc_smcm), tmpval8); | ||
89 | clrbits16(&cp->cp_smc[1].smc_smcmr, SMCMR_REN | SMCMR_TEN); | ||
90 | |||
91 | init_smc2_uart_ioports(0); | ||
92 | #else | ||
93 | setbits32(bcsr_io,BCSR1_RS232EN_2); | ||
94 | out_be16(&cp->cp_smc[1].smc_smcmr, 0); | ||
95 | out_8(&cp->cp_smc[1].smc_smce, 0); | ||
96 | #endif | ||
97 | immr_unmap(cp); | ||
98 | iounmap(bcsr_io); | ||
99 | |||
100 | #ifdef CONFIG_FS_ENET | ||
101 | /* use MDC for MII (common) */ | ||
102 | io_port = (iop8xx_t*)immr_map(im_ioport); | ||
103 | setbits16(&io_port->iop_pdpar, 0x0080); | ||
104 | clrbits16(&io_port->iop_pddir, 0x0080); | ||
105 | |||
106 | bcsr_io = ioremap(BCSR5, sizeof(unsigned long)); | ||
107 | clrbits32(bcsr_io,BCSR5_MII1_EN); | ||
108 | clrbits32(bcsr_io,BCSR5_MII1_RST); | ||
109 | #ifndef CONFIG_FC_ENET_HAS_SCC | ||
110 | clrbits32(bcsr_io,BCSR5_MII2_EN); | ||
111 | clrbits32(bcsr_io,BCSR5_MII2_RST); | ||
112 | |||
113 | #endif | ||
114 | iounmap(bcsr_io); | ||
115 | immr_unmap(io_port); | ||
116 | |||
117 | #endif | ||
118 | } | ||
119 | |||
120 | |||
121 | static void init_fec1_ioports(struct fs_platform_info* ptr) | ||
122 | { | ||
123 | cpm8xx_t *cp = (cpm8xx_t *)immr_map(im_cpm); | ||
124 | iop8xx_t *io_port = (iop8xx_t *)immr_map(im_ioport); | ||
125 | |||
126 | /* configure FEC1 pins */ | ||
127 | setbits16(&io_port->iop_papar, 0xf830); | ||
128 | setbits16(&io_port->iop_padir, 0x0830); | ||
129 | clrbits16(&io_port->iop_padir, 0xf000); | ||
130 | |||
131 | setbits32(&cp->cp_pbpar, 0x00001001); | ||
132 | clrbits32(&cp->cp_pbdir, 0x00001001); | ||
133 | |||
134 | setbits16(&io_port->iop_pcpar, 0x000c); | ||
135 | clrbits16(&io_port->iop_pcdir, 0x000c); | ||
136 | |||
137 | setbits32(&cp->cp_pepar, 0x00000003); | ||
138 | setbits32(&cp->cp_pedir, 0x00000003); | ||
139 | clrbits32(&cp->cp_peso, 0x00000003); | ||
140 | clrbits32(&cp->cp_cptr, 0x00000100); | ||
141 | |||
142 | immr_unmap(io_port); | ||
143 | immr_unmap(cp); | ||
144 | } | ||
145 | |||
146 | |||
147 | static void init_fec2_ioports(struct fs_platform_info* ptr) | ||
148 | { | ||
149 | cpm8xx_t *cp = (cpm8xx_t *)immr_map(im_cpm); | ||
150 | iop8xx_t *io_port = (iop8xx_t *)immr_map(im_ioport); | ||
151 | |||
152 | /* configure FEC2 pins */ | ||
153 | setbits32(&cp->cp_pepar, 0x0003fffc); | ||
154 | setbits32(&cp->cp_pedir, 0x0003fffc); | ||
155 | clrbits32(&cp->cp_peso, 0x000087fc); | ||
156 | setbits32(&cp->cp_peso, 0x00037800); | ||
157 | clrbits32(&cp->cp_cptr, 0x00000080); | ||
158 | |||
159 | immr_unmap(io_port); | ||
160 | immr_unmap(cp); | ||
161 | } | ||
162 | |||
163 | void init_fec_ioports(struct fs_platform_info *fpi) | ||
164 | { | ||
165 | int fec_no = fs_get_fec_index(fpi->fs_no); | ||
166 | |||
167 | switch (fec_no) { | ||
168 | case 0: | ||
169 | init_fec1_ioports(fpi); | ||
170 | break; | ||
171 | case 1: | ||
172 | init_fec2_ioports(fpi); | ||
173 | break; | ||
174 | default: | ||
175 | printk(KERN_ERR "init_fec_ioports: invalid FEC number\n"); | ||
176 | return; | ||
177 | } | ||
178 | } | ||
179 | |||
180 | static void init_scc3_ioports(struct fs_platform_info* fpi) | ||
181 | { | ||
182 | unsigned *bcsr_io; | ||
183 | iop8xx_t *io_port; | ||
184 | cpm8xx_t *cp; | ||
185 | |||
186 | bcsr_io = ioremap(BCSR_ADDR, BCSR_SIZE); | ||
187 | io_port = (iop8xx_t *)immr_map(im_ioport); | ||
188 | cp = (cpm8xx_t *)immr_map(im_cpm); | ||
189 | |||
190 | if (bcsr_io == NULL) { | ||
191 | printk(KERN_CRIT "Could not remap BCSR\n"); | ||
192 | return; | ||
193 | } | ||
194 | |||
195 | /* Enable the PHY. | ||
196 | */ | ||
197 | clrbits32(bcsr_io+4, BCSR4_ETH10_RST); | ||
198 | udelay(1000); | ||
199 | setbits32(bcsr_io+4, BCSR4_ETH10_RST); | ||
200 | /* Configure port A pins for Txd and Rxd. | ||
201 | */ | ||
202 | setbits16(&io_port->iop_papar, PA_ENET_RXD | PA_ENET_TXD); | ||
203 | clrbits16(&io_port->iop_padir, PA_ENET_RXD | PA_ENET_TXD); | ||
204 | |||
205 | /* Configure port C pins to enable CLSN and RENA. | ||
206 | */ | ||
207 | clrbits16(&io_port->iop_pcpar, PC_ENET_CLSN | PC_ENET_RENA); | ||
208 | clrbits16(&io_port->iop_pcdir, PC_ENET_CLSN | PC_ENET_RENA); | ||
209 | setbits16(&io_port->iop_pcso, PC_ENET_CLSN | PC_ENET_RENA); | ||
210 | |||
211 | /* Configure port E for TCLK and RCLK. | ||
212 | */ | ||
213 | setbits32(&cp->cp_pepar, PE_ENET_TCLK | PE_ENET_RCLK); | ||
214 | clrbits32(&cp->cp_pepar, PE_ENET_TENA); | ||
215 | clrbits32(&cp->cp_pedir, | ||
216 | PE_ENET_TCLK | PE_ENET_RCLK | PE_ENET_TENA); | ||
217 | clrbits32(&cp->cp_peso, PE_ENET_TCLK | PE_ENET_RCLK); | ||
218 | setbits32(&cp->cp_peso, PE_ENET_TENA); | ||
219 | |||
220 | /* Configure Serial Interface clock routing. | ||
221 | * First, clear all SCC bits to zero, then set the ones we want. | ||
222 | */ | ||
223 | clrbits32(&cp->cp_sicr, SICR_ENET_MASK); | ||
224 | setbits32(&cp->cp_sicr, SICR_ENET_CLKRT); | ||
225 | |||
226 | /* Disable Rx and Tx. SMC1 sshould be stopped if SCC3 eternet are used. | ||
227 | */ | ||
228 | clrbits16(&cp->cp_smc[0].smc_smcmr, SMCMR_REN | SMCMR_TEN); | ||
229 | /* On the MPC885ADS SCC ethernet PHY is initialized in the full duplex mode | ||
230 | * by H/W setting after reset. SCC ethernet controller support only half duplex. | ||
231 | * This discrepancy of modes causes a lot of carrier lost errors. | ||
232 | */ | ||
233 | |||
234 | /* In the original SCC enet driver the following code is placed at | ||
235 | the end of the initialization */ | ||
236 | setbits32(&cp->cp_pepar, PE_ENET_TENA); | ||
237 | clrbits32(&cp->cp_pedir, PE_ENET_TENA); | ||
238 | setbits32(&cp->cp_peso, PE_ENET_TENA); | ||
239 | |||
240 | setbits32(bcsr_io+4, BCSR1_ETHEN); | ||
241 | iounmap(bcsr_io); | ||
242 | immr_unmap(io_port); | ||
243 | immr_unmap(cp); | ||
244 | } | ||
245 | |||
246 | void init_scc_ioports(struct fs_platform_info *fpi) | ||
247 | { | ||
248 | int scc_no = fs_get_scc_index(fpi->fs_no); | ||
249 | |||
250 | switch (scc_no) { | ||
251 | case 2: | ||
252 | init_scc3_ioports(fpi); | ||
253 | break; | ||
254 | default: | ||
255 | printk(KERN_ERR "init_scc_ioports: invalid SCC number\n"); | ||
256 | return; | ||
257 | } | ||
258 | } | ||
259 | |||
260 | |||
261 | |||
262 | static void init_smc1_uart_ioports(struct fs_uart_platform_info* ptr) | ||
263 | { | ||
264 | unsigned *bcsr_io; | ||
265 | cpm8xx_t *cp; | ||
266 | |||
267 | cp = (cpm8xx_t *)immr_map(im_cpm); | ||
268 | setbits32(&cp->cp_pepar, 0x000000c0); | ||
269 | clrbits32(&cp->cp_pedir, 0x000000c0); | ||
270 | clrbits32(&cp->cp_peso, 0x00000040); | ||
271 | setbits32(&cp->cp_peso, 0x00000080); | ||
272 | immr_unmap(cp); | ||
273 | |||
274 | bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); | ||
275 | |||
276 | if (bcsr_io == NULL) { | ||
277 | printk(KERN_CRIT "Could not remap BCSR1\n"); | ||
278 | return; | ||
279 | } | ||
280 | clrbits32(bcsr_io,BCSR1_RS232EN_1); | ||
281 | iounmap(bcsr_io); | ||
282 | } | ||
283 | |||
284 | static void init_smc2_uart_ioports(struct fs_uart_platform_info* fpi) | ||
285 | { | ||
286 | unsigned *bcsr_io; | ||
287 | cpm8xx_t *cp; | ||
288 | |||
289 | cp = (cpm8xx_t *)immr_map(im_cpm); | ||
290 | setbits32(&cp->cp_pepar, 0x00000c00); | ||
291 | clrbits32(&cp->cp_pedir, 0x00000c00); | ||
292 | clrbits32(&cp->cp_peso, 0x00000400); | ||
293 | setbits32(&cp->cp_peso, 0x00000800); | ||
294 | immr_unmap(cp); | ||
295 | |||
296 | bcsr_io = ioremap(BCSR1, sizeof(unsigned long)); | ||
297 | |||
298 | if (bcsr_io == NULL) { | ||
299 | printk(KERN_CRIT "Could not remap BCSR1\n"); | ||
300 | return; | ||
301 | } | ||
302 | clrbits32(bcsr_io,BCSR1_RS232EN_2); | ||
303 | iounmap(bcsr_io); | ||
304 | } | ||
305 | |||
306 | void init_smc_ioports(struct fs_uart_platform_info *data) | ||
307 | { | ||
308 | int smc_no = fs_uart_id_fsid2smc(data->fs_no); | ||
309 | |||
310 | switch (smc_no) { | ||
311 | case 0: | ||
312 | init_smc1_uart_ioports(data); | ||
313 | data->brg = data->clk_rx; | ||
314 | break; | ||
315 | case 1: | ||
316 | init_smc2_uart_ioports(data); | ||
317 | data->brg = data->clk_rx; | ||
318 | break; | ||
319 | default: | ||
320 | printk(KERN_ERR "init_scc_ioports: invalid SCC number\n"); | ||
321 | return; | ||
322 | } | ||
323 | } | ||
324 | |||
325 | int platform_device_skip(char *model, int id) | ||
326 | { | ||
327 | #ifdef CONFIG_MPC8xx_SECOND_ETH_SCC3 | ||
328 | const char *dev = "FEC"; | ||
329 | int n = 2; | ||
330 | #else | ||
331 | const char *dev = "SCC"; | ||
332 | int n = 3; | ||
333 | #endif | ||
334 | |||
335 | if (!strcmp(model, dev) && n == id) | ||
336 | return 1; | ||
337 | |||
338 | return 0; | ||
339 | } | ||
340 | |||
341 | static void __init mpc885ads_setup_arch(void) | ||
342 | { | ||
343 | struct device_node *cpu; | ||
344 | |||
345 | cpu = of_find_node_by_type(NULL, "cpu"); | ||
346 | if (cpu != 0) { | ||
347 | const unsigned int *fp; | ||
348 | |||
349 | fp = get_property(cpu, "clock-frequency", NULL); | ||
350 | if (fp != 0) | ||
351 | loops_per_jiffy = *fp / HZ; | ||
352 | else | ||
353 | loops_per_jiffy = 50000000 / HZ; | ||
354 | of_node_put(cpu); | ||
355 | } | ||
356 | |||
357 | cpm_reset(); | ||
358 | |||
359 | mpc885ads_board_setup(); | ||
360 | |||
361 | ROOT_DEV = Root_NFS; | ||
362 | } | ||
363 | |||
364 | static int __init mpc885ads_probe(void) | ||
365 | { | ||
366 | char *model = of_get_flat_dt_prop(of_get_flat_dt_root(), | ||
367 | "model", NULL); | ||
368 | if (model == NULL) | ||
369 | return 0; | ||
370 | if (strcmp(model, "MPC885ADS")) | ||
371 | return 0; | ||
372 | |||
373 | return 1; | ||
374 | } | ||
375 | |||
376 | define_machine(mpc885_ads) { | ||
377 | .name = "MPC885 ADS", | ||
378 | .probe = mpc885ads_probe, | ||
379 | .setup_arch = mpc885ads_setup_arch, | ||
380 | .init_IRQ = m8xx_pic_init, | ||
381 | .show_cpuinfo = mpc8xx_show_cpuinfo, | ||
382 | .get_irq = mpc8xx_get_irq, | ||
383 | .restart = mpc8xx_restart, | ||
384 | .calibrate_decr = mpc8xx_calibrate_decr, | ||
385 | .set_rtc_time = mpc8xx_set_rtc_time, | ||
386 | .get_rtc_time = mpc8xx_get_rtc_time, | ||
387 | }; | ||
diff --git a/arch/powerpc/platforms/Makefile b/arch/powerpc/platforms/Makefile index 507d1b98f270..452004283f17 100644 --- a/arch/powerpc/platforms/Makefile +++ b/arch/powerpc/platforms/Makefile | |||
@@ -5,9 +5,11 @@ ifeq ($(CONFIG_PPC64),y) | |||
5 | obj-$(CONFIG_PPC_PMAC) += powermac/ | 5 | obj-$(CONFIG_PPC_PMAC) += powermac/ |
6 | endif | 6 | endif |
7 | endif | 7 | endif |
8 | obj-$(CONFIG_PPC_MPC52xx) += 52xx/ | ||
9 | obj-$(CONFIG_PPC_CHRP) += chrp/ | 8 | obj-$(CONFIG_PPC_CHRP) += chrp/ |
10 | obj-$(CONFIG_4xx) += 4xx/ | 9 | obj-$(CONFIG_4xx) += 4xx/ |
10 | obj-$(CONFIG_PPC_MPC52xx) += 52xx/ | ||
11 | obj-$(CONFIG_PPC_8xx) += 8xx/ | ||
12 | obj-$(CONFIG_PPC_82xx) += 82xx/ | ||
11 | obj-$(CONFIG_PPC_83xx) += 83xx/ | 13 | obj-$(CONFIG_PPC_83xx) += 83xx/ |
12 | obj-$(CONFIG_PPC_85xx) += 85xx/ | 14 | obj-$(CONFIG_PPC_85xx) += 85xx/ |
13 | obj-$(CONFIG_PPC_86xx) += 86xx/ | 15 | obj-$(CONFIG_PPC_86xx) += 86xx/ |
@@ -17,4 +19,5 @@ obj-$(CONFIG_PPC_MAPLE) += maple/ | |||
17 | obj-$(CONFIG_PPC_PASEMI) += pasemi/ | 19 | obj-$(CONFIG_PPC_PASEMI) += pasemi/ |
18 | obj-$(CONFIG_PPC_CELL) += cell/ | 20 | obj-$(CONFIG_PPC_CELL) += cell/ |
19 | obj-$(CONFIG_PPC_PS3) += ps3/ | 21 | obj-$(CONFIG_PPC_PS3) += ps3/ |
22 | obj-$(CONFIG_PPC_CELLEB) += celleb/ | ||
20 | obj-$(CONFIG_EMBEDDED6xx) += embedded6xx/ | 23 | obj-$(CONFIG_EMBEDDED6xx) += embedded6xx/ |
diff --git a/arch/powerpc/platforms/cell/Makefile b/arch/powerpc/platforms/cell/Makefile index f90e8337796c..869af89df6ff 100644 --- a/arch/powerpc/platforms/cell/Makefile +++ b/arch/powerpc/platforms/cell/Makefile | |||
@@ -14,7 +14,12 @@ endif | |||
14 | spufs-modular-$(CONFIG_SPU_FS) += spu_syscalls.o | 14 | spufs-modular-$(CONFIG_SPU_FS) += spu_syscalls.o |
15 | spu-priv1-$(CONFIG_PPC_CELL_NATIVE) += spu_priv1_mmio.o | 15 | spu-priv1-$(CONFIG_PPC_CELL_NATIVE) += spu_priv1_mmio.o |
16 | 16 | ||
17 | spu-manage-$(CONFIG_PPC_CELLEB) += spu_manage.o | ||
18 | spu-manage-$(CONFIG_PPC_CELL_NATIVE) += spu_manage.o | ||
19 | |||
17 | obj-$(CONFIG_SPU_BASE) += spu_callbacks.o spu_base.o \ | 20 | obj-$(CONFIG_SPU_BASE) += spu_callbacks.o spu_base.o \ |
18 | spu_coredump.o \ | 21 | spu_coredump.o \ |
19 | $(spufs-modular-m) \ | 22 | $(spufs-modular-m) \ |
20 | $(spu-priv1-y) spufs/ | 23 | $(spu-priv1-y) \ |
24 | $(spu-manage-y) \ | ||
25 | spufs/ | ||
diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c index b43466ba8096..67d617b60a23 100644 --- a/arch/powerpc/platforms/cell/iommu.c +++ b/arch/powerpc/platforms/cell/iommu.c | |||
@@ -149,7 +149,8 @@ static int cbe_nr_iommus; | |||
149 | static void invalidate_tce_cache(struct cbe_iommu *iommu, unsigned long *pte, | 149 | static void invalidate_tce_cache(struct cbe_iommu *iommu, unsigned long *pte, |
150 | long n_ptes) | 150 | long n_ptes) |
151 | { | 151 | { |
152 | unsigned long *reg, val; | 152 | unsigned long __iomem *reg; |
153 | unsigned long val; | ||
153 | long n; | 154 | long n; |
154 | 155 | ||
155 | reg = iommu->xlate_regs + IOC_IOPT_CacheInvd; | 156 | reg = iommu->xlate_regs + IOC_IOPT_CacheInvd; |
@@ -592,7 +593,7 @@ static void __init cell_iommu_init_one(struct device_node *np, unsigned long off | |||
592 | /* Init base fields */ | 593 | /* Init base fields */ |
593 | i = cbe_nr_iommus++; | 594 | i = cbe_nr_iommus++; |
594 | iommu = &iommus[i]; | 595 | iommu = &iommus[i]; |
595 | iommu->stab = 0; | 596 | iommu->stab = NULL; |
596 | iommu->nid = nid; | 597 | iommu->nid = nid; |
597 | snprintf(iommu->name, sizeof(iommu->name), "iommu%d", i); | 598 | snprintf(iommu->name, sizeof(iommu->name), "iommu%d", i); |
598 | INIT_LIST_HEAD(&iommu->windows); | 599 | INIT_LIST_HEAD(&iommu->windows); |
diff --git a/arch/powerpc/platforms/cell/pmu.c b/arch/powerpc/platforms/cell/pmu.c index d04ae1671e6c..66ca4b5a1dbc 100644 --- a/arch/powerpc/platforms/cell/pmu.c +++ b/arch/powerpc/platforms/cell/pmu.c | |||
@@ -345,18 +345,12 @@ EXPORT_SYMBOL_GPL(cbe_read_trace_buffer); | |||
345 | * Enabling/disabling interrupts for the entire performance monitoring unit. | 345 | * Enabling/disabling interrupts for the entire performance monitoring unit. |
346 | */ | 346 | */ |
347 | 347 | ||
348 | u32 cbe_query_pm_interrupts(u32 cpu) | 348 | u32 cbe_get_and_clear_pm_interrupts(u32 cpu) |
349 | { | ||
350 | return cbe_read_pm(cpu, pm_status); | ||
351 | } | ||
352 | EXPORT_SYMBOL_GPL(cbe_query_pm_interrupts); | ||
353 | |||
354 | u32 cbe_clear_pm_interrupts(u32 cpu) | ||
355 | { | 349 | { |
356 | /* Reading pm_status clears the interrupt bits. */ | 350 | /* Reading pm_status clears the interrupt bits. */ |
357 | return cbe_query_pm_interrupts(cpu); | 351 | return cbe_read_pm(cpu, pm_status); |
358 | } | 352 | } |
359 | EXPORT_SYMBOL_GPL(cbe_clear_pm_interrupts); | 353 | EXPORT_SYMBOL_GPL(cbe_get_and_clear_pm_interrupts); |
360 | 354 | ||
361 | void cbe_enable_pm_interrupts(u32 cpu, u32 thread, u32 mask) | 355 | void cbe_enable_pm_interrupts(u32 cpu, u32 thread, u32 mask) |
362 | { | 356 | { |
@@ -371,7 +365,7 @@ EXPORT_SYMBOL_GPL(cbe_enable_pm_interrupts); | |||
371 | 365 | ||
372 | void cbe_disable_pm_interrupts(u32 cpu) | 366 | void cbe_disable_pm_interrupts(u32 cpu) |
373 | { | 367 | { |
374 | cbe_clear_pm_interrupts(cpu); | 368 | cbe_get_and_clear_pm_interrupts(cpu); |
375 | cbe_write_pm(cpu, pm_status, 0); | 369 | cbe_write_pm(cpu, pm_status, 0); |
376 | } | 370 | } |
377 | EXPORT_SYMBOL_GPL(cbe_disable_pm_interrupts); | 371 | EXPORT_SYMBOL_GPL(cbe_disable_pm_interrupts); |
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c index bd7bffc3ddd0..c43999a10deb 100644 --- a/arch/powerpc/platforms/cell/spu_base.c +++ b/arch/powerpc/platforms/cell/spu_base.c | |||
@@ -170,9 +170,11 @@ int | |||
170 | spu_irq_class_0_bottom(struct spu *spu) | 170 | spu_irq_class_0_bottom(struct spu *spu) |
171 | { | 171 | { |
172 | unsigned long stat, mask; | 172 | unsigned long stat, mask; |
173 | unsigned long flags; | ||
173 | 174 | ||
174 | spu->class_0_pending = 0; | 175 | spu->class_0_pending = 0; |
175 | 176 | ||
177 | spin_lock_irqsave(&spu->register_lock, flags); | ||
176 | mask = spu_int_mask_get(spu, 0); | 178 | mask = spu_int_mask_get(spu, 0); |
177 | stat = spu_int_stat_get(spu, 0); | 179 | stat = spu_int_stat_get(spu, 0); |
178 | 180 | ||
@@ -188,6 +190,7 @@ spu_irq_class_0_bottom(struct spu *spu) | |||
188 | __spu_trap_error(spu); | 190 | __spu_trap_error(spu); |
189 | 191 | ||
190 | spu_int_stat_clear(spu, 0, stat); | 192 | spu_int_stat_clear(spu, 0, stat); |
193 | spin_unlock_irqrestore(&spu->register_lock, flags); | ||
191 | 194 | ||
192 | return (stat & 0x7) ? -EIO : 0; | 195 | return (stat & 0x7) ? -EIO : 0; |
193 | } | 196 | } |
diff --git a/arch/powerpc/platforms/cell/spu_manage.c b/arch/powerpc/platforms/cell/spu_manage.c new file mode 100644 index 000000000000..e34599f53d28 --- /dev/null +++ b/arch/powerpc/platforms/cell/spu_manage.c | |||
@@ -0,0 +1,366 @@ | |||
1 | /* | ||
2 | * spu management operations for of based platforms | ||
3 | * | ||
4 | * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 | ||
5 | * Copyright 2006 Sony Corp. | ||
6 | * (C) Copyright 2007 TOSHIBA CORPORATION | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; version 2 of the License. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along | ||
18 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/interrupt.h> | ||
23 | #include <linux/list.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/ptrace.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/wait.h> | ||
28 | #include <linux/mm.h> | ||
29 | #include <linux/io.h> | ||
30 | #include <linux/mutex.h> | ||
31 | #include <linux/device.h> | ||
32 | |||
33 | #include <asm/spu.h> | ||
34 | #include <asm/spu_priv1.h> | ||
35 | #include <asm/firmware.h> | ||
36 | #include <asm/prom.h> | ||
37 | |||
38 | #include "interrupt.h" | ||
39 | |||
40 | struct device_node *spu_devnode(struct spu *spu) | ||
41 | { | ||
42 | return spu->devnode; | ||
43 | } | ||
44 | |||
45 | EXPORT_SYMBOL_GPL(spu_devnode); | ||
46 | |||
47 | static u64 __init find_spu_unit_number(struct device_node *spe) | ||
48 | { | ||
49 | const unsigned int *prop; | ||
50 | int proplen; | ||
51 | prop = get_property(spe, "unit-id", &proplen); | ||
52 | if (proplen == 4) | ||
53 | return (u64)*prop; | ||
54 | |||
55 | prop = get_property(spe, "reg", &proplen); | ||
56 | if (proplen == 4) | ||
57 | return (u64)*prop; | ||
58 | |||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | static void spu_unmap(struct spu *spu) | ||
63 | { | ||
64 | if (!firmware_has_feature(FW_FEATURE_LPAR)) | ||
65 | iounmap(spu->priv1); | ||
66 | iounmap(spu->priv2); | ||
67 | iounmap(spu->problem); | ||
68 | iounmap((__force u8 __iomem *)spu->local_store); | ||
69 | } | ||
70 | |||
71 | static int __init spu_map_interrupts_old(struct spu *spu, | ||
72 | struct device_node *np) | ||
73 | { | ||
74 | unsigned int isrc; | ||
75 | const u32 *tmp; | ||
76 | int nid; | ||
77 | |||
78 | /* Get the interrupt source unit from the device-tree */ | ||
79 | tmp = get_property(np, "isrc", NULL); | ||
80 | if (!tmp) | ||
81 | return -ENODEV; | ||
82 | isrc = tmp[0]; | ||
83 | |||
84 | tmp = get_property(np->parent->parent, "node-id", NULL); | ||
85 | if (!tmp) { | ||
86 | printk(KERN_WARNING "%s: can't find node-id\n", __FUNCTION__); | ||
87 | nid = spu->node; | ||
88 | } else | ||
89 | nid = tmp[0]; | ||
90 | |||
91 | /* Add the node number */ | ||
92 | isrc |= nid << IIC_IRQ_NODE_SHIFT; | ||
93 | |||
94 | /* Now map interrupts of all 3 classes */ | ||
95 | spu->irqs[0] = irq_create_mapping(NULL, IIC_IRQ_CLASS_0 | isrc); | ||
96 | spu->irqs[1] = irq_create_mapping(NULL, IIC_IRQ_CLASS_1 | isrc); | ||
97 | spu->irqs[2] = irq_create_mapping(NULL, IIC_IRQ_CLASS_2 | isrc); | ||
98 | |||
99 | /* Right now, we only fail if class 2 failed */ | ||
100 | return spu->irqs[2] == NO_IRQ ? -EINVAL : 0; | ||
101 | } | ||
102 | |||
103 | static void __iomem * __init spu_map_prop_old(struct spu *spu, | ||
104 | struct device_node *n, | ||
105 | const char *name) | ||
106 | { | ||
107 | const struct address_prop { | ||
108 | unsigned long address; | ||
109 | unsigned int len; | ||
110 | } __attribute__((packed)) *prop; | ||
111 | int proplen; | ||
112 | |||
113 | prop = get_property(n, name, &proplen); | ||
114 | if (prop == NULL || proplen != sizeof (struct address_prop)) | ||
115 | return NULL; | ||
116 | |||
117 | return ioremap(prop->address, prop->len); | ||
118 | } | ||
119 | |||
120 | static int __init spu_map_device_old(struct spu *spu) | ||
121 | { | ||
122 | struct device_node *node = spu->devnode; | ||
123 | const char *prop; | ||
124 | int ret; | ||
125 | |||
126 | ret = -ENODEV; | ||
127 | spu->name = get_property(node, "name", NULL); | ||
128 | if (!spu->name) | ||
129 | goto out; | ||
130 | |||
131 | prop = get_property(node, "local-store", NULL); | ||
132 | if (!prop) | ||
133 | goto out; | ||
134 | spu->local_store_phys = *(unsigned long *)prop; | ||
135 | |||
136 | /* we use local store as ram, not io memory */ | ||
137 | spu->local_store = (void __force *) | ||
138 | spu_map_prop_old(spu, node, "local-store"); | ||
139 | if (!spu->local_store) | ||
140 | goto out; | ||
141 | |||
142 | prop = get_property(node, "problem", NULL); | ||
143 | if (!prop) | ||
144 | goto out_unmap; | ||
145 | spu->problem_phys = *(unsigned long *)prop; | ||
146 | |||
147 | spu->problem = spu_map_prop_old(spu, node, "problem"); | ||
148 | if (!spu->problem) | ||
149 | goto out_unmap; | ||
150 | |||
151 | spu->priv2 = spu_map_prop_old(spu, node, "priv2"); | ||
152 | if (!spu->priv2) | ||
153 | goto out_unmap; | ||
154 | |||
155 | if (!firmware_has_feature(FW_FEATURE_LPAR)) { | ||
156 | spu->priv1 = spu_map_prop_old(spu, node, "priv1"); | ||
157 | if (!spu->priv1) | ||
158 | goto out_unmap; | ||
159 | } | ||
160 | |||
161 | ret = 0; | ||
162 | goto out; | ||
163 | |||
164 | out_unmap: | ||
165 | spu_unmap(spu); | ||
166 | out: | ||
167 | return ret; | ||
168 | } | ||
169 | |||
170 | static int __init spu_map_interrupts(struct spu *spu, struct device_node *np) | ||
171 | { | ||
172 | struct of_irq oirq; | ||
173 | int ret; | ||
174 | int i; | ||
175 | |||
176 | for (i=0; i < 3; i++) { | ||
177 | ret = of_irq_map_one(np, i, &oirq); | ||
178 | if (ret) { | ||
179 | pr_debug("spu_new: failed to get irq %d\n", i); | ||
180 | goto err; | ||
181 | } | ||
182 | ret = -EINVAL; | ||
183 | pr_debug(" irq %d no 0x%x on %s\n", i, oirq.specifier[0], | ||
184 | oirq.controller->full_name); | ||
185 | spu->irqs[i] = irq_create_of_mapping(oirq.controller, | ||
186 | oirq.specifier, oirq.size); | ||
187 | if (spu->irqs[i] == NO_IRQ) { | ||
188 | pr_debug("spu_new: failed to map it !\n"); | ||
189 | goto err; | ||
190 | } | ||
191 | } | ||
192 | return 0; | ||
193 | |||
194 | err: | ||
195 | pr_debug("failed to map irq %x for spu %s\n", *oirq.specifier, | ||
196 | spu->name); | ||
197 | for (; i >= 0; i--) { | ||
198 | if (spu->irqs[i] != NO_IRQ) | ||
199 | irq_dispose_mapping(spu->irqs[i]); | ||
200 | } | ||
201 | return ret; | ||
202 | } | ||
203 | |||
204 | static int spu_map_resource(struct spu *spu, int nr, | ||
205 | void __iomem** virt, unsigned long *phys) | ||
206 | { | ||
207 | struct device_node *np = spu->devnode; | ||
208 | struct resource resource = { }; | ||
209 | unsigned long len; | ||
210 | int ret; | ||
211 | |||
212 | ret = of_address_to_resource(np, nr, &resource); | ||
213 | if (ret) | ||
214 | return ret; | ||
215 | if (phys) | ||
216 | *phys = resource.start; | ||
217 | len = resource.end - resource.start + 1; | ||
218 | *virt = ioremap(resource.start, len); | ||
219 | if (!*virt) | ||
220 | return -EINVAL; | ||
221 | return 0; | ||
222 | } | ||
223 | |||
224 | static int __init spu_map_device(struct spu *spu) | ||
225 | { | ||
226 | struct device_node *np = spu->devnode; | ||
227 | int ret = -ENODEV; | ||
228 | |||
229 | spu->name = get_property(np, "name", NULL); | ||
230 | if (!spu->name) | ||
231 | goto out; | ||
232 | |||
233 | ret = spu_map_resource(spu, 0, (void __iomem**)&spu->local_store, | ||
234 | &spu->local_store_phys); | ||
235 | if (ret) { | ||
236 | pr_debug("spu_new: failed to map %s resource 0\n", | ||
237 | np->full_name); | ||
238 | goto out; | ||
239 | } | ||
240 | ret = spu_map_resource(spu, 1, (void __iomem**)&spu->problem, | ||
241 | &spu->problem_phys); | ||
242 | if (ret) { | ||
243 | pr_debug("spu_new: failed to map %s resource 1\n", | ||
244 | np->full_name); | ||
245 | goto out_unmap; | ||
246 | } | ||
247 | ret = spu_map_resource(spu, 2, (void __iomem**)&spu->priv2, NULL); | ||
248 | if (ret) { | ||
249 | pr_debug("spu_new: failed to map %s resource 2\n", | ||
250 | np->full_name); | ||
251 | goto out_unmap; | ||
252 | } | ||
253 | if (!firmware_has_feature(FW_FEATURE_LPAR)) | ||
254 | ret = spu_map_resource(spu, 3, | ||
255 | (void __iomem**)&spu->priv1, NULL); | ||
256 | if (ret) { | ||
257 | pr_debug("spu_new: failed to map %s resource 3\n", | ||
258 | np->full_name); | ||
259 | goto out_unmap; | ||
260 | } | ||
261 | pr_debug("spu_new: %s maps:\n", np->full_name); | ||
262 | pr_debug(" local store : 0x%016lx -> 0x%p\n", | ||
263 | spu->local_store_phys, spu->local_store); | ||
264 | pr_debug(" problem state : 0x%016lx -> 0x%p\n", | ||
265 | spu->problem_phys, spu->problem); | ||
266 | pr_debug(" priv2 : 0x%p\n", spu->priv2); | ||
267 | pr_debug(" priv1 : 0x%p\n", spu->priv1); | ||
268 | |||
269 | return 0; | ||
270 | |||
271 | out_unmap: | ||
272 | spu_unmap(spu); | ||
273 | out: | ||
274 | pr_debug("failed to map spe %s: %d\n", spu->name, ret); | ||
275 | return ret; | ||
276 | } | ||
277 | |||
278 | static int __init of_enumerate_spus(int (*fn)(void *data)) | ||
279 | { | ||
280 | int ret; | ||
281 | struct device_node *node; | ||
282 | |||
283 | ret = -ENODEV; | ||
284 | for (node = of_find_node_by_type(NULL, "spe"); | ||
285 | node; node = of_find_node_by_type(node, "spe")) { | ||
286 | ret = fn(node); | ||
287 | if (ret) { | ||
288 | printk(KERN_WARNING "%s: Error initializing %s\n", | ||
289 | __FUNCTION__, node->name); | ||
290 | break; | ||
291 | } | ||
292 | } | ||
293 | return ret; | ||
294 | } | ||
295 | |||
296 | static int __init of_create_spu(struct spu *spu, void *data) | ||
297 | { | ||
298 | int ret; | ||
299 | struct device_node *spe = (struct device_node *)data; | ||
300 | static int legacy_map = 0, legacy_irq = 0; | ||
301 | |||
302 | spu->devnode = of_node_get(spe); | ||
303 | spu->spe_id = find_spu_unit_number(spe); | ||
304 | |||
305 | spu->node = of_node_to_nid(spe); | ||
306 | if (spu->node >= MAX_NUMNODES) { | ||
307 | printk(KERN_WARNING "SPE %s on node %d ignored," | ||
308 | " node number too big\n", spe->full_name, spu->node); | ||
309 | printk(KERN_WARNING "Check if CONFIG_NUMA is enabled.\n"); | ||
310 | ret = -ENODEV; | ||
311 | goto out; | ||
312 | } | ||
313 | |||
314 | ret = spu_map_device(spu); | ||
315 | if (ret) { | ||
316 | if (!legacy_map) { | ||
317 | legacy_map = 1; | ||
318 | printk(KERN_WARNING "%s: Legacy device tree found, " | ||
319 | "trying to map old style\n", __FUNCTION__); | ||
320 | } | ||
321 | ret = spu_map_device_old(spu); | ||
322 | if (ret) { | ||
323 | printk(KERN_ERR "Unable to map %s\n", | ||
324 | spu->name); | ||
325 | goto out; | ||
326 | } | ||
327 | } | ||
328 | |||
329 | ret = spu_map_interrupts(spu, spe); | ||
330 | if (ret) { | ||
331 | if (!legacy_irq) { | ||
332 | legacy_irq = 1; | ||
333 | printk(KERN_WARNING "%s: Legacy device tree found, " | ||
334 | "trying old style irq\n", __FUNCTION__); | ||
335 | } | ||
336 | ret = spu_map_interrupts_old(spu, spe); | ||
337 | if (ret) { | ||
338 | printk(KERN_ERR "%s: could not map interrupts", | ||
339 | spu->name); | ||
340 | goto out_unmap; | ||
341 | } | ||
342 | } | ||
343 | |||
344 | pr_debug("Using SPE %s %p %p %p %p %d\n", spu->name, | ||
345 | spu->local_store, spu->problem, spu->priv1, | ||
346 | spu->priv2, spu->number); | ||
347 | goto out; | ||
348 | |||
349 | out_unmap: | ||
350 | spu_unmap(spu); | ||
351 | out: | ||
352 | return ret; | ||
353 | } | ||
354 | |||
355 | static int of_destroy_spu(struct spu *spu) | ||
356 | { | ||
357 | spu_unmap(spu); | ||
358 | of_node_put(spu->devnode); | ||
359 | return 0; | ||
360 | } | ||
361 | |||
362 | const struct spu_management_ops spu_management_of_ops = { | ||
363 | .enumerate_spus = of_enumerate_spus, | ||
364 | .create_spu = of_create_spu, | ||
365 | .destroy_spu = of_destroy_spu, | ||
366 | }; | ||
diff --git a/arch/powerpc/platforms/cell/spu_priv1_mmio.c b/arch/powerpc/platforms/cell/spu_priv1_mmio.c index 910a926b61a2..67fa7247b80a 100644 --- a/arch/powerpc/platforms/cell/spu_priv1_mmio.c +++ b/arch/powerpc/platforms/cell/spu_priv1_mmio.c | |||
@@ -37,490 +37,112 @@ | |||
37 | #include "interrupt.h" | 37 | #include "interrupt.h" |
38 | #include "spu_priv1_mmio.h" | 38 | #include "spu_priv1_mmio.h" |
39 | 39 | ||
40 | static DEFINE_MUTEX(add_spumem_mutex); | ||
41 | |||
42 | struct spu_pdata { | ||
43 | struct device_node *devnode; | ||
44 | struct spu_priv1 __iomem *priv1; | ||
45 | }; | ||
46 | |||
47 | static struct spu_pdata *spu_get_pdata(struct spu *spu) | ||
48 | { | ||
49 | BUG_ON(!spu->pdata); | ||
50 | return spu->pdata; | ||
51 | } | ||
52 | |||
53 | struct device_node *spu_devnode(struct spu *spu) | ||
54 | { | ||
55 | return spu_get_pdata(spu)->devnode; | ||
56 | } | ||
57 | |||
58 | EXPORT_SYMBOL_GPL(spu_devnode); | ||
59 | |||
60 | static int __init cell_spuprop_present(struct spu *spu, struct device_node *spe, | ||
61 | const char *prop) | ||
62 | { | ||
63 | const struct address_prop { | ||
64 | unsigned long address; | ||
65 | unsigned int len; | ||
66 | } __attribute__((packed)) *p; | ||
67 | int proplen; | ||
68 | |||
69 | unsigned long start_pfn, nr_pages; | ||
70 | struct pglist_data *pgdata; | ||
71 | struct zone *zone; | ||
72 | int ret; | ||
73 | |||
74 | p = get_property(spe, prop, &proplen); | ||
75 | WARN_ON(proplen != sizeof (*p)); | ||
76 | |||
77 | start_pfn = p->address >> PAGE_SHIFT; | ||
78 | nr_pages = ((unsigned long)p->len + PAGE_SIZE - 1) >> PAGE_SHIFT; | ||
79 | |||
80 | pgdata = NODE_DATA(spu->node); | ||
81 | zone = pgdata->node_zones; | ||
82 | |||
83 | /* XXX rethink locking here */ | ||
84 | mutex_lock(&add_spumem_mutex); | ||
85 | ret = __add_pages(zone, start_pfn, nr_pages); | ||
86 | mutex_unlock(&add_spumem_mutex); | ||
87 | |||
88 | return ret; | ||
89 | } | ||
90 | |||
91 | static void __iomem * __init map_spe_prop(struct spu *spu, | ||
92 | struct device_node *n, const char *name) | ||
93 | { | ||
94 | const struct address_prop { | ||
95 | unsigned long address; | ||
96 | unsigned int len; | ||
97 | } __attribute__((packed)) *prop; | ||
98 | |||
99 | const void *p; | ||
100 | int proplen; | ||
101 | void __iomem *ret = NULL; | ||
102 | int err = 0; | ||
103 | |||
104 | p = get_property(n, name, &proplen); | ||
105 | if (proplen != sizeof (struct address_prop)) | ||
106 | return NULL; | ||
107 | |||
108 | prop = p; | ||
109 | |||
110 | err = cell_spuprop_present(spu, n, name); | ||
111 | if (err && (err != -EEXIST)) | ||
112 | goto out; | ||
113 | |||
114 | ret = ioremap(prop->address, prop->len); | ||
115 | |||
116 | out: | ||
117 | return ret; | ||
118 | } | ||
119 | |||
120 | static void spu_unmap(struct spu *spu) | ||
121 | { | ||
122 | iounmap(spu->priv2); | ||
123 | iounmap(spu_get_pdata(spu)->priv1); | ||
124 | iounmap(spu->problem); | ||
125 | iounmap((__force u8 __iomem *)spu->local_store); | ||
126 | } | ||
127 | |||
128 | static int __init spu_map_interrupts_old(struct spu *spu, | ||
129 | struct device_node *np) | ||
130 | { | ||
131 | unsigned int isrc; | ||
132 | const u32 *tmp; | ||
133 | int nid; | ||
134 | |||
135 | /* Get the interrupt source unit from the device-tree */ | ||
136 | tmp = get_property(np, "isrc", NULL); | ||
137 | if (!tmp) | ||
138 | return -ENODEV; | ||
139 | isrc = tmp[0]; | ||
140 | |||
141 | tmp = get_property(np->parent->parent, "node-id", NULL); | ||
142 | if (!tmp) { | ||
143 | printk(KERN_WARNING "%s: can't find node-id\n", __FUNCTION__); | ||
144 | nid = spu->node; | ||
145 | } else | ||
146 | nid = tmp[0]; | ||
147 | |||
148 | /* Add the node number */ | ||
149 | isrc |= nid << IIC_IRQ_NODE_SHIFT; | ||
150 | |||
151 | /* Now map interrupts of all 3 classes */ | ||
152 | spu->irqs[0] = irq_create_mapping(NULL, IIC_IRQ_CLASS_0 | isrc); | ||
153 | spu->irqs[1] = irq_create_mapping(NULL, IIC_IRQ_CLASS_1 | isrc); | ||
154 | spu->irqs[2] = irq_create_mapping(NULL, IIC_IRQ_CLASS_2 | isrc); | ||
155 | |||
156 | /* Right now, we only fail if class 2 failed */ | ||
157 | return spu->irqs[2] == NO_IRQ ? -EINVAL : 0; | ||
158 | } | ||
159 | |||
160 | static int __init spu_map_device_old(struct spu *spu, struct device_node *node) | ||
161 | { | ||
162 | const char *prop; | ||
163 | int ret; | ||
164 | |||
165 | ret = -ENODEV; | ||
166 | spu->name = get_property(node, "name", NULL); | ||
167 | if (!spu->name) | ||
168 | goto out; | ||
169 | |||
170 | prop = get_property(node, "local-store", NULL); | ||
171 | if (!prop) | ||
172 | goto out; | ||
173 | spu->local_store_phys = *(unsigned long *)prop; | ||
174 | |||
175 | /* we use local store as ram, not io memory */ | ||
176 | spu->local_store = (void __force *) | ||
177 | map_spe_prop(spu, node, "local-store"); | ||
178 | if (!spu->local_store) | ||
179 | goto out; | ||
180 | |||
181 | prop = get_property(node, "problem", NULL); | ||
182 | if (!prop) | ||
183 | goto out_unmap; | ||
184 | spu->problem_phys = *(unsigned long *)prop; | ||
185 | |||
186 | spu->problem= map_spe_prop(spu, node, "problem"); | ||
187 | if (!spu->problem) | ||
188 | goto out_unmap; | ||
189 | |||
190 | spu_get_pdata(spu)->priv1= map_spe_prop(spu, node, "priv1"); | ||
191 | |||
192 | spu->priv2= map_spe_prop(spu, node, "priv2"); | ||
193 | if (!spu->priv2) | ||
194 | goto out_unmap; | ||
195 | ret = 0; | ||
196 | goto out; | ||
197 | |||
198 | out_unmap: | ||
199 | spu_unmap(spu); | ||
200 | out: | ||
201 | return ret; | ||
202 | } | ||
203 | |||
204 | static int __init spu_map_interrupts(struct spu *spu, struct device_node *np) | ||
205 | { | ||
206 | struct of_irq oirq; | ||
207 | int ret; | ||
208 | int i; | ||
209 | |||
210 | for (i=0; i < 3; i++) { | ||
211 | ret = of_irq_map_one(np, i, &oirq); | ||
212 | if (ret) { | ||
213 | pr_debug("spu_new: failed to get irq %d\n", i); | ||
214 | goto err; | ||
215 | } | ||
216 | ret = -EINVAL; | ||
217 | pr_debug(" irq %d no 0x%x on %s\n", i, oirq.specifier[0], | ||
218 | oirq.controller->full_name); | ||
219 | spu->irqs[i] = irq_create_of_mapping(oirq.controller, | ||
220 | oirq.specifier, oirq.size); | ||
221 | if (spu->irqs[i] == NO_IRQ) { | ||
222 | pr_debug("spu_new: failed to map it !\n"); | ||
223 | goto err; | ||
224 | } | ||
225 | } | ||
226 | return 0; | ||
227 | |||
228 | err: | ||
229 | pr_debug("failed to map irq %x for spu %s\n", *oirq.specifier, | ||
230 | spu->name); | ||
231 | for (; i >= 0; i--) { | ||
232 | if (spu->irqs[i] != NO_IRQ) | ||
233 | irq_dispose_mapping(spu->irqs[i]); | ||
234 | } | ||
235 | return ret; | ||
236 | } | ||
237 | |||
238 | static int spu_map_resource(struct spu *spu, int nr, | ||
239 | void __iomem** virt, unsigned long *phys) | ||
240 | { | ||
241 | struct device_node *np = spu_get_pdata(spu)->devnode; | ||
242 | unsigned long start_pfn, nr_pages; | ||
243 | struct pglist_data *pgdata; | ||
244 | struct zone *zone; | ||
245 | struct resource resource = { }; | ||
246 | unsigned long len; | ||
247 | int ret; | ||
248 | |||
249 | ret = of_address_to_resource(np, nr, &resource); | ||
250 | if (ret) | ||
251 | goto out; | ||
252 | |||
253 | if (phys) | ||
254 | *phys = resource.start; | ||
255 | len = resource.end - resource.start + 1; | ||
256 | *virt = ioremap(resource.start, len); | ||
257 | if (!*virt) | ||
258 | ret = -EINVAL; | ||
259 | |||
260 | start_pfn = resource.start >> PAGE_SHIFT; | ||
261 | nr_pages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; | ||
262 | |||
263 | pgdata = NODE_DATA(spu->node); | ||
264 | zone = pgdata->node_zones; | ||
265 | |||
266 | /* XXX rethink locking here */ | ||
267 | mutex_lock(&add_spumem_mutex); | ||
268 | ret = __add_pages(zone, start_pfn, nr_pages); | ||
269 | mutex_unlock(&add_spumem_mutex); | ||
270 | |||
271 | out: | ||
272 | return ret; | ||
273 | } | ||
274 | |||
275 | static int __init spu_map_device(struct spu *spu) | ||
276 | { | ||
277 | struct device_node *np = spu_get_pdata(spu)->devnode; | ||
278 | int ret = -ENODEV; | ||
279 | |||
280 | spu->name = get_property(np, "name", NULL); | ||
281 | if (!spu->name) | ||
282 | goto out; | ||
283 | |||
284 | ret = spu_map_resource(spu, 0, (void __iomem**)&spu->local_store, | ||
285 | &spu->local_store_phys); | ||
286 | if (ret) { | ||
287 | pr_debug("spu_new: failed to map %s resource 0\n", | ||
288 | np->full_name); | ||
289 | goto out; | ||
290 | } | ||
291 | ret = spu_map_resource(spu, 1, (void __iomem**)&spu->problem, | ||
292 | &spu->problem_phys); | ||
293 | if (ret) { | ||
294 | pr_debug("spu_new: failed to map %s resource 1\n", | ||
295 | np->full_name); | ||
296 | goto out_unmap; | ||
297 | } | ||
298 | ret = spu_map_resource(spu, 2, (void __iomem**)&spu->priv2, NULL); | ||
299 | if (ret) { | ||
300 | pr_debug("spu_new: failed to map %s resource 2\n", | ||
301 | np->full_name); | ||
302 | goto out_unmap; | ||
303 | } | ||
304 | if (!firmware_has_feature(FW_FEATURE_LPAR)) | ||
305 | ret = spu_map_resource(spu, 3, | ||
306 | (void __iomem**)&spu_get_pdata(spu)->priv1, NULL); | ||
307 | if (ret) { | ||
308 | pr_debug("spu_new: failed to map %s resource 3\n", | ||
309 | np->full_name); | ||
310 | goto out_unmap; | ||
311 | } | ||
312 | pr_debug("spu_new: %s maps:\n", np->full_name); | ||
313 | pr_debug(" local store : 0x%016lx -> 0x%p\n", | ||
314 | spu->local_store_phys, spu->local_store); | ||
315 | pr_debug(" problem state : 0x%016lx -> 0x%p\n", | ||
316 | spu->problem_phys, spu->problem); | ||
317 | pr_debug(" priv2 : 0x%p\n", spu->priv2); | ||
318 | pr_debug(" priv1 : 0x%p\n", | ||
319 | spu_get_pdata(spu)->priv1); | ||
320 | |||
321 | return 0; | ||
322 | |||
323 | out_unmap: | ||
324 | spu_unmap(spu); | ||
325 | out: | ||
326 | pr_debug("failed to map spe %s: %d\n", spu->name, ret); | ||
327 | return ret; | ||
328 | } | ||
329 | |||
330 | static int __init of_enumerate_spus(int (*fn)(void *data)) | ||
331 | { | ||
332 | int ret; | ||
333 | struct device_node *node; | ||
334 | |||
335 | ret = -ENODEV; | ||
336 | for (node = of_find_node_by_type(NULL, "spe"); | ||
337 | node; node = of_find_node_by_type(node, "spe")) { | ||
338 | ret = fn(node); | ||
339 | if (ret) { | ||
340 | printk(KERN_WARNING "%s: Error initializing %s\n", | ||
341 | __FUNCTION__, node->name); | ||
342 | break; | ||
343 | } | ||
344 | } | ||
345 | return ret; | ||
346 | } | ||
347 | |||
348 | static int __init of_create_spu(struct spu *spu, void *data) | ||
349 | { | ||
350 | int ret; | ||
351 | struct device_node *spe = (struct device_node *)data; | ||
352 | |||
353 | spu->pdata = kzalloc(sizeof(struct spu_pdata), | ||
354 | GFP_KERNEL); | ||
355 | if (!spu->pdata) { | ||
356 | ret = -ENOMEM; | ||
357 | goto out; | ||
358 | } | ||
359 | spu_get_pdata(spu)->devnode = of_node_get(spe); | ||
360 | |||
361 | spu->node = of_node_to_nid(spe); | ||
362 | if (spu->node >= MAX_NUMNODES) { | ||
363 | printk(KERN_WARNING "SPE %s on node %d ignored," | ||
364 | " node number too big\n", spe->full_name, spu->node); | ||
365 | printk(KERN_WARNING "Check if CONFIG_NUMA is enabled.\n"); | ||
366 | ret = -ENODEV; | ||
367 | goto out_free; | ||
368 | } | ||
369 | |||
370 | ret = spu_map_device(spu); | ||
371 | /* try old method */ | ||
372 | if (ret) | ||
373 | ret = spu_map_device_old(spu, spe); | ||
374 | if (ret) | ||
375 | goto out_free; | ||
376 | |||
377 | ret = spu_map_interrupts(spu, spe); | ||
378 | if (ret) | ||
379 | ret = spu_map_interrupts_old(spu, spe); | ||
380 | if (ret) | ||
381 | goto out_unmap; | ||
382 | |||
383 | pr_debug(KERN_DEBUG "Using SPE %s %p %p %p %p %d\n", spu->name, | ||
384 | spu->local_store, spu->problem, spu_get_pdata(spu)->priv1, | ||
385 | spu->priv2, spu->number); | ||
386 | goto out; | ||
387 | |||
388 | out_unmap: | ||
389 | spu_unmap(spu); | ||
390 | out_free: | ||
391 | kfree(spu->pdata); | ||
392 | spu->pdata = NULL; | ||
393 | out: | ||
394 | return ret; | ||
395 | } | ||
396 | |||
397 | static int of_destroy_spu(struct spu *spu) | ||
398 | { | ||
399 | spu_unmap(spu); | ||
400 | of_node_put(spu_get_pdata(spu)->devnode); | ||
401 | kfree(spu->pdata); | ||
402 | spu->pdata = NULL; | ||
403 | return 0; | ||
404 | } | ||
405 | |||
406 | const struct spu_management_ops spu_management_of_ops = { | ||
407 | .enumerate_spus = of_enumerate_spus, | ||
408 | .create_spu = of_create_spu, | ||
409 | .destroy_spu = of_destroy_spu, | ||
410 | }; | ||
411 | |||
412 | static void int_mask_and(struct spu *spu, int class, u64 mask) | 40 | static void int_mask_and(struct spu *spu, int class, u64 mask) |
413 | { | 41 | { |
414 | u64 old_mask; | 42 | u64 old_mask; |
415 | 43 | ||
416 | old_mask = in_be64(&spu_get_pdata(spu)->priv1->int_mask_RW[class]); | 44 | old_mask = in_be64(&spu->priv1->int_mask_RW[class]); |
417 | out_be64(&spu_get_pdata(spu)->priv1->int_mask_RW[class], | 45 | out_be64(&spu->priv1->int_mask_RW[class], old_mask & mask); |
418 | old_mask & mask); | ||
419 | } | 46 | } |
420 | 47 | ||
421 | static void int_mask_or(struct spu *spu, int class, u64 mask) | 48 | static void int_mask_or(struct spu *spu, int class, u64 mask) |
422 | { | 49 | { |
423 | u64 old_mask; | 50 | u64 old_mask; |
424 | 51 | ||
425 | old_mask = in_be64(&spu_get_pdata(spu)->priv1->int_mask_RW[class]); | 52 | old_mask = in_be64(&spu->priv1->int_mask_RW[class]); |
426 | out_be64(&spu_get_pdata(spu)->priv1->int_mask_RW[class], | 53 | out_be64(&spu->priv1->int_mask_RW[class], old_mask | mask); |
427 | old_mask | mask); | ||
428 | } | 54 | } |
429 | 55 | ||
430 | static void int_mask_set(struct spu *spu, int class, u64 mask) | 56 | static void int_mask_set(struct spu *spu, int class, u64 mask) |
431 | { | 57 | { |
432 | out_be64(&spu_get_pdata(spu)->priv1->int_mask_RW[class], mask); | 58 | out_be64(&spu->priv1->int_mask_RW[class], mask); |
433 | } | 59 | } |
434 | 60 | ||
435 | static u64 int_mask_get(struct spu *spu, int class) | 61 | static u64 int_mask_get(struct spu *spu, int class) |
436 | { | 62 | { |
437 | return in_be64(&spu_get_pdata(spu)->priv1->int_mask_RW[class]); | 63 | return in_be64(&spu->priv1->int_mask_RW[class]); |
438 | } | 64 | } |
439 | 65 | ||
440 | static void int_stat_clear(struct spu *spu, int class, u64 stat) | 66 | static void int_stat_clear(struct spu *spu, int class, u64 stat) |
441 | { | 67 | { |
442 | out_be64(&spu_get_pdata(spu)->priv1->int_stat_RW[class], stat); | 68 | out_be64(&spu->priv1->int_stat_RW[class], stat); |
443 | } | 69 | } |
444 | 70 | ||
445 | static u64 int_stat_get(struct spu *spu, int class) | 71 | static u64 int_stat_get(struct spu *spu, int class) |
446 | { | 72 | { |
447 | return in_be64(&spu_get_pdata(spu)->priv1->int_stat_RW[class]); | 73 | return in_be64(&spu->priv1->int_stat_RW[class]); |
448 | } | 74 | } |
449 | 75 | ||
450 | static void cpu_affinity_set(struct spu *spu, int cpu) | 76 | static void cpu_affinity_set(struct spu *spu, int cpu) |
451 | { | 77 | { |
452 | u64 target = iic_get_target_id(cpu); | 78 | u64 target = iic_get_target_id(cpu); |
453 | u64 route = target << 48 | target << 32 | target << 16; | 79 | u64 route = target << 48 | target << 32 | target << 16; |
454 | out_be64(&spu_get_pdata(spu)->priv1->int_route_RW, route); | 80 | out_be64(&spu->priv1->int_route_RW, route); |
455 | } | 81 | } |
456 | 82 | ||
457 | static u64 mfc_dar_get(struct spu *spu) | 83 | static u64 mfc_dar_get(struct spu *spu) |
458 | { | 84 | { |
459 | return in_be64(&spu_get_pdata(spu)->priv1->mfc_dar_RW); | 85 | return in_be64(&spu->priv1->mfc_dar_RW); |
460 | } | 86 | } |
461 | 87 | ||
462 | static u64 mfc_dsisr_get(struct spu *spu) | 88 | static u64 mfc_dsisr_get(struct spu *spu) |
463 | { | 89 | { |
464 | return in_be64(&spu_get_pdata(spu)->priv1->mfc_dsisr_RW); | 90 | return in_be64(&spu->priv1->mfc_dsisr_RW); |
465 | } | 91 | } |
466 | 92 | ||
467 | static void mfc_dsisr_set(struct spu *spu, u64 dsisr) | 93 | static void mfc_dsisr_set(struct spu *spu, u64 dsisr) |
468 | { | 94 | { |
469 | out_be64(&spu_get_pdata(spu)->priv1->mfc_dsisr_RW, dsisr); | 95 | out_be64(&spu->priv1->mfc_dsisr_RW, dsisr); |
470 | } | 96 | } |
471 | 97 | ||
472 | static void mfc_sdr_setup(struct spu *spu) | 98 | static void mfc_sdr_setup(struct spu *spu) |
473 | { | 99 | { |
474 | out_be64(&spu_get_pdata(spu)->priv1->mfc_sdr_RW, mfspr(SPRN_SDR1)); | 100 | out_be64(&spu->priv1->mfc_sdr_RW, mfspr(SPRN_SDR1)); |
475 | } | 101 | } |
476 | 102 | ||
477 | static void mfc_sr1_set(struct spu *spu, u64 sr1) | 103 | static void mfc_sr1_set(struct spu *spu, u64 sr1) |
478 | { | 104 | { |
479 | out_be64(&spu_get_pdata(spu)->priv1->mfc_sr1_RW, sr1); | 105 | out_be64(&spu->priv1->mfc_sr1_RW, sr1); |
480 | } | 106 | } |
481 | 107 | ||
482 | static u64 mfc_sr1_get(struct spu *spu) | 108 | static u64 mfc_sr1_get(struct spu *spu) |
483 | { | 109 | { |
484 | return in_be64(&spu_get_pdata(spu)->priv1->mfc_sr1_RW); | 110 | return in_be64(&spu->priv1->mfc_sr1_RW); |
485 | } | 111 | } |
486 | 112 | ||
487 | static void mfc_tclass_id_set(struct spu *spu, u64 tclass_id) | 113 | static void mfc_tclass_id_set(struct spu *spu, u64 tclass_id) |
488 | { | 114 | { |
489 | out_be64(&spu_get_pdata(spu)->priv1->mfc_tclass_id_RW, tclass_id); | 115 | out_be64(&spu->priv1->mfc_tclass_id_RW, tclass_id); |
490 | } | 116 | } |
491 | 117 | ||
492 | static u64 mfc_tclass_id_get(struct spu *spu) | 118 | static u64 mfc_tclass_id_get(struct spu *spu) |
493 | { | 119 | { |
494 | return in_be64(&spu_get_pdata(spu)->priv1->mfc_tclass_id_RW); | 120 | return in_be64(&spu->priv1->mfc_tclass_id_RW); |
495 | } | 121 | } |
496 | 122 | ||
497 | static void tlb_invalidate(struct spu *spu) | 123 | static void tlb_invalidate(struct spu *spu) |
498 | { | 124 | { |
499 | out_be64(&spu_get_pdata(spu)->priv1->tlb_invalidate_entry_W, 0ul); | 125 | out_be64(&spu->priv1->tlb_invalidate_entry_W, 0ul); |
500 | } | 126 | } |
501 | 127 | ||
502 | static void resource_allocation_groupID_set(struct spu *spu, u64 id) | 128 | static void resource_allocation_groupID_set(struct spu *spu, u64 id) |
503 | { | 129 | { |
504 | out_be64(&spu_get_pdata(spu)->priv1->resource_allocation_groupID_RW, | 130 | out_be64(&spu->priv1->resource_allocation_groupID_RW, id); |
505 | id); | ||
506 | } | 131 | } |
507 | 132 | ||
508 | static u64 resource_allocation_groupID_get(struct spu *spu) | 133 | static u64 resource_allocation_groupID_get(struct spu *spu) |
509 | { | 134 | { |
510 | return in_be64( | 135 | return in_be64(&spu->priv1->resource_allocation_groupID_RW); |
511 | &spu_get_pdata(spu)->priv1->resource_allocation_groupID_RW); | ||
512 | } | 136 | } |
513 | 137 | ||
514 | static void resource_allocation_enable_set(struct spu *spu, u64 enable) | 138 | static void resource_allocation_enable_set(struct spu *spu, u64 enable) |
515 | { | 139 | { |
516 | out_be64(&spu_get_pdata(spu)->priv1->resource_allocation_enable_RW, | 140 | out_be64(&spu->priv1->resource_allocation_enable_RW, enable); |
517 | enable); | ||
518 | } | 141 | } |
519 | 142 | ||
520 | static u64 resource_allocation_enable_get(struct spu *spu) | 143 | static u64 resource_allocation_enable_get(struct spu *spu) |
521 | { | 144 | { |
522 | return in_be64( | 145 | return in_be64(&spu->priv1->resource_allocation_enable_RW); |
523 | &spu_get_pdata(spu)->priv1->resource_allocation_enable_RW); | ||
524 | } | 146 | } |
525 | 147 | ||
526 | const struct spu_priv1_ops spu_priv1_mmio_ops = | 148 | const struct spu_priv1_ops spu_priv1_mmio_ops = |
diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c index 0870009f56db..04ad2e364e97 100644 --- a/arch/powerpc/platforms/cell/spufs/context.c +++ b/arch/powerpc/platforms/cell/spufs/context.c | |||
@@ -42,7 +42,7 @@ struct spu_context *alloc_spu_context(struct spu_gang *gang) | |||
42 | } | 42 | } |
43 | spin_lock_init(&ctx->mmio_lock); | 43 | spin_lock_init(&ctx->mmio_lock); |
44 | kref_init(&ctx->kref); | 44 | kref_init(&ctx->kref); |
45 | init_rwsem(&ctx->state_sema); | 45 | mutex_init(&ctx->state_mutex); |
46 | init_MUTEX(&ctx->run_sema); | 46 | init_MUTEX(&ctx->run_sema); |
47 | init_waitqueue_head(&ctx->ibox_wq); | 47 | init_waitqueue_head(&ctx->ibox_wq); |
48 | init_waitqueue_head(&ctx->wbox_wq); | 48 | init_waitqueue_head(&ctx->wbox_wq); |
@@ -53,6 +53,10 @@ struct spu_context *alloc_spu_context(struct spu_gang *gang) | |||
53 | ctx->owner = get_task_mm(current); | 53 | ctx->owner = get_task_mm(current); |
54 | if (gang) | 54 | if (gang) |
55 | spu_gang_add_ctx(gang, ctx); | 55 | spu_gang_add_ctx(gang, ctx); |
56 | ctx->rt_priority = current->rt_priority; | ||
57 | ctx->policy = current->policy; | ||
58 | ctx->prio = current->prio; | ||
59 | INIT_DELAYED_WORK(&ctx->sched_work, spu_sched_tick); | ||
56 | goto out; | 60 | goto out; |
57 | out_free: | 61 | out_free: |
58 | kfree(ctx); | 62 | kfree(ctx); |
@@ -65,9 +69,9 @@ void destroy_spu_context(struct kref *kref) | |||
65 | { | 69 | { |
66 | struct spu_context *ctx; | 70 | struct spu_context *ctx; |
67 | ctx = container_of(kref, struct spu_context, kref); | 71 | ctx = container_of(kref, struct spu_context, kref); |
68 | down_write(&ctx->state_sema); | 72 | mutex_lock(&ctx->state_mutex); |
69 | spu_deactivate(ctx); | 73 | spu_deactivate(ctx); |
70 | up_write(&ctx->state_sema); | 74 | mutex_unlock(&ctx->state_mutex); |
71 | spu_fini_csa(&ctx->csa); | 75 | spu_fini_csa(&ctx->csa); |
72 | if (ctx->gang) | 76 | if (ctx->gang) |
73 | spu_gang_remove_ctx(ctx->gang, ctx); | 77 | spu_gang_remove_ctx(ctx->gang, ctx); |
@@ -96,107 +100,102 @@ void spu_forget(struct spu_context *ctx) | |||
96 | spu_release(ctx); | 100 | spu_release(ctx); |
97 | } | 101 | } |
98 | 102 | ||
99 | void spu_acquire(struct spu_context *ctx) | ||
100 | { | ||
101 | down_read(&ctx->state_sema); | ||
102 | } | ||
103 | |||
104 | void spu_release(struct spu_context *ctx) | ||
105 | { | ||
106 | up_read(&ctx->state_sema); | ||
107 | } | ||
108 | |||
109 | void spu_unmap_mappings(struct spu_context *ctx) | 103 | void spu_unmap_mappings(struct spu_context *ctx) |
110 | { | 104 | { |
111 | if (ctx->local_store) | 105 | if (ctx->local_store) |
112 | unmap_mapping_range(ctx->local_store, 0, LS_SIZE, 1); | 106 | unmap_mapping_range(ctx->local_store, 0, LS_SIZE, 1); |
113 | if (ctx->mfc) | 107 | if (ctx->mfc) |
114 | unmap_mapping_range(ctx->mfc, 0, 0x4000, 1); | 108 | unmap_mapping_range(ctx->mfc, 0, 0x1000, 1); |
115 | if (ctx->cntl) | 109 | if (ctx->cntl) |
116 | unmap_mapping_range(ctx->cntl, 0, 0x4000, 1); | 110 | unmap_mapping_range(ctx->cntl, 0, 0x1000, 1); |
117 | if (ctx->signal1) | 111 | if (ctx->signal1) |
118 | unmap_mapping_range(ctx->signal1, 0, 0x4000, 1); | 112 | unmap_mapping_range(ctx->signal1, 0, PAGE_SIZE, 1); |
119 | if (ctx->signal2) | 113 | if (ctx->signal2) |
120 | unmap_mapping_range(ctx->signal2, 0, 0x4000, 1); | 114 | unmap_mapping_range(ctx->signal2, 0, PAGE_SIZE, 1); |
115 | if (ctx->mss) | ||
116 | unmap_mapping_range(ctx->mss, 0, 0x1000, 1); | ||
117 | if (ctx->psmap) | ||
118 | unmap_mapping_range(ctx->psmap, 0, 0x20000, 1); | ||
121 | } | 119 | } |
122 | 120 | ||
121 | /** | ||
122 | * spu_acquire_exclusive - lock spu contex and protect against userspace access | ||
123 | * @ctx: spu contex to lock | ||
124 | * | ||
125 | * Note: | ||
126 | * Returns 0 and with the context locked on success | ||
127 | * Returns negative error and with the context _unlocked_ on failure. | ||
128 | */ | ||
123 | int spu_acquire_exclusive(struct spu_context *ctx) | 129 | int spu_acquire_exclusive(struct spu_context *ctx) |
124 | { | 130 | { |
125 | int ret = 0; | 131 | int ret = -EINVAL; |
126 | 132 | ||
127 | down_write(&ctx->state_sema); | 133 | spu_acquire(ctx); |
128 | /* ctx is about to be freed, can't acquire any more */ | 134 | /* |
129 | if (!ctx->owner) { | 135 | * Context is about to be freed, so we can't acquire it anymore. |
130 | ret = -EINVAL; | 136 | */ |
131 | goto out; | 137 | if (!ctx->owner) |
132 | } | 138 | goto out_unlock; |
133 | 139 | ||
134 | if (ctx->state == SPU_STATE_SAVED) { | 140 | if (ctx->state == SPU_STATE_SAVED) { |
135 | ret = spu_activate(ctx, 0); | 141 | ret = spu_activate(ctx, 0); |
136 | if (ret) | 142 | if (ret) |
137 | goto out; | 143 | goto out_unlock; |
138 | ctx->state = SPU_STATE_RUNNABLE; | ||
139 | } else { | 144 | } else { |
140 | /* We need to exclude userspace access to the context. */ | 145 | /* |
146 | * We need to exclude userspace access to the context. | ||
147 | * | ||
148 | * To protect against memory access we invalidate all ptes | ||
149 | * and make sure the pagefault handlers block on the mutex. | ||
150 | */ | ||
141 | spu_unmap_mappings(ctx); | 151 | spu_unmap_mappings(ctx); |
142 | } | 152 | } |
143 | 153 | ||
144 | out: | 154 | return 0; |
145 | if (ret) | 155 | |
146 | up_write(&ctx->state_sema); | 156 | out_unlock: |
157 | spu_release(ctx); | ||
147 | return ret; | 158 | return ret; |
148 | } | 159 | } |
149 | 160 | ||
150 | int spu_acquire_runnable(struct spu_context *ctx) | 161 | /** |
162 | * spu_acquire_runnable - lock spu contex and make sure it is in runnable state | ||
163 | * @ctx: spu contex to lock | ||
164 | * | ||
165 | * Note: | ||
166 | * Returns 0 and with the context locked on success | ||
167 | * Returns negative error and with the context _unlocked_ on failure. | ||
168 | */ | ||
169 | int spu_acquire_runnable(struct spu_context *ctx, unsigned long flags) | ||
151 | { | 170 | { |
152 | int ret = 0; | 171 | int ret = -EINVAL; |
153 | |||
154 | down_read(&ctx->state_sema); | ||
155 | if (ctx->state == SPU_STATE_RUNNABLE) { | ||
156 | ctx->spu->prio = current->prio; | ||
157 | return 0; | ||
158 | } | ||
159 | up_read(&ctx->state_sema); | ||
160 | |||
161 | down_write(&ctx->state_sema); | ||
162 | /* ctx is about to be freed, can't acquire any more */ | ||
163 | if (!ctx->owner) { | ||
164 | ret = -EINVAL; | ||
165 | goto out; | ||
166 | } | ||
167 | 172 | ||
173 | spu_acquire(ctx); | ||
168 | if (ctx->state == SPU_STATE_SAVED) { | 174 | if (ctx->state == SPU_STATE_SAVED) { |
169 | ret = spu_activate(ctx, 0); | 175 | /* |
176 | * Context is about to be freed, so we can't acquire it anymore. | ||
177 | */ | ||
178 | if (!ctx->owner) | ||
179 | goto out_unlock; | ||
180 | ret = spu_activate(ctx, flags); | ||
170 | if (ret) | 181 | if (ret) |
171 | goto out; | 182 | goto out_unlock; |
172 | ctx->state = SPU_STATE_RUNNABLE; | ||
173 | } | 183 | } |
174 | 184 | ||
175 | downgrade_write(&ctx->state_sema); | 185 | return 0; |
176 | /* On success, we return holding the lock */ | ||
177 | |||
178 | return ret; | ||
179 | out: | ||
180 | /* Release here, to simplify calling code. */ | ||
181 | up_write(&ctx->state_sema); | ||
182 | 186 | ||
187 | out_unlock: | ||
188 | spu_release(ctx); | ||
183 | return ret; | 189 | return ret; |
184 | } | 190 | } |
185 | 191 | ||
192 | /** | ||
193 | * spu_acquire_saved - lock spu contex and make sure it is in saved state | ||
194 | * @ctx: spu contex to lock | ||
195 | */ | ||
186 | void spu_acquire_saved(struct spu_context *ctx) | 196 | void spu_acquire_saved(struct spu_context *ctx) |
187 | { | 197 | { |
188 | down_read(&ctx->state_sema); | 198 | spu_acquire(ctx); |
189 | 199 | if (ctx->state != SPU_STATE_SAVED) | |
190 | if (ctx->state == SPU_STATE_SAVED) | ||
191 | return; | ||
192 | |||
193 | up_read(&ctx->state_sema); | ||
194 | down_write(&ctx->state_sema); | ||
195 | |||
196 | if (ctx->state == SPU_STATE_RUNNABLE) { | ||
197 | spu_deactivate(ctx); | 200 | spu_deactivate(ctx); |
198 | ctx->state = SPU_STATE_SAVED; | ||
199 | } | ||
200 | |||
201 | downgrade_write(&ctx->state_sema); | ||
202 | } | 201 | } |
diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index 347eff56fcbd..b00653d69c01 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c | |||
@@ -45,8 +45,8 @@ spufs_mem_open(struct inode *inode, struct file *file) | |||
45 | struct spufs_inode_info *i = SPUFS_I(inode); | 45 | struct spufs_inode_info *i = SPUFS_I(inode); |
46 | struct spu_context *ctx = i->i_ctx; | 46 | struct spu_context *ctx = i->i_ctx; |
47 | file->private_data = ctx; | 47 | file->private_data = ctx; |
48 | file->f_mapping = inode->i_mapping; | ||
49 | ctx->local_store = inode->i_mapping; | 48 | ctx->local_store = inode->i_mapping; |
49 | smp_wmb(); | ||
50 | return 0; | 50 | return 0; |
51 | } | 51 | } |
52 | 52 | ||
@@ -95,39 +95,38 @@ spufs_mem_write(struct file *file, const char __user *buffer, | |||
95 | return ret; | 95 | return ret; |
96 | } | 96 | } |
97 | 97 | ||
98 | static struct page * | 98 | static unsigned long spufs_mem_mmap_nopfn(struct vm_area_struct *vma, |
99 | spufs_mem_mmap_nopage(struct vm_area_struct *vma, | 99 | unsigned long address) |
100 | unsigned long address, int *type) | ||
101 | { | 100 | { |
102 | struct page *page = NOPAGE_SIGBUS; | ||
103 | |||
104 | struct spu_context *ctx = vma->vm_file->private_data; | 101 | struct spu_context *ctx = vma->vm_file->private_data; |
105 | unsigned long offset = address - vma->vm_start; | 102 | unsigned long pfn, offset = address - vma->vm_start; |
103 | |||
106 | offset += vma->vm_pgoff << PAGE_SHIFT; | 104 | offset += vma->vm_pgoff << PAGE_SHIFT; |
107 | 105 | ||
106 | if (offset >= LS_SIZE) | ||
107 | return NOPFN_SIGBUS; | ||
108 | |||
108 | spu_acquire(ctx); | 109 | spu_acquire(ctx); |
109 | 110 | ||
110 | if (ctx->state == SPU_STATE_SAVED) { | 111 | if (ctx->state == SPU_STATE_SAVED) { |
111 | vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) | 112 | vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) |
112 | & ~_PAGE_NO_CACHE); | 113 | & ~_PAGE_NO_CACHE); |
113 | page = vmalloc_to_page(ctx->csa.lscsa->ls + offset); | 114 | pfn = vmalloc_to_pfn(ctx->csa.lscsa->ls + offset); |
114 | } else { | 115 | } else { |
115 | vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) | 116 | vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) |
116 | | _PAGE_NO_CACHE); | 117 | | _PAGE_NO_CACHE); |
117 | page = pfn_to_page((ctx->spu->local_store_phys + offset) | 118 | pfn = (ctx->spu->local_store_phys + offset) >> PAGE_SHIFT; |
118 | >> PAGE_SHIFT); | ||
119 | } | 119 | } |
120 | spu_release(ctx); | 120 | vm_insert_pfn(vma, address, pfn); |
121 | 121 | ||
122 | if (type) | 122 | spu_release(ctx); |
123 | *type = VM_FAULT_MINOR; | ||
124 | 123 | ||
125 | page_cache_get(page); | 124 | return NOPFN_REFAULT; |
126 | return page; | ||
127 | } | 125 | } |
128 | 126 | ||
127 | |||
129 | static struct vm_operations_struct spufs_mem_mmap_vmops = { | 128 | static struct vm_operations_struct spufs_mem_mmap_vmops = { |
130 | .nopage = spufs_mem_mmap_nopage, | 129 | .nopfn = spufs_mem_mmap_nopfn, |
131 | }; | 130 | }; |
132 | 131 | ||
133 | static int | 132 | static int |
@@ -136,7 +135,7 @@ spufs_mem_mmap(struct file *file, struct vm_area_struct *vma) | |||
136 | if (!(vma->vm_flags & VM_SHARED)) | 135 | if (!(vma->vm_flags & VM_SHARED)) |
137 | return -EINVAL; | 136 | return -EINVAL; |
138 | 137 | ||
139 | vma->vm_flags |= VM_IO; | 138 | vma->vm_flags |= VM_IO | VM_PFNMAP; |
140 | vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) | 139 | vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) |
141 | | _PAGE_NO_CACHE); | 140 | | _PAGE_NO_CACHE); |
142 | 141 | ||
@@ -144,7 +143,7 @@ spufs_mem_mmap(struct file *file, struct vm_area_struct *vma) | |||
144 | return 0; | 143 | return 0; |
145 | } | 144 | } |
146 | 145 | ||
147 | static struct file_operations spufs_mem_fops = { | 146 | static const struct file_operations spufs_mem_fops = { |
148 | .open = spufs_mem_open, | 147 | .open = spufs_mem_open, |
149 | .read = spufs_mem_read, | 148 | .read = spufs_mem_read, |
150 | .write = spufs_mem_write, | 149 | .write = spufs_mem_write, |
@@ -152,49 +151,42 @@ static struct file_operations spufs_mem_fops = { | |||
152 | .mmap = spufs_mem_mmap, | 151 | .mmap = spufs_mem_mmap, |
153 | }; | 152 | }; |
154 | 153 | ||
155 | static struct page *spufs_ps_nopage(struct vm_area_struct *vma, | 154 | static unsigned long spufs_ps_nopfn(struct vm_area_struct *vma, |
156 | unsigned long address, | 155 | unsigned long address, |
157 | int *type, unsigned long ps_offs, | 156 | unsigned long ps_offs, |
158 | unsigned long ps_size) | 157 | unsigned long ps_size) |
159 | { | 158 | { |
160 | struct page *page = NOPAGE_SIGBUS; | ||
161 | int fault_type = VM_FAULT_SIGBUS; | ||
162 | struct spu_context *ctx = vma->vm_file->private_data; | 159 | struct spu_context *ctx = vma->vm_file->private_data; |
163 | unsigned long offset = address - vma->vm_start; | 160 | unsigned long area, offset = address - vma->vm_start; |
164 | unsigned long area; | ||
165 | int ret; | 161 | int ret; |
166 | 162 | ||
167 | offset += vma->vm_pgoff << PAGE_SHIFT; | 163 | offset += vma->vm_pgoff << PAGE_SHIFT; |
168 | if (offset >= ps_size) | 164 | if (offset >= ps_size) |
169 | goto out; | 165 | return NOPFN_SIGBUS; |
170 | 166 | ||
171 | ret = spu_acquire_runnable(ctx); | 167 | /* error here usually means a signal.. we might want to test |
168 | * the error code more precisely though | ||
169 | */ | ||
170 | ret = spu_acquire_runnable(ctx, 0); | ||
172 | if (ret) | 171 | if (ret) |
173 | goto out; | 172 | return NOPFN_REFAULT; |
174 | 173 | ||
175 | area = ctx->spu->problem_phys + ps_offs; | 174 | area = ctx->spu->problem_phys + ps_offs; |
176 | page = pfn_to_page((area + offset) >> PAGE_SHIFT); | 175 | vm_insert_pfn(vma, address, (area + offset) >> PAGE_SHIFT); |
177 | fault_type = VM_FAULT_MINOR; | ||
178 | page_cache_get(page); | ||
179 | |||
180 | spu_release(ctx); | 176 | spu_release(ctx); |
181 | 177 | ||
182 | out: | 178 | return NOPFN_REFAULT; |
183 | if (type) | ||
184 | *type = fault_type; | ||
185 | |||
186 | return page; | ||
187 | } | 179 | } |
188 | 180 | ||
189 | #if SPUFS_MMAP_4K | 181 | #if SPUFS_MMAP_4K |
190 | static struct page *spufs_cntl_mmap_nopage(struct vm_area_struct *vma, | 182 | static unsigned long spufs_cntl_mmap_nopfn(struct vm_area_struct *vma, |
191 | unsigned long address, int *type) | 183 | unsigned long address) |
192 | { | 184 | { |
193 | return spufs_ps_nopage(vma, address, type, 0x4000, 0x1000); | 185 | return spufs_ps_nopfn(vma, address, 0x4000, 0x1000); |
194 | } | 186 | } |
195 | 187 | ||
196 | static struct vm_operations_struct spufs_cntl_mmap_vmops = { | 188 | static struct vm_operations_struct spufs_cntl_mmap_vmops = { |
197 | .nopage = spufs_cntl_mmap_nopage, | 189 | .nopfn = spufs_cntl_mmap_nopfn, |
198 | }; | 190 | }; |
199 | 191 | ||
200 | /* | 192 | /* |
@@ -205,7 +197,7 @@ static int spufs_cntl_mmap(struct file *file, struct vm_area_struct *vma) | |||
205 | if (!(vma->vm_flags & VM_SHARED)) | 197 | if (!(vma->vm_flags & VM_SHARED)) |
206 | return -EINVAL; | 198 | return -EINVAL; |
207 | 199 | ||
208 | vma->vm_flags |= VM_IO; | 200 | vma->vm_flags |= VM_IO | VM_PFNMAP; |
209 | vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) | 201 | vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) |
210 | | _PAGE_NO_CACHE | _PAGE_GUARDED); | 202 | | _PAGE_NO_CACHE | _PAGE_GUARDED); |
211 | 203 | ||
@@ -243,13 +235,13 @@ static int spufs_cntl_open(struct inode *inode, struct file *file) | |||
243 | struct spu_context *ctx = i->i_ctx; | 235 | struct spu_context *ctx = i->i_ctx; |
244 | 236 | ||
245 | file->private_data = ctx; | 237 | file->private_data = ctx; |
246 | file->f_mapping = inode->i_mapping; | ||
247 | ctx->cntl = inode->i_mapping; | 238 | ctx->cntl = inode->i_mapping; |
239 | smp_wmb(); | ||
248 | return simple_attr_open(inode, file, spufs_cntl_get, | 240 | return simple_attr_open(inode, file, spufs_cntl_get, |
249 | spufs_cntl_set, "0x%08lx"); | 241 | spufs_cntl_set, "0x%08lx"); |
250 | } | 242 | } |
251 | 243 | ||
252 | static struct file_operations spufs_cntl_fops = { | 244 | static const struct file_operations spufs_cntl_fops = { |
253 | .open = spufs_cntl_open, | 245 | .open = spufs_cntl_open, |
254 | .release = simple_attr_close, | 246 | .release = simple_attr_close, |
255 | .read = simple_attr_read, | 247 | .read = simple_attr_read, |
@@ -309,7 +301,7 @@ spufs_regs_write(struct file *file, const char __user *buffer, | |||
309 | return ret; | 301 | return ret; |
310 | } | 302 | } |
311 | 303 | ||
312 | static struct file_operations spufs_regs_fops = { | 304 | static const struct file_operations spufs_regs_fops = { |
313 | .open = spufs_regs_open, | 305 | .open = spufs_regs_open, |
314 | .read = spufs_regs_read, | 306 | .read = spufs_regs_read, |
315 | .write = spufs_regs_write, | 307 | .write = spufs_regs_write, |
@@ -360,7 +352,7 @@ spufs_fpcr_write(struct file *file, const char __user * buffer, | |||
360 | return ret; | 352 | return ret; |
361 | } | 353 | } |
362 | 354 | ||
363 | static struct file_operations spufs_fpcr_fops = { | 355 | static const struct file_operations spufs_fpcr_fops = { |
364 | .open = spufs_regs_open, | 356 | .open = spufs_regs_open, |
365 | .read = spufs_fpcr_read, | 357 | .read = spufs_fpcr_read, |
366 | .write = spufs_fpcr_write, | 358 | .write = spufs_fpcr_write, |
@@ -426,7 +418,7 @@ static ssize_t spufs_mbox_read(struct file *file, char __user *buf, | |||
426 | return count; | 418 | return count; |
427 | } | 419 | } |
428 | 420 | ||
429 | static struct file_operations spufs_mbox_fops = { | 421 | static const struct file_operations spufs_mbox_fops = { |
430 | .open = spufs_pipe_open, | 422 | .open = spufs_pipe_open, |
431 | .read = spufs_mbox_read, | 423 | .read = spufs_mbox_read, |
432 | }; | 424 | }; |
@@ -452,7 +444,7 @@ static ssize_t spufs_mbox_stat_read(struct file *file, char __user *buf, | |||
452 | return 4; | 444 | return 4; |
453 | } | 445 | } |
454 | 446 | ||
455 | static struct file_operations spufs_mbox_stat_fops = { | 447 | static const struct file_operations spufs_mbox_stat_fops = { |
456 | .open = spufs_pipe_open, | 448 | .open = spufs_pipe_open, |
457 | .read = spufs_mbox_stat_read, | 449 | .read = spufs_mbox_stat_read, |
458 | }; | 450 | }; |
@@ -559,7 +551,7 @@ static unsigned int spufs_ibox_poll(struct file *file, poll_table *wait) | |||
559 | return mask; | 551 | return mask; |
560 | } | 552 | } |
561 | 553 | ||
562 | static struct file_operations spufs_ibox_fops = { | 554 | static const struct file_operations spufs_ibox_fops = { |
563 | .open = spufs_pipe_open, | 555 | .open = spufs_pipe_open, |
564 | .read = spufs_ibox_read, | 556 | .read = spufs_ibox_read, |
565 | .poll = spufs_ibox_poll, | 557 | .poll = spufs_ibox_poll, |
@@ -585,7 +577,7 @@ static ssize_t spufs_ibox_stat_read(struct file *file, char __user *buf, | |||
585 | return 4; | 577 | return 4; |
586 | } | 578 | } |
587 | 579 | ||
588 | static struct file_operations spufs_ibox_stat_fops = { | 580 | static const struct file_operations spufs_ibox_stat_fops = { |
589 | .open = spufs_pipe_open, | 581 | .open = spufs_pipe_open, |
590 | .read = spufs_ibox_stat_read, | 582 | .read = spufs_ibox_stat_read, |
591 | }; | 583 | }; |
@@ -692,7 +684,7 @@ static unsigned int spufs_wbox_poll(struct file *file, poll_table *wait) | |||
692 | return mask; | 684 | return mask; |
693 | } | 685 | } |
694 | 686 | ||
695 | static struct file_operations spufs_wbox_fops = { | 687 | static const struct file_operations spufs_wbox_fops = { |
696 | .open = spufs_pipe_open, | 688 | .open = spufs_pipe_open, |
697 | .write = spufs_wbox_write, | 689 | .write = spufs_wbox_write, |
698 | .poll = spufs_wbox_poll, | 690 | .poll = spufs_wbox_poll, |
@@ -718,7 +710,7 @@ static ssize_t spufs_wbox_stat_read(struct file *file, char __user *buf, | |||
718 | return 4; | 710 | return 4; |
719 | } | 711 | } |
720 | 712 | ||
721 | static struct file_operations spufs_wbox_stat_fops = { | 713 | static const struct file_operations spufs_wbox_stat_fops = { |
722 | .open = spufs_pipe_open, | 714 | .open = spufs_pipe_open, |
723 | .read = spufs_wbox_stat_read, | 715 | .read = spufs_wbox_stat_read, |
724 | }; | 716 | }; |
@@ -728,8 +720,8 @@ static int spufs_signal1_open(struct inode *inode, struct file *file) | |||
728 | struct spufs_inode_info *i = SPUFS_I(inode); | 720 | struct spufs_inode_info *i = SPUFS_I(inode); |
729 | struct spu_context *ctx = i->i_ctx; | 721 | struct spu_context *ctx = i->i_ctx; |
730 | file->private_data = ctx; | 722 | file->private_data = ctx; |
731 | file->f_mapping = inode->i_mapping; | ||
732 | ctx->signal1 = inode->i_mapping; | 723 | ctx->signal1 = inode->i_mapping; |
724 | smp_wmb(); | ||
733 | return nonseekable_open(inode, file); | 725 | return nonseekable_open(inode, file); |
734 | } | 726 | } |
735 | 727 | ||
@@ -791,23 +783,23 @@ static ssize_t spufs_signal1_write(struct file *file, const char __user *buf, | |||
791 | return 4; | 783 | return 4; |
792 | } | 784 | } |
793 | 785 | ||
794 | static struct page *spufs_signal1_mmap_nopage(struct vm_area_struct *vma, | 786 | static unsigned long spufs_signal1_mmap_nopfn(struct vm_area_struct *vma, |
795 | unsigned long address, int *type) | 787 | unsigned long address) |
796 | { | 788 | { |
797 | #if PAGE_SIZE == 0x1000 | 789 | #if PAGE_SIZE == 0x1000 |
798 | return spufs_ps_nopage(vma, address, type, 0x14000, 0x1000); | 790 | return spufs_ps_nopfn(vma, address, 0x14000, 0x1000); |
799 | #elif PAGE_SIZE == 0x10000 | 791 | #elif PAGE_SIZE == 0x10000 |
800 | /* For 64k pages, both signal1 and signal2 can be used to mmap the whole | 792 | /* For 64k pages, both signal1 and signal2 can be used to mmap the whole |
801 | * signal 1 and 2 area | 793 | * signal 1 and 2 area |
802 | */ | 794 | */ |
803 | return spufs_ps_nopage(vma, address, type, 0x10000, 0x10000); | 795 | return spufs_ps_nopfn(vma, address, 0x10000, 0x10000); |
804 | #else | 796 | #else |
805 | #error unsupported page size | 797 | #error unsupported page size |
806 | #endif | 798 | #endif |
807 | } | 799 | } |
808 | 800 | ||
809 | static struct vm_operations_struct spufs_signal1_mmap_vmops = { | 801 | static struct vm_operations_struct spufs_signal1_mmap_vmops = { |
810 | .nopage = spufs_signal1_mmap_nopage, | 802 | .nopfn = spufs_signal1_mmap_nopfn, |
811 | }; | 803 | }; |
812 | 804 | ||
813 | static int spufs_signal1_mmap(struct file *file, struct vm_area_struct *vma) | 805 | static int spufs_signal1_mmap(struct file *file, struct vm_area_struct *vma) |
@@ -815,7 +807,7 @@ static int spufs_signal1_mmap(struct file *file, struct vm_area_struct *vma) | |||
815 | if (!(vma->vm_flags & VM_SHARED)) | 807 | if (!(vma->vm_flags & VM_SHARED)) |
816 | return -EINVAL; | 808 | return -EINVAL; |
817 | 809 | ||
818 | vma->vm_flags |= VM_IO; | 810 | vma->vm_flags |= VM_IO | VM_PFNMAP; |
819 | vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) | 811 | vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) |
820 | | _PAGE_NO_CACHE | _PAGE_GUARDED); | 812 | | _PAGE_NO_CACHE | _PAGE_GUARDED); |
821 | 813 | ||
@@ -823,7 +815,7 @@ static int spufs_signal1_mmap(struct file *file, struct vm_area_struct *vma) | |||
823 | return 0; | 815 | return 0; |
824 | } | 816 | } |
825 | 817 | ||
826 | static struct file_operations spufs_signal1_fops = { | 818 | static const struct file_operations spufs_signal1_fops = { |
827 | .open = spufs_signal1_open, | 819 | .open = spufs_signal1_open, |
828 | .read = spufs_signal1_read, | 820 | .read = spufs_signal1_read, |
829 | .write = spufs_signal1_write, | 821 | .write = spufs_signal1_write, |
@@ -835,8 +827,8 @@ static int spufs_signal2_open(struct inode *inode, struct file *file) | |||
835 | struct spufs_inode_info *i = SPUFS_I(inode); | 827 | struct spufs_inode_info *i = SPUFS_I(inode); |
836 | struct spu_context *ctx = i->i_ctx; | 828 | struct spu_context *ctx = i->i_ctx; |
837 | file->private_data = ctx; | 829 | file->private_data = ctx; |
838 | file->f_mapping = inode->i_mapping; | ||
839 | ctx->signal2 = inode->i_mapping; | 830 | ctx->signal2 = inode->i_mapping; |
831 | smp_wmb(); | ||
840 | return nonseekable_open(inode, file); | 832 | return nonseekable_open(inode, file); |
841 | } | 833 | } |
842 | 834 | ||
@@ -899,23 +891,23 @@ static ssize_t spufs_signal2_write(struct file *file, const char __user *buf, | |||
899 | } | 891 | } |
900 | 892 | ||
901 | #if SPUFS_MMAP_4K | 893 | #if SPUFS_MMAP_4K |
902 | static struct page *spufs_signal2_mmap_nopage(struct vm_area_struct *vma, | 894 | static unsigned long spufs_signal2_mmap_nopfn(struct vm_area_struct *vma, |
903 | unsigned long address, int *type) | 895 | unsigned long address) |
904 | { | 896 | { |
905 | #if PAGE_SIZE == 0x1000 | 897 | #if PAGE_SIZE == 0x1000 |
906 | return spufs_ps_nopage(vma, address, type, 0x1c000, 0x1000); | 898 | return spufs_ps_nopfn(vma, address, 0x1c000, 0x1000); |
907 | #elif PAGE_SIZE == 0x10000 | 899 | #elif PAGE_SIZE == 0x10000 |
908 | /* For 64k pages, both signal1 and signal2 can be used to mmap the whole | 900 | /* For 64k pages, both signal1 and signal2 can be used to mmap the whole |
909 | * signal 1 and 2 area | 901 | * signal 1 and 2 area |
910 | */ | 902 | */ |
911 | return spufs_ps_nopage(vma, address, type, 0x10000, 0x10000); | 903 | return spufs_ps_nopfn(vma, address, 0x10000, 0x10000); |
912 | #else | 904 | #else |
913 | #error unsupported page size | 905 | #error unsupported page size |
914 | #endif | 906 | #endif |
915 | } | 907 | } |
916 | 908 | ||
917 | static struct vm_operations_struct spufs_signal2_mmap_vmops = { | 909 | static struct vm_operations_struct spufs_signal2_mmap_vmops = { |
918 | .nopage = spufs_signal2_mmap_nopage, | 910 | .nopfn = spufs_signal2_mmap_nopfn, |
919 | }; | 911 | }; |
920 | 912 | ||
921 | static int spufs_signal2_mmap(struct file *file, struct vm_area_struct *vma) | 913 | static int spufs_signal2_mmap(struct file *file, struct vm_area_struct *vma) |
@@ -923,7 +915,7 @@ static int spufs_signal2_mmap(struct file *file, struct vm_area_struct *vma) | |||
923 | if (!(vma->vm_flags & VM_SHARED)) | 915 | if (!(vma->vm_flags & VM_SHARED)) |
924 | return -EINVAL; | 916 | return -EINVAL; |
925 | 917 | ||
926 | vma->vm_flags |= VM_IO; | 918 | vma->vm_flags |= VM_IO | VM_PFNMAP; |
927 | vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) | 919 | vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) |
928 | | _PAGE_NO_CACHE | _PAGE_GUARDED); | 920 | | _PAGE_NO_CACHE | _PAGE_GUARDED); |
929 | 921 | ||
@@ -934,7 +926,7 @@ static int spufs_signal2_mmap(struct file *file, struct vm_area_struct *vma) | |||
934 | #define spufs_signal2_mmap NULL | 926 | #define spufs_signal2_mmap NULL |
935 | #endif /* !SPUFS_MMAP_4K */ | 927 | #endif /* !SPUFS_MMAP_4K */ |
936 | 928 | ||
937 | static struct file_operations spufs_signal2_fops = { | 929 | static const struct file_operations spufs_signal2_fops = { |
938 | .open = spufs_signal2_open, | 930 | .open = spufs_signal2_open, |
939 | .read = spufs_signal2_read, | 931 | .read = spufs_signal2_read, |
940 | .write = spufs_signal2_write, | 932 | .write = spufs_signal2_write, |
@@ -1000,14 +992,14 @@ DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get, | |||
1000 | spufs_signal2_type_set, "%llu"); | 992 | spufs_signal2_type_set, "%llu"); |
1001 | 993 | ||
1002 | #if SPUFS_MMAP_4K | 994 | #if SPUFS_MMAP_4K |
1003 | static struct page *spufs_mss_mmap_nopage(struct vm_area_struct *vma, | 995 | static unsigned long spufs_mss_mmap_nopfn(struct vm_area_struct *vma, |
1004 | unsigned long address, int *type) | 996 | unsigned long address) |
1005 | { | 997 | { |
1006 | return spufs_ps_nopage(vma, address, type, 0x0000, 0x1000); | 998 | return spufs_ps_nopfn(vma, address, 0x0000, 0x1000); |
1007 | } | 999 | } |
1008 | 1000 | ||
1009 | static struct vm_operations_struct spufs_mss_mmap_vmops = { | 1001 | static struct vm_operations_struct spufs_mss_mmap_vmops = { |
1010 | .nopage = spufs_mss_mmap_nopage, | 1002 | .nopfn = spufs_mss_mmap_nopfn, |
1011 | }; | 1003 | }; |
1012 | 1004 | ||
1013 | /* | 1005 | /* |
@@ -1018,7 +1010,7 @@ static int spufs_mss_mmap(struct file *file, struct vm_area_struct *vma) | |||
1018 | if (!(vma->vm_flags & VM_SHARED)) | 1010 | if (!(vma->vm_flags & VM_SHARED)) |
1019 | return -EINVAL; | 1011 | return -EINVAL; |
1020 | 1012 | ||
1021 | vma->vm_flags |= VM_IO; | 1013 | vma->vm_flags |= VM_IO | VM_PFNMAP; |
1022 | vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) | 1014 | vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) |
1023 | | _PAGE_NO_CACHE | _PAGE_GUARDED); | 1015 | | _PAGE_NO_CACHE | _PAGE_GUARDED); |
1024 | 1016 | ||
@@ -1032,24 +1024,27 @@ static int spufs_mss_mmap(struct file *file, struct vm_area_struct *vma) | |||
1032 | static int spufs_mss_open(struct inode *inode, struct file *file) | 1024 | static int spufs_mss_open(struct inode *inode, struct file *file) |
1033 | { | 1025 | { |
1034 | struct spufs_inode_info *i = SPUFS_I(inode); | 1026 | struct spufs_inode_info *i = SPUFS_I(inode); |
1027 | struct spu_context *ctx = i->i_ctx; | ||
1035 | 1028 | ||
1036 | file->private_data = i->i_ctx; | 1029 | file->private_data = i->i_ctx; |
1030 | ctx->mss = inode->i_mapping; | ||
1031 | smp_wmb(); | ||
1037 | return nonseekable_open(inode, file); | 1032 | return nonseekable_open(inode, file); |
1038 | } | 1033 | } |
1039 | 1034 | ||
1040 | static struct file_operations spufs_mss_fops = { | 1035 | static const struct file_operations spufs_mss_fops = { |
1041 | .open = spufs_mss_open, | 1036 | .open = spufs_mss_open, |
1042 | .mmap = spufs_mss_mmap, | 1037 | .mmap = spufs_mss_mmap, |
1043 | }; | 1038 | }; |
1044 | 1039 | ||
1045 | static struct page *spufs_psmap_mmap_nopage(struct vm_area_struct *vma, | 1040 | static unsigned long spufs_psmap_mmap_nopfn(struct vm_area_struct *vma, |
1046 | unsigned long address, int *type) | 1041 | unsigned long address) |
1047 | { | 1042 | { |
1048 | return spufs_ps_nopage(vma, address, type, 0x0000, 0x20000); | 1043 | return spufs_ps_nopfn(vma, address, 0x0000, 0x20000); |
1049 | } | 1044 | } |
1050 | 1045 | ||
1051 | static struct vm_operations_struct spufs_psmap_mmap_vmops = { | 1046 | static struct vm_operations_struct spufs_psmap_mmap_vmops = { |
1052 | .nopage = spufs_psmap_mmap_nopage, | 1047 | .nopfn = spufs_psmap_mmap_nopfn, |
1053 | }; | 1048 | }; |
1054 | 1049 | ||
1055 | /* | 1050 | /* |
@@ -1060,7 +1055,7 @@ static int spufs_psmap_mmap(struct file *file, struct vm_area_struct *vma) | |||
1060 | if (!(vma->vm_flags & VM_SHARED)) | 1055 | if (!(vma->vm_flags & VM_SHARED)) |
1061 | return -EINVAL; | 1056 | return -EINVAL; |
1062 | 1057 | ||
1063 | vma->vm_flags |= VM_IO; | 1058 | vma->vm_flags |= VM_IO | VM_PFNMAP; |
1064 | vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) | 1059 | vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) |
1065 | | _PAGE_NO_CACHE | _PAGE_GUARDED); | 1060 | | _PAGE_NO_CACHE | _PAGE_GUARDED); |
1066 | 1061 | ||
@@ -1071,26 +1066,29 @@ static int spufs_psmap_mmap(struct file *file, struct vm_area_struct *vma) | |||
1071 | static int spufs_psmap_open(struct inode *inode, struct file *file) | 1066 | static int spufs_psmap_open(struct inode *inode, struct file *file) |
1072 | { | 1067 | { |
1073 | struct spufs_inode_info *i = SPUFS_I(inode); | 1068 | struct spufs_inode_info *i = SPUFS_I(inode); |
1069 | struct spu_context *ctx = i->i_ctx; | ||
1074 | 1070 | ||
1075 | file->private_data = i->i_ctx; | 1071 | file->private_data = i->i_ctx; |
1072 | ctx->psmap = inode->i_mapping; | ||
1073 | smp_wmb(); | ||
1076 | return nonseekable_open(inode, file); | 1074 | return nonseekable_open(inode, file); |
1077 | } | 1075 | } |
1078 | 1076 | ||
1079 | static struct file_operations spufs_psmap_fops = { | 1077 | static const struct file_operations spufs_psmap_fops = { |
1080 | .open = spufs_psmap_open, | 1078 | .open = spufs_psmap_open, |
1081 | .mmap = spufs_psmap_mmap, | 1079 | .mmap = spufs_psmap_mmap, |
1082 | }; | 1080 | }; |
1083 | 1081 | ||
1084 | 1082 | ||
1085 | #if SPUFS_MMAP_4K | 1083 | #if SPUFS_MMAP_4K |
1086 | static struct page *spufs_mfc_mmap_nopage(struct vm_area_struct *vma, | 1084 | static unsigned long spufs_mfc_mmap_nopfn(struct vm_area_struct *vma, |
1087 | unsigned long address, int *type) | 1085 | unsigned long address) |
1088 | { | 1086 | { |
1089 | return spufs_ps_nopage(vma, address, type, 0x3000, 0x1000); | 1087 | return spufs_ps_nopfn(vma, address, 0x3000, 0x1000); |
1090 | } | 1088 | } |
1091 | 1089 | ||
1092 | static struct vm_operations_struct spufs_mfc_mmap_vmops = { | 1090 | static struct vm_operations_struct spufs_mfc_mmap_vmops = { |
1093 | .nopage = spufs_mfc_mmap_nopage, | 1091 | .nopfn = spufs_mfc_mmap_nopfn, |
1094 | }; | 1092 | }; |
1095 | 1093 | ||
1096 | /* | 1094 | /* |
@@ -1101,7 +1099,7 @@ static int spufs_mfc_mmap(struct file *file, struct vm_area_struct *vma) | |||
1101 | if (!(vma->vm_flags & VM_SHARED)) | 1099 | if (!(vma->vm_flags & VM_SHARED)) |
1102 | return -EINVAL; | 1100 | return -EINVAL; |
1103 | 1101 | ||
1104 | vma->vm_flags |= VM_IO; | 1102 | vma->vm_flags |= VM_IO | VM_PFNMAP; |
1105 | vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) | 1103 | vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) |
1106 | | _PAGE_NO_CACHE | _PAGE_GUARDED); | 1104 | | _PAGE_NO_CACHE | _PAGE_GUARDED); |
1107 | 1105 | ||
@@ -1125,6 +1123,8 @@ static int spufs_mfc_open(struct inode *inode, struct file *file) | |||
1125 | return -EBUSY; | 1123 | return -EBUSY; |
1126 | 1124 | ||
1127 | file->private_data = ctx; | 1125 | file->private_data = ctx; |
1126 | ctx->mfc = inode->i_mapping; | ||
1127 | smp_wmb(); | ||
1128 | return nonseekable_open(inode, file); | 1128 | return nonseekable_open(inode, file); |
1129 | } | 1129 | } |
1130 | 1130 | ||
@@ -1309,7 +1309,7 @@ static ssize_t spufs_mfc_write(struct file *file, const char __user *buffer, | |||
1309 | if (ret) | 1309 | if (ret) |
1310 | goto out; | 1310 | goto out; |
1311 | 1311 | ||
1312 | spu_acquire_runnable(ctx); | 1312 | spu_acquire_runnable(ctx, 0); |
1313 | if (file->f_flags & O_NONBLOCK) { | 1313 | if (file->f_flags & O_NONBLOCK) { |
1314 | ret = ctx->ops->send_mfc_command(ctx, &cmd); | 1314 | ret = ctx->ops->send_mfc_command(ctx, &cmd); |
1315 | } else { | 1315 | } else { |
@@ -1393,7 +1393,7 @@ static int spufs_mfc_fasync(int fd, struct file *file, int on) | |||
1393 | return fasync_helper(fd, file, on, &ctx->mfc_fasync); | 1393 | return fasync_helper(fd, file, on, &ctx->mfc_fasync); |
1394 | } | 1394 | } |
1395 | 1395 | ||
1396 | static struct file_operations spufs_mfc_fops = { | 1396 | static const struct file_operations spufs_mfc_fops = { |
1397 | .open = spufs_mfc_open, | 1397 | .open = spufs_mfc_open, |
1398 | .read = spufs_mfc_read, | 1398 | .read = spufs_mfc_read, |
1399 | .write = spufs_mfc_write, | 1399 | .write = spufs_mfc_write, |
@@ -1650,7 +1650,7 @@ static ssize_t spufs_mbox_info_read(struct file *file, char __user *buf, | |||
1650 | return ret; | 1650 | return ret; |
1651 | } | 1651 | } |
1652 | 1652 | ||
1653 | static struct file_operations spufs_mbox_info_fops = { | 1653 | static const struct file_operations spufs_mbox_info_fops = { |
1654 | .open = spufs_info_open, | 1654 | .open = spufs_info_open, |
1655 | .read = spufs_mbox_info_read, | 1655 | .read = spufs_mbox_info_read, |
1656 | .llseek = generic_file_llseek, | 1656 | .llseek = generic_file_llseek, |
@@ -1688,7 +1688,7 @@ static ssize_t spufs_ibox_info_read(struct file *file, char __user *buf, | |||
1688 | return ret; | 1688 | return ret; |
1689 | } | 1689 | } |
1690 | 1690 | ||
1691 | static struct file_operations spufs_ibox_info_fops = { | 1691 | static const struct file_operations spufs_ibox_info_fops = { |
1692 | .open = spufs_info_open, | 1692 | .open = spufs_info_open, |
1693 | .read = spufs_ibox_info_read, | 1693 | .read = spufs_ibox_info_read, |
1694 | .llseek = generic_file_llseek, | 1694 | .llseek = generic_file_llseek, |
@@ -1729,7 +1729,7 @@ static ssize_t spufs_wbox_info_read(struct file *file, char __user *buf, | |||
1729 | return ret; | 1729 | return ret; |
1730 | } | 1730 | } |
1731 | 1731 | ||
1732 | static struct file_operations spufs_wbox_info_fops = { | 1732 | static const struct file_operations spufs_wbox_info_fops = { |
1733 | .open = spufs_info_open, | 1733 | .open = spufs_info_open, |
1734 | .read = spufs_wbox_info_read, | 1734 | .read = spufs_wbox_info_read, |
1735 | .llseek = generic_file_llseek, | 1735 | .llseek = generic_file_llseek, |
@@ -1779,7 +1779,7 @@ static ssize_t spufs_dma_info_read(struct file *file, char __user *buf, | |||
1779 | return ret; | 1779 | return ret; |
1780 | } | 1780 | } |
1781 | 1781 | ||
1782 | static struct file_operations spufs_dma_info_fops = { | 1782 | static const struct file_operations spufs_dma_info_fops = { |
1783 | .open = spufs_info_open, | 1783 | .open = spufs_info_open, |
1784 | .read = spufs_dma_info_read, | 1784 | .read = spufs_dma_info_read, |
1785 | }; | 1785 | }; |
@@ -1830,7 +1830,7 @@ static ssize_t spufs_proxydma_info_read(struct file *file, char __user *buf, | |||
1830 | return ret; | 1830 | return ret; |
1831 | } | 1831 | } |
1832 | 1832 | ||
1833 | static struct file_operations spufs_proxydma_info_fops = { | 1833 | static const struct file_operations spufs_proxydma_info_fops = { |
1834 | .open = spufs_info_open, | 1834 | .open = spufs_info_open, |
1835 | .read = spufs_proxydma_info_read, | 1835 | .read = spufs_proxydma_info_read, |
1836 | }; | 1836 | }; |
diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index 738b9244382f..8079983ef94f 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c | |||
@@ -220,11 +220,11 @@ static int spufs_dir_close(struct inode *inode, struct file *file) | |||
220 | return dcache_dir_close(inode, file); | 220 | return dcache_dir_close(inode, file); |
221 | } | 221 | } |
222 | 222 | ||
223 | struct inode_operations spufs_dir_inode_operations = { | 223 | const struct inode_operations spufs_dir_inode_operations = { |
224 | .lookup = simple_lookup, | 224 | .lookup = simple_lookup, |
225 | }; | 225 | }; |
226 | 226 | ||
227 | struct file_operations spufs_context_fops = { | 227 | const struct file_operations spufs_context_fops = { |
228 | .open = dcache_dir_open, | 228 | .open = dcache_dir_open, |
229 | .release = spufs_dir_close, | 229 | .release = spufs_dir_close, |
230 | .llseek = dcache_dir_lseek, | 230 | .llseek = dcache_dir_lseek, |
@@ -372,7 +372,7 @@ static int spufs_gang_close(struct inode *inode, struct file *file) | |||
372 | return dcache_dir_close(inode, file); | 372 | return dcache_dir_close(inode, file); |
373 | } | 373 | } |
374 | 374 | ||
375 | struct file_operations spufs_gang_fops = { | 375 | const struct file_operations spufs_gang_fops = { |
376 | .open = dcache_dir_open, | 376 | .open = dcache_dir_open, |
377 | .release = spufs_gang_close, | 377 | .release = spufs_gang_close, |
378 | .llseek = dcache_dir_lseek, | 378 | .llseek = dcache_dir_lseek, |
diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c index 1acc2ffef8c8..353a8fa07ab8 100644 --- a/arch/powerpc/platforms/cell/spufs/run.c +++ b/arch/powerpc/platforms/cell/spufs/run.c | |||
@@ -133,7 +133,7 @@ out_drop_priv: | |||
133 | spu_mfc_sr1_set(ctx->spu, sr1); | 133 | spu_mfc_sr1_set(ctx->spu, sr1); |
134 | 134 | ||
135 | out_unlock: | 135 | out_unlock: |
136 | spu_release_exclusive(ctx); | 136 | spu_release(ctx); |
137 | out: | 137 | out: |
138 | return ret; | 138 | return ret; |
139 | } | 139 | } |
@@ -143,7 +143,7 @@ static inline int spu_run_init(struct spu_context *ctx, u32 * npc) | |||
143 | int ret; | 143 | int ret; |
144 | unsigned long runcntl = SPU_RUNCNTL_RUNNABLE; | 144 | unsigned long runcntl = SPU_RUNCNTL_RUNNABLE; |
145 | 145 | ||
146 | ret = spu_acquire_runnable(ctx); | 146 | ret = spu_acquire_runnable(ctx, SPU_ACTIVATE_NOWAKE); |
147 | if (ret) | 147 | if (ret) |
148 | return ret; | 148 | return ret; |
149 | 149 | ||
@@ -155,7 +155,7 @@ static inline int spu_run_init(struct spu_context *ctx, u32 * npc) | |||
155 | spu_release(ctx); | 155 | spu_release(ctx); |
156 | ret = spu_setup_isolated(ctx); | 156 | ret = spu_setup_isolated(ctx); |
157 | if (!ret) | 157 | if (!ret) |
158 | ret = spu_acquire_runnable(ctx); | 158 | ret = spu_acquire_runnable(ctx, SPU_ACTIVATE_NOWAKE); |
159 | } | 159 | } |
160 | 160 | ||
161 | /* if userspace has set the runcntrl register (eg, to issue an | 161 | /* if userspace has set the runcntrl register (eg, to issue an |
@@ -164,8 +164,10 @@ static inline int spu_run_init(struct spu_context *ctx, u32 * npc) | |||
164 | (SPU_RUNCNTL_RUNNABLE | SPU_RUNCNTL_ISOLATE); | 164 | (SPU_RUNCNTL_RUNNABLE | SPU_RUNCNTL_ISOLATE); |
165 | if (runcntl == 0) | 165 | if (runcntl == 0) |
166 | runcntl = SPU_RUNCNTL_RUNNABLE; | 166 | runcntl = SPU_RUNCNTL_RUNNABLE; |
167 | } else | 167 | } else { |
168 | spu_start_tick(ctx); | ||
168 | ctx->ops->npc_write(ctx, *npc); | 169 | ctx->ops->npc_write(ctx, *npc); |
170 | } | ||
169 | 171 | ||
170 | ctx->ops->runcntl_write(ctx, runcntl); | 172 | ctx->ops->runcntl_write(ctx, runcntl); |
171 | return ret; | 173 | return ret; |
@@ -176,6 +178,7 @@ static inline int spu_run_fini(struct spu_context *ctx, u32 * npc, | |||
176 | { | 178 | { |
177 | int ret = 0; | 179 | int ret = 0; |
178 | 180 | ||
181 | spu_stop_tick(ctx); | ||
179 | *status = ctx->ops->status_read(ctx); | 182 | *status = ctx->ops->status_read(ctx); |
180 | *npc = ctx->ops->npc_read(ctx); | 183 | *npc = ctx->ops->npc_read(ctx); |
181 | spu_release(ctx); | 184 | spu_release(ctx); |
@@ -329,8 +332,10 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx, | |||
329 | } | 332 | } |
330 | if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) { | 333 | if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) { |
331 | ret = spu_reacquire_runnable(ctx, npc, &status); | 334 | ret = spu_reacquire_runnable(ctx, npc, &status); |
332 | if (ret) | 335 | if (ret) { |
336 | spu_stop_tick(ctx); | ||
333 | goto out2; | 337 | goto out2; |
338 | } | ||
334 | continue; | 339 | continue; |
335 | } | 340 | } |
336 | ret = spu_process_events(ctx); | 341 | ret = spu_process_events(ctx); |
@@ -361,4 +366,3 @@ out: | |||
361 | up(&ctx->run_sema); | 366 | up(&ctx->run_sema); |
362 | return ret; | 367 | return ret; |
363 | } | 368 | } |
364 | |||
diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c index bd6fe4b7a84b..2f25e68b4bac 100644 --- a/arch/powerpc/platforms/cell/spufs/sched.c +++ b/arch/powerpc/platforms/cell/spufs/sched.c | |||
@@ -44,17 +44,18 @@ | |||
44 | #include <asm/spu_priv1.h> | 44 | #include <asm/spu_priv1.h> |
45 | #include "spufs.h" | 45 | #include "spufs.h" |
46 | 46 | ||
47 | #define SPU_MIN_TIMESLICE (100 * HZ / 1000) | 47 | #define SPU_TIMESLICE (HZ) |
48 | 48 | ||
49 | #define SPU_BITMAP_SIZE (((MAX_PRIO+BITS_PER_LONG)/BITS_PER_LONG)+1) | ||
50 | struct spu_prio_array { | 49 | struct spu_prio_array { |
51 | unsigned long bitmap[SPU_BITMAP_SIZE]; | 50 | DECLARE_BITMAP(bitmap, MAX_PRIO); |
52 | wait_queue_head_t waitq[MAX_PRIO]; | 51 | struct list_head runq[MAX_PRIO]; |
52 | spinlock_t runq_lock; | ||
53 | struct list_head active_list[MAX_NUMNODES]; | 53 | struct list_head active_list[MAX_NUMNODES]; |
54 | struct mutex active_mutex[MAX_NUMNODES]; | 54 | struct mutex active_mutex[MAX_NUMNODES]; |
55 | }; | 55 | }; |
56 | 56 | ||
57 | static struct spu_prio_array *spu_prio; | 57 | static struct spu_prio_array *spu_prio; |
58 | static struct workqueue_struct *spu_sched_wq; | ||
58 | 59 | ||
59 | static inline int node_allowed(int node) | 60 | static inline int node_allowed(int node) |
60 | { | 61 | { |
@@ -68,6 +69,64 @@ static inline int node_allowed(int node) | |||
68 | return 1; | 69 | return 1; |
69 | } | 70 | } |
70 | 71 | ||
72 | void spu_start_tick(struct spu_context *ctx) | ||
73 | { | ||
74 | if (ctx->policy == SCHED_RR) | ||
75 | queue_delayed_work(spu_sched_wq, &ctx->sched_work, SPU_TIMESLICE); | ||
76 | } | ||
77 | |||
78 | void spu_stop_tick(struct spu_context *ctx) | ||
79 | { | ||
80 | if (ctx->policy == SCHED_RR) | ||
81 | cancel_delayed_work(&ctx->sched_work); | ||
82 | } | ||
83 | |||
84 | void spu_sched_tick(struct work_struct *work) | ||
85 | { | ||
86 | struct spu_context *ctx = | ||
87 | container_of(work, struct spu_context, sched_work.work); | ||
88 | struct spu *spu; | ||
89 | int rearm = 1; | ||
90 | |||
91 | mutex_lock(&ctx->state_mutex); | ||
92 | spu = ctx->spu; | ||
93 | if (spu) { | ||
94 | int best = sched_find_first_bit(spu_prio->bitmap); | ||
95 | if (best <= ctx->prio) { | ||
96 | spu_deactivate(ctx); | ||
97 | rearm = 0; | ||
98 | } | ||
99 | } | ||
100 | mutex_unlock(&ctx->state_mutex); | ||
101 | |||
102 | if (rearm) | ||
103 | spu_start_tick(ctx); | ||
104 | } | ||
105 | |||
106 | /** | ||
107 | * spu_add_to_active_list - add spu to active list | ||
108 | * @spu: spu to add to the active list | ||
109 | */ | ||
110 | static void spu_add_to_active_list(struct spu *spu) | ||
111 | { | ||
112 | mutex_lock(&spu_prio->active_mutex[spu->node]); | ||
113 | list_add_tail(&spu->list, &spu_prio->active_list[spu->node]); | ||
114 | mutex_unlock(&spu_prio->active_mutex[spu->node]); | ||
115 | } | ||
116 | |||
117 | /** | ||
118 | * spu_remove_from_active_list - remove spu from active list | ||
119 | * @spu: spu to remove from the active list | ||
120 | */ | ||
121 | static void spu_remove_from_active_list(struct spu *spu) | ||
122 | { | ||
123 | int node = spu->node; | ||
124 | |||
125 | mutex_lock(&spu_prio->active_mutex[node]); | ||
126 | list_del_init(&spu->list); | ||
127 | mutex_unlock(&spu_prio->active_mutex[node]); | ||
128 | } | ||
129 | |||
71 | static inline void mm_needs_global_tlbie(struct mm_struct *mm) | 130 | static inline void mm_needs_global_tlbie(struct mm_struct *mm) |
72 | { | 131 | { |
73 | int nr = (NR_CPUS > 1) ? NR_CPUS : NR_CPUS + 1; | 132 | int nr = (NR_CPUS > 1) ? NR_CPUS : NR_CPUS + 1; |
@@ -94,8 +153,12 @@ int spu_switch_event_unregister(struct notifier_block * n) | |||
94 | return blocking_notifier_chain_unregister(&spu_switch_notifier, n); | 153 | return blocking_notifier_chain_unregister(&spu_switch_notifier, n); |
95 | } | 154 | } |
96 | 155 | ||
97 | 156 | /** | |
98 | static inline void bind_context(struct spu *spu, struct spu_context *ctx) | 157 | * spu_bind_context - bind spu context to physical spu |
158 | * @spu: physical spu to bind to | ||
159 | * @ctx: context to bind | ||
160 | */ | ||
161 | static void spu_bind_context(struct spu *spu, struct spu_context *ctx) | ||
99 | { | 162 | { |
100 | pr_debug("%s: pid=%d SPU=%d NODE=%d\n", __FUNCTION__, current->pid, | 163 | pr_debug("%s: pid=%d SPU=%d NODE=%d\n", __FUNCTION__, current->pid, |
101 | spu->number, spu->node); | 164 | spu->number, spu->node); |
@@ -104,7 +167,6 @@ static inline void bind_context(struct spu *spu, struct spu_context *ctx) | |||
104 | ctx->spu = spu; | 167 | ctx->spu = spu; |
105 | ctx->ops = &spu_hw_ops; | 168 | ctx->ops = &spu_hw_ops; |
106 | spu->pid = current->pid; | 169 | spu->pid = current->pid; |
107 | spu->prio = current->prio; | ||
108 | spu->mm = ctx->owner; | 170 | spu->mm = ctx->owner; |
109 | mm_needs_global_tlbie(spu->mm); | 171 | mm_needs_global_tlbie(spu->mm); |
110 | spu->ibox_callback = spufs_ibox_callback; | 172 | spu->ibox_callback = spufs_ibox_callback; |
@@ -118,12 +180,21 @@ static inline void bind_context(struct spu *spu, struct spu_context *ctx) | |||
118 | spu->timestamp = jiffies; | 180 | spu->timestamp = jiffies; |
119 | spu_cpu_affinity_set(spu, raw_smp_processor_id()); | 181 | spu_cpu_affinity_set(spu, raw_smp_processor_id()); |
120 | spu_switch_notify(spu, ctx); | 182 | spu_switch_notify(spu, ctx); |
183 | spu_add_to_active_list(spu); | ||
184 | ctx->state = SPU_STATE_RUNNABLE; | ||
121 | } | 185 | } |
122 | 186 | ||
123 | static inline void unbind_context(struct spu *spu, struct spu_context *ctx) | 187 | /** |
188 | * spu_unbind_context - unbind spu context from physical spu | ||
189 | * @spu: physical spu to unbind from | ||
190 | * @ctx: context to unbind | ||
191 | */ | ||
192 | static void spu_unbind_context(struct spu *spu, struct spu_context *ctx) | ||
124 | { | 193 | { |
125 | pr_debug("%s: unbind pid=%d SPU=%d NODE=%d\n", __FUNCTION__, | 194 | pr_debug("%s: unbind pid=%d SPU=%d NODE=%d\n", __FUNCTION__, |
126 | spu->pid, spu->number, spu->node); | 195 | spu->pid, spu->number, spu->node); |
196 | |||
197 | spu_remove_from_active_list(spu); | ||
127 | spu_switch_notify(spu, NULL); | 198 | spu_switch_notify(spu, NULL); |
128 | spu_unmap_mappings(ctx); | 199 | spu_unmap_mappings(ctx); |
129 | spu_save(&ctx->csa, spu); | 200 | spu_save(&ctx->csa, spu); |
@@ -136,95 +207,98 @@ static inline void unbind_context(struct spu *spu, struct spu_context *ctx) | |||
136 | spu->dma_callback = NULL; | 207 | spu->dma_callback = NULL; |
137 | spu->mm = NULL; | 208 | spu->mm = NULL; |
138 | spu->pid = 0; | 209 | spu->pid = 0; |
139 | spu->prio = MAX_PRIO; | ||
140 | ctx->ops = &spu_backing_ops; | 210 | ctx->ops = &spu_backing_ops; |
141 | ctx->spu = NULL; | 211 | ctx->spu = NULL; |
142 | spu->flags = 0; | 212 | spu->flags = 0; |
143 | spu->ctx = NULL; | 213 | spu->ctx = NULL; |
144 | } | 214 | } |
145 | 215 | ||
146 | static inline void spu_add_wq(wait_queue_head_t * wq, wait_queue_t * wait, | 216 | /** |
147 | int prio) | 217 | * spu_add_to_rq - add a context to the runqueue |
218 | * @ctx: context to add | ||
219 | */ | ||
220 | static void spu_add_to_rq(struct spu_context *ctx) | ||
148 | { | 221 | { |
149 | prepare_to_wait_exclusive(wq, wait, TASK_INTERRUPTIBLE); | 222 | spin_lock(&spu_prio->runq_lock); |
150 | set_bit(prio, spu_prio->bitmap); | 223 | list_add_tail(&ctx->rq, &spu_prio->runq[ctx->prio]); |
224 | set_bit(ctx->prio, spu_prio->bitmap); | ||
225 | spin_unlock(&spu_prio->runq_lock); | ||
151 | } | 226 | } |
152 | 227 | ||
153 | static inline void spu_del_wq(wait_queue_head_t * wq, wait_queue_t * wait, | 228 | /** |
154 | int prio) | 229 | * spu_del_from_rq - remove a context from the runqueue |
230 | * @ctx: context to remove | ||
231 | */ | ||
232 | static void spu_del_from_rq(struct spu_context *ctx) | ||
155 | { | 233 | { |
156 | u64 flags; | 234 | spin_lock(&spu_prio->runq_lock); |
157 | 235 | list_del_init(&ctx->rq); | |
158 | __set_current_state(TASK_RUNNING); | 236 | if (list_empty(&spu_prio->runq[ctx->prio])) |
159 | 237 | clear_bit(ctx->prio, spu_prio->bitmap); | |
160 | spin_lock_irqsave(&wq->lock, flags); | 238 | spin_unlock(&spu_prio->runq_lock); |
239 | } | ||
161 | 240 | ||
162 | remove_wait_queue_locked(wq, wait); | 241 | /** |
163 | if (list_empty(&wq->task_list)) | 242 | * spu_grab_context - remove one context from the runqueue |
164 | clear_bit(prio, spu_prio->bitmap); | 243 | * @prio: priority of the context to be removed |
244 | * | ||
245 | * This function removes one context from the runqueue for priority @prio. | ||
246 | * If there is more than one context with the given priority the first | ||
247 | * task on the runqueue will be taken. | ||
248 | * | ||
249 | * Returns the spu_context it just removed. | ||
250 | * | ||
251 | * Must be called with spu_prio->runq_lock held. | ||
252 | */ | ||
253 | static struct spu_context *spu_grab_context(int prio) | ||
254 | { | ||
255 | struct list_head *rq = &spu_prio->runq[prio]; | ||
165 | 256 | ||
166 | spin_unlock_irqrestore(&wq->lock, flags); | 257 | if (list_empty(rq)) |
258 | return NULL; | ||
259 | return list_entry(rq->next, struct spu_context, rq); | ||
167 | } | 260 | } |
168 | 261 | ||
169 | static void spu_prio_wait(struct spu_context *ctx, u64 flags) | 262 | static void spu_prio_wait(struct spu_context *ctx) |
170 | { | 263 | { |
171 | int prio = current->prio; | ||
172 | wait_queue_head_t *wq = &spu_prio->waitq[prio]; | ||
173 | DEFINE_WAIT(wait); | 264 | DEFINE_WAIT(wait); |
174 | 265 | ||
175 | if (ctx->spu) | 266 | set_bit(SPU_SCHED_WAKE, &ctx->sched_flags); |
176 | return; | 267 | prepare_to_wait_exclusive(&ctx->stop_wq, &wait, TASK_INTERRUPTIBLE); |
177 | |||
178 | spu_add_wq(wq, &wait, prio); | ||
179 | |||
180 | if (!signal_pending(current)) { | 268 | if (!signal_pending(current)) { |
181 | up_write(&ctx->state_sema); | 269 | mutex_unlock(&ctx->state_mutex); |
182 | pr_debug("%s: pid=%d prio=%d\n", __FUNCTION__, | ||
183 | current->pid, current->prio); | ||
184 | schedule(); | 270 | schedule(); |
185 | down_write(&ctx->state_sema); | 271 | mutex_lock(&ctx->state_mutex); |
186 | } | 272 | } |
187 | 273 | __set_current_state(TASK_RUNNING); | |
188 | spu_del_wq(wq, &wait, prio); | 274 | remove_wait_queue(&ctx->stop_wq, &wait); |
275 | clear_bit(SPU_SCHED_WAKE, &ctx->sched_flags); | ||
189 | } | 276 | } |
190 | 277 | ||
191 | static void spu_prio_wakeup(void) | 278 | /** |
279 | * spu_reschedule - try to find a runnable context for a spu | ||
280 | * @spu: spu available | ||
281 | * | ||
282 | * This function is called whenever a spu becomes idle. It looks for the | ||
283 | * most suitable runnable spu context and schedules it for execution. | ||
284 | */ | ||
285 | static void spu_reschedule(struct spu *spu) | ||
192 | { | 286 | { |
193 | int best = sched_find_first_bit(spu_prio->bitmap); | 287 | int best; |
194 | if (best < MAX_PRIO) { | ||
195 | wait_queue_head_t *wq = &spu_prio->waitq[best]; | ||
196 | wake_up_interruptible_nr(wq, 1); | ||
197 | } | ||
198 | } | ||
199 | 288 | ||
200 | static int get_active_spu(struct spu *spu) | 289 | spu_free(spu); |
201 | { | ||
202 | int node = spu->node; | ||
203 | struct spu *tmp; | ||
204 | int rc = 0; | ||
205 | 290 | ||
206 | mutex_lock(&spu_prio->active_mutex[node]); | 291 | spin_lock(&spu_prio->runq_lock); |
207 | list_for_each_entry(tmp, &spu_prio->active_list[node], list) { | 292 | best = sched_find_first_bit(spu_prio->bitmap); |
208 | if (tmp == spu) { | 293 | if (best < MAX_PRIO) { |
209 | list_del_init(&spu->list); | 294 | struct spu_context *ctx = spu_grab_context(best); |
210 | rc = 1; | 295 | if (ctx && test_bit(SPU_SCHED_WAKE, &ctx->sched_flags)) |
211 | break; | 296 | wake_up(&ctx->stop_wq); |
212 | } | ||
213 | } | 297 | } |
214 | mutex_unlock(&spu_prio->active_mutex[node]); | 298 | spin_unlock(&spu_prio->runq_lock); |
215 | return rc; | ||
216 | } | ||
217 | |||
218 | static void put_active_spu(struct spu *spu) | ||
219 | { | ||
220 | int node = spu->node; | ||
221 | |||
222 | mutex_lock(&spu_prio->active_mutex[node]); | ||
223 | list_add_tail(&spu->list, &spu_prio->active_list[node]); | ||
224 | mutex_unlock(&spu_prio->active_mutex[node]); | ||
225 | } | 299 | } |
226 | 300 | ||
227 | static struct spu *spu_get_idle(struct spu_context *ctx, u64 flags) | 301 | static struct spu *spu_get_idle(struct spu_context *ctx) |
228 | { | 302 | { |
229 | struct spu *spu = NULL; | 303 | struct spu *spu = NULL; |
230 | int node = cpu_to_node(raw_smp_processor_id()); | 304 | int node = cpu_to_node(raw_smp_processor_id()); |
@@ -241,87 +315,154 @@ static struct spu *spu_get_idle(struct spu_context *ctx, u64 flags) | |||
241 | return spu; | 315 | return spu; |
242 | } | 316 | } |
243 | 317 | ||
244 | static inline struct spu *spu_get(struct spu_context *ctx, u64 flags) | 318 | /** |
319 | * find_victim - find a lower priority context to preempt | ||
320 | * @ctx: canidate context for running | ||
321 | * | ||
322 | * Returns the freed physical spu to run the new context on. | ||
323 | */ | ||
324 | static struct spu *find_victim(struct spu_context *ctx) | ||
245 | { | 325 | { |
246 | /* Future: spu_get_idle() if possible, | 326 | struct spu_context *victim = NULL; |
247 | * otherwise try to preempt an active | 327 | struct spu *spu; |
248 | * context. | 328 | int node, n; |
329 | |||
330 | /* | ||
331 | * Look for a possible preemption candidate on the local node first. | ||
332 | * If there is no candidate look at the other nodes. This isn't | ||
333 | * exactly fair, but so far the whole spu schedule tries to keep | ||
334 | * a strong node affinity. We might want to fine-tune this in | ||
335 | * the future. | ||
249 | */ | 336 | */ |
250 | return spu_get_idle(ctx, flags); | 337 | restart: |
338 | node = cpu_to_node(raw_smp_processor_id()); | ||
339 | for (n = 0; n < MAX_NUMNODES; n++, node++) { | ||
340 | node = (node < MAX_NUMNODES) ? node : 0; | ||
341 | if (!node_allowed(node)) | ||
342 | continue; | ||
343 | |||
344 | mutex_lock(&spu_prio->active_mutex[node]); | ||
345 | list_for_each_entry(spu, &spu_prio->active_list[node], list) { | ||
346 | struct spu_context *tmp = spu->ctx; | ||
347 | |||
348 | if (tmp->rt_priority < ctx->rt_priority && | ||
349 | (!victim || tmp->rt_priority < victim->rt_priority)) | ||
350 | victim = spu->ctx; | ||
351 | } | ||
352 | mutex_unlock(&spu_prio->active_mutex[node]); | ||
353 | |||
354 | if (victim) { | ||
355 | /* | ||
356 | * This nests ctx->state_mutex, but we always lock | ||
357 | * higher priority contexts before lower priority | ||
358 | * ones, so this is safe until we introduce | ||
359 | * priority inheritance schemes. | ||
360 | */ | ||
361 | if (!mutex_trylock(&victim->state_mutex)) { | ||
362 | victim = NULL; | ||
363 | goto restart; | ||
364 | } | ||
365 | |||
366 | spu = victim->spu; | ||
367 | if (!spu) { | ||
368 | /* | ||
369 | * This race can happen because we've dropped | ||
370 | * the active list mutex. No a problem, just | ||
371 | * restart the search. | ||
372 | */ | ||
373 | mutex_unlock(&victim->state_mutex); | ||
374 | victim = NULL; | ||
375 | goto restart; | ||
376 | } | ||
377 | spu_unbind_context(spu, victim); | ||
378 | mutex_unlock(&victim->state_mutex); | ||
379 | return spu; | ||
380 | } | ||
381 | } | ||
382 | |||
383 | return NULL; | ||
251 | } | 384 | } |
252 | 385 | ||
253 | /* The three externally callable interfaces | 386 | /** |
254 | * for the scheduler begin here. | 387 | * spu_activate - find a free spu for a context and execute it |
388 | * @ctx: spu context to schedule | ||
389 | * @flags: flags (currently ignored) | ||
255 | * | 390 | * |
256 | * spu_activate - bind a context to SPU, waiting as needed. | 391 | * Tries to find a free spu to run @ctx. If no free spu is availble |
257 | * spu_deactivate - unbind a context from its SPU. | 392 | * add the context to the runqueue so it gets woken up once an spu |
258 | * spu_yield - yield an SPU if others are waiting. | 393 | * is available. |
259 | */ | 394 | */ |
260 | 395 | int spu_activate(struct spu_context *ctx, unsigned long flags) | |
261 | int spu_activate(struct spu_context *ctx, u64 flags) | ||
262 | { | 396 | { |
263 | struct spu *spu; | ||
264 | int ret = 0; | ||
265 | 397 | ||
266 | for (;;) { | 398 | if (ctx->spu) |
267 | if (ctx->spu) | 399 | return 0; |
400 | |||
401 | do { | ||
402 | struct spu *spu; | ||
403 | |||
404 | spu = spu_get_idle(ctx); | ||
405 | /* | ||
406 | * If this is a realtime thread we try to get it running by | ||
407 | * preempting a lower priority thread. | ||
408 | */ | ||
409 | if (!spu && ctx->rt_priority) | ||
410 | spu = find_victim(ctx); | ||
411 | if (spu) { | ||
412 | spu_bind_context(spu, ctx); | ||
268 | return 0; | 413 | return 0; |
269 | spu = spu_get(ctx, flags); | ||
270 | if (spu != NULL) { | ||
271 | if (ctx->spu != NULL) { | ||
272 | spu_free(spu); | ||
273 | spu_prio_wakeup(); | ||
274 | break; | ||
275 | } | ||
276 | bind_context(spu, ctx); | ||
277 | put_active_spu(spu); | ||
278 | break; | ||
279 | } | 414 | } |
280 | spu_prio_wait(ctx, flags); | 415 | |
281 | if (signal_pending(current)) { | 416 | spu_add_to_rq(ctx); |
282 | ret = -ERESTARTSYS; | 417 | if (!(flags & SPU_ACTIVATE_NOWAKE)) |
283 | spu_prio_wakeup(); | 418 | spu_prio_wait(ctx); |
284 | break; | 419 | spu_del_from_rq(ctx); |
285 | } | 420 | } while (!signal_pending(current)); |
286 | } | 421 | |
287 | return ret; | 422 | return -ERESTARTSYS; |
288 | } | 423 | } |
289 | 424 | ||
425 | /** | ||
426 | * spu_deactivate - unbind a context from it's physical spu | ||
427 | * @ctx: spu context to unbind | ||
428 | * | ||
429 | * Unbind @ctx from the physical spu it is running on and schedule | ||
430 | * the highest priority context to run on the freed physical spu. | ||
431 | */ | ||
290 | void spu_deactivate(struct spu_context *ctx) | 432 | void spu_deactivate(struct spu_context *ctx) |
291 | { | 433 | { |
292 | struct spu *spu; | 434 | struct spu *spu = ctx->spu; |
293 | int needs_idle; | ||
294 | 435 | ||
295 | spu = ctx->spu; | 436 | if (spu) { |
296 | if (!spu) | 437 | spu_unbind_context(spu, ctx); |
297 | return; | 438 | spu_reschedule(spu); |
298 | needs_idle = get_active_spu(spu); | ||
299 | unbind_context(spu, ctx); | ||
300 | if (needs_idle) { | ||
301 | spu_free(spu); | ||
302 | spu_prio_wakeup(); | ||
303 | } | 439 | } |
304 | } | 440 | } |
305 | 441 | ||
442 | /** | ||
443 | * spu_yield - yield a physical spu if others are waiting | ||
444 | * @ctx: spu context to yield | ||
445 | * | ||
446 | * Check if there is a higher priority context waiting and if yes | ||
447 | * unbind @ctx from the physical spu and schedule the highest | ||
448 | * priority context to run on the freed physical spu instead. | ||
449 | */ | ||
306 | void spu_yield(struct spu_context *ctx) | 450 | void spu_yield(struct spu_context *ctx) |
307 | { | 451 | { |
308 | struct spu *spu; | 452 | struct spu *spu; |
309 | int need_yield = 0; | 453 | int need_yield = 0; |
310 | 454 | ||
311 | if (down_write_trylock(&ctx->state_sema)) { | 455 | if (mutex_trylock(&ctx->state_mutex)) { |
312 | if ((spu = ctx->spu) != NULL) { | 456 | if ((spu = ctx->spu) != NULL) { |
313 | int best = sched_find_first_bit(spu_prio->bitmap); | 457 | int best = sched_find_first_bit(spu_prio->bitmap); |
314 | if (best < MAX_PRIO) { | 458 | if (best < MAX_PRIO) { |
315 | pr_debug("%s: yielding SPU %d NODE %d\n", | 459 | pr_debug("%s: yielding SPU %d NODE %d\n", |
316 | __FUNCTION__, spu->number, spu->node); | 460 | __FUNCTION__, spu->number, spu->node); |
317 | spu_deactivate(ctx); | 461 | spu_deactivate(ctx); |
318 | ctx->state = SPU_STATE_SAVED; | ||
319 | need_yield = 1; | 462 | need_yield = 1; |
320 | } else { | ||
321 | spu->prio = MAX_PRIO; | ||
322 | } | 463 | } |
323 | } | 464 | } |
324 | up_write(&ctx->state_sema); | 465 | mutex_unlock(&ctx->state_mutex); |
325 | } | 466 | } |
326 | if (unlikely(need_yield)) | 467 | if (unlikely(need_yield)) |
327 | yield(); | 468 | yield(); |
@@ -331,14 +472,19 @@ int __init spu_sched_init(void) | |||
331 | { | 472 | { |
332 | int i; | 473 | int i; |
333 | 474 | ||
475 | spu_sched_wq = create_singlethread_workqueue("spusched"); | ||
476 | if (!spu_sched_wq) | ||
477 | return 1; | ||
478 | |||
334 | spu_prio = kzalloc(sizeof(struct spu_prio_array), GFP_KERNEL); | 479 | spu_prio = kzalloc(sizeof(struct spu_prio_array), GFP_KERNEL); |
335 | if (!spu_prio) { | 480 | if (!spu_prio) { |
336 | printk(KERN_WARNING "%s: Unable to allocate priority queue.\n", | 481 | printk(KERN_WARNING "%s: Unable to allocate priority queue.\n", |
337 | __FUNCTION__); | 482 | __FUNCTION__); |
483 | destroy_workqueue(spu_sched_wq); | ||
338 | return 1; | 484 | return 1; |
339 | } | 485 | } |
340 | for (i = 0; i < MAX_PRIO; i++) { | 486 | for (i = 0; i < MAX_PRIO; i++) { |
341 | init_waitqueue_head(&spu_prio->waitq[i]); | 487 | INIT_LIST_HEAD(&spu_prio->runq[i]); |
342 | __clear_bit(i, spu_prio->bitmap); | 488 | __clear_bit(i, spu_prio->bitmap); |
343 | } | 489 | } |
344 | __set_bit(MAX_PRIO, spu_prio->bitmap); | 490 | __set_bit(MAX_PRIO, spu_prio->bitmap); |
@@ -346,6 +492,7 @@ int __init spu_sched_init(void) | |||
346 | mutex_init(&spu_prio->active_mutex[i]); | 492 | mutex_init(&spu_prio->active_mutex[i]); |
347 | INIT_LIST_HEAD(&spu_prio->active_list[i]); | 493 | INIT_LIST_HEAD(&spu_prio->active_list[i]); |
348 | } | 494 | } |
495 | spin_lock_init(&spu_prio->runq_lock); | ||
349 | return 0; | 496 | return 0; |
350 | } | 497 | } |
351 | 498 | ||
@@ -364,4 +511,5 @@ void __exit spu_sched_exit(void) | |||
364 | mutex_unlock(&spu_prio->active_mutex[node]); | 511 | mutex_unlock(&spu_prio->active_mutex[node]); |
365 | } | 512 | } |
366 | kfree(spu_prio); | 513 | kfree(spu_prio); |
514 | destroy_workqueue(spu_sched_wq); | ||
367 | } | 515 | } |
diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h index 70fb13395c04..0c437891dfd5 100644 --- a/arch/powerpc/platforms/cell/spufs/spufs.h +++ b/arch/powerpc/platforms/cell/spufs/spufs.h | |||
@@ -23,7 +23,7 @@ | |||
23 | #define SPUFS_H | 23 | #define SPUFS_H |
24 | 24 | ||
25 | #include <linux/kref.h> | 25 | #include <linux/kref.h> |
26 | #include <linux/rwsem.h> | 26 | #include <linux/mutex.h> |
27 | #include <linux/spinlock.h> | 27 | #include <linux/spinlock.h> |
28 | #include <linux/fs.h> | 28 | #include <linux/fs.h> |
29 | 29 | ||
@@ -37,11 +37,13 @@ enum { | |||
37 | }; | 37 | }; |
38 | 38 | ||
39 | struct spu_context_ops; | 39 | struct spu_context_ops; |
40 | |||
41 | #define SPU_CONTEXT_PREEMPT 0UL | ||
42 | |||
43 | struct spu_gang; | 40 | struct spu_gang; |
44 | 41 | ||
42 | /* ctx->sched_flags */ | ||
43 | enum { | ||
44 | SPU_SCHED_WAKE = 0, | ||
45 | }; | ||
46 | |||
45 | struct spu_context { | 47 | struct spu_context { |
46 | struct spu *spu; /* pointer to a physical SPU */ | 48 | struct spu *spu; /* pointer to a physical SPU */ |
47 | struct spu_state csa; /* SPU context save area. */ | 49 | struct spu_state csa; /* SPU context save area. */ |
@@ -51,10 +53,12 @@ struct spu_context { | |||
51 | struct address_space *cntl; /* 'control' area mappings. */ | 53 | struct address_space *cntl; /* 'control' area mappings. */ |
52 | struct address_space *signal1; /* 'signal1' area mappings. */ | 54 | struct address_space *signal1; /* 'signal1' area mappings. */ |
53 | struct address_space *signal2; /* 'signal2' area mappings. */ | 55 | struct address_space *signal2; /* 'signal2' area mappings. */ |
56 | struct address_space *mss; /* 'mss' area mappings. */ | ||
57 | struct address_space *psmap; /* 'psmap' area mappings. */ | ||
54 | u64 object_id; /* user space pointer for oprofile */ | 58 | u64 object_id; /* user space pointer for oprofile */ |
55 | 59 | ||
56 | enum { SPU_STATE_RUNNABLE, SPU_STATE_SAVED } state; | 60 | enum { SPU_STATE_RUNNABLE, SPU_STATE_SAVED } state; |
57 | struct rw_semaphore state_sema; | 61 | struct mutex state_mutex; |
58 | struct semaphore run_sema; | 62 | struct semaphore run_sema; |
59 | 63 | ||
60 | struct mm_struct *owner; | 64 | struct mm_struct *owner; |
@@ -75,6 +79,14 @@ struct spu_context { | |||
75 | 79 | ||
76 | struct list_head gang_list; | 80 | struct list_head gang_list; |
77 | struct spu_gang *gang; | 81 | struct spu_gang *gang; |
82 | |||
83 | /* scheduler fields */ | ||
84 | struct list_head rq; | ||
85 | struct delayed_work sched_work; | ||
86 | unsigned long sched_flags; | ||
87 | unsigned long rt_priority; | ||
88 | int policy; | ||
89 | int prio; | ||
78 | }; | 90 | }; |
79 | 91 | ||
80 | struct spu_gang { | 92 | struct spu_gang { |
@@ -149,7 +161,7 @@ long spufs_run_spu(struct file *file, | |||
149 | struct spu_context *ctx, u32 *npc, u32 *status); | 161 | struct spu_context *ctx, u32 *npc, u32 *status); |
150 | long spufs_create(struct nameidata *nd, | 162 | long spufs_create(struct nameidata *nd, |
151 | unsigned int flags, mode_t mode); | 163 | unsigned int flags, mode_t mode); |
152 | extern struct file_operations spufs_context_fops; | 164 | extern const struct file_operations spufs_context_fops; |
153 | 165 | ||
154 | /* gang management */ | 166 | /* gang management */ |
155 | struct spu_gang *alloc_spu_gang(void); | 167 | struct spu_gang *alloc_spu_gang(void); |
@@ -159,6 +171,16 @@ void spu_gang_remove_ctx(struct spu_gang *gang, struct spu_context *ctx); | |||
159 | void spu_gang_add_ctx(struct spu_gang *gang, struct spu_context *ctx); | 171 | void spu_gang_add_ctx(struct spu_gang *gang, struct spu_context *ctx); |
160 | 172 | ||
161 | /* context management */ | 173 | /* context management */ |
174 | static inline void spu_acquire(struct spu_context *ctx) | ||
175 | { | ||
176 | mutex_lock(&ctx->state_mutex); | ||
177 | } | ||
178 | |||
179 | static inline void spu_release(struct spu_context *ctx) | ||
180 | { | ||
181 | mutex_unlock(&ctx->state_mutex); | ||
182 | } | ||
183 | |||
162 | struct spu_context * alloc_spu_context(struct spu_gang *gang); | 184 | struct spu_context * alloc_spu_context(struct spu_gang *gang); |
163 | void destroy_spu_context(struct kref *kref); | 185 | void destroy_spu_context(struct kref *kref); |
164 | struct spu_context * get_spu_context(struct spu_context *ctx); | 186 | struct spu_context * get_spu_context(struct spu_context *ctx); |
@@ -166,20 +188,18 @@ int put_spu_context(struct spu_context *ctx); | |||
166 | void spu_unmap_mappings(struct spu_context *ctx); | 188 | void spu_unmap_mappings(struct spu_context *ctx); |
167 | 189 | ||
168 | void spu_forget(struct spu_context *ctx); | 190 | void spu_forget(struct spu_context *ctx); |
169 | void spu_acquire(struct spu_context *ctx); | 191 | int spu_acquire_runnable(struct spu_context *ctx, unsigned long flags); |
170 | void spu_release(struct spu_context *ctx); | ||
171 | int spu_acquire_runnable(struct spu_context *ctx); | ||
172 | void spu_acquire_saved(struct spu_context *ctx); | 192 | void spu_acquire_saved(struct spu_context *ctx); |
173 | int spu_acquire_exclusive(struct spu_context *ctx); | 193 | int spu_acquire_exclusive(struct spu_context *ctx); |
174 | 194 | enum { | |
175 | static inline void spu_release_exclusive(struct spu_context *ctx) | 195 | SPU_ACTIVATE_NOWAKE = 1, |
176 | { | 196 | }; |
177 | up_write(&ctx->state_sema); | 197 | int spu_activate(struct spu_context *ctx, unsigned long flags); |
178 | } | ||
179 | |||
180 | int spu_activate(struct spu_context *ctx, u64 flags); | ||
181 | void spu_deactivate(struct spu_context *ctx); | 198 | void spu_deactivate(struct spu_context *ctx); |
182 | void spu_yield(struct spu_context *ctx); | 199 | void spu_yield(struct spu_context *ctx); |
200 | void spu_start_tick(struct spu_context *ctx); | ||
201 | void spu_stop_tick(struct spu_context *ctx); | ||
202 | void spu_sched_tick(struct work_struct *work); | ||
183 | int __init spu_sched_init(void); | 203 | int __init spu_sched_init(void); |
184 | void __exit spu_sched_exit(void); | 204 | void __exit spu_sched_exit(void); |
185 | 205 | ||
diff --git a/arch/powerpc/platforms/celleb/Makefile b/arch/powerpc/platforms/celleb/Makefile new file mode 100644 index 000000000000..f4f82520dc4f --- /dev/null +++ b/arch/powerpc/platforms/celleb/Makefile | |||
@@ -0,0 +1,8 @@ | |||
1 | obj-y += interrupt.o iommu.o setup.o \ | ||
2 | htab.o beat.o pci.o \ | ||
3 | scc_epci.o scc_uhc.o hvCall.o | ||
4 | |||
5 | obj-$(CONFIG_SMP) += smp.o | ||
6 | obj-$(CONFIG_PPC_UDBG_BEAT) += udbg_beat.o | ||
7 | obj-$(CONFIG_HAS_TXX9_SERIAL) += scc_sio.o | ||
8 | obj-$(CONFIG_SPU_BASE) += spu_priv1.o | ||
diff --git a/arch/powerpc/platforms/celleb/beat.c b/arch/powerpc/platforms/celleb/beat.c new file mode 100644 index 000000000000..99341ce8a697 --- /dev/null +++ b/arch/powerpc/platforms/celleb/beat.c | |||
@@ -0,0 +1,163 @@ | |||
1 | /* | ||
2 | * Simple routines for Celleb/Beat | ||
3 | * | ||
4 | * (C) Copyright 2006-2007 TOSHIBA CORPORATION | ||
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 along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | |||
21 | #include <linux/module.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/err.h> | ||
24 | #include <linux/rtc.h> | ||
25 | |||
26 | #include <asm/hvconsole.h> | ||
27 | #include <asm/time.h> | ||
28 | |||
29 | #include "beat_wrapper.h" | ||
30 | #include "beat.h" | ||
31 | |||
32 | void beat_restart(char *cmd) | ||
33 | { | ||
34 | beat_shutdown_logical_partition(1); | ||
35 | } | ||
36 | |||
37 | void beat_power_off(void) | ||
38 | { | ||
39 | beat_shutdown_logical_partition(0); | ||
40 | } | ||
41 | |||
42 | u64 beat_halt_code = 0x1000000000000000UL; | ||
43 | |||
44 | void beat_halt(void) | ||
45 | { | ||
46 | beat_shutdown_logical_partition(beat_halt_code); | ||
47 | } | ||
48 | |||
49 | int beat_set_rtc_time(struct rtc_time *rtc_time) | ||
50 | { | ||
51 | u64 tim; | ||
52 | tim = mktime(rtc_time->tm_year+1900, | ||
53 | rtc_time->tm_mon+1, rtc_time->tm_mday, | ||
54 | rtc_time->tm_hour, rtc_time->tm_min, rtc_time->tm_sec); | ||
55 | if (beat_rtc_write(tim)) | ||
56 | return -1; | ||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | void beat_get_rtc_time(struct rtc_time *rtc_time) | ||
61 | { | ||
62 | u64 tim; | ||
63 | |||
64 | if (beat_rtc_read(&tim)) | ||
65 | tim = 0; | ||
66 | to_tm(tim, rtc_time); | ||
67 | rtc_time->tm_year -= 1900; | ||
68 | rtc_time->tm_mon -= 1; | ||
69 | } | ||
70 | |||
71 | #define BEAT_NVRAM_SIZE 4096 | ||
72 | |||
73 | ssize_t beat_nvram_read(char *buf, size_t count, loff_t *index) | ||
74 | { | ||
75 | unsigned int i; | ||
76 | unsigned long len; | ||
77 | char *p = buf; | ||
78 | |||
79 | if (*index >= BEAT_NVRAM_SIZE) | ||
80 | return -ENODEV; | ||
81 | i = *index; | ||
82 | if (i + count > BEAT_NVRAM_SIZE) | ||
83 | count = BEAT_NVRAM_SIZE - i; | ||
84 | |||
85 | for (; count != 0; count -= len) { | ||
86 | len = count; | ||
87 | if (len > BEAT_NVRW_CNT) | ||
88 | len = BEAT_NVRW_CNT; | ||
89 | if (beat_eeprom_read(i, len, p)) { | ||
90 | return -EIO; | ||
91 | } | ||
92 | |||
93 | p += len; | ||
94 | i += len; | ||
95 | } | ||
96 | *index = i; | ||
97 | return p - buf; | ||
98 | } | ||
99 | |||
100 | ssize_t beat_nvram_write(char *buf, size_t count, loff_t *index) | ||
101 | { | ||
102 | unsigned int i; | ||
103 | unsigned long len; | ||
104 | char *p = buf; | ||
105 | |||
106 | if (*index >= BEAT_NVRAM_SIZE) | ||
107 | return -ENODEV; | ||
108 | i = *index; | ||
109 | if (i + count > BEAT_NVRAM_SIZE) | ||
110 | count = BEAT_NVRAM_SIZE - i; | ||
111 | |||
112 | for (; count != 0; count -= len) { | ||
113 | len = count; | ||
114 | if (len > BEAT_NVRW_CNT) | ||
115 | len = BEAT_NVRW_CNT; | ||
116 | if (beat_eeprom_write(i, len, p)) { | ||
117 | return -EIO; | ||
118 | } | ||
119 | |||
120 | p += len; | ||
121 | i += len; | ||
122 | } | ||
123 | *index = i; | ||
124 | return p - buf; | ||
125 | } | ||
126 | |||
127 | ssize_t beat_nvram_get_size(void) | ||
128 | { | ||
129 | return BEAT_NVRAM_SIZE; | ||
130 | } | ||
131 | |||
132 | int beat_set_xdabr(unsigned long dabr) | ||
133 | { | ||
134 | if (beat_set_dabr(dabr, DABRX_KERNEL | DABRX_USER)) | ||
135 | return -1; | ||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | int64_t beat_get_term_char(u64 vterm, u64 *len, u64 *t1, u64 *t2) | ||
140 | { | ||
141 | u64 db[2]; | ||
142 | s64 ret; | ||
143 | |||
144 | ret = beat_get_characters_from_console(vterm, len, (u8*)db); | ||
145 | if (ret == 0) { | ||
146 | *t1 = db[0]; | ||
147 | *t2 = db[1]; | ||
148 | } | ||
149 | return ret; | ||
150 | } | ||
151 | |||
152 | int64_t beat_put_term_char(u64 vterm, u64 len, u64 t1, u64 t2) | ||
153 | { | ||
154 | u64 db[2]; | ||
155 | |||
156 | db[0] = t1; | ||
157 | db[1] = t2; | ||
158 | return beat_put_characters_to_console(vterm, len, (u8*)db); | ||
159 | } | ||
160 | |||
161 | EXPORT_SYMBOL(beat_get_term_char); | ||
162 | EXPORT_SYMBOL(beat_put_term_char); | ||
163 | EXPORT_SYMBOL(beat_halt_code); | ||
diff --git a/arch/powerpc/platforms/celleb/beat.h b/arch/powerpc/platforms/celleb/beat.h new file mode 100644 index 000000000000..2b16bf3bee89 --- /dev/null +++ b/arch/powerpc/platforms/celleb/beat.h | |||
@@ -0,0 +1,40 @@ | |||
1 | /* | ||
2 | * Guest OS Interfaces. | ||
3 | * | ||
4 | * (C) Copyright 2006 TOSHIBA CORPORATION | ||
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 along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | |||
21 | #ifndef _CELLEB_BEAT_H | ||
22 | #define _CELLEB_BEAT_H | ||
23 | |||
24 | #define DABRX_KERNEL (1UL<<1) | ||
25 | #define DABRX_USER (1UL<<0) | ||
26 | |||
27 | int64_t beat_get_term_char(uint64_t,uint64_t*,uint64_t*,uint64_t*); | ||
28 | int64_t beat_put_term_char(uint64_t,uint64_t,uint64_t,uint64_t); | ||
29 | int64_t beat_repository_encode(int, const char *, uint64_t[4]); | ||
30 | void beat_restart(char *); | ||
31 | void beat_power_off(void); | ||
32 | void beat_halt(void); | ||
33 | int beat_set_rtc_time(struct rtc_time *); | ||
34 | void beat_get_rtc_time(struct rtc_time *); | ||
35 | ssize_t beat_nvram_get_size(void); | ||
36 | ssize_t beat_nvram_read(char *, size_t, loff_t *); | ||
37 | ssize_t beat_nvram_write(char *, size_t, loff_t *); | ||
38 | int beat_set_xdabr(unsigned long); | ||
39 | |||
40 | #endif /* _CELLEB_BEAT_H */ | ||
diff --git a/arch/powerpc/platforms/celleb/beat_syscall.h b/arch/powerpc/platforms/celleb/beat_syscall.h new file mode 100644 index 000000000000..14e16974773f --- /dev/null +++ b/arch/powerpc/platforms/celleb/beat_syscall.h | |||
@@ -0,0 +1,160 @@ | |||
1 | /* | ||
2 | * Beat hypervisor call numbers | ||
3 | * | ||
4 | * (C) Copyright 2004-2007 TOSHIBA CORPORATION | ||
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 along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | |||
21 | #ifndef BEAT_BEAT_syscall_H | ||
22 | #define BEAT_BEAT_syscall_H | ||
23 | |||
24 | #ifdef __ASSEMBLY__ | ||
25 | #define __BEAT_ADD_VENDOR_ID(__x, __v) ((__v)<<60|(__x)) | ||
26 | #else | ||
27 | #define __BEAT_ADD_VENDOR_ID(__x, __v) ((u64)(__v)<<60|(__x)) | ||
28 | #endif | ||
29 | #define HV_allocate_memory __BEAT_ADD_VENDOR_ID(0, 0) | ||
30 | #define HV_construct_virtual_address_space __BEAT_ADD_VENDOR_ID(2, 0) | ||
31 | #define HV_destruct_virtual_address_space __BEAT_ADD_VENDOR_ID(10, 0) | ||
32 | #define HV_get_virtual_address_space_id_of_ppe __BEAT_ADD_VENDOR_ID(4, 0) | ||
33 | #define HV_query_logical_partition_address_region_info \ | ||
34 | __BEAT_ADD_VENDOR_ID(6, 0) | ||
35 | #define HV_release_memory __BEAT_ADD_VENDOR_ID(13, 0) | ||
36 | #define HV_select_virtual_address_space __BEAT_ADD_VENDOR_ID(7, 0) | ||
37 | #define HV_load_range_registers __BEAT_ADD_VENDOR_ID(68, 0) | ||
38 | #define HV_set_ppe_l2cache_rmt_entry __BEAT_ADD_VENDOR_ID(70, 0) | ||
39 | #define HV_set_ppe_tlb_rmt_entry __BEAT_ADD_VENDOR_ID(71, 0) | ||
40 | #define HV_set_spe_tlb_rmt_entry __BEAT_ADD_VENDOR_ID(72, 0) | ||
41 | #define HV_get_io_address_translation_fault_info __BEAT_ADD_VENDOR_ID(14, 0) | ||
42 | #define HV_get_iopte __BEAT_ADD_VENDOR_ID(16, 0) | ||
43 | #define HV_preload_iopt_cache __BEAT_ADD_VENDOR_ID(17, 0) | ||
44 | #define HV_put_iopte __BEAT_ADD_VENDOR_ID(15, 0) | ||
45 | #define HV_connect_event_ports __BEAT_ADD_VENDOR_ID(21, 0) | ||
46 | #define HV_construct_event_receive_port __BEAT_ADD_VENDOR_ID(18, 0) | ||
47 | #define HV_destruct_event_receive_port __BEAT_ADD_VENDOR_ID(19, 0) | ||
48 | #define HV_destruct_event_send_port __BEAT_ADD_VENDOR_ID(22, 0) | ||
49 | #define HV_get_state_of_event_send_port __BEAT_ADD_VENDOR_ID(25, 0) | ||
50 | #define HV_request_to_connect_event_ports __BEAT_ADD_VENDOR_ID(20, 0) | ||
51 | #define HV_send_event_externally __BEAT_ADD_VENDOR_ID(23, 0) | ||
52 | #define HV_send_event_locally __BEAT_ADD_VENDOR_ID(24, 0) | ||
53 | #define HV_construct_and_connect_irq_plug __BEAT_ADD_VENDOR_ID(28, 0) | ||
54 | #define HV_destruct_irq_plug __BEAT_ADD_VENDOR_ID(29, 0) | ||
55 | #define HV_detect_pending_interrupts __BEAT_ADD_VENDOR_ID(26, 0) | ||
56 | #define HV_end_of_interrupt __BEAT_ADD_VENDOR_ID(27, 0) | ||
57 | #define HV_assign_control_signal_notification_port __BEAT_ADD_VENDOR_ID(45, 0) | ||
58 | #define HV_end_of_control_signal_processing __BEAT_ADD_VENDOR_ID(48, 0) | ||
59 | #define HV_get_control_signal __BEAT_ADD_VENDOR_ID(46, 0) | ||
60 | #define HV_set_irq_mask_for_spe __BEAT_ADD_VENDOR_ID(61, 0) | ||
61 | #define HV_shutdown_logical_partition __BEAT_ADD_VENDOR_ID(44, 0) | ||
62 | #define HV_connect_message_ports __BEAT_ADD_VENDOR_ID(35, 0) | ||
63 | #define HV_destruct_message_port __BEAT_ADD_VENDOR_ID(36, 0) | ||
64 | #define HV_receive_message __BEAT_ADD_VENDOR_ID(37, 0) | ||
65 | #define HV_get_message_port_info __BEAT_ADD_VENDOR_ID(34, 0) | ||
66 | #define HV_request_to_connect_message_ports __BEAT_ADD_VENDOR_ID(33, 0) | ||
67 | #define HV_send_message __BEAT_ADD_VENDOR_ID(32, 0) | ||
68 | #define HV_get_logical_ppe_id __BEAT_ADD_VENDOR_ID(69, 0) | ||
69 | #define HV_pause __BEAT_ADD_VENDOR_ID(9, 0) | ||
70 | #define HV_destruct_shared_memory_handle __BEAT_ADD_VENDOR_ID(51, 0) | ||
71 | #define HV_get_shared_memory_info __BEAT_ADD_VENDOR_ID(52, 0) | ||
72 | #define HV_permit_sharing_memory __BEAT_ADD_VENDOR_ID(50, 0) | ||
73 | #define HV_request_to_attach_shared_memory __BEAT_ADD_VENDOR_ID(49, 0) | ||
74 | #define HV_enable_logical_spe_execution __BEAT_ADD_VENDOR_ID(55, 0) | ||
75 | #define HV_construct_logical_spe __BEAT_ADD_VENDOR_ID(53, 0) | ||
76 | #define HV_disable_logical_spe_execution __BEAT_ADD_VENDOR_ID(56, 0) | ||
77 | #define HV_destruct_logical_spe __BEAT_ADD_VENDOR_ID(54, 0) | ||
78 | #define HV_sense_spe_execution_status __BEAT_ADD_VENDOR_ID(58, 0) | ||
79 | #define HV_insert_htab_entry __BEAT_ADD_VENDOR_ID(101, 0) | ||
80 | #define HV_read_htab_entries __BEAT_ADD_VENDOR_ID(95, 0) | ||
81 | #define HV_write_htab_entry __BEAT_ADD_VENDOR_ID(94, 0) | ||
82 | #define HV_assign_io_address_translation_fault_port \ | ||
83 | __BEAT_ADD_VENDOR_ID(100, 0) | ||
84 | #define HV_set_interrupt_mask __BEAT_ADD_VENDOR_ID(73, 0) | ||
85 | #define HV_get_logical_partition_id __BEAT_ADD_VENDOR_ID(74, 0) | ||
86 | #define HV_create_repository_node2 __BEAT_ADD_VENDOR_ID(90, 0) | ||
87 | #define HV_create_repository_node __BEAT_ADD_VENDOR_ID(90, 0) /* alias */ | ||
88 | #define HV_get_repository_node_value2 __BEAT_ADD_VENDOR_ID(91, 0) | ||
89 | #define HV_get_repository_node_value __BEAT_ADD_VENDOR_ID(91, 0) /* alias */ | ||
90 | #define HV_modify_repository_node_value2 __BEAT_ADD_VENDOR_ID(92, 0) | ||
91 | #define HV_modify_repository_node_value __BEAT_ADD_VENDOR_ID(92, 0) /* alias */ | ||
92 | #define HV_remove_repository_node2 __BEAT_ADD_VENDOR_ID(93, 0) | ||
93 | #define HV_remove_repository_node __BEAT_ADD_VENDOR_ID(93, 0) /* alias */ | ||
94 | #define HV_cancel_shared_memory __BEAT_ADD_VENDOR_ID(104, 0) | ||
95 | #define HV_clear_interrupt_status_of_spe __BEAT_ADD_VENDOR_ID(206, 0) | ||
96 | #define HV_construct_spe_irq_outlet __BEAT_ADD_VENDOR_ID(80, 0) | ||
97 | #define HV_destruct_spe_irq_outlet __BEAT_ADD_VENDOR_ID(81, 0) | ||
98 | #define HV_disconnect_ipspc_service __BEAT_ADD_VENDOR_ID(88, 0) | ||
99 | #define HV_execute_ipspc_command __BEAT_ADD_VENDOR_ID(86, 0) | ||
100 | #define HV_get_interrupt_status_of_spe __BEAT_ADD_VENDOR_ID(205, 0) | ||
101 | #define HV_get_spe_privileged_state_1_registers __BEAT_ADD_VENDOR_ID(208, 0) | ||
102 | #define HV_permit_use_of_ipspc_service __BEAT_ADD_VENDOR_ID(85, 0) | ||
103 | #define HV_reinitialize_logical_spe __BEAT_ADD_VENDOR_ID(82, 0) | ||
104 | #define HV_request_ipspc_service __BEAT_ADD_VENDOR_ID(84, 0) | ||
105 | #define HV_stop_ipspc_command __BEAT_ADD_VENDOR_ID(87, 0) | ||
106 | #define HV_set_spe_privileged_state_1_registers __BEAT_ADD_VENDOR_ID(204, 0) | ||
107 | #define HV_get_status_of_ipspc_service __BEAT_ADD_VENDOR_ID(203, 0) | ||
108 | #define HV_put_characters_to_console __BEAT_ADD_VENDOR_ID(0x101, 1) | ||
109 | #define HV_get_characters_from_console __BEAT_ADD_VENDOR_ID(0x102, 1) | ||
110 | #define HV_get_base_clock __BEAT_ADD_VENDOR_ID(0x111, 1) | ||
111 | #define HV_set_base_clock __BEAT_ADD_VENDOR_ID(0x112, 1) | ||
112 | #define HV_get_frame_cycle __BEAT_ADD_VENDOR_ID(0x114, 1) | ||
113 | #define HV_disable_console __BEAT_ADD_VENDOR_ID(0x115, 1) | ||
114 | #define HV_disable_all_console __BEAT_ADD_VENDOR_ID(0x116, 1) | ||
115 | #define HV_oneshot_timer __BEAT_ADD_VENDOR_ID(0x117, 1) | ||
116 | #define HV_set_dabr __BEAT_ADD_VENDOR_ID(0x118, 1) | ||
117 | #define HV_get_dabr __BEAT_ADD_VENDOR_ID(0x119, 1) | ||
118 | #define HV_start_hv_stats __BEAT_ADD_VENDOR_ID(0x21c, 1) | ||
119 | #define HV_stop_hv_stats __BEAT_ADD_VENDOR_ID(0x21d, 1) | ||
120 | #define HV_get_hv_stats __BEAT_ADD_VENDOR_ID(0x21e, 1) | ||
121 | #define HV_get_hv_error_stats __BEAT_ADD_VENDOR_ID(0x221, 1) | ||
122 | #define HV_get_stats __BEAT_ADD_VENDOR_ID(0x224, 1) | ||
123 | #define HV_get_heap_stats __BEAT_ADD_VENDOR_ID(0x225, 1) | ||
124 | #define HV_get_memory_stats __BEAT_ADD_VENDOR_ID(0x227, 1) | ||
125 | #define HV_get_memory_detail __BEAT_ADD_VENDOR_ID(0x228, 1) | ||
126 | #define HV_set_priority_of_irq_outlet __BEAT_ADD_VENDOR_ID(0x122, 1) | ||
127 | #define HV_get_physical_spe_by_reservation_id __BEAT_ADD_VENDOR_ID(0x128, 1) | ||
128 | #define HV_get_spe_context __BEAT_ADD_VENDOR_ID(0x129, 1) | ||
129 | #define HV_set_spe_context __BEAT_ADD_VENDOR_ID(0x12a, 1) | ||
130 | #define HV_downcount_of_interrupt __BEAT_ADD_VENDOR_ID(0x12e, 1) | ||
131 | #define HV_peek_spe_context __BEAT_ADD_VENDOR_ID(0x12f, 1) | ||
132 | #define HV_read_bpa_register __BEAT_ADD_VENDOR_ID(0x131, 1) | ||
133 | #define HV_write_bpa_register __BEAT_ADD_VENDOR_ID(0x132, 1) | ||
134 | #define HV_map_context_table_of_spe __BEAT_ADD_VENDOR_ID(0x137, 1) | ||
135 | #define HV_get_slb_for_logical_spe __BEAT_ADD_VENDOR_ID(0x138, 1) | ||
136 | #define HV_set_slb_for_logical_spe __BEAT_ADD_VENDOR_ID(0x139, 1) | ||
137 | #define HV_init_pm __BEAT_ADD_VENDOR_ID(0x150, 1) | ||
138 | #define HV_set_pm_signal __BEAT_ADD_VENDOR_ID(0x151, 1) | ||
139 | #define HV_get_pm_signal __BEAT_ADD_VENDOR_ID(0x152, 1) | ||
140 | #define HV_set_pm_config __BEAT_ADD_VENDOR_ID(0x153, 1) | ||
141 | #define HV_get_pm_config __BEAT_ADD_VENDOR_ID(0x154, 1) | ||
142 | #define HV_get_inner_trace_data __BEAT_ADD_VENDOR_ID(0x155, 1) | ||
143 | #define HV_set_ext_trace_buffer __BEAT_ADD_VENDOR_ID(0x156, 1) | ||
144 | #define HV_get_ext_trace_buffer __BEAT_ADD_VENDOR_ID(0x157, 1) | ||
145 | #define HV_set_pm_interrupt __BEAT_ADD_VENDOR_ID(0x158, 1) | ||
146 | #define HV_get_pm_interrupt __BEAT_ADD_VENDOR_ID(0x159, 1) | ||
147 | #define HV_kick_pm __BEAT_ADD_VENDOR_ID(0x160, 1) | ||
148 | #define HV_construct_pm_context __BEAT_ADD_VENDOR_ID(0x164, 1) | ||
149 | #define HV_destruct_pm_context __BEAT_ADD_VENDOR_ID(0x165, 1) | ||
150 | #define HV_be_slow __BEAT_ADD_VENDOR_ID(0x170, 1) | ||
151 | #define HV_assign_ipspc_server_connection_status_notification_port \ | ||
152 | __BEAT_ADD_VENDOR_ID(0x173, 1) | ||
153 | #define HV_get_raid_of_physical_spe __BEAT_ADD_VENDOR_ID(0x174, 1) | ||
154 | #define HV_set_physical_spe_to_rag __BEAT_ADD_VENDOR_ID(0x175, 1) | ||
155 | #define HV_release_physical_spe_from_rag __BEAT_ADD_VENDOR_ID(0x176, 1) | ||
156 | #define HV_rtc_read __BEAT_ADD_VENDOR_ID(0x190, 1) | ||
157 | #define HV_rtc_write __BEAT_ADD_VENDOR_ID(0x191, 1) | ||
158 | #define HV_eeprom_read __BEAT_ADD_VENDOR_ID(0x192, 1) | ||
159 | #define HV_eeprom_write __BEAT_ADD_VENDOR_ID(0x193, 1) | ||
160 | #endif | ||
diff --git a/arch/powerpc/platforms/celleb/beat_wrapper.h b/arch/powerpc/platforms/celleb/beat_wrapper.h new file mode 100644 index 000000000000..76ea0a6a9011 --- /dev/null +++ b/arch/powerpc/platforms/celleb/beat_wrapper.h | |||
@@ -0,0 +1,220 @@ | |||
1 | /* | ||
2 | * Beat hypervisor call I/F | ||
3 | * | ||
4 | * (C) Copyright 2007 TOSHIBA CORPORATION | ||
5 | * | ||
6 | * This code is based on arch/powerpc/platforms/pseries/plpar_wrapper.h. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along | ||
19 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
20 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
21 | */ | ||
22 | #ifndef BEAT_HCALL | ||
23 | #include "beat_syscall.h" | ||
24 | |||
25 | /* defined in hvCall.S */ | ||
26 | extern s64 beat_hcall_norets(u64 opcode, ...); | ||
27 | extern s64 beat_hcall_norets8(u64 opcode, u64 arg1, u64 arg2, u64 arg3, | ||
28 | u64 arg4, u64 arg5, u64 arg6, u64 arg7, u64 arg8); | ||
29 | extern s64 beat_hcall1(u64 opcode, u64 retbuf[1], ...); | ||
30 | extern s64 beat_hcall2(u64 opcode, u64 retbuf[2], ...); | ||
31 | extern s64 beat_hcall3(u64 opcode, u64 retbuf[3], ...); | ||
32 | extern s64 beat_hcall4(u64 opcode, u64 retbuf[4], ...); | ||
33 | extern s64 beat_hcall5(u64 opcode, u64 retbuf[5], ...); | ||
34 | extern s64 beat_hcall6(u64 opcode, u64 retbuf[6], ...); | ||
35 | |||
36 | static inline s64 beat_downcount_of_interrupt(u64 plug_id) | ||
37 | { | ||
38 | return beat_hcall_norets(HV_downcount_of_interrupt, plug_id); | ||
39 | } | ||
40 | |||
41 | static inline s64 beat_set_interrupt_mask(u64 index, | ||
42 | u64 val0, u64 val1, u64 val2, u64 val3) | ||
43 | { | ||
44 | return beat_hcall_norets(HV_set_interrupt_mask, index, | ||
45 | val0, val1, val2, val3); | ||
46 | } | ||
47 | |||
48 | static inline s64 beat_destruct_irq_plug(u64 plug_id) | ||
49 | { | ||
50 | return beat_hcall_norets(HV_destruct_irq_plug, plug_id); | ||
51 | } | ||
52 | |||
53 | static inline s64 beat_construct_and_connect_irq_plug(u64 plug_id, | ||
54 | u64 outlet_id) | ||
55 | { | ||
56 | return beat_hcall_norets(HV_construct_and_connect_irq_plug, plug_id, | ||
57 | outlet_id); | ||
58 | } | ||
59 | |||
60 | static inline s64 beat_detect_pending_interrupts(u64 index, u64 *retbuf) | ||
61 | { | ||
62 | return beat_hcall4(HV_detect_pending_interrupts, retbuf, index); | ||
63 | } | ||
64 | |||
65 | static inline s64 beat_pause(u64 style) | ||
66 | { | ||
67 | return beat_hcall_norets(HV_pause, style); | ||
68 | } | ||
69 | |||
70 | static inline s64 beat_read_htab_entries(u64 htab_id, u64 index, u64 *retbuf) | ||
71 | { | ||
72 | return beat_hcall5(HV_read_htab_entries, retbuf, htab_id, index); | ||
73 | } | ||
74 | |||
75 | static inline s64 beat_insert_htab_entry(u64 htab_id, u64 group, | ||
76 | u64 bitmask, u64 hpte_v, u64 hpte_r, u64 *slot) | ||
77 | { | ||
78 | u64 dummy[3]; | ||
79 | s64 ret; | ||
80 | |||
81 | ret = beat_hcall3(HV_insert_htab_entry, dummy, htab_id, group, | ||
82 | bitmask, hpte_v, hpte_r); | ||
83 | *slot = dummy[0]; | ||
84 | return ret; | ||
85 | } | ||
86 | |||
87 | static inline s64 beat_write_htab_entry(u64 htab_id, u64 slot, | ||
88 | u64 hpte_v, u64 hpte_r, u64 mask_v, u64 mask_r, | ||
89 | u64 *ret_v, u64 *ret_r) | ||
90 | { | ||
91 | u64 dummy[2]; | ||
92 | s64 ret; | ||
93 | |||
94 | ret = beat_hcall2(HV_write_htab_entry, dummy, htab_id, slot, | ||
95 | hpte_v, hpte_r, mask_v, mask_r); | ||
96 | *ret_v = dummy[0]; | ||
97 | *ret_r = dummy[1]; | ||
98 | return ret; | ||
99 | } | ||
100 | |||
101 | static inline void beat_shutdown_logical_partition(u64 code) | ||
102 | { | ||
103 | (void)beat_hcall_norets(HV_shutdown_logical_partition, code); | ||
104 | } | ||
105 | |||
106 | static inline s64 beat_rtc_write(u64 time_from_epoch) | ||
107 | { | ||
108 | return beat_hcall_norets(HV_rtc_write, time_from_epoch); | ||
109 | } | ||
110 | |||
111 | static inline s64 beat_rtc_read(u64 *time_from_epoch) | ||
112 | { | ||
113 | u64 dummy[1]; | ||
114 | s64 ret; | ||
115 | |||
116 | ret = beat_hcall1(HV_rtc_read, dummy); | ||
117 | *time_from_epoch = dummy[0]; | ||
118 | return ret; | ||
119 | } | ||
120 | |||
121 | #define BEAT_NVRW_CNT (sizeof(u64) * 6) | ||
122 | |||
123 | static inline s64 beat_eeprom_write(u64 index, u64 length, u8 *buffer) | ||
124 | { | ||
125 | u64 b[6]; | ||
126 | |||
127 | if (length > BEAT_NVRW_CNT) | ||
128 | return -1; | ||
129 | memcpy(b, buffer, sizeof(b)); | ||
130 | return beat_hcall_norets8(HV_eeprom_write, index, length, | ||
131 | b[0], b[1], b[2], b[3], b[4], b[5]); | ||
132 | } | ||
133 | |||
134 | static inline s64 beat_eeprom_read(u64 index, u64 length, u8 *buffer) | ||
135 | { | ||
136 | u64 b[6]; | ||
137 | s64 ret; | ||
138 | |||
139 | if (length > BEAT_NVRW_CNT) | ||
140 | return -1; | ||
141 | ret = beat_hcall6(HV_eeprom_read, b, index, length); | ||
142 | memcpy(buffer, b, length); | ||
143 | return ret; | ||
144 | } | ||
145 | |||
146 | static inline s64 beat_set_dabr(u64 value, u64 style) | ||
147 | { | ||
148 | return beat_hcall_norets(HV_set_dabr, value, style); | ||
149 | } | ||
150 | |||
151 | static inline s64 beat_get_characters_from_console(u64 termno, u64 *len, | ||
152 | u8 *buffer) | ||
153 | { | ||
154 | u64 dummy[3]; | ||
155 | s64 ret; | ||
156 | |||
157 | ret = beat_hcall3(HV_get_characters_from_console, dummy, termno, len); | ||
158 | *len = dummy[0]; | ||
159 | memcpy(buffer, dummy + 1, *len); | ||
160 | return ret; | ||
161 | } | ||
162 | |||
163 | static inline s64 beat_put_characters_to_console(u64 termno, u64 len, | ||
164 | u8 *buffer) | ||
165 | { | ||
166 | u64 b[2]; | ||
167 | |||
168 | memcpy(b, buffer, len); | ||
169 | return beat_hcall_norets(HV_put_characters_to_console, termno, len, b[0], b[1]); | ||
170 | } | ||
171 | |||
172 | static inline s64 beat_get_spe_privileged_state_1_registers( | ||
173 | u64 id, u64 offsetof, u64 *value) | ||
174 | { | ||
175 | u64 dummy[1]; | ||
176 | s64 ret; | ||
177 | |||
178 | ret = beat_hcall1(HV_get_spe_privileged_state_1_registers, dummy, id, | ||
179 | offsetof); | ||
180 | *value = dummy[0]; | ||
181 | return ret; | ||
182 | } | ||
183 | |||
184 | static inline s64 beat_set_irq_mask_for_spe(u64 id, u64 class, u64 mask) | ||
185 | { | ||
186 | return beat_hcall_norets(HV_set_irq_mask_for_spe, id, class, mask); | ||
187 | } | ||
188 | |||
189 | static inline s64 beat_clear_interrupt_status_of_spe(u64 id, u64 class, | ||
190 | u64 mask) | ||
191 | { | ||
192 | return beat_hcall_norets(HV_clear_interrupt_status_of_spe, | ||
193 | id, class, mask); | ||
194 | } | ||
195 | |||
196 | static inline s64 beat_set_spe_privileged_state_1_registers( | ||
197 | u64 id, u64 offsetof, u64 value) | ||
198 | { | ||
199 | return beat_hcall_norets(HV_set_spe_privileged_state_1_registers, | ||
200 | id, offsetof, value); | ||
201 | } | ||
202 | |||
203 | static inline s64 beat_get_interrupt_status_of_spe(u64 id, u64 class, u64 *val) | ||
204 | { | ||
205 | u64 dummy[1]; | ||
206 | s64 ret; | ||
207 | |||
208 | ret = beat_hcall1(HV_get_interrupt_status_of_spe, dummy, id, class); | ||
209 | *val = dummy[0]; | ||
210 | return ret; | ||
211 | } | ||
212 | |||
213 | static inline s64 beat_put_iopte(u64 ioas_id, u64 io_addr, u64 real_addr, | ||
214 | u64 ioid, u64 flags) | ||
215 | { | ||
216 | return beat_hcall_norets(HV_put_iopte, ioas_id, io_addr, real_addr, | ||
217 | ioid, flags); | ||
218 | } | ||
219 | |||
220 | #endif | ||
diff --git a/arch/powerpc/platforms/celleb/htab.c b/arch/powerpc/platforms/celleb/htab.c new file mode 100644 index 000000000000..279d7339e170 --- /dev/null +++ b/arch/powerpc/platforms/celleb/htab.c | |||
@@ -0,0 +1,308 @@ | |||
1 | /* | ||
2 | * "Cell Reference Set" HTAB support. | ||
3 | * | ||
4 | * (C) Copyright 2006-2007 TOSHIBA CORPORATION | ||
5 | * | ||
6 | * This code is based on arch/powerpc/platforms/pseries/lpar.c: | ||
7 | * Copyright (C) 2001 Todd Inglett, IBM Corporation | ||
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 of the License, or | ||
12 | * (at your option) 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 along | ||
20 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
21 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
22 | */ | ||
23 | |||
24 | #undef DEBUG_LOW | ||
25 | |||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/spinlock.h> | ||
28 | |||
29 | #include <asm/mmu.h> | ||
30 | #include <asm/page.h> | ||
31 | #include <asm/pgtable.h> | ||
32 | #include <asm/machdep.h> | ||
33 | #include <asm/udbg.h> | ||
34 | |||
35 | #include "beat_wrapper.h" | ||
36 | |||
37 | #ifdef DEBUG_LOW | ||
38 | #define DBG_LOW(fmt...) do { udbg_printf(fmt); } while(0) | ||
39 | #else | ||
40 | #define DBG_LOW(fmt...) do { } while(0) | ||
41 | #endif | ||
42 | |||
43 | static DEFINE_SPINLOCK(beat_htab_lock); | ||
44 | |||
45 | static inline unsigned int beat_read_mask(unsigned hpte_group) | ||
46 | { | ||
47 | unsigned long hpte_v[5]; | ||
48 | unsigned long rmask = 0; | ||
49 | |||
50 | beat_read_htab_entries(0, hpte_group + 0, hpte_v); | ||
51 | if (!(hpte_v[0] & HPTE_V_BOLTED)) | ||
52 | rmask |= 0x8000; | ||
53 | if (!(hpte_v[1] & HPTE_V_BOLTED)) | ||
54 | rmask |= 0x4000; | ||
55 | if (!(hpte_v[2] & HPTE_V_BOLTED)) | ||
56 | rmask |= 0x2000; | ||
57 | if (!(hpte_v[3] & HPTE_V_BOLTED)) | ||
58 | rmask |= 0x1000; | ||
59 | beat_read_htab_entries(0, hpte_group + 4, hpte_v); | ||
60 | if (!(hpte_v[0] & HPTE_V_BOLTED)) | ||
61 | rmask |= 0x0800; | ||
62 | if (!(hpte_v[1] & HPTE_V_BOLTED)) | ||
63 | rmask |= 0x0400; | ||
64 | if (!(hpte_v[2] & HPTE_V_BOLTED)) | ||
65 | rmask |= 0x0200; | ||
66 | if (!(hpte_v[3] & HPTE_V_BOLTED)) | ||
67 | rmask |= 0x0100; | ||
68 | hpte_group = ~hpte_group & (htab_hash_mask * HPTES_PER_GROUP); | ||
69 | beat_read_htab_entries(0, hpte_group + 0, hpte_v); | ||
70 | if (!(hpte_v[0] & HPTE_V_BOLTED)) | ||
71 | rmask |= 0x80; | ||
72 | if (!(hpte_v[1] & HPTE_V_BOLTED)) | ||
73 | rmask |= 0x40; | ||
74 | if (!(hpte_v[2] & HPTE_V_BOLTED)) | ||
75 | rmask |= 0x20; | ||
76 | if (!(hpte_v[3] & HPTE_V_BOLTED)) | ||
77 | rmask |= 0x10; | ||
78 | beat_read_htab_entries(0, hpte_group + 4, hpte_v); | ||
79 | if (!(hpte_v[0] & HPTE_V_BOLTED)) | ||
80 | rmask |= 0x08; | ||
81 | if (!(hpte_v[1] & HPTE_V_BOLTED)) | ||
82 | rmask |= 0x04; | ||
83 | if (!(hpte_v[2] & HPTE_V_BOLTED)) | ||
84 | rmask |= 0x02; | ||
85 | if (!(hpte_v[3] & HPTE_V_BOLTED)) | ||
86 | rmask |= 0x01; | ||
87 | return rmask; | ||
88 | } | ||
89 | |||
90 | static long beat_lpar_hpte_insert(unsigned long hpte_group, | ||
91 | unsigned long va, unsigned long pa, | ||
92 | unsigned long rflags, unsigned long vflags, | ||
93 | int psize) | ||
94 | { | ||
95 | unsigned long lpar_rc; | ||
96 | unsigned long slot; | ||
97 | unsigned long hpte_v, hpte_r; | ||
98 | |||
99 | /* same as iseries */ | ||
100 | if (vflags & HPTE_V_SECONDARY) | ||
101 | return -1; | ||
102 | |||
103 | if (!(vflags & HPTE_V_BOLTED)) | ||
104 | DBG_LOW("hpte_insert(group=%lx, va=%016lx, pa=%016lx, " | ||
105 | "rflags=%lx, vflags=%lx, psize=%d)\n", | ||
106 | hpte_group, va, pa, rflags, vflags, psize); | ||
107 | |||
108 | hpte_v = hpte_encode_v(va, psize) | vflags | HPTE_V_VALID; | ||
109 | hpte_r = hpte_encode_r(pa, psize) | rflags; | ||
110 | |||
111 | if (!(vflags & HPTE_V_BOLTED)) | ||
112 | DBG_LOW(" hpte_v=%016lx, hpte_r=%016lx\n", hpte_v, hpte_r); | ||
113 | |||
114 | if (rflags & (_PAGE_GUARDED|_PAGE_NO_CACHE)) | ||
115 | hpte_r &= ~_PAGE_COHERENT; | ||
116 | |||
117 | spin_lock(&beat_htab_lock); | ||
118 | if ((lpar_rc = beat_read_mask(hpte_group)) == 0) { | ||
119 | if (!(vflags & HPTE_V_BOLTED)) | ||
120 | DBG_LOW(" full\n"); | ||
121 | spin_unlock(&beat_htab_lock); | ||
122 | return -1; | ||
123 | } | ||
124 | |||
125 | lpar_rc = beat_insert_htab_entry(0, hpte_group, lpar_rc << 48, | ||
126 | hpte_v, hpte_r, &slot); | ||
127 | spin_unlock(&beat_htab_lock); | ||
128 | |||
129 | /* | ||
130 | * Since we try and ioremap PHBs we don't own, the pte insert | ||
131 | * will fail. However we must catch the failure in hash_page | ||
132 | * or we will loop forever, so return -2 in this case. | ||
133 | */ | ||
134 | if (unlikely(lpar_rc != 0)) { | ||
135 | if (!(vflags & HPTE_V_BOLTED)) | ||
136 | DBG_LOW(" lpar err %lx\n", lpar_rc); | ||
137 | return -2; | ||
138 | } | ||
139 | if (!(vflags & HPTE_V_BOLTED)) | ||
140 | DBG_LOW(" -> slot: %lx\n", slot); | ||
141 | |||
142 | /* We have to pass down the secondary bucket bit here as well */ | ||
143 | return (slot ^ hpte_group) & 15; | ||
144 | } | ||
145 | |||
146 | static long beat_lpar_hpte_remove(unsigned long hpte_group) | ||
147 | { | ||
148 | DBG_LOW("hpte_remove(group=%lx)\n", hpte_group); | ||
149 | return -1; | ||
150 | } | ||
151 | |||
152 | static unsigned long beat_lpar_hpte_getword0(unsigned long slot) | ||
153 | { | ||
154 | unsigned long dword0, dword[5]; | ||
155 | unsigned long lpar_rc; | ||
156 | |||
157 | lpar_rc = beat_read_htab_entries(0, slot & ~3UL, dword); | ||
158 | |||
159 | dword0 = dword[slot&3]; | ||
160 | |||
161 | BUG_ON(lpar_rc != 0); | ||
162 | |||
163 | return dword0; | ||
164 | } | ||
165 | |||
166 | static void beat_lpar_hptab_clear(void) | ||
167 | { | ||
168 | unsigned long size_bytes = 1UL << ppc64_pft_size; | ||
169 | unsigned long hpte_count = size_bytes >> 4; | ||
170 | int i; | ||
171 | unsigned long dummy0, dummy1; | ||
172 | |||
173 | /* TODO: Use bulk call */ | ||
174 | for (i = 0; i < hpte_count; i++) | ||
175 | beat_write_htab_entry(0, i, 0, 0, -1UL, -1UL, &dummy0, &dummy1); | ||
176 | } | ||
177 | |||
178 | /* | ||
179 | * NOTE: for updatepp ops we are fortunate that the linux "newpp" bits and | ||
180 | * the low 3 bits of flags happen to line up. So no transform is needed. | ||
181 | * We can probably optimize here and assume the high bits of newpp are | ||
182 | * already zero. For now I am paranoid. | ||
183 | */ | ||
184 | static long beat_lpar_hpte_updatepp(unsigned long slot, | ||
185 | unsigned long newpp, | ||
186 | unsigned long va, | ||
187 | int psize, int local) | ||
188 | { | ||
189 | unsigned long lpar_rc; | ||
190 | unsigned long dummy0, dummy1, want_v; | ||
191 | |||
192 | want_v = hpte_encode_v(va, psize); | ||
193 | |||
194 | DBG_LOW(" update: " | ||
195 | "avpnv=%016lx, slot=%016lx, psize: %d, newpp %016lx ... ", | ||
196 | want_v & HPTE_V_AVPN, slot, psize, newpp); | ||
197 | |||
198 | spin_lock(&beat_htab_lock); | ||
199 | dummy0 = beat_lpar_hpte_getword0(slot); | ||
200 | if ((dummy0 & ~0x7FUL) != (want_v & ~0x7FUL)) { | ||
201 | DBG_LOW("not found !\n"); | ||
202 | spin_unlock(&beat_htab_lock); | ||
203 | return -1; | ||
204 | } | ||
205 | |||
206 | lpar_rc = beat_write_htab_entry(0, slot, 0, newpp, 0, 7, &dummy0, | ||
207 | &dummy1); | ||
208 | spin_unlock(&beat_htab_lock); | ||
209 | if (lpar_rc != 0 || dummy0 == 0) { | ||
210 | DBG_LOW("not found !\n"); | ||
211 | return -1; | ||
212 | } | ||
213 | |||
214 | DBG_LOW("ok %lx %lx\n", dummy0, dummy1); | ||
215 | |||
216 | BUG_ON(lpar_rc != 0); | ||
217 | |||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | static long beat_lpar_hpte_find(unsigned long va, int psize) | ||
222 | { | ||
223 | unsigned long hash; | ||
224 | unsigned long i, j; | ||
225 | long slot; | ||
226 | unsigned long want_v, hpte_v; | ||
227 | |||
228 | hash = hpt_hash(va, mmu_psize_defs[psize].shift); | ||
229 | want_v = hpte_encode_v(va, psize); | ||
230 | |||
231 | for (j = 0; j < 2; j++) { | ||
232 | slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; | ||
233 | for (i = 0; i < HPTES_PER_GROUP; i++) { | ||
234 | hpte_v = beat_lpar_hpte_getword0(slot); | ||
235 | |||
236 | if (HPTE_V_COMPARE(hpte_v, want_v) | ||
237 | && (hpte_v & HPTE_V_VALID) | ||
238 | && (!!(hpte_v & HPTE_V_SECONDARY) == j)) { | ||
239 | /* HPTE matches */ | ||
240 | if (j) | ||
241 | slot = -slot; | ||
242 | return slot; | ||
243 | } | ||
244 | ++slot; | ||
245 | } | ||
246 | hash = ~hash; | ||
247 | } | ||
248 | |||
249 | return -1; | ||
250 | } | ||
251 | |||
252 | static void beat_lpar_hpte_updateboltedpp(unsigned long newpp, | ||
253 | unsigned long ea, | ||
254 | int psize) | ||
255 | { | ||
256 | unsigned long lpar_rc, slot, vsid, va, dummy0, dummy1; | ||
257 | |||
258 | vsid = get_kernel_vsid(ea); | ||
259 | va = (vsid << 28) | (ea & 0x0fffffff); | ||
260 | |||
261 | spin_lock(&beat_htab_lock); | ||
262 | slot = beat_lpar_hpte_find(va, psize); | ||
263 | BUG_ON(slot == -1); | ||
264 | |||
265 | lpar_rc = beat_write_htab_entry(0, slot, 0, newpp, 0, 7, | ||
266 | &dummy0, &dummy1); | ||
267 | spin_unlock(&beat_htab_lock); | ||
268 | |||
269 | BUG_ON(lpar_rc != 0); | ||
270 | } | ||
271 | |||
272 | static void beat_lpar_hpte_invalidate(unsigned long slot, unsigned long va, | ||
273 | int psize, int local) | ||
274 | { | ||
275 | unsigned long want_v; | ||
276 | unsigned long lpar_rc; | ||
277 | unsigned long dummy1, dummy2; | ||
278 | unsigned long flags; | ||
279 | |||
280 | DBG_LOW(" inval : slot=%lx, va=%016lx, psize: %d, local: %d\n", | ||
281 | slot, va, psize, local); | ||
282 | want_v = hpte_encode_v(va, psize); | ||
283 | |||
284 | spin_lock_irqsave(&beat_htab_lock, flags); | ||
285 | dummy1 = beat_lpar_hpte_getword0(slot); | ||
286 | |||
287 | if ((dummy1 & ~0x7FUL) != (want_v & ~0x7FUL)) { | ||
288 | DBG_LOW("not found !\n"); | ||
289 | spin_unlock_irqrestore(&beat_htab_lock, flags); | ||
290 | return; | ||
291 | } | ||
292 | |||
293 | lpar_rc = beat_write_htab_entry(0, slot, 0, 0, HPTE_V_VALID, 0, | ||
294 | &dummy1, &dummy2); | ||
295 | spin_unlock_irqrestore(&beat_htab_lock, flags); | ||
296 | |||
297 | BUG_ON(lpar_rc != 0); | ||
298 | } | ||
299 | |||
300 | void __init hpte_init_beat(void) | ||
301 | { | ||
302 | ppc_md.hpte_invalidate = beat_lpar_hpte_invalidate; | ||
303 | ppc_md.hpte_updatepp = beat_lpar_hpte_updatepp; | ||
304 | ppc_md.hpte_updateboltedpp = beat_lpar_hpte_updateboltedpp; | ||
305 | ppc_md.hpte_insert = beat_lpar_hpte_insert; | ||
306 | ppc_md.hpte_remove = beat_lpar_hpte_remove; | ||
307 | ppc_md.hpte_clear_all = beat_lpar_hptab_clear; | ||
308 | } | ||
diff --git a/arch/powerpc/platforms/celleb/hvCall.S b/arch/powerpc/platforms/celleb/hvCall.S new file mode 100644 index 000000000000..74c817448948 --- /dev/null +++ b/arch/powerpc/platforms/celleb/hvCall.S | |||
@@ -0,0 +1,287 @@ | |||
1 | /* | ||
2 | * Beat hypervisor call I/F | ||
3 | * | ||
4 | * (C) Copyright 2007 TOSHIBA CORPORATION | ||
5 | * | ||
6 | * This code is based on arch/powerpc/platforms/pseries/hvCall.S. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along | ||
19 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
20 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
21 | */ | ||
22 | |||
23 | #include <asm/ppc_asm.h> | ||
24 | |||
25 | #define STK_PARM(i) (48 + ((i)-3)*8) | ||
26 | |||
27 | /* Not implemented on Beat, now */ | ||
28 | #define HCALL_INST_PRECALL | ||
29 | #define HCALL_INST_POSTCALL | ||
30 | |||
31 | .text | ||
32 | |||
33 | #define HVSC .long 0x44000022 | ||
34 | |||
35 | /* Note: takes only 7 input parameters at maximum */ | ||
36 | _GLOBAL(beat_hcall_norets) | ||
37 | HMT_MEDIUM | ||
38 | |||
39 | mfcr r0 | ||
40 | stw r0,8(r1) | ||
41 | |||
42 | HCALL_INST_PRECALL | ||
43 | |||
44 | mr r11,r3 | ||
45 | mr r3,r4 | ||
46 | mr r4,r5 | ||
47 | mr r5,r6 | ||
48 | mr r6,r7 | ||
49 | mr r7,r8 | ||
50 | mr r8,r9 | ||
51 | |||
52 | HVSC /* invoke the hypervisor */ | ||
53 | |||
54 | HCALL_INST_POSTCALL | ||
55 | |||
56 | lwz r0,8(r1) | ||
57 | mtcrf 0xff,r0 | ||
58 | |||
59 | blr /* return r3 = status */ | ||
60 | |||
61 | /* Note: takes 8 input parameters at maximum */ | ||
62 | _GLOBAL(beat_hcall_norets8) | ||
63 | HMT_MEDIUM | ||
64 | |||
65 | mfcr r0 | ||
66 | stw r0,8(r1) | ||
67 | |||
68 | HCALL_INST_PRECALL | ||
69 | |||
70 | mr r11,r3 | ||
71 | mr r3,r4 | ||
72 | mr r4,r5 | ||
73 | mr r5,r6 | ||
74 | mr r6,r7 | ||
75 | mr r7,r8 | ||
76 | mr r8,r9 | ||
77 | ld r10,STK_PARM(r10)(r1) | ||
78 | |||
79 | HVSC /* invoke the hypervisor */ | ||
80 | |||
81 | HCALL_INST_POSTCALL | ||
82 | |||
83 | lwz r0,8(r1) | ||
84 | mtcrf 0xff,r0 | ||
85 | |||
86 | blr /* return r3 = status */ | ||
87 | |||
88 | /* Note: takes only 6 input parameters, 1 output parameters at maximum */ | ||
89 | _GLOBAL(beat_hcall1) | ||
90 | HMT_MEDIUM | ||
91 | |||
92 | mfcr r0 | ||
93 | stw r0,8(r1) | ||
94 | |||
95 | HCALL_INST_PRECALL | ||
96 | |||
97 | std r4,STK_PARM(r4)(r1) /* save ret buffer */ | ||
98 | |||
99 | mr r11,r3 | ||
100 | mr r3,r5 | ||
101 | mr r4,r6 | ||
102 | mr r5,r7 | ||
103 | mr r6,r8 | ||
104 | mr r7,r9 | ||
105 | mr r8,r10 | ||
106 | |||
107 | HVSC /* invoke the hypervisor */ | ||
108 | |||
109 | HCALL_INST_POSTCALL | ||
110 | |||
111 | ld r12,STK_PARM(r4)(r1) | ||
112 | std r4, 0(r12) | ||
113 | |||
114 | lwz r0,8(r1) | ||
115 | mtcrf 0xff,r0 | ||
116 | |||
117 | blr /* return r3 = status */ | ||
118 | |||
119 | /* Note: takes only 6 input parameters, 2 output parameters at maximum */ | ||
120 | _GLOBAL(beat_hcall2) | ||
121 | HMT_MEDIUM | ||
122 | |||
123 | mfcr r0 | ||
124 | stw r0,8(r1) | ||
125 | |||
126 | HCALL_INST_PRECALL | ||
127 | |||
128 | std r4,STK_PARM(r4)(r1) /* save ret buffer */ | ||
129 | |||
130 | mr r11,r3 | ||
131 | mr r3,r5 | ||
132 | mr r4,r6 | ||
133 | mr r5,r7 | ||
134 | mr r6,r8 | ||
135 | mr r7,r9 | ||
136 | mr r8,r10 | ||
137 | |||
138 | HVSC /* invoke the hypervisor */ | ||
139 | |||
140 | HCALL_INST_POSTCALL | ||
141 | |||
142 | ld r12,STK_PARM(r4)(r1) | ||
143 | std r4, 0(r12) | ||
144 | std r5, 8(r12) | ||
145 | |||
146 | lwz r0,8(r1) | ||
147 | mtcrf 0xff,r0 | ||
148 | |||
149 | blr /* return r3 = status */ | ||
150 | |||
151 | /* Note: takes only 6 input parameters, 3 output parameters at maximum */ | ||
152 | _GLOBAL(beat_hcall3) | ||
153 | HMT_MEDIUM | ||
154 | |||
155 | mfcr r0 | ||
156 | stw r0,8(r1) | ||
157 | |||
158 | HCALL_INST_PRECALL | ||
159 | |||
160 | std r4,STK_PARM(r4)(r1) /* save ret buffer */ | ||
161 | |||
162 | mr r11,r3 | ||
163 | mr r3,r5 | ||
164 | mr r4,r6 | ||
165 | mr r5,r7 | ||
166 | mr r6,r8 | ||
167 | mr r7,r9 | ||
168 | mr r8,r10 | ||
169 | |||
170 | HVSC /* invoke the hypervisor */ | ||
171 | |||
172 | HCALL_INST_POSTCALL | ||
173 | |||
174 | ld r12,STK_PARM(r4)(r1) | ||
175 | std r4, 0(r12) | ||
176 | std r5, 8(r12) | ||
177 | std r6, 16(r12) | ||
178 | |||
179 | lwz r0,8(r1) | ||
180 | mtcrf 0xff,r0 | ||
181 | |||
182 | blr /* return r3 = status */ | ||
183 | |||
184 | /* Note: takes only 6 input parameters, 4 output parameters at maximum */ | ||
185 | _GLOBAL(beat_hcall4) | ||
186 | HMT_MEDIUM | ||
187 | |||
188 | mfcr r0 | ||
189 | stw r0,8(r1) | ||
190 | |||
191 | HCALL_INST_PRECALL | ||
192 | |||
193 | std r4,STK_PARM(r4)(r1) /* save ret buffer */ | ||
194 | |||
195 | mr r11,r3 | ||
196 | mr r3,r5 | ||
197 | mr r4,r6 | ||
198 | mr r5,r7 | ||
199 | mr r6,r8 | ||
200 | mr r7,r9 | ||
201 | mr r8,r10 | ||
202 | |||
203 | HVSC /* invoke the hypervisor */ | ||
204 | |||
205 | HCALL_INST_POSTCALL | ||
206 | |||
207 | ld r12,STK_PARM(r4)(r1) | ||
208 | std r4, 0(r12) | ||
209 | std r5, 8(r12) | ||
210 | std r6, 16(r12) | ||
211 | std r7, 24(r12) | ||
212 | |||
213 | lwz r0,8(r1) | ||
214 | mtcrf 0xff,r0 | ||
215 | |||
216 | blr /* return r3 = status */ | ||
217 | |||
218 | /* Note: takes only 6 input parameters, 5 output parameters at maximum */ | ||
219 | _GLOBAL(beat_hcall5) | ||
220 | HMT_MEDIUM | ||
221 | |||
222 | mfcr r0 | ||
223 | stw r0,8(r1) | ||
224 | |||
225 | HCALL_INST_PRECALL | ||
226 | |||
227 | std r4,STK_PARM(r4)(r1) /* save ret buffer */ | ||
228 | |||
229 | mr r11,r3 | ||
230 | mr r3,r5 | ||
231 | mr r4,r6 | ||
232 | mr r5,r7 | ||
233 | mr r6,r8 | ||
234 | mr r7,r9 | ||
235 | mr r8,r10 | ||
236 | |||
237 | HVSC /* invoke the hypervisor */ | ||
238 | |||
239 | HCALL_INST_POSTCALL | ||
240 | |||
241 | ld r12,STK_PARM(r4)(r1) | ||
242 | std r4, 0(r12) | ||
243 | std r5, 8(r12) | ||
244 | std r6, 16(r12) | ||
245 | std r7, 24(r12) | ||
246 | std r8, 32(r12) | ||
247 | |||
248 | lwz r0,8(r1) | ||
249 | mtcrf 0xff,r0 | ||
250 | |||
251 | blr /* return r3 = status */ | ||
252 | |||
253 | /* Note: takes only 6 input parameters, 6 output parameters at maximum */ | ||
254 | _GLOBAL(beat_hcall6) | ||
255 | HMT_MEDIUM | ||
256 | |||
257 | mfcr r0 | ||
258 | stw r0,8(r1) | ||
259 | |||
260 | HCALL_INST_PRECALL | ||
261 | |||
262 | std r4,STK_PARM(r4)(r1) /* save ret buffer */ | ||
263 | |||
264 | mr r11,r3 | ||
265 | mr r3,r5 | ||
266 | mr r4,r6 | ||
267 | mr r5,r7 | ||
268 | mr r6,r8 | ||
269 | mr r7,r9 | ||
270 | mr r8,r10 | ||
271 | |||
272 | HVSC /* invoke the hypervisor */ | ||
273 | |||
274 | HCALL_INST_POSTCALL | ||
275 | |||
276 | ld r12,STK_PARM(r4)(r1) | ||
277 | std r4, 0(r12) | ||
278 | std r5, 8(r12) | ||
279 | std r6, 16(r12) | ||
280 | std r7, 24(r12) | ||
281 | std r8, 32(r12) | ||
282 | std r9, 40(r12) | ||
283 | |||
284 | lwz r0,8(r1) | ||
285 | mtcrf 0xff,r0 | ||
286 | |||
287 | blr /* return r3 = status */ | ||
diff --git a/arch/powerpc/platforms/celleb/interrupt.c b/arch/powerpc/platforms/celleb/interrupt.c new file mode 100644 index 000000000000..98e6665681d3 --- /dev/null +++ b/arch/powerpc/platforms/celleb/interrupt.c | |||
@@ -0,0 +1,274 @@ | |||
1 | /* | ||
2 | * Celleb/Beat Interrupt controller | ||
3 | * | ||
4 | * (C) Copyright 2006-2007 TOSHIBA CORPORATION | ||
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 along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | |||
21 | #include <linux/init.h> | ||
22 | #include <linux/interrupt.h> | ||
23 | #include <linux/irq.h> | ||
24 | #include <linux/percpu.h> | ||
25 | #include <linux/types.h> | ||
26 | |||
27 | #include <asm/machdep.h> | ||
28 | |||
29 | #include "interrupt.h" | ||
30 | #include "beat_wrapper.h" | ||
31 | |||
32 | #define MAX_IRQS NR_IRQS | ||
33 | static DEFINE_SPINLOCK(beatic_irq_mask_lock); | ||
34 | static uint64_t beatic_irq_mask_enable[(MAX_IRQS+255)/64]; | ||
35 | static uint64_t beatic_irq_mask_ack[(MAX_IRQS+255)/64]; | ||
36 | |||
37 | static struct irq_host *beatic_host = NULL; | ||
38 | |||
39 | /* | ||
40 | * In this implementation, "virq" == "IRQ plug number", | ||
41 | * "(irq_hw_number_t)hwirq" == "IRQ outlet number". | ||
42 | */ | ||
43 | |||
44 | /* assumption: locked */ | ||
45 | static inline void beatic_update_irq_mask(unsigned int irq_plug) | ||
46 | { | ||
47 | int off; | ||
48 | unsigned long masks[4]; | ||
49 | |||
50 | off = (irq_plug / 256) * 4; | ||
51 | masks[0] = beatic_irq_mask_enable[off + 0] | ||
52 | & beatic_irq_mask_ack[off + 0]; | ||
53 | masks[1] = beatic_irq_mask_enable[off + 1] | ||
54 | & beatic_irq_mask_ack[off + 1]; | ||
55 | masks[2] = beatic_irq_mask_enable[off + 2] | ||
56 | & beatic_irq_mask_ack[off + 2]; | ||
57 | masks[3] = beatic_irq_mask_enable[off + 3] | ||
58 | & beatic_irq_mask_ack[off + 3]; | ||
59 | if (beat_set_interrupt_mask(irq_plug&~255UL, | ||
60 | masks[0], masks[1], masks[2], masks[3]) != 0) | ||
61 | panic("Failed to set mask IRQ!"); | ||
62 | } | ||
63 | |||
64 | static void beatic_mask_irq(unsigned int irq_plug) | ||
65 | { | ||
66 | unsigned long flags; | ||
67 | |||
68 | spin_lock_irqsave(&beatic_irq_mask_lock, flags); | ||
69 | beatic_irq_mask_enable[irq_plug/64] &= ~(1UL << (63 - (irq_plug%64))); | ||
70 | beatic_update_irq_mask(irq_plug); | ||
71 | spin_unlock_irqrestore(&beatic_irq_mask_lock, flags); | ||
72 | } | ||
73 | |||
74 | static void beatic_unmask_irq(unsigned int irq_plug) | ||
75 | { | ||
76 | unsigned long flags; | ||
77 | |||
78 | spin_lock_irqsave(&beatic_irq_mask_lock, flags); | ||
79 | beatic_irq_mask_enable[irq_plug/64] |= 1UL << (63 - (irq_plug%64)); | ||
80 | beatic_update_irq_mask(irq_plug); | ||
81 | spin_unlock_irqrestore(&beatic_irq_mask_lock, flags); | ||
82 | } | ||
83 | |||
84 | static void beatic_ack_irq(unsigned int irq_plug) | ||
85 | { | ||
86 | unsigned long flags; | ||
87 | |||
88 | spin_lock_irqsave(&beatic_irq_mask_lock, flags); | ||
89 | beatic_irq_mask_ack[irq_plug/64] &= ~(1UL << (63 - (irq_plug%64))); | ||
90 | beatic_update_irq_mask(irq_plug); | ||
91 | spin_unlock_irqrestore(&beatic_irq_mask_lock, flags); | ||
92 | } | ||
93 | |||
94 | static void beatic_end_irq(unsigned int irq_plug) | ||
95 | { | ||
96 | s64 err; | ||
97 | unsigned long flags; | ||
98 | |||
99 | if ((err = beat_downcount_of_interrupt(irq_plug)) != 0) { | ||
100 | if ((err & 0xFFFFFFFF) != 0xFFFFFFF5) /* -11: wrong state */ | ||
101 | panic("Failed to downcount IRQ! Error = %16lx", err); | ||
102 | |||
103 | printk(KERN_ERR "IRQ over-downcounted, plug %d\n", irq_plug); | ||
104 | } | ||
105 | spin_lock_irqsave(&beatic_irq_mask_lock, flags); | ||
106 | beatic_irq_mask_ack[irq_plug/64] |= 1UL << (63 - (irq_plug%64)); | ||
107 | beatic_update_irq_mask(irq_plug); | ||
108 | spin_unlock_irqrestore(&beatic_irq_mask_lock, flags); | ||
109 | } | ||
110 | |||
111 | static struct irq_chip beatic_pic = { | ||
112 | .typename = " CELL-BEAT ", | ||
113 | .unmask = beatic_unmask_irq, | ||
114 | .mask = beatic_mask_irq, | ||
115 | .eoi = beatic_end_irq, | ||
116 | }; | ||
117 | |||
118 | /* | ||
119 | * Dispose binding hardware IRQ number (hw) and Virtuql IRQ number (virq), | ||
120 | * update flags. | ||
121 | * | ||
122 | * Note that the number (virq) is already assigned at upper layer. | ||
123 | */ | ||
124 | static void beatic_pic_host_unmap(struct irq_host *h, unsigned int virq) | ||
125 | { | ||
126 | beat_destruct_irq_plug(virq); | ||
127 | } | ||
128 | |||
129 | /* | ||
130 | * Create or update binding hardware IRQ number (hw) and Virtuql | ||
131 | * IRQ number (virq). This is called only once for a given mapping. | ||
132 | * | ||
133 | * Note that the number (virq) is already assigned at upper layer. | ||
134 | */ | ||
135 | static int beatic_pic_host_map(struct irq_host *h, unsigned int virq, | ||
136 | irq_hw_number_t hw) | ||
137 | { | ||
138 | struct irq_desc *desc = get_irq_desc(virq); | ||
139 | int64_t err; | ||
140 | |||
141 | if ((err = beat_construct_and_connect_irq_plug(virq, hw)) < 0) | ||
142 | return -EIO; | ||
143 | |||
144 | desc->status |= IRQ_LEVEL; | ||
145 | set_irq_chip_and_handler(virq, &beatic_pic, handle_fasteoi_irq); | ||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | /* | ||
150 | * Update binding hardware IRQ number (hw) and Virtuql | ||
151 | * IRQ number (virq). This is called only once for a given mapping. | ||
152 | */ | ||
153 | static void beatic_pic_host_remap(struct irq_host *h, unsigned int virq, | ||
154 | irq_hw_number_t hw) | ||
155 | { | ||
156 | beat_construct_and_connect_irq_plug(virq, hw); | ||
157 | } | ||
158 | |||
159 | /* | ||
160 | * Translate device-tree interrupt spec to irq_hw_number_t style (ulong), | ||
161 | * to pass away to irq_create_mapping(). | ||
162 | * | ||
163 | * Called from irq_create_of_mapping() only. | ||
164 | * Note: We have only 1 entry to translate. | ||
165 | */ | ||
166 | static int beatic_pic_host_xlate(struct irq_host *h, struct device_node *ct, | ||
167 | u32 *intspec, unsigned int intsize, | ||
168 | irq_hw_number_t *out_hwirq, | ||
169 | unsigned int *out_flags) | ||
170 | { | ||
171 | u64 *intspec2 = (u64 *)intspec; | ||
172 | |||
173 | *out_hwirq = *intspec2; | ||
174 | *out_flags |= IRQ_TYPE_LEVEL_LOW; | ||
175 | return 0; | ||
176 | } | ||
177 | |||
178 | static struct irq_host_ops beatic_pic_host_ops = { | ||
179 | .map = beatic_pic_host_map, | ||
180 | .remap = beatic_pic_host_remap, | ||
181 | .unmap = beatic_pic_host_unmap, | ||
182 | .xlate = beatic_pic_host_xlate, | ||
183 | }; | ||
184 | |||
185 | /* | ||
186 | * Get an IRQ number | ||
187 | * Note: returns VIRQ | ||
188 | */ | ||
189 | static inline unsigned int beatic_get_irq_plug(void) | ||
190 | { | ||
191 | int i; | ||
192 | uint64_t pending[4], ub; | ||
193 | |||
194 | for (i = 0; i < MAX_IRQS; i += 256) { | ||
195 | beat_detect_pending_interrupts(i, pending); | ||
196 | __asm__ ("cntlzd %0,%1":"=r"(ub): | ||
197 | "r"(pending[0] & beatic_irq_mask_enable[i/64+0] | ||
198 | & beatic_irq_mask_ack[i/64+0])); | ||
199 | if (ub != 64) | ||
200 | return i + ub + 0; | ||
201 | __asm__ ("cntlzd %0,%1":"=r"(ub): | ||
202 | "r"(pending[1] & beatic_irq_mask_enable[i/64+1] | ||
203 | & beatic_irq_mask_ack[i/64+1])); | ||
204 | if (ub != 64) | ||
205 | return i + ub + 64; | ||
206 | __asm__ ("cntlzd %0,%1":"=r"(ub): | ||
207 | "r"(pending[2] & beatic_irq_mask_enable[i/64+2] | ||
208 | & beatic_irq_mask_ack[i/64+2])); | ||
209 | if (ub != 64) | ||
210 | return i + ub + 128; | ||
211 | __asm__ ("cntlzd %0,%1":"=r"(ub): | ||
212 | "r"(pending[3] & beatic_irq_mask_enable[i/64+3] | ||
213 | & beatic_irq_mask_ack[i/64+3])); | ||
214 | if (ub != 64) | ||
215 | return i + ub + 192; | ||
216 | } | ||
217 | |||
218 | return NO_IRQ; | ||
219 | } | ||
220 | unsigned int beatic_get_irq(void) | ||
221 | { | ||
222 | unsigned int ret; | ||
223 | |||
224 | ret = beatic_get_irq_plug(); | ||
225 | if (ret != NO_IRQ) | ||
226 | beatic_ack_irq(ret); | ||
227 | return ret; | ||
228 | } | ||
229 | |||
230 | /* | ||
231 | */ | ||
232 | void __init beatic_init_IRQ(void) | ||
233 | { | ||
234 | int i; | ||
235 | |||
236 | memset(beatic_irq_mask_enable, 0, sizeof(beatic_irq_mask_enable)); | ||
237 | memset(beatic_irq_mask_ack, 255, sizeof(beatic_irq_mask_ack)); | ||
238 | for (i = 0; i < MAX_IRQS; i += 256) | ||
239 | beat_set_interrupt_mask(i, 0L, 0L, 0L, 0L); | ||
240 | |||
241 | /* Set out get_irq function */ | ||
242 | ppc_md.get_irq = beatic_get_irq; | ||
243 | |||
244 | /* Allocate an irq host */ | ||
245 | beatic_host = irq_alloc_host(IRQ_HOST_MAP_NOMAP, 0, | ||
246 | &beatic_pic_host_ops, | ||
247 | 0); | ||
248 | BUG_ON(beatic_host == NULL); | ||
249 | irq_set_default_host(beatic_host); | ||
250 | } | ||
251 | |||
252 | #ifdef CONFIG_SMP | ||
253 | |||
254 | /* Nullified to compile with SMP mode */ | ||
255 | void beatic_setup_cpu(int cpu) | ||
256 | { | ||
257 | } | ||
258 | |||
259 | void beatic_cause_IPI(int cpu, int mesg) | ||
260 | { | ||
261 | } | ||
262 | |||
263 | void beatic_request_IPIs(void) | ||
264 | { | ||
265 | } | ||
266 | #endif /* CONFIG_SMP */ | ||
267 | |||
268 | void beatic_deinit_IRQ(void) | ||
269 | { | ||
270 | int i; | ||
271 | |||
272 | for (i = 1; i < NR_IRQS; i++) | ||
273 | beat_destruct_irq_plug(i); | ||
274 | } | ||
diff --git a/arch/powerpc/platforms/celleb/interrupt.h b/arch/powerpc/platforms/celleb/interrupt.h new file mode 100644 index 000000000000..b470fd0051f1 --- /dev/null +++ b/arch/powerpc/platforms/celleb/interrupt.h | |||
@@ -0,0 +1,33 @@ | |||
1 | /* | ||
2 | * Celleb/Beat Interrupt controller | ||
3 | * | ||
4 | * (C) Copyright 2006 TOSHIBA CORPORATION | ||
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 along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | |||
21 | #ifndef ASM_BEAT_PIC_H | ||
22 | #define ASM_BEAT_PIC_H | ||
23 | #ifdef __KERNEL__ | ||
24 | |||
25 | extern void beatic_init_IRQ(void); | ||
26 | extern unsigned int beatic_get_irq(void); | ||
27 | extern void beatic_cause_IPI(int cpu, int mesg); | ||
28 | extern void beatic_request_IPIs(void); | ||
29 | extern void beatic_setup_cpu(int); | ||
30 | extern void beatic_deinit_IRQ(void); | ||
31 | |||
32 | #endif | ||
33 | #endif /* ASM_BEAT_PIC_H */ | ||
diff --git a/arch/powerpc/platforms/celleb/iommu.c b/arch/powerpc/platforms/celleb/iommu.c new file mode 100644 index 000000000000..f63b94c65353 --- /dev/null +++ b/arch/powerpc/platforms/celleb/iommu.c | |||
@@ -0,0 +1,104 @@ | |||
1 | /* | ||
2 | * Support for IOMMU on Celleb platform. | ||
3 | * | ||
4 | * (C) Copyright 2006-2007 TOSHIBA CORPORATION | ||
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 along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | |||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/dma-mapping.h> | ||
24 | #include <linux/pci.h> | ||
25 | |||
26 | #include <asm/of_platform.h> | ||
27 | |||
28 | #include "beat_wrapper.h" | ||
29 | |||
30 | #define DMA_FLAGS 0xf800000000000000UL /* r/w permitted, coherency required, | ||
31 | strongest order */ | ||
32 | |||
33 | static int __init find_dma_window(u64 *io_space_id, u64 *ioid, | ||
34 | u64 *base, u64 *size, u64 *io_page_size) | ||
35 | { | ||
36 | struct device_node *dn; | ||
37 | const unsigned long *dma_window; | ||
38 | |||
39 | for_each_node_by_type(dn, "ioif") { | ||
40 | dma_window = get_property(dn, "toshiba,dma-window", NULL); | ||
41 | if (dma_window) { | ||
42 | *io_space_id = (dma_window[0] >> 32) & 0xffffffffUL; | ||
43 | *ioid = dma_window[0] & 0x7ffUL; | ||
44 | *base = dma_window[1]; | ||
45 | *size = dma_window[2]; | ||
46 | *io_page_size = 1 << dma_window[3]; | ||
47 | of_node_put(dn); | ||
48 | return 1; | ||
49 | } | ||
50 | } | ||
51 | return 0; | ||
52 | } | ||
53 | |||
54 | static void __init celleb_init_direct_mapping(void) | ||
55 | { | ||
56 | u64 lpar_addr, io_addr; | ||
57 | u64 io_space_id, ioid, dma_base, dma_size, io_page_size; | ||
58 | |||
59 | if (!find_dma_window(&io_space_id, &ioid, &dma_base, &dma_size, | ||
60 | &io_page_size)) { | ||
61 | pr_info("No dma window found !\n"); | ||
62 | return; | ||
63 | } | ||
64 | |||
65 | for (lpar_addr = 0; lpar_addr < dma_size; lpar_addr += io_page_size) { | ||
66 | io_addr = lpar_addr + dma_base; | ||
67 | (void)beat_put_iopte(io_space_id, io_addr, lpar_addr, | ||
68 | ioid, DMA_FLAGS); | ||
69 | } | ||
70 | |||
71 | dma_direct_offset = dma_base; | ||
72 | } | ||
73 | |||
74 | static int celleb_of_bus_notify(struct notifier_block *nb, | ||
75 | unsigned long action, void *data) | ||
76 | { | ||
77 | struct device *dev = data; | ||
78 | |||
79 | /* We are only intereted in device addition */ | ||
80 | if (action != BUS_NOTIFY_ADD_DEVICE) | ||
81 | return 0; | ||
82 | |||
83 | dev->archdata.dma_ops = pci_dma_ops; | ||
84 | |||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | static struct notifier_block celleb_of_bus_notifier = { | ||
89 | .notifier_call = celleb_of_bus_notify | ||
90 | }; | ||
91 | |||
92 | static int __init celleb_init_iommu(void) | ||
93 | { | ||
94 | if (!machine_is(celleb)) | ||
95 | return -ENODEV; | ||
96 | |||
97 | celleb_init_direct_mapping(); | ||
98 | pci_dma_ops = &dma_direct_ops; | ||
99 | bus_register_notifier(&of_platform_bus_type, &celleb_of_bus_notifier); | ||
100 | |||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | arch_initcall(celleb_init_iommu); | ||
diff --git a/arch/powerpc/platforms/celleb/pci.c b/arch/powerpc/platforms/celleb/pci.c new file mode 100644 index 000000000000..98de836dfed3 --- /dev/null +++ b/arch/powerpc/platforms/celleb/pci.c | |||
@@ -0,0 +1,481 @@ | |||
1 | /* | ||
2 | * Support for PCI on Celleb platform. | ||
3 | * | ||
4 | * (C) Copyright 2006-2007 TOSHIBA CORPORATION | ||
5 | * | ||
6 | * This code is based on arch/powerpc/kernel/rtas_pci.c: | ||
7 | * Copyright (C) 2001 Dave Engebretsen, IBM Corporation | ||
8 | * Copyright (C) 2003 Anton Blanchard <anton@au.ibm.com>, IBM | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License along | ||
21 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
22 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
23 | */ | ||
24 | |||
25 | #undef DEBUG | ||
26 | |||
27 | #include <linux/kernel.h> | ||
28 | #include <linux/threads.h> | ||
29 | #include <linux/pci.h> | ||
30 | #include <linux/string.h> | ||
31 | #include <linux/init.h> | ||
32 | #include <linux/bootmem.h> | ||
33 | #include <linux/pci_regs.h> | ||
34 | |||
35 | #include <asm/io.h> | ||
36 | #include <asm/irq.h> | ||
37 | #include <asm/prom.h> | ||
38 | #include <asm/machdep.h> | ||
39 | #include <asm/pci-bridge.h> | ||
40 | #include <asm/ppc-pci.h> | ||
41 | |||
42 | #include "pci.h" | ||
43 | #include "interrupt.h" | ||
44 | |||
45 | #define MAX_PCI_DEVICES 32 | ||
46 | #define MAX_PCI_FUNCTIONS 8 | ||
47 | #define MAX_PCI_BASE_ADDRS 3 /* use 64 bit address */ | ||
48 | |||
49 | /* definition for fake pci configuration area for GbE, .... ,and etc. */ | ||
50 | |||
51 | struct celleb_pci_resource { | ||
52 | struct resource r[MAX_PCI_BASE_ADDRS]; | ||
53 | }; | ||
54 | |||
55 | struct celleb_pci_private { | ||
56 | unsigned char *fake_config[MAX_PCI_DEVICES][MAX_PCI_FUNCTIONS]; | ||
57 | struct celleb_pci_resource *res[MAX_PCI_DEVICES][MAX_PCI_FUNCTIONS]; | ||
58 | }; | ||
59 | |||
60 | static inline u8 celleb_fake_config_readb(void *addr) | ||
61 | { | ||
62 | u8 *p = addr; | ||
63 | return *p; | ||
64 | } | ||
65 | |||
66 | static inline u16 celleb_fake_config_readw(void *addr) | ||
67 | { | ||
68 | __le16 *p = addr; | ||
69 | return le16_to_cpu(*p); | ||
70 | } | ||
71 | |||
72 | static inline u32 celleb_fake_config_readl(void *addr) | ||
73 | { | ||
74 | __le32 *p = addr; | ||
75 | return le32_to_cpu(*p); | ||
76 | } | ||
77 | |||
78 | static inline void celleb_fake_config_writeb(u32 val, void *addr) | ||
79 | { | ||
80 | u8 *p = addr; | ||
81 | *p = val; | ||
82 | } | ||
83 | |||
84 | static inline void celleb_fake_config_writew(u32 val, void *addr) | ||
85 | { | ||
86 | __le16 val16; | ||
87 | __le16 *p = addr; | ||
88 | val16 = cpu_to_le16(val); | ||
89 | *p = val16; | ||
90 | } | ||
91 | |||
92 | static inline void celleb_fake_config_writel(u32 val, void *addr) | ||
93 | { | ||
94 | __le32 val32; | ||
95 | __le32 *p = addr; | ||
96 | val32 = cpu_to_le32(val); | ||
97 | *p = val32; | ||
98 | } | ||
99 | |||
100 | static unsigned char *get_fake_config_start(struct pci_controller *hose, | ||
101 | int devno, int fn) | ||
102 | { | ||
103 | struct celleb_pci_private *private = hose->private_data; | ||
104 | |||
105 | if (private == NULL) | ||
106 | return NULL; | ||
107 | |||
108 | return private->fake_config[devno][fn]; | ||
109 | } | ||
110 | |||
111 | static struct celleb_pci_resource *get_resource_start( | ||
112 | struct pci_controller *hose, | ||
113 | int devno, int fn) | ||
114 | { | ||
115 | struct celleb_pci_private *private = hose->private_data; | ||
116 | |||
117 | if (private == NULL) | ||
118 | return NULL; | ||
119 | |||
120 | return private->res[devno][fn]; | ||
121 | } | ||
122 | |||
123 | |||
124 | static void celleb_config_read_fake(unsigned char *config, int where, | ||
125 | int size, u32 *val) | ||
126 | { | ||
127 | char *p = config + where; | ||
128 | |||
129 | switch (size) { | ||
130 | case 1: | ||
131 | *val = celleb_fake_config_readb(p); | ||
132 | break; | ||
133 | case 2: | ||
134 | *val = celleb_fake_config_readw(p); | ||
135 | break; | ||
136 | case 4: | ||
137 | *val = celleb_fake_config_readl(p); | ||
138 | break; | ||
139 | } | ||
140 | |||
141 | return; | ||
142 | } | ||
143 | |||
144 | static void celleb_config_write_fake(unsigned char *config, int where, | ||
145 | int size, u32 val) | ||
146 | { | ||
147 | char *p = config + where; | ||
148 | |||
149 | switch (size) { | ||
150 | case 1: | ||
151 | celleb_fake_config_writeb(val, p); | ||
152 | break; | ||
153 | case 2: | ||
154 | celleb_fake_config_writew(val, p); | ||
155 | break; | ||
156 | case 4: | ||
157 | celleb_fake_config_writel(val, p); | ||
158 | break; | ||
159 | } | ||
160 | return; | ||
161 | } | ||
162 | |||
163 | static int celleb_fake_pci_read_config(struct pci_bus *bus, | ||
164 | unsigned int devfn, int where, int size, u32 *val) | ||
165 | { | ||
166 | char *config; | ||
167 | struct device_node *node; | ||
168 | struct pci_controller *hose; | ||
169 | unsigned int devno = devfn >> 3; | ||
170 | unsigned int fn = devfn & 0x7; | ||
171 | |||
172 | /* allignment check */ | ||
173 | BUG_ON(where % size); | ||
174 | |||
175 | pr_debug(" fake read: bus=0x%x, ", bus->number); | ||
176 | node = (struct device_node *)bus->sysdata; | ||
177 | hose = pci_find_hose_for_OF_device(node); | ||
178 | config = get_fake_config_start(hose, devno, fn); | ||
179 | |||
180 | pr_debug("devno=0x%x, where=0x%x, size=0x%x, ", devno, where, size); | ||
181 | if (!config) { | ||
182 | pr_debug("failed\n"); | ||
183 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
184 | } | ||
185 | |||
186 | celleb_config_read_fake(config, where, size, val); | ||
187 | pr_debug("val=0x%x\n", *val); | ||
188 | |||
189 | return PCIBIOS_SUCCESSFUL; | ||
190 | } | ||
191 | |||
192 | |||
193 | static int celleb_fake_pci_write_config(struct pci_bus *bus, | ||
194 | unsigned int devfn, int where, int size, u32 val) | ||
195 | { | ||
196 | char *config; | ||
197 | struct device_node *node; | ||
198 | struct pci_controller *hose; | ||
199 | struct celleb_pci_resource *res; | ||
200 | unsigned int devno = devfn >> 3; | ||
201 | unsigned int fn = devfn & 0x7; | ||
202 | |||
203 | /* allignment check */ | ||
204 | BUG_ON(where % size); | ||
205 | |||
206 | node = (struct device_node *)bus->sysdata; | ||
207 | hose = pci_find_hose_for_OF_device(node); | ||
208 | config = get_fake_config_start(hose, devno, fn); | ||
209 | |||
210 | if (!config) | ||
211 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
212 | |||
213 | if (val == ~0) { | ||
214 | int i = (where - PCI_BASE_ADDRESS_0) >> 3; | ||
215 | |||
216 | switch (where) { | ||
217 | case PCI_BASE_ADDRESS_0: | ||
218 | case PCI_BASE_ADDRESS_2: | ||
219 | if (size != 4) | ||
220 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
221 | res = get_resource_start(hose, devno, fn); | ||
222 | if (!res) | ||
223 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
224 | celleb_config_write_fake(config, where, size, | ||
225 | (res->r[i].end - res->r[i].start)); | ||
226 | return PCIBIOS_SUCCESSFUL; | ||
227 | case PCI_BASE_ADDRESS_1: | ||
228 | case PCI_BASE_ADDRESS_3: | ||
229 | case PCI_BASE_ADDRESS_4: | ||
230 | case PCI_BASE_ADDRESS_5: | ||
231 | break; | ||
232 | default: | ||
233 | break; | ||
234 | } | ||
235 | } | ||
236 | |||
237 | celleb_config_write_fake(config, where, size, val); | ||
238 | pr_debug(" fake write: where=%x, size=%d, val=%x\n", | ||
239 | where, size, val); | ||
240 | |||
241 | return PCIBIOS_SUCCESSFUL; | ||
242 | } | ||
243 | |||
244 | static struct pci_ops celleb_fake_pci_ops = { | ||
245 | celleb_fake_pci_read_config, | ||
246 | celleb_fake_pci_write_config | ||
247 | }; | ||
248 | |||
249 | static inline void celleb_setup_pci_base_addrs(struct pci_controller *hose, | ||
250 | unsigned int devno, unsigned int fn, | ||
251 | unsigned int num_base_addr) | ||
252 | { | ||
253 | u32 val; | ||
254 | unsigned char *config; | ||
255 | struct celleb_pci_resource *res; | ||
256 | |||
257 | config = get_fake_config_start(hose, devno, fn); | ||
258 | res = get_resource_start(hose, devno, fn); | ||
259 | |||
260 | if (!config || !res) | ||
261 | return; | ||
262 | |||
263 | switch (num_base_addr) { | ||
264 | case 3: | ||
265 | val = (res->r[2].start & 0xfffffff0) | ||
266 | | PCI_BASE_ADDRESS_MEM_TYPE_64; | ||
267 | celleb_config_write_fake(config, PCI_BASE_ADDRESS_4, 4, val); | ||
268 | val = res->r[2].start >> 32; | ||
269 | celleb_config_write_fake(config, PCI_BASE_ADDRESS_5, 4, val); | ||
270 | /* FALLTHROUGH */ | ||
271 | case 2: | ||
272 | val = (res->r[1].start & 0xfffffff0) | ||
273 | | PCI_BASE_ADDRESS_MEM_TYPE_64; | ||
274 | celleb_config_write_fake(config, PCI_BASE_ADDRESS_2, 4, val); | ||
275 | val = res->r[1].start >> 32; | ||
276 | celleb_config_write_fake(config, PCI_BASE_ADDRESS_3, 4, val); | ||
277 | /* FALLTHROUGH */ | ||
278 | case 1: | ||
279 | val = (res->r[0].start & 0xfffffff0) | ||
280 | | PCI_BASE_ADDRESS_MEM_TYPE_64; | ||
281 | celleb_config_write_fake(config, PCI_BASE_ADDRESS_0, 4, val); | ||
282 | val = res->r[0].start >> 32; | ||
283 | celleb_config_write_fake(config, PCI_BASE_ADDRESS_1, 4, val); | ||
284 | break; | ||
285 | } | ||
286 | |||
287 | val = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; | ||
288 | celleb_config_write_fake(config, PCI_COMMAND, 2, val); | ||
289 | } | ||
290 | |||
291 | static int __devinit celleb_setup_fake_pci_device(struct device_node *node, | ||
292 | struct pci_controller *hose) | ||
293 | { | ||
294 | unsigned int rlen; | ||
295 | int num_base_addr = 0; | ||
296 | u32 val; | ||
297 | const u32 *wi0, *wi1, *wi2, *wi3, *wi4; | ||
298 | unsigned int devno, fn; | ||
299 | struct celleb_pci_private *private = hose->private_data; | ||
300 | unsigned char **config = NULL; | ||
301 | struct celleb_pci_resource **res = NULL; | ||
302 | const char *name; | ||
303 | const unsigned long *li; | ||
304 | int size, result; | ||
305 | |||
306 | if (private == NULL) { | ||
307 | printk(KERN_ERR "PCI: " | ||
308 | "memory space for pci controller is not assigned\n"); | ||
309 | goto error; | ||
310 | } | ||
311 | |||
312 | name = get_property(node, "model", &rlen); | ||
313 | if (!name) { | ||
314 | printk(KERN_ERR "PCI: model property not found.\n"); | ||
315 | goto error; | ||
316 | } | ||
317 | |||
318 | wi4 = get_property(node, "reg", &rlen); | ||
319 | if (wi4 == NULL) | ||
320 | goto error; | ||
321 | |||
322 | devno = ((wi4[0] >> 8) & 0xff) >> 3; | ||
323 | fn = (wi4[0] >> 8) & 0x7; | ||
324 | |||
325 | pr_debug("PCI: celleb_setup_fake_pci() %s devno=%x fn=%x\n", name, | ||
326 | devno, fn); | ||
327 | |||
328 | size = 256; | ||
329 | config = &private->fake_config[devno][fn]; | ||
330 | if (mem_init_done) | ||
331 | *config = kzalloc(size, GFP_KERNEL); | ||
332 | else | ||
333 | *config = alloc_bootmem(size); | ||
334 | if (*config == NULL) { | ||
335 | printk(KERN_ERR "PCI: " | ||
336 | "not enough memory for fake configuration space\n"); | ||
337 | goto error; | ||
338 | } | ||
339 | pr_debug("PCI: fake config area assigned 0x%016lx\n", | ||
340 | (unsigned long)*config); | ||
341 | |||
342 | size = sizeof(struct celleb_pci_resource); | ||
343 | res = &private->res[devno][fn]; | ||
344 | if (mem_init_done) | ||
345 | *res = kzalloc(size, GFP_KERNEL); | ||
346 | else | ||
347 | *res = alloc_bootmem(size); | ||
348 | if (*res == NULL) { | ||
349 | printk(KERN_ERR | ||
350 | "PCI: not enough memory for resource data space\n"); | ||
351 | goto error; | ||
352 | } | ||
353 | pr_debug("PCI: res assigned 0x%016lx\n", (unsigned long)*res); | ||
354 | |||
355 | wi0 = get_property(node, "device-id", NULL); | ||
356 | wi1 = get_property(node, "vendor-id", NULL); | ||
357 | wi2 = get_property(node, "class-code", NULL); | ||
358 | wi3 = get_property(node, "revision-id", NULL); | ||
359 | |||
360 | celleb_config_write_fake(*config, PCI_DEVICE_ID, 2, wi0[0] & 0xffff); | ||
361 | celleb_config_write_fake(*config, PCI_VENDOR_ID, 2, wi1[0] & 0xffff); | ||
362 | pr_debug("class-code = 0x%08x\n", wi2[0]); | ||
363 | |||
364 | celleb_config_write_fake(*config, PCI_CLASS_PROG, 1, wi2[0] & 0xff); | ||
365 | celleb_config_write_fake(*config, PCI_CLASS_DEVICE, 2, | ||
366 | (wi2[0] >> 8) & 0xffff); | ||
367 | celleb_config_write_fake(*config, PCI_REVISION_ID, 1, wi3[0]); | ||
368 | |||
369 | while (num_base_addr < MAX_PCI_BASE_ADDRS) { | ||
370 | result = of_address_to_resource(node, | ||
371 | num_base_addr, &(*res)->r[num_base_addr]); | ||
372 | if (result) | ||
373 | break; | ||
374 | num_base_addr++; | ||
375 | } | ||
376 | |||
377 | celleb_setup_pci_base_addrs(hose, devno, fn, num_base_addr); | ||
378 | |||
379 | li = get_property(node, "interrupts", &rlen); | ||
380 | val = li[0]; | ||
381 | celleb_config_write_fake(*config, PCI_INTERRUPT_PIN, 1, 1); | ||
382 | celleb_config_write_fake(*config, PCI_INTERRUPT_LINE, 1, val); | ||
383 | |||
384 | #ifdef DEBUG | ||
385 | pr_debug("PCI: %s irq=%ld\n", name, li[0]); | ||
386 | for (i = 0; i < 6; i++) { | ||
387 | celleb_config_read_fake(*config, | ||
388 | PCI_BASE_ADDRESS_0 + 0x4 * i, 4, | ||
389 | &val); | ||
390 | pr_debug("PCI: %s fn=%d base_address_%d=0x%x\n", | ||
391 | name, fn, i, val); | ||
392 | } | ||
393 | #endif | ||
394 | |||
395 | celleb_config_write_fake(*config, PCI_HEADER_TYPE, 1, | ||
396 | PCI_HEADER_TYPE_NORMAL); | ||
397 | |||
398 | return 0; | ||
399 | |||
400 | error: | ||
401 | if (mem_init_done) { | ||
402 | if (config && *config) | ||
403 | kfree(*config); | ||
404 | if (res && *res) | ||
405 | kfree(*res); | ||
406 | |||
407 | } else { | ||
408 | if (config && *config) { | ||
409 | size = 256; | ||
410 | free_bootmem((unsigned long)(*config), size); | ||
411 | } | ||
412 | if (res && *res) { | ||
413 | size = sizeof(struct celleb_pci_resource); | ||
414 | free_bootmem((unsigned long)(*res), size); | ||
415 | } | ||
416 | } | ||
417 | |||
418 | return 1; | ||
419 | } | ||
420 | |||
421 | static int __devinit phb_set_bus_ranges(struct device_node *dev, | ||
422 | struct pci_controller *phb) | ||
423 | { | ||
424 | const int *bus_range; | ||
425 | unsigned int len; | ||
426 | |||
427 | bus_range = get_property(dev, "bus-range", &len); | ||
428 | if (bus_range == NULL || len < 2 * sizeof(int)) | ||
429 | return 1; | ||
430 | |||
431 | phb->first_busno = bus_range[0]; | ||
432 | phb->last_busno = bus_range[1]; | ||
433 | |||
434 | return 0; | ||
435 | } | ||
436 | |||
437 | static void __devinit celleb_alloc_private_mem(struct pci_controller *hose) | ||
438 | { | ||
439 | if (mem_init_done) | ||
440 | hose->private_data = | ||
441 | kzalloc(sizeof(struct celleb_pci_private), GFP_KERNEL); | ||
442 | else | ||
443 | hose->private_data = | ||
444 | alloc_bootmem(sizeof(struct celleb_pci_private)); | ||
445 | } | ||
446 | |||
447 | int __devinit celleb_setup_phb(struct pci_controller *phb) | ||
448 | { | ||
449 | const char *name; | ||
450 | struct device_node *dev = phb->arch_data; | ||
451 | struct device_node *node; | ||
452 | unsigned int rlen; | ||
453 | |||
454 | name = get_property(dev, "name", &rlen); | ||
455 | if (!name) | ||
456 | return 1; | ||
457 | |||
458 | pr_debug("PCI: celleb_setup_phb() %s\n", name); | ||
459 | phb_set_bus_ranges(dev, phb); | ||
460 | |||
461 | if (strcmp(name, "epci") == 0) { | ||
462 | phb->ops = &celleb_epci_ops; | ||
463 | return celleb_setup_epci(dev, phb); | ||
464 | |||
465 | } else if (strcmp(name, "pci-pseudo") == 0) { | ||
466 | phb->ops = &celleb_fake_pci_ops; | ||
467 | celleb_alloc_private_mem(phb); | ||
468 | for (node = of_get_next_child(dev, NULL); | ||
469 | node != NULL; node = of_get_next_child(dev, node)) | ||
470 | celleb_setup_fake_pci_device(node, phb); | ||
471 | |||
472 | } else | ||
473 | return 1; | ||
474 | |||
475 | return 0; | ||
476 | } | ||
477 | |||
478 | int celleb_pci_probe_mode(struct pci_bus *bus) | ||
479 | { | ||
480 | return PCI_PROBE_DEVTREE; | ||
481 | } | ||
diff --git a/arch/powerpc/platforms/celleb/pci.h b/arch/powerpc/platforms/celleb/pci.h new file mode 100644 index 000000000000..5340e348e297 --- /dev/null +++ b/arch/powerpc/platforms/celleb/pci.h | |||
@@ -0,0 +1,35 @@ | |||
1 | /* | ||
2 | * pci prototypes for Celleb platform | ||
3 | * | ||
4 | * (C) Copyright 2006-2007 TOSHIBA CORPORATION | ||
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 along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | |||
21 | #ifndef _CELLEB_PCI_H | ||
22 | #define _CELLEB_PCI_H | ||
23 | |||
24 | #include <linux/pci.h> | ||
25 | |||
26 | #include <asm/pci-bridge.h> | ||
27 | #include <asm/prom.h> | ||
28 | |||
29 | extern int celleb_setup_phb(struct pci_controller *); | ||
30 | extern int celleb_pci_probe_mode(struct pci_bus *); | ||
31 | |||
32 | extern struct pci_ops celleb_epci_ops; | ||
33 | extern int celleb_setup_epci(struct device_node *, struct pci_controller *); | ||
34 | |||
35 | #endif /* _CELLEB_PCI_H */ | ||
diff --git a/arch/powerpc/platforms/celleb/scc.h b/arch/powerpc/platforms/celleb/scc.h new file mode 100644 index 000000000000..e9ce8a7c1882 --- /dev/null +++ b/arch/powerpc/platforms/celleb/scc.h | |||
@@ -0,0 +1,145 @@ | |||
1 | /* | ||
2 | * SCC (Super Companion Chip) definitions | ||
3 | * | ||
4 | * (C) Copyright 2004-2006 TOSHIBA CORPORATION | ||
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 along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | |||
21 | #ifndef _CELLEB_SCC_H | ||
22 | #define _CELLEB_SCC_H | ||
23 | |||
24 | #define PCI_VENDOR_ID_TOSHIBA_2 0x102f | ||
25 | #define PCI_DEVICE_ID_TOSHIBA_SCC_PCIEXC_BRIDGE 0x01b0 | ||
26 | #define PCI_DEVICE_ID_TOSHIBA_SCC_EPCI_BRIDGE 0x01b1 | ||
27 | #define PCI_DEVICE_ID_TOSHIBA_SCC_BRIDGE 0x01b2 | ||
28 | #define PCI_DEVICE_ID_TOSHIBA_SCC_GBE 0x01b3 | ||
29 | #define PCI_DEVICE_ID_TOSHIBA_SCC_ATA 0x01b4 | ||
30 | #define PCI_DEVICE_ID_TOSHIBA_SCC_USB2 0x01b5 | ||
31 | #define PCI_DEVICE_ID_TOSHIBA_SCC_USB 0x01b6 | ||
32 | #define PCI_DEVICE_ID_TOSHIBA_SCC_ENCDEC 0x01b7 | ||
33 | |||
34 | #define SCC_EPCI_REG 0x0000d000 | ||
35 | |||
36 | /* EPCI registers */ | ||
37 | #define SCC_EPCI_CNF10_REG 0x010 | ||
38 | #define SCC_EPCI_CNF14_REG 0x014 | ||
39 | #define SCC_EPCI_CNF18_REG 0x018 | ||
40 | #define SCC_EPCI_PVBAT 0x100 | ||
41 | #define SCC_EPCI_VPMBAT 0x104 | ||
42 | #define SCC_EPCI_VPIBAT 0x108 | ||
43 | #define SCC_EPCI_VCSR 0x110 | ||
44 | #define SCC_EPCI_VIENAB 0x114 | ||
45 | #define SCC_EPCI_VISTAT 0x118 | ||
46 | #define SCC_EPCI_VRDCOUNT 0x124 | ||
47 | #define SCC_EPCI_BAM0 0x12c | ||
48 | #define SCC_EPCI_BAM1 0x134 | ||
49 | #define SCC_EPCI_BAM2 0x13c | ||
50 | #define SCC_EPCI_IADR 0x164 | ||
51 | #define SCC_EPCI_CLKRST 0x800 | ||
52 | #define SCC_EPCI_INTSET 0x804 | ||
53 | #define SCC_EPCI_STATUS 0x808 | ||
54 | #define SCC_EPCI_ABTSET 0x80c | ||
55 | #define SCC_EPCI_WATRP 0x810 | ||
56 | #define SCC_EPCI_DUMMYRADR 0x814 | ||
57 | #define SCC_EPCI_SWRESP 0x818 | ||
58 | #define SCC_EPCI_CNTOPT 0x81c | ||
59 | #define SCC_EPCI_ECMODE 0xf00 | ||
60 | #define SCC_EPCI_IOM_AC_NUM 5 | ||
61 | #define SCC_EPCI_IOM_ACTE(n) (0xf10 + (n) * 4) | ||
62 | #define SCC_EPCI_IOT_AC_NUM 4 | ||
63 | #define SCC_EPCI_IOT_ACTE(n) (0xf30 + (n) * 4) | ||
64 | #define SCC_EPCI_MAEA 0xf50 | ||
65 | #define SCC_EPCI_MAEC 0xf54 | ||
66 | #define SCC_EPCI_CKCTRL 0xff0 | ||
67 | |||
68 | /* bits for SCC_EPCI_VCSR */ | ||
69 | #define SCC_EPCI_VCSR_FRE 0x00020000 | ||
70 | #define SCC_EPCI_VCSR_FWE 0x00010000 | ||
71 | #define SCC_EPCI_VCSR_DR 0x00000400 | ||
72 | #define SCC_EPCI_VCSR_SR 0x00000008 | ||
73 | #define SCC_EPCI_VCSR_AT 0x00000004 | ||
74 | |||
75 | /* bits for SCC_EPCI_VIENAB/SCC_EPCI_VISTAT */ | ||
76 | #define SCC_EPCI_VISTAT_PMPE 0x00000008 | ||
77 | #define SCC_EPCI_VISTAT_PMFE 0x00000004 | ||
78 | #define SCC_EPCI_VISTAT_PRA 0x00000002 | ||
79 | #define SCC_EPCI_VISTAT_PRD 0x00000001 | ||
80 | #define SCC_EPCI_VISTAT_ALL 0x0000000f | ||
81 | |||
82 | #define SCC_EPCI_VIENAB_PMPEE 0x00000008 | ||
83 | #define SCC_EPCI_VIENAB_PMFEE 0x00000004 | ||
84 | #define SCC_EPCI_VIENAB_PRA 0x00000002 | ||
85 | #define SCC_EPCI_VIENAB_PRD 0x00000001 | ||
86 | #define SCC_EPCI_VIENAB_ALL 0x0000000f | ||
87 | |||
88 | /* bits for SCC_EPCI_CLKRST */ | ||
89 | #define SCC_EPCI_CLKRST_CKS_MASK 0x00030000 | ||
90 | #define SCC_EPCI_CLKRST_CKS_2 0x00000000 | ||
91 | #define SCC_EPCI_CLKRST_CKS_4 0x00010000 | ||
92 | #define SCC_EPCI_CLKRST_CKS_8 0x00020000 | ||
93 | #define SCC_EPCI_CLKRST_PCICRST 0x00000400 | ||
94 | #define SCC_EPCI_CLKRST_BC 0x00000200 | ||
95 | #define SCC_EPCI_CLKRST_PCIRST 0x00000100 | ||
96 | #define SCC_EPCI_CLKRST_PCKEN 0x00000001 | ||
97 | |||
98 | /* bits for SCC_EPCI_INTSET/SCC_EPCI_STATUS */ | ||
99 | #define SCC_EPCI_INT_2M 0x01000000 | ||
100 | #define SCC_EPCI_INT_RERR 0x00200000 | ||
101 | #define SCC_EPCI_INT_SERR 0x00100000 | ||
102 | #define SCC_EPCI_INT_PRTER 0x00080000 | ||
103 | #define SCC_EPCI_INT_SER 0x00040000 | ||
104 | #define SCC_EPCI_INT_PER 0x00020000 | ||
105 | #define SCC_EPCI_INT_PAI 0x00010000 | ||
106 | #define SCC_EPCI_INT_1M 0x00000100 | ||
107 | #define SCC_EPCI_INT_PME 0x00000010 | ||
108 | #define SCC_EPCI_INT_INTD 0x00000008 | ||
109 | #define SCC_EPCI_INT_INTC 0x00000004 | ||
110 | #define SCC_EPCI_INT_INTB 0x00000002 | ||
111 | #define SCC_EPCI_INT_INTA 0x00000001 | ||
112 | #define SCC_EPCI_INT_DEVINT 0x0000000f | ||
113 | #define SCC_EPCI_INT_ALL 0x003f001f | ||
114 | #define SCC_EPCI_INT_ALLERR 0x003f0000 | ||
115 | |||
116 | /* bits for SCC_EPCI_CKCTRL */ | ||
117 | #define SCC_EPCI_CKCTRL_CRST0 0x00010000 | ||
118 | #define SCC_EPCI_CKCTRL_CRST1 0x00020000 | ||
119 | #define SCC_EPCI_CKCTRL_OCLKEN 0x00000100 | ||
120 | #define SCC_EPCI_CKCTRL_LCLKEN 0x00000001 | ||
121 | |||
122 | #define SCC_EPCI_IDSEL_AD_TO_SLOT(ad) ((ad) - 10) | ||
123 | #define SCC_EPCI_MAX_DEVNU SCC_EPCI_IDSEL_AD_TO_SLOT(32) | ||
124 | |||
125 | /* bits for SCC_EPCI_CNTOPT */ | ||
126 | #define SCC_EPCI_CNTOPT_O2PMB 0x00000002 | ||
127 | |||
128 | /* UHC registers */ | ||
129 | #define SCC_UHC_CKRCTRL 0xff0 | ||
130 | #define SCC_UHC_ECMODE 0xf00 | ||
131 | |||
132 | /* bits for SCC_UHC_CKRCTRL */ | ||
133 | #define SCC_UHC_F48MCKLEN 0x00000001 | ||
134 | #define SCC_UHC_P_SUSPEND 0x00000002 | ||
135 | #define SCC_UHC_PHY_SUSPEND_SEL 0x00000004 | ||
136 | #define SCC_UHC_HCLKEN 0x00000100 | ||
137 | #define SCC_UHC_USBEN 0x00010000 | ||
138 | #define SCC_UHC_USBCEN 0x00020000 | ||
139 | #define SCC_UHC_PHYEN 0x00040000 | ||
140 | |||
141 | /* bits for SCC_UHC_ECMODE */ | ||
142 | #define SCC_UHC_ECMODE_BY_BYTE 0x00000555 | ||
143 | #define SCC_UHC_ECMODE_BY_WORD 0x00000aaa | ||
144 | |||
145 | #endif /* _CELLEB_SCC_H */ | ||
diff --git a/arch/powerpc/platforms/celleb/scc_epci.c b/arch/powerpc/platforms/celleb/scc_epci.c new file mode 100644 index 000000000000..c11b39c3776a --- /dev/null +++ b/arch/powerpc/platforms/celleb/scc_epci.c | |||
@@ -0,0 +1,409 @@ | |||
1 | /* | ||
2 | * Support for SCC external PCI | ||
3 | * | ||
4 | * (C) Copyright 2004-2007 TOSHIBA CORPORATION | ||
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 along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | |||
21 | #undef DEBUG | ||
22 | |||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/threads.h> | ||
25 | #include <linux/pci.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/pci_regs.h> | ||
28 | #include <linux/bootmem.h> | ||
29 | |||
30 | #include <asm/io.h> | ||
31 | #include <asm/irq.h> | ||
32 | #include <asm/prom.h> | ||
33 | #include <asm/machdep.h> | ||
34 | #include <asm/pci-bridge.h> | ||
35 | #include <asm/ppc-pci.h> | ||
36 | |||
37 | #include "scc.h" | ||
38 | #include "pci.h" | ||
39 | #include "interrupt.h" | ||
40 | |||
41 | #define MAX_PCI_DEVICES 32 | ||
42 | #define MAX_PCI_FUNCTIONS 8 | ||
43 | |||
44 | #define iob() __asm__ __volatile__("eieio; sync":::"memory") | ||
45 | |||
46 | |||
47 | #if 0 /* test code for epci dummy read */ | ||
48 | static void celleb_epci_dummy_read(struct pci_dev *dev) | ||
49 | { | ||
50 | void __iomem *epci_base; | ||
51 | struct device_node *node; | ||
52 | struct pci_controller *hose; | ||
53 | u32 val; | ||
54 | |||
55 | node = (struct device_node *)dev->bus->sysdata; | ||
56 | hose = pci_find_hose_for_OF_device(node); | ||
57 | |||
58 | if (!hose) | ||
59 | return; | ||
60 | |||
61 | epci_base = hose->cfg_addr; | ||
62 | |||
63 | val = in_be32(epci_base + SCC_EPCI_WATRP); | ||
64 | iosync(); | ||
65 | |||
66 | return; | ||
67 | } | ||
68 | #endif | ||
69 | |||
70 | static inline void clear_and_disable_master_abort_interrupt( | ||
71 | struct pci_controller *hose) | ||
72 | { | ||
73 | void __iomem *addr; | ||
74 | addr = hose->cfg_addr + PCI_COMMAND; | ||
75 | out_be32(addr, in_be32(addr) | (PCI_STATUS_REC_MASTER_ABORT << 16)); | ||
76 | } | ||
77 | |||
78 | static int celleb_epci_check_abort(struct pci_controller *hose, | ||
79 | void __iomem *addr) | ||
80 | { | ||
81 | void __iomem *reg, *epci_base; | ||
82 | u32 val; | ||
83 | |||
84 | iob(); | ||
85 | epci_base = hose->cfg_addr; | ||
86 | |||
87 | reg = epci_base + PCI_COMMAND; | ||
88 | val = in_be32(reg); | ||
89 | |||
90 | if (val & (PCI_STATUS_REC_MASTER_ABORT << 16)) { | ||
91 | out_be32(reg, | ||
92 | (val & 0xffff) | (PCI_STATUS_REC_MASTER_ABORT << 16)); | ||
93 | |||
94 | /* clear PCI Controller error, FRE, PMFE */ | ||
95 | reg = epci_base + SCC_EPCI_STATUS; | ||
96 | out_be32(reg, SCC_EPCI_INT_PAI); | ||
97 | |||
98 | reg = epci_base + SCC_EPCI_VCSR; | ||
99 | val = in_be32(reg) & 0xffff; | ||
100 | val |= SCC_EPCI_VCSR_FRE; | ||
101 | out_be32(reg, val); | ||
102 | |||
103 | reg = epci_base + SCC_EPCI_VISTAT; | ||
104 | out_be32(reg, SCC_EPCI_VISTAT_PMFE); | ||
105 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
106 | } | ||
107 | |||
108 | return PCIBIOS_SUCCESSFUL; | ||
109 | } | ||
110 | |||
111 | static void __iomem *celleb_epci_make_config_addr(struct pci_controller *hose, | ||
112 | unsigned int devfn, int where) | ||
113 | { | ||
114 | void __iomem *addr; | ||
115 | struct pci_bus *bus = hose->bus; | ||
116 | |||
117 | if (bus->self) | ||
118 | addr = hose->cfg_data + | ||
119 | (((bus->number & 0xff) << 16) | ||
120 | | ((devfn & 0xff) << 8) | ||
121 | | (where & 0xff) | ||
122 | | 0x01000000); | ||
123 | else | ||
124 | addr = hose->cfg_data + | ||
125 | (((devfn & 0xff) << 8) | (where & 0xff)); | ||
126 | |||
127 | pr_debug("EPCI: config_addr = 0x%p\n", addr); | ||
128 | |||
129 | return addr; | ||
130 | } | ||
131 | |||
132 | static int celleb_epci_read_config(struct pci_bus *bus, | ||
133 | unsigned int devfn, int where, int size, u32 * val) | ||
134 | { | ||
135 | void __iomem *addr; | ||
136 | struct device_node *node; | ||
137 | struct pci_controller *hose; | ||
138 | |||
139 | /* allignment check */ | ||
140 | BUG_ON(where % size); | ||
141 | |||
142 | node = (struct device_node *)bus->sysdata; | ||
143 | hose = pci_find_hose_for_OF_device(node); | ||
144 | |||
145 | if (!hose->cfg_data) | ||
146 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
147 | |||
148 | if (bus->number == hose->first_busno && devfn == 0) { | ||
149 | /* EPCI controller self */ | ||
150 | |||
151 | addr = hose->cfg_addr + where; | ||
152 | |||
153 | switch (size) { | ||
154 | case 1: | ||
155 | *val = in_8(addr); | ||
156 | break; | ||
157 | case 2: | ||
158 | *val = in_be16(addr); | ||
159 | break; | ||
160 | case 4: | ||
161 | *val = in_be32(addr); | ||
162 | break; | ||
163 | default: | ||
164 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
165 | } | ||
166 | |||
167 | } else { | ||
168 | |||
169 | clear_and_disable_master_abort_interrupt(hose); | ||
170 | addr = celleb_epci_make_config_addr(hose, devfn, where); | ||
171 | |||
172 | switch (size) { | ||
173 | case 1: | ||
174 | *val = in_8(addr); | ||
175 | break; | ||
176 | case 2: | ||
177 | *val = in_le16(addr); | ||
178 | break; | ||
179 | case 4: | ||
180 | *val = in_le32(addr); | ||
181 | break; | ||
182 | default: | ||
183 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
184 | } | ||
185 | } | ||
186 | |||
187 | pr_debug("EPCI: " | ||
188 | "addr=0x%lx, devfn=0x%x, where=0x%x, size=0x%x, val=0x%x\n", | ||
189 | addr, devfn, where, size, *val); | ||
190 | |||
191 | return celleb_epci_check_abort(hose, NULL); | ||
192 | } | ||
193 | |||
194 | static int celleb_epci_write_config(struct pci_bus *bus, | ||
195 | unsigned int devfn, int where, int size, u32 val) | ||
196 | { | ||
197 | void __iomem *addr; | ||
198 | struct device_node *node; | ||
199 | struct pci_controller *hose; | ||
200 | |||
201 | /* allignment check */ | ||
202 | BUG_ON(where % size); | ||
203 | |||
204 | node = (struct device_node *)bus->sysdata; | ||
205 | hose = pci_find_hose_for_OF_device(node); | ||
206 | |||
207 | if (!hose->cfg_data) | ||
208 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
209 | |||
210 | if (bus->number == hose->first_busno && devfn == 0) { | ||
211 | /* EPCI controller self */ | ||
212 | |||
213 | addr = hose->cfg_addr + where; | ||
214 | |||
215 | switch (size) { | ||
216 | case 1: | ||
217 | out_8(addr, val); | ||
218 | break; | ||
219 | case 2: | ||
220 | out_be16(addr, val); | ||
221 | break; | ||
222 | case 4: | ||
223 | out_be32(addr, val); | ||
224 | break; | ||
225 | default: | ||
226 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
227 | } | ||
228 | |||
229 | } else { | ||
230 | |||
231 | clear_and_disable_master_abort_interrupt(hose); | ||
232 | addr = celleb_epci_make_config_addr(hose, devfn, where); | ||
233 | |||
234 | switch (size) { | ||
235 | case 1: | ||
236 | out_8(addr, val); | ||
237 | break; | ||
238 | case 2: | ||
239 | out_le16(addr, val); | ||
240 | break; | ||
241 | case 4: | ||
242 | out_le32(addr, val); | ||
243 | break; | ||
244 | default: | ||
245 | return PCIBIOS_DEVICE_NOT_FOUND; | ||
246 | } | ||
247 | } | ||
248 | |||
249 | return celleb_epci_check_abort(hose, addr); | ||
250 | } | ||
251 | |||
252 | struct pci_ops celleb_epci_ops = { | ||
253 | celleb_epci_read_config, | ||
254 | celleb_epci_write_config, | ||
255 | }; | ||
256 | |||
257 | /* to be moved in FW */ | ||
258 | static int __devinit celleb_epci_init(struct pci_controller *hose) | ||
259 | { | ||
260 | u32 val; | ||
261 | void __iomem *reg, *epci_base; | ||
262 | int hwres = 0; | ||
263 | |||
264 | epci_base = hose->cfg_addr; | ||
265 | |||
266 | /* PCI core reset(Internal bus and PCI clock) */ | ||
267 | reg = epci_base + SCC_EPCI_CKCTRL; | ||
268 | val = in_be32(reg); | ||
269 | if (val == 0x00030101) | ||
270 | hwres = 1; | ||
271 | else { | ||
272 | val &= ~(SCC_EPCI_CKCTRL_CRST0 | SCC_EPCI_CKCTRL_CRST1); | ||
273 | out_be32(reg, val); | ||
274 | |||
275 | /* set PCI core clock */ | ||
276 | val = in_be32(reg); | ||
277 | val |= (SCC_EPCI_CKCTRL_OCLKEN | SCC_EPCI_CKCTRL_LCLKEN); | ||
278 | out_be32(reg, val); | ||
279 | |||
280 | /* release PCI core reset (internal bus) */ | ||
281 | val = in_be32(reg); | ||
282 | val |= SCC_EPCI_CKCTRL_CRST0; | ||
283 | out_be32(reg, val); | ||
284 | |||
285 | /* set PCI clock select */ | ||
286 | reg = epci_base + SCC_EPCI_CLKRST; | ||
287 | val = in_be32(reg); | ||
288 | val &= ~SCC_EPCI_CLKRST_CKS_MASK; | ||
289 | val |= SCC_EPCI_CLKRST_CKS_2; | ||
290 | out_be32(reg, val); | ||
291 | |||
292 | /* set arbiter */ | ||
293 | reg = epci_base + SCC_EPCI_ABTSET; | ||
294 | out_be32(reg, 0x0f1f001f); /* temporary value */ | ||
295 | |||
296 | /* buffer on */ | ||
297 | reg = epci_base + SCC_EPCI_CLKRST; | ||
298 | val = in_be32(reg); | ||
299 | val |= SCC_EPCI_CLKRST_BC; | ||
300 | out_be32(reg, val); | ||
301 | |||
302 | /* PCI clock enable */ | ||
303 | val = in_be32(reg); | ||
304 | val |= SCC_EPCI_CLKRST_PCKEN; | ||
305 | out_be32(reg, val); | ||
306 | |||
307 | /* release PCI core reset (all) */ | ||
308 | reg = epci_base + SCC_EPCI_CKCTRL; | ||
309 | val = in_be32(reg); | ||
310 | val |= (SCC_EPCI_CKCTRL_CRST0 | SCC_EPCI_CKCTRL_CRST1); | ||
311 | out_be32(reg, val); | ||
312 | |||
313 | /* set base translation registers. (already set by Beat) */ | ||
314 | |||
315 | /* set base address masks. (already set by Beat) */ | ||
316 | } | ||
317 | |||
318 | /* release interrupt masks and clear all interrupts */ | ||
319 | reg = epci_base + SCC_EPCI_INTSET; | ||
320 | out_be32(reg, 0x013f011f); /* all interrupts enable */ | ||
321 | reg = epci_base + SCC_EPCI_VIENAB; | ||
322 | val = SCC_EPCI_VIENAB_PMPEE | SCC_EPCI_VIENAB_PMFEE; | ||
323 | out_be32(reg, val); | ||
324 | reg = epci_base + SCC_EPCI_STATUS; | ||
325 | out_be32(reg, 0xffffffff); | ||
326 | reg = epci_base + SCC_EPCI_VISTAT; | ||
327 | out_be32(reg, 0xffffffff); | ||
328 | |||
329 | /* disable PCI->IB address translation */ | ||
330 | reg = epci_base + SCC_EPCI_VCSR; | ||
331 | val = in_be32(reg); | ||
332 | val &= ~(SCC_EPCI_VCSR_DR | SCC_EPCI_VCSR_AT); | ||
333 | out_be32(reg, val); | ||
334 | |||
335 | /* set base addresses. (no need to set?) */ | ||
336 | |||
337 | /* memory space, bus master enable */ | ||
338 | reg = epci_base + PCI_COMMAND; | ||
339 | val = PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; | ||
340 | out_be32(reg, val); | ||
341 | |||
342 | /* endian mode setup */ | ||
343 | reg = epci_base + SCC_EPCI_ECMODE; | ||
344 | val = 0x00550155; | ||
345 | out_be32(reg, val); | ||
346 | |||
347 | /* set control option */ | ||
348 | reg = epci_base + SCC_EPCI_CNTOPT; | ||
349 | val = in_be32(reg); | ||
350 | val |= SCC_EPCI_CNTOPT_O2PMB; | ||
351 | out_be32(reg, val); | ||
352 | |||
353 | /* XXX: temporay: set registers for address conversion setup */ | ||
354 | reg = epci_base + SCC_EPCI_CNF10_REG; | ||
355 | out_be32(reg, 0x80000008); | ||
356 | reg = epci_base + SCC_EPCI_CNF14_REG; | ||
357 | out_be32(reg, 0x40000008); | ||
358 | |||
359 | reg = epci_base + SCC_EPCI_BAM0; | ||
360 | out_be32(reg, 0x80000000); | ||
361 | reg = epci_base + SCC_EPCI_BAM1; | ||
362 | out_be32(reg, 0xe0000000); | ||
363 | |||
364 | reg = epci_base + SCC_EPCI_PVBAT; | ||
365 | out_be32(reg, 0x80000000); | ||
366 | |||
367 | if (!hwres) { | ||
368 | /* release external PCI reset */ | ||
369 | reg = epci_base + SCC_EPCI_CLKRST; | ||
370 | val = in_be32(reg); | ||
371 | val |= SCC_EPCI_CLKRST_PCIRST; | ||
372 | out_be32(reg, val); | ||
373 | } | ||
374 | |||
375 | return 0; | ||
376 | } | ||
377 | |||
378 | int __devinit celleb_setup_epci(struct device_node *node, | ||
379 | struct pci_controller *hose) | ||
380 | { | ||
381 | struct resource r; | ||
382 | |||
383 | pr_debug("PCI: celleb_setup_epci()\n"); | ||
384 | |||
385 | if (of_address_to_resource(node, 0, &r)) | ||
386 | goto error; | ||
387 | hose->cfg_addr = ioremap(r.start, (r.end - r.start + 1)); | ||
388 | if (!hose->cfg_addr) | ||
389 | goto error; | ||
390 | pr_debug("EPCI: cfg_addr map 0x%016lx->0x%016lx + 0x%016lx\n", | ||
391 | r.start, (unsigned long)hose->cfg_addr, | ||
392 | (r.end - r.start + 1)); | ||
393 | |||
394 | if (of_address_to_resource(node, 2, &r)) | ||
395 | goto error; | ||
396 | hose->cfg_data = ioremap(r.start, (r.end - r.start + 1)); | ||
397 | if (!hose->cfg_data) | ||
398 | goto error; | ||
399 | pr_debug("EPCI: cfg_data map 0x%016lx->0x%016lx + 0x%016lx\n", | ||
400 | r.start, (unsigned long)hose->cfg_data, | ||
401 | (r.end - r.start + 1)); | ||
402 | |||
403 | celleb_epci_init(hose); | ||
404 | |||
405 | return 0; | ||
406 | |||
407 | error: | ||
408 | return 1; | ||
409 | } | ||
diff --git a/arch/powerpc/platforms/celleb/scc_sio.c b/arch/powerpc/platforms/celleb/scc_sio.c new file mode 100644 index 000000000000..bcd25f54d986 --- /dev/null +++ b/arch/powerpc/platforms/celleb/scc_sio.c | |||
@@ -0,0 +1,101 @@ | |||
1 | /* | ||
2 | * setup serial port in SCC | ||
3 | * | ||
4 | * (C) Copyright 2006 TOSHIBA CORPORATION | ||
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 along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | |||
21 | #include <linux/tty.h> | ||
22 | #include <linux/serial.h> | ||
23 | #include <linux/serial_core.h> | ||
24 | #include <linux/console.h> | ||
25 | |||
26 | #include <asm/io.h> | ||
27 | #include <asm/prom.h> | ||
28 | |||
29 | /* sio irq0=0xb00010022 irq0=0xb00010023 irq2=0xb00010024 | ||
30 | mmio=0xfff000-0x1000,0xff2000-0x1000 */ | ||
31 | static int txx9_serial_bitmap = 0; | ||
32 | |||
33 | static struct { | ||
34 | uint32_t offset; | ||
35 | uint32_t index; | ||
36 | } txx9_scc_tab[3] = { | ||
37 | { 0x300, 0 }, /* 0xFFF300 */ | ||
38 | { 0x400, 0 }, /* 0xFFF400 */ | ||
39 | { 0x800, 1 } /* 0xFF2800 */ | ||
40 | }; | ||
41 | |||
42 | static int txx9_serial_init(void) | ||
43 | { | ||
44 | extern int early_serial_txx9_setup(struct uart_port *port); | ||
45 | struct device_node *node; | ||
46 | int i; | ||
47 | struct uart_port req; | ||
48 | struct of_irq irq; | ||
49 | struct resource res; | ||
50 | |||
51 | node = of_find_node_by_path("/ioif1/sio"); | ||
52 | if (!node) | ||
53 | return 0; | ||
54 | |||
55 | for(i = 0; i < sizeof(txx9_scc_tab)/sizeof(txx9_scc_tab[0]); i++) { | ||
56 | if (!(txx9_serial_bitmap & (1<<i))) | ||
57 | continue; | ||
58 | |||
59 | if (of_irq_map_one(node, i, &irq)) | ||
60 | continue; | ||
61 | if (of_address_to_resource(node, txx9_scc_tab[i].index, &res)) | ||
62 | continue; | ||
63 | |||
64 | memset(&req, 0, sizeof(req)); | ||
65 | req.line = i; | ||
66 | req.iotype = UPIO_MEM; | ||
67 | req.mapbase = res.start + txx9_scc_tab[i].offset; | ||
68 | #ifdef CONFIG_SERIAL_TXX9_CONSOLE | ||
69 | req.membase = ioremap(req.mapbase, 0x24); | ||
70 | #endif | ||
71 | req.irq = irq_create_of_mapping(irq.controller, | ||
72 | irq.specifier, irq.size); | ||
73 | req.flags |= UPF_IOREMAP | UPF_BUGGY_UART /*HAVE_CTS_LINE*/; | ||
74 | req.uartclk = 83300000; | ||
75 | early_serial_txx9_setup(&req); | ||
76 | } | ||
77 | |||
78 | of_node_put(node); | ||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | static int txx9_serial_config(char *ptr) | ||
83 | { | ||
84 | int i; | ||
85 | |||
86 | for (;;) { | ||
87 | switch(get_option(&ptr, &i)) { | ||
88 | default: | ||
89 | return 0; | ||
90 | case 2: | ||
91 | txx9_serial_bitmap |= 1 << i; | ||
92 | break; | ||
93 | case 1: | ||
94 | txx9_serial_bitmap |= 1 << i; | ||
95 | return 0; | ||
96 | } | ||
97 | } | ||
98 | } | ||
99 | __setup("txx9_serial=", txx9_serial_config); | ||
100 | |||
101 | console_initcall(txx9_serial_init); | ||
diff --git a/arch/powerpc/platforms/celleb/scc_uhc.c b/arch/powerpc/platforms/celleb/scc_uhc.c new file mode 100644 index 000000000000..a7c548bde2e3 --- /dev/null +++ b/arch/powerpc/platforms/celleb/scc_uhc.c | |||
@@ -0,0 +1,94 @@ | |||
1 | /* | ||
2 | * SCC (Super Companion Chip) UHC setup | ||
3 | * | ||
4 | * (C) Copyright 2006-2007 TOSHIBA CORPORATION | ||
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 along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | |||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/pci.h> | ||
23 | |||
24 | #include <asm/delay.h> | ||
25 | #include <asm/io.h> | ||
26 | #include <asm/machdep.h> | ||
27 | |||
28 | #include "scc.h" | ||
29 | |||
30 | #define UHC_RESET_WAIT_MAX 10000 | ||
31 | |||
32 | static inline int uhc_clkctrl_ready(u32 val) | ||
33 | { | ||
34 | const u32 mask = SCC_UHC_USBCEN | SCC_UHC_USBCEN; | ||
35 | return((val & mask) == mask); | ||
36 | } | ||
37 | |||
38 | /* | ||
39 | * UHC(usb host controler) enable function. | ||
40 | * affect to both of OHCI and EHCI core module. | ||
41 | */ | ||
42 | static void enable_scc_uhc(struct pci_dev *dev) | ||
43 | { | ||
44 | void __iomem *uhc_base; | ||
45 | u32 __iomem *uhc_clkctrl; | ||
46 | u32 __iomem *uhc_ecmode; | ||
47 | u32 val = 0; | ||
48 | int i; | ||
49 | |||
50 | if (!machine_is(celleb)) | ||
51 | return; | ||
52 | |||
53 | uhc_base = ioremap(pci_resource_start(dev, 0), | ||
54 | pci_resource_len(dev, 0)); | ||
55 | if (!uhc_base) { | ||
56 | printk(KERN_ERR "failed to map UHC register base.\n"); | ||
57 | return; | ||
58 | } | ||
59 | uhc_clkctrl = uhc_base + SCC_UHC_CKRCTRL; | ||
60 | uhc_ecmode = uhc_base + SCC_UHC_ECMODE; | ||
61 | |||
62 | /* setup for normal mode */ | ||
63 | val |= SCC_UHC_F48MCKLEN; | ||
64 | out_be32(uhc_clkctrl, val); | ||
65 | val |= SCC_UHC_PHY_SUSPEND_SEL; | ||
66 | out_be32(uhc_clkctrl, val); | ||
67 | udelay(10); | ||
68 | val |= SCC_UHC_PHYEN; | ||
69 | out_be32(uhc_clkctrl, val); | ||
70 | udelay(50); | ||
71 | |||
72 | /* disable reset */ | ||
73 | val |= SCC_UHC_HCLKEN; | ||
74 | out_be32(uhc_clkctrl, val); | ||
75 | val |= (SCC_UHC_USBCEN | SCC_UHC_USBEN); | ||
76 | out_be32(uhc_clkctrl, val); | ||
77 | i = 0; | ||
78 | while (!uhc_clkctrl_ready(in_be32(uhc_clkctrl))) { | ||
79 | udelay(10); | ||
80 | if (i++ > UHC_RESET_WAIT_MAX) { | ||
81 | printk(KERN_ERR "Failed to disable UHC reset %x\n", | ||
82 | in_be32(uhc_clkctrl)); | ||
83 | break; | ||
84 | } | ||
85 | } | ||
86 | |||
87 | /* Endian Conversion Mode for Master ALL area */ | ||
88 | out_be32(uhc_ecmode, SCC_UHC_ECMODE_BY_BYTE); | ||
89 | |||
90 | iounmap(uhc_base); | ||
91 | } | ||
92 | |||
93 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TOSHIBA_2, | ||
94 | PCI_DEVICE_ID_TOSHIBA_SCC_USB, enable_scc_uhc); | ||
diff --git a/arch/powerpc/platforms/celleb/setup.c b/arch/powerpc/platforms/celleb/setup.c new file mode 100644 index 000000000000..5f4d0d933238 --- /dev/null +++ b/arch/powerpc/platforms/celleb/setup.c | |||
@@ -0,0 +1,193 @@ | |||
1 | /* | ||
2 | * Celleb setup code | ||
3 | * | ||
4 | * (C) Copyright 2006-2007 TOSHIBA CORPORATION | ||
5 | * | ||
6 | * This code is based on arch/powerpc/platforms/cell/setup.c: | ||
7 | * Copyright (C) 1995 Linus Torvalds | ||
8 | * Adapted from 'alpha' version by Gary Thomas | ||
9 | * Modified by Cort Dougan (cort@cs.nmt.edu) | ||
10 | * Modified by PPC64 Team, IBM Corp | ||
11 | * Modified by Cell Team, IBM Deutschland Entwicklung GmbH | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License as published by | ||
15 | * the Free Software Foundation; either version 2 of the License, or | ||
16 | * (at your option) any later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License along | ||
24 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
25 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
26 | */ | ||
27 | |||
28 | #undef DEBUG | ||
29 | |||
30 | #include <linux/cpu.h> | ||
31 | #include <linux/sched.h> | ||
32 | #include <linux/kernel.h> | ||
33 | #include <linux/mm.h> | ||
34 | #include <linux/stddef.h> | ||
35 | #include <linux/unistd.h> | ||
36 | #include <linux/reboot.h> | ||
37 | #include <linux/init.h> | ||
38 | #include <linux/delay.h> | ||
39 | #include <linux/irq.h> | ||
40 | #include <linux/seq_file.h> | ||
41 | #include <linux/root_dev.h> | ||
42 | #include <linux/console.h> | ||
43 | |||
44 | #include <asm/mmu.h> | ||
45 | #include <asm/processor.h> | ||
46 | #include <asm/io.h> | ||
47 | #include <asm/kexec.h> | ||
48 | #include <asm/prom.h> | ||
49 | #include <asm/machdep.h> | ||
50 | #include <asm/cputable.h> | ||
51 | #include <asm/irq.h> | ||
52 | #include <asm/spu_priv1.h> | ||
53 | #include <asm/firmware.h> | ||
54 | #include <asm/of_platform.h> | ||
55 | |||
56 | #include "interrupt.h" | ||
57 | #include "beat_wrapper.h" | ||
58 | #include "beat.h" | ||
59 | #include "pci.h" | ||
60 | |||
61 | static char celleb_machine_type[128] = "Celleb"; | ||
62 | |||
63 | static void celleb_show_cpuinfo(struct seq_file *m) | ||
64 | { | ||
65 | struct device_node *root; | ||
66 | const char *model = ""; | ||
67 | |||
68 | root = of_find_node_by_path("/"); | ||
69 | if (root) | ||
70 | model = get_property(root, "model", NULL); | ||
71 | /* using "CHRP" is to trick anaconda into installing FCx into Celleb */ | ||
72 | seq_printf(m, "machine\t\t: %s %s\n", celleb_machine_type, model); | ||
73 | of_node_put(root); | ||
74 | } | ||
75 | |||
76 | static int celleb_machine_type_hack(char *ptr) | ||
77 | { | ||
78 | strncpy(celleb_machine_type, ptr, sizeof(celleb_machine_type)); | ||
79 | celleb_machine_type[sizeof(celleb_machine_type)-1] = 0; | ||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | __setup("celleb_machine_type_hack", celleb_machine_type_hack); | ||
84 | |||
85 | static void celleb_progress(char *s, unsigned short hex) | ||
86 | { | ||
87 | printk("*** %04x : %s\n", hex, s ? s : ""); | ||
88 | } | ||
89 | |||
90 | static void __init celleb_setup_arch(void) | ||
91 | { | ||
92 | #ifdef CONFIG_SPU_BASE | ||
93 | spu_priv1_ops = &spu_priv1_beat_ops; | ||
94 | spu_management_ops = &spu_management_of_ops; | ||
95 | #endif | ||
96 | |||
97 | #ifdef CONFIG_SMP | ||
98 | smp_init_celleb(); | ||
99 | #endif | ||
100 | |||
101 | /* init to some ~sane value until calibrate_delay() runs */ | ||
102 | loops_per_jiffy = 50000000; | ||
103 | |||
104 | if (ROOT_DEV == 0) { | ||
105 | printk("No ramdisk, default root is /dev/hda2\n"); | ||
106 | ROOT_DEV = Root_HDA2; | ||
107 | } | ||
108 | |||
109 | #ifdef CONFIG_DUMMY_CONSOLE | ||
110 | conswitchp = &dummy_con; | ||
111 | #endif | ||
112 | } | ||
113 | |||
114 | static void beat_power_save(void) | ||
115 | { | ||
116 | beat_pause(0); | ||
117 | } | ||
118 | |||
119 | static int __init celleb_probe(void) | ||
120 | { | ||
121 | unsigned long root = of_get_flat_dt_root(); | ||
122 | |||
123 | if (!of_flat_dt_is_compatible(root, "Beat")) | ||
124 | return 0; | ||
125 | |||
126 | powerpc_firmware_features |= FW_FEATURE_CELLEB_POSSIBLE; | ||
127 | hpte_init_beat(); | ||
128 | return 1; | ||
129 | } | ||
130 | |||
131 | /* | ||
132 | * Cell has no legacy IO; anything calling this function has to | ||
133 | * fail or bad things will happen | ||
134 | */ | ||
135 | static int celleb_check_legacy_ioport(unsigned int baseport) | ||
136 | { | ||
137 | return -ENODEV; | ||
138 | } | ||
139 | |||
140 | #ifdef CONFIG_KEXEC | ||
141 | static void celleb_kexec_cpu_down(int crash, int secondary) | ||
142 | { | ||
143 | beatic_deinit_IRQ(); | ||
144 | } | ||
145 | #endif | ||
146 | |||
147 | static struct of_device_id celleb_bus_ids[] = { | ||
148 | { .type = "scc", }, | ||
149 | { .type = "ioif", }, /* old style */ | ||
150 | {}, | ||
151 | }; | ||
152 | |||
153 | static int __init celleb_publish_devices(void) | ||
154 | { | ||
155 | if (!machine_is(celleb)) | ||
156 | return 0; | ||
157 | |||
158 | /* Publish OF platform devices for southbridge IOs */ | ||
159 | of_platform_bus_probe(NULL, celleb_bus_ids, NULL); | ||
160 | |||
161 | return 0; | ||
162 | } | ||
163 | device_initcall(celleb_publish_devices); | ||
164 | |||
165 | define_machine(celleb) { | ||
166 | .name = "Cell Reference Set", | ||
167 | .probe = celleb_probe, | ||
168 | .setup_arch = celleb_setup_arch, | ||
169 | .show_cpuinfo = celleb_show_cpuinfo, | ||
170 | .restart = beat_restart, | ||
171 | .power_off = beat_power_off, | ||
172 | .halt = beat_halt, | ||
173 | .get_rtc_time = beat_get_rtc_time, | ||
174 | .set_rtc_time = beat_set_rtc_time, | ||
175 | .calibrate_decr = generic_calibrate_decr, | ||
176 | .check_legacy_ioport = celleb_check_legacy_ioport, | ||
177 | .progress = celleb_progress, | ||
178 | .power_save = beat_power_save, | ||
179 | .nvram_size = beat_nvram_get_size, | ||
180 | .nvram_read = beat_nvram_read, | ||
181 | .nvram_write = beat_nvram_write, | ||
182 | .set_dabr = beat_set_xdabr, | ||
183 | .init_IRQ = beatic_init_IRQ, | ||
184 | .get_irq = beatic_get_irq, | ||
185 | .pci_probe_mode = celleb_pci_probe_mode, | ||
186 | .pci_setup_phb = celleb_setup_phb, | ||
187 | #ifdef CONFIG_KEXEC | ||
188 | .kexec_cpu_down = celleb_kexec_cpu_down, | ||
189 | .machine_kexec = default_machine_kexec, | ||
190 | .machine_kexec_prepare = default_machine_kexec_prepare, | ||
191 | .machine_crash_shutdown = default_machine_crash_shutdown, | ||
192 | #endif | ||
193 | }; | ||
diff --git a/arch/powerpc/platforms/celleb/smp.c b/arch/powerpc/platforms/celleb/smp.c new file mode 100644 index 000000000000..a7631250aeb4 --- /dev/null +++ b/arch/powerpc/platforms/celleb/smp.c | |||
@@ -0,0 +1,124 @@ | |||
1 | /* | ||
2 | * SMP support for Celleb platform. (Incomplete) | ||
3 | * | ||
4 | * (C) Copyright 2006 TOSHIBA CORPORATION | ||
5 | * | ||
6 | * This code is based on arch/powerpc/platforms/cell/smp.c: | ||
7 | * Dave Engebretsen, Peter Bergner, and | ||
8 | * Mike Corrigan {engebret|bergner|mikec}@us.ibm.com | ||
9 | * Plus various changes from other IBM teams... | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | * GNU General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License along | ||
22 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
23 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
24 | */ | ||
25 | |||
26 | #undef DEBUG | ||
27 | |||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/smp.h> | ||
30 | #include <linux/interrupt.h> | ||
31 | #include <linux/init.h> | ||
32 | #include <linux/threads.h> | ||
33 | #include <linux/cpu.h> | ||
34 | |||
35 | #include <asm/irq.h> | ||
36 | #include <asm/smp.h> | ||
37 | #include <asm/machdep.h> | ||
38 | #include <asm/udbg.h> | ||
39 | |||
40 | #include "interrupt.h" | ||
41 | |||
42 | #ifdef DEBUG | ||
43 | #define DBG(fmt...) udbg_printf(fmt) | ||
44 | #else | ||
45 | #define DBG(fmt...) | ||
46 | #endif | ||
47 | |||
48 | /* | ||
49 | * The primary thread of each non-boot processor is recorded here before | ||
50 | * smp init. | ||
51 | */ | ||
52 | /* static cpumask_t of_spin_map; */ | ||
53 | |||
54 | /** | ||
55 | * smp_startup_cpu() - start the given cpu | ||
56 | * | ||
57 | * At boot time, there is nothing to do for primary threads which were | ||
58 | * started from Open Firmware. For anything else, call RTAS with the | ||
59 | * appropriate start location. | ||
60 | * | ||
61 | * Returns: | ||
62 | * 0 - failure | ||
63 | * 1 - success | ||
64 | */ | ||
65 | static inline int __devinit smp_startup_cpu(unsigned int lcpu) | ||
66 | { | ||
67 | return 0; | ||
68 | } | ||
69 | |||
70 | static void smp_beatic_message_pass(int target, int msg) | ||
71 | { | ||
72 | unsigned int i; | ||
73 | |||
74 | if (target < NR_CPUS) { | ||
75 | beatic_cause_IPI(target, msg); | ||
76 | } else { | ||
77 | for_each_online_cpu(i) { | ||
78 | if (target == MSG_ALL_BUT_SELF | ||
79 | && i == smp_processor_id()) | ||
80 | continue; | ||
81 | beatic_cause_IPI(i, msg); | ||
82 | } | ||
83 | } | ||
84 | } | ||
85 | |||
86 | static int __init smp_beatic_probe(void) | ||
87 | { | ||
88 | return cpus_weight(cpu_possible_map); | ||
89 | } | ||
90 | |||
91 | static void __devinit smp_beatic_setup_cpu(int cpu) | ||
92 | { | ||
93 | beatic_setup_cpu(cpu); | ||
94 | } | ||
95 | |||
96 | static void __devinit smp_celleb_kick_cpu(int nr) | ||
97 | { | ||
98 | BUG_ON(nr < 0 || nr >= NR_CPUS); | ||
99 | |||
100 | if (!smp_startup_cpu(nr)) | ||
101 | return; | ||
102 | } | ||
103 | |||
104 | static int smp_celleb_cpu_bootable(unsigned int nr) | ||
105 | { | ||
106 | return 1; | ||
107 | } | ||
108 | static struct smp_ops_t bpa_beatic_smp_ops = { | ||
109 | .message_pass = smp_beatic_message_pass, | ||
110 | .probe = smp_beatic_probe, | ||
111 | .kick_cpu = smp_celleb_kick_cpu, | ||
112 | .setup_cpu = smp_beatic_setup_cpu, | ||
113 | .cpu_bootable = smp_celleb_cpu_bootable, | ||
114 | }; | ||
115 | |||
116 | /* This is called very early */ | ||
117 | void __init smp_init_celleb(void) | ||
118 | { | ||
119 | DBG(" -> smp_init_celleb()\n"); | ||
120 | |||
121 | smp_ops = &bpa_beatic_smp_ops; | ||
122 | |||
123 | DBG(" <- smp_init_celleb()\n"); | ||
124 | } | ||
diff --git a/arch/powerpc/platforms/celleb/spu_priv1.c b/arch/powerpc/platforms/celleb/spu_priv1.c new file mode 100644 index 000000000000..2bf6700f747a --- /dev/null +++ b/arch/powerpc/platforms/celleb/spu_priv1.c | |||
@@ -0,0 +1,208 @@ | |||
1 | /* | ||
2 | * spu hypervisor abstraction for Beat | ||
3 | * | ||
4 | * (C) Copyright 2006-2007 TOSHIBA CORPORATION | ||
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 along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | |||
21 | #include <linux/module.h> | ||
22 | |||
23 | #include <asm/types.h> | ||
24 | #include <asm/spu.h> | ||
25 | #include <asm/spu_priv1.h> | ||
26 | |||
27 | #include "beat_wrapper.h" | ||
28 | |||
29 | static inline void _int_mask_set(struct spu *spu, int class, u64 mask) | ||
30 | { | ||
31 | spu->shadow_int_mask_RW[class] = mask; | ||
32 | beat_set_irq_mask_for_spe(spu->spe_id, class, mask); | ||
33 | } | ||
34 | |||
35 | static inline u64 _int_mask_get(struct spu *spu, int class) | ||
36 | { | ||
37 | return spu->shadow_int_mask_RW[class]; | ||
38 | } | ||
39 | |||
40 | static void int_mask_set(struct spu *spu, int class, u64 mask) | ||
41 | { | ||
42 | _int_mask_set(spu, class, mask); | ||
43 | } | ||
44 | |||
45 | static u64 int_mask_get(struct spu *spu, int class) | ||
46 | { | ||
47 | return _int_mask_get(spu, class); | ||
48 | } | ||
49 | |||
50 | static void int_mask_and(struct spu *spu, int class, u64 mask) | ||
51 | { | ||
52 | u64 old_mask; | ||
53 | old_mask = _int_mask_get(spu, class); | ||
54 | _int_mask_set(spu, class, old_mask & mask); | ||
55 | } | ||
56 | |||
57 | static void int_mask_or(struct spu *spu, int class, u64 mask) | ||
58 | { | ||
59 | u64 old_mask; | ||
60 | old_mask = _int_mask_get(spu, class); | ||
61 | _int_mask_set(spu, class, old_mask | mask); | ||
62 | } | ||
63 | |||
64 | static void int_stat_clear(struct spu *spu, int class, u64 stat) | ||
65 | { | ||
66 | beat_clear_interrupt_status_of_spe(spu->spe_id, class, stat); | ||
67 | } | ||
68 | |||
69 | static u64 int_stat_get(struct spu *spu, int class) | ||
70 | { | ||
71 | u64 int_stat; | ||
72 | beat_get_interrupt_status_of_spe(spu->spe_id, class, &int_stat); | ||
73 | return int_stat; | ||
74 | } | ||
75 | |||
76 | static void cpu_affinity_set(struct spu *spu, int cpu) | ||
77 | { | ||
78 | return; | ||
79 | } | ||
80 | |||
81 | static u64 mfc_dar_get(struct spu *spu) | ||
82 | { | ||
83 | u64 dar; | ||
84 | beat_get_spe_privileged_state_1_registers( | ||
85 | spu->spe_id, | ||
86 | offsetof(struct spu_priv1, mfc_dar_RW), &dar); | ||
87 | return dar; | ||
88 | } | ||
89 | |||
90 | static u64 mfc_dsisr_get(struct spu *spu) | ||
91 | { | ||
92 | u64 dsisr; | ||
93 | beat_get_spe_privileged_state_1_registers( | ||
94 | spu->spe_id, | ||
95 | offsetof(struct spu_priv1, mfc_dsisr_RW), &dsisr); | ||
96 | return dsisr; | ||
97 | } | ||
98 | |||
99 | static void mfc_dsisr_set(struct spu *spu, u64 dsisr) | ||
100 | { | ||
101 | beat_set_spe_privileged_state_1_registers( | ||
102 | spu->spe_id, | ||
103 | offsetof(struct spu_priv1, mfc_dsisr_RW), dsisr); | ||
104 | } | ||
105 | |||
106 | static void mfc_sdr_setup(struct spu *spu) | ||
107 | { | ||
108 | return; | ||
109 | } | ||
110 | |||
111 | static void mfc_sr1_set(struct spu *spu, u64 sr1) | ||
112 | { | ||
113 | beat_set_spe_privileged_state_1_registers( | ||
114 | spu->spe_id, | ||
115 | offsetof(struct spu_priv1, mfc_sr1_RW), sr1); | ||
116 | } | ||
117 | |||
118 | static u64 mfc_sr1_get(struct spu *spu) | ||
119 | { | ||
120 | u64 sr1; | ||
121 | beat_get_spe_privileged_state_1_registers( | ||
122 | spu->spe_id, | ||
123 | offsetof(struct spu_priv1, mfc_sr1_RW), &sr1); | ||
124 | return sr1; | ||
125 | } | ||
126 | |||
127 | static void mfc_tclass_id_set(struct spu *spu, u64 tclass_id) | ||
128 | { | ||
129 | beat_set_spe_privileged_state_1_registers( | ||
130 | spu->spe_id, | ||
131 | offsetof(struct spu_priv1, mfc_tclass_id_RW), tclass_id); | ||
132 | } | ||
133 | |||
134 | static u64 mfc_tclass_id_get(struct spu *spu) | ||
135 | { | ||
136 | u64 tclass_id; | ||
137 | beat_get_spe_privileged_state_1_registers( | ||
138 | spu->spe_id, | ||
139 | offsetof(struct spu_priv1, mfc_tclass_id_RW), &tclass_id); | ||
140 | return tclass_id; | ||
141 | } | ||
142 | |||
143 | static void tlb_invalidate(struct spu *spu) | ||
144 | { | ||
145 | beat_set_spe_privileged_state_1_registers( | ||
146 | spu->spe_id, | ||
147 | offsetof(struct spu_priv1, tlb_invalidate_entry_W), 0ul); | ||
148 | } | ||
149 | |||
150 | static void resource_allocation_groupID_set(struct spu *spu, u64 id) | ||
151 | { | ||
152 | beat_set_spe_privileged_state_1_registers( | ||
153 | spu->spe_id, | ||
154 | offsetof(struct spu_priv1, resource_allocation_groupID_RW), | ||
155 | id); | ||
156 | } | ||
157 | |||
158 | static u64 resource_allocation_groupID_get(struct spu *spu) | ||
159 | { | ||
160 | u64 id; | ||
161 | beat_get_spe_privileged_state_1_registers( | ||
162 | spu->spe_id, | ||
163 | offsetof(struct spu_priv1, resource_allocation_groupID_RW), | ||
164 | &id); | ||
165 | return id; | ||
166 | } | ||
167 | |||
168 | static void resource_allocation_enable_set(struct spu *spu, u64 enable) | ||
169 | { | ||
170 | beat_set_spe_privileged_state_1_registers( | ||
171 | spu->spe_id, | ||
172 | offsetof(struct spu_priv1, resource_allocation_enable_RW), | ||
173 | enable); | ||
174 | } | ||
175 | |||
176 | static u64 resource_allocation_enable_get(struct spu *spu) | ||
177 | { | ||
178 | u64 enable; | ||
179 | beat_get_spe_privileged_state_1_registers( | ||
180 | spu->spe_id, | ||
181 | offsetof(struct spu_priv1, resource_allocation_enable_RW), | ||
182 | &enable); | ||
183 | return enable; | ||
184 | } | ||
185 | |||
186 | const struct spu_priv1_ops spu_priv1_beat_ops = | ||
187 | { | ||
188 | .int_mask_and = int_mask_and, | ||
189 | .int_mask_or = int_mask_or, | ||
190 | .int_mask_set = int_mask_set, | ||
191 | .int_mask_get = int_mask_get, | ||
192 | .int_stat_clear = int_stat_clear, | ||
193 | .int_stat_get = int_stat_get, | ||
194 | .cpu_affinity_set = cpu_affinity_set, | ||
195 | .mfc_dar_get = mfc_dar_get, | ||
196 | .mfc_dsisr_get = mfc_dsisr_get, | ||
197 | .mfc_dsisr_set = mfc_dsisr_set, | ||
198 | .mfc_sdr_setup = mfc_sdr_setup, | ||
199 | .mfc_sr1_set = mfc_sr1_set, | ||
200 | .mfc_sr1_get = mfc_sr1_get, | ||
201 | .mfc_tclass_id_set = mfc_tclass_id_set, | ||
202 | .mfc_tclass_id_get = mfc_tclass_id_get, | ||
203 | .tlb_invalidate = tlb_invalidate, | ||
204 | .resource_allocation_groupID_set = resource_allocation_groupID_set, | ||
205 | .resource_allocation_groupID_get = resource_allocation_groupID_get, | ||
206 | .resource_allocation_enable_set = resource_allocation_enable_set, | ||
207 | .resource_allocation_enable_get = resource_allocation_enable_get, | ||
208 | }; | ||
diff --git a/arch/powerpc/platforms/celleb/udbg_beat.c b/arch/powerpc/platforms/celleb/udbg_beat.c new file mode 100644 index 000000000000..d888c4674c62 --- /dev/null +++ b/arch/powerpc/platforms/celleb/udbg_beat.c | |||
@@ -0,0 +1,97 @@ | |||
1 | /* | ||
2 | * udbg function for Beat | ||
3 | * | ||
4 | * (C) Copyright 2006 TOSHIBA CORPORATION | ||
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 along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | |||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/console.h> | ||
23 | |||
24 | #include <asm/machdep.h> | ||
25 | #include <asm/prom.h> | ||
26 | #include <asm/udbg.h> | ||
27 | |||
28 | #include "beat.h" | ||
29 | |||
30 | #define celleb_vtermno 0 | ||
31 | |||
32 | static void udbg_putc_beat(char c) | ||
33 | { | ||
34 | unsigned long rc; | ||
35 | |||
36 | if (c == '\n') | ||
37 | udbg_putc_beat('\r'); | ||
38 | |||
39 | rc = beat_put_term_char(celleb_vtermno, 1, (uint64_t)c << 56, 0); | ||
40 | } | ||
41 | |||
42 | /* Buffered chars getc */ | ||
43 | static long inbuflen; | ||
44 | static long inbuf[2]; /* must be 2 longs */ | ||
45 | |||
46 | static int udbg_getc_poll_beat(void) | ||
47 | { | ||
48 | /* The interface is tricky because it may return up to 16 chars. | ||
49 | * We save them statically for future calls to udbg_getc(). | ||
50 | */ | ||
51 | char ch, *buf = (char *)inbuf; | ||
52 | int i; | ||
53 | long rc; | ||
54 | if (inbuflen == 0) { | ||
55 | /* get some more chars. */ | ||
56 | inbuflen = 0; | ||
57 | rc = beat_get_term_char(celleb_vtermno, &inbuflen, inbuf+0, inbuf+1); | ||
58 | if (rc != 0) | ||
59 | inbuflen = 0; /* otherwise inbuflen is garbage */ | ||
60 | } | ||
61 | if (inbuflen <= 0 || inbuflen > 16) { | ||
62 | /* Catch error case as well as other oddities (corruption) */ | ||
63 | inbuflen = 0; | ||
64 | return -1; | ||
65 | } | ||
66 | ch = buf[0]; | ||
67 | for (i = 1; i < inbuflen; i++) /* shuffle them down. */ | ||
68 | buf[i-1] = buf[i]; | ||
69 | inbuflen--; | ||
70 | return ch; | ||
71 | } | ||
72 | |||
73 | static int udbg_getc_beat(void) | ||
74 | { | ||
75 | int ch; | ||
76 | for (;;) { | ||
77 | ch = udbg_getc_poll_beat(); | ||
78 | if (ch == -1) { | ||
79 | /* This shouldn't be needed...but... */ | ||
80 | volatile unsigned long delay; | ||
81 | for (delay=0; delay < 2000000; delay++) | ||
82 | ; | ||
83 | } else { | ||
84 | return ch; | ||
85 | } | ||
86 | } | ||
87 | } | ||
88 | |||
89 | /* call this from early_init() for a working debug console on | ||
90 | * vterm capable LPAR machines | ||
91 | */ | ||
92 | void __init udbg_init_debug_beat(void) | ||
93 | { | ||
94 | udbg_putc = udbg_putc_beat; | ||
95 | udbg_getc = udbg_getc_beat; | ||
96 | udbg_getc_poll = udbg_getc_poll_beat; | ||
97 | } | ||
diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c index e1f51d455984..117c9a0055bd 100644 --- a/arch/powerpc/platforms/chrp/setup.c +++ b/arch/powerpc/platforms/chrp/setup.c | |||
@@ -75,7 +75,7 @@ extern irqreturn_t xmon_irq(int, void *); | |||
75 | extern unsigned long loops_per_jiffy; | 75 | extern unsigned long loops_per_jiffy; |
76 | 76 | ||
77 | /* To be replaced by RTAS when available */ | 77 | /* To be replaced by RTAS when available */ |
78 | static unsigned int *briq_SPOR; | 78 | static unsigned int __iomem *briq_SPOR; |
79 | 79 | ||
80 | #ifdef CONFIG_SMP | 80 | #ifdef CONFIG_SMP |
81 | extern struct smp_ops_t chrp_smp_ops; | 81 | extern struct smp_ops_t chrp_smp_ops; |
@@ -267,7 +267,7 @@ void __init chrp_setup_arch(void) | |||
267 | } else if (machine && strncmp(machine, "TotalImpact,BRIQ-1", 18) == 0) { | 267 | } else if (machine && strncmp(machine, "TotalImpact,BRIQ-1", 18) == 0) { |
268 | _chrp_type = _CHRP_briq; | 268 | _chrp_type = _CHRP_briq; |
269 | /* Map the SPOR register on briq and change the restart hook */ | 269 | /* Map the SPOR register on briq and change the restart hook */ |
270 | briq_SPOR = (unsigned int *)ioremap(0xff0000e8, 4); | 270 | briq_SPOR = ioremap(0xff0000e8, 4); |
271 | ppc_md.restart = briq_restart; | 271 | ppc_md.restart = briq_restart; |
272 | } else { | 272 | } else { |
273 | /* Let's assume it is an IBM chrp if all else fails */ | 273 | /* Let's assume it is an IBM chrp if all else fails */ |
diff --git a/arch/powerpc/platforms/embedded6xx/Kconfig b/arch/powerpc/platforms/embedded6xx/Kconfig index b3c2ce4cb7a8..886c522d78e9 100644 --- a/arch/powerpc/platforms/embedded6xx/Kconfig +++ b/arch/powerpc/platforms/embedded6xx/Kconfig | |||
@@ -104,15 +104,6 @@ config RADSTONE_PPC7D | |||
104 | config PAL4 | 104 | config PAL4 |
105 | bool "SBS-Palomar4" | 105 | bool "SBS-Palomar4" |
106 | 106 | ||
107 | config GEMINI | ||
108 | bool "Synergy-Gemini" | ||
109 | select PPC_INDIRECT_PCI | ||
110 | depends on BROKEN | ||
111 | help | ||
112 | Select Gemini if configuring for a Synergy Microsystems' Gemini | ||
113 | series Single Board Computer. More information is available at: | ||
114 | <http://www.synergymicro.com/PressRel/97_10_15.html>. | ||
115 | |||
116 | config EST8260 | 107 | config EST8260 |
117 | bool "EST8260" | 108 | bool "EST8260" |
118 | ---help--- | 109 | ---help--- |
diff --git a/arch/powerpc/platforms/embedded6xx/linkstation.c b/arch/powerpc/platforms/embedded6xx/linkstation.c index 61599d919ea8..3f6c4114f908 100644 --- a/arch/powerpc/platforms/embedded6xx/linkstation.c +++ b/arch/powerpc/platforms/embedded6xx/linkstation.c | |||
@@ -13,7 +13,6 @@ | |||
13 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
14 | #include <linux/pci.h> | 14 | #include <linux/pci.h> |
15 | #include <linux/initrd.h> | 15 | #include <linux/initrd.h> |
16 | #include <linux/root_dev.h> | ||
17 | #include <linux/mtd/physmap.h> | 16 | #include <linux/mtd/physmap.h> |
18 | 17 | ||
19 | #include <asm/time.h> | 18 | #include <asm/time.h> |
@@ -91,17 +90,6 @@ static void __init linkstation_setup_arch(void) | |||
91 | ARRAY_SIZE(linkstation_physmap_partitions)); | 90 | ARRAY_SIZE(linkstation_physmap_partitions)); |
92 | #endif | 91 | #endif |
93 | 92 | ||
94 | #ifdef CONFIG_BLK_DEV_INITRD | ||
95 | if (initrd_start) | ||
96 | ROOT_DEV = Root_RAM0; | ||
97 | else | ||
98 | #endif | ||
99 | #ifdef CONFIG_ROOT_NFS | ||
100 | ROOT_DEV = Root_NFS; | ||
101 | #else | ||
102 | ROOT_DEV = Root_HDA1; | ||
103 | #endif | ||
104 | |||
105 | /* Lookup PCI host bridges */ | 93 | /* Lookup PCI host bridges */ |
106 | for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) | 94 | for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;) |
107 | add_bridge(np); | 95 | add_bridge(np); |
diff --git a/arch/powerpc/platforms/iseries/lpevents.c b/arch/powerpc/platforms/iseries/lpevents.c index c1f4502a3c6a..91df52a1899a 100644 --- a/arch/powerpc/platforms/iseries/lpevents.c +++ b/arch/powerpc/platforms/iseries/lpevents.c | |||
@@ -308,7 +308,7 @@ static int proc_lpevents_open(struct inode *inode, struct file *file) | |||
308 | return single_open(file, proc_lpevents_show, NULL); | 308 | return single_open(file, proc_lpevents_show, NULL); |
309 | } | 309 | } |
310 | 310 | ||
311 | static struct file_operations proc_lpevents_operations = { | 311 | static const struct file_operations proc_lpevents_operations = { |
312 | .open = proc_lpevents_open, | 312 | .open = proc_lpevents_open, |
313 | .read = seq_read, | 313 | .read = seq_read, |
314 | .llseek = seq_lseek, | 314 | .llseek = seq_lseek, |
diff --git a/arch/powerpc/platforms/iseries/mf.c b/arch/powerpc/platforms/iseries/mf.c index 1ad0e4aaad1a..b1187d95e3b2 100644 --- a/arch/powerpc/platforms/iseries/mf.c +++ b/arch/powerpc/platforms/iseries/mf.c | |||
@@ -1224,7 +1224,7 @@ out: | |||
1224 | return rc; | 1224 | return rc; |
1225 | } | 1225 | } |
1226 | 1226 | ||
1227 | static struct file_operations proc_vmlinux_operations = { | 1227 | static const struct file_operations proc_vmlinux_operations = { |
1228 | .write = proc_mf_change_vmlinux, | 1228 | .write = proc_mf_change_vmlinux, |
1229 | }; | 1229 | }; |
1230 | 1230 | ||
@@ -1253,7 +1253,6 @@ static int __init mf_proc_init(void) | |||
1253 | ent = create_proc_entry("cmdline", S_IFREG|S_IRUSR|S_IWUSR, mf); | 1253 | ent = create_proc_entry("cmdline", S_IFREG|S_IRUSR|S_IWUSR, mf); |
1254 | if (!ent) | 1254 | if (!ent) |
1255 | return 1; | 1255 | return 1; |
1256 | ent->nlink = 1; | ||
1257 | ent->data = (void *)(long)i; | 1256 | ent->data = (void *)(long)i; |
1258 | ent->read_proc = proc_mf_dump_cmdline; | 1257 | ent->read_proc = proc_mf_dump_cmdline; |
1259 | ent->write_proc = proc_mf_change_cmdline; | 1258 | ent->write_proc = proc_mf_change_cmdline; |
@@ -1264,7 +1263,6 @@ static int __init mf_proc_init(void) | |||
1264 | ent = create_proc_entry("vmlinux", S_IFREG|S_IWUSR, mf); | 1263 | ent = create_proc_entry("vmlinux", S_IFREG|S_IWUSR, mf); |
1265 | if (!ent) | 1264 | if (!ent) |
1266 | return 1; | 1265 | return 1; |
1267 | ent->nlink = 1; | ||
1268 | ent->data = (void *)(long)i; | 1266 | ent->data = (void *)(long)i; |
1269 | ent->proc_fops = &proc_vmlinux_operations; | 1267 | ent->proc_fops = &proc_vmlinux_operations; |
1270 | } | 1268 | } |
@@ -1272,7 +1270,6 @@ static int __init mf_proc_init(void) | |||
1272 | ent = create_proc_entry("side", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root); | 1270 | ent = create_proc_entry("side", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root); |
1273 | if (!ent) | 1271 | if (!ent) |
1274 | return 1; | 1272 | return 1; |
1275 | ent->nlink = 1; | ||
1276 | ent->data = (void *)0; | 1273 | ent->data = (void *)0; |
1277 | ent->read_proc = proc_mf_dump_side; | 1274 | ent->read_proc = proc_mf_dump_side; |
1278 | ent->write_proc = proc_mf_change_side; | 1275 | ent->write_proc = proc_mf_change_side; |
@@ -1280,7 +1277,6 @@ static int __init mf_proc_init(void) | |||
1280 | ent = create_proc_entry("src", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root); | 1277 | ent = create_proc_entry("src", S_IFREG|S_IRUSR|S_IWUSR, mf_proc_root); |
1281 | if (!ent) | 1278 | if (!ent) |
1282 | return 1; | 1279 | return 1; |
1283 | ent->nlink = 1; | ||
1284 | ent->data = (void *)0; | 1280 | ent->data = (void *)0; |
1285 | ent->read_proc = proc_mf_dump_src; | 1281 | ent->read_proc = proc_mf_dump_src; |
1286 | ent->write_proc = proc_mf_change_src; | 1282 | ent->write_proc = proc_mf_change_src; |
diff --git a/arch/powerpc/platforms/iseries/proc.c b/arch/powerpc/platforms/iseries/proc.c index b54e37101e69..f2cde4180204 100644 --- a/arch/powerpc/platforms/iseries/proc.c +++ b/arch/powerpc/platforms/iseries/proc.c | |||
@@ -101,7 +101,7 @@ static int proc_titantod_open(struct inode *inode, struct file *file) | |||
101 | return single_open(file, proc_titantod_show, NULL); | 101 | return single_open(file, proc_titantod_show, NULL); |
102 | } | 102 | } |
103 | 103 | ||
104 | static struct file_operations proc_titantod_operations = { | 104 | static const struct file_operations proc_titantod_operations = { |
105 | .open = proc_titantod_open, | 105 | .open = proc_titantod_open, |
106 | .read = seq_read, | 106 | .read = seq_read, |
107 | .llseek = seq_lseek, | 107 | .llseek = seq_lseek, |
diff --git a/arch/powerpc/platforms/iseries/viopath.c b/arch/powerpc/platforms/iseries/viopath.c index a6799ed34a66..e2100ece9c65 100644 --- a/arch/powerpc/platforms/iseries/viopath.c +++ b/arch/powerpc/platforms/iseries/viopath.c | |||
@@ -173,7 +173,7 @@ static int proc_viopath_open(struct inode *inode, struct file *file) | |||
173 | return single_open(file, proc_viopath_show, NULL); | 173 | return single_open(file, proc_viopath_show, NULL); |
174 | } | 174 | } |
175 | 175 | ||
176 | static struct file_operations proc_viopath_operations = { | 176 | static const struct file_operations proc_viopath_operations = { |
177 | .open = proc_viopath_open, | 177 | .open = proc_viopath_open, |
178 | .read = seq_read, | 178 | .read = seq_read, |
179 | .llseek = seq_lseek, | 179 | .llseek = seq_lseek, |
diff --git a/arch/powerpc/platforms/maple/pci.c b/arch/powerpc/platforms/maple/pci.c index 3f6a69f67195..73c59904697f 100644 --- a/arch/powerpc/platforms/maple/pci.c +++ b/arch/powerpc/platforms/maple/pci.c | |||
@@ -425,14 +425,6 @@ static void __init setup_u4_pcie(struct pci_controller* hose) | |||
425 | hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000); | 425 | hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000); |
426 | hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000); | 426 | hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000); |
427 | 427 | ||
428 | /* The bus contains a bridge from root -> device, we need to | ||
429 | * make it visible on bus 0 so that we pick the right type | ||
430 | * of config cycles. If we didn't, we would have to force all | ||
431 | * config cycles to be type 1. So we override the "bus-range" | ||
432 | * property here | ||
433 | */ | ||
434 | hose->first_busno = 0x00; | ||
435 | hose->last_busno = 0xff; | ||
436 | u4_pcie = hose; | 428 | u4_pcie = hose; |
437 | } | 429 | } |
438 | 430 | ||
@@ -560,13 +552,16 @@ void __init maple_pci_init(void) | |||
560 | return; | 552 | return; |
561 | } | 553 | } |
562 | for (np = NULL; (np = of_get_next_child(root, np)) != NULL;) { | 554 | for (np = NULL; (np = of_get_next_child(root, np)) != NULL;) { |
563 | if (np->name == NULL) | 555 | if (!np->type) |
564 | continue; | 556 | continue; |
565 | if (!strcmp(np->name, "pci") || !strcmp(np->name, "pcie")) { | 557 | if (strcmp(np->type, "pci") && strcmp(np->type, "ht")) |
566 | if (add_bridge(np) == 0) | 558 | continue; |
567 | of_node_get(np); | 559 | if ((device_is_compatible(np, "u4-pcie") || |
568 | } | 560 | device_is_compatible(np, "u3-agp")) && |
569 | if (strcmp(np->name, "ht") == 0) { | 561 | add_bridge(np) == 0) |
562 | of_node_get(np); | ||
563 | |||
564 | if (device_is_compatible(np, "u3-ht")) { | ||
570 | of_node_get(np); | 565 | of_node_get(np); |
571 | ht = np; | 566 | ht = np; |
572 | } | 567 | } |
diff --git a/arch/powerpc/platforms/maple/setup.c b/arch/powerpc/platforms/maple/setup.c index 50855d4fd5a0..82d3f9e28d7c 100644 --- a/arch/powerpc/platforms/maple/setup.c +++ b/arch/powerpc/platforms/maple/setup.c | |||
@@ -62,6 +62,7 @@ | |||
62 | #include <asm/mpic.h> | 62 | #include <asm/mpic.h> |
63 | #include <asm/rtas.h> | 63 | #include <asm/rtas.h> |
64 | #include <asm/udbg.h> | 64 | #include <asm/udbg.h> |
65 | #include <asm/nvram.h> | ||
65 | 66 | ||
66 | #include "maple.h" | 67 | #include "maple.h" |
67 | 68 | ||
@@ -195,6 +196,8 @@ void __init maple_setup_arch(void) | |||
195 | maple_use_rtas_reboot_and_halt_if_present(); | 196 | maple_use_rtas_reboot_and_halt_if_present(); |
196 | 197 | ||
197 | printk(KERN_DEBUG "Using native/NAP idle loop\n"); | 198 | printk(KERN_DEBUG "Using native/NAP idle loop\n"); |
199 | |||
200 | mmio_nvram_init(); | ||
198 | } | 201 | } |
199 | 202 | ||
200 | /* | 203 | /* |
diff --git a/arch/powerpc/platforms/pasemi/Kconfig b/arch/powerpc/platforms/pasemi/Kconfig new file mode 100644 index 000000000000..68dc529dfd2f --- /dev/null +++ b/arch/powerpc/platforms/pasemi/Kconfig | |||
@@ -0,0 +1,10 @@ | |||
1 | menu "PA Semi PWRficient options" | ||
2 | depends on PPC_PASEMI | ||
3 | |||
4 | config PPC_PASEMI_IOMMU | ||
5 | bool "PA Semi IOMMU support" | ||
6 | depends on PPC_PASEMI | ||
7 | help | ||
8 | IOMMU support for PA6T-1682M | ||
9 | |||
10 | endmenu | ||
diff --git a/arch/powerpc/platforms/pasemi/Makefile b/arch/powerpc/platforms/pasemi/Makefile index 1be1a993c5f5..e657ccae90a9 100644 --- a/arch/powerpc/platforms/pasemi/Makefile +++ b/arch/powerpc/platforms/pasemi/Makefile | |||
@@ -1 +1,2 @@ | |||
1 | obj-y += setup.o pci.o time.o | 1 | obj-y += setup.o pci.o time.o idle.o powersave.o iommu.o |
2 | |||
diff --git a/arch/powerpc/platforms/pasemi/idle.c b/arch/powerpc/platforms/pasemi/idle.c new file mode 100644 index 000000000000..1ca3ff381591 --- /dev/null +++ b/arch/powerpc/platforms/pasemi/idle.c | |||
@@ -0,0 +1,88 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2006-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 | |||
21 | #undef DEBUG | ||
22 | |||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/string.h> | ||
25 | |||
26 | #include <asm/machdep.h> | ||
27 | #include <asm/reg.h> | ||
28 | |||
29 | #include "pasemi.h" | ||
30 | |||
31 | struct sleep_mode { | ||
32 | char *name; | ||
33 | void (*entry)(void); | ||
34 | }; | ||
35 | |||
36 | static struct sleep_mode modes[] = { | ||
37 | { .name = "spin", .entry = &idle_spin }, | ||
38 | { .name = "doze", .entry = &idle_doze }, | ||
39 | }; | ||
40 | |||
41 | static int current_mode = 0; | ||
42 | |||
43 | static int pasemi_system_reset_exception(struct pt_regs *regs) | ||
44 | { | ||
45 | /* If we were woken up from power savings, we need to return | ||
46 | * to the calling function, since nip is not saved across | ||
47 | * all modes. | ||
48 | */ | ||
49 | |||
50 | if (regs->msr & SRR1_WAKEMASK) | ||
51 | regs->nip = regs->link; | ||
52 | |||
53 | switch (regs->msr & SRR1_WAKEMASK) { | ||
54 | case SRR1_WAKEEE: | ||
55 | do_IRQ(regs); | ||
56 | break; | ||
57 | case SRR1_WAKEDEC: | ||
58 | timer_interrupt(regs); | ||
59 | break; | ||
60 | default: | ||
61 | /* do system reset */ | ||
62 | return 0; | ||
63 | } | ||
64 | /* everything handled */ | ||
65 | regs->msr |= MSR_RI; | ||
66 | return 1; | ||
67 | } | ||
68 | |||
69 | void __init pasemi_idle_init(void) | ||
70 | { | ||
71 | ppc_md.system_reset_exception = pasemi_system_reset_exception; | ||
72 | ppc_md.power_save = modes[current_mode].entry; | ||
73 | printk(KERN_INFO "Using PA6T idle loop (%s)\n", modes[current_mode].name); | ||
74 | } | ||
75 | |||
76 | static int __init idle_param(char *p) | ||
77 | { | ||
78 | int i; | ||
79 | for (i = 0; i < sizeof(modes)/sizeof(struct sleep_mode); i++) { | ||
80 | if (!strcmp(modes[i].name, p)) { | ||
81 | current_mode = i; | ||
82 | break; | ||
83 | } | ||
84 | } | ||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | early_param("idle", idle_param); | ||
diff --git a/arch/powerpc/platforms/pasemi/iommu.c b/arch/powerpc/platforms/pasemi/iommu.c new file mode 100644 index 000000000000..459a53b7d24d --- /dev/null +++ b/arch/powerpc/platforms/pasemi/iommu.c | |||
@@ -0,0 +1,281 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005-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 | #undef DEBUG | ||
21 | |||
22 | #include <linux/types.h> | ||
23 | #include <linux/spinlock.h> | ||
24 | #include <linux/pci.h> | ||
25 | #include <asm/iommu.h> | ||
26 | #include <asm/machdep.h> | ||
27 | #include <asm/abs_addr.h> | ||
28 | |||
29 | |||
30 | #define IOBMAP_PAGE_SHIFT 12 | ||
31 | #define IOBMAP_PAGE_SIZE (1 << IOBMAP_PAGE_SHIFT) | ||
32 | #define IOBMAP_PAGE_MASK (IOBMAP_PAGE_SIZE - 1) | ||
33 | |||
34 | #define IOBMAP_PAGE_FACTOR (PAGE_SHIFT - IOBMAP_PAGE_SHIFT) | ||
35 | |||
36 | #define IOB_BASE 0xe0000000 | ||
37 | #define IOB_SIZE 0x3000 | ||
38 | /* Configuration registers */ | ||
39 | #define IOBCAP_REG 0x10 | ||
40 | #define IOBCOM_REG 0x40 | ||
41 | /* Enable IOB address translation */ | ||
42 | #define IOBCOM_ATEN 0x00000100 | ||
43 | |||
44 | /* Address decode configuration register */ | ||
45 | #define IOB_AD_REG 0x53 | ||
46 | /* IOBCOM_AD_REG fields */ | ||
47 | #define IOB_AD_VGPRT 0x00000e00 | ||
48 | #define IOB_AD_VGAEN 0x00000100 | ||
49 | /* Direct mapping settings */ | ||
50 | #define IOB_AD_MPSEL_MASK 0x00000030 | ||
51 | #define IOB_AD_MPSEL_B38 0x00000000 | ||
52 | #define IOB_AD_MPSEL_B40 0x00000010 | ||
53 | #define IOB_AD_MPSEL_B42 0x00000020 | ||
54 | /* Translation window size / enable */ | ||
55 | #define IOB_AD_TRNG_MASK 0x00000003 | ||
56 | #define IOB_AD_TRNG_256M 0x00000000 | ||
57 | #define IOB_AD_TRNG_2G 0x00000001 | ||
58 | #define IOB_AD_TRNG_128G 0x00000003 | ||
59 | |||
60 | #define IOB_TABLEBASE_REG 0x55 | ||
61 | |||
62 | /* Base of the 64 4-byte L1 registers */ | ||
63 | #define IOB_XLT_L1_REGBASE 0xac0 | ||
64 | |||
65 | /* Register to invalidate TLB entries */ | ||
66 | #define IOB_AT_INVAL_TLB_REG 0xb40 | ||
67 | |||
68 | /* The top two bits of the level 1 entry contains valid and type flags */ | ||
69 | #define IOBMAP_L1E_V 0x40000000 | ||
70 | #define IOBMAP_L1E_V_B 0x80000000 | ||
71 | |||
72 | /* For big page entries, the bottom two bits contains flags */ | ||
73 | #define IOBMAP_L1E_BIG_CACHED 0x00000002 | ||
74 | #define IOBMAP_L1E_BIG_PRIORITY 0x00000001 | ||
75 | |||
76 | /* For regular level 2 entries, top 2 bits contain valid and cache flags */ | ||
77 | #define IOBMAP_L2E_V 0x80000000 | ||
78 | #define IOBMAP_L2E_V_CACHED 0xc0000000 | ||
79 | |||
80 | static u32 *iob; | ||
81 | static u32 iob_l1_emptyval; | ||
82 | static u32 iob_l2_emptyval; | ||
83 | static u32 *iob_l2_base; | ||
84 | |||
85 | static struct iommu_table iommu_table_iobmap; | ||
86 | static int iommu_table_iobmap_inited; | ||
87 | |||
88 | static void iobmap_build(struct iommu_table *tbl, long index, | ||
89 | long npages, unsigned long uaddr, | ||
90 | enum dma_data_direction direction) | ||
91 | { | ||
92 | u32 *ip; | ||
93 | u32 rpn; | ||
94 | unsigned long bus_addr; | ||
95 | |||
96 | pr_debug("iobmap: build at: %lx, %lx, addr: %lx\n", index, npages, uaddr); | ||
97 | |||
98 | bus_addr = (tbl->it_offset + index) << PAGE_SHIFT; | ||
99 | |||
100 | npages <<= IOBMAP_PAGE_FACTOR; | ||
101 | index <<= IOBMAP_PAGE_FACTOR; | ||
102 | |||
103 | ip = ((u32 *)tbl->it_base) + index; | ||
104 | |||
105 | while (npages--) { | ||
106 | rpn = virt_to_abs(uaddr) >> IOBMAP_PAGE_SHIFT; | ||
107 | |||
108 | *(ip++) = IOBMAP_L2E_V | rpn; | ||
109 | /* invalidate tlb, can be optimized more */ | ||
110 | out_le32(iob+IOB_AT_INVAL_TLB_REG, bus_addr >> 14); | ||
111 | |||
112 | uaddr += IOBMAP_PAGE_SIZE; | ||
113 | bus_addr += IOBMAP_PAGE_SIZE; | ||
114 | } | ||
115 | } | ||
116 | |||
117 | |||
118 | static void iobmap_free(struct iommu_table *tbl, long index, | ||
119 | long npages) | ||
120 | { | ||
121 | u32 *ip; | ||
122 | unsigned long bus_addr; | ||
123 | |||
124 | pr_debug("iobmap: free at: %lx, %lx\n", index, npages); | ||
125 | |||
126 | bus_addr = (tbl->it_offset + index) << PAGE_SHIFT; | ||
127 | |||
128 | npages <<= IOBMAP_PAGE_FACTOR; | ||
129 | index <<= IOBMAP_PAGE_FACTOR; | ||
130 | |||
131 | ip = ((u32 *)tbl->it_base) + index; | ||
132 | |||
133 | while (npages--) { | ||
134 | *(ip++) = iob_l2_emptyval; | ||
135 | /* invalidate tlb, can be optimized more */ | ||
136 | out_le32(iob+IOB_AT_INVAL_TLB_REG, bus_addr >> 14); | ||
137 | bus_addr += IOBMAP_PAGE_SIZE; | ||
138 | } | ||
139 | } | ||
140 | |||
141 | |||
142 | static void iommu_table_iobmap_setup(void) | ||
143 | { | ||
144 | pr_debug(" -> %s\n", __func__); | ||
145 | iommu_table_iobmap.it_busno = 0; | ||
146 | iommu_table_iobmap.it_offset = 0; | ||
147 | /* it_size is in number of entries */ | ||
148 | iommu_table_iobmap.it_size = 0x80000000 >> PAGE_SHIFT; | ||
149 | |||
150 | /* Initialize the common IOMMU code */ | ||
151 | iommu_table_iobmap.it_base = (unsigned long)iob_l2_base; | ||
152 | iommu_table_iobmap.it_index = 0; | ||
153 | /* XXXOJN tune this to avoid IOB cache invals. | ||
154 | * Should probably be 8 (64 bytes) | ||
155 | */ | ||
156 | iommu_table_iobmap.it_blocksize = 4; | ||
157 | iommu_init_table(&iommu_table_iobmap, 0); | ||
158 | pr_debug(" <- %s\n", __func__); | ||
159 | } | ||
160 | |||
161 | |||
162 | |||
163 | static void pci_dma_bus_setup_pasemi(struct pci_bus *bus) | ||
164 | { | ||
165 | struct device_node *dn; | ||
166 | |||
167 | pr_debug("pci_dma_bus_setup, bus %p, bus->self %p\n", bus, bus->self); | ||
168 | |||
169 | if (!iommu_table_iobmap_inited) { | ||
170 | iommu_table_iobmap_inited = 1; | ||
171 | iommu_table_iobmap_setup(); | ||
172 | } | ||
173 | |||
174 | dn = pci_bus_to_OF_node(bus); | ||
175 | |||
176 | if (dn) | ||
177 | PCI_DN(dn)->iommu_table = &iommu_table_iobmap; | ||
178 | |||
179 | } | ||
180 | |||
181 | |||
182 | static void pci_dma_dev_setup_pasemi(struct pci_dev *dev) | ||
183 | { | ||
184 | pr_debug("pci_dma_dev_setup, dev %p (%s)\n", dev, pci_name(dev)); | ||
185 | |||
186 | /* DMA device is untranslated, but all other PCI-e goes through | ||
187 | * the IOMMU | ||
188 | */ | ||
189 | if (dev->vendor == 0x1959 && dev->device == 0xa007) | ||
190 | dev->dev.archdata.dma_ops = &dma_direct_ops; | ||
191 | else | ||
192 | dev->dev.archdata.dma_data = &iommu_table_iobmap; | ||
193 | } | ||
194 | |||
195 | static void pci_dma_bus_setup_null(struct pci_bus *b) { } | ||
196 | static void pci_dma_dev_setup_null(struct pci_dev *d) { } | ||
197 | |||
198 | int iob_init(struct device_node *dn) | ||
199 | { | ||
200 | unsigned long tmp; | ||
201 | u32 regword; | ||
202 | int i; | ||
203 | |||
204 | pr_debug(" -> %s\n", __func__); | ||
205 | |||
206 | /* Allocate a spare page to map all invalid IOTLB pages. */ | ||
207 | tmp = lmb_alloc(IOBMAP_PAGE_SIZE, IOBMAP_PAGE_SIZE); | ||
208 | if (!tmp) | ||
209 | panic("IOBMAP: Cannot allocate spare page!"); | ||
210 | /* Empty l1 is marked invalid */ | ||
211 | iob_l1_emptyval = 0; | ||
212 | /* Empty l2 is mapped to dummy page */ | ||
213 | iob_l2_emptyval = IOBMAP_L2E_V | (tmp >> IOBMAP_PAGE_SHIFT); | ||
214 | |||
215 | iob = ioremap(IOB_BASE, IOB_SIZE); | ||
216 | if (!iob) | ||
217 | panic("IOBMAP: Cannot map registers!"); | ||
218 | |||
219 | /* setup direct mapping of the L1 entries */ | ||
220 | for (i = 0; i < 64; i++) { | ||
221 | /* Each L1 covers 32MB, i.e. 8K entries = 32K of ram */ | ||
222 | regword = IOBMAP_L1E_V | (__pa(iob_l2_base + i*0x2000) >> 12); | ||
223 | out_le32(iob+IOB_XLT_L1_REGBASE+i, regword); | ||
224 | } | ||
225 | |||
226 | /* set 2GB translation window, based at 0 */ | ||
227 | regword = in_le32(iob+IOB_AD_REG); | ||
228 | regword &= ~IOB_AD_TRNG_MASK; | ||
229 | regword |= IOB_AD_TRNG_2G; | ||
230 | out_le32(iob+IOB_AD_REG, regword); | ||
231 | |||
232 | /* Enable translation */ | ||
233 | regword = in_le32(iob+IOBCOM_REG); | ||
234 | regword |= IOBCOM_ATEN; | ||
235 | out_le32(iob+IOBCOM_REG, regword); | ||
236 | |||
237 | pr_debug(" <- %s\n", __func__); | ||
238 | |||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | |||
243 | /* These are called very early. */ | ||
244 | void iommu_init_early_pasemi(void) | ||
245 | { | ||
246 | int iommu_off; | ||
247 | |||
248 | #ifndef CONFIG_PPC_PASEMI_IOMMU | ||
249 | iommu_off = 1; | ||
250 | #else | ||
251 | iommu_off = of_chosen && | ||
252 | get_property(of_chosen, "linux,iommu-off", NULL); | ||
253 | #endif | ||
254 | if (iommu_off) { | ||
255 | /* Direct I/O, IOMMU off */ | ||
256 | ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_null; | ||
257 | ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_null; | ||
258 | pci_dma_ops = &dma_direct_ops; | ||
259 | |||
260 | return; | ||
261 | } | ||
262 | |||
263 | iob_init(NULL); | ||
264 | |||
265 | ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_pasemi; | ||
266 | ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_pasemi; | ||
267 | ppc_md.tce_build = iobmap_build; | ||
268 | ppc_md.tce_free = iobmap_free; | ||
269 | pci_dma_ops = &dma_iommu_ops; | ||
270 | } | ||
271 | |||
272 | void __init alloc_iobmap_l2(void) | ||
273 | { | ||
274 | #ifndef CONFIG_PPC_PASEMI_IOMMU | ||
275 | return; | ||
276 | #endif | ||
277 | /* For 2G space, 8x64 pages (2^21 bytes) is max total l2 size */ | ||
278 | iob_l2_base = (u32 *)abs_to_virt(lmb_alloc_base(1UL<<21, 1UL<<21, 0x80000000)); | ||
279 | |||
280 | printk(KERN_INFO "IOBMAP L2 allocated at: %p\n", iob_l2_base); | ||
281 | } | ||
diff --git a/arch/powerpc/platforms/pasemi/pasemi.h b/arch/powerpc/platforms/pasemi/pasemi.h index 51c2a2397ecf..2d3927e6edb0 100644 --- a/arch/powerpc/platforms/pasemi/pasemi.h +++ b/arch/powerpc/platforms/pasemi/pasemi.h | |||
@@ -3,5 +3,17 @@ | |||
3 | 3 | ||
4 | extern unsigned long pas_get_boot_time(void); | 4 | extern unsigned long pas_get_boot_time(void); |
5 | extern void pas_pci_init(void); | 5 | extern void pas_pci_init(void); |
6 | extern void __devinit pas_pci_irq_fixup(struct pci_dev *dev); | ||
7 | extern void __devinit pas_pci_dma_dev_setup(struct pci_dev *dev); | ||
8 | |||
9 | extern void __init alloc_iobmap_l2(void); | ||
10 | |||
11 | extern void __init pasemi_idle_init(void); | ||
12 | |||
13 | /* Power savings modes, implemented in asm */ | ||
14 | extern void idle_spin(void); | ||
15 | extern void idle_doze(void); | ||
16 | |||
17 | |||
6 | 18 | ||
7 | #endif /* _PASEMI_PASEMI_H */ | 19 | #endif /* _PASEMI_PASEMI_H */ |
diff --git a/arch/powerpc/platforms/pasemi/pci.c b/arch/powerpc/platforms/pasemi/pci.c index faa618e04047..7ecb2ba24db9 100644 --- a/arch/powerpc/platforms/pasemi/pci.c +++ b/arch/powerpc/platforms/pasemi/pci.c | |||
@@ -163,6 +163,19 @@ static void __init pas_fixup_phb_resources(void) | |||
163 | } | 163 | } |
164 | 164 | ||
165 | 165 | ||
166 | void __devinit pas_pci_irq_fixup(struct pci_dev *dev) | ||
167 | { | ||
168 | /* DMA is special, 84 interrupts (128 -> 211), all but 128 | ||
169 | * need to be mapped by hand here. | ||
170 | */ | ||
171 | if (dev->vendor == 0x1959 && dev->device == 0xa007) { | ||
172 | int i; | ||
173 | for (i = 129; i < 212; i++) | ||
174 | irq_create_mapping(NULL, i); | ||
175 | } | ||
176 | } | ||
177 | |||
178 | |||
166 | void __init pas_pci_init(void) | 179 | void __init pas_pci_init(void) |
167 | { | 180 | { |
168 | struct device_node *np, *root; | 181 | struct device_node *np, *root; |
diff --git a/arch/powerpc/platforms/pasemi/powersave.S b/arch/powerpc/platforms/pasemi/powersave.S new file mode 100644 index 000000000000..6d0fba6aab17 --- /dev/null +++ b/arch/powerpc/platforms/pasemi/powersave.S | |||
@@ -0,0 +1,80 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2006-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 | |||
21 | #include <asm/processor.h> | ||
22 | #include <asm/page.h> | ||
23 | #include <asm/ppc_asm.h> | ||
24 | #include <asm/cputable.h> | ||
25 | #include <asm/cache.h> | ||
26 | #include <asm/thread_info.h> | ||
27 | #include <asm/asm-offsets.h> | ||
28 | |||
29 | /* Power savings opcodes since not all binutils have them at this time */ | ||
30 | #define DOZE .long 0x4c000324 | ||
31 | #define NAP .long 0x4c000364 | ||
32 | #define SLEEP .long 0x4c0003a4 | ||
33 | #define RVW .long 0x4c0003e4 | ||
34 | |||
35 | /* Common sequence to do before going to any of the | ||
36 | * powersavings modes. | ||
37 | */ | ||
38 | |||
39 | #define PRE_SLEEP_SEQUENCE \ | ||
40 | std r3,8(r1); \ | ||
41 | ptesync ; \ | ||
42 | ld r3,8(r1); \ | ||
43 | 1: cmpd r3,r3; \ | ||
44 | bne 1b | ||
45 | |||
46 | _doze: | ||
47 | PRE_SLEEP_SEQUENCE | ||
48 | DOZE | ||
49 | b . | ||
50 | |||
51 | |||
52 | _GLOBAL(idle_spin) | ||
53 | blr | ||
54 | |||
55 | _GLOBAL(idle_doze) | ||
56 | LOAD_REG_ADDR(r3, _doze) | ||
57 | b sleep_common | ||
58 | |||
59 | /* Add more modes here later */ | ||
60 | |||
61 | sleep_common: | ||
62 | mflr r0 | ||
63 | std r0, 16(r1) | ||
64 | stdu r1,-64(r1) | ||
65 | |||
66 | LOAD_REG_IMMEDIATE(r6,MSR_DR|MSR_IR|MSR_ME|MSR_EE) | ||
67 | mfmsr r4 | ||
68 | andc r5,r4,r6 | ||
69 | mtmsrd r5,0 | ||
70 | |||
71 | mtctr r3 | ||
72 | bctrl | ||
73 | |||
74 | mtmsrd r4,0 | ||
75 | |||
76 | addi r1,r1,64 | ||
77 | ld r0,16(r1) | ||
78 | mtlr r0 | ||
79 | blr | ||
80 | |||
diff --git a/arch/powerpc/platforms/pasemi/setup.c b/arch/powerpc/platforms/pasemi/setup.c index bea7d1bb1a3b..449cf1a08291 100644 --- a/arch/powerpc/platforms/pasemi/setup.c +++ b/arch/powerpc/platforms/pasemi/setup.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2006 PA Semi, Inc | 2 | * Copyright (C) 2006-2007 PA Semi, Inc |
3 | * | 3 | * |
4 | * Authors: Kip Walker, PA Semi | 4 | * Authors: Kip Walker, PA Semi |
5 | * Olof Johansson, PA Semi | 5 | * Olof Johansson, PA Semi |
@@ -38,31 +38,46 @@ | |||
38 | 38 | ||
39 | #include "pasemi.h" | 39 | #include "pasemi.h" |
40 | 40 | ||
41 | static void __iomem *reset_reg; | ||
42 | |||
41 | static void pas_restart(char *cmd) | 43 | static void pas_restart(char *cmd) |
42 | { | 44 | { |
43 | printk("restart unimplemented, looping...\n"); | 45 | printk("Restarting...\n"); |
44 | for (;;) ; | 46 | while (1) |
47 | out_le32(reset_reg, 0x6000000); | ||
45 | } | 48 | } |
46 | 49 | ||
47 | static void pas_power_off(void) | 50 | #ifdef CONFIG_SMP |
51 | static DEFINE_SPINLOCK(timebase_lock); | ||
52 | |||
53 | static void __devinit pas_give_timebase(void) | ||
48 | { | 54 | { |
49 | printk("power off unimplemented, looping...\n"); | 55 | unsigned long tb; |
50 | for (;;) ; | 56 | |
57 | spin_lock(&timebase_lock); | ||
58 | mtspr(SPRN_TBCTL, TBCTL_FREEZE); | ||
59 | tb = mftb(); | ||
60 | mtspr(SPRN_TBCTL, TBCTL_UPDATE_LOWER | (tb & 0xffffffff)); | ||
61 | mtspr(SPRN_TBCTL, TBCTL_UPDATE_UPPER | (tb >> 32)); | ||
62 | mtspr(SPRN_TBCTL, TBCTL_RESTART); | ||
63 | spin_unlock(&timebase_lock); | ||
64 | pr_debug("pas_give_timebase: cpu %d gave tb %lx\n", | ||
65 | smp_processor_id(), tb); | ||
51 | } | 66 | } |
52 | 67 | ||
53 | static void pas_halt(void) | 68 | static void __devinit pas_take_timebase(void) |
54 | { | 69 | { |
55 | pas_power_off(); | 70 | pr_debug("pas_take_timebase: cpu %d has tb %lx\n", |
71 | smp_processor_id(), mftb()); | ||
56 | } | 72 | } |
57 | 73 | ||
58 | #ifdef CONFIG_SMP | ||
59 | struct smp_ops_t pas_smp_ops = { | 74 | struct smp_ops_t pas_smp_ops = { |
60 | .probe = smp_mpic_probe, | 75 | .probe = smp_mpic_probe, |
61 | .message_pass = smp_mpic_message_pass, | 76 | .message_pass = smp_mpic_message_pass, |
62 | .kick_cpu = smp_generic_kick_cpu, | 77 | .kick_cpu = smp_generic_kick_cpu, |
63 | .setup_cpu = smp_mpic_setup_cpu, | 78 | .setup_cpu = smp_mpic_setup_cpu, |
64 | .give_timebase = smp_generic_give_timebase, | 79 | .give_timebase = pas_give_timebase, |
65 | .take_timebase = smp_generic_take_timebase, | 80 | .take_timebase = pas_take_timebase, |
66 | }; | 81 | }; |
67 | #endif /* CONFIG_SMP */ | 82 | #endif /* CONFIG_SMP */ |
68 | 83 | ||
@@ -72,9 +87,6 @@ void __init pas_setup_arch(void) | |||
72 | /* Setup SMP callback */ | 87 | /* Setup SMP callback */ |
73 | smp_ops = &pas_smp_ops; | 88 | smp_ops = &pas_smp_ops; |
74 | #endif | 89 | #endif |
75 | /* no iommu yet */ | ||
76 | pci_dma_ops = &dma_direct_ops; | ||
77 | |||
78 | /* Lookup PCI hosts */ | 90 | /* Lookup PCI hosts */ |
79 | pas_pci_init(); | 91 | pas_pci_init(); |
80 | 92 | ||
@@ -82,7 +94,11 @@ void __init pas_setup_arch(void) | |||
82 | conswitchp = &dummy_con; | 94 | conswitchp = &dummy_con; |
83 | #endif | 95 | #endif |
84 | 96 | ||
85 | printk(KERN_DEBUG "Using default idle loop\n"); | 97 | /* Remap SDC register for doing reset */ |
98 | /* XXXOJN This should maybe come out of the device tree */ | ||
99 | reset_reg = ioremap(0xfc101100, 4); | ||
100 | |||
101 | pasemi_idle_init(); | ||
86 | } | 102 | } |
87 | 103 | ||
88 | /* No legacy IO on our parts */ | 104 | /* No legacy IO on our parts */ |
@@ -130,8 +146,9 @@ static __init void pas_init_IRQ(void) | |||
130 | openpic_addr = of_read_number(opprop, naddr); | 146 | openpic_addr = of_read_number(opprop, naddr); |
131 | printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic_addr); | 147 | printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic_addr); |
132 | 148 | ||
133 | mpic = mpic_alloc(mpic_node, openpic_addr, MPIC_PRIMARY, 0, 0, | 149 | mpic = mpic_alloc(mpic_node, openpic_addr, |
134 | " PAS-OPIC "); | 150 | MPIC_PRIMARY|MPIC_LARGE_VECTORS, |
151 | 0, 0, " PAS-OPIC "); | ||
135 | BUG_ON(!mpic); | 152 | BUG_ON(!mpic); |
136 | 153 | ||
137 | mpic_assign_isu(mpic, 0, openpic_addr + 0x10000); | 154 | mpic_assign_isu(mpic, 0, openpic_addr + 0x10000); |
@@ -146,6 +163,53 @@ static void __init pas_progress(char *s, unsigned short hex) | |||
146 | } | 163 | } |
147 | 164 | ||
148 | 165 | ||
166 | static int pas_machine_check_handler(struct pt_regs *regs) | ||
167 | { | ||
168 | int cpu = smp_processor_id(); | ||
169 | unsigned long srr0, srr1, dsisr; | ||
170 | |||
171 | srr0 = regs->nip; | ||
172 | srr1 = regs->msr; | ||
173 | dsisr = mfspr(SPRN_DSISR); | ||
174 | printk(KERN_ERR "Machine Check on CPU %d\n", cpu); | ||
175 | printk(KERN_ERR "SRR0 0x%016lx SRR1 0x%016lx\n", srr0, srr1); | ||
176 | printk(KERN_ERR "DSISR 0x%016lx DAR 0x%016lx\n", dsisr, regs->dar); | ||
177 | printk(KERN_ERR "Cause:\n"); | ||
178 | |||
179 | if (srr1 & 0x200000) | ||
180 | printk(KERN_ERR "Signalled by SDC\n"); | ||
181 | if (srr1 & 0x100000) { | ||
182 | printk(KERN_ERR "Load/Store detected error:\n"); | ||
183 | if (dsisr & 0x8000) | ||
184 | printk(KERN_ERR "D-cache ECC double-bit error or bus error\n"); | ||
185 | if (dsisr & 0x4000) | ||
186 | printk(KERN_ERR "LSU snoop response error\n"); | ||
187 | if (dsisr & 0x2000) | ||
188 | printk(KERN_ERR "MMU SLB multi-hit or invalid B field\n"); | ||
189 | if (dsisr & 0x1000) | ||
190 | printk(KERN_ERR "Recoverable Duptags\n"); | ||
191 | if (dsisr & 0x800) | ||
192 | printk(KERN_ERR "Recoverable D-cache parity error count overflow\n"); | ||
193 | if (dsisr & 0x400) | ||
194 | printk(KERN_ERR "TLB parity error count overflow\n"); | ||
195 | } | ||
196 | if (srr1 & 0x80000) | ||
197 | printk(KERN_ERR "Bus Error\n"); | ||
198 | if (srr1 & 0x40000) | ||
199 | printk(KERN_ERR "I-side SLB multiple hit\n"); | ||
200 | if (srr1 & 0x20000) | ||
201 | printk(KERN_ERR "I-cache parity error hit\n"); | ||
202 | |||
203 | /* SRR1[62] is from MSR[62] if recoverable, so pass that back */ | ||
204 | return !!(srr1 & 0x2); | ||
205 | } | ||
206 | |||
207 | static void __init pas_init_early(void) | ||
208 | { | ||
209 | iommu_init_early_pasemi(); | ||
210 | } | ||
211 | |||
212 | |||
149 | /* | 213 | /* |
150 | * Called very early, MMU is off, device-tree isn't unflattened | 214 | * Called very early, MMU is off, device-tree isn't unflattened |
151 | */ | 215 | */ |
@@ -158,6 +222,8 @@ static int __init pas_probe(void) | |||
158 | 222 | ||
159 | hpte_init_native(); | 223 | hpte_init_native(); |
160 | 224 | ||
225 | alloc_iobmap_l2(); | ||
226 | |||
161 | return 1; | 227 | return 1; |
162 | } | 228 | } |
163 | 229 | ||
@@ -165,13 +231,14 @@ define_machine(pas) { | |||
165 | .name = "PA Semi PA6T-1682M", | 231 | .name = "PA Semi PA6T-1682M", |
166 | .probe = pas_probe, | 232 | .probe = pas_probe, |
167 | .setup_arch = pas_setup_arch, | 233 | .setup_arch = pas_setup_arch, |
234 | .init_early = pas_init_early, | ||
168 | .init_IRQ = pas_init_IRQ, | 235 | .init_IRQ = pas_init_IRQ, |
169 | .get_irq = mpic_get_irq, | 236 | .get_irq = mpic_get_irq, |
170 | .restart = pas_restart, | 237 | .restart = pas_restart, |
171 | .power_off = pas_power_off, | ||
172 | .halt = pas_halt, | ||
173 | .get_boot_time = pas_get_boot_time, | 238 | .get_boot_time = pas_get_boot_time, |
174 | .calibrate_decr = generic_calibrate_decr, | 239 | .calibrate_decr = generic_calibrate_decr, |
175 | .check_legacy_ioport = pas_check_legacy_ioport, | 240 | .check_legacy_ioport = pas_check_legacy_ioport, |
176 | .progress = pas_progress, | 241 | .progress = pas_progress, |
242 | .machine_check_exception = pas_machine_check_handler, | ||
243 | .pci_irq_fixup = pas_pci_irq_fixup, | ||
177 | }; | 244 | }; |
diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c index 39db12890214..5e5c0e4add91 100644 --- a/arch/powerpc/platforms/powermac/pic.c +++ b/arch/powerpc/platforms/powermac/pic.c | |||
@@ -305,8 +305,6 @@ static int pmac_pic_host_map(struct irq_host *h, unsigned int virq, | |||
305 | level = !!(level_mask[hw >> 5] & (1UL << (hw & 0x1f))); | 305 | level = !!(level_mask[hw >> 5] & (1UL << (hw & 0x1f))); |
306 | if (level) | 306 | if (level) |
307 | desc->status |= IRQ_LEVEL; | 307 | desc->status |= IRQ_LEVEL; |
308 | else | ||
309 | desc->status |= IRQ_DELAYED_DISABLE; | ||
310 | set_irq_chip_and_handler(virq, &pmac_pic, level ? | 308 | set_irq_chip_and_handler(virq, &pmac_pic, level ? |
311 | handle_level_irq : handle_edge_irq); | 309 | handle_level_irq : handle_edge_irq); |
312 | return 0; | 310 | return 0; |
diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c index d949e9df41ef..651fa424ea06 100644 --- a/arch/powerpc/platforms/powermac/setup.c +++ b/arch/powerpc/platforms/powermac/setup.c | |||
@@ -506,8 +506,8 @@ void note_bootable_part(dev_t dev, int part, int goodness) | |||
506 | if ((goodness <= current_root_goodness) && | 506 | if ((goodness <= current_root_goodness) && |
507 | ROOT_DEV != DEFAULT_ROOT_DEVICE) | 507 | ROOT_DEV != DEFAULT_ROOT_DEVICE) |
508 | return; | 508 | return; |
509 | p = strstr(saved_command_line, "root="); | 509 | p = strstr(boot_command_line, "root="); |
510 | if (p != NULL && (p == saved_command_line || p[-1] == ' ')) | 510 | if (p != NULL && (p == boot_command_line || p[-1] == ' ')) |
511 | return; | 511 | return; |
512 | 512 | ||
513 | if (!found_boot) { | 513 | if (!found_boot) { |
diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c index eeb2ae5ffc58..d73fb73802bb 100644 --- a/arch/powerpc/platforms/powermac/smp.c +++ b/arch/powerpc/platforms/powermac/smp.c | |||
@@ -795,7 +795,6 @@ static void __devinit smp_core99_kick_cpu(int nr) | |||
795 | ppc_md.progress("smp_core99_kick_cpu", 0x346); | 795 | ppc_md.progress("smp_core99_kick_cpu", 0x346); |
796 | 796 | ||
797 | local_irq_save(flags); | 797 | local_irq_save(flags); |
798 | local_irq_disable(); | ||
799 | 798 | ||
800 | /* Save reset vector */ | 799 | /* Save reset vector */ |
801 | save_vector = *vector; | 800 | save_vector = *vector; |
diff --git a/arch/powerpc/platforms/ps3/Kconfig b/arch/powerpc/platforms/ps3/Kconfig index de52ec4e9e58..d270a1e374d5 100644 --- a/arch/powerpc/platforms/ps3/Kconfig +++ b/arch/powerpc/platforms/ps3/Kconfig | |||
@@ -51,4 +51,25 @@ config PS3_VUART | |||
51 | including the System Manager and AV Settings. In | 51 | including the System Manager and AV Settings. In |
52 | general, all users will say Y. | 52 | general, all users will say Y. |
53 | 53 | ||
54 | config PS3_PS3AV | ||
55 | tristate "PS3 AV settings driver" | ||
56 | depends on PPC_PS3 | ||
57 | select PS3_VUART | ||
58 | default y | ||
59 | help | ||
60 | Include support for the PS3 AV Settings driver. | ||
61 | |||
62 | This support is required for graphics and sound. In | ||
63 | general, all users will say Y or M. | ||
64 | |||
65 | config PS3_SYS_MANAGER | ||
66 | bool "PS3 System Manager driver" | ||
67 | select PS3_VUART | ||
68 | default y | ||
69 | help | ||
70 | Include support for the PS3 System Manager. | ||
71 | |||
72 | This support is required for system control. In | ||
73 | general, all users will say Y. | ||
74 | |||
54 | endmenu | 75 | endmenu |
diff --git a/arch/powerpc/platforms/ps3/Makefile b/arch/powerpc/platforms/ps3/Makefile index 1994904f580f..a0048fcf0866 100644 --- a/arch/powerpc/platforms/ps3/Makefile +++ b/arch/powerpc/platforms/ps3/Makefile | |||
@@ -1,5 +1,6 @@ | |||
1 | obj-y += setup.o mm.o time.o hvcall.o htab.o repository.o | 1 | obj-y += setup.o mm.o time.o hvcall.o htab.o repository.o |
2 | obj-y += interrupt.o exports.o os-area.o | 2 | obj-y += interrupt.o exports.o os-area.o |
3 | obj-y += system-bus.o | ||
3 | 4 | ||
4 | obj-$(CONFIG_SMP) += smp.o | 5 | obj-$(CONFIG_SMP) += smp.o |
5 | obj-$(CONFIG_SPU_BASE) += spu.o | 6 | obj-$(CONFIG_SPU_BASE) += spu.o |
diff --git a/arch/powerpc/platforms/ps3/htab.c b/arch/powerpc/platforms/ps3/htab.c index 8fe1769655a3..e12e59fea13a 100644 --- a/arch/powerpc/platforms/ps3/htab.c +++ b/arch/powerpc/platforms/ps3/htab.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * PS3 pagetable management routines. | 2 | * PS3 pagetable management routines. |
3 | * | 3 | * |
4 | * Copyright (C) 2006 Sony Computer Entertainment Inc. | 4 | * Copyright (C) 2006 Sony Computer Entertainment Inc. |
5 | * Copyright 2006 Sony Corp. | 5 | * Copyright 2006, 2007 Sony Corporation |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by | 8 | * it under the terms of the GNU General Public License as published by |
@@ -23,8 +23,8 @@ | |||
23 | #include <asm/machdep.h> | 23 | #include <asm/machdep.h> |
24 | #include <asm/lmb.h> | 24 | #include <asm/lmb.h> |
25 | #include <asm/udbg.h> | 25 | #include <asm/udbg.h> |
26 | #include <asm/ps3.h> | ||
27 | #include <asm/lv1call.h> | 26 | #include <asm/lv1call.h> |
27 | #include <asm/ps3fb.h> | ||
28 | 28 | ||
29 | #include "platform.h" | 29 | #include "platform.h" |
30 | 30 | ||
@@ -234,6 +234,9 @@ static void ps3_hpte_invalidate(unsigned long slot, unsigned long va, | |||
234 | 234 | ||
235 | static void ps3_hpte_clear(void) | 235 | static void ps3_hpte_clear(void) |
236 | { | 236 | { |
237 | /* Make sure to clean up the frame buffer device first */ | ||
238 | ps3fb_cleanup(); | ||
239 | |||
237 | lv1_unmap_htab(htab_addr); | 240 | lv1_unmap_htab(htab_addr); |
238 | } | 241 | } |
239 | 242 | ||
diff --git a/arch/powerpc/platforms/ps3/interrupt.c b/arch/powerpc/platforms/ps3/interrupt.c index 6f5de438b980..631c30095617 100644 --- a/arch/powerpc/platforms/ps3/interrupt.c +++ b/arch/powerpc/platforms/ps3/interrupt.c | |||
@@ -24,7 +24,6 @@ | |||
24 | 24 | ||
25 | #include <asm/machdep.h> | 25 | #include <asm/machdep.h> |
26 | #include <asm/udbg.h> | 26 | #include <asm/udbg.h> |
27 | #include <asm/ps3.h> | ||
28 | #include <asm/lv1call.h> | 27 | #include <asm/lv1call.h> |
29 | 28 | ||
30 | #include "platform.h" | 29 | #include "platform.h" |
@@ -36,15 +35,148 @@ | |||
36 | #endif | 35 | #endif |
37 | 36 | ||
38 | /** | 37 | /** |
38 | * struct ps3_bmp - a per cpu irq status and mask bitmap structure | ||
39 | * @status: 256 bit status bitmap indexed by plug | ||
40 | * @unused_1: | ||
41 | * @mask: 256 bit mask bitmap indexed by plug | ||
42 | * @unused_2: | ||
43 | * @lock: | ||
44 | * @ipi_debug_brk_mask: | ||
45 | * | ||
46 | * The HV mantains per SMT thread mappings of HV outlet to HV plug on | ||
47 | * behalf of the guest. These mappings are implemented as 256 bit guest | ||
48 | * supplied bitmaps indexed by plug number. The addresses of the bitmaps | ||
49 | * are registered with the HV through lv1_configure_irq_state_bitmap(). | ||
50 | * The HV requires that the 512 bits of status + mask not cross a page | ||
51 | * boundary. PS3_BMP_MINALIGN is used to define this minimal 64 byte | ||
52 | * alignment. | ||
53 | * | ||
54 | * The HV supports 256 plugs per thread, assigned as {0..255}, for a total | ||
55 | * of 512 plugs supported on a processor. To simplify the logic this | ||
56 | * implementation equates HV plug value to Linux virq value, constrains each | ||
57 | * interrupt to have a system wide unique plug number, and limits the range | ||
58 | * of the plug values to map into the first dword of the bitmaps. This | ||
59 | * gives a usable range of plug values of {NUM_ISA_INTERRUPTS..63}. Note | ||
60 | * that there is no constraint on how many in this set an individual thread | ||
61 | * can acquire. | ||
62 | */ | ||
63 | |||
64 | #define PS3_BMP_MINALIGN 64 | ||
65 | |||
66 | struct ps3_bmp { | ||
67 | struct { | ||
68 | u64 status; | ||
69 | u64 unused_1[3]; | ||
70 | u64 mask; | ||
71 | u64 unused_2[3]; | ||
72 | }; | ||
73 | u64 ipi_debug_brk_mask; | ||
74 | spinlock_t lock; | ||
75 | }; | ||
76 | |||
77 | /** | ||
78 | * struct ps3_private - a per cpu data structure | ||
79 | * @bmp: ps3_bmp structure | ||
80 | * @node: HV logical_ppe_id | ||
81 | * @cpu: HV thread_id | ||
82 | */ | ||
83 | |||
84 | struct ps3_private { | ||
85 | struct ps3_bmp bmp __attribute__ ((aligned (PS3_BMP_MINALIGN))); | ||
86 | u64 node; | ||
87 | unsigned int cpu; | ||
88 | }; | ||
89 | |||
90 | static DEFINE_PER_CPU(struct ps3_private, ps3_private); | ||
91 | |||
92 | int ps3_alloc_irq(enum ps3_cpu_binding cpu, unsigned long outlet, | ||
93 | unsigned int *virq) | ||
94 | { | ||
95 | int result; | ||
96 | struct ps3_private *pd; | ||
97 | |||
98 | /* This defines the default interrupt distribution policy. */ | ||
99 | |||
100 | if (cpu == PS3_BINDING_CPU_ANY) | ||
101 | cpu = 0; | ||
102 | |||
103 | pd = &per_cpu(ps3_private, cpu); | ||
104 | |||
105 | *virq = irq_create_mapping(NULL, outlet); | ||
106 | |||
107 | if (*virq == NO_IRQ) { | ||
108 | pr_debug("%s:%d: irq_create_mapping failed: outlet %lu\n", | ||
109 | __func__, __LINE__, outlet); | ||
110 | result = -ENOMEM; | ||
111 | goto fail_create; | ||
112 | } | ||
113 | |||
114 | /* Binds outlet to cpu + virq. */ | ||
115 | |||
116 | result = lv1_connect_irq_plug_ext(pd->node, pd->cpu, *virq, outlet, 0); | ||
117 | |||
118 | if (result) { | ||
119 | pr_info("%s:%d: lv1_connect_irq_plug_ext failed: %s\n", | ||
120 | __func__, __LINE__, ps3_result(result)); | ||
121 | result = -EPERM; | ||
122 | goto fail_connect; | ||
123 | } | ||
124 | |||
125 | pr_debug("%s:%d: outlet %lu => cpu %u, virq %u\n", __func__, __LINE__, | ||
126 | outlet, cpu, *virq); | ||
127 | |||
128 | result = set_irq_chip_data(*virq, pd); | ||
129 | |||
130 | if (result) { | ||
131 | pr_debug("%s:%d: set_irq_chip_data failed\n", | ||
132 | __func__, __LINE__); | ||
133 | goto fail_set; | ||
134 | } | ||
135 | |||
136 | return result; | ||
137 | |||
138 | fail_set: | ||
139 | lv1_disconnect_irq_plug_ext(pd->node, pd->cpu, *virq); | ||
140 | fail_connect: | ||
141 | irq_dispose_mapping(*virq); | ||
142 | fail_create: | ||
143 | return result; | ||
144 | } | ||
145 | EXPORT_SYMBOL_GPL(ps3_alloc_irq); | ||
146 | |||
147 | int ps3_free_irq(unsigned int virq) | ||
148 | { | ||
149 | int result; | ||
150 | const struct ps3_private *pd = get_irq_chip_data(virq); | ||
151 | |||
152 | pr_debug("%s:%d: node %lu, cpu %d, virq %u\n", __func__, __LINE__, | ||
153 | pd->node, pd->cpu, virq); | ||
154 | |||
155 | result = lv1_disconnect_irq_plug_ext(pd->node, pd->cpu, virq); | ||
156 | |||
157 | if (result) | ||
158 | pr_info("%s:%d: lv1_disconnect_irq_plug_ext failed: %s\n", | ||
159 | __func__, __LINE__, ps3_result(result)); | ||
160 | |||
161 | set_irq_chip_data(virq, NULL); | ||
162 | irq_dispose_mapping(virq); | ||
163 | return result; | ||
164 | } | ||
165 | EXPORT_SYMBOL_GPL(ps3_free_irq); | ||
166 | |||
167 | /** | ||
39 | * ps3_alloc_io_irq - Assign a virq to a system bus device. | 168 | * ps3_alloc_io_irq - Assign a virq to a system bus device. |
40 | * interrupt_id: The device interrupt id read from the system repository. | 169 | * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be |
170 | * serviced on. | ||
171 | * @interrupt_id: The device interrupt id read from the system repository. | ||
41 | * @virq: The assigned Linux virq. | 172 | * @virq: The assigned Linux virq. |
42 | * | 173 | * |
43 | * An io irq represents a non-virtualized device interrupt. interrupt_id | 174 | * An io irq represents a non-virtualized device interrupt. interrupt_id |
44 | * coresponds to the interrupt number of the interrupt controller. | 175 | * coresponds to the interrupt number of the interrupt controller. |
45 | */ | 176 | */ |
46 | 177 | ||
47 | int ps3_alloc_io_irq(unsigned int interrupt_id, unsigned int *virq) | 178 | int ps3_alloc_io_irq(enum ps3_cpu_binding cpu, unsigned int interrupt_id, |
179 | unsigned int *virq) | ||
48 | { | 180 | { |
49 | int result; | 181 | int result; |
50 | unsigned long outlet; | 182 | unsigned long outlet; |
@@ -57,13 +189,12 @@ int ps3_alloc_io_irq(unsigned int interrupt_id, unsigned int *virq) | |||
57 | return result; | 189 | return result; |
58 | } | 190 | } |
59 | 191 | ||
60 | *virq = irq_create_mapping(NULL, outlet); | 192 | result = ps3_alloc_irq(cpu, outlet, virq); |
61 | 193 | BUG_ON(result); | |
62 | pr_debug("%s:%d: interrupt_id %u => outlet %lu, virq %u\n", | ||
63 | __func__, __LINE__, interrupt_id, outlet, *virq); | ||
64 | 194 | ||
65 | return 0; | 195 | return result; |
66 | } | 196 | } |
197 | EXPORT_SYMBOL_GPL(ps3_alloc_io_irq); | ||
67 | 198 | ||
68 | int ps3_free_io_irq(unsigned int virq) | 199 | int ps3_free_io_irq(unsigned int virq) |
69 | { | 200 | { |
@@ -75,13 +206,16 @@ int ps3_free_io_irq(unsigned int virq) | |||
75 | pr_debug("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n", | 206 | pr_debug("%s:%d: lv1_destruct_io_irq_outlet failed: %s\n", |
76 | __func__, __LINE__, ps3_result(result)); | 207 | __func__, __LINE__, ps3_result(result)); |
77 | 208 | ||
78 | irq_dispose_mapping(virq); | 209 | ps3_free_irq(virq); |
79 | 210 | ||
80 | return result; | 211 | return result; |
81 | } | 212 | } |
213 | EXPORT_SYMBOL_GPL(ps3_free_io_irq); | ||
82 | 214 | ||
83 | /** | 215 | /** |
84 | * ps3_alloc_event_irq - Allocate a virq for use with a system event. | 216 | * ps3_alloc_event_irq - Allocate a virq for use with a system event. |
217 | * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be | ||
218 | * serviced on. | ||
85 | * @virq: The assigned Linux virq. | 219 | * @virq: The assigned Linux virq. |
86 | * | 220 | * |
87 | * The virq can be used with lv1_connect_interrupt_event_receive_port() to | 221 | * The virq can be used with lv1_connect_interrupt_event_receive_port() to |
@@ -89,7 +223,7 @@ int ps3_free_io_irq(unsigned int virq) | |||
89 | * events. | 223 | * events. |
90 | */ | 224 | */ |
91 | 225 | ||
92 | int ps3_alloc_event_irq(unsigned int *virq) | 226 | int ps3_alloc_event_irq(enum ps3_cpu_binding cpu, unsigned int *virq) |
93 | { | 227 | { |
94 | int result; | 228 | int result; |
95 | unsigned long outlet; | 229 | unsigned long outlet; |
@@ -103,12 +237,10 @@ int ps3_alloc_event_irq(unsigned int *virq) | |||
103 | return result; | 237 | return result; |
104 | } | 238 | } |
105 | 239 | ||
106 | *virq = irq_create_mapping(NULL, outlet); | 240 | result = ps3_alloc_irq(cpu, outlet, virq); |
107 | 241 | BUG_ON(result); | |
108 | pr_debug("%s:%d: outlet %lu, virq %u\n", __func__, __LINE__, outlet, | ||
109 | *virq); | ||
110 | 242 | ||
111 | return 0; | 243 | return result; |
112 | } | 244 | } |
113 | 245 | ||
114 | int ps3_free_event_irq(unsigned int virq) | 246 | int ps3_free_event_irq(unsigned int virq) |
@@ -123,7 +255,7 @@ int ps3_free_event_irq(unsigned int virq) | |||
123 | pr_debug("%s:%d: lv1_destruct_event_receive_port failed: %s\n", | 255 | pr_debug("%s:%d: lv1_destruct_event_receive_port failed: %s\n", |
124 | __func__, __LINE__, ps3_result(result)); | 256 | __func__, __LINE__, ps3_result(result)); |
125 | 257 | ||
126 | irq_dispose_mapping(virq); | 258 | ps3_free_irq(virq); |
127 | 259 | ||
128 | pr_debug(" <- %s:%d\n", __func__, __LINE__); | 260 | pr_debug(" <- %s:%d\n", __func__, __LINE__); |
129 | return result; | 261 | return result; |
@@ -136,6 +268,8 @@ int ps3_send_event_locally(unsigned int virq) | |||
136 | 268 | ||
137 | /** | 269 | /** |
138 | * ps3_connect_event_irq - Assign a virq to a system bus device. | 270 | * ps3_connect_event_irq - Assign a virq to a system bus device. |
271 | * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be | ||
272 | * serviced on. | ||
139 | * @did: The HV device identifier read from the system repository. | 273 | * @did: The HV device identifier read from the system repository. |
140 | * @interrupt_id: The device interrupt id read from the system repository. | 274 | * @interrupt_id: The device interrupt id read from the system repository. |
141 | * @virq: The assigned Linux virq. | 275 | * @virq: The assigned Linux virq. |
@@ -144,12 +278,13 @@ int ps3_send_event_locally(unsigned int virq) | |||
144 | * coresponds to the software interrupt number. | 278 | * coresponds to the software interrupt number. |
145 | */ | 279 | */ |
146 | 280 | ||
147 | int ps3_connect_event_irq(const struct ps3_device_id *did, | 281 | int ps3_connect_event_irq(enum ps3_cpu_binding cpu, |
148 | unsigned int interrupt_id, unsigned int *virq) | 282 | const struct ps3_device_id *did, unsigned int interrupt_id, |
283 | unsigned int *virq) | ||
149 | { | 284 | { |
150 | int result; | 285 | int result; |
151 | 286 | ||
152 | result = ps3_alloc_event_irq(virq); | 287 | result = ps3_alloc_event_irq(cpu, virq); |
153 | 288 | ||
154 | if (result) | 289 | if (result) |
155 | return result; | 290 | return result; |
@@ -196,6 +331,8 @@ int ps3_disconnect_event_irq(const struct ps3_device_id *did, | |||
196 | 331 | ||
197 | /** | 332 | /** |
198 | * ps3_alloc_vuart_irq - Configure the system virtual uart virq. | 333 | * ps3_alloc_vuart_irq - Configure the system virtual uart virq. |
334 | * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be | ||
335 | * serviced on. | ||
199 | * @virt_addr_bmp: The caller supplied virtual uart interrupt bitmap. | 336 | * @virt_addr_bmp: The caller supplied virtual uart interrupt bitmap. |
200 | * @virq: The assigned Linux virq. | 337 | * @virq: The assigned Linux virq. |
201 | * | 338 | * |
@@ -203,13 +340,14 @@ int ps3_disconnect_event_irq(const struct ps3_device_id *did, | |||
203 | * freeing the interrupt will return a wrong state error. | 340 | * freeing the interrupt will return a wrong state error. |
204 | */ | 341 | */ |
205 | 342 | ||
206 | int ps3_alloc_vuart_irq(void* virt_addr_bmp, unsigned int *virq) | 343 | int ps3_alloc_vuart_irq(enum ps3_cpu_binding cpu, void* virt_addr_bmp, |
344 | unsigned int *virq) | ||
207 | { | 345 | { |
208 | int result; | 346 | int result; |
209 | unsigned long outlet; | 347 | unsigned long outlet; |
210 | unsigned long lpar_addr; | 348 | u64 lpar_addr; |
211 | 349 | ||
212 | BUG_ON(!is_kernel_addr((unsigned long)virt_addr_bmp)); | 350 | BUG_ON(!is_kernel_addr((u64)virt_addr_bmp)); |
213 | 351 | ||
214 | lpar_addr = ps3_mm_phys_to_lpar(__pa(virt_addr_bmp)); | 352 | lpar_addr = ps3_mm_phys_to_lpar(__pa(virt_addr_bmp)); |
215 | 353 | ||
@@ -221,12 +359,10 @@ int ps3_alloc_vuart_irq(void* virt_addr_bmp, unsigned int *virq) | |||
221 | return result; | 359 | return result; |
222 | } | 360 | } |
223 | 361 | ||
224 | *virq = irq_create_mapping(NULL, outlet); | 362 | result = ps3_alloc_irq(cpu, outlet, virq); |
225 | 363 | BUG_ON(result); | |
226 | pr_debug("%s:%d: outlet %lu, virq %u\n", __func__, __LINE__, | ||
227 | outlet, *virq); | ||
228 | 364 | ||
229 | return 0; | 365 | return result; |
230 | } | 366 | } |
231 | 367 | ||
232 | int ps3_free_vuart_irq(unsigned int virq) | 368 | int ps3_free_vuart_irq(unsigned int virq) |
@@ -241,21 +377,23 @@ int ps3_free_vuart_irq(unsigned int virq) | |||
241 | return result; | 377 | return result; |
242 | } | 378 | } |
243 | 379 | ||
244 | irq_dispose_mapping(virq); | 380 | ps3_free_irq(virq); |
245 | 381 | ||
246 | return result; | 382 | return result; |
247 | } | 383 | } |
248 | 384 | ||
249 | /** | 385 | /** |
250 | * ps3_alloc_spe_irq - Configure an spe virq. | 386 | * ps3_alloc_spe_irq - Configure an spe virq. |
387 | * @cpu: enum ps3_cpu_binding indicating the cpu the interrupt should be | ||
388 | * serviced on. | ||
251 | * @spe_id: The spe_id returned from lv1_construct_logical_spe(). | 389 | * @spe_id: The spe_id returned from lv1_construct_logical_spe(). |
252 | * @class: The spe interrupt class {0,1,2}. | 390 | * @class: The spe interrupt class {0,1,2}. |
253 | * @virq: The assigned Linux virq. | 391 | * @virq: The assigned Linux virq. |
254 | * | 392 | * |
255 | */ | 393 | */ |
256 | 394 | ||
257 | int ps3_alloc_spe_irq(unsigned long spe_id, unsigned int class, | 395 | int ps3_alloc_spe_irq(enum ps3_cpu_binding cpu, unsigned long spe_id, |
258 | unsigned int *virq) | 396 | unsigned int class, unsigned int *virq) |
259 | { | 397 | { |
260 | int result; | 398 | int result; |
261 | unsigned long outlet; | 399 | unsigned long outlet; |
@@ -270,73 +408,24 @@ int ps3_alloc_spe_irq(unsigned long spe_id, unsigned int class, | |||
270 | return result; | 408 | return result; |
271 | } | 409 | } |
272 | 410 | ||
273 | *virq = irq_create_mapping(NULL, outlet); | 411 | result = ps3_alloc_irq(cpu, outlet, virq); |
274 | 412 | BUG_ON(result); | |
275 | pr_debug("%s:%d: spe_id %lu, class %u, outlet %lu, virq %u\n", | ||
276 | __func__, __LINE__, spe_id, class, outlet, *virq); | ||
277 | 413 | ||
278 | return 0; | 414 | return result; |
279 | } | 415 | } |
280 | 416 | ||
281 | int ps3_free_spe_irq(unsigned int virq) | 417 | int ps3_free_spe_irq(unsigned int virq) |
282 | { | 418 | { |
283 | irq_dispose_mapping(virq); | 419 | ps3_free_irq(virq); |
284 | return 0; | 420 | return 0; |
285 | } | 421 | } |
286 | 422 | ||
423 | |||
287 | #define PS3_INVALID_OUTLET ((irq_hw_number_t)-1) | 424 | #define PS3_INVALID_OUTLET ((irq_hw_number_t)-1) |
288 | #define PS3_PLUG_MAX 63 | 425 | #define PS3_PLUG_MAX 63 |
289 | 426 | ||
290 | /** | ||
291 | * struct bmp - a per cpu irq status and mask bitmap structure | ||
292 | * @status: 256 bit status bitmap indexed by plug | ||
293 | * @unused_1: | ||
294 | * @mask: 256 bit mask bitmap indexed by plug | ||
295 | * @unused_2: | ||
296 | * @lock: | ||
297 | * @ipi_debug_brk_mask: | ||
298 | * | ||
299 | * The HV mantains per SMT thread mappings of HV outlet to HV plug on | ||
300 | * behalf of the guest. These mappings are implemented as 256 bit guest | ||
301 | * supplied bitmaps indexed by plug number. The address of the bitmaps are | ||
302 | * registered with the HV through lv1_configure_irq_state_bitmap(). | ||
303 | * | ||
304 | * The HV supports 256 plugs per thread, assigned as {0..255}, for a total | ||
305 | * of 512 plugs supported on a processor. To simplify the logic this | ||
306 | * implementation equates HV plug value to linux virq value, constrains each | ||
307 | * interrupt to have a system wide unique plug number, and limits the range | ||
308 | * of the plug values to map into the first dword of the bitmaps. This | ||
309 | * gives a usable range of plug values of {NUM_ISA_INTERRUPTS..63}. Note | ||
310 | * that there is no constraint on how many in this set an individual thread | ||
311 | * can aquire. | ||
312 | */ | ||
313 | |||
314 | struct bmp { | ||
315 | struct { | ||
316 | unsigned long status; | ||
317 | unsigned long unused_1[3]; | ||
318 | unsigned long mask; | ||
319 | unsigned long unused_2[3]; | ||
320 | } __attribute__ ((packed)); | ||
321 | spinlock_t lock; | ||
322 | unsigned long ipi_debug_brk_mask; | ||
323 | }; | ||
324 | |||
325 | /** | ||
326 | * struct private - a per cpu data structure | ||
327 | * @node: HV node id | ||
328 | * @cpu: HV thread id | ||
329 | * @bmp: an HV bmp structure | ||
330 | */ | ||
331 | |||
332 | struct private { | ||
333 | unsigned long node; | ||
334 | unsigned int cpu; | ||
335 | struct bmp bmp; | ||
336 | }; | ||
337 | |||
338 | #if defined(DEBUG) | 427 | #if defined(DEBUG) |
339 | static void _dump_64_bmp(const char *header, const unsigned long *p, unsigned cpu, | 428 | static void _dump_64_bmp(const char *header, const u64 *p, unsigned cpu, |
340 | const char* func, int line) | 429 | const char* func, int line) |
341 | { | 430 | { |
342 | pr_debug("%s:%d: %s %u {%04lx_%04lx_%04lx_%04lx}\n", | 431 | pr_debug("%s:%d: %s %u {%04lx_%04lx_%04lx_%04lx}\n", |
@@ -346,14 +435,14 @@ static void _dump_64_bmp(const char *header, const unsigned long *p, unsigned cp | |||
346 | } | 435 | } |
347 | 436 | ||
348 | static void __attribute__ ((unused)) _dump_256_bmp(const char *header, | 437 | static void __attribute__ ((unused)) _dump_256_bmp(const char *header, |
349 | const unsigned long *p, unsigned cpu, const char* func, int line) | 438 | const u64 *p, unsigned cpu, const char* func, int line) |
350 | { | 439 | { |
351 | pr_debug("%s:%d: %s %u {%016lx:%016lx:%016lx:%016lx}\n", | 440 | pr_debug("%s:%d: %s %u {%016lx:%016lx:%016lx:%016lx}\n", |
352 | func, line, header, cpu, p[0], p[1], p[2], p[3]); | 441 | func, line, header, cpu, p[0], p[1], p[2], p[3]); |
353 | } | 442 | } |
354 | 443 | ||
355 | #define dump_bmp(_x) _dump_bmp(_x, __func__, __LINE__) | 444 | #define dump_bmp(_x) _dump_bmp(_x, __func__, __LINE__) |
356 | static void _dump_bmp(struct private* pd, const char* func, int line) | 445 | static void _dump_bmp(struct ps3_private* pd, const char* func, int line) |
357 | { | 446 | { |
358 | unsigned long flags; | 447 | unsigned long flags; |
359 | 448 | ||
@@ -364,7 +453,7 @@ static void _dump_bmp(struct private* pd, const char* func, int line) | |||
364 | } | 453 | } |
365 | 454 | ||
366 | #define dump_mask(_x) _dump_mask(_x, __func__, __LINE__) | 455 | #define dump_mask(_x) _dump_mask(_x, __func__, __LINE__) |
367 | static void __attribute__ ((unused)) _dump_mask(struct private* pd, | 456 | static void __attribute__ ((unused)) _dump_mask(struct ps3_private* pd, |
368 | const char* func, int line) | 457 | const char* func, int line) |
369 | { | 458 | { |
370 | unsigned long flags; | 459 | unsigned long flags; |
@@ -374,109 +463,94 @@ static void __attribute__ ((unused)) _dump_mask(struct private* pd, | |||
374 | spin_unlock_irqrestore(&pd->bmp.lock, flags); | 463 | spin_unlock_irqrestore(&pd->bmp.lock, flags); |
375 | } | 464 | } |
376 | #else | 465 | #else |
377 | static void dump_bmp(struct private* pd) {}; | 466 | static void dump_bmp(struct ps3_private* pd) {}; |
378 | #endif /* defined(DEBUG) */ | 467 | #endif /* defined(DEBUG) */ |
379 | 468 | ||
380 | static void chip_mask(unsigned int virq) | 469 | static void ps3_chip_mask(unsigned int virq) |
381 | { | 470 | { |
471 | struct ps3_private *pd = get_irq_chip_data(virq); | ||
472 | u64 bit = 0x8000000000000000UL >> virq; | ||
473 | u64 *p = &pd->bmp.mask; | ||
474 | u64 old; | ||
382 | unsigned long flags; | 475 | unsigned long flags; |
383 | struct private *pd = get_irq_chip_data(virq); | ||
384 | 476 | ||
385 | pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq); | 477 | pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq); |
386 | 478 | ||
387 | BUG_ON(virq < NUM_ISA_INTERRUPTS); | 479 | local_irq_save(flags); |
388 | BUG_ON(virq > PS3_PLUG_MAX); | 480 | asm volatile( |
389 | 481 | "1: ldarx %0,0,%3\n" | |
390 | spin_lock_irqsave(&pd->bmp.lock, flags); | 482 | "andc %0,%0,%2\n" |
391 | pd->bmp.mask &= ~(0x8000000000000000UL >> virq); | 483 | "stdcx. %0,0,%3\n" |
392 | spin_unlock_irqrestore(&pd->bmp.lock, flags); | 484 | "bne- 1b" |
485 | : "=&r" (old), "+m" (*p) | ||
486 | : "r" (bit), "r" (p) | ||
487 | : "cc" ); | ||
393 | 488 | ||
394 | lv1_did_update_interrupt_mask(pd->node, pd->cpu); | 489 | lv1_did_update_interrupt_mask(pd->node, pd->cpu); |
490 | local_irq_restore(flags); | ||
395 | } | 491 | } |
396 | 492 | ||
397 | static void chip_unmask(unsigned int virq) | 493 | static void ps3_chip_unmask(unsigned int virq) |
398 | { | 494 | { |
495 | struct ps3_private *pd = get_irq_chip_data(virq); | ||
496 | u64 bit = 0x8000000000000000UL >> virq; | ||
497 | u64 *p = &pd->bmp.mask; | ||
498 | u64 old; | ||
399 | unsigned long flags; | 499 | unsigned long flags; |
400 | struct private *pd = get_irq_chip_data(virq); | ||
401 | 500 | ||
402 | pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq); | 501 | pr_debug("%s:%d: cpu %u, virq %d\n", __func__, __LINE__, pd->cpu, virq); |
403 | 502 | ||
404 | BUG_ON(virq < NUM_ISA_INTERRUPTS); | 503 | local_irq_save(flags); |
405 | BUG_ON(virq > PS3_PLUG_MAX); | 504 | asm volatile( |
406 | 505 | "1: ldarx %0,0,%3\n" | |
407 | spin_lock_irqsave(&pd->bmp.lock, flags); | 506 | "or %0,%0,%2\n" |
408 | pd->bmp.mask |= (0x8000000000000000UL >> virq); | 507 | "stdcx. %0,0,%3\n" |
409 | spin_unlock_irqrestore(&pd->bmp.lock, flags); | 508 | "bne- 1b" |
509 | : "=&r" (old), "+m" (*p) | ||
510 | : "r" (bit), "r" (p) | ||
511 | : "cc" ); | ||
410 | 512 | ||
411 | lv1_did_update_interrupt_mask(pd->node, pd->cpu); | 513 | lv1_did_update_interrupt_mask(pd->node, pd->cpu); |
514 | local_irq_restore(flags); | ||
412 | } | 515 | } |
413 | 516 | ||
414 | static void chip_eoi(unsigned int virq) | 517 | static void ps3_chip_eoi(unsigned int virq) |
415 | { | 518 | { |
416 | lv1_end_of_interrupt(virq); | 519 | const struct ps3_private *pd = get_irq_chip_data(virq); |
520 | lv1_end_of_interrupt_ext(pd->node, pd->cpu, virq); | ||
417 | } | 521 | } |
418 | 522 | ||
419 | static struct irq_chip irq_chip = { | 523 | static struct irq_chip irq_chip = { |
420 | .typename = "ps3", | 524 | .typename = "ps3", |
421 | .mask = chip_mask, | 525 | .mask = ps3_chip_mask, |
422 | .unmask = chip_unmask, | 526 | .unmask = ps3_chip_unmask, |
423 | .eoi = chip_eoi, | 527 | .eoi = ps3_chip_eoi, |
424 | }; | 528 | }; |
425 | 529 | ||
426 | static void host_unmap(struct irq_host *h, unsigned int virq) | 530 | static void ps3_host_unmap(struct irq_host *h, unsigned int virq) |
427 | { | 531 | { |
428 | int result; | 532 | set_irq_chip_data(virq, NULL); |
429 | |||
430 | pr_debug("%s:%d: virq %d\n", __func__, __LINE__, virq); | ||
431 | |||
432 | lv1_disconnect_irq_plug(virq); | ||
433 | |||
434 | result = set_irq_chip_data(virq, NULL); | ||
435 | BUG_ON(result); | ||
436 | } | 533 | } |
437 | 534 | ||
438 | static DEFINE_PER_CPU(struct private, private); | 535 | static int ps3_host_map(struct irq_host *h, unsigned int virq, |
439 | |||
440 | static int host_map(struct irq_host *h, unsigned int virq, | ||
441 | irq_hw_number_t hwirq) | 536 | irq_hw_number_t hwirq) |
442 | { | 537 | { |
443 | int result; | 538 | pr_debug("%s:%d: hwirq %lu, virq %u\n", __func__, __LINE__, hwirq, |
444 | unsigned int cpu; | ||
445 | |||
446 | pr_debug(" -> %s:%d\n", __func__, __LINE__); | ||
447 | pr_debug("%s:%d: hwirq %lu => virq %u\n", __func__, __LINE__, hwirq, | ||
448 | virq); | 539 | virq); |
449 | 540 | ||
450 | /* bind this virq to a cpu */ | ||
451 | |||
452 | preempt_disable(); | ||
453 | cpu = smp_processor_id(); | ||
454 | result = lv1_connect_irq_plug(virq, hwirq); | ||
455 | preempt_enable(); | ||
456 | |||
457 | if (result) { | ||
458 | pr_info("%s:%d: lv1_connect_irq_plug failed:" | ||
459 | " %s\n", __func__, __LINE__, ps3_result(result)); | ||
460 | return -EPERM; | ||
461 | } | ||
462 | |||
463 | result = set_irq_chip_data(virq, &per_cpu(private, cpu)); | ||
464 | BUG_ON(result); | ||
465 | |||
466 | set_irq_chip_and_handler(virq, &irq_chip, handle_fasteoi_irq); | 541 | set_irq_chip_and_handler(virq, &irq_chip, handle_fasteoi_irq); |
467 | 542 | ||
468 | pr_debug(" <- %s:%d\n", __func__, __LINE__); | 543 | return 0; |
469 | return result; | ||
470 | } | 544 | } |
471 | 545 | ||
472 | static struct irq_host_ops host_ops = { | 546 | static struct irq_host_ops ps3_host_ops = { |
473 | .map = host_map, | 547 | .map = ps3_host_map, |
474 | .unmap = host_unmap, | 548 | .unmap = ps3_host_unmap, |
475 | }; | 549 | }; |
476 | 550 | ||
477 | void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq) | 551 | void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq) |
478 | { | 552 | { |
479 | struct private *pd = &per_cpu(private, cpu); | 553 | struct ps3_private *pd = &per_cpu(ps3_private, cpu); |
480 | 554 | ||
481 | pd->bmp.ipi_debug_brk_mask = 0x8000000000000000UL >> virq; | 555 | pd->bmp.ipi_debug_brk_mask = 0x8000000000000000UL >> virq; |
482 | 556 | ||
@@ -484,57 +558,32 @@ void __init ps3_register_ipi_debug_brk(unsigned int cpu, unsigned int virq) | |||
484 | cpu, virq, pd->bmp.ipi_debug_brk_mask); | 558 | cpu, virq, pd->bmp.ipi_debug_brk_mask); |
485 | } | 559 | } |
486 | 560 | ||
487 | static int bmp_get_and_clear_status_bit(struct bmp *m) | 561 | unsigned int ps3_get_irq(void) |
488 | { | 562 | { |
489 | unsigned long flags; | 563 | struct ps3_private *pd = &__get_cpu_var(ps3_private); |
490 | unsigned int bit; | 564 | u64 x = (pd->bmp.status & pd->bmp.mask); |
491 | unsigned long x; | 565 | unsigned int plug; |
492 | |||
493 | spin_lock_irqsave(&m->lock, flags); | ||
494 | 566 | ||
495 | /* check for ipi break first to stop this cpu ASAP */ | 567 | /* check for ipi break first to stop this cpu ASAP */ |
496 | 568 | ||
497 | if (m->status & m->ipi_debug_brk_mask) { | 569 | if (x & pd->bmp.ipi_debug_brk_mask) |
498 | m->status &= ~m->ipi_debug_brk_mask; | 570 | x &= pd->bmp.ipi_debug_brk_mask; |
499 | spin_unlock_irqrestore(&m->lock, flags); | ||
500 | return __ilog2(m->ipi_debug_brk_mask); | ||
501 | } | ||
502 | |||
503 | x = (m->status & m->mask); | ||
504 | 571 | ||
505 | for (bit = NUM_ISA_INTERRUPTS, x <<= bit; x; bit++, x <<= 1) | 572 | asm volatile("cntlzd %0,%1" : "=r" (plug) : "r" (x)); |
506 | if (x & 0x8000000000000000UL) { | 573 | plug &= 0x3f; |
507 | m->status &= ~(0x8000000000000000UL >> bit); | ||
508 | spin_unlock_irqrestore(&m->lock, flags); | ||
509 | return bit; | ||
510 | } | ||
511 | 574 | ||
512 | spin_unlock_irqrestore(&m->lock, flags); | 575 | if (unlikely(plug) == NO_IRQ) { |
513 | |||
514 | pr_debug("%s:%d: not found\n", __func__, __LINE__); | ||
515 | return -1; | ||
516 | } | ||
517 | |||
518 | unsigned int ps3_get_irq(void) | ||
519 | { | ||
520 | int plug; | ||
521 | |||
522 | struct private *pd = &__get_cpu_var(private); | ||
523 | |||
524 | plug = bmp_get_and_clear_status_bit(&pd->bmp); | ||
525 | |||
526 | if (plug < 1) { | ||
527 | pr_debug("%s:%d: no plug found: cpu %u\n", __func__, __LINE__, | 576 | pr_debug("%s:%d: no plug found: cpu %u\n", __func__, __LINE__, |
528 | pd->cpu); | 577 | pd->cpu); |
529 | dump_bmp(&per_cpu(private, 0)); | 578 | dump_bmp(&per_cpu(ps3_private, 0)); |
530 | dump_bmp(&per_cpu(private, 1)); | 579 | dump_bmp(&per_cpu(ps3_private, 1)); |
531 | return NO_IRQ; | 580 | return NO_IRQ; |
532 | } | 581 | } |
533 | 582 | ||
534 | #if defined(DEBUG) | 583 | #if defined(DEBUG) |
535 | if (plug < NUM_ISA_INTERRUPTS || plug > PS3_PLUG_MAX) { | 584 | if (unlikely(plug < NUM_ISA_INTERRUPTS || plug > PS3_PLUG_MAX)) { |
536 | dump_bmp(&per_cpu(private, 0)); | 585 | dump_bmp(&per_cpu(ps3_private, 0)); |
537 | dump_bmp(&per_cpu(private, 1)); | 586 | dump_bmp(&per_cpu(ps3_private, 1)); |
538 | BUG(); | 587 | BUG(); |
539 | } | 588 | } |
540 | #endif | 589 | #endif |
@@ -544,26 +593,27 @@ unsigned int ps3_get_irq(void) | |||
544 | void __init ps3_init_IRQ(void) | 593 | void __init ps3_init_IRQ(void) |
545 | { | 594 | { |
546 | int result; | 595 | int result; |
547 | unsigned long node; | ||
548 | unsigned cpu; | 596 | unsigned cpu; |
549 | struct irq_host *host; | 597 | struct irq_host *host; |
550 | 598 | ||
551 | lv1_get_logical_ppe_id(&node); | 599 | host = irq_alloc_host(IRQ_HOST_MAP_NOMAP, 0, &ps3_host_ops, |
552 | |||
553 | host = irq_alloc_host(IRQ_HOST_MAP_NOMAP, 0, &host_ops, | ||
554 | PS3_INVALID_OUTLET); | 600 | PS3_INVALID_OUTLET); |
555 | irq_set_default_host(host); | 601 | irq_set_default_host(host); |
556 | irq_set_virq_count(PS3_PLUG_MAX + 1); | 602 | irq_set_virq_count(PS3_PLUG_MAX + 1); |
557 | 603 | ||
558 | for_each_possible_cpu(cpu) { | 604 | for_each_possible_cpu(cpu) { |
559 | struct private *pd = &per_cpu(private, cpu); | 605 | struct ps3_private *pd = &per_cpu(ps3_private, cpu); |
560 | 606 | ||
561 | pd->node = node; | 607 | lv1_get_logical_ppe_id(&pd->node); |
562 | pd->cpu = cpu; | 608 | pd->cpu = get_hard_smp_processor_id(cpu); |
563 | spin_lock_init(&pd->bmp.lock); | 609 | spin_lock_init(&pd->bmp.lock); |
564 | 610 | ||
565 | result = lv1_configure_irq_state_bitmap(node, cpu, | 611 | pr_debug("%s:%d: node %lu, cpu %d, bmp %lxh\n", __func__, |
566 | ps3_mm_phys_to_lpar(__pa(&pd->bmp.status))); | 612 | __LINE__, pd->node, pd->cpu, |
613 | ps3_mm_phys_to_lpar(__pa(&pd->bmp))); | ||
614 | |||
615 | result = lv1_configure_irq_state_bitmap(pd->node, pd->cpu, | ||
616 | ps3_mm_phys_to_lpar(__pa(&pd->bmp))); | ||
567 | 617 | ||
568 | if (result) | 618 | if (result) |
569 | pr_debug("%s:%d: lv1_configure_irq_state_bitmap failed:" | 619 | pr_debug("%s:%d: lv1_configure_irq_state_bitmap failed:" |
diff --git a/arch/powerpc/platforms/ps3/mm.c b/arch/powerpc/platforms/ps3/mm.c index 49c0d010d491..42354de3f557 100644 --- a/arch/powerpc/platforms/ps3/mm.c +++ b/arch/powerpc/platforms/ps3/mm.c | |||
@@ -25,7 +25,6 @@ | |||
25 | #include <asm/firmware.h> | 25 | #include <asm/firmware.h> |
26 | #include <asm/lmb.h> | 26 | #include <asm/lmb.h> |
27 | #include <asm/udbg.h> | 27 | #include <asm/udbg.h> |
28 | #include <asm/ps3.h> | ||
29 | #include <asm/lv1call.h> | 28 | #include <asm/lv1call.h> |
30 | 29 | ||
31 | #include "platform.h" | 30 | #include "platform.h" |
diff --git a/arch/powerpc/platforms/ps3/os-area.c b/arch/powerpc/platforms/ps3/os-area.c index 58358305dc10..5c3da08bc0c4 100644 --- a/arch/powerpc/platforms/ps3/os-area.c +++ b/arch/powerpc/platforms/ps3/os-area.c | |||
@@ -22,7 +22,6 @@ | |||
22 | #include <linux/io.h> | 22 | #include <linux/io.h> |
23 | 23 | ||
24 | #include <asm/lmb.h> | 24 | #include <asm/lmb.h> |
25 | #include <asm/ps3.h> | ||
26 | 25 | ||
27 | #include "platform.h" | 26 | #include "platform.h" |
28 | 27 | ||
@@ -59,7 +58,7 @@ struct os_area_header { | |||
59 | u32 ldr_format; | 58 | u32 ldr_format; |
60 | u32 ldr_size; | 59 | u32 ldr_size; |
61 | u32 _reserved_2[6]; | 60 | u32 _reserved_2[6]; |
62 | } __attribute__ ((packed)); | 61 | }; |
63 | 62 | ||
64 | enum { | 63 | enum { |
65 | PARAM_BOOT_FLAG_GAME_OS = 0, | 64 | PARAM_BOOT_FLAG_GAME_OS = 0, |
@@ -67,13 +66,6 @@ enum { | |||
67 | }; | 66 | }; |
68 | 67 | ||
69 | enum { | 68 | enum { |
70 | PARAM_AV_MULTI_OUT_NTSC = 0, | ||
71 | PARAM_AV_MULTI_OUT_PAL_RGB = 1, | ||
72 | PARAM_AV_MULTI_OUT_PAL_YCBCR = 2, | ||
73 | PARAM_AV_MULTI_OUT_SECAM = 3, | ||
74 | }; | ||
75 | |||
76 | enum { | ||
77 | PARAM_CTRL_BUTTON_O_IS_YES = 0, | 69 | PARAM_CTRL_BUTTON_O_IS_YES = 0, |
78 | PARAM_CTRL_BUTTON_X_IS_YES = 1, | 70 | PARAM_CTRL_BUTTON_X_IS_YES = 1, |
79 | }; | 71 | }; |
@@ -114,7 +106,7 @@ struct os_area_params { | |||
114 | u8 dns_primary[4]; | 106 | u8 dns_primary[4]; |
115 | u8 dns_secondary[4]; | 107 | u8 dns_secondary[4]; |
116 | u8 _reserved_5[8]; | 108 | u8 _reserved_5[8]; |
117 | } __attribute__ ((packed)); | 109 | }; |
118 | 110 | ||
119 | /** | 111 | /** |
120 | * struct saved_params - Static working copies of data from the 'Other OS' area. | 112 | * struct saved_params - Static working copies of data from the 'Other OS' area. |
@@ -257,3 +249,13 @@ u64 ps3_os_area_rtc_diff(void) | |||
257 | { | 249 | { |
258 | return saved_params.rtc_diff ? saved_params.rtc_diff : 946684800UL; | 250 | return saved_params.rtc_diff ? saved_params.rtc_diff : 946684800UL; |
259 | } | 251 | } |
252 | |||
253 | /** | ||
254 | * ps3_os_area_get_av_multi_out - Returns the default video mode. | ||
255 | */ | ||
256 | |||
257 | enum ps3_param_av_multi_out ps3_os_area_get_av_multi_out(void) | ||
258 | { | ||
259 | return saved_params.av_multi_out; | ||
260 | } | ||
261 | EXPORT_SYMBOL_GPL(ps3_os_area_get_av_multi_out); | ||
diff --git a/arch/powerpc/platforms/ps3/platform.h b/arch/powerpc/platforms/ps3/platform.h index 23b111bea9d0..ca04f03305c7 100644 --- a/arch/powerpc/platforms/ps3/platform.h +++ b/arch/powerpc/platforms/ps3/platform.h | |||
@@ -22,6 +22,9 @@ | |||
22 | #define _PS3_PLATFORM_H | 22 | #define _PS3_PLATFORM_H |
23 | 23 | ||
24 | #include <linux/rtc.h> | 24 | #include <linux/rtc.h> |
25 | #include <scsi/scsi.h> | ||
26 | |||
27 | #include <asm/ps3.h> | ||
25 | 28 | ||
26 | /* htab */ | 29 | /* htab */ |
27 | 30 | ||
@@ -65,4 +68,152 @@ void ps3_spu_set_platform (void); | |||
65 | static inline void ps3_spu_set_platform (void) {} | 68 | static inline void ps3_spu_set_platform (void) {} |
66 | #endif | 69 | #endif |
67 | 70 | ||
71 | /* repository bus info */ | ||
72 | |||
73 | enum ps3_bus_type { | ||
74 | PS3_BUS_TYPE_SB = 4, | ||
75 | PS3_BUS_TYPE_STORAGE = 5, | ||
76 | }; | ||
77 | |||
78 | enum ps3_dev_type { | ||
79 | PS3_DEV_TYPE_STOR_DISK = TYPE_DISK, /* 0 */ | ||
80 | PS3_DEV_TYPE_SB_GELIC = 3, | ||
81 | PS3_DEV_TYPE_SB_USB = 4, | ||
82 | PS3_DEV_TYPE_STOR_ROM = TYPE_ROM, /* 5 */ | ||
83 | PS3_DEV_TYPE_SB_GPIO = 6, | ||
84 | PS3_DEV_TYPE_STOR_FLASH = TYPE_RBC, /* 14 */ | ||
85 | }; | ||
86 | |||
87 | int ps3_repository_read_bus_str(unsigned int bus_index, const char *bus_str, | ||
88 | u64 *value); | ||
89 | int ps3_repository_read_bus_id(unsigned int bus_index, unsigned int *bus_id); | ||
90 | int ps3_repository_read_bus_type(unsigned int bus_index, | ||
91 | enum ps3_bus_type *bus_type); | ||
92 | int ps3_repository_read_bus_num_dev(unsigned int bus_index, | ||
93 | unsigned int *num_dev); | ||
94 | |||
95 | /* repository bus device info */ | ||
96 | |||
97 | enum ps3_interrupt_type { | ||
98 | PS3_INTERRUPT_TYPE_EVENT_PORT = 2, | ||
99 | PS3_INTERRUPT_TYPE_SB_OHCI = 3, | ||
100 | PS3_INTERRUPT_TYPE_SB_EHCI = 4, | ||
101 | PS3_INTERRUPT_TYPE_OTHER = 5, | ||
102 | }; | ||
103 | |||
104 | enum ps3_reg_type { | ||
105 | PS3_REG_TYPE_SB_OHCI = 3, | ||
106 | PS3_REG_TYPE_SB_EHCI = 4, | ||
107 | PS3_REG_TYPE_SB_GPIO = 5, | ||
108 | }; | ||
109 | |||
110 | int ps3_repository_read_dev_str(unsigned int bus_index, | ||
111 | unsigned int dev_index, const char *dev_str, u64 *value); | ||
112 | int ps3_repository_read_dev_id(unsigned int bus_index, unsigned int dev_index, | ||
113 | unsigned int *dev_id); | ||
114 | int ps3_repository_read_dev_type(unsigned int bus_index, | ||
115 | unsigned int dev_index, enum ps3_dev_type *dev_type); | ||
116 | int ps3_repository_read_dev_intr(unsigned int bus_index, | ||
117 | unsigned int dev_index, unsigned int intr_index, | ||
118 | enum ps3_interrupt_type *intr_type, unsigned int *interrupt_id); | ||
119 | int ps3_repository_read_dev_reg_type(unsigned int bus_index, | ||
120 | unsigned int dev_index, unsigned int reg_index, | ||
121 | enum ps3_reg_type *reg_type); | ||
122 | int ps3_repository_read_dev_reg_addr(unsigned int bus_index, | ||
123 | unsigned int dev_index, unsigned int reg_index, u64 *bus_addr, | ||
124 | u64 *len); | ||
125 | int ps3_repository_read_dev_reg(unsigned int bus_index, | ||
126 | unsigned int dev_index, unsigned int reg_index, | ||
127 | enum ps3_reg_type *reg_type, u64 *bus_addr, u64 *len); | ||
128 | |||
129 | /* repository bus enumerators */ | ||
130 | |||
131 | struct ps3_repository_device { | ||
132 | unsigned int bus_index; | ||
133 | unsigned int dev_index; | ||
134 | struct ps3_device_id did; | ||
135 | }; | ||
136 | |||
137 | int ps3_repository_find_device(enum ps3_bus_type bus_type, | ||
138 | enum ps3_dev_type dev_type, | ||
139 | const struct ps3_repository_device *start_dev, | ||
140 | struct ps3_repository_device *dev); | ||
141 | static inline int ps3_repository_find_first_device( | ||
142 | enum ps3_bus_type bus_type, enum ps3_dev_type dev_type, | ||
143 | struct ps3_repository_device *dev) | ||
144 | { | ||
145 | return ps3_repository_find_device(bus_type, dev_type, NULL, dev); | ||
146 | } | ||
147 | int ps3_repository_find_interrupt(const struct ps3_repository_device *dev, | ||
148 | enum ps3_interrupt_type intr_type, unsigned int *interrupt_id); | ||
149 | int ps3_repository_find_reg(const struct ps3_repository_device *dev, | ||
150 | enum ps3_reg_type reg_type, u64 *bus_addr, u64 *len); | ||
151 | |||
152 | /* repository block device info */ | ||
153 | |||
154 | int ps3_repository_read_stor_dev_port(unsigned int bus_index, | ||
155 | unsigned int dev_index, u64 *port); | ||
156 | int ps3_repository_read_stor_dev_blk_size(unsigned int bus_index, | ||
157 | unsigned int dev_index, u64 *blk_size); | ||
158 | int ps3_repository_read_stor_dev_num_blocks(unsigned int bus_index, | ||
159 | unsigned int dev_index, u64 *num_blocks); | ||
160 | int ps3_repository_read_stor_dev_num_regions(unsigned int bus_index, | ||
161 | unsigned int dev_index, unsigned int *num_regions); | ||
162 | int ps3_repository_read_stor_dev_region_id(unsigned int bus_index, | ||
163 | unsigned int dev_index, unsigned int region_index, | ||
164 | unsigned int *region_id); | ||
165 | int ps3_repository_read_stor_dev_region_size(unsigned int bus_index, | ||
166 | unsigned int dev_index, unsigned int region_index, u64 *region_size); | ||
167 | int ps3_repository_read_stor_dev_region_start(unsigned int bus_index, | ||
168 | unsigned int dev_index, unsigned int region_index, u64 *region_start); | ||
169 | int ps3_repository_read_stor_dev_info(unsigned int bus_index, | ||
170 | unsigned int dev_index, u64 *port, u64 *blk_size, | ||
171 | u64 *num_blocks, unsigned int *num_regions); | ||
172 | int ps3_repository_read_stor_dev_region(unsigned int bus_index, | ||
173 | unsigned int dev_index, unsigned int region_index, | ||
174 | unsigned int *region_id, u64 *region_start, u64 *region_size); | ||
175 | |||
176 | /* repository pu and memory info */ | ||
177 | |||
178 | int ps3_repository_read_num_pu(unsigned int *num_pu); | ||
179 | int ps3_repository_read_ppe_id(unsigned int *pu_index, unsigned int *ppe_id); | ||
180 | int ps3_repository_read_rm_base(unsigned int ppe_id, u64 *rm_base); | ||
181 | int ps3_repository_read_rm_size(unsigned int ppe_id, u64 *rm_size); | ||
182 | int ps3_repository_read_region_total(u64 *region_total); | ||
183 | int ps3_repository_read_mm_info(u64 *rm_base, u64 *rm_size, | ||
184 | u64 *region_total); | ||
185 | |||
186 | /* repository pme info */ | ||
187 | |||
188 | int ps3_repository_read_num_be(unsigned int *num_be); | ||
189 | int ps3_repository_read_be_node_id(unsigned int be_index, u64 *node_id); | ||
190 | int ps3_repository_read_tb_freq(u64 node_id, u64 *tb_freq); | ||
191 | int ps3_repository_read_be_tb_freq(unsigned int be_index, u64 *tb_freq); | ||
192 | |||
193 | /* repository 'Other OS' area */ | ||
194 | |||
195 | int ps3_repository_read_boot_dat_addr(u64 *lpar_addr); | ||
196 | int ps3_repository_read_boot_dat_size(unsigned int *size); | ||
197 | int ps3_repository_read_boot_dat_info(u64 *lpar_addr, unsigned int *size); | ||
198 | |||
199 | /* repository spu info */ | ||
200 | |||
201 | /** | ||
202 | * enum spu_resource_type - Type of spu resource. | ||
203 | * @spu_resource_type_shared: Logical spu is shared with other partions. | ||
204 | * @spu_resource_type_exclusive: Logical spu is not shared with other partions. | ||
205 | * | ||
206 | * Returned by ps3_repository_read_spu_resource_id(). | ||
207 | */ | ||
208 | |||
209 | enum ps3_spu_resource_type { | ||
210 | PS3_SPU_RESOURCE_TYPE_SHARED = 0, | ||
211 | PS3_SPU_RESOURCE_TYPE_EXCLUSIVE = 0x8000000000000000UL, | ||
212 | }; | ||
213 | |||
214 | int ps3_repository_read_num_spu_reserved(unsigned int *num_spu_reserved); | ||
215 | int ps3_repository_read_num_spu_resource_id(unsigned int *num_resource_id); | ||
216 | int ps3_repository_read_spu_resource_id(unsigned int res_index, | ||
217 | enum ps3_spu_resource_type* resource_type, unsigned int *resource_id); | ||
218 | |||
68 | #endif | 219 | #endif |
diff --git a/arch/powerpc/platforms/ps3/repository.c b/arch/powerpc/platforms/ps3/repository.c index 273a0d621bdd..ae586a0e5d3f 100644 --- a/arch/powerpc/platforms/ps3/repository.c +++ b/arch/powerpc/platforms/ps3/repository.c | |||
@@ -18,9 +18,10 @@ | |||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
19 | */ | 19 | */ |
20 | 20 | ||
21 | #include <asm/ps3.h> | ||
22 | #include <asm/lv1call.h> | 21 | #include <asm/lv1call.h> |
23 | 22 | ||
23 | #include "platform.h" | ||
24 | |||
24 | enum ps3_vendor_id { | 25 | enum ps3_vendor_id { |
25 | PS3_VENDOR_ID_NONE = 0, | 26 | PS3_VENDOR_ID_NONE = 0, |
26 | PS3_VENDOR_ID_SONY = 0x8000000000000000UL, | 27 | PS3_VENDOR_ID_SONY = 0x8000000000000000UL, |
@@ -257,7 +258,7 @@ int ps3_repository_read_dev_type(unsigned int bus_index, | |||
257 | 258 | ||
258 | int ps3_repository_read_dev_intr(unsigned int bus_index, | 259 | int ps3_repository_read_dev_intr(unsigned int bus_index, |
259 | unsigned int dev_index, unsigned int intr_index, | 260 | unsigned int dev_index, unsigned int intr_index, |
260 | unsigned int *intr_type, unsigned int* interrupt_id) | 261 | enum ps3_interrupt_type *intr_type, unsigned int* interrupt_id) |
261 | { | 262 | { |
262 | int result; | 263 | int result; |
263 | u64 v1; | 264 | u64 v1; |
@@ -275,7 +276,8 @@ int ps3_repository_read_dev_intr(unsigned int bus_index, | |||
275 | } | 276 | } |
276 | 277 | ||
277 | int ps3_repository_read_dev_reg_type(unsigned int bus_index, | 278 | int ps3_repository_read_dev_reg_type(unsigned int bus_index, |
278 | unsigned int dev_index, unsigned int reg_index, unsigned int *reg_type) | 279 | unsigned int dev_index, unsigned int reg_index, |
280 | enum ps3_reg_type *reg_type) | ||
279 | { | 281 | { |
280 | int result; | 282 | int result; |
281 | u64 v1; | 283 | u64 v1; |
@@ -302,8 +304,8 @@ int ps3_repository_read_dev_reg_addr(unsigned int bus_index, | |||
302 | } | 304 | } |
303 | 305 | ||
304 | int ps3_repository_read_dev_reg(unsigned int bus_index, | 306 | int ps3_repository_read_dev_reg(unsigned int bus_index, |
305 | unsigned int dev_index, unsigned int reg_index, unsigned int *reg_type, | 307 | unsigned int dev_index, unsigned int reg_index, |
306 | u64 *bus_addr, u64 *len) | 308 | enum ps3_reg_type *reg_type, u64 *bus_addr, u64 *len) |
307 | { | 309 | { |
308 | int result = ps3_repository_read_dev_reg_type(bus_index, dev_index, | 310 | int result = ps3_repository_read_dev_reg_type(bus_index, dev_index, |
309 | reg_index, reg_type); | 311 | reg_index, reg_type); |
@@ -343,7 +345,7 @@ int ps3_repository_dump_resource_info(unsigned int bus_index, | |||
343 | } | 345 | } |
344 | 346 | ||
345 | for (res_index = 0; res_index < 10; res_index++) { | 347 | for (res_index = 0; res_index < 10; res_index++) { |
346 | enum ps3_region_type reg_type; | 348 | enum ps3_reg_type reg_type; |
347 | u64 bus_addr; | 349 | u64 bus_addr; |
348 | u64 len; | 350 | u64 len; |
349 | 351 | ||
@@ -367,7 +369,55 @@ int ps3_repository_dump_resource_info(unsigned int bus_index, | |||
367 | return result; | 369 | return result; |
368 | } | 370 | } |
369 | 371 | ||
370 | static int dump_device_info(unsigned int bus_index, unsigned int num_dev) | 372 | static int dump_stor_dev_info(unsigned int bus_index, unsigned int dev_index) |
373 | { | ||
374 | int result = 0; | ||
375 | unsigned int num_regions, region_index; | ||
376 | u64 port, blk_size, num_blocks; | ||
377 | |||
378 | pr_debug(" -> %s:%d: (%u:%u)\n", __func__, __LINE__, | ||
379 | bus_index, dev_index); | ||
380 | |||
381 | result = ps3_repository_read_stor_dev_info(bus_index, dev_index, &port, | ||
382 | &blk_size, &num_blocks, &num_regions); | ||
383 | if (result) { | ||
384 | pr_debug("%s:%d ps3_repository_read_stor_dev_info" | ||
385 | " (%u:%u) failed\n", __func__, __LINE__, | ||
386 | bus_index, dev_index); | ||
387 | goto out; | ||
388 | } | ||
389 | |||
390 | pr_debug("%s:%d (%u:%u): port %lu, blk_size %lu, num_blocks " | ||
391 | "%lu, num_regions %u\n", | ||
392 | __func__, __LINE__, bus_index, dev_index, port, | ||
393 | blk_size, num_blocks, num_regions); | ||
394 | |||
395 | for (region_index = 0; region_index < num_regions; region_index++) { | ||
396 | unsigned int region_id; | ||
397 | u64 region_start, region_size; | ||
398 | |||
399 | result = ps3_repository_read_stor_dev_region(bus_index, | ||
400 | dev_index, region_index, ®ion_id, ®ion_start, | ||
401 | ®ion_size); | ||
402 | if (result) { | ||
403 | pr_debug("%s:%d ps3_repository_read_stor_dev_region" | ||
404 | " (%u:%u) failed\n", __func__, __LINE__, | ||
405 | bus_index, dev_index); | ||
406 | break; | ||
407 | } | ||
408 | |||
409 | pr_debug("%s:%d (%u:%u) region_id %u, start %lxh, size %lxh\n", | ||
410 | __func__, __LINE__, bus_index, dev_index, region_id, | ||
411 | region_start, region_size); | ||
412 | } | ||
413 | |||
414 | out: | ||
415 | pr_debug(" <- %s:%d\n", __func__, __LINE__); | ||
416 | return result; | ||
417 | } | ||
418 | |||
419 | static int dump_device_info(unsigned int bus_index, enum ps3_bus_type bus_type, | ||
420 | unsigned int num_dev) | ||
371 | { | 421 | { |
372 | int result = 0; | 422 | int result = 0; |
373 | unsigned int dev_index; | 423 | unsigned int dev_index; |
@@ -402,6 +452,9 @@ static int dump_device_info(unsigned int bus_index, unsigned int num_dev) | |||
402 | __LINE__, bus_index, dev_index, dev_type, dev_id); | 452 | __LINE__, bus_index, dev_index, dev_type, dev_id); |
403 | 453 | ||
404 | ps3_repository_dump_resource_info(bus_index, dev_index); | 454 | ps3_repository_dump_resource_info(bus_index, dev_index); |
455 | |||
456 | if (bus_type == PS3_BUS_TYPE_STORAGE) | ||
457 | dump_stor_dev_info(bus_index, dev_index); | ||
405 | } | 458 | } |
406 | 459 | ||
407 | pr_debug(" <- %s:%d\n", __func__, __LINE__); | 460 | pr_debug(" <- %s:%d\n", __func__, __LINE__); |
@@ -452,7 +505,7 @@ int ps3_repository_dump_bus_info(void) | |||
452 | __func__, __LINE__, bus_index, bus_type, bus_id, | 505 | __func__, __LINE__, bus_index, bus_type, bus_id, |
453 | num_dev); | 506 | num_dev); |
454 | 507 | ||
455 | dump_device_info(bus_index, num_dev); | 508 | dump_device_info(bus_index, bus_type, num_dev); |
456 | } | 509 | } |
457 | 510 | ||
458 | pr_debug(" <- %s:%d\n", __func__, __LINE__); | 511 | pr_debug(" <- %s:%d\n", __func__, __LINE__); |
@@ -487,7 +540,8 @@ static int find_device(unsigned int bus_index, unsigned int num_dev, | |||
487 | break; | 540 | break; |
488 | } | 541 | } |
489 | 542 | ||
490 | BUG_ON(dev_index == num_dev); | 543 | if (dev_index == num_dev) |
544 | return -1; | ||
491 | 545 | ||
492 | pr_debug("%s:%d: found dev_type %u at dev_index %u\n", | 546 | pr_debug("%s:%d: found dev_type %u at dev_index %u\n", |
493 | __func__, __LINE__, dev_type, dev_index); | 547 | __func__, __LINE__, dev_type, dev_index); |
@@ -521,7 +575,7 @@ int ps3_repository_find_device (enum ps3_bus_type bus_type, | |||
521 | pr_debug("%s:%d: find bus_type %u, dev_type %u\n", __func__, __LINE__, | 575 | pr_debug("%s:%d: find bus_type %u, dev_type %u\n", __func__, __LINE__, |
522 | bus_type, dev_type); | 576 | bus_type, dev_type); |
523 | 577 | ||
524 | dev->bus_index = UINT_MAX; | 578 | BUG_ON(start_dev && start_dev->bus_index > 10); |
525 | 579 | ||
526 | for (bus_index = start_dev ? start_dev->bus_index : 0; bus_index < 10; | 580 | for (bus_index = start_dev ? start_dev->bus_index : 0; bus_index < 10; |
527 | bus_index++) { | 581 | bus_index++) { |
@@ -532,13 +586,15 @@ int ps3_repository_find_device (enum ps3_bus_type bus_type, | |||
532 | if (result) { | 586 | if (result) { |
533 | pr_debug("%s:%d read_bus_type failed\n", | 587 | pr_debug("%s:%d read_bus_type failed\n", |
534 | __func__, __LINE__); | 588 | __func__, __LINE__); |
589 | dev->bus_index = UINT_MAX; | ||
535 | return result; | 590 | return result; |
536 | } | 591 | } |
537 | if (x == bus_type) | 592 | if (x == bus_type) |
538 | break; | 593 | break; |
539 | } | 594 | } |
540 | 595 | ||
541 | BUG_ON(bus_index == 10); | 596 | if (bus_index >= 10) |
597 | return -ENODEV; | ||
542 | 598 | ||
543 | pr_debug("%s:%d: found bus_type %u at bus_index %u\n", | 599 | pr_debug("%s:%d: found bus_type %u at bus_index %u\n", |
544 | __func__, __LINE__, bus_type, bus_index); | 600 | __func__, __LINE__, bus_type, bus_index); |
@@ -604,7 +660,8 @@ int ps3_repository_find_interrupt(const struct ps3_repository_device *dev, | |||
604 | } | 660 | } |
605 | } | 661 | } |
606 | 662 | ||
607 | BUG_ON(res_index == 10); | 663 | if (res_index == 10) |
664 | return -ENODEV; | ||
608 | 665 | ||
609 | pr_debug("%s:%d: found intr_type %u at res_index %u\n", | 666 | pr_debug("%s:%d: found intr_type %u at res_index %u\n", |
610 | __func__, __LINE__, intr_type, res_index); | 667 | __func__, __LINE__, intr_type, res_index); |
@@ -612,8 +669,8 @@ int ps3_repository_find_interrupt(const struct ps3_repository_device *dev, | |||
612 | return result; | 669 | return result; |
613 | } | 670 | } |
614 | 671 | ||
615 | int ps3_repository_find_region(const struct ps3_repository_device *dev, | 672 | int ps3_repository_find_reg(const struct ps3_repository_device *dev, |
616 | enum ps3_region_type reg_type, u64 *bus_addr, u64 *len) | 673 | enum ps3_reg_type reg_type, u64 *bus_addr, u64 *len) |
617 | { | 674 | { |
618 | int result = 0; | 675 | int result = 0; |
619 | unsigned int res_index; | 676 | unsigned int res_index; |
@@ -623,7 +680,7 @@ int ps3_repository_find_region(const struct ps3_repository_device *dev, | |||
623 | *bus_addr = *len = 0; | 680 | *bus_addr = *len = 0; |
624 | 681 | ||
625 | for (res_index = 0; res_index < 10; res_index++) { | 682 | for (res_index = 0; res_index < 10; res_index++) { |
626 | enum ps3_region_type t; | 683 | enum ps3_reg_type t; |
627 | u64 a; | 684 | u64 a; |
628 | u64 l; | 685 | u64 l; |
629 | 686 | ||
@@ -643,7 +700,8 @@ int ps3_repository_find_region(const struct ps3_repository_device *dev, | |||
643 | } | 700 | } |
644 | } | 701 | } |
645 | 702 | ||
646 | BUG_ON(res_index == 10); | 703 | if (res_index == 10) |
704 | return -ENODEV; | ||
647 | 705 | ||
648 | pr_debug("%s:%d: found reg_type %u at res_index %u\n", | 706 | pr_debug("%s:%d: found reg_type %u at res_index %u\n", |
649 | __func__, __LINE__, reg_type, res_index); | 707 | __func__, __LINE__, reg_type, res_index); |
@@ -651,6 +709,136 @@ int ps3_repository_find_region(const struct ps3_repository_device *dev, | |||
651 | return result; | 709 | return result; |
652 | } | 710 | } |
653 | 711 | ||
712 | int ps3_repository_read_stor_dev_port(unsigned int bus_index, | ||
713 | unsigned int dev_index, u64 *port) | ||
714 | { | ||
715 | return read_node(PS3_LPAR_ID_PME, | ||
716 | make_first_field("bus", bus_index), | ||
717 | make_field("dev", dev_index), | ||
718 | make_field("port", 0), | ||
719 | 0, port, 0); | ||
720 | } | ||
721 | |||
722 | int ps3_repository_read_stor_dev_blk_size(unsigned int bus_index, | ||
723 | unsigned int dev_index, u64 *blk_size) | ||
724 | { | ||
725 | return read_node(PS3_LPAR_ID_PME, | ||
726 | make_first_field("bus", bus_index), | ||
727 | make_field("dev", dev_index), | ||
728 | make_field("blk_size", 0), | ||
729 | 0, blk_size, 0); | ||
730 | } | ||
731 | |||
732 | int ps3_repository_read_stor_dev_num_blocks(unsigned int bus_index, | ||
733 | unsigned int dev_index, u64 *num_blocks) | ||
734 | { | ||
735 | return read_node(PS3_LPAR_ID_PME, | ||
736 | make_first_field("bus", bus_index), | ||
737 | make_field("dev", dev_index), | ||
738 | make_field("n_blocks", 0), | ||
739 | 0, num_blocks, 0); | ||
740 | } | ||
741 | |||
742 | int ps3_repository_read_stor_dev_num_regions(unsigned int bus_index, | ||
743 | unsigned int dev_index, unsigned int *num_regions) | ||
744 | { | ||
745 | int result; | ||
746 | u64 v1; | ||
747 | |||
748 | result = read_node(PS3_LPAR_ID_PME, | ||
749 | make_first_field("bus", bus_index), | ||
750 | make_field("dev", dev_index), | ||
751 | make_field("n_regs", 0), | ||
752 | 0, &v1, 0); | ||
753 | *num_regions = v1; | ||
754 | return result; | ||
755 | } | ||
756 | |||
757 | int ps3_repository_read_stor_dev_region_id(unsigned int bus_index, | ||
758 | unsigned int dev_index, unsigned int region_index, | ||
759 | unsigned int *region_id) | ||
760 | { | ||
761 | int result; | ||
762 | u64 v1; | ||
763 | |||
764 | result = read_node(PS3_LPAR_ID_PME, | ||
765 | make_first_field("bus", bus_index), | ||
766 | make_field("dev", dev_index), | ||
767 | make_field("region", region_index), | ||
768 | make_field("id", 0), | ||
769 | &v1, 0); | ||
770 | *region_id = v1; | ||
771 | return result; | ||
772 | } | ||
773 | |||
774 | int ps3_repository_read_stor_dev_region_size(unsigned int bus_index, | ||
775 | unsigned int dev_index, unsigned int region_index, u64 *region_size) | ||
776 | { | ||
777 | return read_node(PS3_LPAR_ID_PME, | ||
778 | make_first_field("bus", bus_index), | ||
779 | make_field("dev", dev_index), | ||
780 | make_field("region", region_index), | ||
781 | make_field("size", 0), | ||
782 | region_size, 0); | ||
783 | } | ||
784 | |||
785 | int ps3_repository_read_stor_dev_region_start(unsigned int bus_index, | ||
786 | unsigned int dev_index, unsigned int region_index, u64 *region_start) | ||
787 | { | ||
788 | return read_node(PS3_LPAR_ID_PME, | ||
789 | make_first_field("bus", bus_index), | ||
790 | make_field("dev", dev_index), | ||
791 | make_field("region", region_index), | ||
792 | make_field("start", 0), | ||
793 | region_start, 0); | ||
794 | } | ||
795 | |||
796 | int ps3_repository_read_stor_dev_info(unsigned int bus_index, | ||
797 | unsigned int dev_index, u64 *port, u64 *blk_size, | ||
798 | u64 *num_blocks, unsigned int *num_regions) | ||
799 | { | ||
800 | int result; | ||
801 | |||
802 | result = ps3_repository_read_stor_dev_port(bus_index, dev_index, port); | ||
803 | if (result) | ||
804 | return result; | ||
805 | |||
806 | result = ps3_repository_read_stor_dev_blk_size(bus_index, dev_index, | ||
807 | blk_size); | ||
808 | if (result) | ||
809 | return result; | ||
810 | |||
811 | result = ps3_repository_read_stor_dev_num_blocks(bus_index, dev_index, | ||
812 | num_blocks); | ||
813 | if (result) | ||
814 | return result; | ||
815 | |||
816 | result = ps3_repository_read_stor_dev_num_regions(bus_index, dev_index, | ||
817 | num_regions); | ||
818 | return result; | ||
819 | } | ||
820 | |||
821 | int ps3_repository_read_stor_dev_region(unsigned int bus_index, | ||
822 | unsigned int dev_index, unsigned int region_index, | ||
823 | unsigned int *region_id, u64 *region_start, u64 *region_size) | ||
824 | { | ||
825 | int result; | ||
826 | |||
827 | result = ps3_repository_read_stor_dev_region_id(bus_index, dev_index, | ||
828 | region_index, region_id); | ||
829 | if (result) | ||
830 | return result; | ||
831 | |||
832 | result = ps3_repository_read_stor_dev_region_start(bus_index, dev_index, | ||
833 | region_index, region_start); | ||
834 | if (result) | ||
835 | return result; | ||
836 | |||
837 | result = ps3_repository_read_stor_dev_region_size(bus_index, dev_index, | ||
838 | region_index, region_size); | ||
839 | return result; | ||
840 | } | ||
841 | |||
654 | int ps3_repository_read_rm_size(unsigned int ppe_id, u64 *rm_size) | 842 | int ps3_repository_read_rm_size(unsigned int ppe_id, u64 *rm_size) |
655 | { | 843 | { |
656 | return read_node(PS3_LPAR_ID_CURRENT, | 844 | return read_node(PS3_LPAR_ID_CURRENT, |
diff --git a/arch/powerpc/platforms/ps3/setup.c b/arch/powerpc/platforms/ps3/setup.c index d8b5cadbe80e..ac5df9688dcb 100644 --- a/arch/powerpc/platforms/ps3/setup.c +++ b/arch/powerpc/platforms/ps3/setup.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/root_dev.h> | 24 | #include <linux/root_dev.h> |
25 | #include <linux/console.h> | 25 | #include <linux/console.h> |
26 | #include <linux/kexec.h> | 26 | #include <linux/kexec.h> |
27 | #include <linux/bootmem.h> | ||
27 | 28 | ||
28 | #include <asm/machdep.h> | 29 | #include <asm/machdep.h> |
29 | #include <asm/firmware.h> | 30 | #include <asm/firmware.h> |
@@ -41,10 +42,22 @@ | |||
41 | #define DBG(fmt...) do{if(0)printk(fmt);}while(0) | 42 | #define DBG(fmt...) do{if(0)printk(fmt);}while(0) |
42 | #endif | 43 | #endif |
43 | 44 | ||
44 | static void ps3_show_cpuinfo(struct seq_file *m) | 45 | #if !defined(CONFIG_SMP) |
46 | static void smp_send_stop(void) {} | ||
47 | #endif | ||
48 | |||
49 | int ps3_get_firmware_version(union ps3_firmware_version *v) | ||
45 | { | 50 | { |
46 | seq_printf(m, "machine\t\t: %s\n", ppc_md.name); | 51 | int result = lv1_get_version_info(&v->raw); |
52 | |||
53 | if (result) { | ||
54 | v->raw = 0; | ||
55 | return -1; | ||
56 | } | ||
57 | |||
58 | return result; | ||
47 | } | 59 | } |
60 | EXPORT_SYMBOL_GPL(ps3_get_firmware_version); | ||
48 | 61 | ||
49 | static void ps3_power_save(void) | 62 | static void ps3_power_save(void) |
50 | { | 63 | { |
@@ -57,25 +70,84 @@ static void ps3_power_save(void) | |||
57 | lv1_pause(0); | 70 | lv1_pause(0); |
58 | } | 71 | } |
59 | 72 | ||
73 | static void ps3_restart(char *cmd) | ||
74 | { | ||
75 | DBG("%s:%d cmd '%s'\n", __func__, __LINE__, cmd); | ||
76 | |||
77 | smp_send_stop(); | ||
78 | ps3_sys_manager_restart(); /* never returns */ | ||
79 | } | ||
80 | |||
81 | static void ps3_power_off(void) | ||
82 | { | ||
83 | DBG("%s:%d\n", __func__, __LINE__); | ||
84 | |||
85 | smp_send_stop(); | ||
86 | ps3_sys_manager_power_off(); /* never returns */ | ||
87 | } | ||
88 | |||
60 | static void ps3_panic(char *str) | 89 | static void ps3_panic(char *str) |
61 | { | 90 | { |
62 | DBG("%s:%d %s\n", __func__, __LINE__, str); | 91 | DBG("%s:%d %s\n", __func__, __LINE__, str); |
63 | 92 | ||
64 | #ifdef CONFIG_SMP | ||
65 | smp_send_stop(); | 93 | smp_send_stop(); |
66 | #endif | ||
67 | printk("\n"); | 94 | printk("\n"); |
68 | printk(" System does not reboot automatically.\n"); | 95 | printk(" System does not reboot automatically.\n"); |
69 | printk(" Please press POWER button.\n"); | 96 | printk(" Please press POWER button.\n"); |
70 | printk("\n"); | 97 | printk("\n"); |
71 | 98 | ||
72 | for (;;) ; | 99 | while(1); |
100 | } | ||
101 | |||
102 | static void prealloc(struct ps3_prealloc *p) | ||
103 | { | ||
104 | if (!p->size) | ||
105 | return; | ||
106 | |||
107 | p->address = __alloc_bootmem(p->size, p->align, __pa(MAX_DMA_ADDRESS)); | ||
108 | if (!p->address) { | ||
109 | printk(KERN_ERR "%s: Cannot allocate %s\n", __FUNCTION__, | ||
110 | p->name); | ||
111 | return; | ||
112 | } | ||
113 | |||
114 | printk(KERN_INFO "%s: %lu bytes at %p\n", p->name, p->size, | ||
115 | p->address); | ||
73 | } | 116 | } |
74 | 117 | ||
118 | #ifdef CONFIG_FB_PS3 | ||
119 | struct ps3_prealloc ps3fb_videomemory = { | ||
120 | .name = "ps3fb videomemory", | ||
121 | .size = CONFIG_FB_PS3_DEFAULT_SIZE_M*1024*1024, | ||
122 | .align = 1024*1024 /* the GPU requires 1 MiB alignment */ | ||
123 | }; | ||
124 | #define prealloc_ps3fb_videomemory() prealloc(&ps3fb_videomemory) | ||
125 | |||
126 | static int __init early_parse_ps3fb(char *p) | ||
127 | { | ||
128 | if (!p) | ||
129 | return 1; | ||
130 | |||
131 | ps3fb_videomemory.size = _ALIGN_UP(memparse(p, &p), | ||
132 | ps3fb_videomemory.align); | ||
133 | return 0; | ||
134 | } | ||
135 | early_param("ps3fb", early_parse_ps3fb); | ||
136 | #else | ||
137 | #define prealloc_ps3fb_videomemory() do { } while (0) | ||
138 | #endif | ||
139 | |||
140 | |||
75 | static void __init ps3_setup_arch(void) | 141 | static void __init ps3_setup_arch(void) |
76 | { | 142 | { |
143 | union ps3_firmware_version v; | ||
144 | |||
77 | DBG(" -> %s:%d\n", __func__, __LINE__); | 145 | DBG(" -> %s:%d\n", __func__, __LINE__); |
78 | 146 | ||
147 | ps3_get_firmware_version(&v); | ||
148 | printk(KERN_INFO "PS3 firmware version %u.%u.%u\n", v.major, v.minor, | ||
149 | v.rev); | ||
150 | |||
79 | ps3_spu_set_platform(); | 151 | ps3_spu_set_platform(); |
80 | ps3_map_htab(); | 152 | ps3_map_htab(); |
81 | 153 | ||
@@ -87,6 +159,7 @@ static void __init ps3_setup_arch(void) | |||
87 | conswitchp = &dummy_con; | 159 | conswitchp = &dummy_con; |
88 | #endif | 160 | #endif |
89 | 161 | ||
162 | prealloc_ps3fb_videomemory(); | ||
90 | ppc_md.power_save = ps3_power_save; | 163 | ppc_md.power_save = ps3_power_save; |
91 | 164 | ||
92 | DBG(" <- %s:%d\n", __func__, __LINE__); | 165 | DBG(" <- %s:%d\n", __func__, __LINE__); |
@@ -156,7 +229,6 @@ define_machine(ps3) { | |||
156 | .name = "PS3", | 229 | .name = "PS3", |
157 | .probe = ps3_probe, | 230 | .probe = ps3_probe, |
158 | .setup_arch = ps3_setup_arch, | 231 | .setup_arch = ps3_setup_arch, |
159 | .show_cpuinfo = ps3_show_cpuinfo, | ||
160 | .init_IRQ = ps3_init_IRQ, | 232 | .init_IRQ = ps3_init_IRQ, |
161 | .panic = ps3_panic, | 233 | .panic = ps3_panic, |
162 | .get_boot_time = ps3_get_boot_time, | 234 | .get_boot_time = ps3_get_boot_time, |
@@ -164,6 +236,8 @@ define_machine(ps3) { | |||
164 | .get_rtc_time = ps3_get_rtc_time, | 236 | .get_rtc_time = ps3_get_rtc_time, |
165 | .calibrate_decr = ps3_calibrate_decr, | 237 | .calibrate_decr = ps3_calibrate_decr, |
166 | .progress = ps3_progress, | 238 | .progress = ps3_progress, |
239 | .restart = ps3_restart, | ||
240 | .power_off = ps3_power_off, | ||
167 | #if defined(CONFIG_KEXEC) | 241 | #if defined(CONFIG_KEXEC) |
168 | .kexec_cpu_down = ps3_kexec_cpu_down, | 242 | .kexec_cpu_down = ps3_kexec_cpu_down, |
169 | .machine_kexec = ps3_machine_kexec, | 243 | .machine_kexec = ps3_machine_kexec, |
diff --git a/arch/powerpc/platforms/ps3/smp.c b/arch/powerpc/platforms/ps3/smp.c index 11d2080607ed..6fb887961a6d 100644 --- a/arch/powerpc/platforms/ps3/smp.c +++ b/arch/powerpc/platforms/ps3/smp.c | |||
@@ -23,7 +23,6 @@ | |||
23 | 23 | ||
24 | #include <asm/machdep.h> | 24 | #include <asm/machdep.h> |
25 | #include <asm/udbg.h> | 25 | #include <asm/udbg.h> |
26 | #include <asm/ps3.h> | ||
27 | 26 | ||
28 | #include "platform.h" | 27 | #include "platform.h" |
29 | 28 | ||
@@ -111,7 +110,7 @@ static void __init ps3_smp_setup_cpu(int cpu) | |||
111 | BUILD_BUG_ON(PPC_MSG_DEBUGGER_BREAK != 3); | 110 | BUILD_BUG_ON(PPC_MSG_DEBUGGER_BREAK != 3); |
112 | 111 | ||
113 | for (i = 0; i < MSG_COUNT; i++) { | 112 | for (i = 0; i < MSG_COUNT; i++) { |
114 | result = ps3_alloc_event_irq(&virqs[i]); | 113 | result = ps3_alloc_event_irq(cpu, &virqs[i]); |
115 | 114 | ||
116 | if (result) | 115 | if (result) |
117 | continue; | 116 | continue; |
diff --git a/arch/powerpc/platforms/ps3/spu.c b/arch/powerpc/platforms/ps3/spu.c index 644532c3b7c4..a397e4e17c13 100644 --- a/arch/powerpc/platforms/ps3/spu.c +++ b/arch/powerpc/platforms/ps3/spu.c | |||
@@ -26,9 +26,10 @@ | |||
26 | 26 | ||
27 | #include <asm/spu.h> | 27 | #include <asm/spu.h> |
28 | #include <asm/spu_priv1.h> | 28 | #include <asm/spu_priv1.h> |
29 | #include <asm/ps3.h> | ||
30 | #include <asm/lv1call.h> | 29 | #include <asm/lv1call.h> |
31 | 30 | ||
31 | #include "platform.h" | ||
32 | |||
32 | /* spu_management_ops */ | 33 | /* spu_management_ops */ |
33 | 34 | ||
34 | /** | 35 | /** |
@@ -50,7 +51,7 @@ enum spe_type { | |||
50 | */ | 51 | */ |
51 | 52 | ||
52 | struct spe_shadow { | 53 | struct spe_shadow { |
53 | u8 padding_0000[0x0140]; | 54 | u8 padding_0140[0x0140]; |
54 | u64 int_status_class0_RW; /* 0x0140 */ | 55 | u64 int_status_class0_RW; /* 0x0140 */ |
55 | u64 int_status_class1_RW; /* 0x0148 */ | 56 | u64 int_status_class1_RW; /* 0x0148 */ |
56 | u64 int_status_class2_RW; /* 0x0150 */ | 57 | u64 int_status_class2_RW; /* 0x0150 */ |
@@ -67,8 +68,7 @@ struct spe_shadow { | |||
67 | u8 padding_0c08[0x0f00-0x0c08]; | 68 | u8 padding_0c08[0x0f00-0x0c08]; |
68 | u64 spe_execution_status; /* 0x0f00 */ | 69 | u64 spe_execution_status; /* 0x0f00 */ |
69 | u8 padding_0f08[0x1000-0x0f08]; | 70 | u8 padding_0f08[0x1000-0x0f08]; |
70 | } __attribute__ ((packed)); | 71 | }; |
71 | |||
72 | 72 | ||
73 | /** | 73 | /** |
74 | * enum spe_ex_state - Logical spe execution state. | 74 | * enum spe_ex_state - Logical spe execution state. |
@@ -170,31 +170,6 @@ static int __init construct_spu(struct spu *spu) | |||
170 | return result; | 170 | return result; |
171 | } | 171 | } |
172 | 172 | ||
173 | static int __init add_spu_pages(unsigned long start_addr, unsigned long size) | ||
174 | { | ||
175 | int result; | ||
176 | unsigned long start_pfn; | ||
177 | unsigned long nr_pages; | ||
178 | struct pglist_data *pgdata; | ||
179 | struct zone *zone; | ||
180 | |||
181 | BUG_ON(!mem_init_done); | ||
182 | |||
183 | start_pfn = start_addr >> PAGE_SHIFT; | ||
184 | nr_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; | ||
185 | |||
186 | pgdata = NODE_DATA(0); | ||
187 | zone = pgdata->node_zones; | ||
188 | |||
189 | result = __add_pages(zone, start_pfn, nr_pages); | ||
190 | |||
191 | if (result) | ||
192 | pr_debug("%s:%d: __add_pages failed: (%d)\n", | ||
193 | __func__, __LINE__, result); | ||
194 | |||
195 | return result; | ||
196 | } | ||
197 | |||
198 | static void spu_unmap(struct spu *spu) | 173 | static void spu_unmap(struct spu *spu) |
199 | { | 174 | { |
200 | iounmap(spu->priv2); | 175 | iounmap(spu->priv2); |
@@ -206,19 +181,6 @@ static void spu_unmap(struct spu *spu) | |||
206 | static int __init setup_areas(struct spu *spu) | 181 | static int __init setup_areas(struct spu *spu) |
207 | { | 182 | { |
208 | struct table {char* name; unsigned long addr; unsigned long size;}; | 183 | struct table {char* name; unsigned long addr; unsigned long size;}; |
209 | int result; | ||
210 | |||
211 | /* setup pages */ | ||
212 | |||
213 | result = add_spu_pages(spu->local_store_phys, LS_SIZE); | ||
214 | if (result) | ||
215 | goto fail_add; | ||
216 | |||
217 | result = add_spu_pages(spu->problem_phys, sizeof(struct spu_problem)); | ||
218 | if (result) | ||
219 | goto fail_add; | ||
220 | |||
221 | /* ioremap */ | ||
222 | 184 | ||
223 | spu_pdata(spu)->shadow = __ioremap( | 185 | spu_pdata(spu)->shadow = __ioremap( |
224 | spu_pdata(spu)->shadow_addr, sizeof(struct spe_shadow), | 186 | spu_pdata(spu)->shadow_addr, sizeof(struct spe_shadow), |
@@ -260,28 +222,28 @@ static int __init setup_areas(struct spu *spu) | |||
260 | 222 | ||
261 | fail_ioremap: | 223 | fail_ioremap: |
262 | spu_unmap(spu); | 224 | spu_unmap(spu); |
263 | fail_add: | 225 | |
264 | return result; | 226 | return -ENOMEM; |
265 | } | 227 | } |
266 | 228 | ||
267 | static int __init setup_interrupts(struct spu *spu) | 229 | static int __init setup_interrupts(struct spu *spu) |
268 | { | 230 | { |
269 | int result; | 231 | int result; |
270 | 232 | ||
271 | result = ps3_alloc_spe_irq(spu_pdata(spu)->spe_id, 0, | 233 | result = ps3_alloc_spe_irq(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id, |
272 | &spu->irqs[0]); | 234 | 0, &spu->irqs[0]); |
273 | 235 | ||
274 | if (result) | 236 | if (result) |
275 | goto fail_alloc_0; | 237 | goto fail_alloc_0; |
276 | 238 | ||
277 | result = ps3_alloc_spe_irq(spu_pdata(spu)->spe_id, 1, | 239 | result = ps3_alloc_spe_irq(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id, |
278 | &spu->irqs[1]); | 240 | 1, &spu->irqs[1]); |
279 | 241 | ||
280 | if (result) | 242 | if (result) |
281 | goto fail_alloc_1; | 243 | goto fail_alloc_1; |
282 | 244 | ||
283 | result = ps3_alloc_spe_irq(spu_pdata(spu)->spe_id, 2, | 245 | result = ps3_alloc_spe_irq(PS3_BINDING_CPU_ANY, spu_pdata(spu)->spe_id, |
284 | &spu->irqs[2]); | 246 | 2, &spu->irqs[2]); |
285 | 247 | ||
286 | if (result) | 248 | if (result) |
287 | goto fail_alloc_2; | 249 | goto fail_alloc_2; |
diff --git a/arch/powerpc/platforms/ps3/system-bus.c b/arch/powerpc/platforms/ps3/system-bus.c new file mode 100644 index 000000000000..a9f7e4a39a2a --- /dev/null +++ b/arch/powerpc/platforms/ps3/system-bus.c | |||
@@ -0,0 +1,384 @@ | |||
1 | /* | ||
2 | * PS3 system bus driver. | ||
3 | * | ||
4 | * Copyright (C) 2006 Sony Computer Entertainment Inc. | ||
5 | * Copyright 2006 Sony Corp. | ||
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 as published by | ||
9 | * the Free Software Foundation; version 2 of the License. | ||
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 Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/dma-mapping.h> | ||
25 | #include <linux/err.h> | ||
26 | |||
27 | #include <asm/udbg.h> | ||
28 | #include <asm/lv1call.h> | ||
29 | #include <asm/firmware.h> | ||
30 | |||
31 | #include "platform.h" | ||
32 | |||
33 | #define dump_mmio_region(_a) _dump_mmio_region(_a, __func__, __LINE__) | ||
34 | static void _dump_mmio_region(const struct ps3_mmio_region* r, | ||
35 | const char* func, int line) | ||
36 | { | ||
37 | pr_debug("%s:%d: dev %u:%u\n", func, line, r->did.bus_id, | ||
38 | r->did.dev_id); | ||
39 | pr_debug("%s:%d: bus_addr %lxh\n", func, line, r->bus_addr); | ||
40 | pr_debug("%s:%d: len %lxh\n", func, line, r->len); | ||
41 | pr_debug("%s:%d: lpar_addr %lxh\n", func, line, r->lpar_addr); | ||
42 | } | ||
43 | |||
44 | int ps3_mmio_region_create(struct ps3_mmio_region *r) | ||
45 | { | ||
46 | int result; | ||
47 | |||
48 | result = lv1_map_device_mmio_region(r->did.bus_id, r->did.dev_id, | ||
49 | r->bus_addr, r->len, r->page_size, &r->lpar_addr); | ||
50 | |||
51 | if (result) { | ||
52 | pr_debug("%s:%d: lv1_map_device_mmio_region failed: %s\n", | ||
53 | __func__, __LINE__, ps3_result(result)); | ||
54 | r->lpar_addr = 0; | ||
55 | } | ||
56 | |||
57 | dump_mmio_region(r); | ||
58 | return result; | ||
59 | } | ||
60 | EXPORT_SYMBOL_GPL(ps3_mmio_region_create); | ||
61 | |||
62 | int ps3_free_mmio_region(struct ps3_mmio_region *r) | ||
63 | { | ||
64 | int result; | ||
65 | |||
66 | result = lv1_unmap_device_mmio_region(r->did.bus_id, r->did.dev_id, | ||
67 | r->lpar_addr); | ||
68 | |||
69 | if (result) | ||
70 | pr_debug("%s:%d: lv1_unmap_device_mmio_region failed: %s\n", | ||
71 | __func__, __LINE__, ps3_result(result)); | ||
72 | |||
73 | r->lpar_addr = 0; | ||
74 | return result; | ||
75 | } | ||
76 | EXPORT_SYMBOL_GPL(ps3_free_mmio_region); | ||
77 | |||
78 | static int ps3_system_bus_match(struct device *_dev, | ||
79 | struct device_driver *_drv) | ||
80 | { | ||
81 | int result; | ||
82 | struct ps3_system_bus_driver *drv = to_ps3_system_bus_driver(_drv); | ||
83 | struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); | ||
84 | |||
85 | result = dev->match_id == drv->match_id; | ||
86 | |||
87 | pr_info("%s:%d: dev=%u(%s), drv=%u(%s): %s\n", __func__, __LINE__, | ||
88 | dev->match_id, dev->core.bus_id, drv->match_id, drv->core.name, | ||
89 | (result ? "match" : "miss")); | ||
90 | return result; | ||
91 | } | ||
92 | |||
93 | static int ps3_system_bus_probe(struct device *_dev) | ||
94 | { | ||
95 | int result; | ||
96 | struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); | ||
97 | struct ps3_system_bus_driver *drv = | ||
98 | to_ps3_system_bus_driver(_dev->driver); | ||
99 | |||
100 | result = lv1_open_device(dev->did.bus_id, dev->did.dev_id, 0); | ||
101 | |||
102 | if (result) { | ||
103 | pr_debug("%s:%d: lv1_open_device failed (%d)\n", | ||
104 | __func__, __LINE__, result); | ||
105 | result = -EACCES; | ||
106 | goto clean_none; | ||
107 | } | ||
108 | |||
109 | if (dev->d_region->did.bus_id) { | ||
110 | result = ps3_dma_region_create(dev->d_region); | ||
111 | |||
112 | if (result) { | ||
113 | pr_debug("%s:%d: ps3_dma_region_create failed (%d)\n", | ||
114 | __func__, __LINE__, result); | ||
115 | BUG_ON("check region type"); | ||
116 | result = -EINVAL; | ||
117 | goto clean_device; | ||
118 | } | ||
119 | } | ||
120 | |||
121 | BUG_ON(!drv); | ||
122 | |||
123 | if (drv->probe) | ||
124 | result = drv->probe(dev); | ||
125 | else | ||
126 | pr_info("%s:%d: %s no probe method\n", __func__, __LINE__, | ||
127 | dev->core.bus_id); | ||
128 | |||
129 | if (result) { | ||
130 | pr_debug("%s:%d: drv->probe failed\n", __func__, __LINE__); | ||
131 | goto clean_dma; | ||
132 | } | ||
133 | |||
134 | return result; | ||
135 | |||
136 | clean_dma: | ||
137 | ps3_dma_region_free(dev->d_region); | ||
138 | clean_device: | ||
139 | lv1_close_device(dev->did.bus_id, dev->did.dev_id); | ||
140 | clean_none: | ||
141 | return result; | ||
142 | } | ||
143 | |||
144 | static int ps3_system_bus_remove(struct device *_dev) | ||
145 | { | ||
146 | struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); | ||
147 | struct ps3_system_bus_driver *drv = | ||
148 | to_ps3_system_bus_driver(_dev->driver); | ||
149 | |||
150 | if (drv->remove) | ||
151 | drv->remove(dev); | ||
152 | else | ||
153 | pr_info("%s:%d: %s no remove method\n", __func__, __LINE__, | ||
154 | dev->core.bus_id); | ||
155 | |||
156 | ps3_dma_region_free(dev->d_region); | ||
157 | ps3_free_mmio_region(dev->m_region); | ||
158 | lv1_close_device(dev->did.bus_id, dev->did.dev_id); | ||
159 | |||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | struct bus_type ps3_system_bus_type = { | ||
164 | .name = "ps3_system_bus", | ||
165 | .match = ps3_system_bus_match, | ||
166 | .probe = ps3_system_bus_probe, | ||
167 | .remove = ps3_system_bus_remove, | ||
168 | }; | ||
169 | |||
170 | int __init ps3_system_bus_init(void) | ||
171 | { | ||
172 | int result; | ||
173 | |||
174 | if (!firmware_has_feature(FW_FEATURE_PS3_LV1)) | ||
175 | return 0; | ||
176 | |||
177 | result = bus_register(&ps3_system_bus_type); | ||
178 | BUG_ON(result); | ||
179 | return result; | ||
180 | } | ||
181 | |||
182 | core_initcall(ps3_system_bus_init); | ||
183 | |||
184 | /* Allocates a contiguous real buffer and creates mappings over it. | ||
185 | * Returns the virtual address of the buffer and sets dma_handle | ||
186 | * to the dma address (mapping) of the first page. | ||
187 | */ | ||
188 | |||
189 | static void * ps3_alloc_coherent(struct device *_dev, size_t size, | ||
190 | dma_addr_t *dma_handle, gfp_t flag) | ||
191 | { | ||
192 | int result; | ||
193 | struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); | ||
194 | unsigned long virt_addr; | ||
195 | |||
196 | BUG_ON(!dev->d_region->bus_addr); | ||
197 | |||
198 | flag &= ~(__GFP_DMA | __GFP_HIGHMEM); | ||
199 | flag |= __GFP_ZERO; | ||
200 | |||
201 | virt_addr = __get_free_pages(flag, get_order(size)); | ||
202 | |||
203 | if (!virt_addr) { | ||
204 | pr_debug("%s:%d: get_free_pages failed\n", __func__, __LINE__); | ||
205 | goto clean_none; | ||
206 | } | ||
207 | |||
208 | result = ps3_dma_map(dev->d_region, virt_addr, size, dma_handle); | ||
209 | |||
210 | if (result) { | ||
211 | pr_debug("%s:%d: ps3_dma_map failed (%d)\n", | ||
212 | __func__, __LINE__, result); | ||
213 | BUG_ON("check region type"); | ||
214 | goto clean_alloc; | ||
215 | } | ||
216 | |||
217 | return (void*)virt_addr; | ||
218 | |||
219 | clean_alloc: | ||
220 | free_pages(virt_addr, get_order(size)); | ||
221 | clean_none: | ||
222 | dma_handle = NULL; | ||
223 | return NULL; | ||
224 | } | ||
225 | |||
226 | static void ps3_free_coherent(struct device *_dev, size_t size, void *vaddr, | ||
227 | dma_addr_t dma_handle) | ||
228 | { | ||
229 | struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); | ||
230 | |||
231 | ps3_dma_unmap(dev->d_region, dma_handle, size); | ||
232 | free_pages((unsigned long)vaddr, get_order(size)); | ||
233 | } | ||
234 | |||
235 | /* Creates TCEs for a user provided buffer. The user buffer must be | ||
236 | * contiguous real kernel storage (not vmalloc). The address of the buffer | ||
237 | * passed here is the kernel (virtual) address of the buffer. The buffer | ||
238 | * need not be page aligned, the dma_addr_t returned will point to the same | ||
239 | * byte within the page as vaddr. | ||
240 | */ | ||
241 | |||
242 | static dma_addr_t ps3_map_single(struct device *_dev, void *ptr, size_t size, | ||
243 | enum dma_data_direction direction) | ||
244 | { | ||
245 | struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); | ||
246 | int result; | ||
247 | unsigned long bus_addr; | ||
248 | |||
249 | result = ps3_dma_map(dev->d_region, (unsigned long)ptr, size, | ||
250 | &bus_addr); | ||
251 | |||
252 | if (result) { | ||
253 | pr_debug("%s:%d: ps3_dma_map failed (%d)\n", | ||
254 | __func__, __LINE__, result); | ||
255 | } | ||
256 | |||
257 | return bus_addr; | ||
258 | } | ||
259 | |||
260 | static void ps3_unmap_single(struct device *_dev, dma_addr_t dma_addr, | ||
261 | size_t size, enum dma_data_direction direction) | ||
262 | { | ||
263 | struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); | ||
264 | int result; | ||
265 | |||
266 | result = ps3_dma_unmap(dev->d_region, dma_addr, size); | ||
267 | |||
268 | if (result) { | ||
269 | pr_debug("%s:%d: ps3_dma_unmap failed (%d)\n", | ||
270 | __func__, __LINE__, result); | ||
271 | } | ||
272 | } | ||
273 | |||
274 | static int ps3_map_sg(struct device *_dev, struct scatterlist *sg, int nents, | ||
275 | enum dma_data_direction direction) | ||
276 | { | ||
277 | struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); | ||
278 | int i; | ||
279 | |||
280 | #if defined(CONFIG_PS3_DYNAMIC_DMA) | ||
281 | BUG_ON("do"); | ||
282 | return -EPERM; | ||
283 | #else | ||
284 | for (i = 0; i < nents; i++, sg++) { | ||
285 | int result = ps3_dma_map(dev->d_region, | ||
286 | page_to_phys(sg->page) + sg->offset, sg->length, | ||
287 | &sg->dma_address); | ||
288 | |||
289 | if (result) { | ||
290 | pr_debug("%s:%d: ps3_dma_map failed (%d)\n", | ||
291 | __func__, __LINE__, result); | ||
292 | return -EINVAL; | ||
293 | } | ||
294 | |||
295 | sg->dma_length = sg->length; | ||
296 | } | ||
297 | |||
298 | return nents; | ||
299 | #endif | ||
300 | } | ||
301 | |||
302 | static void ps3_unmap_sg(struct device *_dev, struct scatterlist *sg, | ||
303 | int nents, enum dma_data_direction direction) | ||
304 | { | ||
305 | #if defined(CONFIG_PS3_DYNAMIC_DMA) | ||
306 | BUG_ON("do"); | ||
307 | #endif | ||
308 | } | ||
309 | |||
310 | static int ps3_dma_supported(struct device *_dev, u64 mask) | ||
311 | { | ||
312 | return mask >= DMA_32BIT_MASK; | ||
313 | } | ||
314 | |||
315 | static struct dma_mapping_ops ps3_dma_ops = { | ||
316 | .alloc_coherent = ps3_alloc_coherent, | ||
317 | .free_coherent = ps3_free_coherent, | ||
318 | .map_single = ps3_map_single, | ||
319 | .unmap_single = ps3_unmap_single, | ||
320 | .map_sg = ps3_map_sg, | ||
321 | .unmap_sg = ps3_unmap_sg, | ||
322 | .dma_supported = ps3_dma_supported | ||
323 | }; | ||
324 | |||
325 | /** | ||
326 | * ps3_system_bus_release_device - remove a device from the system bus | ||
327 | */ | ||
328 | |||
329 | static void ps3_system_bus_release_device(struct device *_dev) | ||
330 | { | ||
331 | struct ps3_system_bus_device *dev = to_ps3_system_bus_device(_dev); | ||
332 | kfree(dev); | ||
333 | } | ||
334 | |||
335 | /** | ||
336 | * ps3_system_bus_device_register - add a device to the system bus | ||
337 | * | ||
338 | * ps3_system_bus_device_register() expects the dev object to be allocated | ||
339 | * dynamically by the caller. The system bus takes ownership of the dev | ||
340 | * object and frees the object in ps3_system_bus_release_device(). | ||
341 | */ | ||
342 | |||
343 | int ps3_system_bus_device_register(struct ps3_system_bus_device *dev) | ||
344 | { | ||
345 | int result; | ||
346 | static unsigned int dev_count = 1; | ||
347 | |||
348 | dev->core.parent = NULL; | ||
349 | dev->core.bus = &ps3_system_bus_type; | ||
350 | dev->core.release = ps3_system_bus_release_device; | ||
351 | |||
352 | dev->core.archdata.of_node = NULL; | ||
353 | dev->core.archdata.dma_ops = &ps3_dma_ops; | ||
354 | dev->core.archdata.numa_node = 0; | ||
355 | |||
356 | snprintf(dev->core.bus_id, sizeof(dev->core.bus_id), "sb_%02x", | ||
357 | dev_count++); | ||
358 | |||
359 | pr_debug("%s:%d add %s\n", __func__, __LINE__, dev->core.bus_id); | ||
360 | |||
361 | result = device_register(&dev->core); | ||
362 | return result; | ||
363 | } | ||
364 | |||
365 | EXPORT_SYMBOL_GPL(ps3_system_bus_device_register); | ||
366 | |||
367 | int ps3_system_bus_driver_register(struct ps3_system_bus_driver *drv) | ||
368 | { | ||
369 | int result; | ||
370 | |||
371 | drv->core.bus = &ps3_system_bus_type; | ||
372 | |||
373 | result = driver_register(&drv->core); | ||
374 | return result; | ||
375 | } | ||
376 | |||
377 | EXPORT_SYMBOL_GPL(ps3_system_bus_driver_register); | ||
378 | |||
379 | void ps3_system_bus_driver_unregister(struct ps3_system_bus_driver *drv) | ||
380 | { | ||
381 | driver_unregister(&drv->core); | ||
382 | } | ||
383 | |||
384 | EXPORT_SYMBOL_GPL(ps3_system_bus_driver_unregister); | ||
diff --git a/arch/powerpc/platforms/pseries/Makefile b/arch/powerpc/platforms/pseries/Makefile index 69590fbf83da..2dfd05095a25 100644 --- a/arch/powerpc/platforms/pseries/Makefile +++ b/arch/powerpc/platforms/pseries/Makefile | |||
@@ -4,11 +4,12 @@ endif | |||
4 | 4 | ||
5 | obj-y := pci.o lpar.o hvCall.o nvram.o reconfig.o \ | 5 | obj-y := pci.o lpar.o hvCall.o nvram.o reconfig.o \ |
6 | setup.o iommu.o ras.o rtasd.o pci_dlpar.o \ | 6 | setup.o iommu.o ras.o rtasd.o pci_dlpar.o \ |
7 | firmware.o | 7 | firmware.o power.o |
8 | obj-$(CONFIG_SMP) += smp.o | 8 | obj-$(CONFIG_SMP) += smp.o |
9 | obj-$(CONFIG_XICS) += xics.o | 9 | obj-$(CONFIG_XICS) += xics.o |
10 | obj-$(CONFIG_SCANLOG) += scanlog.o | 10 | obj-$(CONFIG_SCANLOG) += scanlog.o |
11 | obj-$(CONFIG_EEH) += eeh.o eeh_cache.o eeh_driver.o eeh_event.o | 11 | obj-$(CONFIG_EEH) += eeh.o eeh_cache.o eeh_driver.o eeh_event.o |
12 | obj-$(CONFIG_KEXEC) += kexec.o | ||
12 | 13 | ||
13 | obj-$(CONFIG_HOTPLUG_CPU) += hotplug-cpu.o | 14 | obj-$(CONFIG_HOTPLUG_CPU) += hotplug-cpu.o |
14 | 15 | ||
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c index da6e5362e7cd..6cedbc002e0f 100644 --- a/arch/powerpc/platforms/pseries/eeh.c +++ b/arch/powerpc/platforms/pseries/eeh.c | |||
@@ -747,6 +747,7 @@ struct eeh_early_enable_info { | |||
747 | /* Enable eeh for the given device node. */ | 747 | /* Enable eeh for the given device node. */ |
748 | static void *early_enable_eeh(struct device_node *dn, void *data) | 748 | static void *early_enable_eeh(struct device_node *dn, void *data) |
749 | { | 749 | { |
750 | unsigned int rets[3]; | ||
750 | struct eeh_early_enable_info *info = data; | 751 | struct eeh_early_enable_info *info = data; |
751 | int ret; | 752 | int ret; |
752 | const char *status = get_property(dn, "status", NULL); | 753 | const char *status = get_property(dn, "status", NULL); |
@@ -803,16 +804,14 @@ static void *early_enable_eeh(struct device_node *dn, void *data) | |||
803 | regs[0], info->buid_hi, info->buid_lo, | 804 | regs[0], info->buid_hi, info->buid_lo, |
804 | EEH_ENABLE); | 805 | EEH_ENABLE); |
805 | 806 | ||
807 | enable = 0; | ||
806 | if (ret == 0) { | 808 | if (ret == 0) { |
807 | eeh_subsystem_enabled = 1; | ||
808 | pdn->eeh_mode |= EEH_MODE_SUPPORTED; | ||
809 | pdn->eeh_config_addr = regs[0]; | 809 | pdn->eeh_config_addr = regs[0]; |
810 | 810 | ||
811 | /* If the newer, better, ibm,get-config-addr-info is supported, | 811 | /* If the newer, better, ibm,get-config-addr-info is supported, |
812 | * then use that instead. */ | 812 | * then use that instead. */ |
813 | pdn->eeh_pe_config_addr = 0; | 813 | pdn->eeh_pe_config_addr = 0; |
814 | if (ibm_get_config_addr_info != RTAS_UNKNOWN_SERVICE) { | 814 | if (ibm_get_config_addr_info != RTAS_UNKNOWN_SERVICE) { |
815 | unsigned int rets[2]; | ||
816 | ret = rtas_call (ibm_get_config_addr_info, 4, 2, rets, | 815 | ret = rtas_call (ibm_get_config_addr_info, 4, 2, rets, |
817 | pdn->eeh_config_addr, | 816 | pdn->eeh_config_addr, |
818 | info->buid_hi, info->buid_lo, | 817 | info->buid_hi, info->buid_lo, |
@@ -820,6 +819,20 @@ static void *early_enable_eeh(struct device_node *dn, void *data) | |||
820 | if (ret == 0) | 819 | if (ret == 0) |
821 | pdn->eeh_pe_config_addr = rets[0]; | 820 | pdn->eeh_pe_config_addr = rets[0]; |
822 | } | 821 | } |
822 | |||
823 | /* Some older systems (Power4) allow the | ||
824 | * ibm,set-eeh-option call to succeed even on nodes | ||
825 | * where EEH is not supported. Verify support | ||
826 | * explicitly. */ | ||
827 | ret = read_slot_reset_state(pdn, rets); | ||
828 | if ((ret == 0) && (rets[1] == 1)) | ||
829 | enable = 1; | ||
830 | } | ||
831 | |||
832 | if (enable) { | ||
833 | eeh_subsystem_enabled = 1; | ||
834 | pdn->eeh_mode |= EEH_MODE_SUPPORTED; | ||
835 | |||
823 | #ifdef DEBUG | 836 | #ifdef DEBUG |
824 | printk(KERN_DEBUG "EEH: %s: eeh enabled, config=%x pe_config=%x\n", | 837 | printk(KERN_DEBUG "EEH: %s: eeh enabled, config=%x pe_config=%x\n", |
825 | dn->full_name, pdn->eeh_config_addr, pdn->eeh_pe_config_addr); | 838 | dn->full_name, pdn->eeh_config_addr, pdn->eeh_pe_config_addr); |
@@ -1065,7 +1078,7 @@ static int proc_eeh_open(struct inode *inode, struct file *file) | |||
1065 | return single_open(file, proc_eeh_show, NULL); | 1078 | return single_open(file, proc_eeh_show, NULL); |
1066 | } | 1079 | } |
1067 | 1080 | ||
1068 | static struct file_operations proc_eeh_operations = { | 1081 | static const struct file_operations proc_eeh_operations = { |
1069 | .open = proc_eeh_open, | 1082 | .open = proc_eeh_open, |
1070 | .read = seq_read, | 1083 | .read = seq_read, |
1071 | .llseek = seq_lseek, | 1084 | .llseek = seq_lseek, |
diff --git a/arch/powerpc/platforms/pseries/eeh_driver.c b/arch/powerpc/platforms/pseries/eeh_driver.c index cbd6b0711ab4..a4c0bf84ef2e 100644 --- a/arch/powerpc/platforms/pseries/eeh_driver.c +++ b/arch/powerpc/platforms/pseries/eeh_driver.c | |||
@@ -446,7 +446,8 @@ excess_failures: | |||
446 | */ | 446 | */ |
447 | printk(KERN_ERR | 447 | printk(KERN_ERR |
448 | "EEH: PCI device at location=%s driver=%s pci addr=%s \n" | 448 | "EEH: PCI device at location=%s driver=%s pci addr=%s \n" |
449 | "has failed %d times and has been permanently disabled. \n" | 449 | "has failed %d times in the last hour " |
450 | "and has been permanently disabled. \n" | ||
450 | "Please try reseating this device or replacing it.\n", | 451 | "Please try reseating this device or replacing it.\n", |
451 | location, drv_str, pci_str, frozen_pdn->eeh_freeze_count); | 452 | location, drv_str, pci_str, frozen_pdn->eeh_freeze_count); |
452 | goto perm_error; | 453 | goto perm_error; |
diff --git a/arch/powerpc/platforms/pseries/firmware.c b/arch/powerpc/platforms/pseries/firmware.c index 1c7b2baa5f73..90522e3c9d46 100644 --- a/arch/powerpc/platforms/pseries/firmware.c +++ b/arch/powerpc/platforms/pseries/firmware.c | |||
@@ -59,6 +59,7 @@ firmware_features_table[FIRMWARE_MAX_FEATURES] = { | |||
59 | {FW_FEATURE_XDABR, "hcall-xdabr"}, | 59 | {FW_FEATURE_XDABR, "hcall-xdabr"}, |
60 | {FW_FEATURE_MULTITCE, "hcall-multi-tce"}, | 60 | {FW_FEATURE_MULTITCE, "hcall-multi-tce"}, |
61 | {FW_FEATURE_SPLPAR, "hcall-splpar"}, | 61 | {FW_FEATURE_SPLPAR, "hcall-splpar"}, |
62 | {FW_FEATURE_BULK_REMOVE, "hcall-bulk"}, | ||
62 | }; | 63 | }; |
63 | 64 | ||
64 | /* Build up the firmware features bitmask using the contents of | 65 | /* Build up the firmware features bitmask using the contents of |
diff --git a/arch/powerpc/platforms/pseries/firmware.h b/arch/powerpc/platforms/pseries/firmware.h deleted file mode 100644 index 714f56f55362..000000000000 --- a/arch/powerpc/platforms/pseries/firmware.h +++ /dev/null | |||
@@ -1,17 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright 2006 IBM Corporation. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation; either version | ||
7 | * 2 of the License, or (at your option) any later version. | ||
8 | */ | ||
9 | |||
10 | #ifndef _PSERIES_FIRMWARE_H | ||
11 | #define _PSERIES_FIRMWARE_H | ||
12 | |||
13 | #include <asm/firmware.h> | ||
14 | |||
15 | extern void __init fw_feature_init(void); | ||
16 | |||
17 | #endif /* _PSERIES_FIRMWARE_H */ | ||
diff --git a/arch/powerpc/platforms/pseries/hvCall_inst.c b/arch/powerpc/platforms/pseries/hvCall_inst.c index 3ddc04925d50..eae51ef9af24 100644 --- a/arch/powerpc/platforms/pseries/hvCall_inst.c +++ b/arch/powerpc/platforms/pseries/hvCall_inst.c | |||
@@ -90,7 +90,7 @@ static int hcall_inst_seq_open(struct inode *inode, struct file *file) | |||
90 | return rc; | 90 | return rc; |
91 | } | 91 | } |
92 | 92 | ||
93 | static struct file_operations hcall_inst_seq_fops = { | 93 | static const struct file_operations hcall_inst_seq_fops = { |
94 | .open = hcall_inst_seq_open, | 94 | .open = hcall_inst_seq_open, |
95 | .read = seq_read, | 95 | .read = seq_read, |
96 | .llseek = seq_lseek, | 96 | .llseek = seq_lseek, |
diff --git a/arch/powerpc/platforms/pseries/kexec.c b/arch/powerpc/platforms/pseries/kexec.c new file mode 100644 index 000000000000..af2685607458 --- /dev/null +++ b/arch/powerpc/platforms/pseries/kexec.c | |||
@@ -0,0 +1,72 @@ | |||
1 | /* | ||
2 | * Copyright 2006 Michael Ellerman, IBM Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation; either version | ||
7 | * 2 of the License, or (at your option) any later version. | ||
8 | */ | ||
9 | |||
10 | #include <asm/machdep.h> | ||
11 | #include <asm/page.h> | ||
12 | #include <asm/firmware.h> | ||
13 | #include <asm/kexec.h> | ||
14 | #include <asm/mpic.h> | ||
15 | |||
16 | #include "pseries.h" | ||
17 | #include "xics.h" | ||
18 | #include "plpar_wrappers.h" | ||
19 | |||
20 | static void pseries_kexec_cpu_down(int crash_shutdown, int secondary) | ||
21 | { | ||
22 | /* Don't risk a hypervisor call if we're crashing */ | ||
23 | if (firmware_has_feature(FW_FEATURE_SPLPAR) && !crash_shutdown) { | ||
24 | unsigned long addr; | ||
25 | |||
26 | addr = __pa(get_slb_shadow()); | ||
27 | if (unregister_slb_shadow(hard_smp_processor_id(), addr)) | ||
28 | printk("SLB shadow buffer deregistration of " | ||
29 | "cpu %u (hw_cpu_id %d) failed\n", | ||
30 | smp_processor_id(), | ||
31 | hard_smp_processor_id()); | ||
32 | |||
33 | addr = __pa(get_lppaca()); | ||
34 | if (unregister_vpa(hard_smp_processor_id(), addr)) { | ||
35 | printk("VPA deregistration of cpu %u (hw_cpu_id %d) " | ||
36 | "failed\n", smp_processor_id(), | ||
37 | hard_smp_processor_id()); | ||
38 | } | ||
39 | } | ||
40 | } | ||
41 | |||
42 | static void pseries_kexec_cpu_down_mpic(int crash_shutdown, int secondary) | ||
43 | { | ||
44 | pseries_kexec_cpu_down(crash_shutdown, secondary); | ||
45 | mpic_teardown_this_cpu(secondary); | ||
46 | } | ||
47 | |||
48 | void __init setup_kexec_cpu_down_mpic(void) | ||
49 | { | ||
50 | ppc_md.kexec_cpu_down = pseries_kexec_cpu_down_mpic; | ||
51 | } | ||
52 | |||
53 | static void pseries_kexec_cpu_down_xics(int crash_shutdown, int secondary) | ||
54 | { | ||
55 | pseries_kexec_cpu_down(crash_shutdown, secondary); | ||
56 | xics_teardown_cpu(secondary); | ||
57 | } | ||
58 | |||
59 | void __init setup_kexec_cpu_down_xics(void) | ||
60 | { | ||
61 | ppc_md.kexec_cpu_down = pseries_kexec_cpu_down_xics; | ||
62 | } | ||
63 | |||
64 | static int __init pseries_kexec_setup(void) | ||
65 | { | ||
66 | ppc_md.machine_kexec = default_machine_kexec; | ||
67 | ppc_md.machine_kexec_prepare = default_machine_kexec_prepare; | ||
68 | ppc_md.machine_crash_shutdown = default_machine_crash_shutdown; | ||
69 | |||
70 | return 0; | ||
71 | } | ||
72 | __initcall(pseries_kexec_setup); | ||
diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index 721436db3ef0..7496005566ef 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c | |||
@@ -502,23 +502,70 @@ static void pSeries_lpar_hpte_invalidate(unsigned long slot, unsigned long va, | |||
502 | BUG_ON(lpar_rc != H_SUCCESS); | 502 | BUG_ON(lpar_rc != H_SUCCESS); |
503 | } | 503 | } |
504 | 504 | ||
505 | /* Flag bits for H_BULK_REMOVE */ | ||
506 | #define HBR_REQUEST 0x4000000000000000UL | ||
507 | #define HBR_RESPONSE 0x8000000000000000UL | ||
508 | #define HBR_END 0xc000000000000000UL | ||
509 | #define HBR_AVPN 0x0200000000000000UL | ||
510 | #define HBR_ANDCOND 0x0100000000000000UL | ||
511 | |||
505 | /* | 512 | /* |
506 | * Take a spinlock around flushes to avoid bouncing the hypervisor tlbie | 513 | * Take a spinlock around flushes to avoid bouncing the hypervisor tlbie |
507 | * lock. | 514 | * lock. |
508 | */ | 515 | */ |
509 | static void pSeries_lpar_flush_hash_range(unsigned long number, int local) | 516 | static void pSeries_lpar_flush_hash_range(unsigned long number, int local) |
510 | { | 517 | { |
511 | int i; | 518 | unsigned long i, pix, rc; |
512 | unsigned long flags = 0; | 519 | unsigned long flags = 0; |
513 | struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch); | 520 | struct ppc64_tlb_batch *batch = &__get_cpu_var(ppc64_tlb_batch); |
514 | int lock_tlbie = !cpu_has_feature(CPU_FTR_LOCKLESS_TLBIE); | 521 | int lock_tlbie = !cpu_has_feature(CPU_FTR_LOCKLESS_TLBIE); |
522 | unsigned long param[9]; | ||
523 | unsigned long va; | ||
524 | unsigned long hash, index, shift, hidx, slot; | ||
525 | real_pte_t pte; | ||
526 | int psize; | ||
515 | 527 | ||
516 | if (lock_tlbie) | 528 | if (lock_tlbie) |
517 | spin_lock_irqsave(&pSeries_lpar_tlbie_lock, flags); | 529 | spin_lock_irqsave(&pSeries_lpar_tlbie_lock, flags); |
518 | 530 | ||
519 | for (i = 0; i < number; i++) | 531 | psize = batch->psize; |
520 | flush_hash_page(batch->vaddr[i], batch->pte[i], | 532 | pix = 0; |
521 | batch->psize, local); | 533 | for (i = 0; i < number; i++) { |
534 | va = batch->vaddr[i]; | ||
535 | pte = batch->pte[i]; | ||
536 | pte_iterate_hashed_subpages(pte, psize, va, index, shift) { | ||
537 | hash = hpt_hash(va, shift); | ||
538 | hidx = __rpte_to_hidx(pte, index); | ||
539 | if (hidx & _PTEIDX_SECONDARY) | ||
540 | hash = ~hash; | ||
541 | slot = (hash & htab_hash_mask) * HPTES_PER_GROUP; | ||
542 | slot += hidx & _PTEIDX_GROUP_IX; | ||
543 | if (!firmware_has_feature(FW_FEATURE_BULK_REMOVE)) { | ||
544 | pSeries_lpar_hpte_invalidate(slot, va, psize, | ||
545 | local); | ||
546 | } else { | ||
547 | param[pix] = HBR_REQUEST | HBR_AVPN | slot; | ||
548 | param[pix+1] = hpte_encode_v(va, psize) & | ||
549 | HPTE_V_AVPN; | ||
550 | pix += 2; | ||
551 | if (pix == 8) { | ||
552 | rc = plpar_hcall9(H_BULK_REMOVE, param, | ||
553 | param[0], param[1], param[2], | ||
554 | param[3], param[4], param[5], | ||
555 | param[6], param[7]); | ||
556 | BUG_ON(rc != H_SUCCESS); | ||
557 | pix = 0; | ||
558 | } | ||
559 | } | ||
560 | } pte_iterate_hashed_end(); | ||
561 | } | ||
562 | if (pix) { | ||
563 | param[pix] = HBR_END; | ||
564 | rc = plpar_hcall9(H_BULK_REMOVE, param, param[0], param[1], | ||
565 | param[2], param[3], param[4], param[5], | ||
566 | param[6], param[7]); | ||
567 | BUG_ON(rc != H_SUCCESS); | ||
568 | } | ||
522 | 569 | ||
523 | if (lock_tlbie) | 570 | if (lock_tlbie) |
524 | spin_unlock_irqrestore(&pSeries_lpar_tlbie_lock, flags); | 571 | spin_unlock_irqrestore(&pSeries_lpar_tlbie_lock, flags); |
diff --git a/arch/powerpc/platforms/pseries/pci.c b/arch/powerpc/platforms/pseries/pci.c index 715db5c89908..fa59124ce3fe 100644 --- a/arch/powerpc/platforms/pseries/pci.c +++ b/arch/powerpc/platforms/pseries/pci.c | |||
@@ -77,7 +77,7 @@ void __init pSeries_final_fixup(void) | |||
77 | 77 | ||
78 | /* | 78 | /* |
79 | * Assume the winbond 82c105 is the IDE controller on a | 79 | * Assume the winbond 82c105 is the IDE controller on a |
80 | * p610. We should probably be more careful in case | 80 | * p610/p615/p630. We should probably be more careful in case |
81 | * someone tries to plug in a similar adapter. | 81 | * someone tries to plug in a similar adapter. |
82 | */ | 82 | */ |
83 | static void fixup_winbond_82c105(struct pci_dev* dev) | 83 | static void fixup_winbond_82c105(struct pci_dev* dev) |
@@ -98,6 +98,10 @@ static void fixup_winbond_82c105(struct pci_dev* dev) | |||
98 | if (dev->resource[i].flags & IORESOURCE_IO | 98 | if (dev->resource[i].flags & IORESOURCE_IO |
99 | && dev->bus->number == 0 && dev->devfn == 0x81) | 99 | && dev->bus->number == 0 && dev->devfn == 0x81) |
100 | dev->resource[i].flags &= ~IORESOURCE_IO; | 100 | dev->resource[i].flags &= ~IORESOURCE_IO; |
101 | if (dev->resource[i].start == 0 && dev->resource[i].end) { | ||
102 | dev->resource[i].flags = 0; | ||
103 | dev->resource[i].end = 0; | ||
104 | } | ||
101 | } | 105 | } |
102 | } | 106 | } |
103 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, | 107 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105, |
diff --git a/arch/powerpc/platforms/pseries/power.c b/arch/powerpc/platforms/pseries/power.c new file mode 100644 index 000000000000..2624b71df73d --- /dev/null +++ b/arch/powerpc/platforms/pseries/power.c | |||
@@ -0,0 +1,87 @@ | |||
1 | /* | ||
2 | * Interface for power-management for ppc64 compliant platform | ||
3 | * | ||
4 | * Manish Ahuja <mahuja@us.ibm.com> | ||
5 | * | ||
6 | * Feb 2007 | ||
7 | * | ||
8 | * Copyright (C) 2007 IBM Corporation. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; version 2 of the License. | ||
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | */ | ||
23 | |||
24 | #include <linux/kobject.h> | ||
25 | #include <linux/string.h> | ||
26 | #include <linux/errno.h> | ||
27 | #include <linux/init.h> | ||
28 | |||
29 | unsigned long rtas_poweron_auto; /* default and normal state is 0 */ | ||
30 | |||
31 | static ssize_t auto_poweron_show(struct subsystem *subsys, char *buf) | ||
32 | { | ||
33 | return sprintf(buf, "%lu\n", rtas_poweron_auto); | ||
34 | } | ||
35 | |||
36 | static ssize_t | ||
37 | auto_poweron_store(struct subsystem *subsys, const char *buf, size_t n) | ||
38 | { | ||
39 | int ret; | ||
40 | unsigned long ups_restart; | ||
41 | ret = sscanf(buf, "%lu", &ups_restart); | ||
42 | |||
43 | if ((ret == 1) && ((ups_restart == 1) || (ups_restart == 0))){ | ||
44 | rtas_poweron_auto = ups_restart; | ||
45 | return n; | ||
46 | } | ||
47 | return -EINVAL; | ||
48 | } | ||
49 | |||
50 | static struct subsys_attribute auto_poweron_attr = { | ||
51 | .attr = { | ||
52 | .name = __stringify(auto_poweron), | ||
53 | .mode = 0644, | ||
54 | }, | ||
55 | .show = auto_poweron_show, | ||
56 | .store = auto_poweron_store, | ||
57 | }; | ||
58 | |||
59 | #ifndef CONFIG_PM | ||
60 | decl_subsys(power,NULL,NULL); | ||
61 | |||
62 | static struct attribute *g[] = { | ||
63 | &auto_poweron_attr.attr, | ||
64 | NULL, | ||
65 | }; | ||
66 | |||
67 | static struct attribute_group attr_group = { | ||
68 | .attrs = g, | ||
69 | }; | ||
70 | |||
71 | static int __init pm_init(void) | ||
72 | { | ||
73 | int error = subsystem_register(&power_subsys); | ||
74 | if (!error) | ||
75 | error = sysfs_create_group(&power_subsys.kset.kobj,&attr_group); | ||
76 | return error; | ||
77 | } | ||
78 | core_initcall(pm_init); | ||
79 | #else | ||
80 | extern struct subsystem power_subsys; | ||
81 | |||
82 | static int __init apo_pm_init(void) | ||
83 | { | ||
84 | return (subsys_create_file(&power_subsys, &auto_poweron_attr)); | ||
85 | } | ||
86 | __initcall(apo_pm_init); | ||
87 | #endif | ||
diff --git a/arch/powerpc/platforms/pseries/pseries.h b/arch/powerpc/platforms/pseries/pseries.h new file mode 100644 index 000000000000..22bc01989749 --- /dev/null +++ b/arch/powerpc/platforms/pseries/pseries.h | |||
@@ -0,0 +1,39 @@ | |||
1 | /* | ||
2 | * Copyright 2006 IBM Corporation. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation; either version | ||
7 | * 2 of the License, or (at your option) any later version. | ||
8 | */ | ||
9 | |||
10 | #ifndef _PSERIES_PSERIES_H | ||
11 | #define _PSERIES_PSERIES_H | ||
12 | |||
13 | extern void __init fw_feature_init(void); | ||
14 | |||
15 | struct pt_regs; | ||
16 | |||
17 | extern int pSeries_system_reset_exception(struct pt_regs *regs); | ||
18 | extern int pSeries_machine_check_exception(struct pt_regs *regs); | ||
19 | |||
20 | #ifdef CONFIG_SMP | ||
21 | extern void smp_init_pseries_mpic(void); | ||
22 | extern void smp_init_pseries_xics(void); | ||
23 | #else | ||
24 | static inline smp_init_pseries_mpic(void) { }; | ||
25 | static inline smp_init_pseries_xics(void) { }; | ||
26 | #endif | ||
27 | |||
28 | #ifdef CONFIG_KEXEC | ||
29 | extern void setup_kexec_cpu_down_xics(void); | ||
30 | extern void setup_kexec_cpu_down_mpic(void); | ||
31 | #else | ||
32 | static inline void setup_kexec_cpu_down_xics(void) { } | ||
33 | static inline void setup_kexec_cpu_down_mpic(void) { } | ||
34 | #endif | ||
35 | |||
36 | /* Poweron flag used for enabling auto ups restart */ | ||
37 | extern unsigned long rtas_poweron_auto; | ||
38 | |||
39 | #endif /* _PSERIES_PSERIES_H */ | ||
diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c index b1d3d161249e..edc038873113 100644 --- a/arch/powerpc/platforms/pseries/ras.c +++ b/arch/powerpc/platforms/pseries/ras.c | |||
@@ -51,7 +51,7 @@ | |||
51 | #include <asm/udbg.h> | 51 | #include <asm/udbg.h> |
52 | #include <asm/firmware.h> | 52 | #include <asm/firmware.h> |
53 | 53 | ||
54 | #include "ras.h" | 54 | #include "pseries.h" |
55 | 55 | ||
56 | static unsigned char ras_log_buf[RTAS_ERROR_LOG_MAX]; | 56 | static unsigned char ras_log_buf[RTAS_ERROR_LOG_MAX]; |
57 | static DEFINE_SPINLOCK(ras_log_buf_lock); | 57 | static DEFINE_SPINLOCK(ras_log_buf_lock); |
diff --git a/arch/powerpc/platforms/pseries/ras.h b/arch/powerpc/platforms/pseries/ras.h deleted file mode 100644 index 0e66b0da55e2..000000000000 --- a/arch/powerpc/platforms/pseries/ras.h +++ /dev/null | |||
@@ -1,9 +0,0 @@ | |||
1 | #ifndef _PSERIES_RAS_H | ||
2 | #define _PSERIES_RAS_H | ||
3 | |||
4 | struct pt_regs; | ||
5 | |||
6 | extern int pSeries_system_reset_exception(struct pt_regs *regs); | ||
7 | extern int pSeries_machine_check_exception(struct pt_regs *regs); | ||
8 | |||
9 | #endif /* _PSERIES_RAS_H */ | ||
diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c index 4ad33e41b008..5aa97aff3391 100644 --- a/arch/powerpc/platforms/pseries/reconfig.c +++ b/arch/powerpc/platforms/pseries/reconfig.c | |||
@@ -499,7 +499,7 @@ out: | |||
499 | return rv ? rv : count; | 499 | return rv ? rv : count; |
500 | } | 500 | } |
501 | 501 | ||
502 | static struct file_operations ofdt_fops = { | 502 | static const struct file_operations ofdt_fops = { |
503 | .write = ofdt_write | 503 | .write = ofdt_write |
504 | }; | 504 | }; |
505 | 505 | ||
@@ -513,7 +513,6 @@ static int proc_ppc64_create_ofdt(void) | |||
513 | 513 | ||
514 | ent = create_proc_entry("ppc64/ofdt", S_IWUSR, NULL); | 514 | ent = create_proc_entry("ppc64/ofdt", S_IWUSR, NULL); |
515 | if (ent) { | 515 | if (ent) { |
516 | ent->nlink = 1; | ||
517 | ent->data = NULL; | 516 | ent->data = NULL; |
518 | ent->size = 0; | 517 | ent->size = 0; |
519 | ent->proc_fops = &ofdt_fops; | 518 | ent->proc_fops = &ofdt_fops; |
diff --git a/arch/powerpc/platforms/pseries/rtasd.c b/arch/powerpc/platforms/pseries/rtasd.c index 8ca2612221d6..77d0937d5c07 100644 --- a/arch/powerpc/platforms/pseries/rtasd.c +++ b/arch/powerpc/platforms/pseries/rtasd.c | |||
@@ -331,7 +331,7 @@ static unsigned int rtas_log_poll(struct file *file, poll_table * wait) | |||
331 | return 0; | 331 | return 0; |
332 | } | 332 | } |
333 | 333 | ||
334 | struct file_operations proc_rtas_log_operations = { | 334 | const struct file_operations proc_rtas_log_operations = { |
335 | .read = rtas_log_read, | 335 | .read = rtas_log_read, |
336 | .poll = rtas_log_poll, | 336 | .poll = rtas_log_poll, |
337 | .open = rtas_log_open, | 337 | .open = rtas_log_open, |
diff --git a/arch/powerpc/platforms/pseries/scanlog.c b/arch/powerpc/platforms/pseries/scanlog.c index 45368a57d7dd..8e1ef168e2dd 100644 --- a/arch/powerpc/platforms/pseries/scanlog.c +++ b/arch/powerpc/platforms/pseries/scanlog.c | |||
@@ -184,7 +184,7 @@ static int scanlog_release(struct inode * inode, struct file * file) | |||
184 | return 0; | 184 | return 0; |
185 | } | 185 | } |
186 | 186 | ||
187 | struct file_operations scanlog_fops = { | 187 | const struct file_operations scanlog_fops = { |
188 | .owner = THIS_MODULE, | 188 | .owner = THIS_MODULE, |
189 | .read = scanlog_read, | 189 | .read = scanlog_read, |
190 | .write = scanlog_write, | 190 | .write = scanlog_write, |
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index 042ecae107ac..34aff47b1f55 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c | |||
@@ -55,7 +55,6 @@ | |||
55 | #include <asm/dma.h> | 55 | #include <asm/dma.h> |
56 | #include <asm/machdep.h> | 56 | #include <asm/machdep.h> |
57 | #include <asm/irq.h> | 57 | #include <asm/irq.h> |
58 | #include <asm/kexec.h> | ||
59 | #include <asm/time.h> | 58 | #include <asm/time.h> |
60 | #include <asm/nvram.h> | 59 | #include <asm/nvram.h> |
61 | #include "xics.h" | 60 | #include "xics.h" |
@@ -65,10 +64,10 @@ | |||
65 | #include <asm/i8259.h> | 64 | #include <asm/i8259.h> |
66 | #include <asm/udbg.h> | 65 | #include <asm/udbg.h> |
67 | #include <asm/smp.h> | 66 | #include <asm/smp.h> |
67 | #include <asm/firmware.h> | ||
68 | 68 | ||
69 | #include "plpar_wrappers.h" | 69 | #include "plpar_wrappers.h" |
70 | #include "ras.h" | 70 | #include "pseries.h" |
71 | #include "firmware.h" | ||
72 | 71 | ||
73 | #ifdef DEBUG | 72 | #ifdef DEBUG |
74 | #define DBG(fmt...) udbg_printf(fmt) | 73 | #define DBG(fmt...) udbg_printf(fmt) |
@@ -77,8 +76,6 @@ | |||
77 | #endif | 76 | #endif |
78 | 77 | ||
79 | /* move those away to a .h */ | 78 | /* move those away to a .h */ |
80 | extern void smp_init_pseries_mpic(void); | ||
81 | extern void smp_init_pseries_xics(void); | ||
82 | extern void find_udbg_vterm(void); | 79 | extern void find_udbg_vterm(void); |
83 | 80 | ||
84 | int fwnmi_active; /* TRUE if an FWNMI handler is present */ | 81 | int fwnmi_active; /* TRUE if an FWNMI handler is present */ |
@@ -221,42 +218,6 @@ static void pseries_lpar_enable_pmcs(void) | |||
221 | get_lppaca()->pmcregs_in_use = 1; | 218 | get_lppaca()->pmcregs_in_use = 1; |
222 | } | 219 | } |
223 | 220 | ||
224 | #ifdef CONFIG_KEXEC | ||
225 | static void pseries_kexec_cpu_down(int crash_shutdown, int secondary) | ||
226 | { | ||
227 | /* Don't risk a hypervisor call if we're crashing */ | ||
228 | if (firmware_has_feature(FW_FEATURE_SPLPAR) && !crash_shutdown) { | ||
229 | unsigned long addr; | ||
230 | |||
231 | addr = __pa(get_slb_shadow()); | ||
232 | if (unregister_slb_shadow(hard_smp_processor_id(), addr)) | ||
233 | printk("SLB shadow buffer deregistration of " | ||
234 | "cpu %u (hw_cpu_id %d) failed\n", | ||
235 | smp_processor_id(), | ||
236 | hard_smp_processor_id()); | ||
237 | |||
238 | addr = __pa(get_lppaca()); | ||
239 | if (unregister_vpa(hard_smp_processor_id(), addr)) { | ||
240 | printk("VPA deregistration of cpu %u (hw_cpu_id %d) " | ||
241 | "failed\n", smp_processor_id(), | ||
242 | hard_smp_processor_id()); | ||
243 | } | ||
244 | } | ||
245 | } | ||
246 | |||
247 | static void pseries_kexec_cpu_down_mpic(int crash_shutdown, int secondary) | ||
248 | { | ||
249 | pseries_kexec_cpu_down(crash_shutdown, secondary); | ||
250 | mpic_teardown_this_cpu(secondary); | ||
251 | } | ||
252 | |||
253 | static void pseries_kexec_cpu_down_xics(int crash_shutdown, int secondary) | ||
254 | { | ||
255 | pseries_kexec_cpu_down(crash_shutdown, secondary); | ||
256 | xics_teardown_cpu(secondary); | ||
257 | } | ||
258 | #endif /* CONFIG_KEXEC */ | ||
259 | |||
260 | static void __init pseries_discover_pic(void) | 221 | static void __init pseries_discover_pic(void) |
261 | { | 222 | { |
262 | struct device_node *np; | 223 | struct device_node *np; |
@@ -269,21 +230,13 @@ static void __init pseries_discover_pic(void) | |||
269 | pSeries_mpic_node = of_node_get(np); | 230 | pSeries_mpic_node = of_node_get(np); |
270 | ppc_md.init_IRQ = pseries_mpic_init_IRQ; | 231 | ppc_md.init_IRQ = pseries_mpic_init_IRQ; |
271 | ppc_md.get_irq = mpic_get_irq; | 232 | ppc_md.get_irq = mpic_get_irq; |
272 | #ifdef CONFIG_KEXEC | 233 | setup_kexec_cpu_down_mpic(); |
273 | ppc_md.kexec_cpu_down = pseries_kexec_cpu_down_mpic; | ||
274 | #endif | ||
275 | #ifdef CONFIG_SMP | ||
276 | smp_init_pseries_mpic(); | 234 | smp_init_pseries_mpic(); |
277 | #endif | ||
278 | return; | 235 | return; |
279 | } else if (strstr(typep, "ppc-xicp")) { | 236 | } else if (strstr(typep, "ppc-xicp")) { |
280 | ppc_md.init_IRQ = xics_init_IRQ; | 237 | ppc_md.init_IRQ = xics_init_IRQ; |
281 | #ifdef CONFIG_KEXEC | 238 | setup_kexec_cpu_down_xics(); |
282 | ppc_md.kexec_cpu_down = pseries_kexec_cpu_down_xics; | ||
283 | #endif | ||
284 | #ifdef CONFIG_SMP | ||
285 | smp_init_pseries_xics(); | 239 | smp_init_pseries_xics(); |
286 | #endif | ||
287 | return; | 240 | return; |
288 | } | 241 | } |
289 | } | 242 | } |
@@ -533,6 +486,34 @@ static int pSeries_pci_probe_mode(struct pci_bus *bus) | |||
533 | return PCI_PROBE_NORMAL; | 486 | return PCI_PROBE_NORMAL; |
534 | } | 487 | } |
535 | 488 | ||
489 | /** | ||
490 | * pSeries_power_off - tell firmware about how to power off the system. | ||
491 | * | ||
492 | * This function calls either the power-off rtas token in normal cases | ||
493 | * or the ibm,power-off-ups token (if present & requested) in case of | ||
494 | * a power failure. If power-off token is used, power on will only be | ||
495 | * possible with power button press. If ibm,power-off-ups token is used | ||
496 | * it will allow auto poweron after power is restored. | ||
497 | */ | ||
498 | void pSeries_power_off(void) | ||
499 | { | ||
500 | int rc; | ||
501 | int rtas_poweroff_ups_token = rtas_token("ibm,power-off-ups"); | ||
502 | |||
503 | if (rtas_flash_term_hook) | ||
504 | rtas_flash_term_hook(SYS_POWER_OFF); | ||
505 | |||
506 | if (rtas_poweron_auto == 0 || | ||
507 | rtas_poweroff_ups_token == RTAS_UNKNOWN_SERVICE) { | ||
508 | rc = rtas_call(rtas_token("power-off"), 2, 1, NULL, -1, -1); | ||
509 | printk(KERN_INFO "RTAS power-off returned %d\n", rc); | ||
510 | } else { | ||
511 | rc = rtas_call(rtas_poweroff_ups_token, 0, 1, NULL); | ||
512 | printk(KERN_INFO "RTAS ibm,power-off-ups returned %d\n", rc); | ||
513 | } | ||
514 | for (;;); | ||
515 | } | ||
516 | |||
536 | define_machine(pseries) { | 517 | define_machine(pseries) { |
537 | .name = "pSeries", | 518 | .name = "pSeries", |
538 | .probe = pSeries_probe, | 519 | .probe = pSeries_probe, |
@@ -543,7 +524,7 @@ define_machine(pseries) { | |||
543 | .pcibios_fixup = pSeries_final_fixup, | 524 | .pcibios_fixup = pSeries_final_fixup, |
544 | .pci_probe_mode = pSeries_pci_probe_mode, | 525 | .pci_probe_mode = pSeries_pci_probe_mode, |
545 | .restart = rtas_restart, | 526 | .restart = rtas_restart, |
546 | .power_off = rtas_power_off, | 527 | .power_off = pSeries_power_off, |
547 | .halt = rtas_halt, | 528 | .halt = rtas_halt, |
548 | .panic = rtas_os_term, | 529 | .panic = rtas_os_term, |
549 | .get_boot_time = rtas_get_boot_time, | 530 | .get_boot_time = rtas_get_boot_time, |
@@ -554,9 +535,4 @@ define_machine(pseries) { | |||
554 | .check_legacy_ioport = pSeries_check_legacy_ioport, | 535 | .check_legacy_ioport = pSeries_check_legacy_ioport, |
555 | .system_reset_exception = pSeries_system_reset_exception, | 536 | .system_reset_exception = pSeries_system_reset_exception, |
556 | .machine_check_exception = pSeries_machine_check_exception, | 537 | .machine_check_exception = pSeries_machine_check_exception, |
557 | #ifdef CONFIG_KEXEC | ||
558 | .machine_kexec = default_machine_kexec, | ||
559 | .machine_kexec_prepare = default_machine_kexec_prepare, | ||
560 | .machine_crash_shutdown = default_machine_crash_shutdown, | ||
561 | #endif | ||
562 | }; | 538 | }; |
diff --git a/arch/powerpc/platforms/pseries/smp.c b/arch/powerpc/platforms/pseries/smp.c index 4408518eaebe..116305b22a2b 100644 --- a/arch/powerpc/platforms/pseries/smp.c +++ b/arch/powerpc/platforms/pseries/smp.c | |||
@@ -48,6 +48,7 @@ | |||
48 | #include <asm/vdso_datapage.h> | 48 | #include <asm/vdso_datapage.h> |
49 | 49 | ||
50 | #include "plpar_wrappers.h" | 50 | #include "plpar_wrappers.h" |
51 | #include "pseries.h" | ||
51 | 52 | ||
52 | #ifdef DEBUG | 53 | #ifdef DEBUG |
53 | #include <asm/udbg.h> | 54 | #include <asm/udbg.h> |