Browse Source

Plan 9 from Bell Labs 2002-12-14

David du Colombier 21 years ago
parent
commit
586ca07f2a

+ 11 - 9
dist/replica/plan9.db

@@ -4881,7 +4881,7 @@ sys/src/9/alphapc/etherif.h - 664 sys sys 1039753421 1049
 sys/src/9/alphapc/faultalpha.c - 664 sys sys 1015012784 1257
 sys/src/9/alphapc/fdc37c93x.c - 664 sys sys 1015012785 1110
 sys/src/9/alphapc/floppy.h - 664 sys sys 1015012785 3783
-sys/src/9/alphapc/fns.h - 664 sys sys 1026848229 3840
+sys/src/9/alphapc/fns.h - 664 sys sys 1039794342 3889
 sys/src/9/alphapc/fptrap.c - 664 sys sys 1015012785 707
 sys/src/9/alphapc/i8259.c - 664 sys sys 1015012785 3409
 sys/src/9/alphapc/initcode - 664 sys sys 1039753419 779
@@ -4898,7 +4898,7 @@ sys/src/9/alphapc/mouse.c - 664 sys sys 1015012786 25
 sys/src/9/alphapc/pci.c - 664 sys sys 1039753420 7868
 sys/src/9/alphapc/random.c - 664 sys sys 1039753421 26
 sys/src/9/alphapc/screen.c - 664 sys sys 1039753422 26
-sys/src/9/alphapc/screen.h - 664 sys sys 1039753422 3511
+sys/src/9/alphapc/screen.h - 664 sys sys 1039794340 3547
 sys/src/9/alphapc/sd53c8xx.c - 664 sys sys 1015012787 51009
 sys/src/9/alphapc/sdata.c - 664 sys sys 1015012787 25
 sys/src/9/alphapc/sdscsi.c - 664 sys sys 1015012787 26
@@ -4969,7 +4969,7 @@ sys/src/9/boot/boot.c - 664 sys sys 1036813554 5317
 sys/src/9/boot/boot.h - 664 sys sys 1036813626 1744
 sys/src/9/boot/bootauth.c - 664 sys sys 1039763726 1097
 sys/src/9/boot/bootcache.c - 664 sys sys 1039763729 1518
-sys/src/9/boot/bootip.c - 664 sys sys 1039763724 3383
+sys/src/9/boot/bootip.c - 664 sys sys 1039794324 3397
 sys/src/9/boot/bootmkfile - 664 sys sys 1032053196 390
 sys/src/9/boot/doauthenticate.c - 664 sys sys 1015012529 2300
 sys/src/9/boot/embed.c - 664 sys sys 1039763720 1191
@@ -5073,6 +5073,7 @@ sys/src/9/pc/ether589.c - 664 sys sys 1015014516 4644
 sys/src/9/pc/ether79c970.c - 664 sys sys 1018386992 14056
 sys/src/9/pc/ether8003.c - 664 sys sys 1015014516 6665
 sys/src/9/pc/ether8139.c - 664 sys sys 1026847639 17884
+sys/src/9/pc/ether82543.c - 664 sys sys 1039803177 38406
 sys/src/9/pc/ether82543gc.c - 664 sys sys 1032052916 32377
 sys/src/9/pc/ether82557.c - 664 sys sys 1032543589 29722
 sys/src/9/pc/ether83815.c - 664 sys sys 1026847640 23050
@@ -5083,6 +5084,7 @@ sys/src/9/pc/etherelnk3.c - 664 sys sys 1026847641 48003
 sys/src/9/pc/etherga620.c - 664 sys sys 1032052917 28786
 sys/src/9/pc/etherga620fw.h - 644 sys sys 1026847642 222295
 sys/src/9/pc/etherif.h - 664 sys sys 1026847642 985
+sys/src/9/pc/ethermii.c - 664 sys sys 1039803177 4555
 sys/src/9/pc/ethersink.c - 664 sys sys 1017854323 1075
 sys/src/9/pc/ethersmc.c - 664 sys sys 1015014518 15079
 sys/src/9/pc/etherwavelan.c - 664 sys sys 1026847642 3722
@@ -5106,7 +5108,7 @@ sys/src/9/pc/mp.h - 664 sys sys 1015014520 6575
 sys/src/9/pc/pc - 664 sys sys 1039753496 1311
 sys/src/9/pc/pcauth - 664 sys sys 1039753496 600
 sys/src/9/pc/pccd - 664 sys sys 1039753495 1278
-sys/src/9/pc/pccpu - 664 sys sys 1039753495 785
+sys/src/9/pc/pccpu - 664 sys sys 1039803186 785
 sys/src/9/pc/pcdisk - 664 sys sys 1039764711 1369
 sys/src/9/pc/pcflop - 664 sys sys 1032749195 1353
 sys/src/9/pc/pci.c - 664 sys sys 1032052921 23359
@@ -10260,17 +10262,17 @@ sys/src/cmd/va/l.s - 664 sys sys 944961340 12696
 sys/src/cmd/va/lex.c - 664 sys sys 944961340 11995
 sys/src/cmd/va/mkfile - 664 sys sys 944961340 215
 sys/src/cmd/vac - 20000000775 sys sys 1019678788 0
-sys/src/cmd/vac/cache.c - 664 sys sys 1036006056 15828
+sys/src/cmd/vac/cache.c - 664 sys sys 1039797583 15878
 sys/src/cmd/vac/dat.h - 664 sys sys 1036006061 3997
 sys/src/cmd/vac/error.c - 664 sys sys 1036006057 633
 sys/src/cmd/vac/error.h - 664 sys sys 1036024048 327
-sys/src/cmd/vac/file.c - 664 sys sys 1036006057 18920
+sys/src/cmd/vac/file.c - 664 sys sys 1039797584 18962
 sys/src/cmd/vac/fns.h - 664 sys sys 1036006061 1746
 sys/src/cmd/vac/fs.c - 664 sys sys 1036006058 2880
 sys/src/cmd/vac/mkfile - 664 sys sys 1036024045 434
 sys/src/cmd/vac/pack.c - 664 sys sys 1036006059 10126
 sys/src/cmd/vac/rtest.c - 664 sys sys 1019678787 1116
-sys/src/cmd/vac/source.c - 664 sys sys 1036006058 6671
+sys/src/cmd/vac/source.c - 664 sys sys 1039797584 6723
 sys/src/cmd/vac/srcload.c - 664 sys sys 1036024047 4925
 sys/src/cmd/vac/stdinc.h - 664 sys sys 1036006059 121
 sys/src/cmd/vac/util.c - 664 sys sys 1019678787 930
@@ -10495,12 +10497,12 @@ sys/src/fs/pc/8250.c - 664 sys sys 1015110032 6795
 sys/src/fs/pc/8253.c - 664 sys sys 1032062036 6206
 sys/src/fs/pc/cga.c - 664 sys sys 1015110034 1484
 sys/src/fs/pc/compat.c - 664 sys sys 1037805115 546
-sys/src/fs/pc/compat.h - 664 sys sys 1037805115 1294
+sys/src/fs/pc/compat.h - 664 sys sys 1039794577 1636
 sys/src/fs/pc/devata.c - 664 sys sys 1037805116 26981
 sys/src/fs/pc/dosfs.c - 664 sys sys 1015110040 16461
 sys/src/fs/pc/dosfs.h - 664 sys sys 1037805116 2667
 sys/src/fs/pc/ether2114x.c - 664 sys sys 1015110044 31874
-sys/src/fs/pc/ether8139.c - 664 sys sys 1037805116 18314
+sys/src/fs/pc/ether8139.c - 664 sys sys 1039794573 18318
 sys/src/fs/pc/ether82557.c - 664 sys sys 1037805116 24037
 sys/src/fs/pc/ether83815.c - 664 sys sys 1037805116 27025
 sys/src/fs/pc/etherdp83820.c - 664 sys sys 1037805116 30732

+ 12 - 0
dist/replica/plan9.log

@@ -16744,3 +16744,15 @@
 1039766123 0 c 386/9pcdisk - 775 sys sys 1039766107 1987341
 1039766123 1 c 386/9pcdisk.gz - 664 sys sys 1039766104 703132
 1039768304 0 c sys/src/cmd/vnc/kbd_vwr.c - 664 sys sys 1039767358 2361
+1039795266 0 c sys/src/9/alphapc/fns.h - 664 sys sys 1039794342 3889
+1039795266 1 c sys/src/9/alphapc/screen.h - 664 sys sys 1039794340 3547
+1039795266 2 c sys/src/9/boot/bootip.c - 664 sys sys 1039794324 3397
+1039795266 3 c sys/src/fs/pc/compat.h - 664 sys sys 1039794577 1636
+1039795266 4 c sys/src/fs/pc/ether8139.c - 664 sys sys 1039794573 18318
+1039798866 0 c sys/src/cmd/vac/cache.c - 664 sys sys 1039797583 15878
+1039798866 1 c sys/src/cmd/vac/file.c - 664 sys sys 1039797584 18962
+1039798866 2 c sys/src/cmd/vac/source.c - 664 sys sys 1039797584 6723
+1039802470 0 c sys/src/9/pc/pccpu - 664 sys sys 1039800821 760
+1039804272 0 c sys/src/9/pc/pccpu - 664 sys sys 1039803186 785
+1039804272 1 a sys/src/9/pc/ether82543.c - 664 sys sys 1039803177 38406
+1039804272 2 a sys/src/9/pc/ethermii.c - 664 sys sys 1039803177 4555

+ 1 - 0
sys/src/9/alphapc/fns.h

@@ -40,6 +40,7 @@ int		i8042auxcmd(int);
 void		i8042auxenable(void (*)(int, int));
 void		i8042reset(void);
 void	i8250console(void);
+void	i8250mouse(char*, int(*)(Queue*,int), int);
 void		i8259init(void);
 int		i8259enable(int, int, Vctl*);
 #define	idlehands()			/* nothing to do in the runproc */

+ 1 - 0
sys/src/9/alphapc/screen.h

@@ -70,6 +70,7 @@ struct VGAdev {
 	ulong	(*linear)(VGAscr*, int*, int*);
 	void	(*drawinit)(VGAscr*);
 	int	(*fill)(VGAscr*, Rectangle, ulong);
+	void (*flush)(VGAscr*, Rectangle);
 
 };
 

+ 1 - 0
sys/src/9/boot/bootip.c

@@ -54,6 +54,7 @@ configip(void)
 	bind("#l1", mpoint, MAFTER);
 	bind("#l2", mpoint, MAFTER);
 	bind("#l3", mpoint, MAFTER);
