aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/pci_link.c
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/pci_link.c
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/pci_link.c')
-rw-r--r--drivers/acpi/pci_link.c103
1 files changed, 87 insertions, 16 deletions
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,