xref: /freebsd/sys/dev/acpica/acpi_pci_link.c (revision 407ea2909550d7e6bab84f67e4d40ed28606318e)
1 /*-
2  * Copyright (c) 2002 Mitsuru IWASAKI <iwasaki@jp.freebsd.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
30 #include "opt_acpi.h"
31 #include <sys/param.h>
32 #include <sys/kernel.h>
33 #include <sys/bus.h>
34 
35 #include "acpi.h"
36 
37 #include <dev/acpica/acpivar.h>
38 #include <dev/acpica/acpi_pcibvar.h>
39 
40 /*
41  * Hooks for the ACPI CA debugging infrastructure
42  */
43 #define _COMPONENT	ACPI_BUS
44 ACPI_MODULE_NAME("PCI_LINK")
45 
46 #define MAX_POSSIBLE_INTERRUPTS	16
47 #define MAX_ISA_INTERRUPTS	16
48 #define MAX_ACPI_INTERRUPTS	255
49 
50 struct acpi_pci_link_entry {
51 	TAILQ_ENTRY(acpi_pci_link_entry) links;
52 	ACPI_HANDLE	handle;
53 	UINT8		current_irq;
54 	UINT8		initial_irq;
55 	ACPI_RESOURCE	possible_resources;
56 	UINT8		number_of_interrupts;
57 	UINT8		interrupts[MAX_POSSIBLE_INTERRUPTS];
58 
59 	UINT8		sorted_irq[MAX_POSSIBLE_INTERRUPTS];
60 	int		references;
61 	int		priority;
62 };
63 
64 TAILQ_HEAD(acpi_pci_link_entries, acpi_pci_link_entry);
65 static struct acpi_pci_link_entries acpi_pci_link_entries;
66 
67 struct acpi_prt_entry {
68 	TAILQ_ENTRY(acpi_prt_entry) links;
69 	device_t	pcidev;
70 	int		busno;
71 	ACPI_PCI_ROUTING_TABLE prt;
72 	struct acpi_pci_link_entry *pci_link;
73 };
74 
75 TAILQ_HEAD(acpi_prt_entries, acpi_prt_entry);
76 static struct acpi_prt_entries acpi_prt_entries;
77 
78 static int	irq_penalty[MAX_ACPI_INTERRUPTS];
79 
80 #define ACPI_STA_PRESENT	0x00000001
81 #define ACPI_STA_ENABLE		0x00000002
82 #define ACPI_STA_SHOWINUI	0x00000004
83 #define ACPI_STA_FUNCTIONAL	0x00000008
84 
85 /*
86  * PCI link object management
87  */
88 
89 static void
90 acpi_pci_link_dump_polarity(UINT32 ActiveHighLow)
91 {
92 
93 	switch (ActiveHighLow) {
94 	case ACPI_ACTIVE_HIGH:
95 		printf("high,");
96 		break;
97 
98 	case ACPI_ACTIVE_LOW:
99 		printf("low,");
100 		break;
101 
102 	default:
103 		printf("unknown,");
104 		break;
105 	}
106 }
107 
108 static void
109 acpi_pci_link_dump_trigger(UINT32 EdgeLevel)
110 {
111 
112 	switch (EdgeLevel) {
113 	case ACPI_EDGE_SENSITIVE:
114 		printf("edge,");
115 		break;
116 
117 	case ACPI_LEVEL_SENSITIVE:
118 		printf("level,");
119 		break;
120 
121 	default:
122 		printf("unknown,");
123 		break;
124 	}
125 }
126 
127 static void
128 acpi_pci_link_dump_sharemode(UINT32 SharedExclusive)
129 {
130 
131 	switch (SharedExclusive) {
132 	case ACPI_EXCLUSIVE:
133 		printf("exclusive");
134 		break;
135 
136 	case ACPI_SHARED:
137 		printf("sharable");
138 		break;
139 
140 	default:
141 		printf("unknown");
142 		break;
143 	}
144 }
145 
146 static void
147 acpi_pci_link_entry_dump(struct acpi_prt_entry *entry)
148 {
149 	UINT8			i;
150 	ACPI_RESOURCE_IRQ	*Irq;
151 	ACPI_RESOURCE_EXT_IRQ	*ExtIrq;
152 
153 	if (entry == NULL || entry->pci_link == NULL) {
154 		return;
155 	}
156 
157 	printf("%s irq %3d: ", acpi_name(entry->pci_link->handle),
158 	    entry->pci_link->current_irq);
159 
160 	printf("[");
161 	for (i = 0; i < entry->pci_link->number_of_interrupts; i++) {
162 		printf("%3d", entry->pci_link->interrupts[i]);
163 	}
164 	printf("] ");
165 
166 	switch (entry->pci_link->possible_resources.Id) {
167 	case ACPI_RSTYPE_IRQ:
168 		Irq = &entry->pci_link->possible_resources.Data.Irq;
169 
170 		acpi_pci_link_dump_polarity(Irq->ActiveHighLow);
171 		acpi_pci_link_dump_trigger(Irq->EdgeLevel);
172 		acpi_pci_link_dump_sharemode(Irq->SharedExclusive);
173 		break;
174 
175 	case ACPI_RSTYPE_EXT_IRQ:
176 		ExtIrq = &entry->pci_link->possible_resources.Data.ExtendedIrq;
177 
178 		acpi_pci_link_dump_polarity(ExtIrq->ActiveHighLow);
179 		acpi_pci_link_dump_trigger(ExtIrq->EdgeLevel);
180 		acpi_pci_link_dump_sharemode(ExtIrq->SharedExclusive);
181 		break;
182 	}
183 
184 	printf(" %d.%d.%d", entry->busno,
185 	    (int)((entry->prt.Address & 0xffff0000) >> 16),
186 	    (int)entry->prt.Pin);
187 
188 	printf("\n");
189 }
190 
191 static ACPI_STATUS
192 acpi_pci_link_get_object_status(ACPI_HANDLE handle, UINT32 *sta)
193 {
194 	ACPI_DEVICE_INFO	*devinfo;
195 	ACPI_BUFFER		buf;
196 	ACPI_STATUS		error;
197 
198 	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
199 
200 	if (handle == NULL || sta == NULL) {
201 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
202 		    "invalid argument\n"));
203 		return_ACPI_STATUS (AE_BAD_PARAMETER);
204 	}
205 
206 	buf.Pointer = NULL;
207 	buf.Length = ACPI_ALLOCATE_BUFFER;
208 	error = AcpiGetObjectInfo(handle, &buf);
209 	if (ACPI_FAILURE(error)) {
210 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
211 		    "couldn't get object info %s - %s\n",
212 		    acpi_name(handle), AcpiFormatException(error)));
213 		return_ACPI_STATUS (error);
214 	}
215 	devinfo = (ACPI_DEVICE_INFO *)buf.Pointer;
216 
217 	if ((devinfo->Valid & ACPI_VALID_HID) == 0 ||
218 	    strcmp(devinfo->HardwareId.Value, "PNP0C0F") != 0) {
219 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "invalid hardware ID - %s\n",
220 		    acpi_name(handle)));
221 		AcpiOsFree(buf.Pointer);
222 		return_ACPI_STATUS (AE_TYPE);
223 	}
224 
225 	if ((devinfo->Valid & ACPI_VALID_STA) != 0) {
226 		*sta = devinfo->CurrentStatus;
227 	} else {
228 		ACPI_DEBUG_PRINT((ACPI_DB_WARN, "invalid status - %s\n",
229 		    acpi_name(handle)));
230 		*sta = 0;
231 	}
232 
233 	AcpiOsFree(buf.Pointer);
234 	return_ACPI_STATUS (AE_OK);
235 }
236 
237 static ACPI_STATUS
238 acpi_pci_link_get_irq_resources(ACPI_RESOURCE *resources,
239     UINT8 *number_of_interrupts, UINT8 interrupts[])
240 {
241 	UINT8			count;
242 	UINT8			i;
243 	UINT32			NumberOfInterrupts;
244 	UINT32			*Interrupts;
245 
246 	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
247 
248 	if (resources == NULL || number_of_interrupts == NULL) {
249 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "invalid argument\n"));
250 		return_ACPI_STATUS (AE_BAD_PARAMETER);
251 	}
252 
253 	*number_of_interrupts = 0;
254 	NumberOfInterrupts = 0;
255 	Interrupts = NULL;
256 
257 	if (resources->Id == ACPI_RSTYPE_START_DPF)
258 		resources = ACPI_NEXT_RESOURCE(resources);
259 
260 	if (resources->Id != ACPI_RSTYPE_IRQ &&
261 	    resources->Id != ACPI_RSTYPE_EXT_IRQ) {
262 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
263 		    "Resource is not an IRQ entry - %d\n", resources->Id));
264 		return_ACPI_STATUS (AE_TYPE);
265 	}
266 
267 	switch (resources->Id) {
268 	case ACPI_RSTYPE_IRQ:
269 		NumberOfInterrupts = resources->Data.Irq.NumberOfInterrupts;
270 		Interrupts = resources->Data.Irq.Interrupts;
271 		break;
272 
273 	case ACPI_RSTYPE_EXT_IRQ:
274                 NumberOfInterrupts = resources->Data.ExtendedIrq.NumberOfInterrupts;
275                 Interrupts = resources->Data.ExtendedIrq.Interrupts;
276 		break;
277 	}
278 
279 	if (NumberOfInterrupts == 0) {
280 		ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Blank IRQ resource\n"));
281 		return_ACPI_STATUS (AE_NULL_ENTRY);
282 	}
283 
284 	count = 0;
285 	for (i = 0; i < NumberOfInterrupts; i++) {
286 		if (i >= MAX_POSSIBLE_INTERRUPTS) {
287 			ACPI_DEBUG_PRINT((ACPI_DB_WARN, "too many IRQs %d\n", i));
288 			break;
289 		}
290 
291 		if (Interrupts[i] == 0) {
292 			ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid IRQ %d\n",
293 			    Interrupts[i]));
294 			continue;
295 		}
296 		interrupts[count] = Interrupts[i];
297 		count++;
298 	}
299 	*number_of_interrupts = count;
300 
301 	return_ACPI_STATUS (AE_OK);
302 }
303 
304 static ACPI_STATUS
305 acpi_pci_link_get_current_irq(struct acpi_pci_link_entry *link, UINT8 *irq)
306 {
307 	ACPI_STATUS		error;
308 	ACPI_BUFFER		buf;
309 	ACPI_RESOURCE		*resources;
310 	UINT8			number_of_interrupts;
311 	UINT8			interrupts[MAX_POSSIBLE_INTERRUPTS];;
312 
313 	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
314 
315 	if (link == NULL || irq == NULL) {
316 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "invalid argument\n"));
317 		return_ACPI_STATUS (AE_BAD_PARAMETER);
318 	}
319 
320 	*irq = 0;
321 	buf.Pointer = NULL;
322 	buf.Length = ACPI_ALLOCATE_BUFFER;
323 	error = AcpiGetCurrentResources(link->handle, &buf);
324 	if (ACPI_FAILURE(error)) {
325 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
326 		    "couldn't get PCI interrupt link device _CRS %s - %s\n",
327 		    acpi_name(link->handle), AcpiFormatException(error)));
328 		return_ACPI_STATUS (error);
329 	}
330 	if (buf.Pointer == NULL) {
331 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
332 		    "couldn't allocate memory - %s\n",
333 		    acpi_name(link->handle)));
334 		return_ACPI_STATUS (AE_NO_MEMORY);
335 	}
336 
337 	resources = (ACPI_RESOURCE *) buf.Pointer;
338 
339 	number_of_interrupts = 0;
340 	bzero(interrupts, sizeof(interrupts));
341 	error = acpi_pci_link_get_irq_resources(resources,
342 		    &number_of_interrupts, interrupts);
343 	AcpiOsFree(buf.Pointer);
344 
345 	if (ACPI_FAILURE(error)) {
346 		ACPI_DEBUG_PRINT((ACPI_DB_WARN,
347 		    "couldn't get current IRQ from PCI interrupt link %s - %s\n",
348 		    acpi_name(link->handle), AcpiFormatException(error)));
349 		return_ACPI_STATUS (error);
350 	}
351 
352 	if (number_of_interrupts == 0) {
353 		ACPI_DEBUG_PRINT((ACPI_DB_WARN,
354 		    "PCI interrupt link device _CRS data is corrupted - %s\n",
355 		    acpi_name(link->handle)));
356 		return_ACPI_STATUS (AE_NULL_ENTRY);
357 	}
358 
359 	*irq = interrupts[0];
360 
361 	return_ACPI_STATUS (AE_OK);
362 }
363 
364 static ACPI_STATUS
365 acpi_pci_link_add_link(ACPI_HANDLE handle, struct acpi_prt_entry *entry)
366 {
367 	ACPI_STATUS		error;
368 	ACPI_BUFFER		buf;
369 	ACPI_RESOURCE		*resources;
370 	struct acpi_pci_link_entry *link;
371 
372 	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
373 
374 	entry->pci_link = NULL;
375 	TAILQ_FOREACH(link, &acpi_pci_link_entries, links) {
376 		if (link->handle == handle) {
377 			entry->pci_link = link;
378 			link->references++;
379 			return_ACPI_STATUS (AE_OK);
380 		}
381 	}
382 
383 	link = AcpiOsAllocate(sizeof(struct acpi_pci_link_entry));
384 	if (link == NULL) {
385 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
386 		    "couldn't allocate memory - %s\n", acpi_name(handle)));
387 		return_ACPI_STATUS (AE_NO_MEMORY);
388 	}
389 
390 	buf.Pointer = NULL;
391 	buf.Length = ACPI_ALLOCATE_BUFFER;
392 
393 	bzero(link, sizeof(struct acpi_pci_link_entry));
394 
395 	link->handle = handle;
396 
397 	error = acpi_pci_link_get_current_irq(link, &link->current_irq);
398 	if (ACPI_FAILURE(error)) {
399 		ACPI_DEBUG_PRINT((ACPI_DB_WARN,
400 		    "couldn't get current IRQ from PCI interrupt link %s - %s\n",
401 		    acpi_name(handle), AcpiFormatException(error)));
402 	}
403 
404 	link->initial_irq = link->current_irq;
405 
406 	error = AcpiGetPossibleResources(handle, &buf);
407 	if (ACPI_FAILURE(error)) {
408 		ACPI_DEBUG_PRINT((ACPI_DB_WARN,
409 		    "couldn't get PCI interrupt link device _PRS data %s - %s\n",
410 		    acpi_name(handle), AcpiFormatException(error)));
411 		goto out;
412 	}
413 
414 	if (buf.Pointer == NULL) {
415 		ACPI_DEBUG_PRINT((ACPI_DB_WARN,
416 		    "_PRS nuffer is empty - %s\n", acpi_name(handle)));
417 		error = AE_NO_MEMORY;
418 		goto out;
419 	}
420 
421 	resources = (ACPI_RESOURCE *) buf.Pointer;
422 	bcopy(resources, &link->possible_resources,
423 	    sizeof(link->possible_resources));
424 
425 	error = acpi_pci_link_get_irq_resources(resources,
426 	    &link->number_of_interrupts, link->interrupts);
427 	if (ACPI_FAILURE(error)) {
428 		ACPI_DEBUG_PRINT((ACPI_DB_WARN,
429 		    "couldn't get possible IRQs from PCI interrupt link %s - %s\n",
430 		    acpi_name(handle), AcpiFormatException(error)));
431 		goto out;
432 	}
433 
434 	if (link->number_of_interrupts == 0) {
435 		ACPI_DEBUG_PRINT((ACPI_DB_WARN,
436 		    "PCI interrupt link device _PRS data is corrupted - %s\n",
437 		    acpi_name(handle)));
438 		error = AE_NULL_ENTRY;
439 		goto out;
440 	}
441 
442 	link->references++;
443 
444 	TAILQ_INSERT_TAIL(&acpi_pci_link_entries, link, links);
445 	entry->pci_link = link;
446 
447 	error = AE_OK;
448 out:
449 	if (buf.Pointer != NULL) {
450 		AcpiOsFree(buf.Pointer);
451 	}
452 
453 	if (error != AE_OK && link != NULL) {
454 		AcpiOsFree(link);
455 	}
456 
457 	return_ACPI_STATUS (error);
458 }
459 
460 static ACPI_STATUS
461 acpi_pci_link_add_prt(device_t pcidev, ACPI_PCI_ROUTING_TABLE *prt, int busno)
462 {
463 	ACPI_HANDLE		handle;
464 	ACPI_STATUS		error;
465 	UINT32			sta;
466 	struct acpi_prt_entry	*entry;
467 
468 	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
469 
470 	if ((prt == NULL) || (prt->Source == NULL) || (prt->Source[0] == '\0')) {
471 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
472 		    "couldn't handle this routing table - hardwired\n"));
473 		return_ACPI_STATUS (AE_BAD_PARAMETER);
474 	}
475 
476 	error = AcpiGetHandle(acpi_get_handle(pcidev), prt->Source, &handle);
477 	if (ACPI_FAILURE(error)) {
478 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
479 		    "couldn't get acpi handle - %s\n",
480 		    AcpiFormatException(error)));
481 		return_ACPI_STATUS (error);
482 	}
483 
484 	error = acpi_pci_link_get_object_status(handle, &sta);
485 	if (ACPI_FAILURE(error)) {
486 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
487 		    "couldn't get object status %s - %s\n",
488 		    acpi_name(handle), AcpiFormatException(error)));
489 		return_ACPI_STATUS (error);
490 	}
491 
492 	if (!(sta & (ACPI_STA_PRESENT | ACPI_STA_FUNCTIONAL))) {
493 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
494 		    "PCI interrupt link is not functional - %s\n",
495 		    acpi_name(handle)));
496 		return_ACPI_STATUS (AE_ERROR);
497 	}
498 
499 	TAILQ_FOREACH(entry, &acpi_prt_entries, links) {
500 		if (entry->busno == busno &&
501 		    entry->prt.Address == prt->Address &&
502 		    entry->prt.Pin == prt->Pin) {
503 			ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
504 			    "PCI interrupt link entry already exists - %s\n",
505 			    acpi_name(handle)));
506 			return_ACPI_STATUS (AE_ALREADY_EXISTS);
507 		}
508 	}
509 
510 	entry = AcpiOsAllocate(sizeof(struct acpi_prt_entry));
511 	if (entry == NULL) {
512 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
513 		    "couldn't allocate memory - %s\n", acpi_name(handle)));
514 		return_ACPI_STATUS (AE_NO_MEMORY);
515 	}
516 
517 	bzero(entry, sizeof(struct acpi_prt_entry));
518 
519 	entry->pcidev = pcidev;
520 	entry->busno = busno;
521 	bcopy(prt, &entry->prt, sizeof(entry->prt));
522 
523 	error = acpi_pci_link_add_link(handle, entry);
524 	if (ACPI_FAILURE(error)) {
525 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
526 		    "couldn't add prt entry to pci link %s - %s\n",
527 		    acpi_name(handle), AcpiFormatException(error)));
528 		goto out;
529 	}
530 
531 	TAILQ_INSERT_TAIL(&acpi_prt_entries, entry, links);
532 	error = AE_OK;
533 
534 out:
535 	if (error != AE_OK && entry != NULL) {
536 		AcpiOsFree(entry);
537 	}
538 
539 	return_ACPI_STATUS (error);
540 }
541 
542 static int
543 acpi_pci_link_is_valid_irq(struct acpi_pci_link_entry *link, UINT8 irq)
544 {
545 	UINT8			i;
546 
547 	if (irq == 0) {
548 		return (0);
549 	}
550 
551 	for (i = 0; i < link->number_of_interrupts; i++) {
552 		if (link->interrupts[i] == irq) {
553 			return (1);
554 		}
555 	}
556 
557 	/* allow initial IRQ as valid one. */
558 	if (link->initial_irq == irq) {
559 		return (1);
560 	}
561 
562 	return (0);
563 }
564 
565 static ACPI_STATUS
566 acpi_pci_link_set_irq(struct acpi_pci_link_entry *link, UINT8 irq)
567 {
568 	ACPI_STATUS		error;
569 	ACPI_RESOURCE		resbuf;
570 	ACPI_BUFFER		crsbuf;
571 	UINT32			sta;
572 
573 	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
574 
575 	if (!acpi_pci_link_is_valid_irq(link, irq)) {
576 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
577 		    "couldn't set invalid IRQ %d - %s\n", irq,
578 		    acpi_name(link->handle)));
579 		return_ACPI_STATUS (AE_BAD_PARAMETER);
580 	}
581 
582 	error = acpi_pci_link_get_current_irq(link, &link->current_irq);
583 	if (ACPI_FAILURE(error)) {
584 		ACPI_DEBUG_PRINT((ACPI_DB_WARN,
585 		    "couldn't get current IRQ from PCI interrupt link %s - %s\n",
586 		    acpi_name(link->handle), AcpiFormatException(error)));
587 	}
588 
589 	if (link->current_irq == irq) {
590 		return_ACPI_STATUS (AE_OK);
591 	}
592 
593 	bzero(&resbuf, sizeof(resbuf));
594 	crsbuf.Pointer = NULL;
595 
596 	switch (link->possible_resources.Id) {
597 	default:
598 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
599 		    "Resource is not an IRQ entry %s - %d\n",
600 		    acpi_name(link->handle), link->possible_resources.Id));
601 		return_ACPI_STATUS (AE_TYPE);
602 
603 	case ACPI_RSTYPE_IRQ:
604 		resbuf.Id = ACPI_RSTYPE_IRQ;
605 		resbuf.Length = ACPI_SIZEOF_RESOURCE(ACPI_RESOURCE_IRQ);
606 
607 		/* structure copy other fields */
608 		resbuf.Data.Irq = link->possible_resources.Data.Irq;
609 		resbuf.Data.Irq.NumberOfInterrupts = 1;
610 		resbuf.Data.Irq.Interrupts[0] = irq;
611 		break;
612 
613 	case ACPI_RSTYPE_EXT_IRQ:
614 		resbuf.Id = ACPI_RSTYPE_EXT_IRQ;
615 		resbuf.Length = ACPI_SIZEOF_RESOURCE(ACPI_RESOURCE_EXT_IRQ);
616 
617 		/* structure copy other fields */
618 		resbuf.Data.ExtendedIrq = link->possible_resources.Data.ExtendedIrq;
619 		resbuf.Data.ExtendedIrq.NumberOfInterrupts = 1;
620 		resbuf.Data.ExtendedIrq.Interrupts[0] = irq;
621 		break;
622 	}
623 
624 	error = acpi_AppendBufferResource(&crsbuf, &resbuf);
625 	if (ACPI_FAILURE(error)) {
626 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
627 		    "couldn't setup buffer by acpi_AppendBufferResource - %s\n",
628 		    acpi_name(link->handle)));
629 		return_ACPI_STATUS (error);
630 	}
631 
632 	if (crsbuf.Pointer == NULL) {
633 		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
634 		    "buffer setup by acpi_AppendBufferResource is corrupted - %s\n",
635 		    acpi_name(link->handle)));
636 		return_ACPI_STATUS (AE_NO_MEMORY);
637 	}
638 
639 	error = AcpiSetCurrentResources(link->handle, &crsbuf);
640 	if (ACPI_FAILURE(error)) {
641 		ACPI_DEBUG_PRINT((ACPI_DB_WARN,
642 		    "couldn't set PCI interrupt link device _SRS %s - %s\n",
643 		    acpi_name(link->handle), AcpiFormatException(error)));
644 		return_ACPI_STATUS (error);
645 	}
646 
647 	AcpiOsFree(crsbuf.Pointer);
648 	link->current_irq = 0;
649 
650 	error = acpi_pci_link_get_object_status(link->handle, &sta);
651 	if (ACPI_FAILURE(error)) {
652 		ACPI_DEBUG_PRINT((ACPI_DB_WARN,
653 		    "couldn't get object status %s - %s\n",
654 		    acpi_name(link->handle), AcpiFormatException(error)));
655 		return_ACPI_STATUS (error);
656 	}
657 
658 	if (!(sta & ACPI_STA_ENABLE)) {
659 		ACPI_DEBUG_PRINT((ACPI_DB_WARN,
660 		    "PCI interrupt link is disabled - %s\n",
661 		    acpi_name(link->handle)));
662 		return_ACPI_STATUS (AE_ERROR);
663 	}
664 
665 	error = acpi_pci_link_get_current_irq(link, &link->current_irq);
666 	if (ACPI_FAILURE(error)) {
667 		ACPI_DEBUG_PRINT((ACPI_DB_WARN,
668 		    "couldn't get current IRQ from PCI interrupt link %s - %s\n",
669 		    acpi_name(link->handle), AcpiFormatException(error)));
670 		return_ACPI_STATUS (error);
671 	}
672 
673 	if (link->current_irq == irq) {
674 		error = AE_OK;
675 	} else {
676 		ACPI_DEBUG_PRINT((ACPI_DB_WARN,
677 		    "couldn't set IRQ %d to PCI interrupt link %d - %s\n",
678 		    irq, link->current_irq, acpi_name(link->handle)));
679 
680 		link->current_irq = 0;
681 		error = AE_ERROR;
682 	}
683 
684 	return_ACPI_STATUS (error);
685 }
686 
687 /*
688  * Auto arbitration for boot-disabled devices
689  */
690 
691 static void
692 acpi_pci_link_bootdisabled_dump(void)
693 
694 {
695 	int			i;
696 	int			irq;
697 	struct acpi_pci_link_entry *link;
698 
699 	TAILQ_FOREACH(link, &acpi_pci_link_entries, links) {
700 		/* boot-disabled link only. */
701 		if (link->current_irq != 0) {
702 			continue;
703 		}
704 
705 		printf("%s:\n", acpi_name(link->handle));
706 		printf("	interrupts:	");
707 		for (i = 0; i < link->number_of_interrupts; i++) {
708 			irq = link->sorted_irq[i];
709 			printf("%6d", irq);
710 		}
711 		printf("\n");
712 		printf("	penalty:	");
713 		for (i = 0; i < link->number_of_interrupts; i++) {
714 			irq = link->sorted_irq[i];
715 			printf("%6d", irq_penalty[irq]);
716 		}
717 		printf("\n");
718 		printf("	references:	%d\n", link->references);
719 		printf("	priority:	%d\n", link->priority);
720 	}
721 }
722 
723 static void
724 acpi_pci_link_init_irq_penalty(void)
725 {
726 	int			irq;
727 
728 	bzero(irq_penalty, sizeof(irq_penalty));
729 	for (irq = 0; irq < MAX_ISA_INTERRUPTS; irq++) {
730 		/* 0, 1, 2, 8:	timer, keyboard, cascade */
731 		if (irq == 0 || irq == 1 || irq == 2 || irq == 8) {
732 			irq_penalty[irq] = 100000;
733 			continue;
734 		}
735 
736 		/* 13, 14, 15:	npx, ATA controllers */
737 		if (irq == 13 || irq == 14 || irq == 15) {
738 			irq_penalty[irq] = 10000;
739 			continue;
740 		}
741 
742 		/* 3,4,6,7,12:	typicially used by legacy hardware */
743 		if (irq == 3 || irq == 4 || irq == 6 || irq == 7 || irq == 12) {
744 			irq_penalty[irq] = 1000;
745 			continue;
746 		}
747 	}
748 }
749 
750 static int
751 acpi_pci_link_is_irq_exclusive(ACPI_RESOURCE *res)
752 {
753 	if (res == NULL) {
754 		return (0);
755 	}
756 
757 	if (res->Id != ACPI_RSTYPE_IRQ &&
758 	    res->Id != ACPI_RSTYPE_EXT_IRQ) {
759 		return (0);
760 	}
761 
762 	if (res->Id == ACPI_RSTYPE_IRQ &&
763 	    res->Data.Irq.SharedExclusive == ACPI_EXCLUSIVE) {
764 		return (1);
765 	}
766 
767 	if (res->Id == ACPI_RSTYPE_EXT_IRQ &&
768 	    res->Data.ExtendedIrq.SharedExclusive == ACPI_EXCLUSIVE) {
769 		return (1);
770 	}
771 
772 	return (0);
773 }
774 
775 static void
776 acpi_pci_link_update_irq_penalty(device_t dev, int busno)
777 {
778 	int			i;
779 	int			irq;
780 	int			rid;
781 	struct resource		*res;
782 	struct acpi_prt_entry	*entry;
783 	struct acpi_pci_link_entry *link;
784 
785 	TAILQ_FOREACH(entry, &acpi_prt_entries, links) {
786 		if (entry->busno != busno) {
787 			continue;
788 		}
789 
790 		link = entry->pci_link;
791 		if (link == NULL) {
792 			continue;	/* impossible... */
793 		}
794 
795 		if (link->current_irq != 0) {
796 			/* not boot-disabled link, we will use this IRQ. */
797 			irq_penalty[link->current_irq] += 100;
798 			continue;
799 		}
800 
801 		/* boot-disabled link */
802 		for (i = 0; i < link->number_of_interrupts; i++) {
803 			/* give 10 for each possible IRQs. */
804 			irq = link->interrupts[i];
805 			irq_penalty[irq] += 10;
806 
807 			/* higher penalty if exclusive. */
808 			if (acpi_pci_link_is_irq_exclusive(&link->possible_resources)) {
809 				irq_penalty[irq] += 100;
810 			}
811 
812 			/* XXX try to get this IRQ in non-sharable mode. */
813 			rid = 0;
814 			res = bus_alloc_resource(dev, SYS_RES_IRQ,
815 						 &rid, irq, irq, 1, 0);
816 			if (res != NULL) {
817 				bus_release_resource(dev, SYS_RES_IRQ,
818 				    rid, res);
819 			} else {
820 				/* this is in use, give 100. */
821 				irq_penalty[irq] += 100;
822 			}
823 		}
824 
825 		/* initialize `sorted' possible IRQs. */
826 		bcopy(link->interrupts, link->sorted_irq,
827 		    sizeof(link->sorted_irq));
828 	}
829 }
830 
831 static void
832 acpi_pci_link_set_bootdisabled_priority(void)
833 {
834 	int			sum_penalty;
835 	int			i;
836 	int			irq;
837 	struct acpi_pci_link_entry *link, *link_pri;
838 	TAILQ_HEAD(, acpi_pci_link_entry) sorted_list;
839 
840 	if (bootverbose) {
841 		printf("---- before setting priority for links ------------\n");
842 		acpi_pci_link_bootdisabled_dump();
843 	}
844 
845 	/* reset priority for all links. */
846 	TAILQ_FOREACH(link, &acpi_pci_link_entries, links) {
847 		link->priority = 0;
848 	}
849 
850 	TAILQ_FOREACH(link, &acpi_pci_link_entries, links) {
851 		/* not boot-disabled link, give no chance to be arbitrated. */
852 		if (link->current_irq != 0) {
853 			link->priority = 0;
854 			continue;
855 		}
856 
857 		/*
858 		 * Calculate the priority for each boot-disabled links.
859 		 * o IRQ penalty indicates difficulty to use.
860 		 * o #references for devices indicates importance of the link.
861 		 * o #interrupts indicates flexibility of the link.
862 		 */
863 		sum_penalty = 0;
864 		for (i = 0; i < link->number_of_interrupts; i++) {
865 			irq = link->interrupts[i];
866 			sum_penalty += irq_penalty[irq];
867 		}
868 
869 		link->priority = (sum_penalty * link->references) / link->number_of_interrupts;
870 	}
871 
872 	/*
873 	 * Sort PCI links based on the priority.
874 	 * XXX Any other better ways rather than using work list?
875 	 */
876 	TAILQ_INIT(&sorted_list);
877 	while (!TAILQ_EMPTY(&acpi_pci_link_entries)) {
878 		link = TAILQ_FIRST(&acpi_pci_link_entries);
879 		/* find an entry which has the highest priority. */
880 		TAILQ_FOREACH(link_pri, &acpi_pci_link_entries, links) {
881 			if (link->priority < link_pri->priority) {
882 				link = link_pri;
883 			}
884 		}
885 		/* move to work list. */
886 		TAILQ_REMOVE(&acpi_pci_link_entries, link, links);
887 		TAILQ_INSERT_TAIL(&sorted_list, link, links);
888 	}
889 
890 	while (!TAILQ_EMPTY(&sorted_list)) {
891 		/* move them back to the list, one by one... */
892 		link = TAILQ_FIRST(&sorted_list);
893 		TAILQ_REMOVE(&sorted_list, link, links);
894 		TAILQ_INSERT_TAIL(&acpi_pci_link_entries, link, links);
895 	}
896 }
897 
898 static void
899 acpi_pci_link_fixup_bootdisabled_link(void)
900 {
901 	int			i, j;
902 	int			irq1, irq2;
903 	struct acpi_pci_link_entry *link;
904 	ACPI_STATUS		error;
905 
906 	if (bootverbose) {
907 		printf("---- before fixup boot-disabled links -------------\n");
908 		acpi_pci_link_bootdisabled_dump();
909 	}
910 
911 	TAILQ_FOREACH(link, &acpi_pci_link_entries, links) {
912 		/* ignore non boot-disabled links. */
913 		if (link->current_irq != 0) {
914 			continue;
915 		}
916 
917 		/* sort IRQs based on their penalty descending. */
918 		for (i = 0; i < link->number_of_interrupts; i++) {
919 			irq1 = link->sorted_irq[i];
920 			for (j = i + 1; j < link->number_of_interrupts; j++) {
921 				irq2 = link->sorted_irq[j];
922 				if (irq_penalty[irq1] < irq_penalty[irq2]) {
923 					continue;
924 				}
925 				link->sorted_irq[i] = irq2;
926 				link->sorted_irq[j] = irq1;
927 				irq1 = irq2;
928 			}
929 		}
930 
931 		/* try with lower penalty IRQ. */
932 		for (i = 0; i < link->number_of_interrupts; i++) {
933 			irq1 = link->sorted_irq[i];
934 			error = acpi_pci_link_set_irq(link, irq1);
935 			if (error == AE_OK) {
936 				/* OK, we use this.  give another penalty. */
937 				irq_penalty[irq1] += 100 * link->references;
938 				break;
939 			}
940 			/* NG, try next IRQ... */
941 		}
942 	}
943 
944 	if (bootverbose) {
945 		printf("---- after fixup boot-disabled links --------------\n");
946 		acpi_pci_link_bootdisabled_dump();
947 	}
948 }
949 
950 /*
951  * Public interface
952  */
953 
954 int
955 acpi_pci_link_config(device_t dev, ACPI_BUFFER *prtbuf, int busno)
956 {
957 	struct acpi_prt_entry	*entry;
958 	ACPI_PCI_ROUTING_TABLE	*prt;
959 	u_int8_t		*prtp;
960 	ACPI_STATUS		error;
961 	static int		first_time =1;
962 
963 	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
964 
965 	if (acpi_disabled("pci_link")) {
966 		return (0);
967 	}
968 
969 	if (first_time) {
970 		TAILQ_INIT(&acpi_prt_entries);
971 		TAILQ_INIT(&acpi_pci_link_entries);
972 		acpi_pci_link_init_irq_penalty();
973 		first_time = 0;
974 	}
975 
976 	if (prtbuf == NULL) {
977 		return (-1);
978 	}
979 
980 	prtp = prtbuf->Pointer;
981 	if (prtp == NULL) {		/* didn't get routing table */
982 		return (-1);
983 	}
984 
985 	/* scan the PCI Routing Table */
986 	for (;;) {
987 		prt = (ACPI_PCI_ROUTING_TABLE *)prtp;
988 
989 		if (prt->Length == 0)	/* end of table */
990 		    break;
991 
992 		error = acpi_pci_link_add_prt(dev, prt, busno);
993 		if (ACPI_FAILURE(error)) {
994 			ACPI_DEBUG_PRINT((ACPI_DB_WARN,
995 			    "couldn't add PCI interrupt link entry - %s\n",
996 			    AcpiFormatException(error)));
997 		}
998 
999 		/* skip to next entry */
1000 		prtp += prt->Length;
1001 	}
1002 
1003 	if (bootverbose) {
1004 		printf("---- initial configuration ------------------------\n");
1005 		TAILQ_FOREACH(entry, &acpi_prt_entries, links) {
1006 			if (entry->busno != busno) {
1007 				continue;
1008 			}
1009 
1010 			acpi_pci_link_entry_dump(entry);
1011 		}
1012 	}
1013 
1014 	/* manual configuration. */
1015 	TAILQ_FOREACH(entry, &acpi_prt_entries, links) {
1016 		int			irq;
1017 		char			prthint[32];
1018 
1019 		if (entry->busno != busno) {
1020 			continue;
1021 		}
1022 
1023 		snprintf(prthint, sizeof(prthint),
1024 		    "hw.acpi.pci.link.%d.%d.%d.irq", entry->busno,
1025 		    (int)((entry->prt.Address & 0xffff0000) >> 16),
1026 		    (int)entry->prt.Pin);
1027 
1028 		if (getenv_int(prthint, &irq) == 0)
1029 			continue;
1030 
1031 		if (acpi_pci_link_is_valid_irq(entry->pci_link, irq)) {
1032 			error = acpi_pci_link_set_irq(entry->pci_link, irq);
1033 			if (ACPI_FAILURE(error)) {
1034 				ACPI_DEBUG_PRINT((ACPI_DB_WARN,
1035 				    "couldn't set IRQ to PCI interrupt link entry %s - %s\n",
1036 				    acpi_name(entry->pci_link->handle),
1037 				    AcpiFormatException(error)));
1038 			}
1039 			continue;
1040 		}
1041 
1042 		/*
1043 		 * Do auto arbitration for this device's PCI link
1044 		 * if hint value 0 is specified.
1045 		 */
1046 		if (irq == 0) {
1047 			entry->pci_link->current_irq = 0;
1048 		}
1049 	}
1050 
1051 	/* auto arbitration */
1052 	acpi_pci_link_update_irq_penalty(dev, busno);
1053 	acpi_pci_link_set_bootdisabled_priority();
1054 	acpi_pci_link_fixup_bootdisabled_link();
1055 
1056 	if (bootverbose) {
1057 		printf("---- arbitrated configuration ---------------------\n");
1058 		TAILQ_FOREACH(entry, &acpi_prt_entries, links) {
1059 			if (entry->busno != busno) {
1060 				continue;
1061 			}
1062 
1063 			acpi_pci_link_entry_dump(entry);
1064 		}
1065 	}
1066 
1067 	return (0);
1068 }
1069 
1070 int
1071 acpi_pci_link_resume(device_t dev, ACPI_BUFFER *prtbuf, int busno)
1072 {
1073 	struct acpi_prt_entry	*entry;
1074 	ACPI_STATUS		error;
1075 
1076 	ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
1077 
1078 	if (acpi_disabled("pci_link")) {
1079 		return (0);
1080 	}
1081 
1082 	TAILQ_FOREACH(entry, &acpi_prt_entries, links) {
1083 		if (entry->pcidev != dev) {
1084 			continue;
1085 		}
1086 
1087 		error = acpi_pci_link_set_irq(entry->pci_link,
1088 			    entry->pci_link->current_irq);
1089 		if (ACPI_FAILURE(error)) {
1090 			ACPI_DEBUG_PRINT((ACPI_DB_WARN,
1091 			    "couldn't set IRQ to PCI interrupt link entry %s - %s\n",
1092 			    acpi_name(entry->pci_link->handle),
1093 			    AcpiFormatException(error)));
1094 		}
1095 	}
1096 
1097 	return (0);
1098 }
1099 
1100