mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-07 12:25:00 -04:00
Merge "iommu: arm-smmu: clear TBU halt request when halt times out"
This commit is contained in:
commit
916dbcdb30
1 changed files with 60 additions and 39 deletions
|
|
@ -5012,10 +5012,10 @@ static int qsmmuv500_tbu_halt(struct qsmmuv500_tbu_device *tbu,
|
|||
struct arm_smmu_domain *smmu_domain)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 halt, fsr, sctlr_orig, sctlr, status;
|
||||
void __iomem *base;
|
||||
struct arm_smmu_device *smmu = smmu_domain->smmu;
|
||||
int idx = smmu_domain->cfg.cbndx;
|
||||
u32 halt, fsr, status;
|
||||
void __iomem *tbu_base;
|
||||
|
||||
if (of_property_read_bool(tbu->dev->of_node,
|
||||
"qcom,opt-out-tbu-halting")) {
|
||||
|
|
@ -5030,47 +5030,49 @@ static int qsmmuv500_tbu_halt(struct qsmmuv500_tbu_device *tbu,
|
|||
return 0;
|
||||
}
|
||||
|
||||
base = tbu->base;
|
||||
halt = readl_relaxed(base + DEBUG_SID_HALT_REG);
|
||||
tbu_base = tbu->base;
|
||||
halt = readl_relaxed(tbu_base + DEBUG_SID_HALT_REG);
|
||||
halt |= DEBUG_SID_HALT_REQ;
|
||||
writel_relaxed(halt, base + DEBUG_SID_HALT_REG);
|
||||
|
||||
if (!readl_poll_timeout_atomic(base + DEBUG_SR_HALT_ACK_REG, status,
|
||||
(status & DEBUG_SR_HALT_ACK_VAL),
|
||||
0, TBU_DBG_TIMEOUT_US))
|
||||
goto out;
|
||||
writel_relaxed(halt, tbu_base + DEBUG_SID_HALT_REG);
|
||||
|
||||
fsr = arm_smmu_cb_read(smmu, idx, ARM_SMMU_CB_FSR);
|
||||
if (!(fsr & FSR_FAULT)) {
|
||||
dev_err(tbu->dev, "Couldn't halt TBU!\n");
|
||||
spin_unlock_irqrestore(&tbu->halt_lock, flags);
|
||||
return -ETIMEDOUT;
|
||||
if ((fsr & FSR_FAULT) && (fsr & FSR_SS)) {
|
||||
u32 sctlr_orig, sctlr;
|
||||
/*
|
||||
* We are in a fault; Our request to halt the bus will not
|
||||
* complete until transactions in front of us (such as the fault
|
||||
* itself) have completed. Disable iommu faults and terminate
|
||||
* any existing transactions.
|
||||
*/
|
||||
sctlr_orig = arm_smmu_cb_read(smmu, idx, ARM_SMMU_CB_SCTLR);
|
||||
sctlr = sctlr_orig & ~(SCTLR_CFCFG | SCTLR_CFIE);
|
||||
arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_SCTLR, sctlr);
|
||||
|
||||
arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_FSR, fsr);
|
||||
/*
|
||||
* Barrier required to ensure that the FSR is cleared
|
||||
* before resuming SMMU operation
|
||||
*/
|
||||
wmb();
|
||||
arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_RESUME,
|
||||
RESUME_TERMINATE);
|
||||
|
||||
arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_SCTLR, sctlr_orig);
|
||||
}
|
||||
|
||||
/*
|
||||
* We are in a fault; Our request to halt the bus will not complete
|
||||
* until transactions in front of us (such as the fault itself) have
|
||||
* completed. Disable iommu faults and terminate any existing
|
||||
* transactions.
|
||||
*/
|
||||
sctlr_orig = arm_smmu_cb_read(smmu, idx, ARM_SMMU_CB_SCTLR);
|
||||
sctlr = sctlr_orig & ~(SCTLR_CFCFG | SCTLR_CFIE);
|
||||
arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_SCTLR, sctlr);
|
||||
|
||||
arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_FSR, fsr);
|
||||
arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_RESUME, RESUME_TERMINATE);
|
||||
|
||||
if (readl_poll_timeout_atomic(base + DEBUG_SR_HALT_ACK_REG, status,
|
||||
if (readl_poll_timeout_atomic(tbu_base + DEBUG_SR_HALT_ACK_REG, status,
|
||||
(status & DEBUG_SR_HALT_ACK_VAL),
|
||||
0, TBU_DBG_TIMEOUT_US)) {
|
||||
dev_err(tbu->dev, "Couldn't halt TBU from fault context!\n");
|
||||
arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_SCTLR, sctlr_orig);
|
||||
dev_err(tbu->dev, "Couldn't halt TBU!\n");
|
||||
|
||||
halt = readl_relaxed(tbu_base + DEBUG_SID_HALT_REG);
|
||||
halt &= ~DEBUG_SID_HALT_REQ;
|
||||
writel_relaxed(halt, tbu_base + DEBUG_SID_HALT_REG);
|
||||
|
||||
spin_unlock_irqrestore(&tbu->halt_lock, flags);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_SCTLR, sctlr_orig);
|
||||
out:
|
||||
tbu->halt_count = 1;
|
||||
spin_unlock_irqrestore(&tbu->halt_lock, flags);
|
||||
return 0;
|
||||
|
|
@ -5200,6 +5202,25 @@ static phys_addr_t qsmmuv500_iova_to_phys(
|
|||
sctlr = sctlr_orig & ~(SCTLR_CFCFG | SCTLR_CFIE);
|
||||
arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_SCTLR, sctlr);
|
||||
|
||||
fsr = arm_smmu_cb_read(smmu, idx, ARM_SMMU_CB_FSR);
|
||||
if (fsr & FSR_FAULT) {
|
||||
/* Clear pending interrupts */
|
||||
arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_FSR, fsr);
|
||||
/*
|
||||
* Barrier required to ensure that the FSR is cleared
|
||||
* before resuming SMMU operation.
|
||||
*/
|
||||
wmb();
|
||||
|
||||
/*
|
||||
* TBU halt takes care of resuming any stalled transcation.
|
||||
* Kept it here for completeness sake.
|
||||
*/
|
||||
if (fsr & FSR_SS)
|
||||
arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_RESUME,
|
||||
RESUME_TERMINATE);
|
||||
}
|
||||
|
||||
/* Only one concurrent atos operation */
|
||||
ret = qsmmuv500_ecats_lock(smmu_domain, tbu, &flags);
|
||||
if (ret)
|
||||
|
|
@ -5243,10 +5264,12 @@ redo:
|
|||
|
||||
val = readq_relaxed(tbu->base + DEBUG_PAR_REG);
|
||||
fsr = arm_smmu_cb_read(smmu, idx, ARM_SMMU_CB_FSR);
|
||||
if (fsr & FSR_FAULT) {
|
||||
if (val & DEBUG_PAR_FAULT_VAL) {
|
||||
dev_err(tbu->dev, "ECATS generated a fault interrupt! FSR = %llx, SID=0x%x\n",
|
||||
fsr, sid);
|
||||
fsr, sid);
|
||||
|
||||
dev_err(tbu->dev, "ECATS translation failed! PAR = %llx\n",
|
||||
val);
|
||||
/* Clear pending interrupts */
|
||||
arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_FSR, fsr);
|
||||
/*
|
||||
|
|
@ -5254,13 +5277,11 @@ redo:
|
|||
* before resuming SMMU operation.
|
||||
*/
|
||||
wmb();
|
||||
arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_RESUME,
|
||||
RESUME_TERMINATE);
|
||||
|
||||
/* Check if ECATS translation failed */
|
||||
if (val & DEBUG_PAR_FAULT_VAL)
|
||||
dev_err(tbu->dev, "ECATS translation failed! PAR = %llx\n",
|
||||
val);
|
||||
if (fsr & FSR_SS)
|
||||
arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_RESUME,
|
||||
RESUME_TERMINATE);
|
||||
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue