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: releng/5.2/sys/dev/acpica/acpi_pci_link.c 123654 2003-12-19 00:03:02Z njl $");
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] == NULL) {
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 UINT8 irq;
1017 char *irqstr, *op;
1018 char prthint[32];
1019
1020 if (entry->busno != busno) {
1021 continue;
1022 }
1023
1024 snprintf(prthint, sizeof(prthint),
1025 "hw.acpi.pci.link.%d.%d.%d.irq", entry->busno,
1026 (int)((entry->prt.Address & 0xffff0000) >> 16),
1027 (int)entry->prt.Pin);
1028
1029 irqstr = getenv(prthint);
1030 if (irqstr == NULL) {
1031 continue;
1032 }
1033
1034 irq = strtoul(irqstr, &op, 0);
1035 if (*op != '\0') {
1036 continue;
1037 }
1038
1039 if (acpi_pci_link_is_valid_irq(entry->pci_link, irq)) {
1040 error = acpi_pci_link_set_irq(entry->pci_link, irq);
1041 if (ACPI_FAILURE(error)) {
1042 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
1043 "couldn't set IRQ to PCI interrupt link entry %s - %s\n",
1044 acpi_name(entry->pci_link->handle),
1045 AcpiFormatException(error)));
1046 }
1047 continue;
1048 }
1049
1050 /*
1051 * Do auto arbitration for this device's PCI link
1052 * if hint value 0 is specified.
1053 */
1054 if (irq == 0) {
1055 entry->pci_link->current_irq = 0;
1056 }
1057 }
1058
1059 /* auto arbitration */
1060 acpi_pci_link_update_irq_penalty(dev, busno);
1061 acpi_pci_link_set_bootdisabled_priority();
1062 acpi_pci_link_fixup_bootdisabled_link();
1063
1064 if (bootverbose) {
1065 printf("---- arbitrated configuration ---------------------\n");
1066 TAILQ_FOREACH(entry, &acpi_prt_entries, links) {
1067 if (entry->busno != busno) {
1068 continue;
1069 }
1070
1071 acpi_pci_link_entry_dump(entry);
1072 }
1073 }
1074
1075 return (0);
1076 }
1077
1078 int
1079 acpi_pci_link_resume(device_t dev, ACPI_BUFFER *prtbuf, int busno)
1080 {
1081 struct acpi_prt_entry *entry;
1082 ACPI_STATUS error;
1083
1084 ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
1085
1086 if (acpi_disabled("pci_link")) {
1087 return (0);
1088 }
1089
1090 TAILQ_FOREACH(entry, &acpi_prt_entries, links) {
1091 if (entry->pcidev != dev) {
1092 continue;
1093 }
1094
1095 error = acpi_pci_link_set_irq(entry->pci_link,
1096 entry->pci_link->current_irq);
1097 if (ACPI_FAILURE(error)) {
1098 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
1099 "couldn't set IRQ to PCI interrupt link entry %s - %s\n",
1100 acpi_name(entry->pci_link->handle),
1101 AcpiFormatException(error)));
1102 }
1103 }
1104
1105 return (0);
1106 }
1107
Cache object: c27fe6290611e15cbbbe09573d8f2d7f
|