xref: /openbsd-src/sys/dev/acpi/acpiprt.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /* $OpenBSD: acpiprt.c,v 1.35 2009/03/31 20:59:00 kettenis Exp $ */
2 /*
3  * Copyright (c) 2006 Mark Kettenis <kettenis@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/param.h>
19 #include <sys/proc.h>
20 #include <sys/signalvar.h>
21 #include <sys/systm.h>
22 #include <sys/device.h>
23 #include <sys/malloc.h>
24 
25 #include <machine/bus.h>
26 
27 #include <dev/acpi/acpireg.h>
28 #include <dev/acpi/acpivar.h>
29 #include <dev/acpi/acpidev.h>
30 #include <dev/acpi/amltypes.h>
31 #include <dev/acpi/dsdt.h>
32 
33 #include <dev/pci/pcivar.h>
34 #include <dev/pci/pcidevs.h>
35 #include <dev/pci/ppbreg.h>
36 
37 #include <machine/i82093reg.h>
38 #include <machine/i82093var.h>
39 
40 #include <machine/mpbiosvar.h>
41 
42 #include "ioapic.h"
43 
44 struct acpiprt_map {
45 	int bus, dev;
46 	int pin;
47 	int irq;
48 	struct acpiprt_softc *sc;
49 	struct aml_node *node;
50 	SIMPLEQ_ENTRY(acpiprt_map) list;
51 };
52 
53 SIMPLEQ_HEAD(, acpiprt_map) acpiprt_map_list =
54     SIMPLEQ_HEAD_INITIALIZER(acpiprt_map_list);
55 
56 int	acpiprt_match(struct device *, void *, void *);
57 void	acpiprt_attach(struct device *, struct device *, void *);
58 int	acpiprt_getirq(union acpi_resource *crs, void *arg);
59 int	acpiprt_getminbus(union acpi_resource *, void *);
60 int	acpiprt_chooseirq(union acpi_resource *, void *);
61 
62 struct acpiprt_softc {
63 	struct device		sc_dev;
64 
65 	struct acpi_softc	*sc_acpi;
66 	struct aml_node		*sc_devnode;
67 
68 	int			sc_bus;
69 };
70 
71 struct cfattach acpiprt_ca = {
72 	sizeof(struct acpiprt_softc), acpiprt_match, acpiprt_attach
73 };
74 
75 struct cfdriver acpiprt_cd = {
76 	NULL, "acpiprt", DV_DULL
77 };
78 
79 void	acpiprt_prt_add(struct acpiprt_softc *, struct aml_value *);
80 int	acpiprt_getpcibus(struct acpiprt_softc *, struct aml_node *);
81 void	acpiprt_route_interrupt(int bus, int dev, int pin);
82 
83 int
84 acpiprt_match(struct device *parent, void *match, void *aux)
85 {
86 	struct acpi_attach_args	*aa = aux;
87 	struct cfdata  *cf = match;
88 
89 	/* sanity */
90 	if (aa->aaa_name == NULL ||
91 	    strcmp(aa->aaa_name, cf->cf_driver->cd_name) != 0 ||
92 	    aa->aaa_table != NULL)
93 		return (0);
94 
95 	return (1);
96 }
97 
98 void
99 acpiprt_attach(struct device *parent, struct device *self, void *aux)
100 {
101 	struct acpiprt_softc *sc = (struct acpiprt_softc *)self;
102 	struct acpi_attach_args *aa = aux;
103 	struct aml_value res;
104 	int i;
105 
106 	sc->sc_acpi = (struct acpi_softc *)parent;
107 	sc->sc_devnode = aa->aaa_node;
108 	sc->sc_bus = acpiprt_getpcibus(sc, sc->sc_devnode);
109 
110 	printf(": bus %d (%s)", sc->sc_bus, sc->sc_devnode->parent->name);
111 
112 	if (aml_evalnode(sc->sc_acpi, sc->sc_devnode, 0, NULL, &res)) {
113 		printf(": no PCI interrupt routing table\n");
114 		return;
115 	}
116 
117 	if (res.type != AML_OBJTYPE_PACKAGE) {
118 		printf(": _PRT is not a package\n");
119 		aml_freevalue(&res);
120 		return;
121 	}
122 
123 	printf("\n");
124 
125 	if (sc->sc_bus == -1)
126 		return;
127 
128 	for (i = 0; i < res.length; i++)
129 		acpiprt_prt_add(sc, res.v_package[i]);
130 
131 	aml_freevalue(&res);
132 }
133 
134 int
135 acpiprt_getirq(union acpi_resource *crs, void *arg)
136 {
137 	int *irq = (int *)arg;
138 	int typ;
139 
140 	typ = AML_CRSTYPE(crs);
141 	switch (typ) {
142 	case SR_IRQ:
143 		*irq = ffs(aml_letohost16(crs->sr_irq.irq_mask)) - 1;
144 		break;
145 	case LR_EXTIRQ:
146 		*irq = aml_letohost32(crs->lr_extirq.irq[0]);
147 		break;
148 	default:
149 		printf("unknown interrupt: %x\n", typ);
150 	}
151 	return (0);
152 }
153 
154 int
155 acpiprt_pri[16] = {
156 	0,			/* 8254 Counter 0 */
157 	1,			/* Keyboard */
158 	0,			/* 8259 Slave */
159 	2,			/* Serial Port A */
160 	2,			/* Serial Port B */
161 	5,			/* Parallel Port / Generic */
162 	2,			/* Floppy Disk */
163 	4, 			/* Parallel Port / Generic */
164 	1,			/* RTC */
165 	6,			/* Generic */
166 	7,			/* Generic */
167 	7,			/* Generic */
168 	1,			/* Mouse */
169 	0,			/* FPU */
170 	2,			/* Primary IDE */
171 	3			/* Secondary IDE */
172 };
173 
174 int
175 acpiprt_chooseirq(union acpi_resource *crs, void *arg)
176 {
177 	int *irq = (int *)arg;
178 	int typ, i, pri = -1;
179 
180 	typ = AML_CRSTYPE(crs);
181 	switch (typ) {
182 	case SR_IRQ:
183 		for (i = 0; i < sizeof(crs->sr_irq.irq_mask) * 8; i++) {
184 			if (crs->sr_irq.irq_mask & (1 << i) &&
185 			    acpiprt_pri[i] > pri) {
186 				*irq = i;
187 				pri = acpiprt_pri[*irq];
188 			}
189 		}
190 		break;
191 	case LR_EXTIRQ:
192 		/* First try non-8259 interrupts. */
193 		for (i = 0; i < crs->lr_extirq.irq_count; i++) {
194 			if (crs->lr_extirq.irq[i] > 15) {
195 				*irq = crs->lr_extirq.irq[i];
196 				return (0);
197 			}
198 		}
199 
200 		for (i = 0; i < crs->lr_extirq.irq_count; i++) {
201 			if (acpiprt_pri[crs->lr_extirq.irq[i]] > pri) {
202 				*irq = crs->lr_extirq.irq[i];
203 				pri = acpiprt_pri[*irq];
204 			}
205 		}
206 		break;
207 	default:
208 		printf("unknown interrupt: %x\n", typ);
209 	}
210 	return (0);
211 }
212 
213 void
214 acpiprt_prt_add(struct acpiprt_softc *sc, struct aml_value *v)
215 {
216 	struct aml_node	*node;
217 	struct aml_value res, *pp;
218 	u_int64_t addr;
219 	int pin, irq;
220 	int64_t sta;
221 #if NIOAPIC > 0
222 	struct mp_intr_map *map;
223 	struct ioapic_softc *apic;
224 #endif
225 	pci_chipset_tag_t pc = NULL;
226 	pcitag_t tag;
227 	pcireg_t reg;
228 	int bus, dev, func, nfuncs;
229 	struct acpiprt_map *p;
230 
231 	if (v->type != AML_OBJTYPE_PACKAGE || v->length != 4) {
232 		printf("invalid mapping object\n");
233 		return;
234 	}
235 
236 	addr = aml_val2int(v->v_package[0]);
237 	pin = aml_val2int(v->v_package[1]);
238 	if (pin > 3) {
239 		return;
240 	}
241 
242 	pp = v->v_package[2];
243 	if (pp->type == AML_OBJTYPE_STRING) {
244 		node = aml_searchrel(sc->sc_devnode, pp->v_string);
245 		if (node == NULL) {
246 			printf("Invalid device\n");
247 			return;
248 		}
249 		pp = node->value;
250 	}
251 	if (pp->type == AML_OBJTYPE_NAMEREF) {
252 		node = aml_searchrel(sc->sc_devnode, pp->v_nameref);
253 		if (node == NULL) {
254 			printf("Invalid device\n");
255 			return;
256 		}
257 		pp = node->value;
258 	}
259 	if (pp->type == AML_OBJTYPE_OBJREF) {
260 		pp = pp->v_objref.ref;
261 	}
262 	if (pp->type == AML_OBJTYPE_DEVICE) {
263 		node = pp->node;
264 		if (aml_evalinteger(sc->sc_acpi, node, "_STA", 0, NULL, &sta)) {
265 			printf("no _STA method\n");
266 			return;
267 		}
268 
269 		if ((sta & STA_PRESENT) == 0)
270 			return;
271 
272 		if (aml_evalname(sc->sc_acpi, node, "_CRS", 0, NULL, &res)) {
273 			printf("no _CRS method\n");
274 			return;
275 		}
276 
277 		if (res.type != AML_OBJTYPE_BUFFER || res.length < 5) {
278 			printf("invalid _CRS object\n");
279 			aml_freevalue(&res);
280 			return;
281 		}
282 		aml_parse_resource(res.length, res.v_buffer,
283 		    acpiprt_getirq, &irq);
284 		aml_freevalue(&res);
285 
286 		/* Pick a new IRQ if necessary. */
287 		if ((irq == 0 || irq == 2 || irq == 13) &&
288 		    !aml_evalname(sc->sc_acpi, node, "_PRS", 0, NULL, &res)){
289 			if (res.type == AML_OBJTYPE_BUFFER &&
290 			    res.length >= 5) {
291 				aml_parse_resource(res.length, res.v_buffer,
292 				    acpiprt_chooseirq, &irq);
293 			}
294 			aml_freevalue(&res);
295 		}
296 
297 		if ((p = malloc(sizeof(*p), M_ACPI, M_NOWAIT)) == NULL)
298 			return;
299 		p->bus = sc->sc_bus;
300 		p->dev = ACPI_PCI_DEV(addr << 16);
301 		p->pin = pin;
302 		p->irq = irq;
303 		p->sc = sc;
304 		p->node = node;
305 		SIMPLEQ_INSERT_TAIL(&acpiprt_map_list, p, list);
306 	} else {
307 		irq = aml_val2int(v->v_package[3]);
308 	}
309 
310 #ifdef ACPI_DEBUG
311 	printf("%s: %s addr 0x%llx pin %d irq %d\n",
312 	    DEVNAME(sc), aml_nodename(pp->node), addr, pin, irq);
313 #endif
314 
315 #if NIOAPIC > 0
316 	if (nioapics > 0) {
317 		apic = ioapic_find_bybase(irq);
318 		if (apic == NULL) {
319 			printf("%s: no apic found for irq %d\n", DEVNAME(sc), irq);
320 			return;
321 		}
322 
323 		map = malloc(sizeof(*map), M_DEVBUF, M_NOWAIT | M_ZERO);
324 		if (map == NULL)
325 			return;
326 
327 		map->ioapic = apic;
328 		map->ioapic_pin = irq - apic->sc_apic_vecbase;
329 		map->bus_pin = ((addr >> 14) & 0x7c) | (pin & 0x3);
330 		map->redir = IOAPIC_REDLO_ACTLO | IOAPIC_REDLO_LEVEL;
331 		map->redir |= (IOAPIC_REDLO_DEL_LOPRI << IOAPIC_REDLO_DEL_SHIFT);
332 
333 		map->ioapic_ih = APIC_INT_VIA_APIC |
334 		    ((apic->sc_apicid << APIC_INT_APIC_SHIFT) |
335 		    (map->ioapic_pin << APIC_INT_PIN_SHIFT));
336 
337 		apic->sc_pins[map->ioapic_pin].ip_map = map;
338 
339 		map->next = mp_busses[sc->sc_bus].mb_intrs;
340 		mp_busses[sc->sc_bus].mb_intrs = map;
341 
342 		return;
343 	}
344 #endif
345 
346 	bus = sc->sc_bus;
347 	dev = ACPI_PCI_DEV(addr << 16);
348 	tag = pci_make_tag(pc, bus, dev, 0);
349 
350 	reg = pci_conf_read(pc, tag, PCI_BHLC_REG);
351 	if (PCI_HDRTYPE_MULTIFN(reg))
352 		nfuncs = 8;
353 	else
354 		nfuncs = 1;
355 
356 	for (func = 0; func < nfuncs; func++) {
357 		tag = pci_make_tag(pc, bus, dev, func);
358 		reg = pci_conf_read(pc, tag, PCI_INTERRUPT_REG);
359 		if (PCI_INTERRUPT_PIN(reg) == pin + 1) {
360 			reg &= ~(PCI_INTERRUPT_LINE_MASK << PCI_INTERRUPT_LINE_SHIFT);
361 			reg |= irq << PCI_INTERRUPT_LINE_SHIFT;
362 			pci_conf_write(pc, tag, PCI_INTERRUPT_REG, reg);
363 		}
364 	}
365 }
366 
367 int
368 acpiprt_getminbus(union acpi_resource *crs, void *arg)
369 {
370 	int *bbn = arg;
371 	int typ = AML_CRSTYPE(crs);
372 
373 	/* Check for embedded bus number */
374 	if (typ == LR_WORD && crs->lr_word.type == 2)
375 		*bbn = crs->lr_word._min;
376 	return 0;
377 }
378 
379 int
380 acpiprt_getpcibus(struct acpiprt_softc *sc, struct aml_node *node)
381 {
382 	struct aml_node *parent = node->parent;
383 	struct aml_value res;
384 	pci_chipset_tag_t pc = NULL;
385 	pcitag_t tag;
386 	pcireg_t reg;
387 	int bus, dev, func, rv;
388 	int64_t ires;
389 
390 	if (parent == NULL)
391 		return 0;
392 
393 	/*
394 	 * If our parent is a a bridge, it might have an address descriptor
395 	 * that tells us our bus number.
396 	 */
397 	if (aml_evalname(sc->sc_acpi, parent, "_CRS.", 0, NULL, &res) == 0) {
398 		rv = -1;
399 		if (res.type == AML_OBJTYPE_BUFFER)
400 			aml_parse_resource(res.length, res.v_buffer,
401 			    acpiprt_getminbus, &rv);
402 		aml_freevalue(&res);
403 		if (rv != -1)
404 			return rv;
405 	}
406 
407 	/*
408 	 * If our parent is the root of the bus, it should specify the
409 	 * base bus number.
410 	 */
411 	if (aml_evalinteger(sc->sc_acpi, parent, "_BBN.", 0, NULL, &ires) == 0) {
412 		return (ires);
413 	}
414 
415 	/*
416 	 * If our parent is a PCI-PCI bridge, get our bus number from its
417 	 * PCI config space.
418 	 */
419 	if (aml_evalinteger(sc->sc_acpi, parent, "_ADR.", 0, NULL, &ires) == 0) {
420 		bus = acpiprt_getpcibus(sc, parent);
421 		dev = ACPI_PCI_DEV(ires << 16);
422 		func = ACPI_PCI_FN(ires << 16);
423 
424 		/*
425 		 * Some systems return 255 as the device number for
426 		 * devices that are not really there.
427 		 */
428 		if (dev >= pci_bus_maxdevs(pc, bus))
429 			return (-1);
430 
431 		tag = pci_make_tag(pc, bus, dev, func);
432 
433 		/* Check whether the device is really there. */
434 		reg = pci_conf_read(pc, tag, PCI_ID_REG);
435 		if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID)
436 			return (-1);
437 
438 		/* Fetch bus number from PCI config space. */
439 		reg = pci_conf_read(pc, tag, PCI_CLASS_REG);
440 		if (PCI_CLASS(reg) == PCI_CLASS_BRIDGE &&
441 		    PCI_SUBCLASS(reg) == PCI_SUBCLASS_BRIDGE_PCI) {
442 			reg = pci_conf_read(pc, tag, PPB_REG_BUSINFO);
443 			return (PPB_BUSINFO_SECONDARY(reg));
444 		}
445 	}
446 	return (0);
447 }
448 
449 void
450 acpiprt_route_interrupt(int bus, int dev, int pin)
451 {
452 	struct acpiprt_softc *sc;
453 	struct acpiprt_map *p;
454 	struct aml_node *node = NULL;
455 	struct aml_value res, res2;
456 	union acpi_resource *crs;
457 	int irq, newirq;
458 	int64_t sta;
459 
460 	SIMPLEQ_FOREACH(p, &acpiprt_map_list, list) {
461 		if (p->bus == bus && p->dev == dev && p->pin == (pin - 1)) {
462 			newirq = p->irq;
463 			sc = p->sc;
464 			node = p->node;
465 			break;
466 		}
467 	}
468 	if (node == NULL)
469 		return;
470 
471 	if (aml_evalinteger(sc->sc_acpi, node, "_STA", 0, NULL, &sta)) {
472 		printf("no _STA method\n");
473 		return;
474 	}
475 
476 	KASSERT(sta & STA_PRESENT);
477 
478 	if (aml_evalname(sc->sc_acpi, node, "_CRS", 0, NULL, &res)) {
479 		printf("no _CRS method\n");
480 		return;
481 	}
482 	if (res.type != AML_OBJTYPE_BUFFER || res.length < 5) {
483 		printf("invalid _CRS object\n");
484 		aml_freevalue(&res);
485 		return;
486 	}
487 	aml_parse_resource(res.length, res.v_buffer, acpiprt_getirq, &irq);
488 
489 	/* Only re-route interrupts when necessary. */
490 	if ((sta & STA_ENABLED) && irq == newirq) {
491 		aml_freevalue(&res);
492 		return;
493 	}
494 
495 	crs = (union acpi_resource *)res.v_buffer;
496 	switch (AML_CRSTYPE(crs)) {
497 	case SR_IRQ:
498 		crs->sr_irq.irq_mask = htole16(1 << newirq);
499 		break;
500 	case LR_EXTIRQ:
501 		crs->lr_extirq.irq[0] = htole32(newirq);
502 		break;
503 	}
504 
505 	if (aml_evalname(sc->sc_acpi, node, "_SRS", 1, &res, &res2)) {
506 		printf("no _SRS method\n");
507 		aml_freevalue(&res);
508 		return;
509 	}
510 	aml_freevalue(&res);
511 	aml_freevalue(&res2);
512 }
513