Import 2.3.49pre2
[davej-history.git] / arch / alpha / kernel / sys_cabriolet.c
blob8e016ada0fcac5a0ee7754946e8cb385b4ecb41b
1 /*
2 * linux/arch/alpha/kernel/sys_cabriolet.c
4 * Copyright (C) 1995 David A Rusling
5 * Copyright (C) 1996 Jay A Estabrook
6 * Copyright (C) 1998, 1999 Richard Henderson
8 * Code supporting the Cabriolet (AlphaPC64), EB66+, and EB164,
9 * PC164 and LX164.
12 #include <linux/config.h>
13 #include <linux/kernel.h>
14 #include <linux/types.h>
15 #include <linux/mm.h>
16 #include <linux/sched.h>
17 #include <linux/pci.h>
18 #include <linux/init.h>
20 #include <asm/ptrace.h>
21 #include <asm/system.h>
22 #include <asm/dma.h>
23 #include <asm/irq.h>
24 #include <asm/bitops.h>
25 #include <asm/mmu_context.h>
26 #include <asm/io.h>
27 #include <asm/pgtable.h>
28 #include <asm/core_apecs.h>
29 #include <asm/core_cia.h>
30 #include <asm/core_lca.h>
31 #include <asm/core_pyxis.h>
33 #include "proto.h"
34 #include "irq_impl.h"
35 #include "pci_impl.h"
36 #include "machvec_impl.h"
39 /* Note mask bit is true for DISABLED irqs. */
40 static unsigned long cached_irq_mask = ~0UL;
42 static inline void
43 cabriolet_update_irq_hw(unsigned int irq, unsigned long mask)
45 int ofs = (irq - 16) / 8;
46 outb(mask >> (16 + ofs*3), 0x804 + ofs);
49 static inline void
50 cabriolet_enable_irq(unsigned int irq)
52 cabriolet_update_irq_hw(irq, cached_irq_mask &= ~(1UL << irq));
55 static void
56 cabriolet_disable_irq(unsigned int irq)
58 cabriolet_update_irq_hw(irq, cached_irq_mask |= 1UL << irq);
61 static unsigned int
62 cabriolet_startup_irq(unsigned int irq)
64 cabriolet_enable_irq(irq);
65 return 0; /* never anything pending */
68 static void
69 cabriolet_end_irq(unsigned int irq)
71 if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
72 cabriolet_enable_irq(irq);
75 static struct hw_interrupt_type cabriolet_irq_type = {
76 typename: "CABRIOLET",
77 startup: cabriolet_startup_irq,
78 shutdown: cabriolet_disable_irq,
79 enable: cabriolet_enable_irq,
80 disable: cabriolet_disable_irq,
81 ack: cabriolet_disable_irq,
82 end: cabriolet_end_irq,
85 static void
86 cabriolet_device_interrupt(unsigned long v, struct pt_regs *r)
88 unsigned long pld;
89 unsigned int i;
91 /* Read the interrupt summary registers */
92 pld = inb(0x804) | (inb(0x805) << 8) | (inb(0x806) << 16);
95 * Now for every possible bit set, work through them and call
96 * the appropriate interrupt handler.
98 while (pld) {
99 i = ffz(~pld);
100 pld &= pld - 1; /* clear least bit set */
101 if (i == 4) {
102 isa_device_interrupt(v, r);
103 } else {
104 handle_irq(16 + i, r);
109 static void __init
110 cabriolet_init_irq(void)
112 init_i8259a_irqs();
114 if (alpha_using_srm) {
115 alpha_mv.device_interrupt = srm_device_interrupt;
116 init_srm_irqs(35, 0);
118 else {
119 long i;
121 outb(0xff, 0x804);
122 outb(0xff, 0x805);
123 outb(0xff, 0x806);
125 for (i = 16; i < 35; ++i) {
126 irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
127 irq_desc[i].handler = &cabriolet_irq_type;
131 common_init_isa_dma();
132 setup_irq(16+4, &isa_cascade_irqaction);
135 #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_PC164)
136 static void
137 pc164_device_interrupt(unsigned long v, struct pt_regs *r)
139 /* In theory, the PC164 has the same interrupt hardware as
140 the other Cabriolet based systems. However, something
141 got screwed up late in the development cycle which broke
142 the interrupt masking hardware. Repeat, it is not
143 possible to mask and ack interrupts. At all.
145 In an attempt to work around this, while processing
146 interrupts, we do not allow the IPL to drop below what
147 it is currently. This prevents the possibility of
148 recursion.
150 ??? Another option might be to force all PCI devices
151 to use edge triggered rather than level triggered
152 interrupts. That might be too invasive though. */
154 __min_ipl = getipl();
155 cabriolet_device_interrupt(v, r);
156 __min_ipl = 0;
158 #endif
161 * The EB66+ is very similar to the EB66 except that it does not have
162 * the on-board NCR and Tulip chips. In the code below, I have used
163 * slot number to refer to the id select line and *not* the slot
164 * number used in the EB66+ documentation. However, in the table,
165 * I've given the slot number, the id select line and the Jxx number
166 * that's printed on the board. The interrupt pins from the PCI slots
167 * are wired into 3 interrupt summary registers at 0x804, 0x805 and
168 * 0x806 ISA.
170 * In the table, -1 means don't assign an IRQ number. This is usually
171 * because it is the Saturn IO (SIO) PCI/ISA Bridge Chip.
174 static inline int __init
175 eb66p_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
177 static char irq_tab[5][5] __initlocaldata = {
178 /*INT INTA INTB INTC INTD */
179 {16+0, 16+0, 16+5, 16+9, 16+13}, /* IdSel 6, slot 0, J25 */
180 {16+1, 16+1, 16+6, 16+10, 16+14}, /* IdSel 7, slot 1, J26 */
181 { -1, -1, -1, -1, -1}, /* IdSel 8, SIO */
182 {16+2, 16+2, 16+7, 16+11, 16+15}, /* IdSel 9, slot 2, J27 */
183 {16+3, 16+3, 16+8, 16+12, 16+6} /* IdSel 10, slot 3, J28 */
185 const long min_idsel = 6, max_idsel = 10, irqs_per_slot = 5;
186 return COMMON_TABLE_LOOKUP;
191 * The AlphaPC64 is very similar to the EB66+ except that its slots
192 * are numbered differently. In the code below, I have used slot
193 * number to refer to the id select line and *not* the slot number
194 * used in the AlphaPC64 documentation. However, in the table, I've
195 * given the slot number, the id select line and the Jxx number that's
196 * printed on the board. The interrupt pins from the PCI slots are
197 * wired into 3 interrupt summary registers at 0x804, 0x805 and 0x806
198 * ISA.
200 * In the table, -1 means don't assign an IRQ number. This is usually
201 * because it is the Saturn IO (SIO) PCI/ISA Bridge Chip.
204 static inline int __init
205 cabriolet_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
207 static char irq_tab[5][5] __initlocaldata = {
208 /*INT INTA INTB INTC INTD */
209 { 16+2, 16+2, 16+7, 16+11, 16+15}, /* IdSel 5, slot 2, J21 */
210 { 16+0, 16+0, 16+5, 16+9, 16+13}, /* IdSel 6, slot 0, J19 */
211 { 16+1, 16+1, 16+6, 16+10, 16+14}, /* IdSel 7, slot 1, J20 */
212 { -1, -1, -1, -1, -1}, /* IdSel 8, SIO */
213 { 16+3, 16+3, 16+8, 16+12, 16+16} /* IdSel 9, slot 3, J22 */
215 const long min_idsel = 5, max_idsel = 9, irqs_per_slot = 5;
216 return COMMON_TABLE_LOOKUP;
219 static inline void __init
220 cabriolet_init_pci(void)
222 common_init_pci();
223 ns87312_enable_ide(0x398);
228 * The PC164 and LX164 have 19 PCI interrupts, four from each of the four
229 * PCI slots, the SIO, PCI/IDE, and USB.
231 * Each of the interrupts can be individually masked. This is
232 * accomplished by setting the appropriate bit in the mask register.
233 * A bit is set by writing a "1" to the desired position in the mask
234 * register and cleared by writing a "0". There are 3 mask registers
235 * located at ISA address 804h, 805h and 806h.
237 * An I/O read at ISA address 804h, 805h, 806h will return the
238 * state of the 11 PCI interrupts and not the state of the MASKED
239 * interrupts.
241 * Note: A write to I/O 804h, 805h, and 806h the mask register will be
242 * updated.
245 * ISA DATA<7:0>
246 * ISA +--------------------------------------------------------------+
247 * ADDRESS | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
248 * +==============================================================+
249 * 0x804 | INTB0 | USB | IDE | SIO | INTA3 |INTA2 | INTA1 | INTA0 |
250 * +--------------------------------------------------------------+
251 * 0x805 | INTD0 | INTC3 | INTC2 | INTC1 | INTC0 |INTB3 | INTB2 | INTB1 |
252 * +--------------------------------------------------------------+
253 * 0x806 | Rsrv | Rsrv | Rsrv | Rsrv | Rsrv |INTD3 | INTD2 | INTD1 |
254 * +--------------------------------------------------------------+
255 * * Rsrv = reserved bits
256 * Note: The mask register is write-only.
258 * IdSel
259 * 5 32 bit PCI option slot 2
260 * 6 64 bit PCI option slot 0
261 * 7 64 bit PCI option slot 1
262 * 8 Saturn I/O
263 * 9 32 bit PCI option slot 3
264 * 10 USB
265 * 11 IDE
269 static inline int __init
270 alphapc164_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
272 static char irq_tab[7][5] __initlocaldata = {
273 /*INT INTA INTB INTC INTD */
274 { 16+2, 16+2, 16+9, 16+13, 16+17}, /* IdSel 5, slot 2, J20 */
275 { 16+0, 16+0, 16+7, 16+11, 16+15}, /* IdSel 6, slot 0, J29 */
276 { 16+1, 16+1, 16+8, 16+12, 16+16}, /* IdSel 7, slot 1, J26 */
277 { -1, -1, -1, -1, -1}, /* IdSel 8, SIO */
278 { 16+3, 16+3, 16+10, 16+14, 16+18}, /* IdSel 9, slot 3, J19 */
279 { 16+6, 16+6, 16+6, 16+6, 16+6}, /* IdSel 10, USB */
280 { 16+5, 16+5, 16+5, 16+5, 16+5} /* IdSel 11, IDE */
282 const long min_idsel = 5, max_idsel = 11, irqs_per_slot = 5;
283 return COMMON_TABLE_LOOKUP;
286 static inline void __init
287 alphapc164_init_pci(void)
289 common_init_pci();
290 SMC93x_Init();
295 * The System Vector
298 #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_CABRIOLET)
299 struct alpha_machine_vector cabriolet_mv __initmv = {
300 vector_name: "Cabriolet",
301 DO_EV4_MMU,
302 DO_DEFAULT_RTC,
303 DO_APECS_IO,
304 DO_APECS_BUS,
305 machine_check: apecs_machine_check,
306 max_dma_address: ALPHA_MAX_DMA_ADDRESS,
307 min_io_address: DEFAULT_IO_BASE,
308 min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE,
310 nr_irqs: 35,
311 device_interrupt: cabriolet_device_interrupt,
313 init_arch: apecs_init_arch,
314 init_irq: cabriolet_init_irq,
315 init_rtc: common_init_rtc,
316 init_pci: cabriolet_init_pci,
317 kill_arch: NULL,
318 pci_map_irq: cabriolet_map_irq,
319 pci_swizzle: common_swizzle,
321 ALIAS_MV(cabriolet)
322 #endif
324 #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_EB164)
325 struct alpha_machine_vector eb164_mv __initmv = {
326 vector_name: "EB164",
327 DO_EV5_MMU,
328 DO_DEFAULT_RTC,
329 DO_CIA_IO,
330 DO_CIA_BUS,
331 machine_check: cia_machine_check,
332 max_dma_address: ALPHA_MAX_DMA_ADDRESS,
333 min_io_address: DEFAULT_IO_BASE,
334 min_mem_address: CIA_DEFAULT_MEM_BASE,
336 nr_irqs: 35,
337 device_interrupt: cabriolet_device_interrupt,
339 init_arch: cia_init_arch,
340 init_irq: cabriolet_init_irq,
341 init_rtc: common_init_rtc,
342 init_pci: cabriolet_init_pci,
343 pci_map_irq: cabriolet_map_irq,
344 pci_swizzle: common_swizzle,
346 ALIAS_MV(eb164)
347 #endif
349 #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_EB66P)
350 struct alpha_machine_vector eb66p_mv __initmv = {
351 vector_name: "EB66+",
352 DO_EV4_MMU,
353 DO_DEFAULT_RTC,
354 DO_LCA_IO,
355 DO_LCA_BUS,
356 machine_check: lca_machine_check,
357 max_dma_address: ALPHA_MAX_DMA_ADDRESS,
358 min_io_address: DEFAULT_IO_BASE,
359 min_mem_address: APECS_AND_LCA_DEFAULT_MEM_BASE,
361 nr_irqs: 35,
362 device_interrupt: cabriolet_device_interrupt,
364 init_arch: lca_init_arch,
365 init_irq: cabriolet_init_irq,
366 init_rtc: common_init_rtc,
367 init_pci: cabriolet_init_pci,
368 pci_map_irq: eb66p_map_irq,
369 pci_swizzle: common_swizzle,
371 ALIAS_MV(eb66p)
372 #endif
374 #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_LX164)
375 struct alpha_machine_vector lx164_mv __initmv = {
376 vector_name: "LX164",
377 DO_EV5_MMU,
378 DO_DEFAULT_RTC,
379 DO_PYXIS_IO,
380 DO_PYXIS_BUS,
381 machine_check: pyxis_machine_check,
382 max_dma_address: ALPHA_MAX_DMA_ADDRESS,
383 min_io_address: DEFAULT_IO_BASE,
384 min_mem_address: DEFAULT_MEM_BASE,
386 nr_irqs: 35,
387 device_interrupt: cabriolet_device_interrupt,
389 init_arch: pyxis_init_arch,
390 init_irq: cabriolet_init_irq,
391 init_rtc: common_init_rtc,
392 init_pci: alphapc164_init_pci,
393 pci_map_irq: alphapc164_map_irq,
394 pci_swizzle: common_swizzle,
396 ALIAS_MV(lx164)
397 #endif
399 #if defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_PC164)
400 struct alpha_machine_vector pc164_mv __initmv = {
401 vector_name: "PC164",
402 DO_EV5_MMU,
403 DO_DEFAULT_RTC,
404 DO_CIA_IO,
405 DO_CIA_BUS,
406 machine_check: cia_machine_check,
407 max_dma_address: ALPHA_MAX_DMA_ADDRESS,
408 min_io_address: DEFAULT_IO_BASE,
409 min_mem_address: CIA_DEFAULT_MEM_BASE,
411 nr_irqs: 35,
412 device_interrupt: pc164_device_interrupt,
414 init_arch: cia_init_arch,
415 init_irq: cabriolet_init_irq,
416 init_rtc: common_init_rtc,
417 init_pci: alphapc164_init_pci,
418 pci_map_irq: alphapc164_map_irq,
419 pci_swizzle: common_swizzle,
421 ALIAS_MV(pc164)
422 #endif