1 /* $OpenBSD: pci_kn20aa.c,v 1.26 2009/09/30 20:18:06 miod Exp $ */ 2 /* $NetBSD: pci_kn20aa.c,v 1.21 1996/11/17 02:05:27 cgd 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 <uvm/uvm_extern.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 #include "sio.h" 53 #if NSIO 54 #include <alpha/pci/siovar.h> 55 #endif 56 57 int dec_kn20aa_intr_map(struct pci_attach_args *, pci_intr_handle_t *); 58 const char *dec_kn20aa_intr_string(void *, pci_intr_handle_t); 59 int dec_kn20aa_intr_line(void *, pci_intr_handle_t); 60 void *dec_kn20aa_intr_establish(void *, pci_intr_handle_t, 61 int, int (*func)(void *), void *, const char *); 62 void dec_kn20aa_intr_disestablish(void *, void *); 63 64 #define KN20AA_PCEB_IRQ 31 65 #define KN20AA_MAX_IRQ 32 66 #define PCI_STRAY_MAX 5 67 68 struct alpha_shared_intr *kn20aa_pci_intr; 69 struct evcount kn20aa_intr_count; 70 71 void kn20aa_iointr(void *arg, unsigned long vec); 72 void kn20aa_enable_intr(int irq); 73 void kn20aa_disable_intr(int irq); 74 75 void 76 pci_kn20aa_pickintr(ccp) 77 struct cia_config *ccp; 78 { 79 int i; 80 bus_space_tag_t iot = &ccp->cc_iot; 81 pci_chipset_tag_t pc = &ccp->cc_pc; 82 83 pc->pc_intr_v = ccp; 84 pc->pc_intr_map = dec_kn20aa_intr_map; 85 pc->pc_intr_string = dec_kn20aa_intr_string; 86 pc->pc_intr_line = dec_kn20aa_intr_line; 87 pc->pc_intr_establish = dec_kn20aa_intr_establish; 88 pc->pc_intr_disestablish = dec_kn20aa_intr_disestablish; 89 90 /* Not supported on KN20AA. */ 91 pc->pc_pciide_compat_intr_establish = NULL; 92 pc->pc_pciide_compat_intr_disestablish = NULL; 93 94 kn20aa_pci_intr = alpha_shared_intr_alloc(KN20AA_MAX_IRQ); 95 for (i = 0; i < KN20AA_MAX_IRQ; i++) 96 alpha_shared_intr_set_maxstrays(kn20aa_pci_intr, i, 97 PCI_STRAY_MAX); 98 99 #if NSIO 100 sio_intr_setup(pc, iot); 101 kn20aa_enable_intr(KN20AA_PCEB_IRQ); 102 #endif 103 } 104 105 int 106 dec_kn20aa_intr_map(pa, ihp) 107 struct pci_attach_args *pa; 108 pci_intr_handle_t *ihp; 109 { 110 pcitag_t bustag = pa->pa_intrtag; 111 int buspin = pa->pa_intrpin; 112 pci_chipset_tag_t pc = pa->pa_pc; 113 int device; 114 int kn20aa_irq; 115 116 if (buspin == 0) { 117 /* No IRQ used. */ 118 return 1; 119 } 120 if (buspin > 4) { 121 printf("pci_map_int: bad interrupt pin %d\n", buspin); 122 return 1; 123 } 124 125 /* 126 * Slot->interrupt translation. Appears to work, though it 127 * may not hold up forever. 128 * 129 * The DEC engineers who did this hardware obviously engaged 130 * in random drug testing. 131 */ 132 pci_decompose_tag(pc, bustag, NULL, &device, NULL); 133 switch (device) { 134 case 11: 135 case 12: 136 kn20aa_irq = ((device - 11) + 0) * 4; 137 break; 138 139 case 7: 140 kn20aa_irq = 8; 141 break; 142 143 case 9: 144 kn20aa_irq = 12; 145 break; 146 147 case 6: /* 21040 on AlphaStation 500 */ 148 kn20aa_irq = 13; 149 break; 150 151 case 8: 152 kn20aa_irq = 16; 153 break; 154 155 default: 156 printf("dec_kn20aa_intr_map: weird device number %d\n", 157 device); 158 return 1; 159 } 160 161 kn20aa_irq += buspin - 1; 162 if (kn20aa_irq >= KN20AA_MAX_IRQ) 163 panic("pci_kn20aa_map_int: kn20aa_irq too large (%d)", 164 kn20aa_irq); 165 166 *ihp = kn20aa_irq; 167 return (0); 168 } 169 170 const char * 171 dec_kn20aa_intr_string(ccv, ih) 172 void *ccv; 173 pci_intr_handle_t ih; 174 { 175 static char irqstr[15]; /* 11 + 2 + NULL + sanity */ 176 177 if (ih > KN20AA_MAX_IRQ) 178 panic("dec_kn20aa_intr_string: bogus kn20aa IRQ 0x%x", ih); 179 180 snprintf(irqstr, sizeof irqstr, "kn20aa irq %ld", ih); 181 return (irqstr); 182 } 183 184 int 185 dec_kn20aa_intr_line(ccv, ih) 186 void *ccv; 187 pci_intr_handle_t ih; 188 { 189 return (ih); 190 } 191 192 void * 193 dec_kn20aa_intr_establish(ccv, ih, level, func, arg, name) 194 void *ccv, *arg; 195 pci_intr_handle_t ih; 196 int level; 197 int (*func)(void *); 198 const char *name; 199 { 200 void *cookie; 201 202 if (ih > KN20AA_MAX_IRQ) 203 panic("dec_kn20aa_intr_establish: bogus kn20aa IRQ 0x%x", 204 ih); 205 206 cookie = alpha_shared_intr_establish(kn20aa_pci_intr, ih, IST_LEVEL, 207 level, func, arg, name); 208 209 if (cookie != NULL && 210 alpha_shared_intr_firstactive(kn20aa_pci_intr, ih)) { 211 scb_set(0x900 + SCB_IDXTOVEC(ih), kn20aa_iointr, NULL); 212 kn20aa_enable_intr(ih); 213 } 214 return (cookie); 215 } 216 217 void 218 dec_kn20aa_intr_disestablish(ccv, cookie) 219 void *ccv, *cookie; 220 { 221 struct alpha_shared_intrhand *ih = cookie; 222 unsigned int irq = ih->ih_num; 223 int s; 224 225 s = splhigh(); 226 227 alpha_shared_intr_disestablish(kn20aa_pci_intr, cookie); 228 if (alpha_shared_intr_isactive(kn20aa_pci_intr, irq) == 0) { 229 kn20aa_disable_intr(irq); 230 alpha_shared_intr_set_dfltsharetype(kn20aa_pci_intr, irq, 231 IST_NONE); 232 scb_free(0x900 + SCB_IDXTOVEC(irq)); 233 } 234 splx(s); 235 } 236 237 void 238 kn20aa_iointr(arg, vec) 239 void *arg; 240 unsigned long vec; 241 { 242 int irq; 243 244 irq = SCB_VECTOIDX(vec - 0x900); 245 246 if (!alpha_shared_intr_dispatch(kn20aa_pci_intr, irq)) { 247 alpha_shared_intr_stray(kn20aa_pci_intr, irq, 248 "kn20aa irq"); 249 if (ALPHA_SHARED_INTR_DISABLE(kn20aa_pci_intr, irq)) 250 kn20aa_disable_intr(irq); 251 } else 252 alpha_shared_intr_reset_strays(kn20aa_pci_intr, irq); 253 } 254 255 void 256 kn20aa_enable_intr(irq) 257 int irq; 258 { 259 260 /* 261 * From disassembling small bits of the OSF/1 kernel: 262 * the following appears to enable a given interrupt request. 263 * "blech." I'd give valuable body parts for better docs or 264 * for a good decompiler. 265 */ 266 alpha_mb(); 267 REGVAL(0x8780000000L + 0x40L) |= (1 << irq); /* XXX */ 268 alpha_mb(); 269 } 270 271 void 272 kn20aa_disable_intr(irq) 273 int irq; 274 { 275 276 alpha_mb(); 277 REGVAL(0x8780000000L + 0x40L) &= ~(1 << irq); /* XXX */ 278 alpha_mb(); 279 } 280