Browse Source

Plan 9 from Bell Labs 2003-11-08

David du Colombier 20 years ago
parent
commit
e580421da4

+ 9 - 8
dist/replica/plan9.db

@@ -4587,7 +4587,7 @@ sys/man/1/history - 664 sys sys 1044909169 1709
 sys/man/1/hoc - 664 sys sys 944959676 2357
 sys/man/1/idiff - 664 sys sys 1018386774 927
 sys/man/1/join - 664 sys sys 957920006 2562
-sys/man/1/jpg - 664 sys sys 1032632642 3671
+sys/man/1/jpg - 664 sys sys 1068209494 4003
 sys/man/1/kill - 664 sys sys 1018369246 1193
 sys/man/1/ktrace - 664 sys sys 957920006 1330
 sys/man/1/leak - 664 sys sys 1017423522 2871
@@ -4741,7 +4741,7 @@ sys/man/2/genrandom - 664 sys sys 1017251164 876
 sys/man/2/getcallerpc - 664 sys sys 964455063 670
 sys/man/2/getenv - 664 sys sys 944959695 685
 sys/man/2/getfcr - 664 sys sys 1015091521 2713
-sys/man/2/getfields - 664 sys sys 1015091522 1472
+sys/man/2/getfields - 664 sys sys 1068209043 1605
 sys/man/2/getpid - 664 sys sys 944959694 657
 sys/man/2/getuser - 664 sys sys 1016466457 641
 sys/man/2/getwd - 664 sys sys 971455511 701
@@ -5250,6 +5250,7 @@ sys/src/9/pc/etherif.h - 664 sys sys 1045063564 961
 sys/src/9/pc/etherigbe.c - 664 sys sys 1067792708 42430
 sys/src/9/pc/ethermii.c - 664 sys sys 1039803177 4555
 sys/src/9/pc/ethermii.h - 664 sys sys 1039895684 3259
+sys/src/9/pc/etherrhine.c - 664 sys sys 1068244865 13437
 sys/src/9/pc/ethersink.c - 664 sys sys 1048644103 1076
 sys/src/9/pc/ethersmc.c - 664 sys sys 1015014518 15079
 sys/src/9/pc/etherwavelan.c - 664 sys sys 1026847642 3722
@@ -5298,7 +5299,7 @@ sys/src/9/pc/sd53c8xx.n - 664 sys sys 1032059019 12455
 sys/src/9/pc/sdata.c - 664 sys sys 1067722685 50288
 sys/src/9/pc/sdmylex.c - 664 sys sys 1015014523 27750
 sys/src/9/pc/sdscsi.c - 664 sys sys 1055689892 7406
-sys/src/9/pc/trap.c - 664 sys sys 1067722686 20552
+sys/src/9/pc/trap.c - 664 sys sys 1068237910 20045
 sys/src/9/pc/uarti8250.c - 664 sys sys 1067722686 13859
 sys/src/9/pc/uartpci.c - 664 sys sys 1015014524 2709
 sys/src/9/pc/usb.h - 664 sys sys 1063857246 3566
@@ -5355,7 +5356,7 @@ sys/src/9/port/devmouse.c - 664 sys sys 1067722758 12203
 sys/src/9/port/devnmouse.c - 664 sys sys 1036812999 3738
 sys/src/9/port/devpipe.c - 664 sys sys 1032640439 5825
 sys/src/9/port/devpnp.c - 664 sys sys 1055688361 13021
-sys/src/9/port/devproc.c - 664 sys sys 1067880146 28269
+sys/src/9/port/devproc.c - 664 sys sys 1068237926 28403
 sys/src/9/port/devrealtime.c - 664 sys sys 1055688366 16209
 sys/src/9/port/devroot.c - 664 sys sys 1067722764 4254
 sys/src/9/port/devsd.c - 664 sys sys 1055688396 28669
@@ -5366,7 +5367,7 @@ sys/src/9/port/devssl.c - 664 sys sys 1045063590 26100
 sys/src/9/port/devtinyfs.c - 664 sys sys 1015278339 15347
 sys/src/9/port/devtls.c - 664 sys sys 1066737478 45222
 sys/src/9/port/devuart.c - 664 sys sys 1067722718 11683
-sys/src/9/port/edf.c - 664 sys sys 1068135508 12286
+sys/src/9/port/edf.c - 664 sys sys 1068215525 12348
 sys/src/9/port/edf.h - 664 sys sys 1067722760 1124
 sys/src/9/port/error.h - 664 sys sys 1055700517 2630
 sys/src/9/port/fault.c - 664 sys sys 1067722722 6628
@@ -5395,10 +5396,10 @@ sys/src/9/port/parse.c - 664 sys sys 1014931177 2026
 sys/src/9/port/pgrp.c - 664 sys sys 1067722718 3944
 sys/src/9/port/portclock.c - 664 sys sys 1068135508 4305
 sys/src/9/port/portdat.h - 664 sys sys 1067722763 22621
-sys/src/9/port/portfns.h - 664 sys sys 1067722759 11369
+sys/src/9/port/portfns.h - 664 sys sys 1068215525 11376
 sys/src/9/port/portmkfile - 664 sys sys 1067722766 2098
 sys/src/9/port/print.c - 664 sys sys 1014931178 227
-sys/src/9/port/proc.c - 664 sys sys 1068135509 24818
+sys/src/9/port/proc.c - 664 sys sys 1068215525 24867
 sys/src/9/port/qio.c - 664 sys sys 1067953182 23406
 sys/src/9/port/qlock.c - 664 sys sys 1067722765 3196
 sys/src/9/port/rdb.c - 664 sys sys 1018721202 1698
@@ -5410,7 +5411,7 @@ sys/src/9/port/swap.c - 664 sys sys 1055688551 6980
 sys/src/9/port/sysfile.c - 664 sys sys 1067722760 22127
 sys/src/9/port/sysproc.c - 664 sys sys 1067722765 15396
 sys/src/9/port/systab.h - 664 sys sys 1062721698 3044
