/** * pseries_eeh_reset - Reset the specified PE * @pe: EEH PE * @option: reset option * * Reset the specified PE */ static int pseries_eeh_reset(struct eeh_pe *pe, int option) { int config_addr; int ret; /* Figure out PE address */ config_addr = pe->config_addr; if (pe->addr) config_addr = pe->addr; /* Reset PE through RTAS call */ ret = rtas_call(ibm_set_slot_reset, 4, 1, NULL, config_addr, BUID_HI(pe->phb->buid), BUID_LO(pe->phb->buid), option); /* If fundamental-reset not supported, try hot-reset */ if (option == EEH_RESET_FUNDAMENTAL && ret == -8) { ret = rtas_call(ibm_set_slot_reset, 4, 1, NULL, config_addr, BUID_HI(pe->phb->buid), BUID_LO(pe->phb->buid), EEH_RESET_HOT); } return ret; }
/** * pseries_eeh_configure_bridge - Configure PCI bridges in the indicated PE * @dn: PE associated device node * * The function will be called to reconfigure the bridges included * in the specified PE so that the mulfunctional PE would be recovered * again. */ static int pseries_eeh_configure_bridge(struct device_node *dn) { struct eeh_dev *edev; int config_addr; int ret; /* Figure out the PE address */ edev = of_node_to_eeh_dev(dn); config_addr = edev->config_addr; if (edev->pe_config_addr) config_addr = edev->pe_config_addr; /* Use new configure-pe function, if supported */ if (ibm_configure_pe != RTAS_UNKNOWN_SERVICE) { ret = rtas_call(ibm_configure_pe, 3, 1, NULL, config_addr, BUID_HI(edev->phb->buid), BUID_LO(edev->phb->buid)); } else if (ibm_configure_bridge != RTAS_UNKNOWN_SERVICE) { ret = rtas_call(ibm_configure_bridge, 3, 1, NULL, config_addr, BUID_HI(edev->phb->buid), BUID_LO(edev->phb->buid)); } else { return -EFAULT; } if (ret) pr_warning("%s: Unable to configure bridge %d for %s\n", __func__, ret, dn->full_name); return ret; }
/** * pseries_eeh_configure_bridge - Configure PCI bridges in the indicated PE * @pe: EEH PE * * The function will be called to reconfigure the bridges included * in the specified PE so that the mulfunctional PE would be recovered * again. */ static int pseries_eeh_configure_bridge(struct eeh_pe *pe) { int config_addr; int ret; /* Figure out the PE address */ config_addr = pe->config_addr; if (pe->addr) config_addr = pe->addr; /* Use new configure-pe function, if supported */ if (ibm_configure_pe != RTAS_UNKNOWN_SERVICE) { ret = rtas_call(ibm_configure_pe, 3, 1, NULL, config_addr, BUID_HI(pe->phb->buid), BUID_LO(pe->phb->buid)); } else if (ibm_configure_bridge != RTAS_UNKNOWN_SERVICE) { ret = rtas_call(ibm_configure_bridge, 3, 1, NULL, config_addr, BUID_HI(pe->phb->buid), BUID_LO(pe->phb->buid)); } else { return -EFAULT; } if (ret) pr_warning("%s: Unable to configure bridge PHB#%d-PE#%x (%d)\n", __func__, pe->phb->global_number, pe->addr, ret); return ret; }
/** * pseries_eeh_reset - Reset the specified PE * @dn: PE associated device node * @option: reset option * * Reset the specified PE */ static int pseries_eeh_reset(struct device_node *dn, int option) { struct eeh_dev *edev; int config_addr; int ret; /* Figure out PE address */ edev = of_node_to_eeh_dev(dn); config_addr = edev->config_addr; if (edev->pe_config_addr) config_addr = edev->pe_config_addr; /* Reset PE through RTAS call */ ret = rtas_call(ibm_set_slot_reset, 4, 1, NULL, config_addr, BUID_HI(edev->phb->buid), BUID_LO(edev->phb->buid), option); /* If fundamental-reset not supported, try hot-reset */ if (option == EEH_RESET_FUNDAMENTAL && ret == -8) { ret = rtas_call(ibm_set_slot_reset, 4, 1, NULL, config_addr, BUID_HI(edev->phb->buid), BUID_LO(edev->phb->buid), EEH_RESET_HOT); } return ret; }
/** * pseries_eeh_get_pe_addr - Retrieve PE address * @dn: device node * * Retrieve the assocated PE address. Actually, there're 2 RTAS * function calls dedicated for the purpose. We need implement * it through the new function and then the old one. Besides, * you should make sure the config address is figured out from * FDT node before calling the function. * * It's notable that zero'ed return value means invalid PE config * address. */ static int pseries_eeh_get_pe_addr(struct device_node *dn) { struct eeh_dev *edev; int ret = 0; int rets[3]; edev = of_node_to_eeh_dev(dn); if (ibm_get_config_addr_info2 != RTAS_UNKNOWN_SERVICE) { /* * First of all, we need to make sure there has one PE * associated with the device. Otherwise, PE address is * meaningless. */ ret = rtas_call(ibm_get_config_addr_info2, 4, 2, rets, edev->config_addr, BUID_HI(edev->phb->buid), BUID_LO(edev->phb->buid), 1); if (ret || (rets[0] == 0)) return 0; /* Retrieve the associated PE config address */ ret = rtas_call(ibm_get_config_addr_info2, 4, 2, rets, edev->config_addr, BUID_HI(edev->phb->buid), BUID_LO(edev->phb->buid), 0); if (ret) { pr_warning("%s: Failed to get PE address for %s\n", __func__, dn->full_name); return 0; } return rets[0]; } if (ibm_get_config_addr_info != RTAS_UNKNOWN_SERVICE) { ret = rtas_call(ibm_get_config_addr_info, 4, 2, rets, edev->config_addr, BUID_HI(edev->phb->buid), BUID_LO(edev->phb->buid), 0); if (ret) { pr_warning("%s: Failed to get PE address for %s\n", __func__, dn->full_name); return 0; } return rets[0]; } return ret; }
static void rtas_pci_slot_reset(struct pci_dn *pdn, int state) { int config_addr; int rc; BUG_ON (pdn==NULL); if (!pdn->phb) { printk (KERN_WARNING "EEH: in slot reset, device node %s has no phb\n", pdn->node->full_name); return; } /* Use PE configuration address, if present */ config_addr = pdn->eeh_config_addr; if (pdn->eeh_pe_config_addr) config_addr = pdn->eeh_pe_config_addr; rc = rtas_call(ibm_set_slot_reset,4,1, NULL, config_addr, BUID_HI(pdn->phb->buid), BUID_LO(pdn->phb->buid), state); if (rc) printk (KERN_WARNING "EEH: Unable to reset the failed slot," " (%d) #RST=%d dn=%s\n", rc, state, pdn->node->full_name); }
void eeh_slot_error_detail (struct pci_dn *pdn, int severity) { int config_addr; unsigned long flags; int rc; /* Log the error with the rtas logger */ spin_lock_irqsave(&slot_errbuf_lock, flags); memset(slot_errbuf, 0, eeh_error_buf_size); /* Use PE configuration address, if present */ config_addr = pdn->eeh_config_addr; if (pdn->eeh_pe_config_addr) config_addr = pdn->eeh_pe_config_addr; rc = rtas_call(ibm_slot_error_detail, 8, 1, NULL, config_addr, BUID_HI(pdn->phb->buid), BUID_LO(pdn->phb->buid), NULL, 0, virt_to_phys(slot_errbuf), eeh_error_buf_size, severity); if (rc == 0) log_error(slot_errbuf, ERR_TYPE_RTAS_LOG, 0); spin_unlock_irqrestore(&slot_errbuf_lock, flags); }
int rtas_read_config(struct pci_dn *pdn, int where, int size, u32 *val) { int returnval = -1; unsigned long buid, addr; int ret; if (!pdn) return PCIBIOS_DEVICE_NOT_FOUND; if (!config_access_valid(pdn, where)) return PCIBIOS_BAD_REGISTER_NUMBER; addr = rtas_config_addr(pdn->busno, pdn->devfn, where); buid = pdn->phb->buid; if (buid) { ret = rtas_call(ibm_read_pci_config, 4, 2, &returnval, addr, BUID_HI(buid), BUID_LO(buid), size); } else { ret = rtas_call(read_pci_config, 2, 2, &returnval, addr, size); } *val = returnval; if (ret) return PCIBIOS_DEVICE_NOT_FOUND; if (returnval == EEH_IO_ERROR_VALUE(size) && eeh_dn_check_failure (pdn->node, NULL)) return PCIBIOS_DEVICE_NOT_FOUND; return PCIBIOS_SUCCESSFUL; }
/** * pseries_eeh_set_option - Initialize EEH or MMIO/DMA reenable * @pe: EEH PE * @option: operation to be issued * * The function is used to control the EEH functionality globally. * Currently, following options are support according to PAPR: * Enable EEH, Disable EEH, Enable MMIO and Enable DMA */ static int pseries_eeh_set_option(struct eeh_pe *pe, int option) { int ret = 0; int config_addr; /* * When we're enabling or disabling EEH functioality on * the particular PE, the PE config address is possibly * unavailable. Therefore, we have to figure it out from * the FDT node. */ switch (option) { case EEH_OPT_DISABLE: case EEH_OPT_ENABLE: case EEH_OPT_THAW_MMIO: case EEH_OPT_THAW_DMA: config_addr = pe->config_addr; if (pe->addr) config_addr = pe->addr; break; default: pr_err("%s: Invalid option %d\n", __func__, option); return -EINVAL; } ret = rtas_call(ibm_set_eeh_option, 4, 1, NULL, config_addr, BUID_HI(pe->phb->buid), BUID_LO(pe->phb->buid), option); return ret; }
int rtas_write_config(struct pci_dn *pdn, int where, int size, u32 val) { unsigned long buid, addr; int ret; if (!pdn) return PCIBIOS_DEVICE_NOT_FOUND; if (!config_access_valid(pdn, where)) return PCIBIOS_BAD_REGISTER_NUMBER; addr = ((where & 0xf00) << 20) | (pdn->busno << 16) | (pdn->devfn << 8) | (where & 0xff); buid = pdn->phb->buid; if (buid) { ret = rtas_call(ibm_write_pci_config, 5, 1, NULL, addr, BUID_HI(buid), BUID_LO(buid), size, (ulong) val); } else { ret = rtas_call(write_pci_config, 3, 1, NULL, addr, size, (ulong)val); } if (ret) return PCIBIOS_DEVICE_NOT_FOUND; return PCIBIOS_SUCCESSFUL; }
/** * pseries_eeh_get_log - Retrieve error log * @pe: EEH PE * @severity: temporary or permanent error log * @drv_log: driver log to be combined with retrieved error log * @len: length of driver log * * Retrieve the temporary or permanent error from the PE. * Actually, the error will be retrieved through the dedicated * RTAS call. */ static int pseries_eeh_get_log(struct eeh_pe *pe, int severity, char *drv_log, unsigned long len) { int config_addr; unsigned long flags; int ret; spin_lock_irqsave(&slot_errbuf_lock, flags); memset(slot_errbuf, 0, eeh_error_buf_size); /* Figure out the PE address */ config_addr = pe->config_addr; if (pe->addr) config_addr = pe->addr; ret = rtas_call(ibm_slot_error_detail, 8, 1, NULL, config_addr, BUID_HI(pe->phb->buid), BUID_LO(pe->phb->buid), virt_to_phys(drv_log), len, virt_to_phys(slot_errbuf), eeh_error_buf_size, severity); if (!ret) log_error(slot_errbuf, ERR_TYPE_RTAS_LOG, 0); spin_unlock_irqrestore(&slot_errbuf_lock, flags); return ret; }
/* Check for an eeh failure at the given token address. * The given value has been read and it should be 1's (0xff, 0xffff or * 0xffffffff). * * Probe to determine if an error actually occurred. If not return val. * Otherwise panic. */ unsigned long eeh_check_failure(void *token, unsigned long val) { unsigned long addr; struct pci_dev *dev; struct device_node *dn; unsigned long ret, rets[2]; /* IO BAR access could get us here...or if we manually force EEH * operation on even if the hardware won't support it. */ if (!eeh_implemented || ibm_read_slot_reset_state == RTAS_UNKNOWN_SERVICE) return val; /* Finding the phys addr + pci device is quite expensive. * However, the RTAS call is MUCH slower.... :( */ addr = eeh_token_to_phys((unsigned long)token); dev = pci_find_dev_by_addr(addr); if (!dev) { printk("EEH: no pci dev found for addr=0x%lx\n", addr); return val; } dn = pci_device_to_OF_node(dev); if (!dn) { printk("EEH: no pci dn found for addr=0x%lx\n", addr); return val; } /* Access to IO BARs might get this far and still not want checking. */ if (!(dn->eeh_mode & EEH_MODE_SUPPORTED) || dn->eeh_mode & EEH_MODE_NOCHECK) return val; /* Now test for an EEH failure. This is VERY expensive. * Note that the eeh_config_addr may be a parent device * in the case of a device behind a bridge, or it may be * function zero of a multi-function device. * In any case they must share a common PHB. */ if (dn->eeh_config_addr) { ret = rtas_call(ibm_read_slot_reset_state, 3, 3, rets, dn->eeh_config_addr, BUID_HI(dn->phb->buid), BUID_LO(dn->phb->buid)); if (ret == 0 && rets[1] == 1 && rets[0] >= 2) { /* * XXX We should create a separate sysctl for this. * * Since the panic_on_oops sysctl is used to halt * the system in light of potential corruption, we * can use it here. */ if (panic_on_oops) panic("EEH: MMIO failure (%ld) on device:\n%s\n", rets[0], pci_name(dev)); else printk("EEH: MMIO failure (%ld) on device:\n%s\n", rets[0], pci_name(dev)); } } eeh_false_positives++; return val; /* good case */ }
/** * pseries_eeh_get_pe_addr - Retrieve PE address * @pe: EEH PE * * Retrieve the assocated PE address. Actually, there're 2 RTAS * function calls dedicated for the purpose. We need implement * it through the new function and then the old one. Besides, * you should make sure the config address is figured out from * FDT node before calling the function. * * It's notable that zero'ed return value means invalid PE config * address. */ static int pseries_eeh_get_pe_addr(struct eeh_pe *pe) { int ret = 0; int rets[3]; if (ibm_get_config_addr_info2 != RTAS_UNKNOWN_SERVICE) { /* * First of all, we need to make sure there has one PE * associated with the device. Otherwise, PE address is * meaningless. */ ret = rtas_call(ibm_get_config_addr_info2, 4, 2, rets, pe->config_addr, BUID_HI(pe->phb->buid), BUID_LO(pe->phb->buid), 1); if (ret || (rets[0] == 0)) return 0; /* Retrieve the associated PE config address */ ret = rtas_call(ibm_get_config_addr_info2, 4, 2, rets, pe->config_addr, BUID_HI(pe->phb->buid), BUID_LO(pe->phb->buid), 0); if (ret) { pr_warning("%s: Failed to get address for PHB#%d-PE#%x\n", __func__, pe->phb->global_number, pe->config_addr); return 0; } return rets[0]; } if (ibm_get_config_addr_info != RTAS_UNKNOWN_SERVICE) { ret = rtas_call(ibm_get_config_addr_info, 4, 2, rets, pe->config_addr, BUID_HI(pe->phb->buid), BUID_LO(pe->phb->buid), 0); if (ret) { pr_warning("%s: Failed to get address for PHB#%d-PE#%x\n", __func__, pe->phb->global_number, pe->config_addr); return 0; } return rets[0]; } return ret; }
void rtas_configure_bridge(struct pci_dn *pdn) { int config_addr; int rc; /* Use PE configuration address, if present */ config_addr = pdn->eeh_config_addr; if (pdn->eeh_pe_config_addr) config_addr = pdn->eeh_pe_config_addr; rc = rtas_call(ibm_configure_bridge,3,1, NULL, config_addr, BUID_HI(pdn->phb->buid), BUID_LO(pdn->phb->buid)); if (rc) { printk (KERN_WARNING "EEH: Unable to configure device bridge (%d) for %s\n", rc, pdn->node->full_name); } }
/** * pseries_eeh_set_option - Initialize EEH or MMIO/DMA reenable * @dn: device node * @option: operation to be issued * * The function is used to control the EEH functionality globally. * Currently, following options are support according to PAPR: * Enable EEH, Disable EEH, Enable MMIO and Enable DMA */ static int pseries_eeh_set_option(struct device_node *dn, int option) { int ret = 0; struct eeh_dev *edev; const u32 *reg; int config_addr; edev = of_node_to_eeh_dev(dn); /* * When we're enabling or disabling EEH functioality on * the particular PE, the PE config address is possibly * unavailable. Therefore, we have to figure it out from * the FDT node. */ switch (option) { case EEH_OPT_DISABLE: case EEH_OPT_ENABLE: reg = of_get_property(dn, "reg", NULL); config_addr = reg[0]; break; case EEH_OPT_THAW_MMIO: case EEH_OPT_THAW_DMA: config_addr = edev->config_addr; if (edev->pe_config_addr) config_addr = edev->pe_config_addr; break; default: pr_err("%s: Invalid option %d\n", __func__, option); return -EINVAL; } ret = rtas_call(ibm_set_eeh_option, 4, 1, NULL, config_addr, BUID_HI(edev->phb->buid), BUID_LO(edev->phb->buid), option); return ret; }
/** * read_slot_reset_state - Read the reset state of a device node's slot * @dn: device node to read * @rets: array to return results in */ static int read_slot_reset_state(struct pci_dn *pdn, int rets[]) { int token, outputs; int config_addr; if (ibm_read_slot_reset_state2 != RTAS_UNKNOWN_SERVICE) { token = ibm_read_slot_reset_state2; outputs = 4; } else { token = ibm_read_slot_reset_state; rets[2] = 0; /* fake PE Unavailable info */ outputs = 3; } /* Use PE configuration address, if present */ config_addr = pdn->eeh_config_addr; if (pdn->eeh_pe_config_addr) config_addr = pdn->eeh_pe_config_addr; return rtas_call(token, 3, outputs, rets, config_addr, BUID_HI(pdn->phb->buid), BUID_LO(pdn->phb->buid)); }
int rtas_pci_enable(struct pci_dn *pdn, int function) { int config_addr; int rc; /* Use PE configuration address, if present */ config_addr = pdn->eeh_config_addr; if (pdn->eeh_pe_config_addr) config_addr = pdn->eeh_pe_config_addr; rc = rtas_call(ibm_set_eeh_option, 4, 1, NULL, config_addr, BUID_HI(pdn->phb->buid), BUID_LO(pdn->phb->buid), function); if (rc) printk(KERN_WARNING "EEH: Cannot enable function %d, err=%d dn=%s\n", function, rc, pdn->node->full_name); return rc; }
/** * pseries_eeh_get_state - Retrieve PE state * @pe: EEH PE * @state: return value * * Retrieve the state of the specified PE. On RTAS compliant * pseries platform, there already has one dedicated RTAS function * for the purpose. It's notable that the associated PE config address * might be ready when calling the function. Therefore, endeavour to * use the PE config address if possible. Further more, there're 2 * RTAS calls for the purpose, we need to try the new one and back * to the old one if the new one couldn't work properly. */ static int pseries_eeh_get_state(struct eeh_pe *pe, int *state) { int config_addr; int ret; int rets[4]; int result; /* Figure out PE config address if possible */ config_addr = pe->config_addr; if (pe->addr) config_addr = pe->addr; if (ibm_read_slot_reset_state2 != RTAS_UNKNOWN_SERVICE) { ret = rtas_call(ibm_read_slot_reset_state2, 3, 4, rets, config_addr, BUID_HI(pe->phb->buid), BUID_LO(pe->phb->buid)); } else if (ibm_read_slot_reset_state != RTAS_UNKNOWN_SERVICE) { /* Fake PE unavailable info */ rets[2] = 0; ret = rtas_call(ibm_read_slot_reset_state, 3, 3, rets, config_addr, BUID_HI(pe->phb->buid), BUID_LO(pe->phb->buid)); } else { return EEH_STATE_NOT_SUPPORT; } if (ret) return ret; /* Parse the result out */ result = 0; if (rets[1]) { switch(rets[0]) { case 0: result &= ~EEH_STATE_RESET_ACTIVE; result |= EEH_STATE_MMIO_ACTIVE; result |= EEH_STATE_DMA_ACTIVE; break; case 1: result |= EEH_STATE_RESET_ACTIVE; result |= EEH_STATE_MMIO_ACTIVE; result |= EEH_STATE_DMA_ACTIVE; break; case 2: result &= ~EEH_STATE_RESET_ACTIVE; result &= ~EEH_STATE_MMIO_ACTIVE; result &= ~EEH_STATE_DMA_ACTIVE; break; case 4: result &= ~EEH_STATE_RESET_ACTIVE; result &= ~EEH_STATE_MMIO_ACTIVE; result &= ~EEH_STATE_DMA_ACTIVE; result |= EEH_STATE_MMIO_ENABLED; break; case 5: if (rets[2]) { if (state) *state = rets[2]; result = EEH_STATE_UNAVAILABLE; } else { result = EEH_STATE_NOT_SUPPORT; } default: result = EEH_STATE_NOT_SUPPORT; } } else { result = EEH_STATE_NOT_SUPPORT; } return result; }
/* Check for an eeh failure at the given token address. * The given value has been read and it should be 1's (0xff, 0xffff or * 0xffffffff). * * Probe to determine if an error actually occurred. If not return val. * Otherwise panic. */ unsigned long eeh_check_failure(void *token, unsigned long val) { unsigned long addr; struct pci_dev *dev; struct device_node *dn; unsigned long ret, rets[2]; /* IO BAR access could get us here...or if we manually force EEH * operation on even if the hardware won't support it. */ if (!eeh_implemented || ibm_read_slot_reset_state == RTAS_UNKNOWN_SERVICE) return val; /* Finding the phys addr + pci device is quite expensive. * However, the RTAS call is MUCH slower.... :( */ addr = eeh_token_to_phys((unsigned long)token); dev = pci_find_dev_by_addr(addr); if (!dev) { printk("EEH: no pci dev found for addr=0x%lx\n", addr); return val; } dn = pci_device_to_OF_node(dev); if (!dn) { printk("EEH: no pci dn found for addr=0x%lx\n", addr); return val; } /* Access to IO BARs might get this far and still not want checking. */ if (!(dn->eeh_mode & EEH_MODE_SUPPORTED) || dn->eeh_mode & EEH_MODE_NOCHECK) return val; /* Now test for an EEH failure. This is VERY expensive. * Note that the eeh_config_addr may be a parent device * in the case of a device behind a bridge, or it may be * function zero of a multi-function device. * In any case they must share a common PHB. */ if (dn->eeh_config_addr) { ret = rtas_call(ibm_read_slot_reset_state, 3, 3, rets, dn->eeh_config_addr, BUID_HI(dn->phb->buid), BUID_LO(dn->phb->buid)); if (ret == 0 && rets[1] == 1 && rets[0] >= 2) { unsigned char slot_err_buf[RTAS_ERROR_LOG_MAX]; unsigned long slot_err_ret; memset(slot_err_buf, 0, RTAS_ERROR_LOG_MAX); slot_err_ret = rtas_call(rtas_token("ibm,slot-error-detail"), 8, 1, dn->eeh_config_addr, BUID_HI(dn->phb->buid), BUID_LO(dn->phb->buid), NULL, 0, __pa(slot_err_buf), RTAS_ERROR_LOG_MAX, 2 /* Permanent Error */); if (slot_err_ret == 0) log_error(slot_err_buf, ERR_TYPE_RTAS_LOG, 1 /* Fatal */); panic("EEH: MMIO failure (%ld) on device:\n %s %s\n", rets[0], dev->slot_name, dev->name); } } eeh_false_positives++; return val; /* good case */ }