Subject: [PATCH 2/2][MIPS] add irq_disable_hazard() before c0_compare_int_pending()

From: Yoichi Yuasa <[email-masked]>
Date: Mon, 17 Mar 2008 23:49:42 +0900

Add irq_disable_hazard() before c0_compare_int_pending().

VR41xx sometime fails at this point.
It can be fix this patch.

Signed-off-by: Yoichi Yuasa <[email-masked]>

diff -pruN -X /home/yuasa/Memo/dontdiff linux-orig/arch/mips/kernel/cevt-r4k.c linux/arch/mips/kernel/cevt-r4k.c
--- linux-orig/arch/mips/kernel/cevt-r4k.c	2008-03-12 16:37:31.317624763 +0900
+++ linux/arch/mips/kernel/cevt-r4k.c	2008-03-12 16:37:39.894113510 +0900
@@ -205,6 +205,7 @@ static int c0_compare_int_usable(void)
 	while ((int)(read_c0_count() - cnt) <= 0)
 		;	/* Wait for expiry  */
 
+	irq_disable_hazard();
 	if (!c0_compare_int_pending())
 		return 0;

---

From: Yoichi Yuasa <[email-masked]>
Date: Mon, 17 Mar 2008 23:47:40 +0900

VR41xx, CP0 hazard is necessary between read_c0_count() and write_c0_compare().
However, the problem can be solved by replacing this by c0_timer_ack(). 

diff -pruN -X /home/yuasa/Memo/dontdiff linux-orig/arch/mips/kernel/cevt-r4k.c linux/arch/mips/kernel/cevt-r4k.c
--- linux-orig/arch/mips/kernel/cevt-r4k.c	2008-03-11 10:10:09.453835304 +0900
+++ linux/arch/mips/kernel/cevt-r4k.c	2008-03-12 16:35:42.911447048 +0900
@@ -186,7 +186,7 @@ static int c0_compare_int_usable(void)
 	 * IP7 already pending?  Try to clear it by acking the timer.
 	 */
 	if (c0_compare_int_pending()) {
-		write_c0_compare(read_c0_count());
+		c0_timer_ack();
 		irq_disable_hazard();
 		if (c0_compare_int_pending())
 			return 0;
@@ -198,7 +198,7 @@ static int c0_compare_int_usable(void)
 		write_c0_compare(cnt);
 		irq_disable_hazard();
 		if ((int)(read_c0_count() - cnt) < 0)
-		    break;
+			break;
 		/* increase delta if the timer was already expired */
 	}
 
@@ -208,7 +208,7 @@ static int c0_compare_int_usable(void)
 	if (!c0_compare_int_pending())
 		return 0;
 
-	write_c0_compare(read_c0_count());
+	c0_timer_ack();
 	irq_disable_hazard();
 	if (c0_compare_int_pending())
 		return 0;

---

From: Ralf Baechle <[email-masked]>
Date: Mon, 17 Mar 2008 16:16:35 +0000

> VR41xx, CP0 hazard is necessary between read_c0_count() and write_c0_compare().

Interesting.  I wonder why you need this patch but nobody else?

  Ralf

---

From: Yoichi Yuasa <[email-masked]>
Date: Tue, 18 Mar 2008 13:47:20 +0900

Hi Ralf,

On Mon, 17 Mar 2008 16:16:35 +0000

> Interesting.  I wonder why you need this patch but nobody else?

Three NOP are necessary on the TB0287(VR4131 board).

Yoichi

---

From: Ralf Baechle <[email-masked]>
Date: Tue, 18 Mar 2008 13:27:09 +0000

> Three NOP are necessary on the TB0287(VR4131 board).

That much was obvious from your patch.  I was more wondering about this
change:

c0_timer_ack is defined as

static void c0_timer_ack(void)
{
        write_c0_compare(read_c0_compare());
}

so your patch does a functional change there - even though it should not
actually matter.  So I was wondering if for some reason you need that
change.

Just interested - it looks a bit cleaner so I'm leaning to apply this
change anyway.

  Ralf

---

From: Yoichi Yuasa <[email-masked]>
Date: Wed, 19 Mar 2008 16:38:47 +0900

Hi,

On Tue, 18 Mar 2008 13:27:09 +0000

> actually matter.  So I was wondering if for some reason you need that

OK, update my patch.
Two patches have been brought together in one.

How about this?

VR41xx, CP0 hazard is necessary between read_c0_count() and write_c0_compare()
(or read_c0_cause()).

diff -pruN -X /home/yuasa/Memo/dontdiff linux-orig/arch/mips/kernel/cevt-r4k.c linux/arch/mips/kernel/cevt-r4k.c
--- linux-orig/arch/mips/kernel/cevt-r4k.c	2008-03-19 11:35:53.017749179 +0900
+++ linux/arch/mips/kernel/cevt-r4k.c	2008-03-19 16:31:29.617938142 +0900
@@ -186,7 +186,9 @@ static int c0_compare_int_usable(void)
 	 * IP7 already pending?  Try to clear it by acking the timer.
 	 */
 	if (c0_compare_int_pending()) {
-		write_c0_compare(read_c0_count());
+		cnt = read_c0_count();
+		back_to_back_c0_hazard();
+		write_c0_compare(cnt);
 		irq_disable_hazard();
 		if (c0_compare_int_pending())
 			return 0;
@@ -205,10 +207,13 @@ static int c0_compare_int_usable(void)
 	while ((int)(read_c0_count() - cnt) <= 0)
 		;	/* Wait for expiry  */
 
+	back_to_back_c0_hazard();
 	if (!c0_compare_int_pending())
 		return 0;
 
-	write_c0_compare(read_c0_count());
+	cnt = read_c0_count();
+	back_to_back_c0_hazard();
+	write_c0_compare(cnt);
 	irq_disable_hazard();
 	if (c0_compare_int_pending())
 		return 0;