Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 23 Apr 2000 01:06:21 -0500 (CDT)
From:      Kevin Day <toasty@dragondata.com>
To:        hardware@freebsd.org
Subject:   TESTERS WANTED: OPTi 82C621 ATA support
Message-ID:  <200004230606.BAA42439@celery.dragondata.com>

next in thread | raw e-mail | index | archive | help

I've completed the first pass of support for the OPTi 82C621 IDE controller,
for modes up to PIO4. I've seen a considerable speed boost on my system
after doing this, and it seems stable, however, it's all very untested code.

If anyone has one of these chips in their system and could assist in testing
it, I would really appreciate it. DON'T attempt this without backing up
everything you have. It's completely possible(but not too likely) this could
destroy any data you have on your disk.

Here's a quick measurement of speed gained, with iozone:

iozone -N -s 12m -f /tmp/iozone.tmp
Microseconds/op Mode. Output is in microseconds per operation.
                                                            random  random    bkwd  record  stride                                   
              KB  reclen   write rewrite    read    reread    read   write    read rewrite    read   fwrite frewrite   fread  freread
OPTi PIO4  12288       4     871     771      234      233     286    8333     244     164     254      775      769     317     316
OPTi PIO0  12288       4     874    1021      634      341     299    8291     266     163     301      822      998     684     622
GENERIC    12288       4     887    3115     1992      876     414    8000     381     161     536      908     1834     990    1025

The "GENERIC" was a standard GENERIC kernel with whatever the BIOS happened
to set the chip's timings to. So, it seems that this can make a significant
speed increase, if you have a disk that can handle PIO4. Note that this is
using a nasty slow 2.5" IDE drive, which probably explains the poor write
performance.

This is what you should see during bootup:

ata0-master: success setting up PIO4 mode on OPTi621 chip
ata0-slave: success setting up PIO3 mode on OPTi621 chip
ata0: OPTi621 addressing mode set at PIO3
ad0: <TOSHIBA MK2104MAV/E4.02 A> ATA-4 disk at ata0 as master
ad0: 2067MB (4233600 sectors), 4200 cyls, 16 heads, 63 S/T, 512 B/S
ad0: 16 secs/int, 1 depth queue, PIO4
ad0: piomode=4 dmamode=2 udmamode=-1 cblid=0
Creating DISK ad0
Creating DISK wd0
ata0-slave: piomode=3 dmamode=-1 udmamode=-1 dmaflag=0
acd0: <COMPAQ CRD-S64P/1.03> CDROM drive at ata0 as slave
acd0: read 689KB/s (689KB/s), 128KB buffer, PIO3
acd0: Reads:
acd0: Audio: play, 256 volume levels
acd0: Mechanism: ejectable tray
acd0: Medium: no/blank disc inside, unlocked


Because of a quirk in how the chip handles addressing speed, your 'address
mode speed' will be set to whatever the SLOWEST device is on that cable. If
you've got a nice fast PIO4 drive and a slow PIO0 cd-rom on the same cable,
the chip will use address timings for PIO0. For maximum speed, don't do
this. :)

Here's the patch. Yes, it probably could be cleaned up quite a bit, but it
appears to work here. Please please please give some feedback if you can try
it. :)


This diff is against 4.0-RELEASE, although I could probably make it work on
a different version if necessary.


diff --exclude=*compile* -r -u /usr/src/sys-orig/conf/options /usr/src/sys/conf/options
--- /usr/src/sys-orig/conf/options	Wed Feb 23 14:10:53 2000
+++ /usr/src/sys/conf/options	Sun Apr 23 00:15:13 2000
@@ -219,6 +219,7 @@
 # Options used in the 'ata' ATA/ATAPI driver
 ATA_STATIC_ID		opt_ata.h
 ATA_ENABLE_ATAPI_DMA	opt_ata.h
+ATA_OPTI_PIO		opt_ata.h
 
 # Resource limits.
 DFLDSIZ			opt_rlimit.h
diff --exclude=*compile* -r -u /usr/src/sys-orig/dev/ata/ata-all.c /usr/src/sys/dev/ata/ata-all.c
--- /usr/src/sys-orig/dev/ata/ata-all.c	Sat Mar 18 16:26:28 2000
+++ /usr/src/sys/dev/ata/ata-all.c	Sun Apr 23 00:22:21 2000
@@ -294,6 +294,9 @@
     case 0x00041103:
 	return "HighPoint HPT366 ATA66 controller";
 
