diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1999-06-17 13:25:08 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1999-06-17 13:25:08 +0000 |
commit | 59223edaa18759982db0a8aced0e77457d10c68e (patch) | |
tree | 89354903b01fa0a447bffeefe00df3044495db2e /drivers/block/ide-dma.c | |
parent | db7d4daea91e105e3859cf461d7e53b9b77454b2 (diff) |
Merge with Linux 2.3.6. Sorry, this isn't tested on silicon, I don't
have a MIPS box at hand.
Diffstat (limited to 'drivers/block/ide-dma.c')
-rw-r--r-- | drivers/block/ide-dma.c | 153 |
1 files changed, 135 insertions, 18 deletions
diff --git a/drivers/block/ide-dma.c b/drivers/block/ide-dma.c index a3ac37238..9f26ea6bc 100644 --- a/drivers/block/ide-dma.c +++ b/drivers/block/ide-dma.c @@ -1,5 +1,12 @@ /* - * linux/drivers/block/ide-dma.c Version 4.08 December 31, 1997 + * linux/drivers/block/ide-dma.c Version 4.09 April 23, 1999 + * + * Copyright (c) 1999 Andre Hedrick + * May be copied or modified under the terms of the GNU General Public License + */ + +/* + * 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 @@ -24,7 +31,7 @@ * * Use "hdparm -i" to view modes supported by a given drive. * - * The hdparm-2.4 (or later) utility can be used for manually enabling/disabling + * The hdparm-3.5 (or later) utility can be used for manually enabling/disabling * DMA support, but must be (re-)compiled against this kernel version or later. * * To enable DMA, use "hdparm -d1 /dev/hd?" on a per-drive basis after booting. @@ -79,11 +86,51 @@ #include <linux/interrupt.h> #include <linux/pci.h> #include <linux/init.h> +#include <linux/ide.h> #include <asm/io.h> #include <asm/irq.h> -#include "ide.h" +#define IDE_DMA_NEW_LISTINGS 0 + +#if IDE_DMA_NEW_LISTINGS +struct drive_list_entry { + char * id_model; + char * id_firmware; +}; + +struct drive_list_entry drive_whitelist [] = { + + { "Micropolis 2112A" , "ALL" }, + { "CONNER CTMA 4000" , "ALL" }, + { "CONNER CTT8000-A" , "ALL" }, + { "ST34342A" , "ALL" }, + { 0 , 0 } +}; + +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" }, + { 0 , 0 } + +}; + +int in_drive_list(struct hd_driveid *id, 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; +} +#else /* !IDE_DMA_NEW_LISTINGS */ /* * good_dma_drives() lists the model names (from "hdparm -i") @@ -109,11 +156,14 @@ const char *good_dma_drives[] = {"Micropolis 2112A", */ const char *bad_dma_drives[] = {"WDC AC11000H", "WDC AC22100H", + "WDC AC32100H", "WDC AC32500H", "WDC AC33100H", "WDC AC31600H", NULL}; +#endif /* IDE_DMA_NEW_LISTINGS */ + /* * Our Physical Region Descriptor (PRD) table should be large enough * to handle the biggest I/O request we are likely to see. Since requests @@ -164,11 +214,12 @@ void ide_dma_intr (ide_drive_t *drive) * Returns 0 if all went okay, returns 1 otherwise. * May also be invoked from trm290.c */ -int ide_build_dmatable (ide_drive_t *drive) +int ide_build_dmatable (ide_drive_t *drive, ide_dma_action_t func) { struct request *rq = HWGROUP(drive)->rq; struct buffer_head *bh = rq->bh; unsigned int size, addr, *table = (unsigned int *)HWIF(drive)->dmatable; + unsigned char *virt_addr; #ifdef CONFIG_BLK_DEV_TRM290 unsigned int is_trm290_chipset = (HWIF(drive)->chipset == ide_trm290); #else @@ -185,11 +236,13 @@ int ide_build_dmatable (ide_drive_t *drive) * than two possibly non-adjacent physical 4kB pages. */ if (bh == NULL) { /* paging requests have (rq->bh == NULL) */ - addr = virt_to_bus (rq->buffer); + virt_addr = rq->buffer; + addr = virt_to_bus (virt_addr); size = rq->nr_sectors << 9; } else { /* group sequential buffers into one large buffer */ - addr = virt_to_bus (bh->b_data); + virt_addr = bh->b_data; + addr = virt_to_bus (virt_addr); size = bh->b_size; while ((bh = bh->b_reqnext) != NULL) { if ((addr + size) != virt_to_bus (bh->b_data)) @@ -206,6 +259,20 @@ int ide_build_dmatable (ide_drive_t *drive) printk("%s: misaligned DMA buffer\n", drive->name); return 0; } + + /* + * Some CPUs without cache snooping need to invalidate/write + * back their caches before DMA transfers to guarantee correct + * data. -- rmk + */ + if (size) { + if (func == ide_dma_read) { + dma_cache_inv((unsigned int)virt_addr, size); + } else { + dma_cache_wback((unsigned int)virt_addr, size); + } + } + while (size) { if (++count >= PRD_ENTRIES) { printk("%s: DMA table too small\n", drive->name); @@ -224,10 +291,17 @@ int ide_build_dmatable (ide_drive_t *drive) } } } while (bh != NULL); - if (!count) + if (!count) { printk("%s: empty DMA table?\n", drive->name); - else if (!is_trm290_chipset) - *--table |= cpu_to_le32(0x80000000); /* set End-Of-Table (EOT) bit */ + } else { + if (!is_trm290_chipset) + *--table |= cpu_to_le32(0x80000000); /* set End-Of-Table (EOT) bit */ + /* + * Some CPUs need to flush the DMA table to physical RAM + * before DMA can start. -- rmk + */ + dma_cache_wback((unsigned long)HWIF(drive)->dmatable, count * sizeof(unsigned int) * 2); + } return count; } @@ -238,9 +312,22 @@ int ide_build_dmatable (ide_drive_t *drive) */ int check_drive_lists (ide_drive_t *drive, int good_bad) { - const char **list; struct hd_driveid *id = drive->id; +#if IDE_DMA_NEW_LISTINGS + + if (good_bad) { + return in_drive_list(id, drive_whitelist); + } else { + int blacklist = in_drive_list(id, drive_blacklist); + if (blacklist) + printk("%s: Disabling (U)DMA for %s\n", drive->name, id->model); + return(blacklist); + } +#else /* !IDE_DMA_NEW_LISTINGS */ + + const char **list; + if (good_bad) { /* Consult the list of known "good" drives */ list = good_dma_drives; @@ -259,6 +346,7 @@ int check_drive_lists (ide_drive_t *drive, int good_bad) } } } +#endif /* IDE_DMA_NEW_LISTINGS */ return 0; } @@ -269,18 +357,24 @@ static int config_drive_for_dma (ide_drive_t *drive) if (id && (id->capability & 1) && hwif->autodma) { /* Consult the list of known "bad" drives */ - if (check_drive_lists(drive, BAD_DMA_DRIVE)) + if (ide_dmaproc(ide_dma_bad_drive, drive)) return hwif->dmaproc(ide_dma_off, drive); +#if 0 + /* Enable DMA on any drive that has UltraDMA (mode 3/4) enabled */ + if ((id->field_valid & 4) && (id->word93 & 0x2000)) + if ((id->dma_ultra & (id->dma_ultra >> 11) & 3)) + return hwif->dmaproc(ide_dma_on, drive); +#endif /* Enable DMA on any drive that has UltraDMA (mode 0/1/2) enabled */ if (id->field_valid & 4) /* UltraDMA */ - if ((id->dma_ultra & (id->dma_ultra >> 8) & 7)) + if ((id->dma_ultra & (id->dma_ultra >> 8) & 7)) return hwif->dmaproc(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->dmaproc(ide_dma_on, drive); /* Consult the list of known "good" drives */ - if (check_drive_lists(drive, GOOD_DMA_DRIVE)) + if (ide_dmaproc(ide_dma_good_drive, drive)) return hwif->dmaproc(ide_dma_on, drive); } return hwif->dmaproc(ide_dma_off_quietly, drive); @@ -321,7 +415,7 @@ int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive) case ide_dma_read: reading = 1 << 3; case ide_dma_write: - if (!(count = ide_build_dmatable(drive))) + if (!(count = ide_build_dmatable(drive, func))) return 1; /* try PIO instead of DMA */ outl(virt_to_bus(hwif->dmatable), dma_base + 4); /* PRD table */ outb(reading, dma_base); /* specify r/w */ @@ -348,6 +442,9 @@ int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive) case ide_dma_test_irq: /* returns 1 if dma irq issued, 0 otherwise */ dma_stat = inb(dma_base+2); return (dma_stat & 4) == 4; /* return 1 if INTR asserted */ + case ide_dma_bad_drive: + case ide_dma_good_drive: + return check_drive_lists(drive, (func == ide_dma_good_drive)); default: printk("ide_dmaproc: unsupported func: %d\n", func); return 1; @@ -425,7 +522,7 @@ __initfunc(unsigned long ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, c } else { dma_base = dev->base_address[4] & PCI_BASE_ADDRESS_IO_MASK; if (!dma_base || dma_base == PCI_BASE_ADDRESS_IO_MASK) { - printk("%s: dma_base is invalid (0x%04lx, BIOS problem), please report to <mj@ucw.cz>\n", name, dma_base); + printk("%s: dma_base is invalid (0x%04lx)\n", name, dma_base); dma_base = 0; } } @@ -434,9 +531,29 @@ __initfunc(unsigned long ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, c request_region(dma_base+16, extra, name); dma_base += hwif->channel ? 8 : 0; hwif->dma_extra = extra; - if (inb(dma_base+2) & 0x80) { - printk("%s: simplex device: DMA disabled\n", name); - dma_base = 0; + + switch(dev->device) { + case PCI_DEVICE_ID_CMD_643: + /* + * Lets attempt to use the same Ali tricks + * to fix CMD643..... + */ + case PCI_DEVICE_ID_AL_M5219: + case PCI_DEVICE_ID_AL_M5229: + outb(inb(dma_base+2) & 0x60, dma_base+2); + /* + * Ali 15x3 chipsets know as ALI IV and V report + * this as simplex, skip this test for them. + */ + if (inb(dma_base+2) & 0x80) { + printk("%s: simplex device: DMA forced\n", name); + } + break; + default: + if (inb(dma_base+2) & 0x80) { + printk("%s: simplex device: DMA disabled\n", name); + dma_base = 0; + } } } return dma_base; |