Subject: Re: DPWS500/Pyxis bugs, corrupt memory etc.
To: None <port-alpha@netbsd.org>
From: Jason Thorpe <thorpej@nas.nasa.gov>
List: port-alpha
Date: 02/05/2000 16:36:55
On Sat, 05 Feb 2000 11:53:26 -0800 
 Jason Thorpe <thorpej@nas.nasa.gov> wrote:

 > On Fri, 4 Feb 2000 20:39:11 -0500 (EST) 
 >  Andrew Gallatin <gallatin@cs.duke.edu> wrote:
 > 
 >  > Unless this information is in error or the NetBSD driver does
 >  > something clever & combines transactions so that they are > PAGE_SIZE,
 >  > I'm not sure where the original poster's IDE corruption is coming
 >  > from.
 > 
 > The NetBSD bus_dma implementation DOES indeed do this.  I will fix this
 > RSN (i.e. work out some hueristic to make this NOT happen in the cases
 > where it matters on the buggy Pyxis revs).

This patch should fix the problem for PCI IDE, at least.  It's still
not perfect... for example, it doens't fix the problem for any ISA
DMA that might be restricted to one DMA segment (e.g. things that
use the on-board ISA DMA controller, like the floppy drive), and
prevents coalescing on busses that don't have the problem (i.e.
ones behind the PCI-PCI bridge).

...but it should stop the major issue of corrupted file system data,
at least.

I'll have this pulled up into the 1.4.2 branch.

Man, I wish I'd had access to a Miata when they first came out...

        -- Jason R. Thorpe <thorpej@nas.nasa.gov>

