Subject: port-mips/26959: mips mc_cpuspeed() returns wrong value on gcc3
To: None <gnats-bugs@gnats.NetBSD.org>
From: None <tsutsui@ceres.dti.ne.jp>
List: netbsd-bugs
Date: 09/16/2004 00:16:06
>Number:         26959
>Category:       port-mips
>Synopsis:       mips mc_cpuspeed() returns wrong value on gcc3
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    port-mips-maintainer
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Wed Sep 15 15:17:00 UTC 2004
>Closed-Date:
>Last-Modified:
>Originator:     Izumi Tsutsui
>Release:        NetBSD 1.6ZE and later
>Organization:
>Environment:
NetBSD 1.6ZE
Architecture: mips
Machine: pmax
>Description:
pmax (and maybe some other mips ports) use mc_cpuspeed() and
mips_mcclock_tickloop() in mips_mccloc.c to determine their CPU clock,
but after gcc3 import mips_mcclock_tickloop() returns smaller values
at least on DECstation 5000/125.

In article <031223212041.M0103669@mirage.ceres.dti.ne.jp> on port-pmax
I wrote:

> BTW, I think mc_cpuspeed() in arch/mips/mips/mips_mcclock.c also
> might have some problem with gcc3. Kernels compiled by gcc3
> detect machine clock incorrectly on my 3MIN (5000/125):
> 
> >> NetBSD 1.6ZD (PROUDIA) #29: Sun Oct 26 15:12:26 JST 2003
> >>        tsutsui@mirage:/usr/src/sys/arch/pmax/compile/PROUDIA
> >> DECstation 5000/125 (3MIN)
> >> total memory = 98304 KB
> >> avail memory = 87980 KB
> 
> >> NetBSD 1.6ZE (PROUDIA) #30: Mon Oct 27 02:03:15 JST 2003
> >>        tsutsui@mirage:/usr/src/sys/arch/pmax/compile/PROUDIA
> >> DECstation 5000/120 (3MIN)
> >> total memory = 98304 KB
> >> avail memory = 88068 KB

The following iteration code is used to measure CPU clock
in mips_mcclock_tickloop():
---
	while ((mips_cp0_cause_read() & clockmask) == 0) {
		__asm __volatile ("nop; nop; nop; nop");
		iters++;
	}
---

gcc-2.95.3 generates:
---
	j	2f
	 nop
1:	nop					# __asm __volatile (nop; ...);
	nop
	nop
	nop
	addiu	s0, s0, 1			# iters++;
2:	jal	_C_LABEL(mips_cp0_cause_read)	# v0 = mips_cp0_cause_read();
	 nop
	and	v0, v0, s1			# v0 & clockmask
	beqz	v0, 1b				# if zero then repeat
	 move	v0, s0				# for return (iters);

	j	3f
	 nop
	[...]
3:
---
In this case each iteration contains 10 instructions.

but gcc-3.3.3 generates deferent code:
---
1:	jal	_C_LABEL(mips_cp0_cause_read)	# v0 = mips_cp0_cause_read();
	 nop
	and	v0, v0, s0			# v0 & clockmask
	bnez	v0, 2f				# if !zero then break
	 nop
	nop					# __asm __volatile (nop; ...);
	nop
	nop
	nop
	j	1b
	 addiu	s1, s1, 1			# iters++;
2:	[...]
---
Each loop contains 11 instructions so it returns different iters
from the previous one.

>How-To-Repeat:
boot kernel on DECstation 5000/125 (and other pmaxen)
then the kernel shows wrong machine model name like the above.

>Fix:
An easy fix is to remove one dummy nop from __asm lines (as attached),
but I guess such code should not depend on compiler and should be
written in asm.

Index: mips/mips/mips_mcclock.c
===================================================================
RCS file: /cvsroot/src/sys/arch/mips/mips/mips_mcclock.c,v
retrieving revision 1.11
diff -u -r1.11 mips_mcclock.c
--- mips/mips/mips_mcclock.c	5 Mar 2002 15:54:33 -0000	1.11
+++ mips/mips/mips_mcclock.c	15 Sep 2004 15:01:27 -0000
@@ -166,12 +166,12 @@
 	/* Count loops until next tick-interrupt request occurs (4ms). */
 	if (MIPS_HAS_CLOCK) {
 		while ((mips_cp0_cause_read() & clockmask) == 0) {
-			__asm __volatile ("nop; nop; nop; nop");
+			__asm __volatile ("nop; nop; nop");
 			iters++;
 		}
 	} else {
 		while ((mips_cp0_cause_read() & clockmask) == 0) {
-			__asm __volatile ("nop; nop;");
+			__asm __volatile ("nop;");
 			iters++;
 		}
 	}
>Release-Note:
>Audit-Trail:
>Unformatted: