/* * try to confirm sane operation */ void dmatest(void) { int n, done; uchar *bp; static ulong pat = 0x87654321; static Rendez trendez; if (up == nil) panic("dmatest: up not set yet"); bp = (uchar *)KADDR(PHYSDRAM + 128*MB); memset(bp, Testbyte, Scratch); done = 0; dmastart((void *)PADDR(bp), Postincr, (void *)PADDR(&pat), Const, Testsize, &trendez, &done); sleep(&trendez, istestdmadone, &done); cachedinvse(bp, Scratch); if (((ulong *)bp)[0] != pat) panic("dmainit: copied incorrect data %#lux != %#lux", ((ulong *)bp)[0], pat); for (n = Testsize; n < Scratch && bp[n] != Testbyte; n++) ; if (n >= Scratch) panic("dmainit: ran wild over memory, clobbered ≥%,d bytes", n); if (bp[n] == Testbyte && n != Testsize) iprint("dma: %d-byte dma stopped after %d bytes!\n", Testsize, n); }
void spirw(uint cs, void *buf, int len) { Spiregs *r; assert(cs <= 2); assert(len < (1<<16)); qlock(&spi.lock); if(waserror()){ qunlock(&spi.lock); nexterror(); } if(spi.regs == 0) spiinit(); r = spi.regs; r->dlen = len; r->cs = (cs << Csshift) | Rxclear | Txclear | Dmaen | Adcs | Ta; /* * Start write channel before read channel - cache wb before inv */ dmastart(DmaChanSpiTx, DmaDevSpiTx, DmaM2D, buf, &r->data, len); dmastart(DmaChanSpiRx, DmaDevSpiRx, DmaD2M, &r->data, buf, len); if(dmawait(DmaChanSpiRx) < 0) error(Eio); cachedinvse(buf, len); r->cs = 0; qunlock(&spi.lock); poperror(); }
static long ctltrans(Ep *ep, uchar *req, long n) { Hostchan *hc; Epio *epio; Block *b; uchar *data; int datalen; epio = ep->aux; if(epio->cb != nil){ freeb(epio->cb); epio->cb = nil; } if(n < Rsetuplen) error(Ebadlen); if(req[Rtype] & Rd2h){ datalen = GET2(req+Rcount); if(datalen <= 0 || datalen > Maxctllen) error(Ebadlen); /* XXX cache madness */ epio->cb = b = allocb(ROUND(datalen, ep->maxpkt)); assert(((uintptr)b->wp & (BLOCKALIGN-1)) == 0); memset(b->wp, 0x55, b->lim - b->wp); cachedwbinvse(b->wp, b->lim - b->wp); data = b->wp; }else{ b = nil; datalen = n - Rsetuplen; data = req + Rsetuplen; } hc = chanalloc(ep); if(waserror()){ chanrelease(ep, hc); if(strcmp(up->errstr, Estalled) == 0) return 0; nexterror(); } chansetup(hc, ep); chanio(ep, hc, Epout, SETUP, req, Rsetuplen); if(req[Rtype] & Rd2h){ if(ep->dev->hub <= 1){ ep->toggle[Read] = DATA1; b->wp += multitrans(ep, hc, Read, data, datalen); }else b->wp += chanio(ep, hc, Epin, DATA1, data, datalen); chanio(ep, hc, Epout, DATA1, nil, 0); cachedinvse(b->rp, BLEN(b)); n = Rsetuplen; }else{ if(datalen > 0) chanio(ep, hc, Epout, DATA1, data, datalen); chanio(ep, hc, Epin, DATA1, nil, 0); n = Rsetuplen + datalen; } chanrelease(ep, hc); poperror(); return n; }
static void receive(Ether *ether) { int i; ulong n; Block *b; Ctlr *ctlr = ether->ctlr; Rx *r; ethercheck(ether); for (i = Nrx-2; i > 0; i--) { r = &ctlr->rx[ctlr->rxhead]; /* *r is uncached */ assert(((uintptr)r & (Descralign - 1)) == 0); if(r->cs & RCSdmaown) /* descriptor busy? */ break; b = ctlr->rxb[ctlr->rxhead]; /* got input buffer? */ if (b == nil) panic("ether1116: nil ctlr->rxb[ctlr->rxhead] " "in receive"); ctlr->rxb[ctlr->rxhead] = nil; ctlr->rxhead = NEXT(ctlr->rxhead, Nrx); if((r->cs & (RCSfirst|RCSlast)) != (RCSfirst|RCSlast)) { ctlr->nofirstlast++; /* partial packet */ freeb(b); continue; } if(r->cs & RCSmacerr) { freeb(b); continue; } n = r->countsize >> 16; /* TODO includes 2 pad bytes? */ assert(n >= 2 && n < 2048); /* clear any cached packet or part thereof */ l2cacheuinvse(b->rp, n+2); cachedinvse(b->rp, n+2); b->wp = b->rp + n; /* * skip hardware padding intended to align ipv4 address * in memory (mv-s104860-u0 §8.3.4.1) */ b->rp += 2; etheriq(ether, b, 1); etheractive(ether); if (i % (Nrx / 2) == 0) { rxreplenish(ctlr); rxkick(ctlr); } } rxreplenish(ctlr); rxkick(ctlr); }
static void emmcio(int write, uchar *buf, int len) { u32int *r; int i; r = (u32int*)EMMCREGS; assert((len&3) == 0); okay(1); if(waserror()){ okay(0); nexterror(); } if(write) dmastart(DmaChanEmmc, DmaDevEmmc, DmaM2D, buf, &r[Data], len); else dmastart(DmaChanEmmc, DmaDevEmmc, DmaD2M, &r[Data], buf, len); if(dmawait(DmaChanEmmc) < 0) error(Eio); if(!write) cachedinvse(buf, len); WR(Irpten, Datadone|Err); tsleep(&emmc.r, datadone, 0, 3000); WR(Irpten, 0); emmc.datadone = 0; i = r[Interrupt]; if((i & Datadone) == 0){ print("emmcio: %d timeout intr %ux stat %ux\n", write, i, r[Status]); WR(Interrupt, i); error(Eio); } if(i & Err){ print("emmcio: %d error intr %ux stat %ux\n", write, r[Interrupt], r[Status]); WR(Interrupt, i); error(Eio); } if(i) WR(Interrupt, i); poperror(); okay(0); }
/* * called on a cpu other than 0 from cpureset in l.s, * from _vrst in lexception.s. * mmu and l1 (and system-wide l2) caches and coherency (smpon) are on, * but interrupts are disabled. * our mmu is using an exact copy of cpu0's l1 page table * as it was after userinit ran. */ void cpustart(void) { int ms; ulong *evp; Power *pwr; up = nil; if (active.machs & (1<<m->machno)) { serialputc('?'); serialputc('r'); panic("cpu%d: resetting after start", m->machno); } assert(m->machno != 0); errata(); cortexa9cachecfg(); memdiag(&testmem); machinit(); /* bumps nmach, adds bit to machs */ machoff(m->machno); /* not ready to go yet */ /* clock signals and scu are system-wide and already on */ clockshutdown(); /* kill any watch-dog timer */ trapinit(); clockinit(); /* sets loop delay */ timersinit(); cpuidprint(); /* * notify cpu0 that we're up so it can proceed to l1diag. */ evp = (ulong *)soc.exceptvec; /* magic */ *evp = m->machno; coherence(); l1diag(); /* contend with other cpus to verify sanity */ /* * pwr->noiopwr == 0 * pwr->detect == 0x1ff (default, all disabled) */ pwr = (Power *)soc.power; assert(pwr->gatests == MASK(7)); /* everything has power */ /* * 8169 has to initialise before we get past this, thus cpu0 * has to schedule processes first. */ if (Debug) iprint("cpu%d: waiting for 8169\n", m->machno); for (ms = 0; !l1ptstable.word && ms < 5000; ms += 10) { delay(10); cachedinvse(&l1ptstable.word, sizeof l1ptstable.word); } if (!l1ptstable.word) iprint("cpu%d: 8169 unreasonably slow; proceeding\n", m->machno); /* now safe to copy cpu0's l1 pt in mmuinit */ mmuinit(); /* update our l1 pt from cpu0's */ fpon(); machon(m->machno); /* now ready to go and be scheduled */ if (Debug) iprint("cpu%d: scheding\n", m->machno); schedinit(); panic("cpu%d: schedinit returned", m->machno); }