aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorRajesh Shah <rajesh.shah@intel.com>2005-04-28 03:25:56 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2005-06-28 00:52:43 -0400
commit8e7561cfbdf00fb1cee694cef0e825d0548aedbc (patch)
treee17b88f3200fb35ea62c7f6896cf21977d551b8a /drivers
parent2f523b15901f654a9448bbd47ebe1e783ec3195b (diff)
[PATCH] acpi hotplug: aCPI based root bridge hot-add
acpiphp changes to support acpi based root bridge hot-add. Signed-off-by: Rajesh Shah <rajesh.shah@intel.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c211
1 files changed, 202 insertions, 9 deletions
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index 1501eb26af33..a6270cc218f6 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -6,6 +6,8 @@
6 * Copyright (C) 2002,2003 NEC Corporation 6 * Copyright (C) 2002,2003 NEC Corporation
7 * Copyright (C) 2003-2005 Matthew Wilcox (matthew.wilcox@hp.com) 7 * Copyright (C) 2003-2005 Matthew Wilcox (matthew.wilcox@hp.com)
8 * Copyright (C) 2003-2005 Hewlett Packard 8 * Copyright (C) 2003-2005 Hewlett Packard
9 * Copyright (C) 2005 Rajesh Shah (rajesh.shah@intel.com)
10 * Copyright (C) 2005 Intel Corporation
9 * 11 *
10 * All rights reserved. 12 * All rights reserved.
11 * 13 *
@@ -304,13 +306,15 @@ static void init_bridge_misc(struct acpiphp_bridge *bridge)
304 register_slot, bridge, NULL); 306 register_slot, bridge, NULL);
305 307
306 /* install notify handler */ 308 /* install notify handler */
307 status = acpi_install_notify_handler(bridge->handle, 309 if (bridge->type != BRIDGE_TYPE_HOST) {
310 status = acpi_install_notify_handler(bridge->handle,
308 ACPI_SYSTEM_NOTIFY, 311 ACPI_SYSTEM_NOTIFY,
309 handle_hotplug_event_bridge, 312 handle_hotplug_event_bridge,
310 bridge); 313 bridge);
311 314
312 if (ACPI_FAILURE(status)) { 315 if (ACPI_FAILURE(status)) {
313 err("failed to register interrupt notify handler\n"); 316 err("failed to register interrupt notify handler\n");
317 }
314 } 318 }
315 319
316 list_add(&bridge->list, &bridge_list); 320 list_add(&bridge->list, &bridge_list);
@@ -820,6 +824,143 @@ static int acpiphp_check_bridge(struct acpiphp_bridge *bridge)
820 return retval; 824 return retval;
821} 825}
822 826
827static void program_hpp(struct pci_dev *dev, struct acpiphp_bridge *bridge)
828{
829 u16 pci_cmd, pci_bctl;
830 struct pci_dev *cdev;
831
832 /* Program hpp values for this device */
833 if (!(dev->hdr_type == PCI_HEADER_TYPE_NORMAL ||
834 (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE &&
835 (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI)))
836 return;
837 pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
838 bridge->hpp.cache_line_size);
839 pci_write_config_byte(dev, PCI_LATENCY_TIMER,
840 bridge->hpp.latency_timer);
841 pci_read_config_word(dev, PCI_COMMAND, &pci_cmd);
842 if (bridge->hpp.enable_SERR)
843 pci_cmd |= PCI_COMMAND_SERR;
844 else
845 pci_cmd &= ~PCI_COMMAND_SERR;
846 if (bridge->hpp.enable_PERR)
847 pci_cmd |= PCI_COMMAND_PARITY;
848 else
849 pci_cmd &= ~PCI_COMMAND_PARITY;
850 pci_write_config_word(dev, PCI_COMMAND, pci_cmd);
851
852 /* Program bridge control value and child devices */
853 if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
854 pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER,
855 bridge->hpp.latency_timer);
856 pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &pci_bctl);
857 if (bridge->hpp.enable_SERR)
858 pci_bctl |= PCI_BRIDGE_CTL_SERR;
859 else
860 pci_bctl &= ~PCI_BRIDGE_CTL_SERR;
861 if (bridge->hpp.enable_PERR)
862 pci_bctl |= PCI_BRIDGE_CTL_PARITY;
863 else
864 pci_bctl &= ~PCI_BRIDGE_CTL_PARITY;
865 pci_write_config_word(dev, PCI_BRIDGE_CONTROL, pci_bctl);
866 if (dev->subordinate) {
867 list_for_each_entry(cdev, &dev->subordinate->devices,
868 bus_list)
869 program_hpp(cdev, bridge);
870 }
871 }
872}
873
874static void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus)
875{
876 struct acpiphp_bridge bridge;
877 struct pci_dev *dev;
878
879 memset(&bridge, 0, sizeof(bridge));
880 bridge.handle = handle;
881 decode_hpp(&bridge);
882 list_for_each_entry(dev, &bus->devices, bus_list)
883 program_hpp(dev, &bridge);
884
885}
886
887/*
888 * Remove devices for which we could not assign resources, call
889 * arch specific code to fix-up the bus
890 */
891static void acpiphp_sanitize_bus(struct pci_bus *bus)
892{
893 struct pci_dev *dev;
894 int i;
895 unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM;
896
897 list_for_each_entry(dev, &bus->devices, bus_list) {
898 for (i=0; i<PCI_BRIDGE_RESOURCES; i++) {
899 struct resource *res = &dev->resource[i];
900 if ((res->flags & type_mask) && !res->start &&
901 res->end) {
902 /* Could not assign a required resources
903 * for this device, remove it */
904 pci_remove_bus_device(dev);
905 break;
906 }
907 }
908 }
909}
910
911/* Program resources in newly inserted bridge */
912static int acpiphp_configure_bridge (acpi_handle handle)
913{
914 struct acpi_pci_id pci_id;
915 struct pci_bus *bus;
916
917 if (ACPI_FAILURE(acpi_get_pci_id(handle, &pci_id))) {
918 err("cannot get PCI domain and bus number for bridge\n");
919 return -EINVAL;
920 }
921 bus = pci_find_bus(pci_id.segment, pci_id.bus);
922 if (!bus) {
923 err("cannot find bus %d:%d\n",
924 pci_id.segment, pci_id.bus);
925 return -EINVAL;
926 }
927
928 pci_bus_size_bridges(bus);
929 pci_bus_assign_resources(bus);
930 acpiphp_sanitize_bus(bus);
931 acpiphp_set_hpp_values(handle, bus);
932 pci_enable_bridges(bus);
933 return 0;
934}
935
936static void handle_bridge_insertion(acpi_handle handle, u32 type)
937{
938 struct acpi_device *device, *pdevice;
939 acpi_handle phandle;
940
941 if ((type != ACPI_NOTIFY_BUS_CHECK) &&
942 (type != ACPI_NOTIFY_DEVICE_CHECK)) {
943 err("unexpected notification type %d\n", type);
944 return;
945 }
946
947 acpi_get_parent(handle, &phandle);
948 if (acpi_bus_get_device(phandle, &pdevice)) {
949 dbg("no parent device, assuming NULL\n");
950 pdevice = NULL;
951 }
952 if (acpi_bus_add(&device, pdevice, handle, ACPI_BUS_TYPE_DEVICE)) {
953 err("cannot add bridge to acpi list\n");
954 return;
955 }
956 if (!acpiphp_configure_bridge(handle) &&
957 !acpi_bus_start(device))
958 add_bridge(handle);
959 else
960 err("cannot configure and start bridge\n");
961
962}
963
823/* 964/*
824 * ACPI event handlers 965 * ACPI event handlers
825 */ 966 */
@@ -840,8 +981,19 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont
840 char objname[64]; 981 char objname[64];
841 struct acpi_buffer buffer = { .length = sizeof(objname), 982 struct acpi_buffer buffer = { .length = sizeof(objname),
842 .pointer = objname }; 983 .pointer = objname };
984 struct acpi_device *device;
843 985
844 bridge = (struct acpiphp_bridge *)context; 986 if (acpi_bus_get_device(handle, &device)) {
987 /* This bridge must have just been physically inserted */
988 handle_bridge_insertion(handle, type);
989 return;
990 }
991
992 bridge = acpiphp_handle_to_bridge(handle);
993 if (!bridge) {
994 err("cannot get bridge info\n");
995 return;
996 }
845 997
846 acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); 998 acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
847 999
@@ -941,6 +1093,47 @@ static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *contex
941 } 1093 }
942} 1094}
943 1095
1096static int is_root_bridge(acpi_handle handle)
1097{
1098 acpi_status status;
1099 struct acpi_device_info *info;
1100 struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
1101 int i;
1102
1103 status = acpi_get_object_info(handle, &buffer);
1104 if (ACPI_SUCCESS(status)) {
1105 info = buffer.pointer;
1106 if ((info->valid & ACPI_VALID_HID) &&
1107 !strcmp(PCI_ROOT_HID_STRING,
1108 info->hardware_id.value)) {
1109 acpi_os_free(buffer.pointer);
1110 return 1;
1111 }
1112 if (info->valid & ACPI_VALID_CID) {
1113 for (i=0; i < info->compatibility_id.count; i++) {
1114 if (!strcmp(PCI_ROOT_HID_STRING,
1115 info->compatibility_id.id[i].value)) {
1116 acpi_os_free(buffer.pointer);
1117 return 1;
1118 }
1119 }
1120 }
1121 }
1122 return 0;
1123}
1124
1125static acpi_status
1126find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
1127{
1128 int *count = (int *)context;
1129
1130 if (is_root_bridge(handle)) {
1131 acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
1132 handle_hotplug_event_bridge, NULL);
1133 (*count)++;
1134 }
1135 return AE_OK ;
1136}
944 1137
945static struct acpi_pci_driver acpi_pci_hp_driver = { 1138static struct acpi_pci_driver acpi_pci_hp_driver = {
946 .add = add_bridge, 1139 .add = add_bridge,
@@ -953,15 +1146,15 @@ static struct acpi_pci_driver acpi_pci_hp_driver = {
953 */ 1146 */
954int __init acpiphp_glue_init(void) 1147int __init acpiphp_glue_init(void)
955{ 1148{
956 int num; 1149 int num = 0;
957
958 if (list_empty(&pci_root_buses))
959 return -1;
960 1150
961 num = acpi_pci_register_driver(&acpi_pci_hp_driver); 1151 acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
1152 ACPI_UINT32_MAX, find_root_bridges, &num, NULL);
962 1153
963 if (num <= 0) 1154 if (num <= 0)
964 return -1; 1155 return -1;
1156 else
1157 acpi_pci_register_driver(&acpi_pci_hp_driver);
965 1158
966 return 0; 1159 return 0;
967} 1160}