0001
0002
0003
0004
0005
0006 #include <linux/of_device.h>
0007 #include <linux/qcom_scm.h>
0008 #include <linux/ratelimit.h>
0009
0010 #include "arm-smmu.h"
0011 #include "arm-smmu-qcom.h"
0012
0013 enum qcom_smmu_impl_reg_offset {
0014 QCOM_SMMU_TBU_PWR_STATUS,
0015 QCOM_SMMU_STATS_SYNC_INV_TBU_ACK,
0016 QCOM_SMMU_MMU2QSS_AND_SAFE_WAIT_CNTR,
0017 };
0018
0019 struct qcom_smmu_config {
0020 const u32 *reg_offset;
0021 };
0022
0023 void qcom_smmu_tlb_sync_debug(struct arm_smmu_device *smmu)
0024 {
0025 int ret;
0026 u32 tbu_pwr_status, sync_inv_ack, sync_inv_progress;
0027 struct qcom_smmu *qsmmu = container_of(smmu, struct qcom_smmu, smmu);
0028 const struct qcom_smmu_config *cfg;
0029 static DEFINE_RATELIMIT_STATE(rs, DEFAULT_RATELIMIT_INTERVAL,
0030 DEFAULT_RATELIMIT_BURST);
0031
0032 if (__ratelimit(&rs)) {
0033 dev_err(smmu->dev, "TLB sync timed out -- SMMU may be deadlocked\n");
0034
0035 cfg = qsmmu->cfg;
0036 if (!cfg)
0037 return;
0038
0039 ret = qcom_scm_io_readl(smmu->ioaddr + cfg->reg_offset[QCOM_SMMU_TBU_PWR_STATUS],
0040 &tbu_pwr_status);
0041 if (ret)
0042 dev_err(smmu->dev,
0043 "Failed to read TBU power status: %d\n", ret);
0044
0045 ret = qcom_scm_io_readl(smmu->ioaddr + cfg->reg_offset[QCOM_SMMU_STATS_SYNC_INV_TBU_ACK],
0046 &sync_inv_ack);
0047 if (ret)
0048 dev_err(smmu->dev,
0049 "Failed to read TBU sync/inv ack status: %d\n", ret);
0050
0051 ret = qcom_scm_io_readl(smmu->ioaddr + cfg->reg_offset[QCOM_SMMU_MMU2QSS_AND_SAFE_WAIT_CNTR],
0052 &sync_inv_progress);
0053 if (ret)
0054 dev_err(smmu->dev,
0055 "Failed to read TCU syn/inv progress: %d\n", ret);
0056
0057 dev_err(smmu->dev,
0058 "TBU: power_status %#x sync_inv_ack %#x sync_inv_progress %#x\n",
0059 tbu_pwr_status, sync_inv_ack, sync_inv_progress);
0060 }
0061 }
0062
0063
0064 static const u32 qcom_smmu_impl0_reg_offset[] = {
0065 [QCOM_SMMU_TBU_PWR_STATUS] = 0x2204,
0066 [QCOM_SMMU_STATS_SYNC_INV_TBU_ACK] = 0x25dc,
0067 [QCOM_SMMU_MMU2QSS_AND_SAFE_WAIT_CNTR] = 0x2670,
0068 };
0069
0070 static const struct qcom_smmu_config qcm2290_smmu_cfg = {
0071 .reg_offset = qcom_smmu_impl0_reg_offset,
0072 };
0073
0074 static const struct qcom_smmu_config sc7180_smmu_cfg = {
0075 .reg_offset = qcom_smmu_impl0_reg_offset,
0076 };
0077
0078 static const struct qcom_smmu_config sc7280_smmu_cfg = {
0079 .reg_offset = qcom_smmu_impl0_reg_offset,
0080 };
0081
0082 static const struct qcom_smmu_config sc8180x_smmu_cfg = {
0083 .reg_offset = qcom_smmu_impl0_reg_offset,
0084 };
0085
0086 static const struct qcom_smmu_config sc8280xp_smmu_cfg = {
0087 .reg_offset = qcom_smmu_impl0_reg_offset,
0088 };
0089
0090 static const struct qcom_smmu_config sm6125_smmu_cfg = {
0091 .reg_offset = qcom_smmu_impl0_reg_offset,
0092 };
0093
0094 static const struct qcom_smmu_config sm6350_smmu_cfg = {
0095 .reg_offset = qcom_smmu_impl0_reg_offset,
0096 };
0097
0098 static const struct qcom_smmu_config sm8150_smmu_cfg = {
0099 .reg_offset = qcom_smmu_impl0_reg_offset,
0100 };
0101
0102 static const struct qcom_smmu_config sm8250_smmu_cfg = {
0103 .reg_offset = qcom_smmu_impl0_reg_offset,
0104 };
0105
0106 static const struct qcom_smmu_config sm8350_smmu_cfg = {
0107 .reg_offset = qcom_smmu_impl0_reg_offset,
0108 };
0109
0110 static const struct qcom_smmu_config sm8450_smmu_cfg = {
0111 .reg_offset = qcom_smmu_impl0_reg_offset,
0112 };
0113
0114 static const struct of_device_id __maybe_unused qcom_smmu_impl_debug_match[] = {
0115 { .compatible = "qcom,msm8998-smmu-v2" },
0116 { .compatible = "qcom,qcm2290-smmu-500", .data = &qcm2290_smmu_cfg },
0117 { .compatible = "qcom,sc7180-smmu-500", .data = &sc7180_smmu_cfg },
0118 { .compatible = "qcom,sc7280-smmu-500", .data = &sc7280_smmu_cfg},
0119 { .compatible = "qcom,sc8180x-smmu-500", .data = &sc8180x_smmu_cfg },
0120 { .compatible = "qcom,sc8280xp-smmu-500", .data = &sc8280xp_smmu_cfg },
0121 { .compatible = "qcom,sdm630-smmu-v2" },
0122 { .compatible = "qcom,sdm845-smmu-500" },
0123 { .compatible = "qcom,sm6125-smmu-500", .data = &sm6125_smmu_cfg},
0124 { .compatible = "qcom,sm6350-smmu-500", .data = &sm6350_smmu_cfg},
0125 { .compatible = "qcom,sm8150-smmu-500", .data = &sm8150_smmu_cfg },
0126 { .compatible = "qcom,sm8250-smmu-500", .data = &sm8250_smmu_cfg },
0127 { .compatible = "qcom,sm8350-smmu-500", .data = &sm8350_smmu_cfg },
0128 { .compatible = "qcom,sm8450-smmu-500", .data = &sm8450_smmu_cfg },
0129 { }
0130 };
0131
0132 const void *qcom_smmu_impl_data(struct arm_smmu_device *smmu)
0133 {
0134 const struct of_device_id *match;
0135 const struct device_node *np = smmu->dev->of_node;
0136
0137 match = of_match_node(qcom_smmu_impl_debug_match, np);
0138 if (!match)
0139 return NULL;
0140
0141 return match->data;
0142 }