18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci#include <linux/types.h>
38c2ecf20Sopenharmony_ci#include <linux/kernel.h>
48c2ecf20Sopenharmony_ci#include <linux/export.h>
58c2ecf20Sopenharmony_ci#include <linux/ide.h>
68c2ecf20Sopenharmony_ci#include <linux/scatterlist.h>
78c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h>
88c2ecf20Sopenharmony_ci#include <linux/io.h>
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci/**
118c2ecf20Sopenharmony_ci *	config_drive_for_dma	-	attempt to activate IDE DMA
128c2ecf20Sopenharmony_ci *	@drive: the drive to place in DMA mode
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci *	If the drive supports at least mode 2 DMA or UDMA of any kind
158c2ecf20Sopenharmony_ci *	then attempt to place it into DMA mode. Drives that are known to
168c2ecf20Sopenharmony_ci *	support DMA but predate the DMA properties or that are known
178c2ecf20Sopenharmony_ci *	to have DMA handling bugs are also set up appropriately based
188c2ecf20Sopenharmony_ci *	on the good/bad drive lists.
198c2ecf20Sopenharmony_ci */
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ciint config_drive_for_dma(ide_drive_t *drive)
228c2ecf20Sopenharmony_ci{
238c2ecf20Sopenharmony_ci	ide_hwif_t *hwif = drive->hwif;
248c2ecf20Sopenharmony_ci	u16 *id = drive->id;
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci	if (drive->media != ide_disk) {
278c2ecf20Sopenharmony_ci		if (hwif->host_flags & IDE_HFLAG_NO_ATAPI_DMA)
288c2ecf20Sopenharmony_ci			return 0;
298c2ecf20Sopenharmony_ci	}
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	/*
328c2ecf20Sopenharmony_ci	 * Enable DMA on any drive that has
338c2ecf20Sopenharmony_ci	 * UltraDMA (mode 0/1/2/3/4/5/6) enabled
348c2ecf20Sopenharmony_ci	 */
358c2ecf20Sopenharmony_ci	if ((id[ATA_ID_FIELD_VALID] & 4) &&
368c2ecf20Sopenharmony_ci	    ((id[ATA_ID_UDMA_MODES] >> 8) & 0x7f))
378c2ecf20Sopenharmony_ci		return 1;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	/*
408c2ecf20Sopenharmony_ci	 * Enable DMA on any drive that has mode2 DMA
418c2ecf20Sopenharmony_ci	 * (multi or single) enabled
428c2ecf20Sopenharmony_ci	 */
438c2ecf20Sopenharmony_ci	if ((id[ATA_ID_MWDMA_MODES] & 0x404) == 0x404 ||
448c2ecf20Sopenharmony_ci	    (id[ATA_ID_SWDMA_MODES] & 0x404) == 0x404)
458c2ecf20Sopenharmony_ci		return 1;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	/* Consult the list of known "good" drives */
488c2ecf20Sopenharmony_ci	if (ide_dma_good_drive(drive))
498c2ecf20Sopenharmony_ci		return 1;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	return 0;
528c2ecf20Sopenharmony_ci}
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ciu8 ide_dma_sff_read_status(ide_hwif_t *hwif)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	unsigned long addr = hwif->dma_base + ATA_DMA_STATUS;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	if (hwif->host_flags & IDE_HFLAG_MMIO)
598c2ecf20Sopenharmony_ci		return readb((void __iomem *)addr);
608c2ecf20Sopenharmony_ci	else
618c2ecf20Sopenharmony_ci		return inb(addr);
628c2ecf20Sopenharmony_ci}
638c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ide_dma_sff_read_status);
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_cistatic void ide_dma_sff_write_status(ide_hwif_t *hwif, u8 val)
668c2ecf20Sopenharmony_ci{
678c2ecf20Sopenharmony_ci	unsigned long addr = hwif->dma_base + ATA_DMA_STATUS;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	if (hwif->host_flags & IDE_HFLAG_MMIO)
708c2ecf20Sopenharmony_ci		writeb(val, (void __iomem *)addr);
718c2ecf20Sopenharmony_ci	else
728c2ecf20Sopenharmony_ci		outb(val, addr);
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci/**
768c2ecf20Sopenharmony_ci *	ide_dma_host_set	-	Enable/disable DMA on a host
778c2ecf20Sopenharmony_ci *	@drive: drive to control
788c2ecf20Sopenharmony_ci *
798c2ecf20Sopenharmony_ci *	Enable/disable DMA on an IDE controller following generic
808c2ecf20Sopenharmony_ci *	bus-mastering IDE controller behaviour.
818c2ecf20Sopenharmony_ci */
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_civoid ide_dma_host_set(ide_drive_t *drive, int on)
848c2ecf20Sopenharmony_ci{
858c2ecf20Sopenharmony_ci	ide_hwif_t *hwif = drive->hwif;
868c2ecf20Sopenharmony_ci	u8 unit = drive->dn & 1;
878c2ecf20Sopenharmony_ci	u8 dma_stat = hwif->dma_ops->dma_sff_read_status(hwif);
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	if (on)
908c2ecf20Sopenharmony_ci		dma_stat |= (1 << (5 + unit));
918c2ecf20Sopenharmony_ci	else
928c2ecf20Sopenharmony_ci		dma_stat &= ~(1 << (5 + unit));
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	ide_dma_sff_write_status(hwif, dma_stat);
958c2ecf20Sopenharmony_ci}
968c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ide_dma_host_set);
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci/**
998c2ecf20Sopenharmony_ci *	ide_build_dmatable	-	build IDE DMA table
1008c2ecf20Sopenharmony_ci *
1018c2ecf20Sopenharmony_ci *	ide_build_dmatable() prepares a dma request. We map the command
1028c2ecf20Sopenharmony_ci *	to get the pci bus addresses of the buffers and then build up
1038c2ecf20Sopenharmony_ci *	the PRD table that the IDE layer wants to be fed.
1048c2ecf20Sopenharmony_ci *
1058c2ecf20Sopenharmony_ci *	Most chipsets correctly interpret a length of 0x0000 as 64KB,
1068c2ecf20Sopenharmony_ci *	but at least one (e.g. CS5530) misinterprets it as zero (!).
1078c2ecf20Sopenharmony_ci *	So we break the 64KB entry into two 32KB entries instead.
1088c2ecf20Sopenharmony_ci *
1098c2ecf20Sopenharmony_ci *	Returns the number of built PRD entries if all went okay,
1108c2ecf20Sopenharmony_ci *	returns 0 otherwise.
1118c2ecf20Sopenharmony_ci *
1128c2ecf20Sopenharmony_ci *	May also be invoked from trm290.c
1138c2ecf20Sopenharmony_ci */
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ciint ide_build_dmatable(ide_drive_t *drive, struct ide_cmd *cmd)
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci	ide_hwif_t *hwif = drive->hwif;
1188c2ecf20Sopenharmony_ci	__le32 *table = (__le32 *)hwif->dmatable_cpu;
1198c2ecf20Sopenharmony_ci	unsigned int count = 0;
1208c2ecf20Sopenharmony_ci	int i;
1218c2ecf20Sopenharmony_ci	struct scatterlist *sg;
1228c2ecf20Sopenharmony_ci	u8 is_trm290 = !!(hwif->host_flags & IDE_HFLAG_TRM290);
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	for_each_sg(hwif->sg_table, sg, cmd->sg_nents, i) {
1258c2ecf20Sopenharmony_ci		u32 cur_addr, cur_len, xcount, bcount;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci		cur_addr = sg_dma_address(sg);
1288c2ecf20Sopenharmony_ci		cur_len = sg_dma_len(sg);
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci		/*
1318c2ecf20Sopenharmony_ci		 * Fill in the dma table, without crossing any 64kB boundaries.
1328c2ecf20Sopenharmony_ci		 * Most hardware requires 16-bit alignment of all blocks,
1338c2ecf20Sopenharmony_ci		 * but the trm290 requires 32-bit alignment.
1348c2ecf20Sopenharmony_ci		 */
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci		while (cur_len) {
1378c2ecf20Sopenharmony_ci			if (count++ >= PRD_ENTRIES)
1388c2ecf20Sopenharmony_ci				goto use_pio_instead;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci			bcount = 0x10000 - (cur_addr & 0xffff);
1418c2ecf20Sopenharmony_ci			if (bcount > cur_len)
1428c2ecf20Sopenharmony_ci				bcount = cur_len;
1438c2ecf20Sopenharmony_ci			*table++ = cpu_to_le32(cur_addr);
1448c2ecf20Sopenharmony_ci			xcount = bcount & 0xffff;
1458c2ecf20Sopenharmony_ci			if (is_trm290)
1468c2ecf20Sopenharmony_ci				xcount = ((xcount >> 2) - 1) << 16;
1478c2ecf20Sopenharmony_ci			else if (xcount == 0x0000) {
1488c2ecf20Sopenharmony_ci				if (count++ >= PRD_ENTRIES)
1498c2ecf20Sopenharmony_ci					goto use_pio_instead;
1508c2ecf20Sopenharmony_ci				*table++ = cpu_to_le32(0x8000);
1518c2ecf20Sopenharmony_ci				*table++ = cpu_to_le32(cur_addr + 0x8000);
1528c2ecf20Sopenharmony_ci				xcount = 0x8000;
1538c2ecf20Sopenharmony_ci			}
1548c2ecf20Sopenharmony_ci			*table++ = cpu_to_le32(xcount);
1558c2ecf20Sopenharmony_ci			cur_addr += bcount;
1568c2ecf20Sopenharmony_ci			cur_len -= bcount;
1578c2ecf20Sopenharmony_ci		}
1588c2ecf20Sopenharmony_ci	}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	if (count) {
1618c2ecf20Sopenharmony_ci		if (!is_trm290)
1628c2ecf20Sopenharmony_ci			*--table |= cpu_to_le32(0x80000000);
1638c2ecf20Sopenharmony_ci		return count;
1648c2ecf20Sopenharmony_ci	}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ciuse_pio_instead:
1678c2ecf20Sopenharmony_ci	printk(KERN_ERR "%s: %s\n", drive->name,
1688c2ecf20Sopenharmony_ci		count ? "DMA table too small" : "empty DMA table?");
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	return 0; /* revert to PIO for this request */
1718c2ecf20Sopenharmony_ci}
1728c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ide_build_dmatable);
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci/**
1758c2ecf20Sopenharmony_ci *	ide_dma_setup	-	begin a DMA phase
1768c2ecf20Sopenharmony_ci *	@drive: target device
1778c2ecf20Sopenharmony_ci *	@cmd: command
1788c2ecf20Sopenharmony_ci *
1798c2ecf20Sopenharmony_ci *	Build an IDE DMA PRD (IDE speak for scatter gather table)
1808c2ecf20Sopenharmony_ci *	and then set up the DMA transfer registers for a device
1818c2ecf20Sopenharmony_ci *	that follows generic IDE PCI DMA behaviour. Controllers can
1828c2ecf20Sopenharmony_ci *	override this function if they need to
1838c2ecf20Sopenharmony_ci *
1848c2ecf20Sopenharmony_ci *	Returns 0 on success. If a PIO fallback is required then 1
1858c2ecf20Sopenharmony_ci *	is returned.
1868c2ecf20Sopenharmony_ci */
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ciint ide_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd)
1898c2ecf20Sopenharmony_ci{
1908c2ecf20Sopenharmony_ci	ide_hwif_t *hwif = drive->hwif;
1918c2ecf20Sopenharmony_ci	u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
1928c2ecf20Sopenharmony_ci	u8 rw = (cmd->tf_flags & IDE_TFLAG_WRITE) ? 0 : ATA_DMA_WR;
1938c2ecf20Sopenharmony_ci	u8 dma_stat;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	/* fall back to pio! */
1968c2ecf20Sopenharmony_ci	if (ide_build_dmatable(drive, cmd) == 0) {
1978c2ecf20Sopenharmony_ci		ide_map_sg(drive, cmd);
1988c2ecf20Sopenharmony_ci		return 1;
1998c2ecf20Sopenharmony_ci	}
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	/* PRD table */
2028c2ecf20Sopenharmony_ci	if (mmio)
2038c2ecf20Sopenharmony_ci		writel(hwif->dmatable_dma,
2048c2ecf20Sopenharmony_ci		       (void __iomem *)(hwif->dma_base + ATA_DMA_TABLE_OFS));
2058c2ecf20Sopenharmony_ci	else
2068c2ecf20Sopenharmony_ci		outl(hwif->dmatable_dma, hwif->dma_base + ATA_DMA_TABLE_OFS);
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	/* specify r/w */
2098c2ecf20Sopenharmony_ci	if (mmio)
2108c2ecf20Sopenharmony_ci		writeb(rw, (void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
2118c2ecf20Sopenharmony_ci	else
2128c2ecf20Sopenharmony_ci		outb(rw, hwif->dma_base + ATA_DMA_CMD);
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	/* read DMA status for INTR & ERROR flags */
2158c2ecf20Sopenharmony_ci	dma_stat = hwif->dma_ops->dma_sff_read_status(hwif);
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	/* clear INTR & ERROR flags */
2188c2ecf20Sopenharmony_ci	ide_dma_sff_write_status(hwif, dma_stat | ATA_DMA_ERR | ATA_DMA_INTR);
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	return 0;
2218c2ecf20Sopenharmony_ci}
2228c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ide_dma_setup);
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci/**
2258c2ecf20Sopenharmony_ci *	ide_dma_sff_timer_expiry	-	handle a DMA timeout
2268c2ecf20Sopenharmony_ci *	@drive: Drive that timed out
2278c2ecf20Sopenharmony_ci *
2288c2ecf20Sopenharmony_ci *	An IDE DMA transfer timed out. In the event of an error we ask
2298c2ecf20Sopenharmony_ci *	the driver to resolve the problem, if a DMA transfer is still
2308c2ecf20Sopenharmony_ci *	in progress we continue to wait (arguably we need to add a
2318c2ecf20Sopenharmony_ci *	secondary 'I don't care what the drive thinks' timeout here)
2328c2ecf20Sopenharmony_ci *	Finally if we have an interrupt we let it complete the I/O.
2338c2ecf20Sopenharmony_ci *	But only one time - we clear expiry and if it's still not
2348c2ecf20Sopenharmony_ci *	completed after WAIT_CMD, we error and retry in PIO.
2358c2ecf20Sopenharmony_ci *	This can occur if an interrupt is lost or due to hang or bugs.
2368c2ecf20Sopenharmony_ci */
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ciint ide_dma_sff_timer_expiry(ide_drive_t *drive)
2398c2ecf20Sopenharmony_ci{
2408c2ecf20Sopenharmony_ci	ide_hwif_t *hwif = drive->hwif;
2418c2ecf20Sopenharmony_ci	u8 dma_stat = hwif->dma_ops->dma_sff_read_status(hwif);
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	printk(KERN_WARNING "%s: %s: DMA status (0x%02x)\n",
2448c2ecf20Sopenharmony_ci		drive->name, __func__, dma_stat);
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	if ((dma_stat & 0x18) == 0x18)	/* BUSY Stupid Early Timer !! */
2478c2ecf20Sopenharmony_ci		return WAIT_CMD;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	hwif->expiry = NULL;	/* one free ride for now */
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	if (dma_stat & ATA_DMA_ERR)	/* ERROR */
2528c2ecf20Sopenharmony_ci		return -1;
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	if (dma_stat & ATA_DMA_ACTIVE)	/* DMAing */
2558c2ecf20Sopenharmony_ci		return WAIT_CMD;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	if (dma_stat & ATA_DMA_INTR)	/* Got an Interrupt */
2588c2ecf20Sopenharmony_ci		return WAIT_CMD;
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	return 0;	/* Status is unknown -- reset the bus */
2618c2ecf20Sopenharmony_ci}
2628c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ide_dma_sff_timer_expiry);
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_civoid ide_dma_start(ide_drive_t *drive)
2658c2ecf20Sopenharmony_ci{
2668c2ecf20Sopenharmony_ci	ide_hwif_t *hwif = drive->hwif;
2678c2ecf20Sopenharmony_ci	u8 dma_cmd;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	/* Note that this is done *after* the cmd has
2708c2ecf20Sopenharmony_ci	 * been issued to the drive, as per the BM-IDE spec.
2718c2ecf20Sopenharmony_ci	 * The Promise Ultra33 doesn't work correctly when
2728c2ecf20Sopenharmony_ci	 * we do this part before issuing the drive cmd.
2738c2ecf20Sopenharmony_ci	 */
2748c2ecf20Sopenharmony_ci	if (hwif->host_flags & IDE_HFLAG_MMIO) {
2758c2ecf20Sopenharmony_ci		dma_cmd = readb((void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
2768c2ecf20Sopenharmony_ci		writeb(dma_cmd | ATA_DMA_START,
2778c2ecf20Sopenharmony_ci		       (void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
2788c2ecf20Sopenharmony_ci	} else {
2798c2ecf20Sopenharmony_ci		dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD);
2808c2ecf20Sopenharmony_ci		outb(dma_cmd | ATA_DMA_START, hwif->dma_base + ATA_DMA_CMD);
2818c2ecf20Sopenharmony_ci	}
2828c2ecf20Sopenharmony_ci}
2838c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ide_dma_start);
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci/* returns 1 on error, 0 otherwise */
2868c2ecf20Sopenharmony_ciint ide_dma_end(ide_drive_t *drive)
2878c2ecf20Sopenharmony_ci{
2888c2ecf20Sopenharmony_ci	ide_hwif_t *hwif = drive->hwif;
2898c2ecf20Sopenharmony_ci	u8 dma_stat = 0, dma_cmd = 0;
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	/* stop DMA */
2928c2ecf20Sopenharmony_ci	if (hwif->host_flags & IDE_HFLAG_MMIO) {
2938c2ecf20Sopenharmony_ci		dma_cmd = readb((void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
2948c2ecf20Sopenharmony_ci		writeb(dma_cmd & ~ATA_DMA_START,
2958c2ecf20Sopenharmony_ci		       (void __iomem *)(hwif->dma_base + ATA_DMA_CMD));
2968c2ecf20Sopenharmony_ci	} else {
2978c2ecf20Sopenharmony_ci		dma_cmd = inb(hwif->dma_base + ATA_DMA_CMD);
2988c2ecf20Sopenharmony_ci		outb(dma_cmd & ~ATA_DMA_START, hwif->dma_base + ATA_DMA_CMD);
2998c2ecf20Sopenharmony_ci	}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	/* get DMA status */
3028c2ecf20Sopenharmony_ci	dma_stat = hwif->dma_ops->dma_sff_read_status(hwif);
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	/* clear INTR & ERROR bits */
3058c2ecf20Sopenharmony_ci	ide_dma_sff_write_status(hwif, dma_stat | ATA_DMA_ERR | ATA_DMA_INTR);
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci#define CHECK_DMA_MASK (ATA_DMA_ACTIVE | ATA_DMA_ERR | ATA_DMA_INTR)
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	/* verify good DMA status */
3108c2ecf20Sopenharmony_ci	if ((dma_stat & CHECK_DMA_MASK) != ATA_DMA_INTR)
3118c2ecf20Sopenharmony_ci		return 0x10 | dma_stat;
3128c2ecf20Sopenharmony_ci	return 0;
3138c2ecf20Sopenharmony_ci}
3148c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ide_dma_end);
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci/* returns 1 if dma irq issued, 0 otherwise */
3178c2ecf20Sopenharmony_ciint ide_dma_test_irq(ide_drive_t *drive)
3188c2ecf20Sopenharmony_ci{
3198c2ecf20Sopenharmony_ci	ide_hwif_t *hwif = drive->hwif;
3208c2ecf20Sopenharmony_ci	u8 dma_stat = hwif->dma_ops->dma_sff_read_status(hwif);
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	return (dma_stat & ATA_DMA_INTR) ? 1 : 0;
3238c2ecf20Sopenharmony_ci}
3248c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(ide_dma_test_irq);
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ciconst struct ide_dma_ops sff_dma_ops = {
3278c2ecf20Sopenharmony_ci	.dma_host_set		= ide_dma_host_set,
3288c2ecf20Sopenharmony_ci	.dma_setup		= ide_dma_setup,
3298c2ecf20Sopenharmony_ci	.dma_start		= ide_dma_start,
3308c2ecf20Sopenharmony_ci	.dma_end		= ide_dma_end,
3318c2ecf20Sopenharmony_ci	.dma_test_irq		= ide_dma_test_irq,
3328c2ecf20Sopenharmony_ci	.dma_lost_irq		= ide_dma_lost_irq,
3338c2ecf20Sopenharmony_ci	.dma_timer_expiry	= ide_dma_sff_timer_expiry,
3348c2ecf20Sopenharmony_ci	.dma_sff_read_status	= ide_dma_sff_read_status,
3358c2ecf20Sopenharmony_ci};
3368c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(sff_dma_ops);
337