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
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
pci_kn20aa_pickintr(ccp)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
dec_kn20aa_intr_map(pa,ihp)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 (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
176 const char *
dec_kn20aa_intr_string(ccv,ih)177 dec_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
190 int
dec_kn20aa_intr_line(ccv,ih)191 dec_kn20aa_intr_line(ccv, ih)
192 void *ccv;
193 pci_intr_handle_t ih;
194 {
195 return (ih);
196 }
197
198 void *
dec_kn20aa_intr_establish(ccv,ih,level,func,arg,name)199 dec_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
223 void
dec_kn20aa_intr_disestablish(ccv,cookie)224 dec_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
243 void
kn20aa_iointr(arg,vec)244 kn20aa_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
261 void
kn20aa_enable_intr(irq)262 kn20aa_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
277 void
kn20aa_disable_intr(irq)278 kn20aa_disable_intr(irq)
279 int irq;
280 {
281
282 alpha_mb();
283 REGVAL(0x8780000000L + 0x40L) &= ~(1 << irq); /* XXX */
284 alpha_mb();
285 }
286