root/drivers/block/cmd640.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. put_cmd640_reg_pci1
  2. get_cmd640_reg_pci1
  3. put_cmd640_reg_pci2
  4. get_cmd640_reg_pci2
  5. put_cmd640_reg_vlb
  6. get_cmd640_reg_vlb
  7. probe_for_cmd640_pci1
  8. probe_for_cmd640_pci2
  9. probe_for_cmd640_vlb
  10. cmd640_reset_controller
  11. secondary_port_responding
  12. ide_probe_for_cmd640x
  13. cmd640_off
  14. set_readahead_mode
  15. strmatch
  16. known_drive_readahead
  17. pack_arttim
  18. pack_counts
  19. max
  20. max4
  21. cmd640_set_timing
  22. cmd640_timings_to_clocks
  23. set_pio_mode
  24. cmd640_set_mode
  25. cmd640_tune_drive

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

/* [previous][next][first][last][top][bottom][index][help] */