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