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