[inferno-kirkwood] 4 new revisions pushed by mechiel@ueber.net on 2010-03-28 14:18 GMT

1 view
Skip to first unread message

inferno-...@googlecode.com

unread,
Mar 28, 2010, 10:18:38 AM3/28/10
to inferno-kirk...@googlegroups.com
4 new revisions:

Revision: 93944745ba
Author: Mechiel Lukkien <mec...@ueber.net>
Date: Fri Mar 26 07:47:58 2010
Log: check status in response to commands, to io in chunks....
http://code.google.com/p/inferno-kirkwood/source/detail?r=93944745ba

Revision: 136176e6ed
Author: Mechiel Lukkien <mec...@ueber.net>
Date: Fri Mar 26 08:12:30 2010
Log: use qlock around accessing sd card.
http://code.google.com/p/inferno-kirkwood/source/detail?r=136176e6ed

Revision: ba2f095db3
Author: Mechiel Lukkien <mec...@ueber.net>
Date: Fri Mar 26 09:16:04 2010
Log: little better error handling.
http://code.google.com/p/inferno-kirkwood/source/detail?r=ba2f095db3

Revision: 869fd787f3
Author: Mechiel Lukkien <mec...@ueber.net>
Date: Sun Mar 28 07:18:45 2010
Log: use interrupts for all commands (not just dma). better error
messages...
http://code.google.com/p/inferno-kirkwood/source/detail?r=869fd787f3

==============================================================================
Revision: 93944745ba
Author: Mechiel Lukkien <mec...@ueber.net>
Date: Fri Mar 26 07:47:58 2010
Log: check status in response to commands, to io in chunks.

- check status in r1(b) response from card.
- do io in chunks of max 512kb. so no single reader can completely
hog the port. it should be enough to take reasonable advantage of
speedup of sequential reading.
http://code.google.com/p/inferno-kirkwood/source/detail?r=93944745ba

Modified:
/devsdio.c

=======================================
--- /devsdio.c Thu Mar 18 06:11:29 2010
+++ /devsdio.c Fri Mar 26 07:47:58 2010
@@ -2,8 +2,8 @@
* only memory cards are supported. only sd cards for now, mmc cards seem
obsolete anyway.
*
* todo:
+ * - lock card/controller when using it.
* - abort command on error during sleep.
- * - make sdio() split transaction when it is huge.
* - better error handling
* - hook into devsd.c?
* - use interrupts for all commands? should be better than polling.
@@ -115,7 +115,7 @@

/* est, error status */
Ecmdtimeout = 1<<0,
- Ecmdcrc = 1<<1,
+ Ecmdcrc = 1<<1,
Ecmdendbit = 1<<2,
Ecmdindex = 1<<3,
Edatatimeout = 1<<4,
@@ -143,9 +143,8 @@
CMDWritemulti = 25,

ACMDGetscr = 51,
-};
-
-enum {
+
+
CMD8pattern = 0xaa,
CMD8patternmask = MASK(8),
CMD8voltage = 1<<8,
@@ -154,9 +153,8 @@
ACMD41voltagewindow = MASK(23-15+1)<<15,
ACMD41sdhcsupported = 1<<30,
ACMD41ready = 1<<31,
-};
-
-enum {
+
+
ESAcmd12Notexe = 1<<0,
ESAcmd12Timeout = 1<<1,
ESAcmd12CrcErr = 1<<2,
@@ -164,6 +162,20 @@
ESAcmd12IndexErr = 1<<4,
ESAcmd12RespTBi = 1<<5,
ESAcmd12RespStartBitErr = 1<<6,
+
+ /* sd status, in R1 & R1b responses */
+ SDappcmd = 1<<5, /* next command will be interpreted as app specific */
+ SDreadyfordata = 1<<8, /* buffer empty signal on bus */
+ SDstateshift = 9,
+ SDstatewidth = 4,
+ SDnoecc = 1<<14, /* command executed without ecc */
+ SDerror = 1<<19, /* general/unknown error */
+ SDccerror = 1<<20, /* internal card controller error */
+ SDbadcmd = 1<<22, /* invalid command */
+ SDblocklenerr = 1<<29, /* block length invalid */
+
+ /* bits we consider as error. some indicate conditions we don't (yet)
handle. */
+ SDbad = 1<<3|1<<13|1<<14|1<<15|1<<16|MASK(13)<<19,
};


@@ -184,21 +196,21 @@


