aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/pci_root.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/pci_root.c')
-rw-r--r--drivers/acpi/pci_root.c124
1 files changed, 124 insertions, 0 deletions
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 471b2dcb1c67..1389811aa21b 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -673,3 +673,127 @@ int __init acpi_pci_root_init(void)
673 673
674 return 0; 674 return 0;
675} 675}
676/* Support root bridge hotplug */
677
678static void handle_root_bridge_insertion(acpi_handle handle)
679{
680 struct acpi_device *device;
681
682 if (!acpi_bus_get_device(handle, &device)) {
683 printk(KERN_DEBUG "acpi device exists...\n");
684 return;
685 }
686
687 if (acpi_bus_scan(handle))
688 printk(KERN_ERR "cannot add bridge to acpi list\n");
689}
690
691static void handle_root_bridge_removal(struct acpi_device *device)
692{
693 struct acpi_eject_event *ej_event;
694
695 ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
696 if (!ej_event) {
697 /* Inform firmware the hot-remove operation has error */
698 (void) acpi_evaluate_hotplug_ost(device->handle,
699 ACPI_NOTIFY_EJECT_REQUEST,
700 ACPI_OST_SC_NON_SPECIFIC_FAILURE,
701 NULL);
702 return;
703 }
704
705 ej_event->device = device;
706 ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;
707
708 acpi_bus_hot_remove_device(ej_event);
709}
710
711static void _handle_hotplug_event_root(struct work_struct *work)
712{
713 struct acpi_pci_root *root;
714 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER };
715 struct acpi_hp_work *hp_work;
716 acpi_handle handle;
717 u32 type;
718
719 hp_work = container_of(work, struct acpi_hp_work, work);
720 handle = hp_work->handle;
721 type = hp_work->type;
722
723 root = acpi_pci_find_root(handle);
724
725 acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
726
727 switch (type) {
728 case ACPI_NOTIFY_BUS_CHECK:
729 /* bus enumerate */
730 printk(KERN_DEBUG "%s: Bus check notify on %s\n", __func__,
731 (char *)buffer.pointer);
732 if (!root)
733 handle_root_bridge_insertion(handle);
734
735 break;
736
737 case ACPI_NOTIFY_DEVICE_CHECK:
738 /* device check */
739 printk(KERN_DEBUG "%s: Device check notify on %s\n", __func__,
740 (char *)buffer.pointer);
741 if (!root)
742 handle_root_bridge_insertion(handle);
743 break;
744
745 case ACPI_NOTIFY_EJECT_REQUEST:
746 /* request device eject */
747 printk(KERN_DEBUG "%s: Device eject notify on %s\n", __func__,
748 (char *)buffer.pointer);
749 if (root)
750 handle_root_bridge_removal(root->device);
751 break;
752 default:
753 printk(KERN_WARNING "notify_handler: unknown event type 0x%x for %s\n",
754 type, (char *)buffer.pointer);
755 break;
756 }
757
758 kfree(hp_work); /* allocated in handle_hotplug_event_bridge */
759 kfree(buffer.pointer);
760}
761
762static void handle_hotplug_event_root(acpi_handle handle, u32 type,
763 void *context)
764{
765 alloc_acpi_hp_work(handle, type, context,
766 _handle_hotplug_event_root);
767}
768
769static acpi_status __init
770find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
771{
772 char objname[64];
773 struct acpi_buffer buffer = { .length = sizeof(objname),
774 .pointer = objname };
775 int *count = (int *)context;
776
777 if (!acpi_is_root_bridge(handle))
778 return AE_OK;
779
780 (*count)++;
781
782 acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
783
784 acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
785 handle_hotplug_event_root, NULL);
786 printk(KERN_DEBUG "acpi root: %s notify handler installed\n", objname);
787
788 return AE_OK;
789}
790
791void __init acpi_pci_root_hp_init(void)
792{
793 int num = 0;
794
795 acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
796 ACPI_UINT32_MAX, find_root_bridges, NULL, &num, NULL);
797
798 printk(KERN_DEBUG "Found %d acpi root devices\n", num);
799}