1 /* $NetBSD: pci_kn20aa.c,v 1.20 1996/11/13 21:13:31 cgd Exp $ */ 2 3 /* 4 * Copyright (c) 1995, 1996 Carnegie-Mellon University. 5 * All rights reserved. 6 * 7 * Author: Chris G. Demetriou 8 * 9 * Permission to use, copy, modify and distribute this software and 10 * its documentation is hereby granted, provided that both the copyright 11 * notice and this permission notice appear in all copies of the 12 * software, derivative works or modified versions, and any portions 13 * thereof, and that both notices appear in supporting documentation. 14 * 15 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 16 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 17 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 18 * 19 * Carnegie Mellon requests users of this software to return to 20 * 21 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 22 * School of Computer Science 23 * Carnegie Mellon University 24 * Pittsburgh PA 15213-3890 25 * 26 * any improvements or extensions that they make and grant Carnegie the 27 * rights to redistribute these changes. 28 */ 29 30 #include <sys/types.h> 31 #include <sys/param.h> 32 #include <sys/time.h> 33 #include <sys/systm.h> 34 #include <sys/errno.h> 35 #include <sys/malloc.h> 36 #include <sys/device.h> 37 #include <sys/syslog.h> 38 39 #include <vm/vm.h> 40 41 #include <machine/autoconf.h> 42 43 #include <dev/pci/pcireg.h> 44 #include <dev/pci/pcivar.h> 45 46 #include <alpha/pci/ciareg.h> 47 #include <alpha/pci/ciavar.h> 48 49 #include <alpha/pci/pci_kn20aa.h> 50 51 #ifndef EVCNT_COUNTERS 52 #include <machine/intrcnt.h> 53 #endif 54 55 #include "sio.h" 56 #if NSIO 57 #include <alpha/pci/siovar.h> 58 #endif 59 60 int dec_kn20aa_intr_map __P((void *, pcitag_t, int, int, 61 pci_intr_handle_t *)); 62 const char *dec_kn20aa_intr_string __P((void *, pci_intr_handle_t)); 63 void *dec_kn20aa_intr_establish __P((void *, pci_intr_handle_t, 64 int, int (*func)(void *), void *)); 65 void dec_kn20aa_intr_disestablish __P((void *, void *)); 66 67 #define KN20AA_PCEB_IRQ 31 68 #define KN20AA_MAX_IRQ 32 69 #define PCI_STRAY_MAX 5 70 71 struct kn20aa_intrhand { 72 TAILQ_ENTRY(kn20aa_intrhand) ih_q; 73 int (*ih_fun) __P((void *)); 74 void *ih_arg; 75 u_long ih_count; 76 int ih_level; 77 }; 78 TAILQ_HEAD(kn20aa_intrchain, kn20aa_intrhand); 79 80 struct kn20aa_intrchain kn20aa_pci_intrs[KN20AA_MAX_IRQ]; 81 int kn20aa_pci_strayintrcnt[KN20AA_MAX_IRQ]; 82 #ifdef EVCNT_COUNTERS 83 struct evcnt kn20aa_intr_evcnt; 84 #endif 85 86 void kn20aa_pci_strayintr __P((int irq)); 87 void kn20aa_iointr __P((void *framep, unsigned long vec)); 88 void kn20aa_enable_intr __P((int irq)); 89 void kn20aa_disable_intr __P((int irq)); 90 struct kn20aa_intrhand *kn20aa_attach_intr __P((struct kn20aa_intrchain *, 91 int, int (*) (void *), void *)); 92 93 void 94 pci_kn20aa_pickintr(ccp) 95 struct cia_config *ccp; 96 { 97 int i; 98 bus_space_tag_t iot = ccp->cc_iot; 99 pci_chipset_tag_t pc = &ccp->cc_pc; 100 101 for (i = 0; i < KN20AA_MAX_IRQ; i++) 102 TAILQ_INIT(&kn20aa_pci_intrs[i]); 103 104 pc->pc_intr_v = ccp; 105 pc->pc_intr_map = dec_kn20aa_intr_map; 106 pc->pc_intr_string = dec_kn20aa_intr_string; 107 pc->pc_intr_establish = dec_kn20aa_intr_establish; 108 pc->pc_intr_disestablish = dec_kn20aa_intr_disestablish; 109 110 #if NSIO 111 sio_intr_setup(iot); 112 #endif 113 114 set_iointr(kn20aa_iointr); 115 116 #if NSIO 117 kn20aa_enable_intr(KN20AA_PCEB_IRQ); 118 #if 0 /* XXX init PCEB interrupt handler? */ 119 kn20aa_attach_intr(&kn20aa_pci_intrs[KN20AA_PCEB_IRQ], ???, ???, ???); 120 #endif 121 #endif 122 } 123 124 int 125 dec_kn20aa_intr_map(ccv, bustag, buspin, line, ihp) 126 void *ccv; 127 pcitag_t bustag; 128 int buspin, line; 129 pci_intr_handle_t *ihp; 130 { 131 struct cia_config *ccp = ccv; 132 pci_chipset_tag_t pc = &ccp->cc_pc; 133 int device; 134 int kn20aa_irq; 135 136 if (buspin == 0) { 137 /* No IRQ used. */ 138 return 1; 139 } 140 if (buspin > 4) { 141 printf("pci_map_int: bad interrupt pin %d\n", buspin); 142 return 1; 143 } 144 145 /* 146 * Slot->interrupt translation. Appears to work, though it 147 * may not hold up forever. 148 * 149 * The DEC engineers who did this hardware obviously engaged 150 * in random drug testing. 151 */ 152 pci_decompose_tag(pc, bustag, NULL, &device, NULL); 153 switch (device) { 154 case 11: 155 case 12: 156 kn20aa_irq = ((device - 11) + 0) * 4; 157 break; 158 159 case 7: 160 kn20aa_irq = 8; 161 break; 162 163 case 9: 164 kn20aa_irq = 12; 165 break; 166 167 case 6: /* 21040 on AlphaStation 500 */ 168 kn20aa_irq = 13; 169 break; 170 171 case 8: 172 kn20aa_irq = 16; 173 break; 174 175 default: 176 printf("dec_kn20aa_intr_map: weird device number %d\n", 177 device); 178 return 1; 179 } 180 181 kn20aa_irq += buspin - 1; 182 if (kn20aa_irq > KN20AA_MAX_IRQ) 183 panic("pci_kn20aa_map_int: kn20aa_irq too large (%d)\n", 184 kn20aa_irq); 185 186 *ihp = kn20aa_irq; 187 return (0); 188 } 189 190 const char * 191 dec_kn20aa_intr_string(ccv, ih) 192 void *ccv; 193 pci_intr_handle_t ih; 194 { 195 #if 0 196 struct cia_config *ccp = ccv; 197 #endif 198 static char irqstr[15]; /* 11 + 2 + NULL + sanity */ 199 200 if (ih > KN20AA_MAX_IRQ) 201 panic("dec_kn20aa_a50_intr_string: bogus kn20aa IRQ 0x%x\n", 202 ih); 203 204 sprintf(irqstr, "kn20aa irq %ld", ih); 205 return (irqstr); 206 } 207 208 void * 209 dec_kn20aa_intr_establish(ccv, ih, level, func, arg) 210 void *ccv, *arg; 211 pci_intr_handle_t ih; 212 int level; 213 int (*func) __P((void *)); 214 { 215 #if 0 216 struct cia_config *ccp = ccv; 217 #endif 218 void *cookie; 219 220 if (ih > KN20AA_MAX_IRQ) 221 panic("dec_kn20aa_intr_establish: bogus kn20aa IRQ 0x%x\n", 222 ih); 223 224 cookie = kn20aa_attach_intr(&kn20aa_pci_intrs[ih], level, func, arg); 225 kn20aa_enable_intr(ih); 226 return (cookie); 227 } 228 229 void 230 dec_kn20aa_intr_disestablish(ccv, cookie) 231 void *ccv, *cookie; 232 { 233 #if 0 234 struct cia_config *ccp = ccv; 235 #endif 236 237 panic("dec_kn20aa_intr_disestablish not implemented"); /* XXX */ 238 } 239 240 /* 241 * caught a stray interrupt; notify if not too many seen already. 242 */ 243 void 244 kn20aa_pci_strayintr(irq) 245 int irq; 246 { 247 248 kn20aa_pci_strayintrcnt[irq]++; 249 if (kn20aa_pci_strayintrcnt[irq] == PCI_STRAY_MAX) 250 kn20aa_disable_intr(irq); 251 252 log(LOG_ERR, "stray kn20aa irq %d\n", irq); 253 if (kn20aa_pci_strayintrcnt[irq] == PCI_STRAY_MAX) 254 log(LOG_ERR, "disabling interrupts on kn20aa irq %d\n", irq); 255 } 256 257 void 258 kn20aa_iointr(framep, vec) 259 void *framep; 260 unsigned long vec; 261 { 262 struct kn20aa_intrhand *ih; 263 int irq, handled; 264 265 if (vec >= 0x900) { 266 if (vec >= 0x900 + (KN20AA_MAX_IRQ << 4)) 267 panic("kn20aa_iointr: vec 0x%x out of range\n", vec); 268 irq = (vec - 0x900) >> 4; 269 270 #ifdef EVCNT_COUNTERS 271 kn20aa_intr_evcnt.ev_count++; 272 #else 273 if (KN20AA_MAX_IRQ != INTRCNT_KN20AA_IRQ_LEN) 274 panic("kn20aa interrupt counter sizes inconsistent"); 275 intrcnt[INTRCNT_KN20AA_IRQ + irq]++; 276 #endif 277 278 for (ih = kn20aa_pci_intrs[irq].tqh_first, handled = 0; 279 ih != NULL; ih = ih->ih_q.tqe_next) { 280 int rv; 281 282 rv = (*ih->ih_fun)(ih->ih_arg); 283 284 ih->ih_count++; 285 handled = handled || (rv != 0); 286 } 287 if (!handled) 288 kn20aa_pci_strayintr(irq); 289 return; 290 } 291 if (vec >= 0x800) { 292 #if NSIO 293 sio_iointr(framep, vec); 294 #endif 295 return; 296 } 297 panic("kn20aa_iointr: weird vec 0x%x\n", vec); 298 } 299 300 void 301 kn20aa_enable_intr(irq) 302 int irq; 303 { 304 305 /* 306 * From disassembling small bits of the OSF/1 kernel: 307 * the following appears to enable a given interrupt request. 308 * "blech." I'd give valuable body parts for better docs or 309 * for a good decompiler. 310 */ 311 alpha_mb(); 312 REGVAL(0x8780000000L + 0x40L) |= (1 << irq); /* XXX */ 313 alpha_mb(); 314 } 315 316 void 317 kn20aa_disable_intr(irq) 318 int irq; 319 { 320 321 alpha_mb(); 322 REGVAL(0x8780000000L + 0x40L) &= ~(1 << irq); /* XXX */ 323 alpha_mb(); 324 } 325 326 struct kn20aa_intrhand * 327 kn20aa_attach_intr(chain, level, func, arg) 328 struct kn20aa_intrchain *chain; 329 int level; 330 int (*func) __P((void *)); 331 void *arg; 332 { 333 struct kn20aa_intrhand *nintrhand; 334 335 nintrhand = (struct kn20aa_intrhand *) 336 malloc(sizeof *nintrhand, M_DEVBUF, M_WAITOK); 337 338 nintrhand->ih_fun = func; 339 nintrhand->ih_arg = arg; 340 nintrhand->ih_count = 0; 341 nintrhand->ih_level = level; 342 TAILQ_INSERT_TAIL(chain, nintrhand, ih_q); 343 344 return (nintrhand); 345 } 346