📄 ide-ep93xx.c
字号:
/***************************************************************************** * * 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 + -