File: /usr/src/linux/arch/alpha/kernel/sys_cabriolet.c

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