Subject: Re: bce(4) and memory > 1GB problem
To: Jachym Holecek <freza@dspfpga.com>
From: Yorick Hardy <yhardy@uj.ac.za>
List: tech-kern
Date: 01/17/2007 15:52:55
This is a multi-part message in MIME format.
--------------070403080704050603040700
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit

Jachym Holecek wrote:
> # Yorick Hardy 2007-01-17:
>   
>> --- sys/dev/pci/if_bce.c.orig	2007-01-06 11:49:53.000000000 +0200
>> +++ sys/dev/pci/if_bce.c	2007-01-15 10:56:50.000000000 +0200
>> @@ -293,7 +293,16 @@
>>  	KASSERT(bp != NULL);
>>  
>>  	sc->bce_pa = *pa;
>> -	sc->bce_dmatag = pa->pa_dmat;
>> +
>> +	/* BCM440x can only address 30 bits (1GB) */
>> +	if(bus_dmatag_subregion(pa->pa_dmat, 0, (1 << 30),
>>     
>
> Shouldn't this be s/1 << 30/0x3fffffff/ (or (1 << 30) - 1) then? Looks
> like the value is passed to uvm_pglistalloc() which uses inclusive address
> range I think.
>
> 	-- Jachym
>
>   
Correct.

Thanks for pointing that out.

-- 
Kind regards,

Yorick Hardy


--------------070403080704050603040700
Content-Type: text/plain;
 name="bce5.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="bce5.patch"

--- sys/arch/x86/include/bus.h.orig	2007-01-10 16:49:27.000000000 +0200
+++ sys/arch/x86/include/bus.h	2007-01-15 10:48:34.000000000 +0200
@@ -1108,6 +1108,9 @@
 	void	(*_dmamem_unmap)(bus_dma_tag_t, caddr_t, size_t);
 	paddr_t	(*_dmamem_mmap)(bus_dma_tag_t, bus_dma_segment_t *,
 		    int, off_t, int, int);
+	int 	(*_dmatag_subregion)(bus_dma_tag_t, bus_addr_t, bus_addr_t,
+		    bus_dma_tag_t *, int);
+	void	(*_dmatag_destroy)(bus_dma_tag_t);
 };
 
 static __inline void bus_dmamap_sync(bus_dma_tag_t, bus_dmamap_t,
@@ -1147,6 +1150,10 @@
 	(*(t)->_dmamem_unmap)((t), (k), (s))
 #define	bus_dmamem_mmap(t, sg, n, o, p, f)			\
 	(*(t)->_dmamem_mmap)((t), (sg), (n), (o), (p), (f))
+#define	bus_dmatag_subregion(t, mna, mxa, nt, f)		\
+	(*(t)->_dmatag_subregion)((t), (mna), (mxa), (nt), (f))
+#define	bus_dmatag_destroy(t)					\
+	(*(t)->_dmatag_destroy)((t))
 
 /*
  *	bus_dmamap_t
--- sys/arch/x86/include/bus_private.h.orig	2007-01-13 09:27:46.000000000 +0200
+++ sys/arch/x86/include/bus_private.h	2007-01-15 10:54:39.000000000 +0200
@@ -98,6 +98,10 @@
 paddr_t	_bus_dmamem_mmap(bus_dma_tag_t tag, bus_dma_segment_t *segs,
 	    int nsegs, off_t off, int prot, int flags);
 
+int	_bus_dmatag_subregion(bus_dma_tag_t tag, bus_addr_t min_addr,
+	    bus_addr_t max_addr, bus_dma_tag_t *newtag, int flags);
+void	_bus_dmatag_destroy(bus_dma_tag_t tag);
+
 #ifndef _BUS_DMAMEM_ALLOC_RANGE
 int	_bus_dmamem_alloc_range(bus_dma_tag_t tag, bus_size_t size,
 	    bus_size_t alignment, bus_size_t boundary,
--- sys/arch/x86/isa/isa_machdep.c.orig	2007-01-13 09:05:26.000000000 +0200
+++ sys/arch/x86/isa/isa_machdep.c	2007-01-15 11:41:00.000000000 +0200
@@ -121,6 +121,8 @@
 	_bus_dmamem_map,
 	_bus_dmamem_unmap,
 	_bus_dmamem_mmap,
+	_bus_dmatag_subregion,
+	_bus_dmatag_destroy,
 };
 
 #define	IDTVEC(name)	__CONCAT(X,name)
--- sys/arch/x86/pci/pci_machdep.c.orig	2007-01-06 13:42:22.000000000 +0200
+++ sys/arch/x86/pci/pci_machdep.c	2007-01-15 10:50:43.000000000 +0200
@@ -198,16 +198,14 @@
 	_bus_dmamap_load_uio,
 	_bus_dmamap_load_raw,
 	_bus_dmamap_unload,
-#if defined(_LP64) || defined(PAE)
 	_bus_dmamap_sync,
-#else
-	NULL,
-#endif
 	_bus_dmamem_alloc,
 	_bus_dmamem_free,
 	_bus_dmamem_map,
 	_bus_dmamem_unmap,
 	_bus_dmamem_mmap,
+	_bus_dmatag_subregion,
+	_bus_dmatag_destroy,
 };
 
 #ifdef _LP64
@@ -229,6 +227,8 @@
 	_bus_dmamem_map,
 	_bus_dmamem_unmap,
 	_bus_dmamem_mmap,
+	_bus_dmatag_subregion,
+	_bus_dmatag_destroy,
 };
 #endif
 
--- sys/arch/x86/x86/bus_dma.c.orig	2007-01-06 12:04:01.000000000 +0200
+++ sys/arch/x86/x86/bus_dma.c	2007-01-15 11:38:29.000000000 +0200
@@ -1192,3 +1192,29 @@
 	return (0);
 }
 
+int
+_bus_dmatag_subregion(bus_dma_tag_t tag, bus_addr_t min_addr,
+		      bus_addr_t max_addr, bus_dma_tag_t *newtag, int flags)
+{
+	if ((*newtag = malloc(sizeof(struct x86_bus_dma_tag), M_DMAMAP,
+	    (flags & BUS_DMA_NOWAIT) ? M_NOWAIT : M_WAITOK)) == NULL) {
+		return ENOMEM;
+	}
+
+	memcpy((void*)*newtag, (void*)tag, sizeof(struct x86_bus_dma_tag));
+
+	if(tag->_bounce_thresh == 0 || max_addr < tag->_bounce_thresh)
+		(*newtag)->_bounce_thresh = max_addr;
+	if(tag->_bounce_alloc_hi == 0 || max_addr < tag->_bounce_alloc_hi)
+		(*newtag)->_bounce_alloc_hi = max_addr;
+	if(min_addr > tag->_bounce_alloc_lo)
+		(*newtag)->_bounce_alloc_lo = min_addr;
+
+	return 0;
+}
+
+void
+_bus_dmatag_destroy(bus_dma_tag_t tag)
+{
+	free(tag, M_DMAMAP);
+}
--- sys/dev/pci/if_bce.c.orig	2007-01-06 11:49:53.000000000 +0200
+++ sys/dev/pci/if_bce.c	2007-01-17 15:43:12.000000000 +0200
@@ -293,7 +293,16 @@
 	KASSERT(bp != NULL);
 
 	sc->bce_pa = *pa;
-	sc->bce_dmatag = pa->pa_dmat;
+
+	/* BCM440x can only address 30 bits (1GB) */
+	if(bus_dmatag_subregion(pa->pa_dmat, 0, (1 << 30) - 1,
+			       &(sc->bce_dmatag), BUS_DMA_NOWAIT) != 0)
+	{
+		APRINT_ERROR("WARNING: %s failed to restrict dma range,"
+			     " falling back to parent bus dma range\n",
+			     sc->bce_dev.dv_xname);
+		sc->bce_dmatag = pa->pa_dmat;
+	}
 
 #if __NetBSD_Version__ >= 106120000
 	 aprint_naive(": Ethernet controller\n");

--------------070403080704050603040700--