// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/device.h> #include <linux/firmware/qcom/qcom_scm.h> #include <linux/ratelimit.h> #include "arm-smmu.h" #include "arm-smmu-qcom.h" void qcom_smmu_tlb_sync_debug(struct arm_smmu_device *smmu) { int ret; u32 tbu_pwr_status, sync_inv_ack, sync_inv_progress; struct qcom_smmu *qsmmu = container_of(smmu, struct qcom_smmu, smmu); const struct qcom_smmu_config *cfg; static DEFINE_RATELIMIT_STATE(rs, DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST); if (__ratelimit(&rs)) { dev_err(smmu->dev, "TLB sync timed out -- SMMU may be deadlocked\n"); cfg = qsmmu->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); dev_err(smmu->dev, "TBU: power_status %#x sync_inv_ack %#x sync_inv_progress %#x\n", tbu_pwr_status, sync_inv_ack, sync_inv_progress); } }