+    case 0xc6211045:
+    	return "OPTi/Cirrus Logic 82C621 ATA controller";
+
    /* unsupported but known chipsets, generic DMA only */
     case 0x10001042:
     case 0x10011042:
@@ -1012,11 +1015,125 @@
     return 0;
 }
 
+#ifdef ATA_OPTI_PIO
+#define opti_pcic_unlock() inw(scp->ioaddr + 1); inw(scp->ioaddr + 1)
+
+static void
+opti_reg_write(struct ata_softc *scp, unsigned char reg, unsigned char value)
+{
+    
+    opti_pcic_unlock();
+    outb(scp->ioaddr + 2, 0x03);
+    outb(scp->ioaddr + reg, value);
+    outb(scp->ioaddr + 2, 0x83);
+
+}
+ 
+static void
+opti621_timing(struct ata_softc *scp, int32_t bestmode)
+{
+    int i, data, recovery, addr;
+
+    /* Calculate the address timing for the entire controller */
+
+    switch (inw(scp->ioaddr + 5) & 1) {
+        case 1:	/* 25/50Mhz */
+        switch (bestmode) {
+            case ATA_PIO0:	addr = 2; break;	
+            case ATA_PIO1:	addr = 2; break;
+            case ATA_PIO2:	addr = 1; break;
+            case ATA_PIO3:	addr = 1; break;
+            case ATA_PIO4:	addr = 1; break;
+            default:		addr = 2; break;
+        }
+        break;
+        default:
+        case 0:	/* 33/66MHz */
+        switch (bestmode) {
+            case ATA_PIO0:	addr = 3; break;
+            case ATA_PIO1:	addr = 2; break;
+            case ATA_PIO2:	addr = 2; break;
+            case ATA_PIO3:	addr = 1; break;
+            case ATA_PIO4:	addr = 1; break;
+            default:		addr = 3; break;
+        }
+        break;
+    }
+        
+    /*
+     * The Linux driver seems to be violating the spec for the
+     * chip if I do what they did. If you have problems, try
+     * turning this on
+     *
+     */
+#if 0     
+    outb(scp->ioaddr + 3, 0x81);	/* access B register */
+#endif
+    /*
+     * The Linux driver does this too, without understanding why.
+     * If I don't do it, the chip hangs. Undocumented completely.
+     *
+     */
+    outb(scp->ioaddr + 5, 0xff); 	/* huh? */
+
+    for (i=0;i<2;i++) {	/* Once per drive */
+        
+        switch (inw(scp->ioaddr + 5) & 1) {
+            case 1:	/* 25/50Mhz */
+            switch (scp->mode[i]) {
+    	        case ATA_PIO0:	data = 5; recovery = 8; break;
+	        case ATA_PIO1:	data = 4; recovery = 4; break;
+	        case ATA_PIO2:	data = 3; recovery = 2; break;
+	        case ATA_PIO3:	data = 2; recovery = 2; break;
+	        case ATA_PIO4:	data = 2; recovery = 1; break;
+	        default:	data = 8; recovery = 8; break; 
+	        }
+	        break;
+            default:
+            case 0:	/* 33/66MHz */
+	        switch (scp->mode[i]) {
+	        case ATA_PIO0:	data = 6; recovery = 11; break;
+	        case ATA_PIO1:	data = 5; recovery = 6; break;
+	        case ATA_PIO2:	data = 4; recovery = 2; break;
+	        case ATA_PIO3:	data = 3; recovery = 2; break;
+	        case ATA_PIO4:	data = 3; recovery = 1; break;
+	        default:	data = 8; recovery = 10; break; 
+	        }
+	        break;
+        }
+        
+        opti_reg_write(scp, 6, i);	/* Select proper drive */
+        /* Write the read timing and the write timing */
+        opti_reg_write(scp, 0, recovery | (data << 4));
+        opti_reg_write(scp, 1, recovery | (data << 4));
+        
+    }	
+
+    /*
+     * Disable prefetching (doesn't work right)
+     * Set address select timing
+     * Default DRDY timing (2 LCLKS)
+     *
+     */
+    opti_reg_write(scp, 6, addr << 4);
+
+    /* Enable the changes we made, overriding strapping options */
+    outb(scp->ioaddr + 3, 0x85);
+
+}
+
+#endif /* ATA_OPTI_PIO */
+
 static void 
 ata_boot_attach(void)
 {
     struct ata_softc *scp;
     int32_t ctlr;
+#ifdef ATA_OPTI_PIO
+    int32_t bestmode, error, apiomode;
+#endif
 
     /*
      * run through all ata devices and look for real ATA & ATAPI devices
@@ -1040,6 +1157,62 @@
 		scp->devices &= ~ATA_ATAPI_MASTER;
     }
 
+#ifdef ATA_OPTI_PIO
+    /*
+     * In the case of the OPTi 621, we have to work around the fact that
+     * it's rather brain damaged. While it supports up to PIO4, both the
+     * master and the slave device have to be the same mode for address
+     * timing. If you've got a PIO4 drive and a PIO1 CD-ROM, you're stuck
+     * with PIO1's address speed. Really. Data/recovery speeds do match the
+     * true drive's speed, though.
+     *
+     * So, we have to be at a point where we can look at both devices on
+     * the channel before we can setup the timing, but before we've
+     * actually done the attach. The only place I can see for this is here
+     *
+     */
+    for (ctlr=0; ctlr<devclass_get_maxunit(ata_devclass); ctlr++) {
+   	if (!(scp = devclass_get_softc(ata_devclass, ctlr)))
+	    continue;
+        if (scp->chiptype != 0xc6211045)
+            continue;
+            
+ 	bestmode = 255;
+	if (scp->devices & (ATA_ATA_MASTER | ATA_ATAPI_MASTER)) {
+	    apiomode = ata_pmode(ATA_PARAM(scp,ATA_MASTER));
+	    bestmode = min(bestmode, apiomode);
+	    scp->mode[0] = ata_pio2mode(apiomode);
+	    error = ata_command(scp, ATA_MASTER, ATA_C_SETFEATURES, 0, 0, 0,
+	        ata_pio2mode(apiomode), 
+		ATA_C_F_SETXFER, ATA_WAIT_READY);
+	    if (bootverbose)
+	        ata_printf(scp, ATA_MASTER,
+		    "%s setting up PIO%d mode on OPTi621 chip\n",
+		    (error) ? "failed" : "success",
+		    (apiomode >= 0) ? apiomode : 0);
+	}
+	if (scp->devices & (ATA_ATA_SLAVE | ATA_ATAPI_SLAVE)) {
+	    apiomode = ata_pmode(ATA_PARAM(scp,ATA_SLAVE));
+	    bestmode = min(bestmode, apiomode);
+	    scp->mode[1] = ata_pio2mode(apiomode);
+	    error = ata_command(scp, ATA_SLAVE, ATA_C_SETFEATURES, 0, 0, 0,
+	        ata_pio2mode(apiomode), 
+		ATA_C_F_SETXFER, ATA_WAIT_READY);
+	    if (bootverbose)
+	        ata_printf(scp, ATA_SLAVE,
+		    "%s setting up PIO%d mode on OPTi621 chip\n",
+		    (error) ? "failed" : "success",
+		    (apiomode >= 0) ? apiomode : 0);
+	}
+
+	if (bestmode == 255)
+	    continue;
+	ata_printf(scp, -1, "OPTi621 addressing mode set at PIO%d\n",
+	    bestmode);
+	opti621_timing(scp, bestmode);
+    }
+#endif
+
 #if NATADISK > 0
     /* now we know whats there, do the real attach, first the ATA disks */
     for (ctlr=0; ctlr<devclass_get_maxunit(ata_devclass); ctlr++) {
diff --exclude=*compile* -r -u /usr/src/sys-orig/dev/ata/ata-dma.c /usr/src/sys/dev/ata/ata-dma.c
--- /usr/src/sys-orig/dev/ata/ata-dma.c	Sun Mar  5 10:52:24 2000
+++ /usr/src/sys/dev/ata/ata-dma.c	Sun Apr 23 00:16:54 2000
@@ -64,6 +64,17 @@
     int32_t devno = (scp->unit << 1) + ATA_DEV(device);
     int32_t error;
 
+#ifdef ATA_OPTI_PIO
+    /* 
+     * If we're using the OPTi chip, this will be done later, when
+     * we're attaching the disks. (We need to know what speed both
+     * disks are on the channel to configure the controller)
+     *
+     */
+    if (scp->chiptype == 0xc6211045)
+        return;
+#endif
+        
     /* set our most pessimistic default mode */
     scp->mode[ATA_DEV(device)] = ATA_PIO;
 


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-hardware" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200004230606.BAA42439>