-sys/src/9/port/taslock.c - 664 sys sys 1067722721 3348
+sys/src/9/port/taslock.c - 664 sys sys 1068209643 3532
 sys/src/9/port/thwack.c - 664 sys sys 1057323394 7253
 sys/src/9/port/thwack.h - 664 sys sys 1015278340 1792
 sys/src/9/port/tod.c - 664 sys sys 1067722762 4856

+ 10 - 0
dist/replica/plan9.log

@@ -14189,3 +14189,13 @@
 1068157925 0 c 386/9load - 775 sys sys 1068156766 181788
 1068157925 1 c sys/src/boot/pc/sdata.c - 664 sys sys 1068156754 35084
 1068159726 0 c sys/src/boot/pc/console.c - 664 sys sys 1068158999 3487
+1068210121 0 c sys/man/1/jpg - 664 sys sys 1068209494 4003
+1068210121 1 c sys/man/2/getfields - 664 sys sys 1068209043 1605
+1068210121 2 c sys/src/9/port/taslock.c - 664 sys sys 1068209643 3532
+1068215523 0 c sys/src/9/port/devproc.c - 664 sys sys 1068215525 28324
+1068215523 1 c sys/src/9/port/edf.c - 664 sys sys 1068215525 12348
+1068215523 2 c sys/src/9/port/portfns.h - 664 sys sys 1068215525 11376
+1068215523 3 c sys/src/9/port/proc.c - 664 sys sys 1068215525 24867
+1068238928 0 c sys/src/9/pc/trap.c - 664 sys sys 1068237910 20045
+1068238928 1 c sys/src/9/port/devproc.c - 664 sys sys 1068237926 28403
+1068246130 0 a sys/src/9/pc/etherrhine.c - 664 sys sys 1068244865 13437

+ 14 - 1
sys/man/1/jpg

@@ -145,6 +145,19 @@ Like
 but force the image to RGB even if it is originally grey-scale.
 .PD
 .PP
+.I Jpg
+has two extra options used to process the output of the LML
+video card (see
+.IR lml (1)):
+.TP
+.B -f
+Merge two adjacent images, which represent the two fields of a video picture,
+into a single image.
+.TP
+.B -F
+The input is a motion JPEG file, with multiple images representing frames of the movie.  Sets
+.BR -f .
+.PD
 .PP
 The
 .IR togif
@@ -175,7 +188,6 @@ By default, the images are displayed as fast as they can be rendered.
 This option specifies the time, in milliseconds, to pause while
 displaying the next named
 .IR file .
