HEADS UP: PCI Chnages

M. Warner Losh imp at bsdimp.com
Sun Apr 11 22:18:46 PDT 2004


In message: <446170000.1081743884 at lerlaptop.lerctr.org>
            Larry Rosenman <ler at lerctr.org> writes:
: 
: 
: --On Sunday, April 11, 2004 21:05:24 -0700 Kevin Oberman <oberman at es.net> 
: wrote:
: 
: >> Date: Sun, 11 Apr 2004 18:34:55 -0600 (MDT)
: >> From: "M. Warner Losh" <imp at bsdimp.com>
: >>
: >> Try this patch
: >
: > Bingo! I am running with the new kernel as I type this.
: as soon as OOo-1.1.1 finishes building, I'll try the new kernel waiting
: in the wings on this box (probably in the AM at this point), but this is a 
: good sign :)

You might also try
	http://people.freebsd.org/~imp/ata-patch

This patch is also discected here, to make sure I have my analysis
right.

Index: ata-pci.c
===================================================================
RCS file: /cache/ncvs/src/sys/dev/ata/ata-pci.c,v
retrieving revision 1.77
diff -u -r1.77 ata-pci.c
--- ata-pci.c	17 Mar 2004 17:50:27 -0000	1.77
+++ ata-pci.c	12 Apr 2004 04:54:18 -0000
@@ -246,48 +246,55 @@
     if (type == SYS_RES_IOPORT) {
 	switch (*rid) {
 	case ATA_IOADDR_RID:
+	    /*
+	     * ATA master devices are hard wired to the traditional ata
+	     * I/O addresses.  Some devices have these resources wired to
+	     * their BARs, while others do not, hence the need to hardwire
+	     */
 	    if (ATA_MASTERDEV(dev)) {
-		myrid = 0;
 		start = (unit ? ATA_SECONDARY : ATA_PRIMARY);
 		end = start + ATA_IOSIZE - 1;
 		count = ATA_IOSIZE;
-		res = BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
-					 SYS_RES_IOPORT, &myrid,
-					 start, end, count, flags);
-	    }
-	    else {
-		myrid = 0x10 + 8 * unit;
-		res = BUS_ALLOC_RESOURCE(device_get_parent(dev), dev,
-					 SYS_RES_IOPORT, &myrid,
-					 start, end, count, flags);
 	    }
+	    myrid = 0x10 + 8 * unit;
+	    res = BUS_ALLOC_RESOURCE(device_get_parent(dev), dev,
+				     SYS_RES_IOPORT, &myrid,
+				     start, end, count, flags);
 	    break;
 

OK.  What I'm doing above is changing how we do the allocation a
little.  Before, one had to play 'tricks' to get the resources
allocated correctly.  There was code in the pci bus that prevented
most allocations like this from succeeding, as well as other
complications.

This simplifies these past workarounds now that the PCI bus allocation
has been tightened up.  The old ata code would work with the those
devices that did NOT have the resources encoded in the BARs.  This is
because the new PCI code reserves BAR resources for the exclusive use
of that device.



 	case ATA_ALTADDR_RID:
 	    if (ATA_MASTERDEV(dev)) {
-		myrid = 0;
+#if 0
 		start = (unit ? ATA_SECONDARY : ATA_PRIMARY) + ATA_ALTOFFSET;
 		end = start + ATA_ALTIOSIZE - 1;
 		count = ATA_ALTIOSIZE;
-		res = BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
-					 SYS_RES_IOPORT, &myrid,
-					 start, end, count, flags);
+#else
+		start = (unit ? ATA_SECONDARY : ATA_PRIMARY) + ATA_ALTOFFSET - 2;
+		count = 4;
+		end = start + count - 1;
+#endif
 	    }
-	    else {
-		myrid = 0x14 + 8 * unit;
+printf("ata altaddr start %#lx end %#lx count %#lx\n", start, end, count);
+	    myrid = 0x14 + 8 * unit;
+	    res = BUS_ALLOC_RESOURCE(device_get_parent(dev), dev,
+	                             SYS_RES_IOPORT, &myrid,
+				     start, end, count, flags);
+
+	    /*
+	     * I don't understand why we need to do this dance.  If we get
+	     * the resource, then we release it and allocated something
+	     * else.  This makes little sense to me, and might, in fact
+	     * be a bug.
+	     */
+	    if (res && !ATA_MASTERDEV(dev)) {
+		start = rman_get_start(res) + 2;
+		end = start + ATA_ALTIOSIZE - 1;
+		count = ATA_ALTIOSIZE;
+		BUS_RELEASE_RESOURCE(device_get_parent(dev), dev,
+		                     SYS_RES_IOPORT, myrid, res);
 		res = BUS_ALLOC_RESOURCE(device_get_parent(dev), dev,
 					 SYS_RES_IOPORT, &myrid,
 					 start, end, count, flags);
-		if (res) {
-			start = rman_get_start(res) + 2;
-			end = start + ATA_ALTIOSIZE - 1;
-			count = ATA_ALTIOSIZE;
-			BUS_RELEASE_RESOURCE(device_get_parent(dev), dev,
-					     SYS_RES_IOPORT, myrid, res);
-			res = BUS_ALLOC_RESOURCE(device_get_parent(dev), dev,
-						 SYS_RES_IOPORT, &myrid,
-						 start, end, count, flags);
-		}
 	    }
 	    break;
 	}

@@ -431,7 +429,7 @@
 	ch->r_io[i].offset = i;
     }
     ch->r_io[ATA_ALTSTAT].res = altio;
-    ch->r_io[ATA_ALTSTAT].offset = 0;
+    ch->r_io[ATA_ALTSTAT].offset = 2;
     ch->r_io[ATA_IDX_ADDR].res = io;
 
     if (ctlr->r_res1) {

These are more complicated.  We want to allocate 0x376 and 0x3f6 (Each
for a length of 1).  However, there's a problem with that.  The
problem is that this resource isn't encodable in a PCI bar.  BARs must
be at least 4 in size, and aligned to the size of the resource.  So
the above code tries to round correctly to copensate.  I'm not sure
that I'm entirely happy with it, but it works for me.

Warner




More information about the freebsd-current mailing list