1/* $NetBSD: pci_550.c,v 1.35 2011/06/14 15:34:22 matt Exp $ */
2
3/*-
4 * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 * NASA Ames Research Center, and by Andrew Gallatin.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33/*
34 * Copyright (c) 1995, 1996 Carnegie-Mellon University.
35 * All rights reserved.
36 *
37 * Author: Chris G. Demetriou
38 *
39 * Permission to use, copy, modify and distribute this software and
40 * its documentation is hereby granted, provided that both the copyright
41 * notice and this permission notice appear in all copies of the
42 * software, derivative works or modified versions, and any portions
43 * thereof, and that both notices appear in supporting documentation.
44 *
45 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
46 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
47 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
48 *
49 * Carnegie Mellon requests users of this software to return to
50 *
51 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
52 *  School of Computer Science
53 *  Carnegie Mellon University
54 *  Pittsburgh PA 15213-3890
55 *
56 * any improvements or extensions that they make and grant Carnegie the
57 * rights to redistribute these changes.
58 */
59
60#include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
61
62__KERNEL_RCSID(0, "$NetBSD: pci_550.c,v 1.35 2011/06/14 15:34:22 matt Exp $");
63
64#include <sys/types.h>
65#include <sys/param.h>
66#include <sys/time.h>
67#include <sys/systm.h>
68#include <sys/errno.h>
69#include <sys/malloc.h>
70#include <sys/device.h>
71#include <sys/syslog.h>
72
73#include <machine/autoconf.h>
74#include <machine/rpb.h>
75
76#include <dev/pci/pcireg.h>
77#include <dev/pci/pcivar.h>
78#include <dev/pci/pciidereg.h>
79#include <dev/pci/pciidevar.h>
80
81#include <alpha/pci/ciareg.h>
82#include <alpha/pci/ciavar.h>
83
84#include <alpha/pci/pci_550.h>
85
86#include "sio.h"
87#if NSIO
88#include <alpha/pci/siovar.h>
89#endif
90
91int	dec_550_intr_map(const struct pci_attach_args *,
92	    pci_intr_handle_t *);
93const char *dec_550_intr_string(void *, pci_intr_handle_t);
94const struct evcnt *dec_550_intr_evcnt(void *, pci_intr_handle_t);
95void	*dec_550_intr_establish(void *, pci_intr_handle_t,
96	    int, int (*func)(void *), void *);
97void	dec_550_intr_disestablish(void *, void *);
98
99void	*dec_550_pciide_compat_intr_establish(void *, device_t,
100	    const struct pci_attach_args *, int, int (*)(void *), void *);
101
102#define	DEC_550_PCI_IRQ_BEGIN	8
103#define	DEC_550_MAX_IRQ		(64 - DEC_550_PCI_IRQ_BEGIN)
104
105/*
106 * The Miata has a Pyxis, which seems to have problems with stray
107 * interrupts.  Work around this by just ignoring strays.
108 */
109#define	PCI_STRAY_MAX		0
110
111/*
112 * Some Miata models, notably models with a Cypress PCI-ISA bridge, have
113 * a PCI device (the OHCI USB controller) with interrupts tied to ISA IRQ
114 * lines.  This IRQ is encoded as: line = FLAG | isa_irq. Usually FLAG
115 * is 0xe0, however, it can be 0xf0.  We don't allow 0xf0 | irq15.
116 */
117#define	DEC_550_LINE_IS_ISA(line)	((line) >= 0xe0 && (line) <= 0xfe)
118#define	DEC_550_LINE_ISA_IRQ(line)	((line) & 0x0f)
119
120struct alpha_shared_intr *dec_550_pci_intr;
121
122void	dec_550_iointr(void *arg, unsigned long vec);
123void	dec_550_intr_enable(int irq);
124void	dec_550_intr_disable(int irq);
125
126void
127pci_550_pickintr(struct cia_config *ccp)
128{
129	bus_space_tag_t iot = &ccp->cc_iot;
130	pci_chipset_tag_t pc = &ccp->cc_pc;
131	char *cp;
132	int i;
133
134	pc->pc_intr_v = ccp;
135	pc->pc_intr_map = dec_550_intr_map;
136	pc->pc_intr_string = dec_550_intr_string;
137	pc->pc_intr_evcnt = dec_550_intr_evcnt;
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.  Nothing to map.
147	 */
148
149	for (i = 0; i < DEC_550_MAX_IRQ; i++)
150		dec_550_intr_disable(i);
151
152	dec_550_pci_intr = alpha_shared_intr_alloc(DEC_550_MAX_IRQ, 8);
153	for (i = 0; i < DEC_550_MAX_IRQ; i++) {
154		alpha_shared_intr_set_maxstrays(dec_550_pci_intr, i,
155		    PCI_STRAY_MAX);
156		alpha_shared_intr_set_private(dec_550_pci_intr, i, ccp);
157
158		cp = alpha_shared_intr_string(dec_550_pci_intr, i);
159		sprintf(cp, "irq %d", i);
160		evcnt_attach_dynamic(alpha_shared_intr_evcnt(
161		    dec_550_pci_intr, i), EVCNT_TYPE_INTR, NULL,
162		    "dec_550", cp);
163	}
164
165#if NSIO
166	sio_intr_setup(pc, iot);
167#endif
168}
169
170int
171dec_550_intr_map(const struct pci_attach_args *pa, pci_intr_handle_t *ihp)
172{
173	pcitag_t bustag = pa->pa_intrtag;
174	int buspin = pa->pa_intrpin, line = pa->pa_intrline;
175	pci_chipset_tag_t pc = pa->pa_pc;
176	int bus, device, function;
177
178	if (buspin == 0) {
179		/* No IRQ used. */
180		return 1;
181	}
182	if (buspin > 4) {
183		printf("dec_550_intr_map: bad interrupt pin %d\n", buspin);
184		return 1;
185	}
186
187	pci_decompose_tag(pc, bustag, &bus, &device, &function);
188
189	/*
190	 * There are two main variants of Miata: Miata 1 (Intel SIO)
191	 * and Miata {1.5,2} (Cypress).
192	 *
193	 * The Miata 1 has a CMD PCI IDE wired to compatibility mode at
194	 * device 4 of bus 0.  This variant apparently also has the
195	 * Pyxis DMA bug.
196	 *
197	 * On the Miata 1.5 and Miata 2, the Cypress PCI-ISA bridge lives
198	 * on device 7 of bus 0.  This device has PCI IDE wired to
199	 * compatibility mode on functions 1 and 2.
200	 *
201	 * There will be no interrupt mapping for these devices, so just
202	 * bail out now.
203	 */
204	if (bus == 0) {
205		if ((hwrpb->rpb_variation & SV_ST_MASK) < SV_ST_MIATA_1_5) {
206			/* Miata 1 */
207			if (device == 7)
208				panic("dec_550_intr_map: SIO device");
209			else if (device == 4)
210				return (1);
211		} else {
212			/* Miata 1.5 or Miata 2 */
213			if (device == 7) {
214				if (function == 0)
215					panic("dec_550_intr_map: SIO device");
216				if (function == 1 || function == 2)
217					return (1);
218			}
219		}
220	}
221
222	/*
223	 * The console places the interrupt mapping in the "line" value.
224	 * A value of (char)-1 indicates there is no mapping.
225	 */
226	if (line == 0xff) {
227		printf("dec_550_intr_map: no mapping for %d/%d/%d\n",
228		    bus, device, function);
229		return (1);
230	}
231
232#if NSIO == 0
233	if (DEC_550_LINE_IS_ISA(line)) {
234		printf("dec_550_intr_map: ISA IRQ %d for %d/%d/%d\n",
235		    DEC_550_LINE_ISA_IRQ(line), bus, device, function);
236		return (1);
237	}
238#endif
239
240	if (DEC_550_LINE_IS_ISA(line) == 0 && line >= DEC_550_MAX_IRQ) {
241		printf("dec_550_intr_map: irq %d out of range %d/%d/%d\n",
242		    line, bus, device, function);
243		return (1);
244	}
245	*ihp = line;
246	return (0);
247}
248
249const char *
250dec_550_intr_string(void *ccv, pci_intr_handle_t ih)
251{
252#if 0
253	struct cia_config *ccp = ccv;
254#endif
255	static char irqstr[16];		/* 12 + 2 + NULL + sanity */
256
257#if NSIO
258	if (DEC_550_LINE_IS_ISA(ih))
259		return (sio_intr_string(NULL /*XXX*/,
260		    DEC_550_LINE_ISA_IRQ(ih)));
261#endif
262
263	if (ih >= DEC_550_MAX_IRQ)
264		panic("dec_550_intr_string: bogus 550 IRQ 0x%lx", ih);
265	sprintf(irqstr, "dec 550 irq %ld", ih);
266	return (irqstr);
267}
268
269const struct evcnt *
270dec_550_intr_evcnt(void *ccv, pci_intr_handle_t ih)
271{
272#if 0
273	struct cia_config *ccp = ccv;
274#endif
275
276#if NSIO
277	if (DEC_550_LINE_IS_ISA(ih))
278		return (sio_intr_evcnt(NULL /*XXX*/,
279		    DEC_550_LINE_ISA_IRQ(ih)));
280#endif
281
282	if (ih >= DEC_550_MAX_IRQ)
283		panic("dec_550_intr_evcnt: bogus 550 IRQ 0x%lx", ih);
284
285	return (alpha_shared_intr_evcnt(dec_550_pci_intr, ih));
286}
287
288void *
289dec_550_intr_establish(void *ccv, pci_intr_handle_t ih, int level, int (*func)(void *), void *arg)
290{
291#if 0
292	struct cia_config *ccp = ccv;
293#endif
294	void *cookie;
295
296#if NSIO
297	if (DEC_550_LINE_IS_ISA(ih))
298		return (sio_intr_establish(NULL /*XXX*/,
299		    DEC_550_LINE_ISA_IRQ(ih), IST_LEVEL, level, func, arg));
300#endif
301
302	if (ih >= DEC_550_MAX_IRQ)
303		panic("dec_550_intr_establish: bogus dec 550 IRQ 0x%lx", ih);
304
305	cookie = alpha_shared_intr_establish(dec_550_pci_intr, ih, IST_LEVEL,
306	    level, func, arg, "dec 550 irq");
307
308	if (cookie != NULL &&
309	    alpha_shared_intr_firstactive(dec_550_pci_intr, ih)) {
310		scb_set(0x900 + SCB_IDXTOVEC(ih), dec_550_iointr, NULL,
311		    level);
312		dec_550_intr_enable(ih);
313	}
314	return (cookie);
315}
316
317void
318dec_550_intr_disestablish(void *ccv, void *cookie)
319{
320	struct cia_config *ccp = ccv;
321	struct alpha_shared_intrhand *ih = cookie;
322	unsigned int irq = ih->ih_num;
323	int s;
324
325#if NSIO
326	/*
327	 * We have to determine if this is an ISA IRQ or not!  We do this
328	 * by checking to see if the intrhand points back to an intrhead
329	 * that points to our cia_config.  If not, it's an ISA IRQ.  Pretty
330	 * disgusting, eh?
331	 */
332	if (ih->ih_intrhead->intr_private != ccp) {
333		sio_intr_disestablish(NULL /*XXX*/, cookie);
334		return;
335	}
336#endif
337
338	s = splhigh();
339
340	alpha_shared_intr_disestablish(dec_550_pci_intr, cookie,
341	    "dec 550 irq");
342	if (alpha_shared_intr_isactive(dec_550_pci_intr, irq) == 0) {
343		dec_550_intr_disable(irq);
344		alpha_shared_intr_set_dfltsharetype(dec_550_pci_intr, irq,
345		    IST_NONE);
346		scb_free(0x900 + SCB_IDXTOVEC(irq));
347	}
348
349	splx(s);
350}
351
352void *
353dec_550_pciide_compat_intr_establish(void *v, device_t dev,
354    const struct pci_attach_args *pa, int chan, int (*func)(void *), void *arg)
355{
356	pci_chipset_tag_t pc = pa->pa_pc;
357	void *cookie = NULL;
358	int bus, irq;
359
360	pci_decompose_tag(pc, pa->pa_tag, &bus, NULL, NULL);
361
362	/*
363	 * If this isn't PCI bus #0, all bets are off.
364	 */
365	if (bus != 0)
366		return (NULL);
367
368	irq = PCIIDE_COMPAT_IRQ(chan);
369#if NSIO
370	cookie = sio_intr_establish(NULL /*XXX*/, irq, IST_EDGE, IPL_BIO,
371	    func, arg);
372	if (cookie == NULL)
373		return (NULL);
374	aprint_normal_dev(dev, "%s channel interrupting at %s\n",
375	    PCIIDE_CHANNEL_NAME(chan), sio_intr_string(NULL /*XXX*/, irq));
376#endif
377	return (cookie);
378}
379
380void
381dec_550_iointr(void *arg, unsigned long vec)
382{
383	int irq;
384
385	irq = SCB_VECTOIDX(vec - 0x900);
386
387	if (irq >= DEC_550_MAX_IRQ)
388		panic("550_iointr: vec 0x%lx out of range", vec);
389
390	if (!alpha_shared_intr_dispatch(dec_550_pci_intr, irq)) {
391		alpha_shared_intr_stray(dec_550_pci_intr, irq,
392		    "dec 550 irq");
393		if (ALPHA_SHARED_INTR_DISABLE(dec_550_pci_intr, irq))
394			dec_550_intr_disable(irq);
395	} else
396		alpha_shared_intr_reset_strays(dec_550_pci_intr, irq);
397}
398
399void
400dec_550_intr_enable(int irq)
401{
402
403	cia_pyxis_intr_enable(irq + DEC_550_PCI_IRQ_BEGIN, 1);
404}
405
406void
407dec_550_intr_disable(int irq)
408{
409
410	cia_pyxis_intr_enable(irq + DEC_550_PCI_IRQ_BEGIN, 0);
411}
412