aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi
diff options
context:
space:
mode:
authorBjorn Helgaas <bhelgaas@google.com>2013-01-26 19:35:58 -0500
committerBjorn Helgaas <bhelgaas@google.com>2013-01-26 19:35:58 -0500
commit939de1d69c5fb0da0cfe05a1a7c981421cf876f7 (patch)
tree3ca1c6457e1c1ae4c11adab60e94d666841983aa /drivers/acpi
parentfb455792d91469fe556b68f1baa9ff5493432be8 (diff)
parent4f535093cf8f6da8cfda7c36c2c1ecd2e9586ee4 (diff)
Merge branch 'pci/yinghai-root-bus-hotplug' into next
* pci/yinghai-root-bus-hotplug: PCI: Put pci_dev in device tree as early as possible PCI: Skip attaching driver in device_add() PCI: acpiphp: Keep driver loaded even if no slots found PCI/ACPI: Print info if host bridge notify handler installation fails PCI: acpiphp: Move host bridge hotplug to pci_root.c PCI/ACPI: acpiphp: Rename alloc_acpiphp_hp_work() to alloc_acpi_hp_work() PCI: Make device create/destroy logic symmetric PCI: Fix reference count leak in pci_dev_present() PCI: Set pci_dev dev_node early so IOAPIC irq_descs are allocated locally PCI: Add root bus children dev's res to fail list PCI: acpiphp: Add is_hotplug_bridge detection Conflicts: drivers/pci/pci.h
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/internal.h1
-rw-r--r--drivers/acpi/osl.c24
-rw-r--r--drivers/acpi/pci_root.c130
-rw-r--r--drivers/acpi/scan.c3
4 files changed, 156 insertions, 2 deletions
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index e050254ae143..0f24148a2b2a 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -68,6 +68,7 @@ struct acpi_ec {
68extern struct acpi_ec *first_ec; 68extern struct acpi_ec *first_ec;
69 69
70int acpi_pci_root_init(void); 70int acpi_pci_root_init(void);
71void acpi_pci_root_hp_init(void);
71int acpi_ec_init(void); 72int acpi_ec_init(void);
72int acpi_ec_ecdt_probe(void); 73int acpi_ec_ecdt_probe(void);
73int acpi_boot_ec_enable(void); 74int acpi_boot_ec_enable(void);
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 3ff267861541..59ec5f52e849 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -84,8 +84,7 @@ static acpi_osd_handler acpi_irq_handler;
84static void *acpi_irq_context; 84static void *acpi_irq_context;
85static struct workqueue_struct *kacpid_wq; 85static struct workqueue_struct *kacpid_wq;
86static struct workqueue_struct *kacpi_notify_wq; 86static struct workqueue_struct *kacpi_notify_wq;
87struct workqueue_struct *kacpi_hotplug_wq; 87static struct workqueue_struct *kacpi_hotplug_wq;
88EXPORT_SYMBOL(kacpi_hotplug_wq);
89 88
90/* 89/*
91 * This list of permanent mappings is for memory that may be accessed from 90 * This list of permanent mappings is for memory that may be accessed from
@@ -1778,3 +1777,24 @@ void acpi_os_set_prepare_sleep(int (*func)(u8 sleep_state,
1778{ 1777{
1779 __acpi_os_prepare_sleep = func; 1778 __acpi_os_prepare_sleep = func;
1780} 1779}
1780
1781void alloc_acpi_hp_work(acpi_handle handle, u32 type, void *context,
1782 void (*func)(struct work_struct *work))
1783{
1784 struct acpi_hp_work *hp_work;
1785 int ret;
1786
1787 hp_work = kmalloc(sizeof(*hp_work), GFP_KERNEL);
1788 if (!hp_work)
1789 return;
1790
1791 hp_work->handle = handle;
1792 hp_work->type = type;
1793 hp_work->context = context;
1794
1795 INIT_WORK(&hp_work->work, func);
1796 ret = queue_work(kacpi_hotplug_wq, &hp_work->work);
1797 if (!ret)
1798 kfree(hp_work);
1799}
1800EXPORT_SYMBOL_GPL(alloc_acpi_hp_work);
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index bf5108ad4d63..417487a201fb 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -655,3 +655,133 @@ int __init acpi_pci_root_init(void)
655 655
656 return 0; 656 return 0;
657} 657}
658/* Support root bridge hotplug */
659
660static void handle_root_bridge_insertion(acpi_handle handle)
661{
662 struct acpi_device *device;
663
664 if (!acpi_bus_get_device(handle, &device)) {
665 printk(KERN_DEBUG "acpi device exists...\n");
666 return;
667 }
668
669 if (acpi_bus_scan(handle))
670 printk(KERN_ERR "cannot add bridge to acpi list\n");
671}
672
673static void handle_root_bridge_removal(struct acpi_device *device)
674{
675 struct acpi_eject_event *ej_event;
676
677 ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
678 if (!ej_event) {
679 /* Inform firmware the hot-remove operation has error */
680 (void) acpi_evaluate_hotplug_ost(device->handle,
681 ACPI_NOTIFY_EJECT_REQUEST,
682 ACPI_OST_SC_NON_SPECIFIC_FAILURE,
683 NULL);
684 return;
685 }
686
687 ej_event->device = device;
688 ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;
689
690 acpi_bus_hot_remove_device(ej_event);
691}
692
693static void _handle_hotplug_event_root(struct work_struct *work)
694{
695 struct acpi_pci_root *root;
696 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER };
697 struct acpi_hp_work *hp_work;
698 acpi_handle handle;
699 u32 type;
700
701 hp_work = container_of(work, struct acpi_hp_work, work);
702 handle = hp_work->handle;
703 type = hp_work->type;
704
705 root = acpi_pci_find_root(handle);
706
707 acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
708
709 switch (type) {
710 case ACPI_NOTIFY_BUS_CHECK:
711 /* bus enumerate */
712 printk(KERN_DEBUG "%s: Bus check notify on %s\n", __func__,
713 (char *)buffer.pointer);
714 if (!root)
715 handle_root_bridge_insertion(handle);
716
717 break;
718
719 case ACPI_NOTIFY_DEVICE_CHECK:
720 /* device check */
721 printk(KERN_DEBUG "%s: Device check notify on %s\n", __func__,
722 (char *)buffer.pointer);
723 if (!root)
724 handle_root_bridge_insertion(handle);
725 break;
726
727 case ACPI_NOTIFY_EJECT_REQUEST:
728 /* request device eject */
729 printk(KERN_DEBUG "%s: Device eject notify on %s\n", __func__,
730 (char *)buffer.pointer);
731 if (root)
732 handle_root_bridge_removal(root->device);
733 break;
734 default:
735 printk(KERN_WARNING "notify_handler: unknown event type 0x%x for %s\n",
736 type, (char *)buffer.pointer);
737 break;
738 }
739
740 kfree(hp_work); /* allocated in handle_hotplug_event_bridge */
741 kfree(buffer.pointer);
742}
743
744static void handle_hotplug_event_root(acpi_handle handle, u32 type,
745 void *context)
746{
747 alloc_acpi_hp_work(handle, type, context,
748 _handle_hotplug_event_root);
749}
750
751static acpi_status __init
752find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
753{
754 acpi_status status;
755 char objname[64];
756 struct acpi_buffer buffer = { .length = sizeof(objname),
757 .pointer = objname };
758 int *count = (int *)context;
759
760 if (!acpi_is_root_bridge(handle))
761 return AE_OK;
762
763 (*count)++;
764
765 acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
766
767 status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
768 handle_hotplug_event_root, NULL);
769 if (ACPI_FAILURE(status))
770 printk(KERN_DEBUG "acpi root: %s notify handler is not installed, exit status: %u\n",
771 objname, (unsigned int)status);
772 else
773 printk(KERN_DEBUG "acpi root: %s notify handler is installed\n",
774 objname);
775
776 return AE_OK;
777}
778
779void __init acpi_pci_root_hp_init(void)
780{
781 int num = 0;
782
783 acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
784 ACPI_UINT32_MAX, find_root_bridges, NULL, &num, NULL);
785
786 printk(KERN_DEBUG "Found %d acpi root devices\n", num);
787}
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 7c43bdc36abc..bc2f33790e83 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -1706,5 +1706,8 @@ int __init acpi_scan_init(void)
1706 } 1706 }
1707 1707
1708 acpi_update_all_gpes(); 1708 acpi_update_all_gpes();
1709
1710 acpi_pci_root_hp_init();
1711
1709 return 0; 1712 return 0;
1710} 1713}