ata-dma.c revision 49471
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 * 2849471Ssos * $Id: ata-dma.c,v 1.8 1999/05/26 23:01:57 gallatin Exp $ 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 */ 17245554Ssos devno = (scp->unit << 1) + (device ? 1 : 0); 17345095Ssos if (udmamode >=2) { 17447272Ssos printf("ata%d: %s: setting up UDMA2 mode on Promise chip ", 17545095Ssos scp->lun, (device) ? "slave" : "master"); 17645095Ssos error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, 17745095Ssos ATA_UDMA2, ATA_C_FEA_SETXFER, ATA_WAIT_INTR); 17845095Ssos if (error) { 17945095Ssos printf("failed\n"); 18045095Ssos break; 18145095Ssos } 18245095Ssos printf("OK\n"); 18345798Ssos pci_write_config(scp->dev, 0x60 + (devno << 2), 0x004127f3, 4); 18445116Ssos return 0; 18545095Ssos } 18645095Ssos else if (wdmamode >= 2 && apiomode >= 4) { 18747272Ssos printf("ata%d: %s: setting up WDMA2 mode on Promise chip ", 18845095Ssos scp->lun, (device) ? "slave" : "master"); 18945095Ssos error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, 19045095Ssos ATA_WDMA2, ATA_C_FEA_SETXFER, ATA_WAIT_INTR); 19145095Ssos if (error) { 19245095Ssos printf("failed\n"); 19345095Ssos break; 19445095Ssos } 19545095Ssos printf("OK\n"); 19645798Ssos pci_write_config(scp->dev, 0x60 + (devno << 2), 0x004367f3, 4); 19745116Ssos return 0; 19845095Ssos } 19945095Ssos else { 20047272Ssos printf("ata%d: %s: setting up PIO mode on Promise chip OK\n", 20145095Ssos scp->lun, (device) ? "slave" : "master"); 20245798Ssos pci_write_config(scp->dev, 0x60 + (devno << 2), 0x004fe924, 4); 20345095Ssos } 20445095Ssos break; 20545095Ssos 20645095Ssos case 0x522910b9: /* AcerLabs Aladdin IV/V */ 20745095Ssos if (udmamode >=2) { 20845798Ssos int32_t word54 = pci_read_config(scp->dev, 0x54, 4); 20945095Ssos 21047272Ssos printf("ata%d: %s: setting up UDMA2 mode on Aladdin chip ", 21145095Ssos scp->lun, (device) ? "slave" : "master"); 21245095Ssos error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, 21345095Ssos ATA_UDMA2, ATA_C_FEA_SETXFER, ATA_WAIT_INTR); 21445095Ssos if (error) { 21545095Ssos printf("failed\n"); 21645095Ssos break; 21745095Ssos } 21845095Ssos printf("OK\n"); 21945095Ssos word54 |= 0x5555; 22045095Ssos word54 |= (0x0000000A << (16 + (scp->unit << 3) + (device << 2))); 22145798Ssos pci_write_config(scp->dev, 0x54, word54, 4); 22245095Ssos return 0; 22345095Ssos 22445095Ssos } 22545095Ssos else if (wdmamode >= 2 && apiomode >= 4) { 22647272Ssos printf("ata%d: %s: setting up WDMA2 mode on Aladdin chip ", 22745095Ssos scp->lun, (device) ? "slave" : "master"); 22845095Ssos error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, 22945095Ssos ATA_WDMA2, ATA_C_FEA_SETXFER, ATA_WAIT_INTR); 23045095Ssos if (error) { 23145095Ssos printf("failed\n"); 23245095Ssos break; 23345095Ssos } 23445095Ssos printf("OK\n"); 23545095Ssos return 0; 23645095Ssos } 23745095Ssos break; 23845095Ssos 23945095Ssos default: /* well, we have no support for this, but try anyways */ 24045095Ssos if ((wdmamode >= 2 && apiomode >= 4) || udmamode >= 2) { 24147272Ssos printf("ata%d: %s: setting up generic WDMA2 mode ", 24245095Ssos scp->lun, (device) ? "slave" : "master"); 24345095Ssos error = ata_command(scp, device, ATA_C_SETFEATURES, 0, 0, 0, 24445095Ssos ATA_WDMA2, ATA_C_FEA_SETXFER, ATA_WAIT_INTR); 24545095Ssos if (error) { 24645095Ssos printf("failed\n"); 24745095Ssos break; 24845095Ssos } 24945095Ssos printf("OK\n"); 25045095Ssos return 0; 25145095Ssos } 25245095Ssos } 25345095Ssos free(dmatab, M_DEVBUF); 25445095Ssos return -1; 25545095Ssos} 25645095Ssos 25745095Ssosint32_t 25845095Ssosata_dmasetup(struct ata_softc *scp, int32_t device, 25945095Ssos int8_t *data, int32_t count, int32_t flags) 26045095Ssos{ 26145095Ssos struct ata_dmaentry *dmatab; 26245095Ssos u_int32_t dma_count, dma_base; 26345095Ssos int32_t i = 0; 26445095Ssos 26545095Ssos#ifdef ATA_DEBUGDMA 26645095Ssos printf("ata%d: dmasetup\n", scp->lun); 26745095Ssos#endif 26845720Speter if (((uintptr_t)data & 1) || (count & 1)) 26945095Ssos return -1; 27045095Ssos 27145095Ssos if (!count) { 27245095Ssos printf("ata%d: zero length DMA transfer attempt on %s\n", 27345095Ssos scp->lun, (device ? "slave" : "master")); 27445095Ssos return -1; 27545095Ssos } 27645095Ssos 27745095Ssos dmatab = scp->dmatab[device ? 1 : 0]; 27845095Ssos dma_base = vtophys(data); 27945720Speter dma_count = MIN(count, (PAGE_SIZE - ((uintptr_t)data & PAGE_MASK))); 28045095Ssos data += dma_count; 28145095Ssos count -= dma_count; 28245095Ssos 28345095Ssos while (count) { 28445095Ssos dmatab[i].base = dma_base; 28545095Ssos dmatab[i].count = (dma_count & 0xffff); 28645095Ssos i++; 28745095Ssos if (i >= ATA_DMA_ENTRIES) { 28845095Ssos printf("ata%d: too many segments in DMA table for %s\n", 28945095Ssos scp->lun, (device ? "slave" : "master")); 29045095Ssos return -1; 29145095Ssos } 29245095Ssos dma_base = vtophys(data); 29345095Ssos dma_count = MIN(count, PAGE_SIZE); 29445095Ssos data += MIN(count, PAGE_SIZE); 29545095Ssos count -= MIN(count, PAGE_SIZE); 29645095Ssos } 29745095Ssos#ifdef ATA_DEBUGDMA 29845095Ssosprintf("ata_dmasetup: base=%08x count%08x\n", 29945095Ssos dma_base, dma_count); 30045095Ssos#endif 30145095Ssos dmatab[i].base = dma_base; 30245095Ssos dmatab[i].count = (dma_count & 0xffff) | ATA_DMA_EOT; 30345095Ssos 30445095Ssos outl(scp->bmaddr + ATA_BMDTP_PORT, vtophys(dmatab)); 30545095Ssos#ifdef ATA_DEBUGDMA 30645095Ssosprintf("dmatab=%08x %08x\n", vtophys(dmatab), inl(scp->bmaddr+ATA_BMDTP_PORT)); 30745095Ssos#endif 30845095Ssos outb(scp->bmaddr + ATA_BMCMD_PORT, flags ? ATA_BMCMD_WRITE_READ:0); 30945095Ssos outb(scp->bmaddr + ATA_BMSTAT_PORT, (inb(scp->bmaddr + ATA_BMSTAT_PORT) | 31045095Ssos (ATA_BMSTAT_INTERRUPT | ATA_BMSTAT_ERROR))); 31145095Ssos return 0; 31245095Ssos} 31345095Ssos 31445095Ssosvoid 31545095Ssosata_dmastart(struct ata_softc *scp, int32_t device) 31645095Ssos{ 31745095Ssos#ifdef ATA_DEBUGDMA 31845095Ssos printf("ata%d: dmastart\n", scp->lun); 31945095Ssos#endif 32045095Ssos outb(scp->bmaddr + ATA_BMCMD_PORT, 32145095Ssos inb(scp->bmaddr + ATA_BMCMD_PORT) | ATA_BMCMD_START_STOP); 32245095Ssos} 32345095Ssos 32445095Ssosint32_t 32545095Ssosata_dmadone(struct ata_softc *scp, int32_t device) 32645095Ssos{ 32745095Ssos#ifdef ATA_DEBUGDMA 32845095Ssos printf("ata%d: dmadone\n", scp->lun); 32945095Ssos#endif 33045095Ssos outb(scp->bmaddr + ATA_BMCMD_PORT, 33145095Ssos inb(scp->bmaddr + ATA_BMCMD_PORT) & ~ATA_BMCMD_START_STOP); 33245095Ssos return inb(scp->bmaddr + ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK; 33345095Ssos} 33445095Ssos 33545095Ssosint32_t 33645095Ssosata_dmastatus(struct ata_softc *scp, int32_t device) 33745095Ssos{ 33845095Ssos#ifdef ATA_DEBUGDMA 33945095Ssos printf("ata%d: dmastatus\n", scp->lun); 34045095Ssos#endif 34145095Ssos return inb(scp->bmaddr + ATA_BMSTAT_PORT) & ATA_BMSTAT_MASK; 34245095Ssos} 34345095Ssos 34445095Ssos#else /* NPCI > 0 */ 34545095Ssos 34645095Ssosint32_t 34745095Ssosata_dmainit(struct ata_softc *scp, int32_t device, 34845095Ssos int32_t piomode, int32_t wdmamode, int32_t udmamode) 34945095Ssos{ 35045095Ssos return -1; 35145095Ssos} 35245095Ssos 35345095Ssosint32_t 35445095Ssosata_dmasetup(struct ata_softc *scp, int32_t device, 35545095Ssos int8_t *data, int32_t count, int32_t flags) 35645095Ssos{ 35745095Ssos return -1; 35845095Ssos} 35945095Ssos 36045095Ssosvoid 36145095Ssosata_dmastart(struct ata_softc *scp, int32_t device) 36245095Ssos{ 36345095Ssos} 36445095Ssos 36545095Ssosint32_t 36645095Ssosata_dmadone(struct ata_softc *scp, int32_t device) 36745095Ssos{ 36845095Ssos return -1; 36945095Ssos} 37045095Ssos 37145095Ssosint32_t 37245095Ssosata_dmastatus(struct ata_softc *scp, int32_t device) 37345095Ssos{ 37445095Ssos return -1; 37545095Ssos} 37645095Ssos 37745095Ssos#endif /* NPCI > 0 */ 37845095Ssos#endif /* NATA > 0 */ 379