iommu/arm-smmu-v3: Introduce struct arm_smmu_event

Introduce `struct arm_smmu_event` to represent event records.
Parse out relevant fields from raw event records for ease and
use the new `struct arm_smmu_event` instead.

Signed-off-by: Pranjal Shrivastava <praan@google.com>
Link: https://lore.kernel.org/r/20241203184906.2264528-2-praan@google.com
Signed-off-by: Will Deacon <will@kernel.org>
This commit is contained in:
Pranjal Shrivastava
2024-12-03 18:49:05 +00:00
committed by Will Deacon
parent 4231473890
commit 43ca55f555
2 changed files with 54 additions and 19 deletions

View File

@@ -1759,17 +1759,34 @@ arm_smmu_find_master(struct arm_smmu_device *smmu, u32 sid)
}
/* IRQ and event handlers */
static int arm_smmu_handle_evt(struct arm_smmu_device *smmu, u64 *evt)
static void arm_smmu_decode_event(u64 *raw, struct arm_smmu_event *event)
{
event->id = FIELD_GET(EVTQ_0_ID, raw[0]);
event->sid = FIELD_GET(EVTQ_0_SID, raw[0]);
event->ssv = FIELD_GET(EVTQ_0_SSV, raw[0]);
event->ssid = event->ssv ? FIELD_GET(EVTQ_0_SSID, raw[0]) : IOMMU_NO_PASID;
event->privileged = FIELD_GET(EVTQ_1_PnU, raw[1]);
event->instruction = FIELD_GET(EVTQ_1_InD, raw[1]);
event->s2 = FIELD_GET(EVTQ_1_S2, raw[1]);
event->read = FIELD_GET(EVTQ_1_RnW, raw[1]);
event->stag = FIELD_GET(EVTQ_1_STAG, raw[1]);
event->stall = FIELD_GET(EVTQ_1_STALL, raw[1]);
event->class = FIELD_GET(EVTQ_1_CLASS, raw[1]);
event->iova = FIELD_GET(EVTQ_2_ADDR, raw[2]);
event->ipa = raw[3] & EVTQ_3_IPA;
event->fetch_addr = raw[3] & EVTQ_3_FETCH_ADDR;
}
static int arm_smmu_handle_evt(struct arm_smmu_device *smmu,
struct arm_smmu_event *event)
{
int ret = 0;
u32 perm = 0;
struct arm_smmu_master *master;
bool ssid_valid = evt[0] & EVTQ_0_SSV;
u32 sid = FIELD_GET(EVTQ_0_SID, evt[0]);
struct iopf_fault fault_evt = { };
struct iommu_fault *flt = &fault_evt.fault;
switch (FIELD_GET(EVTQ_0_ID, evt[0])) {
switch (event->id) {
case EVT_ID_TRANSLATION_FAULT:
case EVT_ID_ADDR_SIZE_FAULT:
case EVT_ID_ACCESS_FAULT:
@@ -1779,35 +1796,35 @@ static int arm_smmu_handle_evt(struct arm_smmu_device *smmu, u64 *evt)
return -EOPNOTSUPP;
}
if (!(evt[1] & EVTQ_1_STALL))
if (!event->stall)
return -EOPNOTSUPP;
if (evt[1] & EVTQ_1_RnW)
if (event->read)
perm |= IOMMU_FAULT_PERM_READ;
else
perm |= IOMMU_FAULT_PERM_WRITE;
if (evt[1] & EVTQ_1_InD)
if (event->instruction)
perm |= IOMMU_FAULT_PERM_EXEC;
if (evt[1] & EVTQ_1_PnU)
if (event->privileged)
perm |= IOMMU_FAULT_PERM_PRIV;
flt->type = IOMMU_FAULT_PAGE_REQ;
flt->prm = (struct iommu_fault_page_request) {
.flags = IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE,
.grpid = FIELD_GET(EVTQ_1_STAG, evt[1]),
.grpid = event->stag,
.perm = perm,
.addr = FIELD_GET(EVTQ_2_ADDR, evt[2]),
.addr = event->iova,
};
if (ssid_valid) {
if (event->ssv) {
flt->prm.flags |= IOMMU_FAULT_PAGE_REQUEST_PASID_VALID;
flt->prm.pasid = FIELD_GET(EVTQ_0_SSID, evt[0]);
flt->prm.pasid = event->ssid;
}
mutex_lock(&smmu->streams_mutex);
master = arm_smmu_find_master(smmu, sid);
master = arm_smmu_find_master(smmu, event->sid);
if (!master) {
ret = -EINVAL;
goto out_unlock;
@@ -1822,23 +1839,23 @@ out_unlock:
static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
{
int i, ret;
u64 evt[EVTQ_ENT_DWORDS];
struct arm_smmu_event event = {0};
struct arm_smmu_device *smmu = dev;
struct arm_smmu_queue *q = &smmu->evtq.q;
struct arm_smmu_ll_queue *llq = &q->llq;
static DEFINE_RATELIMIT_STATE(rs, DEFAULT_RATELIMIT_INTERVAL,
DEFAULT_RATELIMIT_BURST);
u64 evt[EVTQ_ENT_DWORDS];
do {
while (!queue_remove_raw(q, evt)) {
u8 id = FIELD_GET(EVTQ_0_ID, evt[0]);
ret = arm_smmu_handle_evt(smmu, evt);
arm_smmu_decode_event(evt, &event);
ret = arm_smmu_handle_evt(smmu, &event);
if (!ret || !__ratelimit(&rs))
continue;
dev_info(smmu->dev, "event 0x%02x received:\n", id);
for (i = 0; i < ARRAY_SIZE(evt); ++i)
dev_info(smmu->dev, "event 0x%02x received:\n", event.id);
for (i = 0; i < EVTQ_ENT_DWORDS; ++i)
dev_info(smmu->dev, "\t0x%016llx\n",
(unsigned long long)evt[i]);

View File

@@ -470,6 +470,7 @@ static inline unsigned int arm_smmu_cdtab_l2_idx(unsigned int ssid)
#define EVTQ_1_TT_READ (1UL << 44)
#define EVTQ_2_ADDR GENMASK_ULL(63, 0)
#define EVTQ_3_IPA GENMASK_ULL(51, 12)
#define EVTQ_3_FETCH_ADDR GENMASK_ULL(51, 3)
/* PRI queue */
#define PRIQ_ENT_SZ_SHIFT 4
@@ -789,6 +790,23 @@ struct arm_smmu_stream {
struct rb_node node;
};
struct arm_smmu_event {
u8 stall : 1,
ssv : 1,
privileged : 1,
instruction : 1,
s2 : 1,
read : 1;
u8 id;
u8 class;
u16 stag;
u32 sid;
u32 ssid;
u64 iova;
u64 ipa;
u64 fetch_addr;
};
/* SMMU private data for each master */
struct arm_smmu_master {
struct arm_smmu_device *smmu;