Index: common/bus_dma.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/alpha/common/bus_dma.c,v
retrieving revision 1.35
diff -c -r1.35 bus_dma.c
*** bus_dma.c	2000/01/20 17:16:25	1.35
--- bus_dma.c	2000/02/06 00:11:52
***************
*** 201,207 ****
  			map->dm_segs[seg].ds_len = sgsize;
  			first = 0;
  		} else {
! 			if (curaddr == lastaddr &&
  			    (map->dm_segs[seg].ds_len + sgsize) <=
  			     map->_dm_maxsegsz &&
  			    (map->_dm_boundary == 0 ||
--- 201,208 ----
  			map->dm_segs[seg].ds_len = sgsize;
  			first = 0;
  		} else {
! 			if ((map->_dm_flags & DMAMAP_NO_COALESCE) == 0 &&
! 			    curaddr == lastaddr &&
  			    (map->dm_segs[seg].ds_len + sgsize) <=
  			     map->_dm_maxsegsz &&
  			    (map->_dm_boundary == 0 ||
Index: include/bus.h
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/alpha/include/bus.h,v
retrieving revision 1.31
diff -c -r1.31 bus.h
*** bus.h	2000/01/25 22:13:17	1.31
--- bus.h	2000/02/06 00:11:54
***************
*** 430,435 ****
--- 430,437 ----
  /*
   * Private flags stored in the DMA map.
   */
+ #define	DMAMAP_NO_COALESCE	0x40000000	/* don't coalesce adjacent
+ 						   segments */
  #define	DMAMAP_HAS_SGMAP	0x80000000	/* sgva/len are valid */
  
  /* Forwards needed by prototypes below. */
Index: pci/cia.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/alpha/pci/cia.c,v
retrieving revision 1.50
diff -c -r1.50 cia.c
*** cia.c	2000/02/01 19:29:28	1.50
--- cia.c	2000/02/06 00:11:57
***************
*** 330,338 ****
  		 * PCI-ISA bridge (i.e. Miata 1.5 and Miata 2) do not
  		 * have the bug, so we use this check.
  		 *
! 		 * XXX We also need to deal with this boundary constraint
! 		 * XXX in the PCI bus 0 (and ISA) DMA tags, but some
! 		 * XXX drivers are going to need to be changed first.
  		 */
  		u_int32_t ctrl;
  
--- 330,340 ----
  		 * PCI-ISA bridge (i.e. Miata 1.5 and Miata 2) do not
  		 * have the bug, so we use this check.
  		 *
! 		 * NOTE: This bug is actually worked around in cia_dma.c,
! 		 * when direct-mapped DMA maps are created.
! 		 *
! 		 * XXX WE NEED TO THINK ABOUT HOW TO HANDLE THIS FOR
! 		 * XXX SGMAP DMA MAPPINGS!
  		 */
  		u_int32_t ctrl;
  
Index: pci/cia_dma.c
===================================================================
RCS file: /cvsroot/syssrc/sys/arch/alpha/pci/cia_dma.c,v
retrieving revision 1.14
diff -c -r1.14 cia_dma.c
*** cia_dma.c	2000/01/25 03:32:36	1.14
--- cia_dma.c	2000/02/06 00:11:58
***************
*** 58,63 ****
--- 58,66 ----
  
  bus_dma_tag_t cia_dma_get_tag __P((bus_dma_tag_t, alpha_bus_t));
  
+ int	cia_bus_dmamap_create_direct __P((bus_dma_tag_t, bus_size_t, int,
+ 	    bus_size_t, bus_size_t, int, bus_dmamap_t *));
+ 
  int	cia_bus_dmamap_create_sgmap __P((bus_dma_tag_t, bus_size_t, int,
  	    bus_size_t, bus_size_t, int, bus_dmamap_t *));
  
***************
*** 118,124 ****
  	t->_boundary = 0;
  	t->_sgmap = NULL;
  	t->_get_tag = cia_dma_get_tag;
! 	t->_dmamap_create = _bus_dmamap_create;
  	t->_dmamap_destroy = _bus_dmamap_destroy;
  	t->_dmamap_load = _bus_dmamap_load_direct;
  	t->_dmamap_load_mbuf = _bus_dmamap_load_mbuf_direct;
--- 121,127 ----
  	t->_boundary = 0;
  	t->_sgmap = NULL;
  	t->_get_tag = cia_dma_get_tag;
! 	t->_dmamap_create = cia_bus_dmamap_create_direct;
  	t->_dmamap_destroy = _bus_dmamap_destroy;
  	t->_dmamap_load = _bus_dmamap_load_direct;
  	t->_dmamap_load_mbuf = _bus_dmamap_load_mbuf_direct;
***************
*** 282,287 ****
--- 285,334 ----
  	default:
  		panic("cia_dma_get_tag: shouldn't be here, really...");
  	}
+ }
+ 
+ /*
+  * Create a CIA direct-mapped DMA map.
+  */
+ int
+ cia_bus_dmamap_create_direct(t, size, nsegments, maxsegsz, boundary,
+     flags, dmamp)
+ 	bus_dma_tag_t t;
+ 	bus_size_t size;
+ 	int nsegments;
+ 	bus_size_t maxsegsz;
+ 	bus_size_t boundary;
+ 	int flags;
+ 	bus_dmamap_t *dmamp;
+ {
+ 	struct cia_config *ccp = t->_cookie;
+ 	bus_dmamap_t map;
+ 	int error;
+ 
+ 	error = _bus_dmamap_create(t, size, nsegments, maxsegsz,
+ 	    boundary, flags, dmamp);
+ 	if (error)
+ 		return (error);
+ 
+ 	map = *dmamp;
+ 
+ 	if ((ccp->cc_flags & CCF_PYXISBUG) != 0 &&
+ 	    map->_dm_segcnt > 1) {
+ 		/*
+ 		 * We have a Pyxis with the DMA page crossing bug, make
+ 		 * sure we don't coalesce adjacent DMA segments.
+ 		 *
+ 		 * NOTE: We can only do this if the max segment count
+ 		 * is greater than 1.  This is because many network
+ 		 * drivers allocate large contiguous blocks of memory
+ 		 * for control data structures, even though they won't
+ 		 * do any single DMA that crosses a page coundary.
+ 		 *	-- thorpej@netbsd.org, 2/5/2000
+ 		 */
+ 		map->_dm_flags |= DMAMAP_NO_COALESCE;
+ 	}
+ 
+ 	return (0);
  }
  
  /*