-.PD
 .PP
 .I Gif
 translates files that contain a `transparency' index by attaching
@@ -183,6 +195,7 @@ an alpha channel to the converted image.
 .SH SOURCE
 .B /sys/src/cmd/jpg
 .SH "SEE ALSO"
+.IR lml (1),
 .IR page (1),
 .IR image (6).
 .SH BUGS

+ 34 - 27
sys/man/2/getfields

@@ -20,45 +20,52 @@ int	gettokens(char *str, char **args, int maxargs, char *delims)
 int	tokenize(char *str, char **args, int maxargs)
 .SH DESCRIPTION
 .I Getfields
-breaks the null-terminated
-.SM UTF
-string
-.I str
-into at most
-.I maxargs
-null-terminated fields and places pointers to the start of these fields in the array
-.IR args .
-Some of the bytes in
-.I str
-are overwritten.
-If there are more than
-.I maxargs
-fields,
-only the first
+places into the array
+.I args
+pointers to the first
 .I maxargs
-fields will be set.
-.I Delims
-is a
+fields of the null terminated
 .SM UTF
-string defining a set of delimiters.
+string
+.IR str .
+Delimiters between these fields are set to null.
 .PP
+Fields are substrings of
+.I str
+whose definition depends on the value of
+.IR multiflag.
 If
 .I multiflag
 is zero,
 adjacent fields are separated by exactly one delimiter.
-A string containing
-.I n
-delimiter characters
-contains
-.IR n +1
-fields.
+For example
+.EX
+
+	getfields("#alice#bob##charles###", arg, 3, 0, "#");
+
+.EE
+yields three substrings:
+null-string ,
+.BR "alice" ,
+and
+.BR "bob##charles###" .
 If the
 .I multiflag
 argument is not zero,
 a field is a non-empty string of non-delimiters.
+For example
+.EX
+
+	getfields("#alice#bob##charles###", arg, 3, 1, "#");
+
+.EE
+yields the three substrings:
+.BR "alice" ,
+.BR "bob" ,
+and
+.BR "charles###" .
 .PP
-Getfields
-returns the number of tokens processed.
+Getfields returns the number of fields pointed to.
 .PP
 .I Gettokens
 is the same as

+ 716 - 0
sys/src/9/pc/etherrhine.c

@@ -0,0 +1,716 @@
+ /*
+	Via Rhine driver, written for VT6102.
+	Uses the ethermii to control PHY.
+
+	Currently always copies on both, tx and rx.
+	rx side could be copy-free, and tx-side might be made
+	(almost) copy-free by using (possibly) two descriptors (if it allows
+	arbitrary tx lengths, which it should..): first for alignment and
+	second for rest of the frame. Rx-part should be worth doing.
+*/
+
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "../port/error.h"
+#include "../port/netif.h"
+#include "etherif.h"
+
+#include "ethermii.h"
+
+typedef struct Desc Desc;
+typedef struct Ctlr Ctlr;
+
+enum {
+	Ntxd = 4,
+	Nrxd = 4,
+	Nwait = 50,
+	Ntxstats = 9,
+	Nrxstats = 8,
+	BIGSTR = 8192,
+};
+
+struct Desc {
+	ulong stat;
+	ulong size;
+	ulong addr;
+	ulong next;
+	char *buf;
+	ulong pad[3];
+};
+
+struct Ctlr {
+	Pcidev *pci;
+	int attached;
+	int txused;
+	int txhead;
+	int txtail;
+	int rxtail;
+	ulong port;
+
+	Mii mii;
+
+	ulong txstats[Ntxstats];
+	ulong rxstats[Nrxstats];
+
+	Desc *txd;	/* wants to be aligned on 16-byte boundary */
+	Desc *rxd;
+
+	QLock attachlck;
+	Lock lock;
+};
+
+#define ior8(c, r)	(inb((c)->port+(r)))
+#define ior16(c, r)	(ins((c)->port+(r)))
+#define ior32(c, r)	(inl((c)->port+(r)))
+#define iow8(c, r, b)	(outb((c)->port+(r), (int)(b)))
+#define iow16(c, r, w)	(outs((c)->port+(r), (ushort)(w)))
+#define iow32(c, r, l)	(outl((c)->port+(r), (ulong)(l)))
+
+enum Regs {
+	Eaddr = 0x0,
+	Rcr = 0x6,
+	Tcr = 0x7,
+	Cr = 0x8,
+	Isr = 0xc,
+	Imr = 0xe,
+	McastAddr = 0x10,
+	RxdAddr = 0x18,
+	TxdAddr = 0x1C,
+	Bcr = 0x6e,
+	RhineMiiPhy = 0x6C,
+	RhineMiiSr = 0x6D,
+	RhineMiiCr = 0x70,
+	RhineMiiAddr = 0x71,
+	RhineMiiData = 0x72,
+	Eecsr = 0x74,
+	ConfigB = 0x79,
+	ConfigD = 0x7B,
+	MiscCr = 0x80,
+	HwSticky = 0x83,
+	MiscIsr = 0x84,
+	MiscImr = 0x86,
+	WolCrSet = 0xA0,
+	WolCfgSet = 0xA1,
+	WolCgSet = 0xA3,
+	WolCrClr = 0xA4,
+	PwrCfgClr = 0xA5,
+	WolCgClr = 0xA7,
+};
+
+enum Rcrbits {
+	RxErrX = 1<<0,
+	RxSmall = 1<<1,
+	RxMcast = 1<<2,
+	RxBcast = 1<<3,
+	RxProm = 1<<4,
+	RxFifo64 = 0<<5, RxFifo32 = 1<<5, RxFifo128 = 2<<5, RxFifo256 = 3<<5,
+	RxFifo512 = 4<<5, RxFifo768 = 5<<5, RxFifo1024 = 6<<5,
+	RxFifoStoreForward = 7<<5,
+};
+
+enum Tcrbits {
+	TxLoopback0 = 1<<1,
+	TxLoopback1 = 1<<2,
+	TxBackoff = 1<<3,
+	TxFifo128 = 0<<5, TxFifo256 = 1<<5, TxFifo512 = 2<<5, TxFifo1024 = 3<<5,
+	TxFifoStoreForward = 7<<5,
+};
+
+enum Crbits {
+	Init = 1<<0,
+	Start = 1<<1,
+	Stop = 1<<2,
+	RxOn = 1<<3,
+	TxOn = 1<<4,
+	Tdmd = 1<<5,
+	Rdmd = 1<<6,
+	EarlyRx = 1<<8,
+	Reserved0 = 1<<9,
+	FullDuplex = 1<<10,
+	NoAutoPoll = 1<<11,
+	Reserved1 = 1<<12,
+	Tdmd1 = 1<<13,
+	Rdmd1 = 1<<14,
+	Reset = 1<<15,
+};
+
+enum Isrbits {
+	RxOk = 1<<0,
+	TxOk = 1<<1,
+	RxErr = 1<<2,
+	TxErr = 1<<3,
+	TxBufUdf = 1<<4,
+	RxBufLinkErr = 1<<5,
+	BusErr = 1<<6,
+	CrcOvf = 1<<7,
+	EarlyRxInt = 1<<8,
+	TxFifoUdf = 1<<9,
+	RxFifoOvf = 1<<10,
+	TxPktRace = 1<<11,
+	NoRxbuf = 1<<12,
+	TxCollision = 1<<13,
+	PortCh = 1<<14,
+	GPInt = 1<<15
+};
+
+enum Bcrbits {
+	Dma32 = 0<<0, Dma64 = 1<<0, Dma128 = 2<<0,
+	Dma256 = 3<<0, Dma512 = 4<<0, Dma1024 = 5<<0,
+	DmaStoreForward = 7<<0,
+	DupRxFifo0 = 1<<3, DupRxFifo1 = 1<<4, DupRxFifo2 = 1<<5,
+	ExtraLed = 1<<6,
+	MediumSelect = 1<<7,
+	PollTimer0 = 1<<8, PollTimer1 = 1<<9, PollTimer2 = 1<<10,
+	DupTxFifo0 = 1<<11, DupTxFifo1 = 1<<12, DupTxFifo2 = 1<<13,
+};
+
+enum Eecsrbits {
+	EeAutoLoad = 1<<5,
+};
+
+enum MiscCrbits {
+	Timer0Enable= 1<<0,
+	Timer0Suspend = 1<<1,
+	HalfDuplexFlowControl = 1<<2,
+	FullDuplexFlowControl = 1<<3,
+	Timer1Enable = 1<<8,
+	ForceSoftReset = 1<<14,
+};
+
+enum HwStickybits {
+	StickyDS0 = 1<<0,
+	StickyDS1 = 1<<1,
+	WOLEna = 1<<2,
+	WOLStat = 1<<3,
+};
+
+enum WolCgbits {
+	PmeOvr = 1<<7,
+};
+
+enum Descbits {
+	OwnNic = 1<<31,		/* stat */
+	TxAbort = 1<<8,		/* stat */
+	TxError = 1<<15,		/* stat */
+	RxChainbuf = 1<<10,	/* stat */
+	RxChainStart = 1<<9,	/* stat */
+	RxChainEnd = 1<<8,		/* stat */
+	Chainbuf = 1<<15,		/* size rx & tx*/
+	TxDisableCrc = 1<<16,	/* size */
+	TxChainStart = 1<<21,	/* size */
+	TxChainEnd = 1<<22,	/* size */
+	TxInt = 1<<23,			/* size */
+};
+
+enum ConfigDbits {
+	BackoffOptional = 1<<0,
+	BackoffAMD = 1<<1,
+	BackoffDEC = 1<<2,
+	BackoffRandom = 1<<3,
+	PmccTestMode = 1<<4,
+	PciReadlineCap = 1<<5,
+	DiagMode = 1<<6,
+	MmioEnable = 1<<7,
+};
+
+enum ConfigBbits {
+	LatencyTimer = 1<<0,
+	WriteWaitState = 1<<1,
+	ReadWaitState = 1<<2,
+	RxArbit = 1<<3,
+	TxArbit = 1<<4,
+	NoMemReadline = 1<<5,
+	NoParity = 1<<6,
+	NoTxQueuing = 1<<7,
+};
+
+enum RhineMiiCrbits {
+	Mdc = 1<<0,
+	Mdi = 1<<1,
+	Mdo = 1<<2,
+	Mdout = 1<<3,
+	Mdpm = 1<<4,
+	Wcmd = 1<<5,
+	Rcmd = 1<<6,
+	Mauto = 1<<7,
+};
+
+enum RhineMiiSrbits {
+	Speed10M = 1<<0,
+	LinkFail = 1<<1,
+	PhyError = 1<<3,
+	DefaultPhy = 1<<4,
+	ResetPhy = 1<<7,
+};
+
+enum RhineMiiAddrbits {
+	Mdone = 1<<5,
+	Msrcen = 1<<6,
+	Midle = 1<<7,
+};
+
+static char *
+txstatnames[Ntxstats] = {
+	"aborts (excess collisions)",
+	"out of window collisions",
+	"carrier sense losses",
+	"fifo underflows",
+	"invalid descriptor format or underflows",
+	"system errors",
+	"reserved",
+	"transmit errors",
+	"collisions",
+};
+
+static char *
+rxstatnames[Nrxstats] = {
+	"receiver errors",
+	"crc errors",
+	"frame alignment errors",
+	"fifo overflows",
+	"long packets",
+	"run packets",
+	"system errors",
+	"buffer underflows",
+};
+
+static void
+attach(Ether *edev)
+{
+	Ctlr *ctlr;
+	Desc *txd, *rxd, *td, *rd;
+	Mii *mi;
+	MiiPhy *phy;
+	int i, s;
+	
+	ctlr = edev->ctlr;
+	qlock(&ctlr->attachlck);
+	if (ctlr->attached == 0) {
+		txd = ctlr->txd;
+		rxd = ctlr->rxd;
+		for (i = 0; i < Ntxd; ++i) {
+			td = &txd[i];
+			td->next = PCIWADDR(&txd[(i+1) % Ntxd]);
+			td->buf = xspanalloc(sizeof(Etherpkt)+4, 4, 0);
+			td->addr = PCIWADDR(td->buf);
+			td->size = 0;
+			coherence();
+			td->stat = 0;
+		}
+		for (i = 0; i < Nrxd; ++i) {
+			rd = &rxd[i];
+			rd->next = PCIWADDR(&rxd[(i+1) % Nrxd]);
+			rd->buf = xspanalloc(sizeof(Etherpkt)+4, 4, 0);
+			rd->addr = PCIWADDR(rd->buf);
+			rd->size = sizeof(Etherpkt)+4;
+			coherence();
+			rd->stat = OwnNic;
+		}
+
+		ctlr->txhead = ctlr->txtail = ctlr->rxtail = 0;
+		mi = &ctlr->mii;
+		miistatus(mi);
+		phy = mi->curphy;
+		s = splhi();
+		iow32(ctlr, TxdAddr, PCIWADDR(&txd[0]));
+		iow32(ctlr, RxdAddr, PCIWADDR(&rxd[0]));
+		iow16(ctlr, Cr, (phy->fd ? FullDuplex : 0) | NoAutoPoll | TxOn | RxOn | Start | Rdmd);
+		iow16(ctlr, Isr, 0xFFFF);
+		iow16(ctlr, Imr, 0xFFFF);
+		iow8(ctlr, MiscIsr, 0xFF);
+		iow8(ctlr, MiscImr, ~(3<<5));
+		splx(s);
+	}
+	ctlr->attached++;
+	qunlock(&ctlr->attachlck);
+}
+
+static void
+txstart(Ether *edev)
+{
+	Ctlr *ctlr;
+	Desc *txd, *td;
+	Block *b;
+	int i, txused, n;
+	ulong size;
+
+	ctlr = edev->ctlr;
+
+	txd = ctlr->txd;
+	i = ctlr->txhead;
+	txused = ctlr->txused;
+	n = 0;
+	while (txused < Ntxd) {
+		if ((b = qget(edev->oq)) == nil)
+			break;
+
+		td = &txd[i];
+
+		size = BLEN(b);
+		memmove(td->buf, b->rp, size);
+		freeb(b);
+		td->size = size | TxChainStart | TxChainEnd | TxInt; /* could reduce number of ints here */
+		coherence();
+		td->stat = OwnNic;
+		i = (i + 1) % Ntxd;
+		txused++;
+		n++;
+	}
+	if (n)
+		iow16(ctlr, Cr, ior16(ctlr, Cr) | Tdmd);
+
+	ctlr->txhead = i;
+	ctlr->txused = txused;
+}
+
+static void
+transmit(Ether *edev)
+{
+	Ctlr *ctlr;
+	ctlr = edev->ctlr;
+	ilock(&ctlr->lock);
+	txstart(edev);
+	iunlock(&ctlr->lock);
+}
+
+static void
+txcomplete(Ether *edev)
+{
+	Ctlr *ctlr;
+	Desc *txd, *td;
+	int i, txused, j;
+	ulong stat;
+
+	ctlr = edev->ctlr;
+ 	txd = ctlr->txd;
+	txused = ctlr->txused;
+	i = ctlr->txtail;
+	while (txused > 0) {
+		td = &txd[i];
+		stat = td->stat;
+
+		if (stat & OwnNic)
+			break;
+
+		ctlr->txstats[Ntxstats-1] += stat & 0xF;
+		for (j = 0; j < Ntxstats-1; ++j)
+			if (stat & (1<<(j+8)))
+				ctlr->txstats[j]++;
+
+		i = (i + 1) % Ntxd;
+		txused--;
+	}
+	ctlr->txused = txused;
+	ctlr->txtail = i;
+
+	if (txused <= Ntxd/2)
+		txstart(edev);
+}
+
+static void
+interrupt(Ureg *, void *arg)
+{
+	Ether *edev;
+	Ctlr *ctlr;
+	ushort  isr, misr;
+	ulong stat;
+	Desc *rxd, *rd;
+	int i, n, j;
+
+	edev = (Ether*)arg;
+	ctlr = edev->ctlr;
+	iow16(ctlr, Imr, 0);
+	isr = ior16(ctlr, Isr);
+	iow16(ctlr, Isr, 0xFFFF);
+	misr = ior16(ctlr, MiscIsr) & ~(3<<5); /* don't care about used defined ints */
+
+	if (isr & RxOk) {
+		Block *b;
+		int size;
+		rxd = ctlr->rxd;
+		i = ctlr->rxtail;
+
+		n = 0;
+		while ((rxd[i].stat & OwnNic) == 0) {
+			rd = &rxd[i];
+			stat = rd->stat;
+			for (j = 0; j < Nrxstats; ++j)
+				if (stat & (1<<j))
+					ctlr->rxstats[j]++;
+
+			if (stat & 0xFF)
+				iprint("rx: %lux\n", stat & 0xFF);
+
+			size = ((rd->stat>>16) & 2047) - 4;
+			b = iallocb(sizeof(Etherpkt));
+			memmove(b->wp, rd->buf, size);
+			b->wp += size;
+			etheriq(edev, b, 1);
+			rd->size = sizeof(Etherpkt)+4;
+			coherence();
+			rd->stat = OwnNic;
+			i = (i + 1) % Nrxd;
+			n++;
+		}
+		if (n)
+			iow16(ctlr, Cr, ior16(ctlr, Cr) | Rdmd);
+		ctlr->rxtail = i;
+		isr &= ~RxOk;
+	}
+	if (isr & TxOk) {
+		txcomplete(edev);
+		isr &= ~TxOk;
+	}
+	if (isr | misr)
+		iprint("etherrhine: unhandled irq(s). isr:%x misr:%x\n", isr, misr);
+
+	iow16(ctlr, Imr, 0xFFFF);
+}
+
+static void
+promiscuous(void *arg, int enable)
+{
+	Ether *edev;
+	Ctlr *ctlr;
+
+	edev = arg;
+	ctlr = edev->ctlr;
+	ilock(&ctlr->lock);
+	iow8(ctlr, Rcr, ior8(ctlr, Rcr) | (enable ? RxProm : RxBcast));
+	iunlock(&ctlr->lock);
+}
+
+static int
+miiread(Mii *mii, int phy, int reg)
+{
+	Ctlr *ctlr;
+	int n;
+
+	ctlr = mii->ctlr;
+	
+	n = Nwait;
+	while (n-- && ior8(ctlr, RhineMiiCr) & (Rcmd | Wcmd))
+		microdelay(1);
+	if (n == Nwait)
+		iprint("etherrhine: miiread: timeout\n");
+
+	iow8(ctlr, RhineMiiCr, 0);
+	iow8(ctlr, RhineMiiPhy, phy);
+	iow8(ctlr, RhineMiiAddr, reg);
+	iow8(ctlr, RhineMiiCr, Rcmd);
+
+	n = Nwait;
+	while (n-- && ior8(ctlr, RhineMiiCr) & Rcmd)
+		microdelay(1);
+	if (n == Nwait)
+		iprint("etherrhine: miiread: timeout\n");
+
+	n = ior16(ctlr, RhineMiiData);
+
+	return n;
+}
+
+static int
+miiwrite(Mii *mii, int phy, int reg, int data)
+{
+	int n;
+	Ctlr *ctlr;
+
+	ctlr = mii->ctlr;
+
+	n = Nwait;
+	while (n-- && ior8(ctlr, RhineMiiCr) & (Rcmd | Wcmd))
+		microdelay(1);
+	if (n == Nwait)
+		iprint("etherrhine: miiwrite: timeout\n");
+
+	iow8(ctlr, RhineMiiCr, 0);
+	iow8(ctlr, RhineMiiPhy, phy);
+	iow8(ctlr, RhineMiiAddr, reg);
+	iow16(ctlr, RhineMiiData, data);
+	iow8(ctlr, RhineMiiCr, Wcmd);
+
+	n = Nwait;
+	while (n-- && ior8(ctlr, RhineMiiCr) & Wcmd)
+		microdelay(1);
+	if (n == Nwait)
+		iprint("etherrhine: miiwrite: timeout\n");
+
+	return 0;
+}
+
+static void
+init(Ether *edev)
+{
+	Ctlr *ctlr;
+	MiiPhy *phy;
+	int i;
+
+	ctlr = edev->ctlr;
+
+	ilock(&ctlr->lock);
+
+	pcisetbme(ctlr->pci);
+
+	iow16(ctlr, Cr, ior16(ctlr, Cr) | Stop);
+	iow16(ctlr, Cr, ior16(ctlr, Cr) | Reset);
+
+	for (i = 0; i < Nwait; ++i) {
+		if ((ior16(ctlr, Cr) & Reset) == 0)
+			break;
+		delay(5);
+	}
+	if (i == Nwait)
+		iprint("etherrhine: reset timeout\n");
+
+	iow8(ctlr, Eecsr, ior8(ctlr, Eecsr) | EeAutoLoad);
+	for (i = 0; i < Nwait; ++i) {
+		if ((ior8(ctlr, Eecsr) & EeAutoLoad) == 0)
+			break;
+		delay(5);
+	}
+	if (i == Nwait)
+		iprint("etherrhine: eeprom autoload timeout\n");
+
+	for (i = 0; i < Eaddrlen; ++i)
+		edev->ea[i] = ior8(ctlr, Eaddr + i);
+
+	ctlr->mii.mir = miiread;
+	ctlr->mii.miw = miiwrite;
+	ctlr->mii.ctlr = ctlr;
+
+	if(mii(&ctlr->mii, ~0) == 0 || ctlr->mii.curphy == nil){
+		iprint("etherrhine: init mii failure\n");
+		return;
+	}
+	for (i = 0; i < NMiiPhy; ++i)
+		if (ctlr->mii.phy[i])
+			if (ctlr->mii.phy[i]->oui != 0xFFFFF)
+				ctlr->mii.curphy = ctlr->mii.phy[i];
+
+	miistatus(&ctlr->mii);
+	phy = ctlr->mii.curphy;
+	edev->mbps = phy->speed;
+
+	iow16(ctlr, Imr, 0);
+	iow16(ctlr, Cr, ior16(ctlr, Cr) | Stop);
+
+	iunlock(&ctlr->lock);
+}
+
+static Pcidev *
+rhinematch(ulong)
+{
+	static int nrhines = 0;
+	int nfound = 0;
+	Pcidev *p = nil;
+
+	while (p = pcimatch(p, 0x1106, 0))
+		if (p->did == 0x3065)
+			if (++nfound > nrhines) {
+				nrhines++;
+				break;
+			}
+	return p;
+}
+static long
+ifstat(Ether* edev, void* a, long n, ulong offset)
+{
+	int l = 0, i;
+	char *p;
+	Ctlr *ctlr;
+	ctlr = edev->ctlr;
+	p = malloc(BIGSTR);
+
+	for (i = 0; i < Ntxstats; ++i)
+		if (txstatnames[i])
+			l += snprint(p+l, BIGSTR - l, "tx: %s: %lud\n", txstatnames[i], ctlr->txstats[i]);
+
+	for (i = 0; i < Nrxstats; ++i)
+		if (rxstatnames[i])
+			l += snprint(p+l, BIGSTR - l, "rx: %s: %lud\n", rxstatnames[i], ctlr->rxstats[i]);
+
+/*
+	for (i = 0; i < NMiiPhyr; ++i) {
+		if ((i % 8) == 0)
+			l += snprint(p + l, BIGSTR - l, "\nmii 0x%02x:", i);
+		reg=miimir(&ctlr->mii, i);
+		reg=miimir(&ctlr->mii, i);
+		l += snprint(p + l, BIGSTR - l, " %4ux", reg);
+	}
+
+	for (i = 0; i < 0x100; i+=1) {
+		if ((i % 16) == 0)
+			l += snprint(p + l, BIGSTR - l, "\nreg 0x%02x:", i);
+		else if ((i % 2) == 0)
+			l += snprint(p + l, BIGSTR - l, " ");
+		reg=ior8(ctlr, i);
+		l += snprint(p + l, BIGSTR - l, "%02x", reg);
+	}
+	l += snprint(p + l, BIGSTR - l, " \n");
+*/
+
+
+	n = readstr(offset, a, n, p);
+	free(p);
+
+	return n;
+}
+
+static int
+pnp(Ether *edev)
+{
+	Pcidev *p;
+	Ctlr *ctlr;
+	ulong port;
+	ulong size;
+
+	p = rhinematch(edev->port);
+	if (p == nil)
+		return -1;
+
+	port = p->mem[0].bar & ~1;
+	size = p->mem[0].size;
+	if (ioalloc(port, size, 0, "rhine") < 0) {
+		print("etherrhine: couldn't allocate port %lud\n", port);
+		return -1;
+	}
+
+	if ((ctlr = malloc(sizeof(Ctlr))) == nil) {
+		print("etherrhine: couldn't allocate memory for ctlr\n");
+		return -1;
+	}
+	memset(ctlr, 0, sizeof(Ctlr));
+	ctlr->txd = xspanalloc(sizeof(Desc) * Ntxd, 16, 0);
+	ctlr->rxd = xspanalloc(sizeof(Desc) * Nrxd, 16, 0);
+		
+	ctlr->pci = p;
+	ctlr->port = port;
+
+	edev->ctlr = ctlr;
+	edev->port = ctlr->port;
+	edev->irq = p->intl;
+	edev->tbdf = p->tbdf;
+
+	init(edev);
+
+	edev->interrupt = interrupt;
+	edev->arg = edev;
+
+	edev->attach = attach;
+	edev->transmit = transmit;
+	edev->ifstat = ifstat;
+	edev->promiscuous = promiscuous;
+
+	return 0;
+}
+
+void
+etherrhinelink(void)
+{
+	addethercard("rhine", pnp);
+}

+ 5 - 23
sys/src/9/pc/trap.c

@@ -19,7 +19,7 @@ static Vctl *vctl[256];
 
 enum
 {
-	Ntimevec = 10		/* number of time buckets for each intr */
+	Ntimevec = 20		/* number of time buckets for each intr */
 };
 ulong intrtimes[256][Ntimevec];
 
@@ -267,7 +267,7 @@ intrtime(Mach*, int vno)
 	if(up == nil && m->perf.inidle > diff)
 		m->perf.inidle -= diff;
 
-	diff /= m->cpumhz*10;	// quantum = 10µsec
+	diff /= m->cpumhz*100;	// quantum = 100µsec
 	if(diff >= Ntimevec)
 		diff = Ntimevec-1;
 	intrtimes[vno][diff]++;
@@ -304,17 +304,12 @@ trap(Ureg* ureg)
 	char buf[ERRMAX];
 	Vctl *ctl, *v;
 	Mach *mach;
-	Ureg urcopy;
-	ulong *u;
-
-	urcopy = *ureg;
-	memset(buf, 0, sizeof(buf));
 
 	m->perf.intrts = perfticks();
 	user = (ureg->cs & 0xFFFF) == UESEL;
 	if(user){
 		up->dbgreg = ureg;
-		if (m->havetsc)
+		if(m->havetsc)
 			cycles(&up->kentry);
 	}
 
@@ -329,20 +324,8 @@ trap(Ureg* ureg)
 		if(ctl->isr)
 			ctl->isr(vno);
 		for(v = ctl; v != nil; v = v->next){
-			if(v->f){
+			if(v->f)
 				v->f(ureg, v->a);
-				if (vno & ~0xff){
-					u = (ulong*)&u;
-					for(i = 0; i < 40; ++i && (u+=4))
-						iprint("0x%lux:	0x%lux	0x%lux	0x%lux	0x%lux\n", u, u[0], u[1], u[2], u[3]);
-					iprint("vno 0x%ux after calling %s\n", vno, v->name);
-					iprint("ureg di si bp nsp bx dx cx ax gs fs es ds trap ecode pc cs flags sp ss\n");
-					u = (ulong*)ureg;
-					for(i = 0; i < 19; i++)
-						iprint("0x%lux ", u[i]);
-					panic("vno");
-				}
-			}
 		}
 		if(ctl->eoi)
 			ctl->eoi(vno);
@@ -505,7 +488,6 @@ _dumpstack(Ureg *ureg)
 	ulong l, v, i, estack;
 	extern ulong etext;
 
-return;
 	print("ktrace /kernel/path %.8lux %.8lux\n", ureg->pc, ureg->sp);
 	i = 0;
 	if(up
@@ -740,7 +722,7 @@ notify(Ureg* ureg)
 		pexit(n->msg, n->flag!=NDebug);
 	}
 
-	if(up->notified) {
+	if(up->notified){
 		qunlock(&up->debug);
 		splhi();
 		return 0;

+ 10 - 5
sys/src/9/port/devproc.c

@@ -155,7 +155,7 @@ static Lock tlock;
 static int topens;
 static int tproduced, tconsumed;
 static Rendez teventr;
-void	(*proctrace)(Proc*, int); 
+void	(*proctrace)(Proc*, int, vlong); 
 
 extern int unfair;
 
@@ -265,18 +265,23 @@ procgen(Chan *c, char *name, Dirtab *tab, int, int s, Dir *dp)
 }
 
 static void
-_proctrace(Proc*p, Tevent etype)
+_proctrace(Proc*p, Tevent etype, vlong ts)
 {
 	Traceevent *te;
 
-	if (p->trace == 0 || topens == 0 || 
-			(tproduced - tconsumed >= Nevents))
+	if (p->trace == 0 || topens == 0)
 		return;
 
+	if(tproduced - tconsumed >= Nevents)
+		tconsumed = tproduced - Nevents + 1;
+		/* discard oldest, never mind the race */
 	te = &tevents[tproduced&Emask];
 	te->pid = p->pid;
 	te->etype = etype;
-	te->time = todget(nil);
+	if (ts == 0)
+		te->time = todget(nil);
+	else
+		te->time = ts;
 	tproduced++;
 
 	/* To avoid circular wakeup when used in combination with 

+ 16 - 15
sys/src/9/port/edf.c

@@ -123,6 +123,7 @@ deadlineintr(Ureg*, Timer *t)
 		return;
 
 	p = t->ta;
+
 	DPRINT("%t deadlineintr %lud[%s]\n", todget(nil), p->pid, statename[p->state]);
 	/* If we're interrupting something other than the proc pointed to by t->a,
 	 * we've already achieved recheduling, so we need not do anything
@@ -142,7 +143,7 @@ release(Proc *p)
 {
 	/* Called with edflock held */
 	Edf *e;
-	void (*pt)(Proc*, int);
+	void (*pt)(Proc*, int, vlong);
 
 	e = p->edf;
 	e->flags &= ~Yield;
@@ -165,8 +166,10 @@ release(Proc *p)
 		e->S = e->C;
 		DPRINT("%t release %lud[%s], r=%t, d=%t, t=%t, S=%t\n",
 			now, p->pid, statename[p->state], e->r, e->d, e->t, e->S);
-		if (pt = proctrace)
-			pt(p, SRelease);
+		if (pt = proctrace){
+			pt(p, SRelease, e->r);
+			pt(p, SDeadline, e->d);
+		}
 	}else{
 		DPRINT("%t release %lud[%s], too late t=%t, called from 0x%lux\n",
 			now, p->pid, statename[p->state], e->t, getcallerpc(&p));
@@ -238,7 +241,7 @@ edfrecord(Proc *p)
 {
 	vlong used;
 	Edf *e;
-	void (*pt)(Proc*, int);
+	void (*pt)(Proc*, int, vlong);
 
 	e = p->edf;
 	edflock();
@@ -250,7 +253,7 @@ edfrecord(Proc *p)
 	if (e->S > 0){
 		if (e->S <= used){
 			if(pt = proctrace)
-				pt(p, SDeadline);
+				pt(p, SSlice, now);
 			DPRINT("%t edfrecord slice used up\n", now);
 			e->d = now;
 			e->S = 0;
@@ -303,7 +306,7 @@ edfadmit(Proc *p)
 	Edf *e;
 	int i;
 	Proc *r;
-	void	(*pt)(Proc*, int);
+	void (*pt)(Proc*, int, vlong);
 
 	e = p->edf;
 	if (e->flags & Admitted)
@@ -331,7 +334,7 @@ edfadmit(Proc *p)
 	e->flags |= Admitted;
 
 	if(pt = proctrace)
-		pt(p, SAdmit);
+		pt(p, SAdmit, now);
 
 	/* Look for another proc with the same period to synchronize to */
 	SET(r);
@@ -392,13 +395,13 @@ void
 edfstop(Proc *p)
 {
 	Edf *e;
-	void	(*pt)(Proc*, int);
+	void (*pt)(Proc*, int, vlong);
 
 	if ((e = p->edf) && (e->flags & Admitted)){
 		edflock();
 		DPRINT("%t edfstop %lud[%s]\n", now, p->pid, statename[p->state]);
 		if(pt = proctrace)
-			pt(p, SExpel);
+			pt(p, SExpel, now);
 		e->flags &= ~Admitted;
 		if (p->tt)
 			timerdel(p);
@@ -417,12 +420,12 @@ edfyield(void)
 {
 	/* sleep until next release */
 	Edf *e;
-	void	(*pt)(Proc*, int);
+	void (*pt)(Proc*, int, vlong);
 
 	edflock();
 	e = up->edf;
 	if(pt = proctrace)
-		pt(up, SYield);
+		pt(up, SYield, now);
 	while(e->t < now)
 		e->t += e->T;
 	e->r = e->t;
@@ -444,7 +447,7 @@ edfready(Proc *p)
 	Edf *e;
 	Schedq *rq;
 	Proc *l, *pp;
-	void (*pt)(Proc*, int);
+	void (*pt)(Proc*, int, vlong);
 
 	if ((e = p->edf) == nil || (e->flags & Admitted) == 0)
 		return 0;	/* Not an edf process */
@@ -489,8 +492,6 @@ edfready(Proc *p)
 		DPRINT("%t edfready %lud %s release now\n", now, p->pid, statename[p->state]);
 		/* release now */
 		release(p);
-		if(pt = proctrace)
-			pt(p, SRelease);
 	}
 	DPRINT("^");
 	rq = &runq[PriEdf];
@@ -517,7 +518,7 @@ edfready(Proc *p)
 	p->readytime = m->ticks;
 	p->state = Ready;
 	if(pt = proctrace)
-		pt(p, SReady);
+		pt(p, SReady, now);
 	edfunlock();
 	return 1;
 }

+ 1 - 1
sys/src/9/port/portfns.h

@@ -243,7 +243,7 @@ void		procinit0(void);
 void		procflushseg(Segment*);
 void		procpriority(Proc*, int, int);
 Proc*		proctab(int);
-extern void	(*proctrace)(Proc*, int); 
+extern void	(*proctrace)(Proc*, int, vlong); 
 void		procwired(Proc*, int);
 Pte*		ptealloc(void);
 Pte*		ptecpy(Pte*);

+ 12 - 8
sys/src/9/port/proc.c

@@ -213,7 +213,7 @@ ready(Proc *p)
 {
 	int s, pri;
 	Schedq *rq;
-	void (*pt)(Proc*, int);
+	void (*pt)(Proc*, int, vlong);
 
 	s = splhi();
 
@@ -258,7 +258,8 @@ ready(Proc *p)
 	p->readytime = m->ticks;
 	p->state = Ready;
 	pt = proctrace;
-	if(pt) pt(p, SReady);
+	if(pt)
+		pt(p, SReady, 0);
 	unlock(runq);
 	splx(s);
 }
@@ -363,7 +364,7 @@ runproc(void)
 	Proc *p;
 	ulong start, now;
 	int i;
-	void (*pt)(Proc*, int);
+	void (*pt)(Proc*, int, vlong);
 
 	start = perfticks();
 
@@ -419,7 +420,8 @@ found:
 		edfunlock();
 	}
 	pt = proctrace;
-	if(pt) pt(p, SRun);
+	if(pt)
+		pt(p, SRun, 0);
 	return p;
 }
 
@@ -589,7 +591,7 @@ void
 sleep(Rendez *r, int (*f)(void*), void *arg)
 {
 	int s;
-	void (*pt)(Proc*, int);
+	void (*pt)(Proc*, int, vlong);
 
 	s = splhi();
 
@@ -625,7 +627,8 @@ sleep(Rendez *r, int (*f)(void*), void *arg)
 		 *  change state and call scheduler
 		 */
 		pt = proctrace;
-		if(pt) pt(up, SSleep);
+		if(pt)
+			pt(up, SSleep, 0);
 		up->state = Wakeme;
 		up->r = r;
 
@@ -912,13 +915,14 @@ pexit(char *exitstr, int freemem)
 	Rgrp *rgrp;
 	Pgrp *pgrp;
 	Chan *dot;
-	void (*pt)(Proc*, int);
+	void (*pt)(Proc*, int, vlong);
 
 	up->alarm = 0;
 	if (up->tt)
 		timerdel(up);
 	pt = proctrace;
-	if(pt) pt(up, SDead);
+	if(pt)
+		pt(up, SDead, 0);
 
 	/* nil out all the resources under lock (free later) */
 	qlock(&up->debug);

+ 7 - 2
sys/src/9/port/taslock.c

@@ -187,8 +187,13 @@ unlock(Lock *l)
 	l->key = 0;
 	coherence();
 
-	if(up)
-		deccnt(&up->nlocks);
+	if(up && deccnt(&up->nlocks) == 0 && up->delaysched && islo()){
+		/*
+		 * Call sched if the need arose while locks were held
+		 * But, don't do it from interrupt routines, hence the islo() test
+		 */
+		sched();
+	}
 }
 
 void