xref: /openbsd/sys/arch/amd64/pci/pci_machdep.c (revision 404b540a)
1 /*	$OpenBSD: pci_machdep.c,v 1.32 2009/09/28 15:58:30 kettenis Exp $	*/
2 /*	$NetBSD: pci_machdep.c,v 1.3 2003/05/07 21:33:58 fvdl Exp $	*/
3 
4 /*-
5  * Copyright (c) 1997, 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) 1996 Christopher G. Demetriou.  All rights reserved.
36  * Copyright (c) 1994 Charles M. Hannum.  All rights reserved.
37  *
38  * Redistribution and use in source and binary forms, with or without
39  * modification, are permitted provided that the following conditions
40  * are met:
41  * 1. Redistributions of source code must retain the above copyright
42  *    notice, this list of conditions and the following disclaimer.
43  * 2. Redistributions in binary form must reproduce the above copyright
44  *    notice, this list of conditions and the following disclaimer in the
45  *    documentation and/or other materials provided with the distribution.
46  * 3. All advertising materials mentioning features or use of this software
47  *    must display the following acknowledgement:
48  *	This product includes software developed by Charles M. Hannum.
49  * 4. The name of the author may not be used to endorse or promote products
50  *    derived from this software without specific prior written permission.
51  *
52  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
53  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
54  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
55  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
56  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
57  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
58  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
59  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
60  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
61  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
62  */
63 
64 /*
65  * Machine-specific functions for PCI autoconfiguration.
66  */
67 
68 #include <sys/types.h>
69 #include <sys/param.h>
70 #include <sys/time.h>
71 #include <sys/systm.h>
72 #include <sys/errno.h>
73 #include <sys/device.h>
74 #include <sys/extent.h>
75 #include <sys/malloc.h>
76 
77 #include <uvm/uvm_extern.h>
78 
79 #include <machine/bus.h>
80 
81 #include <machine/pio.h>
82 #include <machine/intr.h>
83 #include <machine/biosvar.h>
84 
85 #include <dev/isa/isareg.h>
86 #include <dev/isa/isavar.h>
87 #include <dev/pci/pcivar.h>
88 #include <dev/pci/pcireg.h>
89 #include <dev/pci/pcidevs.h>
90 #include <dev/pci/ppbreg.h>
91 
92 #include "ioapic.h"
93 
94 #if NIOAPIC > 0
95 #include <machine/i82093var.h>
96 #include <machine/mpbiosvar.h>
97 #endif
98 
99 struct mutex pci_conf_lock = MUTEX_INITIALIZER(IPL_HIGH);
100 
101 #define	PCI_CONF_LOCK()						\
102 do {									\
103 	mtx_enter(&pci_conf_lock);					\
104 } while (0)
105 
106 #define	PCI_CONF_UNLOCK()						\
107 do {									\
108 	mtx_leave(&pci_conf_lock);					\
109 } while (0)
110 
111 #define	PCI_MODE1_ENABLE	0x80000000UL
112 #define	PCI_MODE1_ADDRESS_REG	0x0cf8
113 #define	PCI_MODE1_DATA_REG	0x0cfc
114 
115 /*
116  * PCI doesn't have any special needs; just use the generic versions
117  * of these functions.
118  */
119 struct bus_dma_tag pci_bus_dma_tag = {
120 	NULL,			/* _may_bounce */
121 	_bus_dmamap_create,
122 	_bus_dmamap_destroy,
123 	_bus_dmamap_load,
124 	_bus_dmamap_load_mbuf,
125 	_bus_dmamap_load_uio,
126 	_bus_dmamap_load_raw,
127 	_bus_dmamap_unload,
128 	NULL,
129 	_bus_dmamem_alloc,
130 	_bus_dmamem_free,
131 	_bus_dmamem_map,
132 	_bus_dmamem_unmap,
133 	_bus_dmamem_mmap,
134 };
135 
136 extern void amdgart_probe(struct pcibus_attach_args *);
137 
138 void
139 pci_attach_hook(struct device *parent, struct device *self,
140     struct pcibus_attach_args *pba)
141 {
142 #ifndef SMALL_KERNEL
143 	if (pba->pba_bus == 0)
144 		amdgart_probe(pba);
145 #endif /* !SMALL_KERNEL */
146 }
147 
148 int
149 pci_bus_maxdevs(pci_chipset_tag_t pc, int busno)
150 {
151 	return (32);
152 }
153 
154 pcitag_t
155 pci_make_tag(pci_chipset_tag_t pc, int bus, int device, int function)
156 {
157 	if (bus >= 256 || device >= 32 || function >= 8)
158 		panic("pci_make_tag: bad request");
159 
160 	return (PCI_MODE1_ENABLE |
161 	    (bus << 16) | (device << 11) | (function << 8));
162 }
163 
164 void
165 pci_decompose_tag(pci_chipset_tag_t pc, pcitag_t tag, int *bp, int *dp, int *fp)
166 {
167 	if (bp != NULL)
168 		*bp = (tag >> 16) & 0xff;
169 	if (dp != NULL)
170 		*dp = (tag >> 11) & 0x1f;
171 	if (fp != NULL)
172 		*fp = (tag >> 8) & 0x7;
173 }
174 
175 pcireg_t
176 pci_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg)
177 {
178 	pcireg_t data;
179 
180 	PCI_CONF_LOCK();
181 	outl(PCI_MODE1_ADDRESS_REG, tag | reg);
182 	data = inl(PCI_MODE1_DATA_REG);
183 	outl(PCI_MODE1_ADDRESS_REG, 0);
184 	PCI_CONF_UNLOCK();
185 
186 	return data;
187 }
188 
189 void
190 pci_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t data)
191 {
192 	PCI_CONF_LOCK();
193 	outl(PCI_MODE1_ADDRESS_REG, tag | reg);
194 	outl(PCI_MODE1_DATA_REG, data);
195 	outl(PCI_MODE1_ADDRESS_REG, 0);
196 	PCI_CONF_UNLOCK();
197 }
198 
199 int
200 pci_intr_map(struct pci_attach_args *pa, pci_intr_handle_t *ihp)
201 {
202 	int pin = pa->pa_rawintrpin;
203 	int line = pa->pa_intrline;
204 #if NIOAPIC > 0
205 	int bus, dev, func;
206 	int mppin;
207 #endif
208 
209 	if (pin == 0) {
210 		/* No IRQ used. */
211 		goto bad;
212 	}
213 
214 	if (pin > PCI_INTERRUPT_PIN_MAX) {
215 		printf("pci_intr_map: bad interrupt pin %d\n", pin);
216 		goto bad;
217 	}
218 
219 	ihp->tag = pa->pa_tag;
220 	ihp->line = line;
221 	ihp->pin = pin;
222 
223 #if NIOAPIC > 0
224 	pci_decompose_tag(pa->pa_pc, pa->pa_tag, &bus, &dev, &func);
225 	if (mp_busses != NULL) {
226 		mppin = (dev << 2)|(pin - 1);
227 		if (intr_find_mpmapping(bus, mppin, &ihp->line) == 0) {
228 			ihp->line |= line;
229 			return 0;
230 		}
231 		if (pa->pa_bridgetag) {
232 			int swizpin = PPB_INTERRUPT_SWIZZLE(pin, dev);
233 			if (pa->pa_bridgeih[swizpin - 1].line != -1) {
234 				ihp->line = pa->pa_bridgeih[swizpin - 1].line;
235 				ihp->line |= line;
236 				return 0;
237 			}
238 		}
239 		/*
240 		 * No explicit PCI mapping found. This is not fatal,
241 		 * we'll try the ISA (or possibly EISA) mappings next.
242 		 */
243 	}
244 #endif
245 
246 	/*
247 	 * Section 6.2.4, `Miscellaneous Functions', says that 255 means
248 	 * `unknown' or `no connection' on a PC.  We assume that a device with
249 	 * `no connection' either doesn't have an interrupt (in which case the
250 	 * pin number should be 0, and would have been noticed above), or
251 	 * wasn't configured by the BIOS (in which case we punt, since there's
252 	 * no real way we can know how the interrupt lines are mapped in the
253 	 * hardware).
254 	 *
255 	 * XXX
256 	 * Since IRQ 0 is only used by the clock, and we can't actually be sure
257 	 * that the BIOS did its job, we also recognize that as meaning that
258 	 * the BIOS has not configured the device.
259 	 */
260 	if (line == 0 || line == X86_PCI_INTERRUPT_LINE_NO_CONNECTION)
261 		goto bad;
262 
263 	if (line >= NUM_LEGACY_IRQS) {
264 		printf("pci_intr_map: bad interrupt line %d\n", line);
265 		goto bad;
266 	}
267 	if (line == 2) {
268 		printf("pci_intr_map: changed line 2 to line 9\n");
269 		line = 9;
270 	}
271 
272 #if NIOAPIC > 0
273 	if (mp_busses != NULL) {
274 		if (mp_isa_bus != NULL &&
275 		    intr_find_mpmapping(mp_isa_bus->mb_idx, line, &ihp->line) == 0) {
276 			ihp->line |= line;
277 			return 0;
278 		}
279 #if NEISA > 0
280 		if (mp_eisa_bus != NULL &&
281 		    intr_find_mpmapping(mp_eisa_bus->mb_idx, line, &ihp->line) == 0) {
282 			ihp->line |= line;
283 			return 0;
284 		}
285 #endif
286 		printf("pci_intr_map: bus %d dev %d func %d pin %d; line %d\n",
287 		    bus, dev, func, pin, line);
288 		printf("pci_intr_map: no MP mapping found\n");
289 	}
290 #endif
291 
292 	return 0;
293 
294 bad:
295 	ihp->line = -1;
296 	return 1;
297 }
298 
299 const char *
300 pci_intr_string(pci_chipset_tag_t pc, pci_intr_handle_t ih)
301 {
302 	static char irqstr[64];
303 
304 	if (ih.line == 0)
305 		panic("pci_intr_string: bogus handle 0x%x", ih.line);
306 
307 #if NIOAPIC > 0
308 	if (ih.line & APIC_INT_VIA_APIC)
309 		snprintf(irqstr, sizeof(irqstr), "apic %d int %d (irq %d)",
310 		    APIC_IRQ_APIC(ih.line),
311 		    APIC_IRQ_PIN(ih.line),
312 		    pci_intr_line(pc, ih));
313 	else
314 		snprintf(irqstr, sizeof(irqstr), "irq %d",
315 		    pci_intr_line(pc, ih));
316 #else
317 	snprintf(irqstr, sizeof(irqstr), "irq %d", pci_intr_line(pc, ih));
318 #endif
319 	return (irqstr);
320 }
321 
322 #include "acpiprt.h"
323 #if NACPIPRT > 0
324 void	acpiprt_route_interrupt(int bus, int dev, int pin);
325 #endif
326 
327 void *
328 pci_intr_establish(pci_chipset_tag_t pc, pci_intr_handle_t ih, int level,
329     int (*func)(void *), void *arg, const char *what)
330 {
331 	int pin, irq;
332 	int bus, dev;
333 	struct pic *pic;
334 
335 	pci_decompose_tag(pc, ih.tag, &bus, &dev, NULL);
336 #if NACPIPRT > 0
337 	acpiprt_route_interrupt(bus, dev, ih.pin);
338 #endif
339 
340 	pic = &i8259_pic;
341 	pin = irq = ih.line;
342 
343 #if NIOAPIC > 0
344 	if (ih.line & APIC_INT_VIA_APIC) {
345 		pic = (struct pic *)ioapic_find(APIC_IRQ_APIC(ih.line));
346 		if (pic == NULL) {
347 			printf("pci_intr_establish: bad ioapic %d\n",
348 			    APIC_IRQ_APIC(ih.line));
349 			return NULL;
350 		}
351 		pin = APIC_IRQ_PIN(ih.line);
352 		irq = APIC_IRQ_LEGACY_IRQ(ih.line);
353 		if (irq < 0 || irq >= NUM_LEGACY_IRQS)
354 			irq = -1;
355 	}
356 #endif
357 
358 	return intr_establish(irq, pic, pin, IST_LEVEL, level, func, arg, what);
359 }
360 
361 void
362 pci_intr_disestablish(pci_chipset_tag_t pc, void *cookie)
363 {
364 	intr_disestablish(cookie);
365 }
366 
367 struct extent *pciio_ex;
368 struct extent *pcimem_ex;
369 
370 void
371 pci_init_extents(void)
372 {
373 	bios_memmap_t *bmp;
374 	u_int64_t size;
375 
376 	if (pciio_ex == NULL) {
377 		/*
378 		 * We only have 64K of addressable I/O space.
379 		 * However, since BARs may contain garbage, we cover
380 		 * the full 32-bit address space defined by PCI of
381 		 * which we only make the first 64K available.
382 		 */
383 		pciio_ex = extent_create("pciio", 0, 0xffffffff, M_DEVBUF,
384 		    NULL, 0, EX_NOWAIT | EX_FILLED);
385 		if (pciio_ex == NULL)
386 			return;
387 		extent_free(pciio_ex, 0, 0x10000, M_NOWAIT);
388 	}
389 
390 	if (pcimem_ex == NULL) {
391 		pcimem_ex = extent_create("pcimem", 0, 0xffffffff, M_DEVBUF,
392 		    NULL, 0, EX_NOWAIT);
393 		if (pcimem_ex == NULL)
394 			return;
395 
396 		for (bmp = bios_memmap; bmp->type != BIOS_MAP_END; bmp++) {
397 			/*
398 			 * Ignore address space beyond 4G.
399 			 */
400 			if (bmp->addr >= 0x100000000ULL)
401 				continue;
402 			size = bmp->size;
403 			if (bmp->addr + size >= 0x100000000ULL)
404 				size = 0x100000000ULL - bmp->addr;
405 
406 			/* Ignore zero-sized regions. */
407 			if (size == 0)
408 				continue;
409 
410 			if (extent_alloc_region(pcimem_ex, bmp->addr, size,
411 			    EX_NOWAIT))
412 				printf("memory map conflict 0x%llx/0x%llx\n",
413 				    bmp->addr, bmp->size);
414 		}
415 
416 		/* Take out the video buffer area and BIOS areas. */
417 		extent_alloc_region(pcimem_ex, IOM_BEGIN, IOM_SIZE,
418 		    EX_CONFLICTOK | EX_NOWAIT);
419 	}
420 }
421