/* Stops the IOC4 DMA Engine */ static int sgiioc4_ide_dma_end(ide_drive_t * drive) { u32 ioc4_dma, bc_dev, bc_mem, num, valid = 0, cnt = 0; ide_hwif_t *hwif = HWIF(drive); unsigned long dma_base = hwif->dma_base; int dma_stat = 0; unsigned long *ending_dma = ide_get_hwifdata(hwif); writel(IOC4_S_DMA_STOP, (void __iomem *)(dma_base + IOC4_DMA_CTRL * 4)); ioc4_dma = sgiioc4_ide_dma_stop(hwif, dma_base); if (ioc4_dma & IOC4_S_DMA_STOP) { printk(KERN_ERR "%s(%s): IOC4 DMA STOP bit is still 1 :" "ioc4_dma_reg 0x%x\n", __FUNCTION__, drive->name, ioc4_dma); dma_stat = 1; } /* * The IOC4 will DMA 1's to the ending dma area to indicate that * previous data DMA is complete. This is necessary because of relaxed * ordering between register reads and DMA writes on the Altix. */ while ((cnt++ < 200) && (!valid)) { for (num = 0; num < 16; num++) { if (ending_dma[num]) { valid = 1; break; } } udelay(1); } if (!valid) { printk(KERN_ERR "%s(%s) : DMA incomplete\n", __FUNCTION__, drive->name); dma_stat = 1; } bc_dev = readl((void __iomem *)(dma_base + IOC4_BC_DEV * 4)); bc_mem = readl((void __iomem *)(dma_base + IOC4_BC_MEM * 4)); if ((bc_dev & 0x01FF) || (bc_mem & 0x1FF)) { if (bc_dev > bc_mem + 8) { printk(KERN_ERR "%s(%s): WARNING!! byte_count_dev %d " "!= byte_count_mem %d\n", __FUNCTION__, drive->name, bc_dev, bc_mem); } } drive->waiting_for_dma = 0; ide_destroy_dmatable(drive); return dma_stat; }
static void it821x_program(ide_drive_t *drive, u16 timing) { ide_hwif_t *hwif = drive->hwif; struct it821x_dev *itdev = ide_get_hwifdata(hwif); int channel = hwif->channel; u8 conf; /* Program PIO/MWDMA timing bits */ if(itdev->clock_mode == ATA_66) conf = timing >> 8; else
static void it821x_program(ide_drive_t *drive, u16 timing) { ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = to_pci_dev(hwif->dev); struct it821x_dev *itdev = ide_get_hwifdata(hwif); int channel = hwif->channel; u8 conf; if(itdev->clock_mode == ATA_66) conf = timing >> 8; else
/* Initializes the IOC4 DMA Engine */ static void sgiioc4_configure_for_dma(int dma_direction, ide_drive_t * drive) { u32 ioc4_dma; ide_hwif_t *hwif = HWIF(drive); unsigned long dma_base = hwif->dma_base; unsigned long ioc4_dma_addr = dma_base + IOC4_DMA_CTRL * 4; u32 dma_addr, ending_dma_addr; ioc4_dma = readl((void __iomem *)ioc4_dma_addr); if (ioc4_dma & IOC4_S_DMA_ACTIVE) { printk(KERN_WARNING "%s(%s):Warning!! DMA from previous transfer was still active\n", __FUNCTION__, drive->name); writel(IOC4_S_DMA_STOP, (void __iomem *)ioc4_dma_addr); ioc4_dma = sgiioc4_ide_dma_stop(hwif, dma_base); if (ioc4_dma & IOC4_S_DMA_STOP) printk(KERN_ERR "%s(%s) : IOC4 Dma STOP bit is still 1\n", __FUNCTION__, drive->name); } ioc4_dma = readl((void __iomem *)ioc4_dma_addr); if (ioc4_dma & IOC4_S_DMA_ERROR) { printk(KERN_WARNING "%s(%s) : Warning!! - DMA Error during Previous" " transfer | status 0x%x\n", __FUNCTION__, drive->name, ioc4_dma); writel(IOC4_S_DMA_STOP, (void __iomem *)ioc4_dma_addr); ioc4_dma = sgiioc4_ide_dma_stop(hwif, dma_base); if (ioc4_dma & IOC4_S_DMA_STOP) printk(KERN_ERR "%s(%s) : IOC4 DMA STOP bit is still 1\n", __FUNCTION__, drive->name); } /* Address of the Scatter Gather List */ dma_addr = cpu_to_le32(hwif->dmatable_dma); writel(dma_addr, (void __iomem *)(dma_base + IOC4_DMA_PTR_L * 4)); /* Address of the Ending DMA */ memset(ide_get_hwifdata(hwif), 0, IOC4_IDE_CACHELINE_SIZE); ending_dma_addr = cpu_to_le32(hwif->dma_status); writel(ending_dma_addr, (void __iomem *)(dma_base + IOC4_DMA_END_ADDR * 4)); writel(dma_direction, (void __iomem *)ioc4_dma_addr); drive->waiting_for_dma = 1; }
/* * HACKITY HACK * * This is a workaround for the limitation 5 of the TC86C001 IDE controller: * if a DMA transfer terminates prematurely, the controller leaves the device's * interrupt request (INTRQ) pending and does not generate a PCI interrupt (or * set the interrupt bit in the DMA status register), thus no PCI interrupt * will occur until a DMA transfer has been successfully completed. * * We work around this by initiating dummy, zero-length DMA transfer on * a DMA timeout expiration. I found no better way to do this with the current * IDE core than to temporarily replace a higher level driver's timer expiry * handler with our own backing up to that handler in case our recovery fails. */ static int tc86c001_timer_expiry(ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); ide_expiry_t *expiry = ide_get_hwifdata(hwif); ide_hwgroup_t *hwgroup = HWGROUP(drive); u8 dma_stat = inb(hwif->dma_base + ATA_DMA_STATUS); /* Restore a higher level driver's expiry handler first. */ hwgroup->expiry = expiry; if ((dma_stat & 5) == 1) { /* DMA active and no interrupt */ unsigned long sc_base = hwif->config_data; unsigned long twcr_port = sc_base + (drive->dn ? 0x06 : 0x04); u8 dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD); printk(KERN_WARNING "%s: DMA interrupt possibly stuck, " "attempting recovery...\n", drive->name); /* Stop DMA */ outb(dma_cmd & ~0x01, hwif->dma_base + ATA_DMA_CMD); /* Setup the dummy DMA transfer */ outw(0, sc_base + 0x0a); /* Sector Count */ outw(0, twcr_port); /* Transfer Word Count 1 or 2 */ /* Start the dummy DMA transfer */ /* clear R_OR_WCTR for write */ outb(0x00, hwif->dma_base + ATA_DMA_CMD); /* set START_STOPBM */ outb(0x01, hwif->dma_base + ATA_DMA_CMD); /* * If an interrupt was pending, it should come thru shortly. * If not, a higher level driver's expiry handler should * eventually cause some kind of recovery from the DMA stall. */ return WAIT_MIN_SLEEP; } /* Chain to the restored expiry handler if DMA wasn't active. */ if (likely(expiry != NULL)) return expiry(drive); /* If there was no handler, "emulate" that for ide_timer_expiry()... */ return -1; }
static void scc_set_dma_mode(ide_drive_t *drive, const u8 speed) { ide_hwif_t *hwif = HWIF(drive); struct scc_ports *ports = ide_get_hwifdata(hwif); unsigned long ctl_base = ports->ctl; unsigned long cckctrl_port = ctl_base + 0xff0; unsigned long mdmact_port = ctl_base + 0x008; unsigned long mcrcst_port = ctl_base + 0x00c; unsigned long sdmact_port = ctl_base + 0x010; unsigned long scrcst_port = ctl_base + 0x014; unsigned long udenvt_port = ctl_base + 0x018; unsigned long tdvhsel_port = ctl_base + 0x020; int is_slave = (&hwif->drives[1] == drive); int offset, idx; unsigned long reg; unsigned long jcactsel; reg = in_be32((void __iomem *)cckctrl_port); if (reg & CCKCTRL_ATACLKOEN) { offset = 1; /* 133MHz */ } else { offset = 0; /* 100MHz */ } idx = speed - XFER_UDMA_0; jcactsel = JCACTSELtbl[offset][idx]; if (is_slave) { out_be32((void __iomem *)sdmact_port, JCHDCTxtbl[offset][idx]); out_be32((void __iomem *)scrcst_port, JCSTWTxtbl[offset][idx]); jcactsel = jcactsel << 2; out_be32((void __iomem *)tdvhsel_port, (in_be32((void __iomem *)tdvhsel_port) & ~TDVHSEL_SLAVE) | jcactsel); } else { out_be32((void __iomem *)mdmact_port, JCHDCTxtbl[offset][idx]); out_be32((void __iomem *)mcrcst_port, JCSTWTxtbl[offset][idx]); out_be32((void __iomem *)tdvhsel_port, (in_be32((void __iomem *)tdvhsel_port) & ~TDVHSEL_MASTER) | jcactsel); } reg = JCTSStbl[offset][idx] << 16 | JCENVTtbl[offset][idx]; out_be32((void __iomem *)udenvt_port, reg); }
static void scc_set_pio_mode(ide_drive_t *drive, const u8 pio) { ide_hwif_t *hwif = HWIF(drive); struct scc_ports *ports = ide_get_hwifdata(hwif); unsigned long ctl_base = ports->ctl; unsigned long cckctrl_port = ctl_base + 0xff0; unsigned long piosht_port = ctl_base + 0x000; unsigned long pioct_port = ctl_base + 0x004; unsigned long reg; int offset; reg = in_be32((void __iomem *)cckctrl_port); if (reg & CCKCTRL_ATACLKOEN) { offset = 1; /* 133MHz */ } else { offset = 0; /* 100MHz */ } reg = JCHSTtbl[offset][pio] << 16 | JCHHTtbl[offset][pio]; out_be32((void __iomem *)piosht_port, reg); reg = JCHCTtbl[offset][pio]; out_be32((void __iomem *)pioct_port, reg); }