]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * linux/arch/alpha/kernel/sys_jensen.c | |
3 | * | |
4 | * Copyright (C) 1995 Linus Torvalds | |
5 | * Copyright (C) 1998, 1999 Richard Henderson | |
6 | * | |
7 | * Code supporting the Jensen. | |
8 | */ | |
9 | ||
10 | #include <linux/kernel.h> | |
11 | #include <linux/types.h> | |
12 | #include <linux/mm.h> | |
13 | #include <linux/sched.h> | |
14 | #include <linux/pci.h> | |
15 | #include <linux/init.h> | |
16 | ||
17 | #include <asm/ptrace.h> | |
18 | #include <asm/system.h> | |
19 | ||
20 | #define __EXTERN_INLINE inline | |
21 | #include <asm/io.h> | |
22 | #include <asm/jensen.h> | |
23 | #undef __EXTERN_INLINE | |
24 | ||
25 | #include <asm/dma.h> | |
26 | #include <asm/irq.h> | |
27 | #include <asm/mmu_context.h> | |
28 | #include <asm/pgtable.h> | |
29 | #include <asm/tlbflush.h> | |
30 | ||
31 | #include "proto.h" | |
32 | #include "irq_impl.h" | |
33 | #include "pci_impl.h" | |
34 | #include "machvec_impl.h" | |
35 | ||
36 | ||
37 | /* | |
38 | * Jensen is special: the vector is 0x8X0 for EISA interrupt X, and | |
39 | * 0x9X0 for the local motherboard interrupts. | |
40 | * | |
41 | * Note especially that those local interrupts CANNOT be masked, | |
42 | * which causes much of the pain below... | |
43 | * | |
44 | * 0x660 - NMI | |
45 | * | |
46 | * 0x800 - IRQ0 interval timer (not used, as we use the RTC timer) | |
47 | * 0x810 - IRQ1 line printer (duh..) | |
48 | * 0x860 - IRQ6 floppy disk | |
49 | * | |
50 | * 0x900 - COM1 | |
51 | * 0x920 - COM2 | |
52 | * 0x980 - keyboard | |
53 | * 0x990 - mouse | |
54 | * | |
55 | * PCI-based systems are more sane: they don't have the local | |
56 | * interrupts at all, and have only normal PCI interrupts from | |
57 | * devices. Happily it's easy enough to do a sane mapping from the | |
58 | * Jensen. | |
59 | * | |
60 | * Note that this means that we may have to do a hardware | |
61 | * "local_op" to a different interrupt than we report to the rest of the | |
62 | * world. | |
63 | */ | |
64 | ||
65 | static unsigned int | |
66 | jensen_local_startup(unsigned int irq) | |
67 | { | |
68 | /* the parport is really hw IRQ 1, silly Jensen. */ | |
69 | if (irq == 7) | |
70 | i8259a_startup_irq(1); | |
71 | else | |
72 | /* | |
73 | * For all true local interrupts, set the flag that prevents | |
74 | * the IPL from being dropped during handler processing. | |
75 | */ | |
76 | if (irq_desc[irq].action) | |
d18ecedc | 77 | irq_desc[irq].action->flags |= IRQF_DISABLED; |
1da177e4 LT |
78 | return 0; |
79 | } | |
80 | ||
81 | static void | |
82 | jensen_local_shutdown(unsigned int irq) | |
83 | { | |
84 | /* the parport is really hw IRQ 1, silly Jensen. */ | |
85 | if (irq == 7) | |
86 | i8259a_disable_irq(1); | |
87 | } | |
88 | ||
89 | static void | |
90 | jensen_local_enable(unsigned int irq) | |
91 | { | |
92 | /* the parport is really hw IRQ 1, silly Jensen. */ | |
93 | if (irq == 7) | |
94 | i8259a_enable_irq(1); | |
95 | } | |
96 | ||
97 | static void | |
98 | jensen_local_disable(unsigned int irq) | |
99 | { | |
100 | /* the parport is really hw IRQ 1, silly Jensen. */ | |
101 | if (irq == 7) | |
102 | i8259a_disable_irq(1); | |
103 | } | |
104 | ||
105 | static void | |
106 | jensen_local_ack(unsigned int irq) | |
107 | { | |
108 | /* the parport is really hw IRQ 1, silly Jensen. */ | |
109 | if (irq == 7) | |
110 | i8259a_mask_and_ack_irq(1); | |
111 | } | |
112 | ||
113 | static void | |
114 | jensen_local_end(unsigned int irq) | |
115 | { | |
116 | /* the parport is really hw IRQ 1, silly Jensen. */ | |
117 | if (irq == 7) | |
118 | i8259a_end_irq(1); | |
119 | } | |
120 | ||
121 | static struct hw_interrupt_type jensen_local_irq_type = { | |
122 | .typename = "LOCAL", | |
123 | .startup = jensen_local_startup, | |
124 | .shutdown = jensen_local_shutdown, | |
125 | .enable = jensen_local_enable, | |
126 | .disable = jensen_local_disable, | |
127 | .ack = jensen_local_ack, | |
128 | .end = jensen_local_end, | |
129 | }; | |
130 | ||
131 | static void | |
7ca56053 | 132 | jensen_device_interrupt(unsigned long vector) |
1da177e4 LT |
133 | { |
134 | int irq; | |
135 | ||
136 | switch (vector) { | |
137 | case 0x660: | |
138 | printk("Whee.. NMI received. Probable hardware error\n"); | |
139 | printk("61=%02x, 461=%02x\n", inb(0x61), inb(0x461)); | |
140 | return; | |
141 | ||
142 | /* local device interrupts: */ | |
143 | case 0x900: irq = 4; break; /* com1 -> irq 4 */ | |
144 | case 0x920: irq = 3; break; /* com2 -> irq 3 */ | |
145 | case 0x980: irq = 1; break; /* kbd -> irq 1 */ | |
146 | case 0x990: irq = 9; break; /* mouse -> irq 9 */ | |
147 | ||
148 | default: | |
149 | if (vector > 0x900) { | |
150 | printk("Unknown local interrupt %lx\n", vector); | |
151 | return; | |
152 | } | |
153 | ||
154 | irq = (vector - 0x800) >> 4; | |
155 | if (irq == 1) | |
156 | irq = 7; | |
157 | break; | |
158 | } | |
159 | ||
160 | /* If there is no handler yet... */ | |
161 | if (irq_desc[irq].action == NULL) { | |
162 | /* If it is a local interrupt that cannot be masked... */ | |
163 | if (vector >= 0x900) | |
164 | { | |
165 | /* Clear keyboard/mouse state */ | |
166 | inb(0x64); | |
167 | inb(0x60); | |
168 | /* Reset serial ports */ | |
169 | inb(0x3fa); | |
170 | inb(0x2fa); | |
171 | outb(0x0c, 0x3fc); | |
172 | outb(0x0c, 0x2fc); | |
173 | /* Clear NMI */ | |
174 | outb(0,0x61); | |
175 | outb(0,0x461); | |
176 | } | |
177 | } | |
178 | ||
179 | #if 0 | |
180 | /* A useful bit of code to find out if an interrupt is going wild. */ | |
181 | { | |
182 | static unsigned int last_msg = 0, last_cc = 0; | |
183 | static int last_irq = -1, count = 0; | |
184 | unsigned int cc; | |
185 | ||
186 | __asm __volatile("rpcc %0" : "=r"(cc)); | |
187 | ++count; | |
188 | #define JENSEN_CYCLES_PER_SEC (150000000) | |
189 | if (cc - last_msg > ((JENSEN_CYCLES_PER_SEC) * 3) || | |
190 | irq != last_irq) { | |
191 | printk(KERN_CRIT " irq %d count %d cc %u @ %lx\n", | |
7ca56053 | 192 | irq, count, cc-last_cc, get_irq_regs()->pc); |
1da177e4 LT |
193 | count = 0; |
194 | last_msg = cc; | |
195 | last_irq = irq; | |
196 | } | |
197 | last_cc = cc; | |
198 | } | |
199 | #endif | |
200 | ||
7ca56053 | 201 | handle_irq(irq, get_irq_regs()); |
1da177e4 LT |
202 | } |
203 | ||
204 | static void __init | |
205 | jensen_init_irq(void) | |
206 | { | |
207 | init_i8259a_irqs(); | |
208 | ||
d1bef4ed IM |
209 | irq_desc[1].chip = &jensen_local_irq_type; |
210 | irq_desc[4].chip = &jensen_local_irq_type; | |
211 | irq_desc[3].chip = &jensen_local_irq_type; | |
212 | irq_desc[7].chip = &jensen_local_irq_type; | |
213 | irq_desc[9].chip = &jensen_local_irq_type; | |
1da177e4 LT |
214 | |
215 | common_init_isa_dma(); | |
216 | } | |
217 | ||
218 | static void __init | |
219 | jensen_init_arch(void) | |
220 | { | |
221 | struct pci_controller *hose; | |
222 | #ifdef CONFIG_PCI | |
223 | static struct pci_dev fake_isa_bridge = { .dma_mask = 0xffffffffUL, }; | |
224 | ||
225 | isa_bridge = &fake_isa_bridge; | |
226 | #endif | |
227 | ||
228 | /* Create a hose so that we can report i/o base addresses to | |
229 | userland. */ | |
230 | ||
231 | pci_isa_hose = hose = alloc_pci_controller(); | |
232 | hose->io_space = &ioport_resource; | |
233 | hose->mem_space = &iomem_resource; | |
234 | hose->index = 0; | |
235 | ||
236 | hose->sparse_mem_base = EISA_MEM - IDENT_ADDR; | |
237 | hose->dense_mem_base = 0; | |
238 | hose->sparse_io_base = EISA_IO - IDENT_ADDR; | |
239 | hose->dense_io_base = 0; | |
240 | ||
241 | hose->sg_isa = hose->sg_pci = NULL; | |
242 | __direct_map_base = 0; | |
243 | __direct_map_size = 0xffffffff; | |
244 | } | |
245 | ||
246 | static void | |
247 | jensen_machine_check (u64 vector, u64 la, struct pt_regs *regs) | |
248 | { | |
249 | printk(KERN_CRIT "Machine check\n"); | |
250 | } | |
251 | ||
252 | ||
253 | /* | |
254 | * The System Vector | |
255 | */ | |
256 | ||
257 | struct alpha_machine_vector jensen_mv __initmv = { | |
258 | .vector_name = "Jensen", | |
259 | DO_EV4_MMU, | |
260 | IO_LITE(JENSEN,jensen), | |
261 | .machine_check = jensen_machine_check, | |
262 | .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, | |
263 | .rtc_port = 0x170, | |
264 | ||
265 | .nr_irqs = 16, | |
266 | .device_interrupt = jensen_device_interrupt, | |
267 | ||
268 | .init_arch = jensen_init_arch, | |
269 | .init_irq = jensen_init_irq, | |
270 | .init_rtc = common_init_rtc, | |
271 | .init_pci = NULL, | |
272 | .kill_arch = NULL, | |
273 | }; | |
274 | ALIAS_MV(jensen) |