1317f06deSGavin Shan /* 2317f06deSGavin Shan * PCI Error Recovery Driver for RPA-compliant PPC64 platform. 3317f06deSGavin Shan * Copyright IBM Corp. 2004 2005 4317f06deSGavin Shan * Copyright Linas Vepstas <linas@linas.org> 2004, 2005 5317f06deSGavin Shan * 6317f06deSGavin Shan * All rights reserved. 7317f06deSGavin Shan * 8317f06deSGavin Shan * This program is free software; you can redistribute it and/or modify 9317f06deSGavin Shan * it under the terms of the GNU General Public License as published by 10317f06deSGavin Shan * the Free Software Foundation; either version 2 of the License, or (at 11317f06deSGavin Shan * your option) any later version. 12317f06deSGavin Shan * 13317f06deSGavin Shan * This program is distributed in the hope that it will be useful, but 14317f06deSGavin Shan * WITHOUT ANY WARRANTY; without even the implied warranty of 15317f06deSGavin Shan * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or 16317f06deSGavin Shan * NON INFRINGEMENT. See the GNU General Public License for more 17317f06deSGavin Shan * details. 18317f06deSGavin Shan * 19317f06deSGavin Shan * You should have received a copy of the GNU General Public License 20317f06deSGavin Shan * along with this program; if not, write to the Free Software 21317f06deSGavin Shan * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 22317f06deSGavin Shan * 23317f06deSGavin Shan * Send comments and feedback to Linas Vepstas <linas@austin.ibm.com> 24317f06deSGavin Shan */ 25317f06deSGavin Shan #include <linux/delay.h> 26317f06deSGavin Shan #include <linux/interrupt.h> 27317f06deSGavin Shan #include <linux/irq.h> 28317f06deSGavin Shan #include <linux/module.h> 29317f06deSGavin Shan #include <linux/pci.h> 30317f06deSGavin Shan #include <asm/eeh.h> 31317f06deSGavin Shan #include <asm/eeh_event.h> 32317f06deSGavin Shan #include <asm/ppc-pci.h> 33317f06deSGavin Shan #include <asm/pci-bridge.h> 34317f06deSGavin Shan #include <asm/prom.h> 35317f06deSGavin Shan #include <asm/rtas.h> 36317f06deSGavin Shan 3767086e32SWei Yang struct eeh_rmv_data { 3867086e32SWei Yang struct list_head edev_list; 3967086e32SWei Yang int removed; 4067086e32SWei Yang }; 4167086e32SWei Yang 42317f06deSGavin Shan /** 43317f06deSGavin Shan * eeh_pcid_name - Retrieve name of PCI device driver 44317f06deSGavin Shan * @pdev: PCI device 45317f06deSGavin Shan * 46317f06deSGavin Shan * This routine is used to retrieve the name of PCI device driver 47317f06deSGavin Shan * if that's valid. 48317f06deSGavin Shan */ 49317f06deSGavin Shan static inline const char *eeh_pcid_name(struct pci_dev *pdev) 50317f06deSGavin Shan { 51317f06deSGavin Shan if (pdev && pdev->dev.driver) 52317f06deSGavin Shan return pdev->dev.driver->name; 53317f06deSGavin Shan return ""; 54317f06deSGavin Shan } 55317f06deSGavin Shan 56317f06deSGavin Shan /** 57317f06deSGavin Shan * eeh_pcid_get - Get the PCI device driver 58317f06deSGavin Shan * @pdev: PCI device 59317f06deSGavin Shan * 60317f06deSGavin Shan * The function is used to retrieve the PCI device driver for 61317f06deSGavin Shan * the indicated PCI device. Besides, we will increase the reference 62317f06deSGavin Shan * of the PCI device driver to prevent that being unloaded on 63317f06deSGavin Shan * the fly. Otherwise, kernel crash would be seen. 64317f06deSGavin Shan */ 65317f06deSGavin Shan static inline struct pci_driver *eeh_pcid_get(struct pci_dev *pdev) 66317f06deSGavin Shan { 67317f06deSGavin Shan if (!pdev || !pdev->driver) 68317f06deSGavin Shan return NULL; 69317f06deSGavin Shan 70317f06deSGavin Shan if (!try_module_get(pdev->driver->driver.owner)) 71317f06deSGavin Shan return NULL; 72317f06deSGavin Shan 73317f06deSGavin Shan return pdev->driver; 74317f06deSGavin Shan } 75317f06deSGavin Shan 76317f06deSGavin Shan /** 77317f06deSGavin Shan * eeh_pcid_put - Dereference on the PCI device driver 78317f06deSGavin Shan * @pdev: PCI device 79317f06deSGavin Shan * 80317f06deSGavin Shan * The function is called to do dereference on the PCI device 81317f06deSGavin Shan * driver of the indicated PCI device. 82317f06deSGavin Shan */ 83317f06deSGavin Shan static inline void eeh_pcid_put(struct pci_dev *pdev) 84317f06deSGavin Shan { 85317f06deSGavin Shan if (!pdev || !pdev->driver) 86317f06deSGavin Shan return; 87317f06deSGavin Shan 88317f06deSGavin Shan module_put(pdev->driver->driver.owner); 89317f06deSGavin Shan } 90317f06deSGavin Shan 91317f06deSGavin Shan /** 92317f06deSGavin Shan * eeh_disable_irq - Disable interrupt for the recovering device 93317f06deSGavin Shan * @dev: PCI device 94317f06deSGavin Shan * 95317f06deSGavin Shan * This routine must be called when reporting temporary or permanent 96317f06deSGavin Shan * error to the particular PCI device to disable interrupt of that 97317f06deSGavin Shan * device. If the device has enabled MSI or MSI-X interrupt, we needn't 98317f06deSGavin Shan * do real work because EEH should freeze DMA transfers for those PCI 99317f06deSGavin Shan * devices encountering EEH errors, which includes MSI or MSI-X. 100317f06deSGavin Shan */ 101317f06deSGavin Shan static void eeh_disable_irq(struct pci_dev *dev) 102317f06deSGavin Shan { 103317f06deSGavin Shan struct eeh_dev *edev = pci_dev_to_eeh_dev(dev); 104317f06deSGavin Shan 105317f06deSGavin Shan /* Don't disable MSI and MSI-X interrupts. They are 106317f06deSGavin Shan * effectively disabled by the DMA Stopped state 107317f06deSGavin Shan * when an EEH error occurs. 108317f06deSGavin Shan */ 109317f06deSGavin Shan if (dev->msi_enabled || dev->msix_enabled) 110317f06deSGavin Shan return; 111317f06deSGavin Shan 112317f06deSGavin Shan if (!irq_has_action(dev->irq)) 113317f06deSGavin Shan return; 114317f06deSGavin Shan 115317f06deSGavin Shan edev->mode |= EEH_DEV_IRQ_DISABLED; 116317f06deSGavin Shan disable_irq_nosync(dev->irq); 117317f06deSGavin Shan } 118317f06deSGavin Shan 119317f06deSGavin Shan /** 120317f06deSGavin Shan * eeh_enable_irq - Enable interrupt for the recovering device 121317f06deSGavin Shan * @dev: PCI device 122317f06deSGavin Shan * 123317f06deSGavin Shan * This routine must be called to enable interrupt while failed 124317f06deSGavin Shan * device could be resumed. 125317f06deSGavin Shan */ 126317f06deSGavin Shan static void eeh_enable_irq(struct pci_dev *dev) 127317f06deSGavin Shan { 128317f06deSGavin Shan struct eeh_dev *edev = pci_dev_to_eeh_dev(dev); 129317f06deSGavin Shan 130317f06deSGavin Shan if ((edev->mode) & EEH_DEV_IRQ_DISABLED) { 131317f06deSGavin Shan edev->mode &= ~EEH_DEV_IRQ_DISABLED; 132b8a9a11bSThomas Gleixner /* 133b8a9a11bSThomas Gleixner * FIXME !!!!! 134b8a9a11bSThomas Gleixner * 135b8a9a11bSThomas Gleixner * This is just ass backwards. This maze has 136b8a9a11bSThomas Gleixner * unbalanced irq_enable/disable calls. So instead of 137b8a9a11bSThomas Gleixner * finding the root cause it works around the warning 138b8a9a11bSThomas Gleixner * in the irq_enable code by conditionally calling 139b8a9a11bSThomas Gleixner * into it. 140b8a9a11bSThomas Gleixner * 141b8a9a11bSThomas Gleixner * That's just wrong.The warning in the core code is 142027dfac6SMichael Ellerman * there to tell people to fix their asymmetries in 143b8a9a11bSThomas Gleixner * their own code, not by abusing the core information 144b8a9a11bSThomas Gleixner * to avoid it. 145b8a9a11bSThomas Gleixner * 146b8a9a11bSThomas Gleixner * I so wish that the assymetry would be the other way 147b8a9a11bSThomas Gleixner * round and a few more irq_disable calls render that 148b8a9a11bSThomas Gleixner * shit unusable forever. 149b8a9a11bSThomas Gleixner * 150b8a9a11bSThomas Gleixner * tglx 151b8a9a11bSThomas Gleixner */ 15257310c3cSThomas Gleixner if (irqd_irq_disabled(irq_get_irq_data(dev->irq))) 153317f06deSGavin Shan enable_irq(dev->irq); 154317f06deSGavin Shan } 15557310c3cSThomas Gleixner } 156317f06deSGavin Shan 157d2b0f6f7SGavin Shan static bool eeh_dev_removed(struct eeh_dev *edev) 158d2b0f6f7SGavin Shan { 159d2b0f6f7SGavin Shan /* EEH device removed ? */ 160d2b0f6f7SGavin Shan if (!edev || (edev->mode & EEH_DEV_REMOVED)) 161d2b0f6f7SGavin Shan return true; 162d2b0f6f7SGavin Shan 163d2b0f6f7SGavin Shan return false; 164d2b0f6f7SGavin Shan } 165d2b0f6f7SGavin Shan 1665cfb20b9SGavin Shan static void *eeh_dev_save_state(void *data, void *userdata) 1675cfb20b9SGavin Shan { 1685cfb20b9SGavin Shan struct eeh_dev *edev = data; 1695cfb20b9SGavin Shan struct pci_dev *pdev; 1705cfb20b9SGavin Shan 1715cfb20b9SGavin Shan if (!edev) 1725cfb20b9SGavin Shan return NULL; 1735cfb20b9SGavin Shan 1745a0cdbfdSGavin Shan /* 1755a0cdbfdSGavin Shan * We cannot access the config space on some adapters. 1765a0cdbfdSGavin Shan * Otherwise, it will cause fenced PHB. We don't save 1775a0cdbfdSGavin Shan * the content in their config space and will restore 1785a0cdbfdSGavin Shan * from the initial config space saved when the EEH 1795a0cdbfdSGavin Shan * device is created. 1805a0cdbfdSGavin Shan */ 1815a0cdbfdSGavin Shan if (edev->pe && (edev->pe->state & EEH_PE_CFG_RESTRICTED)) 1825a0cdbfdSGavin Shan return NULL; 1835a0cdbfdSGavin Shan 1845cfb20b9SGavin Shan pdev = eeh_dev_to_pci_dev(edev); 1855cfb20b9SGavin Shan if (!pdev) 1865cfb20b9SGavin Shan return NULL; 1875cfb20b9SGavin Shan 1885cfb20b9SGavin Shan pci_save_state(pdev); 1895cfb20b9SGavin Shan return NULL; 1905cfb20b9SGavin Shan } 1915cfb20b9SGavin Shan 192317f06deSGavin Shan /** 193317f06deSGavin Shan * eeh_report_error - Report pci error to each device driver 194317f06deSGavin Shan * @data: eeh device 195317f06deSGavin Shan * @userdata: return value 196317f06deSGavin Shan * 197317f06deSGavin Shan * Report an EEH error to each device driver, collect up and 198317f06deSGavin Shan * merge the device driver responses. Cumulative response 199317f06deSGavin Shan * passed back in "userdata". 200317f06deSGavin Shan */ 201317f06deSGavin Shan static void *eeh_report_error(void *data, void *userdata) 202317f06deSGavin Shan { 203317f06deSGavin Shan struct eeh_dev *edev = (struct eeh_dev *)data; 204317f06deSGavin Shan struct pci_dev *dev = eeh_dev_to_pci_dev(edev); 205317f06deSGavin Shan enum pci_ers_result rc, *res = userdata; 206317f06deSGavin Shan struct pci_driver *driver; 207317f06deSGavin Shan 2082311cca5SGavin Shan if (!dev || eeh_dev_removed(edev) || eeh_pe_passed(edev->pe)) 209d2b0f6f7SGavin Shan return NULL; 210317f06deSGavin Shan dev->error_state = pci_channel_io_frozen; 211317f06deSGavin Shan 212317f06deSGavin Shan driver = eeh_pcid_get(dev); 213317f06deSGavin Shan if (!driver) return NULL; 214317f06deSGavin Shan 215317f06deSGavin Shan eeh_disable_irq(dev); 216317f06deSGavin Shan 217317f06deSGavin Shan if (!driver->err_handler || 218317f06deSGavin Shan !driver->err_handler->error_detected) { 219317f06deSGavin Shan eeh_pcid_put(dev); 220317f06deSGavin Shan return NULL; 221317f06deSGavin Shan } 222317f06deSGavin Shan 223317f06deSGavin Shan rc = driver->err_handler->error_detected(dev, pci_channel_io_frozen); 224317f06deSGavin Shan 225317f06deSGavin Shan /* A driver that needs a reset trumps all others */ 226317f06deSGavin Shan if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc; 227317f06deSGavin Shan if (*res == PCI_ERS_RESULT_NONE) *res = rc; 228317f06deSGavin Shan 22967086e32SWei Yang edev->in_error = true; 230317f06deSGavin Shan eeh_pcid_put(dev); 231856e1eb9SBryant G. Ly pci_uevent_ers(dev, PCI_ERS_RESULT_NONE); 232317f06deSGavin Shan return NULL; 233317f06deSGavin Shan } 234317f06deSGavin Shan 235317f06deSGavin Shan /** 236317f06deSGavin Shan * eeh_report_mmio_enabled - Tell drivers that MMIO has been enabled 237317f06deSGavin Shan * @data: eeh device 238317f06deSGavin Shan * @userdata: return value 239317f06deSGavin Shan * 240317f06deSGavin Shan * Tells each device driver that IO ports, MMIO and config space I/O 241317f06deSGavin Shan * are now enabled. Collects up and merges the device driver responses. 242317f06deSGavin Shan * Cumulative response passed back in "userdata". 243317f06deSGavin Shan */ 244317f06deSGavin Shan static void *eeh_report_mmio_enabled(void *data, void *userdata) 245317f06deSGavin Shan { 246317f06deSGavin Shan struct eeh_dev *edev = (struct eeh_dev *)data; 247317f06deSGavin Shan struct pci_dev *dev = eeh_dev_to_pci_dev(edev); 248317f06deSGavin Shan enum pci_ers_result rc, *res = userdata; 249317f06deSGavin Shan struct pci_driver *driver; 250317f06deSGavin Shan 2512311cca5SGavin Shan if (!dev || eeh_dev_removed(edev) || eeh_pe_passed(edev->pe)) 252d2b0f6f7SGavin Shan return NULL; 253d2b0f6f7SGavin Shan 254317f06deSGavin Shan driver = eeh_pcid_get(dev); 255317f06deSGavin Shan if (!driver) return NULL; 256317f06deSGavin Shan 257317f06deSGavin Shan if (!driver->err_handler || 258f26c7a03SGavin Shan !driver->err_handler->mmio_enabled || 259f26c7a03SGavin Shan (edev->mode & EEH_DEV_NO_HANDLER)) { 260317f06deSGavin Shan eeh_pcid_put(dev); 261317f06deSGavin Shan return NULL; 262317f06deSGavin Shan } 263317f06deSGavin Shan 264317f06deSGavin Shan rc = driver->err_handler->mmio_enabled(dev); 265317f06deSGavin Shan 266317f06deSGavin Shan /* A driver that needs a reset trumps all others */ 267317f06deSGavin Shan if (rc == PCI_ERS_RESULT_NEED_RESET) *res = rc; 268317f06deSGavin Shan if (*res == PCI_ERS_RESULT_NONE) *res = rc; 269317f06deSGavin Shan 270317f06deSGavin Shan eeh_pcid_put(dev); 271317f06deSGavin Shan return NULL; 272317f06deSGavin Shan } 273317f06deSGavin Shan 274317f06deSGavin Shan /** 275317f06deSGavin Shan * eeh_report_reset - Tell device that slot has been reset 276317f06deSGavin Shan * @data: eeh device 277317f06deSGavin Shan * @userdata: return value 278317f06deSGavin Shan * 279317f06deSGavin Shan * This routine must be called while EEH tries to reset particular 280317f06deSGavin Shan * PCI device so that the associated PCI device driver could take 281317f06deSGavin Shan * some actions, usually to save data the driver needs so that the 282317f06deSGavin Shan * driver can work again while the device is recovered. 283317f06deSGavin Shan */ 284317f06deSGavin Shan static void *eeh_report_reset(void *data, void *userdata) 285317f06deSGavin Shan { 286317f06deSGavin Shan struct eeh_dev *edev = (struct eeh_dev *)data; 287317f06deSGavin Shan struct pci_dev *dev = eeh_dev_to_pci_dev(edev); 288317f06deSGavin Shan enum pci_ers_result rc, *res = userdata; 289317f06deSGavin Shan struct pci_driver *driver; 290317f06deSGavin Shan 2912311cca5SGavin Shan if (!dev || eeh_dev_removed(edev) || eeh_pe_passed(edev->pe)) 292d2b0f6f7SGavin Shan return NULL; 293317f06deSGavin Shan dev->error_state = pci_channel_io_normal; 294317f06deSGavin Shan 295317f06deSGavin Shan driver = eeh_pcid_get(dev); 296317f06deSGavin Shan if (!driver) return NULL; 297317f06deSGavin Shan 298317f06deSGavin Shan eeh_enable_irq(dev); 299317f06deSGavin Shan 300317f06deSGavin Shan if (!driver->err_handler || 301f26c7a03SGavin Shan !driver->err_handler->slot_reset || 30267086e32SWei Yang (edev->mode & EEH_DEV_NO_HANDLER) || 30367086e32SWei Yang (!edev->in_error)) { 304317f06deSGavin Shan eeh_pcid_put(dev); 305317f06deSGavin Shan return NULL; 306317f06deSGavin Shan } 307317f06deSGavin Shan 308317f06deSGavin Shan rc = driver->err_handler->slot_reset(dev); 309317f06deSGavin Shan if ((*res == PCI_ERS_RESULT_NONE) || 310317f06deSGavin Shan (*res == PCI_ERS_RESULT_RECOVERED)) *res = rc; 311317f06deSGavin Shan if (*res == PCI_ERS_RESULT_DISCONNECT && 312317f06deSGavin Shan rc == PCI_ERS_RESULT_NEED_RESET) *res = rc; 313317f06deSGavin Shan 314317f06deSGavin Shan eeh_pcid_put(dev); 315317f06deSGavin Shan return NULL; 316317f06deSGavin Shan } 317317f06deSGavin Shan 3185cfb20b9SGavin Shan static void *eeh_dev_restore_state(void *data, void *userdata) 3195cfb20b9SGavin Shan { 3205cfb20b9SGavin Shan struct eeh_dev *edev = data; 3215cfb20b9SGavin Shan struct pci_dev *pdev; 3225cfb20b9SGavin Shan 3235cfb20b9SGavin Shan if (!edev) 3245cfb20b9SGavin Shan return NULL; 3255cfb20b9SGavin Shan 3265a0cdbfdSGavin Shan /* 3275a0cdbfdSGavin Shan * The content in the config space isn't saved because 3285a0cdbfdSGavin Shan * the blocked config space on some adapters. We have 3295a0cdbfdSGavin Shan * to restore the initial saved config space when the 3305a0cdbfdSGavin Shan * EEH device is created. 3315a0cdbfdSGavin Shan */ 3325a0cdbfdSGavin Shan if (edev->pe && (edev->pe->state & EEH_PE_CFG_RESTRICTED)) { 3335a0cdbfdSGavin Shan if (list_is_last(&edev->list, &edev->pe->edevs)) 3345a0cdbfdSGavin Shan eeh_pe_restore_bars(edev->pe); 3355a0cdbfdSGavin Shan 3365a0cdbfdSGavin Shan return NULL; 3375a0cdbfdSGavin Shan } 3385a0cdbfdSGavin Shan 3395cfb20b9SGavin Shan pdev = eeh_dev_to_pci_dev(edev); 3405cfb20b9SGavin Shan if (!pdev) 3415cfb20b9SGavin Shan return NULL; 3425cfb20b9SGavin Shan 3435cfb20b9SGavin Shan pci_restore_state(pdev); 3445cfb20b9SGavin Shan return NULL; 3455cfb20b9SGavin Shan } 3465cfb20b9SGavin Shan 347317f06deSGavin Shan /** 348317f06deSGavin Shan * eeh_report_resume - Tell device to resume normal operations 349317f06deSGavin Shan * @data: eeh device 350317f06deSGavin Shan * @userdata: return value 351317f06deSGavin Shan * 352317f06deSGavin Shan * This routine must be called to notify the device driver that it 353317f06deSGavin Shan * could resume so that the device driver can do some initialization 354317f06deSGavin Shan * to make the recovered device work again. 355317f06deSGavin Shan */ 356317f06deSGavin Shan static void *eeh_report_resume(void *data, void *userdata) 357317f06deSGavin Shan { 358317f06deSGavin Shan struct eeh_dev *edev = (struct eeh_dev *)data; 359317f06deSGavin Shan struct pci_dev *dev = eeh_dev_to_pci_dev(edev); 36067086e32SWei Yang bool was_in_error; 361317f06deSGavin Shan struct pci_driver *driver; 362317f06deSGavin Shan 3632311cca5SGavin Shan if (!dev || eeh_dev_removed(edev) || eeh_pe_passed(edev->pe)) 364d2b0f6f7SGavin Shan return NULL; 365317f06deSGavin Shan dev->error_state = pci_channel_io_normal; 366317f06deSGavin Shan 367317f06deSGavin Shan driver = eeh_pcid_get(dev); 368317f06deSGavin Shan if (!driver) return NULL; 369317f06deSGavin Shan 37067086e32SWei Yang was_in_error = edev->in_error; 37167086e32SWei Yang edev->in_error = false; 372317f06deSGavin Shan eeh_enable_irq(dev); 373317f06deSGavin Shan 374317f06deSGavin Shan if (!driver->err_handler || 375f26c7a03SGavin Shan !driver->err_handler->resume || 37667086e32SWei Yang (edev->mode & EEH_DEV_NO_HANDLER) || !was_in_error) { 377f26c7a03SGavin Shan edev->mode &= ~EEH_DEV_NO_HANDLER; 378317f06deSGavin Shan eeh_pcid_put(dev); 379317f06deSGavin Shan return NULL; 380317f06deSGavin Shan } 381317f06deSGavin Shan 382317f06deSGavin Shan driver->err_handler->resume(dev); 383317f06deSGavin Shan 384317f06deSGavin Shan eeh_pcid_put(dev); 385856e1eb9SBryant G. Ly pci_uevent_ers(dev, PCI_ERS_RESULT_RECOVERED); 386856e1eb9SBryant G. Ly #ifdef CONFIG_PCI_IOV 387521ca5a9SJuan J. Alvarez if (eeh_ops->notify_resume && eeh_dev_to_pdn(edev)) 388856e1eb9SBryant G. Ly eeh_ops->notify_resume(eeh_dev_to_pdn(edev)); 389856e1eb9SBryant G. Ly #endif 390317f06deSGavin Shan return NULL; 391317f06deSGavin Shan } 392317f06deSGavin Shan 393317f06deSGavin Shan /** 394317f06deSGavin Shan * eeh_report_failure - Tell device driver that device is dead. 395317f06deSGavin Shan * @data: eeh device 396317f06deSGavin Shan * @userdata: return value 397317f06deSGavin Shan * 398317f06deSGavin Shan * This informs the device driver that the device is permanently 399317f06deSGavin Shan * dead, and that no further recovery attempts will be made on it. 400317f06deSGavin Shan */ 401317f06deSGavin Shan static void *eeh_report_failure(void *data, void *userdata) 402317f06deSGavin Shan { 403317f06deSGavin Shan struct eeh_dev *edev = (struct eeh_dev *)data; 404317f06deSGavin Shan struct pci_dev *dev = eeh_dev_to_pci_dev(edev); 405317f06deSGavin Shan struct pci_driver *driver; 406317f06deSGavin Shan 4072311cca5SGavin Shan if (!dev || eeh_dev_removed(edev) || eeh_pe_passed(edev->pe)) 408d2b0f6f7SGavin Shan return NULL; 409317f06deSGavin Shan dev->error_state = pci_channel_io_perm_failure; 410317f06deSGavin Shan 411317f06deSGavin Shan driver = eeh_pcid_get(dev); 412317f06deSGavin Shan if (!driver) return NULL; 413317f06deSGavin Shan 414317f06deSGavin Shan eeh_disable_irq(dev); 415317f06deSGavin Shan 416317f06deSGavin Shan if (!driver->err_handler || 417317f06deSGavin Shan !driver->err_handler->error_detected) { 418317f06deSGavin Shan eeh_pcid_put(dev); 419317f06deSGavin Shan return NULL; 420317f06deSGavin Shan } 421317f06deSGavin Shan 422317f06deSGavin Shan driver->err_handler->error_detected(dev, pci_channel_io_perm_failure); 423317f06deSGavin Shan 424317f06deSGavin Shan eeh_pcid_put(dev); 425856e1eb9SBryant G. Ly pci_uevent_ers(dev, PCI_ERS_RESULT_DISCONNECT); 426317f06deSGavin Shan return NULL; 427317f06deSGavin Shan } 428317f06deSGavin Shan 42967086e32SWei Yang static void *eeh_add_virt_device(void *data, void *userdata) 43067086e32SWei Yang { 43167086e32SWei Yang struct pci_driver *driver; 43267086e32SWei Yang struct eeh_dev *edev = (struct eeh_dev *)data; 43367086e32SWei Yang struct pci_dev *dev = eeh_dev_to_pci_dev(edev); 43467086e32SWei Yang struct pci_dn *pdn = eeh_dev_to_pdn(edev); 43567086e32SWei Yang 43667086e32SWei Yang if (!(edev->physfn)) { 43767086e32SWei Yang pr_warn("%s: EEH dev %04x:%02x:%02x.%01x not for VF\n", 43869672bd7SAlexey Kardashevskiy __func__, pdn->phb->global_number, pdn->busno, 43967086e32SWei Yang PCI_SLOT(pdn->devfn), PCI_FUNC(pdn->devfn)); 44067086e32SWei Yang return NULL; 44167086e32SWei Yang } 44267086e32SWei Yang 44367086e32SWei Yang driver = eeh_pcid_get(dev); 44467086e32SWei Yang if (driver) { 44567086e32SWei Yang eeh_pcid_put(dev); 44667086e32SWei Yang if (driver->err_handler) 44767086e32SWei Yang return NULL; 44867086e32SWei Yang } 44967086e32SWei Yang 450988fc3baSBryant G. Ly #ifdef CONFIG_PCI_IOV 451753f6124SJan H. Schönherr pci_iov_add_virtfn(edev->physfn, pdn->vf_index); 45267086e32SWei Yang #endif 45367086e32SWei Yang return NULL; 45467086e32SWei Yang } 45567086e32SWei Yang 456f5c57710SGavin Shan static void *eeh_rmv_device(void *data, void *userdata) 457f5c57710SGavin Shan { 458f5c57710SGavin Shan struct pci_driver *driver; 459f5c57710SGavin Shan struct eeh_dev *edev = (struct eeh_dev *)data; 460f5c57710SGavin Shan struct pci_dev *dev = eeh_dev_to_pci_dev(edev); 46167086e32SWei Yang struct eeh_rmv_data *rmv_data = (struct eeh_rmv_data *)userdata; 46267086e32SWei Yang int *removed = rmv_data ? &rmv_data->removed : NULL; 463f5c57710SGavin Shan 464f5c57710SGavin Shan /* 465f5c57710SGavin Shan * Actually, we should remove the PCI bridges as well. 466f5c57710SGavin Shan * However, that's lots of complexity to do that, 467f5c57710SGavin Shan * particularly some of devices under the bridge might 468f5c57710SGavin Shan * support EEH. So we just care about PCI devices for 469f5c57710SGavin Shan * simplicity here. 470f5c57710SGavin Shan */ 47193de6901SBjorn Helgaas if (!dev || (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)) 472f5c57710SGavin Shan return NULL; 4738cc6b6cdSThadeu Lima de Souza Cascardo 474d2b0f6f7SGavin Shan /* 475d2b0f6f7SGavin Shan * We rely on count-based pcibios_release_device() to 476d2b0f6f7SGavin Shan * detach permanently offlined PEs. Unfortunately, that's 477d2b0f6f7SGavin Shan * not reliable enough. We might have the permanently 478d2b0f6f7SGavin Shan * offlined PEs attached, but we needn't take care of 479d2b0f6f7SGavin Shan * them and their child devices. 480d2b0f6f7SGavin Shan */ 481d2b0f6f7SGavin Shan if (eeh_dev_removed(edev)) 482d2b0f6f7SGavin Shan return NULL; 483d2b0f6f7SGavin Shan 484f5c57710SGavin Shan driver = eeh_pcid_get(dev); 4858cc6b6cdSThadeu Lima de Souza Cascardo if (driver) { 4868cc6b6cdSThadeu Lima de Souza Cascardo eeh_pcid_put(dev); 48767086e32SWei Yang if (removed && 4883fa7bf72SGavin Shan eeh_pe_passed(edev->pe)) 4893fa7bf72SGavin Shan return NULL; 4903fa7bf72SGavin Shan if (removed && 49167086e32SWei Yang driver->err_handler && 492f2da4ccfSGavin Shan driver->err_handler->error_detected && 493f6bf0fa1SGavin Shan driver->err_handler->slot_reset) 494f5c57710SGavin Shan return NULL; 4958cc6b6cdSThadeu Lima de Souza Cascardo } 496f5c57710SGavin Shan 497f5c57710SGavin Shan /* Remove it from PCI subsystem */ 498f5c57710SGavin Shan pr_debug("EEH: Removing %s without EEH sensitive driver\n", 499f5c57710SGavin Shan pci_name(dev)); 500f5c57710SGavin Shan edev->bus = dev->bus; 501f5c57710SGavin Shan edev->mode |= EEH_DEV_DISCONNECTED; 50267086e32SWei Yang if (removed) 503f5c57710SGavin Shan (*removed)++; 504f5c57710SGavin Shan 50567086e32SWei Yang if (edev->physfn) { 506988fc3baSBryant G. Ly #ifdef CONFIG_PCI_IOV 50767086e32SWei Yang struct pci_dn *pdn = eeh_dev_to_pdn(edev); 50867086e32SWei Yang 509753f6124SJan H. Schönherr pci_iov_remove_virtfn(edev->physfn, pdn->vf_index); 51067086e32SWei Yang edev->pdev = NULL; 51167086e32SWei Yang 51267086e32SWei Yang /* 51367086e32SWei Yang * We have to set the VF PE number to invalid one, which is 51467086e32SWei Yang * required to plug the VF successfully. 51567086e32SWei Yang */ 51667086e32SWei Yang pdn->pe_number = IODA_INVALID_PE; 51767086e32SWei Yang #endif 51867086e32SWei Yang if (rmv_data) 51967086e32SWei Yang list_add(&edev->rmv_list, &rmv_data->edev_list); 52067086e32SWei Yang } else { 5211c2042c8SRafael J. Wysocki pci_lock_rescan_remove(); 522f5c57710SGavin Shan pci_stop_and_remove_bus_device(dev); 5231c2042c8SRafael J. Wysocki pci_unlock_rescan_remove(); 52467086e32SWei Yang } 525f5c57710SGavin Shan 526f5c57710SGavin Shan return NULL; 527f5c57710SGavin Shan } 528f5c57710SGavin Shan 529f5c57710SGavin Shan static void *eeh_pe_detach_dev(void *data, void *userdata) 530f5c57710SGavin Shan { 531f5c57710SGavin Shan struct eeh_pe *pe = (struct eeh_pe *)data; 532f5c57710SGavin Shan struct eeh_dev *edev, *tmp; 533f5c57710SGavin Shan 534f5c57710SGavin Shan eeh_pe_for_each_dev(pe, edev, tmp) { 535f5c57710SGavin Shan if (!(edev->mode & EEH_DEV_DISCONNECTED)) 536f5c57710SGavin Shan continue; 537f5c57710SGavin Shan 538f5c57710SGavin Shan edev->mode &= ~(EEH_DEV_DISCONNECTED | EEH_DEV_IRQ_DISABLED); 539f5c57710SGavin Shan eeh_rmv_from_parent_pe(edev); 540f5c57710SGavin Shan } 541f5c57710SGavin Shan 542f5c57710SGavin Shan return NULL; 543f5c57710SGavin Shan } 544f5c57710SGavin Shan 54578954700SGavin Shan /* 54678954700SGavin Shan * Explicitly clear PE's frozen state for PowerNV where 54778954700SGavin Shan * we have frozen PE until BAR restore is completed. It's 54878954700SGavin Shan * harmless to clear it for pSeries. To be consistent with 54978954700SGavin Shan * PE reset (for 3 times), we try to clear the frozen state 55078954700SGavin Shan * for 3 times as well. 55178954700SGavin Shan */ 5522c665992SGavin Shan static void *__eeh_clear_pe_frozen_state(void *data, void *flag) 55378954700SGavin Shan { 5542c665992SGavin Shan struct eeh_pe *pe = (struct eeh_pe *)data; 555f05fea5bSGavin Shan bool clear_sw_state = *(bool *)flag; 556c9dd0143SGavin Shan int i, rc = 1; 55778954700SGavin Shan 558c9dd0143SGavin Shan for (i = 0; rc && i < 3; i++) 5595cfb20b9SGavin Shan rc = eeh_unfreeze_pe(pe, clear_sw_state); 56078954700SGavin Shan 561c9dd0143SGavin Shan /* Stop immediately on any errors */ 5622c665992SGavin Shan if (rc) { 563c9dd0143SGavin Shan pr_warn("%s: Failure %d unfreezing PHB#%x-PE#%x\n", 564c9dd0143SGavin Shan __func__, rc, pe->phb->global_number, pe->addr); 5652c665992SGavin Shan return (void *)pe; 5662c665992SGavin Shan } 5672c665992SGavin Shan 5682c665992SGavin Shan return NULL; 5692c665992SGavin Shan } 5702c665992SGavin Shan 5715cfb20b9SGavin Shan static int eeh_clear_pe_frozen_state(struct eeh_pe *pe, 5725cfb20b9SGavin Shan bool clear_sw_state) 5732c665992SGavin Shan { 5742c665992SGavin Shan void *rc; 5752c665992SGavin Shan 5765cfb20b9SGavin Shan rc = eeh_pe_traverse(pe, __eeh_clear_pe_frozen_state, &clear_sw_state); 5772c665992SGavin Shan if (!rc) 57878954700SGavin Shan eeh_pe_state_clear(pe, EEH_PE_ISOLATED); 57978954700SGavin Shan 5802c665992SGavin Shan return rc ? -EIO : 0; 58178954700SGavin Shan } 58278954700SGavin Shan 5835cfb20b9SGavin Shan int eeh_pe_reset_and_recover(struct eeh_pe *pe) 5845cfb20b9SGavin Shan { 5852efc771fSGavin Shan int ret; 5865cfb20b9SGavin Shan 5875cfb20b9SGavin Shan /* Bail if the PE is being recovered */ 5885cfb20b9SGavin Shan if (pe->state & EEH_PE_RECOVERING) 5895cfb20b9SGavin Shan return 0; 5905cfb20b9SGavin Shan 5915cfb20b9SGavin Shan /* Put the PE into recovery mode */ 5925cfb20b9SGavin Shan eeh_pe_state_mark(pe, EEH_PE_RECOVERING); 5935cfb20b9SGavin Shan 5945cfb20b9SGavin Shan /* Save states */ 5955cfb20b9SGavin Shan eeh_pe_dev_traverse(pe, eeh_dev_save_state, NULL); 5965cfb20b9SGavin Shan 5975cfb20b9SGavin Shan /* Issue reset */ 5986654c936SRussell Currey ret = eeh_pe_reset_full(pe); 5995cfb20b9SGavin Shan if (ret) { 60028bf36f9SGavin Shan eeh_pe_state_clear(pe, EEH_PE_RECOVERING); 6015cfb20b9SGavin Shan return ret; 6025cfb20b9SGavin Shan } 6035cfb20b9SGavin Shan 6045cfb20b9SGavin Shan /* Unfreeze the PE */ 6055cfb20b9SGavin Shan ret = eeh_clear_pe_frozen_state(pe, true); 6065cfb20b9SGavin Shan if (ret) { 6075cfb20b9SGavin Shan eeh_pe_state_clear(pe, EEH_PE_RECOVERING); 6085cfb20b9SGavin Shan return ret; 6095cfb20b9SGavin Shan } 6105cfb20b9SGavin Shan 6115cfb20b9SGavin Shan /* Restore device state */ 6125cfb20b9SGavin Shan eeh_pe_dev_traverse(pe, eeh_dev_restore_state, NULL); 6135cfb20b9SGavin Shan 6145cfb20b9SGavin Shan /* Clear recovery mode */ 6155cfb20b9SGavin Shan eeh_pe_state_clear(pe, EEH_PE_RECOVERING); 6165cfb20b9SGavin Shan 6175cfb20b9SGavin Shan return 0; 6185cfb20b9SGavin Shan } 6195cfb20b9SGavin Shan 620317f06deSGavin Shan /** 621317f06deSGavin Shan * eeh_reset_device - Perform actual reset of a pci slot 622317f06deSGavin Shan * @pe: EEH PE 623317f06deSGavin Shan * @bus: PCI bus corresponding to the isolcated slot 624317f06deSGavin Shan * 625317f06deSGavin Shan * This routine must be called to do reset on the indicated PE. 626317f06deSGavin Shan * During the reset, udev might be invoked because those affected 627317f06deSGavin Shan * PCI devices will be removed and then added. 628317f06deSGavin Shan */ 62967086e32SWei Yang static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus, 63067086e32SWei Yang struct eeh_rmv_data *rmv_data) 631317f06deSGavin Shan { 632f5c57710SGavin Shan struct pci_bus *frozen_bus = eeh_pe_bus_get(pe); 633edfd17ffSArnd Bergmann time64_t tstamp; 63467086e32SWei Yang int cnt, rc; 63567086e32SWei Yang struct eeh_dev *edev; 636317f06deSGavin Shan 637317f06deSGavin Shan /* pcibios will clear the counter; save the value */ 638317f06deSGavin Shan cnt = pe->freeze_count; 6395a71978eSGavin Shan tstamp = pe->tstamp; 640317f06deSGavin Shan 641317f06deSGavin Shan /* 642317f06deSGavin Shan * We don't remove the corresponding PE instances because 643317f06deSGavin Shan * we need the information afterwords. The attached EEH 644317f06deSGavin Shan * devices are expected to be attached soon when calling 645bd251b89SGavin Shan * into pci_hp_add_devices(). 646317f06deSGavin Shan */ 647807a827dSGavin Shan eeh_pe_state_mark(pe, EEH_PE_KEEP); 6481c2042c8SRafael J. Wysocki if (bus) { 64967086e32SWei Yang if (pe->type & EEH_PE_VF) { 65067086e32SWei Yang eeh_pe_dev_traverse(pe, eeh_rmv_device, NULL); 65167086e32SWei Yang } else { 6521c2042c8SRafael J. Wysocki pci_lock_rescan_remove(); 653bd251b89SGavin Shan pci_hp_remove_devices(bus); 6541c2042c8SRafael J. Wysocki pci_unlock_rescan_remove(); 65567086e32SWei Yang } 6561c2042c8SRafael J. Wysocki } else if (frozen_bus) { 657cca0e542SGavin Shan eeh_pe_dev_traverse(pe, eeh_rmv_device, rmv_data); 6581c2042c8SRafael J. Wysocki } 659317f06deSGavin Shan 660d0914f50SGavin Shan /* 661d0914f50SGavin Shan * Reset the pci controller. (Asserts RST#; resets config space). 662317f06deSGavin Shan * Reconfigure bridges and devices. Don't try to bring the system 663317f06deSGavin Shan * up if the reset failed for some reason. 664d0914f50SGavin Shan * 665d0914f50SGavin Shan * During the reset, it's very dangerous to have uncontrolled PCI 666d0914f50SGavin Shan * config accesses. So we prefer to block them. However, controlled 667d0914f50SGavin Shan * PCI config accesses initiated from EEH itself are allowed. 668317f06deSGavin Shan */ 6696654c936SRussell Currey rc = eeh_pe_reset_full(pe); 67028bf36f9SGavin Shan if (rc) 671317f06deSGavin Shan return rc; 672317f06deSGavin Shan 6731c2042c8SRafael J. Wysocki pci_lock_rescan_remove(); 6741c2042c8SRafael J. Wysocki 675317f06deSGavin Shan /* Restore PE */ 676317f06deSGavin Shan eeh_ops->configure_bridge(pe); 677317f06deSGavin Shan eeh_pe_restore_bars(pe); 678317f06deSGavin Shan 679dc9c41bdSAndrew Donnellan /* Clear frozen state */ 6805cfb20b9SGavin Shan rc = eeh_clear_pe_frozen_state(pe, false); 681409bf7f8SAndrew Donnellan if (rc) { 682409bf7f8SAndrew Donnellan pci_unlock_rescan_remove(); 68378954700SGavin Shan return rc; 684409bf7f8SAndrew Donnellan } 68578954700SGavin Shan 686317f06deSGavin Shan /* Give the system 5 seconds to finish running the user-space 687317f06deSGavin Shan * hotplug shutdown scripts, e.g. ifdown for ethernet. Yes, 688317f06deSGavin Shan * this is a hack, but if we don't do this, and try to bring 689317f06deSGavin Shan * the device up before the scripts have taken it down, 690317f06deSGavin Shan * potentially weird things happen. 691317f06deSGavin Shan */ 692317f06deSGavin Shan if (bus) { 693f5c57710SGavin Shan pr_info("EEH: Sleep 5s ahead of complete hotplug\n"); 694317f06deSGavin Shan ssleep(5); 695f5c57710SGavin Shan 696f5c57710SGavin Shan /* 697f5c57710SGavin Shan * The EEH device is still connected with its parent 698f5c57710SGavin Shan * PE. We should disconnect it so the binding can be 699f5c57710SGavin Shan * rebuilt when adding PCI devices. 700f5c57710SGavin Shan */ 70167086e32SWei Yang edev = list_first_entry(&pe->edevs, struct eeh_dev, list); 702f5c57710SGavin Shan eeh_pe_traverse(pe, eeh_pe_detach_dev, NULL); 703a3aa256bSGavin Shan if (pe->type & EEH_PE_VF) { 70467086e32SWei Yang eeh_add_virt_device(edev, NULL); 705a3aa256bSGavin Shan } else { 706a3aa256bSGavin Shan eeh_pe_state_clear(pe, EEH_PE_PRI_BUS); 707bd251b89SGavin Shan pci_hp_add_devices(bus); 708a3aa256bSGavin Shan } 70967086e32SWei Yang } else if (frozen_bus && rmv_data->removed) { 710f5c57710SGavin Shan pr_info("EEH: Sleep 5s ahead of partial hotplug\n"); 711f5c57710SGavin Shan ssleep(5); 712f5c57710SGavin Shan 71367086e32SWei Yang edev = list_first_entry(&pe->edevs, struct eeh_dev, list); 714f5c57710SGavin Shan eeh_pe_traverse(pe, eeh_pe_detach_dev, NULL); 71567086e32SWei Yang if (pe->type & EEH_PE_VF) 71667086e32SWei Yang eeh_add_virt_device(edev, NULL); 71767086e32SWei Yang else 718bd251b89SGavin Shan pci_hp_add_devices(frozen_bus); 719317f06deSGavin Shan } 720f5c57710SGavin Shan eeh_pe_state_clear(pe, EEH_PE_KEEP); 7215a71978eSGavin Shan 7225a71978eSGavin Shan pe->tstamp = tstamp; 723317f06deSGavin Shan pe->freeze_count = cnt; 724317f06deSGavin Shan 7251c2042c8SRafael J. Wysocki pci_unlock_rescan_remove(); 726317f06deSGavin Shan return 0; 727317f06deSGavin Shan } 728317f06deSGavin Shan 729317f06deSGavin Shan /* The longest amount of time to wait for a pci device 730317f06deSGavin Shan * to come back on line, in seconds. 731317f06deSGavin Shan */ 732fb48dc22SBrian King #define MAX_WAIT_FOR_RECOVERY 300 733317f06deSGavin Shan 734c0b64978SRussell Currey /** 735c0b64978SRussell Currey * eeh_handle_normal_event - Handle EEH events on a specific PE 736c0b64978SRussell Currey * @pe: EEH PE 737c0b64978SRussell Currey * 738c0b64978SRussell Currey * Attempts to recover the given PE. If recovery fails or the PE has failed 739c0b64978SRussell Currey * too many times, remove the PE. 740c0b64978SRussell Currey * 74168701780SSam Bobroff * While PHB detects address or data parity errors on particular PCI 74268701780SSam Bobroff * slot, the associated PE will be frozen. Besides, DMA's occurring 74368701780SSam Bobroff * to wild addresses (which usually happen due to bugs in device 74468701780SSam Bobroff * drivers or in PCI adapter firmware) can cause EEH error. #SERR, 74568701780SSam Bobroff * #PERR or other misc PCI-related errors also can trigger EEH errors. 74668701780SSam Bobroff * 74768701780SSam Bobroff * Recovery process consists of unplugging the device driver (which 74868701780SSam Bobroff * generated hotplug events to userspace), then issuing a PCI #RST to 74968701780SSam Bobroff * the device, then reconfiguring the PCI config space for all bridges 75068701780SSam Bobroff * & devices under this slot, and then finally restarting the device 75168701780SSam Bobroff * drivers (which cause a second set of hotplug events to go out to 75268701780SSam Bobroff * userspace). 75368701780SSam Bobroff * 754c0b64978SRussell Currey * Returns true if @pe should no longer be used, else false. 755c0b64978SRussell Currey */ 75668701780SSam Bobroff bool eeh_handle_normal_event(struct eeh_pe *pe) 757317f06deSGavin Shan { 758317f06deSGavin Shan struct pci_bus *frozen_bus; 75967086e32SWei Yang struct eeh_dev *edev, *tmp; 760317f06deSGavin Shan int rc = 0; 761317f06deSGavin Shan enum pci_ers_result result = PCI_ERS_RESULT_NONE; 76267086e32SWei Yang struct eeh_rmv_data rmv_data = {LIST_HEAD_INIT(rmv_data.edev_list), 0}; 763317f06deSGavin Shan 764317f06deSGavin Shan frozen_bus = eeh_pe_bus_get(pe); 765317f06deSGavin Shan if (!frozen_bus) { 7661f52f176SRussell Currey pr_err("%s: Cannot find PCI bus for PHB#%x-PE#%x\n", 767317f06deSGavin Shan __func__, pe->phb->global_number, pe->addr); 768daeba295SRussell Currey return false; 769317f06deSGavin Shan } 770317f06deSGavin Shan 7715a71978eSGavin Shan eeh_pe_update_time_stamp(pe); 772317f06deSGavin Shan pe->freeze_count++; 773c0b64978SRussell Currey if (pe->freeze_count > eeh_max_freezes) { 774c0b64978SRussell Currey pr_err("EEH: PHB#%x-PE#%x has failed %d times in the\n" 775c0b64978SRussell Currey "last hour and has been permanently disabled.\n", 776c0b64978SRussell Currey pe->phb->global_number, pe->addr, 777c0b64978SRussell Currey pe->freeze_count); 778c0b64978SRussell Currey goto hard_fail; 779c0b64978SRussell Currey } 7800dae2743SGavin Shan pr_warn("EEH: This PCI device has failed %d times in the last hour\n", 781317f06deSGavin Shan pe->freeze_count); 782317f06deSGavin Shan 783317f06deSGavin Shan /* Walk the various device drivers attached to this slot through 784317f06deSGavin Shan * a reset sequence, giving each an opportunity to do what it needs 785317f06deSGavin Shan * to accomplish the reset. Each child gets a report of the 786317f06deSGavin Shan * status ... if any child can't handle the reset, then the entire 787317f06deSGavin Shan * slot is dlpar removed and added. 7888234fcedSGavin Shan * 7898234fcedSGavin Shan * When the PHB is fenced, we have to issue a reset to recover from 7908234fcedSGavin Shan * the error. Override the result if necessary to have partially 7918234fcedSGavin Shan * hotplug for this case. 792317f06deSGavin Shan */ 79356ca4fdeSGavin Shan pr_info("EEH: Notify device drivers to shutdown\n"); 794317f06deSGavin Shan eeh_pe_dev_traverse(pe, eeh_report_error, &result); 7958234fcedSGavin Shan if ((pe->type & EEH_PE_PHB) && 7968234fcedSGavin Shan result != PCI_ERS_RESULT_NONE && 7978234fcedSGavin Shan result != PCI_ERS_RESULT_NEED_RESET) 7988234fcedSGavin Shan result = PCI_ERS_RESULT_NEED_RESET; 799317f06deSGavin Shan 800317f06deSGavin Shan /* Get the current PCI slot state. This can take a long time, 8012ac3990cSWei Yang * sometimes over 300 seconds for certain systems. 802317f06deSGavin Shan */ 803317f06deSGavin Shan rc = eeh_ops->wait_state(pe, MAX_WAIT_FOR_RECOVERY*1000); 804317f06deSGavin Shan if (rc < 0 || rc == EEH_STATE_NOT_SUPPORT) { 8050dae2743SGavin Shan pr_warn("EEH: Permanent failure\n"); 806317f06deSGavin Shan goto hard_fail; 807317f06deSGavin Shan } 808317f06deSGavin Shan 809317f06deSGavin Shan /* Since rtas may enable MMIO when posting the error log, 810317f06deSGavin Shan * don't post the error log until after all dev drivers 811317f06deSGavin Shan * have been informed. 812317f06deSGavin Shan */ 81356ca4fdeSGavin Shan pr_info("EEH: Collect temporary log\n"); 814317f06deSGavin Shan eeh_slot_error_detail(pe, EEH_LOG_TEMP); 815317f06deSGavin Shan 816317f06deSGavin Shan /* If all device drivers were EEH-unaware, then shut 817317f06deSGavin Shan * down all of the device drivers, and hope they 818317f06deSGavin Shan * go down willingly, without panicing the system. 819317f06deSGavin Shan */ 820317f06deSGavin Shan if (result == PCI_ERS_RESULT_NONE) { 82156ca4fdeSGavin Shan pr_info("EEH: Reset with hotplug activity\n"); 82267086e32SWei Yang rc = eeh_reset_device(pe, frozen_bus, NULL); 823317f06deSGavin Shan if (rc) { 8240dae2743SGavin Shan pr_warn("%s: Unable to reset, err=%d\n", 82556ca4fdeSGavin Shan __func__, rc); 826317f06deSGavin Shan goto hard_fail; 827317f06deSGavin Shan } 828317f06deSGavin Shan } 829317f06deSGavin Shan 830317f06deSGavin Shan /* If all devices reported they can proceed, then re-enable MMIO */ 831317f06deSGavin Shan if (result == PCI_ERS_RESULT_CAN_RECOVER) { 83256ca4fdeSGavin Shan pr_info("EEH: Enable I/O for affected devices\n"); 833317f06deSGavin Shan rc = eeh_pci_enable(pe, EEH_OPT_THAW_MMIO); 834317f06deSGavin Shan 835317f06deSGavin Shan if (rc < 0) 836317f06deSGavin Shan goto hard_fail; 837317f06deSGavin Shan if (rc) { 838317f06deSGavin Shan result = PCI_ERS_RESULT_NEED_RESET; 839317f06deSGavin Shan } else { 84056ca4fdeSGavin Shan pr_info("EEH: Notify device drivers to resume I/O\n"); 841317f06deSGavin Shan eeh_pe_dev_traverse(pe, eeh_report_mmio_enabled, &result); 842317f06deSGavin Shan } 843317f06deSGavin Shan } 844317f06deSGavin Shan 845317f06deSGavin Shan /* If all devices reported they can proceed, then re-enable DMA */ 846317f06deSGavin Shan if (result == PCI_ERS_RESULT_CAN_RECOVER) { 84756ca4fdeSGavin Shan pr_info("EEH: Enabled DMA for affected devices\n"); 848317f06deSGavin Shan rc = eeh_pci_enable(pe, EEH_OPT_THAW_DMA); 849317f06deSGavin Shan 850317f06deSGavin Shan if (rc < 0) 851317f06deSGavin Shan goto hard_fail; 85235845a78SGavin Shan if (rc) { 853317f06deSGavin Shan result = PCI_ERS_RESULT_NEED_RESET; 85435845a78SGavin Shan } else { 85535845a78SGavin Shan /* 85635845a78SGavin Shan * We didn't do PE reset for the case. The PE 85735845a78SGavin Shan * is still in frozen state. Clear it before 85835845a78SGavin Shan * resuming the PE. 85935845a78SGavin Shan */ 86035845a78SGavin Shan eeh_pe_state_clear(pe, EEH_PE_ISOLATED); 861317f06deSGavin Shan result = PCI_ERS_RESULT_RECOVERED; 862317f06deSGavin Shan } 86335845a78SGavin Shan } 864317f06deSGavin Shan 865317f06deSGavin Shan /* If any device has a hard failure, then shut off everything. */ 866317f06deSGavin Shan if (result == PCI_ERS_RESULT_DISCONNECT) { 8670dae2743SGavin Shan pr_warn("EEH: Device driver gave up\n"); 868317f06deSGavin Shan goto hard_fail; 869317f06deSGavin Shan } 870317f06deSGavin Shan 871317f06deSGavin Shan /* If any device called out for a reset, then reset the slot */ 872317f06deSGavin Shan if (result == PCI_ERS_RESULT_NEED_RESET) { 87356ca4fdeSGavin Shan pr_info("EEH: Reset without hotplug activity\n"); 87467086e32SWei Yang rc = eeh_reset_device(pe, NULL, &rmv_data); 875317f06deSGavin Shan if (rc) { 8760dae2743SGavin Shan pr_warn("%s: Cannot reset, err=%d\n", 87756ca4fdeSGavin Shan __func__, rc); 878317f06deSGavin Shan goto hard_fail; 879317f06deSGavin Shan } 88056ca4fdeSGavin Shan 88156ca4fdeSGavin Shan pr_info("EEH: Notify device drivers " 88256ca4fdeSGavin Shan "the completion of reset\n"); 883317f06deSGavin Shan result = PCI_ERS_RESULT_NONE; 884317f06deSGavin Shan eeh_pe_dev_traverse(pe, eeh_report_reset, &result); 885317f06deSGavin Shan } 886317f06deSGavin Shan 887317f06deSGavin Shan /* All devices should claim they have recovered by now. */ 888317f06deSGavin Shan if ((result != PCI_ERS_RESULT_RECOVERED) && 889317f06deSGavin Shan (result != PCI_ERS_RESULT_NONE)) { 8900dae2743SGavin Shan pr_warn("EEH: Not recovered\n"); 891317f06deSGavin Shan goto hard_fail; 892317f06deSGavin Shan } 893317f06deSGavin Shan 89467086e32SWei Yang /* 89567086e32SWei Yang * For those hot removed VFs, we should add back them after PF get 89667086e32SWei Yang * recovered properly. 89767086e32SWei Yang */ 89867086e32SWei Yang list_for_each_entry_safe(edev, tmp, &rmv_data.edev_list, rmv_list) { 89967086e32SWei Yang eeh_add_virt_device(edev, NULL); 90067086e32SWei Yang list_del(&edev->rmv_list); 90167086e32SWei Yang } 90267086e32SWei Yang 903317f06deSGavin Shan /* Tell all device drivers that they can resume operations */ 90456ca4fdeSGavin Shan pr_info("EEH: Notify device driver to resume\n"); 905317f06deSGavin Shan eeh_pe_dev_traverse(pe, eeh_report_resume, NULL); 906317f06deSGavin Shan 907daeba295SRussell Currey return false; 908317f06deSGavin Shan 909c0b64978SRussell Currey hard_fail: 910317f06deSGavin Shan /* 911317f06deSGavin Shan * About 90% of all real-life EEH failures in the field 912317f06deSGavin Shan * are due to poorly seated PCI cards. Only 10% or so are 913317f06deSGavin Shan * due to actual, failed cards. 914317f06deSGavin Shan */ 9151f52f176SRussell Currey pr_err("EEH: Unable to recover from failure from PHB#%x-PE#%x.\n" 916317f06deSGavin Shan "Please try reseating or replacing it\n", 917317f06deSGavin Shan pe->phb->global_number, pe->addr); 918317f06deSGavin Shan 919317f06deSGavin Shan eeh_slot_error_detail(pe, EEH_LOG_PERM); 920317f06deSGavin Shan 921317f06deSGavin Shan /* Notify all devices that they're about to go down. */ 922317f06deSGavin Shan eeh_pe_dev_traverse(pe, eeh_report_failure, NULL); 923317f06deSGavin Shan 924d2b0f6f7SGavin Shan /* Mark the PE to be removed permanently */ 925432227e9SGavin Shan eeh_pe_state_mark(pe, EEH_PE_REMOVED); 926d2b0f6f7SGavin Shan 927d2b0f6f7SGavin Shan /* 928d2b0f6f7SGavin Shan * Shut down the device drivers for good. We mark 929d2b0f6f7SGavin Shan * all removed devices correctly to avoid access 930d2b0f6f7SGavin Shan * the their PCI config any more. 931d2b0f6f7SGavin Shan */ 9321c2042c8SRafael J. Wysocki if (frozen_bus) { 93367086e32SWei Yang if (pe->type & EEH_PE_VF) { 93467086e32SWei Yang eeh_pe_dev_traverse(pe, eeh_rmv_device, NULL); 93567086e32SWei Yang eeh_pe_dev_mode_mark(pe, EEH_DEV_REMOVED); 93667086e32SWei Yang } else { 93705ba75f8SGavin Shan eeh_pe_state_clear(pe, EEH_PE_PRI_BUS); 938d2b0f6f7SGavin Shan eeh_pe_dev_mode_mark(pe, EEH_DEV_REMOVED); 939d2b0f6f7SGavin Shan 9401c2042c8SRafael J. Wysocki pci_lock_rescan_remove(); 941bd251b89SGavin Shan pci_hp_remove_devices(frozen_bus); 9421c2042c8SRafael J. Wysocki pci_unlock_rescan_remove(); 943daeba295SRussell Currey 944daeba295SRussell Currey /* The passed PE should no longer be used */ 945daeba295SRussell Currey return true; 9461c2042c8SRafael J. Wysocki } 947317f06deSGavin Shan } 948daeba295SRussell Currey return false; 94967086e32SWei Yang } 9508a6b1bc7SGavin Shan 951c0b64978SRussell Currey /** 952c0b64978SRussell Currey * eeh_handle_special_event - Handle EEH events without a specific failing PE 953c0b64978SRussell Currey * 954c0b64978SRussell Currey * Called when an EEH event is detected but can't be narrowed down to a 955c0b64978SRussell Currey * specific PE. Iterates through possible failures and handles them as 956c0b64978SRussell Currey * necessary. 957c0b64978SRussell Currey */ 95868701780SSam Bobroff void eeh_handle_special_event(void) 9598a6b1bc7SGavin Shan { 9608a6b1bc7SGavin Shan struct eeh_pe *pe, *phb_pe; 9618a6b1bc7SGavin Shan struct pci_bus *bus; 9627e4e7867SGavin Shan struct pci_controller *hose; 9638a6b1bc7SGavin Shan unsigned long flags; 9647e4e7867SGavin Shan int rc; 9658a6b1bc7SGavin Shan 9667e4e7867SGavin Shan 9677e4e7867SGavin Shan do { 9688a6b1bc7SGavin Shan rc = eeh_ops->next_error(&pe); 9698a6b1bc7SGavin Shan 9708a6b1bc7SGavin Shan switch (rc) { 9717e4e7867SGavin Shan case EEH_NEXT_ERR_DEAD_IOC: 9728a6b1bc7SGavin Shan /* Mark all PHBs in dead state */ 9738a6b1bc7SGavin Shan eeh_serialize_lock(&flags); 9747e4e7867SGavin Shan 9757e4e7867SGavin Shan /* Purge all events */ 9765c7a35e3SGavin Shan eeh_remove_event(NULL, true); 9777e4e7867SGavin Shan 9787e4e7867SGavin Shan list_for_each_entry(hose, &hose_list, list_node) { 9798a6b1bc7SGavin Shan phb_pe = eeh_phb_pe_get(hose); 9808a6b1bc7SGavin Shan if (!phb_pe) continue; 9818a6b1bc7SGavin Shan 9829e049375SGavin Shan eeh_pe_state_mark(phb_pe, EEH_PE_ISOLATED); 9838a6b1bc7SGavin Shan } 9847e4e7867SGavin Shan 9858a6b1bc7SGavin Shan eeh_serialize_unlock(flags); 9868a6b1bc7SGavin Shan 9878a6b1bc7SGavin Shan break; 9887e4e7867SGavin Shan case EEH_NEXT_ERR_FROZEN_PE: 9897e4e7867SGavin Shan case EEH_NEXT_ERR_FENCED_PHB: 9907e4e7867SGavin Shan case EEH_NEXT_ERR_DEAD_PHB: 9918a6b1bc7SGavin Shan /* Mark the PE in fenced state */ 9928a6b1bc7SGavin Shan eeh_serialize_lock(&flags); 9937e4e7867SGavin Shan 9947e4e7867SGavin Shan /* Purge all events of the PHB */ 9955c7a35e3SGavin Shan eeh_remove_event(pe, true); 9967e4e7867SGavin Shan 9977e4e7867SGavin Shan if (rc == EEH_NEXT_ERR_DEAD_PHB) 9989e049375SGavin Shan eeh_pe_state_mark(pe, EEH_PE_ISOLATED); 9998a6b1bc7SGavin Shan else 10008a6b1bc7SGavin Shan eeh_pe_state_mark(pe, 10018a6b1bc7SGavin Shan EEH_PE_ISOLATED | EEH_PE_RECOVERING); 10027e4e7867SGavin Shan 10038a6b1bc7SGavin Shan eeh_serialize_unlock(flags); 10048a6b1bc7SGavin Shan 10058a6b1bc7SGavin Shan break; 10067e4e7867SGavin Shan case EEH_NEXT_ERR_NONE: 10077e4e7867SGavin Shan return; 10088a6b1bc7SGavin Shan default: 10097e4e7867SGavin Shan pr_warn("%s: Invalid value %d from next_error()\n", 10108a6b1bc7SGavin Shan __func__, rc); 10118a6b1bc7SGavin Shan return; 10128a6b1bc7SGavin Shan } 10138a6b1bc7SGavin Shan 10148a6b1bc7SGavin Shan /* 10158a6b1bc7SGavin Shan * For fenced PHB and frozen PE, it's handled as normal 10168a6b1bc7SGavin Shan * event. We have to remove the affected PHBs for dead 10178a6b1bc7SGavin Shan * PHB and IOC 10188a6b1bc7SGavin Shan */ 10197e4e7867SGavin Shan if (rc == EEH_NEXT_ERR_FROZEN_PE || 10207e4e7867SGavin Shan rc == EEH_NEXT_ERR_FENCED_PHB) { 1021daeba295SRussell Currey /* 1022daeba295SRussell Currey * eeh_handle_normal_event() can make the PE stale if it 1023daeba295SRussell Currey * determines that the PE cannot possibly be recovered. 1024daeba295SRussell Currey * Don't modify the PE state if that's the case. 1025daeba295SRussell Currey */ 1026daeba295SRussell Currey if (eeh_handle_normal_event(pe)) 1027daeba295SRussell Currey continue; 1028daeba295SRussell Currey 10299e049375SGavin Shan eeh_pe_state_clear(pe, EEH_PE_RECOVERING); 10307e4e7867SGavin Shan } else { 10311c2042c8SRafael J. Wysocki pci_lock_rescan_remove(); 10327e4e7867SGavin Shan list_for_each_entry(hose, &hose_list, list_node) { 10338a6b1bc7SGavin Shan phb_pe = eeh_phb_pe_get(hose); 10347e4e7867SGavin Shan if (!phb_pe || 10359e049375SGavin Shan !(phb_pe->state & EEH_PE_ISOLATED) || 10369e049375SGavin Shan (phb_pe->state & EEH_PE_RECOVERING)) 10378a6b1bc7SGavin Shan continue; 10388a6b1bc7SGavin Shan 10397e4e7867SGavin Shan /* Notify all devices to be down */ 104005ba75f8SGavin Shan eeh_pe_state_clear(pe, EEH_PE_PRI_BUS); 1041af2e3a00SRussell Currey eeh_pe_dev_traverse(pe, 1042af2e3a00SRussell Currey eeh_report_failure, NULL); 10438a6b1bc7SGavin Shan bus = eeh_pe_bus_get(phb_pe); 104404fec21cSRussell Currey if (!bus) { 104504fec21cSRussell Currey pr_err("%s: Cannot find PCI bus for " 10461f52f176SRussell Currey "PHB#%x-PE#%x\n", 104704fec21cSRussell Currey __func__, 104804fec21cSRussell Currey pe->phb->global_number, 104904fec21cSRussell Currey pe->addr); 105004fec21cSRussell Currey break; 105104fec21cSRussell Currey } 1052bd251b89SGavin Shan pci_hp_remove_devices(bus); 10538a6b1bc7SGavin Shan } 10541c2042c8SRafael J. Wysocki pci_unlock_rescan_remove(); 10558a6b1bc7SGavin Shan } 10567e4e7867SGavin Shan 10577e4e7867SGavin Shan /* 10587e4e7867SGavin Shan * If we have detected dead IOC, we needn't proceed 10597e4e7867SGavin Shan * any more since all PHBs would have been removed 10607e4e7867SGavin Shan */ 10617e4e7867SGavin Shan if (rc == EEH_NEXT_ERR_DEAD_IOC) 10627e4e7867SGavin Shan break; 10637e4e7867SGavin Shan } while (rc != EEH_NEXT_ERR_NONE); 10648a6b1bc7SGavin Shan } 1065