1*2e28bc84SOza Pawandeep // SPDX-License-Identifier: GPL-2.0 2*2e28bc84SOza Pawandeep /* 3*2e28bc84SOza Pawandeep * This file implements the error recovery as a core part of PCIe error 4*2e28bc84SOza Pawandeep * reporting. When a PCIe error is delivered, an error message will be 5*2e28bc84SOza Pawandeep * collected and printed to console, then, an error recovery procedure 6*2e28bc84SOza Pawandeep * will be executed by following the PCI error recovery rules. 7*2e28bc84SOza Pawandeep * 8*2e28bc84SOza Pawandeep * Copyright (C) 2006 Intel Corp. 9*2e28bc84SOza Pawandeep * Tom Long Nguyen (tom.l.nguyen@intel.com) 10*2e28bc84SOza Pawandeep * Zhang Yanmin (yanmin.zhang@intel.com) 11*2e28bc84SOza Pawandeep */ 12*2e28bc84SOza Pawandeep 13*2e28bc84SOza Pawandeep #include <linux/pci.h> 14*2e28bc84SOza Pawandeep #include <linux/module.h> 15*2e28bc84SOza Pawandeep #include <linux/pci.h> 16*2e28bc84SOza Pawandeep #include <linux/kernel.h> 17*2e28bc84SOza Pawandeep #include <linux/errno.h> 18*2e28bc84SOza Pawandeep #include <linux/aer.h> 19*2e28bc84SOza Pawandeep #include "portdrv.h" 20*2e28bc84SOza Pawandeep #include "../pci.h" 21*2e28bc84SOza Pawandeep 22*2e28bc84SOza Pawandeep struct aer_broadcast_data { 23*2e28bc84SOza Pawandeep enum pci_channel_state state; 24*2e28bc84SOza Pawandeep enum pci_ers_result result; 25*2e28bc84SOza Pawandeep }; 26*2e28bc84SOza Pawandeep 27*2e28bc84SOza Pawandeep static pci_ers_result_t merge_result(enum pci_ers_result orig, 28*2e28bc84SOza Pawandeep enum pci_ers_result new) 29*2e28bc84SOza Pawandeep { 30*2e28bc84SOza Pawandeep if (new == PCI_ERS_RESULT_NO_AER_DRIVER) 31*2e28bc84SOza Pawandeep return PCI_ERS_RESULT_NO_AER_DRIVER; 32*2e28bc84SOza Pawandeep 33*2e28bc84SOza Pawandeep if (new == PCI_ERS_RESULT_NONE) 34*2e28bc84SOza Pawandeep return orig; 35*2e28bc84SOza Pawandeep 36*2e28bc84SOza Pawandeep switch (orig) { 37*2e28bc84SOza Pawandeep case PCI_ERS_RESULT_CAN_RECOVER: 38*2e28bc84SOza Pawandeep case PCI_ERS_RESULT_RECOVERED: 39*2e28bc84SOza Pawandeep orig = new; 40*2e28bc84SOza Pawandeep break; 41*2e28bc84SOza Pawandeep case PCI_ERS_RESULT_DISCONNECT: 42*2e28bc84SOza Pawandeep if (new == PCI_ERS_RESULT_NEED_RESET) 43*2e28bc84SOza Pawandeep orig = PCI_ERS_RESULT_NEED_RESET; 44*2e28bc84SOza Pawandeep break; 45*2e28bc84SOza Pawandeep default: 46*2e28bc84SOza Pawandeep break; 47*2e28bc84SOza Pawandeep } 48*2e28bc84SOza Pawandeep 49*2e28bc84SOza Pawandeep return orig; 50*2e28bc84SOza Pawandeep } 51*2e28bc84SOza Pawandeep 52*2e28bc84SOza Pawandeep static int report_error_detected(struct pci_dev *dev, void *data) 53*2e28bc84SOza Pawandeep { 54*2e28bc84SOza Pawandeep pci_ers_result_t vote; 55*2e28bc84SOza Pawandeep const struct pci_error_handlers *err_handler; 56*2e28bc84SOza Pawandeep struct aer_broadcast_data *result_data; 57*2e28bc84SOza Pawandeep 58*2e28bc84SOza Pawandeep result_data = (struct aer_broadcast_data *) data; 59*2e28bc84SOza Pawandeep 60*2e28bc84SOza Pawandeep device_lock(&dev->dev); 61*2e28bc84SOza Pawandeep dev->error_state = result_data->state; 62*2e28bc84SOza Pawandeep 63*2e28bc84SOza Pawandeep if (!dev->driver || 64*2e28bc84SOza Pawandeep !dev->driver->err_handler || 65*2e28bc84SOza Pawandeep !dev->driver->err_handler->error_detected) { 66*2e28bc84SOza Pawandeep if (result_data->state == pci_channel_io_frozen && 67*2e28bc84SOza Pawandeep dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) { 68*2e28bc84SOza Pawandeep /* 69*2e28bc84SOza Pawandeep * In case of fatal recovery, if one of down- 70*2e28bc84SOza Pawandeep * stream device has no driver. We might be 71*2e28bc84SOza Pawandeep * unable to recover because a later insmod 72*2e28bc84SOza Pawandeep * of a driver for this device is unaware of 73*2e28bc84SOza Pawandeep * its hw state. 74*2e28bc84SOza Pawandeep */ 75*2e28bc84SOza Pawandeep pci_printk(KERN_DEBUG, dev, "device has %s\n", 76*2e28bc84SOza Pawandeep dev->driver ? 77*2e28bc84SOza Pawandeep "no AER-aware driver" : "no driver"); 78*2e28bc84SOza Pawandeep } 79*2e28bc84SOza Pawandeep 80*2e28bc84SOza Pawandeep /* 81*2e28bc84SOza Pawandeep * If there's any device in the subtree that does not 82*2e28bc84SOza Pawandeep * have an error_detected callback, returning 83*2e28bc84SOza Pawandeep * PCI_ERS_RESULT_NO_AER_DRIVER prevents calling of 84*2e28bc84SOza Pawandeep * the subsequent mmio_enabled/slot_reset/resume 85*2e28bc84SOza Pawandeep * callbacks of "any" device in the subtree. All the 86*2e28bc84SOza Pawandeep * devices in the subtree are left in the error state 87*2e28bc84SOza Pawandeep * without recovery. 88*2e28bc84SOza Pawandeep */ 89*2e28bc84SOza Pawandeep 90*2e28bc84SOza Pawandeep if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) 91*2e28bc84SOza Pawandeep vote = PCI_ERS_RESULT_NO_AER_DRIVER; 92*2e28bc84SOza Pawandeep else 93*2e28bc84SOza Pawandeep vote = PCI_ERS_RESULT_NONE; 94*2e28bc84SOza Pawandeep } else { 95*2e28bc84SOza Pawandeep err_handler = dev->driver->err_handler; 96*2e28bc84SOza Pawandeep vote = err_handler->error_detected(dev, result_data->state); 97*2e28bc84SOza Pawandeep pci_uevent_ers(dev, PCI_ERS_RESULT_NONE); 98*2e28bc84SOza Pawandeep } 99*2e28bc84SOza Pawandeep 100*2e28bc84SOza Pawandeep result_data->result = merge_result(result_data->result, vote); 101*2e28bc84SOza Pawandeep device_unlock(&dev->dev); 102*2e28bc84SOza Pawandeep return 0; 103*2e28bc84SOza Pawandeep } 104*2e28bc84SOza Pawandeep 105*2e28bc84SOza Pawandeep static int report_mmio_enabled(struct pci_dev *dev, void *data) 106*2e28bc84SOza Pawandeep { 107*2e28bc84SOza Pawandeep pci_ers_result_t vote; 108*2e28bc84SOza Pawandeep const struct pci_error_handlers *err_handler; 109*2e28bc84SOza Pawandeep struct aer_broadcast_data *result_data; 110*2e28bc84SOza Pawandeep 111*2e28bc84SOza Pawandeep result_data = (struct aer_broadcast_data *) data; 112*2e28bc84SOza Pawandeep 113*2e28bc84SOza Pawandeep device_lock(&dev->dev); 114*2e28bc84SOza Pawandeep if (!dev->driver || 115*2e28bc84SOza Pawandeep !dev->driver->err_handler || 116*2e28bc84SOza Pawandeep !dev->driver->err_handler->mmio_enabled) 117*2e28bc84SOza Pawandeep goto out; 118*2e28bc84SOza Pawandeep 119*2e28bc84SOza Pawandeep err_handler = dev->driver->err_handler; 120*2e28bc84SOza Pawandeep vote = err_handler->mmio_enabled(dev); 121*2e28bc84SOza Pawandeep result_data->result = merge_result(result_data->result, vote); 122*2e28bc84SOza Pawandeep out: 123*2e28bc84SOza Pawandeep device_unlock(&dev->dev); 124*2e28bc84SOza Pawandeep return 0; 125*2e28bc84SOza Pawandeep } 126*2e28bc84SOza Pawandeep 127*2e28bc84SOza Pawandeep static int report_slot_reset(struct pci_dev *dev, void *data) 128*2e28bc84SOza Pawandeep { 129*2e28bc84SOza Pawandeep pci_ers_result_t vote; 130*2e28bc84SOza Pawandeep const struct pci_error_handlers *err_handler; 131*2e28bc84SOza Pawandeep struct aer_broadcast_data *result_data; 132*2e28bc84SOza Pawandeep 133*2e28bc84SOza Pawandeep result_data = (struct aer_broadcast_data *) data; 134*2e28bc84SOza Pawandeep 135*2e28bc84SOza Pawandeep device_lock(&dev->dev); 136*2e28bc84SOza Pawandeep if (!dev->driver || 137*2e28bc84SOza Pawandeep !dev->driver->err_handler || 138*2e28bc84SOza Pawandeep !dev->driver->err_handler->slot_reset) 139*2e28bc84SOza Pawandeep goto out; 140*2e28bc84SOza Pawandeep 141*2e28bc84SOza Pawandeep err_handler = dev->driver->err_handler; 142*2e28bc84SOza Pawandeep vote = err_handler->slot_reset(dev); 143*2e28bc84SOza Pawandeep result_data->result = merge_result(result_data->result, vote); 144*2e28bc84SOza Pawandeep out: 145*2e28bc84SOza Pawandeep device_unlock(&dev->dev); 146*2e28bc84SOza Pawandeep return 0; 147*2e28bc84SOza Pawandeep } 148*2e28bc84SOza Pawandeep 149*2e28bc84SOza Pawandeep static int report_resume(struct pci_dev *dev, void *data) 150*2e28bc84SOza Pawandeep { 151*2e28bc84SOza Pawandeep const struct pci_error_handlers *err_handler; 152*2e28bc84SOza Pawandeep 153*2e28bc84SOza Pawandeep device_lock(&dev->dev); 154*2e28bc84SOza Pawandeep dev->error_state = pci_channel_io_normal; 155*2e28bc84SOza Pawandeep 156*2e28bc84SOza Pawandeep if (!dev->driver || 157*2e28bc84SOza Pawandeep !dev->driver->err_handler || 158*2e28bc84SOza Pawandeep !dev->driver->err_handler->resume) 159*2e28bc84SOza Pawandeep goto out; 160*2e28bc84SOza Pawandeep 161*2e28bc84SOza Pawandeep err_handler = dev->driver->err_handler; 162*2e28bc84SOza Pawandeep err_handler->resume(dev); 163*2e28bc84SOza Pawandeep pci_uevent_ers(dev, PCI_ERS_RESULT_RECOVERED); 164*2e28bc84SOza Pawandeep out: 165*2e28bc84SOza Pawandeep device_unlock(&dev->dev); 166*2e28bc84SOza Pawandeep return 0; 167*2e28bc84SOza Pawandeep } 168*2e28bc84SOza Pawandeep 169*2e28bc84SOza Pawandeep /** 170*2e28bc84SOza Pawandeep * default_reset_link - default reset function 171*2e28bc84SOza Pawandeep * @dev: pointer to pci_dev data structure 172*2e28bc84SOza Pawandeep * 173*2e28bc84SOza Pawandeep * Invoked when performing link reset on a Downstream Port or a 174*2e28bc84SOza Pawandeep * Root Port with no aer driver. 175*2e28bc84SOza Pawandeep */ 176*2e28bc84SOza Pawandeep static pci_ers_result_t default_reset_link(struct pci_dev *dev) 177*2e28bc84SOza Pawandeep { 178*2e28bc84SOza Pawandeep pci_reset_bridge_secondary_bus(dev); 179*2e28bc84SOza Pawandeep pci_printk(KERN_DEBUG, dev, "downstream link has been reset\n"); 180*2e28bc84SOza Pawandeep return PCI_ERS_RESULT_RECOVERED; 181*2e28bc84SOza Pawandeep } 182*2e28bc84SOza Pawandeep 183*2e28bc84SOza Pawandeep static pci_ers_result_t reset_link(struct pci_dev *dev) 184*2e28bc84SOza Pawandeep { 185*2e28bc84SOza Pawandeep struct pci_dev *udev; 186*2e28bc84SOza Pawandeep pci_ers_result_t status; 187*2e28bc84SOza Pawandeep struct pcie_port_service_driver *driver = NULL; 188*2e28bc84SOza Pawandeep 189*2e28bc84SOza Pawandeep if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { 190*2e28bc84SOza Pawandeep /* Reset this port for all subordinates */ 191*2e28bc84SOza Pawandeep udev = dev; 192*2e28bc84SOza Pawandeep } else { 193*2e28bc84SOza Pawandeep /* Reset the upstream component (likely downstream port) */ 194*2e28bc84SOza Pawandeep udev = dev->bus->self; 195*2e28bc84SOza Pawandeep } 196*2e28bc84SOza Pawandeep 197*2e28bc84SOza Pawandeep #if IS_ENABLED(CONFIG_PCIEAER) 198*2e28bc84SOza Pawandeep /* Use the aer driver of the component firstly */ 199*2e28bc84SOza Pawandeep driver = find_aer_service(udev); 200*2e28bc84SOza Pawandeep #endif 201*2e28bc84SOza Pawandeep 202*2e28bc84SOza Pawandeep if (driver && driver->reset_link) { 203*2e28bc84SOza Pawandeep status = driver->reset_link(udev); 204*2e28bc84SOza Pawandeep } else if (udev->has_secondary_link) { 205*2e28bc84SOza Pawandeep status = default_reset_link(udev); 206*2e28bc84SOza Pawandeep } else { 207*2e28bc84SOza Pawandeep pci_printk(KERN_DEBUG, dev, "no link-reset support at upstream device %s\n", 208*2e28bc84SOza Pawandeep pci_name(udev)); 209*2e28bc84SOza Pawandeep return PCI_ERS_RESULT_DISCONNECT; 210*2e28bc84SOza Pawandeep } 211*2e28bc84SOza Pawandeep 212*2e28bc84SOza Pawandeep if (status != PCI_ERS_RESULT_RECOVERED) { 213*2e28bc84SOza Pawandeep pci_printk(KERN_DEBUG, dev, "link reset at upstream device %s failed\n", 214*2e28bc84SOza Pawandeep pci_name(udev)); 215*2e28bc84SOza Pawandeep return PCI_ERS_RESULT_DISCONNECT; 216*2e28bc84SOza Pawandeep } 217*2e28bc84SOza Pawandeep 218*2e28bc84SOza Pawandeep return status; 219*2e28bc84SOza Pawandeep } 220*2e28bc84SOza Pawandeep 221*2e28bc84SOza Pawandeep /** 222*2e28bc84SOza Pawandeep * broadcast_error_message - handle message broadcast to downstream drivers 223*2e28bc84SOza Pawandeep * @dev: pointer to from where in a hierarchy message is broadcasted down 224*2e28bc84SOza Pawandeep * @state: error state 225*2e28bc84SOza Pawandeep * @error_mesg: message to print 226*2e28bc84SOza Pawandeep * @cb: callback to be broadcasted 227*2e28bc84SOza Pawandeep * 228*2e28bc84SOza Pawandeep * Invoked during error recovery process. Once being invoked, the content 229*2e28bc84SOza Pawandeep * of error severity will be broadcasted to all downstream drivers in a 230*2e28bc84SOza Pawandeep * hierarchy in question. 231*2e28bc84SOza Pawandeep */ 232*2e28bc84SOza Pawandeep static pci_ers_result_t broadcast_error_message(struct pci_dev *dev, 233*2e28bc84SOza Pawandeep enum pci_channel_state state, 234*2e28bc84SOza Pawandeep char *error_mesg, 235*2e28bc84SOza Pawandeep int (*cb)(struct pci_dev *, void *)) 236*2e28bc84SOza Pawandeep { 237*2e28bc84SOza Pawandeep struct aer_broadcast_data result_data; 238*2e28bc84SOza Pawandeep 239*2e28bc84SOza Pawandeep pci_printk(KERN_DEBUG, dev, "broadcast %s message\n", error_mesg); 240*2e28bc84SOza Pawandeep result_data.state = state; 241*2e28bc84SOza Pawandeep if (cb == report_error_detected) 242*2e28bc84SOza Pawandeep result_data.result = PCI_ERS_RESULT_CAN_RECOVER; 243*2e28bc84SOza Pawandeep else 244*2e28bc84SOza Pawandeep result_data.result = PCI_ERS_RESULT_RECOVERED; 245*2e28bc84SOza Pawandeep 246*2e28bc84SOza Pawandeep if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { 247*2e28bc84SOza Pawandeep /* 248*2e28bc84SOza Pawandeep * If the error is reported by a bridge, we think this error 249*2e28bc84SOza Pawandeep * is related to the downstream link of the bridge, so we 250*2e28bc84SOza Pawandeep * do error recovery on all subordinates of the bridge instead 251*2e28bc84SOza Pawandeep * of the bridge and clear the error status of the bridge. 252*2e28bc84SOza Pawandeep */ 253*2e28bc84SOza Pawandeep if (cb == report_error_detected) 254*2e28bc84SOza Pawandeep dev->error_state = state; 255*2e28bc84SOza Pawandeep pci_walk_bus(dev->subordinate, cb, &result_data); 256*2e28bc84SOza Pawandeep if (cb == report_resume) { 257*2e28bc84SOza Pawandeep pci_cleanup_aer_uncorrect_error_status(dev); 258*2e28bc84SOza Pawandeep dev->error_state = pci_channel_io_normal; 259*2e28bc84SOza Pawandeep } 260*2e28bc84SOza Pawandeep } else { 261*2e28bc84SOza Pawandeep /* 262*2e28bc84SOza Pawandeep * If the error is reported by an end point, we think this 263*2e28bc84SOza Pawandeep * error is related to the upstream link of the end point. 264*2e28bc84SOza Pawandeep */ 265*2e28bc84SOza Pawandeep if (state == pci_channel_io_normal) 266*2e28bc84SOza Pawandeep /* 267*2e28bc84SOza Pawandeep * the error is non fatal so the bus is ok, just invoke 268*2e28bc84SOza Pawandeep * the callback for the function that logged the error. 269*2e28bc84SOza Pawandeep */ 270*2e28bc84SOza Pawandeep cb(dev, &result_data); 271*2e28bc84SOza Pawandeep else 272*2e28bc84SOza Pawandeep pci_walk_bus(dev->bus, cb, &result_data); 273*2e28bc84SOza Pawandeep } 274*2e28bc84SOza Pawandeep 275*2e28bc84SOza Pawandeep return result_data.result; 276*2e28bc84SOza Pawandeep } 277*2e28bc84SOza Pawandeep 278*2e28bc84SOza Pawandeep /** 279*2e28bc84SOza Pawandeep * pcie_do_fatal_recovery - handle fatal error recovery process 280*2e28bc84SOza Pawandeep * @dev: pointer to a pci_dev data structure of agent detecting an error 281*2e28bc84SOza Pawandeep * 282*2e28bc84SOza Pawandeep * Invoked when an error is fatal. Once being invoked, removes the devices 283*2e28bc84SOza Pawandeep * beneath this AER agent, followed by reset link e.g. secondary bus reset 284*2e28bc84SOza Pawandeep * followed by re-enumeration of devices. 285*2e28bc84SOza Pawandeep */ 286*2e28bc84SOza Pawandeep void pcie_do_fatal_recovery(struct pci_dev *dev) 287*2e28bc84SOza Pawandeep { 288*2e28bc84SOza Pawandeep struct pci_dev *udev; 289*2e28bc84SOza Pawandeep struct pci_bus *parent; 290*2e28bc84SOza Pawandeep struct pci_dev *pdev, *temp; 291*2e28bc84SOza Pawandeep pci_ers_result_t result; 292*2e28bc84SOza Pawandeep 293*2e28bc84SOza Pawandeep if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) 294*2e28bc84SOza Pawandeep udev = dev; 295*2e28bc84SOza Pawandeep else 296*2e28bc84SOza Pawandeep udev = dev->bus->self; 297*2e28bc84SOza Pawandeep 298*2e28bc84SOza Pawandeep parent = udev->subordinate; 299*2e28bc84SOza Pawandeep pci_lock_rescan_remove(); 300*2e28bc84SOza Pawandeep list_for_each_entry_safe_reverse(pdev, temp, &parent->devices, 301*2e28bc84SOza Pawandeep bus_list) { 302*2e28bc84SOza Pawandeep pci_dev_get(pdev); 303*2e28bc84SOza Pawandeep pci_dev_set_disconnected(pdev, NULL); 304*2e28bc84SOza Pawandeep if (pci_has_subordinate(pdev)) 305*2e28bc84SOza Pawandeep pci_walk_bus(pdev->subordinate, 306*2e28bc84SOza Pawandeep pci_dev_set_disconnected, NULL); 307*2e28bc84SOza Pawandeep pci_stop_and_remove_bus_device(pdev); 308*2e28bc84SOza Pawandeep pci_dev_put(pdev); 309*2e28bc84SOza Pawandeep } 310*2e28bc84SOza Pawandeep 311*2e28bc84SOza Pawandeep result = reset_link(udev); 312*2e28bc84SOza Pawandeep 313*2e28bc84SOza Pawandeep if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { 314*2e28bc84SOza Pawandeep /* 315*2e28bc84SOza Pawandeep * If the error is reported by a bridge, we think this error 316*2e28bc84SOza Pawandeep * is related to the downstream link of the bridge, so we 317*2e28bc84SOza Pawandeep * do error recovery on all subordinates of the bridge instead 318*2e28bc84SOza Pawandeep * of the bridge and clear the error status of the bridge. 319*2e28bc84SOza Pawandeep */ 320*2e28bc84SOza Pawandeep pci_cleanup_aer_uncorrect_error_status(dev); 321*2e28bc84SOza Pawandeep } 322*2e28bc84SOza Pawandeep 323*2e28bc84SOza Pawandeep if (result == PCI_ERS_RESULT_RECOVERED) { 324*2e28bc84SOza Pawandeep if (pcie_wait_for_link(udev, true)) 325*2e28bc84SOza Pawandeep pci_rescan_bus(udev->bus); 326*2e28bc84SOza Pawandeep pci_info(dev, "Device recovery from fatal error successful\n"); 327*2e28bc84SOza Pawandeep } else { 328*2e28bc84SOza Pawandeep pci_uevent_ers(dev, PCI_ERS_RESULT_DISCONNECT); 329*2e28bc84SOza Pawandeep pci_info(dev, "Device recovery from fatal error failed\n"); 330*2e28bc84SOza Pawandeep } 331*2e28bc84SOza Pawandeep 332*2e28bc84SOza Pawandeep pci_unlock_rescan_remove(); 333*2e28bc84SOza Pawandeep } 334*2e28bc84SOza Pawandeep 335*2e28bc84SOza Pawandeep /** 336*2e28bc84SOza Pawandeep * pcie_do_nonfatal_recovery - handle nonfatal error recovery process 337*2e28bc84SOza Pawandeep * @dev: pointer to a pci_dev data structure of agent detecting an error 338*2e28bc84SOza Pawandeep * 339*2e28bc84SOza Pawandeep * Invoked when an error is nonfatal/fatal. Once being invoked, broadcast 340*2e28bc84SOza Pawandeep * error detected message to all downstream drivers within a hierarchy in 341*2e28bc84SOza Pawandeep * question and return the returned code. 342*2e28bc84SOza Pawandeep */ 343*2e28bc84SOza Pawandeep void pcie_do_nonfatal_recovery(struct pci_dev *dev) 344*2e28bc84SOza Pawandeep { 345*2e28bc84SOza Pawandeep pci_ers_result_t status; 346*2e28bc84SOza Pawandeep enum pci_channel_state state; 347*2e28bc84SOza Pawandeep 348*2e28bc84SOza Pawandeep state = pci_channel_io_normal; 349*2e28bc84SOza Pawandeep 350*2e28bc84SOza Pawandeep status = broadcast_error_message(dev, 351*2e28bc84SOza Pawandeep state, 352*2e28bc84SOza Pawandeep "error_detected", 353*2e28bc84SOza Pawandeep report_error_detected); 354*2e28bc84SOza Pawandeep 355*2e28bc84SOza Pawandeep if (status == PCI_ERS_RESULT_CAN_RECOVER) 356*2e28bc84SOza Pawandeep status = broadcast_error_message(dev, 357*2e28bc84SOza Pawandeep state, 358*2e28bc84SOza Pawandeep "mmio_enabled", 359*2e28bc84SOza Pawandeep report_mmio_enabled); 360*2e28bc84SOza Pawandeep 361*2e28bc84SOza Pawandeep if (status == PCI_ERS_RESULT_NEED_RESET) { 362*2e28bc84SOza Pawandeep /* 363*2e28bc84SOza Pawandeep * TODO: Should call platform-specific 364*2e28bc84SOza Pawandeep * functions to reset slot before calling 365*2e28bc84SOza Pawandeep * drivers' slot_reset callbacks? 366*2e28bc84SOza Pawandeep */ 367*2e28bc84SOza Pawandeep status = broadcast_error_message(dev, 368*2e28bc84SOza Pawandeep state, 369*2e28bc84SOza Pawandeep "slot_reset", 370*2e28bc84SOza Pawandeep report_slot_reset); 371*2e28bc84SOza Pawandeep } 372*2e28bc84SOza Pawandeep 373*2e28bc84SOza Pawandeep if (status != PCI_ERS_RESULT_RECOVERED) 374*2e28bc84SOza Pawandeep goto failed; 375*2e28bc84SOza Pawandeep 376*2e28bc84SOza Pawandeep broadcast_error_message(dev, 377*2e28bc84SOza Pawandeep state, 378*2e28bc84SOza Pawandeep "resume", 379*2e28bc84SOza Pawandeep report_resume); 380*2e28bc84SOza Pawandeep 381*2e28bc84SOza Pawandeep pci_info(dev, "AER: Device recovery successful\n"); 382*2e28bc84SOza Pawandeep return; 383*2e28bc84SOza Pawandeep 384*2e28bc84SOza Pawandeep failed: 385*2e28bc84SOza Pawandeep pci_uevent_ers(dev, PCI_ERS_RESULT_DISCONNECT); 386*2e28bc84SOza Pawandeep 387*2e28bc84SOza Pawandeep /* TODO: Should kernel panic here? */ 388*2e28bc84SOza Pawandeep pci_info(dev, "AER: Device recovery failed\n"); 389*2e28bc84SOza Pawandeep } 390