pci_kn20aa.c revision 1.3
1/* $NetBSD: pci_kn20aa.c,v 1.2 1995/12/24 02:29:45 mycroft 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 58void *kn20aa_pci_map_int __P((void *, pci_conftag_t, pci_intr_pin_t, 59 pci_intr_line_t, int, int (*func)(void *), void *, char *)); 60void 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 71struct 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}; 78TAILQ_HEAD(kn20aa_intrchain, kn20aa_intrhand); 79 80struct kn20aa_intrchain kn20aa_pci_intrs[KN20AA_MAX_IRQ]; 81int kn20aa_pci_strayintrcnt[KN20AA_MAX_IRQ]; 82#ifdef EVCNT_COUNTERS 83struct evcnt kn20aa_intr_evcnt; 84#endif 85 86void kn20aa_pci_strayintr __P((int irq)); 87void kn20aa_iointr __P((void *framep, int vec)); 88void kn20aa_enable_intr __P((int irq)); 89struct kn20aa_intrhand *kn20aa_attach_intr __P((struct kn20aa_intrchain *, 90 int, int (*) (void *), void *)); 91 92void 93pci_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 124void * 125kn20aa_pci_map_int(ccv, tag, pin, line, level, func, arg, what) 126 void *ccv; 127 pci_conftag_t tag; 128 pci_intr_pin_t pin; 129 pci_intr_line_t line; 130 int level; 131 int (*func) __P((void *)); 132 void *arg; 133 char *what; 134{ 135 int device; 136 int kn20aa_slot, kn20aa_irq; 137 void *ih; 138 139 if (pin == 0) { 140 /* No IRQ used. */ 141 return 0; 142 } 143 if (pin > 4) { 144 printf("pci_map_int: bad interrupt pin %d\n", pin); 145 return NULL; 146 } 147 148 /* 149 * Slot->interrupt translation. Appears to work, though it 150 * may not hold up forever. 151 * 152 * The DEC engineers who did this hardware obviously engaged 153 * in random drug testing. 154 */ 155 switch (device = PCI_TAG_DEVICE(tag)) { 156 case 11: 157 case 12: 158 kn20aa_slot = (device - 11) + 0; 159 break; 160 161 case 7: 162 kn20aa_slot = 2; 163 break; 164 165 case 8: 166 kn20aa_slot = 4; 167 break; 168 169 case 9: 170 kn20aa_slot = 3; 171 break; 172 173 default: 174 panic("pci_kn20aa_map_int: invalid device number %d\n", 175 device); 176 } 177 178 kn20aa_irq = (kn20aa_slot * 4) + pin - 1; 179 if (kn20aa_irq > KN20AA_MAX_IRQ) 180 panic("pci_kn20aa_map_int: kn20aa_irq too large (%d)\n", 181 kn20aa_irq); 182 183#if 0 184 printf("kn20aa_attach_intr: func 0x%lx, arg 0x%lx, level %d, irq %d\n", 185 func, arg, level, kn20aa_irq); 186#endif 187 188 ih = kn20aa_attach_intr(&kn20aa_pci_intrs[kn20aa_irq], level, 189 func, arg); 190 kn20aa_enable_intr(kn20aa_irq); 191 return (ih); 192} 193 194void 195kn20aa_pci_unmap_int(pifa, cookie) 196 void *pifa; 197 void *cookie; 198{ 199 200 panic("kn20aa_pci_unmap_int not implemented"); /* XXX */ 201} 202 203/* 204 * caught a stray interrupt; notify if not too many seen already. 205 */ 206void 207kn20aa_pci_strayintr(irq) 208 int irq; 209{ 210 211 if (++kn20aa_pci_strayintrcnt[irq] <= PCI_STRAY_MAX) 212 log(LOG_ERR, "stray PCI interrupt %d%s\n", irq, 213 kn20aa_pci_strayintrcnt[irq] >= PCI_STRAY_MAX ? 214 "; stopped logging" : ""); 215} 216 217void 218kn20aa_iointr(framep, vec) 219 void *framep; 220 int vec; 221{ 222 struct kn20aa_intrhand *ih; 223 int irq, handled; 224 225 if (vec >= 0x900) { 226 if (vec >= 0x900 + (KN20AA_MAX_IRQ << 4)) 227 panic("kn20aa_iointr: vec 0x%x out of range\n", vec); 228 irq = (vec - 0x900) >> 4; 229 230#ifdef EVCNT_COUNTERS 231 kn20aa_intr_evcnt.ev_count++; 232#else 233 if (KN20AA_MAX_IRQ != INTRCNT_KN20AA_IRQ_LEN) 234 panic("kn20aa interrupt counter sizes inconsistent"); 235 intrcnt[INTRCNT_KN20AA_IRQ + irq]++; 236#endif 237 238 for (ih = kn20aa_pci_intrs[irq].tqh_first, handled = 0; 239 ih != NULL; ih = ih->ih_q.tqe_next) { 240 int rv; 241 242 rv = (*ih->ih_fun)(ih->ih_arg); 243 244 ih->ih_count++; 245 handled = handled || (rv != 0); 246 } 247 if (!handled) 248 kn20aa_pci_strayintr(irq); 249 return; 250 } 251 if (vec >= 0x800) { 252#if NSIO 253 sio_iointr(framep, vec); 254#endif 255 return; 256 } 257 panic("kn20aa_iointr: weird vec 0x%x\n", vec); 258} 259 260void 261kn20aa_enable_intr(irq) 262 int irq; 263{ 264 265 /* 266 * From disassembling the OSF/1 source code: 267 * the following appears to enable a given interrupt request. 268 * "blech." I'd give valuable body parts for better docs or 269 * for a good decompiler. 270 */ 271 wbflush(); 272 REGVAL(0x8780000000L + 0x40L) |= (1 << irq); /* XXX */ 273 wbflush(); 274} 275 276struct kn20aa_intrhand * 277kn20aa_attach_intr(chain, level, func, arg) 278 struct kn20aa_intrchain *chain; 279 int level; 280 int (*func) __P((void *)); 281 void *arg; 282{ 283 struct kn20aa_intrhand *nintrhand; 284 285 nintrhand = (struct kn20aa_intrhand *) 286 malloc(sizeof *nintrhand, M_DEVBUF, M_WAITOK); 287 288 nintrhand->ih_fun = func; 289 nintrhand->ih_arg = arg; 290 nintrhand->ih_count = 0; 291 nintrhand->ih_level = level; 292 TAILQ_INSERT_TAIL(chain, nintrhand, ih_q); 293 294 return (nintrhand); 295} 296