iommu: add a function to get MID/PID/BID info
For certain use cases SID remains same and when an smmu page fault occurs it becomes difficult for client to identify which of the usecases is actually causing the fault. In such cases MID/PID/BID info can help. So, add a function for the same so that clients can call this from their fault handler and get the info. Change-Id: Ia720641224f908287ae1d66908ab12def82bbbab Signed-off-by: Vijayanand Jitta <vjitta@codeaurora.org>
This commit is contained in:
parent
245792aaac
commit
2ae11214cb
@ -892,6 +892,42 @@ static int report_iommu_fault_helper(struct arm_smmu_domain *smmu_domain,
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
static int arm_smmu_get_fault_ids(struct iommu_domain *domain,
|
||||
struct qcom_iommu_fault_ids *f_ids)
|
||||
{
|
||||
struct arm_smmu_domain *smmu_domain;
|
||||
struct arm_smmu_device *smmu;
|
||||
u32 fsr, fsynr1;
|
||||
int idx, ret;
|
||||
|
||||
if (!domain || !f_ids)
|
||||
return -EINVAL;
|
||||
|
||||
smmu_domain = to_smmu_domain(domain);
|
||||
smmu = smmu_domain->smmu;
|
||||
idx = smmu_domain->cfg.cbndx;
|
||||
|
||||
ret = arm_smmu_rpm_get(smmu);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
fsr = arm_smmu_cb_read(smmu, idx, ARM_SMMU_CB_FSR);
|
||||
|
||||
if (!(fsr & ARM_SMMU_FSR_FAULT)) {
|
||||
arm_smmu_power_off(smmu, smmu->pwr);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fsynr1 = arm_smmu_cb_read(smmu, idx, ARM_SMMU_CB_FSYNR1);
|
||||
arm_smmu_rpm_put(smmu);
|
||||
|
||||
f_ids->bid = FIELD_GET(ARM_SMMU_FSYNR1_BID, fsynr1);
|
||||
f_ids->pid = FIELD_GET(ARM_SMMU_FSYNR1_PID, fsynr1);
|
||||
f_ids->mid = FIELD_GET(ARM_SMMU_FSYNR1_MID, fsynr1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t arm_smmu_context_fault(int irq, void *dev)
|
||||
{
|
||||
u32 fsr;
|
||||
@ -3171,6 +3207,7 @@ static int arm_smmu_sid_switch(struct device *dev,
|
||||
static struct qcom_iommu_ops arm_smmu_ops = {
|
||||
.iova_to_phys_hard = arm_smmu_iova_to_phys_hard,
|
||||
.sid_switch = arm_smmu_sid_switch,
|
||||
.get_fault_ids = arm_smmu_get_fault_ids,
|
||||
.iommu_ops = {
|
||||
.capable = arm_smmu_capable,
|
||||
.domain_alloc = arm_smmu_domain_alloc,
|
||||
|
@ -358,6 +358,18 @@ int qcom_iommu_sid_switch(struct device *dev, enum sid_switch_direction dir)
|
||||
}
|
||||
EXPORT_SYMBOL(qcom_iommu_sid_switch);
|
||||
|
||||
int qcom_iommu_get_fault_ids(struct iommu_domain *domain,
|
||||
struct qcom_iommu_fault_ids *f_ids)
|
||||
{
|
||||
struct qcom_iommu_ops *ops = to_qcom_iommu_ops(domain->ops);
|
||||
|
||||
if (unlikely(ops->get_fault_ids == NULL))
|
||||
return -EINVAL;
|
||||
|
||||
return ops->get_fault_ids(domain, f_ids);
|
||||
}
|
||||
EXPORT_SYMBOL(qcom_iommu_get_fault_ids);
|
||||
|
||||
struct io_pgtable_ops *qcom_alloc_io_pgtable_ops(enum io_pgtable_fmt fmt,
|
||||
struct qcom_io_pgtable_info *pgtbl_info,
|
||||
void *cookie)
|
||||
|
@ -31,6 +31,12 @@ enum sid_switch_direction {
|
||||
SID_SWITCH_SECURE_TO_HLOS,
|
||||
};
|
||||
|
||||
struct qcom_iommu_fault_ids {
|
||||
u32 bid;
|
||||
u32 pid;
|
||||
u32 mid;
|
||||
};
|
||||
|
||||
/*
|
||||
* @sid_switch: add/remove all SIDS in the iommu domain containing dev from
|
||||
* iommu registers.
|
||||
@ -39,6 +45,8 @@ struct qcom_iommu_ops {
|
||||
phys_addr_t (*iova_to_phys_hard)(struct iommu_domain *domain,
|
||||
struct qcom_iommu_atos_txn *txn);
|
||||
int (*sid_switch)(struct device *dev, enum sid_switch_direction dir);
|
||||
int (*get_fault_ids)(struct iommu_domain *domain,
|
||||
struct qcom_iommu_fault_ids *ids);
|
||||
struct iommu_ops iommu_ops;
|
||||
};
|
||||
#define to_qcom_iommu_ops(x) (container_of(x, struct qcom_iommu_ops, iommu_ops))
|
||||
@ -59,6 +67,11 @@ void qcom_iommu_put_resv_regions(struct device *dev, struct list_head *list);
|
||||
phys_addr_t qcom_iommu_iova_to_phys_hard(struct iommu_domain *domain,
|
||||
struct qcom_iommu_atos_txn *txn);
|
||||
|
||||
|
||||
extern int qcom_iommu_get_fault_ids(struct iommu_domain *domain,
|
||||
struct qcom_iommu_fault_ids *f_ids);
|
||||
|
||||
|
||||
extern int __init qcom_dma_iommu_generic_driver_init(void);
|
||||
extern void qcom_dma_iommu_generic_driver_exit(void);
|
||||
#endif /* __QCOM_IOMMU_UTIL_H */
|
||||
|
Loading…
Reference in New Issue
Block a user