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> | |
1da177e4 LT |
18 | |
19 | #define __EXTERN_INLINE inline | |
20 | #include <asm/io.h> | |
21 | #include <asm/jensen.h> | |
22 | #undef __EXTERN_INLINE | |
23 | ||
24 | #include <asm/dma.h> | |
25 | #include <asm/irq.h> | |
26 | #include <asm/mmu_context.h> | |
27 | #include <asm/pgtable.h> | |
28 | #include <asm/tlbflush.h> | |
29 | ||
30 | #include "proto.h" | |
31 | #include "irq_impl.h" | |
32 | #include "pci_impl.h" | |
33 | #include "machvec_impl.h" | |
34 | ||
35 | ||
36 | /* | |
37 | * Jensen is special: the vector is 0x8X0 for EISA interrupt X, and | |
38 | * 0x9X0 for the local motherboard interrupts. | |
39 | * | |
40 | * Note especially that those local interrupts CANNOT be masked, | |
41 | * which causes much of the pain below... | |
42 | * | |
43 | * 0x660 - NMI | |
44 | * | |
45 | * 0x800 - IRQ0 interval timer (not used, as we use the RTC timer) | |
46 | * 0x810 - IRQ1 line printer (duh..) | |
47 | * 0x860 - IRQ6 floppy disk | |
48 | * | |
49 | * 0x900 - COM1 | |
50 | * 0x920 - COM2 | |
51 | * 0x980 - keyboard | |
52 | * 0x990 - mouse | |
53 | * | |
54 | * PCI-based systems are more sane: they don't have the local | |
55 | * interrupts at all, and have only normal PCI interrupts from | |
56 | * devices. Happily it's easy enough to do a sane mapping from the | |
57 | * Jensen. | |
58 | * | |
59 | * Note that this means that we may have to do a hardware | |
60 | * "local_op" to a different interrupt than we report to the rest of the | |
61 | * world. | |
62 | */ | |
63 | ||
1da177e4 | 64 | static void |
ff53afe6 | 65 | jensen_local_enable(struct irq_data *d) |
1da177e4 LT |
66 | { |
67 | /* the parport is really hw IRQ 1, silly Jensen. */ | |
ff53afe6 TG |
68 | if (d->irq == 7) |
69 | i8259a_enable_irq(d); | |
1da177e4 LT |
70 | } |
71 | ||
72 | static void | |
ff53afe6 | 73 | jensen_local_disable(struct irq_data *d) |
1da177e4 LT |
74 | { |
75 | /* the parport is really hw IRQ 1, silly Jensen. */ | |
ff53afe6 TG |
76 | if (d->irq == 7) |
77 | i8259a_disable_irq(d); | |
1da177e4 LT |
78 | } |
79 | ||
80 | static void | |
ff53afe6 | 81 | jensen_local_mask_ack(struct irq_data *d) |
1da177e4 LT |
82 | { |
83 | /* the parport is really hw IRQ 1, silly Jensen. */ | |
ff53afe6 TG |
84 | if (d->irq == 7) |
85 | i8259a_mask_and_ack_irq(d); | |
1da177e4 LT |
86 | } |
87 | ||
44377f62 | 88 | static struct irq_chip jensen_local_irq_type = { |
8ab1221c | 89 | .name = "LOCAL", |
ff53afe6 TG |
90 | .irq_unmask = jensen_local_enable, |
91 | .irq_mask = jensen_local_disable, | |
92 | .irq_mask_ack = jensen_local_mask_ack, | |
1da177e4 LT |
93 | }; |
94 | ||
95 | static void | |
7ca56053 | 96 | jensen_device_interrupt(unsigned long vector) |
1da177e4 LT |
97 | { |
98 | int irq; | |
99 | ||
100 | switch (vector) { | |
101 | case 0x660: | |
102 | printk("Whee.. NMI received. Probable hardware error\n"); | |
103 | printk("61=%02x, 461=%02x\n", inb(0x61), inb(0x461)); | |
104 | return; | |
105 | ||
106 | /* local device interrupts: */ | |
107 | case 0x900: irq = 4; break; /* com1 -> irq 4 */ | |
108 | case 0x920: irq = 3; break; /* com2 -> irq 3 */ | |
109 | case 0x980: irq = 1; break; /* kbd -> irq 1 */ | |
110 | case 0x990: irq = 9; break; /* mouse -> irq 9 */ | |
111 | ||
112 | default: | |
113 | if (vector > 0x900) { | |
114 | printk("Unknown local interrupt %lx\n", vector); | |
115 | return; | |
116 | } | |
117 | ||
118 | irq = (vector - 0x800) >> 4; | |
119 | if (irq == 1) | |
120 | irq = 7; | |
121 | break; | |
122 | } | |
123 | ||
124 | /* If there is no handler yet... */ | |
a891b393 | 125 | if (!irq_has_action(irq)) { |
1da177e4 LT |
126 | /* If it is a local interrupt that cannot be masked... */ |
127 | if (vector >= 0x900) | |
128 | { | |
129 | /* Clear keyboard/mouse state */ | |
130 | inb(0x64); | |
131 | inb(0x60); | |
132 | /* Reset serial ports */ | |
133 | inb(0x3fa); | |
134 | inb(0x2fa); | |
135 | outb(0x0c, 0x3fc); | |
136 | outb(0x0c, 0x2fc); | |
137 | /* Clear NMI */ | |
138 | outb(0,0x61); | |
139 | outb(0,0x461); | |
140 | } | |
141 | } | |
142 | ||
143 | #if 0 | |
144 | /* A useful bit of code to find out if an interrupt is going wild. */ | |
145 | { | |
146 | static unsigned int last_msg = 0, last_cc = 0; | |
147 | static int last_irq = -1, count = 0; | |
148 | unsigned int cc; | |
149 | ||
150 | __asm __volatile("rpcc %0" : "=r"(cc)); | |
151 | ++count; | |
152 | #define JENSEN_CYCLES_PER_SEC (150000000) | |
153 | if (cc - last_msg > ((JENSEN_CYCLES_PER_SEC) * 3) || | |
154 | irq != last_irq) { | |
155 | printk(KERN_CRIT " irq %d count %d cc %u @ %lx\n", | |
7ca56053 | 156 | irq, count, cc-last_cc, get_irq_regs()->pc); |
1da177e4 LT |
157 | count = 0; |
158 | last_msg = cc; | |
159 | last_irq = irq; | |
160 | } | |
161 | last_cc = cc; | |
162 | } | |
163 | #endif | |
164 | ||
3dbb8c62 | 165 | handle_irq(irq); |
1da177e4 LT |
166 | } |
167 | ||
168 | static void __init | |
169 | jensen_init_irq(void) | |
170 | { | |
171 | init_i8259a_irqs(); | |
172 | ||
a9eb076b TG |
173 | irq_set_chip_and_handler(1, &jensen_local_irq_type, handle_level_irq); |
174 | irq_set_chip_and_handler(4, &jensen_local_irq_type, handle_level_irq); | |
175 | irq_set_chip_and_handler(3, &jensen_local_irq_type, handle_level_irq); | |
176 | irq_set_chip_and_handler(7, &jensen_local_irq_type, handle_level_irq); | |
177 | irq_set_chip_and_handler(9, &jensen_local_irq_type, handle_level_irq); | |
1da177e4 LT |
178 | |
179 | common_init_isa_dma(); | |
180 | } | |
181 | ||
182 | static void __init | |
183 | jensen_init_arch(void) | |
184 | { | |
185 | struct pci_controller *hose; | |
186 | #ifdef CONFIG_PCI | |
187 | static struct pci_dev fake_isa_bridge = { .dma_mask = 0xffffffffUL, }; | |
188 | ||
189 | isa_bridge = &fake_isa_bridge; | |
190 | #endif | |
191 | ||
192 | /* Create a hose so that we can report i/o base addresses to | |
193 | userland. */ | |
194 | ||
195 | pci_isa_hose = hose = alloc_pci_controller(); | |
196 | hose->io_space = &ioport_resource; | |
197 | hose->mem_space = &iomem_resource; | |
198 | hose->index = 0; | |
199 | ||
200 | hose->sparse_mem_base = EISA_MEM - IDENT_ADDR; | |
201 | hose->dense_mem_base = 0; | |
202 | hose->sparse_io_base = EISA_IO - IDENT_ADDR; | |
203 | hose->dense_io_base = 0; | |
204 | ||
205 | hose->sg_isa = hose->sg_pci = NULL; | |
206 | __direct_map_base = 0; | |
207 | __direct_map_size = 0xffffffff; | |
208 | } | |
209 | ||
210 | static void | |
5f0e3da6 | 211 | jensen_machine_check(unsigned long vector, unsigned long la) |
1da177e4 LT |
212 | { |
213 | printk(KERN_CRIT "Machine check\n"); | |
214 | } | |
215 | ||
1da177e4 LT |
216 | /* |
217 | * The System Vector | |
218 | */ | |
219 | ||
220 | struct alpha_machine_vector jensen_mv __initmv = { | |
221 | .vector_name = "Jensen", | |
222 | DO_EV4_MMU, | |
223 | IO_LITE(JENSEN,jensen), | |
224 | .machine_check = jensen_machine_check, | |
225 | .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, | |
226 | .rtc_port = 0x170, | |
227 | ||
228 | .nr_irqs = 16, | |
229 | .device_interrupt = jensen_device_interrupt, | |
230 | ||
231 | .init_arch = jensen_init_arch, | |
232 | .init_irq = jensen_init_irq, | |
233 | .init_rtc = common_init_rtc, | |
234 | .init_pci = NULL, | |
235 | .kill_arch = NULL, | |
236 | }; | |
237 | ALIAS_MV(jensen) |