summaryrefslogtreecommitdiff
path: root/sys/dev/ata/ata-dma.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/ata/ata-dma.c')
-rw-r--r--sys/dev/ata/ata-dma.c164
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;