ide-ep93xx.c

来自「一个2.4.21版本的嵌入式linux内核」· C语言 代码 · 共 2,386 行 · 第 1/5 页

C
2,386
字号
/*****************************************************************************
 *
 * 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>

/*
 *  bit definitions for drive->ep93xx_if_test debugging flag
 */
#define TEST_FOR_READ           0x1
#define TEST_FOR_WRITE          0x2
#define ENABLE_READ_WATCHES     0x4
#define ENABLE_WRITE_WATCHES    0x8
#define READ_AFTER_WRITE        0x10
#define SEQUENTIAL_WRITE        0x20
#define INIT_READ_FIFO          0x40
#define INIT_WRITE_FIFO         0x80
#define HALT_ON_CRC_ERROR       0x100
//statistics
volatile int udma_crc_read_errors=0;
volatile int udma_crc_write_errors=0;


/*****************************************************************************
 *
 * 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

/*****************************************************************************
 * Switch for removing possibility of PIO address glitching during
 * mode switch between PIO and UDMA/UDMA and back.
 * Such glitching could cause spurious writes to devices.
 ****************************************************************************/
#define MODE_SWITCH_FIX 1

/*****************************************************************************
 *
 * 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 struct
drive_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 int
in_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_FS
static int
ep93xx_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_t
ep93xx_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 int
ep93xx_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 int
ide_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));

⌨️ 快捷键说明

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