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 + -
显示快捷键?