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