/* 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; }
/* 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); u64 dma_base = hwif->dma_base; int dma_stat = 0; unsigned long *ending_dma = (unsigned long *) hwif->dma_base2; hwif->OUTL(IOC4_S_DMA_STOP, 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 = hwif->INL(dma_base + IOC4_BC_DEV * 4); bc_mem = hwif->INL(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; }