Commit 43ca55f5 authored by Pranjal Shrivastava's avatar Pranjal Shrivastava Committed by Will Deacon
Browse files

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: default avatarPranjal Shrivastava <praan@google.com>
Link: https://lore.kernel.org/r/20241203184906.2264528-2-praan@google.com


Signed-off-by: default avatarWill Deacon <will@kernel.org>
parent 42314738
Loading
Loading
Loading
Loading
+36 −19
Original line number Diff line number Diff line
@@ -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 @@ static int arm_smmu_handle_evt(struct arm_smmu_device *smmu, u64 *evt)
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]);

+18 −0
Original line number Diff line number Diff line
@@ -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;