1 /* $NetBSD: pci_kn20aa.c,v 1.1 1995/11/23 02:38:00 cgd Exp $ */ 2 3 /* 4 * Copyright (c) 1995 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 <dev/pci/pcireg.h> 42 #include <dev/pci/pcivar.h> 43 44 #include <alpha/pci/ciareg.h> 45 #include <alpha/pci/ciavar.h> 46 47 #include <alpha/pci/pci_kn20aa.h> 48 49 #ifndef EVCNT_COUNTERS 50 #include <machine/intrcnt.h> 51 #endif 52 53 #include "sio.h" 54 #if NSIO 55 #include <alpha/pci/siovar.h> 56 #endif 57 58 void *kn20aa_pci_map_int __P((void *, pci_conftag_t, pci_intr_pin_t, 59 pci_intr_line_t, pci_intrlevel_t, int (*func)(void *), void *)); 60 void kn20aa_pci_unmap_int __P((void *, void *)); 61 62 __const struct pci_intr_fns kn20aa_pci_intr_fns = { 63 kn20aa_pci_map_int, 64 kn20aa_pci_unmap_int, 65 }; 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)(); 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, int vec)); 88 void kn20aa_enable_intr __P((int irq)); 89 struct kn20aa_intrhand *kn20aa_attach_intr __P((struct kn20aa_intrchain *, 90 pci_intrlevel_t, int (*) (void *), void *)); 91 92 void 93 pci_kn20aa_pickintr(pcf, pcfa, ppf, ppfa, pifp, pifap) 94 __const struct pci_conf_fns *pcf; 95 __const struct pci_pio_fns *ppf; 96 void *pcfa, *ppfa; 97 __const struct pci_intr_fns **pifp; 98 void **pifap; 99 { 100 int i; 101 struct kn20aa_intrhand *nintrhand; 102 103 104 for (i = 0; i < KN20AA_MAX_IRQ; i++) 105 TAILQ_INIT(&kn20aa_pci_intrs[i]); 106 107 *pifp = &kn20aa_pci_intr_fns; 108 *pifap = NULL; /* XXX ? */ 109 110 #if NSIO 111 sio_intr_setup(ppf, ppfa); 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 void * 125 kn20aa_pci_map_int(ccv, tag, pin, line, level, func, arg) 126 void *ccv; 127 pci_conftag_t tag; 128 pci_intr_pin_t pin; 129 pci_intr_line_t line; 130 pci_intrlevel_t level; 131 int (*func) __P((void *)); 132 void *arg; 133 { 134 int device; 135 int kn20aa_slot, kn20aa_irq; 136 void *ih; 137 138 if (pin == 0) { 139 /* No IRQ used. */ 140 return 0; 141 } 142 if (pin > 4) { 143 printf("pci_map_int: bad interrupt pin %d\n", pin); 144 return NULL; 145 } 146 147 /* 148 * Slot->interrupt translation. Appears to work, though it 149 * may not hold up forever. 150 * 151 * The DEC engineers who did this hardware obviously engaged 152 * in random drug testing. 153 */ 154 switch (device = PCI_TAG_DEVICE(tag)) { 155 case 11: 156 case 12: 157 kn20aa_slot = (device - 11) + 0; 158 break; 159 160 case 7: 161 kn20aa_slot = 2; 162 break; 163 164 case 8: 165 kn20aa_slot = 4; 166 break; 167 168 case 9: 169 kn20aa_slot = 3; 170 break; 171 172 default: 173 panic("pci_kn20aa_map_int: invalid device number %d\n", 174 device); 175 } 176 177 kn20aa_irq = (kn20aa_slot * 4) + pin - 1; 178 if (kn20aa_irq > KN20AA_MAX_IRQ) 179 panic("pci_kn20aa_map_int: kn20aa_irq too large (%d)\n", 180 kn20aa_irq); 181 182 #if 0 183 printf("kn20aa_attach_intr: func 0x%lx, arg 0x%lx, level %d, irq %d\n", 184 func, arg, level, kn20aa_irq); 185 #endif 186 187 ih = kn20aa_attach_intr(&kn20aa_pci_intrs[kn20aa_irq], level, 188 func, arg); 189 kn20aa_enable_intr(kn20aa_irq); 190 return (ih); 191 } 192 193 void 194 kn20aa_pci_unmap_int(pifa, cookie) 195 void *pifa; 196 void *cookie; 197 { 198 199 panic("kn20aa_pci_unmap_int not implemented"); /* XXX */ 200 } 201 202 /* 203 * caught a stray interrupt; notify if not too many seen already. 204 */ 205 void 206 kn20aa_pci_strayintr(irq) 207 int irq; 208 { 209 210 if (++kn20aa_pci_strayintrcnt[irq] <= PCI_STRAY_MAX) 211 log(LOG_ERR, "stray PCI interrupt %d%s\n", irq, 212 kn20aa_pci_strayintrcnt[irq] >= PCI_STRAY_MAX ? 213 "; stopped logging" : ""); 214 } 215 216 void 217 kn20aa_iointr(framep, vec) 218 void *framep; 219 int vec; 220 { 221 struct kn20aa_intrhand *ih; 222 int irq, handled; 223 224 if (vec >= 0x900) { 225 if (vec >= 0x900 + (KN20AA_MAX_IRQ << 4)) 226 panic("kn20aa_iointr: vec 0x%x out of range\n", vec); 227 irq = (vec - 0x900) >> 4; 228 229 #ifdef EVCNT_COUNTERS 230 kn20aa_intr_evcnt.ev_count++; 231 #else 232 if (KN20AA_MAX_IRQ != INTRCNT_KN20AA_IRQ_LEN) 233 panic("kn20aa interrupt counter sizes inconsistent"); 234 intrcnt[INTRCNT_KN20AA_IRQ + irq]++; 235 #endif 236 237 for (ih = kn20aa_pci_intrs[irq].tqh_first, handled = 0; 238 ih != NULL; ih = ih->ih_q.tqe_next) { 239 int rv; 240 241 rv = (*ih->ih_fun)(ih->ih_arg); 242 243 ih->ih_count++; 244 handled = handled || (rv != 0); 245 } 246 if (!handled) 247 kn20aa_pci_strayintr(irq); 248 return; 249 } 250 if (vec >= 0x800) { 251 #if NSIO 252 sio_iointr(framep, vec); 253 #endif 254 return; 255 } 256 panic("kn20aa_iointr: weird vec 0x%x\n", vec); 257 } 258 259 void 260 kn20aa_enable_intr(irq) 261 int irq; 262 { 263 264 /* 265 * From disassembling the OSF/1 source code: 266 * the following appears to enable a given interrupt request. 267 * "blech." I'd give valuable body parts for better docs or 268 * for a good decompiler. 269 */ 270 wbflush(); 271 REGVAL(0x8780000000L + 0x40L) |= (1 << irq); /* XXX */ 272 wbflush(); 273 } 274 275 struct kn20aa_intrhand * 276 kn20aa_attach_intr(chain, level, func, arg) 277 struct kn20aa_intrchain *chain; 278 pci_intrlevel_t level; 279 int (*func) __P((void *)); 280 void *arg; 281 { 282 struct kn20aa_intrhand *nintrhand; 283 284 nintrhand = (struct kn20aa_intrhand *) 285 malloc(sizeof *nintrhand, M_DEVBUF, M_WAITOK); 286 287 nintrhand->ih_fun = func; 288 nintrhand->ih_arg = arg; 289 nintrhand->ih_count = 0; 290 nintrhand->ih_level = level; 291 TAILQ_INSERT_TAIL(chain, nintrhand, ih_q); 292 293 return (nintrhand); 294 } 295