| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  *	linux/arch/alpha/kernel/sys_rawhide.c | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *	Copyright (C) 1995 David A Rusling | 
					
						
							|  |  |  |  *	Copyright (C) 1996 Jay A Estabrook | 
					
						
							|  |  |  |  *	Copyright (C) 1998, 1999 Richard Henderson | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Code supporting the RAWHIDE. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <linux/kernel.h>
 | 
					
						
							|  |  |  | #include <linux/types.h>
 | 
					
						
							|  |  |  | #include <linux/mm.h>
 | 
					
						
							|  |  |  | #include <linux/sched.h>
 | 
					
						
							|  |  |  | #include <linux/pci.h>
 | 
					
						
							|  |  |  | #include <linux/init.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <asm/ptrace.h>
 | 
					
						
							|  |  |  | #include <asm/dma.h>
 | 
					
						
							|  |  |  | #include <asm/irq.h>
 | 
					
						
							|  |  |  | #include <asm/mmu_context.h>
 | 
					
						
							|  |  |  | #include <asm/io.h>
 | 
					
						
							|  |  |  | #include <asm/pgtable.h>
 | 
					
						
							|  |  |  | #include <asm/core_mcpcia.h>
 | 
					
						
							|  |  |  | #include <asm/tlbflush.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "proto.h"
 | 
					
						
							|  |  |  | #include "irq_impl.h"
 | 
					
						
							|  |  |  | #include "pci_impl.h"
 | 
					
						
							|  |  |  | #include "machvec_impl.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * HACK ALERT! only the boot cpu is used for interrupts. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Note mask bit is true for ENABLED irqs.  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static unsigned int hose_irq_masks[4] = { | 
					
						
							|  |  |  | 	0xff0000, 0xfe0000, 0xff0000, 0xff0000 | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | static unsigned int cached_irq_masks[4]; | 
					
						
							|  |  |  | DEFINE_SPINLOCK(rawhide_irq_lock); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static inline void | 
					
						
							|  |  |  | rawhide_update_irq_hw(int hose, int mask) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	*(vuip)MCPCIA_INT_MASK0(MCPCIA_HOSE2MID(hose)) = mask; | 
					
						
							|  |  |  | 	mb(); | 
					
						
							|  |  |  | 	*(vuip)MCPCIA_INT_MASK0(MCPCIA_HOSE2MID(hose)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-04-16 22:53:17 -07:00
										 |  |  | #define hose_exists(h) \
 | 
					
						
							|  |  |  |   (((h) < MCPCIA_MAX_HOSES) && (cached_irq_masks[(h)] != 0)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | static inline void  | 
					
						
							| 
									
										
										
										
											2011-02-06 14:32:44 +00:00
										 |  |  | rawhide_enable_irq(struct irq_data *d) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	unsigned int mask, hose; | 
					
						
							| 
									
										
										
										
											2011-02-06 14:32:44 +00:00
										 |  |  | 	unsigned int irq = d->irq; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	irq -= 16; | 
					
						
							|  |  |  | 	hose = irq / 24; | 
					
						
							| 
									
										
										
										
											2007-04-16 22:53:17 -07:00
										 |  |  | 	if (!hose_exists(hose)) /* if hose non-existent, exit */ | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	irq -= hose * 24; | 
					
						
							|  |  |  | 	mask = 1 << irq; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	spin_lock(&rawhide_irq_lock); | 
					
						
							|  |  |  | 	mask |= cached_irq_masks[hose]; | 
					
						
							|  |  |  | 	cached_irq_masks[hose] = mask; | 
					
						
							|  |  |  | 	rawhide_update_irq_hw(hose, mask); | 
					
						
							|  |  |  | 	spin_unlock(&rawhide_irq_lock); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void  | 
					
						
							| 
									
										
										
										
											2011-02-06 14:32:44 +00:00
										 |  |  | rawhide_disable_irq(struct irq_data *d) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	unsigned int mask, hose; | 
					
						
							| 
									
										
										
										
											2011-02-06 14:32:44 +00:00
										 |  |  | 	unsigned int irq = d->irq; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	irq -= 16; | 
					
						
							|  |  |  | 	hose = irq / 24; | 
					
						
							| 
									
										
										
										
											2007-04-16 22:53:17 -07:00
										 |  |  | 	if (!hose_exists(hose)) /* if hose non-existent, exit */ | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	irq -= hose * 24; | 
					
						
							|  |  |  | 	mask = ~(1 << irq) | hose_irq_masks[hose]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	spin_lock(&rawhide_irq_lock); | 
					
						
							|  |  |  | 	mask &= cached_irq_masks[hose]; | 
					
						
							|  |  |  | 	cached_irq_masks[hose] = mask; | 
					
						
							|  |  |  | 	rawhide_update_irq_hw(hose, mask); | 
					
						
							|  |  |  | 	spin_unlock(&rawhide_irq_lock); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void | 
					
						
							| 
									
										
										
										
											2011-02-06 14:32:44 +00:00
										 |  |  | rawhide_mask_and_ack_irq(struct irq_data *d) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	unsigned int mask, mask1, hose; | 
					
						
							| 
									
										
										
										
											2011-02-06 14:32:44 +00:00
										 |  |  | 	unsigned int irq = d->irq; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	irq -= 16; | 
					
						
							|  |  |  | 	hose = irq / 24; | 
					
						
							| 
									
										
										
										
											2007-04-16 22:53:17 -07:00
										 |  |  | 	if (!hose_exists(hose)) /* if hose non-existent, exit */ | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	irq -= hose * 24; | 
					
						
							|  |  |  | 	mask1 = 1 << irq; | 
					
						
							|  |  |  | 	mask = ~mask1 | hose_irq_masks[hose]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	spin_lock(&rawhide_irq_lock); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mask &= cached_irq_masks[hose]; | 
					
						
							|  |  |  | 	cached_irq_masks[hose] = mask; | 
					
						
							|  |  |  | 	rawhide_update_irq_hw(hose, mask); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Clear the interrupt.  */ | 
					
						
							|  |  |  | 	*(vuip)MCPCIA_INT_REQ(MCPCIA_HOSE2MID(hose)) = mask1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	spin_unlock(&rawhide_irq_lock); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-06-16 15:33:25 -07:00
										 |  |  | static struct irq_chip rawhide_irq_type = { | 
					
						
							| 
									
										
										
										
											2009-11-30 22:51:31 -05:00
										 |  |  | 	.name		= "RAWHIDE", | 
					
						
							| 
									
										
										
										
											2011-02-06 14:32:44 +00:00
										 |  |  | 	.irq_unmask	= rawhide_enable_irq, | 
					
						
							|  |  |  | 	.irq_mask	= rawhide_disable_irq, | 
					
						
							|  |  |  | 	.irq_mask_ack	= rawhide_mask_and_ack_irq, | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void  | 
					
						
							| 
									
										
										
										
											2006-10-08 14:36:08 +01:00
										 |  |  | rawhide_srm_device_interrupt(unsigned long vector) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	int irq; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	irq = (vector - 0x800) >> 4; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /*
 | 
					
						
							|  |  |  |          * The RAWHIDE SRM console reports PCI interrupts with a vector | 
					
						
							|  |  |  | 	 * 0x80 *higher* than one might expect, as PCI IRQ 0 (ie bit 0) | 
					
						
							|  |  |  | 	 * shows up as IRQ 24, etc, etc. We adjust it down by 8 to have | 
					
						
							|  |  |  | 	 * it line up with the actual bit numbers from the REQ registers, | 
					
						
							|  |  |  | 	 * which is how we manage the interrupts/mask. Sigh... | 
					
						
							|  |  |  | 	 * | 
					
						
							|  |  |  | 	 * Also, PCI #1 interrupts are offset some more... :-( | 
					
						
							|  |  |  |          */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (irq == 52) { | 
					
						
							|  |  |  | 		/* SCSI on PCI1 is special.  */ | 
					
						
							|  |  |  | 		irq = 72; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Adjust by which hose it is from.  */ | 
					
						
							|  |  |  | 	irq -= ((irq + 16) >> 2) & 0x38; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-10-08 14:37:32 +01:00
										 |  |  | 	handle_irq(irq); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void __init | 
					
						
							|  |  |  | rawhide_init_irq(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct pci_controller *hose; | 
					
						
							|  |  |  | 	long i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	mcpcia_init_hoses(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-04-16 22:53:17 -07:00
										 |  |  | 	/* Clear them all; only hoses that exist will be non-zero. */ | 
					
						
							|  |  |  | 	for (i = 0; i < MCPCIA_MAX_HOSES; i++) cached_irq_masks[i] = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	for (hose = hose_head; hose; hose = hose->next) { | 
					
						
							|  |  |  | 		unsigned int h = hose->index; | 
					
						
							|  |  |  | 		unsigned int mask = hose_irq_masks[h]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		cached_irq_masks[h] = mask; | 
					
						
							|  |  |  | 		*(vuip)MCPCIA_INT_MASK0(MCPCIA_HOSE2MID(h)) = mask; | 
					
						
							|  |  |  | 		*(vuip)MCPCIA_INT_MASK1(MCPCIA_HOSE2MID(h)) = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (i = 16; i < 128; ++i) { | 
					
						
							| 
									
										
										
										
											2011-03-25 22:17:31 +01:00
										 |  |  | 		irq_set_chip_and_handler(i, &rawhide_irq_type, | 
					
						
							|  |  |  | 					 handle_level_irq); | 
					
						
							| 
									
										
										
										
											2011-02-06 14:32:44 +00:00
										 |  |  | 		irq_set_status_flags(i, IRQ_LEVEL); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	init_i8259a_irqs(); | 
					
						
							|  |  |  | 	common_init_isa_dma(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * PCI Fixup configuration. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Summary @ MCPCIA_PCI0_INT_REQ: | 
					
						
							|  |  |  |  * Bit      Meaning | 
					
						
							|  |  |  |  * 0        Interrupt Line A from slot 2 PCI0 | 
					
						
							|  |  |  |  * 1        Interrupt Line B from slot 2 PCI0 | 
					
						
							|  |  |  |  * 2        Interrupt Line C from slot 2 PCI0 | 
					
						
							|  |  |  |  * 3        Interrupt Line D from slot 2 PCI0 | 
					
						
							|  |  |  |  * 4        Interrupt Line A from slot 3 PCI0 | 
					
						
							|  |  |  |  * 5        Interrupt Line B from slot 3 PCI0 | 
					
						
							|  |  |  |  * 6        Interrupt Line C from slot 3 PCI0 | 
					
						
							|  |  |  |  * 7        Interrupt Line D from slot 3 PCI0 | 
					
						
							|  |  |  |  * 8        Interrupt Line A from slot 4 PCI0 | 
					
						
							|  |  |  |  * 9        Interrupt Line B from slot 4 PCI0 | 
					
						
							|  |  |  |  * 10       Interrupt Line C from slot 4 PCI0 | 
					
						
							|  |  |  |  * 11       Interrupt Line D from slot 4 PCI0 | 
					
						
							|  |  |  |  * 12       Interrupt Line A from slot 5 PCI0 | 
					
						
							|  |  |  |  * 13       Interrupt Line B from slot 5 PCI0 | 
					
						
							|  |  |  |  * 14       Interrupt Line C from slot 5 PCI0 | 
					
						
							|  |  |  |  * 15       Interrupt Line D from slot 5 PCI0 | 
					
						
							|  |  |  |  * 16       EISA interrupt (PCI 0) or SCSI interrupt (PCI 1) | 
					
						
							|  |  |  |  * 17-23    NA | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * IdSel	 | 
					
						
							|  |  |  |  *   1	 EISA bridge (PCI bus 0 only) | 
					
						
							|  |  |  |  *   2 	 PCI option slot 2 | 
					
						
							|  |  |  |  *   3	 PCI option slot 3 | 
					
						
							|  |  |  |  *   4   PCI option slot 4 | 
					
						
							|  |  |  |  *   5   PCI option slot 5 | 
					
						
							|  |  |  |  *  | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int __init | 
					
						
							| 
									
										
										
										
											2011-06-10 15:30:21 +01:00
										 |  |  | rawhide_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	static char irq_tab[5][5] __initdata = { | 
					
						
							|  |  |  | 		/*INT    INTA   INTB   INTC   INTD */ | 
					
						
							|  |  |  | 		{ 16+16, 16+16, 16+16, 16+16, 16+16}, /* IdSel 1 SCSI PCI 1 */ | 
					
						
							|  |  |  | 		{ 16+ 0, 16+ 0, 16+ 1, 16+ 2, 16+ 3}, /* IdSel 2 slot 2 */ | 
					
						
							|  |  |  | 		{ 16+ 4, 16+ 4, 16+ 5, 16+ 6, 16+ 7}, /* IdSel 3 slot 3 */ | 
					
						
							|  |  |  | 		{ 16+ 8, 16+ 8, 16+ 9, 16+10, 16+11}, /* IdSel 4 slot 4 */ | 
					
						
							|  |  |  | 		{ 16+12, 16+12, 16+13, 16+14, 16+15}  /* IdSel 5 slot 5 */ | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 	const long min_idsel = 1, max_idsel = 5, irqs_per_slot = 5; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	struct pci_controller *hose = dev->sysdata; | 
					
						
							|  |  |  | 	int irq = COMMON_TABLE_LOOKUP; | 
					
						
							|  |  |  | 	if (irq >= 0) | 
					
						
							|  |  |  | 		irq += 24 * hose->index; | 
					
						
							|  |  |  | 	return irq; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * The System Vector | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct alpha_machine_vector rawhide_mv __initmv = { | 
					
						
							|  |  |  | 	.vector_name		= "Rawhide", | 
					
						
							|  |  |  | 	DO_EV5_MMU, | 
					
						
							|  |  |  | 	DO_DEFAULT_RTC, | 
					
						
							|  |  |  | 	DO_MCPCIA_IO, | 
					
						
							|  |  |  | 	.machine_check		= mcpcia_machine_check, | 
					
						
							|  |  |  | 	.max_isa_dma_address	= ALPHA_MAX_ISA_DMA_ADDRESS, | 
					
						
							|  |  |  | 	.min_io_address		= DEFAULT_IO_BASE, | 
					
						
							|  |  |  | 	.min_mem_address	= MCPCIA_DEFAULT_MEM_BASE, | 
					
						
							|  |  |  | 	.pci_dac_offset		= MCPCIA_DAC_OFFSET, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	.nr_irqs		= 128, | 
					
						
							|  |  |  | 	.device_interrupt	= rawhide_srm_device_interrupt, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	.init_arch		= mcpcia_init_arch, | 
					
						
							|  |  |  | 	.init_irq		= rawhide_init_irq, | 
					
						
							|  |  |  | 	.init_rtc		= common_init_rtc, | 
					
						
							|  |  |  | 	.init_pci		= common_init_pci, | 
					
						
							|  |  |  | 	.kill_arch		= NULL, | 
					
						
							|  |  |  | 	.pci_map_irq		= rawhide_map_irq, | 
					
						
							|  |  |  | 	.pci_swizzle		= common_swizzle, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | ALIAS_MV(rawhide) |