--- zzzz-none-000/linux-2.4.17/drivers/ide/ide-pmac.c 2001-10-02 16:08:40.000000000 +0000 +++ sangam-fb-322/linux-2.4.17/drivers/ide/ide-pmac.c 2004-11-24 13:23:46.000000000 +0000 @@ -1,5 +1,5 @@ /* - * linux/drivers/ide/ide-pmac.c Version ?.?? Mar. 18, 2000 + * linux/drivers/ide/ide-pmac.c * * Support for IDE interfaces on PowerMacs. * These IDE interfaces are memory-mapped and have a DBDMA channel @@ -24,13 +24,16 @@ #include #include #include - +#include +#include #include #include #include #include #include -#include +#include +#include +#include #ifdef CONFIG_PMAC_PBOOK #include #include @@ -39,11 +42,11 @@ #include "ide_modes.h" extern char *ide_dmafunc_verbose(ide_dma_action_t dmafunc); +extern void ide_do_request(ide_hwgroup_t *hwgroup, int masked_irq); -#undef IDE_PMAC_DEBUG +#define IDE_PMAC_DEBUG -#define IDE_SYSCLK_NS 30 -#define IDE_SYSCLK_ULTRA_PS 0x1d4c /* (15 * 1000 / 2)*/ +#define DMA_WAIT_TIMEOUT 500 struct pmac_ide_hwif { ide_ioreg_t regbase; @@ -52,12 +55,14 @@ int aapl_bus_id; struct device_node* node; u32 timings[2]; + struct resource* reg_resource; #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC volatile struct dbdma_regs* dma_regs; struct dbdma_cmd* dma_table; + struct resource* dma_resource; #endif -} pmac_ide[MAX_HWIFS]; +} pmac_ide[MAX_HWIFS] __pmacdata; static int pmac_ide_count; @@ -65,33 +70,145 @@ controller_ohare, /* OHare based */ controller_heathrow, /* Heathrow/Paddington */ controller_kl_ata3, /* KeyLargo ATA-3 */ - controller_kl_ata4 /* KeyLargo ATA-4 */ + controller_kl_ata4, /* KeyLargo ATA-4 */ + controller_kl_ata4_80 /* KeyLargo ATA-4 with 80 conductor cable */ }; +/* + * Timing register definitions + */ + +/* Number of IDE_SYSCLK_NS ticks, argument is in nanoseconds */ +#define SYSCLK_TICKS(t) (((t) + IDE_SYSCLK_NS - 1) / IDE_SYSCLK_NS) +#define SYSCLK_TICKS_66(t) (((t) + IDE_SYSCLK_66_NS - 1) / IDE_SYSCLK_66_NS) +#define IDE_SYSCLK_NS 30 /* 33Mhz cell */ +#define IDE_SYSCLK_66_NS 15 /* 66Mhz cell */ + +/* 66Mhz cell, found in KeyLargo. Can do ultra mode 0 to 2 on + * 40 connector cable and to 4 on 80 connector one. + * Clock unit is 15ns (66Mhz) + * + * 3 Values can be programmed: + * - Write data setup, which appears to match the cycle time. They + * also call it DIOW setup. + * - Ready to pause time (from spec) + * - Address setup. That one is weird. I don't see where exactly + * it fits in UDMA cycles, I got it's name from an obscure piece + * of commented out code in Darwin. They leave it to 0, we do as + * well, despite a comment that would lead to think it has a + * min value of 45ns. + * Apple also add 60ns to the write data setup (or cycle time ?) on + * reads. I can't explain that, I tried it and it broke everything + * here. + */ +#define TR_66_UDMA_MASK 0xfff00000 +#define TR_66_UDMA_EN 0x00100000 /* Enable Ultra mode for DMA */ +#define TR_66_UDMA_ADDRSETUP_MASK 0xe0000000 /* Address setup */ +#define TR_66_UDMA_ADDRSETUP_SHIFT 29 +#define TR_66_UDMA_RDY2PAUS_MASK 0x1e000000 /* Ready 2 pause time */ +#define TR_66_UDMA_RDY2PAUS_SHIFT 25 +#define TR_66_UDMA_WRDATASETUP_MASK 0x01e00000 /* Write data setup time */ +#define TR_66_UDMA_WRDATASETUP_SHIFT 21 +#define TR_66_MDMA_MASK 0x000ffc00 +#define TR_66_MDMA_RECOVERY_MASK 0x000f8000 +#define TR_66_MDMA_RECOVERY_SHIFT 15 +#define TR_66_MDMA_ACCESS_MASK 0x00007c00 +#define TR_66_MDMA_ACCESS_SHIFT 10 +#define TR_66_PIO_MASK 0x000003ff +#define TR_66_PIO_RECOVERY_MASK 0x000003e0 +#define TR_66_PIO_RECOVERY_SHIFT 5 +#define TR_66_PIO_ACCESS_MASK 0x0000001f +#define TR_66_PIO_ACCESS_SHIFT 0 + +/* 33Mhz cell, found in OHare, Heathrow (& Paddington) and KeyLargo + * Can do pio & mdma modes, clock unit is 30ns (33Mhz) + * + * The access time and recovery time can be programmed. Some older + * Darwin code base limit OHare to 150ns cycle time. I decided to do + * the same here fore safety against broken old hardware ;) + * The HalfTick bit, when set, adds half a clock (15ns) to the access + * time and removes one from recovery. It's not supported on KeyLargo + * implementation afaik. The E bit appears to be set for PIO mode 0 and + * is used to reach long timings used in this mode. + */ +#define TR_33_MDMA_MASK 0x003ff800 +#define TR_33_MDMA_RECOVERY_MASK 0x001f0000 +#define TR_33_MDMA_RECOVERY_SHIFT 16 +#define TR_33_MDMA_ACCESS_MASK 0x0000f800 +#define TR_33_MDMA_ACCESS_SHIFT 11 +#define TR_33_MDMA_HALFTICK 0x00200000 +#define TR_33_PIO_MASK 0x000007ff +#define TR_33_PIO_E 0x00000400 +#define TR_33_PIO_RECOVERY_MASK 0x000003e0 +#define TR_33_PIO_RECOVERY_SHIFT 5 +#define TR_33_PIO_ACCESS_MASK 0x0000001f +#define TR_33_PIO_ACCESS_SHIFT 0 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC -typedef struct { +/* Rounded Multiword DMA timings + * + * I gave up finding a generic formula for all controller + * types and instead, built tables based on timing values + * used by Apple in Darwin's implementation. + */ +struct mdma_timings_t { int accessTime; + int recoveryTime; int cycleTime; -} pmac_ide_timing; +}; -/* Multiword DMA timings */ -static pmac_ide_timing mdma_timings[] = +struct mdma_timings_t mdma_timings_33[] __pmacdata = { - { 215, 480 }, /* Mode 0 */ - { 80, 150 }, /* 1 */ - { 70, 120 } /* 2 */ + { 240, 240, 480 }, + { 180, 180, 360 }, + { 135, 135, 270 }, + { 120, 120, 240 }, + { 105, 105, 210 }, + { 90, 90, 180 }, + { 75, 75, 150 }, + { 75, 45, 120 }, + { 0, 0, 0 } }; -/* Ultra DMA timings (for use when I know how to calculate them */ -static pmac_ide_timing udma_timings[] = +struct mdma_timings_t mdma_timings_33k[] __pmacdata = { - { 0, 114 }, /* Mode 0 */ - { 0, 75 }, /* 1 */ - { 0, 55 }, /* 2 */ - { 100, 45 }, /* 3 */ - { 100, 25 } /* 4 */ + { 240, 240, 480 }, + { 180, 180, 360 }, + { 150, 150, 300 }, + { 120, 120, 240 }, + { 90, 120, 210 }, + { 90, 90, 180 }, + { 90, 60, 150 }, + { 90, 30, 120 }, + { 0, 0, 0 } +}; + +struct mdma_timings_t mdma_timings_66[] __pmacdata = +{ + { 240, 240, 480 }, + { 180, 180, 360 }, + { 135, 135, 270 }, + { 120, 120, 240 }, + { 105, 105, 210 }, + { 90, 90, 180 }, + { 90, 75, 165 }, + { 75, 45, 120 }, + { 0, 0, 0 } +}; + +/* Ultra DMA timings (rounded) */ +struct { + int addrSetup; /* ??? */ + int rdy2pause; + int wrDataSetup; +} udma_timings[] __pmacdata = +{ + { 0, 180, 120 }, /* Mode 0 */ + { 0, 150, 90 }, /* 1 */ + { 0, 120, 60 }, /* 2 */ + { 0, 90, 45 }, /* 3 */ + { 0, 90, 30 } /* 4 */ }; /* allow up to 256 DBDMA commands per xfer */ @@ -121,7 +238,14 @@ }; #endif /* CONFIG_PMAC_PBOOK */ -static int +static int pmac_ide_notify_reboot(struct notifier_block *, unsigned long, void *); +static struct notifier_block pmac_ide_reboot_notifier = { + pmac_ide_notify_reboot, + NULL, + 0 +}; + +static int __pmac pmac_ide_find(ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); @@ -140,7 +264,8 @@ * N.B. this can't be an initfunc, because the media-bay task can * call ide_[un]register at any time. */ -void pmac_ide_init_hwif_ports(hw_regs_t *hw, +void __pmac +pmac_ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, ide_ioreg_t ctrl_port, int *irq) { @@ -198,24 +323,34 @@ /* Setup timings for the selected drive (master/slave). I still need to verify if this * is enough, I beleive selectproc will be called whenever an IDE command is started, * but... */ -static void +static void __pmac pmac_ide_selectproc(ide_drive_t *drive) { int i = pmac_ide_find(drive); if (i < 0) return; - - if (drive->select.all & 0x10) + + if (drive->select.b.unit & 0x01) out_le32((unsigned *)(IDE_DATA_REG + 0x200 + _IO_BASE), pmac_ide[i].timings[1]); else out_le32((unsigned *)(IDE_DATA_REG + 0x200 + _IO_BASE), pmac_ide[i].timings[0]); + (void)in_le32((unsigned *)(IDE_DATA_REG + 0x200 + _IO_BASE)); } -/* Number of IDE_SYSCLK_NS ticks, argument is in nanoseconds */ -#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) -static __inline__ int +/* Note: We don't use the generic routine here because for some + * yet unexplained reasons, it cause some media-bay CD-ROMs to + * lockup the bus. Strangely, this new version of the code is + * almost identical to the generic one and works, I've not yet + * managed to figure out what bit is causing the lockup in the + * generic code, possibly a timing issue... + * + * --BenH + */ +#undef USE_GENERIC_SETFEATURE + +#ifndef USE_GENERIC_SETFEATURE +static int __pmac wait_for_ready(ide_drive_t *drive) { /* Timeout bumped for some powerbooks */ @@ -240,23 +375,19 @@ } return 0; } +#endif /* USE_GENERIC_SETFEATURE */ -/* Note: We don't use the generic routine here because some of Apple's - * controller seem to be very sensitive about how things are done. - * We should probably set the NIEN bit, but that's an example of thing - * that can cause the controller to hang under some circumstances when - * done on the media-bay CD-ROM during boot. We do get occasional - * spurrious interrupts because of that. - * --BenH - */ -static int +static int __pmac pmac_ide_do_setfeature(ide_drive_t *drive, byte command) { - unsigned long flags; +#ifdef USE_GENERIC_SETFEATURE + return ide_config_drive_speed(drive, command); +#else int result = 1; - - save_flags(flags); - cli(); + unsigned long flags; + ide_hwif_t *hwif = HWIF(drive); + + disable_irq(hwif->irq); /* disable_irq_nosync ?? */ udelay(1); SELECT_DRIVE(HWIF(drive), drive); SELECT_MASK(HWIF(drive), drive, 0); @@ -265,27 +396,35 @@ printk(KERN_ERR "pmac_ide_do_setfeature disk not ready before SET_FEATURE!\n"); goto out; } - OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG); + udelay(10); + OUT_BYTE(drive->ctl | 2, IDE_CONTROL_REG); OUT_BYTE(command, IDE_NSECTOR_REG); + OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG); OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG); udelay(1); + __save_flags(flags); /* local CPU only */ + ide__sti(); /* local CPU only -- for jiffies */ result = wait_for_ready(drive); + __restore_flags(flags); /* local CPU only */ + OUT_BYTE(drive->ctl, IDE_CONTROL_REG); if (result) printk(KERN_ERR "pmac_ide_do_setfeature disk not ready after SET_FEATURE !\n"); out: - restore_flags(flags); - + SELECT_MASK(HWIF(drive), drive, 0); + enable_irq(hwif->irq); return result; +#endif } /* Calculate PIO timings */ -static void +static void __pmac pmac_ide_tuneproc(ide_drive_t *drive, byte pio) { ide_pio_data_t d; int i; u32 *timings; - int accessTicks, recTicks; + unsigned accessTicks, recTicks; + unsigned accessTime, recTime; i = pmac_ide_find(drive); if (i < 0) @@ -293,27 +432,44 @@ pio = ide_get_best_pio_mode(drive, pio, 4, &d); accessTicks = SYSCLK_TICKS(ide_pio_timings[pio].active_time); - if (drive->select.all & 0x10) + if (drive->select.b.unit & 0x01) timings = &pmac_ide[i].timings[1]; else timings = &pmac_ide[i].timings[0]; - - if (pmac_ide[i].kind == controller_kl_ata4) { - /* The "ata-4" IDE controller of Core99 machines */ - accessTicks = SYSCLK_TICKS_UDMA(ide_pio_timings[pio].active_time * 1000); - recTicks = SYSCLK_TICKS_UDMA(d.cycle_time * 1000) - accessTicks; - *timings = ((*timings) & 0x1FFFFFC00) | accessTicks | (recTicks << 5); + recTime = d.cycle_time - ide_pio_timings[pio].active_time + - ide_pio_timings[pio].setup_time; + recTime = max(recTime, 150U); + accessTime = ide_pio_timings[pio].active_time; + accessTime = max(accessTime, 150U); + if (pmac_ide[i].kind == controller_kl_ata4 || + pmac_ide[i].kind == controller_kl_ata4_80) { + /* 66Mhz cell */ + accessTicks = SYSCLK_TICKS_66(accessTime); + accessTicks = min(accessTicks, 0x1fU); + recTicks = SYSCLK_TICKS_66(recTime); + recTicks = min(recTicks, 0x1fU); + *timings = ((*timings) & ~TR_66_PIO_MASK) | + (accessTicks << TR_66_PIO_ACCESS_SHIFT) | + (recTicks << TR_66_PIO_RECOVERY_SHIFT); } else { - /* The old "ata-3" IDE controller */ - accessTicks = SYSCLK_TICKS(ide_pio_timings[pio].active_time); - if (accessTicks < 4) - accessTicks = 4; - recTicks = SYSCLK_TICKS(d.cycle_time) - accessTicks - 4; - if (recTicks < 1) - recTicks = 1; - - *timings = ((*timings) & 0xFFFFFF800) | accessTicks | (recTicks << 5); + /* 33Mhz cell */ + int ebit = 0; + accessTicks = SYSCLK_TICKS(accessTime); + accessTicks = min(accessTicks, 0x1fU); + accessTicks = max(accessTicks, 4U); + recTicks = SYSCLK_TICKS(recTime); + recTicks = min(recTicks, 0x1fU); + recTicks = max(recTicks, 5U) - 4; + if (recTicks > 9) { + recTicks--; /* guess, but it's only for PIO0, so... */ + ebit = 1; + } + *timings = ((*timings) & ~TR_33_PIO_MASK) | + (accessTicks << TR_33_PIO_ACCESS_SHIFT) | + (recTicks << TR_33_PIO_RECOVERY_SHIFT); + if (ebit) + *timings |= TR_33_PIO_E; } #ifdef IDE_PMAC_DEBUG @@ -326,70 +482,134 @@ } #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC -static int -set_timings_udma(int intf, u32 *timings, byte speed) +static int __pmac +set_timings_udma(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); + unsigned rdyToPauseTicks, wrDataSetupTicks, addrTicks; - *timings = ((*timings) & 0xe00fffff) | - ((cycleTicks << 1) | (rdyToPauseTicks << 5) | 1) << 20; + rdyToPauseTicks = SYSCLK_TICKS_66(udma_timings[speed & 0xf].rdy2pause); + wrDataSetupTicks = SYSCLK_TICKS_66(udma_timings[speed & 0xf].wrDataSetup); + addrTicks = SYSCLK_TICKS_66(udma_timings[speed & 0xf].addrSetup); + + *timings = ((*timings) & ~(TR_66_UDMA_MASK | TR_66_MDMA_MASK)) | + (wrDataSetupTicks << TR_66_UDMA_WRDATASETUP_SHIFT) | + (rdyToPauseTicks << TR_66_UDMA_RDY2PAUS_SHIFT) | + (addrTicks < cycleTime) + cycleTime = drive_cycle_time; + /* OHare limits according to some old Apple sources */ + if ((intf_type == controller_ohare) && (cycleTime < 150)) cycleTime = 150; + /* Get the proper timing array for this controller */ + switch(intf_type) { + case controller_kl_ata4: + case controller_kl_ata4_80: + tm = mdma_timings_66; + break; + case controller_kl_ata3: + tm = mdma_timings_33k; + break; + default: + tm = mdma_timings_33; + break; + } + /* Lookup matching access & recovery times */ + i = -1; + for (;;) { + if (tm[i+1].cycleTime < cycleTime) + break; + i++; + } + if (i < 0) + return -1; + cycleTime = tm[i].cycleTime; + accessTime = tm[i].accessTime; + recTime = tm[i].recoveryTime; - /* 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; +#ifdef IDE_PMAC_DEBUG + printk(KERN_ERR "ide_pmac: MDMA, cycleTime: %d, accessTime: %d, recTime: %d\n", + cycleTime, accessTime, recTime); +#endif + if (intf_type == controller_kl_ata4 || intf_type == controller_kl_ata4_80) { + /* 66Mhz cell */ + accessTicks = SYSCLK_TICKS_66(accessTime); + accessTicks = min(accessTicks, 0x1fU); + accessTicks = max(accessTicks, 0x1U); + recTicks = SYSCLK_TICKS_66(recTime); + recTicks = min(recTicks, 0x1fU); + recTicks = max(recTicks, 0x3U); + /* Clear out mdma bits and disable udma */ + *timings = ((*timings) & ~(TR_66_MDMA_MASK | TR_66_UDMA_MASK)) | + (accessTicks << TR_66_MDMA_ACCESS_SHIFT) | + (recTicks << TR_66_MDMA_RECOVERY_SHIFT); + } else if (intf_type == controller_kl_ata3) { + /* 33Mhz cell on KeyLargo */ + accessTicks = SYSCLK_TICKS(accessTime); + accessTicks = max(accessTicks, 1U); + accessTicks = min(accessTicks, 0x1fU); + accessTime = accessTicks * IDE_SYSCLK_NS; + recTicks = SYSCLK_TICKS(recTime); + recTicks = max(recTicks, 1U); + recTicks = min(recTicks, 0x1fU); + *timings = ((*timings) & ~TR_33_MDMA_MASK) | + (accessTicks << TR_33_MDMA_ACCESS_SHIFT) | + (recTicks << TR_33_MDMA_RECOVERY_SHIFT); } else { + /* 33Mhz cell on others */ int halfTick = 0; int origAccessTime = accessTime; - int origCycleTime = cycleTime; + int origRecTime = recTime; accessTicks = SYSCLK_TICKS(accessTime); - if (accessTicks < 1) - accessTicks = 1; + accessTicks = max(accessTicks, 1U); + accessTicks = min(accessTicks, 0x1fU); 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; + recTicks = SYSCLK_TICKS(recTime); + recTicks = max(recTicks, 2U) - 1; + recTicks = min(recTicks, 0x1fU); + recTime = (recTicks + 1) * IDE_SYSCLK_NS; + if ((accessTicks > 1) && + ((accessTime - IDE_SYSCLK_NS/2) >= origAccessTime) && + ((recTime - IDE_SYSCLK_NS/2) >= origRecTime)) { + halfTick = 1; + accessTicks--; + } + *timings = ((*timings) & ~TR_33_MDMA_MASK) | + (accessTicks << TR_33_MDMA_ACCESS_SHIFT) | + (recTicks << TR_33_MDMA_RECOVERY_SHIFT); + if (halfTick) + *timings |= TR_33_MDMA_HALFTICK; } +#ifdef IDE_PMAC_DEBUG + printk(KERN_ERR "ide_pmac: Set MDMA timing for mode %d, reg: 0x%08x\n", + speed & 0xf, *timings); +#endif return 0; } #endif /* #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC */ @@ -397,11 +617,11 @@ /* You may notice we don't use this function on normal operation, * our, normal mdma function is supposed to be more precise */ -static int +static int __pmac 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 unit = (drive->select.b.unit & 0x01); int ret = 0; u32 *timings; @@ -414,19 +634,25 @@ #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC case XFER_UDMA_4: case XFER_UDMA_3: + if (pmac_ide[intf].kind != controller_kl_ata4_80) + return 1; case XFER_UDMA_2: case XFER_UDMA_1: case XFER_UDMA_0: - ret = set_timings_udma(intf, timings, speed); + if (pmac_ide[intf].kind != controller_kl_ata4 && + pmac_ide[intf].kind != controller_kl_ata4_80) + return 1; + ret = set_timings_udma(timings, speed); break; case XFER_MW_DMA_2: case XFER_MW_DMA_1: case XFER_MW_DMA_0: + ret = set_timings_mdma(pmac_ide[intf].kind, timings, speed, 0); + break; case XFER_SW_DMA_2: case XFER_SW_DMA_1: case XFER_SW_DMA_0: - ret = set_timings_mdma(intf, timings, speed); - break; + return 1; #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ case XFER_PIO_4: case XFER_PIO_3: @@ -451,13 +677,46 @@ return 0; } -ide_ioreg_t +static void __pmac +sanitize_timings(int i) +{ + unsigned value; + + switch(pmac_ide[i].kind) { + case controller_kl_ata4: + case controller_kl_ata4_80: + value = 0x0008438c; + break; + case controller_kl_ata3: + value = 0x00084526; + break; + case controller_heathrow: + case controller_ohare: + default: + value = 0x00074526; + break; + } + pmac_ide[i].timings[0] = pmac_ide[i].timings[1] = value; +} + +ide_ioreg_t __pmac pmac_ide_get_base(int index) { return pmac_ide[index].regbase; } -int +int __pmac +pmac_ide_check_base(ide_ioreg_t base) +{ + int ix; + + for (ix = 0; ix < MAX_HWIFS; ++ix) + if (base == pmac_ide[ix].regbase) + return ix; + return -1; +} + +int __pmac pmac_ide_get_irq(ide_ioreg_t base) { int ix; @@ -468,7 +727,7 @@ return 0; } -static int ide_majors[] = { 3, 22, 33, 34, 56, 57 }; +static int ide_majors[] __pmacdata = { 3, 22, 33, 34, 56, 57 }; kdev_t __init pmac_find_ide_boot(char *bootdevice, int n) @@ -532,6 +791,7 @@ for (i = 0, np = atas; i < MAX_HWIFS && np != NULL; np = np->next) { struct device_node *tp; + struct pmac_ide_hwif* pmhw; int *bidp; int in_bay = 0; @@ -560,6 +820,22 @@ ++i; if (i >= MAX_HWIFS) break; + pmhw = &pmac_ide[i]; + + /* + * Some older OFs have bogus sizes, causing request_OF_resource + * to fail. We fix them up here + */ + if (np->addrs[0].size > 0x1000) + np->addrs[0].size = 0x1000; + if (np->n_addrs > 1 && np->addrs[1].size > 0x100) + np->addrs[1].size = 0x100; + + pmhw->reg_resource = request_OF_resource(np, 0, " (mac-io IDE IO)"); + if (!pmhw->reg_resource) { + printk(KERN_ERR "ide-pmac(%s): can't request IO resource !\n", np->name); + continue; + } base = (unsigned long) ioremap(np->addrs[0].address, 0x200) - _IO_BASE; @@ -574,21 +850,30 @@ } else { irq = np->intrs[0].line; } - pmac_ide[i].regbase = base; - pmac_ide[i].irq = irq; - pmac_ide[i].node = np; + pmhw->regbase = base; + pmhw->irq = irq; + pmhw->node = np; if (device_is_compatible(np, "keylargo-ata")) { if (strcmp(np->name, "ata-4") == 0) - pmac_ide[i].kind = controller_kl_ata4; + pmhw->kind = controller_kl_ata4; else - pmac_ide[i].kind = controller_kl_ata3; + pmhw->kind = controller_kl_ata3; } else if (device_is_compatible(np, "heathrow-ata")) - pmac_ide[i].kind = controller_heathrow; + pmhw->kind = controller_heathrow; else - pmac_ide[i].kind = controller_ohare; + pmhw->kind = controller_ohare; bidp = (int *)get_property(np, "AAPL,bus-id", NULL); - pmac_ide[i].aapl_bus_id = bidp ? *bidp : 0; + pmhw->aapl_bus_id = bidp ? *bidp : 0; + + if (pmhw->kind == controller_kl_ata4) { + char* cable = get_property(np, "cable-type", NULL); + if (cable && !strncmp(cable, "80-", 3)) + pmhw->kind = controller_kl_ata4_80; + } + + /* Make sure we have sane timings */ + sanitize_timings(i); if (np->parent && np->parent->name && strcasecmp(np->parent->name, "media-bay") == 0) { @@ -596,39 +881,22 @@ 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) { + if (!bidp) + pmhw->aapl_bus_id = 1; + } else if (pmhw->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 * units, I keep the old way */ - feature_set(np, FEATURE_IDE0_enable); + ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, 0, 1); } else { /* This is necessary to enable IDE when net-booting */ printk(KERN_INFO "pmac_ide: enabling IDE bus ID %d\n", - pmac_ide[i].aapl_bus_id); - switch(pmac_ide[i].aapl_bus_id) { - case 0: - feature_set(np, FEATURE_IDE0_reset); - mdelay(10); - feature_set(np, FEATURE_IDE0_enable); - mdelay(10); - feature_clear(np, FEATURE_IDE0_reset); - break; - case 1: - feature_set(np, FEATURE_IDE1_reset); - mdelay(10); - feature_set(np, FEATURE_IDE1_enable); - mdelay(10); - feature_clear(np, FEATURE_IDE1_reset); - break; - case 2: - /* This one exists only for KL, I don't know - about any enable bit */ - feature_set(np, FEATURE_IDE2_reset); - mdelay(10); - feature_clear(np, FEATURE_IDE2_reset); - break; - } + pmhw->aapl_bus_id); + ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmhw->aapl_bus_id, 1); + ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmhw->aapl_bus_id, 1); + mdelay(10); + ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmhw->aapl_bus_id, 0); big_delay = 1; } @@ -658,6 +926,7 @@ #ifdef CONFIG_PMAC_PBOOK pmu_register_sleep_notifier(&idepmac_sleep_notifier); #endif /* CONFIG_PMAC_PBOOK */ + register_reboot_notifier(&pmac_ide_reboot_notifier); } #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC @@ -665,6 +934,12 @@ static void __init pmac_ide_setup_dma(struct device_node *np, int ix) { + pmac_ide[ix].dma_resource = request_OF_resource(np, 1, " (mac-io IDE DMA)"); + if (!pmac_ide[ix].dma_resource) { + printk(KERN_ERR "ide-pmac(%s): can't request DMA resource !\n", np->name); + return; + } + pmac_ide[ix].dma_regs = (volatile struct dbdma_regs*)ioremap(np->addrs[1].address, 0x200); @@ -692,7 +967,7 @@ * pmac_ide_build_dmatable builds the DBDMA command list * for a transfer and sets the DBDMA channel to point to it. */ -static int +static int __pmac pmac_ide_build_dmatable(ide_drive_t *drive, int ix, int wr) { struct dbdma_cmd *table, *tstart; @@ -703,6 +978,13 @@ volatile struct dbdma_regs *dma = pmac_ide[ix].dma_regs; table = tstart = (struct dbdma_cmd *) DBDMA_ALIGN(pmac_ide[ix].dma_table); + +#ifdef IDE_PMAC_DEBUG + if (in_le32(&dma->status) & (RUN|ACTIVE)) + printk("ide-pmac: channel status not stopped ! (%x)\n", + in_le32(&dma->status)); +#endif + /* Make sure channel is stopped and all error conditions are clear */ out_le32(&dma->control, (RUN|PAUSE|FLUSH|WAKE|DEAD) << 16); while (in_le32(&dma->status) & RUN) udelay(1); @@ -734,6 +1016,10 @@ * Note that one DBDMA command can transfer * at most 65535 bytes. */ +#ifdef IDE_PMAC_DEBUG + if (size & 0x01) + printk("ide-pmac: odd size transfer ! (%d)\n", size); +#endif while (size) { unsigned int tc = (size < 0xfe00)? size: 0xfe00; @@ -782,12 +1068,14 @@ } static __inline__ unsigned char -udma_bits_to_command(unsigned char bits) +udma_bits_to_command(unsigned char bits, int high_speed) { - if(bits & 0x10) - return XFER_UDMA_4; - if(bits & 0x08) - return XFER_UDMA_3; + if (high_speed) { + if(bits & 0x10) + return XFER_UDMA_4; + if(bits & 0x08) + return XFER_UDMA_3; + } if(bits & 0x04) return XFER_UDMA_2; if(bits & 0x02) @@ -798,14 +1086,13 @@ } /* Calculate MultiWord DMA timings */ -static int +static int __pmac pmac_ide_mdma_enable(ide_drive_t *drive, int idx) { byte bits = drive->id->dma_mword & 0x07; byte feature = dma_bits_to_command(bits); u32 *timings; - int cycleTime, accessTime; - int accessTicks, recTicks; + int drive_cycle_time; struct hd_driveid *id = drive->id; int ret; @@ -821,66 +1108,30 @@ drive->init_speed = feature; /* which drive is it ? */ - if (drive->select.all & 0x10) + if (drive->select.b.unit & 0x01) timings = &pmac_ide[idx].timings[1]; else timings = &pmac_ide[idx].timings[0]; - /* Calculate accesstime and cycle time */ - cycleTime = mdma_timings[feature & 0xf].cycleTime; - accessTime = mdma_timings[feature & 0xf].accessTime; + /* Check if drive provide explicit cycle time */ if ((id->field_valid & 2) && (id->eide_dma_time)) - cycleTime = id->eide_dma_time; - if ((pmac_ide[idx].kind == controller_ohare) && (cycleTime < 150)) - cycleTime = 150; + drive_cycle_time = id->eide_dma_time; + else + drive_cycle_time = 0; + + /* Calculate controller timings */ + set_timings_mdma(pmac_ide[idx].kind, timings, feature, drive_cycle_time); - /* 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; - *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[idx].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; - } -#ifdef IDE_PMAC_DEBUG - printk(KERN_INFO "ide_pmac: Set MDMA timing for mode %d, reg: 0x%08x\n", - feature & 0xf, *timings); -#endif drive->current_speed = feature; return 1; } /* Calculate Ultra DMA timings */ -static int -pmac_ide_udma_enable(ide_drive_t *drive, int idx) +static int __pmac +pmac_ide_udma_enable(ide_drive_t *drive, int idx, int high_speed) { byte bits = drive->id->dma_ultra & 0x1f; - byte feature = udma_bits_to_command(bits); - int cycleTime, accessTime; - int rdyToPauseTicks, cycleTicks; + byte feature = udma_bits_to_command(bits, high_speed); u32 *timings; int ret; @@ -896,25 +1147,18 @@ drive->init_speed = feature; /* which drive is it ? */ - if (drive->select.all & 0x10) + if (drive->select.b.unit & 0x01) timings = &pmac_ide[idx].timings[1]; else timings = &pmac_ide[idx].timings[0]; - cycleTime = udma_timings[feature & 0xf].cycleTime; - accessTime = udma_timings[feature & 0xf].accessTime; - - rdyToPauseTicks = SYSCLK_TICKS_UDMA(accessTime * 1000); - cycleTicks = SYSCLK_TICKS_UDMA(cycleTime * 1000); - - *timings = ((*timings) & 0xe00fffff) | - ((cycleTicks << 1) | (rdyToPauseTicks << 5) | 1) << 20; + set_timings_udma(timings, feature); drive->current_speed = feature; return 1; } -static int +static int __pmac pmac_ide_check_dma(ide_drive_t *drive) { int ata4, udma, idx; @@ -935,21 +1179,20 @@ enable = 0; udma = 0; - ata4 = (pmac_ide[idx].kind == controller_kl_ata4); + ata4 = (pmac_ide[idx].kind == controller_kl_ata4 || + pmac_ide[idx].kind == controller_kl_ata4_80); if(enable) { if (ata4 && (drive->media == ide_disk) && - (id->field_valid & 0x0004) && (id->dma_ultra & 0x17)) { + (id->field_valid & 0x0004) && (id->dma_ultra & 0x1f)) { /* UltraDMA modes. */ - drive->using_dma = pmac_ide_udma_enable(drive, idx); + drive->using_dma = pmac_ide_udma_enable(drive, idx, + pmac_ide[idx].kind == controller_kl_ata4_80); } if (!drive->using_dma && (id->dma_mword & 0x0007)) { /* Normal MultiWord DMA modes. */ drive->using_dma = pmac_ide_mdma_enable(drive, idx); } - /* Without this, strange things will happen on Keylargo-based - * machines - */ OUT_BYTE(0, IDE_CONTROL_REG); /* Apply settings to controller */ pmac_ide_selectproc(drive); @@ -957,10 +1200,13 @@ return 0; } -int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive) +static int __pmac +pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive) { - int ix, dstat, i; + int ix, dstat; volatile struct dbdma_regs *dma; + byte unit = (drive->select.b.unit & 0x01); + byte ata4; /* Can we stuff a pointer to our intf structure in config_data * or select_data in hwif ? @@ -969,7 +1215,9 @@ if (ix < 0) return 0; dma = pmac_ide[ix].dma_regs; - + ata4 = (pmac_ide[ix].kind == controller_kl_ata4 || + pmac_ide[ix].kind == controller_kl_ata4_80); + switch (func) { case ide_dma_off: printk(KERN_INFO "%s: DMA disabled\n", drive->name); @@ -984,6 +1232,13 @@ case ide_dma_write: if (!pmac_ide_build_dmatable(drive, ix, func==ide_dma_write)) return 1; + /* Apple adds 60ns to wrDataSetup on reads */ + if (ata4 && (pmac_ide[ix].timings[unit] & TR_66_UDMA_EN)) { + out_le32((unsigned *)(IDE_DATA_REG + 0x200 + _IO_BASE), + pmac_ide[ix].timings[unit] + + ((func == ide_dma_read) ? 0x00800000UL : 0)); + (void)in_le32((unsigned *)(IDE_DATA_REG + 0x200 + _IO_BASE)); + } drive->waiting_for_dma = 1; if (drive->media != ide_disk) return 0; @@ -992,35 +1247,56 @@ IDE_COMMAND_REG); case ide_dma_begin: out_le32(&dma->control, (RUN << 16) | RUN); + /* Make sure it gets to the controller right now */ + (void)in_le32(&dma->control); break; - case ide_dma_end: + case ide_dma_end: /* returns 1 on error, 0 otherwise */ drive->waiting_for_dma = 0; dstat = in_le32(&dma->status); out_le32(&dma->control, ((RUN|WAKE|DEAD) << 16)); /* verify good dma status */ return (dstat & (RUN|DEAD|ACTIVE)) != RUN; - case ide_dma_test_irq: - if ((in_le32(&dma->status) & (RUN|ACTIVE)) == RUN) - return 1; - /* That's a bit ugly and dangerous, but works in our case - * to workaround a problem with the channel status staying - * active if the drive returns an error + case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */ + /* We have to things to deal with here: + * + * - The dbdma won't stop if the command was started + * but completed with an error without transfering all + * datas. This happens when bad blocks are met during + * a multi-block transfer. + * + * - The dbdma fifo hasn't yet finished flushing to + * to system memory when the disk interrupt occurs. + * + * The trick here is to increment drive->waiting_for_dma, + * and return as if no interrupt occured. If the counter + * reach a certain timeout value, we then return 1. If + * we really got the interrupt, it will happen right away + * again. + * Apple's solution here may be more elegant. They issue + * a DMA channel interrupt (a separate irq line) via a DBDMA + * NOP command just before the STOP, and wait for both the + * disk and DBDMA interrupts to have completed. */ - if (IDE_CONTROL_REG) { - byte stat; - stat = GET_ALTSTAT(); - if (stat & ERR_STAT) - return 1; - } - /* In some edge cases, some datas may still be in the dbdma - * engine fifo, we wait a bit for dbdma to complete + + /* If ACTIVE is cleared, the STOP command have passed and + * transfer is complete. */ - while ((in_le32(&dma->status) & (RUN|ACTIVE)) != RUN) { - if (++i > 100) - return 0; - udelay(1); + if (!(in_le32(&dma->status) & ACTIVE)) + return 1; + if (!drive->waiting_for_dma) + printk(KERN_WARNING "ide%d, ide_dma_test_irq \ + called while not waiting\n", ix); + + /* If dbdma didn't execute the STOP command yet, the + * active bit is still set */ + drive->waiting_for_dma++; + if (drive->waiting_for_dma >= DMA_WAIT_TIMEOUT) { + printk(KERN_WARNING "ide%d, timeout waiting \ + for dbdma command stop\n", ix); + return 1; } - return 1; + udelay(1); + return 0; /* Let's implement tose just in case someone wants them */ case ide_dma_bad_drive: @@ -1041,8 +1317,8 @@ } #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ -#ifdef CONFIG_PMAC_PBOOK -static void idepmac_sleep_device(ide_drive_t *drive, int i, unsigned base) +static void __pmac +idepmac_sleep_device(ide_drive_t *drive, int i, unsigned base) { int j; @@ -1052,7 +1328,9 @@ switch (drive->media) { case ide_disk: /* Spin down the drive */ - outb(0xa0, base+0x60); + outb(drive->select.all, base+0x60); + (void)inb(base+0x60); + udelay(100); outb(0x0, base+0x30); outb(0x0, base+0x20); outb(0x0, base+0x40); @@ -1076,8 +1354,10 @@ } } -static void idepmac_wake_device(ide_drive_t *drive, int used_dma) - { +#ifdef CONFIG_PMAC_PBOOK +static void __pmac +idepmac_wake_device(ide_drive_t *drive, int used_dma) +{ /* We force the IDE subdriver to check for a media change * This must be done first or we may lost the condition * @@ -1106,7 +1386,8 @@ #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */ } -static void idepmac_sleep_interface(int i, unsigned base, int mediabay) +static void __pmac +idepmac_sleep_interface(int i, unsigned base, int mediabay) { struct device_node* np = pmac_ide[i].node; @@ -1118,73 +1399,85 @@ if (mediabay) return; - /* Disable and reset the bus */ - feature_set(np, FEATURE_IDE0_reset); - feature_clear(np, FEATURE_IDE0_enable); - switch(pmac_ide[i].aapl_bus_id) { - case 0: - feature_set(np, FEATURE_IDE0_reset); - feature_clear(np, FEATURE_IDE0_enable); - break; - case 1: - feature_set(np, FEATURE_IDE1_reset); - feature_clear(np, FEATURE_IDE1_enable); - break; - case 2: - feature_set(np, FEATURE_IDE2_reset); - break; - } + /* Disable the bus */ + ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmac_ide[i].aapl_bus_id, 0); } -static void idepmac_wake_interface(int i, unsigned long base, int mediabay) +static void __pmac +idepmac_wake_interface(int i, unsigned long base, int mediabay) { struct device_node* np = pmac_ide[i].node; if (!mediabay) { /* Revive IDE disk and controller */ - switch(pmac_ide[i].aapl_bus_id) { - case 0: - feature_set(np, FEATURE_IDE0_reset); - feature_set(np, FEATURE_IOBUS_enable); - mdelay(10); - feature_set(np, FEATURE_IDE0_enable); - mdelay(10); - feature_clear(np, FEATURE_IDE0_reset); - break; - case 1: - feature_set(np, FEATURE_IDE1_reset); - feature_set(np, FEATURE_IOBUS_enable); - mdelay(10); - feature_set(np, FEATURE_IDE1_enable); - mdelay(10); - feature_clear(np, FEATURE_IDE1_reset); - break; - case 2: - /* This one exists only for KL, I don't know - about any enable bit */ - feature_set(np, FEATURE_IDE2_reset); - mdelay(10); - feature_clear(np, FEATURE_IDE2_reset); - break; - } + ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmac_ide[i].aapl_bus_id, 1); + ppc_md.feature_call(PMAC_FTR_IDE_ENABLE, np, pmac_ide[i].aapl_bus_id, 1); + mdelay(10); + ppc_md.feature_call(PMAC_FTR_IDE_RESET, np, pmac_ide[i].aapl_bus_id, 0); + } +} + +static void +idepmac_sleep_drive(ide_drive_t *drive, int idx, unsigned long base) +{ + int unlock = 0; + + /* Wait for HW group to complete operations */ + if (ide_spin_wait_hwgroup(drive)) { + // What can we do here ? Wake drive we had already + // put to sleep and return an error ? + } else { + unlock = 1; + /* Lock HW group */ + HWGROUP(drive)->busy = 1; + /* Stop the device */ + idepmac_sleep_device(drive, idx, base); } + if (unlock) + spin_unlock_irq(&io_request_lock); +} + +static void +idepmac_wake_drive(ide_drive_t *drive, unsigned long base) +{ + unsigned long flags; + int j; /* Reset timings */ - pmac_ide_selectproc(&ide_hwifs[i].drives[0]); + pmac_ide_selectproc(drive); mdelay(10); + + /* Wait up to 20 seconds for the drive to be ready */ + for (j = 0; j < 200; j++) { + int status; + mdelay(100); + outb(drive->select.all, base + 0x60); + if (inb(base + 0x60) != drive->select.all) + continue; + status = inb(base + 0x70); + if (!(status & BUSY_STAT)) + break; + } + + /* We resume processing on the HW group */ + spin_lock_irqsave(&io_request_lock, flags); + HWGROUP(drive)->busy = 0; + if (!list_empty(&drive->queue.queue_head)) + ide_do_request(HWGROUP(drive), 0); + spin_unlock_irqrestore(&io_request_lock, flags); } /* Note: We support only master drives for now. This will have to be * improved if we want to handle sleep on the iMacDV where the CD-ROM * is a slave */ -static int idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when) +static int __pmac +idepmac_notify_sleep(struct pmu_sleep_notifier *self, int when) { int i, ret; unsigned long base; - unsigned long flags; int big_delay; - + switch (when) { case PBOOK_SLEEP_REQUEST: break; @@ -1193,34 +1486,19 @@ case PBOOK_SLEEP_NOW: for (i = 0; i < pmac_ide_count; ++i) { ide_hwif_t *hwif; - ide_drive_t *drive; - int unlock = 0; + int dn; if ((base = pmac_ide[i].regbase) == 0) - continue; + continue; hwif = &ide_hwifs[i]; - drive = &hwif->drives[0]; - - if (drive->present) { - /* Wait for HW group to complete operations */ - if (ide_spin_wait_hwgroup(drive)) { - // What can we do here ? Wake drive we had already - // put to sleep and return an error ? - } else { - unlock = 1; - /* Lock HW group */ - HWGROUP(drive)->busy = 1; - - /* Stop the device */ - idepmac_sleep_device(drive, i, base); - - } + for (dn=0; dndrives[dn].present) + continue; + idepmac_sleep_drive(&hwif->drives[dn], i, base); } /* Disable irq during sleep */ disable_irq(pmac_ide[i].irq); - if (unlock) - spin_unlock_irq(&io_request_lock); /* Check if this is a media bay with an IDE device or not * a media bay. @@ -1237,6 +1515,9 @@ if ((base = pmac_ide[i].regbase) == 0) continue; + /* Make sure we have sane timings */ + sanitize_timings(i); + /* Check if this is a media bay with an IDE device or not * a media bay */ @@ -1253,46 +1534,79 @@ for (i = 0; i < pmac_ide_count; ++i) { ide_hwif_t *hwif; - ide_drive_t *drive; - int j, used_dma; + int used_dma, dn; + int irq_on = 0; if ((base = pmac_ide[i].regbase) == 0) continue; hwif = &ide_hwifs[i]; - drive = &hwif->drives[0]; - - /* Wait for the drive to come up and set it's DMA */ - if (drive->present) { - /* Wait up to 20 seconds */ - for (j = 0; j < 200; j++) { - int status; - mdelay(100); - status = inb(base + 0x70); - if (!(status & BUSY_STAT)) - break; + for (dn=0; dndrives[dn]; + if (!drive->present) + continue; + /* We don't have re-configured DMA yet */ + used_dma = drive->using_dma; + drive->using_dma = 0; + idepmac_wake_drive(drive, base); + if (!irq_on) { + enable_irq(pmac_ide[i].irq); + irq_on = 1; } - } - - /* We don't have re-configured DMA yet */ - used_dma = drive->using_dma; - drive->using_dma = 0; - - /* We resume processing on the HW group */ - spin_lock_irqsave(&io_request_lock, flags); - enable_irq(pmac_ide[i].irq); - if (drive->present) - HWGROUP(drive)->busy = 0; - spin_unlock_irqrestore(&io_request_lock, flags); - - /* Wake the device - * We could handle the slave here - */ - if (drive->present) idepmac_wake_device(drive, used_dma); + } + if (!irq_on) + enable_irq(pmac_ide[i].irq); } break; } return PBOOK_SLEEP_OK; } #endif /* CONFIG_PMAC_PBOOK */ + +static int __pmac +pmac_ide_notify_reboot(struct notifier_block *this, unsigned long code, void *x) +{ + int i, gotone; + unsigned long base; + + if (code != SYS_HALT && code != SYS_POWER_OFF) + return 0; + + gotone = 0; + for (i = 0; i < pmac_ide_count; ++i) { + ide_hwif_t *hwif; + ide_drive_t *drive; + int unlock = 0; + int dn; + + if ((base = pmac_ide[i].regbase) == 0) + continue; + + hwif = &ide_hwifs[i]; + for (dn=0; dndrives[dn]; + if (drive->present) { + gotone = 1; + /* Wait for HW group to complete operations */ + if (ide_spin_wait_hwgroup(drive)) { + // What can we do here ? Wake drive we had already + // put to sleep and return an error ? + } else { + unlock = 1; + /* Lock HW group */ + HWGROUP(drive)->busy = 1; + + /* Stop the device */ + idepmac_sleep_device(drive, i, base); + } + } + if (unlock) + spin_unlock_irq(&io_request_lock); + } + } + if (gotone) + mdelay(1000); + + return NOTIFY_DONE; +}