📄 ide-pmac.c
字号:
}#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 intpmac_ide_udma_enable(ide_drive_t *drive, int idx){ byte bits = drive->id->dma_ultra & 0x1f; byte feature = udma_bits_to_command(bits); int cycleTime, accessTime; int rdyToPauseTicks, cycleTicks; u32 *timings; int ret; /* Set feature on drive */ printk(KERN_INFO "%s: Enabling Ultra DMA %d\n", drive->name, feature & 0xf); ret = pmac_ide_do_setfeature(drive, feature); if (ret) { printk(KERN_WARNING "%s: Failed !\n", drive->name); return 0; } if (!drive->init_speed) drive->init_speed = feature; /* which drive is it ? */ if (drive->select.all & 0x10) 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; drive->current_speed = feature; return 1;}static intpmac_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); if (idx < 0) return 0; if (drive->media == ide_floppy) enable = 0; if (((id->capability & 1) == 0) && !check_drive_lists(drive, GOOD_DMA_DRIVE)) enable = 0; if (check_drive_lists(drive, BAD_DMA_DRIVE)) enable = 0; udma = 0; ata4 = (pmac_ide[idx].kind == controller_kl_ata4); if(enable) { if (ata4 && (drive->media == ide_disk) && (id->field_valid & 0x0004) && (id->dma_ultra & 0x17)) { /* UltraDMA modes. */ drive->using_dma = pmac_ide_udma_enable(drive, idx); } 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); } return 0;}int pmac_ide_dmaproc(ide_dma_action_t func, ide_drive_t *drive){ int ix, dstat, i; volatile struct dbdma_regs *dma; /* Can we stuff a pointer to our intf structure in config_data * or select_data in hwif ? */ ix = pmac_ide_find(drive); if (ix < 0) return 0; dma = pmac_ide[ix].dma_regs; switch (func) { case ide_dma_off: printk(KERN_INFO "%s: DMA disabled\n", drive->name); case ide_dma_off_quietly: drive->using_dma = 0; break; case ide_dma_on: case ide_dma_check: pmac_ide_check_dma(drive); break; case ide_dma_read: case ide_dma_write: if (!pmac_ide_build_dmatable(drive, ix, func==ide_dma_write)) return 1; drive->waiting_for_dma = 1; if (drive->media != ide_disk) return 0; ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL); OUT_BYTE(func==ide_dma_write? WIN_WRITEDMA: WIN_READDMA, IDE_COMMAND_REG); case ide_dma_begin: out_le32(&dma->control, (RUN << 16) | RUN); break; case ide_dma_end: 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 */ 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 */ while ((in_le32(&dma->status) & (RUN|ACTIVE)) != RUN) { if (++i > 100) return 0; udelay(1); } return 1; /* Let's implement tose just in case someone wants them */ case ide_dma_bad_drive: case ide_dma_good_drive: return check_drive_lists(drive, (func == ide_dma_good_drive)); case ide_dma_verbose: return report_drive_dmaing(drive); case ide_dma_retune: case ide_dma_lostirq: case ide_dma_timeout: printk(KERN_WARNING "ide_pmac_dmaproc: chipset supported %s func only: %d\n", ide_dmafunc_verbose(func), func); return 1; default: printk(KERN_WARNING "ide_pmac_dmaproc: unsupported %s func: %d\n", ide_dmafunc_verbose(func), func); return 1; } return 0;}#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */#ifdef CONFIG_PMAC_PBOOKstatic void idepmac_sleep_device(ide_drive_t *drive, int i, unsigned base){ int j; /* FIXME: We only handle the master IDE disk, we shoud * try to fix CD-ROMs here */ switch (drive->media) { case ide_disk: /* Spin down the drive */ outb(0xa0, base+0x60); outb(0x0, base+0x30); outb(0x0, base+0x20); outb(0x0, base+0x40); outb(0x0, base+0x50); outb(0xe0, base+0x70); outb(0x2, base+0x160); for (j = 0; j < 10; j++) { int status; mdelay(100); status = inb(base+0x70); if (!(status & BUSY_STAT) && (status & DRQ_STAT)) break; } break; case ide_cdrom: // todo break; case ide_floppy: // todo break; }}static void 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 * * Problem: This can schedule. I moved the block device * wakeup almost late by priority because of that. */ if (DRIVER(drive) && DRIVER(drive)->media_change) DRIVER(drive)->media_change(drive); /* We kick the VFS too (see fix in ide.c revalidate) */ check_disk_change(MKDEV(HWIF(drive)->major, (drive->select.b.unit) << PARTN_BITS)); #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC /* We re-enable DMA on the drive if it was active. */ /* This doesn't work with the CD-ROM in the media-bay, probably * because of a pending unit attention. The problem if that if I * clear the error, the filesystem dies. */ if (used_dma && !ide_spin_wait_hwgroup(drive)) { /* Lock HW group */ HWGROUP(drive)->busy = 1; pmac_ide_check_dma(drive); HWGROUP(drive)->busy = 0; spin_unlock_irq(&io_request_lock); }#endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */}static void idepmac_sleep_interface(int i, unsigned base, int mediabay){ struct device_node* np = pmac_ide[i].node; /* We clear the timings */ pmac_ide[i].timings[0] = 0; pmac_ide[i].timings[1] = 0; /* The media bay will handle itself just fine */ 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; }}static void 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; } } /* Reset timings */ pmac_ide_selectproc(&ide_hwifs[i].drives[0]); mdelay(10);}/* 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){ int i, ret; unsigned long base; unsigned long flags; int big_delay; switch (when) { case PBOOK_SLEEP_REQUEST: break; case PBOOK_SLEEP_REJECT: break; case PBOOK_SLEEP_NOW: for (i = 0; i < pmac_ide_count; ++i) { ide_hwif_t *hwif; ide_drive_t *drive; int unlock = 0; if ((base = pmac_ide[i].regbase) == 0) 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); } } /* 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. */ ret = check_media_bay_by_base(base, MB_CD); if ((ret == 0) || (ret == -ENODEV)) idepmac_sleep_interface(i, base, (ret == 0)); } break; case PBOOK_WAKE: big_delay = 0; for (i = 0; i < pmac_ide_count; ++i) { if ((base = pmac_ide[i].regbase) == 0) continue; /* Check if this is a media bay with an IDE device or not * a media bay */ ret = check_media_bay_by_base(base, MB_CD); if ((ret == 0) || (ret == -ENODEV)) { idepmac_wake_interface(i, base, (ret == 0)); big_delay = 1; } } /* Let hardware get up to speed */ if (big_delay) mdelay(IDE_WAKEUP_DELAY_MS); for (i = 0; i < pmac_ide_count; ++i) { ide_hwif_t *hwif; ide_drive_t *drive; int j, used_dma; 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; } } /* 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); } break; } return PBOOK_SLEEP_OK;}#endif /* CONFIG_PMAC_PBOOK */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -