This source file includes following definitions.
- sun4m_get_irqmask
- sun4m_disable_irq
- sun4m_enable_irq
- sun4m_send_ipi
- sun4m_clear_ipi
- sun4m_set_udt
- sun4m_clear_clock_irq
- sun4m_clear_profile_irq
- sun4m_load_profile_irq
- sun4m_lvl14_handler
- sun4m_init_timers
- sun4m_init_IRQ
1
2
3
4
5
6
7
8
9
10
11
12 #include <linux/ptrace.h>
13 #include <linux/errno.h>
14 #include <linux/linkage.h>
15 #include <linux/kernel_stat.h>
16 #include <linux/signal.h>
17 #include <linux/sched.h>
18 #include <linux/smp.h>
19 #include <linux/interrupt.h>
20 #include <linux/malloc.h>
21
22 #include <asm/ptrace.h>
23 #include <asm/processor.h>
24 #include <asm/system.h>
25 #include <asm/psr.h>
26 #include <asm/vaddrs.h>
27 #include <asm/timer.h>
28 #include <asm/openprom.h>
29 #include <asm/oplib.h>
30 #include <asm/traps.h>
31 #include <asm/smp.h>
32 #include <asm/irq.h>
33 #include <asm/io.h>
34
35 static unsigned long dummy;
36
37 extern int linux_num_cpus;
38 struct sun4m_intregs *sun4m_interrupts;
39 unsigned long *irq_rcvreg = &dummy;
40
41
42
43
44
45
46
47
48
49
50 static unsigned char irq_xlate[32] = {
51
52 0, 0, 0, 0, 1, 0, 2, 0, 3, 0, 4, 5, 6, 0, 0, 7,
53 0, 0, 8, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 0
54 };
55
56 static unsigned long irq_mask[] = {
57 0,
58 SUN4M_INT_SCSI,
59 SUN4M_INT_ETHERNET,
60 SUN4M_INT_VIDEO,
61 SUN4M_INT_REALTIME,
62 SUN4M_INT_FLOPPY,
63 (SUN4M_INT_SERIAL | SUN4M_INT_KBDMS),
64 SUN4M_INT_MODULE_ERR,
65 SUN4M_INT_SBUS(1),
66 SUN4M_INT_SBUS(2),
67 SUN4M_INT_SBUS(3),
68 SUN4M_INT_SBUS(4),
69 SUN4M_INT_SBUS(5),
70 SUN4M_INT_SBUS(6),
71 SUN4M_INT_SBUS(7)
72 };
73
74 inline unsigned long sun4m_get_irqmask(unsigned int irq)
75 {
76 unsigned long mask;
77
78 if (irq > 0x20) {
79
80 irq &= 0x1f;
81 mask = irq_mask[irq_xlate[irq]];
82 if (!mask)
83 printk("sun4m_get_irqmask: IRQ%d has no valid mask!\n",irq);
84 } else {
85
86
87
88
89 irq &= 0xf;
90 mask = SUN4M_SOFT_INT(irq);
91 }
92 return mask;
93 }
94
95 static void sun4m_disable_irq(unsigned int irq_nr)
96 {
97 unsigned long mask, flags;
98 int cpu = smp_processor_id();
99
100 mask = sun4m_get_irqmask(irq_nr);
101 save_flags(flags); cli();
102 if (irq_nr > 15)
103 sun4m_interrupts->set = mask;
104 else
105 sun4m_interrupts->cpu_intregs[cpu].set = mask;
106 restore_flags(flags);
107 }
108
109 static void sun4m_enable_irq(unsigned int irq_nr)
110 {
111 unsigned long mask, flags;
112 int cpu = smp_processor_id();
113
114
115
116
117
118 if (irq_nr != 0x0b) {
119 mask = sun4m_get_irqmask(irq_nr);
120 save_flags(flags); cli();
121 if (irq_nr > 15)
122 sun4m_interrupts->clear = mask;
123 else
124 sun4m_interrupts->cpu_intregs[cpu].clear = mask;
125 restore_flags(flags);
126 } else {
127 save_flags(flags); cli();
128 sun4m_interrupts->clear = SUN4M_INT_FLOPPY;
129 restore_flags(flags);
130 }
131 }
132
133 void sun4m_send_ipi(int cpu, int level)
134 {
135 unsigned long mask;
136
137 mask = sun4m_get_irqmask(level);
138 sun4m_interrupts->cpu_intregs[cpu].set = mask;
139 }
140
141 void sun4m_clear_ipi(int cpu, int level)
142 {
143 unsigned long mask;
144
145 mask = sun4m_get_irqmask(level);
146 sun4m_interrupts->cpu_intregs[cpu].clear = mask;
147 }
148
149 void sun4m_set_udt(int cpu)
150 {
151 sun4m_interrupts->undirected_target = cpu;
152 }
153
154 #define OBIO_INTR 0x20
155 #define TIMER_IRQ (OBIO_INTR | 10)
156 #define PROFILE_IRQ (OBIO_INTR | 14)
157
158 struct sun4m_timer_regs *sun4m_timers;
159 unsigned int lvl14_resolution = (((1000000/HZ) + 1) << 10);
160
161 static void sun4m_clear_clock_irq(void)
162 {
163 volatile unsigned int clear_intr;
164 clear_intr = sun4m_timers->l10_timer_limit;
165 }
166
167 static void sun4m_clear_profile_irq(void)
168 {
169 volatile unsigned int clear;
170
171 clear = sun4m_timers->cpu_timers[0].l14_timer_limit;
172 }
173
174 static void sun4m_load_profile_irq(unsigned int limit)
175 {
176 sun4m_timers->cpu_timers[0].l14_timer_limit = limit;
177 }
178
179 static void sun4m_lvl14_handler(int irq, void *dev_id, struct pt_regs * regs)
180 {
181 volatile unsigned int clear;
182
183 printk("CPU[%d]: TOOK A LEVEL14!\n", smp_processor_id());
184
185
186
187
188 clear = sun4m_timers->cpu_timers[0].l14_timer_limit;
189
190
191
192
193 sun4m_timers->cpu_timers[0].l14_timer_limit = lvl14_resolution;
194 }
195
196 static void sun4m_init_timers(void (*counter_fn)(int, void *, struct pt_regs *))
197 {
198 int reg_count, irq, cpu;
199 struct linux_prom_registers cnt_regs[PROMREG_MAX];
200 int obio_node, cnt_node;
201
202 cnt_node = 0;
203 if((obio_node =
204 prom_searchsiblings (prom_getchild(prom_root_node), "obio")) == 0 ||
205 (obio_node = prom_getchild (obio_node)) == 0 ||
206 (cnt_node = prom_searchsiblings (obio_node, "counter")) == 0) {
207 prom_printf("Cannot find /obio/counter node\n");
208 prom_halt();
209 }
210 reg_count = prom_getproperty(cnt_node, "reg",
211 (void *) cnt_regs, sizeof(cnt_regs));
212 reg_count = (reg_count/sizeof(struct linux_prom_registers));
213
214
215 prom_apply_obio_ranges(cnt_regs, reg_count);
216
217 cnt_regs[4].phys_addr = cnt_regs[reg_count-1].phys_addr;
218 cnt_regs[4].reg_size = cnt_regs[reg_count-1].reg_size;
219 cnt_regs[4].which_io = cnt_regs[reg_count-1].which_io;
220 for(obio_node = 1; obio_node < 4; obio_node++) {
221 cnt_regs[obio_node].phys_addr =
222 cnt_regs[obio_node-1].phys_addr + PAGE_SIZE;
223 cnt_regs[obio_node].reg_size = cnt_regs[obio_node-1].reg_size;
224 cnt_regs[obio_node].which_io = cnt_regs[obio_node-1].which_io;
225 }
226
227
228 sun4m_timers = sparc_alloc_io(cnt_regs[0].phys_addr, 0,
229 PAGE_SIZE*NCPUS, "counters_percpu",
230 cnt_regs[0].which_io, 0x0);
231
232
233 sparc_alloc_io(cnt_regs[4].phys_addr, 0,
234 cnt_regs[4].reg_size,
235 "counters_system",
236 cnt_regs[4].which_io, 0x0);
237
238 sun4m_timers->l10_timer_limit = (((1000000/HZ) + 1) << 10);
239
240 irq = request_irq(TIMER_IRQ,
241 counter_fn,
242 (SA_INTERRUPT | SA_STATIC_ALLOC),
243 "timer", NULL);
244 if (irq) {
245 prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ);
246 prom_halt();
247 }
248
249
250 #if 0
251 if (linux_num_cpus > 1)
252 claim_ticker14(NULL, PROFILE_IRQ, 0);
253 else
254 claim_ticker14(sun4m_lvl14_handler, PROFILE_IRQ, lvl14_resolution);
255 #endif
256 if(linux_num_cpus > 1) {
257 for(cpu = 0; cpu < 4; cpu++)
258 sun4m_timers->cpu_timers[cpu].l14_timer_limit = 0;
259 sun4m_interrupts->set = SUN4M_INT_E14;
260 } else {
261 sun4m_timers->cpu_timers[0].l14_timer_limit = 0;
262 }
263 }
264
265 void sun4m_init_IRQ(void)
266 {
267 int ie_node,i;
268 struct linux_prom_registers int_regs[PROMREG_MAX];
269 int num_regs;
270
271 cli();
272 if((ie_node = prom_searchsiblings(prom_getchild(prom_root_node), "obio")) == 0 ||
273 (ie_node = prom_getchild (ie_node)) == 0 ||
274 (ie_node = prom_searchsiblings (ie_node, "interrupt")) == 0) {
275 prom_printf("Cannot find /obio/interrupt node\n");
276 prom_halt();
277 }
278 num_regs = prom_getproperty(ie_node, "reg", (char *) int_regs,
279 sizeof(int_regs));
280 num_regs = (num_regs/sizeof(struct linux_prom_registers));
281
282
283 prom_apply_obio_ranges(int_regs, num_regs);
284
285 int_regs[4].phys_addr = int_regs[num_regs-1].phys_addr;
286 int_regs[4].reg_size = int_regs[num_regs-1].reg_size;
287 int_regs[4].which_io = int_regs[num_regs-1].which_io;
288 for(ie_node = 1; ie_node < 4; ie_node++) {
289 int_regs[ie_node].phys_addr = int_regs[ie_node-1].phys_addr + PAGE_SIZE;
290 int_regs[ie_node].reg_size = int_regs[ie_node-1].reg_size;
291 int_regs[ie_node].which_io = int_regs[ie_node-1].which_io;
292 }
293
294
295 sun4m_interrupts = sparc_alloc_io(int_regs[0].phys_addr, 0,
296 PAGE_SIZE*NCPUS, "interrupts_percpu",
297 int_regs[0].which_io, 0x0);
298
299
300 sparc_alloc_io(int_regs[4].phys_addr, 0,
301 int_regs[4].reg_size, "interrupts_system",
302 int_regs[4].which_io, 0x0);
303
304 sun4m_interrupts->set = ~SUN4M_INT_MASKALL;
305 for (i=0; i<linux_num_cpus; i++)
306 sun4m_interrupts->cpu_intregs[i].clear = ~0x17fff;
307
308 if (linux_num_cpus > 1) {
309
310
311
312
313
314
315
316 #if 0
317 printk("Warning:"
318 "sun4m multiple CPU interrupt code requires work\n");
319 #endif
320 irq_rcvreg = &sun4m_interrupts->undirected_target;
321 sun4m_interrupts->undirected_target = 0;
322 }
323 enable_irq = sun4m_enable_irq;
324 disable_irq = sun4m_disable_irq;
325 clear_clock_irq = sun4m_clear_clock_irq;
326 clear_profile_irq = sun4m_clear_profile_irq;
327 load_profile_irq = sun4m_load_profile_irq;
328 init_timers = sun4m_init_timers;
329 #ifdef __SMP__
330 set_cpu_int = sun4m_send_ipi;
331 clear_cpu_int = sun4m_clear_ipi;
332 set_irq_udt = sun4m_set_udt;
333 #endif
334 sti();
335 }