Annotation of Gnu-Mach/i386/i386at/gpl/linux/block/cmd640.c, revision 1.1

1.1     ! root        1: /*
        !             2:  *  linux/drivers/block/cmd640.c       Version 0.07  Jan 27, 1996
        !             3:  *
        !             4:  *  Copyright (C) 1995-1996  Linus Torvalds & author (see below)
        !             5:  */
        !             6: 
        !             7: /*
        !             8:  *  Principal Author/Maintainer:  [email protected] (Igor Abramov)
        !             9:  *
        !            10:  *  This file provides support for the advanced features and bugs
        !            11:  *  of IDE interfaces using the CMD Technologies 0640 IDE interface chip.
        !            12:  *
        !            13:  *  Version 0.01       Initial version, hacked out of ide.c,
        !            14:  *                     and #include'd rather than compiled separately.
        !            15:  *                     This will get cleaned up in a subsequent release.
        !            16:  *
        !            17:  *  Version 0.02       Fixes for vlb initialization code, enable
        !            18:  *                     read-ahead for versions 'B' and 'C' of chip by
        !            19:  *                     default, some code cleanup.
        !            20:  *
        !            21:  *  Version 0.03       Added reset of secondary interface,
        !            22:  *                     and black list for devices which are not compatible
        !            23:  *                     with read ahead mode. Separate function for setting
        !            24:  *                     readahead is added, possibly it will be called some
        !            25:  *                     day from ioctl processing code.
        !            26:  *  
        !            27:  *  Version 0.04       Now configs/compiles separate from ide.c  -ml 
        !            28:  *
        !            29:  *  Version 0.05       Major rewrite of interface timing code.
        !            30:  *                     Added new function cmd640_set_mode to set PIO mode
        !            31:  *                     from ioctl call. New drives added to black list.
        !            32:  *
        !            33:  *  Version 0.06       More code cleanup. Readahead is enabled only for
        !            34:  *                     detected hard drives, not included in readahed
        !            35:  *                     black list.
        !            36:  * 
        !            37:  *  Version 0.07       Changed to more conservative drive tuning policy.
        !            38:  *                     Unknown drives, which report PIO < 4 are set to 
        !            39:  *                     (reported_PIO - 1) if it is supported, or to PIO0.
        !            40:  *                     List of known drives extended by info provided by
        !            41:  *                     CMD at their ftp site.
        !            42:  *
        !            43:  *  Version 0.08       Added autotune/noautotune support.  -ml
        !            44:  *                     
        !            45:  */
        !            46: 
        !            47: #undef REALLY_SLOW_IO          /* most systems can safely undef this */
        !            48: 
        !            49: #include <linux/types.h>
        !            50: #include <linux/kernel.h>
        !            51: #include <linux/delay.h>
        !            52: #include <linux/timer.h>
        !            53: #include <linux/mm.h>
        !            54: #include <linux/ioport.h>
        !            55: #include <linux/blkdev.h>
        !            56: #include <linux/hdreg.h>
        !            57: #include <asm/io.h>
        !            58: #include "ide.h"
        !            59: #include "ide_modes.h"
        !            60: 
        !            61: int cmd640_vlb = 0;
        !            62: 
        !            63: /*
        !            64:  * CMD640 specific registers definition.
        !            65:  */
        !            66: 
        !            67: #define VID            0x00
        !            68: #define DID            0x02
        !            69: #define PCMD           0x04
        !            70: #define PSTTS          0x06
        !            71: #define REVID          0x08
        !            72: #define PROGIF         0x09
        !            73: #define SUBCL          0x0a
        !            74: #define BASCL          0x0b
        !            75: #define BaseA0         0x10
        !            76: #define BaseA1         0x14
        !            77: #define BaseA2         0x18
        !            78: #define BaseA3         0x1c
        !            79: #define INTLINE                0x3c
        !            80: #define INPINE         0x3d
        !            81: 
        !            82: #define        CFR             0x50
        !            83: #define   CFR_DEVREV           0x03
        !            84: #define   CFR_IDE01INTR                0x04
        !            85: #define          CFR_DEVID             0x18
        !            86: #define          CFR_AT_VESA_078h      0x20
        !            87: #define          CFR_DSA1              0x40
        !            88: #define          CFR_DSA0              0x80
        !            89: 
        !            90: #define CNTRL          0x51
        !            91: #define          CNTRL_DIS_RA0         0x40
        !            92: #define   CNTRL_DIS_RA1                0x80
        !            93: #define          CNTRL_ENA_2ND         0x08
        !            94: 
        !            95: #define        CMDTIM          0x52
        !            96: #define        ARTTIM0         0x53
        !            97: #define        DRWTIM0         0x54
        !            98: #define ARTTIM1        0x55
        !            99: #define DRWTIM1                0x56
        !           100: #define ARTTIM23       0x57
        !           101: #define   DIS_RA2              0x04
        !           102: #define   DIS_RA3              0x08
        !           103: #define DRWTIM23       0x58
        !           104: #define BRST           0x59
        !           105: 
        !           106: static ide_tuneproc_t cmd640_tune_drive;
        !           107: 
        !           108: /* Interface to access cmd640x registers */
        !           109: static void (*put_cmd640_reg)(int reg_no, int val);
        !           110: static byte (*get_cmd640_reg)(int reg_no);
        !           111: 
        !           112: enum { none, vlb, pci1, pci2 };
        !           113: static int     bus_type = none;
        !           114: static int     cmd640_chip_version;
        !           115: static int     cmd640_key;
        !           116: static int     bus_speed; /* MHz */
        !           117: 
        !           118: /*
        !           119:  * For some unknown reasons pcibios functions which read and write registers
        !           120:  * do not always work with cmd640. We use direct IO instead.
        !           121:  */
        !           122: 
        !           123: /* PCI method 1 access */
        !           124: 
        !           125: static void put_cmd640_reg_pci1(int reg_no, int val)
        !           126: {
        !           127:        unsigned long flags;
        !           128: 
        !           129:        save_flags(flags);
        !           130:        cli();
        !           131:        outl_p((reg_no & 0xfc) | cmd640_key, 0xcf8);
        !           132:        outb_p(val, (reg_no & 3) + 0xcfc);
        !           133:        restore_flags(flags);
        !           134: }
        !           135: 
        !           136: static byte get_cmd640_reg_pci1(int reg_no)
        !           137: {
        !           138:        byte b;
        !           139:        unsigned long flags;
        !           140: 
        !           141:        save_flags(flags);
        !           142:        cli();
        !           143:        outl_p((reg_no & 0xfc) | cmd640_key, 0xcf8);
        !           144:        b = inb_p(0xcfc + (reg_no & 3));
        !           145:        restore_flags(flags);
        !           146:        return b;
        !           147: }
        !           148: 
        !           149: /* PCI method 2 access (from CMD datasheet) */
        !           150:  
        !           151: static void put_cmd640_reg_pci2(int reg_no, int val)
        !           152: {
        !           153:        unsigned long flags;
        !           154: 
        !           155:        save_flags(flags);
        !           156:        cli();
        !           157:        outb_p(0x10, 0xcf8);
        !           158:        outb_p(val, cmd640_key + reg_no);
        !           159:        outb_p(0, 0xcf8);
        !           160:        restore_flags(flags);
        !           161: }
        !           162: 
        !           163: static byte get_cmd640_reg_pci2(int reg_no)
        !           164: {
        !           165:        byte b;
        !           166:        unsigned long flags;
        !           167: 
        !           168:        save_flags(flags);
        !           169:        cli();
        !           170:        outb_p(0x10, 0xcf8);
        !           171:        b = inb_p(cmd640_key + reg_no);
        !           172:        outb_p(0, 0xcf8);
        !           173:        restore_flags(flags);
        !           174:        return b;
        !           175: }
        !           176: 
        !           177: /* VLB access */
        !           178: 
        !           179: static void put_cmd640_reg_vlb(int reg_no, int val)
        !           180: {
        !           181:        unsigned long flags;
        !           182: 
        !           183:        save_flags(flags);
        !           184:        cli();
        !           185:        outb_p(reg_no, cmd640_key + 8);
        !           186:        outb_p(val, cmd640_key + 0xc);
        !           187:        restore_flags(flags);
        !           188: }
        !           189: 
        !           190: static byte get_cmd640_reg_vlb(int reg_no)
        !           191: {
        !           192:        byte b;
        !           193:        unsigned long flags;
        !           194: 
        !           195:        save_flags(flags);
        !           196:        cli();
        !           197:        outb_p(reg_no, cmd640_key + 8);
        !           198:        b = inb_p(cmd640_key + 0xc);
        !           199:        restore_flags(flags);
        !           200:        return b;
        !           201: }
        !           202: 
        !           203: /*
        !           204:  * Probe for CMD640x -- pci method 1
        !           205:  */
        !           206: 
        !           207: static int probe_for_cmd640_pci1(void)
        !           208: {
        !           209:        long id;
        !           210:        int     k;
        !           211: 
        !           212:        for (k = 0x80000000; k <= 0x8000f800; k += 0x800) {
        !           213:                outl(k, 0xcf8);
        !           214:                id = inl(0xcfc);
        !           215:                if (id != 0x06401095)
        !           216:                        continue;
        !           217:                put_cmd640_reg = put_cmd640_reg_pci1;
        !           218:                get_cmd640_reg = get_cmd640_reg_pci1;
        !           219:                cmd640_key = k;
        !           220:                return 1;
        !           221:        }
        !           222:        return 0;
        !           223: }
        !           224: 
        !           225: /*
        !           226:  * Probe for CMD640x -- pci method 2
        !           227:  */
        !           228: 
        !           229: static int probe_for_cmd640_pci2(void)
        !           230: {
        !           231:        int i;
        !           232:        int v_id;
        !           233:        int d_id;
        !           234: 
        !           235:        for (i = 0xc000; i <= 0xcf00; i += 0x100) {
        !           236:                outb(0x10, 0xcf8);
        !           237:                v_id = inw(i);
        !           238:                d_id = inw(i + 2);
        !           239:                outb(0, 0xcf8);
        !           240:                if (v_id != 0x1095 || d_id != 0x640)
        !           241:                        continue;
        !           242:                put_cmd640_reg = put_cmd640_reg_pci2;
        !           243:                get_cmd640_reg = get_cmd640_reg_pci2;
        !           244:                cmd640_key = i;
        !           245:                return 1;
        !           246:        }
        !           247:        return 0;
        !           248: }
        !           249: 
        !           250: /*
        !           251:  * Probe for CMD640x -- vlb
        !           252:  */
        !           253: 
        !           254: static int probe_for_cmd640_vlb(void) {
        !           255:        byte b;
        !           256: 
        !           257:        outb(CFR, 0x178);
        !           258:        b = inb(0x17c);
        !           259:        if (b == 0xff || b == 0 || (b & CFR_AT_VESA_078h)) {
        !           260:                outb(CFR, 0x78);
        !           261:                b = inb(0x7c);
        !           262:                if (b == 0xff || b == 0 || !(b & CFR_AT_VESA_078h))
        !           263:                        return 0;
        !           264:                cmd640_key = 0x70;
        !           265:        } else {
        !           266:                cmd640_key = 0x170;
        !           267:        }
        !           268:        put_cmd640_reg = put_cmd640_reg_vlb;
        !           269:        get_cmd640_reg = get_cmd640_reg_vlb;
        !           270:        return 1;
        !           271: }
        !           272: 
        !           273: /*
        !           274:  * Low level reset for controller, actually it has nothing specific for
        !           275:  * CMD640, but I don't know how to use standard reset routine before
        !           276:  * we recognized any drives.
        !           277:  */
        !           278: 
        !           279: static void cmd640_reset_controller(int iface_no)
        !           280: {
        !           281:        int retry_count = 600;
        !           282:        int base_port = iface_no ? 0x170 : 0x1f0;
        !           283: 
        !           284:        outb_p(4, base_port + 7);
        !           285:        udelay(5);
        !           286:        outb_p(0, base_port + 7);
        !           287: 
        !           288:        do {
        !           289:                udelay(5);
        !           290:                retry_count -= 1;
        !           291:        } while ((inb_p(base_port + 7) & 0x80) && retry_count);
        !           292: 
        !           293:        if (retry_count == 0)
        !           294:                printk("cmd640: failed to reset controller %d\n", iface_no);
        !           295: #if 0  
        !           296:        else
        !           297:                printk("cmd640: controller %d reset [%d]\n", 
        !           298:                        iface_no, retry_count);
        !           299: #endif
        !           300: }
        !           301: 
        !           302: /*
        !           303:  * Probe for Cmd640x and initialize it if found
        !           304:  */
        !           305: 
        !           306: int ide_probe_for_cmd640x(void)
        !           307: {
        !           308:        int  second_port;
        !           309:         byte b;
        !           310: 
        !           311:        if (probe_for_cmd640_pci1()) {
        !           312:                bus_type = pci1;
        !           313:        } else if (probe_for_cmd640_pci2()) {
        !           314:                bus_type = pci2;
        !           315:        } else if (cmd640_vlb && probe_for_cmd640_vlb()) {
        !           316:                /* May be remove cmd640_vlb at all, and probe in any case */
        !           317:                bus_type = vlb;
        !           318:        } else {
        !           319:                return 0;
        !           320:        }
        !           321: 
        !           322:        ide_hwifs[0].serialized = 1;    /* ensure this *always* gets set */
        !           323:        
        !           324: #if 0  
        !           325:        /* Dump initial state of chip registers */
        !           326:        for (b = 0; b != 0xff; b++) {
        !           327:                printk(" %2x%c", get_cmd640_reg(b),
        !           328:                                ((b&0xf) == 0xf) ? '\n' : ',');
        !           329:        }
        !           330: 
        !           331: #endif
        !           332: 
        !           333:        /*
        !           334:         * Undocumented magic. (There is no 0x5b port in specs)
        !           335:         */
        !           336: 
        !           337:        put_cmd640_reg(0x5b, 0xbd);
        !           338:        if (get_cmd640_reg(0x5b) != 0xbd) {
        !           339:                printk("ide: can't initialize cmd640 -- wrong value in 0x5b\n");
        !           340:                return 0;
        !           341:        }
        !           342:        put_cmd640_reg(0x5b, 0);
        !           343: 
        !           344:        /*
        !           345:         * Documented magic.
        !           346:         */
        !           347: 
        !           348:        cmd640_chip_version = get_cmd640_reg(CFR) & CFR_DEVREV;
        !           349:        if (cmd640_chip_version == 0) {
        !           350:                printk ("ide: wrong CMD640 version -- 0\n");
        !           351:                return 0;
        !           352:        }
        !           353: 
        !           354:        /*
        !           355:         * Setup the most conservative timings for all drives,
        !           356:         */
        !           357:        put_cmd640_reg(ARTTIM0, 0xc0);
        !           358:        put_cmd640_reg(ARTTIM1, 0xc0);
        !           359:        put_cmd640_reg(ARTTIM23, 0xcc); /* 0xc0? */
        !           360: 
        !           361:        /*
        !           362:         * Do not initialize secondary controller for vlbus
        !           363:         */
        !           364:        second_port = (bus_type != vlb);
        !           365: 
        !           366:        /*
        !           367:         * Set the maximum allowed bus speed (it is safest until we
        !           368:         *                                    find how to detect bus speed)
        !           369:         * Normally PCI bus runs at 33MHz, but often works overclocked to 40
        !           370:         */
        !           371:        bus_speed = (bus_type == vlb) ? 50 : 40; 
        !           372: 
        !           373:         /*
        !           374:         * Setup Control Register
        !           375:         */
        !           376:        b = get_cmd640_reg(CNTRL);      
        !           377: 
        !           378:        if (second_port)
        !           379:                b |= CNTRL_ENA_2ND;
        !           380:        else
        !           381:                b &= ~CNTRL_ENA_2ND;
        !           382: 
        !           383:        /*
        !           384:         * Disable readahead for drives at primary interface
        !           385:         */
        !           386:        b |= (CNTRL_DIS_RA0 | CNTRL_DIS_RA1);
        !           387: 
        !           388:         put_cmd640_reg(CNTRL, b);
        !           389: 
        !           390:        /*
        !           391:         * Note that we assume that the first interface is at 0x1f0,
        !           392:         * and that the second interface, if enabled, is at 0x170.
        !           393:         */
        !           394:        ide_hwifs[0].chipset = ide_cmd640;
        !           395:        ide_hwifs[0].tuneproc = &cmd640_tune_drive;
        !           396:        if (ide_hwifs[0].drives[0].autotune == 0)
        !           397:                ide_hwifs[0].drives[0].autotune = 1;
        !           398:        if (ide_hwifs[0].drives[1].autotune == 0)
        !           399:                ide_hwifs[0].drives[1].autotune = 1;
        !           400: 
        !           401:        /*
        !           402:         * Initialize 2nd IDE port, if required
        !           403:         */
        !           404:        if (second_port) {
        !           405:                ide_hwifs[1].chipset = ide_cmd640;
        !           406:                ide_hwifs[1].tuneproc = &cmd640_tune_drive;
        !           407:                if (ide_hwifs[1].drives[0].autotune == 0)
        !           408:                        ide_hwifs[1].drives[0].autotune = 1;
        !           409:                if (ide_hwifs[1].drives[1].autotune == 0)
        !           410:                        ide_hwifs[1].drives[1].autotune = 1;
        !           411:                /* We reset timings, and disable read-ahead */
        !           412:                put_cmd640_reg(ARTTIM23, (DIS_RA2 | DIS_RA3));
        !           413:                put_cmd640_reg(DRWTIM23, 0);
        !           414: 
        !           415:                cmd640_reset_controller(1);
        !           416:        }
        !           417: 
        !           418:        printk("ide: buggy CMD640%c interface at ", 
        !           419:               'A' - 1 + cmd640_chip_version);
        !           420:        switch (bus_type) {
        !           421:                case vlb :
        !           422:                        printk("local bus, port 0x%x", cmd640_key);
        !           423:                        break;
        !           424:                case pci1:
        !           425:                        printk("pci, (0x%x)", cmd640_key);
        !           426:                        break;
        !           427:                case pci2:
        !           428:                        printk("pci,(access method 2) (0x%x)", cmd640_key);
        !           429:                        break;
        !           430:        }
        !           431: 
        !           432:        /*
        !           433:         * Reset interface timings
        !           434:         */
        !           435:        put_cmd640_reg(CMDTIM, 0);
        !           436: 
        !           437:        printk("\n ... serialized, secondary interface %s\n",
        !           438:               second_port ? "enabled" : "disabled");
        !           439: 
        !           440:        return 1;
        !           441: }
        !           442: 
        !           443: int cmd640_off(void) {
        !           444:        static int a = 0;
        !           445:        byte b;
        !           446: 
        !           447:        if (bus_type == none || a == 1)
        !           448:                return 0;
        !           449:        a = 1;
        !           450:        b = get_cmd640_reg(CNTRL);      
        !           451:        b &= ~CNTRL_ENA_2ND;
        !           452:        put_cmd640_reg(CNTRL, b);
        !           453:        return 1;
        !           454: }
        !           455: 
        !           456: /*
        !           457:  * Sets readahead mode for specific drive
        !           458:  *  in the future it could be called from ioctl
        !           459:  */
        !           460: 
        !           461: static void set_readahead_mode(int mode, int if_num, int dr_num)
        !           462: {
        !           463:        static int masks[2][2] = 
        !           464:                { 
        !           465:                        {CNTRL_DIS_RA0, CNTRL_DIS_RA1}, 
        !           466:                        {DIS_RA2,       DIS_RA3}
        !           467:                };
        !           468: 
        !           469:        int port = (if_num == 0) ? CNTRL : ARTTIM23;
        !           470:        int mask = masks[if_num][dr_num];
        !           471:        byte b;
        !           472: 
        !           473:        b = get_cmd640_reg(port);
        !           474:        if (mode)
        !           475:                b &= ~mask;     /* Enable readahead for specific drive */
        !           476:        else
        !           477:                b |= mask;      /* Disable readahed for specific drive */
        !           478:        put_cmd640_reg(port, b);
        !           479: }              
        !           480: 
        !           481: static struct readahead_black_list {
        !           482:        const char*     name;
        !           483:        int             mode;   
        !           484: } drives_ra[] = {
        !           485:         { "ST3655A",   0 },
        !           486:         { "SAMSUNG",   0 },    /* Be conservative */
        !           487:        { NULL, 0 }
        !           488: };     
        !           489: 
        !           490: static int strmatch(const char* pattern, const char* name) {
        !           491:        char c1, c2;
        !           492: 
        !           493:        while (1) {
        !           494:                c1 = *pattern++;
        !           495:                c2 = *name++;
        !           496:                if (c1 == 0) {
        !           497:                        return 0;
        !           498:                }
        !           499:                if (c1 != c2)
        !           500:                        return 1;
        !           501:        }
        !           502: }
        !           503: 
        !           504: static int known_drive_readahead(char* name) {
        !           505:        int i;
        !           506: 
        !           507:        for (i = 0; drives_ra[i].name != NULL; i++) {
        !           508:                if (strmatch(drives_ra[i].name, name) == 0) {
        !           509:                        return drives_ra[i].mode;
        !           510:                }
        !           511:        }
        !           512:         return -1;
        !           513: }
        !           514: 
        !           515: static int arttim[4]  = {2, 2, 2, 2};  /* Address setup count (in clocks) */
        !           516: static int a_count[4] = {1, 1, 1, 1};  /* Active count   (encoded) */
        !           517: static int r_count[4] = {1, 1, 1, 1};  /* Recovery count (encoded) */
        !           518: 
        !           519: /*
        !           520:  * Convert address setup count from number of clocks 
        !           521:  * to representation used by controller
        !           522:  */
        !           523: 
        !           524: inline static int pack_arttim(int clocks)
        !           525: {
        !           526:        if (clocks <= 2) return 0x40;
        !           527:        else if (clocks == 3) return 0x80;
        !           528:        else if (clocks == 4) return 0x00;
        !           529:        else return 0xc0;
        !           530: }
        !           531: 
        !           532: /*
        !           533:  * Pack active and recovery counts into single byte representation
        !           534:  * used by controller
        !           535:  */
        !           536: 
        !           537: inline static int pack_counts(int act_count, int rec_count)
        !           538: {
        !           539:        return ((act_count & 0x0f)<<4) | (rec_count & 0x0f);
        !           540: }
        !           541: 
        !           542: inline int max(int a, int b) { return a > b ? a : b; }
        !           543: inline int max4(int *p) { return max(p[0], max(p[1], max(p[2], p[3]))); }
        !           544: 
        !           545: /*
        !           546:  * Set timing parameters
        !           547:  */
        !           548: 
        !           549: static void cmd640_set_timing(int if_num, int dr_num)
        !           550: {
        !           551:        int     b_reg;
        !           552:        int     ac, rc, at;
        !           553: 
        !           554:        /*
        !           555:         * Set address setup count and drive read/write timing registers.
        !           556:         * Primary interface has individual count/timing registers for
        !           557:         * each drive. Secondary interface has common set of registers, and
        !           558:         * we should set timings for the slowest drive.
        !           559:         */
        !           560: 
        !           561:        if (if_num == 0) {
        !           562:                b_reg = dr_num ? ARTTIM1 : ARTTIM0;
        !           563:                at = arttim[dr_num];
        !           564:                ac = a_count[dr_num];
        !           565:                rc = r_count[dr_num];
        !           566:        } else {
        !           567:                b_reg = ARTTIM23;
        !           568:                at = max(arttim[2], arttim[3]);
        !           569:                ac = max(a_count[2], a_count[3]);
        !           570:                rc = max(r_count[2], r_count[3]);
        !           571:        }
        !           572: 
        !           573:        put_cmd640_reg(b_reg, pack_arttim(at));
        !           574:        put_cmd640_reg(b_reg + 1, pack_counts(ac, rc));
        !           575: 
        !           576:        /*
        !           577:         * Update CMDTIM (IDE Command Block Timing Register) 
        !           578:         */
        !           579: 
        !           580:        ac = max4(r_count);
        !           581:        rc = max4(a_count);
        !           582:        put_cmd640_reg(CMDTIM, pack_counts(ac, rc));
        !           583: }
        !           584: 
        !           585: /*
        !           586:  * Standard timings for PIO modes
        !           587:  */
        !           588: 
        !           589: static struct pio_timing {
        !           590:        int     mc_time;        /* Minimal cycle time (ns) */
        !           591:        int     av_time;        /* Address valid to DIOR-/DIOW- setup (ns) */
        !           592:        int     ds_time;        /* DIOR data setup      (ns) */
        !           593: } pio_timings[6] = {
        !           594:        { 70,   165,    600 },  /* PIO Mode 0 */
        !           595:        { 50,   125,    383 },  /* PIO Mode 1 */
        !           596:        { 30,   100,    240 },  /* PIO Mode 2 */
        !           597:        { 30,   80,     180 },  /* PIO Mode 3 */
        !           598:        { 25,   70,     125 },  /* PIO Mode 4  -- should be 120, not 125 */
        !           599:        { 20,   50,     100 }   /* PIO Mode ? (nonstandard) */
        !           600: };
        !           601: 
        !           602: static void cmd640_timings_to_clocks(int mc_time, int av_time, int ds_time,
        !           603:                                int clock_time, int drv_idx)
        !           604: {
        !           605:        int a, b;
        !           606: 
        !           607:        arttim[drv_idx] = (mc_time + clock_time - 1)/clock_time;
        !           608: 
        !           609:        a = (av_time + clock_time - 1)/clock_time;
        !           610:        if (a < 2)
        !           611:                a = 2;
        !           612:        b = (ds_time + clock_time - 1)/clock_time - a;
        !           613:        if (b < 2)
        !           614:                b = 2;
        !           615:        if (b > 0x11) {
        !           616:                a += b - 0x11;
        !           617:                b = 0x11;
        !           618:        }
        !           619:        if (a > 0x10)
        !           620:                a = 0x10;
        !           621:        if (cmd640_chip_version > 1)
        !           622:                b -= 1;
        !           623:        if (b > 0x10)
        !           624:                b = 0x10;
        !           625: 
        !           626:        a_count[drv_idx] = a;
        !           627:        r_count[drv_idx] = b;
        !           628: }
        !           629: 
        !           630: static void set_pio_mode(int if_num, int drv_num, int mode_num) {
        !           631:        int p_base;
        !           632:        int i;
        !           633: 
        !           634:        p_base = if_num ? 0x170 : 0x1f0;
        !           635:        outb_p(3, p_base + 1);
        !           636:        outb_p(mode_num | 8, p_base + 2);
        !           637:        outb_p((drv_num | 0xa) << 4, p_base + 6);
        !           638:        outb_p(0xef, p_base + 7);
        !           639:        for (i = 0; (i < 100) && (inb (p_base + 7) & 0x80); i++)
        !           640:                udelay(10000);
        !           641: }
        !           642: 
        !           643: /*
        !           644:  * Set a specific pio_mode for a drive
        !           645:  */
        !           646: 
        !           647: static void cmd640_set_mode(ide_drive_t* drive, int pio_mode) {
        !           648:        int interface_number;
        !           649:        int drive_number;
        !           650:        int clock_time; /* ns */
        !           651:        int mc_time, av_time, ds_time;
        !           652: 
        !           653:        interface_number = HWIF(drive)->index;
        !           654:        drive_number = drive->select.b.unit;
        !           655:        clock_time = 1000/bus_speed;
        !           656: 
        !           657:        mc_time = pio_timings[pio_mode].mc_time;
        !           658:        av_time = pio_timings[pio_mode].av_time;
        !           659:        ds_time = pio_timings[pio_mode].ds_time;
        !           660: 
        !           661:        cmd640_timings_to_clocks(mc_time, av_time, ds_time, clock_time,
        !           662:                                interface_number*2 + drive_number);
        !           663:        set_pio_mode(interface_number, drive_number, pio_mode);
        !           664:        cmd640_set_timing(interface_number, drive_number);
        !           665: }
        !           666: 
        !           667: /*
        !           668:  * Drive PIO mode "autoconfiguration".
        !           669:  * Ideally, this code should *always* call cmd640_set_mode(), but it doesn't.
        !           670:  */
        !           671: 
        !           672: static void cmd640_tune_drive(ide_drive_t *drive, byte pio_mode) {
        !           673:        int interface_number;
        !           674:        int drive_number;
        !           675:        int clock_time; /* ns */
        !           676:        int max_pio;
        !           677:        int mc_time, av_time, ds_time;
        !           678:        struct hd_driveid* id;
        !           679:        int readahead;  /* there is a global named read_ahead */
        !           680: 
        !           681:        if (pio_mode != 255) {
        !           682:                cmd640_set_mode(drive, pio_mode);
        !           683:                return;
        !           684:        }
        !           685: 
        !           686:        interface_number = HWIF(drive)->index;
        !           687:        drive_number = drive->select.b.unit;
        !           688:        clock_time = 1000/bus_speed;
        !           689:        id = drive->id;
        !           690:        if ((max_pio = ide_scan_pio_blacklist(id->model)) != -1) {
        !           691:                ds_time = pio_timings[max_pio].ds_time;
        !           692:        } else {
        !           693:                max_pio = id->tPIO;
        !           694:                ds_time = pio_timings[max_pio].ds_time;
        !           695:                if (id->field_valid & 2) {
        !           696:                        if ((id->capability & 8) && (id->eide_pio_modes & 7)) {
        !           697:                                if (id->eide_pio_modes & 4) max_pio = 5;
        !           698:                                else if (id->eide_pio_modes & 2) max_pio = 4;
        !           699:                                else max_pio = 3;
        !           700:                                ds_time = id->eide_pio_iordy;
        !           701:                        } else {
        !           702:                                ds_time = id->eide_pio;
        !           703:                        }
        !           704:                        if (ds_time == 0)
        !           705:                                ds_time = pio_timings[max_pio].ds_time;
        !           706:                }
        !           707: 
        !           708:                /*
        !           709:                 * Conservative "downgrade"
        !           710:                 */
        !           711:                if (max_pio < 4 && max_pio != 0) {
        !           712:                        max_pio -= 1;
        !           713:                        ds_time = pio_timings[max_pio].ds_time;         
        !           714:                }
        !           715:        }
        !           716:        mc_time = pio_timings[max_pio].mc_time;
        !           717:        av_time = pio_timings[max_pio].av_time;
        !           718:        cmd640_timings_to_clocks(mc_time, av_time, ds_time, clock_time,
        !           719:                                interface_number*2 + drive_number);
        !           720:        set_pio_mode(interface_number, drive_number, max_pio);
        !           721:        cmd640_set_timing(interface_number, drive_number);
        !           722: 
        !           723:        /*
        !           724:         * Disable (or set) readahead mode
        !           725:         */
        !           726: 
        !           727:        readahead = 0;
        !           728:        if (cmd640_chip_version > 1) {  /* Mmmm.. probably should be > 2 ?? */
        !           729:                readahead = known_drive_readahead(id->model);
        !           730:                if (readahead == -1)
        !           731:                        readahead = 1;  /* Mmmm.. probably be 0 ?? */
        !           732:                set_readahead_mode(readahead, interface_number, drive_number);
        !           733:        }   
        !           734: 
        !           735:        printk ("Mode and Timing set to PIO%d, Readahead is %s\n", 
        !           736:                max_pio, readahead ? "enabled" : "disabled");
        !           737: }
        !           738: 

unix.superglobalmegacorp.com

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