long rtctime(void) { int i; long t, ot; ilock(&rtclock); /* loop till we get two reads in a row the same */ t = _rtctime(); for(i = 0; i < 100; i++){ ot = t; t = _rtctime(); if(ot == t) break; } if(i == 100) print("we are boofheads\n"); iunlock(&rtclock); return t; }
static void ks8695_modemctl(Uart* uart, int on) { Ctlr *ctlr; ctlr = uart->regs; ilock(&uart->tlock); if(on){ INTRREG->en |= 1<<IRQums; /* TO DO */ uart->modem = 1; uart->cts = csr8r(ctlr, Msr) & Cts; } else{ INTRREG->en &= ~(1<<IRQums); uart->modem = 0; uart->cts = 1; } iunlock(&uart->tlock); /* modem needs fifo */ (*uart->phys->fifo)(uart, on); }
Timer* addclock0link(void (*f)(void), int ms) { Timer *nt; uvlong when; /* Synchronize to hztimer if ms is 0 */ nt = malloc(sizeof(Timer)); if(ms == 0) ms = 1000/HZ; nt->tns = (vlong)ms*1000000LL; nt->tmode = Tperiodic; nt->tt = nil; nt->tf = (void (*)(Ureg*, Timer*))f; ilock(&timers[0]); when = tadd(&timers[0], nt); if(when) timerset(when); iunlock(&timers[0]); return nt; }
// 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. 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; }
void dp8390getea(Ether* ether, uchar* ea) { Dp8390 *ctlr; uchar cr; int i; ctlr = ether->ctlr; /* * Get the ethernet address from the chip. * Take care to restore the command register * afterwards. */ ilock(ctlr); cr = regr(ctlr, Cr) & ~Txp; regw(ctlr, Cr, Page1|(~(Ps1|Ps0) & cr)); for(i = 0; i < Eaddrlen; i++) ea[i] = regr(ctlr, Par0+i); regw(ctlr, Cr, cr); iunlock(ctlr); }
void intrdisable(int irq, void (*f)(Ureg *, void *), void *a, int tbdf, char *name) { Vctl **pv, *v; int vno; if(arch->intrvecno == nil || (tbdf != BUSUNKNOWN && (irq == 0xff || irq == 0))){ /* * on APIC machine, irq is pretty meaningless * and disabling a the vector is not implemented. * however, we still want to remove the matching * Vctl entry to prevent calling Vctl.f() with a * stale Vctl.a pointer. */ irq = -1; vno = VectorPIC; } else { vno = arch->intrvecno(irq); } ilock(&vctllock); do { for(pv = &vctl[vno]; (v = *pv) != nil; pv = &v->next){ if(v->isintr && (v->irq == irq || irq == -1) && v->tbdf == tbdf && v->f == f && v->a == a && strcmp(v->name, name) == 0) break; } if(v != nil){ *pv = v->next; xfree(v); if(irq != -1 && vctl[vno] == nil && arch->intrdisable != nil) arch->intrdisable(irq); break; } } while(irq == -1 && ++vno <= MaxVectorAPIC); iunlock(&vctllock); }
static void oxfifo(Uart *uart, int level) { Ctlr *ctlr; Port *port; port = uart->regs; ctlr = port->ctlr; /* * 950 Mode FIFOs have a depth of 128 bytes; devuart only * cares about setting RHR trigger levels. THR trigger * levels are not supported. */ ilock(ctlr); if(level == 0) port->mem[Fcr] = 0; /* Disable FIFO */ else{ port->mem[Fcr] = 1<<0; /* Enable FIFO */ switch(level){ default: level = 112; case 112: port->mem[Fcr] = 0x03<<6|1<<0; /* RHR Trigger Level */ break; case 64: port->mem[Fcr] = 0x02<<6|1<<0; break; case 32: port->mem[Fcr] = 0x01<<6|1<<0; break; case 16: break; } } port->level = level; iunlock(ctlr); }
Block* iallocb(int size) { Block *b; static int m1, m2, mp; if(ialloc.bytes > conf.ialloc){ if((m1++%10000)==0){ if(mp++ > 1000){ active.exiting = 1; exit(0); } iprint("iallocb: limited %lud/%lud\n", ialloc.bytes, conf.ialloc); } return nil; } if((b = _allocb(size)) == nil){ if((m2++%10000)==0){ if(mp++ > 1000){ active.exiting = 1; exit(0); } iprint("iallocb: no memory %lud/%lud\n", ialloc.bytes, conf.ialloc); } return nil; } setmalloctag(b, getcallerpc(&size)); b->flag = BINTR; ilock(&ialloc); ialloc.bytes += b->lim - b->base; iunlock(&ialloc); return b; }
long w_ctl(Ether* ether, void* buf, long n) { Ctlr *ctlr; if((ctlr = ether->ctlr) == nil) error(Enonexist); if((ctlr->state & Attached) == 0) error(Eshutdown); ilock(ctlr); if(w_option(ctlr, buf, n)){ iunlock(ctlr); error(Ebadctl); } if(ctlr->txbusy) w_txdone(ctlr, WTxErrEv); w_enable(ether); w_txstart(ether); iunlock(ctlr); return n; }
void w_attach(Ether* ether) { Ctlr* ctlr; char name[64]; int rc; if(ether->ctlr == 0) return; snprint(name, sizeof(name), "#l%dtimer", ether->ctlrno); ctlr = (Ctlr*) ether->ctlr; if((ctlr->state & Attached) == 0){ ilock(ctlr); rc = w_enable(ether); iunlock(ctlr); if(rc == 0){ ctlr->state |= Attached; kproc(name, w_timer, ether); } else print("#l%d: enable failed\n",ether->ctlrno); } }
void powerenable(void (*f)(int)) { Power *p, *l; p = malloc(sizeof(*p)); p->f = f; p->prev = nil; p->next = nil; ilock(&power); for(l = power.list.next; l != &power.list; l = l->next) if(l->f == f){ iunlock(&power); free(p); return; } l = &power.list; p->prev = l->prev; l->prev = p; p->next = l; p->prev->next = p; iunlock(&power); }
int i8259disable(int irq) { int irqbit; /* * Given an IRQ, disable the corresponding interrupt * in the 8259. */ if(irq < 0 || irq > MaxIrqPIC){ print("i8259disable: irq %d out of range\n", irq); return -1; } irqbit = 1<<irq; ilock(&i8259lock); if(!(i8259mask & irqbit)){ i8259mask |= irqbit; if(irq < 8) outb(Int0aux, i8259mask & 0xFF); else outb(Int1aux, (i8259mask>>8) & 0xFF); }
/* * wait for the queue to be non-empty or closed. * called with q ilocked. */ static int qwait(Queue *q) { /* wait for data */ for(;;){ if(q->bfirst != nil) break; if(q->state & Qclosed){ if(++q->eof > 3) return -1; if(*q->err && strcmp(q->err, Ehungup) != 0) return -1; return 0; } q->state |= Qstarve; /* flag requesting producer to wake me */ iunlock(q); sleep(&q->rr, notempty, q); ilock(q); } return 1; }
uvlong fastticks(uvlong *hz) { Counter now, sclnow; if(hz) *hz = m->cpuhz; ilock(&clklck); if (m->ticks > HZ/10 && m->fastclock == 0) panic("fastticks: zero m->fastclock; ticks %lud fastclock %#llux", m->ticks, m->fastclock); now.uvl = m->fastclock; now.low = rdcycles(); if(now.uvl < m->fastclock) /* low bits must have wrapped */ now.high++; m->fastclock = now.uvl; coherence(); sclnow.uvl = now.uvl; iunlock(&clklck); return sclnow.uvl; }
/* * Put character, possibly a rune, into read queue at interrupt time. * Called at interrupt time to process a character. */ int kbdputc(Queue *q, int ch) { int n; Rune r; char buf[UTFmax]; r = ch; n = runetochar(buf, &r); echo(buf, n); return 0; #if 0 // Plan 9 VX int i, n; char buf[3]; Rune r; char *next; if(kbd.ir == nil) return 0; /* in case we're not inited yet */ ilock(&kbd.lockputc); /* just a mutex */ r = ch; n = runetochar(buf, &r); for(i = 0; i < n; i++){ next = kbd.iw+1; if(next >= kbd.ie) next = kbd.istage; if(next == kbd.ir) break; *kbd.iw = buf[i]; kbd.iw = next; } iunlock(&kbd.lockputc); return 0; #endif }
static int load_proc(char *path, struct proc *p) { int i; struct proc np; //an inode describes a single unnamed file struct inode *ip; begin_op(); if ((ip = namei(path)) == 0) { end_op(); return -1; } ilock(ip); if((np.pgdir = setupkvm()) == 0) return -1; if((np.sz = allocuvm(np.pgdir, 0, p->sz)) == 0) return -1; for(i = 0; i < p->sz; i+=PGSIZE) { if(loaduvm(np.pgdir, (void *)i, ip, sizeof(struct proc) + i,PGSIZE) < 0) return -1; } iunlockput(ip); end_op(); ip = 0; np.tf->eax = proc->pid; np.tf->eip = p->tf->eip; np.tf->esp = p->tf->esp; np.tf->ebp = p->tf->ebp; proc->pgdir = np.pgdir; proc->sz = PGROUNDUP(np.sz); *proc->tf = *np.tf; switchuvm(proc); return 0; }
int i8259enable(Vctl* v) { int irq, irqbit; /* * Given an IRQ, enable the corresponding interrupt in the i8259 * and return the vector to be used. The i8259 is set to use a fixed * range of vectors starting at VectorPIC. */ irq = v->irq; if(irq < 0 || irq > MaxIrqPIC){ print("i8259enable: irq %d out of range\n", irq); return -1; } irqbit = 1<<irq; ilock(&i8259lock); if(!(i8259mask & irqbit) && !(i8259elcr & irqbit)){ print("i8259enable: irq %d shared but not level\n", irq); iunlock(&i8259lock); return -1; } i8259mask &= ~irqbit; if(irq < 8) outb(Int0aux, i8259mask & 0xFF); else outb(Int1aux, (i8259mask>>8) & 0xFF); if(i8259elcr & irqbit) v->eoi = i8259isr; else v->isr = i8259isr; iunlock(&i8259lock); return VectorPIC+irq; }
static char* startxfer(I2Cdev *d, int op, void (*xfer)(Ctlr*), Block *b, int n, ulong offset) { IICregs *iic; Ctlr *ctlr; int i, cntl, p, s; ctlr = iicctlr; if(up) { qlock(&ctlr->io); if(waserror()) { qunlock(&ctlr->io); nexterror(); } } ilock(ctlr); if(!idlectlr(ctlr)) { iunlock(ctlr); if(up) error("bus confused"); return "bus confused"; } if(ctlr->phase >= Busy) panic("iic: ctlr busy"); cntl = op | Pt; if(d->tenbit) cntl |= Amd10; ctlr->cntl = cntl; ctlr->b = b; ctlr->rdcount = n; ctlr->phase = Busy; iic = ctlr->regs; if(d->tenbit) { iic->hmadr = 0xF0 | (d->addr>>7); /* 2 higher bits of address, LSB don't care */ iic->lmadr = d->addr; } else {
void w_detach(Ether* ether) { Ctlr* ctlr; char name[64]; if(ether->ctlr == nil) return; snprint(name, sizeof(name), "#l%dtimer", ether->ctlrno); ctlr = (Ctlr*) ether->ctlr; if(ctlr->state & Attached){ ilock(ctlr); w_intdis(ctlr); if(ctlr->timerproc){ if(!postnote(ctlr->timerproc, 1, "kill", NExit)) print("timerproc note not posted\n"); print("w_detach, killing 0x%p\n", ctlr->timerproc); } ctlr->state &= ~Attached; iunlock(ctlr); } ether->ctlr = nil; }
void dp8390setea(Ether* ether) { int i; uchar cr; Dp8390 *ctlr; ctlr = ether->ctlr; /* * Set the ethernet address into the chip. * Take care to restore the command register * afterwards. Don't care about multicast * addresses as multicast is never enabled * (currently). */ ilock(ctlr); cr = regr(ctlr, Cr) & ~Txp; regw(ctlr, Cr, Page1|(~(Ps1|Ps0) & cr)); for(i = 0; i < Eaddrlen; i++) regw(ctlr, Par0+i, ether->ea[i]); regw(ctlr, Cr, cr); iunlock(ctlr); }
/* * called regularly to avoid calculation overflows */ static void todfix(void) { vlong ticks, diff; uvlong x; ticks = fastticks(nil); diff = ticks - tod.last; if(diff > tod.hz){ ilock(&tod); /* convert to epoch */ mul64fract(&x, diff, tod.multiplier); if(x > 30000000000ULL) iprint("todfix %llud\n", x); x += tod.off; /* protect against overflows */ tod.last = ticks; tod.off = x; iunlock(&tod); } }
static void i8250modemctl(Uart* uart, int on) { Ctlr *ctlr; ctlr = uart->regs; ilock(&uart->tlock); if(on){ ctlr->sticky[Ier] |= Ems; csr8w(ctlr, Ier, 0); uart->modem = 1; uart->cts = csr8r(ctlr, Msr) & Cts; } else{ ctlr->sticky[Ier] &= ~Ems; csr8w(ctlr, Ier, 0); uart->modem = 0; uart->cts = 1; } iunlock(&uart->tlock); /* modem needs fifo */ (*uart->phys->fifo)(uart, on); }
static void uartclose(Chan *c) { Proc *up = externup(); Uart *p; if(c->qid.type & QTDIR) return; if((c->flag & COPEN) == 0) return; switch(UARTTYPE(c->qid.path)){ case Qdata: case Qctl: p = uart[UARTID(c->qid.path)]; qlock(&p->ql); if(--(p->opens) == 0){ qclose(p->iq); ilock(&p->rlock); p->ir = p->iw = p->istage; iunlock(&p->rlock); /* */ qhangup(p->oq, nil); if(!waserror()){ uartdrainoutput(p); poperror(); } qclose(p->oq); uartdisable(p); p->dcd = p->dsr = p->dohup = 0; } qunlock(&p->ql); break; } }
static void x86wdenable(void) { Wd *wd; vlong r, t; int i, model; u32int evntsel; wd = &x86wd; ilock(wd); if(wd->inuse){ iunlock(wd); error(Einuse); } iunlock(wd); /* * keep this process on cpu 0 so we always see the same timers * and so that this will work even if all other cpus are shut down. */ runoncpu(0); /* * Check the processor is capable of doing performance * monitoring and that it has TSC, RDMSR/WRMSR and a local APIC. */ model = -1; if(strncmp(m->cpuidid, "AuthenticAMD", 12) == 0){ if(X86FAMILY(m->cpuidax) == 0x06) model = K6; else if(X86FAMILY(m->cpuidax) == 0x0F) model = K8; } else if(strncmp(m->cpuidid, "GenuineIntel", 12) == 0){ if(X86FAMILY(m->cpuidax) == 0x06) model = P6; else if(X86FAMILY(m->cpuidax) == 0x0F) model = P4; } if(model == -1 || (m->cpuiddx & (Cpuapic|Cpumsr|Tsc)) != (Cpuapic|Cpumsr|Tsc)) error(Enodev); ilock(wd); if(wd->inuse){ iunlock(wd); error(Einuse); } wd->model = model; wd->inuse = 1; wd->ticks = 0; /* * See the IA-32 Intel Architecture Software * Developer's Manual Volume 3: System Programming Guide, * Chapter 15 and the AMD equivalent for what all this * bit-whacking means. */ t = interval(); switch(model){ case P6: wrmsr(0x186, 0); /* evntsel */ wrmsr(0x187, 0); wrmsr(0xC1, 0); /* perfctr */ wrmsr(0xC2, 0); lapicnmienable(); evntsel = 0x00130000|0x79; wrmsr(0xC1, -t); wrmsr(0x186, 0x00400000|evntsel); break; case P4: rdmsr(0x1A0, &r); if(!(r & 0x0000000000000080LL)) return; for(i = 0; i < 18; i++) wrmsr(0x300+i, 0); /* perfctr */ for(i = 0; i < 18; i++) wrmsr(0x360+i, 0); /* ccr */ for(i = 0; i < 31; i++) wrmsr(0x3A0+i, 0); /* escr */ for(i = 0; i < 6; i++) wrmsr(0x3C0+i, 0); /* escr */ for(i = 0; i < 6; i++) wrmsr(0x3C8+i, 0); /* escr */ for(i = 0; i < 2; i++) wrmsr(0x3E0+i, 0); /* escr */ if(!(r & 0x0000000000001000LL)){ for(i = 0; i < 2; i++) wrmsr(0x3F1+i, 0); /* pebs */ } lapicnmienable(); wrmsr(0x3B8, 0x000000007E00000CLL); /* escr0 */ r = 0x0000000004FF8000ULL; wrmsr(0x36C, r); /* cccr0 */ wrmsr(0x30C, -t); wrmsr(0x36C, 0x0000000000001000LL|r); break; case K6: case K8: /* * PerfEvtSel 0-3, PerfCtr 0-4. */ for(i = 0; i < 8; i++) wrmsr(0xC0010000+i, 0); lapicnmienable(); evntsel = 0x00130000|0x76; wrmsr(0xC0010004, -t); wrmsr(0xC0010000, 0x00400000|evntsel); break; } iunlock(wd); }
int exec(char *path, char **argv) { char *s, *last; int i, off; uint argc, sz, sp, ustack[3+MAXARG+1]; struct elfhdr elf; struct inode *ip; struct proghdr ph; pde_t *pgdir, *oldpgdir; begin_op(); if((ip = namei(path)) == 0){ end_op(); return -1; } ilock(ip); pgdir = 0; // Check ELF header if(readi(ip, (char*)&elf, 0, sizeof(elf)) < sizeof(elf)) goto bad; if(elf.magic != ELF_MAGIC) goto bad; if((pgdir = setupkvm()) == 0) goto bad; // Load program into memory. sz = 0; for(i=0, off=elf.phoff; i<elf.phnum; i++, off+=sizeof(ph)){ if(readi(ip, (char*)&ph, off, sizeof(ph)) != sizeof(ph)) goto bad; if(ph.type != ELF_PROG_LOAD) continue; if(ph.memsz < ph.filesz) goto bad; if((sz = allocuvm(pgdir, sz, ph.vaddr + ph.memsz)) == 0) goto bad; if(loaduvm(pgdir, (char*)ph.vaddr, ip, ph.off, ph.filesz) < 0) goto bad; } iunlockput(ip); end_op(); ip = 0; // Allocate two pages at the next page boundary. // Make the first inaccessible. Use the second as the user stack. sz = PGROUNDUP(sz); if((sz = allocuvm(pgdir, sz, sz + 2*PGSIZE)) == 0) goto bad; clearpteu(pgdir, (char*)(sz - 2*PGSIZE)); sp = sz; // Push argument strings, prepare rest of stack in ustack. for(argc = 0; argv[argc]; argc++) { if(argc >= MAXARG) goto bad; sp = (sp - (strlen(argv[argc]) + 1)) & ~3; if(copyout(pgdir, sp, argv[argc], strlen(argv[argc]) + 1) < 0) goto bad; ustack[3+argc] = sp; } ustack[3+argc] = 0; ustack[0] = 0xffffffff; // fake return PC ustack[1] = argc; ustack[2] = sp - (argc+1)*4; // argv pointer sp -= (3+argc+1) * 4; if(copyout(pgdir, sp, ustack, (3+argc+1)*4) < 0) goto bad; // Save program name for debugging. for(last=s=path; *s; s++) if(*s == '/') last = s+1; safestrcpy(proc->name, last, sizeof(proc->name)); // Commit to the user image. oldpgdir = proc->pgdir; proc->pgdir = pgdir; proc->sz = sz; proc->tf->eip = elf.entry; // main proc->tf->esp = sp; switchuvm(proc); freevm(oldpgdir); return 0; bad: if(pgdir) freevm(pgdir); if(ip){ iunlockput(ip); end_op(); } return -1; }
static void igbeinterrupt(Ureg*, void* arg) { Block *bp; Ctlr *ctlr; Ether *edev; Rdesc *rdesc; int icr, im, rdh, txdw = 0; edev = arg; ctlr = edev->ctlr; ilock(&ctlr->imlock); csr32w(ctlr, Imc, ~0); im = ctlr->im; if((icr = csr32r(ctlr, Icr)) & ctlr->im){ /* * Link status changed. */ if(icr & (Rxseq|Lsc)){ /* * More here... */ } /* * Process any received packets. */ rdh = ctlr->rdh; for(;;){ rdesc = &ctlr->rdba[rdh]; if(!(rdesc->status & Rdd)) break; if ((rdesc->status & Reop) && rdesc->errors == 0) { bp = ctlr->rb[rdh]; ctlr->rb[rdh] = nil; /* * it appears that the original 82543 needed * to have the Ethernet CRC excluded, but that * the newer chips do not? */ bp->wp += rdesc->length /* -4 */; toringbuf(edev, bp); freeb(bp); } else if ((rdesc->status & Reop) && rdesc->errors) print("igbe: input packet error 0x%ux\n", rdesc->errors); rdesc->status = 0; rdh = NEXT(rdh, Nrdesc); } ctlr->rdh = rdh; if(icr & Rxdmt0) igbereplenish(ctlr); if(icr & Txdw){ im &= ~Txdw; txdw++; } } ctlr->im = im; csr32w(ctlr, Ims, im); iunlock(&ctlr->imlock); if(txdw) igbetransmit(edev); }
int exec(char *path, char **argv) { char *s, *last; int i, off; uint argc, sz,s_sz, sp, ustack[3+MAXARG+1]; struct elfhdr elf; struct inode *ip; struct proghdr ph; pde_t *pgdir, *oldpgdir; if((ip = namei(path)) == 0) return -1; ilock(ip); pgdir = 0; // Check ELF header if(readi(ip, (char*)&elf, 0, sizeof(elf)) < sizeof(elf)) goto bad; if(elf.magic != ELF_MAGIC) goto bad; if((pgdir = setupkvm()) == 0) goto bad; // Load program into memory. sz = PGSIZE; for(i=0, off=elf.phoff; i<elf.phnum; i++, off+=sizeof(ph)){ if(readi(ip, (char*)&ph, off, sizeof(ph)) != sizeof(ph)) goto bad; if(ph.type != ELF_PROG_LOAD) continue; if(ph.memsz < ph.filesz) goto bad; if((sz = allocuvm(pgdir, sz, ph.va + ph.memsz)) == 0) goto bad; if(loaduvm(pgdir, (char*)ph.va, ip, ph.offset, ph.filesz) < 0) goto bad; } iunlockput(ip); ip = 0; // Allocate a one-page stack one page away from USERTOP (at bottom // grow upwards) s_sz = (USERTOP - PGSIZE); if((s_sz = allocuvm(pgdir, s_sz, s_sz + PGSIZE)) == 0) goto bad; // Push argument strings, prepare rest of stack in ustack. sp = s_sz; for(argc = 0; argv[argc]; argc++) { if(argc >= MAXARG) goto bad; sp -= strlen(argv[argc]) + 1; sp &= ~3; if(copyout(pgdir, sp, argv[argc], strlen(argv[argc]) + 1) < 0) goto bad; ustack[3+argc] = sp; } ustack[3+argc] = 0; ustack[0] = 0xffffffff; // fake return PC ustack[1] = argc; ustack[2] = sp - (argc+1)*4; // argv pointer sp -= (3+argc+1) * 4; if(copyout(pgdir, sp, ustack, (3+argc+1)*4) < 0) goto bad; // Save program name for debugging. for(last=s=path; *s; s++) if(*s == '/') last = s+1; safestrcpy(proc->name, last, sizeof(proc->name)); s_sz = USERTOP - PGSIZE; // Commit to the user image. oldpgdir = proc->pgdir; proc->pgdir = pgdir; proc->sz = sz; proc->s_sz =s_sz; proc->tf->eip = elf.entry; // main proc->tf->esp = sp; switchuvm(proc); freevm(oldpgdir); // cprintf("finish exec%d\t%d\n",sz,s_sz); return 0; bad: if(pgdir) freevm(pgdir); if(ip) iunlockput(ip); return -1; }
static long loopbackwrite(Chan *c, void *va, long n, vlong off) { Loop *lb; Link *link; Cmdbuf *volatile cb; Block *volatile bp; vlong d0, d0ns; long dn, dnns; switch(TYPE(c->qid.path)){ case Qdata: bp = allocb(n); if(waserror()){ freeb(bp); nexterror(); } memmove(bp->wp, va, n); poperror(); bp->wp += n; return loopbackbwrite(c, bp, off); case Qctl: lb = c->aux; link = &lb->link[ID(c->qid.path)]; cb = parsecmd(va, n); if(waserror()){ free(cb); nexterror(); } if(cb->nf < 1) error("short control request"); if(strcmp(cb->f[0], "delay") == 0){ if(cb->nf != 3) error("usage: delay latency bytedelay"); d0ns = strtoll(cb->f[1], nil, 10); dnns = strtol(cb->f[2], nil, 10); /* * it takes about 20000 cycles on a pentium ii * to run pushlink; perhaps this should be accounted. */ ilock(link); link->delay0ns = d0ns; link->delaynns = dnns; iunlock(link); }else if(strcmp(cb->f[0], "indrop") == 0){ if(cb->nf != 2) error("usage: indrop [01]"); ilock(link); link->indrop = strtol(cb->f[1], nil, 0) != 0; iunlock(link); }else if(strcmp(cb->f[0], "droprate") == 0){ if(cb->nf != 2) error("usage: droprate ofn"); ilock(link); link->droprate = strtol(cb->f[1], nil, 0); iunlock(link); }else if(strcmp(cb->f[0], "limit") == 0){ if(cb->nf != 2) error("usage: limit maxqsize"); ilock(link); link->limit = strtol(cb->f[1], nil, 0); qsetlimit(link->oq, link->limit); qsetlimit(link->iq, link->limit); iunlock(link); }else if(strcmp(cb->f[0], "reset") == 0){ if(cb->nf != 1) error("usage: reset"); ilock(link); link->packets = 0; link->bytes = 0; link->indrop = 0; link->soverflows = 0; link->drops = 0; iunlock(link); }else error("unknown control request"); poperror(); free(cb); break; default: error(Eperm); } return n; }
/* * move blocks between queues if they are ready. * schedule an interrupt for the next interesting time. * * must be called with the link ilocked. */ static void pushlink(Link *link, vlong now) { Block *bp; vlong tout, tin; /* * put another block in the link queue */ ilock(link); if(link->iq == nil || link->oq == nil){ iunlock(link); return; } timerdel(&link->ci); /* * put more blocks into the xmit queue * use the time the last packet was supposed to go out * as the start time for the next packet, rather than * the current time. this more closely models a network * device which can queue multiple output packets. */ tout = link->tout; if(!tout) tout = now; while(tout <= now){ bp = qget(link->oq); if(bp == nil){ tout = 0; break; } /* * can't send the packet before it gets queued */ tin = gtime(bp->rp); if(tin > tout) tout = tin; tout = tout + (BLEN(bp) - Tmsize) * link->delayn; /* * drop packets */ if(link->droprate && nrand(link->droprate) == 0) link->drops++; else{ ptime(bp->rp, tout + link->delay0ns); if(link->tq == nil) link->tq = bp; else link->tqtail->next = bp; link->tqtail = bp; } } /* * record the next time a packet can be sent, * but don't schedule an interrupt if none is waiting */ link->tout = tout; if(!qcanread(link->oq)) tout = 0; /* * put more blocks into the receive queue */ tin = 0; while(bp = link->tq){ tin = gtime(bp->rp); if(tin > now) break; bp->rp += Tmsize; link->tq = bp->next; bp->next = nil; if(!link->indrop) qpassnolim(link->iq, bp); else if(qpass(link->iq, bp) < 0) link->soverflows++; tin = 0; } if(bp == nil && qisclosed(link->oq) && !qcanread(link->oq) && !qisclosed(link->iq)) qhangup(link->iq, nil); link->tin = tin; if(!tin || tin > tout && tout) tin = tout; link->ci.ns = tin - now; if(tin){ if(tin < now) panic("loopback unfinished business"); timeradd(&link->ci); } iunlock(link); }
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); }