ata-dma.c revision 50477
145095Ssos/*- 245095Ssos * Copyright (c) 1998,1999 S�ren Schmidt 345095Ssos * All rights reserved. 445095Ssos * 545095Ssos * Redistribution and use in source and binary forms, with or without 645095Ssos * modification, are permitted provided that the following conditions 745095Ssos * are met: 845095Ssos * 1. Redistributions of source code must retain the above copyright 945095Ssos * notice, this list of conditions and the following disclaimer, 1045095Ssos * without modification, immediately at the beginning of the file. 1145095Ssos * 2. Redistributions in binary form must reproduce the above copyright 1245095Ssos * notice, this list of conditions and the following disclaimer in the 1345095Ssos * documentation and/or other materials provided with the distribution. 1445095Ssos * 3. The name of the author may not be used to endorse or promote products 1545095Ssos * derived from this software without specific prior written permission. 1645095Ssos * 1745095Ssos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1845095Ssos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1945095Ssos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2045095Ssos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2145095Ssos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2245095Ssos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2345095Ssos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2445095Ssos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2545095Ssos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2645095Ssos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2745095Ssos * 2850477Speter * $FreeBSD: head/sys/dev/ata/ata-dma.c 50477 1999-08-28 01:08:13Z peter $ 2945095Ssos */ 3045095Ssos 3145095Ssos#include "ata.h" 3245150Ssos#include "pci.h" 3345095Ssos#if NATA > 0 3445095Ssos#include <sys/param.h> 3545095Ssos#include <sys/systm.h> 3645095Ssos#include <sys/kernel.h> 3745095Ssos#include <sys/buf.h> 3845095Ssos#include <sys/malloc.h> 3945798Ssos#include <sys/bus.h> 4045095Ssos#include <vm/vm.h> 4145095Ssos#include <vm/pmap.h> 4247272Ssos#if NPCI > 0 4345095Ssos#include <pci/pcivar.h> 4445095Ssos#include <pci/pcireg.h> 4547272Ssos#endif 4645095Ssos#include <dev/ata/ata-all.h> 4745095Ssos 4845720Speter#ifdef __alpha__ 4945720Speter#undef vtophys 5047529Sgallatin#define vtophys(va) alpha_XXX_dmamap((vm_offset_t)va) 5145720Speter#endif 5245720Speter 5345095Ssos/* misc defines */ 5445095Ssos#define MIN(a,b) ((a)>(b)?(b):(a)) 5545095Ssos 5645150Ssos#if NPCI > 0 5745150Ssos 5845095Ssosint32_t 5945095Ssosata_dmainit(struct ata_softc *scp, int32_t device, 6045095Ssos int32_t apiomode, int32_t wdmamode, int32_t udmamode) 6145095Ssos{ 6245095Ssos int32_t type, devno, error; 6345095Ssos void *dmatab; 6445095Ssos 6545095Ssos if (!scp->bmaddr) 6645095Ssos return -1; 6745095Ssos#ifdef ATA_DEBUGDMA 6845095Ssos printf("ata%d: dmainit: ioaddr=0x%x altioaddr=0x%x, bmaddr=0x%x\n", 6945095Ssos scp->lun, scp->ioaddr, scp->altioaddr, scp->bmaddr); 7045095Ssos#endif 7145095Ssos 7245095Ssos if (!(dmatab = malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT))) 7345095Ssos return -1; 7445095Ssos 7545798Ssos if (((uintptr_t)dmatab >> PAGE_SHIFT) ^ 7645798Ssos (((uintptr_t)dmatab + PAGE_SIZE - 1) >> PAGE_SHIFT)) { 7745095Ssos printf("ata_dmainit: dmatab crosses page boundary, no DMA\n"); 7845095Ssos free(dmatab, M_DEVBUF); 7945095Ssos return -1; 8045095Ssos } 8145095Ssos scp->dmatab[device ? 1 : 0] = dmatab; 8245095Ssos 8345798Ssos type = pci_get_devid(scp->dev); 8445095Ssos 8545095Ssos switch(type) { 8645095Ssos 8745095Ssos case 0x71118086: /* Intel PIIX4 */ 8845095Ssos if (udmamode >= 2) { 8945095Ssos int32_t mask48, new48; 9045095Ssos 9147272Ssos printf("ata%d: %s: setting up UDMA2 mode on PIIX4 chip ", 9245095Ssos scp->lun, (device) ? "slave" : "master"); 9345095Ssos error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, 9445095Ssos ATA_UDMA2, ATA_C_FEA_SETXFER, ATA_WAIT_INTR); 9545095Ssos if (error) { 9645095Ssos printf("failed\n"); 9745095Ssos break; 9845095Ssos } 9945095Ssos printf("OK\n"); 10045554Ssos devno = (scp->unit << 1) + (device ? 1 : 0); 10145095Ssos mask48 = (1 << devno) + (3 << (16 + (devno << 2))); 10245095Ssos new48 = (1 << devno) + (2 << (16 + (devno << 2))); 10345798Ssos pci_write_config(scp->dev, 0x48, 10445798Ssos (pci_read_config(scp->dev, 0x48, 4) & 10545798Ssos ~mask48) | new48, 4); 10645095Ssos return 0; 10745095Ssos } 10845095Ssos /* FALLTHROUGH */ 10945095Ssos 11045095Ssos case 0x70108086: /* Intel PIIX3 */ 11145095Ssos if (wdmamode >= 2 && apiomode >= 4) { 11245095Ssos int32_t mask40, new40, mask44, new44; 11345095Ssos 11445095Ssos /* if SITRE not set doit for both channels */ 11545798Ssos if (!((pci_read_config(scp->dev, 0x40, 4)>>(scp->unit<<8))&0x4000)){ 11645798Ssos new40 = pci_read_config(scp->dev, 0x40, 4); 11745798Ssos new44 = pci_read_config(scp->dev, 0x44, 4); 11845095Ssos if (!(new40 & 0x00004000)) { 11945095Ssos new44 &= ~0x0000000f; 12045095Ssos new44 |= ((new40&0x00003000)>>10)|((new40&0x00000300)>>8); 12145095Ssos } 12245095Ssos if (!(new40 & 0x40000000)) { 12345095Ssos new44 &= ~0x000000f0; 12445095Ssos new44 |= ((new40&0x30000000)>>22)|((new40&0x03000000)>>20); 12545095Ssos } 12645095Ssos new40 |= 0x40004000; 12745798Ssos pci_write_config(scp->dev, 0x40, new40, 4); 12845798Ssos pci_write_config(scp->dev, 0x44, new44, 4); 12945095Ssos } 13047272Ssos printf("ata%d: %s: setting up WDMA2 mode on PIIX3/4 chip ", 13145095Ssos scp->lun, (device) ? "slave" : "master"); 13245095Ssos error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, 13345095Ssos ATA_WDMA2, ATA_C_FEA_SETXFER, ATA_WAIT_INTR); 13445095Ssos if (error) { 13545095Ssos printf("failed\n"); 13645095Ssos break; 13745095Ssos } 13845095Ssos printf("OK\n"); 13945095Ssos if (device == ATA_MASTER) { 14045095Ssos mask40 = 0x0000330f; 14145095Ssos new40 = 0x00002307; 14245095Ssos mask44 = 0; 14345095Ssos new44 = 0; 14445095Ssos } else { 14545095Ssos mask40 = 0x000000f0; 14645095Ssos new40 = 0x00000070; 14745095Ssos mask44 = 0x0000000f; 14845095Ssos new44 = 0x0000000b; 14945095Ssos } 15045095Ssos if (scp->unit) { 15145095Ssos mask40 <<= 16; 15245095Ssos new40 <<= 16; 15345095Ssos mask44 <<= 4; 15445095Ssos new44 <<= 4; 15545095Ssos } 15645798Ssos pci_write_config(scp->dev, 0x40, 15745798Ssos (pci_read_config(scp->dev, 0x40, 4) & 15845798Ssos ~mask40) | new40, 4); 15945798Ssos pci_write_config(scp->dev, 0x44, 16045798Ssos (pci_read_config(scp->dev, 0x44, 4) & 16145798Ssos ~mask44) | new44, 4); 16245095Ssos return 0; 16345095Ssos } 16445095Ssos break; 16545095Ssos 16645095Ssos case 0x12308086: /* Intel PIIX */ 16745095Ssos /* probably not worth the trouble */ 16845095Ssos break; 16945095Ssos 17045095Ssos case 0x4d33105a: /* Promise Ultra/33 / FastTrack controllers */ 17149471Ssos case 0x4d38105a: /* Promise Ultra/66 controllers */ 17249614Ssos /* the promise seems to have trouble with DMA on ATAPI devices */ 17349614Ssos if ((device == ATA_MASTER && scp->devices & ATA_ATAPI_MASTER) || 17449614Ssos (device == ATA_SLAVE && scp->devices & ATA_ATAPI_SLAVE)) 17549614Ssos break; 17649614Ssos 17745554Ssos devno = (scp->unit << 1) + (device ? 1 : 0); 17845095Ssos if (udmamode >=2) { 17947272Ssos printf("ata%d: %s: setting up UDMA2 mode on Promise chip ", 18045095Ssos scp->lun, (device) ? "slave" : "master"); 18145095Ssos error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, 18245095Ssos ATA_UDMA2, ATA_C_FEA_SETXFER, ATA_WAIT_INTR); 18345095Ssos if (error) { 18445095Ssos printf("failed\n"); 18545095Ssos break; 18645095Ssos } 18745095Ssos printf("OK\n"); 18845798Ssos pci_write_config(scp->dev, 0x60 + (devno << 2), 0x004127f3, 4); 18945116Ssos return 0; 19045095Ssos } 19145095Ssos else if (wdmamode >= 2 && apiomode >= 4) { 19247272Ssos printf("ata%d: %s: setting up WDMA2 mode on Promise chip ", 19345095Ssos scp->lun, (device) ? "slave" : "master"); 19445095Ssos error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, 19545095Ssos ATA_WDMA2, ATA_C_FEA_SETXFER, ATA_WAIT_INTR); 19645095Ssos if (error) { 19745095Ssos printf("failed\n"); 19845095Ssos break; 19945095Ssos } 20045095Ssos printf("OK\n"); 20145798Ssos pci_write_config(scp->dev, 0x60 + (devno << 2), 0x004367f3, 4); 20245116Ssos return 0; 20345095Ssos } 20445095Ssos else { 20547272Ssos printf("ata%d: %s: setting up PIO mode on Promise chip OK\n", 20645095Ssos scp->lun, (device) ? "slave" : "master"); 20745798Ssos pci_write_config(scp->dev, 0x60 + (devno << 2), 0x004fe924, 4); 20845095Ssos } 20945095Ssos break; 21045095Ssos 21145095Ssos case 0x522910b9: /* AcerLabs Aladdin IV/V */ 21245095Ssos if (udmamode >=2) { 21345798Ssos int32_t word54 = pci_read_config(scp->dev, 0x54, 4); 21445095Ssos 21547272Ssos printf("ata%d: %s: setting up UDMA2 mode on Aladdin chip ", 21645095Ssos scp->lun, (device) ? "slave" : "master"); 21745095Ssos error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, 21845095Ssos ATA_UDMA2, ATA_C_FEA_SETXFER, ATA_WAIT_INTR); 21945095Ssos if (error) { 22045095Ssos printf("failed\n"); 22145095Ssos break; 22245095Ssos } 22345095Ssos printf("OK\n"); 22445095Ssos word54 |= 0x5555; 22545095Ssos word54 |= (0x0000000A << (16 + (scp->unit << 3) + (device << 2))); 22645798Ssos pci_write_config(scp->dev, 0x54, word54, 4); 22745095Ssos return 0; 22845095Ssos 22945095Ssos } 23045095Ssos else if (wdmamode >= 2 && apiomode >= 4) { 23147272Ssos printf("ata%d: %s: setting up WDMA2 mode on Aladdin chip ", 23245095Ssos scp->lun, (device) ? "slave" : "master"); 23345095Ssos error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, 23445095Ssos ATA_WDMA2, ATA_C_FEA_SETXFER, ATA_WAIT_INTR); 23545095Ssos if (error) { 23645095Ssos printf("failed\n"); 23745095Ssos break; 23845095Ssos } 23945095Ssos printf("OK\n"); 24045095Ssos return 0; 24145095Ssos } 24245095Ssos break; 24345095Ssos 24445095Ssos default: /* well, we have no support for this, but try anyways */ 24545095Ssos if ((wdmamode >= 2 && apiomode >= 4) || udmamode >= 2) { 24647272Ssos printf("ata%d: %s: setting up generic WDMA2 mode ", 24745095Ssos scp->lun, (device) ? "slave" : "master"); 24845095Ssos error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, 24945095Ssos ATA_WDMA2, ATA_C_FEA_SETXFER, ATA_WAIT_INTR); 25045095Ssos if (error) { 25145095Ssos printf("failed\n"); 25245095Ssos break; 25345095Ssos } 25445095Ssos printf("OK\n"); 25545095Ssos return 0; 25645095Ssos } 25745095Ssos } 25845095Ssos free(dmatab, M_DEVBUF); 25945095Ssos return -1; 26045095Ssos} 26145095Ssos 26245095Ssosint32_t 26345095Ssosata_dmasetup(struct ata_softc *scp, int32_t device, 26445095Ssos int8_t *data, int32_t count, int32_t flags) 26545095Ssos{ 26645095Ssos struct ata_dmaentry *dmatab; 26745095Ssos u_int32_t dma_count, dma_base; 26845095Ssos int32_t i = 0; 26945095Ssos 27045095Ssos#ifdef ATA_DEBUGDMA 27145095Ssos printf("ata%d: dmasetup\n", scp->lun); 27245095Ssos#endif 27345720Speter if (((uintptr_t)data & 1) || (count & 1)) 27445095Ssos return -1; 27545095Ssos 27645095Ssos if (!count) { 27745095Ssos printf("ata%d: zero length DMA transfer attempt on %s\n", 27845095Ssos scp->lun, (device ? "slave" : "master")); 27945095Ssos return -1; 28045095Ssos } 28145095Ssos 28245095Ssos dmatab = scp->dmatab[device ? 1 : 0]; 28345095Ssos dma_base = vtophys(data); 28445720Speter dma_count = MIN(count, (PAGE_SIZE - ((uintptr_t)data & PAGE_MASK))); 28545095Ssos data += dma_count; 28645095Ssos count -= dma_count; 28745095Ssos 28845095Ssos while (count) { 28945095Ssos dmatab[i].base = dma_base; 29045095Ssos dmatab[i].count = (dma_count & 0xffff); 29145095Ssos i++; 29245095Ssos if (i >= ATA_DMA_ENTRIES) { 29345095Ssos printf("ata%d: too many segments in DMA table for %s\n", 29445095Ssos scp->lun, (device ? "slave" : "master")); 29545095Ssos return -1; 29645095Ssos } 29745095Ssos dma_base = vtophys(data); 29845095Ssos dma_count = MIN(count, PAGE_SIZE); 29945095Ssos data += MIN(count, PAGE_SIZE); 30045095Ssos count -= MIN(count, PAGE_SIZE); 30145095Ssos } 30245095Ssos#ifdef ATA_DEBUGDMA 30345095Ssosprintf("ata_dmasetup: base=%08x count%08x\n", 30445095Ssos dma_base, dma_count); 30545095Ssos#endif 30645095Ssos dmatab[i].base = dma_base; 30745095Ssos dmatab[i].count = (dma_count & 0xffff) | ATA_DMA_EOT; 30845095Ssos 30945095Ssos outl(scp->bmaddr + ATA_BMDTP_PORT, vtophys(dmatab)); 31045095Ssos#ifdef ATA_DEBUGDMA 31145095Ssosprintf("dmatab=%08x %08x\n", vtophys(dmatab), inl(scp->bmaddr+ATA_BMDTP_PORT)); 31245095Ssos#endif 31345095Ssos outb(scp->bmaddr + ATA_BMCMD_PORT, flags ? ATA_BMCMD_WRITE_READ:0); 31445095Ssos outb(scp->bmaddr + ATA_BMSTAT_PORT, (inb(scp->bmaddr + ATA_BMSTAT_PORT) | 31545095Ssos (ATA_BMSTAT_INTERRUPT | ATA_BMSTAT_ERROR))); 31645095Ssos return 0; 31745095Ssos} 31845095Ssos 31945095Ssosvoid 32045095Ssosata_dmastart(struct ata_softc *scp, int32_t device) 32145095Ssos{ 32245095Ssos#ifdef ATA_DEBUGDMA 32345095Ssos printf("ata%d: dmastart\n", scp->lun); 32445095Ssos#endif 32545095Ssos outb(scp->bmaddr + ATA_BMCMD_PORT, 32645095Ssos inb(scp->bmaddr + ATA_BMCMD_PORT) | ATA_BMCMD_START_STOP); 32745095Ssos} 32845095Ssos 32945095Ssosint32_t 33045095Ssosata_dmadone(struct ata_softc *scp, int32_t device) 33145095Ssos{ 33245095Ssos#ifdef ATA_DEBUGDMA 33345095Ssos printf("ata%d: dmadone\n", scp->lun); 33445095Ssos#endif 33545095Ssos outb(scp->bmaddr + ATA_BMCMD_PORT, 33645095Ssos inb(scp->bmaddr + ATA_BMCMD_PORT) & ~ATA_BMCMD_START_STOP); 33745095Ssos return inb(scp->bmaddr + ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK; 33845095Ssos} 33945095Ssos 34045095Ssosint32_t 34145095Ssosata_dmastatus(struct ata_softc *scp, int32_t device) 34245095Ssos{ 34345095Ssos#ifdef ATA_DEBUGDMA 34445095Ssos printf("ata%d: dmastatus\n", scp->lun); 34545095Ssos#endif 34645095Ssos return inb(scp->bmaddr + ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK; 34745095Ssos} 34845095Ssos 34945095Ssos#else /* NPCI > 0 */ 35045095Ssos 35145095Ssosint32_t 35245095Ssosata_dmainit(struct ata_softc *scp, int32_t device, 35345095Ssos int32_t piomode, int32_t wdmamode, int32_t udmamode) 35445095Ssos{ 35545095Ssos return -1; 35645095Ssos} 35745095Ssos 35845095Ssosint32_t 35945095Ssosata_dmasetup(struct ata_softc *scp, int32_t device, 36045095Ssos int8_t *data, int32_t count, int32_t flags) 36145095Ssos{ 36245095Ssos return -1; 36345095Ssos} 36445095Ssos 36545095Ssosvoid 36645095Ssosata_dmastart(struct ata_softc *scp, int32_t device) 36745095Ssos{ 36845095Ssos} 36945095Ssos 37045095Ssosint32_t 37145095Ssosata_dmadone(struct ata_softc *scp, int32_t device) 37245095Ssos{ 37345095Ssos return -1; 37445095Ssos} 37545095Ssos 37645095Ssosint32_t 37745095Ssosata_dmastatus(struct ata_softc *scp, int32_t device) 37845095Ssos{ 37945095Ssos return -1; 38045095Ssos} 38145095Ssos 38245095Ssos#endif /* NPCI > 0 */ 38345095Ssos#endif /* NATA > 0 */ 384