1/* $OpenBSD: pci_eb64plus.c,v 1.16 2017/09/08 05:36:51 deraadt Exp $ */
2/* $NetBSD: pci_eb64plus.c,v 1.10 2001/07/27 00:25:20 thorpej Exp $ */
3
4/*-
5 * Copyright (c) 1998 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
10 * NASA Ames Research Center.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 *    notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 *    notice, this list of conditions and the following disclaimer in the
19 *    documentation and/or other materials provided with the distribution.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34/*
35 * Copyright (c) 1995, 1996 Carnegie-Mellon University.
36 * All rights reserved.
37 *
38 * Author: Chris G. Demetriou
39 *
40 * Permission to use, copy, modify and distribute this software and
41 * its documentation is hereby granted, provided that both the copyright
42 * notice and this permission notice appear in all copies of the
43 * software, derivative works or modified versions, and any portions
44 * thereof, and that both notices appear in supporting documentation.
45 *
46 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
47 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
48 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
49 *
50 * Carnegie Mellon requests users of this software to return to
51 *
52 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
53 *  School of Computer Science
54 *  Carnegie Mellon University
55 *  Pittsburgh PA 15213-3890
56 *
57 * any improvements or extensions that they make and grant Carnegie the
58 * rights to redistribute these changes.
59 */
60
61#include <sys/param.h>
62#include <sys/time.h>
63#include <sys/systm.h>
64#include <sys/errno.h>
65#include <sys/malloc.h>
66#include <sys/device.h>
67#include <sys/syslog.h>
68
69#include <uvm/uvm_extern.h>
70
71#include <machine/autoconf.h>
72
73#include <dev/pci/pcireg.h>
74#include <dev/pci/pcivar.h>
75#include <dev/pci/ppbreg.h>
76
77#include <alpha/pci/apecsreg.h>
78#include <alpha/pci/apecsvar.h>
79
80#include <alpha/pci/pci_eb64plus.h>
81
82#include "sio.h"
83#if NSIO
84#include <alpha/pci/siovar.h>
85#endif
86
87int	dec_eb64plus_intr_map(struct pci_attach_args *, pci_intr_handle_t *);
88const char *dec_eb64plus_intr_string(void *, pci_intr_handle_t);
89void	*dec_eb64plus_intr_establish(void *, pci_intr_handle_t,
90	    int, int (*func)(void *), void *, const char *);
91void	dec_eb64plus_intr_disestablish(void *, void *);
92
93#define	EB64PLUS_MAX_IRQ	32
94#define	PCI_STRAY_MAX		5
95
96struct alpha_shared_intr *eb64plus_pci_intr;
97
98bus_space_tag_t eb64plus_intrgate_iot;
99bus_space_handle_t eb64plus_intrgate_ioh;
100
101void	eb64plus_iointr(void *arg, unsigned long vec);
102extern void	eb64plus_intr_enable(int irq);  /* pci_eb64plus_intr.S */
103extern void	eb64plus_intr_disable(int irq); /* pci_eb64plus_intr.S */
104
105void
106pci_eb64plus_pickintr(acp)
107	struct apecs_config *acp;
108{
109	bus_space_tag_t iot = &acp->ac_iot;
110	pci_chipset_tag_t pc = &acp->ac_pc;
111	int i;
112
113        pc->pc_intr_v = acp;
114        pc->pc_intr_map = dec_eb64plus_intr_map;
115        pc->pc_intr_string = dec_eb64plus_intr_string;
116        pc->pc_intr_establish = dec_eb64plus_intr_establish;
117        pc->pc_intr_disestablish = dec_eb64plus_intr_disestablish;
118
119	/* Not supported on the EB64+. */
120	pc->pc_pciide_compat_intr_establish = NULL;
121
122	eb64plus_intrgate_iot = iot;
123	if (bus_space_map(eb64plus_intrgate_iot, 0x804, 3, 0,
124	    &eb64plus_intrgate_ioh) != 0)
125		panic("pci_eb64plus_pickintr: couldn't map interrupt PLD");
126	for (i = 0; i < EB64PLUS_MAX_IRQ; i++)
127		eb64plus_intr_disable(i);
128
129	eb64plus_pci_intr = alpha_shared_intr_alloc(EB64PLUS_MAX_IRQ);
130	for (i = 0; i < EB64PLUS_MAX_IRQ; i++) {
131		alpha_shared_intr_set_maxstrays(eb64plus_pci_intr, i,
132			PCI_STRAY_MAX);
133	}
134
135#if NSIO > 0
136	sio_intr_setup(pc, iot);
137#endif
138}
139
140int
141dec_eb64plus_intr_map(pa, ihp)
142	struct pci_attach_args *pa;
143        pci_intr_handle_t *ihp;
144{
145	int buspin, line = pa->pa_intrline;
146
147	/*
148	 * The console places the interrupt mapping in the "line" value.
149	 * We trust it whenever possible.
150	 */
151	if (line >= 0 && line < EB64PLUS_MAX_IRQ) {
152		*ihp = line;
153		return 0;
154	}
155
156	if (pa->pa_bridgetag) {
157		buspin = PPB_INTERRUPT_SWIZZLE(pa->pa_rawintrpin,
158		    pa->pa_device);
159		if (pa->pa_bridgeih[buspin - 1] != 0) {
160			*ihp = pa->pa_bridgeih[buspin - 1];
161			return 0;
162		}
163	}
164
165	return 1;
166}
167
168const char *
169dec_eb64plus_intr_string(acv, ih)
170	void *acv;
171	pci_intr_handle_t ih;
172{
173        static char irqstr[15];          /* 11 + 2 + NULL + sanity */
174
175        if (ih >= EB64PLUS_MAX_IRQ)
176                panic("dec_eb64plus_intr_string: bogus eb64+ IRQ 0x%lx", ih);
177        snprintf(irqstr, sizeof irqstr, "eb64+ irq %ld", ih);
178        return (irqstr);
179}
180
181void *
182dec_eb64plus_intr_establish(acv, ih, level, func, arg, name)
183        void *acv;
184        pci_intr_handle_t ih;
185        int level;
186        int (*func)(void *);
187	void *arg;
188	const char *name;
189{
190	void *cookie;
191
192	if (ih >= EB64PLUS_MAX_IRQ)
193		panic("dec_eb64plus_intr_establish: bogus eb64+ IRQ 0x%lx",
194		    ih);
195
196	cookie = alpha_shared_intr_establish(eb64plus_pci_intr, ih, IST_LEVEL,
197	    level, func, arg, name);
198
199	if (cookie != NULL &&
200	    alpha_shared_intr_firstactive(eb64plus_pci_intr, ih)) {
201		scb_set(0x900 + SCB_IDXTOVEC(ih), eb64plus_iointr, NULL);
202		eb64plus_intr_enable(ih);
203	}
204	return (cookie);
205}
206
207void
208dec_eb64plus_intr_disestablish(acv, cookie)
209        void *acv, *cookie;
210{
211	struct alpha_shared_intrhand *ih = cookie;
212	unsigned int irq = ih->ih_num;
213	int s;
214
215	s = splhigh();
216
217	alpha_shared_intr_disestablish(eb64plus_pci_intr, cookie);
218	if (alpha_shared_intr_isactive(eb64plus_pci_intr, irq) == 0) {
219		eb64plus_intr_disable(irq);
220		alpha_shared_intr_set_dfltsharetype(eb64plus_pci_intr, irq,
221		    IST_NONE);
222		scb_free(0x900 + SCB_IDXTOVEC(irq));
223	}
224
225	splx(s);
226}
227
228void
229eb64plus_iointr(arg, vec)
230	void *arg;
231	unsigned long vec;
232{
233	int irq;
234
235	irq = SCB_VECTOIDX(vec - 0x900);
236
237	if (!alpha_shared_intr_dispatch(eb64plus_pci_intr, irq)) {
238		alpha_shared_intr_stray(eb64plus_pci_intr, irq,
239		    "eb64+ irq");
240		if (ALPHA_SHARED_INTR_DISABLE(eb64plus_pci_intr, irq))
241			eb64plus_intr_disable(irq);
242	} else
243		alpha_shared_intr_reset_strays(eb64plus_pci_intr, irq);
244}
245
246#if 0		/* THIS DOES NOT WORK!  see pci_eb64plus_intr.S. */
247u_int8_t eb64plus_intr_mask[3] = { 0xff, 0xff, 0xff };
248
249void
250eb64plus_intr_enable(irq)
251	int irq;
252{
253	int byte = (irq / 8), bit = (irq % 8);
254
255#if 1
256	printf("eb64plus_intr_enable: enabling %d (%d:%d)\n", irq, byte, bit);
257#endif
258	eb64plus_intr_mask[byte] &= ~(1 << bit);
259
260	bus_space_write_1(eb64plus_intrgate_iot, eb64plus_intrgate_ioh, byte,
261	    eb64plus_intr_mask[byte]);
262}
263
264void
265eb64plus_intr_disable(irq)
266	int irq;
267{
268	int byte = (irq / 8), bit = (irq % 8);
269
270#if 1
271	printf("eb64plus_intr_disable: disabling %d (%d:%d)\n", irq, byte, bit);
272#endif
273	eb64plus_intr_mask[byte] |= (1 << bit);
274
275	bus_space_write_1(eb64plus_intrgate_iot, eb64plus_intrgate_ioh, byte,
276	    eb64plus_intr_mask[byte]);
277}
278#endif
279