static int w_write(Ctlr* ctlr, int type, int off, void* buf, ulong len) { int tries; for (tries=0; tries < WTmOut; tries++) { if(w_seek(ctlr, type, off, 0)) { DEBUG("wavelan: w_write: seek failed\n"); return 0; } csr_outss(ctlr, WR_Data0, buf, len/2); csr_outs(ctlr, WR_Data0, 0xdead); csr_outs(ctlr, WR_Data0, 0xbeef); if(w_seek(ctlr, type, off + len, 0)) { DEBUG("wavelan: write seek failed\n"); return 0; } if(csr_ins(ctlr, WR_Data0) == 0xdead) if(csr_ins(ctlr, WR_Data0) == 0xbeef) return len; DEBUG("wavelan: Hermes bug byte.\n"); return 0; } DEBUG("wavelan: tx timeout\n"); return 0; }
int w_cmd(Ctlr *ctlr, ushort cmd, ushort arg) { int i, rc; for(i=0; i<WTmOut; i++) if((csr_ins(ctlr, WR_Cmd)&WCmdBusy) == 0) break; if(i==WTmOut){ print("#l%d: issuing cmd %.4ux: %.4ux\n", ctlr->ctlrno, cmd, csr_ins(ctlr, WR_Cmd)); return -1; } csr_outs(ctlr, WR_Parm0, arg); csr_outs(ctlr, WR_Cmd, cmd); for(i=0; i<WTmOut; i++) if(csr_ins(ctlr, WR_EvSts)&WCmdEv) break; if(i==WTmOut){ /* * WCmdIni can take a really long time. */ enum { IniTmOut = 2000 }; for(i=0; i<IniTmOut; i++){ if(csr_ins(ctlr, WR_EvSts)&WCmdEv) break; microdelay(100); } if(i < IniTmOut) if(0) print("#l%d: long cmd %.4ux %d\n", ctlr->ctlrno, cmd, i); if(i == IniTmOut){ print("#l%d: execing cmd %.4ux: %.4ux\n", ctlr->ctlrno, cmd, csr_ins(ctlr, WR_EvSts)); return -1; } } rc = csr_ins(ctlr, WR_Sts); csr_ack(ctlr, WCmdEv); if((rc&WCmdMsk) != (cmd&WCmdMsk)){ print("#l%d: cmd %.4ux: status %.4ux\n", ctlr->ctlrno, cmd, rc); return -1; } if(rc&WResSts){ /* * Don't print; this happens on every WCmdAccWr for some reason. */ if(0) print("#l%d: cmd %.4ux: status %.4ux\n", ctlr->ctlrno, cmd, rc); return -1; } return 0; }
static int w_seek(Ctlr* ctlr, ushort id, ushort offset, int chan) { int i, rc; static ushort sel[] = { WR_Sel0, WR_Sel1 }; static ushort off[] = { WR_Off0, WR_Off1 }; if(chan != 0 && chan != 1) panic("wavelan: bad chan"); csr_outs(ctlr, sel[chan], id); csr_outs(ctlr, off[chan], offset); for (i=0; i<WTmOut; i++){ rc = csr_ins(ctlr, off[chan]); if((rc & (WBusyOff|WErrOff)) == 0) return 0; } return -1; }
static void w_intr(Ether *ether) { int rc, txid; Ctlr* ctlr = (Ctlr*) ether->ctlr; if((ctlr->state & Power) == 0) return; if((ctlr->state & Attached) == 0){ csr_ack(ctlr, 0xffff); csr_outs(ctlr, WR_IntEna, 0); return; } rc = csr_ins(ctlr, WR_EvSts); csr_ack(ctlr, ~WEvs); // Not interested in them if(rc & WRXEv){ w_rxdone(ether); csr_ack(ctlr, WRXEv); } if(rc & WTXEv){ w_txdone(ctlr, rc); csr_ack(ctlr, WTXEv); } if(rc & WAllocEv){ ctlr->nalloc++; txid = csr_ins(ctlr, WR_Alloc); csr_ack(ctlr, WAllocEv); if(txid == ctlr->txdid){ if((rc & WTXEv) == 0) w_txdone(ctlr, rc); } } if(rc & WInfoEv){ ctlr->ninfo++; w_info(ether, ctlr); csr_ack(ctlr, WInfoEv); } if(rc & WTxErrEv){ w_txdone(ctlr, rc); csr_ack(ctlr, WTxErrEv); } if(rc & WIDropEv){ ctlr->nidrop++; csr_ack(ctlr, WIDropEv); } w_txstart(ether); }
static int w_alloc(Ctlr* ctlr, int len) { int rc; int i,j; if(w_cmd(ctlr, WCmdMalloc, len)==0) for (i = 0; i<WTmOut; i++) if(csr_ins(ctlr, WR_EvSts) & WAllocEv){ csr_ack(ctlr, WAllocEv); rc=csr_ins(ctlr, WR_Alloc); if(w_seek(ctlr, rc, 0, 0)) return -1; len = len/2; for (j=0; j<len; j++) csr_outs(ctlr, WR_Data0, 0); return rc; } return -1; }
void w_intdis(Ctlr* ctlr) { csr_outs(ctlr, WR_IntEna, 0); csr_ack(ctlr, 0xffff); }
static void csr_ack(Ctlr *ctlr, int ev) { csr_outs(ctlr, WR_EvAck, ev); }
static void w_intena(Ctlr* ctlr) { csr_outs(ctlr, WR_IntEna, WEvs); }