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/of_device.h> 7 #include <linux/qcom_scm.h> 8 #include <linux/ratelimit.h> 9 10 #include "arm-smmu.h" 11 #include "arm-smmu-qcom.h" 12 13 enum qcom_smmu_impl_reg_offset { 14 QCOM_SMMU_TBU_PWR_STATUS, 15 QCOM_SMMU_STATS_SYNC_INV_TBU_ACK, 16 QCOM_SMMU_MMU2QSS_AND_SAFE_WAIT_CNTR, 17 }; 18 19 struct qcom_smmu_config { 20 const u32 *reg_offset; 21 }; 22 23 void qcom_smmu_tlb_sync_debug(struct arm_smmu_device *smmu) 24 { 25 int ret; 26 u32 tbu_pwr_status, sync_inv_ack, sync_inv_progress; 27 struct qcom_smmu *qsmmu = container_of(smmu, struct qcom_smmu, smmu); 28 const struct qcom_smmu_config *cfg; 29 static DEFINE_RATELIMIT_STATE(rs, DEFAULT_RATELIMIT_INTERVAL, 30 DEFAULT_RATELIMIT_BURST); 31 32 if (__ratelimit(&rs)) { 33 dev_err(smmu->dev, "TLB sync timed out -- SMMU may be deadlocked\n"); 34 35 cfg = qsmmu->cfg; 36 if (!cfg) 37 return; 38 39 ret = qcom_scm_io_readl(smmu->ioaddr + cfg->reg_offset[QCOM_SMMU_TBU_PWR_STATUS], 40 &tbu_pwr_status); 41 if (ret) 42 dev_err(smmu->dev, 43 "Failed to read TBU power status: %d\n", ret); 44 45 ret = qcom_scm_io_readl(smmu->ioaddr + cfg->reg_offset[QCOM_SMMU_STATS_SYNC_INV_TBU_ACK], 46 &sync_inv_ack); 47 if (ret) 48 dev_err(smmu->dev, 49 "Failed to read TBU sync/inv ack status: %d\n", ret); 50 51 ret = qcom_scm_io_readl(smmu->ioaddr + cfg->reg_offset[QCOM_SMMU_MMU2QSS_AND_SAFE_WAIT_CNTR], 52 &sync_inv_progress); 53 if (ret) 54 dev_err(smmu->dev, 55 "Failed to read TCU syn/inv progress: %d\n", ret); 56 57 dev_err(smmu->dev, 58 "TBU: power_status %#x sync_inv_ack %#x sync_inv_progress %#x\n", 59 tbu_pwr_status, sync_inv_ack, sync_inv_progress); 60 } 61 } 62 63 /* Implementation Defined Register Space 0 register offsets */ 64 static const u32 qcom_smmu_impl0_reg_offset[] = { 65 [QCOM_SMMU_TBU_PWR_STATUS] = 0x2204, 66 [QCOM_SMMU_STATS_SYNC_INV_TBU_ACK] = 0x25dc, 67 [QCOM_SMMU_MMU2QSS_AND_SAFE_WAIT_CNTR] = 0x2670, 68 }; 69 70 static const struct qcom_smmu_config qcm2290_smmu_cfg = { 71 .reg_offset = qcom_smmu_impl0_reg_offset, 72 }; 73 74 static const struct qcom_smmu_config sc7180_smmu_cfg = { 75 .reg_offset = qcom_smmu_impl0_reg_offset, 76 }; 77 78 static const struct qcom_smmu_config sc7280_smmu_cfg = { 79 .reg_offset = qcom_smmu_impl0_reg_offset, 80 }; 81 82 static const struct qcom_smmu_config sc8180x_smmu_cfg = { 83 .reg_offset = qcom_smmu_impl0_reg_offset, 84 }; 85 86 static const struct qcom_smmu_config sc8280xp_smmu_cfg = { 87 .reg_offset = qcom_smmu_impl0_reg_offset, 88 }; 89 90 static const struct qcom_smmu_config sm6125_smmu_cfg = { 91 .reg_offset = qcom_smmu_impl0_reg_offset, 92 }; 93 94 static const struct qcom_smmu_config sm6350_smmu_cfg = { 95 .reg_offset = qcom_smmu_impl0_reg_offset, 96 }; 97 98 static const struct qcom_smmu_config sm8150_smmu_cfg = { 99 .reg_offset = qcom_smmu_impl0_reg_offset, 100 }; 101 102 static const struct qcom_smmu_config sm8250_smmu_cfg = { 103 .reg_offset = qcom_smmu_impl0_reg_offset, 104 }; 105 106 static const struct qcom_smmu_config sm8350_smmu_cfg = { 107 .reg_offset = qcom_smmu_impl0_reg_offset, 108 }; 109 110 static const struct qcom_smmu_config sm8450_smmu_cfg = { 111 .reg_offset = qcom_smmu_impl0_reg_offset, 112 }; 113 114 static const struct of_device_id __maybe_unused qcom_smmu_impl_debug_match[] = { 115 { .compatible = "qcom,msm8998-smmu-v2" }, 116 { .compatible = "qcom,qcm2290-smmu-500", .data = &qcm2290_smmu_cfg }, 117 { .compatible = "qcom,sc7180-smmu-500", .data = &sc7180_smmu_cfg }, 118 { .compatible = "qcom,sc7280-smmu-500", .data = &sc7280_smmu_cfg}, 119 { .compatible = "qcom,sc8180x-smmu-500", .data = &sc8180x_smmu_cfg }, 120 { .compatible = "qcom,sc8280xp-smmu-500", .data = &sc8280xp_smmu_cfg }, 121 { .compatible = "qcom,sdm630-smmu-v2" }, 122 { .compatible = "qcom,sdm845-smmu-500" }, 123 { .compatible = "qcom,sm6125-smmu-500", .data = &sm6125_smmu_cfg}, 124 { .compatible = "qcom,sm6350-smmu-500", .data = &sm6350_smmu_cfg}, 125 { .compatible = "qcom,sm8150-smmu-500", .data = &sm8150_smmu_cfg }, 126 { .compatible = "qcom,sm8250-smmu-500", .data = &sm8250_smmu_cfg }, 127 { .compatible = "qcom,sm8350-smmu-500", .data = &sm8350_smmu_cfg }, 128 { .compatible = "qcom,sm8450-smmu-500", .data = &sm8450_smmu_cfg }, 129 { } 130 }; 131 132 const void *qcom_smmu_impl_data(struct arm_smmu_device *smmu) 133 { 134 const struct of_device_id *match; 135 const struct device_node *np = smmu->dev->of_node; 136 137 match = of_match_node(qcom_smmu_impl_debug_match, np); 138 if (!match) 139 return NULL; 140 141 return match->data; 142 } 143