Subject: heuristic for RBUS
To: None <port-i386@netbsd.org>
From: Greg Troxel <gdt@ir.bbn.com>
List: port-i386
Date: 01/06/2007 11:29:48
Long ago, I found that cardbus wouldn't work on my Thinkpad 600E, and
with help from the list determined that setting RBUS_MIN_START to 0.5
GB resulted in success; apparently mapped memory at 1 GB doesn't
really work.  This summer, I found that 1 GB is a bad value for
a Thinkpad T43p with 2 GB of RAM, and also for my T60 with 2 GB.

The following patch changes the logic to choose a value for
rbus_min_start based on the amount of installed memory.
If RBUS_MIN_START is defined, it is respected.

Otherwise, the default remains at 1 GB.   Then for machines <= 192 MB,
0.5 GB is used.  For machines 1 >GB, 2 GB is used.
I believe that this will increase the number of machines on which
cardbus works out of the box, and break very few.

Is this ok to commit?


Index: share/man/man4/cardbus.4
===================================================================
RCS file: /cvsroot/src/share/man/man4/cardbus.4,v
retrieving revision 1.28
diff -u -u -r1.28 cardbus.4
--- share/man/man4/cardbus.4	7 Oct 2006 23:35:39 -0000	1.28
+++ share/man/man4/cardbus.4	6 Jan 2007 16:19:06 -0000
@@ -34,7 +34,7 @@
 .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 .\" POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd October 7, 2006
+.Dd January 6, 2007
 .Dt CARDBUS 4
 .Os
 .Sh NAME
@@ -174,10 +174,15 @@
 abstraction.
 When the mapping does not work, PCMCIA cards are typically ignored on
 insert, and Cardbus cards are recognized but nonfunctional.
-The location is machine-specific, and the default location does not
-work on all hardware.
-On i386, the following kernel configuration line, which maps Cardbus
-space at 512M rather than 1GB, has been found to make Cardbus support
+On i386, the kernel has a heuristic to choose a memory address for
+mapping, defaulting to 1 GB, but choosing 0.5 GB on machines with less
+than 192 MB RAM and 2 GB on machines with more than 1 GB of RAM.
+The intent is to use an address that is larger than available RAM, but
+low enough to work; some systems seem to have trouble with
+addresses requiring more than 20 address lines.
+On i386, the following kernel configuration line disables the
+heuristics and forces Cardbus
+memory space to be mapped at 512M; this value makes Cardbus support
 (including PCMCIA attachment under a cbb) work on some notebook
 models, including the IBM Thinkpad 600E (2645-4AU) and the Compaq
 ARMADA M700:
Index: sys/arch/i386/i386/machdep.c
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/i386/machdep.c,v
retrieving revision 1.588
diff -u -u -r1.588 machdep.c
--- sys/arch/i386/i386/machdep.c	5 Jan 2007 04:07:23 -0000	1.588
+++ sys/arch/i386/i386/machdep.c	6 Jan 2007 16:19:07 -0000
@@ -191,6 +191,14 @@
 #include "npx.h"
 #include "ksyms.h"
 
+#include "cardbus.h"
+#if NCARDBUS > 0
+/* For rbus_min_start hint. */
+#include <machine/bus.h>
+#include <dev/cardbus/rbus.h>
+#include <machine/rbus_machdep.h>
+#endif
+
 #include "mca.h"
 #if NMCA > 0
 #include <machine/mca_machdep.h>	/* for mca_busprobe() */
@@ -446,6 +454,11 @@
 	format_bytes(pbuf, sizeof(pbuf), ptoa(physmem));
 	printf("total memory = %s\n", pbuf);
 
+#if NCARDBUS > 0
+	/* Tell RBUS how much RAM we have, so it can use heuristics. */
+	rbus_min_start_hint(ptoa(physmem));
+#endif
+
 	minaddr = 0;
 
 	/*
Index: sys/arch/i386/i386/rbus_machdep.c
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/i386/rbus_machdep.c,v
retrieving revision 1.18
diff -u -u -r1.18 rbus_machdep.c
--- sys/arch/i386/i386/rbus_machdep.c	11 Dec 2005 12:17:41 -0000	1.18
+++ sys/arch/i386/i386/rbus_machdep.c	6 Jan 2007 16:19:07 -0000
@@ -65,10 +65,62 @@
 
 #ifndef RBUS_MIN_START
 #define RBUS_MIN_START 0x40000000	/* 1GB */
+#else
+/*
+ * Note that kernel config forced RBUS_MIN_START.
+ */
+#define RBUS_MIN_START_FORCED
 #endif
 bus_addr_t rbus_min_start = RBUS_MIN_START;
 
 /*
+ * Dynamically set the start address for rbus.  This must be called
+ * before rbus is initialized.  The start address should be determined
+ * by the amount of installed memory.  Generally 1 GB has been found
+ * to be a good value, but it fails on some Thinkpads (e.g. 2645-4AU),
+ * for which 0.5 GB is a good value.  It also fails on (at least)
+ * Thinkpads with 2GB of RAM, for which 2 GB is a good value.
+ *
+ * Thus, a general strategy of setting rbus_min_start to the amount of
+ * memory seems in order.  However, the actually amount of memory is
+ * generally slightly more than the amount found, e.g. 1014MB vs 1024,
+ * or 2046 vs 2048.
+ */
+void
+rbus_min_start_hint(size_t ram)
+{
+#ifdef RBUS_MIN_START_FORCED
+	printf("rbus: rbus_min_start from config at 0x%0lx\n", rbus_min_start);
+
+#else
+        if (ram <= 192*1024*1024UL) {
+	  /*
+	   * <= 192 MB, so try 0.5 GB.  This will work on Thinkpad
+	   * 600E (2645-4AU), which fails at 1GB, and on some other
+	   * older machines that may have trouble with addresses
+	   * needing more than 20 bits.
+	   */
+	  rbus_min_start = 512 * 1024 * 1024UL;
+	}
+
+	if (ram >= 1024*1024*1024UL) {
+	  /*
+	   * >= 1GB, so try 2 GB.
+	   */
+	  rbus_min_start =  2 * 1024 * 1024 * 1024UL;
+	}
+
+	/*
+	 * XXX For machines with more than 2G, the right choice is not
+	 * clear.
+	 */
+
+	printf("rbus: rbus_min_start set to 0x%0lx\n", rbus_min_start);
+#endif
+}
+
+
+/*
  * rbus_tag_t rbus_fakeparent_mem(struct pci_attach_args *pa)
  *
  *   This function makes an rbus tag for memory space.  This rbus tag
Index: sys/arch/i386/include/rbus_machdep.h
===================================================================
RCS file: /cvsroot/src/sys/arch/i386/include/rbus_machdep.h,v
retrieving revision 1.6
diff -u -u -r1.6 rbus_machdep.h
--- sys/arch/i386/include/rbus_machdep.h	26 Feb 2003 21:29:03 -0000	1.6
+++ sys/arch/i386/include/rbus_machdep.h	6 Jan 2007 16:19:07 -0000
@@ -46,4 +46,6 @@
 rbus_tag_t rbus_pccbb_parent_io(struct pci_attach_args *);
 rbus_tag_t rbus_pccbb_parent_mem(struct pci_attach_args *);
 
+void rbus_min_start_hint(size_t);
+
 #endif /* _ARCH_I386_I386_RBUS_MACHDEP_H_ */