mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
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:
committed by
Will Deacon
parent
4231473890
commit
43ca55f555
@@ -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]);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user