1/*
2 *	linux/arch/alpha/kernel/sys_rawhide.c
3 *
4 *	Copyright (C) 1995 David A Rusling
5 *	Copyright (C) 1996 Jay A Estabrook
6 *	Copyright (C) 1998, 1999 Richard Henderson
7 *
8 * Code supporting the RAWHIDE.
9 */
10
11#include <linux/kernel.h>
12#include <linux/types.h>
13#include <linux/mm.h>
14#include <linux/sched.h>
15#include <linux/pci.h>
16#include <linux/init.h>
17
18#include <asm/ptrace.h>
19#include <asm/system.h>
20#include <asm/dma.h>
21#include <asm/irq.h>
22#include <asm/mmu_context.h>
23#include <asm/io.h>
24#include <asm/pgtable.h>
25#include <asm/core_mcpcia.h>
26
27#include "proto.h"
28#include "irq_impl.h"
29#include "pci_impl.h"
30#include "machvec_impl.h"
31
32
33/*
34 * HACK ALERT! only the boot cpu is used for interrupts.
35 */
36
37
38/* Note mask bit is true for ENABLED irqs.  */
39
40static unsigned int hose_irq_masks[4] = {
41	0xff0000, 0xfe0000, 0xff0000, 0xff0000
42};
43static unsigned int cached_irq_masks[4];
44spinlock_t rawhide_irq_lock = SPIN_LOCK_UNLOCKED;
45
46static inline void
47rawhide_update_irq_hw(int hose, int mask)
48{
49	*(vuip)MCPCIA_INT_MASK0(MCPCIA_HOSE2MID(hose)) = mask;
50	mb();
51	*(vuip)MCPCIA_INT_MASK0(MCPCIA_HOSE2MID(hose));
52}
53
54static inline void
55rawhide_enable_irq(unsigned int irq)
56{
57	unsigned int mask, hose;
58
59	irq -= 16;
60	hose = irq / 24;
61	irq -= hose * 24;
62	mask = 1 << irq;
63
64	spin_lock(&rawhide_irq_lock);
65	mask |= cached_irq_masks[hose];
66	cached_irq_masks[hose] = mask;
67	rawhide_update_irq_hw(hose, mask);
68	spin_unlock(&rawhide_irq_lock);
69}
70
71static void
72rawhide_disable_irq(unsigned int irq)
73{
74	unsigned int mask, hose;
75
76	irq -= 16;
77	hose = irq / 24;
78	irq -= hose * 24;
79	mask = ~(1 << irq) | hose_irq_masks[hose];
80
81	spin_lock(&rawhide_irq_lock);
82	mask &= cached_irq_masks[hose];
83	cached_irq_masks[hose] = mask;
84	rawhide_update_irq_hw(hose, mask);
85	spin_unlock(&rawhide_irq_lock);
86}
87
88static void
89rawhide_mask_and_ack_irq(unsigned int irq)
90{
91	unsigned int mask, mask1, hose;
92
93	irq -= 16;
94	hose = irq / 24;
95	irq -= hose * 24;
96	mask1 = 1 << irq;
97	mask = ~mask1 | hose_irq_masks[hose];
98
99	spin_lock(&rawhide_irq_lock);
100
101	mask &= cached_irq_masks[hose];
102	cached_irq_masks[hose] = mask;
103	rawhide_update_irq_hw(hose, mask);
104
105	/* Clear the interrupt.  */
106	*(vuip)MCPCIA_INT_REQ(MCPCIA_HOSE2MID(hose)) = mask1;
107
108	spin_unlock(&rawhide_irq_lock);
109}
110
111static unsigned int
112rawhide_startup_irq(unsigned int irq)
113{
114	rawhide_enable_irq(irq);
115	return 0;
116}
117
118static void
119rawhide_end_irq(unsigned int irq)
120{
121	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
122		rawhide_enable_irq(irq);
123}
124
125static struct hw_interrupt_type rawhide_irq_type = {
126	typename:	"RAWHIDE",
127	startup:	rawhide_startup_irq,
128	shutdown:	rawhide_disable_irq,
129	enable:		rawhide_enable_irq,
130	disable:	rawhide_disable_irq,
131	ack:		rawhide_mask_and_ack_irq,
132	end:		rawhide_end_irq,
133};
134
135static void
136rawhide_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
137{
138	int irq;
139
140	irq = (vector - 0x800) >> 4;
141
142        /*
143         * The RAWHIDE SRM console reports PCI interrupts with a vector
144	 * 0x80 *higher* than one might expect, as PCI IRQ 0 (ie bit 0)
145	 * shows up as IRQ 24, etc, etc. We adjust it down by 8 to have
146	 * it line up with the actual bit numbers from the REQ registers,
147	 * which is how we manage the interrupts/mask. Sigh...
148	 *
149	 * Also, PCI #1 interrupts are offset some more... :-(
150         */
151
152	if (irq == 52) {
153		/* SCSI on PCI1 is special.  */
154		irq = 72;
155	}
156
157	/* Adjust by which hose it is from.  */
158	irq -= ((irq + 16) >> 2) & 0x38;
159
160	handle_irq(irq, regs);
161}
162
163static void __init
164rawhide_init_irq(void)
165{
166	struct pci_controller *hose;
167	long i;
168
169	mcpcia_init_hoses();
170
171	for (hose = hose_head; hose; hose = hose->next) {
172		unsigned int h = hose->index;
173		unsigned int mask = hose_irq_masks[h];
174
175		cached_irq_masks[h] = mask;
176		*(vuip)MCPCIA_INT_MASK0(MCPCIA_HOSE2MID(h)) = mask;
177		*(vuip)MCPCIA_INT_MASK1(MCPCIA_HOSE2MID(h)) = 0;
178	}
179
180	for (i = 16; i < 128; ++i) {
181		irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
182		irq_desc[i].handler = &rawhide_irq_type;
183	}
184
185	init_i8259a_irqs();
186	common_init_isa_dma();
187}
188
189/*
190 * PCI Fixup configuration.
191 *
192 * Summary @ MCPCIA_PCI0_INT_REQ:
193 * Bit      Meaning
194 * 0        Interrupt Line A from slot 2 PCI0
195 * 1        Interrupt Line B from slot 2 PCI0
196 * 2        Interrupt Line C from slot 2 PCI0
197 * 3        Interrupt Line D from slot 2 PCI0
198 * 4        Interrupt Line A from slot 3 PCI0
199 * 5        Interrupt Line B from slot 3 PCI0
200 * 6        Interrupt Line C from slot 3 PCI0
201 * 7        Interrupt Line D from slot 3 PCI0
202 * 8        Interrupt Line A from slot 4 PCI0
203 * 9        Interrupt Line B from slot 4 PCI0
204 * 10       Interrupt Line C from slot 4 PCI0
205 * 11       Interrupt Line D from slot 4 PCI0
206 * 12       Interrupt Line A from slot 5 PCI0
207 * 13       Interrupt Line B from slot 5 PCI0
208 * 14       Interrupt Line C from slot 5 PCI0
209 * 15       Interrupt Line D from slot 5 PCI0
210 * 16       EISA interrupt (PCI 0) or SCSI interrupt (PCI 1)
211 * 17-23    NA
212 *
213 * IdSel
214 *   1	 EISA bridge (PCI bus 0 only)
215 *   2 	 PCI option slot 2
216 *   3	 PCI option slot 3
217 *   4   PCI option slot 4
218 *   5   PCI option slot 5
219 *
220 */
221
222static int __init
223rawhide_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
224{
225	static char irq_tab[5][5] __initdata = {
226		/*INT    INTA   INTB   INTC   INTD */
227		{ 16+16, 16+16, 16+16, 16+16, 16+16}, /* IdSel 1 SCSI PCI 1 */
228		{ 16+ 0, 16+ 0, 16+ 1, 16+ 2, 16+ 3}, /* IdSel 2 slot 2 */
229		{ 16+ 4, 16+ 4, 16+ 5, 16+ 6, 16+ 7}, /* IdSel 3 slot 3 */
230		{ 16+ 8, 16+ 8, 16+ 9, 16+10, 16+11}, /* IdSel 4 slot 4 */
231		{ 16+12, 16+12, 16+13, 16+14, 16+15}  /* IdSel 5 slot 5 */
232	};
233	const long min_idsel = 1, max_idsel = 5, irqs_per_slot = 5;
234
235	struct pci_controller *hose = dev->sysdata;
236	int irq = COMMON_TABLE_LOOKUP;
237	if (irq >= 0)
238		irq += 24 * hose->index;
239	return irq;
240}
241
242
243/*
244 * The System Vector
245 */
246
247struct alpha_machine_vector rawhide_mv __initmv = {
248	vector_name:		"Rawhide",
249	DO_EV5_MMU,
250	DO_DEFAULT_RTC,
251	DO_MCPCIA_IO,
252	DO_MCPCIA_BUS,
253	machine_check:		mcpcia_machine_check,
254	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
255	min_io_address:		DEFAULT_IO_BASE,
256	min_mem_address:	MCPCIA_DEFAULT_MEM_BASE,
257	pci_dac_offset:		MCPCIA_DAC_OFFSET,
258
259	nr_irqs:		128,
260	device_interrupt:	rawhide_srm_device_interrupt,
261
262	init_arch:		mcpcia_init_arch,
263	init_irq:		rawhide_init_irq,
264	init_rtc:		common_init_rtc,
265	init_pci:		common_init_pci,
266	kill_arch:		NULL,
267	pci_map_irq:		rawhide_map_irq,
268	pci_swizzle:		common_swizzle,
269};
270ALIAS_MV(rawhide)
271