pci_machdep_common.c revision 1.7
1/* $NetBSD: pci_machdep_common.c,v 1.7 2008/01/17 23:42:59 garbled Exp $ */
2
3/*-
4 * Copyright (c) 2007 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Tim Rightnour
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 * Generic PowerPC functions for dealing with a PCI bridge.  For most cases,
41 * these functions will work just fine, however, some machines may need
42 * specialized code, so those ports are free to write thier own functions
43 * and call those instead where appropriate.
44 */
45
46#include <sys/cdefs.h>
47__KERNEL_RCSID(0, "$NetBSD: pci_machdep_common.c,v 1.7 2008/01/17 23:42:59 garbled Exp $");
48
49#include <sys/types.h>
50#include <sys/param.h>
51#include <sys/time.h>
52#include <sys/systm.h>
53#include <sys/errno.h>
54#include <sys/extent.h>
55#include <sys/device.h>
56#include <sys/malloc.h>
57
58#include <uvm/uvm_extern.h>
59
60#define _POWERPC_BUS_DMA_PRIVATE
61#include <machine/bus.h>
62#include <machine/intr.h>
63
64#include <dev/pci/pcivar.h>
65#include <dev/pci/pcireg.h>
66#include <dev/pci/pcidevs.h>
67#include <dev/pci/pciconf.h>
68#include <dev/pci/pciidereg.h>
69
70/*
71 * PCI doesn't have any special needs; just use the generic versions
72 * of these functions.
73 */
74struct powerpc_bus_dma_tag pci_bus_dma_tag = {
75	0,			/* _bounce_thresh */
76	_bus_dmamap_create,
77	_bus_dmamap_destroy,
78	_bus_dmamap_load,
79	_bus_dmamap_load_mbuf,
80	_bus_dmamap_load_uio,
81	_bus_dmamap_load_raw,
82	_bus_dmamap_unload,
83	NULL,			/* _dmamap_sync */
84	_bus_dmamem_alloc,
85	_bus_dmamem_free,
86	_bus_dmamem_map,
87	_bus_dmamem_unmap,
88	_bus_dmamem_mmap,
89};
90
91int
92genppc_pci_bus_maxdevs(pci_chipset_tag_t pc, int busno)
93{
94	return 32;
95}
96
97const char *
98genppc_pci_intr_string(void *v, pci_intr_handle_t ih)
99{
100	static char irqstr[8];		/* 4 + 2 + NULL + sanity */
101
102	if (ih == 0 || ih >= ICU_LEN
103/* XXX on macppc it's completely legal to have PCI interrupts on a slave PIC */
104#ifdef IRQ_SLAVE
105	    || ih == IRQ_SLAVE
106#endif
107	    )
108		panic("pci_intr_string: bogus handle 0x%x", ih);
109
110	sprintf(irqstr, "irq %d", ih);
111	return (irqstr);
112
113}
114
115const struct evcnt *
116genppc_pci_intr_evcnt(void *v, pci_intr_handle_t ih)
117{
118
119	/* XXX for now, no evcnt parent reported */
120	return NULL;
121}
122
123void *
124genppc_pci_intr_establish(void *v, pci_intr_handle_t ih, int level,
125    int (*func)(void *), void *arg)
126{
127
128	if (ih == 0 || ih >= ICU_LEN
129#ifdef IRQ_SLAVE
130	    || ih == IRQ_SLAVE
131#endif
132	    )
133		panic("pci_intr_establish: bogus handle 0x%x", ih);
134
135	return intr_establish(ih, IST_LEVEL, level, func, arg);
136}
137
138void
139genppc_pci_intr_disestablish(void *v, void *cookie)
140{
141
142	intr_disestablish(cookie);
143}
144
145void
146genppc_pci_conf_interrupt(pci_chipset_tag_t pct, int bus, int dev, int pin,
147    int swiz, int *iline)
148{
149	/* do nothing */
150}
151
152int
153genppc_pci_conf_hook(pci_chipset_tag_t pct, int bus, int dev, int func,
154	pcireg_t id)
155{
156	return (PCI_CONF_DEFAULT);
157}
158
159int
160genppc_pci_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
161{
162	int pin = pa->pa_intrpin;
163	int line = pa->pa_intrline;
164
165#ifdef DEBUG
166	printf("%s: pin: %d, line: %d\n", __func__, pin, line);
167#endif
168
169	if (pin == 0) {
170		/* No IRQ used. */
171		aprint_error("pci_intr_map: interrupt pin %d\n", pin);
172		goto bad;
173	}
174
175	if (pin > 4) {
176		aprint_error("pci_intr_map: bad interrupt pin %d\n", pin);
177		goto bad;
178	}
179
180	/*
181	 * Section 6.2.4, `Miscellaneous Functions', says that 255 means
182	 * `unknown' or `no connection' on a PC.  We assume that a device with
183	 * `no connection' either doesn't have an interrupt (in which case the
184	 * pin number should be 0, and would have been noticed above), or
185	 * wasn't configured by the BIOS (in which case we punt, since there's
186	 * no real way we can know how the interrupt lines are mapped in the
187	 * hardware).
188	 *
189	 * XXX
190	 * Since IRQ 0 is only used by the clock, and we can't actually be sure
191	 * that the BIOS did its job, we also recognize that as meaning that
192	 * the BIOS has not configured the device.
193	 */
194	if (line == 0 || line == 255) {
195		aprint_error("pci_intr_map: no mapping for pin %c\n", '@' + pin);
196		goto bad;
197	} else {
198		if (line >= ICU_LEN) {
199			aprint_error("pci_intr_map: bad interrupt line %d\n", line);
200			goto bad;
201		}
202	}
203
204	*ihp = line;
205	return 0;
206
207bad:
208	*ihp = -1;
209	return 1;
210}
211
212#ifdef __HAVE_PCIIDE_MACHDEP_COMPAT_INTR_ESTABLISH
213#include <machine/isa_machdep.h>
214#include "isa.h"
215
216void *genppc_pciide_machdep_compat_intr_establish(struct device *,
217    struct pci_attach_args *, int, int (*)(void *), void *);
218
219void *
220genppc_pciide_machdep_compat_intr_establish(struct device *dev,
221    struct pci_attach_args *pa, int chan, int (*func)(void *), void *arg)
222{
223#if NISA > 0
224	int irq;
225	void *cookie;
226
227	irq = PCIIDE_COMPAT_IRQ(chan);
228	cookie = isa_intr_establish(NULL, irq, IST_LEVEL, IPL_BIO, func, arg);
229	if (cookie == NULL)
230		return (NULL);
231	printf("%s: %s channel interrupting at irq %d\n", dev->dv_xname,
232	    PCIIDE_CHANNEL_NAME(chan), irq);
233	return (cookie);
234#else
235	panic("pciide_machdep_compat_intr_establish() called");
236#endif
237}
238#endif /* __HAVE_PCIIDE_MACHDEP_COMPAT_INTR_ESTABLISH */
239