1/* 2 * linux/arch/alpha/kernel/sys_wildfire.c 3 * 4 * Wildfire support. 5 * 6 * Copyright (C) 2000 Andrea Arcangeli <andrea@suse.de> SuSE 7 */ 8 9#include <linux/kernel.h> 10#include <linux/types.h> 11#include <linux/mm.h> 12#include <linux/sched.h> 13#include <linux/pci.h> 14#include <linux/init.h> 15#include <linux/bitops.h> 16 17#include <asm/ptrace.h> 18#include <asm/system.h> 19#include <asm/dma.h> 20#include <asm/irq.h> 21#include <asm/mmu_context.h> 22#include <asm/io.h> 23#include <asm/pgtable.h> 24#include <asm/core_wildfire.h> 25#include <asm/hwrpb.h> 26#include <asm/tlbflush.h> 27 28#include "proto.h" 29#include "irq_impl.h" 30#include "pci_impl.h" 31#include "machvec_impl.h" 32 33static unsigned long cached_irq_mask[WILDFIRE_NR_IRQS/(sizeof(long)*8)]; 34 35DEFINE_SPINLOCK(wildfire_irq_lock); 36 37static int doing_init_irq_hw = 0; 38 39static void 40wildfire_update_irq_hw(unsigned int irq) 41{ 42 int qbbno = (irq >> 8) & (WILDFIRE_MAX_QBB - 1); 43 int pcano = (irq >> 6) & (WILDFIRE_PCA_PER_QBB - 1); 44 wildfire_pca *pca; 45 volatile unsigned long * enable0; 46 47 if (!WILDFIRE_PCA_EXISTS(qbbno, pcano)) { 48 if (!doing_init_irq_hw) { 49 printk(KERN_ERR "wildfire_update_irq_hw:" 50 " got irq %d for non-existent PCA %d" 51 " on QBB %d.\n", 52 irq, pcano, qbbno); 53 } 54 return; 55 } 56 57 pca = WILDFIRE_pca(qbbno, pcano); 58 enable0 = (unsigned long *) &pca->pca_int[0].enable; /* ??? */ 59 60 *enable0 = cached_irq_mask[qbbno * WILDFIRE_PCA_PER_QBB + pcano]; 61 mb(); 62 *enable0; 63} 64 65static void __init 66wildfire_init_irq_hw(void) 67{ 68 int i; 69 70 doing_init_irq_hw = 1; 71 72 /* Need to update only once for every possible PCA. */ 73 for (i = 0; i < WILDFIRE_NR_IRQS; i+=WILDFIRE_IRQ_PER_PCA) 74 wildfire_update_irq_hw(i); 75 76 doing_init_irq_hw = 0; 77} 78 79static void 80wildfire_enable_irq(unsigned int irq) 81{ 82 if (irq < 16) 83 i8259a_enable_irq(irq); 84 85 spin_lock(&wildfire_irq_lock); 86 set_bit(irq, &cached_irq_mask); 87 wildfire_update_irq_hw(irq); 88 spin_unlock(&wildfire_irq_lock); 89} 90 91static void 92wildfire_disable_irq(unsigned int irq) 93{ 94 if (irq < 16) 95 i8259a_disable_irq(irq); 96 97 spin_lock(&wildfire_irq_lock); 98 clear_bit(irq, &cached_irq_mask); 99 wildfire_update_irq_hw(irq); 100 spin_unlock(&wildfire_irq_lock); 101} 102 103static void 104wildfire_mask_and_ack_irq(unsigned int irq) 105{ 106 if (irq < 16) 107 i8259a_mask_and_ack_irq(irq); 108 109 spin_lock(&wildfire_irq_lock); 110 clear_bit(irq, &cached_irq_mask); 111 wildfire_update_irq_hw(irq); 112 spin_unlock(&wildfire_irq_lock); 113} 114 115static unsigned int 116wildfire_startup_irq(unsigned int irq) 117{ 118 wildfire_enable_irq(irq); 119 return 0; /* never anything pending */ 120} 121 122static void 123wildfire_end_irq(unsigned int irq) 124{ 125 if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) 126 wildfire_enable_irq(irq); 127} 128 129static struct irq_chip wildfire_irq_type = { 130 .name = "WILDFIRE", 131 .startup = wildfire_startup_irq, 132 .shutdown = wildfire_disable_irq, 133 .enable = wildfire_enable_irq, 134 .disable = wildfire_disable_irq, 135 .ack = wildfire_mask_and_ack_irq, 136 .end = wildfire_end_irq, 137}; 138 139static void __init 140wildfire_init_irq_per_pca(int qbbno, int pcano) 141{ 142 int i, irq_bias; 143 unsigned long io_bias; 144 static struct irqaction isa_enable = { 145 .handler = no_action, 146 .name = "isa_enable", 147 }; 148 149 irq_bias = qbbno * (WILDFIRE_PCA_PER_QBB * WILDFIRE_IRQ_PER_PCA) 150 + pcano * WILDFIRE_IRQ_PER_PCA; 151 152 /* Only need the following for first PCI bus per PCA. */ 153 io_bias = WILDFIRE_IO(qbbno, pcano<<1) - WILDFIRE_IO_BIAS; 154 155 156 157 for (i = 0; i < 16; ++i) { 158 if (i == 2) 159 continue; 160 irq_desc[i+irq_bias].status = IRQ_DISABLED | IRQ_LEVEL; 161 irq_desc[i+irq_bias].chip = &wildfire_irq_type; 162 } 163 164 irq_desc[36+irq_bias].status = IRQ_DISABLED | IRQ_LEVEL; 165 irq_desc[36+irq_bias].chip = &wildfire_irq_type; 166 for (i = 40; i < 64; ++i) { 167 irq_desc[i+irq_bias].status = IRQ_DISABLED | IRQ_LEVEL; 168 irq_desc[i+irq_bias].chip = &wildfire_irq_type; 169 } 170 171 setup_irq(32+irq_bias, &isa_enable); 172} 173 174static void __init 175wildfire_init_irq(void) 176{ 177 int qbbno, pcano; 178 179 wildfire_init_irq_hw(); 180 init_i8259a_irqs(); 181 182 for (qbbno = 0; qbbno < WILDFIRE_MAX_QBB; qbbno++) { 183 if (WILDFIRE_QBB_EXISTS(qbbno)) { 184 for (pcano = 0; pcano < WILDFIRE_PCA_PER_QBB; pcano++) { 185 if (WILDFIRE_PCA_EXISTS(qbbno, pcano)) { 186 wildfire_init_irq_per_pca(qbbno, pcano); 187 } 188 } 189 } 190 } 191} 192 193static void 194wildfire_device_interrupt(unsigned long vector) 195{ 196 int irq; 197 198 irq = (vector - 0x800) >> 4; 199 200 /* 201 * bits 10-8: source QBB ID 202 * bits 7-6: PCA 203 * bits 5-0: irq in PCA 204 */ 205 206 handle_irq(irq); 207 return; 208} 209 210/* 211 * PCI Fixup configuration. 212 * 213 * Summary per PCA (2 PCI or HIPPI buses): 214 * 215 * Bit Meaning 216 * 0-15 ISA 217 * 218 *32 ISA summary 219 *33 SMI 220 *34 NMI 221 *36 builtin QLogic SCSI (or slot 0 if no IO module) 222 *40 Interrupt Line A from slot 2 PCI0 223 *41 Interrupt Line B from slot 2 PCI0 224 *42 Interrupt Line C from slot 2 PCI0 225 *43 Interrupt Line D from slot 2 PCI0 226 *44 Interrupt Line A from slot 3 PCI0 227 *45 Interrupt Line B from slot 3 PCI0 228 *46 Interrupt Line C from slot 3 PCI0 229 *47 Interrupt Line D from slot 3 PCI0 230 * 231 *48 Interrupt Line A from slot 4 PCI1 232 *49 Interrupt Line B from slot 4 PCI1 233 *50 Interrupt Line C from slot 4 PCI1 234 *51 Interrupt Line D from slot 4 PCI1 235 *52 Interrupt Line A from slot 5 PCI1 236 *53 Interrupt Line B from slot 5 PCI1 237 *54 Interrupt Line C from slot 5 PCI1 238 *55 Interrupt Line D from slot 5 PCI1 239 *56 Interrupt Line A from slot 6 PCI1 240 *57 Interrupt Line B from slot 6 PCI1 241 *58 Interrupt Line C from slot 6 PCI1 242 *50 Interrupt Line D from slot 6 PCI1 243 *60 Interrupt Line A from slot 7 PCI1 244 *61 Interrupt Line B from slot 7 PCI1 245 *62 Interrupt Line C from slot 7 PCI1 246 *63 Interrupt Line D from slot 7 PCI1 247 * 248 * 249 * IdSel 250 * 0 Cypress Bridge I/O (ISA summary interrupt) 251 * 1 64 bit PCI 0 option slot 1 (SCSI QLogic builtin) 252 * 2 64 bit PCI 0 option slot 2 253 * 3 64 bit PCI 0 option slot 3 254 * 4 64 bit PCI 1 option slot 4 255 * 5 64 bit PCI 1 option slot 5 256 * 6 64 bit PCI 1 option slot 6 257 * 7 64 bit PCI 1 option slot 7 258 */ 259 260static int __init 261wildfire_map_irq(struct pci_dev *dev, u8 slot, u8 pin) 262{ 263 static char irq_tab[8][5] __initdata = { 264 /*INT INTA INTB INTC INTD */ 265 { -1, -1, -1, -1, -1}, /* IdSel 0 ISA Bridge */ 266 { 36, 36, 36+1, 36+2, 36+3}, /* IdSel 1 SCSI builtin */ 267 { 40, 40, 40+1, 40+2, 40+3}, /* IdSel 2 PCI 0 slot 2 */ 268 { 44, 44, 44+1, 44+2, 44+3}, /* IdSel 3 PCI 0 slot 3 */ 269 { 48, 48, 48+1, 48+2, 48+3}, /* IdSel 4 PCI 1 slot 4 */ 270 { 52, 52, 52+1, 52+2, 52+3}, /* IdSel 5 PCI 1 slot 5 */ 271 { 56, 56, 56+1, 56+2, 56+3}, /* IdSel 6 PCI 1 slot 6 */ 272 { 60, 60, 60+1, 60+2, 60+3}, /* IdSel 7 PCI 1 slot 7 */ 273 }; 274 long min_idsel = 0, max_idsel = 7, irqs_per_slot = 5; 275 276 struct pci_controller *hose = dev->sysdata; 277 int irq = COMMON_TABLE_LOOKUP; 278 279 if (irq > 0) { 280 int qbbno = hose->index >> 3; 281 int pcano = (hose->index >> 1) & 3; 282 irq += (qbbno << 8) + (pcano << 6); 283 } 284 return irq; 285} 286 287 288/* 289 * The System Vectors 290 */ 291 292struct alpha_machine_vector wildfire_mv __initmv = { 293 .vector_name = "WILDFIRE", 294 DO_EV6_MMU, 295 DO_DEFAULT_RTC, 296 DO_WILDFIRE_IO, 297 .machine_check = wildfire_machine_check, 298 .max_isa_dma_address = ALPHA_MAX_ISA_DMA_ADDRESS, 299 .min_io_address = DEFAULT_IO_BASE, 300 .min_mem_address = DEFAULT_MEM_BASE, 301 302 .nr_irqs = WILDFIRE_NR_IRQS, 303 .device_interrupt = wildfire_device_interrupt, 304 305 .init_arch = wildfire_init_arch, 306 .init_irq = wildfire_init_irq, 307 .init_rtc = common_init_rtc, 308 .init_pci = common_init_pci, 309 .kill_arch = wildfire_kill_arch, 310 .pci_map_irq = wildfire_map_irq, 311 .pci_swizzle = common_swizzle, 312 313 .pa_to_nid = wildfire_pa_to_nid, 314 .cpuid_to_nid = wildfire_cpuid_to_nid, 315 .node_mem_start = wildfire_node_mem_start, 316 .node_mem_size = wildfire_node_mem_size, 317}; 318ALIAS_MV(wildfire) 319