/* for bits in st, est, acmd12st registers */
-static char *statusstrs[] = {
+const static char *statusstrs[] = {
"cmdcomplete", "xfercomplete", "blockgapevent", "dmaintr",
"txready", "rxready", "", "",
"cardintr", "readwaiton", "fifo8wfull", "fifo8wavail",
"suspended", "autocmd12done", "unexpresp", "errorintr",
};

-static char *errstatusstrs[] = {
+const static char *errstatusstrs[] = {
"cmdtimeout", "cmdcrc", "cmdendbit", "cmdindex",
"datatimeout", "rddatacrc", "rddataend", "",
"autocmd12", "cmdstartbit", "xfersize", "resptbit",
"crcendbit", "crcstartbit", "crcstatus",
};

-static char *acmd12ststrs[] = {
+const static char *acmd12ststrs[] = {
"acmd12notexe", "acmd12timeout", "acmd12crcerr", "acmd12endbiterr",
"acmd12indexerr", "acmd12resptbi", "acmd12respstartbiterr",
};
@@ -224,7 +236,6 @@
{
return mkstr(p, e, v, errstatusstrs, nelem(errstatusstrs));
}
-

static char*
acmd12ststr(char *p, char *e, ulong v)
@@ -232,6 +243,29 @@
return mkstr(p, e, v, acmd12ststrs, nelem(acmd12ststrs));
}

+static const char *sdstatusstrs[] = {
+"tm0", "tm1", "apprsvd", "akeseqerr",
+"sdiorsvd", "appcmd", "rsvd6", "rsvd7",
+"readyfordata", "st9", "st10", "st11",
+"st12", "erasereset", "noecc", "wperaseskip",
+"csdoverwrite", "rsvd17", "rsvd18", "error",
+"ccerror", "eccfail", "badcmd", "cmdcrcerr",
+"lockerr", "locked", "wpviolation", "eraseparam",
+"eraseseqerr", "blocklenerr", "addrerr", "outofrange",
+};
+static char *
+sdstatusstr(char *p, char *e, ulong v)
+{
+ return mkstr(p, e, v, sdstatusstrs, nelem(sdstatusstrs));
+}
+
+static const char *statestrs[] = {
+"idle", "ready", "ident", "stby",
+"tran", "data", "rcv", "prg",
+"dis", "", "", "",
+"", "", "", "",
+};
+
static void
printstatus(char *s, ulong st, ulong est, ulong acmd12st)
{
@@ -313,6 +347,8 @@
s = sdcmd(c, acmd, card.rca<<16, R1, 0);
if(s < 0)
return s;
+ if((c->resp[2]>>8 & SDappcmd) == 0)
+ return -1;
}

/* clear status */
@@ -419,6 +455,19 @@
c->resp[2] = w;
break;
}
+
+ if(rt == R1 || rt == R1b) {
+ char buf[128];
+
+ v = c->resp[2]>>8;
+ dprint("status %#lux\n", v);
+ if(v & SDbad)
+ return -1;
+
+ sdstatusstr(buf, buf+sizeof buf, v);
+ v = v>>SDstateshift & MASK(SDstatewidth);
+ dprint(" %s, st %s (%#lux)\n", buf, statestrs[v], v);
+ }
return 0;
}

@@ -565,9 +614,9 @@
if(sdcmd(&card, 7, card.rca<<16, R1b, 0) < 0)
errorsd("selecting card");

-if(0){
+if(0){
uchar *p = malloc(512);
- if(sdcmddma(&card, 55, 1<<0, p, 512, 1, R1, Fappdata|Fdmad2h) < 0)
+ if(sdcmddma(&card, 51, 1<<0, p, 512, 1, R1, Fappdata|Fdmad2h) < 0)
errorsd("read scr");
}

@@ -587,7 +636,7 @@
static long
sdio(uchar *a, long n, vlong offset, int iswrite)
{
- ulong cmd, arg, fl;
+ ulong cmd, arg, fl, h, nn;

if(card.valid == 0)
error(Enocard);
@@ -603,12 +652,20 @@

cmd = iswrite ? CMDWritemulti : CMDReadmulti;
fl = iswrite ? Fdmah2d : Fdmad2h;
- if(card.sdhc)
- arg = offset/card.bs;
- else
- arg = offset;
- if(sdcmddma(&card, cmd, arg, a, card.bs, n/card.bs, R1, fl|Fmulti) < 0)
- errorsd("io");
+
+ h = 0;
+ while(h < n) {
+ if(card.sdhc)
+ arg = (offset+h)/card.bs;
+ else
+ arg = offset+h;
+ nn = n;
+ if(nn > 512*1024)
+ nn = 512*1024;
+ if(sdcmddma(&card, cmd, arg, a+h, card.bs, nn/card.bs, R1, fl|Fmulti) <
0)
+ errorsd("io");
+ h += nn;
+ }
return n;
}

@@ -653,9 +710,9 @@
SdioReg *r = SDIOREG;

/* disable all interrupts. dma interrupt will be enabled as required.
all bits lead to IRQ0sdio. */
+ intrdisable(Irqlo, IRQ0sdio, sdiointr, nil, "sdio");
r->stirq = 0;
r->estirq = 0;
- intrenable(Irqlo, IRQ0sdio, sdiointr, nil, "sdio");
}

