diff options
Diffstat (limited to 'sys/dev/ata/ata-dma.c')
| -rw-r--r-- | sys/dev/ata/ata-dma.c | 164 |
1 files changed, 116 insertions, 48 deletions
diff --git a/sys/dev/ata/ata-dma.c b/sys/dev/ata/ata-dma.c index 838495d28080..763017d159a0 100644 --- a/sys/dev/ata/ata-dma.c +++ b/sys/dev/ata/ata-dma.c @@ -48,8 +48,9 @@ #if NPCI > 0 /* prototypes */ -static void promise_timing(struct ata_softc *, int32_t, int32_t); -static void hpt_timing(struct ata_softc *, int32_t, int32_t); +static void cyrix_timing(struct ata_softc *, int, int); +static void promise_timing(struct ata_softc *, int, int); +static void hpt_timing(struct ata_softc *, int, int); /* misc defines */ #ifdef __alpha__ @@ -57,9 +58,25 @@ static void hpt_timing(struct ata_softc *, int32_t, int32_t); #define vtophys(va) alpha_XXX_dmamap((vm_offset_t)va) #endif +void * +ata_dmaalloc(struct ata_softc *scp, int device) +{ + void *dmatab; + + if ((dmatab = malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT))) { + if (((uintptr_t)dmatab >> PAGE_SHIFT) ^ + (((uintptr_t)dmatab + PAGE_SIZE - 1) >> PAGE_SHIFT)) { + ata_printf(scp, device, "dmatab crosses page boundary, no DMA\n"); + free(dmatab, M_DEVBUF); + dmatab = NULL; + } + } + return dmatab; +} + void -ata_dmainit(struct ata_softc *scp, int32_t device, - int32_t apiomode, int32_t wdmamode, int32_t udmamode) +ata_dmainit(struct ata_softc *scp, int device, + int apiomode, int wdmamode, int udmamode) { device_t parent = device_get_parent(scp->dev); int devno = (scp->unit << 1) + ATA_DEV(device); @@ -81,19 +98,9 @@ ata_dmainit(struct ata_softc *scp, int32_t device, } } - if (!scp->dmatab[ATA_DEV(device)]) { - void *dmatab; + /* DMA engine address alignment is usually 1 word (2 bytes) */ + scp->alignment = 0x1; - if (!(dmatab = malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT))) - return; - if (((uintptr_t)dmatab >> PAGE_SHIFT) ^ - (((uintptr_t)dmatab + PAGE_SIZE - 1) >> PAGE_SHIFT)) { - ata_printf(scp, device, "dmatab crosses page boundary, no DMA\n"); - free(dmatab, M_DEVBUF); - return; - } - scp->dmatab[ATA_DEV(device)] = dmatab; - } if (udmamode > 2 && !ATA_PARAM(scp, device)->cblid) { ata_printf(scp, device, "DMA limited to UDMA33, non-ATA66 compliant cable\n"); @@ -285,7 +292,7 @@ ata_dmainit(struct ata_softc *scp, int32_t device, "Aladdin: two atapi devices on this channel, no DMA\n"); break; } - if (udmamode >= 2) { + if (udmamode >= 2 && pci_read_config(parent, 0x08, 1) > 0x20) { int32_t word54 = pci_read_config(parent, 0x54, 4); error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, @@ -472,15 +479,54 @@ via_82c586: /* we could set PIO mode timings, but we assume the BIOS did that */ break; - case 0x4d33105a: /* Promise Ultra33 / FastTrak33 controllers */ - case 0x4d38105a: /* Promise Ultra66 / FastTrak66 controllers */ - case 0x4d30105a: /* Promise Ultra100 / FastTrak100 controllers */ + case 0x01021078: + scp->alignment = 0xf; /* DMA engine requires 16 byte alignment */ + if (udmamode >= 2) { + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + ATA_UDMA2, ATA_C_F_SETXFER, ATA_WAIT_READY); + if (bootverbose) + ata_printf(scp, device, "%s setting UDMA2 on Cyrix chip\n", + (error) ? "failed" : "success"); + if (!error) { + cyrix_timing(scp, devno, ATA_UDMA2); + scp->mode[ATA_DEV(device)] = ATA_UDMA2; + return; + } + } + if (wdmamode >= 2 && apiomode >= 4) { + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + ATA_WDMA2, ATA_C_F_SETXFER, ATA_WAIT_READY); + if (bootverbose) + ata_printf(scp, device, "%s setting WDMA2 on Cyrix chip\n", + (error) ? "failed" : "success"); + if (!error) { + cyrix_timing(scp, devno, ATA_WDMA2); + scp->mode[ATA_DEV(device)] = ATA_WDMA2; + return; + } + } + error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, + ata_pio2mode(apiomode), ATA_C_F_SETXFER, + ATA_WAIT_READY); + if (bootverbose) + ata_printf(scp, device, "%s setting %s on Cyrix chip\n", + (error) ? "failed" : "success", + ata_mode2str(ata_pio2mode(apiomode))); + cyrix_timing(scp, devno, ata_pio2mode(apiomode)); + scp->mode[ATA_DEV(device)] = ata_pio2mode(apiomode); + return; + + case 0x4d33105a: /* Promise Ultra/FastTrak 33 controllers */ + case 0x4d38105a: /* Promise Ultra/FastTrak 66 controllers */ + case 0x4d30105a: /* Promise Ultra/FastTrak 100 controllers */ + case 0x0d30105a: /* Promise OEM ATA100 controllers */ /* the Promise can only do DMA on ATA disks not on ATAPI devices */ if ((device == ATA_MASTER && scp->devices & ATA_ATAPI_MASTER) || (device == ATA_SLAVE && scp->devices & ATA_ATAPI_SLAVE)) break; - if (udmamode >=5 && scp->chiptype == 0x4d30105a && + if (udmamode >=5 && + (scp->chiptype == 0x4d30105a || scp->chiptype == 0x0d30105a) && !(pci_read_config(parent, 0x50, 2)&(scp->unit ? 1<<11 : 1<<10))) { error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, ATA_UDMA5, ATA_C_F_SETXFER, ATA_WAIT_READY); @@ -494,8 +540,8 @@ via_82c586: return; } } - if (udmamode >=4 && - (scp->chiptype == 0x4d38105a || scp->chiptype == 0x4d30105a) && + if (udmamode >=4 && (scp->chiptype == 0x4d38105a || + scp->chiptype == 0x4d30105a || scp->chiptype == 0x0d30105a) && !(pci_read_config(parent, 0x50, 2)&(scp->unit ? 1<<11 : 1<<10))) { error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, ATA_UDMA4, ATA_C_F_SETXFER, ATA_WAIT_READY); @@ -663,23 +709,23 @@ via_82c586: } } -int32_t -ata_dmasetup(struct ata_softc *scp, int32_t device, - int8_t *data, int32_t count, int32_t flags) +int +ata_dmasetup(struct ata_softc *scp, int device, struct ata_dmaentry *dmatab, + caddr_t data, int32_t count) { - struct ata_dmaentry *dmatab; u_int32_t dma_count, dma_base; int i = 0; - if (((uintptr_t)data & 1) || (count & 1)) + if (((uintptr_t)data & scp->alignment) || (count & scp->alignment)) { + ata_printf(scp, device, "non aligned DMA transfer attempted\n"); return -1; + } if (!count) { ata_printf(scp, device, "zero length DMA transfer attempted\n"); return -1; } - dmatab = scp->dmatab[ATA_DEV(device)]; dma_base = vtophys(data); dma_count = min(count, (PAGE_SIZE - ((uintptr_t)data & PAGE_MASK))); data += dma_count; @@ -700,22 +746,24 @@ ata_dmasetup(struct ata_softc *scp, int32_t device, } dmatab[i].base = dma_base; dmatab[i].count = (dma_count & 0xffff) | ATA_DMA_EOT; - outl(scp->bmaddr + ATA_BMDTP_PORT, vtophys(dmatab)); - outb(scp->bmaddr + ATA_BMCMD_PORT, flags ? ATA_BMCMD_WRITE_READ:0); - outb(scp->bmaddr + ATA_BMSTAT_PORT, (inb(scp->bmaddr + ATA_BMSTAT_PORT) | - (ATA_BMSTAT_INTERRUPT | ATA_BMSTAT_ERROR))); return 0; } void -ata_dmastart(struct ata_softc *scp) +ata_dmastart(struct ata_softc *scp, int device, + struct ata_dmaentry *dmatab, int dir) { scp->flags |= ATA_DMA_ACTIVE; + outl(scp->bmaddr + ATA_BMDTP_PORT, vtophys(dmatab)); + outb(scp->bmaddr + ATA_BMCMD_PORT, dir ? ATA_BMCMD_WRITE_READ : 0); + outb(scp->bmaddr + ATA_BMSTAT_PORT, + (inb(scp->bmaddr + ATA_BMSTAT_PORT) | + (ATA_BMSTAT_INTERRUPT | ATA_BMSTAT_ERROR))); outb(scp->bmaddr + ATA_BMCMD_PORT, inb(scp->bmaddr + ATA_BMCMD_PORT) | ATA_BMCMD_START_STOP); } -int32_t +int ata_dmadone(struct ata_softc *scp) { outb(scp->bmaddr + ATA_BMCMD_PORT, @@ -724,14 +772,33 @@ ata_dmadone(struct ata_softc *scp) return inb(scp->bmaddr + ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK; } -int32_t +int ata_dmastatus(struct ata_softc *scp) { return inb(scp->bmaddr + ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK; } static void -promise_timing(struct ata_softc *scp, int32_t devno, int32_t mode) +cyrix_timing(struct ata_softc *scp, int devno, int mode) +{ + u_int32_t reg20 = 0x0000e132; + u_int32_t reg24 = 0x00017771; + + switch (mode) { + case ATA_PIO0: reg20 = 0x0000e132; break; + case ATA_PIO1: reg20 = 0x00018121; break; + case ATA_PIO2: reg20 = 0x00024020; break; + case ATA_PIO3: reg20 = 0x00032010; break; + case ATA_PIO4: reg20 = 0x00040010; break; + case ATA_WDMA2: reg24 = 0x00002020; break; + case ATA_UDMA2: reg24 = 0x00911030; break; + } + outl(scp->bmaddr + (devno * 8) + 0x20, reg20); + outl(scp->bmaddr + (devno * 8) + 0x24, reg24); +} + +static void +promise_timing(struct ata_softc *scp, int devno, int mode) { u_int32_t timing = 0; struct promise_timing { @@ -756,7 +823,7 @@ promise_timing(struct ata_softc *scp, int32_t devno, int32_t mode) } switch (scp->chiptype) { - case 0x4d33105a: /* Promise 33's */ + case 0x4d33105a: /* Promise Ultra/Fasttrak 33 */ switch (mode) { default: case ATA_PIO0: t->pa = 9; t->pb = 19; t->mb = 7; t->mc = 15; break; @@ -769,8 +836,9 @@ promise_timing(struct ata_softc *scp, int32_t devno, int32_t mode) } break; - case 0x4d38105a: /* Promise 66's */ - case 0x4d30105a: /* Promise 100's */ + case 0x4d38105a: /* Promise Ultra/Fasttrak 66 */ + case 0x4d30105a: /* Promise Ultra/Fasttrak 100 */ + case 0x0d30105a: /* Promise OEM ATA 100 */ switch (mode) { default: case ATA_PIO0: t->pa = 15; t->pb = 31; t->mb = 7; t->mc = 15; break; @@ -789,7 +857,7 @@ promise_timing(struct ata_softc *scp, int32_t devno, int32_t mode) } static void -hpt_timing(struct ata_softc *scp, int32_t devno, int32_t mode) +hpt_timing(struct ata_softc *scp, int devno, int mode) { device_t parent = device_get_parent(scp->dev); u_int32_t timing; @@ -859,14 +927,14 @@ hpt_timing(struct ata_softc *scp, int32_t devno, int32_t mode) #else /* NPCI > 0 */ void -ata_dmainit(struct ata_softc *scp, int32_t device, - int32_t piomode, int32_t wdmamode, int32_t udmamode) +ata_dmainit(struct ata_softc *scp, int device, + int piomode, int wdmamode, int udmamode) { } -int32_t -ata_dmasetup(struct ata_softc *scp, int32_t device, - int8_t *data, int32_t count, int32_t flags) +int +ata_dmasetup(struct ata_softc *scp, int device, + int8_t *data, int32_t count, int flags) { return -1; } @@ -876,13 +944,13 @@ ata_dmastart(struct ata_softc *scp) { } -int32_t +int ata_dmadone(struct ata_softc *scp) { return -1; } -int32_t +int ata_dmastatus(struct ata_softc *scp) { return -1; |
