|
@@ -116,10 +116,107 @@ static int ioda_eeh_set_option(struct eeh_pe *pe, int option)
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * ioda_eeh_get_state - Retrieve the state of PE
|
|
|
+ * @pe: EEH PE
|
|
|
+ *
|
|
|
+ * The PE's state should be retrieved from the PEEV, PEST
|
|
|
+ * IODA tables. Since the OPAL has exported the function
|
|
|
+ * to do it, it'd better to use that.
|
|
|
+ */
|
|
|
+static int ioda_eeh_get_state(struct eeh_pe *pe)
|
|
|
+{
|
|
|
+ s64 ret = 0;
|
|
|
+ u8 fstate;
|
|
|
+ u16 pcierr;
|
|
|
+ u32 pe_no;
|
|
|
+ int result;
|
|
|
+ struct pci_controller *hose = pe->phb;
|
|
|
+ struct pnv_phb *phb = hose->private_data;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Sanity check on PE address. The PHB PE address should
|
|
|
+ * be zero.
|
|
|
+ */
|
|
|
+ if (pe->addr < 0 || pe->addr >= phb->ioda.total_pe) {
|
|
|
+ pr_err("%s: PE address %x out of range [0, %x] "
|
|
|
+ "on PHB#%x\n",
|
|
|
+ __func__, pe->addr, phb->ioda.total_pe,
|
|
|
+ hose->global_number);
|
|
|
+ return EEH_STATE_NOT_SUPPORT;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Retrieve PE status through OPAL */
|
|
|
+ pe_no = pe->addr;
|
|
|
+ ret = opal_pci_eeh_freeze_status(phb->opal_id, pe_no,
|
|
|
+ &fstate, &pcierr, NULL);
|
|
|
+ if (ret) {
|
|
|
+ pr_err("%s: Failed to get EEH status on "
|
|
|
+ "PHB#%x-PE#%x\n, err=%lld\n",
|
|
|
+ __func__, hose->global_number, pe_no, ret);
|
|
|
+ return EEH_STATE_NOT_SUPPORT;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Check PHB status */
|
|
|
+ if (pe->type & EEH_PE_PHB) {
|
|
|
+ result = 0;
|
|
|
+ result &= ~EEH_STATE_RESET_ACTIVE;
|
|
|
+
|
|
|
+ if (pcierr != OPAL_EEH_PHB_ERROR) {
|
|
|
+ result |= EEH_STATE_MMIO_ACTIVE;
|
|
|
+ result |= EEH_STATE_DMA_ACTIVE;
|
|
|
+ result |= EEH_STATE_MMIO_ENABLED;
|
|
|
+ result |= EEH_STATE_DMA_ENABLED;
|
|
|
+ }
|
|
|
+
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Parse result out */
|
|
|
+ result = 0;
|
|
|
+ switch (fstate) {
|
|
|
+ case OPAL_EEH_STOPPED_NOT_FROZEN:
|
|
|
+ result &= ~EEH_STATE_RESET_ACTIVE;
|
|
|
+ result |= EEH_STATE_MMIO_ACTIVE;
|
|
|
+ result |= EEH_STATE_DMA_ACTIVE;
|
|
|
+ result |= EEH_STATE_MMIO_ENABLED;
|
|
|
+ result |= EEH_STATE_DMA_ENABLED;
|
|
|
+ break;
|
|
|
+ case OPAL_EEH_STOPPED_MMIO_FREEZE:
|
|
|
+ result &= ~EEH_STATE_RESET_ACTIVE;
|
|
|
+ result |= EEH_STATE_DMA_ACTIVE;
|
|
|
+ result |= EEH_STATE_DMA_ENABLED;
|
|
|
+ break;
|
|
|
+ case OPAL_EEH_STOPPED_DMA_FREEZE:
|
|
|
+ result &= ~EEH_STATE_RESET_ACTIVE;
|
|
|
+ result |= EEH_STATE_MMIO_ACTIVE;
|
|
|
+ result |= EEH_STATE_MMIO_ENABLED;
|
|
|
+ break;
|
|
|
+ case OPAL_EEH_STOPPED_MMIO_DMA_FREEZE:
|
|
|
+ result &= ~EEH_STATE_RESET_ACTIVE;
|
|
|
+ break;
|
|
|
+ case OPAL_EEH_STOPPED_RESET:
|
|
|
+ result |= EEH_STATE_RESET_ACTIVE;
|
|
|
+ break;
|
|
|
+ case OPAL_EEH_STOPPED_TEMP_UNAVAIL:
|
|
|
+ result |= EEH_STATE_UNAVAILABLE;
|
|
|
+ break;
|
|
|
+ case OPAL_EEH_STOPPED_PERM_UNAVAIL:
|
|
|
+ result |= EEH_STATE_NOT_SUPPORT;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ pr_warning("%s: Unexpected EEH status 0x%x "
|
|
|
+ "on PHB#%x-PE#%x\n",
|
|
|
+ __func__, fstate, hose->global_number, pe_no);
|
|
|
+ }
|
|
|
+
|
|
|
+ return result;
|
|
|
+}
|
|
|
+
|
|
|
struct pnv_eeh_ops ioda_eeh_ops = {
|
|
|
.post_init = ioda_eeh_post_init,
|
|
|
.set_option = ioda_eeh_set_option,
|
|
|
- .get_state = NULL,
|
|
|
+ .get_state = ioda_eeh_get_state,
|
|
|
.reset = NULL,
|
|
|
.get_log = NULL,
|
|
|
.configure_bridge = NULL,
|