pci_kn20aa.c revision 1.29
1/* $OpenBSD: pci_kn20aa.c,v 1.29 2017/09/08 05:36:51 deraadt 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/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 <uvm/uvm_extern.h> 40 41#include <machine/autoconf.h> 42 43#include <dev/pci/pcireg.h> 44#include <dev/pci/pcivar.h> 45#include <dev/pci/ppbreg.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 57int dec_kn20aa_intr_map(struct pci_attach_args *, pci_intr_handle_t *); 58const char *dec_kn20aa_intr_string(void *, pci_intr_handle_t); 59int dec_kn20aa_intr_line(void *, pci_intr_handle_t); 60void *dec_kn20aa_intr_establish(void *, pci_intr_handle_t, 61 int, int (*func)(void *), void *, const char *); 62void 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 68struct alpha_shared_intr *kn20aa_pci_intr; 69struct evcount kn20aa_intr_count; 70 71void kn20aa_iointr(void *arg, unsigned long vec); 72void kn20aa_enable_intr(int irq); 73void kn20aa_disable_intr(int irq); 74 75void 76pci_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 105int 106dec_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 (pa->pa_bridgetag) { 117 buspin = PPB_INTERRUPT_SWIZZLE(pa->pa_rawintrpin, 118 pa->pa_device); 119 if (pa->pa_bridgeih[buspin - 1] != 0) { 120 *ihp = pa->pa_bridgeih[buspin - 1]; 121 return 0; 122 } 123 124 return 1; 125 } 126 127 /* 128 * Slot->interrupt translation. Appears to work, though it 129 * may not hold up forever. 130 * 131 * The DEC engineers who did this hardware obviously engaged 132 * in random drug testing. 133 */ 134 pci_decompose_tag(pc, bustag, NULL, &device, NULL); 135 switch (device) { 136 case 11: 137 case 12: 138 kn20aa_irq = ((device - 11) + 0) * 4; 139 break; 140 141 case 7: 142 kn20aa_irq = 8; 143 break; 144 145 case 9: 146 kn20aa_irq = 12; 147 break; 148 149 case 6: /* 21040 on AlphaStation 500 */ 150 kn20aa_irq = 13; 151 break; 152 153 case 8: 154 kn20aa_irq = 16; 155 break; 156 157 default: 158 printf("dec_kn20aa_intr_map: don't know how to setup %d/%d/%d\n", 159 pa->pa_bus, pa->pa_device, pa->pa_function); 160 return 1; 161 } 162 163 if (kn20aa_irq != 13) 164 kn20aa_irq += buspin - 1; 165 166 if (kn20aa_irq >= KN20AA_MAX_IRQ) { 167 printf("dec_kn20aa_intr_map: kn20aa_irq %d too large for %d/%d/%d\n", 168 kn20aa_irq, pa->pa_bus, pa->pa_device, pa->pa_function); 169 return 1; 170 } 171 172 *ihp = kn20aa_irq; 173 return 0; 174} 175 176const char * 177dec_kn20aa_intr_string(ccv, ih) 178 void *ccv; 179 pci_intr_handle_t ih; 180{ 181 static char irqstr[15]; /* 11 + 2 + NULL + sanity */ 182 183 if (ih > KN20AA_MAX_IRQ) 184 panic("dec_kn20aa_intr_string: bogus kn20aa IRQ 0x%lx", ih); 185 186 snprintf(irqstr, sizeof irqstr, "kn20aa irq %ld", ih); 187 return (irqstr); 188} 189 190int 191dec_kn20aa_intr_line(ccv, ih) 192 void *ccv; 193 pci_intr_handle_t ih; 194{ 195 return (ih); 196} 197 198void * 199dec_kn20aa_intr_establish(ccv, ih, level, func, arg, name) 200 void *ccv, *arg; 201 pci_intr_handle_t ih; 202 int level; 203 int (*func)(void *); 204 const char *name; 205{ 206 void *cookie; 207 208 if (ih > KN20AA_MAX_IRQ) 209 panic("dec_kn20aa_intr_establish: bogus kn20aa IRQ 0x%lx", 210 ih); 211 212 cookie = alpha_shared_intr_establish(kn20aa_pci_intr, ih, IST_LEVEL, 213 level, func, arg, name); 214 215 if (cookie != NULL && 216 alpha_shared_intr_firstactive(kn20aa_pci_intr, ih)) { 217 scb_set(0x900 + SCB_IDXTOVEC(ih), kn20aa_iointr, NULL); 218 kn20aa_enable_intr(ih); 219 } 220 return (cookie); 221} 222 223void 224dec_kn20aa_intr_disestablish(ccv, cookie) 225 void *ccv, *cookie; 226{ 227 struct alpha_shared_intrhand *ih = cookie; 228 unsigned int irq = ih->ih_num; 229 int s; 230 231 s = splhigh(); 232 233 alpha_shared_intr_disestablish(kn20aa_pci_intr, cookie); 234 if (alpha_shared_intr_isactive(kn20aa_pci_intr, irq) == 0) { 235 kn20aa_disable_intr(irq); 236 alpha_shared_intr_set_dfltsharetype(kn20aa_pci_intr, irq, 237 IST_NONE); 238 scb_free(0x900 + SCB_IDXTOVEC(irq)); 239 } 240 splx(s); 241} 242 243void 244kn20aa_iointr(arg, vec) 245 void *arg; 246 unsigned long vec; 247{ 248 int irq; 249 250 irq = SCB_VECTOIDX(vec - 0x900); 251 252 if (!alpha_shared_intr_dispatch(kn20aa_pci_intr, irq)) { 253 alpha_shared_intr_stray(kn20aa_pci_intr, irq, 254 "kn20aa irq"); 255 if (ALPHA_SHARED_INTR_DISABLE(kn20aa_pci_intr, irq)) 256 kn20aa_disable_intr(irq); 257 } else 258 alpha_shared_intr_reset_strays(kn20aa_pci_intr, irq); 259} 260 261void 262kn20aa_enable_intr(irq) 263 int irq; 264{ 265 266 /* 267 * From disassembling small bits of the OSF/1 kernel: 268 * the following appears to enable a given interrupt request. 269 * "blech." I'd give valuable body parts for better docs or 270 * for a good decompiler. 271 */ 272 alpha_mb(); 273 REGVAL(0x8780000000L + 0x40L) |= (1 << irq); /* XXX */ 274 alpha_mb(); 275} 276 277void 278kn20aa_disable_intr(irq) 279 int irq; 280{ 281 282 alpha_mb(); 283 REGVAL(0x8780000000L + 0x40L) &= ~(1 << irq); /* XXX */ 284 alpha_mb(); 285} 286