aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/pci_root.c
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/pci_root.c
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/pci_root.c')
-rw-r--r--drivers/acpi/pci_root.c130
1 files changed, 130 insertions, 0 deletions
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}