MTRR patch causes system lockups

Emil Briggs (briggs@bucky.physics.ncsu.edu)
Thu, 15 Jan 1998 17:26:18 -0500 (EST)


The MTRR setting patch can cause a system lockup for certain
motherboards/bioses using the Natoma chipset. I've tested this
under two P6 motherboards so far and obtained the same results.
Heres the conditions under which the lockup occurs.

1. write combining to the linear frame buffer is enabled
2. passive release is not enabled in the PIIX3 (bit 1 offset 82h)
3. access to the floppy drive at the same time as large transfers
to the LFB are occuring.

I tested this by starting up X in 8 bpp mode then doing

dd if=testfile of=/dev/fd0 bs=1k

testfile being around 1 Meg -- then run the dga benchmark that
comes with XFree86. System locks up every time. I found the fix
information in an Intel spec update sheet for the 440FX chipset
available at

http://www.intel.com/design/pcisets/specupdt/297654.htm

A deadlock condition occurs unless the passive release bit
is enabled. The lockups would probably occur with any device
that uses the PIIX3 for anything (i.e. sound card) not just the floppy.

This probably doesn't effect every P6 board using the 440FX
chipset -- both systems I tested use an AMI bios which doesn't
set things up correctly. The following C program is a quick and
dirty fix. Probably should add a test to the mtrr kernel patch to
make sure the passive release bit is set if write combining is
enabled for the LFB.

---------------------------------------------------------
/*

Run as root -- sets passive release enable bit on P6 boards
using the 440FX chipset.

Compile using -O2 for out macros.

*/


#include <asm/io.h>
#include <stdio.h>

#define PCI_CONFIG 0xcf8
#define PCI_DATA 0xcfc

main()
{

unsigned confreg;
unsigned char inbyte;

/* Turn on iopl */
iopl(3);


/* Bus 0, slot 7, function 0, dword 32 in PCI-config space */
/* Don't use pcibios here in case it's broken */
confreg = (1 << 31) + (7 << 11) + (32 << 2);

/* Offset 2 */
outl(confreg, PCI_CONFIG);
inbyte = inb(PCI_DATA + 2);
printf("Passive release bit status = %d\n", (inbyte & 2));

/* set bit 1 */
inbyte = inbyte | 2;
outb(inbyte, PCI_DATA + 2);


/* Make sure */
outl(confreg, PCI_CONFIG);
inbyte = inb(PCI_DATA + 2);
printf("Passive release bit status = %d\n", (inbyte & 2));

}