⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ide-dma.c

📁 ep9315平台下硬盘驱动的源码
💻 C
📖 第 1 页 / 共 3 页
字号:
			} else {				u32 xcount, bcount = 0x10000 - (cur_addr & 0xffff);				if (bcount > cur_len)					bcount = cur_len;				*table++ = cpu_to_le32(cur_addr);				xcount = bcount & 0xffff;				if (is_trm290)					xcount = ((xcount >> 2) - 1) << 16;				if (xcount == 0x0000) {	/* 	 * Most chipsets correctly interpret a length of 0x0000 as 64KB,	 * but at least one (e.g. CS5530) misinterprets it as zero (!).	 * So here we break the 64KB entry into two 32KB entries instead.	 */					if (count++ >= PRD_ENTRIES) {						printk("%s: DMA table too small\n", drive->name);						goto use_pio_instead;					}					*table++ = cpu_to_le32(0x8000);					*table++ = cpu_to_le32(cur_addr + 0x8000);					xcount = 0x8000;				}				*table++ = cpu_to_le32(xcount);				cur_addr += bcount;				cur_len -= bcount;			}		}		sg++;		i--;	}	if (count) {		if (!is_trm290)			*--table |= cpu_to_le32(0x80000000);		return count;	}	printk("%s: empty DMA table?\n", drive->name);use_pio_instead:	pci_unmap_sg(hwif->pci_dev,		     hwif->sg_table,		     hwif->sg_nents,		     hwif->sg_dma_direction);	hwif->sg_dma_active = 0;	return 0; /* revert to PIO for this request */}EXPORT_SYMBOL_GPL(ide_build_dmatable);/** *	ide_destroy_dmatable	-	clean up DMA mapping *	@drive: The drive to unmap * *	Teardown mappings after DMA has completed. This must be called *	after the completion of each use of ide_build_dmatable and before *	the next use of ide_build_dmatable. Failure to do so will cause *	an oops as only one mapping can be live for each target at a given *	time. */ void ide_destroy_dmatable (ide_drive_t *drive){	struct pci_dev *dev = HWIF(drive)->pci_dev;	struct scatterlist *sg = HWIF(drive)->sg_table;	int nents = HWIF(drive)->sg_nents;	pci_unmap_sg(dev, sg, nents, HWIF(drive)->sg_dma_direction);	HWIF(drive)->sg_dma_active = 0;}EXPORT_SYMBOL_GPL(ide_destroy_dmatable);/** *	config_drive_for_dma	-	attempt to activate IDE DMA *	@drive: the drive to place in DMA mode * *	If the drive supports at least mode 2 DMA or UDMA of any kind *	then attempt to place it into DMA mode. Drives that are known to *	support DMA but predate the DMA properties or that are known *	to have DMA handling bugs are also set up appropriately based *	on the good/bad drive lists. */ static int config_drive_for_dma (ide_drive_t *drive){	struct hd_driveid *id = drive->id;	ide_hwif_t *hwif = HWIF(drive);	if ((id->capability & 1) && hwif->autodma) {		/* Consult the list of known "bad" drives */		if (hwif->ide_dma_bad_drive(drive))			return hwif->ide_dma_off(drive);		/*		 * Enable DMA on any drive that has		 * UltraDMA (mode 0/1/2/3/4/5/6) enabled		 */		if ((id->field_valid & 4) && ((id->dma_ultra >> 8) & 0x7f))			return hwif->ide_dma_on(drive);		/*		 * Enable DMA on any drive that has mode2 DMA		 * (multi or single) enabled		 */		if (id->field_valid & 2)	/* regular DMA */			if ((id->dma_mword & 0x404) == 0x404 ||			    (id->dma_1word & 0x404) == 0x404)				return hwif->ide_dma_on(drive);		/* Consult the list of known "good" drives */		if (hwif->ide_dma_good_drive(drive))			return hwif->ide_dma_on(drive);	}//	if (hwif->tuneproc != NULL) hwif->tuneproc(drive, 255);	return hwif->ide_dma_off_quietly(drive);}/** *	dma_timer_expiry	-	handle a DMA timeout *	@drive: Drive that timed out * *	An IDE DMA transfer timed out. In the event of an error we ask *	the driver to resolve the problem, if a DMA transfer is still *	in progress we continue to wait (arguably we need to add a  *	secondary 'I dont care what the drive thinks' timeout here) *	Finally if we have an interrupt but for some reason got the *	timeout first we complete the I/O. This can occur if an  *	interrupt is lost or due to bugs. */ static int dma_timer_expiry (ide_drive_t *drive){	ide_hwif_t *hwif	= HWIF(drive);	u8 dma_stat		= hwif->INB(hwif->dma_status);	printk(KERN_WARNING "%s: dma_timer_expiry: dma status == 0x%02x\n",		drive->name, dma_stat);	if ((dma_stat & 0x18) == 0x18)	/* BUSY Stupid Early Timer !! */		return WAIT_CMD;	HWGROUP(drive)->expiry = NULL;	/* one free ride for now */	/* 1 dmaing, 2 error, 4 intr */		if (dma_stat & 2) {	/* ERROR */		(void) hwif->ide_dma_end(drive);		return DRIVER(drive)->error(drive,			"dma_timer_expiry", hwif->INB(IDE_STATUS_REG));	}	if (dma_stat & 1)	/* DMAing */		return WAIT_CMD;	if (dma_stat & 4)	/* Got an Interrupt */		HWGROUP(drive)->handler(drive);	return 0;}/** *	__ide_dma_host_off	-	Generic DMA kill *	@drive: drive to control * *	Perform the generic IDE controller DMA off operation. This *	works for most IDE bus mastering controllers */int __ide_dma_host_off (ide_drive_t *drive){	ide_hwif_t *hwif	= HWIF(drive);	u8 unit			= (drive->select.b.unit & 0x01);	u8 dma_stat		= hwif->INB(hwif->dma_status);	hwif->OUTB((dma_stat & ~(1<<(5+unit))), hwif->dma_status);	return 0;}EXPORT_SYMBOL(__ide_dma_host_off);/** *	__ide_dma_host_off_quietly	-	Generic DMA kill *	@drive: drive to control * *	Turn off the current DMA on this IDE controller.  */int __ide_dma_off_quietly (ide_drive_t *drive){	drive->using_dma = 0;	ide_toggle_bounce(drive, 0);	return HWIF(drive)->ide_dma_host_off(drive);}EXPORT_SYMBOL(__ide_dma_off_quietly);/** *	__ide_dma_host_off	-	Generic DMA kill *	@drive: drive to control * *	Turn off the current DMA on this IDE controller. Inform the *	user that DMA has been disabled.  */int __ide_dma_off (ide_drive_t *drive){	printk(KERN_INFO "%s: DMA disabled\n", drive->name);	return HWIF(drive)->ide_dma_off_quietly(drive);}EXPORT_SYMBOL(__ide_dma_off);/** *	__ide_dma_host_on	-	Enable DMA on a host *	@drive: drive to enable for DMA * *	Enable DMA on an IDE controller following generic bus mastering *	IDE controller behaviour */ int __ide_dma_host_on (ide_drive_t *drive){	if (drive->using_dma) {		ide_hwif_t *hwif	= HWIF(drive);		u8 unit			= (drive->select.b.unit & 0x01);		u8 dma_stat		= hwif->INB(hwif->dma_status);		hwif->OUTB((dma_stat|(1<<(5+unit))), hwif->dma_status);		return 0;	}	return 1;}EXPORT_SYMBOL(__ide_dma_host_on);/** *	__ide_dma_on		-	Enable DMA on a device *	@drive: drive to enable DMA on * *	Enable IDE DMA for a device on this IDE controller. */ int __ide_dma_on (ide_drive_t *drive){	drive->using_dma = 1;	ide_toggle_bounce(drive, 1);	return HWIF(drive)->ide_dma_host_on(drive);}EXPORT_SYMBOL(__ide_dma_on);/** *	__ide_dma_check		-	check DMA setup *	@drive: drive to check * *	Don't use - due for extermination */ int __ide_dma_check (ide_drive_t *drive){	return config_drive_for_dma(drive);}EXPORT_SYMBOL(__ide_dma_check);int __ide_dma_read (ide_drive_t *drive /*, struct request *rq */){	ide_hwif_t *hwif	= HWIF(drive);	struct request *rq	= HWGROUP(drive)->rq;//	ide_task_t *args	= rq->special;	unsigned int reading	= 1 << 3;	unsigned int count	= 0;	u8 dma_stat = 0, lba48	= (drive->addressing == 1) ? 1 : 0;	task_ioreg_t command	= WIN_NOP;	if (!(count = ide_build_dmatable(drive, rq, PCI_DMA_FROMDEVICE)))		/* try PIO instead of DMA */		return 1;	/* PRD table */	hwif->OUTL(hwif->dmatable_dma, hwif->dma_prdtable);	/* specify r/w */	hwif->OUTB(reading, hwif->dma_command);	/* read dma_status for INTR & ERROR flags */	dma_stat = hwif->INB(hwif->dma_status);	/* clear INTR & ERROR flags */	hwif->OUTB(dma_stat|6, hwif->dma_status);	drive->waiting_for_dma = 1;	if (drive->media != ide_disk)		return 0;	/*	 * FIX ME to use only ACB ide_task_t args Struct	 */#if 0	{		ide_task_t *args = rq->special;		command = args->tfRegister[IDE_COMMAND_OFFSET];	}#else	command = (lba48) ? WIN_READDMA_EXT : WIN_READDMA;	if (rq->cmd == IDE_DRIVE_TASKFILE) {		ide_task_t *args = rq->special;		command = args->tfRegister[IDE_COMMAND_OFFSET];	}#endif	/* issue cmd to drive */	ide_execute_command(drive, command, &ide_dma_intr, 2*WAIT_CMD, dma_timer_expiry);	return HWIF(drive)->ide_dma_count(drive);}EXPORT_SYMBOL(__ide_dma_read);int __ide_dma_write (ide_drive_t *drive /*, struct request *rq */){	ide_hwif_t *hwif	= HWIF(drive);	struct request *rq	= HWGROUP(drive)->rq;//	ide_task_t *args	= rq->special;	unsigned int reading	= 0;	unsigned int count	= 0;	u8 dma_stat = 0, lba48	= (drive->addressing == 1) ? 1 : 0;	task_ioreg_t command	= WIN_NOP;	if (!(count = ide_build_dmatable(drive, rq, PCI_DMA_TODEVICE)))		/* try PIO instead of DMA */		return 1;	/* PRD table */	hwif->OUTL(hwif->dmatable_dma, hwif->dma_prdtable);	/* specify r/w */	hwif->OUTB(reading, hwif->dma_command);	/* read dma_status for INTR & ERROR flags */	dma_stat = hwif->INB(hwif->dma_status);	/* clear INTR & ERROR flags */	hwif->OUTB(dma_stat|6, hwif->dma_status);	drive->waiting_for_dma = 1;	if (drive->media != ide_disk)		return 0;	/*	 * FIX ME to use only ACB ide_task_t args Struct	 */#if 0	{		ide_task_t *args = rq->special;		command = args->tfRegister[IDE_COMMAND_OFFSET];	}#else	command = (lba48) ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;	if (rq->cmd == IDE_DRIVE_TASKFILE) {		ide_task_t *args = rq->special;		command = args->tfRegister[IDE_COMMAND_OFFSET];	}#endif	/* issue cmd to drive */	ide_execute_command(drive, command, &ide_dma_intr, 2*WAIT_CMD, dma_timer_expiry);	return HWIF(drive)->ide_dma_count(drive);}EXPORT_SYMBOL(__ide_dma_write);int __ide_dma_begin (ide_drive_t *drive){	ide_hwif_t *hwif	= HWIF(drive);	u8 dma_cmd		= hwif->INB(hwif->dma_command);	/* Note that this is done *after* the cmd has	 * been issued to the drive, as per the BM-IDE spec.	 * The Promise Ultra33 doesn't work correctly when	 * we do this part before issuing the drive cmd.	 */	/* start DMA */	hwif->OUTB(dma_cmd|1, hwif->dma_command);	return 0;}EXPORT_SYMBOL(__ide_dma_begin);/* returns 1 on error, 0 otherwise */int __ide_dma_end (ide_drive_t *drive){	ide_hwif_t *hwif	= HWIF(drive);	u8 dma_stat = 0, dma_cmd = 0;	drive->waiting_for_dma = 0;	/* get dma_command mode */	dma_cmd = hwif->INB(hwif->dma_command);	/* stop DMA */	hwif->OUTB(dma_cmd&~1, hwif->dma_command);	/* get DMA status */	dma_stat = hwif->INB(hwif->dma_status);	/* clear the INTR & ERROR bits */	hwif->OUTB(dma_stat|6, hwif->dma_status);	/* purge DMA mappings */	ide_destroy_dmatable(drive);	/* verify good DMA status */	return (dma_stat & 7) != 4 ? (0x10 | dma_stat) : 0;}EXPORT_SYMBOL(__ide_dma_end);/* returns 1 if dma irq issued, 0 otherwise */int __ide_dma_test_irq (ide_drive_t *drive){	ide_hwif_t *hwif	= HWIF(drive);	u8 dma_stat		= hwif->INB(hwif->dma_status);#if 0  /* do not set unless you know what you are doing */	if (dma_stat & 4) {		u8 stat = hwif->INB(IDE_STATUS_REG);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -