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