edev->pe_config_addr = (pdn->busno << 16) | (pdn->devfn << 8);
eeh_pe_tree_remove(edev); /* Remove as it is adding to bus pe */
eeh_pe_tree_insert(edev, physfn_pe); /* Add as VF PE type */
} #endif
eeh_probe_device(pdev);
}
if (ibm_get_config_addr_info2 != RTAS_UNKNOWN_SERVICE) { /* *Firstofall,usefunction1todetermineifthisdeviceis *partofaPEornot.ret[0]beingzeroindicatesit'snot.
*/
ret = rtas_call(ibm_get_config_addr_info2, 4, 2, rets,
config_addr, BUID_HI(phb->buid),
BUID_LO(phb->buid), 1); if (ret || (rets[0] == 0)) return -ENOENT;
/* Retrieve the associated PE config address with function 0 */
ret = rtas_call(ibm_get_config_addr_info2, 4, 2, rets,
config_addr, BUID_HI(phb->buid),
BUID_LO(phb->buid), 0); if (ret) {
pr_warn("%s: Failed to get address for PHB#%x-PE#%x\n",
__func__, phb->global_number, config_addr); return -ENXIO;
}
return rets[0];
}
if (ibm_get_config_addr_info != RTAS_UNKNOWN_SERVICE) {
ret = rtas_call(ibm_get_config_addr_info, 4, 2, rets,
config_addr, BUID_HI(phb->buid),
BUID_LO(phb->buid), 0); if (ret) {
pr_warn("%s: Failed to get address for PHB#%x-PE#%x\n",
__func__, phb->global_number, config_addr); return -ENXIO;
}
/** *pseries_eeh_phb_reset-ResetthespecifiedPHB *@phb:PCIcontroller *@config_addr:theassociatedconfigaddress *@option:resetoption * *ResetthespecifiedPHB/PE
*/ staticint pseries_eeh_phb_reset(struct pci_controller *phb, int config_addr, int option)
{ int ret;
/* Reset PE through RTAS call */
ret = rtas_call(ibm_set_slot_reset, 4, 1, NULL,
config_addr, BUID_HI(phb->buid),
BUID_LO(phb->buid), option);
/* If fundamental-reset not supported, try hot-reset */ if (option == EEH_RESET_FUNDAMENTAL && ret == -8) {
option = EEH_RESET_HOT;
ret = rtas_call(ibm_set_slot_reset, 4, 1, NULL,
config_addr, BUID_HI(phb->buid),
BUID_LO(phb->buid), option);
}
/* We need reset hold or settlement delay */ if (option == EEH_RESET_FUNDAMENTAL || option == EEH_RESET_HOT)
msleep(EEH_PE_RST_HOLD_TIME); else
msleep(EEH_PE_RST_SETTLE_TIME);
return ret;
}
/** *pseries_eeh_phb_configure_bridge-ConfigurePCIbridgesintheindicatedPE *@phb:PCIcontroller *@config_addr:theassociatedconfigaddress * *Thefunctionwillbecalledtoreconfigurethebridgesincluded *inthespecifiedPEsothatthemulfunctionalPEwouldberecovered *again.
*/ staticint pseries_eeh_phb_configure_bridge(struct pci_controller *phb, int config_addr)
{ int ret; /* Waiting 0.2s maximum before skipping configuration */ int max_wait = 200;
while (max_wait > 0) {
ret = rtas_call(ibm_configure_pe, 3, 1, NULL,
config_addr, BUID_HI(phb->buid),
BUID_LO(phb->buid));
if (!ret) return ret; if (ret < 0) break;
/* *IfRTASreturnsadelayvaluethat'sabove100ms,cutit *downto100msincasefirmwaremadeamistake.Formore *onhowthesedelayvaluesworkseertas_busy_delay_time
*/ if (ret > RTAS_EXTENDED_DELAY_MIN+2 &&
ret <= RTAS_EXTENDED_DELAY_MAX)
ret = RTAS_EXTENDED_DELAY_MIN+2;
max_wait -= rtas_busy_delay_time(ret);
if (max_wait < 0) break;
rtas_busy_delay(ret);
}
pr_warn("%s: Unable to configure bridge PHB#%x-PE#%x (%d)\n",
__func__, phb->global_number, config_addr, ret); /* PAPR defines -3 as "Parameter Error" for this function: */ if (ret == -3) return -EINVAL; else return -EIO;
}
rtas_pci_dn_read_config(pdn, PCI_STATUS, 2, &status); if (!(status & PCI_STATUS_CAP_LIST)) return0;
return PCI_CAPABILITY_LIST;
}
staticint pseries_eeh_find_cap(struct pci_dn *pdn, int cap)
{ int pos = pseries_eeh_cap_start(pdn); int cnt = 48; /* Maximal number of capabilities */
u32 id;
if (!pos) return0;
while (cnt--) {
rtas_pci_dn_read_config(pdn, pos, 1, &pos); if (pos < 0x40) break;
pos &= ~3;
rtas_pci_dn_read_config(pdn, pos + PCI_CAP_LIST_ID, 1, &id); if (id == 0xff) break; if (id == cap) return pos;
pos += PCI_CAP_LIST_NEXT;
}
return0;
}
staticint pseries_eeh_find_ecap(struct pci_dn *pdn, int cap)
{ struct eeh_dev *edev = pdn_to_eeh_dev(pdn);
u32 header; int pos = 256; int ttl = (4096 - 256) / 8;
if (!edev || !edev->pcie_cap) return0; if (rtas_pci_dn_read_config(pdn, pos, 4, &header) != PCIBIOS_SUCCESSFUL) return0; elseif (!header) return0;
while (ttl-- > 0) { if (PCI_EXT_CAP_ID(header) == cap && pos) return pos;
pos = PCI_EXT_CAP_NEXT(header); if (pos < 256) break;
if (rtas_pci_dn_read_config(pdn, pos, 4, &header) != PCIBIOS_SUCCESSFUL) break;
}
/* first up, find the pe_config_addr for the PE containing the device */
ret = pseries_eeh_get_pe_config_addr(pdn); if (ret < 0) {
eeh_edev_dbg(edev, "Unable to find pe_config_addr\n"); goto err;
}
/* Try enable EEH on the fake PE */
memset(&pe, 0, sizeof(struct eeh_pe));
pe.phb = pdn->phb;
pe.addr = ret;
eeh_edev_dbg(edev, "Enabling EEH on device\n");
ret = eeh_ops->set_option(&pe, EEH_OPT_ENABLE); if (ret) {
eeh_edev_dbg(edev, "EEH failed to enable on device (code %d)\n", ret); goto err;
}
/** *pseries_eeh_set_option-InitializeEEHorMMIO/DMAreenable *@pe:EEHPE *@option:operationtobeissued * *ThefunctionisusedtocontroltheEEHfunctionalityglobally. *Currently,followingoptionsaresupportaccordingtoPAPR: *EnableEEH,DisableEEH,EnableMMIOandEnableDMA
*/ staticint pseries_eeh_set_option(struct eeh_pe *pe, int option)
{ int ret = 0;
/* *Whenwe'reenablingordisablingEEHfunctionalityon *theparticularPE,thePEconfigaddressispossibly *unavailable.Therefore,wehavetofigureitoutfrom *theFDTnode.
*/ switch (option) { case EEH_OPT_DISABLE: case EEH_OPT_ENABLE: case EEH_OPT_THAW_MMIO: case EEH_OPT_THAW_DMA: break; case EEH_OPT_FREEZE_PE: /* Not support */ return0; default:
pr_err("%s: Invalid option %d\n", __func__, option); return -EINVAL;
}
ret = rtas_call(ibm_set_eeh_option, 4, 1, NULL,
pe->addr, BUID_HI(pe->phb->buid),
BUID_LO(pe->phb->buid), option);
return ret;
}
/** *pseries_eeh_get_state-RetrievePEstate *@pe:EEHPE *@delay:suggestedtimetowaitifstateisunavailable * *RetrievethestateofthespecifiedPE.OnRTAScompliant *pseriesplatform,therealreadyhasonededicatedRTASfunction *forthepurpose.It'snotablethattheassociatedPEconfigaddress *mightbereadywhencallingthefunction.Therefore,endeavourto *usethePEconfigaddressifpossible.Furthermore,there're2 *RTAScallsforthepurpose,weneedtotrythenewoneandback *totheoldoneifthenewonecouldn'tworkproperly.
*/ staticint pseries_eeh_get_state(struct eeh_pe *pe, int *delay)
{ int ret; int rets[4]; int result;
if (ibm_read_slot_reset_state2 != RTAS_UNKNOWN_SERVICE) {
ret = rtas_call(ibm_read_slot_reset_state2, 3, 4, rets,
pe->addr, BUID_HI(pe->phb->buid),
BUID_LO(pe->phb->buid));
} elseif (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,
pe->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 */ if (!rets[1]) return EEH_STATE_NOT_SUPPORT;
switch(rets[0]) { case0:
result = EEH_STATE_MMIO_ACTIVE |
EEH_STATE_DMA_ACTIVE |
EEH_STATE_MMIO_ENABLED |
EEH_STATE_DMA_ENABLED; break; case1:
result = EEH_STATE_RESET_ACTIVE |
EEH_STATE_MMIO_ACTIVE |
EEH_STATE_DMA_ACTIVE; break; case2:
result = 0; break; case4:
result = EEH_STATE_MMIO_ENABLED; break; case5: if (rets[2]) { if (delay)
*delay = rets[2];
result = EEH_STATE_UNAVAILABLE;
} else {
result = EEH_STATE_NOT_SUPPORT;
} break; default:
result = EEH_STATE_NOT_SUPPORT;
}
/* Check on PCI error type */ if (type != EEH_ERR_TYPE_32 && type != EEH_ERR_TYPE_64) return -EINVAL;
switch (func) { case EEH_ERR_FUNC_LD_MEM_ADDR: case EEH_ERR_FUNC_LD_MEM_DATA: case EEH_ERR_FUNC_ST_MEM_ADDR: case EEH_ERR_FUNC_ST_MEM_DATA: /* injects a MMIO error for all pdev's belonging to PE */
pci_lock_rescan_remove();
list_for_each_entry(pdev, &pe->edevs, entry)
eeh_pe_inject_mmio_error(pdev->pdev);
pci_unlock_rescan_remove(); break; default: return -ERANGE;
}
/* Set EEH probe mode */
eeh_add_flag(EEH_PROBE_MODE_DEVTREE | EEH_ENABLE_IO_FOR_LOG);
/* Set EEH machine dependent code */
ppc_md.pcibios_bus_add_device = pseries_pcibios_bus_add_device;
if (is_kdump_kernel() || reset_devices) {
pr_info("Issue PHB reset ...\n");
list_for_each_entry(phb, &hose_list, list_node) { // Skip if the slot is empty if (list_empty(&PCI_DN(phb->dn)->child_list)) continue;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.