1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32#include <linux/kernel.h>
33#include <linux/module.h>
34#include <linux/init.h>
35#include <linux/types.h>
36#include <linux/proc_fs.h>
37#include <linux/spinlock.h>
38#include <linux/pm.h>
39#include <linux/pci.h>
40
41#include <acpi/acpi_bus.h>
42#include <acpi/acpi_drivers.h>
43
44
45#define _COMPONENT ACPI_PCI_COMPONENT
46ACPI_MODULE_NAME ("pci_link")
47
48#define PREFIX "ACPI: "
49
50
51#define ACPI_PCI_LINK_MAX_POSSIBLE 16
52
53static int acpi_pci_link_add (struct acpi_device *device);
54static int acpi_pci_link_remove (struct acpi_device *device, int type);
55
56static struct acpi_driver acpi_pci_link_driver = {
57 .name = ACPI_PCI_LINK_DRIVER_NAME,
58 .class = ACPI_PCI_LINK_CLASS,
59 .ids = ACPI_PCI_LINK_HID,
60 .ops = {
61 .add = acpi_pci_link_add,
62 .remove = acpi_pci_link_remove,
63 },
64};
65
66struct acpi_pci_link_irq {
67 u8 active;
68 u8 edge_level;
69 u8 active_high_low;
70 u8 setonboot;
71 u8 possible_count;
72 u8 possible[ACPI_PCI_LINK_MAX_POSSIBLE];
73};
74
75struct acpi_pci_link {
76 struct list_head node;
77 struct acpi_device *device;
78 acpi_handle handle;
79 struct acpi_pci_link_irq irq;
80};
81
82static struct {
83 int count;
84 struct list_head entries;
85} acpi_link;
86
87
88
89
90
91
92static acpi_status
93acpi_pci_link_check_possible (
94 struct acpi_resource *resource,
95 void *context)
96{
97 struct acpi_pci_link *link = (struct acpi_pci_link *) context;
98 u32 i = 0;
99
100 ACPI_FUNCTION_TRACE("acpi_pci_link_check_possible");
101
102 switch (resource->id) {
103 case ACPI_RSTYPE_START_DPF:
104 return AE_OK;
105 case ACPI_RSTYPE_IRQ:
106 {
107 struct acpi_resource_irq *p = &resource->data.irq;
108 if (!p || !p->number_of_interrupts) {
109 ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Blank IRQ resource\n"));
110 return AE_OK;
111 }
112 for (i = 0; (i<p->number_of_interrupts && i<ACPI_PCI_LINK_MAX_POSSIBLE); i++) {
113 if (!p->interrupts[i]) {
114 ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid IRQ %d\n", p->interrupts[i]));
115 continue;
116 }
117 link->irq.possible[i] = p->interrupts[i];
118 link->irq.possible_count++;
119 }
120 link->irq.edge_level = p->edge_level;
121 link->irq.active_high_low = p->active_high_low;
122 break;
123 }
124 case ACPI_RSTYPE_EXT_IRQ:
125 {
126 struct acpi_resource_ext_irq *p = &resource->data.extended_irq;
127 if (!p || !p->number_of_interrupts) {
128 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
129 "Blank IRQ resource\n"));
130 return AE_OK;
131 }
132 for (i = 0; (i<p->number_of_interrupts && i<ACPI_PCI_LINK_MAX_POSSIBLE); i++) {
133 if (!p->interrupts[i]) {
134 ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid IRQ %d\n", p->interrupts[i]));
135 continue;
136 }
137 link->irq.possible[i] = p->interrupts[i];
138 link->irq.possible_count++;
139 }
140 link->irq.edge_level = p->edge_level;
141 link->irq.active_high_low = p->active_high_low;
142 break;
143 }
144 default:
145 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
146 "Resource is not an IRQ entry\n"));
147 return AE_OK;
148 }
149
150 return AE_CTRL_TERMINATE;
151}
152
153
154static int
155acpi_pci_link_get_possible (
156 struct acpi_pci_link *link)
157{
158 acpi_status status;
159
160 ACPI_FUNCTION_TRACE("acpi_pci_link_get_possible");
161
162 if (!link)
163 return_VALUE(-EINVAL);
164
165 status = acpi_walk_resources(link->handle, METHOD_NAME__PRS,
166 acpi_pci_link_check_possible, link);
167 if (ACPI_FAILURE(status)) {
168 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PRS\n"));
169 return_VALUE(-ENODEV);
170 }
171
172 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
173 "Found %d possible IRQs\n", link->irq.possible_count));
174
175 return_VALUE(0);
176}
177
178
179static acpi_status
180acpi_pci_link_check_current (
181 struct acpi_resource *resource,
182 void *context)
183{
184 int *irq = (int *) context;
185
186 ACPI_FUNCTION_TRACE("acpi_pci_link_check_current");
187
188 switch (resource->id) {
189 case ACPI_RSTYPE_IRQ:
190 {
191 struct acpi_resource_irq *p = &resource->data.irq;
192 if (!p || !p->number_of_interrupts) {
193 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
194 "Blank IRQ resource\n"));
195 return AE_OK;
196 }
197 *irq = p->interrupts[0];
198 break;
199 }
200 case ACPI_RSTYPE_EXT_IRQ:
201 {
202 struct acpi_resource_ext_irq *p = &resource->data.extended_irq;
203 if (!p || !p->number_of_interrupts) {
204 ACPI_DEBUG_PRINT((ACPI_DB_WARN,
205 "Blank IRQ resource\n"));
206 return AE_OK;
207 }
208 *irq = p->interrupts[0];
209 break;
210 }
211 default:
212 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
213 "Resource isn't an IRQ\n"));
214 return AE_OK;
215 }
216 return AE_CTRL_TERMINATE;
217}
218
219static int
220acpi_pci_link_get_current (
221 struct acpi_pci_link *link)
222{
223 int result = 0;
224 acpi_status status = AE_OK;
225 int irq = 0;
226
227 ACPI_FUNCTION_TRACE("acpi_pci_link_get_current");
228
229 if (!link || !link->handle)
230 return_VALUE(-EINVAL);
231
232 link->irq.active = 0;
233
234
235 result = acpi_bus_get_status(link->device);
236 if (result) {
237 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to read status\n"));
238 goto end;
239 }
240 if (!link->device->status.enabled) {
241 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link disabled\n"));
242 return_VALUE(0);
243 }
244
245
246
247
248
249 status = acpi_walk_resources(link->handle, METHOD_NAME__CRS,
250 acpi_pci_link_check_current, &irq);
251 if (ACPI_FAILURE(status)) {
252 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _CRS\n"));
253 result = -ENODEV;
254 goto end;
255 }
256
257 if (!irq) {
258 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "No IRQ resource found\n"));
259 result = -ENODEV;
260 goto end;
261 }
262
263
264
265
266
267
268
269 link->irq.active = irq;
270
271 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link at IRQ %d \n", link->irq.active));
272
273end:
274 return_VALUE(result);
275}
276
277static int
278acpi_pci_link_try_get_current (
279 struct acpi_pci_link *link,
280 int irq)
281{
282 int result;
283
284 ACPI_FUNCTION_TRACE("acpi_pci_link_try_get_current");
285
286 result = acpi_pci_link_get_current(link);
287 if (result && link->irq.active) {
288 return_VALUE(result);
289 }
290
291 if (!link->irq.active) {
292 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "No active IRQ resource found\n"));
293 printk(KERN_WARNING "_CRS returns NULL! Using IRQ %d for"
294 "device (%s [%s]).\n", irq,
295 acpi_device_name(link->device),
296 acpi_device_bid(link->device));
297 link->irq.active = irq;
298 }
299
300 return 0;
301}
302
303static int
304acpi_pci_link_set (
305 struct acpi_pci_link *link,
306 int irq)
307{
308 int result = 0;
309 acpi_status status = AE_OK;
310 struct {
311 struct acpi_resource res;
312 struct acpi_resource end;
313 } resource;
314 struct acpi_buffer buffer = {sizeof(resource)+1, &resource};
315 int i = 0;
316 int valid = 0;
317 int resource_type = 0;
318
319 ACPI_FUNCTION_TRACE("acpi_pci_link_set");
320
321 if (!link || !irq)
322 return_VALUE(-EINVAL);
323
324
325 if (link->irq.setonboot) {
326
327 if (irq == link->irq.active)
328 return_VALUE(0);
329
330
331 for (i=0; i<link->irq.possible_count; i++) {
332 if (irq == link->irq.possible[i])
333 valid = 1;
334 }
335 if (!valid) {
336 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Target IRQ %d invalid\n", irq));
337 return_VALUE(-EINVAL);
338 }
339 }
340
341
342
343 if (irq <= 15) {
344 resource_type = ACPI_RSTYPE_IRQ;
345 } else {
346 resource_type = ACPI_RSTYPE_EXT_IRQ;
347 }
348
349retry_programming:
350
351 memset(&resource, 0, sizeof(resource));
352
353
354
355
356 switch(resource_type) {
357 case ACPI_RSTYPE_IRQ:
358 resource.res.id = ACPI_RSTYPE_IRQ;
359 resource.res.length = sizeof(struct acpi_resource);
360 resource.res.data.irq.edge_level = link->irq.edge_level;
361 resource.res.data.irq.active_high_low = link->irq.active_high_low;
362 resource.res.data.irq.shared_exclusive = ACPI_SHARED;
363 resource.res.data.irq.number_of_interrupts = 1;
364 resource.res.data.irq.interrupts[0] = irq;
365 break;
366
367 case ACPI_RSTYPE_EXT_IRQ:
368 resource.res.id = ACPI_RSTYPE_EXT_IRQ;
369 resource.res.length = sizeof(struct acpi_resource);
370 resource.res.data.extended_irq.producer_consumer = ACPI_CONSUMER;
371 resource.res.data.extended_irq.edge_level = link->irq.edge_level;
372 resource.res.data.extended_irq.active_high_low = link->irq.active_high_low;
373 resource.res.data.extended_irq.shared_exclusive = ACPI_SHARED;
374 resource.res.data.extended_irq.number_of_interrupts = 1;
375 resource.res.data.extended_irq.interrupts[0] = irq;
376
377 break;
378 }
379 resource.end.id = ACPI_RSTYPE_END_TAG;
380
381
382 status = acpi_set_current_resources(link->handle, &buffer);
383
384
385
386 if (ACPI_FAILURE(status) && (resource_type == ACPI_RSTYPE_IRQ)) {
387 resource_type = ACPI_RSTYPE_EXT_IRQ;
388 printk(PREFIX "Retrying with extended IRQ descriptor\n");
389 goto retry_programming;
390 }
391
392
393 if (ACPI_FAILURE(status)) {
394 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _SRS\n"));
395 return_VALUE(-ENODEV);
396 }
397
398
399 result = acpi_bus_get_status(link->device);
400 if (result) {
401 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to read status\n"));
402 return_VALUE(result);
403 }
404 if (!link->device->status.enabled) {
405 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Link disabled\n"));
406 return_VALUE(-ENODEV);
407 }
408
409
410 result = acpi_pci_link_try_get_current(link, irq);
411 if (result) {
412 return_VALUE(result);
413 }
414
415 if (link->irq.active != irq) {
416 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
417 "Attempt to enable at IRQ %d resulted in IRQ %d\n",
418 irq, link->irq.active));
419 link->irq.active = 0;
420 acpi_ut_evaluate_object (link->handle, "_DIS", 0, NULL);
421 return_VALUE(-ENODEV);
422 }
423
424 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Set IRQ %d\n", link->irq.active));
425
426 return_VALUE(0);
427}
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465#define ACPI_MAX_IRQS 256
466#define ACPI_MAX_ISA_IRQ 16
467
468#define PIRQ_PENALTY_PCI_AVAILABLE (0)
469#define PIRQ_PENALTY_PCI_POSSIBLE (16*16)
470#define PIRQ_PENALTY_PCI_USING (16*16*16)
471#define PIRQ_PENALTY_ISA_TYPICAL (16*16*16*16)
472#define PIRQ_PENALTY_ISA_USED (16*16*16*16*16)
473#define PIRQ_PENALTY_ISA_ALWAYS (16*16*16*16*16*16)
474
475static int acpi_irq_penalty[ACPI_MAX_IRQS] = {
476 PIRQ_PENALTY_ISA_ALWAYS,
477 PIRQ_PENALTY_ISA_ALWAYS,
478 PIRQ_PENALTY_ISA_ALWAYS,
479 PIRQ_PENALTY_ISA_TYPICAL,
480 PIRQ_PENALTY_ISA_TYPICAL,
481 PIRQ_PENALTY_ISA_TYPICAL,
482 PIRQ_PENALTY_ISA_TYPICAL,
483 PIRQ_PENALTY_ISA_TYPICAL,
484 PIRQ_PENALTY_ISA_TYPICAL,
485 PIRQ_PENALTY_PCI_AVAILABLE,
486 PIRQ_PENALTY_PCI_AVAILABLE,
487 PIRQ_PENALTY_PCI_AVAILABLE,
488 PIRQ_PENALTY_ISA_TYPICAL,
489 PIRQ_PENALTY_ISA_USED,
490 PIRQ_PENALTY_ISA_USED,
491 PIRQ_PENALTY_ISA_USED,
492
493};
494
495int
496acpi_pci_link_check (void)
497{
498 struct list_head *node = NULL;
499 struct acpi_pci_link *link = NULL;
500 int i = 0;
501
502 ACPI_FUNCTION_TRACE("acpi_pci_link_check");
503
504
505
506
507 list_for_each(node, &acpi_link.entries) {
508
509 link = list_entry(node, struct acpi_pci_link, node);
510 if (!link) {
511 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link context\n"));
512 continue;
513 }
514
515
516
517
518
519 if (link->irq.possible_count) {
520 int penalty = PIRQ_PENALTY_PCI_POSSIBLE / link->irq.possible_count;
521
522 for (i = 0; i < link->irq.possible_count; i++) {
523 if (link->irq.possible[i] < ACPI_MAX_ISA_IRQ)
524 acpi_irq_penalty[link->irq.possible[i]] += penalty;
525 }
526
527 } else if (link->irq.active) {
528 acpi_irq_penalty[link->irq.active] += PIRQ_PENALTY_PCI_POSSIBLE;
529 }
530 }
531
532 acpi_irq_penalty[acpi_fadt.sci_int] += PIRQ_PENALTY_PCI_USING;
533
534 return_VALUE(0);
535}
536
537static int acpi_irq_balance;
538
539static int acpi_pci_link_allocate(struct acpi_pci_link* link) {
540 int irq;
541 int i;
542
543 ACPI_FUNCTION_TRACE("acpi_pci_link_allocate");
544
545 if (link->irq.setonboot)
546 return_VALUE(0);
547
548 if (link->irq.active) {
549 irq = link->irq.active;
550 } else {
551 irq = link->irq.possible[0];
552 }
553
554 if (acpi_irq_balance || !link->irq.active) {
555
556
557
558
559 for (i = (link->irq.possible_count - 1); i >= 0; i--) {
560 if (acpi_irq_penalty[irq] > acpi_irq_penalty[link->irq.possible[i]])
561 irq = link->irq.possible[i];
562 }
563 }
564
565
566 if (acpi_pci_link_set(link, irq)) {
567 printk(PREFIX "Unable to set IRQ for %s [%s] (likely buggy ACPI BIOS). Aborting ACPI-based IRQ routing. Try pci=noacpi or acpi=off\n",
568 acpi_device_name(link->device),
569 acpi_device_bid(link->device));
570 return_VALUE(-ENODEV);
571 } else {
572 acpi_irq_penalty[link->irq.active] += PIRQ_PENALTY_PCI_USING;
573 printk(PREFIX "%s [%s] enabled at IRQ %d\n",
574 acpi_device_name(link->device),
575 acpi_device_bid(link->device), link->irq.active);
576 }
577
578 link->irq.setonboot = 1;
579
580 return_VALUE(0);
581}
582
583
584int
585acpi_pci_link_get_irq (
586 acpi_handle handle,
587 int index,
588 int* edge_level,
589 int* active_high_low)
590{
591 int result = 0;
592 struct acpi_device *device = NULL;
593 struct acpi_pci_link *link = NULL;
594
595 ACPI_FUNCTION_TRACE("acpi_pci_link_get_irq");
596
597 result = acpi_bus_get_device(handle, &device);
598 if (result) {
599 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link device\n"));
600 return_VALUE(0);
601 }
602
603 link = (struct acpi_pci_link *) acpi_driver_data(device);
604 if (!link) {
605 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link context\n"));
606 return_VALUE(0);
607 }
608
609
610 if (index) {
611 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid index %d\n", index));
612 return_VALUE(0);
613 }
614
615 if (acpi_pci_link_allocate(link))
616 return_VALUE(0);
617
618 if (!link->irq.active) {
619 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Link disabled\n"));
620 return_VALUE(0);
621 }
622
623 if (edge_level) *edge_level = link->irq.edge_level;
624 if (active_high_low) *active_high_low = link->irq.active_high_low;
625 return_VALUE(link->irq.active);
626}
627
628
629
630
631
632
633static int
634acpi_pci_link_add (
635 struct acpi_device *device)
636{
637 int result = 0;
638 struct acpi_pci_link *link = NULL;
639 int i = 0;
640 int found = 0;
641
642 ACPI_FUNCTION_TRACE("acpi_pci_link_add");
643
644 if (!device)
645 return_VALUE(-EINVAL);
646
647 link = kmalloc(sizeof(struct acpi_pci_link), GFP_KERNEL);
648 if (!link)
649 return_VALUE(-ENOMEM);
650 memset(link, 0, sizeof(struct acpi_pci_link));
651
652 link->device = device;
653 link->handle = device->handle;
654 sprintf(acpi_device_name(device), "%s", ACPI_PCI_LINK_DEVICE_NAME);
655 sprintf(acpi_device_class(device), "%s", ACPI_PCI_LINK_CLASS);
656 acpi_driver_data(device) = link;
657
658 result = acpi_pci_link_get_possible(link);
659 if (result)
660 goto end;
661
662
663 acpi_pci_link_get_current(link);
664
665
666 printk(PREFIX "%s [%s] (IRQs", acpi_device_name(device),
667 acpi_device_bid(device));
668 for (i = 0; i < link->irq.possible_count; i++) {
669 if (link->irq.active == link->irq.possible[i]) {
670 printk(" *%d", link->irq.possible[i]);
671 found = 1;
672 }
673 else
674 printk(" %d", link->irq.possible[i]);
675 }
676 printk(")\n");
677
678
679
680 list_add_tail(&link->node, &acpi_link.entries);
681 acpi_link.count++;
682
683end:
684 if (result)
685 kfree(link);
686
687 return_VALUE(result);
688}
689
690
691static int
692acpi_pci_link_remove (
693 struct acpi_device *device,
694 int type)
695{
696 struct acpi_pci_link *link = NULL;
697
698 ACPI_FUNCTION_TRACE("acpi_pci_link_remove");
699
700 if (!device || !acpi_driver_data(device))
701 return_VALUE(-EINVAL);
702
703 link = (struct acpi_pci_link *) acpi_driver_data(device);
704
705
706 list_del(&link->node);
707
708 kfree(link);
709
710 return_VALUE(0);
711}
712
713
714
715
716static int __init acpi_irq_penalty_update(char *str, int used)
717{
718 int i;
719
720 for (i = 0; i < 16; i++) {
721 int retval;
722 int irq;
723
724 retval = get_option(&str,&irq);
725
726 if (!retval)
727 break;
728
729 if (irq < 0)
730 continue;
731
732 if (irq >= ACPI_MAX_IRQS)
733 continue;
734
735 if (used)
736 acpi_irq_penalty[irq] += PIRQ_PENALTY_ISA_USED;
737 else
738 acpi_irq_penalty[irq] = PIRQ_PENALTY_PCI_AVAILABLE;
739
740 if (retval != 2)
741 break;
742 }
743 return 1;
744}
745
746
747
748
749
750
751static int __init acpi_irq_isa(char *str)
752{
753 return(acpi_irq_penalty_update(str, 1));
754}
755__setup("acpi_irq_isa=", acpi_irq_isa);
756
757
758
759
760
761
762static int __init acpi_irq_pci(char *str)
763{
764 return(acpi_irq_penalty_update(str, 0));
765}
766__setup("acpi_irq_pci=", acpi_irq_pci);
767
768static int __init acpi_irq_nobalance_set(char *str)
769{
770printk("ACPI STATIC SET\n");
771 acpi_irq_balance = 0;
772 return(1);
773}
774__setup("acpi_irq_nobalance", acpi_irq_nobalance_set);
775
776int __init acpi_irq_balance_set(char *str)
777{
778printk("ACPI BALANCE SET\n");
779 acpi_irq_balance = 1;
780 return(1);
781}
782__setup("acpi_irq_balance", acpi_irq_balance_set);
783
784
785int __init
786acpi_pci_link_init (void)
787{
788 ACPI_FUNCTION_TRACE("acpi_pci_link_init");
789
790 acpi_link.count = 0;
791 INIT_LIST_HEAD(&acpi_link.entries);
792
793 if (acpi_bus_register_driver(&acpi_pci_link_driver) < 0)
794 return_VALUE(-ENODEV);
795
796 return_VALUE(0);
797}
798