Annotation of sys/dev/acpi/acpiprt.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: acpiprt.c,v 1.16 2007/02/23 00:04:40 jordan 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/ppbreg.h>
35:
36: #include <machine/i82093reg.h>
37: #include <machine/i82093var.h>
38:
39: #include <machine/mpbiosvar.h>
40:
41: #include "ioapic.h"
42:
43: int acpiprt_match(struct device *, void *, void *);
44: void acpiprt_attach(struct device *, struct device *, void *);
45: int acpiprt_getirq(union acpi_resource *crs, void *arg);
46: int acpiprt_getminbus(union acpi_resource *, void *);
47:
48:
49: struct acpiprt_softc {
50: struct device sc_dev;
51:
52: struct acpi_softc *sc_acpi;
53: struct aml_node *sc_devnode;
54:
55: int sc_bus;
56: };
57:
58: struct cfattach acpiprt_ca = {
59: sizeof(struct acpiprt_softc), acpiprt_match, acpiprt_attach
60: };
61:
62: struct cfdriver acpiprt_cd = {
63: NULL, "acpiprt", DV_DULL
64: };
65:
66: void acpiprt_prt_add(struct acpiprt_softc *, struct aml_value *);
67: int acpiprt_getpcibus(struct acpiprt_softc *, struct aml_node *);
68:
69: int
70: acpiprt_match(struct device *parent, void *match, void *aux)
71: {
72: struct acpi_attach_args *aa = aux;
73: struct cfdata *cf = match;
74:
75: /* sanity */
76: if (aa->aaa_name == NULL ||
77: strcmp(aa->aaa_name, cf->cf_driver->cd_name) != 0 ||
78: aa->aaa_table != NULL)
79: return (0);
80:
81: return (1);
82: }
83:
84: void
85: acpiprt_attach(struct device *parent, struct device *self, void *aux)
86: {
87: struct acpiprt_softc *sc = (struct acpiprt_softc *)self;
88: struct acpi_attach_args *aa = aux;
89: struct aml_value res;
90: int i;
91:
92: sc->sc_acpi = (struct acpi_softc *)parent;
93: sc->sc_devnode = aa->aaa_node;
94: sc->sc_bus = acpiprt_getpcibus(sc, sc->sc_devnode);
95:
96: printf(": bus %d (%s)", sc->sc_bus, sc->sc_devnode->parent->name);
97:
98: if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_PRT", 0, NULL, &res)) {
99: printf(": no PCI interrupt routing table\n");
100: return;
101: }
102:
103: if (res.type != AML_OBJTYPE_PACKAGE) {
104: printf(": _PRT is not a package\n");
105: aml_freevalue(&res);
106: return;
107: }
108:
109: printf("\n");
110:
111: if (sc->sc_bus == -1)
112: return;
113:
114: for (i = 0; i < res.length; i++)
115: acpiprt_prt_add(sc, res.v_package[i]);
116:
117: aml_freevalue(&res);
118: }
119:
120: int
121: acpiprt_getirq(union acpi_resource *crs, void *arg)
122: {
123: int *irq = (int *)arg;
124: int typ;
125:
126: typ = AML_CRSTYPE(crs);
127: switch (typ) {
128: case SR_IRQ:
129: *irq = ffs(aml_letohost16(crs->sr_irq.irq_mask)) - 1;
130: break;
131: case LR_EXTIRQ:
132: *irq = aml_letohost32(crs->lr_extirq.irq[0]);
133: break;
134: default:
135: printf("Unknown interrupt : %x\n", typ);
136: }
137: return (0);
138: }
139:
140: void
141: acpiprt_prt_add(struct acpiprt_softc *sc, struct aml_value *v)
142: {
143: struct aml_node *node;
144: struct aml_value res, *pp;
145: u_int64_t addr;
146: int pin, irq, sta;
147: #if NIOAPIC > 0
148: struct mp_intr_map *map;
149: struct ioapic_softc *apic;
150: #endif
151: pci_chipset_tag_t pc = NULL;
152: pcitag_t tag;
153: pcireg_t reg;
154: int bus, dev, func, nfuncs;
155:
156: if (v->type != AML_OBJTYPE_PACKAGE || v->length != 4) {
157: printf("invalid mapping object\n");
158: return;
159: }
160:
161: addr = aml_val2int(v->v_package[0]);
162: pin = aml_val2int(v->v_package[1]);
163: if (pin > 3) {
164: return;
165: }
166:
167: pp = v->v_package[2];
168: if (pp->type == AML_OBJTYPE_NAMEREF) {
169: node = aml_searchname(sc->sc_devnode, pp->v_nameref);
170: if (node == NULL) {
171: printf("Invalid device!\n");
172: return;
173: }
174: pp = node->value;
175: }
176: if (pp->type == AML_OBJTYPE_OBJREF) {
177: pp = pp->v_objref.ref;
178: }
179: if (pp->type == AML_OBJTYPE_DEVICE) {
180: node = pp->node;
181: if (aml_evalname(sc->sc_acpi, node, "_STA", 0, NULL, &res))
182: printf("no _STA method\n");
183:
184: sta = aml_val2int(&res) & STA_ENABLED;
185: aml_freevalue(&res);
186: if (sta == 0)
187: return;
188:
189: if (aml_evalname(sc->sc_acpi, node, "_CRS", 0, NULL, &res))
190: printf("no _CRS method\n");
191:
192: if (res.type != AML_OBJTYPE_BUFFER || res.length < 6) {
193: printf("invalid _CRS object\n");
194: aml_freevalue(&res);
195: return;
196: }
197: aml_parse_resource(res.length, res.v_buffer,
198: acpiprt_getirq, &irq);
199: aml_freevalue(&res);
200: } else {
201: irq = aml_val2int(v->v_package[3]);
202: }
203:
204: #ifdef ACPI_DEBUG
205: printf("%s: %s addr 0x%llx pin %d irq %d\n",
206: DEVNAME(sc), aml_nodename(pp->node), addr, pin, irq);
207: #endif
208:
209: #if NIOAPIC > 0
210: if (nioapics > 0) {
211: apic = ioapic_find_bybase(irq);
212: if (apic == NULL) {
213: printf("%s: no apic found for irq %d\n", DEVNAME(sc), irq);
214: return;
215: }
216:
217: map = malloc(sizeof (struct mp_intr_map), M_DEVBUF, M_NOWAIT);
218: if (map == NULL)
219: return;
220:
221: memset(map, 0, sizeof *map);
222: map->ioapic = apic;
223: map->ioapic_pin = irq - apic->sc_apic_vecbase;
224: map->bus_pin = ((addr >> 14) & 0x7c) | (pin & 0x3);
225: map->redir = IOAPIC_REDLO_ACTLO | IOAPIC_REDLO_LEVEL;
226: map->redir |= (IOAPIC_REDLO_DEL_LOPRI << IOAPIC_REDLO_DEL_SHIFT);
227:
228: map->ioapic_ih = APIC_INT_VIA_APIC |
229: ((apic->sc_apicid << APIC_INT_APIC_SHIFT) |
230: (map->ioapic_pin << APIC_INT_PIN_SHIFT));
231:
232: apic->sc_pins[map->ioapic_pin].ip_map = map;
233:
234: map->next = mp_busses[sc->sc_bus].mb_intrs;
235: mp_busses[sc->sc_bus].mb_intrs = map;
236:
237: return;
238: }
239: #endif
240:
241: bus = sc->sc_bus;
242: dev = ACPI_PCI_DEV(addr << 16);
243: tag = pci_make_tag(pc, bus, dev, 0);
244:
245: reg = pci_conf_read(pc, tag, PCI_BHLC_REG);
246: if (PCI_HDRTYPE_MULTIFN(reg))
247: nfuncs = 8;
248: else
249: nfuncs = 1;
250:
251: for (func = 0; func < nfuncs; func++) {
252: tag = pci_make_tag(pc, bus, dev, func);
253: reg = pci_conf_read(pc, tag, PCI_INTERRUPT_REG);
254: if (PCI_INTERRUPT_PIN(reg) == pin + 1) {
255: reg &= ~(PCI_INTERRUPT_LINE_MASK << PCI_INTERRUPT_LINE_SHIFT);
256: reg |= irq << PCI_INTERRUPT_LINE_SHIFT;
257: pci_conf_write(pc, tag, PCI_INTERRUPT_REG, reg);
258: }
259: }
260: }
261:
262: int
263: acpiprt_getminbus(union acpi_resource *crs, void *arg)
264: {
265: int *bbn = arg;
266: int typ = AML_CRSTYPE(crs);
267:
268: /* Check for embedded bus number */
269: if (typ == LR_WORD && crs->lr_word.type == 2)
270: *bbn = crs->lr_word._min;
271: return 0;
272: }
273:
274: int
275: acpiprt_getpcibus(struct acpiprt_softc *sc, struct aml_node *node)
276: {
277: struct aml_node *parent = node->parent;
278: struct aml_value res;
279: pci_chipset_tag_t pc = NULL;
280: pcitag_t tag;
281: pcireg_t reg;
282: int bus, dev, func, rv;
283:
284: if (parent == NULL)
285: return 0;
286:
287: if (aml_evalname(sc->sc_acpi, parent, "_ADR", 0, NULL, &res) == 0) {
288: bus = acpiprt_getpcibus(sc, parent);
289: dev = ACPI_PCI_DEV(aml_val2int(&res) << 16);
290: func = ACPI_PCI_FN(aml_val2int(&res) << 16);
291: aml_freevalue(&res);
292:
293: /*
294: * Some systems return 255 as the device number for
295: * devices that are not really there.
296: */
297: if (dev >= pci_bus_maxdevs(pc, bus))
298: return (-1);
299:
300: tag = pci_make_tag(pc, bus, dev, func);
301: reg = pci_conf_read(pc, tag, PCI_CLASS_REG);
302: if (PCI_CLASS(reg) == PCI_CLASS_BRIDGE &&
303: PCI_SUBCLASS(reg) == PCI_SUBCLASS_BRIDGE_PCI) {
304: reg = pci_conf_read(pc, tag, PPB_REG_BUSINFO);
305: return (PPB_BUSINFO_SECONDARY(reg));
306: }
307: }
308:
309: if (aml_evalname(sc->sc_acpi, parent, "_CRS", 0, NULL, &res) == 0) {
310: rv = -1;
311: if (res.type == AML_OBJTYPE_BUFFER)
312: aml_parse_resource(res.length, res.v_buffer,
313: acpiprt_getminbus, &rv);
314: aml_freevalue(&res);
315: if (rv != -1)
316: return rv;
317: }
318: if (aml_evalname(sc->sc_acpi, parent, "_BBN", 0, NULL, &res) == 0) {
319: rv = aml_val2int(&res);
320: aml_freevalue(&res);
321: return (rv);
322: }
323:
324: return (0);
325: }
CVSweb