All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/2] iommu/arm-smmu-v3: Parse out event records
@ 2024-08-27 19:30 Pranjal Shrivastava
  2024-08-27 19:30 ` [PATCH v2 1/2] iommu/arm-smmu-v3: Print better events records Pranjal Shrivastava
  2024-08-27 19:30 ` [PATCH v2 2/2] iommu/arm-smmu-v3: Adopt arm_smmu_event in handlers Pranjal Shrivastava
  0 siblings, 2 replies; 19+ messages in thread
From: Pranjal Shrivastava @ 2024-08-27 19:30 UTC (permalink / raw)
  To: Joerg Roedel, Will Deacon, Robin Murphy
  Cc: Mostafa Saleh, iommu, Pranjal Shrivastava

Enhance the arm-smmu-v3 driver to parse out useful information from
event records into a structure for better event handling & logging.

v2
 * Addressed review comments
 * Introduced `struct arm_smmu_event` to hold relevant event fields
 * Broke out helper functions to populate & dump event info
 * Modified the event handler routines to use `struct arm_smmu_event`

v1
 https://lore.kernel.org/linux-iommu/20240816211722.1404070-1-praan@google.com/

Pranjal Shrivastava (2):
  iommu/arm-smmu-v3: Print better events records
  iommu/arm-smmu-v3: Adopt arm_smmu_event in handlers

 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 165 ++++++++++++++++----
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h |  27 ++++
 2 files changed, 162 insertions(+), 30 deletions(-)

-- 
2.46.0.295.g3b9ea8a38a-goog


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v2 1/2] iommu/arm-smmu-v3: Print better events records
  2024-08-27 19:30 [PATCH v2 0/2] iommu/arm-smmu-v3: Parse out event records Pranjal Shrivastava
@ 2024-08-27 19:30 ` Pranjal Shrivastava
  2024-08-29  6:36   ` Nicolin Chen
  2024-08-27 19:30 ` [PATCH v2 2/2] iommu/arm-smmu-v3: Adopt arm_smmu_event in handlers Pranjal Shrivastava
  1 sibling, 1 reply; 19+ messages in thread
From: Pranjal Shrivastava @ 2024-08-27 19:30 UTC (permalink / raw)
  To: Joerg Roedel, Will Deacon, Robin Murphy
  Cc: Mostafa Saleh, iommu, Pranjal Shrivastava, Daniel Mentz

Currently, the driver dumps the hex for a received event, improve this
by parsing out fields from an event for easier-to-read event records.

Signed-off-by: Daniel Mentz <danielmentz@google.com>
Signed-off-by: Pranjal Shrivastava <praan@google.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 128 ++++++++++++++++++--
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h |  27 +++++
 2 files changed, 148 insertions(+), 7 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 8a6cd0adfcf2..65160b52d944 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -83,6 +83,33 @@ static struct arm_smmu_option_prop arm_smmu_options[] = {
 	{ 0, NULL},
 };
 
+static const char * const evts[] = {
+	/* Bad config events */
+	[EVT_ID_BAD_SID_CONFIG] = "C_BAD_STREAMID",
+	[EVT_ID_BAD_STE_CONFIG] = "C_BAD_STE",
+	[EVT_ID_BAD_CD_CONFIG] = "C_BAD_CD",
+	[EVT_ID_BAD_SSID_CONFIG] = "C_BAD_SUBSTREAMID",
+	[EVT_ID_STREAM_DISABLED] = "F_STREAM_DISABLED",
+
+	/* Bad translation events */
+	[EVT_ID_TRANSLATION_FAULT] = "F_TRANSLATION",
+	[EVT_ID_ADDR_SIZE_FAULT] = "F_ADDR_SIZE",
+	[EVT_ID_ACCESS_FAULT] = "F_ACCESS",
+	[EVT_ID_PERMISSION_FAULT] = "F_PERMISSION",
+
+	/* Bad fetch events */
+	[EVT_ID_STE_FETCH_FAULT] = "F_STE_FETCH",
+	[EVT_ID_CD_FETCH_FAULT] = "F_CD_FETCH",
+	[EVT_ID_VMS_FETCH_FAULT] = "F_VMS_FAULT"
+};
+
+static const char * const class_str[] = {
+	[0] = "CD",
+	[1] = "TTD",
+	[2] = "IN",
+	[3] = "RES",
+};
+
 static int arm_smmu_domain_finalise(struct arm_smmu_domain *smmu_domain,
 				    struct arm_smmu_device *smmu, u32 flags);
 static int arm_smmu_alloc_cd_tables(struct arm_smmu_master *master);
@@ -1783,9 +1810,100 @@ static int arm_smmu_handle_evt(struct arm_smmu_device *smmu, u64 *evt)
 	return ret;
 }
 
+static void arm_smmu_get_evt_info(struct arm_smmu_device *smmu, u64 *evt,
+				  struct arm_smmu_event *event)
+{
+	/* Pick out the good stuff */
+	event->id = FIELD_GET(EVTQ_0_ID, evt[0]);
+	event->sid = FIELD_GET(EVTQ_0_SID, evt[0]);
+	event->ssid_valid = evt[0] & EVTQ_0_SSV;
+	event->ssid = event->ssid_valid ? FIELD_GET(EVTQ_0_SSID, evt[0]) : IOMMU_NO_PASID;
+	event->class = FIELD_GET(EVTQ_1_CLASS, evt[1]);
+	event->iova = FIELD_GET(EVTQ_2_ADDR, evt[2]);
+	event->ipa = FIELD_GET(EVTQ_3_IPA, evt[3]);
+	event->privileged = FIELD_GET(EVTQ_1_PnU, evt[1]);
+	event->instruction = FIELD_GET(EVTQ_1_InD, evt[1]);
+	event->stage = FIELD_GET(EVTQ_1_S2, evt[1]);
+	event->read = FIELD_GET(EVTQ_1_RnW, evt[1]);
+	event->raw = evt;
+
+	mutex_lock(&smmu->streams_mutex);
+	event->master = arm_smmu_find_master(smmu, event->sid);
+	mutex_unlock(&smmu->streams_mutex);
+
+	if (event->master)
+		event->master_name = dev_name(event->master->dev);
+	else
+		event->master_name = "(unassigned sid)";
+}
+
+static void arm_smmu_dump_xlation_fault(struct arm_smmu_device *smmu,
+					struct arm_smmu_event *event)
+{
+	dev_err(smmu->dev, "Fault: %s client %s sid 0x%08x.0x%05x:\n",
+			evts[event->id], event->master_name, event->sid, event->ssid);
+	dev_err(smmu->dev, "\tiova = %#llx ipa = %#llx (%s%s%s%s%s%s)\n", event->iova, event->ipa,
+		    event->privileged ? "Priv " : "Unpriv ",
+		    event->instruction ? "Inst " : "Data ",
+		    event->read ? "Read " : "Write ",
+		    event->stage ? "S2 " : "S1 ", class_str[event->class],
+		    ((event->id == EVT_ID_PERMISSION_FAULT) && (event->class == EVTQ_1_CLASS_TT)) ?
+		    (FIELD_GET(EVTQ_1_TT_READ, event->raw[1]) ? " TTD Read" : " TTD Write")
+		    : "");
+}
+
+static void arm_smmu_dump_fetch_fault(struct arm_smmu_device *smmu,
+				      struct arm_smmu_event *event)
+{
+	dev_err(smmu->dev, "Bad fetch: %s client %s sid 0x%08x.0x%05x: fetch addr = %#llx\n",
+			evts[event->id], event->master_name, event->sid, event->ssid, event->ipa);
+}
+
+static void arm_smmu_dump_raw_event(struct arm_smmu_device *smmu,
+				    struct arm_smmu_event *event)
+{
+	int i;
+
+	dev_err(smmu->dev, "event 0x%02x received: client %s:\n", event->id, event->master_name);
+	for (i = 0; i < EVTQ_ENT_DWORDS; ++i)
+		dev_err(smmu->dev, "\t0x%016llx\n",
+			 (unsigned long long)event->raw[i]);
+}
+
+static void arm_smmu_dump_event(struct arm_smmu_device *smmu,
+				 struct arm_smmu_event *event)
+{
+	switch (event->id) {
+	case EVT_ID_BAD_SID_CONFIG:
+	case EVT_ID_BAD_STE_CONFIG:
+	case EVT_ID_BAD_SSID_CONFIG:
+	case EVT_ID_BAD_CD_CONFIG:
+	case EVT_ID_STREAM_DISABLED:
+		dev_err(smmu->dev, "Bad smmu config - %s client %s sid 0x%08x.0x%05x\n",
+				evts[event->id], event->master_name, event->sid, event->ssid);
+		break;
+
+	case EVT_ID_TRANSLATION_FAULT:
+	case EVT_ID_ADDR_SIZE_FAULT:
+	case EVT_ID_ACCESS_FAULT:
+	case EVT_ID_PERMISSION_FAULT:
+		arm_smmu_dump_xlation_fault(smmu, event);
+		break;
+
+	case EVT_ID_STE_FETCH_FAULT:
+	case EVT_ID_CD_FETCH_FAULT:
+	case EVT_ID_VMS_FETCH_FAULT:
+		arm_smmu_dump_fetch_fault(smmu, event);
+		break;
+	}
+
+	arm_smmu_dump_raw_event(smmu, event);
+}
+
 static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
 {
-	int i, ret;
+	int ret;
+	struct arm_smmu_event event;
 	struct arm_smmu_device *smmu = dev;
 	struct arm_smmu_queue *q = &smmu->evtq.q;
 	struct arm_smmu_ll_queue *llq = &q->llq;
@@ -1795,17 +1913,13 @@ static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
 
 	do {
 		while (!queue_remove_raw(q, evt)) {
-			u8 id = FIELD_GET(EVTQ_0_ID, evt[0]);
 
+			arm_smmu_get_evt_info(smmu, evt, &event);
 			ret = arm_smmu_handle_evt(smmu, evt);
 			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, "\t0x%016llx\n",
-					 (unsigned long long)evt[i]);
-
+			arm_smmu_dump_event(smmu, &event);
 			cond_resched();
 		}
 
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index 14bca41a981b..6728e306e4da 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -399,10 +399,19 @@ struct arm_smmu_cd {
 
 #define EVTQ_0_ID			GENMASK_ULL(7, 0)
 
+/* Events */
+#define EVT_ID_BAD_SID_CONFIG		0x02
+#define EVT_ID_STE_FETCH_FAULT		0x03
+#define EVT_ID_BAD_STE_CONFIG		0x04
+#define EVT_ID_STREAM_DISABLED		0x06
+#define EVT_ID_BAD_SSID_CONFIG		0x08
+#define EVT_ID_CD_FETCH_FAULT		0x09
+#define EVT_ID_BAD_CD_CONFIG		0x0a
 #define EVT_ID_TRANSLATION_FAULT	0x10
 #define EVT_ID_ADDR_SIZE_FAULT		0x11
 #define EVT_ID_ACCESS_FAULT		0x12
 #define EVT_ID_PERMISSION_FAULT		0x13
+#define EVT_ID_VMS_FETCH_FAULT		0x25
 
 #define EVTQ_0_SSV			(1UL << 11)
 #define EVTQ_0_SSID			GENMASK_ULL(31, 12)
@@ -414,6 +423,7 @@ struct arm_smmu_cd {
 #define EVTQ_1_RnW			(1UL << 35)
 #define EVTQ_1_S2			(1UL << 39)
 #define EVTQ_1_CLASS			GENMASK_ULL(41, 40)
+#define EVTQ_1_CLASS_TT			0x1
 #define EVTQ_1_TT_READ			(1UL << 44)
 #define EVTQ_2_ADDR			GENMASK_ULL(63, 0)
 #define EVTQ_3_IPA			GENMASK_ULL(51, 12)
@@ -702,6 +712,23 @@ struct arm_smmu_stream {
 	struct rb_node			node;
 };
 
+struct arm_smmu_event {
+	struct arm_smmu_master		*master;
+	const char			*master_name;
+	u8				id;
+	u8				class;
+	u32				sid;
+	u32				ssid;
+	u64				iova;
+	u64				ipa;
+	u64				*raw;
+	bool				ssid_valid;
+	bool				privileged;
+	bool				instruction;
+	bool				stage;
+	bool				read;
+};
+
 /* SMMU private data for each master */
 struct arm_smmu_master {
 	struct arm_smmu_device		*smmu;
-- 
2.46.0.295.g3b9ea8a38a-goog


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* [PATCH v2 2/2] iommu/arm-smmu-v3: Adopt arm_smmu_event in handlers
  2024-08-27 19:30 [PATCH v2 0/2] iommu/arm-smmu-v3: Parse out event records Pranjal Shrivastava
  2024-08-27 19:30 ` [PATCH v2 1/2] iommu/arm-smmu-v3: Print better events records Pranjal Shrivastava
@ 2024-08-27 19:30 ` Pranjal Shrivastava
  2024-08-29  5:20   ` Nicolin Chen
  1 sibling, 1 reply; 19+ messages in thread
From: Pranjal Shrivastava @ 2024-08-27 19:30 UTC (permalink / raw)
  To: Joerg Roedel, Will Deacon, Robin Murphy
  Cc: Mostafa Saleh, iommu, Pranjal Shrivastava

Modify the event handler routines to leverage `struct arm_smmu_event`

Signed-off-by: Pranjal Shrivastava <praan@google.com>
---
 drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 39 ++++++++-------------
 1 file changed, 15 insertions(+), 24 deletions(-)

diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 65160b52d944..e33f73079a2a 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -1746,17 +1746,14 @@ 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 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:
@@ -1767,46 +1764,40 @@ static int arm_smmu_handle_evt(struct arm_smmu_device *smmu, u64 *evt)
 	}
 
 	/* Stage-2 is always pinned at the moment */
-	if (evt[1] & EVTQ_1_S2)
+	if (event->stage)
 		return -EFAULT;
 
