aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi
diff options
context:
space:
mode:
authorDavid Shaohua Li <shaohua.li@intel.com>2005-07-27 23:02:00 -0400
committerLen Brown <len.brown@intel.com>2005-07-29 22:49:38 -0400
commit87bec66b9691522414862dd8d41e430b063735ef (patch)
treef9976d7f6bb92fe3ebeda3b5d3644ac048147e62 /drivers/acpi
parent68ac767686fd72f37a25bb4895fb4ab0080ba755 (diff)
[ACPI] suspend/resume ACPI PCI Interrupt Links
Add reference count and disable ACPI PCI Interrupt Link when no device still uses it. Warn when drivers have not released Link at suspend time. http://bugzilla.kernel.org/show_bug.cgi?id=3469 Signed-off-by: David Shaohua Li <shaohua.li@intel.com> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/pci_irq.c85
-rw-r--r--drivers/acpi/pci_link.c103
2 files changed, 146 insertions, 42 deletions
diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c
index 8093f2e00321..c536ccfc5413 100644
--- a/drivers/acpi/pci_irq.c
+++ b/drivers/acpi/pci_irq.c
@@ -269,7 +269,51 @@ acpi_pci_irq_del_prt (int segment, int bus)
269/* -------------------------------------------------------------------------- 269/* --------------------------------------------------------------------------
270 PCI Interrupt Routing Support 270 PCI Interrupt Routing Support
271 -------------------------------------------------------------------------- */ 271 -------------------------------------------------------------------------- */
272typedef int (*irq_lookup_func)(struct acpi_prt_entry *, int *, int *, char **);
272 273
274static int
275acpi_pci_allocate_irq(struct acpi_prt_entry *entry,
276 int *edge_level,
277 int *active_high_low,
278 char **link)
279{
280 int irq;
281
282 ACPI_FUNCTION_TRACE("acpi_pci_allocate_irq");
283
284 if (entry->link.handle) {
285 irq = acpi_pci_link_allocate_irq(entry->link.handle,
286 entry->link.index, edge_level, active_high_low, link);
287 if (irq < 0) {
288 ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid IRQ link routing entry\n"));
289 return_VALUE(-1);
290 }
291 } else {
292 irq = entry->link.index;
293 *edge_level = ACPI_LEVEL_SENSITIVE;
294 *active_high_low = ACPI_ACTIVE_LOW;
295 }
296
297 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found IRQ %d\n", irq));
298 return_VALUE(irq);
299}
300
301static int
302acpi_pci_free_irq(struct acpi_prt_entry *entry,
303 int *edge_level,
304 int *active_high_low,
305 char **link)
306{
307 int irq;
308
309 ACPI_FUNCTION_TRACE("acpi_pci_free_irq");
310 if (entry->link.handle) {
311 irq = acpi_pci_link_free_irq(entry->link.handle);
312 } else {
313 irq = entry->link.index;
314 }
315 return_VALUE(irq);
316}
273/* 317/*
274 * acpi_pci_irq_lookup 318 * acpi_pci_irq_lookup
275 * success: return IRQ >= 0 319 * success: return IRQ >= 0
@@ -282,12 +326,13 @@ acpi_pci_irq_lookup (
282 int pin, 326 int pin,
283 int *edge_level, 327 int *edge_level,
284 int *active_high_low, 328 int *active_high_low,
285 char **link) 329 char **link,
330 irq_lookup_func func)
286{ 331{
287 struct acpi_prt_entry *entry = NULL; 332 struct acpi_prt_entry *entry = NULL;
288 int segment = pci_domain_nr(bus); 333 int segment = pci_domain_nr(bus);
289 int bus_nr = bus->number; 334 int bus_nr = bus->number;
290 int irq; 335 int ret;
291 336
292 ACPI_FUNCTION_TRACE("acpi_pci_irq_lookup"); 337 ACPI_FUNCTION_TRACE("acpi_pci_irq_lookup");
293 338
@@ -301,22 +346,8 @@ acpi_pci_irq_lookup (
301 return_VALUE(-1); 346 return_VALUE(-1);
302 } 347 }
303 348
304 if (entry->link.handle) { 349 ret = func(entry, edge_level, active_high_low, link);
305 irq = acpi_pci_link_get_irq(entry->link.handle, 350 return_VALUE(ret);
306 entry->link.index, edge_level, active_high_low, link);
307 if (irq < 0) {
308 ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid IRQ link routing entry\n"));
309 return_VALUE(-1);
310 }
311 } else {
312 irq = entry->link.index;
313 *edge_level = ACPI_LEVEL_SENSITIVE;
314 *active_high_low = ACPI_ACTIVE_LOW;
315 }
316
317 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found IRQ %d\n", irq));
318
319 return_VALUE(irq);
320} 351}
321 352
322/* 353/*
@@ -330,7 +361,8 @@ acpi_pci_irq_derive (
330 int pin, 361 int pin,
331 int *edge_level, 362 int *edge_level,
332 int *active_high_low, 363 int *active_high_low,
333 char **link) 364 char **link,
365 irq_lookup_func func)
334{ 366{
335 struct pci_dev *bridge = dev; 367 struct pci_dev *bridge = dev;
336 int irq = -1; 368 int irq = -1;
@@ -363,7 +395,7 @@ acpi_pci_irq_derive (
363 } 395 }
364 396
365 irq = acpi_pci_irq_lookup(bridge->bus, PCI_SLOT(bridge->devfn), 397 irq = acpi_pci_irq_lookup(bridge->bus, PCI_SLOT(bridge->devfn),
366 pin, edge_level, active_high_low, link); 398 pin, edge_level, active_high_low, link, func);
367 } 399 }
368 400
369 if (irq < 0) { 401 if (irq < 0) {
@@ -415,7 +447,7 @@ acpi_pci_irq_enable (
415 * values override any BIOS-assigned IRQs set during boot. 447 * values override any BIOS-assigned IRQs set during boot.
416 */ 448 */
417 irq = acpi_pci_irq_lookup(dev->bus, PCI_SLOT(dev->devfn), pin, 449 irq = acpi_pci_irq_lookup(dev->bus, PCI_SLOT(dev->devfn), pin,
418 &edge_level, &active_high_low, &link); 450 &edge_level, &active_high_low, &link, acpi_pci_allocate_irq);
419 451
420 /* 452 /*
421 * If no PRT entry was found, we'll try to derive an IRQ from the 453 * If no PRT entry was found, we'll try to derive an IRQ from the
@@ -423,7 +455,7 @@ acpi_pci_irq_enable (
423 */ 455 */
424 if (irq < 0) 456 if (irq < 0)
425 irq = acpi_pci_irq_derive(dev, pin, &edge_level, 457 irq = acpi_pci_irq_derive(dev, pin, &edge_level,
426 &active_high_low, &link); 458 &active_high_low, &link, acpi_pci_allocate_irq);
427 459
428 /* 460 /*
429 * No IRQ known to the ACPI subsystem - maybe the BIOS / 461 * No IRQ known to the ACPI subsystem - maybe the BIOS /
@@ -461,7 +493,9 @@ acpi_pci_irq_enable (
461EXPORT_SYMBOL(acpi_pci_irq_enable); 493EXPORT_SYMBOL(acpi_pci_irq_enable);
462 494
463 495
464#ifdef CONFIG_ACPI_DEALLOCATE_IRQ 496/* FIXME: implement x86/x86_64 version */
497void __attribute__((weak)) acpi_unregister_gsi(u32 i) {}
498
465void 499void
466acpi_pci_irq_disable ( 500acpi_pci_irq_disable (
467 struct pci_dev *dev) 501 struct pci_dev *dev)
@@ -488,14 +522,14 @@ acpi_pci_irq_disable (
488 * First we check the PCI IRQ routing table (PRT) for an IRQ. 522 * First we check the PCI IRQ routing table (PRT) for an IRQ.
489 */ 523 */
490 gsi = acpi_pci_irq_lookup(dev->bus, PCI_SLOT(dev->devfn), pin, 524 gsi = acpi_pci_irq_lookup(dev->bus, PCI_SLOT(dev->devfn), pin,
491 &edge_level, &active_high_low, NULL); 525 &edge_level, &active_high_low, NULL, acpi_pci_free_irq);
492 /* 526 /*
493 * If no PRT entry was found, we'll try to derive an IRQ from the 527 * If no PRT entry was found, we'll try to derive an IRQ from the
494 * device's parent bridge. 528 * device's parent bridge.
495 */ 529 */
496 if (gsi < 0) 530 if (gsi < 0)
497 gsi = acpi_pci_irq_derive(dev, pin, 531 gsi = acpi_pci_irq_derive(dev, pin,
498 &edge_level, &active_high_low, NULL); 532 &edge_level, &active_high_low, NULL, acpi_pci_free_irq);
499 if (gsi < 0) 533 if (gsi < 0)
500 return_VOID; 534 return_VOID;
501 535
@@ -511,4 +545,3 @@ acpi_pci_irq_disable (
511 545
512 return_VOID; 546 return_VOID;
513} 547}
514#endif /* CONFIG_ACPI_DEALLOCATE_IRQ */
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index 6ad0e77df9b3..6a29610edc11 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -68,6 +68,10 @@ static struct acpi_driver acpi_pci_link_driver = {
68 }, 68 },
69}; 69};
70 70
71/*
72 * If a link is initialized, we never change its active and initialized
73 * later even the link is disable. Instead, we just repick the active irq
74 */
71struct acpi_pci_link_irq { 75struct acpi_pci_link_irq {
72 u8 active; /* Current IRQ */ 76 u8 active; /* Current IRQ */
73 u8 edge_level; /* All IRQs */ 77 u8 edge_level; /* All IRQs */
@@ -76,8 +80,7 @@ struct acpi_pci_link_irq {
76 u8 possible_count; 80 u8 possible_count;
77 u8 possible[ACPI_PCI_LINK_MAX_POSSIBLE]; 81 u8 possible[ACPI_PCI_LINK_MAX_POSSIBLE];
78 u8 initialized:1; 82 u8 initialized:1;
79 u8 suspend_resume:1; 83 u8 reserved:7;
80 u8 reserved:6;
81}; 84};
82 85
83struct acpi_pci_link { 86struct acpi_pci_link {
@@ -85,12 +88,14 @@ struct acpi_pci_link {
85 struct acpi_device *device; 88 struct acpi_device *device;
86 acpi_handle handle; 89 acpi_handle handle;
87 struct acpi_pci_link_irq irq; 90 struct acpi_pci_link_irq irq;
91 int refcnt;
88}; 92};
89 93
90static struct { 94static struct {
91 int count; 95 int count;
92 struct list_head entries; 96 struct list_head entries;
93} acpi_link; 97} acpi_link;
98DECLARE_MUTEX(acpi_link_lock);
94 99
95 100
96/* -------------------------------------------------------------------------- 101/* --------------------------------------------------------------------------
@@ -532,12 +537,12 @@ static int acpi_pci_link_allocate(
532 537
533 ACPI_FUNCTION_TRACE("acpi_pci_link_allocate"); 538 ACPI_FUNCTION_TRACE("acpi_pci_link_allocate");
534 539
535 if (link->irq.suspend_resume) { 540 if (link->irq.initialized) {
536 acpi_pci_link_set(link, link->irq.active); 541 if (link->refcnt == 0)
537 link->irq.suspend_resume = 0; 542 /* This means the link is disabled but initialized */
538 } 543 acpi_pci_link_set(link, link->irq.active);
539 if (link->irq.initialized)
540 return_VALUE(0); 544 return_VALUE(0);
545 }
541 546
542 /* 547 /*
543 * search for active IRQ in list of possible IRQs. 548 * search for active IRQ in list of possible IRQs.
@@ -596,13 +601,13 @@ static int acpi_pci_link_allocate(
596} 601}
597 602
598/* 603/*
599 * acpi_pci_link_get_irq 604 * acpi_pci_link_allocate_irq
600 * success: return IRQ >= 0 605 * success: return IRQ >= 0
601 * failure: return -1 606 * failure: return -1
602 */ 607 */
603 608
604int 609int
605acpi_pci_link_get_irq ( 610acpi_pci_link_allocate_irq (
606 acpi_handle handle, 611 acpi_handle handle,
607 int index, 612 int index,
608 int *edge_level, 613 int *edge_level,
@@ -613,7 +618,7 @@ acpi_pci_link_get_irq (
613 struct acpi_device *device = NULL; 618 struct acpi_device *device = NULL;
614 struct acpi_pci_link *link = NULL; 619 struct acpi_pci_link *link = NULL;
615 620
616 ACPI_FUNCTION_TRACE("acpi_pci_link_get_irq"); 621 ACPI_FUNCTION_TRACE("acpi_pci_link_allocate_irq");
617 622
618 result = acpi_bus_get_device(handle, &device); 623 result = acpi_bus_get_device(handle, &device);
619 if (result) { 624 if (result) {
@@ -633,21 +638,70 @@ acpi_pci_link_get_irq (
633 return_VALUE(-1); 638 return_VALUE(-1);
634 } 639 }
635 640
636 if (acpi_pci_link_allocate(link)) 641 down(&acpi_link_lock);
642 if (acpi_pci_link_allocate(link)) {
643 up(&acpi_link_lock);
637 return_VALUE(-1); 644 return_VALUE(-1);
645 }
638 646
639 if (!link->irq.active) { 647 if (!link->irq.active) {
648 up(&acpi_link_lock);
640 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Link active IRQ is 0!\n")); 649 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Link active IRQ is 0!\n"));
641 return_VALUE(-1); 650 return_VALUE(-1);
642 } 651 }
652 link->refcnt ++;
653 up(&acpi_link_lock);
643 654
644 if (edge_level) *edge_level = link->irq.edge_level; 655 if (edge_level) *edge_level = link->irq.edge_level;
645 if (active_high_low) *active_high_low = link->irq.active_high_low; 656 if (active_high_low) *active_high_low = link->irq.active_high_low;
646 if (name) *name = acpi_device_bid(link->device); 657 if (name) *name = acpi_device_bid(link->device);
658 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
659 "Link %s is referenced\n", acpi_device_bid(link->device)));
647 return_VALUE(link->irq.active); 660 return_VALUE(link->irq.active);
648} 661}
649 662
663/*
664 * We don't change link's irq information here. After it is reenabled, we
665 * continue use the info
666 */
667int
668acpi_pci_link_free_irq(acpi_handle handle)
669{
670 struct acpi_device *device = NULL;
671 struct acpi_pci_link *link = NULL;
672 acpi_status result;
673
674 ACPI_FUNCTION_TRACE("acpi_pci_link_free_irq");
675
676 result = acpi_bus_get_device(handle, &device);
677 if (result) {
678 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link device\n"));
679 return_VALUE(-1);
680 }
650 681
682 link = (struct acpi_pci_link *) acpi_driver_data(device);
683 if (!link) {
684 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link context\n"));
685 return_VALUE(-1);
686 }
687
688 down(&acpi_link_lock);
689 if (!link->irq.initialized) {
690 up(&acpi_link_lock);
691 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Link isn't initialized\n"));
692 return_VALUE(-1);
693 }
694
695 link->refcnt --;
696 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
697 "Link %s is dereferenced\n", acpi_device_bid(link->device)));
698
699 if (link->refcnt == 0) {
700 acpi_ut_evaluate_object(link->handle, "_DIS", 0, NULL);
701 }
702 up(&acpi_link_lock);
703 return_VALUE(link->irq.active);
704}
651/* -------------------------------------------------------------------------- 705/* --------------------------------------------------------------------------
652 Driver Interface 706 Driver Interface
653 -------------------------------------------------------------------------- */ 707 -------------------------------------------------------------------------- */
@@ -677,6 +731,7 @@ acpi_pci_link_add (
677 strcpy(acpi_device_class(device), ACPI_PCI_LINK_CLASS); 731 strcpy(acpi_device_class(device), ACPI_PCI_LINK_CLASS);
678 acpi_driver_data(device) = link; 732 acpi_driver_data(device) = link;
679 733
734 down(&acpi_link_lock);
680 result = acpi_pci_link_get_possible(link); 735 result = acpi_pci_link_get_possible(link);
681 if (result) 736 if (result)
682 goto end; 737 goto end;
@@ -712,6 +767,7 @@ acpi_pci_link_add (
712end: 767end:
713 /* disable all links -- to be activated on use */ 768 /* disable all links -- to be activated on use */
714 acpi_ut_evaluate_object(link->handle, "_DIS", 0, NULL); 769 acpi_ut_evaluate_object(link->handle, "_DIS", 0, NULL);
770 up(&acpi_link_lock);
715 771
716 if (result) 772 if (result)
717 kfree(link); 773 kfree(link);
@@ -726,19 +782,32 @@ irqrouter_suspend(
726{ 782{
727 struct list_head *node = NULL; 783 struct list_head *node = NULL;
728 struct acpi_pci_link *link = NULL; 784 struct acpi_pci_link *link = NULL;
785 int ret = 0;
729 786
730 ACPI_FUNCTION_TRACE("irqrouter_suspend"); 787 ACPI_FUNCTION_TRACE("irqrouter_suspend");
731 788
732 list_for_each(node, &acpi_link.entries) { 789 list_for_each(node, &acpi_link.entries) {
733 link = list_entry(node, struct acpi_pci_link, node); 790 link = list_entry(node, struct acpi_pci_link, node);
734 if (!link) { 791 if (!link) {
735 ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link context\n")); 792 ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
793 "Invalid link context\n"));
736 continue; 794 continue;
737 } 795 }
738 if (link->irq.active && link->irq.initialized) 796 if (link->irq.initialized && link->refcnt != 0
739 link->irq.suspend_resume = 1; 797 /* We ignore legacy IDE device irq */
798 && link->irq.active != 14 && link->irq.active !=15) {
799 printk(KERN_WARNING PREFIX
800 "%d drivers with interrupt %d neglected to call"
801 " pci_disable_device at .suspend\n",
802 link->refcnt,
803 link->irq.active);
804 printk(KERN_WARNING PREFIX
805 "Fix the driver, or rmmod before suspend\n");
806 link->refcnt = 0;
807 ret = -EINVAL;
808 }
740 } 809 }
741 return_VALUE(0); 810 return_VALUE(ret);
742} 811}
743 812
744 813
@@ -756,8 +825,9 @@ acpi_pci_link_remove (
756 825
757 link = (struct acpi_pci_link *) acpi_driver_data(device); 826 link = (struct acpi_pci_link *) acpi_driver_data(device);
758 827
759 /* TBD: Acquire/release lock */ 828 down(&acpi_link_lock);
760 list_del(&link->node); 829 list_del(&link->node);
830 up(&acpi_link_lock);
761 831
762 kfree(link); 832 kfree(link);
763 833
@@ -849,6 +919,7 @@ int __init acpi_irq_balance_set(char *str)
849__setup("acpi_irq_balance", acpi_irq_balance_set); 919__setup("acpi_irq_balance", acpi_irq_balance_set);
850 920
851 921
922/* FIXME: we will remove this interface after all drivers call pci_disable_device */
852static struct sysdev_class irqrouter_sysdev_class = { 923static struct sysdev_class irqrouter_sysdev_class = {
853 set_kset_name("irqrouter"), 924 set_kset_name("irqrouter"),
854 .suspend = irqrouter_suspend, 925 .suspend = irqrouter_suspend,