diff -urN linux/Documentation/Configure.help bk/Documentation/Configure.help --- linux/Documentation/Configure.help Wed Aug 30 08:13:28 2000 +++ bk/Documentation/Configure.help Tue Aug 29 16:47:15 2000 @@ -1088,22 +1088,25 @@ Support for PowerMac IDE devices (must also enable IDE) CONFIG_BLK_DEV_IDE_PMAC - No help for CONFIG_BLK_DEV_IDE_PMAC + This driver provides support for the built-in IDE controller on most + of the recent Apple Power Macintoshes and PowerBooks. + If unsure, say Y. PowerMac IDE DMA support CONFIG_BLK_DEV_IDEDMA_PMAC - No help for CONFIG_BLK_DEV_IDEDMA_PMAC + This option allows the driver for the built-in IDE controller on + Power Macintoshes and PowerBooks to use DMA (direct memory access) + to transfer data to and from memory. Saying Y is safe and improves + performance. Use DMA by default -CONFIG_IDEDMA_PMAC_AUTO - Prior to kernel version 2.1.112, Linux used to automatically use - DMA for IDE drives and chipsets which support it. Due to concerns - about a couple of cases where buggy hardware may have caused damage, - the default is now to NOT use DMA automatically. To revert to the - previous behaviour, say Y to this question. - - If you suspect your hardware is at all flakey, say N here. - Do NOT email the IDE kernel people regarding this issue! +CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO + This option allows the driver for the built-in IDE controller on + Power Macintoshes and PowerBooks to use DMA automatically, without + it having to be explicitly enabled. This option is provided because + of concerns about a couple of cases where using DMA on buggy PC + hardware may have caused damage. Saying Y should be safe on all + Apple machines. Macintosh Quadra/Powerbook IDE interface support CONFIG_BLK_DEV_MAC_IDE diff -urN linux/drivers/ide/Config.in bk/drivers/ide/Config.in --- linux/drivers/ide/Config.in Tue Jun 27 14:52:30 2000 +++ bk/drivers/ide/Config.in Sat Jul 29 17:59:38 2000 @@ -80,7 +80,7 @@ if [ "$CONFIG_PMAC" = "y" -o "$CONFIG_ALL_PPC" = "y" ]; then bool ' Builtin PowerMac IDE support' CONFIG_BLK_DEV_IDE_PMAC dep_bool ' PowerMac IDE DMA support' CONFIG_BLK_DEV_IDEDMA_PMAC $CONFIG_BLK_DEV_IDE_PMAC - dep_bool ' Use DMA by default' CONFIG_IDEDMA_PMAC_AUTO $CONFIG_BLK_DEV_IDEDMA_PMAC + dep_bool ' Use DMA by default' CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO $CONFIG_BLK_DEV_IDEDMA_PMAC define_bool CONFIG_BLK_DEV_IDEDMA $CONFIG_BLK_DEV_IDEDMA_PMAC define_bool CONFIG_BLK_DEV_IDEPCI $CONFIG_BLK_DEV_IDEDMA_PMAC fi @@ -125,7 +125,7 @@ fi if [ "$CONFIG_IDEDMA_PCI_AUTO" = "y" -o \ - "$CONFIG_IDEDMA_PMAC_AUTO" = "y" -o \ + "$CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO" = "y" -o \ "$CONFIG_IDEDMA_ICS_AUTO" = "y" ]; then define_bool CONFIG_IDEDMA_AUTO y else diff -urN linux/drivers/ide/ide-pmac.c bk/drivers/ide/ide-pmac.c --- linux/drivers/ide/ide-pmac.c Tue Jun 27 14:52:30 2000 +++ bk/drivers/ide/ide-pmac.c Thu Aug 31 08:50:02 2000 @@ -43,6 +43,9 @@ extern char *ide_dmafunc_verbose(ide_dma_action_t dmafunc); #undef IDE_PMAC_DEBUG +/* define this one when it's bug free */ +#undef USE_IDE_CONFIG_DRIVE_SPEED + #define IDE_SYSCLK_NS 30 #define IDE_SYSCLK_ULTRA_PS 0x1d4c /* (15 * 1000 / 2)*/ @@ -175,12 +178,12 @@ ide_hwifs[ix].tuneproc = pmac_ide_tuneproc; ide_hwifs[ix].selectproc = pmac_ide_selectproc; + ide_hwifs[ix].speedproc = &pmac_ide_tune_chipset; if (pmac_ide[ix].dma_regs && pmac_ide[ix].dma_table) { ide_hwifs[ix].dmaproc = &pmac_ide_dmaproc; -#ifdef CONFIG_PMAC_IDEDMA_AUTO +#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO ide_hwifs[ix].autodma = 1; #endif -// ide_hwifs[ix].speedproc = &pmac_ide_tune_chipset; } } @@ -219,6 +222,67 @@ #define SYSCLK_TICKS(t) (((t) + IDE_SYSCLK_NS - 1) / IDE_SYSCLK_NS) #define SYSCLK_TICKS_UDMA(t) (((t) + IDE_SYSCLK_ULTRA_PS - 1) / IDE_SYSCLK_ULTRA_PS) +#ifndef USE_IDE_CONFIG_DRIVE_SPEED +static __inline__ int +wait_for_ready(ide_drive_t *drive) +{ + /* Timeout bumped for some powerbooks */ + int timeout = 2000; + byte stat; + + while(--timeout) { + stat = GET_STAT(); + if(!(stat & BUSY_STAT)) { + if (drive->ready_stat == 0) + break; + else if((stat & drive->ready_stat) || (stat & ERR_STAT)) + break; + } + mdelay(1); + } + if((stat & ERR_STAT) || timeout <= 0) { + if (stat & ERR_STAT) { + printk("ide_pmace: wait_for_ready, error status: %x\n", stat); + } + return 1; + } + return 0; +} + +static int +pmac_ide_do_setfeature(ide_drive_t *drive, byte command) +{ + unsigned long flags; + int result = 1; + + save_flags(flags); + cli(); + udelay(1); + SELECT_DRIVE(HWIF(drive), drive); + SELECT_MASK(HWIF(drive), drive, 0); + udelay(1); + if(wait_for_ready(drive)) { + printk("pmac_ide_do_setfeature disk not ready before SET_FEATURE!\n"); + goto out; + } +#if 0 /* This one has a problem, the bus occasionally hangs */ + if (IDE_CONTROL_REG) + OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG); +#endif + OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG); + OUT_BYTE(command, IDE_NSECTOR_REG); + OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG); + udelay(1); + result = wait_for_ready(drive); + if (result) + printk("pmac_ide_do_setfeature disk not ready after SET_FEATURE !\n"); +out: + restore_flags(flags); + + return result; +} +#endif /* USE_IDE_CONFIG_DRIVE_SPEED */ + /* Calculate PIO timings */ static void pmac_ide_tuneproc(ide_drive_t *drive, byte pio) @@ -266,6 +330,136 @@ pmac_ide_selectproc(drive); } +#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC +static int +set_timings_udma(int intf, u32 *timings, byte speed) +{ + int cycleTime, accessTime; + int rdyToPauseTicks, cycleTicks; + + if (pmac_ide[intf].kind != controller_kl_ata4) + return 1; + + cycleTime = udma_timings[speed & 0xf].cycleTime; + accessTime = udma_timings[speed & 0xf].accessTime; + + rdyToPauseTicks = SYSCLK_TICKS_UDMA(accessTime * 1000); + cycleTicks = SYSCLK_TICKS_UDMA(cycleTime * 1000); + + *timings = ((*timings) & 0xe00fffff) | + ((cycleTicks << 1) | (rdyToPauseTicks << 5) | 1) << 20; + + return 0; +} + +static int +set_timings_mdma(int intf, u32 *timings, byte speed) +{ + int cycleTime, accessTime; + int accessTicks, recTicks; + + /* Calculate accesstime and cycle time */ + cycleTime = mdma_timings[speed & 0xf].cycleTime; + accessTime = mdma_timings[speed & 0xf].accessTime; + if ((pmac_ide[intf].kind == controller_ohare) && (cycleTime < 150)) + cycleTime = 150; + + /* For ata-4 controller */ + if (pmac_ide[intf].kind == controller_kl_ata4) { + accessTicks = SYSCLK_TICKS_UDMA(accessTime * 1000); + recTicks = SYSCLK_TICKS_UDMA(cycleTime * 1000) - accessTicks; + *timings = ((*timings) & 0xffe003ff) | + (accessTicks | (recTicks << 5)) << 10; + } else { + int halfTick = 0; + int origAccessTime = accessTime; + int origCycleTime = cycleTime; + + accessTicks = SYSCLK_TICKS(accessTime); + if (accessTicks < 1) + accessTicks = 1; + accessTime = accessTicks * IDE_SYSCLK_NS; + recTicks = SYSCLK_TICKS(cycleTime - accessTime) - 1; + if (recTicks < 1) + recTicks = 1; + cycleTime = (recTicks + 1 + accessTicks) * IDE_SYSCLK_NS; + + /* KeyLargo ata-3 don't support the half-tick stuff */ + if ((pmac_ide[intf].kind != controller_kl_ata3) && + (accessTicks > 1) && + ((accessTime - IDE_SYSCLK_NS/2) >= origAccessTime) && + ((cycleTime - IDE_SYSCLK_NS) >= origCycleTime)) { + halfTick = 1; + accessTicks--; + } + *timings = ((*timings) & 0x7FF) | + (accessTicks | (recTicks << 5) | (halfTick << 10)) << 11; + } + return 0; +} +#endif /* #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC */ + +/* You may notice we don't use this function on normal operation, + * our, normal mdma function is supposed to be more precise + */ +static int +pmac_ide_tune_chipset (ide_drive_t *drive, byte speed) +{ + int intf = pmac_ide_find(drive); + int unit = (drive->select.all & 0x10) ? 1:0; + int ret = 0; + u32 *timings; + + if (intf < 0) + return 1; + + timings = &pmac_ide[intf].timings[unit]; + + switch(speed) { +#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC + case XFER_UDMA_4: + case XFER_UDMA_3: + case XFER_UDMA_2: + case XFER_UDMA_1: + case XFER_UDMA_0: + ret = set_timings_udma(intf, timings, speed); + break; + case XFER_MW_DMA_2: + case XFER_MW_DMA_1: + case XFER_MW_DMA_0: + case XFER_SW_DMA_2: + case XFER_SW_DMA_1: + case XFER_SW_DMA_0: + ret = set_timings_mdma(intf, timings, speed); + break; +#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ + case XFER_PIO_4: + case XFER_PIO_3: + case XFER_PIO_2: + case XFER_PIO_1: + case XFER_PIO_0: + pmac_ide_tuneproc(drive, speed & 0x07); + break; + default: + ret = 1; + } + if (ret) + return ret; + +#ifdef USE_IDE_CONFIG_DRIVE_SPEED + ret = ide_config_drive_speed(drive, speed); +#else + ret = pmac_ide_do_setfeature(drive, speed); +#endif + if (ret) + return ret; + + pmac_ide_selectproc(drive); + drive->current_speed = speed; + + return 0; +} + ide_ioreg_t pmac_ide_get_base(int index) { @@ -337,7 +531,8 @@ for (i = 0, np = atas; i < MAX_HWIFS && np != NULL; np = np->next) { struct device_node *tp; int *bidp; - + int in_bay = 0; + /* * If this node is not under a mac-io or dbdma node, * leave it to the generic PCI driver. @@ -395,7 +590,10 @@ if (np->parent && np->parent->name && strcasecmp(np->parent->name, "media-bay") == 0) { +#ifdef CONFIG_PMAC_PBOOK media_bay_set_ide_infos(np->parent,base,irq,i); +#endif /* CONFIG_PMAC_PBOOK */ + in_bay = 1; } else if (pmac_ide[i].kind == controller_ohare) { /* The code below is having trouble on some ohare machines * (timing related ?). Until I can put my hand on one of these @@ -436,8 +634,11 @@ pmac_ide_init_hwif_ports(&hwif->hw, base, 0, &hwif->irq); memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports)); hwif->chipset = ide_pmac; - hwif->noprobe = (!hwif->io_ports[IDE_DATA_OFFSET]) || - (check_media_bay_by_base(base, MB_CD) == -EINVAL); + hwif->noprobe = !hwif->io_ports[IDE_DATA_OFFSET] || in_bay; +#ifdef CONFIG_PMAC_PBOOK + if (in_bay && check_media_bay_by_base(base, MB_CD) == 0) + hwif->noprobe = 0; +#endif /* CONFIG_PMAC_PBOOK */ #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC if (np->n_addrs >= 2) { @@ -479,7 +680,7 @@ } ide_hwifs[ix].dmaproc = &pmac_ide_dmaproc; -#ifdef CONFIG_PMAC_IDEDMA_AUTO +#ifdef CONFIG_BLK_DEV_IDEDMA_PMAC_AUTO ide_hwifs[ix].autodma = 1; #endif } @@ -565,99 +766,34 @@ } -/* This is fun. -DaveM */ -#define IDE_SETXFER 0x03 -#define IDE_SETFEATURE 0xef -#define IDE_DMA2_ENABLE 0x22 -#define IDE_DMA1_ENABLE 0x21 -#define IDE_DMA0_ENABLE 0x20 -#define IDE_UDMA4_ENABLE 0x44 -#define IDE_UDMA3_ENABLE 0x43 -#define IDE_UDMA2_ENABLE 0x42 -#define IDE_UDMA1_ENABLE 0x41 -#define IDE_UDMA0_ENABLE 0x40 - static __inline__ unsigned char dma_bits_to_command(unsigned char bits) { if(bits & 0x04) - return IDE_DMA2_ENABLE; + return XFER_MW_DMA_2; if(bits & 0x02) - return IDE_DMA1_ENABLE; - return IDE_DMA0_ENABLE; + return XFER_MW_DMA_1; + if(bits & 0x01) + return XFER_MW_DMA_0; + return 0; } static __inline__ unsigned char udma_bits_to_command(unsigned char bits) { if(bits & 0x10) - return IDE_UDMA4_ENABLE; + return XFER_UDMA_4; if(bits & 0x08) - return IDE_UDMA3_ENABLE; + return XFER_UDMA_3; if(bits & 0x04) - return IDE_UDMA2_ENABLE; + return XFER_UDMA_2; if(bits & 0x02) - return IDE_UDMA1_ENABLE; + return XFER_UDMA_1; if(bits & 0x01) - return IDE_UDMA0_ENABLE; + return XFER_UDMA_0; return 0; } -static __inline__ int -wait_for_ready(ide_drive_t *drive) -{ - /* Timeout bumped for some powerbooks */ - int timeout = 2000; - byte stat; - - while(--timeout) { - stat = GET_STAT(); - if(!(stat & BUSY_STAT)) { - if (drive->ready_stat == 0) - break; - else if((stat & drive->ready_stat) || (stat & ERR_STAT)) - break; - } - mdelay(1); - } - if((stat & ERR_STAT) || timeout <= 0) { - if (stat & ERR_STAT) { - printk("ide_pmace: wait_for_ready, error status: %x\n", stat); - } - return 1; - } - return 0; -} - -static int -pmac_ide_do_setfeature(ide_drive_t *drive, byte command) -{ - unsigned long flags; - byte old_select; - int result = 1; - - save_flags(flags); - cli(); - old_select = IN_BYTE(IDE_SELECT_REG); - OUT_BYTE(drive->select.all, IDE_SELECT_REG); - udelay(10); - OUT_BYTE(IDE_SETXFER, IDE_FEATURE_REG); - OUT_BYTE(command, IDE_NSECTOR_REG); - if(wait_for_ready(drive)) { - printk("pmac_ide_do_setfeature disk not ready before SET_FEATURE!\n"); - goto out; - } - OUT_BYTE(IDE_SETFEATURE, IDE_COMMAND_REG); - result = wait_for_ready(drive); - if (result) - printk("pmac_ide_do_setfeature disk not ready after SET_FEATURE !\n"); -out: - OUT_BYTE(old_select, IDE_SELECT_REG); - restore_flags(flags); - - return result; -} - /* Calculate MultiWord DMA timings */ static int pmac_ide_mdma_enable(ide_drive_t *drive, int idx) @@ -668,10 +804,16 @@ int cycleTime, accessTime; int accessTicks, recTicks; struct hd_driveid *id = drive->id; + int ret; /* Set feature on drive */ printk("%s: Enabling MultiWord DMA %d\n", drive->name, feature & 0xf); - if (pmac_ide_do_setfeature(drive, feature)) { +#ifdef USE_IDE_CONFIG_DRIVE_SPEED + ret = ide_config_drive_speed(drive, feature); +#else + ret = pmac_ide_do_setfeature(drive, feature); +#endif + if (ret) { printk("%s: Failed !\n", drive->name); return 0; } @@ -693,7 +835,7 @@ if ((pmac_ide[idx].kind == controller_ohare) && (cycleTime < 150)) cycleTime = 150; - /* For ata-4 controller, we don't know the calculation */ + /* For ata-4 controller */ if (pmac_ide[idx].kind == controller_kl_ata4) { accessTicks = SYSCLK_TICKS_UDMA(accessTime * 1000); recTicks = SYSCLK_TICKS_UDMA(cycleTime * 1000) - accessTicks; @@ -741,10 +883,16 @@ int cycleTime, accessTime; int rdyToPauseTicks, cycleTicks; u32 *timings; - + int ret; + /* Set feature on drive */ printk("%s: Enabling Ultra DMA %d\n", drive->name, feature & 0xf); - if (pmac_ide_do_setfeature(drive, feature)) { +#ifdef USE_IDE_CONFIG_DRIVE_SPEED + ret = ide_config_drive_speed(drive, feature); +#else + ret = pmac_ide_do_setfeature(drive, feature); +#endif + if (ret) { printk("%s: Failed !\n", drive->name); return 0; } @@ -772,11 +920,12 @@ } static int -pmac_ide_dma_onoff(ide_drive_t *drive, int enable) +pmac_ide_check_dma(ide_drive_t *drive) { int ata4, udma, idx; struct hd_driveid *id = drive->id; - + int enable = 1; + drive->using_dma = 0; idx = pmac_ide_find(drive); @@ -807,15 +956,14 @@ * machines */ OUT_BYTE(0, IDE_CONTROL_REG); - if (drive->select.all == IN_BYTE(IDE_SELECT_REG)) - pmac_ide_selectproc(drive); + /* Apply settings to controller */ + pmac_ide_selectproc(drive); } return 0; } int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); int ix, dstat; volatile struct dbdma_regs *dma; @@ -828,15 +976,14 @@ dma = pmac_ide[ix].dma_regs; switch (func) { - case ide_dma_on: case ide_dma_off: + printk("%s: DMA disabled\n", drive->name); case ide_dma_off_quietly: - pmac_ide_dma_onoff(drive, (func == ide_dma_on)); + drive->using_dma = 0; break; + case ide_dma_on: case ide_dma_check: - printk("IDE-DMA check !\n"); - if (hwif->autodma) - pmac_ide_dma_onoff(drive, 1); + pmac_ide_check_dma(drive); break; case ide_dma_read: case ide_dma_write: @@ -1026,7 +1173,7 @@ #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC if (hwif->drives[0].present && hwif->drives[0].using_dma) - pmac_ide_dma_onoff(&hwif->drives[0], 1); + pmac_ide_check_dma(&hwif->drives[0]); #endif } break;