pci_550.c revision 1.2 1 /* $NetBSD: pci_550.c,v 1.2 1998/06/05 03:34:27 ross Exp $ */
2
3 /*-
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Andrew Gallatin and Jason R. Thorpe.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*
40 * Copyright (c) 1995, 1996 Carnegie-Mellon University.
41 * All rights reserved.
42 *
43 * Author: Chris G. Demetriou
44 *
45 * Permission to use, copy, modify and distribute this software and
46 * its documentation is hereby granted, provided that both the copyright
47 * notice and this permission notice appear in all copies of the
48 * software, derivative works or modified versions, and any portions
49 * thereof, and that both notices appear in supporting documentation.
50 *
51 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
52 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
53 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
54 *
55 * Carnegie Mellon requests users of this software to return to
56 *
57 * Software Distribution Coordinator or Software.Distribution (at) CS.CMU.EDU
58 * School of Computer Science
59 * Carnegie Mellon University
60 * Pittsburgh PA 15213-3890
61 *
62 * any improvements or extensions that they make and grant Carnegie the
63 * rights to redistribute these changes.
64 */
65
66 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
67
68 __KERNEL_RCSID(0, "$NetBSD: pci_550.c,v 1.2 1998/06/05 03:34:27 ross Exp $");
69
70 #include <sys/types.h>
71 #include <sys/param.h>
72 #include <sys/time.h>
73 #include <sys/systm.h>
74 #include <sys/errno.h>
75 #include <sys/malloc.h>
76 #include <sys/device.h>
77 #include <sys/syslog.h>
78
79 #include <vm/vm.h>
80
81 #include <machine/autoconf.h>
82
83 #include <dev/pci/pcireg.h>
84 #include <dev/pci/pcivar.h>
85 #include <dev/pci/pciidereg.h>
86 #include <dev/pci/pciidevar.h>
87
88 #include <alpha/pci/ciareg.h>
89 #include <alpha/pci/ciavar.h>
90
91 #include <alpha/pci/pci_550.h>
92
93 #ifndef EVCNT_COUNTERS
94 #include <machine/intrcnt.h>
95 #endif
96
97 #include "sio.h"
98 #if NSIO
99 #include <alpha/pci/siovar.h>
100 #endif
101
102 int dec_550_intr_map __P((void *, pcitag_t, int, int,
103 pci_intr_handle_t *));
104 const char *dec_550_intr_string __P((void *, pci_intr_handle_t));
105 void *dec_550_intr_establish __P((void *, pci_intr_handle_t,
106 int, int (*func)(void *), void *));
107 void dec_550_intr_disestablish __P((void *, void *));
108
109 void *dec_550_pciide_compat_intr_establish __P((void *, struct device *,
110 struct pci_attach_args *, int, int (*)(void *), void *));
111
112 #define DEC_550_PCI_IRQ_BEGIN 8
113 #define DEC_550_MAX_IRQ 48
114 #define PCI_STRAY_MAX 5
115
116 struct alpha_shared_intr *dec_550_pci_intr;
117 #ifdef EVCNT_COUNTERS
118 struct evcnt dec_550_intr_evcnt;
119 #endif
120
121 void dec_550_iointr __P((void *framep, unsigned long vec));
122 void dec_550_intr_enable __P((int irq));
123 void dec_550_intr_disable __P((int irq));
124
125 u_int64_t *dec_550_int_mask_reg;
126
127 void
128 pci_550_pickintr(ccp)
129 struct cia_config *ccp;
130 {
131 bus_space_tag_t iot = &ccp->cc_iot;
132 pci_chipset_tag_t pc = &ccp->cc_pc;
133 int i;
134
135 pc->pc_intr_v = ccp;
136 pc->pc_intr_map = dec_550_intr_map;
137 pc->pc_intr_string = dec_550_intr_string;
138 pc->pc_intr_establish = dec_550_intr_establish;
139 pc->pc_intr_disestablish = dec_550_intr_disestablish;
140
141 pc->pc_pciide_compat_intr_establish =
142 dec_550_pciide_compat_intr_establish;
143
144 /*
145 * DEC 550's interrupts are enabled via the Pyxis interrupt
146 * mask register.
147 */
148 dec_550_int_mask_reg =
149 (u_int64_t *)ALPHA_PHYS_TO_K0SEG(PYXIS_INT_MASK);
150
151 for (i = DEC_550_PCI_IRQ_BEGIN; i < DEC_550_MAX_IRQ; i++)
152 dec_550_intr_disable(i);
153
154 dec_550_pci_intr = alpha_shared_intr_alloc(DEC_550_MAX_IRQ);
155 for (i = 0; i < DEC_550_MAX_IRQ; i++)
156 alpha_shared_intr_set_maxstrays(dec_550_pci_intr, i,
157 PCI_STRAY_MAX);
158
159 #if NSIO
160 sio_intr_setup(pc, iot);
161 #endif
162
163 set_iointr(dec_550_iointr);
164 }
165
166 int
167 dec_550_intr_map(ccv, bustag, buspin, line, ihp)
168 void *ccv;
169 pcitag_t bustag;
170 int buspin, line;
171 pci_intr_handle_t *ihp;
172 {
173 struct cia_config *ccp = ccv;
174 pci_chipset_tag_t pc = &ccp->cc_pc;
175 int bus, device, function;
176
177 if (buspin == 0) {
178 /* No IRQ used. */
179 return 1;
180 }
181 if (buspin > 4) {
182 printf("dec_550_intr_map: bad interrupt pin %d\n", buspin);
183 return 1;
184 }
185
186 alpha_pci_decompose_tag(pc, bustag, &bus, &device, &function);
187
188 /*
189 * The PCI-ISA bridge lives on device 7 of bus 0. On the MiataGL
190 * this is a Cypress chip with PCI IDE wired to compatibility
191 * mode on functions 1 and 2. There will be no interrupt mapping
192 * for this device, so just bail out now.
193 */
194 if (bus == 0 && device == 7) {
195 if (function == 0)
196 panic("dec_550_intr_map: SIO device");
197 }
198
199 /*
200 * The console places the interrupt mapping in the "line" value.
201 * A value of (char)-1 indicates there is no mapping.
202 */
203 if (line == 0xff) {
204 printf("dec_550_intr_map: no mapping for %d/%d/%d\n",
205 bus, device, function);
206 return (1);
207 }
208
209 /* Account for the PCI interrupt offset. */
210 line += DEC_550_PCI_IRQ_BEGIN;
211
212 if (line >= DEC_550_MAX_IRQ)
213 panic("dec_550_intr_map: dec 550 irq too large (%d)\n",
214 line);
215
216 *ihp = line;
217 return (0);
218 }
219
220 const char *
221 dec_550_intr_string(ccv, ih)
222 void *ccv;
223 pci_intr_handle_t ih;
224 {
225 #if 0
226 struct cia_config *ccp = ccv;
227 #endif
228 static char irqstr[16]; /* 12 + 2 + NULL + sanity */
229
230 if (ih >= DEC_550_MAX_IRQ)
231 panic("dec_550_intr_string: bogus 550 IRQ 0x%x\n", ih);
232 sprintf(irqstr, "dec 550 irq %d", ih);
233 return (irqstr);
234 }
235
236 void *
237 dec_550_intr_establish(ccv, ih, level, func, arg)
238 void *ccv, *arg;
239 pci_intr_handle_t ih;
240 int level;
241 int (*func) __P((void *));
242 {
243 #if 0
244 struct cia_config *ccp = ccv;
245 #endif
246 void *cookie;
247
248 if (ih >= DEC_550_MAX_IRQ)
249 panic("dec_550_intr_establish: bogus dec 550 IRQ 0x%x\n", ih);
250
251 cookie = alpha_shared_intr_establish(dec_550_pci_intr, ih, IST_LEVEL,
252 level, func, arg, "dec 550 irq");
253
254 if (cookie != NULL && alpha_shared_intr_isactive(dec_550_pci_intr, ih))
255 dec_550_intr_enable(ih);
256 return (cookie);
257 }
258
259 void
260 dec_550_intr_disestablish(ccv, cookie)
261 void *ccv, *cookie;
262 {
263 #if 0
264 struct cia_config *ccp = ccv;
265 #endif
266
267 panic("dec_550_intr_disestablish not implemented"); /* XXX */
268 }
269
270 void *
271 dec_550_pciide_compat_intr_establish(v, dev, pa, chan, func, arg)
272 void *v;
273 struct device *dev;
274 struct pci_attach_args *pa;
275 int chan;
276 int (*func) __P((void *));
277 void *arg;
278 {
279 pci_chipset_tag_t pc = pa->pa_pc;
280 void *cookie = NULL;
281 int bus, irq;
282
283 alpha_pci_decompose_tag(pc, pa->pa_tag, &bus, NULL, NULL);
284
285 /*
286 * If this isn't PCI bus #0, all bets are off.
287 */
288 if (bus != 0)
289 return (NULL);
290
291 irq = PCIIDE_COMPAT_IRQ(chan);
292 #if NSIO
293 cookie = sio_intr_establish(NULL /*XXX*/, irq, IST_EDGE, IPL_BIO,
294 func, arg);
295 #endif
296 return (cookie);
297 }
298
299 void
300 dec_550_iointr(framep, vec)
301 void *framep;
302 unsigned long vec;
303 {
304 int irq;
305
306 if (vec >= 0x900) {
307 irq = ((vec - 0x900) >> 4) + DEC_550_PCI_IRQ_BEGIN;
308
309 if (irq >= DEC_550_MAX_IRQ)
310 panic("550_iointr: vec 0x%x out of range\n", vec);
311
312 #ifdef EVCNT_COUNTERS
313 dec_550_intr_evcnt.ev_count++;
314 #else
315 if (DEC_550_MAX_IRQ != INTRCNT_DEC_550_IRQ_LEN)
316 panic("dec_550 interrupt counter sizes inconsistent");
317 intrcnt[INTRCNT_DEC_550_IRQ + irq]++;
318 #endif
319
320 if (!alpha_shared_intr_dispatch(dec_550_pci_intr, irq)) {
321 alpha_shared_intr_stray(dec_550_pci_intr, irq,
322 "dec 550 irq");
323 if (dec_550_pci_intr[irq].intr_nstrays ==
324 dec_550_pci_intr[irq].intr_maxstrays)
325 dec_550_intr_disable(irq);
326 }
327 return;
328 }
329 #if NSIO
330 if (vec >= 0x800) {
331 sio_iointr(framep, vec);
332 return;
333 }
334 #endif
335 panic("dec_550_iointr: weird vec 0x%x\n", vec);
336 }
337
338 void
339 dec_550_intr_enable(irq)
340 int irq;
341 {
342 u_int64_t imask;
343 int s;
344
345 #if 1
346 printf("dec_550_intr_enable: enabling %d\n", irq);
347 #endif
348
349 s = splhigh();
350 alpha_mb();
351 imask = *dec_550_int_mask_reg;
352 imask |= (1UL << irq);
353 *dec_550_int_mask_reg = imask;
354 alpha_mb();
355 splx(s);
356 }
357
358 void
359 dec_550_intr_disable(irq)
360 int irq;
361 {
362 u_int64_t imask;
363 int s;
364
365 #if 1
366 printf("dec_550_intr_disable: disabling %d\n", irq);
367 #endif
368
369 s = splhigh();
370 alpha_mb();
371 imask = *dec_550_int_mask_reg;
372 imask &= ~(1UL << irq);
373 *dec_550_int_mask_reg = imask;
374 alpha_mb();
375 splx(s);
376 }
377