[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>

authored by Rajesh Shah and committed by Greg Kroah-Hartman 8e7561cf 2f523b15

+202 -9
+202 -9
drivers/pci/hotplug/acpiphp_glue.c
··· 6 6 * Copyright (C) 2002,2003 NEC Corporation 7 7 * Copyright (C) 2003-2005 Matthew Wilcox (matthew.wilcox@hp.com) 8 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 12 * All rights reserved. 11 13 * ··· 306 304 register_slot, bridge, NULL); 307 305 308 306 /* install notify handler */ 309 - status = acpi_install_notify_handler(bridge->handle, 307 + if (bridge->type != BRIDGE_TYPE_HOST) { 308 + status = acpi_install_notify_handler(bridge->handle, 310 309 ACPI_SYSTEM_NOTIFY, 311 310 handle_hotplug_event_bridge, 312 311 bridge); 313 312 314 - if (ACPI_FAILURE(status)) { 315 - err("failed to register interrupt notify handler\n"); 313 + if (ACPI_FAILURE(status)) { 314 + err("failed to register interrupt notify handler\n"); 315 + } 316 316 } 317 317 318 318 list_add(&bridge->list, &bridge_list); ··· 824 820 return retval; 825 821 } 826 822 823 + static void program_hpp(struct pci_dev *dev, struct acpiphp_bridge *bridge) 824 + { 825 + u16 pci_cmd, pci_bctl; 826 + struct pci_dev *cdev; 827 + 828 + /* Program hpp values for this device */ 829 + if (!(dev->hdr_type == PCI_HEADER_TYPE_NORMAL || 830 + (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE && 831 + (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI))) 832 + return; 833 + pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 834 + bridge->hpp.cache_line_size); 835 + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 836 + bridge->hpp.latency_timer); 837 + pci_read_config_word(dev, PCI_COMMAND, &pci_cmd); 838 + if (bridge->hpp.enable_SERR) 839 + pci_cmd |= PCI_COMMAND_SERR; 840 + else 841 + pci_cmd &= ~PCI_COMMAND_SERR; 842 + if (bridge->hpp.enable_PERR) 843 + pci_cmd |= PCI_COMMAND_PARITY; 844 + else 845 + pci_cmd &= ~PCI_COMMAND_PARITY; 846 + pci_write_config_word(dev, PCI_COMMAND, pci_cmd); 847 + 848 + /* Program bridge control value and child devices */ 849 + if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { 850 + pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 851 + bridge->hpp.latency_timer); 852 + pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &pci_bctl); 853 + if (bridge->hpp.enable_SERR) 854 + pci_bctl |= PCI_BRIDGE_CTL_SERR; 855 + else 856 + pci_bctl &= ~PCI_BRIDGE_CTL_SERR; 857 + if (bridge->hpp.enable_PERR) 858 + pci_bctl |= PCI_BRIDGE_CTL_PARITY; 859 + else 860 + pci_bctl &= ~PCI_BRIDGE_CTL_PARITY; 861 + pci_write_config_word(dev, PCI_BRIDGE_CONTROL, pci_bctl); 862 + if (dev->subordinate) { 863 + list_for_each_entry(cdev, &dev->subordinate->devices, 864 + bus_list) 865 + program_hpp(cdev, bridge); 866 + } 867 + } 868 + } 869 + 870 + static void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus) 871 + { 872 + struct acpiphp_bridge bridge; 873 + struct pci_dev *dev; 874 + 875 + memset(&bridge, 0, sizeof(bridge)); 876 + bridge.handle = handle; 877 + decode_hpp(&bridge); 878 + list_for_each_entry(dev, &bus->devices, bus_list) 879 + program_hpp(dev, &bridge); 880 + 881 + } 882 + 883 + /* 884 + * Remove devices for which we could not assign resources, call 885 + * arch specific code to fix-up the bus 886 + */ 887 + static void acpiphp_sanitize_bus(struct pci_bus *bus) 888 + { 889 + struct pci_dev *dev; 890 + int i; 891 + unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM; 892 + 893 + list_for_each_entry(dev, &bus->devices, bus_list) { 894 + for (i=0; i<PCI_BRIDGE_RESOURCES; i++) { 895 + struct resource *res = &dev->resource[i]; 896 + if ((res->flags & type_mask) && !res->start && 897 + res->end) { 898 + /* Could not assign a required resources 899 + * for this device, remove it */ 900 + pci_remove_bus_device(dev); 901 + break; 902 + } 903 + } 904 + } 905 + } 906 + 907 + /* Program resources in newly inserted bridge */ 908 + static int acpiphp_configure_bridge (acpi_handle handle) 909 + { 910 + struct acpi_pci_id pci_id; 911 + struct pci_bus *bus; 912 + 913 + if (ACPI_FAILURE(acpi_get_pci_id(handle, &pci_id))) { 914 + err("cannot get PCI domain and bus number for bridge\n"); 915 + return -EINVAL; 916 + } 917 + bus = pci_find_bus(pci_id.segment, pci_id.bus); 918 + if (!bus) { 919 + err("cannot find bus %d:%d\n", 920 + pci_id.segment, pci_id.bus); 921 + return -EINVAL; 922 + } 923 + 924 + pci_bus_size_bridges(bus); 925 + pci_bus_assign_resources(bus); 926 + acpiphp_sanitize_bus(bus); 927 + acpiphp_set_hpp_values(handle, bus); 928 + pci_enable_bridges(bus); 929 + return 0; 930 + } 931 + 932 + static void handle_bridge_insertion(acpi_handle handle, u32 type) 933 + { 934 + struct acpi_device *device, *pdevice; 935 + acpi_handle phandle; 936 + 937 + if ((type != ACPI_NOTIFY_BUS_CHECK) && 938 + (type != ACPI_NOTIFY_DEVICE_CHECK)) { 939 + err("unexpected notification type %d\n", type); 940 + return; 941 + } 942 + 943 + acpi_get_parent(handle, &phandle); 944 + if (acpi_bus_get_device(phandle, &pdevice)) { 945 + dbg("no parent device, assuming NULL\n"); 946 + pdevice = NULL; 947 + } 948 + if (acpi_bus_add(&device, pdevice, handle, ACPI_BUS_TYPE_DEVICE)) { 949 + err("cannot add bridge to acpi list\n"); 950 + return; 951 + } 952 + if (!acpiphp_configure_bridge(handle) && 953 + !acpi_bus_start(device)) 954 + add_bridge(handle); 955 + else 956 + err("cannot configure and start bridge\n"); 957 + 958 + } 959 + 827 960 /* 828 961 * ACPI event handlers 829 962 */ ··· 981 840 char objname[64]; 982 841 struct acpi_buffer buffer = { .length = sizeof(objname), 983 842 .pointer = objname }; 843 + struct acpi_device *device; 984 844 985 - bridge = (struct acpiphp_bridge *)context; 845 + if (acpi_bus_get_device(handle, &device)) { 846 + /* This bridge must have just been physically inserted */ 847 + handle_bridge_insertion(handle, type); 848 + return; 849 + } 850 + 851 + bridge = acpiphp_handle_to_bridge(handle); 852 + if (!bridge) { 853 + err("cannot get bridge info\n"); 854 + return; 855 + } 986 856 987 857 acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); 988 858 ··· 1093 941 } 1094 942 } 1095 943 944 + static int is_root_bridge(acpi_handle handle) 945 + { 946 + acpi_status status; 947 + struct acpi_device_info *info; 948 + struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; 949 + int i; 950 + 951 + status = acpi_get_object_info(handle, &buffer); 952 + if (ACPI_SUCCESS(status)) { 953 + info = buffer.pointer; 954 + if ((info->valid & ACPI_VALID_HID) && 955 + !strcmp(PCI_ROOT_HID_STRING, 956 + info->hardware_id.value)) { 957 + acpi_os_free(buffer.pointer); 958 + return 1; 959 + } 960 + if (info->valid & ACPI_VALID_CID) { 961 + for (i=0; i < info->compatibility_id.count; i++) { 962 + if (!strcmp(PCI_ROOT_HID_STRING, 963 + info->compatibility_id.id[i].value)) { 964 + acpi_os_free(buffer.pointer); 965 + return 1; 966 + } 967 + } 968 + } 969 + } 970 + return 0; 971 + } 972 + 973 + static acpi_status 974 + find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) 975 + { 976 + int *count = (int *)context; 977 + 978 + if (is_root_bridge(handle)) { 979 + acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, 980 + handle_hotplug_event_bridge, NULL); 981 + (*count)++; 982 + } 983 + return AE_OK ; 984 + } 1096 985 1097 986 static struct acpi_pci_driver acpi_pci_hp_driver = { 1098 987 .add = add_bridge, ··· 1146 953 */ 1147 954 int __init acpiphp_glue_init(void) 1148 955 { 1149 - int num; 956 + int num = 0; 1150 957 1151 - if (list_empty(&pci_root_buses)) 1152 - return -1; 1153 - 1154 - num = acpi_pci_register_driver(&acpi_pci_hp_driver); 958 + acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, 959 + ACPI_UINT32_MAX, find_root_bridges, &num, NULL); 1155 960 1156 961 if (num <= 0) 1157 962 return -1; 963 + else 964 + acpi_pci_register_driver(&acpi_pci_hp_driver); 1158 965 1159 966 return 0; 1160 967 }