diff options
Diffstat (limited to 'arch/sparc/kernel')
30 files changed, 982 insertions, 1803 deletions
diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile index 6e03a2a7863c..2d6582095099 100644 --- a/arch/sparc/kernel/Makefile +++ b/arch/sparc/kernel/Makefile | |||
@@ -13,15 +13,13 @@ obj-y := entry.o wof.o wuf.o etrap.o rtrap.o traps.o $(IRQ_OBJS) \ | |||
13 | time.o windows.o cpu.o devices.o \ | 13 | time.o windows.o cpu.o devices.o \ |
14 | tadpole.o tick14.o ptrace.o \ | 14 | tadpole.o tick14.o ptrace.o \ |
15 | unaligned.o una_asm.o muldiv.o \ | 15 | unaligned.o una_asm.o muldiv.o \ |
16 | prom.o of_device.o devres.o | 16 | prom.o of_device.o devres.o dma.o |
17 | 17 | ||
18 | devres-y = ../../../kernel/irq/devres.o | 18 | devres-y = ../../../kernel/irq/devres.o |
19 | 19 | ||
20 | obj-$(CONFIG_PCI) += pcic.o | 20 | obj-$(CONFIG_PCI) += pcic.o |
21 | obj-$(CONFIG_SUN4) += sun4setup.o | ||
22 | obj-$(CONFIG_SMP) += trampoline.o smp.o sun4m_smp.o sun4d_smp.o | 21 | obj-$(CONFIG_SMP) += trampoline.o smp.o sun4m_smp.o sun4d_smp.o |
23 | obj-$(CONFIG_SUN_AUXIO) += auxio.o | 22 | obj-$(CONFIG_SUN_AUXIO) += auxio.o |
24 | obj-$(CONFIG_PCI) += ebus.o | ||
25 | obj-$(CONFIG_SUN_PM) += apc.o pmc.o | 23 | obj-$(CONFIG_SUN_PM) += apc.o pmc.o |
26 | obj-$(CONFIG_MODULES) += module.o sparc_ksyms.o | 24 | obj-$(CONFIG_MODULES) += module.o sparc_ksyms.o |
27 | obj-$(CONFIG_SPARC_LED) += led.o | 25 | obj-$(CONFIG_SPARC_LED) += led.o |
diff --git a/arch/sparc/kernel/apc.c b/arch/sparc/kernel/apc.c index 5267d48fb2c6..4dd1ba752ce6 100644 --- a/arch/sparc/kernel/apc.c +++ b/arch/sparc/kernel/apc.c | |||
@@ -12,9 +12,10 @@ | |||
12 | #include <linux/miscdevice.h> | 12 | #include <linux/miscdevice.h> |
13 | #include <linux/smp_lock.h> | 13 | #include <linux/smp_lock.h> |
14 | #include <linux/pm.h> | 14 | #include <linux/pm.h> |
15 | #include <linux/of.h> | ||
16 | #include <linux/of_device.h> | ||
15 | 17 | ||
16 | #include <asm/io.h> | 18 | #include <asm/io.h> |
17 | #include <asm/sbus.h> | ||
18 | #include <asm/oplib.h> | 19 | #include <asm/oplib.h> |
19 | #include <asm/uaccess.h> | 20 | #include <asm/uaccess.h> |
20 | #include <asm/auxio.h> | 21 | #include <asm/auxio.h> |
@@ -29,11 +30,10 @@ | |||
29 | #define APC_OBPNAME "power-management" | 30 | #define APC_OBPNAME "power-management" |
30 | #define APC_DEVNAME "apc" | 31 | #define APC_DEVNAME "apc" |
31 | 32 | ||
32 | volatile static u8 __iomem *regs; | 33 | static u8 __iomem *regs; |
33 | static int apc_regsize; | ||
34 | static int apc_no_idle __initdata = 0; | 34 | static int apc_no_idle __initdata = 0; |
35 | 35 | ||
36 | #define apc_readb(offs) (sbus_readb(regs+offs)) | 36 | #define apc_readb(offs) (sbus_readb(regs+offs)) |
37 | #define apc_writeb(val, offs) (sbus_writeb(val, regs+offs)) | 37 | #define apc_writeb(val, offs) (sbus_writeb(val, regs+offs)) |
38 | 38 | ||
39 | /* Specify "apc=noidle" on the kernel command line to | 39 | /* Specify "apc=noidle" on the kernel command line to |
@@ -69,9 +69,9 @@ static void apc_swift_idle(void) | |||
69 | #endif | 69 | #endif |
70 | } | 70 | } |
71 | 71 | ||
72 | static inline void apc_free(void) | 72 | static inline void apc_free(struct of_device *op) |
73 | { | 73 | { |
74 | sbus_iounmap(regs, apc_regsize); | 74 | of_iounmap(&op->resource[0], regs, resource_size(&op->resource[0])); |
75 | } | 75 | } |
76 | 76 | ||
77 | static int apc_open(struct inode *inode, struct file *f) | 77 | static int apc_open(struct inode *inode, struct file *f) |
@@ -153,52 +153,56 @@ static const struct file_operations apc_fops = { | |||
153 | 153 | ||
154 | static struct miscdevice apc_miscdev = { APC_MINOR, APC_DEVNAME, &apc_fops }; | 154 | static struct miscdevice apc_miscdev = { APC_MINOR, APC_DEVNAME, &apc_fops }; |
155 | 155 | ||
156 | static int __init apc_probe(void) | 156 | static int __devinit apc_probe(struct of_device *op, |
157 | const struct of_device_id *match) | ||
157 | { | 158 | { |
158 | struct sbus_bus *sbus = NULL; | 159 | int err; |
159 | struct sbus_dev *sdev = NULL; | ||
160 | int iTmp = 0; | ||
161 | |||
162 | for_each_sbus(sbus) { | ||
163 | for_each_sbusdev(sdev, sbus) { | ||
164 | if (!strcmp(sdev->prom_name, APC_OBPNAME)) { | ||
165 | goto sbus_done; | ||
166 | } | ||
167 | } | ||
168 | } | ||
169 | 160 | ||
170 | sbus_done: | 161 | regs = of_ioremap(&op->resource[0], 0, |
171 | if (!sdev) { | 162 | resource_size(&op->resource[0]), APC_OBPNAME); |
172 | return -ENODEV; | 163 | if (!regs) { |
173 | } | ||
174 | |||
175 | apc_regsize = sdev->reg_addrs[0].reg_size; | ||
176 | regs = sbus_ioremap(&sdev->resource[0], 0, | ||
177 | apc_regsize, APC_OBPNAME); | ||
178 | if(!regs) { | ||
179 | printk(KERN_ERR "%s: unable to map registers\n", APC_DEVNAME); | 164 | printk(KERN_ERR "%s: unable to map registers\n", APC_DEVNAME); |
180 | return -ENODEV; | 165 | return -ENODEV; |
181 | } | 166 | } |
182 | 167 | ||
183 | iTmp = misc_register(&apc_miscdev); | 168 | err = misc_register(&apc_miscdev); |
184 | if (iTmp != 0) { | 169 | if (err) { |
185 | printk(KERN_ERR "%s: unable to register device\n", APC_DEVNAME); | 170 | printk(KERN_ERR "%s: unable to register device\n", APC_DEVNAME); |
186 | apc_free(); | 171 | apc_free(op); |
187 | return -ENODEV; | 172 | return -ENODEV; |
188 | } | 173 | } |
189 | 174 | ||
190 | /* Assign power management IDLE handler */ | 175 | /* Assign power management IDLE handler */ |
191 | if(!apc_no_idle) | 176 | if (!apc_no_idle) |
192 | pm_idle = apc_swift_idle; | 177 | pm_idle = apc_swift_idle; |
193 | 178 | ||
194 | printk(KERN_INFO "%s: power management initialized%s\n", | 179 | printk(KERN_INFO "%s: power management initialized%s\n", |
195 | APC_DEVNAME, apc_no_idle ? " (CPU idle disabled)" : ""); | 180 | APC_DEVNAME, apc_no_idle ? " (CPU idle disabled)" : ""); |
181 | |||
196 | return 0; | 182 | return 0; |
197 | } | 183 | } |
198 | 184 | ||
185 | static struct of_device_id __initdata apc_match[] = { | ||
186 | { | ||
187 | .name = APC_OBPNAME, | ||
188 | }, | ||
189 | {}, | ||
190 | }; | ||
191 | MODULE_DEVICE_TABLE(of, apc_match); | ||
192 | |||
193 | static struct of_platform_driver apc_driver = { | ||
194 | .name = "apc", | ||
195 | .match_table = apc_match, | ||
196 | .probe = apc_probe, | ||
197 | }; | ||
198 | |||
199 | static int __init apc_init(void) | ||
200 | { | ||
201 | return of_register_driver(&apc_driver, &of_bus_type); | ||
202 | } | ||
203 | |||
199 | /* This driver is not critical to the boot process | 204 | /* This driver is not critical to the boot process |
200 | * and is easiest to ioremap when SBus is already | 205 | * and is easiest to ioremap when SBus is already |
201 | * initialized, so we install ourselves thusly: | 206 | * initialized, so we install ourselves thusly: |
202 | */ | 207 | */ |
203 | __initcall(apc_probe); | 208 | __initcall(apc_init); |
204 | |||
diff --git a/arch/sparc/kernel/auxio.c b/arch/sparc/kernel/auxio.c index baf4ed3fb0f3..09c857215a52 100644 --- a/arch/sparc/kernel/auxio.c +++ b/arch/sparc/kernel/auxio.c | |||
@@ -6,6 +6,8 @@ | |||
6 | #include <linux/stddef.h> | 6 | #include <linux/stddef.h> |
7 | #include <linux/init.h> | 7 | #include <linux/init.h> |
8 | #include <linux/spinlock.h> | 8 | #include <linux/spinlock.h> |
9 | #include <linux/of.h> | ||
10 | #include <linux/of_device.h> | ||
9 | #include <asm/oplib.h> | 11 | #include <asm/oplib.h> |
10 | #include <asm/io.h> | 12 | #include <asm/io.h> |
11 | #include <asm/auxio.h> | 13 | #include <asm/auxio.h> |
@@ -59,7 +61,7 @@ void __init auxio_probe(void) | |||
59 | r.flags = auxregs[0].which_io & 0xF; | 61 | r.flags = auxregs[0].which_io & 0xF; |
60 | r.start = auxregs[0].phys_addr; | 62 | r.start = auxregs[0].phys_addr; |
61 | r.end = auxregs[0].phys_addr + auxregs[0].reg_size - 1; | 63 | r.end = auxregs[0].phys_addr + auxregs[0].reg_size - 1; |
62 | auxio_register = sbus_ioremap(&r, 0, auxregs[0].reg_size, "auxio"); | 64 | auxio_register = of_ioremap(&r, 0, auxregs[0].reg_size, "auxio"); |
63 | /* Fix the address on sun4m and sun4c. */ | 65 | /* Fix the address on sun4m and sun4c. */ |
64 | if((((unsigned long) auxregs[0].phys_addr) & 3) == 3 || | 66 | if((((unsigned long) auxregs[0].phys_addr) & 3) == 3 || |
65 | sparc_cpu_model == sun4c) | 67 | sparc_cpu_model == sun4c) |
@@ -128,7 +130,7 @@ void __init auxio_power_probe(void) | |||
128 | r.flags = regs.which_io & 0xF; | 130 | r.flags = regs.which_io & 0xF; |
129 | r.start = regs.phys_addr; | 131 | r.start = regs.phys_addr; |
130 | r.end = regs.phys_addr + regs.reg_size - 1; | 132 | r.end = regs.phys_addr + regs.reg_size - 1; |
131 | auxio_power_register = (unsigned char *) sbus_ioremap(&r, 0, | 133 | auxio_power_register = (unsigned char *) of_ioremap(&r, 0, |
132 | regs.reg_size, "auxpower"); | 134 | regs.reg_size, "auxpower"); |
133 | 135 | ||
134 | /* Display a quick message on the console. */ | 136 | /* Display a quick message on the console. */ |
diff --git a/arch/sparc/kernel/devices.c b/arch/sparc/kernel/devices.c index b240b8863fd0..ad656b044b8c 100644 --- a/arch/sparc/kernel/devices.c +++ b/arch/sparc/kernel/devices.c | |||
@@ -143,7 +143,7 @@ void __init device_scan(void) | |||
143 | #endif | 143 | #endif |
144 | clock_stop_probe(); | 144 | clock_stop_probe(); |
145 | 145 | ||
146 | if (ARCH_SUN4C_SUN4) | 146 | if (ARCH_SUN4C) |
147 | sun4c_probe_memerr_reg(); | 147 | sun4c_probe_memerr_reg(); |
148 | 148 | ||
149 | return; | 149 | return; |
diff --git a/arch/sparc/kernel/dma.c b/arch/sparc/kernel/dma.c new file mode 100644 index 000000000000..ebc8403b035e --- /dev/null +++ b/arch/sparc/kernel/dma.c | |||
@@ -0,0 +1,227 @@ | |||
1 | /* dma.c: PCI and SBUS DMA accessors for 32-bit sparc. | ||
2 | * | ||
3 | * Copyright (C) 2008 David S. Miller <davem@davemloft.net> | ||
4 | */ | ||
5 | |||
6 | #include <linux/kernel.h> | ||
7 | #include <linux/module.h> | ||
8 | #include <linux/dma-mapping.h> | ||
9 | #include <linux/scatterlist.h> | ||
10 | #include <linux/mm.h> | ||
11 | |||
12 | #ifdef CONFIG_PCI | ||
13 | #include <linux/pci.h> | ||
14 | #endif | ||
15 | |||
16 | #include "dma.h" | ||
17 | |||
18 | int dma_supported(struct device *dev, u64 mask) | ||
19 | { | ||
20 | #ifdef CONFIG_PCI | ||
21 | if (dev->bus == &pci_bus_type) | ||
22 | return pci_dma_supported(to_pci_dev(dev), mask); | ||
23 | #endif | ||
24 | return 0; | ||
25 | } | ||
26 | EXPORT_SYMBOL(dma_supported); | ||
27 | |||
28 | int dma_set_mask(struct device *dev, u64 dma_mask) | ||
29 | { | ||
30 | #ifdef CONFIG_PCI | ||
31 | if (dev->bus == &pci_bus_type) | ||
32 | return pci_set_dma_mask(to_pci_dev(dev), dma_mask); | ||
33 | #endif | ||
34 | return -EOPNOTSUPP; | ||
35 | } | ||
36 | EXPORT_SYMBOL(dma_set_mask); | ||
37 | |||
38 | void *dma_alloc_coherent(struct device *dev, size_t size, | ||
39 | dma_addr_t *dma_handle, gfp_t flag) | ||
40 | { | ||
41 | #ifdef CONFIG_PCI | ||
42 | if (dev->bus == &pci_bus_type) | ||
43 | return pci_alloc_consistent(to_pci_dev(dev), size, dma_handle); | ||
44 | #endif | ||
45 | return sbus_alloc_consistent(dev, size, dma_handle); | ||
46 | } | ||
47 | EXPORT_SYMBOL(dma_alloc_coherent); | ||
48 | |||
49 | void dma_free_coherent(struct device *dev, size_t size, | ||
50 | void *cpu_addr, dma_addr_t dma_handle) | ||
51 | { | ||
52 | #ifdef CONFIG_PCI | ||
53 | if (dev->bus == &pci_bus_type) { | ||
54 | pci_free_consistent(to_pci_dev(dev), size, | ||
55 | cpu_addr, dma_handle); | ||
56 | return; | ||
57 | } | ||
58 | #endif | ||
59 | sbus_free_consistent(dev, size, cpu_addr, dma_handle); | ||
60 | } | ||
61 | EXPORT_SYMBOL(dma_free_coherent); | ||
62 | |||
63 | dma_addr_t dma_map_single(struct device *dev, void *cpu_addr, | ||
64 | size_t size, enum dma_data_direction direction) | ||
65 | { | ||
66 | #ifdef CONFIG_PCI | ||
67 | if (dev->bus == &pci_bus_type) | ||
68 | return pci_map_single(to_pci_dev(dev), cpu_addr, | ||
69 | size, (int)direction); | ||
70 | #endif | ||
71 | return sbus_map_single(dev, cpu_addr, size, (int)direction); | ||
72 | } | ||
73 | EXPORT_SYMBOL(dma_map_single); | ||
74 | |||
75 | void dma_unmap_single(struct device *dev, dma_addr_t dma_addr, | ||
76 | size_t size, | ||
77 | enum dma_data_direction direction) | ||
78 | { | ||
79 | #ifdef CONFIG_PCI | ||
80 | if (dev->bus == &pci_bus_type) { | ||
81 | pci_unmap_single(to_pci_dev(dev), dma_addr, | ||
82 | size, (int)direction); | ||
83 | return; | ||
84 | } | ||
85 | #endif | ||
86 | sbus_unmap_single(dev, dma_addr, size, (int)direction); | ||
87 | } | ||
88 | EXPORT_SYMBOL(dma_unmap_single); | ||
89 | |||
90 | dma_addr_t dma_map_page(struct device *dev, struct page *page, | ||
91 | unsigned long offset, size_t size, | ||
92 | enum dma_data_direction direction) | ||
93 | { | ||
94 | #ifdef CONFIG_PCI | ||
95 | if (dev->bus == &pci_bus_type) | ||
96 | return pci_map_page(to_pci_dev(dev), page, offset, | ||
97 | size, (int)direction); | ||
98 | #endif | ||
99 | return sbus_map_single(dev, page_address(page) + offset, | ||
100 | size, (int)direction); | ||
101 | } | ||
102 | EXPORT_SYMBOL(dma_map_page); | ||
103 | |||
104 | void dma_unmap_page(struct device *dev, dma_addr_t dma_address, | ||
105 | size_t size, enum dma_data_direction direction) | ||
106 | { | ||
107 | #ifdef CONFIG_PCI | ||
108 | if (dev->bus == &pci_bus_type) { | ||
109 | pci_unmap_page(to_pci_dev(dev), dma_address, | ||
110 | size, (int)direction); | ||
111 | return; | ||
112 | } | ||
113 | #endif | ||
114 | sbus_unmap_single(dev, dma_address, size, (int)direction); | ||
115 | } | ||
116 | EXPORT_SYMBOL(dma_unmap_page); | ||
117 | |||
118 | int dma_map_sg(struct device *dev, struct scatterlist *sg, | ||
119 | int nents, enum dma_data_direction direction) | ||
120 | { | ||
121 | #ifdef CONFIG_PCI | ||
122 | if (dev->bus == &pci_bus_type) | ||
123 | return pci_map_sg(to_pci_dev(dev), sg, nents, (int)direction); | ||
124 | #endif | ||
125 | return sbus_map_sg(dev, sg, nents, direction); | ||
126 | } | ||
127 | EXPORT_SYMBOL(dma_map_sg); | ||
128 | |||
129 | void dma_unmap_sg(struct device *dev, struct scatterlist *sg, | ||
130 | int nents, enum dma_data_direction direction) | ||
131 | { | ||
132 | #ifdef CONFIG_PCI | ||
133 | if (dev->bus == &pci_bus_type) { | ||
134 | pci_unmap_sg(to_pci_dev(dev), sg, nents, (int)direction); | ||
135 | return; | ||
136 | } | ||
137 | #endif | ||
138 | sbus_unmap_sg(dev, sg, nents, (int)direction); | ||
139 | } | ||
140 | EXPORT_SYMBOL(dma_unmap_sg); | ||
141 | |||
142 | void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, | ||
143 | size_t size, enum dma_data_direction direction) | ||
144 | { | ||
145 | #ifdef CONFIG_PCI | ||
146 | if (dev->bus == &pci_bus_type) { | ||
147 | pci_dma_sync_single_for_cpu(to_pci_dev(dev), dma_handle, | ||
148 | size, (int)direction); | ||
149 | return; | ||
150 | } | ||
151 | #endif | ||
152 | sbus_dma_sync_single_for_cpu(dev, dma_handle, size, (int) direction); | ||
153 | } | ||
154 | EXPORT_SYMBOL(dma_sync_single_for_cpu); | ||
155 | |||
156 | void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, | ||
157 | size_t size, enum dma_data_direction direction) | ||
158 | { | ||
159 | #ifdef CONFIG_PCI | ||
160 | if (dev->bus == &pci_bus_type) { | ||
161 | pci_dma_sync_single_for_device(to_pci_dev(dev), dma_handle, | ||
162 | size, (int)direction); | ||
163 | return; | ||
164 | } | ||
165 | #endif | ||
166 | sbus_dma_sync_single_for_device(dev, dma_handle, size, (int) direction); | ||
167 | } | ||
168 | EXPORT_SYMBOL(dma_sync_single_for_device); | ||
169 | |||
170 | void dma_sync_single_range_for_cpu(struct device *dev, | ||
171 | dma_addr_t dma_handle, | ||
172 | unsigned long offset, | ||
173 | size_t size, | ||
174 | enum dma_data_direction direction) | ||
175 | { | ||
176 | dma_sync_single_for_cpu(dev, dma_handle+offset, size, direction); | ||
177 | } | ||
178 | EXPORT_SYMBOL(dma_sync_single_range_for_cpu); | ||
179 | |||
180 | void dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle, | ||
181 | unsigned long offset, size_t size, | ||
182 | enum dma_data_direction direction) | ||
183 | { | ||
184 | dma_sync_single_for_device(dev, dma_handle+offset, size, direction); | ||
185 | } | ||
186 | EXPORT_SYMBOL(dma_sync_single_range_for_device); | ||
187 | |||
188 | void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, | ||
189 | int nelems, enum dma_data_direction direction) | ||
190 | { | ||
191 | #ifdef CONFIG_PCI | ||
192 | if (dev->bus == &pci_bus_type) { | ||
193 | pci_dma_sync_sg_for_cpu(to_pci_dev(dev), sg, | ||
194 | nelems, (int)direction); | ||
195 | return; | ||
196 | } | ||
197 | #endif | ||
198 | BUG(); | ||
199 | } | ||
200 | EXPORT_SYMBOL(dma_sync_sg_for_cpu); | ||
201 | |||
202 | void dma_sync_sg_for_device(struct device *dev, | ||
203 | struct scatterlist *sg, int nelems, | ||
204 | enum dma_data_direction direction) | ||
205 | { | ||
206 | #ifdef CONFIG_PCI | ||
207 | if (dev->bus == &pci_bus_type) { | ||
208 | pci_dma_sync_sg_for_device(to_pci_dev(dev), sg, | ||
209 | nelems, (int)direction); | ||
210 | return; | ||
211 | } | ||
212 | #endif | ||
213 | BUG(); | ||
214 | } | ||
215 | EXPORT_SYMBOL(dma_sync_sg_for_device); | ||
216 | |||
217 | int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) | ||
218 | { | ||
219 | return (dma_addr == DMA_ERROR_CODE); | ||
220 | } | ||
221 | EXPORT_SYMBOL(dma_mapping_error); | ||
222 | |||
223 | int dma_get_cache_alignment(void) | ||
224 | { | ||
225 | return 32; | ||
226 | } | ||
227 | EXPORT_SYMBOL(dma_get_cache_alignment); | ||
diff --git a/arch/sparc/kernel/dma.h b/arch/sparc/kernel/dma.h new file mode 100644 index 000000000000..f8d8951adb53 --- /dev/null +++ b/arch/sparc/kernel/dma.h | |||
@@ -0,0 +1,14 @@ | |||
1 | void *sbus_alloc_consistent(struct device *dev, long len, u32 *dma_addrp); | ||
2 | void sbus_free_consistent(struct device *dev, long n, void *p, u32 ba); | ||
3 | dma_addr_t sbus_map_single(struct device *dev, void *va, | ||
4 | size_t len, int direction); | ||
5 | void sbus_unmap_single(struct device *dev, dma_addr_t ba, | ||
6 | size_t n, int direction); | ||
7 | int sbus_map_sg(struct device *dev, struct scatterlist *sg, | ||
8 | int n, int direction); | ||
9 | void sbus_unmap_sg(struct device *dev, struct scatterlist *sg, | ||
10 | int n, int direction); | ||
11 | void sbus_dma_sync_single_for_cpu(struct device *dev, dma_addr_t ba, | ||
12 | size_t size, int direction); | ||
13 | void sbus_dma_sync_single_for_device(struct device *dev, dma_addr_t ba, | ||
14 | size_t size, int direction); | ||
diff --git a/arch/sparc/kernel/ebus.c b/arch/sparc/kernel/ebus.c deleted file mode 100644 index 97294232259c..000000000000 --- a/arch/sparc/kernel/ebus.c +++ /dev/null | |||
@@ -1,393 +0,0 @@ | |||
1 | /* | ||
2 | * ebus.c: PCI to EBus bridge device. | ||
3 | * | ||
4 | * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) | ||
5 | * | ||
6 | * Adopted for sparc by V. Roganov and G. Raiko. | ||
7 | * Fixes for different platforms by Pete Zaitcev. | ||
8 | */ | ||
9 | |||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/types.h> | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/slab.h> | ||
14 | #include <linux/string.h> | ||
15 | |||
16 | #include <asm/system.h> | ||
17 | #include <asm/page.h> | ||
18 | #include <asm/pbm.h> | ||
19 | #include <asm/ebus.h> | ||
20 | #include <asm/io.h> | ||
21 | #include <asm/oplib.h> | ||
22 | #include <asm/prom.h> | ||
23 | #include <asm/bpp.h> | ||
24 | |||
25 | struct linux_ebus *ebus_chain = NULL; | ||
26 | |||
27 | /* We are together with pcic.c under CONFIG_PCI. */ | ||
28 | extern unsigned int pcic_pin_to_irq(unsigned int, const char *name); | ||
29 | |||
30 | /* | ||
31 | * IRQ Blacklist | ||
32 | * Here we list PROMs and systems that are known to supply crap as IRQ numbers. | ||
33 | */ | ||
34 | struct ebus_device_irq { | ||
35 | char *name; | ||
36 | unsigned int pin; | ||
37 | }; | ||
38 | |||
39 | struct ebus_system_entry { | ||
40 | char *esname; | ||
41 | struct ebus_device_irq *ipt; | ||
42 | }; | ||
43 | |||
44 | static struct ebus_device_irq je1_1[] = { | ||
45 | { "8042", 3 }, | ||
46 | { "SUNW,CS4231", 0 }, | ||
47 | { "parallel", 0 }, | ||
48 | { "se", 2 }, | ||
49 | { NULL, 0 } | ||
50 | }; | ||
51 | |||
52 | /* | ||
53 | * Gleb's JE1 supplied reasonable pin numbers, but mine did not (OBP 2.32). | ||
54 | * Blacklist the sucker... Note that Gleb's system will work. | ||
55 | */ | ||
56 | static struct ebus_system_entry ebus_blacklist[] = { | ||
57 | { "SUNW,JavaEngine1", je1_1 }, | ||
58 | { NULL, NULL } | ||
59 | }; | ||
60 | |||
61 | static struct ebus_device_irq *ebus_blackp = NULL; | ||
62 | |||
63 | /* | ||
64 | */ | ||
65 | static inline unsigned long ebus_alloc(size_t size) | ||
66 | { | ||
67 | return (unsigned long)kmalloc(size, GFP_ATOMIC); | ||
68 | } | ||
69 | |||
70 | /* | ||
71 | */ | ||
72 | static int __init ebus_blacklist_irq(const char *name) | ||
73 | { | ||
74 | struct ebus_device_irq *dp; | ||
75 | |||
76 | if ((dp = ebus_blackp) != NULL) { | ||
77 | for (; dp->name != NULL; dp++) { | ||
78 | if (strcmp(name, dp->name) == 0) { | ||
79 | return pcic_pin_to_irq(dp->pin, name); | ||
80 | } | ||
81 | } | ||
82 | } | ||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | static void __init fill_ebus_child(struct device_node *dp, | ||
87 | struct linux_ebus_child *dev) | ||
88 | { | ||
89 | const int *regs; | ||
90 | const int *irqs; | ||
91 | int i, len; | ||
92 | |||
93 | dev->prom_node = dp; | ||
94 | regs = of_get_property(dp, "reg", &len); | ||
95 | if (!regs) | ||
96 | len = 0; | ||
97 | dev->num_addrs = len / sizeof(regs[0]); | ||
98 | |||
99 | for (i = 0; i < dev->num_addrs; i++) { | ||
100 | if (regs[i] >= dev->parent->num_addrs) { | ||
101 | prom_printf("UGH: property for %s was %d, need < %d\n", | ||
102 | dev->prom_node->name, len, | ||
103 | dev->parent->num_addrs); | ||
104 | panic(__func__); | ||
105 | } | ||
106 | |||
107 | /* XXX resource */ | ||
108 | dev->resource[i].start = | ||
109 | dev->parent->resource[regs[i]].start; | ||
110 | } | ||
111 | |||
112 | for (i = 0; i < PROMINTR_MAX; i++) | ||
113 | dev->irqs[i] = PCI_IRQ_NONE; | ||
114 | |||
115 | if ((dev->irqs[0] = ebus_blacklist_irq(dev->prom_node->name)) != 0) { | ||
116 | dev->num_irqs = 1; | ||
117 | } else { | ||
118 | irqs = of_get_property(dp, "interrupts", &len); | ||
119 | if (!irqs) { | ||
120 | dev->num_irqs = 0; | ||
121 | dev->irqs[0] = 0; | ||
122 | if (dev->parent->num_irqs != 0) { | ||
123 | dev->num_irqs = 1; | ||
124 | dev->irqs[0] = dev->parent->irqs[0]; | ||
125 | } | ||
126 | } else { | ||
127 | dev->num_irqs = len / sizeof(irqs[0]); | ||
128 | if (irqs[0] == 0 || irqs[0] >= 8) { | ||
129 | /* | ||
130 | * XXX Zero is a valid pin number... | ||
131 | * This works as long as Ebus is not wired | ||
132 | * to INTA#. | ||
133 | */ | ||
134 | printk("EBUS: %s got bad irq %d from PROM\n", | ||
135 | dev->prom_node->name, irqs[0]); | ||
136 | dev->num_irqs = 0; | ||
137 | dev->irqs[0] = 0; | ||
138 | } else { | ||
139 | dev->irqs[0] = | ||
140 | pcic_pin_to_irq(irqs[0], | ||
141 | dev->prom_node->name); | ||
142 | } | ||
143 | } | ||
144 | } | ||
145 | } | ||
146 | |||
147 | static void __init fill_ebus_device(struct device_node *dp, | ||
148 | struct linux_ebus_device *dev) | ||
149 | { | ||
150 | const struct linux_prom_registers *regs; | ||
151 | struct linux_ebus_child *child; | ||
152 | struct dev_archdata *sd; | ||
153 | const int *irqs; | ||
154 | int i, n, len; | ||
155 | unsigned long baseaddr; | ||
156 | |||
157 | dev->prom_node = dp; | ||
158 | |||
159 | regs = of_get_property(dp, "reg", &len); | ||
160 | if (!regs) | ||
161 | len = 0; | ||
162 | if (len % sizeof(struct linux_prom_registers)) { | ||
163 | prom_printf("UGH: proplen for %s was %d, need multiple of %d\n", | ||
164 | dev->prom_node->name, len, | ||
165 | (int)sizeof(struct linux_prom_registers)); | ||
166 | panic(__func__); | ||
167 | } | ||
168 | dev->num_addrs = len / sizeof(struct linux_prom_registers); | ||
169 | |||
170 | for (i = 0; i < dev->num_addrs; i++) { | ||
171 | /* | ||
172 | * XXX Collect JE-1 PROM | ||
173 | * | ||
174 | * Example - JS-E with 3.11: | ||
175 | * /ebus | ||
176 | * regs | ||
177 | * 0x00000000, 0x0, 0x00000000, 0x0, 0x00000000, | ||
178 | * 0x82000010, 0x0, 0xf0000000, 0x0, 0x01000000, | ||
179 | * 0x82000014, 0x0, 0x38800000, 0x0, 0x00800000, | ||
180 | * ranges | ||
181 | * 0x00, 0x00000000, 0x02000010, 0x0, 0x0, 0x01000000, | ||
182 | * 0x01, 0x01000000, 0x02000014, 0x0, 0x0, 0x00800000, | ||
183 | * /ebus/8042 | ||
184 | * regs | ||
185 | * 0x00000001, 0x00300060, 0x00000008, | ||
186 | * 0x00000001, 0x00300060, 0x00000008, | ||
187 | */ | ||
188 | n = regs[i].which_io; | ||
189 | if (n >= 4) { | ||
190 | /* XXX This is copied from old JE-1 by Gleb. */ | ||
191 | n = (regs[i].which_io - 0x10) >> 2; | ||
192 | } else { | ||
193 | ; | ||
194 | } | ||
195 | |||
196 | /* | ||
197 | * XXX Now as we have regions, why don't we make an on-demand allocation... | ||
198 | */ | ||
199 | dev->resource[i].start = 0; | ||
200 | if ((baseaddr = dev->bus->self->resource[n].start + | ||
201 | regs[i].phys_addr) != 0) { | ||
202 | /* dev->resource[i].name = dev->prom_name; */ | ||
203 | if ((baseaddr = (unsigned long) ioremap(baseaddr, | ||
204 | regs[i].reg_size)) == 0) { | ||
205 | panic("ebus: unable to remap dev %s", | ||
206 | dev->prom_node->name); | ||
207 | } | ||
208 | } | ||
209 | dev->resource[i].start = baseaddr; /* XXX Unaligned */ | ||
210 | } | ||
211 | |||
212 | for (i = 0; i < PROMINTR_MAX; i++) | ||
213 | dev->irqs[i] = PCI_IRQ_NONE; | ||
214 | |||
215 | if ((dev->irqs[0] = ebus_blacklist_irq(dev->prom_node->name)) != 0) { | ||
216 | dev->num_irqs = 1; | ||
217 | } else { | ||
218 | irqs = of_get_property(dp, "interrupts", &len); | ||
219 | if (!irqs) { | ||
220 | dev->num_irqs = 0; | ||
221 | if ((dev->irqs[0] = dev->bus->self->irq) != 0) { | ||
222 | dev->num_irqs = 1; | ||
223 | /* P3 */ /* printk("EBUS: child %s irq %d from parent\n", dev->prom_name, dev->irqs[0]); */ | ||
224 | } | ||
225 | } else { | ||
226 | dev->num_irqs = 1; /* dev->num_irqs = len / sizeof(irqs[0]); */ | ||
227 | if (irqs[0] == 0 || irqs[0] >= 8) { | ||
228 | /* See above for the parent. XXX */ | ||
229 | printk("EBUS: %s got bad irq %d from PROM\n", | ||
230 | dev->prom_node->name, irqs[0]); | ||
231 | dev->num_irqs = 0; | ||
232 | dev->irqs[0] = 0; | ||
233 | } else { | ||
234 | dev->irqs[0] = | ||
235 | pcic_pin_to_irq(irqs[0], | ||
236 | dev->prom_node->name); | ||
237 | } | ||
238 | } | ||
239 | } | ||
240 | |||
241 | sd = &dev->ofdev.dev.archdata; | ||
242 | sd->prom_node = dp; | ||
243 | sd->op = &dev->ofdev; | ||
244 | sd->iommu = dev->bus->ofdev.dev.parent->archdata.iommu; | ||
245 | |||
246 | dev->ofdev.node = dp; | ||
247 | dev->ofdev.dev.parent = &dev->bus->ofdev.dev; | ||
248 | dev->ofdev.dev.bus = &ebus_bus_type; | ||
249 | sprintf(dev->ofdev.dev.bus_id, "ebus[%08x]", dp->node); | ||
250 | |||
251 | /* Register with core */ | ||
252 | if (of_device_register(&dev->ofdev) != 0) | ||
253 | printk(KERN_DEBUG "ebus: device registration error for %s!\n", | ||
254 | dp->path_component_name); | ||
255 | |||
256 | if ((dp = dp->child) != NULL) { | ||
257 | dev->children = (struct linux_ebus_child *) | ||
258 | ebus_alloc(sizeof(struct linux_ebus_child)); | ||
259 | |||
260 | child = dev->children; | ||
261 | child->next = NULL; | ||
262 | child->parent = dev; | ||
263 | child->bus = dev->bus; | ||
264 | fill_ebus_child(dp, child); | ||
265 | |||
266 | while ((dp = dp->sibling) != NULL) { | ||
267 | child->next = (struct linux_ebus_child *) | ||
268 | ebus_alloc(sizeof(struct linux_ebus_child)); | ||
269 | |||
270 | child = child->next; | ||
271 | child->next = NULL; | ||
272 | child->parent = dev; | ||
273 | child->bus = dev->bus; | ||
274 | fill_ebus_child(dp, child); | ||
275 | } | ||
276 | } | ||
277 | } | ||
278 | |||
279 | void __init ebus_init(void) | ||
280 | { | ||
281 | const struct linux_prom_pci_registers *regs; | ||
282 | struct linux_pbm_info *pbm; | ||
283 | struct linux_ebus_device *dev; | ||
284 | struct linux_ebus *ebus; | ||
285 | struct ebus_system_entry *sp; | ||
286 | struct pci_dev *pdev; | ||
287 | struct pcidev_cookie *cookie; | ||
288 | struct device_node *dp; | ||
289 | struct resource *p; | ||
290 | unsigned short pci_command; | ||
291 | int len, reg, nreg; | ||
292 | int num_ebus = 0; | ||
293 | |||
294 | dp = of_find_node_by_path("/"); | ||
295 | for (sp = ebus_blacklist; sp->esname != NULL; sp++) { | ||
296 | if (strcmp(dp->name, sp->esname) == 0) { | ||
297 | ebus_blackp = sp->ipt; | ||
298 | break; | ||
299 | } | ||
300 | } | ||
301 | |||
302 | pdev = pci_get_device(PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_EBUS, NULL); | ||
303 | if (!pdev) | ||
304 | return; | ||
305 | |||
306 | cookie = pdev->sysdata; | ||
307 | dp = cookie->prom_node; | ||
308 | |||
309 | ebus_chain = ebus = (struct linux_ebus *) | ||
310 | ebus_alloc(sizeof(struct linux_ebus)); | ||
311 | ebus->next = NULL; | ||
312 | |||
313 | while (dp) { | ||
314 | struct device_node *nd; | ||
315 | |||
316 | ebus->prom_node = dp; | ||
317 | ebus->self = pdev; | ||
318 | ebus->parent = pbm = cookie->pbm; | ||
319 | |||
320 | /* Enable BUS Master. */ | ||
321 | pci_read_config_word(pdev, PCI_COMMAND, &pci_command); | ||
322 | pci_command |= PCI_COMMAND_MASTER; | ||
323 | pci_write_config_word(pdev, PCI_COMMAND, pci_command); | ||
324 | |||
325 | regs = of_get_property(dp, "reg", &len); | ||
326 | if (!regs) { | ||
327 | prom_printf("%s: can't find reg property\n", | ||
328 | __func__); | ||
329 | prom_halt(); | ||
330 | } | ||
331 | nreg = len / sizeof(struct linux_prom_pci_registers); | ||
332 | |||
333 | p = &ebus->self->resource[0]; | ||
334 | for (reg = 0; reg < nreg; reg++) { | ||
335 | if (!(regs[reg].which_io & 0x03000000)) | ||
336 | continue; | ||
337 | |||
338 | (p++)->start = regs[reg].phys_lo; | ||
339 | } | ||
340 | |||
341 | ebus->ofdev.node = dp; | ||
342 | ebus->ofdev.dev.parent = &pdev->dev; | ||
343 | ebus->ofdev.dev.bus = &ebus_bus_type; | ||
344 | sprintf(ebus->ofdev.dev.bus_id, "ebus%d", num_ebus); | ||
345 | |||
346 | /* Register with core */ | ||
347 | if (of_device_register(&ebus->ofdev) != 0) | ||
348 | printk(KERN_DEBUG "ebus: device registration error for %s!\n", | ||
349 | dp->path_component_name); | ||
350 | |||
351 | |||
352 | nd = dp->child; | ||
353 | if (!nd) | ||
354 | goto next_ebus; | ||
355 | |||
356 | ebus->devices = (struct linux_ebus_device *) | ||
357 | ebus_alloc(sizeof(struct linux_ebus_device)); | ||
358 | |||
359 | dev = ebus->devices; | ||
360 | dev->next = NULL; | ||
361 | dev->children = NULL; | ||
362 | dev->bus = ebus; | ||
363 | fill_ebus_device(nd, dev); | ||
364 | |||
365 | while ((nd = nd->sibling) != NULL) { | ||
366 | dev->next = (struct linux_ebus_device *) | ||
367 | ebus_alloc(sizeof(struct linux_ebus_device)); | ||
368 | |||
369 | dev = dev->next; | ||
370 | dev->next = NULL; | ||
371 | dev->children = NULL; | ||
372 | dev->bus = ebus; | ||
373 | fill_ebus_device(nd, dev); | ||
374 | } | ||
375 | |||
376 | next_ebus: | ||
377 | pdev = pci_get_device(PCI_VENDOR_ID_SUN, | ||
378 | PCI_DEVICE_ID_SUN_EBUS, pdev); | ||
379 | if (!pdev) | ||
380 | break; | ||
381 | |||
382 | cookie = pdev->sysdata; | ||
383 | dp = cookie->prom_node; | ||
384 | |||
385 | ebus->next = (struct linux_ebus *) | ||
386 | ebus_alloc(sizeof(struct linux_ebus)); | ||
387 | ebus = ebus->next; | ||
388 | ebus->next = NULL; | ||
389 | ++num_ebus; | ||
390 | } | ||
391 | if (pdev) | ||
392 | pci_dev_put(pdev); | ||
393 | } | ||
diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S index e8cdf715a546..faf9ccd9ef5d 100644 --- a/arch/sparc/kernel/entry.S +++ b/arch/sparc/kernel/entry.S | |||
@@ -20,11 +20,7 @@ | |||
20 | #include <asm/memreg.h> | 20 | #include <asm/memreg.h> |
21 | #include <asm/page.h> | 21 | #include <asm/page.h> |
22 | #include <asm/pgtable.h> | 22 | #include <asm/pgtable.h> |
23 | #ifdef CONFIG_SUN4 | ||
24 | #include <asm/pgtsun4.h> | ||
25 | #else | ||
26 | #include <asm/pgtsun4c.h> | 23 | #include <asm/pgtsun4c.h> |
27 | #endif | ||
28 | #include <asm/winmacro.h> | 24 | #include <asm/winmacro.h> |
29 | #include <asm/signal.h> | 25 | #include <asm/signal.h> |
30 | #include <asm/obio.h> | 26 | #include <asm/obio.h> |
@@ -276,17 +272,18 @@ smp4m_ticker: | |||
276 | */ | 272 | */ |
277 | maybe_smp4m_msg: | 273 | maybe_smp4m_msg: |
278 | GET_PROCESSOR4M_ID(o3) | 274 | GET_PROCESSOR4M_ID(o3) |
279 | set sun4m_interrupts, %l5 | 275 | sethi %hi(sun4m_irq_percpu), %l5 |
280 | ld [%l5], %o5 | 276 | sll %o3, 2, %o3 |
277 | or %l5, %lo(sun4m_irq_percpu), %o5 | ||
281 | sethi %hi(0x40000000), %o2 | 278 | sethi %hi(0x40000000), %o2 |
282 | sll %o3, 12, %o3 | ||
283 | ld [%o5 + %o3], %o1 | 279 | ld [%o5 + %o3], %o1 |
284 | andcc %o1, %o2, %g0 | 280 | ld [%o1 + 0x00], %o3 ! sun4m_irq_percpu[cpu]->pending |
281 | andcc %o3, %o2, %g0 | ||
285 | be,a smp4m_ticker | 282 | be,a smp4m_ticker |
286 | cmp %l7, 14 | 283 | cmp %l7, 14 |
287 | st %o2, [%o5 + 0x4] | 284 | st %o2, [%o1 + 0x04] ! sun4m_irq_percpu[cpu]->clear=0x40000000 |
288 | WRITE_PAUSE | 285 | WRITE_PAUSE |
289 | ld [%o5], %g0 | 286 | ld [%o1 + 0x00], %g0 ! sun4m_irq_percpu[cpu]->pending |
290 | WRITE_PAUSE | 287 | WRITE_PAUSE |
291 | or %l0, PSR_PIL, %l4 | 288 | or %l0, PSR_PIL, %l4 |
292 | wr %l4, 0x0, %psr | 289 | wr %l4, 0x0, %psr |
@@ -304,16 +301,16 @@ linux_trap_ipi15_sun4m: | |||
304 | SAVE_ALL | 301 | SAVE_ALL |
305 | sethi %hi(0x80000000), %o2 | 302 | sethi %hi(0x80000000), %o2 |
306 | GET_PROCESSOR4M_ID(o0) | 303 | GET_PROCESSOR4M_ID(o0) |
307 | set sun4m_interrupts, %l5 | 304 | sethi %hi(sun4m_irq_percpu), %l5 |
308 | ld [%l5], %o5 | 305 | or %l5, %lo(sun4m_irq_percpu), %o5 |
309 | sll %o0, 12, %o0 | 306 | sll %o0, 2, %o0 |
310 | add %o5, %o0, %o5 | 307 | ld [%o5 + %o0], %o5 |
311 | ld [%o5], %o3 | 308 | ld [%o5 + 0x00], %o3 ! sun4m_irq_percpu[cpu]->pending |
312 | andcc %o3, %o2, %g0 | 309 | andcc %o3, %o2, %g0 |
313 | be 1f ! Must be an NMI async memory error | 310 | be 1f ! Must be an NMI async memory error |
314 | st %o2, [%o5 + 4] | 311 | st %o2, [%o5 + 0x04] ! sun4m_irq_percpu[cpu]->clear=0x80000000 |
315 | WRITE_PAUSE | 312 | WRITE_PAUSE |
316 | ld [%o5], %g0 | 313 | ld [%o5 + 0x00], %g0 ! sun4m_irq_percpu[cpu]->pending |
317 | WRITE_PAUSE | 314 | WRITE_PAUSE |
318 | or %l0, PSR_PIL, %l4 | 315 | or %l0, PSR_PIL, %l4 |
319 | wr %l4, 0x0, %psr | 316 | wr %l4, 0x0, %psr |
@@ -327,12 +324,11 @@ linux_trap_ipi15_sun4m: | |||
327 | 1: | 324 | 1: |
328 | /* NMI async memory error handling. */ | 325 | /* NMI async memory error handling. */ |
329 | sethi %hi(0x80000000), %l4 | 326 | sethi %hi(0x80000000), %l4 |
330 | sethi %hi(0x4000), %o3 | 327 | sethi %hi(sun4m_irq_global), %o5 |
331 | sub %o5, %o0, %o5 | 328 | ld [%o5 + %lo(sun4m_irq_global)], %l5 |
332 | add %o5, %o3, %l5 | 329 | st %l4, [%l5 + 0x0c] ! sun4m_irq_global->mask_set=0x80000000 |
333 | st %l4, [%l5 + 0xc] | ||
334 | WRITE_PAUSE | 330 | WRITE_PAUSE |
335 | ld [%l5], %g0 | 331 | ld [%l5 + 0x00], %g0 ! sun4m_irq_global->pending |
336 | WRITE_PAUSE | 332 | WRITE_PAUSE |
337 | or %l0, PSR_PIL, %l4 | 333 | or %l0, PSR_PIL, %l4 |
338 | wr %l4, 0x0, %psr | 334 | wr %l4, 0x0, %psr |
@@ -341,9 +337,9 @@ linux_trap_ipi15_sun4m: | |||
341 | WRITE_PAUSE | 337 | WRITE_PAUSE |
342 | call sun4m_nmi | 338 | call sun4m_nmi |
343 | nop | 339 | nop |
344 | st %l4, [%l5 + 0x8] | 340 | st %l4, [%l5 + 0x08] ! sun4m_irq_global->mask_clear=0x80000000 |
345 | WRITE_PAUSE | 341 | WRITE_PAUSE |
346 | ld [%l5], %g0 | 342 | ld [%l5 + 0x00], %g0 ! sun4m_irq_global->pending |
347 | WRITE_PAUSE | 343 | WRITE_PAUSE |
348 | RESTORE_ALL | 344 | RESTORE_ALL |
349 | 345 | ||
@@ -775,11 +771,7 @@ vac_linesize_patch_32: subcc %l7, 32, %l7 | |||
775 | * Ugly, but we cant use hardware flushing on the sun4 and we'd require | 771 | * Ugly, but we cant use hardware flushing on the sun4 and we'd require |
776 | * two instructions (Anton) | 772 | * two instructions (Anton) |
777 | */ | 773 | */ |
778 | #ifdef CONFIG_SUN4 | ||
779 | vac_hwflush_patch1_on: nop | ||
780 | #else | ||
781 | vac_hwflush_patch1_on: addcc %l7, -PAGE_SIZE, %l7 | 774 | vac_hwflush_patch1_on: addcc %l7, -PAGE_SIZE, %l7 |
782 | #endif | ||
783 | 775 | ||
784 | vac_hwflush_patch2_on: sta %g0, [%l3 + %l7] ASI_HWFLUSHSEG | 776 | vac_hwflush_patch2_on: sta %g0, [%l3 + %l7] ASI_HWFLUSHSEG |
785 | 777 | ||
@@ -798,42 +790,10 @@ vac_hwflush_patch2_on: sta %g0, [%l3 + %l7] ASI_HWFLUSHSEG | |||
798 | ! %l7 = 1 for textfault | 790 | ! %l7 = 1 for textfault |
799 | ! We want error in %l5, vaddr in %l6 | 791 | ! We want error in %l5, vaddr in %l6 |
800 | sun4c_fault: | 792 | sun4c_fault: |
801 | #ifdef CONFIG_SUN4 | ||
802 | sethi %hi(sun4c_memerr_reg), %l4 | ||
803 | ld [%l4+%lo(sun4c_memerr_reg)], %l4 ! memerr ctrl reg addr | ||
804 | ld [%l4], %l6 ! memerr ctrl reg | ||
805 | ld [%l4 + 4], %l5 ! memerr vaddr reg | ||
806 | andcc %l6, 0x80, %g0 ! check for error type | ||
807 | st %g0, [%l4 + 4] ! clear the error | ||
808 | be 0f ! normal error | ||
809 | sethi %hi(AC_BUS_ERROR), %l4 ! bus err reg addr | ||
810 | |||
811 | call prom_halt ! something weird happened | ||
812 | ! what exactly did happen? | ||
813 | ! what should we do here? | ||
814 | |||
815 | 0: or %l4, %lo(AC_BUS_ERROR), %l4 ! bus err reg addr | ||
816 | lduba [%l4] ASI_CONTROL, %l6 ! bus err reg | ||
817 | |||
818 | cmp %l7, 1 ! text fault? | ||
819 | be 1f ! yes | ||
820 | nop | ||
821 | |||
822 | ld [%l1], %l4 ! load instruction that caused fault | ||
823 | srl %l4, 21, %l4 | ||
824 | andcc %l4, 1, %g0 ! store instruction? | ||
825 | |||
826 | be 1f ! no | ||
827 | sethi %hi(SUN4C_SYNC_BADWRITE), %l4 ! yep | ||
828 | ! %lo(SUN4C_SYNC_BADWRITE) = 0 | ||
829 | or %l4, %l6, %l6 ! set write bit to emulate sun4c | ||
830 | 1: | ||
831 | #else | ||
832 | sethi %hi(AC_SYNC_ERR), %l4 | 793 | sethi %hi(AC_SYNC_ERR), %l4 |
833 | add %l4, 0x4, %l6 ! AC_SYNC_VA in %l6 | 794 | add %l4, 0x4, %l6 ! AC_SYNC_VA in %l6 |
834 | lda [%l6] ASI_CONTROL, %l5 ! Address | 795 | lda [%l6] ASI_CONTROL, %l5 ! Address |
835 | lda [%l4] ASI_CONTROL, %l6 ! Error, retained for a bit | 796 | lda [%l4] ASI_CONTROL, %l6 ! Error, retained for a bit |
836 | #endif | ||
837 | 797 | ||
838 | andn %l5, 0xfff, %l5 ! Encode all info into l7 | 798 | andn %l5, 0xfff, %l5 ! Encode all info into l7 |
839 | srl %l6, 14, %l4 | 799 | srl %l6, 14, %l4 |
@@ -880,12 +840,7 @@ sun4c_fault: | |||
880 | or %l4, %lo(swapper_pg_dir), %l4 | 840 | or %l4, %lo(swapper_pg_dir), %l4 |
881 | sll %l6, 2, %l6 | 841 | sll %l6, 2, %l6 |
882 | ld [%l4 + %l6], %l4 | 842 | ld [%l4 + %l6], %l4 |
883 | #ifdef CONFIG_SUN4 | ||
884 | sethi %hi(PAGE_MASK), %l6 | ||
885 | andcc %l4, %l6, %g0 | ||
886 | #else | ||
887 | andcc %l4, PAGE_MASK, %g0 | 843 | andcc %l4, PAGE_MASK, %g0 |
888 | #endif | ||
889 | be sun4c_fault_fromuser | 844 | be sun4c_fault_fromuser |
890 | lduXa [%l5] ASI_SEGMAP, %l4 | 845 | lduXa [%l5] ASI_SEGMAP, %l4 |
891 | 846 | ||
@@ -937,11 +892,7 @@ invalid_segment_patch1: | |||
937 | ld [%l6 + 0x08], %l3 ! tmp = entry->vaddr | 892 | ld [%l6 + 0x08], %l3 ! tmp = entry->vaddr |
938 | 893 | ||
939 | ! Flush segment from the cache. | 894 | ! Flush segment from the cache. |
940 | #ifdef CONFIG_SUN4 | ||
941 | sethi %hi((128 * 1024)), %l7 | ||
942 | #else | ||
943 | sethi %hi((64 * 1024)), %l7 | 895 | sethi %hi((64 * 1024)), %l7 |
944 | #endif | ||
945 | 9: | 896 | 9: |
946 | vac_hwflush_patch1: | 897 | vac_hwflush_patch1: |
947 | vac_linesize_patch: | 898 | vac_linesize_patch: |
@@ -1029,12 +980,7 @@ invalid_segment_patch2: | |||
1029 | or %l4, %lo(swapper_pg_dir), %l4 | 980 | or %l4, %lo(swapper_pg_dir), %l4 |
1030 | sll %l3, 2, %l3 | 981 | sll %l3, 2, %l3 |
1031 | ld [%l4 + %l3], %l4 | 982 | ld [%l4 + %l3], %l4 |
1032 | #ifndef CONFIG_SUN4 | ||
1033 | and %l4, PAGE_MASK, %l4 | 983 | and %l4, PAGE_MASK, %l4 |
1034 | #else | ||
1035 | sethi %hi(PAGE_MASK), %l6 | ||
1036 | and %l4, %l6, %l4 | ||
1037 | #endif | ||
1038 | 984 | ||
1039 | srl %l5, (PAGE_SHIFT - 2), %l6 | 985 | srl %l5, (PAGE_SHIFT - 2), %l6 |
1040 | and %l6, ((SUN4C_PTRS_PER_PTE - 1) << 2), %l6 | 986 | and %l6, ((SUN4C_PTRS_PER_PTE - 1) << 2), %l6 |
diff --git a/arch/sparc/kernel/head.S b/arch/sparc/kernel/head.S index 50d9a16af795..2d325fd84579 100644 --- a/arch/sparc/kernel/head.S +++ b/arch/sparc/kernel/head.S | |||
@@ -63,15 +63,9 @@ cputypvar_sun4m: | |||
63 | 63 | ||
64 | .align 4 | 64 | .align 4 |
65 | 65 | ||
66 | #ifndef CONFIG_SUN4 | ||
67 | sun4_notsup: | 66 | sun4_notsup: |
68 | .asciz "Sparc-Linux sun4 needs a specially compiled kernel, turn CONFIG_SUN4 on.\n\n" | 67 | .asciz "Sparc-Linux sun4 support does no longer exist.\n\n" |
69 | .align 4 | 68 | .align 4 |
70 | #else | ||
71 | sun4cdm_notsup: | ||
72 | .asciz "Kernel compiled with CONFIG_SUN4 cannot run on SUN4C/SUN4M/SUN4D\nTurn CONFIG_SUN4 off.\n\n" | ||
73 | .align 4 | ||
74 | #endif | ||
75 | 69 | ||
76 | sun4e_notsup: | 70 | sun4e_notsup: |
77 | .asciz "Sparc-Linux sun4e support does not exist\n\n" | 71 | .asciz "Sparc-Linux sun4e support does not exist\n\n" |
@@ -780,15 +774,6 @@ execute_in_high_mem: | |||
780 | nop | 774 | nop |
781 | 775 | ||
782 | found_version: | 776 | found_version: |
783 | #ifdef CONFIG_SUN4 | ||
784 | /* For people who try sun4 kernels, even if Configure.help advises them. */ | ||
785 | ld [%g7 + 0x68], %o1 | ||
786 | set sun4cdm_notsup, %o0 | ||
787 | call %o1 | ||
788 | nop | ||
789 | b halt_me | ||
790 | nop | ||
791 | #endif | ||
792 | /* Get the machine type via the mysterious romvec node operations. */ | 777 | /* Get the machine type via the mysterious romvec node operations. */ |
793 | 778 | ||
794 | add %g7, 0x1c, %l1 | 779 | add %g7, 0x1c, %l1 |
@@ -1150,15 +1135,6 @@ sun4c_continue_boot: | |||
1150 | nop | 1135 | nop |
1151 | 1136 | ||
1152 | sun4_init: | 1137 | sun4_init: |
1153 | #ifdef CONFIG_SUN4 | ||
1154 | /* There, happy now Adrian? */ | ||
1155 | set cputypval, %o2 ! Let everyone know we | ||
1156 | set ' ', %o0 ! are a "sun4 " architecture | ||
1157 | stb %o0, [%o2 + 0x4] | ||
1158 | |||
1159 | b got_prop | ||
1160 | nop | ||
1161 | #else | ||
1162 | sethi %hi(SUN4_PROM_VECTOR+0x84), %o1 | 1138 | sethi %hi(SUN4_PROM_VECTOR+0x84), %o1 |
1163 | ld [%o1 + %lo(SUN4_PROM_VECTOR+0x84)], %o1 | 1139 | ld [%o1 + %lo(SUN4_PROM_VECTOR+0x84)], %o1 |
1164 | set sun4_notsup, %o0 | 1140 | set sun4_notsup, %o0 |
@@ -1170,7 +1146,7 @@ sun4_init: | |||
1170 | nop | 1146 | nop |
1171 | 1: ba 1b ! Cannot exit into KMON | 1147 | 1: ba 1b ! Cannot exit into KMON |
1172 | nop | 1148 | nop |
1173 | #endif | 1149 | |
1174 | no_sun4e_here: | 1150 | no_sun4e_here: |
1175 | ld [%g7 + 0x68], %o1 | 1151 | ld [%g7 + 0x68], %o1 |
1176 | set sun4e_notsup, %o0 | 1152 | set sun4e_notsup, %o0 |
diff --git a/arch/sparc/kernel/idprom.c b/arch/sparc/kernel/idprom.c index fc511f3c4c18..223a6582e1e2 100644 --- a/arch/sparc/kernel/idprom.c +++ b/arch/sparc/kernel/idprom.c | |||
@@ -12,10 +12,6 @@ | |||
12 | #include <asm/oplib.h> | 12 | #include <asm/oplib.h> |
13 | #include <asm/idprom.h> | 13 | #include <asm/idprom.h> |
14 | #include <asm/machines.h> /* Fun with Sun released architectures. */ | 14 | #include <asm/machines.h> /* Fun with Sun released architectures. */ |
15 | #ifdef CONFIG_SUN4 | ||
16 | #include <asm/sun4paddr.h> | ||
17 | extern void sun4setup(void); | ||
18 | #endif | ||
19 | 15 | ||
20 | struct idprom *idprom; | 16 | struct idprom *idprom; |
21 | static struct idprom idprom_buffer; | 17 | static struct idprom idprom_buffer; |
@@ -101,7 +97,4 @@ void __init idprom_init(void) | |||
101 | idprom->id_ethaddr[0], idprom->id_ethaddr[1], | 97 | idprom->id_ethaddr[0], idprom->id_ethaddr[1], |
102 | idprom->id_ethaddr[2], idprom->id_ethaddr[3], | 98 | idprom->id_ethaddr[2], idprom->id_ethaddr[3], |
103 | idprom->id_ethaddr[4], idprom->id_ethaddr[5]); | 99 | idprom->id_ethaddr[4], idprom->id_ethaddr[5]); |
104 | #ifdef CONFIG_SUN4 | ||
105 | sun4setup(); | ||
106 | #endif | ||
107 | } | 100 | } |
diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c index 2a8a847764d8..4f025b36934b 100644 --- a/arch/sparc/kernel/ioport.c +++ b/arch/sparc/kernel/ioport.c | |||
@@ -42,10 +42,13 @@ | |||
42 | #include <asm/vaddrs.h> | 42 | #include <asm/vaddrs.h> |
43 | #include <asm/oplib.h> | 43 | #include <asm/oplib.h> |
44 | #include <asm/prom.h> | 44 | #include <asm/prom.h> |
45 | #include <asm/sbus.h> | ||
46 | #include <asm/page.h> | 45 | #include <asm/page.h> |
47 | #include <asm/pgalloc.h> | 46 | #include <asm/pgalloc.h> |
48 | #include <asm/dma.h> | 47 | #include <asm/dma.h> |
48 | #include <asm/iommu.h> | ||
49 | #include <asm/io-unit.h> | ||
50 | |||
51 | #include "dma.h" | ||
49 | 52 | ||
50 | #define mmu_inval_dma_area(p, l) /* Anton pulled it out for 2.4.0-xx */ | 53 | #define mmu_inval_dma_area(p, l) /* Anton pulled it out for 2.4.0-xx */ |
51 | 54 | ||
@@ -139,15 +142,6 @@ void iounmap(volatile void __iomem *virtual) | |||
139 | } | 142 | } |
140 | } | 143 | } |
141 | 144 | ||
142 | /* | ||
143 | */ | ||
144 | void __iomem *sbus_ioremap(struct resource *phyres, unsigned long offset, | ||
145 | unsigned long size, char *name) | ||
146 | { | ||
147 | return _sparc_alloc_io(phyres->flags & 0xF, | ||
148 | phyres->start + offset, size, name); | ||
149 | } | ||
150 | |||
151 | void __iomem *of_ioremap(struct resource *res, unsigned long offset, | 145 | void __iomem *of_ioremap(struct resource *res, unsigned long offset, |
152 | unsigned long size, char *name) | 146 | unsigned long size, char *name) |
153 | { | 147 | { |
@@ -164,13 +158,6 @@ void of_iounmap(struct resource *res, void __iomem *base, unsigned long size) | |||
164 | EXPORT_SYMBOL(of_iounmap); | 158 | EXPORT_SYMBOL(of_iounmap); |
165 | 159 | ||
166 | /* | 160 | /* |
167 | */ | ||
168 | void sbus_iounmap(volatile void __iomem *addr, unsigned long size) | ||
169 | { | ||
170 | iounmap(addr); | ||
171 | } | ||
172 | |||
173 | /* | ||
174 | * Meat of mapping | 161 | * Meat of mapping |
175 | */ | 162 | */ |
176 | static void __iomem *_sparc_alloc_io(unsigned int busno, unsigned long phys, | 163 | static void __iomem *_sparc_alloc_io(unsigned int busno, unsigned long phys, |
@@ -246,63 +233,19 @@ static void _sparc_free_io(struct resource *res) | |||
246 | 233 | ||
247 | #ifdef CONFIG_SBUS | 234 | #ifdef CONFIG_SBUS |
248 | 235 | ||
249 | void sbus_set_sbus64(struct sbus_dev *sdev, int x) | 236 | void sbus_set_sbus64(struct device *dev, int x) |
250 | { | 237 | { |
251 | printk("sbus_set_sbus64: unsupported\n"); | 238 | printk("sbus_set_sbus64: unsupported\n"); |
252 | } | 239 | } |
253 | 240 | ||
254 | extern unsigned int sun4d_build_irq(struct sbus_dev *sdev, int irq); | ||
255 | void __init sbus_fill_device_irq(struct sbus_dev *sdev) | ||
256 | { | ||
257 | struct linux_prom_irqs irqs[PROMINTR_MAX]; | ||
258 | int len; | ||
259 | |||
260 | len = prom_getproperty(sdev->prom_node, "intr", | ||
261 | (char *)irqs, sizeof(irqs)); | ||
262 | if (len != -1) { | ||
263 | sdev->num_irqs = len / 8; | ||
264 | if (sdev->num_irqs == 0) { | ||
265 | sdev->irqs[0] = 0; | ||
266 | } else if (sparc_cpu_model == sun4d) { | ||
267 | for (len = 0; len < sdev->num_irqs; len++) | ||
268 | sdev->irqs[len] = | ||
269 | sun4d_build_irq(sdev, irqs[len].pri); | ||
270 | } else { | ||
271 | for (len = 0; len < sdev->num_irqs; len++) | ||
272 | sdev->irqs[len] = irqs[len].pri; | ||
273 | } | ||
274 | } else { | ||
275 | int interrupts[PROMINTR_MAX]; | ||
276 | |||
277 | /* No "intr" node found-- check for "interrupts" node. | ||
278 | * This node contains SBus interrupt levels, not IPLs | ||
279 | * as in "intr", and no vector values. We convert | ||
280 | * SBus interrupt levels to PILs (platform specific). | ||
281 | */ | ||
282 | len = prom_getproperty(sdev->prom_node, "interrupts", | ||
283 | (char *)interrupts, sizeof(interrupts)); | ||
284 | if (len == -1) { | ||
285 | sdev->irqs[0] = 0; | ||
286 | sdev->num_irqs = 0; | ||
287 | } else { | ||
288 | sdev->num_irqs = len / sizeof(int); | ||
289 | for (len = 0; len < sdev->num_irqs; len++) { | ||
290 | sdev->irqs[len] = | ||
291 | sbint_to_irq(sdev, interrupts[len]); | ||
292 | } | ||
293 | } | ||
294 | } | ||
295 | } | ||
296 | |||
297 | /* | 241 | /* |
298 | * Allocate a chunk of memory suitable for DMA. | 242 | * Allocate a chunk of memory suitable for DMA. |
299 | * Typically devices use them for control blocks. | 243 | * Typically devices use them for control blocks. |
300 | * CPU may access them without any explicit flushing. | 244 | * CPU may access them without any explicit flushing. |
301 | * | ||
302 | * XXX Some clever people know that sdev is not used and supply NULL. Watch. | ||
303 | */ | 245 | */ |
304 | void *sbus_alloc_consistent(struct sbus_dev *sdev, long len, u32 *dma_addrp) | 246 | void *sbus_alloc_consistent(struct device *dev, long len, u32 *dma_addrp) |
305 | { | 247 | { |
248 | struct of_device *op = to_of_device(dev); | ||
306 | unsigned long len_total = (len + PAGE_SIZE-1) & PAGE_MASK; | 249 | unsigned long len_total = (len + PAGE_SIZE-1) & PAGE_MASK; |
307 | unsigned long va; | 250 | unsigned long va; |
308 | struct resource *res; | 251 | struct resource *res; |
@@ -336,13 +279,10 @@ void *sbus_alloc_consistent(struct sbus_dev *sdev, long len, u32 *dma_addrp) | |||
336 | * XXX That's where sdev would be used. Currently we load | 279 | * XXX That's where sdev would be used. Currently we load |
337 | * all iommu tables with the same translations. | 280 | * all iommu tables with the same translations. |
338 | */ | 281 | */ |
339 | if (mmu_map_dma_area(dma_addrp, va, res->start, len_total) != 0) | 282 | if (mmu_map_dma_area(dev, dma_addrp, va, res->start, len_total) != 0) |
340 | goto err_noiommu; | 283 | goto err_noiommu; |
341 | 284 | ||
342 | /* Set the resource name, if known. */ | 285 | res->name = op->node->name; |
343 | if (sdev) { | ||
344 | res->name = sdev->prom_name; | ||
345 | } | ||
346 | 286 | ||
347 | return (void *)(unsigned long)res->start; | 287 | return (void *)(unsigned long)res->start; |
348 | 288 | ||
@@ -356,7 +296,7 @@ err_nopages: | |||
356 | return NULL; | 296 | return NULL; |
357 | } | 297 | } |
358 | 298 | ||
359 | void sbus_free_consistent(struct sbus_dev *sdev, long n, void *p, u32 ba) | 299 | void sbus_free_consistent(struct device *dev, long n, void *p, u32 ba) |
360 | { | 300 | { |
361 | struct resource *res; | 301 | struct resource *res; |
362 | struct page *pgv; | 302 | struct page *pgv; |
@@ -383,8 +323,8 @@ void sbus_free_consistent(struct sbus_dev *sdev, long n, void *p, u32 ba) | |||
383 | kfree(res); | 323 | kfree(res); |
384 | 324 | ||
385 | /* mmu_inval_dma_area(va, n); */ /* it's consistent, isn't it */ | 325 | /* mmu_inval_dma_area(va, n); */ /* it's consistent, isn't it */ |
386 | pgv = mmu_translate_dvma(ba); | 326 | pgv = virt_to_page(p); |
387 | mmu_unmap_dma_area(ba, n); | 327 | mmu_unmap_dma_area(dev, ba, n); |
388 | 328 | ||
389 | __free_pages(pgv, get_order(n)); | 329 | __free_pages(pgv, get_order(n)); |
390 | } | 330 | } |
@@ -394,7 +334,7 @@ void sbus_free_consistent(struct sbus_dev *sdev, long n, void *p, u32 ba) | |||
394 | * CPU view of this memory may be inconsistent with | 334 | * CPU view of this memory may be inconsistent with |
395 | * a device view and explicit flushing is necessary. | 335 | * a device view and explicit flushing is necessary. |
396 | */ | 336 | */ |
397 | dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *va, size_t len, int direction) | 337 | dma_addr_t sbus_map_single(struct device *dev, void *va, size_t len, int direction) |
398 | { | 338 | { |
399 | /* XXX why are some lengths signed, others unsigned? */ | 339 | /* XXX why are some lengths signed, others unsigned? */ |
400 | if (len <= 0) { | 340 | if (len <= 0) { |
@@ -404,17 +344,17 @@ dma_addr_t sbus_map_single(struct sbus_dev *sdev, void *va, size_t len, int dire | |||
404 | if (len > 256*1024) { /* __get_free_pages() limit */ | 344 | if (len > 256*1024) { /* __get_free_pages() limit */ |
405 | return 0; | 345 | return 0; |
406 | } | 346 | } |
407 | return mmu_get_scsi_one(va, len, sdev->bus); | 347 | return mmu_get_scsi_one(dev, va, len); |
408 | } | 348 | } |
409 | 349 | ||
410 | void sbus_unmap_single(struct sbus_dev *sdev, dma_addr_t ba, size_t n, int direction) | 350 | void sbus_unmap_single(struct device *dev, dma_addr_t ba, size_t n, int direction) |
411 | { | 351 | { |
412 | mmu_release_scsi_one(ba, n, sdev->bus); | 352 | mmu_release_scsi_one(dev, ba, n); |
413 | } | 353 | } |
414 | 354 | ||
415 | int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction) | 355 | int sbus_map_sg(struct device *dev, struct scatterlist *sg, int n, int direction) |
416 | { | 356 | { |
417 | mmu_get_scsi_sgl(sg, n, sdev->bus); | 357 | mmu_get_scsi_sgl(dev, sg, n); |
418 | 358 | ||
419 | /* | 359 | /* |
420 | * XXX sparc64 can return a partial length here. sun4c should do this | 360 | * XXX sparc64 can return a partial length here. sun4c should do this |
@@ -423,145 +363,28 @@ int sbus_map_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direct | |||
423 | return n; | 363 | return n; |
424 | } | 364 | } |
425 | 365 | ||
426 | void sbus_unmap_sg(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction) | 366 | void sbus_unmap_sg(struct device *dev, struct scatterlist *sg, int n, int direction) |
427 | { | ||
428 | mmu_release_scsi_sgl(sg, n, sdev->bus); | ||
429 | } | ||
430 | |||
431 | /* | ||
432 | */ | ||
433 | void sbus_dma_sync_single_for_cpu(struct sbus_dev *sdev, dma_addr_t ba, size_t size, int direction) | ||
434 | { | ||
435 | #if 0 | ||
436 | unsigned long va; | ||
437 | struct resource *res; | ||
438 | |||
439 | /* We do not need the resource, just print a message if invalid. */ | ||
440 | res = _sparc_find_resource(&_sparc_dvma, ba); | ||
441 | if (res == NULL) | ||
442 | panic("sbus_dma_sync_single: 0x%x\n", ba); | ||
443 | |||
444 | va = page_address(mmu_translate_dvma(ba)); /* XXX higmem */ | ||
445 | /* | ||
446 | * XXX This bogosity will be fixed with the iommu rewrite coming soon | ||
447 | * to a kernel near you. - Anton | ||
448 | */ | ||
449 | /* mmu_inval_dma_area(va, (size + PAGE_SIZE-1) & PAGE_MASK); */ | ||
450 | #endif | ||
451 | } | ||
452 | |||
453 | void sbus_dma_sync_single_for_device(struct sbus_dev *sdev, dma_addr_t ba, size_t size, int direction) | ||
454 | { | 367 | { |
455 | #if 0 | 368 | mmu_release_scsi_sgl(dev, sg, n); |
456 | unsigned long va; | ||
457 | struct resource *res; | ||
458 | |||
459 | /* We do not need the resource, just print a message if invalid. */ | ||
460 | res = _sparc_find_resource(&_sparc_dvma, ba); | ||
461 | if (res == NULL) | ||
462 | panic("sbus_dma_sync_single: 0x%x\n", ba); | ||
463 | |||
464 | va = page_address(mmu_translate_dvma(ba)); /* XXX higmem */ | ||
465 | /* | ||
466 | * XXX This bogosity will be fixed with the iommu rewrite coming soon | ||
467 | * to a kernel near you. - Anton | ||
468 | */ | ||
469 | /* mmu_inval_dma_area(va, (size + PAGE_SIZE-1) & PAGE_MASK); */ | ||
470 | #endif | ||
471 | } | 369 | } |
472 | 370 | ||
473 | void sbus_dma_sync_sg_for_cpu(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction) | 371 | void sbus_dma_sync_single_for_cpu(struct device *dev, dma_addr_t ba, size_t size, int direction) |
474 | { | 372 | { |
475 | printk("sbus_dma_sync_sg_for_cpu: not implemented yet\n"); | ||
476 | } | 373 | } |
477 | 374 | ||
478 | void sbus_dma_sync_sg_for_device(struct sbus_dev *sdev, struct scatterlist *sg, int n, int direction) | 375 | void sbus_dma_sync_single_for_device(struct device *dev, dma_addr_t ba, size_t size, int direction) |
479 | { | 376 | { |
480 | printk("sbus_dma_sync_sg_for_device: not implemented yet\n"); | ||
481 | } | ||
482 | |||
483 | /* Support code for sbus_init(). */ | ||
484 | /* | ||
485 | * XXX This functions appears to be a distorted version of | ||
486 | * prom_sbus_ranges_init(), with all sun4d stuff cut away. | ||
487 | * Ask DaveM what is going on here, how is sun4d supposed to work... XXX | ||
488 | */ | ||
489 | /* added back sun4d patch from Thomas Bogendoerfer - should be OK (crn) */ | ||
490 | void __init sbus_arch_bus_ranges_init(struct device_node *pn, struct sbus_bus *sbus) | ||
491 | { | ||
492 | int parent_node = pn->node; | ||
493 | |||
494 | if (sparc_cpu_model == sun4d) { | ||
495 | struct linux_prom_ranges iounit_ranges[PROMREG_MAX]; | ||
496 | int num_iounit_ranges, len; | ||
497 | |||
498 | len = prom_getproperty(parent_node, "ranges", | ||
499 | (char *) iounit_ranges, | ||
500 | sizeof (iounit_ranges)); | ||
501 | if (len != -1) { | ||
502 | num_iounit_ranges = | ||
503 | (len / sizeof(struct linux_prom_ranges)); | ||
504 | prom_adjust_ranges(sbus->sbus_ranges, | ||
505 | sbus->num_sbus_ranges, | ||
506 | iounit_ranges, num_iounit_ranges); | ||
507 | } | ||
508 | } | ||
509 | } | 377 | } |
510 | 378 | ||
511 | void __init sbus_setup_iommu(struct sbus_bus *sbus, struct device_node *dp) | 379 | static int __init sparc_register_ioport(void) |
512 | { | ||
513 | #ifndef CONFIG_SUN4 | ||
514 | struct device_node *parent = dp->parent; | ||
515 | |||
516 | if (sparc_cpu_model != sun4d && | ||
517 | parent != NULL && | ||
518 | !strcmp(parent->name, "iommu")) { | ||
519 | extern void iommu_init(int iommu_node, struct sbus_bus *sbus); | ||
520 | |||
521 | iommu_init(parent->node, sbus); | ||
522 | } | ||
523 | |||
524 | if (sparc_cpu_model == sun4d) { | ||
525 | extern void iounit_init(int sbi_node, int iounit_node, | ||
526 | struct sbus_bus *sbus); | ||
527 | |||
528 | iounit_init(dp->node, parent->node, sbus); | ||
529 | } | ||
530 | #endif | ||
531 | } | ||
532 | |||
533 | void __init sbus_setup_arch_props(struct sbus_bus *sbus, struct device_node *dp) | ||
534 | { | ||
535 | if (sparc_cpu_model == sun4d) { | ||
536 | struct device_node *parent = dp->parent; | ||
537 | |||
538 | sbus->devid = of_getintprop_default(parent, "device-id", 0); | ||
539 | sbus->board = of_getintprop_default(parent, "board#", 0); | ||
540 | } | ||
541 | } | ||
542 | |||
543 | int __init sbus_arch_preinit(void) | ||
544 | { | 380 | { |
545 | register_proc_sparc_ioport(); | 381 | register_proc_sparc_ioport(); |
546 | 382 | ||
547 | #ifdef CONFIG_SUN4 | ||
548 | { | ||
549 | extern void sun4_dvma_init(void); | ||
550 | sun4_dvma_init(); | ||
551 | } | ||
552 | return 1; | ||
553 | #else | ||
554 | return 0; | 383 | return 0; |
555 | #endif | ||
556 | } | 384 | } |
557 | 385 | ||
558 | void __init sbus_arch_postinit(void) | 386 | arch_initcall(sparc_register_ioport); |
559 | { | 387 | |
560 | if (sparc_cpu_model == sun4d) { | ||
561 | extern void sun4d_init_sbi_irq(void); | ||
562 | sun4d_init_sbi_irq(); | ||
563 | } | ||
564 | } | ||
565 | #endif /* CONFIG_SBUS */ | 388 | #endif /* CONFIG_SBUS */ |
566 | 389 | ||
567 | #ifdef CONFIG_PCI | 390 | #ifdef CONFIG_PCI |
diff --git a/arch/sparc/kernel/irq.h b/arch/sparc/kernel/irq.h index 32ef3ebd0a88..db7513881530 100644 --- a/arch/sparc/kernel/irq.h +++ b/arch/sparc/kernel/irq.h | |||
@@ -13,7 +13,6 @@ BTFIXUPDEF_CALL(void, enable_irq, unsigned int) | |||
13 | BTFIXUPDEF_CALL(void, disable_pil_irq, unsigned int) | 13 | BTFIXUPDEF_CALL(void, disable_pil_irq, unsigned int) |
14 | BTFIXUPDEF_CALL(void, enable_pil_irq, unsigned int) | 14 | BTFIXUPDEF_CALL(void, enable_pil_irq, unsigned int) |
15 | BTFIXUPDEF_CALL(void, clear_clock_irq, void) | 15 | BTFIXUPDEF_CALL(void, clear_clock_irq, void) |
16 | BTFIXUPDEF_CALL(void, clear_profile_irq, int) | ||
17 | BTFIXUPDEF_CALL(void, load_profile_irq, int, unsigned int) | 16 | BTFIXUPDEF_CALL(void, load_profile_irq, int, unsigned int) |
18 | 17 | ||
19 | static inline void __disable_irq(unsigned int irq) | 18 | static inline void __disable_irq(unsigned int irq) |
@@ -41,11 +40,6 @@ static inline void clear_clock_irq(void) | |||
41 | BTFIXUP_CALL(clear_clock_irq)(); | 40 | BTFIXUP_CALL(clear_clock_irq)(); |
42 | } | 41 | } |
43 | 42 | ||
44 | static inline void clear_profile_irq(int irq) | ||
45 | { | ||
46 | BTFIXUP_CALL(clear_profile_irq)(irq); | ||
47 | } | ||
48 | |||
49 | static inline void load_profile_irq(int cpu, int limit) | 43 | static inline void load_profile_irq(int cpu, int limit) |
50 | { | 44 | { |
51 | BTFIXUP_CALL(load_profile_irq)(cpu, limit); | 45 | BTFIXUP_CALL(load_profile_irq)(cpu, limit); |
diff --git a/arch/sparc/kernel/of_device.c b/arch/sparc/kernel/of_device.c index c481d45f97b7..0837bd52e28f 100644 --- a/arch/sparc/kernel/of_device.c +++ b/arch/sparc/kernel/of_device.c | |||
@@ -29,15 +29,38 @@ struct of_device *of_find_device_by_node(struct device_node *dp) | |||
29 | } | 29 | } |
30 | EXPORT_SYMBOL(of_find_device_by_node); | 30 | EXPORT_SYMBOL(of_find_device_by_node); |
31 | 31 | ||
32 | #ifdef CONFIG_PCI | 32 | unsigned int irq_of_parse_and_map(struct device_node *node, int index) |
33 | struct bus_type ebus_bus_type; | 33 | { |
34 | EXPORT_SYMBOL(ebus_bus_type); | 34 | struct of_device *op = of_find_device_by_node(node); |
35 | #endif | 35 | |
36 | if (!op || index >= op->num_irqs) | ||
37 | return 0; | ||
38 | |||
39 | return op->irqs[index]; | ||
40 | } | ||
41 | EXPORT_SYMBOL(irq_of_parse_and_map); | ||
42 | |||
43 | /* Take the archdata values for IOMMU, STC, and HOSTDATA found in | ||
44 | * BUS and propagate to all child of_device objects. | ||
45 | */ | ||
46 | void of_propagate_archdata(struct of_device *bus) | ||
47 | { | ||
48 | struct dev_archdata *bus_sd = &bus->dev.archdata; | ||
49 | struct device_node *bus_dp = bus->node; | ||
50 | struct device_node *dp; | ||
51 | |||
52 | for (dp = bus_dp->child; dp; dp = dp->sibling) { | ||
53 | struct of_device *op = of_find_device_by_node(dp); | ||
36 | 54 | ||
37 | #ifdef CONFIG_SBUS | 55 | op->dev.archdata.iommu = bus_sd->iommu; |
38 | struct bus_type sbus_bus_type; | 56 | op->dev.archdata.stc = bus_sd->stc; |
39 | EXPORT_SYMBOL(sbus_bus_type); | 57 | op->dev.archdata.host_controller = bus_sd->host_controller; |
40 | #endif | 58 | op->dev.archdata.numa_node = bus_sd->numa_node; |
59 | |||
60 | if (dp->child) | ||
61 | of_propagate_archdata(op); | ||
62 | } | ||
63 | } | ||
41 | 64 | ||
42 | struct bus_type of_platform_bus_type; | 65 | struct bus_type of_platform_bus_type; |
43 | EXPORT_SYMBOL(of_platform_bus_type); | 66 | EXPORT_SYMBOL(of_platform_bus_type); |
@@ -241,7 +264,7 @@ static int of_bus_sbus_map(u32 *addr, const u32 *range, int na, int ns, int pna) | |||
241 | return of_bus_default_map(addr, range, na, ns, pna); | 264 | return of_bus_default_map(addr, range, na, ns, pna); |
242 | } | 265 | } |
243 | 266 | ||
244 | static unsigned int of_bus_sbus_get_flags(const u32 *addr) | 267 | static unsigned long of_bus_sbus_get_flags(const u32 *addr, unsigned long flags) |
245 | { | 268 | { |
246 | return IORESOURCE_MEM; | 269 | return IORESOURCE_MEM; |
247 | } | 270 | } |
@@ -327,6 +350,27 @@ static int __init build_one_resource(struct device_node *parent, | |||
327 | return 1; | 350 | return 1; |
328 | } | 351 | } |
329 | 352 | ||
353 | static int __init use_1to1_mapping(struct device_node *pp) | ||
354 | { | ||
355 | /* If we have a ranges property in the parent, use it. */ | ||
356 | if (of_find_property(pp, "ranges", NULL) != NULL) | ||
357 | return 0; | ||
358 | |||
359 | /* Some SBUS devices use intermediate nodes to express | ||
360 | * hierarchy within the device itself. These aren't | ||
361 | * real bus nodes, and don't have a 'ranges' property. | ||
362 | * But, we should still pass the translation work up | ||
363 | * to the SBUS itself. | ||
364 | */ | ||
365 | if (!strcmp(pp->name, "dma") || | ||
366 | !strcmp(pp->name, "espdma") || | ||
367 | !strcmp(pp->name, "ledma") || | ||
368 | !strcmp(pp->name, "lebuffer")) | ||
369 | return 0; | ||
370 | |||
371 | return 1; | ||
372 | } | ||
373 | |||
330 | static int of_resource_verbose; | 374 | static int of_resource_verbose; |
331 | 375 | ||
332 | static void __init build_device_resources(struct of_device *op, | 376 | static void __init build_device_resources(struct of_device *op, |
@@ -373,10 +417,7 @@ static void __init build_device_resources(struct of_device *op, | |||
373 | 417 | ||
374 | flags = bus->get_flags(reg, 0); | 418 | flags = bus->get_flags(reg, 0); |
375 | 419 | ||
376 | /* If the immediate parent has no ranges property to apply, | 420 | if (use_1to1_mapping(pp)) { |
377 | * just use a 1<->1 mapping. | ||
378 | */ | ||
379 | if (of_find_property(pp, "ranges", NULL) == NULL) { | ||
380 | result = of_read_addr(addr, na); | 421 | result = of_read_addr(addr, na); |
381 | goto build_res; | 422 | goto build_res; |
382 | } | 423 | } |
@@ -565,15 +606,6 @@ static int __init of_bus_driver_init(void) | |||
565 | int err; | 606 | int err; |
566 | 607 | ||
567 | err = of_bus_type_init(&of_platform_bus_type, "of"); | 608 | err = of_bus_type_init(&of_platform_bus_type, "of"); |
568 | #ifdef CONFIG_PCI | ||
569 | if (!err) | ||
570 | err = of_bus_type_init(&ebus_bus_type, "ebus"); | ||
571 | #endif | ||
572 | #ifdef CONFIG_SBUS | ||
573 | if (!err) | ||
574 | err = of_bus_type_init(&sbus_bus_type, "sbus"); | ||
575 | #endif | ||
576 | |||
577 | if (!err) | 609 | if (!err) |
578 | scan_of_devices(); | 610 | scan_of_devices(); |
579 | 611 | ||
diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c index a6a6f9823370..462584e55fba 100644 --- a/arch/sparc/kernel/pcic.c +++ b/arch/sparc/kernel/pcic.c | |||
@@ -17,8 +17,6 @@ | |||
17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
18 | #include <linux/jiffies.h> | 18 | #include <linux/jiffies.h> |
19 | 19 | ||
20 | #include <asm/ebus.h> | ||
21 | #include <asm/sbus.h> /* for sanity check... */ | ||
22 | #include <asm/swift.h> /* for cache flushing. */ | 20 | #include <asm/swift.h> /* for cache flushing. */ |
23 | #include <asm/io.h> | 21 | #include <asm/io.h> |
24 | 22 | ||
@@ -430,7 +428,6 @@ static int __init pcic_init(void) | |||
430 | 428 | ||
431 | pcic_pbm_scan_bus(pcic); | 429 | pcic_pbm_scan_bus(pcic); |
432 | 430 | ||
433 | ebus_init(); | ||
434 | return 0; | 431 | return 0; |
435 | } | 432 | } |
436 | 433 | ||
@@ -493,10 +490,6 @@ static void pcic_map_pci_device(struct linux_pcic *pcic, | |||
493 | * do ioremap() before accessing PC-style I/O, | 490 | * do ioremap() before accessing PC-style I/O, |
494 | * we supply virtual, ready to access address. | 491 | * we supply virtual, ready to access address. |
495 | * | 492 | * |
496 | * Ebus devices do not come here even if | ||
497 | * CheerIO makes a similar conversion. | ||
498 | * See ebus.c for details. | ||
499 | * | ||
500 | * Note that request_region() | 493 | * Note that request_region() |
501 | * works for these devices. | 494 | * works for these devices. |
502 | * | 495 | * |
@@ -677,7 +670,7 @@ void __devinit pcibios_fixup_bus(struct pci_bus *bus) | |||
677 | } | 670 | } |
678 | 671 | ||
679 | /* | 672 | /* |
680 | * pcic_pin_to_irq() is exported to ebus.c. | 673 | * pcic_pin_to_irq() is exported to bus probing code |
681 | */ | 674 | */ |
682 | unsigned int | 675 | unsigned int |
683 | pcic_pin_to_irq(unsigned int pin, const char *name) | 676 | pcic_pin_to_irq(unsigned int pin, const char *name) |
@@ -904,11 +897,6 @@ static void pcic_enable_irq(unsigned int irq_nr) | |||
904 | local_irq_restore(flags); | 897 | local_irq_restore(flags); |
905 | } | 898 | } |
906 | 899 | ||
907 | static void pcic_clear_profile_irq(int cpu) | ||
908 | { | ||
909 | printk("PCIC: unimplemented code: FILE=%s LINE=%d", __FILE__, __LINE__); | ||
910 | } | ||
911 | |||
912 | static void pcic_load_profile_irq(int cpu, unsigned int limit) | 900 | static void pcic_load_profile_irq(int cpu, unsigned int limit) |
913 | { | 901 | { |
914 | printk("PCIC: unimplemented code: FILE=%s LINE=%d", __FILE__, __LINE__); | 902 | printk("PCIC: unimplemented code: FILE=%s LINE=%d", __FILE__, __LINE__); |
@@ -934,7 +922,6 @@ void __init sun4m_pci_init_IRQ(void) | |||
934 | BTFIXUPSET_CALL(enable_pil_irq, pcic_enable_pil_irq, BTFIXUPCALL_NORM); | 922 | BTFIXUPSET_CALL(enable_pil_irq, pcic_enable_pil_irq, BTFIXUPCALL_NORM); |
935 | BTFIXUPSET_CALL(disable_pil_irq, pcic_disable_pil_irq, BTFIXUPCALL_NORM); | 923 | BTFIXUPSET_CALL(disable_pil_irq, pcic_disable_pil_irq, BTFIXUPCALL_NORM); |
936 | BTFIXUPSET_CALL(clear_clock_irq, pcic_clear_clock_irq, BTFIXUPCALL_NORM); | 924 | BTFIXUPSET_CALL(clear_clock_irq, pcic_clear_clock_irq, BTFIXUPCALL_NORM); |
937 | BTFIXUPSET_CALL(clear_profile_irq, pcic_clear_profile_irq, BTFIXUPCALL_NORM); | ||
938 | BTFIXUPSET_CALL(load_profile_irq, pcic_load_profile_irq, BTFIXUPCALL_NORM); | 925 | BTFIXUPSET_CALL(load_profile_irq, pcic_load_profile_irq, BTFIXUPCALL_NORM); |
939 | } | 926 | } |
940 | 927 | ||
diff --git a/arch/sparc/kernel/pmc.c b/arch/sparc/kernel/pmc.c index 7eca8871ff47..2afcfab4f11c 100644 --- a/arch/sparc/kernel/pmc.c +++ b/arch/sparc/kernel/pmc.c | |||
@@ -8,11 +8,11 @@ | |||
8 | #include <linux/fs.h> | 8 | #include <linux/fs.h> |
9 | #include <linux/errno.h> | 9 | #include <linux/errno.h> |
10 | #include <linux/init.h> | 10 | #include <linux/init.h> |
11 | #include <linux/miscdevice.h> | ||
12 | #include <linux/pm.h> | 11 | #include <linux/pm.h> |
12 | #include <linux/of.h> | ||
13 | #include <linux/of_device.h> | ||
13 | 14 | ||
14 | #include <asm/io.h> | 15 | #include <asm/io.h> |
15 | #include <asm/sbus.h> | ||
16 | #include <asm/oplib.h> | 16 | #include <asm/oplib.h> |
17 | #include <asm/uaccess.h> | 17 | #include <asm/uaccess.h> |
18 | #include <asm/auxio.h> | 18 | #include <asm/auxio.h> |
@@ -23,17 +23,15 @@ | |||
23 | * #define PMC_NO_IDLE | 23 | * #define PMC_NO_IDLE |
24 | */ | 24 | */ |
25 | 25 | ||
26 | #define PMC_MINOR MISC_DYNAMIC_MINOR | ||
27 | #define PMC_OBPNAME "SUNW,pmc" | 26 | #define PMC_OBPNAME "SUNW,pmc" |
28 | #define PMC_DEVNAME "pmc" | 27 | #define PMC_DEVNAME "pmc" |
29 | 28 | ||
30 | #define PMC_IDLE_REG 0x00 | 29 | #define PMC_IDLE_REG 0x00 |
31 | #define PMC_IDLE_ON 0x01 | 30 | #define PMC_IDLE_ON 0x01 |
32 | 31 | ||
33 | volatile static u8 __iomem *regs; | 32 | static u8 __iomem *regs; |
34 | static int pmc_regsize; | ||
35 | 33 | ||
36 | #define pmc_readb(offs) (sbus_readb(regs+offs)) | 34 | #define pmc_readb(offs) (sbus_readb(regs+offs)) |
37 | #define pmc_writeb(val, offs) (sbus_writeb(val, regs+offs)) | 35 | #define pmc_writeb(val, offs) (sbus_writeb(val, regs+offs)) |
38 | 36 | ||
39 | /* | 37 | /* |
@@ -53,31 +51,11 @@ void pmc_swift_idle(void) | |||
53 | #endif | 51 | #endif |
54 | } | 52 | } |
55 | 53 | ||
56 | static inline void pmc_free(void) | 54 | static int __devinit pmc_probe(struct of_device *op, |
55 | const struct of_device_id *match) | ||
57 | { | 56 | { |
58 | sbus_iounmap(regs, pmc_regsize); | 57 | regs = of_ioremap(&op->resource[0], 0, |
59 | } | 58 | resource_size(&op->resource[0]), PMC_OBPNAME); |
60 | |||
61 | static int __init pmc_probe(void) | ||
62 | { | ||
63 | struct sbus_bus *sbus = NULL; | ||
64 | struct sbus_dev *sdev = NULL; | ||
65 | for_each_sbus(sbus) { | ||
66 | for_each_sbusdev(sdev, sbus) { | ||
67 | if (!strcmp(sdev->prom_name, PMC_OBPNAME)) { | ||
68 | goto sbus_done; | ||
69 | } | ||
70 | } | ||
71 | } | ||
72 | |||
73 | sbus_done: | ||
74 | if (!sdev) { | ||
75 | return -ENODEV; | ||
76 | } | ||
77 | |||
78 | pmc_regsize = sdev->reg_addrs[0].reg_size; | ||
79 | regs = sbus_ioremap(&sdev->resource[0], 0, | ||
80 | pmc_regsize, PMC_OBPNAME); | ||
81 | if (!regs) { | 59 | if (!regs) { |
82 | printk(KERN_ERR "%s: unable to map registers\n", PMC_DEVNAME); | 60 | printk(KERN_ERR "%s: unable to map registers\n", PMC_DEVNAME); |
83 | return -ENODEV; | 61 | return -ENODEV; |
@@ -92,8 +70,27 @@ sbus_done: | |||
92 | return 0; | 70 | return 0; |
93 | } | 71 | } |
94 | 72 | ||
73 | static struct of_device_id __initdata pmc_match[] = { | ||
74 | { | ||
75 | .name = PMC_OBPNAME, | ||
76 | }, | ||
77 | {}, | ||
78 | }; | ||
79 | MODULE_DEVICE_TABLE(of, pmc_match); | ||
80 | |||
81 | static struct of_platform_driver pmc_driver = { | ||
82 | .name = "pmc", | ||
83 | .match_table = pmc_match, | ||
84 | .probe = pmc_probe, | ||
85 | }; | ||
86 | |||
87 | static int __init pmc_init(void) | ||
88 | { | ||
89 | return of_register_driver(&pmc_driver, &of_bus_type); | ||
90 | } | ||
91 | |||
95 | /* This driver is not critical to the boot process | 92 | /* This driver is not critical to the boot process |
96 | * and is easiest to ioremap when SBus is already | 93 | * and is easiest to ioremap when SBus is already |
97 | * initialized, so we install ourselves thusly: | 94 | * initialized, so we install ourselves thusly: |
98 | */ | 95 | */ |
99 | __initcall(pmc_probe); | 96 | __initcall(pmc_init); |
diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c index 4bb430940a61..e8c43ffe317e 100644 --- a/arch/sparc/kernel/process.c +++ b/arch/sparc/kernel/process.c | |||
@@ -75,7 +75,7 @@ void cpu_idle(void) | |||
75 | { | 75 | { |
76 | /* endless idle loop with no priority at all */ | 76 | /* endless idle loop with no priority at all */ |
77 | for (;;) { | 77 | for (;;) { |
78 | if (ARCH_SUN4C_SUN4) { | 78 | if (ARCH_SUN4C) { |
79 | static int count = HZ; | 79 | static int count = HZ; |
80 | static unsigned long last_jiffies; | 80 | static unsigned long last_jiffies; |
81 | static unsigned long last_faults; | 81 | static unsigned long last_faults; |
diff --git a/arch/sparc/kernel/prom.c b/arch/sparc/kernel/prom.c index cd4fb79aa3a8..eee5efcfe50e 100644 --- a/arch/sparc/kernel/prom.c +++ b/arch/sparc/kernel/prom.c | |||
@@ -54,6 +54,9 @@ int of_getintprop_default(struct device_node *np, const char *name, int def) | |||
54 | } | 54 | } |
55 | EXPORT_SYMBOL(of_getintprop_default); | 55 | EXPORT_SYMBOL(of_getintprop_default); |
56 | 56 | ||
57 | DEFINE_MUTEX(of_set_property_mutex); | ||
58 | EXPORT_SYMBOL(of_set_property_mutex); | ||
59 | |||
57 | int of_set_property(struct device_node *dp, const char *name, void *val, int len) | 60 | int of_set_property(struct device_node *dp, const char *name, void *val, int len) |
58 | { | 61 | { |
59 | struct property **prevp; | 62 | struct property **prevp; |
@@ -77,7 +80,10 @@ int of_set_property(struct device_node *dp, const char *name, void *val, int len | |||
77 | void *old_val = prop->value; | 80 | void *old_val = prop->value; |
78 | int ret; | 81 | int ret; |
79 | 82 | ||
83 | mutex_lock(&of_set_property_mutex); | ||
80 | ret = prom_setprop(dp->node, (char *) name, val, len); | 84 | ret = prom_setprop(dp->node, (char *) name, val, len); |
85 | mutex_unlock(&of_set_property_mutex); | ||
86 | |||
81 | err = -EINVAL; | 87 | err = -EINVAL; |
82 | if (ret >= 0) { | 88 | if (ret >= 0) { |
83 | prop->value = new_val; | 89 | prop->value = new_val; |
@@ -436,7 +442,6 @@ static void __init of_console_init(void) | |||
436 | 442 | ||
437 | switch (prom_vers) { | 443 | switch (prom_vers) { |
438 | case PROM_V0: | 444 | case PROM_V0: |
439 | case PROM_SUN4: | ||
440 | skip = 0; | 445 | skip = 0; |
441 | switch (*romvec->pv_stdout) { | 446 | switch (*romvec->pv_stdout) { |
442 | case PROMDEV_SCREEN: | 447 | case PROMDEV_SCREEN: |
diff --git a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c index 20699c701412..8ce6285a06d5 100644 --- a/arch/sparc/kernel/ptrace.c +++ b/arch/sparc/kernel/ptrace.c | |||
@@ -288,7 +288,7 @@ static const struct user_regset sparc32_regsets[] = { | |||
288 | */ | 288 | */ |
289 | [REGSET_GENERAL] = { | 289 | [REGSET_GENERAL] = { |
290 | .core_note_type = NT_PRSTATUS, | 290 | .core_note_type = NT_PRSTATUS, |
291 | .n = 38 * sizeof(u32), | 291 | .n = 38, |
292 | .size = sizeof(u32), .align = sizeof(u32), | 292 | .size = sizeof(u32), .align = sizeof(u32), |
293 | .get = genregs32_get, .set = genregs32_set | 293 | .get = genregs32_get, .set = genregs32_set |
294 | }, | 294 | }, |
@@ -304,7 +304,7 @@ static const struct user_regset sparc32_regsets[] = { | |||
304 | */ | 304 | */ |
305 | [REGSET_FP] = { | 305 | [REGSET_FP] = { |
306 | .core_note_type = NT_PRFPREG, | 306 | .core_note_type = NT_PRFPREG, |
307 | .n = 99 * sizeof(u32), | 307 | .n = 99, |
308 | .size = sizeof(u32), .align = sizeof(u32), | 308 | .size = sizeof(u32), .align = sizeof(u32), |
309 | .get = fpregs32_get, .set = fpregs32_set | 309 | .get = fpregs32_get, .set = fpregs32_set |
310 | }, | 310 | }, |
diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c index 9e451b21202e..24fe3078bd4b 100644 --- a/arch/sparc/kernel/setup.c +++ b/arch/sparc/kernel/setup.c | |||
@@ -213,23 +213,25 @@ void __init setup_arch(char **cmdline_p) | |||
213 | /* Initialize PROM console and command line. */ | 213 | /* Initialize PROM console and command line. */ |
214 | *cmdline_p = prom_getbootargs(); | 214 | *cmdline_p = prom_getbootargs(); |
215 | strcpy(boot_command_line, *cmdline_p); | 215 | strcpy(boot_command_line, *cmdline_p); |
216 | parse_early_param(); | ||
216 | 217 | ||
217 | /* Set sparc_cpu_model */ | 218 | /* Set sparc_cpu_model */ |
218 | sparc_cpu_model = sun_unknown; | 219 | sparc_cpu_model = sun_unknown; |
219 | if(!strcmp(&cputypval,"sun4 ")) { sparc_cpu_model=sun4; } | 220 | if (!strcmp(&cputypval,"sun4 ")) |
220 | if(!strcmp(&cputypval,"sun4c")) { sparc_cpu_model=sun4c; } | 221 | sparc_cpu_model = sun4; |
221 | if(!strcmp(&cputypval,"sun4m")) { sparc_cpu_model=sun4m; } | 222 | if (!strcmp(&cputypval,"sun4c")) |
222 | if(!strcmp(&cputypval,"sun4s")) { sparc_cpu_model=sun4m; } /* CP-1200 with PROM 2.30 -E */ | 223 | sparc_cpu_model = sun4c; |
223 | if(!strcmp(&cputypval,"sun4d")) { sparc_cpu_model=sun4d; } | 224 | if (!strcmp(&cputypval,"sun4m")) |
224 | if(!strcmp(&cputypval,"sun4e")) { sparc_cpu_model=sun4e; } | 225 | sparc_cpu_model = sun4m; |
225 | if(!strcmp(&cputypval,"sun4u")) { sparc_cpu_model=sun4u; } | 226 | if (!strcmp(&cputypval,"sun4s")) |
226 | 227 | sparc_cpu_model = sun4m; /* CP-1200 with PROM 2.30 -E */ | |
227 | #ifdef CONFIG_SUN4 | 228 | if (!strcmp(&cputypval,"sun4d")) |
228 | if (sparc_cpu_model != sun4) { | 229 | sparc_cpu_model = sun4d; |
229 | prom_printf("This kernel is for Sun4 architecture only.\n"); | 230 | if (!strcmp(&cputypval,"sun4e")) |
230 | prom_halt(); | 231 | sparc_cpu_model = sun4e; |
231 | } | 232 | if (!strcmp(&cputypval,"sun4u")) |
232 | #endif | 233 | sparc_cpu_model = sun4u; |
234 | |||
233 | printk("ARCH: "); | 235 | printk("ARCH: "); |
234 | switch(sparc_cpu_model) { | 236 | switch(sparc_cpu_model) { |
235 | case sun4: | 237 | case sun4: |
@@ -263,7 +265,7 @@ void __init setup_arch(char **cmdline_p) | |||
263 | boot_flags_init(*cmdline_p); | 265 | boot_flags_init(*cmdline_p); |
264 | 266 | ||
265 | idprom_init(); | 267 | idprom_init(); |
266 | if (ARCH_SUN4C_SUN4) | 268 | if (ARCH_SUN4C) |
267 | sun4c_probe_vac(); | 269 | sun4c_probe_vac(); |
268 | load_mmu(); | 270 | load_mmu(); |
269 | 271 | ||
diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c index b23cea5ca5d1..b0dfff848653 100644 --- a/arch/sparc/kernel/sparc_ksyms.c +++ b/arch/sparc/kernel/sparc_ksyms.c | |||
@@ -38,17 +38,12 @@ | |||
38 | #include <asm/idprom.h> | 38 | #include <asm/idprom.h> |
39 | #include <asm/head.h> | 39 | #include <asm/head.h> |
40 | #include <asm/smp.h> | 40 | #include <asm/smp.h> |
41 | #include <asm/mostek.h> | ||
42 | #include <asm/ptrace.h> | 41 | #include <asm/ptrace.h> |
43 | #include <asm/uaccess.h> | 42 | #include <asm/uaccess.h> |
44 | #include <asm/checksum.h> | 43 | #include <asm/checksum.h> |
45 | #ifdef CONFIG_SBUS | 44 | #ifdef CONFIG_SBUS |
46 | #include <asm/sbus.h> | ||
47 | #include <asm/dma.h> | 45 | #include <asm/dma.h> |
48 | #endif | 46 | #endif |
49 | #ifdef CONFIG_PCI | ||
50 | #include <asm/ebus.h> | ||
51 | #endif | ||
52 | #include <asm/io-unit.h> | 47 | #include <asm/io-unit.h> |
53 | #include <asm/bug.h> | 48 | #include <asm/bug.h> |
54 | 49 | ||
@@ -127,16 +122,11 @@ EXPORT_SYMBOL(phys_cpu_present_map); | |||
127 | EXPORT_SYMBOL(__udelay); | 122 | EXPORT_SYMBOL(__udelay); |
128 | EXPORT_SYMBOL(__ndelay); | 123 | EXPORT_SYMBOL(__ndelay); |
129 | EXPORT_SYMBOL(rtc_lock); | 124 | EXPORT_SYMBOL(rtc_lock); |
130 | EXPORT_SYMBOL(mostek_lock); | ||
131 | EXPORT_SYMBOL(mstk48t02_regs); | ||
132 | #ifdef CONFIG_SUN_AUXIO | 125 | #ifdef CONFIG_SUN_AUXIO |
133 | EXPORT_SYMBOL(set_auxio); | 126 | EXPORT_SYMBOL(set_auxio); |
134 | EXPORT_SYMBOL(get_auxio); | 127 | EXPORT_SYMBOL(get_auxio); |
135 | #endif | 128 | #endif |
136 | EXPORT_SYMBOL(io_remap_pfn_range); | 129 | EXPORT_SYMBOL(io_remap_pfn_range); |
137 | /* P3: iounit_xxx may be needed, sun4d users */ | ||
138 | /* EXPORT_SYMBOL(iounit_map_dma_init); */ | ||
139 | /* EXPORT_SYMBOL(iounit_map_dma_page); */ | ||
140 | 130 | ||
141 | #ifndef CONFIG_SMP | 131 | #ifndef CONFIG_SMP |
142 | EXPORT_SYMBOL(BTFIXUP_CALL(___xchg32)); | 132 | EXPORT_SYMBOL(BTFIXUP_CALL(___xchg32)); |
@@ -153,24 +143,9 @@ EXPORT_SYMBOL(BTFIXUP_CALL(mmu_release_scsi_one)); | |||
153 | EXPORT_SYMBOL(BTFIXUP_CALL(pgprot_noncached)); | 143 | EXPORT_SYMBOL(BTFIXUP_CALL(pgprot_noncached)); |
154 | 144 | ||
155 | #ifdef CONFIG_SBUS | 145 | #ifdef CONFIG_SBUS |
156 | EXPORT_SYMBOL(sbus_root); | ||
157 | EXPORT_SYMBOL(dma_chain); | ||
158 | EXPORT_SYMBOL(sbus_set_sbus64); | 146 | EXPORT_SYMBOL(sbus_set_sbus64); |
159 | EXPORT_SYMBOL(sbus_alloc_consistent); | ||
160 | EXPORT_SYMBOL(sbus_free_consistent); | ||
161 | EXPORT_SYMBOL(sbus_map_single); | ||
162 | EXPORT_SYMBOL(sbus_unmap_single); | ||
163 | EXPORT_SYMBOL(sbus_map_sg); | ||
164 | EXPORT_SYMBOL(sbus_unmap_sg); | ||
165 | EXPORT_SYMBOL(sbus_dma_sync_single_for_cpu); | ||
166 | EXPORT_SYMBOL(sbus_dma_sync_single_for_device); | ||
167 | EXPORT_SYMBOL(sbus_dma_sync_sg_for_cpu); | ||
168 | EXPORT_SYMBOL(sbus_dma_sync_sg_for_device); | ||
169 | EXPORT_SYMBOL(sbus_iounmap); | ||
170 | EXPORT_SYMBOL(sbus_ioremap); | ||
171 | #endif | 147 | #endif |
172 | #ifdef CONFIG_PCI | 148 | #ifdef CONFIG_PCI |
173 | EXPORT_SYMBOL(ebus_chain); | ||
174 | EXPORT_SYMBOL(insb); | 149 | EXPORT_SYMBOL(insb); |
175 | EXPORT_SYMBOL(outsb); | 150 | EXPORT_SYMBOL(outsb); |
176 | EXPORT_SYMBOL(insw); | 151 | EXPORT_SYMBOL(insw); |
diff --git a/arch/sparc/kernel/sun4c_irq.c b/arch/sparc/kernel/sun4c_irq.c index 340fc395fe2d..5dc8a5769489 100644 --- a/arch/sparc/kernel/sun4c_irq.c +++ b/arch/sparc/kernel/sun4c_irq.c | |||
@@ -18,6 +18,8 @@ | |||
18 | #include <linux/interrupt.h> | 18 | #include <linux/interrupt.h> |
19 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
20 | #include <linux/init.h> | 20 | #include <linux/init.h> |
21 | #include <linux/of.h> | ||
22 | #include <linux/of_device.h> | ||
21 | #include "irq.h" | 23 | #include "irq.h" |
22 | 24 | ||
23 | #include <asm/ptrace.h> | 25 | #include <asm/ptrace.h> |
@@ -31,15 +33,8 @@ | |||
31 | #include <asm/traps.h> | 33 | #include <asm/traps.h> |
32 | #include <asm/irq.h> | 34 | #include <asm/irq.h> |
33 | #include <asm/io.h> | 35 | #include <asm/io.h> |
34 | #include <asm/sun4paddr.h> | ||
35 | #include <asm/idprom.h> | 36 | #include <asm/idprom.h> |
36 | #include <asm/machines.h> | 37 | #include <asm/machines.h> |
37 | #include <asm/sbus.h> | ||
38 | |||
39 | #if 0 | ||
40 | static struct resource sun4c_timer_eb = { "sun4c_timer" }; | ||
41 | static struct resource sun4c_intr_eb = { "sun4c_intr" }; | ||
42 | #endif | ||
43 | 38 | ||
44 | /* | 39 | /* |
45 | * Bit field defines for the interrupt registers on various | 40 | * Bit field defines for the interrupt registers on various |
@@ -64,19 +59,7 @@ static struct resource sun4c_intr_eb = { "sun4c_intr" }; | |||
64 | * | 59 | * |
65 | * so don't go making it static, like I tried. sigh. | 60 | * so don't go making it static, like I tried. sigh. |
66 | */ | 61 | */ |
67 | unsigned char *interrupt_enable = NULL; | 62 | unsigned char __iomem *interrupt_enable = NULL; |
68 | |||
69 | static int sun4c_pil_map[] = { 0, 1, 2, 3, 5, 7, 8, 9 }; | ||
70 | |||
71 | static unsigned int sun4c_sbint_to_irq(struct sbus_dev *sdev, | ||
72 | unsigned int sbint) | ||
73 | { | ||
74 | if (sbint >= sizeof(sun4c_pil_map)) { | ||
75 | printk(KERN_ERR "%s: bogus SBINT %d\n", sdev->prom_name, sbint); | ||
76 | BUG(); | ||
77 | } | ||
78 | return sun4c_pil_map[sbint]; | ||
79 | } | ||
80 | 63 | ||
81 | static void sun4c_disable_irq(unsigned int irq_nr) | 64 | static void sun4c_disable_irq(unsigned int irq_nr) |
82 | { | 65 | { |
@@ -85,7 +68,7 @@ static void sun4c_disable_irq(unsigned int irq_nr) | |||
85 | 68 | ||
86 | local_irq_save(flags); | 69 | local_irq_save(flags); |
87 | irq_nr &= (NR_IRQS - 1); | 70 | irq_nr &= (NR_IRQS - 1); |
88 | current_mask = *interrupt_enable; | 71 | current_mask = sbus_readb(interrupt_enable); |
89 | switch(irq_nr) { | 72 | switch(irq_nr) { |
90 | case 1: | 73 | case 1: |
91 | new_mask = ((current_mask) & (~(SUN4C_INT_E1))); | 74 | new_mask = ((current_mask) & (~(SUN4C_INT_E1))); |
@@ -103,7 +86,7 @@ static void sun4c_disable_irq(unsigned int irq_nr) | |||
103 | local_irq_restore(flags); | 86 | local_irq_restore(flags); |
104 | return; | 87 | return; |
105 | } | 88 | } |
106 | *interrupt_enable = new_mask; | 89 | sbus_writeb(new_mask, interrupt_enable); |
107 | local_irq_restore(flags); | 90 | local_irq_restore(flags); |
108 | } | 91 | } |
109 | 92 | ||
@@ -114,7 +97,7 @@ static void sun4c_enable_irq(unsigned int irq_nr) | |||
114 | 97 | ||
115 | local_irq_save(flags); | 98 | local_irq_save(flags); |
116 | irq_nr &= (NR_IRQS - 1); | 99 | irq_nr &= (NR_IRQS - 1); |
117 | current_mask = *interrupt_enable; | 100 | current_mask = sbus_readb(interrupt_enable); |
118 | switch(irq_nr) { | 101 | switch(irq_nr) { |
119 | case 1: | 102 | case 1: |
120 | new_mask = ((current_mask) | SUN4C_INT_E1); | 103 | new_mask = ((current_mask) | SUN4C_INT_E1); |
@@ -132,37 +115,22 @@ static void sun4c_enable_irq(unsigned int irq_nr) | |||
132 | local_irq_restore(flags); | 115 | local_irq_restore(flags); |
133 | return; | 116 | return; |
134 | } | 117 | } |
135 | *interrupt_enable = new_mask; | 118 | sbus_writeb(new_mask, interrupt_enable); |
136 | local_irq_restore(flags); | 119 | local_irq_restore(flags); |
137 | } | 120 | } |
138 | 121 | ||
139 | #define TIMER_IRQ 10 /* Also at level 14, but we ignore that one. */ | 122 | struct sun4c_timer_info { |
140 | #define PROFILE_IRQ 14 /* Level14 ticker.. used by OBP for polling */ | 123 | u32 l10_count; |
141 | 124 | u32 l10_limit; | |
142 | volatile struct sun4c_timer_info *sun4c_timers; | 125 | u32 l14_count; |
126 | u32 l14_limit; | ||
127 | }; | ||
143 | 128 | ||
144 | #ifdef CONFIG_SUN4 | 129 | static struct sun4c_timer_info __iomem *sun4c_timers; |
145 | /* This is an ugly hack to work around the | ||
146 | current timer code, and make it work with | ||
147 | the sun4/260 intersil | ||
148 | */ | ||
149 | volatile struct sun4c_timer_info sun4_timer; | ||
150 | #endif | ||
151 | 130 | ||
152 | static void sun4c_clear_clock_irq(void) | 131 | static void sun4c_clear_clock_irq(void) |
153 | { | 132 | { |
154 | volatile unsigned int clear_intr; | 133 | sbus_readl(&sun4c_timers->l10_limit); |
155 | #ifdef CONFIG_SUN4 | ||
156 | if (idprom->id_machtype == (SM_SUN4 | SM_4_260)) | ||
157 | clear_intr = sun4_timer.timer_limit10; | ||
158 | else | ||
159 | #endif | ||
160 | clear_intr = sun4c_timers->timer_limit10; | ||
161 | } | ||
162 | |||
163 | static void sun4c_clear_profile_irq(int cpu) | ||
164 | { | ||
165 | /* Errm.. not sure how to do this.. */ | ||
166 | } | 134 | } |
167 | 135 | ||
168 | static void sun4c_load_profile_irq(int cpu, unsigned int limit) | 136 | static void sun4c_load_profile_irq(int cpu, unsigned int limit) |
@@ -172,41 +140,48 @@ static void sun4c_load_profile_irq(int cpu, unsigned int limit) | |||
172 | 140 | ||
173 | static void __init sun4c_init_timers(irq_handler_t counter_fn) | 141 | static void __init sun4c_init_timers(irq_handler_t counter_fn) |
174 | { | 142 | { |
175 | int irq; | 143 | const struct linux_prom_irqs *irq; |
144 | struct device_node *dp; | ||
145 | const u32 *addr; | ||
146 | int err; | ||
147 | |||
148 | dp = of_find_node_by_name(NULL, "counter-timer"); | ||
149 | if (!dp) { | ||
150 | prom_printf("sun4c_init_timers: Unable to find counter-timer\n"); | ||
151 | prom_halt(); | ||
152 | } | ||
176 | 153 | ||
177 | /* Map the Timer chip, this is implemented in hardware inside | 154 | addr = of_get_property(dp, "address", NULL); |
178 | * the cache chip on the sun4c. | 155 | if (!addr) { |
179 | */ | 156 | prom_printf("sun4c_init_timers: No address property\n"); |
180 | #ifdef CONFIG_SUN4 | 157 | prom_halt(); |
181 | if (idprom->id_machtype == (SM_SUN4 | SM_4_260)) | 158 | } |
182 | sun4c_timers = &sun4_timer; | 159 | |
183 | else | 160 | sun4c_timers = (void __iomem *) (unsigned long) addr[0]; |
184 | #endif | 161 | |
185 | sun4c_timers = ioremap(SUN_TIMER_PHYSADDR, | 162 | irq = of_get_property(dp, "intr", NULL); |
186 | sizeof(struct sun4c_timer_info)); | 163 | if (!irq) { |
164 | prom_printf("sun4c_init_timers: No intr property\n"); | ||
165 | prom_halt(); | ||
166 | } | ||
187 | 167 | ||
188 | /* Have the level 10 timer tick at 100HZ. We don't touch the | 168 | /* Have the level 10 timer tick at 100HZ. We don't touch the |
189 | * level 14 timer limit since we are letting the prom handle | 169 | * level 14 timer limit since we are letting the prom handle |
190 | * them until we have a real console driver so L1-A works. | 170 | * them until we have a real console driver so L1-A works. |
191 | */ | 171 | */ |
192 | sun4c_timers->timer_limit10 = (((1000000/HZ) + 1) << 10); | 172 | sbus_writel((((1000000/HZ) + 1) << 10), &sun4c_timers->l10_limit); |
193 | master_l10_counter = &sun4c_timers->cur_count10; | ||
194 | master_l10_limit = &sun4c_timers->timer_limit10; | ||
195 | 173 | ||
196 | irq = request_irq(TIMER_IRQ, | 174 | master_l10_counter = &sun4c_timers->l10_count; |
197 | counter_fn, | 175 | |
176 | err = request_irq(irq[0].pri, counter_fn, | ||
198 | (IRQF_DISABLED | SA_STATIC_ALLOC), | 177 | (IRQF_DISABLED | SA_STATIC_ALLOC), |
199 | "timer", NULL); | 178 | "timer", NULL); |
200 | if (irq) { | 179 | if (err) { |
201 | prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ); | 180 | prom_printf("sun4c_init_timers: request_irq() fails with %d\n", err); |
202 | prom_halt(); | 181 | prom_halt(); |
203 | } | 182 | } |
204 | 183 | ||
205 | #if 0 | 184 | sun4c_disable_irq(irq[1].pri); |
206 | /* This does not work on 4/330 */ | ||
207 | sun4c_enable_irq(10); | ||
208 | #endif | ||
209 | claim_ticker14(NULL, PROFILE_IRQ, 0); | ||
210 | } | 185 | } |
211 | 186 | ||
212 | #ifdef CONFIG_SMP | 187 | #ifdef CONFIG_SMP |
@@ -215,41 +190,28 @@ static void sun4c_nop(void) {} | |||
215 | 190 | ||
216 | void __init sun4c_init_IRQ(void) | 191 | void __init sun4c_init_IRQ(void) |
217 | { | 192 | { |
218 | struct linux_prom_registers int_regs[2]; | 193 | struct device_node *dp; |
219 | int ie_node; | 194 | const u32 *addr; |
220 | 195 | ||
221 | if (ARCH_SUN4) { | 196 | dp = of_find_node_by_name(NULL, "interrupt-enable"); |
222 | interrupt_enable = (char *) | 197 | if (!dp) { |
223 | ioremap(sun4_ie_physaddr, PAGE_SIZE); | 198 | prom_printf("sun4c_init_IRQ: Unable to find interrupt-enable\n"); |
224 | } else { | 199 | prom_halt(); |
225 | struct resource phyres; | 200 | } |
226 | |||
227 | ie_node = prom_searchsiblings (prom_getchild(prom_root_node), | ||
228 | "interrupt-enable"); | ||
229 | if(ie_node == 0) | ||
230 | panic("Cannot find /interrupt-enable node"); | ||
231 | 201 | ||
232 | /* Depending on the "address" property is bad news... */ | 202 | addr = of_get_property(dp, "address", NULL); |
233 | interrupt_enable = NULL; | 203 | if (!addr) { |
234 | if (prom_getproperty(ie_node, "reg", (char *) int_regs, | 204 | prom_printf("sun4c_init_IRQ: No address property\n"); |
235 | sizeof(int_regs)) != -1) { | 205 | prom_halt(); |
236 | memset(&phyres, 0, sizeof(struct resource)); | ||
237 | phyres.flags = int_regs[0].which_io; | ||
238 | phyres.start = int_regs[0].phys_addr; | ||
239 | interrupt_enable = (char *) sbus_ioremap(&phyres, 0, | ||
240 | int_regs[0].reg_size, "sun4c_intr"); | ||
241 | } | ||
242 | } | 206 | } |
243 | if (!interrupt_enable) | ||
244 | panic("Cannot map interrupt_enable"); | ||
245 | 207 | ||
246 | BTFIXUPSET_CALL(sbint_to_irq, sun4c_sbint_to_irq, BTFIXUPCALL_NORM); | 208 | interrupt_enable = (void __iomem *) (unsigned long) addr[0]; |
209 | |||
247 | BTFIXUPSET_CALL(enable_irq, sun4c_enable_irq, BTFIXUPCALL_NORM); | 210 | BTFIXUPSET_CALL(enable_irq, sun4c_enable_irq, BTFIXUPCALL_NORM); |
248 | BTFIXUPSET_CALL(disable_irq, sun4c_disable_irq, BTFIXUPCALL_NORM); | 211 | BTFIXUPSET_CALL(disable_irq, sun4c_disable_irq, BTFIXUPCALL_NORM); |
249 | BTFIXUPSET_CALL(enable_pil_irq, sun4c_enable_irq, BTFIXUPCALL_NORM); | 212 | BTFIXUPSET_CALL(enable_pil_irq, sun4c_enable_irq, BTFIXUPCALL_NORM); |
250 | BTFIXUPSET_CALL(disable_pil_irq, sun4c_disable_irq, BTFIXUPCALL_NORM); | 213 | BTFIXUPSET_CALL(disable_pil_irq, sun4c_disable_irq, BTFIXUPCALL_NORM); |
251 | BTFIXUPSET_CALL(clear_clock_irq, sun4c_clear_clock_irq, BTFIXUPCALL_NORM); | 214 | BTFIXUPSET_CALL(clear_clock_irq, sun4c_clear_clock_irq, BTFIXUPCALL_NORM); |
252 | BTFIXUPSET_CALL(clear_profile_irq, sun4c_clear_profile_irq, BTFIXUPCALL_NOP); | ||
253 | BTFIXUPSET_CALL(load_profile_irq, sun4c_load_profile_irq, BTFIXUPCALL_NOP); | 215 | BTFIXUPSET_CALL(load_profile_irq, sun4c_load_profile_irq, BTFIXUPCALL_NOP); |
254 | sparc_init_timers = sun4c_init_timers; | 216 | sparc_init_timers = sun4c_init_timers; |
255 | #ifdef CONFIG_SMP | 217 | #ifdef CONFIG_SMP |
@@ -257,6 +219,6 @@ void __init sun4c_init_IRQ(void) | |||
257 | BTFIXUPSET_CALL(clear_cpu_int, sun4c_nop, BTFIXUPCALL_NOP); | 219 | BTFIXUPSET_CALL(clear_cpu_int, sun4c_nop, BTFIXUPCALL_NOP); |
258 | BTFIXUPSET_CALL(set_irq_udt, sun4c_nop, BTFIXUPCALL_NOP); | 220 | BTFIXUPSET_CALL(set_irq_udt, sun4c_nop, BTFIXUPCALL_NOP); |
259 | #endif | 221 | #endif |
260 | *interrupt_enable = (SUN4C_INT_ENABLE); | 222 | sbus_writeb(SUN4C_INT_ENABLE, interrupt_enable); |
261 | /* Cannot enable interrupts until OBP ticker is disabled. */ | 223 | /* Cannot enable interrupts until OBP ticker is disabled. */ |
262 | } | 224 | } |
diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c index 1290b5998f83..d3cb76ce418b 100644 --- a/arch/sparc/kernel/sun4d_irq.c +++ b/arch/sparc/kernel/sun4d_irq.c | |||
@@ -19,6 +19,8 @@ | |||
19 | #include <linux/smp.h> | 19 | #include <linux/smp.h> |
20 | #include <linux/spinlock.h> | 20 | #include <linux/spinlock.h> |
21 | #include <linux/seq_file.h> | 21 | #include <linux/seq_file.h> |
22 | #include <linux/of.h> | ||
23 | #include <linux/of_device.h> | ||
22 | 24 | ||
23 | #include <asm/ptrace.h> | 25 | #include <asm/ptrace.h> |
24 | #include <asm/processor.h> | 26 | #include <asm/processor.h> |
@@ -34,7 +36,6 @@ | |||
34 | #include <asm/io.h> | 36 | #include <asm/io.h> |
35 | #include <asm/pgalloc.h> | 37 | #include <asm/pgalloc.h> |
36 | #include <asm/pgtable.h> | 38 | #include <asm/pgtable.h> |
37 | #include <asm/sbus.h> | ||
38 | #include <asm/sbi.h> | 39 | #include <asm/sbi.h> |
39 | #include <asm/cacheflush.h> | 40 | #include <asm/cacheflush.h> |
40 | #include <asm/irq_regs.h> | 41 | #include <asm/irq_regs.h> |
@@ -44,16 +45,22 @@ | |||
44 | /* If you trust current SCSI layer to handle different SCSI IRQs, enable this. I don't trust it... -jj */ | 45 | /* If you trust current SCSI layer to handle different SCSI IRQs, enable this. I don't trust it... -jj */ |
45 | /* #define DISTRIBUTE_IRQS */ | 46 | /* #define DISTRIBUTE_IRQS */ |
46 | 47 | ||
47 | struct sun4d_timer_regs *sun4d_timers; | 48 | struct sun4d_timer_regs { |
49 | u32 l10_timer_limit; | ||
50 | u32 l10_cur_countx; | ||
51 | u32 l10_limit_noclear; | ||
52 | u32 ctrl; | ||
53 | u32 l10_cur_count; | ||
54 | }; | ||
55 | |||
56 | static struct sun4d_timer_regs __iomem *sun4d_timers; | ||
57 | |||
48 | #define TIMER_IRQ 10 | 58 | #define TIMER_IRQ 10 |
49 | 59 | ||
50 | #define MAX_STATIC_ALLOC 4 | 60 | #define MAX_STATIC_ALLOC 4 |
51 | extern struct irqaction static_irqaction[MAX_STATIC_ALLOC]; | 61 | extern struct irqaction static_irqaction[MAX_STATIC_ALLOC]; |
52 | extern int static_irq_count; | 62 | extern int static_irq_count; |
53 | unsigned char cpu_leds[32]; | ||
54 | #ifdef CONFIG_SMP | ||
55 | static unsigned char sbus_tid[32]; | 63 | static unsigned char sbus_tid[32]; |
56 | #endif | ||
57 | 64 | ||
58 | static struct irqaction *irq_action[NR_IRQS]; | 65 | static struct irqaction *irq_action[NR_IRQS]; |
59 | extern spinlock_t irq_action_lock; | 66 | extern spinlock_t irq_action_lock; |
@@ -72,9 +79,9 @@ static int sbus_to_pil[] = { | |||
72 | }; | 79 | }; |
73 | 80 | ||
74 | static int nsbi; | 81 | static int nsbi; |
75 | #ifdef CONFIG_SMP | 82 | |
83 | /* Exported for sun4d_smp.c */ | ||
76 | DEFINE_SPINLOCK(sun4d_imsk_lock); | 84 | DEFINE_SPINLOCK(sun4d_imsk_lock); |
77 | #endif | ||
78 | 85 | ||
79 | int show_sun4d_interrupts(struct seq_file *p, void *v) | 86 | int show_sun4d_interrupts(struct seq_file *p, void *v) |
80 | { | 87 | { |
@@ -257,26 +264,6 @@ void sun4d_handler_irq(int irq, struct pt_regs * regs) | |||
257 | set_irq_regs(old_regs); | 264 | set_irq_regs(old_regs); |
258 | } | 265 | } |
259 | 266 | ||
260 | unsigned int sun4d_build_irq(struct sbus_dev *sdev, int irq) | ||
261 | { | ||
262 | int sbusl = pil_to_sbus[irq]; | ||
263 | |||
264 | if (sbusl) | ||
265 | return ((sdev->bus->board + 1) << 5) + (sbusl << 2) + sdev->slot; | ||
266 | else | ||
267 | return irq; | ||
268 | } | ||
269 | |||
270 | static unsigned int sun4d_sbint_to_irq(struct sbus_dev *sdev, | ||
271 | unsigned int sbint) | ||
272 | { | ||
273 | if (sbint >= sizeof(sbus_to_pil)) { | ||
274 | printk(KERN_ERR "%s: bogus SBINT %d\n", sdev->prom_name, sbint); | ||
275 | BUG(); | ||
276 | } | ||
277 | return sun4d_build_irq(sdev, sbus_to_pil[sbint]); | ||
278 | } | ||
279 | |||
280 | int sun4d_request_irq(unsigned int irq, | 267 | int sun4d_request_irq(unsigned int irq, |
281 | irq_handler_t handler, | 268 | irq_handler_t handler, |
282 | unsigned long irqflags, const char * devname, void *dev_id) | 269 | unsigned long irqflags, const char * devname, void *dev_id) |
@@ -360,36 +347,28 @@ out: | |||
360 | 347 | ||
361 | static void sun4d_disable_irq(unsigned int irq) | 348 | static void sun4d_disable_irq(unsigned int irq) |
362 | { | 349 | { |
363 | #ifdef CONFIG_SMP | ||
364 | int tid = sbus_tid[(irq >> 5) - 1]; | 350 | int tid = sbus_tid[(irq >> 5) - 1]; |
365 | unsigned long flags; | 351 | unsigned long flags; |
366 | #endif | ||
367 | 352 | ||
368 | if (irq < NR_IRQS) return; | 353 | if (irq < NR_IRQS) |
369 | #ifdef CONFIG_SMP | 354 | return; |
355 | |||
370 | spin_lock_irqsave(&sun4d_imsk_lock, flags); | 356 | spin_lock_irqsave(&sun4d_imsk_lock, flags); |
371 | cc_set_imsk_other(tid, cc_get_imsk_other(tid) | (1 << sbus_to_pil[(irq >> 2) & 7])); | 357 | cc_set_imsk_other(tid, cc_get_imsk_other(tid) | (1 << sbus_to_pil[(irq >> 2) & 7])); |
372 | spin_unlock_irqrestore(&sun4d_imsk_lock, flags); | 358 | spin_unlock_irqrestore(&sun4d_imsk_lock, flags); |
373 | #else | ||
374 | cc_set_imsk(cc_get_imsk() | (1 << sbus_to_pil[(irq >> 2) & 7])); | ||
375 | #endif | ||
376 | } | 359 | } |
377 | 360 | ||
378 | static void sun4d_enable_irq(unsigned int irq) | 361 | static void sun4d_enable_irq(unsigned int irq) |
379 | { | 362 | { |
380 | #ifdef CONFIG_SMP | ||
381 | int tid = sbus_tid[(irq >> 5) - 1]; | 363 | int tid = sbus_tid[(irq >> 5) - 1]; |
382 | unsigned long flags; | 364 | unsigned long flags; |
383 | #endif | ||
384 | 365 | ||
385 | if (irq < NR_IRQS) return; | 366 | if (irq < NR_IRQS) |
386 | #ifdef CONFIG_SMP | 367 | return; |
368 | |||
387 | spin_lock_irqsave(&sun4d_imsk_lock, flags); | 369 | spin_lock_irqsave(&sun4d_imsk_lock, flags); |
388 | cc_set_imsk_other(tid, cc_get_imsk_other(tid) & ~(1 << sbus_to_pil[(irq >> 2) & 7])); | 370 | cc_set_imsk_other(tid, cc_get_imsk_other(tid) & ~(1 << sbus_to_pil[(irq >> 2) & 7])); |
389 | spin_unlock_irqrestore(&sun4d_imsk_lock, flags); | 371 | spin_unlock_irqrestore(&sun4d_imsk_lock, flags); |
390 | #else | ||
391 | cc_set_imsk(cc_get_imsk() & ~(1 << sbus_to_pil[(irq >> 2) & 7])); | ||
392 | #endif | ||
393 | } | 372 | } |
394 | 373 | ||
395 | #ifdef CONFIG_SMP | 374 | #ifdef CONFIG_SMP |
@@ -409,47 +388,55 @@ static void sun4d_set_udt(int cpu) | |||
409 | /* Setup IRQ distribution scheme. */ | 388 | /* Setup IRQ distribution scheme. */ |
410 | void __init sun4d_distribute_irqs(void) | 389 | void __init sun4d_distribute_irqs(void) |
411 | { | 390 | { |
391 | struct device_node *dp; | ||
392 | |||
412 | #ifdef DISTRIBUTE_IRQS | 393 | #ifdef DISTRIBUTE_IRQS |
413 | struct sbus_bus *sbus; | 394 | cpumask_t sbus_serving_map; |
414 | unsigned long sbus_serving_map; | ||
415 | 395 | ||
416 | sbus_serving_map = cpu_present_map; | 396 | sbus_serving_map = cpu_present_map; |
417 | for_each_sbus(sbus) { | 397 | for_each_node_by_name(dp, "sbi") { |
418 | if ((sbus->board * 2) == boot_cpu_id && (cpu_present_map & (1 << (sbus->board * 2 + 1)))) | 398 | int board = of_getintprop_default(dp, "board#", 0); |
419 | sbus_tid[sbus->board] = (sbus->board * 2 + 1); | 399 | |
420 | else if (cpu_present_map & (1 << (sbus->board * 2))) | 400 | if ((board * 2) == boot_cpu_id && cpu_isset(board * 2 + 1, cpu_present_map)) |
421 | sbus_tid[sbus->board] = (sbus->board * 2); | 401 | sbus_tid[board] = (board * 2 + 1); |
422 | else if (cpu_present_map & (1 << (sbus->board * 2 + 1))) | 402 | else if (cpu_isset(board * 2, cpu_present_map)) |
423 | sbus_tid[sbus->board] = (sbus->board * 2 + 1); | 403 | sbus_tid[board] = (board * 2); |
404 | else if (cpu_isset(board * 2 + 1, cpu_present_map)) | ||
405 | sbus_tid[board] = (board * 2 + 1); | ||
424 | else | 406 | else |
425 | sbus_tid[sbus->board] = 0xff; | 407 | sbus_tid[board] = 0xff; |
426 | if (sbus_tid[sbus->board] != 0xff) | 408 | if (sbus_tid[board] != 0xff) |
427 | sbus_serving_map &= ~(1 << sbus_tid[sbus->board]); | 409 | cpu_clear(sbus_tid[board], sbus_serving_map); |
428 | } | 410 | } |
429 | for_each_sbus(sbus) | 411 | for_each_node_by_name(dp, "sbi") { |
430 | if (sbus_tid[sbus->board] == 0xff) { | 412 | int board = of_getintprop_default(dp, "board#", 0); |
413 | if (sbus_tid[board] == 0xff) { | ||
431 | int i = 31; | 414 | int i = 31; |
432 | 415 | ||
433 | if (!sbus_serving_map) | 416 | if (cpus_empty(sbus_serving_map)) |
434 | sbus_serving_map = cpu_present_map; | 417 | sbus_serving_map = cpu_present_map; |
435 | while (!(sbus_serving_map & (1 << i))) | 418 | while (cpu_isset(i, sbus_serving_map)) |
436 | i--; | 419 | i--; |
437 | sbus_tid[sbus->board] = i; | 420 | sbus_tid[board] = i; |
438 | sbus_serving_map &= ~(1 << i); | 421 | cpu_clear(i, sbus_serving_map); |
439 | } | 422 | } |
440 | for_each_sbus(sbus) { | 423 | } |
441 | printk("sbus%d IRQs directed to CPU%d\n", sbus->board, sbus_tid[sbus->board]); | 424 | for_each_node_by_name(dp, "sbi") { |
442 | set_sbi_tid(sbus->devid, sbus_tid[sbus->board] << 3); | 425 | int devid = of_getintprop_default(dp, "device-id", 0); |
426 | int board = of_getintprop_default(dp, "board#", 0); | ||
427 | printk("sbus%d IRQs directed to CPU%d\n", board, sbus_tid[board]); | ||
428 | set_sbi_tid(devid, sbus_tid[board] << 3); | ||
443 | } | 429 | } |
444 | #else | 430 | #else |
445 | struct sbus_bus *sbus; | ||
446 | int cpuid = cpu_logical_map(1); | 431 | int cpuid = cpu_logical_map(1); |
447 | 432 | ||
448 | if (cpuid == -1) | 433 | if (cpuid == -1) |
449 | cpuid = cpu_logical_map(0); | 434 | cpuid = cpu_logical_map(0); |
450 | for_each_sbus(sbus) { | 435 | for_each_node_by_name(dp, "sbi") { |
451 | sbus_tid[sbus->board] = cpuid; | 436 | int devid = of_getintprop_default(dp, "device-id", 0); |
452 | set_sbi_tid(sbus->devid, cpuid << 3); | 437 | int board = of_getintprop_default(dp, "board#", 0); |
438 | sbus_tid[board] = cpuid; | ||
439 | set_sbi_tid(devid, cpuid << 3); | ||
453 | } | 440 | } |
454 | printk("All sbus IRQs directed to CPU%d\n", cpuid); | 441 | printk("All sbus IRQs directed to CPU%d\n", cpuid); |
455 | #endif | 442 | #endif |
@@ -458,13 +445,7 @@ void __init sun4d_distribute_irqs(void) | |||
458 | 445 | ||
459 | static void sun4d_clear_clock_irq(void) | 446 | static void sun4d_clear_clock_irq(void) |
460 | { | 447 | { |
461 | volatile unsigned int clear_intr; | 448 | sbus_readl(&sun4d_timers->l10_timer_limit); |
462 | clear_intr = sun4d_timers->l10_timer_limit; | ||
463 | } | ||
464 | |||
465 | static void sun4d_clear_profile_irq(int cpu) | ||
466 | { | ||
467 | bw_get_prof_limit(cpu); | ||
468 | } | 449 | } |
469 | 450 | ||
470 | static void sun4d_load_profile_irq(int cpu, unsigned int limit) | 451 | static void sun4d_load_profile_irq(int cpu, unsigned int limit) |
@@ -472,98 +453,121 @@ static void sun4d_load_profile_irq(int cpu, unsigned int limit) | |||
472 | bw_set_prof_limit(cpu, limit); | 453 | bw_set_prof_limit(cpu, limit); |
473 | } | 454 | } |
474 | 455 | ||
475 | static void __init sun4d_init_timers(irq_handler_t counter_fn) | 456 | static void __init sun4d_load_profile_irqs(void) |
476 | { | 457 | { |
477 | int irq; | 458 | int cpu = 0, mid; |
478 | int cpu; | ||
479 | struct resource r; | ||
480 | int mid; | ||
481 | 459 | ||
482 | /* Map the User Timer registers. */ | 460 | while (!cpu_find_by_instance(cpu, NULL, &mid)) { |
483 | memset(&r, 0, sizeof(r)); | 461 | sun4d_load_profile_irq(mid >> 3, 0); |
462 | cpu++; | ||
463 | } | ||
464 | } | ||
465 | |||
466 | static void __init sun4d_fixup_trap_table(void) | ||
467 | { | ||
484 | #ifdef CONFIG_SMP | 468 | #ifdef CONFIG_SMP |
485 | r.start = CSR_BASE(boot_cpu_id)+BW_TIMER_LIMIT; | 469 | unsigned long flags; |
486 | #else | 470 | extern unsigned long lvl14_save[4]; |
487 | r.start = CSR_BASE(0)+BW_TIMER_LIMIT; | 471 | struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)]; |
472 | extern unsigned int real_irq_entry[], smp4d_ticker[]; | ||
473 | extern unsigned int patchme_maybe_smp_msg[]; | ||
474 | |||
475 | /* Adjust so that we jump directly to smp4d_ticker */ | ||
476 | lvl14_save[2] += smp4d_ticker - real_irq_entry; | ||
477 | |||
478 | /* For SMP we use the level 14 ticker, however the bootup code | ||
479 | * has copied the firmware's level 14 vector into the boot cpu's | ||
480 | * trap table, we must fix this now or we get squashed. | ||
481 | */ | ||
482 | local_irq_save(flags); | ||
483 | patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */ | ||
484 | trap_table->inst_one = lvl14_save[0]; | ||
485 | trap_table->inst_two = lvl14_save[1]; | ||
486 | trap_table->inst_three = lvl14_save[2]; | ||
487 | trap_table->inst_four = lvl14_save[3]; | ||
488 | local_flush_cache_all(); | ||
489 | local_irq_restore(flags); | ||
488 | #endif | 490 | #endif |
489 | r.flags = 0xf; | 491 | } |
490 | sun4d_timers = (struct sun4d_timer_regs *) sbus_ioremap(&r, 0, | ||
491 | PAGE_SIZE, "user timer"); | ||
492 | 492 | ||
493 | sun4d_timers->l10_timer_limit = (((1000000/HZ) + 1) << 10); | 493 | static void __init sun4d_init_timers(irq_handler_t counter_fn) |
494 | master_l10_counter = &sun4d_timers->l10_cur_count; | 494 | { |
495 | master_l10_limit = &sun4d_timers->l10_timer_limit; | 495 | struct device_node *dp; |
496 | struct resource res; | ||
497 | const u32 *reg; | ||
498 | int err; | ||
499 | |||
500 | dp = of_find_node_by_name(NULL, "cpu-unit"); | ||
501 | if (!dp) { | ||
502 | prom_printf("sun4d_init_timers: Unable to find cpu-unit\n"); | ||
503 | prom_halt(); | ||
504 | } | ||
496 | 505 | ||
497 | irq = request_irq(TIMER_IRQ, | 506 | /* Which cpu-unit we use is arbitrary, we can view the bootbus timer |
498 | counter_fn, | 507 | * registers via any cpu's mapping. The first 'reg' property is the |
499 | (IRQF_DISABLED | SA_STATIC_ALLOC), | 508 | * bootbus. |
500 | "timer", NULL); | 509 | */ |
501 | if (irq) { | 510 | reg = of_get_property(dp, "reg", NULL); |
502 | prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ); | 511 | if (!reg) { |
512 | prom_printf("sun4d_init_timers: No reg property\n"); | ||
503 | prom_halt(); | 513 | prom_halt(); |
504 | } | 514 | } |
505 | |||
506 | /* Enable user timer free run for CPU 0 in BW */ | ||
507 | /* bw_set_ctrl(0, bw_get_ctrl(0) | BW_CTRL_USER_TIMER); */ | ||
508 | 515 | ||
509 | cpu = 0; | 516 | res.start = reg[1]; |
510 | while (!cpu_find_by_instance(cpu, NULL, &mid)) { | 517 | res.end = reg[2] - 1; |
511 | sun4d_load_profile_irq(mid >> 3, 0); | 518 | res.flags = reg[0] & 0xff; |
512 | cpu++; | 519 | sun4d_timers = of_ioremap(&res, BW_TIMER_LIMIT, |
520 | sizeof(struct sun4d_timer_regs), "user timer"); | ||
521 | if (!sun4d_timers) { | ||
522 | prom_printf("sun4d_init_timers: Can't map timer regs\n"); | ||
523 | prom_halt(); | ||
513 | } | 524 | } |
514 | 525 | ||
515 | #ifdef CONFIG_SMP | 526 | sbus_writel((((1000000/HZ) + 1) << 10), &sun4d_timers->l10_timer_limit); |
516 | { | 527 | |
517 | unsigned long flags; | 528 | master_l10_counter = &sun4d_timers->l10_cur_count; |
518 | extern unsigned long lvl14_save[4]; | 529 | |
519 | struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)]; | 530 | err = request_irq(TIMER_IRQ, counter_fn, |
520 | extern unsigned int real_irq_entry[], smp4d_ticker[]; | 531 | (IRQF_DISABLED | SA_STATIC_ALLOC), |
521 | extern unsigned int patchme_maybe_smp_msg[]; | 532 | "timer", NULL); |
522 | 533 | if (err) { | |
523 | /* Adjust so that we jump directly to smp4d_ticker */ | 534 | prom_printf("sun4d_init_timers: request_irq() failed with %d\n", err); |
524 | lvl14_save[2] += smp4d_ticker - real_irq_entry; | 535 | prom_halt(); |
525 | |||
526 | /* For SMP we use the level 14 ticker, however the bootup code | ||
527 | * has copied the firmware's level 14 vector into the boot cpu's | ||
528 | * trap table, we must fix this now or we get squashed. | ||
529 | */ | ||
530 | local_irq_save(flags); | ||
531 | patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */ | ||
532 | trap_table->inst_one = lvl14_save[0]; | ||
533 | trap_table->inst_two = lvl14_save[1]; | ||
534 | trap_table->inst_three = lvl14_save[2]; | ||
535 | trap_table->inst_four = lvl14_save[3]; | ||
536 | local_flush_cache_all(); | ||
537 | local_irq_restore(flags); | ||
538 | } | 536 | } |
539 | #endif | 537 | sun4d_load_profile_irqs(); |
538 | sun4d_fixup_trap_table(); | ||
540 | } | 539 | } |
541 | 540 | ||
542 | void __init sun4d_init_sbi_irq(void) | 541 | void __init sun4d_init_sbi_irq(void) |
543 | { | 542 | { |
544 | struct sbus_bus *sbus; | 543 | struct device_node *dp; |
545 | unsigned mask; | 544 | int target_cpu = 0; |
545 | |||
546 | #ifdef CONFIG_SMP | ||
547 | target_cpu = boot_cpu_id; | ||
548 | #endif | ||
546 | 549 | ||
547 | nsbi = 0; | 550 | nsbi = 0; |
548 | for_each_sbus(sbus) | 551 | for_each_node_by_name(dp, "sbi") |
549 | nsbi++; | 552 | nsbi++; |
550 | sbus_actions = kzalloc (nsbi * 8 * 4 * sizeof(struct sbus_action), GFP_ATOMIC); | 553 | sbus_actions = kzalloc (nsbi * 8 * 4 * sizeof(struct sbus_action), GFP_ATOMIC); |
551 | if (!sbus_actions) { | 554 | if (!sbus_actions) { |
552 | prom_printf("SUN4D: Cannot allocate sbus_actions, halting.\n"); | 555 | prom_printf("SUN4D: Cannot allocate sbus_actions, halting.\n"); |
553 | prom_halt(); | 556 | prom_halt(); |
554 | } | 557 | } |
555 | for_each_sbus(sbus) { | 558 | for_each_node_by_name(dp, "sbi") { |
556 | #ifdef CONFIG_SMP | 559 | int devid = of_getintprop_default(dp, "device-id", 0); |
557 | extern unsigned char boot_cpu_id; | 560 | int board = of_getintprop_default(dp, "board#", 0); |
558 | 561 | unsigned int mask; | |
559 | set_sbi_tid(sbus->devid, boot_cpu_id << 3); | 562 | |
560 | sbus_tid[sbus->board] = boot_cpu_id; | 563 | set_sbi_tid(devid, target_cpu << 3); |
561 | #endif | 564 | sbus_tid[board] = target_cpu; |
565 | |||
562 | /* Get rid of pending irqs from PROM */ | 566 | /* Get rid of pending irqs from PROM */ |
563 | mask = acquire_sbi(sbus->devid, 0xffffffff); | 567 | mask = acquire_sbi(devid, 0xffffffff); |
564 | if (mask) { | 568 | if (mask) { |
565 | printk ("Clearing pending IRQs %08x on SBI %d\n", mask, sbus->board); | 569 | printk ("Clearing pending IRQs %08x on SBI %d\n", mask, board); |
566 | release_sbi(sbus->devid, mask); | 570 | release_sbi(devid, mask); |
567 | } | 571 | } |
568 | } | 572 | } |
569 | } | 573 | } |
@@ -572,11 +576,9 @@ void __init sun4d_init_IRQ(void) | |||
572 | { | 576 | { |
573 | local_irq_disable(); | 577 | local_irq_disable(); |
574 | 578 | ||
575 | BTFIXUPSET_CALL(sbint_to_irq, sun4d_sbint_to_irq, BTFIXUPCALL_NORM); | ||
576 | BTFIXUPSET_CALL(enable_irq, sun4d_enable_irq, BTFIXUPCALL_NORM); | 579 | BTFIXUPSET_CALL(enable_irq, sun4d_enable_irq, BTFIXUPCALL_NORM); |
577 | BTFIXUPSET_CALL(disable_irq, sun4d_disable_irq, BTFIXUPCALL_NORM); | 580 | BTFIXUPSET_CALL(disable_irq, sun4d_disable_irq, BTFIXUPCALL_NORM); |
578 | BTFIXUPSET_CALL(clear_clock_irq, sun4d_clear_clock_irq, BTFIXUPCALL_NORM); | 581 | BTFIXUPSET_CALL(clear_clock_irq, sun4d_clear_clock_irq, BTFIXUPCALL_NORM); |
579 | BTFIXUPSET_CALL(clear_profile_irq, sun4d_clear_profile_irq, BTFIXUPCALL_NORM); | ||
580 | BTFIXUPSET_CALL(load_profile_irq, sun4d_load_profile_irq, BTFIXUPCALL_NORM); | 582 | BTFIXUPSET_CALL(load_profile_irq, sun4d_load_profile_irq, BTFIXUPCALL_NORM); |
581 | sparc_init_timers = sun4d_init_timers; | 583 | sparc_init_timers = sun4d_init_timers; |
582 | #ifdef CONFIG_SMP | 584 | #ifdef CONFIG_SMP |
diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c index 69596402a500..ce3d45db94e9 100644 --- a/arch/sparc/kernel/sun4d_smp.c +++ b/arch/sparc/kernel/sun4d_smp.c | |||
@@ -30,7 +30,6 @@ | |||
30 | #include <asm/pgalloc.h> | 30 | #include <asm/pgalloc.h> |
31 | #include <asm/pgtable.h> | 31 | #include <asm/pgtable.h> |
32 | #include <asm/oplib.h> | 32 | #include <asm/oplib.h> |
33 | #include <asm/sbus.h> | ||
34 | #include <asm/sbi.h> | 33 | #include <asm/sbi.h> |
35 | #include <asm/tlbflush.h> | 34 | #include <asm/tlbflush.h> |
36 | #include <asm/cacheflush.h> | 35 | #include <asm/cacheflush.h> |
@@ -72,6 +71,17 @@ static void smp_setup_percpu_timer(void); | |||
72 | extern void cpu_probe(void); | 71 | extern void cpu_probe(void); |
73 | extern void sun4d_distribute_irqs(void); | 72 | extern void sun4d_distribute_irqs(void); |
74 | 73 | ||
74 | static unsigned char cpu_leds[32]; | ||
75 | |||
76 | static inline void show_leds(int cpuid) | ||
77 | { | ||
78 | cpuid &= 0x1e; | ||
79 | __asm__ __volatile__ ("stba %0, [%1] %2" : : | ||
80 | "r" ((cpu_leds[cpuid] << 4) | cpu_leds[cpuid+1]), | ||
81 | "r" (ECSR_BASE(cpuid) | BB_LEDS), | ||
82 | "i" (ASI_M_CTL)); | ||
83 | } | ||
84 | |||
75 | void __init smp4d_callin(void) | 85 | void __init smp4d_callin(void) |
76 | { | 86 | { |
77 | int cpuid = hard_smp4d_processor_id(); | 87 | int cpuid = hard_smp4d_processor_id(); |
@@ -88,6 +98,7 @@ void __init smp4d_callin(void) | |||
88 | local_flush_cache_all(); | 98 | local_flush_cache_all(); |
89 | local_flush_tlb_all(); | 99 | local_flush_tlb_all(); |
90 | 100 | ||
101 | notify_cpu_starting(cpuid); | ||
91 | /* | 102 | /* |
92 | * Unblock the master CPU _only_ when the scheduler state | 103 | * Unblock the master CPU _only_ when the scheduler state |
93 | * of all secondary CPUs will be up-to-date, so after | 104 | * of all secondary CPUs will be up-to-date, so after |
diff --git a/arch/sparc/kernel/sun4m_irq.c b/arch/sparc/kernel/sun4m_irq.c index 94e02de960ea..f10317179ee6 100644 --- a/arch/sparc/kernel/sun4m_irq.c +++ b/arch/sparc/kernel/sun4m_irq.c | |||
@@ -20,6 +20,8 @@ | |||
20 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
21 | #include <linux/init.h> | 21 | #include <linux/init.h> |
22 | #include <linux/ioport.h> | 22 | #include <linux/ioport.h> |
23 | #include <linux/of.h> | ||
24 | #include <linux/of_device.h> | ||
23 | 25 | ||
24 | #include <asm/ptrace.h> | 26 | #include <asm/ptrace.h> |
25 | #include <asm/processor.h> | 27 | #include <asm/processor.h> |
@@ -35,59 +37,27 @@ | |||
35 | #include <asm/smp.h> | 37 | #include <asm/smp.h> |
36 | #include <asm/irq.h> | 38 | #include <asm/irq.h> |
37 | #include <asm/io.h> | 39 | #include <asm/io.h> |
38 | #include <asm/sbus.h> | ||
39 | #include <asm/cacheflush.h> | 40 | #include <asm/cacheflush.h> |
40 | 41 | ||
41 | #include "irq.h" | 42 | #include "irq.h" |
42 | 43 | ||
43 | /* On the sun4m, just like the timers, we have both per-cpu and master | 44 | struct sun4m_irq_percpu { |
44 | * interrupt registers. | 45 | u32 pending; |
45 | */ | 46 | u32 clear; |
46 | 47 | u32 set; | |
47 | /* These registers are used for sending/receiving irqs from/to | ||
48 | * different cpu's. | ||
49 | */ | ||
50 | struct sun4m_intreg_percpu { | ||
51 | unsigned int tbt; /* Interrupts still pending for this cpu. */ | ||
52 | |||
53 | /* These next two registers are WRITE-ONLY and are only | ||
54 | * "on bit" sensitive, "off bits" written have NO affect. | ||
55 | */ | ||
56 | unsigned int clear; /* Clear this cpus irqs here. */ | ||
57 | unsigned int set; /* Set this cpus irqs here. */ | ||
58 | unsigned char space[PAGE_SIZE - 12]; | ||
59 | }; | 48 | }; |
60 | 49 | ||
61 | /* | 50 | struct sun4m_irq_global { |
62 | * djhr | 51 | u32 pending; |
63 | * Actually the clear and set fields in this struct are misleading.. | 52 | u32 mask; |
64 | * according to the SLAVIO manual (and the same applies for the SEC) | 53 | u32 mask_clear; |
65 | * the clear field clears bits in the mask which will ENABLE that IRQ | 54 | u32 mask_set; |
66 | * the set field sets bits in the mask to DISABLE the IRQ. | 55 | u32 interrupt_target; |
67 | * | ||
68 | * Also the undirected_xx address in the SLAVIO is defined as | ||
69 | * RESERVED and write only.. | ||
70 | * | ||
71 | * DAVEM_NOTE: The SLAVIO only specifies behavior on uniprocessor | ||
72 | * sun4m machines, for MP the layout makes more sense. | ||
73 | */ | ||
74 | struct sun4m_intregs { | ||
75 | struct sun4m_intreg_percpu cpu_intregs[SUN4M_NCPUS]; | ||
76 | unsigned int tbt; /* IRQ's that are still pending. */ | ||
77 | unsigned int irqs; /* Master IRQ bits. */ | ||
78 | |||
79 | /* Again, like the above, two these registers are WRITE-ONLY. */ | ||
80 | unsigned int clear; /* Clear master IRQ's by setting bits here. */ | ||
81 | unsigned int set; /* Set master IRQ's by setting bits here. */ | ||
82 | |||
83 | /* This register is both READ and WRITE. */ | ||
84 | unsigned int undirected_target; /* Which cpu gets undirected irqs. */ | ||
85 | }; | 56 | }; |
86 | 57 | ||
87 | static unsigned long dummy; | 58 | /* Code in entry.S needs to get at these register mappings. */ |
88 | 59 | struct sun4m_irq_percpu __iomem *sun4m_irq_percpu[SUN4M_NCPUS]; | |
89 | struct sun4m_intregs *sun4m_interrupts; | 60 | struct sun4m_irq_global __iomem *sun4m_irq_global; |
90 | unsigned long *irq_rcvreg = &dummy; | ||
91 | 61 | ||
92 | /* Dave Redman (djhr@tadpole.co.uk) | 62 | /* Dave Redman (djhr@tadpole.co.uk) |
93 | * The sun4m interrupt registers. | 63 | * The sun4m interrupt registers. |
@@ -101,8 +71,9 @@ unsigned long *irq_rcvreg = &dummy; | |||
101 | 71 | ||
102 | #define SUN4M_INT_MASKALL 0x80000000 /* mask all interrupts */ | 72 | #define SUN4M_INT_MASKALL 0x80000000 /* mask all interrupts */ |
103 | #define SUN4M_INT_MODULE_ERR 0x40000000 /* module error */ | 73 | #define SUN4M_INT_MODULE_ERR 0x40000000 /* module error */ |
104 | #define SUN4M_INT_M2S_WRITE 0x20000000 /* write buffer error */ | 74 | #define SUN4M_INT_M2S_WRITE_ERR 0x20000000 /* write buffer error */ |
105 | #define SUN4M_INT_ECC 0x10000000 /* ecc memory error */ | 75 | #define SUN4M_INT_ECC_ERR 0x10000000 /* ecc memory error */ |
76 | #define SUN4M_INT_VME_ERR 0x08000000 /* vme async error */ | ||
106 | #define SUN4M_INT_FLOPPY 0x00400000 /* floppy disk */ | 77 | #define SUN4M_INT_FLOPPY 0x00400000 /* floppy disk */ |
107 | #define SUN4M_INT_MODULE 0x00200000 /* module interrupt */ | 78 | #define SUN4M_INT_MODULE 0x00200000 /* module interrupt */ |
108 | #define SUN4M_INT_VIDEO 0x00100000 /* onboard video */ | 79 | #define SUN4M_INT_VIDEO 0x00100000 /* onboard video */ |
@@ -113,75 +84,126 @@ unsigned long *irq_rcvreg = &dummy; | |||
113 | #define SUN4M_INT_SERIAL 0x00008000 /* serial ports */ | 84 | #define SUN4M_INT_SERIAL 0x00008000 /* serial ports */ |
114 | #define SUN4M_INT_KBDMS 0x00004000 /* keyboard/mouse */ | 85 | #define SUN4M_INT_KBDMS 0x00004000 /* keyboard/mouse */ |
115 | #define SUN4M_INT_SBUSBITS 0x00003F80 /* sbus int bits */ | 86 | #define SUN4M_INT_SBUSBITS 0x00003F80 /* sbus int bits */ |
87 | #define SUN4M_INT_VMEBITS 0x0000007F /* vme int bits */ | ||
88 | |||
89 | #define SUN4M_INT_ERROR (SUN4M_INT_MODULE_ERR | \ | ||
90 | SUN4M_INT_M2S_WRITE_ERR | \ | ||
91 | SUN4M_INT_ECC_ERR | \ | ||
92 | SUN4M_INT_VME_ERR) | ||
116 | 93 | ||
117 | #define SUN4M_INT_SBUS(x) (1 << (x+7)) | 94 | #define SUN4M_INT_SBUS(x) (1 << (x+7)) |
118 | #define SUN4M_INT_VME(x) (1 << (x)) | 95 | #define SUN4M_INT_VME(x) (1 << (x)) |
119 | 96 | ||
120 | /* These tables only apply for interrupts greater than 15.. | 97 | /* Interrupt levels used by OBP */ |
121 | * | 98 | #define OBP_INT_LEVEL_SOFT 0x10 |
122 | * any intr value below 0x10 is considered to be a soft-int | 99 | #define OBP_INT_LEVEL_ONBOARD 0x20 |
123 | * this may be useful or it may not.. but that's how I've done it. | 100 | #define OBP_INT_LEVEL_SBUS 0x30 |
124 | * and it won't clash with what OBP is telling us about devices. | 101 | #define OBP_INT_LEVEL_VME 0x40 |
102 | |||
103 | /* Interrupt level assignment on sun4m: | ||
104 | * | ||
105 | * level source | ||
106 | * ------------------------------------------------------------ | ||
107 | * 1 softint-1 | ||
108 | * 2 softint-2, VME/SBUS level 1 | ||
109 | * 3 softint-3, VME/SBUS level 2 | ||
110 | * 4 softint-4, onboard SCSI | ||
111 | * 5 softint-5, VME/SBUS level 3 | ||
112 | * 6 softint-6, onboard ETHERNET | ||
113 | * 7 softint-7, VME/SBUS level 4 | ||
114 | * 8 softint-8, onboard VIDEO | ||
115 | * 9 softint-9, VME/SBUS level 5, Module Interrupt | ||
116 | * 10 softint-10, system counter/timer | ||
117 | * 11 softint-11, VME/SBUS level 6, Floppy | ||
118 | * 12 softint-12, Keyboard/Mouse, Serial | ||
119 | * 13 softint-13, VME/SBUS level 7, ISDN Audio | ||
120 | * 14 softint-14, per-processor counter/timer | ||
121 | * 15 softint-15, Asynchronous Errors (broadcast) | ||
125 | * | 122 | * |
126 | * take an encoded intr value and lookup if it's valid | 123 | * Each interrupt source is masked distinctly in the sun4m interrupt |
127 | * then get the mask bits that match from irq_mask | 124 | * registers. The PIL level alone is therefore ambiguous, since multiple |
125 | * interrupt sources map to a single PIL. | ||
128 | * | 126 | * |
129 | * P3: Translation from irq 0x0d to mask 0x2000 is for MrCoffee. | 127 | * This ambiguity is resolved in the 'intr' property for device nodes |
128 | * in the OF device tree. Each 'intr' property entry is composed of | ||
129 | * two 32-bit words. The first word is the IRQ priority value, which | ||
130 | * is what we're intersted in. The second word is the IRQ vector, which | ||
131 | * is unused. | ||
132 | * | ||
133 | * The low 4 bits of the IRQ priority indicate the PIL, and the upper | ||
134 | * 4 bits indicate onboard vs. SBUS leveled vs. VME leveled. 0x20 | ||
135 | * means onboard, 0x30 means SBUS leveled, and 0x40 means VME leveled. | ||
136 | * | ||
137 | * For example, an 'intr' IRQ priority value of 0x24 is onboard SCSI | ||
138 | * whereas a value of 0x33 is SBUS level 2. Here are some sample | ||
139 | * 'intr' property IRQ priority values from ss4, ss5, ss10, ss20, and | ||
140 | * Tadpole S3 GX systems. | ||
141 | * | ||
142 | * esp: 0x24 onboard ESP SCSI | ||
143 | * le: 0x26 onboard Lance ETHERNET | ||
144 | * p9100: 0x32 SBUS level 1 P9100 video | ||
145 | * bpp: 0x33 SBUS level 2 BPP parallel port device | ||
146 | * DBRI: 0x39 SBUS level 5 DBRI ISDN audio | ||
147 | * SUNW,leo: 0x39 SBUS level 5 LEO video | ||
148 | * pcmcia: 0x3b SBUS level 6 PCMCIA controller | ||
149 | * uctrl: 0x3b SBUS level 6 UCTRL device | ||
150 | * modem: 0x3d SBUS level 7 MODEM | ||
151 | * zs: 0x2c onboard keyboard/mouse/serial | ||
152 | * floppy: 0x2b onboard Floppy | ||
153 | * power: 0x22 onboard power device (XXX unknown mask bit XXX) | ||
130 | */ | 154 | */ |
131 | static unsigned char irq_xlate[32] = { | ||
132 | /* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f */ | ||
133 | 0, 0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 5, 6, 14, 0, 7, | ||
134 | 0, 0, 8, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 0 | ||
135 | }; | ||
136 | 155 | ||
137 | static unsigned long irq_mask[] = { | 156 | static unsigned long irq_mask[0x50] = { |
138 | 0, /* illegal index */ | 157 | /* SMP */ |
139 | SUN4M_INT_SCSI, /* 1 irq 4 */ | 158 | 0, SUN4M_SOFT_INT(1), |
140 | SUN4M_INT_ETHERNET, /* 2 irq 6 */ | 159 | SUN4M_SOFT_INT(2), SUN4M_SOFT_INT(3), |
141 | SUN4M_INT_VIDEO, /* 3 irq 8 */ | 160 | SUN4M_SOFT_INT(4), SUN4M_SOFT_INT(5), |
142 | SUN4M_INT_REALTIME, /* 4 irq 10 */ | 161 | SUN4M_SOFT_INT(6), SUN4M_SOFT_INT(7), |
143 | SUN4M_INT_FLOPPY, /* 5 irq 11 */ | 162 | SUN4M_SOFT_INT(8), SUN4M_SOFT_INT(9), |
144 | (SUN4M_INT_SERIAL | SUN4M_INT_KBDMS), /* 6 irq 12 */ | 163 | SUN4M_SOFT_INT(10), SUN4M_SOFT_INT(11), |
145 | SUN4M_INT_MODULE_ERR, /* 7 irq 15 */ | 164 | SUN4M_SOFT_INT(12), SUN4M_SOFT_INT(13), |
146 | SUN4M_INT_SBUS(0), /* 8 irq 2 */ | 165 | SUN4M_SOFT_INT(14), SUN4M_SOFT_INT(15), |
147 | SUN4M_INT_SBUS(1), /* 9 irq 3 */ | 166 | /* soft */ |
148 | SUN4M_INT_SBUS(2), /* 10 irq 5 */ | 167 | 0, SUN4M_SOFT_INT(1), |
149 | SUN4M_INT_SBUS(3), /* 11 irq 7 */ | 168 | SUN4M_SOFT_INT(2), SUN4M_SOFT_INT(3), |
150 | SUN4M_INT_SBUS(4), /* 12 irq 9 */ | 169 | SUN4M_SOFT_INT(4), SUN4M_SOFT_INT(5), |
151 | SUN4M_INT_SBUS(5), /* 13 irq 11 */ | 170 | SUN4M_SOFT_INT(6), SUN4M_SOFT_INT(7), |
152 | SUN4M_INT_SBUS(6) /* 14 irq 13 */ | 171 | SUN4M_SOFT_INT(8), SUN4M_SOFT_INT(9), |
172 | SUN4M_SOFT_INT(10), SUN4M_SOFT_INT(11), | ||
173 | SUN4M_SOFT_INT(12), SUN4M_SOFT_INT(13), | ||
174 | SUN4M_SOFT_INT(14), SUN4M_SOFT_INT(15), | ||
175 | /* onboard */ | ||
176 | 0, 0, 0, 0, | ||
177 | SUN4M_INT_SCSI, 0, SUN4M_INT_ETHERNET, 0, | ||
178 | SUN4M_INT_VIDEO, SUN4M_INT_MODULE, | ||
179 | SUN4M_INT_REALTIME, SUN4M_INT_FLOPPY, | ||
180 | (SUN4M_INT_SERIAL | SUN4M_INT_KBDMS), | ||
181 | SUN4M_INT_AUDIO, 0, SUN4M_INT_MODULE_ERR, | ||
182 | /* sbus */ | ||
183 | 0, 0, SUN4M_INT_SBUS(0), SUN4M_INT_SBUS(1), | ||
184 | 0, SUN4M_INT_SBUS(2), 0, SUN4M_INT_SBUS(3), | ||
185 | 0, SUN4M_INT_SBUS(4), 0, SUN4M_INT_SBUS(5), | ||
186 | 0, SUN4M_INT_SBUS(6), 0, 0, | ||
187 | /* vme */ | ||
188 | 0, 0, SUN4M_INT_VME(0), SUN4M_INT_VME(1), | ||
189 | 0, SUN4M_INT_VME(2), 0, SUN4M_INT_VME(3), | ||
190 | 0, SUN4M_INT_VME(4), 0, SUN4M_INT_VME(5), | ||
191 | 0, SUN4M_INT_VME(6), 0, 0 | ||
153 | }; | 192 | }; |
154 | 193 | ||
155 | static int sun4m_pil_map[] = { 0, 2, 3, 5, 7, 9, 11, 13 }; | ||
156 | |||
157 | static unsigned int sun4m_sbint_to_irq(struct sbus_dev *sdev, | ||
158 | unsigned int sbint) | ||
159 | { | ||
160 | if (sbint >= sizeof(sun4m_pil_map)) { | ||
161 | printk(KERN_ERR "%s: bogus SBINT %d\n", sdev->prom_name, sbint); | ||
162 | BUG(); | ||
163 | } | ||
164 | return sun4m_pil_map[sbint] | 0x30; | ||
165 | } | ||
166 | |||
167 | static unsigned long sun4m_get_irqmask(unsigned int irq) | 194 | static unsigned long sun4m_get_irqmask(unsigned int irq) |
168 | { | 195 | { |
169 | unsigned long mask; | 196 | unsigned long mask; |
170 | 197 | ||
171 | if (irq > 0x20) { | 198 | if (irq < 0x50) |
172 | /* OBIO/SBUS interrupts */ | 199 | mask = irq_mask[irq]; |
173 | irq &= 0x1f; | 200 | else |
174 | mask = irq_mask[irq_xlate[irq]]; | 201 | mask = 0; |
175 | if (!mask) | 202 | |
176 | printk("sun4m_get_irqmask: IRQ%d has no valid mask!\n",irq); | 203 | if (!mask) |
177 | } else { | 204 | printk(KERN_ERR "sun4m_get_irqmask: IRQ%d has no valid mask!\n", |
178 | /* Soft Interrupts will come here. | 205 | irq); |
179 | * Currently there is no way to trigger them but I'm sure | 206 | |
180 | * something could be cooked up. | ||
181 | */ | ||
182 | irq &= 0xf; | ||
183 | mask = SUN4M_SOFT_INT(irq); | ||
184 | } | ||
185 | return mask; | 207 | return mask; |
186 | } | 208 | } |
187 | 209 | ||
@@ -193,9 +215,9 @@ static void sun4m_disable_irq(unsigned int irq_nr) | |||
193 | mask = sun4m_get_irqmask(irq_nr); | 215 | mask = sun4m_get_irqmask(irq_nr); |
194 | local_irq_save(flags); | 216 | local_irq_save(flags); |
195 | if (irq_nr > 15) | 217 | if (irq_nr > 15) |
196 | sun4m_interrupts->set = mask; | 218 | sbus_writel(mask, &sun4m_irq_global->mask_set); |
197 | else | 219 | else |
198 | sun4m_interrupts->cpu_intregs[cpu].set = mask; | 220 | sbus_writel(mask, &sun4m_irq_percpu[cpu]->set); |
199 | local_irq_restore(flags); | 221 | local_irq_restore(flags); |
200 | } | 222 | } |
201 | 223 | ||
@@ -212,13 +234,13 @@ static void sun4m_enable_irq(unsigned int irq_nr) | |||
212 | mask = sun4m_get_irqmask(irq_nr); | 234 | mask = sun4m_get_irqmask(irq_nr); |
213 | local_irq_save(flags); | 235 | local_irq_save(flags); |
214 | if (irq_nr > 15) | 236 | if (irq_nr > 15) |
215 | sun4m_interrupts->clear = mask; | 237 | sbus_writel(mask, &sun4m_irq_global->mask_clear); |
216 | else | 238 | else |
217 | sun4m_interrupts->cpu_intregs[cpu].clear = mask; | 239 | sbus_writel(mask, &sun4m_irq_percpu[cpu]->clear); |
218 | local_irq_restore(flags); | 240 | local_irq_restore(flags); |
219 | } else { | 241 | } else { |
220 | local_irq_save(flags); | 242 | local_irq_save(flags); |
221 | sun4m_interrupts->clear = SUN4M_INT_FLOPPY; | 243 | sbus_writel(SUN4M_INT_FLOPPY, &sun4m_irq_global->mask_clear); |
222 | local_irq_restore(flags); | 244 | local_irq_restore(flags); |
223 | } | 245 | } |
224 | } | 246 | } |
@@ -236,10 +258,10 @@ static unsigned long cpu_pil_to_imask[16] = { | |||
236 | /*9*/ SUN4M_INT_SBUS(4) | SUN4M_INT_VME(4) | SUN4M_INT_MODULE_ERR, | 258 | /*9*/ SUN4M_INT_SBUS(4) | SUN4M_INT_VME(4) | SUN4M_INT_MODULE_ERR, |
237 | /*10*/ SUN4M_INT_REALTIME, | 259 | /*10*/ SUN4M_INT_REALTIME, |
238 | /*11*/ SUN4M_INT_SBUS(5) | SUN4M_INT_VME(5) | SUN4M_INT_FLOPPY, | 260 | /*11*/ SUN4M_INT_SBUS(5) | SUN4M_INT_VME(5) | SUN4M_INT_FLOPPY, |
239 | /*12*/ SUN4M_INT_SERIAL | SUN4M_INT_KBDMS, | 261 | /*12*/ SUN4M_INT_SERIAL | SUN4M_INT_KBDMS, |
240 | /*13*/ SUN4M_INT_AUDIO, | 262 | /*13*/ SUN4M_INT_SBUS(6) | SUN4M_INT_VME(6) | SUN4M_INT_AUDIO, |
241 | /*14*/ SUN4M_INT_E14, | 263 | /*14*/ SUN4M_INT_E14, |
242 | /*15*/ 0x00000000 | 264 | /*15*/ SUN4M_INT_ERROR |
243 | }; | 265 | }; |
244 | 266 | ||
245 | /* We assume the caller has disabled local interrupts when these are called, | 267 | /* We assume the caller has disabled local interrupts when these are called, |
@@ -247,126 +269,141 @@ static unsigned long cpu_pil_to_imask[16] = { | |||
247 | */ | 269 | */ |
248 | static void sun4m_disable_pil_irq(unsigned int pil) | 270 | static void sun4m_disable_pil_irq(unsigned int pil) |
249 | { | 271 | { |
250 | sun4m_interrupts->set = cpu_pil_to_imask[pil]; | 272 | sbus_writel(cpu_pil_to_imask[pil], &sun4m_irq_global->mask_set); |
251 | } | 273 | } |
252 | 274 | ||
253 | static void sun4m_enable_pil_irq(unsigned int pil) | 275 | static void sun4m_enable_pil_irq(unsigned int pil) |
254 | { | 276 | { |
255 | sun4m_interrupts->clear = cpu_pil_to_imask[pil]; | 277 | sbus_writel(cpu_pil_to_imask[pil], &sun4m_irq_global->mask_clear); |
256 | } | 278 | } |
257 | 279 | ||
258 | #ifdef CONFIG_SMP | 280 | #ifdef CONFIG_SMP |
259 | static void sun4m_send_ipi(int cpu, int level) | 281 | static void sun4m_send_ipi(int cpu, int level) |
260 | { | 282 | { |
261 | unsigned long mask; | 283 | unsigned long mask = sun4m_get_irqmask(level); |
262 | 284 | sbus_writel(mask, &sun4m_irq_percpu[cpu]->set); | |
263 | mask = sun4m_get_irqmask(level); | ||
264 | sun4m_interrupts->cpu_intregs[cpu].set = mask; | ||
265 | } | 285 | } |
266 | 286 | ||
267 | static void sun4m_clear_ipi(int cpu, int level) | 287 | static void sun4m_clear_ipi(int cpu, int level) |
268 | { | 288 | { |
269 | unsigned long mask; | 289 | unsigned long mask = sun4m_get_irqmask(level); |
270 | 290 | sbus_writel(mask, &sun4m_irq_percpu[cpu]->clear); | |
271 | mask = sun4m_get_irqmask(level); | ||
272 | sun4m_interrupts->cpu_intregs[cpu].clear = mask; | ||
273 | } | 291 | } |
274 | 292 | ||
275 | static void sun4m_set_udt(int cpu) | 293 | static void sun4m_set_udt(int cpu) |
276 | { | 294 | { |
277 | sun4m_interrupts->undirected_target = cpu; | 295 | sbus_writel(cpu, &sun4m_irq_global->interrupt_target); |
278 | } | 296 | } |
279 | #endif | 297 | #endif |
280 | 298 | ||
281 | #define OBIO_INTR 0x20 | 299 | struct sun4m_timer_percpu { |
282 | #define TIMER_IRQ (OBIO_INTR | 10) | 300 | u32 l14_limit; |
283 | #define PROFILE_IRQ (OBIO_INTR | 14) | 301 | u32 l14_count; |
302 | u32 l14_limit_noclear; | ||
303 | u32 user_timer_start_stop; | ||
304 | }; | ||
305 | |||
306 | static struct sun4m_timer_percpu __iomem *timers_percpu[SUN4M_NCPUS]; | ||
307 | |||
308 | struct sun4m_timer_global { | ||
309 | u32 l10_limit; | ||
310 | u32 l10_count; | ||
311 | u32 l10_limit_noclear; | ||
312 | u32 reserved; | ||
313 | u32 timer_config; | ||
314 | }; | ||
315 | |||
316 | static struct sun4m_timer_global __iomem *timers_global; | ||
317 | |||
318 | #define TIMER_IRQ (OBP_INT_LEVEL_ONBOARD | 10) | ||
284 | 319 | ||
285 | static struct sun4m_timer_regs *sun4m_timers; | ||
286 | unsigned int lvl14_resolution = (((1000000/HZ) + 1) << 10); | 320 | unsigned int lvl14_resolution = (((1000000/HZ) + 1) << 10); |
287 | 321 | ||
288 | static void sun4m_clear_clock_irq(void) | 322 | static void sun4m_clear_clock_irq(void) |
289 | { | 323 | { |
290 | volatile unsigned int clear_intr; | 324 | sbus_readl(&timers_global->l10_limit); |
291 | clear_intr = sun4m_timers->l10_timer_limit; | ||
292 | } | 325 | } |
293 | 326 | ||
294 | static void sun4m_clear_profile_irq(int cpu) | 327 | void sun4m_nmi(struct pt_regs *regs) |
295 | { | 328 | { |
296 | volatile unsigned int clear; | 329 | unsigned long afsr, afar, si; |
297 | 330 | ||
298 | clear = sun4m_timers->cpu_timers[cpu].l14_timer_limit; | 331 | printk(KERN_ERR "Aieee: sun4m NMI received!\n"); |
332 | /* XXX HyperSparc hack XXX */ | ||
333 | __asm__ __volatile__("mov 0x500, %%g1\n\t" | ||
334 | "lda [%%g1] 0x4, %0\n\t" | ||
335 | "mov 0x600, %%g1\n\t" | ||
336 | "lda [%%g1] 0x4, %1\n\t" : | ||
337 | "=r" (afsr), "=r" (afar)); | ||
338 | printk(KERN_ERR "afsr=%08lx afar=%08lx\n", afsr, afar); | ||
339 | si = sbus_readl(&sun4m_irq_global->pending); | ||
340 | printk(KERN_ERR "si=%08lx\n", si); | ||
341 | if (si & SUN4M_INT_MODULE_ERR) | ||
342 | printk(KERN_ERR "Module async error\n"); | ||
343 | if (si & SUN4M_INT_M2S_WRITE_ERR) | ||
344 | printk(KERN_ERR "MBus/SBus async error\n"); | ||
345 | if (si & SUN4M_INT_ECC_ERR) | ||
346 | printk(KERN_ERR "ECC memory error\n"); | ||
347 | if (si & SUN4M_INT_VME_ERR) | ||
348 | printk(KERN_ERR "VME async error\n"); | ||
349 | printk(KERN_ERR "you lose buddy boy...\n"); | ||
350 | show_regs(regs); | ||
351 | prom_halt(); | ||
352 | } | ||
353 | |||
354 | /* Exported for sun4m_smp.c */ | ||
355 | void sun4m_clear_profile_irq(int cpu) | ||
356 | { | ||
357 | sbus_readl(&timers_percpu[cpu]->l14_limit); | ||
299 | } | 358 | } |
300 | 359 | ||
301 | static void sun4m_load_profile_irq(int cpu, unsigned int limit) | 360 | static void sun4m_load_profile_irq(int cpu, unsigned int limit) |
302 | { | 361 | { |
303 | sun4m_timers->cpu_timers[cpu].l14_timer_limit = limit; | 362 | sbus_writel(limit, &timers_percpu[cpu]->l14_limit); |
304 | } | 363 | } |
305 | 364 | ||
306 | static void __init sun4m_init_timers(irq_handler_t counter_fn) | 365 | static void __init sun4m_init_timers(irq_handler_t counter_fn) |
307 | { | 366 | { |
308 | int reg_count, irq, cpu; | 367 | struct device_node *dp = of_find_node_by_name(NULL, "counter"); |
309 | struct linux_prom_registers cnt_regs[PROMREG_MAX]; | 368 | int i, err, len, num_cpu_timers; |
310 | int obio_node, cnt_node; | 369 | const u32 *addr; |
311 | struct resource r; | 370 | |
312 | 371 | if (!dp) { | |
313 | cnt_node = 0; | 372 | printk(KERN_ERR "sun4m_init_timers: No 'counter' node.\n"); |
314 | if((obio_node = | 373 | return; |
315 | prom_searchsiblings (prom_getchild(prom_root_node), "obio")) == 0 || | ||
316 | (obio_node = prom_getchild (obio_node)) == 0 || | ||
317 | (cnt_node = prom_searchsiblings (obio_node, "counter")) == 0) { | ||
318 | prom_printf("Cannot find /obio/counter node\n"); | ||
319 | prom_halt(); | ||
320 | } | 374 | } |
321 | reg_count = prom_getproperty(cnt_node, "reg", | 375 | |
322 | (void *) cnt_regs, sizeof(cnt_regs)); | 376 | addr = of_get_property(dp, "address", &len); |
323 | reg_count = (reg_count/sizeof(struct linux_prom_registers)); | 377 | if (!addr) { |
324 | 378 | printk(KERN_ERR "sun4m_init_timers: No 'address' prop.\n"); | |
325 | /* Apply the obio ranges to the timer registers. */ | 379 | return; |
326 | prom_apply_obio_ranges(cnt_regs, reg_count); | ||
327 | |||
328 | cnt_regs[4].phys_addr = cnt_regs[reg_count-1].phys_addr; | ||
329 | cnt_regs[4].reg_size = cnt_regs[reg_count-1].reg_size; | ||
330 | cnt_regs[4].which_io = cnt_regs[reg_count-1].which_io; | ||
331 | for(obio_node = 1; obio_node < 4; obio_node++) { | ||
332 | cnt_regs[obio_node].phys_addr = | ||
333 | cnt_regs[obio_node-1].phys_addr + PAGE_SIZE; | ||
334 | cnt_regs[obio_node].reg_size = cnt_regs[obio_node-1].reg_size; | ||
335 | cnt_regs[obio_node].which_io = cnt_regs[obio_node-1].which_io; | ||
336 | } | 380 | } |
337 | 381 | ||
338 | memset((char*)&r, 0, sizeof(struct resource)); | 382 | num_cpu_timers = (len / sizeof(u32)) - 1; |
339 | /* Map the per-cpu Counter registers. */ | 383 | for (i = 0; i < num_cpu_timers; i++) { |
340 | r.flags = cnt_regs[0].which_io; | 384 | timers_percpu[i] = (void __iomem *) |
341 | r.start = cnt_regs[0].phys_addr; | 385 | (unsigned long) addr[i]; |
342 | sun4m_timers = (struct sun4m_timer_regs *) sbus_ioremap(&r, 0, | ||
343 | PAGE_SIZE*SUN4M_NCPUS, "sun4m_cpu_cnt"); | ||
344 | /* Map the system Counter register. */ | ||
345 | /* XXX Here we expect consequent calls to yeld adjusent maps. */ | ||
346 | r.flags = cnt_regs[4].which_io; | ||
347 | r.start = cnt_regs[4].phys_addr; | ||
348 | sbus_ioremap(&r, 0, cnt_regs[4].reg_size, "sun4m_sys_cnt"); | ||
349 | |||
350 | sun4m_timers->l10_timer_limit = (((1000000/HZ) + 1) << 10); | ||
351 | master_l10_counter = &sun4m_timers->l10_cur_count; | ||
352 | master_l10_limit = &sun4m_timers->l10_timer_limit; | ||
353 | |||
354 | irq = request_irq(TIMER_IRQ, | ||
355 | counter_fn, | ||
356 | (IRQF_DISABLED | SA_STATIC_ALLOC), | ||
357 | "timer", NULL); | ||
358 | if (irq) { | ||
359 | prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ); | ||
360 | prom_halt(); | ||
361 | } | 386 | } |
362 | 387 | timers_global = (void __iomem *) | |
363 | if (!cpu_find_by_instance(1, NULL, NULL)) { | 388 | (unsigned long) addr[num_cpu_timers]; |
364 | for(cpu = 0; cpu < 4; cpu++) | 389 | |
365 | sun4m_timers->cpu_timers[cpu].l14_timer_limit = 0; | 390 | sbus_writel((((1000000/HZ) + 1) << 10), &timers_global->l10_limit); |
366 | sun4m_interrupts->set = SUN4M_INT_E14; | 391 | |
367 | } else { | 392 | master_l10_counter = &timers_global->l10_count; |
368 | sun4m_timers->cpu_timers[0].l14_timer_limit = 0; | 393 | |
394 | err = request_irq(TIMER_IRQ, counter_fn, | ||
395 | (IRQF_DISABLED | SA_STATIC_ALLOC), "timer", NULL); | ||
396 | if (err) { | ||
397 | printk(KERN_ERR "sun4m_init_timers: Register IRQ error %d.\n", | ||
398 | err); | ||
399 | return; | ||
369 | } | 400 | } |
401 | |||
402 | for (i = 0; i < num_cpu_timers; i++) | ||
403 | sbus_writel(0, &timers_percpu[i]->l14_limit); | ||
404 | if (num_cpu_timers == 4) | ||
405 | sbus_writel(SUN4M_INT_E14, &sun4m_irq_global->mask_set); | ||
406 | |||
370 | #ifdef CONFIG_SMP | 407 | #ifdef CONFIG_SMP |
371 | { | 408 | { |
372 | unsigned long flags; | 409 | unsigned long flags; |
@@ -390,70 +427,43 @@ static void __init sun4m_init_timers(irq_handler_t counter_fn) | |||
390 | 427 | ||
391 | void __init sun4m_init_IRQ(void) | 428 | void __init sun4m_init_IRQ(void) |
392 | { | 429 | { |
393 | int ie_node,i; | 430 | struct device_node *dp = of_find_node_by_name(NULL, "interrupt"); |
394 | struct linux_prom_registers int_regs[PROMREG_MAX]; | 431 | int len, i, mid, num_cpu_iregs; |
395 | int num_regs; | 432 | const u32 *addr; |
396 | struct resource r; | 433 | |
397 | int mid; | 434 | if (!dp) { |
398 | 435 | printk(KERN_ERR "sun4m_init_IRQ: No 'interrupt' node.\n"); | |
399 | local_irq_disable(); | 436 | return; |
400 | if((ie_node = prom_searchsiblings(prom_getchild(prom_root_node), "obio")) == 0 || | ||
401 | (ie_node = prom_getchild (ie_node)) == 0 || | ||
402 | (ie_node = prom_searchsiblings (ie_node, "interrupt")) == 0) { | ||
403 | prom_printf("Cannot find /obio/interrupt node\n"); | ||
404 | prom_halt(); | ||
405 | } | 437 | } |
406 | num_regs = prom_getproperty(ie_node, "reg", (char *) int_regs, | 438 | |
407 | sizeof(int_regs)); | 439 | addr = of_get_property(dp, "address", &len); |
408 | num_regs = (num_regs/sizeof(struct linux_prom_registers)); | 440 | if (!addr) { |
409 | 441 | printk(KERN_ERR "sun4m_init_IRQ: No 'address' prop.\n"); | |
410 | /* Apply the obio ranges to these registers. */ | 442 | return; |
411 | prom_apply_obio_ranges(int_regs, num_regs); | ||
412 | |||
413 | int_regs[4].phys_addr = int_regs[num_regs-1].phys_addr; | ||
414 | int_regs[4].reg_size = int_regs[num_regs-1].reg_size; | ||
415 | int_regs[4].which_io = int_regs[num_regs-1].which_io; | ||
416 | for(ie_node = 1; ie_node < 4; ie_node++) { | ||
417 | int_regs[ie_node].phys_addr = int_regs[ie_node-1].phys_addr + PAGE_SIZE; | ||
418 | int_regs[ie_node].reg_size = int_regs[ie_node-1].reg_size; | ||
419 | int_regs[ie_node].which_io = int_regs[ie_node-1].which_io; | ||
420 | } | 443 | } |
421 | 444 | ||
422 | memset((char *)&r, 0, sizeof(struct resource)); | 445 | num_cpu_iregs = (len / sizeof(u32)) - 1; |
423 | /* Map the interrupt registers for all possible cpus. */ | 446 | for (i = 0; i < num_cpu_iregs; i++) { |
424 | r.flags = int_regs[0].which_io; | 447 | sun4m_irq_percpu[i] = (void __iomem *) |
425 | r.start = int_regs[0].phys_addr; | 448 | (unsigned long) addr[i]; |
426 | sun4m_interrupts = (struct sun4m_intregs *) sbus_ioremap(&r, 0, | 449 | } |
427 | PAGE_SIZE*SUN4M_NCPUS, "interrupts_percpu"); | 450 | sun4m_irq_global = (void __iomem *) |
451 | (unsigned long) addr[num_cpu_iregs]; | ||
428 | 452 | ||
429 | /* Map the system interrupt control registers. */ | 453 | local_irq_disable(); |
430 | r.flags = int_regs[4].which_io; | ||
431 | r.start = int_regs[4].phys_addr; | ||
432 | sbus_ioremap(&r, 0, int_regs[4].reg_size, "interrupts_system"); | ||
433 | 454 | ||
434 | sun4m_interrupts->set = ~SUN4M_INT_MASKALL; | 455 | sbus_writel(~SUN4M_INT_MASKALL, &sun4m_irq_global->mask_set); |
435 | for (i = 0; !cpu_find_by_instance(i, NULL, &mid); i++) | 456 | for (i = 0; !cpu_find_by_instance(i, NULL, &mid); i++) |
436 | sun4m_interrupts->cpu_intregs[mid].clear = ~0x17fff; | 457 | sbus_writel(~0x17fff, &sun4m_irq_percpu[mid]->clear); |
437 | 458 | ||
438 | if (!cpu_find_by_instance(1, NULL, NULL)) { | 459 | if (num_cpu_iregs == 4) |
439 | /* system wide interrupts go to cpu 0, this should always | 460 | sbus_writel(0, &sun4m_irq_global->interrupt_target); |
440 | * be safe because it is guaranteed to be fitted or OBP doesn't | 461 | |
441 | * come up | ||
442 | * | ||
443 | * Not sure, but writing here on SLAVIO systems may puke | ||
444 | * so I don't do it unless there is more than 1 cpu. | ||
445 | */ | ||
446 | irq_rcvreg = (unsigned long *) | ||
447 | &sun4m_interrupts->undirected_target; | ||
448 | sun4m_interrupts->undirected_target = 0; | ||
449 | } | ||
450 | BTFIXUPSET_CALL(sbint_to_irq, sun4m_sbint_to_irq, BTFIXUPCALL_NORM); | ||
451 | BTFIXUPSET_CALL(enable_irq, sun4m_enable_irq, BTFIXUPCALL_NORM); | 462 | BTFIXUPSET_CALL(enable_irq, sun4m_enable_irq, BTFIXUPCALL_NORM); |
452 | BTFIXUPSET_CALL(disable_irq, sun4m_disable_irq, BTFIXUPCALL_NORM); | 463 | BTFIXUPSET_CALL(disable_irq, sun4m_disable_irq, BTFIXUPCALL_NORM); |
453 | BTFIXUPSET_CALL(enable_pil_irq, sun4m_enable_pil_irq, BTFIXUPCALL_NORM); | 464 | BTFIXUPSET_CALL(enable_pil_irq, sun4m_enable_pil_irq, BTFIXUPCALL_NORM); |
454 | BTFIXUPSET_CALL(disable_pil_irq, sun4m_disable_pil_irq, BTFIXUPCALL_NORM); | 465 | BTFIXUPSET_CALL(disable_pil_irq, sun4m_disable_pil_irq, BTFIXUPCALL_NORM); |
455 | BTFIXUPSET_CALL(clear_clock_irq, sun4m_clear_clock_irq, BTFIXUPCALL_NORM); | 466 | BTFIXUPSET_CALL(clear_clock_irq, sun4m_clear_clock_irq, BTFIXUPCALL_NORM); |
456 | BTFIXUPSET_CALL(clear_profile_irq, sun4m_clear_profile_irq, BTFIXUPCALL_NORM); | ||
457 | BTFIXUPSET_CALL(load_profile_irq, sun4m_load_profile_irq, BTFIXUPCALL_NORM); | 467 | BTFIXUPSET_CALL(load_profile_irq, sun4m_load_profile_irq, BTFIXUPCALL_NORM); |
458 | sparc_init_timers = sun4m_init_timers; | 468 | sparc_init_timers = sun4m_init_timers; |
459 | #ifdef CONFIG_SMP | 469 | #ifdef CONFIG_SMP |
@@ -461,5 +471,6 @@ void __init sun4m_init_IRQ(void) | |||
461 | BTFIXUPSET_CALL(clear_cpu_int, sun4m_clear_ipi, BTFIXUPCALL_NORM); | 471 | BTFIXUPSET_CALL(clear_cpu_int, sun4m_clear_ipi, BTFIXUPCALL_NORM); |
462 | BTFIXUPSET_CALL(set_irq_udt, sun4m_set_udt, BTFIXUPCALL_NORM); | 472 | BTFIXUPSET_CALL(set_irq_udt, sun4m_set_udt, BTFIXUPCALL_NORM); |
463 | #endif | 473 | #endif |
474 | |||
464 | /* Cannot enable interrupts until OBP ticker is disabled. */ | 475 | /* Cannot enable interrupts until OBP ticker is disabled. */ |
465 | } | 476 | } |
diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c index a14a76ac7f36..0c564ba9e709 100644 --- a/arch/sparc/kernel/sun4m_smp.c +++ b/arch/sparc/kernel/sun4m_smp.c | |||
@@ -71,6 +71,8 @@ void __cpuinit smp4m_callin(void) | |||
71 | local_flush_cache_all(); | 71 | local_flush_cache_all(); |
72 | local_flush_tlb_all(); | 72 | local_flush_tlb_all(); |
73 | 73 | ||
74 | notify_cpu_starting(cpuid); | ||
75 | |||
74 | /* Get our local ticker going. */ | 76 | /* Get our local ticker going. */ |
75 | smp_setup_percpu_timer(); | 77 | smp_setup_percpu_timer(); |
76 | 78 | ||
@@ -313,6 +315,8 @@ void smp4m_cross_call_irq(void) | |||
313 | ccall_info.processors_out[i] = 1; | 315 | ccall_info.processors_out[i] = 1; |
314 | } | 316 | } |
315 | 317 | ||
318 | extern void sun4m_clear_profile_irq(int cpu); | ||
319 | |||
316 | void smp4m_percpu_timer_interrupt(struct pt_regs *regs) | 320 | void smp4m_percpu_timer_interrupt(struct pt_regs *regs) |
317 | { | 321 | { |
318 | struct pt_regs *old_regs; | 322 | struct pt_regs *old_regs; |
@@ -320,7 +324,7 @@ void smp4m_percpu_timer_interrupt(struct pt_regs *regs) | |||
320 | 324 | ||
321 | old_regs = set_irq_regs(regs); | 325 | old_regs = set_irq_regs(regs); |
322 | 326 | ||
323 | clear_profile_irq(cpu); | 327 | sun4m_clear_profile_irq(cpu); |
324 | 328 | ||
325 | profile_tick(CPU_PROFILING); | 329 | profile_tick(CPU_PROFILING); |
326 | 330 | ||
diff --git a/arch/sparc/kernel/sun4setup.c b/arch/sparc/kernel/sun4setup.c deleted file mode 100644 index 229a52f55f16..000000000000 --- a/arch/sparc/kernel/sun4setup.c +++ /dev/null | |||
@@ -1,75 +0,0 @@ | |||
1 | /* sun4setup.c: Setup the hardware address of various items in the sun4 | ||
2 | * architecture. Called from idprom_init | ||
3 | * | ||
4 | * Copyright (C) 1998 Chris G. Davis (cdavis@cois.on.ca) | ||
5 | */ | ||
6 | |||
7 | #include <asm/page.h> | ||
8 | #include <asm/oplib.h> | ||
9 | #include <asm/idprom.h> | ||
10 | #include <asm/sun4paddr.h> | ||
11 | #include <asm/machines.h> | ||
12 | |||
13 | int sun4_memreg_physaddr; | ||
14 | int sun4_ie_physaddr; | ||
15 | int sun4_clock_physaddr; | ||
16 | int sun4_timer_physaddr; | ||
17 | int sun4_eth_physaddr; | ||
18 | int sun4_si_physaddr; | ||
19 | int sun4_bwtwo_physaddr; | ||
20 | int sun4_zs0_physaddr; | ||
21 | int sun4_zs1_physaddr; | ||
22 | int sun4_dma_physaddr; | ||
23 | int sun4_esp_physaddr; | ||
24 | int sun4_ie_physaddr; | ||
25 | |||
26 | void __init sun4setup(void) | ||
27 | { | ||
28 | printk("Sun4 Hardware Setup v1.0 18/May/98 Chris Davis (cdavis@cois.on.ca). "); | ||
29 | /* | ||
30 | setup standard sun4 info | ||
31 | */ | ||
32 | sun4_ie_physaddr=SUN4_IE_PHYSADDR; | ||
33 | |||
34 | /* | ||
35 | setup model specific info | ||
36 | */ | ||
37 | switch(idprom->id_machtype) { | ||
38 | case (SM_SUN4 | SM_4_260 ): | ||
39 | printk("Setup for a SUN4/260\n"); | ||
40 | sun4_memreg_physaddr=SUN4_200_MEMREG_PHYSADDR; | ||
41 | sun4_clock_physaddr=SUN4_200_CLOCK_PHYSADDR; | ||
42 | sun4_timer_physaddr=SUN4_UNUSED_PHYSADDR; | ||
43 | sun4_eth_physaddr=SUN4_200_ETH_PHYSADDR; | ||
44 | sun4_si_physaddr=SUN4_200_SI_PHYSADDR; | ||
45 | sun4_bwtwo_physaddr=SUN4_200_BWTWO_PHYSADDR; | ||
46 | sun4_dma_physaddr=SUN4_UNUSED_PHYSADDR; | ||
47 | sun4_esp_physaddr=SUN4_UNUSED_PHYSADDR; | ||
48 | break; | ||
49 | case (SM_SUN4 | SM_4_330 ): | ||
50 | printk("Setup for a SUN4/330\n"); | ||
51 | sun4_memreg_physaddr=SUN4_300_MEMREG_PHYSADDR; | ||
52 | sun4_clock_physaddr=SUN4_300_CLOCK_PHYSADDR; | ||
53 | sun4_timer_physaddr=SUN4_300_TIMER_PHYSADDR; | ||
54 | sun4_eth_physaddr=SUN4_300_ETH_PHYSADDR; | ||
55 | sun4_si_physaddr=SUN4_UNUSED_PHYSADDR; | ||
56 | sun4_bwtwo_physaddr=SUN4_300_BWTWO_PHYSADDR; | ||
57 | sun4_dma_physaddr=SUN4_300_DMA_PHYSADDR; | ||
58 | sun4_esp_physaddr=SUN4_300_ESP_PHYSADDR; | ||
59 | break; | ||
60 | case (SM_SUN4 | SM_4_470 ): | ||
61 | printk("Setup for a SUN4/470\n"); | ||
62 | sun4_memreg_physaddr=SUN4_400_MEMREG_PHYSADDR; | ||
63 | sun4_clock_physaddr=SUN4_400_CLOCK_PHYSADDR; | ||
64 | sun4_timer_physaddr=SUN4_400_TIMER_PHYSADDR; | ||
65 | sun4_eth_physaddr=SUN4_400_ETH_PHYSADDR; | ||
66 | sun4_si_physaddr=SUN4_UNUSED_PHYSADDR; | ||
67 | sun4_bwtwo_physaddr=SUN4_400_BWTWO_PHYSADDR; | ||
68 | sun4_dma_physaddr=SUN4_400_DMA_PHYSADDR; | ||
69 | sun4_esp_physaddr=SUN4_400_ESP_PHYSADDR; | ||
70 | break; | ||
71 | default: | ||
72 | ; | ||
73 | } | ||
74 | } | ||
75 | |||
diff --git a/arch/sparc/kernel/sys_sparc.c b/arch/sparc/kernel/sys_sparc.c index 4d73421559c3..03035c852a43 100644 --- a/arch/sparc/kernel/sys_sparc.c +++ b/arch/sparc/kernel/sys_sparc.c | |||
@@ -53,7 +53,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi | |||
53 | /* See asm-sparc/uaccess.h */ | 53 | /* See asm-sparc/uaccess.h */ |
54 | if (len > TASK_SIZE - PAGE_SIZE) | 54 | if (len > TASK_SIZE - PAGE_SIZE) |
55 | return -ENOMEM; | 55 | return -ENOMEM; |
56 | if (ARCH_SUN4C_SUN4 && len > 0x20000000) | 56 | if (ARCH_SUN4C && len > 0x20000000) |
57 | return -ENOMEM; | 57 | return -ENOMEM; |
58 | if (!addr) | 58 | if (!addr) |
59 | addr = TASK_UNMAPPED_BASE; | 59 | addr = TASK_UNMAPPED_BASE; |
@@ -65,7 +65,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi | |||
65 | 65 | ||
66 | for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) { | 66 | for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) { |
67 | /* At this point: (!vmm || addr < vmm->vm_end). */ | 67 | /* At this point: (!vmm || addr < vmm->vm_end). */ |
68 | if (ARCH_SUN4C_SUN4 && addr < 0xe0000000 && 0x20000000 - len < addr) { | 68 | if (ARCH_SUN4C && addr < 0xe0000000 && 0x20000000 - len < addr) { |
69 | addr = PAGE_OFFSET; | 69 | addr = PAGE_OFFSET; |
70 | vmm = find_vma(current->mm, PAGE_OFFSET); | 70 | vmm = find_vma(current->mm, PAGE_OFFSET); |
71 | } | 71 | } |
@@ -81,7 +81,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi | |||
81 | 81 | ||
82 | asmlinkage unsigned long sparc_brk(unsigned long brk) | 82 | asmlinkage unsigned long sparc_brk(unsigned long brk) |
83 | { | 83 | { |
84 | if(ARCH_SUN4C_SUN4) { | 84 | if(ARCH_SUN4C) { |
85 | if ((brk & 0xe0000000) != (current->mm->brk & 0xe0000000)) | 85 | if ((brk & 0xe0000000) != (current->mm->brk & 0xe0000000)) |
86 | return current->mm->brk; | 86 | return current->mm->brk; |
87 | } | 87 | } |
@@ -221,7 +221,7 @@ out: | |||
221 | 221 | ||
222 | int sparc_mmap_check(unsigned long addr, unsigned long len) | 222 | int sparc_mmap_check(unsigned long addr, unsigned long len) |
223 | { | 223 | { |
224 | if (ARCH_SUN4C_SUN4 && | 224 | if (ARCH_SUN4C && |
225 | (len > 0x20000000 || | 225 | (len > 0x20000000 || |
226 | (addr < 0xe0000000 && addr + len > 0x20000000))) | 226 | (addr < 0xe0000000 && addr + len > 0x20000000))) |
227 | return -EINVAL; | 227 | return -EINVAL; |
diff --git a/arch/sparc/kernel/tick14.c b/arch/sparc/kernel/tick14.c index 707bfda86570..138bbf5f8724 100644 --- a/arch/sparc/kernel/tick14.c +++ b/arch/sparc/kernel/tick14.c | |||
@@ -1,31 +1,12 @@ | |||
1 | /* tick14.c | 1 | /* tick14.c |
2 | * linux/arch/sparc/kernel/tick14.c | ||
3 | * | 2 | * |
4 | * Copyright (C) 1996 David Redman (djhr@tadpole.co.uk) | 3 | * Copyright (C) 1996 David Redman (djhr@tadpole.co.uk) |
5 | * | 4 | * |
6 | * This file handles the Sparc specific level14 ticker | 5 | * This file handles the Sparc specific level14 ticker |
7 | * This is really useful for profiling OBP uses it for keyboard | 6 | * This is really useful for profiling OBP uses it for keyboard |
8 | * aborts and other stuff. | 7 | * aborts and other stuff. |
9 | * | ||
10 | * | ||
11 | */ | 8 | */ |
12 | #include <linux/errno.h> | ||
13 | #include <linux/sched.h> | ||
14 | #include <linux/kernel.h> | 9 | #include <linux/kernel.h> |
15 | #include <linux/param.h> | ||
16 | #include <linux/string.h> | ||
17 | #include <linux/mm.h> | ||
18 | #include <linux/timex.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | |||
21 | #include <asm/oplib.h> | ||
22 | #include <asm/timer.h> | ||
23 | #include <asm/mostek.h> | ||
24 | #include <asm/system.h> | ||
25 | #include <asm/irq.h> | ||
26 | #include <asm/io.h> | ||
27 | |||
28 | #include "irq.h" | ||
29 | 10 | ||
30 | extern unsigned long lvl14_save[5]; | 11 | extern unsigned long lvl14_save[5]; |
31 | static unsigned long *linux_lvl14 = NULL; | 12 | static unsigned long *linux_lvl14 = NULL; |
@@ -56,31 +37,3 @@ void install_obp_ticker(void) | |||
56 | linux_lvl14[2] = obp_lvl14[2]; | 37 | linux_lvl14[2] = obp_lvl14[2]; |
57 | linux_lvl14[3] = obp_lvl14[3]; | 38 | linux_lvl14[3] = obp_lvl14[3]; |
58 | } | 39 | } |
59 | |||
60 | void claim_ticker14(irq_handler_t handler, | ||
61 | int irq_nr, unsigned int timeout ) | ||
62 | { | ||
63 | int cpu = smp_processor_id(); | ||
64 | |||
65 | /* first we copy the obp handler instructions | ||
66 | */ | ||
67 | __disable_irq(irq_nr); | ||
68 | if (!handler) | ||
69 | return; | ||
70 | |||
71 | linux_lvl14 = (unsigned long *)lvl14_save[4]; | ||
72 | obp_lvl14[0] = linux_lvl14[0]; | ||
73 | obp_lvl14[1] = linux_lvl14[1]; | ||
74 | obp_lvl14[2] = linux_lvl14[2]; | ||
75 | obp_lvl14[3] = linux_lvl14[3]; | ||
76 | |||
77 | if (!request_irq(irq_nr, | ||
78 | handler, | ||
79 | (IRQF_DISABLED | SA_STATIC_ALLOC), | ||
80 | "counter14", | ||
81 | NULL)) { | ||
82 | install_linux_ticker(); | ||
83 | load_profile_irq(cpu, timeout); | ||
84 | __enable_irq(irq_nr); | ||
85 | } | ||
86 | } | ||
diff --git a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c index 0762f5db1924..62c1d94cb434 100644 --- a/arch/sparc/kernel/time.c +++ b/arch/sparc/kernel/time.c | |||
@@ -23,22 +23,24 @@ | |||
23 | #include <linux/mm.h> | 23 | #include <linux/mm.h> |
24 | #include <linux/interrupt.h> | 24 | #include <linux/interrupt.h> |
25 | #include <linux/time.h> | 25 | #include <linux/time.h> |
26 | #include <linux/rtc.h> | ||
27 | #include <linux/rtc/m48t59.h> | ||
26 | #include <linux/timex.h> | 28 | #include <linux/timex.h> |
27 | #include <linux/init.h> | 29 | #include <linux/init.h> |
28 | #include <linux/pci.h> | 30 | #include <linux/pci.h> |
29 | #include <linux/ioport.h> | 31 | #include <linux/ioport.h> |
30 | #include <linux/profile.h> | 32 | #include <linux/profile.h> |
33 | #include <linux/of.h> | ||
31 | #include <linux/of_device.h> | 34 | #include <linux/of_device.h> |
35 | #include <linux/platform_device.h> | ||
32 | 36 | ||
33 | #include <asm/oplib.h> | 37 | #include <asm/oplib.h> |
34 | #include <asm/timer.h> | 38 | #include <asm/timer.h> |
35 | #include <asm/mostek.h> | ||
36 | #include <asm/system.h> | 39 | #include <asm/system.h> |
37 | #include <asm/irq.h> | 40 | #include <asm/irq.h> |
38 | #include <asm/io.h> | 41 | #include <asm/io.h> |
39 | #include <asm/idprom.h> | 42 | #include <asm/idprom.h> |
40 | #include <asm/machines.h> | 43 | #include <asm/machines.h> |
41 | #include <asm/sun4paddr.h> | ||
42 | #include <asm/page.h> | 44 | #include <asm/page.h> |
43 | #include <asm/pcic.h> | 45 | #include <asm/pcic.h> |
44 | #include <asm/irq_regs.h> | 46 | #include <asm/irq_regs.h> |
@@ -46,34 +48,9 @@ | |||
46 | #include "irq.h" | 48 | #include "irq.h" |
47 | 49 | ||
48 | DEFINE_SPINLOCK(rtc_lock); | 50 | DEFINE_SPINLOCK(rtc_lock); |
49 | static enum sparc_clock_type sp_clock_typ; | ||
50 | DEFINE_SPINLOCK(mostek_lock); | ||
51 | void __iomem *mstk48t02_regs = NULL; | ||
52 | static struct mostek48t08 __iomem *mstk48t08_regs = NULL; | ||
53 | static int set_rtc_mmss(unsigned long); | 51 | static int set_rtc_mmss(unsigned long); |
54 | static int sbus_do_settimeofday(struct timespec *tv); | 52 | static int sbus_do_settimeofday(struct timespec *tv); |
55 | 53 | ||
56 | #ifdef CONFIG_SUN4 | ||
57 | struct intersil *intersil_clock; | ||
58 | #define intersil_cmd(intersil_reg, intsil_cmd) intersil_reg->int_cmd_reg = \ | ||
59 | (intsil_cmd) | ||
60 | |||
61 | #define intersil_intr(intersil_reg, intsil_cmd) intersil_reg->int_intr_reg = \ | ||
62 | (intsil_cmd) | ||
63 | |||
64 | #define intersil_start(intersil_reg) intersil_cmd(intersil_reg, \ | ||
65 | ( INTERSIL_START | INTERSIL_32K | INTERSIL_NORMAL | INTERSIL_24H |\ | ||
66 | INTERSIL_INTR_ENABLE)) | ||
67 | |||
68 | #define intersil_stop(intersil_reg) intersil_cmd(intersil_reg, \ | ||
69 | ( INTERSIL_STOP | INTERSIL_32K | INTERSIL_NORMAL | INTERSIL_24H |\ | ||
70 | INTERSIL_INTR_ENABLE)) | ||
71 | |||
72 | #define intersil_read_intr(intersil_reg, towhere) towhere = \ | ||
73 | intersil_reg->int_intr_reg | ||
74 | |||
75 | #endif | ||
76 | |||
77 | unsigned long profile_pc(struct pt_regs *regs) | 54 | unsigned long profile_pc(struct pt_regs *regs) |
78 | { | 55 | { |
79 | extern char __copy_user_begin[], __copy_user_end[]; | 56 | extern char __copy_user_begin[], __copy_user_end[]; |
@@ -96,7 +73,6 @@ unsigned long profile_pc(struct pt_regs *regs) | |||
96 | EXPORT_SYMBOL(profile_pc); | 73 | EXPORT_SYMBOL(profile_pc); |
97 | 74 | ||
98 | __volatile__ unsigned int *master_l10_counter; | 75 | __volatile__ unsigned int *master_l10_counter; |
99 | __volatile__ unsigned int *master_l10_limit; | ||
100 | 76 | ||
101 | /* | 77 | /* |
102 | * timer_interrupt() needs to keep up the real-time clock, | 78 | * timer_interrupt() needs to keep up the real-time clock, |
@@ -116,15 +92,7 @@ static irqreturn_t timer_interrupt(int dummy, void *dev_id) | |||
116 | 92 | ||
117 | /* Protect counter clear so that do_gettimeoffset works */ | 93 | /* Protect counter clear so that do_gettimeoffset works */ |
118 | write_seqlock(&xtime_lock); | 94 | write_seqlock(&xtime_lock); |
119 | #ifdef CONFIG_SUN4 | 95 | |
120 | if((idprom->id_machtype == (SM_SUN4 | SM_4_260)) || | ||
121 | (idprom->id_machtype == (SM_SUN4 | SM_4_110))) { | ||
122 | int temp; | ||
123 | intersil_read_intr(intersil_clock, temp); | ||
124 | /* re-enable the irq */ | ||
125 | enable_pil_irq(10); | ||
126 | } | ||
127 | #endif | ||
128 | clear_clock_irq(); | 96 | clear_clock_irq(); |
129 | 97 | ||
130 | do_timer(1); | 98 | do_timer(1); |
@@ -147,157 +115,56 @@ static irqreturn_t timer_interrupt(int dummy, void *dev_id) | |||
147 | return IRQ_HANDLED; | 115 | return IRQ_HANDLED; |
148 | } | 116 | } |
149 | 117 | ||
150 | /* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */ | 118 | static unsigned char mostek_read_byte(struct device *dev, u32 ofs) |
151 | static void __devinit kick_start_clock(void) | ||
152 | { | 119 | { |
153 | struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs; | 120 | struct platform_device *pdev = to_platform_device(dev); |
154 | unsigned char sec; | 121 | struct m48t59_plat_data *pdata = pdev->dev.platform_data; |
155 | int i, count; | 122 | void __iomem *regs = pdata->ioaddr; |
156 | 123 | unsigned char val = readb(regs + ofs); | |
157 | prom_printf("CLOCK: Clock was stopped. Kick start "); | 124 | |
158 | 125 | /* the year 0 is 1968 */ | |
159 | spin_lock_irq(&mostek_lock); | 126 | if (ofs == pdata->offset + M48T59_YEAR) { |
160 | 127 | val += 0x68; | |
161 | /* Turn on the kick start bit to start the oscillator. */ | 128 | if ((val & 0xf) > 9) |
162 | regs->creg |= MSTK_CREG_WRITE; | 129 | val += 6; |
163 | regs->sec &= ~MSTK_STOP; | ||
164 | regs->hour |= MSTK_KICK_START; | ||
165 | regs->creg &= ~MSTK_CREG_WRITE; | ||
166 | |||
167 | spin_unlock_irq(&mostek_lock); | ||
168 | |||
169 | /* Delay to allow the clock oscillator to start. */ | ||
170 | sec = MSTK_REG_SEC(regs); | ||
171 | for (i = 0; i < 3; i++) { | ||
172 | while (sec == MSTK_REG_SEC(regs)) | ||
173 | for (count = 0; count < 100000; count++) | ||
174 | /* nothing */ ; | ||
175 | prom_printf("."); | ||
176 | sec = regs->sec; | ||
177 | } | ||
178 | prom_printf("\n"); | ||
179 | |||
180 | spin_lock_irq(&mostek_lock); | ||
181 | |||
182 | /* Turn off kick start and set a "valid" time and date. */ | ||
183 | regs->creg |= MSTK_CREG_WRITE; | ||
184 | regs->hour &= ~MSTK_KICK_START; | ||
185 | MSTK_SET_REG_SEC(regs,0); | ||
186 | MSTK_SET_REG_MIN(regs,0); | ||
187 | MSTK_SET_REG_HOUR(regs,0); | ||
188 | MSTK_SET_REG_DOW(regs,5); | ||
189 | MSTK_SET_REG_DOM(regs,1); | ||
190 | MSTK_SET_REG_MONTH(regs,8); | ||
191 | MSTK_SET_REG_YEAR(regs,1996 - MSTK_YEAR_ZERO); | ||
192 | regs->creg &= ~MSTK_CREG_WRITE; | ||
193 | |||
194 | spin_unlock_irq(&mostek_lock); | ||
195 | |||
196 | /* Ensure the kick start bit is off. If it isn't, turn it off. */ | ||
197 | while (regs->hour & MSTK_KICK_START) { | ||
198 | prom_printf("CLOCK: Kick start still on!\n"); | ||
199 | |||
200 | spin_lock_irq(&mostek_lock); | ||
201 | regs->creg |= MSTK_CREG_WRITE; | ||
202 | regs->hour &= ~MSTK_KICK_START; | ||
203 | regs->creg &= ~MSTK_CREG_WRITE; | ||
204 | spin_unlock_irq(&mostek_lock); | ||
205 | } | 130 | } |
206 | 131 | return val; | |
207 | prom_printf("CLOCK: Kick start procedure successful.\n"); | ||
208 | } | ||
209 | |||
210 | /* Return nonzero if the clock chip battery is low. */ | ||
211 | static inline int has_low_battery(void) | ||
212 | { | ||
213 | struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs; | ||
214 | unsigned char data1, data2; | ||
215 | |||
216 | spin_lock_irq(&mostek_lock); | ||
217 | data1 = regs->eeprom[0]; /* Read some data. */ | ||
218 | regs->eeprom[0] = ~data1; /* Write back the complement. */ | ||
219 | data2 = regs->eeprom[0]; /* Read back the complement. */ | ||
220 | regs->eeprom[0] = data1; /* Restore the original value. */ | ||
221 | spin_unlock_irq(&mostek_lock); | ||
222 | |||
223 | return (data1 == data2); /* Was the write blocked? */ | ||
224 | } | 132 | } |
225 | 133 | ||
226 | static void __devinit mostek_set_system_time(void) | 134 | static void mostek_write_byte(struct device *dev, u32 ofs, u8 val) |
227 | { | 135 | { |
228 | unsigned int year, mon, day, hour, min, sec; | 136 | struct platform_device *pdev = to_platform_device(dev); |
229 | struct mostek48t02 *mregs; | 137 | struct m48t59_plat_data *pdata = pdev->dev.platform_data; |
230 | 138 | void __iomem *regs = pdata->ioaddr; | |
231 | mregs = (struct mostek48t02 *)mstk48t02_regs; | 139 | |
232 | if(!mregs) { | 140 | if (ofs == pdata->offset + M48T59_YEAR) { |
233 | prom_printf("Something wrong, clock regs not mapped yet.\n"); | 141 | if (val < 0x68) |
234 | prom_halt(); | 142 | val += 0x32; |
235 | } | 143 | else |
236 | spin_lock_irq(&mostek_lock); | 144 | val -= 0x68; |
237 | mregs->creg |= MSTK_CREG_READ; | 145 | if ((val & 0xf) > 9) |
238 | sec = MSTK_REG_SEC(mregs); | 146 | val += 6; |
239 | min = MSTK_REG_MIN(mregs); | 147 | if ((val & 0xf0) > 0x9A) |
240 | hour = MSTK_REG_HOUR(mregs); | 148 | val += 0x60; |
241 | day = MSTK_REG_DOM(mregs); | 149 | } |
242 | mon = MSTK_REG_MONTH(mregs); | 150 | writeb(val, regs + ofs); |
243 | year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) ); | ||
244 | xtime.tv_sec = mktime(year, mon, day, hour, min, sec); | ||
245 | xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); | ||
246 | set_normalized_timespec(&wall_to_monotonic, | ||
247 | -xtime.tv_sec, -xtime.tv_nsec); | ||
248 | mregs->creg &= ~MSTK_CREG_READ; | ||
249 | spin_unlock_irq(&mostek_lock); | ||
250 | } | 151 | } |
251 | 152 | ||
252 | /* Probe for the real time clock chip on Sun4 */ | 153 | static struct m48t59_plat_data m48t59_data = { |
253 | static inline void sun4_clock_probe(void) | 154 | .read_byte = mostek_read_byte, |
254 | { | 155 | .write_byte = mostek_write_byte, |
255 | #ifdef CONFIG_SUN4 | 156 | }; |
256 | int temp; | ||
257 | struct resource r; | ||
258 | |||
259 | memset(&r, 0, sizeof(r)); | ||
260 | if( idprom->id_machtype == (SM_SUN4 | SM_4_330) ) { | ||
261 | sp_clock_typ = MSTK48T02; | ||
262 | r.start = sun4_clock_physaddr; | ||
263 | mstk48t02_regs = sbus_ioremap(&r, 0, | ||
264 | sizeof(struct mostek48t02), NULL); | ||
265 | mstk48t08_regs = NULL; /* To catch weirdness */ | ||
266 | intersil_clock = NULL; /* just in case */ | ||
267 | |||
268 | /* Kick start the clock if it is completely stopped. */ | ||
269 | if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP) | ||
270 | kick_start_clock(); | ||
271 | } else if( idprom->id_machtype == (SM_SUN4 | SM_4_260)) { | ||
272 | /* intersil setup code */ | ||
273 | printk("Clock: INTERSIL at %8x ",sun4_clock_physaddr); | ||
274 | sp_clock_typ = INTERSIL; | ||
275 | r.start = sun4_clock_physaddr; | ||
276 | intersil_clock = (struct intersil *) | ||
277 | sbus_ioremap(&r, 0, sizeof(*intersil_clock), "intersil"); | ||
278 | mstk48t02_regs = 0; /* just be sure */ | ||
279 | mstk48t08_regs = NULL; /* ditto */ | ||
280 | /* initialise the clock */ | ||
281 | |||
282 | intersil_intr(intersil_clock,INTERSIL_INT_100HZ); | ||
283 | |||
284 | intersil_start(intersil_clock); | ||
285 | |||
286 | intersil_read_intr(intersil_clock, temp); | ||
287 | while (!(temp & 0x80)) | ||
288 | intersil_read_intr(intersil_clock, temp); | ||
289 | |||
290 | intersil_read_intr(intersil_clock, temp); | ||
291 | while (!(temp & 0x80)) | ||
292 | intersil_read_intr(intersil_clock, temp); | ||
293 | |||
294 | intersil_stop(intersil_clock); | ||
295 | 157 | ||
296 | } | 158 | /* resource is set at runtime */ |
297 | #endif | 159 | static struct platform_device m48t59_rtc = { |
298 | } | 160 | .name = "rtc-m48t59", |
161 | .id = 0, | ||
162 | .num_resources = 1, | ||
163 | .dev = { | ||
164 | .platform_data = &m48t59_data, | ||
165 | }, | ||
166 | }; | ||
299 | 167 | ||
300 | #ifndef CONFIG_SUN4 | ||
301 | static int __devinit clock_probe(struct of_device *op, const struct of_device_id *match) | 168 | static int __devinit clock_probe(struct of_device *op, const struct of_device_id *match) |
302 | { | 169 | { |
303 | struct device_node *dp = op->node; | 170 | struct device_node *dp = op->node; |
@@ -306,38 +173,26 @@ static int __devinit clock_probe(struct of_device *op, const struct of_device_id | |||
306 | if (!model) | 173 | if (!model) |
307 | return -ENODEV; | 174 | return -ENODEV; |
308 | 175 | ||
176 | m48t59_rtc.resource = &op->resource[0]; | ||
309 | if (!strcmp(model, "mk48t02")) { | 177 | if (!strcmp(model, "mk48t02")) { |
310 | sp_clock_typ = MSTK48T02; | ||
311 | |||
312 | /* Map the clock register io area read-only */ | 178 | /* Map the clock register io area read-only */ |
313 | mstk48t02_regs = of_ioremap(&op->resource[0], 0, | 179 | m48t59_data.ioaddr = of_ioremap(&op->resource[0], 0, |
314 | sizeof(struct mostek48t02), | 180 | 2048, "rtc-m48t59"); |
315 | "mk48t02"); | 181 | m48t59_data.type = M48T59RTC_TYPE_M48T02; |
316 | mstk48t08_regs = NULL; /* To catch weirdness */ | ||
317 | } else if (!strcmp(model, "mk48t08")) { | 182 | } else if (!strcmp(model, "mk48t08")) { |
318 | sp_clock_typ = MSTK48T08; | 183 | m48t59_data.ioaddr = of_ioremap(&op->resource[0], 0, |
319 | mstk48t08_regs = of_ioremap(&op->resource[0], 0, | 184 | 8192, "rtc-m48t59"); |
320 | sizeof(struct mostek48t08), | 185 | m48t59_data.type = M48T59RTC_TYPE_M48T08; |
321 | "mk48t08"); | ||
322 | |||
323 | mstk48t02_regs = &mstk48t08_regs->regs; | ||
324 | } else | 186 | } else |
325 | return -ENODEV; | 187 | return -ENODEV; |
326 | 188 | ||
327 | /* Report a low battery voltage condition. */ | 189 | if (platform_device_register(&m48t59_rtc) < 0) |
328 | if (has_low_battery()) | 190 | printk(KERN_ERR "Registering RTC device failed\n"); |
329 | printk(KERN_CRIT "NVRAM: Low battery voltage!\n"); | ||
330 | |||
331 | /* Kick start the clock if it is completely stopped. */ | ||
332 | if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP) | ||
333 | kick_start_clock(); | ||
334 | |||
335 | mostek_set_system_time(); | ||
336 | 191 | ||
337 | return 0; | 192 | return 0; |
338 | } | 193 | } |
339 | 194 | ||
340 | static struct of_device_id clock_match[] = { | 195 | static struct of_device_id __initdata clock_match[] = { |
341 | { | 196 | { |
342 | .name = "eeprom", | 197 | .name = "eeprom", |
343 | }, | 198 | }, |
@@ -348,7 +203,7 @@ static struct of_platform_driver clock_driver = { | |||
348 | .match_table = clock_match, | 203 | .match_table = clock_match, |
349 | .probe = clock_probe, | 204 | .probe = clock_probe, |
350 | .driver = { | 205 | .driver = { |
351 | .name = "clock", | 206 | .name = "rtc", |
352 | }, | 207 | }, |
353 | }; | 208 | }; |
354 | 209 | ||
@@ -364,7 +219,6 @@ static int __init clock_init(void) | |||
364 | * need to see the clock registers. | 219 | * need to see the clock registers. |
365 | */ | 220 | */ |
366 | fs_initcall(clock_init); | 221 | fs_initcall(clock_init); |
367 | #endif /* !CONFIG_SUN4 */ | ||
368 | 222 | ||
369 | static void __init sbus_time_init(void) | 223 | static void __init sbus_time_init(void) |
370 | { | 224 | { |
@@ -372,51 +226,8 @@ static void __init sbus_time_init(void) | |||
372 | BTFIXUPSET_CALL(bus_do_settimeofday, sbus_do_settimeofday, BTFIXUPCALL_NORM); | 226 | BTFIXUPSET_CALL(bus_do_settimeofday, sbus_do_settimeofday, BTFIXUPCALL_NORM); |
373 | btfixup(); | 227 | btfixup(); |
374 | 228 | ||
375 | if (ARCH_SUN4) | ||
376 | sun4_clock_probe(); | ||
377 | |||
378 | sparc_init_timers(timer_interrupt); | 229 | sparc_init_timers(timer_interrupt); |
379 | 230 | ||
380 | #ifdef CONFIG_SUN4 | ||
381 | if(idprom->id_machtype == (SM_SUN4 | SM_4_330)) { | ||
382 | mostek_set_system_time(); | ||
383 | } else if(idprom->id_machtype == (SM_SUN4 | SM_4_260) ) { | ||
384 | /* initialise the intersil on sun4 */ | ||
385 | unsigned int year, mon, day, hour, min, sec; | ||
386 | int temp; | ||
387 | struct intersil *iregs; | ||
388 | |||
389 | iregs=intersil_clock; | ||
390 | if(!iregs) { | ||
391 | prom_printf("Something wrong, clock regs not mapped yet.\n"); | ||
392 | prom_halt(); | ||
393 | } | ||
394 | |||
395 | intersil_intr(intersil_clock,INTERSIL_INT_100HZ); | ||
396 | disable_pil_irq(10); | ||
397 | intersil_stop(iregs); | ||
398 | intersil_read_intr(intersil_clock, temp); | ||
399 | |||
400 | temp = iregs->clk.int_csec; | ||
401 | |||
402 | sec = iregs->clk.int_sec; | ||
403 | min = iregs->clk.int_min; | ||
404 | hour = iregs->clk.int_hour; | ||
405 | day = iregs->clk.int_day; | ||
406 | mon = iregs->clk.int_month; | ||
407 | year = MSTK_CVT_YEAR(iregs->clk.int_year); | ||
408 | |||
409 | enable_pil_irq(10); | ||
410 | intersil_start(iregs); | ||
411 | |||
412 | xtime.tv_sec = mktime(year, mon, day, hour, min, sec); | ||
413 | xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); | ||
414 | set_normalized_timespec(&wall_to_monotonic, | ||
415 | -xtime.tv_sec, -xtime.tv_nsec); | ||
416 | printk("%u/%u/%u %u:%u:%u\n",day,mon,year,hour,min,sec); | ||
417 | } | ||
418 | #endif | ||
419 | |||
420 | /* Now that OBP ticker has been silenced, it is safe to enable IRQ. */ | 231 | /* Now that OBP ticker has been silenced, it is safe to enable IRQ. */ |
421 | local_irq_enable(); | 232 | local_irq_enable(); |
422 | } | 233 | } |
@@ -522,80 +333,15 @@ static int sbus_do_settimeofday(struct timespec *tv) | |||
522 | return 0; | 333 | return 0; |
523 | } | 334 | } |
524 | 335 | ||
525 | /* | 336 | static int set_rtc_mmss(unsigned long secs) |
526 | * BUG: This routine does not handle hour overflow properly; it just | ||
527 | * sets the minutes. Usually you won't notice until after reboot! | ||
528 | */ | ||
529 | static int set_rtc_mmss(unsigned long nowtime) | ||
530 | { | 337 | { |
531 | int real_seconds, real_minutes, mostek_minutes; | 338 | struct rtc_device *rtc = rtc_class_open("rtc0"); |
532 | struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs; | 339 | int err = -1; |
533 | unsigned long flags; | ||
534 | #ifdef CONFIG_SUN4 | ||
535 | struct intersil *iregs = intersil_clock; | ||
536 | int temp; | ||
537 | #endif | ||
538 | 340 | ||
539 | /* Not having a register set can lead to trouble. */ | 341 | if (rtc) { |
540 | if (!regs) { | 342 | err = rtc_set_mmss(rtc, secs); |
541 | #ifdef CONFIG_SUN4 | 343 | rtc_class_close(rtc); |
542 | if(!iregs) | ||
543 | return -1; | ||
544 | else { | ||
545 | temp = iregs->clk.int_csec; | ||
546 | |||
547 | mostek_minutes = iregs->clk.int_min; | ||
548 | |||
549 | real_seconds = nowtime % 60; | ||
550 | real_minutes = nowtime / 60; | ||
551 | if (((abs(real_minutes - mostek_minutes) + 15)/30) & 1) | ||
552 | real_minutes += 30; /* correct for half hour time zone */ | ||
553 | real_minutes %= 60; | ||
554 | |||
555 | if (abs(real_minutes - mostek_minutes) < 30) { | ||
556 | intersil_stop(iregs); | ||
557 | iregs->clk.int_sec=real_seconds; | ||
558 | iregs->clk.int_min=real_minutes; | ||
559 | intersil_start(iregs); | ||
560 | } else { | ||
561 | printk(KERN_WARNING | ||
562 | "set_rtc_mmss: can't update from %d to %d\n", | ||
563 | mostek_minutes, real_minutes); | ||
564 | return -1; | ||
565 | } | ||
566 | |||
567 | return 0; | ||
568 | } | ||
569 | #endif | ||
570 | } | 344 | } |
571 | 345 | ||
572 | spin_lock_irqsave(&mostek_lock, flags); | 346 | return err; |
573 | /* Read the current RTC minutes. */ | ||
574 | regs->creg |= MSTK_CREG_READ; | ||
575 | mostek_minutes = MSTK_REG_MIN(regs); | ||
576 | regs->creg &= ~MSTK_CREG_READ; | ||
577 | |||
578 | /* | ||
579 | * since we're only adjusting minutes and seconds, | ||
580 | * don't interfere with hour overflow. This avoids | ||
581 | * messing with unknown time zones but requires your | ||
582 | * RTC not to be off by more than 15 minutes | ||
583 | */ | ||
584 | real_seconds = nowtime % 60; | ||
585 | real_minutes = nowtime / 60; | ||
586 | if (((abs(real_minutes - mostek_minutes) + 15)/30) & 1) | ||
587 | real_minutes += 30; /* correct for half hour time zone */ | ||
588 | real_minutes %= 60; | ||
589 | |||
590 | if (abs(real_minutes - mostek_minutes) < 30) { | ||
591 | regs->creg |= MSTK_CREG_WRITE; | ||
592 | MSTK_SET_REG_SEC(regs,real_seconds); | ||
593 | MSTK_SET_REG_MIN(regs,real_minutes); | ||
594 | regs->creg &= ~MSTK_CREG_WRITE; | ||
595 | spin_unlock_irqrestore(&mostek_lock, flags); | ||
596 | return 0; | ||
597 | } else { | ||
598 | spin_unlock_irqrestore(&mostek_lock, flags); | ||
599 | return -1; | ||
600 | } | ||
601 | } | 347 | } |
diff --git a/arch/sparc/kernel/traps.c b/arch/sparc/kernel/traps.c index 5d45d5fd8c99..2b7d50659036 100644 --- a/arch/sparc/kernel/traps.c +++ b/arch/sparc/kernel/traps.c | |||
@@ -43,23 +43,6 @@ void syscall_trace_exit(struct pt_regs *regs) | |||
43 | { | 43 | { |
44 | } | 44 | } |
45 | 45 | ||
46 | void sun4m_nmi(struct pt_regs *regs) | ||
47 | { | ||
48 | unsigned long afsr, afar; | ||
49 | |||
50 | printk("Aieee: sun4m NMI received!\n"); | ||
51 | /* XXX HyperSparc hack XXX */ | ||
52 | __asm__ __volatile__("mov 0x500, %%g1\n\t" | ||
53 | "lda [%%g1] 0x4, %0\n\t" | ||
54 | "mov 0x600, %%g1\n\t" | ||
55 | "lda [%%g1] 0x4, %1\n\t" : | ||
56 | "=r" (afsr), "=r" (afar)); | ||
57 | printk("afsr=%08lx afar=%08lx\n", afsr, afar); | ||
58 | printk("you lose buddy boy...\n"); | ||
59 | show_regs(regs); | ||
60 | prom_halt(); | ||
61 | } | ||
62 | |||
63 | void sun4d_nmi(struct pt_regs *regs) | 46 | void sun4d_nmi(struct pt_regs *regs) |
64 | { | 47 | { |
65 | printk("Aieee: sun4d NMI received!\n"); | 48 | printk("Aieee: sun4d NMI received!\n"); |