summaryrefslogtreecommitdiff
path: root/hw/arm/smmuv3.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/arm/smmuv3.c')
-rw-r--r--hw/arm/smmuv3.c104
1 files changed, 100 insertions, 4 deletions
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index d581ada3d7..cfce013ac5 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -117,23 +117,119 @@ static MemTxResult queue_write(SMMUQueue *q, void *data)
return MEMTX_OK;
}
-void smmuv3_write_eventq(SMMUv3State *s, Evt *evt)
+static MemTxResult smmuv3_write_eventq(SMMUv3State *s, Evt *evt)
{
SMMUQueue *q = &s->eventq;
+ MemTxResult r;
if (!smmuv3_eventq_enabled(s)) {
- return;
+ return MEMTX_ERROR;
}
if (smmuv3_q_full(q)) {
- return;
+ return MEMTX_ERROR;
}
- queue_write(q, evt);
+ r = queue_write(q, evt);
+ if (r != MEMTX_OK) {
+ return r;
+ }
if (smmuv3_q_empty(q)) {
smmuv3_trigger_irq(s, SMMU_IRQ_EVTQ, 0);
}
+ return MEMTX_OK;
+}
+
+void smmuv3_record_event(SMMUv3State *s, SMMUEventInfo *info)
+{
+ Evt evt;
+ MemTxResult r;
+
+ if (!smmuv3_eventq_enabled(s)) {
+ return;
+ }
+
+ EVT_SET_TYPE(&evt, info->type);
+ EVT_SET_SID(&evt, info->sid);
+
+ switch (info->type) {
+ case SMMU_EVT_OK:
+ return;
+ case SMMU_EVT_F_UUT:
+ EVT_SET_SSID(&evt, info->u.f_uut.ssid);
+ EVT_SET_SSV(&evt, info->u.f_uut.ssv);
+ EVT_SET_ADDR(&evt, info->u.f_uut.addr);
+ EVT_SET_RNW(&evt, info->u.f_uut.rnw);
+ EVT_SET_PNU(&evt, info->u.f_uut.pnu);
+ EVT_SET_IND(&evt, info->u.f_uut.ind);
+ break;
+ case SMMU_EVT_C_BAD_STREAMID:
+ EVT_SET_SSID(&evt, info->u.c_bad_streamid.ssid);
+ EVT_SET_SSV(&evt, info->u.c_bad_streamid.ssv);
+ break;
+ case SMMU_EVT_F_STE_FETCH:
+ EVT_SET_SSID(&evt, info->u.f_ste_fetch.ssid);
+ EVT_SET_SSV(&evt, info->u.f_ste_fetch.ssv);
+ EVT_SET_ADDR(&evt, info->u.f_ste_fetch.addr);
+ break;
+ case SMMU_EVT_C_BAD_STE:
+ EVT_SET_SSID(&evt, info->u.c_bad_ste.ssid);
+ EVT_SET_SSV(&evt, info->u.c_bad_ste.ssv);
+ break;
+ case SMMU_EVT_F_STREAM_DISABLED:
+ break;
+ case SMMU_EVT_F_TRANS_FORBIDDEN:
+ EVT_SET_ADDR(&evt, info->u.f_transl_forbidden.addr);
+ EVT_SET_RNW(&evt, info->u.f_transl_forbidden.rnw);
+ break;
+ case SMMU_EVT_C_BAD_SUBSTREAMID:
+ EVT_SET_SSID(&evt, info->u.c_bad_substream.ssid);
+ break;
+ case SMMU_EVT_F_CD_FETCH:
+ EVT_SET_SSID(&evt, info->u.f_cd_fetch.ssid);
+ EVT_SET_SSV(&evt, info->u.f_cd_fetch.ssv);
+ EVT_SET_ADDR(&evt, info->u.f_cd_fetch.addr);
+ break;
+ case SMMU_EVT_C_BAD_CD:
+ EVT_SET_SSID(&evt, info->u.c_bad_cd.ssid);
+ EVT_SET_SSV(&evt, info->u.c_bad_cd.ssv);
+ break;
+ case SMMU_EVT_F_WALK_EABT:
+ case SMMU_EVT_F_TRANSLATION:
+ case SMMU_EVT_F_ADDR_SIZE:
+ case SMMU_EVT_F_ACCESS:
+ case SMMU_EVT_F_PERMISSION:
+ EVT_SET_STALL(&evt, info->u.f_walk_eabt.stall);
+ EVT_SET_STAG(&evt, info->u.f_walk_eabt.stag);
+ EVT_SET_SSID(&evt, info->u.f_walk_eabt.ssid);
+ EVT_SET_SSV(&evt, info->u.f_walk_eabt.ssv);
+ EVT_SET_S2(&evt, info->u.f_walk_eabt.s2);
+ EVT_SET_ADDR(&evt, info->u.f_walk_eabt.addr);
+ EVT_SET_RNW(&evt, info->u.f_walk_eabt.rnw);
+ EVT_SET_PNU(&evt, info->u.f_walk_eabt.pnu);
+ EVT_SET_IND(&evt, info->u.f_walk_eabt.ind);
+ EVT_SET_CLASS(&evt, info->u.f_walk_eabt.class);
+ EVT_SET_ADDR2(&evt, info->u.f_walk_eabt.addr2);
+ break;
+ case SMMU_EVT_F_CFG_CONFLICT:
+ EVT_SET_SSID(&evt, info->u.f_cfg_conflict.ssid);
+ EVT_SET_SSV(&evt, info->u.f_cfg_conflict.ssv);
+ break;
+ /* rest is not implemented */
+ case SMMU_EVT_F_BAD_ATS_TREQ:
+ case SMMU_EVT_F_TLB_CONFLICT:
+ case SMMU_EVT_E_PAGE_REQ:
+ default:
+ g_assert_not_reached();
+ }
+
+ trace_smmuv3_record_event(smmu_event_string(info->type), info->sid);
+ r = smmuv3_write_eventq(s, &evt);
+ if (r != MEMTX_OK) {
+ smmuv3_trigger_irq(s, SMMU_IRQ_GERROR, R_GERROR_EVENTQ_ABT_ERR_MASK);
+ }
+ info->recorded = true;
}
static void smmuv3_init_regs(SMMUv3State *s)