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