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

PCI-Express AER implemetation: pcie_portdrv error handler

Patch 4 implements error handlers for pcie_portdrv.

Signed-off-by: Zhang Yanmin <yanmin.zhang@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

authored by

Zhang, Yanmin and committed by
Greg Kroah-Hartman
4bf3392e 6c2b374d

+177 -23
+177 -23
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}; 137 107 138 - if (!ret) 139 - ret = pcie_portdrv_save_config(dev); 140 - return ret; 108 + device_for_each_child(&dev->dev, &result_data, error_detected_iter); 109 + 110 + return result_data.result; 141 111 } 142 112 143 - static int pcie_portdrv_resume (struct pci_dev *dev) 113 + static int mmio_enabled_iter(struct device *device, void *data) 144 114 { 145 - pcie_portdrv_restore_config(dev); 146 - return pcie_port_device_resume(dev); 115 + struct pcie_device *pcie_device; 116 + struct pcie_port_service_driver *driver; 117 + pci_ers_result_t status, *result; 118 + 119 + result = (pci_ers_result_t *) data; 120 + 121 + if (device->bus == &pcie_port_bus_type && device->driver) { 122 + driver = to_service_driver(device->driver); 123 + if (driver && 124 + driver->err_handler && 125 + driver->err_handler->mmio_enabled) { 126 + pcie_device = to_pcie_device(device); 127 + 128 + /* Forward error message to service drivers */ 129 + status = driver->err_handler->mmio_enabled( 130 + pcie_device->port); 131 + *result = merge_result(*result, status); 132 + } 133 + } 134 + 135 + return 0; 147 136 } 148 - #endif 137 + 138 + static pci_ers_result_t pcie_portdrv_mmio_enabled(struct pci_dev *dev) 139 + { 140 + pci_ers_result_t status = PCI_ERS_RESULT_RECOVERED; 141 + 142 + device_for_each_child(&dev->dev, &status, mmio_enabled_iter); 143 + return status; 144 + } 145 + 146 + static int slot_reset_iter(struct device *device, void *data) 147 + { 148 + struct pcie_device *pcie_device; 149 + struct pcie_port_service_driver *driver; 150 + pci_ers_result_t status, *result; 151 + 152 + result = (pci_ers_result_t *) data; 153 + 154 + if (device->bus == &pcie_port_bus_type && device->driver) { 155 + driver = to_service_driver(device->driver); 156 + if (driver && 157 + driver->err_handler && 158 + driver->err_handler->slot_reset) { 159 + pcie_device = to_pcie_device(device); 160 + 161 + /* Forward error message to service drivers */ 162 + status = driver->err_handler->slot_reset( 163 + pcie_device->port); 164 + *result = merge_result(*result, status); 165 + } 166 + } 167 + 168 + return 0; 169 + } 170 + 171 + static pci_ers_result_t pcie_portdrv_slot_reset(struct pci_dev *dev) 172 + { 173 + pci_ers_result_t status; 174 + 175 + /* If fatal, restore cfg space for possible link reset at upstream */ 176 + if (dev->error_state == pci_channel_io_frozen) { 177 + pcie_portdrv_restore_config(dev); 178 + pci_enable_pcie_error_reporting(dev); 179 + } 180 + 181 + device_for_each_child(&dev->dev, &status, slot_reset_iter); 182 + 183 + return status; 184 + } 185 + 186 + static int resume_iter(struct device *device, void *data) 187 + { 188 + struct pcie_device *pcie_device; 189 + struct pcie_port_service_driver *driver; 190 + 191 + if (device->bus == &pcie_port_bus_type && device->driver) { 192 + driver = to_service_driver(device->driver); 193 + if (driver && 194 + driver->err_handler && 195 + driver->err_handler->resume) { 196 + pcie_device = to_pcie_device(device); 197 + 198 + /* Forward error message to service drivers */ 199 + driver->err_handler->resume(pcie_device->port); 200 + } 201 + } 202 + 203 + return 0; 204 + } 205 + 206 + static void pcie_portdrv_err_resume(struct pci_dev *dev) 207 + { 208 + device_for_each_child(&dev->dev, NULL, resume_iter); 209 + } 149 210 150 211 /* 151 212 * LINUX Device Driver Model ··· 261 114 }; 262 115 MODULE_DEVICE_TABLE(pci, port_pci_ids); 263 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 + 264 124 static struct pci_driver pcie_portdrv = { 265 125 .name = (char *)device_name, 266 126 .id_table = &port_pci_ids[0], ··· 275 121 .probe = pcie_portdrv_probe, 276 122 .remove = pcie_portdrv_remove, 277 123 278 - #ifdef CONFIG_PM 279 124 .suspend = pcie_portdrv_suspend, 280 125 .resume = pcie_portdrv_resume, 281 - #endif /* PM */ 126 + 127 + .err_handler = &pcie_portdrv_err_handler, 282 128 }; 283 129 284 130 static int __init pcie_portdrv_init(void)