From 6d70572ca20c22d631dd483d544ebe5678e89999 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Sat, 8 Jul 2000 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 2000-07-08 --- boot/key.c | 2 + pc/vgas3.c | 87 ++++---- port/devloopback.c | 514 +++++++++++++++++++++++++++++---------------- port/devns16552.c | 47 +++-- 4 files changed, 415 insertions(+), 235 deletions(-) diff --git a/boot/key.c b/boot/key.c index bd0149a7d313fd07f3f27dee0fb792f7f7122101..7846812efb47bd212fe5e0a81842470d3309a54c 100644 --- a/boot/key.c +++ b/boot/key.c @@ -92,6 +92,8 @@ key(int islocal, Method *mp) fatal("#c/hostowner"); /* set host's domain */ + if(*safe->authdom == 0) + strcpy(safe->authdom, "plan9"); if(writefile("#c/hostdomain", safe->authdom, strlen(safe->authdom)) < 0) fatal("#c/hostdomain"); } diff --git a/pc/vgas3.c b/pc/vgas3.c index 4fc38f5dd0140bedcea341fe50318ec1bd0a17e1..a2d348cf7c323e2c3e3f3f4f387e540e52daf457 100644 --- a/pc/vgas3.c +++ b/pc/vgas3.c @@ -179,46 +179,6 @@ s3disable(VGAscr*) vgaxo(Crtx, 0x45, crt45); } -static void -s3enable(VGAscr* scr) -{ - int i; - ulong storage; - - s3disable(scr); - - /* - * Cursor colours. Set both the CR0[EF] and the colour - * stack in case we are using a 16-bit RAMDAC. - */ - vgaxo(Crtx, 0x0E, Pwhite); - vgaxo(Crtx, 0x0F, Pblack); - vgaxi(Crtx, 0x45); - - for(i = 0; i < 3; i++) - vgaxo(Crtx, 0x4A, Pblack); - vgaxi(Crtx, 0x45); - for(i = 0; i < 3; i++) - vgaxo(Crtx, 0x4B, Pwhite); - - /* - * Find a place for the cursor data in display memory. - * Must be on a 1024-byte boundary. - */ - storage = (scr->gscreen->width*BY2WD*scr->gscreen->r.max.y+1023)/1024; - vgaxo(Crtx, 0x4C, storage>>8); - vgaxo(Crtx, 0x4D, storage & 0xFF); - storage *= 1024; - scr->storage = storage; - - /* - * Enable the cursor in Microsoft Windows format. - */ - vgaxo(Crtx, 0x55, vgaxi(Crtx, 0x55) & ~0x10); - s3vsyncactive(); - vgaxo(Crtx, 0x45, 0x01); -} - static void s3load(VGAscr* scr, Cursor* curs) { @@ -240,7 +200,7 @@ s3load(VGAscr* scr, Cursor* curs) case 0xE18A: /* ViRGE/[DG]X */ case 0xE110: /* ViRGE/GX2 */ case 0xE13D: /* ViRGE/VX */ - case 0xE112: /* Savage4/MX */ + case 0xE112: /* Savage4/IX-MV */ case 0xE122: /* Savage4 */ p += scr->storage; break; @@ -288,7 +248,7 @@ s3load(VGAscr* scr, Cursor* curs) case 0xE18A: /* ViRGE/[DG]X */ case 0xE110: /* ViRGE/GX2 */ case 0xE13D: /* ViRGE/VX */ - case 0xE112: /* Savage4/MX */ + case 0xE112: /* Savage4/IX-MV */ case 0xE122: /* Savage4 */ break; @@ -343,6 +303,49 @@ s3move(VGAscr* scr, Point p) return 0; } +static void +s3enable(VGAscr* scr) +{ + int i; + ulong storage; + + s3disable(scr); + + /* + * Cursor colours. Set both the CR0[EF] and the colour + * stack in case we are using a 16-bit RAMDAC. + */ + vgaxo(Crtx, 0x0E, Pwhite); + vgaxo(Crtx, 0x0F, Pblack); + vgaxi(Crtx, 0x45); + + for(i = 0; i < 3; i++) + vgaxo(Crtx, 0x4A, Pblack); + vgaxi(Crtx, 0x45); + for(i = 0; i < 3; i++) + vgaxo(Crtx, 0x4B, Pwhite); + + /* + * Find a place for the cursor data in display memory. + * Must be on a 1024-byte boundary. + */ + storage = (scr->gscreen->width*BY2WD*scr->gscreen->r.max.y+1023)/1024; + vgaxo(Crtx, 0x4C, storage>>8); + vgaxo(Crtx, 0x4D, storage & 0xFF); + storage *= 1024; + scr->storage = storage; + + /* + * Load, locate and enable the cursor + * in Microsoft Windows format. + */ + s3load(scr, &arrow); + s3move(scr, ZP); + vgaxo(Crtx, 0x55, vgaxi(Crtx, 0x55) & ~0x10); + s3vsyncactive(); + vgaxo(Crtx, 0x45, 0x01); +} + /* * The manual gives byte offsets, but we want ulong offsets, hence /4. */ diff --git a/port/devloopback.c b/port/devloopback.c index 48faefa636912ebb80204d80db841df0e22de41c..5339c43410bdb5b144da66f4a403855d3b4df588 100644 --- a/port/devloopback.c +++ b/port/devloopback.c @@ -5,8 +5,6 @@ #include "fns.h" #include "../port/error.h" -#include "netif.h" - typedef struct Link Link; typedef struct Loop Loop; @@ -16,20 +14,28 @@ struct Link int ref; - int nodrop; /* disable dropping on iq overflow */ - int soverflows; /* packets dropped because iq overflowed */ - int drops; /* packets deliberately dropped */ + long packets; /* total number of packets sent */ + long bytes; /* total number of bytes sent */ + int indrop; /* enable dropping on iq overflow */ + long soverflows; /* packets dropped because iq overflowed */ + long droprate; /* drop 1/droprate packets in tq */ + long drops; /* packets deliberately dropped */ - long delay0; /* fastticks of delay in the link */ - long delayn; /* fastticks of delay per byte */ + long delay0ns; /* nanosec of delay in the link */ + long delaynns; /* nanosec of delay per byte */ + long delay0; /* fastticks of delay */ + long delayn; Block *tq; /* transmission queue */ Block *tqtail; vlong tout; /* time the last packet in tq is really out */ vlong tin; /* time the head packet in tq enters the remote side */ + long limit; /* queue buffering limit */ Queue *oq; /* output queue from other side & packets in the link */ Queue *iq; + + Cycintr ci; /* time to move packets from next packet from oq */ }; struct Loop @@ -39,7 +45,6 @@ struct Loop int minmtu; /* smallest block transmittable */ Loop *next; ulong path; - long limit; /* queue buffering limit */ Link link[2]; }; @@ -51,45 +56,68 @@ static struct enum { - Qdir, + Qtopdir= 1, /* top level directory */ + + Qloopdir, /* loopback* directory */ + + Qportdir, /* directory each end of the loop */ Qctl, Qstatus, Qstats, - Qdata0, - Qdata1, + Qdata, + + MaxQ, - TMSIZE = 8, + Nloopbacks = 1, - NLOOPBACKS = 1, - LOOPBACKSIZE = 32*1024, /*ZZZ change to settable; size of queues */ + Statelen = 23*1024, /* status buffer size */ + + Tmsize = 8, + Delayn = 10000, /* default delays */ + Delay0 = 2500000, + + Loopqlim = 32*1024, /* default size of queues */ }; -Dirtab loopbackdir[] = +static Dirtab loopportdir[] = { "ctl", {Qctl}, 0, 0222, - "status", {Qstatus}, 0, 0222, + "status", {Qstatus}, 0, 0444, "stats", {Qstats}, 0, 0444, - "data", {Qdata0}, 0, 0666, - "data1", {Qdata1}, 0, 0666, + "data", {Qdata}, 0, 0666, }; +static Dirtab loopdirs[MaxQ]; + +static Loop loopbacks[Nloopbacks]; + +static uvlong fasthz; -static Loop loopbacks[NLOOPBACKS]; +#define TYPE(x) ((x)&0xff) +#define ID(x) (((x)&~CHDIR)>>8) +#define QID(x,y) (((x)<<8)|(y)) + +#define NS2FASTHZ(t) ((fasthz*(t))/1000000000); static void looper(Loop *lb); static long loopoput(Loop *lb, Link *link, Block *bp); static void ptime(uchar *p, vlong t); static vlong gtime(uchar *p); static void closelink(Link *link, int dofree); -static vlong pushlink(Link *link, vlong now); +static void pushlink(Link *link, vlong now); static void freelb(Loop *lb); +static void linkintr(Ureg*, Cycintr *ci); static void loopbackinit(void) { int i; - for(i = 0; i < NLOOPBACKS; i++) + for(i = 0; i < Nloopbacks; i++) loopbacks[i].path = i; + + /* invert directory tables for non-directory entries */ + for(i=0; i= Nloopbacks) + error(Ebadspec); + } c = devattach('X', spec); - lb = &loopbacks[0]; + lb = &loopbacks[dev]; qlock(lb); if(waserror()){ + lb->ref--; qunlock(lb); nexterror(); } lb->ref++; if(lb->ref == 1){ - lb->limit = LOOPBACKSIZE; + fastticks(&fasthz); for(chan = 0; chan < 2; chan++){ - q = qopen(lb->limit, 0, 0, 0); + lb->link[chan].ci.a = &lb->link[chan]; + lb->link[chan].ci.f = linkintr; + lb->link[chan].limit = Loopqlim; + q = qopen(lb->link[chan].limit, 0, 0, 0); lb->link[chan].iq = q; if(q == nil){ freelb(lb); exhausted("memory"); } - q = qopen(lb->limit, 0, 0, 0); + q = qopen(lb->link[chan].limit, 0, 0, 0); lb->link[chan].oq = q; if(q == nil){ freelb(lb); exhausted("memory"); } - lb->link[chan].nodrop = 1; + lb->link[chan].indrop = 1; + + lb->link[chan].delayn = NS2FASTHZ(Delayn); + lb->link[chan].delaynns = Delayn; + lb->link[chan].delay0 = NS2FASTHZ(Delay0); + lb->link[chan].delay0ns = Delay0; } } poperror(); qunlock(lb); - c->qid = (Qid){CHDIR|NETQID(2*lb->path, Qdir), 0}; + c->qid = (Qid){CHDIR|QID(0, Qtopdir), 0}; c->aux = lb; c->dev = 0; return c; @@ -141,85 +189,92 @@ static Chan* loopbackclone(Chan *c, Chan *nc) { Loop *lb; - int chan; lb = c->aux; nc = devclone(c, nc); qlock(lb); lb->ref++; - if(c->flag & COPEN){ - switch(chan = NETTYPE(c->qid.path)){ - case Qdata0: - case Qdata1: - chan -= Qdata0; - lb->link[chan].ref++; - break; - } - } + if((c->flag & COPEN) && TYPE(c->qid.path) == Qdata) + lb->link[ID(c->qid.path)].ref++; qunlock(lb); return nc; } static int -loopbackgen(Chan *c, Dirtab *tab, int ntab, int i, Dir *dp) +loopbackgen(Chan *c, Dirtab*, int, int i, Dir *dp) { Loop *lb; - int id, len, chan; + Dirtab *tab; + char buf[NAMELEN]; + int len, type; + type = TYPE(c->qid.path); if(i == DEVDOTDOT){ - devdir(c, c->qid, "#X", 0, eve, CHDIR|0555, dp); + switch(type){ + case Qtopdir: + case Qloopdir: + snprint(buf, sizeof(buf), "#X%ld", c->dev); + devdir(c, (Qid){CHDIR|QID(0, Qtopdir), 0}, buf, 0, eve, 0555, dp); + break; + case Qportdir: + snprint(buf, sizeof(buf), "loopback%ld", c->dev); + devdir(c, (Qid){CHDIR|QID(0, Qloopdir), 0}, buf, 0, eve, 0555, dp); + break; + default: + panic("loopbackgen %lux", c->qid.path); + } return 1; } - id = NETID(c->qid.path); - if(i > 1) - id++; - if(tab==nil || i>=ntab) - return -1; - tab += i; - lb = c->aux; - switch(chan = tab->qid.path){ - case Qdata0: - case Qdata1: - chan -= Qdata0; - len = qlen(lb->link[chan].iq); - break; + switch(type){ + case Qtopdir: + if(i != 0) + return -1; + snprint(buf, sizeof(buf), "loopback%ld", c->dev); + devdir(c, (Qid){QID(0, Qloopdir) | CHDIR, 0}, buf, 0, eve, 0555, dp); + return 1; + case Qloopdir: + if(i >= 2) + return -1; + snprint(buf, sizeof(buf), "%d", i); + devdir(c, (Qid){QID(i, QID(0, Qportdir)) | CHDIR, 0}, buf, 0, eve, 0555, dp); + return 1; + case Qportdir: + if(i >= nelem(loopportdir)) + return -1; + tab = &loopportdir[i]; + devdir(c, (Qid){QID(ID(c->qid.path), tab->qid.path), 0}, tab->name, tab->length, eve, tab->perm, dp); + return 1; default: + /* non directory entries end up here; must be in lowest level */ + if(c->qid.path & CHDIR) + panic("loopbackgen: unexpected directory"); + if(i != 0) + return -1; + tab = &loopdirs[type]; + if(tab == nil) + panic("loopbackgen: unknown type: %d", type); len = tab->length; - break; + if(type == Qdata){ + lb = c->aux; + len = qlen(lb->link[ID(c->qid.path)].iq); + } + devdir(c, c->qid, tab->name, len, eve, tab->perm, dp); + return 1; } - devdir(c, (Qid){NETQID(id, tab->qid.path),0}, tab->name, len, eve, tab->perm, dp); - return 1; } static int loopbackwalk(Chan *c, char *name) { - return devwalk(c, name, loopbackdir, nelem(loopbackdir), loopbackgen); + return devwalk(c, name, nil, 0, loopbackgen); } static void loopbackstat(Chan *c, char *db) { - Loop *lb; - Dir dir; - int chan; - - lb = c->aux; - switch(chan = NETTYPE(c->qid.path)){ - case Qdir: - devdir(c, c->qid, ".", nelem(loopbackdir)*DIRLEN, eve, CHDIR|0555, &dir); - break; - case Qdata0: - case Qdata1: - chan -= Qdata0; - devdir(c, c->qid, "data", qlen(lb->link[chan].iq), eve, 0660, &dir); - break; - default: - panic("loopbackstat"); - } - convD2M(&dir, db); + devstat(c, db, nil, 0, loopbackgen); } /* @@ -229,7 +284,6 @@ static Chan* loopbackopen(Chan *c, int omode) { Loop *lb; - int chan; if(c->qid.path & CHDIR){ if(omode != OREAD) @@ -242,13 +296,8 @@ loopbackopen(Chan *c, int omode) lb = c->aux; qlock(lb); - switch(chan = NETTYPE(c->qid.path)){ - case Qdata0: - case Qdata1: - chan -= Qdata0; - lb->link[chan].ref++; - break; - } + if(TYPE(c->qid.path) == Qdata) + lb->link[ID(c->qid.path)].ref++; qunlock(lb); c->mode = openmode(omode); @@ -266,19 +315,15 @@ loopbackclose(Chan *c) lb = c->aux; qlock(lb); - if(c->flag & COPEN){ - /* - * closing either side hangs up the stream - */ - switch(chan = NETTYPE(c->qid.path)){ - case Qdata0: - case Qdata1: - chan -= Qdata0; - if(--lb->link[chan].ref == 0){ - qhangup(lb->link[chan ^ 1].oq, nil); - looper(lb); - } - break; + + /* + * closing either side hangs up the stream + */ + if((c->flag & COPEN) && TYPE(c->qid.path) == Qdata){ + chan = ID(c->qid.path); + if(--lb->link[chan].ref == 0){ + qhangup(lb->link[chan ^ 1].oq, nil); + looper(lb); } } @@ -291,6 +336,8 @@ loopbackclose(Chan *c) closelink(&lb->link[chan], 0); qreopen(lb->link[chan].iq); qreopen(lb->link[chan].oq); + qsetlimit(lb->link[chan].oq, lb->link[chan].limit); + qsetlimit(lb->link[chan].iq, lb->link[chan].limit); } } ref = --lb->ref; @@ -326,6 +373,7 @@ closelink(Link *link, int dofree) link->tqtail = nil; link->tout = 0; link->tin = 0; + cycintrdel(&link->ci); iunlock(link); if(iq != nil){ qclose(iq); @@ -349,41 +397,56 @@ closelink(Link *link, int dofree) } static long -loopbackread(Chan *c, void *va, long n, vlong) +loopbackread(Chan *c, void *va, long n, vlong offset) { Loop *lb; - int chan; + Link *link; + char *buf; + long rv; lb = c->aux; -//ZZZ ctl message to set q limit -- qsetlimit(q, limit) -//ZZZ ctl message to set blocking/dropping qnoblock(q, dropit) -//ZZZ ctl message for delays - switch(chan = NETTYPE(c->qid.path)){ - case Qdir: - return devdirread(c, va, n, loopbackdir, nelem(loopbackdir), loopbackgen); - case Qdata0: - case Qdata1: - chan -= Qdata0; - return qread(lb->link[chan].iq, va, n); + switch(TYPE(c->qid.path)){ default: - panic("loopbackread"); + error(Eperm); + return -1; /* not reached */ + case Qtopdir: + case Qloopdir: + case Qportdir: + return devdirread(c, va, n, nil, 0, loopbackgen); + case Qdata: + return qread(lb->link[ID(c->qid.path)].iq, va, n); + case Qstatus: + link = &lb->link[ID(c->qid.path)]; + buf = smalloc(Statelen); + rv = snprint(buf, Statelen, "delay %ld %ld\n", link->delay0ns, link->delaynns); + rv += snprint(buf+rv, Statelen-rv, "limit %ld\n", link->limit); + rv += snprint(buf+rv, Statelen-rv, "indrop %d\n", link->indrop); + snprint(buf+rv, Statelen-rv, "droprate %ld\n", link->droprate); + rv = readstr(offset, va, n, buf); + free(buf); + break; + case Qstats: + link = &lb->link[ID(c->qid.path)]; + buf = smalloc(Statelen); + rv = snprint(buf, Statelen, "packets: %ld\n", link->packets); + rv += snprint(buf+rv, Statelen-rv, "bytes: %ld\n", link->bytes); + rv += snprint(buf+rv, Statelen-rv, "dropped: %ld\n", link->drops); + snprint(buf+rv, Statelen-rv, "soft overflows: %ld\n", link->soverflows); + rv = readstr(offset, va, n, buf); + free(buf); + break; } - return -1; /* not reached */ + return rv; } static Block* loopbackbread(Chan *c, long n, ulong offset) { Loop *lb; - int chan; lb = c->aux; - switch(chan = NETTYPE(c->qid.path)){ - case Qdata0: - case Qdata1: - chan -= Qdata0; - return qbread(lb->link[chan].iq, n); - } + if(TYPE(c->qid.path) == Qdata) + return qbread(lb->link[ID(c->qid.path)].iq, n); return devbread(c, n, offset); } @@ -392,30 +455,24 @@ static long loopbackbwrite(Chan *c, Block *bp, ulong off) { Loop *lb; - int chan; lb = c->aux; - switch(chan = NETTYPE(c->qid.path)){ - case Qdata0: - case Qdata1: - chan -= Qdata0; - return loopoput(lb, &lb->link[chan ^ 1], bp); - default: - return devbwrite(c, bp, off); - } + if(TYPE(c->qid.path) == Qdata) + return loopoput(lb, &lb->link[ID(c->qid.path) ^ 1], bp); + return devbwrite(c, bp, off); } static long loopbackwrite(Chan *c, void *va, long n, vlong off) { + Loop *lb; + Link *link; + Cmdbuf *cb; Block *bp; + long d0, dn, d0ns, dnns; - if(!islo()) - print("loopbackwrite hi %lux\n", getcallerpc(&c)); - - switch(NETTYPE(c->qid.path)){ - case Qdata0: - case Qdata1: + switch(TYPE(c->qid.path)){ + case Qdata: bp = allocb(n); if(waserror()){ freeb(bp); @@ -426,8 +483,65 @@ loopbackwrite(Chan *c, void *va, long n, vlong off) 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(cb->nf < 1) + error("short control request"); + if(strcmp(cb->f[0], "delay") == 0){ + if(cb->nf != 3) + error("usage: delay latency bytedelay"); + d0ns = strtol(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. + */ + d0 = NS2FASTHZ(d0ns); + dn = NS2FASTHZ(dnns); + + ilock(link); + link->delay0 = d0; + link->delayn = dn; + 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: droprate ofn"); + 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"); + break; default: - panic("loopbackwrite"); + error(Eperm); } return n; @@ -440,46 +554,55 @@ loopoput(Loop *lb, Link *link, Block *bp) n = BLEN(bp); - /* make it a single block with space for the loopback header */ - bp = padblock(bp, TMSIZE); + /* make it a single block with space for the loopback timing header */ + bp = padblock(bp, Tmsize); if(bp->next) bp = concatblock(bp); if(BLEN(bp) < lb->minmtu) bp = adjustblock(bp, lb->minmtu); + ptime(bp->rp, fastticks(nil)); + + link->packets++; + link->bytes += n; qbwrite(link->oq, bp); + looper(lb); return n; } -/* - * move blocks between queues if they are ready. - * schedule an interrupt for the next interesting time - */ static void looper(Loop *lb) { - vlong t, tt; - - tt = fastticks(nil); -again:; - t = pushlink(&lb->link[0], tt); - tt = pushlink(&lb->link[1], tt); - if(t > tt && tt) - t = tt; - if(t){ - tt = fastticks(nil); - if(tt <= t) - goto again; - //schedule an intr at tt-t fastticks - } + vlong t; + int chan; + + t = fastticks(nil); + for(chan = 0; chan < 2; chan++) + pushlink(&lb->link[chan], t); + clockintrsched(); } -static vlong +static void +linkintr(Ureg*, Cycintr *ci) +{ + Link *link; + + link = ci->a; + pushlink(link, ci->when); +} + +/* + * 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 t; + vlong tout, tin; /* * put another block in the link queue @@ -487,50 +610,89 @@ pushlink(Link *link, vlong now) ilock(link); if(link->iq == nil || link->oq == nil){ iunlock(link); - return 0; + return; + } - t = link->tout; - if(!t || t < now){ + cycintrdel(&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){ - if(!t) - t = now; - link->tout = t + BLEN(bp) * link->delayn; - ptime(bp->rp, t + link->delay0); -//ZZZ drop or introduce errors here + 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->delay0); if(link->tq == nil) link->tq = bp; else link->tqtail->next = bp; link->tqtail = bp; - }else - link->tout = 0; + } } + /* + * 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 */ - t = 0; + tin = 0; while(bp = link->tq){ - t = gtime(bp->rp); - if(t > now) + tin = gtime(bp->rp); + if(tin > now) break; - bp->rp += TMSIZE; + bp->rp += Tmsize; link->tq = bp->next; bp->next = nil; - if(link->nodrop) + if(!link->indrop) qpassnolim(link->iq, bp); else if(qpass(link->iq, bp) < 0) link->soverflows++; - t = 0; + tin = 0; } if(bp == nil && qisclosed(link->oq) && !qcanread(link->oq) && !qisclosed(link->iq)) qhangup(link->iq, nil); - link->tin = t; - if(!t || t < link->tout) - t = link->tout; + link->tin = tin; + if(!tin || tin > tout && tout) + tin = tout; + + link->ci.when = tin; + if(tin){ + if(tin < now) + panic("loopback unfinished business"); + cycintradd(&link->ci); + } iunlock(link); - return t; } static void diff --git a/port/devns16552.c b/port/devns16552.c index f847fedbca20427e1dabc6a41861ca45920ea9dd..cd0b5ea44dbf38cbac81da0262c394162f29f94c 100644 --- a/port/devns16552.c +++ b/port/devns16552.c @@ -284,16 +284,28 @@ ns16552break(Uart *p, int ms) uartwrreg(p, Format, 0); } +/* + * always called under lock(&p->flock) + */ static void -ns16552fifoon(Uart *p) +ns16552fifo(Uart *p, int n) { - ulong i, x; + ulong i; + int x; if(p->type < Ns550) return; x = splhi(); + if(n == 0){ + /* turn off fifo's */ + p->fifoon = 0; + uartwrreg(p, Fifoctl, 0); + splx(x); + return; + } + /* reset fifos */ uartwrreg(p, Fifoctl, Fclear); @@ -318,7 +330,6 @@ ns16552fifoon(Uart *p) /* didn't work, must be an earlier chip type */ p->type = Ns450; } - splx(x); } @@ -356,16 +367,10 @@ ns16552mflow(Uart *p, int n) } iunlock(&p->tlock); - ilock(&p->flock); - if(n) - /* turn on fifo's */ - ns16552fifoon(p); - else { - /* turn off fifo's */ - p->fifoon = 0; - uartwrreg(p, Fifoctl, 0); - } - iunlock(&p->flock); + /* modem needs fifo */ + lock(&p->flock); + ns16552fifo(p, n); + unlock(&p->flock); } /* @@ -985,6 +990,12 @@ ns16552ctl(Uart *p, char *cmd) qhangup(p->iq, 0); qhangup(p->oq, 0); break; + case 'i': + case 'I': + lock(&p->flock); + ns16552fifo(p, n); + unlock(&p->flock); + break; case 'L': case 'l': ns16552bits(p, n); @@ -1048,10 +1059,12 @@ ns16552write(Chan *c, void *buf, long n, vlong) * The fifo's turn themselves off sometimes. * It must be something I don't understand. -- presotto */ - lock(&p->flock); - if((p->istat & Fenabd) == 0 && p->fifoon && p->type < Ns550) - ns16552fifoon(p); - unlock(&p->flock); + if((p->istat & Fenabd) == 0 && p->fifoon && p->type < Ns550){ + lock(&p->flock); + if((p->istat & Fenabd) == 0 && p->fifoon && p->type < Ns550) + ns16552fifo(p, 1); + unlock(&p->flock); + } switch(NETTYPE(c->qid.path)){ case Ndataqid: