pci_kn20aa.c revision 1.4
1/* $NetBSD: pci_kn20aa.c,v 1.3.4.2 1996/06/13 18:35: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 <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 58int dec_kn20aa_intr_map __P((void *, pcitag_t, int, int, 59 pci_intr_handle_t *)); 60const char *dec_kn20aa_intr_string __P((void *, pci_intr_handle_t)); 61void *dec_kn20aa_intr_establish __P((void *, pci_intr_handle_t, 62 int, int (*func)(void *), void *)); 63void dec_kn20aa_intr_disestablish __P((void *, void *)); 64 65#define KN20AA_PCEB_IRQ 31 66#define KN20AA_MAX_IRQ 32 67#define PCI_STRAY_MAX 5 68 69struct kn20aa_intrhand { 70 TAILQ_ENTRY(kn20aa_intrhand) ih_q; 71 int (*ih_fun)(); 72 void *ih_arg; 73 u_long ih_count; 74 int ih_level; 75}; 76TAILQ_HEAD(kn20aa_intrchain, kn20aa_intrhand); 77 78struct kn20aa_intrchain kn20aa_pci_intrs[KN20AA_MAX_IRQ]; 79int kn20aa_pci_strayintrcnt[KN20AA_MAX_IRQ]; 80#ifdef EVCNT_COUNTERS 81struct evcnt kn20aa_intr_evcnt; 82#endif 83 84void kn20aa_pci_strayintr __P((int irq)); 85void kn20aa_iointr __P((void *framep, int vec)); 86void kn20aa_enable_intr __P((int irq)); 87struct kn20aa_intrhand *kn20aa_attach_intr __P((struct kn20aa_intrchain *, 88 int, int (*) (void *), void *)); 89 90void 91pci_kn20aa_pickintr(ccp) 92 struct cia_config *ccp; 93{ 94 int i; 95 struct kn20aa_intrhand *nintrhand; 96 bus_chipset_tag_t bc = &ccp->cc_bc; 97 pci_chipset_tag_t pc = &ccp->cc_pc; 98 99 for (i = 0; i < KN20AA_MAX_IRQ; i++) 100 TAILQ_INIT(&kn20aa_pci_intrs[i]); 101 102 pc->pc_intr_v = ccp; 103 pc->pc_intr_map = dec_kn20aa_intr_map; 104 pc->pc_intr_string = dec_kn20aa_intr_string; 105 pc->pc_intr_establish = dec_kn20aa_intr_establish; 106 pc->pc_intr_disestablish = dec_kn20aa_intr_disestablish; 107 108#if NSIO 109 sio_intr_setup(bc); 110#endif 111 112 set_iointr(kn20aa_iointr); 113 114#if NSIO 115 kn20aa_enable_intr(KN20AA_PCEB_IRQ); 116#if 0 /* XXX init PCEB interrupt handler? */ 117 kn20aa_attach_intr(&kn20aa_pci_intrs[KN20AA_PCEB_IRQ], ???, ???, ???); 118#endif 119#endif 120} 121 122int 123dec_kn20aa_intr_map(ccv, bustag, buspin, line, ihp) 124 void *ccv; 125 pcitag_t bustag; 126 int buspin, line; 127 pci_intr_handle_t *ihp; 128{ 129 struct cia_config *ccp = ccv; 130 pci_chipset_tag_t pc = &ccp->cc_pc; 131 int device; 132 int kn20aa_slot, kn20aa_irq; 133 void *ih; 134 135 if (buspin == 0) { 136 /* No IRQ used. */ 137 return 0; 138 } 139 if (buspin > 4) { 140 printf("pci_map_int: bad interrupt pin %d\n", buspin); 141 return NULL; 142 } 143 144 /* 145 * Slot->interrupt translation. Appears to work, though it 146 * may not hold up forever. 147 * 148 * The DEC engineers who did this hardware obviously engaged 149 * in random drug testing. 150 */ 151 pci_decompose_tag(pc, bustag, NULL, &device, NULL); 152 switch (device) { 153 case 11: 154 case 12: 155 kn20aa_slot = (device - 11) + 0; 156 break; 157 158 case 7: 159 kn20aa_slot = 2; 160 break; 161 162 case 8: 163 kn20aa_slot = 4; 164 break; 165 166 case 9: 167 kn20aa_slot = 3; 168 break; 169 170 default: 171 panic("pci_kn20aa_map_int: invalid device number %d\n", 172 device); 173 } 174 175 kn20aa_irq = (kn20aa_slot * 4) + buspin - 1; 176 if (kn20aa_irq > KN20AA_MAX_IRQ) 177 panic("pci_kn20aa_map_int: kn20aa_irq too large (%d)\n", 178 kn20aa_irq); 179 180 *ihp = kn20aa_irq; 181} 182 183const char * 184dec_kn20aa_intr_string(ccv, ih) 185 void *ccv; 186 pci_intr_handle_t ih; 187{ 188 struct cia_config *ccp = ccv; 189 static char irqstr[15]; /* 11 + 2 + NULL + sanity */ 190 191 if (ih > KN20AA_MAX_IRQ) 192 panic("dec_kn20aa_a50_intr_string: bogus kn20aa IRQ 0x%x\n", 193 ih); 194 195 sprintf(irqstr, "kn20aa irq %d", ih); 196 return (irqstr); 197} 198 199void * 200dec_kn20aa_intr_establish(ccv, ih, level, func, arg) 201 void *ccv, *arg; 202 pci_intr_handle_t ih; 203 int level; 204 int (*func) __P((void *)); 205{ 206 struct cia_config *ccp = ccv; 207 void *cookie; 208 209 if (ih > KN20AA_MAX_IRQ) 210 panic("dec_kn20aa_intr_establish: bogus kn20aa IRQ 0x%x\n", 211 ih); 212 213 cookie = kn20aa_attach_intr(&kn20aa_pci_intrs[ih], level, func, arg); 214 kn20aa_enable_intr(ih); 215 return (cookie); 216} 217 218void 219dec_kn20aa_intr_disestablish(ccv, cookie) 220 void *ccv, *cookie; 221{ 222 struct cia_config *ccp = ccv; 223 224 panic("dec_kn20aa_intr_disestablish not implemented"); /* XXX */ 225} 226 227/* 228 * caught a stray interrupt; notify if not too many seen already. 229 */ 230void 231kn20aa_pci_strayintr(irq) 232 int irq; 233{ 234 235 if (++kn20aa_pci_strayintrcnt[irq] <= PCI_STRAY_MAX) 236 log(LOG_ERR, "stray PCI interrupt %d%s\n", irq, 237 kn20aa_pci_strayintrcnt[irq] >= PCI_STRAY_MAX ? 238 "; stopped logging" : ""); 239} 240 241void 242kn20aa_iointr(framep, vec) 243 void *framep; 244 int vec; 245{ 246 struct kn20aa_intrhand *ih; 247 int irq, handled; 248 249 if (vec >= 0x900) { 250 if (vec >= 0x900 + (KN20AA_MAX_IRQ << 4)) 251 panic("kn20aa_iointr: vec 0x%x out of range\n", vec); 252 irq = (vec - 0x900) >> 4; 253 254#ifdef EVCNT_COUNTERS 255 kn20aa_intr_evcnt.ev_count++; 256#else 257 if (KN20AA_MAX_IRQ != INTRCNT_KN20AA_IRQ_LEN) 258 panic("kn20aa interrupt counter sizes inconsistent"); 259 intrcnt[INTRCNT_KN20AA_IRQ + irq]++; 260#endif 261 262 for (ih = kn20aa_pci_intrs[irq].tqh_first, handled = 0; 263 ih != NULL; ih = ih->ih_q.tqe_next) { 264 int rv; 265 266 rv = (*ih->ih_fun)(ih->ih_arg); 267 268 ih->ih_count++; 269 handled = handled || (rv != 0); 270 } 271 if (!handled) 272 kn20aa_pci_strayintr(irq); 273 return; 274 } 275 if (vec >= 0x800) { 276#if NSIO 277 sio_iointr(framep, vec); 278#endif 279 return; 280 } 281 panic("kn20aa_iointr: weird vec 0x%x\n", vec); 282} 283 284void 285kn20aa_enable_intr(irq) 286 int irq; 287{ 288 289 /* 290 * From disassembling the OSF/1 source code: 291 * the following appears to enable a given interrupt request. 292 * "blech." I'd give valuable body parts for better docs or 293 * for a good decompiler. 294 */ 295 wbflush(); 296 REGVAL(0x8780000000L + 0x40L) |= (1 << irq); /* XXX */ 297 wbflush(); 298} 299 300struct kn20aa_intrhand * 301kn20aa_attach_intr(chain, level, func, arg) 302 struct kn20aa_intrchain *chain; 303 int level; 304 int (*func) __P((void *)); 305 void *arg; 306{ 307 struct kn20aa_intrhand *nintrhand; 308 309 nintrhand = (struct kn20aa_intrhand *) 310 malloc(sizeof *nintrhand, M_DEVBUF, M_WAITOK); 311 312 nintrhand->ih_fun = func; 313 nintrhand->ih_arg = arg; 314 nintrhand->ih_count = 0; 315 nintrhand->ih_level = level; 316 TAILQ_INSERT_TAIL(chain, nintrhand, ih_q); 317 318 return (nintrhand); 319} 320