static void
@@ -663,6 +720,8 @@
{
SdioReg *r = SDIOREG;

+ intrdisable(Irqlo, IRQ0sdio, sdiointr, nil, "sdio");
+
card.valid = 0;

/* reset the bus, forcing all cards to idle state */
@@ -685,6 +744,7 @@
/* disable all interrupts. dma interrupt will be enabled as required.
all bits lead to IRQ0sdio. */
r->stirq = 0;
r->estirq = 0;
+ intrenable(Irqlo, IRQ0sdio, sdiointr, nil, "sdio");
}

static Chan*

==============================================================================
Revision: 136176e6ed
Author: Mechiel Lukkien <mec...@ueber.net>
Date: Fri Mar 26 08:12:30 2010
Log: use qlock around accessing sd card.
http://code.google.com/p/inferno-kirkwood/source/detail?r=136176e6ed

Modified:
/devsdio.c

=======================================
--- /devsdio.c Fri Mar 26 07:47:58 2010
+++ /devsdio.c Fri Mar 26 08:12:30 2010
@@ -2,7 +2,6 @@
* only memory cards are supported. only sd cards for now, mmc cards seem
obsolete anyway.
*
* todo:
- * - lock card/controller when using it.
* - abort command on error during sleep.
* - better error handling
* - hook into devsd.c?
@@ -181,6 +180,7 @@

static Card card;
static Rendez dmar;
+static QLock sdl;

enum {
Qdir, Qctl, Qinfo, Qdata, Qstatus,
@@ -782,10 +782,17 @@
{
char *buf, *p, *e;
SdioReg *r = SDIOREG;
+
+ qlock(&sdl);
+ if(waserror()) {
+ qunlock(&sdl);
+ nexterror();
+ }

switch((ulong)c->qid.path){
case Qdir:
- return devdirread(c, a, n, sdiotab, nelem(sdiotab), devgen);
+ n = devdirread(c, a, n, sdiotab, nelem(sdiotab), devgen);
+ break;
case Qctl:
cardstr(&card, up->genbuf, sizeof (up->genbuf));
n = readstr(offset, a, n, up->genbuf);
@@ -830,11 +837,16 @@

n = readstr(offset, a, n, buf);
free(buf);
+
break;
default:
n = 0;
break;
}
+
+ qunlock(&sdl);
+ poperror();
+
return n;
}

@@ -854,6 +866,12 @@
Cmdbuf *cb;
Cmdtab *ct;
SdioReg *r = SDIOREG;
+
+ qlock(&sdl);
+ if(waserror()) {
+ qunlock(&sdl);
+ nexterror();
+ }

switch((ulong)c->qid.path){
case Qctl:
@@ -888,6 +906,10 @@
default:
error(Ebadusefd);
}
+
+ qunlock(&sdl);
+ poperror();
+
return n;
}


==============================================================================
Revision: ba2f095db3
Author: Mechiel Lukkien <mec...@ueber.net>
Date: Fri Mar 26 09:16:04 2010
Log: little better error handling.
http://code.google.com/p/inferno-kirkwood/source/detail?r=ba2f095db3

Modified:
/devsdio.c
/sdcard.h

=======================================
--- /devsdio.c Fri Mar 26 08:12:30 2010
+++ /devsdio.c Fri Mar 26 09:16:04 2010
@@ -2,12 +2,11 @@
* only memory cards are supported. only sd cards for now, mmc cards seem
obsolete anyway.
*
* todo:
- * - abort command on error during sleep.
- * - better error handling
- * - hook into devsd.c?
* - use interrupts for all commands? should be better than polling.
- * - see if we can detect device inserts/ejects? yes, by sd_cd gpio pin
(on mpp47).
+ * - don't crash when proc doing read/write is killed.
+ * - hook into devsd.c?
* - test with non-high capacity sd cards. i think it does need different
code.
+ * - see if we can detect device inserts/ejects? yes, by sd_cd gpio pin
(on mpp47).
* - ctl commands for erasing?
* - erase before writing big buffer?
*/
@@ -27,10 +26,13 @@
char Enocard[] = "no card";

