1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
4  */
5 
6 #include <linux/device.h>
7 #include <linux/firmware/qcom/qcom_scm.h>
8 #include <linux/ratelimit.h>
9 
10 #include "arm-smmu.h"
11 #include "arm-smmu-qcom.h"
12 
qcom_smmu_tlb_sync_debug(struct arm_smmu_device * smmu)13 void qcom_smmu_tlb_sync_debug(struct arm_smmu_device *smmu)
14 {
15 	int ret;
16 	u32 tbu_pwr_status, sync_inv_ack, sync_inv_progress;
17 	struct qcom_smmu *qsmmu = container_of(smmu, struct qcom_smmu, smmu);
18 	const struct qcom_smmu_config *cfg;
19 	static DEFINE_RATELIMIT_STATE(rs, DEFAULT_RATELIMIT_INTERVAL,
20 				      DEFAULT_RATELIMIT_BURST);
21 
22 	if (__ratelimit(&rs)) {
23 		dev_err(smmu->dev, "TLB sync timed out -- SMMU may be deadlocked\n");
24 
25 		cfg = qsmmu->cfg;
26 		if (!cfg)
27 			return;
28 
29 		ret = qcom_scm_io_readl(smmu->ioaddr + cfg->reg_offset[QCOM_SMMU_TBU_PWR_STATUS],
30 					&tbu_pwr_status);
31 		if (ret)
32 			dev_err(smmu->dev,
33 				"Failed to read TBU power status: %d\n", ret);
34 
35 		ret = qcom_scm_io_readl(smmu->ioaddr + cfg->reg_offset[QCOM_SMMU_STATS_SYNC_INV_TBU_ACK],
36 					&sync_inv_ack);
37 		if (ret)
38 			dev_err(smmu->dev,
39 				"Failed to read TBU sync/inv ack status: %d\n", ret);
40 
41 		ret = qcom_scm_io_readl(smmu->ioaddr + cfg->reg_offset[QCOM_SMMU_MMU2QSS_AND_SAFE_WAIT_CNTR],
42 					&sync_inv_progress);
43 		if (ret)
44 			dev_err(smmu->dev,
45 				"Failed to read TCU syn/inv progress: %d\n", ret);
46 
47 		dev_err(smmu->dev,
48 			"TBU: power_status %#x sync_inv_ack %#x sync_inv_progress %#x\n",
49 			tbu_pwr_status, sync_inv_ack, sync_inv_progress);
50 	}
51 }
52