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) + CACHELINESZ); b->wp = (uchar*)ROUND((uintptr)b->wp, CACHELINESZ); //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->env->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); 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; }
void* mmuuncache(void* v, usize size) { int x; PTE *pte; uintptr va; /* * Simple helper for ucalloc(). * Uncache a Section, must already be * valid in the MMU. */ va = PTR2UINT(v); assert(!(va & (1*MiB-1)) && size == 1*MiB); x = L1X(va); pte = &m->mmul1[x]; if((*pte & (Fine|Section|Coarse)) != Section) return nil; *pte &= ~(Cached|Buffered); mmuinvalidateaddr(va); cachedwbinvse(pte, 4); return v; }
/* go to user space */ void kexit(Ureg*) { uvlong t; Tos *tos; /* precise time accounting, kernel exit */ tos = (Tos*)(USTKTOP-sizeof(Tos)); t = fastticks(nil); tos->kcycles += t - up->kentry; tos->pcycles = up->pcycles; tos->cyclefreq = Frequency; tos->pid = up->pid; /* make visible immediately to user proc */ cachedwbinvse(tos, sizeof *tos); }
static int vcreq(int tag, void *buf, int vallen, int rsplen) { uintptr r; int n; Prophdr *prop; uintptr aprop; static int busaddr = 1; if(rsplen < vallen) rsplen = vallen; rsplen = (rsplen+3) & ~3; prop = (Prophdr*)(VCBUFFER); n = sizeof(Prophdr) + rsplen + 8; memset(prop, 0, n); prop->len = n; prop->req = Req; prop->tag = tag; prop->tagbuflen = rsplen; prop->taglen = vallen; if(vallen > 0) memmove(prop->data, buf, vallen); cachedwbinvse(prop, prop->len); for(;;){ aprop = busaddr? dmaaddr(prop) : PTR2UINT(prop); vcwrite(ChanProps, aprop); r = vcread(ChanProps); if(r == aprop) break; if(!busaddr) return -1; busaddr = 0; } if(prop->req == RspOk && prop->tag == tag && (prop->taglen&TagResp)) { if((n = prop->taglen & ~TagResp) < rsplen) rsplen = n; memmove(buf, prop->data, rsplen); }else rsplen = -1; return rsplen; }
static int vcreq(int tag, void *buf, int vallen, int rsplen) { uintptr r; int n; Prophdr *prop; static uintptr base = BUSDRAM; if(rsplen < vallen) rsplen = vallen; rsplen = (rsplen+3) & ~3; prop = (Prophdr*)(VCBUFFER); n = sizeof(Prophdr) + rsplen + 8; memset(prop, 0, n); prop->len = n; prop->req = Req; prop->tag = tag; prop->tagbuflen = rsplen; prop->taglen = vallen; if(vallen > 0) memmove(prop->data, buf, vallen); cachedwbinvse(prop, prop->len); for(;;){ vcwrite(ChanProps, PADDR(prop) + base); r = vcread(ChanProps); if(r == PADDR(prop) + base) break; if(base == 0) return -1; base = 0; } if(prop->req == RspOk && prop->tag == tag && (prop->taglen&TagResp)) { if((n = prop->taglen & ~TagResp) < rsplen) rsplen = n; memmove(buf, prop->data, rsplen); }else rsplen = -1; return rsplen; }
uintptr mmukunmap(uintptr va, uintptr pa, usize size) { int x; PTE *pte; /* * Stub. */ assert(!(va & (1*MiB-1)) && !(pa & (1*MiB-1)) && size == 1*MiB); x = L1X(va); pte = &m->mmul1[x]; if(*pte != (pa|Dom0|L1AP(Krw)|Section)) return 0; *pte = Fault; mmuinvalidateaddr(va); cachedwbinvse(pte, 4); return va; }
void* fbinit(int set, int *width, int *height, int *depth) { Fbinfo *fi; uintptr va; if(!set) fbdefault(width, height, depth); /* Screen width must be a multiple of 16 */ *width &= ~0xF; fi = (Fbinfo*)(VCBUFFER); memset(fi, 0, sizeof(*fi)); fi->xres = fi->xresvirtual = *width; fi->yres = fi->yresvirtual = *height; fi->bpp = *depth; cachedwbinvse(fi, sizeof(*fi)); vcwrite(ChanFb, DMAADDR(fi)); if(vcread(ChanFb) != 0) return 0; va = mmukmap(FRAMEBUFFER, PADDR(fi->base), fi->screensize); if(va) memset((char*)va, 0x7F, fi->screensize); return (void*)va; }
void clockinit(void) { int i, s; Timerregs *tn; clockshutdown(); /* turn cycle counter on */ cpwrsc(0, CpCLD, CpCLDena, CpCLDenacyc, 1<<31); /* turn all counters on and clear the cycle counter */ cpwrsc(0, CpCLD, CpCLDena, CpCLDenapmnc, 1<<2 | 1); /* let users read the cycle counter directly */ cpwrsc(0, CpCLD, CpCLDena, CpCLDenapmnc, 1); ilock(&clklck); m->fastclock = 1; m->ticks = ticks = 0; /* * T0 is a freerunning timer (cycle counter); it wraps, * automatically reloads, and does not dispatch interrupts. */ tn = (Timerregs *)Tn0; tn->tcrr = Freebase; /* count up to 0 */ tn->tldr = Freebase; coherence(); tn->tclr = Ar | St; iunlock(&clklck); /* * T1 is the interrupting timer and does not participate * in measuring time. It is initially set to HZ. */ tn = (Timerregs *)Tn1; irqenable(Tn0irq+1, clockintr, tn, "clock"); ilock(&clklck); tn->tcrr = -Tcycles; /* approx.; count up to 0 */ tn->tldr = -Tcycles; coherence(); tn->tclr = Ar | St; coherence(); tn->tier = Ovf_it; coherence(); iunlock(&clklck); /* * verify sanity of timer1 */ s = spllo(); /* risky */ for (i = 0; i < 5 && ticks == 0; i++) { delay(10); cachedwbinvse(&ticks, sizeof ticks); } splx(s); if (ticks == 0) { if (tn->tcrr == 0) panic("clock not interrupting"); else if (tn->tcrr == tn->tldr) panic("clock not ticking at all"); #ifdef PARANOID else panic("clock running very slowly"); #endif } guessmips(issue1loop, "single"); if (Debug) iprint(", "); guessmips(issue2loop, "dual"); if (Debug) iprint("\n"); /* * m->delayloop should be the number of delay loop iterations * needed to consume 1 ms. 2 is min. instructions in the delay loop. */ m->delayloop = m->cpuhz / (1000 * 2); // iprint("m->delayloop = %lud\n", m->delayloop); /* * desynchronize the processor clocks so that they all don't * try to resched at the same time. */ delay(m->machno*2); }
void segflush(void* p, ulong n) { cachedwbinvse(p,n); cacheiinvse(p,n); }
void dmastart(int chan, int dev, int dir, void *src, void *dst, int len) { Ctlr *ctlr; Cb *cb; int ti; ctlr = &dma[chan]; if(ctlr->regs == nil){ ctlr->regs = (u32int*)(DMAREGS + chan*Regsize); ctlr->cb = xspanalloc(sizeof(Cb), Cbalign, 0); assert(ctlr->cb != nil); dmaregs[Enable] |= 1<<chan; ctlr->regs[Cs] = Reset; while(ctlr->regs[Cs] & Reset) ; intrenable(IRQDMA(chan), dmainterrupt, ctlr, 0, "dma"); } cb = ctlr->cb; ti = 0; switch(dir){ case DmaD2M: cachedwbinvse(dst, len); ti = Srcdreq | Destinc; cb->sourcead = DMAIO(src); cb->destad = DMAADDR(dst); break; case DmaM2D: cachedwbse(src, len); ti = Destdreq | Srcinc; cb->sourcead = DMAADDR(src); cb->destad = DMAIO(dst); break; case DmaM2M: cachedwbse(src, len); cachedwbinvse(dst, len); ti = Srcinc | Destinc; cb->sourcead = DMAADDR(src); cb->destad = DMAADDR(dst); break; } cb->ti = ti | dev<<Permapshift | Inten; cb->txfrlen = len; cb->stride = 0; cb->nextconbk = 0; cachedwbse(cb, sizeof(Cb)); ctlr->regs[Cs] = 0; microdelay(1); ctlr->regs[Conblkad] = DMAADDR(cb); DBG print("dma start: %ux %ux %ux %ux %ux %ux\n", cb->ti, cb->sourcead, cb->destad, cb->txfrlen, cb->stride, cb->nextconbk); DBG print("intstatus %ux\n", dmaregs[Intstatus]); dmaregs[Intstatus] = 0; ctlr->regs[Cs] = Int; microdelay(1); coherence(); DBG dumpdregs("before Active", ctlr->regs); ctlr->regs[Cs] = Active; DBG dumpdregs("after Active", ctlr->regs); }