+	werrstr("");
 
 	/* let ipconfig configure the ip interface */
 	switch(pid = fork()){

+ 1652 - 0
sys/src/9/pc/ether82543.c

@@ -0,0 +1,1652 @@
+/*
+ * Intel RS-8254[3456]NN Gigabit Ethernet Controller
+ * as found on the Intel PRO/1000 series of adapters.
+ *
+ * To Do:
+ *	finish autonegotiation code;
+ *	integrate fiber stuff back in (this ONLY handles
+ *	the CAT5 cards at the moment);
+ *	redo the transmit code to use a transmit routine
+ *	again, but figure out how to use fewer interupts.
+ */
+#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"
+
+enum {
+	Ctrl		= 0x00000000,	/* Device Control */
+	Status		= 0x00000008,	/* Device Status */
+	Eecd		= 0x00000010,	/* EEPROM/Flash Control/Data */
+	Ctrlext		= 0x00000018,	/* Extended Device Control */
+	Mdic		= 0x00000020,	/* MDI Control */
+	Fcal		= 0x00000028,	/* Flow Control Address Low */
+	Fcah		= 0x0000002C,	/* Flow Control Address High */
+	Fct		= 0x00000030,	/* Flow Control Type */
+	Icr		= 0x000000C0,	/* Interrupt Cause Read */
+	Ics		= 0x000000C8,	/* Interrupt Cause Set */
+	Ims		= 0x000000D0,	/* Interrupt Mask Set/Read */
+	Imc		= 0x000000D8,	/* Interrupt mask Clear */
+	Rctl		= 0x00000100,	/* Receive Control */
+	Fcttv		= 0x00000170,	/* Flow Control Transmit Timer Value */
+	Txcw		= 0x00000178,	/* Transmit Configuration Word */
+	Rxcw		= 0x00000180,	/* Receive Configuration Word */
+	Tctl		= 0x00000400,	/* Transmit Control */
+	Tipg		= 0x00000410,	/* Transmit IPG */
+	Tbt		= 0x00000448,	/* Transmit Burst Timer */
+	Ait		= 0x00000458,	/* Adaptive IFS Throttle */
+	Fcrtl		= 0x00002160,	/* Flow Control RX Threshold Low */
+	Fcrth		= 0x00002168,	/* Flow Control Rx Threshold High */
+	Rdfh		= 0x00002410,	/* Receive data fifo head */
+	Rdft		= 0x00002418,	/* Receive data fifo tail */
+	Rdfhs		= 0x00002420,	/* Receive data fifo head saved */
+	Rdfts		= 0x00002428,	/* Receive data fifo tail saved */
+	Rdfpc		= 0x00002430,	/* Receive data fifo packet count */
+	Rdbal		= 0x00002800,	/* Rd Base Address Low */
+	Rdbah		= 0x00002804,	/* Rd Base Address High */
+	Rdlen		= 0x00002808,	/* Receive Descriptor Length */
+	Rdh		= 0x00002810,	/* Receive Descriptor Head */
+	Rdt		= 0x00002818,	/* Receive Descriptor Tail */
+	Rdtr		= 0x00002820,	/* Receive Descriptor Timer Ring */
+	Rxdctl		= 0x00002828,	/* Receive Descriptor Control */
+	Txdmac		= 0x00003000,	/* Transfer DMA Control */
+	Ett		= 0x00003008,	/* Early Transmit Control */
+	Tdfh		= 0x00003410,	/* Transmit data fifo head */
+	Tdft		= 0x00003418,	/* Transmit data fifo tail */
+	Tdfhs		= 0x00003420,	/* Transmit data Fifo Head saved */
+	Tdfts		= 0x00003428,	/* Transmit data fifo tail saved */
+	Tdfpc		= 0x00003430,	/* Trasnmit data Fifo packet count */
+	Tdbal		= 0x00003800,	/* Td Base Address Low */
+	Tdbah		= 0x00003804,	/* Td Base Address High */
+	Tdlen		= 0x00003808,	/* Transmit Descriptor Length */
+	Tdh		= 0x00003810,	/* Transmit Descriptor Head */
+	Tdt		= 0x00003818,	/* Transmit Descriptor Tail */
+	Tidv		= 0x00003820,	/* Transmit Interrupt Delay Value */
+	Txdctl		= 0x00003828,	/* Transmit Descriptor Control */
+
+	Statistics	= 0x00004000,	/* Start of Statistics Area */
+	Gorcl		= 0x88/4,	/* Good Octets Received Count */
+	Gotcl		= 0x90/4,	/* Good Octets Transmitted Count */
+	Torl		= 0xC0/4,	/* Total Octets Received */
+	Totl		= 0xC8/4,	/* Total Octets Transmitted */
+	Nstatistics	= 64,
+
+	Rxcsum		= 0x00005000,	/* Receive Checksum Control */
+	Mta		= 0x00005200,	/* Multicast Table Array */
+	Ral		= 0x00005400,	/* Receive Address Low */
+	Rah		= 0x00005404,	/* Receive Address High */
+};
+
+enum {					/* Ctrl */
+	Bem		= 0x00000002,	/* Big Endian Mode */
+	Prior		= 0x00000004,	/* Priority on the PCI bus */
+	Lrst		= 0x00000008,	/* Link Reset */
+	Asde		= 0x00000020,	/* Auto-Speed Detection Enable */
+	Slu		= 0x00000040,	/* Set Link Up */
+	Ilos		= 0x00000080,	/* Invert Loss of Signal (LOS) */
+	SspeedMASK	= 0x00000300,	/* Speed Selection */
+	SspeedSHIFT	= 8,
+	Sspeed10	= 0x00000000,	/* 10Mb/s */
+	Sspeed100	= 0x00000100,	/* 100Mb/s */
+	Sspeed1000	= 0x00000200,	/* 1000Mb/s */
+	Frcspd		= 0x00000800,	/* Force Speed */
+	Frcdplx		= 0x00001000,	/* Force Duplex */
+	SwdpinsloMASK	= 0x003C0000,	/* Software Defined Pins - lo nibble */
+	SwdpinsloSHIFT	= 18,
+	SwdpioloMASK	= 0x03C00000,	/* Software Defined Pins - I or O */
+	SwdpioloSHIFT	= 22,
+	Devrst		= 0x04000000,	/* Device Reset */
+	Rfce		= 0x08000000,	/* Receive Flow Control Enable */
+	Tfce		= 0x10000000,	/* Transmit Flow Control Enable */
+	Vme		= 0x40000000,	/* VLAN Mode Enable */
+};
+
+enum {					/* Status */
+	Lu		= 0x00000002,	/* Link Up */
+	Tckok		= 0x00000004,	/* Transmit clock is running */
+	Rbcok		= 0x00000008,	/* Receive clock is running */
+	Txoff		= 0x00000010,	/* Transmission Paused */
+	Tbimode		= 0x00000020,	/* TBI Mode Indication */
+	LspeedMASK	= 0x000000C0,	/* Link Speed Setting */
+	LspeedSHIFT	= 6,
+	Lspeed10	= 0x00000000,	/* 10Mb/s */
+	Lspeed100	= 0x00000040,	/* 100Mb/s */
+	Lspeed1000	= 0x00000080,	/* 1000Mb/s */
+	Mtxckok		= 0x00000400,	/* MTX clock is running */
+	Pci66		= 0x00000800,	/* PCI Bus speed indication */
+	Bus64		= 0x00001000,	/* PCI Bus width indication */
+};
+
+enum {					/* Ctrl and Status */
+	Fd		= 0x00000001,	/* Full-Duplex */
+	AsdvMASK	= 0x00000300,
+	AsdvSHIFT	= 8,
+	Asdv10		= 0x00000000,	/* 10Mb/s */
+	Asdv100		= 0x00000100,	/* 100Mb/s */
+	Asdv1000	= 0x00000200,	/* 1000Mb/s */
+};
+
+enum {					/* Eecd */
+	Sk		= 0x00000001,	/* Clock input to the EEPROM */
+	Cs		= 0x00000002,	/* Chip Select */
+	Di		= 0x00000004,	/* Data Input to the EEPROM */
+	Do		= 0x00000008,	/* Data Output from the EEPROM */
+};
+
+enum {					/* Ctrlext */
+	Gpien		= 0x0000000F,	/* General Purpose Interrupt Enables */
+	SwdpinshiMASK	= 0x000000F0,	/* Software Defined Pins - hi nibble */
+	SwdpinshiSHIFT	= 4,
+	SwdpiohiMASK	= 0x00000F00,	/* Software Defined Pins - I or O */
+	SwdpiohiSHIFT	= 8,
+	Asdchk		= 0x00001000,	/* ASD Check */
+	Eerst		= 0x00002000,	/* EEPROM Reset */
+	Ips		= 0x00004000,	/* Invert Power State */
+	Spdbyps		= 0x00008000,	/* Speed Select Bypass */
+};
+
+enum {					/* EEPROM content offsets */
+	Ea		= 0x00,		/* Ethernet Address */
+	Cf		= 0x03,		/* Compatibility Field */
+	Pba		= 0x08,		/* Printed Board Assembly number */
+	Icw1		= 0x0A,		/* Initialization Control Word 1 */
+	Sid		= 0x0B,		/* Subsystem ID */
+	Svid		= 0x0C,		/* Subsystem Vendor ID */
+	Did		= 0x0D,		/* Device ID */
+	Vid		= 0x0E,		/* Vendor ID */
+	Icw2		= 0x0F,		/* Initialization Control Word 2 */
+};
+
+enum {					/* Mdic */
+	MDIdMASK	= 0x0000FFFF,	/* Data */
+	MDIdSHIFT	= 0,
+	MDIrMASK	= 0x001F0000,	/* PHY Register Address */
+	MDIrSHIFT	= 16,
+	MDIpMASK	= 0x03E00000,	/* PHY Address */
+	MDIpSHIFT	= 21,
+	MDIwop		= 0x04000000,	/* Write Operation */
+	MDIrop		= 0x08000000,	/* Read Operation */
+	MDIready	= 0x10000000,	/* End of Transaction */
+	MDIie		= 0x20000000,	/* Interrupt Enable */
+	MDIe		= 0x40000000,	/* Error */
+};
+
+enum {					/* Icr, Ics, Ims, Imc */
+	Txdw		= 0x00000001,	/* Transmit Descriptor Written Back */
+	Txqe		= 0x00000002,	/* Transmit Queue Empty */
+	Lsc		= 0x00000004,	/* Link Status Change */
+	Rxseq		= 0x00000008,	/* Receive Sequence Error */
+	Rxdmt0		= 0x00000010,	/* Rd Minimum Threshold Reached */
+	Rxo		= 0x00000040,	/* Receiver Overrun */
+	Rxt0		= 0x00000080,	/* Receiver Timer Interrupt */
+	Mdac		= 0x00000200,	/* MDIO Access Completed */
+	Rxcfg		= 0x00000400,	/* Receiving /C/ ordered sets */
+	Gpi0		= 0x00000800,	/* General Purpose Interrupts */
+	Gpi1		= 0x00001000,
+	Gpi2		= 0x00002000,
+	Gpi3		= 0x00004000,
+};
+
+/*
+ * The Mdic register isn't implemented on the 82543GC,
+ * the software defined pins are used instead.
+ * These definitions work for the Intel PRO/1000 T Server Adapter.
+ * The direction pin bits are read from the EEPROM.
+ */
+enum {
+	Mdd		= ((1<<2)<<SwdpinsloSHIFT),	/* data */
+	Mddo		= ((1<<2)<<SwdpioloSHIFT),	/* pin direction */
+	Mdc		= ((1<<3)<<SwdpinsloSHIFT),	/* clock */
+	Mdco		= ((1<<3)<<SwdpioloSHIFT),	/* pin direction */
+	Mdr		= ((1<<0)<<SwdpinshiSHIFT),	/* reset */
+	Mdro		= ((1<<0)<<SwdpiohiSHIFT),	/* pin direction */
+};
+
+enum {					/* Txcw */
+	TxcwFd		= 0x00000020,	/* Full Duplex */
+	TxcwHd		= 0x00000040,	/* Half Duplex */
+	TxcwPauseMASK	= 0x00000180,	/* Pause */
+	TxcwPauseSHIFT	= 7,
+	TxcwPs		= (1<<TxcwPauseSHIFT),	/* Pause Supported */
+	TxcwAs		= (2<<TxcwPauseSHIFT),	/* Asymmetric FC desired */
+	TxcwRfiMASK	= 0x00003000,	/* Remote Fault Indication */
+	TxcwRfiSHIFT	= 12,
+	TxcwNpr		= 0x00008000,	/* Next Page Request */
+	TxcwConfig	= 0x40000000,	/* Transmit COnfig Control */
+	TxcwAne		= 0x80000000,	/* Auto-Negotiation Enable */
+};
+
+enum {					/* Rxcw */
+	Rxword		= 0x0000FFFF,	/* Data from auto-negotiation process */
+	Rxnocarrier	= 0x04000000,	/* Carrier Sense indication */
+	Rxinvalid	= 0x08000000,	/* Invalid Symbol during configuration */
+	Rxchange	= 0x10000000,	/* Change to the Rxword indication */
+	Rxconfig	= 0x20000000,	/* /C/ order set reception indication */
+	Rxsync		= 0x40000000,	/* Lost bit synchronization indication */
+	Anc		= 0x80000000,	/* Auto Negotiation Complete */
+};
+
+enum {					/* Rctl */
+	Rrst		= 0x00000001,	/* Receiver Software Reset */
+	Ren		= 0x00000002,	/* Receiver Enable */
+	Sbp		= 0x00000004,	/* Store Bad Packets */
+	Upe		= 0x00000008,	/* Unicast Promiscuous Enable */
+	Mpe		= 0x00000010,	/* Multicast Promiscuous Enable */
+	Lpe		= 0x00000020,	/* Long Packet Reception Enable */
+	LbmMASK		= 0x000000C0,	/* Loopback Mode */
+	LbmOFF		= 0x00000000,	/* No Loopback */
+	LbmTBI		= 0x00000040,	/* TBI Loopback */
+	LbmMII		= 0x00000080,	/* GMII/MII Loopback */
+	LbmXCVR		= 0x000000C0,	/* Transceiver Loopback */
+	RdtmsMASK	= 0x00000300,	/* Rd Minimum Threshold Size */
+	RdtmsHALF	= 0x00000000,	/* Threshold is 1/2 Rdlen */
+	RdtmsQUARTER	= 0x00000100,	/* Threshold is 1/4 Rdlen */
+	RdtmsEIGHTH	= 0x00000200,	/* Threshold is 1/8 Rdlen */
+	MoMASK		= 0x00003000,	/* Multicast Offset */
+	Mo47b36		= 0x00000000,	/* bits [47:36] of received address */
+	Mo46b35		= 0x00001000,	/* bits [46:35] of received address */
+	Mo45b34		= 0x00002000,	/* bits [45:34] of received address */
+	Mo43b32		= 0x00003000,	/* bits [43:32] of received address */
+	Bam		= 0x00008000,	/* Broadcast Accept Mode */
+	BsizeMASK	= 0x00030000,	/* Receive Buffer Size */
+	Bsize2048	= 0x00000000,	/* Bsex = 0 */
+	Bsize1024	= 0x00010000,	/* Bsex = 0 */
+	Bsize512	= 0x00020000,	/* Bsex = 0 */
+	Bsize256	= 0x00030000,	/* Bsex = 0 */
+	Bsize16384	= 0x00010000,	/* Bsex = 1 */
+	Vfe		= 0x00040000,	/* VLAN Filter Enable */
+	Cfien		= 0x00080000,	/* Canonical Form Indicator Enable */
+	Cfi		= 0x00100000,	/* Canonical Form Indicator value */
+	Dpf		= 0x00400000,	/* Discard Pause Frames */
+	Pmcf		= 0x00800000,	/* Pass MAC Control Frames */
+	Bsex		= 0x02000000,	/* Buffer Size Extension */
+	Secrc		= 0x04000000,	/* Strip CRC from incoming packet */
+};
+
+enum {					/* Tctl */
+	Trst		= 0x00000001,	/* Transmitter Software Reset */
+	Ten		= 0x00000002,	/* Transmit Enable */
+	Psp		= 0x00000008,	/* Pad Short Packets */
+	CtMASK		= 0x00000FF0,	/* Collision Threshold */
+	CtSHIFT		= 4,
+	ColdMASK	= 0x003FF000,	/* Collision Distance */
+	ColdSHIFT	= 12,
+	Swxoff		= 0x00400000,	/* Sofware XOFF Transmission */
+	Pbe		= 0x00800000,	/* Packet Burst Enable */
+	Rtlc		= 0x01000000,	/* Re-transmit on Late Collision */
+	Nrtu		= 0x02000000,	/* No Re-transmit on Underrrun */
+};
+
+enum {					/* [RT]xdctl */
+	PthreshMASK	= 0x0000003F,	/* Prefetch Threshold */
+	PthreshSHIFT	= 0,
+	HthreshMASK	= 0x00003F00,	/* Host Threshold */
+	HthreshSHIFT	= 8,
+	WthreshMASK	= 0x003F0000,	/* Writeback Threshold */
+	WthreshSHIFT	= 16,
+	Gran		= 0x00000000,	/* Granularity */
+	RxGran		= 0x01000000,	/* Granularity */
+};
+
+enum {					/* Rxcsum */
+	PcssMASK	= 0x000000FF,	/* Packet Checksum Start */
+	PcssSHIFT	= 0,
+	Ipofl		= 0x00000100,	/* IP Checksum Off-load Enable */
+	Tuofl		= 0x00000200,	/* TCP/UDP Checksum Off-load Enable */
+};
+
+enum {					/* Receive Delay Timer Ring */
+	Fpd		= 0x80000000,	/* Flush partial Descriptor Block */
+};
+
+typedef struct Rd {			/* Receive Descriptor */
+	uint	addr[2];
+	ushort	length;
+	ushort	checksum;
+	uchar	status;
+	uchar	errors;
+	ushort	special;
+} Rd;
+
+enum {					/* Rd status */
+	Rdd		= 0x01,		/* Descriptor Done */
+	Reop		= 0x02,		/* End of Packet */
+	Ixsm		= 0x04,		/* Ignore Checksum Indication */
+	Vp		= 0x08,		/* Packet is 802.1Q (matched VET) */
+	Tcpcs		= 0x20,		/* TCP Checksum Calculated on Packet */
+	Ipcs		= 0x40,		/* IP Checksum Calculated on Packet */
+	Pif		= 0x80,		/* Passed in-exact filter */
+};
+
+enum {					/* Rd errors */
+	Ce		= 0x01,		/* CRC Error or Alignment Error */
+	Se		= 0x02,		/* Symbol Error */
+	Seq		= 0x04,		/* Sequence Error */
+	Cxe		= 0x10,		/* Carrier Extension Error */
+	Tcpe		= 0x20,		/* TCP/UDP Checksum Error */
+	Ipe		= 0x40,		/* IP Checksum Error */
+	Rxe		= 0x80,		/* RX Data Error */
+};
+
+typedef struct Td {			/* Legacy+Normal Transmit Descriptor */
+	uint	addr[2];
+	uint	control;		/* varies with descriptor type */
+	uint	status;			/* varies with descriptor type */
+} Td;
+
+enum {					/* Td control */
+	CsoMASK		= 0x00000F00,	/* Checksum Offset */
+	CsoSHIFT	= 16,
+	Teop		= 0x01000000,	/* End of Packet */
+	Ifcs		= 0x02000000,	/* Insert FCS */
+	Ic		= 0x04000000,	/* Insert Checksum (Dext == 0) */
+	Tse		= 0x04000000,	/* TCP Segmentaion Enable (Dext == 1) */
+	Rs		= 0x08000000,	/* Report Status */
+	Rps		= 0x10000000,	/* Report Status Sent */
+	Dext		= 0x20000000,	/* Extension (!legacy) */
+	Vle		= 0x40000000,	/* VLAN Packet Enable */
+	Ide		= 0x80000000,	/* Interrupt Delay Enable */
+};
+
+enum {					/* Td status */
+	Tdd		= 0x00000001,	/* Descriptor Done */
+	Ec		= 0x00000002,	/* Excess Collisions */
+	Lc		= 0x00000004,	/* Late Collision */
+	Tu		= 0x00000008,	/* Transmit Underrun */
+	CssMASK		= 0x0000FF00,	/* Checksum Start Field */
+	CssSHIFT	= 8,
+};
+
+enum {
+	Nrd		= 256,		/* multiple of 8 */
+	Ntd		= 64,		/* multiple of 8 */
+	Nrb		= 1024,		/* private receive buffers per Ctlr */
+	Rbsz		= 2048,
+};
+
+typedef struct Ctlr Ctlr;
+typedef struct Ctlr {
+	int	port;
+	Pcidev*	pcidev;
+	Ctlr*	next;
+	int	active;
+	int	started;
+	int	id;
+	int	cls;
+	ushort	eeprom[0x40];
+
+	QLock	alock;			/* attach */
+	void*	alloc;			/* receive/transmit descriptors */
+	int	nrd;
+	int	ntd;
+	int	nrb;			/* how many this Ctlr has in the pool */
+
+	int*	nic;
+	Lock	imlock;
+	int	im;			/* interrupt mask */
+
+	Mii*	mii;
+	Rendez	lrendez;
+	int	lim;
+
+	int	link;
+
+	QLock	slock;
+	uint	statistics[Nstatistics];
+	uint	lsleep;
+	uint	lintr;
+	uint	rsleep;
+	uint	rintr;
+	uint	tsleep;
+	uint	txdw;
+	uint	tintr;
+
+	uchar	ra[Eaddrlen];		/* receive address */
+	ulong	mta[128];		/* multicast table array */
+
+	Rendez	rrendez;
+	int	rim;
+	int	rdfree;
+	Rd*	rdba;			/* receive descriptor base address */
+	Block**	rb;			/* receive buffers */
+	int	rdh;			/* receive descriptor head */
+	int	rdt;			/* receive descriptor tail */
+
+	Rendez	trendez;
+	int	tim;
+	int	tdfree;
+	Td*	tdba;			/* transmit descriptor base address */
+	Block**	tb;			/* transmit buffers */
+	int	tdh;			/* transmit descriptor head */
+	int	tdt;			/* transmit descriptor tail */
+
+	int	txcw;
+	int	fcrtl;
+	int	fcrth;
+} Ctlr;
+
+#define csr32r(c, r)	(*((c)->nic+((r)/4)))
+#define csr32w(c, r, v)	(*((c)->nic+((r)/4)) = (v))
+
+static Ctlr* i82543ctlrhead;
+static Ctlr* i82543ctlrtail;
+
+static Lock i82543rblock;		/* free receive Blocks */
+static Block* i82543rbpool;
+
+static char* statistics[Nstatistics] = {
+	"CRC Error",
+	"Alignment Error",
+	"Symbol Error",
+	"RX Error",
+	"Missed Packets",
+	"Single Collision",
+	"Excessive Collisions",
+	"Multiple Collision",
+	"Late Collisions",
+	nil,
+	"Collision",
+	"Transmit Underrun",
+	"Defer",
+	"Transmit - No CRS",
+	"Sequence Error",
+	"Carrier Extension Error",
+	"Receive Error Length",
+	nil,
+	"XON Received",
+	"XON Transmitted",
+	"XOFF Received",
+	"XOFF Transmitted",
+	"FC Received Unsupported",
+	"Packets Received (64 Bytes)",
+	"Packets Received (65-127 Bytes)",
+	"Packets Received (128-255 Bytes)",
+	"Packets Received (256-511 Bytes)",
+	"Packets Received (512-1023 Bytes)",
+	"Packets Received (1024-1522 Bytes)",
+	"Good Packets Received",
+	"Broadcast Packets Received",
+	"Multicast Packets Received",
+	"Good Packets Transmitted",
+	nil,
+	"Good Octets Received",
+	nil,
+	"Good Octets Transmitted",
+	nil,
+	nil,
+	nil,
+	"Receive No Buffers",
+	"Receive Undersize",
+	"Receive Fragment",
+	"Receive Oversize",
+	"Receive Jabber",
+	nil,
+	nil,
+	nil,
+	"Total Octets Received",
+	nil,
+	"Total Octets Transmitted",
+	nil,
+	"Total Packets Received",
+	"Total Packets Transmitted",
+	"Packets Transmitted (64 Bytes)",
+	"Packets Transmitted (65-127 Bytes)",
+	"Packets Transmitted (128-255 Bytes)",
+	"Packets Transmitted (256-511 Bytes)",
+	"Packets Transmitted (512-1023 Bytes)",
+	"Packets Transmitted (1024-1522 Bytes)",
+	"Multicast Packets Transmitted",
+	"Broadcast Packets Transmitted",
+	"TCP Segmentation Context Transmitted",
+	"TCP Segmentation Context Fail",
+};
+
+static int
+i82543mdior(Ctlr* ctlr, int n)
+{
+	int ctrl, data, i, r;
+
+	/*
+	 * Read n bits from the Management Data I/O Interface.
+	 */
+	ctrl = csr32r(ctlr, Ctrl);
+	r = (ctrl & ~Mddo)|Mdco;
+	data = 0;
+	for(i = n-1; i >= 0; i--){
+		if(csr32r(ctlr, Ctrl) & Mdd)
+			data |= (1<<i);
+		csr32w(ctlr, Ctrl, Mdc|r);
+		csr32w(ctlr, Ctrl, r);
+	}
+	csr32w(ctlr, Ctrl, ctrl);
+
+	return data;
+}
+
+static int
+i82543mdiow(Ctlr* ctlr, int bits, int n)
+{
+	int ctrl, i, r;
+
+	/*
+	 * Write n bits to the Management Data I/O Interface.
+	 */
+	ctrl = csr32r(ctlr, Ctrl);
+	r = Mdco|Mddo|ctrl;
+	for(i = n-1; i >= 0; i--){
+		if(bits & (1<<i))
+			r |= Mdd;
+		else
+			r &= ~Mdd;
+		csr32w(ctlr, Ctrl, Mdc|r);
+		csr32w(ctlr, Ctrl, r);
+	}
+	csr32w(ctlr, Ctrl, ctrl);
+
+	return 0;
+}
+
+static int
+i82543miimir(Mii* mii, int pa, int ra)
+{
+	int data;
+	Ctlr *ctlr;
+
+	ctlr = mii->ctlr;
+
+	/*
+	 * MII Management Interface Read.
+	 *
+	 * Preamble;
+	 * ST+OP+PHYAD+REGAD;
+	 * TA + 16 data bits.
+	 */
+	i82543mdiow(ctlr, 0xFFFFFFFF, 32);
+	i82543mdiow(ctlr, 0x1800|(pa<<5)|ra, 14);
+	data = i82543mdior(ctlr, 18);
+
+	if(data & 0x10000)
+		return -1;
+
+	return data & 0xFFFF;
+}
+
+static int
+i82543miimiw(Mii* mii, int pa, int ra, int data)
+{
+	Ctlr *ctlr;
+
+	ctlr = mii->ctlr;
+
+	/*
+	 * MII Management Interface Write.
+	 *
+	 * Preamble;
+	 * ST+OP+PHYAD+REGAD+TA + 16 data bits;
+	 * Z.
+	 */
+	i82543mdiow(ctlr, 0xFFFFFFFF, 32);
+	data &= 0xFFFF;
+	data |= (0x05<<(5+5+2+16))|(pa<<(5+2+16))|(ra<<(2+16))|(0x02<<16);
+	i82543mdiow(ctlr, data, 32);
+
+	return 0;
+}
+
+static int
+gc82544miimir(Mii* mii, int pa, int ra)
+{
+	Ctlr *ctlr;
+	int mdic, timo;
+
+	ctlr = mii->ctlr;
+
+	csr32w(ctlr, Mdic, MDIrop|(pa<<MDIpSHIFT)|(ra<<MDIrSHIFT));
+	mdic = 0;
+	for(timo = 64; timo; timo--){
+		mdic = csr32r(ctlr, Mdic);
+		if(mdic & (MDIe|MDIready))
+			break;
+		microdelay(1);
+	}
+
+	if((mdic & (MDIe|MDIready)) == MDIready)
+		return mdic & 0xFFFF;
+	return -1;
+}
+
+static int
+gc82544miimiw(Mii* mii, int pa, int ra, int data)
+{
+	Ctlr *ctlr;
+	int mdic, timo;
+
+	ctlr = mii->ctlr;
+
+	data &= MDIdMASK;
+	csr32w(ctlr, Mdic, MDIwop|(pa<<MDIpSHIFT)|(ra<<MDIrSHIFT)|data);
+	mdic = 0;
+	for(timo = 64; timo; timo--){
+		mdic = csr32r(ctlr, Mdic);
+		if(mdic & (MDIe|MDIready))
+			break;
+		microdelay(1);
+	}
+	if((mdic & (MDIe|MDIready)) == MDIready)
+		return 0;
+	return -1;
+}
+
+static long
+i82543ifstat(Ether* edev, void* a, long n, ulong offset)
+{
+	Ctlr *ctlr;
+	char *p, *s;
+	int i, l, r;
+	uvlong tuvl, ruvl;
+
+	ctlr = edev->ctlr;
+	qlock(&ctlr->slock);
+	p = malloc(2*READSTR);
+	l = 0;
+	for(i = 0; i < Nstatistics; i++){
+		r = csr32r(ctlr, Statistics+i*4);
+		if((s = statistics[i]) == nil)
+			continue;
+		switch(i){
+		case Gorcl:
+		case Gotcl:
+		case Torl:
+		case Totl:
+			ruvl = r;
+			ruvl += ((uvlong)csr32r(ctlr, Statistics+(i+1)*4))<<32;
+			tuvl = ruvl;
+			tuvl += ctlr->statistics[i];
+			tuvl += ((uvlong)ctlr->statistics[i+1])<<32;
+			if(tuvl == 0)
+				continue;
+			ctlr->statistics[i] = tuvl;
+			ctlr->statistics[i+1] = tuvl>>32;
+			l += snprint(p+l, 2*READSTR-l, "%s: %llud %llud\n",
+				s, tuvl, ruvl);
+			i++;
+			break;
+
+		default:
+			ctlr->statistics[i] += r;
+			if(ctlr->statistics[i] == 0)
+				continue;
+			l += snprint(p+l, 2*READSTR-l, "%s: %ud %ud\n",
+				s, ctlr->statistics[i], r);
+			break;
+		}
+	}
+
+	l += snprint(p+l, 2*READSTR-l, "lintr: %ud %ud\n",
+		ctlr->lintr, ctlr->lsleep);
+	l += snprint(p+l, 2*READSTR-l, "rintr: %ud %ud\n",
+		ctlr->rintr, ctlr->rsleep);
+	l += snprint(p+l, 2*READSTR-l, "tintr: %ud %ud %ud\n",
+		ctlr->tintr, ctlr->tsleep, ctlr->txdw);
+
+	l += snprint(p+l, 2*READSTR-l, "eeprom:");
+	for(i = 0; i < 0x40; i++){
+		if(i && ((i & 0x07) == 0))
+			l += snprint(p+l, 2*READSTR-l, "\n       ");
+		l += snprint(p+l, 2*READSTR-l, " %4.4uX", ctlr->eeprom[i]);
+	}
+	l += snprint(p+l, 2*READSTR-l, "\n");
+
+	if(ctlr->mii != nil && ctlr->mii->curphy != nil){
+		l += snprint(p+l, 2*READSTR, "phy:   ");
+		for(i = 0; i < NMiiPhyr; i++){
+			if(i && ((i & 0x07) == 0))
+				l += snprint(p+l, 2*READSTR-l, "\n       ");
+			r = miimir(ctlr->mii, i);
+			l += snprint(p+l, 2*READSTR-l, " %4.4uX", r);
+		}
+		snprint(p+l, 2*READSTR-l, "\n");
+	}
+	n = readstr(offset, a, n, p);
+	free(p);
+	qunlock(&ctlr->slock);
+
+	return n;
+}
+
+static void
+i82543promiscuous(void* arg, int on)
+{
+	int rctl;
+	Ctlr *ctlr;
+	Ether *edev;
+
+	edev = arg;
+	ctlr = edev->ctlr;
+
+	rctl = csr32r(ctlr, Rctl);
+	rctl &= ~MoMASK;
+	rctl |= Mo47b36;
+	if(on)
+		rctl |= Upe|Mpe;
+	else
+		rctl &= ~(Upe|Mpe);
+	csr32w(ctlr, Rctl, rctl);
+}
+
+static Block*
+i82543rballoc(void)
+{
+	Block *bp;
+
+	ilock(&i82543rblock);
+	if((bp = i82543rbpool) != nil){
+		i82543rbpool = bp->next;
+		bp->next = nil;
+	}
+	iunlock(&i82543rblock);
+
+	return bp;
+}
+
+static void
+i82543rbfree(Block* bp)
+{
+	bp->rp = bp->lim - Rbsz;
+	bp->wp = bp->rp;
+
+	ilock(&i82543rblock);
+	bp->next = i82543rbpool;
+	i82543rbpool = bp;
+	iunlock(&i82543rblock);
+}
+
+static void
+i82543im(Ctlr* ctlr, int im)
+{
+	ilock(&ctlr->imlock);
+	ctlr->im |= im;
+	csr32w(ctlr, Ims, ctlr->im);
+	iunlock(&ctlr->imlock);
+}
+
+static int
+i82543lim(void* ctlr)
+{
+	return ((Ctlr*)ctlr)->lim != 0;
+}
+
+static void
+i82543lproc(void* arg)
+{
+	Ctlr *ctlr;
+	Ether *edev;
+	MiiPhy *phy;
+	int ctrl, r;
+
+	edev = arg;
+	ctlr = edev->ctlr;
+	for(;;){
+		if(ctlr->mii == nil || ctlr->mii->curphy == nil)
+			continue;
+
+		/*
+		 * To do:
+		 *	logic to manage status change,
+		 *	this is incomplete but should work
+		 *	one time to set up the hardware.
+		 *
+		 *	MiiPhy.speed, etc. should be in Mii.
+		 */
+		if(miistatus(ctlr->mii) < 0)
+			//continue;
+			goto enable;
+print("lproc status ok\n");
+
+		phy = ctlr->mii->curphy;
+		ctrl = csr32r(ctlr, Ctrl);
+		if(!(ctrl & Asde)){
+			ctrl &= ~(SspeedMASK|Ilos|Fd);
+			ctrl |= Frcdplx|Frcspd;
+			if(phy->speed == 1000)
+				ctrl |= Sspeed1000;
+			else if(phy->speed == 100)
+				ctrl |= Sspeed100;
+			if(phy->fd)
+				ctrl |= Fd;
+		}
+		if(phy->rfc)
+			ctrl |= Rfce;
+		if(phy->tfc)
+			ctrl |= Tfce;
+		csr32w(ctlr, Ctrl, ctrl);
+print("ctrl %8.8uX\n", ctrl);
+
+		r = csr32r(ctlr, Tctl);
+		r &= ~ColdMASK;
+		if(phy->fd)
+			r |= 64<<ColdSHIFT;
+		else
+			r |= 512<<ColdSHIFT;
+		csr32w(ctlr, Tctl, r);
+enable:
+		ctlr->lim = 0;
+		i82543im(ctlr, Lsc);
+
+		ctlr->lsleep++;
+		sleep(&ctlr->lrendez, i82543lim, ctlr);
+	}
+}
+
+static void
+i82543txinit(Ctlr* ctlr)
+{
+	int i, r;
+	Block *bp;
+
+	csr32w(ctlr, Tctl, (0x0F<<CtSHIFT)|Psp|(66<<ColdSHIFT));
+	switch(ctlr->id){
+	default:
+		r = 6;
+		break;
+	case (0x1004<<16)|0x8086:	/* Intel PRO/1000 T */
+	case (0x1008<<16)|0x8086:	/* Intel PRO/1000 XT */
+		r = 8;
+		break;
+	}
+	csr32w(ctlr, Tipg, (6<<20)|(8<<10)|r);
+	csr32w(ctlr, Ait, 0);
+	csr32w(ctlr, Txdmac, 0);
+
+	csr32w(ctlr, Tdbal, PCIWADDR(ctlr->tdba));
+	csr32w(ctlr, Tdbah, 0);
+	csr32w(ctlr, Tdlen, ctlr->ntd*sizeof(Td));
+	ctlr->tdh = PREV(0, ctlr->ntd);
+	csr32w(ctlr, Tdh, 0);
+	ctlr->tdt = 0;
+	csr32w(ctlr, Tdt, 0);
+
+	for(i = 0; i < ctlr->ntd; i++){
+		if((bp = ctlr->tb[i]) != nil){
+			ctlr->tb[i] = nil;
+			freeb(bp);
+		}
+		memset(&ctlr->tdba[i], 0, sizeof(Td));
+	}
+	ctlr->tdfree = ctlr->ntd;
+
+	csr32w(ctlr, Tidv, 128);
+	csr32w(ctlr, Txdctl, (4<<WthreshSHIFT)|(4<<HthreshSHIFT)|8);
+}
+
+static int
+i82543tim(void* ctlr)
+{
+	return ((Ctlr*)ctlr)->tim != 0;
+}
+
+static void
+i82543tproc(void* arg)
+{
+	Td *td;
+	Block *bp;
+	Ctlr *ctlr;
+	Ether *edev;
+	int r, tdh, tdt;
+
+	edev = arg;
+	ctlr = edev->ctlr;
+
+	i82543txinit(ctlr);
+	r = csr32r(ctlr, Tctl);
+	r |= Ten;
+	csr32w(ctlr, Tctl, r);
+
+	if(waserror()){
+		print("%s: exiting\n", up->text);
+		r = csr32r(ctlr, Tctl);
+		r &= ~Ten;
+		csr32w(ctlr, Tctl, r);
+		pexit("disabled", 0);
+	}
+
+	for(;;){
+		/*
+		 * Free any completed packets
+		 */
+		tdh = ctlr->tdh;
+		while(NEXT(tdh, ctlr->ntd) != csr32r(ctlr, Tdh)){
+			td = &ctlr->tdba[tdh];
+			if((bp = ctlr->tb[tdh]) != nil){
+				ctlr->tb[tdh] = nil;
+				freeb(bp);
+			}
+			memset(td, 0, sizeof(Td));
+			tdh = NEXT(tdh, ctlr->ntd);
+		}
+		ctlr->tdh = tdh;
+
+		/*
+		 */
+		tdt = ctlr->tdt;
+		if(NEXT(tdt, ctlr->ntd) == tdh){
+			ctlr->tim = 0;
+			i82543im(ctlr, Txdw);
+			ctlr->tsleep++;
+			sleep(&ctlr->trendez, i82543tim, ctlr);
+			continue;
+		}
+
+		/*
+		 * Try to fill the ring back up.
+		 */
+		while(NEXT(tdt, ctlr->ntd) != tdh){
+			if((bp = qbread(edev->oq, Rbsz)) == nil)
+				break;
+			td = &ctlr->tdba[tdt];
+			td->addr[0] = PCIWADDR(bp->rp);
+			td->control = Ifcs|Teop|BLEN(bp);
+			ctlr->tb[tdt] = bp;
+			tdt = NEXT(tdt, ctlr->ntd);
+			if(NEXT(tdt, ctlr->ntd) == tdh){
+				td->control |= Rs;
+				ctlr->txdw++;
+			}
+
+			if(!qcanread(edev->oq))
+				break;
+		}
+		ctlr->tdt = tdt;
+		csr32w(ctlr, Tdt, tdt);
+	}
+	poperror();
+}
+
+static void
+i82543replenish(Ctlr* ctlr)
+{
+	Rd *rd;
+	int rdt;
+	Block *bp;
+
+	rdt = ctlr->rdt;
+	while(NEXT(rdt, ctlr->nrd) != ctlr->rdh){
+		rd = &ctlr->rdba[rdt];
+		if(ctlr->rb[rdt] == nil){
+			bp = i82543rballoc();
+			if(bp == nil){
+				iprint("no available buffers\n");
+				break;
+			}
+			ctlr->rb[rdt] = bp;
+			rd->addr[0] = PCIWADDR(bp->rp);
+			rd->addr[1] = 0;
+		}
+		coherence();
+		rd->status = 0;
+		rdt = NEXT(rdt, ctlr->nrd);
+		ctlr->rdfree++;
+	}
+	ctlr->rdt = rdt;
+	csr32w(ctlr, Rdt, rdt);
+}
+
+static void
+i82543rxinit(Ctlr* ctlr)
+{
+	int i;
+	Block *bp;
+
+	csr32w(ctlr, Rctl, Dpf|Bsize2048|Bam|RdtmsHALF);
+
+	csr32w(ctlr, Rdbal, PCIWADDR(ctlr->rdba));
+	csr32w(ctlr, Rdbah, 0);
+	csr32w(ctlr, Rdlen, ctlr->nrd*sizeof(Rd));
+	ctlr->rdh = 0;
+	csr32w(ctlr, Rdh, 0);
+	ctlr->rdt = 0;
+	csr32w(ctlr, Rdt, 0);
+	csr32w(ctlr, Rdtr, Fpd|14);
+
+	for(i = 0; i < ctlr->nrd; i++){
+		if((bp = ctlr->rb[i]) != nil){
+			ctlr->rb[i] = nil;
+			freeb(bp);
+		}
+	}
+	i82543replenish(ctlr);
+
+	csr32w(ctlr, Rxdctl, (8<<WthreshSHIFT)|(8<<HthreshSHIFT)|4);
+}
+
+static int
+i82543rim(void* ctlr)
+{
+	return ((Ctlr*)ctlr)->rim != 0;
+}
+
+static void
+i82543rproc(void* arg)
+{
+	Rd *rd;
+	Block *bp;
+	Ctlr *ctlr;
+	int r, rdh;
+	Ether *edev;
+
+	edev = arg;
+	ctlr = edev->ctlr;
+
+	i82543rxinit(ctlr);
+	r = csr32r(ctlr, Rctl);
+	r |= Ren;
+	csr32w(ctlr, Rctl, r);
+
+	for(;;){
+		ctlr->rim = 0;
+		i82543im(ctlr, Rxt0|Rxo|Rxdmt0|Rxseq);
+		ctlr->rsleep++;
+		sleep(&ctlr->rrendez, i82543rim, ctlr);
+
+		rdh = ctlr->rdh;
+		for(;;){
+			rd = &ctlr->rdba[rdh];
+	
+			if(!(rd->status & Rdd))
+				break;
+	
+			if((rd->status & Reop) && rd->errors == 0){
+				bp = ctlr->rb[rdh];
+				ctlr->rb[rdh] = nil;
+				bp->wp += rd->length;
+				bp->next = nil;
+				etheriq(edev, bp, 1);
+			}
+	
+			if(ctlr->rb[rdh] != nil){
+				/* either non eop packet, or error */
+				freeb(ctlr->rb[rdh]);
+				ctlr->rb[rdh] = nil;
+			}
+
+			memset(rd, 0, sizeof(Rd));
+			coherence();
+			ctlr->rdfree--;
+			rdh = NEXT(rdh, ctlr->nrd);
+		}
+		ctlr->rdh = rdh;
+	
+		if(ctlr->rdfree < ctlr->nrd/2 || (ctlr->rim & Rxdmt0))
+			i82543replenish(ctlr);
+	}
+}
+
+static void
+i82543attach(Ether* edev)
+{
+	Block *bp;
+	Ctlr *ctlr;
+	char name[KNAMELEN];
+
+	ctlr = edev->ctlr;
+	qlock(&ctlr->alock);
+	if(ctlr->alloc != nil){
+		qunlock(&ctlr->alock);
+		return;
+	}
+
+	ctlr->nrd = ROUND(Nrd, 8);
+	ctlr->ntd = ROUND(Ntd, 8);
+	ctlr->alloc = malloc(ctlr->nrd*sizeof(Rd)+ctlr->ntd*sizeof(Td) + 127);
+	if(ctlr->alloc == nil){
+		qunlock(&ctlr->alock);
+		return;
+	}
+	ctlr->rdba = (Rd*)ROUNDUP((ulong)ctlr->alloc, 128);
+	ctlr->tdba = (Td*)(ctlr->rdba+ctlr->nrd);
+
+	ctlr->rb = malloc(ctlr->nrd*sizeof(Block*));
+	ctlr->tb = malloc(ctlr->ntd*sizeof(Block*));
+
+	if(waserror()){
+		while(ctlr->nrb > 0){
+			bp = i82543rballoc();
+			bp->free = nil;
+			freeb(bp);
+			ctlr->nrb--;
+		}
+		free(ctlr->tb);
+		ctlr->tb = nil;
+		free(ctlr->rb);
+		ctlr->rb = nil;
+		free(ctlr->alloc);
+		ctlr->alloc = nil;
+		qunlock(&ctlr->alock);
+		nexterror();
+	}
+
+	for(ctlr->nrb = 0; ctlr->nrb < Nrb; ctlr->nrb++){
+		if((bp = allocb(Rbsz)) == nil)
+			break;
+		bp->free = i82543rbfree;
+		freeb(bp);
+	}
+
+	snprint(name, KNAMELEN, "#l%dlproc", edev->ctlrno);
+	kproc(name, i82543lproc, edev);
+
+	snprint(name, KNAMELEN, "#l%drproc", edev->ctlrno);
+	kproc(name, i82543rproc, edev);
+
+	snprint(name, KNAMELEN, "#l%dtproc", edev->ctlrno);
+	kproc(name, i82543tproc, edev);
+
+	qunlock(&ctlr->alock);
+	poperror();
+}
+
+static void
+i82543interrupt(Ureg*, void* arg)
+{
+	Ctlr *ctlr;
+	Ether *edev;
+	int icr, im;
+
+	edev = arg;
+	ctlr = edev->ctlr;
+
+	ilock(&ctlr->imlock);
+	csr32w(ctlr, Imc, ~0);
+	im = ctlr->im;
+
+	while((icr = csr32r(ctlr, Icr) & ctlr->im) != 0){
+//print("I%x/%8.8uX+", icr, csr32r(ctlr, Status));
+		if(icr & Lsc){
+			im &= ~Lsc;
+			ctlr->lim = icr & Lsc;
+			wakeup(&ctlr->lrendez);
+			ctlr->lintr++;
+		}
+		if(icr & (Rxt0|Rxo|Rxdmt0|Rxseq)){
+			im &= ~(Rxt0|Rxo|Rxdmt0|Rxseq);
+			ctlr->rim = icr & (Rxt0|Rxo|Rxdmt0|Rxseq);
+			wakeup(&ctlr->rrendez);
+			ctlr->rintr++;
+		}
+		if(icr & Txdw){
+			im &= ~Txdw;
+			ctlr->tim = icr & Txdw;
+			wakeup(&ctlr->trendez);
+			ctlr->tintr++;
+		}
+	}
+
+	ctlr->im = im;
+	csr32w(ctlr, Ims, im);
+	iunlock(&ctlr->imlock);
+}
+
+static int
+i82543mii(Ctlr* ctlr)
+{
+	MiiPhy *phy;
+	int ctrl, p, r;
+
+	r = csr32r(ctlr, Status);
+	if(r & Tbimode)
+		return -1;
+	if((ctlr->mii = malloc(sizeof(Mii))) == nil)
+		return -1;
+	ctlr->mii->ctlr = ctlr;
+
+	ctrl = csr32r(ctlr, Ctrl);
+	ctrl |= Slu;
+
+	switch(ctlr->id){
+	case (0x1004<<16)|0x8086:
+		ctrl |= Frcdplx|Frcspd;
+		csr32w(ctlr, Ctrl, ctrl);
+
+		/*
+		 * The reset pin direction (Mdro) should already
+		 * be set from the EEPROM load.
+		 * If it's not set this configuration is unexpected
+		 * so bail.
+		 */
+		r = csr32r(ctlr, Ctrlext);
+		if(!(r & Mdro))
+			return -1;
+		csr32w(ctlr, Ctrlext, r);
+		delay(20);
+		r = csr32r(ctlr, Ctrlext);
+		r &= ~Mdr;
+		csr32w(ctlr, Ctrlext, r);
+		delay(20);
+		r = csr32r(ctlr, Ctrlext);
+		r |= Mdr;
+		csr32w(ctlr, Ctrlext, r);
+		delay(20);
+
+		ctlr->mii->mir = i82543miimir;
+		ctlr->mii->miw = i82543miimiw;
+		break;
+	case (0x1008<<16)|0x8086:
+		ctrl &= ~(Frcdplx|Frcspd);
+		csr32w(ctlr, Ctrl, ctrl);
+		ctlr->mii->mir = gc82544miimir;
+		ctlr->mii->miw = gc82544miimiw;
+		break;
+	default:
+		free(ctlr->mii);
+		ctlr->mii = nil;
+		return -1;
+	}
+
+	if(mii(ctlr->mii, ~0) == 0 || (phy = ctlr->mii->curphy) == nil){
+		free(ctlr->mii);
+		ctlr->mii = nil;
+		return -1;
+	}
+	print("oui %X phyno %d\n", phy->oui, phy->phyno);
+
+	/*
+	 * 82543GC-specific PHY registers not in 802.3:
+	 *	0x10	PHY specific control
+	 *	0x14	extended PHY specific control
+	 * Set appropriate values then reset the PHY to have
+	 * changes noted.
+	 */
+	r = miimir(ctlr->mii, 0x10);
+	r |= 0x0800;				/* assert CRS on Tx */
+	r |= 0x0060;				/* auto-crossover all speeds */
+	r |= 0x0002;				/* polarity reversal enabled */
+	miimiw(ctlr->mii, 0x10, r);
+
+	r = miimir(ctlr->mii, 0x14);
+	r |= 0x0070;				/* +25MHz clock */
+	r &= ~0x0F00;
+	r |= 0x0100;				/* 1x downshift */
+	miimiw(ctlr->mii, 0x14, r);
+
+	miireset(ctlr->mii);
+
+	p = 0;
+	if(ctlr->txcw & TxcwPs)
+		p |= AnaP;
+	if(ctlr->txcw & TxcwAs)
+		p |= AnaAP;
+	miiane(ctlr->mii, ~0, p, ~0);
+
+	return 0;
+}
+
+static int
+at93c46io(Ctlr* ctlr, char* op, int data)
+{
+	char *lp, *p;
+	int i, loop, eecd, r;
+
+	eecd = csr32r(ctlr, Eecd);
+
+	r = 0;
+	loop = -1;
+	lp = nil;
+	for(p = op; *p != '\0'; p++){
+		switch(*p){
+		default:
+			return -1;
+		case ' ':
+			continue;
+		case ':':			/* start of loop */
+			if(lp != nil){
+				if(p != (lp+1) || loop != 7)
+					return -1;
+				lp = p;
+				loop = 15;
+				continue;
+			}
+			lp = p;
+			loop = 7;
+			continue;
+		case ';':			/* end of loop */
+			if(lp == nil)
+				return -1;
+			loop--;
+			if(loop >= 0)
+				p = lp;
+			else
+				lp = nil;
+			continue;
+		case 'C':			/* assert clock */
+			eecd |= Sk;
+			break;
+		case 'c':			/* deassert clock */
+			eecd &= ~Sk;
+			break;
+		case 'D':			/* next bit in 'data' byte */
+			if(loop < 0)
+				return -1;
+			if(data & (1<<loop))
+				eecd |= Di;
+			else
+				eecd &= ~Di;
+			break;
+		case 'O':			/* collect data output */
+			i = (csr32r(ctlr, Eecd) & Do) != 0;
+			if(loop >= 0)
+				r |= (i<<loop);
+			else
+				r = i;
+			continue;
+		case 'I':			/* assert data input */
+			eecd |= Di;
+			break;
+		case 'i':			/* deassert data input */
+			eecd &= ~Di;
+			break;
+		case 'S':			/* enable chip select */
+			eecd |= Cs;
+			break;
+		case 's':			/* disable chip select */
+			eecd &= ~Cs;
+			break;
+		}
+		csr32w(ctlr, Eecd, eecd);
+		microdelay(1);
+	}
+	if(loop >= 0)
+		return -1;
+	return r;
+}
+
+static int
+at93c46r(Ctlr* ctlr)
+{
+	ushort sum;
+	int addr, data;
+
+	sum = 0;
+	for(addr = 0; addr < 0x40; addr++){
+		/*
+		 * Read a word at address 'addr' from the Atmel AT93C46
+		 * 3-Wire Serial EEPROM or compatible. The EEPROM access is
+		 * controlled by 4 bits in Eecd. See the AT93C46 datasheet
+		 * for protocol details.
+		 */
+		if(at93c46io(ctlr, "S ICc :DCc;", (0x02<<6)|addr) != 0)
+			break;
+		data = at93c46io(ctlr, "::COc;", 0);
+		at93c46io(ctlr, "sic", 0);
+		ctlr->eeprom[addr] = data;
+		sum += data;
+	}
+
+	return sum;
+}
+
+static void
+i82543detach(Ctlr* ctlr)
+{
+	/*
+	 * Perform a device reset to get the chip back to the
+	 * power-on state, followed by an EEPROM reset to read
+	 * the defaults for some internal registers.
+	 */
+	csr32w(ctlr, Imc, ~0);
+	csr32w(ctlr, Rctl, 0);
+	csr32w(ctlr, Tctl, 0);
+
+	delay(10);
+
+	csr32w(ctlr, Ctrl, Devrst);
+	while(csr32r(ctlr, Ctrl) & Devrst)
+		;
+
+	csr32w(ctlr, Ctrlext, Eerst);
+	while(csr32r(ctlr, Ctrlext) & Eerst)
+		;
+
+	csr32w(ctlr, Imc, ~0);
+	while(csr32r(ctlr, Icr))
+		;
+}
+
+static int
+i82543reset(Ctlr* ctlr)
+{
+	int ctrl, i, pause, r, swdpio, txcw;
+
+print("B: ctrl %8.8uX ctrlext %8.8uX status %8.8uX txcw %8.8uX\n",
+	csr32r(ctlr, Ctrl),  csr32r(ctlr, Ctrlext),
+	csr32r(ctlr, Status), csr32r(ctlr, Txcw));
+
+	i82543detach(ctlr);
+
+	/*
+	 * Read the EEPROM, validate the checksum
+	 * then get the device back to a power-on state.
+	 */
+	if(at93c46r(ctlr) != 0xBABA)
+		return -1;
+
+	/*
+	 * Snarf and set up the receive addresses.
+	 * There are 16 addresses. The first should be the MAC address.
+	 * The others are cleared and not marked valid (MS bit of Rah).
+	 */
+	for(i = Ea; i < Eaddrlen/2; i++){
+		ctlr->ra[2*i] = ctlr->eeprom[i];
+		ctlr->ra[2*i+1] = ctlr->eeprom[i]>>8;
+	}
+	r = (ctlr->ra[3]<<24)|(ctlr->ra[2]<<16)|(ctlr->ra[1]<<8)|ctlr->ra[0];
+	csr32w(ctlr, Ral, r);
+	r = 0x80000000|(ctlr->ra[5]<<8)|ctlr->ra[4];
+	csr32w(ctlr, Rah, r);
+	for(i = 1; i < 16; i++){
+		csr32w(ctlr, Ral+i*8, 0);
+		csr32w(ctlr, Rah+i*8, 0);
+	}
+
+	/*
+	 * Clear the Multicast Table Array.
+	 * It's a 4096 bit vector accessed as 128 32-bit registers.
+	 */
+	for(i = 0; i < 128; i++)
+		csr32w(ctlr, Mta+i*4, 0);
+
+	/*
+	 * Just in case the Eerst didn't load the defaults
+	 * (doesn't appear to fully on the 8243GC), do it manually.
+	 */
+	txcw = csr32r(ctlr, Txcw);
+	txcw &= ~(TxcwAne|TxcwPauseMASK|TxcwFd);
+	ctrl = csr32r(ctlr, Ctrl);
+	ctrl &= ~(SwdpioloMASK|Frcspd|Ilos|Lrst|Fd);
+
+	if(ctlr->eeprom[Icw1] & 0x0400){
+		ctrl |= Fd;
+		txcw |= TxcwFd;
+	}
+	if(ctlr->eeprom[Icw1] & 0x0200)
+		ctrl |= Lrst;
+	if(ctlr->eeprom[Icw1] & 0x0010)
+		ctrl |= Ilos;
+	if(ctlr->eeprom[Icw1] & 0x0800)
+		ctrl |= Frcspd;
+	swdpio = (ctlr->eeprom[Icw1] & 0x01E0)>>5;
+	ctrl |= swdpio<<SwdpioloSHIFT;
+	csr32w(ctlr, Ctrl, ctrl);
+	
+	ctrl = csr32r(ctlr, Ctrlext);
+	ctrl &= ~(Ips|SwdpiohiMASK);
+	swdpio = (ctlr->eeprom[Icw2] & 0x00F0)>>4;
+	if(ctlr->eeprom[Icw1] & 0x1000)
+		ctrl |= Ips;
+	ctrl |= swdpio<<SwdpiohiSHIFT;
+	csr32w(ctlr, Ctrlext, ctrl);
+
+	if(ctlr->eeprom[Icw2] & 0x08000)
+		txcw |= TxcwAne;
+	pause = (ctlr->eeprom[Icw2] & 0x3000)>>12;
+	txcw |= pause<<TxcwPauseSHIFT;
+	switch(pause){
+	default:
+		ctlr->fcrtl = 0x00002000;
+		ctlr->fcrth = 0x00004000;
+		txcw |= TxcwAs|TxcwPs;
+		break;
+	case 0:
+		ctlr->fcrtl = 0x00002000;
+		ctlr->fcrth = 0x00004000;
+		break;
+	case 2:
+		ctlr->fcrtl = 0;
+		ctlr->fcrth = 0;
+		txcw |= TxcwAs;
+		break;
+	}
+	ctlr->txcw = txcw;
+	csr32w(ctlr, Txcw, txcw);
+
+	delay(10);
+
+	if(!(csr32r(ctlr, Status) & Tbimode))
+		i82543mii(ctlr);
+
+	/*
+	 * Flow control - values from the datasheet.
+	 */
+	csr32w(ctlr, Fcal, 0x00C28001);
+	csr32w(ctlr, Fcah, 0x00000100);
+	csr32w(ctlr, Fct, 0x00008808);
+	csr32w(ctlr, Fcttv, 0x00000100);
+
+	csr32w(ctlr, Fcrtl, ctlr->fcrtl);
+	csr32w(ctlr, Fcrth, ctlr->fcrth);
+
+print("A: ctrl %8.8uX ctrlext %8.8uX status %8.8uX txcw %8.8uX rxdctl %8.8uX\n",
+	csr32r(ctlr, Ctrl),  csr32r(ctlr, Ctrlext),
+	csr32r(ctlr, Status), csr32r(ctlr, Txcw),
+	csr32r(ctlr, Rxdctl));
+
+	return 0;
+}
+
+static void
+i82543pci(void)
+{
+	int port, cls;
+	Pcidev *p;
+	Ctlr *ctlr;
+
+	p = nil;
+	while(p = pcimatch(p, 0, 0)){
+		if(p->ccrb != 0x02 || p->ccru != 0)
+			continue;
+
+		switch((p->did<<16)|p->vid){
+		case (0x1000<<16)|0x8086:	/* LSI L2A1157 (82542) */
+		default:
+			continue;
+		case (0x1001<<16)|0x8086:	/* Intel PRO/1000 F */
+			break;
+		case (0x1004<<16)|0x8086:	/* Intel PRO/1000 T */
+			break;
+		case (0x1008<<16)|0x8086:	/* Intel PRO/1000 XT */
+			break;
+		}
+
+		port = upamalloc(p->mem[0].bar & ~0x0F, p->mem[0].size, 0);
+		if(port == 0){
+			print("i82543: can't map %8.8luX\n", p->mem[0].bar);
+			continue;
+		}
+		cls = pcicfgr8(p, PciCLS);
+		switch(cls){
+			default:
+				print("82543: unexpected CLS - %d\n", cls*4);
+				break;
+			case 0x00:
+			case 0xFF:
+				print("82543: unusable CLS\n");
+				continue;
+			case 0x08:
+				break;
+		}
+		ctlr = malloc(sizeof(Ctlr));
+		ctlr->port = port;
+		ctlr->pcidev = p;
+		ctlr->id = (p->did<<16)|p->vid;
+		ctlr->cls = cls*4;
+
+		ctlr->nic = KADDR(ctlr->port);
+
+		if(i82543reset(ctlr)){
+			free(ctlr);
+			continue;
+		}
+
+		if(i82543ctlrhead != nil)
+			i82543ctlrtail->next = ctlr;
+		else
+			i82543ctlrhead = ctlr;
+		i82543ctlrtail = ctlr;
+	}
+}
+
+static int
+i82543pnp(Ether* edev)
+{
+	Ctlr *ctlr;
+
+	if(i82543ctlrhead == nil)
+		i82543pci();
+
+	/*
+	 * Any adapter matches if no edev->port is supplied,
+	 * otherwise the ports must match.
+	 */
+	for(ctlr = i82543ctlrhead; ctlr != nil; ctlr = ctlr->next){
+		if(ctlr->active)
+			continue;
+		if(edev->port == 0 || edev->port == ctlr->port){
+			ctlr->active = 1;
+			break;
+		}
+	}
+	if(ctlr == nil)
+		return -1;
+
+	edev->ctlr = ctlr;
+	edev->port = ctlr->port;
+	edev->irq = ctlr->pcidev->intl;
+	edev->tbdf = ctlr->pcidev->tbdf;
+	edev->mbps = 1000;
+	memmove(edev->ea, ctlr->ra, Eaddrlen);
+
+	/*
+	 * Linkage to the generic ethernet driver.
+	 */
+	edev->attach = i82543attach;
+	edev->transmit = nil/*i82543transmit*/;
+	edev->interrupt = i82543interrupt;
+	edev->ifstat = i82543ifstat;
+
+	edev->arg = edev;
+	edev->promiscuous = i82543promiscuous;
+
+	return 0;
+}
+
+void
+ether82543link(void)
+{
+	addethercard("i82543", i82543pnp);
+}

+ 233 - 0
sys/src/9/pc/ethermii.c

@@ -0,0 +1,233 @@
+#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"
+
+int
+mii(Mii* mii, int mask)
+{
+	MiiPhy *miiphy;
+	int bit, phyno, r, rmask;
+
+	/*
+	 * Probe through mii for PHYs in mask;
+	 * return the mask of those found in the current probe.
+	 * If the PHY has not already been probed, update
+	 * the Mii information.
+	 */
+	rmask = 0;
+	for(phyno = 0; phyno < NMiiPhy; phyno++){
+		bit = 1<<phyno;
+		if(!(mask & bit))
+			continue;
+		if(mii->mask & bit){
+			rmask |= bit;
+			continue;
+		}
+		if(mii->mir(mii, phyno, Bmsr) == -1)
+			continue;
+		if((miiphy = malloc(sizeof(MiiPhy))) == nil)
+			continue;
+
+		miiphy->mii = mii;
+		r = mii->mir(mii, phyno, Phyidr1);
+		miiphy->oui = (r & 0x3FFF)<<6;
+		r = mii->mir(mii, phyno, Phyidr2);
+		miiphy->oui |= r>>10;
+		miiphy->phyno = phyno;
+
+		miiphy->anar = ~0;
+		miiphy->fc = ~0;
+		miiphy->mscr = ~0;
+
+		mii->phy[phyno] = miiphy;
+		if(mii->curphy == nil)
+			mii->curphy = miiphy;
+		mii->mask |= bit;
+		mii->nphy++;
+
+		rmask |= bit;
+	}
+	return rmask;
+}
+
+int
+miimir(Mii* mii, int r)
+{
+	if(mii == nil || mii->ctlr == nil || mii->curphy == nil)
+		return -1;
+	return mii->mir(mii, mii->curphy->phyno, r);
+}
+
+int
+miimiw(Mii* mii, int r, int data)
+{
+	if(mii == nil || mii->ctlr == nil || mii->curphy == nil)
+		return -1;
+	return mii->miw(mii, mii->curphy->phyno, r, data);
+}
+
+int
+miireset(Mii* mii)
+{
+	int bmcr;
+
+	if(mii == nil || mii->ctlr == nil || mii->curphy == nil)
+		return -1;
+	bmcr = mii->mir(mii, mii->curphy->phyno, Bmcr);
+	bmcr |= BmcrR;
+	mii->miw(mii, mii->curphy->phyno, Bmcr, bmcr);
+	microdelay(1);
+
+	return 0;
+}
+
+int
+miiane(Mii* mii, int a, int p, int e)
+{
+	int anar, bmsr, mscr, r, phyno;
+
+	if(mii == nil || mii->ctlr == nil || mii->curphy == nil)
+		return -1;
+	phyno = mii->curphy->phyno;
+
+	bmsr = mii->mir(mii, phyno, Bmsr);
+	if(!(bmsr & BmsrAna))
+		return -1;
+
+	if(a != ~0)
+		anar = (AnaTXFD|AnaTXHD|Ana10FD|Ana10HD) & a;
+	else if(mii->curphy->anar != ~0)
+		anar = mii->curphy->anar;
+	else{
+		anar = mii->mir(mii, phyno, Anar);
+		anar &= ~(AnaAP|AnaP|AnaT4|AnaTXFD|AnaTXHD|Ana10FD|Ana10HD);
+		if(bmsr & Bmsr10THD)
+			anar |= Ana10HD;
+		if(bmsr & Bmsr10TFD)
+			anar |= Ana10FD;
+		if(bmsr & Bmsr100TXHD)
+			anar |= AnaTXHD;
+		if(bmsr & Bmsr100TXFD)
+			anar |= AnaTXFD;
+	}
+	mii->curphy->anar = anar;
+
+	if(p != ~0)
+		anar |= (AnaAP|AnaP) & p;
+	else if(mii->curphy->fc != ~0)
+		anar |= mii->curphy->fc;
+	mii->curphy->fc = (AnaAP|AnaP) & anar;
+
+	if(bmsr & BmsrEs){
+		mscr = mii->mir(mii, phyno, Mscr);
+		mscr &= ~(Mscr1000TFD|Mscr1000THD);
+		if(e != ~0)
+			mscr |= (Mscr1000TFD|Mscr1000THD) & e;
+		else if(mii->curphy->mscr != ~0)
+			mscr = mii->curphy->mscr;
+		else{
+			r = mii->mir(mii, phyno, Esr);
+			if(r & Esr1000THD)
+				mscr |= Mscr1000THD;
+			if(r & Esr1000TFD)
+				mscr |= Mscr1000TFD;
+		}
+		mii->curphy->mscr = mscr;
+		mii->miw(mii, phyno, Mscr, mscr);
+	}
+	mii->miw(mii, phyno, Anar, anar);
+
+	r = mii->mir(mii, phyno, Bmcr);
+	if(!(r & BmcrR)){
+		r |= BmcrAne|BmcrRan;
+		mii->miw(mii, phyno, Bmcr, r);
+	}
+
+	return 0;
+}
+
+int
+miistatus(Mii* mii)
+{
+	MiiPhy *phy;
+	int anlpar, bmsr, p, r, phyno;
+
+	if(mii == nil || mii->ctlr == nil || mii->curphy == nil)
+		return -1;
+	phy = mii->curphy;
+	phyno = phy->phyno;
+
+	/*
+	 * Check Auto-Negotiation is complete and link is up.
+	 * (Read status twice as the Ls bit is sticky).
+	 */
+	bmsr = mii->mir(mii, phyno, Bmsr);
+	if(!(bmsr & (BmsrAnc|BmsrAna)))
+{
+print("miistatus 1\n");
+		return -1;
+}
+
+	bmsr = mii->mir(mii, phyno, Bmsr);
+	if(!(bmsr & BmsrLs)){
+print("miistatus 2\n");
+		phy->link = 0;
+		return -1;
+	}
+
+	phy->speed = phy->fd = phy->rfc = phy->tfc = 0;
+	if(phy->mscr){
+		r = mii->mir(mii, phyno, Mssr);
+		if((phy->mscr & Mscr1000TFD) && (r & Mssr1000TFD)){
+			phy->speed = 1000;
+			phy->fd = 1;
+		}
+		else if((phy->mscr & Mscr1000THD) && (r & Mssr1000THD))
+			phy->speed = 1000;
+	}
+
+	anlpar = mii->mir(mii, phyno, Anlpar);
+	if(phy->speed == 0){
+		r = phy->anar & anlpar;
+		if(r & AnaTXFD){
+			phy->speed = 100;
+			phy->fd = 1;
+		}
+		else if(r & AnaTXHD)
+			phy->speed = 100;
+		else if(r & Ana10FD){
+			phy->speed = 10;
+			phy->fd = 1;
+		}
+		else if(r & Ana10HD)
+			phy->speed = 10;
+	}
+	if(phy->speed == 0)
+{
+print("miistatus 3\n");
+		return -1;
+}
+
+	if(phy->fd){
+		p = phy->fc;
+		r = anlpar & (AnaAP|AnaP);
+		if(p == AnaAP && r == (AnaAP|AnaP))
+			phy->tfc = 1;
+		else if(p == (AnaAP|AnaP) && r == AnaAP)
+			phy->rfc = 1;
+		else if((p & AnaP) && (r & AnaP))
+			phy->rfc = phy->tfc = 1;
+	}
+
+	phy->link = 1;
+
+	return 0;
+}

+ 3 - 2
sys/src/cmd/vac/cache.c

@@ -449,6 +449,7 @@ found:
 	n = vtRead(c->z, score, type, b->data, size);
 	if(n < 0) {
 fprint(2, "vtRead failed: %V %d %d: %R\n", score, type, size);
+abort();
 		lumpDecRef(b, 1);
 		return nil;
 	}
@@ -457,8 +458,8 @@ fprint(2, "vtRead failed: %V %d %d: %R\n", score, type, size);
 		lumpDecRef(b, 1);
 		return nil;
 	}
