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

📄 ide-ep93xx.c

📁 ep9315平台下硬盘驱动的源码
💻 C
📖 第 1 页 / 共 4 页
字号:
/***************************************************************************** * * drivers/ide/ide-ep93xx.c * *  Copyright (c) 2003 Cirrus Logic, Inc. * * Some code based in whole or in part on: * *      linux/drivers/ide/ide-dma.c		Version 4.13	May 21, 2003 * *      Copyright (c) 1999-2000	Andre Hedrick <andre@linux-ide.org> *      May be copied or modified under the terms of the GNU General Public License * *      Portions Copyright Red Hat 2003 * *      Special Thanks to Mark for his Six years of work. * *      Copyright (c) 1995-1998  Mark Lord *      May be copied or modified under the terms of the GNU General Public License * * * Some code taken from the PowerMac implentation * *      Copyright (C) 1998-2001 Paul Mackerras & Ben. Herrenschmidt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA * * *************************************************************************** * * Cirrus Logic's EP93XX architecture specific ide driver. This driver * supports the following ide transfer modes: * *     PIO mode 4 *     UDMA modes 0 - 2 * * This driver provides workarounds for the following hardware bugs: * * Write bug #1: If DDMARDYn is deasserted at the appropriate time (which is *               within the ATA spec. and is therefore valid), 32-bits of data *               to be written to the device is lost.  Since the upper 16-bits *               of that word is written to the IDE data bus, but never strobed *               to the device, this will also result in a CRC error (the *               EP93xx CRC generator will see the 16-bit value, but the device *               CRC generator will not). * *               This can be detected in two ways.  The first is the fact that *               the DMA controller will complete the transfer while the device *               is still requesting data.  This is not guaranteed to occur due *               to the second write bug; the data from one incident of this *               write bug will be offset by the data from two incidents of the *               second write bug (see below).  The other is to look for CRC *               errors.  If the device wants more data, the DMA controller is *               given more data 32-bits at a time until the device is happy. * * Write bug #2: If a data out burst is terminated after an odd number of *               16-bit words have been written to the device, the last 16-bit *               word of the burst is repeated as the first 16-bit word of the *               subsequent burst.  This also results in the last 16-bit word *               of data being "lost" since it is never written to the device. *               No CRC error occurs since the same data is seen by both the *               EP93xx CRC generator and the device CRC generator.  If this *               bug occurs only once during a single request, and the first *               write bug does not occur during that request, then this is an *               undetectable situation since the final "extra" 16-bit word is *               transferred to the device, which simply ignores it. * *               This can be detected by seeing that the device no longs wants *               data (it has deasserted DMARQ and has asserted INTRQ) but the *               DMA controller has more data to transfer. * *               A single instance of this bug in a request can be detected by *               reading back the data from the drive after each write.  This *               is obviously not acceptable from a performance point of view. *               Fortunately, this bug only appears to be triggered by old, *               small drives. * * Read bug #1:  If a data in burst is terminated after an odd number of *               16-bit words have been read from the device, the last 16-bit *               word of the burst is lost.  Like write bug #2, no CRC error *               occurs.  Note that this bug always occurs in pairs.  If it *               actually happens one time, there will always be an odd number *               of 16-bit words left to be read from the device.  Therefore, *               it will happen again either in the middle of the remaining *               data (leaving an even number of words remaining), or at the *               end of the request. * *               This can be detected by seeing that the device has no more *               data (it has deasserted DMARQ and has asserted INTRQ) but the *               DMA controller still expects more data to transfer. * * Once any of these bugs is detected, the request is retried.  If the request * can not be satisfied after RETRIES_PER_TRANSFER attempts, it is done in PIO * mode.  If FAILURES_BEFORE_BACKOFF requests in a row can not be completed * successfully (including retries), the transfer mode is backed down (i.e. * moving to UDMA1 instead of UDMA2).  Lower transfer modes are less likely * to be affected by these bugs, so a slower data transfer rate with less * retries will be better than a higher data transfer rate with more retries. * * The transfer mode and retries are managed independently for the two devices * on the IDE bus.  So, if the master device doesn't excite these bugs, but the * slave device does, the transfer rate of the master device isn't affected by * the slow down/retries on the slave device. * ****************************************************************************/#include <linux/ide.h>#include <linux/delay.h>#include <linux/proc_fs.h>#include <asm/io.h>#include <asm/ide.h>#include <asm/irq.h>#include <asm/arch/ide.h>#include <asm/arch/dma.h>#include <asm/hardware.h>/***************************************************************************** * * Debugging macros * ****************************************************************************/#undef DEBUG//#define DEBUG 1#ifdef DEBUG#define DPRINTK( fmt, arg... )  printk( fmt, ##arg )#else#define DPRINTK( fmt, arg... )#endif/***************************************************************************** * * Functions and macros for handling dma transfers. * ****************************************************************************/#define RETRIES_PER_TRANSFER			5#define FAILURES_BEFORE_BACKOFF			50/***************************************************************************** * * Global to keep track of the number of entries in the dma buffer * table for each transfer. * ****************************************************************************/static int g_prd_count;static unsigned int g_prd_total;static unsigned int g_prd_returned;static unsigned int *g_dma_table_base;/***************************************************************************** * * Global to set during the DMA callback function to indicate that a DMA * error occurred (i.e. the DMA completed while the device was still * requesting). * ****************************************************************************/static unsigned int g_bad = 0;/***************************************************************************** * * A garbage word that is used to satify additional DMA requests from the * device. * ****************************************************************************/static unsigned long g_garbage;/***************************************************************************** * * The particulars of the most recent command that was executed. * ****************************************************************************/static unsigned long g_cmd = 0;static ide_drive_t *g_drive = NULL;static unsigned long g_sector = 0;static unsigned long g_nr_sectors = 0;static unsigned long g_cur_retries = 0;/***************************************************************************** * * The count of consective DMA request errors.  For each array, the first * entry is for hda reads, the second for hda writes, the third for hdb reads, * and the forth for hdb writes. * ****************************************************************************/static unsigned long g_errors[4] = { 0, 0, 0, 0 };/***************************************************************************** * * Some statistics that are gathered about the transfers.  For each array, the * first entry is for hda reads, the second for hda writes, the third for hdb * reads, and the fourth for hdb writes. * ****************************************************************************/static unsigned long g_sectors[4] = { 0, 0, 0, 0 };static unsigned long g_xfers[4] = { 0, 0, 0, 0 };static unsigned long g_retries[4] = { 0, 0, 0, 0 };static unsigned long g_max_retries[4] = { 0, 0, 0, 0 };/***************************************************************************** * * Forward declarations. * ****************************************************************************/static int ep93xx_ide_dma_on(ide_drive_t *drive);static int ep93xx_ide_dma_off(ide_drive_t *drive);static int ep93xx_ide_dma_begin(ide_drive_t *drive);static int ep93xx_ide_dma_end(ide_drive_t *drive);static int ep93xx_ide_dma_host_on(ide_drive_t *drive);/***************************************************************************** * * The following is directly from ide-dma.c. * ****************************************************************************/struct drive_list_entry{	const char * id_model;	const char * id_firmware;};static const structdrive_list_entry drive_blacklist [] ={	{ "WDC AC11000H",			"ALL"		},	{ "WDC AC22100H",			"ALL"		},	{ "WDC AC32500H",			"ALL"		},	{ "WDC AC33100H",			"ALL"		},	{ "WDC AC31600H",			"ALL"		},	{ "WDC AC32100H",			"24.09P07"	},	{ "WDC AC23200L",			"21.10N21"	},	{ "Compaq CRD-8241B",			"ALL"		},	{ "CRD-8400B",				"ALL"		},	{ "CRD-8480B",				"ALL"		},	{ "CRD-8480C",				"ALL"		},	{ "CRD-8482B",				"ALL"		},	{ "CRD-84",				"ALL"		},	{ "SanDisk SDP3B",			"ALL"		},	{ "SanDisk SDP3B-64",			"ALL"		},	{ "SANYO CD-ROM CRD",			"ALL"		},	{ "HITACHI CDR-8",			"ALL"		},	{ "HITACHI CDR-8335",			"ALL"		},	{ "HITACHI CDR-8435",			"ALL"		},	{ "Toshiba CD-ROM XM-6202B",		"ALL"		},	{ "CD-532E-A",				"ALL"		},	{ "E-IDE CD-ROM CR-840",		"ALL"		},	{ "CD-ROM Drive/F5A",			"ALL"		},	{ "RICOH CD-R/RW MP7083A",		"ALL"		},	{ "WPI CDD-820",			"ALL"		},	{ "SAMSUNG CD-ROM SC-148C",		"ALL"		},	{ "SAMSUNG CD-ROM SC-148F",		"ALL"		},	{ "SAMSUNG CD-ROM SC",			"ALL"		},	{ "SanDisk SDP3B-64",			"ALL"		},	{ "SAMSUNG CD-ROM SN-124",		"ALL"		},	{ "PLEXTOR CD-R PX-W8432T",		"ALL"		},	{ "ATAPI CD-ROM DRIVE 40X MAXIMUM",	"ALL"		},	{ "_NEC DV5800A",			"ALL"		},	{ NULL,					NULL		}};/***************************************************************************** * *	This is directly from ide-dma.c * *  in_drive_list	-	look for drive in black/white list *	@id: drive identifier *	@drive_table: list to inspect * *	Look for a drive in the blacklist and the whitelist tables *	Returns 1 if the drive is found in the table. * ****************************************************************************/static intin_drive_list(struct hd_driveid *id,              const struct drive_list_entry *drive_table){	for ( ; drive_table->id_model ; drive_table++)		if ((!strcmp(drive_table->id_model, id->model)) &&		    ((!strstr(drive_table->id_firmware, id->fw_rev)) ||		     (!strcmp(drive_table->id_firmware, "ALL"))))			return 1;	return 0;}/***************************************************************************** * * Return some statistics that are gathered about the operation of the IDE * driver. * ****************************************************************************/#ifdef CONFIG_PROC_FSstatic intep93xx_get_info(char *buffer, char **addr, off_t offset, int count){	char *p = buffer;	p += sprintf(p, "               sectors    requests     retries"			                 "         max\n");	p += sprintf(p, "hda read :  %10ld  %10ld  %10ld  %10ld\n",		     g_sectors[0], g_xfers[0], g_retries[0], g_max_retries[0]);	p += sprintf(p, "hda write:  %10ld  %10ld  %10ld  %10ld\n",		     g_sectors[1], g_xfers[1], g_retries[1], g_max_retries[1]);	p += sprintf(p, "hdb read :  %10ld  %10ld  %10ld  %10ld\n",		     g_sectors[2], g_xfers[2], g_retries[2], g_max_retries[2]);	p += sprintf(p, "hdb write:  %10ld  %10ld  %10ld  %10ld\n",		     g_sectors[3], g_xfers[3], g_retries[3], g_max_retries[3]);	return p - buffer;}#endif/***************************************************************************** * * ep93xx_ide_dma_intr() is the handler for disk read/write DMA interrupts * ****************************************************************************/static ide_startstop_tep93xx_ide_dma_intr (ide_drive_t *drive){	struct request *rq = HWGROUP(drive)->rq;	byte stat, dma_stat;	int i;	DPRINTK("%s: ep93xx_ide_dma_intr\n", drive->name);	/*	 * Disable the DMA for this transfer and cleanup.	 */	dma_stat = HWIF(drive)->ide_dma_end(drive);	/*	 * Get status from the ide device.	 */	stat = HWIF(drive)->INB(IDE_STATUS_REG);	/*	 * Retry the transfer if a DMA error occurred.	 */	if(dma_stat)		return ide_stopped;	/*	 * See if the drive returned an error.	 */	if (OK_STAT(stat,DRIVE_READY,drive->bad_wstat|DRQ_STAT)) {		/*		 * Complete the request.		 */		for (i = rq->nr_sectors; i > 0;) {			i -= rq->current_nr_sectors;			DRIVER(drive)->end_request(drive, 1);		}		/*		 * The transfer has been completed.		 */		return ide_stopped;	}	/*	 * Print out an error.	 */	return DRIVER(drive)->error(drive, __FUNCTION__, stat);}/**************************************************************************** * * Map a set of buffers described by scatterlist in streaming * mode for DMA.  This is the scather-gather version of the * above pci_map_single interface.  Here the scatter gather list * elements are each tagged with the appropriate dma address * and length.  They are obtained via sg_dma_{address,length}(SG). * * NOTE: An implementation may be able to use a smaller number of *       DMA address/length pairs than there are SG table elements. *       (for example via virtual mapping capabilities) *       The routine returns the number of addr/length pairs actually *       used, at most nents. * * Device ownership issues as mentioned above for pci_map_single are * the same here. * ****************************************************************************/static inline intep93xx_map_sg(struct scatterlist *sg, unsigned int entries,              unsigned int direction){	unsigned int loop;	for (loop = 0; loop < entries; loop++, sg++) {		consistent_sync(sg->address, sg->length, direction);		sg->dma_address = virt_to_bus(sg->address);	}	return entries;}/***************************************************************************** * * ide_build_sglist() * * Builds a table of buffers to be used by the dma.  Each buffer consists * of a region of memory which is contiguous in virtual memory. * ****************************************************************************/static intide_build_sglist(ide_hwif_t *hwif, struct request *rq){	struct buffer_head *buf_head;	struct scatterlist *sg = hwif->sg_table;	int nents = 0;	DPRINTK("%s: ide_build_sglist: sg_table 0x%08lx\n", hwif->name,		(unsigned long)hwif->sg_table);	if (hwif->sg_dma_active)		BUG();	/*	 * Set up the direction of the command	 */	if (rq->cmd == READ)		hwif->sg_dma_direction = PCI_DMA_FROMDEVICE;	else		hwif->sg_dma_direction = PCI_DMA_TODEVICE;	/*	 * Get a pointer to the buffer head.	 */	buf_head = rq->bh;	do {		unsigned char *virt_addr = buf_head->b_data;		unsigned int size = buf_head->b_size;		if (nents >= PRD_ENTRIES)			return 0;		while ((buf_head = buf_head->b_reqnext) != NULL) {			if ((virt_addr + size) !=			    (unsigned char *)buf_head->b_data)				break;			size += buf_head->b_size;		}		memset(&sg[nents], 0, sizeof(*sg));		sg[nents].address = virt_addr;		sg[nents].length = size;		nents++;	} while (buf_head != NULL);	/*	 * This call to map_sg will return the number of entries	 * for which DMAable memory could be mapped.	 */	return ep93xx_map_sg(sg, nents, hwif->sg_dma_direction);}/***************************************************************************** * * ide_build_dmatable() prepares a dma request. * Returns 0 if all went okay, returns 1 otherwise. * ****************************************************************************/static intide_build_dmatable(ide_drive_t *drive){	unsigned int *table = HWIF(drive)->dmatable_cpu = g_dma_table_base;	unsigned int count = 0;	int i;	struct scatterlist *sg;	DPRINTK("%s: ide_build_dmatable\n", drive->name);	HWIF(drive)->sg_nents = i = ide_build_sglist(HWIF(drive),						     HWGROUP(drive)->rq);	if (!i)		return 0;	sg = HWIF(drive)->sg_table;	while (i && sg_dma_len(sg)) {		u32 cur_addr;		u32 cur_len;		cur_addr = sg_dma_address(sg);		cur_len = sg_dma_len(sg);		/*		 * Fill in the dma table, without crossing any 64kB boundaries.		 * Most hardware requires 16-bit alignment of all blocks,		 * but the trm290 requires 32-bit alignment.		 */		while (cur_len) {			if (count++ >= PRD_ENTRIES) {				printk("%s: DMA table too small\n", drive->name);				goto use_pio_instead;			} else {				u32 xcount, bcount = 0x10000 - (cur_addr & 0xffff);				if (bcount > cur_len)					bcount = cur_len;

⌨️ 快捷键说明

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