|
|
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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.