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>