129310e5eSGavin Shan /* 229310e5eSGavin Shan * The file intends to implement the platform dependent EEH operations on 329310e5eSGavin Shan * powernv platform. Actually, the powernv was created in order to fully 429310e5eSGavin Shan * hypervisor support. 529310e5eSGavin Shan * 629310e5eSGavin Shan * Copyright Benjamin Herrenschmidt & Gavin Shan, IBM Corporation 2013. 729310e5eSGavin Shan * 829310e5eSGavin Shan * This program is free software; you can redistribute it and/or modify 929310e5eSGavin Shan * it under the terms of the GNU General Public License as published by 1029310e5eSGavin Shan * the Free Software Foundation; either version 2 of the License, or 1129310e5eSGavin Shan * (at your option) any later version. 1229310e5eSGavin Shan */ 1329310e5eSGavin Shan 1429310e5eSGavin Shan #include <linux/atomic.h> 1529310e5eSGavin Shan #include <linux/delay.h> 1629310e5eSGavin Shan #include <linux/export.h> 1729310e5eSGavin Shan #include <linux/init.h> 1829310e5eSGavin Shan #include <linux/list.h> 1929310e5eSGavin Shan #include <linux/msi.h> 2029310e5eSGavin Shan #include <linux/of.h> 2129310e5eSGavin Shan #include <linux/pci.h> 2229310e5eSGavin Shan #include <linux/proc_fs.h> 2329310e5eSGavin Shan #include <linux/rbtree.h> 2429310e5eSGavin Shan #include <linux/sched.h> 2529310e5eSGavin Shan #include <linux/seq_file.h> 2629310e5eSGavin Shan #include <linux/spinlock.h> 2729310e5eSGavin Shan 2829310e5eSGavin Shan #include <asm/eeh.h> 2929310e5eSGavin Shan #include <asm/eeh_event.h> 3029310e5eSGavin Shan #include <asm/firmware.h> 3129310e5eSGavin Shan #include <asm/io.h> 3229310e5eSGavin Shan #include <asm/iommu.h> 3329310e5eSGavin Shan #include <asm/machdep.h> 3429310e5eSGavin Shan #include <asm/msi_bitmap.h> 3529310e5eSGavin Shan #include <asm/opal.h> 3629310e5eSGavin Shan #include <asm/ppc-pci.h> 3729310e5eSGavin Shan 3829310e5eSGavin Shan #include "powernv.h" 3929310e5eSGavin Shan #include "pci.h" 4029310e5eSGavin Shan 4129310e5eSGavin Shan /** 4229310e5eSGavin Shan * powernv_eeh_init - EEH platform dependent initialization 4329310e5eSGavin Shan * 4429310e5eSGavin Shan * EEH platform dependent initialization on powernv 4529310e5eSGavin Shan */ 4629310e5eSGavin Shan static int powernv_eeh_init(void) 4729310e5eSGavin Shan { 48dc561fb9SGavin Shan struct pci_controller *hose; 49dc561fb9SGavin Shan struct pnv_phb *phb; 50dc561fb9SGavin Shan 5129310e5eSGavin Shan /* We require OPALv3 */ 5229310e5eSGavin Shan if (!firmware_has_feature(FW_FEATURE_OPALv3)) { 530dae2743SGavin Shan pr_warn("%s: OPALv3 is required !\n", 540dae2743SGavin Shan __func__); 5529310e5eSGavin Shan return -EINVAL; 5629310e5eSGavin Shan } 5729310e5eSGavin Shan 5805b1721dSGavin Shan /* Set probe mode */ 5905b1721dSGavin Shan eeh_add_flag(EEH_PROBE_MODE_DEV); 6029310e5eSGavin Shan 61dc561fb9SGavin Shan /* 62dc561fb9SGavin Shan * P7IOC blocks PCI config access to frozen PE, but PHB3 63dc561fb9SGavin Shan * doesn't do that. So we have to selectively enable I/O 64dc561fb9SGavin Shan * prior to collecting error log. 65dc561fb9SGavin Shan */ 66dc561fb9SGavin Shan list_for_each_entry(hose, &hose_list, list_node) { 67dc561fb9SGavin Shan phb = hose->private_data; 68dc561fb9SGavin Shan 69dc561fb9SGavin Shan if (phb->model == PNV_PHB_MODEL_P7IOC) 70dc561fb9SGavin Shan eeh_add_flag(EEH_ENABLE_IO_FOR_LOG); 71dc561fb9SGavin Shan break; 72dc561fb9SGavin Shan } 73dc561fb9SGavin Shan 7429310e5eSGavin Shan return 0; 7529310e5eSGavin Shan } 7629310e5eSGavin Shan 7729310e5eSGavin Shan /** 7829310e5eSGavin Shan * powernv_eeh_post_init - EEH platform dependent post initialization 7929310e5eSGavin Shan * 8029310e5eSGavin Shan * EEH platform dependent post initialization on powernv. When 8129310e5eSGavin Shan * the function is called, the EEH PEs and devices should have 8229310e5eSGavin Shan * been built. If the I/O cache staff has been built, EEH is 8329310e5eSGavin Shan * ready to supply service. 8429310e5eSGavin Shan */ 8529310e5eSGavin Shan static int powernv_eeh_post_init(void) 8629310e5eSGavin Shan { 8729310e5eSGavin Shan struct pci_controller *hose; 8829310e5eSGavin Shan struct pnv_phb *phb; 8929310e5eSGavin Shan int ret = 0; 9029310e5eSGavin Shan 9129310e5eSGavin Shan list_for_each_entry(hose, &hose_list, list_node) { 9229310e5eSGavin Shan phb = hose->private_data; 9329310e5eSGavin Shan 9429310e5eSGavin Shan if (phb->eeh_ops && phb->eeh_ops->post_init) { 9529310e5eSGavin Shan ret = phb->eeh_ops->post_init(hose); 9629310e5eSGavin Shan if (ret) 9729310e5eSGavin Shan break; 9829310e5eSGavin Shan } 9929310e5eSGavin Shan } 10029310e5eSGavin Shan 10129310e5eSGavin Shan return ret; 10229310e5eSGavin Shan } 10329310e5eSGavin Shan 10429310e5eSGavin Shan /** 10529310e5eSGavin Shan * powernv_eeh_dev_probe - Do probe on PCI device 10629310e5eSGavin Shan * @dev: PCI device 10729310e5eSGavin Shan * @flag: unused 10829310e5eSGavin Shan * 10929310e5eSGavin Shan * When EEH module is installed during system boot, all PCI devices 11029310e5eSGavin Shan * are checked one by one to see if it supports EEH. The function 11129310e5eSGavin Shan * is introduced for the purpose. By default, EEH has been enabled 11229310e5eSGavin Shan * on all PCI devices. That's to say, we only need do necessary 11329310e5eSGavin Shan * initialization on the corresponding eeh device and create PE 11429310e5eSGavin Shan * accordingly. 11529310e5eSGavin Shan * 11629310e5eSGavin Shan * It's notable that's unsafe to retrieve the EEH device through 11729310e5eSGavin Shan * the corresponding PCI device. During the PCI device hotplug, which 11829310e5eSGavin Shan * was possiblly triggered by EEH core, the binding between EEH device 11929310e5eSGavin Shan * and the PCI device isn't built yet. 12029310e5eSGavin Shan */ 12129310e5eSGavin Shan static int powernv_eeh_dev_probe(struct pci_dev *dev, void *flag) 12229310e5eSGavin Shan { 12329310e5eSGavin Shan struct pci_controller *hose = pci_bus_to_host(dev->bus); 12429310e5eSGavin Shan struct pnv_phb *phb = hose->private_data; 12529310e5eSGavin Shan struct device_node *dn = pci_device_to_OF_node(dev); 12629310e5eSGavin Shan struct eeh_dev *edev = of_node_to_eeh_dev(dn); 127dadcd6d6SMike Qiu int ret; 12829310e5eSGavin Shan 12929310e5eSGavin Shan /* 13029310e5eSGavin Shan * When probing the root bridge, which doesn't have any 13129310e5eSGavin Shan * subordinate PCI devices. We don't have OF node for 13229310e5eSGavin Shan * the root bridge. So it's not reasonable to continue 13329310e5eSGavin Shan * the probing. 13429310e5eSGavin Shan */ 135f5c57710SGavin Shan if (!dn || !edev || edev->pe) 13629310e5eSGavin Shan return 0; 13729310e5eSGavin Shan 13829310e5eSGavin Shan /* Skip for PCI-ISA bridge */ 13929310e5eSGavin Shan if ((dev->class >> 8) == PCI_CLASS_BRIDGE_ISA) 14029310e5eSGavin Shan return 0; 14129310e5eSGavin Shan 14229310e5eSGavin Shan /* Initialize eeh device */ 14329310e5eSGavin Shan edev->class_code = dev->class; 144ab55d218SGavin Shan edev->mode &= 0xFFFFFF00; 1454b83bd45SGavin Shan if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) 1464b83bd45SGavin Shan edev->mode |= EEH_DEV_BRIDGE; 1472a18dfc6SGavin Shan edev->pcix_cap = pci_find_capability(dev, PCI_CAP_ID_PCIX); 1484b83bd45SGavin Shan if (pci_is_pcie(dev)) { 1494b83bd45SGavin Shan edev->pcie_cap = pci_pcie_cap(dev); 1504b83bd45SGavin Shan 1514b83bd45SGavin Shan if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT) 1524b83bd45SGavin Shan edev->mode |= EEH_DEV_ROOT_PORT; 1534b83bd45SGavin Shan else if (pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM) 1544b83bd45SGavin Shan edev->mode |= EEH_DEV_DS_PORT; 1552a18dfc6SGavin Shan 1562a18dfc6SGavin Shan edev->aer_cap = pci_find_ext_capability(dev, 1572a18dfc6SGavin Shan PCI_EXT_CAP_ID_ERR); 1584b83bd45SGavin Shan } 1594b83bd45SGavin Shan 16029310e5eSGavin Shan edev->config_addr = ((dev->bus->number << 8) | dev->devfn); 16129310e5eSGavin Shan edev->pe_config_addr = phb->bdfn_to_pe(phb, dev->bus, dev->devfn & 0xff); 16229310e5eSGavin Shan 16329310e5eSGavin Shan /* Create PE */ 164dadcd6d6SMike Qiu ret = eeh_add_to_parent_pe(edev); 165dadcd6d6SMike Qiu if (ret) { 166dadcd6d6SMike Qiu pr_warn("%s: Can't add PCI dev %s to parent PE (%d)\n", 167dadcd6d6SMike Qiu __func__, pci_name(dev), ret); 168dadcd6d6SMike Qiu return ret; 169dadcd6d6SMike Qiu } 170dadcd6d6SMike Qiu 171dadcd6d6SMike Qiu /* 172b6541db1SGavin Shan * If the PE contains any one of following adapters, the 173b6541db1SGavin Shan * PCI config space can't be accessed when dumping EEH log. 174b6541db1SGavin Shan * Otherwise, we will run into fenced PHB caused by shortage 175b6541db1SGavin Shan * of outbound credits in the adapter. The PCI config access 176b6541db1SGavin Shan * should be blocked until PE reset. MMIO access is dropped 177b6541db1SGavin Shan * by hardware certainly. In order to drop PCI config requests, 178b6541db1SGavin Shan * one more flag (EEH_PE_CFG_RESTRICTED) is introduced, which 179b6541db1SGavin Shan * will be checked in the backend for PE state retrival. If 180b6541db1SGavin Shan * the PE becomes frozen for the first time and the flag has 181b6541db1SGavin Shan * been set for the PE, we will set EEH_PE_CFG_BLOCKED for 182b6541db1SGavin Shan * that PE to block its config space. 183b6541db1SGavin Shan * 184b6541db1SGavin Shan * Broadcom Austin 4-ports NICs (14e4:1657) 185b6541db1SGavin Shan */ 186b6541db1SGavin Shan if (dev->vendor == PCI_VENDOR_ID_BROADCOM && 187b6541db1SGavin Shan dev->device == 0x1657) 188b6541db1SGavin Shan edev->pe->state |= EEH_PE_CFG_RESTRICTED; 189b6541db1SGavin Shan 190b6541db1SGavin Shan /* 191dadcd6d6SMike Qiu * Cache the PE primary bus, which can't be fetched when 192dadcd6d6SMike Qiu * full hotplug is in progress. In that case, all child 193dadcd6d6SMike Qiu * PCI devices of the PE are expected to be removed prior 194dadcd6d6SMike Qiu * to PE reset. 195dadcd6d6SMike Qiu */ 196dadcd6d6SMike Qiu if (!edev->pe->bus) 197dadcd6d6SMike Qiu edev->pe->bus = dev->bus; 19829310e5eSGavin Shan 19929310e5eSGavin Shan /* 20029310e5eSGavin Shan * Enable EEH explicitly so that we will do EEH check 20129310e5eSGavin Shan * while accessing I/O stuff 20229310e5eSGavin Shan */ 20305b1721dSGavin Shan eeh_add_flag(EEH_ENABLED); 20429310e5eSGavin Shan 20529310e5eSGavin Shan /* Save memory bars */ 20629310e5eSGavin Shan eeh_save_bars(edev); 20729310e5eSGavin Shan 20829310e5eSGavin Shan return 0; 20929310e5eSGavin Shan } 21029310e5eSGavin Shan 21129310e5eSGavin Shan /** 21229310e5eSGavin Shan * powernv_eeh_set_option - Initialize EEH or MMIO/DMA reenable 21329310e5eSGavin Shan * @pe: EEH PE 21429310e5eSGavin Shan * @option: operation to be issued 21529310e5eSGavin Shan * 21629310e5eSGavin Shan * The function is used to control the EEH functionality globally. 21729310e5eSGavin Shan * Currently, following options are support according to PAPR: 21829310e5eSGavin Shan * Enable EEH, Disable EEH, Enable MMIO and Enable DMA 21929310e5eSGavin Shan */ 22029310e5eSGavin Shan static int powernv_eeh_set_option(struct eeh_pe *pe, int option) 22129310e5eSGavin Shan { 22229310e5eSGavin Shan struct pci_controller *hose = pe->phb; 22329310e5eSGavin Shan struct pnv_phb *phb = hose->private_data; 22429310e5eSGavin Shan int ret = -EEXIST; 22529310e5eSGavin Shan 22629310e5eSGavin Shan /* 22729310e5eSGavin Shan * What we need do is pass it down for hardware 22829310e5eSGavin Shan * implementation to handle it. 22929310e5eSGavin Shan */ 23029310e5eSGavin Shan if (phb->eeh_ops && phb->eeh_ops->set_option) 23129310e5eSGavin Shan ret = phb->eeh_ops->set_option(pe, option); 23229310e5eSGavin Shan 23329310e5eSGavin Shan return ret; 23429310e5eSGavin Shan } 23529310e5eSGavin Shan 23629310e5eSGavin Shan /** 23729310e5eSGavin Shan * powernv_eeh_get_pe_addr - Retrieve PE address 23829310e5eSGavin Shan * @pe: EEH PE 23929310e5eSGavin Shan * 24029310e5eSGavin Shan * Retrieve the PE address according to the given tranditional 24129310e5eSGavin Shan * PCI BDF (Bus/Device/Function) address. 24229310e5eSGavin Shan */ 24329310e5eSGavin Shan static int powernv_eeh_get_pe_addr(struct eeh_pe *pe) 24429310e5eSGavin Shan { 24529310e5eSGavin Shan return pe->addr; 24629310e5eSGavin Shan } 24729310e5eSGavin Shan 24829310e5eSGavin Shan /** 24929310e5eSGavin Shan * powernv_eeh_get_state - Retrieve PE state 25029310e5eSGavin Shan * @pe: EEH PE 25129310e5eSGavin Shan * @delay: delay while PE state is temporarily unavailable 25229310e5eSGavin Shan * 25329310e5eSGavin Shan * Retrieve the state of the specified PE. For IODA-compitable 25429310e5eSGavin Shan * platform, it should be retrieved from IODA table. Therefore, 25529310e5eSGavin Shan * we prefer passing down to hardware implementation to handle 25629310e5eSGavin Shan * it. 25729310e5eSGavin Shan */ 25829310e5eSGavin Shan static int powernv_eeh_get_state(struct eeh_pe *pe, int *delay) 25929310e5eSGavin Shan { 26029310e5eSGavin Shan struct pci_controller *hose = pe->phb; 26129310e5eSGavin Shan struct pnv_phb *phb = hose->private_data; 26229310e5eSGavin Shan int ret = EEH_STATE_NOT_SUPPORT; 26329310e5eSGavin Shan 26429310e5eSGavin Shan if (phb->eeh_ops && phb->eeh_ops->get_state) { 26529310e5eSGavin Shan ret = phb->eeh_ops->get_state(pe); 26629310e5eSGavin Shan 26729310e5eSGavin Shan /* 26829310e5eSGavin Shan * If the PE state is temporarily unavailable, 26929310e5eSGavin Shan * to inform the EEH core delay for default 27029310e5eSGavin Shan * period (1 second) 27129310e5eSGavin Shan */ 27229310e5eSGavin Shan if (delay) { 27329310e5eSGavin Shan *delay = 0; 27429310e5eSGavin Shan if (ret & EEH_STATE_UNAVAILABLE) 27529310e5eSGavin Shan *delay = 1000; 27629310e5eSGavin Shan } 27729310e5eSGavin Shan } 27829310e5eSGavin Shan 27929310e5eSGavin Shan return ret; 28029310e5eSGavin Shan } 28129310e5eSGavin Shan 28229310e5eSGavin Shan /** 28329310e5eSGavin Shan * powernv_eeh_reset - Reset the specified PE 28429310e5eSGavin Shan * @pe: EEH PE 28529310e5eSGavin Shan * @option: reset option 28629310e5eSGavin Shan * 28729310e5eSGavin Shan * Reset the specified PE 28829310e5eSGavin Shan */ 28929310e5eSGavin Shan static int powernv_eeh_reset(struct eeh_pe *pe, int option) 29029310e5eSGavin Shan { 29129310e5eSGavin Shan struct pci_controller *hose = pe->phb; 29229310e5eSGavin Shan struct pnv_phb *phb = hose->private_data; 29329310e5eSGavin Shan int ret = -EEXIST; 29429310e5eSGavin Shan 29529310e5eSGavin Shan if (phb->eeh_ops && phb->eeh_ops->reset) 29629310e5eSGavin Shan ret = phb->eeh_ops->reset(pe, option); 29729310e5eSGavin Shan 29829310e5eSGavin Shan return ret; 29929310e5eSGavin Shan } 30029310e5eSGavin Shan 30129310e5eSGavin Shan /** 30229310e5eSGavin Shan * powernv_eeh_wait_state - Wait for PE state 30329310e5eSGavin Shan * @pe: EEH PE 30429310e5eSGavin Shan * @max_wait: maximal period in microsecond 30529310e5eSGavin Shan * 30629310e5eSGavin Shan * Wait for the state of associated PE. It might take some time 30729310e5eSGavin Shan * to retrieve the PE's state. 30829310e5eSGavin Shan */ 30929310e5eSGavin Shan static int powernv_eeh_wait_state(struct eeh_pe *pe, int max_wait) 31029310e5eSGavin Shan { 31129310e5eSGavin Shan int ret; 31229310e5eSGavin Shan int mwait; 31329310e5eSGavin Shan 31429310e5eSGavin Shan while (1) { 31529310e5eSGavin Shan ret = powernv_eeh_get_state(pe, &mwait); 31629310e5eSGavin Shan 31729310e5eSGavin Shan /* 31829310e5eSGavin Shan * If the PE's state is temporarily unavailable, 31929310e5eSGavin Shan * we have to wait for the specified time. Otherwise, 32029310e5eSGavin Shan * the PE's state will be returned immediately. 32129310e5eSGavin Shan */ 32229310e5eSGavin Shan if (ret != EEH_STATE_UNAVAILABLE) 32329310e5eSGavin Shan return ret; 32429310e5eSGavin Shan 32529310e5eSGavin Shan max_wait -= mwait; 32629310e5eSGavin Shan if (max_wait <= 0) { 3270dae2743SGavin Shan pr_warn("%s: Timeout getting PE#%x's state (%d)\n", 32829310e5eSGavin Shan __func__, pe->addr, max_wait); 32929310e5eSGavin Shan return EEH_STATE_NOT_SUPPORT; 33029310e5eSGavin Shan } 33129310e5eSGavin Shan 33229310e5eSGavin Shan msleep(mwait); 33329310e5eSGavin Shan } 33429310e5eSGavin Shan 33529310e5eSGavin Shan return EEH_STATE_NOT_SUPPORT; 33629310e5eSGavin Shan } 33729310e5eSGavin Shan 33829310e5eSGavin Shan /** 33929310e5eSGavin Shan * powernv_eeh_get_log - Retrieve error log 34029310e5eSGavin Shan * @pe: EEH PE 34129310e5eSGavin Shan * @severity: temporary or permanent error log 34229310e5eSGavin Shan * @drv_log: driver log to be combined with retrieved error log 34329310e5eSGavin Shan * @len: length of driver log 34429310e5eSGavin Shan * 34529310e5eSGavin Shan * Retrieve the temporary or permanent error from the PE. 34629310e5eSGavin Shan */ 34729310e5eSGavin Shan static int powernv_eeh_get_log(struct eeh_pe *pe, int severity, 34829310e5eSGavin Shan char *drv_log, unsigned long len) 34929310e5eSGavin Shan { 35029310e5eSGavin Shan struct pci_controller *hose = pe->phb; 35129310e5eSGavin Shan struct pnv_phb *phb = hose->private_data; 35229310e5eSGavin Shan int ret = -EEXIST; 35329310e5eSGavin Shan 35429310e5eSGavin Shan if (phb->eeh_ops && phb->eeh_ops->get_log) 35529310e5eSGavin Shan ret = phb->eeh_ops->get_log(pe, severity, drv_log, len); 35629310e5eSGavin Shan 35729310e5eSGavin Shan return ret; 35829310e5eSGavin Shan } 35929310e5eSGavin Shan 36029310e5eSGavin Shan /** 36129310e5eSGavin Shan * powernv_eeh_configure_bridge - Configure PCI bridges in the indicated PE 36229310e5eSGavin Shan * @pe: EEH PE 36329310e5eSGavin Shan * 36429310e5eSGavin Shan * The function will be called to reconfigure the bridges included 36529310e5eSGavin Shan * in the specified PE so that the mulfunctional PE would be recovered 36629310e5eSGavin Shan * again. 36729310e5eSGavin Shan */ 36829310e5eSGavin Shan static int powernv_eeh_configure_bridge(struct eeh_pe *pe) 36929310e5eSGavin Shan { 37029310e5eSGavin Shan struct pci_controller *hose = pe->phb; 37129310e5eSGavin Shan struct pnv_phb *phb = hose->private_data; 37229310e5eSGavin Shan int ret = 0; 37329310e5eSGavin Shan 37429310e5eSGavin Shan if (phb->eeh_ops && phb->eeh_ops->configure_bridge) 37529310e5eSGavin Shan ret = phb->eeh_ops->configure_bridge(pe); 37629310e5eSGavin Shan 37729310e5eSGavin Shan return ret; 37829310e5eSGavin Shan } 37929310e5eSGavin Shan 38029310e5eSGavin Shan /** 381131c123aSGavin Shan * powernv_pe_err_inject - Inject specified error to the indicated PE 382131c123aSGavin Shan * @pe: the indicated PE 383131c123aSGavin Shan * @type: error type 384131c123aSGavin Shan * @func: specific error type 385131c123aSGavin Shan * @addr: address 386131c123aSGavin Shan * @mask: address mask 387131c123aSGavin Shan * 388131c123aSGavin Shan * The routine is called to inject specified error, which is 389131c123aSGavin Shan * determined by @type and @func, to the indicated PE for 390131c123aSGavin Shan * testing purpose. 391131c123aSGavin Shan */ 392131c123aSGavin Shan static int powernv_eeh_err_inject(struct eeh_pe *pe, int type, int func, 393131c123aSGavin Shan unsigned long addr, unsigned long mask) 394131c123aSGavin Shan { 395131c123aSGavin Shan struct pci_controller *hose = pe->phb; 396131c123aSGavin Shan struct pnv_phb *phb = hose->private_data; 397131c123aSGavin Shan int ret = -EEXIST; 398131c123aSGavin Shan 399131c123aSGavin Shan if (phb->eeh_ops && phb->eeh_ops->err_inject) 400131c123aSGavin Shan ret = phb->eeh_ops->err_inject(pe, type, func, addr, mask); 401131c123aSGavin Shan 402131c123aSGavin Shan return ret; 403131c123aSGavin Shan } 404131c123aSGavin Shan 405d2cfbcd7SGavin Shan static inline bool powernv_eeh_cfg_blocked(struct device_node *dn) 406d2cfbcd7SGavin Shan { 407d2cfbcd7SGavin Shan struct eeh_dev *edev = of_node_to_eeh_dev(dn); 408d2cfbcd7SGavin Shan 409d2cfbcd7SGavin Shan if (!edev || !edev->pe) 410d2cfbcd7SGavin Shan return false; 411d2cfbcd7SGavin Shan 412d2cfbcd7SGavin Shan if (edev->pe->state & EEH_PE_CFG_BLOCKED) 413d2cfbcd7SGavin Shan return true; 414d2cfbcd7SGavin Shan 415d2cfbcd7SGavin Shan return false; 416d2cfbcd7SGavin Shan } 417d2cfbcd7SGavin Shan 418d2cfbcd7SGavin Shan static int powernv_eeh_read_config(struct device_node *dn, 419d2cfbcd7SGavin Shan int where, int size, u32 *val) 420d2cfbcd7SGavin Shan { 421d2cfbcd7SGavin Shan if (powernv_eeh_cfg_blocked(dn)) { 422d2cfbcd7SGavin Shan *val = 0xFFFFFFFF; 423d2cfbcd7SGavin Shan return PCIBIOS_SET_FAILED; 424d2cfbcd7SGavin Shan } 425d2cfbcd7SGavin Shan 426d2cfbcd7SGavin Shan return pnv_pci_cfg_read(dn, where, size, val); 427d2cfbcd7SGavin Shan } 428d2cfbcd7SGavin Shan 429d2cfbcd7SGavin Shan static int powernv_eeh_write_config(struct device_node *dn, 430d2cfbcd7SGavin Shan int where, int size, u32 val) 431d2cfbcd7SGavin Shan { 432d2cfbcd7SGavin Shan if (powernv_eeh_cfg_blocked(dn)) 433d2cfbcd7SGavin Shan return PCIBIOS_SET_FAILED; 434d2cfbcd7SGavin Shan 435d2cfbcd7SGavin Shan return pnv_pci_cfg_write(dn, where, size, val); 436d2cfbcd7SGavin Shan } 437d2cfbcd7SGavin Shan 438131c123aSGavin Shan /** 43929310e5eSGavin Shan * powernv_eeh_next_error - Retrieve next EEH error to handle 44029310e5eSGavin Shan * @pe: Affected PE 44129310e5eSGavin Shan * 44229310e5eSGavin Shan * Using OPAL API, to retrieve next EEH error for EEH core to handle 44329310e5eSGavin Shan */ 44429310e5eSGavin Shan static int powernv_eeh_next_error(struct eeh_pe **pe) 44529310e5eSGavin Shan { 44629310e5eSGavin Shan struct pci_controller *hose; 44729310e5eSGavin Shan struct pnv_phb *phb = NULL; 44829310e5eSGavin Shan 44929310e5eSGavin Shan list_for_each_entry(hose, &hose_list, list_node) { 45029310e5eSGavin Shan phb = hose->private_data; 45129310e5eSGavin Shan break; 45229310e5eSGavin Shan } 45329310e5eSGavin Shan 45429310e5eSGavin Shan if (phb && phb->eeh_ops->next_error) 45529310e5eSGavin Shan return phb->eeh_ops->next_error(pe); 45629310e5eSGavin Shan 45729310e5eSGavin Shan return -EEXIST; 45829310e5eSGavin Shan } 45929310e5eSGavin Shan 4609be3beccSGavin Shan static int powernv_eeh_restore_config(struct device_node *dn) 4619be3beccSGavin Shan { 4629be3beccSGavin Shan struct eeh_dev *edev = of_node_to_eeh_dev(dn); 4639be3beccSGavin Shan struct pnv_phb *phb; 4649be3beccSGavin Shan s64 ret; 4659be3beccSGavin Shan 4669be3beccSGavin Shan if (!edev) 4679be3beccSGavin Shan return -EEXIST; 4689be3beccSGavin Shan 4699be3beccSGavin Shan phb = edev->phb->private_data; 4709be3beccSGavin Shan ret = opal_pci_reinit(phb->opal_id, 4719be3beccSGavin Shan OPAL_REINIT_PCI_DEV, edev->config_addr); 4729be3beccSGavin Shan if (ret) { 4739be3beccSGavin Shan pr_warn("%s: Can't reinit PCI dev 0x%x (%lld)\n", 4749be3beccSGavin Shan __func__, edev->config_addr, ret); 4759be3beccSGavin Shan return -EIO; 4769be3beccSGavin Shan } 4779be3beccSGavin Shan 4789be3beccSGavin Shan return 0; 4799be3beccSGavin Shan } 4809be3beccSGavin Shan 48129310e5eSGavin Shan static struct eeh_ops powernv_eeh_ops = { 48229310e5eSGavin Shan .name = "powernv", 48329310e5eSGavin Shan .init = powernv_eeh_init, 48429310e5eSGavin Shan .post_init = powernv_eeh_post_init, 48529310e5eSGavin Shan .of_probe = NULL, 48629310e5eSGavin Shan .dev_probe = powernv_eeh_dev_probe, 48729310e5eSGavin Shan .set_option = powernv_eeh_set_option, 48829310e5eSGavin Shan .get_pe_addr = powernv_eeh_get_pe_addr, 48929310e5eSGavin Shan .get_state = powernv_eeh_get_state, 49029310e5eSGavin Shan .reset = powernv_eeh_reset, 49129310e5eSGavin Shan .wait_state = powernv_eeh_wait_state, 49229310e5eSGavin Shan .get_log = powernv_eeh_get_log, 49329310e5eSGavin Shan .configure_bridge = powernv_eeh_configure_bridge, 494131c123aSGavin Shan .err_inject = powernv_eeh_err_inject, 495d2cfbcd7SGavin Shan .read_config = powernv_eeh_read_config, 496d2cfbcd7SGavin Shan .write_config = powernv_eeh_write_config, 4971d350544SGavin Shan .next_error = powernv_eeh_next_error, 4989be3beccSGavin Shan .restore_config = powernv_eeh_restore_config 49929310e5eSGavin Shan }; 50029310e5eSGavin Shan 50129310e5eSGavin Shan /** 50229310e5eSGavin Shan * eeh_powernv_init - Register platform dependent EEH operations 50329310e5eSGavin Shan * 50429310e5eSGavin Shan * EEH initialization on powernv platform. This function should be 50529310e5eSGavin Shan * called before any EEH related functions. 50629310e5eSGavin Shan */ 50729310e5eSGavin Shan static int __init eeh_powernv_init(void) 50829310e5eSGavin Shan { 50929310e5eSGavin Shan int ret = -EINVAL; 51029310e5eSGavin Shan 511bb593c00SGavin Shan eeh_set_pe_aux_size(PNV_PCI_DIAG_BUF_SIZE); 51229310e5eSGavin Shan ret = eeh_ops_register(&powernv_eeh_ops); 51329310e5eSGavin Shan if (!ret) 51429310e5eSGavin Shan pr_info("EEH: PowerNV platform initialized\n"); 51529310e5eSGavin Shan else 51629310e5eSGavin Shan pr_info("EEH: Failed to initialize PowerNV platform (%d)\n", ret); 51729310e5eSGavin Shan 51829310e5eSGavin Shan return ret; 51929310e5eSGavin Shan } 520b14726c5SMichael Ellerman machine_early_initcall(powernv, eeh_powernv_init); 521