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