Annotation of Gnu-Mach/linux/src/drivers/block/cmd640.c, revision 1.1

1.1     ! root        1: /*
        !             2:  *  linux/drivers/block/cmd640.c       Version 1.02  Sep 01, 1996
        !             3:  *
        !             4:  *  Copyright (C) 1995-1996  Linus Torvalds & authors (see below)
        !             5:  */
        !             6: 
        !             7: /*
        !             8:  *  Original author:   [email protected] (Igor Abramov)
        !             9:  *
        !            10:  *  Maintained by:     [email protected] (Mark Lord)
        !            11:  *                     with fanatical support from a legion of hackers!
        !            12:  *
        !            13:  *  This file provides support for the advanced features and bugs
        !            14:  *  of IDE interfaces using the CMD Technologies 0640 IDE interface chip.
        !            15:  *
        !            16:  *  These chips are basically fucked by design, and getting this driver
        !            17:  *  to work on every motherboard design that uses this screwed chip seems
        !            18:  *  bloody well impossible.  However, we're still trying.
        !            19:  *
        !            20:  *  Version 0.97 worked for everybody.
        !            21:  *
        !            22:  *  User feedback is essential.  Many thanks to the beta test team:
        !            23:  *
        !            24:  *  [email protected], [email protected], [email protected],
        !            25:  *  [email protected], [email protected], [email protected],
        !            26:  *  [email protected], [email protected],
        !            27:  *  [email protected], [email protected],
        !            28:  *  [email protected], [email protected], [email protected],
        !            29:  *  [email protected], [email protected], [email protected],
        !            30:  *  [email protected], [email protected], [email protected],
        !            31:  *  [email protected], [email protected], [email protected],
        !            32:  *  [email protected], [email protected], [email protected],
        !            33:  *  [email protected], [email protected], [email protected], [email protected]
        !            34:  *  [email protected], and others.
        !            35:  *
        !            36:  *  Version 0.01       Initial version, hacked out of ide.c,
        !            37:  *                     and #include'd rather than compiled separately.
        !            38:  *                     This will get cleaned up in a subsequent release.
        !            39:  *
        !            40:  *  Version 0.02       Fixes for vlb initialization code, enable prefetch
        !            41:  *                     for versions 'B' and 'C' of chip by default,
        !            42:  *                     some code cleanup.
        !            43:  *
        !            44:  *  Version 0.03       Added reset of secondary interface,
        !            45:  *                     and black list for devices which are not compatible
        !            46:  *                     with prefetch mode. Separate function for setting
        !            47:  *                     prefetch is added, possibly it will be called some
        !            48:  *                     day from ioctl processing code.
        !            49:  *
        !            50:  *  Version 0.04       Now configs/compiles separate from ide.c
        !            51:  *
        !            52:  *  Version 0.05       Major rewrite of interface timing code.
        !            53:  *                     Added new function cmd640_set_mode to set PIO mode
        !            54:  *                     from ioctl call. New drives added to black list.
        !            55:  *
        !            56:  *  Version 0.06       More code cleanup. Prefetch is enabled only for
        !            57:  *                     detected hard drives, not included in prefetch
        !            58:  *                     black list.
        !            59:  *
        !            60:  *  Version 0.07       Changed to more conservative drive tuning policy.
        !            61:  *                     Unknown drives, which report PIO < 4 are set to
        !            62:  *                     (reported_PIO - 1) if it is supported, or to PIO0.
        !            63:  *                     List of known drives extended by info provided by
        !            64:  *                     CMD at their ftp site.
        !            65:  *
        !            66:  *  Version 0.08       Added autotune/noautotune support.
        !            67:  *
        !            68:  *  Version 0.09       Try to be smarter about 2nd port enabling.
        !            69:  *  Version 0.10       Be nice and don't reset 2nd port.
        !            70:  *  Version 0.11       Try to handle more wierd situations.
        !            71:  *
        !            72:  *  Version 0.12       Lots of bug fixes from Laszlo Peter
        !            73:  *                     irq unmasking disabled for reliability.
        !            74:  *                     try to be even smarter about the second port.
        !            75:  *                     tidy up source code formatting.
        !            76:  *  Version 0.13       permit irq unmasking again.
        !            77:  *  Version 0.90       massive code cleanup, some bugs fixed.
        !            78:  *                     defaults all drives to PIO mode0, prefetch off.
        !            79:  *                     autotune is OFF by default, with compile time flag.
        !            80:  *                     prefetch can be turned OFF/ON using "hdparm -p8/-p9"
        !            81:  *                      (requires hdparm-3.1 or newer)
        !            82:  *  Version 0.91       first release to linux-kernel list.
        !            83:  *  Version 0.92       move initial reg dump to separate callable function
        !            84:  *                     change "readahead" to "prefetch" to avoid confusion
        !            85:  *  Version 0.95       respect original BIOS timings unless autotuning.
        !            86:  *                     tons of code cleanup and rearrangement.
        !            87:  *                     added CONFIG_BLK_DEV_CMD640_ENHANCED option
        !            88:  *                     prevent use of unmask when prefetch is on
        !            89:  *  Version 0.96       prevent use of io_32bit when prefetch is off
        !            90:  *  Version 0.97       fix VLB secondary interface for [email protected]
        !            91:  *                     other minor tune-ups:  0.96 was very good.
        !            92:  *  Version 0.98       ignore PCI version when disabled by BIOS
        !            93:  *  Version 0.99       display setup/active/recovery clocks with PIO mode
        !            94:  *  Version 1.00       Mmm.. cannot depend on PCMD_ENA in all systems
        !            95:  *  Version 1.01       slow/fast devsel can be selected with "hdparm -p6/-p7"
        !            96:  *                      ("fast" is necessary for 32bit I/O in some systems)
        !            97:  *  Version 1.02       fix bug that resulted in slow "setup times"
        !            98:  *                      (patch courtesy of Zoltan Hidvegi)
        !            99:  */
        !           100: 
        !           101: #undef REALLY_SLOW_IO          /* most systems can safely undef this */
        !           102: #define CMD640_PREFETCH_MASKS 1
        !           103: 
        !           104: #include <linux/config.h>
        !           105: #include <linux/types.h>
        !           106: #include <linux/kernel.h>
        !           107: #include <linux/delay.h>
        !           108: #include <linux/timer.h>
        !           109: #include <linux/mm.h>
        !           110: #include <linux/ioport.h>
        !           111: #include <linux/blkdev.h>
        !           112: #include <linux/hdreg.h>
        !           113: #include <asm/io.h>
        !           114: #include "ide.h"
        !           115: #include "ide_modes.h"
        !           116: 
        !           117: /*
        !           118:  * This flag is set in ide.c by the parameter:  ide0=cmd640_vlb
        !           119:  */
        !           120: int cmd640_vlb = 0;
        !           121: 
        !           122: /*
        !           123:  * CMD640 specific registers definition.
        !           124:  */
        !           125: 
        !           126: #define VID            0x00
        !           127: #define DID            0x02
        !           128: #define PCMD           0x04
        !           129: #define   PCMD_ENA     0x01
        !           130: #define PSTTS          0x06
        !           131: #define REVID          0x08
        !           132: #define PROGIF         0x09
        !           133: #define SUBCL          0x0a
        !           134: #define BASCL          0x0b
        !           135: #define BaseA0         0x10
        !           136: #define BaseA1         0x14
        !           137: #define BaseA2         0x18
        !           138: #define BaseA3         0x1c
        !           139: #define INTLINE                0x3c
        !           140: #define INPINE         0x3d
        !           141: 
        !           142: #define        CFR             0x50
        !           143: #define   CFR_DEVREV           0x03
        !           144: #define   CFR_IDE01INTR                0x04
        !           145: #define          CFR_DEVID             0x18
        !           146: #define          CFR_AT_VESA_078h      0x20
        !           147: #define          CFR_DSA1              0x40
        !           148: #define          CFR_DSA0              0x80
        !           149: 
        !           150: #define CNTRL          0x51
        !           151: #define          CNTRL_DIS_RA0         0x40
        !           152: #define   CNTRL_DIS_RA1                0x80
        !           153: #define          CNTRL_ENA_2ND         0x08
        !           154: 
        !           155: #define        CMDTIM          0x52
        !           156: #define        ARTTIM0         0x53
        !           157: #define        DRWTIM0         0x54
        !           158: #define ARTTIM1        0x55
        !           159: #define DRWTIM1                0x56
        !           160: #define ARTTIM23       0x57
        !           161: #define   ARTTIM23_DIS_RA2     0x04
        !           162: #define   ARTTIM23_DIS_RA3     0x08
        !           163: #define DRWTIM23       0x58
        !           164: #define BRST           0x59
        !           165: 
        !           166: /*
        !           167:  * Registers and masks for easy access by drive index:
        !           168:  */
        !           169: static byte prefetch_regs[4]  = {CNTRL, CNTRL, ARTTIM23, ARTTIM23};
        !           170: static byte prefetch_masks[4] = {CNTRL_DIS_RA0, CNTRL_DIS_RA1, ARTTIM23_DIS_RA2, ARTTIM23_DIS_RA3};
        !           171: 
        !           172: #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
        !           173: 
        !           174: static byte arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23};
        !           175: static byte drwtim_regs[4] = {DRWTIM0, DRWTIM1, DRWTIM23, DRWTIM23};
        !           176: 
        !           177: /*
        !           178:  * Current cmd640 timing values for each drive.
        !           179:  * The defaults for each are the slowest possible timings.
        !           180:  */
        !           181: static byte setup_counts[4]    = {4, 4, 4, 4};     /* Address setup count (in clocks) */
        !           182: static byte active_counts[4]   = {16, 16, 16, 16}; /* Active count   (encoded) */
        !           183: static byte recovery_counts[4] = {16, 16, 16, 16}; /* Recovery count (encoded) */
        !           184: 
        !           185: #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
        !           186: 
        !           187: /*
        !           188:  * These are initialized to point at the devices we control
        !           189:  */
        !           190: static ide_hwif_t  *cmd_hwif0, *cmd_hwif1;
        !           191: static ide_drive_t *cmd_drives[4];
        !           192: 
        !           193: /*
        !           194:  * Interface to access cmd640x registers
        !           195:  */
        !           196: static unsigned int cmd640_key;
        !           197: static void (*put_cmd640_reg)(unsigned short reg, byte val);
        !           198: static byte (*get_cmd640_reg)(unsigned short reg);
        !           199: 
        !           200: /*
        !           201:  * This is read from the CFR reg, and is used in several places.
        !           202:  */
        !           203: static unsigned int cmd640_chip_version;
        !           204: 
        !           205: /*
        !           206:  * The CMD640x chip does not support DWORD config write cycles, but some
        !           207:  * of the BIOSes use them to implement the config services.
        !           208:  * Therefore, we must use direct IO instead.
        !           209:  */
        !           210: 
        !           211: /* PCI method 1 access */
        !           212: 
        !           213: static void put_cmd640_reg_pci1 (unsigned short reg, byte val)
        !           214: {
        !           215:        unsigned long flags;
        !           216: 
        !           217:        save_flags(flags);
        !           218:        cli();
        !           219:        outl_p((reg & 0xfc) | cmd640_key, 0xcf8);
        !           220:        outb_p(val, (reg & 3) | 0xcfc);
        !           221:        restore_flags(flags);
        !           222: }
        !           223: 
        !           224: static byte get_cmd640_reg_pci1 (unsigned short reg)
        !           225: {
        !           226:        byte b;
        !           227:        unsigned long flags;
        !           228: 
        !           229:        save_flags(flags);
        !           230:        cli();
        !           231:        outl_p((reg & 0xfc) | cmd640_key, 0xcf8);
        !           232:        b = inb_p((reg & 3) | 0xcfc);
        !           233:        restore_flags(flags);
        !           234:        return b;
        !           235: }
        !           236: 
        !           237: /* PCI method 2 access (from CMD datasheet) */
        !           238: 
        !           239: static void put_cmd640_reg_pci2 (unsigned short reg, byte val)
        !           240: {
        !           241:        unsigned long flags;
        !           242: 
        !           243:        save_flags(flags);
        !           244:        cli();
        !           245:        outb_p(0x10, 0xcf8);
        !           246:        outb_p(val, cmd640_key + reg);
        !           247:        outb_p(0, 0xcf8);
        !           248:        restore_flags(flags);
        !           249: }
        !           250: 
        !           251: static byte get_cmd640_reg_pci2 (unsigned short reg)
        !           252: {
        !           253:        byte b;
        !           254:        unsigned long flags;
        !           255: 
        !           256:        save_flags(flags);
        !           257:        cli();
        !           258:        outb_p(0x10, 0xcf8);
        !           259:        b = inb_p(cmd640_key + reg);
        !           260:        outb_p(0, 0xcf8);
        !           261:        restore_flags(flags);
        !           262:        return b;
        !           263: }
        !           264: 
        !           265: /* VLB access */
        !           266: 
        !           267: static void put_cmd640_reg_vlb (unsigned short reg, byte val)
        !           268: {
        !           269:        unsigned long flags;
        !           270: 
        !           271:        save_flags(flags);
        !           272:        cli();
        !           273:        outb_p(reg, cmd640_key);
        !           274:        outb_p(val, cmd640_key + 4);
        !           275:        restore_flags(flags);
        !           276: }
        !           277: 
        !           278: static byte get_cmd640_reg_vlb (unsigned short reg)
        !           279: {
        !           280:        byte b;
        !           281:        unsigned long flags;
        !           282: 
        !           283:        save_flags(flags);
        !           284:        cli();
        !           285:        outb_p(reg, cmd640_key);
        !           286:        b = inb_p(cmd640_key + 4);
        !           287:        restore_flags(flags);
        !           288:        return b;
        !           289: }
        !           290: 
        !           291: static int match_pci_cmd640_device (void)
        !           292: {
        !           293:        const byte ven_dev[4] = {0x95, 0x10, 0x40, 0x06};
        !           294:        unsigned int i;
        !           295:        for (i = 0; i < 4; i++) {
        !           296:                if (get_cmd640_reg(i) != ven_dev[i])
        !           297:                        return 0;
        !           298:        }
        !           299: #ifdef STUPIDLY_TRUST_BROKEN_PCMD_ENA_BIT
        !           300:        if ((get_cmd640_reg(PCMD) & PCMD_ENA) == 0) {
        !           301:                printk("ide: cmd640 on PCI disabled by BIOS\n");
        !           302:                return 0;
        !           303:        }
        !           304: #endif /* STUPIDLY_TRUST_BROKEN_PCMD_ENA_BIT */
        !           305:        return 1; /* success */
        !           306: }
        !           307: 
        !           308: /*
        !           309:  * Probe for CMD640x -- pci method 1
        !           310:  */
        !           311: static int probe_for_cmd640_pci1 (void)
        !           312: {
        !           313:        get_cmd640_reg = get_cmd640_reg_pci1;
        !           314:        put_cmd640_reg = put_cmd640_reg_pci1;
        !           315:        for (cmd640_key = 0x80000000; cmd640_key <= 0x8000f800; cmd640_key += 0x800) {
        !           316:                if (match_pci_cmd640_device())
        !           317:                        return 1; /* success */
        !           318:        }
        !           319:        return 0;
        !           320: }
        !           321: 
        !           322: /*
        !           323:  * Probe for CMD640x -- pci method 2
        !           324:  */
        !           325: static int probe_for_cmd640_pci2 (void)
        !           326: {
        !           327:        get_cmd640_reg = get_cmd640_reg_pci2;
        !           328:        put_cmd640_reg = put_cmd640_reg_pci2;
        !           329:        for (cmd640_key = 0xc000; cmd640_key <= 0xcf00; cmd640_key += 0x100) {
        !           330:                if (match_pci_cmd640_device())
        !           331:                        return 1; /* success */
        !           332:        }
        !           333:        return 0;
        !           334: }
        !           335: 
        !           336: /*
        !           337:  * Probe for CMD640x -- vlb
        !           338:  */
        !           339: static int probe_for_cmd640_vlb (void)
        !           340: {
        !           341:        byte b;
        !           342: 
        !           343:        get_cmd640_reg = get_cmd640_reg_vlb;
        !           344:        put_cmd640_reg = put_cmd640_reg_vlb;
        !           345:        cmd640_key = 0x178;
        !           346:        b = get_cmd640_reg(CFR);
        !           347:        if (b == 0xff || b == 0x00 || (b & CFR_AT_VESA_078h)) {
        !           348:                cmd640_key = 0x78;
        !           349:                b = get_cmd640_reg(CFR);
        !           350:                if (b == 0xff || b == 0x00 || !(b & CFR_AT_VESA_078h))
        !           351:                        return 0;
        !           352:        }
        !           353:        return 1; /* success */
        !           354: }
        !           355: 
        !           356: /*
        !           357:  *  Returns 1 if an IDE interface/drive exists at 0x170,
        !           358:  *  Returns 0 otherwise.
        !           359:  */
        !           360: static int secondary_port_responding (void)
        !           361: {
        !           362:        unsigned long flags;
        !           363: 
        !           364:        save_flags(flags);
        !           365:        cli();
        !           366: 
        !           367:        outb_p(0x0a, 0x170 + IDE_SELECT_OFFSET);        /* select drive0 */
        !           368:        udelay(100);
        !           369:        if ((inb_p(0x170 + IDE_SELECT_OFFSET) & 0x1f) != 0x0a) {
        !           370:                outb_p(0x1a, 0x170 + IDE_SELECT_OFFSET); /* select drive1 */
        !           371:                udelay(100);
        !           372:                if ((inb_p(0x170 + IDE_SELECT_OFFSET) & 0x1f) != 0x1a) {
        !           373:                        restore_flags(flags);
        !           374:                        return 0; /* nothing responded */
        !           375:                }
        !           376:        }
        !           377:        restore_flags(flags);
        !           378:        return 1; /* success */
        !           379: }
        !           380: 
        !           381: #ifdef CMD640_DUMP_REGS
        !           382: /*
        !           383:  * Dump out all cmd640 registers.  May be called from ide.c
        !           384:  */
        !           385: void cmd640_dump_regs (void)
        !           386: {
        !           387:        unsigned int reg = cmd640_vlb ? 0x50 : 0x00;
        !           388: 
        !           389:        /* Dump current state of chip registers */
        !           390:        printk("ide: cmd640 internal register dump:");
        !           391:        for (; reg <= 0x59; reg++) {
        !           392:                if (!(reg & 0x0f))
        !           393:                        printk("\n%04x:", reg);
        !           394:                printk(" %02x", get_cmd640_reg(reg));
        !           395:        }
        !           396:        printk("\n");
        !           397: }
        !           398: #endif
        !           399: 
        !           400: /*
        !           401:  * Check whether prefetch is on for a drive,
        !           402:  * and initialize the unmask flags for safe operation.
        !           403:  */
        !           404: static void check_prefetch (unsigned int index)
        !           405: {
        !           406:        ide_drive_t *drive = cmd_drives[index];
        !           407:        byte b = get_cmd640_reg(prefetch_regs[index]);
        !           408: 
        !           409:        if (b & prefetch_masks[index]) {        /* is prefetch off? */
        !           410:                drive->no_unmask = 0;
        !           411:                drive->no_io_32bit = 1;
        !           412:                drive->io_32bit = 0;
        !           413:        } else {
        !           414: #if CMD640_PREFETCH_MASKS
        !           415:                drive->no_unmask = 1;
        !           416:                drive->unmask = 0;
        !           417: #endif
        !           418:                drive->no_io_32bit = 0;
        !           419:        }
        !           420: }
        !           421: 
        !           422: /*
        !           423:  * Figure out which devices we control
        !           424:  */
        !           425: static void setup_device_ptrs (void)
        !           426: {
        !           427:        unsigned int i;
        !           428: 
        !           429:        cmd_hwif0 = &ide_hwifs[0]; /* default, if not found below */
        !           430:        cmd_hwif1 = &ide_hwifs[1]; /* default, if not found below */
        !           431:        for (i = 0; i < MAX_HWIFS; i++) {
        !           432:                ide_hwif_t *hwif = &ide_hwifs[i];
        !           433:                if (hwif->chipset == ide_unknown || hwif->chipset == ide_generic) {
        !           434:                        if (hwif->io_base == 0x1f0)
        !           435:                                cmd_hwif0 = hwif;
        !           436:                        else if (hwif->io_base == 0x170)
        !           437:                                cmd_hwif1 = hwif;
        !           438:                }
        !           439:        }
        !           440:        cmd_drives[0] = &cmd_hwif0->drives[0];
        !           441:        cmd_drives[1] = &cmd_hwif0->drives[1];
        !           442:        cmd_drives[2] = &cmd_hwif1->drives[0];
        !           443:        cmd_drives[3] = &cmd_hwif1->drives[1];
        !           444: }
        !           445: 
        !           446: #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
        !           447: 
        !           448: /*
        !           449:  * Sets prefetch mode for a drive.
        !           450:  */
        !           451: static void set_prefetch_mode (unsigned int index, int mode)
        !           452: {
        !           453:        ide_drive_t *drive = cmd_drives[index];
        !           454:        int reg = prefetch_regs[index];
        !           455:        byte b;
        !           456:        unsigned long flags;
        !           457: 
        !           458:        save_flags(flags);
        !           459:        cli();
        !           460:        b = get_cmd640_reg(reg);
        !           461:        if (mode) {     /* want prefetch on? */
        !           462: #if CMD640_PREFETCH_MASKS
        !           463:                drive->no_unmask = 1;
        !           464:                drive->unmask = 0;
        !           465: #endif
        !           466:                drive->no_io_32bit = 0;
        !           467:                b &= ~prefetch_masks[index];    /* enable prefetch */
        !           468:        } else {
        !           469:                drive->no_unmask = 0;
        !           470:                drive->no_io_32bit = 1;
        !           471:                drive->io_32bit = 0;
        !           472:                b |= prefetch_masks[index];     /* disable prefetch */
        !           473:        }
        !           474:        put_cmd640_reg(reg, b);
        !           475:        restore_flags(flags);
        !           476: }
        !           477: 
        !           478: /*
        !           479:  * Dump out current drive clocks settings
        !           480:  */
        !           481: static void display_clocks (unsigned int index)
        !           482: {
        !           483:        byte active_count, recovery_count;
        !           484: 
        !           485:        active_count = active_counts[index];
        !           486:        if (active_count == 1)
        !           487:                ++active_count;
        !           488:        recovery_count = recovery_counts[index];
        !           489:        if (active_count > 3 && recovery_count == 1)
        !           490:                ++recovery_count;
        !           491:        if (cmd640_chip_version > 1)
        !           492:                recovery_count += 1;  /* cmd640b uses (count + 1)*/
        !           493:        printk(", clocks=%d/%d/%d\n", setup_counts[index], active_count, recovery_count);
        !           494: }
        !           495: 
        !           496: /*
        !           497:  * Pack active and recovery counts into single byte representation
        !           498:  * used by controller
        !           499:  */
        !           500: inline static byte pack_nibbles (byte upper, byte lower)
        !           501: {
        !           502:        return ((upper & 0x0f) << 4) | (lower & 0x0f);
        !           503: }
        !           504: 
        !           505: /*
        !           506:  * This routine retrieves the initial drive timings from the chipset.
        !           507:  */
        !           508: static void retrieve_drive_counts (unsigned int index)
        !           509: {
        !           510:        byte b;
        !           511: 
        !           512:        /*
        !           513:         * Get the internal setup timing, and convert to clock count
        !           514:         */
        !           515:        b = get_cmd640_reg(arttim_regs[index]) & ~0x3f;
        !           516:        switch (b) {
        !           517:                case 0x00: b = 4; break;
        !           518:                case 0x80: b = 3; break;
        !           519:                case 0x40: b = 2; break;
        !           520:                default:   b = 5; break;
        !           521:        }
        !           522:        setup_counts[index] = b;
        !           523: 
        !           524:        /*
        !           525:         * Get the active/recovery counts
        !           526:         */
        !           527:        b = get_cmd640_reg(drwtim_regs[index]);
        !           528:        active_counts[index]   = (b >> 4)   ? (b >> 4)   : 0x10;
        !           529:        recovery_counts[index] = (b & 0x0f) ? (b & 0x0f) : 0x10;
        !           530: }
        !           531: 
        !           532: 
        !           533: /*
        !           534:  * This routine writes the prepared setup/active/recovery counts
        !           535:  * for a drive into the cmd640 chipset registers to active them.
        !           536:  */
        !           537: static void program_drive_counts (unsigned int index)
        !           538: {
        !           539:        unsigned long flags;
        !           540:        byte setup_count    = setup_counts[index];
        !           541:        byte active_count   = active_counts[index];
        !           542:        byte recovery_count = recovery_counts[index];
        !           543: 
        !           544:        /*
        !           545:         * Set up address setup count and drive read/write timing registers.
        !           546:         * Primary interface has individual count/timing registers for
        !           547:         * each drive.  Secondary interface has one common set of registers,
        !           548:         * so we merge the timings, using the slowest value for each timing.
        !           549:         */
        !           550:        if (index > 1) {
        !           551:                unsigned int mate;
        !           552:                if (cmd_drives[mate = index ^ 1]->present) {
        !           553:                        if (setup_count < setup_counts[mate])
        !           554:                                setup_count = setup_counts[mate];
        !           555:                        if (active_count < active_counts[mate])
        !           556:                                active_count = active_counts[mate];
        !           557:                        if (recovery_count < recovery_counts[mate])
        !           558:                                recovery_count = recovery_counts[mate];
        !           559:                }
        !           560:        }
        !           561: 
        !           562:        /*
        !           563:         * Convert setup_count to internal chipset representation
        !           564:         */
        !           565:        switch (setup_count) {
        !           566:                case 4:  setup_count = 0x00; break;
        !           567:                case 3:  setup_count = 0x80; break;
        !           568:                case 1:
        !           569:                case 2:  setup_count = 0x40; break;
        !           570:                default: setup_count = 0xc0; /* case 5 */
        !           571:        }
        !           572: 
        !           573:        /*
        !           574:         * Now that everything is ready, program the new timings
        !           575:         */
        !           576:        save_flags (flags);
        !           577:        cli();
        !           578:        /*
        !           579:         * Program the address_setup clocks into ARTTIM reg,
        !           580:         * and then the active/recovery counts into the DRWTIM reg
        !           581:         * (this converts counts of 16 into counts of zero -- okay).
        !           582:         */
        !           583:        setup_count |= get_cmd640_reg(arttim_regs[index]) & 0x3f;
        !           584:        put_cmd640_reg(arttim_regs[index], setup_count);
        !           585:        put_cmd640_reg(drwtim_regs[index], pack_nibbles(active_count, recovery_count));
        !           586:        restore_flags(flags);
        !           587: }
        !           588: 
        !           589: /*
        !           590:  * Set a specific pio_mode for a drive
        !           591:  */
        !           592: static void cmd640_set_mode (unsigned int index, byte pio_mode, unsigned int cycle_time)
        !           593: {
        !           594:        int setup_time, active_time, recovery_time, clock_time;
        !           595:        byte setup_count, active_count, recovery_count, recovery_count2, cycle_count;
        !           596:        int bus_speed = ide_system_bus_speed();
        !           597: 
        !           598:        if (pio_mode > 5)
        !           599:                pio_mode = 5;
        !           600:        setup_time  = ide_pio_timings[pio_mode].setup_time;
        !           601:        active_time = ide_pio_timings[pio_mode].active_time;
        !           602:        recovery_time = cycle_time - (setup_time + active_time);
        !           603:        clock_time = 1000 / bus_speed;
        !           604:        cycle_count = (cycle_time + clock_time - 1) / clock_time;
        !           605: 
        !           606:        setup_count = (setup_time + clock_time - 1) / clock_time;
        !           607: 
        !           608:        active_count = (active_time + clock_time - 1) / clock_time;
        !           609:        if (active_count < 2)
        !           610:                active_count = 2; /* minimum allowed by cmd640 */
        !           611: 
        !           612:        recovery_count = (recovery_time + clock_time - 1) / clock_time;
        !           613:        recovery_count2 = cycle_count - (setup_count + active_count);
        !           614:        if (recovery_count2 > recovery_count)
        !           615:                recovery_count = recovery_count2;
        !           616:        if (recovery_count < 2)
        !           617:                recovery_count = 2; /* minimum allowed by cmd640 */
        !           618:        if (recovery_count > 17) {
        !           619:                active_count += recovery_count - 17;
        !           620:                recovery_count = 17;
        !           621:        }
        !           622:        if (active_count > 16)
        !           623:                active_count = 16; /* maximum allowed by cmd640 */
        !           624:        if (cmd640_chip_version > 1)
        !           625:                recovery_count -= 1;  /* cmd640b uses (count + 1)*/
        !           626:        if (recovery_count > 16)
        !           627:                recovery_count = 16; /* maximum allowed by cmd640 */
        !           628: 
        !           629:        setup_counts[index]    = setup_count;
        !           630:        active_counts[index]   = active_count;
        !           631:        recovery_counts[index] = recovery_count;
        !           632: 
        !           633:        /*
        !           634:         * In a perfect world, we might set the drive pio mode here
        !           635:         * (using WIN_SETFEATURE) before continuing.
        !           636:         *
        !           637:         * But we do not, because:
        !           638:         *      1) this is the wrong place to do it (proper is do_special() in ide.c)
        !           639:         *      2) in practice this is rarely, if ever, necessary
        !           640:         */
        !           641:        program_drive_counts (index);
        !           642: }
        !           643: 
        !           644: /*
        !           645:  * Drive PIO mode selection:
        !           646:  */
        !           647: static void cmd640_tune_drive (ide_drive_t *drive, byte mode_wanted)
        !           648: {
        !           649:        byte b;
        !           650:        ide_pio_data_t  d;
        !           651:        unsigned int index = 0;
        !           652: 
        !           653:        while (drive != cmd_drives[index]) {
        !           654:                if (++index > 3) {
        !           655:                        printk("%s: bad news in cmd640_tune_drive\n", drive->name);
        !           656:                        return;
        !           657:                }
        !           658:        }
        !           659:        switch (mode_wanted) {
        !           660:                case 6: /* set fast-devsel off */
        !           661:                case 7: /* set fast-devsel on */
        !           662:                        mode_wanted &= 1;
        !           663:                        b = get_cmd640_reg(CNTRL) & ~0x27;
        !           664:                        if (mode_wanted)
        !           665:                                b |= 0x27;
        !           666:                        put_cmd640_reg(CNTRL, b);
        !           667:                        printk("%s: %sabled cmd640 fast host timing (devsel)\n", drive->name, mode_wanted ? "en" : "dis");
        !           668:                        return;
        !           669: 
        !           670:                case 8: /* set prefetch off */
        !           671:                case 9: /* set prefetch on */
        !           672:                        mode_wanted &= 1;
        !           673:                        set_prefetch_mode(index, mode_wanted);
        !           674:                        printk("%s: %sabled cmd640 prefetch\n", drive->name, mode_wanted ? "en" : "dis");
        !           675:                        return;
        !           676:        }
        !           677: 
        !           678:        (void) ide_get_best_pio_mode (drive, mode_wanted, 5, &d);
        !           679:        cmd640_set_mode (index, d.pio_mode, d.cycle_time);
        !           680: 
        !           681:        printk ("%s: selected cmd640 PIO mode%d (%dns) %s/IORDY%s",
        !           682:                drive->name,
        !           683:                d.pio_mode,
        !           684:                d.cycle_time,
        !           685:                d.use_iordy ? "w" : "wo",
        !           686:                d.overridden ? " (overriding vendor mode)" : "");
        !           687:        display_clocks(index);
        !           688: }
        !           689: 
        !           690: #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
        !           691: 
        !           692: /*
        !           693:  * Probe for a cmd640 chipset, and initialize it if found.  Called from ide.c
        !           694:  */
        !           695: int ide_probe_for_cmd640x (void)
        !           696: {
        !           697: #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
        !           698:        int second_port_toggled = 0;
        !           699: #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
        !           700:        int second_port_cmd640 = 0;
        !           701:        const char *bus_type, *port2;
        !           702:        unsigned int index;
        !           703:        byte b, cfr;
        !           704: 
        !           705:        if (cmd640_vlb && probe_for_cmd640_vlb()) {
        !           706:                bus_type = "VLB";
        !           707:        } else {
        !           708:                cmd640_vlb = 0;
        !           709:                if (probe_for_cmd640_pci1())
        !           710:                        bus_type = "PCI (type1)";
        !           711:                else if (probe_for_cmd640_pci2())
        !           712:                        bus_type = "PCI (type2)";
        !           713:                else
        !           714:                        return 0;
        !           715:        }
        !           716:        /*
        !           717:         * Undocumented magic (there is no 0x5b reg in specs)
        !           718:         */
        !           719:        put_cmd640_reg(0x5b, 0xbd);
        !           720:        if (get_cmd640_reg(0x5b) != 0xbd) {
        !           721:                printk("ide: cmd640 init failed: wrong value in reg 0x5b\n");
        !           722:                return 0;
        !           723:        }
        !           724:        put_cmd640_reg(0x5b, 0);
        !           725: 
        !           726: #ifdef CMD640_DUMP_REGS
        !           727:        CMD640_DUMP_REGS;
        !           728: #endif
        !           729: 
        !           730:        /*
        !           731:         * Documented magic begins here
        !           732:         */
        !           733:        cfr = get_cmd640_reg(CFR);
        !           734:        cmd640_chip_version = cfr & CFR_DEVREV;
        !           735:        if (cmd640_chip_version == 0) {
        !           736:                printk ("ide: bad cmd640 revision: %d\n", cmd640_chip_version);
        !           737:                return 0;
        !           738:        }
        !           739: 
        !           740:        /*
        !           741:         * Initialize data for primary port
        !           742:         */
        !           743:        setup_device_ptrs ();
        !           744:        printk("%s: buggy cmd640%c interface on %s, config=0x%02x\n",
        !           745:               cmd_hwif0->name, 'a' + cmd640_chip_version - 1, bus_type, cfr);
        !           746:        cmd_hwif0->chipset = ide_cmd640;
        !           747: #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
        !           748:        cmd_hwif0->tuneproc = &cmd640_tune_drive;
        !           749: #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
        !           750: 
        !           751:        /*
        !           752:         * Ensure compatibility by always using the slowest timings
        !           753:         * for access to the drive's command register block,
        !           754:         * and reset the prefetch burstsize to default (512 bytes).
        !           755:         *
        !           756:         * Maybe we need a way to NOT do these on *some* systems?
        !           757:         */
        !           758:        put_cmd640_reg(CMDTIM, 0);
        !           759:        put_cmd640_reg(BRST, 0x40);
        !           760: 
        !           761:        /*
        !           762:         * Try to enable the secondary interface, if not already enabled
        !           763:         */
        !           764:        if (cmd_hwif1->noprobe) {
        !           765:                port2 = "not probed";
        !           766:        } else {
        !           767:                b = get_cmd640_reg(CNTRL);
        !           768:                if (secondary_port_responding()) {
        !           769:                        if ((b & CNTRL_ENA_2ND)) {
        !           770:                                second_port_cmd640 = 1;
        !           771:                                port2 = "okay";
        !           772:                        } else if (cmd640_vlb) {
        !           773:                                second_port_cmd640 = 1;
        !           774:                                port2 = "alive";
        !           775:                        } else
        !           776:                                port2 = "not cmd640";
        !           777:                } else {
        !           778:                        put_cmd640_reg(CNTRL, b ^ CNTRL_ENA_2ND); /* toggle the bit */
        !           779:                        if (secondary_port_responding()) {
        !           780:                                second_port_cmd640 = 1;
        !           781: #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
        !           782:                                second_port_toggled = 1;
        !           783: #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
        !           784:                                port2 = "enabled";
        !           785:                        } else {
        !           786:                                put_cmd640_reg(CNTRL, b); /* restore original setting */
        !           787:                                port2 = "not responding";
        !           788:                        }
        !           789:                }
        !           790:        }
        !           791: 
        !           792:        /*
        !           793:         * Initialize data for secondary cmd640 port, if enabled
        !           794:         */
        !           795:        if (second_port_cmd640) {
        !           796:                cmd_hwif0->serialized = 1;
        !           797:                cmd_hwif1->serialized = 1;
        !           798:                cmd_hwif1->chipset = ide_cmd640;
        !           799: #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
        !           800:                cmd_hwif1->tuneproc = &cmd640_tune_drive;
        !           801: #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
        !           802:        }
        !           803:        printk("%s: %sserialized, secondary interface %s\n", cmd_hwif1->name,
        !           804:                cmd_hwif0->serialized ? "" : "not ", port2);
        !           805: 
        !           806:        /*
        !           807:         * Establish initial timings/prefetch for all drives.
        !           808:         * Do not unnecessarily disturb any prior BIOS setup of these.
        !           809:         */
        !           810:        for (index = 0; index < (2 + (second_port_cmd640 << 1)); index++) {
        !           811:                ide_drive_t *drive = cmd_drives[index];
        !           812: #ifdef CONFIG_BLK_DEV_CMD640_ENHANCED
        !           813:                if (drive->autotune || ((index > 1) && second_port_toggled)) {
        !           814:                        /*
        !           815:                         * Reset timing to the slowest speed and turn off prefetch.
        !           816:                         * This way, the drive identify code has a better chance.
        !           817:                         */
        !           818:                        setup_counts    [index] = 4;    /* max possible */
        !           819:                        active_counts   [index] = 16;   /* max possible */
        !           820:                        recovery_counts [index] = 16;   /* max possible */
        !           821:                        program_drive_counts (index);
        !           822:                        set_prefetch_mode (index, 0);
        !           823:                        printk("cmd640: drive%d timings/prefetch cleared\n", index);
        !           824:                } else {
        !           825:                        /*
        !           826:                         * Record timings/prefetch without changing them.
        !           827:                         * This preserves any prior BIOS setup.
        !           828:                         */
        !           829:                        retrieve_drive_counts (index);
        !           830:                        check_prefetch (index);
        !           831:                        printk("cmd640: drive%d timings/prefetch(%s) preserved",
        !           832:                                index, drive->no_io_32bit ? "off" : "on");
        !           833:                        display_clocks(index);
        !           834:                }
        !           835: #else
        !           836:                /*
        !           837:                 * Set the drive unmask flags to match the prefetch setting
        !           838:                 */
        !           839:                check_prefetch (index);
        !           840:                printk("cmd640: drive%d timings/prefetch(%s) preserved\n",
        !           841:                        index, drive->no_io_32bit ? "off" : "on");
        !           842: #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */
        !           843:        }
        !           844: 
        !           845: #ifdef CMD640_DUMP_REGS
        !           846:        CMD640_DUMP_REGS;
        !           847: #endif
        !           848:        return 1;
        !           849: }
        !           850: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.