Пример #1
0
/* 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;
}
Пример #2
0
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
Пример #3
0
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
Пример #4
0
/* 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;
}
Пример #5
0
/*
 * 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;
}
Пример #6
0
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);
}
Пример #7
0
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);
}