// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
*/
if (__ratelimit(&rs)) {
dev_err(smmu->dev, "TLB sync timed out -- SMMU may be deadlocked\n");
cfg = qsmmu->data->cfg; if (!cfg) return;
ret = qcom_scm_io_readl(smmu->ioaddr + cfg->reg_offset[QCOM_SMMU_TBU_PWR_STATUS],
&tbu_pwr_status); if (ret)
dev_err(smmu->dev, "Failed to read TBU power status: %d\n", ret);
ret = qcom_scm_io_readl(smmu->ioaddr + cfg->reg_offset[QCOM_SMMU_STATS_SYNC_INV_TBU_ACK],
&sync_inv_ack); if (ret)
dev_err(smmu->dev, "Failed to read TBU sync/inv ack status: %d\n", ret);
ret = qcom_scm_io_readl(smmu->ioaddr + cfg->reg_offset[QCOM_SMMU_MMU2QSS_AND_SAFE_WAIT_CNTR],
&sync_inv_progress); if (ret)
dev_err(smmu->dev, "Failed to read TCU syn/inv progress: %d\n", ret);
/* * 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 & ~(ARM_SMMU_SCTLR_CFCFG | ARM_SMMU_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, ARM_SMMU_RESUME_TERMINATE);
arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_SCTLR, sctlr_orig);
}
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, "Timeout while trying to halt TBU!\n");
ret = -ETIMEDOUT;
val = readl_relaxed(tbu->base + DEBUG_SID_HALT_REG);
val &= ~DEBUG_SID_HALT_VAL;
writel_relaxed(val, tbu->base + DEBUG_SID_HALT_REG);
/* * TBU halt takes care of resuming any stalled transcation. * Kept it here for completeness sake.
*/ if (fsr & ARM_SMMU_CB_FSR_SS)
arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_RESUME,
ARM_SMMU_RESUME_TERMINATE);
}
/* Only one concurrent atos operation */
scoped_guard(spinlock_irqsave, &atos_lock) { /* * If the translation fails, attempt the lookup more time."
*/ do {
phys = qcom_tbu_trigger_atos(smmu_domain, tbu, iova, sid);
if (__ratelimit(&_rs)) {
arm_smmu_print_context_fault_info(smmu, idx, &cfi);
dev_err(smmu->dev, "soft iova-to-phys=%pa\n", &phys_soft); if (!phys_soft)
dev_err(smmu->dev, "SOFTWARE TABLE WALK FAILED! Looks like %s accessed an unmapped address!\n",
dev_name(smmu->dev)); if (phys_atos)
dev_err(smmu->dev, "hard iova-to-phys (ATOS)=%pa\n",
&phys_atos); else
dev_err(smmu->dev, "hard iova-to-phys (ATOS) failed\n");
}
ret = IRQ_NONE;
resume = ARM_SMMU_RESUME_TERMINATE;
}
/* * If the client returns -EBUSY, do not clear FSR and do not RESUME * if stalled. This is required to keep the IOMMU client stalled on * the outstanding fault. This gives the client a chance to take any * debug action and then terminate the stalled transaction. * So, the sequence in case of stall on fault should be: * 1) Do not clear FSR or write to RESUME here * 2) Client takes any debug action * 3) Client terminates the stalled transaction and resumes the IOMMU * 4) Client clears FSR. The FSR should only be cleared after 3) and * not before so that the fault remains outstanding. This ensures * SCTLR.HUPCF has the desired effect if subsequent transactions also * need to be terminated.
*/ if (tmp != -EBUSY) { /* Clear the faulting FSR */
arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_FSR, cfi.fsr);
/* Retry or terminate any stalled transactions */ if (cfi.fsr & ARM_SMMU_CB_FSR_SS)
arm_smmu_cb_write(smmu, idx, ARM_SMMU_CB_RESUME, resume);
}
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.