sdide: limit max dma transfer size, make sure dma transfer is stoped in error case, set bytecount to 0 for dma

This commit is contained in:
cinap_lenrek 2011-07-23 23:40:35 +02:00
parent 3202d39042
commit cb02859888

View file

@ -259,7 +259,7 @@ typedef struct Prd { /* Physical Region Descriptor */
} Prd; } Prd;
enum { enum {
BMspan = 64*1024, /* must be power of 2 <= 64*1024 */ BMspan = 32*1024, /* must be power of 2 <= 64*1024 */
Nprd = SDmaxio/BMspan+2, Nprd = SDmaxio/BMspan+2,
}; };
@ -272,6 +272,7 @@ typedef struct Ctlr {
int bmiba; /* bus master interface base address */ int bmiba; /* bus master interface base address */
int maxio; /* sector count transfer maximum */ int maxio; /* sector count transfer maximum */
int span; /* don't span this boundary with dma */ int span; /* don't span this boundary with dma */
int maxdma; /* don't attempt dma transfers bigger than this */
Pcidev* pcidev; Pcidev* pcidev;
void (*ienable)(Ctlr*); void (*ienable)(Ctlr*);
@ -1019,6 +1020,8 @@ atadmasetup(Drive* drive, int len)
pa = PCIWADDR(drive->data); pa = PCIWADDR(drive->data);
if(pa & 0x03) if(pa & 0x03)
return -1; return -1;
if(ctlr->maxdma && len > ctlr->maxdma)
return -1;
/* /*
* Sometimes drives identify themselves as being DMA capable * Sometimes drives identify themselves as being DMA capable
@ -1047,7 +1050,7 @@ atadmasetup(Drive* drive, int len)
prd++; prd++;
} }
if(i == Nprd) if(i == Nprd)
(prd-1)->count |= PrdEOT; return -1;
bmiba = ctlr->bmiba; bmiba = ctlr->bmiba;
outl(bmiba+Bmidtpx, PCIWADDR(ctlr->prdt)); outl(bmiba+Bmidtpx, PCIWADDR(ctlr->prdt));
@ -1134,6 +1137,8 @@ atapktinterrupt(Drive* drive)
break; break;
case 0: case 0:
if(drive->pktdma)
goto Pktdma;
len = (inb(cmdport+Bytehi)<<8)|inb(cmdport+Bytelo); len = (inb(cmdport+Bytehi)<<8)|inb(cmdport+Bytelo);
if(drive->data+len > drive->limit){ if(drive->data+len > drive->limit){
atanop(drive, 0); atanop(drive, 0);
@ -1144,6 +1149,8 @@ atapktinterrupt(Drive* drive)
break; break;
case Io: case Io:
if(drive->pktdma)
goto Pktdma;
len = (inb(cmdport+Bytehi)<<8)|inb(cmdport+Bytelo); len = (inb(cmdport+Bytehi)<<8)|inb(cmdport+Bytelo);
if(drive->data+len > drive->limit){ if(drive->data+len > drive->limit){
atanop(drive, 0); atanop(drive, 0);
@ -1154,9 +1161,10 @@ atapktinterrupt(Drive* drive)
break; break;
case Io|Cd: case Io|Cd:
if(drive->pktdma) if(drive->pktdma){
Pktdma:
atadmainterrupt(drive, drive->dlen); atadmainterrupt(drive, drive->dlen);
else } else
ctlr->done = 1; ctlr->done = 1;
break; break;
} }
@ -1186,26 +1194,25 @@ atapktio0(Drive *drive, SDreq *r)
return SDnostatus; return SDnostatus;
ilock(ctlr); ilock(ctlr);
if(drive->dlen && drive->dmactl && !atadmasetup(drive, drive->dlen)) if(drive->dlen && drive->dmactl && !atadmasetup(drive, drive->dlen)){
drive->pktdma = Dma; drive->pktdma = Dma;
else len = 0; /* bytecount should be 0 for dma */
}else{
drive->pktdma = 0; drive->pktdma = 0;
outb(cmdport+Features, drive->pktdma);
outb(cmdport+Count, 0);
outb(cmdport+Sector, 0);
if(drive->secsize) if(drive->secsize)
len = 16*drive->secsize; len = 16*drive->secsize;
else else
len = 0x8000; len = 0x8000;
}
outb(cmdport+Features, drive->pktdma);
outb(cmdport+Count, 0);
outb(cmdport+Sector, 0);
outb(cmdport+Bytelo, len); outb(cmdport+Bytelo, len);
outb(cmdport+Bytehi, len>>8); outb(cmdport+Bytehi, len>>8);
outb(cmdport+Dh, drive->dev); outb(cmdport+Dh, drive->dev);
ctlr->done = 0; ctlr->done = 0;
ctlr->curdrive = drive; ctlr->curdrive = drive;
ctlr->command = Cpkt; /* debugging */ ctlr->command = Cpkt; /* debugging */
if(drive->pktdma)
atadmastart(ctlr, drive->write);
outb(cmdport+Command, Cpkt); outb(cmdport+Command, Cpkt);
if((drive->info[Iconfig] & Mdrq) != 0x0020){ if((drive->info[Iconfig] & Mdrq) != 0x0020){
@ -1219,23 +1226,22 @@ atapktio0(Drive *drive, SDreq *r)
}else }else
atapktinterrupt(drive); atapktinterrupt(drive);
} }
if(drive->pktdma)
atadmastart(ctlr, drive->write);
iunlock(ctlr); iunlock(ctlr);
if(iowait(drive, 20*1000, 1) <= 0){ if(iowait(drive, 20*1000, 1) <= 0){
ilock(ctlr); ilock(ctlr);
if(!drive->error){
ataabort(drive, 0); ataabort(drive, 0);
if(drive->pktdma){ } else
atadmastop(ctlr); ilock(ctlr);
drive->dmactl = 0;
}
}
if(drive->error){ if(drive->error){
if(drive->pktdma)
atadmastop(ctlr);
drive->status |= Chk; drive->status |= Chk;
ctlr->curdrive = nil; ctlr->curdrive = nil;
} }
iunlock(ctlr); iunlock(ctlr);
}
if(drive->status & Chk) if(drive->status & Chk)
rv = SDcheck; rv = SDcheck;
@ -2001,7 +2007,7 @@ static SDev*
atapnp(void) atapnp(void)
{ {
char *s; char *s;
int channel, map, ispc87415, maxio, pi, r, span, tbdf; int channel, map, ispc87415, maxio, pi, r, span, maxdma, tbdf;
Ctlr *ctlr; Ctlr *ctlr;
Pcidev *p; Pcidev *p;
SDev *sdev, *head, *tail; SDev *sdev, *head, *tail;
@ -2034,6 +2040,7 @@ atapnp(void)
pi = p->ccrp; pi = p->ccrp;
map = 3; map = 3;
ispc87415 = 0; ispc87415 = 0;
maxdma = 0;
maxio = 0; maxio = 0;
if(s = getconf("*idemaxio")) if(s = getconf("*idemaxio"))
maxio = atoi(s); maxio = atoi(s);
@ -2172,9 +2179,10 @@ atapnp(void)
case (0x2366<<16)|0x197b: /* jmicron jmb366 */ case (0x2366<<16)|0x197b: /* jmicron jmb366 */
case (0x2368<<16)|0x197b: /* jmicron jmb368 */ case (0x2368<<16)|0x197b: /* jmicron jmb368 */
break; break;
case (0x1230<<16)|0x8086: /* 82371FB (PIIX) */
case (0x7010<<16)|0x8086: /* 82371SB (PIIX3) */ case (0x7010<<16)|0x8086: /* 82371SB (PIIX3) */
case (0x1230<<16)|0x8086: /* 82371FB (PIIX) */
case (0x7111<<16)|0x8086: /* 82371[AE]B (PIIX4[E]) */ case (0x7111<<16)|0x8086: /* 82371[AE]B (PIIX4[E]) */
maxdma = 0x20000;
break; break;
case (0x2411<<16)|0x8086: /* 82801AA (ICH) */ case (0x2411<<16)|0x8086: /* 82801AA (ICH) */
case (0x2421<<16)|0x8086: /* 82801AB (ICH0) */ case (0x2421<<16)|0x8086: /* 82801AB (ICH0) */
@ -2246,6 +2254,7 @@ atapnp(void)
ctlr->tbdf = tbdf; ctlr->tbdf = tbdf;
ctlr->pcidev = p; ctlr->pcidev = p;
ctlr->maxio = maxio; ctlr->maxio = maxio;
ctlr->maxdma = maxdma;
ctlr->span = span; ctlr->span = span;
ctlr->irqack = irqack; ctlr->irqack = irqack;
if(pi & 0x80) if(pi & 0x80)