Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0d5ee520 authored by Gavin Shan's avatar Gavin Shan Committed by Michael Ellerman
Browse files

powerpc/eeh: Freeze PE before PE reset



The patch adds one more option (EEH_OPT_FREEZE_PE) to set_option()
method to proactively freeze PE, which will be issued before resetting
pass-throughed PE to drop MMIO access during reset because it's
always contributing to recursive EEH error.

Signed-off-by: default avatarGavin Shan <gwshan@linux.vnet.ibm.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent 940376b3
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -172,6 +172,7 @@ enum {
#define EEH_OPT_ENABLE		1	/* EEH enable	*/
#define EEH_OPT_ENABLE		1	/* EEH enable	*/
#define EEH_OPT_THAW_MMIO	2	/* MMIO enable	*/
#define EEH_OPT_THAW_MMIO	2	/* MMIO enable	*/
#define EEH_OPT_THAW_DMA	3	/* DMA enable	*/
#define EEH_OPT_THAW_DMA	3	/* DMA enable	*/
#define EEH_OPT_FREEZE_PE	4	/* Freeze PE	*/
#define EEH_STATE_UNAVAILABLE	(1 << 0)	/* State unavailable	*/
#define EEH_STATE_UNAVAILABLE	(1 << 0)	/* State unavailable	*/
#define EEH_STATE_NOT_SUPPORT	(1 << 1)	/* EEH not supported	*/
#define EEH_STATE_NOT_SUPPORT	(1 << 1)	/* EEH not supported	*/
#define EEH_STATE_RESET_ACTIVE	(1 << 2)	/* Active reset		*/
#define EEH_STATE_RESET_ACTIVE	(1 << 2)	/* Active reset		*/
+7 −0
Original line number Original line Diff line number Diff line
@@ -1382,6 +1382,13 @@ int eeh_pe_reset(struct eeh_pe *pe, int option)
		break;
		break;
	case EEH_RESET_HOT:
	case EEH_RESET_HOT:
	case EEH_RESET_FUNDAMENTAL:
	case EEH_RESET_FUNDAMENTAL:
		/*
		 * Proactively freeze the PE to drop all MMIO access
		 * during reset, which should be banned as it's always
		 * cause recursive EEH error.
		 */
		eeh_ops->set_option(pe, EEH_OPT_FREEZE_PE);

		ret = eeh_ops->reset(pe, option);
		ret = eeh_ops->reset(pe, option);
		break;
		break;
	default:
	default:
+33 −10
Original line number Original line Diff line number Diff line
@@ -189,6 +189,7 @@ static int ioda_eeh_set_option(struct eeh_pe *pe, int option)
{
{
	struct pci_controller *hose = pe->phb;
	struct pci_controller *hose = pe->phb;
	struct pnv_phb *phb = hose->private_data;
	struct pnv_phb *phb = hose->private_data;
	bool freeze_pe = false;
	int enable, ret = 0;
	int enable, ret = 0;
	s64 rc;
	s64 rc;


@@ -212,6 +213,10 @@ static int ioda_eeh_set_option(struct eeh_pe *pe, int option)
	case EEH_OPT_THAW_DMA:
	case EEH_OPT_THAW_DMA:
		enable = OPAL_EEH_ACTION_CLEAR_FREEZE_DMA;
		enable = OPAL_EEH_ACTION_CLEAR_FREEZE_DMA;
		break;
		break;
	case EEH_OPT_FREEZE_PE:
		freeze_pe = true;
		enable = OPAL_EEH_ACTION_SET_FREEZE_ALL;
		break;
	default:
	default:
		pr_warn("%s: Invalid option %d\n",
		pr_warn("%s: Invalid option %d\n",
			__func__, option);
			__func__, option);
@@ -219,6 +224,22 @@ static int ioda_eeh_set_option(struct eeh_pe *pe, int option)
	}
	}


	/* If PHB supports compound PE, to handle it */
	/* If PHB supports compound PE, to handle it */
	if (freeze_pe) {
		if (phb->freeze_pe) {
			phb->freeze_pe(phb, pe->addr);
		} else {
			rc = opal_pci_eeh_freeze_set(phb->opal_id,
						     pe->addr,
						     enable);
			if (rc != OPAL_SUCCESS) {
				pr_warn("%s: Failure %lld freezing "
					"PHB#%x-PE#%x\n",
					__func__, rc,
					phb->hose->global_number, pe->addr);
				ret = -EIO;
			}
		}
	} else {
		if (phb->unfreeze_pe) {
		if (phb->unfreeze_pe) {
			ret = phb->unfreeze_pe(phb, pe->addr, enable);
			ret = phb->unfreeze_pe(phb, pe->addr, enable);
		} else {
		} else {
@@ -226,12 +247,14 @@ static int ioda_eeh_set_option(struct eeh_pe *pe, int option)
						       pe->addr,
						       pe->addr,
						       enable);
						       enable);
			if (rc != OPAL_SUCCESS) {
			if (rc != OPAL_SUCCESS) {
			pr_warn("%s: Failure %lld enable %d for PHB#%x-PE#%x\n",
				pr_warn("%s: Failure %lld enable %d "
				__func__, rc, option, phb->hose->global_number,
					"for PHB#%x-PE#%x\n",
				pe->addr);
					__func__, rc, option,
					phb->hose->global_number, pe->addr);
				ret = -EIO;
				ret = -EIO;
			}
			}
		}
		}
	}


	return ret;
	return ret;
}
}
+3 −1
Original line number Original line Diff line number Diff line
@@ -349,7 +349,9 @@ static int pseries_eeh_set_option(struct eeh_pe *pe, int option)
		if (pe->addr)
		if (pe->addr)
			config_addr = pe->addr;
			config_addr = pe->addr;
		break;
		break;

	case EEH_OPT_FREEZE_PE:
		/* Not support */
		return 0;
	default:
	default:
		pr_err("%s: Invalid option %d\n",
		pr_err("%s: Invalid option %d\n",
			__func__, option);
			__func__, option);