Bug 25781

Summary: Statclocks cannot be disabled on ServerWorks chipset (MB: Acer Altos 1200, Tyan S2510, ...) if APM is enabled in SMP environment
Product: Base System Reporter: belian <belian>
Component: i386Assignee: Remko Lodder <remko>
Status: Closed FIXED    
Severity: Affects Only Me    
Priority: Normal    
Version: Unspecified   
Hardware: Any   
OS: Any   

Description belian 2001-03-13 20:50:00 UTC
The problem occurs with the two-processors configuration on the motherboards with 
ServerWorks chipset (such as described in the Environment section).

The following configuration leads to freezing computer before mounting root partition:

# To make an SMP kernel, the next two are needed
options 	SMP			# Symmetric MultiProcessor Kernel
options 	APIC_IO			# Symmetric (APIC) I/O

# Power management support (see LINT for more options)
device		apm0    at nexus? flags 0x20 # Advanced Power Management

Fix: 

It is necessary to fix the procedure cpu_initclocks() from /usr/src/sys/i386/isa/clock.c:


/*
 * Start both clocks running.
 */
void
cpu_initclocks()


There we have that part:



	if (statclock_disable) {
		/*
		 * The stat interrupt mask is different without the
		 * statistics clock.  Also, don't set the interrupt
		 * flag which would normally cause the RTC to generate
		 * interrupts.
		 */
		stat_imask = HWI_MASK | SWI_MASK;
		rtc_statusb = RTCSB_24HR;
	} else {
	        /* Setting stathz to nonzero early helps avoid races. */
		stathz = RTC_NOPROFRATE;
		profhz = RTC_PROFRATE;
        }




For which flag 0x20 in the apm(4) is sufficient. That's Ok. But than:




	/* Finish initializing 8253 timer 0. */
#ifdef APIC_IO

	apic_8254_intr = isa_apic_irq(0);
	apic_8254_trial = 0;
	if (apic_8254_intr >= 0 ) {
		if (apic_int_type(0, 0) == 3)
			apic_8254_trial = 1;
	} else {
		/* look for ExtInt on pin 0 */
		if (apic_int_type(0, 0) == 3) {
			apic_8254_intr = apic_irq(0, 0);
			setup_8254_mixed_mode();
		} else 
			panic("APIC_IO: Cannot route 8254 interrupt to CPU");
	}





we are detecting the flag ``apic_8254_trial''. That flag, as I understand,
indicates that the check if 8254 is broken (or, at least, non-standard) should be
performed. That's Ok as well. And now we do the following:





	clkdesc = inthand_add("clk", apic_8254_intr, (inthand2_t *)clkintr,
			      NULL, &clk_imask, INTR_EXCL);
	INTREN(1 << apic_8254_intr);
	
#else /* APIC_IO */

	inthand_add("clk", 0, (inthand2_t *)clkintr, NULL, &clk_imask,
		    INTR_EXCL);
	INTREN(IRQ0);

#endif /* APIC_IO */

	/* Initialize RTC. */
	writertc(RTC_STATUSA, rtc_statusa);
	writertc(RTC_STATUSB, RTCSB_24HR);

	/* Don't bother enabling the statistics clock. */
	if (statclock_disable)
		return;



- and those check, the necessaty of wich we marked in the previous piece of code
will NEVER be done if we want to disable statclock. That's obviously wrong because
in the case of the non-standard 8254 we will handle it in the wrong way.




	diag = rtcin(RTC_DIAG);
	if (diag != 0)
		printf("RTC BIOS diagnostic error %b\n", diag, RTCDG_BITS);

#ifdef APIC_IO
	if (isa_apic_irq(8) != 8)
		panic("APIC RTC != 8");
#endif /* APIC_IO */

	inthand_add("rtc", 8, (inthand2_t *)rtcintr, NULL, &stat_imask,
		    INTR_EXCL);

#ifdef APIC_IO
	INTREN(APIC_IRQ8);
#else
	INTREN(IRQ8);
#endif /* APIC_IO */

	writertc(RTC_STATUSB, rtc_statusb);

#ifdef APIC_IO
	if (apic_8254_trial) {
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^




The testing that should be done is here. As you can see it is necessary only if we
have APIC_IO defined, i.e. in the SMP environment.

It is possible that we need early return from the procedure if statclock is
disabled but proper initialization of the APIC should be done anyway!

Also, probably ``flags 0x20'' should be deleted from the standard GENERIC kernel
since the most popular way of building new kernel config is stripping GENERIC
config people can getting trouble leaving that flag: from the comment in the LINT
it is absolutely unclear why it should be removed. At least, the comment about
the trouble described above is necessary in that remark in the LINT config since
it is not obvious at all that the apm flags can influence on the kernel boot-time
freezes.



By the way, it will be nice to have workaround for just turning power off without
including all those big and (as said in the man pages) instable code in order to
make possible to use FreeBSD on heavy-servers configurations without console at
all.
How-To-Repeat: 
1) Include the srings above to the kernel config
2) Compile the kernel with the obtain config on the MB with ServerWorks chipset and
   dual processors
3) Boot

After hardware initialization computer will freeze.
Comment 1 Tilman Keskinoz freebsd_committer freebsd_triage 2004-05-20 12:32:23 UTC
Responsible Changed
From-To: freebsd-bugs->freebsd-i386

This is i386-specific
Comment 2 Remko Lodder freebsd_committer freebsd_triage 2006-03-19 16:25:41 UTC
State Changed
From-To: open->feedback

Hi, 

Can you tell me whether this is still applicable to a modern 
world? (read: FreeBSD 5.4 and/or 6.0 or even the BETA's that 
were just released). 


Comment 3 Remko Lodder freebsd_committer freebsd_triage 2006-03-19 16:25:41 UTC
Responsible Changed
From-To: freebsd-i386->remko

Grab the PR so that i can track the feedback etc.
Comment 4 Remko Lodder freebsd_committer freebsd_triage 2006-03-20 17:13:39 UTC
State Changed
From-To: feedback->closed

The submitter does no longer own a ServerWorks LE based 
motherboard so this cannot be tested anymore.  Also the 
submitter (and I do as well) thinks that the problem is 
outdated.  I will close the PR with the assumption that 
it had been solved.  The submitter had been informed 
that if the problem still persists he should contact me 
so that i can try to obtain more information and delegate 
this to the proper person.