-	if (!(evt[1] & EVTQ_1_STALL))
+	if (!(event->raw[1] & EVTQ_1_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 = FIELD_GET(EVTQ_1_STAG, event->raw[1]),
 		.perm = perm,
-		.addr = FIELD_GET(EVTQ_2_ADDR, evt[2]),
+		.addr = event->iova,
 	};
 
-	if (ssid_valid) {
+	if (event->ssid_valid) {
 		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);
-	if (!master) {
-		ret = -EINVAL;
-		goto out_unlock;
-	}
+	if (!event->master)
+		return -EINVAL;
 
-	ret = iommu_report_device_fault(master->dev, &fault_evt);
-out_unlock:
-	mutex_unlock(&smmu->streams_mutex);
+	ret = iommu_report_device_fault(event->master->dev, &fault_evt);
 	return ret;
 }
 
@@ -1915,7 +1906,7 @@ static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
 		while (!queue_remove_raw(q, evt)) {
 
 			arm_smmu_get_evt_info(smmu, evt, &event);
-			ret = arm_smmu_handle_evt(smmu, evt);
+			ret = arm_smmu_handle_evt(smmu, &event);
 			if (!ret || !__ratelimit(&rs))
 				continue;
 
-- 
2.46.0.295.g3b9ea8a38a-goog


^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 2/2] iommu/arm-smmu-v3: Adopt arm_smmu_event in handlers
  2024-08-27 19:30 ` [PATCH v2 2/2] iommu/arm-smmu-v3: Adopt arm_smmu_event in handlers Pranjal Shrivastava
@ 2024-08-29  5:20   ` Nicolin Chen
  2024-08-30  0:06     ` Pranjal Shrivastava
  0 siblings, 1 reply; 19+ messages in thread
From: Nicolin Chen @ 2024-08-29  5:20 UTC (permalink / raw)
  To: Pranjal Shrivastava
  Cc: Joerg Roedel, Will Deacon, Robin Murphy, Mostafa Saleh,
	iommu@lists.linux.dev

Hi Pranjal,

On Tue, Aug 27, 2024 at 12:30:26PM -0700, Pranjal Shrivastava wrote:

>         /* Stage-2 is always pinned at the moment */
> -       if (evt[1] & EVTQ_1_S2)
> +       if (event->stage)
>                 return -EFAULT;

Should it be named to "s2" v.s stage?

> -       mutex_lock(&smmu->streams_mutex);
> -       master = arm_smmu_find_master(smmu, sid);
> -       if (!master) {
> -               ret = -EINVAL;
> -               goto out_unlock;
> -       }
> +       if (!event->master)
> +               return -EINVAL;
> 
> -       ret = iommu_report_device_fault(master->dev, &fault_evt);
> -out_unlock:
> -       mutex_unlock(&smmu->streams_mutex);
> +       ret = iommu_report_device_fault(event->master->dev, &fault_evt);

The iommu_report_device_fault(master->dev) call lost its mutex
lock. I wonder if it could be unsafe to continue with that dev
pointer.

Nicolin 

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 1/2] iommu/arm-smmu-v3: Print better events records
  2024-08-27 19:30 ` [PATCH v2 1/2] iommu/arm-smmu-v3: Print better events records Pranjal Shrivastava
@ 2024-08-29  6:36   ` Nicolin Chen
  2024-08-29 23:54     ` Pranjal Shrivastava
  0 siblings, 1 reply; 19+ messages in thread
From: Nicolin Chen @ 2024-08-29  6:36 UTC (permalink / raw)
  To: Pranjal Shrivastava
  Cc: Joerg Roedel, Will Deacon, Robin Murphy, Mostafa Saleh,
	iommu@lists.linux.dev, Daniel Mentz

Hi Pranjal,

The prints would be very helpful for debugging. Thanks for the
patch!

I have some personally thoughts here, so hopefully we can make
it cleaner and more readable.

On Tue, Aug 27, 2024 at 12:30:25PM -0700, Pranjal Shrivastava wrote:

> +static const char * const evts[] = {

s/evts/event_str

> +       /* Bad config events */
> +       [EVT_ID_BAD_SID_CONFIG] = "C_BAD_STREAMID",
> +       [EVT_ID_BAD_STE_CONFIG] = "C_BAD_STE",
> +       [EVT_ID_BAD_CD_CONFIG] = "C_BAD_CD",
> +       [EVT_ID_BAD_SSID_CONFIG] = "C_BAD_SUBSTREAMID",
> +       [EVT_ID_STREAM_DISABLED] = "F_STREAM_DISABLED",
> +
> +       /* Bad translation events */
> +       [EVT_ID_TRANSLATION_FAULT] = "F_TRANSLATION",
> +       [EVT_ID_ADDR_SIZE_FAULT] = "F_ADDR_SIZE",
> +       [EVT_ID_ACCESS_FAULT] = "F_ACCESS",
> +       [EVT_ID_PERMISSION_FAULT] = "F_PERMISSION",
> +
> +       /* Bad fetch events */
> +       [EVT_ID_STE_FETCH_FAULT] = "F_STE_FETCH",
> +       [EVT_ID_CD_FETCH_FAULT] = "F_CD_FETCH",
> +       [EVT_ID_VMS_FETCH_FAULT] = "F_VMS_FAULT"
> +};
> +
> +static const char * const class_str[] = {
> +       [0] = "CD",
> +       [1] = "TTD",
> +       [2] = "IN",
> +       [3] = "RES",
> +};

Unlike the event IDs, these class code names are still uneasy to
read. Though it'd result in a print-format change, yet could we
simply dump full strings instead?

> +static void arm_smmu_get_evt_info(struct arm_smmu_device *smmu, u64 *evt,
> +                                 struct arm_smmu_event *event)
> +{
> +       /* Pick out the good stuff */
> +       event->id = FIELD_GET(EVTQ_0_ID, evt[0]);
> +       event->sid = FIELD_GET(EVTQ_0_SID, evt[0]);
> +       event->ssid_valid = evt[0] & EVTQ_0_SSV;
> +       event->ssid = event->ssid_valid ? FIELD_GET(EVTQ_0_SSID, evt[0]) : IOMMU_NO_PASID;
> +       event->class = FIELD_GET(EVTQ_1_CLASS, evt[1]);
> +       event->iova = FIELD_GET(EVTQ_2_ADDR, evt[2]);
> +       event->ipa = FIELD_GET(EVTQ_3_IPA, evt[3]);
> +       event->privileged = FIELD_GET(EVTQ_1_PnU, evt[1]);
> +       event->instruction = FIELD_GET(EVTQ_1_InD, evt[1]);
> +       event->stage = FIELD_GET(EVTQ_1_S2, evt[1]);
> +       event->read = FIELD_GET(EVTQ_1_RnW, evt[1]);
> +       event->raw = evt;

Maybe we could define struct arm_smmu_event in this way:

+struct arm_smmu_event {
+	union {
+		u64 evt[4];
+		struct {
+			/* Bit 0:63 */
+			u64 id : 8;
+			u64 _res0 : 3;
+			u64 ssv : 1;
+			u64 ssid : 20;
+			u64 sid : 32;
+			/* Bit 64:127 */
+			u64 stag : 16;
+			u64 _res1 : 15;
+			u64 stall : 1;
+			u64 _res2 : 1;
+			u64 pnu : 1;
+			u64 ind : 1;
+			u64 rnw : 1;
+			u64 _res3 : 2;
+			u64 nsipa : 1;
+			u64 s2 : 1;
+			u64 class : 2;
+			u64 _res4 : 6;
+			u64 impl_def : 16;
+			/* Bit 128:191 */
+			u64 inputaddr;
+			/* Bit 192:255 */
+			u64 _res5 : 12;
+			u64 ipa : 40;
+			u64 _res6 : 12;
+		} f_trans;
+		/* FIXME Add other event structs */
+	};
+};

Then, event would be just:
+		struct arm_smmu_event *event = (struct arm_smmu_event *)evt;

Not sure if Will would like this though...

> +
> +       mutex_lock(&smmu->streams_mutex);
> +       event->master = arm_smmu_find_master(smmu, event->sid);
> +       mutex_unlock(&smmu->streams_mutex);

Same as I pointed out at the other patch, "master" is unprotected
after the unlock. It can unlikely-yet-still-possibly race against
arm_smmu_release_device.

> +static void arm_smmu_dump_xlation_fault(struct arm_smmu_device *smmu,
> +                                       struct arm_smmu_event *event)
> +{
> +       dev_err(smmu->dev, "Fault: %s client %s sid 0x%08x.0x%05x:\n",

"client" doesn't seem to be used anywhere in this driver, I would:
s/client/master

And it'd feel clearer to have an "ssid". And perhaps adding commas
to separate them too.

> +                       evts[event->id], event->master_name, event->sid, event->ssid);
> +       dev_err(smmu->dev, "\tiova = %#llx ipa = %#llx (%s%s%s%s%s%s)\n", event->iova, event->ipa,
> +                   event->privileged ? "Priv " : "Unpriv ",
> +                   event->instruction ? "Inst " : "Data ",
> +                   event->read ? "Read " : "Write ",
> +                   event->stage ? "S2 " : "S1 ", class_str[event->class],
> +                   ((event->id == EVT_ID_PERMISSION_FAULT) && (event->class == EVTQ_1_CLASS_TT)) ?
> +                   (FIELD_GET(EVTQ_1_TT_READ, event->raw[1]) ? " TTD Read" : " TTD Write")
> +                   : "");

Indentation should follow the existing printk() in this driver. And
those ternary operators at the last field(s?) are hard to ready..

> +static void arm_smmu_dump_fetch_fault(struct arm_smmu_device *smmu,
> +                                     struct arm_smmu_event *event)
> +{
> +       dev_err(smmu->dev, "Bad fetch: %s client %s sid 0x%08x.0x%05x: fetch addr = %#llx\n",
> +                       evts[event->id], event->master_name, event->sid, event->ssid, event->ipa);

Actually, the "Fault", "Bad fetch", and "Bad smmu config" doesn't
feel very necessary, since we prints the event string already.

> +}
> +
> +static void arm_smmu_dump_raw_event(struct arm_smmu_device *smmu,
> +                                   struct arm_smmu_event *event)
> +{
> +       int i;
> +
> +       dev_err(smmu->dev, "event 0x%02x received: client %s:\n", event->id, event->master_name);

Looks like it would print another title that's sorta duplicated to
other dump functions yet less informative?

> +       for (i = 0; i < EVTQ_ENT_DWORDS; ++i)
> +               dev_err(smmu->dev, "\t0x%016llx\n",
> +                        (unsigned long long)event->raw[i]);
> +}
> +
> +static void arm_smmu_dump_event(struct arm_smmu_device *smmu,
> +                                struct arm_smmu_event *event)
> +{
> +       switch (event->id) {
> +       case EVT_ID_BAD_SID_CONFIG:
> +       case EVT_ID_BAD_STE_CONFIG:
> +       case EVT_ID_BAD_SSID_CONFIG:
> +       case EVT_ID_BAD_CD_CONFIG:
> +       case EVT_ID_STREAM_DISABLED:
> +               dev_err(smmu->dev, "Bad smmu config - %s client %s sid 0x%08x.0x%05x\n",
> +                               evts[event->id], event->master_name, event->sid, event->ssid);
> +               break;
> +
> +       case EVT_ID_TRANSLATION_FAULT:
> +       case EVT_ID_ADDR_SIZE_FAULT:
> +       case EVT_ID_ACCESS_FAULT:
> +       case EVT_ID_PERMISSION_FAULT:
> +               arm_smmu_dump_xlation_fault(smmu, event);
> +               break;
> +
> +       case EVT_ID_STE_FETCH_FAULT:
> +       case EVT_ID_CD_FETCH_FAULT:
> +       case EVT_ID_VMS_FETCH_FAULT:
> +               arm_smmu_dump_fetch_fault(smmu, event);
> +               break;
> +       }
> +
> +       arm_smmu_dump_raw_event(smmu, event);

I wonder if something like this would be cleaner:

	...
	char title[256];
	char addrs[256];
	char other[256];
	int i;

	switch () {
	case xxxx:
		/* If duplicated between cases, put them into helpers */
		snprintf(title, 256, "%s: Master %s, sid 0x%08x, ssid 0x%05x\n",
			 event_str(event->id], dev_name(master->dev),
			 event->sid, event->ssid);
		snprintf(addrs, 256, .....);
		snprintf(other, 256, .....);
		break;
	...
	default:
		/* snprintf raw title */
		break;
	}
	if (strlen(title))
		dev_err(smmu->dev, "%s", title);
	if (strlen(addrs))
		dev_err(smmu->dev, "%s", addrs);
	if (strlen(other))
		dev_err(smmu->dev, "%s", other);
	for (i = 0; i < EVTQ_ENT_DWORDS; ++i)
		dev_err(smmu->dev, "\t0x%016llx\n", event->evt[i]);
	...

Thanks
Nicolin

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 1/2] iommu/arm-smmu-v3: Print better events records
  2024-08-29  6:36   ` Nicolin Chen
@ 2024-08-29 23:54     ` Pranjal Shrivastava
  2024-08-30  1:45       ` Nicolin Chen
  2024-11-04 16:40       ` Daniel Mentz
  0 siblings, 2 replies; 19+ messages in thread
From: Pranjal Shrivastava @ 2024-08-29 23:54 UTC (permalink / raw)
  To: Nicolin Chen
  Cc: Joerg Roedel, Will Deacon, Robin Murphy, Mostafa Saleh,
	iommu@lists.linux.dev, Daniel Mentz

On Wed, Aug 28, 2024 at 11:36:02PM -0700, Nicolin Chen wrote:
Hi Nicolin,
> Hi Pranjal,
> 
> The prints would be very helpful for debugging. Thanks for the
> patch!
> 
> I have some personally thoughts here, so hopefully we can make
> it cleaner and more readable.
> 
> On Tue, Aug 27, 2024 at 12:30:25PM -0700, Pranjal Shrivastava wrote:
> 
> > +static const char * const evts[] = {
> 
> s/evts/event_str
> 

Ack, would change that in the follow up patch.

> > +       /* Bad config events */
> > +       [EVT_ID_BAD_SID_CONFIG] = "C_BAD_STREAMID",
> > +       [EVT_ID_BAD_STE_CONFIG] = "C_BAD_STE",
> > +       [EVT_ID_BAD_CD_CONFIG] = "C_BAD_CD",
> > +       [EVT_ID_BAD_SSID_CONFIG] = "C_BAD_SUBSTREAMID",
> > +       [EVT_ID_STREAM_DISABLED] = "F_STREAM_DISABLED",
> > +
> > +       /* Bad translation events */
> > +       [EVT_ID_TRANSLATION_FAULT] = "F_TRANSLATION",
> > +       [EVT_ID_ADDR_SIZE_FAULT] = "F_ADDR_SIZE",
> > +       [EVT_ID_ACCESS_FAULT] = "F_ACCESS",
> > +       [EVT_ID_PERMISSION_FAULT] = "F_PERMISSION",
> > +
> > +       /* Bad fetch events */
> > +       [EVT_ID_STE_FETCH_FAULT] = "F_STE_FETCH",
> > +       [EVT_ID_CD_FETCH_FAULT] = "F_CD_FETCH",
> > +       [EVT_ID_VMS_FETCH_FAULT] = "F_VMS_FAULT"
> > +};
> > +
> > +static const char * const class_str[] = {
> > +       [0] = "CD",
> > +       [1] = "TTD",
> > +       [2] = "IN",
> > +       [3] = "RES",
> > +};
> 
> Unlike the event IDs, these class code names are still uneasy to
> read. Though it'd result in a print-format change, yet could we
> simply dump full strings instead?
> 

By "full strings" do you mean "CD => CD Fetch" as mentioned in the spec?
Or do you mean "Context Descriptor", "Translation Table Desc" etc.? I'm
afraid that the latter would make the printed string much longer.
Although, I wouldn't mind doing that if we have consensus.

> > +static void arm_smmu_get_evt_info(struct arm_smmu_device *smmu, u64 *evt,
> > +                                 struct arm_smmu_event *event)
> > +{
> > +       /* Pick out the good stuff */
> > +       event->id = FIELD_GET(EVTQ_0_ID, evt[0]);
> > +       event->sid = FIELD_GET(EVTQ_0_SID, evt[0]);
> > +       event->ssid_valid = evt[0] & EVTQ_0_SSV;
> > +       event->ssid = event->ssid_valid ? FIELD_GET(EVTQ_0_SSID, evt[0]) : IOMMU_NO_PASID;
> > +       event->class = FIELD_GET(EVTQ_1_CLASS, evt[1]);
> > +       event->iova = FIELD_GET(EVTQ_2_ADDR, evt[2]);
> > +       event->ipa = FIELD_GET(EVTQ_3_IPA, evt[3]);
> > +       event->privileged = FIELD_GET(EVTQ_1_PnU, evt[1]);
> > +       event->instruction = FIELD_GET(EVTQ_1_InD, evt[1]);
> > +       event->stage = FIELD_GET(EVTQ_1_S2, evt[1]);
> > +       event->read = FIELD_GET(EVTQ_1_RnW, evt[1]);
> > +       event->raw = evt;
> 
> Maybe we could define struct arm_smmu_event in this way:
> 
> +struct arm_smmu_event {
> +	union {
> +		u64 evt[4];
> +		struct {
> +			/* Bit 0:63 */
> +			u64 id : 8;
> +			u64 _res0 : 3;
> +			u64 ssv : 1;
> +			u64 ssid : 20;
> +			u64 sid : 32;
> +			/* Bit 64:127 */
> +			u64 stag : 16;
> +			u64 _res1 : 15;
> +			u64 stall : 1;
> +			u64 _res2 : 1;
> +			u64 pnu : 1;
> +			u64 ind : 1;
> +			u64 rnw : 1;
> +			u64 _res3 : 2;
> +			u64 nsipa : 1;
> +			u64 s2 : 1;
> +			u64 class : 2;
> +			u64 _res4 : 6;
> +			u64 impl_def : 16;
> +			/* Bit 128:191 */
> +			u64 inputaddr;
> +			/* Bit 192:255 */
> +			u64 _res5 : 12;
> +			u64 ipa : 40;
> +			u64 _res6 : 12;
> +		} f_trans;
> +		/* FIXME Add other event structs */
> +	};
> +};
> 
> Then, event would be just:
> +		struct arm_smmu_event *event = (struct arm_smmu_event *)evt;
> 
> Not sure if Will would like this though...

Yea, I thought about this too but I felt that it'd bloat up the code
for every new event that's introduced. Also, the printing would become
more complicated as we'd have to log different fields for different
events. Additionally, I don't see that many unions being defined
elsewhere in the kernel.

...and, I'm not a fan of too many unions (personally) :) 

> 
> > +
> > +       mutex_lock(&smmu->streams_mutex);
> > +       event->master = arm_smmu_find_master(smmu, event->sid);
> > +       mutex_unlock(&smmu->streams_mutex);
> 
> Same as I pointed out at the other patch, "master" is unprotected
> after the unlock. It can unlikely-yet-still-possibly race against
> arm_smmu_release_device.
>

Hmm.. are you suggesting that the `master` could've been removed by the
arm_smmu_release_device while we access it in an event handler?

As in, something like the following situation:

1. The evtq_thread gets scheduled
2. arm_smmu_release_device removes the `master` & its streams
3. In the `handle_evt` we dereference `master` which has been `kfree`ed
   (also, we don't return -EINVAL like we ideally should)

In that case, I think I should add back the `arm_smmu_find_master` to
the `arm_smmu_handle_evt` along with the locks. Nice catch! :)


> > +static void arm_smmu_dump_xlation_fault(struct arm_smmu_device *smmu,
> > +                                       struct arm_smmu_event *event)
> > +{
> > +       dev_err(smmu->dev, "Fault: %s client %s sid 0x%08x.0x%05x:\n",
> 
> "client" doesn't seem to be used anywhere in this driver, I would:
> s/client/master
> 

Ack, would change this to "master".

> And it'd feel clearer to have an "ssid". And perhaps adding commas
> to separate them too.

I referred to the log in `arm_smmu_handle_ppr` for the sid.ssid format.
If we'd prefer a separate "ssid", should we change the one in ppr too?
LMK, what you and Will think about that?

> 
> > +                       evts[event->id], event->master_name, event->sid, event->ssid);
> > +       dev_err(smmu->dev, "\tiova = %#llx ipa = %#llx (%s%s%s%s%s%s)\n", event->iova, event->ipa,
> > +                   event->privileged ? "Priv " : "Unpriv ",
> > +                   event->instruction ? "Inst " : "Data ",
> > +                   event->read ? "Read " : "Write ",
> > +                   event->stage ? "S2 " : "S1 ", class_str[event->class],
> > +                   ((event->id == EVT_ID_PERMISSION_FAULT) && (event->class == EVTQ_1_CLASS_TT)) ?
> > +                   (FIELD_GET(EVTQ_1_TT_READ, event->raw[1]) ? " TTD Read" : " TTD Write")
> > +                   : "");
> 
> Indentation should follow the existing printk() in this driver. And

I'm sorry but I'm not sure if I understand what is meant by "the
existing printk indentation in this driver", do you mean aligning the
next line with the opening brace? For example:

	dev_err(smmu->dev,
		"failed to allocate queue (0x%zx
		bytes) for %s\n",
		qsz, name);

> those ternary operators at the last field(s?) are hard to ready..
>

Hmm, I wanted the last fields to be printed only when the fault was
F_PERMISSION, in the same log. Any suggestions on what might make it
easier to read? Some helpful comments around it? Something else?

I just noticed that I've missed the `STAG` field in the in xlation_fault
dump, would add that too in the next version of this patch.

> > +static void arm_smmu_dump_fetch_fault(struct arm_smmu_device *smmu,
> > +                                     struct arm_smmu_event *event)
> > +{
> > +       dev_err(smmu->dev, "Bad fetch: %s client %s sid 0x%08x.0x%05x: fetch addr = %#llx\n",
> > +                       evts[event->id], event->master_name, event->sid, event->ssid, event->ipa);
> 
> Actually, the "Fault", "Bad fetch", and "Bad smmu config" doesn't
> feel very necessary, since we prints the event string already.
> 

That makes sense, I'll remove those in a follow up patch.
Although, I guess we should still say "fault" somewhere to hint folks
without arm-smmu-v3 knowledge that the event wasn't normal operation.

LMK what you think? I've had a few interactions where clients tend to
ignore the current "event received" dump considering that to be a part
of normal SMMU operation.

> > +}
> > +
> > +static void arm_smmu_dump_raw_event(struct arm_smmu_device *smmu,
> > +                                   struct arm_smmu_event *event)
> > +{
> > +       int i;
> > +
> > +       dev_err(smmu->dev, "event 0x%02x received: client %s:\n", event->id, event->master_name);
> 
> Looks like it would print another title that's sorta duplicated to
> other dump functions yet less informative?
>

Yea, I didn't wanna break backward compatibility, people might have
tools to parse out the existing dump, lol!

On a serious note, I believe it'd be better to print this as some
implmentations might have some "IMPLEMENTATION DEFINED" fields which
people might be interested to look at.

Although, we can dump the raw event only in the `default` case, i.e.
when we don't have a dumper function for that particular event ID but
that might still avoid printing the IMPL_DEFINED fields in fetch faults

> > +       for (i = 0; i < EVTQ_ENT_DWORDS; ++i)
> > +               dev_err(smmu->dev, "\t0x%016llx\n",
> > +                        (unsigned long long)event->raw[i]);
> > +}
> > +
> > +static void arm_smmu_dump_event(struct arm_smmu_device *smmu,
> > +                                struct arm_smmu_event *event)
> > +{
> > +       switch (event->id) {
> > +       case EVT_ID_BAD_SID_CONFIG:
> > +       case EVT_ID_BAD_STE_CONFIG:
> > +       case EVT_ID_BAD_SSID_CONFIG:
> > +       case EVT_ID_BAD_CD_CONFIG:
> > +       case EVT_ID_STREAM_DISABLED:
> > +               dev_err(smmu->dev, "Bad smmu config - %s client %s sid 0x%08x.0x%05x\n",
> > +                               evts[event->id], event->master_name, event->sid, event->ssid);
> > +               break;
> > +
> > +       case EVT_ID_TRANSLATION_FAULT:
> > +       case EVT_ID_ADDR_SIZE_FAULT:
> > +       case EVT_ID_ACCESS_FAULT:
> > +       case EVT_ID_PERMISSION_FAULT:
> > +               arm_smmu_dump_xlation_fault(smmu, event);
> > +               break;
> > +
> > +       case EVT_ID_STE_FETCH_FAULT:
> > +       case EVT_ID_CD_FETCH_FAULT:
> > +       case EVT_ID_VMS_FETCH_FAULT:
> > +               arm_smmu_dump_fetch_fault(smmu, event);
> > +               break;
> > +       }
> > +
> > +       arm_smmu_dump_raw_event(smmu, event);
> 
> I wonder if something like this would be cleaner:
> 
> 	...
> 	char title[256];
> 	char addrs[256];
> 	char other[256];
> 	int i;
> 
> 	switch () {
> 	case xxxx:
> 		/* If duplicated between cases, put them into helpers */
> 		snprintf(title, 256, "%s: Master %s, sid 0x%08x, ssid 0x%05x\n",
> 			 event_str(event->id], dev_name(master->dev),
> 			 event->sid, event->ssid);
> 		snprintf(addrs, 256, .....);
> 		snprintf(other, 256, .....);
> 		break;
> 	...
> 	default:
> 		/* snprintf raw title */
> 		break;
> 	}
> 	if (strlen(title))
> 		dev_err(smmu->dev, "%s", title);
> 	if (strlen(addrs))
> 		dev_err(smmu->dev, "%s", addrs);
> 	if (strlen(other))
> 		dev_err(smmu->dev, "%s", other);
> 	for (i = 0; i < EVTQ_ENT_DWORDS; ++i)
> 		dev_err(smmu->dev, "\t0x%016llx\n", event->evt[i]);
> 	...
> 

I thought about something similar as well, but then referred to Robin's
comments on [1]. Also, printing strings in 3 different `dev_err` logs
could result in interruptions from other logs in dmesg, I'd prefer to
see the entire log in a single `dev_err` for ease. Although, I think we
should be able to do something like the following to achieve that:
	...

	dev_err(%s %s %s, strlen(title) ? title : ""
		strlen(addrs) ? addrs : ""
		strlen(other) ? other : ""

	for (i = 0; i < EVTQ_ENT_DWORDS; ++i)
		dev_err(smmu->dev, "\t0x%016llx\n", event->evt[i]);

	...

It does look cleaner to me as well. I'd wait for what other have to say.

> Thanks
> Nicolin

[1]
https://lore.kernel.org/linux-arm-kernel/07c7426c-7d01-4160-a344-1857b738e9c4@arm.com/T/#m9c38920897999c56f0b135556133cae38f40b754a

Thanks,
Pranjal

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 2/2] iommu/arm-smmu-v3: Adopt arm_smmu_event in handlers
  2024-08-29  5:20   ` Nicolin Chen
@ 2024-08-30  0:06     ` Pranjal Shrivastava
  0 siblings, 0 replies; 19+ messages in thread
From: Pranjal Shrivastava @ 2024-08-30  0:06 UTC (permalink / raw)
  To: Nicolin Chen
  Cc: Joerg Roedel, Will Deacon, Robin Murphy, Mostafa Saleh,
	iommu@lists.linux.dev

On Wed, Aug 28, 2024 at 10:20:02PM -0700, Nicolin Chen wrote:
> Hi Pranjal,
> 
> On Tue, Aug 27, 2024 at 12:30:26PM -0700, Pranjal Shrivastava wrote:
> 
> >         /* Stage-2 is always pinned at the moment */
> > -       if (evt[1] & EVTQ_1_S2)
> > +       if (event->stage)
> >                 return -EFAULT;
> 
> Should it be named to "s2" v.s stage?

Sure, will rename it with the next version.

> 
> > -       mutex_lock(&smmu->streams_mutex);
> > -       master = arm_smmu_find_master(smmu, sid);
> > -       if (!master) {
> > -               ret = -EINVAL;
> > -               goto out_unlock;
> > -       }
> > +       if (!event->master)
> > +               return -EINVAL;
> > 
> > -       ret = iommu_report_device_fault(master->dev, &fault_evt);
> > -out_unlock:
> > -       mutex_unlock(&smmu->streams_mutex);
> > +       ret = iommu_report_device_fault(event->master->dev, &fault_evt);
> 
> The iommu_report_device_fault(master->dev) call lost its mutex
> lock. I wonder if it could be unsafe to continue with that dev
> pointer.

Ack, I agree, responded with [Patch 1/2] in detail.

In summary, we need to avoid the following situation:

1. The evtq_thread gets scheduled
2. arm_smmu_release_device removes the `master` & its streams
3. In the `handle_evt` we dereference `master` which has been `kfree`ed
   (also, we don't return -EINVAL in that case as we ideally should)

I'll add back the `arm_smmu_find_master` in the the `arm_smmu_handle_evt`
along with the locks. Nice catch! :)

> 
> Nicolin

Thanks,
Pranjal

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 1/2] iommu/arm-smmu-v3: Print better events records
  2024-08-29 23:54     ` Pranjal Shrivastava
@ 2024-08-30  1:45       ` Nicolin Chen
  2024-09-02  8:23         ` Pranjal Shrivastava
  2024-11-04 16:40       ` Daniel Mentz
  1 sibling, 1 reply; 19+ messages in thread
From: Nicolin Chen @ 2024-08-30  1:45 UTC (permalink / raw)
  To: Pranjal Shrivastava
  Cc: Joerg Roedel, Will Deacon, Robin Murphy, Mostafa Saleh,
	iommu@lists.linux.dev, Daniel Mentz

On Thu, Aug 29, 2024 at 11:54:26PM +0000, Pranjal Shrivastava wrote:

> > > +static const char * const class_str[] = {
> > > +       [0] = "CD",
> > > +       [1] = "TTD",
> > > +       [2] = "IN",
> > > +       [3] = "RES",
> > > +};
> >
> > Unlike the event IDs, these class code names are still uneasy to
> > read. Though it'd result in a print-format change, yet could we
> > simply dump full strings instead?
> >
> 
> By "full strings" do you mean "CD => CD Fetch" as mentioned in the spec?

Yes.

> > > +static void arm_smmu_get_evt_info(struct arm_smmu_device *smmu, u64 *evt,
> > > +                                 struct arm_smmu_event *event)
> > > +{
> > > +       /* Pick out the good stuff */
> > > +       event->id = FIELD_GET(EVTQ_0_ID, evt[0]);
> > > +       event->sid = FIELD_GET(EVTQ_0_SID, evt[0]);
> > > +       event->ssid_valid = evt[0] & EVTQ_0_SSV;
> > > +       event->ssid = event->ssid_valid ? FIELD_GET(EVTQ_0_SSID, evt[0]) : IOMMU_NO_PASID;
> > > +       event->class = FIELD_GET(EVTQ_1_CLASS, evt[1]);
> > > +       event->iova = FIELD_GET(EVTQ_2_ADDR, evt[2]);
> > > +       event->ipa = FIELD_GET(EVTQ_3_IPA, evt[3]);
> > > +       event->privileged = FIELD_GET(EVTQ_1_PnU, evt[1]);
> > > +       event->instruction = FIELD_GET(EVTQ_1_InD, evt[1]);
> > > +       event->stage = FIELD_GET(EVTQ_1_S2, evt[1]);
> > > +       event->read = FIELD_GET(EVTQ_1_RnW, evt[1]);
> > > +       event->raw = evt;
> >
> > Maybe we could define struct arm_smmu_event in this way:
> >
> > +struct arm_smmu_event {
> > +     union {
> > +             u64 evt[4];
> > +             struct {
> > +                     /* Bit 0:63 */
> > +                     u64 id : 8;
> > +                     u64 _res0 : 3;
> > +                     u64 ssv : 1;
> > +                     u64 ssid : 20;
> > +                     u64 sid : 32;
> > +                     /* Bit 64:127 */
> > +                     u64 stag : 16;
> > +                     u64 _res1 : 15;
> > +                     u64 stall : 1;
> > +                     u64 _res2 : 1;
> > +                     u64 pnu : 1;
> > +                     u64 ind : 1;
> > +                     u64 rnw : 1;
> > +                     u64 _res3 : 2;
> > +                     u64 nsipa : 1;
> > +                     u64 s2 : 1;
> > +                     u64 class : 2;
> > +                     u64 _res4 : 6;
> > +                     u64 impl_def : 16;
> > +                     /* Bit 128:191 */
> > +                     u64 inputaddr;
> > +                     /* Bit 192:255 */
> > +                     u64 _res5 : 12;
> > +                     u64 ipa : 40;
> > +                     u64 _res6 : 12;
> > +             } f_trans;
> > +             /* FIXME Add other event structs */
> > +     };
> > +};
> >
> > Then, event would be just:
> > +             struct arm_smmu_event *event = (struct arm_smmu_event *)evt;
> >
> > Not sure if Will would like this though...
> 
> Yea, I thought about this too but I felt that it'd bloat up the code
> for every new event that's introduced.

That'd be in the header. The IRQ Handler would be always clean
and fast.

> Also, the printing would become
> more complicated as we'd have to log different fields for different
> events. Additionally, I don't see that many unions being defined
> elsewhere in the kernel.

OK. That's a fair point. I think we could have just one common
union for the "good stuff" fields. Then, if something isn't in
the common union, do a FIELD_GET(raw)?

> > > +       mutex_lock(&smmu->streams_mutex);
> > > +       event->master = arm_smmu_find_master(smmu, event->sid);
> > > +       mutex_unlock(&smmu->streams_mutex);
> >
> > Same as I pointed out at the other patch, "master" is unprotected
> > after the unlock. It can unlikely-yet-still-possibly race against
> > arm_smmu_release_device.
> >
> 
> Hmm.. are you suggesting that the `master` could've been removed by the
> arm_smmu_release_device while we access it in an event handler?
> 
> As in, something like the following situation:
> 
> 1. The evtq_thread gets scheduled
> 2. arm_smmu_release_device removes the `master` & its streams
> 3. In the `handle_evt` we dereference `master` which has been `kfree`ed
>    (also, we don't return -EINVAL like we ideally should)
> 
> In that case, I think I should add back the `arm_smmu_find_master` to
> the `arm_smmu_handle_evt` along with the locks. Nice catch! :)

Probably could lock the entire iteration, master pointer could
be then passed in safely between the helper functions.

> > And it'd feel clearer to have an "ssid". And perhaps adding commas
> > to separate them too.
> 
> I referred to the log in `arm_smmu_handle_ppr` for the sid.ssid format.
> If we'd prefer a separate "ssid", should we change the one in ppr too?
> LMK, what you and Will think about that?

Didn't realize arm_smmu_handle_ppr does that. It's fine to keep
the format in that way then.

> > > +                       evts[event->id], event->master_name, event->sid, event->ssid);
> > > +       dev_err(smmu->dev, "\tiova = %#llx ipa = %#llx (%s%s%s%s%s%s)\n", event->iova, event->ipa,
> > > +                   event->privileged ? "Priv " : "Unpriv ",
> > > +                   event->instruction ? "Inst " : "Data ",
> > > +                   event->read ? "Read " : "Write ",
> > > +                   event->stage ? "S2 " : "S1 ", class_str[event->class],
> > > +                   ((event->id == EVT_ID_PERMISSION_FAULT) && (event->class == EVTQ_1_CLASS_TT)) ?
> > > +                   (FIELD_GET(EVTQ_1_TT_READ, event->raw[1]) ? " TTD Read" : " TTD Write")
> > > +                   : "");
> >
> > Indentation should follow the existing printk() in this driver. And
> 
> I'm sorry but I'm not sure if I understand what is meant by "the
> existing printk indentation in this driver", do you mean aligning the
> next line with the opening brace? For example:
> 
>         dev_err(smmu->dev,
>                 "failed to allocate queue (0x%zx
>                 bytes) for %s\n",
>                 qsz, name);

Yea, just to keep the same coding style, line wrapping can still
happen to 80 characters in general though.

> > those ternary operators at the last field(s?) are hard to ready..
> >
> 
> Hmm, I wanted the last fields to be printed only when the fault was
> F_PERMISSION, in the same log. Any suggestions on what might make it
> easier to read? Some helpful comments around it? Something else?

With an "other" string, we could sprintf on conditions inside the
"case F_PERMISSION:".

> > > +static void arm_smmu_dump_fetch_fault(struct arm_smmu_device *smmu,
> > > +                                     struct arm_smmu_event *event)
> > > +{
> > > +       dev_err(smmu->dev, "Bad fetch: %s client %s sid 0x%08x.0x%05x: fetch addr = %#llx\n",
> > > +                       evts[event->id], event->master_name, event->sid, event->ssid, event->ipa);
> >
> > Actually, the "Fault", "Bad fetch", and "Bad smmu config" doesn't
> > feel very necessary, since we prints the event string already.
> >
> 
> That makes sense, I'll remove those in a follow up patch.
> Although, I guess we should still say "fault" somewhere to hint folks
> without arm-smmu-v3 knowledge that the event wasn't normal operation.
> 
> LMK what you think? I've had a few interactions where clients tend to
> ignore the current "event received" dump considering that to be a part
> of normal SMMU operation.

Well, we could improve the event_str with human-readable ones:
	s/F_TRANSLATION/Translation\ Fault

> > > +}
> > > +
> > > +static void arm_smmu_dump_raw_event(struct arm_smmu_device *smmu,
> > > +                                   struct arm_smmu_event *event)
> > > +{
> > > +       int i;
> > > +
> > > +       dev_err(smmu->dev, "event 0x%02x received: client %s:\n", event->id, event->master_name);
> >
> > Looks like it would print another title that's sorta duplicated to
> > other dump functions yet less informative?
> >
> 
> Yea, I didn't wanna break backward compatibility, people might have
> tools to parse out the existing dump, lol!
>
> On a serious note, I believe it'd be better to print this as some
> implmentations might have some "IMPLEMENTATION DEFINED" fields which
> people might be interested to look at.
> 
> Although, we can dump the raw event only in the `default` case, i.e.
> when we don't have a dumper function for that particular event ID but
> that might still avoid printing the IMPL_DEFINED fields in fetch faults

Makes sense to me by having a different title for the default case.

> > > +       for (i = 0; i < EVTQ_ENT_DWORDS; ++i)
> > > +               dev_err(smmu->dev, "\t0x%016llx\n",
> > > +                        (unsigned long long)event->raw[i]);
> > > +}
> > > +
> > > +static void arm_smmu_dump_event(struct arm_smmu_device *smmu,
> > > +    
> 
> I thought about something similar as well, but then referred to Robin's
> comments on [1]. Also, printing strings in 3 different `dev_err` logs
> could result in interruptions from other logs in dmesg, I'd prefer to

Ack.

> see the entire log in a single `dev_err` for ease. Although, I think we
> should be able to do something like the following to achieve that:
>         ...
> 
>         dev_err(%s %s %s, strlen(title) ? title : ""
>                 strlen(addrs) ? addrs : ""
>                 strlen(other) ? other : ""

That is fine, though should break the lines too. Maybe:
	dev_err(smmu->dev, "%s%s%s%s%s\n", title,
		strlen(addrs) ? "\n" : "", addrs,
		strlen(other) ? "\n" : "", other);
?

> 
>         for (i = 0; i < EVTQ_ENT_DWORDS; ++i)
>                 dev_err(smmu->dev, "\t0x%016llx\n", event->evt[i]);

Maybe merge the four dev_err iterations too?

Nicolin

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 1/2] iommu/arm-smmu-v3: Print better events records
  2024-08-30  1:45       ` Nicolin Chen
@ 2024-09-02  8:23         ` Pranjal Shrivastava
  2024-09-02 23:02           ` Nicolin Chen
  0 siblings, 1 reply; 19+ messages in thread
From: Pranjal Shrivastava @ 2024-09-02  8:23 UTC (permalink / raw)
  To: Nicolin Chen
  Cc: Joerg Roedel, Will Deacon, Robin Murphy, Mostafa Saleh,
	iommu@lists.linux.dev, Daniel Mentz

On Thu, Aug 29, 2024 at 06:45:53PM -0700, Nicolin Chen wrote:
> On Thu, Aug 29, 2024 at 11:54:26PM +0000, Pranjal Shrivastava wrote:
> 
> > > > +static const char * const class_str[] = {
> > > > +       [0] = "CD",
> > > > +       [1] = "TTD",
> > > > +       [2] = "IN",
> > > > +       [3] = "RES",
> > > > +};
> > >
> > > Unlike the event IDs, these class code names are still uneasy to
> > > read. Though it'd result in a print-format change, yet could we
> > > simply dump full strings instead?
> > >
> > 
> > By "full strings" do you mean "CD => CD Fetch" as mentioned in the spec?
> 
> Yes.

Ack. So, just for confirmation we want the following 4 class strings:
"CD Fetch"
"Stage 1 translation table fetch"
"Input address caused fault"
"Reserved"

Right?

> 
> > > > +static void arm_smmu_get_evt_info(struct arm_smmu_device *smmu, u64 *evt,
> > > > +                                 struct arm_smmu_event *event)
> > > > +{
> > > > +       /* Pick out the good stuff */
> > > > +       event->id = FIELD_GET(EVTQ_0_ID, evt[0]);
> > > > +       event->sid = FIELD_GET(EVTQ_0_SID, evt[0]);
> > > > +       event->ssid_valid = evt[0] & EVTQ_0_SSV;
> > > > +       event->ssid = event->ssid_valid ? FIELD_GET(EVTQ_0_SSID, evt[0]) : IOMMU_NO_PASID;
> > > > +       event->class = FIELD_GET(EVTQ_1_CLASS, evt[1]);
> > > > +       event->iova = FIELD_GET(EVTQ_2_ADDR, evt[2]);
> > > > +       event->ipa = FIELD_GET(EVTQ_3_IPA, evt[3]);
> > > > +       event->privileged = FIELD_GET(EVTQ_1_PnU, evt[1]);
> > > > +       event->instruction = FIELD_GET(EVTQ_1_InD, evt[1]);
> > > > +       event->stage = FIELD_GET(EVTQ_1_S2, evt[1]);
> > > > +       event->read = FIELD_GET(EVTQ_1_RnW, evt[1]);
> > > > +       event->raw = evt;
> > >
> > > Maybe we could define struct arm_smmu_event in this way:
> > >
> > > +struct arm_smmu_event {
> > > +     union {
> > > +             u64 evt[4];
> > > +             struct {
> > > +                     /* Bit 0:63 */
> > > +                     u64 id : 8;
> > > +                     u64 _res0 : 3;
> > > +                     u64 ssv : 1;
> > > +                     u64 ssid : 20;
> > > +                     u64 sid : 32;
> > > +                     /* Bit 64:127 */
> > > +                     u64 stag : 16;
> > > +                     u64 _res1 : 15;
> > > +                     u64 stall : 1;
> > > +                     u64 _res2 : 1;
> > > +                     u64 pnu : 1;
> > > +                     u64 ind : 1;
> > > +                     u64 rnw : 1;
> > > +                     u64 _res3 : 2;
> > > +                     u64 nsipa : 1;
> > > +                     u64 s2 : 1;
> > > +                     u64 class : 2;
> > > +                     u64 _res4 : 6;
> > > +                     u64 impl_def : 16;
> > > +                     /* Bit 128:191 */
> > > +                     u64 inputaddr;
> > > +                     /* Bit 192:255 */
> > > +                     u64 _res5 : 12;
> > > +                     u64 ipa : 40;
> > > +                     u64 _res6 : 12;
> > > +             } f_trans;
> > > +             /* FIXME Add other event structs */
> > > +     };
> > > +};
> > >
> > > Then, event would be just:
> > > +             struct arm_smmu_event *event = (struct arm_smmu_event *)evt;
> > >
> > > Not sure if Will would like this though...
> > 
> > Yea, I thought about this too but I felt that it'd bloat up the code
> > for every new event that's introduced.
> 
> That'd be in the header. The IRQ Handler would be always clean
> and fast.
> 
> > Also, the printing would become
> > more complicated as we'd have to log different fields for different
> > events. Additionally, I don't see that many unions being defined
> > elsewhere in the kernel.
> 
> OK. That's a fair point. I think we could have just one common
> union for the "good stuff" fields. Then, if something isn't in
> the common union, do a FIELD_GET(raw)?
> 

I'm not sure if I get this right, but are you suggesting something like:

+struct arm_smmu_event {
+	union {
+	u64 raw_evt[4];
+	struct {
+		/* "Good stuff" fields */
+	};
+};

and then based on the fault type we can use the "good stuff" or raw_evt?
So, basically just add a union between raw_evt and the other fields to
improve struct arm_smmu_event present in v2?

> > > > +       mutex_lock(&smmu->streams_mutex);
> > > > +       event->master = arm_smmu_find_master(smmu, event->sid);
> > > > +       mutex_unlock(&smmu->streams_mutex);
> > >
> > > Same as I pointed out at the other patch, "master" is unprotected
> > > after the unlock. It can unlikely-yet-still-possibly race against
> > > arm_smmu_release_device.
> > >
> > 
> > Hmm.. are you suggesting that the `master` could've been removed by the
> > arm_smmu_release_device while we access it in an event handler?
> > 
> > As in, something like the following situation:
> > 
> > 1. The evtq_thread gets scheduled
> > 2. arm_smmu_release_device removes the `master` & its streams
> > 3. In the `handle_evt` we dereference `master` which has been `kfree`ed
> >    (also, we don't return -EINVAL like we ideally should)
> > 
> > In that case, I think I should add back the `arm_smmu_find_master` to
> > the `arm_smmu_handle_evt` along with the locks. Nice catch! :)
> 
> Probably could lock the entire iteration, master pointer could
> be then passed in safely between the helper functions.

I'm just wondering if that'd be too much to print the "master_name", I
mean what if we simply save the master_name in `struct arm_smmu_event`?
That way, we can keep the locking as is in `arm_smmu_handle_evt` and
simply print the stored "master_name".

Note: I'm suggesting to store the entire string and not just the ptr
returned by dev_name(master->dev)), something like: 

`strcpy(event->master_name, dev_name(master->dev))`

> 
> > > And it'd feel clearer to have an "ssid". And perhaps adding commas
> > > to separate them too.
> > 
> > I referred to the log in `arm_smmu_handle_ppr` for the sid.ssid format.
> > If we'd prefer a separate "ssid", should we change the one in ppr too?
> > LMK, what you and Will think about that?
> 
> Didn't realize arm_smmu_handle_ppr does that. It's fine to keep
> the format in that way then.

Ack.

> 
> > > > +                       evts[event->id], event->master_name, event->sid, event->ssid);
> > > > +       dev_err(smmu->dev, "\tiova = %#llx ipa = %#llx (%s%s%s%s%s%s)\n", event->iova, event->ipa,
> > > > +                   event->privileged ? "Priv " : "Unpriv ",
> > > > +                   event->instruction ? "Inst " : "Data ",
> > > > +                   event->read ? "Read " : "Write ",
> > > > +                   event->stage ? "S2 " : "S1 ", class_str[event->class],
> > > > +                   ((event->id == EVT_ID_PERMISSION_FAULT) && (event->class == EVTQ_1_CLASS_TT)) ?
> > > > +                   (FIELD_GET(EVTQ_1_TT_READ, event->raw[1]) ? " TTD Read" : " TTD Write")
> > > > +                   : "");
> > >
> > > Indentation should follow the existing printk() in this driver. And
> > 
> > I'm sorry but I'm not sure if I understand what is meant by "the
> > existing printk indentation in this driver", do you mean aligning the
> > next line with the opening brace? For example:
> > 
> >         dev_err(smmu->dev,
> >                 "failed to allocate queue (0x%zx
> >                 bytes) for %s\n",
> >                 qsz, name);
> 
> Yea, just to keep the same coding style, line wrapping can still
> happen to 80 characters in general though.
> 

Ack.

> > > those ternary operators at the last field(s?) are hard to ready..
> > >
> > 
> > Hmm, I wanted the last fields to be printed only when the fault was
> > F_PERMISSION, in the same log. Any suggestions on what might make it
> > easier to read? Some helpful comments around it? Something else?
> 
> With an "other" string, we could sprintf on conditions inside the
> "case F_PERMISSION:".
> 

Ohh alright, basically we append something extra in the "other" string
for `F_PERMISSION`. Got it.

> > > > +static void arm_smmu_dump_fetch_fault(struct arm_smmu_device *smmu,
> > > > +                                     struct arm_smmu_event *event)
> > > > +{
> > > > +       dev_err(smmu->dev, "Bad fetch: %s client %s sid 0x%08x.0x%05x: fetch addr = %#llx\n",
> > > > +                       evts[event->id], event->master_name, event->sid, event->ssid, event->ipa);
> > >
> > > Actually, the "Fault", "Bad fetch", and "Bad smmu config" doesn't
> > > feel very necessary, since we prints the event string already.
> > >
> > 
> > That makes sense, I'll remove those in a follow up patch.
> > Although, I guess we should still say "fault" somewhere to hint folks
> > without arm-smmu-v3 knowledge that the event wasn't normal operation.
> > 
> > LMK what you think? I've had a few interactions where clients tend to
> > ignore the current "event received" dump considering that to be a part
> > of normal SMMU operation.
> 
> Well, we could improve the event_str with human-readable ones:
> 	s/F_TRANSLATION/Translation\ Fault
> 

Yea, but I'd still want to see a "spec searchable" name for the fault.
Maybe we can have "Unexpected event recieved:<spec_fault_name>" in the
"title" string?

> > > > +}
> > > > +
> > > > +static void arm_smmu_dump_raw_event(struct arm_smmu_device *smmu,
> > > > +                                   struct arm_smmu_event *event)
> > > > +{
> > > > +       int i;
> > > > +
> > > > +       dev_err(smmu->dev, "event 0x%02x received: client %s:\n", event->id, event->master_name);
> > >
> > > Looks like it would print another title that's sorta duplicated to
> > > other dump functions yet less informative?
> > >
> > 
> > Yea, I didn't wanna break backward compatibility, people might have
> > tools to parse out the existing dump, lol!
> >
> > On a serious note, I believe it'd be better to print this as some
> > implmentations might have some "IMPLEMENTATION DEFINED" fields which
> > people might be interested to look at.
> > 
> > Although, we can dump the raw event only in the `default` case, i.e.
> > when we don't have a dumper function for that particular event ID but
> > that might still avoid printing the IMPL_DEFINED fields in fetch faults
> 
> Makes sense to me by having a different title for the default case.
> 

Ack, we can have a different title for the default case. However, on a
second thought, I believe we should log the "raw" event in all cases,
since we aren't printing all the fields anyway. For example, for
F_TRANSLATION we don't print IMPL_DEF fields, NSIPA etc. It might be 
helpful to see the raw event even for the "non-default" cases.

> > > > +       for (i = 0; i < EVTQ_ENT_DWORDS; ++i)
> > > > +               dev_err(smmu->dev, "\t0x%016llx\n",
> > > > +                        (unsigned long long)event->raw[i]);
> > > > +}
> > > > +
> > > > +static void arm_smmu_dump_event(struct arm_smmu_device *smmu,
> > > > +    
> > 
> > I thought about something similar as well, but then referred to Robin's
> > comments on [1]. Also, printing strings in 3 different `dev_err` logs
> > could result in interruptions from other logs in dmesg, I'd prefer to
> 
> Ack.
> 
> > see the entire log in a single `dev_err` for ease. Although, I think we
> > should be able to do something like the following to achieve that:
> >         ...
> > 
> >         dev_err(%s %s %s, strlen(title) ? title : ""
> >                 strlen(addrs) ? addrs : ""
> >                 strlen(other) ? other : ""
> 
> That is fine, though should break the lines too. Maybe:
> 	dev_err(smmu->dev, "%s%s%s%s%s\n", title,
> 		strlen(addrs) ? "\n" : "", addrs,
> 		strlen(other) ? "\n" : "", other);
> ?
> 

I'd like line-feeds too, but I'm unsure if that could cause dmesg log
interruptions? I assume adding a "\n" flushes the console buffer, i.e.
we might get interrupted logs (I maybe wrong here).

> > 
> >         for (i = 0; i < EVTQ_ENT_DWORDS; ++i)
> >                 dev_err(smmu->dev, "\t0x%016llx\n", event->evt[i]);
> 
> Maybe merge the four dev_err iterations too?

Ack.

> 
> Nicolin

Thanks,
Pranjal

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 1/2] iommu/arm-smmu-v3: Print better events records
  2024-09-02  8:23         ` Pranjal Shrivastava
@ 2024-09-02 23:02           ` Nicolin Chen
  2024-09-05 16:06             ` Pranjal Shrivastava
  0 siblings, 1 reply; 19+ messages in thread
From: Nicolin Chen @ 2024-09-02 23:02 UTC (permalink / raw)
  To: Pranjal Shrivastava
  Cc: Joerg Roedel, Will Deacon, Robin Murphy, Mostafa Saleh,
	iommu@lists.linux.dev, Daniel Mentz

On Mon, Sep 02, 2024 at 08:23:20AM +0000, Pranjal Shrivastava wrote:

> On Thu, Aug 29, 2024 at 06:45:53PM -0700, Nicolin Chen wrote:
> > On Thu, Aug 29, 2024 at 11:54:26PM +0000, Pranjal Shrivastava wrote:
> >
> > > > > +static const char * const class_str[] = {
> > > > > +       [0] = "CD",
> > > > > +       [1] = "TTD",
> > > > > +       [2] = "IN",
> > > > > +       [3] = "RES",
> > > > > +};
> > > >
> > > > Unlike the event IDs, these class code names are still uneasy to
> > > > read. Though it'd result in a print-format change, yet could we
> > > > simply dump full strings instead?
> > > >
> > >
> > > By "full strings" do you mean "CD => CD Fetch" as mentioned in the spec?
> >
> > Yes.
> 
> Ack. So, just for confirmation we want the following 4 class strings:
> "CD Fetch"
> "Stage 1 translation table fetch"
> "Input address caused fault"
> "Reserved"
> 
> Right?

Yes. I know they are longer, but more readable. So, you might want
to arrange the output format to present them nicely.

> > > Also, the printing would become
> > > more complicated as we'd have to log different fields for different
> > > events. Additionally, I don't see that many unions being defined
> > > elsewhere in the kernel.
> >
> > OK. That's a fair point. I think we could have just one common
> > union for the "good stuff" fields. Then, if something isn't in
> > the common union, do a FIELD_GET(raw)?
> >
> 
> I'm not sure if I get this right, but are you suggesting something like:
> 
> +struct arm_smmu_event {
> +       union {
> +       u64 raw_evt[4];
> +       struct {
> +               /* "Good stuff" fields */
> +       };
> +};
> 
> and then based on the fault type we can use the "good stuff" or raw_evt?
> So, basically just add a union between raw_evt and the other fields to
> improve struct arm_smmu_event present in v2?

Yea, I attached a test code at the EOM for your reference. Please
feel free to drop fields if they aren't common enough, and confirm
those bits are correctly written too.

> > > > > +       mutex_lock(&smmu->streams_mutex);
> > > > > +       event->master = arm_smmu_find_master(smmu, event->sid);
> > > > > +       mutex_unlock(&smmu->streams_mutex);
> > > >
> > > > Same as I pointed out at the other patch, "master" is unprotected
> > > > after the unlock. It can unlikely-yet-still-possibly race against
> > > > arm_smmu_release_device.
> > > >
> > >
> > > Hmm.. are you suggesting that the `master` could've been removed by the
> > > arm_smmu_release_device while we access it in an event handler?
> > >
> > > As in, something like the following situation:
> > >
> > > 1. The evtq_thread gets scheduled
> > > 2. arm_smmu_release_device removes the `master` & its streams
> > > 3. In the `handle_evt` we dereference `master` which has been `kfree`ed
> > >    (also, we don't return -EINVAL like we ideally should)
> > >
> > > In that case, I think I should add back the `arm_smmu_find_master` to
> > > the `arm_smmu_handle_evt` along with the locks. Nice catch! :)
> >
> > Probably could lock the entire iteration, master pointer could
> > be then passed in safely between the helper functions.
> 
> I'm just wondering if that'd be too much to print the "master_name", I
> mean what if we simply save the master_name in `struct arm_smmu_event`?
> That way, we can keep the locking as is in `arm_smmu_handle_evt` and
> simply print the stored "master_name".
> 
> Note: I'm suggesting to store the entire string and not just the ptr
> returned by dev_name(master->dev)), something like:
> 
> `strcpy(event->master_name, dev_name(master->dev))`

I'd probably move the dump() call inside arm_smmu_handle_evt(), and
within the lock to avoid strcpy. And eventually it would be located
at "else { /* Unhandled events should be pinned */ ret = -EFAULT; }:
https://lore.kernel.org/linux-iommu/8b93be1d913f9e227748de2d07e8540ddc2372ab.1724777091.git.nicolinc@nvidia.com/

> > > > Actually, the "Fault", "Bad fetch", and "Bad smmu config" doesn't
> > > > feel very necessary, since we prints the event string already.
> > > >
> > >
> > > That makes sense, I'll remove those in a follow up patch.
> > > Although, I guess we should still say "fault" somewhere to hint folks
> > > without arm-smmu-v3 knowledge that the event wasn't normal operation.
> > >
> > > LMK what you think? I've had a few interactions where clients tend to
> > > ignore the current "event received" dump considering that to be a part
> > > of normal SMMU operation.
> >
> > Well, we could improve the event_str with human-readable ones:
> >       s/F_TRANSLATION/Translation\ Fault
> >
> 
> Yea, but I'd still want to see a "spec searchable" name for the fault.
> Maybe we can have "Unexpected event recieved:<spec_fault_name>" in the
> "title" string?

That looks good to me.

> > > Although, we can dump the raw event only in the `default` case, i.e.
> > > when we don't have a dumper function for that particular event ID but
> > > that might still avoid printing the IMPL_DEFINED fields in fetch faults
> >
> > Makes sense to me by having a different title for the default case.
> >
> 
> Ack, we can have a different title for the default case. However, on a
> second thought, I believe we should log the "raw" event in all cases,
> since we aren't printing all the fields anyway. For example, for
> F_TRANSLATION we don't print IMPL_DEF fields, NSIPA etc. It might be
> helpful to see the raw event even for the "non-default" cases.

That makes sense. I'd dump the raw dwords outside the switch-case,
i.e. in the common path.

> > That is fine, though should break the lines too. Maybe:
> >       dev_err(smmu->dev, "%s%s%s%s%s\n", title,
> >               strlen(addrs) ? "\n" : "", addrs,
> >               strlen(other) ? "\n" : "", other);
> > ?
> >
> 
> I'd like line-feeds too, but I'm unsure if that could cause dmesg log
> interruptions? I assume adding a "\n" flushes the console buffer, i.e.
> we might get interrupted logs (I maybe wrong here).

I think the console_lock is grabbed per printk call, not per "\n".

Thanks
Nicolin

-------------------------------------------------------------------------------
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 6c48b53fc2b8..6b1ca9379999 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -1894,6 +1894,37 @@ static int arm_smmu_handle_evt(struct arm_smmu_device *smmu, u64 *evt)
 	return ret;
 }
 
+union arm_smmu_event {
+	u64 evt[EVTQ_ENT_DWORDS];
+	struct {
+	/* Bit 0:63 */
+	u64 id : 8;
+	u64 _res0 : 3;
+	u64 ssv : 1;
+	u64 ssid : 20;
+	u64 sid : 32;
+	/* Bit 64:127 */
+	u64 stag : 16;
+	u64 _res1 : 15;
+	u64 stall : 1;
+	u64 _res2 : 1;
+	u64 pnu : 1;
+	u64 ind : 1;
+	u64 rnw : 1;
+	u64 _res3 : 2;
+	u64 nsipa : 1;
+	u64 s2 : 1;
+	u64 class : 2;
+	u64 _res4 : 6;
+	u64 impl_def : 16;
+	/* Bit 128:191 */
+	u64 addr1;
+	/* Bit 192:255 */
+	u64 addr2: 56;
+	u64 _res5: 8;
+	};
+};
+
 static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
 {
 	int i, ret;
@@ -1902,20 +1933,27 @@ static irqreturn_t arm_smmu_evtq_thread(int irq, void *dev)
 	struct arm_smmu_ll_queue *llq = &q->llq;
 	static DEFINE_RATELIMIT_STATE(rs, DEFAULT_RATELIMIT_INTERVAL,
 				      DEFAULT_RATELIMIT_BURST);
-	u64 evt[EVTQ_ENT_DWORDS];
+	union arm_smmu_event event;
 
 	do {
-		while (!queue_remove_raw(q, evt)) {
-			u8 id = FIELD_GET(EVTQ_0_ID, evt[0]);
+		while (!queue_remove_raw(q, event.evt)) {
+			u8 id = FIELD_GET(EVTQ_0_ID, event.evt[0]);
 
-			ret = arm_smmu_handle_evt(smmu, evt);
+			ret = arm_smmu_handle_evt(smmu, event.evt);
 			if (!ret || !__ratelimit(&rs))
 				continue;
 
 			dev_info(smmu->dev, "event 0x%02x received:\n", id);
-			for (i = 0; i < ARRAY_SIZE(evt); ++i)
+			for (i = 0; i < ARRAY_SIZE(event.evt); ++i)
 				dev_info(smmu->dev, "\t0x%016llx\n",
-					 (unsigned long long)evt[i]);
+					 event.evt[i]);
+			dev_info(smmu->dev, "id=%d\n", event.id);
+			dev_info(smmu->dev, "sid=%x\n", event.sid);
+			dev_info(smmu->dev, "class=%d\n", event.class);
+			dev_info(smmu->dev, "s2=%d\n", event.s2);
+			dev_info(smmu->dev, "inputaddr=%llx\n", event.addr1);
+			dev_info(smmu->dev, "ipa=%llx\n",
+					(u64)event.addr2 & GENMASK(55, 12));
 
 			cond_resched();
 		}

^ permalink raw reply related	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 1/2] iommu/arm-smmu-v3: Print better events records
  2024-09-02 23:02           ` Nicolin Chen
@ 2024-09-05 16:06             ` Pranjal Shrivastava
  2024-09-06  1:55               ` Nicolin Chen
  0 siblings, 1 reply; 19+ messages in thread
From: Pranjal Shrivastava @ 2024-09-05 16:06 UTC (permalink / raw)
  To: Nicolin Chen
  Cc: Joerg Roedel, Will Deacon, Robin Murphy, Mostafa Saleh,
	iommu@lists.linux.dev, Daniel Mentz

On Mon, Sep 02, 2024 at 04:02:44PM -0700, Nicolin Chen wrote:
> On Mon, Sep 02, 2024 at 08:23:20AM +0000, Pranjal Shrivastava wrote:
> 
> > On Thu, Aug 29, 2024 at 06:45:53PM -0700, Nicolin Chen wrote:
> > > On Thu, Aug 29, 2024 at 11:54:26PM +0000, Pranjal Shrivastava wrote:
> > >
> > > > > > +static const char * const class_str[] = {
> > > > > > +       [0] = "CD",
> > > > > > +       [1] = "TTD",
> > > > > > +       [2] = "IN",
> > > > > > +       [3] = "RES",
> > > > > > +};
> > > > >
> > > > > Unlike the event IDs, these class code names are still uneasy to
> > > > > read. Though it'd result in a print-format change, yet could we
> > > > > simply dump full strings instead?
> > > > >
> > > >
> > > > By "full strings" do you mean "CD => CD Fetch" as mentioned in the spec?
> > >
> > > Yes.
> > 
> > Ack. So, just for confirmation we want the following 4 class strings:
> > "CD Fetch"
> > "Stage 1 translation table fetch"
> > "Input address caused fault"
> > "Reserved"
> > 
> > Right?
> 
> Yes. I know they are longer, but more readable. So, you might want
> to arrange the output format to present them nicely.
> 

Ack, thanks for confirming!

> > > > Also, the printing would become
> > > > more complicated as we'd have to log different fields for different
> > > > events. Additionally, I don't see that many unions being defined
> > > > elsewhere in the kernel.
> > >
> > > OK. That's a fair point. I think we could have just one common
> > > union for the "good stuff" fields. Then, if something isn't in
> > > the common union, do a FIELD_GET(raw)?
> > >
> > 
> > I'm not sure if I get this right, but are you suggesting something like:
> > 
> > +struct arm_smmu_event {
> > +       union {
> > +       u64 raw_evt[4];
> > +       struct {
> > +               /* "Good stuff" fields */
> > +       };
> > +};
> > 
> > and then based on the fault type we can use the "good stuff" or raw_evt?
> > So, basically just add a union between raw_evt and the other fields to
> > improve struct arm_smmu_event present in v2?
> 
> Yea, I attached a test code at the EOM for your reference. Please
> feel free to drop fields if they aren't common enough, and confirm
> those bits are correctly written too.
> 

Hmm, so you're suggesting to make the event a union instead of a struct
thus, making reading event fields easy.

The only thing I'm slightly worried about is if the bitfields don't
remain constant if more events are added in the future.

For example, the "IPA" field is in dword[3] for now, but if it changes
in the future, it may get difficult to scale the union for future events
If we can guarantee that it doesn't happen then I think union is better.

Will, do you have any suggestions here?

> > > > > > +       mutex_lock(&smmu->streams_mutex);
> > > > > > +       event->master = arm_smmu_find_master(smmu, event->sid);
> > > > > > +       mutex_unlock(&smmu->streams_mutex);
> > > > >
> > > > > Same as I pointed out at the other patch, "master" is unprotected
> > > > > after the unlock. It can unlikely-yet-still-possibly race against
> > > > > arm_smmu_release_device.
> > > > >
> > > >
> > > > Hmm.. are you suggesting that the `master` could've been removed by the
> > > > arm_smmu_release_device while we access it in an event handler?
> > > >
> > > > As in, something like the following situation:
> > > >
> > > > 1. The evtq_thread gets scheduled
> > > > 2. arm_smmu_release_device removes the `master` & its streams
> > > > 3. In the `handle_evt` we dereference `master` which has been `kfree`ed
> > > >    (also, we don't return -EINVAL like we ideally should)
> > > >
> > > > In that case, I think I should add back the `arm_smmu_find_master` to
> > > > the `arm_smmu_handle_evt` along with the locks. Nice catch! :)
> > >
> > > Probably could lock the entire iteration, master pointer could
> > > be then passed in safely between the helper functions.
> > 
> > I'm just wondering if that'd be too much to print the "master_name", I
> > mean what if we simply save the master_name in `struct arm_smmu_event`?
> > That way, we can keep the locking as is in `arm_smmu_handle_evt` and
> > simply print the stored "master_name".
> > 
> > Note: I'm suggesting to store the entire string and not just the ptr
> > returned by dev_name(master->dev)), something like:
> > 
> > `strcpy(event->master_name, dev_name(master->dev))`
> 
> I'd probably move the dump() call inside arm_smmu_handle_evt(), and
> within the lock to avoid strcpy. And eventually it would be located
> at "else { /* Unhandled events should be pinned */ ret = -EFAULT; }:
> https://lore.kernel.org/linux-iommu/8b93be1d913f9e227748de2d07e8540ddc2372ab.1724777091.git.nicolinc@nvidia.com/
> 

I think we'll still need to dump the event for other cases, such as the
case where the master wasn't found, we return `-EINVAL` and the case
where EVTQ_1_S2 is set. I guess, we should have a case under the label
`out_unlock` we can call the dump function based on the ret value. E.g.:

out_unlock:
+	if (ret)
+		arm_smmu_dump_event(smmu, evt);
 	mutex_unlock(&smmu->streams_mutex);
 	return ret;

> > > > > Actually, the "Fault", "Bad fetch", and "Bad smmu config" doesn't
> > > > > feel very necessary, since we prints the event string already.
> > > > >
> > > >
> > > > That makes sense, I'll remove those in a follow up patch.
> > > > Although, I guess we should still say "fault" somewhere to hint folks
> > > > without arm-smmu-v3 knowledge that the event wasn't normal operation.
> > > >
> > > > LMK what you think? I've had a few interactions where clients tend to
> > > > ignore the current "event received" dump considering that to be a part
> > > > of normal SMMU operation.
> > >
> > > Well, we could improve the event_str with human-readable ones:
> > >       s/F_TRANSLATION/Translation\ Fault
> > >
> > 
> > Yea, but I'd still want to see a "spec searchable" name for the fault.
> > Maybe we can have "Unexpected event recieved:<spec_fault_name>" in the
> > "title" string?
> 
> That looks good to me.
> 

Ack.

> > > > Although, we can dump the raw event only in the `default` case, i.e.
> > > > when we don't have a dumper function for that particular event ID but
> > > > that might still avoid printing the IMPL_DEFINED fields in fetch faults
> > >
> > > Makes sense to me by having a different title for the default case.
> > >
> > 
> > Ack, we can have a different title for the default case. However, on a
> > second thought, I believe we should log the "raw" event in all cases,
> > since we aren't printing all the fields anyway. For example, for
> > F_TRANSLATION we don't print IMPL_DEF fields, NSIPA etc. It might be
> > helpful to see the raw event even for the "non-default" cases.
> 
> That makes sense. I'd dump the raw dwords outside the switch-case,
> i.e. in the common path.
> 

Ack. I'd dump the raw dwords outside the switch-case in v3.

> > > That is fine, though should break the lines too. Maybe:
> > >       dev_err(smmu->dev, "%s%s%s%s%s\n", title,
> > >               strlen(addrs) ? "\n" : "", addrs,
> > >               strlen(other) ? "\n" : "", other);
> > > ?
> > >
> > 
> > I'd like line-feeds too, but I'm unsure if that could cause dmesg log
> > interruptions? I assume adding a "\n" flushes the console buffer, i.e.
> > we might get interrupted logs (I maybe wrong here).
> 
> I think the console_lock is grabbed per printk call, not per "\n".

Ahh okay! I took the opportunity to read up the printk implementation.
I see the `vprintk_store` stores a single log as a unit in the buffer,
and the `console_unlock` actually flushes it out to the console. That
said, I think nothing (other than hard IRQs printing logs) should cause
interleaving between the log. Interesting stuff!

> 
> Thanks
> Nicolin

Thanks,
Pranjal

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 1/2] iommu/arm-smmu-v3: Print better events records
  2024-09-05 16:06             ` Pranjal Shrivastava
@ 2024-09-06  1:55               ` Nicolin Chen
  2024-09-06 12:55                 ` Will Deacon
  0 siblings, 1 reply; 19+ messages in thread
From: Nicolin Chen @ 2024-09-06  1:55 UTC (permalink / raw)
  To: Pranjal Shrivastava
  Cc: Joerg Roedel, Will Deacon, Robin Murphy, Mostafa Saleh,
	iommu@lists.linux.dev, Daniel Mentz

On Thu, Sep 05, 2024 at 04:06:24PM +0000, Pranjal Shrivastava wrote:

> > > > > Also, the printing would become
> > > > > more complicated as we'd have to log different fields for different
> > > > > events. Additionally, I don't see that many unions being defined
> > > > > elsewhere in the kernel.
> > > >
> > > > OK. That's a fair point. I think we could have just one common
> > > > union for the "good stuff" fields. Then, if something isn't in
> > > > the common union, do a FIELD_GET(raw)?
> > > >
> > >
> > > I'm not sure if I get this right, but are you suggesting something like:
> > >
> > > +struct arm_smmu_event {
> > > +       union {
> > > +       u64 raw_evt[4];
> > > +       struct {
> > > +               /* "Good stuff" fields */
> > > +       };
> > > +};
> > >
> > > and then based on the fault type we can use the "good stuff" or raw_evt?
> > > So, basically just add a union between raw_evt and the other fields to
> > > improve struct arm_smmu_event present in v2?
> >
> > Yea, I attached a test code at the EOM for your reference. Please
> > feel free to drop fields if they aren't common enough, and confirm
> > those bits are correctly written too.
> >
> 
> Hmm, so you're suggesting to make the event a union instead of a struct
> thus, making reading event fields easy.
> 
> The only thing I'm slightly worried about is if the bitfields don't
> remain constant if more events are added in the future.
> 
> For example, the "IPA" field is in dword[3] for now, but if it changes
> in the future, it may get difficult to scale the union for future events
> If we can guarantee that it doesn't happen then I think union is better.

I believe HW has its own reason to put those fields constantly
following the same pattern, and must have its tendency to keep
in that way.

The "union { u64 raw; struct {} }" way isn't that uncommon in
the kernel, here are a few existing examples:
	drivers/crypto/marvell/octeontx2/otx2_cpt_hw_types.h
	drivers/crypto/cavium/nitrox/nitrox_req.h
	include/asm-generic/hyperv-tlfs.h

Taking a step back, if one field in a new event in the future
happens to be odd, we could still fetch field in its own way:
event->evt[4] is still available to extract via FIELD_GET; or
just define another union exclusively for that event, neither
of which sounds like the end of world.

Having said that, I'd defer to Will. So, here is just my two
cents.

> > > I'm just wondering if that'd be too much to print the "master_name", I
> > > mean what if we simply save the master_name in `struct arm_smmu_event`?
> > > That way, we can keep the locking as is in `arm_smmu_handle_evt` and
> > > simply print the stored "master_name".
> > >
> > > Note: I'm suggesting to store the entire string and not just the ptr
> > > returned by dev_name(master->dev)), something like:
> > >
> > > `strcpy(event->master_name, dev_name(master->dev))`
> >
> > I'd probably move the dump() call inside arm_smmu_handle_evt(), and
> > within the lock to avoid strcpy. And eventually it would be located
> > at "else { /* Unhandled events should be pinned */ ret = -EFAULT; }:
> > https://lore.kernel.org/linux-iommu/8b93be1d913f9e227748de2d07e8540ddc2372ab.1724777091.git.nicolinc@nvidia.com/
> >
> 
> I think we'll still need to dump the event for other cases, such as the
> case where the master wasn't found, we return `-EINVAL` and the case
> where EVTQ_1_S2 is set. I guess, we should have a case under the label
> `out_unlock` we can call the dump function based on the ret value. E.g.:
> 
> out_unlock:
> +       if (ret)
> +               arm_smmu_dump_event(smmu, evt);
>         mutex_unlock(&smmu->streams_mutex);
>         return ret;

Ah, that's thoughtful. I missed it. I agree.

Thanks
Nicolin

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 1/2] iommu/arm-smmu-v3: Print better events records
  2024-09-06  1:55               ` Nicolin Chen
@ 2024-09-06 12:55                 ` Will Deacon
  2024-09-06 16:39                   ` Robin Murphy
  0 siblings, 1 reply; 19+ messages in thread
From: Will Deacon @ 2024-09-06 12:55 UTC (permalink / raw)
  To: Nicolin Chen
  Cc: Pranjal Shrivastava, Joerg Roedel, Robin Murphy, Mostafa Saleh,
	iommu@lists.linux.dev, Daniel Mentz

On Thu, Sep 05, 2024 at 06:55:33PM -0700, Nicolin Chen wrote:
> On Thu, Sep 05, 2024 at 04:06:24PM +0000, Pranjal Shrivastava wrote:
> 
> > > > > > Also, the printing would become
> > > > > > more complicated as we'd have to log different fields for different
> > > > > > events. Additionally, I don't see that many unions being defined
> > > > > > elsewhere in the kernel.
> > > > >
> > > > > OK. That's a fair point. I think we could have just one common
> > > > > union for the "good stuff" fields. Then, if something isn't in
> > > > > the common union, do a FIELD_GET(raw)?
> > > > >
> > > >
> > > > I'm not sure if I get this right, but are you suggesting something like:
> > > >
> > > > +struct arm_smmu_event {
> > > > +       union {
> > > > +       u64 raw_evt[4];
> > > > +       struct {
> > > > +               /* "Good stuff" fields */
> > > > +       };
> > > > +};
> > > >
> > > > and then based on the fault type we can use the "good stuff" or raw_evt?
> > > > So, basically just add a union between raw_evt and the other fields to
> > > > improve struct arm_smmu_event present in v2?
> > >
> > > Yea, I attached a test code at the EOM for your reference. Please
> > > feel free to drop fields if they aren't common enough, and confirm
> > > those bits are correctly written too.
> > >
> > 
> > Hmm, so you're suggesting to make the event a union instead of a struct
> > thus, making reading event fields easy.
> > 
> > The only thing I'm slightly worried about is if the bitfields don't
> > remain constant if more events are added in the future.
> > 
> > For example, the "IPA" field is in dword[3] for now, but if it changes
> > in the future, it may get difficult to scale the union for future events
> > If we can guarantee that it doesn't happen then I think union is better.
> 
> I believe HW has its own reason to put those fields constantly
> following the same pattern, and must have its tendency to keep
> in that way.
> 
> The "union { u64 raw; struct {} }" way isn't that uncommon in
> the kernel, here are a few existing examples:
> 	drivers/crypto/marvell/octeontx2/otx2_cpt_hw_types.h
> 	drivers/crypto/cavium/nitrox/nitrox_req.h
> 	include/asm-generic/hyperv-tlfs.h
> 
> Taking a step back, if one field in a new event in the future
> happens to be odd, we could still fetch field in its own way:
> event->evt[4] is still available to extract via FIELD_GET; or
> just define another union exclusively for that event, neither
> of which sounds like the end of world.
> 
> Having said that, I'd defer to Will. So, here is just my two
> cents.

My only real concern is the fragility of using bitfields. I don't _think_
the compiler is obliged to lay them out in the obvious way and I can't
think of anything worse than being given a bad pretty-print when debugging
a real driver issue!

Will

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 1/2] iommu/arm-smmu-v3: Print better events records
  2024-09-06 12:55                 ` Will Deacon
@ 2024-09-06 16:39                   ` Robin Murphy
  2024-09-06 18:42                     ` Nicolin Chen
  0 siblings, 1 reply; 19+ messages in thread
From: Robin Murphy @ 2024-09-06 16:39 UTC (permalink / raw)
  To: Will Deacon, Nicolin Chen
  Cc: Pranjal Shrivastava, Joerg Roedel, Mostafa Saleh,
	iommu@lists.linux.dev, Daniel Mentz

On 06/09/2024 1:55 pm, Will Deacon wrote:
> On Thu, Sep 05, 2024 at 06:55:33PM -0700, Nicolin Chen wrote:
>> On Thu, Sep 05, 2024 at 04:06:24PM +0000, Pranjal Shrivastava wrote:
>>
>>>>>>> Also, the printing would become
>>>>>>> more complicated as we'd have to log different fields for different
>>>>>>> events. Additionally, I don't see that many unions being defined
>>>>>>> elsewhere in the kernel.
>>>>>>
>>>>>> OK. That's a fair point. I think we could have just one common
>>>>>> union for the "good stuff" fields. Then, if something isn't in
>>>>>> the common union, do a FIELD_GET(raw)?
>>>>>>
>>>>>
>>>>> I'm not sure if I get this right, but are you suggesting something like:
>>>>>
>>>>> +struct arm_smmu_event {
>>>>> +       union {
>>>>> +       u64 raw_evt[4];
>>>>> +       struct {
>>>>> +               /* "Good stuff" fields */
>>>>> +       };
>>>>> +};
>>>>>
>>>>> and then based on the fault type we can use the "good stuff" or raw_evt?
>>>>> So, basically just add a union between raw_evt and the other fields to
>>>>> improve struct arm_smmu_event present in v2?
>>>>
>>>> Yea, I attached a test code at the EOM for your reference. Please
>>>> feel free to drop fields if they aren't common enough, and confirm
>>>> those bits are correctly written too.
>>>>
>>>
>>> Hmm, so you're suggesting to make the event a union instead of a struct
>>> thus, making reading event fields easy.
>>>
>>> The only thing I'm slightly worried about is if the bitfields don't
>>> remain constant if more events are added in the future.
>>>
>>> For example, the "IPA" field is in dword[3] for now, but if it changes
>>> in the future, it may get difficult to scale the union for future events
>>> If we can guarantee that it doesn't happen then I think union is better.
>>
>> I believe HW has its own reason to put those fields constantly
>> following the same pattern, and must have its tendency to keep
>> in that way.
>>
>> The "union { u64 raw; struct {} }" way isn't that uncommon in
>> the kernel, here are a few existing examples:
>> 	drivers/crypto/marvell/octeontx2/otx2_cpt_hw_types.h
>> 	drivers/crypto/cavium/nitrox/nitrox_req.h
>> 	include/asm-generic/hyperv-tlfs.h
>>
>> Taking a step back, if one field in a new event in the future
>> happens to be odd, we could still fetch field in its own way:
>> event->evt[4] is still available to extract via FIELD_GET; or
>> just define another union exclusively for that event, neither
>> of which sounds like the end of world.
>>
>> Having said that, I'd defer to Will. So, here is just my two
>> cents.
> 
> My only real concern is the fragility of using bitfields. I don't _think_
> the compiler is obliged to lay them out in the obvious way and I can't
> think of anything worse than being given a bad pretty-print when debugging
> a real driver issue!

Shall I mention big-endian? :D

FWIW I'm not a fan of the bitfield trickery either. However, unions 
aside, I do still think it would be a good idea for the raw event data 
storage to be in struct arm_smmu_event itself - having one local 
variable carry a pointer to another local variable in the same scope 
seems a bit silly.

Thanks,
Robin.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 1/2] iommu/arm-smmu-v3: Print better events records
  2024-09-06 16:39                   ` Robin Murphy
@ 2024-09-06 18:42                     ` Nicolin Chen
  2024-09-09 14:45                       ` Will Deacon
  0 siblings, 1 reply; 19+ messages in thread
From: Nicolin Chen @ 2024-09-06 18:42 UTC (permalink / raw)
  To: Will Deacon, Robin Murphy
  Cc: Pranjal Shrivastava, Joerg Roedel, Mostafa Saleh,
	iommu@lists.linux.dev, Daniel Mentz

On Fri, Sep 06, 2024 at 05:39:03PM +0100, Robin Murphy wrote:
> On 06/09/2024 1:55 pm, Will Deacon wrote:
> > > > > > +struct arm_smmu_event {
> > > > > > +       union {
> > > > > > +       u64 raw_evt[4];
> > > > > > +       struct {
> > > > > > +               /* "Good stuff" fields */
> > > > > > +       };
> > > > > > +};
> > > > > > 
> > > > > > and then based on the fault type we can use the "good stuff" or raw_evt?
> > > > > > So, basically just add a union between raw_evt and the other fields to
> > > > > > improve struct arm_smmu_event present in v2?
> > > > > 
> > > > > Yea, I attached a test code at the EOM for your reference. Please
> > > > > feel free to drop fields if they aren't common enough, and confirm
> > > > > those bits are correctly written too.
> > > > > 
> > > > 
> > > > Hmm, so you're suggesting to make the event a union instead of a struct
> > > > thus, making reading event fields easy.
> > > > 
> > > > The only thing I'm slightly worried about is if the bitfields don't
> > > > remain constant if more events are added in the future.
> > > > 
> > > > For example, the "IPA" field is in dword[3] for now, but if it changes
> > > > in the future, it may get difficult to scale the union for future events
> > > > If we can guarantee that it doesn't happen then I think union is better.
> > > 
> > > I believe HW has its own reason to put those fields constantly
> > > following the same pattern, and must have its tendency to keep
> > > in that way.
> > > 
> > > The "union { u64 raw; struct {} }" way isn't that uncommon in
> > > the kernel, here are a few existing examples:
> > >      drivers/crypto/marvell/octeontx2/otx2_cpt_hw_types.h
> > >      drivers/crypto/cavium/nitrox/nitrox_req.h
> > >      include/asm-generic/hyperv-tlfs.h
> > > 
> > > Taking a step back, if one field in a new event in the future
> > > happens to be odd, we could still fetch field in its own way:
> > > event->evt[4] is still available to extract via FIELD_GET; or
> > > just define another union exclusively for that event, neither
> > > of which sounds like the end of world.
> > > 
> > > Having said that, I'd defer to Will. So, here is just my two
> > > cents.
> > 
> > My only real concern is the fragility of using bitfields. I don't _think_
> > the compiler is obliged to lay them out in the obvious way and I can't
> > think of anything worse than being given a bad pretty-print when debugging
> > a real driver issue!

Well, if compiler is going to be an issue, I can't disagree with
your point.

Any reference to some existing issue with compiler failing to lay
out properly? I wonder how other headers could define their unions
using bitfields and stay safe..

> Shall I mention big-endian? :D

Ah, right. queue_read() converts le64 to native CPU format..

> FWIW I'm not a fan of the bitfield trickery either. However, unions

I am trying to learn here: apart from what Will mentioned above,
is there any other reason to stay away from bitfield?

Thanks!
Nicolin

> aside, I do still think it would be a good idea for the raw event data
> storage to be in struct arm_smmu_event itself - having one local
> variable carry a pointer to another local variable in the same scope
> seems a bit silly.
> 
> Thanks,
> Robin.

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 1/2] iommu/arm-smmu-v3: Print better events records
  2024-09-06 18:42                     ` Nicolin Chen
@ 2024-09-09 14:45                       ` Will Deacon
  2024-09-09 17:30                         ` Pranjal Shrivastava
  0 siblings, 1 reply; 19+ messages in thread
From: Will Deacon @ 2024-09-09 14:45 UTC (permalink / raw)
  To: Nicolin Chen
  Cc: Robin Murphy, Pranjal Shrivastava, Joerg Roedel, Mostafa Saleh,
	iommu@lists.linux.dev, Daniel Mentz

On Fri, Sep 06, 2024 at 11:42:31AM -0700, Nicolin Chen wrote:
> On Fri, Sep 06, 2024 at 05:39:03PM +0100, Robin Murphy wrote:
> > On 06/09/2024 1:55 pm, Will Deacon wrote:
> > > > > > > +struct arm_smmu_event {
> > > > > > > +       union {
> > > > > > > +       u64 raw_evt[4];
> > > > > > > +       struct {
> > > > > > > +               /* "Good stuff" fields */
> > > > > > > +       };
> > > > > > > +};
> > > > > > > 
> > > > > > > and then based on the fault type we can use the "good stuff" or raw_evt?
> > > > > > > So, basically just add a union between raw_evt and the other fields to
> > > > > > > improve struct arm_smmu_event present in v2?
> > > > > > 
> > > > > > Yea, I attached a test code at the EOM for your reference. Please
> > > > > > feel free to drop fields if they aren't common enough, and confirm
> > > > > > those bits are correctly written too.
> > > > > > 
> > > > > 
> > > > > Hmm, so you're suggesting to make the event a union instead of a struct
> > > > > thus, making reading event fields easy.
> > > > > 
> > > > > The only thing I'm slightly worried about is if the bitfields don't
> > > > > remain constant if more events are added in the future.
> > > > > 
> > > > > For example, the "IPA" field is in dword[3] for now, but if it changes
> > > > > in the future, it may get difficult to scale the union for future events
> > > > > If we can guarantee that it doesn't happen then I think union is better.
> > > > 
> > > > I believe HW has its own reason to put those fields constantly
> > > > following the same pattern, and must have its tendency to keep
> > > > in that way.
> > > > 
> > > > The "union { u64 raw; struct {} }" way isn't that uncommon in
> > > > the kernel, here are a few existing examples:
> > > >      drivers/crypto/marvell/octeontx2/otx2_cpt_hw_types.h
> > > >      drivers/crypto/cavium/nitrox/nitrox_req.h
> > > >      include/asm-generic/hyperv-tlfs.h
> > > > 
> > > > Taking a step back, if one field in a new event in the future
> > > > happens to be odd, we could still fetch field in its own way:
> > > > event->evt[4] is still available to extract via FIELD_GET; or
> > > > just define another union exclusively for that event, neither
> > > > of which sounds like the end of world.
> > > > 
> > > > Having said that, I'd defer to Will. So, here is just my two
> > > > cents.
> > > 
> > > My only real concern is the fragility of using bitfields. I don't _think_
> > > the compiler is obliged to lay them out in the obvious way and I can't
> > > think of anything worse than being given a bad pretty-print when debugging
> > > a real driver issue!
> 
> Well, if compiler is going to be an issue, I can't disagree with
> your point.
> 
> Any reference to some existing issue with compiler failing to lay
> out properly? I wonder how other headers could define their unions
> using bitfields and stay safe..

It's not so much about buggy compilers, but more that I don't think the
C standard defines the order and so relying on it can be fragile. If you
fancy going to the effort of ensuring that LLVM and GCC will agree on
the "obvious" layout forever more, then don't let me stop you ;)

Will

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 1/2] iommu/arm-smmu-v3: Print better events records
  2024-09-09 14:45                       ` Will Deacon
@ 2024-09-09 17:30                         ` Pranjal Shrivastava
  2024-09-10  4:43                           ` Nicolin Chen
  0 siblings, 1 reply; 19+ messages in thread
From: Pranjal Shrivastava @ 2024-09-09 17:30 UTC (permalink / raw)
  To: Will Deacon
  Cc: Nicolin Chen, Robin Murphy, Joerg Roedel, Mostafa Saleh,
	iommu@lists.linux.dev, Daniel Mentz

On Mon, Sep 09, 2024 at 03:45:06PM +0100, Will Deacon wrote:
> On Fri, Sep 06, 2024 at 11:42:31AM -0700, Nicolin Chen wrote:
> > On Fri, Sep 06, 2024 at 05:39:03PM +0100, Robin Murphy wrote:
> > > On 06/09/2024 1:55 pm, Will Deacon wrote:
> > > > > > > > +struct arm_smmu_event {
> > > > > > > > +       union {
> > > > > > > > +       u64 raw_evt[4];
> > > > > > > > +       struct {
> > > > > > > > +               /* "Good stuff" fields */
> > > > > > > > +       };
> > > > > > > > +};
> > > > > > > > 
> > > > > > > > and then based on the fault type we can use the "good stuff" or raw_evt?
> > > > > > > > So, basically just add a union between raw_evt and the other fields to
> > > > > > > > improve struct arm_smmu_event present in v2?
> > > > > > > 
> > > > > > > Yea, I attached a test code at the EOM for your reference. Please
> > > > > > > feel free to drop fields if they aren't common enough, and confirm
> > > > > > > those bits are correctly written too.
> > > > > > > 
> > > > > > 
> > > > > > Hmm, so you're suggesting to make the event a union instead of a struct
> > > > > > thus, making reading event fields easy.
> > > > > > 
> > > > > > The only thing I'm slightly worried about is if the bitfields don't
> > > > > > remain constant if more events are added in the future.
> > > > > > 
> > > > > > For example, the "IPA" field is in dword[3] for now, but if it changes
> > > > > > in the future, it may get difficult to scale the union for future events
> > > > > > If we can guarantee that it doesn't happen then I think union is better.
> > > > > 
> > > > > I believe HW has its own reason to put those fields constantly
> > > > > following the same pattern, and must have its tendency to keep
> > > > > in that way.
> > > > > 
> > > > > The "union { u64 raw; struct {} }" way isn't that uncommon in
> > > > > the kernel, here are a few existing examples:
> > > > >      drivers/crypto/marvell/octeontx2/otx2_cpt_hw_types.h
> > > > >      drivers/crypto/cavium/nitrox/nitrox_req.h
> > > > >      include/asm-generic/hyperv-tlfs.h
> > > > > 
> > > > > Taking a step back, if one field in a new event in the future
> > > > > happens to be odd, we could still fetch field in its own way:
> > > > > event->evt[4] is still available to extract via FIELD_GET; or
> > > > > just define another union exclusively for that event, neither
> > > > > of which sounds like the end of world.
> > > > > 
> > > > > Having said that, I'd defer to Will. So, here is just my two
> > > > > cents.
> > > > 
> > > > My only real concern is the fragility of using bitfields. I don't _think_
> > > > the compiler is obliged to lay them out in the obvious way and I can't
> > > > think of anything worse than being given a bad pretty-print when debugging
> > > > a real driver issue!
> > 
> > Well, if compiler is going to be an issue, I can't disagree with
> > your point.
> > 
> > Any reference to some existing issue with compiler failing to lay
> > out properly? I wonder how other headers could define their unions
> > using bitfields and stay safe..
> 
> It's not so much about buggy compilers, but more that I don't think the
> C standard defines the order and so relying on it can be fragile. If you
> fancy going to the effort of ensuring that LLVM and GCC will agree on
> the "obvious" layout forever more, then don't let me stop you ;)
> 

Hmmm.. +1
I had some time, so.. I dived into the C specification[1] (free draft)
to look for bitfield layouts, under section 6.7.2.1, point 11 
(page 101 of the pdf), and I see the following paragraph:

"An implementation may allocate any addressable storage unit large
enough to hold a bit-field. If enough space remains, a bit-field that
immediately follows another bit-field in a structure shall be packed
into adjacent bits of the same unit. If insufficient space remains,
whether a bit-field that does not fit is put into the next unit or
overlaps adjacent units is implementation-defined. The order of 
allocation of bit-fields within a unit (high-order to low-order or 
low-order to high-order) is implementation-defined. The alignment
of the addressable storage unit is unspecified."

However, I'm not sure how these "implementations" comprehend the spec.

> Will

> > I am trying to learn here: apart from what Will mentioned above,
> > is there any other reason to stay away from bitfield?

One more thing I can think of is Alignment faults on certain archs.
Accessing individual bitfields within the struct could lead to unaligned
memory accesses. I have run into alignment faults on $ARCH=arm64 couple
of times while using packed structs in the kernel code.

[1]
 https://web.archive.org/web/20181230041359if_/http://www.open-std.org/jtc1/sc22/wg14/www/abq/c17_updated_proposed_fdis.pdf

Thanks,
Pranjal

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 1/2] iommu/arm-smmu-v3: Print better events records
  2024-09-09 17:30                         ` Pranjal Shrivastava
@ 2024-09-10  4:43                           ` Nicolin Chen
  0 siblings, 0 replies; 19+ messages in thread
From: Nicolin Chen @ 2024-09-10  4:43 UTC (permalink / raw)
  To: Pranjal Shrivastava
  Cc: Will Deacon, Robin Murphy, Joerg Roedel, Mostafa Saleh,
	iommu@lists.linux.dev, Daniel Mentz

On Mon, Sep 09, 2024 at 05:30:22PM +0000, Pranjal Shrivastava wrote:

> > > > > My only real concern is the fragility of using bitfields. I don't _think_
> > > > > the compiler is obliged to lay them out in the obvious way and I can't
> > > > > think of anything worse than being given a bad pretty-print when debugging
> > > > > a real driver issue!
> > >
> > > Well, if compiler is going to be an issue, I can't disagree with
> > > your point.
> > >
> > > Any reference to some existing issue with compiler failing to lay
> > > out properly? I wonder how other headers could define their unions
> > > using bitfields and stay safe..
> >
> > It's not so much about buggy compilers, but more that I don't think the
> > C standard defines the order and so relying on it can be fragile. If you
> > fancy going to the effort of ensuring that LLVM and GCC will agree on
> > the "obvious" layout forever more, then don't let me stop you ;)

I see!
 
> Hmmm.. +1
> I had some time, so.. I dived into the C specification[1] (free draft)
> to look for bitfield layouts, under section 6.7.2.1, point 11
> (page 101 of the pdf), and I see the following paragraph:
> 
> "An implementation may allocate any addressable storage unit large
> enough to hold a bit-field. If enough space remains, a bit-field that
> immediately follows another bit-field in a structure shall be packed
> into adjacent bits of the same unit. If insufficient space remains,
> whether a bit-field that does not fit is put into the next unit or
> overlaps adjacent units is implementation-defined. The order of
> allocation of bit-fields within a unit (high-order to low-order or
> low-order to high-order) is implementation-defined. The alignment
> of the addressable storage unit is unspecified."

Thanks for digging into the standard doc!

> However, I'm not sure how these "implementations" comprehend the spec.
> 
> > Will
> 
> > > I am trying to learn here: apart from what Will mentioned above,
> > > is there any other reason to stay away from bitfield?
> 
> One more thing I can think of is Alignment faults on certain archs.
> Accessing individual bitfields within the struct could lead to unaligned
> memory accesses. I have run into alignment faults on $ARCH=arm64 couple
> of times while using packed structs in the kernel code.

OK. It seems that we should stay safe with verbose FIELD_GETs then.

Thank you
Nicolin

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v2 1/2] iommu/arm-smmu-v3: Print better events records
  2024-08-29 23:54     ` Pranjal Shrivastava
  2024-08-30  1:45       ` Nicolin Chen
@ 2024-11-04 16:40       ` Daniel Mentz
  1 sibling, 0 replies; 19+ messages in thread
From: Daniel Mentz @ 2024-11-04 16:40 UTC (permalink / raw)
  To: Pranjal Shrivastava
  Cc: Nicolin Chen, Joerg Roedel, Will Deacon, Robin Murphy,
	Mostafa Saleh, iommu@lists.linux.dev

On Thu, Aug 29, 2024 at 4:54 PM Pranjal Shrivastava <praan@google.com> wrote:
>
> On Wed, Aug 28, 2024 at 11:36:02PM -0700, Nicolin Chen wrote:
> > > +static void arm_smmu_dump_xlation_fault(struct arm_smmu_device *smmu,
> > > +                                       struct arm_smmu_event *event)
> > > +{
> > > +       dev_err(smmu->dev, "Fault: %s client %s sid 0x%08x.0x%05x:\n",
> >
> > "client" doesn't seem to be used anywhere in this driver, I would:
> > s/client/master
> >
>
> Ack, would change this to "master".

To align with Documentation/process/coding-style.rst , I propose using
the term "client" as it can be considered "new usage". In this driver,
there are no existing log messages that use the word "master". The Arm
SMMUv3 arch spec consistently uses the term "client device" and
completely avoids the term "master". (The Arm MMU-700 TRM does use the
master/slave terminology)

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2024-11-04 16:41 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-08-27 19:30 [PATCH v2 0/2] iommu/arm-smmu-v3: Parse out event records Pranjal Shrivastava
2024-08-27 19:30 ` [PATCH v2 1/2] iommu/arm-smmu-v3: Print better events records Pranjal Shrivastava
2024-08-29  6:36   ` Nicolin Chen
2024-08-29 23:54     ` Pranjal Shrivastava
2024-08-30  1:45       ` Nicolin Chen
2024-09-02  8:23         ` Pranjal Shrivastava
2024-09-02 23:02           ` Nicolin Chen
2024-09-05 16:06             ` Pranjal Shrivastava
2024-09-06  1:55               ` Nicolin Chen
2024-09-06 12:55                 ` Will Deacon
2024-09-06 16:39                   ` Robin Murphy
2024-09-06 18:42                     ` Nicolin Chen
2024-09-09 14:45                       ` Will Deacon
2024-09-09 17:30                         ` Pranjal Shrivastava
2024-09-10  4:43                           ` Nicolin Chen
2024-11-04 16:40       ` Daniel Mentz
2024-08-27 19:30 ` [PATCH v2 2/2] iommu/arm-smmu-v3: Adopt arm_smmu_event in handlers Pranjal Shrivastava
2024-08-29  5:20   ` Nicolin Chen
2024-08-30  0:06     ` Pranjal Shrivastava

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.