-
-	b->asize = n;
+	vtZeroExtend(type, b->data, n, size);
+	b->asize = size;
 	lumpSetState(b, LumpVenti);
 
 	return b;

+ 6 - 3
sys/src/cmd/vac/file.c

@@ -314,6 +314,7 @@ Err:
 VacFile *
 vfRoot(VacFS *fs, uchar *score)
 {
+	VtEntry e;
 	Lump *u, *v;
 	Source *r, *r0, *r1, *r2;
 	MetaBlock mb;
@@ -346,8 +347,8 @@ vfRoot(VacFS *fs, uchar *score)
 		v = nil;
 	}
 	vtUnlock(u->lk);
-	if(u->asize <= VtEntrySize){	/* just one entry */
-		fprint(2, "new\n");
+	vtEntryUnpack(&e, u->data, 2);
+	if(e.flags == 0){		/* just one entry */
 		r = sourceAlloc(fs->cache, u, 0, 0, fs->readOnly);
 		if(r == nil)
 			goto Err;
@@ -398,6 +399,7 @@ vfRoot(VacFS *fs, uchar *score)
 		goto Err;
 	if(!vdUnpack(&root->dir, &me))
 		goto Err;
+
 	vfRAccess(root);
 	lumpDecRef(u, 0);
 	sourceFree(r2);
@@ -688,7 +690,7 @@ if(0)fprint(2, "vfRead: %s %d, %lld\n", vf->dir.elem, cnt, offset);
 		if(nn > n)
 			nn = n;
 		memmove(b, u->data+off, nn);
-		memset(b+nn, 0, nn-n);
+		memset(b+nn, 0, n-nn);
 		off = 0;
 		bn++;
 		cnt -= n;
@@ -1078,6 +1080,7 @@ dirEntrySize(Source *s, ulong elem, ulong gen, uvlong *size)
 	}
 	vtEntryUnpack(&e, u->data, elem);
 	if(!(e.flags & VtEntryActive) || e.gen != gen) {
+fprint(2, "gen mismatch\n");
 		vtSetError(ENoDir);
 		goto Err;
 	}

+ 1 - 0
sys/src/cmd/vac/source.c

@@ -36,6 +36,7 @@ sourceAlloc(Cache *c, Lump *u, ulong block, int entry, int readOnly)
 		return nil;
 	
 	if(!(d.flags & VtEntryActive)) {
+fprint(2, "bad flags %#ux %V\n", d.flags, d.score);
 		vtSetError(ENoDir);
 		return nil;
 	}

+ 9 - 3
sys/src/fs/pc/compat.h

@@ -2,12 +2,19 @@
  * fs kernel compatibility hacks for drivers from the cpu/terminal kernel
  */
 #define ETHERIQ(a, b, c) 	etheriq((a), (b))
-#define SETWPCNT(bp, cnt)	(bp)->count = (cnt)
 /*
- * mballoc does:	mb->data = mb->xdata+256;
+ * cpu kernel uses bp->rp to point to start of packet and bp->wp to point
+ * just past valid data in the packet.
+ * fs kernel uses bp->data to point to start of packet and bp->data+bp->count
+ * points just past valid data.
+ * except beware that mballoc(count, ...) sets  bp->count = count(!)
  */
+#define BLEN(bp)		(bp)->count
+#define SETWPCNT(bp, cnt)	(bp)->count = (cnt)
+/* mballoc does:	mb->data = mb->xdata+256; */
 #define BLKRESET(bp)		((bp)->data = (bp)->xdata +256, (bp)->count = 0)
 #define INCRPTR(bp, incr)	(bp)->count += (incr)
+#define ENDDATA(bp)		((bp)->data + (bp)->count)
 
 #define Block	Msgbuf
 #define rp	data			/* Block member → Msgbuf member */
@@ -18,7 +25,6 @@
 #define PCIWINDOW	0
 #define PCIWADDR(va)	(PADDR(va)+PCIWINDOW)
 
-#define BLEN(bp) ((bp)->count)
 #define iprint print
 #define allocb(sz)  mballoc((sz), 0, Maeth1)
 #define iallocb(sz) mballoc((sz), 0, Mbeth1)

+ 12 - 14
sys/src/fs/pc/ether8139.c

@@ -501,28 +501,26 @@ rtl8139receive(Ether* edev)
 		p = ctlr->rbstart+capr;
 		capr = (capr+length) % ctlr->rblen;
 
-/*
- * there's a real conflict here; the 83820 driver uses compat.h's 
- *	#define rp data
- * rp and wp presumably can't both be data.
- */
-#ifdef FS
-#define wp data
-#endif
 		if((bp = iallocb(length)) != nil){
+			SETWPCNT(bp, 0);
 			if(p+length >= ctlr->rbstart+ctlr->rblen){
 				l = ctlr->rbstart+ctlr->rblen - p;
-				memmove(bp->wp, p, l);
-				bp->wp += l;
+				memmove(ENDDATA(bp), p, l);
+				INCRPTR(bp, l);
 				length -= l;
 				p = ctlr->rbstart;
 			}
 			if(length > 0){
-				memmove(bp->wp, p, length);
-				bp->wp += length;
+				memmove(ENDDATA(bp), p, length);
+				INCRPTR(bp, length);
 			}
-			bp->wp -= 4;
-			ETHERIQ(edev, bp, 1);
+			INCRPTR(bp, -4);
+			if (BLEN(bp) < 0) {
+				print("rtl8139receive: input packet of negative length\n");
+				SETWPCNT(bp, 0);
+				freeb(bp);
+			} else
+				ETHERIQ(edev, bp, 1);
 		}
 
 		capr = ROUNDUP(capr, 4);