void timerdel(Timer *dt) { Timers *tt; uvlong when; ilock(dt); if(tt = dt->tt){ ilock(tt); when = tdel(dt); if(when && tt == &timers[m->machno]) timerset(tt->head->twhen); iunlock(tt); } iunlock(dt); }
/* * Set the time of day struct */ void todset(vlong t, vlong delta, int n) { if(!tod.init) todinit(); ilock(&tod); if(t >= 0){ tod.off = t; tod.last = fastticks(nil); tod.lasttime = 0; tod.delta = 0; tod.sstart = tod.send; } else { if(n <= 0) n = 1; n *= HZ; if(delta < 0 && n > -delta) n = -delta; if(delta > 0 && n > delta) n = delta; delta = delta/n; tod.sstart = MACHP(0)->ticks; tod.send = tod.sstart + n; tod.delta = delta; } iunlock(&tod); }
// Look up and return the inode for a path name. // If parent != 0, return the inode for the parent and copy the final // path element into name, which must have room for DIRSIZ bytes. // Must be called inside a transaction since it calls iput(). static struct inode* namex(char *path, int nameiparent, char *name) { struct inode *ip, *next; if(*path == '/') ip = iget(ROOTDEV, ROOTINO); else ip = idup(proc->cwd); while((path = skipelem(path, name)) != 0){ ilock(ip); if(ip->type != T_DIR){ iunlockput(ip); return 0; } if(nameiparent && *path == '\0'){ // Stop one level early. iunlock(ip); return ip; } if((next = dirlookup(ip, name, 0)) == 0){ iunlockput(ip); return 0; } iunlockput(ip); ip = next; } if(nameiparent){ iput(ip); return 0; } return ip; }
/* * Mark a queue as closed. No further IO is permitted. * All blocks are released. */ void qclose(Queue *q) { Block *bfirst; if(q == nil) return; /* mark it */ ilock(q); q->state |= Qclosed; q->state &= ~(Qflow|Qstarve); kstrcpy(q->err, Ehungup, ERRMAX); bfirst = q->bfirst; q->bfirst = nil; q->len = 0; q->dlen = 0; q->noblock = 0; iunlock(q); /* free queued blocks */ freeblist(bfirst); /* wake up readers/writers */ wakeup(&q->rr); wakeup(&q->wr); }
static void shutdown(Hci *hp) { int i; Ctlr *ctlr; Eopio *opio; ctlr = hp->aux; ilock(ctlr); opio = ctlr->opio; opio->cmd |= Chcreset; /* controller reset */ coherence(); for(i = 0; i < 100; i++){ if((opio->cmd & Chcreset) == 0) break; delay(1); } if(i >= 100) print("ehci %#p controller reset timed out\n", ctlr->capio); delay(100); ehcirun(ctlr, 0); opio->frbase = 0; coherence(); iunlock(ctlr); }
void timerdel(Timer *dt) { Timers *tt; int64_t when; ilock(&dt->l); if((tt = dt->tt) != nil){ ilock(&tt->l); when = tdel(dt); if(when && tt == &timers[machp()->machno]) timerset(tt->head->twhen); iunlock(&tt->l); } iunlock(&dt->l); }
static void cecputs(char *str, int n) { int i, c, wake; Conn *cp; wake = 0; for(cp = conn; cp < conn+Nconns; cp++){ ilock(cp); if(cp->state == Copen){ for (i = 0; i < n; i++){ c = str[i]; if(c == 0) continue; /* BOTCH */ if(c == '\n') cbput(cp, '\r'); cbput(cp, c); } cp->stalled = 1; wake = 1; } iunlock(cp); } if(wake){ tcond = 1; wakeup(&trendez); } }
static void ks8695_modemintr(Ureg*, void *arg) { Ctlr *ctlr; Uart *uart; int old, r; uart = arg; ctlr = uart->regs; r = csr8r(ctlr, Msr); if(r & Dcts){ ilock(&uart->tlock); old = uart->cts; uart->cts = r & Cts; if(old == 0 && uart->cts) uart->ctsbackoff = 2; iunlock(&uart->tlock); } if(r & Ddsr){ old = r & Dsr; if(uart->hup_dsr && uart->dsr && !old) uart->dohup = 1; uart->dsr = old; } if(r & Ddcd){ old = r & Dcd; if(uart->hup_dcd && uart->dcd && !old) uart->dohup = 1; uart->dcd = old; } }
void * osi_UFSOpen(afs_dcache_id_t *ainode) { struct inode *ip; struct osi_file *afile = NULL; extern int cacheDiskType; afs_int32 code = 0; int dummy; AFS_STATCNT(osi_UFSOpen); if (cacheDiskType != AFS_FCACHE_TYPE_UFS) { osi_Panic("UFSOpen called for non-UFS cache\n"); } if (!afs_osicred_initialized) { /* valid for alpha_osf, SunOS, Ultrix */ memset(&afs_osi_cred, 0, sizeof(afs_ucred_t)); crhold(&afs_osi_cred); /* don't let it evaporate, since it is static */ afs_osicred_initialized = 1; } afile = osi_AllocSmallSpace(sizeof(struct osi_file)); setuerror(0); AFS_GUNLOCK(); ip = (struct inode *)igetinode(afs_cacheVfsp, (dev_t) cacheDev.dev, (ino_t) ainode->ufs, &dummy); AFS_GLOCK(); if (getuerror()) { osi_FreeSmallSpace(afile); osi_Panic("UFSOpen: igetinode failed"); } iunlock(ip); afile->vnode = ITOV(ip); afile->size = VTOI(afile->vnode)->i_size; afile->offset = 0; afile->proc = (int (*)())0; return (void *)afile; }
void freeb(Block *b) { void *dead = (void*)Bdead; uint8_t *p; if(b == nil) return; /* * drivers which perform non cache coherent DMA manage their own buffer * pool of uncached buffers and provide their own free routine. */ if(b->free) { b->free(b); return; } if(b->flag & BINTR) { ilock(&ialloc); ialloc.bytes -= b->lim - b->base; iunlock(&ialloc); } p = b->base; /* poison the block in case someone is still holding onto it */ b->next = dead; b->rp = dead; b->wp = dead; b->lim = dead; b->base = dead; free(p); }
Block* iallocb(int size) { Block *b; static int m1, m2; if(ialloc.bytes > conf.ialloc){ if((m1++%10000)==0) print("iallocb: limited %lud/%lud\n", ialloc.bytes, conf.ialloc); return 0; } if((b = _allocb(size)) == nil){ if((m2++%10000)==0) print("iallocb: no memory %lud/%lud\n", ialloc.bytes, conf.ialloc); return nil; } setmalloctag(b, getcallerpc(&size)); b->flag = BINTR; ilock(&ialloc.lk); ialloc.bytes += b->lim - b->base; iunlock(&ialloc.lk); return b; }
int qpassnolim(Queue *q, Block *b) { int dlen, len, dowakeup; /* sync with qread */ dowakeup = 0; ilock(q); if(q->state & Qclosed){ freeblist(b); iunlock(q); return BALLOC(b); } /* add buffer to queue */ if(q->bfirst) q->blast->next = b; else q->bfirst = b; len = BALLOC(b); dlen = BLEN(b); QDEBUG checkb(b, "qpass"); while(b->next){ b = b->next; QDEBUG checkb(b, "qpass"); len += BALLOC(b); dlen += BLEN(b); } q->blast = b; q->len += len; q->dlen += dlen; if(q->len >= q->limit/2) q->state |= Qflow; if(q->state & Qstarve){ q->state &= ~Qstarve; dowakeup = 1; } iunlock(q); if(dowakeup) wakeup(&q->rr); return len; }
void intrenable(int irq, void (*f)(Ureg*, void*), void* a, int tbdf, char *name) { int vno; Vctl *v; if(f == nil){ print("intrenable: nil handler for %d, tbdf 0x%uX for %s\n", irq, tbdf, name); return; } if(tbdf != BUSUNKNOWN && (irq == 0xff || irq == 0)){ print("intrenable: got unassigned irq %d, tbdf 0x%uX for %s\n", irq, tbdf, name); irq = -1; } if((v = xalloc(sizeof(Vctl))) == nil) panic("intrenable: out of memory"); v->isintr = 1; v->irq = irq; v->tbdf = tbdf; v->f = f; v->a = a; strncpy(v->name, name, KNAMELEN-1); v->name[KNAMELEN-1] = 0; ilock(&vctllock); vno = arch->intrenable(v); if(vno == -1){ iunlock(&vctllock); print("intrenable: couldn't enable irq %d, tbdf 0x%uX for %s\n", irq, tbdf, v->name); xfree(v); return; } if(vctl[vno]){ if(vctl[vno]->isr != v->isr || vctl[vno]->eoi != v->eoi) panic("intrenable: handler: %s %s %#p %#p %#p %#p", vctl[vno]->name, v->name, vctl[vno]->isr, v->isr, vctl[vno]->eoi, v->eoi); v->next = vctl[vno]; } vctl[vno] = v; iunlock(&vctllock); }
static struct inode *_name(char *p, int nameiparent, char *dirname) { struct inode *in, *next; char *name; char arr[64]; char *path = arr; strcpy(arr, p); if(*path == '/') { in = iget(0, 1); while(*++path == '/') ; } else in = idup(current_proc->cwd); name = strtok(path, "/"); while(name) { // printk("File system search:%s\n", name); ilock(in); if(!ISDIR(in->mode)) { iunlock(in); iput(in); return NULL; } if(nameiparent && !tok_hasnext()) { iunlock(in); if(dirname) strcpy(dirname, name); return in; } if(!(next = dirlookup(in, name, 0))) { iunlock(in); iput(in); return NULL; } iunlock(in); iput(in); in = next; if(!tok_hasnext() && dirname) strcpy(dirname, name); name = strtok(NULL, "/"); } return in; }
/* * copy from offset in the queue */ Block* qcopy(Queue *q, int len, ulong offset) { int sofar; int n; Block *b, *nb; uchar *p; nb = allocb(len); ilock(q); /* go to offset */ b = q->bfirst; for(sofar = 0; ; sofar += n){ if(b == nil){ iunlock(q); return nb; } n = BLEN(b); if(sofar + n > offset){ p = b->rp + offset - sofar; n -= offset - sofar; break; } QDEBUG checkb(b, "qcopy"); b = b->next; } /* copy bytes from there */ for(sofar = 0; sofar < len;){ if(n > len - sofar) n = len - sofar; memmove(nb->wp, p, n); qcopycnt += n; sofar += n; nb->wp += n; b = b->next; if(b == nil) break; n = BLEN(b); p = b->rp; } iunlock(q); return nb; }
static void w_timer(void* arg) { Ether* ether = (Ether*) arg; Ctlr* ctlr = (Ctlr*)ether->ctlr; ctlr->timerproc = up; for(;;) { tsleep(&up->sleep, return0, 0, MSperTick); ctlr = (Ctlr*)ether->ctlr; if(ctlr == 0) break; if((ctlr->state & (Attached|Power)) != (Attached|Power)) continue; ctlr->ticks++; ilock(ctlr); // Seems that the card gets frames BUT does // not send the interrupt; this is a problem because // I suspect it runs out of receive buffers and // stops receiving until a transmit watchdog // reenables the card. // The problem is serious because it leads to // poor rtts. // This can be seen clearly by commenting out // the next if and doing a ping: it will stop // receiving (although the icmp replies are being // issued from the remote) after a few seconds. // Of course this `bug' could be because I'm reading // the card frames in the wrong way; due to the // lack of documentation I cannot know. if(csr_ins(ctlr, WR_EvSts)&WEvs) { ctlr->tickintr++; w_intr(ether); } if((ctlr->ticks % 10) == 0) { if(ctlr->txtmout && --ctlr->txtmout == 0) { ctlr->nwatchdogs++; w_txdone(ctlr, WTxErrEv); if(w_enable(ether)) { DEBUG("wavelan: wdog enable failed\n"); } w_txstart(ether); } if((ctlr->ticks % 120) == 0) if(ctlr->txbusy == 0) w_cmd(ctlr, WCmdEnquire, WTyp_Stats); if(ctlr->scanticks > 0) if((ctlr->ticks % ctlr->scanticks) == 0) if(ctlr->txbusy == 0) w_cmd(ctlr, WCmdEnquire, WTyp_Scan); } iunlock(ctlr); } pexit("terminated", 0); }
static void igbetransmit(Ether* edev) { Block *bp; Ctlr *ctlr; Tdesc *tdesc; RingBuf *tb; int tdh; /* * For now there are no smarts here. Tuning comes later. */ ctlr = edev->ctlr; ilock(&ctlr->tdlock); /* * Free any completed packets * - try to get the soft tdh to catch the tdt; * - if the packet had an underrun bump the threshold * - the Tu bit doesn't seem to ever be set, perhaps * because Rs mode is used? */ tdh = ctlr->tdh; for(;;){ tdesc = &ctlr->tdba[tdh]; if(!(tdesc->status & Tdd)) break; if(tdesc->status & Tu){ ctlr->ett++; csr32w(ctlr, Ett, ctlr->ett); } tdesc->status = 0; if(ctlr->tb[tdh] != nil){ freeb(ctlr->tb[tdh]); ctlr->tb[tdh] = nil; } tdh = NEXT(tdh, Ntdesc); } ctlr->tdh = tdh; /* copy packets from the software RingBuf to the transmission q */ /* from boot ether83815.c */ while((tb = &edev->tb[edev->ti])->owner == Interface){ bp = fromringbuf(edev); /* put the buffer on the transmit queue */ if(ctlr->bqhead) ctlr->bqtail->next = bp; else ctlr->bqhead = bp; ctlr->bqtail = bp; txstart(edev); /* kick transmitter */ tb->owner = Host; /* give descriptor back */ edev->ti = NEXT(edev->ti, edev->ntb); } iunlock(&ctlr->tdlock); }
static void igbeim(Ctlr* ctlr, int im) { ilock(&ctlr->imlock); ctlr->im |= im; csr32w(ctlr, Ims, ctlr->im); iunlock(&ctlr->imlock); }
int vgaxi(long port, uchar index) { uchar data; ilock(&vgaxlock); switch(port){ case Seqx: case Crtx: case Grx: outb(port, index); data = inb(port+1); break; case Attrx: /* * Allow processor access to the colour * palette registers. Writes to Attrx must * be preceded by a read from Status1 to * initialise the register to point to the * index register and not the data register. * Processor access is allowed by turning * off bit 0x20. */ inb(Status1); if(index < 0x10){ outb(Attrx, index); data = inb(Attrx+1); inb(Status1); outb(Attrx, 0x20|index); } else{ outb(Attrx, 0x20|index); data = inb(Attrx+1); } break; default: iunlock(&vgaxlock); return -1; } iunlock(&vgaxlock); return data & 0xFF; }
static void attach(Ether *ether) { Smc91xx* ctlr; ctlr = ether->ctlr; ilock(ctlr); if (ctlr->attached) { iunlock(ctlr); return; } chipenable(ether); ctlr->attached = 1; iunlock(ctlr); }
void cgaconsputs(char* s, int n) { ilock(&cgalock); while(n-- > 0) cgaputc(*s++); iunlock(&cgalock); }
static void vt6102imr(Ctlr* ctlr, int imr) { ilock(&ctlr->clock); ctlr->imr |= imr; csr16w(ctlr, Imr, ctlr->imr); iunlock(&ctlr->clock); }
static void freeref(int ref) { ilock(&refalloc); refalloc.refs[ref] = refalloc.free; refalloc.free = ref; iunlock(&refalloc); }
void nvramwrite(int addr, uchar data) { ilock(&nvrtlock); outb(Paddr, addr); outb(Pdata, data); iunlock(&nvrtlock); }
int conwrite(struct inode *in, char *addr, int len) { iunlock(in); for(int i = 0; i < len && addr[i]; i++) putchar_normal(addr[i]); ilock(in); return len; }
/* * transmit strategy: fill the output ring as far as possible, * perhaps leaving a few spare; kick off the output and take * an interrupt only when the transmit queue is empty. */ static void transmit(Ether *ether) { int i, kick, len; Block *b; Ctlr *ctlr = ether->ctlr; Gbereg *reg = ctlr->reg; Tx *t; ethercheck(ether); ilock(ctlr); txreplenish(ether); /* reap old packets */ /* queue new packets; use at most half the tx descs to avoid livelock */ kick = 0; for (i = Ntx/2 - 2; i > 0; i--) { t = &ctlr->tx[ctlr->txhead]; /* *t is uncached */ assert(((uintptr)t & (Descralign - 1)) == 0); if(t->cs & TCSdmaown) { /* descriptor busy? */ ctlr->txringfull++; break; } b = qget(ether->oq); /* outgoing packet? */ if (b == nil) break; len = BLEN(b); if(len < ether->minmtu || len > ether->maxmtu) { freeb(b); continue; } ctlr->txb[ctlr->txhead] = b; /* make sure the whole packet is in memory */ cachedwbse(b->rp, len); l2cacheuwbse(b->rp, len); /* set up the transmit descriptor */ t->buf = PADDR(b->rp); t->countchk = len << 16; coherence(); /* and fire */ t->cs = TCSpadding | TCSfirst | TCSlast | TCSdmaown | TCSenableintr; coherence(); kick++; ctlr->txhead = NEXT(ctlr->txhead, Ntx); } if (kick) { txkick(ctlr); reg->irqmask |= Itxendq(Qno); reg->irqemask |= IEtxerrq(Qno) | IEtxunderrun; } iunlock(ctlr); }
static void ehcireset(Ctlr *ctlr) { Eopio *opio; int i; ilock(ctlr); dprint("ehci %#p reset\n", ctlr->capio); opio = ctlr->opio; /* * Turn off legacy mode. Some controllers won't * interrupt us as expected otherwise. */ ehcirun(ctlr, 0); /* clear high 32 bits of address signals if it's 64 bits capable. * This is probably not needed but it does not hurt and others do it. */ if((ctlr->capio->capparms & C64) != 0){ dprint("ehci: 64 bits\n"); opio->seg = 0; } if(ehcidebugcapio != ctlr->capio){ opio->cmd |= Chcreset; /* controller reset */ coherence(); for(i = 0; i < 100; i++){ if((opio->cmd & Chcreset) == 0) break; delay(1); } if(i == 100) print("ehci %#p controller reset timed out\n", ctlr->capio); } /* requesting more interrupts per µframe may miss interrupts */ opio->cmd &= ~Citcmask; opio->cmd |= 1 << Citcshift; /* max of 1 intr. per 125 µs */ coherence(); switch(opio->cmd & Cflsmask){ case Cfls1024: ctlr->nframes = 1024; break; case Cfls512: ctlr->nframes = 512; break; case Cfls256: ctlr->nframes = 256; break; default: panic("ehci: unknown fls %ld", opio->cmd & Cflsmask); } coherence(); dprint("ehci: %d frames\n", ctlr->nframes); iunlock(ctlr); }
void gpiorelease(ulong mask) { ilock(&gpiolock); if((gpioreserved & mask) != mask) panic("gpiorelease: unexpected release of 0x%.8lux", ~gpioreserved & mask); gpioreserved &= ~mask; iunlock(&gpiolock); }
void gpioreserve(ulong mask) { ilock(&gpiolock); if(gpioreserved & mask) panic("gpioreserve: duplicate use of 0x%.8lux", gpioreserved & mask); gpioreserved |= mask; iunlock(&gpiolock); }
static void i82563interrupt(Ureg*, void* arg) { int icr, im, rdh, txdw = 0; Block *bp; Ctlr *ctlr; Ether *edev; Rdesc *rdesc; edev = arg; ctlr = edev->ctlr; ilock(&ctlr->imlock); csr32w(ctlr, Imc, ~0); im = ctlr->im; for(icr = csr32r(ctlr, Icr); icr & ctlr->im; icr = csr32r(ctlr, Icr)){ if(icr & (Rxseq|Lsc)){ /* should be more here */ } rdh = ctlr->rdh; for (;;) { rdesc = &ctlr->rdba[rdh]; if(!(rdesc->status & Rdd)) break; if ((rdesc->status & Reop) && rdesc->errors == 0) { bp = ctlr->rb[rdh]; if(0 && memcmp(bp->rp, broadcast, 6) != 0) print("#l%d: rx %d %E %E %d\n", edev->ctlrno, rdh, bp->rp, bp->rp+6, rdesc->length); ctlr->rb[rdh] = nil; bp->wp += rdesc->length; if (interesting(bp)) toringbuf(edev, bp); freeb(bp); } else if (rdesc->status & Reop && rdesc->errors) print("%s: input packet error %#ux\n", tname[ctlr->type], rdesc->errors); rdesc->status = 0; rdh = NEXT(rdh, Nrdesc); } ctlr->rdh = rdh; if(icr & Rxdmt0) i82563replenish(ctlr); if(icr & Txdw){ im &= ~Txdw; txdw++; } } ctlr->im = im; csr32w(ctlr, Ims, im); iunlock(&ctlr->imlock); if(txdw) i82563transmit(edev); }