[PATCH] irqchip/gic-v3-its: handle rd_idx wrapping in its_wait_for_range_completion()

Yang Yingliang yangyingliang at huawei.com
Sat Feb 10 19:42:01 PST 2018


In direct case, rd_idx will wrap if other cpus post commands
that make rd_idx increase. When rd_idx wrapped, the driver prints
timeout messages but in fact the command is finished. To handle
this case by adding last_rd_id to check rd_idx whether wrapped.

Signed-off-by: Yang Yingliang <yangyingliang at huawei.com>
---
 drivers/irqchip/irq-gic-v3-its.c | 84 ++++++++++++++++++++++------------------
 1 file changed, 46 insertions(+), 38 deletions(-)

diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 06f025f..d7176d1 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -713,7 +713,8 @@ static void its_flush_cmd(struct its_node *its, struct its_cmd_block *cmd)
 
 static int its_wait_for_range_completion(struct its_node *its,
 					 struct its_cmd_block *from,
-					 struct its_cmd_block *to)
+					 struct its_cmd_block *to,
+					 u64 last_rd_idx)
 {
 	u64 rd_idx, from_idx, to_idx;
 	u32 count = 1000000;	/* 1s! */
@@ -724,9 +725,14 @@ static int its_wait_for_range_completion(struct its_node *its,
 	while (1) {
 		rd_idx = readl_relaxed(its->base + GITS_CREADR);
 
-		/* Direct case */
-		if (from_idx < to_idx && rd_idx >= to_idx)
-			break;
+
+		/*
+		 * Direct case. In this case, rd_idx may wrapped,
+		 * because other cpus may post commands that make
+		 * rd_idx increase.
+		 */
+		if (from_idx < to_idx && (rd_idx >= to_idx || rd_idx < last_rd_idx))
+				break;
 
 		/* Wrapped case */
 		if (from_idx >= to_idx && rd_idx >= to_idx && rd_idx < from_idx)
@@ -746,40 +752,42 @@ static int its_wait_for_range_completion(struct its_node *its,
 }
 
 /* Warning, macro hell follows */
-#define BUILD_SINGLE_CMD_FUNC(name, buildtype, synctype, buildfn)	\
-void name(struct its_node *its,						\
-	  buildtype builder,						\
-	  struct its_cmd_desc *desc)					\
-{									\
-	struct its_cmd_block *cmd, *sync_cmd, *next_cmd;		\
-	synctype *sync_obj;						\
-	unsigned long flags;						\
-									\
-	raw_spin_lock_irqsave(&its->lock, flags);			\
-									\
-	cmd = its_allocate_entry(its);					\
-	if (!cmd) {		/* We're soooooo screewed... */		\
-		raw_spin_unlock_irqrestore(&its->lock, flags);		\
-		return;							\
-	}								\
-	sync_obj = builder(its, cmd, desc);				\
-	its_flush_cmd(its, cmd);					\
-									\
-	if (sync_obj) {							\
-		sync_cmd = its_allocate_entry(its);			\
-		if (!sync_cmd)						\
-			goto post;					\
-									\
-		buildfn(its, sync_cmd, sync_obj);			\
-		its_flush_cmd(its, sync_cmd);				\
-	}								\
-									\
-post:									\
-	next_cmd = its_post_commands(its);				\
-	raw_spin_unlock_irqrestore(&its->lock, flags);			\
-									\
-	if (its_wait_for_range_completion(its, cmd, next_cmd))		\
-		pr_err_ratelimited("ITS cmd %ps failed\n", builder);	\
+#define BUILD_SINGLE_CMD_FUNC(name, buildtype, synctype, buildfn)		\
+void name(struct its_node *its,							\
+	  buildtype builder,							\
+	  struct its_cmd_desc *desc)						\
+{										\
+	struct its_cmd_block *cmd, *sync_cmd, *next_cmd;			\
+	synctype *sync_obj;							\
+	unsigned long flags;							\
+	u64 last_rd_idx;							\
+										\
+	raw_spin_lock_irqsave(&its->lock, flags);				\
+										\
+	cmd = its_allocate_entry(its);						\
+	if (!cmd) {		/* We're soooooo screewed... */			\
+		raw_spin_unlock_irqrestore(&its->lock, flags);			\
+		return;								\
+	}									\
+	sync_obj = builder(its, cmd, desc);					\
+	its_flush_cmd(its, cmd);						\
+										\
+	if (sync_obj) {								\
+		sync_cmd = its_allocate_entry(its);				\
+		if (!sync_cmd)							\
+			goto post;						\
+										\
+		buildfn(its, sync_cmd, sync_obj);				\
+		its_flush_cmd(its, sync_cmd);					\
+	}									\
+										\
+post:										\
+	next_cmd = its_post_commands(its);					\
+	last_rd_idx = readl_relaxed(its->base + GITS_CREADR);			\
+	raw_spin_unlock_irqrestore(&its->lock, flags);				\
+										\
+	if (its_wait_for_range_completion(its, cmd, next_cmd, last_rd_idx))	\
+		pr_err_ratelimited("ITS cmd %ps failed\n", builder);		\
 }
 
 static void its_build_sync_cmd(struct its_node *its,
-- 
1.8.3





More information about the linux-arm-kernel mailing list