*BSD News Article 15157


Return to BSD News archive

Path: sserve!newshost.anu.edu.au!munnari.oz.au!news.Hawaii.Edu!ames!haven.umd.edu!uunet!pipex!sunic!isgate!veda.is!adam
From: adam@veda.is (Adam David)
Newsgroups: comp.os.386bsd.bugs
Subject: Fixing SCSI DMA / cache problem
Message-ID: <C637wx.3HA@veda.is>
Date: 26 Apr 93 11:00:17 GMT
Organization: Veda Systems, Iceland
Lines: 72

Here's a quick and dirty fix to work around the broken motherboard problem.

Problem description:

The cache controller in the motherboard chipset does not invalidate the
cache when data is read into memory by DMA. This causes the cache and
external memory to be inconsistent with each other, resulting in files
"temporarily" containing random garbage in a non-predictable manner.

Possible solutions:

1) get a better motherboard. Known braindead chipsets include Headland,
no doubt many others exist. A lot of manufacturers still seem to be unaware
of the necessity to coordinate DMA and cache control so that they actually
work together without specialised software support.

2,3) disable or correctly invalidate the cache. Most 486 systems have a two
layer cache, the internal CPU cache is not always possible to configure in
the CMOS setup. In such cases it is either necessary to disable the internal
cache by writing some magic value to an unknown port address on the chipset,
or the software (in this case 386bsd) has to make sure the cache is not
allowed to become inconsistent after a DMA read operation. The external
cache is always possible to configure on or off in the CMOS setup, so the
simplest "quick fix" on 386 systems or those 486 systems that support it
is to simply disable all memory caching (but this runs slow).

4) Mark any memory pages uncachable before allowing DMA to them. This is
the best solution for how to successfully use these badly designed boards.
However, this method requires substantial rewriting of parts of the VM system
and will probably not be done before 386bsd 0.2.

On systems with a write-back cache it is to be hoped that the controller
takes care of maintaining consistency correctly. Otherwise the cache (if
enabled) would have to be flushed also before every DMA write operation.

The solution that I include here invalidates the 486 internal cache after
every DMA disk read operation. Until it is known how to invalidate the
external cache, it is necessary to disable the external cache in the CMOS
setup.

This is a really ugly fix, because it has to be done for every bus-mastering
device. Also the whole cache is invalidated, whether it needs to or not,
or the individual cache entries. This fix has at least made my motherboard
useable (though rather slow), pending a better fix. The same method could
be applied to other drivers, this one is Julian's low-level SCSI driver.

The fix:
============================================================================
*** aha1542.c.old	Mon Apr 26 10:31:49 1993
--- aha1542.c	Mon Apr 26 10:34:50 1993
***************
*** 898,901 ****
--- 898,904 ----
  	xs->flags |= ITSDONE;
  	aha_free_ccb(unit,ccb, xs->flags);
+ #ifdef BROKEN_CACHE
+ 	INVALIDATE_CACHE
+ #endif
  	if(xs->when_done)
  		(*(xs->when_done))(xs->done_arg,xs->done_arg2);
============================================================================

This relies on the otherwise unused INVALIDATE_CACHE macro that just happened
to be in the same file, perhaps there is a more strategic positioning for this
call. The macro could be improved on to allow the external cache to be enabled.

Thanks to prallon@nce.ufrj.br for pointing me in the right direction to get
this fix done. At last I am able to compile the kernel without perpetual
crashings (think of all those tiny header files bouncing around in the cache
space). Previously the compile would stop with an error when it found binary
garbage in the middle of source files, and the machine would often reboot
spontaneously before very long after that.