enum {
+ /* keep in sync with errstrs[] */
SDOk = 0,
SDTimeout = -1,
SDCardbusy = -2,
SDError = -3,
+ SDInterrupted = -4,
+ SDBadstatus = -5, /* status in r1(b) response indicated error, see
card.status */

/* expected response to command */
R0 = 0,
@@ -289,16 +291,22 @@


static char *errstrs[] = {
-"success", "timeout", "card busy", "error",
+"success", "timeout", "card busy", "error", "interrupted", "badstatus",
};

static void
-errorsd(char *s)
-{
- if(card.lasterr == SDOk)
- errorf("%s (%scmd %d)", s, card.lastisapp ? "a" : "", card.lastcmd);
- else
- errorf("%s, %s for %scmd %d", s, errstrs[-card.lasterr],
card.lastisapp ? "a" : "", card.lastcmd);
+errorsd(char *s, int e)
+{
+ char buf[ERRMAX+1];
+ char *p = buf;
+
+ p = seprint(p, buf+sizeof buf, "%s", s);
+ if(e != SDOk)
+ p = seprint(p, buf+sizeof buf, ": %s", errstrs[-e]);
+ if(e == SDBadstatus)
+ p = seprint(p, buf+sizeof buf, " (r1status %#lux)", card.status);
+ USED(p);
+ error(buf);
}

static int
@@ -348,7 +356,7 @@
if(s < 0)
return s;
if((c->resp[2]>>8 & SDappcmd) == 0)
- return -1;
+ return SDError;
}

/* clear status */
@@ -386,13 +394,15 @@

if(fl & (Fdmad2h|Fdmah2d)) {
/* wait for dma interrupt that signals completion */
- while(waserror())
- {}
+ s = 0;
+ while(waserror()) {
+ s = SDInterrupted;
+ }
tsleep(&dmar, dmadone, nil, 5000);
poperror();

need = Scmdcomplete|Sdmaintr;
- if((r->st & need) != need || (r->st & (Serror|Sunexpresp))) {
+ if(s < 0 || (r->st & need) != need || (r->st & (Serror|Sunexpresp))) {
printstatus("dma error: ", r->st, r->est, r->acmd12st);
return SDError;
}
@@ -459,10 +469,10 @@
if(rt == R1 || rt == R1b) {
char buf[128];

- v = c->resp[2]>>8;
+ v = c->status = c->resp[2]>>8;
dprint("status %#lux\n", v);
if(v & SDbad)
- return -1;
+ return SDBadstatus;

sdstatusstr(buf, buf+sizeof buf, v);
v = v>>SDstateshift & MASK(SDstatewidth);
@@ -481,10 +491,8 @@
r->dmaaddrhi = ((ulong)a>>16) & MASK(16);
r->blksize = blsz;
r->blkcount = nbl;
- //tsleep(&up->sleep, return0, nil, 250);
- dprint("sdio, a %#lux, dmaddrlo %#lux dmaadrhi %#lux blksize %d
blkcount %d cmdarg %#lux\n",
+ dprint("sdcmddma, a %#lux, dmaddrlo %#lux dmaadrhi %#lux blksize %d
blkcount %d cmdarg %#lux\n",
a, (ulong)a & MASK(16), ((ulong)a>>16) & MASK(16), blsz, nbl, arg);
- //tsleep(&up->sleep, return0, nil, 250);
return sdcmd(c, cmd, arg, resp, fl);
}

@@ -505,8 +513,9 @@
r->hostctl &= ~HChighspeed;

/* force card to idle state */
- if(sdcmd(&card, 0, 0, R0, 0) < 0)
- errorsd("reset failed");
+ s = sdcmd(&card, 0, 0, R0, 0);
+ if(s < 0)
+ errorsd("reset failed", s);

/*
* "send interface command". only >=2.00 cards will respond.
@@ -521,12 +530,12 @@
card.sd2 = 1;
v = card.resp[2]>>8;
if((v & CMD8patternmask) != CMD8pattern)
- errorsd("sd check pattern mismatch");
+ error("check pattern mismatch");
if((v & CMD8voltagemask) != CMD8voltage) {
- errorsd("sd voltage not supported");
+ error("voltage not supported");
}
} else if(s != SDTimeout)
- errorsd("voltage exchange failed");
+ error("voltage exchange failed");

/*
* "send host capacity support information".
@@ -538,39 +547,38 @@
for(;;) {
v = ACMD41sdhcsupported|ACMD41voltagewindow;
s = sdcmd(&card, 41, v, R3, Fapp);
- if(s == SDTimeout) {
- if(card.sd2)
- errorsd("sd >=2.00 card");
- card.mmc = 1;
- break;
- }
- if(s < 0)
- errorsd("exchange voltage/sdhc support info");
+ if(s < 0) {
+ if(s == SDTimeout && !card.sd2)
+ card.mmc = 1;
+ errorsd("exchange voltage/sdhc support info", s);
+ }
v = card.resp[2]>>8;
if((v & ACMD41voltagewindow) == 0)
- errorsd("voltage not supported");
+ error("voltage not supported");
if(v & ACMD41ready) {
card.sdhc = (v & ACMD41sdhcsupported) != 0;
break;
}

if(i >= 20)
- errorsd("sd card failed to power up");
+ error("sd card failed to power up");
tsleep(&up->sleep, return0, nil, 10);
}
dprint("acmd41 done, mmc %d, sd2 %d, sdhc %d\n", card.mmc, card.sd2,
card.sdhc);
if(card.mmc)
error("mmc cards not yet supported"); // xxx p14 says this involves
sending cmd1

- if(sdcmd(&card, 2, 0, R2, 0) < 0)
- errorsd("card identification");
+ s = sdcmd(&card, 2, 0, R2, 0);
+ if(s < 0)
+ errorsd("card identification", s);
if(parsecid(&card.cid, card.resp) < 0)
- errorsd("bad cid register");
+ error("bad cid register");

i = 0;
for(;;) {
- if(sdcmd(&card, 3, 0, R6, 0) < 0)
- errorsd("getting relative address");
+ s = sdcmd(&card, 3, 0, R6, 0);
+ if(s < 0)
+ errorsd("getting relative address", s);
card.rca = (card.resp[2]>>24) & MASK(16);
v = (card.resp[2]>>8) & MASK(16);
dprint("have card rca %ux, status %lux\n", card.rca, v);
@@ -578,13 +586,14 @@
if(card.rca != 0)
break;
if(i++ == 10)
- errorsd("card insists on invalid rca 0");
+ error("card insists on invalid rca 0");
}

- if(sdcmd(&card, 9, card.rca<<16, R2, 0) < 0)
- errorsd("get csd");
+ s = sdcmd(&card, 9, card.rca<<16, R2, 0);
+ if(s < 0)
+ errorsd("get csd", s);
if(parsecsd(&card.csd, card.resp) < 0)
- errorsd("bad csd register");
+ error("bad csd register");

if(card.csd.version == 0) {
card.bs = 1<<card.csd.readblocklength;
@@ -611,21 +620,25 @@
sdclock(25*1000*1000);
}

- if(sdcmd(&card, 7, card.rca<<16, R1b, 0) < 0)
- errorsd("selecting card");
+ s = sdcmd(&card, 7, card.rca<<16, R1b, 0);
+ if(s < 0)
+ errorsd("selecting card", s);

if(0){
uchar *p = malloc(512);
- if(sdcmddma(&card, 51, 1<<0, p, 512, 1, R1, Fappdata|Fdmad2h) < 0)
- errorsd("read scr");
+ s = sdcmddma(&card, 51, 1<<0, p, 512, 1, R1, Fappdata|Fdmad2h);
+ if(s < 0)
+ errorsd("read scr", s);
}

/* xxx have to check if this is supported by card. in scr register */
- if(sdcmd(&card, 6, (1<<1), R1, Fapp) < 0)
- errorsd("setting buswidth to 4-bit");
-
- if(sdcmd(&card, 16, card.bs, R1, 0) < 0)
- errorsd("setting block length");
+ s = sdcmd(&card, 6, (1<<1), R1, Fapp);
+ if(s < 0)
+ errorsd("setting buswidth to 4-bit", s);
+
+ s = sdcmd(&card, 16, card.bs, R1, 0);
+ if(s < 0)
+ errorsd("setting block length", s);

sdiotab[Qdata].length = card.size;
card.valid = 1;
@@ -637,6 +650,7 @@
sdio(uchar *a, long n, vlong offset, int iswrite)
{
ulong cmd, arg, fl, h, nn;
+ int s;

if(card.valid == 0)
error(Enocard);
@@ -662,8 +676,9 @@
nn = n;
if(nn > 512*1024)
nn = 512*1024;
- if(sdcmddma(&card, cmd, arg, a+h, card.bs, nn/card.bs, R1, fl|Fmulti) <
0)
- errorsd("io");
+ s = sdcmddma(&card, cmd, arg, a+h, card.bs, nn/card.bs, R1, fl|Fmulti);
+ if(s < 0)
+ errorsd("io", s);
h += nn;
}
return n;
=======================================
--- /sdcard.h Thu Mar 18 06:11:29 2010
+++ /sdcard.h Fri Mar 26 09:16:04 2010
@@ -71,9 +71,7 @@
int sdhc;
uint rca;
uvlong resp[3];
- int lastcmd;
- int lastisapp;
- int lasterr;
+ ulong status;
};

int parsecid(Cid *c, uvlong *r);

==============================================================================
Revision: 869fd787f3
Author: Mechiel Lukkien <mec...@ueber.net>
Date: Sun Mar 28 07:18:45 2010
Log: use interrupts for all commands (not just dma). better error
messages. cleanups.

we now use interrupts for all commands, not just read/write (which
is done with dma). so no more polling.

propagate error messages better.

when doing large i/o transfers, release the lock in between the
512k chunks. to give other procs a chance to use the sd card.
http://code.google.com/p/inferno-kirkwood/source/detail?r=869fd787f3

Modified:
/devsdio.c
/sdcard.h

=======================================
--- /devsdio.c Fri Mar 26 09:16:04 2010
+++ /devsdio.c Sun Mar 28 07:18:45 2010
@@ -1,8 +1,7 @@
/*
- * only memory cards are supported. only sd cards for now, mmc cards seem
obsolete anyway.
+ * only memory cards are supported (not sdio). only sd cards for now, mmc
cards seem obsolete anyway.
*
* todo:
- * - use interrupts for all commands? should be better than polling.
* - don't crash when proc doing read/write is killed.
* - hook into devsd.c?
* - test with non-high capacity sd cards. i think it does need different
code.
@@ -43,7 +42,7 @@
R6,
R7,

- /* flags for cmd and cmddma */
+ /* flags for sdcmd and sdcmddma */
Fapp = 1<<0, /* app-specific command */
Fappdata= 1<<1, /* app-specific data command */
Fdmad2h = 1<<2, /* dma from device to host */
@@ -156,14 +155,6 @@
ACMD41ready = 1<<31,


- ESAcmd12Notexe = 1<<0,
- ESAcmd12Timeout = 1<<1,
- ESAcmd12CrcErr = 1<<2,
- ESAcmd12EndBitErr = 1<<3,
- ESAcmd12IndexErr = 1<<4,
- ESAcmd12RespTBi = 1<<5,
- ESAcmd12RespStartBitErr = 1<<6,
-
/* sd status, in R1 & R1b responses */
SDappcmd = 1<<5, /* next command will be interpreted as app specific */
SDreadyfordata = 1<<8, /* buffer empty signal on bus */
@@ -181,7 +172,7 @@


static Card card;
-static Rendez dmar;
+static Rendez cmdr;
static QLock sdl;

enum {
@@ -198,31 +189,42 @@


/* for bits in st, est, acmd12st registers */
-const static char *statusstrs[] = {
+static const char *statusstrs[] = {
"cmdcomplete", "xfercomplete", "blockgapevent", "dmaintr",
"txready", "rxready", "", "",
"cardintr", "readwaiton", "fifo8wfull", "fifo8wavail",
"suspended", "autocmd12done", "unexpresp", "errorintr",
};

-const static char *errstatusstrs[] = {
+static const char *errstatusstrs[] = {
"cmdtimeout", "cmdcrc", "cmdendbit", "cmdindex",
"datatimeout", "rddatacrc", "rddataend", "",
"autocmd12", "cmdstartbit", "xfersize", "resptbit",
"crcendbit", "crcstartbit", "crcstatus",
};

-const static char *acmd12ststrs[] = {
+static const char *acmd12ststrs[] = {
"acmd12notexe", "acmd12timeout", "acmd12crcerr", "acmd12endbiterr",
"acmd12indexerr", "acmd12resptbi", "acmd12respstartbiterr",
};

+static const char *sdstatusstrs[] = {
+"tm0", "tm1", "apprsvd", "akeseqerr",
+"sdiorsvd", "appcmd", "rsvd6", "rsvd7",
+"readyfordata", "st9", "st10", "st11",
+"st12", "erasereset", "noecc", "wperaseskip",
+"csdoverwrite", "rsvd17", "rsvd18", "error",
+"ccerror", "eccfail", "badcmd", "cmdcrcerr",
+"lockerr", "locked", "wpviolation", "eraseparam",
+"eraseseqerr", "blocklenerr", "addrerr", "outofrange",
+};
+
static char*
mkstr(char *p, char *e, ulong v, char **s, int ns)
{
int i;
for(i = 0; i < ns; i++)
- if(v & (1<<i))
+ if(v & 1<<i)
p = seprint(p, e, " %q", s[i]);
return p;
}
@@ -245,16 +247,6 @@
return mkstr(p, e, v, acmd12ststrs, nelem(acmd12ststrs));
}

-static const char *sdstatusstrs[] = {
-"tm0", "tm1", "apprsvd", "akeseqerr",
-"sdiorsvd", "appcmd", "rsvd6", "rsvd7",
-"readyfordata", "st9", "st10", "st11",
-"st12", "erasereset", "noecc", "wperaseskip",
-"csdoverwrite", "rsvd17", "rsvd18", "error",
-"ccerror", "eccfail", "badcmd", "cmdcrcerr",
-"lockerr", "locked", "wpviolation", "eraseparam",
-"eraseseqerr", "blocklenerr", "addrerr", "outofrange",
-};
static char *
sdstatusstr(char *p, char *e, ulong v)
{
@@ -290,43 +282,45 @@
}


-static char *errstrs[] = {
+static const char *errstrs[] = {
"success", "timeout", "card busy", "error", "interrupted", "badstatus",
};

static void
-errorsd(char *s, int e)
-{
- char buf[ERRMAX+1];
- char *p = buf;
-
- p = seprint(p, buf+sizeof buf, "%s", s);
- if(e != SDOk)
- p = seprint(p, buf+sizeof buf, ": %s", errstrs[-e]);
- if(e == SDBadstatus)
- p = seprint(p, buf+sizeof buf, " (r1status %#lux)", card.status);
+errorsd(char *s, int v)
+{
+ char buf[ERRMAX];
+ char * p = buf;
+ char * const e = buf+sizeof buf;
+
+ p = seprint(p, e, "%s", s);
+ if(v != SDOk)
+ p = seprint(p, e, ": %s", errstrs[-v]);
+ if(v == SDBadstatus)
+ p = seprint(p, e, " (r1status %#lux)", card.status);
+ if(v == SDError) {
+ p = seprint(p, e, " (est %#lux", card.status);
+ p = errstatusstr(p, e, card.status);
+ p = seprint(p, e, ")");
+ }
USED(p);
error(buf);
}

static int
-dmadone(void*)
+isdone(void *)
{
SdioReg *r = SDIOREG;
- ulong need = Scmdcomplete|Sdmaintr;
-
- if((r->st & need) == need) {
- dprint("dmadone\n");
+
+ if(r->st & r->stirq) {
+ r->stirq = 0;
return 1;
}
- dprint("not dmadone\n");
- r->stirq = Sdmaintr|Serror|Sunexpresp;
- r->estirq = ~0;
return 0;
}

/* keep in sync with R* contants */
-static ulong resptypes[] = {
+static const ulong resptypes[] = {
Respnone, Resp48, Resp48busy, Resp136, Resp48, Resp48, Resp48,
};
static int
@@ -336,9 +330,11 @@
int i, s;
ulong acmd;
ulong cmdopts, mode;
- ulong need, v;
+ ulong need;
uvlong w;

+ print("sdcmd, cmd %ld, arg %ld, fl %#lux\n", cmd, arg, fl);
+
i = 0;
for(;;) {
if((r->hoststate & (HScmdinhibit|HScardbusy)) == 0)
@@ -356,19 +352,22 @@
if(s < 0)
return s;
if((c->resp[2]>>8 & SDappcmd) == 0)
- return SDError;
+ return SDBadstatus;
}

/* clear status */
r->st = ~0;
r->est = ~0;
r->acmd12st = ~0;
+ // xxx remove?
printstatus("before cmd: ", r->st, r->est, r->acmd12st);

+ // xxx?
microdelay(1000);
+
/* prepare args & execute command */
- r->arglo = (arg>>0) & MASK(16);
- r->arghi = (arg>>16) & MASK(16);
+ r->arglo = arg>>0 & MASK(16);
+ r->arghi = arg>>16 & MASK(16);
cmdopts = CMDunexpresp;
mode = 0;
if(fl & Fdmad2h)
@@ -379,7 +378,7 @@
mode |= TMautocmd12;
r->acmd12arglo = 0;
r->acmd12arghi = 0;
- r->acmd12idx = AIcheckbusy|AIcheckindex|(12<<AIcmdshift);
+ r->acmd12idx = AIcheckbusy|AIcheckindex|12<<AIcmdshift;
}
if(fl & (Fdmad2h|Fdmah2d))
cmdopts |= CMDdatapresent;
@@ -390,44 +389,27 @@
if(rt != R0 && rt != R2 && rt != R3)
cmdopts |= CMDcmdindexcheck;
r->mode = mode;
- r->cmd = (cmd<<CMDshift)|cmdopts|resptypes[rt];
-
- if(fl & (Fdmad2h|Fdmah2d)) {
- /* wait for dma interrupt that signals completion */
- s = 0;
- while(waserror()) {
- s = SDInterrupted;
- }
- tsleep(&dmar, dmadone, nil, 5000);
- poperror();
-
- need = Scmdcomplete|Sdmaintr;
- if(s < 0 || (r->st & need) != need || (r->st & (Serror|Sunexpresp))) {
- printstatus("dma error: ", r->st, r->est, r->acmd12st);
- return SDError;
- }
- } else {
- /* poll for completion/error */
- need = Scmdcomplete;
- i = 0;
- for(;;) {
- v = r->st;
- if(v & (Serror|Sunexpresp)) {
- printstatus("error: ", v, r->est, r->acmd12st);
- if(r->est & Ecmdtimeout)
- return SDTimeout;
- return SDError;
- }
- if((v & need) == need)
- break;
- if(i++ >= 100) {
- print("command unfinished\n");
- printstatus("timeout: ", v, r->est, r->acmd12st);
- return SDError;
- }
- tsleep(&up->sleep, return0, nil, 10);
- }
- }
+ r->cmd = cmd<<CMDshift|cmdopts|resptypes[rt];
+
+ /* Scmdcomplete/Sdma and errors signal completion */
+ s = 0;
+ need = Scmdcomplete;
+ if(fl & (Fdmad2h|Fdmah2d))
+ need = Sdmaintr;
+ r->stirq = need|Sunexpresp|Serror;
+ r->estirq = ~0;
+ while(waserror())
+ s = SDInterrupted;
+ tsleep(&cmdr, isdone, nil, 5000);
+ poperror();
+
+ if(s == SDInterrupted)
+ return s;
+ if((r->st & need) == 0) {
+ card.status = r->est;
+ return SDError;
+ }
+
printstatus("success", r->st, r->est, r->acmd12st);

/* fetch the response */
@@ -467,16 +449,9 @@
}

if(rt == R1 || rt == R1b) {
- char buf[128];
-
- v = c->status = c->resp[2]>>8;
- dprint("status %#lux\n", v);
- if(v & SDbad)
+ c->status = c->resp[2]>>8;
+ if(c->status & SDbad)
return SDBadstatus;
-
- sdstatusstr(buf, buf+sizeof buf, v);
- v = v>>SDstateshift & MASK(SDstatewidth);
- dprint(" %s, st %s (%#lux)\n", buf, statestrs[v], v);
}
return 0;
}
@@ -560,9 +535,9 @@
break;
}

- if(i >= 20)
+ if(i >= 100)
error("sd card failed to power up");
- tsleep(&up->sleep, return0, nil, 10);
+ tsleep(&up->sleep, return0, nil, 5);
}
dprint("acmd41 done, mmc %d, sd2 %d, sdhc %d\n", card.mmc, card.sd2,
card.sdhc);
if(card.mmc)
@@ -632,7 +607,7 @@
}

/* xxx have to check if this is supported by card. in scr register */
- s = sdcmd(&card, 6, (1<<1), R1, Fapp);
+ s = sdcmd(&card, 6, 1<<1, R1, Fapp);
if(s < 0)
errorsd("setting buswidth to 4-bit", s);

@@ -655,7 +630,7 @@
if(card.valid == 0)
error(Enocard);

- /* xxx we should cover this cases with a buffer, and then use the same
code to allow non-sector-aligned reads? */
+ /* xxx we should cover this case with a buffer, and then use the same
code to allow non-sector-aligned reads? */
if((ulong)a % 4 != 0)
error("bad buffer alignment...");

@@ -664,11 +639,15 @@
if(n % card.bs != 0)
error("not multiple of sector size");

- cmd = iswrite ? CMDWritemulti : CMDReadmulti;
- fl = iswrite ? Fdmah2d : Fdmad2h;
+ cmd = CMDReadmulti;
+ fl = Fdmad2h;
+ if(iswrite) {
+ cmd = CMDWritemulti;
+ fl = Fdmah2d;
+ }

h = 0;
- while(h < n) {
+ for(;;) {
if(card.sdhc)
arg = (offset+h)/card.bs;
else
@@ -680,6 +659,17 @@
if(s < 0)
errorsd("io", s);
h += nn;
+ if(h >= n)
+ break;
+
+ /* give others a chance */
+ if(waserror()) {
+ qlock(&sdl);
+ nexterror();
+ }
+ qunlock(&sdl);
+ poperror();
+ qlock(&sdl);
}
return n;
}
@@ -688,35 +678,12 @@
sdiointr(Ureg*, void*)
{
SdioReg *r = SDIOREG;
- char buf[128];
- char *p, *e;
-
- if(DEBUG) {
- iprint("sdio intr %lux %lux %lux %lux\n",
- r->st,
- r->st & r->stirq,
- r->est,
- r->est & r->estirq);
-
- p = buf;
- e = p+sizeof (buf);
-
- p = statusstr(p, e, r->st);
- p = seprint(p, e, ";");
- p = errstatusstr(p, e, r->est);
- USED(p);
-
- iprint("intr: %s\n", buf);
- }
-
- /*
- * for now, interrupts are only used for dma transfers.
- * don't clear the status, just make sure we are not called again
- * before this interrupt is handled.
- */
- wakeup(&dmar);
- r->stirq &= ~Sdmaintr;
+
+ /* disable interrupt, st & est are unchanged, caller reads & clears them
before next cmd. */
+ r->stirq = 0;
+ r->estirq = 0;
intrclear(Irqlo, IRQ0sdio);
+ wakeup(&cmdr);
}

static void
=======================================
--- /sdcard.h Fri Mar 26 09:16:04 2010
+++ /sdcard.h Sun Mar 28 07:18:45 2010
@@ -71,7 +71,7 @@
int sdhc;
uint rca;
uvlong resp[3];
- ulong status;
+ ulong status; /* r1 card status, for SDBadstatus; SDIOREG->est for
SDError */
};

int parsecid(Cid *c, uvlong *r);

Reply all
Reply to author
Forward
0 new messages