Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/pci-2.6

* master.kernel.org:/pub/scm/linux/kernel/git/gregkh/pci-2.6: (28 commits)
pciehp - fix wrong return value
IA64: PCI: dont disable irq which is not enabled
acpiphp: add support for ioapic hot-remove
PCI: assign ioapic resource at hotplug
acpiphp: disable bridges
acpiphp: stop bus device before acpi_bus_trim
PCI: add pci_stop_bus_device
acpiphp: do not initialize existing ioapics
acpiphp: initialize ioapics before starting devices
acpiphp: set hpp values before starting devices
PCI Hotplug: cleanup pcihp skeleton code.
PCI: Restore PCI Express capability registers after PM event
PCI: drivers/pci/hotplug/acpiphp_glue.c: make a function static
PCI: Multiprobe sanitizer
PCI: fix __must_check warnings
PCI Hotplug: fix __must_check warnings
SHPCHP: fix __must_check warnings
PCI-Express AER implemetation: pcie_portdrv error handler
PCI-Express AER implemetation: AER core and aerdriver
PCI-Express AER implemetation: export pcie_port_bus_type
...

+2722 -214
+253
Documentation/pcieaer-howto.txt
··· 1 + The PCI Express Advanced Error Reporting Driver Guide HOWTO 2 + T. Long Nguyen <tom.l.nguyen@intel.com> 3 + Yanmin Zhang <yanmin.zhang@intel.com> 4 + 07/29/2006 5 + 6 + 7 + 1. Overview 8 + 9 + 1.1 About this guide 10 + 11 + This guide describes the basics of the PCI Express Advanced Error 12 + Reporting (AER) driver and provides information on how to use it, as 13 + well as how to enable the drivers of endpoint devices to conform with 14 + PCI Express AER driver. 15 + 16 + 1.2 Copyright � Intel Corporation 2006. 17 + 18 + 1.3 What is the PCI Express AER Driver? 19 + 20 + PCI Express error signaling can occur on the PCI Express link itself 21 + or on behalf of transactions initiated on the link. PCI Express 22 + defines two error reporting paradigms: the baseline capability and 23 + the Advanced Error Reporting capability. The baseline capability is 24 + required of all PCI Express components providing a minimum defined 25 + set of error reporting requirements. Advanced Error Reporting 26 + capability is implemented with a PCI Express advanced error reporting 27 + extended capability structure providing more robust error reporting. 28 + 29 + The PCI Express AER driver provides the infrastructure to support PCI 30 + Express Advanced Error Reporting capability. The PCI Express AER 31 + driver provides three basic functions: 32 + 33 + - Gathers the comprehensive error information if errors occurred. 34 + - Reports error to the users. 35 + - Performs error recovery actions. 36 + 37 + AER driver only attaches root ports which support PCI-Express AER 38 + capability. 39 + 40 + 41 + 2. User Guide 42 + 43 + 2.1 Include the PCI Express AER Root Driver into the Linux Kernel 44 + 45 + The PCI Express AER Root driver is a Root Port service driver attached 46 + to the PCI Express Port Bus driver. If a user wants to use it, the driver 47 + has to be compiled. Option CONFIG_PCIEAER supports this capability. It 48 + depends on CONFIG_PCIEPORTBUS, so pls. set CONFIG_PCIEPORTBUS=y and 49 + CONFIG_PCIEAER = y. 50 + 51 + 2.2 Load PCI Express AER Root Driver 52 + There is a case where a system has AER support in BIOS. Enabling the AER 53 + Root driver and having AER support in BIOS may result unpredictable 54 + behavior. To avoid this conflict, a successful load of the AER Root driver 55 + requires ACPI _OSC support in the BIOS to allow the AER Root driver to 56 + request for native control of AER. See the PCI FW 3.0 Specification for 57 + details regarding OSC usage. Currently, lots of firmwares don't provide 58 + _OSC support while they use PCI Express. To support such firmwares, 59 + forceload, a parameter of type bool, could enable AER to continue to 60 + be initiated although firmwares have no _OSC support. To enable the 61 + walkaround, pls. add aerdriver.forceload=y to kernel boot parameter line 62 + when booting kernel. Note that forceload=n by default. 63 + 64 + 2.3 AER error output 65 + When a PCI-E AER error is captured, an error message will be outputed to 66 + console. If it's a correctable error, it is outputed as a warning. 67 + Otherwise, it is printed as an error. So users could choose different 68 + log level to filter out correctable error messages. 69 + 70 + Below shows an example. 71 + +------ PCI-Express Device Error -----+ 72 + Error Severity : Uncorrected (Fatal) 73 + PCIE Bus Error type : Transaction Layer 74 + Unsupported Request : First 75 + Requester ID : 0500 76 + VendorID=8086h, DeviceID=0329h, Bus=05h, Device=00h, Function=00h 77 + TLB Header: 78 + 04000001 00200a03 05010000 00050100 79 + 80 + In the example, 'Requester ID' means the ID of the device who sends 81 + the error message to root port. Pls. refer to pci express specs for 82 + other fields. 83 + 84 + 85 + 3. Developer Guide 86 + 87 + To enable AER aware support requires a software driver to configure 88 + the AER capability structure within its device and to provide callbacks. 89 + 90 + To support AER better, developers need understand how AER does work 91 + firstly. 92 + 93 + PCI Express errors are classified into two types: correctable errors 94 + and uncorrectable errors. This classification is based on the impacts 95 + of those errors, which may result in degraded performance or function 96 + failure. 97 + 98 + Correctable errors pose no impacts on the functionality of the 99 + interface. The PCI Express protocol can recover without any software 100 + intervention or any loss of data. These errors are detected and 101 + corrected by hardware. Unlike correctable errors, uncorrectable 102 + errors impact functionality of the interface. Uncorrectable errors 103 + can cause a particular transaction or a particular PCI Express link 104 + to be unreliable. Depending on those error conditions, uncorrectable 105 + errors are further classified into non-fatal errors and fatal errors. 106 + Non-fatal errors cause the particular transaction to be unreliable, 107 + but the PCI Express link itself is fully functional. Fatal errors, on 108 + the other hand, cause the link to be unreliable. 109 + 110 + When AER is enabled, a PCI Express device will automatically send an 111 + error message to the PCIE root port above it when the device captures 112 + an error. The Root Port, upon receiving an error reporting message, 113 + internally processes and logs the error message in its PCI Express 114 + capability structure. Error information being logged includes storing 115 + the error reporting agent's requestor ID into the Error Source 116 + Identification Registers and setting the error bits of the Root Error 117 + Status Register accordingly. If AER error reporting is enabled in Root 118 + Error Command Register, the Root Port generates an interrupt if an 119 + error is detected. 120 + 121 + Note that the errors as described above are related to the PCI Express 122 + hierarchy and links. These errors do not include any device specific 123 + errors because device specific errors will still get sent directly to 124 + the device driver. 125 + 126 + 3.1 Configure the AER capability structure 127 + 128 + AER aware drivers of PCI Express component need change the device 129 + control registers to enable AER. They also could change AER registers, 130 + including mask and severity registers. Helper function 131 + pci_enable_pcie_error_reporting could be used to enable AER. See 132 + section 3.3. 133 + 134 + 3.2. Provide callbacks 135 + 136 + 3.2.1 callback reset_link to reset pci express link 137 + 138 + This callback is used to reset the pci express physical link when a 139 + fatal error happens. The root port aer service driver provides a 140 + default reset_link function, but different upstream ports might 141 + have different specifications to reset pci express link, so all 142 + upstream ports should provide their own reset_link functions. 143 + 144 + In struct pcie_port_service_driver, a new pointer, reset_link, is 145 + added. 146 + 147 + pci_ers_result_t (*reset_link) (struct pci_dev *dev); 148 + 149 + Section 3.2.2.2 provides more detailed info on when to call 150 + reset_link. 151 + 152 + 3.2.2 PCI error-recovery callbacks 153 + 154 + The PCI Express AER Root driver uses error callbacks to coordinate 155 + with downstream device drivers associated with a hierarchy in question 156 + when performing error recovery actions. 157 + 158 + Data struct pci_driver has a pointer, err_handler, to point to 159 + pci_error_handlers who consists of a couple of callback function 160 + pointers. AER driver follows the rules defined in 161 + pci-error-recovery.txt except pci express specific parts (e.g. 162 + reset_link). Pls. refer to pci-error-recovery.txt for detailed 163 + definitions of the callbacks. 164 + 165 + Below sections specify when to call the error callback functions. 166 + 167 + 3.2.2.1 Correctable errors 168 + 169 + Correctable errors pose no impacts on the functionality of 170 + the interface. The PCI Express protocol can recover without any 171 + software intervention or any loss of data. These errors do not 172 + require any recovery actions. The AER driver clears the device's 173 + correctable error status register accordingly and logs these errors. 174 + 175 + 3.2.2.2 Non-correctable (non-fatal and fatal) errors 176 + 177 + If an error message indicates a non-fatal error, performing link reset 178 + at upstream is not required. The AER driver calls error_detected(dev, 179 + pci_channel_io_normal) to all drivers associated within a hierarchy in 180 + question. for example, 181 + EndPoint<==>DownstreamPort B<==>UpstreamPort A<==>RootPort. 182 + If Upstream port A captures an AER error, the hierarchy consists of 183 + Downstream port B and EndPoint. 184 + 185 + A driver may return PCI_ERS_RESULT_CAN_RECOVER, 186 + PCI_ERS_RESULT_DISCONNECT, or PCI_ERS_RESULT_NEED_RESET, depending on 187 + whether it can recover or the AER driver calls mmio_enabled as next. 188 + 189 + If an error message indicates a fatal error, kernel will broadcast 190 + error_detected(dev, pci_channel_io_frozen) to all drivers within 191 + a hierarchy in question. Then, performing link reset at upstream is 192 + necessary. As different kinds of devices might use different approaches 193 + to reset link, AER port service driver is required to provide the 194 + function to reset link. Firstly, kernel looks for if the upstream 195 + component has an aer driver. If it has, kernel uses the reset_link 196 + callback of the aer driver. If the upstream component has no aer driver 197 + and the port is downstream port, we will use the aer driver of the 198 + root port who reports the AER error. As for upstream ports, 199 + they should provide their own aer service drivers with reset_link 200 + function. If error_detected returns PCI_ERS_RESULT_CAN_RECOVER and 201 + reset_link returns PCI_ERS_RESULT_RECOVERED, the error handling goes 202 + to mmio_enabled. 203 + 204 + 3.3 helper functions 205 + 206 + 3.3.1 int pci_find_aer_capability(struct pci_dev *dev); 207 + pci_find_aer_capability locates the PCI Express AER capability 208 + in the device configuration space. If the device doesn't support 209 + PCI-Express AER, the function returns 0. 210 + 211 + 3.3.2 int pci_enable_pcie_error_reporting(struct pci_dev *dev); 212 + pci_enable_pcie_error_reporting enables the device to send error 213 + messages to root port when an error is detected. Note that devices 214 + don't enable the error reporting by default, so device drivers need 215 + call this function to enable it. 216 + 217 + 3.3.3 int pci_disable_pcie_error_reporting(struct pci_dev *dev); 218 + pci_disable_pcie_error_reporting disables the device to send error 219 + messages to root port when an error is detected. 220 + 221 + 3.3.4 int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev); 222 + pci_cleanup_aer_uncorrect_error_status cleanups the uncorrectable 223 + error status register. 224 + 225 + 3.4 Frequent Asked Questions 226 + 227 + Q: What happens if a PCI Express device driver does not provide an 228 + error recovery handler (pci_driver->err_handler is equal to NULL)? 229 + 230 + A: The devices attached with the driver won't be recovered. If the 231 + error is fatal, kernel will print out warning messages. Please refer 232 + to section 3 for more information. 233 + 234 + Q: What happens if an upstream port service driver does not provide 235 + callback reset_link? 236 + 237 + A: Fatal error recovery will fail if the errors are reported by the 238 + upstream ports who are attached by the service driver. 239 + 240 + Q: How does this infrastructure deal with driver that is not PCI 241 + Express aware? 242 + 243 + A: This infrastructure calls the error callback functions of the 244 + driver when an error happens. But if the driver is not aware of 245 + PCI Express, the device might not report its own errors to root 246 + port. 247 + 248 + Q: What modifications will that driver need to make it compatible 249 + with the PCI Express AER Root driver? 250 + 251 + A: It could call the helper functions to enable AER in devices and 252 + cleanup uncorrectable status register. Pls. refer to section 3.3. 253 +
+2 -1
arch/ia64/pci/pci.c
··· 562 562 void 563 563 pcibios_disable_device (struct pci_dev *dev) 564 564 { 565 - acpi_pci_irq_disable(dev); 565 + if (dev->is_enabled) 566 + acpi_pci_irq_disable(dev); 566 567 } 567 568 568 569 void
+1 -1
arch/powerpc/sysdev/mpic.c
··· 339 339 for (pos = readb(devbase + PCI_CAPABILITY_LIST); pos != 0; 340 340 pos = readb(devbase + pos + PCI_CAP_LIST_NEXT)) { 341 341 u8 id = readb(devbase + pos + PCI_CAP_LIST_ID); 342 - if (id == PCI_CAP_ID_HT_IRQCONF) { 342 + if (id == PCI_CAP_ID_HT) { 343 343 id = readb(devbase + pos + 3); 344 344 if (id == 0x80) 345 345 break;
+2 -3
drivers/infiniband/hw/ipath/ipath_iba6110.c
··· 742 742 return 0; 743 743 } 744 744 745 - #define HT_CAPABILITY_ID 0x08 /* HT capabilities not defined in kernel */ 746 745 #define HT_INTR_DISC_CONFIG 0x80 /* HT interrupt and discovery cap */ 747 746 #define HT_INTR_REG_INDEX 2 /* intconfig requires indirect accesses */ 748 747 ··· 972 973 * do this early, before we ever enable errors or hardware errors, 973 974 * mostly to avoid causing the chip to enter freeze mode. 974 975 */ 975 - pos = pci_find_capability(pdev, HT_CAPABILITY_ID); 976 + pos = pci_find_capability(pdev, PCI_CAP_ID_HT); 976 977 if (!pos) { 977 978 ipath_dev_err(dd, "Couldn't find HyperTransport " 978 979 "capability; no interrupts\n"); ··· 995 996 else if (cap_type == HT_INTR_DISC_CONFIG) 996 997 ihandler = set_int_handler(dd, pdev, pos); 997 998 } while ((pos = pci_find_next_capability(pdev, pos, 998 - HT_CAPABILITY_ID))); 999 + PCI_CAP_ID_HT))); 999 1000 1000 1001 if (!ihandler) { 1001 1002 ipath_dev_err(dd, "Couldn't find interrupt handler in "
+16 -6
drivers/pci/bus.c
··· 77 77 * This adds a single pci device to the global 78 78 * device list and adds sysfs and procfs entries 79 79 */ 80 - void __devinit pci_bus_add_device(struct pci_dev *dev) 80 + int __devinit pci_bus_add_device(struct pci_dev *dev) 81 81 { 82 - device_add(&dev->dev); 82 + int retval; 83 + retval = device_add(&dev->dev); 84 + if (retval) 85 + return retval; 83 86 84 87 down_write(&pci_bus_sem); 85 88 list_add_tail(&dev->global_list, &pci_devices); ··· 90 87 91 88 pci_proc_attach_device(dev); 92 89 pci_create_sysfs_dev_files(dev); 90 + return 0; 93 91 } 94 92 95 93 /** ··· 108 104 void __devinit pci_bus_add_devices(struct pci_bus *bus) 109 105 { 110 106 struct pci_dev *dev; 107 + int retval; 111 108 112 109 list_for_each_entry(dev, &bus->devices, bus_list) { 113 110 /* ··· 117 112 */ 118 113 if (!list_empty(&dev->global_list)) 119 114 continue; 120 - pci_bus_add_device(dev); 115 + retval = pci_bus_add_device(dev); 116 + if (retval) 117 + dev_err(&dev->dev, "Error adding device, continuing\n"); 121 118 } 122 119 123 120 list_for_each_entry(dev, &bus->devices, bus_list) { ··· 136 129 list_add_tail(&dev->subordinate->node, 137 130 &dev->bus->children); 138 131 up_write(&pci_bus_sem); 139 - } 132 + } 140 133 pci_bus_add_devices(dev->subordinate); 141 - 142 - sysfs_create_link(&dev->subordinate->class_dev.kobj, &dev->dev.kobj, "bridge"); 134 + retval = sysfs_create_link(&dev->subordinate->class_dev.kobj, 135 + &dev->dev.kobj, "bridge"); 136 + if (retval) 137 + dev_err(&dev->dev, "Error creating sysfs " 138 + "bridge symlink, continuing...\n"); 143 139 } 144 140 } 145 141 }
+5
drivers/pci/hotplug/acpiphp.h
··· 150 150 struct module *owner; 151 151 }; 152 152 153 + struct acpiphp_ioapic { 154 + struct pci_dev *dev; 155 + u32 gsi_base; 156 + struct list_head list; 157 + }; 153 158 154 159 /* PCI bus bridge HID */ 155 160 #define ACPI_PCI_HOST_HID "PNP0A03"
+110 -17
drivers/pci/hotplug/acpiphp_glue.c
··· 53 53 #include "acpiphp.h" 54 54 55 55 static LIST_HEAD(bridge_list); 56 + static LIST_HEAD(ioapic_list); 57 + static DEFINE_SPINLOCK(ioapic_list_lock); 56 58 57 59 #define MY_NAME "acpiphp_glue" 58 60 ··· 799 797 struct pci_dev *pdev; 800 798 u32 gsi_base; 801 799 u64 phys_addr; 800 + struct acpiphp_ioapic *ioapic; 802 801 803 802 /* Evaluate _STA if present */ 804 803 status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); ··· 814 811 if (get_gsi_base(handle, &gsi_base)) 815 812 return AE_OK; 816 813 814 + ioapic = kmalloc(sizeof(*ioapic), GFP_KERNEL); 815 + if (!ioapic) 816 + return AE_NO_MEMORY; 817 + 817 818 pdev = get_apic_pci_info(handle); 818 819 if (!pdev) 819 - return AE_OK; 820 + goto exit_kfree; 820 821 821 - if (pci_enable_device(pdev)) { 822 - pci_dev_put(pdev); 823 - return AE_OK; 824 - } 822 + if (pci_enable_device(pdev)) 823 + goto exit_pci_dev_put; 825 824 826 825 pci_set_master(pdev); 827 826 828 - if (pci_request_region(pdev, 0, "I/O APIC(acpiphp)")) { 829 - pci_disable_device(pdev); 830 - pci_dev_put(pdev); 831 - return AE_OK; 832 - } 827 + if (pci_request_region(pdev, 0, "I/O APIC(acpiphp)")) 828 + goto exit_pci_disable_device; 833 829 834 830 phys_addr = pci_resource_start(pdev, 0); 835 - if (acpi_register_ioapic(handle, phys_addr, gsi_base)) { 836 - pci_release_region(pdev, 0); 837 - pci_disable_device(pdev); 838 - pci_dev_put(pdev); 831 + if (acpi_register_ioapic(handle, phys_addr, gsi_base)) 832 + goto exit_pci_release_region; 833 + 834 + ioapic->gsi_base = gsi_base; 835 + ioapic->dev = pdev; 836 + spin_lock(&ioapic_list_lock); 837 + list_add_tail(&ioapic->list, &ioapic_list); 838 + spin_unlock(&ioapic_list_lock); 839 + 840 + return AE_OK; 841 + 842 + exit_pci_release_region: 843 + pci_release_region(pdev, 0); 844 + exit_pci_disable_device: 845 + pci_disable_device(pdev); 846 + exit_pci_dev_put: 847 + pci_dev_put(pdev); 848 + exit_kfree: 849 + kfree(ioapic); 850 + 851 + return AE_OK; 852 + } 853 + 854 + static acpi_status 855 + ioapic_remove(acpi_handle handle, u32 lvl, void *context, void **rv) 856 + { 857 + acpi_status status; 858 + unsigned long sta; 859 + acpi_handle tmp; 860 + u32 gsi_base; 861 + struct acpiphp_ioapic *pos, *n, *ioapic = NULL; 862 + 863 + /* Evaluate _STA if present */ 864 + status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); 865 + if (ACPI_SUCCESS(status) && sta != ACPI_STA_ALL) 866 + return AE_CTRL_DEPTH; 867 + 868 + /* Scan only PCI bus scope */ 869 + status = acpi_get_handle(handle, "_HID", &tmp); 870 + if (ACPI_SUCCESS(status)) 871 + return AE_CTRL_DEPTH; 872 + 873 + if (get_gsi_base(handle, &gsi_base)) 839 874 return AE_OK; 875 + 876 + acpi_unregister_ioapic(handle, gsi_base); 877 + 878 + spin_lock(&ioapic_list_lock); 879 + list_for_each_entry_safe(pos, n, &ioapic_list, list) { 880 + if (pos->gsi_base != gsi_base) 881 + continue; 882 + ioapic = pos; 883 + list_del(&ioapic->list); 884 + break; 840 885 } 886 + spin_unlock(&ioapic_list_lock); 887 + 888 + if (!ioapic) 889 + return AE_OK; 890 + 891 + pci_release_region(ioapic->dev, 0); 892 + pci_disable_device(ioapic->dev); 893 + pci_dev_put(ioapic->dev); 894 + kfree(ioapic); 841 895 842 896 return AE_OK; 843 897 } 844 898 845 899 static int acpiphp_configure_ioapics(acpi_handle handle) 846 900 { 901 + ioapic_add(handle, 0, NULL, NULL); 847 902 acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 848 903 ACPI_UINT32_MAX, ioapic_add, NULL, NULL); 904 + return 0; 905 + } 906 + 907 + static int acpiphp_unconfigure_ioapics(acpi_handle handle) 908 + { 909 + ioapic_remove(handle, 0, NULL, NULL); 910 + acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 911 + ACPI_UINT32_MAX, ioapic_remove, NULL, NULL); 849 912 return 0; 850 913 } 851 914 ··· 1066 997 * @handle: handle to acpi namespace 1067 998 * 1068 999 */ 1069 - int acpiphp_bus_trim(acpi_handle handle) 1000 + static int acpiphp_bus_trim(acpi_handle handle) 1070 1001 { 1071 1002 struct acpi_device *device; 1072 1003 int retval; ··· 1143 1074 1144 1075 pci_bus_assign_resources(bus); 1145 1076 acpiphp_sanitize_bus(bus); 1077 + acpiphp_set_hpp_values(slot->bridge->handle, bus); 1078 + list_for_each_entry(func, &slot->funcs, sibling) 1079 + acpiphp_configure_ioapics(func->handle); 1146 1080 pci_enable_bridges(bus); 1147 1081 pci_bus_add_devices(bus); 1148 - acpiphp_set_hpp_values(slot->bridge->handle, bus); 1149 - acpiphp_configure_ioapics(slot->bridge->handle); 1150 1082 1151 1083 /* associate pci_dev to our representation */ 1152 1084 list_for_each (l, &slot->funcs) { ··· 1173 1103 return retval; 1174 1104 } 1175 1105 1106 + static void disable_bridges(struct pci_bus *bus) 1107 + { 1108 + struct pci_dev *dev; 1109 + list_for_each_entry(dev, &bus->devices, bus_list) { 1110 + if (dev->subordinate) { 1111 + disable_bridges(dev->subordinate); 1112 + pci_disable_device(dev); 1113 + } 1114 + } 1115 + } 1176 1116 1177 1117 /** 1178 1118 * disable_device - disable a slot ··· 1207 1127 func->bridge = NULL; 1208 1128 } 1209 1129 1130 + if (func->pci_dev) { 1131 + pci_stop_bus_device(func->pci_dev); 1132 + if (func->pci_dev->subordinate) { 1133 + disable_bridges(func->pci_dev->subordinate); 1134 + pci_disable_device(func->pci_dev); 1135 + } 1136 + } 1137 + } 1138 + 1139 + list_for_each (l, &slot->funcs) { 1140 + func = list_entry(l, struct acpiphp_func, sibling); 1141 + 1142 + acpiphp_unconfigure_ioapics(func->handle); 1210 1143 acpiphp_bus_trim(func->handle); 1211 1144 /* try to remove anyway. 1212 1145 * acpiphp_bus_add might have been failed */
+14 -4
drivers/pci/hotplug/fakephp.c
··· 176 176 struct pci_bus *bus = temp->bus; 177 177 struct pci_dev *dev; 178 178 int func; 179 + int retval; 179 180 u8 hdr_type; 181 + 180 182 if (!pci_read_config_byte(temp, PCI_HEADER_TYPE, &hdr_type)) { 181 183 temp->hdr_type = hdr_type & 0x7f; 182 184 if (!pci_find_slot(bus->number, temp->devfn)) { ··· 187 185 dbg("New device on %s function %x:%x\n", 188 186 bus->name, temp->devfn >> 3, 189 187 temp->devfn & 7); 190 - pci_bus_add_device(dev); 191 - add_slot(dev); 188 + retval = pci_bus_add_device(dev); 189 + if (retval) 190 + dev_err(&dev->dev, "error adding " 191 + "device, continuing.\n"); 192 + else 193 + add_slot(dev); 192 194 } 193 195 } 194 196 /* multifunction device? */ ··· 211 205 dbg("New device on %s function %x:%x\n", 212 206 bus->name, temp->devfn >> 3, 213 207 temp->devfn & 7); 214 - pci_bus_add_device(dev); 215 - add_slot(dev); 208 + retval = pci_bus_add_device(dev); 209 + if (retval) 210 + dev_err(&dev->dev, "error adding " 211 + "device, continuing.\n"); 212 + else 213 + add_slot(dev); 216 214 } 217 215 } 218 216 }
+2 -2
drivers/pci/hotplug/pci_hotplug.h
··· 172 172 173 173 extern int pci_hp_register (struct hotplug_slot *slot); 174 174 extern int pci_hp_deregister (struct hotplug_slot *slot); 175 - extern int pci_hp_change_slot_info (struct hotplug_slot *slot, 176 - struct hotplug_slot_info *info); 175 + extern int __must_check pci_hp_change_slot_info (struct hotplug_slot *slot, 176 + struct hotplug_slot_info *info); 177 177 extern struct subsystem pci_hotplug_slots_subsys; 178 178 179 179 /* PCI Setting Record (Type 0) */
+126 -31
drivers/pci/hotplug/pci_hotplug_core.c
··· 482 482 483 483 static int fs_add_slot (struct hotplug_slot *slot) 484 484 { 485 - if (has_power_file(slot) == 0) 486 - sysfs_create_file(&slot->kobj, &hotplug_slot_attr_power.attr); 485 + int retval = 0; 487 486 488 - if (has_attention_file(slot) == 0) 489 - sysfs_create_file(&slot->kobj, &hotplug_slot_attr_attention.attr); 487 + if (has_power_file(slot) == 0) { 488 + retval = sysfs_create_file(&slot->kobj, &hotplug_slot_attr_power.attr); 489 + if (retval) 490 + goto exit_power; 491 + } 490 492 491 - if (has_latch_file(slot) == 0) 492 - sysfs_create_file(&slot->kobj, &hotplug_slot_attr_latch.attr); 493 + if (has_attention_file(slot) == 0) { 494 + retval = sysfs_create_file(&slot->kobj, 495 + &hotplug_slot_attr_attention.attr); 496 + if (retval) 497 + goto exit_attention; 498 + } 493 499 494 - if (has_adapter_file(slot) == 0) 495 - sysfs_create_file(&slot->kobj, &hotplug_slot_attr_presence.attr); 500 + if (has_latch_file(slot) == 0) { 501 + retval = sysfs_create_file(&slot->kobj, 502 + &hotplug_slot_attr_latch.attr); 503 + if (retval) 504 + goto exit_latch; 505 + } 496 506 497 - if (has_address_file(slot) == 0) 498 - sysfs_create_file(&slot->kobj, &hotplug_slot_attr_address.attr); 507 + if (has_adapter_file(slot) == 0) { 508 + retval = sysfs_create_file(&slot->kobj, 509 + &hotplug_slot_attr_presence.attr); 510 + if (retval) 511 + goto exit_adapter; 512 + } 499 513 500 - if (has_max_bus_speed_file(slot) == 0) 501 - sysfs_create_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr); 514 + if (has_address_file(slot) == 0) { 515 + retval = sysfs_create_file(&slot->kobj, 516 + &hotplug_slot_attr_address.attr); 517 + if (retval) 518 + goto exit_address; 519 + } 502 520 521 + if (has_max_bus_speed_file(slot) == 0) { 522 + retval = sysfs_create_file(&slot->kobj, 523 + &hotplug_slot_attr_max_bus_speed.attr); 524 + if (retval) 525 + goto exit_max_speed; 526 + } 527 + 528 + if (has_cur_bus_speed_file(slot) == 0) { 529 + retval = sysfs_create_file(&slot->kobj, 530 + &hotplug_slot_attr_cur_bus_speed.attr); 531 + if (retval) 532 + goto exit_cur_speed; 533 + } 534 + 535 + if (has_test_file(slot) == 0) { 536 + retval = sysfs_create_file(&slot->kobj, 537 + &hotplug_slot_attr_test.attr); 538 + if (retval) 539 + goto exit_test; 540 + } 541 + 542 + goto exit; 543 + 544 + exit_test: 503 545 if (has_cur_bus_speed_file(slot) == 0) 504 - sysfs_create_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr); 546 + sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr); 505 547 506 - if (has_test_file(slot) == 0) 507 - sysfs_create_file(&slot->kobj, &hotplug_slot_attr_test.attr); 548 + exit_cur_speed: 549 + if (has_max_bus_speed_file(slot) == 0) 550 + sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr); 508 551 509 - return 0; 552 + exit_max_speed: 553 + if (has_address_file(slot) == 0) 554 + sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_address.attr); 555 + 556 + exit_address: 557 + if (has_adapter_file(slot) == 0) 558 + sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_presence.attr); 559 + 560 + exit_adapter: 561 + if (has_latch_file(slot) == 0) 562 + sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_latch.attr); 563 + 564 + exit_latch: 565 + if (has_attention_file(slot) == 0) 566 + sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_attention.attr); 567 + 568 + exit_attention: 569 + if (has_power_file(slot) == 0) 570 + sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_power.attr); 571 + exit_power: 572 + exit: 573 + return retval; 510 574 } 511 575 512 576 static void fs_remove_slot (struct hotplug_slot *slot) ··· 690 626 * 691 627 * Returns 0 if successful, anything else for an error. 692 628 */ 693 - int pci_hp_change_slot_info (struct hotplug_slot *slot, struct hotplug_slot_info *info) 629 + int __must_check pci_hp_change_slot_info(struct hotplug_slot *slot, 630 + struct hotplug_slot_info *info) 694 631 { 632 + int retval; 633 + 695 634 if ((slot == NULL) || (info == NULL)) 696 635 return -ENODEV; 697 636 ··· 703 636 * for the files referring to the fields that have now changed. 704 637 */ 705 638 if ((has_power_file(slot) == 0) && 706 - (slot->info->power_status != info->power_status)) 707 - sysfs_update_file(&slot->kobj, &hotplug_slot_attr_power.attr); 639 + (slot->info->power_status != info->power_status)) { 640 + retval = sysfs_update_file(&slot->kobj, 641 + &hotplug_slot_attr_power.attr); 642 + if (retval) 643 + return retval; 644 + } 708 645 709 646 if ((has_attention_file(slot) == 0) && 710 - (slot->info->attention_status != info->attention_status)) 711 - sysfs_update_file(&slot->kobj, &hotplug_slot_attr_attention.attr); 647 + (slot->info->attention_status != info->attention_status)) { 648 + retval = sysfs_update_file(&slot->kobj, 649 + &hotplug_slot_attr_attention.attr); 650 + if (retval) 651 + return retval; 652 + } 712 653 713 654 if ((has_latch_file(slot) == 0) && 714 - (slot->info->latch_status != info->latch_status)) 715 - sysfs_update_file(&slot->kobj, &hotplug_slot_attr_latch.attr); 655 + (slot->info->latch_status != info->latch_status)) { 656 + retval = sysfs_update_file(&slot->kobj, 657 + &hotplug_slot_attr_latch.attr); 658 + if (retval) 659 + return retval; 660 + } 716 661 717 662 if ((has_adapter_file(slot) == 0) && 718 - (slot->info->adapter_status != info->adapter_status)) 719 - sysfs_update_file(&slot->kobj, &hotplug_slot_attr_presence.attr); 663 + (slot->info->adapter_status != info->adapter_status)) { 664 + retval = sysfs_update_file(&slot->kobj, 665 + &hotplug_slot_attr_presence.attr); 666 + if (retval) 667 + return retval; 668 + } 720 669 721 670 if ((has_address_file(slot) == 0) && 722 - (slot->info->address != info->address)) 723 - sysfs_update_file(&slot->kobj, &hotplug_slot_attr_address.attr); 671 + (slot->info->address != info->address)) { 672 + retval = sysfs_update_file(&slot->kobj, 673 + &hotplug_slot_attr_address.attr); 674 + if (retval) 675 + return retval; 676 + } 724 677 725 678 if ((has_max_bus_speed_file(slot) == 0) && 726 - (slot->info->max_bus_speed != info->max_bus_speed)) 727 - sysfs_update_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr); 679 + (slot->info->max_bus_speed != info->max_bus_speed)) { 680 + retval = sysfs_update_file(&slot->kobj, 681 + &hotplug_slot_attr_max_bus_speed.attr); 682 + if (retval) 683 + return retval; 684 + } 728 685 729 686 if ((has_cur_bus_speed_file(slot) == 0) && 730 - (slot->info->cur_bus_speed != info->cur_bus_speed)) 731 - sysfs_update_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr); 687 + (slot->info->cur_bus_speed != info->cur_bus_speed)) { 688 + retval = sysfs_update_file(&slot->kobj, 689 + &hotplug_slot_attr_cur_bus_speed.attr); 690 + if (retval) 691 + return retval; 692 + } 732 693 733 694 memcpy (slot->info, info, sizeof (struct hotplug_slot_info)); 734 695
+6 -6
drivers/pci/hotplug/pciehp_ctrl.c
··· 762 762 if (rc || !getstatus) { 763 763 info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number); 764 764 mutex_unlock(&p_slot->ctrl->crit_sect); 765 - return 1; 765 + return -ENODEV; 766 766 } 767 767 if (MRL_SENS(p_slot->ctrl->ctrlcap)) { 768 768 rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); 769 769 if (rc || getstatus) { 770 770 info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); 771 771 mutex_unlock(&p_slot->ctrl->crit_sect); 772 - return 1; 772 + return -ENODEV; 773 773 } 774 774 } 775 775 ··· 778 778 if (rc || getstatus) { 779 779 info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number); 780 780 mutex_unlock(&p_slot->ctrl->crit_sect); 781 - return 1; 781 + return -EINVAL; 782 782 } 783 783 } 784 784 mutex_unlock(&p_slot->ctrl->crit_sect); ··· 813 813 if (ret || !getstatus) { 814 814 info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number); 815 815 mutex_unlock(&p_slot->ctrl->crit_sect); 816 - return 1; 816 + return -ENODEV; 817 817 } 818 818 } 819 819 ··· 822 822 if (ret || getstatus) { 823 823 info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number); 824 824 mutex_unlock(&p_slot->ctrl->crit_sect); 825 - return 1; 825 + return -ENODEV; 826 826 } 827 827 } 828 828 ··· 831 831 if (ret || !getstatus) { 832 832 info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number); 833 833 mutex_unlock(&p_slot->ctrl->crit_sect); 834 - return 1; 834 + return -EINVAL; 835 835 } 836 836 } 837 837
+3 -6
drivers/pci/hotplug/pcihp_skeleton.c
··· 1 1 /* 2 - * PCI Hot Plug Controller Skeleton Driver - 0.2 2 + * PCI Hot Plug Controller Skeleton Driver - 0.3 3 3 * 4 4 * Copyright (C) 2001,2003 Greg Kroah-Hartman (greg@kroah.com) 5 5 * Copyright (C) 2001,2003 IBM Corp. ··· 21 21 * along with this program; if not, write to the Free Software 22 22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 23 23 * 24 - * This driver is to be used as a skeleton driver to be show how to interface 24 + * This driver is to be used as a skeleton driver to show how to interface 25 25 * with the pci hotplug core easily. 26 26 * 27 27 * Send feedback to <greg@kroah.com> ··· 57 57 #define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg) 58 58 #define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg) 59 59 #define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg) 60 - 61 - 62 60 63 61 /* local variables */ 64 62 static int debug; ··· 106 108 107 109 return retval; 108 110 } 109 - 110 111 111 112 static int disable_slot(struct hotplug_slot *hotplug_slot) 112 113 { ··· 339 342 info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); 340 343 /* 341 344 * Do specific initialization stuff for your driver here 342 - * Like initializing your controller hardware (if any) and 345 + * like initializing your controller hardware (if any) and 343 346 * determining the number of slots you have in the system 344 347 * right now. 345 348 */
+1 -1
drivers/pci/hotplug/shpchp.h
··· 173 173 #define msg_button_cancel "PCI slot #%s - action canceled due to button press.\n" 174 174 175 175 /* sysfs functions for the hotplug controller info */ 176 - extern void shpchp_create_ctrl_files (struct controller *ctrl); 176 + extern int __must_check shpchp_create_ctrl_files(struct controller *ctrl); 177 177 178 178 extern int shpchp_sysfs_enable_slot(struct slot *slot); 179 179 extern int shpchp_sysfs_disable_slot(struct slot *slot);
+5 -1
drivers/pci/hotplug/shpchp_core.c
··· 449 449 ctrl->speed = PCI_SPEED_33MHz; 450 450 } 451 451 452 - shpchp_create_ctrl_files(ctrl); 452 + rc = shpchp_create_ctrl_files(ctrl); 453 + if (rc) 454 + goto err_cleanup_slots; 453 455 454 456 return 0; 455 457 458 + err_cleanup_slots: 459 + cleanup_slots(ctrl); 456 460 err_out_release_ctlr: 457 461 ctrl->hpc_ops->release_ctlr(ctrl); 458 462 err_out_free_ctrl:
+2 -2
drivers/pci/hotplug/shpchp_sysfs.c
··· 91 91 } 92 92 static DEVICE_ATTR (ctrl, S_IRUGO, show_ctrl, NULL); 93 93 94 - void shpchp_create_ctrl_files (struct controller *ctrl) 94 + int __must_check shpchp_create_ctrl_files (struct controller *ctrl) 95 95 { 96 - device_create_file (&ctrl->pci_dev->dev, &dev_attr_ctrl); 96 + return device_create_file (&ctrl->pci_dev->dev, &dev_attr_ctrl); 97 97 } 98 98 99 99 void shpchp_remove_ctrl_files(struct controller *ctrl)
+31 -20
drivers/pci/msi.c
··· 901 901 } 902 902 903 903 /** 904 + * pci_msi_supported - check whether MSI may be enabled on device 905 + * @dev: pointer to the pci_dev data structure of MSI device function 906 + * 907 + * MSI must be globally enabled and supported by the device and its root 908 + * bus. But, the root bus is not easy to find since some architectures 909 + * have virtual busses on top of the PCI hierarchy (for instance the 910 + * hypertransport bus), while the actual bus where MSI must be supported 911 + * is below. So we test the MSI flag on all parent busses and assume 912 + * that no quirk will ever set the NO_MSI flag on a non-root bus. 913 + **/ 914 + static 915 + int pci_msi_supported(struct pci_dev * dev) 916 + { 917 + struct pci_bus *bus; 918 + 919 + if (!pci_msi_enable || !dev || dev->no_msi) 920 + return -EINVAL; 921 + 922 + /* check MSI flags of all parent busses */ 923 + for (bus = dev->bus; bus; bus = bus->parent) 924 + if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI) 925 + return -EINVAL; 926 + 927 + return 0; 928 + } 929 + 930 + /** 904 931 * pci_enable_msi - configure device's MSI capability structure 905 932 * @dev: pointer to the pci_dev data structure of MSI device function 906 933 * ··· 939 912 **/ 940 913 int pci_enable_msi(struct pci_dev* dev) 941 914 { 942 - struct pci_bus *bus; 943 - int pos, temp, status = -EINVAL; 915 + int pos, temp, status; 944 916 u16 control; 945 917 946 - if (!pci_msi_enable || !dev) 947 - return status; 948 - 949 - if (dev->no_msi) 950 - return status; 951 - 952 - for (bus = dev->bus; bus; bus = bus->parent) 953 - if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI) 954 - return -EINVAL; 918 + if (pci_msi_supported(dev) < 0) 919 + return -EINVAL; 955 920 956 921 temp = dev->irq; 957 922 ··· 1153 1134 **/ 1154 1135 int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec) 1155 1136 { 1156 - struct pci_bus *bus; 1157 1137 int status, pos, nr_entries, free_vectors; 1158 1138 int i, j, temp; 1159 1139 u16 control; 1160 1140 unsigned long flags; 1161 1141 1162 - if (!pci_msi_enable || !dev || !entries) 1142 + if (!entries || pci_msi_supported(dev) < 0) 1163 1143 return -EINVAL; 1164 - 1165 - if (dev->no_msi) 1166 - return -EINVAL; 1167 - 1168 - for (bus = dev->bus; bus; bus = bus->parent) 1169 - if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI) 1170 - return -EINVAL; 1171 1144 1172 1145 status = msi_init(); 1173 1146 if (status < 0)
+9 -2
drivers/pci/pci-driver.c
··· 56 56 subdevice=PCI_ANY_ID, class=0, class_mask=0; 57 57 unsigned long driver_data=0; 58 58 int fields=0; 59 + int retval = 0; 59 60 60 61 fields = sscanf(buf, "%x %x %x %x %x %x %lux", 61 62 &vendor, &device, &subvendor, &subdevice, ··· 83 82 spin_unlock(&pdrv->dynids.lock); 84 83 85 84 if (get_driver(&pdrv->driver)) { 86 - driver_attach(&pdrv->driver); 85 + retval = driver_attach(&pdrv->driver); 87 86 put_driver(&pdrv->driver); 88 87 } 89 88 89 + if (retval) 90 + return retval; 90 91 return count; 91 92 } 92 93 static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id); ··· 421 418 drv->driver.bus = &pci_bus_type; 422 419 drv->driver.owner = owner; 423 420 drv->driver.kobj.ktype = &pci_driver_kobj_type; 424 - drv->driver.multithread_probe = pci_multithread_probe; 421 + 422 + if (pci_multithread_probe) 423 + drv->driver.multithread_probe = pci_multithread_probe; 424 + else 425 + drv->driver.multithread_probe = drv->multithread_probe; 425 426 426 427 spin_lock_init(&drv->dynids.lock); 427 428 INIT_LIST_HEAD(&drv->dynids.list);
+114 -39
drivers/pci/pci-sysfs.c
··· 117 117 const char *buf, size_t count) 118 118 { 119 119 struct pci_dev *pdev = to_pci_dev(dev); 120 + int retval = 0; 120 121 121 122 /* this can crash the machine when done on the "wrong" device */ 122 123 if (!capable(CAP_SYS_ADMIN)) ··· 127 126 pci_disable_device(pdev); 128 127 129 128 if (*buf == '1') 130 - pci_enable_device(pdev); 129 + retval = pci_enable_device(pdev); 131 130 131 + if (retval) 132 + return retval; 132 133 return count; 133 134 } 134 135 136 + static ssize_t 137 + msi_bus_show(struct device *dev, struct device_attribute *attr, char *buf) 138 + { 139 + struct pci_dev *pdev = to_pci_dev(dev); 140 + 141 + if (!pdev->subordinate) 142 + return 0; 143 + 144 + return sprintf (buf, "%u\n", 145 + !(pdev->subordinate->bus_flags & PCI_BUS_FLAGS_NO_MSI)); 146 + } 147 + 148 + static ssize_t 149 + msi_bus_store(struct device *dev, struct device_attribute *attr, 150 + const char *buf, size_t count) 151 + { 152 + struct pci_dev *pdev = to_pci_dev(dev); 153 + 154 + /* bad things may happen if the no_msi flag is changed 155 + * while some drivers are loaded */ 156 + if (!capable(CAP_SYS_ADMIN)) 157 + return count; 158 + 159 + if (!pdev->subordinate) 160 + return count; 161 + 162 + if (*buf == '0') { 163 + pdev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI; 164 + dev_warn(&pdev->dev, "forced subordinate bus to not support MSI," 165 + " bad things could happen.\n"); 166 + } 167 + 168 + if (*buf == '1') { 169 + pdev->subordinate->bus_flags &= ~PCI_BUS_FLAGS_NO_MSI; 170 + dev_warn(&pdev->dev, "forced subordinate bus to support MSI," 171 + " bad things could happen.\n"); 172 + } 173 + 174 + return count; 175 + } 135 176 136 177 struct device_attribute pci_dev_attrs[] = { 137 178 __ATTR_RO(resource), ··· 188 145 __ATTR(enable, 0600, is_enabled_show, is_enabled_store), 189 146 __ATTR(broken_parity_status,(S_IRUGO|S_IWUSR), 190 147 broken_parity_status_show,broken_parity_status_store), 148 + __ATTR(msi_bus, 0644, msi_bus_show, msi_bus_store), 191 149 __ATTR_NULL, 192 150 }; 193 151 ··· 429 385 } 430 386 431 387 /** 388 + * pci_remove_resource_files - cleanup resource files 389 + * @dev: dev to cleanup 390 + * 391 + * If we created resource files for @dev, remove them from sysfs and 392 + * free their resources. 393 + */ 394 + static void 395 + pci_remove_resource_files(struct pci_dev *pdev) 396 + { 397 + int i; 398 + 399 + for (i = 0; i < PCI_ROM_RESOURCE; i++) { 400 + struct bin_attribute *res_attr; 401 + 402 + res_attr = pdev->res_attr[i]; 403 + if (res_attr) { 404 + sysfs_remove_bin_file(&pdev->dev.kobj, res_attr); 405 + kfree(res_attr); 406 + } 407 + } 408 + } 409 + 410 + /** 432 411 * pci_create_resource_files - create resource files in sysfs for @dev 433 412 * @dev: dev in question 434 413 * 435 414 * Walk the resources in @dev creating files for each resource available. 436 415 */ 437 - static void 438 - pci_create_resource_files(struct pci_dev *pdev) 416 + static int pci_create_resource_files(struct pci_dev *pdev) 439 417 { 440 418 int i; 419 + int retval; 441 420 442 421 /* Expose the PCI resources from this device as files */ 443 422 for (i = 0; i < PCI_ROM_RESOURCE; i++) { ··· 483 416 res_attr->size = pci_resource_len(pdev, i); 484 417 res_attr->mmap = pci_mmap_resource; 485 418 res_attr->private = &pdev->resource[i]; 486 - sysfs_create_bin_file(&pdev->dev.kobj, res_attr); 419 + retval = sysfs_create_bin_file(&pdev->dev.kobj, res_attr); 420 + if (retval) { 421 + pci_remove_resource_files(pdev); 422 + return retval; 423 + } 424 + } else { 425 + return -ENOMEM; 487 426 } 488 427 } 489 - } 490 - 491 - /** 492 - * pci_remove_resource_files - cleanup resource files 493 - * @dev: dev to cleanup 494 - * 495 - * If we created resource files for @dev, remove them from sysfs and 496 - * free their resources. 497 - */ 498 - static void 499 - pci_remove_resource_files(struct pci_dev *pdev) 500 - { 501 - int i; 502 - 503 - for (i = 0; i < PCI_ROM_RESOURCE; i++) { 504 - struct bin_attribute *res_attr; 505 - 506 - res_attr = pdev->res_attr[i]; 507 - if (res_attr) { 508 - sysfs_remove_bin_file(&pdev->dev.kobj, res_attr); 509 - kfree(res_attr); 510 - } 511 - } 428 + return 0; 512 429 } 513 430 #else /* !HAVE_PCI_MMAP */ 514 - static inline void pci_create_resource_files(struct pci_dev *dev) { return; } 431 + static inline int pci_create_resource_files(struct pci_dev *dev) { return 0; } 515 432 static inline void pci_remove_resource_files(struct pci_dev *dev) { return; } 516 433 #endif /* HAVE_PCI_MMAP */ 517 434 ··· 580 529 .write = pci_write_config, 581 530 }; 582 531 583 - int pci_create_sysfs_dev_files (struct pci_dev *pdev) 532 + int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev) 584 533 { 534 + struct bin_attribute *rom_attr = NULL; 535 + int retval; 536 + 585 537 if (!sysfs_initialized) 586 538 return -EACCES; 587 539 588 540 if (pdev->cfg_size < 4096) 589 - sysfs_create_bin_file(&pdev->dev.kobj, &pci_config_attr); 541 + retval = sysfs_create_bin_file(&pdev->dev.kobj, &pci_config_attr); 590 542 else 591 - sysfs_create_bin_file(&pdev->dev.kobj, &pcie_config_attr); 543 + retval = sysfs_create_bin_file(&pdev->dev.kobj, &pcie_config_attr); 544 + if (retval) 545 + goto err; 592 546 593 - pci_create_resource_files(pdev); 547 + retval = pci_create_resource_files(pdev); 548 + if (retval) 549 + goto err_bin_file; 594 550 595 551 /* If the device has a ROM, try to expose it in sysfs. */ 596 552 if (pci_resource_len(pdev, PCI_ROM_RESOURCE)) { 597 - struct bin_attribute *rom_attr; 598 - 599 553 rom_attr = kzalloc(sizeof(*rom_attr), GFP_ATOMIC); 600 554 if (rom_attr) { 601 555 pdev->rom_attr = rom_attr; ··· 610 554 rom_attr->attr.owner = THIS_MODULE; 611 555 rom_attr->read = pci_read_rom; 612 556 rom_attr->write = pci_write_rom; 613 - sysfs_create_bin_file(&pdev->dev.kobj, rom_attr); 557 + retval = sysfs_create_bin_file(&pdev->dev.kobj, rom_attr); 558 + if (retval) 559 + goto err_rom; 560 + } else { 561 + retval = -ENOMEM; 562 + goto err_bin_file; 614 563 } 615 564 } 616 565 /* add platform-specific attributes */ 617 566 pcibios_add_platform_entries(pdev); 618 - 567 + 619 568 return 0; 569 + 570 + err_rom: 571 + kfree(rom_attr); 572 + err_bin_file: 573 + if (pdev->cfg_size < 4096) 574 + sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr); 575 + else 576 + sysfs_remove_bin_file(&pdev->dev.kobj, &pcie_config_attr); 577 + err: 578 + return retval; 620 579 } 621 580 622 581 /** ··· 660 589 static int __init pci_sysfs_init(void) 661 590 { 662 591 struct pci_dev *pdev = NULL; 663 - 592 + int retval; 593 + 664 594 sysfs_initialized = 1; 665 - for_each_pci_dev(pdev) 666 - pci_create_sysfs_dev_files(pdev); 595 + for_each_pci_dev(pdev) { 596 + retval = pci_create_sysfs_dev_files(pdev); 597 + if (retval) 598 + return retval; 599 + } 667 600 668 601 return 0; 669 602 }
+50
drivers/pci/pci.c
··· 445 445 446 446 EXPORT_SYMBOL(pci_choose_state); 447 447 448 + static int pci_save_pcie_state(struct pci_dev *dev) 449 + { 450 + int pos, i = 0; 451 + struct pci_cap_saved_state *save_state; 452 + u16 *cap; 453 + 454 + pos = pci_find_capability(dev, PCI_CAP_ID_EXP); 455 + if (pos <= 0) 456 + return 0; 457 + 458 + save_state = kzalloc(sizeof(*save_state) + sizeof(u16) * 4, GFP_KERNEL); 459 + if (!save_state) { 460 + dev_err(&dev->dev, "Out of memory in pci_save_pcie_state\n"); 461 + return -ENOMEM; 462 + } 463 + cap = (u16 *)&save_state->data[0]; 464 + 465 + pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &cap[i++]); 466 + pci_read_config_word(dev, pos + PCI_EXP_LNKCTL, &cap[i++]); 467 + pci_read_config_word(dev, pos + PCI_EXP_SLTCTL, &cap[i++]); 468 + pci_read_config_word(dev, pos + PCI_EXP_RTCTL, &cap[i++]); 469 + pci_add_saved_cap(dev, save_state); 470 + return 0; 471 + } 472 + 473 + static void pci_restore_pcie_state(struct pci_dev *dev) 474 + { 475 + int i = 0, pos; 476 + struct pci_cap_saved_state *save_state; 477 + u16 *cap; 478 + 479 + save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP); 480 + pos = pci_find_capability(dev, PCI_CAP_ID_EXP); 481 + if (!save_state || pos <= 0) 482 + return; 483 + cap = (u16 *)&save_state->data[0]; 484 + 485 + pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, cap[i++]); 486 + pci_write_config_word(dev, pos + PCI_EXP_LNKCTL, cap[i++]); 487 + pci_write_config_word(dev, pos + PCI_EXP_SLTCTL, cap[i++]); 488 + pci_write_config_word(dev, pos + PCI_EXP_RTCTL, cap[i++]); 489 + pci_remove_saved_cap(save_state); 490 + kfree(save_state); 491 + } 492 + 448 493 /** 449 494 * pci_save_state - save the PCI configuration space of a device before suspending 450 495 * @dev: - PCI device that we're dealing with ··· 505 460 return i; 506 461 if ((i = pci_save_msix_state(dev)) != 0) 507 462 return i; 463 + if ((i = pci_save_pcie_state(dev)) != 0) 464 + return i; 508 465 return 0; 509 466 } 510 467 ··· 519 472 { 520 473 int i; 521 474 int val; 475 + 476 + /* PCI Express register must be restored first */ 477 + pci_restore_pcie_state(dev); 522 478 523 479 /* 524 480 * The Base Address register should be programmed before the command
+1 -1
drivers/pci/pci.h
··· 42 42 /* Lock for read/write access to pci device and bus lists */ 43 43 extern struct rw_semaphore pci_bus_sem; 44 44 45 - #ifdef CONFIG_X86_IO_APIC 45 + #ifdef CONFIG_PCI_MSI 46 46 extern int pci_msi_quirk; 47 47 #else 48 48 #define pci_msi_quirk 0
+1
drivers/pci/pcie/Kconfig
··· 34 34 35 35 When in doubt, say N. 36 36 37 + source "drivers/pci/pcie/aer/Kconfig"
+3
drivers/pci/pcie/Makefile
··· 5 5 pcieportdrv-y := portdrv_core.o portdrv_pci.o portdrv_bus.o 6 6 7 7 obj-$(CONFIG_PCIEPORTBUS) += pcieportdrv.o 8 + 9 + # Build PCI Express AER if needed 10 + obj-$(CONFIG_PCIEAER) += aer/
+12
drivers/pci/pcie/aer/Kconfig
··· 1 + # 2 + # PCI Express Root Port Device AER Configuration 3 + # 4 + 5 + config PCIEAER 6 + boolean "Root Port Advanced Error Reporting support" 7 + depends on PCIEPORTBUS && ACPI 8 + default y 9 + help 10 + This enables PCI Express Root Port Advanced Error Reporting 11 + (AER) driver support. Error reporting messages sent to Root 12 + Port will be handled by PCI Express AER driver.
+8
drivers/pci/pcie/aer/Makefile
··· 1 + # 2 + # Makefile for PCI-Express Root Port Advanced Error Reporting Driver 3 + # 4 + 5 + obj-$(CONFIG_PCIEAER) += aerdriver.o 6 + 7 + aerdriver-objs := aerdrv_errprint.o aerdrv_core.o aerdrv.o aerdrv_acpi.o 8 +
+346
drivers/pci/pcie/aer/aerdrv.c
··· 1 + /* 2 + * drivers/pci/pcie/aer/aerdrv.c 3 + * 4 + * This file is subject to the terms and conditions of the GNU General Public 5 + * License. See the file "COPYING" in the main directory of this archive 6 + * for more details. 7 + * 8 + * This file implements the AER root port service driver. The driver will 9 + * register an irq handler. When root port triggers an AER interrupt, the irq 10 + * handler will collect root port status and schedule a work. 11 + * 12 + * Copyright (C) 2006 Intel Corp. 13 + * Tom Long Nguyen (tom.l.nguyen@intel.com) 14 + * Zhang Yanmin (yanmin.zhang@intel.com) 15 + * 16 + */ 17 + 18 + #include <linux/module.h> 19 + #include <linux/pci.h> 20 + #include <linux/kernel.h> 21 + #include <linux/errno.h> 22 + #include <linux/pm.h> 23 + #include <linux/init.h> 24 + #include <linux/interrupt.h> 25 + #include <linux/delay.h> 26 + #include <linux/pcieport_if.h> 27 + 28 + #include "aerdrv.h" 29 + 30 + /* 31 + * Version Information 32 + */ 33 + #define DRIVER_VERSION "v1.0" 34 + #define DRIVER_AUTHOR "tom.l.nguyen@intel.com" 35 + #define DRIVER_DESC "Root Port Advanced Error Reporting Driver" 36 + MODULE_AUTHOR(DRIVER_AUTHOR); 37 + MODULE_DESCRIPTION(DRIVER_DESC); 38 + MODULE_LICENSE("GPL"); 39 + 40 + static int __devinit aer_probe (struct pcie_device *dev, 41 + const struct pcie_port_service_id *id ); 42 + static void aer_remove(struct pcie_device *dev); 43 + static int aer_suspend(struct pcie_device *dev, pm_message_t state) 44 + {return 0;} 45 + static int aer_resume(struct pcie_device *dev) {return 0;} 46 + static pci_ers_result_t aer_error_detected(struct pci_dev *dev, 47 + enum pci_channel_state error); 48 + static void aer_error_resume(struct pci_dev *dev); 49 + static pci_ers_result_t aer_root_reset(struct pci_dev *dev); 50 + 51 + /* 52 + * PCI Express bus's AER Root service driver data structure 53 + */ 54 + static struct pcie_port_service_id aer_id[] = { 55 + { 56 + .vendor = PCI_ANY_ID, 57 + .device = PCI_ANY_ID, 58 + .port_type = PCIE_RC_PORT, 59 + .service_type = PCIE_PORT_SERVICE_AER, 60 + }, 61 + { /* end: all zeroes */ } 62 + }; 63 + 64 + static struct pci_error_handlers aer_error_handlers = { 65 + .error_detected = aer_error_detected, 66 + .resume = aer_error_resume, 67 + }; 68 + 69 + static struct pcie_port_service_driver aerdrv = { 70 + .name = "aer", 71 + .id_table = &aer_id[0], 72 + 73 + .probe = aer_probe, 74 + .remove = aer_remove, 75 + 76 + .suspend = aer_suspend, 77 + .resume = aer_resume, 78 + 79 + .err_handler = &aer_error_handlers, 80 + 81 + .reset_link = aer_root_reset, 82 + }; 83 + 84 + /** 85 + * aer_irq - Root Port's ISR 86 + * @irq: IRQ assigned to Root Port 87 + * @context: pointer to Root Port data structure 88 + * @r: pointer struct pt_regs 89 + * 90 + * Invoked when Root Port detects AER messages. 91 + **/ 92 + static irqreturn_t aer_irq(int irq, void *context, struct pt_regs * r) 93 + { 94 + unsigned int status, id; 95 + struct pcie_device *pdev = (struct pcie_device *)context; 96 + struct aer_rpc *rpc = get_service_data(pdev); 97 + int next_prod_idx; 98 + unsigned long flags; 99 + int pos; 100 + 101 + pos = pci_find_aer_capability(pdev->port); 102 + /* 103 + * Must lock access to Root Error Status Reg, Root Error ID Reg, 104 + * and Root error producer/consumer index 105 + */ 106 + spin_lock_irqsave(&rpc->e_lock, flags); 107 + 108 + /* Read error status */ 109 + pci_read_config_dword(pdev->port, pos + PCI_ERR_ROOT_STATUS, &status); 110 + if (!(status & ROOT_ERR_STATUS_MASKS)) { 111 + spin_unlock_irqrestore(&rpc->e_lock, flags); 112 + return IRQ_NONE; 113 + } 114 + 115 + /* Read error source and clear error status */ 116 + pci_read_config_dword(pdev->port, pos + PCI_ERR_ROOT_COR_SRC, &id); 117 + pci_write_config_dword(pdev->port, pos + PCI_ERR_ROOT_STATUS, status); 118 + 119 + /* Store error source for later DPC handler */ 120 + next_prod_idx = rpc->prod_idx + 1; 121 + if (next_prod_idx == AER_ERROR_SOURCES_MAX) 122 + next_prod_idx = 0; 123 + if (next_prod_idx == rpc->cons_idx) { 124 + /* 125 + * Error Storm Condition - possibly the same error occurred. 126 + * Drop the error. 127 + */ 128 + spin_unlock_irqrestore(&rpc->e_lock, flags); 129 + return IRQ_HANDLED; 130 + } 131 + rpc->e_sources[rpc->prod_idx].status = status; 132 + rpc->e_sources[rpc->prod_idx].id = id; 133 + rpc->prod_idx = next_prod_idx; 134 + spin_unlock_irqrestore(&rpc->e_lock, flags); 135 + 136 + /* Invoke DPC handler */ 137 + schedule_work(&rpc->dpc_handler); 138 + 139 + return IRQ_HANDLED; 140 + } 141 + 142 + /** 143 + * aer_alloc_rpc - allocate Root Port data structure 144 + * @dev: pointer to the pcie_dev data structure 145 + * 146 + * Invoked when Root Port's AER service is loaded. 147 + **/ 148 + static struct aer_rpc* aer_alloc_rpc(struct pcie_device *dev) 149 + { 150 + struct aer_rpc *rpc; 151 + 152 + if (!(rpc = (struct aer_rpc *)kmalloc(sizeof(struct aer_rpc), 153 + GFP_KERNEL))) 154 + return NULL; 155 + 156 + memset(rpc, 0, sizeof(struct aer_rpc)); 157 + /* 158 + * Initialize Root lock access, e_lock, to Root Error Status Reg, 159 + * Root Error ID Reg, and Root error producer/consumer index. 160 + */ 161 + rpc->e_lock = SPIN_LOCK_UNLOCKED; 162 + 163 + rpc->rpd = dev; 164 + INIT_WORK(&rpc->dpc_handler, aer_isr, (void *)dev); 165 + rpc->prod_idx = rpc->cons_idx = 0; 166 + mutex_init(&rpc->rpc_mutex); 167 + init_waitqueue_head(&rpc->wait_release); 168 + 169 + /* Use PCIE bus function to store rpc into PCIE device */ 170 + set_service_data(dev, rpc); 171 + 172 + return rpc; 173 + } 174 + 175 + /** 176 + * aer_remove - clean up resources 177 + * @dev: pointer to the pcie_dev data structure 178 + * 179 + * Invoked when PCI Express bus unloads or AER probe fails. 180 + **/ 181 + static void aer_remove(struct pcie_device *dev) 182 + { 183 + struct aer_rpc *rpc = get_service_data(dev); 184 + 185 + if (rpc) { 186 + /* If register interrupt service, it must be free. */ 187 + if (rpc->isr) 188 + free_irq(dev->irq, dev); 189 + 190 + wait_event(rpc->wait_release, rpc->prod_idx == rpc->cons_idx); 191 + 192 + aer_delete_rootport(rpc); 193 + set_service_data(dev, NULL); 194 + } 195 + } 196 + 197 + /** 198 + * aer_probe - initialize resources 199 + * @dev: pointer to the pcie_dev data structure 200 + * @id: pointer to the service id data structure 201 + * 202 + * Invoked when PCI Express bus loads AER service driver. 203 + **/ 204 + static int __devinit aer_probe (struct pcie_device *dev, 205 + const struct pcie_port_service_id *id ) 206 + { 207 + int status; 208 + struct aer_rpc *rpc; 209 + struct device *device = &dev->device; 210 + 211 + /* Init */ 212 + if ((status = aer_init(dev))) 213 + return status; 214 + 215 + /* Alloc rpc data structure */ 216 + if (!(rpc = aer_alloc_rpc(dev))) { 217 + printk(KERN_DEBUG "%s: Alloc rpc fails on PCIE device[%s]\n", 218 + __FUNCTION__, device->bus_id); 219 + aer_remove(dev); 220 + return -ENOMEM; 221 + } 222 + 223 + /* Request IRQ ISR */ 224 + if ((status = request_irq(dev->irq, aer_irq, SA_SHIRQ, "aerdrv", 225 + dev))) { 226 + printk(KERN_DEBUG "%s: Request ISR fails on PCIE device[%s]\n", 227 + __FUNCTION__, device->bus_id); 228 + aer_remove(dev); 229 + return status; 230 + } 231 + 232 + rpc->isr = 1; 233 + 234 + aer_enable_rootport(rpc); 235 + 236 + return status; 237 + } 238 + 239 + /** 240 + * aer_root_reset - reset link on Root Port 241 + * @dev: pointer to Root Port's pci_dev data structure 242 + * 243 + * Invoked by Port Bus driver when performing link reset at Root Port. 244 + **/ 245 + static pci_ers_result_t aer_root_reset(struct pci_dev *dev) 246 + { 247 + u16 p2p_ctrl; 248 + u32 status; 249 + int pos; 250 + 251 + pos = pci_find_aer_capability(dev); 252 + 253 + /* Disable Root's interrupt in response to error messages */ 254 + pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, 0); 255 + 256 + /* Assert Secondary Bus Reset */ 257 + pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &p2p_ctrl); 258 + p2p_ctrl |= PCI_CB_BRIDGE_CTL_CB_RESET; 259 + pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl); 260 + 261 + /* De-assert Secondary Bus Reset */ 262 + p2p_ctrl &= ~PCI_CB_BRIDGE_CTL_CB_RESET; 263 + pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl); 264 + 265 + /* 266 + * System software must wait for at least 100ms from the end 267 + * of a reset of one or more device before it is permitted 268 + * to issue Configuration Requests to those devices. 269 + */ 270 + msleep(200); 271 + printk(KERN_DEBUG "Complete link reset at Root[%s]\n", dev->dev.bus_id); 272 + 273 + /* Enable Root Port's interrupt in response to error messages */ 274 + pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, &status); 275 + pci_write_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, status); 276 + pci_write_config_dword(dev, 277 + pos + PCI_ERR_ROOT_COMMAND, 278 + ROOT_PORT_INTR_ON_MESG_MASK); 279 + 280 + return PCI_ERS_RESULT_RECOVERED; 281 + } 282 + 283 + /** 284 + * aer_error_detected - update severity status 285 + * @dev: pointer to Root Port's pci_dev data structure 286 + * @error: error severity being notified by port bus 287 + * 288 + * Invoked by Port Bus driver during error recovery. 289 + **/ 290 + static pci_ers_result_t aer_error_detected(struct pci_dev *dev, 291 + enum pci_channel_state error) 292 + { 293 + /* Root Port has no impact. Always recovers. */ 294 + return PCI_ERS_RESULT_CAN_RECOVER; 295 + } 296 + 297 + /** 298 + * aer_error_resume - clean up corresponding error status bits 299 + * @dev: pointer to Root Port's pci_dev data structure 300 + * 301 + * Invoked by Port Bus driver during nonfatal recovery. 302 + **/ 303 + static void aer_error_resume(struct pci_dev *dev) 304 + { 305 + int pos; 306 + u32 status, mask; 307 + u16 reg16; 308 + 309 + /* Clean up Root device status */ 310 + pos = pci_find_capability(dev, PCI_CAP_ID_EXP); 311 + pci_read_config_word(dev, pos + PCI_EXP_DEVSTA, &reg16); 312 + pci_write_config_word(dev, pos + PCI_EXP_DEVSTA, reg16); 313 + 314 + /* Clean AER Root Error Status */ 315 + pos = pci_find_aer_capability(dev); 316 + pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status); 317 + pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, &mask); 318 + if (dev->error_state == pci_channel_io_normal) 319 + status &= ~mask; /* Clear corresponding nonfatal bits */ 320 + else 321 + status &= mask; /* Clear corresponding fatal bits */ 322 + pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status); 323 + } 324 + 325 + /** 326 + * aer_service_init - register AER root service driver 327 + * 328 + * Invoked when AER root service driver is loaded. 329 + **/ 330 + static int __init aer_service_init(void) 331 + { 332 + return pcie_port_service_register(&aerdrv); 333 + } 334 + 335 + /** 336 + * aer_service_exit - unregister AER root service driver 337 + * 338 + * Invoked when AER root service driver is unloaded. 339 + **/ 340 + static void __exit aer_service_exit(void) 341 + { 342 + pcie_port_service_unregister(&aerdrv); 343 + } 344 + 345 + module_init(aer_service_init); 346 + module_exit(aer_service_exit);
+125
drivers/pci/pcie/aer/aerdrv.h
··· 1 + /* 2 + * Copyright (C) 2006 Intel Corp. 3 + * Tom Long Nguyen (tom.l.nguyen@intel.com) 4 + * Zhang Yanmin (yanmin.zhang@intel.com) 5 + * 6 + */ 7 + 8 + #ifndef _AERDRV_H_ 9 + #define _AERDRV_H_ 10 + 11 + #include <linux/pcieport_if.h> 12 + #include <linux/aer.h> 13 + 14 + #define AER_NONFATAL 0 15 + #define AER_FATAL 1 16 + #define AER_CORRECTABLE 2 17 + #define AER_UNCORRECTABLE 4 18 + #define AER_ERROR_MASK 0x001fffff 19 + #define AER_ERROR(d) (d & AER_ERROR_MASK) 20 + 21 + #define OSC_METHOD_RUN_SUCCESS 0 22 + #define OSC_METHOD_NOT_SUPPORTED 1 23 + #define OSC_METHOD_RUN_FAILURE 2 24 + 25 + /* Root Error Status Register Bits */ 26 + #define ROOT_ERR_STATUS_MASKS 0x0f 27 + 28 + #define SYSTEM_ERROR_INTR_ON_MESG_MASK (PCI_EXP_RTCTL_SECEE| \ 29 + PCI_EXP_RTCTL_SENFEE| \ 30 + PCI_EXP_RTCTL_SEFEE) 31 + #define ROOT_PORT_INTR_ON_MESG_MASK (PCI_ERR_ROOT_CMD_COR_EN| \ 32 + PCI_ERR_ROOT_CMD_NONFATAL_EN| \ 33 + PCI_ERR_ROOT_CMD_FATAL_EN) 34 + #define ERR_COR_ID(d) (d & 0xffff) 35 + #define ERR_UNCOR_ID(d) (d >> 16) 36 + 37 + #define AER_SUCCESS 0 38 + #define AER_UNSUCCESS 1 39 + #define AER_ERROR_SOURCES_MAX 100 40 + 41 + #define AER_LOG_TLP_MASKS (PCI_ERR_UNC_POISON_TLP| \ 42 + PCI_ERR_UNC_ECRC| \ 43 + PCI_ERR_UNC_UNSUP| \ 44 + PCI_ERR_UNC_COMP_ABORT| \ 45 + PCI_ERR_UNC_UNX_COMP| \ 46 + PCI_ERR_UNC_MALF_TLP) 47 + 48 + /* AER Error Info Flags */ 49 + #define AER_TLP_HEADER_VALID_FLAG 0x00000001 50 + #define AER_MULTI_ERROR_VALID_FLAG 0x00000002 51 + 52 + #define ERR_CORRECTABLE_ERROR_MASK 0x000031c1 53 + #define ERR_UNCORRECTABLE_ERROR_MASK 0x001ff010 54 + 55 + struct header_log_regs { 56 + unsigned int dw0; 57 + unsigned int dw1; 58 + unsigned int dw2; 59 + unsigned int dw3; 60 + }; 61 + 62 + struct aer_err_info { 63 + int severity; /* 0:NONFATAL | 1:FATAL | 2:COR */ 64 + int flags; 65 + unsigned int status; /* COR/UNCOR Error Status */ 66 + struct header_log_regs tlp; /* TLP Header */ 67 + }; 68 + 69 + struct aer_err_source { 70 + unsigned int status; 71 + unsigned int id; 72 + }; 73 + 74 + struct aer_rpc { 75 + struct pcie_device *rpd; /* Root Port device */ 76 + struct work_struct dpc_handler; 77 + struct aer_err_source e_sources[AER_ERROR_SOURCES_MAX]; 78 + unsigned short prod_idx; /* Error Producer Index */ 79 + unsigned short cons_idx; /* Error Consumer Index */ 80 + int isr; 81 + spinlock_t e_lock; /* 82 + * Lock access to Error Status/ID Regs 83 + * and error producer/consumer index 84 + */ 85 + struct mutex rpc_mutex; /* 86 + * only one thread could do 87 + * recovery on the same 88 + * root port hierachy 89 + */ 90 + wait_queue_head_t wait_release; 91 + }; 92 + 93 + struct aer_broadcast_data { 94 + enum pci_channel_state state; 95 + enum pci_ers_result result; 96 + }; 97 + 98 + static inline pci_ers_result_t merge_result(enum pci_ers_result orig, 99 + enum pci_ers_result new) 100 + { 101 + switch (orig) { 102 + case PCI_ERS_RESULT_CAN_RECOVER: 103 + case PCI_ERS_RESULT_RECOVERED: 104 + orig = new; 105 + break; 106 + case PCI_ERS_RESULT_DISCONNECT: 107 + if (new == PCI_ERS_RESULT_NEED_RESET) 108 + orig = new; 109 + break; 110 + default: 111 + break; 112 + } 113 + 114 + return orig; 115 + } 116 + 117 + extern struct bus_type pcie_port_bus_type; 118 + extern void aer_enable_rootport(struct aer_rpc *rpc); 119 + extern void aer_delete_rootport(struct aer_rpc *rpc); 120 + extern int aer_init(struct pcie_device *dev); 121 + extern void aer_isr(void *context); 122 + extern void aer_print_error(struct pci_dev *dev, struct aer_err_info *info); 123 + extern int aer_osc_setup(struct pci_dev *dev); 124 + 125 + #endif //_AERDRV_H_
+68
drivers/pci/pcie/aer/aerdrv_acpi.c
··· 1 + /* 2 + * Access ACPI _OSC method 3 + * 4 + * Copyright (C) 2006 Intel Corp. 5 + * Tom Long Nguyen (tom.l.nguyen@intel.com) 6 + * Zhang Yanmin (yanmin.zhang@intel.com) 7 + * 8 + */ 9 + 10 + #include <linux/module.h> 11 + #include <linux/pci.h> 12 + #include <linux/kernel.h> 13 + #include <linux/errno.h> 14 + #include <linux/pm.h> 15 + #include <linux/suspend.h> 16 + #include <linux/acpi.h> 17 + #include <linux/pci-acpi.h> 18 + #include <linux/delay.h> 19 + #include "aerdrv.h" 20 + 21 + /** 22 + * aer_osc_setup - run ACPI _OSC method 23 + * 24 + * Return: 25 + * Zero if success. Nonzero for otherwise. 26 + * 27 + * Invoked when PCIE bus loads AER service driver. To avoid conflict with 28 + * BIOS AER support requires BIOS to yield AER control to OS native driver. 29 + **/ 30 + int aer_osc_setup(struct pci_dev *dev) 31 + { 32 + int retval = OSC_METHOD_RUN_SUCCESS; 33 + acpi_status status; 34 + acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->dev); 35 + struct pci_dev *pdev = dev; 36 + struct pci_bus *parent; 37 + 38 + while (!handle) { 39 + if (!pdev || !pdev->bus->parent) 40 + break; 41 + parent = pdev->bus->parent; 42 + if (!parent->self) 43 + /* Parent must be a host bridge */ 44 + handle = acpi_get_pci_rootbridge_handle( 45 + pci_domain_nr(parent), 46 + parent->number); 47 + else 48 + handle = DEVICE_ACPI_HANDLE( 49 + &(parent->self->dev)); 50 + pdev = parent->self; 51 + } 52 + 53 + if (!handle) 54 + return OSC_METHOD_NOT_SUPPORTED; 55 + 56 + pci_osc_support_set(OSC_EXT_PCI_CONFIG_SUPPORT); 57 + status = pci_osc_control_set(handle, OSC_PCI_EXPRESS_AER_CONTROL | 58 + OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL); 59 + if (ACPI_FAILURE(status)) { 60 + if (status == AE_SUPPORT) 61 + retval = OSC_METHOD_NOT_SUPPORTED; 62 + else 63 + retval = OSC_METHOD_RUN_FAILURE; 64 + } 65 + 66 + return retval; 67 + } 68 +
+758
drivers/pci/pcie/aer/aerdrv_core.c
··· 1 + /* 2 + * drivers/pci/pcie/aer/aerdrv_core.c 3 + * 4 + * This file is subject to the terms and conditions of the GNU General Public 5 + * License. See the file "COPYING" in the main directory of this archive 6 + * for more details. 7 + * 8 + * This file implements the core part of PCI-Express AER. When an pci-express 9 + * error is delivered, an error message will be collected and printed to 10 + * console, then, an error recovery procedure will be executed by following 11 + * the pci error recovery rules. 12 + * 13 + * Copyright (C) 2006 Intel Corp. 14 + * Tom Long Nguyen (tom.l.nguyen@intel.com) 15 + * Zhang Yanmin (yanmin.zhang@intel.com) 16 + * 17 + */ 18 + 19 + #include <linux/module.h> 20 + #include <linux/pci.h> 21 + #include <linux/kernel.h> 22 + #include <linux/errno.h> 23 + #include <linux/pm.h> 24 + #include <linux/suspend.h> 25 + #include <linux/acpi.h> 26 + #include <linux/pci-acpi.h> 27 + #include <linux/delay.h> 28 + #include "aerdrv.h" 29 + 30 + static int forceload; 31 + module_param(forceload, bool, 0); 32 + 33 + #define PCI_CFG_SPACE_SIZE (0x100) 34 + int pci_find_aer_capability(struct pci_dev *dev) 35 + { 36 + int pos; 37 + u32 reg32 = 0; 38 + 39 + /* Check if it's a pci-express device */ 40 + pos = pci_find_capability(dev, PCI_CAP_ID_EXP); 41 + if (!pos) 42 + return 0; 43 + 44 + /* Check if it supports pci-express AER */ 45 + pos = PCI_CFG_SPACE_SIZE; 46 + while (pos) { 47 + if (pci_read_config_dword(dev, pos, &reg32)) 48 + return 0; 49 + 50 + /* some broken boards return ~0 */ 51 + if (reg32 == 0xffffffff) 52 + return 0; 53 + 54 + if (PCI_EXT_CAP_ID(reg32) == PCI_EXT_CAP_ID_ERR) 55 + break; 56 + 57 + pos = reg32 >> 20; 58 + } 59 + 60 + return pos; 61 + } 62 + 63 + int pci_enable_pcie_error_reporting(struct pci_dev *dev) 64 + { 65 + u16 reg16 = 0; 66 + int pos; 67 + 68 + pos = pci_find_capability(dev, PCI_CAP_ID_EXP); 69 + if (!pos) 70 + return -EIO; 71 + 72 + pci_read_config_word(dev, pos+PCI_EXP_DEVCTL, &reg16); 73 + reg16 = reg16 | 74 + PCI_EXP_DEVCTL_CERE | 75 + PCI_EXP_DEVCTL_NFERE | 76 + PCI_EXP_DEVCTL_FERE | 77 + PCI_EXP_DEVCTL_URRE; 78 + pci_write_config_word(dev, pos+PCI_EXP_DEVCTL, 79 + reg16); 80 + return 0; 81 + } 82 + 83 + int pci_disable_pcie_error_reporting(struct pci_dev *dev) 84 + { 85 + u16 reg16 = 0; 86 + int pos; 87 + 88 + pos = pci_find_capability(dev, PCI_CAP_ID_EXP); 89 + if (!pos) 90 + return -EIO; 91 + 92 + pci_read_config_word(dev, pos+PCI_EXP_DEVCTL, &reg16); 93 + reg16 = reg16 & ~(PCI_EXP_DEVCTL_CERE | 94 + PCI_EXP_DEVCTL_NFERE | 95 + PCI_EXP_DEVCTL_FERE | 96 + PCI_EXP_DEVCTL_URRE); 97 + pci_write_config_word(dev, pos+PCI_EXP_DEVCTL, 98 + reg16); 99 + return 0; 100 + } 101 + 102 + int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev) 103 + { 104 + int pos; 105 + u32 status, mask; 106 + 107 + pos = pci_find_aer_capability(dev); 108 + if (!pos) 109 + return -EIO; 110 + 111 + pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status); 112 + pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, &mask); 113 + if (dev->error_state == pci_channel_io_normal) 114 + status &= ~mask; /* Clear corresponding nonfatal bits */ 115 + else 116 + status &= mask; /* Clear corresponding fatal bits */ 117 + pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status); 118 + 119 + return 0; 120 + } 121 + 122 + static int find_device_iter(struct device *device, void *data) 123 + { 124 + struct pci_dev *dev; 125 + u16 id = *(unsigned long *)data; 126 + u8 secondary, subordinate, d_bus = id >> 8; 127 + 128 + if (device->bus == &pci_bus_type) { 129 + dev = to_pci_dev(device); 130 + if (id == ((dev->bus->number << 8) | dev->devfn)) { 131 + /* 132 + * Device ID match 133 + */ 134 + *(unsigned long*)data = (unsigned long)device; 135 + return 1; 136 + } 137 + 138 + /* 139 + * If device is P2P, check if it is an upstream? 140 + */ 141 + if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE) { 142 + pci_read_config_byte(dev, PCI_SECONDARY_BUS, 143 + &secondary); 144 + pci_read_config_byte(dev, PCI_SUBORDINATE_BUS, 145 + &subordinate); 146 + if (d_bus >= secondary && d_bus <= subordinate) { 147 + *(unsigned long*)data = (unsigned long)device; 148 + return 1; 149 + } 150 + } 151 + } 152 + 153 + return 0; 154 + } 155 + 156 + /** 157 + * find_source_device - search through device hierarchy for source device 158 + * @p_dev: pointer to Root Port pci_dev data structure 159 + * @id: device ID of agent who sends an error message to this Root Port 160 + * 161 + * Invoked when error is detected at the Root Port. 162 + **/ 163 + static struct device* find_source_device(struct pci_dev *parent, u16 id) 164 + { 165 + struct pci_dev *dev = parent; 166 + struct device *device; 167 + unsigned long device_addr; 168 + int status; 169 + 170 + /* Is Root Port an agent that sends error message? */ 171 + if (id == ((dev->bus->number << 8) | dev->devfn)) 172 + return &dev->dev; 173 + 174 + do { 175 + device_addr = id; 176 + if ((status = device_for_each_child(&dev->dev, 177 + &device_addr, find_device_iter))) { 178 + device = (struct device*)device_addr; 179 + dev = to_pci_dev(device); 180 + if (id == ((dev->bus->number << 8) | dev->devfn)) 181 + return device; 182 + } 183 + }while (status); 184 + 185 + return NULL; 186 + } 187 + 188 + static void report_error_detected(struct pci_dev *dev, void *data) 189 + { 190 + pci_ers_result_t vote; 191 + struct pci_error_handlers *err_handler; 192 + struct aer_broadcast_data *result_data; 193 + result_data = (struct aer_broadcast_data *) data; 194 + 195 + dev->error_state = result_data->state; 196 + 197 + if (!dev->driver || 198 + !dev->driver->err_handler || 199 + !dev->driver->err_handler->error_detected) { 200 + if (result_data->state == pci_channel_io_frozen && 201 + !(dev->hdr_type & PCI_HEADER_TYPE_BRIDGE)) { 202 + /* 203 + * In case of fatal recovery, if one of down- 204 + * stream device has no driver. We might be 205 + * unable to recover because a later insmod 206 + * of a driver for this device is unaware of 207 + * its hw state. 208 + */ 209 + printk(KERN_DEBUG "Device ID[%s] has %s\n", 210 + dev->dev.bus_id, (dev->driver) ? 211 + "no AER-aware driver" : "no driver"); 212 + } 213 + return; 214 + } 215 + 216 + err_handler = dev->driver->err_handler; 217 + vote = err_handler->error_detected(dev, result_data->state); 218 + result_data->result = merge_result(result_data->result, vote); 219 + return; 220 + } 221 + 222 + static void report_mmio_enabled(struct pci_dev *dev, void *data) 223 + { 224 + pci_ers_result_t vote; 225 + struct pci_error_handlers *err_handler; 226 + struct aer_broadcast_data *result_data; 227 + result_data = (struct aer_broadcast_data *) data; 228 + 229 + if (!dev->driver || 230 + !dev->driver->err_handler || 231 + !dev->driver->err_handler->mmio_enabled) 232 + return; 233 + 234 + err_handler = dev->driver->err_handler; 235 + vote = err_handler->mmio_enabled(dev); 236 + result_data->result = merge_result(result_data->result, vote); 237 + return; 238 + } 239 + 240 + static void report_slot_reset(struct pci_dev *dev, void *data) 241 + { 242 + pci_ers_result_t vote; 243 + struct pci_error_handlers *err_handler; 244 + struct aer_broadcast_data *result_data; 245 + result_data = (struct aer_broadcast_data *) data; 246 + 247 + if (!dev->driver || 248 + !dev->driver->err_handler || 249 + !dev->driver->err_handler->slot_reset) 250 + return; 251 + 252 + err_handler = dev->driver->err_handler; 253 + vote = err_handler->slot_reset(dev); 254 + result_data->result = merge_result(result_data->result, vote); 255 + return; 256 + } 257 + 258 + static void report_resume(struct pci_dev *dev, void *data) 259 + { 260 + struct pci_error_handlers *err_handler; 261 + 262 + dev->error_state = pci_channel_io_normal; 263 + 264 + if (!dev->driver || 265 + !dev->driver->err_handler || 266 + !dev->driver->err_handler->slot_reset) 267 + return; 268 + 269 + err_handler = dev->driver->err_handler; 270 + err_handler->resume(dev); 271 + return; 272 + } 273 + 274 + /** 275 + * broadcast_error_message - handle message broadcast to downstream drivers 276 + * @device: pointer to from where in a hierarchy message is broadcasted down 277 + * @api: callback to be broadcasted 278 + * @state: error state 279 + * 280 + * Invoked during error recovery process. Once being invoked, the content 281 + * of error severity will be broadcasted to all downstream drivers in a 282 + * hierarchy in question. 283 + **/ 284 + static pci_ers_result_t broadcast_error_message(struct pci_dev *dev, 285 + enum pci_channel_state state, 286 + char *error_mesg, 287 + void (*cb)(struct pci_dev *, void *)) 288 + { 289 + struct aer_broadcast_data result_data; 290 + 291 + printk(KERN_DEBUG "Broadcast %s message\n", error_mesg); 292 + result_data.state = state; 293 + if (cb == report_error_detected) 294 + result_data.result = PCI_ERS_RESULT_CAN_RECOVER; 295 + else 296 + result_data.result = PCI_ERS_RESULT_RECOVERED; 297 + 298 + if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE) { 299 + /* 300 + * If the error is reported by a bridge, we think this error 301 + * is related to the downstream link of the bridge, so we 302 + * do error recovery on all subordinates of the bridge instead 303 + * of the bridge and clear the error status of the bridge. 304 + */ 305 + if (cb == report_error_detected) 306 + dev->error_state = state; 307 + pci_walk_bus(dev->subordinate, cb, &result_data); 308 + if (cb == report_resume) { 309 + pci_cleanup_aer_uncorrect_error_status(dev); 310 + dev->error_state = pci_channel_io_normal; 311 + } 312 + } 313 + else { 314 + /* 315 + * If the error is reported by an end point, we think this 316 + * error is related to the upstream link of the end point. 317 + */ 318 + pci_walk_bus(dev->bus, cb, &result_data); 319 + } 320 + 321 + return result_data.result; 322 + } 323 + 324 + struct find_aer_service_data { 325 + struct pcie_port_service_driver *aer_driver; 326 + int is_downstream; 327 + }; 328 + 329 + static int find_aer_service_iter(struct device *device, void *data) 330 + { 331 + struct device_driver *driver; 332 + struct pcie_port_service_driver *service_driver; 333 + struct pcie_device *pcie_dev; 334 + struct find_aer_service_data *result; 335 + 336 + result = (struct find_aer_service_data *) data; 337 + 338 + if (device->bus == &pcie_port_bus_type) { 339 + pcie_dev = to_pcie_device(device); 340 + if (pcie_dev->id.port_type == PCIE_SW_DOWNSTREAM_PORT) 341 + result->is_downstream = 1; 342 + 343 + driver = device->driver; 344 + if (driver) { 345 + service_driver = to_service_driver(driver); 346 + if (service_driver->id_table->service_type == 347 + PCIE_PORT_SERVICE_AER) { 348 + result->aer_driver = service_driver; 349 + return 1; 350 + } 351 + } 352 + } 353 + 354 + return 0; 355 + } 356 + 357 + static void find_aer_service(struct pci_dev *dev, 358 + struct find_aer_service_data *data) 359 + { 360 + int retval; 361 + retval = device_for_each_child(&dev->dev, data, find_aer_service_iter); 362 + } 363 + 364 + static pci_ers_result_t reset_link(struct pcie_device *aerdev, 365 + struct pci_dev *dev) 366 + { 367 + struct pci_dev *udev; 368 + pci_ers_result_t status; 369 + struct find_aer_service_data data; 370 + 371 + if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE) 372 + udev = dev; 373 + else 374 + udev= dev->bus->self; 375 + 376 + data.is_downstream = 0; 377 + data.aer_driver = NULL; 378 + find_aer_service(udev, &data); 379 + 380 + /* 381 + * Use the aer driver of the error agent firstly. 382 + * If it hasn't the aer driver, use the root port's 383 + */ 384 + if (!data.aer_driver || !data.aer_driver->reset_link) { 385 + if (data.is_downstream && 386 + aerdev->device.driver && 387 + to_service_driver(aerdev->device.driver)->reset_link) { 388 + data.aer_driver = 389 + to_service_driver(aerdev->device.driver); 390 + } else { 391 + printk(KERN_DEBUG "No link-reset support to Device ID" 392 + "[%s]\n", 393 + dev->dev.bus_id); 394 + return PCI_ERS_RESULT_DISCONNECT; 395 + } 396 + } 397 + 398 + status = data.aer_driver->reset_link(udev); 399 + if (status != PCI_ERS_RESULT_RECOVERED) { 400 + printk(KERN_DEBUG "Link reset at upstream Device ID" 401 + "[%s] failed\n", 402 + udev->dev.bus_id); 403 + return PCI_ERS_RESULT_DISCONNECT; 404 + } 405 + 406 + return status; 407 + } 408 + 409 + /** 410 + * do_recovery - handle nonfatal/fatal error recovery process 411 + * @aerdev: pointer to a pcie_device data structure of root port 412 + * @dev: pointer to a pci_dev data structure of agent detecting an error 413 + * @severity: error severity type 414 + * 415 + * Invoked when an error is nonfatal/fatal. Once being invoked, broadcast 416 + * error detected message to all downstream drivers within a hierarchy in 417 + * question and return the returned code. 418 + **/ 419 + static pci_ers_result_t do_recovery(struct pcie_device *aerdev, 420 + struct pci_dev *dev, 421 + int severity) 422 + { 423 + pci_ers_result_t status, result = PCI_ERS_RESULT_RECOVERED; 424 + enum pci_channel_state state; 425 + 426 + if (severity == AER_FATAL) 427 + state = pci_channel_io_frozen; 428 + else 429 + state = pci_channel_io_normal; 430 + 431 + status = broadcast_error_message(dev, 432 + state, 433 + "error_detected", 434 + report_error_detected); 435 + 436 + if (severity == AER_FATAL) { 437 + result = reset_link(aerdev, dev); 438 + if (result != PCI_ERS_RESULT_RECOVERED) { 439 + /* TODO: Should panic here? */ 440 + return result; 441 + } 442 + } 443 + 444 + if (status == PCI_ERS_RESULT_CAN_RECOVER) 445 + status = broadcast_error_message(dev, 446 + state, 447 + "mmio_enabled", 448 + report_mmio_enabled); 449 + 450 + if (status == PCI_ERS_RESULT_NEED_RESET) { 451 + /* 452 + * TODO: Should call platform-specific 453 + * functions to reset slot before calling 454 + * drivers' slot_reset callbacks? 455 + */ 456 + status = broadcast_error_message(dev, 457 + state, 458 + "slot_reset", 459 + report_slot_reset); 460 + } 461 + 462 + if (status == PCI_ERS_RESULT_RECOVERED) 463 + broadcast_error_message(dev, 464 + state, 465 + "resume", 466 + report_resume); 467 + 468 + return status; 469 + } 470 + 471 + /** 472 + * handle_error_source - handle logging error into an event log 473 + * @aerdev: pointer to pcie_device data structure of the root port 474 + * @dev: pointer to pci_dev data structure of error source device 475 + * @info: comprehensive error information 476 + * 477 + * Invoked when an error being detected by Root Port. 478 + **/ 479 + static void handle_error_source(struct pcie_device * aerdev, 480 + struct pci_dev *dev, 481 + struct aer_err_info info) 482 + { 483 + pci_ers_result_t status = 0; 484 + int pos; 485 + 486 + if (info.severity == AER_CORRECTABLE) { 487 + /* 488 + * Correctable error does not need software intevention. 489 + * No need to go through error recovery process. 490 + */ 491 + pos = pci_find_aer_capability(dev); 492 + if (pos) 493 + pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS, 494 + info.status); 495 + } else { 496 + status = do_recovery(aerdev, dev, info.severity); 497 + if (status == PCI_ERS_RESULT_RECOVERED) { 498 + printk(KERN_DEBUG "AER driver successfully recovered\n"); 499 + } else { 500 + /* TODO: Should kernel panic here? */ 501 + printk(KERN_DEBUG "AER driver didn't recover\n"); 502 + } 503 + } 504 + } 505 + 506 + /** 507 + * aer_enable_rootport - enable Root Port's interrupts when receiving messages 508 + * @rpc: pointer to a Root Port data structure 509 + * 510 + * Invoked when PCIE bus loads AER service driver. 511 + **/ 512 + void aer_enable_rootport(struct aer_rpc *rpc) 513 + { 514 + struct pci_dev *pdev = rpc->rpd->port; 515 + int pos, aer_pos; 516 + u16 reg16; 517 + u32 reg32; 518 + 519 + pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); 520 + /* Clear PCIE Capability's Device Status */ 521 + pci_read_config_word(pdev, pos+PCI_EXP_DEVSTA, &reg16); 522 + pci_write_config_word(pdev, pos+PCI_EXP_DEVSTA, reg16); 523 + 524 + /* Disable system error generation in response to error messages */ 525 + pci_read_config_word(pdev, pos + PCI_EXP_RTCTL, &reg16); 526 + reg16 &= ~(SYSTEM_ERROR_INTR_ON_MESG_MASK); 527 + pci_write_config_word(pdev, pos + PCI_EXP_RTCTL, reg16); 528 + 529 + aer_pos = pci_find_aer_capability(pdev); 530 + /* Clear error status */ 531 + pci_read_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, &reg32); 532 + pci_write_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, reg32); 533 + pci_read_config_dword(pdev, aer_pos + PCI_ERR_COR_STATUS, &reg32); 534 + pci_write_config_dword(pdev, aer_pos + PCI_ERR_COR_STATUS, reg32); 535 + pci_read_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, &reg32); 536 + pci_write_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, reg32); 537 + 538 + /* Enable Root Port device reporting error itself */ 539 + pci_read_config_word(pdev, pos+PCI_EXP_DEVCTL, &reg16); 540 + reg16 = reg16 | 541 + PCI_EXP_DEVCTL_CERE | 542 + PCI_EXP_DEVCTL_NFERE | 543 + PCI_EXP_DEVCTL_FERE | 544 + PCI_EXP_DEVCTL_URRE; 545 + pci_write_config_word(pdev, pos+PCI_EXP_DEVCTL, 546 + reg16); 547 + 548 + /* Enable Root Port's interrupt in response to error messages */ 549 + pci_write_config_dword(pdev, 550 + aer_pos + PCI_ERR_ROOT_COMMAND, 551 + ROOT_PORT_INTR_ON_MESG_MASK); 552 + } 553 + 554 + /** 555 + * disable_root_aer - disable Root Port's interrupts when receiving messages 556 + * @rpc: pointer to a Root Port data structure 557 + * 558 + * Invoked when PCIE bus unloads AER service driver. 559 + **/ 560 + static void disable_root_aer(struct aer_rpc *rpc) 561 + { 562 + struct pci_dev *pdev = rpc->rpd->port; 563 + u32 reg32; 564 + int pos; 565 + 566 + pos = pci_find_aer_capability(pdev); 567 + /* Disable Root's interrupt in response to error messages */ 568 + pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_COMMAND, 0); 569 + 570 + /* Clear Root's error status reg */ 571 + pci_read_config_dword(pdev, pos + PCI_ERR_ROOT_STATUS, &reg32); 572 + pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_STATUS, reg32); 573 + } 574 + 575 + /** 576 + * get_e_source - retrieve an error source 577 + * @rpc: pointer to the root port which holds an error 578 + * 579 + * Invoked by DPC handler to consume an error. 580 + **/ 581 + static struct aer_err_source* get_e_source(struct aer_rpc *rpc) 582 + { 583 + struct aer_err_source *e_source; 584 + unsigned long flags; 585 + 586 + /* Lock access to Root error producer/consumer index */ 587 + spin_lock_irqsave(&rpc->e_lock, flags); 588 + if (rpc->prod_idx == rpc->cons_idx) { 589 + spin_unlock_irqrestore(&rpc->e_lock, flags); 590 + return NULL; 591 + } 592 + e_source = &rpc->e_sources[rpc->cons_idx]; 593 + rpc->cons_idx++; 594 + if (rpc->cons_idx == AER_ERROR_SOURCES_MAX) 595 + rpc->cons_idx = 0; 596 + spin_unlock_irqrestore(&rpc->e_lock, flags); 597 + 598 + return e_source; 599 + } 600 + 601 + static int get_device_error_info(struct pci_dev *dev, struct aer_err_info *info) 602 + { 603 + int pos; 604 + 605 + pos = pci_find_aer_capability(dev); 606 + 607 + /* The device might not support AER */ 608 + if (!pos) 609 + return AER_SUCCESS; 610 + 611 + if (info->severity == AER_CORRECTABLE) { 612 + pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS, 613 + &info->status); 614 + if (!(info->status & ERR_CORRECTABLE_ERROR_MASK)) 615 + return AER_UNSUCCESS; 616 + } else if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE || 617 + info->severity == AER_NONFATAL) { 618 + 619 + /* Link is still healthy for IO reads */ 620 + pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, 621 + &info->status); 622 + if (!(info->status & ERR_UNCORRECTABLE_ERROR_MASK)) 623 + return AER_UNSUCCESS; 624 + 625 + if (info->status & AER_LOG_TLP_MASKS) { 626 + info->flags |= AER_TLP_HEADER_VALID_FLAG; 627 + pci_read_config_dword(dev, 628 + pos + PCI_ERR_HEADER_LOG, &info->tlp.dw0); 629 + pci_read_config_dword(dev, 630 + pos + PCI_ERR_HEADER_LOG + 4, &info->tlp.dw1); 631 + pci_read_config_dword(dev, 632 + pos + PCI_ERR_HEADER_LOG + 8, &info->tlp.dw2); 633 + pci_read_config_dword(dev, 634 + pos + PCI_ERR_HEADER_LOG + 12, &info->tlp.dw3); 635 + } 636 + } 637 + 638 + return AER_SUCCESS; 639 + } 640 + 641 + /** 642 + * aer_isr_one_error - consume an error detected by root port 643 + * @p_device: pointer to error root port service device 644 + * @e_src: pointer to an error source 645 + **/ 646 + static void aer_isr_one_error(struct pcie_device *p_device, 647 + struct aer_err_source *e_src) 648 + { 649 + struct device *s_device; 650 + struct aer_err_info e_info = {0, 0, 0,}; 651 + int i; 652 + u16 id; 653 + 654 + /* 655 + * There is a possibility that both correctable error and 656 + * uncorrectable error being logged. Report correctable error first. 657 + */ 658 + for (i = 1; i & ROOT_ERR_STATUS_MASKS ; i <<= 2) { 659 + if (i > 4) 660 + break; 661 + if (!(e_src->status & i)) 662 + continue; 663 + 664 + /* Init comprehensive error information */ 665 + if (i & PCI_ERR_ROOT_COR_RCV) { 666 + id = ERR_COR_ID(e_src->id); 667 + e_info.severity = AER_CORRECTABLE; 668 + } else { 669 + id = ERR_UNCOR_ID(e_src->id); 670 + e_info.severity = ((e_src->status >> 6) & 1); 671 + } 672 + if (e_src->status & 673 + (PCI_ERR_ROOT_MULTI_COR_RCV | 674 + PCI_ERR_ROOT_MULTI_UNCOR_RCV)) 675 + e_info.flags |= AER_MULTI_ERROR_VALID_FLAG; 676 + if (!(s_device = find_source_device(p_device->port, id))) { 677 + printk(KERN_DEBUG "%s->can't find device of ID%04x\n", 678 + __FUNCTION__, id); 679 + continue; 680 + } 681 + if (get_device_error_info(to_pci_dev(s_device), &e_info) == 682 + AER_SUCCESS) { 683 + aer_print_error(to_pci_dev(s_device), &e_info); 684 + handle_error_source(p_device, 685 + to_pci_dev(s_device), 686 + e_info); 687 + } 688 + } 689 + } 690 + 691 + /** 692 + * aer_isr - consume errors detected by root port 693 + * @context: pointer to a private data of pcie device 694 + * 695 + * Invoked, as DPC, when root port records new detected error 696 + **/ 697 + void aer_isr(void *context) 698 + { 699 + struct pcie_device *p_device = (struct pcie_device *) context; 700 + struct aer_rpc *rpc = get_service_data(p_device); 701 + struct aer_err_source *e_src; 702 + 703 + mutex_lock(&rpc->rpc_mutex); 704 + e_src = get_e_source(rpc); 705 + while (e_src) { 706 + aer_isr_one_error(p_device, e_src); 707 + e_src = get_e_source(rpc); 708 + } 709 + mutex_unlock(&rpc->rpc_mutex); 710 + 711 + wake_up(&rpc->wait_release); 712 + } 713 + 714 + /** 715 + * aer_delete_rootport - disable root port aer and delete service data 716 + * @rpc: pointer to a root port device being deleted 717 + * 718 + * Invoked when AER service unloaded on a specific Root Port 719 + **/ 720 + void aer_delete_rootport(struct aer_rpc *rpc) 721 + { 722 + /* Disable root port AER itself */ 723 + disable_root_aer(rpc); 724 + 725 + kfree(rpc); 726 + } 727 + 728 + /** 729 + * aer_init - provide AER initialization 730 + * @dev: pointer to AER pcie device 731 + * 732 + * Invoked when AER service driver is loaded. 733 + **/ 734 + int aer_init(struct pcie_device *dev) 735 + { 736 + int status; 737 + 738 + /* Run _OSC Method */ 739 + status = aer_osc_setup(dev->port); 740 + 741 + if(status != OSC_METHOD_RUN_SUCCESS) { 742 + printk(KERN_DEBUG "%s: AER service init fails - %s\n", 743 + __FUNCTION__, 744 + (status == OSC_METHOD_NOT_SUPPORTED) ? 745 + "No ACPI _OSC support" : "Run ACPI _OSC fails"); 746 + 747 + if (!forceload) 748 + return status; 749 + } 750 + 751 + return AER_SUCCESS; 752 + } 753 + 754 + EXPORT_SYMBOL_GPL(pci_find_aer_capability); 755 + EXPORT_SYMBOL_GPL(pci_enable_pcie_error_reporting); 756 + EXPORT_SYMBOL_GPL(pci_disable_pcie_error_reporting); 757 + EXPORT_SYMBOL_GPL(pci_cleanup_aer_uncorrect_error_status); 758 +
+248
drivers/pci/pcie/aer/aerdrv_errprint.c
··· 1 + /* 2 + * drivers/pci/pcie/aer/aerdrv_errprint.c 3 + * 4 + * This file is subject to the terms and conditions of the GNU General Public 5 + * License. See the file "COPYING" in the main directory of this archive 6 + * for more details. 7 + * 8 + * Format error messages and print them to console. 9 + * 10 + * Copyright (C) 2006 Intel Corp. 11 + * Tom Long Nguyen (tom.l.nguyen@intel.com) 12 + * Zhang Yanmin (yanmin.zhang@intel.com) 13 + * 14 + */ 15 + 16 + #include <linux/module.h> 17 + #include <linux/pci.h> 18 + #include <linux/kernel.h> 19 + #include <linux/errno.h> 20 + #include <linux/pm.h> 21 + #include <linux/suspend.h> 22 + 23 + #include "aerdrv.h" 24 + 25 + #define AER_AGENT_RECEIVER 0 26 + #define AER_AGENT_REQUESTER 1 27 + #define AER_AGENT_COMPLETER 2 28 + #define AER_AGENT_TRANSMITTER 3 29 + 30 + #define AER_AGENT_REQUESTER_MASK (PCI_ERR_UNC_COMP_TIME| \ 31 + PCI_ERR_UNC_UNSUP) 32 + 33 + #define AER_AGENT_COMPLETER_MASK PCI_ERR_UNC_COMP_ABORT 34 + 35 + #define AER_AGENT_TRANSMITTER_MASK(t, e) (e & (PCI_ERR_COR_REP_ROLL| \ 36 + ((t == AER_CORRECTABLE) ? PCI_ERR_COR_REP_TIMER: 0))) 37 + 38 + #define AER_GET_AGENT(t, e) \ 39 + ((e & AER_AGENT_COMPLETER_MASK) ? AER_AGENT_COMPLETER : \ 40 + (e & AER_AGENT_REQUESTER_MASK) ? AER_AGENT_REQUESTER : \ 41 + (AER_AGENT_TRANSMITTER_MASK(t, e)) ? AER_AGENT_TRANSMITTER : \ 42 + AER_AGENT_RECEIVER) 43 + 44 + #define AER_PHYSICAL_LAYER_ERROR_MASK PCI_ERR_COR_RCVR 45 + #define AER_DATA_LINK_LAYER_ERROR_MASK(t, e) \ 46 + (PCI_ERR_UNC_DLP| \ 47 + PCI_ERR_COR_BAD_TLP| \ 48 + PCI_ERR_COR_BAD_DLLP| \ 49 + PCI_ERR_COR_REP_ROLL| \ 50 + ((t == AER_CORRECTABLE) ? \ 51 + PCI_ERR_COR_REP_TIMER: 0)) 52 + 53 + #define AER_PHYSICAL_LAYER_ERROR 0 54 + #define AER_DATA_LINK_LAYER_ERROR 1 55 + #define AER_TRANSACTION_LAYER_ERROR 2 56 + 57 + #define AER_GET_LAYER_ERROR(t, e) \ 58 + ((e & AER_PHYSICAL_LAYER_ERROR_MASK) ? \ 59 + AER_PHYSICAL_LAYER_ERROR : \ 60 + (e & AER_DATA_LINK_LAYER_ERROR_MASK(t, e)) ? \ 61 + AER_DATA_LINK_LAYER_ERROR : \ 62 + AER_TRANSACTION_LAYER_ERROR) 63 + 64 + /* 65 + * AER error strings 66 + */ 67 + static char* aer_error_severity_string[] = { 68 + "Uncorrected (Non-Fatal)", 69 + "Uncorrected (Fatal)", 70 + "Corrected" 71 + }; 72 + 73 + static char* aer_error_layer[] = { 74 + "Physical Layer", 75 + "Data Link Layer", 76 + "Transaction Layer" 77 + }; 78 + static char* aer_correctable_error_string[] = { 79 + "Receiver Error ", /* Bit Position 0 */ 80 + NULL, 81 + NULL, 82 + NULL, 83 + NULL, 84 + NULL, 85 + "Bad TLP ", /* Bit Position 6 */ 86 + "Bad DLLP ", /* Bit Position 7 */ 87 + "RELAY_NUM Rollover ", /* Bit Position 8 */ 88 + NULL, 89 + NULL, 90 + NULL, 91 + "Replay Timer Timeout ", /* Bit Position 12 */ 92 + "Advisory Non-Fatal ", /* Bit Position 13 */ 93 + NULL, 94 + NULL, 95 + NULL, 96 + NULL, 97 + NULL, 98 + NULL, 99 + NULL, 100 + NULL, 101 + NULL, 102 + NULL, 103 + NULL, 104 + NULL, 105 + NULL, 106 + NULL, 107 + NULL, 108 + NULL, 109 + NULL, 110 + NULL, 111 + }; 112 + 113 + static char* aer_uncorrectable_error_string[] = { 114 + NULL, 115 + NULL, 116 + NULL, 117 + NULL, 118 + "Data Link Protocol ", /* Bit Position 4 */ 119 + NULL, 120 + NULL, 121 + NULL, 122 + NULL, 123 + NULL, 124 + NULL, 125 + NULL, 126 + "Poisoned TLP ", /* Bit Position 12 */ 127 + "Flow Control Protocol ", /* Bit Position 13 */ 128 + "Completion Timeout ", /* Bit Position 14 */ 129 + "Completer Abort ", /* Bit Position 15 */ 130 + "Unexpected Completion ", /* Bit Position 16 */ 131 + "Receiver Overflow ", /* Bit Position 17 */ 132 + "Malformed TLP ", /* Bit Position 18 */ 133 + "ECRC ", /* Bit Position 19 */ 134 + "Unsupported Request ", /* Bit Position 20 */ 135 + NULL, 136 + NULL, 137 + NULL, 138 + NULL, 139 + NULL, 140 + NULL, 141 + NULL, 142 + NULL, 143 + NULL, 144 + NULL, 145 + NULL, 146 + }; 147 + 148 + static char* aer_agent_string[] = { 149 + "Receiver ID", 150 + "Requester ID", 151 + "Completer ID", 152 + "Transmitter ID" 153 + }; 154 + 155 + static char * aer_get_error_source_name(int severity, 156 + unsigned int status, 157 + char errmsg_buff[]) 158 + { 159 + int i; 160 + char * errmsg = NULL; 161 + 162 + for (i = 0; i < 32; i++) { 163 + if (!(status & (1 << i))) 164 + continue; 165 + 166 + if (severity == AER_CORRECTABLE) 167 + errmsg = aer_correctable_error_string[i]; 168 + else 169 + errmsg = aer_uncorrectable_error_string[i]; 170 + 171 + if (!errmsg) { 172 + sprintf(errmsg_buff, "Unknown Error Bit %2d ", i); 173 + errmsg = errmsg_buff; 174 + } 175 + 176 + break; 177 + } 178 + 179 + return errmsg; 180 + } 181 + 182 + static DEFINE_SPINLOCK(logbuf_lock); 183 + static char errmsg_buff[100]; 184 + void aer_print_error(struct pci_dev *dev, struct aer_err_info *info) 185 + { 186 + char * errmsg; 187 + int err_layer, agent; 188 + char * loglevel; 189 + 190 + if (info->severity == AER_CORRECTABLE) 191 + loglevel = KERN_WARNING; 192 + else 193 + loglevel = KERN_ERR; 194 + 195 + printk("%s+------ PCI-Express Device Error ------+\n", loglevel); 196 + printk("%sError Severity\t\t: %s\n", loglevel, 197 + aer_error_severity_string[info->severity]); 198 + 199 + if ( info->status == 0) { 200 + printk("%sPCIE Bus Error type\t: (Unaccessible)\n", loglevel); 201 + printk("%sUnaccessible Received\t: %s\n", loglevel, 202 + info->flags & AER_MULTI_ERROR_VALID_FLAG ? 203 + "Multiple" : "First"); 204 + printk("%sUnregistered Agent ID\t: %04x\n", loglevel, 205 + (dev->bus->number << 8) | dev->devfn); 206 + } else { 207 + err_layer = AER_GET_LAYER_ERROR(info->severity, info->status); 208 + printk("%sPCIE Bus Error type\t: %s\n", loglevel, 209 + aer_error_layer[err_layer]); 210 + 211 + spin_lock(&logbuf_lock); 212 + errmsg = aer_get_error_source_name(info->severity, 213 + info->status, 214 + errmsg_buff); 215 + printk("%s%s\t: %s\n", loglevel, errmsg, 216 + info->flags & AER_MULTI_ERROR_VALID_FLAG ? 217 + "Multiple" : "First"); 218 + spin_unlock(&logbuf_lock); 219 + 220 + agent = AER_GET_AGENT(info->severity, info->status); 221 + printk("%s%s\t\t: %04x\n", loglevel, 222 + aer_agent_string[agent], 223 + (dev->bus->number << 8) | dev->devfn); 224 + 225 + printk("%sVendorID=%04xh, DeviceID=%04xh," 226 + " Bus=%02xh, Device=%02xh, Function=%02xh\n", 227 + loglevel, 228 + dev->vendor, 229 + dev->device, 230 + dev->bus->number, 231 + PCI_SLOT(dev->devfn), 232 + PCI_FUNC(dev->devfn)); 233 + 234 + if (info->flags & AER_TLP_HEADER_VALID_FLAG) { 235 + unsigned char *tlp = (unsigned char *) &info->tlp; 236 + printk("%sTLB Header:\n", loglevel); 237 + printk("%s%02x%02x%02x%02x %02x%02x%02x%02x" 238 + " %02x%02x%02x%02x %02x%02x%02x%02x\n", 239 + loglevel, 240 + *(tlp + 3), *(tlp + 2), *(tlp + 1), *tlp, 241 + *(tlp + 7), *(tlp + 6), *(tlp + 5), *(tlp + 4), 242 + *(tlp + 11), *(tlp + 10), *(tlp + 9), 243 + *(tlp + 8), *(tlp + 15), *(tlp + 14), 244 + *(tlp + 13), *(tlp + 12)); 245 + } 246 + } 247 + } 248 +
+1 -1
drivers/pci/pcie/portdrv.h
··· 39 39 extern int pcie_port_device_resume(struct pci_dev *dev); 40 40 #endif 41 41 extern void pcie_port_device_remove(struct pci_dev *dev); 42 - extern void pcie_port_bus_register(void); 42 + extern int pcie_port_bus_register(void); 43 43 extern void pcie_port_bus_unregister(void); 44 44 45 45 #endif /* _PORTDRV_H_ */
+1
drivers/pci/pcie/portdrv_bus.c
··· 24 24 .suspend = pcie_port_bus_suspend, 25 25 .resume = pcie_port_bus_resume, 26 26 }; 27 + EXPORT_SYMBOL_GPL(pcie_port_bus_type); 27 28 28 29 static int pcie_port_bus_match(struct device *dev, struct device_driver *drv) 29 30 {
+5 -6
drivers/pci/pcie/portdrv_core.c
··· 6 6 * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com) 7 7 */ 8 8 9 + #include <linux/compiler.h> 9 10 #include <linux/module.h> 10 11 #include <linux/pci.h> 11 12 #include <linux/kernel.h> ··· 340 339 341 340 int pcie_port_device_suspend(struct pci_dev *dev, pm_message_t state) 342 341 { 343 - device_for_each_child(&dev->dev, &state, suspend_iter); 344 - return 0; 342 + return device_for_each_child(&dev->dev, &state, suspend_iter); 345 343 } 346 344 347 345 static int resume_iter(struct device *dev, void *data) ··· 358 358 359 359 int pcie_port_device_resume(struct pci_dev *dev) 360 360 { 361 - device_for_each_child(&dev->dev, NULL, resume_iter); 362 - return 0; 361 + return device_for_each_child(&dev->dev, NULL, resume_iter); 363 362 } 364 363 #endif 365 364 ··· 401 402 pci_disable_msi(dev); 402 403 } 403 404 404 - void pcie_port_bus_register(void) 405 + int __must_check pcie_port_bus_register(void) 405 406 { 406 - bus_register(&pcie_port_bus_type); 407 + return bus_register(&pcie_port_bus_type); 407 408 } 408 409 409 410 void pcie_port_bus_unregister(void)
+192 -25
drivers/pci/pcie/portdrv_pci.c
··· 14 14 #include <linux/init.h> 15 15 #include <linux/slab.h> 16 16 #include <linux/pcieport_if.h> 17 + #include <linux/aer.h> 17 18 18 19 #include "portdrv.h" 20 + #include "aer/aerdrv.h" 19 21 20 22 /* 21 23 * Version Information ··· 31 29 32 30 /* global data */ 33 31 static const char device_name[] = "pcieport-driver"; 32 + 33 + static int pcie_portdrv_save_config(struct pci_dev *dev) 34 + { 35 + return pci_save_state(dev); 36 + } 37 + 38 + #ifdef CONFIG_PM 39 + static int pcie_portdrv_restore_config(struct pci_dev *dev) 40 + { 41 + int retval; 42 + 43 + pci_restore_state(dev); 44 + retval = pci_enable_device(dev); 45 + if (retval) 46 + return retval; 47 + pci_set_master(dev); 48 + return 0; 49 + } 50 + 51 + static int pcie_portdrv_suspend(struct pci_dev *dev, pm_message_t state) 52 + { 53 + int ret = pcie_port_device_suspend(dev, state); 54 + 55 + if (!ret) 56 + ret = pcie_portdrv_save_config(dev); 57 + return ret; 58 + } 59 + 60 + static int pcie_portdrv_resume(struct pci_dev *dev) 61 + { 62 + pcie_portdrv_restore_config(dev); 63 + return pcie_port_device_resume(dev); 64 + } 65 + #else 66 + #define pcie_portdrv_suspend NULL 67 + #define pcie_portdrv_resume NULL 68 + #endif 34 69 35 70 /* 36 71 * pcie_portdrv_probe - Probe PCI-Express port devices ··· 100 61 return -ENOMEM; 101 62 } 102 63 64 + pcie_portdrv_save_config(dev); 65 + 66 + pci_enable_pcie_error_reporting(dev); 67 + 103 68 return 0; 104 69 } 105 70 ··· 113 70 kfree(pci_get_drvdata(dev)); 114 71 } 115 72 116 - #ifdef CONFIG_PM 117 - static int pcie_portdrv_save_config(struct pci_dev *dev) 73 + static int error_detected_iter(struct device *device, void *data) 118 74 { 119 - return pci_save_state(dev); 120 - } 75 + struct pcie_device *pcie_device; 76 + struct pcie_port_service_driver *driver; 77 + struct aer_broadcast_data *result_data; 78 + pci_ers_result_t status; 121 79 122 - static int pcie_portdrv_restore_config(struct pci_dev *dev) 123 - { 124 - int retval; 80 + result_data = (struct aer_broadcast_data *) data; 125 81 126 - pci_restore_state(dev); 127 - retval = pci_enable_device(dev); 128 - if (retval) 129 - return retval; 130 - pci_set_master(dev); 82 + if (device->bus == &pcie_port_bus_type && device->driver) { 83 + driver = to_service_driver(device->driver); 84 + if (!driver || 85 + !driver->err_handler || 86 + !driver->err_handler->error_detected) 87 + return 0; 88 + 89 + pcie_device = to_pcie_device(device); 90 + 91 + /* Forward error detected message to service drivers */ 92 + status = driver->err_handler->error_detected( 93 + pcie_device->port, 94 + result_data->state); 95 + result_data->result = 96 + merge_result(result_data->result, status); 97 + } 98 + 131 99 return 0; 132 100 } 133 101 134 - static int pcie_portdrv_suspend (struct pci_dev *dev, pm_message_t state) 102 + static pci_ers_result_t pcie_portdrv_error_detected(struct pci_dev *dev, 103 + enum pci_channel_state error) 135 104 { 136 - int ret = pcie_port_device_suspend(dev, state); 105 + struct aer_broadcast_data result_data = 106 + {error, PCI_ERS_RESULT_CAN_RECOVER}; 107 + int retval; 137 108 138 - if (!ret) 139 - ret = pcie_portdrv_save_config(dev); 140 - return ret; 109 + /* can not fail */ 110 + retval = device_for_each_child(&dev->dev, &result_data, error_detected_iter); 111 + 112 + return result_data.result; 141 113 } 142 114 143 - static int pcie_portdrv_resume (struct pci_dev *dev) 115 + static int mmio_enabled_iter(struct device *device, void *data) 144 116 { 145 - pcie_portdrv_restore_config(dev); 146 - return pcie_port_device_resume(dev); 117 + struct pcie_device *pcie_device; 118 + struct pcie_port_service_driver *driver; 119 + pci_ers_result_t status, *result; 120 + 121 + result = (pci_ers_result_t *) data; 122 + 123 + if (device->bus == &pcie_port_bus_type && device->driver) { 124 + driver = to_service_driver(device->driver); 125 + if (driver && 126 + driver->err_handler && 127 + driver->err_handler->mmio_enabled) { 128 + pcie_device = to_pcie_device(device); 129 + 130 + /* Forward error message to service drivers */ 131 + status = driver->err_handler->mmio_enabled( 132 + pcie_device->port); 133 + *result = merge_result(*result, status); 134 + } 135 + } 136 + 137 + return 0; 147 138 } 148 - #endif 139 + 140 + static pci_ers_result_t pcie_portdrv_mmio_enabled(struct pci_dev *dev) 141 + { 142 + pci_ers_result_t status = PCI_ERS_RESULT_RECOVERED; 143 + int retval; 144 + 145 + /* get true return value from &status */ 146 + retval = device_for_each_child(&dev->dev, &status, mmio_enabled_iter); 147 + return status; 148 + } 149 + 150 + static int slot_reset_iter(struct device *device, void *data) 151 + { 152 + struct pcie_device *pcie_device; 153 + struct pcie_port_service_driver *driver; 154 + pci_ers_result_t status, *result; 155 + 156 + result = (pci_ers_result_t *) data; 157 + 158 + if (device->bus == &pcie_port_bus_type && device->driver) { 159 + driver = to_service_driver(device->driver); 160 + if (driver && 161 + driver->err_handler && 162 + driver->err_handler->slot_reset) { 163 + pcie_device = to_pcie_device(device); 164 + 165 + /* Forward error message to service drivers */ 166 + status = driver->err_handler->slot_reset( 167 + pcie_device->port); 168 + *result = merge_result(*result, status); 169 + } 170 + } 171 + 172 + return 0; 173 + } 174 + 175 + static pci_ers_result_t pcie_portdrv_slot_reset(struct pci_dev *dev) 176 + { 177 + pci_ers_result_t status; 178 + int retval; 179 + 180 + /* If fatal, restore cfg space for possible link reset at upstream */ 181 + if (dev->error_state == pci_channel_io_frozen) { 182 + pcie_portdrv_restore_config(dev); 183 + pci_enable_pcie_error_reporting(dev); 184 + } 185 + 186 + /* get true return value from &status */ 187 + retval = device_for_each_child(&dev->dev, &status, slot_reset_iter); 188 + 189 + return status; 190 + } 191 + 192 + static int resume_iter(struct device *device, void *data) 193 + { 194 + struct pcie_device *pcie_device; 195 + struct pcie_port_service_driver *driver; 196 + 197 + if (device->bus == &pcie_port_bus_type && device->driver) { 198 + driver = to_service_driver(device->driver); 199 + if (driver && 200 + driver->err_handler && 201 + driver->err_handler->resume) { 202 + pcie_device = to_pcie_device(device); 203 + 204 + /* Forward error message to service drivers */ 205 + driver->err_handler->resume(pcie_device->port); 206 + } 207 + } 208 + 209 + return 0; 210 + } 211 + 212 + static void pcie_portdrv_err_resume(struct pci_dev *dev) 213 + { 214 + int retval; 215 + /* nothing to do with error value, if it ever happens */ 216 + retval = device_for_each_child(&dev->dev, NULL, resume_iter); 217 + } 149 218 150 219 /* 151 220 * LINUX Device Driver Model ··· 269 114 }; 270 115 MODULE_DEVICE_TABLE(pci, port_pci_ids); 271 116 117 + static struct pci_error_handlers pcie_portdrv_err_handler = { 118 + .error_detected = pcie_portdrv_error_detected, 119 + .mmio_enabled = pcie_portdrv_mmio_enabled, 120 + .slot_reset = pcie_portdrv_slot_reset, 121 + .resume = pcie_portdrv_err_resume, 122 + }; 123 + 272 124 static struct pci_driver pcie_portdrv = { 273 125 .name = (char *)device_name, 274 126 .id_table = &port_pci_ids[0], ··· 283 121 .probe = pcie_portdrv_probe, 284 122 .remove = pcie_portdrv_remove, 285 123 286 - #ifdef CONFIG_PM 287 124 .suspend = pcie_portdrv_suspend, 288 125 .resume = pcie_portdrv_resume, 289 - #endif /* PM */ 126 + 127 + .err_handler = &pcie_portdrv_err_handler, 290 128 }; 291 129 292 130 static int __init pcie_portdrv_init(void) 293 131 { 294 - int retval = 0; 132 + int retval; 295 133 296 - pcie_port_bus_register(); 134 + retval = pcie_port_bus_register(); 135 + if (retval) { 136 + printk(KERN_WARNING "PCIE: bus_register error: %d\n", retval); 137 + goto out; 138 + } 297 139 retval = pci_register_driver(&pcie_portdrv); 298 140 if (retval) 299 141 pcie_port_bus_unregister(); 142 + out: 300 143 return retval; 301 144 } 302 145
+14 -2
drivers/pci/probe.c
··· 339 339 { 340 340 struct pci_bus *child; 341 341 int i; 342 + int retval; 342 343 343 344 /* 344 345 * Allocate a new bus, and inherit stuff from the parent.. ··· 357 356 358 357 child->class_dev.class = &pcibus_class; 359 358 sprintf(child->class_dev.class_id, "%04x:%02x", pci_domain_nr(child), busnr); 360 - class_device_register(&child->class_dev); 361 - class_device_create_file(&child->class_dev, &class_device_attr_cpuaffinity); 359 + retval = class_device_register(&child->class_dev); 360 + if (retval) 361 + goto error_register; 362 + retval = class_device_create_file(&child->class_dev, 363 + &class_device_attr_cpuaffinity); 364 + if (retval) 365 + goto error_file_create; 362 366 363 367 /* 364 368 * Set up the primary, secondary and subordinate ··· 381 375 bridge->subordinate = child; 382 376 383 377 return child; 378 + 379 + error_file_create: 380 + class_device_unregister(&child->class_dev); 381 + error_register: 382 + kfree(child); 383 + return NULL; 384 384 } 385 385 386 386 struct pci_bus * __devinit pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr)
+89 -15
drivers/pci/quirks.c
··· 577 577 } 578 578 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_ANY_ID, quirk_ioapic_rmw ); 579 579 580 - int pci_msi_quirk; 581 - 582 580 #define AMD8131_revA0 0x01 583 581 #define AMD8131_revB0 0x11 584 582 #define AMD8131_MISC 0x40 ··· 585 587 { 586 588 unsigned char revid, tmp; 587 589 588 - if (dev->subordinate) { 589 - printk(KERN_WARNING "PCI: MSI quirk detected. " 590 - "PCI_BUS_FLAGS_NO_MSI set for subordinate bus.\n"); 591 - dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI; 592 - } 593 - 594 590 if (nr_ioapics == 0) 595 591 return; 596 592 ··· 597 605 } 598 606 } 599 607 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_amd_8131_ioapic); 600 - 601 - static void __init quirk_svw_msi(struct pci_dev *dev) 602 - { 603 - pci_msi_quirk = 1; 604 - printk(KERN_WARNING "PCI: MSI quirk detected. pci_msi_quirk set.\n"); 605 - } 606 - DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_GCNB_LE, quirk_svw_msi ); 607 608 #endif /* CONFIG_X86_IO_APIC */ 608 609 609 610 ··· 1674 1689 } 1675 1690 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE, 1676 1691 quirk_nvidia_ck804_pcie_aer_ext_cap); 1692 + 1693 + #ifdef CONFIG_PCI_MSI 1694 + /* To disable MSI globally */ 1695 + int pci_msi_quirk; 1696 + 1697 + /* The Serverworks PCI-X chipset does not support MSI. We cannot easily rely 1698 + * on setting PCI_BUS_FLAGS_NO_MSI in its bus flags because there are actually 1699 + * some other busses controlled by the chipset even if Linux is not aware of it. 1700 + * Instead of setting the flag on all busses in the machine, simply disable MSI 1701 + * globally. 1702 + */ 1703 + static void __init quirk_svw_msi(struct pci_dev *dev) 1704 + { 1705 + pci_msi_quirk = 1; 1706 + printk(KERN_WARNING "PCI: MSI quirk detected. pci_msi_quirk set.\n"); 1707 + } 1708 + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_GCNB_LE, quirk_svw_msi); 1709 + 1710 + /* Disable MSI on chipsets that are known to not support it */ 1711 + static void __devinit quirk_disable_msi(struct pci_dev *dev) 1712 + { 1713 + if (dev->subordinate) { 1714 + printk(KERN_WARNING "PCI: MSI quirk detected. " 1715 + "PCI_BUS_FLAGS_NO_MSI set for %s subordinate bus.\n", 1716 + pci_name(dev)); 1717 + dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI; 1718 + } 1719 + } 1720 + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_disable_msi); 1721 + 1722 + /* Go through the list of Hypertransport capabilities and 1723 + * return 1 if a HT MSI capability is found and enabled */ 1724 + static int __devinit msi_ht_cap_enabled(struct pci_dev *dev) 1725 + { 1726 + u8 pos; 1727 + int ttl; 1728 + for (pos = pci_find_capability(dev, PCI_CAP_ID_HT), ttl = 48; 1729 + pos && ttl; 1730 + pos = pci_find_next_capability(dev, pos, PCI_CAP_ID_HT), ttl--) { 1731 + u32 cap_hdr; 1732 + /* MSI mapping section according to Hypertransport spec */ 1733 + if (pci_read_config_dword(dev, pos, &cap_hdr) == 0 1734 + && (cap_hdr & 0xf8000000) == 0xa8000000 /* MSI mapping */) { 1735 + printk(KERN_INFO "PCI: Found HT MSI mapping on %s with capability %s\n", 1736 + pci_name(dev), cap_hdr & 0x10000 ? "enabled" : "disabled"); 1737 + return (cap_hdr & 0x10000) != 0; /* MSI mapping cap enabled */ 1738 + } 1739 + } 1740 + return 0; 1741 + } 1742 + 1743 + /* Check the hypertransport MSI mapping to know whether MSI is enabled or not */ 1744 + static void __devinit quirk_msi_ht_cap(struct pci_dev *dev) 1745 + { 1746 + if (dev->subordinate && !msi_ht_cap_enabled(dev)) { 1747 + printk(KERN_WARNING "PCI: MSI quirk detected. " 1748 + "MSI disabled on chipset %s.\n", 1749 + pci_name(dev)); 1750 + dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI; 1751 + } 1752 + } 1753 + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT2000_PCIE, 1754 + quirk_msi_ht_cap); 1755 + 1756 + /* The nVidia CK804 chipset may have 2 HT MSI mappings. 1757 + * MSI are supported if the MSI capability set in any of these mappings. 1758 + */ 1759 + static void __devinit quirk_nvidia_ck804_msi_ht_cap(struct pci_dev *dev) 1760 + { 1761 + struct pci_dev *pdev; 1762 + 1763 + if (!dev->subordinate) 1764 + return; 1765 + 1766 + /* check HT MSI cap on this chipset and the root one. 1767 + * a single one having MSI is enough to be sure that MSI are supported. 1768 + */ 1769 + pdev = pci_find_slot(dev->bus->number, 0); 1770 + if (dev->subordinate && !msi_ht_cap_enabled(dev) 1771 + && !msi_ht_cap_enabled(pdev)) { 1772 + printk(KERN_WARNING "PCI: MSI quirk detected. " 1773 + "MSI disabled on chipset %s.\n", 1774 + pci_name(dev)); 1775 + dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI; 1776 + } 1777 + } 1778 + DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE, 1779 + quirk_nvidia_ck804_msi_ht_cap); 1780 + #endif /* CONFIG_PCI_MSI */ 1677 1781 1678 1782 EXPORT_SYMBOL(pcie_mch_quirk); 1679 1783 #ifdef CONFIG_HOTPLUG
+36 -1
drivers/pci/remove.c
··· 16 16 } 17 17 } 18 18 19 - static void pci_destroy_dev(struct pci_dev *dev) 19 + static void pci_stop_dev(struct pci_dev *dev) 20 20 { 21 + if (!dev->global_list.next) 22 + return; 23 + 21 24 if (!list_empty(&dev->global_list)) { 22 25 pci_proc_detach_device(dev); 23 26 pci_remove_sysfs_dev_files(dev); ··· 30 27 dev->global_list.next = dev->global_list.prev = NULL; 31 28 up_write(&pci_bus_sem); 32 29 } 30 + } 31 + 32 + static void pci_destroy_dev(struct pci_dev *dev) 33 + { 34 + pci_stop_dev(dev); 33 35 34 36 /* Remove the device from the device lists, and prevent any further 35 37 * list accesses from this device */ ··· 127 119 } 128 120 } 129 121 122 + static void pci_stop_bus_devices(struct pci_bus *bus) 123 + { 124 + struct list_head *l, *n; 125 + 126 + list_for_each_safe(l, n, &bus->devices) { 127 + struct pci_dev *dev = pci_dev_b(l); 128 + pci_stop_bus_device(dev); 129 + } 130 + } 131 + 132 + /** 133 + * pci_stop_bus_device - stop a PCI device and any children 134 + * @dev: the device to stop 135 + * 136 + * Stop a PCI device (detach the driver, remove from the global list 137 + * and so on). This also stop any subordinate buses and children in a 138 + * depth-first manner. 139 + */ 140 + void pci_stop_bus_device(struct pci_dev *dev) 141 + { 142 + if (dev->subordinate) 143 + pci_stop_bus_devices(dev->subordinate); 144 + 145 + pci_stop_dev(dev); 146 + } 147 + 130 148 EXPORT_SYMBOL(pci_remove_bus_device); 131 149 EXPORT_SYMBOL(pci_remove_behind_bridge); 150 + EXPORT_SYMBOL_GPL(pci_stop_bus_device);
+10 -3
drivers/pci/setup-bus.c
··· 55 55 list_for_each_entry(dev, &bus->devices, bus_list) { 56 56 u16 class = dev->class >> 8; 57 57 58 - /* Don't touch classless devices or host bridges or ioapics. */ 58 + /* Don't touch classless devices or host bridges. */ 59 59 if (class == PCI_CLASS_NOT_DEFINED || 60 - class == PCI_CLASS_BRIDGE_HOST || 61 - class == PCI_CLASS_SYSTEM_PIC) 60 + class == PCI_CLASS_BRIDGE_HOST) 62 61 continue; 62 + 63 + /* Don't touch ioapics if it has the assigned resources. */ 64 + if (class == PCI_CLASS_SYSTEM_PIC) { 65 + res = &dev->resource[0]; 66 + if (res[0].start || res[1].start || res[2].start || 67 + res[3].start || res[4].start || res[5].start) 68 + continue; 69 + } 63 70 64 71 pdev_sort_resources(dev, &head); 65 72 }
+24
include/linux/aer.h
··· 1 + /* 2 + * Copyright (C) 2006 Intel Corp. 3 + * Tom Long Nguyen (tom.l.nguyen@intel.com) 4 + * Zhang Yanmin (yanmin.zhang@intel.com) 5 + */ 6 + 7 + #ifndef _AER_H_ 8 + #define _AER_H_ 9 + 10 + #if defined(CONFIG_PCIEAER) 11 + /* pci-e port driver needs this function to enable aer */ 12 + extern int pci_enable_pcie_error_reporting(struct pci_dev *dev); 13 + extern int pci_find_aer_capability(struct pci_dev *dev); 14 + extern int pci_disable_pcie_error_reporting(struct pci_dev *dev); 15 + extern int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev); 16 + #else 17 + #define pci_enable_pcie_error_reporting(dev) do { } while (0) 18 + #define pci_find_aer_capability(dev) do { } while (0) 19 + #define pci_disable_pcie_error_reporting(dev) do { } while (0) 20 + #define pci_cleanup_aer_uncorrect_error_status(dev) do { } while (0) 21 + #endif 22 + 23 + #endif //_AER_H_ 24 +
+4 -1
include/linux/pci.h
··· 356 356 struct pci_error_handlers *err_handler; 357 357 struct device_driver driver; 358 358 struct pci_dynids dynids; 359 + 360 + int multithread_probe; 359 361 }; 360 362 361 363 #define to_pci_driver(drv) container_of(drv,struct pci_driver, driver) ··· 433 431 struct pci_dev * pci_scan_single_device(struct pci_bus *bus, int devfn); 434 432 void pci_device_add(struct pci_dev *dev, struct pci_bus *bus); 435 433 unsigned int pci_scan_child_bus(struct pci_bus *bus); 436 - void pci_bus_add_device(struct pci_dev *dev); 434 + int __must_check pci_bus_add_device(struct pci_dev *dev); 437 435 void pci_read_bridge_bases(struct pci_bus *child); 438 436 struct resource *pci_find_parent_resource(const struct pci_dev *dev, struct resource *res); 439 437 int pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge); ··· 441 439 extern void pci_dev_put(struct pci_dev *dev); 442 440 extern void pci_remove_bus(struct pci_bus *b); 443 441 extern void pci_remove_bus_device(struct pci_dev *dev); 442 + extern void pci_stop_bus_device(struct pci_dev *dev); 444 443 void pci_setup_cardbus(struct pci_bus *bus); 445 444 446 445 /* Generic PCI functions exported to card drivers */
+1
include/linux/pci_ids.h
··· 1411 1411 #define PCI_DEVICE_ID_SERVERWORKS_LE 0x0009 1412 1412 #define PCI_DEVICE_ID_SERVERWORKS_GCNB_LE 0x0017 1413 1413 #define PCI_DEVICE_ID_SERVERWORKS_EPB 0x0103 1414 + #define PCI_DEVICE_ID_SERVERWORKS_HT2000_PCIE 0x0132 1414 1415 #define PCI_DEVICE_ID_SERVERWORKS_OSB4 0x0200 1415 1416 #define PCI_DEVICE_ID_SERVERWORKS_CSB5 0x0201 1416 1417 #define PCI_DEVICE_ID_SERVERWORKS_CSB6 0x0203
+1 -1
include/linux/pci_regs.h
··· 196 196 #define PCI_CAP_ID_MSI 0x05 /* Message Signalled Interrupts */ 197 197 #define PCI_CAP_ID_CHSWP 0x06 /* CompactPCI HotSwap */ 198 198 #define PCI_CAP_ID_PCIX 0x07 /* PCI-X */ 199 - #define PCI_CAP_ID_HT_IRQCONF 0x08 /* HyperTransport IRQ Configuration */ 199 + #define PCI_CAP_ID_HT 0x08 /* HyperTransport */ 200 200 #define PCI_CAP_ID_VNDR 0x09 /* Vendor specific capability */ 201 201 #define PCI_CAP_ID_SHPC 0x0C /* PCI Standard Hot-Plug Controller */ 202 202 #define PCI_CAP_ID_EXP 0x10 /* PCI Express */
+6
include/linux/pcieport_if.h
··· 62 62 int (*suspend) (struct pcie_device *dev, pm_message_t state); 63 63 int (*resume) (struct pcie_device *dev); 64 64 65 + /* Service Error Recovery Handler */ 66 + struct pci_error_handlers *err_handler; 67 + 68 + /* Link Reset Capability - AER service driver specific */ 69 + pci_ers_result_t (*reset_link) (struct pci_dev *dev); 70 + 65 71 const struct pcie_port_service_id *id_table; 66 72 struct device_driver driver; 67 73 };
+16 -16
kernel/resource.c
··· 344 344 * 345 345 * Returns 0 on success, -EBUSY if the resource can't be inserted. 346 346 * 347 - * This function is equivalent of request_resource when no conflict 347 + * This function is equivalent to request_resource when no conflict 348 348 * happens. If a conflict happens, and the conflicting resources 349 349 * entirely fit within the range of the new resource, then the new 350 - * resource is inserted and the conflicting resources become childs of 351 - * the new resource. Otherwise the new resource becomes the child of 352 - * the conflicting resource 350 + * resource is inserted and the conflicting resources become children of 351 + * the new resource. 353 352 */ 354 353 int insert_resource(struct resource *parent, struct resource *new) 355 354 { ··· 356 357 struct resource *first, *next; 357 358 358 359 write_lock(&resource_lock); 359 - begin: 360 - result = 0; 361 - first = __request_resource(parent, new); 362 - if (!first) 363 - goto out; 364 360 365 - result = -EBUSY; 366 - if (first == parent) 367 - goto out; 361 + for (;; parent = first) { 362 + result = 0; 363 + first = __request_resource(parent, new); 364 + if (!first) 365 + goto out; 368 366 369 - /* Resource fully contained by the clashing resource? Recurse into it */ 370 - if (first->start <= new->start && first->end >= new->end) { 371 - parent = first; 372 - goto begin; 367 + result = -EBUSY; 368 + if (first == parent) 369 + goto out; 370 + 371 + if ((first->start > new->start) || (first->end < new->end)) 372 + break; 373 + if ((first->start == new->start) && (first->end == new->end)) 374 + break; 373 375 } 374 376 375 377 for (next = first; ; next = next->sibling) {